diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..189c28b0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +.git +.travis.yml +.idea +bin +.gitignore +integration_test +LICENSE +postgraphile +.private_blockchain_password +README.md +scripts +Supfile +test_config +.travis.yml +vulcanizedb.log +Dockerfile diff --git a/.gitignore b/.gitignore index f5d38a88..d29ae381 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea +.vscode test_data_dir/ contracts/* environments/*.toml @@ -7,3 +8,9 @@ vagrant*.sh .vagrant test_scripts/ vulcanizedb +postgraphile/build/ +postgraphile/node_modules/ +postgraphile/package-lock.json +vulcanizedb.log +db/migrations/20*.sql +plugins/*.so diff --git a/.private_blockchain_password b/.private_blockchain_password deleted file mode 100644 index 81c545ef..00000000 --- a/.private_blockchain_password +++ /dev/null @@ -1 +0,0 @@ -1234 diff --git a/.travis.yml b/.travis.yml index bda07aa3..5282ec5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,21 +5,25 @@ go: services: - postgresql addons: - postgresql: "9.6" - + postgresql: '9.6' go_import_path: github.com/vulcanize/vulcanizedb - before_install: - # ginkgo golint dep migrate - make installtools - bash ./scripts/install-postgres-10.sh - + - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - + - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list + - sudo apt-get update && sudo apt-get install yarn before_script: - sudo -u postgres createdb vulcanize_private - make migrate NAME=vulcanize_private - + - cd postgraphile && yarn script: + - yarn test + - cd ../ - make test - + - make integrationtest notifications: email: false +env: + matrix: + secure: GA4GiMHy868UD/C+59jRUOdJxxdLSMauNapPA31AODUMv0lcEOXg6TBJkv6Vn3OOrLHYYSpwCGiGQjF86U2vpKWzD1mSITalPfP/kNpFnrHVNf2oPpfrQs8ccs9gnFpbCNLDy0w2+55pgnrd5hvdnlsTEUS1lHWSKEZmWsSqUeS/dw22IS0+nUja0Pc3pHaWlJz2R502uEKIixjq1fOX65Z/9r1BrMqklOwWrABK0GwgYcDZwc+b3iovyDPkDa3sT/Ddz/srkcYi/Y182zdLdrknj3MVR3GiW5iSqIVm6gr427SFXF4EQVwkEBwAGoo83wRhCgCAslYTRZZ5aleb1HUtAWzuiMAd/JlAYb2jc6VJa19+rQ/5wd7Bann3hB5bY2uV+b02qFK3qWe6uqZLBSESWjFEyWJVoaXgpH0QDc0JG1R9UFxLSVa8NM3P/jgTnUgnAvdW36mTC4dg73Ha9bYdeLpuAZr6k8iTh5qp0CazKAazsdJ+ECNt6q3fkgsI/V5ZwCFfQwlauq+PiBaZsQqr7eeP19klipE3vGf6BCBRvCBdubzSgGZPIRkxOQREc24j/gzBjBNGeqoU2uOp8sXMEG5idfIyHbMU+n2Yi6IRKKPe5lwjgWEsqLkkoM2REMPIEPffRQz0f+mD48HWP0H4KjKHvubKRCE0v2ONlM4= diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..4c853c43 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:alpine as builder +RUN apk --update --no-cache add make git g++ + +# Build statically linked vDB binary (wonky path because of Dep) +RUN mkdir -p /go/src/github.com/vulcanize/vulcanizedb +ADD . /go/src/github.com/vulcanize/vulcanizedb +WORKDIR /go/src/github.com/vulcanize/vulcanizedb +RUN GCO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' . + +# Build migration tool +RUN go get -u -d github.com/pressly/goose/cmd/goose +WORKDIR /go/src/github.com/pressly/goose/cmd/goose +RUN GCO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -tags='no_mysql no_sqlite' -o goose + +# Second stage +FROM alpine +COPY --from=builder /go/src/github.com/vulcanize/vulcanizedb/vulcanizedb /app/vulcanizedb +COPY --from=builder /go/src/github.com/vulcanize/vulcanizedb/environments/staging.toml /app/environments/ +COPY --from=builder /go/src/github.com/vulcanize/vulcanizedb/dockerfiles/startup_script.sh /app/ +COPY --from=builder /go/src/github.com/vulcanize/vulcanizedb/db/migrations/* /app/ +COPY --from=builder /go/src/github.com/pressly/goose/cmd/goose/goose /app/goose + +WORKDIR /app +CMD ["./startup_script.sh"] diff --git a/Gopkg.lock b/Gopkg.lock index 1976e519..adc6f867 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,20 +2,39 @@ [[projects]] - branch = "master" - digest = "1:c5e006ec5f6460f05964be0a9d34a42e3ad25bbc2564a289d7b4f6f2290c76e5" - name = "github.com/aristanetworks/goarista" - packages = ["monotime"] + digest = "1:48a213e9dc4880bbbd6999309a476fa4d3cc67560aa7127154cf8ea95bd464c2" + name = "github.com/allegro/bigcache" + packages = [ + ".", + "queue", + ] pruneopts = "" - revision = "8d0e8f607a4080e7df3532e645440ed0900c64a4" + revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068" + version = "v1.1.0" [[projects]] branch = "master" - digest = "1:735be9b1e9daa0f731c20fbd2f0d4d0d3efbebe674f415f78b72c19defc07fa1" + digest = "1:a313376bcbcce8ae8bddb8089a7293e0473a0f8e9e3710d6244e09e81875ccf0" + name = "github.com/aristanetworks/goarista" + packages = ["monotime"] + pruneopts = "" + revision = "ff33da284e760fcdb03c33d37a719e5ed30ba844" + +[[projects]] + branch = "master" + digest = "1:c6bf1ac7bbc0fe51637bf54d5a88ff79b171b3b42dbc665dec98303c862d8662" name = "github.com/btcsuite/btcd" packages = ["btcec"] pruneopts = "" - revision = "2e60448ffcc6bf78332d1fe590260095f554dd78" + revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" + +[[projects]] + digest = "1:5d47691333460db6ac83ced03c79b4bdb9aff3e322be24affb7855bed8affc6c" + name = "github.com/dave/jennifer" + packages = ["jen"] + pruneopts = "" + revision = "14e399b6b5e8456c66c45c955fc27b568bacb5c9" + version = "v1.3.0" [[projects]] digest = "1:aaeffbff5bd24654cb4c190ed75d6c7b57b4f5d6741914c1a7a6bb7447e756c5" @@ -26,7 +45,7 @@ version = "v1.7.1" [[projects]] - digest = "1:c205f1963071408c1fac73c1b37c86ef9b98d80f17e690a2239853cde255ad3d" + digest = "1:90d36f5b581e95e00ced808cd48824ed6c320c25887828cce461bdef4cb7bc7c" name = "github.com/ethereum/go-ethereum" packages = [ ".", @@ -40,22 +59,15 @@ "common/math", "common/mclock", "common/prque", - "consensus", - "consensus/misc", - "core", "core/rawdb", - "core/state", "core/types", - "core/vm", "crypto", - "crypto/bn256", - "crypto/bn256/cloudflare", - "crypto/bn256/google", "crypto/ecies", "crypto/secp256k1", - "crypto/sha3", "ethclient", "ethdb", + "ethdb/leveldb", + "ethdb/memorydb", "event", "log", "metrics", @@ -72,8 +84,7 @@ "trie", ] pruneopts = "" - revision = "58632d44021bf095b43a1bb2443e6e3690a94739" - version = "v1.8.18" + revision = "cd79bc61a983d6482579d12cdd239b37bbfa12ef" [[projects]] digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd" @@ -84,36 +95,36 @@ version = "v1.4.7" [[projects]] - digest = "1:9ca737b471693542351e112c9e86be9bf7385e42256893a09ecb2a98e2036f74" + digest = "1:a01080d20c45c031c13f3828c56e58f4f51d926a482ad10cc0316225097eb7ea" name = "github.com/go-stack/stack" packages = ["."] pruneopts = "" - revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" - version = "v1.7.0" + revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a" + version = "v1.8.0" [[projects]] - branch = "master" - digest = "1:3b760d3b93f994df8eb1d9ebfad17d3e9e37edcb7f7efaa15b427c0d7a64f4e4" + digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18" name = "github.com/golang/protobuf" packages = ["proto"] pruneopts = "" - revision = "1e59b77b52bf8e4b449a57e6f79f21226d571845" + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" [[projects]] branch = "master" - digest = "1:09307dfb1aa3f49a2bf869dcfa4c6c06ecd3c207221bd1c1a1141f0e51f209eb" + digest = "1:2a5888946cdbc8aa360fd43301f9fc7869d663f60d5eedae7d4e6e5e4f06f2bf" name = "github.com/golang/snappy" packages = ["."] pruneopts = "" - revision = "553a641470496b2327abcac10b36396bd98e45c9" + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" [[projects]] - digest = "1:a25a2c5ae694b01713fb6cd03c3b1ac1ccc1902b9f0a922680a88ec254f968e1" + digest = "1:5247b135b5492aa232a731acdcb52b08f32b874cb398f21ab460396eadbe866b" name = "github.com/google/uuid" packages = ["."] pruneopts = "" - revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" - version = "v1.1.0" + revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" + version = "v1.0.0" [[projects]] branch = "master" @@ -127,13 +138,13 @@ revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" [[projects]] - branch = "master" - digest = "1:147d671753effde6d3bcd58fc74c1d67d740196c84c280c762a5417319499972" + digest = "1:d14365c51dd1d34d5c79833ec91413bfbb166be978724f15701e17080dc06dec" name = "github.com/hashicorp/hcl" packages = [ ".", "hcl/ast", "hcl/parser", + "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -142,11 +153,26 @@ "json/token", ] pruneopts = "" - revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" + revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241" + version = "v1.0.0" + +[[projects]] + digest = "1:b3c5b95e56c06f5aa72cb2500e6ee5f44fcd122872d4fec2023a488e561218bc" + name = "github.com/hpcloud/tail" + packages = [ + ".", + "ratelimiter", + "util", + "watch", + "winfile", + ] + pruneopts = "" + revision = "a30252cb686a21eb2d0b98132633053ec2f7f1e5" + version = "v1.0.0" [[projects]] branch = "master" - digest = "1:b5ef0f034b2eda02c19c2cfcccc9754b372c4e04fa593972fbd8e3d9813d8d98" + digest = "1:b6e4cc26365c004808649862e22069de09594a9222143399a7a04904e9f7018c" name = "github.com/huin/goupnp" packages = [ ".", @@ -158,7 +184,7 @@ "ssdp", ] pruneopts = "" - revision = "dceda08e705b2acee36aab47d765ed801f64cfc7" + revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca" [[projects]] digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" @@ -178,52 +204,60 @@ [[projects]] branch = "master" - digest = "1:fff68ae49ca708829c24a986fb0a044ee2b5aa44b65a0b57b1840fbb0a81f9a6" + digest = "1:617ee2434b77e911fa26b678730be9a617f75243b194eadc8201c8ac860844aa" name = "github.com/jmoiron/sqlx" packages = [ ".", "reflectx", ] pruneopts = "" - revision = "99f3ad6d85ae53d0fecf788ab62d0e9734b3c117" + revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849" + +[[projects]] + digest = "1:6a874e3ddfb9db2b42bd8c85b6875407c702fa868eed20634ff489bc896ccfd3" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" [[projects]] branch = "master" - digest = "1:3b5167b89f2203a949b71e29783418a0532531238ad36eb8610ec12e9c7b997f" + digest = "1:29145d7af4adafd72a79df5e41456ac9e232d5a28c1cd4dacf3ff008a217fc10" name = "github.com/lib/pq" packages = [ ".", "oid", ] pruneopts = "" - revision = "83612a56d3dd153a94a629cd64925371c9adad78" + revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79" [[projects]] - digest = "1:739b2038a38cebb50e922d18f4b042c042256320fea2db094814aeef8891e0c1" + digest = "1:961dc3b1d11f969370533390fdf203813162980c858e1dabe827b60940c909a5" name = "github.com/magiconair/properties" packages = ["."] pruneopts = "" - revision = "d419a98cdbed11a922bf76f257b7c4be79b50e73" - version = "v1.7.4" + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" [[projects]] - branch = "master" - digest = "1:59d11e81d6fdd12a771321696bb22abdd9a94d26ac864787e98c9b419e428734" + digest = "1:096a8a9182648da3d00ff243b88407838902b6703fc12657f76890e08d1899bf" name = "github.com/mitchellh/go-homedir" packages = ["."] pruneopts = "" - revision = "b8bc1bf767474819792c23f32d8286a45736f1c6" + revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4" + version = "v1.0.0" [[projects]] - branch = "master" - digest = "1:a31c8ff06bf8ccc1826e3a28a4132bf217a53f3b096e6a03dcac7b6a9eb796f9" + digest = "1:5219b4506253ccc598f9340677162a42d6a78f340a4cc6df2d62db4d0593c4e9" name = "github.com/mitchellh/mapstructure" packages = ["."] pruneopts = "" - revision = "b4575eea38cca1123ec2dc90c26529b5c5acfcff" + revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8" + version = "v1.0.0" [[projects]] - digest = "1:32b27072cd55bd2fb7244de0425943d125da6a552ae2b6517cdd965a662baf18" + digest = "1:a7fd918fb5bd2188436785c0424f8a50b4addfedf37a2b14d796be2a927b8007" name = "github.com/onsi/ginkgo" packages = [ ".", @@ -246,11 +280,11 @@ "types", ] pruneopts = "" - revision = "9eda700730cba42af70d53180f9dcce9266bc2bc" - version = "v1.4.0" + revision = "3774a09d95489ccaa16032e0770d08ea77ba6184" + version = "v1.6.0" [[projects]] - digest = "1:a4e59d0b2821c983b58c317f141cd77df20570979632da8a7a352e5d12698de7" + digest = "1:3ecd0a37c4a90c12a97e31c398cdbc173824351aa891898ee178120bfe71c478" name = "github.com/onsi/gomega" packages = [ ".", @@ -268,8 +302,8 @@ "types", ] pruneopts = "" - revision = "c893efa28eb45626cdaa76c9f653b62488858837" - version = "v1.2.0" + revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369" + version = "v1.4.2" [[projects]] digest = "1:a5484d4fa43127138ae6e7b2299a6a52ae006c7f803d98d717f60abf3e97192e" @@ -280,83 +314,91 @@ version = "v1.2" [[projects]] - digest = "1:d60cfeee185019d4fcd35e8c89c83aff576e4723b6100300bf67b05be961388f" + digest = "1:894aef961c056b6d85d12bac890bf60c44e99b46292888bfa66caf529f804457" name = "github.com/pelletier/go-toml" packages = ["."] pruneopts = "" - revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8" - version = "v1.1.0" + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" [[projects]] - digest = "1:6938b6ee0351393c55baa54b64352e49a741a1b7b616a7d134d237106812070f" + digest = "1:7143292549152d009ca9e9c493b74736a2ebd93f921bea8a4b308d7cc5edc6b3" name = "github.com/rjeczalik/notify" packages = ["."] pruneopts = "" - revision = "69d839f37b13a8cb7a78366f7633a4071cb43be7" - version = "v0.9.2" + revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8" + version = "v0.9.1" [[projects]] - digest = "1:bfc8db90e2676a2fc0d742a536f376044a9b74f2745b2c60d339eb06c6c6988a" + digest = "1:78c9cf43ddeacd0e472f412082227a0fac2ae107ee60e9112156f9371f9912cf" name = "github.com/rs/cors" packages = ["."] pruneopts = "" - revision = "7af7a1e09ba336d2ea14b1ce73bf693c6837dbf6" - version = "v1.2" + revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f" + version = "v1.5.0" [[projects]] - digest = "1:dae0d7dd55563fd389e7263a32d2030022ef29cceff941336e53f6520e0308c0" + digest = "1:9d57e200ef5ccc4217fe0a34287308bac652435e7c6513f6263e0493d2245c56" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "" + revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95" + version = "v1.2.0" + +[[projects]] + digest = "1:d0431c2fd72e39ee43ea7742322abbc200c3e704c9102c5c3c2e2e667095b0ca" name = "github.com/spf13/afero" packages = [ ".", "mem", ] pruneopts = "" - revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c" - version = "v1.0.2" + revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd" + version = "v1.1.2" [[projects]] - digest = "1:6ff9b74bfea2625f805edec59395dc37e4a06458dd3c14e3372337e3d35a2ed6" + digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4" name = "github.com/spf13/cast" packages = ["."] pruneopts = "" - revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4" - version = "v1.1.0" + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" [[projects]] - digest = "1:2208a80fc3259291e43b30f42f844d18f4218036dff510f42c653ec9890d460a" + digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6" name = "github.com/spf13/cobra" packages = ["."] pruneopts = "" - revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" - version = "v0.0.1" + revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" + version = "v0.0.3" [[projects]] - branch = "master" - digest = "1:104517520aab91164020ab6524a5d6b7cafc641b2e42ac6236f6ac1deac4f66a" + digest = "1:9ceffa4ab5f7195ecf18b3a7fff90c837a9ed5e22e66d18069e4bccfe1f52aa0" name = "github.com/spf13/jwalterweatherman" packages = ["."] pruneopts = "" - revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" + revision = "4a4406e478ca629068e7768fc33f3f044173c0a6" + version = "v1.0.0" [[projects]] - digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000" + digest = "1:0a52bcb568386d98f4894575d53ce3e456f56471de6897bb8b9de13c33d9340e" name = "github.com/spf13/pflag" packages = ["."] pruneopts = "" - revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" - version = "v1.0.0" + revision = "9a97c102cda95a86cec2345a6f09f55a939babf5" + version = "v1.0.2" [[projects]] - digest = "1:59354ad53dfe6ed1b941844cb029cd37c0377598eec3a0d49c03aee2375ef9c4" + digest = "1:ac25ea6cc1156aca9611411274b4a0bdd83a623845df6985aab508253955cc66" name = "github.com/spf13/viper" packages = ["."] pruneopts = "" - revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" - version = "v1.0.0" + revision = "8fb642006536c8d3760c99d4fa2389f5e2205631" + version = "v1.2.0" [[projects]] branch = "master" - digest = "1:f87eb23fc0c2b143947616f754533344626637d3ae1b03ba077136ccb17de3f2" + digest = "1:ce5194e5afac308cc34e500cab45b4ce88a0742d689e3cf7e37b607ad76bed2f" name = "github.com/syndtr/goleveldb" packages = [ "leveldb", @@ -373,23 +415,24 @@ "leveldb/util", ] pruneopts = "" - revision = "adf24ef3f94bd13ec4163060b21a5678f22b429b" + revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd" [[projects]] branch = "master" - digest = "1:450f85e389d9cbd8265299827a2a062b1b6aee8d4c7b78d849d913a6eb405908" + digest = "1:59b49c47c11a48f1054529207f65907c014ecf5f9a7c0d9c0f1616dec7b062ed" name = "golang.org/x/crypto" packages = [ "pbkdf2", - "ripemd160", "scrypt", + "sha3", + "ssh/terminal", ] pruneopts = "" - revision = "613d6eafa307c6881a737a3c35c0e312e8d3a8c5" + revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908" [[projects]] branch = "master" - digest = "1:950b672f2ee80d0fc4c95a15a976ba9ee573a6fb8ede8a777770b2230776367e" + digest = "1:fbdbb6cf8db3278412c9425ad78b26bb8eb788181f26a3ffb3e4f216b314f86a" name = "golang.org/x/net" packages = [ "context", @@ -399,7 +442,7 @@ "websocket", ] pruneopts = "" - revision = "faacc1b5e36e3ff02cbec9661c69ac63dd5a83ad" + revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2" [[projects]] branch = "master" @@ -411,18 +454,17 @@ [[projects]] branch = "master" - digest = "1:303c0ee48d6229a2423950f41b3ccb5a2067dc4c7b65f8863cfbd962bef05a85" + digest = "1:70d519d5cddeb60ceda2db88c24c340b1b2d7efb25ab54bacb38f57ea1998df7" name = "golang.org/x/sys" packages = [ - "cpu", "unix", + "windows", ] pruneopts = "" - revision = "62eef0e2fa9b2c385f7b2778e763486da6880d37" + revision = "d641721ec2dead6fe5ca284096fe4b1fcd49e427" [[projects]] - branch = "master" - digest = "1:1c70f7bb89783a026dc32920575a3feef48e065ef6e170ad227903e8194d7a36" + digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4" name = "golang.org/x/text" packages = [ "encoding", @@ -447,7 +489,17 @@ "unicode/norm", ] pruneopts = "" - revision = "be25de41fadfae372d6470bda81ca6beb55ef551" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd" + name = "gopkg.in/fsnotify.v1" + packages = ["."] + pruneopts = "" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + source = "gopkg.in/fsnotify/fsnotify.v1" + version = "v1.4.7" [[projects]] branch = "v2" @@ -458,42 +510,55 @@ revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6" [[projects]] - branch = "v2" - digest = "1:f769ed60e075e4221612c2f4162fccc9d3795ef358fa463425e3b3d7a5debb27" + branch = "v1" + digest = "1:a96d16bd088460f2e0685d46c39bcf1208ba46e0a977be2df49864ec7da447dd" + name = "gopkg.in/tomb.v1" + packages = ["."] + pruneopts = "" + revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8" + +[[projects]] + digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2" name = "gopkg.in/yaml.v2" packages = ["."] pruneopts = "" - revision = "287cf08546ab5e7e37d55a84f7ed3fd1db036de5" + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" [solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = [ + "github.com/dave/jennifer/jen", "github.com/ethereum/go-ethereum", "github.com/ethereum/go-ethereum/accounts/abi", "github.com/ethereum/go-ethereum/accounts/abi/bind", "github.com/ethereum/go-ethereum/common", "github.com/ethereum/go-ethereum/common/hexutil", - "github.com/ethereum/go-ethereum/core", + "github.com/ethereum/go-ethereum/core/rawdb", "github.com/ethereum/go-ethereum/core/types", "github.com/ethereum/go-ethereum/crypto", "github.com/ethereum/go-ethereum/ethclient", "github.com/ethereum/go-ethereum/ethdb", "github.com/ethereum/go-ethereum/p2p", - "github.com/ethereum/go-ethereum/p2p/discover", + "github.com/ethereum/go-ethereum/p2p/discv5", "github.com/ethereum/go-ethereum/params", + "github.com/ethereum/go-ethereum/rlp", "github.com/ethereum/go-ethereum/rpc", - "github.com/ethereum/go-ethereum/core/types", + "github.com/hashicorp/golang-lru", + "github.com/hpcloud/tail", "github.com/jmoiron/sqlx", "github.com/lib/pq", "github.com/mitchellh/go-homedir", "github.com/onsi/ginkgo", "github.com/onsi/gomega", "github.com/onsi/gomega/ghttp", + "github.com/sirupsen/logrus", "github.com/spf13/cobra", "github.com/spf13/viper", "golang.org/x/net/context", "golang.org/x/sync/errgroup", + "gopkg.in/tomb.v1", ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index f9156bc8..e42fb2af 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -21,6 +21,14 @@ # version = "2.4.0" +[[override]] + name = "gopkg.in/fsnotify.v1" + source = "gopkg.in/fsnotify/fsnotify.v1" + +[[override]] + name = "github.com/pressly/sup" + version = "0.5.3" + [[constraint]] name = "github.com/onsi/ginkgo" version = "1.4.0" @@ -33,10 +41,14 @@ branch = "master" name = "github.com/lib/pq" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.2.0" + [[constraint]] name = "github.com/spf13/cobra" version = "0.0.1" [[constraint]] name = "github.com/ethereum/go-ethereum" - version = "1.8.18" + revision = "cd79bc61a983d6482579d12cdd239b37bbfa12ef" diff --git a/Makefile b/Makefile index 5769da09..f8658e97 100644 --- a/Makefile +++ b/Makefile @@ -2,31 +2,37 @@ BIN = $(GOPATH)/bin BASE = $(GOPATH)/src/$(PACKAGE) PKGS = go list ./... | grep -v "^vendor/" -#Tools +# Tools +## Dependency management DEP = $(BIN)/dep $(BIN)/dep: go get -u github.com/golang/dep/cmd/dep +## Testing library GINKGO = $(BIN)/ginkgo $(BIN)/ginkgo: go get -u github.com/onsi/ginkgo/ginkgo -MIGRATE = $(BIN)/migrate -$(BIN)/migrate: - go get -u -d github.com/mattes/migrate/cli github.com/lib/pq - go build -tags 'postgres' -o $(BIN)/migrate github.com/mattes/migrate/cli +## Migration tool +GOOSE = $(BIN)/goose +$(BIN)/goose: + go get -u -d github.com/pressly/goose/cmd/goose + go build -tags='no_mysql no_sqlite' -o $(BIN)/goose github.com/pressly/goose/cmd/goose +## Source linter LINT = $(BIN)/golint $(BIN)/golint: go get -u golang.org/x/lint/golint +## Combination linter METALINT = $(BIN)/gometalinter.v2 $(BIN)/gometalinter.v2: go get -u gopkg.in/alecthomas/gometalinter.v2 $(METALINT) --install + .PHONY: installtools -installtools: | $(LINT) $(MIGRATE) $(GINKGO) $(DEP) +installtools: | $(LINT) $(GOOSE) $(GINKGO) $(DEP) echo "Installing tools" .PHONY: metalint @@ -42,10 +48,15 @@ lint: .PHONY: test test: | $(GINKGO) $(LINT) - go get -t ./... go vet ./... go fmt ./... - $(GINKGO) -r + $(GINKGO) -r --skipPackage=integration_tests,integration + +.PHONY: integrationtest +integrationtest: | $(GINKGO) $(LINT) + go vet ./... + go fmt ./... + $(GINKGO) -r integration_test/ .PHONY: dep dep: | $(DEP) @@ -61,30 +72,74 @@ PORT = 5432 NAME = CONNECT_STRING=postgresql://$(HOST_NAME):$(PORT)/$(NAME)?sslmode=disable +# Parameter checks +## Check that DB variables are provided .PHONY: checkdbvars checkdbvars: - test -n "$(HOST_NAME)" # $$HOST_NAME + test -n "$(HOST_NAME)" # $$HOST_NAME test -n "$(PORT)" # $$PORT test -n "$(NAME)" # $$NAME @echo $(CONNECT_STRING) +## Check that the migration variable (id/timestamp) is provided +.PHONY: checkmigration +checkmigration: + test -n "$(MIGRATION)" # $$MIGRATION +# Check that the migration name is provided +.PHONY: checkmigname +checkmigname: + test -n "$(NAME)" # $$NAME + +# Migration operations +## Rollback the last migration .PHONY: rollback -rollback: $(MIGRATE) checkdbvars - $(MIGRATE) -database $(CONNECT_STRING) -path ./db/migrations down 1 +rollback: $(GOOSE) checkdbvars + cd db/migrations;\ + $(GOOSE) postgres "$(CONNECT_STRING)" down pg_dump -O -s $(CONNECT_STRING) > db/schema.sql + +## Rollbackt to a select migration (id/timestamp) +.PHONY: rollback_to +rollback_to: $(GOOSE) checkmigration checkdbvars + cd db/migrations;\ + $(GOOSE) postgres "$(CONNECT_STRING)" down-to "$(MIGRATION)" + +## Apply all migrations not already run .PHONY: migrate -migrate: $(MIGRATE) checkdbvars - $(MIGRATE) -database $(CONNECT_STRING) -path ./db/migrations up +migrate: $(GOOSE) checkdbvars + cd db/migrations;\ + $(GOOSE) postgres "$(CONNECT_STRING)" up pg_dump -O -s $(CONNECT_STRING) > db/schema.sql +## Create a new migration file +.PHONY: new_migration +new_migration: $(GOOSE) checkmigname + cd db/migrations;\ + $(GOOSE) create $(NAME) sql + +## Check which migrations are applied at the moment +.PHONY: migration_status +migration_status: $(GOOSE) checkdbvars + cd db/migrations;\ + $(GOOSE) postgres "$(CONNECT_STRING)" status + +# Convert timestamped migrations to versioned (to be run in CI); +# merge timestamped files to prevent conflict +.PHONY: version_migrations +version_migrations: + cd db/migrations; $(GOOSE) fix + +# Import a psql schema to the database .PHONY: import import: test -n "$(NAME)" # $$NAME psql $(NAME) < db/schema.sql -#Rinkeby docker environment + +# Docker actions +## Rinkeby docker environment RINKEBY_COMPOSE_FILE=dockerfiles/rinkeby/docker-compose.yml .PHONY: rinkeby_env_up diff --git a/README.md b/README.md index dc80404a..1a219d29 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,76 @@ # Vulcanize DB -[![Join the chat at https://gitter.im/vulcanizeio/VulcanizeDB](https://badges.gitter.im/vulcanizeio/VulcanizeDB.svg)](https://gitter.im/vulcanizeio/VulcanizeDB?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - [![Build Status](https://travis-ci.org/vulcanize/vulcanizedb.svg?branch=master)](https://travis-ci.org/vulcanize/vulcanizedb) +[![Go Report Card](https://goreportcard.com/badge/github.com/vulcanize/vulcanizedb)](https://goreportcard.com/report/github.com/vulcanize/vulcanizedb) -## About +> Vulcanize DB is a set of tools that make it easier for developers to write application-specific indexes and caches for dapps built on Ethereum. + + +## Table of Contents +1. [Background](../staging/README.md#background) +1. [Dependencies](../staging/README.md#dependencies) +1. [Install](../staging/README.md#install) +1. [Usage](../staging/README.md#usage) +1. [Tests](../staging/README.md#tests) +1. [API](../staging/README.md#API) +1. [Contributing](../staging/README.md#contributing) +1. [License](../staging/README.md#license) + + +## Background +The same data structures and encodings that make Ethereum an effective and trust-less distributed virtual machine +complicate data accessibility and usability for dApp developers. -Vulcanize DB is a set of tools that make it easier for developers to write application-specific indexes and caches for dapps built on Ethereum. ## Dependencies - Go 1.11+ - - Postgres 10 + - Postgres 10.6 - Ethereum Node - - [Go Ethereum](https://ethereum.github.io/go-ethereum/downloads/) (1.8.18+) + - [Go Ethereum](https://ethereum.github.io/go-ethereum/downloads/) (1.8.23+) - [Parity 1.8.11+](https://github.com/paritytech/parity/releases) -## Project Setup -Using Vulcanize for the first time requires several steps be done in order to allow use of the software. The following instructions will offer a guide through the steps of the process: +## Install +1. [Building the project](../staging/README.md#building-the-project) +1. [Setting up the database](../staging/README.md#setting-up-the-database) +1. [Configuring a synced Ethereum node](../staging/README.md#configuring-a-synced-ethereum-node) -1. Fetching the project -2. Installing dependencies -3. Configuring shell environment -4. Database setup -5. Configuring synced Ethereum node integration -6. Data syncing - -## Installation - -In order to fetch the project codebase for local use or modification, install it to your `GOPATH` via: +### Building the project +Download the codebase to your local `GOPATH` via: `go get github.com/vulcanize/vulcanizedb` -Once fetched, dependencies can be installed via `go get` or (the preferred method) at specific versions via `golang/dep`, the prototype golang pakcage manager. Installation instructions are [here](https://golang.github.io/dep/docs/installation.html). +Move to the project directory and use [golang/dep](https://github.com/golang/dep) to install the dependencies: -In order to install packages with `dep`, ensure you are in the project directory now within your `GOPATH` (default location is `~/go/src/github.com/vulcanize/vulcanizedb/`) and run: +`cd $GOPATH/src/github.com/vulcanize/vulcanizedb` `dep ensure` -After `dep` finishes, dependencies should be installed within your `GOPATH` at the versions specified in `Gopkg.toml`. +Once the dependencies have been successfully installed, build the executable with: -Lastly, ensure that `GOPATH` is defined in your shell. If necessary, `GOPATH` can be set in `~/.bashrc` or `~/.bash_profile`, depending upon your system. It can be additionally helpful to add `$GOPATH/bin` to your shell's `$PATH`. +`make build` -## Setting up the Database +If you are running into issues at this stage, ensure that `GOPATH` is defined in your shell. +If necessary, `GOPATH` can be set in `~/.bashrc` or `~/.bash_profile`, depending upon your system. +It can be additionally helpful to add `$GOPATH/bin` to your shell's `$PATH`. + +### Setting up the database 1. Install Postgres 1. Create a superuser for yourself and make sure `psql --list` works without prompting for a password. -1. Execute `createdb vulcanize_public` -1. Execute `cd $GOPATH/src/github.com/vulcanize/vulcanizedb` -1. Run the migrations: `make migrate HOST_NAME=localhost NAME=vulcanize_public PORT=` +1. `createdb vulcanize_public` +1. `cd $GOPATH/src/github.com/vulcanize/vulcanizedb` +1. Run the migrations: `make migrate HOST_NAME=localhost NAME=vulcanize_public PORT=5432` + - To rollback a single step: `make rollback NAME=vulcanize_public` + - To rollback to a certain migration: `make rollback_to MIGRATION=n NAME=vulcanize_public` + - To see status of migrations: `make migration_status NAME=vulcanize_public` * See below for configuring additional environments + +In some cases (such as recent Ubuntu systems), it may be necessary to overcome failures of password authentication from localhost. To allow access on Ubuntu, set localhost connections via hostname, ipv4, and ipv6 from peer/md5 to trust in: /etc/postgresql//pg_hba.conf -In some cases (such as recent Ubuntu systems), it may be necessary to overcome failures of password authentication from `localhost`. To allow access on Ubuntu, set localhost connections via hostname, ipv4, and ipv6 from `peer`/`md5` to `trust` in: `/etc/postgresql//pg_hba.conf` +(It should be noted that trusted auth should only be enabled on systems without sensitive data in them: development and local test databases) -(It should be noted that trusted auth should only be enabled on systems without sensitive data in them: development and local test databases.) - -## Configuring Ethereum Node Integration +### Configuring a synced Ethereum node - To use a local Ethereum node, copy `environments/public.toml.example` to `environments/public.toml` and update the `ipcPath` and `levelDbPath`. - `ipcPath` should match the local node's IPC filepath: @@ -71,7 +86,7 @@ In some cases (such as recent Ubuntu systems), it may be necessary to overcome f - The default location is: - Mac: `/Library/Application\ Support/io.parity.ethereum/` - Linux: `/local/share/io.parity.ethereum/` - + - `levelDbPath` should match Geth's chaindata directory path. - The geth LevelDB chaindata path is printed to the console when you start geth. - The default location is: @@ -79,95 +94,41 @@ In some cases (such as recent Ubuntu systems), it may be necessary to overcome f - Linux: `/ethereum/geth/chaindata` - `levelDbPath` is irrelevant (and `coldImport` is currently unavailable) if only running parity. -- See `environments/infura.toml` to configure commands to run against infura, if a local node is unavailable. (Support is currently experimental, at this time.) -## Start syncing with postgres -Syncs VulcanizeDB with the configured Ethereum node. -1. Start the node - - If node state is not yet fully synced, Vulcanize will not be able to operate on the fetched data. You will need to wait for the initial sync to finish. -1. Start the vulcanize_db sync or lightSync - - Execute `./vulcanizedb sync --config ` - - Or `./vulcanizedb lightSync --config ` - - Or to sync from a specific block: `./vulcanizedb sync --config --starting-block-number ` - - Or `./vulcanizedb lightSync --config --starting-block-number ` +## Usage +Usage is broken up into two processes: -## Alternatively, sync from Geth's underlying LevelDB -Sync VulcanizeDB from the LevelDB underlying a Geth node. -1. Assure node is not running, and that it has synced to the desired block height. -1. Start vulcanize_db - - `./vulcanizedb coldImport --config ` -1. Optional flags: - - `--starting-block-number `/`-s `: block number to start syncing from - - `--ending-block-number `/`-e `: block number to sync to - - `--all`/`-a`: sync all missing blocks +### Data syncing +To provide data for transformations, raw Ethereum data must first be synced into vDB. +This is accomplished through the use of the `lightSync`, `sync`, or `coldImport` commands. +These commands are described in detail [here](../staging/documentation/sync.md). -## Running the Tests +### Data transformation +Contract watchers use the raw data that has been synced into Postgres to filter out and apply transformations to specific data of interest. -In order to run the full test suite, a test database must be prepared. By default, the rests use a database named `vulcanize_private`. Create the database in Postgres, and run migrations on the new database in preparation for executing tests: +There is a built-in `contractWatcher` command which provides generic transformation of most contract data. This command is described in detail [here](../staging/documentation/contractWatcher.md). -`make migrate HOST_NAME=localhost NAME=vulcanize_private PORT=` +In many cases a custom transformer or set of transformers will need to be written to provide complete or more comprehensive coverage or to optimize other aspects of the output for a specific end-use. +In this case we have provided the `compose`, `execute`, and `composeAndExecute` commands for running custom transformers from external repositories. This is described in detail [here](../staging/documentation/composeAndExecute.md). -Ginkgo is declared as a `dep` package test execution. Linting and tests can be run together via a provided `make` task: -`make test` +## Tests +- Replace the empty `ipcPath` in the `environments/infura.toml` with a path to a full node's eth_jsonrpc endpoint (e.g. local geth node ipc path or infura url) + - Note: integration tests require configuration with an archival node +- `createdb vulcanize_private` will create the test db +- `make migrate NAME=vulcanize_private` will run the db migrations +- `make test` will run the unit tests and skip the integration tests +- `make integrationtest` will run just the integration tests -Tests can be run directly via Ginkgo in the project's root directory: +## API +[Postgraphile](https://www.graphile.org/postgraphile/) is used to expose GraphQL endpoints for our database schemas, this is described in detail [here](../staging/postgraphile/README.md). -`ginkgo -r` -## Start full environment in docker by single command +## Contributing +Contributions are welcome! For more on this, please see [here](../staging/documentation/contributing.md). -### Geth Rinkeby +Small note: If editing the Readme, please conform to the [standard-readme specification](https://github.com/RichardLitt/standard-readme). -make command | description -------------------- | ---------------- -rinkeby_env_up | start geth, postgres and rolling migrations, after migrations done starting vulcanizedb container -rinkeby_env_deploy | build and run vulcanizedb container in rinkeby environment -rinkeby_env_migrate | build and run rinkeby env migrations -rinkeby_env_down | stop and remove all rinkeby env containers -Success run of the VulcanizeDB container require full geth state sync, -attach to geth console and check sync state: - -```bash -$ docker exec -it rinkeby_vulcanizedb_geth geth --rinkeby attach -... -> eth.syncing -false -``` - -If you have full rinkeby chaindata you can move it to `rinkeby_vulcanizedb_geth_data` docker volume to skip long wait of sync. - -## omniWatcher and lightOmniWatcher -These commands require a pre-synced (full or light) vulcanizeDB (see above sections) - -To watch all events of a contract using a light synced vDB: - - Execute `./vulcanizedb omniWatcher --config --contract-address ` - -Or if you are using a full synced vDB, change the mode to full: - - Execute `./vulcanizedb omniWatcher --mode full --config --contract-address ` - -To watch contracts on a network other than mainnet, use the network flag: - - Execute `./vulcanizedb omniWatcher --config --contract-address --network ` - -To watch events starting at a certain block use the starting block flag: - - Execute `./vulcanizedb omniWatcher --config --contract-address --starting-block-number <#>` - -To watch only specified events use the events flag: - - Execute `./vulcanizedb omniWatcher --config --contract-address --events --events ` - -To watch events and poll the specified methods with any addresses and hashes emitted by the watched events utilize the methods flag: - - Execute `./vulcanizedb omniWatcher --config --contract-address --methods --methods ` - -To watch specified events and poll the specified method with any addresses and hashes emitted by the watched events: - - Execute `./vulcanizedb omniWatcher --config --contract-address --events --events --methods ` - -To turn on method piping so that values returned from previous method calls are cached and used as arguments in subsequent method calls: - - Execute `./vulcanizedb omniWatcher --config --piping true --contract-address --events --events --methods ` - -To watch all types of events of the contract but only persist the ones that emit one of the filtered-for argument values: - - Execute `./vulcanizedb omniWatcher --config --contract-address --event-args --event-args ` - -To watch all events of the contract but only poll the specified method with specified argument values (if they are emitted from the watched events): - - Execute `./vulcanizedb omniWatcher --config --contract-address --methods --method-args --method-args ` - \ No newline at end of file +## License +[AGPL-3.0](../staging/LICENSE) © Vulcanize Inc \ No newline at end of file diff --git a/cmd/coldImport.go b/cmd/coldImport.go index d5a4d589..58d9df89 100644 --- a/cmd/coldImport.go +++ b/cmd/coldImport.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,7 @@ package cmd import ( - "log" - + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/vulcanize/vulcanizedb/pkg/crypto" diff --git a/cmd/compose.go b/cmd/compose.go new file mode 100644 index 00000000..b8098b9b --- /dev/null +++ b/cmd/compose.go @@ -0,0 +1,187 @@ +// Copyright © 2019 Vulcanize, Inc +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "errors" + "fmt" + "strconv" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/vulcanize/vulcanizedb/pkg/config" + p2 "github.com/vulcanize/vulcanizedb/pkg/plugin" +) + +// composeCmd represents the compose command +var composeCmd = &cobra.Command{ + Use: "compose", + Short: "Composes transformer initializer plugin", + Long: `This command needs a config .toml file of form: + +[database] + name = "vulcanize_public" + hostname = "localhost" + user = "vulcanize" + password = "vulcanize" + port = 5432 + +[client] + ipcPath = "/Users/user/Library/Ethereum/geth.ipc" + +[exporter] + home = "github.com/vulcanize/vulcanizedb" + name = "exampleTransformerExporter" + save = false + transformerNames = [ + "transformer1", + "transformer2", + "transformer3", + "transformer4", + ] + [exporter.transformer1] + path = "path/to/transformer1" + type = "eth_event" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer2] + path = "path/to/transformer2" + type = "eth_contract" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer3] + path = "path/to/transformer3" + type = "eth_event" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer4] + path = "path/to/transformer4" + type = "eth_storage" + repository = "github.com/account2/repo2" + migrations = "to/db/migrations" + rank = "1" + + +Note: If any of the plugin transformer need additional +configuration variables include them in the .toml file as well + +This information is used to write and build a go plugin with a transformer +set composed from the transformer imports specified in the config file +This plugin is loaded and the set of transformer initializers is exported +from it and loaded into and executed over by the appropriate watcher. + +The type of watcher that the transformer works with is specified using the +type variable for each transformer in the config. Currently there are watchers +of event data from an eth node (eth_event) and storage data from an eth node +(eth_storage), and a more generic interface for accepting contract_watcher pkg +based transformers which can perform both event watching and public method +polling (eth_contract). + +Transformers of different types can be ran together in the same command using a +single config file or in separate command instances using different config files + +Specify config location when executing the command: +./vulcanizedb compose --config=./environments/config_name.toml`, + Run: func(cmd *cobra.Command, args []string) { + compose() + }, +} + +func compose() { + // Build plugin generator config + prepConfig() + + // Generate code to build the plugin according to the config file + log.Info("generating plugin") + generator, err := p2.NewGenerator(genConfig, databaseConfig) + if err != nil { + log.Fatal(err) + } + err = generator.GenerateExporterPlugin() + if err != nil { + log.Debug("generating plugin failed") + log.Fatal(err) + } + // TODO: Embed versioning info in the .so files so we know which version of vulcanizedb to run them with + _, pluginPath, err := genConfig.GetPluginPaths() + if err != nil { + log.Fatal(err) + } + fmt.Printf("Composed plugin %s", pluginPath) + log.Info("plugin .so file output to", pluginPath) +} + +func init() { + rootCmd.AddCommand(composeCmd) +} + +func prepConfig() { + log.Info("configuring plugin") + names := viper.GetStringSlice("exporter.transformerNames") + transformers := make(map[string]config.Transformer) + for _, name := range names { + transformer := viper.GetStringMapString("exporter." + name) + p, pOK := transformer["path"] + if !pOK || p == "" { + log.Fatal(name, "transformer config is missing `path` value") + } + r, rOK := transformer["repository"] + if !rOK || r == "" { + log.Fatal(name, "transformer config is missing `repository` value") + } + m, mOK := transformer["migrations"] + if !mOK || m == "" { + log.Fatal(name, "transformer config is missing `migrations` value") + } + mr, mrOK := transformer["rank"] + if !mrOK || mr == "" { + log.Fatal(name, "transformer config is missing `rank` value") + } + rank, err := strconv.ParseUint(mr, 10, 64) + if err != nil { + log.Fatal(name, "migration `rank` can't be converted to an unsigned integer") + } + t, tOK := transformer["type"] + if !tOK { + log.Fatal(name, "transformer config is missing `type` value") + } + transformerType := config.GetTransformerType(t) + if transformerType == config.UnknownTransformerType { + log.Fatal(errors.New(`unknown transformer type in exporter config accepted types are "eth_event", "eth_storage"`)) + } + + transformers[name] = config.Transformer{ + Path: p, + Type: transformerType, + RepositoryPath: r, + MigrationPath: m, + MigrationRank: rank, + } + } + + genConfig = config.Plugin{ + Transformers: transformers, + FilePath: "$GOPATH/src/github.com/vulcanize/vulcanizedb/plugins", + FileName: viper.GetString("exporter.name"), + Save: viper.GetBool("exporter.save"), + Home: viper.GetString("exporter.home"), + } +} diff --git a/cmd/composeAndExecute.go b/cmd/composeAndExecute.go new file mode 100644 index 00000000..d2abd045 --- /dev/null +++ b/cmd/composeAndExecute.go @@ -0,0 +1,191 @@ +// Copyright © 2019 Vulcanize, Inc +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/vulcanize/vulcanizedb/libraries/shared/watcher" + "github.com/vulcanize/vulcanizedb/pkg/fs" + p2 "github.com/vulcanize/vulcanizedb/pkg/plugin" + "github.com/vulcanize/vulcanizedb/pkg/plugin/helpers" + "github.com/vulcanize/vulcanizedb/utils" + "os" + "plugin" + syn "sync" +) + +// composeAndExecuteCmd represents the composeAndExecute command +var composeAndExecuteCmd = &cobra.Command{ + Use: "composeAndExecute", + Short: "Composes, loads, and executes transformer initializer plugin", + Long: `This command needs a config .toml file of form: + +[database] + name = "vulcanize_public" + hostname = "localhost" + user = "vulcanize" + password = "vulcanize" + port = 5432 + +[client] + ipcPath = "/Users/user/Library/Ethereum/geth.ipc" + +[exporter] + home = "github.com/vulcanize/vulcanizedb" + name = "exampleTransformerExporter" + save = false + transformerNames = [ + "transformer1", + "transformer2", + "transformer3", + "transformer4", + ] + [exporter.transformer1] + path = "path/to/transformer1" + type = "eth_event" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer2] + path = "path/to/transformer2" + type = "eth_contract" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "2" + [exporter.transformer3] + path = "path/to/transformer3" + type = "eth_event" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer4] + path = "path/to/transformer4" + type = "eth_storage" + repository = "github.com/account2/repo2" + migrations = "to/db/migrations" + rank = "1" + + +Note: If any of the plugin transformer need additional +configuration variables include them in the .toml file as well + +This information is used to write and build a go plugin with a transformer +set composed from the transformer imports specified in the config file +This plugin is loaded and the set of transformer initializers is exported +from it and loaded into and executed over by the appropriate watcher. + +The type of watcher that the transformer works with is specified using the +type variable for each transformer in the config. Currently there are watchers +of event data from an eth node (eth_event) and storage data from an eth node +(eth_storage), and a more generic interface for accepting contract_watcher pkg +based transformers which can perform both event watching and public method +polling (eth_contract). + +Transformers of different types can be ran together in the same command using a +single config file or in separate command instances using different config files + +Specify config location when executing the command: +./vulcanizedb composeAndExecute --config=./environments/config_name.toml`, + Run: func(cmd *cobra.Command, args []string) { + composeAndExecute() + }, +} + +func composeAndExecute() { + // Build plugin generator config + prepConfig() + + // Generate code to build the plugin according to the config file + log.Info("generating plugin") + generator, err := p2.NewGenerator(genConfig, databaseConfig) + if err != nil { + log.Fatal(err) + } + err = generator.GenerateExporterPlugin() + if err != nil { + log.Debug("generating plugin failed") + log.Fatal(err) + } + + // Get the plugin path and load the plugin + _, pluginPath, err := genConfig.GetPluginPaths() + if err != nil { + log.Fatal(err) + } + if !genConfig.Save { + defer helpers.ClearFiles(pluginPath) + } + log.Info("linking plugin", pluginPath) + plug, err := plugin.Open(pluginPath) + if err != nil { + log.Debug("linking plugin failed") + log.Fatal(err) + } + + // Load the `Exporter` symbol from the plugin + log.Info("loading transformers from plugin") + symExporter, err := plug.Lookup("Exporter") + if err != nil { + log.Debug("loading Exporter symbol failed") + log.Fatal(err) + } + + // Assert that the symbol is of type Exporter + exporter, ok := symExporter.(Exporter) + if !ok { + log.Debug("plugged-in symbol not of type Exporter") + os.Exit(1) + } + + // Use the Exporters export method to load the EventTransformerInitializer, StorageTransformerInitializer, and ContractTransformerInitializer sets + ethEventInitializers, ethStorageInitializers, ethContractInitializers := exporter.Export() + + // Setup bc and db objects + blockChain := getBlockChain() + db := utils.LoadPostgres(databaseConfig, blockChain.Node()) + + // Execute over transformer sets returned by the exporter + // Use WaitGroup to wait on both goroutines + var wg syn.WaitGroup + if len(ethEventInitializers) > 0 { + ew := watcher.NewEventWatcher(&db, blockChain) + ew.AddTransformers(ethEventInitializers) + wg.Add(1) + go watchEthEvents(&ew, &wg) + } + + if len(ethStorageInitializers) > 0 { + tailer := fs.FileTailer{Path: storageDiffsPath} + sw := watcher.NewStorageWatcher(tailer, &db) + sw.AddTransformers(ethStorageInitializers) + wg.Add(1) + go watchEthStorage(&sw, &wg) + } + + if len(ethContractInitializers) > 0 { + gw := watcher.NewContractWatcher(&db, blockChain) + gw.AddTransformers(ethContractInitializers) + wg.Add(1) + go watchEthContract(&gw, &wg) + } + wg.Wait() +} + +func init() { + rootCmd.AddCommand(composeAndExecuteCmd) + composeAndExecuteCmd.Flags().BoolVar(&recheckHeadersArg, "recheckHeaders", false, "checks headers that are already checked for each transformer.") +} diff --git a/cmd/contractWatcher.go b/cmd/contractWatcher.go new file mode 100644 index 00000000..d27802ce --- /dev/null +++ b/cmd/contractWatcher.go @@ -0,0 +1,125 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "fmt" + "github.com/vulcanize/vulcanizedb/pkg/config" + "time" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + st "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + ft "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer" + lt "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/transformer" + "github.com/vulcanize/vulcanizedb/utils" +) + +// contractWatcherCmd represents the contractWatcher command +var contractWatcherCmd = &cobra.Command{ + Use: "contractWatcher", + Short: "Watches events at the provided contract address using fully synced vDB", + Long: `Uses input contract address and event filters to watch events + +Expects an ethereum node to be running +Expects an archival node synced into vulcanizeDB +Requires a .toml config file: + + [database] + name = "vulcanize_public" + hostname = "localhost" + port = 5432 + + [client] + ipcPath = "/Users/user/Library/Ethereum/geth.ipc" + + [contract] + network = "" + addresses = [ + "contractAddress1", + "contractAddress2" + ] + [contract.contractAddress1] + abi = 'ABI for contract 1' + startingBlock = 982463 + [contract.contractAddress2] + abi = 'ABI for contract 2' + events = [ + "event1", + "event2" + ] + eventArgs = [ + "arg1", + "arg2" + ] + methods = [ + "method1", + "method2" + ] + methodArgs = [ + "arg1", + "arg2" + ] + startingBlock = 4448566 + piping = true +`, + Run: func(cmd *cobra.Command, args []string) { + contractWatcher() + }, +} + +var ( + mode string +) + +func contractWatcher() { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + blockChain := getBlockChain() + db := utils.LoadPostgres(databaseConfig, blockChain.Node()) + + var t st.ContractTransformer + con := config.ContractConfig{} + con.PrepConfig() + switch mode { + case "light": + t = lt.NewTransformer(con, blockChain, &db) + case "full": + t = ft.NewTransformer(con, blockChain, &db) + default: + log.Fatal("Invalid mode") + } + + err := t.Init() + if err != nil { + log.Fatal(fmt.Sprintf("Failed to initialized transformer\r\nerr: %v\r\n", err)) + } + + for range ticker.C { + err = t.Execute() + if err != nil { + log.Error("Execution error for transformer:", t.GetConfig().Name, err) + } + } +} + +func init() { + rootCmd.AddCommand(contractWatcherCmd) + contractWatcherCmd.Flags().StringVarP(&mode, "mode", "o", "light", "'light' or 'full' mode to work with either light synced or fully synced vDB (default is light)") +} diff --git a/cmd/erc20.go b/cmd/erc20.go deleted file mode 100644 index 5ca89d62..00000000 --- a/cmd/erc20.go +++ /dev/null @@ -1,87 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package cmd - -import ( - "log" - "time" - - "github.com/spf13/cobra" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai" - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/examples/generic" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/utils" -) - -// erc20Cmd represents the erc20 command -var erc20Cmd = &cobra.Command{ - Use: "erc20", - Short: "Fetches and persists token supply", - Long: `Fetches transfer and approval events, totalSupply, allowances, and -balances for the configured token from each block and persists it in Vulcanize DB. -vulcanizedb erc20 --config environments/public - -Expects an ethereum node to be running and requires a .toml config file: - - [database] - name = "vulcanize_public" - hostname = "localhost" - port = 5432 - - [client] - ipcPath = "/Users/user/Library/Ethereum/geth.ipc" -`, - Run: func(cmd *cobra.Command, args []string) { - watchERC20s() - }, -} - -func watchERC20s() { - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - - blockChain := getBlockChain() - db := utils.LoadPostgres(databaseConfig, blockChain.Node()) - - con := generic.DaiConfig - con.Filters = constants.DaiERC20Filters - watcher := shared.Watcher{ - DB: db, - Blockchain: blockChain, - } - - // It is important that the event transformer is executed before the every_block transformer - // because the events are used to generate the token holder address list that is used to - // collect balances and allowances at every block - transformers := append(dai.DaiEventTriggeredTransformerInitializer(), every_block.ERC20EveryBlockTransformerInitializer()...) - - err := watcher.AddTransformers(transformers, con) - if err != nil { - log.Fatal(err) - } - - for range ticker.C { - watcher.Execute() - } -} - -func init() { - rootCmd.AddCommand(erc20Cmd) -} diff --git a/cmd/execute.go b/cmd/execute.go new file mode 100644 index 00000000..3ebc15f1 --- /dev/null +++ b/cmd/execute.go @@ -0,0 +1,182 @@ +// Copyright © 2019 Vulcanize, Inc +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "fmt" + "os" + "plugin" + syn "sync" + "time" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/libraries/shared/watcher" + "github.com/vulcanize/vulcanizedb/pkg/fs" + "github.com/vulcanize/vulcanizedb/utils" +) + +// executeCmd represents the execute command +var executeCmd = &cobra.Command{ + Use: "execute", + Short: "executes a precomposed transformer initializer plugin", + Long: `This command needs a config .toml file of form: + +[database] + name = "vulcanize_public" + hostname = "localhost" + user = "vulcanize" + password = "vulcanize" + port = 5432 + +[client] + ipcPath = "/Users/user/Library/Ethereum/geth.ipc" + +[exporter] + name = "exampleTransformerExporter" + +Note: If any of the plugin transformer need additional +configuration variables include them in the .toml file as well + +The exporter.name is the name (without extension) of the plugin to be loaded. +The plugin file needs to be located in the /plugins directory and this command assumes +the db migrations remain from when the plugin was composed. Additionally, the plugin +must have been composed by the same version of vulcanizedb or else it will not be compatible. + +Specify config location when executing the command: +./vulcanizedb execute --config=./environments/config_name.toml`, + Run: func(cmd *cobra.Command, args []string) { + execute() + }, +} + +func execute() { + // Build plugin generator config + prepConfig() + + // Get the plugin path and load the plugin + _, pluginPath, err := genConfig.GetPluginPaths() + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Executing plugin %s", pluginPath) + log.Info("linking plugin", pluginPath) + plug, err := plugin.Open(pluginPath) + if err != nil { + log.Debug("linking plugin failed") + log.Fatal(err) + } + + // Load the `Exporter` symbol from the plugin + log.Info("loading transformers from plugin") + symExporter, err := plug.Lookup("Exporter") + if err != nil { + log.Debug("loading Exporter symbol failed") + log.Fatal(err) + } + + // Assert that the symbol is of type Exporter + exporter, ok := symExporter.(Exporter) + if !ok { + log.Debug("plugged-in symbol not of type Exporter") + os.Exit(1) + } + + // Use the Exporters export method to load the EventTransformerInitializer, StorageTransformerInitializer, and ContractTransformerInitializer sets + ethEventInitializers, ethStorageInitializers, ethContractInitializers := exporter.Export() + + // Setup bc and db objects + blockChain := getBlockChain() + db := utils.LoadPostgres(databaseConfig, blockChain.Node()) + + // Execute over transformer sets returned by the exporter + // Use WaitGroup to wait on both goroutines + var wg syn.WaitGroup + if len(ethEventInitializers) > 0 { + ew := watcher.NewEventWatcher(&db, blockChain) + ew.AddTransformers(ethEventInitializers) + wg.Add(1) + go watchEthEvents(&ew, &wg) + } + + if len(ethStorageInitializers) > 0 { + tailer := fs.FileTailer{Path: storageDiffsPath} + sw := watcher.NewStorageWatcher(tailer, &db) + sw.AddTransformers(ethStorageInitializers) + wg.Add(1) + go watchEthStorage(&sw, &wg) + } + + if len(ethContractInitializers) > 0 { + gw := watcher.NewContractWatcher(&db, blockChain) + gw.AddTransformers(ethContractInitializers) + wg.Add(1) + go watchEthContract(&gw, &wg) + } + wg.Wait() +} + +func init() { + rootCmd.AddCommand(executeCmd) + executeCmd.Flags().BoolVar(&recheckHeadersArg, "recheckHeaders", false, "checks headers that are already checked for each transformer.") +} + +type Exporter interface { + Export() ([]transformer.EventTransformerInitializer, []transformer.StorageTransformerInitializer, []transformer.ContractTransformerInitializer) +} + +func watchEthEvents(w *watcher.EventWatcher, wg *syn.WaitGroup) { + defer wg.Done() + // Execute over the EventTransformerInitializer set using the watcher + log.Info("executing event transformers") + var recheck constants.TransformerExecution + if recheckHeadersArg { + recheck = constants.HeaderRecheck + } else { + recheck = constants.HeaderMissing + } + ticker := time.NewTicker(pollingInterval) + defer ticker.Stop() + for range ticker.C { + w.Execute(recheck) + } +} + +func watchEthStorage(w *watcher.StorageWatcher, wg *syn.WaitGroup) { + defer wg.Done() + // Execute over the StorageTransformerInitializer set using the storage watcher + log.Info("executing storage transformers") + ticker := time.NewTicker(pollingInterval) + defer ticker.Stop() + for range ticker.C { + w.Execute() + } +} + +func watchEthContract(w *watcher.ContractWatcher, wg *syn.WaitGroup) { + defer wg.Done() + // Execute over the ContractTransformerInitializer set using the contract watcher + log.Info("executing contract_watcher transformers") + ticker := time.NewTicker(pollingInterval) + defer ticker.Stop() + for range ticker.C { + w.Execute() + } +} diff --git a/cmd/lightSync.go b/cmd/lightSync.go index 7bd2f6bc..5ce62647 100644 --- a/cmd/lightSync.go +++ b/cmd/lightSync.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,10 +17,9 @@ package cmd import ( - "log" - "os" "time" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/vulcanize/vulcanizedb/pkg/core" @@ -37,12 +36,16 @@ var lightSyncCmd = &cobra.Command{ Short: "Syncs VulcanizeDB with local ethereum node's block headers", Long: `Syncs VulcanizeDB with local ethereum node. Populates Postgres with block headers. + ./vulcanizedb lightSync --starting-block-number 0 --config public.toml + Expects ethereum node to be running and requires a .toml config: + [database] name = "vulcanize_public" hostname = "localhost" port = 5432 + [client] ipcPath = "/Users/user/Library/Ethereum/geth.ipc" `, @@ -59,7 +62,9 @@ func init() { func backFillAllHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, missingBlocksPopulated chan int, startingBlockNumber int64) { populated, err := history.PopulateMissingHeaders(blockchain, headerRepository, startingBlockNumber) if err != nil { - log.Fatal("Error populating headers: ", err) + // TODO Lots of possible errors in the call stack above. If errors occur, we still put + // 0 in the channel, triggering another round + log.Error("backfillAllHeaders: Error populating headers: ", err) } missingBlocksPopulated <- populated } @@ -79,20 +84,29 @@ func lightSync() { for { select { case <-ticker.C: - window := validator.ValidateHeaders() - window.Log(os.Stdout) - case <-missingBlocksPopulated: + window, err := validator.ValidateHeaders() + if err != nil { + log.Error("lightSync: ValidateHeaders failed: ", err) + } + log.Info(window.GetString()) + case n := <-missingBlocksPopulated: + if n == 0 { + time.Sleep(3 * time.Second) + } go backFillAllHeaders(blockChain, headerRepository, missingBlocksPopulated, startingBlockNumber) } } } func validateArgs(blockChain *geth.BlockChain) { - lastBlock := blockChain.LastBlock().Int64() - if lastBlock == 0 { + lastBlock, err := blockChain.LastBlock() + if err != nil { + log.Error("validateArgs: Error getting last block: ", err) + } + if lastBlock.Int64() == 0 { log.Fatal("geth initial: state sync not finished") } - if startingBlockNumber > lastBlock { + if startingBlockNumber > lastBlock.Int64() { log.Fatal("starting block number > current block number") } } diff --git a/cmd/omniWatcher.go b/cmd/omniWatcher.go deleted file mode 100644 index dbb9beb9..00000000 --- a/cmd/omniWatcher.go +++ /dev/null @@ -1,125 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package cmd - -import ( - "fmt" - "log" - "time" - - "github.com/spf13/cobra" - - "github.com/vulcanize/vulcanizedb/libraries/shared" - ft "github.com/vulcanize/vulcanizedb/pkg/omni/full/transformer" - lt "github.com/vulcanize/vulcanizedb/pkg/omni/light/transformer" - st "github.com/vulcanize/vulcanizedb/pkg/omni/shared/transformer" - "github.com/vulcanize/vulcanizedb/utils" -) - -// omniWatcherCmd represents the omniWatcher command -var omniWatcherCmd = &cobra.Command{ - Use: "omniWatcher", - Short: "Watches events at the provided contract address using fully synced vDB", - Long: `Uses input contract address and event filters to watch events - -Expects an ethereum node to be running -Expects an archival node synced into vulcanizeDB -Requires a .toml config file: - - [database] - name = "vulcanize_public" - hostname = "localhost" - port = 5432 - - [client] - ipcPath = "/Users/user/Library/Ethereum/geth.ipc" -`, - Run: func(cmd *cobra.Command, args []string) { - omniWatcher() - }, -} - -var ( - network string - contractAddress string - contractAddresses []string - contractEvents []string - contractMethods []string - eventArgs []string - methodArgs []string - methodPiping bool - mode string -) - -func omniWatcher() { - if contractAddress == "" && len(contractAddresses) == 0 { - log.Fatal("Contract address required") - } - - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - - blockChain := getBlockChain() - db := utils.LoadPostgres(databaseConfig, blockChain.Node()) - - var t st.Transformer - switch mode { - case "light": - t = lt.NewTransformer(network, blockChain, &db) - case "full": - t = ft.NewTransformer(network, blockChain, &db) - default: - log.Fatal("Invalid mode") - } - - contractAddresses = append(contractAddresses, contractAddress) - for _, addr := range contractAddresses { - t.SetEvents(addr, contractEvents) - t.SetMethods(addr, contractMethods) - t.SetEventArgs(addr, eventArgs) - t.SetMethodArgs(addr, methodArgs) - t.SetPiping(addr, methodPiping) - t.SetStartingBlock(addr, startingBlockNumber) - } - - err := t.Init() - if err != nil { - log.Fatal(fmt.Sprintf("Failed to initialized transformer\r\nerr: %v\r\n", err)) - } - - w := shared.Watcher{} - w.AddTransformer(t) - - for range ticker.C { - w.Execute() - } -} - -func init() { - rootCmd.AddCommand(omniWatcherCmd) - - omniWatcherCmd.Flags().StringVarP(&mode, "mode", "o", "light", "'light' or 'full' mode to work with either light synced or fully synced vDB (default is light)") - omniWatcherCmd.Flags().StringVarP(&contractAddress, "contract-address", "a", "", "Single address to generate watchers for") - omniWatcherCmd.Flags().StringArrayVarP(&contractAddresses, "contract-addresses", "l", []string{}, "list of addresses to use; warning: watcher targets the same events and methods for each address") - omniWatcherCmd.Flags().StringArrayVarP(&contractEvents, "events", "e", []string{}, "Subset of events to watch; by default all events are watched") - omniWatcherCmd.Flags().StringArrayVarP(&contractMethods, "methods", "m", nil, "Subset of methods to poll; by default no methods are polled") - omniWatcherCmd.Flags().StringArrayVarP(&eventArgs, "event-args", "f", []string{}, "Argument values to filter event logs for; will only persist event logs that emit at least one of the value specified") - omniWatcherCmd.Flags().StringArrayVarP(&methodArgs, "method-args", "g", []string{}, "Argument values to limit methods to; will only call methods with emitted values that were specified here") - omniWatcherCmd.Flags().StringVarP(&network, "network", "n", "", `Network the contract is deployed on; options: "ropsten", "kovan", and "rinkeby"; default is mainnet"`) - omniWatcherCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block to begin watching- default is first block the contract exists") - omniWatcherCmd.Flags().BoolVarP(&methodPiping, "piping", "p", false, "Turn on method output piping: methods listed first will be polled first and their output used as input to subsequent methods") -} diff --git a/cmd/root.go b/cmd/root.go index 49c1b69b..f322867e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,12 +18,13 @@ package cmd import ( "fmt" - "log" "os" + "strings" + "time" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" - "github.com/mitchellh/go-homedir" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -37,11 +38,19 @@ import ( var ( cfgFile string databaseConfig config.Database + genConfig config.Plugin ipc string levelDbPath string startingBlockNumber int64 + storageDiffsPath string syncAll bool endingBlockNumber int64 + recheckHeadersArg bool +) + +const ( + pollingInterval = 7 * time.Second + validationWindow = 15 ) var rootCmd = &cobra.Command{ @@ -50,8 +59,9 @@ var rootCmd = &cobra.Command{ } func Execute() { + log.Info("----- Starting vDB -----") if err := rootCmd.Execute(); err != nil { - fmt.Println(err) + log.Fatal(err) os.Exit(1) } } @@ -59,6 +69,7 @@ func Execute() { func database(cmd *cobra.Command, args []string) { ipc = viper.GetString("client.ipcpath") levelDbPath = viper.GetString("client.leveldbpath") + storageDiffsPath = viper.GetString("filesystem.storageDiffsPath") databaseConfig = config.Database{ Name: viper.GetString("database.name"), Hostname: viper.GetString("database.hostname"), @@ -71,8 +82,11 @@ func database(cmd *cobra.Command, args []string) { func init() { cobra.OnInitialize(initConfig) + // When searching for env variables, replace dots in config keys with underscores + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "environment/public.toml", "config file location") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location") rootCmd.PersistentFlags().String("database-name", "vulcanize_public", "database name") rootCmd.PersistentFlags().Int("database-port", 5432, "database port") rootCmd.PersistentFlags().String("database-hostname", "localhost", "database hostname") @@ -80,6 +94,8 @@ func init() { rootCmd.PersistentFlags().String("database-password", "", "database password") rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file") rootCmd.PersistentFlags().String("client-levelDbPath", "", "location of levelDb chaindata") + rootCmd.PersistentFlags().String("filesystem-storageDiffsPath", "", "location of storage diffs csv file") + rootCmd.PersistentFlags().String("exporter-name", "exporter", "name of exporter plugin") viper.BindPFlag("database.name", rootCmd.PersistentFlags().Lookup("database-name")) viper.BindPFlag("database.port", rootCmd.PersistentFlags().Lookup("database-port")) @@ -88,26 +104,27 @@ func init() { viper.BindPFlag("database.password", rootCmd.PersistentFlags().Lookup("database-password")) viper.BindPFlag("client.ipcPath", rootCmd.PersistentFlags().Lookup("client-ipcPath")) viper.BindPFlag("client.levelDbPath", rootCmd.PersistentFlags().Lookup("client-levelDbPath")) + viper.BindPFlag("filesystem.storageDiffsPath", rootCmd.PersistentFlags().Lookup("filesystem-storageDiffsPath")) + viper.BindPFlag("exporter.fileName", rootCmd.PersistentFlags().Lookup("exporter-name")) } func initConfig() { if cfgFile != "" { viper.SetConfigFile(cfgFile) } else { - home, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - viper.AddConfigPath(home) - viper.SetConfigName(".vulcanizedb") + noConfigError := "No config file passed with --config flag" + fmt.Println("Error: ", noConfigError) + log.Fatal(noConfigError) + os.Exit(1) } - viper.AutomaticEnv() - if err := viper.ReadInConfig(); err == nil { - fmt.Printf("Using config file: %s\n\n", viper.ConfigFileUsed()) + log.Printf("Using config file: %s\n\n", viper.ConfigFileUsed()) + } else { + invalidConfigError := "Couldn't read config file" + fmt.Println("Error: ", invalidConfigError) + log.Fatal(invalidConfigError) + os.Exit(1) } } diff --git a/cmd/sync.go b/cmd/sync.go index b6484f43..6dd2be07 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,10 +17,9 @@ package cmd import ( - "log" - "os" "time" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/vulcanize/vulcanizedb/pkg/core" @@ -54,11 +53,6 @@ Expects ethereum node to be running and requires a .toml config: }, } -const ( - pollingInterval = 7 * time.Second - validationWindow = 15 -) - func init() { rootCmd.AddCommand(syncCmd) @@ -66,7 +60,11 @@ func init() { } func backFillAllBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, missingBlocksPopulated chan int, startingBlockNumber int64) { - missingBlocksPopulated <- history.PopulateMissingBlocks(blockchain, blockRepository, startingBlockNumber) + populated, err := history.PopulateMissingBlocks(blockchain, blockRepository, startingBlockNumber) + if err != nil { + log.Error("backfillAllBlocks: error in populateMissingBlocks: ", err) + } + missingBlocksPopulated <- populated } func sync() { @@ -74,13 +72,15 @@ func sync() { defer ticker.Stop() blockChain := getBlockChain() - - lastBlock := blockChain.LastBlock().Int64() - if lastBlock == 0 { + lastBlock, err := blockChain.LastBlock() + if err != nil { + log.Error("sync: Error getting last block: ", err) + } + if lastBlock.Int64() == 0 { log.Fatal("geth initial: state sync not finished") } - if startingBlockNumber > lastBlock { - log.Fatal("starting block number > current block number") + if startingBlockNumber > lastBlock.Int64() { + log.Fatal("sync: starting block number > current block number") } db := utils.LoadPostgres(databaseConfig, blockChain.Node()) @@ -92,8 +92,11 @@ func sync() { for { select { case <-ticker.C: - window := validator.ValidateBlocks() - window.Log(os.Stdout) + window, err := validator.ValidateBlocks() + if err != nil { + log.Error("sync: error in validateBlocks: ", err) + } + log.Info(window.GetString()) case <-missingBlocksPopulated: go backFillAllBlocks(blockChain, blockRepository, missingBlocksPopulated, startingBlockNumber) } diff --git a/db/migrations/00001_create_blocks_table.sql b/db/migrations/00001_create_blocks_table.sql new file mode 100644 index 00000000..c11cf1de --- /dev/null +++ b/db/migrations/00001_create_blocks_table.sql @@ -0,0 +1,23 @@ +-- +goose Up +CREATE TABLE public.blocks ( + id SERIAL PRIMARY KEY, + difficulty BIGINT, + extra_data VARCHAR, + gas_limit BIGINT, + gas_used BIGINT, + hash VARCHAR(66), + miner VARCHAR(42), + nonce VARCHAR(20), + "number" BIGINT, + parent_hash VARCHAR(66), + reward NUMERIC, + uncles_reward NUMERIC, + "size" VARCHAR, + "time" BIGINT, + is_final BOOLEAN, + uncle_hash VARCHAR(66) +); + + +-- +goose Down +DROP TABLE public.blocks; \ No newline at end of file diff --git a/db/migrations/00002_create_full_sync_transactions_table.sql b/db/migrations/00002_create_full_sync_transactions_table.sql new file mode 100644 index 00000000..72548c95 --- /dev/null +++ b/db/migrations/00002_create_full_sync_transactions_table.sql @@ -0,0 +1,18 @@ +-- +goose Up +CREATE TABLE full_sync_transactions ( + id SERIAL PRIMARY KEY, + block_id INTEGER NOT NULL REFERENCES blocks(id) ON DELETE CASCADE, + gas_limit NUMERIC, + gas_price NUMERIC, + hash VARCHAR(66), + input_data BYTEA, + nonce NUMERIC, + raw BYTEA, + tx_from VARCHAR(66), + tx_index INTEGER, + tx_to VARCHAR(66), + "value" NUMERIC +); + +-- +goose Down +DROP TABLE full_sync_transactions; \ No newline at end of file diff --git a/db/migrations/00003_add_block_index_to_blocks.sql b/db/migrations/00003_add_block_index_to_blocks.sql new file mode 100644 index 00000000..4ce50e6e --- /dev/null +++ b/db/migrations/00003_add_block_index_to_blocks.sql @@ -0,0 +1,6 @@ +-- +goose Up +CREATE INDEX number_index ON blocks (number); + + +-- +goose Down +DROP INDEX number_index; diff --git a/db/migrations/00004_create_contracts_table.sql b/db/migrations/00004_create_contracts_table.sql new file mode 100644 index 00000000..3ff43bef --- /dev/null +++ b/db/migrations/00004_create_contracts_table.sql @@ -0,0 +1,10 @@ +-- +goose Up +CREATE TABLE watched_contracts +( + contract_id SERIAL PRIMARY KEY, + contract_abi json, + contract_hash VARCHAR(66) UNIQUE +); + +-- +goose Down +DROP TABLE watched_contracts; diff --git a/db/migrations/00005_create_nodes_table.sql b/db/migrations/00005_create_nodes_table.sql new file mode 100644 index 00000000..c2c0c7b8 --- /dev/null +++ b/db/migrations/00005_create_nodes_table.sql @@ -0,0 +1,12 @@ +-- +goose Up +CREATE TABLE nodes ( + id SERIAL PRIMARY KEY, + client_name VARCHAR, + genesis_block VARCHAR(66), + network_id NUMERIC, + node_id VARCHAR(128), + CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id) +); + +-- +goose Down +DROP TABLE nodes; diff --git a/db/migrations/1513275969_add_cascade_delete_to_blocks.up.sql b/db/migrations/00006_add_node_fk_to_blocks.sql similarity index 58% rename from db/migrations/1513275969_add_cascade_delete_to_blocks.up.sql rename to db/migrations/00006_add_node_fk_to_blocks.sql index 37ee1f18..4db8c03f 100644 --- a/db/migrations/1513275969_add_cascade_delete_to_blocks.up.sql +++ b/db/migrations/00006_add_node_fk_to_blocks.sql @@ -1,12 +1,11 @@ -BEGIN; - -ALTER TABLE blocks - DROP CONSTRAINT node_fk; - +-- +goose Up ALTER TABLE blocks + ADD COLUMN node_id INTEGER NOT NULL, ADD CONSTRAINT node_fk FOREIGN KEY (node_id) REFERENCES nodes (id) ON DELETE CASCADE; -COMMIT; \ No newline at end of file +-- +goose Down +ALTER TABLE blocks + DROP COLUMN node_id; diff --git a/db/migrations/1513029953_add_logs_table.up.sql b/db/migrations/00007_create_logs_table.sql similarity index 87% rename from db/migrations/1513029953_add_logs_table.up.sql rename to db/migrations/00007_create_logs_table.sql index a0cd805d..f85d35bd 100644 --- a/db/migrations/1513029953_add_logs_table.up.sql +++ b/db/migrations/00007_create_logs_table.sql @@ -1,3 +1,4 @@ +-- +goose Up CREATE TABLE logs ( id SERIAL PRIMARY KEY, block_number BIGINT, @@ -12,3 +13,7 @@ CREATE TABLE logs ( CONSTRAINT log_uc UNIQUE (block_number, index) ); + + +-- +goose Down +DROP TABLE logs; diff --git a/db/migrations/00008_add_node_block_number_unique_constraint_to_blocks.sql b/db/migrations/00008_add_node_block_number_unique_constraint_to_blocks.sql new file mode 100644 index 00000000..30be138d --- /dev/null +++ b/db/migrations/00008_add_node_block_number_unique_constraint_to_blocks.sql @@ -0,0 +1,7 @@ +-- +goose Up +ALTER TABLE blocks + ADD CONSTRAINT node_id_block_number_uc UNIQUE (number, node_id); + +-- +goose Down +ALTER TABLE blocks + DROP CONSTRAINT node_id_block_number_uc; diff --git a/db/migrations/00009_add_block_id_index_to_full_sync_transactions.sql b/db/migrations/00009_add_block_id_index_to_full_sync_transactions.sql new file mode 100644 index 00000000..99b2ca78 --- /dev/null +++ b/db/migrations/00009_add_block_id_index_to_full_sync_transactions.sql @@ -0,0 +1,5 @@ +-- +goose Up +CREATE INDEX block_id_index ON full_sync_transactions (block_id); + +-- +goose Down +DROP INDEX block_id_index; diff --git a/db/migrations/00010_add_node_id_index_to_blocks.sql b/db/migrations/00010_add_node_id_index_to_blocks.sql new file mode 100644 index 00000000..bab71f97 --- /dev/null +++ b/db/migrations/00010_add_node_id_index_to_blocks.sql @@ -0,0 +1,5 @@ +-- +goose Up +CREATE INDEX node_id_index ON blocks (node_id); + +-- +goose Down +DROP INDEX node_id_index; diff --git a/db/migrations/00011_add_tx_to_index_to_full_sync_transactions.sql b/db/migrations/00011_add_tx_to_index_to_full_sync_transactions.sql new file mode 100644 index 00000000..cf2977d1 --- /dev/null +++ b/db/migrations/00011_add_tx_to_index_to_full_sync_transactions.sql @@ -0,0 +1,5 @@ +-- +goose Up +CREATE INDEX tx_to_index ON full_sync_transactions(tx_to); + +-- +goose Down +DROP INDEX tx_to_index; diff --git a/db/migrations/00012_add_tx_from_index_to_full_sync_transactions.sql b/db/migrations/00012_add_tx_from_index_to_full_sync_transactions.sql new file mode 100644 index 00000000..fa6f0543 --- /dev/null +++ b/db/migrations/00012_add_tx_from_index_to_full_sync_transactions.sql @@ -0,0 +1,5 @@ +-- +goose Up +CREATE INDEX tx_from_index ON full_sync_transactions(tx_from); + +-- +goose Down +DROP INDEX tx_from_index; diff --git a/db/migrations/00013_create_receipts_table.sql b/db/migrations/00013_create_receipts_table.sql new file mode 100644 index 00000000..2864f226 --- /dev/null +++ b/db/migrations/00013_create_receipts_table.sql @@ -0,0 +1,16 @@ +-- +goose Up +CREATE TABLE full_sync_receipts +( + id SERIAL PRIMARY KEY, + transaction_id INTEGER NOT NULL REFERENCES full_sync_transactions (id) ON DELETE CASCADE, + contract_address VARCHAR(42), + cumulative_gas_used NUMERIC, + gas_used NUMERIC, + state_root VARCHAR(66), + status INTEGER, + tx_hash VARCHAR(66) +); + + +-- +goose Down +DROP TABLE full_sync_receipts; diff --git a/db/migrations/00014_add_transaction_id_index_to_receipts.sql b/db/migrations/00014_add_transaction_id_index_to_receipts.sql new file mode 100644 index 00000000..04ff38b7 --- /dev/null +++ b/db/migrations/00014_add_transaction_id_index_to_receipts.sql @@ -0,0 +1,5 @@ +-- +goose Up +CREATE INDEX transaction_id_index ON full_sync_receipts (transaction_id); + +-- +goose Down +DROP INDEX transaction_id_index; diff --git a/db/migrations/00015_add_receipts_fk_to_logs.sql b/db/migrations/00015_add_receipts_fk_to_logs.sql new file mode 100644 index 00000000..9301e545 --- /dev/null +++ b/db/migrations/00015_add_receipts_fk_to_logs.sql @@ -0,0 +1,23 @@ +-- +goose Up +ALTER TABLE logs + DROP CONSTRAINT log_uc; + +ALTER TABLE logs + ADD COLUMN receipt_id INT; + +ALTER TABLE logs + ADD CONSTRAINT receipts_fk +FOREIGN KEY (receipt_id) +REFERENCES full_sync_receipts (id) +ON DELETE CASCADE; + + +-- +goose Down +ALTER TABLE logs + DROP CONSTRAINT receipts_fk; + +ALTER TABLE logs + DROP COLUMN receipt_id; + +ALTER TABLE logs + ADD CONSTRAINT log_uc UNIQUE (block_number, index); diff --git a/db/migrations/1516648743_add_log_filters.up.sql b/db/migrations/00016_create_log_filters.sql similarity index 86% rename from db/migrations/1516648743_add_log_filters.up.sql rename to db/migrations/00016_create_log_filters.sql index 100a5718..0367f5e5 100644 --- a/db/migrations/1516648743_add_log_filters.up.sql +++ b/db/migrations/00016_create_log_filters.sql @@ -1,3 +1,4 @@ +-- +goose Up CREATE TABLE log_filters ( id SERIAL, name VARCHAR NOT NULL CHECK (name <> ''), @@ -9,4 +10,7 @@ CREATE TABLE log_filters ( topic2 VARCHAR(66), topic3 VARCHAR(66), CONSTRAINT name_uc UNIQUE (name) -); \ No newline at end of file +); + +-- +goose Down +DROP TABLE log_filters; diff --git a/db/migrations/1516653373_add_watched_event_logs.up.sql b/db/migrations/00017_create_watched_event_logs.sql similarity index 90% rename from db/migrations/1516653373_add_watched_event_logs.up.sql rename to db/migrations/00017_create_watched_event_logs.sql index 3bba916f..ae17ee08 100644 --- a/db/migrations/1516653373_add_watched_event_logs.up.sql +++ b/db/migrations/00017_create_watched_event_logs.sql @@ -1,3 +1,4 @@ +-- +goose Up CREATE VIEW block_stats AS SELECT max(block_number) AS max_block, @@ -26,4 +27,8 @@ CREATE VIEW watched_event_logs AS WHERE (log_filters.topic0 = logs.topic0 OR log_filters.topic0 ISNULL) AND (log_filters.topic1 = logs.topic1 OR log_filters.topic1 ISNULL) AND (log_filters.topic2 = logs.topic2 OR log_filters.topic2 ISNULL) - AND (log_filters.topic3 = logs.topic3 OR log_filters.topic3 ISNULL); \ No newline at end of file + AND (log_filters.topic3 = logs.topic3 OR log_filters.topic3 ISNULL); + +-- +goose Down +DROP VIEW watched_event_logs; +DROP VIEW block_stats; diff --git a/db/migrations/00018_update_log_filters_to_block_constraint.sql b/db/migrations/00018_update_log_filters_to_block_constraint.sql new file mode 100644 index 00000000..512a44db --- /dev/null +++ b/db/migrations/00018_update_log_filters_to_block_constraint.sql @@ -0,0 +1,14 @@ +-- +goose Up +ALTER TABLE log_filters + DROP CONSTRAINT log_filters_from_block_check1; + +ALTER TABLE log_filters + ADD CONSTRAINT log_filters_to_block_check CHECK (to_block >= 0); + + +-- +goose Down +ALTER TABLE log_filters + DROP CONSTRAINT log_filters_to_block_check; + +ALTER TABLE log_filters + ADD CONSTRAINT log_filters_from_block_check1 CHECK (to_block >= 0); diff --git a/db/migrations/00019_rename_node_table.sql b/db/migrations/00019_rename_node_table.sql new file mode 100644 index 00000000..061fda57 --- /dev/null +++ b/db/migrations/00019_rename_node_table.sql @@ -0,0 +1,43 @@ +-- +goose Up +ALTER TABLE public.nodes RENAME TO eth_nodes; + +ALTER TABLE public.eth_nodes RENAME COLUMN node_id TO eth_node_id; + +ALTER TABLE public.eth_nodes DROP CONSTRAINT node_uc; +ALTER TABLE public.eth_nodes + ADD CONSTRAINT eth_node_uc UNIQUE (genesis_block, network_id, eth_node_id); + +ALTER TABLE public.blocks RENAME COLUMN node_id TO eth_node_id; + +ALTER TABLE public.blocks DROP CONSTRAINT node_id_block_number_uc; +ALTER TABLE public.blocks + ADD CONSTRAINT eth_node_id_block_number_uc UNIQUE (number, eth_node_id); + +ALTER TABLE public.blocks DROP CONSTRAINT node_fk; +ALTER TABLE public.blocks + ADD CONSTRAINT node_fk +FOREIGN KEY (eth_node_id) REFERENCES eth_nodes (id) ON DELETE CASCADE; + + +-- +goose Down +ALTER TABLE public.eth_nodes + RENAME TO nodes; + +ALTER TABLE public.nodes + RENAME COLUMN eth_node_id TO node_id; + +ALTER TABLE public.nodes + DROP CONSTRAINT eth_node_uc; +ALTER TABLE public.nodes + ADD CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id); + +ALTER TABLE public.blocks RENAME COLUMN eth_node_id TO node_id; + +ALTER TABLE public.blocks DROP CONSTRAINT eth_node_id_block_number_uc; +ALTER TABLE public.blocks + ADD CONSTRAINT node_id_block_number_uc UNIQUE (number, node_id); + +ALTER TABLE public.blocks DROP CONSTRAINT node_fk; +ALTER TABLE public.blocks + ADD CONSTRAINT node_fk +FOREIGN KEY (node_id) REFERENCES nodes (id) ON DELETE CASCADE; diff --git a/db/migrations/00020_associate_receipts_with_blocks.sql b/db/migrations/00020_associate_receipts_with_blocks.sql new file mode 100644 index 00000000..b60aa2d4 --- /dev/null +++ b/db/migrations/00020_associate_receipts_with_blocks.sql @@ -0,0 +1,44 @@ +-- +goose Up +ALTER TABLE full_sync_receipts + ADD COLUMN block_id INT; + +UPDATE full_sync_receipts + SET block_id = ( + SELECT block_id FROM full_sync_transactions WHERE full_sync_transactions.id = full_sync_receipts.transaction_id + ); + +ALTER TABLE full_sync_receipts + ALTER COLUMN block_id SET NOT NULL; + +ALTER TABLE full_sync_receipts + ADD CONSTRAINT blocks_fk +FOREIGN KEY (block_id) +REFERENCES blocks (id) +ON DELETE CASCADE; + +ALTER TABLE full_sync_receipts + DROP COLUMN transaction_id; + + +-- +goose Down +ALTER TABLE full_sync_receipts + ADD COLUMN transaction_id INT; + +CREATE INDEX transaction_id_index ON full_sync_receipts (transaction_id); + +UPDATE full_sync_receipts + SET transaction_id = ( + SELECT id FROM full_sync_transactions WHERE full_sync_transactions.hash = full_sync_receipts.tx_hash + ); + +ALTER TABLE full_sync_receipts + ALTER COLUMN transaction_id SET NOT NULL; + +ALTER TABLE full_sync_receipts + ADD CONSTRAINT transaction_fk +FOREIGN KEY (transaction_id) +REFERENCES full_sync_transactions (id) +ON DELETE CASCADE; + +ALTER TABLE full_sync_receipts + DROP COLUMN block_id; diff --git a/db/migrations/1525464568_add_eth_node_fingerprint_to_blocks.up.sql b/db/migrations/00021_add_eth_node_fingerprint_to_blocks.sql similarity index 76% rename from db/migrations/1525464568_add_eth_node_fingerprint_to_blocks.up.sql rename to db/migrations/00021_add_eth_node_fingerprint_to_blocks.sql index 947db2c7..5c48c03e 100644 --- a/db/migrations/1525464568_add_eth_node_fingerprint_to_blocks.up.sql +++ b/db/migrations/00021_add_eth_node_fingerprint_to_blocks.sql @@ -1,5 +1,4 @@ -BEGIN; - +-- +goose Up ALTER TABLE blocks ADD COLUMN eth_node_fingerprint VARCHAR(128); @@ -11,4 +10,7 @@ UPDATE blocks ALTER TABLE blocks ALTER COLUMN eth_node_fingerprint SET NOT NULL; -COMMIT; \ No newline at end of file + +-- +goose Down +ALTER TABLE blocks + DROP COLUMN eth_node_fingerprint; diff --git a/db/migrations/00022_create_headers_table.sql b/db/migrations/00022_create_headers_table.sql new file mode 100644 index 00000000..925c202b --- /dev/null +++ b/db/migrations/00022_create_headers_table.sql @@ -0,0 +1,17 @@ +-- +goose Up +CREATE TABLE public.headers ( + id SERIAL PRIMARY KEY, + hash VARCHAR(66), + block_number BIGINT, + raw JSONB, + block_timestamp NUMERIC, + eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE, + eth_node_fingerprint VARCHAR(128) +); + +-- Index is removed when table is +CREATE INDEX headers_block_number ON public.headers (block_number); + + +-- +goose Down +DROP TABLE public.headers; diff --git a/db/migrations/1532468317_create_checked_headers_table.up.sql b/db/migrations/00023_create_checked_headers_table.sql similarity index 71% rename from db/migrations/1532468317_create_checked_headers_table.up.sql rename to db/migrations/00023_create_checked_headers_table.sql index 638d759c..acf0fbdb 100644 --- a/db/migrations/1532468317_create_checked_headers_table.up.sql +++ b/db/migrations/00023_create_checked_headers_table.sql @@ -1,4 +1,8 @@ +-- +goose Up CREATE TABLE public.checked_headers ( id SERIAL PRIMARY KEY, header_id INTEGER UNIQUE NOT NULL REFERENCES headers (id) ON DELETE CASCADE -); \ No newline at end of file +); + +-- +goose Down +DROP TABLE public.checked_headers; diff --git a/db/migrations/00024_create_queued_storage.sql b/db/migrations/00024_create_queued_storage.sql new file mode 100644 index 00000000..bd5e468e --- /dev/null +++ b/db/migrations/00024_create_queued_storage.sql @@ -0,0 +1,12 @@ +-- +goose Up +CREATE TABLE public.queued_storage ( + id SERIAL PRIMARY KEY, + block_height BIGINT, + block_hash BYTEA, + contract BYTEA, + storage_key BYTEA, + storage_value BYTEA +); + +-- +goose Down +DROP TABLE public.queued_storage; diff --git a/db/migrations/00025_create_light_sync_transactions_table.sql b/db/migrations/00025_create_light_sync_transactions_table.sql new file mode 100644 index 00000000..2567876e --- /dev/null +++ b/db/migrations/00025_create_light_sync_transactions_table.sql @@ -0,0 +1,19 @@ +-- +goose Up +CREATE TABLE light_sync_transactions ( + id SERIAL PRIMARY KEY, + header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE, + hash VARCHAR(66), + gas_limit NUMERIC, + gas_price NUMERIC, + input_data BYTEA, + nonce NUMERIC, + raw BYTEA, + tx_from VARCHAR(44), + tx_index INTEGER, + tx_to VARCHAR(44), + "value" NUMERIC, + UNIQUE (header_id, hash) +); + +-- +goose Down +DROP TABLE light_sync_transactions; diff --git a/db/migrations/00026_create_light_sync_receipts_table.sql b/db/migrations/00026_create_light_sync_receipts_table.sql new file mode 100644 index 00000000..224a2440 --- /dev/null +++ b/db/migrations/00026_create_light_sync_receipts_table.sql @@ -0,0 +1,18 @@ +-- +goose Up +CREATE TABLE light_sync_receipts( + id SERIAL PRIMARY KEY, + transaction_id INTEGER NOT NULL REFERENCES light_sync_transactions(id) ON DELETE CASCADE, + header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE, + contract_address VARCHAR(42), + cumulative_gas_used NUMERIC, + gas_used NUMERIC, + state_root VARCHAR(66), + status INTEGER, + tx_hash VARCHAR(66), + rlp BYTEA, + UNIQUE(header_id, transaction_id) +); + + +-- +goose Down +DROP TABLE light_sync_receipts; diff --git a/db/migrations/00027_create_uncles_table.sql b/db/migrations/00027_create_uncles_table.sql new file mode 100644 index 00000000..9ec0ffa7 --- /dev/null +++ b/db/migrations/00027_create_uncles_table.sql @@ -0,0 +1,16 @@ +-- +goose Up +CREATE TABLE public.uncles ( + id SERIAL PRIMARY KEY, + hash VARCHAR(66) NOT NULL, + block_id INTEGER NOT NULL REFERENCES blocks (id) ON DELETE CASCADE, + reward NUMERIC NOT NULL, + miner VARCHAR(42) NOT NULL, + raw JSONB, + block_timestamp NUMERIC, + eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE, + eth_node_fingerprint VARCHAR(128), + UNIQUE (block_id, hash) +); + +-- +goose Down +DROP TABLE public.uncles; diff --git a/db/migrations/1508943247_create_blocks_table.down.sql b/db/migrations/1508943247_create_blocks_table.down.sql deleted file mode 100644 index 8ea49617..00000000 --- a/db/migrations/1508943247_create_blocks_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE public.blocks diff --git a/db/migrations/1508943247_create_blocks_table.up.sql b/db/migrations/1508943247_create_blocks_table.up.sql deleted file mode 100644 index 398bc2c7..00000000 --- a/db/migrations/1508943247_create_blocks_table.up.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE public.blocks -( - block_number BIGINT -) diff --git a/db/migrations/1508965325_add_columns_to_blocks.down.sql b/db/migrations/1508965325_add_columns_to_blocks.down.sql deleted file mode 100644 index 7624ef13..00000000 --- a/db/migrations/1508965325_add_columns_to_blocks.down.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN block_gaslimit, - DROP COLUMN block_gasused, - DROP COLUMN block_time; - diff --git a/db/migrations/1508965325_add_columns_to_blocks.up.sql b/db/migrations/1508965325_add_columns_to_blocks.up.sql deleted file mode 100644 index 65c6262e..00000000 --- a/db/migrations/1508965325_add_columns_to_blocks.up.sql +++ /dev/null @@ -1,4 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN block_gaslimit DOUBLE PRECISION, - ADD COLUMN block_gasused DOUBLE PRECISION, - ADD COLUMN block_time DOUBLE PRECISION; diff --git a/db/migrations/1509119369_initial_transaction_table.down.sql b/db/migrations/1509119369_initial_transaction_table.down.sql deleted file mode 100644 index bd4e7b76..00000000 --- a/db/migrations/1509119369_initial_transaction_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE transactions \ No newline at end of file diff --git a/db/migrations/1509119369_initial_transaction_table.up.sql b/db/migrations/1509119369_initial_transaction_table.up.sql deleted file mode 100644 index d73b09fe..00000000 --- a/db/migrations/1509119369_initial_transaction_table.up.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE transactions -( - id SERIAL PRIMARY KEY, - tx_hash VARCHAR(66), - tx_nonce NUMERIC, - tx_to varchar(66), - tx_gaslimit NUMERIC, - tx_gasprice NUMERIC, - tx_value NUMERIC -) \ No newline at end of file diff --git a/db/migrations/1509391861_add_primary_key_to_blocks.down.sql b/db/migrations/1509391861_add_primary_key_to_blocks.down.sql deleted file mode 100644 index 8840f9d2..00000000 --- a/db/migrations/1509391861_add_primary_key_to_blocks.down.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE blocks DROP id \ No newline at end of file diff --git a/db/migrations/1509391861_add_primary_key_to_blocks.up.sql b/db/migrations/1509391861_add_primary_key_to_blocks.up.sql deleted file mode 100644 index e2b68955..00000000 --- a/db/migrations/1509391861_add_primary_key_to_blocks.up.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE blocks ADD COLUMN id SERIAL PRIMARY KEY \ No newline at end of file diff --git a/db/migrations/1509460207_add_block_id_to_transactions.down.sql b/db/migrations/1509460207_add_block_id_to_transactions.down.sql deleted file mode 100644 index ef380fe4..00000000 --- a/db/migrations/1509460207_add_block_id_to_transactions.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE transactions - DROP COLUMN block_id \ No newline at end of file diff --git a/db/migrations/1509460207_add_block_id_to_transactions.up.sql b/db/migrations/1509460207_add_block_id_to_transactions.up.sql deleted file mode 100644 index 0132dbc7..00000000 --- a/db/migrations/1509460207_add_block_id_to_transactions.up.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE transactions - ADD COLUMN block_id INTEGER NOT NULL, - ADD CONSTRAINT fk_test - FOREIGN KEY (block_id) - REFERENCES blocks (id) diff --git a/db/migrations/1509484288_add_block_index.down.sql b/db/migrations/1509484288_add_block_index.down.sql deleted file mode 100644 index 9a1d42fb..00000000 --- a/db/migrations/1509484288_add_block_index.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX block_number_index; \ No newline at end of file diff --git a/db/migrations/1509484288_add_block_index.up.sql b/db/migrations/1509484288_add_block_index.up.sql deleted file mode 100644 index a4710b9c..00000000 --- a/db/migrations/1509484288_add_block_index.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX block_number_index ON blocks (block_number); diff --git a/db/migrations/1509633481_add_blocks_columns.down.sql b/db/migrations/1509633481_add_blocks_columns.down.sql deleted file mode 100644 index 74f2f396..00000000 --- a/db/migrations/1509633481_add_blocks_columns.down.sql +++ /dev/null @@ -1,7 +0,0 @@ -ALTER TABLE blocks - Drop COLUMN block_difficulty, - Drop COLUMN block_hash, - drop COLUMN block_nonce, - drop COLUMN block_parenthash, - drop COLUMN block_size, - drop COLUMN uncle_hash \ No newline at end of file diff --git a/db/migrations/1509633481_add_blocks_columns.up.sql b/db/migrations/1509633481_add_blocks_columns.up.sql deleted file mode 100644 index d373b00f..00000000 --- a/db/migrations/1509633481_add_blocks_columns.up.sql +++ /dev/null @@ -1,7 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN block_difficulty BIGINT, - ADD COLUMN block_hash VARCHAR(66), - ADD COLUMN block_nonce VARCHAR(20), - ADD COLUMN block_parenthash VARCHAR(66), - ADD COLUMN block_size BIGINT, - ADD COLUMN uncle_hash VARCHAR(66) diff --git a/db/migrations/1510257608_add_contracts_table.down.sql b/db/migrations/1510257608_add_contracts_table.down.sql deleted file mode 100644 index 3762ad16..00000000 --- a/db/migrations/1510257608_add_contracts_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE watched_contracts \ No newline at end of file diff --git a/db/migrations/1510257608_add_contracts_table.up.sql b/db/migrations/1510257608_add_contracts_table.up.sql deleted file mode 100644 index c6dfe39a..00000000 --- a/db/migrations/1510257608_add_contracts_table.up.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE watched_contracts -( - contract_id SERIAL PRIMARY KEY, - contract_hash VARCHAR(66) -) \ No newline at end of file diff --git a/db/migrations/1510262915_add_from_to_transactions.down.sql b/db/migrations/1510262915_add_from_to_transactions.down.sql deleted file mode 100644 index 1f323136..00000000 --- a/db/migrations/1510262915_add_from_to_transactions.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE transactions - DROP COLUMN tx_from diff --git a/db/migrations/1510262915_add_from_to_transactions.up.sql b/db/migrations/1510262915_add_from_to_transactions.up.sql deleted file mode 100644 index 2222e866..00000000 --- a/db/migrations/1510262915_add_from_to_transactions.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE transactions - ADD COLUMN tx_from VARCHAR(66) diff --git a/db/migrations/1512417153_add_abi_to_watched_contracts.down.sql b/db/migrations/1512417153_add_abi_to_watched_contracts.down.sql deleted file mode 100644 index e22ac41f..00000000 --- a/db/migrations/1512417153_add_abi_to_watched_contracts.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE watched_contracts - DROP COLUMN contract_abi; \ No newline at end of file diff --git a/db/migrations/1512417153_add_abi_to_watched_contracts.up.sql b/db/migrations/1512417153_add_abi_to_watched_contracts.up.sql deleted file mode 100644 index 4212ee9f..00000000 --- a/db/migrations/1512417153_add_abi_to_watched_contracts.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE watched_contracts - ADD COLUMN contract_abi json; \ No newline at end of file diff --git a/db/migrations/1512504078_add_nodes_table.down.sql b/db/migrations/1512504078_add_nodes_table.down.sql deleted file mode 100644 index c095b945..00000000 --- a/db/migrations/1512504078_add_nodes_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE nodes; \ No newline at end of file diff --git a/db/migrations/1512504078_add_nodes_table.up.sql b/db/migrations/1512504078_add_nodes_table.up.sql deleted file mode 100644 index 06fa91d9..00000000 --- a/db/migrations/1512504078_add_nodes_table.up.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE nodes ( - id SERIAL PRIMARY KEY, - genesis_block VARCHAR(66), - network_id NUMERIC, - CONSTRAINT node_uc UNIQUE (genesis_block, network_id) -); \ No newline at end of file diff --git a/db/migrations/1512507280_add_node_fk_to_blocks.down.sql b/db/migrations/1512507280_add_node_fk_to_blocks.down.sql deleted file mode 100644 index 97e87635..00000000 --- a/db/migrations/1512507280_add_node_fk_to_blocks.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN node_id; \ No newline at end of file diff --git a/db/migrations/1512507280_add_node_fk_to_blocks.up.sql b/db/migrations/1512507280_add_node_fk_to_blocks.up.sql deleted file mode 100644 index 6e03577c..00000000 --- a/db/migrations/1512507280_add_node_fk_to_blocks.up.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN node_id INTEGER NOT NULL, - ADD CONSTRAINT node_fk -FOREIGN KEY (node_id) -REFERENCES nodes (id); \ No newline at end of file diff --git a/db/migrations/1512595007_add_contract_hash_constraint_to_watched_contracts.down.sql b/db/migrations/1512595007_add_contract_hash_constraint_to_watched_contracts.down.sql deleted file mode 100644 index 70672822..00000000 --- a/db/migrations/1512595007_add_contract_hash_constraint_to_watched_contracts.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE watched_contracts - DROP CONSTRAINT contract_hash_uc; \ No newline at end of file diff --git a/db/migrations/1512595007_add_contract_hash_constraint_to_watched_contracts.up.sql b/db/migrations/1512595007_add_contract_hash_constraint_to_watched_contracts.up.sql deleted file mode 100644 index f27a54c0..00000000 --- a/db/migrations/1512595007_add_contract_hash_constraint_to_watched_contracts.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE watched_contracts - ADD CONSTRAINT contract_hash_uc UNIQUE (contract_hash); diff --git a/db/migrations/1513029953_add_logs_table.down.sql b/db/migrations/1513029953_add_logs_table.down.sql deleted file mode 100644 index c3866786..00000000 --- a/db/migrations/1513029953_add_logs_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE logs; \ No newline at end of file diff --git a/db/migrations/1513192766_add_cascade_delete_to_transactions.down.sql b/db/migrations/1513192766_add_cascade_delete_to_transactions.down.sql deleted file mode 100644 index 6546f2be..00000000 --- a/db/migrations/1513192766_add_cascade_delete_to_transactions.down.sql +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN; - -ALTER TABLE transactions - DROP CONSTRAINT blocks_fk; - -ALTER TABLE transactions - ADD CONSTRAINT fk_test -FOREIGN KEY (block_id) -REFERENCES blocks (id); - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1513192766_add_cascade_delete_to_transactions.up.sql b/db/migrations/1513192766_add_cascade_delete_to_transactions.up.sql deleted file mode 100644 index 50ca360c..00000000 --- a/db/migrations/1513192766_add_cascade_delete_to_transactions.up.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -ALTER TABLE transactions - DROP CONSTRAINT fk_test; - -ALTER TABLE transactions - ADD CONSTRAINT blocks_fk -FOREIGN KEY (block_id) -REFERENCES blocks (id) -ON DELETE CASCADE; - -COMMIT; diff --git a/db/migrations/1513275969_add_cascade_delete_to_blocks.down.sql b/db/migrations/1513275969_add_cascade_delete_to_blocks.down.sql deleted file mode 100644 index da798ece..00000000 --- a/db/migrations/1513275969_add_cascade_delete_to_blocks.down.sql +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN; - -ALTER TABLE blocks - DROP CONSTRAINT node_fk; - -ALTER TABLE blocks - ADD CONSTRAINT node_fk -FOREIGN KEY (node_id) -REFERENCES nodes (id); - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1513613036_add_is_final_to_blocks.down.sql b/db/migrations/1513613036_add_is_final_to_blocks.down.sql deleted file mode 100644 index 5a0b113c..00000000 --- a/db/migrations/1513613036_add_is_final_to_blocks.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN is_final; \ No newline at end of file diff --git a/db/migrations/1513613036_add_is_final_to_blocks.up.sql b/db/migrations/1513613036_add_is_final_to_blocks.up.sql deleted file mode 100644 index 667954ed..00000000 --- a/db/migrations/1513613036_add_is_final_to_blocks.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN is_final BOOLEAN; \ No newline at end of file diff --git a/db/migrations/1513781105_add_unique_constraint_blocks_node.down.sql b/db/migrations/1513781105_add_unique_constraint_blocks_node.down.sql deleted file mode 100644 index d72b7e91..00000000 --- a/db/migrations/1513781105_add_unique_constraint_blocks_node.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - DROP CONSTRAINT node_id_block_number_uc; \ No newline at end of file diff --git a/db/migrations/1513781105_add_unique_constraint_blocks_node.up.sql b/db/migrations/1513781105_add_unique_constraint_blocks_node.up.sql deleted file mode 100644 index 99c9293c..00000000 --- a/db/migrations/1513781105_add_unique_constraint_blocks_node.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - ADD CONSTRAINT node_id_block_number_uc UNIQUE (block_number, node_id); \ No newline at end of file diff --git a/db/migrations/1513783615_add_block_id_index_on_transactions_table.down.sql b/db/migrations/1513783615_add_block_id_index_on_transactions_table.down.sql deleted file mode 100644 index 214e4604..00000000 --- a/db/migrations/1513783615_add_block_id_index_on_transactions_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX block_id_index; \ No newline at end of file diff --git a/db/migrations/1513783615_add_block_id_index_on_transactions_table.up.sql b/db/migrations/1513783615_add_block_id_index_on_transactions_table.up.sql deleted file mode 100644 index 1e375eec..00000000 --- a/db/migrations/1513783615_add_block_id_index_on_transactions_table.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX block_id_index ON transactions (block_id); \ No newline at end of file diff --git a/db/migrations/1513783944_add_node_id_index_on_blocks_table.down.sql b/db/migrations/1513783944_add_node_id_index_on_blocks_table.down.sql deleted file mode 100644 index f8621c94..00000000 --- a/db/migrations/1513783944_add_node_id_index_on_blocks_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX node_id_index; \ No newline at end of file diff --git a/db/migrations/1513783944_add_node_id_index_on_blocks_table.up.sql b/db/migrations/1513783944_add_node_id_index_on_blocks_table.up.sql deleted file mode 100644 index a60623a4..00000000 --- a/db/migrations/1513783944_add_node_id_index_on_blocks_table.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX node_id_index ON blocks (node_id); \ No newline at end of file diff --git a/db/migrations/1513805096_tx_to_index.down.sql b/db/migrations/1513805096_tx_to_index.down.sql deleted file mode 100644 index cd501119..00000000 --- a/db/migrations/1513805096_tx_to_index.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX tx_to_index; \ No newline at end of file diff --git a/db/migrations/1513805096_tx_to_index.up.sql b/db/migrations/1513805096_tx_to_index.up.sql deleted file mode 100644 index d51eb6f2..00000000 --- a/db/migrations/1513805096_tx_to_index.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX tx_to_index ON transactions(tx_to); \ No newline at end of file diff --git a/db/migrations/1513805100_tx_from_index.down.sql b/db/migrations/1513805100_tx_from_index.down.sql deleted file mode 100644 index 5e0d00a0..00000000 --- a/db/migrations/1513805100_tx_from_index.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX tx_from_index; \ No newline at end of file diff --git a/db/migrations/1513805100_tx_from_index.up.sql b/db/migrations/1513805100_tx_from_index.up.sql deleted file mode 100644 index d56c117d..00000000 --- a/db/migrations/1513805100_tx_from_index.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX tx_from_index ON transactions(tx_from); \ No newline at end of file diff --git a/db/migrations/1514392444_add_miner.down.sql b/db/migrations/1514392444_add_miner.down.sql deleted file mode 100644 index 417ad684..00000000 --- a/db/migrations/1514392444_add_miner.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN block_miner; \ No newline at end of file diff --git a/db/migrations/1514392444_add_miner.up.sql b/db/migrations/1514392444_add_miner.up.sql deleted file mode 100644 index 2667365b..00000000 --- a/db/migrations/1514392444_add_miner.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN block_miner VARCHAR(42); \ No newline at end of file diff --git a/db/migrations/1514397430_add_extra_data.down.sql b/db/migrations/1514397430_add_extra_data.down.sql deleted file mode 100644 index 0da3cdeb..00000000 --- a/db/migrations/1514397430_add_extra_data.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN block_extra_data; \ No newline at end of file diff --git a/db/migrations/1514397430_add_extra_data.up.sql b/db/migrations/1514397430_add_extra_data.up.sql deleted file mode 100644 index 71839271..00000000 --- a/db/migrations/1514397430_add_extra_data.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN block_extra_data VARCHAR; \ No newline at end of file diff --git a/db/migrations/1514476024_add_block_reward_uncle_reward.down.sql b/db/migrations/1514476024_add_block_reward_uncle_reward.down.sql deleted file mode 100644 index ec96263f..00000000 --- a/db/migrations/1514476024_add_block_reward_uncle_reward.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN block_reward, - DROP COLUMN block_uncles_reward; diff --git a/db/migrations/1514476024_add_block_reward_uncle_reward.up.sql b/db/migrations/1514476024_add_block_reward_uncle_reward.up.sql deleted file mode 100644 index 447e53a6..00000000 --- a/db/migrations/1514476024_add_block_reward_uncle_reward.up.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE blocks - ADD COLUMN block_reward NUMERIC, - ADD COLUMN block_uncles_reward NUMERIC; diff --git a/db/migrations/1514502281_add_data_input_to_transactions.down.sql b/db/migrations/1514502281_add_data_input_to_transactions.down.sql deleted file mode 100644 index cbaddf86..00000000 --- a/db/migrations/1514502281_add_data_input_to_transactions.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE transactions - DROP COLUMN tx_input_data; \ No newline at end of file diff --git a/db/migrations/1514502281_add_data_input_to_transactions.up.sql b/db/migrations/1514502281_add_data_input_to_transactions.up.sql deleted file mode 100644 index 963d0c75..00000000 --- a/db/migrations/1514502281_add_data_input_to_transactions.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE transactions - ADD COLUMN tx_input_data VARCHAR; \ No newline at end of file diff --git a/db/migrations/1514564898_create_receipts_table.down.sql b/db/migrations/1514564898_create_receipts_table.down.sql deleted file mode 100644 index 4009cc9f..00000000 --- a/db/migrations/1514564898_create_receipts_table.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE receipts; - diff --git a/db/migrations/1514564898_create_receipts_table.up.sql b/db/migrations/1514564898_create_receipts_table.up.sql deleted file mode 100644 index 2c4fd2f8..00000000 --- a/db/migrations/1514564898_create_receipts_table.up.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE receipts -( - id SERIAL PRIMARY KEY, - transaction_id INTEGER NOT NULL, - contract_address VARCHAR(42), - cumulative_gas_used NUMERIC, - gas_used NUMERIC, - state_root VARCHAR(66), - status INTEGER, - tx_hash VARCHAR(66), - CONSTRAINT transaction_fk FOREIGN KEY (transaction_id) - REFERENCES transactions (id) - ON DELETE CASCADE -); - - diff --git a/db/migrations/1514932205_add_transaction_id_index_to_receipts.down.sql b/db/migrations/1514932205_add_transaction_id_index_to_receipts.down.sql deleted file mode 100644 index 7fbd62b2..00000000 --- a/db/migrations/1514932205_add_transaction_id_index_to_receipts.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX transaction_id_index; diff --git a/db/migrations/1514932205_add_transaction_id_index_to_receipts.up.sql b/db/migrations/1514932205_add_transaction_id_index_to_receipts.up.sql deleted file mode 100644 index 5ae39214..00000000 --- a/db/migrations/1514932205_add_transaction_id_index_to_receipts.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX transaction_id_index ON receipts (transaction_id); \ No newline at end of file diff --git a/db/migrations/1515613181_add_fields_to_node.down.sql b/db/migrations/1515613181_add_fields_to_node.down.sql deleted file mode 100644 index 66ffb290..00000000 --- a/db/migrations/1515613181_add_fields_to_node.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE nodes - DROP COLUMN node_id, - DROP COLUMN client_name; \ No newline at end of file diff --git a/db/migrations/1515613181_add_fields_to_node.up.sql b/db/migrations/1515613181_add_fields_to_node.up.sql deleted file mode 100644 index 5396e26a..00000000 --- a/db/migrations/1515613181_add_fields_to_node.up.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE nodes - ADD COLUMN node_id VARCHAR(128), - ADD COLUMN client_name VARCHAR; \ No newline at end of file diff --git a/db/migrations/1515613715_update_node_index.down.sql b/db/migrations/1515613715_update_node_index.down.sql deleted file mode 100644 index 5c252c4b..00000000 --- a/db/migrations/1515613715_update_node_index.down.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN; - -ALTER TABLE nodes - DROP CONSTRAINT node_uc; - -ALTER TABLE nodes - ADD CONSTRAINT node_uc UNIQUE (genesis_block, network_id); - -COMMIT; diff --git a/db/migrations/1515613715_update_node_index.up.sql b/db/migrations/1515613715_update_node_index.up.sql deleted file mode 100644 index 6abf9347..00000000 --- a/db/migrations/1515613715_update_node_index.up.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN; - -ALTER TABLE nodes - DROP CONSTRAINT node_uc; - -ALTER TABLE nodes - ADD CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id); - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1516050071_add_log_fk_constraint.down.sql b/db/migrations/1516050071_add_log_fk_constraint.down.sql deleted file mode 100644 index 55779b51..00000000 --- a/db/migrations/1516050071_add_log_fk_constraint.down.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -ALTER TABLE logs - DROP CONSTRAINT receipts_fk; - -ALTER TABLE logs - DROP COLUMN receipt_id; - -ALTER TABLE logs - ADD CONSTRAINT log_uc UNIQUE (block_number, index); - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1516050071_add_log_fk_constraint.up.sql b/db/migrations/1516050071_add_log_fk_constraint.up.sql deleted file mode 100644 index 60733b71..00000000 --- a/db/migrations/1516050071_add_log_fk_constraint.up.sql +++ /dev/null @@ -1,14 +0,0 @@ -BEGIN; -ALTER TABLE logs - DROP CONSTRAINT log_uc; - -ALTER TABLE logs - ADD COLUMN receipt_id INT; - -ALTER TABLE logs - ADD CONSTRAINT receipts_fk -FOREIGN KEY (receipt_id) -REFERENCES receipts (id) -ON DELETE CASCADE; - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1516648743_add_log_filters.down.sql b/db/migrations/1516648743_add_log_filters.down.sql deleted file mode 100644 index a28adeee..00000000 --- a/db/migrations/1516648743_add_log_filters.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE log_filters; \ No newline at end of file diff --git a/db/migrations/1516653373_add_watched_event_logs.down.sql b/db/migrations/1516653373_add_watched_event_logs.down.sql deleted file mode 100644 index 294d7bfe..00000000 --- a/db/migrations/1516653373_add_watched_event_logs.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP VIEW watched_event_logs; -DROP VIEW block_stats; diff --git a/db/migrations/1517538273_update_gas_limit_gas_used.down.sql b/db/migrations/1517538273_update_gas_limit_gas_used.down.sql deleted file mode 100644 index 1bdce02f..00000000 --- a/db/migrations/1517538273_update_gas_limit_gas_used.down.sql +++ /dev/null @@ -1,17 +0,0 @@ -BEGIN; -ALTER TABLE blocks - ALTER COLUMN block_gaslimit TYPE DOUBLE PRECISION USING block_gaslimit :: DOUBLE PRECISION; - -ALTER TABLE blocks - ALTER COLUMN block_gasused TYPE DOUBLE PRECISION USING block_gasused :: DOUBLE PRECISION; - -ALTER TABLE blocks - ALTER COLUMN block_time TYPE DOUBLE PRECISION USING block_time :: DOUBLE PRECISION; - -ALTER TABLE blocks - ALTER COLUMN block_reward TYPE NUMERIC USING block_time :: NUMERIC; - -ALTER TABLE blocks - ALTER COLUMN block_uncles_reward TYPE NUMERIC USING block_time :: NUMERIC; - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1517538273_update_gas_limit_gas_used.up.sql b/db/migrations/1517538273_update_gas_limit_gas_used.up.sql deleted file mode 100644 index 7426a59b..00000000 --- a/db/migrations/1517538273_update_gas_limit_gas_used.up.sql +++ /dev/null @@ -1,17 +0,0 @@ -BEGIN; -ALTER TABLE blocks - ALTER COLUMN block_gaslimit TYPE BIGINT USING block_gaslimit :: BIGINT; - -ALTER TABLE blocks - ALTER COLUMN block_gasused TYPE BIGINT USING block_gasused :: BIGINT; - -ALTER TABLE blocks - ALTER COLUMN block_time TYPE BIGINT USING block_time :: BIGINT; - -ALTER TABLE blocks - ALTER COLUMN block_reward TYPE DOUBLE PRECISION USING block_time :: DOUBLE PRECISION; - -ALTER TABLE blocks - ALTER COLUMN block_uncles_reward TYPE DOUBLE PRECISION USING block_time :: DOUBLE PRECISION; - -COMMIT; diff --git a/db/migrations/1517603663_rename_block_columns.down.sql b/db/migrations/1517603663_rename_block_columns.down.sql deleted file mode 100644 index 6993a276..00000000 --- a/db/migrations/1517603663_rename_block_columns.down.sql +++ /dev/null @@ -1,40 +0,0 @@ -BEGIN; -ALTER TABLE blocks - RENAME COLUMN number TO block_number; - -ALTER TABLE blocks - RENAME COLUMN gaslimit TO block_gaslimit; - -ALTER TABLE blocks - RENAME COLUMN gasused TO block_gasused; - -ALTER TABLE blocks - RENAME COLUMN TIME TO block_time; - -ALTER TABLE blocks - RENAME COLUMN difficulty TO block_difficulty; - -ALTER TABLE blocks - RENAME COLUMN HASH TO block_hash; - -ALTER TABLE blocks - RENAME COLUMN nonce TO block_nonce; - -ALTER TABLE blocks - RENAME COLUMN parenthash TO block_parenthash; - -ALTER TABLE blocks - RENAME COLUMN size TO block_size; - -ALTER TABLE blocks - RENAME COLUMN miner TO block_miner; - -ALTER TABLE blocks - RENAME COLUMN extra_data TO block_extra_data; - -ALTER TABLE blocks - RENAME COLUMN reward TO block_reward; - -ALTER TABLE blocks - RENAME COLUMN uncles_reward TO block_uncles_reward; -COMMIT; \ No newline at end of file diff --git a/db/migrations/1517603663_rename_block_columns.up.sql b/db/migrations/1517603663_rename_block_columns.up.sql deleted file mode 100644 index cbd572cf..00000000 --- a/db/migrations/1517603663_rename_block_columns.up.sql +++ /dev/null @@ -1,50 +0,0 @@ -BEGIN; -ALTER TABLE blocks - RENAME COLUMN block_number TO number; - -ALTER TABLE blocks - RENAME COLUMN block_gaslimit TO gaslimit; - -ALTER TABLE blocks - RENAME COLUMN block_gasused TO gasused; - -ALTER TABLE blocks - RENAME COLUMN block_time TO time; - -ALTER TABLE blocks - RENAME COLUMN block_difficulty TO difficulty; - -ALTER TABLE blocks - RENAME COLUMN block_hash TO hash; - -ALTER TABLE blocks - RENAME COLUMN block_nonce TO nonce; - -ALTER TABLE blocks - RENAME COLUMN block_parenthash TO parenthash; - -ALTER TABLE blocks - RENAME COLUMN block_size TO size; - -ALTER TABLE blocks - RENAME COLUMN block_miner TO miner; - -ALTER TABLE blocks - RENAME COLUMN block_extra_data TO extra_data; - -ALTER TABLE blocks - RENAME COLUMN block_reward TO reward; - -ALTER TABLE blocks - RENAME COLUMN block_uncles_reward TO uncles_reward; -COMMIT; - - - - - - - - - - diff --git a/db/migrations/1517605676_update_tx_table_names.down.sql b/db/migrations/1517605676_update_tx_table_names.down.sql deleted file mode 100644 index f2060aae..00000000 --- a/db/migrations/1517605676_update_tx_table_names.down.sql +++ /dev/null @@ -1,19 +0,0 @@ -BEGIN; -ALTER TABLE transactions - RENAME COLUMN hash TO tx_hash; - -ALTER TABLE transactions - RENAME COLUMN nonce TO tx_nonce; - -ALTER TABLE transactions - RENAME COLUMN gaslimit TO tx_gaslimit; - -ALTER TABLE transactions - RENAME COLUMN gasprice TO tx_gasprice; - -ALTER TABLE transactions - RENAME COLUMN value TO tx_value; - -ALTER TABLE transactions - RENAME COLUMN input_data TO tx_input_data; -COMMIT; diff --git a/db/migrations/1517605676_update_tx_table_names.up.sql b/db/migrations/1517605676_update_tx_table_names.up.sql deleted file mode 100644 index 316fc593..00000000 --- a/db/migrations/1517605676_update_tx_table_names.up.sql +++ /dev/null @@ -1,19 +0,0 @@ -BEGIN; -ALTER TABLE transactions - RENAME COLUMN tx_hash TO hash; - -ALTER TABLE transactions - RENAME COLUMN tx_nonce TO nonce; - -ALTER TABLE transactions - RENAME COLUMN tx_gaslimit TO gaslimit; - -ALTER TABLE transactions - RENAME COLUMN tx_gasprice TO gasprice; - -ALTER TABLE transactions - RENAME COLUMN tx_value TO value; - -ALTER TABLE transactions - RENAME COLUMN tx_input_data TO input_data; -COMMIT; diff --git a/db/migrations/1517854395_update_log_filters_to_block_constraint.down.sql b/db/migrations/1517854395_update_log_filters_to_block_constraint.down.sql deleted file mode 100644 index 253d5849..00000000 --- a/db/migrations/1517854395_update_log_filters_to_block_constraint.down.sql +++ /dev/null @@ -1,7 +0,0 @@ -BEGIN; -ALTER TABLE log_filters - DROP CONSTRAINT log_filters_to_block_check; - -ALTER TABLE log_filters - ADD CONSTRAINT log_filters_from_block_check1 CHECK (to_block >= 0); -COMMIT; \ No newline at end of file diff --git a/db/migrations/1517854395_update_log_filters_to_block_constraint.up.sql b/db/migrations/1517854395_update_log_filters_to_block_constraint.up.sql deleted file mode 100644 index 32fa00cb..00000000 --- a/db/migrations/1517854395_update_log_filters_to_block_constraint.up.sql +++ /dev/null @@ -1,7 +0,0 @@ -BEGIN; -ALTER TABLE log_filters - DROP CONSTRAINT log_filters_from_block_check1; - -ALTER TABLE log_filters - ADD CONSTRAINT log_filters_to_block_check CHECK (to_block >= 0); -COMMIT; diff --git a/db/migrations/1520289493_update_eth18_types.down.sql b/db/migrations/1520289493_update_eth18_types.down.sql deleted file mode 100644 index 439f5f9e..00000000 --- a/db/migrations/1520289493_update_eth18_types.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - ALTER COLUMN size TYPE BIGINT USING size::BIGINT; diff --git a/db/migrations/1520289493_update_eth18_types.up.sql b/db/migrations/1520289493_update_eth18_types.up.sql deleted file mode 100644 index 529fe9c8..00000000 --- a/db/migrations/1520289493_update_eth18_types.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - ALTER COLUMN size TYPE VARCHAR USING size::VARCHAR; diff --git a/db/migrations/1521640994_rename_node_table.down.sql b/db/migrations/1521640994_rename_node_table.down.sql deleted file mode 100644 index 70d459c2..00000000 --- a/db/migrations/1521640994_rename_node_table.down.sql +++ /dev/null @@ -1,23 +0,0 @@ -BEGIN; -ALTER TABLE public.eth_nodes - RENAME TO nodes; - -ALTER TABLE public.nodes - RENAME COLUMN eth_node_id TO node_id; - -ALTER TABLE public.nodes - DROP CONSTRAINT eth_node_uc; -ALTER TABLE public.nodes - ADD CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id); - -ALTER TABLE public.blocks RENAME COLUMN eth_node_id TO node_id; - -ALTER TABLE public.blocks DROP CONSTRAINT eth_node_id_block_number_uc; -ALTER TABLE public.blocks - ADD CONSTRAINT node_id_block_number_uc UNIQUE (number, node_id); - -ALTER TABLE public.blocks DROP CONSTRAINT node_fk; -ALTER TABLE public.blocks - ADD CONSTRAINT node_fk -FOREIGN KEY (node_id) REFERENCES nodes (id) ON DELETE CASCADE; -COMMIT; \ No newline at end of file diff --git a/db/migrations/1521640994_rename_node_table.up.sql b/db/migrations/1521640994_rename_node_table.up.sql deleted file mode 100644 index 3b6343c0..00000000 --- a/db/migrations/1521640994_rename_node_table.up.sql +++ /dev/null @@ -1,21 +0,0 @@ -BEGIN; -ALTER TABLE public.nodes RENAME TO eth_nodes; - -ALTER TABLE public.eth_nodes RENAME COLUMN node_id TO eth_node_id; - -ALTER TABLE public.eth_nodes DROP CONSTRAINT node_uc; -ALTER TABLE public.eth_nodes - ADD CONSTRAINT eth_node_uc UNIQUE (genesis_block, network_id, eth_node_id); - -ALTER TABLE public.blocks RENAME COLUMN node_id TO eth_node_id; - -ALTER TABLE public.blocks DROP CONSTRAINT node_id_block_number_uc; -ALTER TABLE public.blocks - ADD CONSTRAINT eth_node_id_block_number_uc UNIQUE (number, eth_node_id); - -ALTER TABLE public.blocks DROP CONSTRAINT node_fk; -ALTER TABLE public.blocks - ADD CONSTRAINT node_fk -FOREIGN KEY (eth_node_id) REFERENCES eth_nodes (id) ON DELETE CASCADE; - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1525122581_associate_receipts_with_blocks.down.sql b/db/migrations/1525122581_associate_receipts_with_blocks.down.sql deleted file mode 100644 index 0a32c92e..00000000 --- a/db/migrations/1525122581_associate_receipts_with_blocks.down.sql +++ /dev/null @@ -1,23 +0,0 @@ -BEGIN; - -ALTER TABLE receipts - ADD COLUMN transaction_id INT; - -UPDATE receipts - SET transaction_id = ( - SELECT id FROM transactions WHERE transactions.hash = receipts.tx_hash - ); - -ALTER TABLE receipts - ALTER COLUMN transaction_id SET NOT NULL; - -ALTER TABLE receipts - ADD CONSTRAINT transaction_fk -FOREIGN KEY (transaction_id) -REFERENCES transactions (id) -ON DELETE CASCADE; - -ALTER TABLE receipts - DROP COLUMN block_id; - -COMMIT; \ No newline at end of file diff --git a/db/migrations/1525122581_associate_receipts_with_blocks.up.sql b/db/migrations/1525122581_associate_receipts_with_blocks.up.sql deleted file mode 100644 index 51d22747..00000000 --- a/db/migrations/1525122581_associate_receipts_with_blocks.up.sql +++ /dev/null @@ -1,23 +0,0 @@ -BEGIN; - -ALTER TABLE receipts - ADD COLUMN block_id INT; - -UPDATE receipts - SET block_id = ( - SELECT block_id FROM transactions WHERE transactions.id = receipts.transaction_id - ); - -ALTER TABLE receipts - ALTER COLUMN block_id SET NOT NULL; - -ALTER TABLE receipts - ADD CONSTRAINT blocks_fk -FOREIGN KEY (block_id) -REFERENCES blocks (id) -ON DELETE CASCADE; - -ALTER TABLE receipts - DROP COLUMN transaction_id; - -COMMIT; diff --git a/db/migrations/1525464568_add_eth_node_fingerprint_to_blocks.down.sql b/db/migrations/1525464568_add_eth_node_fingerprint_to_blocks.down.sql deleted file mode 100644 index f1980bec..00000000 --- a/db/migrations/1525464568_add_eth_node_fingerprint_to_blocks.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE blocks - DROP COLUMN eth_node_fingerprint; \ No newline at end of file diff --git a/db/migrations/1528317902_create_token_supply_table.down.sql b/db/migrations/1528317902_create_token_supply_table.down.sql deleted file mode 100644 index fdc23208..00000000 --- a/db/migrations/1528317902_create_token_supply_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_supply; \ No newline at end of file diff --git a/db/migrations/1528317902_create_token_supply_table.up.sql b/db/migrations/1528317902_create_token_supply_table.up.sql deleted file mode 100644 index 69289885..00000000 --- a/db/migrations/1528317902_create_token_supply_table.up.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE token_supply ( - id SERIAL, - block_id INTEGER NOT NULL, - supply DECIMAL NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - CONSTRAINT blocks_fk FOREIGN KEY (block_id) - REFERENCES blocks (id) - ON DELETE CASCADE -) diff --git a/db/migrations/1531758090_create_headers_table.down.sql b/db/migrations/1531758090_create_headers_table.down.sql deleted file mode 100644 index d9b283f9..00000000 --- a/db/migrations/1531758090_create_headers_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE public.headers; \ No newline at end of file diff --git a/db/migrations/1531758090_create_headers_table.up.sql b/db/migrations/1531758090_create_headers_table.up.sql deleted file mode 100644 index 47fafda2..00000000 --- a/db/migrations/1531758090_create_headers_table.up.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE public.headers ( - id SERIAL PRIMARY KEY, - hash VARCHAR(66), - block_number BIGINT, - raw JSONB, - block_timestamp NUMERIC, - eth_node_id INTEGER, - eth_node_fingerprint VARCHAR(128), - CONSTRAINT eth_nodes_fk FOREIGN KEY (eth_node_id) - REFERENCES eth_nodes (id) - ON DELETE CASCADE -); \ No newline at end of file diff --git a/db/migrations/1532468317_create_checked_headers_table.down.sql b/db/migrations/1532468317_create_checked_headers_table.down.sql deleted file mode 100644 index d9bf78df..00000000 --- a/db/migrations/1532468317_create_checked_headers_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE public.checked_headers; \ No newline at end of file diff --git a/db/migrations/1535055894_create_token_balance_table.down.sql b/db/migrations/1535055894_create_token_balance_table.down.sql deleted file mode 100644 index b1a2ced6..00000000 --- a/db/migrations/1535055894_create_token_balance_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_balance; \ No newline at end of file diff --git a/db/migrations/1535055894_create_token_balance_table.up.sql b/db/migrations/1535055894_create_token_balance_table.up.sql deleted file mode 100644 index a0bc5326..00000000 --- a/db/migrations/1535055894_create_token_balance_table.up.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE token_balance ( - id SERIAL, - block_id INTEGER NOT NULL, - balance DECIMAL NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - token_holder_address CHARACTER VARYING(66) NOT NULL, - CONSTRAINT blocks_fk FOREIGN KEY (block_id) - REFERENCES blocks (id) - ON DELETE CASCADE -) \ No newline at end of file diff --git a/db/migrations/20180823160858_create_token_allowance_table.down.sql b/db/migrations/20180823160858_create_token_allowance_table.down.sql deleted file mode 100644 index 09a816f7..00000000 --- a/db/migrations/20180823160858_create_token_allowance_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_allowance; \ No newline at end of file diff --git a/db/migrations/20180823160858_create_token_allowance_table.up.sql b/db/migrations/20180823160858_create_token_allowance_table.up.sql deleted file mode 100644 index 2d1c9b3b..00000000 --- a/db/migrations/20180823160858_create_token_allowance_table.up.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE token_allowance ( - id SERIAL, - block_id INTEGER NOT NULL, - allowance DECIMAL NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - token_holder_address CHARACTER VARYING(66) NOT NULL, - token_spender_address CHARACTER VARYING(66) NOT NULL, - CONSTRAINT blocks_fk FOREIGN KEY (block_id) - REFERENCES blocks (id) - ON DELETE CASCADE -) \ No newline at end of file diff --git a/db/migrations/20180827120358_create_token_transfer_table.down.sql b/db/migrations/20180827120358_create_token_transfer_table.down.sql deleted file mode 100644 index 82bff29e..00000000 --- a/db/migrations/20180827120358_create_token_transfer_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_transfers; \ No newline at end of file diff --git a/db/migrations/20180827120358_create_token_transfer_table.up.sql b/db/migrations/20180827120358_create_token_transfer_table.up.sql deleted file mode 100644 index fe8091b4..00000000 --- a/db/migrations/20180827120358_create_token_transfer_table.up.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE token_transfers ( - id SERIAL, - vulcanize_log_id INTEGER NOT NULL UNIQUE, - token_name CHARACTER VARYING(66) NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - to_address CHARACTER VARYING(66) NOT NULL, - from_address CHARACTER VARYING(66) NOT NULL, - tokens DECIMAL NOT NULL, - block INTEGER NOT NULL, - tx CHARACTER VARYING(66) NOT NULL, - CONSTRAINT log_index_fk FOREIGN KEY (vulcanize_log_id) - REFERENCES logs (id) - ON DELETE CASCADE -) \ No newline at end of file diff --git a/db/migrations/20180827120410_create_token_approval_table.down.sql b/db/migrations/20180827120410_create_token_approval_table.down.sql deleted file mode 100644 index acfcaca5..00000000 --- a/db/migrations/20180827120410_create_token_approval_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_approvals; \ No newline at end of file diff --git a/db/migrations/20180827120410_create_token_approval_table.up.sql b/db/migrations/20180827120410_create_token_approval_table.up.sql deleted file mode 100644 index 5dc45164..00000000 --- a/db/migrations/20180827120410_create_token_approval_table.up.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE token_approvals ( - id SERIAL, - vulcanize_log_id INTEGER NOT NULL UNIQUE, - token_name CHARACTER VARYING(66) NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - owner CHARACTER VARYING(66) NOT NULL, - spender CHARACTER VARYING(66) NOT NULL, - tokens DECIMAL NOT NULL, - block INTEGER NOT NULL, - tx CHARACTER VARYING(66) NOT NULL, - CONSTRAINT log_index_fk FOREIGN KEY (vulcanize_log_id) - REFERENCES logs (id) - ON DELETE CASCADE -) \ No newline at end of file diff --git a/db/migrations/20180911134701_create_token_burn_table.down.sql b/db/migrations/20180911134701_create_token_burn_table.down.sql deleted file mode 100644 index f22d52c6..00000000 --- a/db/migrations/20180911134701_create_token_burn_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_burns; \ No newline at end of file diff --git a/db/migrations/20180911134701_create_token_burn_table.up.sql b/db/migrations/20180911134701_create_token_burn_table.up.sql deleted file mode 100644 index b2a25217..00000000 --- a/db/migrations/20180911134701_create_token_burn_table.up.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE token_burns ( - id SERIAL, - vulcanize_log_id INTEGER NOT NULL UNIQUE, - token_name CHARACTER VARYING(66) NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - burner CHARACTER VARYING(66) NOT NULL, - tokens DECIMAL NOT NULL, - block INTEGER NOT NULL, - tx CHARACTER VARYING(66) NOT NULL, - CONSTRAINT log_index_fk FOREIGN KEY (vulcanize_log_id) - REFERENCES logs (id) - ON DELETE CASCADE -) \ No newline at end of file diff --git a/db/migrations/20180911134708_create_token_mint_table.down.sql b/db/migrations/20180911134708_create_token_mint_table.down.sql deleted file mode 100644 index 0725fcb9..00000000 --- a/db/migrations/20180911134708_create_token_mint_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE token_mints; \ No newline at end of file diff --git a/db/migrations/20180911134708_create_token_mint_table.up.sql b/db/migrations/20180911134708_create_token_mint_table.up.sql deleted file mode 100644 index 85396e7d..00000000 --- a/db/migrations/20180911134708_create_token_mint_table.up.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE token_mints ( - id SERIAL, - vulcanize_log_id INTEGER NOT NULL UNIQUE, - token_name CHARACTER VARYING(66) NOT NULL, - token_address CHARACTER VARYING(66) NOT NULL, - minter CHARACTER VARYING(66) NOT NULL, - mintee CHARACTER VARYING(66) NOT NULL, - tokens DECIMAL NOT NULL, - block INTEGER NOT NULL, - tx CHARACTER VARYING(66) NOT NULL, - CONSTRAINT log_index_fk FOREIGN KEY (vulcanize_log_id) - REFERENCES logs (id) - ON DELETE CASCADE -) \ No newline at end of file diff --git a/db/schema.sql b/db/schema.sql index 5fe85da7..eb6db179 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -2,8 +2,8 @@ -- PostgreSQL database dump -- --- Dumped from database version 10.3 --- Dumped by pg_dump version 10.3 +-- Dumped from database version 10.6 +-- Dumped by pg_dump version 10.6 SET statement_timeout = 0; SET lock_timeout = 0; @@ -67,23 +67,23 @@ CREATE VIEW public.block_stats AS -- CREATE TABLE public.blocks ( - number bigint, - gaslimit bigint, - gasused bigint, - "time" bigint, id integer NOT NULL, difficulty bigint, + extra_data character varying, + gas_limit bigint, + gas_used bigint, hash character varying(66), + miner character varying(42), nonce character varying(20), - parenthash character varying(66), + number bigint, + parent_hash character varying(66), + reward numeric, + uncles_reward numeric, size character varying, + "time" bigint, + is_final boolean, uncle_hash character varying(66), eth_node_id integer NOT NULL, - is_final boolean, - miner character varying(42), - extra_data character varying, - reward double precision, - uncles_reward double precision, eth_node_fingerprint character varying(128) NOT NULL ); @@ -108,19 +108,157 @@ CREATE SEQUENCE public.blocks_id_seq ALTER SEQUENCE public.blocks_id_seq OWNED BY public.blocks.id; +-- +-- Name: checked_headers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.checked_headers ( + id integer NOT NULL, + header_id integer NOT NULL +); + + +-- +-- Name: checked_headers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.checked_headers_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: checked_headers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.checked_headers_id_seq OWNED BY public.checked_headers.id; + + -- -- Name: eth_nodes; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.eth_nodes ( id integer NOT NULL, + client_name character varying, genesis_block character varying(66), network_id numeric, - eth_node_id character varying(128), - client_name character varying + eth_node_id character varying(128) ); +-- +-- Name: full_sync_receipts; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.full_sync_receipts ( + id integer NOT NULL, + contract_address character varying(42), + cumulative_gas_used numeric, + gas_used numeric, + state_root character varying(66), + status integer, + tx_hash character varying(66), + block_id integer NOT NULL +); + + +-- +-- Name: full_sync_receipts_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.full_sync_receipts_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: full_sync_receipts_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.full_sync_receipts_id_seq OWNED BY public.full_sync_receipts.id; + + +-- +-- Name: full_sync_transactions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.full_sync_transactions ( + id integer NOT NULL, + block_id integer NOT NULL, + gas_limit numeric, + gas_price numeric, + hash character varying(66), + input_data bytea, + nonce numeric, + raw bytea, + tx_from character varying(66), + tx_index integer, + tx_to character varying(66), + value numeric +); + + +-- +-- Name: full_sync_transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.full_sync_transactions_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: full_sync_transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.full_sync_transactions_id_seq OWNED BY public.full_sync_transactions.id; + + +-- +-- Name: goose_db_version; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.goose_db_version ( + id integer NOT NULL, + version_id bigint NOT NULL, + is_applied boolean NOT NULL, + tstamp timestamp without time zone DEFAULT now() +); + + +-- +-- Name: goose_db_version_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.goose_db_version_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: goose_db_version_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.goose_db_version_id_seq OWNED BY public.goose_db_version.id; + + -- -- Name: headers; Type: TABLE; Schema: public; Owner: - -- @@ -129,8 +267,9 @@ CREATE TABLE public.headers ( id integer NOT NULL, hash character varying(66), block_number bigint, - raw bytea, - eth_node_id integer, + raw jsonb, + block_timestamp numeric, + eth_node_id integer NOT NULL, eth_node_fingerprint character varying(128) ); @@ -155,6 +294,84 @@ CREATE SEQUENCE public.headers_id_seq ALTER SEQUENCE public.headers_id_seq OWNED BY public.headers.id; +-- +-- Name: light_sync_receipts; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.light_sync_receipts ( + id integer NOT NULL, + transaction_id integer NOT NULL, + header_id integer NOT NULL, + contract_address character varying(42), + cumulative_gas_used numeric, + gas_used numeric, + state_root character varying(66), + status integer, + tx_hash character varying(66), + rlp bytea +); + + +-- +-- Name: light_sync_receipts_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.light_sync_receipts_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: light_sync_receipts_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.light_sync_receipts_id_seq OWNED BY public.light_sync_receipts.id; + + +-- +-- Name: light_sync_transactions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.light_sync_transactions ( + id integer NOT NULL, + header_id integer NOT NULL, + hash character varying(66), + gas_limit numeric, + gas_price numeric, + input_data bytea, + nonce numeric, + raw bytea, + tx_from character varying(44), + tx_index integer, + tx_to character varying(44), + value numeric +); + + +-- +-- Name: light_sync_transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.light_sync_transactions_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: light_sync_transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.light_sync_transactions_id_seq OWNED BY public.light_sync_transactions.id; + + -- -- Name: log_filters; Type: TABLE; Schema: public; Owner: - -- @@ -236,26 +453,24 @@ ALTER SEQUENCE public.nodes_id_seq OWNED BY public.eth_nodes.id; -- --- Name: receipts; Type: TABLE; Schema: public; Owner: - +-- Name: queued_storage; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE public.receipts ( +CREATE TABLE public.queued_storage ( id integer NOT NULL, - contract_address character varying(42), - cumulative_gas_used numeric, - gas_used numeric, - state_root character varying(66), - status integer, - tx_hash character varying(66), - block_id integer NOT NULL + block_height bigint, + block_hash bytea, + contract bytea, + storage_key bytea, + storage_value bytea ); -- --- Name: receipts_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- Name: queued_storage_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- -CREATE SEQUENCE public.receipts_id_seq +CREATE SEQUENCE public.queued_storage_id_seq AS integer START WITH 1 INCREMENT BY 1 @@ -265,39 +480,34 @@ CREATE SEQUENCE public.receipts_id_seq -- --- Name: receipts_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- Name: queued_storage_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- -ALTER SEQUENCE public.receipts_id_seq OWNED BY public.receipts.id; +ALTER SEQUENCE public.queued_storage_id_seq OWNED BY public.queued_storage.id; -- --- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- Name: uncles; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE public.schema_migrations ( - version bigint NOT NULL, - dirty boolean NOT NULL -); - - --- --- Name: token_supply; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.token_supply ( +CREATE TABLE public.uncles ( id integer NOT NULL, + hash character varying(66) NOT NULL, block_id integer NOT NULL, - supply numeric NOT NULL, - token_address character varying(66) NOT NULL + reward numeric NOT NULL, + miner character varying(42) NOT NULL, + raw jsonb, + block_timestamp numeric, + eth_node_id integer NOT NULL, + eth_node_fingerprint character varying(128) ); -- --- Name: token_supply_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- Name: uncles_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- -CREATE SEQUENCE public.token_supply_id_seq +CREATE SEQUENCE public.uncles_id_seq AS integer START WITH 1 INCREMENT BY 1 @@ -307,48 +517,10 @@ CREATE SEQUENCE public.token_supply_id_seq -- --- Name: token_supply_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- Name: uncles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- -ALTER SEQUENCE public.token_supply_id_seq OWNED BY public.token_supply.id; - - --- --- Name: transactions; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.transactions ( - id integer NOT NULL, - hash character varying(66), - nonce numeric, - tx_to character varying(66), - gaslimit numeric, - gasprice numeric, - value numeric, - block_id integer NOT NULL, - tx_from character varying(66), - input_data character varying -); - - --- --- Name: transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.transactions_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.transactions_id_seq OWNED BY public.transactions.id; +ALTER SEQUENCE public.uncles_id_seq OWNED BY public.uncles.id; -- @@ -357,8 +529,8 @@ ALTER SEQUENCE public.transactions_id_seq OWNED BY public.transactions.id; CREATE TABLE public.watched_contracts ( contract_id integer NOT NULL, - contract_hash character varying(66), - contract_abi json + contract_abi json, + contract_hash character varying(66) ); @@ -412,6 +584,13 @@ CREATE VIEW public.watched_event_logs AS ALTER TABLE ONLY public.blocks ALTER COLUMN id SET DEFAULT nextval('public.blocks_id_seq'::regclass); +-- +-- Name: checked_headers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.checked_headers ALTER COLUMN id SET DEFAULT nextval('public.checked_headers_id_seq'::regclass); + + -- -- Name: eth_nodes id; Type: DEFAULT; Schema: public; Owner: - -- @@ -419,6 +598,27 @@ ALTER TABLE ONLY public.blocks ALTER COLUMN id SET DEFAULT nextval('public.block ALTER TABLE ONLY public.eth_nodes ALTER COLUMN id SET DEFAULT nextval('public.nodes_id_seq'::regclass); +-- +-- Name: full_sync_receipts id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.full_sync_receipts ALTER COLUMN id SET DEFAULT nextval('public.full_sync_receipts_id_seq'::regclass); + + +-- +-- Name: full_sync_transactions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.full_sync_transactions ALTER COLUMN id SET DEFAULT nextval('public.full_sync_transactions_id_seq'::regclass); + + +-- +-- Name: goose_db_version id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.goose_db_version ALTER COLUMN id SET DEFAULT nextval('public.goose_db_version_id_seq'::regclass); + + -- -- Name: headers id; Type: DEFAULT; Schema: public; Owner: - -- @@ -426,6 +626,20 @@ ALTER TABLE ONLY public.eth_nodes ALTER COLUMN id SET DEFAULT nextval('public.no ALTER TABLE ONLY public.headers ALTER COLUMN id SET DEFAULT nextval('public.headers_id_seq'::regclass); +-- +-- Name: light_sync_receipts id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_receipts ALTER COLUMN id SET DEFAULT nextval('public.light_sync_receipts_id_seq'::regclass); + + +-- +-- Name: light_sync_transactions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_transactions ALTER COLUMN id SET DEFAULT nextval('public.light_sync_transactions_id_seq'::regclass); + + -- -- Name: log_filters id; Type: DEFAULT; Schema: public; Owner: - -- @@ -441,24 +655,17 @@ ALTER TABLE ONLY public.logs ALTER COLUMN id SET DEFAULT nextval('public.logs_id -- --- Name: receipts id; Type: DEFAULT; Schema: public; Owner: - +-- Name: queued_storage id; Type: DEFAULT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.receipts ALTER COLUMN id SET DEFAULT nextval('public.receipts_id_seq'::regclass); +ALTER TABLE ONLY public.queued_storage ALTER COLUMN id SET DEFAULT nextval('public.queued_storage_id_seq'::regclass); -- --- Name: token_supply id; Type: DEFAULT; Schema: public; Owner: - +-- Name: uncles id; Type: DEFAULT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.token_supply ALTER COLUMN id SET DEFAULT nextval('public.token_supply_id_seq'::regclass); - - --- --- Name: transactions id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.transactions ALTER COLUMN id SET DEFAULT nextval('public.transactions_id_seq'::regclass); +ALTER TABLE ONLY public.uncles ALTER COLUMN id SET DEFAULT nextval('public.uncles_id_seq'::regclass); -- @@ -477,11 +684,19 @@ ALTER TABLE ONLY public.blocks -- --- Name: watched_contracts contract_hash_uc; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: checked_headers checked_headers_header_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.watched_contracts - ADD CONSTRAINT contract_hash_uc UNIQUE (contract_hash); +ALTER TABLE ONLY public.checked_headers + ADD CONSTRAINT checked_headers_header_id_key UNIQUE (header_id); + + +-- +-- Name: checked_headers checked_headers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.checked_headers + ADD CONSTRAINT checked_headers_pkey PRIMARY KEY (id); -- @@ -500,6 +715,30 @@ ALTER TABLE ONLY public.eth_nodes ADD CONSTRAINT eth_node_uc UNIQUE (genesis_block, network_id, eth_node_id); +-- +-- Name: full_sync_receipts full_sync_receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.full_sync_receipts + ADD CONSTRAINT full_sync_receipts_pkey PRIMARY KEY (id); + + +-- +-- Name: full_sync_transactions full_sync_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.full_sync_transactions + ADD CONSTRAINT full_sync_transactions_pkey PRIMARY KEY (id); + + +-- +-- Name: goose_db_version goose_db_version_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.goose_db_version + ADD CONSTRAINT goose_db_version_pkey PRIMARY KEY (id); + + -- -- Name: headers headers_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -508,6 +747,38 @@ ALTER TABLE ONLY public.headers ADD CONSTRAINT headers_pkey PRIMARY KEY (id); +-- +-- Name: light_sync_receipts light_sync_receipts_header_id_transaction_id_key; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_receipts + ADD CONSTRAINT light_sync_receipts_header_id_transaction_id_key UNIQUE (header_id, transaction_id); + + +-- +-- Name: light_sync_receipts light_sync_receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_receipts + ADD CONSTRAINT light_sync_receipts_pkey PRIMARY KEY (id); + + +-- +-- Name: light_sync_transactions light_sync_transactions_header_id_hash_key; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_transactions + ADD CONSTRAINT light_sync_transactions_header_id_hash_key UNIQUE (header_id, hash); + + +-- +-- Name: light_sync_transactions light_sync_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_transactions + ADD CONSTRAINT light_sync_transactions_pkey PRIMARY KEY (id); + + -- -- Name: logs logs_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -533,27 +804,35 @@ ALTER TABLE ONLY public.eth_nodes -- --- Name: receipts receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: queued_storage queued_storage_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.receipts - ADD CONSTRAINT receipts_pkey PRIMARY KEY (id); +ALTER TABLE ONLY public.queued_storage + ADD CONSTRAINT queued_storage_pkey PRIMARY KEY (id); -- --- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: uncles uncles_block_id_hash_key; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.schema_migrations - ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); +ALTER TABLE ONLY public.uncles + ADD CONSTRAINT uncles_block_id_hash_key UNIQUE (block_id, hash); -- --- Name: transactions transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: uncles uncles_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.transactions - ADD CONSTRAINT transactions_pkey PRIMARY KEY (id); +ALTER TABLE ONLY public.uncles + ADD CONSTRAINT uncles_pkey PRIMARY KEY (id); + + +-- +-- Name: watched_contracts watched_contracts_contract_hash_key; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.watched_contracts + ADD CONSTRAINT watched_contracts_contract_hash_key UNIQUE (contract_hash); -- @@ -568,14 +847,14 @@ ALTER TABLE ONLY public.watched_contracts -- Name: block_id_index; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX block_id_index ON public.transactions USING btree (block_id); +CREATE INDEX block_id_index ON public.full_sync_transactions USING btree (block_id); -- --- Name: block_number_index; Type: INDEX; Schema: public; Owner: - +-- Name: headers_block_number; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX block_number_index ON public.blocks USING btree (number); +CREATE INDEX headers_block_number ON public.headers USING btree (block_number); -- @@ -585,50 +864,81 @@ CREATE INDEX block_number_index ON public.blocks USING btree (number); CREATE INDEX node_id_index ON public.blocks USING btree (eth_node_id); +-- +-- Name: number_index; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX number_index ON public.blocks USING btree (number); + + -- -- Name: tx_from_index; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX tx_from_index ON public.transactions USING btree (tx_from); +CREATE INDEX tx_from_index ON public.full_sync_transactions USING btree (tx_from); -- -- Name: tx_to_index; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX tx_to_index ON public.transactions USING btree (tx_to); +CREATE INDEX tx_to_index ON public.full_sync_transactions USING btree (tx_to); -- --- Name: transactions blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- Name: full_sync_receipts blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.transactions +ALTER TABLE ONLY public.full_sync_receipts ADD CONSTRAINT blocks_fk FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE; -- --- Name: receipts blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- Name: checked_headers checked_headers_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.receipts - ADD CONSTRAINT blocks_fk FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.checked_headers + ADD CONSTRAINT checked_headers_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE; -- --- Name: token_supply blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- Name: full_sync_transactions full_sync_transactions_block_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.token_supply - ADD CONSTRAINT blocks_fk FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.full_sync_transactions + ADD CONSTRAINT full_sync_transactions_block_id_fkey FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE; -- --- Name: headers eth_nodes_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- Name: headers headers_eth_node_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.headers - ADD CONSTRAINT eth_nodes_fk FOREIGN KEY (eth_node_id) REFERENCES public.eth_nodes(id) ON DELETE CASCADE; + ADD CONSTRAINT headers_eth_node_id_fkey FOREIGN KEY (eth_node_id) REFERENCES public.eth_nodes(id) ON DELETE CASCADE; + + +-- +-- Name: light_sync_receipts light_sync_receipts_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_receipts + ADD CONSTRAINT light_sync_receipts_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE; + + +-- +-- Name: light_sync_receipts light_sync_receipts_transaction_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_receipts + ADD CONSTRAINT light_sync_receipts_transaction_id_fkey FOREIGN KEY (transaction_id) REFERENCES public.light_sync_transactions(id) ON DELETE CASCADE; + + +-- +-- Name: light_sync_transactions light_sync_transactions_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.light_sync_transactions + ADD CONSTRAINT light_sync_transactions_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE; -- @@ -644,9 +954,26 @@ ALTER TABLE ONLY public.blocks -- ALTER TABLE ONLY public.logs - ADD CONSTRAINT receipts_fk FOREIGN KEY (receipt_id) REFERENCES public.receipts(id) ON DELETE CASCADE; + ADD CONSTRAINT receipts_fk FOREIGN KEY (receipt_id) REFERENCES public.full_sync_receipts(id) ON DELETE CASCADE; + + +-- +-- Name: uncles uncles_block_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.uncles + ADD CONSTRAINT uncles_block_id_fkey FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE; + + +-- +-- Name: uncles uncles_eth_node_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.uncles + ADD CONSTRAINT uncles_eth_node_id_fkey FOREIGN KEY (eth_node_id) REFERENCES public.eth_nodes(id) ON DELETE CASCADE; -- -- PostgreSQL database dump complete --- \ No newline at end of file +-- + diff --git a/dockerfiles/README.md b/dockerfiles/README.md new file mode 100644 index 00000000..5bf3c61a --- /dev/null +++ b/dockerfiles/README.md @@ -0,0 +1,32 @@ +S +`Dockerfile` will build an alpine image containing: +- vDB as a binary with runtime deps statically linked: `/app/vulcanizedb` +- The migration tool goose: `/app/goose` +- Two services for running `lightSync` and `continuousLogSync`, started with the default configuration `environments/staging.toml`. + +By default, vDB is configured towards the Kovan deploy. The configuration values can be overridden using environment variables, using the same hierarchical naming pattern but in CAPS and using underscores. For example, the contract address for the `Pit` can be set with the variable `CONTRACT_ADDRESS_PIT="0x123..."`. + +## To use the container: +1. Setup a postgres database with superuser `vulcanize` +2. Set the env variables `DATABASE_NAME`, `DATABASE_HOSTNAME`, + `DATABASE_PORT`, `DATABASE_USER` & `DATABASE_PASSWORD` +3. Run the DB migrations: + * `./goose postgres "postgresql://$(DATABASE_USER):$(DATABASE_PASSWORD)@$(DATABASE_HOSTNAME):$(DATABASE_PORT)/$(DATABASE_NAME)?sslmode=disable" +e` +4. Set `CLIENT_IPCPATH` to a node endpoint +5. Set the contract variables: + * `CONTRACT_ADDRESS_[CONTRACT NAME]=0x123...` + * `CONTRACT_ABI_[CONTRACT NAME]="ABI STRING"` + * `CONTRACT_DEPLOYMENT-BLOCK_[CONTRACT NAME]=0` (doesn't really matter on a short chain, just avoids long unnecessary searching) +6. Start the `lightSync` and `continuousLogSync` services: + * `./vulcanizedb lightSync --config environments/staging.toml` + * `./vulcanizedb continuousLogSync --config environments/staging.toml` + +### Automated +The steps above have been rolled into a script: `/app/startup_script.sh`, which just assumes the DB env variables have been set, and defaults the rest to Kovan according to `environments/staging.toml`. This can be called with something like: + +`docker run -d -e DATABASE_NAME=vulcanize_public -e DATABASE_HOSTNAME=localhost -e DATABASE_PORT=5432 -e DATABASE_USER=vulcanize -e DATABASE_PASSWORD=vulcanize m0ar/images:vDB` + +### Logging +When running, vDB services log to `/app/vulcanizedb.log`. + diff --git a/dockerfiles/startup_script.sh b/dockerfiles/startup_script.sh new file mode 100755 index 00000000..8373715a --- /dev/null +++ b/dockerfiles/startup_script.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# Runs the migrations and starts the lightSync and continuousLogSync services + +# Exit if the variable tests fail +set -e + +# Check the database variables are set +test $DATABASE_NAME +test $DATABASE_HOSTNAME +test $DATABASE_PORT +test $DATABASE_USER +test $DATABASE_PASSWORD + +# Construct the connection string for postgres +CONNECT_STRING=postgresql://$DATABASE_USER:$DATABASE_PASSWORD@$DATABASE_HOSTNAME:$DATABASE_PORT/$DATABASE_NAME?sslmode=disable +echo "Connecting with: $CONNECT_STRING" + +set +e + +# Run the DB migrations +./goose postgres "$CONNECT_STRING" up +if [ $? -eq 0 ]; then + # Fire up the services + ./vulcanizedb lightSync --config environments/staging.toml & + ./vulcanizedb continuousLogSync --config environments/staging.toml & +else + echo "Could not run migrations. Are the database details correct?" +fi +wait diff --git a/documentation/composeAndExecute.md b/documentation/composeAndExecute.md new file mode 100644 index 00000000..6efbcf75 --- /dev/null +++ b/documentation/composeAndExecute.md @@ -0,0 +1,152 @@ +# composeAndExecute +The `composeAndExecute` command is used to compose and execute over an arbitrary set of custom transformers. +This is accomplished by generating a Go pluggin which allows the `vulcanizedb` binary to link to external transformers, so +long as they abide by one of the standard [interfaces](../staging/libraries/shared/transformer). + +This command requires Go 1.11+ and [Go plugins](https://golang.org/pkg/plugin/) only work on Unix-based systems. + +## Writing custom transformers +Storage Transformers + * [Guide](../../staging/libraries/shared/factories/storage/README.md) + * [Example](../../staging/libraries/shared/factories/storage/EXAMPLE.md) + +Event Transformers + * [Guide](../../staging/libraries/shared/factories/event/README.md) + * [Example 1](https://github.com/vulcanize/ens_transformers/tree/master/transformers/registar) + * [Example 2](https://github.com/vulcanize/ens_transformers/tree/master/transformers/registry) + * [Example 3](https://github.com/vulcanize/ens_transformers/tree/master/transformers/resolver) + +Contract Transformers + * [Example 1](https://github.com/vulcanize/account_transformers) + * [Example 2](https://github.com/vulcanize/ens_transformers/tree/master/transformers/domain_records) + +## Preparing transformers to work as a plugin for composeAndExecute +To plug in an external transformer we need to: + +1. Create a package that exports a variable `TransformerInitializer`, `StorageTransformerInitializer`, or `ContractTransformerInitializer` that are of type [TransformerInitializer](../staging/libraries/shared/transformer/event_transformer.go#L33) +or [StorageTransformerInitializer](../../staging/libraries/shared/transformer/storage_transformer.go#L31), +or [ContractTransformerInitializer](../../staging/libraries/shared/transformer/contract_transformer.go#L31), respectively +2. Design the transformers to work in the context of their [event](../staging/libraries/shared/watcher/event_watcher.go#L83), +[storage](../../staging/libraries/shared/watcher/storage_watcher.go#L53), +or [contract](../../staging/libraries/shared/watcher/contract_watcher.go#L68) watcher execution modes +3. Create db migrations to run against vulcanizeDB so that we can store the transformer output + * Do not `goose fix` the transformer migrations, this is to ensure they are always ran after the core vulcanizedb migrations which are kept in their fixed form + * Specify migration locations for each transformer in the config with the `exporter.transformer.migrations` fields + * If the base vDB migrations occupy this path as well, they need to be in their `goose fix`ed form + as they are [here](../../staging/db/migrations) + +To update a plugin repository with changes to the core vulcanizedb repository, replace the vulcanizedb vendored in the plugin repo (`plugin_repo/vendor/github.com/vulcanize/vulcanizedb`) +with the newly updated version +* The entire vendor lib within the vendored vulcanizedb needs to be deleted (`plugin_repo/vendor/github.com/vulcanize/vulcanizedb/vendor`) +* These complications arise due to this [conflict](https://github.com/golang/go/issues/20481) between `dep` and Go plugins + +## Configuration +A .toml config file is specified when executing the command: +`./vulcanizedb composeAndExecute --config=./environments/config_name.toml` + +The config provides information for composing a set of transformers: + +```toml +[database] + name = "vulcanize_public" + hostname = "localhost" + user = "vulcanize" + password = "vulcanize" + port = 5432 + +[client] + ipcPath = "/Users/user/Library/Ethereum/geth.ipc" + +[exporter] + home = "github.com/vulcanize/vulcanizedb" + name = "exampleTransformerExporter" + save = false + transformerNames = [ + "transformer1", + "transformer2", + "transformer3", + "transformer4", + ] + [exporter.transformer1] + path = "path/to/transformer1" + type = "eth_event" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer2] + path = "path/to/transformer2" + type = "eth_contract" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer3] + path = "path/to/transformer3" + type = "eth_event" + repository = "github.com/account/repo" + migrations = "db/migrations" + rank = "0" + [exporter.transformer4] + path = "path/to/transformer4" + type = "eth_storage" + repository = "github.com/account2/repo2" + migrations = "to/db/migrations" + rank = "1" +``` +- `home` is the name of the package you are building the plugin for, in most cases this is github.com/vulcanize/vulcanizedb +- `name` is the name used for the plugin files (.so and .go) +- `save` indicates whether or not the user wants to save the .go file instead of removing it after .so compilation. Sometimes useful for debugging/trouble-shooting purposes. +- `transformerNames` is the list of the names of the transformers we are composing together, so we know how to access their submaps in the exporter map +- `exporter.`s are the sub-mappings containing config info for the transformers + - `repository` is the path for the repository which contains the transformer and its `TransformerInitializer` + - `path` is the relative path from `repository` to the transformer's `TransformerInitializer` directory (initializer package). + - Transformer repositories need to be cloned into the user's $GOPATH (`go get`) + - `type` is the type of the transformer; indicating which type of watcher it works with (for now, there are only two options: `eth_event` and `eth_storage`) + - `eth_storage` indicates the transformer works with the [storage watcher](../../staging/libraries/shared/watcher/storage_watcher.go) + that fetches state and storage diffs from an ETH node (instead of, for example, from IPFS) + - `eth_event` indicates the transformer works with the [event watcher](../../staging/libraries/shared/watcher/event_watcher.go) + that fetches event logs from an ETH node + - `eth_contract` indicates the transformer works with the [contract watcher](../staging/libraries/shared/watcher/contract_watcher.go) + that is made to work with [contract_watcher pkg](../../staging/pkg/contract_watcher) + based transformers which work with either a light or full sync vDB to watch events and poll public methods ([example1](https://github.com/vulcanize/account_transformers/tree/master/transformers/account/light), [example2](https://github.com/vulcanize/ens_transformers/tree/working/transformers/domain_records)) + - `migrations` is the relative path from `repository` to the db migrations directory for the transformer + - `rank` determines the order that migrations are ran, with lower ranked migrations running first + - this is to help isolate any potential conflicts between transformer migrations + - start at "0" + - use strings + - don't leave gaps + - transformers with identical migrations/migration paths should share the same rank +- Note: If any of the imported transformers need additional config variables those need to be included as well + +This information is used to write and build a Go plugin which exports the configured transformers. +These transformers are loaded onto their specified watchers and executed. + +Transformers of different types can be run together in the same command using a single config file or in separate instances using different config files + +The general structure of a plugin .go file, and what we would see built with the above config is shown below + +```go +package main + +import ( + interface1 "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + transformer1 "github.com/account/repo/path/to/transformer1" + transformer2 "github.com/account/repo/path/to/transformer2" + transformer3 "github.com/account/repo/path/to/transformer3" + transformer4 "github.com/account2/repo2/path/to/transformer4" +) + +type exporter string + +var Exporter exporter + +func (e exporter) Export() []interface1.EventTransformerInitializer, []interface1.StorageTransformerInitializer, []interface1.ContractTransformerInitializer { + return []interface1.TransformerInitializer{ + transformer1.TransformerInitializer, + transformer3.TransformerInitializer, + }, []interface1.StorageTransformerInitializer{ + transformer4.StorageTransformerInitializer, + }, []interface1.ContractTransformerInitializer{ + transformer2.TransformerInitializer, + } +} +``` diff --git a/documentation/contractWatcher.md b/documentation/contractWatcher.md new file mode 100644 index 00000000..02a77895 --- /dev/null +++ b/documentation/contractWatcher.md @@ -0,0 +1,160 @@ +# contractWatcher +The `contractWatcher` command is a built-in generic contract watcher. It can watch any and all events for a given contract provided the contract's ABI is available. +It also provides some state variable coverage by automating polling of public methods, with some restrictions: +1. The method must have 2 or less arguments +1. The method's arguments must all be of type address or bytes32 (hash) +1. The method must return a single value + +This command operates in two modes- `light` and `full`- which require a light or full-synced vulcanizeDB, respectively. + +This command requires the contract ABI be available on Etherscan if it is not provided in the config file by the user. + +If method polling is turned on we require an archival node at the ETH ipc endpoint in our config, whether or not we are operating in `light` or `full` mode. +Otherwise we only need to connect to a full node. + +## Configuration +This command takes a config of the form: + +```toml + [database] + name = "vulcanize_public" + hostname = "localhost" + port = 5432 + + [client] + ipcPath = "/Users/user/Library/Ethereum/geth.ipc" + + [contract] + network = "" + addresses = [ + "contractAddress1", + "contractAddress2" + ] + [contract.contractAddress1] + abi = 'ABI for contract 1' + startingBlock = 982463 + [contract.contractAddress2] + abi = 'ABI for contract 2' + events = [ + "event1", + "event2" + ] + eventArgs = [ + "arg1", + "arg2" + ] + methods = [ + "method1", + "method2" + ] + methodArgs = [ + "arg1", + "arg2" + ] + startingBlock = 4448566 + piping = true +```` + +- The `contract` section defines which contracts we want to watch and with which conditions. +- `network` is only necessary if the ABIs are not provided and wish to be fetched from Etherscan. + - Empty or nil string indicates mainnet + - "ropsten", "kovan", and "rinkeby" indicate their respective networks +- `addresses` lists the contract addresses we are watching and is used to load their individual configuration parameters +- `contract.` are the sub-mappings which contain the parameters specific to each contract address + - `abi` is the ABI for the contract; if none is provided the application will attempt to fetch one from Etherscan using the provided address and network + - `events` is the list of events to watch + - If this field is omitted or no events are provided then by defualt ALL events extracted from the ABI will be watched + - If event names are provided then only those events will be watched + - `eventArgs` is the list of arguments to filter events with + - If this field is omitted or no eventArgs are provided then by default watched events are not filtered by their argument values + - If eventArgs are provided then only those events which emit at least one of these values as an argument are watched + - `methods` is the list of methods to poll + - If this is omitted or no methods are provided then by default NO methods are polled + - If method names are provided then those methods will be polled, provided + 1) Method has two or less arguments + 1) Arguments are all of address or hash types + 1) Method returns a single value + - `methodArgs` is the list of arguments to limit polling methods to + - If this field is omitted or no methodArgs are provided then by default methods will be polled with every combination of the appropriately typed values that have been collected from watched events + - If methodArgs are provided then only those values will be used to poll methods + - `startingBlock` is the block we want to begin watching the contract, usually the deployment block of that contract + - `piping` is a boolean flag which indicates whether or not we want to pipe return method values forward as arguments to subsequent method calls + +At the very minimum, for each contract address an ABI and a starting block number need to be provided (or just the starting block if the ABI can be reliably fetched from Etherscan). +With just this information we will be able to watch all events at the contract, but with no additional filters and no method polling. + +## Output + +Transformed events and polled method results are committed to Postgres in schemas and tables generated according to the contract abi. + +Schemas are created for each contract using the naming convention `_` +Under this schema, tables are generated for watched events as `_event` and for polled methods as `_method` +The 'method' and 'event' identifiers are tacked onto the end of the table names to prevent collisions between methods and events of the same lowercase name + +## Example: + +Modify `./environments/example.toml` to replace the empty `ipcPath` with a path that points to an ethjson_rpc endpoint (e.g. a local geth node ipc path or an Infura url). +This endpoint should be for an archival eth node if we want to perform method polling as this configuration is currently set up to do. To work with a non-archival full node, +remove the `balanceOf` method from the `0x8dd5fbce2f6a956c3022ba3663759011dd51e73e` (TrueUSD) contract. + +If you are operating a light sync vDB, run: + + `./vulcanizedb contractWatcher --config=./environments/example.toml --mode=light` + +If instead you are operating a full sync vDB and provided an archival node IPC path, run in full mode: + + `./vulcanizedb contractWatcher --config=./environments/example.toml --mode=full` + +This will run the contractWatcher and configures it to watch the contracts specified in the config file. Note that +by default we operate in `light` mode but the flag is included here to demonstrate its use. + +The example config we link to in this example watches two contracts, the ENS Registry (0x314159265dD8dbb310642f98f50C066173C1259b) and TrueUSD (0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E). + +Because the ENS Registry is configured with only an ABI and a starting block, we will watch all events for this contract and poll none of its methods. Note that the ENS Registry is an example +of a contract which does not have its ABI available over Etherscan and must have it included in the config file. + +The TrueUSD contract is configured with two events (`Transfer` and `Mint`) and a single method (`balanceOf`), as such it will watch these two events and use any addresses it collects emitted from them +to poll the `balanceOf` method with those addresses at every block. Note that we do not provide an ABI for TrueUSD as its ABI can be fetched from Etherscan. + +For the ENS contract, it produces and populates a schema with four tables" +`light_0x314159265dd8dbb310642f98f50c066173c1259b.newowner_event` +`light_0x314159265dd8dbb310642f98f50c066173c1259b.newresolver_event` +`light_0x314159265dd8dbb310642f98f50c066173c1259b.newttl_event` +`light_0x314159265dd8dbb310642f98f50c066173c1259b.transfer_event` + +For the TrusUSD contract, it produces and populates a schema with three tables: + +`light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event` +`light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.mint_event` +`light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method` + +Column ids and types for these tables are generated based on the event and method argument names and types and method return types, resulting in tables such as: + +Table "light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event" + +| Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +|:----------:|:---------------------:|:---------:|:--------:|:-------------------------------------------------------------------------------------------:|:--------:|:------------:|:-----------:| +| id | integer | | not null | nextval('light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event_id_seq'::regclass) | plain | | | +| header_id | integer | | not null | | plain | | | +| token_name | character varying(66) | | not null | | extended | | | +| raw_log | jsonb | | | | extended | | | +| log_idx | integer | | not null | | plain | | | +| tx_idx | integer | | not null | | plain | | | +| from_ | character varying(66) | | not null | | extended | | | +| to_ | character varying(66) | | not null | | extended | | | +| value_ | numeric | | not null | | main | | | + + +Table "light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method" + +| Column | Type | Collation | Nullable | Default | Storage | Stats target | Description | +|:----------:|:---------------------:|:---------:|:--------:|:-------------------------------------------------------------------------------------------:|:--------:|:------------:|:-----------:| +| id | integer | | not null | nextval('light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method_id_seq'::regclass) | plain | | | +| token_name | character varying(66) | | not null | | extended | | | +| block | integer | | not null | | plain | | | +| who_ | character varying(66) | | not null | | extended | | | +| returned | numeric | | not null | | main | | | + +The addition of '_' after table names is to prevent collisions with reserved Postgres words. + +Also notice that the contract address used for the schema name has been down-cased. \ No newline at end of file diff --git a/documentation/contributing.md b/documentation/contributing.md new file mode 100644 index 00000000..db255507 --- /dev/null +++ b/documentation/contributing.md @@ -0,0 +1,11 @@ +# Contribution guidelines + +Contributions are welcome! In addition to core contributions, developers are encouraged to build their own custom transformers which +can be run together with other custom transformers using the [composeAndExeucte](../../staging/documentation/composeAndExecute.md) command. + +## Creating a new migration file +1. `make new_migration NAME=add_columnA_to_table1` + - This will create a new timestamped migration file in `db/migrations` +1. Write the migration code in the created file, under the respective `goose` pragma + - Goose automatically runs each migration in a transaction; don't add `BEGIN` and `COMMIT` statements. +1. Core migrations should be committed in their `goose fix`ed form. \ No newline at end of file diff --git a/documentation/sync.md b/documentation/sync.md new file mode 100644 index 00000000..a1eda615 --- /dev/null +++ b/documentation/sync.md @@ -0,0 +1,26 @@ +# Syncing commands +These commands are used to sync raw Ethereum data into Postgres. + +## lightSync +Syncs VulcanizeDB with the configured Ethereum node, populating only block headers. +This command is useful when you want a minimal baseline from which to track targeted data on the blockchain (e.g. individual smart contract storage values or event logs). +1. Start Ethereum node +1. In a separate terminal start VulcanizeDB: + - `./vulcanizedb lightSync --config --starting-block-number ` + +## sync +Syncs VulcanizeDB with the configured Ethereum node, populating blocks, transactions, receipts, and logs. +This command is useful when you want to maintain a broad cache of what's happening on the blockchain. +1. Start Ethereum node (**if fast syncing your Ethereum node, wait for initial sync to finish**) +1. In a separate terminal start VulcanizeDB: + - `./vulcanizedb sync --config --starting-block-number ` + +## coldImport +Sync VulcanizeDB from the LevelDB underlying a Geth node. +1. Assure node is not running, and that it has synced to the desired block height. +1. Start vulcanize_db + - `./vulcanizedb coldImport --config ` +1. Optional flags: + - `--starting-block-number `/`-s `: block number to start syncing from + - `--ending-block-number `/`-e `: block number to sync to + - `--all`/`-a`: sync all missing blocks diff --git a/environments/composeAndExecuteAccountTransformer.toml b/environments/composeAndExecuteAccountTransformer.toml new file mode 100644 index 00000000..97a2b21a --- /dev/null +++ b/environments/composeAndExecuteAccountTransformer.toml @@ -0,0 +1,38 @@ +[database] + name = "vulcanize_public" + hostname = "localhost" + port = 5432 + +[client] + ipcPath = "" + +[exporter] + home = "github.com/vulcanize/vulcanizedb" + name = "accountTransformerExporter" + save = false + transformerNames = [ + "account" + ] + [exporter.account] + path = "transformers/account/light/initializer" + type = "eth_contract" + repository = "github.com/vulcanize/account_transformers" + migrations = "db/migrations" + rank = "0" + +[token] + addresses = [ + "0x58b6A8A3302369DAEc383334672404Ee733aB239", + "0x862Da0A691bb0b74038377295f8fF523D0493eB4", + ] + [token.equivalents] + 0x0000000000085d4780B73119b644AE5ecd22b376 = [ + "0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E" + ] + 0x58b6A8A3302369DAEc383334672404Ee733aB239 = [ + "0x8e306b005773bee6bA6A6e8972Bc79D766cC15c8" + ] + +[account] + start = 0 + addresses = [] diff --git a/environments/example.toml b/environments/example.toml new file mode 100644 index 00000000..e025baaa --- /dev/null +++ b/environments/example.toml @@ -0,0 +1,26 @@ +[database] + name = "vulcanize_public" + hostname = "localhost" + port = 5432 + +[client] + ipcPath = "" + +[contract] + network = "" + addresses = [ + "0x314159265dD8dbb310642f98f50C066173C1259b", + "0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E" + ] + [contract.0x314159265dD8dbb310642f98f50C066173C1259b] + abi = '[{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"label","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"name":"","type":"uint64"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":true,"name":"label","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"}]' + startingBlock = 3327417 + [contract.0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E] + events = [ + "Transfer", + "Issue" + ] + methods = [ + "balanceOf" + ] + startingBlock = 5197514 \ No newline at end of file diff --git a/environments/infura.toml b/environments/infura.toml index ac91b4dc..fb9876fb 100644 --- a/environments/infura.toml +++ b/environments/infura.toml @@ -1,7 +1,7 @@ [database] -name = "vulcanize_infura" -hostname = "localhost" -port = 5432 + name = "vulcanize_public" + hostname = "localhost" + port = 5432 [client] -ipcPath = "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" + ipcPath = "" diff --git a/environments/private.toml b/environments/private.toml index d7c71775..83f80f7b 100644 --- a/environments/private.toml +++ b/environments/private.toml @@ -1,7 +1,7 @@ [database] -name = "vulcanize_private" -hostname = "localhost" -port = 5432 + name = "vulcanize_private" + hostname = "localhost" + port = 5432 [client] -ipcPath = "test_data_dir/geth.ipc" + ipcPath = "http://127.0.0.1:7545" diff --git a/environments/public.toml.example b/environments/public.toml.example index ac9dbf85..52f8a2d1 100644 --- a/environments/public.toml.example +++ b/environments/public.toml.example @@ -1,8 +1,8 @@ [database] -name = "vulcanize_public" -hostname = "localhost" -port = 5432 + name = "vulcanize_public" + hostname = "localhost" + port = 5432 [client] -ipcPath = -levelDbPath = + ipcPath = + levelDbPath = diff --git a/examples/erc20_watcher/ERC20WatcherREADME.md b/examples/erc20_watcher/ERC20WatcherREADME.md deleted file mode 100644 index 97ecdfe4..00000000 --- a/examples/erc20_watcher/ERC20WatcherREADME.md +++ /dev/null @@ -1,19 +0,0 @@ -# ERC20 Transformers - -## Description -The Transformers in this directory are associated with contract functions and events that conform to the [ERC20 Token interface](https://theethereum.wiki/w/index.php/ERC20_Token_Standard#The_ERC20_Token_Standard_Interface). - -See `libraries/shared/TransformerREADME.md` for further information regarding the Transformer interface. - -## Configuration -In addition to environment configuration mentioned in the main VulcanizeDB README, the ERC20 transformers also need to be configured with contract information for the desired token(s) to be watched. This configuration file is located at `./vulcanizedb/examples/erc20_watcher/config.go`. - -## ERC20 Functions -The `everyblock` directory contains transformers that fetch data from the contract itself, via one of the standard functions. - -Currently, the `totalSupply` function transformer has been implemented. This transformer will fetch the total supply for the given contract address and persist `total_supply` records in the database. - -## Running the transformers -1. If running against a local node, make sure that the node has been started. -1. In a separate terminal run the following command: -`./vulcanizedb erc20 --config ` diff --git a/examples/erc20_watcher/event_triggered/dai/converter.go b/examples/erc20_watcher/event_triggered/dai/converter.go deleted file mode 100644 index d5ecb9f9..00000000 --- a/examples/erc20_watcher/event_triggered/dai/converter.go +++ /dev/null @@ -1,122 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package dai - -import ( - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" -) - -// Converter converts a raw event log into its corresponding entity -// and can subsequently convert the entity into a model - -type ERC20ConverterInterface interface { - ToTransferEntity(watchedEvent core.WatchedEvent) (*TransferEntity, error) - ToTransferModel(entity *TransferEntity) *event_triggered.TransferModel - ToApprovalEntity(watchedEvent core.WatchedEvent) (*ApprovalEntity, error) - ToApprovalModel(entity *ApprovalEntity) *event_triggered.ApprovalModel -} - -type ERC20Converter struct { - config shared.ContractConfig -} - -func NewERC20Converter(config shared.ContractConfig) (*ERC20Converter, error) { - var err error - - config.ParsedAbi, err = geth.ParseAbi(config.Abi) - if err != nil { - return nil, err - } - - converter := &ERC20Converter{ - config: config, - } - - return converter, nil -} - -func (c ERC20Converter) ToTransferEntity(watchedEvent core.WatchedEvent) (*TransferEntity, error) { - result := &TransferEntity{} - contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) - event := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLog(result, constants.TransferEvent.String(), event) - if err != nil { - return result, err - } - result.TokenName = c.config.Name - result.TokenAddress = common.HexToAddress(c.config.Address) - result.Block = watchedEvent.BlockNumber - result.TxHash = watchedEvent.TxHash - - return result, nil -} - -func (c ERC20Converter) ToTransferModel(entity *TransferEntity) *event_triggered.TransferModel { - to := entity.Dst.String() - from := entity.Src.String() - tokens := entity.Wad.String() - - return &event_triggered.TransferModel{ - TokenName: c.config.Name, - TokenAddress: c.config.Address, - To: to, - From: from, - Tokens: tokens, - Block: entity.Block, - TxHash: entity.TxHash, - } -} - -func (c ERC20Converter) ToApprovalEntity(watchedEvent core.WatchedEvent) (*ApprovalEntity, error) { - result := &ApprovalEntity{} - contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) - event := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLog(result, constants.ApprovalEvent.String(), event) - if err != nil { - return result, err - } - result.TokenName = c.config.Name - result.TokenAddress = common.HexToAddress(c.config.Address) - result.Block = watchedEvent.BlockNumber - result.TxHash = watchedEvent.TxHash - - return result, nil -} - -func (c ERC20Converter) ToApprovalModel(entity *ApprovalEntity) *event_triggered.ApprovalModel { - tokenOwner := entity.Src.String() - spender := entity.Guy.String() - tokens := entity.Wad.String() - - return &event_triggered.ApprovalModel{ - TokenName: c.config.Name, - TokenAddress: c.config.Address, - Owner: tokenOwner, - Spender: spender, - Tokens: tokens, - Block: entity.Block, - TxHash: entity.TxHash, - } -} diff --git a/examples/erc20_watcher/event_triggered/dai/converter_test.go b/examples/erc20_watcher/event_triggered/dai/converter_test.go deleted file mode 100644 index d303772f..00000000 --- a/examples/erc20_watcher/event_triggered/dai/converter_test.go +++ /dev/null @@ -1,154 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package dai_test - -import ( - "github.com/ethereum/go-ethereum/common" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai" - "github.com/vulcanize/vulcanizedb/examples/generic" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" -) - -var expectedTransferModel = event_triggered.TransferModel{ - TokenName: "Dai", - TokenAddress: constants.DaiContractAddress, - To: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", - From: "0x000000000000000000000000000000000000Af21", - Tokens: "1097077688018008265106216665536940668749033598146", - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var expectedTransferEntity = dai.TransferEntity{ - TokenName: "Dai", - TokenAddress: common.HexToAddress(constants.DaiContractAddress), - Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), - Dst: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Wad: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var expectedApprovalModel = event_triggered.ApprovalModel{ - TokenName: "Dai", - TokenAddress: constants.DaiContractAddress, - Owner: "0x000000000000000000000000000000000000Af21", - Spender: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", - Tokens: "1097077688018008265106216665536940668749033598146", - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var expectedApprovalEntity = dai.ApprovalEntity{ - TokenName: "Dai", - TokenAddress: common.HexToAddress(constants.DaiContractAddress), - Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), - Guy: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Wad: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var transferEvent = core.WatchedEvent{ - LogID: 1, - Name: constants.TransferEvent.String(), - BlockNumber: 5488076, - Address: constants.DaiContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.TransferEvent.Signature(), - Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", - Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -var approvalEvent = core.WatchedEvent{ - LogID: 1, - Name: constants.ApprovalEvent.String(), - BlockNumber: 5488076, - Address: constants.DaiContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.ApprovalEvent.Signature(), - Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", - Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -var _ = Describe("Transfer Converter", func() { - - var daiConverter *dai.ERC20Converter - var err error - - BeforeEach(func() { - daiConverter, err = dai.NewERC20Converter(generic.DaiConfig) - Expect(err).NotTo(HaveOccurred()) - }) - - It("converts a watched transfer event into a TransferEntity", func() { - - result, err := daiConverter.ToTransferEntity(transferEvent) - Expect(err).NotTo(HaveOccurred()) - Expect(result).To(Equal(&expectedTransferEntity)) - }) - - It("converts a TransferEntity to an TransferModel", func() { - - result, err := daiConverter.ToTransferEntity(transferEvent) - Expect(err).NotTo(HaveOccurred()) - - model := daiConverter.ToTransferModel(result) - Expect(model).To(Equal(&expectedTransferModel)) - }) - -}) - -var _ = Describe("Approval Converter", func() { - - var daiConverter *dai.ERC20Converter - var err error - - BeforeEach(func() { - daiConverter, err = dai.NewERC20Converter(generic.DaiConfig) - Expect(err).NotTo(HaveOccurred()) - }) - - It("converts a watched approval event into a ApprovalEntity", func() { - - result, err := daiConverter.ToApprovalEntity(approvalEvent) - Expect(err).NotTo(HaveOccurred()) - Expect(result).To(Equal(&expectedApprovalEntity)) - }) - - It("converts a ApprovalEntity to an ApprovalModel", func() { - - result, err := daiConverter.ToApprovalEntity(approvalEvent) - Expect(err).NotTo(HaveOccurred()) - - model := daiConverter.ToApprovalModel(result) - Expect(model).To(Equal(&expectedApprovalModel)) - }) - -}) diff --git a/examples/erc20_watcher/event_triggered/dai/integration_test.go b/examples/erc20_watcher/event_triggered/dai/integration_test.go deleted file mode 100644 index d4e59f69..00000000 --- a/examples/erc20_watcher/event_triggered/dai/integration_test.go +++ /dev/null @@ -1,138 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package dai_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai" - "github.com/vulcanize/vulcanizedb/examples/generic" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var transferLog = core.Log{ - BlockNumber: 5488076, - Address: constants.DaiContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topics: [4]string{ - constants.TransferEvent.Signature(), - "0x000000000000000000000000000000000000000000000000000000000000af21", - "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - "", - }, - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -var approvalLog = core.Log{ - BlockNumber: 5488076, - Address: constants.DaiContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topics: [4]string{ - constants.ApprovalEvent.Signature(), - "0x000000000000000000000000000000000000000000000000000000000000af21", - "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - "", - }, - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -//converted transfer to assert against -var logs = []core.Log{ - transferLog, - approvalLog, - { - BlockNumber: 0, - TxHash: "", - Address: "", - Topics: core.Topics{}, - Index: 0, - Data: "", - }, -} - -var _ = Describe("Integration test with vulcanizedb", func() { - var db *postgres.DB - var blk core.BlockChain - - BeforeEach(func() { - db = test_helpers.SetupIntegrationDB(db, logs) - }) - - AfterEach(func() { - db = test_helpers.TearDownIntegrationDB(db) - }) - - It("creates token_transfers entry for each Transfer event received", func() { - transformer, err := dai.NewTransformer(db, blk, generic.DaiConfig) - Expect(err).ToNot(HaveOccurred()) - - transformer.Execute() - - var count int - err = db.QueryRow(`SELECT COUNT(*) FROM token_transfers`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - - transfer := event_triggered.TransferModel{} - - err = db.Get(&transfer, `SELECT - token_name, - token_address, - to_address, - from_address, - tokens, - block, - tx - FROM token_transfers WHERE block=$1`, logs[0].BlockNumber) - Expect(err).ToNot(HaveOccurred()) - Expect(transfer).To(Equal(expectedTransferModel)) - }) - - It("creates token_approvals entry for each Approval event received", func() { - transformer, err := dai.NewTransformer(db, blk, generic.DaiConfig) - Expect(err).ToNot(HaveOccurred()) - - transformer.Execute() - - var count int - err = db.QueryRow(`SELECT COUNT(*) FROM token_approvals`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - - approval := event_triggered.ApprovalModel{} - - err = db.Get(&approval, `SELECT - token_name, - token_address, - owner, - spender, - tokens, - block, - tx - FROM token_approvals WHERE block=$1`, logs[0].BlockNumber) - Expect(err).ToNot(HaveOccurred()) - Expect(approval).To(Equal(expectedApprovalModel)) - }) - -}) diff --git a/examples/erc20_watcher/event_triggered/dai/repository_test.go b/examples/erc20_watcher/event_triggered/dai/repository_test.go deleted file mode 100644 index 12ace1e1..00000000 --- a/examples/erc20_watcher/event_triggered/dai/repository_test.go +++ /dev/null @@ -1,236 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package dai_test - -import ( - "math/rand" - "time" - - "github.com/ethereum/go-ethereum/common" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/config" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" -) - -var transferEntity = &dai.TransferEntity{ - TokenName: "Dai", - TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), - Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), - Dst: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Wad: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var approvalEntity = &dai.ApprovalEntity{ - TokenName: "Dai", - TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), - Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), - Guy: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Wad: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var _ = Describe("Approval and Transfer Repository Tests", func() { - var db *postgres.DB - var converter dai.ERC20Converter - var repository event_triggered.ERC20EventRepository - var logRepository repositories.LogRepository - var blockRepository repositories.BlockRepository - var receiptRepository repositories.ReceiptRepository - var blockNumber int64 - var blockId int64 - var vulcanizeLogId int64 - rand.Seed(time.Now().UnixNano()) - - BeforeEach(func() { - var err error - db, err = postgres.NewDB(config.Database{ - Hostname: "localhost", - Name: "vulcanize_private", - Port: 5432, - }, core.Node{}) - Expect(err).NotTo(HaveOccurred()) - - receiptRepository = repositories.ReceiptRepository{DB: db} - logRepository = repositories.LogRepository{DB: db} - blockRepository = *repositories.NewBlockRepository(db) - - blockNumber = rand.Int63() - blockId = test_helpers.CreateBlock(blockNumber, blockRepository) - - log := core.Log{} - logs := []core.Log{log} - receipt := core.Receipt{ - Logs: logs, - } - receipts := []core.Receipt{receipt} - - err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts) - Expect(err).ToNot(HaveOccurred()) - - err = logRepository.Get(&vulcanizeLogId, `SELECT id FROM logs`) - Expect(err).ToNot(HaveOccurred()) - - repository = event_triggered.ERC20EventRepository{DB: db} - converter = dai.ERC20Converter{} - - }) - - AfterEach(func() { - db.Query(`DELETE FROM logs`) - db.Query(`DELETE FROM log_filters`) - db.Query(`DELETE FROM token_transfers`) - db.Query(`DELETE FROM token_approvals`) - - }) - - It("Creates a new Transfer record", func() { - model := converter.ToTransferModel(transferEntity) - err := repository.CreateTransfer(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - type DBRow struct { - DBID uint64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` - event_triggered.TransferModel - } - dbResult := DBRow{} - - err = repository.QueryRowx(`SELECT * FROM token_transfers`).StructScan(&dbResult) - Expect(err).ToNot(HaveOccurred()) - - Expect(dbResult.VulcanizeLogID).To(Equal(vulcanizeLogId)) - Expect(dbResult.TokenName).To(Equal(model.TokenName)) - Expect(dbResult.TokenAddress).To(Equal(model.TokenAddress)) - Expect(dbResult.To).To(Equal(model.To)) - Expect(dbResult.From).To(Equal(model.From)) - Expect(dbResult.Tokens).To(Equal(model.Tokens)) - Expect(dbResult.Block).To(Equal(model.Block)) - Expect(dbResult.TxHash).To(Equal(model.TxHash)) - }) - - It("does not duplicate token_transfers that have already been seen", func() { - model := converter.ToTransferModel(transferEntity) - - err := repository.CreateTransfer(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = repository.CreateTransfer(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_transfers`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - }) - - It("Removes a Transfer record when the corresponding log is removed", func() { - var exists bool - - model := converter.ToTransferModel(transferEntity) - err := repository.CreateTransfer(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - err = repository.DB.QueryRow(`SELECT exists (SELECT * FROM token_transfers WHERE vulcanize_log_id = $1)`, vulcanizeLogId).Scan(&exists) - Expect(err).ToNot(HaveOccurred()) - Expect(exists).To(BeTrue()) - - var logCount int - _, err = logRepository.DB.Exec(`DELETE FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = logRepository.Get(&logCount, `SELECT count(*) FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - Expect(logCount).To(BeZero()) - - var LogKillCount int - err = repository.DB.QueryRowx( - `SELECT count(*) FROM token_transfers WHERE vulcanize_log_id = $1`, vulcanizeLogId).Scan(&LogKillCount) - Expect(err).ToNot(HaveOccurred()) - Expect(LogKillCount).To(BeZero()) - }) - - It("Creates a new Approval record", func() { - model := converter.ToApprovalModel(approvalEntity) - err := repository.CreateApproval(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - type DBRow struct { - DBID uint64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` - event_triggered.ApprovalModel - } - dbResult := DBRow{} - - err = repository.QueryRowx(`SELECT * FROM token_approvals`).StructScan(&dbResult) - Expect(err).ToNot(HaveOccurred()) - - Expect(dbResult.VulcanizeLogID).To(Equal(vulcanizeLogId)) - Expect(dbResult.TokenName).To(Equal(model.TokenName)) - Expect(dbResult.TokenAddress).To(Equal(model.TokenAddress)) - Expect(dbResult.Owner).To(Equal(model.Owner)) - Expect(dbResult.Spender).To(Equal(model.Spender)) - Expect(dbResult.Tokens).To(Equal(model.Tokens)) - Expect(dbResult.Block).To(Equal(model.Block)) - Expect(dbResult.TxHash).To(Equal(model.TxHash)) - }) - - It("does not duplicate token_approvals that have already been seen", func() { - model := converter.ToApprovalModel(approvalEntity) - - err := repository.CreateApproval(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = repository.CreateApproval(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_approvals`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - }) - - It("Removes a Approval record when the corresponding log is removed", func() { - var exists bool - - model := converter.ToApprovalModel(approvalEntity) - err := repository.CreateApproval(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - err = repository.DB.QueryRow(`SELECT exists (SELECT * FROM token_approvals WHERE vulcanize_log_id = $1)`, vulcanizeLogId).Scan(&exists) - Expect(err).ToNot(HaveOccurred()) - Expect(exists).To(BeTrue()) - - var logCount int - _, err = logRepository.DB.Exec(`DELETE FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = logRepository.Get(&logCount, `SELECT count(*) FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - Expect(logCount).To(BeZero()) - - var LogKillCount int - err = repository.DB.QueryRowx( - `SELECT count(*) FROM token_approvals WHERE vulcanize_log_id = $1`, vulcanizeLogId).Scan(&LogKillCount) - Expect(err).ToNot(HaveOccurred()) - Expect(LogKillCount).To(BeZero()) - }) -}) diff --git a/examples/erc20_watcher/event_triggered/dai/transformer.go b/examples/erc20_watcher/event_triggered/dai/transformer.go deleted file mode 100644 index fda12307..00000000 --- a/examples/erc20_watcher/event_triggered/dai/transformer.go +++ /dev/null @@ -1,96 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package dai - -import ( - "fmt" - "log" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/filters" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -type ERC20EventTransformer struct { - Converter ERC20ConverterInterface - WatchedEventRepository datastore.WatchedEventRepository - FilterRepository datastore.FilterRepository - Repository event_triggered.ERC20EventDatastore - Filters []filters.LogFilter -} - -func NewTransformer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) { - var transformer shared.Transformer - - cnvtr, err := NewERC20Converter(con) - if err != nil { - return nil, err - } - - wer := repositories.WatchedEventRepository{DB: db} - fr := repositories.FilterRepository{DB: db} - lkr := event_triggered.ERC20EventRepository{DB: db} - - transformer = ERC20EventTransformer{ - Converter: cnvtr, - WatchedEventRepository: wer, - FilterRepository: fr, - Repository: lkr, - Filters: con.Filters, - } - - for _, filter := range con.Filters { - fr.CreateFilter(filter) - } - - return transformer, nil -} - -func (tr ERC20EventTransformer) Execute() error { - for _, filter := range tr.Filters { - watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name) - if err != nil { - log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err) - return err - } - for _, we := range watchedEvents { - if filter.Name == constants.TransferEvent.String() { - entity, err := tr.Converter.ToTransferEntity(*we) - model := tr.Converter.ToTransferModel(entity) - if err != nil { - log.Printf("Error persisting data for Dai Transfers (watchedEvent.LogID %d):\n %s", we.LogID, err) - } - tr.Repository.CreateTransfer(model, we.LogID) - } - if filter.Name == constants.ApprovalEvent.String() { - entity, err := tr.Converter.ToApprovalEntity(*we) - model := tr.Converter.ToApprovalModel(entity) - if err != nil { - log.Printf("Error persisting data for Dai Approvals (watchedEvent.LogID %d):\n %s", we.LogID, err) - } - tr.Repository.CreateApproval(model, we.LogID) - } - } - } - - return nil -} diff --git a/examples/erc20_watcher/event_triggered/dai/transformer_test.go b/examples/erc20_watcher/event_triggered/dai/transformer_test.go deleted file mode 100644 index 71da2806..00000000 --- a/examples/erc20_watcher/event_triggered/dai/transformer_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package dai_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai" - "github.com/vulcanize/vulcanizedb/examples/mocks" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var blockID1 = int64(5428074) -var logID1 = int64(113) -var blockID2 = int64(5428405) -var logID2 = int64(100) - -var fakeWatchedEvents = []*core.WatchedEvent{ - { - LogID: logID1, - Name: constants.TransferEvent.String(), - BlockNumber: blockID1, - Address: constants.DaiContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.TransferEvent.Signature(), - Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", - Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", - }, - { - LogID: logID2, - Name: constants.ApprovalEvent.String(), - BlockNumber: blockID2, - Address: constants.DaiContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.ApprovalEvent.Signature(), - Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", - Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", - }, -} - -var _ = Describe("Mock ERC20 transformer", func() { - var mockERC20Converter mocks.MockERC20Converter - var watchedEventsRepo mocks.MockWatchedEventsRepository - var mockEventRepo mocks.MockEventRepo - var filterRepo mocks.MockFilterRepository - var transformer dai.ERC20EventTransformer - - BeforeEach(func() { - mockERC20Converter = mocks.MockERC20Converter{} - watchedEventsRepo = mocks.MockWatchedEventsRepository{} - watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents) - mockEventRepo = mocks.MockEventRepo{} - filterRepo = mocks.MockFilterRepository{} - filters := constants.DaiERC20Filters - - transformer = dai.ERC20EventTransformer{ - Converter: &mockERC20Converter, - WatchedEventRepository: &watchedEventsRepo, - FilterRepository: filterRepo, - Repository: &mockEventRepo, - Filters: filters, - } - }) - - It("calls the watched events repo with correct filter", func() { - transformer.Execute() - Expect(len(watchedEventsRepo.Names)).To(Equal(2)) - Expect(watchedEventsRepo.Names).To(ConsistOf([]string{constants.TransferEvent.String(), constants.ApprovalEvent.String()})) - }) - - It("calls the mock ERC20 converter with the watched events", func() { - transformer.Execute() - Expect(len(mockERC20Converter.WatchedEvents)).To(Equal(2)) - Expect(mockERC20Converter.WatchedEvents).To(ConsistOf(fakeWatchedEvents)) - }) - - It("converts a Transfer and Approval entity to their models", func() { - transformer.Execute() - Expect(len(mockERC20Converter.TransfersToConvert)).To(Equal(1)) - Expect(mockERC20Converter.TransfersToConvert[0].Block).To(Equal(blockID1)) - - Expect(len(mockERC20Converter.ApprovalsToConvert)).To(Equal(1)) - Expect(mockERC20Converter.ApprovalsToConvert[0].Block).To(Equal(blockID2)) - }) - - It("persists Transfer and Approval data for each watched Transfer or Approval event", func() { - transformer.Execute() - Expect(len(mockEventRepo.TransferLogs)).To(Equal(1)) - Expect(len(mockEventRepo.ApprovalLogs)).To(Equal(1)) - Expect(mockEventRepo.VulcanizeLogIDs).To(ConsistOf(logID1, logID2)) - }) - -}) diff --git a/examples/erc20_watcher/event_triggered/model.go b/examples/erc20_watcher/event_triggered/model.go deleted file mode 100644 index 5cc728d1..00000000 --- a/examples/erc20_watcher/event_triggered/model.go +++ /dev/null @@ -1,37 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package event_triggered - -type TransferModel struct { - TokenName string `db:"token_name"` - TokenAddress string `db:"token_address"` - To string `db:"to_address"` - From string `db:"from_address"` - Tokens string `db:"tokens"` - Block int64 `db:"block"` - TxHash string `db:"tx"` -} - -type ApprovalModel struct { - TokenName string `db:"token_name"` - TokenAddress string `db:"token_address"` - Owner string `db:"owner"` - Spender string `db:"spender"` - Tokens string `db:"tokens"` - Block int64 `db:"block"` - TxHash string `db:"tx"` -} diff --git a/examples/erc20_watcher/event_triggered/repository.go b/examples/erc20_watcher/event_triggered/repository.go deleted file mode 100644 index d5cf100a..00000000 --- a/examples/erc20_watcher/event_triggered/repository.go +++ /dev/null @@ -1,52 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package event_triggered - -import ( - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -type ERC20EventDatastore interface { - CreateTransfer(model *TransferModel, vulcanizeLogId int64) error - CreateApproval(model *ApprovalModel, vulcanizeLogId int64) error -} - -type ERC20EventRepository struct { - *postgres.DB -} - -func (repository ERC20EventRepository) CreateTransfer(transferModel *TransferModel, vulcanizeLogId int64) error { - _, err := repository.DB.Exec( - - `INSERT INTO token_transfers (vulcanize_log_id, token_name, token_address, to_address, from_address, tokens, block, tx) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8) - ON CONFLICT (vulcanize_log_id) DO NOTHING`, - vulcanizeLogId, transferModel.TokenName, transferModel.TokenAddress, transferModel.To, transferModel.From, transferModel.Tokens, transferModel.Block, transferModel.TxHash) - - return err -} - -func (repository ERC20EventRepository) CreateApproval(approvalModel *ApprovalModel, vulcanizeLogId int64) error { - _, err := repository.DB.Exec( - - `INSERT INTO token_approvals (vulcanize_log_id, token_name, token_address, owner, spender, tokens, block, tx) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8) - ON CONFLICT (vulcanize_log_id) DO NOTHING`, - vulcanizeLogId, approvalModel.TokenName, approvalModel.TokenAddress, approvalModel.Owner, approvalModel.Spender, approvalModel.Tokens, approvalModel.Block, approvalModel.TxHash) - - return err -} diff --git a/examples/erc20_watcher/every_block/getter.go b/examples/erc20_watcher/every_block/getter.go deleted file mode 100644 index 5df9da0b..00000000 --- a/examples/erc20_watcher/every_block/getter.go +++ /dev/null @@ -1,66 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block - -import ( - "math/big" - - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/fetcher" -) - -// Getter serves as a higher level data fetcher that invokes its underlying Fetcher methods for a given contract method - -// Interface definition for a Getter -type ERC20GetterInterface interface { - GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) - GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) - GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) - GetBlockChain() core.BlockChain -} - -// Getter struct -type ERC20Getter struct { - fetcher.Fetcher -} - -// Initializes and returns a Getter with the given blockchain -func NewGetter(blockChain core.BlockChain) ERC20Getter { - return ERC20Getter{ - Fetcher: fetcher.Fetcher{ - BlockChain: blockChain, - }, - } -} - -// Public getter methods for calling contract methods -func (g ERC20Getter) GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { - return g.Fetcher.FetchBigInt("totalSupply", contractAbi, contractAddress, blockNumber, nil) -} - -func (g ERC20Getter) GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { - return g.Fetcher.FetchBigInt("balanceOf", contractAbi, contractAddress, blockNumber, methodArgs) -} - -func (g ERC20Getter) GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { - return g.Fetcher.FetchBigInt("allowance", contractAbi, contractAddress, blockNumber, methodArgs) -} - -// Method to retrieve the Getter's blockchain -func (g ERC20Getter) GetBlockChain() core.BlockChain { - return g.Fetcher.BlockChain -} diff --git a/examples/erc20_watcher/every_block/getter_test.go b/examples/erc20_watcher/every_block/getter_test.go deleted file mode 100644 index ce409e7e..00000000 --- a/examples/erc20_watcher/every_block/getter_test.go +++ /dev/null @@ -1,214 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block_test - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/pkg/fakes" - "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/geth/client" - rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" - "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var _ = Describe("ERC20 Getter", func() { - blockNumber := int64(6194634) - - Describe("totalSupply", func() { - It("gets total supply data from the blockchain with the correct arguments", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetTotalSupply(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "totalSupply", nil, &expected, blockNumber) - }) - - It("gets dai token's total supply at the given block height", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetTotalSupply(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expectedResult.SetString("47327413946297204537985606", 10) - Expect(result.String()).To(Equal(expectedResult.String())) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetTotalSupply("", "", 0) - - Expect(result.String()).To(Equal("0")) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("totalSupply")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("balanceOf", func() { - It("gets balance of a token holder address at a token contract address from the blockchain with the correct arguments", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - testTokenHolderAddress := common.HexToAddress("0x2cccc4b4708b318a6290511aac75d6c3dbe0cf9f") - hashArgs := []common.Address{testTokenHolderAddress} - balanceOfArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - balanceOfArgs[i] = s - } - - _, err := testGetter.GetBalance(testAbi, testContractAddress, blockNumber, balanceOfArgs) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "balanceOf", balanceOfArgs, &expected, blockNumber) - }) - - It("gets a token holder address's balance on the dai contract at the given block height", func() { - infuraIPC := "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - - testTokenHolderAddress := common.HexToAddress("0x2cccc4b4708b318a6290511aac75d6c3dbe0cf9f") - hashArgs := []common.Address{testTokenHolderAddress} - balanceOfArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - balanceOfArgs[i] = s - } - - result, err := realGetter.GetBalance(constants.DaiAbiString, constants.DaiContractAddress, blockNumber, balanceOfArgs) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expectedResult.SetString("1000000000000000000000000", 10) - Expect(result.String()).To(Equal(expectedResult.String())) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetBalance("", "", 0, nil) - - Expect(result.String()).To(Equal("0")) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("balanceOf")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("allowance", func() { - It("gets allowance data from the blockchain with the correct arguments", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - testTokenHolderAddress := common.HexToAddress("0x2cccc4b4708b318a6290511aac75d6c3dbe0cf9f") - testTokenSpenderAddress := common.HexToAddress("0x2cccc4b4708b318a6290511aac75d6c3dbe0cf9f") - - hashArgs := []common.Address{testTokenHolderAddress, testTokenSpenderAddress} - allowanceArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - allowanceArgs[i] = s - } - - _, err := testGetter.GetAllowance(testAbi, testContractAddress, blockNumber, allowanceArgs) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "allowance", allowanceArgs, &expected, blockNumber) - }) - - It("gets the allowance for a spending address and holder address on the dai contract at the given block height", func() { - infuraIPC := "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - - testTokenHolderAddress := common.HexToAddress("0x2cccc4b4708b318a6290511aac75d6c3dbe0cf9f") - testTokenSpenderAddress := common.HexToAddress("0x2cccc4b4708b318a6290511aac75d6c3dbe0cf9f") - - hashArgs := []common.Address{testTokenHolderAddress, testTokenSpenderAddress} - allowanceArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - allowanceArgs[i] = s - } - - result, err := realGetter.GetAllowance(constants.DaiAbiString, constants.DaiContractAddress, blockNumber, allowanceArgs) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expectedResult.SetString("0", 10) - Expect(result.String()).To(Equal(expectedResult.String())) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetAllowance("", "", 0, nil) - - Expect(result.String()).To(Equal("0")) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("allowance")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) -}) diff --git a/examples/erc20_watcher/every_block/integration_test.go b/examples/erc20_watcher/every_block/integration_test.go deleted file mode 100644 index c9ee0183..00000000 --- a/examples/erc20_watcher/every_block/integration_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block_test - -import ( - "math/big" - "strconv" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/examples/generic" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/fakes" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -func setLastBlockOnChain(blockChain *fakes.MockBlockChain, blockNumber int64) { - blockNumberString := strconv.FormatInt(blockNumber, 10) - lastBlockOnChain := big.Int{} - lastBlockOnChain.SetString(blockNumberString, 10) - blockChain.SetLastBlock(&lastBlockOnChain) -} - -var _ = Describe("Everyblock transformers", func() { - var db *postgres.DB - var blockChain *fakes.MockBlockChain - var blockNumber int64 - var blockId int64 - var err error - - BeforeEach(func() { - blockChain = fakes.NewMockBlockChain() - blockNumber = generic.DaiConfig.FirstBlock - lastBlockNumber := blockNumber + 1 - db = test_helpers.CreateNewDatabase() - setLastBlockOnChain(blockChain, lastBlockNumber) - - blockRepository := repositories.NewBlockRepository(db) - - blockId, err = blockRepository.CreateOrUpdateBlock(core.Block{Number: blockNumber}) - Expect(err).NotTo(HaveOccurred()) - _, err = blockRepository.CreateOrUpdateBlock(core.Block{Number: lastBlockNumber}) - Expect(err).NotTo(HaveOccurred()) - }) - - It("creates a token_supply record for each block in the given range", func() { - transformer, err := every_block.NewERC20TokenTransformer(db, blockChain, generic.DaiConfig) - Expect(err).ToNot(HaveOccurred()) - transformer.Execute() - - var tokenSupplyCount int - err = db.QueryRow(`SELECT COUNT(*) FROM token_supply where block_id = $1`, blockId).Scan(&tokenSupplyCount) - Expect(err).ToNot(HaveOccurred()) - Expect(tokenSupplyCount).To(Equal(1)) - - var tokenSupply test_helpers.TokenSupplyDBRow - err = db.Get(&tokenSupply, `SELECT * from token_supply where block_id = $1`, blockId) - Expect(err).ToNot(HaveOccurred()) - Expect(tokenSupply.BlockID).To(Equal(blockId)) - Expect(tokenSupply.TokenAddress).To(Equal(constants.DaiContractAddress)) - Expect(tokenSupply.Supply).To(Equal(int64(0))) - }) -}) diff --git a/examples/erc20_watcher/every_block/model.go b/examples/erc20_watcher/every_block/model.go deleted file mode 100644 index a2b5364b..00000000 --- a/examples/erc20_watcher/every_block/model.go +++ /dev/null @@ -1,41 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block - -// Struct to hold token supply data -type TokenSupply struct { - Value string - TokenAddress string - BlockNumber int64 -} - -// Struct to hold token holder address balance data -type TokenBalance struct { - Value string - TokenAddress string - BlockNumber int64 - TokenHolderAddress string -} - -// Struct to hold token allowance data -type TokenAllowance struct { - Value string - TokenAddress string - BlockNumber int64 - TokenHolderAddress string - TokenSpenderAddress string -} diff --git a/examples/erc20_watcher/every_block/repository.go b/examples/erc20_watcher/every_block/repository.go deleted file mode 100644 index ad5b7441..00000000 --- a/examples/erc20_watcher/every_block/repository.go +++ /dev/null @@ -1,205 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block - -import ( - "fmt" - "log" - - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -// Interface definition for a generic ERC20 token repository -type ERC20TokenDatastore interface { - CreateSupply(supply TokenSupply) error - CreateBalance(balance TokenBalance) error - CreateAllowance(allowance TokenAllowance) error - MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) - MissingBalanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress string) ([]int64, error) - MissingAllowanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress, spenderAddress string) ([]int64, error) -} - -// Generic ERC20 token Repo struct -type ERC20TokenRepository struct { - *postgres.DB -} - -// Repo error -type repositoryError struct { - err string - msg string - blockNumber int64 -} - -// Repo error method -func (re *repositoryError) Error() string { - return fmt.Sprintf(re.msg, re.blockNumber, re.err) -} - -// Used to create a new Repo error for a given error and fetch method -func newRepositoryError(err error, msg string, blockNumber int64) error { - e := repositoryError{err.Error(), msg, blockNumber} - log.Println(e.Error()) - return &e -} - -// Constant error definitions -const ( - GetBlockError = "Error fetching block number %d: %s" - InsertTokenSupplyError = "Error inserting token_supply for block number %d: %s" - InsertTokenBalanceError = "Error inserting token_balance for block number %d: %s" - InsertTokenAllowanceError = "Error inserting token_allowance for block number %d: %s" - MissingBlockError = "Error finding missing token_supply records starting at block %d: %s" -) - -// Supply methods -// This method inserts the supply for a given token contract address at a given block height into the token_supply table -func (tsp *ERC20TokenRepository) CreateSupply(supply TokenSupply) error { - var blockId int - err := tsp.DB.Get(&blockId, `SELECT id FROM blocks WHERE number = $1 AND eth_node_id = $2`, supply.BlockNumber, tsp.NodeID) - if err != nil { - return newRepositoryError(err, GetBlockError, supply.BlockNumber) - } - - _, err = tsp.DB.Exec( - `INSERT INTO token_supply (supply, token_address, block_id) - VALUES($1, $2, $3)`, - supply.Value, supply.TokenAddress, blockId) - if err != nil { - return newRepositoryError(err, InsertTokenSupplyError, supply.BlockNumber) - } - return nil -} - -// This method returns an array of blocks that are missing a token_supply entry for a given tokenAddress -func (tsp *ERC20TokenRepository) MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) { - blockNumbers := make([]int64, 0) - - err := tsp.DB.Select( - &blockNumbers, - `SELECT number FROM BLOCKS - LEFT JOIN token_supply ON blocks.id = block_id - AND token_address = $1 - WHERE block_id ISNULL - AND eth_node_id = $2 - AND number >= $3 - AND number <= $4 - LIMIT 20`, - tokenAddress, - tsp.NodeID, - startingBlock, - highestBlock, - ) - if err != nil { - return []int64{}, newRepositoryError(err, MissingBlockError, startingBlock) - } - return blockNumbers, err -} - -// Balance methods -// This method inserts the balance for a given token contract address and token owner address at a given block height into the token_balance table -func (tsp *ERC20TokenRepository) CreateBalance(balance TokenBalance) error { - var blockId int - err := tsp.DB.Get(&blockId, `SELECT id FROM blocks WHERE number = $1 AND eth_node_id = $2`, balance.BlockNumber, tsp.NodeID) - if err != nil { - return newRepositoryError(err, GetBlockError, balance.BlockNumber) - } - - _, err = tsp.DB.Exec( - `INSERT INTO token_balance (balance, token_address, block_id, token_holder_address) - VALUES($1, $2, $3, $4)`, - balance.Value, balance.TokenAddress, blockId, balance.TokenHolderAddress) - if err != nil { - return newRepositoryError(err, InsertTokenBalanceError, balance.BlockNumber) - } - return nil -} - -// This method returns an array of blocks that are missing a token_balance entry for a given token contract address and token owner address -func (tsp *ERC20TokenRepository) MissingBalanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress string) ([]int64, error) { - blockNumbers := make([]int64, 0) - - err := tsp.DB.Select( - &blockNumbers, - `SELECT number FROM BLOCKS - LEFT JOIN token_balance ON blocks.id = block_id - AND token_address = $1 - AND token_holder_address = $2 - WHERE block_id ISNULL - AND eth_node_id = $3 - AND number >= $4 - AND number <= $5 - LIMIT 20`, - tokenAddress, - holderAddress, - tsp.NodeID, - startingBlock, - highestBlock, - ) - if err != nil { - return []int64{}, newRepositoryError(err, MissingBlockError, startingBlock) - } - return blockNumbers, err -} - -// Allowance methods -// This method inserts the allowance for a given token contract address, token owner address, and token spender address at a given block height into the -func (tsp *ERC20TokenRepository) CreateAllowance(allowance TokenAllowance) error { - var blockId int - err := tsp.DB.Get(&blockId, `SELECT id FROM blocks WHERE number = $1 AND eth_node_id = $2`, allowance.BlockNumber, tsp.NodeID) - if err != nil { - return newRepositoryError(err, GetBlockError, allowance.BlockNumber) - } - - _, err = tsp.DB.Exec( - `INSERT INTO token_allowance (allowance, token_address, block_id, token_holder_address, token_spender_address) - VALUES($1, $2, $3, $4, $5)`, - allowance.Value, allowance.TokenAddress, blockId, allowance.TokenHolderAddress, allowance.TokenSpenderAddress) - if err != nil { - return newRepositoryError(err, InsertTokenAllowanceError, allowance.BlockNumber) - } - return nil -} - -// This method returns an array of blocks that are missing a token_allowance entry for a given token contract address, token owner address, and token spender address -func (tsp *ERC20TokenRepository) MissingAllowanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress, spenderAddress string) ([]int64, error) { - blockNumbers := make([]int64, 0) - - err := tsp.DB.Select( - &blockNumbers, - `SELECT number FROM BLOCKS - LEFT JOIN token_allowance ON blocks.id = block_id - AND token_address = $1 - AND token_holder_address = $2 - AND token_spender_address = $3 - WHERE block_id ISNULL - AND eth_node_id = $4 - AND number >= $5 - AND number <= $6 - LIMIT 20`, - tokenAddress, - holderAddress, - spenderAddress, - tsp.NodeID, - startingBlock, - highestBlock, - ) - if err != nil { - return []int64{}, newRepositoryError(err, MissingBlockError, startingBlock) - } - return blockNumbers, err -} diff --git a/examples/erc20_watcher/every_block/repository_test.go b/examples/erc20_watcher/every_block/repository_test.go deleted file mode 100644 index c3472209..00000000 --- a/examples/erc20_watcher/every_block/repository_test.go +++ /dev/null @@ -1,583 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block_test - -import ( - "math/rand" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/test_config" -) - -var _ = Describe("ERC20 Token Supply Repository", func() { - var db *postgres.DB - var blockId int64 - var blockNumber int64 - var repository every_block.ERC20TokenRepository - var blockRepository repositories.BlockRepository - testAddress := "abc" - - BeforeEach(func() { - db = test_helpers.CreateNewDatabase() - repository = every_block.ERC20TokenRepository{DB: db} - _, err := db.Query(`DELETE FROM token_supply`) - Expect(err).NotTo(HaveOccurred()) - - blockRepository = *repositories.NewBlockRepository(db) - blockNumber = rand.Int63() - blockId = test_helpers.CreateBlock(blockNumber, blockRepository) - }) - - Describe("Create", func() { - It("creates a token supply record", func() { - supply := supplyModel(blockNumber, testAddress, "100") - err := repository.CreateSupply(supply) - Expect(err).NotTo(HaveOccurred()) - - dbResult := test_helpers.TokenSupplyDBRow{} - expectedTokenSupply := test_helpers.TokenSupplyDBRow{ - Supply: int64(100), - BlockID: blockId, - TokenAddress: testAddress, - } - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_supply`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(1)) - - err = repository.DB.QueryRowx(`SELECT * FROM token_supply`).StructScan(&dbResult) - Expect(err).NotTo(HaveOccurred()) - Expect(dbResult.Supply).To(Equal(expectedTokenSupply.Supply)) - Expect(dbResult.BlockID).To(Equal(expectedTokenSupply.BlockID)) - Expect(dbResult.TokenAddress).To(Equal(expectedTokenSupply.TokenAddress)) - }) - - It("returns an error if fetching the block's id from the database fails", func() { - errorSupply := supplyModel(-1, "", "") - err := repository.CreateSupply(errorSupply) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("sql")) - Expect(err.Error()).To(ContainSubstring("block number -1")) - }) - - It("returns an error if inserting the token_supply fails", func() { - errorSupply := supplyModel(blockNumber, "", "") - err := repository.CreateSupply(errorSupply) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("pq")) - Expect(err.Error()).To(ContainSubstring("token_supply for block number")) - }) - }) - - Describe("When there are multiple nodes", func() { - var node2DB *postgres.DB - var node2BlockRepo *repositories.BlockRepository - var node2BlockId int64 - var node2TokenSupplyRepo every_block.ERC20TokenRepository - var tokenSupply every_block.TokenSupply - - BeforeEach(func() { - node2DB = createDbForAnotherNode() - - //create another block with the same number on node2 - node2BlockRepo = repositories.NewBlockRepository(node2DB) - node2BlockId = test_helpers.CreateBlock(blockNumber, *node2BlockRepo) - - tokenSupply = supplyModel(blockNumber, "abc", "100") - node2TokenSupplyRepo = every_block.ERC20TokenRepository{DB: node2DB} - }) - - It("only creates token_supply records for the current node (node2)", func() { - err := node2TokenSupplyRepo.CreateSupply(tokenSupply) - Expect(err).NotTo(HaveOccurred()) - - var tokenSupplies []test_helpers.TokenSupplyDBRow - err = node2TokenSupplyRepo.DB.Select(&tokenSupplies, `SELECT * FROM token_supply`) - Expect(err).NotTo(HaveOccurred()) - Expect(len(tokenSupplies)).To(Equal(1)) - Expect(tokenSupplies[0].BlockID).To(Equal(node2BlockId)) - }) - - It("only includes missing block numbers for the current node", func() { - //create token_supply on original node - err := repository.CreateSupply(tokenSupply) - Expect(err).NotTo(HaveOccurred()) - - originalNodeMissingBlocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress) - Expect(err).NotTo(HaveOccurred()) - Expect(len(originalNodeMissingBlocks)).To(Equal(0)) - - node2MissingBlocks, err := node2TokenSupplyRepo.MissingSupplyBlocks(blockNumber, blockNumber, testAddress) - Expect(err).NotTo(HaveOccurred()) - Expect(len(node2MissingBlocks)).To(Equal(1)) - }) - }) - - Describe("MissingBlocks", func() { - It("returns the block numbers for which an associated TokenSupply record hasn't been created", func() { - createTokenSupplyFor(repository, blockNumber, testAddress) - - newBlockNumber := blockNumber + 1 - test_helpers.CreateBlock(newBlockNumber, blockRepository) - blocks, err := repository.MissingSupplyBlocks(blockNumber, newBlockNumber, testAddress) - - Expect(blocks).To(ConsistOf(newBlockNumber)) - Expect(err).NotTo(HaveOccurred()) - }) - - It("only returns blocks within the given range", func() { - newBlockNumber := blockNumber + 1 - test_helpers.CreateBlock(newBlockNumber, blockRepository) - blocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress) - - Expect(blocks).NotTo(ConsistOf(newBlockNumber)) - Expect(err).NotTo(HaveOccurred()) - }) - - It("does not return numbers that already have an associated TokenSupply record", func() { - createTokenSupplyFor(repository, blockNumber, testAddress) - blocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress) - - Expect(blocks).To(BeEmpty()) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - It("deletes the token supply record when the associated block is deleted", func() { - err := repository.CreateSupply(every_block.TokenSupply{BlockNumber: blockNumber, TokenAddress: testAddress, Value: "0"}) - Expect(err).NotTo(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_supply`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(1)) - - _, err = db.Query(`DELETE FROM blocks`) - Expect(err).NotTo(HaveOccurred()) - - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_supply`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(0)) - }) -}) - -var _ = Describe("ERC20 Token Balance Repository", func() { - var db *postgres.DB - var blockId int64 - var blockNumber int64 - var repository every_block.ERC20TokenRepository - var blockRepository repositories.BlockRepository - testTokenAddress := "abc" - testHolderAddress := "def" - - BeforeEach(func() { - db = test_helpers.CreateNewDatabase() - repository = every_block.ERC20TokenRepository{DB: db} - _, err := db.Query(`DELETE FROM token_balance`) - Expect(err).NotTo(HaveOccurred()) - - blockRepository = *repositories.NewBlockRepository(db) - blockNumber = rand.Int63() - blockId = test_helpers.CreateBlock(blockNumber, blockRepository) - }) - - Describe("Create", func() { - It("creates a token balance record", func() { - balance := balanceOfModel(blockNumber, testTokenAddress, testHolderAddress, "100") - err := repository.CreateBalance(balance) - Expect(err).NotTo(HaveOccurred()) - - dbResult := test_helpers.TokenBalanceDBRow{} - expectedTokenBalance := test_helpers.TokenBalanceDBRow{ - Balance: int64(100), - BlockID: blockId, - TokenAddress: testTokenAddress, - TokenHolderAddress: testHolderAddress, - } - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_balance`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(1)) - - err = repository.DB.QueryRowx(`SELECT * FROM token_balance`).StructScan(&dbResult) - Expect(err).NotTo(HaveOccurred()) - Expect(dbResult.Balance).To(Equal(expectedTokenBalance.Balance)) - Expect(dbResult.BlockID).To(Equal(expectedTokenBalance.BlockID)) - Expect(dbResult.TokenAddress).To(Equal(expectedTokenBalance.TokenAddress)) - Expect(dbResult.TokenHolderAddress).To(Equal(expectedTokenBalance.TokenHolderAddress)) - }) - - It("returns an error if fetching the block's id from the database fails", func() { - errorBalance := balanceOfModel(-1, "", "", "") - err := repository.CreateBalance(errorBalance) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("sql")) - Expect(err.Error()).To(ContainSubstring("block number -1")) - }) - - It("returns an error if inserting the token_balance fails", func() { - errorBalance := balanceOfModel(blockNumber, "", "", "") - err := repository.CreateBalance(errorBalance) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("pq")) - Expect(err.Error()).To(ContainSubstring("token_balance for block number")) - }) - }) - - Describe("When there are multiple nodes", func() { - var node2DB *postgres.DB - var node2BlockRepo *repositories.BlockRepository - var node2BlockId int64 - var node2TokenSupplyRepo every_block.ERC20TokenRepository - var tokenBalance every_block.TokenBalance - - BeforeEach(func() { - node2DB = createDbForAnotherNode() - - //create another block with the same number on node2 - node2BlockRepo = repositories.NewBlockRepository(node2DB) - node2BlockId = test_helpers.CreateBlock(blockNumber, *node2BlockRepo) - - tokenBalance = balanceOfModel(blockNumber, "abc", "def", "100") - node2TokenSupplyRepo = every_block.ERC20TokenRepository{DB: node2DB} - }) - - It("only creates token_balance records for the current node (node2)", func() { - err := node2TokenSupplyRepo.CreateBalance(tokenBalance) - Expect(err).NotTo(HaveOccurred()) - - var tokenBalances []test_helpers.TokenBalanceDBRow - err = node2TokenSupplyRepo.DB.Select(&tokenBalances, `SELECT * FROM token_balance`) - Expect(err).NotTo(HaveOccurred()) - Expect(len(tokenBalances)).To(Equal(1)) - Expect(tokenBalances[0].BlockID).To(Equal(node2BlockId)) - }) - - It("only includes missing block numbers for the current node", func() { - //create token_balance on original node - err := repository.CreateBalance(tokenBalance) - Expect(err).NotTo(HaveOccurred()) - - originalNodeMissingBlocks, err := repository.MissingBalanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress) - Expect(err).NotTo(HaveOccurred()) - Expect(len(originalNodeMissingBlocks)).To(Equal(0)) - - node2MissingBlocks, err := node2TokenSupplyRepo.MissingBalanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress) - Expect(err).NotTo(HaveOccurred()) - Expect(len(node2MissingBlocks)).To(Equal(1)) - }) - }) - - Describe("MissingBlocks", func() { - It("returns the block numbers for which an associated TokenBalance record hasn't been created", func() { - createTokenBalanceFor(repository, blockNumber, testTokenAddress, testHolderAddress) - - newBlockNumber := blockNumber + 1 - test_helpers.CreateBlock(newBlockNumber, blockRepository) - blocks, err := repository.MissingBalanceBlocks(blockNumber, newBlockNumber, testTokenAddress, testHolderAddress) - - Expect(blocks).To(ConsistOf(newBlockNumber)) - Expect(err).NotTo(HaveOccurred()) - }) - - It("only returns blocks within the given range", func() { - newBlockNumber := blockNumber + 1 - test_helpers.CreateBlock(newBlockNumber, blockRepository) - blocks, err := repository.MissingBalanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress) - - Expect(blocks).NotTo(ConsistOf(newBlockNumber)) - Expect(err).NotTo(HaveOccurred()) - }) - - It("does not return numbers that already have an associated TokenBalance record", func() { - createTokenBalanceFor(repository, blockNumber, testTokenAddress, testHolderAddress) - blocks, err := repository.MissingBalanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress) - - Expect(blocks).To(BeEmpty()) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - It("deletes the token balance record when the associated block is deleted", func() { - err := repository.CreateBalance(every_block.TokenBalance{ - BlockNumber: blockNumber, - TokenAddress: testTokenAddress, - TokenHolderAddress: testHolderAddress, - Value: "0", - }) - Expect(err).NotTo(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_balance`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(1)) - - _, err = db.Query(`DELETE FROM blocks`) - Expect(err).NotTo(HaveOccurred()) - - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_balance`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(0)) - }) -}) - -var _ = Describe("ERC20 Token Allowance Repository", func() { - var db *postgres.DB - var blockId int64 - var blockNumber int64 - var repository every_block.ERC20TokenRepository - var blockRepository repositories.BlockRepository - testTokenAddress := "abc" - testHolderAddress := "def" - testSpenderAddress := "ghi" - - BeforeEach(func() { - db = test_helpers.CreateNewDatabase() - repository = every_block.ERC20TokenRepository{DB: db} - _, err := db.Query(`DELETE FROM token_allowance`) - Expect(err).NotTo(HaveOccurred()) - - blockRepository = *repositories.NewBlockRepository(db) - blockNumber = rand.Int63() - blockId = test_helpers.CreateBlock(blockNumber, blockRepository) - }) - - Describe("Create", func() { - It("creates a token balance record", func() { - allowance := allowanceModel(blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress, "100") - err := repository.CreateAllowance(allowance) - Expect(err).NotTo(HaveOccurred()) - - dbResult := test_helpers.TokenAllowanceDBRow{} - expectedTokenAllowance := test_helpers.TokenAllowanceDBRow{ - Allowance: int64(100), - BlockID: blockId, - TokenAddress: testTokenAddress, - TokenHolderAddress: testHolderAddress, - TokenSpenderAddress: testSpenderAddress, - } - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_allowance`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(1)) - - err = repository.DB.QueryRowx(`SELECT * FROM token_allowance`).StructScan(&dbResult) - Expect(err).NotTo(HaveOccurred()) - Expect(dbResult.Allowance).To(Equal(expectedTokenAllowance.Allowance)) - Expect(dbResult.BlockID).To(Equal(expectedTokenAllowance.BlockID)) - Expect(dbResult.TokenAddress).To(Equal(expectedTokenAllowance.TokenAddress)) - Expect(dbResult.TokenHolderAddress).To(Equal(expectedTokenAllowance.TokenHolderAddress)) - }) - - It("returns an error if fetching the block's id from the database fails", func() { - errorAllowance := allowanceModel(-1, "", "", "", "") - err := repository.CreateAllowance(errorAllowance) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("sql")) - Expect(err.Error()).To(ContainSubstring("block number -1")) - }) - - It("returns an error if inserting the token_allowance fails", func() { - errorAllowance := allowanceModel(blockNumber, "", "", "", "") - err := repository.CreateAllowance(errorAllowance) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("pq")) - Expect(err.Error()).To(ContainSubstring("token_allowance for block number")) - }) - }) - - Describe("When there are multiple nodes", func() { - var node2DB *postgres.DB - var node2BlockRepo *repositories.BlockRepository - var node2BlockId int64 - var node2TokenSupplyRepo every_block.ERC20TokenRepository - var tokenAllowance every_block.TokenAllowance - - BeforeEach(func() { - node2DB = createDbForAnotherNode() - - //create another block with the same number on node2 - node2BlockRepo = repositories.NewBlockRepository(node2DB) - node2BlockId = test_helpers.CreateBlock(blockNumber, *node2BlockRepo) - - tokenAllowance = allowanceModel(blockNumber, "abc", "def", "ghi", "100") - node2TokenSupplyRepo = every_block.ERC20TokenRepository{DB: node2DB} - }) - - It("only creates token_allowance records for the current node (node2)", func() { - err := node2TokenSupplyRepo.CreateAllowance(tokenAllowance) - Expect(err).NotTo(HaveOccurred()) - - var tokenAllowances []test_helpers.TokenAllowanceDBRow - err = node2TokenSupplyRepo.DB.Select(&tokenAllowances, `SELECT * FROM token_allowance`) - Expect(err).NotTo(HaveOccurred()) - Expect(len(tokenAllowances)).To(Equal(1)) - Expect(tokenAllowances[0].BlockID).To(Equal(node2BlockId)) - }) - - It("only includes missing block numbers for the current node", func() { - //create token_allowance on original node - err := repository.CreateAllowance(tokenAllowance) - Expect(err).NotTo(HaveOccurred()) - - originalNodeMissingBlocks, err := repository.MissingAllowanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - Expect(err).NotTo(HaveOccurred()) - Expect(len(originalNodeMissingBlocks)).To(Equal(0)) - - node2MissingBlocks, err := node2TokenSupplyRepo.MissingAllowanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - Expect(err).NotTo(HaveOccurred()) - Expect(len(node2MissingBlocks)).To(Equal(1)) - }) - }) - - Describe("MissingBlocks", func() { - It("returns the block numbers for which an associated TokenAllowance record hasn't been created", func() { - createTokenAllowanceFor(repository, blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - - newBlockNumber := blockNumber + 1 - test_helpers.CreateBlock(newBlockNumber, blockRepository) - blocks, err := repository.MissingAllowanceBlocks(blockNumber, newBlockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - - Expect(blocks).To(ConsistOf(newBlockNumber)) - Expect(err).NotTo(HaveOccurred()) - }) - - It("only returns blocks within the given range", func() { - newBlockNumber := blockNumber + 1 - test_helpers.CreateBlock(newBlockNumber, blockRepository) - blocks, err := repository.MissingAllowanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - - Expect(blocks).NotTo(ConsistOf(newBlockNumber)) - Expect(err).NotTo(HaveOccurred()) - }) - - It("does not return numbers that already have an associated TokenAllowance record", func() { - createTokenAllowanceFor(repository, blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - blocks, err := repository.MissingAllowanceBlocks(blockNumber, blockNumber, testTokenAddress, testHolderAddress, testSpenderAddress) - - Expect(blocks).To(BeEmpty()) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - It("deletes the token balance record when the associated block is deleted", func() { - err := repository.CreateAllowance(every_block.TokenAllowance{ - BlockNumber: blockNumber, - TokenAddress: testTokenAddress, - TokenHolderAddress: testHolderAddress, - TokenSpenderAddress: testSpenderAddress, - Value: "0", - }) - Expect(err).NotTo(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_allowance`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(1)) - - _, err = db.Query(`DELETE FROM blocks`) - Expect(err).NotTo(HaveOccurred()) - - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_allowance`).Scan(&count) - Expect(err).NotTo(HaveOccurred()) - Expect(count).To(Equal(0)) - }) -}) - -func supplyModel(blockNumber int64, tokenAddress, supplyValue string) every_block.TokenSupply { - return every_block.TokenSupply{ - Value: supplyValue, - TokenAddress: tokenAddress, - BlockNumber: blockNumber, - } -} - -func balanceOfModel(blockNumber int64, tokenAddress, holderAddress, supplyValue string) every_block.TokenBalance { - return every_block.TokenBalance{ - Value: supplyValue, - TokenAddress: tokenAddress, - TokenHolderAddress: holderAddress, - BlockNumber: blockNumber, - } -} - -func allowanceModel(blockNumber int64, tokenAddress, holderAddress, spenderAddress, supplyValue string) every_block.TokenAllowance { - return every_block.TokenAllowance{ - Value: supplyValue, - TokenAddress: tokenAddress, - TokenHolderAddress: holderAddress, - TokenSpenderAddress: spenderAddress, - BlockNumber: blockNumber, - } -} - -func createTokenSupplyFor(repository every_block.ERC20TokenRepository, blockNumber int64, tokenAddress string) { - err := repository.CreateSupply(every_block.TokenSupply{ - BlockNumber: blockNumber, - TokenAddress: tokenAddress, - Value: "0", - }) - Expect(err).NotTo(HaveOccurred()) -} - -func createTokenBalanceFor(repository every_block.ERC20TokenRepository, blockNumber int64, tokenAddress, holderAddress string) { - err := repository.CreateBalance(every_block.TokenBalance{ - BlockNumber: blockNumber, - TokenAddress: tokenAddress, - TokenHolderAddress: holderAddress, - Value: "0", - }) - Expect(err).NotTo(HaveOccurred()) -} - -func createTokenAllowanceFor(repository every_block.ERC20TokenRepository, blockNumber int64, tokenAddress, holderAddress, spenderAddress string) { - err := repository.CreateAllowance(every_block.TokenAllowance{ - BlockNumber: blockNumber, - TokenAddress: tokenAddress, - TokenHolderAddress: holderAddress, - TokenSpenderAddress: spenderAddress, - Value: "0", - }) - Expect(err).NotTo(HaveOccurred()) -} - -func createDbForAnotherNode() *postgres.DB { - anotherNode := core.Node{ - GenesisBlock: "GENESIS", - NetworkID: 1, - ID: "testNodeId", - ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9", - } - - return test_config.NewTestDBWithoutDeletingRecords(anotherNode) -} diff --git a/examples/erc20_watcher/every_block/transformer.go b/examples/erc20_watcher/every_block/transformer.go deleted file mode 100644 index bdff1afa..00000000 --- a/examples/erc20_watcher/every_block/transformer.go +++ /dev/null @@ -1,240 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block - -import ( - "fmt" - "log" - "math/big" - - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -type ERC20Transformer struct { - Getter ERC20GetterInterface - Repository ERC20TokenDatastore - Retriever erc20_watcher.TokenHolderRetriever - Config shared.ContractConfig -} - -func (t *ERC20Transformer) SetConfiguration(config shared.ContractConfig) { - t.Config = config -} - -func NewERC20TokenTransformer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) { - getter := NewGetter(blockchain) - repository := ERC20TokenRepository{DB: db} - retriever := erc20_watcher.NewTokenHolderRetriever(db, con.Address) - - transformer := ERC20Transformer{ - Getter: &getter, - Repository: &repository, - Retriever: retriever, - Config: con, - } - - return transformer, nil -} - -const ( - FetchingBlocksError = "Error fetching missing blocks starting at block number %d: %s" - FetchingSupplyError = "Error fetching supply for block %d: %s" - CreateSupplyError = "Error inserting token_supply for block %d: %s" - FetchingTokenAddressesError = "Error fetching token holder addresses at block %d: %s" - FetchingBalanceError = "Error fetching balance at block %d: %s" - CreateBalanceError = "Error inserting token_balance at block %d: %s" - FetchingAllowanceError = "Error fetching allowance at block %d: %s" - CreateAllowanceError = "Error inserting allowance at block %d: %s" -) - -type transformerError struct { - err string - blockNumber int64 - msg string -} - -func (te *transformerError) Error() string { - return fmt.Sprintf(te.msg, te.blockNumber, te.err) -} - -func newTransformerError(err error, blockNumber int64, msg string) error { - e := transformerError{err.Error(), blockNumber, msg} - log.Println(e.Error()) - return &e -} - -func (t ERC20Transformer) Execute() error { - var upperBoundBlock int64 - blockchain := t.Getter.GetBlockChain() - lastBlock := blockchain.LastBlock().Int64() - - if t.Config.LastBlock == -1 { - upperBoundBlock = lastBlock - } else { - upperBoundBlock = t.Config.LastBlock - } - - // Supply transformations: - - // Fetch missing supply blocks - blocks, err := t.Repository.MissingSupplyBlocks(t.Config.FirstBlock, upperBoundBlock, t.Config.Address) - - if err != nil { - return newTransformerError(err, t.Config.FirstBlock, FetchingBlocksError) - } - - // Fetch supply for missing blocks - log.Printf("Fetching totalSupply for %d blocks", len(blocks)) - - // For each block missing total supply, create supply model and feed the missing data into the repository - for _, blockNumber := range blocks { - totalSupply, err := t.Getter.GetTotalSupply(t.Config.Abi, t.Config.Address, blockNumber) - - if err != nil { - return newTransformerError(err, blockNumber, FetchingSupplyError) - } - // Create the supply model - model := createTokenSupplyModel(totalSupply, t.Config.Address, blockNumber) - // Feed it into the repository - err = t.Repository.CreateSupply(model) - - if err != nil { - return newTransformerError(err, blockNumber, CreateSupplyError) - } - } - - // Balance and allowance transformations: - - // Retrieve all token holder addresses for the given contract configuration - - tokenHolderAddresses, err := t.Retriever.RetrieveTokenHolderAddresses() - if err != nil { - return newTransformerError(err, t.Config.FirstBlock, FetchingTokenAddressesError) - } - - // Iterate over the addresses and add their balances and allowances at each block height to the repository - for holderAddr := range tokenHolderAddresses { - - // Balance transformations: - - blocks, err := t.Repository.MissingBalanceBlocks(t.Config.FirstBlock, upperBoundBlock, t.Config.Address, holderAddr.String()) - - if err != nil { - return newTransformerError(err, t.Config.FirstBlock, FetchingBlocksError) - } - - log.Printf("Fetching balances for %d blocks", len(blocks)) - - // For each block missing balances for the given address, create a balance model and feed the missing data into the repository - for _, blockNumber := range blocks { - - hashArgs := []common.Address{holderAddr} - balanceOfArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - balanceOfArgs[i] = s - } - - totalSupply, err := t.Getter.GetBalance(t.Config.Abi, t.Config.Address, blockNumber, balanceOfArgs) - - if err != nil { - return newTransformerError(err, blockNumber, FetchingBalanceError) - } - - model := createTokenBalanceModel(totalSupply, t.Config.Address, blockNumber, holderAddr.String()) - - err = t.Repository.CreateBalance(model) - - if err != nil { - return newTransformerError(err, blockNumber, CreateBalanceError) - } - } - - // Allowance transformations: - - for spenderAddr := range tokenHolderAddresses { - - blocks, err := t.Repository.MissingAllowanceBlocks(t.Config.FirstBlock, upperBoundBlock, t.Config.Address, holderAddr.String(), spenderAddr.String()) - - if err != nil { - return newTransformerError(err, t.Config.FirstBlock, FetchingBlocksError) - } - - log.Printf("Fetching allowances for %d blocks", len(blocks)) - - // For each block missing allowances for the given holder and spender addresses, create a allowance model and feed the missing data into the repository - for _, blockNumber := range blocks { - - hashArgs := []common.Address{holderAddr, spenderAddr} - allowanceArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - allowanceArgs[i] = s - } - - totalSupply, err := t.Getter.GetAllowance(t.Config.Abi, t.Config.Address, blockNumber, allowanceArgs) - - if err != nil { - return newTransformerError(err, blockNumber, FetchingAllowanceError) - } - - model := createTokenAllowanceModel(totalSupply, t.Config.Address, blockNumber, holderAddr.String(), spenderAddr.String()) - - err = t.Repository.CreateAllowance(model) - - if err != nil { - return newTransformerError(err, blockNumber, CreateAllowanceError) - } - - } - - } - - } - - return nil -} - -func createTokenSupplyModel(totalSupply big.Int, address string, blockNumber int64) TokenSupply { - return TokenSupply{ - Value: totalSupply.String(), - TokenAddress: address, - BlockNumber: blockNumber, - } -} - -func createTokenBalanceModel(tokenBalance big.Int, tokenAddress string, blockNumber int64, tokenHolderAddress string) TokenBalance { - return TokenBalance{ - Value: tokenBalance.String(), - TokenAddress: tokenAddress, - BlockNumber: blockNumber, - TokenHolderAddress: tokenHolderAddress, - } -} - -func createTokenAllowanceModel(tokenBalance big.Int, tokenAddress string, blockNumber int64, tokenHolderAddress, tokenSpenderAddress string) TokenAllowance { - return TokenAllowance{ - Value: tokenBalance.String(), - TokenAddress: tokenAddress, - BlockNumber: blockNumber, - TokenHolderAddress: tokenHolderAddress, - TokenSpenderAddress: tokenSpenderAddress, - } -} diff --git a/examples/erc20_watcher/every_block/transformer_test.go b/examples/erc20_watcher/every_block/transformer_test.go deleted file mode 100644 index 43a6dce1..00000000 --- a/examples/erc20_watcher/every_block/transformer_test.go +++ /dev/null @@ -1,197 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block_test - -import ( - "math/big" - "math/rand" - "strconv" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher" - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/examples/mocks" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/fakes" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var testContractConfig = shared.ContractConfig{ - Address: constants.DaiContractAddress, - Abi: constants.DaiAbiString, - FirstBlock: int64(4752008), - LastBlock: int64(5750050), - Name: "Dai", -} - -var config = testContractConfig - -var _ = Describe("Everyblock transformer", func() { - var getter mocks.Getter - var repository mocks.ERC20TokenRepository - var transformer every_block.ERC20Transformer - var blockChain *fakes.MockBlockChain - var initialSupply = "27647235749155415536952630" - var initialSupplyPlusOne = "27647235749155415536952631" - var initialSupplyPlusTwo = "27647235749155415536952632" - var initialSupplyPlusThree = "27647235749155415536952633" - var defaultLastBlock = big.Int{} - - BeforeEach(func() { - blockChain = fakes.NewMockBlockChain() - blockChain.SetLastBlock(&defaultLastBlock) - getter = mocks.NewGetter(blockChain) - getter.Fetcher.SetSupply(initialSupply) - repository = mocks.ERC20TokenRepository{} - repository.SetMissingSupplyBlocks([]int64{config.FirstBlock}) - db := test_helpers.CreateNewDatabase() - rt := erc20_watcher.NewTokenHolderRetriever(db, config.Address) - //setting the mock repository to return the first block as the missing blocks - - transformer = every_block.ERC20Transformer{ - Getter: &getter, - Repository: &repository, - Retriever: rt, - Config: config, - } - transformer.SetConfiguration(config) - }) - - It("fetches and persists the total supply of a token for a single block", func() { - err := transformer.Execute() - Expect(err).NotTo(HaveOccurred()) - - Expect(len(getter.Fetcher.FetchedBlocks)).To(Equal(1)) - Expect(getter.Fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock)) - Expect(getter.Fetcher.Abi).To(Equal(config.Abi)) - Expect(getter.Fetcher.ContractAddress).To(Equal(config.Address)) - - Expect(repository.StartingBlock).To(Equal(config.FirstBlock)) - Expect(repository.EndingBlock).To(Equal(config.LastBlock)) - Expect(len(repository.TotalSuppliesCreated)).To(Equal(1)) - expectedSupply := big.Int{} - expectedSupply.SetString(initialSupply, 10) - expectedSupply.Add(&expectedSupply, big.NewInt(1)) - - Expect(repository.TotalSuppliesCreated[0].Value).To(Equal(expectedSupply.String())) - }) - - It("retrieves the total supply for every missing block", func() { - missingBlocks := []int64{ - config.FirstBlock, - config.FirstBlock + 1, - config.FirstBlock + 2, - } - repository.SetMissingSupplyBlocks(missingBlocks) - err := transformer.Execute() - Expect(err).NotTo(HaveOccurred()) - - Expect(len(getter.Fetcher.FetchedBlocks)).To(Equal(3)) - Expect(getter.Fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock, config.FirstBlock+1, config.FirstBlock+2)) - Expect(getter.Fetcher.Abi).To(Equal(config.Abi)) - Expect(getter.Fetcher.ContractAddress).To(Equal(config.Address)) - - Expect(len(repository.TotalSuppliesCreated)).To(Equal(3)) - Expect(repository.TotalSuppliesCreated[0].Value).To(Equal(initialSupplyPlusOne)) - Expect(repository.TotalSuppliesCreated[1].Value).To(Equal(initialSupplyPlusTwo)) - Expect(repository.TotalSuppliesCreated[2].Value).To(Equal(initialSupplyPlusThree)) - }) - - It("uses the set contract configuration", func() { - repository.SetMissingSupplyBlocks([]int64{testContractConfig.FirstBlock}) - transformer.SetConfiguration(testContractConfig) - err := transformer.Execute() - Expect(err).NotTo(HaveOccurred()) - - Expect(getter.Fetcher.FetchedBlocks).To(ConsistOf(testContractConfig.FirstBlock)) - Expect(getter.Fetcher.Abi).To(Equal(testContractConfig.Abi)) - Expect(getter.Fetcher.ContractAddress).To(Equal(testContractConfig.Address)) - - Expect(repository.StartingBlock).To(Equal(testContractConfig.FirstBlock)) - Expect(repository.EndingBlock).To(Equal(testContractConfig.LastBlock)) - Expect(len(repository.TotalSuppliesCreated)).To(Equal(1)) - expectedTokenSupply := every_block.TokenSupply{ - Value: initialSupplyPlusOne, - TokenAddress: testContractConfig.Address, - BlockNumber: testContractConfig.FirstBlock, - } - Expect(repository.TotalSuppliesCreated[0]).To(Equal(expectedTokenSupply)) - }) - - It("uses the most recent block if the Config.LastBlock is -1", func() { - testContractConfig.LastBlock = -1 - transformer.SetConfiguration(testContractConfig) - - randomBlockNumber := rand.Int63() - numberToString := strconv.FormatInt(randomBlockNumber, 10) - mostRecentBlock := big.Int{} - mostRecentBlock.SetString(numberToString, 10) - - blockChain.SetLastBlock(&mostRecentBlock) - - err := transformer.Execute() - Expect(err).NotTo(HaveOccurred()) - - Expect(repository.EndingBlock).To(Equal(randomBlockNumber)) - }) - - It("returns an error if the call to get missing blocks fails", func() { - failureRepository := mocks.FailureRepository{} - failureRepository.SetMissingSupplyBlocksFail(true) - transformer = every_block.ERC20Transformer{ - Getter: &getter, - Repository: &failureRepository, - } - err := transformer.Execute() - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - Expect(err.Error()).To(ContainSubstring("fetching missing blocks")) - }) - - It("returns an error if the call to the blockChain fails", func() { - failureBlockchain := fakes.NewMockBlockChain() - failureBlockchain.SetLastBlock(&defaultLastBlock) - failureBlockchain.SetFetchContractDataErr(fakes.FakeError) - getter := every_block.NewGetter(failureBlockchain) - transformer = every_block.ERC20Transformer{ - Getter: &getter, - Repository: &repository, - } - err := transformer.Execute() - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - Expect(err.Error()).To(ContainSubstring("supply")) - }) - - It("returns an error if the call to save the token_supply fails", func() { - failureRepository := mocks.FailureRepository{} - failureRepository.SetMissingSupplyBlocks([]int64{config.FirstBlock}) - failureRepository.SetCreateSupplyFail(true) - - transformer = every_block.ERC20Transformer{ - Getter: &getter, - Repository: &failureRepository, - } - err := transformer.Execute() - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - Expect(err.Error()).To(ContainSubstring("supply")) - }) -}) diff --git a/examples/erc20_watcher/retriever.go b/examples/erc20_watcher/retriever.go deleted file mode 100644 index 02232a5a..00000000 --- a/examples/erc20_watcher/retriever.go +++ /dev/null @@ -1,185 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package erc20_watcher - -import ( - "fmt" - "log" - - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -// ERC20 retriever is used to iterate over addresses involved in token -// transfers and approvals to generate a list of token holder addresses - -type TokenHolderRetrieverInterface interface { - RetrieveTokenHolderAddresses() (map[common.Address]bool, error) - retrieveTokenSenders() ([]string, error) - retrieveTokenReceivers() ([]string, error) - retrieveTokenOwners() ([]string, error) - retrieveTokenSpenders() ([]string, error) -} - -type TokenHolderRetriever struct { - Database *postgres.DB - ContractAddress string -} - -type retrieverError struct { - err string - msg string - address string -} - -// Retriever error method -func (re *retrieverError) Error() string { - return fmt.Sprintf(re.msg, re.address, re.err) -} - -// Used to create a new retriever error for a given error and fetch method -func newRetrieverError(err error, msg string, address string) error { - e := retrieverError{err.Error(), msg, address} - log.Println(e.Error()) - return &e -} - -// Constant error definitions -const ( - GetSendersError = "Error fetching token senders from contract %s: %s" - GetReceiversError = "Error fetching token receivers from contract %s: %s" - GetOwnersError = "Error fetching token owners from contract %s: %s" - GetSpendersError = "Error fetching token spenders from contract %s: %s" -) - -func NewTokenHolderRetriever(db *postgres.DB, address string) TokenHolderRetriever { - return TokenHolderRetriever{ - Database: db, - ContractAddress: address, - } -} - -func (rt TokenHolderRetriever) retrieveTokenSenders() ([]string, error) { - - senders := make([]string, 0) - - err := rt.Database.DB.Select( - &senders, - `SELECT from_address FROM token_transfers - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetSendersError, rt.ContractAddress) - } - - return senders, nil -} - -func (rt TokenHolderRetriever) retrieveTokenReceivers() ([]string, error) { - - receivers := make([]string, 0) - - err := rt.Database.DB.Select( - &receivers, - `SELECT to_address FROM token_transfers - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetReceiversError, rt.ContractAddress) - } - return receivers, err -} - -func (rt TokenHolderRetriever) retrieveTokenOwners() ([]string, error) { - - owners := make([]string, 0) - - err := rt.Database.DB.Select( - &owners, - `SELECT owner FROM token_approvals - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetOwnersError, rt.ContractAddress) - } - - return owners, nil -} - -func (rt TokenHolderRetriever) retrieveTokenSpenders() ([]string, error) { - - spenders := make([]string, 0) - - err := rt.Database.DB.Select( - &spenders, - `SELECT spender FROM token_approvals - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetSpendersError, rt.ContractAddress) - } - - return spenders, nil -} - -func (rt TokenHolderRetriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, error) { - - senders, err := rt.retrieveTokenSenders() - if err != nil { - return nil, err - } - - receivers, err := rt.retrieveTokenReceivers() - if err != nil { - return nil, err - } - - owners, err := rt.retrieveTokenOwners() - if err != nil { - return nil, err - } - - spenders, err := rt.retrieveTokenSenders() - if err != nil { - return nil, err - } - - contractAddresses := make(map[common.Address]bool) - - for _, addr := range senders { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range receivers { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range owners { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range spenders { - contractAddresses[common.HexToAddress(addr)] = true - } - - return contractAddresses, nil -} diff --git a/examples/generic/event_triggered/model.go b/examples/generic/event_triggered/model.go deleted file mode 100644 index d8a6299e..00000000 --- a/examples/generic/event_triggered/model.go +++ /dev/null @@ -1,36 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package event_triggered - -type BurnModel struct { - TokenName string `db:"token_name"` - TokenAddress string `db:"token_address"` - Burner string `db:"burner"` - Tokens string `db:"tokens"` - Block int64 `db:"block"` - TxHash string `db:"tx"` -} - -type MintModel struct { - TokenName string `db:"token_name"` - TokenAddress string `db:"token_address"` - Mintee string `db:"mintee"` - Minter string `db:"minter"` - Tokens string `db:"tokens"` - Block int64 `db:"block"` - TxHash string `db:"tx"` -} diff --git a/examples/generic/event_triggered/repository.go b/examples/generic/event_triggered/repository.go deleted file mode 100644 index b0904b76..00000000 --- a/examples/generic/event_triggered/repository.go +++ /dev/null @@ -1,52 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package event_triggered - -import ( - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -type GenericEventDatastore interface { - CreateBurn(model *BurnModel, vulcanizeLogId int64) error - CreateMint(model *MintModel, vulcanizeLogId int64) error -} - -type GenericEventRepository struct { - *postgres.DB -} - -func (repository GenericEventRepository) CreateBurn(burnModel *BurnModel, vulcanizeLogId int64) error { - _, err := repository.DB.Exec( - - `INSERT INTO token_burns (vulcanize_log_id, token_name, token_address, burner, tokens, block, tx) - VALUES ($1, $2, $3, $4, $5, $6, $7) - ON CONFLICT (vulcanize_log_id) DO NOTHING`, - vulcanizeLogId, burnModel.TokenName, burnModel.TokenAddress, burnModel.Burner, burnModel.Tokens, burnModel.Block, burnModel.TxHash) - - return err -} - -func (repository GenericEventRepository) CreateMint(mintModel *MintModel, vulcanizeLogId int64) error { - _, err := repository.DB.Exec( - - `INSERT INTO token_mints (vulcanize_log_id, token_name, token_address, minter, mintee, tokens, block, tx) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8) - ON CONFLICT (vulcanize_log_id) DO NOTHING`, - vulcanizeLogId, mintModel.TokenName, mintModel.TokenAddress, mintModel.Minter, mintModel.Mintee, mintModel.Tokens, mintModel.Block, mintModel.TxHash) - - return err -} diff --git a/examples/generic/event_triggered/tusd/converter.go b/examples/generic/event_triggered/tusd/converter.go deleted file mode 100644 index 43fe0bf2..00000000 --- a/examples/generic/event_triggered/tusd/converter.go +++ /dev/null @@ -1,120 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package tusd - -import ( - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" -) - -// Converter converts a raw event log into its corresponding entity -// and can subsequently convert the entity into a model - -type GenericConverterInterface interface { - ToBurnEntity(watchedEvent core.WatchedEvent) (*BurnEntity, error) - ToBurnModel(entity *BurnEntity) *event_triggered.BurnModel - ToMintEntity(watchedEvent core.WatchedEvent) (*MintEntity, error) - ToMintModel(entity *MintEntity) *event_triggered.MintModel -} - -type GenericConverter struct { - config shared.ContractConfig -} - -func NewGenericConverter(config shared.ContractConfig) (*GenericConverter, error) { - var err error - - config.ParsedAbi, err = geth.ParseAbi(config.Abi) - if err != nil { - return nil, err - } - - converter := &GenericConverter{ - config: config, - } - - return converter, nil -} - -func (c GenericConverter) ToBurnEntity(watchedEvent core.WatchedEvent) (*BurnEntity, error) { - result := &BurnEntity{} - contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) - event := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLog(result, constants.BurnEvent.String(), event) - if err != nil { - return result, err - } - result.TokenName = c.config.Name - result.TokenAddress = common.HexToAddress(c.config.Address) - result.Block = watchedEvent.BlockNumber - result.TxHash = watchedEvent.TxHash - - return result, nil -} - -func (c GenericConverter) ToBurnModel(entity *BurnEntity) *event_triggered.BurnModel { - burner := entity.Burner.String() - tokens := entity.Value.String() - - return &event_triggered.BurnModel{ - TokenName: c.config.Name, - TokenAddress: c.config.Address, - Burner: burner, - Tokens: tokens, - Block: entity.Block, - TxHash: entity.TxHash, - } -} - -func (c GenericConverter) ToMintEntity(watchedEvent core.WatchedEvent) (*MintEntity, error) { - result := &MintEntity{} - contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) - event := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLog(result, constants.MintEvent.String(), event) - if err != nil { - return result, err - } - result.TokenName = c.config.Name - result.TokenAddress = common.HexToAddress(c.config.Address) - result.Block = watchedEvent.BlockNumber - result.TxHash = watchedEvent.TxHash - - return result, nil -} - -func (c GenericConverter) ToMintModel(entity *MintEntity) *event_triggered.MintModel { - mintee := entity.To.String() - minter := c.config.Owner - tokens := entity.Amount.String() - - return &event_triggered.MintModel{ - TokenName: c.config.Name, - TokenAddress: c.config.Address, - Mintee: mintee, - Minter: minter, - Tokens: tokens, - Block: entity.Block, - TxHash: entity.TxHash, - } -} diff --git a/examples/generic/event_triggered/tusd/converter_test.go b/examples/generic/event_triggered/tusd/converter_test.go deleted file mode 100644 index c2527022..00000000 --- a/examples/generic/event_triggered/tusd/converter_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package tusd_test - -import ( - "github.com/ethereum/go-ethereum/common" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/generic" - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered/tusd" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" -) - -var expectedBurnModel = event_triggered.BurnModel{ - TokenName: "Tusd", - TokenAddress: constants.TusdContractAddress, - Burner: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", - Tokens: "1097077688018008265106216665536940668749033598146", - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var expectedBurnEntity = tusd.BurnEntity{ - TokenName: "Tusd", - TokenAddress: common.HexToAddress(constants.TusdContractAddress), - Burner: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Value: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var expectedMintModel = event_triggered.MintModel{ - TokenName: "Tusd", - TokenAddress: constants.TusdContractAddress, - Minter: constants.TusdContractOwner, - Mintee: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", - Tokens: "1097077688018008265106216665536940668749033598146", - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var expectedMintEntity = tusd.MintEntity{ - TokenName: "Tusd", - TokenAddress: common.HexToAddress(constants.TusdContractAddress), - To: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Amount: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var burnEvent = core.WatchedEvent{ - LogID: 1, - Name: constants.BurnEvent.String(), - BlockNumber: 5488076, - Address: constants.TusdContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.BurnEvent.Signature(), - Topic1: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic2: "", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -var mintEvent = core.WatchedEvent{ - LogID: 1, - Name: constants.MintEvent.String(), - BlockNumber: 5488076, - Address: constants.TusdContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.MintEvent.Signature(), - Topic1: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic2: "", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -var _ = Describe("Transfer Converter", func() { - - var converter *tusd.GenericConverter - var err error - - BeforeEach(func() { - converter, err = tusd.NewGenericConverter(generic.TusdConfig) - Expect(err).NotTo(HaveOccurred()) - }) - - It("converts a watched burn event into a BurnEntity", func() { - - result, err := converter.ToBurnEntity(burnEvent) - Expect(err).NotTo(HaveOccurred()) - Expect(result).To(Equal(&expectedBurnEntity)) - }) - - It("converts a BurnEntity to a BurnModel", func() { - - result, err := converter.ToBurnEntity(burnEvent) - Expect(err).NotTo(HaveOccurred()) - - model := converter.ToBurnModel(result) - Expect(model).To(Equal(&expectedBurnModel)) - }) - -}) - -var _ = Describe("Approval Converter", func() { - - var converter *tusd.GenericConverter - var err error - - BeforeEach(func() { - converter, err = tusd.NewGenericConverter(generic.TusdConfig) - Expect(err).NotTo(HaveOccurred()) - }) - - It("converts a watched mint event into a MintEntity", func() { - - result, err := converter.ToMintEntity(mintEvent) - Expect(err).NotTo(HaveOccurred()) - Expect(result).To(Equal(&expectedMintEntity)) - }) - - It("converts a MintEntity to a MintModel", func() { - - result, err := converter.ToMintEntity(mintEvent) - Expect(err).NotTo(HaveOccurred()) - - model := converter.ToMintModel(result) - Expect(model).To(Equal(&expectedMintModel)) - }) - -}) diff --git a/examples/generic/event_triggered/tusd/integration_test.go b/examples/generic/event_triggered/tusd/integration_test.go deleted file mode 100644 index 2b4b33b2..00000000 --- a/examples/generic/event_triggered/tusd/integration_test.go +++ /dev/null @@ -1,137 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package tusd_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/generic" - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered/tusd" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var burnLog = core.Log{ - BlockNumber: 5488076, - Address: constants.TusdContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topics: [4]string{ - constants.BurnEvent.Signature(), - "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - "", - "", - }, - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -var mintLog = core.Log{ - BlockNumber: 5488076, - Address: constants.TusdContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topics: [4]string{ - constants.MintEvent.Signature(), - "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - "", - "", - }, - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", -} - -//converted transfer to assert against -var logs = []core.Log{ - burnLog, - mintLog, - { - BlockNumber: 0, - TxHash: "", - Address: "", - Topics: core.Topics{}, - Index: 0, - Data: "", - }, -} - -var _ = Describe("Integration test with vulcanizedb", func() { - var db *postgres.DB - var blk core.BlockChain - - BeforeEach(func() { - db = test_helpers.SetupIntegrationDB(db, logs) - }) - - AfterEach(func() { - db = test_helpers.TearDownIntegrationDB(db) - }) - - It("creates token_burns entry for each Burn event received", func() { - transformer, err := tusd.NewTransformer(db, blk, generic.TusdConfig) - Expect(err).ToNot(HaveOccurred()) - - transformer.Execute() - - var count int - err = db.QueryRow(`SELECT COUNT(*) FROM token_burns`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - - burn := event_triggered.BurnModel{} - - err = db.Get(&burn, `SELECT - token_name, - token_address, - burner, - tokens, - block, - tx - FROM token_burns WHERE block=$1`, logs[0].BlockNumber) - Expect(err).ToNot(HaveOccurred()) - Expect(burn).To(Equal(expectedBurnModel)) - }) - - It("creates token_mints entry for each Mint event received", func() { - transformer, err := tusd.NewTransformer(db, blk, generic.TusdConfig) - Expect(err).ToNot(HaveOccurred()) - - transformer.Execute() - - var count int - err = db.QueryRow(`SELECT COUNT(*) FROM token_mints`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - - mint := event_triggered.MintModel{} - - err = db.Get(&mint, `SELECT - token_name, - token_address, - minter, - mintee, - tokens, - block, - tx - FROM token_mints WHERE block=$1`, logs[0].BlockNumber) - Expect(err).ToNot(HaveOccurred()) - Expect(mint).To(Equal(expectedMintModel)) - }) - -}) diff --git a/examples/generic/event_triggered/tusd/repository_test.go b/examples/generic/event_triggered/tusd/repository_test.go deleted file mode 100644 index afa66cfb..00000000 --- a/examples/generic/event_triggered/tusd/repository_test.go +++ /dev/null @@ -1,232 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package tusd_test - -import ( - "math/rand" - "time" - - "github.com/ethereum/go-ethereum/common" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered/tusd" - "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/config" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" -) - -var burnEntity = &tusd.BurnEntity{ - TokenName: "Tusd", - TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), - Burner: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Value: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var mintEntity = &tusd.MintEntity{ - TokenName: "Tusd", - TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), - To: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), - Amount: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), - Block: 5488076, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", -} - -var _ = Describe("Approval and Transfer Repository Tests", func() { - var db *postgres.DB - var converter tusd.GenericConverter - var repository event_triggered.GenericEventRepository - var logRepository repositories.LogRepository - var blockRepository repositories.BlockRepository - var receiptRepository repositories.ReceiptRepository - var blockNumber int64 - var blockId int64 - var vulcanizeLogId int64 - rand.Seed(time.Now().UnixNano()) - - BeforeEach(func() { - var err error - db, err = postgres.NewDB(config.Database{ - Hostname: "localhost", - Name: "vulcanize_private", - Port: 5432, - }, core.Node{}) - Expect(err).NotTo(HaveOccurred()) - - receiptRepository = repositories.ReceiptRepository{DB: db} - logRepository = repositories.LogRepository{DB: db} - blockRepository = *repositories.NewBlockRepository(db) - - blockNumber = rand.Int63() - blockId = test_helpers.CreateBlock(blockNumber, blockRepository) - - log := core.Log{} - logs := []core.Log{log} - receipt := core.Receipt{ - Logs: logs, - } - receipts := []core.Receipt{receipt} - - err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts) - Expect(err).ToNot(HaveOccurred()) - - err = logRepository.Get(&vulcanizeLogId, `SELECT id FROM logs`) - Expect(err).ToNot(HaveOccurred()) - - repository = event_triggered.GenericEventRepository{DB: db} - converter = tusd.GenericConverter{} - }) - - AfterEach(func() { - db.Query(`DELETE FROM logs`) - db.Query(`DELETE FROM log_filters`) - db.Query(`DELETE FROM token_burns`) - db.Query(`DELETE FROM token_mints`) - - }) - - It("Creates a new Burn record", func() { - model := converter.ToBurnModel(burnEntity) - err := repository.CreateBurn(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - type DBRow struct { - DBID uint64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` - event_triggered.BurnModel - } - dbResult := DBRow{} - - err = repository.QueryRowx(`SELECT * FROM token_burns`).StructScan(&dbResult) - Expect(err).ToNot(HaveOccurred()) - - Expect(dbResult.VulcanizeLogID).To(Equal(vulcanizeLogId)) - Expect(dbResult.TokenName).To(Equal(model.TokenName)) - Expect(dbResult.TokenAddress).To(Equal(model.TokenAddress)) - Expect(dbResult.Burner).To(Equal(model.Burner)) - Expect(dbResult.Tokens).To(Equal(model.Tokens)) - Expect(dbResult.Block).To(Equal(model.Block)) - Expect(dbResult.TxHash).To(Equal(model.TxHash)) - }) - - It("does not duplicate token_transfers that have already been seen", func() { - model := converter.ToBurnModel(burnEntity) - - err := repository.CreateBurn(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = repository.CreateBurn(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_burns`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - }) - - It("Removes a Burn record when the corresponding log is removed", func() { - var exists bool - - model := converter.ToBurnModel(burnEntity) - err := repository.CreateBurn(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - err = repository.DB.QueryRow(`SELECT exists (SELECT * FROM token_burns WHERE vulcanize_log_id = $1)`, vulcanizeLogId).Scan(&exists) - Expect(err).ToNot(HaveOccurred()) - Expect(exists).To(BeTrue()) - - var logCount int - _, err = logRepository.DB.Exec(`DELETE FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = logRepository.Get(&logCount, `SELECT count(*) FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - Expect(logCount).To(BeZero()) - - var LogKillCount int - err = repository.DB.QueryRowx( - `SELECT count(*) FROM token_burns WHERE vulcanize_log_id = $1`, vulcanizeLogId).Scan(&LogKillCount) - Expect(err).ToNot(HaveOccurred()) - Expect(LogKillCount).To(BeZero()) - }) - - It("Creates a new Mint record", func() { - model := converter.ToMintModel(mintEntity) - err := repository.CreateMint(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - type DBRow struct { - DBID uint64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` - event_triggered.MintModel - } - dbResult := DBRow{} - - err = repository.QueryRowx(`SELECT * FROM token_mints`).StructScan(&dbResult) - Expect(err).ToNot(HaveOccurred()) - - Expect(dbResult.VulcanizeLogID).To(Equal(vulcanizeLogId)) - Expect(dbResult.TokenName).To(Equal(model.TokenName)) - Expect(dbResult.TokenAddress).To(Equal(model.TokenAddress)) - Expect(dbResult.Mintee).To(Equal(model.Mintee)) - Expect(dbResult.Minter).To(Equal(model.Minter)) - Expect(dbResult.Tokens).To(Equal(model.Tokens)) - Expect(dbResult.Block).To(Equal(model.Block)) - Expect(dbResult.TxHash).To(Equal(model.TxHash)) - }) - - It("does not duplicate token_mints that have already been seen", func() { - model := converter.ToMintModel(mintEntity) - - err := repository.CreateMint(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = repository.CreateMint(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - var count int - err = repository.DB.QueryRowx(`SELECT count(*) FROM token_mints`).Scan(&count) - Expect(err).ToNot(HaveOccurred()) - Expect(count).To(Equal(1)) - }) - - It("Removes a Mint record when the corresponding log is removed", func() { - var exists bool - - model := converter.ToMintModel(mintEntity) - err := repository.CreateMint(model, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - - err = repository.DB.QueryRow(`SELECT exists (SELECT * FROM token_mints WHERE vulcanize_log_id = $1)`, vulcanizeLogId).Scan(&exists) - Expect(err).ToNot(HaveOccurred()) - Expect(exists).To(BeTrue()) - - var logCount int - _, err = logRepository.DB.Exec(`DELETE FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - err = logRepository.Get(&logCount, `SELECT count(*) FROM logs WHERE id = $1`, vulcanizeLogId) - Expect(err).ToNot(HaveOccurred()) - Expect(logCount).To(BeZero()) - - var LogKillCount int - err = repository.DB.QueryRowx( - `SELECT count(*) FROM token_mints WHERE vulcanize_log_id = $1`, vulcanizeLogId).Scan(&LogKillCount) - Expect(err).ToNot(HaveOccurred()) - Expect(LogKillCount).To(BeZero()) - }) -}) diff --git a/examples/generic/event_triggered/tusd/transformer.go b/examples/generic/event_triggered/tusd/transformer.go deleted file mode 100644 index 233f0372..00000000 --- a/examples/generic/event_triggered/tusd/transformer.go +++ /dev/null @@ -1,96 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package tusd - -import ( - "fmt" - "log" - - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/filters" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -type GenericTransformer struct { - Converter GenericConverterInterface - WatchedEventRepository datastore.WatchedEventRepository - FilterRepository datastore.FilterRepository - Repository event_triggered.GenericEventDatastore - Filters []filters.LogFilter -} - -func NewTransformer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) { - var transformer shared.Transformer - - cnvtr, err := NewGenericConverter(con) - if err != nil { - return nil, err - } - - wer := repositories.WatchedEventRepository{DB: db} - fr := repositories.FilterRepository{DB: db} - lkr := event_triggered.GenericEventRepository{DB: db} - - transformer = GenericTransformer{ - Converter: cnvtr, - WatchedEventRepository: wer, - FilterRepository: fr, - Repository: lkr, - Filters: con.Filters, - } - - for _, filter := range con.Filters { - fr.CreateFilter(filter) - } - - return transformer, nil -} - -func (tr GenericTransformer) Execute() error { - for _, filter := range tr.Filters { - watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name) - if err != nil { - log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err) - return err - } - for _, we := range watchedEvents { - if filter.Name == constants.BurnEvent.String() { - entity, err := tr.Converter.ToBurnEntity(*we) - model := tr.Converter.ToBurnModel(entity) - if err != nil { - log.Printf("Error persisting data for TrueUSD Burns (watchedEvent.LogID %d):\n %s", we.LogID, err) - } - tr.Repository.CreateBurn(model, we.LogID) - } - if filter.Name == constants.MintEvent.String() { - entity, err := tr.Converter.ToMintEntity(*we) - model := tr.Converter.ToMintModel(entity) - if err != nil { - log.Printf("Error persisting data for TrueUSD Mints (watchedEvent.LogID %d):\n %s", we.LogID, err) - } - tr.Repository.CreateMint(model, we.LogID) - } - } - } - - return nil -} diff --git a/examples/generic/event_triggered/tusd/transformer_test.go b/examples/generic/event_triggered/tusd/transformer_test.go deleted file mode 100644 index 34b9b408..00000000 --- a/examples/generic/event_triggered/tusd/transformer_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package tusd_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered/tusd" - "github.com/vulcanize/vulcanizedb/examples/mocks" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var blockID1 = int64(5428074) -var logID1 = int64(113) -var blockID2 = int64(5428405) -var logID2 = int64(100) - -var fakeWatchedEvents = []*core.WatchedEvent{ - { - LogID: logID1, - Name: constants.BurnEvent.String(), - BlockNumber: blockID1, - Address: constants.TusdContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.BurnEvent.Signature(), - Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", - Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", - }, - { - LogID: logID2, - Name: constants.MintEvent.String(), - BlockNumber: blockID2, - Address: constants.TusdContractAddress, - TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", - Index: 110, - Topic0: constants.MintEvent.Signature(), - Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", - Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", - Topic3: "", - Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", - }, -} - -var _ = Describe("Mock ERC20 transformer", func() { - var mockERC20Converter mocks.MockERC20Converter - var watchedEventsRepo mocks.MockWatchedEventsRepository - var mockEventRepo mocks.MockEventRepo - var filterRepo mocks.MockFilterRepository - var transformer tusd.GenericTransformer - - BeforeEach(func() { - mockERC20Converter = mocks.MockERC20Converter{} - watchedEventsRepo = mocks.MockWatchedEventsRepository{} - watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents) - mockEventRepo = mocks.MockEventRepo{} - filterRepo = mocks.MockFilterRepository{} - filters := constants.TusdGenericFilters - - transformer = tusd.GenericTransformer{ - Converter: &mockERC20Converter, - WatchedEventRepository: &watchedEventsRepo, - FilterRepository: filterRepo, - Repository: &mockEventRepo, - Filters: filters, - } - }) - - It("calls the watched events repo with correct filter", func() { - transformer.Execute() - Expect(len(watchedEventsRepo.Names)).To(Equal(2)) - Expect(watchedEventsRepo.Names).To(ConsistOf([]string{constants.BurnEvent.String(), constants.MintEvent.String()})) - }) - - It("calls the mock ERC20 converter with the watched events", func() { - transformer.Execute() - Expect(len(mockERC20Converter.WatchedEvents)).To(Equal(2)) - Expect(mockERC20Converter.WatchedEvents).To(ConsistOf(fakeWatchedEvents)) - }) - - It("converts a Burn and Mint entity to their models", func() { - transformer.Execute() - Expect(len(mockERC20Converter.BurnsToConvert)).To(Equal(1)) - Expect(mockERC20Converter.BurnsToConvert[0].Block).To(Equal(blockID1)) - - Expect(len(mockERC20Converter.MintsToConvert)).To(Equal(1)) - Expect(mockERC20Converter.MintsToConvert[0].Block).To(Equal(blockID2)) - }) - - It("persists Burn and Mint data for each watched Burn or Mint event", func() { - transformer.Execute() - Expect(len(mockEventRepo.BurnLogs)).To(Equal(1)) - Expect(len(mockEventRepo.MintLogs)).To(Equal(1)) - Expect(mockEventRepo.VulcanizeLogIDs).To(ConsistOf(logID1, logID2)) - }) - -}) diff --git a/examples/generic/every_block/getter.go b/examples/generic/every_block/getter.go deleted file mode 100644 index f3a228be..00000000 --- a/examples/generic/every_block/getter.go +++ /dev/null @@ -1,88 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/fetcher" -) - -// Getter serves as a higher level data fetcher that invokes its underlying Fetcher methods for a given contract method - -// Interface definition for a Getter -type GenericGetterInterface interface { - GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) - GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) - GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) - GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) - GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) - GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) - GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) - GetBlockChain() core.BlockChain -} - -// Getter struct -type GenericGetter struct { - fetcher.Fetcher // Underlying Fetcher -} - -// Initializes and returns a Getter with the given blockchain -func NewGetter(blockChain core.BlockChain) GenericGetter { - return GenericGetter{ - Fetcher: fetcher.Fetcher{ - BlockChain: blockChain, - }, - } -} - -// Public getter methods for calling contract methods -func (g GenericGetter) GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) { - return g.Fetcher.FetchAddress("owner", contractAbi, contractAddress, blockNumber, nil) -} - -func (g GenericGetter) GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) { - return g.Fetcher.FetchBool("stopped", contractAbi, contractAddress, blockNumber, nil) -} - -func (g GenericGetter) GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) { - return g.Fetcher.FetchString("name", contractAbi, contractAddress, blockNumber, nil) -} - -func (g GenericGetter) GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { - return g.Fetcher.FetchHash("name", contractAbi, contractAddress, blockNumber, nil) -} - -func (g GenericGetter) GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) { - return g.Fetcher.FetchString("symbol", contractAbi, contractAddress, blockNumber, nil) -} - -func (g GenericGetter) GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { - return g.Fetcher.FetchHash("symbol", contractAbi, contractAddress, blockNumber, nil) -} - -func (g GenericGetter) GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { - return g.Fetcher.FetchBigInt("decimals", contractAbi, contractAddress, blockNumber, nil) -} - -// Method to retrieve the Getter's blockchain -func (g GenericGetter) GetBlockChain() core.BlockChain { - return g.Fetcher.BlockChain -} diff --git a/examples/generic/every_block/getter_test.go b/examples/generic/every_block/getter_test.go deleted file mode 100644 index cfc841af..00000000 --- a/examples/generic/every_block/getter_test.go +++ /dev/null @@ -1,367 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package every_block_test - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/examples/generic/every_block" - "github.com/vulcanize/vulcanizedb/pkg/fakes" - "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/geth/client" - rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" - "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" -) - -var _ = Describe("every_block Getter", func() { - blockNumber := int64(5502914) - - Describe("stopped", func() { - It("checks whether or not the contract has been stopped", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetStoppedStatus(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult bool - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "stopped", nil, &expected, blockNumber) - }) - - It("gets dai token's stopped status at the given block height", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetStoppedStatus(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - Expect(result).To(Equal(false)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetStoppedStatus("", "", 0) - - Expect(result).To(Equal(false)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("stopped")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("owner", func() { - It("checks what the contract's owner address is", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetOwner(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult common.Address - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "owner", nil, &expected, blockNumber) - }) - - It("gets dai token's owner address at the given block height", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetOwner(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := common.HexToAddress("0x0000000000000000000000000000000000000000") - Expect(result).To(Equal(expectedResult)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetOwner("", "", 0) - - expectedResult := new(common.Address) - Expect(result).To(Equal(*expectedResult)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("owner")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("hash name", func() { - It("checks the contract's name", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetHashName(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult common.Hash - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "name", nil, &expected, blockNumber) - }) - - It("gets dai token's name at the given blockheight", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetHashName(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := common.HexToHash("0x44616920537461626c65636f696e2076312e3000000000000000000000000000") - Expect(result).To(Equal(expectedResult)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetHashName("", "", 0) - - expectedResult := new(common.Hash) - Expect(result).To(Equal(*expectedResult)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("name")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("hash symbol", func() { - It("checks the contract's symbol", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetHashSymbol(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult common.Hash - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "symbol", nil, &expected, blockNumber) - }) - - It("gets dai token's symbol at the given blockheight", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetHashSymbol(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := common.HexToHash("0x4441490000000000000000000000000000000000000000000000000000000000") - Expect(result).To(Equal(expectedResult)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetHashSymbol("", "", 0) - - expectedResult := new(common.Hash) - Expect(result).To(Equal(*expectedResult)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("symbol")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("decimals", func() { - It("checks what the token's number of decimals", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetDecimals(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult big.Int - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "decimals", nil, &expected, blockNumber) - }) - - It("gets dai token's number of decimals at the given block height", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetDecimals(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := big.Int{} - expectedResult.SetString("18", 10) - Expect(result).To(Equal(expectedResult)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetDecimals("", "", 0) - - expectedResult := new(big.Int) - Expect(result).To(Equal(*expectedResult)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("decimals")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("string name", func() { - It("checks the contract's name", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetStringName(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult string - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "name", nil, &expected, blockNumber) - }) - - It("gets tusd token's name at the given blockheight", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetStringName(constants.TusdAbiString, constants.TusdContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := "TrueUSD" - Expect(result).To(Equal(expectedResult)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetStringName("", "", 0) - - expectedResult := new(string) - Expect(result).To(Equal(*expectedResult)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("name")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) - - Describe("string symbol", func() { - It("checks the contract's symbol", func() { - fakeBlockChain := fakes.NewMockBlockChain() - testGetter := every_block.NewGetter(fakeBlockChain) - testAbi := "testAbi" - testContractAddress := "testContractAddress" - - _, err := testGetter.GetStringSymbol(testAbi, testContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - var expectedResult string - expected := &expectedResult - fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "symbol", nil, &expected, blockNumber) - }) - - It("gets tusd token's symbol at the given blockheight", func() { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - realGetter := every_block.NewGetter(blockChain) - result, err := realGetter.GetStringName(constants.TusdAbiString, constants.TusdContractAddress, blockNumber) - - Expect(err).NotTo(HaveOccurred()) - expectedResult := "TrueUSD" - Expect(result).To(Equal(expectedResult)) - }) - - It("returns an error if the call to the blockchain fails", func() { - blockChain := fakes.NewMockBlockChain() - blockChain.SetFetchContractDataErr(fakes.FakeError) - errorGetter := every_block.NewGetter(blockChain) - result, err := errorGetter.GetStringSymbol("", "", 0) - - expectedResult := new(string) - Expect(result).To(Equal(*expectedResult)) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("symbol")) - Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) - }) - }) -}) diff --git a/examples/generic/retriever.go b/examples/generic/retriever.go deleted file mode 100644 index a4aa62f0..00000000 --- a/examples/generic/retriever.go +++ /dev/null @@ -1,241 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package generic - -import ( - "fmt" - "log" - - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -// Generic retriever is used to iterate over addresses involved in token -// transfers, approvals, mints, and burns to generate a list of token holder addresses - -type TokenHolderRetrieverInterface interface { - RetrieveTokenHolderAddresses() (map[common.Address]bool, error) - retrieveTokenSenders() ([]string, error) - retrieveTokenReceivers() ([]string, error) - retrieveTokenOwners() ([]string, error) - retrieveTokenSpenders() ([]string, error) - retrieveTokenMintees() ([]string, error) - retrieveTokenBurners() ([]string, error) -} - -type TokenHolderRetriever struct { - Database *postgres.DB - ContractAddress string -} - -type retrieverError struct { - err string - msg string - address string -} - -// Retriever error method -func (re *retrieverError) Error() string { - return fmt.Sprintf(re.msg, re.address, re.err) -} - -// Used to create a new retriever error for a given error and fetch method -func newRetrieverError(err error, msg string, address string) error { - e := retrieverError{err.Error(), msg, address} - log.Println(e.Error()) - return &e -} - -// Constant error definitions -const ( - GetSendersError = "Error fetching token senders from contract %s: %s" - GetReceiversError = "Error fetching token receivers from contract %s: %s" - GetOwnersError = "Error fetching token owners from contract %s: %s" - GetSpendersError = "Error fetching token spenders from contract %s: %s" - GetMinteesError = "Error fetching token mintees from contract %s: %s" - GetBurnersError = "Error fetching token burners from contract %s: %s" -) - -func NewTokenHolderRetriever(db *postgres.DB, address string) TokenHolderRetriever { - return TokenHolderRetriever{ - Database: db, - ContractAddress: address, - } -} - -func (rt TokenHolderRetriever) retrieveTokenSenders() ([]string, error) { - - senders := make([]string, 0) - - err := rt.Database.DB.Select( - &senders, - `SELECT from_address FROM token_transfers - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetSendersError, rt.ContractAddress) - } - - return senders, nil -} - -func (rt TokenHolderRetriever) retrieveTokenReceivers() ([]string, error) { - - receivers := make([]string, 0) - - err := rt.Database.DB.Select( - &receivers, - `SELECT to_address FROM token_transfers - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetReceiversError, rt.ContractAddress) - } - return receivers, err -} - -func (rt TokenHolderRetriever) retrieveTokenMintees() ([]string, error) { - - mintees := make([]string, 0) - - err := rt.Database.DB.Select( - &mintees, - `SELECT mintee FROM token_mints - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetMinteesError, rt.ContractAddress) - } - - return mintees, nil -} - -func (rt TokenHolderRetriever) retrieveTokenBurners() ([]string, error) { - - burners := make([]string, 0) - - err := rt.Database.DB.Select( - &burners, - `SELECT burner FROM token_burns - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetBurnersError, rt.ContractAddress) - } - - return burners, nil -} - -func (rt TokenHolderRetriever) retrieveTokenOwners() ([]string, error) { - - owners := make([]string, 0) - - err := rt.Database.DB.Select( - &owners, - `SELECT owner FROM token_approvals - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetOwnersError, rt.ContractAddress) - } - - return owners, nil -} - -func (rt TokenHolderRetriever) retrieveTokenSpenders() ([]string, error) { - - spenders := make([]string, 0) - - err := rt.Database.DB.Select( - &spenders, - `SELECT spender FROM token_approvals - WHERE token_address = $1`, - rt.ContractAddress, - ) - if err != nil { - return []string{}, newRetrieverError(err, GetSpendersError, rt.ContractAddress) - } - - return spenders, nil -} - -func (rt TokenHolderRetriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, error) { - - senders, err := rt.retrieveTokenSenders() - if err != nil { - return nil, err - } - - receivers, err := rt.retrieveTokenReceivers() - if err != nil { - return nil, err - } - - mintees, err := rt.retrieveTokenMintees() - if err != nil { - return nil, err - } - - burners, err := rt.retrieveTokenBurners() - if err != nil { - return nil, err - } - - owners, err := rt.retrieveTokenOwners() - if err != nil { - return nil, err - } - - spenders, err := rt.retrieveTokenSenders() - if err != nil { - return nil, err - } - - contractAddresses := make(map[common.Address]bool) - - for _, addr := range senders { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range receivers { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range mintees { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range burners { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range owners { - contractAddresses[common.HexToAddress(addr)] = true - } - - for _, addr := range spenders { - contractAddresses[common.HexToAddress(addr)] = true - } - - return contractAddresses, nil -} diff --git a/examples/mocks/converter.go b/examples/mocks/converter.go deleted file mode 100644 index e5376426..00000000 --- a/examples/mocks/converter.go +++ /dev/null @@ -1,82 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package mocks - -import ( - et1 "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai" - et2 "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered/tusd" - "github.com/vulcanize/vulcanizedb/pkg/core" -) - -type MockERC20Converter struct { - WatchedEvents []*core.WatchedEvent - TransfersToConvert []dai.TransferEntity - ApprovalsToConvert []dai.ApprovalEntity - BurnsToConvert []tusd.BurnEntity - MintsToConvert []tusd.MintEntity - block int64 -} - -func (mlkc *MockERC20Converter) ToTransferModel(entity *dai.TransferEntity) *et1.TransferModel { - mlkc.TransfersToConvert = append(mlkc.TransfersToConvert, *entity) - return &et1.TransferModel{} -} - -func (mlkc *MockERC20Converter) ToTransferEntity(watchedEvent core.WatchedEvent) (*dai.TransferEntity, error) { - mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) - e := &dai.TransferEntity{Block: watchedEvent.BlockNumber} - mlkc.block++ - return e, nil -} - -func (mlkc *MockERC20Converter) ToApprovalModel(entity *dai.ApprovalEntity) *et1.ApprovalModel { - mlkc.ApprovalsToConvert = append(mlkc.ApprovalsToConvert, *entity) - return &et1.ApprovalModel{} -} - -func (mlkc *MockERC20Converter) ToApprovalEntity(watchedEvent core.WatchedEvent) (*dai.ApprovalEntity, error) { - mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) - e := &dai.ApprovalEntity{Block: watchedEvent.BlockNumber} - mlkc.block++ - return e, nil -} - -func (mlkc *MockERC20Converter) ToBurnEntity(watchedEvent core.WatchedEvent) (*tusd.BurnEntity, error) { - mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) - e := &tusd.BurnEntity{Block: watchedEvent.BlockNumber} - mlkc.block++ - return e, nil -} - -func (mlkc *MockERC20Converter) ToBurnModel(entity *tusd.BurnEntity) *et2.BurnModel { - mlkc.BurnsToConvert = append(mlkc.BurnsToConvert, *entity) - return &et2.BurnModel{} -} - -func (mlkc *MockERC20Converter) ToMintEntity(watchedEvent core.WatchedEvent) (*tusd.MintEntity, error) { - mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) - e := &tusd.MintEntity{Block: watchedEvent.BlockNumber} - mlkc.block++ - return e, nil -} - -func (mlkc *MockERC20Converter) ToMintModel(entity *tusd.MintEntity) *et2.MintModel { - mlkc.MintsToConvert = append(mlkc.MintsToConvert, *entity) - return &et2.MintModel{} -} diff --git a/examples/mocks/event_repo.go b/examples/mocks/event_repo.go deleted file mode 100644 index 1de651aa..00000000 --- a/examples/mocks/event_repo.go +++ /dev/null @@ -1,118 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package mocks - -import ( - et1 "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" - et2 "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/filters" -) - -type MockWatchedEventsRepository struct { - watchedTransferEvents []*core.WatchedEvent - watchedApprovalEvents []*core.WatchedEvent - watchedBurnEvents []*core.WatchedEvent - watchedMintEvents []*core.WatchedEvent - Names []string -} - -func (mwer *MockWatchedEventsRepository) SetWatchedEvents(watchedEvents []*core.WatchedEvent) { - for _, event := range watchedEvents { - if event.Name == "Transfer" { - mwer.watchedTransferEvents = append(mwer.watchedTransferEvents, event) - } - if event.Name == "Approval" { - mwer.watchedApprovalEvents = append(mwer.watchedApprovalEvents, event) - } - if event.Name == "Burn" { - mwer.watchedBurnEvents = append(mwer.watchedBurnEvents, event) - } - if event.Name == "Mint" { - mwer.watchedMintEvents = append(mwer.watchedMintEvents, event) - } - } -} - -func (mwer *MockWatchedEventsRepository) GetWatchedEvents(name string) ([]*core.WatchedEvent, error) { - mwer.Names = append(mwer.Names, name) - var result []*core.WatchedEvent - if name == "Transfer" { - result = mwer.watchedTransferEvents - // clear watched events once returned so same events are returned for every filter while testing - mwer.watchedTransferEvents = []*core.WatchedEvent{} - } - if name == "Approval" { - result = mwer.watchedApprovalEvents - // clear watched events once returned so same events are returned for every filter while testing - mwer.watchedApprovalEvents = []*core.WatchedEvent{} - } - if name == "Burn" { - result = mwer.watchedBurnEvents - // clear watched events once returned so same events are returned for every filter while testing - mwer.watchedBurnEvents = []*core.WatchedEvent{} - } - if name == "Mint" { - result = mwer.watchedMintEvents - // clear watched events once returned so same events are returned for every filter while testing - mwer.watchedMintEvents = []*core.WatchedEvent{} - } - return result, nil -} - -type MockEventRepo struct { - TransferLogs []et1.TransferModel - ApprovalLogs []et1.ApprovalModel - BurnLogs []et2.BurnModel - MintLogs []et2.MintModel - VulcanizeLogIDs []int64 -} - -func (molr *MockEventRepo) CreateTransfer(transferModel *et1.TransferModel, vulcanizeLogId int64) error { - molr.TransferLogs = append(molr.TransferLogs, *transferModel) - molr.VulcanizeLogIDs = append(molr.VulcanizeLogIDs, vulcanizeLogId) - return nil -} - -func (molk *MockEventRepo) CreateApproval(approvalModel *et1.ApprovalModel, vulcanizeLogID int64) error { - molk.ApprovalLogs = append(molk.ApprovalLogs, *approvalModel) - molk.VulcanizeLogIDs = append(molk.VulcanizeLogIDs, vulcanizeLogID) - return nil -} - -func (molr *MockEventRepo) CreateBurn(burnModel *et2.BurnModel, vulcanizeLogId int64) error { - molr.BurnLogs = append(molr.BurnLogs, *burnModel) - molr.VulcanizeLogIDs = append(molr.VulcanizeLogIDs, vulcanizeLogId) - return nil -} - -func (molk *MockEventRepo) CreateMint(mintModel *et2.MintModel, vulcanizeLogID int64) error { - molk.MintLogs = append(molk.MintLogs, *mintModel) - molk.VulcanizeLogIDs = append(molk.VulcanizeLogIDs, vulcanizeLogID) - return nil -} - -type MockFilterRepository struct { -} - -func (MockFilterRepository) CreateFilter(filter filters.LogFilter) error { - panic("implement me") -} - -func (MockFilterRepository) GetFilter(name string) (filters.LogFilter, error) { - panic("implement me") -} diff --git a/examples/mocks/every_block_repo.go b/examples/mocks/every_block_repo.go deleted file mode 100644 index c5bfe39b..00000000 --- a/examples/mocks/every_block_repo.go +++ /dev/null @@ -1,77 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package mocks - -import ( - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" -) - -type ERC20TokenRepository struct { - TotalSuppliesCreated []every_block.TokenSupply - MissingSupplyBlockNumbers []int64 - TotalBalancesCreated []every_block.TokenBalance - MissingBalanceBlockNumbers []int64 - TotalAllowancesCreated []every_block.TokenAllowance - MissingAllowanceBlockNumbers []int64 - StartingBlock int64 - EndingBlock int64 -} - -func (fr *ERC20TokenRepository) CreateSupply(supply every_block.TokenSupply) error { - fr.TotalSuppliesCreated = append(fr.TotalSuppliesCreated, supply) - return nil -} - -func (fr *ERC20TokenRepository) CreateBalance(balance every_block.TokenBalance) error { - fr.TotalBalancesCreated = append(fr.TotalBalancesCreated, balance) - return nil -} - -func (fr *ERC20TokenRepository) CreateAllowance(allowance every_block.TokenAllowance) error { - fr.TotalAllowancesCreated = append(fr.TotalAllowancesCreated, allowance) - return nil -} - -func (fr *ERC20TokenRepository) MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) { - fr.StartingBlock = startingBlock - fr.EndingBlock = highestBlock - return fr.MissingSupplyBlockNumbers, nil -} - -func (fr *ERC20TokenRepository) MissingBalanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress string) ([]int64, error) { - fr.StartingBlock = startingBlock - fr.EndingBlock = highestBlock - return fr.MissingBalanceBlockNumbers, nil -} - -func (fr *ERC20TokenRepository) MissingAllowanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress, spenderAddress string) ([]int64, error) { - fr.StartingBlock = startingBlock - fr.EndingBlock = highestBlock - return fr.MissingAllowanceBlockNumbers, nil -} - -func (fr *ERC20TokenRepository) SetMissingSupplyBlocks(missingBlocks []int64) { - fr.MissingSupplyBlockNumbers = missingBlocks -} - -func (fr *ERC20TokenRepository) SetMissingBalanceBlocks(missingBlocks []int64) { - fr.MissingBalanceBlockNumbers = missingBlocks -} - -func (fr *ERC20TokenRepository) SetMissingAllowanceBlocks(missingBlocks []int64) { - fr.MissingAllowanceBlockNumbers = missingBlocks -} diff --git a/examples/mocks/failure_repo.go b/examples/mocks/failure_repo.go deleted file mode 100644 index bd84fa45..00000000 --- a/examples/mocks/failure_repo.go +++ /dev/null @@ -1,118 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package mocks - -import ( - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/pkg/fakes" -) - -type FailureRepository struct { - createSupplyFail bool - createBalanceFail bool - createAllowanceFail bool - missingSupplyBlocksFail bool - missingBalanceBlocksFail bool - missingAllowanceBlocksFail bool - missingSupplyBlocksNumbers []int64 - missingBalanceBlocksNumbers []int64 - missingAllowanceBlocksNumbers []int64 -} - -func (fr *FailureRepository) CreateSupply(supply every_block.TokenSupply) error { - if fr.createSupplyFail { - return fakes.FakeError - } else { - return nil - } -} - -func (fr *FailureRepository) CreateBalance(balance every_block.TokenBalance) error { - if fr.createBalanceFail { - return fakes.FakeError - } else { - return nil - } -} - -func (fr *FailureRepository) CreateAllowance(allowance every_block.TokenAllowance) error { - if fr.createAllowanceFail { - return fakes.FakeError - } else { - return nil - } -} - -func (fr *FailureRepository) MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) { - if fr.missingSupplyBlocksFail { - return []int64{}, fakes.FakeError - } else { - return fr.missingSupplyBlocksNumbers, nil - } -} - -func (fr *FailureRepository) MissingBalanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress string) ([]int64, error) { - if fr.missingBalanceBlocksFail { - return []int64{}, fakes.FakeError - } else { - return fr.missingBalanceBlocksNumbers, nil - } -} - -func (fr *FailureRepository) MissingAllowanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress, spenderAddress string) ([]int64, error) { - if fr.missingAllowanceBlocksFail { - return []int64{}, fakes.FakeError - } else { - return fr.missingAllowanceBlocksNumbers, nil - } -} - -func (fr *FailureRepository) SetCreateSupplyFail(fail bool) { - fr.createSupplyFail = fail -} - -func (fr *FailureRepository) SetCreateBalanceFail(fail bool) { - fr.createBalanceFail = fail -} - -func (fr *FailureRepository) SetCreateAllowanceFail(fail bool) { - fr.createAllowanceFail = fail -} - -func (fr *FailureRepository) SetMissingSupplyBlocksFail(fail bool) { - fr.missingSupplyBlocksFail = fail -} - -func (fr *FailureRepository) SetMissingBalanceBlocksFail(fail bool) { - fr.missingBalanceBlocksFail = fail -} - -func (fr *FailureRepository) SetMissingAllowanceBlocksFail(fail bool) { - fr.missingAllowanceBlocksFail = fail -} - -func (fr *FailureRepository) SetMissingSupplyBlocks(missingBlocks []int64) { - fr.missingSupplyBlocksNumbers = missingBlocks -} - -func (fr *FailureRepository) SetMissingBalanceBlocks(missingBlocks []int64) { - fr.missingBalanceBlocksNumbers = missingBlocks -} - -func (fr *FailureRepository) SetMissingAllowanceBlocks(missingBlocks []int64) { - fr.missingAllowanceBlocksNumbers = missingBlocks -} diff --git a/examples/mocks/fetcher.go b/examples/mocks/fetcher.go deleted file mode 100644 index c72622e6..00000000 --- a/examples/mocks/fetcher.go +++ /dev/null @@ -1,162 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package mocks - -import ( - "errors" - "math/big" - "reflect" - - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/pkg/core" -) - -type Fetcher struct { - ContractAddress string - Abi string - FetchedBlocks []int64 - BlockChain core.BlockChain - supply big.Int - balance map[string]*big.Int - allowance map[string]map[string]*big.Int - owner common.Address - stopped bool - stringName string - hashName common.Hash - stringSymbol string - hashSymbol common.Hash -} - -func (f *Fetcher) SetSupply(supply string) { - f.supply.SetString(supply, 10) -} - -func (f Fetcher) GetBlockChain() core.BlockChain { - return f.BlockChain -} - -func (f *Fetcher) FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { - - f.Abi = contractAbi - f.ContractAddress = contractAddress - f.FetchedBlocks = append(f.FetchedBlocks, blockNumber) - - accumulator := big.NewInt(1) - - if method == "totalSupply" { - f.supply.Add(&f.supply, accumulator) - - return f.supply, nil - } - - if method == "balanceOf" { - rfl := reflect.ValueOf(methodArgs[0]) - tokenHolderAddr := rfl.Interface().(string) - pnt := f.balance[tokenHolderAddr] - f.balance[tokenHolderAddr].Add(pnt, accumulator) - - return *f.balance[tokenHolderAddr], nil - } - - if method == "allowance" { - rfl1 := reflect.ValueOf(methodArgs[0]) - rfl2 := reflect.ValueOf(methodArgs[1]) - tokenHolderAddr := rfl1.Interface().(string) - spenderAddr := rfl2.Interface().(string) - pnt := f.allowance[tokenHolderAddr][spenderAddr] - f.allowance[tokenHolderAddr][spenderAddr].Add(pnt, accumulator) - - return *f.allowance[tokenHolderAddr][spenderAddr], nil - } - - return *big.NewInt(0), errors.New("invalid method argument") - -} - -func (f *Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) { - - f.Abi = contractAbi - f.ContractAddress = contractAddress - f.FetchedBlocks = append(f.FetchedBlocks, blockNumber) - - b := true - - if method == "stopped" { - f.stopped = b - - return f.stopped, nil - } - - return false, errors.New("invalid method argument") -} - -func (f *Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) { - - f.Abi = contractAbi - f.ContractAddress = contractAddress - f.FetchedBlocks = append(f.FetchedBlocks, blockNumber) - - adr := common.HexToAddress("test_address") - - if method == "owner" { - f.owner = adr - - return f.owner, nil - } - return common.HexToAddress(""), errors.New("invalid method argument") -} - -func (f *Fetcher) FetchString(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (string, error) { - - f.Abi = contractAbi - f.ContractAddress = contractAddress - f.FetchedBlocks = append(f.FetchedBlocks, blockNumber) - - if method == "name" { - f.stringName = "test_name" - - return f.stringName, nil - } - - if method == "symbol" { - f.stringSymbol = "test_symbol" - - return f.stringSymbol, nil - } - return "", errors.New("invalid method argument") -} - -func (f *Fetcher) FetchHash(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Hash, error) { - - f.Abi = contractAbi - f.ContractAddress = contractAddress - f.FetchedBlocks = append(f.FetchedBlocks, blockNumber) - - if method == "name" { - f.hashName = common.HexToHash("test_name") - - return f.hashName, nil - } - - if method == "symbol" { - f.hashSymbol = common.HexToHash("test_symbol") - - return f.hashSymbol, nil - } - return common.HexToHash(""), errors.New("invalid method argument") -} diff --git a/examples/mocks/getter.go b/examples/mocks/getter.go deleted file mode 100644 index 084ede25..00000000 --- a/examples/mocks/getter.go +++ /dev/null @@ -1,81 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package mocks - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - - "github.com/vulcanize/vulcanizedb/pkg/core" -) - -type Getter struct { - Fetcher Fetcher -} - -func NewGetter(blockChain core.BlockChain) Getter { - return Getter{ - Fetcher: Fetcher{ - BlockChain: blockChain, - }, - } -} - -func (g *Getter) GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { - return g.Fetcher.FetchBigInt("totalSupply", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { - return g.Fetcher.FetchBigInt("balanceOf", contractAbi, contractAddress, blockNumber, methodArgs) -} - -func (g *Getter) GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { - return g.Fetcher.FetchBigInt("allowance", contractAbi, contractAddress, blockNumber, methodArgs) -} - -func (g *Getter) GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) { - return g.Fetcher.FetchAddress("owner", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) { - return g.Fetcher.FetchBool("stopped", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) { - return g.Fetcher.FetchString("name", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { - return g.Fetcher.FetchHash("name", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) { - return g.Fetcher.FetchString("symbol", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { - return g.Fetcher.FetchHash("symbol", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { - return g.Fetcher.FetchBigInt("decimals", contractAbi, contractAddress, blockNumber, nil) -} - -func (g *Getter) GetBlockChain() core.BlockChain { - return g.Fetcher.BlockChain -} diff --git a/examples/test_helpers/database.go b/examples/test_helpers/database.go deleted file mode 100644 index 60d2d4b0..00000000 --- a/examples/test_helpers/database.go +++ /dev/null @@ -1,131 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package test_helpers - -import ( - "math/rand" - "time" - - . "github.com/onsi/gomega" - - "github.com/vulcanize/vulcanizedb/pkg/config" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/test_config" -) - -type TokenSupplyDBRow struct { - ID int64 `db:"id"` - Supply int64 `db:"supply"` - BlockID int64 `db:"block_id"` - TokenAddress string `db:"token_address"` -} - -type TokenBalanceDBRow struct { - ID int64 `db:"id"` - Balance int64 `db:"balance"` - BlockID int64 `db:"block_id"` - TokenAddress string `db:"token_address"` - TokenHolderAddress string `db:"token_holder_address"` -} - -type TokenAllowanceDBRow struct { - ID int64 `db:"id"` - Allowance int64 `db:"allowance"` - BlockID int64 `db:"block_id"` - TokenAddress string `db:"token_address"` - TokenHolderAddress string `db:"token_holder_address"` - TokenSpenderAddress string `db:"token_spender_address"` -} - -type TransferDBRow struct { - ID int64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` -} - -func CreateNewDatabase() *postgres.DB { - var node core.Node - node = core.Node{ - GenesisBlock: "GENESIS", - NetworkID: 1, - ID: "2ea672a45c4c7b96e3c4b130b21a22af390a552fd0b3cff96420b4bda26568d470dc56e05e453823f64f2556a6e4460ad1d4d00eb2d8b8fc16fcb1be73e86522", - ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9", - } - db := test_config.NewTestDB(node) - - _, err := db.Exec(`DELETE FROM logs`) - Expect(err).NotTo(HaveOccurred()) - - return db -} - -func CreateBlock(blockNumber int64, repository repositories.BlockRepository) (blockId int64) { - blockId, err := repository.CreateOrUpdateBlock(core.Block{Number: blockNumber}) - Expect(err).NotTo(HaveOccurred()) - - return blockId -} - -func SetupIntegrationDB(db *postgres.DB, logs []core.Log) *postgres.DB { - - rand.Seed(time.Now().UnixNano()) - - db, err := postgres.NewDB(config.Database{ - Hostname: "localhost", - Name: "vulcanize_private", - Port: 5432, - }, core.Node{}) - Expect(err).NotTo(HaveOccurred()) - - receiptRepository := repositories.ReceiptRepository{DB: db} - blockRepository := *repositories.NewBlockRepository(db) - - blockNumber := rand.Int63() - blockId := CreateBlock(blockNumber, blockRepository) - - receipt := core.Receipt{ - Logs: logs, - } - receipts := []core.Receipt{receipt} - - err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts) - Expect(err).NotTo(HaveOccurred()) - - var vulcanizeLogIds []int64 - err = db.Select(&vulcanizeLogIds, `SELECT id FROM logs`) - Expect(err).NotTo(HaveOccurred()) - - return db -} - -func TearDownIntegrationDB(db *postgres.DB) *postgres.DB { - - _, err := db.Exec(`DELETE FROM token_transfers`) - Expect(err).NotTo(HaveOccurred()) - - _, err = db.Exec(`DELETE FROM token_approvals`) - Expect(err).NotTo(HaveOccurred()) - - _, err = db.Exec(`DELETE FROM log_filters`) - Expect(err).NotTo(HaveOccurred()) - - _, err = db.Exec(`DELETE FROM logs`) - Expect(err).NotTo(HaveOccurred()) - - return db -} diff --git a/integration_test/block_rewards_test.go b/integration_test/block_rewards_test.go index f379b870..7e66f374 100644 --- a/integration_test/block_rewards_test.go +++ b/integration_test/block_rewards_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -42,7 +42,7 @@ var _ = Describe("Rewards calculations", func() { blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) block, err := blockChain.GetBlockByNumber(1071819) Expect(err).ToNot(HaveOccurred()) - Expect(block.Reward).To(Equal(5.31355)) + Expect(block.Reward).To(Equal("5313550000000000000")) }) It("calculates an uncle reward for a real block", func() { @@ -56,7 +56,7 @@ var _ = Describe("Rewards calculations", func() { blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) block, err := blockChain.GetBlockByNumber(1071819) Expect(err).ToNot(HaveOccurred()) - Expect(block.UnclesReward).To(Equal(6.875)) + Expect(block.UnclesReward).To(Equal("6875000000000000000")) }) }) diff --git a/integration_test/contract_test.go b/integration_test/contract_test.go index f8ada3b9..3d2dd866 100644 --- a/integration_test/contract_test.go +++ b/integration_test/contract_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -76,11 +76,10 @@ var _ = Describe("Reading contracts", func() { transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - logs, err := blockChain.GetLogs(core.Contract{Hash: "x123"}, big.NewInt(4703824), nil) + logs, err := blockChain.GetLogs(core.Contract{Hash: "0x123"}, big.NewInt(4703824), nil) Expect(err).To(BeNil()) Expect(len(logs)).To(Equal(0)) - }) }) @@ -98,14 +97,10 @@ var _ = Describe("Reading contracts", func() { contract := testing.SampleContract() var balance = new(big.Int) - arg := common.HexToHash("0xd26114cd6ee289accf82350c8d8487fedb8a0c07") - hashArgs := []common.Hash{arg} - balanceOfArgs := make([]interface{}, len(hashArgs)) - for i, s := range hashArgs { - balanceOfArgs[i] = s - } + args := make([]interface{}, 1) + args[0] = common.HexToHash("0xd26114cd6ee289accf82350c8d8487fedb8a0c07") - err = blockChain.FetchContractData(contract.Abi, "0xd26114cd6ee289accf82350c8d8487fedb8a0c07", "balanceOf", balanceOfArgs, &balance, 5167471) + err = blockChain.FetchContractData(contract.Abi, "0xd26114cd6ee289accf82350c8d8487fedb8a0c07", "balanceOf", args, &balance, 5167471) Expect(err).NotTo(HaveOccurred()) expected := new(big.Int) expected.SetString("10897295492887612977137", 10) diff --git a/pkg/omni/full/transformer/transformer_test.go b/integration_test/contract_watcher_full_transformer_test.go similarity index 58% rename from pkg/omni/full/transformer/transformer_test.go rename to integration_test/contract_watcher_full_transformer_test.go index 9d68143c..943428f2 100644 --- a/pkg/omni/full/transformer/transformer_test.go +++ b/integration_test/contract_watcher_full_transformer_test.go @@ -1,23 +1,8 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package transformer_test +package integration import ( "fmt" + "github.com/vulcanize/vulcanizedb/pkg/config" "math/rand" "strings" "time" @@ -26,16 +11,16 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/full/transformer" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" ) -var _ = Describe("Transformer", func() { +var _ = Describe("contractWatcher full transformer", func() { var db *postgres.DB var err error var blockChain core.BlockChain @@ -53,72 +38,13 @@ var _ = Describe("Transformer", func() { test_helpers.TearDown(db) }) - Describe("SetEvents", func() { - It("Sets which events to watch from the given contract address", func() { - watchedEvents := []string{"Transfer", "Mint"} - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, watchedEvents) - Expect(t.WatchedEvents[tusdAddr]).To(Equal(watchedEvents)) - }) - }) - - Describe("SetEventAddrs", func() { - It("Sets which account addresses to watch events for", func() { - eventAddrs := []string{"test1", "test2"} - t := transformer.NewTransformer("", blockChain, db) - t.SetEventArgs(constants.TusdContractAddress, eventAddrs) - Expect(t.EventArgs[tusdAddr]).To(Equal(eventAddrs)) - }) - }) - - Describe("SetMethods", func() { - It("Sets which methods to poll at the given contract address", func() { - watchedMethods := []string{"balanceOf", "totalSupply"} - t := transformer.NewTransformer("", blockChain, db) - t.SetMethods(constants.TusdContractAddress, watchedMethods) - Expect(t.WantedMethods[tusdAddr]).To(Equal(watchedMethods)) - }) - }) - - Describe("SetMethodAddrs", func() { - It("Sets which account addresses to poll methods against", func() { - methodAddrs := []string{"test1", "test2"} - t := transformer.NewTransformer("", blockChain, db) - t.SetMethodArgs(constants.TusdContractAddress, methodAddrs) - Expect(t.MethodArgs[tusdAddr]).To(Equal(methodAddrs)) - }) - }) - - Describe("SetStartingBlock", func() { - It("Sets the block range that the contract should be watched within", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetStartingBlock(constants.TusdContractAddress, 11) - Expect(t.ContractStart[tusdAddr]).To(Equal(int64(11))) - }) - }) - - Describe("SetCreateAddrList", func() { - It("Sets the block range that the contract should be watched within", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetCreateAddrList(constants.TusdContractAddress, true) - Expect(t.CreateAddrList[tusdAddr]).To(Equal(true)) - }) - }) - - Describe("SetCreateHashList", func() { - It("Sets the block range that the contract should be watched within", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetCreateHashList(constants.TusdContractAddress, true) - Expect(t.CreateHashList[tusdAddr]).To(Equal(true)) - }) - }) - Describe("Init", func() { It("Initializes transformer's contract objects", func() { - blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1) - blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2) - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) + _, insertErr := blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1) + Expect(insertErr).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2) + Expect(insertErrTwo).NotTo(HaveOccurred()) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -126,25 +52,30 @@ var _ = Describe("Transformer", func() { Expect(ok).To(Equal(true)) Expect(c.StartingBlock).To(Equal(int64(6194633))) - Expect(c.LastBlock).To(Equal(int64(6194634))) Expect(c.Abi).To(Equal(constants.TusdAbiString)) Expect(c.Name).To(Equal("TrueUSD")) Expect(c.Address).To(Equal(tusdAddr)) }) It("Fails to initialize if first and most recent blocks cannot be fetched from vDB", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Init() Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) It("Does nothing if watched events are unset", func() { - blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1) - blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2) - t := transformer.NewTransformer("", blockChain, db) + _, insertErr := blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1) + Expect(insertErr).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2) + Expect(insertErrTwo).NotTo(HaveOccurred()) + var testConf config.ContractConfig + testConf = test_helpers.TusdConfig + testConf.Events = nil + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() - Expect(err).ToNot(HaveOccurred()) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no filters created")) _, ok := t.Contracts[tusdAddr] Expect(ok).To(Equal(false)) @@ -153,14 +84,14 @@ var _ = Describe("Transformer", func() { Describe("Execute", func() { BeforeEach(func() { - blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1) - blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2) + _, insertErr := blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1) + Expect(insertErr).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2) + Expect(insertErrTwo).NotTo(HaveOccurred()) }) It("Transforms watched contract data into custom repositories", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, nil) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -179,9 +110,12 @@ var _ = Describe("Transformer", func() { }) It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"}) + var testConf config.ContractConfig + testConf = test_helpers.TusdConfig + testConf.Methods = map[string][]string{ + tusdAddr: {"balanceOf"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -213,9 +147,12 @@ var _ = Describe("Transformer", func() { }) It("Polls given methods using generated token holder address", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"}) + var testConf config.ContractConfig + testConf = test_helpers.TusdConfig + testConf.Methods = map[string][]string{ + tusdAddr: {"balanceOf"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -236,28 +173,28 @@ var _ = Describe("Transformer", func() { err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6194634'", tusdAddr)).StructScan(&res) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) It("Fails if initialization has not been done", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, nil) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Execute() Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("transformer has no initialized contracts to work with")) }) }) Describe("Execute- against ENS registry contract", func() { BeforeEach(func() { - blockRepository.CreateOrUpdateBlock(mocks.NewOwnerBlock1) - blockRepository.CreateOrUpdateBlock(mocks.NewOwnerBlock2) + _, insertErr := blockRepository.CreateOrUpdateBlock(mocks.NewOwnerBlock1) + Expect(insertErr).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(mocks.NewOwnerBlock2) + Expect(insertErrTwo).NotTo(HaveOccurred()) }) It("Transforms watched contract data into custom repositories", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, nil) + t := transformer.NewTransformer(test_helpers.ENSConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -277,9 +214,12 @@ var _ = Describe("Transformer", func() { }) It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -304,9 +244,12 @@ var _ = Describe("Transformer", func() { }) It("Polls given methods using generated token holder address", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -324,15 +267,18 @@ var _ = Describe("Transformer", func() { Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000")) Expect(res.TokenName).To(Equal("")) - err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHIS288IS625bFAKE' AND block = '6194636'", ensAddr)).StructScan(&res) + err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x9THIS110dcc444fIS242510c09bbAbe21aFAKEcacNODE82f7b843HASH61ba391' AND block = '6194636'", ensAddr)).StructScan(&res) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) It("It does not perist events if they do not pass the emitted arg filter", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, nil) - t.SetEventArgs(constants.EnsContractAddress, []string{"fake_filter_value"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.EventArgs = map[string][]string{ + ensAddr: {"fake_filter_value"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -343,13 +289,19 @@ var _ = Describe("Transformer", func() { log := test_helpers.LightNewOwnerLog{} err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.newowner_event", ensAddr)).StructScan(&log) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("does not exist")) }) It("If a method arg filter is applied, only those arguments are used in polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) - t.SetMethodArgs(constants.EnsContractAddress, []string{"0x0000000000000000000000000000000000000000000000000000c02aaa39b223"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.MethodArgs = map[string][]string{ + ensAddr: {"0x0000000000000000000000000000000000000000000000000000c02aaa39b223"}, + } + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -364,6 +316,7 @@ var _ = Describe("Transformer", func() { err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391' AND block = '6194636'", ensAddr)).StructScan(&res) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) }) }) diff --git a/pkg/omni/light/transformer/transformer_test.go b/integration_test/contract_watcher_light_transformer_test.go similarity index 58% rename from pkg/omni/light/transformer/transformer_test.go rename to integration_test/contract_watcher_light_transformer_test.go index db805532..3aaa3267 100644 --- a/pkg/omni/light/transformer/transformer_test.go +++ b/integration_test/contract_watcher_light_transformer_test.go @@ -1,20 +1,4 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package transformer_test +package integration import ( "fmt" @@ -24,21 +8,22 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/transformer" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/transformer" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" ) -var _ = Describe("Transformer", func() { +var _ = Describe("contractWatcher light transformer", func() { var db *postgres.DB var err error var blockChain core.BlockChain var headerRepository repositories.HeaderRepository - var headerID, headerID2 int64 + var headerID int64 var ensAddr = strings.ToLower(constants.EnsContractAddress) var tusdAddr = strings.ToLower(constants.TusdContractAddress) @@ -51,72 +36,13 @@ var _ = Describe("Transformer", func() { test_helpers.TearDown(db) }) - Describe("SetEvents", func() { - It("Sets which events to watch from the given contract address", func() { - watchedEvents := []string{"Transfer", "Mint"} - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, watchedEvents) - Expect(t.WatchedEvents[tusdAddr]).To(Equal(watchedEvents)) - }) - }) - - Describe("SetEventAddrs", func() { - It("Sets which account addresses to watch events for", func() { - eventAddrs := []string{"test1", "test2"} - t := transformer.NewTransformer("", blockChain, db) - t.SetEventArgs(constants.TusdContractAddress, eventAddrs) - Expect(t.EventArgs[tusdAddr]).To(Equal(eventAddrs)) - }) - }) - - Describe("SetMethods", func() { - It("Sets which methods to poll at the given contract address", func() { - watchedMethods := []string{"balanceOf", "totalSupply"} - t := transformer.NewTransformer("", blockChain, db) - t.SetMethods(constants.TusdContractAddress, watchedMethods) - Expect(t.WantedMethods[tusdAddr]).To(Equal(watchedMethods)) - }) - }) - - Describe("SetMethodAddrs", func() { - It("Sets which account addresses to poll methods against", func() { - methodAddrs := []string{"test1", "test2"} - t := transformer.NewTransformer("", blockChain, db) - t.SetMethodArgs(constants.TusdContractAddress, methodAddrs) - Expect(t.MethodArgs[tusdAddr]).To(Equal(methodAddrs)) - }) - }) - - Describe("SetStartingBlock", func() { - It("Sets the block range that the contract should be watched within", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetStartingBlock(constants.TusdContractAddress, 11) - Expect(t.ContractStart[tusdAddr]).To(Equal(int64(11))) - }) - }) - - Describe("SetCreateAddrList", func() { - It("Sets the block range that the contract should be watched within", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetCreateAddrList(constants.TusdContractAddress, true) - Expect(t.CreateAddrList[tusdAddr]).To(Equal(true)) - }) - }) - - Describe("SetCreateHashList", func() { - It("Sets the block range that the contract should be watched within", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetCreateHashList(constants.TusdContractAddress, true) - Expect(t.CreateHashList[tusdAddr]).To(Equal(true)) - }) - }) - Describe("Init", func() { It("Initializes transformer's contract objects", func() { - headerRepository.CreateOrUpdateHeader(mocks.MockHeader1) - headerRepository.CreateOrUpdateHeader(mocks.MockHeader3) - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) + _, insertErr := headerRepository.CreateOrUpdateHeader(mocks.MockHeader1) + Expect(insertErr).NotTo(HaveOccurred()) + _, insertErrTwo := headerRepository.CreateOrUpdateHeader(mocks.MockHeader3) + Expect(insertErrTwo).NotTo(HaveOccurred()) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -124,23 +50,27 @@ var _ = Describe("Transformer", func() { Expect(ok).To(Equal(true)) Expect(c.StartingBlock).To(Equal(int64(6194632))) - Expect(c.LastBlock).To(Equal(int64(-1))) Expect(c.Abi).To(Equal(constants.TusdAbiString)) Expect(c.Name).To(Equal("TrueUSD")) Expect(c.Address).To(Equal(tusdAddr)) }) - It("Fails to initialize if first and most recent block numbers cannot be fetched from vDB headers table", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) + It("Fails to initialize if first and block cannot be fetched from vDB headers table", func() { + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Init() Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) - It("Does nothing if watched events are unset", func() { - headerRepository.CreateOrUpdateHeader(mocks.MockHeader1) - headerRepository.CreateOrUpdateHeader(mocks.MockHeader3) - t := transformer.NewTransformer("", blockChain, db) + It("Does nothing if nothing if no addresses are configured", func() { + _, insertErr := headerRepository.CreateOrUpdateHeader(mocks.MockHeader1) + Expect(insertErr).NotTo(HaveOccurred()) + _, insertErrTwo := headerRepository.CreateOrUpdateHeader(mocks.MockHeader3) + Expect(insertErrTwo).NotTo(HaveOccurred()) + var testConf config.ContractConfig + testConf = test_helpers.TusdConfig + testConf.Addresses = nil + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) @@ -164,9 +94,7 @@ var _ = Describe("Transformer", func() { }) It("Transforms watched contract data into custom repositories", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, nil) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() @@ -183,9 +111,12 @@ var _ = Describe("Transformer", func() { }) It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"}) + var testConf config.ContractConfig + testConf = test_helpers.TusdConfig + testConf.Methods = map[string][]string{ + tusdAddr: {"balanceOf"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) c, ok := t.Contracts[tusdAddr] @@ -225,9 +156,12 @@ var _ = Describe("Transformer", func() { }) It("Polls given methods using generated token holder address", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"}) + var testConf config.ContractConfig + testConf = test_helpers.TusdConfig + testConf.Methods = map[string][]string{ + tusdAddr: {"balanceOf"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() @@ -241,14 +175,14 @@ var _ = Describe("Transformer", func() { err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6791669'", tusdAddr)).StructScan(&res) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) It("Fails if initialization has not been done", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, nil) + t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db) err = t.Execute() Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("transformer has no initialized contracts")) }) }) @@ -267,13 +201,12 @@ var _ = Describe("Transformer", func() { }) It("Transforms watched contract data into custom repositories", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, nil) + t := transformer.NewTransformer(test_helpers.ENSConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() Expect(err).ToNot(HaveOccurred()) + Expect(t.Start).To(Equal(int64(6885698))) log := test_helpers.LightNewOwnerLog{} err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&log) @@ -286,9 +219,12 @@ var _ = Describe("Transformer", func() { }) It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) c, ok := t.Contracts[ensAddr] @@ -312,9 +248,12 @@ var _ = Describe("Transformer", func() { }) It("Polls given method using list of collected hashes", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() @@ -331,15 +270,18 @@ var _ = Describe("Transformer", func() { Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000")) Expect(res.TokenName).To(Equal("")) - err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHIS288IS625bFAKE' AND block = '6885696'", ensAddr)).StructScan(&res) + err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x9THIS110dcc444fIS242510c09bbAbe21aFAKEcacNODE82f7b843HASH61ba391' AND block = '6885696'", ensAddr)).StructScan(&res) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) It("It does not persist events if they do not pass the emitted arg filter", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, nil) - t.SetEventArgs(constants.EnsContractAddress, []string{"fake_filter_value"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.EventArgs = map[string][]string{ + ensAddr: {"fake_filter_value"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() @@ -348,13 +290,19 @@ var _ = Describe("Transformer", func() { log := test_helpers.LightNewOwnerLog{} err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&log) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("does not exist")) }) It("If a method arg filter is applied, only those arguments are used in polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) - t.SetMethodArgs(constants.EnsContractAddress, []string{"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSConfig + testConf.MethodArgs = map[string][]string{ + ensAddr: {"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"}, + } + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() @@ -368,49 +316,32 @@ var _ = Describe("Transformer", func() { err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) }) Describe("Execute- against both ENS and TrueUSD", func() { BeforeEach(func() { - header1, err := blockChain.GetHeaderByNumber(6791668) - Expect(err).ToNot(HaveOccurred()) - header2, err := blockChain.GetHeaderByNumber(6791669) - Expect(err).ToNot(HaveOccurred()) - header3, err := blockChain.GetHeaderByNumber(6791670) - Expect(err).ToNot(HaveOccurred()) - header4, err := blockChain.GetHeaderByNumber(6885695) - Expect(err).ToNot(HaveOccurred()) - header5, err := blockChain.GetHeaderByNumber(6885696) - Expect(err).ToNot(HaveOccurred()) - header6, err := blockChain.GetHeaderByNumber(6885697) - Expect(err).ToNot(HaveOccurred()) - headerRepository.CreateOrUpdateHeader(header1) - headerID, err = headerRepository.CreateOrUpdateHeader(header2) - Expect(err).ToNot(HaveOccurred()) - headerRepository.CreateOrUpdateHeader(header3) - headerRepository.CreateOrUpdateHeader(header4) - headerID2, err = headerRepository.CreateOrUpdateHeader(header5) - Expect(err).ToNot(HaveOccurred()) - headerRepository.CreateOrUpdateHeader(header6) + for i := 6885692; i <= 6885701; i++ { + header, err := blockChain.GetHeaderByNumber(int64(i)) + Expect(err).ToNot(HaveOccurred()) + _, err = headerRepository.CreateOrUpdateHeader(header) + Expect(err).ToNot(HaveOccurred()) + } }) It("Transforms watched contract data into custom repositories", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, nil) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, nil) + t := transformer.NewTransformer(test_helpers.ENSandTusdConfig, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() Expect(err).ToNot(HaveOccurred()) + Expect(t.Start).To(Equal(int64(6885702))) newOwnerLog := test_helpers.LightNewOwnerLog{} err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&newOwnerLog) Expect(err).ToNot(HaveOccurred()) // We don't know vulcID, so compare individual fields instead of complete structures - Expect(newOwnerLog.HeaderID).To(Equal(headerID2)) Expect(newOwnerLog.Node).To(Equal("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae")) Expect(newOwnerLog.Label).To(Equal("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047")) Expect(newOwnerLog.Owner).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef")) @@ -419,18 +350,19 @@ var _ = Describe("Transformer", func() { err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.transfer_event", tusdAddr)).StructScan(&transferLog) Expect(err).ToNot(HaveOccurred()) // We don't know vulcID, so compare individual fields instead of complete structures - Expect(transferLog.HeaderID).To(Equal(headerID)) - Expect(transferLog.From).To(Equal("0x1062a747393198f70F71ec65A582423Dba7E5Ab3")) - Expect(transferLog.To).To(Equal("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0")) - Expect(transferLog.Value).To(Equal("9998940000000000000000")) + Expect(transferLog.From).To(Equal("0x8cA465764873E71CEa525F5EB6AE973d650c22C2")) + Expect(transferLog.To).To(Equal("0xc338482360651E5D30BEd77b7c85358cbBFB2E0e")) + Expect(transferLog.Value).To(Equal("2800000000000000000000")) }) It("Keeps track of contract-related hashes and addresses while transforming event data if they need to be used for later method polling", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSandTusdConfig + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + tusdAddr: {"balanceOf"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) ens, ok := t.Contracts[ensAddr] @@ -441,7 +373,7 @@ var _ = Describe("Transformer", func() { Expect(err).ToNot(HaveOccurred()) Expect(len(ens.EmittedHashes)).To(Equal(2)) Expect(len(ens.EmittedAddrs)).To(Equal(0)) - Expect(len(tusd.EmittedAddrs)).To(Equal(4)) + Expect(len(tusd.EmittedAddrs)).To(Equal(2)) Expect(len(tusd.EmittedHashes)).To(Equal(0)) b, ok := ens.EmittedHashes[common.HexToHash("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae")] @@ -452,29 +384,26 @@ var _ = Describe("Transformer", func() { Expect(ok).To(Equal(true)) Expect(b).To(Equal(true)) - b, ok = tusd.EmittedAddrs[common.HexToAddress("0x1062a747393198f70F71ec65A582423Dba7E5Ab3")] + b, ok = tusd.EmittedAddrs[common.HexToAddress("0x8cA465764873E71CEa525F5EB6AE973d650c22C2")] Expect(ok).To(Equal(true)) Expect(b).To(Equal(true)) - b, ok = tusd.EmittedAddrs[common.HexToAddress("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0")] + b, ok = tusd.EmittedAddrs[common.HexToAddress("0xc338482360651E5D30BEd77b7c85358cbBFB2E0e")] Expect(ok).To(Equal(true)) Expect(b).To(Equal(true)) - b, ok = tusd.EmittedAddrs[common.HexToAddress("0x571A326f5B15E16917dC17761c340c1ec5d06f6d")] - Expect(ok).To(Equal(true)) - Expect(b).To(Equal(true)) - - b, ok = tusd.EmittedAddrs[common.HexToAddress("0xFBb1b73C4f0BDa4f67dcA266ce6Ef42f520fBB98")] - Expect(ok).To(Equal(true)) - Expect(b).To(Equal(true)) + _, ok = tusd.EmittedAddrs[common.HexToAddress("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef")] + Expect(ok).To(Equal(false)) }) It("Polls given methods for each contract, using list of collected values", func() { - t := transformer.NewTransformer("", blockChain, db) - t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"}) - t.SetMethods(constants.EnsContractAddress, []string{"owner"}) - t.SetEvents(constants.TusdContractAddress, []string{"Transfer"}) - t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"}) + var testConf config.ContractConfig + testConf = test_helpers.ENSandTusdConfig + testConf.Methods = map[string][]string{ + ensAddr: {"owner"}, + tusdAddr: {"balanceOf"}, + } + t := transformer.NewTransformer(testConf, blockChain, db) err = t.Init() Expect(err).ToNot(HaveOccurred()) err = t.Execute() @@ -491,17 +420,19 @@ var _ = Describe("Transformer", func() { Expect(owner.Address).To(Equal("0x0000000000000000000000000000000000000000")) Expect(owner.TokenName).To(Equal("")) - err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHIS288IS625bFAKE' AND block = '6885696'", ensAddr)).StructScan(&owner) + err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHItransformers.8IS625bFAKE' AND block = '6885696'", ensAddr)).StructScan(&owner) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) bal := test_helpers.BalanceOf{} - err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", tusdAddr)).StructScan(&bal) + err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x8cA465764873E71CEa525F5EB6AE973d650c22C2' AND block = '6885701'", tusdAddr)).StructScan(&bal) Expect(err).ToNot(HaveOccurred()) - Expect(bal.Balance).To(Equal("55849938025000000000000")) + Expect(bal.Balance).To(Equal("1954436000000000000000")) Expect(bal.TokenName).To(Equal("TrueUSD")) - err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6791669'", tusdAddr)).StructScan(&bal) + err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6885701'", tusdAddr)).StructScan(&bal) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no rows in result set")) }) }) }) diff --git a/integration_test/geth_blockchain_test.go b/integration_test/geth_blockchain_test.go index 54719774..69b15a82 100644 --- a/integration_test/geth_blockchain_test.go +++ b/integration_test/geth_blockchain_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package integration_test import ( + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" @@ -48,9 +49,13 @@ var _ = Describe("Reading from the Geth blockchain", func() { It("reads two blocks", func(done Done) { blocks := fakes.NewMockBlockRepository() - lastBlock := blockChain.LastBlock() + lastBlock, err := blockChain.LastBlock() + Expect(err).NotTo(HaveOccurred()) + queriedBlocks := []int64{lastBlock.Int64() - 5, lastBlock.Int64() - 6} - history.RetrieveAndUpdateBlocks(blockChain, blocks, queriedBlocks) + _, err = history.RetrieveAndUpdateBlocks(blockChain, blocks, queriedBlocks) + Expect(err).NotTo(HaveOccurred()) + blocks.AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(2, []int64{lastBlock.Int64() - 5, lastBlock.Int64() - 6}) close(done) }, 30) @@ -60,8 +65,9 @@ var _ = Describe("Reading from the Geth blockchain", func() { Expect(err).ToNot(HaveOccurred()) firstBlock, err := blockChain.GetBlockByNumber(int64(1)) Expect(err).ToNot(HaveOccurred()) - lastBlockNumber := blockChain.LastBlock() + lastBlockNumber, err := blockChain.LastBlock() + Expect(err).NotTo(HaveOccurred()) Expect(genesisBlock.Number).To(Equal(int64(0))) Expect(firstBlock.Number).To(Equal(int64(1))) Expect(lastBlockNumber.Int64()).To(BeNumerically(">", 0)) @@ -80,6 +86,41 @@ var _ = Describe("Reading from the Geth blockchain", func() { close(done) }, 15) + It("retrieves transaction", func() { + // actual transaction: https://etherscan.io/tx/0x44d462f2a19ad267e276b234a62c542fc91c974d2e4754a325ca405f95440255 + txHash := common.HexToHash("0x44d462f2a19ad267e276b234a62c542fc91c974d2e4754a325ca405f95440255") + transactions, err := blockChain.GetTransactions([]common.Hash{txHash}) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(transactions)).To(Equal(1)) + expectedData := []byte{149, 227, 197, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 160, 85, 105, 13, 157, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 241, 202, 218, 90, 30, 178, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 92, 155, 193, 43} + expectedRaw := []byte{248, 201, 9, 132, 59, 154, 202, 0, 131, 1, 102, 93, 148, 44, 75, 208, 100, 185, 152, 131, + 128, 118, 250, 52, 26, 131, 208, 7, 252, 47, 165, 9, 87, 128, 184, 100, 149, 227, 197, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 160, 85, 105, 13, 157, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 241, 202, 218, 90, 30, 178, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 155, 193, 43, 37, 160, 237, 184, 236, 248, 23, 152, + 53, 238, 44, 215, 181, 234, 229, 157, 246, 212, 178, 88, 25, 116, 134, 163, 124, 64, 2, 66, 25, 118, 1, 253, 27, + 101, 160, 36, 226, 116, 43, 147, 236, 124, 76, 227, 250, 228, 168, 22, 19, 248, 155, 248, 151, 219, 14, 1, 186, + 159, 35, 154, 22, 222, 123, 254, 147, 63, 221} + expectedModel := core.TransactionModel{ + Data: expectedData, + From: "0x3b08b99441086edd66f36f9f9aee733280698378", + GasLimit: 91741, + GasPrice: 1000000000, + Hash: "0x44d462f2a19ad267e276b234a62c542fc91c974d2e4754a325ca405f95440255", + Nonce: 9, + Raw: expectedRaw, + Receipt: core.Receipt{}, + To: "0x2c4bd064b998838076fa341a83d007fc2fa50957", + TxIndex: 30, + Value: "0", + } + Expect(transactions[0]).To(Equal(expectedModel)) + }) + //Benchmarking test: remove skip to test performance of block retrieval XMeasure("retrieving n blocks", func(b Benchmarker) { b.Time("runtime", func() { diff --git a/integration_test/integration_test_suite_test.go b/integration_test/integration_test_suite_test.go index cc2318de..fd5e5588 100644 --- a/integration_test/integration_test_suite_test.go +++ b/integration_test/integration_test_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/shared/poller/poller_test.go b/integration_test/poller_test.go similarity index 89% rename from pkg/omni/shared/poller/poller_test.go rename to integration_test/poller_test.go index b36cecde..fe913176 100644 --- a/pkg/omni/shared/poller/poller_test.go +++ b/integration_test/poller_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package poller_test +package integration_test import ( "fmt" @@ -23,18 +23,18 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/poller" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) var _ = Describe("Poller", func() { - var p poller.Poller + var contractPoller poller.Poller var con *contract.Contract var db *postgres.DB var bc core.BlockChain @@ -46,7 +46,7 @@ var _ = Describe("Poller", func() { Describe("Full sync mode", func() { BeforeEach(func() { db, bc = test_helpers.SetupDBandBC() - p = poller.NewPoller(bc, db, types.FullSync) + contractPoller = poller.NewPoller(bc, db, types.FullSync) }) Describe("PollContract", func() { @@ -54,10 +54,9 @@ var _ = Describe("Poller", func() { con = test_helpers.SetupTusdContract(nil, []string{"balanceOf"}) Expect(con.Abi).To(Equal(constants.TusdAbiString)) con.StartingBlock = 6707322 - con.LastBlock = 6707323 con.AddEmittedAddr(common.HexToAddress("0xfE9e8709d3215310075d67E3ed32A380CCf451C8"), common.HexToAddress("0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE")) - err := p.PollContract(*con) + err := contractPoller.PollContract(*con, 6707323) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.BalanceOf{} @@ -89,7 +88,7 @@ var _ = Describe("Poller", func() { Expect(len(con.Methods)).To(Equal(1)) con.AddEmittedHash(common.HexToHash("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"), common.HexToHash("0x7e74a86b6e146964fb965db04dc2590516da77f720bb6759337bf5632415fd86")) - err := p.PollContractAt(*con, 6885877) + err := contractPoller.PollContractAt(*con, 6885877) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.Owner{} @@ -109,10 +108,9 @@ var _ = Describe("Poller", func() { con = test_helpers.SetupTusdContract(nil, nil) Expect(con.Abi).To(Equal(constants.TusdAbiString)) con.StartingBlock = 6707322 - con.LastBlock = 6707323 con.AddEmittedAddr(common.HexToAddress("0xfE9e8709d3215310075d67E3ed32A380CCf451C8"), common.HexToAddress("0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE")) - err := p.PollContract(*con) + err := contractPoller.PollContract(*con, 6707323) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.BalanceOf{} @@ -125,7 +123,7 @@ var _ = Describe("Poller", func() { Describe("FetchContractData", func() { It("Calls a single contract method", func() { var name = new(string) - err := p.FetchContractData(constants.TusdAbiString, constants.TusdContractAddress, "name", nil, &name, 6197514) + err := contractPoller.FetchContractData(constants.TusdAbiString, constants.TusdContractAddress, "name", nil, &name, 6197514) Expect(err).ToNot(HaveOccurred()) Expect(*name).To(Equal("TrueUSD")) }) @@ -135,7 +133,7 @@ var _ = Describe("Poller", func() { Describe("Light sync mode", func() { BeforeEach(func() { db, bc = test_helpers.SetupDBandBC() - p = poller.NewPoller(bc, db, types.LightSync) + contractPoller = poller.NewPoller(bc, db, types.LightSync) }) Describe("PollContract", func() { @@ -143,10 +141,9 @@ var _ = Describe("Poller", func() { con = test_helpers.SetupTusdContract(nil, []string{"balanceOf"}) Expect(con.Abi).To(Equal(constants.TusdAbiString)) con.StartingBlock = 6707322 - con.LastBlock = 6707323 con.AddEmittedAddr(common.HexToAddress("0xfE9e8709d3215310075d67E3ed32A380CCf451C8"), common.HexToAddress("0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE")) - err := p.PollContract(*con) + err := contractPoller.PollContract(*con, 6707323) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.BalanceOf{} @@ -178,7 +175,7 @@ var _ = Describe("Poller", func() { Expect(len(con.Methods)).To(Equal(1)) con.AddEmittedHash(common.HexToHash("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"), common.HexToHash("0x7e74a86b6e146964fb965db04dc2590516da77f720bb6759337bf5632415fd86")) - err := p.PollContractAt(*con, 6885877) + err := contractPoller.PollContractAt(*con, 6885877) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.Owner{} @@ -198,10 +195,9 @@ var _ = Describe("Poller", func() { con = test_helpers.SetupTusdContract(nil, nil) Expect(con.Abi).To(Equal(constants.TusdAbiString)) con.StartingBlock = 6707322 - con.LastBlock = 6707323 con.AddEmittedAddr(common.HexToAddress("0xfE9e8709d3215310075d67E3ed32A380CCf451C8"), common.HexToAddress("0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE")) - err := p.PollContract(*con) + err := contractPoller.PollContract(*con, 6707323) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.BalanceOf{} @@ -214,11 +210,10 @@ var _ = Describe("Poller", func() { con = test_helpers.SetupENSContract(nil, []string{"resolver"}) Expect(con.Abi).To(Equal(constants.ENSAbiString)) con.StartingBlock = 6921967 - con.LastBlock = 6921968 con.EmittedAddrs = map[interface{}]bool{} con.Piping = false con.AddEmittedHash(common.HexToHash("0x495b6e6efdedb750aa519919b5cf282bdaa86067b82a2293a3ff5723527141e8")) - err := p.PollContract(*con) + err := contractPoller.PollContract(*con, 6921968) Expect(err).ToNot(HaveOccurred()) scanStruct := test_helpers.Resolver{} @@ -230,10 +225,10 @@ var _ = Describe("Poller", func() { test_helpers.TearDown(db) db, bc = test_helpers.SetupDBandBC() - p = poller.NewPoller(bc, db, types.LightSync) + contractPoller = poller.NewPoller(bc, db, types.LightSync) con.Piping = true - err = p.PollContract(*con) + err = contractPoller.PollContract(*con, 6921968) Expect(err).ToNot(HaveOccurred()) err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.resolver_method WHERE node_ = '0x495b6e6efdedb750aa519919b5cf282bdaa86067b82a2293a3ff5723527141e8' AND block = '6921967'", constants.EnsContractAddress)).StructScan(&scanStruct) @@ -248,7 +243,7 @@ var _ = Describe("Poller", func() { Describe("FetchContractData", func() { It("Calls a single contract method", func() { var name = new(string) - err := p.FetchContractData(constants.TusdAbiString, constants.TusdContractAddress, "name", nil, &name, 6197514) + err := contractPoller.FetchContractData(constants.TusdAbiString, constants.TusdContractAddress, "name", nil, &name, 6197514) Expect(err).ToNot(HaveOccurred()) Expect(*name).To(Equal("TrueUSD")) }) diff --git a/libraries/shared/README.md b/libraries/shared/README.md new file mode 100644 index 00000000..8a97476d --- /dev/null +++ b/libraries/shared/README.md @@ -0,0 +1,8 @@ +# Shared Tools + +## Description +Code that is useful for or used by plugins written on top of VulcanizeDB. + +## Note +Much code in this directory may not be used outside of the tests, but don't delete it - it could be used by a plugin. +Renaming and/or deleting functions in this namespace requires a version bump to avoid breaking plugins. \ No newline at end of file diff --git a/libraries/shared/TransformerREADME.md b/libraries/shared/TransformerREADME.md deleted file mode 100644 index 1049f271..00000000 --- a/libraries/shared/TransformerREADME.md +++ /dev/null @@ -1,27 +0,0 @@ -# Transformers - -## Description -Transformers must be defined in order to define what events should trigger data updates and how those are performed. - -## Interface - -### Initializer -Accepts DB and Blockchain from Vulcanize and returns a new transformer. E.g. for a new object "Cup": -`func NewCupTransformer(db *postgres.DB, blockchain core.ContractDataFetcher) transformers.Transformer` - -### Execute -Triggers operations to take in response to a given log event. -Can persist data from logs, fetch and persist arbitrary data from outside services (e.g. contract state), or take any number of other actions. E.g.: -`func (cupTransformer *CupTransformer) Execute() error` - -## Additional Requirements -Transformers must define log filters and create them so that relevant watched events can be identified and retrieved. E.g.: -```$xslt - { - Name: "CupsBite", - FromBlock: 0, - ToBlock: -1, - Address: "0x448a5065aebb8e423f0896e6c5d525c040f59af3", - Topics: core.Topics{"0x40cc885400000000000000000000000000000000000000000000000000000000"}, - }, -``` \ No newline at end of file diff --git a/libraries/shared/chunker/chunker_suite_test.go b/libraries/shared/chunker/chunker_suite_test.go new file mode 100644 index 00000000..0c5d4562 --- /dev/null +++ b/libraries/shared/chunker/chunker_suite_test.go @@ -0,0 +1,35 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package chunker_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" + "io/ioutil" +) + +func TestFactories(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Chunker Suite") +} + +var _ = BeforeSuite(func() { + log.SetOutput(ioutil.Discard) +}) diff --git a/libraries/shared/chunker/log_chunker.go b/libraries/shared/chunker/log_chunker.go new file mode 100644 index 00000000..87861ba4 --- /dev/null +++ b/libraries/shared/chunker/log_chunker.go @@ -0,0 +1,72 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package chunker + +import ( + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" +) + +type Chunker interface { + AddConfigs(transformerConfigs []shared_t.EventTransformerConfig) + ChunkLogs(logs []types.Log) map[string][]types.Log +} + +type LogChunker struct { + AddressToNames map[string][]string + NameToTopic0 map[string]common.Hash +} + +// Returns a new log chunker with initialised maps. +// Needs to have configs added with `AddConfigs` to consider logs for the respective transformer. +func NewLogChunker() *LogChunker { + return &LogChunker{ + AddressToNames: map[string][]string{}, + NameToTopic0: map[string]common.Hash{}, + } +} + +// Configures the chunker by adding more addreses and topics to consider. +func (chunker *LogChunker) AddConfigs(transformerConfigs []shared_t.EventTransformerConfig) { + for _, config := range transformerConfigs { + for _, address := range config.ContractAddresses { + var lowerCaseAddress = strings.ToLower(address) + chunker.AddressToNames[lowerCaseAddress] = append(chunker.AddressToNames[lowerCaseAddress], config.TransformerName) + chunker.NameToTopic0[config.TransformerName] = common.HexToHash(config.Topic) + } + } +} + +// Goes through an array of logs, associating relevant logs (matching addresses and topic) with transformers +func (chunker *LogChunker) ChunkLogs(logs []types.Log) map[string][]types.Log { + chunks := map[string][]types.Log{} + for _, log := range logs { + // Topic0 is not unique to each transformer, also need to consider the contract address + relevantTransformers := chunker.AddressToNames[strings.ToLower(log.Address.String())] + + for _, transformer := range relevantTransformers { + if chunker.NameToTopic0[transformer] == log.Topics[0] { + chunks[transformer] = append(chunks[transformer], log) + } + } + } + return chunks +} diff --git a/libraries/shared/chunker/log_chunker_test.go b/libraries/shared/chunker/log_chunker_test.go new file mode 100644 index 00000000..daf23a50 --- /dev/null +++ b/libraries/shared/chunker/log_chunker_test.go @@ -0,0 +1,152 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package chunker_test + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + chunk "github.com/vulcanize/vulcanizedb/libraries/shared/chunker" + shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" +) + +var _ = Describe("Log chunker", func() { + var ( + configs []shared_t.EventTransformerConfig + chunker *chunk.LogChunker + ) + + BeforeEach(func() { + configA := shared_t.EventTransformerConfig{ + TransformerName: "TransformerA", + ContractAddresses: []string{"0x00000000000000000000000000000000000000A1", "0x00000000000000000000000000000000000000A2"}, + Topic: "0xA", + } + configB := shared_t.EventTransformerConfig{ + TransformerName: "TransformerB", + ContractAddresses: []string{"0x00000000000000000000000000000000000000B1"}, + Topic: "0xB", + } + + configC := shared_t.EventTransformerConfig{ + TransformerName: "TransformerC", + ContractAddresses: []string{"0x00000000000000000000000000000000000000A2"}, + Topic: "0xC", + } + + configs = []shared_t.EventTransformerConfig{configA, configB, configC} + chunker = chunk.NewLogChunker() + chunker.AddConfigs(configs) + }) + + Describe("initialisation", func() { + It("creates lookup maps correctly", func() { + Expect(chunker.AddressToNames).To(Equal(map[string][]string{ + "0x00000000000000000000000000000000000000a1": {"TransformerA"}, + "0x00000000000000000000000000000000000000a2": {"TransformerA", "TransformerC"}, + "0x00000000000000000000000000000000000000b1": {"TransformerB"}, + })) + + Expect(chunker.NameToTopic0).To(Equal(map[string]common.Hash{ + "TransformerA": common.HexToHash("0xA"), + "TransformerB": common.HexToHash("0xB"), + "TransformerC": common.HexToHash("0xC"), + })) + }) + }) + + Describe("AddConfigs", func() { + It("can add more configs later", func() { + configD := shared_t.EventTransformerConfig{ + TransformerName: "TransformerD", + ContractAddresses: []string{"0x000000000000000000000000000000000000000D"}, + Topic: "0xD", + } + chunker.AddConfigs([]shared_t.EventTransformerConfig{configD}) + + Expect(chunker.AddressToNames).To(ContainElement([]string{"TransformerD"})) + Expect(chunker.NameToTopic0).To(ContainElement(common.HexToHash("0xD"))) + }) + + It("lower cases address", func() { + configD := shared_t.EventTransformerConfig{ + TransformerName: "TransformerD", + ContractAddresses: []string{"0x000000000000000000000000000000000000000D"}, + Topic: "0xD", + } + chunker.AddConfigs([]shared_t.EventTransformerConfig{configD}) + + Expect(chunker.AddressToNames["0x000000000000000000000000000000000000000d"]).To(Equal([]string{"TransformerD"})) + }) + }) + + Describe("ChunkLogs", func() { + It("only associates logs with relevant topic0 and address to transformers", func() { + logs := []types.Log{log1, log2, log3, log4, log5} + chunks := chunker.ChunkLogs(logs) + + Expect(chunks["TransformerA"]).To(And(ContainElement(log1), ContainElement(log4))) + Expect(chunks["TransformerB"]).To(BeEmpty()) + Expect(chunks["TransformerC"]).To(ContainElement(log5)) + }) + }) +}) + +var ( + // Match TransformerA + log1 = types.Log{ + Address: common.HexToAddress("0xA1"), + Topics: []common.Hash{ + common.HexToHash("0xA"), + common.HexToHash("0xLogTopic1"), + }, + } + // Match TransformerA address, but not topic0 + log2 = types.Log{ + Address: common.HexToAddress("0xA1"), + Topics: []common.Hash{ + common.HexToHash("0xB"), + common.HexToHash("0xLogTopic2"), + }, + } + // Match TransformerA topic, but TransformerB address + log3 = types.Log{ + Address: common.HexToAddress("0xB1"), + Topics: []common.Hash{ + common.HexToHash("0xA"), + common.HexToHash("0xLogTopic3"), + }, + } + // Match TransformerA, with the other address + log4 = types.Log{ + Address: common.HexToAddress("0xA2"), + Topics: []common.Hash{ + common.HexToHash("0xA"), + common.HexToHash("0xLogTopic4"), + }, + } + // Match TransformerC, which shares address with TransformerA + log5 = types.Log{ + Address: common.HexToAddress("0xA2"), + Topics: []common.Hash{ + common.HexToHash("0xC"), + common.HexToHash("0xLogTopic5"), + }, + } +) diff --git a/examples/erc20_watcher/event_triggered/dai/dai_suite_test.go b/libraries/shared/constants/checked_headers.go similarity index 74% rename from examples/erc20_watcher/event_triggered/dai/dai_suite_test.go rename to libraries/shared/constants/checked_headers.go index e766c6a6..c3fdbeb3 100644 --- a/examples/erc20_watcher/event_triggered/dai/dai_suite_test.go +++ b/libraries/shared/constants/checked_headers.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,16 +14,12 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package dai_test +package constants -import ( - "testing" +type TransformerExecution bool - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" +const ( + HeaderRecheck TransformerExecution = true + HeaderMissing TransformerExecution = false + RecheckHeaderCap = "4" ) - -func TestLogKill(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Dai ERC20 Event Triggered Test Suite") -} diff --git a/libraries/shared/constants/data.go b/libraries/shared/constants/data.go new file mode 100644 index 00000000..f4803592 --- /dev/null +++ b/libraries/shared/constants/data.go @@ -0,0 +1,19 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package constants + +var DataItemLength = 32 diff --git a/libraries/shared/contract_config.go b/libraries/shared/contract_config.go deleted file mode 100644 index 8eac45a7..00000000 --- a/libraries/shared/contract_config.go +++ /dev/null @@ -1,33 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package shared - -import ( - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/vulcanize/vulcanizedb/pkg/filters" -) - -type ContractConfig struct { - Address string - Owner string - Abi string - ParsedAbi abi.ABI - FirstBlock int64 - LastBlock int64 - Name string - Filters []filters.LogFilter -} diff --git a/libraries/shared/factories/event/README.md b/libraries/shared/factories/event/README.md new file mode 100644 index 00000000..d68bd709 --- /dev/null +++ b/libraries/shared/factories/event/README.md @@ -0,0 +1,388 @@ +# Watching Contract Events + +One approach VulcanizeDB takes to caching and indexing smart contracts is to watch contract events emitted in receipt logs. + +With a light synced vDB we can watch events by iterating over headers retrieved from the synced `headers` table and using these headers to +fetch and verify relevant event logs from a full Ethereum node, keeping track of which headers we have checked for which events +with our `checked_headers` table. + +## Assumptions + +This approach assumes you are running a vDB light sync which is itself run against a light Ethereum node, +this approach also assumes there is a full node available. + +Looking forward, we will be building fetchers that enable sourcing data from IPFS instead of an ETH node. + +## Shared Code + +VulcanizeDB has shared code built out for building and plugging in event transformers + +### [Event Watcher (light sync)](../staging/libraries/shared/watcher/event_watcher.go) + +The event watcher is responsible for continuously fetching and delegating chunks of logs and their associated header to the appropriate transformers. + +Using the `compose` or `composeAndExecute` command, event watchers can be loaded with plugin event transformers and execute over them. + +### [Event Transformer](../staging/libraries/shared/transformer/event_transformer.go) + +The event transformer is responsible for converting event logs into more useful data objects and storing them in Postgres. +The event transformer is composed of converter and repository interfaces and a config struct: +```go +type EventTransformer struct { + Config transformer.EventTransformerConfig + Converter Converter + Repository Repository +} +``` + +The event transformer executes over provided event logs at a given header. + +In this process, the converter unpacks these logs into entities and then converts these entities +to their final db models. These models are then written to the Postgres db by the repository. + +```go +func (transformer Transformer) Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error { + transformerName := transformer.Config.TransformerName + config := transformer.Config + + if len(logs) < 1 { + err := transformer.Repository.MarkHeaderChecked(header.Id) + if err != nil { + log.Printf("Error marking header as checked in %v: %v", transformerName, err) + return err + } + return nil + } + + entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs) + if err != nil { + log.Printf("Error converting logs to entities in %v: %v", transformerName, err) + return err + } + + models, err := transformer.Converter.ToModels(entities) + if err != nil { + log.Printf("Error converting entities to models in %v: %v", transformerName, err) + return err + } + + err = transformer.Repository.Create(header.Id, models) + if err != nil { + log.Printf("Error persisting %v record: %v", transformerName, err) + return err + } + + return nil +} +``` + + +## Custom Code + +In order to watch events at a smart contract, for those events the developer must create: + +1. Config - struct to hold configuration information (contract address, starting block, event name and signature). +1. Entity - struct to unpack the event log into. +1. Model - struct representing the final data model we want to write to Postgres. +1. Converter - an interface which can unpack event logs into our entities and convert those entities to our models. +1. Repository - an interface to write our models to Postgres. +1. EventTransformerInitializer - a public variable which exports our configured transformer to be loaded as part of a plugin. +1. DB migrations - migrations to generate the Postgres schema, tables, views, function, etc that are needed to store and interface with the transformed data models. + +The example event we will use looks like: +``` +event ExampleEvent(bytes32 indexed arg1, address indexed arg2, bytes32 arg3, uint256 arg4, uint256 arg5); +``` + +### Config + +The config holds configuration variables for the event transformer, including a name for the transformer, the contract address +it is working at, the contract's ABI, the topic (e.g. event signature; topic0) that it is filtering for, and starting +and ending block numbers. + +```go +type EventTransformerConfig struct { + TransformerName string + ContractAddresses []string + ContractAbi string + Topic string + StartingBlockNumber int64 + EndingBlockNumber int64 // Set -1 for indefinite transformer +} +``` + +### Entity + +Entity field names for event arguments need to be exported and match the argument's name and type. LogIndex, +TransactionIndex, and the Raw log are retained in order to link the data to it's source for downstream validation. + +```go +type ExampleEntity struct { + Arg1 common.Hash + Arg2 common.Address + Arg3 common.Hash + Arg4 *big.Int + Arg5 *big.Int + LogIndex uint + TransactionIndex uint + Raw types.Log +} +``` + +### Model + +Model fields are not constrained by the event log structure. +This allows us to rename our fields, decode or convert our log values into more useful types, and perform operations +with or on the values before persisting the data to Postgres. + +```go +type ExampleModel struct { + EventHash string + UserAddress string + FractionSkimmed string + Surplus string + Deficit string + FinalPosition string + LogIndex uint + TransactionIndex uint + Raw types.Log +} +``` + +### Converter + +The converter needs to satisfy the interface. One for unpacking logs into the custom defined entities, and +another for converting those entities to their final db models. + +```go +type Converter interface { + ToEntities(contractAbi string, ethLog []types.Log) ([]interface{}, error) + ToModels([]interface{}) ([]interface{}, error) +} +``` + +For the example event, this might look like: +```go +type ExampleConverter struct{} + +func (ExampleConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) { + var entities []interface{} + for _, ethLog := range ethLogs { + entity := &ExampleEntity{} + address := ethLog.Address + abi, err := geth.ParseAbi(contractAbi) + if err != nil { + return nil, err + } + + contract := bind.NewBoundContract(address, abi, nil, nil, nil) + + err = contract.UnpackLog(entity, "ExampleEvent", ethLog) + if err != nil { + return nil, err + } + + entity.Raw = ethLog + entity.LogIndex = ethLog.Index + entity.TransactionIndex = ethLog.TxIndex + + entities = append(entities, *entity) + } + + return entities, nil +} + +func (converter ExampleConverter) ToModels(entities []interface{}) ([]interface{}, error) { + var models []interface{} + for _, entity := range entities { + entity, ok := entity.(ExampleModel) + if !ok { + return nil, fmt.Errorf("entity of type %T, not %T", entity, ExampleModel{}) + } + + fractionSkimmed, err := hexutil.DecodeBig(entity.Arg3.Hex()) + if err != nil { + reuturn nil, err + } + position := new(big.Int) + position.Sub(entity.Arg4, entity.Arg5) + finalPosition := new(big.Int) + if preTaxPosition.Sign() < 0 { + finalPosition = position + } else { + skim := new(big.Int) + skim.Div(position, fractionSkimmed) + finalPosition = position.Sub(position, skim) + } + + rawLog, err := json.Marshal(entity.Raw) + if err != nil { + return nil, err + } + + model := ExampleModel{ + EventHash: entity.Arg1.Hex(), + UserAddress: entity.Arg2.Hex(), + FractionSkimmed: fractionSkimmed.String(), + Surplus: entity.Arg4.String(), + Deficit: entity.Arg5.String(), + FinalPosition: finalPosition, + LogIndex: entity.LogIndex, + TransactionIndex: entity.TransactionIndex, + Raw: rawLog, + } + models = append(models, model) + } + return models, nil +} +``` +Notice that in this example we have a bytes32 argument in the event that needs to be decoded to an integer before it can be worked with +to produce our hypothetical `FinalPosition` field. This is to highlight the fact that contracts can and sometimes do encode the +data types we want to work with into raw bytes. Writing custom transformers with these converters allows us to account for this. + +### Repository + +The repository needs to satisfy the interface and use the `Create` method to write the model to Postgres. +```go +type Repository interface { + Create(headerID int64, models []interface{}) error + MarkHeaderChecked(headerID int64) error + MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) + RecheckHeaders(startingBlockNumber, endingBlockNUmber int64) ([]core.Header, error) + SetDB(db *postgres.DB) +} +``` + +For the example event, this might look like: +```go +type ExampleRepository struct { + db *postgres.DB +} + +func (repository *ExampleRepository) SetDB(db *postgres.DB) { + repository.db = db +} + +func (repository ExampleRepository) Create(headerID int64, models []interface{}) error { + tx, dBaseErr := repository.db.Beginx() + if dBaseErr != nil { + return dBaseErr + } + for _, model := range models { + model, ok := model.(ExampleModel) + if !ok { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + log.Error("failed to rollback ", rollbackErr) + } + return fmt.Errorf("model of type %T, not %T", model, ExampleModel{}) + } + + _, execErr := tx.Exec( + `INSERT into example_schema.example_event (header_id, event_hash, user_address, fraction_skimmed, surplus, deficit, final_position, log_idx, tx_idx, raw_log) + VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET event_hash = $2, user_address = $3, fraction_skimmed = $4, surplus = $5, deficit = $6, final_position = $7, raw_log = $10;`, + headerID, model.EventHash, model.UserAddress, model.FractonSkimmed, model.Surplus, model.Deficit, model.FinalPosition, model.LogIndex, model.TransactionIndex, model.Raw, + ) + if execErr != nil { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + log.Error("failed to rollback ", rollbackErr) + } + return execErr + } + } + + checkHeaderErr := repo.MarkHeaderCheckedInTransaction(headerID, tx, "example_event_checked") + if checkHeaderErr != nil { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + log.Error("failed to rollback ", rollbackErr) + } + return checkHeaderErr + } + + return tx.Commit() +} + +func (repository ExampleRepository) MarkHeaderChecked(headerID int64) error { + return repo.MarkHeaderChecked(headerID, repository.db, "example_event_checked") +} + +func (repository ExampleRepository) MissingHeaders(startingBlockNumber int64, endingBlockNumber int64) ([]core.Header, error) { + return repo.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db,"example_event_checked") +} + +func (repository ExampleRepository) RecheckHeaders(startingBlockNumber int64, endingBlockNumber int64) ([]core.Header, error) { + return repo.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, "example_event_checked") +} +``` + +### EventTransformerInitializer + +A transformer initializer variable needs to be exported from somewhere within the transformer repository so that the transformer can be +loaded as part of a plugin in the `compose` or `composeAndExecute` commands. It is important that this variable is named `EventTransformerInitializer` and +it must be of `type EventTransformerInitializer func(db *postgres.DB) EventTransformer`. + +```go +var EventTransformerInitializer transformer.EventTransformerInitializer = factories.Transformer{ + Config: exampleEventConfig, + Converter: ExampleConverter{}, + Repository: &ExampleRepository{}, +}.NewTransformer +``` + +### DB migrations + +We use `goose` as our migration management tool. Any Go data model that needs to be written to Postgres by the +repository needs a db migration for the corresponding Postgres data model. + +Each contract or set of transformers being watched should define its own namespace with a db schema: +```postgresql +-- +goose Up +CREATE SCHEMA example_schema; + + +-- +goose Down +DROP SCHEMA example_schema; + +``` + +For the example event and its resulting model, the table we write to would look like: +```postgresql +-- +goose Up +CREATE TABLE example_schema.example_event ( + id SERIAL PRIMARY KEY, + header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE, + event_hash CHARACTER VARYING(66) NOT NULL, + user_address CHARACTER VARYING(66) NOT NULL, + fraction_skimmed NUMERIC NOT NULL, + surplus NUMERIC NOT NULL, + deficit NUMERIC NOT NULL, + final_position NUMERIC NOT NULL, + tx_idx INTEGER NOT NUll, + log_idx INTEGER NOT NUll, + raw_log JSONB, + UNIQUE (header_id, tx_idx, log_idx) +); + +ALTER TABLE public.checked_headers + ADD COLUMN example_event_checked INTEGER NOT NULL DEFAULT 0; + + +-- +goose Down +DROP TABLE example_schema.example_event; + +ALTER TABLE public.checked_headers + DROP COLUMN example_event_checked; +``` + +Notice that we have also added a column to the `checked_headers` table for this event so that we can keep track +of which headers we have already filtered through for this event. + +## Summary + +To create a transformer for a contract event we need to create entities for unpacking the raw log, models to represent +the final data structure, a converter to mediate this unpacking and conversion between entities to models, a repository to write +these models to Postgres, db migrations to accommodate these models in Postgres, and a EventTransformerInitializer to export the +configured transformer and load it as a plugin to the `compose` or `composeAndExecute` commands as described in the main readme. diff --git a/libraries/shared/factories/event/converter.go b/libraries/shared/factories/event/converter.go new file mode 100644 index 00000000..4fb647f2 --- /dev/null +++ b/libraries/shared/factories/event/converter.go @@ -0,0 +1,24 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package event + +import "github.com/ethereum/go-ethereum/core/types" + +type Converter interface { + ToEntities(contractAbi string, ethLog []types.Log) ([]interface{}, error) + ToModels([]interface{}) ([]interface{}, error) +} diff --git a/examples/generic/every_block/every_block_suite_test.go b/libraries/shared/factories/event/factories_suite_test.go similarity index 85% rename from examples/generic/every_block/every_block_suite_test.go rename to libraries/shared/factories/event/factories_suite_test.go index a9228ec9..f2687b75 100644 --- a/examples/generic/every_block/every_block_suite_test.go +++ b/libraries/shared/factories/event/factories_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,20 +14,20 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package every_block_test +package event_test import ( - "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" + "io/ioutil" ) -func TestEveryBlock(t *testing.T) { +func TestFactories(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Generic EveryBlock Suite") + RunSpecs(t, "Factories Suite") } var _ = BeforeSuite(func() { diff --git a/examples/generic/event_triggered/tusd/tusd_suite_test.go b/libraries/shared/factories/event/log_note_converter.go similarity index 73% rename from examples/generic/event_triggered/tusd/tusd_suite_test.go rename to libraries/shared/factories/event/log_note_converter.go index 6ab43fa2..3b18c46c 100644 --- a/examples/generic/event_triggered/tusd/tusd_suite_test.go +++ b/libraries/shared/factories/event/log_note_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,16 +14,10 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package tusd_test +package event -import ( - "testing" +import "github.com/ethereum/go-ethereum/core/types" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestLogKill(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Tusd Generic Event Triggered Test Suite") +type LogNoteConverter interface { + ToModels(ethLog []types.Log) ([]interface{}, error) } diff --git a/libraries/shared/factories/event/log_note_transformer.go b/libraries/shared/factories/event/log_note_transformer.go new file mode 100644 index 00000000..2b4699b6 --- /dev/null +++ b/libraries/shared/factories/event/log_note_transformer.go @@ -0,0 +1,73 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package event + +import ( + "github.com/ethereum/go-ethereum/core/types" + log "github.com/sirupsen/logrus" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type LogNoteTransformer struct { + Config transformer.EventTransformerConfig + Converter LogNoteConverter + Repository Repository +} + +func (tr LogNoteTransformer) NewLogNoteTransformer(db *postgres.DB) transformer.EventTransformer { + tr.Repository.SetDB(db) + return tr +} + +func (tr LogNoteTransformer) Execute(logs []types.Log, header core.Header, recheckedHeader constants.TransformerExecution) error { + transformerName := tr.Config.TransformerName + + // No matching logs, mark the header as checked for this type of logs + if len(logs) < 1 { + err := tr.Repository.MarkHeaderChecked(header.Id) + if err != nil { + log.Printf("Error marking header as checked in %v: %v", transformerName, err) + return err + } + return nil + } + + models, err := tr.Converter.ToModels(logs) + if err != nil { + log.Printf("Error converting logs in %v: %v", transformerName, err) + return err + } + + err = tr.Repository.Create(header.Id, models) + if err != nil { + log.Printf("Error persisting %v record: %v", transformerName, err) + return err + } + return nil +} + +func (tr LogNoteTransformer) GetName() string { + return tr.Config.TransformerName +} + +func (tr LogNoteTransformer) GetConfig() transformer.EventTransformerConfig { + return tr.Config +} diff --git a/libraries/shared/factories/event/log_note_transformer_test.go b/libraries/shared/factories/event/log_note_transformer_test.go new file mode 100644 index 00000000..efc36d34 --- /dev/null +++ b/libraries/shared/factories/event/log_note_transformer_test.go @@ -0,0 +1,126 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package event_test + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/factories/event" + "github.com/vulcanize/vulcanizedb/libraries/shared/mocks" + "github.com/vulcanize/vulcanizedb/libraries/shared/test_data" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" +) + +var _ = Describe("LogNoteTransformer", func() { + var ( + repository mocks.MockRepository + converter mocks.MockLogNoteConverter + headerOne core.Header + t transformer.EventTransformer + model test_data.GenericModel + config = test_data.GenericTestConfig + logs = test_data.GenericTestLogs + ) + + BeforeEach(func() { + repository = mocks.MockRepository{} + converter = mocks.MockLogNoteConverter{} + t = event.LogNoteTransformer{ + Config: config, + Converter: &converter, + Repository: &repository, + }.NewLogNoteTransformer(nil) + + headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()} + }) + + It("sets the database", func() { + Expect(repository.SetDbCalled).To(BeTrue()) + }) + + It("marks header checked if no logs are provided", func() { + err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id) + }) + + It("doesn't attempt to convert or persist an empty collection when there are no logs", func() { + err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.ToModelsCalledCounter).To(Equal(0)) + Expect(repository.CreateCalledCounter).To(Equal(0)) + }) + + It("does not call repository.MarkCheckedHeader when there are logs", func() { + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + repository.AssertMarkHeaderCheckedNotCalled() + }) + + It("returns error if marking header checked returns err", func() { + repository.SetMarkHeaderCheckedError(fakes.FakeError) + + err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("converts matching logs to models", func() { + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.PassedLogs).To(Equal(logs)) + }) + + It("returns error if converter returns error", func() { + converter.SetConverterError(fakes.FakeError) + + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("persists the model", func() { + converter.SetReturnModels([]interface{}{model}) + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(repository.PassedHeaderID).To(Equal(headerOne.Id)) + Expect(repository.PassedModels).To(Equal([]interface{}{model})) + }) + + It("returns error if repository returns error for create", func() { + repository.SetCreateError(fakes.FakeError) + + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) +}) diff --git a/libraries/shared/factories/event/repository.go b/libraries/shared/factories/event/repository.go new file mode 100644 index 00000000..e1d6e403 --- /dev/null +++ b/libraries/shared/factories/event/repository.go @@ -0,0 +1,30 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package event + +import ( + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type Repository interface { + Create(headerID int64, models []interface{}) error + MarkHeaderChecked(headerID int64) error + MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) + RecheckHeaders(startingBlockNumber, endingBlockNUmber int64) ([]core.Header, error) + SetDB(db *postgres.DB) +} diff --git a/libraries/shared/factories/event/transformer.go b/libraries/shared/factories/event/transformer.go new file mode 100644 index 00000000..bf178948 --- /dev/null +++ b/libraries/shared/factories/event/transformer.go @@ -0,0 +1,80 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package event + +import ( + "github.com/ethereum/go-ethereum/core/types" + log "github.com/sirupsen/logrus" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type Transformer struct { + Config transformer.EventTransformerConfig + Converter Converter + Repository Repository +} + +func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.EventTransformer { + transformer.Repository.SetDB(db) + return transformer +} + +func (transformer Transformer) Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error { + transformerName := transformer.Config.TransformerName + config := transformer.Config + + if len(logs) < 1 { + err := transformer.Repository.MarkHeaderChecked(header.Id) + if err != nil { + log.Printf("Error marking header as checked in %v: %v", transformerName, err) + return err + } + return nil + } + + entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs) + if err != nil { + log.Printf("Error converting logs to entities in %v: %v", transformerName, err) + return err + } + + models, err := transformer.Converter.ToModels(entities) + if err != nil { + log.Printf("Error converting entities to models in %v: %v", transformerName, err) + return err + } + + err = transformer.Repository.Create(header.Id, models) + if err != nil { + log.Printf("Error persisting %v record: %v", transformerName, err) + return err + } + + return nil +} + +func (transformer Transformer) GetName() string { + return transformer.Config.TransformerName +} + +func (transformer Transformer) GetConfig() transformer.EventTransformerConfig { + return transformer.Config +} diff --git a/libraries/shared/factories/event/transformer_test.go b/libraries/shared/factories/event/transformer_test.go new file mode 100644 index 00000000..a5065611 --- /dev/null +++ b/libraries/shared/factories/event/transformer_test.go @@ -0,0 +1,147 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package event_test + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/factories/event" + "github.com/vulcanize/vulcanizedb/libraries/shared/mocks" + "github.com/vulcanize/vulcanizedb/libraries/shared/test_data" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" +) + +var _ = Describe("Transformer", func() { + var ( + repository mocks.MockRepository + converter mocks.MockConverter + t transformer.EventTransformer + headerOne core.Header + config = test_data.GenericTestConfig + logs = test_data.GenericTestLogs + ) + + BeforeEach(func() { + repository = mocks.MockRepository{} + converter = mocks.MockConverter{} + + t = event.Transformer{ + Repository: &repository, + Converter: &converter, + Config: config, + }.NewTransformer(nil) + + headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()} + }) + + It("sets the db", func() { + Expect(repository.SetDbCalled).To(BeTrue()) + }) + + It("marks header checked if no logs returned", func() { + err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id) + }) + + It("doesn't attempt to convert or persist an empty collection when there are no logs", func() { + err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.ToEntitiesCalledCounter).To(Equal(0)) + Expect(converter.ToModelsCalledCounter).To(Equal(0)) + Expect(repository.CreateCalledCounter).To(Equal(0)) + }) + + It("does not call repository.MarkCheckedHeader when there are logs", func() { + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + repository.AssertMarkHeaderCheckedNotCalled() + }) + + It("returns error if marking header checked returns err", func() { + repository.SetMarkHeaderCheckedError(fakes.FakeError) + + err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("converts an eth log to an entity", func() { + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.ContractAbi).To(Equal(config.ContractAbi)) + Expect(converter.LogsToConvert).To(Equal(logs)) + }) + + It("returns an error if converter fails", func() { + converter.ToEntitiesError = fakes.FakeError + + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("converts an entity to a model", func() { + converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}} + + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{})) + }) + + It("returns an error if converting to models fails", func() { + converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}} + converter.ToModelsError = fakes.FakeError + + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("persists the record", func() { + converter.ModelsToReturn = []interface{}{test_data.GenericModel{}} + + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(repository.PassedHeaderID).To(Equal(headerOne.Id)) + Expect(repository.PassedModels[0]).To(Equal(test_data.GenericModel{})) + }) + + It("returns error if persisting the record fails", func() { + repository.SetCreateError(fakes.FakeError) + err := t.Execute(logs, headerOne, constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) +}) diff --git a/libraries/shared/factories/storage/EXAMPLE.md b/libraries/shared/factories/storage/EXAMPLE.md new file mode 100644 index 00000000..116edbfb --- /dev/null +++ b/libraries/shared/factories/storage/EXAMPLE.md @@ -0,0 +1,167 @@ +# Storage Transformer Example + +In the Storage Transformer README, we went over code that needs to be written to add a new storage transformer to VulcanizeDB. +In this document, we'll go over an example contract and discuss how one would go about watching its storage. + +## Example Contract + +For the purposes of this document, we'll be assuming that we're interested in watching the following contract: + +```solidity +pragma solidity ^0.5.1; + +contract Contract { + uint256 public num_addresses; + mapping(address => uint) public addresses; + + event AddressAdded( + address addr, + uint256 num_addrs + ); + + constructor() public { + addresses[msg.sender] = 1; + num_addresses = 1; + } + + function add_address(address addr) public { + bool exists = addresses[addr] > 0; + addresses[addr]++; + if (!exists) { + emit AddressAdded(addr, ++num_addresses); + } + } +} +``` + +Disclaimer: this contract has not been audited and is not intended to be modeled or used in production. :) + +This contract persists two values in its storage: + +1. `num_addresses`: the total number of unique addresses known to the contract. +2. `addresses`: a mapping that records the number of times an address has been added to the contract. + +It also emits an event each time a new address is added into the contract's storage. + +## Custom Code + +In order to monitor the state of this smart contract, we'd need to implement: an event transformer, a mappings namespace, and a repository. +We will go through each of these in turn. + +### Event Transformer + +Given that the contract's storage includes a mapping, `addresses`, we will need to be able to identify the keys to that mapping that exist in the system so that we can recognize contract storage keys that correspond to non-zero values in that mapping. + +The simplest way to be aware of keys used in a contract's mapping is to listen for contract events that emit the keys that are used in its mapping(s). +Since this contract includes an event, `AddressAdded`, that is emitted each time a new address is added to the `addresses` mapping, we will want to listen for those events and cache the adddresses that map to non-zero values. + +Please see the event transformer README for detailed instructions about developing this code. +In short, it should be feasible to recognize `AddressAdded` events on the blockchain and parse them to keep a record of addresses that have been added to the system. + +### Mappings + +If we point an ethereum node at a blockchain hosting this contract and our node is equipped to write out storage changes happening on this contract, we will expect such changes to appear each time `add_address` (which modifies the `addresses` mapping) is called. + +In order for those changes - which include raw hex versions of storage keys and storage values, to be useful for us - we need to know how to recognize and parse them. +Our mappings file should assist us with both of these tasks: the `Lookup` function should recognize raw storage keys and return known metadata about the storage value. + +In order to perform this lookup, the mappings file should maintain its own mapping of known storage keys to the corresponding storage value metadata. +This internal mapping should contain the storage key for `num_addresses` as well as a storage key for each `addresses` key known to be associated with a non-zero value. + +#### num_addresses + +`num_addresses` is the first variable declared on the contract, and it is a simple (non-array, non-mapping) type. +Therefore, we know that its storage key is `0000000000000000000000000000000000000000000000000000000000000000`. +The storage key for non-array and non-mapping variables is (usually*) the index of the variable on the contract's storage. +If we see a storage diff being emitted from this contract with this storage key, we know that the `num_addresses` variable has been modified. + +In this case, we would expect that the call `mappings.Lookup("0000000000000000000000000000000000000000000000000000000000000000")` would return metadata corresponding to the `num_addresses` variable. +This metadata would probably look something like: + +```golang +shared.StorageValueMetadata{ + Name: "num_addresses", + Keys: nil, + Type: shared.Uint256, +} +``` + +* Occasionally, multiple variables may be packed into one storage slot, which complicates a direct translation of the index of the variable on the contract to its storage key. + +#### addresses + +`addresses` is the second variable declared on the contract, but it is a mapping. +Since it is a mapping, the storage key is more complex than `0000000000000000000000000000000000000000000000000000000000000001` (which would be the key for the variable if it were not an array or mapping). +Having a single storage slot for an entire mapping would not work, since there can be an arbitrary number of entries in a mapping, and a single storage value slot is constrained to 32 bytes. + +The way that smart contract mappings are maintained in storage (in Solidity) is by creating a new storage key/value pair for each entry in the mapping, where the storage key is a hash of the occupied slot's key concatenated with the mapping's index on the contract. +Given an occupied slot's key, `k`, and a mapping's index on the contract, `i`, we can generate the storage key with the following code: + +```golang +func GetMappingStorageKey(k, i string) string { + return common.BytesToHash(crypto.Keccak256(common.FromHex(k + i))).Hex() +} +``` + +If we were to call the contract's `add_address` function with `0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe`, we would expect to see an `AddressAdded` event emitted, with `0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` in its payload. +From that event, we would know that there exists in the contract's storage a storage key of: + +```golang +GetMappingStorageKey("0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe", "0000000000000000000000000000000000000000000000000000000000000001") +``` + +Executing the above code results in: `0x0f96a1133cfd5b94c329aa0526b5962bd791dbbfc481ca82f7d4a439e1e9bc40`. + +Therefore, the first time `add_address` was called for this address, we would also expect to see a storage diff with a key of `0x0f96a1133cfd5b94c329aa0526b5962bd791dbbfc481ca82f7d4a439e1e9bc40` and a value of `0000000000000000000000000000000000000000000000000000000000000001`. +This would be the indication that in contract storage, the address `0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` maps to the value 1. + +Given that we knew this address was a key in the mapping from our event transformer, we would expect a call to `mappings.Lookup("0x0f96a1133cfd5b94c329aa0526b5962bd791dbbfc481ca82f7d4a439e1e9bc40")` to return metadata corresponding to _this slot_ in the addresses mapping: + +```golang +shared.StorageValueMetadata{ + Name: "addresses, + Keys: map[Key]string{Address: "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe"}, + Type: shared.Uint256, +} +``` + +### Repository + +Once we have recognized a storage diff, we can decode the storage value to the data's known type. +Since the metadata tells us that the above values are `uint256`, we can decode a value like `0000000000000000000000000000000000000000000000000000000000000001` to `1`. + +The purpose of the contract-specific repository is to write that value to the database in a way that makes it useful for future queries. +Typically, this involves writing the block hash, block number, decoded value, and any keys in the metadata to a table. + +The current repository interface has a generalized `Create` function that can accept any arbitrary storage row along with its metadata. +This is deliberate, to facilitate shared use of the common storage transformer. +An implication of this decision is that the `Create` function typically includes a `switch` statement that selects which table to write to, as well as what data to include, based on the name of the variable as defined in the metadata. + +An example implementation of `Create` for our example contract above might look like: + +```golang +func (repository AddressStorageRepository) Create(blockNumber int, blockHash string, metadata shared.StorageValueMetadata, value interface{}) error { + switch metadata.Name { + case "num_addresses": + _, err := repository.db.Exec(`INSERT INTO storage.num_addresses (block_hash, block_number, n) VALUES ($1, $2, $3)`, + blockHash, blockNumber, value) + return err + case "addresses": + _, err := repository.db.Exec(`INSERT INTO storage.addresses (block_hash, block_number, address, n) VALUES ($1, $2, $3, $4)`, + blockHash, blockNumber, metadata.Keys[Address], value) + return err + default: + panic(fmt.Sprintf("unrecognized contract storage name: %s", metadata.Name)) + } +} +``` + +## Summary + +With our very simple address storing contract, we would be able to read its storage diffs by implementing an event transformer, a mappings, and a repository. + +The mappings would be able to lookup storage keys reflecting `num_addresses` or any slot in `addresses`, using addresses derived from watching the `AddressAdded` event for the latter. + +The repository would be able to persist the value or `num_addresses` or any slot in `addresses`, using metadata returned from the mappings. + +The mappings and repository could be plugged into the common storage transformer, enabling us to know the contract's state as it is changing. diff --git a/libraries/shared/factories/storage/README.md b/libraries/shared/factories/storage/README.md new file mode 100644 index 00000000..cd8dc792 --- /dev/null +++ b/libraries/shared/factories/storage/README.md @@ -0,0 +1,123 @@ +# Watching Contract Storage + +One approach VulcanizeDB takes to caching and indexing smart contracts is to ingest raw contract storage values. +Assuming that you are running an ethereum node that is writing contract storage changes to a CSV file, VulcanizeDB can parse them and persist the results to postgres. + +## Assumptions + +The current approach for caching smart contract storage diffs assumes that you are running a node that is writing contract storage diffs to a CSV file. +The CSV file is expected to have 5 columns: contract address, block hash, block number, storage key, storage value. + +We have [a branch on vulcanize/parity-ethereum](https://github.com/vulcanize/parity-ethereum/tree/watch-storage-diffs) that enables running a node that writes storage diffs this way. + +Looking forward, we would like to isolate this assumption as much as possible. +We may end up needing to read CSV data that is formatted differently, or reading data from a non-CSV source, and we do not want resulting changes to cascade throughout the codebase. + +## Shared Code + +VulcanizeDB has shared code for continuously reading from the CSV file written by the ethereum node and writing a parsed version of each row to postgres. + +### Storage Watcher + +The storage watcher is responsible for continuously delegating CSV rows to the appropriate transformer as they are being written by the ethereum node. +It maintains a mapping of contract addresses to transformers, and will ignore storage diff rows for contract addresses that do not have a corresponding transformer. + +Storage watchers can be loaded with plugin storage transformers and executed using the `composeAndExecute` command. + +### Storage Transformer + +The storage transformer is responsible for converting raw contract storage hex values into useful data and writing them to postgres. +The storage transformer depends on contract-specific implementations of code capable of recognizing storage keys and writing the matching (decoded) storage value to disk. + +```golang +func (transformer Transformer) Execute(row shared.StorageDiffRow) error { + metadata, lookupErr := transformer.Mappings.Lookup(row.StorageKey) + if lookupErr != nil { + return lookupErr + } + value, decodeErr := shared.Decode(row, metadata) + if decodeErr != nil { + return decodeErr + } + return transformer.Repository.Create(row.BlockHeight, row.BlockHash.Hex(), metadata, value) +} +``` + +## Custom Code + +In order to watch an additional smart contract, a developer must create three things: + +1. Mappings - specify how to identify keys in the contract's storage trie. +1. Repository - specify how to persist a parsed version of the storage value matching the recognized storage key. +1. Instance - create an instance of the storage transformer that uses your mappings and repository. + +### Mappings + +```golang +type Mappings interface { + Lookup(key common.Hash) (shared.StorageValueMetadata, error) + SetDB(db *postgres.DB) +} +``` + +A contract-specific implementation of the mappings interface enables the storage transformer to fetch metadata associated with a storage key. + +Storage metadata contains: the name of the variable matching the storage key, a raw version of any keys associated with the variable (if the variable is a mapping), and the variable's type. + +```golang +type StorageValueMetadata struct { + Name string + Keys map[Key]string + Type ValueType +} +``` + +Keys are only relevant if the variable is a mapping. For example, in the following Solidity code: + +```solidity +pragma solidity ^0.4.0; + +contract Contract { + uint x; + mapping(address => uint) y; +} +``` + +The metadata for variable `x` would not have any associated keys, but the metadata for a storage key associated with `y` would include the address used to specify that key's index in the mapping. + +The `SetDB` function is required for the mappings to connect to the database. +A database connection may be desired when keys in a mapping variable need to be read from log events (e.g. to lookup what addresses may exist in `y`, above). + +### Repository + +```golang +type Repository interface { + Create(blockNumber int, blockHash string, metadata shared.StorageValueMetadata, value interface{}) error + SetDB(db *postgres.DB) +} +``` + +A contract-specific implementation of the repository interface enables the transformer to write the decoded storage value to the appropriate table in postgres. + +The `Create` function is expected to recognize and persist a given storage value by the variable's name, as indicated on the row's metadata. + +The `SetDB` function is required for the repository to connect to the database. + +### Instance + +```golang +type Transformer struct { + Address common.Address + Mappings storage_diffs.Mappings + Repository storage_diffs.Repository +} +``` + +A new instance of the storage transformer is initialized with the contract-specific mappings and repository, as well as the contract's address. +The contract's address is included so that the watcher can query that value from the transformer in order to build up its mapping of addresses to transformers. + +## Summary + +To begin watching an additional smart contract, create a new mappings file for looking up storage keys on that contract, a repository for writing storage values from the contract, and initialize a new storage transformer instance with the mappings, repository, and contract address. + +The new instance, wrapped in an initializer that calls `SetDB` on the mappings and repository, should be passed to the `AddTransformers` function on the storage watcher. \ No newline at end of file diff --git a/libraries/shared/shared_suite_test.go b/libraries/shared/factories/storage/storage_suite_test.go similarity index 86% rename from libraries/shared/shared_suite_test.go rename to libraries/shared/factories/storage/storage_suite_test.go index a36f747f..14fb90a0 100644 --- a/libraries/shared/shared_suite_test.go +++ b/libraries/shared/factories/storage/storage_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package shared_test +package storage_test import ( "testing" @@ -23,7 +23,7 @@ import ( . "github.com/onsi/gomega" ) -func TestShared(t *testing.T) { +func TestStorage(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Shared Suite") + RunSpecs(t, "Storage Factories Suite") } diff --git a/libraries/shared/factories/storage/transformer.go b/libraries/shared/factories/storage/transformer.go new file mode 100644 index 00000000..fce04465 --- /dev/null +++ b/libraries/shared/factories/storage/transformer.go @@ -0,0 +1,55 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package storage + +import ( + "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/libraries/shared/repository" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type Transformer struct { + Address common.Address + Mappings storage.Mappings + Repository repository.StorageRepository +} + +func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer { + transformer.Mappings.SetDB(db) + transformer.Repository.SetDB(db) + return transformer +} + +func (transformer Transformer) ContractAddress() common.Address { + return transformer.Address +} + +func (transformer Transformer) Execute(row utils.StorageDiffRow) error { + metadata, lookupErr := transformer.Mappings.Lookup(row.StorageKey) + if lookupErr != nil { + return lookupErr + } + value, decodeErr := utils.Decode(row, metadata) + if decodeErr != nil { + return decodeErr + } + return transformer.Repository.Create(row.BlockHeight, row.BlockHash.Hex(), metadata, value) +} diff --git a/libraries/shared/factories/storage/transformer_test.go b/libraries/shared/factories/storage/transformer_test.go new file mode 100644 index 00000000..354c106b --- /dev/null +++ b/libraries/shared/factories/storage/transformer_test.go @@ -0,0 +1,103 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package storage_test + +import ( + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/factories/storage" + "github.com/vulcanize/vulcanizedb/libraries/shared/mocks" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/fakes" +) + +var _ = Describe("Storage transformer", func() { + var ( + mappings *mocks.MockMappings + repository *mocks.MockStorageRepository + t storage.Transformer + ) + + BeforeEach(func() { + mappings = &mocks.MockMappings{} + repository = &mocks.MockStorageRepository{} + t = storage.Transformer{ + Address: common.Address{}, + Mappings: mappings, + Repository: repository, + } + }) + + It("returns the contract address being watched", func() { + fakeAddress := common.HexToAddress("0x12345") + t.Address = fakeAddress + + Expect(t.ContractAddress()).To(Equal(fakeAddress)) + }) + + It("looks up metadata for storage key", func() { + t.Execute(utils.StorageDiffRow{}) + + Expect(mappings.LookupCalled).To(BeTrue()) + }) + + It("returns error if lookup fails", func() { + mappings.LookupErr = fakes.FakeError + + err := t.Execute(utils.StorageDiffRow{}) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("creates storage row with decoded data", func() { + fakeMetadata := utils.StorageValueMetadata{Type: utils.Address} + mappings.Metadata = fakeMetadata + rawValue := common.HexToAddress("0x12345") + fakeBlockNumber := 123 + fakeBlockHash := "0x67890" + fakeRow := utils.StorageDiffRow{ + Contract: common.Address{}, + BlockHash: common.HexToHash(fakeBlockHash), + BlockHeight: fakeBlockNumber, + StorageKey: common.Hash{}, + StorageValue: rawValue.Hash(), + } + + err := t.Execute(fakeRow) + + Expect(err).NotTo(HaveOccurred()) + Expect(repository.PassedBlockNumber).To(Equal(fakeBlockNumber)) + Expect(repository.PassedBlockHash).To(Equal(common.HexToHash(fakeBlockHash).Hex())) + Expect(repository.PassedMetadata).To(Equal(fakeMetadata)) + Expect(repository.PassedValue.(string)).To(Equal(rawValue.Hex())) + }) + + It("returns error if creating row fails", func() { + rawValue := common.HexToAddress("0x12345") + fakeMetadata := utils.StorageValueMetadata{Type: utils.Address} + mappings.Metadata = fakeMetadata + repository.CreateErr = fakes.FakeError + + err := t.Execute(utils.StorageDiffRow{StorageValue: rawValue.Hash()}) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) +}) diff --git a/libraries/shared/fetcher/fetcher_suite_test.go b/libraries/shared/fetcher/fetcher_suite_test.go new file mode 100644 index 00000000..e1bb832a --- /dev/null +++ b/libraries/shared/fetcher/fetcher_suite_test.go @@ -0,0 +1,35 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package fetcher_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" + "io/ioutil" +) + +func TestFactories(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Fetcher Suite") +} + +var _ = BeforeSuite(func() { + log.SetOutput(ioutil.Discard) +}) diff --git a/libraries/shared/fetcher/log_fetcher.go b/libraries/shared/fetcher/log_fetcher.go new file mode 100644 index 00000000..a231b3de --- /dev/null +++ b/libraries/shared/fetcher/log_fetcher.go @@ -0,0 +1,58 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package fetcher + +import ( + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/pkg/core" +) + +type LogFetcher interface { + FetchLogs(contractAddresses []common.Address, topics []common.Hash, missingHeader core.Header) ([]types.Log, error) +} + +type Fetcher struct { + blockChain core.BlockChain +} + +func NewFetcher(blockchain core.BlockChain) *Fetcher { + return &Fetcher{ + blockChain: blockchain, + } +} + +// Checks all topic0s, on all addresses, fetching matching logs for the given header +func (fetcher Fetcher) FetchLogs(addresses []common.Address, topic0s []common.Hash, header core.Header) ([]types.Log, error) { + blockHash := common.HexToHash(header.Hash) + query := ethereum.FilterQuery{ + BlockHash: &blockHash, + Addresses: addresses, + // Search for _any_ of the topics in topic0 position; see docs on `FilterQuery` + Topics: [][]common.Hash{topic0s}, + } + + logs, err := fetcher.blockChain.GetEthLogsWithCustomQuery(query) + if err != nil { + // TODO review aggregate fetching error handling + return []types.Log{}, err + } + + return logs, nil +} diff --git a/libraries/shared/fetcher/log_fetcher_test.go b/libraries/shared/fetcher/log_fetcher_test.go new file mode 100644 index 00000000..1a41a5a3 --- /dev/null +++ b/libraries/shared/fetcher/log_fetcher_test.go @@ -0,0 +1,70 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package fetcher_test + +import ( + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + fetch "github.com/vulcanize/vulcanizedb/libraries/shared/fetcher" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" +) + +var _ = Describe("Fetcher", func() { + Describe("FetchLogs", func() { + It("fetches logs based on the given query", func() { + blockChain := fakes.NewMockBlockChain() + fetcher := fetch.NewFetcher(blockChain) + header := fakes.FakeHeader + + addresses := []common.Address{ + common.HexToAddress("0xfakeAddress"), + common.HexToAddress("0xanotherFakeAddress"), + } + + topicZeros := []common.Hash{common.BytesToHash([]byte{1, 2, 3, 4, 5})} + + _, err := fetcher.FetchLogs(addresses, topicZeros, header) + + address1 := common.HexToAddress("0xfakeAddress") + address2 := common.HexToAddress("0xanotherFakeAddress") + Expect(err).NotTo(HaveOccurred()) + + blockHash := common.HexToHash(header.Hash) + expectedQuery := ethereum.FilterQuery{ + BlockHash: &blockHash, + Addresses: []common.Address{address1, address2}, + Topics: [][]common.Hash{topicZeros}, + } + blockChain.AssertGetEthLogsWithCustomQueryCalledWith(expectedQuery) + }) + + It("returns an error if fetching the logs fails", func() { + blockChain := fakes.NewMockBlockChain() + blockChain.SetGetEthLogsWithCustomQueryErr(fakes.FakeError) + fetcher := fetch.NewFetcher(blockChain) + + _, err := fetcher.FetchLogs([]common.Address{}, []common.Hash{}, core.Header{}) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + }) +}) diff --git a/libraries/shared/mocks/converter.go b/libraries/shared/mocks/converter.go new file mode 100644 index 00000000..01b0e4a6 --- /dev/null +++ b/libraries/shared/mocks/converter.go @@ -0,0 +1,58 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mocks + +import ( + "github.com/ethereum/go-ethereum/core/types" +) + +type MockConverter struct { + ToEntitiesError error + PassedContractAddresses []string + ToModelsError error + entityConverterError error + modelConverterError error + ContractAbi string + LogsToConvert []types.Log + EntitiesToConvert []interface{} + EntitiesToReturn []interface{} + ModelsToReturn []interface{} + ToEntitiesCalledCounter int + ToModelsCalledCounter int +} + +func (converter *MockConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) { + for _, log := range ethLogs { + converter.PassedContractAddresses = append(converter.PassedContractAddresses, log.Address.Hex()) + } + converter.ContractAbi = contractAbi + converter.LogsToConvert = ethLogs + return converter.EntitiesToReturn, converter.ToEntitiesError +} + +func (converter *MockConverter) ToModels(entities []interface{}) ([]interface{}, error) { + converter.EntitiesToConvert = entities + return converter.ModelsToReturn, converter.ToModelsError +} + +func (converter *MockConverter) SetToEntityConverterError(err error) { + converter.entityConverterError = err +} + +func (c *MockConverter) SetToModelConverterError(err error) { + c.modelConverterError = err +} diff --git a/examples/generic/config.go b/libraries/shared/mocks/log_note_converter.go similarity index 51% rename from examples/generic/config.go rename to libraries/shared/mocks/log_note_converter.go index a185980d..7125fc5e 100644 --- a/examples/generic/config.go +++ b/libraries/shared/mocks/log_note_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,28 +14,29 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package generic +package mocks import ( - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" + "github.com/ethereum/go-ethereum/core/types" ) -var DaiConfig = shared.ContractConfig{ - Address: constants.DaiContractAddress, - Abi: constants.DaiAbiString, - FirstBlock: int64(4752008), - LastBlock: -1, - Name: "Dai", - Filters: constants.DaiERC20Filters, +type MockLogNoteConverter struct { + err error + returnModels []interface{} + PassedLogs []types.Log + ToModelsCalledCounter int } -var TusdConfig = shared.ContractConfig{ - Address: constants.TusdContractAddress, - Owner: constants.TusdContractOwner, - Abi: constants.TusdAbiString, - FirstBlock: int64(5197514), - LastBlock: -1, - Name: "Tusd", - Filters: constants.TusdGenericFilters, +func (converter *MockLogNoteConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) { + converter.PassedLogs = ethLogs + converter.ToModelsCalledCounter++ + return converter.returnModels, converter.err +} + +func (converter *MockLogNoteConverter) SetConverterError(e error) { + converter.err = e +} + +func (converter *MockLogNoteConverter) SetReturnModels(models []interface{}) { + converter.returnModels = models } diff --git a/examples/erc20_watcher/event_triggered/dai/entity.go b/libraries/shared/mocks/mappings.go similarity index 58% rename from examples/erc20_watcher/event_triggered/dai/entity.go rename to libraries/shared/mocks/mappings.go index c35931ac..d2f681bb 100644 --- a/examples/erc20_watcher/event_triggered/dai/entity.go +++ b/libraries/shared/mocks/mappings.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,30 +14,26 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package dai +package mocks import ( - "math/big" - "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) -type TransferEntity struct { - TokenName string - TokenAddress common.Address - Src common.Address - Dst common.Address - Wad *big.Int - Block int64 - TxHash string +type MockMappings struct { + Metadata utils.StorageValueMetadata + LookupCalled bool + LookupErr error } -type ApprovalEntity struct { - TokenName string - TokenAddress common.Address - Src common.Address - Guy common.Address - Wad *big.Int - Block int64 - TxHash string +func (mappings *MockMappings) Lookup(key common.Hash) (utils.StorageValueMetadata, error) { + mappings.LookupCalled = true + return mappings.Metadata, mappings.LookupErr +} + +func (*MockMappings) SetDB(db *postgres.DB) { + panic("implement me") } diff --git a/libraries/shared/mocks/mock_watcher_repository.go b/libraries/shared/mocks/mock_watcher_repository.go new file mode 100644 index 00000000..fb0da575 --- /dev/null +++ b/libraries/shared/mocks/mock_watcher_repository.go @@ -0,0 +1,69 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mocks + +import ( + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type MockWatcherRepository struct { + ReturnCheckedColumnNames []string + GetCheckedColumnNamesError error + GetCheckedColumnNamesCalled bool + + ReturnNotCheckedSQL string + CreateNotCheckedSQLCalled bool + + ReturnMissingHeaders []core.Header + MissingHeadersError error + MissingHeadersCalled bool +} + +func (repository *MockWatcherRepository) GetCheckedColumnNames(db *postgres.DB) ([]string, error) { + repository.GetCheckedColumnNamesCalled = true + if repository.GetCheckedColumnNamesError != nil { + return []string{}, repository.GetCheckedColumnNamesError + } + + return repository.ReturnCheckedColumnNames, nil +} + +func (repository *MockWatcherRepository) SetCheckedColumnNames(checkedColumnNames []string) { + repository.ReturnCheckedColumnNames = checkedColumnNames +} + +func (repository *MockWatcherRepository) CreateNotCheckedSQL(boolColumns []string) string { + repository.CreateNotCheckedSQLCalled = true + return repository.ReturnNotCheckedSQL +} + +func (repository *MockWatcherRepository) SetNotCheckedSQL(notCheckedSql string) { + repository.ReturnNotCheckedSQL = notCheckedSql +} + +func (repository *MockWatcherRepository) MissingHeaders(startingBlockNumber int64, endingBlockNumber int64, db *postgres.DB, notCheckedSQL string) ([]core.Header, error) { + if repository.MissingHeadersError != nil { + return []core.Header{}, repository.MissingHeadersError + } + repository.MissingHeadersCalled = true + return repository.ReturnMissingHeaders, nil +} + +func (repository *MockWatcherRepository) SetMissingHeaders(headers []core.Header) { + repository.ReturnMissingHeaders = headers +} diff --git a/libraries/shared/mocks/repository.go b/libraries/shared/mocks/repository.go new file mode 100644 index 00000000..1c3efe13 --- /dev/null +++ b/libraries/shared/mocks/repository.go @@ -0,0 +1,98 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mocks + +import ( + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type MockRepository struct { + createError error + markHeaderCheckedError error + MarkHeaderCheckedPassedHeaderIDs []int64 + CreatedHeaderIds []int64 + missingHeaders []core.Header + allHeaders []core.Header + missingHeadersError error + PassedStartingBlockNumber int64 + PassedEndingBlockNumber int64 + PassedHeaderID int64 + PassedModels []interface{} + SetDbCalled bool + CreateCalledCounter int +} + +func (repository *MockRepository) Create(headerID int64, models []interface{}) error { + repository.PassedHeaderID = headerID + repository.PassedModels = models + repository.CreatedHeaderIds = append(repository.CreatedHeaderIds, headerID) + repository.CreateCalledCounter++ + + return repository.createError +} + +func (repository *MockRepository) MarkHeaderChecked(headerID int64) error { + repository.MarkHeaderCheckedPassedHeaderIDs = append(repository.MarkHeaderCheckedPassedHeaderIDs, headerID) + return repository.markHeaderCheckedError +} + +func (repository *MockRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { + repository.PassedStartingBlockNumber = startingBlockNumber + repository.PassedEndingBlockNumber = endingBlockNumber + return repository.missingHeaders, repository.missingHeadersError +} + +func (repository *MockRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { + repository.PassedStartingBlockNumber = startingBlockNumber + repository.PassedEndingBlockNumber = endingBlockNumber + return repository.allHeaders, nil +} + +func (repository *MockRepository) SetDB(db *postgres.DB) { + repository.SetDbCalled = true +} + +func (repository *MockRepository) SetMissingHeadersError(e error) { + repository.missingHeadersError = e +} + +func (repository *MockRepository) SetAllHeaders(headers []core.Header) { + repository.allHeaders = headers +} + +func (repository *MockRepository) SetMissingHeaders(headers []core.Header) { + repository.missingHeaders = headers +} + +func (repository *MockRepository) SetMarkHeaderCheckedError(e error) { + repository.markHeaderCheckedError = e +} + +func (repository *MockRepository) SetCreateError(e error) { + repository.createError = e +} + +func (repository *MockRepository) AssertMarkHeaderCheckedCalledWith(i int64) { + Expect(repository.MarkHeaderCheckedPassedHeaderIDs).To(ContainElement(i)) +} + +func (repository *MockRepository) AssertMarkHeaderCheckedNotCalled() { + Expect(len(repository.MarkHeaderCheckedPassedHeaderIDs)).To(Equal(0)) +} diff --git a/pkg/omni/shared/poller/poller_suite_test.go b/libraries/shared/mocks/storage_queue.go similarity index 70% rename from pkg/omni/shared/poller/poller_suite_test.go rename to libraries/shared/mocks/storage_queue.go index 9a2ea847..fa44c474 100644 --- a/pkg/omni/shared/poller/poller_suite_test.go +++ b/libraries/shared/mocks/storage_queue.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,22 +14,18 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package poller_test +package mocks import ( - "io/ioutil" - "log" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" ) -func TestPoller(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Poller Suite Test") +type MockStorageQueue struct { + AddCalled bool + AddError error } -var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) -}) +func (queue *MockStorageQueue) Add(row utils.StorageDiffRow) error { + queue.AddCalled = true + return queue.AddError +} diff --git a/libraries/shared/mocks/storage_repository.go b/libraries/shared/mocks/storage_repository.go new file mode 100644 index 00000000..c4e351be --- /dev/null +++ b/libraries/shared/mocks/storage_repository.go @@ -0,0 +1,42 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mocks + +import ( + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type MockStorageRepository struct { + CreateErr error + PassedBlockNumber int + PassedBlockHash string + PassedMetadata utils.StorageValueMetadata + PassedValue interface{} +} + +func (repository *MockStorageRepository) Create(blockNumber int, blockHash string, metadata utils.StorageValueMetadata, value interface{}) error { + repository.PassedBlockNumber = blockNumber + repository.PassedBlockHash = blockHash + repository.PassedMetadata = metadata + repository.PassedValue = value + return repository.CreateErr +} + +func (*MockStorageRepository) SetDB(db *postgres.DB) { + panic("implement me") +} diff --git a/libraries/shared/mocks/storage_transformer.go b/libraries/shared/mocks/storage_transformer.go new file mode 100644 index 00000000..a2140de0 --- /dev/null +++ b/libraries/shared/mocks/storage_transformer.go @@ -0,0 +1,44 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mocks + +import ( + "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type MockStorageTransformer struct { + Address common.Address + ExecuteErr error + PassedRow utils.StorageDiffRow +} + +func (transformer *MockStorageTransformer) Execute(row utils.StorageDiffRow) error { + transformer.PassedRow = row + return transformer.ExecuteErr +} + +func (transformer *MockStorageTransformer) ContractAddress() common.Address { + return transformer.Address +} + +func (transformer *MockStorageTransformer) FakeTransformerInitializer(db *postgres.DB) transformer.StorageTransformer { + return transformer +} diff --git a/libraries/shared/mocks/transformer.go b/libraries/shared/mocks/transformer.go new file mode 100644 index 00000000..cf3e00e0 --- /dev/null +++ b/libraries/shared/mocks/transformer.go @@ -0,0 +1,62 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package mocks + +import ( + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type MockTransformer struct { + ExecuteWasCalled bool + ExecuteError error + PassedLogs []types.Log + PassedHeader core.Header + config shared_t.EventTransformerConfig +} + +func (mh *MockTransformer) Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error { + if mh.ExecuteError != nil { + return mh.ExecuteError + } + mh.ExecuteWasCalled = true + mh.PassedLogs = logs + mh.PassedHeader = header + return nil +} + +func (mh *MockTransformer) GetConfig() shared_t.EventTransformerConfig { + return mh.config +} + +func (mh *MockTransformer) SetTransformerConfig(config shared_t.EventTransformerConfig) { + mh.config = config +} + +func (mh *MockTransformer) FakeTransformerInitializer(db *postgres.DB) shared_t.EventTransformer { + return mh +} + +var FakeTransformerConfig = shared_t.EventTransformerConfig{ + TransformerName: "FakeTransformer", + ContractAddresses: []string{"FakeAddress"}, + Topic: "FakeTopic", +} diff --git a/libraries/shared/repository/repository.go b/libraries/shared/repository/repository.go new file mode 100644 index 00000000..bab8aa9d --- /dev/null +++ b/libraries/shared/repository/repository.go @@ -0,0 +1,157 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package repository + +import ( + "bytes" + "database/sql/driver" + "fmt" + "github.com/jmoiron/sqlx" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +func MarkHeaderChecked(headerID int64, db *postgres.DB, checkedHeadersColumn string) error { + _, err := db.Exec(`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) + VALUES ($1, $2) + ON CONFLICT (header_id) DO + UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1) + return err +} + +func MarkHeaderCheckedInTransaction(headerID int64, tx *sqlx.Tx, checkedHeadersColumn string) error { + _, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) + VALUES ($1, $2) + ON CONFLICT (header_id) DO + UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1) + return err +} + +// Treats a header as missing if it's not in the headers table, or not checked for some log type +func MissingHeaders(startingBlockNumber, endingBlockNumber int64, db *postgres.DB, notCheckedSQL string) ([]core.Header, error) { + var result []core.Header + var query string + var err error + + if endingBlockNumber == -1 { + query = `SELECT headers.id, headers.block_number, headers.hash FROM headers + LEFT JOIN checked_headers on headers.id = header_id + WHERE (header_id ISNULL OR ` + notCheckedSQL + `) + AND headers.block_number >= $1 + AND headers.eth_node_fingerprint = $2` + err = db.Select(&result, query, startingBlockNumber, db.Node.ID) + } else { + query = `SELECT headers.id, headers.block_number, headers.hash FROM headers + LEFT JOIN checked_headers on headers.id = header_id + WHERE (header_id ISNULL OR ` + notCheckedSQL + `) + AND headers.block_number >= $1 + AND headers.block_number <= $2 + AND headers.eth_node_fingerprint = $3` + err = db.Select(&result, query, startingBlockNumber, endingBlockNumber, db.Node.ID) + } + + return result, err +} + +func RecheckHeaders(startingBlockNumber, endingBlockNumber int64, db *postgres.DB, checkedHeadersColumn string) ([]core.Header, error) { + var result []core.Header + var query string + var err error + + if endingBlockNumber == -1 { + query = `SELECT headers.id, headers.block_number, headers.hash FROM headers + LEFT JOIN checked_headers on headers.id = header_id + WHERE ` + checkedHeadersColumn + ` between 1 and ` + constants.RecheckHeaderCap + ` + AND headers.block_number >= $1 + AND headers.eth_node_fingerprint = $2` + err = db.Select(&result, query, startingBlockNumber, db.Node.ID) + } else { + query = `SELECT headers.id, headers.block_number, headers.hash FROM headers + LEFT JOIN checked_headers on headers.id = header_id + WHERE ` + checkedHeadersColumn + ` between 1 and ` + constants.RecheckHeaderCap + ` + AND headers.block_number >= $1 + AND headers.block_number <= $2 + AND headers.eth_node_fingerprint = $3` + err = db.Select(&result, query, startingBlockNumber, endingBlockNumber, db.Node.ID) + } + + return result, err +} + +func GetCheckedColumnNames(db *postgres.DB) ([]string, error) { + // Query returns `[]driver.Value`, nullable polymorphic interface + var queryResult []driver.Value + columnNamesQuery := + `SELECT column_name FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'checked_headers' + AND column_name ~ '_checked';` + + err := db.Select(&queryResult, columnNamesQuery) + if err != nil { + return []string{}, err + } + + // Transform column names from `driver.Value` to strings + var columnNames []string + for _, result := range queryResult { + if columnName, ok := result.(string); ok { + columnNames = append(columnNames, columnName) + } else { + return []string{}, fmt.Errorf("incorrect value for checked_headers column name") + } + } + + return columnNames, nil +} + +// Builds a SQL string that checks if any column value is 0, given the column names. +// Defaults to FALSE when no columns are provided. +// Ex: ["columnA", "columnB"] => "NOT (columnA!=0 AND columnB!=0)" +// [] => "FALSE" +func CreateNotCheckedSQL(boolColumns []string, recheckHeaders constants.TransformerExecution) string { + + var result bytes.Buffer + + if len(boolColumns) == 0 { + return "FALSE" + } + + result.WriteString("NOT (") + + // Loop excluding last column name + for _, column := range boolColumns[:len(boolColumns)-1] { + + if recheckHeaders { + result.WriteString(fmt.Sprintf("%v>=%s AND ", column, constants.RecheckHeaderCap)) + } else { + result.WriteString(fmt.Sprintf("%v!=0 AND ", column)) + } + } + + // No trailing "OR" for the last column name + if recheckHeaders { + result.WriteString(fmt.Sprintf("%v>=%s)", boolColumns[len(boolColumns)-1], constants.RecheckHeaderCap)) + } else { + result.WriteString(fmt.Sprintf("%v!=0)", boolColumns[len(boolColumns)-1])) + + } + + return result.String() +} diff --git a/libraries/shared/repository/repository_suite_test.go b/libraries/shared/repository/repository_suite_test.go new file mode 100644 index 00000000..d934f9f8 --- /dev/null +++ b/libraries/shared/repository/repository_suite_test.go @@ -0,0 +1,35 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package repository_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" + "io/ioutil" +) + +func TestFactories(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Repository Suite") +} + +var _ = BeforeSuite(func() { + log.SetOutput(ioutil.Discard) +}) diff --git a/libraries/shared/repository/repository_test.go b/libraries/shared/repository/repository_test.go new file mode 100644 index 00000000..ccf6257f --- /dev/null +++ b/libraries/shared/repository/repository_test.go @@ -0,0 +1,325 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package repository_test + +import ( + "fmt" + "math/rand" + "strconv" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + shared "github.com/vulcanize/vulcanizedb/libraries/shared/repository" + r2 "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/repository" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" + "github.com/vulcanize/vulcanizedb/pkg/fakes" + "github.com/vulcanize/vulcanizedb/test_config" +) + +var _ = Describe("Repository", func() { + Describe("MarkHeaderChecked", func() { + var ( + checkedHeadersColumn string + db *postgres.DB + ) + + BeforeEach(func() { + db = test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + + checkedHeadersColumn = "test_column_checked" + _, migrateErr := db.Exec(`ALTER TABLE public.checked_headers + ADD COLUMN ` + checkedHeadersColumn + ` integer`) + Expect(migrateErr).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + _, cleanupMigrateErr := db.Exec(`ALTER TABLE public.checked_headers DROP COLUMN ` + checkedHeadersColumn) + Expect(cleanupMigrateErr).NotTo(HaveOccurred()) + }) + + It("marks passed column as checked for passed header", func() { + headerRepository := repositories.NewHeaderRepository(db) + headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) + Expect(headerErr).NotTo(HaveOccurred()) + + err := shared.MarkHeaderChecked(headerID, db, checkedHeadersColumn) + + Expect(err).NotTo(HaveOccurred()) + var checkedCount int + fetchErr := db.Get(&checkedCount, `SELECT `+checkedHeadersColumn+` FROM public.checked_headers LIMIT 1`) + Expect(fetchErr).NotTo(HaveOccurred()) + Expect(checkedCount).To(Equal(1)) + }) + }) + + Describe("MarkHeaderCheckedInTransaction", func() { + var ( + checkedHeadersColumn string + db *postgres.DB + ) + + BeforeEach(func() { + db = test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + + checkedHeadersColumn = "test_column_checked" + _, migrateErr := db.Exec(`ALTER TABLE public.checked_headers + ADD COLUMN ` + checkedHeadersColumn + ` integer`) + Expect(migrateErr).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + _, cleanupMigrateErr := db.Exec(`ALTER TABLE public.checked_headers DROP COLUMN ` + checkedHeadersColumn) + Expect(cleanupMigrateErr).NotTo(HaveOccurred()) + }) + + It("marks passed column as checked for passed header within a passed transaction", func() { + headerRepository := repositories.NewHeaderRepository(db) + headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) + Expect(headerErr).NotTo(HaveOccurred()) + tx, txErr := db.Beginx() + Expect(txErr).NotTo(HaveOccurred()) + + err := shared.MarkHeaderCheckedInTransaction(headerID, tx, checkedHeadersColumn) + + Expect(err).NotTo(HaveOccurred()) + commitErr := tx.Commit() + Expect(commitErr).NotTo(HaveOccurred()) + var checkedCount int + fetchErr := db.Get(&checkedCount, `SELECT `+checkedHeadersColumn+` FROM public.checked_headers LIMIT 1`) + Expect(fetchErr).NotTo(HaveOccurred()) + Expect(checkedCount).To(Equal(1)) + }) + }) + + Describe("MissingHeaders", func() { + var ( + db *postgres.DB + headerRepository datastore.HeaderRepository + startingBlockNumber int64 + endingBlockNumber int64 + eventSpecificBlockNumber int64 + blockNumbers []int64 + headerIDs []int64 + notCheckedSQL string + err error + hr r2.HeaderRepository + ) + + BeforeEach(func() { + db = test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + headerRepository = repositories.NewHeaderRepository(db) + hr = r2.NewHeaderRepository(db) + hr.AddCheckColumns(getExpectedColumnNames()) + + columnNames, err := shared.GetCheckedColumnNames(db) + Expect(err).NotTo(HaveOccurred()) + notCheckedSQL = shared.CreateNotCheckedSQL(columnNames, constants.HeaderMissing) + + startingBlockNumber = rand.Int63() + eventSpecificBlockNumber = startingBlockNumber + 1 + endingBlockNumber = startingBlockNumber + 2 + outOfRangeBlockNumber := endingBlockNumber + 1 + + blockNumbers = []int64{startingBlockNumber, eventSpecificBlockNumber, endingBlockNumber, outOfRangeBlockNumber} + + headerIDs = []int64{} + for _, n := range blockNumbers { + headerID, err := headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) + headerIDs = append(headerIDs, headerID) + Expect(err).NotTo(HaveOccurred()) + } + }) + + AfterEach(func() { + test_config.CleanCheckedHeadersTable(db, getExpectedColumnNames()) + }) + + It("only treats headers as checked if the event specific logs have been checked", func() { + _, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerIDs[1]) + Expect(err).NotTo(HaveOccurred()) + + headers, err := shared.MissingHeaders(startingBlockNumber, endingBlockNumber, db, notCheckedSQL) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(headers)).To(Equal(3)) + Expect(headers[0].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber))) + Expect(headers[1].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber))) + Expect(headers[2].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber))) + }) + + It("only returns headers associated with the current node", func() { + dbTwo := test_config.NewTestDB(core.Node{ID: "second"}) + headerRepositoryTwo := repositories.NewHeaderRepository(dbTwo) + for _, n := range blockNumbers { + _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n + 10)) + Expect(err).NotTo(HaveOccurred()) + } + + Expect(err).NotTo(HaveOccurred()) + nodeOneMissingHeaders, err := shared.MissingHeaders(startingBlockNumber, endingBlockNumber, db, notCheckedSQL) + Expect(err).NotTo(HaveOccurred()) + Expect(len(nodeOneMissingHeaders)).To(Equal(3)) + Expect(nodeOneMissingHeaders[0].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(eventSpecificBlockNumber), Equal(endingBlockNumber))) + Expect(nodeOneMissingHeaders[1].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(eventSpecificBlockNumber), Equal(endingBlockNumber))) + Expect(nodeOneMissingHeaders[2].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(startingBlockNumber), Equal(eventSpecificBlockNumber), Equal(endingBlockNumber))) + + nodeTwoMissingHeaders, err := shared.MissingHeaders(startingBlockNumber, endingBlockNumber+10, dbTwo, notCheckedSQL) + Expect(err).NotTo(HaveOccurred()) + Expect(len(nodeTwoMissingHeaders)).To(Equal(3)) + Expect(nodeTwoMissingHeaders[0].BlockNumber).To(Or(Equal(startingBlockNumber+10), Equal(eventSpecificBlockNumber+10), Equal(endingBlockNumber+10))) + Expect(nodeTwoMissingHeaders[1].BlockNumber).To(Or(Equal(startingBlockNumber+10), Equal(eventSpecificBlockNumber+10), Equal(endingBlockNumber+10))) + }) + }) + + Describe("RecheckHeaders", func() { + var ( + checkedHeadersColumn string + db *postgres.DB + headerOneID, headerTwoID, headerThreeID, headerFourID int64 + headerOneErr, headerTwoErr, headerThreeErr, headerFourErr error + ) + + BeforeEach(func() { + db = test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + + // create header checked column + checkedHeadersColumn = "test_column_checked" + _, migrateErr := db.Exec(`ALTER TABLE public.checked_headers ADD COLUMN ` + checkedHeadersColumn + ` integer`) + Expect(migrateErr).NotTo(HaveOccurred()) + + // create headers + headerRepository := repositories.NewHeaderRepository(db) + headerOneID, headerOneErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(1)) + Expect(headerOneErr).NotTo(HaveOccurred()) + headerTwoID, headerTwoErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(2)) + Expect(headerTwoErr).NotTo(HaveOccurred()) + headerThreeID, headerThreeErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(3)) + Expect(headerThreeErr).NotTo(HaveOccurred()) + headerFourID, headerFourErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(4)) + Expect(headerFourErr).NotTo(HaveOccurred()) + + // mark every header checked at least once, with one fully rechecked (headerThree) + maxCheckCount, intConversionErr := strconv.Atoi(constants.RecheckHeaderCap) + Expect(intConversionErr).NotTo(HaveOccurred()) + _, markHeaderOneCheckedErr := db.Exec( + `INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`, + headerOneID, maxCheckCount) + Expect(markHeaderOneCheckedErr).NotTo(HaveOccurred()) + _, markHeaderTwoCheckedErr := db.Exec( + `INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`, + headerTwoID, maxCheckCount) + Expect(markHeaderTwoCheckedErr).NotTo(HaveOccurred()) + _, markHeaderThreeCheckedErr := db.Exec( + `INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`, + headerThreeID, maxCheckCount+1) + Expect(markHeaderThreeCheckedErr).NotTo(HaveOccurred()) + _, markHeaderFourCheckedErr := db.Exec( + `INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`, + headerFourID, maxCheckCount) + Expect(markHeaderFourCheckedErr).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + _, cleanupMigrateErr := db.Exec(`ALTER TABLE public.checked_headers DROP COLUMN ` + checkedHeadersColumn) + Expect(cleanupMigrateErr).NotTo(HaveOccurred()) + }) + + Describe("when no ending block number (ending block number == -1)", func() { + It("returns all headers since starting block where checked count is less than cap", func() { + headers, err := shared.RecheckHeaders(1, -1, db, checkedHeadersColumn) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(headers)).To(Equal(3)) + Expect(headers[0].Id).To(Or(Equal(headerOneID), Equal(headerTwoID), Equal(headerFourID))) + Expect(headers[1].Id).To(Or(Equal(headerOneID), Equal(headerTwoID), Equal(headerFourID))) + Expect(headers[2].Id).To(Or(Equal(headerOneID), Equal(headerTwoID), Equal(headerFourID))) + }) + }) + + Describe("when ending block number specified", func() { + It("returns headers between starting and ending block where checked count is less than cap", func() { + headers, err := shared.RecheckHeaders(1, 3, db, checkedHeadersColumn) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(headers)).To(Equal(2)) + Expect(headers[0].Id).To(Or(Equal(headerOneID), Equal(headerTwoID))) + Expect(headers[1].Id).To(Or(Equal(headerOneID), Equal(headerTwoID))) + }) + }) + }) + + Describe("GetCheckedColumnNames", func() { + It("gets the column names from checked_headers", func() { + db := test_config.NewTestDB(test_config.NewTestNode()) + hr := r2.NewHeaderRepository(db) + hr.AddCheckColumns(getExpectedColumnNames()) + test_config.CleanTestDB(db) + expectedColumnNames := getExpectedColumnNames() + actualColumnNames, err := shared.GetCheckedColumnNames(db) + Expect(err).NotTo(HaveOccurred()) + Expect(actualColumnNames).To(Equal(expectedColumnNames)) + test_config.CleanCheckedHeadersTable(db, getExpectedColumnNames()) + }) + }) + + Describe("CreateNotCheckedSQL", func() { + It("generates a correct SQL string for one column", func() { + columns := []string{"columnA"} + expected := "NOT (columnA!=0)" + actual := shared.CreateNotCheckedSQL(columns, constants.HeaderMissing) + Expect(actual).To(Equal(expected)) + }) + + It("generates a correct SQL string for several columns", func() { + columns := []string{"columnA", "columnB"} + expected := "NOT (columnA!=0 AND columnB!=0)" + actual := shared.CreateNotCheckedSQL(columns, constants.HeaderMissing) + Expect(actual).To(Equal(expected)) + }) + + It("defaults to FALSE when there are no columns", func() { + expected := "FALSE" + actual := shared.CreateNotCheckedSQL([]string{}, constants.HeaderMissing) + Expect(actual).To(Equal(expected)) + }) + + It("generates a correct SQL string for rechecking headers", func() { + columns := []string{"columnA", "columnB"} + expected := fmt.Sprintf("NOT (columnA>=%s AND columnB>=%s)", constants.RecheckHeaderCap, constants.RecheckHeaderCap) + actual := shared.CreateNotCheckedSQL(columns, constants.HeaderRecheck) + Expect(actual).To(Equal(expected)) + }) + }) +}) + +func getExpectedColumnNames() []string { + return []string{ + "column_1_checked", + "column_2_checked", + "column_3_checked", + "column_4_checked", + } +} diff --git a/examples/erc20_watcher/every_block/transformers.go b/libraries/shared/repository/storage_repository.go similarity index 67% rename from examples/erc20_watcher/every_block/transformers.go rename to libraries/shared/repository/storage_repository.go index 8a58c2b7..f921d5aa 100644 --- a/examples/erc20_watcher/every_block/transformers.go +++ b/libraries/shared/repository/storage_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,14 +14,14 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package every_block +package repository import ( - "github.com/vulcanize/vulcanizedb/libraries/shared" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) -func ERC20EveryBlockTransformerInitializer() []shared.TransformerInitializer { - return []shared.TransformerInitializer{ - NewERC20TokenTransformer, - } +type StorageRepository interface { + Create(blockNumber int, blockHash string, metadata utils.StorageValueMetadata, value interface{}) error + SetDB(db *postgres.DB) } diff --git a/libraries/shared/storage/mappings.go b/libraries/shared/storage/mappings.go new file mode 100644 index 00000000..dcb2e3ea --- /dev/null +++ b/libraries/shared/storage/mappings.go @@ -0,0 +1,65 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package storage + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type Mappings interface { + Lookup(key common.Hash) (utils.StorageValueMetadata, error) + SetDB(db *postgres.DB) +} + +const ( + IndexZero = "0000000000000000000000000000000000000000000000000000000000000000" + IndexOne = "0000000000000000000000000000000000000000000000000000000000000001" + IndexTwo = "0000000000000000000000000000000000000000000000000000000000000002" + IndexThree = "0000000000000000000000000000000000000000000000000000000000000003" + IndexFour = "0000000000000000000000000000000000000000000000000000000000000004" + IndexFive = "0000000000000000000000000000000000000000000000000000000000000005" + IndexSix = "0000000000000000000000000000000000000000000000000000000000000006" + IndexSeven = "0000000000000000000000000000000000000000000000000000000000000007" + IndexEight = "0000000000000000000000000000000000000000000000000000000000000008" + IndexNine = "0000000000000000000000000000000000000000000000000000000000000009" + IndexTen = "000000000000000000000000000000000000000000000000000000000000000a" + IndexEleven = "000000000000000000000000000000000000000000000000000000000000000b" +) + +func GetMapping(indexOnContract, key string) common.Hash { + keyBytes := common.FromHex("0x" + key + indexOnContract) + encoded := crypto.Keccak256(keyBytes) + return common.BytesToHash(encoded) +} + +func GetNestedMapping(indexOnContract, primaryKey, secondaryKey string) common.Hash { + primaryMappingIndex := crypto.Keccak256(common.FromHex(primaryKey + indexOnContract)) + secondaryMappingIndex := crypto.Keccak256(common.FromHex(secondaryKey), primaryMappingIndex) + return common.BytesToHash(secondaryMappingIndex) +} + +func GetIncrementedKey(original common.Hash, incrementBy int64) common.Hash { + originalMappingAsInt := original.Big() + incremented := big.NewInt(0).Add(originalMappingAsInt, big.NewInt(incrementBy)) + return common.BytesToHash(incremented.Bytes()) +} diff --git a/libraries/shared/storage/mappings_test.go b/libraries/shared/storage/mappings_test.go new file mode 100644 index 00000000..f696add6 --- /dev/null +++ b/libraries/shared/storage/mappings_test.go @@ -0,0 +1,65 @@ +package storage_test + +import ( + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage" +) + +var _ = Describe("Mappings", func() { + Describe("GetMapping", func() { + It("returns the storage key for a mapping when passed the mapping's index on the contract and the desired value's key", func() { + // ex. solidity: + // mapping (bytes32 => uint) public amounts + // to access amounts, pass in the index of the mapping on the contract + the bytes32 key for the uint val being looked up + indexOfMappingOnContract := storage.IndexZero + keyForDesiredValueInMapping := "1234567890abcdef" + + storageKey := storage.GetMapping(indexOfMappingOnContract, keyForDesiredValueInMapping) + + expectedStorageKey := common.HexToHash("0xee0c1b59a3856bafbfb8730e7694c4badc271eb5f01ce4a8d7a53d8a6499676f") + Expect(storageKey).To(Equal(expectedStorageKey)) + }) + }) + + Describe("GetNestedMapping", func() { + It("returns the storage key for a nested mapping when passed the mapping's index on the contract and the desired value's keys", func() { + // ex. solidity: + // mapping (bytes32 => uint) public amounts + // mapping (address => mapping (uint => bytes32)) public addressNames + // to access addressNames, pass in the index of the mapping on the contract + the address and uint keys for the bytes32 val being looked up + indexOfMappingOnContract := storage.IndexOne + keyForOuterMapping := "1234567890abcdef" + keyForInnerMapping := "123" + + storageKey := storage.GetNestedMapping(indexOfMappingOnContract, keyForOuterMapping, keyForInnerMapping) + + expectedStorageKey := common.HexToHash("0x82113529f6cd61061d1a6f0de53f2bdd067a1addd3d2b46be50a99abfcdb1661") + Expect(storageKey).To(Equal(expectedStorageKey)) + }) + }) + + Describe("GetIncrementedKey", func() { + It("returns the storage key for later values sharing an index on the contract with other earlier values", func() { + // ex. solidity: + // mapping (bytes32 => uint) public amounts + // mapping (address => mapping (uint => bytes32)) public addressNames + // struct Data { + // uint256 quantity; + // uint256 quality; + // } + // mapping (bytes32 => Data) public itemData; + // to access quality from itemData, pass in the storage key for the zero-indexed value (quantity) + the number of increments required. + // (For "quality", we must increment the storage key for the corresponding "quantity" by 1). + indexOfMappingOnContract := storage.IndexTwo + keyForDesiredValueInMapping := "1234567890abcdef" + storageKeyForFirstPropertyOnStruct := storage.GetMapping(indexOfMappingOnContract, keyForDesiredValueInMapping) + + storageKey := storage.GetIncrementedKey(storageKeyForFirstPropertyOnStruct, 1) + + expectedStorageKey := common.HexToHash("0x69b38749f0a8ed5d505c8474f7fb62c7828aad8a7627f1c67e07af1d2368cad4") + Expect(storageKey).To(Equal(expectedStorageKey)) + }) + }) +}) diff --git a/libraries/shared/storage/storage_queue.go b/libraries/shared/storage/storage_queue.go new file mode 100644 index 00000000..a077a4f9 --- /dev/null +++ b/libraries/shared/storage/storage_queue.go @@ -0,0 +1,42 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package storage + +import ( + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type IStorageQueue interface { + Add(row utils.StorageDiffRow) error +} + +type StorageQueue struct { + db *postgres.DB +} + +func NewStorageQueue(db *postgres.DB) StorageQueue { + return StorageQueue{db: db} +} + +func (queue StorageQueue) Add(row utils.StorageDiffRow) error { + _, err := queue.db.Exec(`INSERT INTO public.queued_storage (contract, + block_hash, block_height, storage_key, storage_value) VALUES + ($1, $2, $3, $4, $5)`, row.Contract.Bytes(), row.BlockHash.Bytes(), + row.BlockHeight, row.StorageKey.Bytes(), row.StorageValue.Bytes()) + return err +} diff --git a/libraries/shared/storage/storage_queue_test.go b/libraries/shared/storage/storage_queue_test.go new file mode 100644 index 00000000..9157fcda --- /dev/null +++ b/libraries/shared/storage/storage_queue_test.go @@ -0,0 +1,33 @@ +package storage_test + +import ( + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/test_config" +) + +var _ = Describe("Storage queue", func() { + It("adds a storage row to the db", func() { + row := utils.StorageDiffRow{ + Contract: common.HexToAddress("0x123456"), + BlockHash: common.HexToHash("0x678901"), + BlockHeight: 987, + StorageKey: common.HexToHash("0x654321"), + StorageValue: common.HexToHash("0x198765"), + } + db := test_config.NewTestDB(test_config.NewTestNode()) + queue := storage.NewStorageQueue(db) + + addErr := queue.Add(row) + + Expect(addErr).NotTo(HaveOccurred()) + var result utils.StorageDiffRow + getErr := db.Get(&result, `SELECT contract, block_hash, block_height, storage_key, storage_value FROM public.queued_storage`) + Expect(getErr).NotTo(HaveOccurred()) + Expect(result).To(Equal(row)) + }) +}) diff --git a/libraries/shared/storage/storage_suite_test.go b/libraries/shared/storage/storage_suite_test.go new file mode 100644 index 00000000..a24f35d3 --- /dev/null +++ b/libraries/shared/storage/storage_suite_test.go @@ -0,0 +1,35 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package storage_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" + "io/ioutil" +) + +func TestFactories(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Storage Suite") +} + +var _ = BeforeSuite(func() { + log.SetOutput(ioutil.Discard) +}) diff --git a/libraries/shared/storage/utils/decoder.go b/libraries/shared/storage/utils/decoder.go new file mode 100644 index 00000000..1a6ac31c --- /dev/null +++ b/libraries/shared/storage/utils/decoder.go @@ -0,0 +1,53 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +func Decode(row StorageDiffRow, metadata StorageValueMetadata) (interface{}, error) { + switch metadata.Type { + case Uint256: + return decodeUint256(row.StorageValue.Bytes()), nil + case Uint48: + return decodeUint48(row.StorageValue.Bytes()), nil + case Address: + return decodeAddress(row.StorageValue.Bytes()), nil + case Bytes32: + return row.StorageValue.Hex(), nil + default: + panic(fmt.Sprintf("can't decode unknown type: %d", metadata.Type)) + } +} + +func decodeUint256(raw []byte) string { + n := big.NewInt(0).SetBytes(raw) + return n.String() +} + +func decodeUint48(raw []byte) string { + n := big.NewInt(0).SetBytes(raw) + return n.String() +} + +func decodeAddress(raw []byte) string { + return common.BytesToAddress(raw).Hex() +} diff --git a/libraries/shared/storage/utils/decoder_test.go b/libraries/shared/storage/utils/decoder_test.go new file mode 100644 index 00000000..9e7bb65a --- /dev/null +++ b/libraries/shared/storage/utils/decoder_test.go @@ -0,0 +1,62 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils_test + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" +) + +var _ = Describe("Storage decoder", func() { + It("decodes uint256", func() { + fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000539") + row := utils.StorageDiffRow{StorageValue: fakeInt} + metadata := utils.StorageValueMetadata{Type: utils.Uint256} + + result, err := utils.Decode(row, metadata) + + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String())) + }) + + It("decodes uint48", func() { + fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123") + row := utils.StorageDiffRow{StorageValue: fakeInt} + metadata := utils.StorageValueMetadata{Type: utils.Uint48} + + result, err := utils.Decode(row, metadata) + + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String())) + }) + + It("decodes address", func() { + fakeAddress := common.HexToAddress("0x12345") + row := utils.StorageDiffRow{StorageValue: fakeAddress.Hash()} + metadata := utils.StorageValueMetadata{Type: utils.Address} + + result, err := utils.Decode(row, metadata) + + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(fakeAddress.Hex())) + }) +}) diff --git a/libraries/shared/storage/utils/errors.go b/libraries/shared/storage/utils/errors.go new file mode 100644 index 00000000..0c87c642 --- /dev/null +++ b/libraries/shared/storage/utils/errors.go @@ -0,0 +1,53 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils + +import ( + "fmt" +) + +type ErrContractNotFound struct { + Contract string +} + +func (e ErrContractNotFound) Error() string { + return fmt.Sprintf("transformer not found for contract: %s", e.Contract) +} + +type ErrMetadataMalformed struct { + MissingData Key +} + +func (e ErrMetadataMalformed) Error() string { + return fmt.Sprintf("storage metadata malformed: missing %s", e.MissingData) +} + +type ErrRowMalformed struct { + Length int +} + +func (e ErrRowMalformed) Error() string { + return fmt.Sprintf("storage row malformed: length %d, expected %d", e.Length, ExpectedRowLength) +} + +type ErrStorageKeyNotFound struct { + Key string +} + +func (e ErrStorageKeyNotFound) Error() string { + return fmt.Sprintf("unknown storage key: %s", e.Key) +} diff --git a/libraries/shared/storage/utils/row.go b/libraries/shared/storage/utils/row.go new file mode 100644 index 00000000..dddb4e8f --- /dev/null +++ b/libraries/shared/storage/utils/row.go @@ -0,0 +1,50 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils + +import ( + "strconv" + + "github.com/ethereum/go-ethereum/common" +) + +const ExpectedRowLength = 5 + +type StorageDiffRow struct { + Contract common.Address + BlockHash common.Hash `db:"block_hash"` + BlockHeight int `db:"block_height"` + StorageKey common.Hash `db:"storage_key"` + StorageValue common.Hash `db:"storage_value"` +} + +func FromStrings(csvRow []string) (StorageDiffRow, error) { + if len(csvRow) != ExpectedRowLength { + return StorageDiffRow{}, ErrRowMalformed{Length: len(csvRow)} + } + height, err := strconv.Atoi(csvRow[2]) + if err != nil { + return StorageDiffRow{}, err + } + return StorageDiffRow{ + Contract: common.HexToAddress(csvRow[0]), + BlockHash: common.HexToHash(csvRow[1]), + BlockHeight: height, + StorageKey: common.HexToHash(csvRow[3]), + StorageValue: common.HexToHash(csvRow[4]), + }, nil +} diff --git a/libraries/shared/storage/utils/row_test.go b/libraries/shared/storage/utils/row_test.go new file mode 100644 index 00000000..ffd49fbf --- /dev/null +++ b/libraries/shared/storage/utils/row_test.go @@ -0,0 +1,58 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils_test + +import ( + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" +) + +var _ = Describe("Storage row parsing", func() { + It("converts an array of strings to a row struct", func() { + contract := "0x123" + blockHash := "0x456" + blockHeight := "789" + storageKey := "0x987" + storageValue := "0x654" + data := []string{contract, blockHash, blockHeight, storageKey, storageValue} + + result, err := utils.FromStrings(data) + + Expect(err).NotTo(HaveOccurred()) + Expect(result.Contract).To(Equal(common.HexToAddress(contract))) + Expect(result.BlockHash).To(Equal(common.HexToHash(blockHash))) + Expect(result.BlockHeight).To(Equal(789)) + Expect(result.StorageKey).To(Equal(common.HexToHash(storageKey))) + Expect(result.StorageValue).To(Equal(common.HexToHash(storageValue))) + }) + + It("returns an error if row is missing data", func() { + _, err := utils.FromStrings([]string{"0x123"}) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(utils.ErrRowMalformed{Length: 1})) + }) + + It("returns error if block height malformed", func() { + _, err := utils.FromStrings([]string{"", "", "", "", ""}) + + Expect(err).To(HaveOccurred()) + }) +}) diff --git a/libraries/shared/storage/utils/utils_suite_test.go b/libraries/shared/storage/utils/utils_suite_test.go new file mode 100644 index 00000000..f77d6860 --- /dev/null +++ b/libraries/shared/storage/utils/utils_suite_test.go @@ -0,0 +1,35 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package utils_test + +import ( + "github.com/sirupsen/logrus" + "io/ioutil" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestShared(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Storage Utils Suite") +} + +var _ = BeforeSuite(func() { + logrus.SetOutput(ioutil.Discard) +}) diff --git a/examples/generic/event_triggered/tusd/transformers.go b/libraries/shared/storage/utils/value.go similarity index 63% rename from examples/generic/event_triggered/tusd/transformers.go rename to libraries/shared/storage/utils/value.go index 1bf59f49..095ff8fd 100644 --- a/examples/generic/event_triggered/tusd/transformers.go +++ b/libraries/shared/storage/utils/value.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,14 +14,29 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package tusd +package utils -import ( - "github.com/vulcanize/vulcanizedb/libraries/shared" +type ValueType int + +const ( + Uint256 ValueType = iota + Uint48 + Bytes32 + Address ) -func TusdEventTriggeredTransformerInitializer() []shared.TransformerInitializer { - return []shared.TransformerInitializer{ - NewTransformer, +type Key string + +type StorageValueMetadata struct { + Name string + Keys map[Key]string + Type ValueType +} + +func GetStorageValueMetadata(name string, keys map[Key]string, t ValueType) StorageValueMetadata { + return StorageValueMetadata{ + Name: name, + Keys: keys, + Type: t, } } diff --git a/libraries/shared/storage/utils/value_test.go b/libraries/shared/storage/utils/value_test.go new file mode 100644 index 00000000..6af20499 --- /dev/null +++ b/libraries/shared/storage/utils/value_test.go @@ -0,0 +1,22 @@ +package utils_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" +) + +var _ = Describe("Storage value metadata getter", func() { + It("returns a storage value metadata instance with corresponding fields assigned", func() { + metadataName := "fake_name" + metadataKeys := map[utils.Key]string{"key": "value"} + metadataType := utils.Uint256 + + expectedMetadata := utils.StorageValueMetadata{ + Name: metadataName, + Keys: metadataKeys, + Type: metadataType, + } + Expect(utils.GetStorageValueMetadata(metadataName, metadataKeys, metadataType)).To(Equal(expectedMetadata)) + }) +}) diff --git a/libraries/shared/test_data/generic.go b/libraries/shared/test_data/generic.go new file mode 100644 index 00000000..eb68f03a --- /dev/null +++ b/libraries/shared/test_data/generic.go @@ -0,0 +1,61 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package test_data + +import ( + "math/rand" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" +) + +type GenericModel struct{} +type GenericEntity struct{} + +var startingBlockNumber = rand.Int63() +var topic = "0x" + randomString(64) +var address = "0x" + randomString(38) + +var GenericTestLogs = []types.Log{{ + Address: common.HexToAddress(address), + Topics: []common.Hash{common.HexToHash(topic)}, + BlockNumber: uint64(startingBlockNumber), +}} + +var GenericTestConfig = transformer.EventTransformerConfig{ + TransformerName: "generic-test-transformer", + ContractAddresses: []string{address}, + ContractAbi: randomString(100), + Topic: topic, + StartingBlockNumber: startingBlockNumber, + EndingBlockNumber: startingBlockNumber + 1, +} + +func randomString(length int) string { + var seededRand = rand.New( + rand.NewSource(time.Now().UnixNano())) + charset := "abcdefghijklmnopqrstuvwxyz1234567890" + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + + return string(b) +} diff --git a/libraries/shared/transactions/syncer.go b/libraries/shared/transactions/syncer.go new file mode 100644 index 00000000..8e043dd7 --- /dev/null +++ b/libraries/shared/transactions/syncer.go @@ -0,0 +1,53 @@ +package transactions + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" +) + +type ITransactionsSyncer interface { + SyncTransactions(headerID int64, logs []types.Log) error +} + +type TransactionsSyncer struct { + BlockChain core.BlockChain + Repository datastore.HeaderRepository +} + +func NewTransactionsSyncer(db *postgres.DB, blockChain core.BlockChain) TransactionsSyncer { + repository := repositories.NewHeaderRepository(db) + return TransactionsSyncer{ + BlockChain: blockChain, + Repository: repository, + } +} + +func (syncer TransactionsSyncer) SyncTransactions(headerID int64, logs []types.Log) error { + transactionHashes := getUniqueTransactionHashes(logs) + transactions, transactionErr := syncer.BlockChain.GetTransactions(transactionHashes) + if transactionErr != nil { + return transactionErr + } + writeErr := syncer.Repository.CreateTransactions(headerID, transactions) + if writeErr != nil { + return writeErr + } + return nil +} + +func getUniqueTransactionHashes(logs []types.Log) []common.Hash { + seen := make(map[common.Hash]struct{}, len(logs)) + var result []common.Hash + for _, log := range logs { + if _, ok := seen[log.TxHash]; ok { + continue + } + seen[log.TxHash] = struct{}{} + result = append(result, log.TxHash) + } + return result +} diff --git a/libraries/shared/transactions/syncer_test.go b/libraries/shared/transactions/syncer_test.go new file mode 100644 index 00000000..53df7817 --- /dev/null +++ b/libraries/shared/transactions/syncer_test.go @@ -0,0 +1,75 @@ +package transactions_test + +import ( + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/libraries/shared/transactions" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" + "github.com/vulcanize/vulcanizedb/test_config" +) + +var _ = Describe("Transaction syncer", func() { + var ( + blockChain *fakes.MockBlockChain + syncer transactions.TransactionsSyncer + ) + + BeforeEach(func() { + db := test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + blockChain = fakes.NewMockBlockChain() + syncer = transactions.NewTransactionsSyncer(db, blockChain) + }) + + It("fetches transactions for logs", func() { + err := syncer.SyncTransactions(0, []types.Log{}) + + Expect(err).NotTo(HaveOccurred()) + Expect(blockChain.GetTransactionsCalled).To(BeTrue()) + }) + + It("only fetches transactions with unique hashes", func() { + err := syncer.SyncTransactions(0, []types.Log{{ + TxHash: fakes.FakeHash, + }, { + TxHash: fakes.FakeHash, + }}) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(blockChain.GetTransactionsPassedHashes)).To(Equal(1)) + }) + + It("returns error if fetching transactions fails", func() { + blockChain.GetTransactionsError = fakes.FakeError + + err := syncer.SyncTransactions(0, []types.Log{}) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("passes transactions to repository for persistence", func() { + blockChain.Transactions = []core.TransactionModel{{}} + mockHeaderRepository := fakes.NewMockHeaderRepository() + syncer.Repository = mockHeaderRepository + + err := syncer.SyncTransactions(0, []types.Log{}) + + Expect(err).NotTo(HaveOccurred()) + Expect(mockHeaderRepository.CreateTransactionsCalled).To(BeTrue()) + }) + + It("returns error if persisting transactions fails", func() { + blockChain.Transactions = []core.TransactionModel{{}} + mockHeaderRepository := fakes.NewMockHeaderRepository() + mockHeaderRepository.CreateTransactionsError = fakes.FakeError + syncer.Repository = mockHeaderRepository + + err := syncer.SyncTransactions(0, []types.Log{}) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) +}) diff --git a/libraries/shared/transactions/transactions_suite_test.go b/libraries/shared/transactions/transactions_suite_test.go new file mode 100644 index 00000000..1771a687 --- /dev/null +++ b/libraries/shared/transactions/transactions_suite_test.go @@ -0,0 +1,13 @@ +package transactions_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestTransactions(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Transactions Suite") +} diff --git a/libraries/shared/transformer_interface.go b/libraries/shared/transformer/contract_transformer.go similarity index 63% rename from libraries/shared/transformer_interface.go rename to libraries/shared/transformer/contract_transformer.go index 626c430c..14b8ab97 100644 --- a/libraries/shared/transformer_interface.go +++ b/libraries/shared/transformer/contract_transformer.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,26 +14,18 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package shared +package transformer import ( - "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/config" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) -type Transformer interface { +type ContractTransformer interface { + Init() error Execute() error + GetConfig() config.ContractConfig } -type TransformerInitializer func(db *postgres.DB, blockchain core.BlockChain, con ContractConfig) (Transformer, error) - -func HexToInt64(byteString string) int64 { - value := common.HexToHash(byteString) - return value.Big().Int64() -} - -func HexToString(byteString string) string { - value := common.HexToHash(byteString) - return value.Big().String() -} +type ContractTransformerInitializer func(db *postgres.DB, bc core.BlockChain) ContractTransformer diff --git a/libraries/shared/transformer/event_transformer.go b/libraries/shared/transformer/event_transformer.go new file mode 100644 index 00000000..c38b5454 --- /dev/null +++ b/libraries/shared/transformer/event_transformer.go @@ -0,0 +1,59 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package transformer + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type EventTransformer interface { + Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error + GetConfig() EventTransformerConfig +} + +type EventTransformerInitializer func(db *postgres.DB) EventTransformer + +type EventTransformerConfig struct { + TransformerName string + ContractAddresses []string + ContractAbi string + Topic string + StartingBlockNumber int64 + EndingBlockNumber int64 // Set -1 for indefinite transformer +} + +func HexToInt64(byteString string) int64 { + value := common.HexToHash(byteString) + return value.Big().Int64() +} + +func HexToString(byteString string) string { + value := common.HexToHash(byteString) + return value.Big().String() +} + +func HexStringsToAddresses(strings []string) (addresses []common.Address) { + for _, hexString := range strings { + addresses = append(addresses, common.HexToAddress(hexString)) + } + return +} diff --git a/examples/generic/event_triggered/tusd/entity.go b/libraries/shared/transformer/storage_transformer.go similarity index 65% rename from examples/generic/event_triggered/tusd/entity.go rename to libraries/shared/transformer/storage_transformer.go index a3e07018..3db5c0c1 100644 --- a/examples/generic/event_triggered/tusd/entity.go +++ b/libraries/shared/transformer/storage_transformer.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,28 +14,18 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package tusd +package transformer import ( - "math/big" - "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) -type BurnEntity struct { - TokenName string - TokenAddress common.Address - Burner common.Address - Value *big.Int - Block int64 - TxHash string +type StorageTransformer interface { + Execute(row utils.StorageDiffRow) error + ContractAddress() common.Address } -type MintEntity struct { - TokenName string - TokenAddress common.Address - To common.Address - Amount *big.Int - Block int64 - TxHash string -} +type StorageTransformerInitializer func(db *postgres.DB) StorageTransformer diff --git a/examples/erc20_watcher/event_triggered/dai/transformers.go b/libraries/shared/utilities/utils.go similarity index 73% rename from examples/erc20_watcher/event_triggered/dai/transformers.go rename to libraries/shared/utilities/utils.go index 665d86d0..02fc104e 100644 --- a/examples/erc20_watcher/event_triggered/dai/transformers.go +++ b/libraries/shared/utilities/utils.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,14 +14,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package dai +package utilities -import ( - "github.com/vulcanize/vulcanizedb/libraries/shared" -) - -func DaiEventTriggeredTransformerInitializer() []shared.TransformerInitializer { - return []shared.TransformerInitializer{ - NewTransformer, +func NullToZero(str string) string { + if str == "" { + return "0" } + return str } diff --git a/libraries/shared/watcher.go b/libraries/shared/watcher.go deleted file mode 100644 index a8866125..00000000 --- a/libraries/shared/watcher.go +++ /dev/null @@ -1,52 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package shared - -import ( - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -type Watcher struct { - Transformers []Transformer - DB postgres.DB - Blockchain core.BlockChain -} - -func (watcher *Watcher) AddTransformers(us []TransformerInitializer, con ContractConfig) error { - for _, transformerInitializer := range us { - transformer, err := transformerInitializer(&watcher.DB, watcher.Blockchain, con) - if err != nil { - return err - } - watcher.Transformers = append(watcher.Transformers, transformer) - } - - return nil -} - -func (watcher *Watcher) AddTransformer(t Transformer) { - watcher.Transformers = append(watcher.Transformers, t) -} - -func (watcher *Watcher) Execute() error { - var err error - for _, transformer := range watcher.Transformers { - err = transformer.Execute() - } - return err -} diff --git a/libraries/shared/watcher/contract_watcher.go b/libraries/shared/watcher/contract_watcher.go new file mode 100644 index 00000000..ebb4cc37 --- /dev/null +++ b/libraries/shared/watcher/contract_watcher.go @@ -0,0 +1,76 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Contract watcher is built with a more generic interface +// that allows offloading more of the operational logic to +// the transformers, allowing them to act more dynamically +// Built to work primarily with the contract_watcher packaging +package watcher + +import ( + "fmt" + + log "github.com/sirupsen/logrus" + + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type ContractWatcher struct { + Transformers []transformer.ContractTransformer + DB *postgres.DB + BlockChain core.BlockChain +} + +func NewContractWatcher(db *postgres.DB, bc core.BlockChain) ContractWatcher { + return ContractWatcher{ + DB: db, + BlockChain: bc, + } +} + +func (watcher *ContractWatcher) AddTransformers(inits interface{}) error { + initializers, ok := inits.([]transformer.ContractTransformerInitializer) + if !ok { + return fmt.Errorf("initializers of type %T, not %T", inits, []transformer.ContractTransformerInitializer{}) + } + + for _, initializer := range initializers { + t := initializer(watcher.DB, watcher.BlockChain) + watcher.Transformers = append(watcher.Transformers, t) + } + + for _, transformer := range watcher.Transformers { + err := transformer.Init() + if err != nil { + log.Print("Unable to initialize transformer:", transformer.GetConfig().Name, err) + return err + } + } + return nil +} + +func (watcher *ContractWatcher) Execute() error { + for _, transformer := range watcher.Transformers { + err := transformer.Execute() + if err != nil { + log.Error("Unable to execute transformer:", transformer.GetConfig().Name, err) + return err + } + } + return nil +} diff --git a/libraries/shared/watcher/event_watcher.go b/libraries/shared/watcher/event_watcher.go new file mode 100644 index 00000000..9bad688a --- /dev/null +++ b/libraries/shared/watcher/event_watcher.go @@ -0,0 +1,148 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package watcher + +import ( + "fmt" + "github.com/vulcanize/vulcanizedb/libraries/shared/transactions" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/sirupsen/logrus" + + "github.com/vulcanize/vulcanizedb/libraries/shared/chunker" + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/fetcher" + "github.com/vulcanize/vulcanizedb/libraries/shared/repository" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type EventWatcher struct { + Transformers []transformer.EventTransformer + BlockChain core.BlockChain + DB *postgres.DB + Fetcher fetcher.LogFetcher + Chunker chunker.Chunker + Addresses []common.Address + Topics []common.Hash + StartingBlock *int64 + Syncer transactions.ITransactionsSyncer +} + +func NewEventWatcher(db *postgres.DB, bc core.BlockChain) EventWatcher { + logChunker := chunker.NewLogChunker() + logFetcher := fetcher.NewFetcher(bc) + transactionSyncer := transactions.NewTransactionsSyncer(db, bc) + return EventWatcher{ + BlockChain: bc, + DB: db, + Fetcher: logFetcher, + Chunker: logChunker, + Syncer: transactionSyncer, + } +} + +// Adds transformers to the watcher and updates the chunker, so that it will consider the new transformers. +func (watcher *EventWatcher) AddTransformers(initializers []transformer.EventTransformerInitializer) { + var contractAddresses []common.Address + var topic0s []common.Hash + var configs []transformer.EventTransformerConfig + + for _, initializer := range initializers { + t := initializer(watcher.DB) + watcher.Transformers = append(watcher.Transformers, t) + + config := t.GetConfig() + configs = append(configs, config) + + if watcher.StartingBlock == nil { + watcher.StartingBlock = &config.StartingBlockNumber + } else if earlierStartingBlockNumber(config.StartingBlockNumber, *watcher.StartingBlock) { + watcher.StartingBlock = &config.StartingBlockNumber + } + + addresses := transformer.HexStringsToAddresses(config.ContractAddresses) + contractAddresses = append(contractAddresses, addresses...) + topic0s = append(topic0s, common.HexToHash(config.Topic)) + } + + watcher.Addresses = append(watcher.Addresses, contractAddresses...) + watcher.Topics = append(watcher.Topics, topic0s...) + watcher.Chunker.AddConfigs(configs) +} + +func (watcher *EventWatcher) Execute(recheckHeaders constants.TransformerExecution) error { + if watcher.Transformers == nil { + return fmt.Errorf("No transformers added to watcher") + } + + checkedColumnNames, err := repository.GetCheckedColumnNames(watcher.DB) + if err != nil { + return err + } + notCheckedSQL := repository.CreateNotCheckedSQL(checkedColumnNames, recheckHeaders) + + missingHeaders, err := repository.MissingHeaders(*watcher.StartingBlock, -1, watcher.DB, notCheckedSQL) + if err != nil { + logrus.Error("Fetching of missing headers failed in watcher!") + return err + } + + for _, header := range missingHeaders { + // TODO Extend FetchLogs for doing several blocks at a time + logs, err := watcher.Fetcher.FetchLogs(watcher.Addresses, watcher.Topics, header) + if err != nil { + logrus.Errorf("Error while fetching logs for header %v in watcher", header.Id) + return err + } + + transactionsSyncErr := watcher.Syncer.SyncTransactions(header.Id, logs) + if transactionsSyncErr != nil { + logrus.Errorf("error syncing transactions: %s", transactionsSyncErr.Error()) + return transactionsSyncErr + } + + transformErr := watcher.transformLogs(logs, header) + if transformErr != nil { + return transformErr + } + } + return err +} + +func (watcher *EventWatcher) transformLogs(logs []types.Log, header core.Header) error { + chunkedLogs := watcher.Chunker.ChunkLogs(logs) + + // Can't quit early and mark as checked if there are no logs. If we are running continuousLogSync, + // not all logs we're interested in might have been fetched. + for _, t := range watcher.Transformers { + transformerName := t.GetConfig().TransformerName + logChunk := chunkedLogs[transformerName] + err := t.Execute(logChunk, header, constants.HeaderMissing) + if err != nil { + logrus.Errorf("%v transformer failed to execute in watcher: %v", transformerName, err) + return err + } + } + return nil +} + +func earlierStartingBlockNumber(transformerBlock, watcherBlock int64) bool { + return transformerBlock < watcherBlock +} diff --git a/libraries/shared/watcher/event_watcher_test.go b/libraries/shared/watcher/event_watcher_test.go new file mode 100644 index 00000000..6edd168d --- /dev/null +++ b/libraries/shared/watcher/event_watcher_test.go @@ -0,0 +1,237 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package watcher_test + +import ( + "errors" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/libraries/shared/constants" + "github.com/vulcanize/vulcanizedb/libraries/shared/mocks" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/libraries/shared/watcher" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" + "github.com/vulcanize/vulcanizedb/pkg/fakes" + "github.com/vulcanize/vulcanizedb/test_config" +) + +var _ = Describe("Watcher", func() { + It("initialises correctly", func() { + db := test_config.NewTestDB(core.Node{ID: "testNode"}) + bc := fakes.NewMockBlockChain() + + w := watcher.NewEventWatcher(db, bc) + + Expect(w.DB).To(Equal(db)) + Expect(w.Fetcher).NotTo(BeNil()) + Expect(w.Chunker).NotTo(BeNil()) + }) + + It("adds transformers", func() { + w := watcher.NewEventWatcher(nil, nil) + fakeTransformer := &mocks.MockTransformer{} + fakeTransformer.SetTransformerConfig(mocks.FakeTransformerConfig) + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + + Expect(len(w.Transformers)).To(Equal(1)) + Expect(w.Transformers).To(ConsistOf(fakeTransformer)) + Expect(w.Topics).To(Equal([]common.Hash{common.HexToHash("FakeTopic")})) + Expect(w.Addresses).To(Equal([]common.Address{common.HexToAddress("FakeAddress")})) + }) + + It("adds transformers from multiple sources", func() { + w := watcher.NewEventWatcher(nil, nil) + fakeTransformer1 := &mocks.MockTransformer{} + fakeTransformer1.SetTransformerConfig(mocks.FakeTransformerConfig) + + fakeTransformer2 := &mocks.MockTransformer{} + fakeTransformer2.SetTransformerConfig(mocks.FakeTransformerConfig) + + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer1.FakeTransformerInitializer}) + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer2.FakeTransformerInitializer}) + + Expect(len(w.Transformers)).To(Equal(2)) + Expect(w.Topics).To(Equal([]common.Hash{common.HexToHash("FakeTopic"), + common.HexToHash("FakeTopic")})) + Expect(w.Addresses).To(Equal([]common.Address{common.HexToAddress("FakeAddress"), + common.HexToAddress("FakeAddress")})) + }) + + It("calculates earliest starting block number", func() { + fakeTransformer1 := &mocks.MockTransformer{} + fakeTransformer1.SetTransformerConfig(transformer.EventTransformerConfig{StartingBlockNumber: 5}) + + fakeTransformer2 := &mocks.MockTransformer{} + fakeTransformer2.SetTransformerConfig(transformer.EventTransformerConfig{StartingBlockNumber: 3}) + + w := watcher.NewEventWatcher(nil, nil) + w.AddTransformers([]transformer.EventTransformerInitializer{ + fakeTransformer1.FakeTransformerInitializer, + fakeTransformer2.FakeTransformerInitializer, + }) + + Expect(*w.StartingBlock).To(Equal(int64(3))) + }) + + It("returns an error when run without transformers", func() { + w := watcher.NewEventWatcher(nil, nil) + err := w.Execute(constants.HeaderMissing) + Expect(err).To(MatchError("No transformers added to watcher")) + }) + + Describe("with missing headers", func() { + var ( + db *postgres.DB + w watcher.EventWatcher + mockBlockChain fakes.MockBlockChain + headerRepository repositories.HeaderRepository + repository mocks.MockWatcherRepository + ) + + BeforeEach(func() { + db = test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + mockBlockChain = fakes.MockBlockChain{} + headerRepository = repositories.NewHeaderRepository(db) + _, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) + Expect(err).NotTo(HaveOccurred()) + + repository = mocks.MockWatcherRepository{} + w = watcher.NewEventWatcher(db, &mockBlockChain) + }) + + It("syncs transactions for fetched logs", func() { + fakeTransformer := &mocks.MockTransformer{} + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + repository.SetMissingHeaders([]core.Header{fakes.FakeHeader}) + mockTransactionSyncer := &fakes.MockTransactionSyncer{} + w.Syncer = mockTransactionSyncer + + err := w.Execute(constants.HeaderMissing) + + Expect(err).NotTo(HaveOccurred()) + Expect(mockTransactionSyncer.SyncTransactionsCalled).To(BeTrue()) + }) + + It("returns error if syncing transactions fails", func() { + fakeTransformer := &mocks.MockTransformer{} + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + repository.SetMissingHeaders([]core.Header{fakes.FakeHeader}) + mockTransactionSyncer := &fakes.MockTransactionSyncer{} + mockTransactionSyncer.SyncTransactionsError = fakes.FakeError + w.Syncer = mockTransactionSyncer + + err := w.Execute(constants.HeaderMissing) + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("executes each transformer", func() { + fakeTransformer := &mocks.MockTransformer{} + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + repository.SetMissingHeaders([]core.Header{fakes.FakeHeader}) + + err := w.Execute(constants.HeaderMissing) + Expect(err).NotTo(HaveOccurred()) + Expect(fakeTransformer.ExecuteWasCalled).To(BeTrue()) + }) + + It("returns an error if transformer returns an error", func() { + fakeTransformer := &mocks.MockTransformer{ExecuteError: errors.New("Something bad happened")} + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + repository.SetMissingHeaders([]core.Header{fakes.FakeHeader}) + + err := w.Execute(constants.HeaderMissing) + Expect(err).To(HaveOccurred()) + Expect(fakeTransformer.ExecuteWasCalled).To(BeFalse()) + }) + + It("passes only relevant logs to each transformer", func() { + transformerA := &mocks.MockTransformer{} + transformerB := &mocks.MockTransformer{} + + configA := transformer.EventTransformerConfig{TransformerName: "transformerA", + ContractAddresses: []string{"0x000000000000000000000000000000000000000A"}, + Topic: "0xA"} + configB := transformer.EventTransformerConfig{TransformerName: "transformerB", + ContractAddresses: []string{"0x000000000000000000000000000000000000000b"}, + Topic: "0xB"} + + transformerA.SetTransformerConfig(configA) + transformerB.SetTransformerConfig(configB) + + logA := types.Log{Address: common.HexToAddress("0xA"), + Topics: []common.Hash{common.HexToHash("0xA")}} + logB := types.Log{Address: common.HexToAddress("0xB"), + Topics: []common.Hash{common.HexToHash("0xB")}} + mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{logA, logB}) + + repository.SetMissingHeaders([]core.Header{fakes.FakeHeader}) + w = watcher.NewEventWatcher(db, &mockBlockChain) + w.AddTransformers([]transformer.EventTransformerInitializer{ + transformerA.FakeTransformerInitializer, transformerB.FakeTransformerInitializer}) + + err := w.Execute(constants.HeaderMissing) + Expect(err).NotTo(HaveOccurred()) + Expect(transformerA.PassedLogs).To(Equal([]types.Log{logA})) + Expect(transformerB.PassedLogs).To(Equal([]types.Log{logB})) + }) + + Describe("uses the LogFetcher correctly:", func() { + var fakeTransformer mocks.MockTransformer + BeforeEach(func() { + repository.SetMissingHeaders([]core.Header{fakes.FakeHeader}) + fakeTransformer = mocks.MockTransformer{} + }) + + It("fetches logs for added transformers", func() { + addresses := []string{"0xA", "0xB"} + topic := "0x1" + fakeTransformer.SetTransformerConfig(transformer.EventTransformerConfig{ + Topic: topic, ContractAddresses: addresses}) + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + + err := w.Execute(constants.HeaderMissing) + Expect(err).NotTo(HaveOccurred()) + + fakeHash := common.HexToHash(fakes.FakeHeader.Hash) + mockBlockChain.AssertGetEthLogsWithCustomQueryCalledWith(ethereum.FilterQuery{ + BlockHash: &fakeHash, + Addresses: transformer.HexStringsToAddresses(addresses), + Topics: [][]common.Hash{{common.HexToHash(topic)}}, + }) + }) + + It("propagates log fetcher errors", func() { + fetcherError := errors.New("FetcherError") + mockBlockChain.SetGetEthLogsWithCustomQueryErr(fetcherError) + + w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + err := w.Execute(constants.HeaderMissing) + Expect(err).To(MatchError(fetcherError)) + }) + }) + }) +}) diff --git a/libraries/shared/watcher/storage_watcher.go b/libraries/shared/watcher/storage_watcher.go new file mode 100644 index 00000000..524cbcd4 --- /dev/null +++ b/libraries/shared/watcher/storage_watcher.go @@ -0,0 +1,91 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package watcher + +import ( + "reflect" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/sirupsen/logrus" + + "github.com/vulcanize/vulcanizedb/libraries/shared/storage" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/fs" +) + +type StorageWatcher struct { + db *postgres.DB + tailer fs.Tailer + Queue storage.IStorageQueue + Transformers map[common.Address]transformer.StorageTransformer +} + +func NewStorageWatcher(tailer fs.Tailer, db *postgres.DB) StorageWatcher { + transformers := make(map[common.Address]transformer.StorageTransformer) + queue := storage.NewStorageQueue(db) + return StorageWatcher{ + db: db, + tailer: tailer, + Queue: queue, + Transformers: transformers, + } +} + +func (watcher StorageWatcher) AddTransformers(initializers []transformer.StorageTransformerInitializer) { + for _, initializer := range initializers { + storageTransformer := initializer(watcher.db) + watcher.Transformers[storageTransformer.ContractAddress()] = storageTransformer + } +} + +func (watcher StorageWatcher) Execute() error { + t, tailErr := watcher.tailer.Tail() + if tailErr != nil { + return tailErr + } + for line := range t.Lines { + row, parseErr := utils.FromStrings(strings.Split(line.Text, ",")) + if parseErr != nil { + return parseErr + } + storageTransformer, ok := watcher.Transformers[row.Contract] + if !ok { + logrus.Warn(utils.ErrContractNotFound{Contract: row.Contract.Hex()}.Error()) + continue + } + executeErr := storageTransformer.Execute(row) + if executeErr != nil { + if isKeyNotFound(executeErr) { + queueErr := watcher.Queue.Add(row) + if queueErr != nil { + logrus.Warn(queueErr.Error()) + } + } else { + logrus.Warn(executeErr.Error()) + } + continue + } + } + return nil +} + +func isKeyNotFound(executeErr error) bool { + return reflect.TypeOf(executeErr) == reflect.TypeOf(utils.ErrStorageKeyNotFound{}) +} diff --git a/libraries/shared/watcher/storage_watcher_test.go b/libraries/shared/watcher/storage_watcher_test.go new file mode 100644 index 00000000..dc74eba4 --- /dev/null +++ b/libraries/shared/watcher/storage_watcher_test.go @@ -0,0 +1,212 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package watcher_test + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/hpcloud/tail" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/sirupsen/logrus" + + "github.com/vulcanize/vulcanizedb/libraries/shared/mocks" + "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer" + "github.com/vulcanize/vulcanizedb/libraries/shared/watcher" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" + "github.com/vulcanize/vulcanizedb/test_config" +) + +var _ = Describe("Storage Watcher", func() { + It("adds transformers", func() { + fakeAddress := common.HexToAddress("0x12345") + fakeTransformer := &mocks.MockStorageTransformer{Address: fakeAddress} + w := watcher.NewStorageWatcher(&fakes.MockTailer{}, test_config.NewTestDB(core.Node{})) + + w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + + Expect(w.Transformers[fakeAddress]).To(Equal(fakeTransformer)) + }) + + It("reads the tail of the storage diffs file", func() { + mockTailer := fakes.NewMockTailer() + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + + assert(func(err error) { + Expect(err).To(BeNil()) + Expect(mockTailer.TailCalled).To(BeTrue()) + }, w, mockTailer, []*tail.Line{}) + }) + + It("returns error if row parsing fails", func() { + mockTailer := fakes.NewMockTailer() + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + line := &tail.Line{Text: "oops"} + + assert(func(err error) { + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(utils.ErrRowMalformed{Length: 1})) + }, w, mockTailer, []*tail.Line{line}) + }) + + It("logs error if no transformer can parse storage row", func() { + mockTailer := fakes.NewMockTailer() + address := common.HexToAddress("0x12345") + line := getFakeLine(address.Bytes()) + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + tempFile, err := ioutil.TempFile("", "log") + defer os.Remove(tempFile.Name()) + Expect(err).NotTo(HaveOccurred()) + logrus.SetOutput(tempFile) + + assert(func(err error) { + Expect(err).NotTo(HaveOccurred()) + logContent, readErr := ioutil.ReadFile(tempFile.Name()) + Expect(readErr).NotTo(HaveOccurred()) + Expect(string(logContent)).To(ContainSubstring(utils.ErrContractNotFound{Contract: address.Hex()}.Error())) + }, w, mockTailer, []*tail.Line{line}) + }) + + It("executes transformer with storage row", func() { + address := []byte{1, 2, 3} + line := getFakeLine(address) + mockTailer := fakes.NewMockTailer() + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + fakeTransformer := &mocks.MockStorageTransformer{Address: common.BytesToAddress(address)} + w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + + assert(func(err error) { + Expect(err).To(BeNil()) + expectedRow, err := utils.FromStrings(strings.Split(line.Text, ",")) + Expect(err).NotTo(HaveOccurred()) + Expect(fakeTransformer.PassedRow).To(Equal(expectedRow)) + }, w, mockTailer, []*tail.Line{line}) + }) + + Describe("when executing transformer fails", func() { + It("queues row when error is storage key not found", func() { + address := []byte{1, 2, 3} + line := getFakeLine(address) + mockTailer := fakes.NewMockTailer() + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + mockQueue := &mocks.MockStorageQueue{} + w.Queue = mockQueue + keyNotFoundError := utils.ErrStorageKeyNotFound{Key: "unknown_storage_key"} + fakeTransformer := &mocks.MockStorageTransformer{Address: common.BytesToAddress(address), ExecuteErr: keyNotFoundError} + w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + + assert(func(err error) { + Expect(err).NotTo(HaveOccurred()) + Expect(mockQueue.AddCalled).To(BeTrue()) + }, w, mockTailer, []*tail.Line{line}) + }) + + It("logs error if queuing row fails", func() { + address := []byte{1, 2, 3} + line := getFakeLine(address) + mockTailer := fakes.NewMockTailer() + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + mockQueue := &mocks.MockStorageQueue{} + mockQueue.AddError = fakes.FakeError + w.Queue = mockQueue + keyNotFoundError := utils.ErrStorageKeyNotFound{Key: "unknown_storage_key"} + fakeTransformer := &mocks.MockStorageTransformer{Address: common.BytesToAddress(address), ExecuteErr: keyNotFoundError} + w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + tempFile, err := ioutil.TempFile("", "log") + defer os.Remove(tempFile.Name()) + Expect(err).NotTo(HaveOccurred()) + logrus.SetOutput(tempFile) + + assert(func(err error) { + Expect(err).NotTo(HaveOccurred()) + Expect(mockQueue.AddCalled).To(BeTrue()) + logContent, readErr := ioutil.ReadFile(tempFile.Name()) + Expect(readErr).NotTo(HaveOccurred()) + Expect(string(logContent)).To(ContainSubstring(fakes.FakeError.Error())) + }, w, mockTailer, []*tail.Line{line}) + }) + + It("logs any other error", func() { + address := []byte{1, 2, 3} + line := getFakeLine(address) + mockTailer := fakes.NewMockTailer() + w := watcher.NewStorageWatcher(mockTailer, test_config.NewTestDB(core.Node{})) + executionError := errors.New("storage watcher failed attempting to execute transformer") + fakeTransformer := &mocks.MockStorageTransformer{Address: common.BytesToAddress(address), ExecuteErr: executionError} + w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer}) + tempFile, err := ioutil.TempFile("", "log") + defer os.Remove(tempFile.Name()) + Expect(err).NotTo(HaveOccurred()) + logrus.SetOutput(tempFile) + + assert(func(err error) { + Expect(err).NotTo(HaveOccurred()) + logContent, readErr := ioutil.ReadFile(tempFile.Name()) + Expect(readErr).NotTo(HaveOccurred()) + Expect(string(logContent)).To(ContainSubstring(executionError.Error())) + }, w, mockTailer, []*tail.Line{line}) + }) + }) +}) + +func assert(assertion func(err error), watcher watcher.StorageWatcher, mockTailer *fakes.MockTailer, lines []*tail.Line) { + errs := make(chan error, 1) + done := make(chan bool, 1) + go execute(watcher, errs, done) + for _, line := range lines { + mockTailer.Lines <- line + } + close(mockTailer.Lines) + + select { + case err := <-errs: + assertion(err) + break + case <-done: + assertion(nil) + break + } +} + +func execute(w watcher.StorageWatcher, errs chan error, done chan bool) { + err := w.Execute() + if err != nil { + errs <- err + } else { + done <- true + } +} + +func getFakeLine(address []byte) *tail.Line { + blockHash := []byte{4, 5, 6} + blockHeight := int64(789) + storageKey := []byte{9, 8, 7} + storageValue := []byte{6, 5, 4} + return &tail.Line{ + Text: fmt.Sprintf("%s,%s,%d,%s,%s", common.Bytes2Hex(address), common.Bytes2Hex(blockHash), blockHeight, common.Bytes2Hex(storageKey), common.Bytes2Hex(storageValue)), + Time: time.Time{}, + Err: nil, + } +} diff --git a/examples/erc20_watcher/every_block/every_block_suite_test.go b/libraries/shared/watcher/watcher_suite_test.go similarity index 84% rename from examples/erc20_watcher/every_block/every_block_suite_test.go rename to libraries/shared/watcher/watcher_suite_test.go index ae7c269a..9685a721 100644 --- a/examples/erc20_watcher/every_block/every_block_suite_test.go +++ b/libraries/shared/watcher/watcher_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -14,20 +14,20 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package every_block_test +package watcher_test import ( + log "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) -func TestEveryBlock(t *testing.T) { +func TestShared(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "ERC20 EveryBlock Suite") + RunSpecs(t, "Shared Watcher Suite") } var _ = BeforeSuite(func() { diff --git a/libraries/shared/watcher_test.go b/libraries/shared/watcher_test.go deleted file mode 100644 index 18142339..00000000 --- a/libraries/shared/watcher_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package shared_test - -import ( - "errors" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/libraries/shared" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" -) - -type MockTransformer struct { - executeWasCalled bool - executeError error -} - -func (mh *MockTransformer) Execute() error { - if mh.executeError != nil { - return mh.executeError - } - mh.executeWasCalled = true - return nil -} - -func fakeTransformerInitializer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) { - return &MockTransformer{}, nil -} - -var _ = Describe("Watcher", func() { - It("Adds transformers", func() { - watcher := shared.Watcher{} - con := shared.ContractConfig{} - - watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer}, con) - - Expect(len(watcher.Transformers)).To(Equal(1)) - Expect(watcher.Transformers).To(ConsistOf(&MockTransformer{})) - }) - - It("Adds transformers from multiple sources", func() { - watcher := shared.Watcher{} - con := shared.ContractConfig{} - - watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer}, con) - watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer}, con) - - Expect(len(watcher.Transformers)).To(Equal(2)) - }) - - It("Executes each transformer", func() { - watcher := shared.Watcher{} - fakeTransformer := &MockTransformer{} - watcher.Transformers = []shared.Transformer{fakeTransformer} - - watcher.Execute() - - Expect(fakeTransformer.executeWasCalled).To(BeTrue()) - }) - - It("Returns an error if transformer returns an error", func() { - watcher := shared.Watcher{} - fakeTransformer := &MockTransformer{executeError: errors.New("Something bad happened")} - watcher.Transformers = []shared.Transformer{fakeTransformer} - - err := watcher.Execute() - - Expect(err).To(HaveOccurred()) - Expect(fakeTransformer.executeWasCalled).To(BeFalse()) - }) -}) diff --git a/main.go b/main.go index a27eb869..bf9b2677 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,20 @@ package main import ( "github.com/vulcanize/vulcanizedb/cmd" + + log "github.com/sirupsen/logrus" + "os" ) func main() { + log.SetFormatter(&log.JSONFormatter{}) + file, err := os.OpenFile("vulcanizedb.log", + os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err == nil { + log.SetOutput(file) + } else { + log.Info("Failed to log to file, using default stderr") + } + cmd.Execute() } diff --git a/pkg/config/client.go b/pkg/config/client.go index 650bf5b1..ea426d5d 100644 --- a/pkg/config/client.go +++ b/pkg/config/client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/config/config.go b/pkg/config/config.go index 9b7c9799..87588f9d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/config/config_suite_test.go b/pkg/config/config_suite_test.go index 22df0c6f..97aa327c 100644 --- a/pkg/config/config_suite_test.go +++ b/pkg/config/config_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index fe8dc0aa..0daa5e77 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/config/contract.go b/pkg/config/contract.go new file mode 100644 index 00000000..50b8366a --- /dev/null +++ b/pkg/config/contract.go @@ -0,0 +1,217 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package config + +import ( + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" + "github.com/vulcanize/vulcanizedb/pkg/geth" + "strings" +) + +// Config struct for generic contract transformer +type ContractConfig struct { + // Name for the transformer + Name string + + // Ethereum network name; default "" is mainnet + Network string + + // List of contract addresses (map to ensure no duplicates) + Addresses map[string]bool + + // Map of contract address to abi + // If an address has no associated abi the parser will attempt to fetch one from etherscan + Abis map[string]string + + // Map of contract address to slice of events + // Used to set which addresses to watch + // If any events are listed in the slice only those will be watched + // Otherwise all events in the contract ABI are watched + Events map[string][]string + + // Map of contract address to slice of methods + // If any methods are listed in the slice only those will be polled + // Otherwise no methods will be polled + Methods map[string][]string + + // Map of contract address to slice of event arguments to filter for + // If arguments are provided then only events which emit those arguments are watched + // Otherwise arguments are not filtered on events + EventArgs map[string][]string + + // Map of contract address to slice of method arguments to limit polling to + // If arguments are provided then only those arguments are allowed as arguments in method polling + // Otherwise any argument of the right type seen emitted from events at that contract will be used in method polling + MethodArgs map[string][]string + + // Map of contract address to their starting block + StartingBlocks map[string]int64 + + // Map of contract address to whether or not to pipe method polling results forward into subsequent method calls + Piping map[string]bool +} + +func (contractConfig *ContractConfig) PrepConfig() { + addrs := viper.GetStringSlice("contract.addresses") + contractConfig.Network = viper.GetString("contract.network") + contractConfig.Addresses = make(map[string]bool, len(addrs)) + contractConfig.Abis = make(map[string]string, len(addrs)) + contractConfig.Methods = make(map[string][]string, len(addrs)) + contractConfig.Events = make(map[string][]string, len(addrs)) + contractConfig.MethodArgs = make(map[string][]string, len(addrs)) + contractConfig.EventArgs = make(map[string][]string, len(addrs)) + contractConfig.StartingBlocks = make(map[string]int64, len(addrs)) + contractConfig.Piping = make(map[string]bool, len(addrs)) + // De-dupe addresses + for _, addr := range addrs { + contractConfig.Addresses[strings.ToLower(addr)] = true + } + + // Iterate over addresses to pull out config info for each contract + for _, addr := range addrs { + transformer := viper.GetStringMap("contract." + addr) + + // Get and check abi + var abi string + abiInterface, abiOK := transformer["abi"] + if !abiOK { + log.Warnf("contract %s not configured with an ABI, will attempt to fetch it from Etherscan\r\n", addr) + } else { + abi, abiOK = abiInterface.(string) + if !abiOK { + log.Fatal(addr, "transformer `abi` not of type []string") + } + } + if abi != "" { + if _, abiErr := geth.ParseAbi(abi); abiErr != nil { + log.Fatal(addr, "transformer `abi` not valid JSON") + } + } + contractConfig.Abis[strings.ToLower(addr)] = abi + + // Get and check events + events := make([]string, 0) + eventsInterface, eventsOK := transformer["events"] + if !eventsOK { + log.Warnf("contract %s not configured with a list of events to watch, will watch all events\r\n", addr) + events = []string{} + } else { + eventsI, eventsOK := eventsInterface.([]interface{}) + if !eventsOK { + log.Fatal(addr, "transformer `events` not of type []string\r\n") + } + for _, strI := range eventsI { + str, strOK := strI.(string) + if !strOK { + log.Fatal(addr, "transformer `events` not of type []string\r\n") + } + events = append(events, str) + } + } + contractConfig.Events[strings.ToLower(addr)] = events + + // Get and check methods + methods := make([]string, 0) + methodsInterface, methodsOK := transformer["methods"] + if !methodsOK { + log.Warnf("contract %s not configured with a list of methods to poll, will not poll any methods\r\n", addr) + methods = []string{} + } else { + methodsI, methodsOK := methodsInterface.([]interface{}) + if !methodsOK { + log.Fatal(addr, "transformer `methods` not of type []string\r\n") + } + for _, strI := range methodsI { + str, strOK := strI.(string) + if !strOK { + log.Fatal(addr, "transformer `methods` not of type []string\r\n") + } + methods = append(methods, str) + } + } + contractConfig.Methods[strings.ToLower(addr)] = methods + + // Get and check eventArgs + eventArgs := make([]string, 0) + eventArgsInterface, eventArgsOK := transformer["eventArgs"] + if !eventArgsOK { + log.Warnf("contract %s not configured with a list of event arguments to filter for, will not filter events for specific emitted values\r\n", addr) + eventArgs = []string{} + } else { + eventArgsI, eventArgsOK := eventArgsInterface.([]interface{}) + if !eventArgsOK { + log.Fatal(addr, "transformer `eventArgs` not of type []string\r\n") + } + for _, strI := range eventArgsI { + str, strOK := strI.(string) + if !strOK { + log.Fatal(addr, "transformer `eventArgs` not of type []string\r\n") + } + eventArgs = append(eventArgs, str) + } + } + contractConfig.EventArgs[strings.ToLower(addr)] = eventArgs + + // Get and check methodArgs + methodArgs := make([]string, 0) + methodArgsInterface, methodArgsOK := transformer["methodArgs"] + if !methodArgsOK { + log.Warnf("contract %s not configured with a list of method argument values to poll with, will poll methods with all available arguments\r\n", addr) + methodArgs = []string{} + } else { + methodArgsI, methodArgsOK := methodArgsInterface.([]interface{}) + if !methodArgsOK { + log.Fatal(addr, "transformer `methodArgs` not of type []string\r\n") + } + for _, strI := range methodArgsI { + str, strOK := strI.(string) + if !strOK { + log.Fatal(addr, "transformer `methodArgs` not of type []string\r\n") + } + methodArgs = append(methodArgs, str) + } + } + contractConfig.MethodArgs[strings.ToLower(addr)] = methodArgs + + // Get and check startingBlock + startInterface, startOK := transformer["startingblock"] + if !startOK { + log.Fatal(addr, "transformer config is missing `startingBlock` value\r\n") + } + start, startOK := startInterface.(int64) + if !startOK { + log.Fatal(addr, "transformer `startingBlock` not of type int\r\n") + } + contractConfig.StartingBlocks[strings.ToLower(addr)] = start + + // Get pipping + var piping bool + _, pipeOK := transformer["piping"] + if !pipeOK { + log.Warnf("contract %s does not have its `piping` set, by default piping is turned off\r\n", addr) + piping = false + } else { + pipingInterface := transformer["piping"] + piping, pipeOK = pipingInterface.(bool) + if !pipeOK { + log.Fatal(addr, "transformer `piping` not of type bool\r\n") + } + } + contractConfig.Piping[strings.ToLower(addr)] = piping + } +} diff --git a/pkg/config/database.go b/pkg/config/database.go index 62bdd8bf..2eb37e1b 100644 --- a/pkg/config/database.go +++ b/pkg/config/database.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/config/plugin.go b/pkg/config/plugin.go new file mode 100644 index 00000000..fad07cbc --- /dev/null +++ b/pkg/config/plugin.go @@ -0,0 +1,167 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package config + +import ( + "errors" + "fmt" + "path/filepath" + "strings" + + "github.com/vulcanize/vulcanizedb/pkg/plugin/helpers" +) + +type Plugin struct { + Transformers map[string]Transformer + FilePath string + FileName string + Save bool + Home string +} + +type Transformer struct { + Path string + Type TransformerType + MigrationPath string + MigrationRank uint64 + RepositoryPath string +} + +func (pluginConfig *Plugin) GetPluginPaths() (string, string, error) { + path, err := helpers.CleanPath(pluginConfig.FilePath) + if err != nil { + return "", "", err + } + + name := strings.Split(pluginConfig.FileName, ".")[0] + goFile := filepath.Join(path, name+".go") + soFile := filepath.Join(path, name+".so") + + return goFile, soFile, nil +} + +// Removes duplicate migration paths and returns them in ranked order +func (pluginConfig *Plugin) GetMigrationsPaths() ([]string, error) { + paths := make(map[uint64]string) + highestRank := -1 + for name, transformer := range pluginConfig.Transformers { + repo := transformer.RepositoryPath + mig := transformer.MigrationPath + path := filepath.Join("$GOPATH/src", pluginConfig.Home, "vendor", repo, mig) + cleanPath, err := helpers.CleanPath(path) + if err != nil { + return nil, err + } + // If there is a different path with the same rank then we have a conflict + _, ok := paths[transformer.MigrationRank] + if ok { + conflictingPath := paths[transformer.MigrationRank] + if conflictingPath != cleanPath { + return nil, errors.New(fmt.Sprintf("transformer %s has the same migration rank (%d) as another transformer", name, transformer.MigrationRank)) + } + } + paths[transformer.MigrationRank] = cleanPath + if int(transformer.MigrationRank) >= highestRank { + highestRank = int(transformer.MigrationRank) + } + } + // Check for gaps and duplicates + if len(paths) != (highestRank + 1) { + return []string{}, errors.New("number of distinct ranks does not match number of distinct migration paths") + } + if anyDupes(paths) { + return []string{}, errors.New("duplicate paths with different ranks present") + } + + sortedPaths := make([]string, len(paths)) + for rank, path := range paths { + sortedPaths[rank] = path + } + + return sortedPaths, nil +} + +// Removes duplicate repo paths before returning them +func (pluginConfig *Plugin) GetRepoPaths() map[string]bool { + paths := make(map[string]bool) + for _, transformer := range pluginConfig.Transformers { + paths[transformer.RepositoryPath] = true + } + + return paths +} + +type TransformerType int + +const ( + UnknownTransformerType TransformerType = iota + EthEvent + EthStorage + EthContract +) + +func (transformerType TransformerType) String() string { + names := [...]string{ + "Unknown", + "eth_event", + "eth_storage", + "eth_contract", + } + + if transformerType > EthContract || transformerType < EthEvent { + return "Unknown" + } + + return names[transformerType] +} + +func GetTransformerType(str string) TransformerType { + types := [...]TransformerType{ + EthEvent, + EthStorage, + EthContract, + } + + for _, ty := range types { + if ty.String() == str { + return ty + } + } + + return UnknownTransformerType +} + +func anyDupes(list map[uint64]string) bool { + seen := make([]string, 0, len(list)) + for _, str := range list { + dupe := inList(str, seen) + if dupe { + return true + } + seen = append(seen, str) + } + return false +} + +func inList(str string, list []string) bool { + for _, element := range list { + if str == element { + return true + } + } + return false +} diff --git a/pkg/config/plugin_test.go b/pkg/config/plugin_test.go new file mode 100644 index 00000000..1d1616bb --- /dev/null +++ b/pkg/config/plugin_test.go @@ -0,0 +1,241 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package config_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/config" + "os" + "path/filepath" +) + +var allDifferentPathsConfig = config.Plugin{ + Transformers: map[string]config.Transformer{ + "transformer1": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer2": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path2", + MigrationRank: 2, + RepositoryPath: "test/repo/path", + }, + "transformer3": { + Path: "test/init/path2", + Type: config.EthEvent, + MigrationPath: "test/migration/path3", + MigrationRank: 1, + RepositoryPath: "test/repo/path", + }, + }, +} + +var overlappingPathsConfig = config.Plugin{ + Transformers: map[string]config.Transformer{ + "transformer1": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer2": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer3": { + Path: "test/init/path2", + Type: config.EthEvent, + MigrationPath: "test/migration/path3", + MigrationRank: 1, + RepositoryPath: "test/repo/path", + }, + }, +} + +var conflictErrorConfig = config.Plugin{ + Transformers: map[string]config.Transformer{ + "transformer1": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer2": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path2", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer3": { + Path: "test/init/path2", + Type: config.EthEvent, + MigrationPath: "test/migration/path3", + MigrationRank: 1, + RepositoryPath: "test/repo/path", + }, + }, +} + +var gapErrorConfig = config.Plugin{ + Transformers: map[string]config.Transformer{ + "transformer1": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer2": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path2", + MigrationRank: 3, + RepositoryPath: "test/repo/path", + }, + "transformer3": { + Path: "test/init/path2", + Type: config.EthEvent, + MigrationPath: "test/migration/path3", + MigrationRank: 1, + RepositoryPath: "test/repo/path", + }, + }, +} + +var missingRankErrorConfig = config.Plugin{ + Transformers: map[string]config.Transformer{ + "transformer1": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer2": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path2", + RepositoryPath: "test/repo/path", + }, + "transformer3": { + Path: "test/init/path2", + Type: config.EthEvent, + MigrationPath: "test/migration/path3", + MigrationRank: 1, + RepositoryPath: "test/repo/path", + }, + }, +} + +var duplicateErrorConfig = config.Plugin{ + Transformers: map[string]config.Transformer{ + "transformer1": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + MigrationRank: 0, + RepositoryPath: "test/repo/path", + }, + "transformer2": { + Path: "test/init/path", + Type: config.EthEvent, + MigrationPath: "test/migration/path1", + RepositoryPath: "test/repo/path", + MigrationRank: 2, + }, + "transformer3": { + Path: "test/init/path2", + Type: config.EthEvent, + MigrationPath: "test/migration/path3", + MigrationRank: 1, + RepositoryPath: "test/repo/path", + }, + }, +} + +var _ = Describe("GetMigrationsPaths", func() { + It("Sorts migration paths by rank", func() { + plugin := allDifferentPathsConfig + migrationPaths, err := plugin.GetMigrationsPaths() + Expect(err).ToNot(HaveOccurred()) + Expect(len(migrationPaths)).To(Equal(3)) + + env := os.Getenv("GOPATH") + path1 := filepath.Join(env, "src/vendor/test/repo/path/test/migration/path1") + path2 := filepath.Join(env, "src/vendor/test/repo/path/test/migration/path3") + path3 := filepath.Join(env, "src/vendor/test/repo/path/test/migration/path2") + expectedMigrationPaths := []string{path1, path2, path3} + Expect(migrationPaths).To(Equal(expectedMigrationPaths)) + }) + + It("Expects identical migration paths to have the same rank", func() { + plugin := overlappingPathsConfig + migrationPaths, err := plugin.GetMigrationsPaths() + Expect(err).ToNot(HaveOccurred()) + Expect(len(migrationPaths)).To(Equal(2)) + + env := os.Getenv("GOPATH") + path1 := filepath.Join(env, "src/vendor/test/repo/path/test/migration/path1") + path2 := filepath.Join(env, "src/vendor/test/repo/path/test/migration/path3") + expectedMigrationPaths := []string{path1, path2} + Expect(migrationPaths).To(Equal(expectedMigrationPaths)) + }) + + It("Fails if two different migration paths have the same rank", func() { + plugin := conflictErrorConfig + migrationPaths, err := plugin.GetMigrationsPaths() + Expect(err).To(HaveOccurred()) + Expect(len(migrationPaths)).To(Equal(0)) + Expect(err.Error()).To(ContainSubstring("has the same migration rank")) + }) + + It("Fails if there is a gap in the ranks of the migration paths", func() { + plugin := gapErrorConfig + migrationPaths, err := plugin.GetMigrationsPaths() + Expect(err).To(HaveOccurred()) + Expect(len(migrationPaths)).To(Equal(0)) + Expect(err.Error()).To(ContainSubstring("number of distinct ranks does not match number of distinct migration paths")) + }) + + It("Fails if a transformer is missing its rank", func() { + plugin := missingRankErrorConfig + migrationPaths, err := plugin.GetMigrationsPaths() + Expect(err).To(HaveOccurred()) + Expect(len(migrationPaths)).To(Equal(0)) + Expect(err.Error()).To(ContainSubstring("has the same migration rank")) + }) + + It("Fails if the same migration path has more than one rank", func() { + plugin := duplicateErrorConfig + migrationPaths, err := plugin.GetMigrationsPaths() + Expect(err).To(HaveOccurred()) + Expect(len(migrationPaths)).To(Equal(0)) + Expect(err.Error()).To(ContainSubstring("duplicate paths with different ranks present")) + }) +}) diff --git a/pkg/omni/full/converter/converter.go b/pkg/contract_watcher/full/converter/converter.go similarity index 82% rename from pkg/omni/full/converter/converter.go rename to pkg/contract_watcher/full/converter/converter.go index dd5b9725..09bae256 100644 --- a/pkg/omni/full/converter/converter.go +++ b/pkg/contract_watcher/full/converter/converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -26,39 +26,33 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) // Converter is used to convert watched event logs to // custom logs containing event input name => value maps -type Converter interface { +type ConverterInterface interface { Convert(watchedEvent core.WatchedEvent, event types.Event) (*types.Log, error) Update(info *contract.Contract) } -type converter struct { +type Converter struct { ContractInfo *contract.Contract } -func NewConverter(info *contract.Contract) *converter { - return &converter{ - ContractInfo: info, - } -} - -func (c *converter) Update(info *contract.Contract) { +func (c *Converter) Update(info *contract.Contract) { c.ContractInfo = info } // Convert the given watched event log into a types.Log for the given event -func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (*types.Log, error) { - contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil) +func (c *Converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (*types.Log, error) { + boundContract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil) values := make(map[string]interface{}) log := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLogIntoMap(values, event.Name, log) + err := boundContract.UnpackLogIntoMap(values, event.Name, log) if err != nil { return nil, err } diff --git a/pkg/omni/full/converter/converter_suite_test.go b/pkg/contract_watcher/full/converter/converter_suite_test.go similarity index 96% rename from pkg/omni/full/converter/converter_suite_test.go rename to pkg/contract_watcher/full/converter/converter_suite_test.go index 93fd8aef..e8cb72e6 100644 --- a/pkg/omni/full/converter/converter_suite_test.go +++ b/pkg/contract_watcher/full/converter/converter_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/full/converter/converter_test.go b/pkg/contract_watcher/full/converter/converter_test.go similarity index 83% rename from pkg/omni/full/converter/converter_test.go rename to pkg/contract_watcher/full/converter/converter_test.go index e35780b8..864a53a2 100644 --- a/pkg/omni/full/converter/converter_test.go +++ b/pkg/contract_watcher/full/converter/converter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -21,11 +21,11 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/omni/full/converter" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/converter" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" ) var _ = Describe("Converter", func() { @@ -39,7 +39,8 @@ var _ = Describe("Converter", func() { Describe("Update", func() { It("Updates contract con held by the converter", func() { - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) Expect(c.ContractInfo).To(Equal(con)) con := test_helpers.SetupTusdContract([]string{}, []string{}) @@ -58,7 +59,8 @@ var _ = Describe("Converter", func() { err = con.GenerateFilters() Expect(err).ToNot(HaveOccurred()) - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) log, err := c.Convert(mocks.MockTranferEvent, event) Expect(err).ToNot(HaveOccurred()) @@ -77,7 +79,8 @@ var _ = Describe("Converter", func() { event, ok := con.Events["Transfer"] Expect(ok).To(Equal(true)) - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) _, err := c.Convert(mocks.MockTranferEvent, event) Expect(err).ToNot(HaveOccurred()) @@ -101,7 +104,8 @@ var _ = Describe("Converter", func() { It("Fails with an empty contract", func() { event := con.Events["Transfer"] - c := converter.NewConverter(&contract.Contract{}) + c := converter.Converter{} + c.Update(&contract.Contract{}) _, err = c.Convert(mocks.MockTranferEvent, event) Expect(err).To(HaveOccurred()) }) diff --git a/pkg/omni/full/retriever/block_retriever.go b/pkg/contract_watcher/full/retriever/block_retriever.go similarity index 96% rename from pkg/omni/full/retriever/block_retriever.go rename to pkg/contract_watcher/full/retriever/block_retriever.go index f4c3ac5d..2f595cb2 100644 --- a/pkg/omni/full/retriever/block_retriever.go +++ b/pkg/contract_watcher/full/retriever/block_retriever.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -53,7 +53,7 @@ func (r *blockRetriever) retrieveFirstBlockFromReceipts(contractAddr string) (in err := r.db.Get( &firstBlock, `SELECT number FROM blocks - WHERE id = (SELECT block_id FROM receipts + WHERE id = (SELECT block_id FROM full_sync_receipts WHERE lower(contract_address) = $1 ORDER BY block_id ASC LIMIT 1)`, diff --git a/pkg/omni/full/retriever/block_retriever_test.go b/pkg/contract_watcher/full/retriever/block_retriever_test.go similarity index 69% rename from pkg/omni/full/retriever/block_retriever_test.go rename to pkg/contract_watcher/full/retriever/block_retriever_test.go index caa1a1ed..f0255db0 100644 --- a/pkg/omni/full/retriever/block_retriever_test.go +++ b/pkg/contract_watcher/full/retriever/block_retriever_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,34 +17,40 @@ package retriever_test import ( + "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "strings" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/full/retriever" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" ) var _ = Describe("Block Retriever", func() { var db *postgres.DB var r retriever.BlockRetriever + var rawTransaction []byte var blockRepository repositories.BlockRepository // Contains no contract address var block1 = core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ert", Number: 1, - Transactions: []core.Transaction{}, + Transactions: []core.TransactionModel{}, } BeforeEach(func() { db, _ = test_helpers.SetupDBandBC() blockRepository = *repositories.NewBlockRepository(db) r = retriever.NewBlockRetriever(db) + gethTransaction := types.Transaction{} + var err error + rawTransaction, err = gethTransaction.MarshalJSON() + Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { @@ -53,18 +59,23 @@ var _ = Describe("Block Retriever", func() { Describe("RetrieveFirstBlock", func() { It("Retrieves block number where contract first appears in receipt, if available", func() { - // Contains the address in the receipt block2 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ert", Number: 2, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Transactions: []core.TransactionModel{{ + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + GasPrice: 0, + GasLimit: 0, + Nonce: 0, + Raw: rawTransaction, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", ContractAddress: constants.TusdContractAddress, Logs: []core.Log{}, }, + TxIndex: 0, + Value: "0", }}, } @@ -72,8 +83,12 @@ var _ = Describe("Block Retriever", func() { block3 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad456yui", Number: 3, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", + Transactions: []core.TransactionModel{{ + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", + GasPrice: 0, + GasLimit: 0, + Nonce: 0, + Raw: rawTransaction, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", ContractAddress: constants.TusdContractAddress, @@ -91,12 +106,17 @@ var _ = Describe("Block Retriever", func() { Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", }}, }, + TxIndex: 0, + Value: "0", }}, } - blockRepository.CreateOrUpdateBlock(block1) - blockRepository.CreateOrUpdateBlock(block2) - blockRepository.CreateOrUpdateBlock(block3) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(block1) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(block2) + Expect(insertErrTwo).NotTo(HaveOccurred()) + _, insertErrThree := blockRepository.CreateOrUpdateBlock(block3) + Expect(insertErrThree).NotTo(HaveOccurred()) i, err := r.RetrieveFirstBlock(strings.ToLower(constants.TusdContractAddress)) Expect(err).NotTo(HaveOccurred()) @@ -104,12 +124,15 @@ var _ = Describe("Block Retriever", func() { }) It("Retrieves block number where contract first appears in event logs if it cannot find the address in a receipt", func() { - block2 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ert", Number: 2, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Transactions: []core.TransactionModel{{ + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + GasPrice: 0, + GasLimit: 0, + Nonce: 0, + Raw: rawTransaction, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", ContractAddress: "", @@ -127,14 +150,20 @@ var _ = Describe("Block Retriever", func() { Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", }}, }, + TxIndex: 0, + Value: "0", }}, } block3 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad456yui", Number: 3, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", + Transactions: []core.TransactionModel{{ + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", + GasPrice: 0, + GasLimit: 0, + Nonce: 0, + Raw: rawTransaction, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", ContractAddress: "", @@ -152,12 +181,17 @@ var _ = Describe("Block Retriever", func() { Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", }}, }, + TxIndex: 0, + Value: "0", }}, } - blockRepository.CreateOrUpdateBlock(block1) - blockRepository.CreateOrUpdateBlock(block2) - blockRepository.CreateOrUpdateBlock(block3) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(block1) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(block2) + Expect(insertErrTwo).NotTo(HaveOccurred()) + _, insertErrThree := blockRepository.CreateOrUpdateBlock(block3) + Expect(insertErrThree).NotTo(HaveOccurred()) i, err := r.RetrieveFirstBlock(constants.DaiContractAddress) Expect(err).NotTo(HaveOccurred()) @@ -168,18 +202,21 @@ var _ = Describe("Block Retriever", func() { block2 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ert", Number: 2, - Transactions: []core.Transaction{}, + Transactions: []core.TransactionModel{}, } block3 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad456yui", Number: 3, - Transactions: []core.Transaction{}, + Transactions: []core.TransactionModel{}, } - blockRepository.CreateOrUpdateBlock(block1) - blockRepository.CreateOrUpdateBlock(block2) - blockRepository.CreateOrUpdateBlock(block3) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(block1) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(block2) + Expect(insertErrTwo).NotTo(HaveOccurred()) + _, insertErrThree := blockRepository.CreateOrUpdateBlock(block3) + Expect(insertErrThree).NotTo(HaveOccurred()) _, err := r.RetrieveFirstBlock(constants.DaiContractAddress) Expect(err).To(HaveOccurred()) @@ -191,18 +228,21 @@ var _ = Describe("Block Retriever", func() { block2 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ert", Number: 2, - Transactions: []core.Transaction{}, + Transactions: []core.TransactionModel{}, } block3 := core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad456yui", Number: 3, - Transactions: []core.Transaction{}, + Transactions: []core.TransactionModel{}, } - blockRepository.CreateOrUpdateBlock(block1) - blockRepository.CreateOrUpdateBlock(block2) - blockRepository.CreateOrUpdateBlock(block3) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(block1) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(block2) + Expect(insertErrTwo).NotTo(HaveOccurred()) + _, insertErrThree := blockRepository.CreateOrUpdateBlock(block3) + Expect(insertErrThree).NotTo(HaveOccurred()) i, err := r.RetrieveMostRecentBlock() Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/omni/full/retriever/retriever_suite_test.go b/pkg/contract_watcher/full/retriever/retriever_suite_test.go similarity index 90% rename from pkg/omni/full/retriever/retriever_suite_test.go rename to pkg/contract_watcher/full/retriever/retriever_suite_test.go index 948f5e8e..005d2817 100644 --- a/pkg/omni/full/retriever/retriever_suite_test.go +++ b/pkg/contract_watcher/full/retriever/retriever_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package retriever_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -31,5 +31,5 @@ func TestRetriever(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/contract_watcher/full/transformer/transformer.go b/pkg/contract_watcher/full/transformer/transformer.go new file mode 100644 index 00000000..ad2bba69 --- /dev/null +++ b/pkg/contract_watcher/full/transformer/transformer.go @@ -0,0 +1,226 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package transformer + +import ( + "errors" + + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/converter" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/parser" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/poller" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" +) + +// Requires a fully synced vDB and a running eth node (or infura) +type Transformer struct { + // Database interfaces + FilterRepository datastore.FilterRepository // Log filters repo; accepts filters generated by Contract.GenerateFilters() + WatchedEventRepository datastore.WatchedEventRepository // Watched event log views, created by the log filters + TransformedEventRepository repository.EventRepository // Holds transformed watched event log data + + // Pre-processing interfaces + Parser parser.Parser // Parses events and methods out of contract abi fetched using contract address + Retriever retriever.BlockRetriever // Retrieves first block for contract and current block height + + // Processing interfaces + Converter converter.ConverterInterface // Converts watched event logs into custom log + Poller poller.Poller // Polls methods using contract's token holder addresses and persists them using method datastore + + // Store contract configuration information + Config config.ContractConfig + + // Store contract info as mapping to contract address + Contracts map[string]*contract.Contract + + // Latest block in the block repository + LastBlock int64 +} + +// Transformer takes in config for blockchain, database, and network id +func NewTransformer(con config.ContractConfig, BC core.BlockChain, DB *postgres.DB) *Transformer { + return &Transformer{ + Poller: poller.NewPoller(BC, DB, types.FullSync), + Parser: parser.NewParser(con.Network), + Retriever: retriever.NewBlockRetriever(DB), + Converter: &converter.Converter{}, + Contracts: map[string]*contract.Contract{}, + WatchedEventRepository: repositories.WatchedEventRepository{DB: DB}, + FilterRepository: repositories.FilterRepository{DB: DB}, + TransformedEventRepository: repository.NewEventRepository(DB, types.FullSync), + Config: con, + } +} + +// Use after creating and setting transformer +// Loops over all of the addr => filter sets +// Uses parser to pull event info from abi +// Use this info to generate event filters +func (tr *Transformer) Init() error { + for contractAddr := range tr.Config.Addresses { + // Configure Abi + if tr.Config.Abis[contractAddr] == "" { + // If no abi is given in the config, this method will try fetching from internal look-up table and etherscan + err := tr.Parser.Parse(contractAddr) + if err != nil { + return err + } + } else { + // If we have an abi from the config, load that into the parser + err := tr.Parser.ParseAbiStr(tr.Config.Abis[contractAddr]) + if err != nil { + return err + } + } + + // Get first block and most recent block number in the header repo + firstBlock, err := tr.Retriever.RetrieveFirstBlock(contractAddr) + if err != nil { + return err + } + // Set to specified range if it falls within the bounds + if firstBlock < tr.Config.StartingBlocks[contractAddr] { + firstBlock = tr.Config.StartingBlocks[contractAddr] + } + + // Get contract name if it has one + var name = new(string) + tr.Poller.FetchContractData(tr.Parser.Abi(), contractAddr, "name", nil, name, tr.LastBlock) + + // Remove any potential accidental duplicate inputs in arg filter values + eventArgs := map[string]bool{} + for _, arg := range tr.Config.EventArgs[contractAddr] { + eventArgs[arg] = true + } + methodArgs := map[string]bool{} + for _, arg := range tr.Config.MethodArgs[contractAddr] { + methodArgs[arg] = true + } + + // Aggregate info into contract object + info := contract.Contract{ + Name: *name, + Network: tr.Config.Network, + Address: contractAddr, + Abi: tr.Parser.Abi(), + ParsedAbi: tr.Parser.ParsedAbi(), + StartingBlock: firstBlock, + Events: tr.Parser.GetEvents(tr.Config.Events[contractAddr]), + Methods: tr.Parser.GetSelectMethods(tr.Config.Methods[contractAddr]), + FilterArgs: eventArgs, + MethodArgs: methodArgs, + Piping: tr.Config.Piping[contractAddr], + }.Init() + + // Use info to create filters + err = info.GenerateFilters() + if err != nil { + return err + } + + // Iterate over filters and push them to the repo using filter repository interface + for _, filter := range info.Filters { + err = tr.FilterRepository.CreateFilter(filter) + if err != nil { + return err + } + } + + // Store contract info for further processing + tr.Contracts[contractAddr] = info + } + + // Get the most recent block number in the block repo + var err error + tr.LastBlock, err = tr.Retriever.RetrieveMostRecentBlock() + if err != nil { + return err + } + + return nil +} + +// Iterates through stored, initialized contract objects +// Iterates through contract's event filters, grabbing watched event logs +// Uses converter to convert logs into custom log type +// Persists converted logs into custuom postgres tables +// Calls selected methods, using token holder address generated during event log conversion +func (tr *Transformer) Execute() error { + if len(tr.Contracts) == 0 { + return errors.New("error: transformer has no initialized contracts to work with") + } + // Iterate through all internal contracts + for _, con := range tr.Contracts { + // Update converter with current contract + tr.Converter.Update(con) + + // Iterate through contract filters and get watched event logs + for eventSig, filter := range con.Filters { + watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name) + if err != nil { + return err + } + + // Iterate over watched event logs + for _, we := range watchedEvents { + // Convert them to our custom log type + cstm, err := tr.Converter.Convert(*we, con.Events[eventSig]) + if err != nil { + return err + } + if cstm == nil { + continue + } + + // If log is not empty, immediately persist in repo + // Run this in seperate goroutine? + err = tr.TransformedEventRepository.PersistLogs([]types.Log{*cstm}, con.Events[eventSig], con.Address, con.Name) + if err != nil { + return err + } + } + } + + // After persisting all watched event logs + // poller polls select contract methods + // and persists the results into custom pg tables + if err := tr.Poller.PollContract(*con, tr.LastBlock); err != nil { + return err + } + } + + // At the end of a transformation cycle, and before the next + // update the latest block from the block repo + var err error + tr.LastBlock, err = tr.Retriever.RetrieveMostRecentBlock() + if err != nil { + return err + } + + return nil +} + +func (tr *Transformer) GetConfig() config.ContractConfig { + return tr.Config +} diff --git a/pkg/omni/full/transformer/transformer_suite_test.go b/pkg/contract_watcher/full/transformer/transformer_suite_test.go similarity index 90% rename from pkg/omni/full/transformer/transformer_suite_test.go rename to pkg/contract_watcher/full/transformer/transformer_suite_test.go index 1f362f2b..42d0ffb0 100644 --- a/pkg/omni/full/transformer/transformer_suite_test.go +++ b/pkg/contract_watcher/full/transformer/transformer_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package transformer_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -31,5 +31,5 @@ func TestTransformer(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/contract_watcher/full/transformer/transformer_test.go b/pkg/contract_watcher/full/transformer/transformer_test.go new file mode 100644 index 00000000..ac03e1a6 --- /dev/null +++ b/pkg/contract_watcher/full/transformer/transformer_test.go @@ -0,0 +1,98 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package transformer_test + +import ( + "math/rand" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/parser" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/poller" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" + "github.com/vulcanize/vulcanizedb/pkg/fakes" +) + +var _ = Describe("Transformer", func() { + var fakeAddress = "0x1234567890abcdef" + rand.Seed(time.Now().UnixNano()) + + Describe("Init", func() { + It("Initializes transformer's contract objects", func() { + blockRetriever := &fakes.MockFullBlockRetriever{} + firstBlock := int64(1) + mostRecentBlock := int64(2) + blockRetriever.FirstBlock = firstBlock + blockRetriever.MostRecentBlock = mostRecentBlock + + parsr := &fakes.MockParser{} + fakeAbi := "fake_abi" + eventName := "Transfer" + event := types.Event{} + parsr.AbiToReturn = fakeAbi + parsr.EventName = eventName + parsr.Event = event + + pollr := &fakes.MockPoller{} + fakeContractName := "fake_contract_name" + pollr.ContractName = fakeContractName + + t := getTransformer(blockRetriever, parsr, pollr) + + err := t.Init() + + Expect(err).ToNot(HaveOccurred()) + + c, ok := t.Contracts[fakeAddress] + Expect(ok).To(Equal(true)) + + Expect(c.StartingBlock).To(Equal(firstBlock)) + Expect(t.LastBlock).To(Equal(mostRecentBlock)) + Expect(c.Abi).To(Equal(fakeAbi)) + Expect(c.Name).To(Equal(fakeContractName)) + Expect(c.Address).To(Equal(fakeAddress)) + }) + + It("Fails to initialize if first and most recent blocks cannot be fetched from vDB", func() { + blockRetriever := &fakes.MockFullBlockRetriever{} + blockRetriever.FirstBlockErr = fakes.FakeError + t := getTransformer(blockRetriever, &fakes.MockParser{}, &fakes.MockPoller{}) + + err := t.Init() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + }) +}) + +func getTransformer(blockRetriever retriever.BlockRetriever, parsr parser.Parser, pollr poller.Poller) transformer.Transformer { + return transformer.Transformer{ + FilterRepository: &fakes.MockFilterRepository{}, + Parser: parsr, + Retriever: blockRetriever, + Poller: pollr, + Contracts: map[string]*contract.Contract{}, + Config: mocks.MockConfig, + } +} diff --git a/pkg/omni/light/converter/converter.go b/pkg/contract_watcher/light/converter/converter.go similarity index 90% rename from pkg/omni/light/converter/converter.go rename to pkg/contract_watcher/light/converter/converter.go index 3deba288..3a62c807 100644 --- a/pkg/omni/light/converter/converter.go +++ b/pkg/contract_watcher/light/converter/converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -28,33 +28,27 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" ) -type Converter interface { +type ConverterInterface interface { Convert(logs []gethTypes.Log, event types.Event, headerID int64) ([]types.Log, error) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) Update(info *contract.Contract) } -type converter struct { +type Converter struct { ContractInfo *contract.Contract } -func NewConverter(info *contract.Contract) *converter { - return &converter{ - ContractInfo: info, - } -} - -func (c *converter) Update(info *contract.Contract) { +func (c *Converter) Update(info *contract.Contract) { c.ContractInfo = info } // Convert the given watched event log into a types.Log for the given event -func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID int64) ([]types.Log, error) { - contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil) +func (c *Converter) Convert(logs []gethTypes.Log, event types.Event, headerID int64) ([]types.Log, error) { + boundContract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil) returnLogs := make([]types.Log, 0, len(logs)) for _, log := range logs { values := make(map[string]interface{}) @@ -63,7 +57,7 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in values[field.Name] = i } - err := contract.UnpackLogIntoMap(values, event.Name, log) + err := boundContract.UnpackLogIntoMap(values, event.Name, log) if err != nil { return nil, err } @@ -132,7 +126,7 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in } // Convert the given watched event logs into types.Logs; returns a map of event names to a slice of their converted logs -func (c *converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) { +func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) { contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil) eventsToLogs := make(map[string][]types.Log) for _, event := range events { diff --git a/pkg/omni/light/converter/converter_suite_test.go b/pkg/contract_watcher/light/converter/converter_suite_test.go similarity index 96% rename from pkg/omni/light/converter/converter_suite_test.go rename to pkg/contract_watcher/light/converter/converter_suite_test.go index d69367df..98964a11 100644 --- a/pkg/omni/light/converter/converter_suite_test.go +++ b/pkg/contract_watcher/light/converter/converter_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/light/converter/converter_test.go b/pkg/contract_watcher/light/converter/converter_test.go similarity index 88% rename from pkg/omni/light/converter/converter_test.go rename to pkg/contract_watcher/light/converter/converter_test.go index 374bb699..769fe057 100644 --- a/pkg/omni/light/converter/converter_test.go +++ b/pkg/contract_watcher/light/converter/converter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,11 +22,11 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/converter" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/converter" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" ) var _ = Describe("Converter", func() { @@ -38,7 +38,8 @@ var _ = Describe("Converter", func() { Describe("Update", func() { It("Updates contract info held by the converter", func() { con = test_helpers.SetupTusdContract(tusdWantedEvents, []string{}) - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) Expect(c.ContractInfo).To(Equal(con)) info := test_helpers.SetupTusdContract([]string{}, []string{}) @@ -56,7 +57,8 @@ var _ = Describe("Converter", func() { event, ok := con.Events["Transfer"] Expect(ok).To(Equal(true)) - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) logs, err := c.Convert([]types.Log{mocks.MockTransferLog1, mocks.MockTransferLog2}, event, 232) Expect(err).ToNot(HaveOccurred()) Expect(len(logs)).To(Equal(2)) @@ -80,7 +82,8 @@ var _ = Describe("Converter", func() { event, ok := con.Events["Transfer"] Expect(ok).To(Equal(true)) - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) _, err := c.Convert([]types.Log{mocks.MockTransferLog1, mocks.MockTransferLog2}, event, 232) Expect(err).ToNot(HaveOccurred()) @@ -110,7 +113,8 @@ var _ = Describe("Converter", func() { event, ok := con.Events["NewOwner"] Expect(ok).To(Equal(true)) - c := converter.NewConverter(con) + c := converter.Converter{} + c.Update(con) _, err := c.Convert([]types.Log{mocks.MockNewOwnerLog1, mocks.MockNewOwnerLog2}, event, 232) Expect(err).ToNot(HaveOccurred()) Expect(len(con.EmittedHashes)).To(Equal(3)) @@ -143,7 +147,8 @@ var _ = Describe("Converter", func() { It("Fails with an empty contract", func() { event := con.Events["Transfer"] - c := converter.NewConverter(&contract.Contract{}) + c := converter.Converter{} + c.Update(&contract.Contract{}) _, err = c.Convert([]types.Log{mocks.MockTransferLog1}, event, 232) Expect(err).To(HaveOccurred()) }) diff --git a/pkg/omni/light/fetcher/fetcher.go b/pkg/contract_watcher/light/fetcher/fetcher.go similarity index 98% rename from pkg/omni/light/fetcher/fetcher.go rename to pkg/contract_watcher/light/fetcher/fetcher.go index 77162f0e..bfecf807 100644 --- a/pkg/omni/light/fetcher/fetcher.go +++ b/pkg/contract_watcher/light/fetcher/fetcher.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/light/fetcher/fetcher_suite_test.go b/pkg/contract_watcher/light/fetcher/fetcher_suite_test.go similarity index 96% rename from pkg/omni/light/fetcher/fetcher_suite_test.go rename to pkg/contract_watcher/light/fetcher/fetcher_suite_test.go index 3b60a906..031d15fc 100644 --- a/pkg/omni/light/fetcher/fetcher_suite_test.go +++ b/pkg/contract_watcher/light/fetcher/fetcher_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/light/fetcher/fetcher_test.go b/pkg/contract_watcher/light/fetcher/fetcher_test.go similarity index 95% rename from pkg/omni/light/fetcher/fetcher_test.go rename to pkg/contract_watcher/light/fetcher/fetcher_test.go index 8dca9ca8..b3b9b96c 100644 --- a/pkg/omni/light/fetcher/fetcher_test.go +++ b/pkg/contract_watcher/light/fetcher/fetcher_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,9 +22,9 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/fetcher" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/fakes" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/fetcher" ) var _ = Describe("Fetcher", func() { diff --git a/pkg/omni/light/repository/header_repository.go b/pkg/contract_watcher/light/repository/header_repository.go similarity index 73% rename from pkg/omni/light/repository/header_repository.go rename to pkg/contract_watcher/light/repository/header_repository.go index c26b3e60..91b8cd8c 100644 --- a/pkg/omni/light/repository/header_repository.go +++ b/pkg/contract_watcher/light/repository/header_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,10 +17,10 @@ package repository import ( - "database/sql" "fmt" "github.com/hashicorp/golang-lru" + "github.com/jmoiron/sqlx" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" @@ -53,6 +53,7 @@ func NewHeaderRepository(db *postgres.DB) *headerRepository { } } +// Adds a checked_header column for the provided column id func (r *headerRepository) AddCheckColumn(id string) error { // Check cache to see if column already exists before querying pg _, ok := r.columns.Get(id) @@ -61,7 +62,7 @@ func (r *headerRepository) AddCheckColumn(id string) error { } pgStr := "ALTER TABLE public.checked_headers ADD COLUMN IF NOT EXISTS " - pgStr = pgStr + id + " BOOLEAN NOT NULL DEFAULT FALSE" + pgStr = pgStr + id + " INTEGER NOT NULL DEFAULT 0" _, err := r.db.Exec(pgStr) if err != nil { return err @@ -73,6 +74,7 @@ func (r *headerRepository) AddCheckColumn(id string) error { return nil } +// Adds a checked_header column for all of the provided column ids func (r *headerRepository) AddCheckColumns(ids []string) error { var err error baseQuery := "ALTER TABLE public.checked_headers" @@ -80,7 +82,7 @@ func (r *headerRepository) AddCheckColumns(ids []string) error { for _, id := range ids { _, ok := r.columns.Get(id) if !ok { - baseQuery += " ADD COLUMN IF NOT EXISTS " + id + " BOOLEAN NOT NULL DEFAULT FALSE," + baseQuery += " ADD COLUMN IF NOT EXISTS " + id + " INTEGER NOT NULL DEFAULT 0," input = append(input, id) } } @@ -96,15 +98,16 @@ func (r *headerRepository) AddCheckColumns(ids []string) error { return err } +// Marks the header checked for the provided column id func (r *headerRepository) MarkHeaderChecked(headerID int64, id string) error { _, err := r.db.Exec(`INSERT INTO public.checked_headers (header_id, `+id+`) VALUES ($1, $2) ON CONFLICT (header_id) DO - UPDATE SET `+id+` = $2`, headerID, true) - + UPDATE SET `+id+` = checked_headers.`+id+` + 1`, headerID, 1) return err } +// Marks the header checked for all of the provided column ids func (r *headerRepository) MarkHeaderCheckedForAll(headerID int64, ids []string) error { pgStr := "INSERT INTO public.checked_headers (header_id, " for _, id := range ids { @@ -112,24 +115,23 @@ func (r *headerRepository) MarkHeaderCheckedForAll(headerID int64, ids []string) } pgStr = pgStr[:len(pgStr)-2] + ") VALUES ($1, " for i := 0; i < len(ids); i++ { - pgStr += "true, " + pgStr += "1, " } pgStr = pgStr[:len(pgStr)-2] + ") ON CONFLICT (header_id) DO UPDATE SET " for _, id := range ids { - pgStr += fmt.Sprintf("%s = true, ", id) + pgStr += id + `= checked_headers.` + id + ` + 1, ` } pgStr = pgStr[:len(pgStr)-2] _, err := r.db.Exec(pgStr, headerID) - return err } +// Marks all of the provided headers checked for each of the provided column ids func (r *headerRepository) MarkHeadersCheckedForAll(headers []core.Header, ids []string) error { - tx, err := r.db.Begin() + tx, err := r.db.Beginx() if err != nil { return err } - for _, header := range headers { pgStr := "INSERT INTO public.checked_headers (header_id, " for _, id := range ids { @@ -137,11 +139,11 @@ func (r *headerRepository) MarkHeadersCheckedForAll(headers []core.Header, ids [ } pgStr = pgStr[:len(pgStr)-2] + ") VALUES ($1, " for i := 0; i < len(ids); i++ { - pgStr += "true, " + pgStr += "1, " } pgStr = pgStr[:len(pgStr)-2] + ") ON CONFLICT (header_id) DO UPDATE SET " for _, id := range ids { - pgStr += fmt.Sprintf("%s = true, ", id) + pgStr += fmt.Sprintf("%s = checked_headers.%s + 1, ", id, id) } pgStr = pgStr[:len(pgStr)-2] _, err = tx.Exec(pgStr, header.Id) @@ -150,19 +152,19 @@ func (r *headerRepository) MarkHeadersCheckedForAll(headers []core.Header, ids [ return err } } - - return tx.Commit() + err = tx.Commit() + return err } +// Returns missing headers for the provided checked_headers column id func (r *headerRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64, id string) ([]core.Header, error) { var result []core.Header var query string var err error - if endingBlockNumber == -1 { query = `SELECT headers.id, headers.block_number, headers.hash FROM headers LEFT JOIN checked_headers on headers.id = header_id - WHERE (header_id ISNULL OR ` + id + ` IS FALSE) + WHERE (header_id ISNULL OR checked_headers.` + id + `=0) AND headers.block_number >= $1 AND headers.eth_node_fingerprint = $2 ORDER BY headers.block_number` @@ -170,29 +172,27 @@ func (r *headerRepository) MissingHeaders(startingBlockNumber, endingBlockNumber } else { query = `SELECT headers.id, headers.block_number, headers.hash FROM headers LEFT JOIN checked_headers on headers.id = header_id - WHERE (header_id ISNULL OR ` + id + ` IS FALSE) + WHERE (header_id ISNULL OR checked_headers.` + id + `=0) AND headers.block_number >= $1 AND headers.block_number <= $2 AND headers.eth_node_fingerprint = $3 ORDER BY headers.block_number` err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID) } - - return result, err + return contiguousHeaders(result, startingBlockNumber), err } +// Returns missing headers for all of the provided checked_headers column ids func (r *headerRepository) MissingHeadersForAll(startingBlockNumber, endingBlockNumber int64, ids []string) ([]core.Header, error) { var result []core.Header var query string var err error - baseQuery := `SELECT headers.id, headers.block_number, headers.hash FROM headers LEFT JOIN checked_headers on headers.id = header_id WHERE (header_id ISNULL` for _, id := range ids { - baseQuery += ` OR ` + id + ` IS FALSE` + baseQuery += ` OR checked_headers.` + id + `= 0` } - if endingBlockNumber == -1 { endStr := `) AND headers.block_number >= $1 AND headers.eth_node_fingerprint = $2 @@ -207,27 +207,44 @@ func (r *headerRepository) MissingHeadersForAll(startingBlockNumber, endingBlock query = baseQuery + endStr err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID) } - - return result, err + return contiguousHeaders(result, startingBlockNumber), err } +// Returns a continuous set of headers that is contiguous with the provided startingBlockNumber +func contiguousHeaders(headers []core.Header, startingBlockNumber int64) []core.Header { + if len(headers) < 1 { + return headers + } + previousHeader := headers[0].BlockNumber + if previousHeader != startingBlockNumber { + return []core.Header{} + } + for i := 1; i < len(headers); i++ { + previousHeader++ + if headers[i].BlockNumber != previousHeader { + return headers[:i] + } + } + + return headers +} + +// Returns headers that have been checked for all of the provided event ids but not for the provided method ids func (r *headerRepository) MissingMethodsCheckedEventsIntersection(startingBlockNumber, endingBlockNumber int64, methodIds, eventIds []string) ([]core.Header, error) { var result []core.Header var query string var err error - baseQuery := `SELECT headers.id, headers.block_number, headers.hash FROM headers LEFT JOIN checked_headers on headers.id = header_id WHERE (header_id IS NOT NULL` for _, id := range eventIds { - baseQuery += ` AND ` + id + ` IS TRUE` + baseQuery += ` AND ` + id + `!=0` } baseQuery += `) AND (` for _, id := range methodIds { - baseQuery += id + ` IS FALSE AND ` + baseQuery += id + ` =0 AND ` } baseQuery = baseQuery[:len(baseQuery)-5] + `) ` - if endingBlockNumber == -1 { endStr := `AND headers.block_number >= $1 AND headers.eth_node_fingerprint = $2 @@ -242,18 +259,35 @@ func (r *headerRepository) MissingMethodsCheckedEventsIntersection(startingBlock query = baseQuery + endStr err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID) } - - return result, err + return continuousHeaders(result), err } +// Returns a continuous set of headers +func continuousHeaders(headers []core.Header) []core.Header { + if len(headers) < 1 { + return headers + } + previousHeader := headers[0].BlockNumber + for i := 1; i < len(headers); i++ { + previousHeader++ + if headers[i].BlockNumber != previousHeader { + return headers[:i] + } + } + + return headers +} + +// Check the repositories column id cache for a value func (r *headerRepository) CheckCache(key string) (interface{}, bool) { return r.columns.Get(key) } -func MarkHeaderCheckedInTransaction(headerID int64, tx *sql.Tx, eventID string) error { +// Used to mark a header checked as part of some external transaction so as to group into one commit +func (r *headerRepository) MarkHeaderCheckedInTransaction(headerID int64, tx *sqlx.Tx, eventID string) error { _, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+eventID+`) VALUES ($1, $2) ON CONFLICT (header_id) DO - UPDATE SET `+eventID+` = $2`, headerID, true) + UPDATE SET `+eventID+` = checked_headers.`+eventID+` + 1`, headerID, 1) return err } diff --git a/pkg/omni/light/repository/header_repository_test.go b/pkg/contract_watcher/light/repository/header_repository_test.go similarity index 59% rename from pkg/omni/light/repository/header_repository_test.go rename to pkg/contract_watcher/light/repository/header_repository_test.go index 4f25cabc..23a47068 100644 --- a/pkg/omni/light/repository/header_repository_test.go +++ b/pkg/contract_watcher/light/repository/header_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,17 +23,17 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" ) var _ = Describe("Repository", func() { var db *postgres.DB - var omniHeaderRepo repository.HeaderRepository // omni/light header repository - var coreHeaderRepo repositories.HeaderRepository // pkg/datastore header repository + var contractHeaderRepo repository.HeaderRepository // contract_watcher light header repository + var coreHeaderRepo repositories.HeaderRepository // pkg/datastore header repository var eventIDs = []string{ "eventName_contractAddr", "eventName_contractAddr2", @@ -47,7 +47,7 @@ var _ = Describe("Repository", func() { BeforeEach(func() { db, _ = test_helpers.SetupDBandBC() - omniHeaderRepo = repository.NewHeaderRepository(db) + contractHeaderRepo = repository.NewHeaderRepository(db) coreHeaderRepo = repositories.NewHeaderRepository(db) }) @@ -61,7 +61,7 @@ var _ = Describe("Repository", func() { _, err := db.Exec(query) Expect(err).To(HaveOccurred()) - err = omniHeaderRepo.AddCheckColumn(eventIDs[0]) + err = contractHeaderRepo.AddCheckColumn(eventIDs[0]) Expect(err).ToNot(HaveOccurred()) _, err = db.Exec(query) @@ -69,13 +69,13 @@ var _ = Describe("Repository", func() { }) It("Caches column it creates so that it does not need to repeatedly query the database to check for it's existence", func() { - _, ok := omniHeaderRepo.CheckCache(eventIDs[0]) + _, ok := contractHeaderRepo.CheckCache(eventIDs[0]) Expect(ok).To(Equal(false)) - err := omniHeaderRepo.AddCheckColumn(eventIDs[0]) + err := contractHeaderRepo.AddCheckColumn(eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - v, ok := omniHeaderRepo.CheckCache(eventIDs[0]) + v, ok := contractHeaderRepo.CheckCache(eventIDs[0]) Expect(ok).To(Equal(true)) Expect(v).To(Equal(true)) }) @@ -88,7 +88,7 @@ var _ = Describe("Repository", func() { Expect(err).To(HaveOccurred()) } - err := omniHeaderRepo.AddCheckColumns(eventIDs) + err := contractHeaderRepo.AddCheckColumns(eventIDs) Expect(err).ToNot(HaveOccurred()) for _, id := range eventIDs { @@ -99,15 +99,15 @@ var _ = Describe("Repository", func() { It("Caches columns it creates so that it does not need to repeatedly query the database to check for it's existence", func() { for _, id := range eventIDs { - _, ok := omniHeaderRepo.CheckCache(id) + _, ok := contractHeaderRepo.CheckCache(id) Expect(ok).To(Equal(false)) } - err := omniHeaderRepo.AddCheckColumns(eventIDs) + err := contractHeaderRepo.AddCheckColumns(eventIDs) Expect(err).ToNot(HaveOccurred()) for _, id := range eventIDs { - v, ok := omniHeaderRepo.CheckCache(id) + v, ok := contractHeaderRepo.CheckCache(id) Expect(ok).To(Equal(true)) Expect(v).To(Equal(true)) } @@ -117,20 +117,20 @@ var _ = Describe("Repository", func() { Describe("MissingHeaders", func() { It("Returns all unchecked headers for the given eventID", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumn(eventIDs[0]) + err := contractHeaderRepo.AddCheckColumn(eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err := omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err := contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) }) It("Returns unchecked headers in ascending order", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumn(eventIDs[0]) + err := contractHeaderRepo.AddCheckColumn(eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err := omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err := contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) @@ -142,12 +142,24 @@ var _ = Describe("Repository", func() { Expect(h3.BlockNumber).To(Equal(int64(6194634))) }) - It("Fails if eventID does not yet exist in check_headers table", func() { - addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumn(eventIDs[0]) + It("Returns only contiguous chunks of headers", func() { + addDiscontinuousHeaders(coreHeaderRepo) + err := contractHeaderRepo.AddCheckColumns(eventIDs) Expect(err).ToNot(HaveOccurred()) - _, err = omniHeaderRepo.MissingHeaders(6194630, 6194635, "notEventId") + missingHeaders, err := contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) + Expect(err).ToNot(HaveOccurred()) + Expect(len(missingHeaders)).To(Equal(2)) + Expect(missingHeaders[0].BlockNumber).To(Equal(int64(6194632))) + Expect(missingHeaders[1].BlockNumber).To(Equal(int64(6194633))) + }) + + It("Fails if eventID does not yet exist in check_headers table", func() { + addHeaders(coreHeaderRepo) + err := contractHeaderRepo.AddCheckColumn(eventIDs[0]) + Expect(err).ToNot(HaveOccurred()) + + _, err = contractHeaderRepo.MissingHeaders(6194632, 6194635, "notEventId") Expect(err).To(HaveOccurred()) }) }) @@ -155,37 +167,49 @@ var _ = Describe("Repository", func() { Describe("MissingHeadersForAll", func() { // HERE It("Returns all headers that have not been checked for all of the ids provided", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumns(eventIDs) + err := contractHeaderRepo.AddCheckColumns(eventIDs) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err := omniHeaderRepo.MissingHeadersForAll(6194630, 6194635, eventIDs) + missingHeaders, err := contractHeaderRepo.MissingHeadersForAll(6194632, 6194635, eventIDs) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) - err = omniHeaderRepo.MarkHeaderChecked(missingHeaders[0].Id, eventIDs[0]) + err = contractHeaderRepo.MarkHeaderChecked(missingHeaders[0].Id, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err = omniHeaderRepo.MissingHeadersForAll(6194630, 6194635, eventIDs) + missingHeaders, err = contractHeaderRepo.MissingHeadersForAll(6194632, 6194635, eventIDs) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) - err = omniHeaderRepo.MarkHeaderChecked(missingHeaders[0].Id, eventIDs[1]) + err = contractHeaderRepo.MarkHeaderChecked(missingHeaders[0].Id, eventIDs[1]) Expect(err).ToNot(HaveOccurred()) - err = omniHeaderRepo.MarkHeaderChecked(missingHeaders[0].Id, eventIDs[2]) + err = contractHeaderRepo.MarkHeaderChecked(missingHeaders[0].Id, eventIDs[2]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err = omniHeaderRepo.MissingHeadersForAll(6194630, 6194635, eventIDs) + missingHeaders, err = contractHeaderRepo.MissingHeadersForAll(6194633, 6194635, eventIDs) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(2)) }) + It("Returns only contiguous chunks of headers", func() { + addDiscontinuousHeaders(coreHeaderRepo) + err := contractHeaderRepo.AddCheckColumns(eventIDs) + Expect(err).ToNot(HaveOccurred()) + + missingHeaders, err := contractHeaderRepo.MissingHeadersForAll(6194632, 6194635, eventIDs) + Expect(err).ToNot(HaveOccurred()) + Expect(len(missingHeaders)).To(Equal(2)) + Expect(missingHeaders[0].BlockNumber).To(Equal(int64(6194632))) + Expect(missingHeaders[1].BlockNumber).To(Equal(int64(6194633))) + }) + It("Fails if one of the eventIDs does not yet exist in check_headers table", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumns(eventIDs) + err := contractHeaderRepo.AddCheckColumns(eventIDs) Expect(err).ToNot(HaveOccurred()) badEventIDs := append(eventIDs, "notEventId") - _, err = omniHeaderRepo.MissingHeadersForAll(6194630, 6194635, badEventIDs) + _, err = contractHeaderRepo.MissingHeadersForAll(6194632, 6194635, badEventIDs) Expect(err).To(HaveOccurred()) }) }) @@ -193,36 +217,36 @@ var _ = Describe("Repository", func() { Describe("MarkHeaderChecked", func() { It("Marks the header checked for the given eventID", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumn(eventIDs[0]) + err := contractHeaderRepo.AddCheckColumn(eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err := omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err := contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) headerID := missingHeaders[0].Id - err = omniHeaderRepo.MarkHeaderChecked(headerID, eventIDs[0]) + err = contractHeaderRepo.MarkHeaderChecked(headerID, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err = omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err = contractHeaderRepo.MissingHeaders(6194633, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(2)) }) It("Fails if eventID does not yet exist in check_headers table", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumn(eventIDs[0]) + err := contractHeaderRepo.AddCheckColumn(eventIDs[0]) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err := omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err := contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) headerID := missingHeaders[0].Id - err = omniHeaderRepo.MarkHeaderChecked(headerID, "notEventId") + err = contractHeaderRepo.MarkHeaderChecked(headerID, "notEventId") Expect(err).To(HaveOccurred()) - missingHeaders, err = omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err = contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) }) @@ -231,18 +255,18 @@ var _ = Describe("Repository", func() { Describe("MarkHeaderCheckedForAll", func() { It("Marks the header checked for all provided column ids", func() { addHeaders(coreHeaderRepo) - err := omniHeaderRepo.AddCheckColumns(eventIDs) + err := contractHeaderRepo.AddCheckColumns(eventIDs) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err := omniHeaderRepo.MissingHeadersForAll(6194630, 6194635, eventIDs) + missingHeaders, err := contractHeaderRepo.MissingHeadersForAll(6194632, 6194635, eventIDs) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) headerID := missingHeaders[0].Id - err = omniHeaderRepo.MarkHeaderCheckedForAll(headerID, eventIDs) + err = contractHeaderRepo.MarkHeaderCheckedForAll(headerID, eventIDs) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err = omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err = contractHeaderRepo.MissingHeaders(6194633, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(2)) }) @@ -259,17 +283,17 @@ var _ = Describe("Repository", func() { var missingHeaders []core.Header for _, id := range methodIDs { - err := omniHeaderRepo.AddCheckColumn(id) + err := contractHeaderRepo.AddCheckColumn(id) Expect(err).ToNot(HaveOccurred()) - missingHeaders, err = omniHeaderRepo.MissingHeaders(6194630, 6194635, id) + missingHeaders, err = contractHeaderRepo.MissingHeaders(6194632, 6194635, id) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) } - err := omniHeaderRepo.MarkHeadersCheckedForAll(missingHeaders, methodIDs) + err := contractHeaderRepo.MarkHeadersCheckedForAll(missingHeaders, methodIDs) Expect(err).ToNot(HaveOccurred()) for _, id := range methodIDs { - missingHeaders, err = omniHeaderRepo.MissingHeaders(6194630, 6194635, id) + missingHeaders, err = contractHeaderRepo.MissingHeaders(6194632, 6194635, id) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(0)) } @@ -280,28 +304,28 @@ var _ = Describe("Repository", func() { It("Returns headers that have been checked for all the provided events but have not been checked for all the provided methods", func() { addHeaders(coreHeaderRepo) for i, id := range eventIDs { - err := omniHeaderRepo.AddCheckColumn(id) + err := contractHeaderRepo.AddCheckColumn(id) Expect(err).ToNot(HaveOccurred()) - err = omniHeaderRepo.AddCheckColumn(methodIDs[i]) + err = contractHeaderRepo.AddCheckColumn(methodIDs[i]) Expect(err).ToNot(HaveOccurred()) } - missingHeaders, err := omniHeaderRepo.MissingHeaders(6194630, 6194635, eventIDs[0]) + missingHeaders, err := contractHeaderRepo.MissingHeaders(6194632, 6194635, eventIDs[0]) Expect(err).ToNot(HaveOccurred()) Expect(len(missingHeaders)).To(Equal(3)) headerID := missingHeaders[0].Id headerID2 := missingHeaders[1].Id for i, id := range eventIDs { - err = omniHeaderRepo.MarkHeaderChecked(headerID, id) + err = contractHeaderRepo.MarkHeaderChecked(headerID, id) Expect(err).ToNot(HaveOccurred()) - err = omniHeaderRepo.MarkHeaderChecked(headerID2, id) + err = contractHeaderRepo.MarkHeaderChecked(headerID2, id) Expect(err).ToNot(HaveOccurred()) - err = omniHeaderRepo.MarkHeaderChecked(headerID, methodIDs[i]) + err = contractHeaderRepo.MarkHeaderChecked(headerID, methodIDs[i]) Expect(err).ToNot(HaveOccurred()) } - intersectionHeaders, err := omniHeaderRepo.MissingMethodsCheckedEventsIntersection(6194630, 6194635, methodIDs, eventIDs) + intersectionHeaders, err := contractHeaderRepo.MissingMethodsCheckedEventsIntersection(6194632, 6194635, methodIDs, eventIDs) Expect(err).ToNot(HaveOccurred()) Expect(len(intersectionHeaders)).To(Equal(1)) Expect(intersectionHeaders[0].Id).To(Equal(headerID2)) @@ -315,3 +339,9 @@ func addHeaders(coreHeaderRepo repositories.HeaderRepository) { coreHeaderRepo.CreateOrUpdateHeader(mocks.MockHeader2) coreHeaderRepo.CreateOrUpdateHeader(mocks.MockHeader3) } + +func addDiscontinuousHeaders(coreHeaderRepo repositories.HeaderRepository) { + coreHeaderRepo.CreateOrUpdateHeader(mocks.MockHeader1) + coreHeaderRepo.CreateOrUpdateHeader(mocks.MockHeader2) + coreHeaderRepo.CreateOrUpdateHeader(mocks.MockHeader4) +} diff --git a/pkg/omni/light/repository/repository_suite_test.go b/pkg/contract_watcher/light/repository/repository_suite_test.go similarity index 90% rename from pkg/omni/light/repository/repository_suite_test.go rename to pkg/contract_watcher/light/repository/repository_suite_test.go index 80215953..8edfbbec 100644 --- a/pkg/omni/light/repository/repository_suite_test.go +++ b/pkg/contract_watcher/light/repository/repository_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package repository_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -31,5 +31,5 @@ func TestRepository(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/omni/light/retriever/block_retriever.go b/pkg/contract_watcher/light/retriever/block_retriever.go similarity index 98% rename from pkg/omni/light/retriever/block_retriever.go rename to pkg/contract_watcher/light/retriever/block_retriever.go index a871278e..47691013 100644 --- a/pkg/omni/light/retriever/block_retriever.go +++ b/pkg/contract_watcher/light/retriever/block_retriever.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/light/retriever/block_retriever_test.go b/pkg/contract_watcher/light/retriever/block_retriever_test.go similarity index 89% rename from pkg/omni/light/retriever/block_retriever_test.go rename to pkg/contract_watcher/light/retriever/block_retriever_test.go index 563e3738..a57852e5 100644 --- a/pkg/omni/light/retriever/block_retriever_test.go +++ b/pkg/contract_watcher/light/retriever/block_retriever_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,11 +20,11 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/retriever" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" ) var _ = Describe("Block Retriever", func() { diff --git a/pkg/omni/light/retriever/retriever_suite_test.go b/pkg/contract_watcher/light/retriever/retriever_suite_test.go similarity index 85% rename from pkg/omni/light/retriever/retriever_suite_test.go rename to pkg/contract_watcher/light/retriever/retriever_suite_test.go index cb5a7313..83a16269 100644 --- a/pkg/omni/light/retriever/retriever_suite_test.go +++ b/pkg/contract_watcher/light/retriever/retriever_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package retriever_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -27,9 +27,9 @@ import ( func TestRetriever(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Light BLock Number Retriever Suite Test") + RunSpecs(t, "Light Block Number Retriever Suite Test") } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/omni/light/transformer/transformer.go b/pkg/contract_watcher/light/transformer/transformer.go similarity index 56% rename from pkg/omni/light/transformer/transformer.go rename to pkg/contract_watcher/light/transformer/transformer.go index 565e6966..8ce5f064 100644 --- a/pkg/omni/light/transformer/transformer.go +++ b/pkg/contract_watcher/light/transformer/transformer.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,67 +23,48 @@ import ( "github.com/ethereum/go-ethereum/common" gethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/converter" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/fetcher" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/parser" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/poller" + srep "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/converter" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/fetcher" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/retriever" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller" - srep "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) // Requires a light synced vDB (headers) and a running eth node (or infura) -type transformer struct { +type Transformer struct { // Database interfaces - srep.EventRepository // Holds transformed watched event log data - repository.HeaderRepository // Interface for interaction with header repositories + EventRepository srep.EventRepository // Holds transformed watched event log data + HeaderRepository repository.HeaderRepository // Interface for interaction with header repositories // Pre-processing interfaces - parser.Parser // Parses events and methods out of contract abi fetched using contract address - retriever.BlockRetriever // Retrieves first block for contract and current block height + Parser parser.Parser // Parses events and methods out of contract abi fetched using contract address + Retriever retriever.BlockRetriever // Retrieves first block for contract // Processing interfaces - fetcher.Fetcher // Fetches event logs, using header hashes - converter.Converter // Converts watched event logs into custom log - poller.Poller // Polls methods using arguments collected from events and persists them using a method datastore + Fetcher fetcher.Fetcher // Fetches event logs, using header hashes + Converter converter.ConverterInterface // Converts watched event logs into custom log + Poller poller.Poller // Polls methods using arguments collected from events and persists them using a method datastore - // Ethereum network name; default "" is mainnet - Network string + // Store contract configuration information + Config config.ContractConfig // Store contract info as mapping to contract address Contracts map[string]*contract.Contract - // Targeted subset of events/methods - // Stored as maps of contract address to events/method names of interest - WatchedEvents map[string][]string // Default/empty event list means all are watched - WantedMethods map[string][]string // Default/empty method list means none are polled - - // Starting block number for each contract - ContractStart map[string]int64 - - // Lists of argument values to filter event or - // method data with; if empty no filter is applied - EventArgs map[string][]string - MethodArgs map[string][]string - - // Whether or not to create a list of emitted address or hashes for the contract in postgres - CreateAddrList map[string]bool - CreateHashList map[string]bool - - // Method piping on/off for a contract - Piping map[string]bool - // Internally configured transformer variables contractAddresses []string // Holds all contract addresses, for batch fetching of logs sortedEventIds map[string][]string // Map to sort event column ids by contract, for post fetch processing and persisting of logs sortedMethodIds map[string][]string // Map to sort method column ids by contract, for post fetch method polling eventIds []string // Holds event column ids across all contract, for batch fetching of headers eventFilters []common.Hash // Holds topic0 hashes across all contracts, for batch fetching of logs - start int64 // Hold the lowest starting block and the highest ending block + Start int64 // Hold the lowest starting block and the highest ending block } // Order-of-operations: @@ -93,26 +74,18 @@ type transformer struct { // 4. Execute // Transformer takes in config for blockchain, database, and network id -func NewTransformer(network string, bc core.BlockChain, db *postgres.DB) *transformer { +func NewTransformer(con config.ContractConfig, bc core.BlockChain, db *postgres.DB) *Transformer { - return &transformer{ + return &Transformer{ Poller: poller.NewPoller(bc, db, types.LightSync), Fetcher: fetcher.NewFetcher(bc), - Parser: parser.NewParser(network), + Parser: parser.NewParser(con.Network), HeaderRepository: repository.NewHeaderRepository(db), - BlockRetriever: retriever.NewBlockRetriever(db), - Converter: converter.NewConverter(&contract.Contract{}), + Retriever: retriever.NewBlockRetriever(db), + Converter: &converter.Converter{}, Contracts: map[string]*contract.Contract{}, EventRepository: srep.NewEventRepository(db, types.LightSync), - WatchedEvents: map[string][]string{}, - WantedMethods: map[string][]string{}, - ContractStart: map[string]int64{}, - EventArgs: map[string][]string{}, - MethodArgs: map[string][]string{}, - CreateAddrList: map[string]bool{}, - CreateHashList: map[string]bool{}, - Piping: map[string]bool{}, - Network: network, + Config: con, } } @@ -120,68 +93,70 @@ func NewTransformer(network string, bc core.BlockChain, db *postgres.DB) *transf // Loops over all of the addr => filter sets // Uses parser to pull event info from abi // Use this info to generate event filters -func (tr *transformer) Init() error { +func (tr *Transformer) Init() error { // Initialize internally configured transformer settings tr.contractAddresses = make([]string, 0) // Holds all contract addresses, for batch fetching of logs tr.sortedEventIds = make(map[string][]string) // Map to sort event column ids by contract, for post fetch processing and persisting of logs tr.sortedMethodIds = make(map[string][]string) // Map to sort method column ids by contract, for post fetch method polling tr.eventIds = make([]string, 0) // Holds event column ids across all contract, for batch fetching of headers tr.eventFilters = make([]common.Hash, 0) // Holds topic0 hashes across all contracts, for batch fetching of logs - tr.start = 100000000000 // Hold the lowest starting block and the highest ending block + tr.Start = 100000000000 // Iterate through all internal contract addresses - for contractAddr, subset := range tr.WatchedEvents { - // Get Abi - err := tr.Parser.Parse(contractAddr) - if err != nil { - return err + for contractAddr := range tr.Config.Addresses { + // Configure Abi + if tr.Config.Abis[contractAddr] == "" { + // If no abi is given in the config, this method will try fetching from internal look-up table and etherscan + err := tr.Parser.Parse(contractAddr) + if err != nil { + return err + } + } else { + // If we have an abi from the config, load that into the parser + err := tr.Parser.ParseAbiStr(tr.Config.Abis[contractAddr]) + if err != nil { + return err + } } // Get first block and most recent block number in the header repo - firstBlock, err := tr.BlockRetriever.RetrieveFirstBlock() - if err != nil { - return err - } - lastBlock, err := tr.BlockRetriever.RetrieveMostRecentBlock() + firstBlock, err := tr.Retriever.RetrieveFirstBlock() if err != nil { return err } // Set to specified range if it falls within the bounds - if firstBlock < tr.ContractStart[contractAddr] { - firstBlock = tr.ContractStart[contractAddr] + if firstBlock < tr.Config.StartingBlocks[contractAddr] { + firstBlock = tr.Config.StartingBlocks[contractAddr] } // Get contract name if it has one var name = new(string) - tr.FetchContractData(tr.Abi(), contractAddr, "name", nil, &name, lastBlock) + tr.Poller.FetchContractData(tr.Parser.Abi(), contractAddr, "name", nil, name, -1) - // Remove any potential accidental duplicate inputs in arg filter values + // Remove any potential accidental duplicate inputs eventArgs := map[string]bool{} - for _, arg := range tr.EventArgs[contractAddr] { + for _, arg := range tr.Config.EventArgs[contractAddr] { eventArgs[arg] = true } methodArgs := map[string]bool{} - for _, arg := range tr.MethodArgs[contractAddr] { + for _, arg := range tr.Config.MethodArgs[contractAddr] { methodArgs[arg] = true } // Aggregate info into contract object and store for execution con := contract.Contract{ - Name: *name, - Network: tr.Network, - Address: contractAddr, - Abi: tr.Parser.Abi(), - ParsedAbi: tr.Parser.ParsedAbi(), - StartingBlock: firstBlock, - LastBlock: -1, - Events: tr.Parser.GetEvents(subset), - Methods: tr.Parser.GetSelectMethods(tr.WantedMethods[contractAddr]), - FilterArgs: eventArgs, - MethodArgs: methodArgs, - CreateAddrList: tr.CreateAddrList[contractAddr], - CreateHashList: tr.CreateHashList[contractAddr], - Piping: tr.Piping[contractAddr], + Name: *name, + Network: tr.Config.Network, + Address: contractAddr, + Abi: tr.Parser.Abi(), + ParsedAbi: tr.Parser.ParsedAbi(), + StartingBlock: firstBlock, + Events: tr.Parser.GetEvents(tr.Config.Events[contractAddr]), + Methods: tr.Parser.GetSelectMethods(tr.Config.Methods[contractAddr]), + FilterArgs: eventArgs, + MethodArgs: methodArgs, + Piping: tr.Config.Piping[contractAddr], }.Init() tr.Contracts[contractAddr] = con tr.contractAddresses = append(tr.contractAddresses, con.Address) @@ -213,33 +188,33 @@ func (tr *transformer) Init() error { } // Update start to the lowest block - if con.StartingBlock < tr.start { - tr.start = con.StartingBlock + if con.StartingBlock < tr.Start { + tr.Start = con.StartingBlock } } return nil } -func (tr *transformer) Execute() error { +func (tr *Transformer) Execute() error { if len(tr.Contracts) == 0 { return errors.New("error: transformer has no initialized contracts") } - // Map to sort batch fetched logs by which contract they belong to, for post fetch processing - sortedLogs := make(map[string][]gethTypes.Log) - for _, con := range tr.Contracts { - sortedLogs[con.Address] = []gethTypes.Log{} - } - // Find unchecked headers for all events across all contracts; these are returned in asc order - missingHeaders, err := tr.HeaderRepository.MissingHeadersForAll(tr.start, -1, tr.eventIds) + missingHeaders, err := tr.HeaderRepository.MissingHeadersForAll(tr.Start, -1, tr.eventIds) if err != nil { return err } // Iterate over headers for _, header := range missingHeaders { + // Set `start` to this header + // This way if we throw an error but don't bring the execution cycle down (how it is currently handled) + // we restart the cycle at this header + tr.Start = header.BlockNumber + // Map to sort batch fetched logs by which contract they belong to, for post fetch processing + sortedLogs := make(map[string][]gethTypes.Log) // And fetch all event logs across contracts at this header allLogs, err := tr.Fetcher.FetchLogs(tr.contractAddresses, tr.eventFilters, header) if err != nil { @@ -257,6 +232,7 @@ func (tr *transformer) Execute() error { if err != nil { return err } + tr.Start = header.BlockNumber + 1 // Empty header; setup to start at the next header continue } @@ -305,13 +281,15 @@ func (tr *transformer) Execute() error { if err != nil { return err } + // Success; setup to start at the next header + tr.Start = header.BlockNumber + 1 } return nil } // Used to poll contract methods at a given header -func (tr *transformer) methodPolling(header core.Header, sortedMethodIds map[string][]string) error { +func (tr *Transformer) methodPolling(header core.Header, sortedMethodIds map[string][]string) error { for _, con := range tr.Contracts { // Skip method polling processes if no methods are specified // Also don't try to poll methods below this contract's specified starting block @@ -335,42 +313,6 @@ func (tr *transformer) methodPolling(header core.Header, sortedMethodIds map[str return nil } -// Used to set which contract addresses and which of their events to watch -func (tr *transformer) SetEvents(contractAddr string, filterSet []string) { - tr.WatchedEvents[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set subset of account addresses to watch events for -func (tr *transformer) SetEventArgs(contractAddr string, filterSet []string) { - tr.EventArgs[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set which contract addresses and which of their methods to call -func (tr *transformer) SetMethods(contractAddr string, filterSet []string) { - tr.WantedMethods[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set subset of account addresses to poll methods on -func (tr *transformer) SetMethodArgs(contractAddr string, filterSet []string) { - tr.MethodArgs[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set the block range to watch for a given address -func (tr *transformer) SetStartingBlock(contractAddr string, start int64) { - tr.ContractStart[strings.ToLower(contractAddr)] = start -} - -// Used to set whether or not to persist an account address list -func (tr *transformer) SetCreateAddrList(contractAddr string, on bool) { - tr.CreateAddrList[strings.ToLower(contractAddr)] = on -} - -// Used to set whether or not to persist an hash list -func (tr *transformer) SetCreateHashList(contractAddr string, on bool) { - tr.CreateHashList[strings.ToLower(contractAddr)] = on -} - -// Used to turn method piping on for a contract -func (tr *transformer) SetPiping(contractAddr string, on bool) { - tr.Piping[strings.ToLower(contractAddr)] = on +func (tr *Transformer) GetConfig() config.ContractConfig { + return tr.Config } diff --git a/pkg/omni/light/transformer/transformer_suite_test.go b/pkg/contract_watcher/light/transformer/transformer_suite_test.go similarity index 90% rename from pkg/omni/light/transformer/transformer_suite_test.go rename to pkg/contract_watcher/light/transformer/transformer_suite_test.go index 52ab1197..34a84416 100644 --- a/pkg/omni/light/transformer/transformer_suite_test.go +++ b/pkg/contract_watcher/light/transformer/transformer_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package transformer_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -31,5 +31,5 @@ func TestTransformer(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/contract_watcher/light/transformer/transformer_test.go b/pkg/contract_watcher/light/transformer/transformer_test.go new file mode 100644 index 00000000..8c17f570 --- /dev/null +++ b/pkg/contract_watcher/light/transformer/transformer_test.go @@ -0,0 +1,126 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package transformer_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/transformer" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/parser" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/poller" + "github.com/vulcanize/vulcanizedb/pkg/fakes" +) + +var _ = Describe("Transformer", func() { + var fakeAddress = "0x1234567890abcdef" + Describe("Init", func() { + It("Initializes transformer's contract objects", func() { + blockRetriever := &fakes.MockLightBlockRetriever{} + firstBlock := int64(1) + blockRetriever.FirstBlock = firstBlock + + parsr := &fakes.MockParser{} + fakeAbi := "fake_abi" + parsr.AbiToReturn = fakeAbi + + pollr := &fakes.MockPoller{} + fakeContractName := "fake_contract_name" + pollr.ContractName = fakeContractName + + t := getFakeTransformer(blockRetriever, parsr, pollr) + + err := t.Init() + + Expect(err).ToNot(HaveOccurred()) + + c, ok := t.Contracts[fakeAddress] + Expect(ok).To(Equal(true)) + + Expect(c.StartingBlock).To(Equal(firstBlock)) + Expect(c.Abi).To(Equal(fakeAbi)) + Expect(c.Name).To(Equal(fakeContractName)) + Expect(c.Address).To(Equal(fakeAddress)) + }) + + It("Fails to initialize if first block cannot be fetched from vDB headers table", func() { + blockRetriever := &fakes.MockLightBlockRetriever{} + blockRetriever.FirstBlockErr = fakes.FakeError + t := getFakeTransformer(blockRetriever, &fakes.MockParser{}, &fakes.MockPoller{}) + + err := t.Init() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + }) + + Describe("Execute", func() { + It("Executes contract transformations", func() { + blockRetriever := &fakes.MockLightBlockRetriever{} + firstBlock := int64(1) + blockRetriever.FirstBlock = firstBlock + + parsr := &fakes.MockParser{} + fakeAbi := "fake_abi" + parsr.AbiToReturn = fakeAbi + + pollr := &fakes.MockPoller{} + fakeContractName := "fake_contract_name" + pollr.ContractName = fakeContractName + + t := getFakeTransformer(blockRetriever, parsr, pollr) + + err := t.Init() + + Expect(err).ToNot(HaveOccurred()) + + c, ok := t.Contracts[fakeAddress] + Expect(ok).To(Equal(true)) + + Expect(c.StartingBlock).To(Equal(firstBlock)) + Expect(c.Abi).To(Equal(fakeAbi)) + Expect(c.Name).To(Equal(fakeContractName)) + Expect(c.Address).To(Equal(fakeAddress)) + }) + + It("Fails to initialize if first block cannot be fetched from vDB headers table", func() { + blockRetriever := &fakes.MockLightBlockRetriever{} + blockRetriever.FirstBlockErr = fakes.FakeError + t := getFakeTransformer(blockRetriever, &fakes.MockParser{}, &fakes.MockPoller{}) + + err := t.Init() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + }) +}) + +func getFakeTransformer(blockRetriever retriever.BlockRetriever, parsr parser.Parser, pollr poller.Poller) transformer.Transformer { + return transformer.Transformer{ + Parser: parsr, + Retriever: blockRetriever, + Poller: pollr, + HeaderRepository: &fakes.MockLightHeaderRepository{}, + Contracts: map[string]*contract.Contract{}, + Config: mocks.MockConfig, + } +} diff --git a/pkg/omni/shared/constants/constants.go b/pkg/contract_watcher/shared/constants/constants.go similarity index 99% rename from pkg/omni/shared/constants/constants.go rename to pkg/contract_watcher/shared/constants/constants.go index 594e0fce..5545f791 100644 --- a/pkg/omni/shared/constants/constants.go +++ b/pkg/contract_watcher/shared/constants/constants.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,9 +18,9 @@ package constants import ( "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/filters" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers" ) // Event enums diff --git a/pkg/omni/shared/constants/interface.go b/pkg/contract_watcher/shared/constants/interface.go similarity index 99% rename from pkg/omni/shared/constants/interface.go rename to pkg/contract_watcher/shared/constants/interface.go index a1bf56b0..f49ac96a 100644 --- a/pkg/omni/shared/constants/interface.go +++ b/pkg/contract_watcher/shared/constants/interface.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/shared/contract/contract.go b/pkg/contract_watcher/shared/contract/contract.go similarity index 92% rename from pkg/omni/shared/contract/contract.go rename to pkg/contract_watcher/shared/contract/contract.go index a916e734..6b3eb0ff 100644 --- a/pkg/omni/shared/contract/contract.go +++ b/pkg/contract_watcher/shared/contract/contract.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,13 +18,14 @@ package contract import ( "errors" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/filters" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) // Contract object to hold our contract data @@ -33,7 +34,6 @@ type Contract struct { Address string // Address of the contract Network string // Network on which the contract is deployed; default empty "" is Ethereum mainnet StartingBlock int64 // Starting block of the contract - LastBlock int64 // Most recent block on the network Abi string // Abi string ParsedAbi abi.ABI // Parsed abi Events map[string]types.Event // List of events to watch @@ -63,22 +63,16 @@ func (c Contract) Init() *Contract { } } - // If we are creating an address list in postgres - // we initialize the map despite what method call, if any - if c.CreateAddrList { - c.EmittedAddrs = map[interface{}]bool{} - } - return &c } -// Use contract info to generate event filters - full sync omni watcher only +// Use contract info to generate event filters - full sync contract watcher only func (c *Contract) GenerateFilters() error { c.Filters = map[string]filters.LogFilter{} for name, event := range c.Events { c.Filters[name] = filters.LogFilter{ - Name: event.Name, + Name: c.Address + "_" + event.Name, FromBlock: c.StartingBlock, ToBlock: -1, Address: common.HexToAddress(c.Address).Hex(), diff --git a/pkg/omni/shared/contract/contract_suite_test.go b/pkg/contract_watcher/shared/contract/contract_suite_test.go similarity index 96% rename from pkg/omni/shared/contract/contract_suite_test.go rename to pkg/contract_watcher/shared/contract/contract_suite_test.go index 9ef74e40..fa6d1257 100644 --- a/pkg/omni/shared/contract/contract_suite_test.go +++ b/pkg/contract_watcher/shared/contract/contract_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/shared/contract/contract_test.go b/pkg/contract_watcher/shared/contract/contract_test.go similarity index 95% rename from pkg/omni/shared/contract/contract_test.go rename to pkg/contract_watcher/shared/contract/contract_test.go index a9164f94..38a996ec 100644 --- a/pkg/omni/shared/contract/contract_test.go +++ b/pkg/contract_watcher/shared/contract/contract_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,10 +20,10 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" ) var _ = Describe("Contract", func() { diff --git a/pkg/omni/shared/fetcher/fetcher.go b/pkg/contract_watcher/shared/fetcher/fetcher.go similarity index 83% rename from pkg/omni/shared/fetcher/fetcher.go rename to pkg/contract_watcher/shared/fetcher/fetcher.go index f481b6aa..459e96c3 100644 --- a/pkg/omni/shared/fetcher/fetcher.go +++ b/pkg/contract_watcher/shared/fetcher/fetcher.go @@ -1,16 +1,18 @@ -// Copyright 2018 Vulcanize -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package fetcher diff --git a/pkg/omni/shared/getter/getter_suite_test.go b/pkg/contract_watcher/shared/getter/getter_suite_test.go similarity index 96% rename from pkg/omni/shared/getter/getter_suite_test.go rename to pkg/contract_watcher/shared/getter/getter_suite_test.go index 78fdc7bf..75b2e014 100644 --- a/pkg/omni/shared/getter/getter_suite_test.go +++ b/pkg/contract_watcher/shared/getter/getter_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/shared/getter/getter_test.go b/pkg/contract_watcher/shared/getter/getter_test.go similarity index 88% rename from pkg/omni/shared/getter/getter_test.go rename to pkg/contract_watcher/shared/getter/getter_test.go index 1c440972..0f5d7cb6 100644 --- a/pkg/omni/shared/getter/getter_test.go +++ b/pkg/contract_watcher/shared/getter/getter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,21 +22,22 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/getter" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/getter" + "github.com/vulcanize/vulcanizedb/test_config" ) var _ = Describe("Interface Getter", func() { Describe("GetAbi", func() { It("Constructs and returns a custom abi based on results from supportsInterface calls", func() { expectedABI := `[` + constants.AddrChangeInterface + `,` + constants.NameChangeInterface + `,` + constants.ContentChangeInterface + `,` + constants.AbiChangeInterface + `,` + constants.PubkeyChangeInterface + `]` - + con := test_config.InfuraClient + infuraIPC := con.IPCPath blockNumber := int64(6885696) - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" rawRpcClient, err := rpc.Dial(infuraIPC) Expect(err).NotTo(HaveOccurred()) rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) diff --git a/pkg/omni/shared/getter/interface_getter.go b/pkg/contract_watcher/shared/getter/interface_getter.go similarity index 95% rename from pkg/omni/shared/getter/interface_getter.go rename to pkg/contract_watcher/shared/getter/interface_getter.go index a49ac669..8aee7d03 100644 --- a/pkg/omni/shared/getter/interface_getter.go +++ b/pkg/contract_watcher/shared/getter/interface_getter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,9 +17,9 @@ package getter import ( + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/fetcher" "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/fetcher" ) type InterfaceGetter interface { diff --git a/pkg/omni/shared/helpers/helpers.go b/pkg/contract_watcher/shared/helpers/helpers.go similarity index 98% rename from pkg/omni/shared/helpers/helpers.go rename to pkg/contract_watcher/shared/helpers/helpers.go index 3c448989..9fb8dfae 100644 --- a/pkg/omni/shared/helpers/helpers.go +++ b/pkg/contract_watcher/shared/helpers/helpers.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/shared/helpers/test_helpers/database.go b/pkg/contract_watcher/shared/helpers/test_helpers/database.go similarity index 89% rename from pkg/omni/shared/helpers/test_helpers/database.go rename to pkg/contract_watcher/shared/helpers/test_helpers/database.go index 3bea427b..5f943666 100644 --- a/pkg/omni/shared/helpers/test_helpers/database.go +++ b/pkg/contract_watcher/shared/helpers/test_helpers/database.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -24,6 +24,9 @@ import ( . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" @@ -31,9 +34,7 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/geth/client" rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/test_config" ) type TransferLog struct { @@ -106,22 +107,9 @@ type Owner struct { Address string `db:"returned"` } -func SetupBC() core.BlockChain { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" - rawRpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) - ethClient := ethclient.NewClient(rawRpcClient) - blockChainClient := client.NewEthClient(ethClient) - node := node.MakeNode(rpcClient) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter) - - return blockChain -} - func SetupDBandBC() (*postgres.DB, core.BlockChain) { - infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05" + con := test_config.InfuraClient + infuraIPC := con.IPCPath rawRpcClient, err := rpc.Dial(infuraIPC) Expect(err).NotTo(HaveOccurred()) rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) @@ -180,7 +168,6 @@ func SetupTusdContract(wantedEvents, wantedMethods []string) *contract.Contract Abi: p.Abi(), ParsedAbi: p.ParsedAbi(), StartingBlock: 6194634, - LastBlock: 6507323, Events: p.GetEvents(wantedEvents), Methods: p.GetSelectMethods(wantedMethods), MethodArgs: map[string]bool{}, @@ -227,7 +214,6 @@ func SetupENSContract(wantedEvents, wantedMethods []string) *contract.Contract { Abi: p.Abi(), ParsedAbi: p.ParsedAbi(), StartingBlock: 6194634, - LastBlock: 6507323, Events: p.GetEvents(wantedEvents), Methods: p.GetSelectMethods(wantedMethods), MethodArgs: map[string]bool{}, @@ -236,7 +222,7 @@ func SetupENSContract(wantedEvents, wantedMethods []string) *contract.Contract { } func TearDown(db *postgres.DB) { - tx, err := db.Begin() + tx, err := db.Beginx() Expect(err).NotTo(HaveOccurred()) _, err = tx.Exec(`DELETE FROM blocks`) @@ -251,10 +237,16 @@ func TearDown(db *postgres.DB) { _, err = tx.Exec(`DELETE FROM log_filters`) Expect(err).NotTo(HaveOccurred()) - _, err = tx.Exec(`DELETE FROM transactions`) + _, err = tx.Exec(`DELETE FROM full_sync_transactions`) Expect(err).NotTo(HaveOccurred()) - _, err = tx.Exec(`DELETE FROM receipts`) + _, err = tx.Exec("DELETE FROM light_sync_transactions") + Expect(err).NotTo(HaveOccurred()) + + _, err = tx.Exec(`DELETE FROM full_sync_receipts`) + Expect(err).NotTo(HaveOccurred()) + + _, err = tx.Exec(`DELETE FROM light_sync_receipts`) Expect(err).NotTo(HaveOccurred()) _, err = tx.Exec(`DROP TABLE checked_headers`) @@ -277,6 +269,9 @@ func TearDown(db *postgres.DB) { err = tx.Commit() Expect(err).NotTo(HaveOccurred()) + + _, err = db.Exec(`VACUUM checked_headers`) + Expect(err).NotTo(HaveOccurred()) } func CreateBlock(blockNumber int64, repository repositories.BlockRepository) (blockId int64) { diff --git a/pkg/omni/shared/helpers/test_helpers/mocks/entities.go b/pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go similarity index 81% rename from pkg/omni/shared/helpers/test_helpers/mocks/entities.go rename to pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go index 4d865382..be6d5aec 100644 --- a/pkg/omni/shared/helpers/test_helpers/mocks/entities.go +++ b/pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,21 +18,26 @@ package mocks import ( "encoding/json" + "strings" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/filters" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" ) var TransferBlock1 = core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ert", Number: 6194633, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654aaa", + Transactions: []core.TransactionModel{{ + GasLimit: 0, + GasPrice: 0, + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654aaa", + Nonce: 0, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654aaa", ContractAddress: "", @@ -50,14 +55,19 @@ var TransferBlock1 = core.Block{ Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", }}, }, + TxIndex: 0, + Value: "0", }}, } var TransferBlock2 = core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ooo", Number: 6194634, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654eee", + Transactions: []core.TransactionModel{{ + GasLimit: 0, + GasPrice: 0, + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654eee", + Nonce: 0, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654eee", ContractAddress: "", @@ -75,14 +85,19 @@ var TransferBlock2 = core.Block{ Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", }}, }, + TxIndex: 0, + Value: "0", }}, } var NewOwnerBlock1 = core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ppp", Number: 6194635, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654bbb", + Transactions: []core.TransactionModel{{ + GasLimit: 0, + GasPrice: 0, + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654bbb", + Nonce: 0, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654bbb", ContractAddress: "", @@ -100,14 +115,19 @@ var NewOwnerBlock1 = core.Block{ Data: "0x000000000000000000000000000000000000000000000000000000000000af21", }}, }, + TxIndex: 0, + Value: "0", }}, } var NewOwnerBlock2 = core.Block{ Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad123ggg", Number: 6194636, - Transactions: []core.Transaction{{ - Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654lll", + Transactions: []core.TransactionModel{{ + GasLimit: 0, + GasPrice: 0, + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654lll", + Nonce: 0, Receipt: core.Receipt{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654lll", ContractAddress: "", @@ -125,11 +145,13 @@ var NewOwnerBlock2 = core.Block{ Data: "0x000000000000000000000000000000000000000000000000000000000000af21", }}, }, + TxIndex: 0, + Value: "0", }}, } var ExpectedTransferFilter = filters.LogFilter{ - Name: "Transfer", + Name: constants.TusdContractAddress + "_" + "Transfer", Address: constants.TusdContractAddress, ToBlock: -1, FromBlock: 6194634, @@ -137,7 +159,7 @@ var ExpectedTransferFilter = filters.LogFilter{ } var ExpectedApprovalFilter = filters.LogFilter{ - Name: "Approval", + Name: constants.TusdContractAddress + "_" + "Approval", Address: constants.TusdContractAddress, ToBlock: -1, FromBlock: 6194634, @@ -181,6 +203,13 @@ var MockHeader3 = core.Header{ Timestamp: "50000030", } +var MockHeader4 = core.Header{ + Hash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs", + BlockNumber: 6194635, + Raw: rawFakeHeader, + Timestamp: "50000030", +} + var MockTransferLog1 = types.Log{ Index: 1, Address: common.HexToAddress(constants.TusdContractAddress), @@ -249,3 +278,50 @@ var MockNewOwnerLog2 = types.Log{ }, Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000af21"), } + +var ens = strings.ToLower(constants.EnsContractAddress) +var tusd = strings.ToLower(constants.TusdContractAddress) + +var MockConfig = config.ContractConfig{ + Network: "", + Addresses: map[string]bool{ + "0x1234567890abcdef": true, + }, + Abis: map[string]string{ + "0x1234567890abcdef": "fake_abi", + }, + Events: map[string][]string{ + "0x1234567890abcdef": []string{"Transfer"}, + }, + Methods: map[string][]string{ + "0x1234567890abcdef": nil, + }, + MethodArgs: map[string][]string{ + "0x1234567890abcdef": nil, + }, + EventArgs: map[string][]string{ + "0x1234567890abcdef": nil, + }, +} + +var MockEmptyConfig = config.ContractConfig{ + Network: "", + Addresses: map[string]bool{ + "0x1234567890abcdef": true, + }, + Abis: map[string]string{ + "0x1234567890abcdef": "fake_abi", + }, + Events: map[string][]string{ + "0x1234567890abcdef": nil, + }, + Methods: map[string][]string{ + "0x1234567890abcdef": nil, + }, + MethodArgs: map[string][]string{ + "0x1234567890abcdef": nil, + }, + EventArgs: map[string][]string{ + "0x1234567890abcdef": nil, + }, +} diff --git a/pkg/omni/shared/helpers/test_helpers/mocks/parser.go b/pkg/contract_watcher/shared/helpers/test_helpers/mocks/parser.go similarity index 97% rename from pkg/omni/shared/helpers/test_helpers/mocks/parser.go rename to pkg/contract_watcher/shared/helpers/test_helpers/mocks/parser.go index 5fd8f5fc..6ea0948d 100644 --- a/pkg/omni/shared/helpers/test_helpers/mocks/parser.go +++ b/pkg/contract_watcher/shared/helpers/test_helpers/mocks/parser.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -19,8 +19,8 @@ package mocks import ( "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) // Mock parser diff --git a/pkg/contract_watcher/shared/helpers/test_helpers/test_data.go b/pkg/contract_watcher/shared/helpers/test_helpers/test_data.go new file mode 100644 index 00000000..c52fd20c --- /dev/null +++ b/pkg/contract_watcher/shared/helpers/test_helpers/test_data.go @@ -0,0 +1,109 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package test_helpers + +import ( + "strings" + + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" +) + +var ens = strings.ToLower(constants.EnsContractAddress) +var tusd = strings.ToLower(constants.TusdContractAddress) + +var TusdConfig = config.ContractConfig{ + Network: "", + Addresses: map[string]bool{ + tusd: true, + }, + Abis: map[string]string{ + tusd: "", + }, + Events: map[string][]string{ + tusd: []string{"Transfer"}, + }, + Methods: map[string][]string{ + tusd: nil, + }, + MethodArgs: map[string][]string{ + tusd: nil, + }, + EventArgs: map[string][]string{ + tusd: nil, + }, + StartingBlocks: map[string]int64{ + tusd: 5197514, + }, +} + +var ENSConfig = config.ContractConfig{ + Network: "", + Addresses: map[string]bool{ + ens: true, + }, + Abis: map[string]string{ + ens: "", + }, + Events: map[string][]string{ + ens: []string{"NewOwner"}, + }, + Methods: map[string][]string{ + ens: nil, + }, + MethodArgs: map[string][]string{ + ens: nil, + }, + EventArgs: map[string][]string{ + ens: nil, + }, + StartingBlocks: map[string]int64{ + ens: 3327417, + }, +} + +var ENSandTusdConfig = config.ContractConfig{ + Network: "", + Addresses: map[string]bool{ + ens: true, + tusd: true, + }, + Abis: map[string]string{ + ens: "", + tusd: "", + }, + Events: map[string][]string{ + ens: []string{"NewOwner"}, + tusd: []string{"Transfer"}, + }, + Methods: map[string][]string{ + ens: nil, + tusd: nil, + }, + MethodArgs: map[string][]string{ + ens: nil, + tusd: nil, + }, + EventArgs: map[string][]string{ + ens: nil, + tusd: nil, + }, + StartingBlocks: map[string]int64{ + ens: 3327417, + tusd: 5197514, + }, +} diff --git a/pkg/omni/shared/parser/parser.go b/pkg/contract_watcher/shared/parser/parser.go similarity index 95% rename from pkg/omni/shared/parser/parser.go rename to pkg/contract_watcher/shared/parser/parser.go index 14860f43..77af237b 100644 --- a/pkg/omni/shared/parser/parser.go +++ b/pkg/contract_watcher/shared/parser/parser.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,9 +22,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) // Parser is used to fetch and parse contract ABIs @@ -98,7 +98,7 @@ func (p *parser) lookUp(contractAddr string) (string, error) { return v, nil } - return "", errors.New("ABI not present in lookup tabe") + return "", errors.New("ABI not present in lookup table") } // Returns only specified methods, if they meet the criteria diff --git a/pkg/omni/shared/parser/parser_suite_test.go b/pkg/contract_watcher/shared/parser/parser_suite_test.go similarity index 96% rename from pkg/omni/shared/parser/parser_suite_test.go rename to pkg/contract_watcher/shared/parser/parser_suite_test.go index ccc11fb2..ce6d4944 100644 --- a/pkg/omni/shared/parser/parser_suite_test.go +++ b/pkg/contract_watcher/shared/parser/parser_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/omni/shared/parser/parser_test.go b/pkg/contract_watcher/shared/parser/parser_test.go similarity index 93% rename from pkg/omni/shared/parser/parser_test.go rename to pkg/contract_watcher/shared/parser/parser_test.go index 0b7f3aa3..95b065cb 100644 --- a/pkg/omni/shared/parser/parser_test.go +++ b/pkg/contract_watcher/shared/parser/parser_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -21,11 +21,11 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/parser" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) var _ = Describe("Parser", func() { @@ -112,7 +112,7 @@ var _ = Describe("Parser", func() { Expect(abiTy).To(Equal(abi.UintTy)) pgTy = e.Fields[2].PgType - Expect(pgTy).To(Equal("DECIMAL")) + Expect(pgTy).To(Equal("NUMERIC")) _, ok = events["Approval"] Expect(ok).To(Equal(false)) @@ -143,7 +143,7 @@ var _ = Describe("Parser", func() { Expect(abiTy).To(Equal(abi.UintTy)) pgTy = balOf.Return[0].PgType - Expect(pgTy).To(Equal("DECIMAL")) + Expect(pgTy).To(Equal("NUMERIC")) }) @@ -200,7 +200,7 @@ var _ = Describe("Parser", func() { Expect(abiTy).To(Equal(abi.UintTy)) pgTy = balOf.Return[0].PgType - Expect(pgTy).To(Equal("DECIMAL")) + Expect(pgTy).To(Equal("NUMERIC")) }) diff --git a/pkg/omni/shared/poller/poller.go b/pkg/contract_watcher/shared/poller/poller.go similarity index 93% rename from pkg/omni/shared/poller/poller.go rename to pkg/contract_watcher/shared/poller/poller.go index c1b30a93..b3f1c51b 100644 --- a/pkg/omni/shared/poller/poller.go +++ b/pkg/contract_watcher/shared/poller/poller.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -26,15 +26,15 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) type Poller interface { - PollContract(con contract.Contract) error + PollContract(con contract.Contract, lastBlock int64) error PollContractAt(con contract.Contract, blockNumber int64) error FetchContractData(contractAbi, contractAddress, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error } @@ -52,9 +52,11 @@ func NewPoller(blockChain core.BlockChain, db *postgres.DB, mode types.Mode) *po } } -func (p *poller) PollContract(con contract.Contract) error { - for i := con.StartingBlock; i <= con.LastBlock; i++ { - p.PollContractAt(con, i) +func (p *poller) PollContract(con contract.Contract, lastBlock int64) error { + for i := con.StartingBlock; i <= lastBlock; i++ { + if err := p.PollContractAt(con, i); err != nil { + return err + } } return nil @@ -98,7 +100,6 @@ func (p *poller) pollNoArgAt(m types.Method, bn int64) error { if err != nil { return errors.New(fmt.Sprintf("poller error calling 0 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err)) } - strOut, err := stringify(out) if err != nil { return err @@ -138,8 +139,8 @@ func (p *poller) pollSingleArgAt(m types.Method, bn int64) error { if len(args) == 0 { // If we haven't collected any args by now we can't call the method return nil } - results := make([]types.Result, 0, len(args)) + results := make([]types.Result, 0, len(args)) for arg := range args { in := []interface{}{arg} strIn := []interface{}{contract.StringifyArg(arg)} @@ -160,7 +161,6 @@ func (p *poller) pollSingleArgAt(m types.Method, bn int64) error { result.Output = strOut results = append(results, result) } - // Persist result set as batch err := p.PersistResults(results, m, p.contract.Address, p.contract.Name) if err != nil { @@ -204,7 +204,6 @@ func (p *poller) pollDoubleArgAt(m types.Method, bn int64) error { } results := make([]types.Result, 0, len(firstArgs)*len(secondArgs)) - for arg1 := range firstArgs { for arg2 := range secondArgs { in := []interface{}{arg1, arg2} @@ -215,18 +214,15 @@ func (p *poller) pollDoubleArgAt(m types.Method, bn int64) error { if err != nil { return errors.New(fmt.Sprintf("poller error calling 2 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err)) } - strOut, err := stringify(out) if err != nil { return err } - p.cache(out) result.Output = strOut result.Inputs = strIn results = append(results, result) - } } @@ -243,9 +239,8 @@ func (p *poller) FetchContractData(contractAbi, contractAddress, method string, return p.bc.FetchContractData(contractAbi, contractAddress, method, methodArgs, result, blockNumber) } -// This is used to cache an method return value if method piping is turned on +// This is used to cache a method return value if method piping is turned on func (p *poller) cache(out interface{}) { - // Cache returned value if piping is turned on if p.contract.Piping { switch out.(type) { case common.Hash: diff --git a/pkg/omni/shared/repository/event_repository.go b/pkg/contract_watcher/shared/repository/event_repository.go similarity index 97% rename from pkg/omni/shared/repository/event_repository.go rename to pkg/contract_watcher/shared/repository/event_repository.go index 4b599447..3701ec3e 100644 --- a/pkg/omni/shared/repository/event_repository.go +++ b/pkg/contract_watcher/shared/repository/event_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,9 +23,9 @@ import ( "github.com/hashicorp/golang-lru" + "github.com/vulcanize/vulcanizedb/libraries/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/light/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) const ( @@ -97,7 +97,7 @@ func (r *eventRepository) persistLogs(logs []types.Log, eventInfo types.Event, c // Creates a custom postgres command to persist logs for the given event (compatible with light synced vDB) func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error { - tx, err := r.db.Begin() + tx, err := r.db.Beginx() if err != nil { return err } @@ -151,7 +151,7 @@ func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types // Creates a custom postgres command to persist logs for the given event (compatible with fully synced vDB) func (r *eventRepository) persistFullSyncLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error { - tx, err := r.db.Begin() + tx, err := r.db.Beginx() if err != nil { return err } diff --git a/pkg/omni/shared/repository/event_repository_test.go b/pkg/contract_watcher/shared/repository/event_repository_test.go similarity index 93% rename from pkg/omni/shared/repository/event_repository_test.go rename to pkg/contract_watcher/shared/repository/event_repository_test.go index 06cac7d7..44a4cd66 100644 --- a/pkg/omni/shared/repository/event_repository_test.go +++ b/pkg/contract_watcher/shared/repository/event_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -26,17 +26,17 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + fc "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/converter" + lc "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/converter" + lr "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks" + sr "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - fc "github.com/vulcanize/vulcanizedb/pkg/omni/full/converter" - lc "github.com/vulcanize/vulcanizedb/pkg/omni/light/converter" - lr "github.com/vulcanize/vulcanizedb/pkg/omni/light/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks" - sr "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) var _ = Describe("Repository", func() { @@ -134,7 +134,8 @@ var _ = Describe("Repository", func() { Describe("PersistLogs", func() { BeforeEach(func() { - c := fc.NewConverter(con) + c := fc.Converter{} + c.Update(con) log, err = c.Convert(mockEvent, event) Expect(err).ToNot(HaveOccurred()) }) @@ -276,7 +277,8 @@ var _ = Describe("Repository", func() { headerRepository := repositories.NewHeaderRepository(db) headerID, err = headerRepository.CreateOrUpdateHeader(mocks.MockHeader1) Expect(err).ToNot(HaveOccurred()) - c := lc.NewConverter(con) + c := lc.Converter{} + c.Update(con) logs, err = c.Convert([]geth.Log{mockLog1, mockLog2}, event, headerID) Expect(err).ToNot(HaveOccurred()) }) diff --git a/pkg/omni/shared/repository/method_repository.go b/pkg/contract_watcher/shared/repository/method_repository.go similarity index 98% rename from pkg/omni/shared/repository/method_repository.go rename to pkg/contract_watcher/shared/repository/method_repository.go index 4231404b..2616675e 100644 --- a/pkg/omni/shared/repository/method_repository.go +++ b/pkg/contract_watcher/shared/repository/method_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,8 +23,8 @@ import ( "github.com/hashicorp/golang-lru" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) const methodCacheSize = 1000 @@ -77,7 +77,7 @@ func (r *methodRepository) PersistResults(results []types.Result, methodInfo typ // Creates a custom postgres command to persist logs for the given event func (r *methodRepository) persistResults(results []types.Result, methodInfo types.Method, contractAddr, contractName string) error { - tx, err := r.DB.Begin() + tx, err := r.DB.Beginx() if err != nil { return err } diff --git a/pkg/omni/shared/repository/method_repository_test.go b/pkg/contract_watcher/shared/repository/method_repository_test.go similarity index 95% rename from pkg/omni/shared/repository/method_repository_test.go rename to pkg/contract_watcher/shared/repository/method_repository_test.go index c6936e8a..b50f1ee5 100644 --- a/pkg/omni/shared/repository/method_repository_test.go +++ b/pkg/contract_watcher/shared/repository/method_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,12 +23,12 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) var _ = Describe("Repository", func() { diff --git a/pkg/omni/shared/repository/repository_suite_test.go b/pkg/contract_watcher/shared/repository/repository_suite_test.go similarity index 90% rename from pkg/omni/shared/repository/repository_suite_test.go rename to pkg/contract_watcher/shared/repository/repository_suite_test.go index a1bfc548..1ffa6ded 100644 --- a/pkg/omni/shared/repository/repository_suite_test.go +++ b/pkg/contract_watcher/shared/repository/repository_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package repository_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -31,5 +31,5 @@ func TestRepository(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/omni/shared/retriever/address_retriever.go b/pkg/contract_watcher/shared/retriever/address_retriever.go similarity index 95% rename from pkg/omni/shared/retriever/address_retriever.go rename to pkg/contract_watcher/shared/retriever/address_retriever.go index f56d448f..6acdf72b 100644 --- a/pkg/omni/shared/retriever/address_retriever.go +++ b/pkg/contract_watcher/shared/retriever/address_retriever.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,14 +18,14 @@ package retriever import ( "fmt" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "strings" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" ) // Address retriever is used to retrieve the addresses associated with a contract diff --git a/pkg/omni/shared/retriever/address_retriever_test.go b/pkg/contract_watcher/shared/retriever/address_retriever_test.go similarity index 85% rename from pkg/omni/shared/retriever/address_retriever_test.go rename to pkg/contract_watcher/shared/retriever/address_retriever_test.go index 48f45531..c8aa6fff 100644 --- a/pkg/omni/shared/retriever/address_retriever_test.go +++ b/pkg/contract_watcher/shared/retriever/address_retriever_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -21,15 +21,15 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/converter" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/repository" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/retriever" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/omni/full/converter" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/retriever" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" ) var mockEvent = core.WatchedEvent{ @@ -64,7 +64,8 @@ var _ = Describe("Address Retriever Test", func() { err = info.GenerateFilters() Expect(err).ToNot(HaveOccurred()) - c := converter.NewConverter(info) + c := converter.Converter{} + c.Update(info) log, err = c.Convert(mockEvent, event) Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/omni/shared/retriever/retriever_suite_test.go b/pkg/contract_watcher/shared/retriever/retriever_suite_test.go similarity index 90% rename from pkg/omni/shared/retriever/retriever_suite_test.go rename to pkg/contract_watcher/shared/retriever/retriever_suite_test.go index b46c31fd..aff7fab1 100644 --- a/pkg/omni/shared/retriever/retriever_suite_test.go +++ b/pkg/contract_watcher/shared/retriever/retriever_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,8 @@ package retriever_test import ( + "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" . "github.com/onsi/ginkgo" @@ -31,5 +31,5 @@ func TestRetriever(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetOutput(ioutil.Discard) + logrus.SetOutput(ioutil.Discard) }) diff --git a/pkg/omni/shared/types/event.go b/pkg/contract_watcher/shared/types/event.go similarity index 96% rename from pkg/omni/shared/types/event.go rename to pkg/contract_watcher/shared/types/event.go index 8d801d15..2818cc8d 100644 --- a/pkg/omni/shared/types/event.go +++ b/pkg/contract_watcher/shared/types/event.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -38,7 +38,7 @@ type Field struct { // Struct to hold instance of an event log data type Log struct { - Id int64 // VulcanizeIdLog for full sync and header ID for light sync omni watcher + Id int64 // VulcanizeIdLog for full sync and header ID for light sync contract watcher Values map[string]string // Map of event input names to their values // Used for full sync only @@ -64,7 +64,7 @@ func NewEvent(e abi.Event) Event { case abi.HashTy, abi.AddressTy: fields[i].PgType = "CHARACTER VARYING(66)" case abi.IntTy, abi.UintTy: - fields[i].PgType = "DECIMAL" + fields[i].PgType = "NUMERIC" case abi.BoolTy: fields[i].PgType = "BOOLEAN" case abi.BytesTy, abi.FixedBytesTy: diff --git a/pkg/omni/shared/types/method.go b/pkg/contract_watcher/shared/types/method.go similarity index 96% rename from pkg/omni/shared/types/method.go rename to pkg/contract_watcher/shared/types/method.go index fbd3e25a..795b5b7f 100644 --- a/pkg/omni/shared/types/method.go +++ b/pkg/contract_watcher/shared/types/method.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -53,7 +53,7 @@ func NewMethod(m abi.Method) Method { case abi.HashTy, abi.AddressTy: inputs[i].PgType = "CHARACTER VARYING(66)" case abi.IntTy, abi.UintTy: - inputs[i].PgType = "DECIMAL" + inputs[i].PgType = "NUMERIC" case abi.BoolTy: inputs[i].PgType = "BOOLEAN" case abi.BytesTy, abi.FixedBytesTy: @@ -77,7 +77,7 @@ func NewMethod(m abi.Method) Method { case abi.HashTy, abi.AddressTy: outputs[i].PgType = "CHARACTER VARYING(66)" case abi.IntTy, abi.UintTy: - outputs[i].PgType = "DECIMAL" + outputs[i].PgType = "NUMERIC" case abi.BoolTy: outputs[i].PgType = "BOOLEAN" case abi.BytesTy, abi.FixedBytesTy: diff --git a/pkg/omni/shared/types/mode.go b/pkg/contract_watcher/shared/types/mode.go similarity index 86% rename from pkg/omni/shared/types/mode.go rename to pkg/contract_watcher/shared/types/mode.go index 71e5c531..9f37a857 100644 --- a/pkg/omni/shared/types/mode.go +++ b/pkg/contract_watcher/shared/types/mode.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -47,7 +47,7 @@ func (mode Mode) MarshalText() ([]byte, error) { case FullSync: return []byte("full"), nil default: - return nil, fmt.Errorf("omni watcher: unknown mode %d, want LightSync or FullSync", mode) + return nil, fmt.Errorf("contract watcher: unknown mode %d, want LightSync or FullSync", mode) } } @@ -58,7 +58,7 @@ func (mode *Mode) UnmarshalText(text []byte) error { case "full": *mode = FullSync default: - return fmt.Errorf(`omni watcher: unknown mode %q, want "light" or "full"`, text) + return fmt.Errorf(`contract watcher: unknown mode %q, want "light" or "full"`, text) } return nil } diff --git a/pkg/core/block.go b/pkg/core/block.go index cf3eb5e6..e877f80d 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,20 +17,21 @@ package core type Block struct { - Reward float64 `db:"reward"` - Difficulty int64 `db:"difficulty"` - ExtraData string `db:"extra_data"` - GasLimit uint64 `db:"gaslimit"` - GasUsed uint64 `db:"gasused"` - Hash string `db:"hash"` - IsFinal bool `db:"is_final"` - Miner string `db:"miner"` - Nonce string `db:"nonce"` - Number int64 `db:"number"` - ParentHash string `db:"parenthash"` - Size string `db:"size"` - Time int64 `db:"time"` - Transactions []Transaction - UncleHash string `db:"uncle_hash"` - UnclesReward float64 `db:"uncles_reward"` + Reward string `db:"reward"` + Difficulty int64 `db:"difficulty"` + ExtraData string `db:"extra_data"` + GasLimit uint64 `db:"gas_limit"` + GasUsed uint64 `db:"gas_used"` + Hash string `db:"hash"` + IsFinal bool `db:"is_final"` + Miner string `db:"miner"` + Nonce string `db:"nonce"` + Number int64 `db:"number"` + ParentHash string `db:"parent_hash"` + Size string `db:"size"` + Time int64 `db:"time"` + Transactions []TransactionModel + UncleHash string `db:"uncle_hash"` + UnclesReward string `db:"uncles_reward"` + Uncles []Uncle } diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 9b182f02..be2fe9eb 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package core import ( + "github.com/ethereum/go-ethereum/common" "math/big" "github.com/ethereum/go-ethereum" @@ -25,14 +26,21 @@ import ( type BlockChain interface { ContractDataFetcher + AccountDataFetcher GetBlockByNumber(blockNumber int64) (Block, error) - GetHeaderByNumber(blockNumber int64) (Header, error) - GetLogs(contract Contract, startingBlockNumber *big.Int, endingBlockNumber *big.Int) ([]Log, error) GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error) - LastBlock() *big.Int + GetHeaderByNumber(blockNumber int64) (Header, error) + GetHeaderByNumbers(blockNumbers []int64) ([]Header, error) + GetLogs(contract Contract, startingBlockNumber *big.Int, endingBlockNumber *big.Int) ([]Log, error) + GetTransactions(transactionHashes []common.Hash) ([]TransactionModel, error) + LastBlock() (*big.Int, error) Node() Node } type ContractDataFetcher interface { FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error } + +type AccountDataFetcher interface { + GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error) +} diff --git a/pkg/core/contract.go b/pkg/core/contract.go index 1ca4dffd..48646dbf 100644 --- a/pkg/core/contract.go +++ b/pkg/core/contract.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -19,5 +19,5 @@ package core type Contract struct { Abi string Hash string - Transactions []Transaction + Transactions []TransactionModel } diff --git a/pkg/core/eth_client.go b/pkg/core/eth_client.go index 2ec6c6bb..d2aa2779 100644 --- a/pkg/core/eth_client.go +++ b/pkg/core/eth_client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -32,4 +32,5 @@ type EthClient interface { HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) + BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) } diff --git a/pkg/core/header.go b/pkg/core/header.go index 007e3aad..591aec7d 100644 --- a/pkg/core/header.go +++ b/pkg/core/header.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/core/log.go b/pkg/core/log.go index 33ff4146..16962055 100644 --- a/pkg/core/log.go +++ b/pkg/core/log.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/core/node_info.go b/pkg/core/node_info.go index 6b84ca36..db1d9de6 100644 --- a/pkg/core/node_info.go +++ b/pkg/core/node_info.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/core/receipts.go b/pkg/core/receipts.go index dad982e6..f58ba4f6 100644 --- a/pkg/core/receipts.go +++ b/pkg/core/receipts.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,11 +18,12 @@ package core type Receipt struct { Bloom string - ContractAddress string - CumulativeGasUsed uint64 - GasUsed uint64 + ContractAddress string `db:"contract_address"` + CumulativeGasUsed uint64 `db:"cumulative_gas_used"` + GasUsed uint64 `db:"gas_used"` Logs []Log - StateRoot string + StateRoot string `db:"state_root"` Status int - TxHash string + TxHash string `db:"tx_hash"` + Rlp []byte `db:"rlp"` } diff --git a/pkg/core/rpc_client.go b/pkg/core/rpc_client.go index 5f739383..1f52b27a 100644 --- a/pkg/core/rpc_client.go +++ b/pkg/core/rpc_client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -16,10 +16,15 @@ package core -import "context" +import ( + "context" + + "github.com/vulcanize/vulcanizedb/pkg/geth/client" +) type RpcClient interface { CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + BatchCall(batch []client.BatchElem) error IpcPath() string SupportedModules() (map[string]string, error) } diff --git a/pkg/core/topics.go b/pkg/core/topics.go index 643579b9..d1e2f11a 100644 --- a/pkg/core/topics.go +++ b/pkg/core/topics.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/core/transaction.go b/pkg/core/transaction.go index ca3beb9a..2ef428d1 100644 --- a/pkg/core/transaction.go +++ b/pkg/core/transaction.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -16,14 +16,31 @@ package core -type Transaction struct { - Hash string `db:"hash"` - Data string `db:"input_data"` - Nonce uint64 `db:"nonce"` - To string `db:"tx_to"` +type TransactionModel struct { + Data []byte `db:"input_data"` From string `db:"tx_from"` - GasLimit uint64 `db:"gaslimit"` - GasPrice int64 `db:"gasprice"` + GasLimit uint64 `db:"gas_limit"` + GasPrice int64 `db:"gas_price"` + Hash string + Nonce uint64 + Raw []byte `db:"raw"` Receipt - Value string `db:"value"` + To string `db:"tx_to"` + TxIndex int64 `db:"tx_index"` + Value string +} + +type RpcTransaction struct { + Nonce string `json:"nonce"` + GasPrice string `json:"gasPrice"` + GasLimit string `json:"gas"` + Recipient string `json:"to"` + Amount string `json:"value"` + Payload string `json:"input"` + V string `json:"v"` + R string `json:"r"` + S string `json:"s"` + Hash string + From string + TransactionIndex string `json:"transactionIndex"` } diff --git a/pkg/core/uncle.go b/pkg/core/uncle.go new file mode 100644 index 00000000..dfece8e7 --- /dev/null +++ b/pkg/core/uncle.go @@ -0,0 +1,26 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package core + +type Uncle struct { + Id int64 + Miner string + Reward string + Hash string + Timestamp string `db:"block_timestamp"` + Raw []byte +} diff --git a/pkg/core/watched_event_log.go b/pkg/core/watched_event_log.go index fa2a495b..695bb94e 100644 --- a/pkg/core/watched_event_log.go +++ b/pkg/core/watched_event_log.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/crypto/crypto_suite_test.go b/pkg/crypto/crypto_suite_test.go index 4d08b0b0..25e15381 100644 --- a/pkg/crypto/crypto_suite_test.go +++ b/pkg/crypto/crypto_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/crypto/parser.go b/pkg/crypto/parser.go index 91af01a8..bf65cb7f 100644 --- a/pkg/crypto/parser.go +++ b/pkg/crypto/parser.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/crypto/parser_test.go b/pkg/crypto/parser_test.go index 711e9d83..b1576c42 100644 --- a/pkg/crypto/parser_test.go +++ b/pkg/crypto/parser_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/errors.go b/pkg/datastore/errors.go new file mode 100644 index 00000000..97da92e5 --- /dev/null +++ b/pkg/datastore/errors.go @@ -0,0 +1,19 @@ +package datastore + +import "fmt" + +func ErrBlockDoesNotExist(blockNumber int64) error { + return fmt.Errorf("Block number %d does not exist", blockNumber) +} + +func ErrContractDoesNotExist(contractHash string) error { + return fmt.Errorf("Contract %v does not exist", contractHash) +} + +func ErrFilterDoesNotExist(name string) error { + return fmt.Errorf("filter %s does not exist", name) +} + +func ErrReceiptDoesNotExist(txHash string) error { + return fmt.Errorf("Receipt for tx: %v does not exist", txHash) +} diff --git a/pkg/datastore/ethereum/config.go b/pkg/datastore/ethereum/config.go index 589ae819..ffc463ab 100644 --- a/pkg/datastore/ethereum/config.go +++ b/pkg/datastore/ethereum/config.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/ethereum/database.go b/pkg/datastore/ethereum/database.go index 2f4bb577..2f36ea2a 100644 --- a/pkg/datastore/ethereum/database.go +++ b/pkg/datastore/ethereum/database.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,10 +18,10 @@ package ethereum import ( "fmt" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/sirupsen/logrus" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/vulcanize/vulcanizedb/pkg/datastore/ethereum/level" ) @@ -35,8 +35,9 @@ type Database interface { func CreateDatabase(config DatabaseConfig) (Database, error) { switch config.Type { case Level: - levelDBConnection, err := ethdb.NewLDBDatabase(config.Path, 128, 1024) + levelDBConnection, err := rawdb.NewLevelDBDatabase(config.Path, 128, 1024, "vdb") if err != nil { + logrus.Error("CreateDatabase: error connecting to new LDBD: ", err) return nil, err } levelDBReader := level.NewLevelDatabaseReader(levelDBConnection) diff --git a/pkg/datastore/ethereum/level/database.go b/pkg/datastore/ethereum/level/database.go index 6deb7125..a05d95b7 100644 --- a/pkg/datastore/ethereum/level/database.go +++ b/pkg/datastore/ethereum/level/database.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/ethereum/level/database_reader.go b/pkg/datastore/ethereum/level/database_reader.go index 66f49c8d..670fb2de 100644 --- a/pkg/datastore/ethereum/level/database_reader.go +++ b/pkg/datastore/ethereum/level/database_reader.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" ) type Reader interface { @@ -31,10 +32,10 @@ type Reader interface { } type LevelDatabaseReader struct { - reader rawdb.DatabaseReader + reader ethdb.Reader } -func NewLevelDatabaseReader(reader rawdb.DatabaseReader) *LevelDatabaseReader { +func NewLevelDatabaseReader(reader ethdb.Reader) *LevelDatabaseReader { return &LevelDatabaseReader{reader: reader} } diff --git a/pkg/datastore/ethereum/level/database_test.go b/pkg/datastore/ethereum/level/database_test.go index 5e9de31e..e8b1fe1a 100644 --- a/pkg/datastore/ethereum/level/database_test.go +++ b/pkg/datastore/ethereum/level/database_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/ethereum/level/level_suite_test.go b/pkg/datastore/ethereum/level/level_suite_test.go index 26c6cb49..7aac15b2 100644 --- a/pkg/datastore/ethereum/level/level_suite_test.go +++ b/pkg/datastore/ethereum/level/level_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/postgres/errors.go b/pkg/datastore/postgres/errors.go new file mode 100644 index 00000000..ffb23e78 --- /dev/null +++ b/pkg/datastore/postgres/errors.go @@ -0,0 +1,38 @@ +package postgres + +import ( + "errors" + "fmt" +) + +const ( + BeginTransactionFailedMsg = "failed to begin transaction" + DbConnectionFailedMsg = "db connection failed" + DeleteQueryFailedMsg = "delete query failed" + InsertQueryFailedMsg = "insert query failed" + SettingNodeFailedMsg = "unable to set db node" +) + +func ErrBeginTransactionFailed(beginErr error) error { + return formatError(BeginTransactionFailedMsg, beginErr.Error()) +} + +func ErrDBConnectionFailed(connectErr error) error { + return formatError(DbConnectionFailedMsg, connectErr.Error()) +} + +func ErrDBDeleteFailed(deleteErr error) error { + return formatError(DeleteQueryFailedMsg, deleteErr.Error()) +} + +func ErrDBInsertFailed(insertErr error) error { + return formatError(InsertQueryFailedMsg, insertErr.Error()) +} + +func ErrUnableToSetNode(setErr error) error { + return formatError(SettingNodeFailedMsg, setErr.Error()) +} + +func formatError(msg, err string) error { + return errors.New(fmt.Sprintf("%s: %s", msg, err)) +} diff --git a/pkg/datastore/postgres/postgres.go b/pkg/datastore/postgres/postgres.go index 82a1b2ac..66cf535f 100644 --- a/pkg/datastore/postgres/postgres.go +++ b/pkg/datastore/postgres/postgres.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,6 @@ package postgres import ( - "errors" - "github.com/jmoiron/sqlx" _ "github.com/lib/pq" //postgres driver "github.com/vulcanize/vulcanizedb/pkg/config" @@ -31,23 +29,18 @@ type DB struct { NodeID int64 } -var ( - ErrDBInsertFailed = errors.New("postgres: insert failed") - ErrDBDeleteFailed = errors.New("postgres: delete failed") - ErrDBConnectionFailed = errors.New("postgres: db connection failed") - ErrUnableToSetNode = errors.New("postgres: unable to set node") -) +var () func NewDB(databaseConfig config.Database, node core.Node) (*DB, error) { connectString := config.DbConnectionString(databaseConfig) - db, err := sqlx.Connect("postgres", connectString) - if err != nil { - return &DB{}, ErrDBConnectionFailed + db, connectErr := sqlx.Connect("postgres", connectString) + if connectErr != nil { + return &DB{}, ErrDBConnectionFailed(connectErr) } pg := DB{DB: db, Node: node} - err = pg.CreateNode(&node) - if err != nil { - return &DB{}, ErrUnableToSetNode + nodeErr := pg.CreateNode(&node) + if nodeErr != nil { + return &DB{}, ErrUnableToSetNode(nodeErr) } return &pg, nil } @@ -66,7 +59,7 @@ func (db *DB) CreateNode(node *core.Node) error { RETURNING id`, node.GenesisBlock, node.NetworkID, node.ID, node.ClientName).Scan(&nodeId) if err != nil { - return ErrUnableToSetNode + return ErrUnableToSetNode(err) } db.NodeID = nodeId return nil diff --git a/pkg/datastore/postgres/postgres_suite_test.go b/pkg/datastore/postgres/postgres_suite_test.go index 8a86a397..0868f58c 100644 --- a/pkg/datastore/postgres/postgres_suite_test.go +++ b/pkg/datastore/postgres/postgres_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -19,8 +19,8 @@ package postgres_test import ( "testing" + log "github.com/sirupsen/logrus" "io/ioutil" - "log" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" diff --git a/pkg/datastore/postgres/postgres_test.go b/pkg/datastore/postgres/postgres_test.go index 447665e3..1bf0e92e 100644 --- a/pkg/datastore/postgres/postgres_test.go +++ b/pkg/datastore/postgres/postgres_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -88,7 +88,7 @@ var _ = Describe("Postgres DB", func() { badBlock := core.Block{ Number: 123, Nonce: badNonce, - Transactions: []core.Transaction{}, + Transactions: []core.TransactionModel{}, } node := core.Node{GenesisBlock: "GENESIS", NetworkID: 1, ID: "x123", ClientName: "geth"} db := test_config.NewTestDB(node) @@ -109,14 +109,18 @@ var _ = Describe("Postgres DB", func() { _, err := postgres.NewDB(invalidDatabase, node) - Expect(err).To(Equal(postgres.ErrDBConnectionFailed)) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(postgres.DbConnectionFailedMsg)) }) It("throws error when can't create node", func() { badHash := fmt.Sprintf("x %s", strings.Repeat("1", 100)) node := core.Node{GenesisBlock: badHash, NetworkID: 1, ID: "x123", ClientName: "geth"} + _, err := postgres.NewDB(test_config.DBConfig, node) - Expect(err).To(Equal(postgres.ErrUnableToSetNode)) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(postgres.SettingNodeFailedMsg)) }) It("does not commit log if log is invalid", func() { @@ -134,17 +138,18 @@ var _ = Describe("Postgres DB", func() { err := logRepository.CreateLogs([]core.Log{badLog}, 123) Expect(err).ToNot(BeNil()) - savedBlock := logRepository.GetLogs("x123", 1) + savedBlock, err := logRepository.GetLogs("x123", 1) Expect(savedBlock).To(BeNil()) + Expect(err).To(Not(HaveOccurred())) }) It("does not commit block or transactions if transaction is invalid", func() { //badHash violates db To field length badHash := fmt.Sprintf("x %s", strings.Repeat("1", 100)) - badTransaction := core.Transaction{To: badHash} + badTransaction := core.TransactionModel{To: badHash} block := core.Block{ Number: 123, - Transactions: []core.Transaction{badTransaction}, + Transactions: []core.TransactionModel{badTransaction}, } node := core.Node{GenesisBlock: "GENESIS", NetworkID: 1, ID: "x123", ClientName: "geth"} db, _ := postgres.NewDB(test_config.DBConfig, node) diff --git a/pkg/datastore/postgres/repositories/block_repository.go b/pkg/datastore/postgres/repositories/block_repository.go index 189ce942..979bd633 100644 --- a/pkg/datastore/postgres/repositories/block_repository.go +++ b/pkg/datastore/postgres/repositories/block_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,12 +17,11 @@ package repositories import ( - "context" "database/sql" "errors" - "log" "github.com/jmoiron/sqlx" + log "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" @@ -43,12 +42,14 @@ func NewBlockRepository(database *postgres.DB) *BlockRepository { return &BlockRepository{database: database} } -func (blockRepository BlockRepository) SetBlocksStatus(chainHead int64) { +func (blockRepository BlockRepository) SetBlocksStatus(chainHead int64) error { cutoff := chainHead - blocksFromHeadBeforeFinal - blockRepository.database.Exec(` + _, err := blockRepository.database.Exec(` UPDATE blocks SET is_final = TRUE WHERE is_final = FALSE AND number < $1`, cutoff) + + return err } func (blockRepository BlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) { @@ -70,7 +71,7 @@ func (blockRepository BlockRepository) CreateOrUpdateBlock(block core.Block) (in func (blockRepository BlockRepository) MissingBlockNumbers(startingBlockNumber int64, highestBlockNumber int64, nodeId string) []int64 { numbers := make([]int64, 0) - blockRepository.database.Select(&numbers, + err := blockRepository.database.Select(&numbers, `SELECT all_block_numbers FROM ( SELECT generate_series($1::INT, $2::INT) AS all_block_numbers) series @@ -79,6 +80,9 @@ func (blockRepository BlockRepository) MissingBlockNumbers(startingBlockNumber i ) `, startingBlockNumber, highestBlockNumber, nodeId) + if err != nil { + log.Error("MissingBlockNumbers: error getting blocks: ", err) + } return numbers } @@ -86,13 +90,13 @@ func (blockRepository BlockRepository) GetBlock(blockNumber int64) (core.Block, blockRows := blockRepository.database.QueryRowx( `SELECT id, number, - gaslimit, - gasused, + gas_limit, + gas_used, time, difficulty, hash, nonce, - parenthash, + parent_hash, size, uncle_hash, is_final, @@ -108,6 +112,7 @@ func (blockRepository BlockRepository) GetBlock(blockNumber int64) (core.Block, case sql.ErrNoRows: return core.Block{}, datastore.ErrBlockDoesNotExist(blockNumber) default: + log.Error("GetBlock: error loading blocks: ", err) return savedBlock, err } } @@ -116,30 +121,89 @@ func (blockRepository BlockRepository) GetBlock(blockNumber int64) (core.Block, func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, error) { var blockId int64 - tx, _ := blockRepository.database.BeginTx(context.Background(), nil) - err := tx.QueryRow( + tx, beginErr := blockRepository.database.Beginx() + if beginErr != nil { + return 0, postgres.ErrBeginTransactionFailed(beginErr) + } + insertBlockErr := tx.QueryRow( `INSERT INTO blocks - (eth_node_id, number, gaslimit, gasused, time, difficulty, hash, nonce, parenthash, size, uncle_hash, is_final, miner, extra_data, reward, uncles_reward, eth_node_fingerprint) + (eth_node_id, number, gas_limit, gas_used, time, difficulty, hash, nonce, parent_hash, size, uncle_hash, is_final, miner, extra_data, reward, uncles_reward, eth_node_fingerprint) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) RETURNING id `, - blockRepository.database.NodeID, block.Number, block.GasLimit, block.GasUsed, block.Time, block.Difficulty, block.Hash, block.Nonce, block.ParentHash, block.Size, block.UncleHash, block.IsFinal, block.Miner, block.ExtraData, block.Reward, block.UnclesReward, blockRepository.database.Node.ID). + blockRepository.database.NodeID, + block.Number, + block.GasLimit, + block.GasUsed, + block.Time, + block.Difficulty, + block.Hash, + block.Nonce, + block.ParentHash, + block.Size, + block.UncleHash, + block.IsFinal, + block.Miner, + block.ExtraData, + nullStringToZero(block.Reward), + nullStringToZero(block.UnclesReward), + blockRepository.database.Node.ID). Scan(&blockId) - if err != nil { - tx.Rollback() - return 0, err + if insertBlockErr != nil { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + log.Error("failed to rollback transaction: ", rollbackErr) + } + return 0, postgres.ErrDBInsertFailed(insertBlockErr) } - if len(block.Transactions) > 0 { - err = blockRepository.createTransactions(tx, blockId, block.Transactions) - if err != nil { + if len(block.Uncles) > 0 { + insertUncleErr := blockRepository.createUncles(tx, blockId, block.Hash, block.Uncles) + if insertUncleErr != nil { tx.Rollback() - return 0, postgres.ErrDBInsertFailed + return 0, postgres.ErrDBInsertFailed(insertUncleErr) } } - tx.Commit() + if len(block.Transactions) > 0 { + insertTxErr := blockRepository.createTransactions(tx, blockId, block.Transactions) + if insertTxErr != nil { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + log.Warn("failed to rollback transaction: ", rollbackErr) + } + return 0, postgres.ErrDBInsertFailed(insertTxErr) + } + } + commitErr := tx.Commit() + if commitErr != nil { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + log.Warn("failed to rollback transaction: ", rollbackErr) + } + return 0, commitErr + } return blockId, nil } -func (blockRepository BlockRepository) createTransactions(tx *sql.Tx, blockId int64, transactions []core.Transaction) error { +func (blockRepository BlockRepository) createUncles(tx *sqlx.Tx, blockId int64, blockHash string, uncles []core.Uncle) error { + for _, uncle := range uncles { + err := blockRepository.createUncle(tx, blockId, uncle) + if err != nil { + return err + } + } + return nil +} + +func (blockRepository BlockRepository) createUncle(tx *sqlx.Tx, blockId int64, uncle core.Uncle) error { + _, err := tx.Exec( + `INSERT INTO uncles + (hash, block_id, reward, miner, raw, block_timestamp, eth_node_id, eth_node_fingerprint) + VALUES ($1, $2, $3, $4, $5, $6, $7::NUMERIC, $8) + RETURNING id`, + uncle.Hash, blockId, nullStringToZero(uncle.Reward), uncle.Miner, uncle.Raw, uncle.Timestamp, blockRepository.database.NodeID, blockRepository.database.Node.ID) + return err +} + +func (blockRepository BlockRepository) createTransactions(tx *sqlx.Tx, blockId int64, transactions []core.TransactionModel) error { for _, transaction := range transactions { err := blockRepository.createTransaction(tx, blockId, transaction) if err != nil { @@ -159,13 +223,13 @@ func nullStringToZero(s string) string { return s } -func (blockRepository BlockRepository) createTransaction(tx *sql.Tx, blockId int64, transaction core.Transaction) error { +func (blockRepository BlockRepository) createTransaction(tx *sqlx.Tx, blockId int64, transaction core.TransactionModel) error { _, err := tx.Exec( - `INSERT INTO transactions - (block_id, hash, nonce, tx_to, tx_from, gaslimit, gasprice, value, input_data) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8::NUMERIC, $9) - RETURNING id`, - blockId, transaction.Hash, transaction.Nonce, transaction.To, transaction.From, transaction.GasLimit, transaction.GasPrice, nullStringToZero(transaction.Value), transaction.Data) + `INSERT INTO full_sync_transactions + (block_id, gas_limit, gas_price, hash, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") + VALUES ($1, $2::NUMERIC, $3::NUMERIC, $4, $5, $6::NUMERIC, $7, $8, $9::NUMERIC, $10, $11::NUMERIC) + RETURNING id`, blockId, transaction.GasLimit, transaction.GasPrice, transaction.Hash, transaction.Data, + transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To, nullStringToZero(transaction.Value)) if err != nil { return err } @@ -184,24 +248,25 @@ func (blockRepository BlockRepository) createTransaction(tx *sql.Tx, blockId int return nil } -func hasLogs(transaction core.Transaction) bool { +func hasLogs(transaction core.TransactionModel) bool { return len(transaction.Receipt.Logs) > 0 } -func hasReceipt(transaction core.Transaction) bool { +func hasReceipt(transaction core.TransactionModel) bool { return transaction.Receipt.TxHash != "" } -func (blockRepository BlockRepository) createReceipt(tx *sql.Tx, blockId int64, receipt core.Receipt) (int, error) { +func (blockRepository BlockRepository) createReceipt(tx *sqlx.Tx, blockId int64, receipt core.Receipt) (int, error) { //Not currently persisting log bloom filters var receiptId int err := tx.QueryRow( - `INSERT INTO receipts + `INSERT INTO full_sync_receipts (contract_address, tx_hash, cumulative_gas_used, gas_used, state_root, status, block_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id`, receipt.ContractAddress, receipt.TxHash, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, blockId).Scan(&receiptId) if err != nil { + log.Error("createReceipt: error inserting receipt: ", err) return receiptId, err } return receiptId, nil @@ -209,6 +274,7 @@ func (blockRepository BlockRepository) createReceipt(tx *sql.Tx, blockId int64, func (blockRepository BlockRepository) getBlockHash(block core.Block) (string, bool) { var retrievedBlockHash string + // TODO: handle possible error blockRepository.database.Get(&retrievedBlockHash, `SELECT hash FROM blocks @@ -217,7 +283,7 @@ func (blockRepository BlockRepository) getBlockHash(block core.Block) (string, b return retrievedBlockHash, blockExists(retrievedBlockHash) } -func (blockRepository BlockRepository) createLogs(tx *sql.Tx, logs []core.Log, receiptId int) error { +func (blockRepository BlockRepository) createLogs(tx *sqlx.Tx, logs []core.Log, receiptId int) error { for _, tlog := range logs { _, err := tx.Exec( `INSERT INTO logs (block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data, receipt_id) @@ -226,7 +292,7 @@ func (blockRepository BlockRepository) createLogs(tx *sql.Tx, logs []core.Log, r tlog.BlockNumber, tlog.Address, tlog.TxHash, tlog.Index, tlog.Topics[0], tlog.Topics[1], tlog.Topics[2], tlog.Topics[3], tlog.Data, receiptId, ) if err != nil { - return postgres.ErrDBInsertFailed + return postgres.ErrDBInsertFailed(err) } } return nil @@ -238,12 +304,10 @@ func blockExists(retrievedBlockHash string) bool { func (blockRepository BlockRepository) removeBlock(blockNumber int64) error { _, err := blockRepository.database.Exec( - `DELETE FROM - blocks - WHERE number=$1 AND eth_node_id=$2`, + `DELETE FROM blocks WHERE number=$1 AND eth_node_id=$2`, blockNumber, blockRepository.database.NodeID) if err != nil { - return postgres.ErrDBDeleteFailed + return postgres.ErrDBDeleteFailed(err) } return nil } @@ -256,31 +320,35 @@ func (blockRepository BlockRepository) loadBlock(blockRows *sqlx.Row) (core.Bloc var block b err := blockRows.StructScan(&block) if err != nil { + log.Error("loadBlock: error loading block: ", err) return core.Block{}, err } transactionRows, err := blockRepository.database.Queryx(` - SELECT hash, - nonce, - tx_to, - tx_from, - gaslimit, - gasprice, - value, - input_data - FROM transactions - WHERE block_id = $1 - ORDER BY hash`, block.ID) + SELECT hash, + gas_limit, + gas_price, + input_data, + nonce, + raw, + tx_from, + tx_index, + tx_to, + value + FROM full_sync_transactions + WHERE block_id = $1 + ORDER BY hash`, block.ID) if err != nil { + log.Error("loadBlock: error fetting transactions: ", err) return core.Block{}, err } block.Transactions = blockRepository.LoadTransactions(transactionRows) return block.Block, nil } -func (blockRepository BlockRepository) LoadTransactions(transactionRows *sqlx.Rows) []core.Transaction { - var transactions []core.Transaction +func (blockRepository BlockRepository) LoadTransactions(transactionRows *sqlx.Rows) []core.TransactionModel { + var transactions []core.TransactionModel for transactionRows.Next() { - var transaction core.Transaction + var transaction core.TransactionModel err := transactionRows.StructScan(&transaction) if err != nil { log.Fatal(err) diff --git a/pkg/datastore/postgres/repositories/block_repository_test.go b/pkg/datastore/postgres/repositories/block_repository_test.go index ae391424..873652be 100644 --- a/pkg/datastore/postgres/repositories/block_repository_test.go +++ b/pkg/datastore/postgres/repositories/block_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,10 @@ package repositories_test import ( + "bytes" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "math/big" "strconv" @@ -51,7 +55,8 @@ var _ = Describe("Saving blocks", func() { block := core.Block{ Number: 123, } - blockRepository.CreateOrUpdateBlock(block) + _, insertErr := blockRepository.CreateOrUpdateBlock(block) + Expect(insertErr).NotTo(HaveOccurred()) nodeTwo := core.Node{ GenesisBlock: "0x456", NetworkID: 1, @@ -79,8 +84,8 @@ var _ = Describe("Saving blocks", func() { uncleHash := "x789" blockSize := string("1000") difficulty := int64(10) - blockReward := float64(5.132) - unclesReward := float64(3.580) + blockReward := "5132000000000000000" + unclesReward := "3580000000000000000" block := core.Block{ Reward: blockReward, Difficulty: difficulty, @@ -98,8 +103,9 @@ var _ = Describe("Saving blocks", func() { UnclesReward: unclesReward, } - blockRepository.CreateOrUpdateBlock(block) + _, insertErr := blockRepository.CreateOrUpdateBlock(block) + Expect(insertErr).NotTo(HaveOccurred()) savedBlock, err := blockRepository.GetBlock(blockNumber) Expect(err).NotTo(HaveOccurred()) Expect(savedBlock.Reward).To(Equal(blockReward)) @@ -127,42 +133,120 @@ var _ = Describe("Saving blocks", func() { It("saves one transaction associated to the block", func() { block := core.Block{ Number: 123, - Transactions: []core.Transaction{{}}, + Transactions: []core.TransactionModel{fakes.FakeTransaction}, } - blockRepository.CreateOrUpdateBlock(block) + _, insertErr := blockRepository.CreateOrUpdateBlock(block) - savedBlock, _ := blockRepository.GetBlock(123) + Expect(insertErr).NotTo(HaveOccurred()) + savedBlock, getErr := blockRepository.GetBlock(123) + Expect(getErr).NotTo(HaveOccurred()) Expect(len(savedBlock.Transactions)).To(Equal(1)) }) It("saves two transactions associated to the block", func() { block := core.Block{ Number: 123, - Transactions: []core.Transaction{{}, {}}, + Transactions: []core.TransactionModel{fakes.FakeTransaction, fakes.FakeTransaction}, } - blockRepository.CreateOrUpdateBlock(block) + _, insertErr := blockRepository.CreateOrUpdateBlock(block) - savedBlock, _ := blockRepository.GetBlock(123) + Expect(insertErr).NotTo(HaveOccurred()) + savedBlock, getErr := blockRepository.GetBlock(123) + Expect(getErr).NotTo(HaveOccurred()) Expect(len(savedBlock.Transactions)).To(Equal(2)) }) + It("saves one uncle associated to the block", func() { + block := core.Block{ + Hash: fakes.FakeHash.String(), + Number: 123, + Transactions: []core.TransactionModel{fakes.FakeTransaction}, + Uncles: []core.Uncle{fakes.GetFakeUncle(common.BytesToHash([]byte{1, 2, 3}).String(), "100000")}, + UnclesReward: "156250000000000000", + } + + id, insertErr := blockRepository.CreateOrUpdateBlock(block) + + Expect(insertErr).NotTo(HaveOccurred()) + savedBlock, getErr := blockRepository.GetBlock(123) + Expect(getErr).NotTo(HaveOccurred()) + Expect(len(savedBlock.Transactions)).To(Equal(1)) + Expect(savedBlock.UnclesReward).To(Equal(big.NewInt(0).Div(big.NewInt(5000000000000000000), big.NewInt(32)).String())) + + var uncleModel core.Uncle + err := db.Get(&uncleModel, `SELECT hash, reward, miner, raw, block_timestamp FROM uncles + WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{1, 2, 3}).Hex()) + Expect(err).ToNot(HaveOccurred()) + Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{1, 2, 3}).Hex())) + Expect(uncleModel.Reward).To(Equal("100000")) + Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) + Expect(uncleModel.Timestamp).To(Equal("111111111")) + }) + + It("saves two uncles associated to the block", func() { + block := core.Block{ + Hash: fakes.FakeHash.String(), + Number: 123, + Transactions: []core.TransactionModel{fakes.FakeTransaction}, + Uncles: []core.Uncle{ + fakes.GetFakeUncle(common.BytesToHash([]byte{1, 2, 3}).String(), "100000"), + fakes.GetFakeUncle(common.BytesToHash([]byte{3, 2, 1}).String(), "90000")}, + UnclesReward: "312500000000000000", + } + + id, insertErr := blockRepository.CreateOrUpdateBlock(block) + + Expect(insertErr).NotTo(HaveOccurred()) + savedBlock, getErr := blockRepository.GetBlock(123) + Expect(getErr).NotTo(HaveOccurred()) + Expect(len(savedBlock.Transactions)).To(Equal(1)) + b := new(big.Int) + b.SetString("10000000000000000000", 10) + Expect(savedBlock.UnclesReward).To(Equal(big.NewInt(0).Div(b, big.NewInt(32)).String())) + + var uncleModel core.Uncle + err := db.Get(&uncleModel, `SELECT hash, reward, miner, raw, block_timestamp FROM uncles + WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{1, 2, 3}).Hex()) + Expect(err).ToNot(HaveOccurred()) + Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{1, 2, 3}).Hex())) + Expect(uncleModel.Reward).To(Equal("100000")) + Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) + Expect(uncleModel.Timestamp).To(Equal("111111111")) + + err = db.Get(&uncleModel, `SELECT hash, reward, miner, raw, block_timestamp FROM uncles + WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{3, 2, 1}).Hex()) + Expect(err).ToNot(HaveOccurred()) + Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{3, 2, 1}).Hex())) + Expect(uncleModel.Reward).To(Equal("90000")) + Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) + Expect(uncleModel.Timestamp).To(Equal("111111111")) + }) + It(`replaces blocks and transactions associated to the block when a more new block is in conflict (same block number + nodeid)`, func() { blockOne := core.Block{ - Number: 123, - Hash: "xabc", - Transactions: []core.Transaction{{Hash: "x123"}, {Hash: "x345"}}, + Number: 123, + Hash: "xabc", + Transactions: []core.TransactionModel{ + fakes.GetFakeTransaction("x123", core.Receipt{}), + fakes.GetFakeTransaction("x345", core.Receipt{}), + }, } blockTwo := core.Block{ - Number: 123, - Hash: "xdef", - Transactions: []core.Transaction{{Hash: "x678"}, {Hash: "x9ab"}}, + Number: 123, + Hash: "xdef", + Transactions: []core.TransactionModel{ + fakes.GetFakeTransaction("x678", core.Receipt{}), + fakes.GetFakeTransaction("x9ab", core.Receipt{}), + }, } - blockRepository.CreateOrUpdateBlock(blockOne) - blockRepository.CreateOrUpdateBlock(blockTwo) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(blockOne) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(blockTwo) + Expect(insertErrTwo).NotTo(HaveOccurred()) savedBlock, _ := blockRepository.GetBlock(123) Expect(len(savedBlock.Transactions)).To(Equal(2)) @@ -173,14 +257,21 @@ var _ = Describe("Saving blocks", func() { It(`does not replace blocks when block number is not unique but block number + node id is`, func() { blockOne := core.Block{ - Number: 123, - Transactions: []core.Transaction{{Hash: "x123"}, {Hash: "x345"}}, + Number: 123, + Transactions: []core.TransactionModel{ + fakes.GetFakeTransaction("x123", core.Receipt{}), + fakes.GetFakeTransaction("x345", core.Receipt{}), + }, } blockTwo := core.Block{ - Number: 123, - Transactions: []core.Transaction{{Hash: "x678"}, {Hash: "x9ab"}}, + Number: 123, + Transactions: []core.TransactionModel{ + fakes.GetFakeTransaction("x678", core.Receipt{}), + fakes.GetFakeTransaction("x9ab", core.Receipt{}), + }, } - blockRepository.CreateOrUpdateBlock(blockOne) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(blockOne) + Expect(insertErrOne).NotTo(HaveOccurred()) nodeTwo := core.Node{ GenesisBlock: "0x456", NetworkID: 1, @@ -189,10 +280,14 @@ var _ = Describe("Saving blocks", func() { test_config.CleanTestDB(dbTwo) repositoryTwo := repositories.NewBlockRepository(dbTwo) - blockRepository.CreateOrUpdateBlock(blockOne) - repositoryTwo.CreateOrUpdateBlock(blockTwo) - retrievedBlockOne, _ := blockRepository.GetBlock(123) - retrievedBlockTwo, _ := repositoryTwo.GetBlock(123) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(blockOne) + Expect(insertErrTwo).NotTo(HaveOccurred()) + _, insertErrThree := repositoryTwo.CreateOrUpdateBlock(blockTwo) + Expect(insertErrThree).NotTo(HaveOccurred()) + retrievedBlockOne, getErrOne := blockRepository.GetBlock(123) + Expect(getErrOne).NotTo(HaveOccurred()) + retrievedBlockTwo, getErrTwo := repositoryTwo.GetBlock(123) + Expect(getErrTwo).NotTo(HaveOccurred()) Expect(retrievedBlockOne.Transactions[0].Hash).To(Equal("x123")) Expect(retrievedBlockTwo.Transactions[0].Hash).To(Equal("x678")) @@ -223,46 +318,51 @@ var _ = Describe("Saving blocks", func() { var value = new(big.Int) value.SetString("34940183920000000000", 10) inputData := "0xf7d8c8830000000000000000000000000000000000000000000000000000000000037788000000000000000000000000000000000000000000000000000000000003bd14" - transaction := core.Transaction{ - Hash: "x1234", - GasPrice: gasPrice, - GasLimit: gasLimit, - Nonce: nonce, - To: to, + gethTransaction := types.NewTransaction(nonce, common.HexToAddress(to), value, gasLimit, big.NewInt(gasPrice), common.FromHex(inputData)) + var raw bytes.Buffer + rlpErr := gethTransaction.EncodeRLP(&raw) + Expect(rlpErr).NotTo(HaveOccurred()) + transaction := core.TransactionModel{ + Data: common.Hex2Bytes(inputData), From: from, + GasLimit: gasLimit, + GasPrice: gasPrice, + Hash: "x1234", + Nonce: nonce, + Receipt: core.Receipt{}, + To: to, + TxIndex: 2, Value: value.String(), - Data: inputData, + Raw: []byte{}, } block := core.Block{ Number: 123, - Transactions: []core.Transaction{transaction}, + Transactions: []core.TransactionModel{transaction}, } - blockRepository.CreateOrUpdateBlock(block) + _, insertErr := blockRepository.CreateOrUpdateBlock(block) + Expect(insertErr).NotTo(HaveOccurred()) - savedBlock, _ := blockRepository.GetBlock(123) + savedBlock, err := blockRepository.GetBlock(123) + Expect(err).NotTo(HaveOccurred()) Expect(len(savedBlock.Transactions)).To(Equal(1)) savedTransaction := savedBlock.Transactions[0] - Expect(savedTransaction.Data).To(Equal(transaction.Data)) - Expect(savedTransaction.Hash).To(Equal(transaction.Hash)) - Expect(savedTransaction.To).To(Equal(to)) - Expect(savedTransaction.From).To(Equal(from)) - Expect(savedTransaction.Nonce).To(Equal(nonce)) - Expect(savedTransaction.GasLimit).To(Equal(gasLimit)) - Expect(savedTransaction.GasPrice).To(Equal(gasPrice)) - Expect(savedTransaction.Value).To(Equal(value.String())) + Expect(savedTransaction).To(Equal(transaction)) }) Describe("The missing block numbers", func() { It("is empty the starting block number is the highest known block number", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 1}) + _, insertErr := blockRepository.CreateOrUpdateBlock(core.Block{Number: 1}) + Expect(insertErr).NotTo(HaveOccurred()) Expect(len(blockRepository.MissingBlockNumbers(1, 1, node.ID))).To(Equal(0)) }) It("is empty if copies of block exist from both current node and another", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 0}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 1}) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(core.Block{Number: 0}) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(core.Block{Number: 1}) + Expect(insertErrTwo).NotTo(HaveOccurred()) nodeTwo := core.Node{ GenesisBlock: "0x456", NetworkID: 1, @@ -270,7 +370,8 @@ var _ = Describe("Saving blocks", func() { dbTwo, err := postgres.NewDB(test_config.DBConfig, nodeTwo) Expect(err).NotTo(HaveOccurred()) repositoryTwo := repositories.NewBlockRepository(dbTwo) - repositoryTwo.CreateOrUpdateBlock(core.Block{Number: 0}) + _, insertErrThree := repositoryTwo.CreateOrUpdateBlock(core.Block{Number: 0}) + Expect(insertErrThree).NotTo(HaveOccurred()) missing := blockRepository.MissingBlockNumbers(0, 1, node.ID) @@ -278,42 +379,53 @@ var _ = Describe("Saving blocks", func() { }) It("is the only missing block number", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 2}) + _, insertErr := blockRepository.CreateOrUpdateBlock(core.Block{Number: 2}) + Expect(insertErr).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(1, 2, node.ID)).To(Equal([]int64{1})) }) It("is both missing block numbers", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 3}) + _, insertErr := blockRepository.CreateOrUpdateBlock(core.Block{Number: 3}) + Expect(insertErr).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(1, 3, node.ID)).To(Equal([]int64{1, 2})) }) It("goes back to the starting block number", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + _, insertErr := blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + Expect(insertErr).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(4, 6, node.ID)).To(Equal([]int64{4, 5})) }) It("only includes missing block numbers", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 4}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(core.Block{Number: 4}) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + Expect(insertErrTwo).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(4, 6, node.ID)).To(Equal([]int64{5})) }) It("includes blocks created by a different node", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 4}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(core.Block{Number: 4}) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + Expect(insertErrTwo).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(4, 6, "Different node id")).To(Equal([]int64{4, 5, 6})) }) It("is a list with multiple gaps", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 4}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 5}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 8}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 10}) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(core.Block{Number: 4}) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(core.Block{Number: 5}) + Expect(insertErrTwo).NotTo(HaveOccurred()) + _, insertErrThree := blockRepository.CreateOrUpdateBlock(core.Block{Number: 8}) + Expect(insertErrThree).NotTo(HaveOccurred()) + _, insertErrFour := blockRepository.CreateOrUpdateBlock(core.Block{Number: 10}) + Expect(insertErrFour).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(3, 10, node.ID)).To(Equal([]int64{3, 6, 7, 9})) }) @@ -323,8 +435,10 @@ var _ = Describe("Saving blocks", func() { }) It("only returns requested range even when other gaps exist", func() { - blockRepository.CreateOrUpdateBlock(core.Block{Number: 3}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 8}) + _, insertErrOne := blockRepository.CreateOrUpdateBlock(core.Block{Number: 3}) + Expect(insertErrOne).NotTo(HaveOccurred()) + _, insertErrTwo := blockRepository.CreateOrUpdateBlock(core.Block{Number: 8}) + Expect(insertErrTwo).NotTo(HaveOccurred()) Expect(blockRepository.MissingBlockNumbers(1, 5, node.ID)).To(Equal([]int64{1, 2, 4, 5})) }) @@ -334,11 +448,13 @@ var _ = Describe("Saving blocks", func() { It("sets the status of blocks within n-20 of chain HEAD as final", func() { blockNumberOfChainHead := 25 for i := 0; i < blockNumberOfChainHead; i++ { - blockRepository.CreateOrUpdateBlock(core.Block{Number: int64(i), Hash: strconv.Itoa(i)}) + _, err := blockRepository.CreateOrUpdateBlock(core.Block{Number: int64(i), Hash: strconv.Itoa(i)}) + Expect(err).NotTo(HaveOccurred()) } - blockRepository.SetBlocksStatus(int64(blockNumberOfChainHead)) + setErr := blockRepository.SetBlocksStatus(int64(blockNumberOfChainHead)) + Expect(setErr).NotTo(HaveOccurred()) blockOne, err := blockRepository.GetBlock(1) Expect(err).ToNot(HaveOccurred()) Expect(blockOne.IsFinal).To(Equal(true)) diff --git a/pkg/datastore/postgres/repositories/contract_repository.go b/pkg/datastore/postgres/repositories/contract_repository.go index 0ff0afdd..d198ecae 100644 --- a/pkg/datastore/postgres/repositories/contract_repository.go +++ b/pkg/datastore/postgres/repositories/contract_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -42,19 +42,22 @@ func (contractRepository ContractRepository) CreateContract(contract core.Contra SET contract_hash = $1, contract_abi = $2 `, contract.Hash, abiToInsert) if err != nil { - return postgres.ErrDBInsertFailed + return postgres.ErrDBInsertFailed(err) } return nil } -func (contractRepository ContractRepository) ContractExists(contractHash string) bool { +func (contractRepository ContractRepository) ContractExists(contractHash string) (bool, error) { var exists bool - contractRepository.DB.QueryRow( + err := contractRepository.DB.QueryRow( `SELECT exists( SELECT 1 FROM watched_contracts WHERE contract_hash = $1)`, contractHash).Scan(&exists) - return exists + if err != nil { + return false, err + } + return exists, nil } func (contractRepository ContractRepository) GetContract(contractHash string) (core.Contract, error) { @@ -66,25 +69,31 @@ func (contractRepository ContractRepository) GetContract(contractHash string) (c if err == sql.ErrNoRows { return core.Contract{}, datastore.ErrContractDoesNotExist(contractHash) } - savedContract := contractRepository.addTransactions(core.Contract{Hash: hash, Abi: abi}) + savedContract, err := contractRepository.addTransactions(core.Contract{Hash: hash, Abi: abi}) + if err != nil { + return core.Contract{}, err + } return savedContract, nil } -func (contractRepository ContractRepository) addTransactions(contract core.Contract) core.Contract { - transactionRows, _ := contractRepository.DB.Queryx(` +func (contractRepository ContractRepository) addTransactions(contract core.Contract) (core.Contract, error) { + transactionRows, err := contractRepository.DB.Queryx(` SELECT hash, nonce, tx_to, tx_from, - gaslimit, - gasprice, + gas_limit, + gas_price, value, input_data - FROM transactions + FROM full_sync_transactions WHERE tx_to = $1 ORDER BY block_id DESC`, contract.Hash) + if err != nil { + return core.Contract{}, err + } blockRepository := &BlockRepository{contractRepository.DB} transactions := blockRepository.LoadTransactions(transactionRows) savedContract := core.Contract{Hash: contract.Hash, Transactions: transactions, Abi: contract.Abi} - return savedContract + return savedContract, nil } diff --git a/pkg/datastore/postgres/repositories/contract_repository_test.go b/pkg/datastore/postgres/repositories/contract_repository_test.go index e386cf99..4afdab20 100644 --- a/pkg/datastore/postgres/repositories/contract_repository_test.go +++ b/pkg/datastore/postgres/repositories/contract_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -73,24 +73,26 @@ var _ = Describe("Creating contracts", func() { blockRepository = repositories.NewBlockRepository(db) block := core.Block{ Number: 123, - Transactions: []core.Transaction{ + Transactions: []core.TransactionModel{ {Hash: "TRANSACTION1", To: "x123", Value: "0"}, {Hash: "TRANSACTION2", To: "x345", Value: "0"}, {Hash: "TRANSACTION3", To: "x123", Value: "0"}, }, } - blockRepository.CreateOrUpdateBlock(block) + _, insertBlockErr := blockRepository.CreateOrUpdateBlock(block) + Expect(insertBlockErr).NotTo(HaveOccurred()) - contractRepository.CreateContract(core.Contract{Hash: "x123"}) + insertContractErr := contractRepository.CreateContract(core.Contract{Hash: "x123"}) + Expect(insertContractErr).NotTo(HaveOccurred()) contract, err := contractRepository.GetContract("x123") Expect(err).ToNot(HaveOccurred()) sort.Slice(contract.Transactions, func(i, j int) bool { return contract.Transactions[i].Hash < contract.Transactions[j].Hash }) Expect(contract.Transactions).To( - Equal([]core.Transaction{ - {Hash: "TRANSACTION1", To: "x123", Value: "0"}, - {Hash: "TRANSACTION3", To: "x123", Value: "0"}, + Equal([]core.TransactionModel{ + {Data: []byte{}, Hash: "TRANSACTION1", To: "x123", Value: "0"}, + {Data: []byte{}, Hash: "TRANSACTION3", To: "x123", Value: "0"}, })) }) diff --git a/pkg/datastore/postgres/repositories/header_repository.go b/pkg/datastore/postgres/repositories/header_repository.go index d7813892..fa5ee3de 100644 --- a/pkg/datastore/postgres/repositories/header_repository.go +++ b/pkg/datastore/postgres/repositories/header_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,6 +20,9 @@ import ( "database/sql" "errors" + "github.com/jmoiron/sqlx" + log "github.com/sirupsen/logrus" + "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) @@ -40,6 +43,7 @@ func (repository HeaderRepository) CreateOrUpdateHeader(header core.Header) (int if headerDoesNotExist(err) { return repository.insertHeader(header) } + log.Error("CreateOrUpdateHeader: error getting header hash: ", err) return 0, err } if headerMustBeReplaced(hash, header) { @@ -48,23 +52,81 @@ func (repository HeaderRepository) CreateOrUpdateHeader(header core.Header) (int return 0, ErrValidHeaderExists } +func (repository HeaderRepository) CreateTransactions(headerID int64, transactions []core.TransactionModel) error { + for _, transaction := range transactions { + _, err := repository.database.Exec(`INSERT INTO public.light_sync_transactions + (header_id, hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") + VALUES ($1, $2, $3::NUMERIC, $4::NUMERIC, $5, $6::NUMERIC, $7, $8, $9::NUMERIC, $10, $11::NUMERIC) + ON CONFLICT DO NOTHING`, headerID, transaction.Hash, transaction.GasLimit, transaction.GasPrice, + transaction.Data, transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To, + transaction.Value) + if err != nil { + return err + } + } + return nil +} + +func (repository HeaderRepository) CreateTransactionInTx(tx *sqlx.Tx, headerID int64, transaction core.TransactionModel) (int64, error) { + var txId int64 + err := tx.QueryRowx(`INSERT INTO public.light_sync_transactions + (header_id, hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") + VALUES ($1, $2, $3::NUMERIC, $4::NUMERIC, $5, $6::NUMERIC, $7, $8, $9::NUMERIC, $10, $11::NUMERIC) + ON CONFLICT (header_id, hash) DO UPDATE + SET (gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") = ($3::NUMERIC, $4::NUMERIC, $5, $6::NUMERIC, $7, $8, $9::NUMERIC, $10, $11::NUMERIC) + RETURNING id`, + headerID, transaction.Hash, transaction.GasLimit, transaction.GasPrice, + transaction.Data, transaction.Nonce, transaction.Raw, transaction.From, + transaction.TxIndex, transaction.To, transaction.Value).Scan(&txId) + if err != nil { + log.Error("header_repository: error inserting transaction: ", err) + return txId, err + } + return txId, err +} + +func (repository HeaderRepository) CreateReceiptInTx(tx *sqlx.Tx, headerID, transactionID int64, receipt core.Receipt) (int64, error) { + var receiptId int64 + err := tx.QueryRowx(`INSERT INTO public.light_sync_receipts + (header_id, transaction_id, contract_address, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) + ON CONFLICT (header_id, transaction_id) DO UPDATE + SET (contract_address, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp) = ($3, $4::NUMERIC, $5::NUMERIC, $6, $7, $8, $9) + RETURNING id`, + headerID, transactionID, receipt.ContractAddress, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, receipt.TxHash, receipt.Rlp).Scan(&receiptId) + if err != nil { + log.Error("header_repository: error inserting receipt: ", err) + return receiptId, err + } + return receiptId, err +} + func (repository HeaderRepository) GetHeader(blockNumber int64) (core.Header, error) { var header core.Header - err := repository.database.Get(&header, `SELECT block_number, hash, raw FROM headers WHERE block_number = $1 AND eth_node_fingerprint = $2`, + err := repository.database.Get(&header, `SELECT id, block_number, hash, raw, block_timestamp FROM headers WHERE block_number = $1 AND eth_node_fingerprint = $2`, blockNumber, repository.database.Node.ID) + if err != nil { + log.Error("GetHeader: error getting headers: ", err) + } return header, err } -func (repository HeaderRepository) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) []int64 { +func (repository HeaderRepository) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) ([]int64, error) { numbers := make([]int64, 0) - repository.database.Select(&numbers, `SELECT all_block_numbers - FROM ( - SELECT generate_series($1::INT, $2::INT) AS all_block_numbers) series - WHERE all_block_numbers NOT IN ( - SELECT block_number FROM headers WHERE eth_node_fingerprint = $3 - ) `, + err := repository.database.Select(&numbers, + `SELECT series.block_number + FROM (SELECT generate_series($1::INT, $2::INT) AS block_number) AS series + LEFT OUTER JOIN (SELECT block_number FROM headers + WHERE eth_node_fingerprint = $3) AS synced + USING (block_number) + WHERE synced.block_number IS NULL`, startingBlockNumber, endingBlockNumber, nodeID) - return numbers + if err != nil { + log.Errorf("MissingBlockNumbers failed to get blocks between %v - %v for node %v", + startingBlockNumber, endingBlockNumber, nodeID) + return []int64{}, err + } + return numbers, nil } func headerMustBeReplaced(hash string, header core.Header) bool { @@ -87,6 +149,9 @@ func (repository HeaderRepository) insertHeader(header core.Header) (int64, erro err := repository.database.QueryRowx( `INSERT INTO public.headers (block_number, hash, block_timestamp, raw, eth_node_id, eth_node_fingerprint) VALUES ($1, $2, $3::NUMERIC, $4, $5, $6) RETURNING id`, header.BlockNumber, header.Hash, header.Timestamp, header.Raw, repository.database.NodeID, repository.database.Node.ID).Scan(&headerId) + if err != nil { + log.Error("insertHeader: error inserting header: ", err) + } return headerId, err } @@ -94,6 +159,7 @@ func (repository HeaderRepository) replaceHeader(header core.Header) (int64, err _, err := repository.database.Exec(`DELETE FROM headers WHERE block_number = $1 AND eth_node_fingerprint = $2`, header.BlockNumber, repository.database.Node.ID) if err != nil { + log.Error("replaceHeader: error deleting headers: ", err) return 0, err } return repository.insertHeader(header) diff --git a/pkg/datastore/postgres/repositories/header_repository_test.go b/pkg/datastore/postgres/repositories/header_repository_test.go index dca34a08..c165600a 100644 --- a/pkg/datastore/postgres/repositories/header_repository_test.go +++ b/pkg/datastore/postgres/repositories/header_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -19,15 +19,17 @@ package repositories_test import ( "database/sql" "encoding/json" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/test_config" - "math/big" ) var _ = Describe("Block header repository", func() { @@ -35,29 +37,30 @@ var _ = Describe("Block header repository", func() { rawHeader []byte err error timestamp string + db *postgres.DB + repo repositories.HeaderRepository + header core.Header ) BeforeEach(func() { rawHeader, err = json.Marshal(types.Header{}) Expect(err).NotTo(HaveOccurred()) timestamp = big.NewInt(123456789).String() + + db = test_config.NewTestDB(test_config.NewTestNode()) + test_config.CleanTestDB(db) + repo = repositories.NewHeaderRepository(db) + header = core.Header{ + BlockNumber: 100, + Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), + Raw: rawHeader, + Timestamp: timestamp, + } }) Describe("creating or updating a header", func() { It("adds a header", func() { - node := core.Node{} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - - _, err := repo.CreateOrUpdateHeader(header) - + _, err = repo.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) var dbHeader core.Header err = db.Get(&dbHeader, `SELECT block_number, hash, raw, block_timestamp FROM public.headers WHERE block_number = $1`, header.BlockNumber) @@ -69,18 +72,7 @@ var _ = Describe("Block header repository", func() { }) It("adds node data to header", func() { - node := core.Node{ID: "EthNodeFingerprint"} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Raw: rawHeader, - Timestamp: timestamp, - } - - _, err := repo.CreateOrUpdateHeader(header) - + _, err = repo.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) var ethNodeId int64 err = db.Get(ðNodeId, `SELECT eth_node_id FROM public.headers WHERE block_number = $1`, header.BlockNumber) @@ -93,18 +85,7 @@ var _ = Describe("Block header repository", func() { }) It("returns valid header exists error if attempting duplicate headers", func() { - node := core.Node{} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - - _, err := repo.CreateOrUpdateHeader(header) + _, err = repo.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) _, err = repo.CreateOrUpdateHeader(header) @@ -118,18 +99,9 @@ var _ = Describe("Block header repository", func() { }) It("replaces header if hash is different", func() { - node := core.Node{} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - _, err := repo.CreateOrUpdateHeader(header) + _, err = repo.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) + headerTwo := core.Header{ BlockNumber: header.BlockNumber, Hash: common.BytesToHash([]byte{5, 4, 3, 2, 1}).Hex(), @@ -148,20 +120,12 @@ var _ = Describe("Block header repository", func() { }) It("does not replace header if node fingerprint is different", func() { - node := core.Node{ID: "Fingerprint"} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - _, err := repo.CreateOrUpdateHeader(header) + _, err = repo.CreateOrUpdateHeader(header) + Expect(err).NotTo(HaveOccurred()) nodeTwo := core.Node{ID: "FingerprintTwo"} dbTwo, err := postgres.NewDB(test_config.DBConfig, nodeTwo) Expect(err).NotTo(HaveOccurred()) + repoTwo := repositories.NewHeaderRepository(dbTwo) headerTwo := core.Header{ BlockNumber: header.BlockNumber, @@ -180,19 +144,13 @@ var _ = Describe("Block header repository", func() { }) It("only replaces header with matching node fingerprint", func() { - node := core.Node{ID: "Fingerprint"} - db := test_config.NewTestDB(node) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - _, err := repo.CreateOrUpdateHeader(header) + _, err = repo.CreateOrUpdateHeader(header) + Expect(err).NotTo(HaveOccurred()) + nodeTwo := core.Node{ID: "FingerprintTwo"} dbTwo, err := postgres.NewDB(test_config.DBConfig, nodeTwo) Expect(err).NotTo(HaveOccurred()) + repoTwo := repositories.NewHeaderRepository(dbTwo) headerTwo := core.Header{ BlockNumber: header.BlockNumber, @@ -222,43 +180,233 @@ var _ = Describe("Block header repository", func() { }) }) + Describe("creating a receipt", func() { + It("adds a receipt in a tx", func() { + headerID, err := repo.CreateOrUpdateHeader(header) + Expect(err).NotTo(HaveOccurred()) + fromAddress := common.HexToAddress("0x1234") + toAddress := common.HexToAddress("0x5678") + txHash := common.HexToHash("0x9876") + txIndex := big.NewInt(123) + transaction := core.TransactionModel{ + Data: []byte{}, + From: fromAddress.Hex(), + GasLimit: 0, + GasPrice: 0, + Hash: txHash.Hex(), + Nonce: 0, + Raw: []byte{}, + To: toAddress.Hex(), + TxIndex: txIndex.Int64(), + Value: "0", + } + tx, err := db.Beginx() + Expect(err).ToNot(HaveOccurred()) + txId, txErr := repo.CreateTransactionInTx(tx, headerID, transaction) + Expect(txErr).ToNot(HaveOccurred()) + + contractAddr := common.HexToAddress("0x1234") + stateRoot := common.HexToHash("0x5678") + receipt := core.Receipt{ + ContractAddress: contractAddr.Hex(), + TxHash: txHash.Hex(), + GasUsed: 10, + CumulativeGasUsed: 100, + StateRoot: stateRoot.Hex(), + Rlp: []byte{1, 2, 3}, + } + + _, receiptErr := repo.CreateReceiptInTx(tx, headerID, txId, receipt) + commitErr := tx.Commit() + Expect(commitErr).ToNot(HaveOccurred()) + Expect(receiptErr).ToNot(HaveOccurred()) + + type idModel struct { + TransactionId int64 `db:"transaction_id"` + core.Receipt + } + var dbReceipt idModel + err = db.Get(&dbReceipt, + `SELECT transaction_id, contract_address, cumulative_gas_used, gas_used, state_root, status, tx_hash, rlp + FROM public.light_sync_receipts WHERE header_id = $1`, headerID) + Expect(err).NotTo(HaveOccurred()) + Expect(dbReceipt.TransactionId).To(Equal(txId)) + Expect(dbReceipt.TxHash).To(Equal(txHash.Hex())) + Expect(dbReceipt.ContractAddress).To(Equal(contractAddr.Hex())) + Expect(dbReceipt.CumulativeGasUsed).To(Equal(uint64(100))) + Expect(dbReceipt.GasUsed).To(Equal(uint64(10))) + Expect(dbReceipt.StateRoot).To(Equal(stateRoot.Hex())) + Expect(dbReceipt.Rlp).To(Equal([]byte{1, 2, 3})) + }) + }) + + Describe("creating a transaction", func() { + var ( + headerID int64 + transactions []core.TransactionModel + ) + + BeforeEach(func() { + var err error + headerID, err = repo.CreateOrUpdateHeader(header) + Expect(err).NotTo(HaveOccurred()) + fromAddress := common.HexToAddress("0x1234") + toAddress := common.HexToAddress("0x5678") + txHash := common.HexToHash("0x9876") + txHashTwo := common.HexToHash("0x5432") + txIndex := big.NewInt(123) + transactions = []core.TransactionModel{{ + Data: []byte{}, + From: fromAddress.Hex(), + GasLimit: 0, + GasPrice: 0, + Hash: txHash.Hex(), + Nonce: 0, + Raw: []byte{}, + To: toAddress.Hex(), + TxIndex: txIndex.Int64(), + Value: "0", + Receipt: core.Receipt{}, + }, { + Data: []byte{}, + From: fromAddress.Hex(), + GasLimit: 1, + GasPrice: 1, + Hash: txHashTwo.Hex(), + Nonce: 1, + Raw: []byte{}, + To: toAddress.Hex(), + TxIndex: 1, + Value: "1", + }} + + insertErr := repo.CreateTransactions(headerID, transactions) + Expect(insertErr).NotTo(HaveOccurred()) + }) + + It("adds transactions", func() { + var dbTransactions []core.TransactionModel + err = db.Select(&dbTransactions, + `SELECT hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" + FROM public.light_sync_transactions WHERE header_id = $1`, headerID) + Expect(err).NotTo(HaveOccurred()) + Expect(dbTransactions).To(ConsistOf(transactions)) + }) + + It("silently ignores duplicate inserts", func() { + insertTwoErr := repo.CreateTransactions(headerID, transactions) + Expect(insertTwoErr).NotTo(HaveOccurred()) + + var dbTransactions []core.TransactionModel + err = db.Select(&dbTransactions, + `SELECT hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" + FROM public.light_sync_transactions WHERE header_id = $1`, headerID) + Expect(err).NotTo(HaveOccurred()) + Expect(len(dbTransactions)).To(Equal(2)) + }) + }) + + Describe("creating a transaction in a sqlx tx", func() { + It("adds a transaction", func() { + headerID, err := repo.CreateOrUpdateHeader(header) + Expect(err).NotTo(HaveOccurred()) + fromAddress := common.HexToAddress("0x1234") + toAddress := common.HexToAddress("0x5678") + txHash := common.HexToHash("0x9876") + txIndex := big.NewInt(123) + transaction := core.TransactionModel{ + Data: []byte{}, + From: fromAddress.Hex(), + GasLimit: 0, + GasPrice: 0, + Hash: txHash.Hex(), + Nonce: 0, + Raw: []byte{1, 2, 3}, + To: toAddress.Hex(), + TxIndex: txIndex.Int64(), + Value: "0", + } + + tx, err := db.Beginx() + Expect(err).ToNot(HaveOccurred()) + _, insertErr := repo.CreateTransactionInTx(tx, headerID, transaction) + commitErr := tx.Commit() + Expect(commitErr).ToNot(HaveOccurred()) + Expect(insertErr).NotTo(HaveOccurred()) + + var dbTransaction core.TransactionModel + err = db.Get(&dbTransaction, + `SELECT hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" + FROM public.light_sync_transactions WHERE header_id = $1`, headerID) + Expect(err).NotTo(HaveOccurred()) + Expect(dbTransaction).To(Equal(transaction)) + }) + + It("silently upserts", func() { + headerID, err := repo.CreateOrUpdateHeader(header) + Expect(err).NotTo(HaveOccurred()) + fromAddress := common.HexToAddress("0x1234") + toAddress := common.HexToAddress("0x5678") + txHash := common.HexToHash("0x9876") + txIndex := big.NewInt(123) + transaction := core.TransactionModel{ + Data: []byte{}, + From: fromAddress.Hex(), + GasLimit: 0, + GasPrice: 0, + Hash: txHash.Hex(), + Nonce: 0, + Raw: []byte{}, + Receipt: core.Receipt{}, + To: toAddress.Hex(), + TxIndex: txIndex.Int64(), + Value: "0", + } + + tx1, err := db.Beginx() + Expect(err).ToNot(HaveOccurred()) + txId1, insertErr := repo.CreateTransactionInTx(tx1, headerID, transaction) + commit1Err := tx1.Commit() + Expect(commit1Err).ToNot(HaveOccurred()) + Expect(insertErr).NotTo(HaveOccurred()) + + tx2, err := db.Beginx() + Expect(err).ToNot(HaveOccurred()) + txId2, insertErr := repo.CreateTransactionInTx(tx2, headerID, transaction) + commit2Err := tx2.Commit() + Expect(commit2Err).ToNot(HaveOccurred()) + Expect(insertErr).NotTo(HaveOccurred()) + Expect(txId1).To(Equal(txId2)) + + var dbTransactions []core.TransactionModel + err = db.Select(&dbTransactions, + `SELECT hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" + FROM public.light_sync_transactions WHERE header_id = $1`, headerID) + Expect(err).NotTo(HaveOccurred()) + Expect(len(dbTransactions)).To(Equal(1)) + }) + }) + Describe("Getting a header", func() { It("returns header if it exists", func() { - node := core.Node{} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash([]byte{1, 2, 3, 4, 5}).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - _, err := repo.CreateOrUpdateHeader(header) + _, err = repo.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) dbHeader, err := repo.GetHeader(header.BlockNumber) Expect(err).NotTo(HaveOccurred()) + Expect(dbHeader.Id).NotTo(BeZero()) Expect(dbHeader.BlockNumber).To(Equal(header.BlockNumber)) Expect(dbHeader.Hash).To(Equal(header.Hash)) Expect(dbHeader.Raw).To(MatchJSON(header.Raw)) + Expect(dbHeader.Timestamp).To(Equal(header.Timestamp)) }) It("does not return header for a different node fingerprint", func() { - node := core.Node{} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - header := core.Header{ - BlockNumber: 100, - Hash: common.BytesToHash(rawHeader).Hex(), - Raw: rawHeader, - Timestamp: timestamp, - } - _, err := repo.CreateOrUpdateHeader(header) + _, err = repo.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) - nodeTwo := core.Node{ID: "NodeFingerprintTwo"} + + nodeTwo := core.Node{ID: "FingerprintTwo"} dbTwo, err := postgres.NewDB(test_config.DBConfig, nodeTwo) Expect(err).NotTo(HaveOccurred()) repoTwo := repositories.NewHeaderRepository(dbTwo) @@ -272,57 +420,62 @@ var _ = Describe("Block header repository", func() { Describe("Getting missing headers", func() { It("returns block numbers for headers not in the database", func() { - node := core.Node{} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - repo.CreateOrUpdateHeader(core.Header{ + _, err = repo.CreateOrUpdateHeader(core.Header{ BlockNumber: 1, Raw: rawHeader, Timestamp: timestamp, }) - repo.CreateOrUpdateHeader(core.Header{ + Expect(err).NotTo(HaveOccurred()) + + _, err = repo.CreateOrUpdateHeader(core.Header{ BlockNumber: 3, Raw: rawHeader, Timestamp: timestamp, }) - repo.CreateOrUpdateHeader(core.Header{ + Expect(err).NotTo(HaveOccurred()) + + _, err = repo.CreateOrUpdateHeader(core.Header{ BlockNumber: 5, Raw: rawHeader, Timestamp: timestamp, }) + Expect(err).NotTo(HaveOccurred()) - missingBlockNumbers := repo.MissingBlockNumbers(1, 5, node.ID) + missingBlockNumbers, err := repo.MissingBlockNumbers(1, 5, db.Node.ID) + Expect(err).NotTo(HaveOccurred()) Expect(missingBlockNumbers).To(ConsistOf([]int64{2, 4})) }) It("does not count headers created by a different node fingerprint", func() { - node := core.Node{ID: "NodeFingerprint"} - db := test_config.NewTestDB(node) - test_config.CleanTestDB(db) - repo := repositories.NewHeaderRepository(db) - repo.CreateOrUpdateHeader(core.Header{ + _, err = repo.CreateOrUpdateHeader(core.Header{ BlockNumber: 1, Raw: rawHeader, Timestamp: timestamp, }) - repo.CreateOrUpdateHeader(core.Header{ + Expect(err).NotTo(HaveOccurred()) + + _, err = repo.CreateOrUpdateHeader(core.Header{ BlockNumber: 3, Raw: rawHeader, Timestamp: timestamp, }) - repo.CreateOrUpdateHeader(core.Header{ + Expect(err).NotTo(HaveOccurred()) + + _, err = repo.CreateOrUpdateHeader(core.Header{ BlockNumber: 5, Raw: rawHeader, Timestamp: timestamp, }) - nodeTwo := core.Node{ID: "NodeFingerprintTwo"} + Expect(err).NotTo(HaveOccurred()) + + nodeTwo := core.Node{ID: "FingerprintTwo"} dbTwo, err := postgres.NewDB(test_config.DBConfig, nodeTwo) Expect(err).NotTo(HaveOccurred()) repoTwo := repositories.NewHeaderRepository(dbTwo) - missingBlockNumbers := repoTwo.MissingBlockNumbers(1, 5, nodeTwo.ID) + missingBlockNumbers, err := repoTwo.MissingBlockNumbers(1, 5, nodeTwo.ID) + Expect(err).NotTo(HaveOccurred()) Expect(missingBlockNumbers).To(ConsistOf([]int64{1, 2, 3, 4, 5})) }) diff --git a/pkg/datastore/postgres/repositories/log_filter_repository.go b/pkg/datastore/postgres/repositories/log_filter_repository.go index faad7ca8..705f721e 100644 --- a/pkg/datastore/postgres/repositories/log_filter_repository.go +++ b/pkg/datastore/postgres/repositories/log_filter_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/postgres/repositories/log_filter_repository_test.go b/pkg/datastore/postgres/repositories/log_filter_repository_test.go index 5426868d..69f9b8e2 100644 --- a/pkg/datastore/postgres/repositories/log_filter_repository_test.go +++ b/pkg/datastore/postgres/repositories/log_filter_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/postgres/repositories/logs_repository.go b/pkg/datastore/postgres/repositories/logs_repository.go index 4886e15f..4c13e723 100644 --- a/pkg/datastore/postgres/repositories/logs_repository.go +++ b/pkg/datastore/postgres/repositories/logs_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,7 +17,7 @@ package repositories import ( - "context" + "github.com/sirupsen/logrus" "database/sql" @@ -30,25 +30,35 @@ type LogRepository struct { } func (logRepository LogRepository) CreateLogs(lgs []core.Log, receiptId int64) error { - tx, _ := logRepository.DB.BeginTx(context.Background(), nil) + tx, _ := logRepository.DB.Beginx() for _, tlog := range lgs { - _, err := tx.Exec( + _, insertLogErr := tx.Exec( `INSERT INTO logs (block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data, receipt_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) `, tlog.BlockNumber, tlog.Address, tlog.TxHash, tlog.Index, tlog.Topics[0], tlog.Topics[1], tlog.Topics[2], tlog.Topics[3], tlog.Data, receiptId, ) - if err != nil { - tx.Rollback() - return postgres.ErrDBInsertFailed + if insertLogErr != nil { + rollbackErr := tx.Rollback() + if rollbackErr != nil { + logrus.Error("CreateLogs: could not perform rollback: ", rollbackErr) + } + return postgres.ErrDBInsertFailed(insertLogErr) } } - tx.Commit() + err := tx.Commit() + if err != nil { + err = tx.Rollback() + if err != nil { + logrus.Error("CreateLogs: could not perform rollback: ", err) + } + return postgres.ErrDBInsertFailed(err) + } return nil } -func (logRepository LogRepository) GetLogs(address string, blockNumber int64) []core.Log { - logRows, _ := logRepository.DB.Query( +func (logRepository LogRepository) GetLogs(address string, blockNumber int64) ([]core.Log, error) { + logRows, err := logRepository.DB.Query( `SELECT block_number, address, tx_hash, @@ -61,10 +71,13 @@ func (logRepository LogRepository) GetLogs(address string, blockNumber int64) [] FROM logs WHERE address = $1 AND block_number = $2 ORDER BY block_number DESC`, address, blockNumber) + if err != nil { + return []core.Log{}, err + } return logRepository.loadLogs(logRows) } -func (logRepository LogRepository) loadLogs(logsRows *sql.Rows) []core.Log { +func (logRepository LogRepository) loadLogs(logsRows *sql.Rows) ([]core.Log, error) { var lgs []core.Log for logsRows.Next() { var blockNumber int64 @@ -73,7 +86,11 @@ func (logRepository LogRepository) loadLogs(logsRows *sql.Rows) []core.Log { var index int64 var data string var topics core.Topics - logsRows.Scan(&blockNumber, &address, &txHash, &index, &topics[0], &topics[1], &topics[2], &topics[3], &data) + err := logsRows.Scan(&blockNumber, &address, &txHash, &index, &topics[0], &topics[1], &topics[2], &topics[3], &data) + if err != nil { + logrus.Error("loadLogs: Error scanning a row in logRows: ", err) + return []core.Log{}, err + } lg := core.Log{ BlockNumber: blockNumber, TxHash: txHash, @@ -86,5 +103,5 @@ func (logRepository LogRepository) loadLogs(logsRows *sql.Rows) []core.Log { } lgs = append(lgs, lg) } - return lgs + return lgs, nil } diff --git a/pkg/datastore/postgres/repositories/logs_repository_test.go b/pkg/datastore/postgres/repositories/logs_repository_test.go index 1f88cc6c..fe5d069d 100644 --- a/pkg/datastore/postgres/repositories/logs_repository_test.go +++ b/pkg/datastore/postgres/repositories/logs_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package repositories_test import ( + "github.com/vulcanize/vulcanizedb/pkg/fakes" "sort" . "github.com/onsi/ginkgo" @@ -56,7 +57,7 @@ var _ = Describe("Logs Repository", func() { Expect(err).NotTo(HaveOccurred()) receiptId, err := receiptRepository.CreateReceipt(blockId, core.Receipt{}) Expect(err).NotTo(HaveOccurred()) - logsRepository.CreateLogs([]core.Log{{ + err = logsRepository.CreateLogs([]core.Log{{ BlockNumber: blockNumber, Index: 0, Address: "x123", @@ -64,9 +65,11 @@ var _ = Describe("Logs Repository", func() { Topics: core.Topics{0: "x777", 1: "x888", 2: "x999"}, Data: "xabc", }}, receiptId) + Expect(err).NotTo(HaveOccurred()) - log := logsRepository.GetLogs("x123", blockNumber) + log, err := logsRepository.GetLogs("x123", blockNumber) + Expect(err).NotTo(HaveOccurred()) Expect(log).NotTo(BeNil()) Expect(log[0].BlockNumber).To(Equal(blockNumber)) Expect(log[0].Address).To(Equal("x123")) @@ -79,7 +82,8 @@ var _ = Describe("Logs Repository", func() { }) It("returns nil if log does not exist", func() { - log := logsRepository.GetLogs("x123", 1) + log, err := logsRepository.GetLogs("x123", 1) + Expect(err).NotTo(HaveOccurred()) Expect(log).To(BeNil()) }) @@ -89,7 +93,8 @@ var _ = Describe("Logs Repository", func() { Expect(err).NotTo(HaveOccurred()) receiptId, err := receiptRepository.CreateReceipt(blockId, core.Receipt{}) Expect(err).NotTo(HaveOccurred()) - logsRepository.CreateLogs([]core.Log{{ + + err = logsRepository.CreateLogs([]core.Log{{ BlockNumber: blockNumber, Index: 0, Address: "x123", @@ -97,7 +102,9 @@ var _ = Describe("Logs Repository", func() { Topics: core.Topics{0: "x777", 1: "x888", 2: "x999"}, Data: "xabc", }}, receiptId) - logsRepository.CreateLogs([]core.Log{{ + Expect(err).NotTo(HaveOccurred()) + + err = logsRepository.CreateLogs([]core.Log{{ BlockNumber: blockNumber, Index: 1, Address: "x123", @@ -105,7 +112,9 @@ var _ = Describe("Logs Repository", func() { Topics: core.Topics{0: "x111", 1: "x222", 2: "x333"}, Data: "xdef", }}, receiptId) - logsRepository.CreateLogs([]core.Log{{ + Expect(err).NotTo(HaveOccurred()) + + err = logsRepository.CreateLogs([]core.Log{{ BlockNumber: 2, Index: 0, Address: "x123", @@ -113,13 +122,16 @@ var _ = Describe("Logs Repository", func() { Topics: core.Topics{0: "x777", 1: "x888", 2: "x999"}, Data: "xabc", }}, receiptId) + Expect(err).NotTo(HaveOccurred()) - log := logsRepository.GetLogs("x123", blockNumber) + log, err := logsRepository.GetLogs("x123", blockNumber) + Expect(err).NotTo(HaveOccurred()) type logIndex struct { blockNumber int64 Index int64 } + var uniqueBlockNumbers []logIndex for _, log := range log { uniqueBlockNumbers = append(uniqueBlockNumbers, @@ -190,17 +202,14 @@ var _ = Describe("Logs Repository", func() { Status: 1, TxHash: "0x002c4799161d809b23f67884eb6598c9df5894929fe1a9ead97ca175d360f547", } - transaction := - core.Transaction{ - Hash: receipt.TxHash, - Receipt: receipt, - } + transaction := fakes.GetFakeTransaction(receipt.TxHash, receipt) - block := core.Block{Transactions: []core.Transaction{transaction}} + block := core.Block{Transactions: []core.TransactionModel{transaction}} _, err := blockRepository.CreateOrUpdateBlock(block) Expect(err).To(Not(HaveOccurred())) - retrievedLogs := logsRepository.GetLogs("0x99041f808d598b782d5a3e498681c2452a31da08", 4745407) + retrievedLogs, err := logsRepository.GetLogs("0x99041f808d598b782d5a3e498681c2452a31da08", 4745407) + Expect(err).NotTo(HaveOccurred()) expected := logs[1:] Expect(retrievedLogs).To(Equal(expected)) }) diff --git a/pkg/datastore/postgres/repositories/receipt_repository.go b/pkg/datastore/postgres/repositories/receipt_repository.go index 9981559c..01e38f09 100644 --- a/pkg/datastore/postgres/repositories/receipt_repository.go +++ b/pkg/datastore/postgres/repositories/receipt_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,9 @@ package repositories import ( - "context" "database/sql" + "github.com/jmoiron/sqlx" + "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" @@ -30,7 +31,7 @@ type ReceiptRepository struct { } func (receiptRepository ReceiptRepository) CreateReceiptsAndLogs(blockId int64, receipts []core.Receipt) error { - tx, err := receiptRepository.DB.BeginTx(context.Background(), nil) + tx, err := receiptRepository.DB.Beginx() if err != nil { return err } @@ -52,19 +53,22 @@ func (receiptRepository ReceiptRepository) CreateReceiptsAndLogs(blockId int64, return nil } -func createReceipt(receipt core.Receipt, blockId int64, tx *sql.Tx) (int64, error) { +func createReceipt(receipt core.Receipt, blockId int64, tx *sqlx.Tx) (int64, error) { var receiptId int64 err := tx.QueryRow( - `INSERT INTO receipts + `INSERT INTO full_sync_receipts (contract_address, tx_hash, cumulative_gas_used, gas_used, state_root, status, block_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id`, receipt.ContractAddress, receipt.TxHash, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, blockId, ).Scan(&receiptId) + if err != nil { + logrus.Error("createReceipt: Error inserting: ", err) + } return receiptId, err } -func createLogs(logs []core.Log, receiptId int64, tx *sql.Tx) error { +func createLogs(logs []core.Log, receiptId int64, tx *sqlx.Tx) error { for _, log := range logs { _, err := tx.Exec( `INSERT INTO logs (block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data, receipt_id) @@ -80,16 +84,17 @@ func createLogs(logs []core.Log, receiptId int64, tx *sql.Tx) error { } func (receiptRepository ReceiptRepository) CreateReceipt(blockId int64, receipt core.Receipt) (int64, error) { - tx, _ := receiptRepository.DB.BeginTx(context.Background(), nil) + tx, _ := receiptRepository.DB.Beginx() var receiptId int64 err := tx.QueryRow( - `INSERT INTO receipts + `INSERT INTO full_sync_receipts (contract_address, tx_hash, cumulative_gas_used, gas_used, state_root, status, block_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id`, receipt.ContractAddress, receipt.TxHash, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, blockId).Scan(&receiptId) if err != nil { tx.Rollback() + logrus.Warning("CreateReceipt: error inserting receipt: ", err) return receiptId, err } tx.Commit() @@ -104,7 +109,7 @@ func (receiptRepository ReceiptRepository) GetReceipt(txHash string) (core.Recei gas_used, state_root, status - FROM receipts + FROM full_sync_receipts WHERE tx_hash = $1`, txHash) receipt, err := loadReceipt(row) if err != nil { diff --git a/pkg/datastore/postgres/repositories/receipts_repository_test.go b/pkg/datastore/postgres/repositories/receipt_repository_test.go similarity index 89% rename from pkg/datastore/postgres/repositories/receipts_repository_test.go rename to pkg/datastore/postgres/repositories/receipt_repository_test.go index 4ba64db4..76d1516b 100644 --- a/pkg/datastore/postgres/repositories/receipts_repository_test.go +++ b/pkg/datastore/postgres/repositories/receipt_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,10 +23,11 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/datastore" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/test_config" ) -var _ = Describe("Receipts Repository", func() { +var _ = Describe("Receipt Repository", func() { var blockRepository datastore.BlockRepository var logRepository datastore.LogRepository var receiptRepository datastore.ReceiptRepository @@ -87,14 +88,19 @@ var _ = Describe("Receipts Repository", func() { Expect(err).NotTo(HaveOccurred()) Expect(persistedReceiptOne).NotTo(BeNil()) Expect(persistedReceiptOne.TxHash).To(Equal(txHashOne)) + persistedReceiptTwo, err := receiptRepository.GetReceipt(txHashTwo) Expect(err).NotTo(HaveOccurred()) Expect(persistedReceiptTwo).NotTo(BeNil()) Expect(persistedReceiptTwo.TxHash).To(Equal(txHashTwo)) - persistedAddressOneLogs := logRepository.GetLogs(addressOne, blockNumber) + + persistedAddressOneLogs, err := logRepository.GetLogs(addressOne, blockNumber) + Expect(err).NotTo(HaveOccurred()) Expect(persistedAddressOneLogs).NotTo(BeNil()) Expect(len(persistedAddressOneLogs)).To(Equal(2)) - persistedAddressTwoLogs := logRepository.GetLogs(addressTwo, blockNumber) + + persistedAddressTwoLogs, err := logRepository.GetLogs(addressTwo, blockNumber) + Expect(err).NotTo(HaveOccurred()) Expect(persistedAddressTwoLogs).NotTo(BeNil()) Expect(len(persistedAddressTwoLogs)).To(Equal(1)) }) @@ -112,11 +118,8 @@ var _ = Describe("Receipts Repository", func() { TxHash: "0xe340558980f89d5f86045ac11e5cc34e4bcec20f9f1e2a427aa39d87114e8223", } - transaction := core.Transaction{ - Hash: expected.TxHash, - Receipt: expected, - } - block := core.Block{Transactions: []core.Transaction{transaction}} + transaction := fakes.GetFakeTransaction(expected.TxHash, expected) + block := core.Block{Transactions: []core.TransactionModel{transaction}} _, err := blockRepository.CreateOrUpdateBlock(block) @@ -142,13 +145,10 @@ var _ = Describe("Receipts Repository", func() { receipt := core.Receipt{ TxHash: "0x002c4799161d809b23f67884eb6598c9df5894929fe1a9ead97ca175d360f547", } - transaction := core.Transaction{ - Hash: receipt.TxHash, - Receipt: receipt, - } + transaction := fakes.GetFakeTransaction(receipt.TxHash, receipt) block := core.Block{ - Transactions: []core.Transaction{transaction}, + Transactions: []core.TransactionModel{transaction}, } _, err := blockRepository.CreateOrUpdateBlock(block) diff --git a/pkg/datastore/postgres/repositories/repositories_suite_test.go b/pkg/datastore/postgres/repositories/repositories_suite_test.go index bf45707e..c34a23b0 100644 --- a/pkg/datastore/postgres/repositories/repositories_suite_test.go +++ b/pkg/datastore/postgres/repositories/repositories_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,8 @@ package repositories_test import ( + "github.com/sirupsen/logrus" + "io/ioutil" "testing" . "github.com/onsi/ginkgo" @@ -27,3 +29,7 @@ func TestRepositories(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Repositories Suite") } + +var _ = BeforeSuite(func() { + logrus.SetOutput(ioutil.Discard) +}) diff --git a/pkg/datastore/postgres/repositories/watched_events_repository.go b/pkg/datastore/postgres/repositories/watched_events_repository.go index b5931666..7cda002b 100644 --- a/pkg/datastore/postgres/repositories/watched_events_repository.go +++ b/pkg/datastore/postgres/repositories/watched_events_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package repositories import ( + "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) @@ -28,6 +29,7 @@ type WatchedEventRepository struct { func (watchedEventRepository WatchedEventRepository) GetWatchedEvents(name string) ([]*core.WatchedEvent, error) { rows, err := watchedEventRepository.DB.Queryx(`SELECT id, name, block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data FROM watched_event_logs where name=$1`, name) if err != nil { + logrus.Error("GetWatchedEvents: error getting watched events: ", err) return nil, err } defer rows.Close() @@ -37,11 +39,13 @@ func (watchedEventRepository WatchedEventRepository) GetWatchedEvents(name strin lg := new(core.WatchedEvent) err = rows.StructScan(lg) if err != nil { + logrus.Warn("GetWatchedEvents: error scanning log: ", err) return nil, err } lgs = append(lgs, lg) } if err = rows.Err(); err != nil { + logrus.Warn("GetWatchedEvents: error scanning logs: ", err) return nil, err } return lgs, nil diff --git a/pkg/datastore/postgres/repositories/watched_events_repository_test.go b/pkg/datastore/postgres/repositories/watched_events_repository_test.go index 100e0f00..957d3c33 100644 --- a/pkg/datastore/postgres/repositories/watched_events_repository_test.go +++ b/pkg/datastore/postgres/repositories/watched_events_repository_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/datastore/repository.go b/pkg/datastore/repository.go index 5c3bde21..db0c220b 100644 --- a/pkg/datastore/repository.go +++ b/pkg/datastore/repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,35 +17,21 @@ package datastore import ( - "fmt" - "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/filters" ) -var ErrBlockDoesNotExist = func(blockNumber int64) error { - return fmt.Errorf("Block number %d does not exist", blockNumber) -} - type BlockRepository interface { CreateOrUpdateBlock(block core.Block) (int64, error) GetBlock(blockNumber int64) (core.Block, error) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) []int64 - SetBlocksStatus(chainHead int64) -} - -var ErrContractDoesNotExist = func(contractHash string) error { - return fmt.Errorf("Contract %v does not exist", contractHash) + SetBlocksStatus(chainHead int64) error } type ContractRepository interface { CreateContract(contract core.Contract) error GetContract(contractHash string) (core.Contract, error) - ContractExists(contractHash string) bool -} - -var ErrFilterDoesNotExist = func(name string) error { - return fmt.Errorf("filter %s does not exist", name) + ContractExists(contractHash string) (bool, error) } type FilterRepository interface { @@ -55,17 +41,14 @@ type FilterRepository interface { type HeaderRepository interface { CreateOrUpdateHeader(header core.Header) (int64, error) + CreateTransactions(headerID int64, transactions []core.TransactionModel) error GetHeader(blockNumber int64) (core.Header, error) - MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) []int64 + MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) ([]int64, error) } type LogRepository interface { CreateLogs(logs []core.Log, receiptId int64) error - GetLogs(address string, blockNumber int64) []core.Log -} - -var ErrReceiptDoesNotExist = func(txHash string) error { - return fmt.Errorf("Receipt for tx: %v does not exist", txHash) + GetLogs(address string, blockNumber int64) ([]core.Log, error) } type ReceiptRepository interface { diff --git a/pkg/fakes/data.go b/pkg/fakes/data.go index 32eff1d3..8b8b45a7 100644 --- a/pkg/fakes/data.go +++ b/pkg/fakes/data.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package fakes import ( + "bytes" "encoding/json" "errors" "strconv" @@ -28,6 +29,7 @@ import ( ) var ( + FakeAddress = common.HexToAddress("0x1234567890abcdef") FakeError = errors.New("failed") FakeHash = common.BytesToHash([]byte{1, 2, 3, 4, 5}) fakeTimestamp = int64(111111111) @@ -48,3 +50,52 @@ func GetFakeHeader(blockNumber int64) core.Header { Timestamp: strconv.FormatInt(fakeTimestamp, 10), } } + +var fakeTransaction types.Transaction +var rawTransaction bytes.Buffer +var _ = fakeTransaction.EncodeRLP(&rawTransaction) +var FakeTransaction = core.TransactionModel{ + Data: []byte{}, + From: "", + GasLimit: 0, + GasPrice: 0, + Hash: "", + Nonce: 0, + Raw: rawTransaction.Bytes(), + Receipt: core.Receipt{}, + To: "", + TxIndex: 0, + Value: "0", +} + +func GetFakeTransaction(hash string, receipt core.Receipt) core.TransactionModel { + gethTransaction := types.Transaction{} + var raw bytes.Buffer + err := gethTransaction.EncodeRLP(&raw) + if err != nil { + panic("failed to marshal transaction while creating test fake") + } + return core.TransactionModel{ + Data: []byte{}, + From: "", + GasLimit: 0, + GasPrice: 0, + Hash: hash, + Nonce: 0, + Raw: raw.Bytes(), + Receipt: receipt, + To: "", + TxIndex: 0, + Value: "0", + } +} + +func GetFakeUncle(hash, reward string) core.Uncle { + return core.Uncle{ + Miner: FakeAddress.String(), + Hash: hash, + Reward: reward, + Raw: rawFakeHeader, + Timestamp: strconv.FormatInt(fakeTimestamp, 10), + } +} diff --git a/pkg/fakes/mock_block_repository.go b/pkg/fakes/mock_block_repository.go index b39a034f..70c89d02 100644 --- a/pkg/fakes/mock_block_repository.go +++ b/pkg/fakes/mock_block_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -85,9 +85,10 @@ func (repository *MockBlockRepository) MissingBlockNumbers(startingBlockNumber i return repository.missingBlockNumbersReturnArray } -func (repository *MockBlockRepository) SetBlocksStatus(chainHead int64) { +func (repository *MockBlockRepository) SetBlocksStatus(chainHead int64) error { repository.setBlockStatusCalled = true repository.setBlockStatusPassedChainHead = chainHead + return nil } func (repository *MockBlockRepository) AssertCreateOrUpdateBlockCallCountEquals(times int) { diff --git a/pkg/fakes/mock_blockchain.go b/pkg/fakes/mock_blockchain.go index 2951ad7e..d09a91b3 100644 --- a/pkg/fakes/mock_blockchain.go +++ b/pkg/fakes/mock_blockchain.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package fakes import ( + "github.com/ethereum/go-ethereum/common" "math/big" "github.com/ethereum/go-ethereum" @@ -35,11 +36,17 @@ type MockBlockChain struct { fetchContractDataPassedResult interface{} fetchContractDataPassedBlockNumber int64 getBlockByNumberErr error + GetTransactionsCalled bool + GetTransactionsError error + GetTransactionsPassedHashes []common.Hash logQuery ethereum.FilterQuery logQueryErr error logQueryReturnLogs []types.Log lastBlock *big.Int node core.Node + Transactions []core.TransactionModel + accountBalanceReturnValue *big.Int + getAccountBalanceErr error } func NewMockBlockChain() *MockBlockChain { @@ -48,16 +55,16 @@ func NewMockBlockChain() *MockBlockChain { } } -func (blockChain *MockBlockChain) SetFetchContractDataErr(err error) { - blockChain.fetchContractDataErr = err +func (chain *MockBlockChain) SetFetchContractDataErr(err error) { + chain.fetchContractDataErr = err } -func (blockChain *MockBlockChain) SetLastBlock(blockNumber *big.Int) { - blockChain.lastBlock = blockNumber +func (chain *MockBlockChain) SetLastBlock(blockNumber *big.Int) { + chain.lastBlock = blockNumber } -func (blockChain *MockBlockChain) SetGetBlockByNumberErr(err error) { - blockChain.getBlockByNumberErr = err +func (chain *MockBlockChain) SetGetBlockByNumberErr(err error) { + chain.getBlockByNumberErr = err } func (chain *MockBlockChain) SetGetEthLogsWithCustomQueryErr(err error) { @@ -68,10 +75,6 @@ func (chain *MockBlockChain) SetGetEthLogsWithCustomQueryReturnLogs(logs []types chain.logQueryReturnLogs = logs } -func (blockChain *MockBlockChain) GetHeaderByNumber(blockNumber int64) (core.Header, error) { - return core.Header{BlockNumber: blockNumber}, nil -} - func (blockChain *MockBlockChain) FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error { blockChain.fetchContractDataPassedAbi = abiJSON blockChain.fetchContractDataPassedAddress = address @@ -91,16 +94,35 @@ func (blockChain *MockBlockChain) GetEthLogsWithCustomQuery(query ethereum.Filte return blockChain.logQueryReturnLogs, blockChain.logQueryErr } +func (chain *MockBlockChain) GetHeaderByNumber(blockNumber int64) (core.Header, error) { + return core.Header{BlockNumber: blockNumber}, nil +} + +func (chain *MockBlockChain) GetHeaderByNumbers(blockNumbers []int64) ([]core.Header, error) { + var headers []core.Header + for _, blockNumber := range blockNumbers { + var header = core.Header{BlockNumber: int64(blockNumber)} + headers = append(headers, header) + } + return headers, nil +} + func (chain *MockBlockChain) GetLogs(contract core.Contract, startingBlockNumber, endingBlockNumber *big.Int) ([]core.Log, error) { return []core.Log{}, nil } +func (chain *MockBlockChain) GetTransactions(transactionHashes []common.Hash) ([]core.TransactionModel, error) { + chain.GetTransactionsCalled = true + chain.GetTransactionsPassedHashes = transactionHashes + return chain.Transactions, chain.GetTransactionsError +} + func (chain *MockBlockChain) CallContract(contractHash string, input []byte, blockNumber *big.Int) ([]byte, error) { return []byte{}, nil } -func (chain *MockBlockChain) LastBlock() *big.Int { - return chain.lastBlock +func (chain *MockBlockChain) LastBlock() (*big.Int, error) { + return chain.lastBlock, nil } func (chain *MockBlockChain) Node() core.Node { @@ -121,3 +143,15 @@ func (chain *MockBlockChain) AssertFetchContractDataCalledWith(abiJSON string, a func (blockChain *MockBlockChain) AssertGetEthLogsWithCustomQueryCalledWith(query ethereum.FilterQuery) { Expect(blockChain.logQuery).To(Equal(query)) } + +func (blockChain *MockBlockChain) SetGetAccountBalanceErr(err error) { + blockChain.getAccountBalanceErr = err +} + +func (blockChain *MockBlockChain) SetGetAccountBalance(balance *big.Int) { + blockChain.accountBalanceReturnValue = balance +} + +func (blockChain *MockBlockChain) GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error) { + return blockChain.accountBalanceReturnValue, blockChain.getAccountBalanceErr +} diff --git a/pkg/fakes/mock_crypto_parser.go b/pkg/fakes/mock_crypto_parser.go index e4de379c..d2644a24 100644 --- a/pkg/fakes/mock_crypto_parser.go +++ b/pkg/fakes/mock_crypto_parser.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/fakes/mock_eth_client.go b/pkg/fakes/mock_eth_client.go index a08cc175..033232d5 100644 --- a/pkg/fakes/mock_eth_client.go +++ b/pkg/fakes/mock_eth_client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -24,6 +24,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/geth/client" ) type MockEthClient struct { @@ -40,14 +42,23 @@ type MockEthClient struct { headerByNumberPassedContext context.Context headerByNumberPassedNumber *big.Int headerByNumberReturnHeader *types.Header + headerByNumbersReturnHeader []*types.Header + headerByNumbersPassedNumber []*big.Int filterLogsErr error filterLogsPassedContext context.Context filterLogsPassedQuery ethereum.FilterQuery filterLogsReturnLogs []types.Log transactionReceipts map[string]*types.Receipt err error + passedBatch []client.BatchElem + passedMethod string transactionSenderErr error transactionReceiptErr error + passedAddress common.Address + passedBlockNumber *big.Int + passedBalance *big.Int + balanceAtErr error + passedbalanceAtContext context.Context } func NewMockEthClient() *MockEthClient { @@ -71,6 +82,8 @@ func NewMockEthClient() *MockEthClient { filterLogsReturnLogs: nil, transactionReceipts: make(map[string]*types.Receipt), err: nil, + passedBatch: nil, + passedMethod: "123", } } @@ -98,6 +111,10 @@ func (client *MockEthClient) SetHeaderByNumberReturnHeader(header *types.Header) client.headerByNumberReturnHeader = header } +func (client *MockEthClient) SetHeaderByNumbersReturnHeader(headers []*types.Header) { + client.headerByNumbersReturnHeader = headers +} + func (client *MockEthClient) SetFilterLogsErr(err error) { client.filterLogsErr = err } @@ -127,6 +144,13 @@ func (client *MockEthClient) CallContract(ctx context.Context, msg ethereum.Call return client.callContractReturnBytes, client.callContractErr } +func (client *MockEthClient) BatchCall(batch []client.BatchElem) error { + client.passedBatch = batch + client.passedMethod = batch[0].Method + + return nil +} + func (client *MockEthClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { client.blockByNumberPassedContext = ctx client.blockByNumberPassedNumber = number @@ -139,6 +163,11 @@ func (client *MockEthClient) HeaderByNumber(ctx context.Context, number *big.Int return client.headerByNumberReturnHeader, client.headerByNumberErr } +func (client *MockEthClient) HeaderByNumbers(numbers []*big.Int) ([]*types.Header, error) { + client.headerByNumbersPassedNumber = numbers + return client.headerByNumbersReturnHeader, client.headerByNumberErr +} + func (client *MockEthClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { client.filterLogsPassedContext = ctx client.filterLogsPassedQuery = q @@ -172,7 +201,36 @@ func (client *MockEthClient) AssertHeaderByNumberCalledWith(ctx context.Context, Expect(client.headerByNumberPassedNumber).To(Equal(number)) } +func (client *MockEthClient) AssertHeaderByNumbersCalledWith(number []*big.Int) { + Expect(client.headerByNumbersPassedNumber).To(Equal(number)) +} + func (client *MockEthClient) AssertFilterLogsCalledWith(ctx context.Context, q ethereum.FilterQuery) { Expect(client.filterLogsPassedContext).To(Equal(ctx)) Expect(client.filterLogsPassedQuery).To(Equal(q)) } + +func (client *MockEthClient) AssertBatchCalledWith(method string) { + Expect(client.passedMethod).To(Equal(method)) +} + +func (client *MockEthClient) SetBalanceAtErr(err error) { + client.balanceAtErr = err +} + +func (client *MockEthClient) SetBalanceAt(balance *big.Int) { + client.passedBalance = balance +} + +func (client *MockEthClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { + client.passedbalanceAtContext = ctx + client.passedAddress = account + client.passedBlockNumber = blockNumber + return client.passedBalance, client.balanceAtErr +} + +func (client *MockEthClient) AssertBalanceAtCalled(ctx context.Context, account common.Address, blockNumber *big.Int) { + Expect(client.passedbalanceAtContext).To(Equal(ctx)) + Expect(client.passedAddress).To(Equal(account)) + Expect(client.passedBlockNumber).To(Equal(blockNumber)) +} diff --git a/pkg/fakes/mock_ethereum_database.go b/pkg/fakes/mock_ethereum_database.go index 038d04ba..c1424304 100644 --- a/pkg/fakes/mock_ethereum_database.go +++ b/pkg/fakes/mock_ethereum_database.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/fakes/mock_filter_repository.go b/pkg/fakes/mock_filter_repository.go new file mode 100644 index 00000000..e6f160a8 --- /dev/null +++ b/pkg/fakes/mock_filter_repository.go @@ -0,0 +1,14 @@ +package fakes + +import "github.com/vulcanize/vulcanizedb/pkg/filters" + +type MockFilterRepository struct { +} + +func (*MockFilterRepository) CreateFilter(filter filters.LogFilter) error { + return nil +} + +func (*MockFilterRepository) GetFilter(name string) (filters.LogFilter, error) { + panic("implement me") +} diff --git a/pkg/fakes/mock_fs_reader.go b/pkg/fakes/mock_fs_reader.go index e967a2cd..b1bfafda 100644 --- a/pkg/fakes/mock_fs_reader.go +++ b/pkg/fakes/mock_fs_reader.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/fakes/mock_full_block_retriever.go b/pkg/fakes/mock_full_block_retriever.go new file mode 100644 index 00000000..c1fa67bc --- /dev/null +++ b/pkg/fakes/mock_full_block_retriever.go @@ -0,0 +1,15 @@ +package fakes + +type MockFullBlockRetriever struct { + FirstBlock int64 + FirstBlockErr error + MostRecentBlock int64 +} + +func (retriever *MockFullBlockRetriever) RetrieveFirstBlock(contractAddr string) (int64, error) { + return retriever.FirstBlock, retriever.FirstBlockErr +} + +func (retriever *MockFullBlockRetriever) RetrieveMostRecentBlock() (int64, error) { + return retriever.MostRecentBlock, nil +} diff --git a/pkg/fakes/mock_header_repository.go b/pkg/fakes/mock_header_repository.go index 58338538..8f268146 100644 --- a/pkg/fakes/mock_header_repository.go +++ b/pkg/fakes/mock_header_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -23,34 +23,64 @@ import ( ) type MockHeaderRepository struct { - createOrUpdateBlockNumbersCallCount int - createOrUpdateBlockNumbersPassedBlockNumbers []int64 - missingBlockNumbers []int64 + createOrUpdateHeaderCallCount int + createOrUpdateHeaderErr error + createOrUpdateHeaderPassedBlockNumbers []int64 + createOrUpdateHeaderReturnID int64 + CreateTransactionsCalled bool + CreateTransactionsError error + getHeaderError error + getHeaderReturnBlockHash string + missingBlockNumbers []int64 + headerExists bool + GetHeaderPassedBlockNumber int64 } func NewMockHeaderRepository() *MockHeaderRepository { return &MockHeaderRepository{} } +func (repository *MockHeaderRepository) SetCreateOrUpdateHeaderReturnID(id int64) { + repository.createOrUpdateHeaderReturnID = id +} + +func (repository *MockHeaderRepository) SetCreateOrUpdateHeaderReturnErr(err error) { + repository.createOrUpdateHeaderErr = err +} + func (repository *MockHeaderRepository) SetMissingBlockNumbers(blockNumbers []int64) { repository.missingBlockNumbers = blockNumbers } func (repository *MockHeaderRepository) CreateOrUpdateHeader(header core.Header) (int64, error) { - repository.createOrUpdateBlockNumbersCallCount++ - repository.createOrUpdateBlockNumbersPassedBlockNumbers = append(repository.createOrUpdateBlockNumbersPassedBlockNumbers, header.BlockNumber) - return 0, nil + repository.createOrUpdateHeaderCallCount++ + repository.createOrUpdateHeaderPassedBlockNumbers = append(repository.createOrUpdateHeaderPassedBlockNumbers, header.BlockNumber) + return repository.createOrUpdateHeaderReturnID, repository.createOrUpdateHeaderErr } -func (*MockHeaderRepository) GetHeader(blockNumber int64) (core.Header, error) { - return core.Header{BlockNumber: blockNumber}, nil +func (repository *MockHeaderRepository) CreateTransactions(headerID int64, transactions []core.TransactionModel) error { + repository.CreateTransactionsCalled = true + return repository.CreateTransactionsError } -func (repository *MockHeaderRepository) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) []int64 { - return repository.missingBlockNumbers +func (repository *MockHeaderRepository) GetHeader(blockNumber int64) (core.Header, error) { + repository.GetHeaderPassedBlockNumber = blockNumber + return core.Header{BlockNumber: blockNumber, Hash: repository.getHeaderReturnBlockHash}, repository.getHeaderError +} + +func (repository *MockHeaderRepository) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) ([]int64, error) { + return repository.missingBlockNumbers, nil +} + +func (repository *MockHeaderRepository) SetGetHeaderError(err error) { + repository.getHeaderError = err +} + +func (repository *MockHeaderRepository) SetGetHeaderReturnBlockHash(hash string) { + repository.getHeaderReturnBlockHash = hash } func (repository *MockHeaderRepository) AssertCreateOrUpdateHeaderCallCountAndPassedBlockNumbers(times int, blockNumbers []int64) { - Expect(repository.createOrUpdateBlockNumbersCallCount).To(Equal(times)) - Expect(repository.createOrUpdateBlockNumbersPassedBlockNumbers).To(Equal(blockNumbers)) + Expect(repository.createOrUpdateHeaderCallCount).To(Equal(times)) + Expect(repository.createOrUpdateHeaderPassedBlockNumbers).To(Equal(blockNumbers)) } diff --git a/pkg/fakes/mock_level_database_reader.go b/pkg/fakes/mock_level_database_reader.go index 261d6be0..78f99987 100644 --- a/pkg/fakes/mock_level_database_reader.go +++ b/pkg/fakes/mock_level_database_reader.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/fakes/mock_light_block_retriever.go b/pkg/fakes/mock_light_block_retriever.go new file mode 100644 index 00000000..37c4c09c --- /dev/null +++ b/pkg/fakes/mock_light_block_retriever.go @@ -0,0 +1,14 @@ +package fakes + +type MockLightBlockRetriever struct { + FirstBlock int64 + FirstBlockErr error +} + +func (retriever *MockLightBlockRetriever) RetrieveFirstBlock() (int64, error) { + return retriever.FirstBlock, retriever.FirstBlockErr +} + +func (retriever *MockLightBlockRetriever) RetrieveMostRecentBlock() (int64, error) { + return 0, nil +} diff --git a/pkg/fakes/mock_light_header_repository.go b/pkg/fakes/mock_light_header_repository.go new file mode 100644 index 00000000..9e963a99 --- /dev/null +++ b/pkg/fakes/mock_light_header_repository.go @@ -0,0 +1,42 @@ +package fakes + +import "github.com/vulcanize/vulcanizedb/pkg/core" + +type MockLightHeaderRepository struct { +} + +func (*MockLightHeaderRepository) AddCheckColumn(id string) error { + return nil +} + +func (*MockLightHeaderRepository) AddCheckColumns(ids []string) error { + panic("implement me") +} + +func (*MockLightHeaderRepository) MarkHeaderChecked(headerID int64, eventID string) error { + panic("implement me") +} + +func (*MockLightHeaderRepository) MarkHeaderCheckedForAll(headerID int64, ids []string) error { + panic("implement me") +} + +func (*MockLightHeaderRepository) MarkHeadersCheckedForAll(headers []core.Header, ids []string) error { + panic("implement me") +} + +func (*MockLightHeaderRepository) MissingHeaders(startingBlockNumber int64, endingBlockNumber int64, eventID string) ([]core.Header, error) { + panic("implement me") +} + +func (*MockLightHeaderRepository) MissingMethodsCheckedEventsIntersection(startingBlockNumber, endingBlockNumber int64, methodIds, eventIds []string) ([]core.Header, error) { + panic("implement me") +} + +func (*MockLightHeaderRepository) MissingHeadersForAll(startingBlockNumber, endingBlockNumber int64, ids []string) ([]core.Header, error) { + panic("implement me") +} + +func (*MockLightHeaderRepository) CheckCache(key string) (interface{}, bool) { + panic("implement me") +} diff --git a/pkg/fakes/mock_parser.go b/pkg/fakes/mock_parser.go new file mode 100644 index 00000000..dd03bbab --- /dev/null +++ b/pkg/fakes/mock_parser.go @@ -0,0 +1,41 @@ +package fakes + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types" +) + +type MockParser struct { + AbiToReturn string + EventName string + Event types.Event +} + +func (*MockParser) Parse(contractAddr string) error { + return nil +} + +func (m *MockParser) ParseAbiStr(abiStr string) error { + m.AbiToReturn = abiStr + return nil +} + +func (parser *MockParser) Abi() string { + return parser.AbiToReturn +} + +func (*MockParser) ParsedAbi() abi.ABI { + return abi.ABI{} +} + +func (*MockParser) GetMethods(wanted []string) []types.Method { + panic("implement me") +} + +func (*MockParser) GetSelectMethods(wanted []string) []types.Method { + return []types.Method{} +} + +func (parser *MockParser) GetEvents(wanted []string) map[string]types.Event { + return map[string]types.Event{parser.EventName: parser.Event} +} diff --git a/pkg/fakes/mock_poller.go b/pkg/fakes/mock_poller.go new file mode 100644 index 00000000..2d782b18 --- /dev/null +++ b/pkg/fakes/mock_poller.go @@ -0,0 +1,24 @@ +package fakes + +import ( + "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract" +) + +type MockPoller struct { + ContractName string +} + +func (*MockPoller) PollContract(con contract.Contract, lastBlock int64) error { + panic("implement me") +} + +func (*MockPoller) PollContractAt(con contract.Contract, blockNumber int64) error { + panic("implement me") +} + +func (poller *MockPoller) FetchContractData(contractAbi, contractAddress, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error { + if p, ok := result.(*string); ok { + *p = poller.ContractName + } + return nil +} diff --git a/pkg/fakes/mock_receipt_repository.go b/pkg/fakes/mock_receipt_repository.go index 5663eeed..63a0d24d 100644 --- a/pkg/fakes/mock_receipt_repository.go +++ b/pkg/fakes/mock_receipt_repository.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/fakes/mock_rpc_client.go b/pkg/fakes/mock_rpc_client.go index 20863d1e..fcf224cc 100644 --- a/pkg/fakes/mock_rpc_client.go +++ b/pkg/fakes/mock_rpc_client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/geth/client" ) type MockRpcClient struct { @@ -34,7 +35,11 @@ type MockRpcClient struct { passedContext context.Context passedMethod string passedResult interface{} + passedBatch []client.BatchElem + lengthOfBatch int returnPOAHeader core.POAHeader + returnPOAHeaders []core.POAHeader + returnPOWHeaders []*types.Header supportedModules map[string]string } @@ -46,6 +51,27 @@ func (client *MockRpcClient) SetIpcPath(ipcPath string) { client.ipcPath = ipcPath } +func (client *MockRpcClient) BatchCall(batch []client.BatchElem) error { + client.passedBatch = batch + client.passedMethod = batch[0].Method + client.lengthOfBatch = len(batch) + + for _, batchElem := range batch { + client.passedContext = context.Background() + client.passedResult = &batchElem.Result + client.passedMethod = batchElem.Method + if p, ok := batchElem.Result.(*types.Header); ok { + *p = types.Header{Number: big.NewInt(100)} + } + if p, ok := batchElem.Result.(*core.POAHeader); ok { + + *p = client.returnPOAHeader + } + } + + return nil +} + func (client *MockRpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { client.passedContext = ctx client.passedResult = result @@ -58,9 +84,10 @@ func (client *MockRpcClient) CallContext(ctx context.Context, result interface{} } case "eth_getBlockByNumber": if p, ok := result.(*types.Header); ok { - *p = types.Header{Number: big.NewInt(123)} + *p = types.Header{Number: big.NewInt(100)} } if p, ok := result.(*core.POAHeader); ok { + *p = client.returnPOAHeader } if client.callContextErr != nil { @@ -110,8 +137,24 @@ func (client *MockRpcClient) SetReturnPOAHeader(header core.POAHeader) { client.returnPOAHeader = header } +func (client *MockRpcClient) SetReturnPOWHeaders(headers []*types.Header) { + client.returnPOWHeaders = headers +} + +func (client *MockRpcClient) SetReturnPOAHeaders(headers []core.POAHeader) { + client.returnPOAHeaders = headers +} + func (client *MockRpcClient) AssertCallContextCalledWith(ctx context.Context, result interface{}, method string) { Expect(client.passedContext).To(Equal(ctx)) Expect(client.passedResult).To(BeAssignableToTypeOf(result)) Expect(client.passedMethod).To(Equal(method)) } + +func (client *MockRpcClient) AssertBatchCalledWith(method string, lengthOfBatch int) { + Expect(client.lengthOfBatch).To(Equal(lengthOfBatch)) + for _, batch := range client.passedBatch { + Expect(batch.Method).To(Equal(method)) + } + Expect(client.passedMethod).To(Equal(method)) +} diff --git a/pkg/fakes/mock_tailer.go b/pkg/fakes/mock_tailer.go new file mode 100644 index 00000000..888688d6 --- /dev/null +++ b/pkg/fakes/mock_tailer.go @@ -0,0 +1,29 @@ +package fakes + +import ( + "github.com/hpcloud/tail" + "gopkg.in/tomb.v1" +) + +type MockTailer struct { + Lines chan *tail.Line + TailCalled bool +} + +func NewMockTailer() *MockTailer { + return &MockTailer{ + Lines: make(chan *tail.Line, 1), + TailCalled: false, + } +} + +func (mock *MockTailer) Tail() (*tail.Tail, error) { + mock.TailCalled = true + fakeTail := &tail.Tail{ + Filename: "", + Lines: mock.Lines, + Config: tail.Config{}, + Tomb: tomb.Tomb{}, + } + return fakeTail, nil +} diff --git a/pkg/fakes/mock_transaction_converter.go b/pkg/fakes/mock_transaction_converter.go index b36c390e..5f23310d 100644 --- a/pkg/fakes/mock_transaction_converter.go +++ b/pkg/fakes/mock_transaction_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,39 +18,30 @@ package fakes import ( "github.com/ethereum/go-ethereum/core/types" - . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/core" ) type MockTransactionConverter struct { - convertTransactionsToCoreCalled bool - convertTransactionsToCorePassedBlock *types.Block - convertTransactionsToCoreReturnTransactions []core.Transaction - convertTransactionsToCoreReturnError error + ConvertHeaderTransactionIndexToIntCalled bool + ConvertBlockTransactionsToCoreCalled bool + ConvertBlockTransactionsToCorePassedBlock *types.Block } func NewMockTransactionConverter() *MockTransactionConverter { return &MockTransactionConverter{ - convertTransactionsToCoreCalled: false, - convertTransactionsToCorePassedBlock: nil, - convertTransactionsToCoreReturnTransactions: nil, - convertTransactionsToCoreReturnError: nil, + ConvertHeaderTransactionIndexToIntCalled: false, + ConvertBlockTransactionsToCoreCalled: false, + ConvertBlockTransactionsToCorePassedBlock: nil, } } -func (mtc *MockTransactionConverter) SetConvertTransactionsToCoreReturnVals(transactions []core.Transaction, err error) { - mtc.convertTransactionsToCoreReturnTransactions = transactions - mtc.convertTransactionsToCoreReturnError = err +func (converter *MockTransactionConverter) ConvertBlockTransactionsToCore(gethBlock *types.Block) ([]core.TransactionModel, error) { + converter.ConvertBlockTransactionsToCoreCalled = true + converter.ConvertBlockTransactionsToCorePassedBlock = gethBlock + return []core.TransactionModel{}, nil } -func (mtc *MockTransactionConverter) ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) { - mtc.convertTransactionsToCoreCalled = true - mtc.convertTransactionsToCorePassedBlock = gethBlock - return mtc.convertTransactionsToCoreReturnTransactions, mtc.convertTransactionsToCoreReturnError -} - -func (mtc *MockTransactionConverter) AssertConvertTransactionsToCoreCalledWith(gethBlock *types.Block) { - Expect(mtc.convertTransactionsToCoreCalled).To(BeTrue()) - Expect(mtc.convertTransactionsToCorePassedBlock).To(Equal(gethBlock)) +func (converter *MockTransactionConverter) ConvertRpcTransactionsToModels(transactions []core.RpcTransaction) ([]core.TransactionModel, error) { + converter.ConvertHeaderTransactionIndexToIntCalled = true + return nil, nil } diff --git a/pkg/fakes/mock_transaction_syncer.go b/pkg/fakes/mock_transaction_syncer.go new file mode 100644 index 00000000..0753a69a --- /dev/null +++ b/pkg/fakes/mock_transaction_syncer.go @@ -0,0 +1,13 @@ +package fakes + +import "github.com/ethereum/go-ethereum/core/types" + +type MockTransactionSyncer struct { + SyncTransactionsCalled bool + SyncTransactionsError error +} + +func (syncer *MockTransactionSyncer) SyncTransactions(headerID int64, logs []types.Log) error { + syncer.SyncTransactionsCalled = true + return syncer.SyncTransactionsError +} diff --git a/pkg/filters/filter_query.go b/pkg/filters/filter_query.go index 26e3f428..6db68638 100644 --- a/pkg/filters/filter_query.go +++ b/pkg/filters/filter_query.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/filters/filter_test.go b/pkg/filters/filter_test.go index ea475f8c..9c4e8b79 100644 --- a/pkg/filters/filter_test.go +++ b/pkg/filters/filter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/filters/query_builder_suite_test.go b/pkg/filters/query_builder_suite_test.go index 7f49afb6..189a4314 100644 --- a/pkg/filters/query_builder_suite_test.go +++ b/pkg/filters/query_builder_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/fs/reader.go b/pkg/fs/reader.go index fe9df6ac..05326ae7 100644 --- a/pkg/fs/reader.go +++ b/pkg/fs/reader.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,8 +22,7 @@ type Reader interface { Read(path string) ([]byte, error) } -type FsReader struct { -} +type FsReader struct{} func (FsReader) Read(path string) ([]byte, error) { return ioutil.ReadFile(path) diff --git a/pkg/fs/tail.go b/pkg/fs/tail.go new file mode 100644 index 00000000..7c84c692 --- /dev/null +++ b/pkg/fs/tail.go @@ -0,0 +1,15 @@ +package fs + +import "github.com/hpcloud/tail" + +type Tailer interface { + Tail() (*tail.Tail, error) +} + +type FileTailer struct { + Path string +} + +func (tailer FileTailer) Tail() (*tail.Tail, error) { + return tail.TailFile(tailer.Path, tail.Config{Follow: true}) +} diff --git a/pkg/geth/abi.go b/pkg/geth/abi.go index d6943597..37d3bd77 100644 --- a/pkg/geth/abi.go +++ b/pkg/geth/abi.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/abi_test.go b/pkg/geth/abi_test.go index 3e5a78dc..8e601783 100644 --- a/pkg/geth/abi_test.go +++ b/pkg/geth/abi_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/blockchain.go b/pkg/geth/blockchain.go index 432ef6dd..a2b641c7 100644 --- a/pkg/geth/blockchain.go +++ b/pkg/geth/blockchain.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,35 +18,42 @@ package geth import ( "errors" - "math/big" - + "fmt" "github.com/ethereum/go-ethereum" + "math/big" + "strconv" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "golang.org/x/net/context" "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/geth/client" vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common" ) var ErrEmptyHeader = errors.New("empty header returned over RPC") +const MAX_BATCH_SIZE = 100 + type BlockChain struct { - blockConverter vulcCommon.BlockConverter - ethClient core.EthClient - headerConverter vulcCommon.HeaderConverter - node core.Node - rpcClient core.RpcClient + blockConverter vulcCommon.BlockConverter + ethClient core.EthClient + headerConverter vulcCommon.HeaderConverter + node core.Node + rpcClient core.RpcClient + transactionConverter vulcCommon.TransactionConverter } func NewBlockChain(ethClient core.EthClient, rpcClient core.RpcClient, node core.Node, converter vulcCommon.TransactionConverter) *BlockChain { return &BlockChain{ - blockConverter: vulcCommon.NewBlockConverter(converter), - ethClient: ethClient, - headerConverter: vulcCommon.HeaderConverter{}, - node: node, - rpcClient: rpcClient, + blockConverter: vulcCommon.NewBlockConverter(converter), + ethClient: ethClient, + headerConverter: vulcCommon.HeaderConverter{}, + node: node, + rpcClient: rpcClient, + transactionConverter: converter, } } @@ -58,6 +65,14 @@ func (blockChain *BlockChain) GetBlockByNumber(blockNumber int64) (block core.Bl return blockChain.blockConverter.ToCoreBlock(gethBlock) } +func (blockChain *BlockChain) GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error) { + gethLogs, err := blockChain.ethClient.FilterLogs(context.Background(), query) + if err != nil { + return []types.Log{}, err + } + return gethLogs, nil +} + func (blockChain *BlockChain) GetHeaderByNumber(blockNumber int64) (header core.Header, err error) { if blockChain.node.NetworkID == core.KOVAN_NETWORK_ID { return blockChain.getPOAHeader(blockNumber) @@ -65,12 +80,62 @@ func (blockChain *BlockChain) GetHeaderByNumber(blockNumber int64) (header core. return blockChain.getPOWHeader(blockNumber) } -func (blockChain *BlockChain) getPOWHeader(blockNumber int64) (header core.Header, err error) { - gethHeader, err := blockChain.ethClient.HeaderByNumber(context.Background(), big.NewInt(blockNumber)) - if err != nil { - return header, err +func (blockChain *BlockChain) GetHeaderByNumbers(blockNumbers []int64) (header []core.Header, err error) { + if blockChain.node.NetworkID == core.KOVAN_NETWORK_ID { + return blockChain.getPOAHeaders(blockNumbers) } - return blockChain.headerConverter.Convert(gethHeader, gethHeader.Hash().String()) + return blockChain.getPOWHeaders(blockNumbers) +} + +func (blockChain *BlockChain) GetLogs(contract core.Contract, startingBlockNumber, endingBlockNumber *big.Int) ([]core.Log, error) { + if endingBlockNumber == nil { + endingBlockNumber = startingBlockNumber + } + contractAddress := common.HexToAddress(contract.Hash) + fc := ethereum.FilterQuery{ + FromBlock: startingBlockNumber, + ToBlock: endingBlockNumber, + Addresses: []common.Address{contractAddress}, + Topics: nil, + } + gethLogs, err := blockChain.GetEthLogsWithCustomQuery(fc) + if err != nil { + return []core.Log{}, err + } + logs := vulcCommon.ToCoreLogs(gethLogs) + return logs, nil +} + +func (blockChain *BlockChain) GetTransactions(transactionHashes []common.Hash) ([]core.TransactionModel, error) { + numTransactions := len(transactionHashes) + var batch []client.BatchElem + transactions := make([]core.RpcTransaction, numTransactions) + + for index, transactionHash := range transactionHashes { + batchElem := client.BatchElem{ + Method: "eth_getTransactionByHash", + Result: &transactions[index], + Args: []interface{}{transactionHash}, + } + batch = append(batch, batchElem) + } + + rpcErr := blockChain.rpcClient.BatchCall(batch) + if rpcErr != nil { + fmt.Println("rpc err") + return []core.TransactionModel{}, rpcErr + } + + return blockChain.transactionConverter.ConvertRpcTransactionsToModels(transactions) +} + +func (blockChain *BlockChain) LastBlock() (*big.Int, error) { + block, err := blockChain.ethClient.HeaderByNumber(context.Background(), nil) + return block.Number, err +} + +func (blockChain *BlockChain) Node() core.Node { + return blockChain.node } func (blockChain *BlockChain) getPOAHeader(blockNumber int64) (header core.Header, err error) { @@ -98,41 +163,109 @@ func (blockChain *BlockChain) getPOAHeader(blockNumber int64) (header core.Heade GasUsed: uint64(POAHeader.GasUsed), Time: POAHeader.Time.ToInt(), Extra: POAHeader.Extra, - }, POAHeader.Hash.String()) + }, POAHeader.Hash.String()), nil } -func (blockChain *BlockChain) GetLogs(contract core.Contract, startingBlockNumber, endingBlockNumber *big.Int) ([]core.Log, error) { - if endingBlockNumber == nil { - endingBlockNumber = startingBlockNumber +func (blockChain *BlockChain) getPOAHeaders(blockNumbers []int64) (headers []core.Header, err error) { + + var batch []client.BatchElem + var POAHeaders [MAX_BATCH_SIZE]core.POAHeader + includeTransactions := false + + for index, blockNumber := range blockNumbers { + + if index >= MAX_BATCH_SIZE { + break + } + + blockNumberArg := hexutil.EncodeBig(big.NewInt(blockNumber)) + + batchElem := client.BatchElem{ + Method: "eth_getBlockByNumber", + Result: &POAHeaders[index], + Args: []interface{}{blockNumberArg, includeTransactions}, + } + + batch = append(batch, batchElem) } - contractAddress := common.HexToAddress(contract.Hash) - fc := ethereum.FilterQuery{ - FromBlock: startingBlockNumber, - ToBlock: endingBlockNumber, - Addresses: []common.Address{contractAddress}, - Topics: nil, - } - gethLogs, err := blockChain.GetEthLogsWithCustomQuery(fc) + + err = blockChain.rpcClient.BatchCall(batch) if err != nil { - return []core.Log{}, err + return headers, err } - logs := vulcCommon.ToCoreLogs(gethLogs) - return logs, nil + + for _, POAHeader := range POAHeaders { + var header core.Header + //Header.Number of the newest block will return nil. + if _, err := strconv.ParseUint(POAHeader.Number.ToInt().String(), 16, 64); err == nil { + header = blockChain.headerConverter.Convert(&types.Header{ + ParentHash: POAHeader.ParentHash, + UncleHash: POAHeader.UncleHash, + Coinbase: POAHeader.Coinbase, + Root: POAHeader.Root, + TxHash: POAHeader.TxHash, + ReceiptHash: POAHeader.ReceiptHash, + Bloom: POAHeader.Bloom, + Difficulty: POAHeader.Difficulty.ToInt(), + Number: POAHeader.Number.ToInt(), + GasLimit: uint64(POAHeader.GasLimit), + GasUsed: uint64(POAHeader.GasUsed), + Time: POAHeader.Time.ToInt(), + Extra: POAHeader.Extra, + }, POAHeader.Hash.String()) + + headers = append(headers, header) + } + } + + return headers, err } -func (blockChain *BlockChain) GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error) { - gethLogs, err := blockChain.ethClient.FilterLogs(context.Background(), query) +func (blockChain *BlockChain) getPOWHeader(blockNumber int64) (header core.Header, err error) { + gethHeader, err := blockChain.ethClient.HeaderByNumber(context.Background(), big.NewInt(blockNumber)) if err != nil { - return []types.Log{}, err + return header, err } - return gethLogs, nil + return blockChain.headerConverter.Convert(gethHeader, gethHeader.Hash().String()), nil } -func (blockChain *BlockChain) LastBlock() *big.Int { - block, _ := blockChain.ethClient.HeaderByNumber(context.Background(), nil) - return block.Number +func (blockChain *BlockChain) getPOWHeaders(blockNumbers []int64) (headers []core.Header, err error) { + var batch []client.BatchElem + var POWHeaders [MAX_BATCH_SIZE]types.Header + includeTransactions := false + + for index, blockNumber := range blockNumbers { + + if index >= MAX_BATCH_SIZE { + break + } + + blockNumberArg := hexutil.EncodeBig(big.NewInt(blockNumber)) + + batchElem := client.BatchElem{ + Method: "eth_getBlockByNumber", + Result: &POWHeaders[index], + Args: []interface{}{blockNumberArg, includeTransactions}, + } + + batch = append(batch, batchElem) + } + + err = blockChain.rpcClient.BatchCall(batch) + if err != nil { + return headers, err + } + + for _, POWHeader := range POWHeaders { + if POWHeader.Number != nil { + header := blockChain.headerConverter.Convert(&POWHeader, POWHeader.Hash().String()) + headers = append(headers, header) + } + } + + return headers, err } -func (blockChain *BlockChain) Node() core.Node { - return blockChain.node +func (blockChain *BlockChain) GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error) { + return blockChain.ethClient.BalanceAt(context.Background(), address, blockNumber) } diff --git a/pkg/geth/blockchain_test.go b/pkg/geth/blockchain_test.go index 2360e613..d70eda92 100644 --- a/pkg/geth/blockchain_test.go +++ b/pkg/geth/blockchain_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,6 +18,7 @@ package geth_test import ( "context" + "errors" "math/big" "github.com/ethereum/go-ethereum" @@ -30,20 +31,23 @@ import ( vulcCore "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/geth" - "github.com/vulcanize/vulcanizedb/pkg/geth/converters/cold_db" ) var _ = Describe("Geth blockchain", func() { - var mockClient *fakes.MockEthClient - var mockRpcClient *fakes.MockRpcClient - var node vulcCore.Node - var blockChain *geth.BlockChain + var ( + mockClient *fakes.MockEthClient + blockChain *geth.BlockChain + mockRpcClient *fakes.MockRpcClient + mockTransactionConverter *fakes.MockTransactionConverter + node vulcCore.Node + ) BeforeEach(func() { mockClient = fakes.NewMockEthClient() mockRpcClient = fakes.NewMockRpcClient() + mockTransactionConverter = fakes.NewMockTransactionConverter() node = vulcCore.Node{} - blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, cold_db.NewColdDbTransactionConverter()) + blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, mockTransactionConverter) }) Describe("getting a block", func() { @@ -87,14 +91,21 @@ var _ = Describe("Geth blockchain", func() { Expect(err).To(HaveOccurred()) Expect(err).To(MatchError(fakes.FakeError)) }) + + It("fetches headers with multiple blocks", func() { + _, err := blockChain.GetHeaderByNumbers([]int64{100, 99}) + + Expect(err).NotTo(HaveOccurred()) + mockRpcClient.AssertBatchCalledWith("eth_getBlockByNumber", 2) + }) }) Describe("POA/Kovan", func() { It("fetches header from rpcClient", func() { node.NetworkID = vulcCore.KOVAN_NETWORK_ID - blockNumber := hexutil.Big(*big.NewInt(123)) + blockNumber := hexutil.Big(*big.NewInt(100)) mockRpcClient.SetReturnPOAHeader(vulcCore.POAHeader{Number: &blockNumber}) - blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, cold_db.NewColdDbTransactionConverter()) + blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, fakes.NewMockTransactionConverter()) _, err := blockChain.GetHeaderByNumber(100) @@ -105,7 +116,7 @@ var _ = Describe("Geth blockchain", func() { It("returns err if rpcClient returns err", func() { node.NetworkID = vulcCore.KOVAN_NETWORK_ID mockRpcClient.SetCallContextErr(fakes.FakeError) - blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, cold_db.NewColdDbTransactionConverter()) + blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, fakes.NewMockTransactionConverter()) _, err := blockChain.GetHeaderByNumber(100) @@ -115,13 +126,24 @@ var _ = Describe("Geth blockchain", func() { It("returns error if returned header is empty", func() { node.NetworkID = vulcCore.KOVAN_NETWORK_ID - blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, cold_db.NewColdDbTransactionConverter()) + blockChain = geth.NewBlockChain(mockClient, mockRpcClient, node, fakes.NewMockTransactionConverter()) _, err := blockChain.GetHeaderByNumber(100) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError(geth.ErrEmptyHeader)) }) + + It("returns multiple headers with multiple blocknumbers", func() { + node.NetworkID = vulcCore.KOVAN_NETWORK_ID + blockNumber := hexutil.Big(*big.NewInt(100)) + mockRpcClient.SetReturnPOAHeaders([]vulcCore.POAHeader{{Number: &blockNumber}}) + + _, err := blockChain.GetHeaderByNumbers([]int64{100, 99}) + + Expect(err).NotTo(HaveOccurred()) + mockRpcClient.AssertBatchCalledWith("eth_getBlockByNumber", 2) + }) }) }) @@ -195,15 +217,56 @@ var _ = Describe("Geth blockchain", func() { }) }) + Describe("getting transactions", func() { + It("fetches transaction for each hash", func() { + _, err := blockChain.GetTransactions([]common.Hash{{}, {}}) + + Expect(err).NotTo(HaveOccurred()) + mockRpcClient.AssertBatchCalledWith("eth_getTransactionByHash", 2) + }) + + It("converts transaction indexes from hex to int", func() { + _, err := blockChain.GetTransactions([]common.Hash{{}, {}}) + + Expect(err).NotTo(HaveOccurred()) + Expect(mockTransactionConverter.ConvertHeaderTransactionIndexToIntCalled).To(BeTrue()) + }) + }) + Describe("getting the most recent block number", func() { It("fetches latest header from ethClient", func() { blockNumber := int64(100) mockClient.SetHeaderByNumberReturnHeader(&types.Header{Number: big.NewInt(blockNumber)}) - result := blockChain.LastBlock() + result, err := blockChain.LastBlock() + Expect(err).NotTo(HaveOccurred()) mockClient.AssertHeaderByNumberCalledWith(context.Background(), nil) Expect(result).To(Equal(big.NewInt(blockNumber))) }) }) + + Describe("getting an account balance", func() { + It("fetches the balance for a given account address at a given block height", func() { + balance := big.NewInt(100000) + mockClient.SetBalanceAt(balance) + + result, err := blockChain.GetAccountBalance(common.HexToAddress("0x40"), big.NewInt(100)) + Expect(err).NotTo(HaveOccurred()) + + mockClient.AssertBalanceAtCalled(context.Background(), common.HexToAddress("0x40"), big.NewInt(100)) + Expect(result).To(Equal(balance)) + }) + + It("fails if the client returns an error", func() { + balance := big.NewInt(100000) + mockClient.SetBalanceAt(balance) + setErr := errors.New("testError") + mockClient.SetBalanceAtErr(setErr) + + _, err := blockChain.GetAccountBalance(common.HexToAddress("0x40"), big.NewInt(100)) + Expect(err).To(HaveOccurred()) + Expect(err).To(Equal(setErr)) + }) + }) }) diff --git a/pkg/geth/client/eth_client.go b/pkg/geth/client/eth_client.go index c4af6009..fca30d39 100644 --- a/pkg/geth/client/eth_client.go +++ b/pkg/geth/client/eth_client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -56,3 +56,7 @@ func (client EthClient) TransactionSender(ctx context.Context, tx *types.Transac func (client EthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { return client.client.TransactionReceipt(ctx, txHash) } + +func (client EthClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { + return client.client.BalanceAt(ctx, account, blockNumber) +} diff --git a/pkg/geth/client/rpc_client.go b/pkg/geth/client/rpc_client.go index abb74586..b80a746d 100644 --- a/pkg/geth/client/rpc_client.go +++ b/pkg/geth/client/rpc_client.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -26,6 +26,13 @@ type RpcClient struct { ipcPath string } +type BatchElem struct { + Method string + Args []interface{} + Result interface{} + Error error +} + func NewRpcClient(client *rpc.Client, ipcPath string) RpcClient { return RpcClient{ client: client, @@ -34,7 +41,14 @@ func NewRpcClient(client *rpc.Client, ipcPath string) RpcClient { } func (client RpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { - return client.client.CallContext(ctx, result, method, args) + //If an empty interface (or other nil object) is passed to CallContext, when the JSONRPC message is created the params will + //be interpreted as [null]. This seems to work fine for most of the ethereum clients (which presumably ignore a null parameter. + //Ganache however does not ignore it, and throws an 'Incorrect number of arguments' error. + if args == nil { + return client.client.CallContext(ctx, result, method) + } else { + return client.client.CallContext(ctx, result, method, args...) + } } func (client RpcClient) IpcPath() string { @@ -44,3 +58,18 @@ func (client RpcClient) IpcPath() string { func (client RpcClient) SupportedModules() (map[string]string, error) { return client.client.SupportedModules() } + +func (client RpcClient) BatchCall(batch []BatchElem) error { + var rpcBatch []rpc.BatchElem + for _, batchElem := range batch { + var newBatchElem = rpc.BatchElem{ + Result: batchElem.Result, + Method: batchElem.Method, + Args: batchElem.Args, + Error: batchElem.Error, + } + + rpcBatch = append(rpcBatch, newBatchElem) + } + return client.client.BatchCall(rpcBatch) +} diff --git a/pkg/geth/cold_import/cold_import_suite_test.go b/pkg/geth/cold_import/cold_import_suite_test.go index 22f9632c..d11dbf00 100644 --- a/pkg/geth/cold_import/cold_import_suite_test.go +++ b/pkg/geth/cold_import/cold_import_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/cold_import/importer.go b/pkg/geth/cold_import/importer.go index 9ebeb0dc..e29bfd22 100644 --- a/pkg/geth/cold_import/importer.go +++ b/pkg/geth/cold_import/importer.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -67,6 +67,9 @@ func (ci *ColdImporter) createBlocksAndTransactions(hash []byte, i int64) (int64 func (ci *ColdImporter) createReceiptsAndLogs(hash []byte, number int64, blockId int64) error { receipts := ci.ethDB.GetBlockReceipts(hash, number) - coreReceipts := common.ToCoreReceipts(receipts) + coreReceipts, err := common.ToCoreReceipts(receipts) + if err != nil { + return err + } return ci.receiptRepository.CreateReceiptsAndLogs(blockId, coreReceipts) } diff --git a/pkg/geth/cold_import/importer_test.go b/pkg/geth/cold_import/importer_test.go index 3e50b110..ed435f5f 100644 --- a/pkg/geth/cold_import/importer_test.go +++ b/pkg/geth/cold_import/importer_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,7 +20,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/geth/cold_import" @@ -55,7 +54,8 @@ var _ = Describe("Geth cold importer", func() { mockEthereumDatabase.SetReturnBlock(fakeGethBlock) importer := cold_import.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter) - importer.Execute(startingBlockNumber, endingBlockNumber, nodeId) + err := importer.Execute(startingBlockNumber, endingBlockNumber, nodeId) + Expect(err).NotTo(HaveOccurred()) mockBlockRepository.AssertMissingBlockNumbersCalledWith(startingBlockNumber, endingBlockNumber, nodeId) mockEthereumDatabase.AssertGetBlockHashCalledWith(missingBlockNumber) @@ -76,11 +76,13 @@ var _ = Describe("Geth cold importer", func() { mockEthereumDatabase.SetReturnBlock(fakeGethBlock) importer := cold_import.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter) - importer.Execute(blockNumber, blockNumber, "node_id") + err := importer.Execute(blockNumber, blockNumber, "node_id") + Expect(err).NotTo(HaveOccurred()) mockEthereumDatabase.AssertGetBlockHashCalledWith(blockNumber) mockEthereumDatabase.AssertGetBlockCalledWith(fakeHash, blockNumber) - mockTransactionConverter.AssertConvertTransactionsToCoreCalledWith(fakeGethBlock) + Expect(mockTransactionConverter.ConvertBlockTransactionsToCoreCalled).To(BeTrue()) + Expect(mockTransactionConverter.ConvertBlockTransactionsToCorePassedBlock).To(Equal(fakeGethBlock)) convertedBlock, err := blockConverter.ToCoreBlock(fakeGethBlock) Expect(err).NotTo(HaveOccurred()) mockBlockRepository.AssertCreateOrUpdateBlockCalledWith(convertedBlock) @@ -101,8 +103,8 @@ var _ = Describe("Geth cold importer", func() { mockEthereumDatabase.SetReturnBlock(fakeGethBlock) importer := cold_import.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter) - importer.Execute(startingBlockNumber, endingBlockNumber, "node_id") - + err := importer.Execute(startingBlockNumber, endingBlockNumber, "node_id") + Expect(err).NotTo(HaveOccurred()) mockBlockRepository.AssertSetBlockStatusCalledWith(endingBlockNumber) }) @@ -122,9 +124,10 @@ var _ = Describe("Geth cold importer", func() { mockEthereumDatabase.SetReturnReceipts(fakeReceipts) importer := cold_import.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter) - importer.Execute(blockNumber, blockNumber, "node_id") - - expectedReceipts := vulcCommon.ToCoreReceipts(fakeReceipts) + err := importer.Execute(blockNumber, blockNumber, "node_id") + Expect(err).NotTo(HaveOccurred()) + expectedReceipts, err := vulcCommon.ToCoreReceipts(fakeReceipts) + Expect(err).ToNot(HaveOccurred()) mockReceiptRepository.AssertCreateReceiptsAndLogsCalledWith(blockId, expectedReceipts) }) diff --git a/pkg/geth/cold_import/node_builder.go b/pkg/geth/cold_import/node_builder.go index 4e39bf69..b9c12080 100644 --- a/pkg/geth/cold_import/node_builder.go +++ b/pkg/geth/cold_import/node_builder.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/cold_import/node_builder_test.go b/pkg/geth/cold_import/node_builder_test.go index 83300078..e2be8620 100644 --- a/pkg/geth/cold_import/node_builder_test.go +++ b/pkg/geth/cold_import/node_builder_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/contract.go b/pkg/geth/contract.go index 4c49f422..b5f968ec 100644 --- a/pkg/geth/contract.go +++ b/pkg/geth/contract.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -43,7 +43,11 @@ func (blockChain *BlockChain) FetchContractData(abiJSON string, address string, if err != nil { return err } - output, err := blockChain.callContract(address, input, big.NewInt(blockNumber)) + var bn *big.Int + if blockNumber > 0 { + bn = big.NewInt(blockNumber) + } + output, err := blockChain.callContract(address, input, bn) if err != nil { return err } diff --git a/pkg/geth/converters/cold_db/transaction_converter.go b/pkg/geth/converters/cold_db/transaction_converter.go index 3b095754..fd6a319e 100644 --- a/pkg/geth/converters/cold_db/transaction_converter.go +++ b/pkg/geth/converters/cold_db/transaction_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,7 +18,6 @@ package cold_db import ( "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/vulcanize/vulcanizedb/pkg/core" "golang.org/x/sync/errgroup" @@ -31,9 +30,9 @@ func NewColdDbTransactionConverter() *ColdDbTransactionConverter { return &ColdDbTransactionConverter{} } -func (cdtc *ColdDbTransactionConverter) ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) { +func (cdtc *ColdDbTransactionConverter) ConvertBlockTransactionsToCore(gethBlock *types.Block) ([]core.TransactionModel, error) { var g errgroup.Group - coreTransactions := make([]core.Transaction, len(gethBlock.Transactions())) + coreTransactions := make([]core.TransactionModel, len(gethBlock.Transactions())) for gethTransactionIndex, gethTransaction := range gethBlock.Transactions() { transaction := gethTransaction @@ -55,6 +54,10 @@ func (cdtc *ColdDbTransactionConverter) ConvertTransactionsToCore(gethBlock *typ return coreTransactions, nil } +func (cdtc *ColdDbTransactionConverter) ConvertRpcTransactionsToModels(transactions []core.RpcTransaction) ([]core.TransactionModel, error) { + panic("converting transaction indexes to integer not supported for cold import") +} + func getSigner(tx *types.Transaction) types.Signer { v, _, _ := tx.RawSignatureValues() if v.Sign() != 0 && tx.Protected() { @@ -63,9 +66,8 @@ func getSigner(tx *types.Transaction) types.Signer { return types.HomesteadSigner{} } -func transToCoreTrans(transaction *types.Transaction, from *common.Address) core.Transaction { - data := hexutil.Encode(transaction.Data()) - return core.Transaction{ +func transToCoreTrans(transaction *types.Transaction, from *common.Address) core.TransactionModel { + return core.TransactionModel{ Hash: transaction.Hash().Hex(), Nonce: transaction.Nonce(), To: strings.ToLower(addressToHex(transaction.To())), @@ -73,7 +75,7 @@ func transToCoreTrans(transaction *types.Transaction, from *common.Address) core GasLimit: transaction.Gas(), GasPrice: transaction.GasPrice().Int64(), Value: transaction.Value().String(), - Data: data, + Data: transaction.Data(), } } diff --git a/pkg/geth/converters/common/block_converter.go b/pkg/geth/converters/common/block_converter.go index 8976a164..b813223d 100644 --- a/pkg/geth/converters/common/block_converter.go +++ b/pkg/geth/converters/common/block_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,10 +17,14 @@ package common import ( + "encoding/json" + "math/big" + "strings" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/vulcanize/vulcanizedb/pkg/core" - "strings" ) type BlockConverter struct { @@ -32,7 +36,7 @@ func NewBlockConverter(transactionConverter TransactionConverter) BlockConverter } func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error) { - transactions, err := bc.transactionConverter.ConvertTransactionsToCore(gethBlock) + transactions, err := bc.transactionConverter.ConvertBlockTransactionsToCore(gethBlock) if err != nil { return core.Block{}, err } @@ -52,7 +56,35 @@ func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error) Transactions: transactions, UncleHash: gethBlock.UncleHash().Hex(), } - coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()) - coreBlock.UnclesReward = CalcUnclesReward(coreBlock, gethBlock.Uncles()) + coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()).String() + totalUncleReward, uncles := bc.ToCoreUncle(coreBlock, gethBlock.Uncles()) + + coreBlock.UnclesReward = totalUncleReward.String() + coreBlock.Uncles = uncles return coreBlock, nil } + +// Rewards for the miners of uncles is calculated as (U_n + 8 - B_n) * R / 8 +// Where U_n is the uncle block number, B_n is the parent block number and R is the static block reward at B_n +// https://github.com/ethereum/go-ethereum/issues/1591 +// https://ethereum.stackexchange.com/questions/27172/different-uncles-reward +// https://github.com/ethereum/homestead-guide/issues/399 +// Returns the total uncle reward and the individual processed uncles +func (bc BlockConverter) ToCoreUncle(block core.Block, uncles []*types.Header) (*big.Int, []core.Uncle) { + totalUncleRewards := new(big.Int) + coreUncles := make([]core.Uncle, 0, len(uncles)) + for _, uncle := range uncles { + thisUncleReward := calcUncleMinerReward(block.Number, uncle.Number.Int64()) + raw, _ := json.Marshal(uncle) + coreUncle := core.Uncle{ + Miner: uncle.Coinbase.Hex(), + Hash: uncle.Hash().Hex(), + Raw: raw, + Reward: thisUncleReward.String(), + Timestamp: uncle.Time.String(), + } + coreUncles = append(coreUncles, coreUncle) + totalUncleRewards.Add(totalUncleRewards, thisUncleReward) + } + return totalUncleRewards, coreUncles +} diff --git a/pkg/geth/converters/common/block_converter_test.go b/pkg/geth/converters/common/block_converter_test.go index 0df05be4..0c03cbc8 100644 --- a/pkg/geth/converters/common/block_converter_test.go +++ b/pkg/geth/converters/common/block_converter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package common_test import ( + "bytes" "io/ioutil" "log" "math/big" @@ -113,9 +114,13 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { blockConverter := vulcCommon.NewBlockConverter(transactionConverter) coreBlock, err := blockConverter.ToCoreBlock(block) - Expect(err).ToNot(HaveOccurred()) - Expect(vulcCommon.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(5.31355)) + + expectedBlockReward := new(big.Int) + expectedBlockReward.SetString("5313550000000000000", 10) + + blockReward := vulcCommon.CalcBlockReward(coreBlock, block.Uncles()) + Expect(blockReward.String()).To(Equal(expectedBlockReward.String())) }) It("calculates the uncles reward for a block", func() { @@ -150,9 +155,20 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { blockConverter := vulcCommon.NewBlockConverter(transactionConverter) coreBlock, err := blockConverter.ToCoreBlock(block) - Expect(err).ToNot(HaveOccurred()) - Expect(vulcCommon.CalcUnclesReward(coreBlock, block.Uncles())).To(Equal(6.875)) + + expectedTotalReward := new(big.Int) + expectedTotalReward.SetString("6875000000000000000", 10) + totalReward, coreUncles := blockConverter.ToCoreUncle(coreBlock, block.Uncles()) + Expect(totalReward.String()).To(Equal(expectedTotalReward.String())) + + Expect(len(coreUncles)).To(Equal(2)) + Expect(coreUncles[0].Reward).To(Equal("3125000000000000000")) + Expect(coreUncles[0].Miner).To(Equal("0x0000000000000000000000000000000000000000")) + Expect(coreUncles[0].Hash).To(Equal("0xb629de4014b6e30cf9555ee833f1806fa0d8b8516fde194405f9c98c2deb8772")) + Expect(coreUncles[1].Reward).To(Equal("3750000000000000000")) + Expect(coreUncles[1].Miner).To(Equal("0x0000000000000000000000000000000000000000")) + Expect(coreUncles[1].Hash).To(Equal("0x673f5231e4888a951e0bc8a25b5774b982e6e9e258362c21affaff6e02dd5a2b")) }) It("decreases the static block reward from 5 to 3 for blocks after block 4,269,999", func() { @@ -199,9 +215,12 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { blockConverter := vulcCommon.NewBlockConverter(transactionConverter) coreBlock, err := blockConverter.ToCoreBlock(block) - Expect(err).ToNot(HaveOccurred()) - Expect(vulcCommon.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(3.024990672)) + + expectedRewards := new(big.Int) + expectedRewards.SetString("3024990672000000000", 10) + rewards := vulcCommon.CalcBlockReward(coreBlock, block.Uncles()) + Expect(rewards.String()).To(Equal(expectedRewards.String())) }) }) @@ -227,6 +246,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { big.NewInt(3), hexutil.MustDecode("0xf7d8c8830000000000000000000000000000000000000000000000000000000000037788000000000000000000000000000000000000000000000000000000000003bd14"), ) + var rawTransaction bytes.Buffer + encodeErr := gethTransaction.EncodeRLP(&rawTransaction) + Expect(encodeErr).NotTo(HaveOccurred()) gethReceipt := &types.Receipt{ Bloom: types.BytesToBloom(hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")), @@ -256,16 +278,20 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { Expect(err).ToNot(HaveOccurred()) Expect(len(coreBlock.Transactions)).To(Equal(1)) coreTransaction := coreBlock.Transactions[0] - Expect(coreTransaction.Data).To(Equal("0xf7d8c8830000000000000000000000000000000000000000000000000000000000037788000000000000000000000000000000000000000000000000000000000003bd14")) + expectedData := common.FromHex("0xf7d8c8830000000000000000000000000000000000000000000000000000000000037788000000000000000000000000000000000000000000000000000000000003bd14") + Expect(coreTransaction.Data).To(Equal(expectedData)) Expect(coreTransaction.To).To(Equal(gethTransaction.To().Hex())) Expect(coreTransaction.From).To(Equal("0x0000000000000000000000000000000000000123")) Expect(coreTransaction.GasLimit).To(Equal(gethTransaction.Gas())) Expect(coreTransaction.GasPrice).To(Equal(gethTransaction.GasPrice().Int64())) + Expect(coreTransaction.Raw).To(Equal(rawTransaction.Bytes())) + Expect(coreTransaction.TxIndex).To(Equal(int64(0))) Expect(coreTransaction.Value).To(Equal(gethTransaction.Value().String())) Expect(coreTransaction.Nonce).To(Equal(gethTransaction.Nonce())) coreReceipt := coreTransaction.Receipt - expectedReceipt := vulcCommon.ToCoreReceipt(gethReceipt) + expectedReceipt, err := vulcCommon.ToCoreReceipt(gethReceipt) + Expect(err).ToNot(HaveOccurred()) Expect(coreReceipt).To(Equal(expectedReceipt)) }) @@ -304,7 +330,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { Expect(coreTransaction.To).To(Equal("")) coreReceipt := coreTransaction.Receipt - expectedReceipt := vulcCommon.ToCoreReceipt(gethReceipt) + expectedReceipt, err := vulcCommon.ToCoreReceipt(gethReceipt) + Expect(err).ToNot(HaveOccurred()) Expect(coreReceipt).To(Equal(expectedReceipt)) }) }) diff --git a/pkg/geth/converters/common/block_rewards.go b/pkg/geth/converters/common/block_rewards.go index 51c967fc..c0f6aae6 100644 --- a/pkg/geth/converters/common/block_rewards.go +++ b/pkg/geth/converters/common/block_rewards.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,54 +17,61 @@ package common import ( + "math/big" + "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" "github.com/vulcanize/vulcanizedb/pkg/core" ) -func CalcUnclesReward(block core.Block, uncles []*types.Header) float64 { - var unclesReward float64 - for _, uncle := range uncles { - blockNumber := block.Number - staticBlockReward := float64(staticRewardByBlockNumber(blockNumber)) - unclesReward += (1.0 + float64(uncle.Number.Int64()-block.Number)/8.0) * staticBlockReward - } - return unclesReward -} - -func CalcBlockReward(block core.Block, uncles []*types.Header) float64 { - blockNumber := block.Number - staticBlockReward := staticRewardByBlockNumber(blockNumber) +func CalcBlockReward(block core.Block, uncles []*types.Header) *big.Int { + staticBlockReward := staticRewardByBlockNumber(block.Number) transactionFees := calcTransactionFees(block) uncleInclusionRewards := calcUncleInclusionRewards(block, uncles) - return transactionFees + uncleInclusionRewards + staticBlockReward + tmp := transactionFees.Add(transactionFees, uncleInclusionRewards) + return tmp.Add(tmp, staticBlockReward) } -func calcTransactionFees(block core.Block) float64 { - var transactionFees float64 +func calcUncleMinerReward(blockNumber, uncleBlockNumber int64) *big.Int { + staticBlockReward := staticRewardByBlockNumber(blockNumber) + rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8)) + mainBlock := big.NewInt(blockNumber) + uncleBlock := big.NewInt(uncleBlockNumber) + uncleBlockPlus8 := uncleBlock.Add(uncleBlock, big.NewInt(8)) + uncleBlockPlus8MinusMainBlock := uncleBlockPlus8.Sub(uncleBlockPlus8, mainBlock) + return rewardDiv8.Mul(rewardDiv8, uncleBlockPlus8MinusMainBlock) +} + +func calcTransactionFees(block core.Block) *big.Int { + transactionFees := new(big.Int) for _, transaction := range block.Transactions { receipt := transaction.Receipt - transactionFees += float64(uint64(transaction.GasPrice) * receipt.GasUsed) + gasPrice := big.NewInt(transaction.GasPrice) + gasUsed := big.NewInt(int64(receipt.GasUsed)) + transactionFee := gasPrice.Mul(gasPrice, gasUsed) + transactionFees = transactionFees.Add(transactionFees, transactionFee) } - return transactionFees / params.Ether + return transactionFees } -func calcUncleInclusionRewards(block core.Block, uncles []*types.Header) float64 { - var uncleInclusionRewards float64 - staticBlockReward := staticRewardByBlockNumber(block.Number) +func calcUncleInclusionRewards(block core.Block, uncles []*types.Header) *big.Int { + uncleInclusionRewards := new(big.Int) for range uncles { - uncleInclusionRewards += staticBlockReward * 1 / 32 + staticBlockReward := staticRewardByBlockNumber(block.Number) + staticBlockReward.Div(staticBlockReward, big.NewInt(32)) + uncleInclusionRewards.Add(uncleInclusionRewards, staticBlockReward) } return uncleInclusionRewards } -func staticRewardByBlockNumber(blockNumber int64) float64 { - var staticBlockReward float64 +func staticRewardByBlockNumber(blockNumber int64) *big.Int { + staticBlockReward := new(big.Int) //https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/ - if blockNumber >= 4370000 { - staticBlockReward = 3 + if blockNumber >= 7280000 { + staticBlockReward.SetString("2000000000000000000", 10) + } else if blockNumber >= 4370000 { + staticBlockReward.SetString("3000000000000000000", 10) } else { - staticBlockReward = 5 + staticBlockReward.SetString("5000000000000000000", 10) } return staticBlockReward } diff --git a/pkg/geth/converters/common/common_suite_test.go b/pkg/geth/converters/common/common_suite_test.go index 3d8de4d8..06af9ce1 100644 --- a/pkg/geth/converters/common/common_suite_test.go +++ b/pkg/geth/converters/common/common_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/converters/common/header_converter.go b/pkg/geth/converters/common/header_converter.go index 183001c7..90d14a11 100644 --- a/pkg/geth/converters/common/header_converter.go +++ b/pkg/geth/converters/common/header_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,13 +20,12 @@ import ( "encoding/json" "github.com/ethereum/go-ethereum/core/types" - "github.com/vulcanize/vulcanizedb/pkg/core" ) type HeaderConverter struct{} -func (converter HeaderConverter) Convert(gethHeader *types.Header, blockHash string) (core.Header, error) { +func (converter HeaderConverter) Convert(gethHeader *types.Header, blockHash string) core.Header { rawHeader, err := json.Marshal(gethHeader) if err != nil { panic(err) @@ -37,5 +36,5 @@ func (converter HeaderConverter) Convert(gethHeader *types.Header, blockHash str Raw: rawHeader, Timestamp: gethHeader.Time.String(), } - return coreHeader, nil + return coreHeader } diff --git a/pkg/geth/converters/common/header_converter_test.go b/pkg/geth/converters/common/header_converter_test.go index 7eb12d83..6c939425 100644 --- a/pkg/geth/converters/common/header_converter_test.go +++ b/pkg/geth/converters/common/header_converter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -44,9 +44,8 @@ var _ = Describe("Block header converter", func() { converter := common2.HeaderConverter{} hash := fakes.FakeHash.String() - coreHeader, err := converter.Convert(gethHeader, hash) + coreHeader := converter.Convert(gethHeader, hash) - Expect(err).NotTo(HaveOccurred()) Expect(coreHeader.BlockNumber).To(Equal(gethHeader.Number.Int64())) Expect(coreHeader.Hash).To(Equal(hash)) Expect(coreHeader.Timestamp).To(Equal(gethHeader.Time.String())) @@ -56,9 +55,8 @@ var _ = Describe("Block header converter", func() { gethHeader := types.Header{Number: big.NewInt(123)} converter := common2.HeaderConverter{} - coreHeader, err := converter.Convert(&gethHeader, fakes.FakeHash.String()) + coreHeader := converter.Convert(&gethHeader, fakes.FakeHash.String()) - Expect(err).NotTo(HaveOccurred()) expectedJSON, err := json.Marshal(gethHeader) Expect(err).NotTo(HaveOccurred()) Expect(coreHeader.Raw).To(Equal(expectedJSON)) diff --git a/pkg/geth/converters/common/log_converter.go b/pkg/geth/converters/common/log_converter.go index 11dce787..8904a720 100644 --- a/pkg/geth/converters/common/log_converter.go +++ b/pkg/geth/converters/common/log_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/converters/common/log_converter_test.go b/pkg/geth/converters/common/log_converter_test.go index d382aa25..6a5505cb 100644 --- a/pkg/geth/converters/common/log_converter_test.go +++ b/pkg/geth/converters/common/log_converter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/converters/common/receipt_converter.go b/pkg/geth/converters/common/receipt_converter.go index 5d558948..50b365d3 100644 --- a/pkg/geth/converters/common/receipt_converter.go +++ b/pkg/geth/converters/common/receipt_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -26,16 +26,19 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/core" ) -func ToCoreReceipts(gethReceipts types.Receipts) []core.Receipt { +func ToCoreReceipts(gethReceipts types.Receipts) ([]core.Receipt, error) { var coreReceipts []core.Receipt for _, receipt := range gethReceipts { - coreReceipt := ToCoreReceipt(receipt) + coreReceipt, err := ToCoreReceipt(receipt) + if err != nil { + return nil, err + } coreReceipts = append(coreReceipts, coreReceipt) } - return coreReceipts + return coreReceipts, nil } -func ToCoreReceipt(gethReceipt *types.Receipt) core.Receipt { +func ToCoreReceipt(gethReceipt *types.Receipt) (core.Receipt, error) { bloom := hexutil.Encode(gethReceipt.Bloom.Bytes()) var postState string var status int @@ -43,6 +46,12 @@ func ToCoreReceipt(gethReceipt *types.Receipt) core.Receipt { logs := dereferenceLogs(gethReceipt) contractAddress := setContractAddress(gethReceipt) + rlpBuff := new(bytes.Buffer) + receiptForStorage := types.ReceiptForStorage(*gethReceipt) + err := receiptForStorage.EncodeRLP(rlpBuff) + if err != nil { + return core.Receipt{}, err + } return core.Receipt{ Bloom: bloom, ContractAddress: contractAddress, @@ -52,7 +61,8 @@ func ToCoreReceipt(gethReceipt *types.Receipt) core.Receipt { StateRoot: postState, TxHash: gethReceipt.TxHash.Hex(), Status: status, - } + Rlp: rlpBuff.Bytes(), + }, nil } func setContractAddress(gethReceipt *types.Receipt) string { diff --git a/pkg/geth/converters/common/receipt_converter_test.go b/pkg/geth/converters/common/receipt_converter_test.go index b43b6152..bd34ca33 100644 --- a/pkg/geth/converters/common/receipt_converter_test.go +++ b/pkg/geth/converters/common/receipt_converter_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package common_test import ( + "bytes" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -40,6 +41,11 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() { TxHash: common.HexToHash("0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017"), } + rlpBuff := new(bytes.Buffer) + receiptForStorage := types.ReceiptForStorage(receipt) + err := receiptForStorage.EncodeRLP(rlpBuff) + Expect(err).ToNot(HaveOccurred()) + expected := core.Receipt{ Bloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ContractAddress: "", @@ -49,9 +55,11 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() { StateRoot: "0x88abf7e73128227370aa7baa3dd4e18d0af70e92ef1f9ef426942fbe2dddb733", Status: -99, TxHash: receipt.TxHash.Hex(), + Rlp: rlpBuff.Bytes(), } - coreReceipt := vulcCommon.ToCoreReceipt(&receipt) + coreReceipt, err := vulcCommon.ToCoreReceipt(&receipt) + Expect(err).ToNot(HaveOccurred()) Expect(coreReceipt.Bloom).To(Equal(expected.Bloom)) Expect(coreReceipt.ContractAddress).To(Equal(expected.ContractAddress)) Expect(coreReceipt.CumulativeGasUsed).To(Equal(expected.CumulativeGasUsed)) @@ -60,7 +68,7 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() { Expect(coreReceipt.StateRoot).To(Equal(expected.StateRoot)) Expect(coreReceipt.Status).To(Equal(expected.Status)) Expect(coreReceipt.TxHash).To(Equal(expected.TxHash)) - + Expect(bytes.Compare(coreReceipt.Rlp, expected.Rlp)).To(Equal(0)) }) It("converts geth receipt to internal receipt format (post Byzantium has status", func() { @@ -74,6 +82,11 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() { TxHash: common.HexToHash("0xe340558980f89d5f86045ac11e5cc34e4bcec20f9f1e2a427aa39d87114e8223"), } + rlpBuff := new(bytes.Buffer) + receiptForStorage := types.ReceiptForStorage(receipt) + err := receiptForStorage.EncodeRLP(rlpBuff) + Expect(err).ToNot(HaveOccurred()) + expected := core.Receipt{ Bloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ContractAddress: receipt.ContractAddress.Hex(), @@ -83,9 +96,11 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() { StateRoot: "", Status: 1, TxHash: receipt.TxHash.Hex(), + Rlp: rlpBuff.Bytes(), } - coreReceipt := vulcCommon.ToCoreReceipt(&receipt) + coreReceipt, err := vulcCommon.ToCoreReceipt(&receipt) + Expect(err).ToNot(HaveOccurred()) Expect(coreReceipt.Bloom).To(Equal(expected.Bloom)) Expect(coreReceipt.ContractAddress).To(Equal("")) Expect(coreReceipt.CumulativeGasUsed).To(Equal(expected.CumulativeGasUsed)) @@ -94,5 +109,6 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() { Expect(coreReceipt.StateRoot).To(Equal(expected.StateRoot)) Expect(coreReceipt.Status).To(Equal(expected.Status)) Expect(coreReceipt.TxHash).To(Equal(expected.TxHash)) + Expect(bytes.Compare(coreReceipt.Rlp, expected.Rlp)).To(Equal(0)) }) }) diff --git a/pkg/geth/converters/common/transaction_converter.go b/pkg/geth/converters/common/transaction_converter.go index 320dc975..fb9584f6 100644 --- a/pkg/geth/converters/common/transaction_converter.go +++ b/pkg/geth/converters/common/transaction_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,5 +22,6 @@ import ( ) type TransactionConverter interface { - ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) + ConvertBlockTransactionsToCore(gethBlock *types.Block) ([]core.TransactionModel, error) + ConvertRpcTransactionsToModels(transactions []core.RpcTransaction) ([]core.TransactionModel, error) } diff --git a/pkg/geth/converters/rpc/rpc_suite_test.go b/pkg/geth/converters/rpc/rpc_suite_test.go new file mode 100644 index 00000000..346968fa --- /dev/null +++ b/pkg/geth/converters/rpc/rpc_suite_test.go @@ -0,0 +1,13 @@ +package rpc_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestRpc(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Rpc Suite") +} diff --git a/pkg/geth/converters/rpc/transaction_converter.go b/pkg/geth/converters/rpc/transaction_converter.go index d741f908..f1c9b238 100644 --- a/pkg/geth/converters/rpc/transaction_converter.go +++ b/pkg/geth/converters/rpc/transaction_converter.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,13 +17,17 @@ package rpc import ( + "bytes" "context" + "fmt" + "github.com/ethereum/go-ethereum/common/hexutil" "log" + "math/big" "strings" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" "golang.org/x/sync/errgroup" "github.com/vulcanize/vulcanizedb/pkg/core" @@ -34,26 +38,75 @@ type RpcTransactionConverter struct { client core.EthClient } +// raw transaction data, required for generating RLP +type transactionData struct { + AccountNonce uint64 + Price *big.Int + GasLimit uint64 + Recipient *common.Address `rlp:"nil"` // nil means contract creation + Amount *big.Int + Payload []byte + V *big.Int + R *big.Int + S *big.Int +} + func NewRpcTransactionConverter(client core.EthClient) *RpcTransactionConverter { return &RpcTransactionConverter{client: client} } -func (rtc *RpcTransactionConverter) ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) { +func (converter *RpcTransactionConverter) ConvertRpcTransactionsToModels(transactions []core.RpcTransaction) ([]core.TransactionModel, error) { + var results []core.TransactionModel + for _, transaction := range transactions { + txData, convertErr := getTransactionData(transaction) + if convertErr != nil { + return nil, convertErr + } + txRLP, rlpErr := getTransactionRLP(txData) + if rlpErr != nil { + return nil, rlpErr + } + txIndex, txIndexErr := hexToBigInt(transaction.TransactionIndex) + if txIndexErr != nil { + return nil, txIndexErr + } + transactionModel := core.TransactionModel{ + Data: txData.Payload, + From: transaction.From, + GasLimit: txData.GasLimit, + GasPrice: txData.Price.Int64(), + Hash: transaction.Hash, + Nonce: txData.AccountNonce, + Raw: txRLP, + // NOTE: Light Sync transactions don't include receipt; would require separate RPC call + To: transaction.Recipient, + TxIndex: txIndex.Int64(), + Value: txData.Amount.String(), + } + results = append(results, transactionModel) + } + return results, nil +} + +func (converter *RpcTransactionConverter) ConvertBlockTransactionsToCore(gethBlock *types.Block) ([]core.TransactionModel, error) { var g errgroup.Group - coreTransactions := make([]core.Transaction, len(gethBlock.Transactions())) + coreTransactions := make([]core.TransactionModel, len(gethBlock.Transactions())) for gethTransactionIndex, gethTransaction := range gethBlock.Transactions() { //https://golang.org/doc/faq#closures_and_goroutines transaction := gethTransaction transactionIndex := uint(gethTransactionIndex) g.Go(func() error { - from, err := rtc.client.TransactionSender(context.Background(), transaction, gethBlock.Hash(), transactionIndex) + from, err := converter.client.TransactionSender(context.Background(), transaction, gethBlock.Hash(), transactionIndex) if err != nil { log.Println("transaction sender: ", err) return err } - coreTransaction := transToCoreTrans(transaction, &from) - coreTransaction, err = rtc.appendReceiptToTransaction(coreTransaction) + coreTransaction, convertErr := convertGethTransactionToModel(transaction, &from, int64(gethTransactionIndex)) + if convertErr != nil { + return convertErr + } + coreTransaction, err = converter.appendReceiptToTransaction(coreTransaction) if err != nil { log.Println("receipt: ", err) return err @@ -69,28 +122,89 @@ func (rtc *RpcTransactionConverter) ConvertTransactionsToCore(gethBlock *types.B return coreTransactions, nil } -func (rtc *RpcTransactionConverter) appendReceiptToTransaction(transaction core.Transaction) (core.Transaction, error) { +func (rtc *RpcTransactionConverter) appendReceiptToTransaction(transaction core.TransactionModel) (core.TransactionModel, error) { gethReceipt, err := rtc.client.TransactionReceipt(context.Background(), common.HexToHash(transaction.Hash)) if err != nil { return transaction, err } - receipt := vulcCommon.ToCoreReceipt(gethReceipt) + receipt, err := vulcCommon.ToCoreReceipt(gethReceipt) + if err != nil { + return transaction, err + } transaction.Receipt = receipt return transaction, nil } -func transToCoreTrans(transaction *types.Transaction, from *common.Address) core.Transaction { - data := hexutil.Encode(transaction.Data()) - return core.Transaction{ - Hash: transaction.Hash().Hex(), - Nonce: transaction.Nonce(), - To: strings.ToLower(addressToHex(transaction.To())), +func convertGethTransactionToModel(transaction *types.Transaction, from *common.Address, transactionIndex int64) (core.TransactionModel, error) { + raw := bytes.Buffer{} + encodeErr := transaction.EncodeRLP(&raw) + if encodeErr != nil { + return core.TransactionModel{}, encodeErr + } + return core.TransactionModel{ + Data: transaction.Data(), From: strings.ToLower(addressToHex(from)), GasLimit: transaction.Gas(), GasPrice: transaction.GasPrice().Int64(), + Hash: transaction.Hash().Hex(), + Nonce: transaction.Nonce(), + Raw: raw.Bytes(), + To: strings.ToLower(addressToHex(transaction.To())), + TxIndex: transactionIndex, Value: transaction.Value().String(), - Data: data, + }, nil +} + +func getTransactionData(transaction core.RpcTransaction) (transactionData, error) { + nonce, nonceErr := hexToBigInt(transaction.Nonce) + if nonceErr != nil { + return transactionData{}, nonceErr } + gasPrice, gasPriceErr := hexToBigInt(transaction.GasPrice) + if gasPriceErr != nil { + return transactionData{}, gasPriceErr + } + gasLimit, gasLimitErr := hexToBigInt(transaction.GasLimit) + if gasLimitErr != nil { + return transactionData{}, gasLimitErr + } + recipient := common.HexToAddress(transaction.Recipient) + amount, amountErr := hexToBigInt(transaction.Amount) + if amountErr != nil { + return transactionData{}, amountErr + } + v, vErr := hexToBigInt(transaction.V) + if vErr != nil { + return transactionData{}, vErr + } + r, rErr := hexToBigInt(transaction.R) + if rErr != nil { + return transactionData{}, rErr + } + s, sErr := hexToBigInt(transaction.S) + if sErr != nil { + return transactionData{}, sErr + } + return transactionData{ + AccountNonce: nonce.Uint64(), + Price: gasPrice, + GasLimit: gasLimit.Uint64(), + Recipient: &recipient, + Amount: amount, + Payload: hexutil.MustDecode(transaction.Payload), + V: v, + R: r, + S: s, + }, nil +} + +func getTransactionRLP(txData transactionData) ([]byte, error) { + transactionRlp := bytes.Buffer{} + encodeErr := rlp.Encode(&transactionRlp, txData) + if encodeErr != nil { + return nil, encodeErr + } + return transactionRlp.Bytes(), nil } func addressToHex(to *common.Address) string { @@ -99,3 +213,12 @@ func addressToHex(to *common.Address) string { } return to.Hex() } + +func hexToBigInt(hex string) (*big.Int, error) { + result := big.NewInt(0) + _, scanErr := fmt.Sscan(hex, result) + if scanErr != nil { + return nil, scanErr + } + return result, nil +} diff --git a/pkg/geth/converters/rpc/transaction_converter_test.go b/pkg/geth/converters/rpc/transaction_converter_test.go new file mode 100644 index 00000000..21047c92 --- /dev/null +++ b/pkg/geth/converters/rpc/transaction_converter_test.go @@ -0,0 +1,108 @@ +package rpc_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" + "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" +) + +var _ = Describe("RPC transaction converter", func() { + var converter rpc.RpcTransactionConverter + + BeforeEach(func() { + converter = rpc.RpcTransactionConverter{} + }) + + It("converts hex fields to integers", func() { + rpcTransaction := getFakeRpcTransaction("0x1") + + transactionModels, err := converter.ConvertRpcTransactionsToModels([]core.RpcTransaction{rpcTransaction}) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(transactionModels)).To(Equal(1)) + Expect(transactionModels[0].GasLimit).To(Equal(uint64(1))) + Expect(transactionModels[0].GasPrice).To(Equal(int64(1))) + Expect(transactionModels[0].Nonce).To(Equal(uint64(1))) + Expect(transactionModels[0].TxIndex).To(Equal(int64(1))) + Expect(transactionModels[0].Value).To(Equal("1")) + }) + + It("returns error if invalid hex cannot be converted", func() { + invalidTransaction := getFakeRpcTransaction("invalid") + + _, err := converter.ConvertRpcTransactionsToModels([]core.RpcTransaction{invalidTransaction}) + + Expect(err).To(HaveOccurred()) + }) + + It("copies RPC transaction hash, from, and to values to model", func() { + rpcTransaction := getFakeRpcTransaction("0x1") + + transactionModels, err := converter.ConvertRpcTransactionsToModels([]core.RpcTransaction{rpcTransaction}) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(transactionModels)).To(Equal(1)) + Expect(transactionModels[0].Hash).To(Equal(rpcTransaction.Hash)) + Expect(transactionModels[0].From).To(Equal(rpcTransaction.From)) + Expect(transactionModels[0].To).To(Equal(rpcTransaction.Recipient)) + }) + + It("derives transaction RLP", func() { + // actual transaction: https://kovan.etherscan.io/tx/0x3b29ef265425d304069c57e5145cd1c7558568b06d231775f50a693bee1aad4f + rpcTransaction := core.RpcTransaction{ + Nonce: "0x7aa9", + GasPrice: "0x3b9aca00", + GasLimit: "0x7a120", + Recipient: "0xf88bbdc1e2718f8857f30a180076ec38d53cf296", + Amount: "0x0", + Payload: "0x18178358", + V: "0x78", + R: "0x79f6a78ababfdb37b87a4d52795a49b08b5b5171443d1f2fb8f373431e77439c", + S: "0x3f1a210dd3b59d161735a314b88568fa91552dfe207c00a2fdbcd52ccb081409", + Hash: "0x3b29ef265425d304069c57e5145cd1c7558568b06d231775f50a693bee1aad4f", + From: "0x694032e172d9b0ee6aff5d36749bad4947a36e4e", + TransactionIndex: "0xa", + } + + transactionModels, err := converter.ConvertRpcTransactionsToModels([]core.RpcTransaction{rpcTransaction}) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(transactionModels)).To(Equal(1)) + model := transactionModels[0] + expectedRLP := []byte{248, 106, 130, 122, 169, 132, 59, 154, 202, 0, 131, 7, 161, 32, 148, 248, 139, 189, 193, + 226, 113, 143, 136, 87, 243, 10, 24, 0, 118, 236, 56, 213, 60, 242, 150, 128, 132, 24, 23, 131, 88, 120, 160, + 121, 246, 167, 138, 186, 191, 219, 55, 184, 122, 77, 82, 121, 90, 73, 176, 139, 91, 81, 113, 68, 61, 31, 47, + 184, 243, 115, 67, 30, 119, 67, 156, 160, 63, 26, 33, 13, 211, 181, 157, 22, 23, 53, 163, 20, 184, 133, 104, + 250, 145, 85, 45, 254, 32, 124, 0, 162, 253, 188, 213, 44, 203, 8, 20, 9} + Expect(model.Raw).To(Equal(expectedRLP)) + }) + + It("does not include transaction receipt", func() { + rpcTransaction := getFakeRpcTransaction("0x1") + + transactionModels, err := converter.ConvertRpcTransactionsToModels([]core.RpcTransaction{rpcTransaction}) + + Expect(err).NotTo(HaveOccurred()) + Expect(len(transactionModels)).To(Equal(1)) + Expect(transactionModels[0].Receipt).To(Equal(core.Receipt{})) + }) +}) + +func getFakeRpcTransaction(hex string) core.RpcTransaction { + return core.RpcTransaction{ + Hash: "0x2", + Amount: hex, + GasLimit: hex, + GasPrice: hex, + Nonce: hex, + From: fakes.FakeAddress.Hex(), + Recipient: fakes.FakeAddress.Hex(), + V: "0x2", + R: "0x2", + S: "0x2", + Payload: "0x12", + TransactionIndex: hex, + } +} diff --git a/pkg/geth/geth_suite_test.go b/pkg/geth/geth_suite_test.go index c4078ffc..1a151480 100644 --- a/pkg/geth/geth_suite_test.go +++ b/pkg/geth/geth_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/node/node.go b/pkg/geth/node/node.go index 7c276097..7fa6a087 100644 --- a/pkg/geth/node/node.go +++ b/pkg/geth/node/node.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/node/node_suite_test.go b/pkg/geth/node/node_suite_test.go index 27139341..38ca2516 100644 --- a/pkg/geth/node/node_suite_test.go +++ b/pkg/geth/node/node_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/node/node_test.go b/pkg/geth/node/node_test.go index 58ad5ca9..8a74a441 100644 --- a/pkg/geth/node/node_test.go +++ b/pkg/geth/node/node_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by diff --git a/pkg/geth/testing/helpers.go b/pkg/geth/testing/helpers.go index 145f8fd7..70929e40 100644 --- a/pkg/geth/testing/helpers.go +++ b/pkg/geth/testing/helpers.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,7 +17,7 @@ package testing import ( - "log" + log "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/geth" diff --git a/pkg/history/block_validator.go b/pkg/history/block_validator.go index 6f7791a2..d7b41a8d 100644 --- a/pkg/history/block_validator.go +++ b/pkg/history/block_validator.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package history import ( + "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" ) @@ -35,11 +36,30 @@ func NewBlockValidator(blockchain core.BlockChain, blockRepository datastore.Blo } } -func (bv BlockValidator) ValidateBlocks() ValidationWindow { - window := MakeValidationWindow(bv.blockchain, bv.windowSize) +func (bv BlockValidator) ValidateBlocks() (ValidationWindow, error) { + window, err := MakeValidationWindow(bv.blockchain, bv.windowSize) + if err != nil { + logrus.Error("ValidateBlocks: error creating validation window: ", err) + return ValidationWindow{}, err + } + blockNumbers := MakeRange(window.LowerBound, window.UpperBound) - RetrieveAndUpdateBlocks(bv.blockchain, bv.blockRepository, blockNumbers) - lastBlock := bv.blockchain.LastBlock().Int64() - bv.blockRepository.SetBlocksStatus(lastBlock) - return window + _, err = RetrieveAndUpdateBlocks(bv.blockchain, bv.blockRepository, blockNumbers) + if err != nil { + logrus.Error("ValidateBlocks: error getting and updating blocks: ", err) + return ValidationWindow{}, err + } + + lastBlock, err := bv.blockchain.LastBlock() + if err != nil { + logrus.Error("ValidateBlocks: error getting last block: ", err) + return ValidationWindow{}, err + } + + err = bv.blockRepository.SetBlocksStatus(lastBlock.Int64()) + if err != nil { + logrus.Error("ValidateBlocks: error setting block status: ", err) + return ValidationWindow{}, err + } + return window, nil } diff --git a/pkg/history/block_validator_test.go b/pkg/history/block_validator_test.go index a98fad1a..6548fc2d 100644 --- a/pkg/history/block_validator_test.go +++ b/pkg/history/block_validator_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,12 +17,13 @@ package history_test import ( + "math/big" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" - "math/big" ) var _ = Describe("Blocks validator", func() { @@ -33,7 +34,8 @@ var _ = Describe("Blocks validator", func() { blocksRepository := fakes.NewMockBlockRepository() validator := history.NewBlockValidator(blockChain, blocksRepository, 2) - window := validator.ValidateBlocks() + window, err := validator.ValidateBlocks() + Expect(err).NotTo(HaveOccurred()) Expect(window).To(Equal(history.ValidationWindow{LowerBound: 5, UpperBound: 7})) blocksRepository.AssertCreateOrUpdateBlockCallCountEquals(3) @@ -42,7 +44,7 @@ var _ = Describe("Blocks validator", func() { It("returns the number of largest block", func() { blockChain := fakes.NewMockBlockChain() blockChain.SetLastBlock(big.NewInt(3)) - maxBlockNumber := blockChain.LastBlock() + maxBlockNumber, _ := blockChain.LastBlock() Expect(maxBlockNumber.Int64()).To(Equal(int64(3))) }) diff --git a/pkg/history/header_validator.go b/pkg/history/header_validator.go index 23e8ceb0..5065f65c 100644 --- a/pkg/history/header_validator.go +++ b/pkg/history/header_validator.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,6 +17,7 @@ package history import ( + "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" ) @@ -35,9 +36,17 @@ func NewHeaderValidator(blockChain core.BlockChain, repository datastore.HeaderR } } -func (validator HeaderValidator) ValidateHeaders() ValidationWindow { - window := MakeValidationWindow(validator.blockChain, validator.windowSize) +func (validator HeaderValidator) ValidateHeaders() (ValidationWindow, error) { + window, err := MakeValidationWindow(validator.blockChain, validator.windowSize) + if err != nil { + logrus.Error("ValidateHeaders: error creating validation window: ", err) + return ValidationWindow{}, err + } blockNumbers := MakeRange(window.LowerBound, window.UpperBound) - RetrieveAndUpdateHeaders(validator.blockChain, validator.headerRepository, blockNumbers) - return window + _, err = RetrieveAndUpdateHeaders(validator.blockChain, validator.headerRepository, blockNumbers) + if err != nil { + logrus.Error("ValidateHeaders: error getting/updating headers: ", err) + return ValidationWindow{}, err + } + return window, nil } diff --git a/pkg/history/header_validator_test.go b/pkg/history/header_validator_test.go index 3aaef365..b77d50cf 100644 --- a/pkg/history/header_validator_test.go +++ b/pkg/history/header_validator_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,22 +17,45 @@ package history_test import ( + "errors" + "math/big" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" - "math/big" ) var _ = Describe("Header validator", func() { + var ( + headerRepository *fakes.MockHeaderRepository + blockChain *fakes.MockBlockChain + ) + + BeforeEach(func() { + headerRepository = fakes.NewMockHeaderRepository() + blockChain = fakes.NewMockBlockChain() + }) + It("attempts to create every header in the validation window", func() { - headerRepository := fakes.NewMockHeaderRepository() headerRepository.SetMissingBlockNumbers([]int64{}) - blockChain := fakes.NewMockBlockChain() blockChain.SetLastBlock(big.NewInt(3)) validator := history.NewHeaderValidator(blockChain, headerRepository, 2) - validator.ValidateHeaders() + _, err := validator.ValidateHeaders() + Expect(err).NotTo(HaveOccurred()) headerRepository.AssertCreateOrUpdateHeaderCallCountAndPassedBlockNumbers(3, []int64{1, 2, 3}) }) + + It("propagates header repository errors", func() { + blockChain.SetLastBlock(big.NewInt(3)) + headerRepositoryError := errors.New("CreateOrUpdate") + headerRepository.SetCreateOrUpdateHeaderReturnErr(headerRepositoryError) + validator := history.NewHeaderValidator(blockChain, headerRepository, 2) + + _, err := validator.ValidateHeaders() + Expect(err).To(MatchError(headerRepositoryError)) + }) }) diff --git a/pkg/history/history_suite_test.go b/pkg/history/history_suite_test.go index 0e8706da..99cd6951 100644 --- a/pkg/history/history_suite_test.go +++ b/pkg/history/history_suite_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,8 +20,8 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" "io/ioutil" - "log" "testing" ) diff --git a/pkg/history/populate_blocks.go b/pkg/history/populate_blocks.go index 1f7806c1..a2c542d0 100644 --- a/pkg/history/populate_blocks.go +++ b/pkg/history/populate_blocks.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,30 +17,47 @@ package history import ( - "log" + log "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" ) -func PopulateMissingBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, startingBlockNumber int64) int { - lastBlock := blockchain.LastBlock().Int64() - blockRange := blockRepository.MissingBlockNumbers(startingBlockNumber, lastBlock, blockchain.Node().ID) - log.SetPrefix("") +func PopulateMissingBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, startingBlockNumber int64) (int, error) { + lastBlock, err := blockchain.LastBlock() + if err != nil { + log.Error("PopulateMissingBlocks: error getting last block: ", err) + return 0, err + } + blockRange := blockRepository.MissingBlockNumbers(startingBlockNumber, lastBlock.Int64(), blockchain.Node().ID) + + if len(blockRange) == 0 { + return 0, nil + } + log.Printf("Backfilling %d blocks\n\n", len(blockRange)) - RetrieveAndUpdateBlocks(blockchain, blockRepository, blockRange) - return len(blockRange) + _, err = RetrieveAndUpdateBlocks(blockchain, blockRepository, blockRange) + if err != nil { + log.Error("PopulateMissingBlocks: error gettings/updating blocks: ", err) + return 0, err + } + return len(blockRange), nil } -func RetrieveAndUpdateBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, blockNumbers []int64) int { +func RetrieveAndUpdateBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, blockNumbers []int64) (int, error) { for _, blockNumber := range blockNumbers { block, err := blockchain.GetBlockByNumber(blockNumber) if err != nil { - log.Printf("failed to retrieve block number: %d\n", blockNumber) - return 0 + log.Error("RetrieveAndUpdateBlocks: error getting block: ", err) + return 0, err } - // TODO: handle possible error here - blockRepository.CreateOrUpdateBlock(block) + + _, err = blockRepository.CreateOrUpdateBlock(block) + if err != nil { + log.Error("RetrieveAndUpdateBlocks: error creating/updating block: ", err) + return 0, err + } + } - return len(blockNumbers) + return len(blockNumbers), nil } diff --git a/pkg/history/populate_blocks_test.go b/pkg/history/populate_blocks_test.go index 5ff67a13..6a5138ed 100644 --- a/pkg/history/populate_blocks_test.go +++ b/pkg/history/populate_blocks_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -36,8 +36,9 @@ var _ = Describe("Populating blocks", func() { blockChain.SetLastBlock(big.NewInt(2)) blockRepository.SetMissingBlockNumbersReturnArray([]int64{2}) - blocksAdded := history.PopulateMissingBlocks(blockChain, blockRepository, 1) - _, err := blockRepository.GetBlock(1) + blocksAdded, err := history.PopulateMissingBlocks(blockChain, blockRepository, 1) + Expect(err).NotTo(HaveOccurred()) + _, err = blockRepository.GetBlock(1) Expect(blocksAdded).To(Equal(1)) Expect(err).ToNot(HaveOccurred()) @@ -48,8 +49,9 @@ var _ = Describe("Populating blocks", func() { blockChain.SetLastBlock(big.NewInt(13)) blockRepository.SetMissingBlockNumbersReturnArray([]int64{5, 8, 10}) - blocksAdded := history.PopulateMissingBlocks(blockChain, blockRepository, 5) + blocksAdded, err := history.PopulateMissingBlocks(blockChain, blockRepository, 5) + Expect(err).NotTo(HaveOccurred()) Expect(blocksAdded).To(Equal(3)) blockRepository.AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(3, []int64{5, 8, 10}) }) @@ -59,16 +61,18 @@ var _ = Describe("Populating blocks", func() { blockChain.SetLastBlock(big.NewInt(6)) blockRepository.SetMissingBlockNumbersReturnArray([]int64{4, 5}) - numberOfBlocksCreated := history.PopulateMissingBlocks(blockChain, blockRepository, 3) + numberOfBlocksCreated, err := history.PopulateMissingBlocks(blockChain, blockRepository, 3) + Expect(err).NotTo(HaveOccurred()) Expect(numberOfBlocksCreated).To(Equal(2)) }) It("updates the repository with a range of blocks w/in the range ", func() { blockChain := fakes.NewMockBlockChain() - history.RetrieveAndUpdateBlocks(blockChain, blockRepository, history.MakeRange(2, 5)) + _, err := history.RetrieveAndUpdateBlocks(blockChain, blockRepository, history.MakeRange(2, 5)) + Expect(err).NotTo(HaveOccurred()) blockRepository.AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(4, []int64{2, 3, 4, 5}) }) @@ -77,8 +81,9 @@ var _ = Describe("Populating blocks", func() { blockChain.SetGetBlockByNumberErr(fakes.FakeError) blocks := history.MakeRange(1, 10) - history.RetrieveAndUpdateBlocks(blockChain, blockRepository, blocks) + _, err := history.RetrieveAndUpdateBlocks(blockChain, blockRepository, blocks) + Expect(err).To(HaveOccurred()) blockRepository.AssertCreateOrUpdateBlockCallCountEquals(0) }) }) diff --git a/pkg/history/populate_headers.go b/pkg/history/populate_headers.go index 7ca500be..e545fd23 100644 --- a/pkg/history/populate_headers.go +++ b/pkg/history/populate_headers.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,7 +17,7 @@ package history import ( - "log" + log "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" @@ -25,23 +25,32 @@ import ( ) func PopulateMissingHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, startingBlockNumber int64) (int, error) { - lastBlock := blockchain.LastBlock().Int64() - blockRange := headerRepository.MissingBlockNumbers(startingBlockNumber, lastBlock, blockchain.Node().ID) - log.SetPrefix("") - log.Printf("Backfilling %d blocks\n\n", len(blockRange)) - _, err := RetrieveAndUpdateHeaders(blockchain, headerRepository, blockRange) + lastBlock, err := blockchain.LastBlock() if err != nil { + log.Error("PopulateMissingHeaders: Error getting last block: ", err) return 0, err } - return len(blockRange), nil + + blockNumbers, err := headerRepository.MissingBlockNumbers(startingBlockNumber, lastBlock.Int64(), blockchain.Node().ID) + if err != nil { + log.Error("PopulateMissingHeaders: Error getting missing block numbers: ", err) + return 0, err + } else if len(blockNumbers) == 0 { + return 0, nil + } + + log.Printf("Backfilling %d blocks\n\n", len(blockNumbers)) + _, err = RetrieveAndUpdateHeaders(blockchain, headerRepository, blockNumbers) + if err != nil { + log.Error("PopulateMissingHeaders: Error getting/updating headers:", err) + return 0, err + } + return len(blockNumbers), nil } func RetrieveAndUpdateHeaders(chain core.BlockChain, headerRepository datastore.HeaderRepository, blockNumbers []int64) (int, error) { - for _, blockNumber := range blockNumbers { - header, err := chain.GetHeaderByNumber(blockNumber) - if err != nil { - return 0, err - } + headers, err := chain.GetHeaderByNumbers(blockNumbers) + for _, header := range headers { _, err = headerRepository.CreateOrUpdateHeader(header) if err != nil { if err == repositories.ErrValidHeaderExists { diff --git a/pkg/history/populate_headers_test.go b/pkg/history/populate_headers_test.go index 84485108..2a5fa37c 100644 --- a/pkg/history/populate_headers_test.go +++ b/pkg/history/populate_headers_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -55,4 +55,13 @@ var _ = Describe("Populating headers", func() { Expect(err).NotTo(HaveOccurred()) headerRepository.AssertCreateOrUpdateHeaderCallCountAndPassedBlockNumbers(1, []int64{2}) }) + + It("returns early if the db is already synced up to the head of the chain", func() { + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(2)) + headersAdded, err := history.PopulateMissingHeaders(blockChain, headerRepository, 2) + + Expect(err).NotTo(HaveOccurred()) + Expect(headersAdded).To(Equal(0)) + }) }) diff --git a/pkg/history/validation_window.go b/pkg/history/validation_window.go index fb843907..24ae5ff0 100644 --- a/pkg/history/validation_window.go +++ b/pkg/history/validation_window.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,18 +17,11 @@ package history import ( + "fmt" + log "github.com/sirupsen/logrus" "github.com/vulcanize/vulcanizedb/pkg/core" - "io" - "text/template" ) -const WindowTemplate = `Validating Blocks -|{{.LowerBound}}|-- Validation Window --|{{.UpperBound}}| ({{.UpperBound}}:HEAD) - -` - -var ParsedWindowTemplate = *template.Must(template.New("window").Parse(WindowTemplate)) - type ValidationWindow struct { LowerBound int64 UpperBound int64 @@ -38,10 +31,14 @@ func (window ValidationWindow) Size() int { return int(window.UpperBound - window.LowerBound) } -func MakeValidationWindow(blockchain core.BlockChain, windowSize int) ValidationWindow { - upperBound := blockchain.LastBlock().Int64() - lowerBound := upperBound - int64(windowSize) - return ValidationWindow{lowerBound, upperBound} +func MakeValidationWindow(blockchain core.BlockChain, windowSize int) (ValidationWindow, error) { + upperBound, err := blockchain.LastBlock() + if err != nil { + log.Error("MakeValidationWindow: error getting LastBlock: ", err) + return ValidationWindow{}, err + } + lowerBound := upperBound.Int64() - int64(windowSize) + return ValidationWindow{lowerBound, upperBound.Int64()}, nil } func MakeRange(min, max int64) []int64 { @@ -52,6 +49,7 @@ func MakeRange(min, max int64) []int64 { return a } -func (window ValidationWindow) Log(out io.Writer) { - ParsedWindowTemplate.Execute(out, window) +func (window ValidationWindow) GetString() string { + return fmt.Sprintf("Validating Blocks |%v|-- Validation Window --|%v}|", + window.LowerBound, window.UpperBound) } diff --git a/pkg/history/validation_window_test.go b/pkg/history/validation_window_test.go index 55434f34..86e45c66 100644 --- a/pkg/history/validation_window_test.go +++ b/pkg/history/validation_window_test.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,6 @@ package history_test import ( - "bytes" - . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -32,8 +30,9 @@ var _ = Describe("Validation window", func() { blockChain := fakes.NewMockBlockChain() blockChain.SetLastBlock(big.NewInt(5)) - validationWindow := history.MakeValidationWindow(blockChain, 2) + validationWindow, err := history.MakeValidationWindow(blockChain, 2) + Expect(err).NotTo(HaveOccurred()) Expect(validationWindow.LowerBound).To(Equal(int64(3))) Expect(validationWindow.UpperBound).To(Equal(int64(5))) }) @@ -50,15 +49,4 @@ var _ = Describe("Validation window", func() { Expect(numberOfBlocksCreated).To(Equal(expected)) }) - - It("logs window message", func() { - expectedMessage := &bytes.Buffer{} - window := history.ValidationWindow{LowerBound: 5, UpperBound: 7} - history.ParsedWindowTemplate.Execute(expectedMessage, window) - actualMessage := &bytes.Buffer{} - - window.Log(actualMessage) - - Expect(actualMessage).To(Equal(expectedMessage)) - }) }) diff --git a/pkg/omni/full/transformer/transformer.go b/pkg/omni/full/transformer/transformer.go deleted file mode 100644 index 5c8a4337..00000000 --- a/pkg/omni/full/transformer/transformer.go +++ /dev/null @@ -1,271 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package transformer - -import ( - "errors" - "strings" - - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "github.com/vulcanize/vulcanizedb/pkg/omni/full/converter" - "github.com/vulcanize/vulcanizedb/pkg/omni/full/retriever" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository" - "github.com/vulcanize/vulcanizedb/pkg/omni/shared/types" -) - -// Requires a fully synced vDB and a running eth node (or infura) -type transformer struct { - // Database interfaces - datastore.FilterRepository // Log filters repo; accepts filters generated by Contract.GenerateFilters() - datastore.WatchedEventRepository // Watched event log views, created by the log filters - repository.EventRepository // Holds transformed watched event log data - - // Pre-processing interfaces - parser.Parser // Parses events and methods out of contract abi fetched using contract address - retriever.BlockRetriever // Retrieves first block for contract and current block height - - // Processing interfaces - converter.Converter // Converts watched event logs into custom log - poller.Poller // Polls methods using contract's token holder addresses and persists them using method datastore - - // Ethereum network name; default "" is mainnet - Network string - - // Store contract info as mapping to contract address - Contracts map[string]*contract.Contract - - // Targeted subset of events/methods - // Stored as map sof contract address to events/method names of interest - WatchedEvents map[string][]string // Default/empty event list means all are watched - WantedMethods map[string][]string // Default/empty method list means none are polled - - // Starting block for contracts - ContractStart map[string]int64 - - // Lists of addresses to filter event or method data - // before persisting; if empty no filter is applied - EventArgs map[string][]string - MethodArgs map[string][]string - - // Whether or not to create a list of emitted address or hashes for the contract in postgres - CreateAddrList map[string]bool - CreateHashList map[string]bool - - // Method piping on/off for a contract - Piping map[string]bool -} - -// Transformer takes in config for blockchain, database, and network id -func NewTransformer(network string, BC core.BlockChain, DB *postgres.DB) *transformer { - return &transformer{ - Poller: poller.NewPoller(BC, DB, types.FullSync), - Parser: parser.NewParser(network), - BlockRetriever: retriever.NewBlockRetriever(DB), - Converter: converter.NewConverter(&contract.Contract{}), - Contracts: map[string]*contract.Contract{}, - WatchedEventRepository: repositories.WatchedEventRepository{DB: DB}, - FilterRepository: repositories.FilterRepository{DB: DB}, - EventRepository: repository.NewEventRepository(DB, types.FullSync), - WatchedEvents: map[string][]string{}, - WantedMethods: map[string][]string{}, - ContractStart: map[string]int64{}, - EventArgs: map[string][]string{}, - MethodArgs: map[string][]string{}, - CreateAddrList: map[string]bool{}, - CreateHashList: map[string]bool{}, - Piping: map[string]bool{}, - } -} - -// Use after creating and setting transformer -// Loops over all of the addr => filter sets -// Uses parser to pull event info from abi -// Use this info to generate event filters -func (t *transformer) Init() error { - for contractAddr, subset := range t.WatchedEvents { - // Get Abi - err := t.Parser.Parse(contractAddr) - if err != nil { - return err - } - - // Get first block and most recent block number in the header repo - firstBlock, err := t.BlockRetriever.RetrieveFirstBlock(contractAddr) - if err != nil { - return err - } - lastBlock, err := t.BlockRetriever.RetrieveMostRecentBlock() - if err != nil { - return err - } - - // Set to specified range if it falls within the bounds - if firstBlock < t.ContractStart[contractAddr] { - firstBlock = t.ContractStart[contractAddr] - } - - // Get contract name if it has one - var name = new(string) - t.FetchContractData(t.Abi(), contractAddr, "name", nil, &name, lastBlock) - - // Remove any potential accidental duplicate inputs in arg filter values - eventArgs := map[string]bool{} - for _, arg := range t.EventArgs[contractAddr] { - eventArgs[arg] = true - } - methodArgs := map[string]bool{} - for _, arg := range t.MethodArgs[contractAddr] { - methodArgs[arg] = true - } - - // Aggregate info into contract object - info := contract.Contract{ - Name: *name, - Network: t.Network, - Address: contractAddr, - Abi: t.Parser.Abi(), - ParsedAbi: t.Parser.ParsedAbi(), - StartingBlock: firstBlock, - LastBlock: lastBlock, - Events: t.Parser.GetEvents(subset), - Methods: t.Parser.GetSelectMethods(t.WantedMethods[contractAddr]), - FilterArgs: eventArgs, - MethodArgs: methodArgs, - CreateAddrList: t.CreateAddrList[contractAddr], - CreateHashList: t.CreateHashList[contractAddr], - Piping: t.Piping[contractAddr], - }.Init() - - // Use info to create filters - err = info.GenerateFilters() - if err != nil { - return err - } - - // Iterate over filters and push them to the repo using filter repository interface - for _, filter := range info.Filters { - err = t.CreateFilter(filter) - if err != nil { - return err - } - } - - // Store contract info for further processing - t.Contracts[contractAddr] = info - } - - return nil -} - -// Iterates through stored, initialized contract objects -// Iterates through contract's event filters, grabbing watched event logs -// Uses converter to convert logs into custom log type -// Persists converted logs into custuom postgres tables -// Calls selected methods, using token holder address generated during event log conversion -func (tr transformer) Execute() error { - if len(tr.Contracts) == 0 { - return errors.New("error: transformer has no initialized contracts to work with") - } - // Iterate through all internal contracts - for _, con := range tr.Contracts { - // Update converter with current contract - tr.Update(con) - - // Iterate through contract filters and get watched event logs - for eventSig, filter := range con.Filters { - watchedEvents, err := tr.GetWatchedEvents(filter.Name) - if err != nil { - return err - } - - // Iterate over watched event logs - for _, we := range watchedEvents { - // Convert them to our custom log type - cstm, err := tr.Converter.Convert(*we, con.Events[eventSig]) - if err != nil { - return err - } - if cstm == nil { - continue - } - - // If log is not empty, immediately persist in repo - // Run this in seperate goroutine? - err = tr.PersistLogs([]types.Log{*cstm}, con.Events[eventSig], con.Address, con.Name) - if err != nil { - return err - } - } - } - - // After persisting all watched event logs - // poller polls select contract methods - // and persists the results into custom pg tables - // Run this in seperate goroutine? - if err := tr.PollContract(*con); err != nil { - return err - } - } - - return nil -} - -// Used to set which contract addresses and which of their events to watch -func (tr *transformer) SetEvents(contractAddr string, filterSet []string) { - tr.WatchedEvents[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set subset of account addresses to watch events for -func (tr *transformer) SetEventArgs(contractAddr string, filterSet []string) { - tr.EventArgs[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set which contract addresses and which of their methods to call -func (tr *transformer) SetMethods(contractAddr string, filterSet []string) { - tr.WantedMethods[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set subset of account addresses to poll methods on -func (tr *transformer) SetMethodArgs(contractAddr string, filterSet []string) { - tr.MethodArgs[strings.ToLower(contractAddr)] = filterSet -} - -// Used to set the block range to watch for a given address -func (tr *transformer) SetStartingBlock(contractAddr string, start int64) { - tr.ContractStart[strings.ToLower(contractAddr)] = start -} - -// Used to set whether or not to persist an account address list -func (tr *transformer) SetCreateAddrList(contractAddr string, on bool) { - tr.CreateAddrList[strings.ToLower(contractAddr)] = on -} - -// Used to set whether or not to persist an hash list -func (tr *transformer) SetCreateHashList(contractAddr string, on bool) { - tr.CreateHashList[strings.ToLower(contractAddr)] = on -} - -// Used to turn method piping on for a contract -func (tr *transformer) SetPiping(contractAddr string, on bool) { - tr.Piping[strings.ToLower(contractAddr)] = on -} diff --git a/pkg/omni/shared/transformer/interface.go b/pkg/omni/shared/transformer/interface.go deleted file mode 100644 index 42a241df..00000000 --- a/pkg/omni/shared/transformer/interface.go +++ /dev/null @@ -1,32 +0,0 @@ -// VulcanizeDB -// Copyright © 2018 Vulcanize - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package transformer - -// Used to extract any/all events and a subset of method (state variable) -// data for any contract and persists it to custom postgres tables in vDB -type Transformer interface { - SetEvents(contractAddr string, filterSet []string) - SetEventArgs(contractAddr string, filterSet []string) - SetMethods(contractAddr string, filterSet []string) - SetMethodArgs(contractAddr string, filterSet []string) - SetStartingBlock(contractAddr string, start int64) - SetCreateAddrList(contractAddr string, on bool) - SetCreateHashList(contractAddr string, on bool) - SetPiping(contractAddr string, on bool) - Init() error - Execute() error -} diff --git a/pkg/plugin/builder/builder.go b/pkg/plugin/builder/builder.go new file mode 100644 index 00000000..f126a9dc --- /dev/null +++ b/pkg/plugin/builder/builder.go @@ -0,0 +1,132 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package builder + +import ( + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/plugin/helpers" +) + +// Interface for compile Go code written by the +// PluginWriter into a shared object (.so file) +// which can be used loaded as a plugin +type PluginBuilder interface { + BuildPlugin() error + CleanUp() error +} + +type builder struct { + GenConfig config.Plugin + dependencies []string + tmpVenDirs []string // Keep track of temp vendor directories + goFile string // Keep track of goFile name +} + +// Requires populated plugin config +func NewPluginBuilder(gc config.Plugin) *builder { + return &builder{ + GenConfig: gc, + tmpVenDirs: make([]string, 0), + } +} + +func (b *builder) BuildPlugin() error { + // Get plugin .go and .so file paths + var err error + var soFile string + b.goFile, soFile, err = b.GenConfig.GetPluginPaths() + if err != nil { + return err + } + + // setup env to build plugin + setupErr := b.setupBuildEnv() + if setupErr != nil { + return setupErr + } + + // Build the .go file into a .so plugin + execErr := exec.Command("go", "build", "-buildmode=plugin", "-o", soFile, b.goFile).Run() + if execErr != nil { + return errors.New(fmt.Sprintf("unable to build .so file: %s", execErr.Error())) + } + return nil +} + +// Sets up temporary vendor libs needed for plugin build +// This is to work around a conflict between plugins and vendoring (https://github.com/golang/go/issues/20481) +func (b *builder) setupBuildEnv() error { + // TODO: Less hacky way of handling plugin build deps + vendorPath, err := helpers.CleanPath(filepath.Join("$GOPATH/src", b.GenConfig.Home, "vendor")) + if err != nil { + return err + } + + repoPaths := b.GenConfig.GetRepoPaths() + + // Import transformer dependencies so that we can build our plugin + for importPath := range repoPaths { + dst := filepath.Join(vendorPath, importPath) + src, cleanErr := helpers.CleanPath(filepath.Join("$GOPATH/src", importPath)) + if cleanErr != nil { + return cleanErr + } + + copyErr := helpers.CopyDir(src, dst, "vendor") + if copyErr != nil { + return errors.New(fmt.Sprintf("unable to copy transformer dependency from %s to %s: %v", src, dst, copyErr)) + } + + // Have to clear out the copied over vendor lib or plugin won't build (see issue above) + removeErr := os.RemoveAll(filepath.Join(dst, "vendor")) + if removeErr != nil { + return removeErr + } + // Keep track of this vendor directory to clear later + b.tmpVenDirs = append(b.tmpVenDirs, dst) + } + + return nil +} + +// Used to clear all of the tmp vendor libs used to build the plugin +// Also clears the go file if saving it has not been specified in the config +// Do not call until after the MigrationManager has performed its operations +// as it needs to pull the db migrations from the tmpVenDirs +func (b *builder) CleanUp() error { + if !b.GenConfig.Save { + err := helpers.ClearFiles(b.goFile) + if err != nil { + return err + } + } + + for _, venDir := range b.tmpVenDirs { + err := os.RemoveAll(venDir) + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/plugin/generator.go b/pkg/plugin/generator.go new file mode 100644 index 00000000..7b3310f2 --- /dev/null +++ b/pkg/plugin/generator.go @@ -0,0 +1,68 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package plugin + +import ( + "errors" + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/plugin/builder" + "github.com/vulcanize/vulcanizedb/pkg/plugin/manager" + "github.com/vulcanize/vulcanizedb/pkg/plugin/writer" +) + +// Generator is the top-level interface for creating transformer plugins +type Generator interface { + GenerateExporterPlugin() error +} + +type generator struct { + writer.PluginWriter + builder.PluginBuilder + manager.MigrationManager +} + +// Creates a new generator from a plugin and database config +func NewGenerator(gc config.Plugin, dbc config.Database) (*generator, error) { + if len(gc.Transformers) < 1 { + return nil, errors.New("plugin generator is not configured with any transformers") + } + return &generator{ + PluginWriter: writer.NewPluginWriter(gc), + PluginBuilder: builder.NewPluginBuilder(gc), + MigrationManager: manager.NewMigrationManager(gc, dbc), + }, nil +} + +// Generates plugin for the transformer initializers specified in the generator config +// Writes plugin code => Sets up build environment => Builds .so file => Performs db migrations for the plugin transformers => Clean up +func (g *generator) GenerateExporterPlugin() error { + // Use plugin writer interface to write the plugin code + err := g.PluginWriter.WritePlugin() + if err != nil { + return err + } + // Clean up temporary files and directories when we are done + defer g.PluginBuilder.CleanUp() + // Use plugin builder interface to setup build environment and compile .go file into a .so file + err = g.PluginBuilder.BuildPlugin() + if err != nil { + return err + } + + // Perform db migrations for the transformers + return g.MigrationManager.RunMigrations() +} diff --git a/pkg/plugin/helpers/helpers.go b/pkg/plugin/helpers/helpers.go new file mode 100644 index 00000000..a3904d3c --- /dev/null +++ b/pkg/plugin/helpers/helpers.go @@ -0,0 +1,116 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package helpers + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "syscall" + + "github.com/mitchellh/go-homedir" +) + +func CleanPath(str string) (string, error) { + path, err := homedir.Expand(filepath.Clean(str)) + if err != nil { + return "", err + } + if strings.Contains(path, "$GOPATH") { + env := os.Getenv("GOPATH") + spl := strings.Split(path, "$GOPATH")[1] + path = filepath.Join(env, spl) + } + + return path, nil +} + +func ClearFiles(files ...string) error { + for _, file := range files { + if _, err := os.Stat(file); err == nil { + err = os.Remove(file) + if err != nil { + return err + } + } else if os.IsNotExist(err) { + continue + } else { + return err + } + } + + return nil +} + +func CopyFile(src, dst string) error { + in, err := os.Open(src) + if err != nil { + return err + } + out, err := os.OpenFile(dst, syscall.O_CREAT|syscall.O_EXCL|os.O_WRONLY, os.FileMode(0666)) // Doesn't overwrite files + if err != nil { + in.Close() + return err + } + + _, err = io.Copy(out, in) + in.Close() + out.Close() + return err +} + +func CopyDir(src string, dst string, excludeRecursiveDir string) error { + var err error + var fds []os.FileInfo + var srcinfo os.FileInfo + + srcinfo, err = os.Stat(src) + if err != nil { + return err + } + + mkErr := os.MkdirAll(dst, srcinfo.Mode()) + if mkErr != nil { + return mkErr + } + + fds, readErr := ioutil.ReadDir(src) + if err != readErr { + return readErr + } + for _, fd := range fds { + srcfp := filepath.Join(src, fd.Name()) + dstfp := filepath.Join(dst, fd.Name()) + + if fd.IsDir() { + if fd.Name() != excludeRecursiveDir { + dirErr := CopyDir(srcfp, dstfp, "") + if dirErr != nil { + return dirErr + } + } + } else { + fileErr := CopyFile(srcfp, dstfp) + if fileErr != nil { + return fileErr + } + } + } + return nil +} diff --git a/pkg/plugin/manager/manager.go b/pkg/plugin/manager/manager.go new file mode 100644 index 00000000..e19fbd0b --- /dev/null +++ b/pkg/plugin/manager/manager.go @@ -0,0 +1,144 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package manager + +import ( + "errors" + "fmt" + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/plugin/helpers" + "io/ioutil" + "os" + "os/exec" + "path/filepath" +) + +// Interface for managing the db migrations for plugin transformers +type MigrationManager interface { + RunMigrations() error +} + +type manager struct { + GenConfig config.Plugin + DBConfig config.Database + tmpMigDir string +} + +// Manager requires both filled in generator and database configs +func NewMigrationManager(gc config.Plugin, dbc config.Database) *manager { + return &manager{ + GenConfig: gc, + DBConfig: dbc, + } +} + +func (m *manager) RunMigrations() error { + // Get paths to db migrations from the plugin config + paths, err := m.GenConfig.GetMigrationsPaths() + if err != nil { + return err + } + if len(paths) < 1 { + return nil + } + // Init directory for temporary copies of migrations + err = m.setupMigrationEnv() + if err != nil { + return err + } + defer m.cleanUp() + // Creates copies of migrations for all the plugin's transformers in a tmp dir + err = m.createMigrationCopies(paths) + if err != nil { + return err + } + + return nil +} + +// Setup a temporary directory to hold transformer db migrations +func (m *manager) setupMigrationEnv() error { + var err error + m.tmpMigDir, err = helpers.CleanPath(filepath.Join("$GOPATH/src", m.GenConfig.Home+".plugin_migrations")) + if err != nil { + return err + } + err = os.RemoveAll(m.tmpMigDir) + if err != nil { + return errors.New(fmt.Sprintf("unable to remove file found at %s where tmp directory needs to be written", m.tmpMigDir)) + } + err = os.Mkdir(m.tmpMigDir, os.FileMode(os.ModePerm)) + if err != nil { + return errors.New(fmt.Sprintf("unable to create temporary migration directory %s", m.tmpMigDir)) + } + + return nil +} + +// Create copies of db migrations from vendored libs +func (m *manager) createMigrationCopies(paths []string) error { + // Iterate through migration paths to find migration directory + for _, path := range paths { + dir, err := ioutil.ReadDir(path) + if err != nil { + return err + } + // For each file in the directory check if it is a migration + for _, file := range dir { + if file.IsDir() || filepath.Ext(file.Name()) != ".sql" { + continue + } + src := filepath.Join(path, file.Name()) + dst := filepath.Join(m.tmpMigDir, file.Name()) + // and if it is make a copy of it to our tmp migration directory + err = helpers.CopyFile(src, dst) + if err != nil { + return err + } + } + err = m.fixAndRun(path) + if err != nil { + return err + } + } + + return nil +} + +func (m *manager) fixAndRun(path string) error { + // Fix the migrations + cmd := exec.Command("goose", "fix") + cmd.Dir = m.tmpMigDir + err := cmd.Run() + if err != nil { + return errors.New(fmt.Sprintf("version fixing for plugin migrations at %s failed: %s", path, err.Error())) + } + // Run the copied migrations with goose + pgStr := fmt.Sprintf("postgres://%s:%d/%s?sslmode=disable", m.DBConfig.Hostname, m.DBConfig.Port, m.DBConfig.Name) + cmd = exec.Command("goose", "postgres", pgStr, "up") + cmd.Dir = m.tmpMigDir + err = cmd.Run() + if err != nil { + return errors.New(fmt.Sprintf("db migrations for plugin transformers at %s failed: %s", path, err.Error())) + } + + return nil +} + +func (m *manager) cleanUp() error { + return os.RemoveAll(m.tmpMigDir) +} diff --git a/pkg/plugin/writer/writer.go b/pkg/plugin/writer/writer.go new file mode 100644 index 00000000..e888bc5b --- /dev/null +++ b/pkg/plugin/writer/writer.go @@ -0,0 +1,125 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package writer + +import ( + "errors" + "fmt" + + . "github.com/dave/jennifer/jen" + + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/plugin/helpers" +) + +// Interface for writing a .go file for a simple +// plugin that exports the set of transformer +// initializers specified in the config +type PluginWriter interface { + WritePlugin() error +} + +type writer struct { + GenConfig config.Plugin +} + +// Requires populated plugin config +func NewPluginWriter(gc config.Plugin) *writer { + return &writer{ + GenConfig: gc, + } +} + +// Generates the plugin code according to config specification +func (w *writer) WritePlugin() error { + // Setup plugin file paths + goFile, err := w.setupFilePath() + if err != nil { + return err + } + + // Begin code generation + f := NewFile("main") + f.HeaderComment("This is a plugin generated to export the configured transformer initializers") + + // Import pkgs for generic TransformerInitializer interface and specific TransformerInitializers specified in config + f.ImportAlias("github.com/vulcanize/vulcanizedb/libraries/shared/transformer", "interface") + for name, transformer := range w.GenConfig.Transformers { + f.ImportAlias(transformer.RepositoryPath+"/"+transformer.Path, name) + } + + // Collect initializer code + code, err := w.collectTransformers() + if err != nil { + return err + } + + // Create Exporter variable with method to export the set of the imported storage and event transformer initializers + f.Type().Id("exporter").String() + f.Var().Id("Exporter").Id("exporter") + f.Func().Params(Id("e").Id("exporter")).Id("Export").Params().Parens(List( + Index().Qual("github.com/vulcanize/vulcanizedb/libraries/shared/transformer", "EventTransformerInitializer"), + Index().Qual("github.com/vulcanize/vulcanizedb/libraries/shared/transformer", "StorageTransformerInitializer"), + Index().Qual("github.com/vulcanize/vulcanizedb/libraries/shared/transformer", "ContractTransformerInitializer"), + )).Block(Return( + Index().Qual( + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer", + "EventTransformerInitializer").Values(code[config.EthEvent]...), + Index().Qual( + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer", + "StorageTransformerInitializer").Values(code[config.EthStorage]...), + Index().Qual( + "github.com/vulcanize/vulcanizedb/libraries/shared/transformer", + "ContractTransformerInitializer").Values(code[config.EthContract]...))) // Exports the collected event and storage transformer initializers + + // Write code to destination file + err = f.Save(goFile) + if err != nil { + return errors.New(fmt.Sprintf("failed to save generated .go file: %s\r\n%s", goFile, err.Error())) + } + return nil +} + +// Collect code for various types of initializers +func (w *writer) collectTransformers() (map[config.TransformerType][]Code, error) { + code := make(map[config.TransformerType][]Code) + for _, transformer := range w.GenConfig.Transformers { + path := transformer.RepositoryPath + "/" + transformer.Path + switch transformer.Type { + case config.EthEvent: + code[config.EthEvent] = append(code[config.EthEvent], Qual(path, "EventTransformerInitializer")) + case config.EthStorage: + code[config.EthStorage] = append(code[config.EthStorage], Qual(path, "StorageTransformerInitializer")) + case config.EthContract: + code[config.EthContract] = append(code[config.EthContract], Qual(path, "ContractTransformerInitializer")) + default: + return nil, errors.New(fmt.Sprintf("invalid transformer type %s", transformer.Type)) + } + } + + return code, nil +} + +// Setup the .go, clear old ones if present +func (w *writer) setupFilePath() (string, error) { + goFile, soFile, err := w.GenConfig.GetPluginPaths() + if err != nil { + return "", err + } + // Clear .go and .so files of the same name if they exist + return goFile, helpers.ClearFiles(goFile, soFile) +} diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 00000000..a17ed3f1 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,2 @@ +## Plugins +This empty directory is for Exporter plugins (.go and .so files) written, built, and linked to by the composeAndExecute command diff --git a/postgraphile/.dockerignore b/postgraphile/.dockerignore new file mode 100644 index 00000000..1e5df4d8 --- /dev/null +++ b/postgraphile/.dockerignore @@ -0,0 +1,7 @@ +package-lock.json +yarn.lock +node_modules +Dockerfile +README.md +spec +.dockerignore diff --git a/postgraphile/Dockerfile b/postgraphile/Dockerfile new file mode 100644 index 00000000..f2785e36 --- /dev/null +++ b/postgraphile/Dockerfile @@ -0,0 +1,9 @@ +FROM mhart/alpine-node:10 +RUN apk --update --no-cache add make g++ python findutils postgresql-dev + +WORKDIR /app +COPY . /app +run yarn install +RUN ["./node_modules/typescript/bin/tsc"] +EXPOSE 3000 +CMD ["node", "/app/build/dist/index.js"] diff --git a/postgraphile/README.md b/postgraphile/README.md new file mode 100644 index 00000000..0bd5958c --- /dev/null +++ b/postgraphile/README.md @@ -0,0 +1,31 @@ +# Vulcanize GraphQL API + +This application utilizes Postgraphile to expose GraphQL endpoints for exposure of the varied data that VulcanizeDB tracks. + +## Docker use +_Note: currently this image is ~500MB large (unpacked)_ + +Build the docker image in this directory. Start the `GraphiQL` frontend by: +* Setting the env variables for the database connection: `DATABASE_HOST`, + `DATABASE_NAME`, `DATABASE_USER`, `DATABASE_PASSWORD` (and optionally + `DATABASE_PORT` if running on non-standard port). + * The specified user needs to be `superuser` on the vulcanizeDB database +* Run the container (ex. `docker run -e DATABASE_HOST=localhost -e DATABASE_NAME=vulcanize_public -e DATABASE_USER=vulcanize -e DATABASE_PASSWORD=vulcanize -d m0ar/images:postgraphile-alpine`) +* GraphiQL is available at `:3000/graphiql` + + +## Building + +*This application assumes the use of the [Yarn package manager](https://yarnpkg.com/en/). The use of npm may produce unexpected results.* + +Install dependencies with `yarn` and execute `yarn build`. The bundle produced by Webpack will be present in `build/dist/`. + +This application currently uses the Postgraphile supporter plugin. This plugin is present in the `vendor/` directory and is copied to `node_modules/` after installation of packages. It is a fresh checkout of the plugin as of August 31st, 2018. + +## Running + +Provide the built bundle to node as a runnable script: `node ./build/dist/vulcanize-postgraphile-server.js` + +## Testing + +Tests are executed via Jasmine with a console reporter via the `yarn test` task. diff --git a/postgraphile/package.json b/postgraphile/package.json new file mode 100644 index 00000000..24500f18 --- /dev/null +++ b/postgraphile/package.json @@ -0,0 +1,56 @@ +{ + "name": "vulcanizedb", + "version": "1.0.0", + "description": "", + "scripts": { + "build": "rm -rf ./build/dist && webpack --config=./webpack.config.js", + "lint": "tslint --project ./tsconfig.json --config ./tslint.json", + "postinstall": "rm -rf node_modules/@graphile && mkdir node_modules/@graphile && cp -R ./vendor/postgraphile-supporter/ ./node_modules/@graphile/plugin-supporter/", + "start": "npm run build && node ./build/dist/vulcanize-postgraphile-server.js", + "test": "rm -rf ./build/spec && tsc --build ./tsconfig.test.json && jasmine --config=./spec/support/jasmine.json", + "test:ci": "npm run lint && npm run test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vulcanize/vulcanizedb.git" + }, + "author": "Vulcanize, Inc.", + "license": "AGPL-3.0", + "bugs": { + "url": "https://github.com/vulcanize/vulcanizedb/issues" + }, + "homepage": "https://github.com/vulcanize/vulcanizedb", + "dependencies": { + "express-session": "1.15.6", + "graphql-subscriptions": "0.5.8", + "lodash": "4.17.10", + "passport": "0.4.0", + "pg": "6.4.2", + "pg-native": "3.0.0", + "postgraphile": "4.0.0-rc.4", + "subscriptions-transport-ws": "0.9.14", + "toml": "2.3.3" + }, + "devDependencies": { + "@types/express": "4.16.0", + "@types/express-session": "1.15.10", + "@types/graphql": "^0.13.4", + "@types/jasmine": "2.8.8", + "@types/lodash": "4.14.116", + "@types/node": "^10.12.21", + "@types/passport": "0.4.6", + "awesome-typescript-loader": "5.2.0", + "jasmine": "3.2.0", + "jasmine-ts-console-reporter": "3.1.1", + "source-map-loader": "0.2.4", + "tslint": "5.11.0", + "tslint-eslint-rules": "5.4.0", + "typescript": "3.0.1", + "webpack": "4.17.1", + "webpack-cli": "3.1.0", + "webpack-dev-server": "3.1.6" + }, + "resolutions": { + "pg": "6.4.2" + } +} diff --git a/postgraphile/spec/config/parse.spec.ts b/postgraphile/spec/config/parse.spec.ts new file mode 100644 index 00000000..4756cb3c --- /dev/null +++ b/postgraphile/spec/config/parse.spec.ts @@ -0,0 +1,78 @@ +import { parseConfig } from '../../src/config/parse'; + +describe('parseConfig', () => { + let configPath: string; + let tomlContents: string; + let parsedToml: object; + let readCallback: jasmine.Spy; + let tomlParseCallback: jasmine.Spy; + + beforeEach(() => { + configPath = '/example/config/path.toml'; + tomlContents = `[database]\nname = 'example_database'\n ` + + `hostname = 'example.com'\nport = 1234`; + + parsedToml = { + database: { + hostname: 'example.com', + name: 'example_database', + port: '1234', + user: 'user', + password: 'password' + } + }; + + readCallback = jasmine.createSpy('readCallback'); + readCallback.and.returnValue(tomlContents); + + tomlParseCallback = jasmine.createSpy('tomlParseCallback'); + tomlParseCallback.and.returnValue(parsedToml); + }); + + it('provides the database host', () => { + const databaseConfig = parseConfig( + readCallback, tomlParseCallback, configPath); + + expect(databaseConfig.host).toEqual('postgres://user:password@example.com:1234'); + }); + + it('provides the database name', () => { + const databaseConfig = parseConfig( + readCallback, tomlParseCallback, configPath); + + expect(databaseConfig.database).toEqual('example_database'); + }); + + it('handles a missing config path', () => { + const failingCall = () => + parseConfig(readCallback, tomlParseCallback, ''); + + tomlParseCallback.and.returnValue({ + database: { hostname: 'example.com', name: 'example_database' } + }); + + expect(failingCall).toThrow(); + }); + + it('handles a missing database host', () => { + const failingCall = () => + parseConfig(readCallback, tomlParseCallback, configPath); + + tomlParseCallback.and.returnValue({ + database: { hostname: '', name: 'example_database' } + }); + + expect(failingCall).toThrow(); + }); + + it('handles a missing database name', () => { + const failingCall = () => + parseConfig(readCallback, tomlParseCallback, configPath); + + tomlParseCallback.and.returnValue({ + database: { hostname: 'example.com', name: '', port: '1234' } + }); + + expect(failingCall).toThrow(); + }); +}); diff --git a/postgraphile/spec/helpers/ts_console.ts b/postgraphile/spec/helpers/ts_console.ts new file mode 100644 index 00000000..cae7febd --- /dev/null +++ b/postgraphile/spec/helpers/ts_console.ts @@ -0,0 +1,7 @@ +// NOTE: This file helps Jasmine +// comprehend TS sourcemaps by installing a reporter +// specifically for TypeScript +const TSConsoleReporter = require('jasmine-ts-console-reporter'); + +jasmine.getEnv().clearReporters(); +jasmine.getEnv().addReporter(new TSConsoleReporter()); diff --git a/postgraphile/spec/server/config.spec.ts b/postgraphile/spec/server/config.spec.ts new file mode 100644 index 00000000..1a6c17f9 --- /dev/null +++ b/postgraphile/spec/server/config.spec.ts @@ -0,0 +1,105 @@ +import { PassportStatic } from 'passport'; + +import { PostgraphileMiddleware } from '../../src/adapters/postgraphile'; +import { buildServerConfig } from '../../src/server/config'; + +import { + DatabaseConfig, + ServerConfig, + ServerUtilities +} from '../../src/server/interface'; + +describe('buildServerConfig', () => { + let configParser: jasmine.Spy; + let postgraphileMiddleware: PostgraphileMiddleware; + let expressSessionHandler: jasmine.Spy; + let passportInitializer: jasmine.Spy; + let passportSessionHandler: jasmine.Spy; + let serverConfig: ServerConfig; + + let serverUtilities: ServerUtilities; + let databaseConfig: DatabaseConfig; + + beforeEach(() => { + databaseConfig = { host: 'example.com', database: 'example_database' }; + + postgraphileMiddleware = jasmine + .createSpyObj(['call']), + + serverUtilities = { + pluginHook: jasmine.createSpy('pluginHook'), + enableSubscriptions: jasmine.createSpy('enableSubscriptions'), + express: jasmine.createSpy('express'), + expressSession: jasmine.createSpy('expressSession'), + httpServerFactory: jasmine.createSpy('httpServerFactory'), + passport: jasmine.createSpyObj(['initialize', 'session']), + postgraphile: jasmine.createSpy('postgraphile') + }; + + const rawConfig: object = { exampleOption: 'example value' }; + + configParser = jasmine.createSpy('configParser'); + configParser.and.returnValue(rawConfig); + + expressSessionHandler = jasmine.createSpy('expressSessionHandler'); + passportInitializer = jasmine.createSpy('passportInitializer'); + passportSessionHandler = jasmine.createSpy('passportSessionHandler'); + + (serverUtilities.postgraphile as jasmine.Spy) + .and.returnValue(postgraphileMiddleware); + (serverUtilities.expressSession as jasmine.Spy) + .and.returnValue(expressSessionHandler); + (serverUtilities.passport.initialize as jasmine.Spy) + .and.returnValue(passportInitializer); + (serverUtilities.passport.session as jasmine.Spy) + .and.returnValue(passportSessionHandler); + + serverConfig = buildServerConfig( + serverUtilities, databaseConfig, undefined); + }); + + it('provides the Postgraphile options', () => { + expect(serverConfig.options).not.toBeNull(); + }); + + it('enables simple subscriptions', () => { + expect(serverConfig.options.simpleSubscriptions).toBe(true); + }); + + it('it adds the express session handler as the first middleware', () => { + expect(serverConfig.options.webSocketMiddlewares[0]) + .toBe(expressSessionHandler); + }); + + it('it adds the passport initializer as the second middleware', () => { + expect(serverConfig.options.webSocketMiddlewares[1]) + .toBe(passportInitializer); + }); + + it('it adds the passport session handler as the third middleware', () => { + expect(serverConfig.options.webSocketMiddlewares[2]) + .toBe(passportSessionHandler); + }); + + it('provides the database config to Postgraphile', () => { + expect(serverUtilities.postgraphile).toHaveBeenCalledWith( + `${databaseConfig.host}/${databaseConfig.database}`, + ["public"], + jasmine.any(Object)); + }); + + it('provides the Postgraphile middleware', () => { + expect(serverConfig.middleware).toBe(postgraphileMiddleware); + }); + + it('sets the default server port', () => { + expect(serverConfig.port).toEqual(3000); + }); + + it('sets an explicit server port', () => { + const serverConfigWithPort = buildServerConfig( + serverUtilities, databaseConfig, '1234'); + + expect(serverConfigWithPort.port).toEqual(1234); + }); +}); diff --git a/postgraphile/spec/server/runtime.spec.ts b/postgraphile/spec/server/runtime.spec.ts new file mode 100644 index 00000000..85b55b61 --- /dev/null +++ b/postgraphile/spec/server/runtime.spec.ts @@ -0,0 +1,71 @@ +import { Express } from 'express'; +import { PassportStatic } from 'passport'; +import { Server } from 'http'; + +import { ServerUtilities, ServerConfig } from '../../src/server/interface'; +import { bootServer } from '../../src/server/runtime'; +import { PostgraphileMiddleware } from '../../src/adapters/postgraphile'; + +describe('bootServer', () => { + let serverUtilities: ServerUtilities; + let serverConfig: ServerConfig; + let mockExpressApp: Express; + let mockHttpServer: Server; + + beforeEach(() => { + serverUtilities = { + pluginHook: jasmine.createSpy('pluginHook'), + enableSubscriptions: jasmine.createSpy('enableSubscriptions'), + express: jasmine.createSpy('express'), + expressSession: jasmine.createSpy('expressSession'), + httpServerFactory: jasmine.createSpy('httpServerFactory'), + passport: jasmine.createSpyObj(['initialize', 'session']), + postgraphile: jasmine.createSpy('postgraphile') + }; + + serverConfig = { + middleware: jasmine.createSpyObj(['call']), + options: { + pluginHook: jasmine.createSpy('pluginHook'), + watchPg: true, + enableCors: true, + simpleSubscriptions: true, + graphiql: true, + webSocketMiddlewares: [] }, + port: 5678 + }; + + mockExpressApp = jasmine.createSpyObj(['use']); + (serverUtilities.express as jasmine.Spy) + .and.returnValue(mockExpressApp); + + mockHttpServer = jasmine.createSpyObj(['listen']); + (serverUtilities.httpServerFactory as jasmine.Spy) + .and.returnValue(mockHttpServer); + + bootServer(serverUtilities, serverConfig); + }); + + it('builds a new, Node HTTP server', () => { + expect(serverUtilities.httpServerFactory) + .toHaveBeenCalledWith(mockExpressApp); + }); + + it('provides Postgraphile middleware to the Express app', () => { + const useSpy = mockExpressApp.use as jasmine.Spy; + expect(useSpy).toHaveBeenCalledWith(serverConfig.middleware); + }); + + it('enahances the Node HTTP server with Postgraphile subscriptions', () => { + expect(serverUtilities.enableSubscriptions) + .toHaveBeenCalledWith( + mockHttpServer, + serverConfig.middleware, + serverConfig.options); + }); + + it('instructs the server to listen on the given port', () => { + const listenSpy = mockHttpServer.listen as jasmine.Spy; + expect(listenSpy).toHaveBeenCalledWith(serverConfig.port); + }); +}); diff --git a/postgraphile/spec/support/jasmine.json b/postgraphile/spec/support/jasmine.json new file mode 100644 index 00000000..c69916da --- /dev/null +++ b/postgraphile/spec/support/jasmine.json @@ -0,0 +1,11 @@ +{ + "spec_dir": "build/spec/", + "spec_files": [ + "**/*[sS]pec.js" + ], + "helpers": [ + "helpers/*.js" + ], + "stopSpecOnExpectationFailure": false, + "random": true +} diff --git a/postgraphile/src/adapters/fs.ts b/postgraphile/src/adapters/fs.ts new file mode 100644 index 00000000..68716e55 --- /dev/null +++ b/postgraphile/src/adapters/fs.ts @@ -0,0 +1,11 @@ +import { URL } from 'url'; + +export type ReadFileSyncCallback = ( + path: string | number | Buffer | URL, + options?: { encoding?: null | undefined; flag?: string | undefined; } + | null + | undefined +) => string | Buffer; + +export type TomlParseCallback + = (fileContents: string) => { [key: string]: { [key: string]: string } }; diff --git a/postgraphile/src/adapters/http.ts b/postgraphile/src/adapters/http.ts new file mode 100644 index 00000000..13ce0fed --- /dev/null +++ b/postgraphile/src/adapters/http.ts @@ -0,0 +1,7 @@ +import { IncomingMessage, ServerResponse, Server } from 'http'; + +export type RequestListenerCallback + = (request: IncomingMessage, response: ServerResponse) => void; + +export type CreateHttpServerCallback + = (requestListener?: RequestListenerCallback) => Server; diff --git a/postgraphile/src/adapters/postgraphile.ts b/postgraphile/src/adapters/postgraphile.ts new file mode 100644 index 00000000..17e4bf4e --- /dev/null +++ b/postgraphile/src/adapters/postgraphile.ts @@ -0,0 +1,33 @@ +import { RequestHandler } from 'express'; +import { Server } from 'http'; +import { PluginHookFn } from 'postgraphile/build/postgraphile/pluginHook'; + +// NOTE: Shape of the middleware is not +// currently important to this application, but if a need arises, +// any needed shape can be assigned from a custom type here. For +// the time being, this is a named stub to provide clarity. +export interface PostgraphileMiddleware extends RequestHandler {} + +export interface PostgraphileOptions { + pluginHook: PluginHookFn, + simpleSubscriptions: boolean; + watchPg: boolean; + enableCors: boolean; + graphiql: boolean; + // NOTE: Shape of the middlewares is not + // currently important to this application, but if a need arises, + // any needed shape can be assigned from a custom type here. + webSocketMiddlewares: object[]; +} + +export type PostgraphileInitCallback = ( + databaseUrl: string, + schemas: string[], + options: PostgraphileOptions +) => PostgraphileMiddleware; + +export type AddSubscriptionsCallback = ( + httpServer: Server, + middleware: PostgraphileMiddleware, + options: PostgraphileOptions +) => void; diff --git a/postgraphile/src/adapters/session.ts b/postgraphile/src/adapters/session.ts new file mode 100644 index 00000000..86c5c6bd --- /dev/null +++ b/postgraphile/src/adapters/session.ts @@ -0,0 +1,20 @@ +import { SessionOptions } from 'express-session'; +import { Express, RequestHandler, Handler } from 'express'; + +export type ExpressInitCallback = () => Express; + +export type ExpressSessionInitCallback + = (options?: SessionOptions) => RequestHandler ; + +export type PassportInitCallback = ( + options?: { userProperty: string; } | undefined +) => Handler; + +export type PassportSessionCallback = ( + options?: { pauseStream: boolean; } | undefined +) => Handler; + +export interface StaticPassportProvider { + initialize: PassportInitCallback; + session: PassportSessionCallback; +} diff --git a/postgraphile/src/config/parse.ts b/postgraphile/src/config/parse.ts new file mode 100644 index 00000000..513aa4fe --- /dev/null +++ b/postgraphile/src/config/parse.ts @@ -0,0 +1,54 @@ +import { CONFIG_PATH_KEY } from '../server/config'; +import { DatabaseConfig } from '../server/interface'; +import { ReadFileSyncCallback, TomlParseCallback } from '../adapters/fs'; + +export const MISSING_PATH_MESSAGE = `No path to config toml file provided, ` + + `please check the value of ${CONFIG_PATH_KEY} in your environment`; + +export const MISSING_HOST_MESSAGE = 'No database host provided in config toml'; +export const MISSING_USER_MESSAGE = 'No database user & password provided in config toml'; +export const MISSING_DATABASE_MESSAGE = 'No database name provided in config toml'; + +export function parseConfig( + readCallback: ReadFileSyncCallback, + tomlParseCallback: TomlParseCallback, + configPath?: string +): DatabaseConfig { + let host = ''; + let port = ''; + let database = ''; + let user = ''; + let password = ''; + + if (configPath) { + const tomlContents = readCallback(`${configPath}`).toString(); + const parsedToml = tomlParseCallback(tomlContents); + + host = parsedToml['database']['hostname']; + port = parsedToml['database']['port']; + database = parsedToml['database']['name']; + user = parsedToml['database']['user']; + password = parsedToml['database']['password']; + } + + // Overwrite config values with env. vars if such are set + host = process.env.DATABASE_HOST || host; + port = process.env.DATABASE_PORT || port; + database = process.env.DATABASE_NAME || database; + user = process.env.DATABASE_USER || user; + password = process.env.DATABASE_PASSWORD || password; + + if (!host) { + throw new Error(MISSING_HOST_MESSAGE); + } + + if (!database) { + throw new Error(MISSING_DATABASE_MESSAGE); + } + + if (!user || !password) { + throw new Error(MISSING_USER_MESSAGE); + } + + return { host: `postgres://${user}:${password}@${host}:${port}`, database }; +} diff --git a/postgraphile/src/index.ts b/postgraphile/src/index.ts new file mode 100644 index 00000000..d14aa0d6 --- /dev/null +++ b/postgraphile/src/index.ts @@ -0,0 +1,43 @@ +import { createServer } from 'http'; +import { postgraphile, makePluginHook } from 'postgraphile'; +import { readFileSync } from 'fs'; + +import express = require('express'); +import passport = require('passport'); +import session = require('express-session'); +import toml = require('toml'); + +const { + default: PostGraphileSupporter, + enhanceHttpServerWithSubscriptions, +} = require('@graphile/plugin-supporter'); +const pluginHook = makePluginHook([PostGraphileSupporter]); + +import { ServerUtilities } from './server/interface'; +import { bootServer } from './server/runtime'; +import { parseConfig } from './config/parse'; + +import { + buildServerConfig, + CONFIG_PATH_KEY, + SERVER_PORT_KEY +} from './server/config'; + +const configPath = process.env[CONFIG_PATH_KEY]; +const serverPort = process.env[SERVER_PORT_KEY]; + +const serverUtilities: ServerUtilities = { + enableSubscriptions: enhanceHttpServerWithSubscriptions, + express, + expressSession: session, + httpServerFactory: createServer, + passport, + postgraphile, + pluginHook +}; + +const databaseConfig = parseConfig(readFileSync, toml.parse, configPath); +const serverConfig = buildServerConfig( + serverUtilities, databaseConfig, serverPort); + +bootServer(serverUtilities, serverConfig); diff --git a/postgraphile/src/server/config.ts b/postgraphile/src/server/config.ts new file mode 100644 index 00000000..e2be53a1 --- /dev/null +++ b/postgraphile/src/server/config.ts @@ -0,0 +1,47 @@ +import { ServerUtilities, DatabaseConfig, ServerConfig } from './interface'; + +import { + PostgraphileMiddleware, + PostgraphileOptions +} from '../adapters/postgraphile'; + +export const CONFIG_PATH_KEY = 'CONFIG_PATH'; +export const SERVER_PORT_KEY = 'SERVER_PORT'; + +const DEFAULT_SERVER_PORT = '3000'; + +export function buildServerConfig( + utilities: ServerUtilities, + databaseConfig: DatabaseConfig, + port?: string +): ServerConfig { + if (!port || port.length < 1) { + port = DEFAULT_SERVER_PORT; + } + + const expressSessionHandler = utilities.expressSession(); + const passportInitializer = utilities.passport.initialize(); + const passportSessionHandler = utilities.passport.session(); + const pluginHook = utilities.pluginHook; + + const options: PostgraphileOptions = { + pluginHook: pluginHook, + simpleSubscriptions: true, + watchPg: true, + enableCors: true, + graphiql: true, + webSocketMiddlewares: [ + expressSessionHandler, + passportInitializer, + passportSessionHandler + ] + }; + + const middleware: PostgraphileMiddleware = utilities.postgraphile( + `${databaseConfig.host}/${databaseConfig.database}`, + ["public"], + options + ); + + return { middleware, options, port: parseInt(port, 10) }; +} diff --git a/postgraphile/src/server/interface.ts b/postgraphile/src/server/interface.ts new file mode 100644 index 00000000..b1d251b7 --- /dev/null +++ b/postgraphile/src/server/interface.ts @@ -0,0 +1,36 @@ +import { CreateHttpServerCallback } from '../adapters/http'; + +import { + ExpressInitCallback, + ExpressSessionInitCallback, + StaticPassportProvider +} from '../adapters/session'; + +import { + AddSubscriptionsCallback, + PostgraphileInitCallback, + PostgraphileMiddleware, + PostgraphileOptions +} from '../adapters/postgraphile'; +import { PluginHookFn } from 'postgraphile/build/postgraphile/pluginHook'; + +export interface DatabaseConfig { + host: string; + database: string; +} + +export interface ServerConfig { + middleware: PostgraphileMiddleware; + options: PostgraphileOptions; + port: number; +} + +export interface ServerUtilities { + enableSubscriptions: AddSubscriptionsCallback; + express: ExpressInitCallback; + expressSession: ExpressSessionInitCallback; + httpServerFactory: CreateHttpServerCallback; + passport: StaticPassportProvider; + postgraphile: PostgraphileInitCallback; + pluginHook: PluginHookFn +} diff --git a/postgraphile/src/server/runtime.ts b/postgraphile/src/server/runtime.ts new file mode 100644 index 00000000..cf42fe6d --- /dev/null +++ b/postgraphile/src/server/runtime.ts @@ -0,0 +1,18 @@ +import { ServerUtilities, ServerConfig } from './interface'; + +export function bootServer( + utilities: ServerUtilities, + config: ServerConfig +): void { + const expressApp = utilities.express(); + expressApp.use(config.middleware); + + const httpServer = utilities.httpServerFactory(expressApp); + + utilities.enableSubscriptions( + httpServer, + config.middleware, + config.options); + + httpServer.listen(config.port); +} diff --git a/postgraphile/tsconfig.json b/postgraphile/tsconfig.json new file mode 100644 index 00000000..c31646c1 --- /dev/null +++ b/postgraphile/tsconfig.json @@ -0,0 +1,54 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "lib": ["esnext"], /* Specify library files to be included in the compilation: */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "build/dist", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} diff --git a/postgraphile/tsconfig.test.json b/postgraphile/tsconfig.test.json new file mode 100644 index 00000000..4ae95b7c --- /dev/null +++ b/postgraphile/tsconfig.test.json @@ -0,0 +1,54 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "lib": ["esnext"], /* Specify library files to be included in the compilation: */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "build/spec", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} diff --git a/postgraphile/tslint.json b/postgraphile/tslint.json new file mode 100644 index 00000000..b662fd78 --- /dev/null +++ b/postgraphile/tslint.json @@ -0,0 +1,93 @@ +{ + "extends": [ + "tslint-eslint-rules" + ], + "rules": { + "object-curly-spacing": true, + "ter-indent": [true, 2], + "array-bracket-spacing": ["error", "never"], + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": [true, "ignore-same-line"], + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "label-position": true, + "max-line-length": [ + true, + 80 + ], + "member-access": [true, "no-public"], + "member-ordering": [true, { "order": "statics-first" }], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-consecutive-blank-lines": true, + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": true, + "no-shadowed-variable": false, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": false, + "no-unused-expression": false, + "no-use-before-declare": true, + "no-var-keyword": false, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-whitespace" + ], + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": true, + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + + "use-host-property-decorator": false, + "no-access-missing-member": false, + "templates-use-public": false, + "brace-style": false + } +} diff --git a/postgraphile/webpack.config.js b/postgraphile/webpack.config.js new file mode 100644 index 00000000..480039b5 --- /dev/null +++ b/postgraphile/webpack.config.js @@ -0,0 +1,20 @@ +module.exports = { + entry: "./src/index.ts", + mode: "production", + devtool: "source-map", + target: 'node', + output: { + filename: "vulcanize-postgraphile-server.js", + path: __dirname + "/build/dist/", + publicPath: "build/dist/" + }, + resolve: { + extensions: [".ts", ".tsx", ".mjs", ".js", ".json", ".css", ".png"] + }, + module: { + rules: [ + { test: /\.ts$/, loader: "awesome-typescript-loader" }, + { enforce: "pre", test: /\.js$/, loader: "source-map-loader" } + ] + } +}; diff --git a/postgraphile/yarn.lock b/postgraphile/yarn.lock new file mode 100644 index 00000000..c0e913de --- /dev/null +++ b/postgraphile/yarn.lock @@ -0,0 +1,4329 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/accepts@*": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" + dependencies: + "@types/node" "*" + +"@types/body-parser@*": + version "1.17.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.32" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" + dependencies: + "@types/node" "*" + +"@types/cookies@*": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.1.tgz#f9f204bd6767d389eea3b87609e30c090c77a540" + dependencies: + "@types/connect" "*" + "@types/express" "*" + "@types/keygrip" "*" + "@types/node" "*" + +"@types/events@*": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" + +"@types/express-serve-static-core@*": + version "4.16.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz#fdfe777594ddc1fe8eb8eccce52e261b496e43e7" + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/range-parser" "*" + +"@types/express-session@1.15.10": + version "1.15.10" + resolved "https://registry.yarnpkg.com/@types/express-session/-/express-session-1.15.10.tgz#d0ae7d3d2fee26512574306333ac272a37430c86" + dependencies: + "@types/events" "*" + "@types/express" "*" + "@types/node" "*" + +"@types/express@*", "@types/express@4.16.0": + version "4.16.0" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.0.tgz#6d8bc42ccaa6f35cf29a2b7c3333cb47b5a32a19" + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/serve-static" "*" + +"@types/graphql@^0.13.4": + version "0.13.4" + resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.4.tgz#55ae9c29f0fd6b85ee536f5c72b4769d5c5e06b1" + +"@types/http-assert@*": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.3.0.tgz#5e932606153da28e1d04f9043f4912cf61fd55dd" + +"@types/jasmine@2.8.8": + version "2.8.8" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.8.tgz#bf53a7d193ea8b03867a38bfdb4fbb0e0bf066c9" + +"@types/jsonwebtoken@<7.2.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-7.2.0.tgz#0fed32c8501da80ac9839d2d403a65c83d776ffd" + dependencies: + "@types/node" "*" + +"@types/keygrip@*": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.1.tgz#ff540462d2fb4d0a88441ceaf27d287b01c3d878" + +"@types/koa-compose@*": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.2.tgz#dc106e000bbf92a3ac900f756df47344887ee847" + +"@types/koa@2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.0.44.tgz#4d972a3dec4d6eb89bd3c16775de26305d1c51a6" + dependencies: + "@types/accepts" "*" + "@types/cookies" "*" + "@types/events" "*" + "@types/http-assert" "*" + "@types/keygrip" "*" + "@types/koa-compose" "*" + "@types/node" "*" + +"@types/lodash@4.14.116": + version "4.14.116" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.116.tgz#5ccf215653e3e8c786a58390751033a9adca0eb9" + +"@types/mime@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.0.tgz#5a7306e367c539b9f6543499de8dd519fac37a8b" + +"@types/node@*": + version "10.9.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.4.tgz#0f4cb2dc7c1de6096055357f70179043c33e9897" + +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== + +"@types/passport@0.4.6": + version "0.4.6" + resolved "https://registry.yarnpkg.com/@types/passport/-/passport-0.4.6.tgz#1c6a1a3fd105e9354816e179c5c9cd13852864d1" + dependencies: + "@types/express" "*" + +"@types/pg-types@*": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@types/pg-types/-/pg-types-1.11.4.tgz#8d7c59fb509ce3dca3f8bae589252051c639a9a8" + dependencies: + moment ">=2.14.0" + +"@types/pg@^7.4.10": + version "7.4.10" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-7.4.10.tgz#1cf4d6c5d32e621566eca82981161b371fb90ace" + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/pg-types" "*" + +"@types/range-parser@*": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.2.tgz#fa8e1ad1d474688a757140c91de6dace6f4abc8d" + +"@types/serve-static@*": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +"@webassemblyjs/ast@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25" + dependencies: + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" + debug "^3.1.0" + mamacro "^0.0.3" + +"@webassemblyjs/floating-point-hex-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz#29ce0baa97411f70e8cce68ce9c0f9d819a4e298" + +"@webassemblyjs/helper-api-error@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz#e49b051d67ee19a56e29b9aa8bd949b5b4442a59" + +"@webassemblyjs/helper-buffer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz#873bb0a1b46449231137c1262ddfd05695195a1e" + dependencies: + debug "^3.1.0" + +"@webassemblyjs/helper-code-frame@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz#1bd2181b6a0be14e004f0fe9f5a660d265362b58" + dependencies: + "@webassemblyjs/wast-printer" "1.5.13" + +"@webassemblyjs/helper-fsm@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz#cdf3d9d33005d543a5c5e5adaabf679ffa8db924" + +"@webassemblyjs/helper-module-context@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz#dc29ddfb51ed657655286f94a5d72d8a489147c5" + dependencies: + debug "^3.1.0" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz#03245817f0a762382e61733146f5773def15a747" + +"@webassemblyjs/helper-wasm-section@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz#efc76f44a10d3073b584b43c38a179df173d5c7d" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + debug "^3.1.0" + +"@webassemblyjs/ieee754@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz#573e97c8c12e4eebb316ca5fde0203ddd90b0364" + dependencies: + ieee754 "^1.1.11" + +"@webassemblyjs/leb128@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.13.tgz#ab52ebab9cec283c1c1897ac1da833a04a3f4cee" + dependencies: + long "4.0.0" + +"@webassemblyjs/utf8@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.13.tgz#6b53d2cd861cf94fa99c1f12779dde692fbc2469" + +"@webassemblyjs/wasm-edit@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz#c9cef5664c245cf11b3b3a73110c9155831724a8" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/helper-wasm-section" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + "@webassemblyjs/wast-printer" "1.5.13" + debug "^3.1.0" + +"@webassemblyjs/wasm-gen@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz#8e6ea113c4b432fa66540189e79b16d7a140700e" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" + +"@webassemblyjs/wasm-opt@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz#147aad7717a7ee4211c36b21a5f4c30dddf33138" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + debug "^3.1.0" + +"@webassemblyjs/wasm-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz#6f46516c5bb23904fbdf58009233c2dd8a54c72f" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" + +"@webassemblyjs/wast-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz#5727a705d397ae6a3ae99d7f5460acf2ec646eea" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/floating-point-hex-parser" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-code-frame" "1.5.13" + "@webassemblyjs/helper-fsm" "1.5.13" + long "^3.2.0" + mamacro "^0.0.3" + +"@webassemblyjs/wast-printer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz#bb34d528c14b4f579e7ec11e793ec50ad7cd7c95" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" + long "^3.2.0" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +accepts@~1.3.4, accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" + +acorn@^5.0.0, acorn@^5.6.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5" + +ajv-keywords@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + +ajv@^6.1.0: + version "6.5.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.0.5.tgz#cb9dc64993b64fd6945485f797fc3853137d9a7b" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-flatten@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + dependencies: + lodash "^4.17.10" + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + +awesome-typescript-loader@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/awesome-typescript-loader/-/awesome-typescript-loader-5.2.0.tgz#d7bccf4823c45096ec24da4c12a1507d276ba15a" + dependencies: + chalk "^2.4.1" + enhanced-resolve "^4.0.0" + loader-utils "^1.1.0" + lodash "^4.17.5" + micromatch "^3.1.9" + mkdirp "^0.5.1" + source-map-support "^0.5.3" + webpack-log "^1.2.0" + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +backo2@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +bindings@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" + +bluebird@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +body-parser@1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + +body-parser@^1.15.2: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + +buffer-writer@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-1.0.1.tgz#22a936901e3029afcd7547eb4487ceb697a3bf08" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +chalk@^1.1.3: + version "1.1.3" + resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + +chokidar@^2.0.0, chokidar@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + dependencies: + tslib "^1.9.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +commander@^2.12.1, commander@^2.9.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +compressible@~2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" + dependencies: + mime-db ">= 1.34.0 < 2" + +compression@^1.5.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.14" + debug "2.6.9" + on-headers "~1.0.1" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect-history-api-fallback@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +crc@3.4.4: + version "3.4.4" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@2.6.9, "debug@>=2 <3", debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decamelize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + dependencies: + xregexp "4.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + dependencies: + globby "^6.1.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + p-map "^1.1.1" + pify "^3.0.0" + rimraf "^2.2.8" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-node@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + +diff@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + dependencies: + buffer-indexof "^1.0.0" + +doctrine@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" + dependencies: + esutils "^1.1.6" + isarray "0.0.1" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecdsa-sig-formatter@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3" + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +elliptic@^6.0.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.2.tgz#4ae8dbaa2bf90a8b450707b9149dcabca135520d" + dependencies: + stackframe "^1.0.4" + +es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.46" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.46.tgz#efd99f67c5a7ec789baa3daa7f79870388f7f572" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "1" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +eventemitter3@^3.0.0, eventemitter3@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +eventsource@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" + dependencies: + original ">=0.0.5" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express-session@1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.15.6.tgz#47b4160c88f42ab70fe8a508e31cbff76757ab0a" + dependencies: + cookie "0.3.1" + cookie-signature "1.0.6" + crc "3.4.4" + debug "2.6.9" + depd "~1.1.1" + on-headers "~1.0.1" + parseurl "~1.3.2" + uid-safe "~2.1.5" + utils-merge "1.0.1" + +express@^4.16.2: + version "4.16.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.3" + qs "6.5.1" + range-parser "~1.2.0" + safe-buffer "5.1.1" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +external-editor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + dependencies: + websocket-driver ">=0.5.1" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1, finalhandler@^1.0.6: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +follow-redirects@^1.0.0: + version "1.5.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.7.tgz#a39e4804dacb90202bca76a9e2ac10433ca6a69a" + dependencies: + debug "^3.1.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +generic-pool@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.4.3.tgz#780c36f69dfad05a5a045dd37be7adca11a4f6ff" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules-path@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +graphile-build-pg@4.0.0-rc.9: + version "4.0.0-rc.9" + resolved "https://registry.yarnpkg.com/graphile-build-pg/-/graphile-build-pg-4.0.0-rc.9.tgz#241d3776bbb12b48cb7cbc599b80f51cf4133a00" + dependencies: + chalk "^2.1.0" + debug ">=2 <3" + graphile-build "4.0.0-rc.9" + graphql-iso-date "^3.2.0" + jsonwebtoken "^8.1.1" + lodash ">=4 <5" + lru-cache ">=4 <5" + pg-sql2 "2.2.1" + postgres-interval "1.1.1" + +graphile-build@4.0.0-rc.9: + version "4.0.0-rc.9" + resolved "https://registry.yarnpkg.com/graphile-build/-/graphile-build-4.0.0-rc.9.tgz#8fb16994c65f21b7900c76dd6a67c037f5bb00ee" + dependencies: + "@types/graphql" "^0.13.4" + debug ">=2 <3" + graphql-parse-resolve-info "4.0.0-rc.8" + lodash ">=4 <5" + lru-cache ">=4 <5" + pluralize "7.0.0" + +graphql-iso-date@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/graphql-iso-date/-/graphql-iso-date-3.5.0.tgz#55a1be0efa8d28c1453afd2eb5ce1d052189a513" + +graphql-parse-resolve-info@4.0.0-rc.8: + version "4.0.0-rc.8" + resolved "https://registry.yarnpkg.com/graphql-parse-resolve-info/-/graphql-parse-resolve-info-4.0.0-rc.8.tgz#32ef7981411c72e7292fc765222127710cc088dc" + dependencies: + "@types/graphql" "^0.13.4" + debug ">=2 <3" + +graphql-subscriptions@0.5.8: + version "0.5.8" + resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-0.5.8.tgz#13a6143c546bce390404657dc73ca501def30aa7" + dependencies: + iterall "^1.2.1" + +"graphql@^0.6.0 || ^0.7.0 || ^0.8.0-b || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0": + version "0.13.2" + resolved "http://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270" + dependencies: + iterall "^1.2.1" + +handle-thing@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + +http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.0.tgz#b6d36492a201c7888bdcb5dd0471140423c4ad2a" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-parser-js@>=0.4.0: + version "0.4.13" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" + +http-proxy-middleware@~0.18.0: + version "0.18.0" + resolved "http://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" + dependencies: + http-proxy "^1.16.2" + is-glob "^4.0.0" + lodash "^4.17.5" + micromatch "^3.1.9" + +http-proxy@^1.16.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + dependencies: + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.11, ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +inquirer@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.0" + figures "^2.0.0" + lodash "^4.17.10" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.1.0" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +internal-ip@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" + dependencies: + meow "^3.3.0" + +interpret@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +iterall@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" + +jasmine-core@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.2.1.tgz#8e4ff5b861603ee83343f2b49eee6a0ffe9650ce" + +jasmine-ts-console-reporter@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/jasmine-ts-console-reporter/-/jasmine-ts-console-reporter-3.1.1.tgz#86ce9a557f3073431130954b66c3c6bd77ce56ef" + dependencies: + error-stack-parser "^2.0.1" + minimatch "^3.0.4" + source-map "^0.5.7" + source-map-resolve "^0.5.0" + +jasmine@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.2.0.tgz#b3a018454781805650e46578803d08e7cfdd7b3d" + dependencies: + glob "^7.0.6" + jasmine-core "~3.2.0" + +js-string-escape@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.7.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonwebtoken@^8.0.0, jsonwebtoken@^8.1.1: + version "8.3.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz#056c90eee9a65ed6e6c72ddb0a1d325109aaf643" + dependencies: + jws "^3.1.5" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + +jwa@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.6.tgz#87240e76c9808dbde18783cf2264ef4929ee50e6" + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.10" + safe-buffer "^5.0.1" + +jws@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.5.tgz#80d12d05b293d1e841e7cb8b4e69e561adcf834f" + dependencies: + jwa "^1.1.5" + safe-buffer "^5.0.1" + +killable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +libpq@^1.7.0: + version "1.8.8" + resolved "https://registry.yarnpkg.com/libpq/-/libpq-1.8.8.tgz#805005723c15c061185ae5cd8128b6e4174c1810" + dependencies: + bindings "1.2.1" + nan "^2.10.0" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash@4.17.10, "lodash@>=3.5 <5", "lodash@>=4 <5", lodash@^4.17.10, lodash@^4.17.5: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +log-symbols@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +loglevel@^1.4.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" + +loglevelnext@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" + dependencies: + es6-symbol "^3.1.1" + object.assign "^4.1.0" + +long@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + +long@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" + +loud-rejection@^1.0.0, loud-rejection@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +"lru-cache@>=4 <5", lru-cache@^4.0.1, lru-cache@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.3.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +"mime-db@>= 1.34.0 < 2", mime-db@~1.36.0: + version "1.36.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" + +mime-types@~2.1.17, mime-types@~2.1.18: + version "2.1.20" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" + dependencies: + mime-db "~1.36.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mime@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: + version "0.5.1" + resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment@>=2.14.0: + version "2.22.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.10.0, nan@^2.9.2: + version "2.11.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.2.tgz#1120ca4c41f2fcc6976fd28a8968afe239929418" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +neo-async@^2.5.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.2.tgz#489105ce7bc54e709d736b195f82135048c50fcc" + +next-tick@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" + +npm-packlist@^1.1.6: + version "1.1.11" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +obuf@^1.0.0, obuf@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +opn@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + dependencies: + is-wsl "^1.1.0" + +original@>=0.0.5: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +p-try@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + +packet-reader@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.3.1.tgz#cd62e60af8d7fea8a705ec4ff990871c46871f27" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parseurl@^1.3.1, parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +passport-strategy@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + +passport@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811" + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + +pbkdf2@^3.0.3: + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pg-connection-string@0.1.3, pg-connection-string@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + +pg-native@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pg-native/-/pg-native-3.0.0.tgz#20c64e651e20b28f5c060b3823522d1c8c4429c3" + dependencies: + libpq "^1.7.0" + pg-types "^1.12.1" + readable-stream "1.0.31" + +pg-pool@1.*: + version "1.8.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.8.0.tgz#f7ec73824c37a03f076f51bfdf70e340147c4f37" + dependencies: + generic-pool "2.4.3" + object-assign "4.1.0" + +pg-sql2@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/pg-sql2/-/pg-sql2-2.2.1.tgz#a37612e5243887c5135a6849dec1f20b2cf00553" + dependencies: + "@types/pg" "^7.4.10" + debug ">=2 <3" + +pg-types@1.*, pg-types@^1.12.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.13.0.tgz#75f490b8a8abf75f1386ef5ec4455ecf6b345c63" + dependencies: + pg-int8 "1.0.1" + postgres-array "~1.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.0" + postgres-interval "^1.1.0" + +pg@6.4.2, "pg@>=6.1.0 <8": + version "6.4.2" + resolved "https://registry.yarnpkg.com/pg/-/pg-6.4.2.tgz#c364011060eac7a507a2ae063eb857ece910e27f" + dependencies: + buffer-writer "1.0.1" + js-string-escape "1.0.1" + packet-reader "0.3.1" + pg-connection-string "0.1.3" + pg-pool "1.*" + pg-types "1.*" + pgpass "1.*" + semver "4.3.2" + +pgpass@1.*: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.2.tgz#2a7bb41b6065b67907e91da1b07c1847c877b306" + dependencies: + split "^1.0.0" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + +pluralize@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + +portfinder@^1.0.9: + version "1.0.17" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.17.tgz#a8a1691143e46c4735edefcf4fbcccedad26456a" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postgraphile-core@4.0.0-rc.9: + version "4.0.0-rc.9" + resolved "https://registry.yarnpkg.com/postgraphile-core/-/postgraphile-core-4.0.0-rc.9.tgz#7dc9bf1d0da3a4f81bd68b3977d27ed174a5c72f" + dependencies: + "@types/graphql" "^0.13.4" + graphile-build "4.0.0-rc.9" + graphile-build-pg "4.0.0-rc.9" + +postgraphile@4.0.0-rc.4: + version "4.0.0-rc.4" + resolved "https://registry.yarnpkg.com/postgraphile/-/postgraphile-4.0.0-rc.4.tgz#15a610c28bce2e077fc34d5b4600504c2b86cb39" + dependencies: + "@types/graphql" "^0.13.4" + "@types/jsonwebtoken" "<7.2.1" + "@types/koa" "2.0.44" + "@types/pg" "^7.4.10" + body-parser "^1.15.2" + chalk "^1.1.3" + commander "^2.9.0" + debug "^2.3.3" + finalhandler "^1.0.6" + graphql "^0.6.0 || ^0.7.0 || ^0.8.0-b || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0" + http-errors "^1.5.1" + jsonwebtoken "^8.0.0" + lodash ">=3.5 <5" + lru-cache ">=4 <5" + parseurl "^1.3.1" + pg ">=6.1.0 <8" + pg-connection-string "^0.1.3" + pg-sql2 "2.2.1" + postgraphile-core "4.0.0-rc.9" + send "^0.16.1" + tslib "^1.5.0" + +postgres-array@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-1.0.2.tgz#8e0b32eb03bf77a5c0a7851e0441c169a256a238" + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + +postgres-date@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8" + +postgres-interval@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.1.1.tgz#acdb0f897b4b1c6e496d9d4e0a853e1c428f06f0" + dependencies: + xtend "^4.0.0" + +postgres-interval@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.1.2.tgz#bf71ff902635f21cb241a013fc421d81d1db15a9" + dependencies: + xtend "^4.0.0" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + +proxy-addr@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +qs@6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +querystringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755" + +random-bytes@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.0.3, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@1.0.31: + version "1.0.31" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.31.tgz#8f2502e0bc9e3b0da1b94520aabb4e2603ecafae" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@^1.3.2: + version "1.8.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + +rxjs@^6.1.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.2.tgz#6a688b16c4e6e980e62ea805ec30648e1c60907f" + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +schema-utils@^0.4.4, schema-utils@^0.4.5: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + +selfsigned@^1.9.1: + version "1.10.3" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.3.tgz#d628ecf9e3735f84e8bafba936b3cf85bea43823" + dependencies: + node-forge "0.7.5" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0: + version "5.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" + +semver@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" + +send@0.16.2, send@^0.16.1: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" + +serve-index@^1.7.2: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83" + dependencies: + debug "^2.6.6" + eventsource "0.1.6" + faye-websocket "~0.11.0" + inherits "^2.0.1" + json3 "^3.3.2" + url-parse "^1.1.8" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + +source-map-loader@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-0.2.4.tgz#c18b0dc6e23bf66f6792437557c569a11e072271" + dependencies: + async "^2.5.0" + loader-utils "^1.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.3: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +spdy-transport@^2.0.18: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.0.tgz#4bbb15aaffed0beefdd56ad61dbdc8ba3e2cb7a1" + dependencies: + debug "^2.6.8" + detect-node "^2.0.3" + hpack.js "^2.1.6" + obuf "^1.1.1" + readable-stream "^2.2.9" + safe-buffer "^5.0.1" + wbuf "^1.7.2" + +spdy@^3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" + dependencies: + debug "^2.6.8" + handle-thing "^1.2.5" + http-deceiver "^1.2.7" + safe-buffer "^5.0.1" + select-hose "^2.0.0" + spdy-transport "^2.0.18" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + +stackframe@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.0.4.tgz#357b24a992f9427cba6b545d96a14ed2cbca187b" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +subscriptions-transport-ws@0.9.14: + version "0.9.14" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.14.tgz#a39e08edba89ee4cfd95f30484c55d865f5d8451" + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + +symbol-observable@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + +tapable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" + +tar@^4: + version "4.4.6" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@2, through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +thunky@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + dependencies: + setimmediate "^1.0.4" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + +toml@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.3.tgz#8d683d729577cb286231dfc7a8affe58d31728fb" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +tslib@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + +tslib@^1.5.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + +tslint-eslint-rules@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5" + dependencies: + doctrine "0.7.2" + tslib "1.9.0" + tsutils "^3.0.0" + +tslint@5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" + dependencies: + babel-code-frame "^6.22.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^3.2.0" + glob "^7.1.1" + js-yaml "^3.7.0" + minimatch "^3.0.4" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.27.2" + +tsutils@^2.27.2: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + dependencies: + tslib "^1.8.1" + +tsutils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.0.0.tgz#0c5070a17a0503e056da038c48b5a1870a50a9ad" + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +type-is@~1.6.15, type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typescript@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.0.1.tgz#43738f29585d3a87575520a4b93ab6026ef11fdb" + +uglify-es@^3.3.4: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + +uglifyjs-webpack-plugin@^1.2.4: + version "1.3.0" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de" + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + schema-utils "^0.4.5" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +uid-safe@~2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" + dependencies: + random-bytes "~1.0.0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-join@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" + +url-parse@^1.1.8, url-parse@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.3.tgz#bfaee455c889023219d757e045fa6a684ec36c15" + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +v8-compile-cache@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + dependencies: + minimalistic-assert "^1.0.0" + +webpack-cli@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.0.tgz#d71a83687dcfeb758fdceeb0fe042f96bcf62994" + dependencies: + chalk "^2.4.1" + cross-spawn "^6.0.5" + enhanced-resolve "^4.0.0" + global-modules-path "^2.1.0" + import-local "^1.0.0" + inquirer "^6.0.0" + interpret "^1.1.0" + loader-utils "^1.1.0" + supports-color "^5.4.0" + v8-compile-cache "^2.0.0" + yargs "^12.0.1" + +webpack-dev-middleware@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.2.0.tgz#a20ceef194873710052da678f3c6ee0aeed92552" + dependencies: + loud-rejection "^1.6.0" + memory-fs "~0.4.1" + mime "^2.3.1" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + url-join "^4.0.0" + webpack-log "^2.0.0" + +webpack-dev-server@3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.6.tgz#8617503768b1131fd539cf43c3e2e63bd34c1521" + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.0.0" + compression "^1.5.2" + connect-history-api-fallback "^1.3.0" + debug "^3.1.0" + del "^3.0.0" + express "^4.16.2" + html-entities "^1.2.0" + http-proxy-middleware "~0.18.0" + import-local "^1.0.0" + internal-ip "1.2.0" + ip "^1.1.5" + killable "^1.0.0" + loglevel "^1.4.1" + opn "^5.1.0" + portfinder "^1.0.9" + selfsigned "^1.9.1" + serve-index "^1.7.2" + sockjs "0.3.19" + sockjs-client "1.1.5" + spdy "^3.4.1" + strip-ansi "^3.0.0" + supports-color "^5.1.0" + webpack-dev-middleware "3.2.0" + webpack-log "^2.0.0" + yargs "12.0.1" + +webpack-log@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" + dependencies: + chalk "^2.1.0" + log-symbols "^2.1.0" + loglevelnext "^1.0.1" + uuid "^3.1.0" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-sources@^1.0.1, webpack-sources@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.2.0.tgz#18181e0d013fce096faf6f8e6d41eeffffdceac2" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.17.1.tgz#0f026e3d823f3fc604f811ed3ea8f0d9b267fb1e" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/wasm-edit" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + acorn "^5.6.2" + acorn-dynamic-import "^3.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^0.4.4" + tapable "^1.0.0" + uglifyjs-webpack-plugin "^1.2.4" + watchpack "^1.5.0" + webpack-sources "^1.0.1" + +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + +xregexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + dependencies: + camelcase "^4.1.0" + +yargs@12.0.1, yargs@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.1.tgz#6432e56123bb4e7c3562115401e98374060261c2" + dependencies: + cliui "^4.0.0" + decamelize "^2.0.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^10.1.0" diff --git a/scripts/create_migration b/scripts/create_migration deleted file mode 100755 index 23148ff6..00000000 --- a/scripts/create_migration +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -if [ $# -eq 1 ] -then - migrate create -dir ./db/migrations -ext sql $1 -else - echo "**An Error Occurred**" - echo "Usage: ./scripts/create_migration " -fi diff --git a/scripts/reset_db b/scripts/reset_db new file mode 100755 index 00000000..c7870271 --- /dev/null +++ b/scripts/reset_db @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Provide me with a postgres database name, and I will: +# - Drop the database +# - Recreate the database +# - Run the vulcanizedb migration + +if [ "$1" = "" ]; then + echo "Provide a database name to reset" + exit 1 +fi + +db=$1 +dir=$(basename "$(pwd)") +if [ $dir != "vulcanizedb" ] +then + echo "Run me from the vulcanizedb root dir" + exit 1 +fi + +user=$(whoami) +psql -c "DROP DATABASE $db" postgres +if [ $? -eq 0 ]; then + psql -c "CREATE DATABASE $db WITH OWNER $user" postgres + make migrate HOST_NAME=localhost NAME=$db PORT=5432 +else + echo "Couldnt drop the database. Are you connected? Does it exist?" +fi diff --git a/scripts/start_blockchain b/scripts/start_blockchain deleted file mode 100755 index fbec61d7..00000000 --- a/scripts/start_blockchain +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -geth --fast --cache=1024 diff --git a/test_config/test_config.go b/test_config/test_config.go index 2c3bfa1d..13e42e8c 100644 --- a/test_config/test_config.go +++ b/test_config/test_config.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,10 +17,12 @@ package test_config import ( - "log" + "errors" + "fmt" "os" . "github.com/onsi/gomega" + log "github.com/sirupsen/logrus" "github.com/spf13/viper" "github.com/vulcanize/vulcanizedb/pkg/config" @@ -47,13 +49,14 @@ func setTestConfig() { TestConfig.SetConfigName("private") TestConfig.AddConfigPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/environments/") err := TestConfig.ReadInConfig() - ipc := TestConfig.GetString("client.ipcPath") if err != nil { log.Fatal(err) } + ipc := TestConfig.GetString("client.ipcPath") hn := TestConfig.GetString("database.hostname") port := TestConfig.GetInt("database.port") name := TestConfig.GetString("database.name") + DBConfig = config.Database{ Hostname: hn, Name: name, @@ -69,10 +72,20 @@ func setInfuraConfig() { Infura.SetConfigName("infura") Infura.AddConfigPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/environments/") err := Infura.ReadInConfig() - ipc := Infura.GetString("client.ipcpath") if err != nil { log.Fatal(err) } + ipc := Infura.GetString("client.ipcpath") + + // If we don't have an ipc path in the config file, check the env variable + if ipc == "" { + Infura.BindEnv("url", "INFURA_URL") + ipc = Infura.GetString("url") + } + if ipc == "" { + log.Fatal(errors.New("infura.toml IPC path or $INFURA_URL env variable need to be set")) + } + InfuraClient = config.Client{ IPCPath: ipc, } @@ -84,21 +97,36 @@ func setABIPath() { } func NewTestDB(node core.Node) *postgres.DB { - db, _ := postgres.NewDB(DBConfig, node) + db, err := postgres.NewDB(DBConfig, node) + if err != nil { + panic(fmt.Sprintf("Could not create new test db: %v", err)) + } return db } func CleanTestDB(db *postgres.DB) { db.MustExec("DELETE FROM blocks") - db.MustExec("DELETE FROM headers") db.MustExec("DELETE FROM checked_headers") + // can't delete from eth_nodes since this function is called after the required eth_node is persisted + db.MustExec("DELETE FROM full_sync_transactions") + db.MustExec("DELETE FROM goose_db_version") + db.MustExec("DELETE FROM headers") + db.MustExec("DELETE FROM light_sync_transactions") db.MustExec("DELETE FROM log_filters") db.MustExec("DELETE FROM logs") - db.MustExec("DELETE FROM receipts") - db.MustExec("DELETE FROM transactions") + db.MustExec("DELETE FROM queued_storage") + db.MustExec("DELETE FROM full_sync_receipts") + db.MustExec("DELETE FROM light_sync_receipts") db.MustExec("DELETE FROM watched_contracts") } +func CleanCheckedHeadersTable(db *postgres.DB, columnNames []string) { + for _, name := range columnNames { + db.MustExec("ALTER TABLE checked_headers DROP COLUMN IF EXISTS " + name) + } +} + +// Returns a new test node, with the same ID func NewTestNode() core.Node { return core.Node{ GenesisBlock: "GENESIS", @@ -114,8 +142,3 @@ func NewTestBlock(blockNumber int64, repository repositories.BlockRepository) (b return blockId } - -func NewTestDBWithoutDeletingRecords(node core.Node) *postgres.DB { - db, _ := postgres.NewDB(DBConfig, node) - return db -} diff --git a/utils/utils.go b/utils/utils.go index 8f78250b..bf098ef5 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,5 +1,5 @@ // VulcanizeDB -// Copyright © 2018 Vulcanize +// Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,7 +17,7 @@ package utils import ( - "log" + log "github.com/sirupsen/logrus" "math/big" "os" "path/filepath" diff --git a/vendor/github.com/allegro/bigcache/.gitignore b/vendor/github.com/allegro/bigcache/.gitignore new file mode 100644 index 00000000..372c42cb --- /dev/null +++ b/vendor/github.com/allegro/bigcache/.gitignore @@ -0,0 +1,5 @@ +.idea +.DS_Store +/server/server.exe +/server/server +CHANGELOG.md diff --git a/vendor/github.com/allegro/bigcache/.travis.yml b/vendor/github.com/allegro/bigcache/.travis.yml new file mode 100644 index 00000000..a9d987ef --- /dev/null +++ b/vendor/github.com/allegro/bigcache/.travis.yml @@ -0,0 +1,31 @@ +language: go + +go: + - 1.x + - tip + +matrix: + allow_failures: + - go: tip + fast_finish: true + +before_install: + - go get github.com/modocache/gover + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover + - go get golang.org/x/tools/cmd/goimports + - go get github.com/golang/lint/golint + - go get github.com/stretchr/testify/assert + - go get github.com/gordonklaus/ineffassign + +script: + - gofiles=$(find ./ -name '*.go') && [ -z "$gofiles" ] || unformatted=$(goimports -l $gofiles) && [ -z "$unformatted" ] || (echo >&2 "Go files must be formatted with gofmt. Following files has problem:\n $unformatted" && false) + - diff <(echo -n) <(gofmt -s -d .) + - golint ./... # This won't break the build, just show warnings + - ineffassign . + - go vet ./... + - go test -race -count=1 -coverprofile=queue.coverprofile ./queue + - go test -race -count=1 -coverprofile=server.coverprofile ./server + - go test -race -count=1 -coverprofile=main.coverprofile + - $HOME/gopath/bin/gover + - $HOME/gopath/bin/goveralls -coverprofile=gover.coverprofile -service travis-ci diff --git a/vendor/github.com/allegro/bigcache/LICENSE b/vendor/github.com/allegro/bigcache/LICENSE new file mode 100644 index 00000000..8dada3ed --- /dev/null +++ b/vendor/github.com/allegro/bigcache/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/allegro/bigcache/README.md b/vendor/github.com/allegro/bigcache/README.md new file mode 100644 index 00000000..cd462d36 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/README.md @@ -0,0 +1,145 @@ +# BigCache [![Build Status](https://travis-ci.org/allegro/bigcache.svg?branch=master)](https://travis-ci.org/allegro/bigcache) [![Coverage Status](https://coveralls.io/repos/github/allegro/bigcache/badge.svg?branch=master)](https://coveralls.io/github/allegro/bigcache?branch=master) [![GoDoc](https://godoc.org/github.com/allegro/bigcache?status.svg)](https://godoc.org/github.com/allegro/bigcache) [![Go Report Card](https://goreportcard.com/badge/github.com/allegro/bigcache)](https://goreportcard.com/report/github.com/allegro/bigcache) + +Fast, concurrent, evicting in-memory cache written to keep big number of entries without impact on performance. +BigCache keeps entries on heap but omits GC for them. To achieve that operations on bytes arrays take place, +therefore entries (de)serialization in front of the cache will be needed in most use cases. + +## Usage + +### Simple initialization + +```go +import "github.com/allegro/bigcache" + +cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute)) + +cache.Set("my-unique-key", []byte("value")) + +entry, _ := cache.Get("my-unique-key") +fmt.Println(string(entry)) +``` + +### Custom initialization + +When cache load can be predicted in advance then it is better to use custom initialization because additional memory +allocation can be avoided in that way. + +```go +import ( + "log" + + "github.com/allegro/bigcache" +) + +config := bigcache.Config { + // number of shards (must be a power of 2) + Shards: 1024, + // time after which entry can be evicted + LifeWindow: 10 * time.Minute, + // rps * lifeWindow, used only in initial memory allocation + MaxEntriesInWindow: 1000 * 10 * 60, + // max entry size in bytes, used only in initial memory allocation + MaxEntrySize: 500, + // prints information about additional memory allocation + Verbose: true, + // cache will not allocate more memory than this limit, value in MB + // if value is reached then the oldest entries can be overridden for the new ones + // 0 value means no size limit + HardMaxCacheSize: 8192, + // callback fired when the oldest entry is removed because of its + // expiration time or no space left for the new entry. Default value is nil which + // means no callback and it prevents from unwrapping the oldest entry. + OnRemove: nil, + } + +cache, initErr := bigcache.NewBigCache(config) +if initErr != nil { + log.Fatal(initErr) +} + +cache.Set("my-unique-key", []byte("value")) + +if entry, err := cache.Get("my-unique-key"); err == nil { + fmt.Println(string(entry)) +} +``` + +## Benchmarks + +Three caches were compared: bigcache, [freecache](https://github.com/coocood/freecache) and map. +Benchmark tests were made using an i7-6700K with 32GB of RAM on Windows 10. + +### Writes and reads + +```bash +cd caches_bench; go test -bench=. -benchtime=10s ./... -timeout 30m + +BenchmarkMapSet-8 2000000 716 ns/op 336 B/op 3 allocs/op +BenchmarkConcurrentMapSet-8 1000000 1292 ns/op 347 B/op 8 allocs/op +BenchmarkFreeCacheSet-8 3000000 501 ns/op 371 B/op 3 allocs/op +BenchmarkBigCacheSet-8 3000000 482 ns/op 303 B/op 2 allocs/op +BenchmarkMapGet-8 5000000 309 ns/op 24 B/op 1 allocs/op +BenchmarkConcurrentMapGet-8 2000000 659 ns/op 24 B/op 2 allocs/op +BenchmarkFreeCacheGet-8 3000000 541 ns/op 152 B/op 3 allocs/op +BenchmarkBigCacheGet-8 3000000 420 ns/op 152 B/op 3 allocs/op +BenchmarkBigCacheSetParallel-8 10000000 184 ns/op 313 B/op 3 allocs/op +BenchmarkFreeCacheSetParallel-8 10000000 195 ns/op 357 B/op 4 allocs/op +BenchmarkConcurrentMapSetParallel-8 5000000 242 ns/op 200 B/op 6 allocs/op +BenchmarkBigCacheGetParallel-8 20000000 100 ns/op 152 B/op 4 allocs/op +BenchmarkFreeCacheGetParallel-8 10000000 133 ns/op 152 B/op 4 allocs/op +BenchmarkConcurrentMapGetParallel-8 10000000 202 ns/op 24 B/op 2 allocs/op +``` + +Writes and reads in bigcache are faster than in freecache. +Writes to map are the slowest. + +### GC pause time + +```bash +cd caches_bench; go run caches_gc_overhead_comparison.go + +Number of entries: 20000000 +GC pause for bigcache: 5.8658ms +GC pause for freecache: 32.4341ms +GC pause for map: 52.9661ms +``` + +Test shows how long are the GC pauses for caches filled with 20mln of entries. +Bigcache and freecache have very similar GC pause time. +It is clear that both reduce GC overhead in contrast to map +which GC pause time took more than 10 seconds. + +## How it works + +BigCache relies on optimization presented in 1.5 version of Go ([issue-9477](https://github.com/golang/go/issues/9477)). +This optimization states that if map without pointers in keys and values is used then GC will omit its content. +Therefore BigCache uses `map[uint64]uint32` where keys are hashed and values are offsets of entries. + +Entries are kept in bytes array, to omit GC again. +Bytes array size can grow to gigabytes without impact on performance +because GC will only see single pointer to it. + +## Bigcache vs Freecache + +Both caches provide the same core features but they reduce GC overhead in different ways. +Bigcache relies on `map[uint64]uint32`, freecache implements its own mapping built on +slices to reduce number of pointers. + +Results from benchmark tests are presented above. +One of the advantage of bigcache over freecache is that you don’t need to know +the size of the cache in advance, because when bigcache is full, +it can allocate additional memory for new entries instead of +overwriting existing ones as freecache does currently. +However hard max size in bigcache also can be set, check [HardMaxCacheSize](https://godoc.org/github.com/allegro/bigcache#Config). + +## HTTP Server + +This package also includes an easily deployable HTTP implementation of BigCache, which can be found in the [server](/server) package. + +## More + +Bigcache genesis is described in allegro.tech blog post: [writing a very fast cache service in Go](http://allegro.tech/2016/03/writing-fast-cache-service-in-go.html) + +## License + +BigCache is released under the Apache 2.0 license (see [LICENSE](LICENSE)) diff --git a/vendor/github.com/allegro/bigcache/bigcache.go b/vendor/github.com/allegro/bigcache/bigcache.go new file mode 100644 index 00000000..3a6f6bd6 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/bigcache.go @@ -0,0 +1,155 @@ +package bigcache + +import ( + "fmt" + "time" +) + +const ( + minimumEntriesInShard = 10 // Minimum number of entries in single shard +) + +// BigCache is fast, concurrent, evicting cache created to keep big number of entries without impact on performance. +// It keeps entries on heap but omits GC for them. To achieve that operations on bytes arrays take place, +// therefore entries (de)serialization in front of the cache will be needed in most use cases. +type BigCache struct { + shards []*cacheShard + lifeWindow uint64 + clock clock + hash Hasher + config Config + shardMask uint64 + maxShardSize uint32 +} + +// NewBigCache initialize new instance of BigCache +func NewBigCache(config Config) (*BigCache, error) { + return newBigCache(config, &systemClock{}) +} + +func newBigCache(config Config, clock clock) (*BigCache, error) { + + if !isPowerOfTwo(config.Shards) { + return nil, fmt.Errorf("Shards number must be power of two") + } + + if config.Hasher == nil { + config.Hasher = newDefaultHasher() + } + + cache := &BigCache{ + shards: make([]*cacheShard, config.Shards), + lifeWindow: uint64(config.LifeWindow.Seconds()), + clock: clock, + hash: config.Hasher, + config: config, + shardMask: uint64(config.Shards - 1), + maxShardSize: uint32(config.maximumShardSize()), + } + + var onRemove func(wrappedEntry []byte) + if config.OnRemove == nil { + onRemove = cache.notProvidedOnRemove + } else { + onRemove = cache.providedOnRemove + } + + for i := 0; i < config.Shards; i++ { + cache.shards[i] = initNewShard(config, onRemove, clock) + } + + if config.CleanWindow > 0 { + go func() { + for t := range time.Tick(config.CleanWindow) { + cache.cleanUp(uint64(t.Unix())) + } + }() + } + + return cache, nil +} + +// Get reads entry for the key. +// It returns an EntryNotFoundError when +// no entry exists for the given key. +func (c *BigCache) Get(key string) ([]byte, error) { + hashedKey := c.hash.Sum64(key) + shard := c.getShard(hashedKey) + return shard.get(key, hashedKey) +} + +// Set saves entry under the key +func (c *BigCache) Set(key string, entry []byte) error { + hashedKey := c.hash.Sum64(key) + shard := c.getShard(hashedKey) + return shard.set(key, hashedKey, entry) +} + +// Delete removes the key +func (c *BigCache) Delete(key string) error { + hashedKey := c.hash.Sum64(key) + shard := c.getShard(hashedKey) + return shard.del(key, hashedKey) +} + +// Reset empties all cache shards +func (c *BigCache) Reset() error { + for _, shard := range c.shards { + shard.reset(c.config) + } + return nil +} + +// Len computes number of entries in cache +func (c *BigCache) Len() int { + var len int + for _, shard := range c.shards { + len += shard.len() + } + return len +} + +// Stats returns cache's statistics +func (c *BigCache) Stats() Stats { + var s Stats + for _, shard := range c.shards { + tmp := shard.getStats() + s.Hits += tmp.Hits + s.Misses += tmp.Misses + s.DelHits += tmp.DelHits + s.DelMisses += tmp.DelMisses + s.Collisions += tmp.Collisions + } + return s +} + +// Iterator returns iterator function to iterate over EntryInfo's from whole cache. +func (c *BigCache) Iterator() *EntryInfoIterator { + return newIterator(c) +} + +func (c *BigCache) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func() error) bool { + oldestTimestamp := readTimestampFromEntry(oldestEntry) + if currentTimestamp-oldestTimestamp > c.lifeWindow { + evict() + return true + } + return false +} + +func (c *BigCache) cleanUp(currentTimestamp uint64) { + for _, shard := range c.shards { + shard.cleanUp(currentTimestamp) + } +} + +func (c *BigCache) getShard(hashedKey uint64) (shard *cacheShard) { + return c.shards[hashedKey&c.shardMask] +} + +func (c *BigCache) providedOnRemove(wrappedEntry []byte) { + c.config.OnRemove(readKeyFromEntry(wrappedEntry), readEntry(wrappedEntry)) +} + +func (c *BigCache) notProvidedOnRemove(wrappedEntry []byte) { +} diff --git a/vendor/github.com/allegro/bigcache/bigcache_bench_test.go b/vendor/github.com/allegro/bigcache/bigcache_bench_test.go new file mode 100644 index 00000000..59d0061d --- /dev/null +++ b/vendor/github.com/allegro/bigcache/bigcache_bench_test.go @@ -0,0 +1,141 @@ +package bigcache + +import ( + "fmt" + "math/rand" + "strconv" + "testing" + "time" +) + +var message = blob('a', 256) + +func BenchmarkWriteToCacheWith1Shard(b *testing.B) { + writeToCache(b, 1, 100*time.Second, b.N) +} + +func BenchmarkWriteToLimitedCacheWithSmallInitSizeAnd1Shard(b *testing.B) { + m := blob('a', 1024) + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: 100 * time.Second, + MaxEntriesInWindow: 100, + MaxEntrySize: 256, + HardMaxCacheSize: 1, + }) + + b.ReportAllocs() + for i := 0; i < b.N; i++ { + cache.Set(fmt.Sprintf("key-%d", i), m) + } +} + +func BenchmarkWriteToUnlimitedCacheWithSmallInitSizeAnd1Shard(b *testing.B) { + m := blob('a', 1024) + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: 100 * time.Second, + MaxEntriesInWindow: 100, + MaxEntrySize: 256, + }) + + b.ReportAllocs() + for i := 0; i < b.N; i++ { + cache.Set(fmt.Sprintf("key-%d", i), m) + } +} + +func BenchmarkWriteToCache(b *testing.B) { + for _, shards := range []int{1, 512, 1024, 8192} { + b.Run(fmt.Sprintf("%d-shards", shards), func(b *testing.B) { + writeToCache(b, shards, 100*time.Second, b.N) + }) + } +} + +func BenchmarkReadFromCache(b *testing.B) { + for _, shards := range []int{1, 512, 1024, 8192} { + b.Run(fmt.Sprintf("%d-shards", shards), func(b *testing.B) { + readFromCache(b, 1024) + }) + } +} + +func BenchmarkIterateOverCache(b *testing.B) { + + m := blob('a', 1) + + for _, shards := range []int{512, 1024, 8192} { + b.Run(fmt.Sprintf("%d-shards", shards), func(b *testing.B) { + cache, _ := NewBigCache(Config{ + Shards: shards, + LifeWindow: 1000 * time.Second, + MaxEntriesInWindow: max(b.N, 100), + MaxEntrySize: 500, + }) + + for i := 0; i < b.N; i++ { + cache.Set(fmt.Sprintf("key-%d", i), m) + } + + b.ResetTimer() + it := cache.Iterator() + + b.RunParallel(func(pb *testing.PB) { + b.ReportAllocs() + + for pb.Next() { + if it.SetNext() { + it.Value() + } + } + }) + }) + } +} + +func BenchmarkWriteToCacheWith1024ShardsAndSmallShardInitSize(b *testing.B) { + writeToCache(b, 1024, 100*time.Second, 100) +} + +func writeToCache(b *testing.B, shards int, lifeWindow time.Duration, requestsInLifeWindow int) { + cache, _ := NewBigCache(Config{ + Shards: shards, + LifeWindow: lifeWindow, + MaxEntriesInWindow: max(requestsInLifeWindow, 100), + MaxEntrySize: 500, + }) + rand.Seed(time.Now().Unix()) + + b.RunParallel(func(pb *testing.PB) { + id := rand.Int() + counter := 0 + + b.ReportAllocs() + for pb.Next() { + cache.Set(fmt.Sprintf("key-%d-%d", id, counter), message) + counter = counter + 1 + } + }) +} + +func readFromCache(b *testing.B, shards int) { + cache, _ := NewBigCache(Config{ + Shards: shards, + LifeWindow: 1000 * time.Second, + MaxEntriesInWindow: max(b.N, 100), + MaxEntrySize: 500, + }) + for i := 0; i < b.N; i++ { + cache.Set(strconv.Itoa(i), message) + } + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + b.ReportAllocs() + + for pb.Next() { + cache.Get(strconv.Itoa(rand.Intn(b.N))) + } + }) +} diff --git a/vendor/github.com/allegro/bigcache/bigcache_test.go b/vendor/github.com/allegro/bigcache/bigcache_test.go new file mode 100644 index 00000000..a6a41460 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/bigcache_test.go @@ -0,0 +1,579 @@ +package bigcache + +import ( + "fmt" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +var sink []byte + +func TestParallel(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(DefaultConfig(5 * time.Second)) + value := []byte("value") + var wg sync.WaitGroup + wg.Add(3) + keys := 1337 + + // when + go func() { + defer wg.Done() + for i := 0; i < keys; i++ { + cache.Set(fmt.Sprintf("key%d", i), value) + } + }() + go func() { + defer wg.Done() + for i := 0; i < keys; i++ { + sink, _ = cache.Get(fmt.Sprintf("key%d", i)) + } + }() + go func() { + defer wg.Done() + for i := 0; i < keys; i++ { + cache.Delete(fmt.Sprintf("key%d", i)) + } + }() + + // then + wg.Wait() +} + +func TestWriteAndGetOnCache(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(DefaultConfig(5 * time.Second)) + value := []byte("value") + + // when + cache.Set("key", value) + cachedValue, err := cache.Get("key") + + // then + assert.NoError(t, err) + assert.Equal(t, value, cachedValue) +} + +func TestConstructCacheWithDefaultHasher(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 16, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 10, + MaxEntrySize: 256, + }) + + assert.IsType(t, fnv64a{}, cache.hash) +} + +func TestWillReturnErrorOnInvalidNumberOfPartitions(t *testing.T) { + t.Parallel() + + // given + cache, error := NewBigCache(Config{ + Shards: 18, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 10, + MaxEntrySize: 256, + }) + + assert.Nil(t, cache) + assert.Error(t, error, "Shards number must be power of two") +} + +func TestEntryNotFound(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 16, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 10, + MaxEntrySize: 256, + }) + + // when + _, err := cache.Get("nonExistingKey") + + // then + assert.EqualError(t, err, "Entry \"nonExistingKey\" not found") +} + +func TestTimingEviction(t *testing.T) { + t.Parallel() + + // given + clock := mockedClock{value: 0} + cache, _ := newBigCache(Config{ + Shards: 1, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }, &clock) + + // when + cache.Set("key", []byte("value")) + clock.set(5) + cache.Set("key2", []byte("value2")) + _, err := cache.Get("key") + + // then + assert.EqualError(t, err, "Entry \"key\" not found") +} + +func TestTimingEvictionShouldEvictOnlyFromUpdatedShard(t *testing.T) { + t.Parallel() + + // given + clock := mockedClock{value: 0} + cache, _ := newBigCache(Config{ + Shards: 4, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }, &clock) + + // when + cache.Set("key", []byte("value")) + clock.set(5) + cache.Set("key2", []byte("value 2")) + value, err := cache.Get("key") + + // then + assert.NoError(t, err, "Entry \"key\" not found") + assert.Equal(t, []byte("value"), value) +} + +func TestCleanShouldEvictAll(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 4, + LifeWindow: time.Second, + CleanWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + + // when + cache.Set("key", []byte("value")) + <-time.After(3 * time.Second) + value, err := cache.Get("key") + + // then + assert.EqualError(t, err, "Entry \"key\" not found") + assert.Equal(t, value, []byte(nil)) +} + +func TestOnRemoveCallback(t *testing.T) { + t.Parallel() + + // given + clock := mockedClock{value: 0} + onRemoveInvoked := false + onRemove := func(key string, entry []byte) { + onRemoveInvoked = true + assert.Equal(t, "key", key) + assert.Equal(t, []byte("value"), entry) + } + cache, _ := newBigCache(Config{ + Shards: 1, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + OnRemove: onRemove, + }, &clock) + + // when + cache.Set("key", []byte("value")) + clock.set(5) + cache.Set("key2", []byte("value2")) + + // then + assert.True(t, onRemoveInvoked) +} + +func TestCacheLen(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 8, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + keys := 1337 + + // when + for i := 0; i < keys; i++ { + cache.Set(fmt.Sprintf("key%d", i), []byte("value")) + } + + // then + assert.Equal(t, keys, cache.Len()) +} + +func TestCacheStats(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 8, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + + // when + for i := 0; i < 100; i++ { + cache.Set(fmt.Sprintf("key%d", i), []byte("value")) + } + + for i := 0; i < 10; i++ { + value, err := cache.Get(fmt.Sprintf("key%d", i)) + assert.Nil(t, err) + assert.Equal(t, string(value), "value") + } + for i := 100; i < 110; i++ { + _, err := cache.Get(fmt.Sprintf("key%d", i)) + assert.Error(t, err) + } + for i := 10; i < 20; i++ { + err := cache.Delete(fmt.Sprintf("key%d", i)) + assert.Nil(t, err) + } + for i := 110; i < 120; i++ { + err := cache.Delete(fmt.Sprintf("key%d", i)) + assert.Error(t, err) + } + + // then + stats := cache.Stats() + assert.Equal(t, stats.Hits, int64(10)) + assert.Equal(t, stats.Misses, int64(10)) + assert.Equal(t, stats.DelHits, int64(10)) + assert.Equal(t, stats.DelMisses, int64(10)) +} + +func TestCacheDel(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(DefaultConfig(time.Second)) + + // when + err := cache.Delete("nonExistingKey") + + // then + assert.Equal(t, err.Error(), "Entry \"nonExistingKey\" not found") + + // and when + cache.Set("existingKey", nil) + err = cache.Delete("existingKey") + cachedValue, _ := cache.Get("existingKey") + + // then + assert.Nil(t, err) + assert.Len(t, cachedValue, 0) +} + +func TestCacheReset(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 8, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + keys := 1337 + + // when + for i := 0; i < keys; i++ { + cache.Set(fmt.Sprintf("key%d", i), []byte("value")) + } + + // then + assert.Equal(t, keys, cache.Len()) + + // and when + cache.Reset() + + // then + assert.Equal(t, 0, cache.Len()) + + // and when + for i := 0; i < keys; i++ { + cache.Set(fmt.Sprintf("key%d", i), []byte("value")) + } + + // then + assert.Equal(t, keys, cache.Len()) +} + +func TestIterateOnResetCache(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 8, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + keys := 1337 + + // when + for i := 0; i < keys; i++ { + cache.Set(fmt.Sprintf("key%d", i), []byte("value")) + } + cache.Reset() + + // then + iterator := cache.Iterator() + + assert.Equal(t, false, iterator.SetNext()) +} + +func TestGetOnResetCache(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 8, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + keys := 1337 + + // when + for i := 0; i < keys; i++ { + cache.Set(fmt.Sprintf("key%d", i), []byte("value")) + } + + cache.Reset() + + // then + value, err := cache.Get("key1") + + assert.Equal(t, err.Error(), "Entry \"key1\" not found") + assert.Equal(t, value, []byte(nil)) +} + +func TestEntryUpdate(t *testing.T) { + t.Parallel() + + // given + clock := mockedClock{value: 0} + cache, _ := newBigCache(Config{ + Shards: 1, + LifeWindow: 6 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }, &clock) + + // when + cache.Set("key", []byte("value")) + clock.set(5) + cache.Set("key", []byte("value2")) + clock.set(7) + cache.Set("key2", []byte("value3")) + cachedValue, _ := cache.Get("key") + + // then + assert.Equal(t, []byte("value2"), cachedValue) +} + +func TestOldestEntryDeletionWhenMaxCacheSizeIsReached(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 1, + HardMaxCacheSize: 1, + }) + + // when + cache.Set("key1", blob('a', 1024*400)) + cache.Set("key2", blob('b', 1024*400)) + cache.Set("key3", blob('c', 1024*800)) + + _, key1Err := cache.Get("key1") + _, key2Err := cache.Get("key2") + entry3, _ := cache.Get("key3") + + // then + assert.EqualError(t, key1Err, "Entry \"key1\" not found") + assert.EqualError(t, key2Err, "Entry \"key2\" not found") + assert.Equal(t, blob('c', 1024*800), entry3) +} + +func TestRetrievingEntryShouldCopy(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 1, + HardMaxCacheSize: 1, + }) + cache.Set("key1", blob('a', 1024*400)) + value, key1Err := cache.Get("key1") + + // when + // override queue + cache.Set("key2", blob('b', 1024*400)) + cache.Set("key3", blob('c', 1024*400)) + cache.Set("key4", blob('d', 1024*400)) + cache.Set("key5", blob('d', 1024*400)) + + // then + assert.Nil(t, key1Err) + assert.Equal(t, blob('a', 1024*400), value) +} + +func TestEntryBiggerThanMaxShardSizeError(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 1, + HardMaxCacheSize: 1, + }) + + // when + err := cache.Set("key1", blob('a', 1024*1025)) + + // then + assert.EqualError(t, err, "entry is bigger than max shard size") +} + +func TestHashCollision(t *testing.T) { + t.Parallel() + + ml := &mockedLogger{} + // given + cache, _ := NewBigCache(Config{ + Shards: 16, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 10, + MaxEntrySize: 256, + Verbose: true, + Hasher: hashStub(5), + Logger: ml, + }) + + // when + cache.Set("liquid", []byte("value")) + cachedValue, err := cache.Get("liquid") + + // then + assert.NoError(t, err) + assert.Equal(t, []byte("value"), cachedValue) + + // when + cache.Set("costarring", []byte("value 2")) + cachedValue, err = cache.Get("costarring") + + // then + assert.NoError(t, err) + assert.Equal(t, []byte("value 2"), cachedValue) + + // when + cachedValue, err = cache.Get("liquid") + + // then + assert.Error(t, err) + assert.Nil(t, cachedValue) + + assert.NotEqual(t, "", ml.lastFormat) + assert.Equal(t, cache.Stats().Collisions, int64(1)) +} + +func TestNilValueCaching(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: 5 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 1, + HardMaxCacheSize: 1, + }) + + // when + cache.Set("Kierkegaard", []byte{}) + cachedValue, err := cache.Get("Kierkegaard") + + // then + assert.NoError(t, err) + assert.Equal(t, []byte{}, cachedValue) + + // when + cache.Set("Sartre", nil) + cachedValue, err = cache.Get("Sartre") + + // then + assert.NoError(t, err) + assert.Equal(t, []byte{}, cachedValue) + + // when + cache.Set("Nietzsche", []byte(nil)) + cachedValue, err = cache.Get("Nietzsche") + + // then + assert.NoError(t, err) + assert.Equal(t, []byte{}, cachedValue) +} + +type mockedLogger struct { + lastFormat string + lastArgs []interface{} +} + +func (ml *mockedLogger) Printf(format string, v ...interface{}) { + ml.lastFormat = format + ml.lastArgs = v +} + +type mockedClock struct { + value int64 +} + +func (mc *mockedClock) epoch() int64 { + return mc.value +} + +func (mc *mockedClock) set(value int64) { + mc.value = value +} + +func blob(char byte, len int) []byte { + b := make([]byte, len) + for index := range b { + b[index] = char + } + return b +} diff --git a/vendor/github.com/allegro/bigcache/caches_bench/caches_bench_test.go b/vendor/github.com/allegro/bigcache/caches_bench/caches_bench_test.go new file mode 100644 index 00000000..d083f7f1 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/caches_bench/caches_bench_test.go @@ -0,0 +1,219 @@ +package main + +import ( + "fmt" + "math/rand" + "sync" + "testing" + "time" + + "github.com/allegro/bigcache" + "github.com/coocood/freecache" +) + +const maxEntrySize = 256 + +func BenchmarkMapSet(b *testing.B) { + m := make(map[string][]byte) + for i := 0; i < b.N; i++ { + m[key(i)] = value() + } +} + +func BenchmarkConcurrentMapSet(b *testing.B) { + var m sync.Map + for i := 0; i < b.N; i++ { + m.Store(key(i), value()) + } +} + +func BenchmarkFreeCacheSet(b *testing.B) { + cache := freecache.NewCache(b.N * maxEntrySize) + for i := 0; i < b.N; i++ { + cache.Set([]byte(key(i)), value(), 0) + } +} + +func BenchmarkBigCacheSet(b *testing.B) { + cache := initBigCache(b.N) + for i := 0; i < b.N; i++ { + cache.Set(key(i), value()) + } +} + +func BenchmarkMapGet(b *testing.B) { + b.StopTimer() + m := make(map[string][]byte) + for i := 0; i < b.N; i++ { + m[key(i)] = value() + } + + b.StartTimer() + hitCount := 0 + for i := 0; i < b.N; i++ { + if m[key(i)] != nil { + hitCount++ + } + } +} + +func BenchmarkConcurrentMapGet(b *testing.B) { + b.StopTimer() + var m sync.Map + for i := 0; i < b.N; i++ { + m.Store(key(i), value()) + } + + b.StartTimer() + hitCounter := 0 + for i := 0; i < b.N; i++ { + _, ok := m.Load(key(i)) + if ok { + hitCounter++ + } + } +} + +func BenchmarkFreeCacheGet(b *testing.B) { + b.StopTimer() + cache := freecache.NewCache(b.N * maxEntrySize) + for i := 0; i < b.N; i++ { + cache.Set([]byte(key(i)), value(), 0) + } + + b.StartTimer() + for i := 0; i < b.N; i++ { + cache.Get([]byte(key(i))) + } +} + +func BenchmarkBigCacheGet(b *testing.B) { + b.StopTimer() + cache := initBigCache(b.N) + for i := 0; i < b.N; i++ { + cache.Set(key(i), value()) + } + + b.StartTimer() + for i := 0; i < b.N; i++ { + cache.Get(key(i)) + } +} + +func BenchmarkBigCacheSetParallel(b *testing.B) { + cache := initBigCache(b.N) + rand.Seed(time.Now().Unix()) + + b.RunParallel(func(pb *testing.PB) { + id := rand.Intn(1000) + counter := 0 + for pb.Next() { + cache.Set(parallelKey(id, counter), value()) + counter = counter + 1 + } + }) +} + +func BenchmarkFreeCacheSetParallel(b *testing.B) { + cache := freecache.NewCache(b.N * maxEntrySize) + rand.Seed(time.Now().Unix()) + + b.RunParallel(func(pb *testing.PB) { + id := rand.Intn(1000) + counter := 0 + for pb.Next() { + cache.Set([]byte(parallelKey(id, counter)), value(), 0) + counter = counter + 1 + } + }) +} + +func BenchmarkConcurrentMapSetParallel(b *testing.B) { + var m sync.Map + + b.RunParallel(func(pb *testing.PB) { + id := rand.Intn(1000) + for pb.Next() { + m.Store(key(id), value()) + } + }) +} + +func BenchmarkBigCacheGetParallel(b *testing.B) { + b.StopTimer() + cache := initBigCache(b.N) + for i := 0; i < b.N; i++ { + cache.Set(key(i), value()) + } + + b.StartTimer() + b.RunParallel(func(pb *testing.PB) { + counter := 0 + for pb.Next() { + cache.Get(key(counter)) + counter = counter + 1 + } + }) +} + +func BenchmarkFreeCacheGetParallel(b *testing.B) { + b.StopTimer() + cache := freecache.NewCache(b.N * maxEntrySize) + for i := 0; i < b.N; i++ { + cache.Set([]byte(key(i)), value(), 0) + } + + b.StartTimer() + b.RunParallel(func(pb *testing.PB) { + counter := 0 + for pb.Next() { + cache.Get([]byte(key(counter))) + counter = counter + 1 + } + }) +} + +func BenchmarkConcurrentMapGetParallel(b *testing.B) { + b.StopTimer() + var m sync.Map + for i := 0; i < b.N; i++ { + m.Store(key(i), value()) + } + + b.StartTimer() + hitCount := 0 + + b.RunParallel(func(pb *testing.PB) { + id := rand.Intn(1000) + for pb.Next() { + _, ok := m.Load(key(id)) + if ok { + hitCount++ + } + } + }) +} + +func key(i int) string { + return fmt.Sprintf("key-%010d", i) +} + +func value() []byte { + return make([]byte, 100) +} + +func parallelKey(threadID int, counter int) string { + return fmt.Sprintf("key-%04d-%06d", threadID, counter) +} + +func initBigCache(entriesInWindow int) *bigcache.BigCache { + cache, _ := bigcache.NewBigCache(bigcache.Config{ + Shards: 256, + LifeWindow: 10 * time.Minute, + MaxEntriesInWindow: entriesInWindow, + MaxEntrySize: maxEntrySize, + Verbose: true, + }) + + return cache +} diff --git a/vendor/github.com/allegro/bigcache/caches_bench/caches_gc_overhead_comparison.go b/vendor/github.com/allegro/bigcache/caches_bench/caches_gc_overhead_comparison.go new file mode 100644 index 00000000..7e212103 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/caches_bench/caches_gc_overhead_comparison.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + "runtime" + "runtime/debug" + "time" + + "github.com/allegro/bigcache" + "github.com/coocood/freecache" +) + +func gcPause() time.Duration { + runtime.GC() + var stats debug.GCStats + debug.ReadGCStats(&stats) + return stats.PauseTotal +} + +const ( + entries = 20000000 + valueSize = 100 +) + +func main() { + debug.SetGCPercent(10) + fmt.Println("Number of entries: ", entries) + + config := bigcache.Config{ + Shards: 256, + LifeWindow: 100 * time.Minute, + MaxEntriesInWindow: entries, + MaxEntrySize: 200, + Verbose: true, + } + + bigcache, _ := bigcache.NewBigCache(config) + for i := 0; i < entries; i++ { + key, val := generateKeyValue(i, valueSize) + bigcache.Set(key, val) + } + + firstKey, _ := generateKeyValue(1, valueSize) + checkFirstElement(bigcache.Get(firstKey)) + + fmt.Println("GC pause for bigcache: ", gcPause()) + bigcache = nil + gcPause() + + //------------------------------------------ + + freeCache := freecache.NewCache(entries * 200) //allocate entries * 200 bytes + for i := 0; i < entries; i++ { + key, val := generateKeyValue(i, valueSize) + if err := freeCache.Set([]byte(key), val, 0); err != nil { + fmt.Println("Error in set: ", err.Error()) + } + } + + firstKey, _ = generateKeyValue(1, valueSize) + checkFirstElement(freeCache.Get([]byte(firstKey))) + + if freeCache.OverwriteCount() != 0 { + fmt.Println("Overwritten: ", freeCache.OverwriteCount()) + } + fmt.Println("GC pause for freecache: ", gcPause()) + freeCache = nil + gcPause() + + //------------------------------------------ + + mapCache := make(map[string][]byte) + for i := 0; i < entries; i++ { + key, val := generateKeyValue(i, valueSize) + mapCache[key] = val + } + fmt.Println("GC pause for map: ", gcPause()) + +} + +func checkFirstElement(val []byte, err error) { + _, expectedVal := generateKeyValue(1, valueSize) + if err != nil { + fmt.Println("Error in get: ", err.Error()) + } else if string(val) != string(expectedVal) { + fmt.Println("Wrong first element: ", string(val)) + } +} + +func generateKeyValue(index int, valSize int) (string, []byte) { + key := fmt.Sprintf("key-%010d", index) + fixedNumber := []byte(fmt.Sprintf("%010d", index)) + val := append(make([]byte, valSize-10), fixedNumber...) + + return key, val +} diff --git a/vendor/github.com/allegro/bigcache/clock.go b/vendor/github.com/allegro/bigcache/clock.go new file mode 100644 index 00000000..f8b535e1 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/clock.go @@ -0,0 +1,14 @@ +package bigcache + +import "time" + +type clock interface { + epoch() int64 +} + +type systemClock struct { +} + +func (c systemClock) epoch() int64 { + return time.Now().Unix() +} diff --git a/vendor/github.com/allegro/bigcache/config.go b/vendor/github.com/allegro/bigcache/config.go new file mode 100644 index 00000000..0a523947 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/config.go @@ -0,0 +1,67 @@ +package bigcache + +import "time" + +// Config for BigCache +type Config struct { + // Number of cache shards, value must be a power of two + Shards int + // Time after which entry can be evicted + LifeWindow time.Duration + // Interval between removing expired entries (clean up). + // If set to <= 0 then no action is performed. Setting to < 1 second is counterproductive — bigcache has a one second resolution. + CleanWindow time.Duration + // Max number of entries in life window. Used only to calculate initial size for cache shards. + // When proper value is set then additional memory allocation does not occur. + MaxEntriesInWindow int + // Max size of entry in bytes. Used only to calculate initial size for cache shards. + MaxEntrySize int + // Verbose mode prints information about new memory allocation + Verbose bool + // Hasher used to map between string keys and unsigned 64bit integers, by default fnv64 hashing is used. + Hasher Hasher + // HardMaxCacheSize is a limit for cache size in MB. Cache will not allocate more memory than this limit. + // It can protect application from consuming all available memory on machine, therefore from running OOM Killer. + // Default value is 0 which means unlimited size. When the limit is higher than 0 and reached then + // the oldest entries are overridden for the new ones. + HardMaxCacheSize int + // OnRemove is a callback fired when the oldest entry is removed because of its expiration time or no space left + // for the new entry. Default value is nil which means no callback and it prevents from unwrapping the oldest entry. + OnRemove func(key string, entry []byte) + + // Logger is a logging interface and used in combination with `Verbose` + // Defaults to `DefaultLogger()` + Logger Logger +} + +// DefaultConfig initializes config with default values. +// When load for BigCache can be predicted in advance then it is better to use custom config. +func DefaultConfig(eviction time.Duration) Config { + return Config{ + Shards: 1024, + LifeWindow: eviction, + CleanWindow: 0, + MaxEntriesInWindow: 1000 * 10 * 60, + MaxEntrySize: 500, + Verbose: true, + Hasher: newDefaultHasher(), + HardMaxCacheSize: 0, + Logger: DefaultLogger(), + } +} + +// initialShardSize computes initial shard size +func (c Config) initialShardSize() int { + return max(c.MaxEntriesInWindow/c.Shards, minimumEntriesInShard) +} + +// maximumShardSize computes maximum shard size +func (c Config) maximumShardSize() int { + maxShardSize := 0 + + if c.HardMaxCacheSize > 0 { + maxShardSize = convertMBToBytes(c.HardMaxCacheSize) / c.Shards + } + + return maxShardSize +} diff --git a/vendor/github.com/allegro/bigcache/encoding.go b/vendor/github.com/allegro/bigcache/encoding.go new file mode 100644 index 00000000..5d90d71d --- /dev/null +++ b/vendor/github.com/allegro/bigcache/encoding.go @@ -0,0 +1,70 @@ +package bigcache + +import ( + "encoding/binary" + "reflect" + "unsafe" +) + +const ( + timestampSizeInBytes = 8 // Number of bytes used for timestamp + hashSizeInBytes = 8 // Number of bytes used for hash + keySizeInBytes = 2 // Number of bytes used for size of entry key + headersSizeInBytes = timestampSizeInBytes + hashSizeInBytes + keySizeInBytes // Number of bytes used for all headers +) + +func wrapEntry(timestamp uint64, hash uint64, key string, entry []byte, buffer *[]byte) []byte { + keyLength := len(key) + blobLength := len(entry) + headersSizeInBytes + keyLength + + if blobLength > len(*buffer) { + *buffer = make([]byte, blobLength) + } + blob := *buffer + + binary.LittleEndian.PutUint64(blob, timestamp) + binary.LittleEndian.PutUint64(blob[timestampSizeInBytes:], hash) + binary.LittleEndian.PutUint16(blob[timestampSizeInBytes+hashSizeInBytes:], uint16(keyLength)) + copy(blob[headersSizeInBytes:], key) + copy(blob[headersSizeInBytes+keyLength:], entry) + + return blob[:blobLength] +} + +func readEntry(data []byte) []byte { + length := binary.LittleEndian.Uint16(data[timestampSizeInBytes+hashSizeInBytes:]) + + // copy on read + dst := make([]byte, len(data)-int(headersSizeInBytes+length)) + copy(dst, data[headersSizeInBytes+length:]) + + return dst +} + +func readTimestampFromEntry(data []byte) uint64 { + return binary.LittleEndian.Uint64(data) +} + +func readKeyFromEntry(data []byte) string { + length := binary.LittleEndian.Uint16(data[timestampSizeInBytes+hashSizeInBytes:]) + + // copy on read + dst := make([]byte, length) + copy(dst, data[headersSizeInBytes:headersSizeInBytes+length]) + + return bytesToString(dst) +} + +func bytesToString(b []byte) string { + bytesHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + strHeader := reflect.StringHeader{Data: bytesHeader.Data, Len: bytesHeader.Len} + return *(*string)(unsafe.Pointer(&strHeader)) +} + +func readHashFromEntry(data []byte) uint64 { + return binary.LittleEndian.Uint64(data[timestampSizeInBytes:]) +} + +func resetKeyFromEntry(data []byte) { + binary.LittleEndian.PutUint64(data[timestampSizeInBytes:], 0) +} diff --git a/vendor/github.com/allegro/bigcache/encoding_test.go b/vendor/github.com/allegro/bigcache/encoding_test.go new file mode 100644 index 00000000..ae83811d --- /dev/null +++ b/vendor/github.com/allegro/bigcache/encoding_test.go @@ -0,0 +1,46 @@ +package bigcache + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestEncodeDecode(t *testing.T) { + // given + now := uint64(time.Now().Unix()) + hash := uint64(42) + key := "key" + data := []byte("data") + buffer := make([]byte, 100) + + // when + wrapped := wrapEntry(now, hash, key, data, &buffer) + + // then + assert.Equal(t, key, readKeyFromEntry(wrapped)) + assert.Equal(t, hash, readHashFromEntry(wrapped)) + assert.Equal(t, now, readTimestampFromEntry(wrapped)) + assert.Equal(t, data, readEntry(wrapped)) + assert.Equal(t, 100, len(buffer)) +} + +func TestAllocateBiggerBuffer(t *testing.T) { + //given + now := uint64(time.Now().Unix()) + hash := uint64(42) + key := "1" + data := []byte("2") + buffer := make([]byte, 1) + + // when + wrapped := wrapEntry(now, hash, key, data, &buffer) + + // then + assert.Equal(t, key, readKeyFromEntry(wrapped)) + assert.Equal(t, hash, readHashFromEntry(wrapped)) + assert.Equal(t, now, readTimestampFromEntry(wrapped)) + assert.Equal(t, data, readEntry(wrapped)) + assert.Equal(t, 2+headersSizeInBytes, len(buffer)) +} diff --git a/vendor/github.com/allegro/bigcache/entry_not_found_error.go b/vendor/github.com/allegro/bigcache/entry_not_found_error.go new file mode 100644 index 00000000..e6955a57 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/entry_not_found_error.go @@ -0,0 +1,17 @@ +package bigcache + +import "fmt" + +// EntryNotFoundError is an error type struct which is returned when entry was not found for provided key +type EntryNotFoundError struct { + message string +} + +func notFound(key string) error { + return &EntryNotFoundError{fmt.Sprintf("Entry %q not found", key)} +} + +// Error returned when entry does not exist. +func (e EntryNotFoundError) Error() string { + return e.message +} diff --git a/vendor/github.com/allegro/bigcache/fnv.go b/vendor/github.com/allegro/bigcache/fnv.go new file mode 100644 index 00000000..188c9aa6 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/fnv.go @@ -0,0 +1,28 @@ +package bigcache + +// newDefaultHasher returns a new 64-bit FNV-1a Hasher which makes no memory allocations. +// Its Sum64 method will lay the value out in big-endian byte order. +// See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function +func newDefaultHasher() Hasher { + return fnv64a{} +} + +type fnv64a struct{} + +const ( + // offset64 FNVa offset basis. See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function#FNV-1a_hash + offset64 = 14695981039346656037 + // prime64 FNVa prime value. See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function#FNV-1a_hash + prime64 = 1099511628211 +) + +// Sum64 gets the string and returns its uint64 hash value. +func (f fnv64a) Sum64(key string) uint64 { + var hash uint64 = offset64 + for i := 0; i < len(key); i++ { + hash ^= uint64(key[i]) + hash *= prime64 + } + + return hash +} diff --git a/vendor/github.com/allegro/bigcache/fnv_bench_test.go b/vendor/github.com/allegro/bigcache/fnv_bench_test.go new file mode 100644 index 00000000..327cf32f --- /dev/null +++ b/vendor/github.com/allegro/bigcache/fnv_bench_test.go @@ -0,0 +1,18 @@ +package bigcache + +import "testing" + +var text = "abcdefg" + +func BenchmarkFnvHashSum64(b *testing.B) { + h := newDefaultHasher() + for i := 0; i < b.N; i++ { + h.Sum64(text) + } +} + +func BenchmarkFnvHashStdLibSum64(b *testing.B) { + for i := 0; i < b.N; i++ { + stdLibFnvSum64(text) + } +} diff --git a/vendor/github.com/allegro/bigcache/fnv_test.go b/vendor/github.com/allegro/bigcache/fnv_test.go new file mode 100644 index 00000000..c94c0746 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/fnv_test.go @@ -0,0 +1,35 @@ +package bigcache + +import ( + "hash/fnv" + "testing" +) + +type testCase struct { + text string + expectedHash uint64 +} + +var testCases = []testCase{ + {"", stdLibFnvSum64("")}, + {"a", stdLibFnvSum64("a")}, + {"ab", stdLibFnvSum64("ab")}, + {"abc", stdLibFnvSum64("abc")}, + {"some longer and more complicated text", stdLibFnvSum64("some longer and more complicated text")}, +} + +func TestFnvHashSum64(t *testing.T) { + h := newDefaultHasher() + for _, testCase := range testCases { + hashed := h.Sum64(testCase.text) + if hashed != testCase.expectedHash { + t.Errorf("hash(%q) = %d want %d", testCase.text, hashed, testCase.expectedHash) + } + } +} + +func stdLibFnvSum64(key string) uint64 { + h := fnv.New64a() + h.Write([]byte(key)) + return h.Sum64() +} diff --git a/vendor/github.com/allegro/bigcache/hash.go b/vendor/github.com/allegro/bigcache/hash.go new file mode 100644 index 00000000..5f8ade77 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/hash.go @@ -0,0 +1,8 @@ +package bigcache + +// Hasher is responsible for generating unsigned, 64 bit hash of provided string. Hasher should minimize collisions +// (generating same hash for different strings) and while performance is also important fast functions are preferable (i.e. +// you can use FarmHash family). +type Hasher interface { + Sum64(string) uint64 +} diff --git a/vendor/github.com/allegro/bigcache/hash_test.go b/vendor/github.com/allegro/bigcache/hash_test.go new file mode 100644 index 00000000..2252e7fb --- /dev/null +++ b/vendor/github.com/allegro/bigcache/hash_test.go @@ -0,0 +1,7 @@ +package bigcache + +type hashStub uint64 + +func (stub hashStub) Sum64(_ string) uint64 { + return uint64(stub) +} diff --git a/vendor/github.com/allegro/bigcache/iterator.go b/vendor/github.com/allegro/bigcache/iterator.go new file mode 100644 index 00000000..70b98d90 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/iterator.go @@ -0,0 +1,122 @@ +package bigcache + +import "sync" + +type iteratorError string + +func (e iteratorError) Error() string { + return string(e) +} + +// ErrInvalidIteratorState is reported when iterator is in invalid state +const ErrInvalidIteratorState = iteratorError("Iterator is in invalid state. Use SetNext() to move to next position") + +// ErrCannotRetrieveEntry is reported when entry cannot be retrieved from underlying +const ErrCannotRetrieveEntry = iteratorError("Could not retrieve entry from cache") + +var emptyEntryInfo = EntryInfo{} + +// EntryInfo holds informations about entry in the cache +type EntryInfo struct { + timestamp uint64 + hash uint64 + key string + value []byte +} + +// Key returns entry's underlying key +func (e EntryInfo) Key() string { + return e.key +} + +// Hash returns entry's hash value +func (e EntryInfo) Hash() uint64 { + return e.hash +} + +// Timestamp returns entry's timestamp (time of insertion) +func (e EntryInfo) Timestamp() uint64 { + return e.timestamp +} + +// Value returns entry's underlying value +func (e EntryInfo) Value() []byte { + return e.value +} + +// EntryInfoIterator allows to iterate over entries in the cache +type EntryInfoIterator struct { + mutex sync.Mutex + cache *BigCache + currentShard int + currentIndex int + elements []uint32 + elementsCount int + valid bool +} + +// SetNext moves to next element and returns true if it exists. +func (it *EntryInfoIterator) SetNext() bool { + it.mutex.Lock() + + it.valid = false + it.currentIndex++ + + if it.elementsCount > it.currentIndex { + it.valid = true + it.mutex.Unlock() + return true + } + + for i := it.currentShard + 1; i < it.cache.config.Shards; i++ { + it.elements, it.elementsCount = it.cache.shards[i].copyKeys() + + // Non empty shard - stick with it + if it.elementsCount > 0 { + it.currentIndex = 0 + it.currentShard = i + it.valid = true + it.mutex.Unlock() + return true + } + } + it.mutex.Unlock() + return false +} + +func newIterator(cache *BigCache) *EntryInfoIterator { + elements, count := cache.shards[0].copyKeys() + + return &EntryInfoIterator{ + cache: cache, + currentShard: 0, + currentIndex: -1, + elements: elements, + elementsCount: count, + } +} + +// Value returns current value from the iterator +func (it *EntryInfoIterator) Value() (EntryInfo, error) { + it.mutex.Lock() + + if !it.valid { + it.mutex.Unlock() + return emptyEntryInfo, ErrInvalidIteratorState + } + + entry, err := it.cache.shards[it.currentShard].getEntry(int(it.elements[it.currentIndex])) + + if err != nil { + it.mutex.Unlock() + return emptyEntryInfo, ErrCannotRetrieveEntry + } + it.mutex.Unlock() + + return EntryInfo{ + timestamp: readTimestampFromEntry(entry), + hash: readHashFromEntry(entry), + key: readKeyFromEntry(entry), + value: readEntry(entry), + }, nil +} diff --git a/vendor/github.com/allegro/bigcache/iterator_test.go b/vendor/github.com/allegro/bigcache/iterator_test.go new file mode 100644 index 00000000..ec8bf137 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/iterator_test.go @@ -0,0 +1,150 @@ +package bigcache + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestEntriesIterator(t *testing.T) { + t.Parallel() + + // given + keysCount := 1000 + cache, _ := NewBigCache(Config{ + Shards: 8, + LifeWindow: 6 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + value := []byte("value") + + for i := 0; i < keysCount; i++ { + cache.Set(fmt.Sprintf("key%d", i), value) + } + + // when + keys := make(map[string]struct{}) + iterator := cache.Iterator() + + for iterator.SetNext() { + current, err := iterator.Value() + + if err == nil { + keys[current.Key()] = struct{}{} + } + } + + // then + assert.Equal(t, keysCount, len(keys)) +} + +func TestEntriesIteratorWithMostShardsEmpty(t *testing.T) { + t.Parallel() + + // given + clock := mockedClock{value: 0} + cache, _ := newBigCache(Config{ + Shards: 8, + LifeWindow: 6 * time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }, &clock) + + cache.Set("key", []byte("value")) + + // when + iterator := cache.Iterator() + + // then + if !iterator.SetNext() { + t.Errorf("Iterator should contain at least single element") + } + + current, err := iterator.Value() + + // then + assert.Nil(t, err) + assert.Equal(t, "key", current.Key()) + assert.Equal(t, uint64(0x3dc94a19365b10ec), current.Hash()) + assert.Equal(t, []byte("value"), current.Value()) + assert.Equal(t, uint64(0), current.Timestamp()) +} + +func TestEntriesIteratorWithConcurrentUpdate(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + + cache.Set("key", []byte("value")) + + // when + iterator := cache.Iterator() + + // then + if !iterator.SetNext() { + t.Errorf("Iterator should contain at least single element") + } + + // Quite ugly but works + for i := 0; i < cache.config.Shards; i++ { + if oldestEntry, err := cache.shards[i].getOldestEntry(); err == nil { + cache.onEvict(oldestEntry, 10, cache.shards[i].removeOldestEntry) + } + } + + current, err := iterator.Value() + + // then + assert.Equal(t, ErrCannotRetrieveEntry, err) + assert.Equal(t, "Could not retrieve entry from cache", err.Error()) + assert.Equal(t, EntryInfo{}, current) +} + +func TestEntriesIteratorWithAllShardsEmpty(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + + // when + iterator := cache.Iterator() + + // then + if iterator.SetNext() { + t.Errorf("Iterator should not contain any elements") + } +} + +func TestEntriesIteratorInInvalidState(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(Config{ + Shards: 1, + LifeWindow: time.Second, + MaxEntriesInWindow: 1, + MaxEntrySize: 256, + }) + + // when + iterator := cache.Iterator() + + // then + _, err := iterator.Value() + assert.Equal(t, ErrInvalidIteratorState, err) + assert.Equal(t, "Iterator is in invalid state. Use SetNext() to move to next position", err.Error()) +} diff --git a/vendor/github.com/allegro/bigcache/logger.go b/vendor/github.com/allegro/bigcache/logger.go new file mode 100644 index 00000000..50e84abc --- /dev/null +++ b/vendor/github.com/allegro/bigcache/logger.go @@ -0,0 +1,30 @@ +package bigcache + +import ( + "log" + "os" +) + +// Logger is invoked when `Config.Verbose=true` +type Logger interface { + Printf(format string, v ...interface{}) +} + +// this is a safeguard, breaking on compile time in case +// `log.Logger` does not adhere to our `Logger` interface. +// see https://golang.org/doc/faq#guarantee_satisfies_interface +var _ Logger = &log.Logger{} + +// DefaultLogger returns a `Logger` implementation +// backed by stdlib's log +func DefaultLogger() *log.Logger { + return log.New(os.Stdout, "", log.LstdFlags) +} + +func newLogger(custom Logger) Logger { + if custom != nil { + return custom + } + + return DefaultLogger() +} diff --git a/vendor/github.com/allegro/bigcache/queue/bytes_queue.go b/vendor/github.com/allegro/bigcache/queue/bytes_queue.go new file mode 100644 index 00000000..0285c72c --- /dev/null +++ b/vendor/github.com/allegro/bigcache/queue/bytes_queue.go @@ -0,0 +1,210 @@ +package queue + +import ( + "encoding/binary" + "log" + "time" +) + +const ( + // Number of bytes used to keep information about entry size + headerEntrySize = 4 + // Bytes before left margin are not used. Zero index means element does not exist in queue, useful while reading slice from index + leftMarginIndex = 1 + // Minimum empty blob size in bytes. Empty blob fills space between tail and head in additional memory allocation. + // It keeps entries indexes unchanged + minimumEmptyBlobSize = 32 + headerEntrySize +) + +// BytesQueue is a non-thread safe queue type of fifo based on bytes array. +// For every push operation index of entry is returned. It can be used to read the entry later +type BytesQueue struct { + array []byte + capacity int + maxCapacity int + head int + tail int + count int + rightMargin int + headerBuffer []byte + verbose bool + initialCapacity int +} + +type queueError struct { + message string +} + +// NewBytesQueue initialize new bytes queue. +// Initial capacity is used in bytes array allocation +// When verbose flag is set then information about memory allocation are printed +func NewBytesQueue(initialCapacity int, maxCapacity int, verbose bool) *BytesQueue { + return &BytesQueue{ + array: make([]byte, initialCapacity), + capacity: initialCapacity, + maxCapacity: maxCapacity, + headerBuffer: make([]byte, headerEntrySize), + tail: leftMarginIndex, + head: leftMarginIndex, + rightMargin: leftMarginIndex, + verbose: verbose, + initialCapacity: initialCapacity, + } +} + +// Reset removes all entries from queue +func (q *BytesQueue) Reset() { + // Just reset indexes + q.tail = leftMarginIndex + q.head = leftMarginIndex + q.rightMargin = leftMarginIndex + q.count = 0 +} + +// Push copies entry at the end of queue and moves tail pointer. Allocates more space if needed. +// Returns index for pushed data or error if maximum size queue limit is reached. +func (q *BytesQueue) Push(data []byte) (int, error) { + dataLen := len(data) + + if q.availableSpaceAfterTail() < dataLen+headerEntrySize { + if q.availableSpaceBeforeHead() >= dataLen+headerEntrySize { + q.tail = leftMarginIndex + } else if q.capacity+headerEntrySize+dataLen >= q.maxCapacity && q.maxCapacity > 0 { + return -1, &queueError{"Full queue. Maximum size limit reached."} + } else { + q.allocateAdditionalMemory(dataLen + headerEntrySize) + } + } + + index := q.tail + + q.push(data, dataLen) + + return index, nil +} + +func (q *BytesQueue) allocateAdditionalMemory(minimum int) { + start := time.Now() + if q.capacity < minimum { + q.capacity += minimum + } + q.capacity = q.capacity * 2 + if q.capacity > q.maxCapacity && q.maxCapacity > 0 { + q.capacity = q.maxCapacity + } + + oldArray := q.array + q.array = make([]byte, q.capacity) + + if leftMarginIndex != q.rightMargin { + copy(q.array, oldArray[:q.rightMargin]) + + if q.tail < q.head { + emptyBlobLen := q.head - q.tail - headerEntrySize + q.push(make([]byte, emptyBlobLen), emptyBlobLen) + q.head = leftMarginIndex + q.tail = q.rightMargin + } + } + + if q.verbose { + log.Printf("Allocated new queue in %s; Capacity: %d \n", time.Since(start), q.capacity) + } +} + +func (q *BytesQueue) push(data []byte, len int) { + binary.LittleEndian.PutUint32(q.headerBuffer, uint32(len)) + q.copy(q.headerBuffer, headerEntrySize) + + q.copy(data, len) + + if q.tail > q.head { + q.rightMargin = q.tail + } + + q.count++ +} + +func (q *BytesQueue) copy(data []byte, len int) { + q.tail += copy(q.array[q.tail:], data[:len]) +} + +// Pop reads the oldest entry from queue and moves head pointer to the next one +func (q *BytesQueue) Pop() ([]byte, error) { + data, size, err := q.peek(q.head) + if err != nil { + return nil, err + } + + q.head += headerEntrySize + size + q.count-- + + if q.head == q.rightMargin { + q.head = leftMarginIndex + if q.tail == q.rightMargin { + q.tail = leftMarginIndex + } + q.rightMargin = q.tail + } + + return data, nil +} + +// Peek reads the oldest entry from list without moving head pointer +func (q *BytesQueue) Peek() ([]byte, error) { + data, _, err := q.peek(q.head) + return data, err +} + +// Get reads entry from index +func (q *BytesQueue) Get(index int) ([]byte, error) { + data, _, err := q.peek(index) + return data, err +} + +// Capacity returns number of allocated bytes for queue +func (q *BytesQueue) Capacity() int { + return q.capacity +} + +// Len returns number of entries kept in queue +func (q *BytesQueue) Len() int { + return q.count +} + +// Error returns error message +func (e *queueError) Error() string { + return e.message +} + +func (q *BytesQueue) peek(index int) ([]byte, int, error) { + + if q.count == 0 { + return nil, 0, &queueError{"Empty queue"} + } + + if index <= 0 { + return nil, 0, &queueError{"Index must be grater than zero. Invalid index."} + } + + if index+headerEntrySize >= len(q.array) { + return nil, 0, &queueError{"Index out of range"} + } + + blockSize := int(binary.LittleEndian.Uint32(q.array[index : index+headerEntrySize])) + return q.array[index+headerEntrySize : index+headerEntrySize+blockSize], blockSize, nil +} + +func (q *BytesQueue) availableSpaceAfterTail() int { + if q.tail >= q.head { + return q.capacity - q.tail + } + return q.head - q.tail - minimumEmptyBlobSize +} + +func (q *BytesQueue) availableSpaceBeforeHead() int { + if q.tail >= q.head { + return q.head - leftMarginIndex - minimumEmptyBlobSize + } + return q.head - q.tail - minimumEmptyBlobSize +} diff --git a/vendor/github.com/allegro/bigcache/queue/bytes_queue_test.go b/vendor/github.com/allegro/bigcache/queue/bytes_queue_test.go new file mode 100644 index 00000000..f4342b4e --- /dev/null +++ b/vendor/github.com/allegro/bigcache/queue/bytes_queue_test.go @@ -0,0 +1,365 @@ +package queue + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPushAndPop(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(10, 0, true) + entry := []byte("hello") + + // when + _, err := queue.Pop() + + // then + assert.EqualError(t, err, "Empty queue") + + // when + queue.Push(entry) + + // then + assert.Equal(t, entry, pop(queue)) +} + +func TestLen(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(100, 0, false) + entry := []byte("hello") + assert.Zero(t, queue.Len()) + + // when + queue.Push(entry) + + // then + assert.Equal(t, queue.Len(), 1) +} + +func TestPeek(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(100, 0, false) + entry := []byte("hello") + + // when + read, err := queue.Peek() + + // then + assert.EqualError(t, err, "Empty queue") + assert.Nil(t, read) + + // when + queue.Push(entry) + read, err = queue.Peek() + + // then + assert.NoError(t, err) + assert.Equal(t, pop(queue), read) + assert.Equal(t, entry, read) +} + +func TestReset(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(100, 0, false) + entry := []byte("hello") + + // when + queue.Push(entry) + queue.Push(entry) + queue.Push(entry) + + queue.Reset() + read, err := queue.Peek() + + // then + assert.EqualError(t, err, "Empty queue") + assert.Nil(t, read) + + // when + queue.Push(entry) + read, err = queue.Peek() + + // then + assert.NoError(t, err) + assert.Equal(t, pop(queue), read) + assert.Equal(t, entry, read) + + // when + read, err = queue.Peek() + + // then + assert.EqualError(t, err, "Empty queue") + assert.Nil(t, read) +} + +func TestReuseAvailableSpace(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(100, 0, false) + + // when + queue.Push(blob('a', 70)) + queue.Push(blob('b', 20)) + queue.Pop() + queue.Push(blob('c', 20)) + + // then + assert.Equal(t, 100, queue.Capacity()) + assert.Equal(t, blob('b', 20), pop(queue)) +} + +func TestAllocateAdditionalSpace(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(11, 0, false) + + // when + queue.Push([]byte("hello1")) + queue.Push([]byte("hello2")) + + // then + assert.Equal(t, 22, queue.Capacity()) +} + +func TestAllocateAdditionalSpaceForInsufficientFreeFragmentedSpaceWhereHeadIsBeforeTail(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(25, 0, false) + + // when + queue.Push(blob('a', 3)) // header + entry + left margin = 8 bytes + queue.Push(blob('b', 6)) // additional 10 bytes + queue.Pop() // space freed, 7 bytes available at the beginning + queue.Push(blob('c', 6)) // 10 bytes needed, 14 available but not in one segment, allocate additional memory + + // then + assert.Equal(t, 50, queue.Capacity()) + assert.Equal(t, blob('b', 6), pop(queue)) + assert.Equal(t, blob('c', 6), pop(queue)) +} + +func TestUnchangedEntriesIndexesAfterAdditionalMemoryAllocationWhereHeadIsBeforeTail(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(25, 0, false) + + // when + queue.Push(blob('a', 3)) // header + entry + left margin = 8 bytes + index, _ := queue.Push(blob('b', 6)) // additional 10 bytes + queue.Pop() // space freed, 7 bytes available at the beginning + newestIndex, _ := queue.Push(blob('c', 6)) // 10 bytes needed, 14 available but not in one segment, allocate additional memory + + // then + assert.Equal(t, 50, queue.Capacity()) + assert.Equal(t, blob('b', 6), get(queue, index)) + assert.Equal(t, blob('c', 6), get(queue, newestIndex)) +} + +func TestAllocateAdditionalSpaceForInsufficientFreeFragmentedSpaceWhereTailIsBeforeHead(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(100, 0, false) + + // when + queue.Push(blob('a', 70)) // header + entry + left margin = 75 bytes + queue.Push(blob('b', 10)) // 75 + 10 + 4 = 89 bytes + queue.Pop() // space freed at the beginning + queue.Push(blob('c', 30)) // 34 bytes used at the beginning, tail pointer is before head pointer + queue.Push(blob('d', 40)) // 44 bytes needed but no available in one segment, allocate new memory + + // then + assert.Equal(t, 200, queue.Capacity()) + assert.Equal(t, blob('c', 30), pop(queue)) + // empty blob fills space between tail and head, + // created when additional memory was allocated, + // it keeps current entries indexes unchanged + assert.Equal(t, blob(0, 36), pop(queue)) + assert.Equal(t, blob('b', 10), pop(queue)) + assert.Equal(t, blob('d', 40), pop(queue)) +} + +func TestUnchangedEntriesIndexesAfterAdditionalMemoryAllocationWhereTailIsBeforeHead(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(100, 0, false) + + // when + queue.Push(blob('a', 70)) // header + entry + left margin = 75 bytes + index, _ := queue.Push(blob('b', 10)) // 75 + 10 + 4 = 89 bytes + queue.Pop() // space freed at the beginning + queue.Push(blob('c', 30)) // 34 bytes used at the beginning, tail pointer is before head pointer + newestIndex, _ := queue.Push(blob('d', 40)) // 44 bytes needed but no available in one segment, allocate new memory + + // then + assert.Equal(t, 200, queue.Capacity()) + assert.Equal(t, blob('b', 10), get(queue, index)) + assert.Equal(t, blob('d', 40), get(queue, newestIndex)) +} + +func TestAllocateAdditionalSpaceForValueBiggerThanInitQueue(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(11, 0, false) + + // when + queue.Push(blob('a', 100)) + + // then + assert.Equal(t, blob('a', 100), pop(queue)) + assert.Equal(t, 230, queue.Capacity()) +} + +func TestAllocateAdditionalSpaceForValueBiggerThanQueue(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(21, 0, false) + + // when + queue.Push(make([]byte, 2)) + queue.Push(make([]byte, 2)) + queue.Push(make([]byte, 100)) + + // then + queue.Pop() + queue.Pop() + assert.Equal(t, make([]byte, 100), pop(queue)) + assert.Equal(t, 250, queue.Capacity()) +} + +func TestPopWholeQueue(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(13, 0, false) + + // when + queue.Push([]byte("a")) + queue.Push([]byte("b")) + queue.Pop() + queue.Pop() + queue.Push([]byte("c")) + + // then + assert.Equal(t, 13, queue.Capacity()) + assert.Equal(t, []byte("c"), pop(queue)) +} + +func TestGetEntryFromIndex(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(20, 0, false) + + // when + queue.Push([]byte("a")) + index, _ := queue.Push([]byte("b")) + queue.Push([]byte("c")) + result, _ := queue.Get(index) + + // then + assert.Equal(t, []byte("b"), result) +} + +func TestGetEntryFromInvalidIndex(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(1, 0, false) + queue.Push([]byte("a")) + + // when + result, err := queue.Get(0) + + // then + assert.Nil(t, result) + assert.EqualError(t, err, "Index must be grater than zero. Invalid index.") +} + +func TestGetEntryFromIndexOutOfRange(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(1, 0, false) + queue.Push([]byte("a")) + + // when + result, err := queue.Get(42) + + // then + assert.Nil(t, result) + assert.EqualError(t, err, "Index out of range") +} + +func TestGetEntryFromEmptyQueue(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(13, 0, false) + + // when + result, err := queue.Get(1) + + // then + assert.Nil(t, result) + assert.EqualError(t, err, "Empty queue") +} + +func TestMaxSizeLimit(t *testing.T) { + t.Parallel() + + // given + queue := NewBytesQueue(30, 50, false) + + // when + queue.Push(blob('a', 25)) + queue.Push(blob('b', 5)) + capacity := queue.Capacity() + _, err := queue.Push(blob('c', 15)) + + // then + assert.Equal(t, 50, capacity) + assert.EqualError(t, err, "Full queue. Maximum size limit reached.") + assert.Equal(t, blob('a', 25), pop(queue)) + assert.Equal(t, blob('b', 5), pop(queue)) +} + +func pop(queue *BytesQueue) []byte { + entry, err := queue.Pop() + if err != nil { + panic(err) + } + return entry +} + +func get(queue *BytesQueue, index int) []byte { + entry, err := queue.Get(index) + if err != nil { + panic(err) + } + return entry +} + +func blob(char byte, len int) []byte { + b := make([]byte, len) + for index := range b { + b[index] = char + } + return b +} diff --git a/vendor/github.com/allegro/bigcache/server/README.md b/vendor/github.com/allegro/bigcache/server/README.md new file mode 100644 index 00000000..894235f3 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/server/README.md @@ -0,0 +1,105 @@ +# BigCache HTTP Server + +This is a basic HTTP server implementation for BigCache. It has a basic RESTful API and is designed for easy operational deployments. This server is intended to be consumed as a standalone executable, for things like Cloud Foundry, Heroku, etc. A design goal is versatility, so if you want to cache pictures, software artifacts, text, or any type of bit, the BigCache HTTP Server should fit your needs. + +```bash +# cache API. +GET /api/v1/cache/{key} +PUT /api/v1/cache/{key} +DELETE /api/v1/cache/{key} + +# stats API. +GET /api/v1/stats +``` + +The cache API is designed for ease-of-use caching and accepts any content type. The stats API will return hit and miss statistics about the cache since the last time the server was started - they will reset whenever the server is restarted. + +### Notes for Operators + +1. No SSL support, currently. +1. No authentication, currently. +1. Stats from the stats API are not persistent. +1. The easiest way to clean the cache is to restart the process; it takes less than a second to initialise. +1. There is no replication or clustering. + +### Command-line Interface + +```powershell +PS C:\go\src\github.com\mxplusb\bigcache\server> .\server.exe -h +Usage of C:\go\src\github.com\mxplusb\bigcache\server\server.exe: + -lifetime duration + Lifetime of each cache object. (default 10m0s) + -logfile string + Location of the logfile. + -max int + Maximum amount of data in the cache in MB. (default 8192) + -maxInWindow int + Used only in initial memory allocation. (default 600000) + -maxShardEntrySize int + The maximum size of each object stored in a shard. Used only in initial memory allocation. (default 500) + -port int + The port to listen on. (default 9090) + -shards int + Number of shards for the cache. (default 1024) + -v Verbose logging. + -version + Print server version. +``` + +Example: + +```bash +$ curl -v -XPUT localhost:9090/api/v1/cache/example -d "yay!" +* Trying 127.0.0.1... +* Connected to localhost (127.0.0.1) port 9090 (#0) +> PUT /api/v1/cache/example HTTP/1.1 +> Host: localhost:9090 +> User-Agent: curl/7.47.0 +> Accept: */* +> Content-Length: 4 +> Content-Type: application/x-www-form-urlencoded +> +* upload completely sent off: 4 out of 4 bytes +< HTTP/1.1 201 Created +< Date: Fri, 17 Nov 2017 03:50:07 GMT +< Content-Length: 0 +< Content-Type: text/plain; charset=utf-8 +< +* Connection #0 to host localhost left intact +$ +$ curl -v -XGET localhost:9090/api/v1/cache/example +Note: Unnecessary use of -X or --request, GET is already inferred. +* Trying 127.0.0.1... +* Connected to localhost (127.0.0.1) port 9090 (#0) +> GET /api/v1/cache/example HTTP/1.1 +> Host: localhost:9090 +> User-Agent: curl/7.47.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Date: Fri, 17 Nov 2017 03:50:23 GMT +< Content-Length: 4 +< Content-Type: text/plain; charset=utf-8 +< +* Connection #0 to host localhost left intact +yay! +``` + +The server does log basic metrics: + +```bash +$ ./server +2017/11/16 22:49:22 cache initialised. +2017/11/16 22:49:22 starting server on :9090 +2017/11/16 22:50:07 stored "example" in cache. +2017/11/16 22:50:07 request took 277000ns. +2017/11/16 22:50:23 request took 9000ns. +``` + +### Acquiring Natively + +This is native Go with no external dependencies, so it will compile for all supported Golang platforms. To build: + +```bash +go build server.go +``` diff --git a/vendor/github.com/allegro/bigcache/server/cache_handlers.go b/vendor/github.com/allegro/bigcache/server/cache_handlers.go new file mode 100644 index 00000000..48e41130 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/server/cache_handlers.go @@ -0,0 +1,87 @@ +package main + +import ( + "io/ioutil" + "log" + "net/http" + "strings" +) + +func cacheIndexHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + getCacheHandler(w, r) + case http.MethodPut: + putCacheHandler(w, r) + case http.MethodDelete: + deleteCacheHandler(w, r) + } + }) +} + +// handles get requests. +func getCacheHandler(w http.ResponseWriter, r *http.Request) { + target := r.URL.Path[len(cachePath):] + if target == "" { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("can't get a key if there is no key.")) + log.Print("empty request.") + return + } + entry, err := cache.Get(target) + if err != nil { + errMsg := (err).Error() + if strings.Contains(errMsg, "not found") { + log.Print(err) + w.WriteHeader(http.StatusNotFound) + return + } + log.Print(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Write(entry) +} + +func putCacheHandler(w http.ResponseWriter, r *http.Request) { + target := r.URL.Path[len(cachePath):] + if target == "" { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("can't put a key if there is no key.")) + log.Print("empty request.") + return + } + + entry, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Print(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + if err := cache.Set(target, []byte(entry)); err != nil { + log.Print(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + log.Printf("stored \"%s\" in cache.", target) + w.WriteHeader(http.StatusCreated) +} + +// delete cache objects. +func deleteCacheHandler(w http.ResponseWriter, r *http.Request) { + target := r.URL.Path[len(cachePath):] + if err := cache.Delete(target); err != nil { + if strings.Contains((err).Error(), "not found") { + w.WriteHeader(http.StatusNotFound) + log.Printf("%s not found.", target) + return + } + w.WriteHeader(http.StatusInternalServerError) + log.Printf("internal cache error: %s", err) + } + // this is what the RFC says to use when calling DELETE. + w.WriteHeader(http.StatusOK) + return +} diff --git a/vendor/github.com/allegro/bigcache/server/middleware.go b/vendor/github.com/allegro/bigcache/server/middleware.go new file mode 100644 index 00000000..a4c673f3 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/server/middleware.go @@ -0,0 +1,29 @@ +package main + +import ( + "log" + "net/http" + "time" +) + +// our base middleware implementation. +type service func(http.Handler) http.Handler + +// chain load middleware services. +func serviceLoader(h http.Handler, svcs ...service) http.Handler { + for _, svc := range svcs { + h = svc(h) + } + return h +} + +// middleware for request length metrics. +func requestMetrics(l *log.Logger) service { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + h.ServeHTTP(w, r) + l.Printf("%s request to %s took %vns.", r.Method, r.URL.Path, time.Now().Sub(start).Nanoseconds()) + }) + } +} diff --git a/vendor/github.com/allegro/bigcache/server/server.go b/vendor/github.com/allegro/bigcache/server/server.go new file mode 100644 index 00000000..35843437 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/server/server.go @@ -0,0 +1,85 @@ +package main + +import ( + "flag" + "fmt" + "log" + "net/http" + "os" + "strconv" + + "github.com/allegro/bigcache" +) + +const ( + // base HTTP paths. + apiVersion = "v1" + apiBasePath = "/api/" + apiVersion + "/" + + // path to cache. + cachePath = apiBasePath + "cache/" + statsPath = apiBasePath + "stats" + + // server version. + version = "1.0.0" +) + +var ( + port int + logfile string + ver bool + + // cache-specific settings. + cache *bigcache.BigCache + config = bigcache.Config{} +) + +func init() { + flag.BoolVar(&config.Verbose, "v", false, "Verbose logging.") + flag.IntVar(&config.Shards, "shards", 1024, "Number of shards for the cache.") + flag.IntVar(&config.MaxEntriesInWindow, "maxInWindow", 1000*10*60, "Used only in initial memory allocation.") + flag.DurationVar(&config.LifeWindow, "lifetime", 100000*100000*60, "Lifetime of each cache object.") + flag.IntVar(&config.HardMaxCacheSize, "max", 8192, "Maximum amount of data in the cache in MB.") + flag.IntVar(&config.MaxEntrySize, "maxShardEntrySize", 500, "The maximum size of each object stored in a shard. Used only in initial memory allocation.") + flag.IntVar(&port, "port", 9090, "The port to listen on.") + flag.StringVar(&logfile, "logfile", "", "Location of the logfile.") + flag.BoolVar(&ver, "version", false, "Print server version.") +} + +func main() { + flag.Parse() + + if ver { + fmt.Printf("BigCache HTTP Server v%s", version) + os.Exit(0) + } + + var logger *log.Logger + + if logfile == "" { + logger = log.New(os.Stdout, "", log.LstdFlags) + } else { + f, err := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + panic(err) + } + logger = log.New(f, "", log.LstdFlags) + } + + var err error + cache, err = bigcache.NewBigCache(config) + if err != nil { + logger.Fatal(err) + } + + logger.Print("cache initialised.") + + // let the middleware log. + http.Handle(cachePath, serviceLoader(cacheIndexHandler(), requestMetrics(logger))) + http.Handle(statsPath, serviceLoader(statsIndexHandler(), requestMetrics(logger))) + + logger.Printf("starting server on :%d", port) + + strPort := ":" + strconv.Itoa(port) + log.Fatal("ListenAndServe: ", http.ListenAndServe(strPort, nil)) +} diff --git a/vendor/github.com/allegro/bigcache/server/server_test.go b/vendor/github.com/allegro/bigcache/server/server_test.go new file mode 100644 index 00000000..328a7f1b --- /dev/null +++ b/vendor/github.com/allegro/bigcache/server/server_test.go @@ -0,0 +1,185 @@ +package main + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http/httptest" + "testing" + "time" + + "github.com/allegro/bigcache" +) + +const ( + testBaseString = "http://bigcache.org" +) + +func testCacheSetup() { + cache, _ = bigcache.NewBigCache(bigcache.Config{ + Shards: 1024, + LifeWindow: 10 * time.Minute, + MaxEntriesInWindow: 1000 * 10 * 60, + MaxEntrySize: 500, + Verbose: true, + HardMaxCacheSize: 8192, + OnRemove: nil, + }) +} + +func TestMain(m *testing.M) { + testCacheSetup() + m.Run() +} + +func TestGetWithNoKey(t *testing.T) { + t.Parallel() + req := httptest.NewRequest("GET", testBaseString+"/api/v1/cache/", nil) + rr := httptest.NewRecorder() + + getCacheHandler(rr, req) + resp := rr.Result() + + if resp.StatusCode != 400 { + t.Errorf("want: 400; got: %d", resp.StatusCode) + } +} + +func TestGetWithMissingKey(t *testing.T) { + t.Parallel() + req := httptest.NewRequest("GET", testBaseString+"/api/v1/cache/doesNotExist", nil) + rr := httptest.NewRecorder() + + getCacheHandler(rr, req) + resp := rr.Result() + + if resp.StatusCode != 404 { + t.Errorf("want: 404; got: %d", resp.StatusCode) + } +} + +func TestGetKey(t *testing.T) { + t.Parallel() + req := httptest.NewRequest("GET", testBaseString+"/api/v1/cache/getKey", nil) + rr := httptest.NewRecorder() + + // set something. + cache.Set("getKey", []byte("123")) + + getCacheHandler(rr, req) + resp := rr.Result() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("cannot deserialise test response: %s", err) + } + + if string(body) != "123" { + t.Errorf("want: 123; got: %s.\n\tcan't get existing key getKey.", string(body)) + } +} + +func TestPutKey(t *testing.T) { + t.Parallel() + req := httptest.NewRequest("PUT", testBaseString+"/api/v1/cache/putKey", bytes.NewBuffer([]byte("123"))) + rr := httptest.NewRecorder() + + putCacheHandler(rr, req) + + testPutKeyResult, err := cache.Get("putKey") + if err != nil { + t.Errorf("error returning cache entry: %s", err) + } + + if string(testPutKeyResult) != "123" { + t.Errorf("want: 123; got: %s.\n\tcan't get PUT key putKey.", string(testPutKeyResult)) + } +} + +func TestPutEmptyKey(t *testing.T) { + t.Parallel() + + req := httptest.NewRequest("PUT", testBaseString+"/api/v1/cache/", bytes.NewBuffer([]byte("123"))) + rr := httptest.NewRecorder() + + putCacheHandler(rr, req) + resp := rr.Result() + + if resp.StatusCode != 400 { + t.Errorf("want: 400; got: %d.\n\tempty key insertion should return with 400", resp.StatusCode) + } +} + +func TestDeleteEmptyKey(t *testing.T) { + t.Parallel() + + req := httptest.NewRequest("DELETE", testBaseString+"/api/v1/cache/", bytes.NewBuffer([]byte("123"))) + rr := httptest.NewRecorder() + + deleteCacheHandler(rr, req) + resp := rr.Result() + + if resp.StatusCode != 404 { + t.Errorf("want: 404; got: %d.\n\tapparently we're trying to delete empty keys.", resp.StatusCode) + } +} + +func TestDeleteInvalidKey(t *testing.T) { + t.Parallel() + + req := httptest.NewRequest("DELETE", testBaseString+"/api/v1/cache/invalidDeleteKey", bytes.NewBuffer([]byte("123"))) + rr := httptest.NewRecorder() + + deleteCacheHandler(rr, req) + resp := rr.Result() + + if resp.StatusCode != 404 { + t.Errorf("want: 404; got: %d.\n\tapparently we're trying to delete invalid keys.", resp.StatusCode) + } +} + +func TestDeleteKey(t *testing.T) { + t.Parallel() + + req := httptest.NewRequest("DELETE", testBaseString+"/api/v1/cache/testDeleteKey", bytes.NewBuffer([]byte("123"))) + rr := httptest.NewRecorder() + + if err := cache.Set("testDeleteKey", []byte("123")); err != nil { + t.Errorf("can't set key for testing. %s", err) + } + + deleteCacheHandler(rr, req) + resp := rr.Result() + + if resp.StatusCode != 200 { + t.Errorf("want: 200; got: %d.\n\tcan't delete keys.", resp.StatusCode) + } +} + +func TestGetStats(t *testing.T) { + t.Parallel() + var testStats bigcache.Stats + + req := httptest.NewRequest("GET", testBaseString+"/api/v1/stats", nil) + rr := httptest.NewRecorder() + + // manually enter a key so there are some stats. get it so there's at least 1 hit. + if err := cache.Set("incrementStats", []byte("123")); err != nil { + t.Errorf("error setting cache value. error %s", err) + } + // it's okay if this fails, since we'll catch it downstream. + if _, err := cache.Get("incrementStats"); err != nil { + t.Errorf("can't find incrementStats. error: %s", err) + } + + getCacheStatsHandler(rr, req) + resp := rr.Result() + + if err := json.NewDecoder(resp.Body).Decode(&testStats); err != nil { + t.Errorf("error decoding cache stats. error: %s", err) + } + + if testStats.Hits == 0 { + t.Errorf("want: > 0; got: 0.\n\thandler not properly returning stats info.") + } +} diff --git a/vendor/github.com/allegro/bigcache/server/stats_handler.go b/vendor/github.com/allegro/bigcache/server/stats_handler.go new file mode 100644 index 00000000..4584b96a --- /dev/null +++ b/vendor/github.com/allegro/bigcache/server/stats_handler.go @@ -0,0 +1,33 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" +) + +// index for stats handle +func statsIndexHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + getCacheStatsHandler(w, r) + default: + w.WriteHeader(http.StatusMethodNotAllowed) + } + }) +} + +// returns the cache's statistics. +func getCacheStatsHandler(w http.ResponseWriter, r *http.Request) { + target, err := json.Marshal(cache.Stats()) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + log.Printf("cannot marshal cache stats. error: %s", err) + return + } + // since we're sending a struct, make it easy for consumers to interface. + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Write(target) + return +} diff --git a/vendor/github.com/allegro/bigcache/shard.go b/vendor/github.com/allegro/bigcache/shard.go new file mode 100644 index 00000000..af48ebc3 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/shard.go @@ -0,0 +1,229 @@ +package bigcache + +import ( + "fmt" + "sync" + "sync/atomic" + + "github.com/allegro/bigcache/queue" +) + +type cacheShard struct { + hashmap map[uint64]uint32 + entries queue.BytesQueue + lock sync.RWMutex + entryBuffer []byte + onRemove func(wrappedEntry []byte) + + isVerbose bool + logger Logger + clock clock + lifeWindow uint64 + + stats Stats +} + +type onRemoveCallback func(wrappedEntry []byte) + +func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) { + s.lock.RLock() + itemIndex := s.hashmap[hashedKey] + + if itemIndex == 0 { + s.lock.RUnlock() + s.miss() + return nil, notFound(key) + } + + wrappedEntry, err := s.entries.Get(int(itemIndex)) + if err != nil { + s.lock.RUnlock() + s.miss() + return nil, err + } + if entryKey := readKeyFromEntry(wrappedEntry); key != entryKey { + if s.isVerbose { + s.logger.Printf("Collision detected. Both %q and %q have the same hash %x", key, entryKey, hashedKey) + } + s.lock.RUnlock() + s.collision() + return nil, notFound(key) + } + s.lock.RUnlock() + s.hit() + return readEntry(wrappedEntry), nil +} + +func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error { + currentTimestamp := uint64(s.clock.epoch()) + + s.lock.Lock() + + if previousIndex := s.hashmap[hashedKey]; previousIndex != 0 { + if previousEntry, err := s.entries.Get(int(previousIndex)); err == nil { + resetKeyFromEntry(previousEntry) + } + } + + if oldestEntry, err := s.entries.Peek(); err == nil { + s.onEvict(oldestEntry, currentTimestamp, s.removeOldestEntry) + } + + w := wrapEntry(currentTimestamp, hashedKey, key, entry, &s.entryBuffer) + + for { + if index, err := s.entries.Push(w); err == nil { + s.hashmap[hashedKey] = uint32(index) + s.lock.Unlock() + return nil + } + if s.removeOldestEntry() != nil { + s.lock.Unlock() + return fmt.Errorf("entry is bigger than max shard size") + } + } +} + +func (s *cacheShard) del(key string, hashedKey uint64) error { + s.lock.RLock() + itemIndex := s.hashmap[hashedKey] + + if itemIndex == 0 { + s.lock.RUnlock() + s.delmiss() + return notFound(key) + } + + wrappedEntry, err := s.entries.Get(int(itemIndex)) + if err != nil { + s.lock.RUnlock() + s.delmiss() + return err + } + s.lock.RUnlock() + + s.lock.Lock() + { + delete(s.hashmap, hashedKey) + s.onRemove(wrappedEntry) + resetKeyFromEntry(wrappedEntry) + } + s.lock.Unlock() + + s.delhit() + return nil +} + +func (s *cacheShard) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func() error) bool { + oldestTimestamp := readTimestampFromEntry(oldestEntry) + if currentTimestamp-oldestTimestamp > s.lifeWindow { + evict() + return true + } + return false +} + +func (s *cacheShard) cleanUp(currentTimestamp uint64) { + s.lock.Lock() + for { + if oldestEntry, err := s.entries.Peek(); err != nil { + break + } else if evicted := s.onEvict(oldestEntry, currentTimestamp, s.removeOldestEntry); !evicted { + break + } + } + s.lock.Unlock() +} + +func (s *cacheShard) getOldestEntry() ([]byte, error) { + return s.entries.Peek() +} + +func (s *cacheShard) getEntry(index int) ([]byte, error) { + return s.entries.Get(index) +} + +func (s *cacheShard) copyKeys() (keys []uint32, next int) { + keys = make([]uint32, len(s.hashmap)) + + s.lock.RLock() + + for _, index := range s.hashmap { + keys[next] = index + next++ + } + + s.lock.RUnlock() + return keys, next +} + +func (s *cacheShard) removeOldestEntry() error { + oldest, err := s.entries.Pop() + if err == nil { + hash := readHashFromEntry(oldest) + delete(s.hashmap, hash) + s.onRemove(oldest) + return nil + } + return err +} + +func (s *cacheShard) reset(config Config) { + s.lock.Lock() + s.hashmap = make(map[uint64]uint32, config.initialShardSize()) + s.entryBuffer = make([]byte, config.MaxEntrySize+headersSizeInBytes) + s.entries.Reset() + s.lock.Unlock() +} + +func (s *cacheShard) len() int { + s.lock.RLock() + res := len(s.hashmap) + s.lock.RUnlock() + return res +} + +func (s *cacheShard) getStats() Stats { + var stats = Stats{ + Hits: atomic.LoadInt64(&s.stats.Hits), + Misses: atomic.LoadInt64(&s.stats.Misses), + DelHits: atomic.LoadInt64(&s.stats.DelHits), + DelMisses: atomic.LoadInt64(&s.stats.DelMisses), + Collisions: atomic.LoadInt64(&s.stats.Collisions), + } + return stats +} + +func (s *cacheShard) hit() { + atomic.AddInt64(&s.stats.Hits, 1) +} + +func (s *cacheShard) miss() { + atomic.AddInt64(&s.stats.Misses, 1) +} + +func (s *cacheShard) delhit() { + atomic.AddInt64(&s.stats.DelHits, 1) +} + +func (s *cacheShard) delmiss() { + atomic.AddInt64(&s.stats.DelMisses, 1) +} + +func (s *cacheShard) collision() { + atomic.AddInt64(&s.stats.Collisions, 1) +} + +func initNewShard(config Config, callback onRemoveCallback, clock clock) *cacheShard { + return &cacheShard{ + hashmap: make(map[uint64]uint32, config.initialShardSize()), + entries: *queue.NewBytesQueue(config.initialShardSize()*config.MaxEntrySize, config.maximumShardSize(), config.Verbose), + entryBuffer: make([]byte, config.MaxEntrySize+headersSizeInBytes), + onRemove: callback, + + isVerbose: config.Verbose, + logger: newLogger(config.Logger), + clock: clock, + lifeWindow: uint64(config.LifeWindow.Seconds()), + } +} diff --git a/vendor/github.com/allegro/bigcache/stats.go b/vendor/github.com/allegro/bigcache/stats.go new file mode 100644 index 00000000..07157132 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/stats.go @@ -0,0 +1,15 @@ +package bigcache + +// Stats stores cache statistics +type Stats struct { + // Hits is a number of successfully found keys + Hits int64 `json:"hits"` + // Misses is a number of not found keys + Misses int64 `json:"misses"` + // DelHits is a number of successfully deleted keys + DelHits int64 `json:"delete_hits"` + // DelMisses is a number of not deleted keys + DelMisses int64 `json:"delete_misses"` + // Collisions is a number of happened key-collisions + Collisions int64 `json:"collisions"` +} diff --git a/vendor/github.com/allegro/bigcache/utils.go b/vendor/github.com/allegro/bigcache/utils.go new file mode 100644 index 00000000..ca1df79b --- /dev/null +++ b/vendor/github.com/allegro/bigcache/utils.go @@ -0,0 +1,16 @@ +package bigcache + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func convertMBToBytes(value int) int { + return value * 1024 * 1024 +} + +func isPowerOfTwo(number int) bool { + return (number & (number - 1)) == 0 +} diff --git a/vendor/github.com/aristanetworks/goarista/.travis.yml b/vendor/github.com/aristanetworks/goarista/.travis.yml index a75913c8..c6d1ac4b 100644 --- a/vendor/github.com/aristanetworks/goarista/.travis.yml +++ b/vendor/github.com/aristanetworks/goarista/.travis.yml @@ -1,7 +1,8 @@ language: go go: -- 1.9 -- tip +- 1.10.x +- 1.x +- master before_install: - go get -v github.com/golang/lint/golint - go get -v -t -d ./... diff --git a/vendor/github.com/aristanetworks/goarista/Dockerfile b/vendor/github.com/aristanetworks/goarista/Dockerfile index 692bc2ab..374a8dac 100644 --- a/vendor/github.com/aristanetworks/goarista/Dockerfile +++ b/vendor/github.com/aristanetworks/goarista/Dockerfile @@ -3,7 +3,7 @@ # that can be found in the COPYING file. # TODO: move this to cmd/ockafka (https://github.com/docker/hub-feedback/issues/292) -FROM golang:1.7.3 +FROM golang:1.10.3 RUN mkdir -p /go/src/github.com/aristanetworks/goarista/cmd WORKDIR /go/src/github.com/aristanetworks/goarista diff --git a/vendor/github.com/aristanetworks/goarista/README.md b/vendor/github.com/aristanetworks/goarista/README.md index 2f55cfa2..0db1ca4f 100644 --- a/vendor/github.com/aristanetworks/goarista/README.md +++ b/vendor/github.com/aristanetworks/goarista/README.md @@ -25,19 +25,20 @@ class of service flags to use for incoming connections. Requires `go1.9`. ## key -Provides a common type used across various Arista projects, named `key.Key`, -which is used to work around the fact that Go can't let one -use a non-hashable type as a key to a `map`, and we sometimes need to use -a `map[string]interface{}` (or something containing one) as a key to maps. -As a result, we frequently use `map[key.Key]interface{}` instead of just -`map[interface{}]interface{}` when we need a generic key-value collection. +Provides common types used across various Arista projects. The type `key.Key` +is used to work around the fact that Go can't let one use a non-hashable type +as a key to a `map`, and we sometimes need to use a `map[string]interface{}` +(or something containing one) as a key to maps. As a result, we frequently use +`map[key.Key]interface{}` instead of just `map[interface{}]interface{}` when we +need a generic key-value collection. The type `key.Path` is the representation +of a path broken down into individual elements, where each element is a `key.Key`. +The type `key.Pointer` represents a pointer to a `key.Path`. ## path -Provides a common type used across various Arista projects, named `path.Path`, -which is the representation of a path broken down into individual elements. -Each element is a `key.Key`. The type `path.Map` may be used for mapping paths -to values. It allows for some fuzzy matching. +Provides functions that can be used to manipulate `key.Path` objects. The type +`path.Map` may be used for mapping paths to values. It allows for some fuzzy +matching for paths containing `path.Wildcard` keys. ## lanz A client for [LANZ](https://eos.arista.com/latency-analyzer-lanz-architectures-and-configuration/) @@ -55,9 +56,10 @@ A library to help expose monitoring metrics on top of the `netns.Do(namespace, cb)` provides a handy mechanism to execute the given callback `cb` in the given [network namespace](https://lwn.net/Articles/580893/). -## pathmap +## influxlib -DEPRECATED; use`path.Map` instead. +This is a influxdb library that provides easy methods of connecting to, writing to, +and reading from the service. ## test diff --git a/vendor/github.com/aristanetworks/goarista/cmd/gnmi/README.md b/vendor/github.com/aristanetworks/goarista/cmd/gnmi/README.md index c0f2c3b5..69a663a6 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/gnmi/README.md +++ b/vendor/github.com/aristanetworks/goarista/cmd/gnmi/README.md @@ -16,10 +16,20 @@ under [GOPATH](https://golang.org/doc/code.html#GOPATH). # Usage +``` +$ gnmi [OPTIONS] [OPERATION] +``` + +When running on the switch in a non-default VRF: + +``` +$ ip netns exec ns- gnmi [OPTIONS] [OPERATION] +``` + ## Options -* `-addr ADDR:PORT` -Address of the gNMI endpoint (REQUIRED) +* `-addr [/]ADDR:PORT` +Address of the gNMI endpoint (REQUIRED) with VRF name (OPTIONAL) * `-username USERNAME` Username to authenticate with * `-password PASSWORD` @@ -92,7 +102,7 @@ $ gnmi [OPTIONS] delete '/network-instances/network-instance[name=default]/proto ``` `update` and `replace` both take a path and a value in JSON -format. See +format. The JSON data may be provided in a file. See [here](https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#344-modes-of-update-replace-versus-update) for documentation on the differences between `update` and `replace`. @@ -108,15 +118,46 @@ Replace the BGP global configuration: gnmi [OPTIONS] replace '/network-instances/network-instance[name=default]/protocols/protocol[name=BGP][identifier=BGP]/bgp/global' '{"config":{"as": 1234, "router-id": "1.2.3.4"}}' ``` -Note: String values must be quoted. For example, setting the hostname to `"tor13"`: +Note: String values need to be quoted if they look like JSON. For example, setting the login banner to `tor[13]`: ``` -gnmi [OPTIONS] update '/system/config/hostname' '"tor13"' +gnmi [OPTIONS] update '/system/config/login-banner '"tor[13]"' +``` + +#### JSON in a file + +The value argument to `update` and `replace` may be a file. The +content of the file is used to make the request. + +Example: + +File `path/to/subintf100.json` contains the following: + +``` +{ + "subinterface": [ + { + "config": { + "enabled": true, + "index": 100 + }, + "index": 100 + } + ] +} +``` + +Add subinterface 100 to interfaces Ethernet4/1/1 and Ethernet4/2/1 in +one transaction: + +``` +gnmi [OPTIONS] update '/interfaces/interface[name=Ethernet4/1/1]/subinterfaces' path/to/subintf100.json \ + update '/interfaces/interface[name=Ethernet4/2/1]/subinterfaces' path/to/subintf100.json ``` ### CLI requests `gnmi` offers the ability to send CLI text inside an `update` or `replace` operation. This is achieved by doing an `update` or -`replace` and using `"cli"` as the path and a set of configure-mode +`replace` and specifying `"origin=cli"` along with an empty path and a set of configure-mode CLI commands separated by `\n`. Example: @@ -127,6 +168,18 @@ gnmi [OPTIONS] update 'cli' 'management ssh idle-timeout 300' ``` +### P4 Config +`gnmi` offers the ability to send p4 config files inside a `replace` operation. +This is achieved by doing a `replace` and specifying `"origin=p4_config"` +along with the path of the p4 config file to send. + +Example: + +Send the config.p4 file +``` +gnmi [OPTIONS] replace 'origin=p4_config' 'config.p4' +``` + ## Paths Paths in `gnmi` use a simplified xpath style. Path elements are diff --git a/vendor/github.com/aristanetworks/goarista/cmd/gnmi/main.go b/vendor/github.com/aristanetworks/goarista/cmd/gnmi/main.go index ed6f5ccd..f7a2a7b9 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/gnmi/main.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/gnmi/main.go @@ -9,6 +9,8 @@ import ( "flag" "fmt" "os" + "strings" + "time" "github.com/aristanetworks/goarista/gnmi" @@ -18,22 +20,24 @@ import ( // TODO: Make this more clear var help = `Usage of gnmi: -gnmi -addr ADDRESS:PORT [options...] +gnmi -addr [/]ADDRESS:PORT [options...] capabilities get PATH+ subscribe PATH+ - ((update|replace PATH JSON)|(delete PATH))+ + ((update|replace (origin=ORIGIN) PATH JSON|FILE)|(delete (origin=ORIGIN) PATH))+ ` -func exitWithError(s string) { +func usageAndExit(s string) { flag.Usage() - fmt.Fprintln(os.Stderr, s) + if s != "" { + fmt.Fprintln(os.Stderr, s) + } os.Exit(1) } func main() { cfg := &gnmi.Config{} - flag.StringVar(&cfg.Addr, "addr", "", "Address of gNMI gRPC server") + flag.StringVar(&cfg.Addr, "addr", "", "Address of gNMI gRPC server with optional VRF name") flag.StringVar(&cfg.CAFile, "cafile", "", "Path to server TLS certificate file") flag.StringVar(&cfg.CertFile, "certfile", "", "Path to client TLS certificate file") flag.StringVar(&cfg.KeyFile, "keyfile", "", "Path to client TLS private key file") @@ -41,26 +45,54 @@ func main() { flag.StringVar(&cfg.Username, "username", "", "Username to authenticate with") flag.BoolVar(&cfg.TLS, "tls", false, "Enable TLS") + subscribeOptions := &gnmi.SubscribeOptions{} + flag.StringVar(&subscribeOptions.Prefix, "prefix", "", "Subscribe prefix path") + flag.BoolVar(&subscribeOptions.UpdatesOnly, "updates_only", false, + "Subscribe to updates only (false | true)") + flag.StringVar(&subscribeOptions.Mode, "mode", "stream", + "Subscribe mode (stream | once | poll)") + flag.StringVar(&subscribeOptions.StreamMode, "stream_mode", "target_defined", + "Subscribe stream mode, only applies for stream subscriptions "+ + "(target_defined | on_change | sample)") + sampleIntervalStr := flag.String("sample_interval", "0", "Subscribe sample interval, "+ + "only applies for sample subscriptions (400ms, 2.5s, 1m, etc.)") + heartbeatIntervalStr := flag.String("heartbeat_interval", "0", "Subscribe heartbeat "+ + "interval, only applies for on-change subscriptions (400ms, 2.5s, 1m, etc.)") + flag.Usage = func() { fmt.Fprintln(os.Stderr, help) flag.PrintDefaults() } flag.Parse() if cfg.Addr == "" { - exitWithError("error: address not specified") + usageAndExit("error: address not specified") } + var sampleInterval, heartbeatInterval time.Duration + var err error + if sampleInterval, err = time.ParseDuration(*sampleIntervalStr); err != nil { + usageAndExit(fmt.Sprintf("error: sample interval (%s) invalid", *sampleIntervalStr)) + } + subscribeOptions.SampleInterval = uint64(sampleInterval) + if heartbeatInterval, err = time.ParseDuration(*heartbeatIntervalStr); err != nil { + usageAndExit(fmt.Sprintf("error: heartbeat interval (%s) invalid", *heartbeatIntervalStr)) + } + subscribeOptions.HeartbeatInterval = uint64(heartbeatInterval) + args := flag.Args() ctx := gnmi.NewContext(context.Background(), cfg) - client := gnmi.Dial(cfg) + client, err := gnmi.Dial(cfg) + if err != nil { + glog.Fatal(err) + } var setOps []*gnmi.Operation for i := 0; i < len(args); i++ { switch args[i] { case "capabilities": if len(setOps) != 0 { - exitWithError("error: 'capabilities' not allowed after 'merge|replace|delete'") + usageAndExit("error: 'capabilities' not allowed after 'merge|replace|delete'") } err := gnmi.Capabilities(ctx, client) if err != nil { @@ -69,7 +101,7 @@ func main() { return case "get": if len(setOps) != 0 { - exitWithError("error: 'get' not allowed after 'merge|replace|delete'") + usageAndExit("error: 'get' not allowed after 'merge|replace|delete'") } err := gnmi.Get(ctx, client, gnmi.SplitPaths(args[i+1:])) if err != nil { @@ -78,49 +110,55 @@ func main() { return case "subscribe": if len(setOps) != 0 { - exitWithError("error: 'subscribe' not allowed after 'merge|replace|delete'") + usageAndExit("error: 'subscribe' not allowed after 'merge|replace|delete'") } respChan := make(chan *pb.SubscribeResponse) errChan := make(chan error) - defer close(respChan) defer close(errChan) - go gnmi.Subscribe(ctx, client, gnmi.SplitPaths(args[i+1:]), respChan, errChan) + subscribeOptions.Paths = gnmi.SplitPaths(args[i+1:]) + go gnmi.Subscribe(ctx, client, subscribeOptions, respChan, errChan) for { select { - case resp := <-respChan: + case resp, open := <-respChan: + if !open { + return + } if err := gnmi.LogSubscribeResponse(resp); err != nil { - exitWithError(err.Error()) + glog.Fatal(err) } case err := <-errChan: - exitWithError(err.Error()) + glog.Fatal(err) } } case "update", "replace", "delete": if len(args) == i+1 { - exitWithError("error: missing path") + usageAndExit("error: missing path") } op := &gnmi.Operation{ Type: args[i], } i++ + if strings.HasPrefix(args[i], "origin=") { + op.Origin = strings.TrimPrefix(args[i], "origin=") + i++ + } op.Path = gnmi.SplitPath(args[i]) if op.Type != "delete" { if len(args) == i+1 { - exitWithError("error: missing JSON") + usageAndExit("error: missing JSON or FILEPATH to data") } i++ op.Val = args[i] } setOps = append(setOps, op) default: - exitWithError(fmt.Sprintf("error: unknown operation %q", args[i])) + usageAndExit(fmt.Sprintf("error: unknown operation %q", args[i])) } } if len(setOps) == 0 { - flag.Usage() - os.Exit(1) + usageAndExit("") } - err := gnmi.Set(ctx, client, setOps) + err = gnmi.Set(ctx, client, setOps) if err != nil { glog.Fatal(err) } diff --git a/vendor/github.com/aristanetworks/goarista/cmd/json2test/main.go b/vendor/github.com/aristanetworks/goarista/cmd/json2test/main.go new file mode 100644 index 00000000..35da7388 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/json2test/main.go @@ -0,0 +1,120 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +// json2test reformats 'go test -json' output as text as if the -json +// flag were not passed to go test. It is useful if you want to +// analyze go test -json output, but still want a human readable test +// log. +// +// Usage: +// +// go test -json > out.txt; out.txt; cat out.txt | json2test +// +package main + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "os" + "time" +) + +var errTestFailure = errors.New("testfailure") + +func main() { + err := writeTestOutput(os.Stdin, os.Stdout) + if err == errTestFailure { + os.Exit(1) + } else if err != nil { + log.Fatal(err) + } +} + +type testEvent struct { + Time time.Time // encodes as an RFC3339-format string + Action string + Package string + Test string + Elapsed float64 // seconds + Output string +} + +type test struct { + pkg string + test string +} + +type outputBuffer struct { + output []string +} + +func (o *outputBuffer) push(s string) { + o.output = append(o.output, s) +} + +type testFailure struct { + t test + o outputBuffer +} + +func writeTestOutput(in io.Reader, out io.Writer) error { + testOutputBuffer := map[test]*outputBuffer{} + var failures []testFailure + d := json.NewDecoder(in) + + buf := bufio.NewWriter(out) + defer buf.Flush() + for { + var e testEvent + if err := d.Decode(&e); err != nil { + break + } + + switch e.Action { + default: + continue + case "run": + testOutputBuffer[test{pkg: e.Package, test: e.Test}] = new(outputBuffer) + case "pass": + // Don't hold onto text for passing + delete(testOutputBuffer, test{pkg: e.Package, test: e.Test}) + case "fail": + // fail may be for a package, which won't have an entry in + // testOutputBuffer because packages don't have a "run" + // action. + t := test{pkg: e.Package, test: e.Test} + if o, ok := testOutputBuffer[t]; ok { + f := testFailure{t: t, o: *o} + delete(testOutputBuffer, t) + failures = append(failures, f) + } + case "output": + buf.WriteString(e.Output) + // output may be for a package, which won't have an entry + // in testOutputBuffer because packages don't have a "run" + // action. + if o, ok := testOutputBuffer[test{pkg: e.Package, test: e.Test}]; ok { + o.push(e.Output) + } + } + } + if len(failures) == 0 { + return nil + } + buf.WriteString("\nTest failures:\n") + for i, f := range failures { + fmt.Fprintf(buf, "[%d] %s.%s\n", i+1, f.t.pkg, f.t.test) + for _, s := range f.o.output { + buf.WriteString(s) + } + if i < len(failures)-1 { + buf.WriteByte('\n') + } + } + return errTestFailure +} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/json2test/main_test.go b/vendor/github.com/aristanetworks/goarista/cmd/json2test/main_test.go new file mode 100644 index 00000000..b7f712a0 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/json2test/main_test.go @@ -0,0 +1,41 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "testing" +) + +func TestWriteTestOutput(t *testing.T) { + input, err := os.Open("testdata/input.txt") + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + if err := writeTestOutput(input, &out); err != errTestFailure { + t.Error("expected test failure") + } + + gold, err := os.Open("testdata/gold.txt") + if err != nil { + t.Fatal(err) + } + expected, err := ioutil.ReadAll(gold) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(out.Bytes(), expected) { + t.Error("output does not match gold.txt") + fmt.Println("Expected:") + fmt.Println(string(expected)) + fmt.Println("Got:") + fmt.Println(out.String()) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/json2test/testdata/gold.txt b/vendor/github.com/aristanetworks/goarista/cmd/json2test/testdata/gold.txt new file mode 100644 index 00000000..ed50a1eb --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/json2test/testdata/gold.txt @@ -0,0 +1,16 @@ +? pkg/skipped [no test files] +=== RUN TestPass +--- PASS: TestPass (0.00s) +PASS +ok pkg/passed 0.013s +panic +FAIL pkg/panic 600.029s +--- FAIL: TestFail (0.18s) + +Test failures: +[1] pkg/panic.TestPanic +panic +FAIL pkg/panic 600.029s + +[2] pkg/failed.TestFail +--- FAIL: TestFail (0.18s) diff --git a/vendor/github.com/aristanetworks/goarista/cmd/json2test/testdata/input.txt b/vendor/github.com/aristanetworks/goarista/cmd/json2test/testdata/input.txt new file mode 100644 index 00000000..d99f5a31 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/json2test/testdata/input.txt @@ -0,0 +1,17 @@ +{"Time":"2018-03-08T10:33:12.002692769-08:00","Action":"output","Package":"pkg/skipped","Output":"? \tpkg/skipped\t[no test files]\n"} +{"Time":"2018-03-08T10:33:12.003199228-08:00","Action":"skip","Package":"pkg/skipped","Elapsed":0.001} +{"Time":"2018-03-08T10:33:12.343866281-08:00","Action":"run","Package":"pkg/passed","Test":"TestPass"} +{"Time":"2018-03-08T10:33:12.34406622-08:00","Action":"output","Package":"pkg/passed","Test":"TestPass","Output":"=== RUN TestPass\n"} +{"Time":"2018-03-08T10:33:12.344139342-08:00","Action":"output","Package":"pkg/passed","Test":"TestPass","Output":"--- PASS: TestPass (0.00s)\n"} +{"Time":"2018-03-08T10:33:12.344165231-08:00","Action":"pass","Package":"pkg/passed","Test":"TestPass","Elapsed":0} +{"Time":"2018-03-08T10:33:12.344297059-08:00","Action":"output","Package":"pkg/passed","Output":"PASS\n"} +{"Time":"2018-03-08T10:33:12.345217622-08:00","Action":"output","Package":"pkg/passed","Output":"ok \tpkg/passed\t0.013s\n"} +{"Time":"2018-03-08T10:33:12.34533033-08:00","Action":"pass","Package":"pkg/passed","Elapsed":0.013} +{"Time":"2018-03-08T10:33:20.243866281-08:00","Action":"run","Package":"pkg/panic","Test":"TestPanic"} +{"Time":"2018-03-08T10:33:20.27231537-08:00","Action":"output","Package":"pkg/panic","Test":"TestPanic","Output":"panic\n"} +{"Time":"2018-03-08T10:33:20.272414481-08:00","Action":"output","Package":"pkg/panic","Test":"TestPanic","Output":"FAIL\tpkg/panic\t600.029s\n"} +{"Time":"2018-03-08T10:33:20.272440286-08:00","Action":"fail","Package":"pkg/panic","Test":"TestPanic","Elapsed":600.029} +{"Time":"2018-03-08T10:33:26.143866281-08:00","Action":"run","Package":"pkg/failed","Test":"TestFail"} +{"Time":"2018-03-08T10:33:27.158776469-08:00","Action":"output","Package":"pkg/failed","Test":"TestFail","Output":"--- FAIL: TestFail (0.18s)\n"} +{"Time":"2018-03-08T10:33:27.158860934-08:00","Action":"fail","Package":"pkg/failed","Test":"TestFail","Elapsed":0.18} +{"Time":"2018-03-08T10:33:27.161302093-08:00","Action":"fail","Package":"pkg/failed","Elapsed":0.204} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ockafka/main.go b/vendor/github.com/aristanetworks/goarista/cmd/ockafka/main.go index 2765aaba..d016ed27 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ockafka/main.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ockafka/main.go @@ -26,13 +26,12 @@ var keysFlag = flag.String("kafkakeys", "", "Keys for kafka messages (comma-separated, default: the value of -addrs") func newProducer(addresses []string, topic, key, dataset string) (producer.Producer, error) { - - glog.Infof("Connected to Kafka brokers at %s", addresses) encodedKey := sarama.StringEncoder(key) p, err := producer.New(openconfig.NewEncoder(topic, encodedKey, dataset), addresses, nil) if err != nil { - return nil, fmt.Errorf("Failed to create Kafka producer: %s", err) + return nil, fmt.Errorf("Failed to create Kafka brokers: %s", err) } + glog.Infof("Connected to Kafka brokers at %s", addresses) return p, nil } diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/README.md b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/README.md index 024a9af4..9de9c8d9 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/README.md +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/README.md @@ -33,5 +33,5 @@ Prometheus 2.0 will probably support timestamps. See the `-help` output, but here's an example to push all the metrics defined in the sample config file: ``` -ocprometheus -addrs :6042 -config sampleconfig.json +ocprometheus -addr :6042 -config sampleconfig.json ``` diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector.go b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector.go index 324d15e5..4113d023 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector.go @@ -11,7 +11,7 @@ import ( "github.com/aristanetworks/glog" "github.com/golang/protobuf/proto" - "github.com/openconfig/reference/rpc/openconfig" + pb "github.com/openconfig/gnmi/proto/gnmi" "github.com/prometheus/client_golang/prometheus" ) @@ -24,8 +24,10 @@ type source struct { // Since the labels are fixed per-path and per-device we can cache them here, // to avoid recomputing them. type labelledMetric struct { - metric prometheus.Metric - labels []string + metric prometheus.Metric + labels []string + defaultValue float64 + stringMetric bool } type collector struct { @@ -43,13 +45,14 @@ func newCollector(config *Config) *collector { } } -// Process a notfication and update or create the corresponding metrics. +// Process a notification and update or create the corresponding metrics. func (c *collector) update(addr string, message proto.Message) { - resp, ok := message.(*openconfig.SubscribeResponse) + resp, ok := message.(*pb.SubscribeResponse) if !ok { glog.Errorf("Unexpected type of message: %T", message) return } + notif := resp.GetUpdate() if notif == nil { return @@ -57,7 +60,6 @@ func (c *collector) update(addr string, message proto.Message) { device := strings.Split(addr, ":")[0] prefix := "/" + strings.Join(notif.Prefix.Element, "/") - // Process deletes first for _, del := range notif.Delete { path := prefix + "/" + strings.Join(del.Element, "/") @@ -70,7 +72,7 @@ func (c *collector) update(addr string, message proto.Message) { // Process updates next for _, update := range notif.Update { // We only use JSON encoded values - if update.Value == nil || update.Value.Type != openconfig.Type_JSON { + if update.Value == nil || update.Value.Type != pb.Encoding_JSON { glog.V(9).Infof("Ignoring incompatible update value in %s", update) continue } @@ -80,40 +82,81 @@ func (c *collector) update(addr string, message proto.Message) { if !ok { continue } + + var strUpdate bool + var floatVal float64 + var strVal string + + switch v := value.(type) { + case float64: + strUpdate = false + floatVal = v + case string: + strUpdate = true + strVal = v + } + if suffix != "" { path += "/" + suffix } + src := source{addr: device, path: path} c.m.Lock() // Use the cached labels and descriptor if available if m, ok := c.metrics[src]; ok { - m.metric = prometheus.MustNewConstMetric(m.metric.Desc(), prometheus.GaugeValue, value, - m.labels...) + if strUpdate { + // Skip string updates for non string metrics + if !m.stringMetric { + c.m.Unlock() + continue + } + // Display a default value and replace the value label with the string value + floatVal = m.defaultValue + m.labels[len(m.labels)-1] = strVal + } + + m.metric = prometheus.MustNewConstMetric(m.metric.Desc(), prometheus.GaugeValue, + floatVal, m.labels...) c.m.Unlock() continue } - c.m.Unlock() + c.m.Unlock() // Get the descriptor and labels for this source - desc, labelValues := c.config.getDescAndLabels(src) - if desc == nil { + metric := c.config.getMetricValues(src) + if metric == nil || metric.desc == nil { glog.V(8).Infof("Ignoring unmatched update at %s:%s: %+v", device, path, update.Value) continue } - c.m.Lock() + if strUpdate { + if !metric.stringMetric { + // Skip string updates for non string metrics + continue + } + // Display a default value and replace the value label with the string value + floatVal = metric.defaultValue + metric.labels[len(metric.labels)-1] = strVal + } + // Save the metric and labels in the cache - metric := prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, value, labelValues...) + c.m.Lock() + lm := prometheus.MustNewConstMetric(metric.desc, prometheus.GaugeValue, + floatVal, metric.labels...) c.metrics[src] = &labelledMetric{ - metric: metric, - labels: labelValues, + metric: lm, + labels: metric.labels, + defaultValue: metric.defaultValue, + stringMetric: metric.stringMetric, } c.m.Unlock() } } -func parseValue(update *openconfig.Update) (float64, string, bool) { - // All metrics in Prometheus are floats, so only try to unmarshal as float64. +// ParseValue takes in an update and parses a value and suffix +// Returns an interface that contains either a string or a float64 as well as a suffix +// Unparseable updates return (0, empty string, false) +func parseValue(update *pb.Update) (interface{}, string, bool) { var intf interface{} if err := json.Unmarshal(update.Value.Value, &intf); err != nil { glog.Errorf("Can't parse value in update %v: %v", update, err) @@ -129,13 +172,16 @@ func parseValue(update *openconfig.Update) (float64, string, bool) { return val, "value", true } } + // float64 or string expected as the return value case bool: if value { - return 1, "", true + return float64(1), "", true } - return 0, "", true + return float64(0), "", true + case string: + return value, "", true default: - glog.V(9).Infof("Ignorig non-numeric update: %v", update) + glog.V(9).Infof("Ignoring update with unexpected type: %T", value) } return 0, "", false diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector_test.go b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector_test.go index 33e3d36b..9745f53c 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector_test.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/collector_test.go @@ -5,33 +5,80 @@ package main import ( + "fmt" + "strings" "testing" "github.com/aristanetworks/goarista/test" - - "github.com/openconfig/reference/rpc/openconfig" + pb "github.com/openconfig/gnmi/proto/gnmi" "github.com/prometheus/client_golang/prometheus" ) -func makeMetrics(cfg *Config, expValues map[source]float64) map[source]*labelledMetric { +func makeMetrics(cfg *Config, expValues map[source]float64, notification *pb.Notification, + prevMetrics map[source]*labelledMetric) map[source]*labelledMetric { + expMetrics := map[source]*labelledMetric{} - for k, v := range expValues { - desc, labels := cfg.getDescAndLabels(k) - if desc == nil || labels == nil { - panic("cfg.getDescAndLabels returned nil") + if prevMetrics != nil { + expMetrics = prevMetrics + } + for src, v := range expValues { + metric := cfg.getMetricValues(src) + if metric == nil || metric.desc == nil || metric.labels == nil { + panic("cfg.getMetricValues returned nil") } - expMetrics[k] = &labelledMetric{ - metric: prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, v, labels...), - labels: labels, + // Preserve current value of labels + labels := metric.labels + if _, ok := expMetrics[src]; ok && expMetrics[src] != nil { + labels = expMetrics[src].labels + } + + // Handle string updates + if notification.Update != nil { + if update, err := findUpdate(notification, src.path); err == nil { + val, _, ok := parseValue(update) + if !ok { + continue + } + if strVal, ok := val.(string); ok { + if !metric.stringMetric { + continue + } + v = metric.defaultValue + labels[len(labels)-1] = strVal + } + } + } + expMetrics[src] = &labelledMetric{ + metric: prometheus.MustNewConstMetric(metric.desc, prometheus.GaugeValue, v, + labels...), + labels: labels, + defaultValue: metric.defaultValue, + stringMetric: metric.stringMetric, + } + } + // Handle deletion + for key := range expMetrics { + if _, ok := expValues[key]; !ok { + delete(expMetrics, key) } } - return expMetrics } -func makeResponse(notif *openconfig.Notification) *openconfig.SubscribeResponse { - return &openconfig.SubscribeResponse{ - Response: &openconfig.SubscribeResponse_Update{Update: notif}, +func findUpdate(notif *pb.Notification, path string) (*pb.Update, error) { + prefix := notif.Prefix.Element + for _, v := range notif.Update { + fullPath := "/" + strings.Join(append(prefix, v.Path.Element...), "/") + if strings.Contains(path, fullPath) || path == fullPath { + return v, nil + } + } + return nil, fmt.Errorf("Failed to find matching update for path %v", path) +} + +func makeResponse(notif *pb.Notification) *pb.SubscribeResponse { + return &pb.SubscribeResponse{ + Response: &pb.SubscribeResponse_Update{Update: notif}, } } @@ -49,6 +96,11 @@ subscriptions: - /Sysdb/environment/power/status - /Sysdb/bridging/igmpsnooping/forwarding/forwarding/status metrics: + - name: fanName + path: /Sysdb/environment/cooling/status/fan/name + help: Fan Name + valuelabel: name + defaultvalue: 2.5 - name: intfCounter path: /Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P.+)/intfCounter help: Per-Interface Bytes/Errors/Discards Counters @@ -64,79 +116,101 @@ metrics: } coll := newCollector(cfg) - notif := &openconfig.Notification{ - Prefix: &openconfig.Path{Element: []string{"Sysdb"}}, - Update: []*openconfig.Update{ + notif := &pb.Notification{ + Prefix: &pb.Path{Element: []string{"Sysdb"}}, + Update: []*pb.Update{ { - Path: &openconfig.Path{ + Path: &pb.Path{ Element: []string{"lag", "intfCounterDir", "Ethernet1", "intfCounter"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("42"), }, }, { - Path: &openconfig.Path{ + Path: &pb.Path{ Element: []string{"environment", "cooling", "status", "fan", "speed"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("{\"value\": 45}"), }, }, { - Path: &openconfig.Path{ + Path: &pb.Path{ Element: []string{"igmpsnooping", "vlanStatus", "2050", "ethGroup", "01:00:5e:01:01:01", "intf", "Cpu"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("true"), }, }, + { + Path: &pb.Path{ + Element: []string{"environment", "cooling", "status", "fan", "name"}, + }, + Value: &pb.Value{ + Type: pb.Encoding_JSON, + Value: []byte("\"Fan1.1\""), + }, + }, }, } expValues := map[source]float64{ - source{ + { addr: "10.1.1.1", path: "/Sysdb/lag/intfCounterDir/Ethernet1/intfCounter", }: 42, - source{ + { addr: "10.1.1.1", path: "/Sysdb/environment/cooling/status/fan/speed/value", }: 45, - source{ + { addr: "10.1.1.1", path: "/Sysdb/igmpsnooping/vlanStatus/2050/ethGroup/01:00:5e:01:01:01/intf/Cpu", }: 1, + { + addr: "10.1.1.1", + path: "/Sysdb/environment/cooling/status/fan/name", + }: 2.5, } coll.update("10.1.1.1:6042", makeResponse(notif)) - expMetrics := makeMetrics(cfg, expValues) + expMetrics := makeMetrics(cfg, expValues, notif, nil) if !test.DeepEqual(expMetrics, coll.metrics) { t.Errorf("Mismatched metrics: %v", test.Diff(expMetrics, coll.metrics)) } - // Update one value, and one path which is not a metric - notif = &openconfig.Notification{ - Prefix: &openconfig.Path{Element: []string{"Sysdb"}}, - Update: []*openconfig.Update{ + // Update two values, and one path which is not a metric + notif = &pb.Notification{ + Prefix: &pb.Path{Element: []string{"Sysdb"}}, + Update: []*pb.Update{ { - Path: &openconfig.Path{ + Path: &pb.Path{ Element: []string{"lag", "intfCounterDir", "Ethernet1", "intfCounter"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("52"), }, }, { - Path: &openconfig.Path{ + Path: &pb.Path{ + Element: []string{"environment", "cooling", "status", "fan", "name"}, + }, + Value: &pb.Value{ + Type: pb.Encoding_JSON, + Value: []byte("\"Fan2.1\""), + }, + }, + { + Path: &pb.Path{ Element: []string{"environment", "doesntexist", "status"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("{\"value\": 45}"), }, }, @@ -149,21 +223,21 @@ metrics: expValues[src] = 52 coll.update("10.1.1.1:6042", makeResponse(notif)) - expMetrics = makeMetrics(cfg, expValues) + expMetrics = makeMetrics(cfg, expValues, notif, expMetrics) if !test.DeepEqual(expMetrics, coll.metrics) { t.Errorf("Mismatched metrics: %v", test.Diff(expMetrics, coll.metrics)) } // Same path, different device - notif = &openconfig.Notification{ - Prefix: &openconfig.Path{Element: []string{"Sysdb"}}, - Update: []*openconfig.Update{ + notif = &pb.Notification{ + Prefix: &pb.Path{Element: []string{"Sysdb"}}, + Update: []*pb.Update{ { - Path: &openconfig.Path{ + Path: &pb.Path{ Element: []string{"lag", "intfCounterDir", "Ethernet1", "intfCounter"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("42"), }, }, @@ -173,15 +247,15 @@ metrics: expValues[src] = 42 coll.update("10.1.1.2:6042", makeResponse(notif)) - expMetrics = makeMetrics(cfg, expValues) + expMetrics = makeMetrics(cfg, expValues, notif, expMetrics) if !test.DeepEqual(expMetrics, coll.metrics) { t.Errorf("Mismatched metrics: %v", test.Diff(expMetrics, coll.metrics)) } // Delete a path - notif = &openconfig.Notification{ - Prefix: &openconfig.Path{Element: []string{"Sysdb"}}, - Delete: []*openconfig.Path{ + notif = &pb.Notification{ + Prefix: &pb.Path{Element: []string{"Sysdb"}}, + Delete: []*pb.Path{ { Element: []string{"lag", "intfCounterDir", "Ethernet1", "intfCounter"}, }, @@ -191,21 +265,21 @@ metrics: delete(expValues, src) coll.update("10.1.1.1:6042", makeResponse(notif)) - expMetrics = makeMetrics(cfg, expValues) + expMetrics = makeMetrics(cfg, expValues, notif, expMetrics) if !test.DeepEqual(expMetrics, coll.metrics) { t.Errorf("Mismatched metrics: %v", test.Diff(expMetrics, coll.metrics)) } - // Non-numeric update - notif = &openconfig.Notification{ - Prefix: &openconfig.Path{Element: []string{"Sysdb"}}, - Update: []*openconfig.Update{ + // Non-numeric update to path without value label + notif = &pb.Notification{ + Prefix: &pb.Path{Element: []string{"Sysdb"}}, + Update: []*pb.Update{ { - Path: &openconfig.Path{ + Path: &pb.Path{ Element: []string{"lag", "intfCounterDir", "Ethernet1", "intfCounter"}, }, - Value: &openconfig.Value{ - Type: openconfig.Type_JSON, + Value: &pb.Value{ + Type: pb.Encoding_JSON, Value: []byte("\"test\""), }, }, @@ -213,6 +287,7 @@ metrics: } coll.update("10.1.1.1:6042", makeResponse(notif)) + // Don't make new metrics as it should have no effect if !test.DeepEqual(expMetrics, coll.metrics) { t.Errorf("Mismatched metrics: %v", test.Diff(expMetrics, coll.metrics)) } diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config.go b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config.go index 3e3adf3f..ace655e9 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config.go @@ -33,7 +33,7 @@ type MetricDef struct { Path string // Path compiled as a regexp. - re *regexp.Regexp + re *regexp.Regexp `deepequal:"ignore"` // Metric name. Name string @@ -41,6 +41,15 @@ type MetricDef struct { // Metric help string. Help string + // Label to store string values + ValueLabel string + + // Default value to display for string values + DefaultValue float64 + + // Does the metric store a string value + stringMetric bool + // This map contains the metric descriptors for this metric for each device. devDesc map[string]*prometheus.Desc @@ -48,6 +57,14 @@ type MetricDef struct { desc *prometheus.Desc } +// metricValues contains the values used in updating a metric +type metricValues struct { + desc *prometheus.Desc + labels []string + defaultValue float64 + stringMetric bool +} + // Parses the config and creates the descriptors for each path and device. func parseConfig(cfg []byte) (*Config, error) { config := &Config{ @@ -56,10 +73,8 @@ func parseConfig(cfg []byte) (*Config, error) { if err := yaml.Unmarshal(cfg, config); err != nil { return nil, fmt.Errorf("Failed to parse config: %v", err) } - for _, def := range config.Metrics { def.re = regexp.MustCompile(def.Path) - // Extract label names reNames := def.re.SubexpNames()[1:] labelNames := make([]string, len(reNames)) @@ -69,7 +84,10 @@ func parseConfig(cfg []byte) (*Config, error) { labelNames[i] = "unnamedLabel" + strconv.Itoa(i+1) } } - + if def.ValueLabel != "" { + labelNames = append(labelNames, def.ValueLabel) + def.stringMetric = true + } // Create a default descriptor only if there aren't any per-device labels, // or if it's explicitly declared if len(config.DeviceLabels) == 0 || len(config.DeviceLabels["*"]) > 0 { @@ -88,20 +106,25 @@ func parseConfig(cfg []byte) (*Config, error) { return config, nil } -// Returns the descriptor corresponding to the device and path, and labels extracted from the path. +// Returns a struct containing the descriptor corresponding to the device and path, labels +// extracted from the path, the default value for the metric and if it accepts string values. // If the device and path doesn't match any metrics, returns nil. -func (c *Config) getDescAndLabels(s source) (*prometheus.Desc, []string) { +func (c *Config) getMetricValues(s source) *metricValues { for _, def := range c.Metrics { if groups := def.re.FindStringSubmatch(s.path); groups != nil { - if desc, ok := def.devDesc[s.addr]; ok { - return desc, groups[1:] + if def.ValueLabel != "" { + groups = append(groups, def.ValueLabel) } - - return def.desc, groups[1:] + desc, ok := def.devDesc[s.addr] + if !ok { + desc = def.desc + } + return &metricValues{desc: desc, labels: groups[1:], defaultValue: def.DefaultValue, + stringMetric: def.stringMetric} } } - return nil, nil + return nil } // Sends all the descriptors to the channel. diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config_test.go b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config_test.go index 67a167e9..64f97ea7 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config_test.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/config_test.go @@ -31,6 +31,11 @@ subscriptions: - /Sysdb/environment/cooling/status - /Sysdb/environment/power/status metrics: + - name: fanName + path: /Sysdb/environment/cooling/status/fan/name + help: Fan Name + valuelabel: name + defaultvalue: 25 - name: intfCounter path: /Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P.+)/intfCounter help: Per-Interface Bytes/Errors/Discards Counters @@ -53,6 +58,26 @@ metrics: "/Sysdb/environment/power/status", }, Metrics: []*MetricDef{ + { + Path: "/Sysdb/environment/cooling/status/fan/name", + re: regexp.MustCompile( + "/Sysdb/environment/cooling/status/fan/name"), + Name: "fanName", + Help: "Fan Name", + ValueLabel: "name", + DefaultValue: 25, + stringMetric: true, + devDesc: map[string]*prometheus.Desc{ + "10.1.1.1": prometheus.NewDesc("fanName", + "Fan Name", + []string{"name"}, + prometheus.Labels{"lab1": "val1", "lab2": "val2"}), + }, + desc: prometheus.NewDesc("fanName", + "Fan Name", + []string{"name"}, + prometheus.Labels{"lab1": "val3", "lab2": "val4"}), + }, { Path: "/Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P.+)/intfCounter", re: regexp.MustCompile( @@ -126,8 +151,9 @@ metrics: prometheus.Labels{"lab1": "val3", "lab2": "val4"}), }, { - Path: "/Sysdb/environment/cooling/fan/speed/value", - re: regexp.MustCompile("/Sysdb/environment/cooling/fan/speed/value"), + Path: "/Sysdb/environment/cooling/fan/speed/value", + re: regexp.MustCompile( + "/Sysdb/environment/cooling/fan/speed/value"), Name: "fanSpeed", Help: "Fan Speed", devDesc: map[string]*prometheus.Desc{}, @@ -180,7 +206,8 @@ metrics: }, { Path: "/Sysdb/environment/cooling/fan/speed/value", - re: regexp.MustCompile("/Sysdb/environment/cooling/fan/speed/value"), + re: regexp.MustCompile( + "/Sysdb/environment/cooling/fan/speed/value"), Name: "fanSpeed", Help: "Fan Speed", devDesc: map[string]*prometheus.Desc{ @@ -222,8 +249,9 @@ metrics: []string{"intf"}, prometheus.Labels{}), }, { - Path: "/Sysdb/environment/cooling/fan/speed/value", - re: regexp.MustCompile("/Sysdb/environment/cooling/fan/speed/value"), + Path: "/Sysdb/environment/cooling/fan/speed/value", + re: regexp.MustCompile( + "/Sysdb/environment/cooling/fan/speed/value"), Name: "fanSpeed", Help: "Fan Speed", devDesc: map[string]*prometheus.Desc{}, @@ -247,7 +275,7 @@ metrics: } } -func TestGetDescAndLabels(t *testing.T) { +func TestGetMetricValues(t *testing.T) { config := []byte(` devicelabels: 10.1.1.1: @@ -317,12 +345,16 @@ metrics: } for i, c := range tCases { - desc, labels := cfg.getDescAndLabels(c.src) - if !test.DeepEqual(desc, c.desc) { - t.Errorf("Test case %d: desc mismatch %v", i+1, test.Diff(desc, c.desc)) + metric := cfg.getMetricValues(c.src) + if metric == nil { + // Avoids error from trying to access metric.desc when metric is nil + metric = &metricValues{} } - if !test.DeepEqual(labels, c.labels) { - t.Errorf("Test case %d: labels mismatch %v", i+1, test.Diff(labels, c.labels)) + if !test.DeepEqual(metric.desc, c.desc) { + t.Errorf("Test case %d: desc mismatch %v", i+1, test.Diff(metric.desc, c.desc)) + } + if !test.DeepEqual(metric.labels, c.labels) { + t.Errorf("Test case %d: labels mismatch %v", i+1, test.Diff(metric.labels, c.labels)) } } } diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/main.go b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/main.go index 0d0f78ab..d91e3c6b 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/main.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/main.go @@ -6,25 +6,39 @@ package main import ( + "context" "flag" "io/ioutil" "net/http" - "sync" - - "github.com/aristanetworks/goarista/openconfig/client" + "strings" "github.com/aristanetworks/glog" + "github.com/aristanetworks/goarista/gnmi" + pb "github.com/openconfig/gnmi/proto/gnmi" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { + // gNMI options + gNMIcfg := &gnmi.Config{} + flag.StringVar(&gNMIcfg.Addr, "addr", "localhost", "gNMI gRPC server `address`") + flag.StringVar(&gNMIcfg.CAFile, "cafile", "", "Path to server TLS certificate file") + flag.StringVar(&gNMIcfg.CertFile, "certfile", "", "Path to client TLS certificate file") + flag.StringVar(&gNMIcfg.KeyFile, "keyfile", "", "Path to client TLS private key file") + flag.StringVar(&gNMIcfg.Username, "username", "", "Username to authenticate with") + flag.StringVar(&gNMIcfg.Password, "password", "", "Password to authenticate with") + flag.BoolVar(&gNMIcfg.TLS, "tls", false, "Enable TLS") + subscribePaths := flag.String("subscribe", "/", "Comma-separated list of paths to subscribe to") + + // program options listenaddr := flag.String("listenaddr", ":8080", "Address on which to expose the metrics") url := flag.String("url", "/metrics", "URL where to expose the metrics") configFlag := flag.String("config", "", "Config to turn OpenConfig telemetry into Prometheus metrics") - username, password, subscriptions, addrs, opts := client.ParseFlags() + flag.Parse() + subscriptions := strings.Split(*subscribePaths, ",") if *configFlag == "" { glog.Fatal("You need specify a config file using -config flag") } @@ -39,7 +53,7 @@ func main() { // Ignore the default "subscribe-to-everything" subscription of the // -subscribe flag. - if subscriptions[0] == "" { + if subscriptions[0] == "/" { subscriptions = subscriptions[1:] } // Add the subscriptions from the config file. @@ -47,14 +61,33 @@ func main() { coll := newCollector(config) prometheus.MustRegister(coll) - - wg := new(sync.WaitGroup) - for _, addr := range addrs { - wg.Add(1) - c := client.New(username, password, addr, opts) - go c.Subscribe(wg, subscriptions, coll.update) + ctx := gnmi.NewContext(context.Background(), gNMIcfg) + client, err := gnmi.Dial(gNMIcfg) + if err != nil { + glog.Fatal(err) } + respChan := make(chan *pb.SubscribeResponse) + errChan := make(chan error) + subscribeOptions := &gnmi.SubscribeOptions{ + Mode: "stream", + StreamMode: "target_defined", + Paths: gnmi.SplitPaths(subscriptions), + } + go gnmi.Subscribe(ctx, client, subscribeOptions, respChan, errChan) + go handleSubscription(respChan, errChan, coll, gNMIcfg.Addr) http.Handle(*url, promhttp.Handler()) glog.Fatal(http.ListenAndServe(*listenaddr, nil)) } + +func handleSubscription(respChan chan *pb.SubscribeResponse, + errChan chan error, coll *collector, addr string) { + for { + select { + case resp := <-respChan: + coll.update(addr, resp) + case err := <-errChan: + glog.Fatal(err) + } + } +} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig_above_4.20.yml b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig_above_4.20.yml new file mode 100644 index 00000000..526f8659 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig_above_4.20.yml @@ -0,0 +1,80 @@ +# Per-device labels. Optional +# Exactly the same set of labels must be specified for each device. +# If device address is *, the labels apply to all devices not listed explicitly. +# If any explicit device if listed below, then you need to specify all devices you're subscribed to, +# or have a wildcard entry. Otherwise, updates from non-listed devices will be ignored. +#deviceLabels: +# 10.1.1.1: +# lab1: val1 +# lab2: val2 +# '*': +# lab1: val3 +# lab2: val4 + +# Subscriptions to OpenConfig paths. +subscriptions: + - /Smash/counters/ethIntf + - /Smash/interface/counter/lag/current/counter + - /Sysdb/environment/archer/cooling/status + - /Sysdb/environment/archer/power/status + - /Sysdb/environment/archer/temperature/status + - /Sysdb/hardware/archer/xcvr/status + - /Sysdb/interface/config/eth + +# Prometheus metrics configuration. +# If you use named capture groups in the path, they will be extracted into labels with the same name. +# All fields are mandatory. +metrics: + - name: interfaceDescription + path: /Sysdb/interface/config/eth/phy/slice/1/intfConfig/(?PEthernet.)/description + help: Description + valuelabel: description + defaultvalue: 15 + - name: intfCounter + path: /Smash/counters/ethIntf/FocalPointV2/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(Octets|Errors|Discards) + help: Per-Interface Bytes/Errors/Discards Counters + - name: intfLagCounter + path: /Smash/interface/counter/lag/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(Octets|Errors|Discards) + help: Per-Lag Bytes/Errors/Discards Counters + - name: intfPktCounter + path: /Smash/counters/ethIntf/FocalPointV2/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(?P(?:Ucast|Multicast|Broadcast))(Pkt) + help: Per-Interface Unicast/Multicast/Broadcast Packer Counters + - name: intfLagPktCounter + path: /Smash/interface/counter/lag/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(?P(?:Ucast|Multicast|Broadcast))(Pkt) + help: Per-Lag Unicast/Multicast/Broadcast Packer Counters + - name: intfPfcClassCounter + path: /Smash/counters/ethIntf/FocalPointV2/current/(counter)/(?P.+)/ethStatistics/(?P(?:in|out))(PfcClassFrames) + help: Per-Interface Input/Output PFC Frames Counters + - name: tempSensor + path: /Sysdb/(environment)/archer/temperature/status/(?P.+)/((?:maxT|t)emperature) + help: Temperature and Maximum Temperature + - name: tempSensorAlert + path: /Sysdb/(environment)/archer/temperature/status/(?P.+)/(alertRaisedCount) + help: Temperature Alerts Counter + - name: currentSensor + path: /Sysdb/(environment)/archer/power/status/currentSensor/(?P.+)/(current) + help: Current Levels + - name: powerSensor + path: /Sysdb/(environment)/archer/(power)/status/powerSupply/(?P.+)/(input|output)Power + help: Input/Output Power Levels + - name: voltageSensor + path: /Sysdb/(environment)/archer/power/status/voltageSensor/(?:cell/.+|system)/(?P.+)/(voltage) + help: Voltage Levels + - name: railCurrentSensor + path: /Sysdb/(environment)/archer/power/status/voltageSensor/(?:cell/.+|system)/(?P.+)/(current) + help: Rail Current Levels + - name: fanSpeed + path: /Sysdb/(environment)/archer/(cooling)/status/(?P.+)/speed + help: Fan Speed + - name: qsfpModularRxPower + path: /Sysdb/hardware/archer/(xcvr)/status/slice/(?P.+)/(?P.+)/domRegisterData/lane(?P\\d)(OpticalRxPower) + help: qsfpModularRxPower + - name: qsfpFixedRxPower + path: /Sysdb/hardware/archer/(xcvr)/status/all/(?P.+)/domRegisterData/lane(?P\\d)(OpticalRxPower) + help: qsfpFixedRxPower + - name: sfpModularTemperature + path: /Sysdb/hardware/archer/(xcvr)/status/slice/(?P.+)/(?P.+)/lastDomUpdateTime/(temperature) + help: sfpModularTemperature + - name: sfpFixedTemperature + path: /Sysdb/hardware/archer/(xcvr)/status/all/(?P.+)/lastDomUpdateTime/(temperature) + help: sfpFixedTemperature diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig.yml b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig_below_4.20.yml similarity index 90% rename from vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig.yml rename to vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig_below_4.20.yml index d1438a43..2c02249b 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig.yml +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocprometheus/sampleconfig_below_4.20.yml @@ -18,11 +18,18 @@ subscriptions: - /Sysdb/environment/temperature/status - /Sysdb/interface/counter/eth/lag - /Sysdb/interface/counter/eth/slice/phy + - /Sysdb/interface/config + - /Sysdb/interface/config/eth/phy/slice/1/intfConfig # Prometheus metrics configuration. # If you use named capture groups in the path, they will be extracted into labels with the same name. # All fields are mandatory. metrics: + - name: interfaceDescription + path: Sysdb/interface/config/eth/phy/slice/1/intfConfig/(?PEthernet.)/description + help: Description + valuelabel: description + defaultvalue: 15 - name: intfCounter path: /Sysdb/interface/counter/eth/(?:lag|slice/phy/.+)/intfCounterDir/(?P.+)/intfCounter/current/statistics/(?P(?:in|out))(?P(Octets|Errors|Discards)) help: Per-Interface Bytes/Errors/Discards Counters diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocredis/README.md b/vendor/github.com/aristanetworks/goarista/cmd/ocredis/README.md index 8fc1ca1a..195f35ec 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocredis/README.md +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocredis/README.md @@ -17,5 +17,5 @@ See the `-help` output, but here's an example to push all the temperature sensors into Redis. You can also not pass any `-subscribe` flag to push _everything_ into Redis. ``` -ocredis -subscribe /Sysdb/environment/temperature -addrs :6042 -redis :6379 +ocredis -subscribe /Sysdb/environment/temperature -addr :6042 -redis :6379 ``` diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocredis/main.go b/vendor/github.com/aristanetworks/goarista/cmd/ocredis/main.go index 26132ac9..9926396a 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocredis/main.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocredis/main.go @@ -8,16 +8,15 @@ package main import ( + "context" "encoding/json" "flag" "strings" - "sync" - occlient "github.com/aristanetworks/goarista/openconfig/client" + "github.com/aristanetworks/goarista/gnmi" "github.com/aristanetworks/glog" - "github.com/golang/protobuf/proto" - "github.com/openconfig/reference/rpc/openconfig" + pb "github.com/openconfig/gnmi/proto/gnmi" redis "gopkg.in/redis.v4" ) @@ -42,11 +41,23 @@ type baseClient interface { var client baseClient func main() { - username, password, subscriptions, hostAddrs, opts := occlient.ParseFlags() + + // gNMI options + cfg := &gnmi.Config{} + flag.StringVar(&cfg.Addr, "addr", "localhost", "gNMI gRPC server `address`") + flag.StringVar(&cfg.CAFile, "cafile", "", "Path to server TLS certificate file") + flag.StringVar(&cfg.CertFile, "certfile", "", "Path to client TLS certificate file") + flag.StringVar(&cfg.KeyFile, "keyfile", "", "Path to client TLS private key file") + flag.StringVar(&cfg.Username, "username", "", "Username to authenticate with") + flag.StringVar(&cfg.Password, "password", "", "Password to authenticate with") + flag.BoolVar(&cfg.TLS, "tls", false, "Enable TLS") + subscribePaths := flag.String("subscribe", "/", "Comma-separated list of paths to subscribe to") + flag.Parse() if *redisFlag == "" { glog.Fatal("Specify the address of the Redis server to write to with -redis") } + subscriptions := strings.Split(*subscribePaths, ",") redisAddrs := strings.Split(*redisFlag, ",") if !*clusterMode && len(redisAddrs) > 1 { glog.Fatal("Please pass only 1 redis address in noncluster mode or enable cluster mode") @@ -72,25 +83,27 @@ func main() { if err != nil { glog.Fatal("Failed to connect to client: ", err) } - - ocPublish := func(addr string, message proto.Message) { - resp, ok := message.(*openconfig.SubscribeResponse) - if !ok { - glog.Errorf("Unexpected type of message: %T", message) - return - } - if notif := resp.GetUpdate(); notif != nil { - bufferToRedis(addr, notif) + ctx := gnmi.NewContext(context.Background(), cfg) + client, err := gnmi.Dial(cfg) + if err != nil { + glog.Fatal(err) + } + respChan := make(chan *pb.SubscribeResponse) + errChan := make(chan error) + subscribeOptions := &gnmi.SubscribeOptions{ + Mode: "stream", + StreamMode: "target_defined", + Paths: gnmi.SplitPaths(subscriptions), + } + go gnmi.Subscribe(ctx, client, subscribeOptions, respChan, errChan) + for { + select { + case resp := <-respChan: + bufferToRedis(cfg.Addr, resp.GetUpdate()) + case err := <-errChan: + glog.Fatal(err) } } - - wg := new(sync.WaitGroup) - for _, hostAddr := range hostAddrs { - wg.Add(1) - c := occlient.New(username, password, hostAddr, opts) - go c.Subscribe(wg, subscriptions, ocPublish) - } - wg.Wait() } type redisData struct { @@ -100,7 +113,12 @@ type redisData struct { pub map[string]interface{} } -func bufferToRedis(addr string, notif *openconfig.Notification) { +func bufferToRedis(addr string, notif *pb.Notification) { + if notif == nil { + // possible that this should be ignored silently + glog.Error("Nil notification ignored") + return + } path := addr + "/" + joinPath(notif.Prefix) data := &redisData{key: path} @@ -167,20 +185,21 @@ func redisPublish(path, kind string, payload interface{}) { } } -func joinPath(path *openconfig.Path) string { +func joinPath(path *pb.Path) string { + // path.Elem is empty for some reason so using path.Element instead return strings.Join(path.Element, "/") } -func convertUpdate(update *openconfig.Update) interface{} { +func convertUpdate(update *pb.Update) interface{} { switch update.Value.Type { - case openconfig.Type_JSON: + case pb.Encoding_JSON: var value interface{} err := json.Unmarshal(update.Value.Value, &value) if err != nil { glog.Fatalf("Malformed JSON update %q in %s", update.Value.Value, update) } return value - case openconfig.Type_BYTES: + case pb.Encoding_BYTES: return update.Value.Value default: glog.Fatalf("Unhandled type of value %v in %s", update.Value.Type, update) diff --git a/vendor/github.com/aristanetworks/goarista/cmd/ocsplunk/main.go b/vendor/github.com/aristanetworks/goarista/cmd/ocsplunk/main.go index 780e8f9d..f6db1efd 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/ocsplunk/main.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/ocsplunk/main.go @@ -14,9 +14,10 @@ import ( "strings" "time" + "github.com/aristanetworks/glog" "github.com/aristanetworks/goarista/gnmi" + "github.com/aristanetworks/splunk-hec-go" - "github.com/fuyufjh/splunk-hec-go" pb "github.com/openconfig/gnmi/proto/gnmi" ) @@ -49,7 +50,10 @@ func main() { ctx := gnmi.NewContext(context.Background(), cfg) // Store the address without the port so it can be used as the host in the Splunk event. addr := cfg.Addr - client := gnmi.Dial(cfg) + client, err := gnmi.Dial(cfg) + if err != nil { + glog.Fatal(err) + } // Splunk connection urls := strings.Split(*splunkURLs, ",") @@ -67,10 +71,14 @@ func main() { // gNMI subscription respChan := make(chan *pb.SubscribeResponse) errChan := make(chan error) - defer close(respChan) defer close(errChan) paths := strings.Split(*subscribePaths, ",") - go gnmi.Subscribe(ctx, client, gnmi.SplitPaths(paths), respChan, errChan) + subscribeOptions := &gnmi.SubscribeOptions{ + Mode: "stream", + StreamMode: "target_defined", + Paths: gnmi.SplitPaths(paths), + } + go gnmi.Subscribe(ctx, client, subscribeOptions, respChan, errChan) // Forward subscribe responses to Splunk for { diff --git a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/README.md b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/README.md index a47333e2..4026f3cc 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/README.md +++ b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/README.md @@ -6,28 +6,51 @@ dropped. This tool requires a config file to specify how to map the path of the notificatons coming out of the OpenConfig gRPC interface onto OpenTSDB -metric names, and how to extract tags from the path. For example, the -following rule, excerpt from `sampleconfig.json`: +metric names, and how to extract tags from the path. + +## Getting Started +To begin, a list of subscriptions is required (excerpt from `sampleconfig.json`): ```json - "metrics": { - "tempSensor": { - "path": "/Sysdb/(environment)/temperature/status/tempSensor/(?P.+)/((?:maxT|t)emperature)/value" - }, - ... + "subscriptions": [ + "/Sysdb/interface/counter/eth/lag", + "/Sysdb/interface/counter/eth/slice/phy", + + "/Sysdb/environment/temperature/status", + "/Sysdb/environment/cooling/status", + "/Sysdb/environment/power/status", + + "/Sysdb/hardware/xcvr/status/all/xcvrStatus" + ], + ... ``` -Applied to an update for the path -`/Sysdb/environment/temperature/status/tempSensor/TempSensor1/temperature/value` -will lead to the metric name `environment.temperature` and tags `sensor=TempSensor1`. +Note that subscriptions should not end with a trailing `/` as that will cause +the subscription to fail. -Basically, un-named groups are used to make up the metric name, and named -groups are used to extract (optional) tags. +Afterwards, the metrics are defined (excerpt from `sampleconfig.json`): + +```json + "metrics": { + "tempSensor": { + "path": "/Sysdb/(environment)/temperature/status/tempSensor/(?P.+)/((?:maxT|t)emperature)" + }, + ... + } +``` + +In the metrics path, unnamed matched groups are used to make up the metric name, and named matched groups +are used to extract optional tags. Note that unnamed groups are required, otherwise the metric +name will be empty and the update will be silently dropped. + +For example, using the above metrics path applied to an update for the path +`/Sysdb/environment/temperature/status/tempSensor/TempSensor1/temperature` +will lead to the metric name `environment.temperature` and tags `sensor=TempSensor1`. ## Usage See the `-help` output, but here's an example to push all the metrics defined in the sample config file: ``` -octsdb -addrs :6042 -config sampleconfig.json -text | nc 4242 +octsdb -addr :6042 -config sampleconfig.json -text | nc 4242 ``` diff --git a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/config_test.go b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/config_test.go index 56a326f3..ab0daa2f 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/config_test.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/config_test.go @@ -16,6 +16,9 @@ func TestConfig(t *testing.T) { t.Fatal("Managed to load a nonexistent config!") } cfg, err = loadConfig("sampleconfig.json") + if err != nil { + t.Fatal("Failed to load config:", err) + } testcases := []struct { path string diff --git a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main.go b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main.go index 6824bc16..3daadb16 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main.go @@ -7,22 +7,35 @@ package main import ( "bytes" + "context" "encoding/json" "flag" "os" "strconv" "strings" - "sync" "time" - "github.com/aristanetworks/goarista/openconfig/client" + "github.com/aristanetworks/goarista/gnmi" "github.com/aristanetworks/glog" - "github.com/golang/protobuf/proto" - "github.com/openconfig/reference/rpc/openconfig" + pb "github.com/openconfig/gnmi/proto/gnmi" ) func main() { + + // gNMI options + cfg := &gnmi.Config{} + flag.StringVar(&cfg.Addr, "addr", "localhost", "gNMI gRPC server `address`") + flag.StringVar(&cfg.CAFile, "cafile", "", "Path to server TLS certificate file") + flag.StringVar(&cfg.CertFile, "certfile", "", "Path to client TLS certificate file") + flag.StringVar(&cfg.KeyFile, "keyfile", "", "Path to client TLS private key file") + flag.StringVar(&cfg.Username, "username", "", "Username to authenticate with") + flag.StringVar(&cfg.Password, "password", "", "Password to authenticate with") + flag.BoolVar(&cfg.TLS, "tls", false, "Enable TLS") + + // Program options + subscribePaths := flag.String("paths", "/", "Comma-separated list of paths to subscribe to") + tsdbFlag := flag.String("tsdb", "", "Address of the OpenTSDB server where to push telemetry to") textFlag := flag.Bool("text", false, @@ -38,8 +51,8 @@ func main() { " Clients and servers should have the same number.") udpTimeoutFlag := flag.Duration("udptimeout", 2*time.Second, "Timeout for each") - username, password, subscriptions, addrs, opts := client.ParseFlags() + flag.Parse() if !(*tsdbFlag != "" || *textFlag || *udpAddrFlag != "") { glog.Fatal("Specify the address of the OpenTSDB server to write to with -tsdb") } else if *configFlag == "" { @@ -52,6 +65,7 @@ func main() { } // Ignore the default "subscribe-to-everything" subscription of the // -subscribe flag. + subscriptions := strings.Split(*subscribePaths, ",") if subscriptions[0] == "" { subscriptions = subscriptions[1:] } @@ -79,33 +93,37 @@ func main() { // TODO: support HTTP(S). c = newTelnetClient(*tsdbFlag) } - - wg := new(sync.WaitGroup) - for _, addr := range addrs { - wg.Add(1) - publish := func(addr string, message proto.Message) { - resp, ok := message.(*openconfig.SubscribeResponse) - if !ok { - glog.Errorf("Unexpected type of message: %T", message) - return - } - if notif := resp.GetUpdate(); notif != nil { - pushToOpenTSDB(addr, c, config, notif) - } - } - c := client.New(username, password, addr, opts) - go c.Subscribe(wg, subscriptions, publish) + ctx := gnmi.NewContext(context.Background(), cfg) + client, err := gnmi.Dial(cfg) + if err != nil { + glog.Fatal(err) + } + respChan := make(chan *pb.SubscribeResponse) + errChan := make(chan error) + subscribeOptions := &gnmi.SubscribeOptions{ + Mode: "stream", + StreamMode: "target_defined", + Paths: gnmi.SplitPaths(subscriptions), + } + go gnmi.Subscribe(ctx, client, subscribeOptions, respChan, errChan) + for { + select { + case resp := <-respChan: + pushToOpenTSDB(cfg.Addr, c, config, resp.GetUpdate()) + case err := <-errChan: + glog.Fatal(err) + } } - wg.Wait() } -func pushToOpenTSDB(addr string, conn OpenTSDBConn, config *Config, - notif *openconfig.Notification) { - +func pushToOpenTSDB(addr string, conn OpenTSDBConn, config *Config, notif *pb.Notification) { + if notif == nil { + glog.Error("Nil notification ignored") + return + } if notif.Timestamp <= 0 { glog.Fatalf("Invalid timestamp %d in %s", notif.Timestamp, notif) } - host := addr[:strings.IndexRune(addr, ':')] if host == "localhost" { // TODO: On Linux this reads /proc/sys/kernel/hostname each time, @@ -118,18 +136,15 @@ func pushToOpenTSDB(addr string, conn OpenTSDBConn, config *Config, } } prefix := "/" + strings.Join(notif.Prefix.Element, "/") - for _, update := range notif.Update { - if update.Value == nil || update.Value.Type != openconfig.Type_JSON { + if update.Value == nil || update.Value.Type != pb.Encoding_JSON { glog.V(9).Infof("Ignoring incompatible update value in %s", update) continue } - value := parseValue(update) if value == nil { continue } - path := prefix + "/" + strings.Join(update.Path.Element, "/") metricName, tags := config.Match(path) if metricName == "" { @@ -137,7 +152,6 @@ func pushToOpenTSDB(addr string, conn OpenTSDBConn, config *Config, continue } tags["host"] = host - for i, v := range value { if len(value) > 1 { tags["index"] = strconv.Itoa(i) @@ -158,7 +172,7 @@ func pushToOpenTSDB(addr string, conn OpenTSDBConn, config *Config, // parseValue returns either an integer/floating point value of the given update, or if // the value is a slice of integers/floating point values. If the value is neither of these // or if any element in the slice is non numerical, parseValue returns nil. -func parseValue(update *openconfig.Update) []interface{} { +func parseValue(update *pb.Update) []interface{} { var value interface{} decoder := json.NewDecoder(bytes.NewReader(update.Value.Value)) @@ -196,7 +210,7 @@ func parseValue(update *openconfig.Update) []interface{} { } // Convert our json.Number to either an int64, uint64, or float64. -func parseNumber(num json.Number, update *openconfig.Update) interface{} { +func parseNumber(num json.Number, update *pb.Update) interface{} { var value interface{} var err error if value, err = num.Int64(); err != nil { diff --git a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main_test.go b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main_test.go index c42fe997..64d10c95 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main_test.go +++ b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/main_test.go @@ -9,8 +9,7 @@ import ( "testing" "github.com/aristanetworks/goarista/test" - - "github.com/openconfig/reference/rpc/openconfig" + pb "github.com/openconfig/gnmi/proto/gnmi" ) func TestParseValue(t *testing.T) { // Because parsing JSON sucks. @@ -35,8 +34,8 @@ func TestParseValue(t *testing.T) { // Because parsing JSON sucks. }, } for i, tcase := range testcases { - actual := parseValue(&openconfig.Update{ - Value: &openconfig.Value{ + actual := parseValue(&pb.Update{ + Value: &pb.Value{ Value: []byte(tcase.input), }, }) diff --git a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig.json b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig.json index cfe56b82..a5ececf4 100644 --- a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig.json +++ b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig.json @@ -1,11 +1,14 @@ { - "comment": "This is a sample configuration", + "comment": "This is a sample configuration for EOS versions below 4.20", "subscriptions": [ + "/Sysdb/interface/counter/eth/lag", + "/Sysdb/interface/counter/eth/slice/phy", + + "/Sysdb/environment/temperature/status", "/Sysdb/environment/cooling/status", "/Sysdb/environment/power/status", - "/Sysdb/environment/temperature/status", - "/Sysdb/interface/counter/eth/lag", - "/Sysdb/interface/counter/eth/slice/phy" + + "/Sysdb/hardware/xcvr/status/all/xcvrStatus" ], "metricPrefix": "eos", "metrics": { @@ -20,25 +23,32 @@ }, "tempSensor": { - "path": "/Sysdb/(environment)/temperature/status/tempSensor/(?P.+)/((?:maxT|t)emperature)/value" + "path": "/Sysdb/(environment)/temperature/status/tempSensor/(?P.+)/((?:maxT|t)emperature)" }, "tempSensorAlert": { "path": "/Sysdb/(environment)/temperature/status/tempSensor/(?P.+)/(alertRaisedCount)" }, "currentSensor": { - "path": "/Sysdb/(environment)/power/status/currentSensor/(?P.+)/(current)/value" + "path": "/Sysdb/(environment)/power/status/currentSensor/(?P.+)/(current)" }, "powerSensor": { - "path": "/Sysdb/(environment/power)/status/powerSupply/(?P.+)/(input|output)Power/value" + "path": "/Sysdb/(environment/power)/status/powerSupply/(?P.+)/(input|output)Power" }, "voltageSensor": { - "path": "/Sysdb/(environment)/power/status/voltageSensor/(?P.+)/(voltage)/value" + "path": "/Sysdb/(environment)/power/status/voltageSensor/(?P.+)/(voltage)" }, "railCurrentSensor": { - "path": "/Sysdb/(environment)/power/status/voltageSensor/(?P.+)/(current)/value" + "path": "/Sysdb/(environment)/power/status/voltageSensor/(?P.+)/(current)" }, "fanSpeed": { - "path": "/Sysdb/(environment)/cooling/status/(fan)/(?P.+)/(speed)/value" + "path": "/Sysdb/(environment)/cooling/status/(fan)/(?P.+)/(speed)" + }, + + "qsfpRxPower": { + "path": "/Sysdb/hardware/(xcvr)/status/all/xcvrStatus/(?P.+)/domRegisterData/lane(?P\\d)(OpticalRxPower)" + }, + "sfpTemperature": { + "path": "/Sysdb/hardware/(xcvr)/status/all/xcvrStatus/(?P.+)/lastDomUpdateTime/(temperature)" } } } diff --git a/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig4.20.json b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig4.20.json new file mode 100644 index 00000000..b9ba7309 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/octsdb/sampleconfig4.20.json @@ -0,0 +1,66 @@ +{ + "comment": "This is a sample configuration for EOS versions above 4.20", + "subscriptions": [ + "/Smash/counters/ethIntf", + "/Smash/interface/counter/lag/current/counter", + + "/Sysdb/environment/archer/cooling/status", + "/Sysdb/environment/archer/power/status", + "/Sysdb/environment/archer/temperature/status", + + "/Sysdb/hardware/archer/xcvr/status" + ], + "metricPrefix": "eos", + "metrics": { + "intfCounter": { + "path": "/Smash/counters/ethIntf/FocalPointV2/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(Octets|Errors|Discards)" + }, + "intfLagCounter": { + "path": "/Smash/interface/counter/lag/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(Octets|Errors|Discards)" + }, + "intfPktCounter": { + "path": "/Smash/counters/ethIntf/FocalPointV2/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(?P(?:Ucast|Multicast|Broadcast))(Pkt)" + }, + "intfLagPktCounter": { + "path": "/Smash/interface/counter/lag/current/(counter)/(?P.+)/statistics/(?P(?:in|out))(?P(?:Ucast|Multicast|Broadcast))(Pkt)" + }, + "intfPfcClassCounter": { + "path": "/Smash/counters/ethIntf/FocalPointV2/current/(counter)/(?P.+)/ethStatistics/(?P(?:in|out))(PfcClassFrames)" + }, + + "tempSensor": { + "path": "/Sysdb/(environment)/archer/temperature/status/(?P.+)/((?:maxT|t)emperature)" + }, + "tempSensorAlert": { + "path": "/Sysdb/(environment)/archer/temperature/status/(?P.+)/(alertRaisedCount)" + }, + "currentSensor": { + "path": "/Sysdb/(environment)/archer/power/status/currentSensor/(?P.+)/(current)" + }, + "powerSensor": { + "path": "/Sysdb/(environment)/archer/(power)/status/powerSupply/(?P.+)/(input|output)Power" + }, + "voltageSensor": { + "path": "/Sysdb/(environment)/archer/power/status/voltageSensor/(?:cell/.+|system)/(?P.+)/(voltage)" + }, + "railCurrentSensor": { + "path": "/Sysdb/(environment)/archer/power/status/voltageSensor/(?:cell/.+|system)/(?P.+)/(current)" + }, + "fanSpeed": { + "path": "/Sysdb/(environment)/archer/(cooling)/status/(?P.+)/speed" + }, + + "qsfpModularRxPower": { + "path": "/Sysdb/hardware/archer/(xcvr)/status/slice/(?P.+)/(?P.+)/domRegisterData/lane(?P\\d)(OpticalRxPower)" + }, + "qsfpFixedRxPower": { + "path": "/Sysdb/hardware/archer/(xcvr)/status/all/(?P.+)/domRegisterData/lane(?P\\d)(OpticalRxPower)" + }, + "sfpModularTemperature": { + "path": "/Sysdb/hardware/archer/(xcvr)/status/slice/(?P.+)/(?P.+)/lastDomUpdateTime/(temperature)" + }, + "sfpFixedTemperature": { + "path": "/Sysdb/hardware/archer/(xcvr)/status/all/(?P.+)/lastDomUpdateTime/(temperature)" + } + } +} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/main.go b/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/main.go new file mode 100644 index 00000000..a4caa2ae --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/main.go @@ -0,0 +1,286 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +// test2influxdb writes results from 'go test -json' to an influxdb +// database. +// +// Example usage: +// +// go test -json | test2influxdb [options...] +// +// Points are written to influxdb with tags: +// +// package +// type "package" for a package result; "test" for a test result +// Additional tags set by -tags flag +// +// And fields: +// +// test string // "NONE" for whole package results +// elapsed float64 // in seconds +// pass float64 // 1 for PASS, 0 for FAIL +// Additional fields set by -fields flag +// +// "test" is a field instead of a tag to reduce cardinality of data. +// +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" + + "github.com/aristanetworks/glog" + client "github.com/influxdata/influxdb/client/v2" +) + +type tag struct { + key string + value string +} + +type tags []tag + +func (ts *tags) String() string { + s := make([]string, len(*ts)) + for i, t := range *ts { + s[i] = t.key + "=" + t.value + } + return strings.Join(s, ",") +} + +func (ts *tags) Set(s string) error { + for _, fieldString := range strings.Split(s, ",") { + kv := strings.Split(fieldString, "=") + if len(kv) != 2 { + return fmt.Errorf("invalid tag, expecting one '=': %q", fieldString) + } + key := strings.TrimSpace(kv[0]) + if key == "" { + return fmt.Errorf("invalid tag key %q in %q", key, fieldString) + } + val := strings.TrimSpace(kv[1]) + if val == "" { + return fmt.Errorf("invalid tag value %q in %q", val, fieldString) + } + + *ts = append(*ts, tag{key: key, value: val}) + } + return nil +} + +type field struct { + key string + value interface{} +} + +type fields []field + +func (fs *fields) String() string { + s := make([]string, len(*fs)) + for i, f := range *fs { + var valString string + switch v := f.value.(type) { + case bool: + valString = strconv.FormatBool(v) + case float64: + valString = strconv.FormatFloat(v, 'f', -1, 64) + case int64: + valString = strconv.FormatInt(v, 10) + "i" + case string: + valString = v + } + + s[i] = f.key + "=" + valString + } + return strings.Join(s, ",") +} + +func (fs *fields) Set(s string) error { + for _, fieldString := range strings.Split(s, ",") { + kv := strings.Split(fieldString, "=") + if len(kv) != 2 { + return fmt.Errorf("invalid field, expecting one '=': %q", fieldString) + } + key := strings.TrimSpace(kv[0]) + if key == "" { + return fmt.Errorf("invalid field key %q in %q", key, fieldString) + } + val := strings.TrimSpace(kv[1]) + if val == "" { + return fmt.Errorf("invalid field value %q in %q", val, fieldString) + } + var value interface{} + var err error + if value, err = strconv.ParseBool(val); err == nil { + // It's a bool + } else if value, err = strconv.ParseFloat(val, 64); err == nil { + // It's a float64 + } else if value, err = strconv.ParseInt(val[:len(val)-1], 0, 64); err == nil && + val[len(val)-1] == 'i' { + // ints are suffixed with an "i" + } else { + value = val + } + + *fs = append(*fs, field{key: key, value: value}) + } + return nil +} + +var ( + flagAddr = flag.String("addr", "http://localhost:8086", "adddress of influxdb database") + flagDB = flag.String("db", "gotest", "use `database` in influxdb") + flagMeasurement = flag.String("m", "result", "`measurement` used in influxdb database") + + flagTags tags + flagFields fields +) + +func init() { + flag.Var(&flagTags, "tags", "set additional `tags`. Ex: name=alice,food=pasta") + flag.Var(&flagFields, "fields", "set additional `fields`. Ex: id=1234i,long=34.123,lat=72.234") +} + +func main() { + flag.Parse() + + c, err := client.NewHTTPClient(client.HTTPConfig{ + Addr: *flagAddr, + }) + if err != nil { + glog.Fatal(err) + } + + batch, err := client.NewBatchPoints(client.BatchPointsConfig{Database: *flagDB}) + if err != nil { + glog.Fatal(err) + } + + if err := parseTestOutput(os.Stdin, batch); err != nil { + glog.Fatal(err) + } + + if err := c.Write(batch); err != nil { + glog.Fatal(err) + } +} + +// See https://golang.org/cmd/test2json/ for a description of 'go test +// -json' output +type testEvent struct { + Time time.Time // encodes as an RFC3339-format string + Action string + Package string + Test string + Elapsed float64 // seconds + Output string +} + +func createTags(e *testEvent) map[string]string { + tags := make(map[string]string, len(flagTags)+2) + for _, t := range flagTags { + tags[t.key] = t.value + } + resultType := "test" + if e.Test == "" { + resultType = "package" + } + tags["package"] = e.Package + tags["type"] = resultType + return tags +} + +func createFields(e *testEvent) map[string]interface{} { + fields := make(map[string]interface{}, len(flagFields)+3) + for _, f := range flagFields { + fields[f.key] = f.value + } + // Use a float64 instead of a bool to be able to SUM test + // successes in influxdb. + var pass float64 + if e.Action == "pass" { + pass = 1 + } + fields["pass"] = pass + fields["elapsed"] = e.Elapsed + if e.Test != "" { + fields["test"] = e.Test + } + return fields +} + +func parseTestOutput(r io.Reader, batch client.BatchPoints) error { + // pkgs holds packages seen in r. Unfortunately, if a test panics, + // then there is no "fail" result from a package. To detect these + // kind of failures, keep track of all the packages that never had + // a "pass" or "fail". + // + // The last seen timestamp is stored with the package, so that + // package result measurement written to influxdb can be later + // than any test result for that package. + pkgs := make(map[string]time.Time) + d := json.NewDecoder(r) + for { + e := &testEvent{} + if err := d.Decode(e); err != nil { + if err != io.EOF { + return err + } + break + } + + switch e.Action { + case "pass", "fail": + default: + continue + } + + if e.Test == "" { + // A package has completed. + delete(pkgs, e.Package) + } else { + pkgs[e.Package] = e.Time + } + + point, err := client.NewPoint( + *flagMeasurement, + createTags(e), + createFields(e), + e.Time, + ) + if err != nil { + return err + } + + batch.AddPoint(point) + } + + for pkg, t := range pkgs { + pkgFail := &testEvent{ + Action: "fail", + Package: pkg, + } + point, err := client.NewPoint( + *flagMeasurement, + createTags(pkgFail), + createFields(pkgFail), + // Fake a timestamp that is later than anything that + // occurred for this package + t.Add(time.Millisecond), + ) + if err != nil { + return err + } + + batch.AddPoint(point) + } + + return nil +} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/main_test.go b/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/main_test.go new file mode 100644 index 00000000..331ac496 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/main_test.go @@ -0,0 +1,151 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package main + +import ( + "os" + "testing" + "time" + + "github.com/aristanetworks/goarista/test" + "github.com/influxdata/influxdb/client/v2" +) + +func newPoint(t *testing.T, measurement string, tags map[string]string, + fields map[string]interface{}, timeString string) *client.Point { + t.Helper() + timestamp, err := time.Parse(time.RFC3339Nano, timeString) + if err != nil { + t.Fatal(err) + } + p, err := client.NewPoint(measurement, tags, fields, timestamp) + if err != nil { + t.Fatal(err) + } + return p +} + +func TestParseTestOutput(t *testing.T) { + // Verify tags and fields set by flags are set in records + flagTags.Set("tag=foo") + flagFields.Set("field=true") + defer func() { + flagTags = nil + flagFields = nil + }() + + f, err := os.Open("testdata/output.txt") + if err != nil { + t.Fatal(err) + } + + makeTags := func(pkg, resultType string) map[string]string { + return map[string]string{"package": pkg, "type": resultType, "tag": "foo"} + } + makeFields := func(pass, elapsed float64, test string) map[string]interface{} { + m := map[string]interface{}{"pass": pass, "elapsed": elapsed, "field": true} + if test != "" { + m["test"] = test + } + return m + } + + expected := []*client.Point{ + newPoint(t, + "result", + makeTags("pkg/passed", "test"), + makeFields(1, 0, "TestPass"), + "2018-03-08T10:33:12.344165231-08:00", + ), + newPoint(t, + "result", + makeTags("pkg/passed", "package"), + makeFields(1, 0.013, ""), + "2018-03-08T10:33:12.34533033-08:00", + ), + newPoint(t, + "result", + makeTags("pkg/panic", "test"), + makeFields(0, 600.029, "TestPanic"), + "2018-03-08T10:33:20.272440286-08:00", + ), + newPoint(t, + "result", + makeTags("pkg/failed", "test"), + makeFields(0, 0.18, "TestFail"), + "2018-03-08T10:33:27.158860934-08:00", + ), + newPoint(t, + "result", + makeTags("pkg/failed", "package"), + makeFields(0, 0.204, ""), + "2018-03-08T10:33:27.161302093-08:00", + ), + newPoint(t, + "result", + makeTags("pkg/panic", "package"), + makeFields(0, 0, ""), + "2018-03-08T10:33:20.273440286-08:00", + ), + } + + batch, err := client.NewBatchPoints(client.BatchPointsConfig{}) + if err != nil { + t.Fatal(err) + } + if err := parseTestOutput(f, batch); err != nil { + t.Fatal(err) + } + + if diff := test.Diff(expected, batch.Points()); diff != "" { + t.Errorf("unexpected diff: %s", diff) + } +} + +func TestTagsFlag(t *testing.T) { + for tc, expected := range map[string]tags{ + "abc=def": tags{tag{key: "abc", value: "def"}}, + "abc=def,ghi=klm": tags{tag{key: "abc", value: "def"}, tag{key: "ghi", value: "klm"}}, + } { + t.Run(tc, func(t *testing.T) { + var ts tags + ts.Set(tc) + if diff := test.Diff(expected, ts); diff != "" { + t.Errorf("unexpected diff from Set: %s", diff) + } + + if s := ts.String(); s != tc { + t.Errorf("unexpected diff from String: %q vs. %q", tc, s) + } + }) + } +} + +func TestFieldsFlag(t *testing.T) { + for tc, expected := range map[string]fields{ + "str=abc": fields{field{key: "str", value: "abc"}}, + "bool=true": fields{field{key: "bool", value: true}}, + "bool=false": fields{field{key: "bool", value: false}}, + "float64=42": fields{field{key: "float64", value: float64(42)}}, + "float64=42.123": fields{field{key: "float64", value: float64(42.123)}}, + "int64=42i": fields{field{key: "int64", value: int64(42)}}, + "str=abc,bool=true,float64=42,int64=42i": fields{field{key: "str", value: "abc"}, + field{key: "bool", value: true}, + field{key: "float64", value: float64(42)}, + field{key: "int64", value: int64(42)}}, + } { + t.Run(tc, func(t *testing.T) { + var fs fields + fs.Set(tc) + if diff := test.Diff(expected, fs); diff != "" { + t.Errorf("unexpected diff from Set: %s", diff) + } + + if s := fs.String(); s != tc { + t.Errorf("unexpected diff from String: %q vs. %q", tc, s) + } + }) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/testdata/output.txt b/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/testdata/output.txt new file mode 100644 index 00000000..34f6944d --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/cmd/test2influxdb/testdata/output.txt @@ -0,0 +1,15 @@ +{"Time":"2018-03-08T10:33:12.002692769-08:00","Action":"output","Package":"pkg/skipped","Output":"? \tpkg/skipped\t[no test files]\n"} +{"Time":"2018-03-08T10:33:12.003199228-08:00","Action":"skip","Package":"pkg/skipped","Elapsed":0.001} +{"Time":"2018-03-08T10:33:12.343866281-08:00","Action":"run","Package":"pkg/passed","Test":"TestPass"} +{"Time":"2018-03-08T10:33:12.34406622-08:00","Action":"output","Package":"pkg/passed","Test":"TestPass","Output":"=== RUN TestPass\n"} +{"Time":"2018-03-08T10:33:12.344139342-08:00","Action":"output","Package":"pkg/passed","Test":"TestPass","Output":"--- PASS: TestPass (0.00s)\n"} +{"Time":"2018-03-08T10:33:12.344165231-08:00","Action":"pass","Package":"pkg/passed","Test":"TestPass","Elapsed":0} +{"Time":"2018-03-08T10:33:12.344297059-08:00","Action":"output","Package":"pkg/passed","Output":"PASS\n"} +{"Time":"2018-03-08T10:33:12.345217622-08:00","Action":"output","Package":"pkg/passed","Output":"ok \tpkg/passed\t0.013s\n"} +{"Time":"2018-03-08T10:33:12.34533033-08:00","Action":"pass","Package":"pkg/passed","Elapsed":0.013} +{"Time":"2018-03-08T10:33:20.27231537-08:00","Action":"output","Package":"pkg/panic","Test":"TestPanic","Output":"panic\n"} +{"Time":"2018-03-08T10:33:20.272414481-08:00","Action":"output","Package":"pkg/panic","Test":"TestPanic","Output":"FAIL\tpkg/panic\t600.029s\n"} +{"Time":"2018-03-08T10:33:20.272440286-08:00","Action":"fail","Package":"pkg/panic","Test":"TestPanic","Elapsed":600.029} +{"Time":"2018-03-08T10:33:27.158776469-08:00","Action":"output","Package":"pkg/failed","Test":"TestFail","Output":"--- FAIL: TestFail (0.18s)\n"} +{"Time":"2018-03-08T10:33:27.158860934-08:00","Action":"fail","Package":"pkg/failed","Test":"TestFail","Elapsed":0.18} +{"Time":"2018-03-08T10:33:27.161302093-08:00","Action":"fail","Package":"pkg/failed","Elapsed":0.204} diff --git a/vendor/github.com/aristanetworks/goarista/dscp/dial.go b/vendor/github.com/aristanetworks/goarista/dscp/dial.go index 7a928f59..83bf82b4 100644 --- a/vendor/github.com/aristanetworks/goarista/dscp/dial.go +++ b/vendor/github.com/aristanetworks/goarista/dscp/dial.go @@ -8,7 +8,6 @@ package dscp import ( "fmt" "net" - "reflect" "time" ) @@ -20,8 +19,7 @@ func DialTCPWithTOS(laddr, raddr *net.TCPAddr, tos byte) (*net.TCPConn, error) { if err != nil { return nil, err } - value := reflect.ValueOf(conn) - if err = setTOS(raddr.IP, value, tos); err != nil { + if err = setTOS(raddr.IP, conn, tos); err != nil { conn.Close() return nil, err } @@ -54,7 +52,24 @@ func DialTimeoutWithTOS(network, address string, timeout time.Duration, tos byte conn.Close() return nil, fmt.Errorf("DialTimeoutWithTOS: cannot set TOS on a %s socket", network) } - if err = setTOS(ip, reflect.ValueOf(conn), tos); err != nil { + if err = setTOS(ip, conn, tos); err != nil { + conn.Close() + return nil, err + } + return conn, err +} + +// DialTCPTimeoutWithTOS is same as DialTimeoutWithTOS except for enforcing "tcp" and +// providing an option to specify local address (source) +func DialTCPTimeoutWithTOS(laddr, raddr *net.TCPAddr, tos byte, timeout time.Duration) (net.Conn, + error) { + d := net.Dialer{Timeout: timeout, LocalAddr: laddr} + conn, err := d.Dial("tcp", raddr.String()) + if err != nil { + return nil, err + } + + if err = setTOS(raddr.IP, conn, tos); err != nil { conn.Close() return nil, err } diff --git a/vendor/github.com/aristanetworks/goarista/dscp/dial_test.go b/vendor/github.com/aristanetworks/goarista/dscp/dial_test.go index 83cc5230..d983276a 100644 --- a/vendor/github.com/aristanetworks/goarista/dscp/dial_test.go +++ b/vendor/github.com/aristanetworks/goarista/dscp/dial_test.go @@ -5,8 +5,11 @@ package dscp_test import ( + "fmt" "net" + "strings" "testing" + "time" "github.com/aristanetworks/goarista/dscp" ) @@ -51,3 +54,50 @@ func TestDialTCPWithTOS(t *testing.T) { conn.Write(buf) <-done } + +func TestDialTCPTimeoutWithTOS(t *testing.T) { + raddr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0} + for name, td := range map[string]*net.TCPAddr{ + "ipNoPort": &net.TCPAddr{ + IP: net.ParseIP("127.0.0.42"), Port: 0, + }, + "ipWithPort": &net.TCPAddr{ + IP: net.ParseIP("127.0.0.42"), Port: 10001, + }, + } { + t.Run(name, func(t *testing.T) { + l, err := net.ListenTCP("tcp", raddr) + if err != nil { + t.Fatal(err) + } + defer l.Close() + + var srcAddr net.Addr + done := make(chan struct{}) + go func() { + conn, err := l.Accept() + if err != nil { + t.Fatal(err) + } + defer conn.Close() + srcAddr = conn.RemoteAddr() + close(done) + }() + + conn, err := dscp.DialTCPTimeoutWithTOS(td, l.Addr().(*net.TCPAddr), 40, 5*time.Second) + if err != nil { + t.Fatal("Connection failed:", err) + } + defer conn.Close() + + pfx := td.IP.String() + ":" + if td.Port > 0 { + pfx = fmt.Sprintf("%s%d", pfx, td.Port) + } + <-done + if !strings.HasPrefix(srcAddr.String(), pfx) { + t.Fatalf("DialTCPTimeoutWithTOS wrong address: %q instead of %q", srcAddr, pfx) + } + }) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/dscp/listen.go b/vendor/github.com/aristanetworks/goarista/dscp/listen.go index 50f82b4b..3ba86f5c 100644 --- a/vendor/github.com/aristanetworks/goarista/dscp/listen.go +++ b/vendor/github.com/aristanetworks/goarista/dscp/listen.go @@ -7,7 +7,6 @@ package dscp import ( "net" - "reflect" ) // ListenTCPWithTOS is similar to net.ListenTCP but with the socket configured @@ -18,8 +17,7 @@ func ListenTCPWithTOS(address *net.TCPAddr, tos byte) (*net.TCPListener, error) if err != nil { return nil, err } - value := reflect.ValueOf(lsnr) - if err = setTOS(address.IP, value, tos); err != nil { + if err = setTOS(address.IP, lsnr, tos); err != nil { lsnr.Close() return nil, err } diff --git a/vendor/github.com/aristanetworks/goarista/dscp/tos_unix.go b/vendor/github.com/aristanetworks/goarista/dscp/tos_unix.go index 7a2ee21e..335dedc9 100644 --- a/vendor/github.com/aristanetworks/goarista/dscp/tos_unix.go +++ b/vendor/github.com/aristanetworks/goarista/dscp/tos_unix.go @@ -5,19 +5,18 @@ package dscp import ( + "fmt" "net" "os" "reflect" + "syscall" "golang.org/x/sys/unix" ) // This works for the UNIX implementation of netFD, i.e. not on Windows and Plan9. -// This kludge is needed until https://github.com/golang/go/issues/9661 is fixed. -// value can be the reflection of a connection or a dialer. -func setTOS(ip net.IP, value reflect.Value, tos byte) error { - netFD := value.Elem().FieldByName("fd").Elem() - fd := int(netFD.FieldByName("pfd").FieldByName("Sysfd").Int()) +// conn must either implement syscall.Conn or be a TCPListener. +func setTOS(ip net.IP, conn interface{}, tos byte) error { var proto, optname int if ip.To4() != nil { proto = unix.IPPROTO_IP @@ -26,8 +25,42 @@ func setTOS(ip net.IP, value reflect.Value, tos byte) error { proto = unix.IPPROTO_IPV6 optname = unix.IPV6_TCLASS } + + switch c := conn.(type) { + case syscall.Conn: + return setTOSWithSyscallConn(proto, optname, c, tos) + case *net.TCPListener: + // This code is needed to support go1.9. In go1.10 + // *net.TCPListener implements syscall.Conn. + return setTOSWithTCPListener(proto, optname, c, tos) + } + return fmt.Errorf("unsupported connection type: %T", conn) +} + +func setTOSWithTCPListener(proto, optname int, conn *net.TCPListener, tos byte) error { + // A kludge for pre-go1.10 to get the fd of a net.TCPListener + value := reflect.ValueOf(conn) + netFD := value.Elem().FieldByName("fd").Elem() + fd := int(netFD.FieldByName("pfd").FieldByName("Sysfd").Int()) if err := unix.SetsockoptInt(fd, proto, optname, int(tos)); err != nil { return os.NewSyscallError("setsockopt", err) } return nil } + +func setTOSWithSyscallConn(proto, optname int, conn syscall.Conn, tos byte) error { + syscallConn, err := conn.SyscallConn() + if err != nil { + return err + } + var setsockoptErr error + err = syscallConn.Control(func(fd uintptr) { + if err := unix.SetsockoptInt(int(fd), proto, optname, int(tos)); err != nil { + setsockoptErr = os.NewSyscallError("setsockopt", err) + } + }) + if setsockoptErr != nil { + return setsockoptErr + } + return err +} diff --git a/vendor/github.com/aristanetworks/goarista/gnmi/client.go b/vendor/github.com/aristanetworks/goarista/gnmi/client.go index 1eb31133..84b07117 100644 --- a/vendor/github.com/aristanetworks/goarista/gnmi/client.go +++ b/vendor/github.com/aristanetworks/goarista/gnmi/client.go @@ -8,10 +8,15 @@ import ( "context" "crypto/tls" "crypto/x509" + "fmt" + "math" + "net" + "time" + "io/ioutil" "strings" - "github.com/aristanetworks/glog" + "github.com/aristanetworks/goarista/netns" pb "github.com/openconfig/gnmi/proto/gnmi" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -19,7 +24,7 @@ import ( ) const ( - defaultPort = "6042" + defaultPort = "6030" ) // Config is the gnmi.Client config @@ -33,19 +38,30 @@ type Config struct { TLS bool } +// SubscribeOptions is the gNMI subscription request options +type SubscribeOptions struct { + UpdatesOnly bool + Prefix string + Mode string + StreamMode string + SampleInterval uint64 + HeartbeatInterval uint64 + Paths [][]string +} + // Dial connects to a gnmi service and returns a client -func Dial(cfg *Config) pb.GNMIClient { +func Dial(cfg *Config) (pb.GNMIClient, error) { var opts []grpc.DialOption if cfg.TLS || cfg.CAFile != "" || cfg.CertFile != "" { tlsConfig := &tls.Config{} if cfg.CAFile != "" { b, err := ioutil.ReadFile(cfg.CAFile) if err != nil { - glog.Fatal(err) + return nil, err } cp := x509.NewCertPool() if !cp.AppendCertsFromPEM(b) { - glog.Fatalf("credentials: failed to append certificates") + return nil, fmt.Errorf("credentials: failed to append certificates") } tlsConfig.RootCAs = cp } else { @@ -53,11 +69,11 @@ func Dial(cfg *Config) pb.GNMIClient { } if cfg.CertFile != "" { if cfg.KeyFile == "" { - glog.Fatalf("Please provide both -certfile and -keyfile") + return nil, fmt.Errorf("please provide both -certfile and -keyfile") } cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile) if err != nil { - glog.Fatal(err) + return nil, err } tlsConfig.Certificates = []tls.Certificate{cert} } @@ -69,12 +85,33 @@ func Dial(cfg *Config) pb.GNMIClient { if !strings.ContainsRune(cfg.Addr, ':') { cfg.Addr += ":" + defaultPort } - conn, err := grpc.Dial(cfg.Addr, opts...) - if err != nil { - glog.Fatalf("Failed to dial: %s", err) + + dial := func(addrIn string, time time.Duration) (net.Conn, error) { + var conn net.Conn + nsName, addr, err := netns.ParseAddress(addrIn) + if err != nil { + return nil, err + } + + err = netns.Do(nsName, func() error { + var err error + conn, err = net.Dial("tcp", addr) + return err + }) + return conn, err } - return pb.NewGNMIClient(conn) + opts = append(opts, + grpc.WithDialer(dial), + + // Allows received protobuf messages to be larger than 4MB + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt32)), + ) + grpcconn, err := grpc.Dial(cfg.Addr, opts...) + if err != nil { + return nil, fmt.Errorf("failed to dial: %s", err) + } + return pb.NewGNMIClient(grpcconn), nil } // NewContext returns a new context with username and password @@ -104,17 +141,53 @@ func NewGetRequest(paths [][]string) (*pb.GetRequest, error) { } // NewSubscribeRequest returns a SubscribeRequest for the given paths -func NewSubscribeRequest(paths [][]string) (*pb.SubscribeRequest, error) { - subList := &pb.SubscriptionList{ - Subscription: make([]*pb.Subscription, len(paths)), +func NewSubscribeRequest(subscribeOptions *SubscribeOptions) (*pb.SubscribeRequest, error) { + var mode pb.SubscriptionList_Mode + switch subscribeOptions.Mode { + case "once": + mode = pb.SubscriptionList_ONCE + case "poll": + mode = pb.SubscriptionList_POLL + case "stream": + mode = pb.SubscriptionList_STREAM + default: + return nil, fmt.Errorf("subscribe mode (%s) invalid", subscribeOptions.Mode) } - for i, p := range paths { + + var streamMode pb.SubscriptionMode + switch subscribeOptions.StreamMode { + case "on_change": + streamMode = pb.SubscriptionMode_ON_CHANGE + case "sample": + streamMode = pb.SubscriptionMode_SAMPLE + case "target_defined": + streamMode = pb.SubscriptionMode_TARGET_DEFINED + default: + return nil, fmt.Errorf("subscribe stream mode (%s) invalid", subscribeOptions.StreamMode) + } + + prefixPath, err := ParseGNMIElements(SplitPath(subscribeOptions.Prefix)) + if err != nil { + return nil, err + } + subList := &pb.SubscriptionList{ + Subscription: make([]*pb.Subscription, len(subscribeOptions.Paths)), + Mode: mode, + UpdatesOnly: subscribeOptions.UpdatesOnly, + Prefix: prefixPath, + } + for i, p := range subscribeOptions.Paths { gnmiPath, err := ParseGNMIElements(p) if err != nil { return nil, err } - subList.Subscription[i] = &pb.Subscription{Path: gnmiPath} + subList.Subscription[i] = &pb.Subscription{ + Path: gnmiPath, + Mode: streamMode, + SampleInterval: subscribeOptions.SampleInterval, + HeartbeatInterval: subscribeOptions.HeartbeatInterval, + } } - return &pb.SubscribeRequest{ - Request: &pb.SubscribeRequest_Subscribe{Subscribe: subList}}, nil + return &pb.SubscribeRequest{Request: &pb.SubscribeRequest_Subscribe{ + Subscribe: subList}}, nil } diff --git a/vendor/github.com/aristanetworks/goarista/gnmi/json.go b/vendor/github.com/aristanetworks/goarista/gnmi/json.go index b6e815e4..30aacd3d 100644 --- a/vendor/github.com/aristanetworks/goarista/gnmi/json.go +++ b/vendor/github.com/aristanetworks/goarista/gnmi/json.go @@ -17,7 +17,7 @@ func NotificationToMap(notif *gnmi.Notification) (map[string]interface{}, error) updates := make(map[string]interface{}, len(notif.Update)) var err error for _, update := range notif.Update { - updates[StrPath(update.Path)] = strUpdateVal(update) + updates[StrPath(update.Path)] = StrUpdateVal(update) if err != nil { return nil, err } diff --git a/vendor/github.com/aristanetworks/goarista/gnmi/operation.go b/vendor/github.com/aristanetworks/goarista/gnmi/operation.go index 62f1e0c3..45327aed 100644 --- a/vendor/github.com/aristanetworks/goarista/gnmi/operation.go +++ b/vendor/github.com/aristanetworks/goarista/gnmi/operation.go @@ -5,14 +5,22 @@ package gnmi import ( + "bufio" "bytes" "context" + "encoding/base64" + "encoding/json" "errors" "fmt" "io" "io/ioutil" + "os" "path" + "strconv" + "strings" + "time" + "github.com/aristanetworks/glog" pb "github.com/openconfig/gnmi/proto/gnmi" "google.golang.org/grpc/codes" ) @@ -28,9 +36,10 @@ func Get(ctx context.Context, client pb.GNMIClient, paths [][]string) error { return err } for _, notif := range resp.Notification { + prefix := StrPath(notif.Prefix) for _, update := range notif.Update { - fmt.Printf("%s:\n", StrPath(update.Path)) - fmt.Println(strUpdateVal(update)) + fmt.Printf("%s:\n", path.Join(prefix, StrPath(update.Path))) + fmt.Println(StrUpdateVal(update)) } } return nil @@ -55,49 +64,104 @@ func Capabilities(ctx context.Context, client pb.GNMIClient) error { // val may be a path to a file or it may be json. First see if it is a // file, if so return its contents, otherwise return val func extractJSON(val string) []byte { - jsonBytes, err := ioutil.ReadFile(val) - if err != nil { - jsonBytes = []byte(val) + if jsonBytes, err := ioutil.ReadFile(val); err == nil { + return jsonBytes } - return jsonBytes + // Best effort check if the value might a string literal, in which + // case wrap it in quotes. This is to allow a user to do: + // gnmi update ../hostname host1234 + // gnmi update ../description 'This is a description' + // instead of forcing them to quote the string: + // gnmi update ../hostname '"host1234"' + // gnmi update ../description '"This is a description"' + maybeUnquotedStringLiteral := func(s string) bool { + if s == "true" || s == "false" || s == "null" || // JSON reserved words + strings.ContainsAny(s, `"'{}[]`) { // Already quoted or is a JSON object or array + return false + } else if _, err := strconv.ParseInt(s, 0, 32); err == nil { + // Integer. Using byte size of 32 because larger integer + // types are supposed to be sent as strings in JSON. + return false + } else if _, err := strconv.ParseFloat(s, 64); err == nil { + // Float + return false + } + + return true + } + if maybeUnquotedStringLiteral(val) { + out := make([]byte, len(val)+2) + out[0] = '"' + copy(out[1:], val) + out[len(out)-1] = '"' + return out + } + return []byte(val) } -// strUpdateVal will return a string representing the value within the supplied update -func strUpdateVal(u *pb.Update) string { +// StrUpdateVal will return a string representing the value within the supplied update +func StrUpdateVal(u *pb.Update) string { if u.Value != nil { - return string(u.Value.Value) // Backwards compatibility with pre-v0.4 gnmi + // Backwards compatibility with pre-v0.4 gnmi + switch u.Value.Type { + case pb.Encoding_JSON, pb.Encoding_JSON_IETF: + return strJSON(u.Value.Value) + case pb.Encoding_BYTES, pb.Encoding_PROTO: + return base64.StdEncoding.EncodeToString(u.Value.Value) + case pb.Encoding_ASCII: + return string(u.Value.Value) + default: + return string(u.Value.Value) + } } - return strVal(u.Val) + return StrVal(u.Val) } -// strVal will return a string representing the supplied value -func strVal(val *pb.TypedValue) string { +// StrVal will return a string representing the supplied value +func StrVal(val *pb.TypedValue) string { switch v := val.GetValue().(type) { case *pb.TypedValue_StringVal: return v.StringVal case *pb.TypedValue_JsonIetfVal: - return string(v.JsonIetfVal) + return strJSON(v.JsonIetfVal) + case *pb.TypedValue_JsonVal: + return strJSON(v.JsonVal) case *pb.TypedValue_IntVal: - return fmt.Sprintf("%v", v.IntVal) + return strconv.FormatInt(v.IntVal, 10) case *pb.TypedValue_UintVal: - return fmt.Sprintf("%v", v.UintVal) + return strconv.FormatUint(v.UintVal, 10) case *pb.TypedValue_BoolVal: - return fmt.Sprintf("%v", v.BoolVal) + return strconv.FormatBool(v.BoolVal) case *pb.TypedValue_BytesVal: - return string(v.BytesVal) + return base64.StdEncoding.EncodeToString(v.BytesVal) case *pb.TypedValue_DecimalVal: return strDecimal64(v.DecimalVal) + case *pb.TypedValue_FloatVal: + return strconv.FormatFloat(float64(v.FloatVal), 'g', -1, 32) case *pb.TypedValue_LeaflistVal: return strLeaflist(v.LeaflistVal) + case *pb.TypedValue_AsciiVal: + return v.AsciiVal + case *pb.TypedValue_AnyVal: + return v.AnyVal.String() default: panic(v) } } +func strJSON(inJSON []byte) string { + var out bytes.Buffer + err := json.Indent(&out, inJSON, "", " ") + if err != nil { + return fmt.Sprintf("(error unmarshalling json: %s)\n", err) + string(inJSON) + } + return out.String() +} + func strDecimal64(d *pb.Decimal64) string { - var i, frac uint64 + var i, frac int64 if d.Precision > 0 { - div := uint64(10) + div := int64(10) it := d.Precision - 1 for it > 0 { div *= 10 @@ -108,32 +172,25 @@ func strDecimal64(d *pb.Decimal64) string { } else { i = d.Digits } + if frac < 0 { + frac = -frac + } return fmt.Sprintf("%d.%d", i, frac) } -// strLeafList builds a human-readable form of a leaf-list. e.g. [1,2,3] or [a,b,c] +// strLeafList builds a human-readable form of a leaf-list. e.g. [1, 2, 3] or [a, b, c] func strLeaflist(v *pb.ScalarArray) string { - s := make([]string, 0, len(v.Element)) - sz := 2 // [] + var buf bytes.Buffer + buf.WriteByte('[') - // convert arbitrary TypedValues to string form - for _, elm := range v.Element { - str := strVal(elm) - s = append(s, str) - sz += len(str) + 1 // %v + , - } - - b := make([]byte, sz) - buf := bytes.NewBuffer(b) - - buf.WriteRune('[') - for i := range v.Element { - buf.WriteString(s[i]) + for i, elm := range v.Element { + buf.WriteString(StrVal(elm)) if i < len(v.Element)-1 { - buf.WriteRune(',') + buf.WriteString(", ") } } - buf.WriteRune(']') + + buf.WriteByte(']') return buf.String() } @@ -143,9 +200,16 @@ func update(p *pb.Path, val string) *pb.Update { case "": v = &pb.TypedValue{ Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: extractJSON(val)}} - case "cli": + case "cli", "test-regen-cli": v = &pb.TypedValue{ Value: &pb.TypedValue_AsciiVal{AsciiVal: val}} + case "p4_config": + b, err := ioutil.ReadFile(val) + if err != nil { + glog.Fatalf("Cannot read p4 file: %s", err) + } + v = &pb.TypedValue{ + Value: &pb.TypedValue_ProtoBytes{ProtoBytes: b}} default: panic(fmt.Errorf("unexpected origin: %q", p.Origin)) } @@ -155,9 +219,10 @@ func update(p *pb.Path, val string) *pb.Update { // Operation describes an gNMI operation. type Operation struct { - Type string - Path []string - Val string + Type string + Origin string + Path []string + Val string } func newSetRequest(setOps []*Operation) (*pb.SetRequest, error) { @@ -167,6 +232,7 @@ func newSetRequest(setOps []*Operation) (*pb.SetRequest, error) { if err != nil { return nil, err } + p.Origin = op.Origin switch op.Type { case "delete": @@ -199,16 +265,18 @@ func Set(ctx context.Context, client pb.GNMIClient, setOps []*Operation) error { } // Subscribe sends a SubscribeRequest to the given client. -func Subscribe(ctx context.Context, client pb.GNMIClient, paths [][]string, +func Subscribe(ctx context.Context, client pb.GNMIClient, subscribeOptions *SubscribeOptions, respChan chan<- *pb.SubscribeResponse, errChan chan<- error) { ctx, cancel := context.WithCancel(ctx) defer cancel() + defer close(respChan) + stream, err := client.Subscribe(ctx) if err != nil { errChan <- err return } - req, err := NewSubscribeRequest(paths) + req, err := NewSubscribeRequest(subscribeOptions) if err != nil { errChan <- err return @@ -228,6 +296,26 @@ func Subscribe(ctx context.Context, client pb.GNMIClient, paths [][]string, return } respChan <- resp + + // For POLL subscriptions, initiate a poll request by pressing ENTER + if subscribeOptions.Mode == "poll" { + switch resp.Response.(type) { + case *pb.SubscribeResponse_SyncResponse: + fmt.Print("Press ENTER to send a poll request: ") + reader := bufio.NewReader(os.Stdin) + reader.ReadString('\n') + + pollReq := &pb.SubscribeRequest{ + Request: &pb.SubscribeRequest_Poll{ + Poll: &pb.Poll{}, + }, + } + if err := stream.Send(pollReq); err != nil { + errChan <- err + return + } + } + } } } @@ -241,10 +329,16 @@ func LogSubscribeResponse(response *pb.SubscribeResponse) error { return errors.New("initial sync failed") } case *pb.SubscribeResponse_Update: + t := time.Unix(0, resp.Update.Timestamp).UTC() prefix := StrPath(resp.Update.Prefix) for _, update := range resp.Update.Update { - fmt.Printf("%s = %s\n", path.Join(prefix, StrPath(update.Path)), - strUpdateVal(update)) + fmt.Printf("[%s] %s = %s\n", t.Format(time.RFC3339Nano), + path.Join(prefix, StrPath(update.Path)), + StrUpdateVal(update)) + } + for _, del := range resp.Update.Delete { + fmt.Printf("[%s] Deleted %s\n", t.Format(time.RFC3339Nano), + path.Join(prefix, StrPath(del))) } } return nil diff --git a/vendor/github.com/aristanetworks/goarista/gnmi/operation_test.go b/vendor/github.com/aristanetworks/goarista/gnmi/operation_test.go index 694dca01..2e5b07e5 100644 --- a/vendor/github.com/aristanetworks/goarista/gnmi/operation_test.go +++ b/vendor/github.com/aristanetworks/goarista/gnmi/operation_test.go @@ -5,9 +5,14 @@ package gnmi import ( + "bytes" + "io/ioutil" + "os" "testing" "github.com/aristanetworks/goarista/test" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" pb "github.com/openconfig/gnmi/proto/gnmi" ) @@ -15,24 +20,41 @@ import ( func TestNewSetRequest(t *testing.T) { pathFoo := &pb.Path{ Element: []string{"foo"}, - Elem: []*pb.PathElem{&pb.PathElem{Name: "foo"}}, + Elem: []*pb.PathElem{{Name: "foo"}}, } pathCli := &pb.Path{ Origin: "cli", } + pathP4 := &pb.Path{ + Origin: "p4_config", + } + + p4FileContent := "p4_config test" + p4TestFile, err := ioutil.TempFile("", "p4TestFile") + if err != nil { + t.Errorf("cannot create test file for p4_config") + } + p4Filename := p4TestFile.Name() + + defer os.Remove(p4Filename) + + if _, err := p4TestFile.WriteString(p4FileContent); err != nil { + t.Errorf("cannot write test file for p4_config") + } + p4TestFile.Close() testCases := map[string]struct { setOps []*Operation exp pb.SetRequest }{ "delete": { - setOps: []*Operation{&Operation{Type: "delete", Path: []string{"foo"}}}, + setOps: []*Operation{{Type: "delete", Path: []string{"foo"}}}, exp: pb.SetRequest{Delete: []*pb.Path{pathFoo}}, }, "update": { - setOps: []*Operation{&Operation{Type: "update", Path: []string{"foo"}, Val: "true"}}, + setOps: []*Operation{{Type: "update", Path: []string{"foo"}, Val: "true"}}, exp: pb.SetRequest{ - Update: []*pb.Update{&pb.Update{ + Update: []*pb.Update{{ Path: pathFoo, Val: &pb.TypedValue{ Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: []byte("true")}}, @@ -40,9 +62,9 @@ func TestNewSetRequest(t *testing.T) { }, }, "replace": { - setOps: []*Operation{&Operation{Type: "replace", Path: []string{"foo"}, Val: "true"}}, + setOps: []*Operation{{Type: "replace", Path: []string{"foo"}, Val: "true"}}, exp: pb.SetRequest{ - Replace: []*pb.Update{&pb.Update{ + Replace: []*pb.Update{{ Path: pathFoo, Val: &pb.TypedValue{ Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: []byte("true")}}, @@ -50,16 +72,27 @@ func TestNewSetRequest(t *testing.T) { }, }, "cli-replace": { - setOps: []*Operation{&Operation{Type: "replace", Path: []string{"cli"}, + setOps: []*Operation{{Type: "replace", Origin: "cli", Val: "hostname foo\nip routing"}}, exp: pb.SetRequest{ - Replace: []*pb.Update{&pb.Update{ + Replace: []*pb.Update{{ Path: pathCli, Val: &pb.TypedValue{ Value: &pb.TypedValue_AsciiVal{AsciiVal: "hostname foo\nip routing"}}, }}, }, }, + "p4_config": { + setOps: []*Operation{{Type: "replace", Origin: "p4_config", + Val: p4Filename}}, + exp: pb.SetRequest{ + Replace: []*pb.Update{{ + Path: pathP4, + Val: &pb.TypedValue{ + Value: &pb.TypedValue_ProtoBytes{ProtoBytes: []byte(p4FileContent)}}, + }}, + }, + }, } for name, tc := range testCases { @@ -74,3 +107,183 @@ func TestNewSetRequest(t *testing.T) { }) } } + +func TestStrUpdateVal(t *testing.T) { + anyBytes, err := proto.Marshal(&pb.ModelData{Name: "foobar"}) + if err != nil { + t.Fatal(err) + } + anyMessage := &any.Any{TypeUrl: "gnmi/ModelData", Value: anyBytes} + anyString := proto.CompactTextString(anyMessage) + + for name, tc := range map[string]struct { + update *pb.Update + exp string + }{ + "JSON Value": { + update: &pb.Update{ + Value: &pb.Value{ + Value: []byte(`{"foo":"bar"}`), + Type: pb.Encoding_JSON}}, + exp: `{ + "foo": "bar" +}`, + }, + "JSON_IETF Value": { + update: &pb.Update{ + Value: &pb.Value{ + Value: []byte(`{"foo":"bar"}`), + Type: pb.Encoding_JSON_IETF}}, + exp: `{ + "foo": "bar" +}`, + }, + "BYTES Value": { + update: &pb.Update{ + Value: &pb.Value{ + Value: []byte{0xde, 0xad}, + Type: pb.Encoding_BYTES}}, + exp: "3q0=", + }, + "PROTO Value": { + update: &pb.Update{ + Value: &pb.Value{ + Value: []byte{0xde, 0xad}, + Type: pb.Encoding_PROTO}}, + exp: "3q0=", + }, + "ASCII Value": { + update: &pb.Update{ + Value: &pb.Value{ + Value: []byte("foobar"), + Type: pb.Encoding_ASCII}}, + exp: "foobar", + }, + "INVALID Value": { + update: &pb.Update{ + Value: &pb.Value{ + Value: []byte("foobar"), + Type: pb.Encoding(42)}}, + exp: "foobar", + }, + "StringVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_StringVal{StringVal: "foobar"}}}, + exp: "foobar", + }, + "IntVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_IntVal{IntVal: -42}}}, + exp: "-42", + }, + "UintVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_UintVal{UintVal: 42}}}, + exp: "42", + }, + "BoolVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_BoolVal{BoolVal: true}}}, + exp: "true", + }, + "BytesVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_BytesVal{BytesVal: []byte{0xde, 0xad}}}}, + exp: "3q0=", + }, + "FloatVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_FloatVal{FloatVal: 3.14}}}, + exp: "3.14", + }, + "DecimalVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_DecimalVal{ + DecimalVal: &pb.Decimal64{Digits: 314, Precision: 2}, + }}}, + exp: "3.14", + }, + "LeafListVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_LeaflistVal{ + LeaflistVal: &pb.ScalarArray{Element: []*pb.TypedValue{ + &pb.TypedValue{Value: &pb.TypedValue_BoolVal{BoolVal: true}}, + &pb.TypedValue{Value: &pb.TypedValue_AsciiVal{AsciiVal: "foobar"}}, + }}, + }}}, + exp: "[true, foobar]", + }, + "AnyVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_AnyVal{AnyVal: anyMessage}}}, + exp: anyString, + }, + "JsonVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_JsonVal{JsonVal: []byte(`{"foo":"bar"}`)}}}, + exp: `{ + "foo": "bar" +}`, + }, + "JsonIetfVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: []byte(`{"foo":"bar"}`)}}}, + exp: `{ + "foo": "bar" +}`, + }, + "AsciiVal": { + update: &pb.Update{Val: &pb.TypedValue{ + Value: &pb.TypedValue_AsciiVal{AsciiVal: "foobar"}}}, + exp: "foobar", + }, + } { + t.Run(name, func(t *testing.T) { + got := StrUpdateVal(tc.update) + if got != tc.exp { + t.Errorf("Expected: %q Got: %q", tc.exp, got) + } + }) + } +} + +func TestExtractJSON(t *testing.T) { + jsonFile, err := ioutil.TempFile("", "extractJSON") + if err != nil { + t.Fatal(err) + } + defer os.Remove(jsonFile.Name()) + if _, err := jsonFile.Write([]byte(`"jsonFile"`)); err != nil { + jsonFile.Close() + t.Fatal(err) + } + if err := jsonFile.Close(); err != nil { + t.Fatal(err) + } + + for val, exp := range map[string][]byte{ + jsonFile.Name(): []byte(`"jsonFile"`), + "foobar": []byte(`"foobar"`), + `"foobar"`: []byte(`"foobar"`), + "Val: true": []byte(`"Val: true"`), + "host42": []byte(`"host42"`), + "42": []byte("42"), + "-123.43": []byte("-123.43"), + "0xFFFF": []byte("0xFFFF"), + // Int larger than can fit in 32 bits should be quoted + "0x8000000000": []byte(`"0x8000000000"`), + "-0x8000000000": []byte(`"-0x8000000000"`), + "true": []byte("true"), + "false": []byte("false"), + "null": []byte("null"), + "{true: 42}": []byte("{true: 42}"), + "[]": []byte("[]"), + } { + t.Run(val, func(t *testing.T) { + got := extractJSON(val) + if !bytes.Equal(exp, got) { + t.Errorf("Unexpected diff. Expected: %q Got: %q", exp, got) + } + }) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/gnmi/path.go b/vendor/github.com/aristanetworks/goarista/gnmi/path.go index c1349208..117411c1 100644 --- a/vendor/github.com/aristanetworks/goarista/gnmi/path.go +++ b/vendor/github.com/aristanetworks/goarista/gnmi/path.go @@ -126,11 +126,6 @@ func writeSafeString(buf *bytes.Buffer, s string, esc rune) { // ParseGNMIElements builds up a gnmi path, from user-supplied text func ParseGNMIElements(elms []string) (*pb.Path, error) { - if len(elms) == 1 && elms[0] == "cli" { - return &pb.Path{ - Origin: "cli", - }, nil - } var parsed []*pb.PathElem for _, e := range elms { n, keys, err := parseElement(e) diff --git a/vendor/github.com/aristanetworks/goarista/gnmi/path_test.go b/vendor/github.com/aristanetworks/goarista/gnmi/path_test.go index ff664114..7ef6038e 100644 --- a/vendor/github.com/aristanetworks/goarista/gnmi/path_test.go +++ b/vendor/github.com/aristanetworks/goarista/gnmi/path_test.go @@ -85,19 +85,6 @@ func TestStrPath(t *testing.T) { } } -func TestOriginCLIPath(t *testing.T) { - path := "cli" - sElms := SplitPath(path) - pbPath, err := ParseGNMIElements(sElms) - if err != nil { - t.Fatal(err) - } - expected := pb.Path{Origin: "cli"} - if !test.DeepEqual(expected, *pbPath) { - t.Errorf("want %v, got %v", expected, *pbPath) - } -} - func TestStrPathBackwardsCompat(t *testing.T) { for i, tc := range []struct { path *pb.Path diff --git a/vendor/github.com/aristanetworks/goarista/influxlib/config.go b/vendor/github.com/aristanetworks/goarista/influxlib/config.go new file mode 100644 index 00000000..ace2b793 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/influxlib/config.go @@ -0,0 +1,20 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package influxlib + +//Connection type. +const ( + HTTP = "HTTP" + UDP = "UDP" +) + +//InfluxConfig is a configuration struct for influxlib. +type InfluxConfig struct { + Hostname string + Port uint16 + Protocol string + Database string + RetentionPolicy string +} diff --git a/vendor/github.com/aristanetworks/goarista/influxlib/doc.go b/vendor/github.com/aristanetworks/goarista/influxlib/doc.go new file mode 100644 index 00000000..c805a965 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/influxlib/doc.go @@ -0,0 +1,37 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +/* + Package: influxlib + Title: Influx DB Library + Authors: ssdaily, manojm321, senkrish, kthommandra + Email: influxdb-dev@arista.com + + Description: The main purpose of influxlib is to provide users with a simple + and easy interface through which to connect to influxdb. It removed a lot of + the need to run the same setup and tear down code to connect the the service. + + Example Code: + + connection, err := influxlib.Connect(&influxlib.InfluxConfig { + Hostname: conf.Host, + Port: conf.Port, + Protocol: influxlib.UDP, + Database, conf.AlertDB, + }) + + tags := map[string]string { + "tag1": someStruct.Tag["host"], + "tag2": someStruct.Tag["tag2"], + } + + fields := map[string]interface{} { + "field1": someStruct.Somefield, + "field2": someStruct.Somefield2, + } + + connection.WritePoint("measurement", tags, fields) +*/ + +package influxlib diff --git a/vendor/github.com/aristanetworks/goarista/influxlib/lib.go b/vendor/github.com/aristanetworks/goarista/influxlib/lib.go new file mode 100644 index 00000000..82fec81a --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/influxlib/lib.go @@ -0,0 +1,173 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package influxlib + +import ( + "errors" + "fmt" + "time" + + influxdb "github.com/influxdata/influxdb/client/v2" +) + +// Row is defined as a map where the key (string) is the name of the +// column (field name) and the value is left as an interface to +// accept any value. +type Row map[string]interface{} + +// InfluxDBConnection is an object that the wrapper uses. +// Holds a client of the type v2.Client and the configuration +type InfluxDBConnection struct { + Client influxdb.Client + Config *InfluxConfig +} + +// Point represents a datapoint to be written. +// Measurement: +// The measurement to write to +// Tags: +// A dictionary of tags in the form string=string +// Fields: +// A dictionary of fields(keys) with their associated values +type Point struct { + Measurement string + Tags map[string]string + Fields map[string]interface{} + Timestamp time.Time +} + +// Connect takes an InfluxConfig and establishes a connection +// to InfluxDB. It returns an InfluxDBConnection structure. +// InfluxConfig may be nil for a default connection. +func Connect(config *InfluxConfig) (*InfluxDBConnection, error) { + var con influxdb.Client + var err error + + switch config.Protocol { + case HTTP: + addr := fmt.Sprintf("http://%s:%v", config.Hostname, config.Port) + con, err = influxdb.NewHTTPClient(influxdb.HTTPConfig{ + Addr: addr, + Timeout: 1 * time.Second, + }) + case UDP: + addr := fmt.Sprintf("%s:%v", config.Hostname, config.Port) + con, err = influxdb.NewUDPClient(influxdb.UDPConfig{ + Addr: addr, + }) + default: + return nil, errors.New("Invalid Protocol") + } + + if err != nil { + return nil, err + } + + return &InfluxDBConnection{Client: con, Config: config}, nil +} + +// RecordBatchPoints takes in a slice of influxlib.Point and writes them to the +// database. +func (conn *InfluxDBConnection) RecordBatchPoints(points []Point) error { + var err error + bp, err := influxdb.NewBatchPoints(influxdb.BatchPointsConfig{ + Database: conn.Config.Database, + Precision: "ns", + RetentionPolicy: conn.Config.RetentionPolicy, + }) + if err != nil { + return err + } + + var influxPoints []*influxdb.Point + + for _, p := range points { + if p.Timestamp.IsZero() { + p.Timestamp = time.Now() + } + + point, err := influxdb.NewPoint(p.Measurement, p.Tags, p.Fields, + p.Timestamp) + if err != nil { + return err + } + influxPoints = append(influxPoints, point) + } + + bp.AddPoints(influxPoints) + + if err = conn.Client.Write(bp); err != nil { + return err + } + + return nil +} + +// WritePoint stores a datapoint to the database. +// Measurement: +// The measurement to write to +// Tags: +// A dictionary of tags in the form string=string +// Fields: +// A dictionary of fields(keys) with their associated values +func (conn *InfluxDBConnection) WritePoint(measurement string, + tags map[string]string, fields map[string]interface{}) error { + return conn.RecordPoint(Point{ + Measurement: measurement, + Tags: tags, + Fields: fields, + Timestamp: time.Now(), + }) +} + +// RecordPoint implements the same as WritePoint but used a point struct +// as the argument instead. +func (conn *InfluxDBConnection) RecordPoint(p Point) error { + return conn.RecordBatchPoints([]Point{p}) +} + +// Query sends a query to the influxCli and returns a slice of +// rows. Rows are of type map[string]interface{} +func (conn *InfluxDBConnection) Query(query string) ([]Row, error) { + q := influxdb.NewQuery(query, conn.Config.Database, "ns") + var rows []Row + var index = 0 + + response, err := conn.Client.Query(q) + if err != nil { + return nil, err + } + if response.Error() != nil { + return nil, response.Error() + } + + // The intent here is to combine the separate client v2 + // series into a single array. As a result queries that + // utilize "group by" will be combined into a single + // array. And the tag value will be added to the query. + // Similar to what you would expect from a SQL query + for _, result := range response.Results { + for _, series := range result.Series { + columnNames := series.Columns + for _, row := range series.Values { + rows = append(rows, make(Row)) + for columnIdx, value := range row { + rows[index][columnNames[columnIdx]] = value + } + for tagKey, tagValue := range series.Tags { + rows[index][tagKey] = tagValue + } + index++ + } + } + } + + return rows, nil +} + +// Close closes the connection opened by Connect() +func (conn *InfluxDBConnection) Close() { + conn.Client.Close() +} diff --git a/vendor/github.com/aristanetworks/goarista/influxlib/lib_test.go b/vendor/github.com/aristanetworks/goarista/influxlib/lib_test.go new file mode 100644 index 00000000..01bfacca --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/influxlib/lib_test.go @@ -0,0 +1,157 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package influxlib + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func testFields(line string, fields map[string]interface{}, + t *testing.T) { + for k, v := range fields { + formatString := "%s=%v" + + if _, ok := v.(string); ok { + formatString = "%s=%q" + } + assert.Contains(t, line, fmt.Sprintf(formatString, k, v), + fmt.Sprintf(formatString+" expected in %s", k, v, line)) + } +} + +func testTags(line string, tags map[string]string, + t *testing.T) { + for k, v := range tags { + assert.Contains(t, line, fmt.Sprintf("%s=%s", k, v), + fmt.Sprintf("%s=%s expected in %s", k, v, line)) + } +} + +func TestBasicWrite(t *testing.T) { + testConn, _ := NewMockConnection() + + measurement := "TestData" + tags := map[string]string{ + "tag1": "Happy", + "tag2": "Valentines", + "tag3": "Day", + } + fields := map[string]interface{}{ + "Data1": 1234, + "Data2": "apples", + "Data3": 5.34, + } + + err := testConn.WritePoint(measurement, tags, fields) + assert.NoError(t, err) + + line, err := GetTestBuffer(testConn) + assert.NoError(t, err) + + assert.Contains(t, line, measurement, + fmt.Sprintf("%s does not appear in %s", measurement, line)) + testTags(line, tags, t) + testFields(line, fields, t) +} + +func TestConnectionToHostFailure(t *testing.T) { + assert := assert.New(t) + var err error + + config := &InfluxConfig{ + Port: 8086, + Protocol: HTTP, + Database: "test", + } + config.Hostname = "this is fake.com" + _, err = Connect(config) + assert.Error(err) + config.Hostname = "\\-Fake.Url.Com" + _, err = Connect(config) + assert.Error(err) +} + +func TestWriteFailure(t *testing.T) { + con, _ := NewMockConnection() + + measurement := "TestData" + tags := map[string]string{ + "tag1": "hi", + } + data := map[string]interface{}{ + "Data1": "cats", + } + err := con.WritePoint(measurement, tags, data) + assert.NoError(t, err) + + fc, _ := con.Client.(*fakeClient) + fc.failAll = true + + err = con.WritePoint(measurement, tags, data) + assert.Error(t, err) +} + +func TestQuery(t *testing.T) { + query := "SELECT * FROM 'system' LIMIT 50;" + + con, _ := NewMockConnection() + + _, err := con.Query(query) + + assert.NoError(t, err) +} + +func TestAddAndWriteBatchPoints(t *testing.T) { + testConn, _ := NewMockConnection() + + measurement := "TestData" + points := []Point{ + Point{ + Measurement: measurement, + Tags: map[string]string{ + "tag1": "Happy", + "tag2": "Valentines", + "tag3": "Day", + }, + Fields: map[string]interface{}{ + "Data1": 1234, + "Data2": "apples", + "Data3": 5.34, + }, + Timestamp: time.Now(), + }, + Point{ + Measurement: measurement, + Tags: map[string]string{ + "tag1": "Happy", + "tag2": "New", + "tag3": "Year", + }, + Fields: map[string]interface{}{ + "Data1": 5678, + "Data2": "bananas", + "Data3": 3.14, + }, + Timestamp: time.Now(), + }, + } + + err := testConn.RecordBatchPoints(points) + assert.NoError(t, err) + + line, err := GetTestBuffer(testConn) + assert.NoError(t, err) + + assert.Contains(t, line, measurement, + fmt.Sprintf("%s does not appear in %s", measurement, line)) + for _, p := range points { + testTags(line, p.Tags, t) + testFields(line, p.Fields, t) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/influxlib/testlib.go b/vendor/github.com/aristanetworks/goarista/influxlib/testlib.go new file mode 100644 index 00000000..23fdac74 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/influxlib/testlib.go @@ -0,0 +1,79 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package influxlib + +import ( + "bytes" + "errors" + "fmt" + "time" + + influx "github.com/influxdata/influxdb/client/v2" +) + +// This will serve as a fake client object to test off of. +// The idea is to provide a way to test the Influx Wrapper +// without having it connected to the database. +type fakeClient struct { + writer bytes.Buffer + failAll bool +} + +func (w *fakeClient) Ping(timeout time.Duration) (time.Duration, + string, error) { + return 0, "", nil +} + +func (w *fakeClient) Query(q influx.Query) (*influx.Response, error) { + if w.failAll { + return nil, errors.New("quering points failed") + } + + return &influx.Response{Results: nil, Err: ""}, nil +} + +func (w *fakeClient) Close() error { + return nil +} + +func (w *fakeClient) Write(bp influx.BatchPoints) error { + if w.failAll { + return errors.New("writing point failed") + } + w.writer.Reset() + for _, p := range bp.Points() { + fmt.Fprintf(&w.writer, p.String()+"\n") + } + return nil +} + +func (w *fakeClient) qString() string { + return w.writer.String() +} + +/***************************************************/ + +// NewMockConnection returns an influxDBConnection with +// a "fake" client for offline testing. +func NewMockConnection() (*InfluxDBConnection, error) { + client := new(fakeClient) + config := &InfluxConfig{ + Hostname: "localhost", + Port: 8086, + Protocol: HTTP, + Database: "Test", + } + return &InfluxDBConnection{client, config}, nil +} + +// GetTestBuffer returns the string that would normally +// be written to influx DB +func GetTestBuffer(con *InfluxDBConnection) (string, error) { + fc, ok := con.Client.(*fakeClient) + if !ok { + return "", errors.New("Expected a fake client but recieved a real one") + } + return fc.qString(), nil +} diff --git a/vendor/github.com/aristanetworks/goarista/iptables.sh b/vendor/github.com/aristanetworks/goarista/iptables.sh deleted file mode 100755 index 55e77bc3..00000000 --- a/vendor/github.com/aristanetworks/goarista/iptables.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# Copyright (c) 2016 Arista Networks, Inc. -# Use of this source code is governed by the Apache License 2.0 -# that can be found in the COPYING file. - -DEFAULT_PORT=6042 - -set -e - -if [ "$#" -lt 1 ] -then - echo "usage: $0 []" - exit 1 -fi - -echo "WARNING: if you're not using EOS-INT, EOS-REV-0-1 or EOS 4.18 or earlier please use -allowed_ips on the server instead." - -host=$1 -port=$DEFAULT_PORT -if [ "$#" -gt 1 ] -then - port=$2 -fi -iptables="bash sudo iptables -A INPUT -p tcp --dport $port -j ACCEPT" -ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $host "$iptables" -echo "opened TCP port $port on $host" diff --git a/vendor/github.com/aristanetworks/goarista/kafka/openconfig/encoder.go b/vendor/github.com/aristanetworks/goarista/kafka/openconfig/encoder.go index 9c20432a..9d303a13 100644 --- a/vendor/github.com/aristanetworks/goarista/kafka/openconfig/encoder.go +++ b/vendor/github.com/aristanetworks/goarista/kafka/openconfig/encoder.go @@ -79,7 +79,7 @@ func (e *elasticsearchMessageEncoder) Encode(message proto.Message) ([]*sarama.P } glog.V(9).Infof("kafka: %s", updateJSON) return []*sarama.ProducerMessage{ - &sarama.ProducerMessage{ + { Topic: e.topic, Key: e.key, Value: sarama.ByteEncoder(updateJSON), diff --git a/vendor/github.com/aristanetworks/goarista/kafka/producer/producer.go b/vendor/github.com/aristanetworks/goarista/kafka/producer/producer.go index 6302c993..76d89b8b 100644 --- a/vendor/github.com/aristanetworks/goarista/kafka/producer/producer.go +++ b/vendor/github.com/aristanetworks/goarista/kafka/producer/producer.go @@ -116,7 +116,7 @@ func (p *producer) produceNotifications(protoMessage proto.Message) error { case <-p.done: return nil case p.kafkaProducer.Input() <- m: - glog.V(9).Infof("Message produced to Kafka: %s", m) + glog.V(9).Infof("Message produced to Kafka: %v", m) } } return nil diff --git a/vendor/github.com/aristanetworks/goarista/key/composite.go b/vendor/github.com/aristanetworks/goarista/key/composite.go index 6158fdb6..57a53902 100644 --- a/vendor/github.com/aristanetworks/goarista/key/composite.go +++ b/vendor/github.com/aristanetworks/goarista/key/composite.go @@ -5,59 +5,30 @@ package key import ( - "encoding/json" - "fmt" "reflect" "unsafe" "github.com/aristanetworks/goarista/areflect" ) -// composite allows storing a map[string]interface{} as a key in a Go map. -// This is useful when the key isn't a fixed data structure known at compile -// time but rather something generic, like a bag of key-value pairs. -// Go does not allow storing a map inside the key of a map, because maps are -// not comparable or hashable, and keys in maps must be both. This file is -// a hack specific to the 'gc' implementation of Go (which is the one most -// people use when they use Go), to bypass this check, by abusing reflection -// to override how Go compares composite for equality or how it's hashed. -// The values allowed in this map are only the types whitelisted in New() as -// well as map[Key]interface{}. -// -// See also https://github.com/golang/go/issues/283 -type composite struct { - // This value must always be set to the sentinel constant above. - sentinel uintptr - m map[string]interface{} -} - -func (k composite) Key() interface{} { - return k.m -} - -func (k composite) String() string { - return stringify(k.Key()) -} - -func (k composite) GoString() string { - return fmt.Sprintf("key.New(%#v)", k.Key()) -} - -func (k composite) MarshalJSON() ([]byte, error) { - return json.Marshal(k.Key()) -} - -func (k composite) Equal(other interface{}) bool { - o, ok := other.(composite) - return ok && mapStringEqual(k.m, o.m) -} - func hashInterface(v interface{}) uintptr { switch v := v.(type) { case map[string]interface{}: return hashMapString(v) case map[Key]interface{}: return hashMapKey(v) + case []interface{}: + return hashSlice(v) + case Pointer: + // This case applies to pointers used + // as values in maps or slices (i.e. + // not wrapped in a key). + return hashSlice(pointerToSlice(v)) + case Path: + // This case applies to paths used + // as values in maps or slices (i.e + // not wrapped in a kay). + return hashSlice(pathToSlice(v)) default: return _nilinterhash(v) } @@ -78,9 +49,9 @@ func hashMapKey(m map[Key]interface{}) uintptr { for k, v := range m { // Use addition so that the order of iteration doesn't matter. switch k := k.(type) { - case keyImpl: + case interfaceKey: h += _nilinterhash(k.key) - case composite: + case compositeKey: h += hashMapString(k.m) } h += hashInterface(v) @@ -88,28 +59,42 @@ func hashMapKey(m map[Key]interface{}) uintptr { return h } +func hashSlice(s []interface{}) uintptr { + h := uintptr(31 * (len(s) + 1)) + for _, v := range s { + h += hashInterface(v) + } + return h +} + func hash(p unsafe.Pointer, seed uintptr) uintptr { - ck := *(*composite)(p) + ck := *(*compositeKey)(p) if ck.sentinel != sentinel { panic("use of unhashable type in a map") } - return seed ^ hashMapString(ck.m) + if ck.m != nil { + return seed ^ hashMapString(ck.m) + } + return seed ^ hashSlice(ck.s) } func equal(a unsafe.Pointer, b unsafe.Pointer) bool { - ca := (*composite)(a) - cb := (*composite)(b) + ca := (*compositeKey)(a) + cb := (*compositeKey)(b) if ca.sentinel != sentinel { panic("use of uncomparable type on the lhs of ==") } if cb.sentinel != sentinel { panic("use of uncomparable type on the rhs of ==") } - return mapStringEqual(ca.m, cb.m) + if ca.m != nil { + return mapStringEqual(ca.m, cb.m) + } + return sliceEqual(ca.s, cb.s) } func init() { - typ := reflect.TypeOf(composite{}) + typ := reflect.TypeOf(compositeKey{}) alg := reflect.ValueOf(typ).Elem().FieldByName("alg").Elem() // Pretty certain that doing this voids your warranty. // This overwrites the typeAlg of either alg_NOEQ64 (on 32-bit platforms) diff --git a/vendor/github.com/aristanetworks/goarista/key/composite_test.go b/vendor/github.com/aristanetworks/goarista/key/composite_test.go index 9178b1f8..43a83fcf 100644 --- a/vendor/github.com/aristanetworks/goarista/key/composite_test.go +++ b/vendor/github.com/aristanetworks/goarista/key/composite_test.go @@ -19,7 +19,7 @@ type unhashable struct { func TestBadComposite(t *testing.T) { test.ShouldPanicWith(t, "use of unhashable type in a map", func() { m := map[interface{}]struct{}{ - unhashable{func() {}, 0x42}: struct{}{}, + unhashable{func() {}, 0x42}: {}, } // Use Key here to make sure init() is called. if _, ok := m[New("foo")]; ok { diff --git a/vendor/github.com/aristanetworks/goarista/key/key.go b/vendor/github.com/aristanetworks/goarista/key/key.go index 1ceffcb0..0fe85b28 100644 --- a/vendor/github.com/aristanetworks/goarista/key/key.go +++ b/vendor/github.com/aristanetworks/goarista/key/key.go @@ -16,14 +16,35 @@ import ( // Key represents the Key in the updates and deletes of the Notification // objects. The only reason this exists is that Go won't let us define // our own hash function for non-hashable types, and unfortunately we -// need to be able to index maps by map[string]interface{} objects. +// need to be able to index maps by map[string]interface{} objects +// and slices by []interface{} objects. type Key interface { Key() interface{} String() string Equal(other interface{}) bool } -type keyImpl struct { +// compositeKey allows storing a map[string]interface{} or []interface{} as a key +// in a Go map. This is useful when the key isn't a fixed data structure known +// at compile time but rather something generic, like a bag of key-value pairs +// or a list of elements. Go does not allow storing a map or slice inside the +// key of a map, because maps and slices are not comparable or hashable, and +// keys in maps and slice elements must be both. This file is a hack specific +// to the 'gc' implementation of Go (which is the one most people use when they +// use Go), to bypass this check, by abusing reflection to override how Go +// compares compositeKey for equality or how it's hashed. The values allowed in +// this map are only the types whitelisted in New() as well as map[Key]interface{} +// and []interface{}. +// +// See also https://github.com/golang/go/issues/283 +type compositeKey struct { + // This value must always be set to the sentinel constant above. + sentinel uintptr + m map[string]interface{} + s []interface{} +} + +type interfaceKey struct { key interface{} } @@ -44,13 +65,43 @@ type float64Key float64 type boolKey bool +type pointerKey compositeKey + +type pathKey compositeKey + +func pathToSlice(path Path) []interface{} { + s := make([]interface{}, len(path)) + for i, element := range path { + s[i] = element.Key() + } + return s +} + +func sliceToPath(s []interface{}) Path { + path := make(Path, len(s)) + for i, intf := range s { + path[i] = New(intf) + } + return path +} + +func pointerToSlice(ptr Pointer) []interface{} { + return pathToSlice(ptr.Pointer()) +} + +func sliceToPointer(s []interface{}) pointer { + return pointer(sliceToPath(s)) +} + // New wraps the given value in a Key. // This function panics if the value passed in isn't allowed in a Key or // doesn't implement value.Value. func New(intf interface{}) Key { switch t := intf.(type) { case map[string]interface{}: - return composite{sentinel, t} + return compositeKey{sentinel: sentinel, m: t} + case []interface{}: + return compositeKey{sentinel: sentinel, s: t} case string: return strKey(t) case int8: @@ -76,31 +127,35 @@ func New(intf interface{}) Key { case bool: return boolKey(t) case value.Value: - return keyImpl{key: intf} + return interfaceKey{key: intf} + case Pointer: + return pointerKey{sentinel: sentinel, s: pointerToSlice(t)} + case Path: + return pathKey{sentinel: sentinel, s: pathToSlice(t)} default: panic(fmt.Sprintf("Invalid type for key: %T", intf)) } } -func (k keyImpl) Key() interface{} { +func (k interfaceKey) Key() interface{} { return k.key } -func (k keyImpl) String() string { +func (k interfaceKey) String() string { return stringify(k.key) } -func (k keyImpl) GoString() string { +func (k interfaceKey) GoString() string { return fmt.Sprintf("key.New(%#v)", k.Key()) } -func (k keyImpl) MarshalJSON() ([]byte, error) { +func (k interfaceKey) MarshalJSON() ([]byte, error) { return json.Marshal(k.Key()) } -func (k keyImpl) Equal(other interface{}) bool { - o, ok := other.(keyImpl) - return ok && keyEqual(k.key, o.key) +func (k interfaceKey) Equal(other interface{}) bool { + o, ok := other.(Key) + return ok && keyEqual(k.key, o.Key()) } // Comparable types have an equality-testing method. @@ -121,6 +176,18 @@ func mapStringEqual(a, b map[string]interface{}) bool { return true } +func sliceEqual(a, b []interface{}) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if !keyEqual(v, b[i]) { + return false + } + } + return true +} + func keyEqual(a, b interface{}) bool { switch a := a.(type) { case map[string]interface{}: @@ -137,19 +204,56 @@ func keyEqual(a, b interface{}) bool { } } return true + case []interface{}: + b, ok := b.([]interface{}) + return ok && sliceEqual(a, b) case Comparable: return a.Equal(b) + case Pointer: + b, ok := b.(Pointer) + return ok && pointerEqual(a, b) + case Path: + b, ok := b.(Path) + return ok && pathEqual(a, b) } return a == b } +// Key interface implementation for map[string]interface{} and []interface{} +func (k compositeKey) Key() interface{} { + if k.m != nil { + return k.m + } + return k.s +} + +func (k compositeKey) String() string { + return stringify(k.Key()) +} + +func (k compositeKey) GoString() string { + return fmt.Sprintf("key.New(%#v)", k.Key()) +} + +func (k compositeKey) MarshalJSON() ([]byte, error) { + return json.Marshal(k.Key()) +} + +func (k compositeKey) Equal(other interface{}) bool { + o, ok := other.(compositeKey) + if k.m != nil { + return ok && mapStringEqual(k.m, o.m) + } + return ok && sliceEqual(k.s, o.s) +} + func (k strKey) Key() interface{} { return string(k) } func (k strKey) String() string { - return escape(string(k)) + return string(k) } func (k strKey) GoString() string { @@ -157,7 +261,7 @@ func (k strKey) GoString() string { } func (k strKey) MarshalJSON() ([]byte, error) { - return json.Marshal(string(k)) + return json.Marshal(escape(string(k))) } func (k strKey) Equal(other interface{}) bool { @@ -175,7 +279,7 @@ func (k int8Key) String() string { } func (k int8Key) GoString() string { - return fmt.Sprintf("key.New(%d)", int8(k)) + return fmt.Sprintf("key.New(int8(%d))", int8(k)) } func (k int8Key) MarshalJSON() ([]byte, error) { @@ -197,7 +301,7 @@ func (k int16Key) String() string { } func (k int16Key) GoString() string { - return fmt.Sprintf("key.New(%d)", int16(k)) + return fmt.Sprintf("key.New(int16(%d))", int16(k)) } func (k int16Key) MarshalJSON() ([]byte, error) { @@ -219,7 +323,7 @@ func (k int32Key) String() string { } func (k int32Key) GoString() string { - return fmt.Sprintf("key.New(%d)", int32(k)) + return fmt.Sprintf("key.New(int32(%d))", int32(k)) } func (k int32Key) MarshalJSON() ([]byte, error) { @@ -241,7 +345,7 @@ func (k int64Key) String() string { } func (k int64Key) GoString() string { - return fmt.Sprintf("key.New(%d)", int64(k)) + return fmt.Sprintf("key.New(int64(%d))", int64(k)) } func (k int64Key) MarshalJSON() ([]byte, error) { @@ -263,7 +367,7 @@ func (k uint8Key) String() string { } func (k uint8Key) GoString() string { - return fmt.Sprintf("key.New(%d)", uint8(k)) + return fmt.Sprintf("key.New(uint8(%d))", uint8(k)) } func (k uint8Key) MarshalJSON() ([]byte, error) { @@ -285,7 +389,7 @@ func (k uint16Key) String() string { } func (k uint16Key) GoString() string { - return fmt.Sprintf("key.New(%d)", uint16(k)) + return fmt.Sprintf("key.New(uint16(%d))", uint16(k)) } func (k uint16Key) MarshalJSON() ([]byte, error) { @@ -307,7 +411,7 @@ func (k uint32Key) String() string { } func (k uint32Key) GoString() string { - return fmt.Sprintf("key.New(%d)", uint32(k)) + return fmt.Sprintf("key.New(uint32(%d))", uint32(k)) } func (k uint32Key) MarshalJSON() ([]byte, error) { @@ -329,7 +433,7 @@ func (k uint64Key) String() string { } func (k uint64Key) GoString() string { - return fmt.Sprintf("key.New(%d)", uint64(k)) + return fmt.Sprintf("key.New(uint64(%d))", uint64(k)) } func (k uint64Key) MarshalJSON() ([]byte, error) { @@ -351,7 +455,7 @@ func (k float32Key) String() string { } func (k float32Key) GoString() string { - return fmt.Sprintf("key.New(%v)", float32(k)) + return fmt.Sprintf("key.New(float32(%v))", float32(k)) } func (k float32Key) MarshalJSON() ([]byte, error) { @@ -373,7 +477,7 @@ func (k float64Key) String() string { } func (k float64Key) GoString() string { - return fmt.Sprintf("key.New(%v)", float64(k)) + return fmt.Sprintf("key.New(float64(%v))", float64(k)) } func (k float64Key) MarshalJSON() ([]byte, error) { @@ -406,3 +510,59 @@ func (k boolKey) Equal(other interface{}) bool { o, ok := other.(boolKey) return ok && k == o } + +// Key interface implementation for Pointer +func (k pointerKey) Key() interface{} { + return sliceToPointer(k.s) +} + +func (k pointerKey) String() string { + return sliceToPointer(k.s).String() +} + +func (k pointerKey) GoString() string { + return fmt.Sprintf("key.New(%#v)", k.s) +} + +func (k pointerKey) MarshalJSON() ([]byte, error) { + return sliceToPointer(k.s).MarshalJSON() +} + +func (k pointerKey) Equal(other interface{}) bool { + if o, ok := other.(pointerKey); ok { + return sliceEqual(k.s, o.s) + } + key, ok := other.(Key) + if !ok { + return false + } + return ok && sliceToPointer(k.s).Equal(key.Key()) +} + +// Key interface implementation for Path +func (k pathKey) Key() interface{} { + return sliceToPath(k.s) +} + +func (k pathKey) String() string { + return sliceToPath(k.s).String() +} + +func (k pathKey) GoString() string { + return fmt.Sprintf("key.New(%#v)", k.s) +} + +func (k pathKey) MarshalJSON() ([]byte, error) { + return sliceToPath(k.s).MarshalJSON() +} + +func (k pathKey) Equal(other interface{}) bool { + if o, ok := other.(pathKey); ok { + return sliceEqual(k.s, o.s) + } + key, ok := other.(Key) + if !ok { + return false + } + return ok && sliceToPath(k.s).Equal(key.Key()) +} diff --git a/vendor/github.com/aristanetworks/goarista/key/key_test.go b/vendor/github.com/aristanetworks/goarista/key/key_test.go index 1a74d95a..410a7157 100644 --- a/vendor/github.com/aristanetworks/goarista/key/key_test.go +++ b/vendor/github.com/aristanetworks/goarista/key/key_test.go @@ -55,6 +55,34 @@ func TestKeyEqual(t *testing.T) { a: New("foo"), b: New("bar"), result: false, + }, { + a: New([]interface{}{}), + b: New("bar"), + result: false, + }, { + a: New([]interface{}{}), + b: New([]interface{}{}), + result: true, + }, { + a: New([]interface{}{"a", "b"}), + b: New([]interface{}{"a"}), + result: false, + }, { + a: New([]interface{}{"a", "b"}), + b: New([]interface{}{"b", "a"}), + result: false, + }, { + a: New([]interface{}{"a", "b"}), + b: New([]interface{}{"a", "b"}), + result: true, + }, { + a: New([]interface{}{"a", map[string]interface{}{"b": "c"}}), + b: New([]interface{}{"a", map[string]interface{}{"c": "b"}}), + result: false, + }, { + a: New([]interface{}{"a", map[string]interface{}{"b": "c"}}), + b: New([]interface{}{"a", map[string]interface{}{"b": "c"}}), + result: true, }, { a: New(map[string]interface{}{}), b: New("bar"), @@ -151,6 +179,32 @@ func TestGetFromMap(t *testing.T) { k: New(uint32(37)), m: map[Key]interface{}{}, found: false, + }, { + k: New([]interface{}{"a", "b"}), + m: map[Key]interface{}{ + New([]interface{}{"a", "b"}): "foo", + }, + v: "foo", + found: true, + }, { + k: New([]interface{}{"a", "b"}), + m: map[Key]interface{}{ + New([]interface{}{"a", "b", "c"}): "foo", + }, + found: false, + }, { + k: New([]interface{}{"a", map[string]interface{}{"b": "c"}}), + m: map[Key]interface{}{ + New([]interface{}{"a", map[string]interface{}{"b": "c"}}): "foo", + }, + v: "foo", + found: true, + }, { + k: New([]interface{}{"a", map[string]interface{}{"b": "c"}}), + m: map[Key]interface{}{ + New([]interface{}{"a", map[string]interface{}{"c": "b"}}): "foo", + }, + found: false, }, { k: New(map[string]interface{}{"a": "b", "c": uint64(4)}), m: map[Key]interface{}{ @@ -392,6 +446,53 @@ func TestSetToMap(t *testing.T) { } } +func TestGoString(t *testing.T) { + tcases := []struct { + in Key + out string + }{{ + in: New(uint8(1)), + out: "key.New(uint8(1))", + }, { + in: New(uint16(1)), + out: "key.New(uint16(1))", + }, { + in: New(uint32(1)), + out: "key.New(uint32(1))", + }, { + in: New(uint64(1)), + out: "key.New(uint64(1))", + }, { + in: New(int8(1)), + out: "key.New(int8(1))", + }, { + in: New(int16(1)), + out: "key.New(int16(1))", + }, { + in: New(int32(1)), + out: "key.New(int32(1))", + }, { + in: New(int64(1)), + out: "key.New(int64(1))", + }, { + in: New(float32(1)), + out: "key.New(float32(1))", + }, { + in: New(float64(1)), + out: "key.New(float64(1))", + }, { + in: New(map[string]interface{}{"foo": true}), + out: `key.New(map[string]interface {}{"foo":true})`, + }} + for i, tcase := range tcases { + t.Run(strconv.Itoa(i), func(t *testing.T) { + if out := fmt.Sprintf("%#v", tcase.in); out != tcase.out { + t.Errorf("Wanted Go representation %q but got %q", tcase.out, out) + } + }) + } +} + func TestMisc(t *testing.T) { k := New(map[string]interface{}{"foo": true}) js, err := json.Marshal(k) @@ -400,11 +501,6 @@ func TestMisc(t *testing.T) { } else if expected := `{"foo":true}`; string(js) != expected { t.Errorf("Wanted JSON %q but got %q", expected, js) } - expected := `key.New(map[string]interface {}{"foo":true})` - gostr := fmt.Sprintf("%#v", k) - if expected != gostr { - t.Errorf("Wanted Go representation %q but got %q", expected, gostr) - } test.ShouldPanic(t, func() { New(42) }) diff --git a/vendor/github.com/aristanetworks/goarista/key/path.go b/vendor/github.com/aristanetworks/goarista/key/path.go new file mode 100644 index 00000000..396a3ee9 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/key/path.go @@ -0,0 +1,51 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package key + +import ( + "bytes" + "fmt" +) + +// Path represents a path decomposed into elements where each +// element is a Key. A Path can be interpreted as either +// absolute or relative depending on how it is used. +type Path []Key + +// String returns the Path as an absolute path string. +func (p Path) String() string { + if len(p) == 0 { + return "/" + } + var buf bytes.Buffer + for _, element := range p { + buf.WriteByte('/') + buf.WriteString(element.String()) + } + return buf.String() +} + +// MarshalJSON marshals a Path to JSON. +func (p Path) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`{"_path":%q}`, p)), nil +} + +// Equal returns whether a Path is equal to @other. +func (p Path) Equal(other interface{}) bool { + o, ok := other.(Path) + return ok && pathEqual(p, o) +} + +func pathEqual(a, b Path) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if !a[i].Equal(b[i]) { + return false + } + } + return true +} diff --git a/vendor/github.com/aristanetworks/goarista/key/path_test.go b/vendor/github.com/aristanetworks/goarista/key/path_test.go new file mode 100644 index 00000000..f19301f6 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/key/path_test.go @@ -0,0 +1,141 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package key_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/aristanetworks/goarista/key" + "github.com/aristanetworks/goarista/path" +) + +func TestPath(t *testing.T) { + expected := path.New("leet") + k := key.New(expected) + + keyPath, ok := k.Key().(key.Path) + if !ok { + t.Fatalf("key.Key() did not return a key.Path") + } + if !path.Equal(keyPath, expected) { + t.Errorf("expected path from key is %#v, got %#v", expected, keyPath) + } + + if expected, actual := "/leet", fmt.Sprint(k); actual != expected { + t.Errorf("expected string from path key %q, got %q", expected, actual) + } + + if js, err := json.Marshal(k); err != nil { + t.Errorf("JSON marshalling error: %v", err) + } else if expected, actual := `{"_path":"/leet"}`, string(js); actual != expected { + t.Errorf("expected json output %q, got %q", expected, actual) + } +} + +func newPathKey(e ...interface{}) key.Key { + return key.New(path.New(e...)) +} + +type customPath string + +func (p customPath) Key() interface{} { + return path.FromString(string(p)) +} + +func (p customPath) Equal(other interface{}) bool { + o, ok := other.(key.Key) + return ok && o.Equal(p) +} + +func (p customPath) String() string { return string(p) } +func (p customPath) ToBuiltin() interface{} { panic("not impl") } +func (p customPath) MarshalJSON() ([]byte, error) { panic("not impl") } + +func TestPathEqual(t *testing.T) { + tests := []struct { + a key.Key + b key.Key + result bool + }{{ + a: newPathKey(), + b: nil, + result: false, + }, { + a: newPathKey(), + b: newPathKey(), + result: true, + }, { + a: newPathKey(), + b: newPathKey("foo"), + result: false, + }, { + a: newPathKey("foo"), + b: newPathKey(), + result: false, + }, { + a: newPathKey(int16(1337)), + b: newPathKey(int64(1337)), + result: false, + }, { + a: newPathKey(path.Wildcard, "bar"), + b: newPathKey("foo", path.Wildcard), + result: false, + }, { + a: newPathKey(map[string]interface{}{"a": "x", "b": "y"}), + b: newPathKey(map[string]interface{}{"b": "y", "a": "x"}), + result: true, + }, { + a: newPathKey(map[string]interface{}{"a": "x", "b": "y"}), + b: newPathKey(map[string]interface{}{"x": "x", "y": "y"}), + result: false, + }, { + a: newPathKey("foo", "bar"), + b: customPath("/foo/bar"), + result: true, + }, { + a: customPath("/foo/bar"), + b: newPathKey("foo", "bar"), + result: true, + }, { + a: newPathKey("foo"), + b: key.New(customPath("/bar")), + result: false, + }, { + a: key.New(customPath("/foo")), + b: newPathKey("foo", "bar"), + result: false, + }} + + for i, tc := range tests { + if a, b := tc.a, tc.b; a.Equal(b) != tc.result { + t.Errorf("result not as expected for test case %d", i) + } + } +} + +func TestPathAsKey(t *testing.T) { + a := newPathKey("foo", path.Wildcard, map[string]interface{}{ + "bar": map[key.Key]interface{}{ + // Should be able to embed a path key and value + newPathKey("path", "to", "something"): path.New("else"), + }, + }) + m := map[key.Key]string{ + a: "thats a complex key!", + } + if s, ok := m[a]; !ok { + t.Error("complex key not found in map") + } else if s != "thats a complex key!" { + t.Errorf("incorrect value in map: %s", s) + } + + // preserve custom path implementations + b := key.New(customPath("/foo/bar")) + if _, ok := b.Key().(customPath); !ok { + t.Errorf("customPath implementation not preserved: %T", b.Key()) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/key/pointer.go b/vendor/github.com/aristanetworks/goarista/key/pointer.go new file mode 100644 index 00000000..4da5dc90 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/key/pointer.go @@ -0,0 +1,46 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package key + +import ( + "fmt" +) + +// Pointer is a pointer to a path. +type Pointer interface { + Pointer() Path +} + +// NewPointer creates a new pointer to a path. +func NewPointer(path Path) Pointer { + return pointer(path) +} + +// This is the type returned by pointerKey.Key. Returning this is a +// lot faster than having pointerKey implement Pointer, since it is +// a compositeKey and thus would require reconstructing a Path from +// []interface{} any time the Pointer method is called. +type pointer Path + +func (ptr pointer) Pointer() Path { + return Path(ptr) +} + +func (ptr pointer) String() string { + return "{" + ptr.Pointer().String() + "}" +} + +func (ptr pointer) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`{"_ptr":%q}`, ptr.Pointer().String())), nil +} + +func (ptr pointer) Equal(other interface{}) bool { + o, ok := other.(Pointer) + return ok && pointerEqual(ptr, o) +} + +func pointerEqual(a, b Pointer) bool { + return pathEqual(a.Pointer(), b.Pointer()) +} diff --git a/vendor/github.com/aristanetworks/goarista/key/pointer_test.go b/vendor/github.com/aristanetworks/goarista/key/pointer_test.go new file mode 100644 index 00000000..c21691ba --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/key/pointer_test.go @@ -0,0 +1,189 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package key_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/aristanetworks/goarista/key" + "github.com/aristanetworks/goarista/path" +) + +func TestPointer(t *testing.T) { + p := key.NewPointer(path.New("foo")) + if expected, actual := path.New("foo"), p.Pointer(); !path.Equal(expected, actual) { + t.Errorf("Expected %#v but got %#v", expected, actual) + } + if expected, actual := "{/foo}", fmt.Sprintf("%s", p); actual != expected { + t.Errorf("Expected %q but got %q", expected, actual) + } + if js, err := json.Marshal(p); err != nil { + t.Errorf("JSON marshaling failed: %s", err) + } else if expected, actual := `{"_ptr":"/foo"}`, string(js); actual != expected { + t.Errorf("Expected %q but got %q", expected, actual) + } +} + +type pointer string + +func (ptr pointer) Pointer() key.Path { + return path.FromString(string(ptr)) +} + +func (ptr pointer) ToBuiltin() interface{} { + panic("NOT IMPLEMENTED") +} + +func (ptr pointer) String() string { + panic("NOT IMPLEMENTED") +} + +func (ptr pointer) MarshalJSON() ([]byte, error) { + panic("NOT IMPLEMENTED") +} + +func TestPointerEqual(t *testing.T) { + tests := []struct { + a key.Pointer + b key.Pointer + result bool + }{{ + a: key.NewPointer(nil), + b: key.NewPointer(path.New()), + result: true, + }, { + a: key.NewPointer(path.New()), + b: key.NewPointer(nil), + result: true, + }, { + a: key.NewPointer(path.New("foo")), + b: key.NewPointer(path.New("foo")), + result: true, + }, { + a: key.NewPointer(path.New("foo")), + b: key.NewPointer(path.New("bar")), + result: false, + }, { + a: key.NewPointer(path.New(true)), + b: key.NewPointer(path.New("true")), + result: false, + }, { + a: key.NewPointer(path.New(int8(0))), + b: key.NewPointer(path.New(int16(0))), + result: false, + }, { + a: key.NewPointer(path.New(path.Wildcard, "bar")), + b: key.NewPointer(path.New("foo", path.Wildcard)), + result: false, + }, { + a: key.NewPointer(path.New(map[string]interface{}{"a": "x", "b": "y"})), + b: key.NewPointer(path.New(map[string]interface{}{"b": "y", "a": "x"})), + result: true, + }, { + a: key.NewPointer(path.New(map[string]interface{}{"a": "x", "b": "y"})), + b: key.NewPointer(path.New(map[string]interface{}{"x": "x", "y": "y"})), + result: false, + }, { + a: key.NewPointer(path.New("foo")), + b: pointer("/foo"), + result: true, + }, { + a: pointer("/foo"), + b: key.NewPointer(path.New("foo")), + result: true, + }, { + a: key.NewPointer(path.New("foo")), + b: pointer("/foo/bar"), + result: false, + }, { + a: pointer("/foo/bar"), + b: key.NewPointer(path.New("foo")), + result: false, + }} + + for i, tcase := range tests { + if key.New(tcase.a).Equal(key.New(tcase.b)) != tcase.result { + t.Errorf("Error in pointer comparison for test %d", i) + } + } +} + +func TestPointerAsKey(t *testing.T) { + a := key.NewPointer(path.New("foo", path.Wildcard, map[string]interface{}{ + "bar": map[key.Key]interface{}{ + // Should be able to embed pointer key. + key.New(key.NewPointer(path.New("baz"))): + // Should be able to embed pointer value. + key.NewPointer(path.New("baz")), + }, + })) + m := map[key.Key]string{ + key.New(a): "a", + } + if s, ok := m[key.New(a)]; !ok { + t.Error("pointer to path not keyed in map") + } else if s != "a" { + t.Errorf("pointer to path not mapped to correct value in map: %s", s) + } + + // Ensure that we preserve custom pointer implementations. + b := key.New(pointer("/foo/bar")) + if _, ok := b.Key().(pointer); !ok { + t.Errorf("pointer implementation not preserved: %T", b.Key()) + } +} + +func BenchmarkPointer(b *testing.B) { + benchmarks := []key.Path{ + path.New(), + path.New("foo"), + path.New("foo", "bar"), + path.New("foo", "bar", "baz"), + path.New("foo", "bar", "baz", "qux"), + } + for i, benchmark := range benchmarks { + b.Run(fmt.Sprintf("%d", i), func(b *testing.B) { + for i := 0; i < b.N; i++ { + key.NewPointer(benchmark) + } + }) + } +} + +func BenchmarkPointerAsKey(b *testing.B) { + benchmarks := []key.Pointer{ + key.NewPointer(path.New()), + key.NewPointer(path.New("foo")), + key.NewPointer(path.New("foo", "bar")), + key.NewPointer(path.New("foo", "bar", "baz")), + key.NewPointer(path.New("foo", "bar", "baz", "qux")), + } + for i, benchmark := range benchmarks { + b.Run(fmt.Sprintf("%d", i), func(b *testing.B) { + for i := 0; i < b.N; i++ { + key.New(benchmark) + } + }) + } +} + +func BenchmarkEmbeddedPointerAsKey(b *testing.B) { + benchmarks := [][]interface{}{ + []interface{}{key.NewPointer(path.New())}, + []interface{}{key.NewPointer(path.New("foo"))}, + []interface{}{key.NewPointer(path.New("foo", "bar"))}, + []interface{}{key.NewPointer(path.New("foo", "bar", "baz"))}, + []interface{}{key.NewPointer(path.New("foo", "bar", "baz", "qux"))}, + } + for i, benchmark := range benchmarks { + b.Run(fmt.Sprintf("%d", i), func(b *testing.B) { + for i := 0; i < b.N; i++ { + key.New(benchmark) + } + }) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/key/stringify.go b/vendor/github.com/aristanetworks/goarista/key/stringify.go index bf72cb23..f9a32fdb 100644 --- a/vendor/github.com/aristanetworks/goarista/key/stringify.go +++ b/vendor/github.com/aristanetworks/goarista/key/stringify.go @@ -5,11 +5,13 @@ package key import ( + "encoding/base64" "errors" "fmt" "math" "strconv" "strings" + "unicode/utf8" "github.com/aristanetworks/goarista/value" ) @@ -67,7 +69,16 @@ func StringifyInterface(key interface{}) (string, error) { keys[i] = stringify(k) + "=" + stringify(m[k]) } str = strings.Join(keys, "_") - + case []interface{}: + elements := make([]string, len(key)) + for i, element := range key { + elements[i] = stringify(element) + } + str = strings.Join(elements, ",") + case Pointer: + return "{" + key.Pointer().String() + "}", nil + case Path: + return "[" + key.String() + "]", nil case value.Value: return key.String(), nil @@ -78,15 +89,14 @@ func StringifyInterface(key interface{}) (string, error) { return str, nil } +// escape checks if the string is a valid utf-8 string. +// If it is, it will return the string as is. +// If it is not, it will return the base64 representation of the byte array string func escape(str string) string { - for i := 0; i < len(str); i++ { - if chr := str[i]; chr < 0x20 || chr > 0x7E { - str = strconv.QuoteToASCII(str) - str = str[1 : len(str)-1] // Drop the leading and trailing quotes. - break - } + if utf8.ValidString(str) { + return str } - return str + return base64.StdEncoding.EncodeToString([]byte(str)) } func stringify(key interface{}) string { diff --git a/vendor/github.com/aristanetworks/goarista/key/stringify_test.go b/vendor/github.com/aristanetworks/goarista/key/stringify_test.go index 503861b1..20174f2a 100644 --- a/vendor/github.com/aristanetworks/goarista/key/stringify_test.go +++ b/vendor/github.com/aristanetworks/goarista/key/stringify_test.go @@ -27,9 +27,21 @@ func TestStringify(t *testing.T) { input: "foobar", output: "foobar", }, { - name: "non-ASCII string", + name: "valid non-ASCII UTF-8 string", input: "日本語", - output: `\u65e5\u672c\u8a9e`, + output: "日本語", + }, { + name: "invalid UTF-8 string 1", + input: string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe}), + output: "77++vr6+vg==", + }, { + name: "invalid UTF-8 string 2", + input: string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x23}), + output: "77++vr6+viM=", + }, { + name: "invalid UTF-8 string 3", + input: string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x23, 0x24}), + output: "77++vr6+viMk", }, { name: "uint8", input: uint8(43), @@ -107,6 +119,22 @@ func TestStringify(t *testing.T) { "n": nil, }, output: "Unable to stringify nil", + }, { + name: "[]interface{}", + input: []interface{}{ + uint32(42), + true, + "foo", + map[Key]interface{}{ + New("a"): "b", + New("b"): "c", + }, + }, + output: "42,true,foo,a=b_b=c", + }, { + name: "pointer", + input: NewPointer(Path{New("foo"), New("bar")}), + output: "{/foo/bar}", }} for _, tcase := range testcases { diff --git a/vendor/github.com/aristanetworks/goarista/netns/netns.go b/vendor/github.com/aristanetworks/goarista/netns/netns.go index ac8f6afa..40412d6a 100644 --- a/vendor/github.com/aristanetworks/goarista/netns/netns.go +++ b/vendor/github.com/aristanetworks/goarista/netns/netns.go @@ -8,8 +8,6 @@ package netns import ( "fmt" - "os" - "runtime" ) const ( @@ -45,54 +43,3 @@ func setNsByName(nsName string) error { } return nil } - -// Do takes a function which it will call in the network namespace specified by nsName. -// The goroutine that calls this will lock itself to its current OS thread, hop -// namespaces, call the given function, hop back to its original namespace, and then -// unlock itself from its current OS thread. -// Do returns an error if an error occurs at any point besides in the invocation of -// the given function, or if the given function itself returns an error. -// -// The callback function is expected to do something simple such as just -// creating a socket / opening a connection, and you should not kick off any -// complex logic from the callback or call any complicated code or create any -// new goroutine from the callback. The callback should not panic or use defer. -// The behavior of this function is undefined if the callback doesn't conform -// these demands. -//go:nosplit -func Do(nsName string, cb Callback) error { - // If destNS is empty, the function is called in the caller's namespace - if nsName == "" { - return cb() - } - - // Get the file descriptor to the current namespace - currNsFd, err := getNs(selfNsFile) - if os.IsNotExist(err) { - return fmt.Errorf("File descriptor to current namespace does not exist: %s", err) - } else if err != nil { - return fmt.Errorf("Failed to open %s: %s", selfNsFile, err) - } - - runtime.LockOSThread() - - // Jump to the new network namespace - if err := setNsByName(nsName); err != nil { - runtime.UnlockOSThread() - currNsFd.close() - return fmt.Errorf("Failed to set the namespace to %s: %s", nsName, err) - } - - // Call the given function - cbErr := cb() - - // Come back to the original namespace - if err = setNs(currNsFd); err != nil { - cbErr = fmt.Errorf("Failed to return to the original namespace: %s (callback returned %v)", - err, cbErr) - } - - runtime.UnlockOSThread() - currNsFd.close() - return cbErr -} diff --git a/vendor/github.com/aristanetworks/goarista/netns/netns_110.go b/vendor/github.com/aristanetworks/goarista/netns/netns_110.go new file mode 100644 index 00000000..b7f336a2 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/netns/netns_110.go @@ -0,0 +1,60 @@ +// Copyright (c) 2016 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +// +build go1.10 + +package netns + +import ( + "fmt" + "os" + "runtime" +) + +// Do takes a function which it will call in the network namespace specified by nsName. +// The goroutine that calls this will lock itself to its current OS thread, hop +// namespaces, call the given function, hop back to its original namespace, and then +// unlock itself from its current OS thread. +// Do returns an error if an error occurs at any point besides in the invocation of +// the given function, or if the given function itself returns an error. +// +// The callback function is expected to do something simple such as just +// creating a socket / opening a connection, as it's not desirable to start +// complex logic in a goroutine that is pinned to the current OS thread. +// Also any goroutine started from the callback function may or may not +// execute in the desired namespace. +func Do(nsName string, cb Callback) error { + // If destNS is empty, the function is called in the caller's namespace + if nsName == "" { + return cb() + } + + // Get the file descriptor to the current namespace + currNsFd, err := getNs(selfNsFile) + if os.IsNotExist(err) { + return fmt.Errorf("File descriptor to current namespace does not exist: %s", err) + } else if err != nil { + return fmt.Errorf("Failed to open %s: %s", selfNsFile, err) + } + defer currNsFd.close() + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // Jump to the new network namespace + if err := setNsByName(nsName); err != nil { + return fmt.Errorf("Failed to set the namespace to %s: %s", nsName, err) + } + + // Call the given function + cbErr := cb() + + // Come back to the original namespace + if err = setNs(currNsFd); err != nil { + return fmt.Errorf("Failed to return to the original namespace: %s (callback returned %v)", + err, cbErr) + } + + return cbErr +} diff --git a/vendor/github.com/aristanetworks/goarista/netns/netns_pre110.go b/vendor/github.com/aristanetworks/goarista/netns/netns_pre110.go new file mode 100644 index 00000000..af41a640 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/netns/netns_pre110.go @@ -0,0 +1,64 @@ +// Copyright (c) 2016 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +// +build !go1.10 + +package netns + +import ( + "fmt" + "os" + "runtime" +) + +// Do takes a function which it will call in the network namespace specified by nsName. +// The goroutine that calls this will lock itself to its current OS thread, hop +// namespaces, call the given function, hop back to its original namespace, and then +// unlock itself from its current OS thread. +// Do returns an error if an error occurs at any point besides in the invocation of +// the given function, or if the given function itself returns an error. +// +// The callback function is expected to do something simple such as just +// creating a socket / opening a connection, and you should not kick off any +// complex logic from the callback or call any complicated code or create any +// new goroutine from the callback. The callback should not panic or use defer. +// The behavior of this function is undefined if the callback doesn't conform +// these demands. +//go:nosplit +func Do(nsName string, cb Callback) error { + // If destNS is empty, the function is called in the caller's namespace + if nsName == "" { + return cb() + } + + // Get the file descriptor to the current namespace + currNsFd, err := getNs(selfNsFile) + if os.IsNotExist(err) { + return fmt.Errorf("File descriptor to current namespace does not exist: %s", err) + } else if err != nil { + return fmt.Errorf("Failed to open %s: %s", selfNsFile, err) + } + + runtime.LockOSThread() + + // Jump to the new network namespace + if err := setNsByName(nsName); err != nil { + runtime.UnlockOSThread() + currNsFd.close() + return fmt.Errorf("Failed to set the namespace to %s: %s", nsName, err) + } + + // Call the given function + cbErr := cb() + + // Come back to the original namespace + if err = setNs(currNsFd); err != nil { + cbErr = fmt.Errorf("Failed to return to the original namespace: %s (callback returned %v)", + err, cbErr) + } + + runtime.UnlockOSThread() + currNsFd.close() + return cbErr +} diff --git a/vendor/github.com/aristanetworks/goarista/openconfig/client/client.go b/vendor/github.com/aristanetworks/goarista/openconfig/client/client.go index 616b9893..0a8d5618 100644 --- a/vendor/github.com/aristanetworks/goarista/openconfig/client/client.go +++ b/vendor/github.com/aristanetworks/goarista/openconfig/client/client.go @@ -18,7 +18,7 @@ import ( "google.golang.org/grpc/metadata" ) -const defaultPort = "6042" +const defaultPort = "6030" // PublishFunc is the method to publish responses type PublishFunc func(addr string, message proto.Message) @@ -36,6 +36,9 @@ func New(username, password, addr string, opts []grpc.DialOption) *Client { if !strings.ContainsRune(addr, ':') { addr += ":" + defaultPort } + // Make sure we don't move past the grpc.Dial() call until we actually + // established an HTTP/2 connection successfully. + opts = append(opts, grpc.WithBlock(), grpc.WithWaitForHandshake()) conn, err := grpc.Dial(addr, opts...) if err != nil { glog.Fatalf("Failed to dial: %s", err) @@ -93,7 +96,7 @@ func (c *Client) Subscribe(wg *sync.WaitGroup, subscriptions []string, Request: &openconfig.SubscribeRequest_Subscribe{ Subscribe: &openconfig.SubscriptionList{ Subscription: []*openconfig.Subscription{ - &openconfig.Subscription{ + { Path: &openconfig.Path{Element: strings.Split(path, "/")}, }, }, diff --git a/vendor/github.com/aristanetworks/goarista/openconfig/client/flags.go b/vendor/github.com/aristanetworks/goarista/openconfig/client/flags.go index 7e9ad101..865a60b6 100644 --- a/vendor/github.com/aristanetworks/goarista/openconfig/client/flags.go +++ b/vendor/github.com/aristanetworks/goarista/openconfig/client/flags.go @@ -23,7 +23,7 @@ func ParseFlags() (username string, password string, subscriptions, addrs []stri opts []grpc.DialOption) { var ( - addrsFlag = flag.String("addrs", "localhost:6042", + addrsFlag = flag.String("addrs", "localhost:6030", "Comma-separated list of addresses of OpenConfig gRPC servers") caFileFlag = flag.String("cafile", "", diff --git a/vendor/github.com/aristanetworks/goarista/openconfig/json_test.go b/vendor/github.com/aristanetworks/goarista/openconfig/json_test.go index 51b5e55d..1dfc41d5 100644 --- a/vendor/github.com/aristanetworks/goarista/openconfig/json_test.go +++ b/vendor/github.com/aristanetworks/goarista/openconfig/json_test.go @@ -80,11 +80,11 @@ func TestNotificationToMap(t *testing.T) { }, }, Delete: []*openconfig.Path{ - &openconfig.Path{ + { Element: []string{ "route", "237.255.255.250_0.0.0.0", }}, - &openconfig.Path{ + { Element: []string{ "route", "238.255.255.250_0.0.0.0", }, diff --git a/vendor/github.com/aristanetworks/goarista/path/map.go b/vendor/github.com/aristanetworks/goarista/path/map.go index bda2f365..05e2256c 100644 --- a/vendor/github.com/aristanetworks/goarista/path/map.go +++ b/vendor/github.com/aristanetworks/goarista/path/map.go @@ -10,221 +10,288 @@ import ( "sort" "github.com/aristanetworks/goarista/key" - "github.com/aristanetworks/goarista/pathmap" ) -// Map associates Paths to values. It allows wildcards. The -// primary use of Map is to be able to register handlers to paths -// that can be efficiently looked up every time a path is updated. -// -// For example: -// -// m.Set({key.New("interfaces"), key.New("*"), key.New("adminStatus")}, AdminStatusHandler) -// m.Set({key.New("interface"), key.New("Management1"), key.New("adminStatus")}, -// Management1AdminStatusHandler) -// -// m.Visit(Path{key.New("interfaces"), key.New("Ethernet3/32/1"), key.New("adminStatus")}, -// HandlerExecutor) -// >> AdminStatusHandler gets passed to HandlerExecutor -// m.Visit(Path{key.New("interfaces"), key.New("Management1"), key.New("adminStatus")}, -// HandlerExecutor) -// >> AdminStatusHandler and Management1AdminStatusHandler gets passed to HandlerExecutor -// -// Note, Visit performance is typically linearly with the length of -// the path. But, it can be as bad as O(2^len(Path)) when TreeMap -// nodes have children and a wildcard associated with it. For example, -// if these paths were registered: -// -// m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz")}, 1) -// m.Set(Path{key.New("*"), key.New("bar"), key.New("baz")}, 2) -// m.Set(Path{key.New("*"), key.New("*"), key.New("baz")}, 3) -// m.Set(Path{key.New("*"), key.New("*"), key.New("*")}, 4) -// m.Set(Path{key.New("foo"), key.New("*"), key.New("*")}, 5) -// m.Set(Path{key.New("foo"), key.New("bar"), key.New("*")}, 6) -// m.Set(Path{key.New("foo"), key.New("*"), key.New("baz")}, 7) -// m.Set(Path{key.New("*"), key.New("bar"), key.New("*")}, 8) -// -// m.Visit(Path{key.New("foo"),key.New("bar"),key.New("baz")}, Foo) // 2^3 nodes traversed -// -// This shouldn't be a concern with our paths because it is likely -// that a TreeMap node will either have a wildcard or children, not -// both. A TreeMap node that corresponds to a collection will often be a -// wildcard, otherwise it will have specific children. -type Map interface { - // Visit calls f for every registration in the Map that - // matches path. For example, - // - // m.Set(Path{key.New("foo"), key.New("bar")}, 1) - // m.Set(Path{key.New("*"), key.New("bar")}, 2) - // - // m.Visit(Path{key.New("foo"), key.New("bar")}, Printer) - // >> Calls Printer(1) and Printer(2) - Visit(p Path, f pathmap.VisitorFunc) error - - // VisitPrefix calls f for every registration in the Map that - // is a prefix of path. For example, - // - // m.Set(Path{}, 0) - // m.Set(Path{key.New("foo")}, 1) - // m.Set(Path{key.New("foo"), key.New("bar")}, 2) - // m.Set(Path{key.New("foo"), key.New("quux")}, 3) - // m.Set(Path{key.New("*"), key.New("bar")}, 4) - // - // m.VisitPrefix(Path{key.New("foo"), key.New("bar"), key.New("baz")}, Printer) - // >> Calls Printer on values 0, 1, 2, and 4 - VisitPrefix(p Path, f pathmap.VisitorFunc) error - - // Get returns the mapping for path. This returns the exact - // mapping for path. For example, if you register two paths - // - // m.Set(Path{key.New("foo"), key.New("bar")}, 1) - // m.Set(Path{key.New("*"), key.New("bar")}, 2) - // - // m.Get(Path{key.New("foo"), key.New("bar")}) => 1 - // m.Get(Path{key.New("*"), key.New("bar")}) => 2 - Get(p Path) interface{} - - // Set a mapping of path to value. Path may contain wildcards. Set - // replaces what was there before. - Set(p Path, v interface{}) - - // Delete removes the mapping for path - Delete(p Path) bool -} - -// Wildcard is a special key representing any possible path -var Wildcard key.Key = key.New("*") - -type node struct { +// Map associates paths to values. It allows wildcards. A Map +// is primarily used to register handlers with paths that can +// be easily looked up each time a path is updated. +type Map struct { val interface{} - wildcard *node - children map[key.Key]*node + ok bool + wildcard *Map + children map[key.Key]*Map } -// NewMap creates a new Map -func NewMap() Map { - return &node{} -} +// VisitorFunc is a function that handles the value associated +// with a path in a Map. Note that only the value is passed in +// as an argument since the path can be stored inside the value +// if needed. +type VisitorFunc func(v interface{}) error -// Visit calls f for every matching registration in the Map -func (n *node) Visit(p Path, f pathmap.VisitorFunc) error { +// Visit calls a function fn for every value in the Map +// that is registered with a match of a path p. In the +// general case, time complexity is linear with respect +// to the length of p but it can be as bad as O(2^len(p)) +// if there are a lot of paths with wildcards registered. +// +// Example: +// +// a := path.New("foo", "bar", "baz") +// b := path.New("foo", path.Wildcard, "baz") +// c := path.New(path.Wildcard, "bar", "baz") +// d := path.New("foo", "bar", path.Wildcard) +// e := path.New(path.Wildcard, path.Wildcard, "baz") +// f := path.New(path.Wildcard, "bar", path.Wildcard) +// g := path.New("foo", path.Wildcard, path.Wildcard) +// h := path.New(path.Wildcard, path.Wildcard, path.Wildcard) +// +// m.Set(a, 1) +// m.Set(b, 2) +// m.Set(c, 3) +// m.Set(d, 4) +// m.Set(e, 5) +// m.Set(f, 6) +// m.Set(g, 7) +// m.Set(h, 8) +// +// p := path.New("foo", "bar", "baz") +// +// m.Visit(p, fn) +// +// Result: fn(1), fn(2), fn(3), fn(4), fn(5), fn(6), fn(7) and fn(8) +func (m *Map) Visit(p key.Path, fn VisitorFunc) error { for i, element := range p { - if n.wildcard != nil { - if err := n.wildcard.Visit(p[i+1:], f); err != nil { + if m.wildcard != nil { + if err := m.wildcard.Visit(p[i+1:], fn); err != nil { return err } } - next, ok := n.children[element] + next, ok := m.children[element] if !ok { return nil } - n = next + m = next } - if n.val == nil { + if !m.ok { return nil } - return f(n.val) + return fn(m.val) } -// VisitPrefix calls f for every registered path that is a prefix of -// the path -func (n *node) VisitPrefix(p Path, f pathmap.VisitorFunc) error { +// VisitPrefixes calls a function fn for every value in the +// Map that is registered with a prefix of a path p. +// +// Example: +// +// a := path.New() +// b := path.New("foo") +// c := path.New("foo", "bar") +// d := path.New("foo", "baz") +// e := path.New(path.Wildcard, "bar") +// +// m.Set(a, 1) +// m.Set(b, 2) +// m.Set(c, 3) +// m.Set(d, 4) +// m.Set(e, 5) +// +// p := path.New("foo", "bar", "baz") +// +// m.VisitPrefixes(p, fn) +// +// Result: fn(1), fn(2), fn(3), fn(5) +func (m *Map) VisitPrefixes(p key.Path, fn VisitorFunc) error { for i, element := range p { - // Call f on each node we visit - if n.val != nil { - if err := f(n.val); err != nil { + if m.ok { + if err := fn(m.val); err != nil { return err } } - if n.wildcard != nil { - if err := n.wildcard.VisitPrefix(p[i+1:], f); err != nil { + if m.wildcard != nil { + if err := m.wildcard.VisitPrefixes(p[i+1:], fn); err != nil { return err } } - next, ok := n.children[element] + next, ok := m.children[element] if !ok { return nil } - n = next + m = next } - if n.val == nil { + if !m.ok { return nil } - // Call f on the final node - return f(n.val) + return fn(m.val) } -// Get returns the mapping for path -func (n *node) Get(p Path) interface{} { - for _, element := range p { - if element.Equal(Wildcard) { - if n.wildcard == nil { - return nil +// VisitPrefixed calls fn for every value in the map that is +// registerd with a path that is prefixed by p. This method +// can be used to visit every registered path if p is the +// empty path (or root path) which prefixes all paths. +// +// Example: +// +// a := path.New("foo") +// b := path.New("foo", "bar") +// c := path.New("foo", "bar", "baz") +// d := path.New("foo", path.Wildcard) +// +// m.Set(a, 1) +// m.Set(b, 2) +// m.Set(c, 3) +// m.Set(d, 4) +// +// p := path.New("foo", "bar") +// +// m.VisitPrefixed(p, fn) +// +// Result: fn(2), fn(3), fn(4) +func (m *Map) VisitPrefixed(p key.Path, fn VisitorFunc) error { + for i, element := range p { + if m.wildcard != nil { + if err := m.wildcard.VisitPrefixed(p[i+1:], fn); err != nil { + return err } - n = n.wildcard - continue } - next, ok := n.children[element] + next, ok := m.children[element] if !ok { return nil } - n = next + m = next } - return n.val + return m.visitSubtree(fn) } -// Set a mapping of path to value. Path may contain wildcards. Set -// replaces what was there before. -func (n *node) Set(p Path, v interface{}) { +func (m *Map) visitSubtree(fn VisitorFunc) error { + if m.ok { + if err := fn(m.val); err != nil { + return err + } + } + if m.wildcard != nil { + if err := m.wildcard.visitSubtree(fn); err != nil { + return err + } + } + for _, next := range m.children { + if err := next.visitSubtree(fn); err != nil { + return err + } + } + return nil +} + +// Get returns the value registered with an exact match of a +// path p. If there is no exact match for p, Get returns nil +// and false. If p has an exact match and it is set to true, +// Get returns nil and true. +// +// Example: +// +// m.Set(path.New("foo", "bar"), 1) +// m.Set(path.New("baz", "qux"), nil) +// +// a := m.Get(path.New("foo", "bar")) +// b := m.Get(path.New("foo", path.Wildcard)) +// c, ok := m.Get(path.New("baz", "qux")) +// +// Result: a == 1, b == nil, c == nil and ok == true +func (m *Map) Get(p key.Path) (interface{}, bool) { for _, element := range p { if element.Equal(Wildcard) { - if n.wildcard == nil { - n.wildcard = &node{} + if m.wildcard == nil { + return nil, false } - n = n.wildcard + m = m.wildcard continue } - if n.children == nil { - n.children = map[key.Key]*node{} - } - next, ok := n.children[element] + next, ok := m.children[element] if !ok { - next = &node{} - n.children[element] = next + return nil, false } - n = next + m = next } - n.val = v + return m.val, m.ok } -// Delete removes the mapping for path -func (n *node) Delete(p Path) bool { - nodes := make([]*node, len(p)+1) - for i, element := range p { - nodes[i] = n +// Set registers a path p with a value. If the path was already +// registered with a value it returns true and false otherwise. +// +// Example: +// +// p := path.New("foo", "bar") +// +// a := m.Set(p, 0) +// b := m.Set(p, 1) +// +// v := m.Get(p) +// +// Result: a == false, b == true and v == 1 +func (m *Map) Set(p key.Path, v interface{}) bool { + for _, element := range p { if element.Equal(Wildcard) { - if n.wildcard == nil { + if m.wildcard == nil { + m.wildcard = &Map{} + } + m = m.wildcard + continue + } + if m.children == nil { + m.children = map[key.Key]*Map{} + } + next, ok := m.children[element] + if !ok { + next = &Map{} + m.children[element] = next + } + m = next + } + set := !m.ok + m.val, m.ok = v, true + return set +} + +// Delete unregisters the value registered with a path. It +// returns true if a value was deleted and false otherwise. +// +// Example: +// +// p := path.New("foo", "bar") +// +// m.Set(p, 0) +// +// a := m.Delete(p) +// b := m.Delete(p) +// +// Result: a == true and b == false +func (m *Map) Delete(p key.Path) bool { + maps := make([]*Map, len(p)+1) + for i, element := range p { + maps[i] = m + if element.Equal(Wildcard) { + if m.wildcard == nil { return false } - n = n.wildcard + m = m.wildcard continue } - next, ok := n.children[element] + next, ok := m.children[element] if !ok { return false } - n = next + m = next } - n.val = nil - nodes[len(p)] = n + deleted := m.ok + m.val, m.ok = nil, false + maps[len(p)] = m - // See if we can delete any node objects + // Remove any empty maps. for i := len(p); i > 0; i-- { - n = nodes[i] - if n.val != nil || n.wildcard != nil || len(n.children) > 0 { + m = maps[i] + if m.ok || m.wildcard != nil || len(m.children) > 0 { break } - parent := nodes[i-1] + parent := maps[i-1] element := p[i-1] if element.Equal(Wildcard) { parent.wildcard = nil @@ -232,28 +299,28 @@ func (n *node) Delete(p Path) bool { delete(parent.children, element) } } - return true + return deleted } -func (n *node) String() string { +func (m *Map) String() string { var b bytes.Buffer - n.write(&b, "") + m.write(&b, "") return b.String() } -func (n *node) write(b *bytes.Buffer, indent string) { - if n.val != nil { +func (m *Map) write(b *bytes.Buffer, indent string) { + if m.ok { b.WriteString(indent) - fmt.Fprintf(b, "Val: %v", n.val) + fmt.Fprintf(b, "Val: %v", m.val) b.WriteString("\n") } - if n.wildcard != nil { + if m.wildcard != nil { b.WriteString(indent) fmt.Fprintf(b, "Child %q:\n", Wildcard) - n.wildcard.write(b, indent+" ") + m.wildcard.write(b, indent+" ") } - children := make([]key.Key, 0, len(n.children)) - for key := range n.children { + children := make([]key.Key, 0, len(m.children)) + for key := range m.children { children = append(children, key) } sort.Slice(children, func(i, j int) bool { @@ -261,7 +328,7 @@ func (n *node) write(b *bytes.Buffer, indent string) { }) for _, key := range children { - child := n.children[key] + child := m.children[key] b.WriteString(indent) fmt.Fprintf(b, "Child %q:\n", key.String()) child.write(b, indent+" ") diff --git a/vendor/github.com/aristanetworks/goarista/path/map_test.go b/vendor/github.com/aristanetworks/goarista/path/map_test.go index 90def4eb..da5f28fe 100644 --- a/vendor/github.com/aristanetworks/goarista/path/map_test.go +++ b/vendor/github.com/aristanetworks/goarista/path/map_test.go @@ -10,68 +10,76 @@ import ( "testing" "github.com/aristanetworks/goarista/key" - "github.com/aristanetworks/goarista/pathmap" "github.com/aristanetworks/goarista/test" ) -func accumulator(counter map[int]int) pathmap.VisitorFunc { +func accumulator(counter map[int]int) VisitorFunc { return func(val interface{}) error { counter[val.(int)]++ return nil } } -func TestVisit(t *testing.T) { - m := NewMap() - m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz")}, 1) - m.Set(Path{key.New("*"), key.New("bar"), key.New("baz")}, 2) - m.Set(Path{key.New("*"), key.New("*"), key.New("baz")}, 3) - m.Set(Path{key.New("*"), key.New("*"), key.New("*")}, 4) - m.Set(Path{key.New("foo"), key.New("*"), key.New("*")}, 5) - m.Set(Path{key.New("foo"), key.New("bar"), key.New("*")}, 6) - m.Set(Path{key.New("foo"), key.New("*"), key.New("baz")}, 7) - m.Set(Path{key.New("*"), key.New("bar"), key.New("*")}, 8) +func TestMapSet(t *testing.T) { + m := Map{} + a := m.Set(key.Path{key.New("foo")}, 0) + b := m.Set(key.Path{key.New("foo")}, 1) + if !a || b { + t.Fatal("Map.Set not working properly") + } +} - m.Set(Path{}, 10) +func TestMapVisit(t *testing.T) { + m := Map{} + m.Set(key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, 1) + m.Set(key.Path{Wildcard, key.New("bar"), key.New("baz")}, 2) + m.Set(key.Path{Wildcard, Wildcard, key.New("baz")}, 3) + m.Set(key.Path{Wildcard, Wildcard, Wildcard}, 4) + m.Set(key.Path{key.New("foo"), Wildcard, Wildcard}, 5) + m.Set(key.Path{key.New("foo"), key.New("bar"), Wildcard}, 6) + m.Set(key.Path{key.New("foo"), Wildcard, key.New("baz")}, 7) + m.Set(key.Path{Wildcard, key.New("bar"), Wildcard}, 8) - m.Set(Path{key.New("*")}, 20) - m.Set(Path{key.New("foo")}, 21) + m.Set(key.Path{}, 10) - m.Set(Path{key.New("zap"), key.New("zip")}, 30) - m.Set(Path{key.New("zap"), key.New("zip")}, 31) + m.Set(key.Path{Wildcard}, 20) + m.Set(key.Path{key.New("foo")}, 21) - m.Set(Path{key.New("zip"), key.New("*")}, 40) - m.Set(Path{key.New("zip"), key.New("*")}, 41) + m.Set(key.Path{key.New("zap"), key.New("zip")}, 30) + m.Set(key.Path{key.New("zap"), key.New("zip")}, 31) + + m.Set(key.Path{key.New("zip"), Wildcard}, 40) + m.Set(key.Path{key.New("zip"), Wildcard}, 41) testCases := []struct { - path Path + path key.Path expected map[int]int }{{ - path: Path{key.New("foo"), key.New("bar"), key.New("baz")}, + path: key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, expected: map[int]int{1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, }, { - path: Path{key.New("qux"), key.New("bar"), key.New("baz")}, + path: key.Path{key.New("qux"), key.New("bar"), key.New("baz")}, expected: map[int]int{2: 1, 3: 1, 4: 1, 8: 1}, }, { - path: Path{key.New("foo"), key.New("qux"), key.New("baz")}, + path: key.Path{key.New("foo"), key.New("qux"), key.New("baz")}, expected: map[int]int{3: 1, 4: 1, 5: 1, 7: 1}, }, { - path: Path{key.New("foo"), key.New("bar"), key.New("qux")}, + path: key.Path{key.New("foo"), key.New("bar"), key.New("qux")}, expected: map[int]int{4: 1, 5: 1, 6: 1, 8: 1}, }, { - path: Path{}, + path: key.Path{}, expected: map[int]int{10: 1}, }, { - path: Path{key.New("foo")}, + path: key.Path{key.New("foo")}, expected: map[int]int{20: 1, 21: 1}, }, { - path: Path{key.New("foo"), key.New("bar")}, + path: key.Path{key.New("foo"), key.New("bar")}, expected: map[int]int{}, }, { - path: Path{key.New("zap"), key.New("zip")}, + path: key.Path{key.New("zap"), key.New("zip")}, expected: map[int]int{31: 1}, }, { - path: Path{key.New("zip"), key.New("zap")}, + path: key.Path{key.New("zip"), key.New("zap")}, expected: map[int]int{41: 1}, }} @@ -84,135 +92,160 @@ func TestVisit(t *testing.T) { } } -func TestVisitError(t *testing.T) { - m := NewMap() - m.Set(Path{key.New("foo"), key.New("bar")}, 1) - m.Set(Path{key.New("*"), key.New("bar")}, 2) +func TestMapVisitError(t *testing.T) { + m := Map{} + m.Set(key.Path{key.New("foo"), key.New("bar")}, 1) + m.Set(key.Path{Wildcard, key.New("bar")}, 2) errTest := errors.New("Test") - err := m.Visit(Path{key.New("foo"), key.New("bar")}, + err := m.Visit(key.Path{key.New("foo"), key.New("bar")}, func(v interface{}) error { return errTest }) if err != errTest { t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err) } - err = m.VisitPrefix(Path{key.New("foo"), key.New("bar"), key.New("baz")}, + err = m.VisitPrefixes(key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, func(v interface{}) error { return errTest }) if err != errTest { t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err) } } -func TestGet(t *testing.T) { - m := NewMap() - m.Set(Path{}, 0) - m.Set(Path{key.New("foo"), key.New("bar")}, 1) - m.Set(Path{key.New("foo"), key.New("*")}, 2) - m.Set(Path{key.New("*"), key.New("bar")}, 3) - m.Set(Path{key.New("zap"), key.New("zip")}, 4) +func TestMapGet(t *testing.T) { + m := Map{} + m.Set(key.Path{}, 0) + m.Set(key.Path{key.New("foo"), key.New("bar")}, 1) + m.Set(key.Path{key.New("foo"), Wildcard}, 2) + m.Set(key.Path{Wildcard, key.New("bar")}, 3) + m.Set(key.Path{key.New("zap"), key.New("zip")}, 4) + m.Set(key.Path{key.New("baz"), key.New("qux")}, nil) testCases := []struct { - path Path - expected interface{} + path key.Path + v interface{} + ok bool }{{ - path: Path{}, - expected: 0, + path: key.Path{}, + v: 0, + ok: true, }, { - path: Path{key.New("foo"), key.New("bar")}, - expected: 1, + path: key.Path{key.New("foo"), key.New("bar")}, + v: 1, + ok: true, }, { - path: Path{key.New("foo"), key.New("*")}, - expected: 2, + path: key.Path{key.New("foo"), Wildcard}, + v: 2, + ok: true, }, { - path: Path{key.New("*"), key.New("bar")}, - expected: 3, + path: key.Path{Wildcard, key.New("bar")}, + v: 3, + ok: true, }, { - path: Path{key.New("bar"), key.New("foo")}, - expected: nil, + path: key.Path{key.New("baz"), key.New("qux")}, + v: nil, + ok: true, }, { - path: Path{key.New("zap"), key.New("*")}, - expected: nil, + path: key.Path{key.New("bar"), key.New("foo")}, + v: nil, + }, { + path: key.Path{key.New("zap"), Wildcard}, + v: nil, }} for _, tc := range testCases { - got := m.Get(tc.path) - if got != tc.expected { - t.Errorf("Test case %v: Expected %v, Got %v", - tc.path, tc.expected, got) + v, ok := m.Get(tc.path) + if v != tc.v || ok != tc.ok { + t.Errorf("Test case %v: Expected (v: %v, ok: %t), Got (v: %v, ok: %t)", + tc.path, tc.v, tc.ok, v, ok) } } } -func countNodes(n *node) int { - if n == nil { +func countNodes(m *Map) int { + if m == nil { return 0 } count := 1 - count += countNodes(n.wildcard) - for _, child := range n.children { + count += countNodes(m.wildcard) + for _, child := range m.children { count += countNodes(child) } return count } -func TestDelete(t *testing.T) { - m := NewMap() - m.Set(Path{}, 0) - m.Set(Path{key.New("*")}, 1) - m.Set(Path{key.New("foo"), key.New("bar")}, 2) - m.Set(Path{key.New("foo"), key.New("*")}, 3) +func TestMapDelete(t *testing.T) { + m := Map{} + m.Set(key.Path{}, 0) + m.Set(key.Path{Wildcard}, 1) + m.Set(key.Path{key.New("foo"), key.New("bar")}, 2) + m.Set(key.Path{key.New("foo"), Wildcard}, 3) + m.Set(key.Path{key.New("foo")}, 4) - n := countNodes(m.(*node)) + n := countNodes(&m) if n != 5 { t.Errorf("Initial count wrong. Expected: 5, Got: %d", n) } testCases := []struct { - del Path // Path to delete + del key.Path // key.Path to delete expected bool // expected return value of Delete - visit Path // Path to Visit + visit key.Path // key.Path to Visit before map[int]int // Expected to find items before deletion after map[int]int // Expected to find items after deletion count int // Count of nodes }{{ - del: Path{key.New("zap")}, // A no-op Delete + del: key.Path{key.New("zap")}, // A no-op Delete expected: false, - visit: Path{key.New("foo"), key.New("bar")}, + visit: key.Path{key.New("foo"), key.New("bar")}, before: map[int]int{2: 1, 3: 1}, after: map[int]int{2: 1, 3: 1}, count: 5, }, { - del: Path{key.New("foo"), key.New("bar")}, + del: key.Path{key.New("foo"), key.New("bar")}, expected: true, - visit: Path{key.New("foo"), key.New("bar")}, + visit: key.Path{key.New("foo"), key.New("bar")}, before: map[int]int{2: 1, 3: 1}, after: map[int]int{3: 1}, count: 4, }, { - del: Path{key.New("*")}, + del: key.Path{key.New("foo")}, expected: true, - visit: Path{key.New("foo")}, + visit: key.Path{key.New("foo")}, + before: map[int]int{1: 1, 4: 1}, + after: map[int]int{1: 1}, + count: 4, + }, { + del: key.Path{key.New("foo")}, + expected: false, + visit: key.Path{key.New("foo")}, + before: map[int]int{1: 1}, + after: map[int]int{1: 1}, + count: 4, + }, { + del: key.Path{Wildcard}, + expected: true, + visit: key.Path{key.New("foo")}, before: map[int]int{1: 1}, after: map[int]int{}, count: 3, }, { - del: Path{key.New("*")}, + del: key.Path{Wildcard}, expected: false, - visit: Path{key.New("foo")}, + visit: key.Path{key.New("foo")}, before: map[int]int{}, after: map[int]int{}, count: 3, }, { - del: Path{key.New("foo"), key.New("*")}, + del: key.Path{key.New("foo"), Wildcard}, expected: true, - visit: Path{key.New("foo"), key.New("bar")}, + visit: key.Path{key.New("foo"), key.New("bar")}, before: map[int]int{3: 1}, after: map[int]int{}, count: 1, // Should have deleted "foo" and "bar" nodes }, { - del: Path{}, + del: key.Path{}, expected: true, - visit: Path{}, + visit: key.Path{}, before: map[int]int{0: 1}, after: map[int]int{}, count: 1, // Root node can't be deleted @@ -238,53 +271,102 @@ func TestDelete(t *testing.T) { } } -func TestVisitPrefix(t *testing.T) { - m := NewMap() - m.Set(Path{}, 0) - m.Set(Path{key.New("foo")}, 1) - m.Set(Path{key.New("foo"), key.New("bar")}, 2) - m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz")}, 3) - m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz"), key.New("quux")}, 4) - m.Set(Path{key.New("quux"), key.New("bar")}, 5) - m.Set(Path{key.New("foo"), key.New("quux")}, 6) - m.Set(Path{key.New("*")}, 7) - m.Set(Path{key.New("foo"), key.New("*")}, 8) - m.Set(Path{key.New("*"), key.New("bar")}, 9) - m.Set(Path{key.New("*"), key.New("quux")}, 10) - m.Set(Path{key.New("quux"), key.New("quux"), key.New("quux"), key.New("quux")}, 11) +func TestMapVisitPrefixes(t *testing.T) { + m := Map{} + m.Set(key.Path{}, 0) + m.Set(key.Path{key.New("foo")}, 1) + m.Set(key.Path{key.New("foo"), key.New("bar")}, 2) + m.Set(key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, 3) + m.Set(key.Path{key.New("foo"), key.New("bar"), key.New("baz"), key.New("quux")}, 4) + m.Set(key.Path{key.New("quux"), key.New("bar")}, 5) + m.Set(key.Path{key.New("foo"), key.New("quux")}, 6) + m.Set(key.Path{Wildcard}, 7) + m.Set(key.Path{key.New("foo"), Wildcard}, 8) + m.Set(key.Path{Wildcard, key.New("bar")}, 9) + m.Set(key.Path{Wildcard, key.New("quux")}, 10) + m.Set(key.Path{key.New("quux"), key.New("quux"), key.New("quux"), key.New("quux")}, 11) testCases := []struct { - path Path + path key.Path expected map[int]int }{{ - path: Path{key.New("foo"), key.New("bar"), key.New("baz")}, + path: key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, expected: map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 7: 1, 8: 1, 9: 1}, }, { - path: Path{key.New("zip"), key.New("zap")}, + path: key.Path{key.New("zip"), key.New("zap")}, expected: map[int]int{0: 1, 7: 1}, }, { - path: Path{key.New("foo"), key.New("zap")}, + path: key.Path{key.New("foo"), key.New("zap")}, expected: map[int]int{0: 1, 1: 1, 8: 1, 7: 1}, }, { - path: Path{key.New("quux"), key.New("quux"), key.New("quux")}, + path: key.Path{key.New("quux"), key.New("quux"), key.New("quux")}, expected: map[int]int{0: 1, 7: 1, 10: 1}, }} for _, tc := range testCases { result := make(map[int]int, len(tc.expected)) - m.VisitPrefix(tc.path, accumulator(result)) + m.VisitPrefixes(tc.path, accumulator(result)) if diff := test.Diff(tc.expected, result); diff != "" { t.Errorf("Test case %v: %s", tc.path, diff) } } } -func TestString(t *testing.T) { - m := NewMap() - m.Set(Path{}, 0) - m.Set(Path{key.New("foo"), key.New("bar")}, 1) - m.Set(Path{key.New("foo"), key.New("quux")}, 2) - m.Set(Path{key.New("foo"), key.New("*")}, 3) +func TestMapVisitPrefixed(t *testing.T) { + m := Map{} + m.Set(key.Path{}, 0) + m.Set(key.Path{key.New("qux")}, 1) + m.Set(key.Path{key.New("foo")}, 2) + m.Set(key.Path{key.New("foo"), key.New("qux")}, 3) + m.Set(key.Path{key.New("foo"), key.New("bar")}, 4) + m.Set(key.Path{Wildcard, key.New("bar")}, 5) + m.Set(key.Path{key.New("foo"), Wildcard}, 6) + m.Set(key.Path{key.New("qux"), key.New("foo"), key.New("bar")}, 7) + + testCases := []struct { + in key.Path + out map[int]int + }{{ + in: key.Path{}, + out: map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1}, + }, { + in: key.Path{key.New("qux")}, + out: map[int]int{1: 1, 5: 1, 7: 1}, + }, { + in: key.Path{key.New("foo")}, + out: map[int]int{2: 1, 3: 1, 4: 1, 5: 1, 6: 1}, + }, { + in: key.Path{key.New("foo"), key.New("qux")}, + out: map[int]int{3: 1, 6: 1}, + }, { + in: key.Path{key.New("foo"), key.New("bar")}, + out: map[int]int{4: 1, 5: 1, 6: 1}, + }, { + in: key.Path{key.New(int64(0))}, + out: map[int]int{5: 1}, + }, { + in: key.Path{Wildcard}, + out: map[int]int{5: 1}, + }, { + in: key.Path{Wildcard, Wildcard}, + out: map[int]int{}, + }} + + for _, tc := range testCases { + out := make(map[int]int, len(tc.out)) + m.VisitPrefixed(tc.in, accumulator(out)) + if diff := test.Diff(tc.out, out); diff != "" { + t.Errorf("Test case %v: %s", tc.out, diff) + } + } +} + +func TestMapString(t *testing.T) { + m := Map{} + m.Set(key.Path{}, 0) + m.Set(key.Path{key.New("foo"), key.New("bar")}, 1) + m.Set(key.Path{key.New("foo"), key.New("quux")}, 2) + m.Set(key.Path{key.New("foo"), Wildcard}, 3) expected := `Val: 0 Child "foo": @@ -295,19 +377,19 @@ Child "foo": Child "quux": Val: 2 ` - got := fmt.Sprint(m) + got := fmt.Sprint(&m) if expected != got { t.Errorf("Unexpected string. Expected:\n\n%s\n\nGot:\n\n%s", expected, got) } } -func genWords(count, wordLength int) Path { +func genWords(count, wordLength int) key.Path { chars := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") if count+wordLength > len(chars) { panic("need more chars") } - result := make(Path, count) + result := make(key.Path, count) for i := 0; i < count; i++ { result[i] = key.New(string(chars[i : i+wordLength])) } @@ -315,18 +397,16 @@ func genWords(count, wordLength int) Path { } func benchmarkPathMap(pathLength, pathDepth int, b *testing.B) { - m := NewMap() - // Push pathDepth paths, each of length pathLength path := genWords(pathLength, 10) words := genWords(pathDepth, 10) - n := m.(*node) + m := &Map{} for _, element := range path { - n.children = map[key.Key]*node{} + m.children = map[key.Key]*Map{} for _, word := range words { - n.children[word] = &node{} + m.children[word] = &Map{} } - n = n.children[element] + m = m.children[element] } b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/vendor/github.com/aristanetworks/goarista/path/path.go b/vendor/github.com/aristanetworks/goarista/path/path.go index 2b0ffb28..90d6540a 100644 --- a/vendor/github.com/aristanetworks/goarista/path/path.go +++ b/vendor/github.com/aristanetworks/goarista/path/path.go @@ -2,109 +2,167 @@ // Use of this source code is governed by the Apache License 2.0 // that can be found in the COPYING file. -// Package path provides functionality for dealing with absolute paths elementally. +// Package path contains methods for dealing with key.Paths. package path import ( - "bytes" - "fmt" "strings" "github.com/aristanetworks/goarista/key" ) -// Path is an absolute path broken down into elements where each element is a key.Key. -type Path []key.Key - -func copyElements(path Path, elements ...interface{}) { - for i, element := range elements { - switch val := element.(type) { - case string: - path[i] = key.New(val) - case key.Key: - path[i] = val - default: - panic(fmt.Errorf("unsupported type: %T", element)) - } - } +// New constructs a path from a variable number of elements. +// Each element may either be a key.Key or a value that can +// be wrapped by a key.Key. +func New(elements ...interface{}) key.Path { + result := make(key.Path, len(elements)) + copyElements(result, elements...) + return result } -// New constructs a Path from a variable number of elements. -// Each element may either be a string or a key.Key. -func New(elements ...interface{}) Path { - path := make(Path, len(elements)) - copyElements(path, elements...) - return path -} - -// FromString constructs a Path from the elements resulting -// from a split of the input string by "/". The string MUST -// begin with a '/' character unless it is the empty string -// in which case an empty Path is returned. -func FromString(str string) Path { - if str == "" { - return Path{} - } else if str[0] != '/' { - panic(fmt.Errorf("not an absolute path: %q", str)) - } - elements := strings.Split(str, "/")[1:] - path := make(Path, len(elements)) - for i, element := range elements { - path[i] = key.New(element) - } - return path -} - -// Append appends a variable number of elements to a Path. -// Each element may either be a string or a key.Key. -func Append(path Path, elements ...interface{}) Path { +// Append appends a variable number of elements to a path. +// Each element may either be a key.Key or a value that can +// be wrapped by a key.Key. Note that calling Append on a +// single path returns that same path, whereas in all other +// cases a new path is returned. +func Append(path key.Path, elements ...interface{}) key.Path { if len(elements) == 0 { return path } n := len(path) - p := make(Path, n+len(elements)) - copy(p, path) - copyElements(p[n:], elements...) - return p + result := make(key.Path, n+len(elements)) + copy(result, path) + copyElements(result[n:], elements...) + return result } -// String returns the Path as a string. -func (p Path) String() string { - if len(p) == 0 { - return "" +// Join joins a variable number of paths together. Each path +// in the joining is treated as a subpath of its predecessor. +// Calling Join with no or only empty paths returns nil. +func Join(paths ...key.Path) key.Path { + n := 0 + for _, path := range paths { + n += len(path) } - var buf bytes.Buffer - for _, element := range p { - buf.WriteByte('/') - buf.WriteString(element.String()) + if n == 0 { + return nil } - return buf.String() + result, i := make(key.Path, n), 0 + for _, path := range paths { + i += copy(result[i:], path) + } + return result } -// Equal returns whether the Path contains the same elements as the other Path. -// This method implements key.Comparable. -func (p Path) Equal(other interface{}) bool { - o, ok := other.(Path) - if !ok { - return false +// Parent returns all but the last element of the path. If +// the path is empty, Parent returns nil. +func Parent(path key.Path) key.Path { + if len(path) > 0 { + return path[:len(path)-1] } - if len(o) != len(p) { - return false - } - return o.hasPrefix(p) + return nil } -// HasPrefix returns whether the Path is prefixed by the other Path. -func (p Path) HasPrefix(prefix Path) bool { - if len(prefix) > len(p) { - return false +// Base returns the last element of the path. If the path is +// empty, Base returns nil. +func Base(path key.Path) key.Key { + if len(path) > 0 { + return path[len(path)-1] } - return p.hasPrefix(prefix) + return nil } -func (p Path) hasPrefix(prefix Path) bool { - for i := range prefix { - if !prefix[i].Equal(p[i]) { +// Clone returns a new path with the same elements as in the +// provided path. +func Clone(path key.Path) key.Path { + result := make(key.Path, len(path)) + copy(result, path) + return result +} + +// Equal returns whether path a and path b are the same +// length and whether each element in b corresponds to the +// same element in a. +func Equal(a, b key.Path) bool { + return len(a) == len(b) && hasPrefix(a, b) +} + +// HasElement returns whether element b exists in path a. +func HasElement(a key.Path, b key.Key) bool { + for _, element := range a { + if element.Equal(b) { + return true + } + } + return false +} + +// HasPrefix returns whether path b is a prefix of path a. +// It checks that b is at most the length of path a and +// whether each element in b corresponds to the same element +// in a from the first element. +func HasPrefix(a, b key.Path) bool { + return len(a) >= len(b) && hasPrefix(a, b) +} + +// Match returns whether path a and path b are the same +// length and whether each element in b corresponds to the +// same element or a wildcard in a. +func Match(a, b key.Path) bool { + return len(a) == len(b) && matchPrefix(a, b) +} + +// MatchPrefix returns whether path b is a prefix of path a +// where path a may contain wildcards. +// It checks that b is at most the length of path a and +// whether each element in b corresponds to the same element +// or a wildcard in a from the first element. +func MatchPrefix(a, b key.Path) bool { + return len(a) >= len(b) && matchPrefix(a, b) +} + +// FromString constructs a path from the elements resulting +// from a split of the input string by "/". Strings that do +// not lead with a '/' are accepted but not reconstructable +// with key.Path.String. Both "" and "/" are treated as a +// key.Path{}. +func FromString(str string) key.Path { + if str == "" || str == "/" { + return key.Path{} + } else if str[0] == '/' { + str = str[1:] + } + elements := strings.Split(str, "/") + result := make(key.Path, len(elements)) + for i, element := range elements { + result[i] = key.New(element) + } + return result +} + +func copyElements(dest key.Path, elements ...interface{}) { + for i, element := range elements { + switch val := element.(type) { + case key.Key: + dest[i] = val + default: + dest[i] = key.New(val) + } + } +} + +func hasPrefix(a, b key.Path) bool { + for i := range b { + if !b[i].Equal(a[i]) { + return false + } + } + return true +} + +func matchPrefix(a, b key.Path) bool { + for i := range b { + if !a[i].Equal(Wildcard) && !b[i].Equal(a[i]) { return false } } diff --git a/vendor/github.com/aristanetworks/goarista/path/path_test.go b/vendor/github.com/aristanetworks/goarista/path/path_test.go index 86eb6ae0..17d84a47 100644 --- a/vendor/github.com/aristanetworks/goarista/path/path_test.go +++ b/vendor/github.com/aristanetworks/goarista/path/path_test.go @@ -12,79 +12,179 @@ import ( "github.com/aristanetworks/goarista/value" ) -func TestNewPath(t *testing.T) { +func TestNew(t *testing.T) { tcases := []struct { in []interface{} - out Path + out key.Path }{ { in: nil, - out: nil, + out: key.Path{}, }, { in: []interface{}{}, - out: Path{}, + out: key.Path{}, }, { - in: []interface{}{""}, - out: Path{key.New("")}, + in: []interface{}{"foo", key.New("bar"), true}, + out: key.Path{key.New("foo"), key.New("bar"), key.New(true)}, }, { - in: []interface{}{key.New("")}, - out: Path{key.New("")}, + in: []interface{}{int8(5), int16(5), int32(5), int64(5)}, + out: key.Path{key.New(int8(5)), key.New(int16(5)), key.New(int32(5)), + key.New(int64(5))}, }, { - in: []interface{}{"foo"}, - out: Path{key.New("foo")}, + in: []interface{}{uint8(5), uint16(5), uint32(5), uint64(5)}, + out: key.Path{key.New(uint8(5)), key.New(uint16(5)), key.New(uint32(5)), + key.New(uint64(5))}, }, { - in: []interface{}{key.New("foo")}, - out: Path{key.New("foo")}, + in: []interface{}{float32(5), float64(5)}, + out: key.Path{key.New(float32(5)), key.New(float64(5))}, }, { - in: []interface{}{"foo", key.New("bar")}, - out: Path{key.New("foo"), key.New("bar")}, - }, { - in: []interface{}{key.New("foo"), "bar", key.New("baz")}, - out: Path{key.New("foo"), key.New("bar"), key.New("baz")}, + in: []interface{}{customKey{i: &a}, map[string]interface{}{}}, + out: key.Path{key.New(customKey{i: &a}), key.New(map[string]interface{}{})}, }, } for i, tcase := range tcases { - if p := New(tcase.in...); !p.Equal(tcase.out) { + if p := New(tcase.in...); !Equal(p, tcase.out) { t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.out) } } } -func TestAppendPath(t *testing.T) { +func TestClone(t *testing.T) { + if !Equal(Clone(key.Path{}), key.Path{}) { + t.Error("Clone(key.Path{}) != key.Path{}") + } + a := key.Path{key.New("foo"), key.New("bar")} + b, c := Clone(a), Clone(a) + b[1] = key.New("baz") + if Equal(a, b) || !Equal(a, c) { + t.Error("Clone is not making a copied path") + } +} + +func TestAppend(t *testing.T) { tcases := []struct { - base Path - elements []interface{} - expected Path + a key.Path + b []interface{} + result key.Path }{ { - base: Path{}, - elements: []interface{}{}, - expected: Path{}, + a: key.Path{}, + b: []interface{}{}, + result: key.Path{}, }, { - base: Path{}, - elements: []interface{}{""}, - expected: Path{key.New("")}, + a: key.Path{key.New("foo")}, + b: []interface{}{}, + result: key.Path{key.New("foo")}, }, { - base: Path{}, - elements: []interface{}{key.New("")}, - expected: Path{key.New("")}, + a: key.Path{}, + b: []interface{}{"foo", key.New("bar")}, + result: key.Path{key.New("foo"), key.New("bar")}, }, { - base: Path{}, - elements: []interface{}{"foo", key.New("bar")}, - expected: Path{key.New("foo"), key.New("bar")}, - }, { - base: Path{key.New("foo")}, - elements: []interface{}{key.New("bar"), "baz"}, - expected: Path{key.New("foo"), key.New("bar"), key.New("baz")}, - }, { - base: Path{key.New("foo"), key.New("bar")}, - elements: []interface{}{key.New("baz")}, - expected: Path{key.New("foo"), key.New("bar"), key.New("baz")}, + a: key.Path{key.New("foo")}, + b: []interface{}{int64(0), key.New("bar")}, + result: key.Path{key.New("foo"), key.New(int64(0)), key.New("bar")}, }, } for i, tcase := range tcases { - if p := Append(tcase.base, tcase.elements...); !p.Equal(tcase.expected) { - t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.expected) + if p := Append(tcase.a, tcase.b...); !Equal(p, tcase.result) { + t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.result) + } + } +} + +func TestJoin(t *testing.T) { + tcases := []struct { + paths []key.Path + result key.Path + }{ + { + paths: nil, + result: nil, + }, { + paths: []key.Path{}, + result: nil, + }, { + paths: []key.Path{key.Path{}}, + result: nil, + }, { + paths: []key.Path{key.Path{key.New(true)}, key.Path{}}, + result: key.Path{key.New(true)}, + }, { + paths: []key.Path{key.Path{}, key.Path{key.New(true)}}, + result: key.Path{key.New(true)}, + }, { + paths: []key.Path{key.Path{key.New("foo")}, key.Path{key.New("bar")}}, + result: key.Path{key.New("foo"), key.New("bar")}, + }, { + paths: []key.Path{key.Path{key.New("bar")}, key.Path{key.New("foo")}}, + result: key.Path{key.New("bar"), key.New("foo")}, + }, { + paths: []key.Path{ + key.Path{key.New(uint32(0)), key.New(uint64(0))}, + key.Path{key.New(int8(0))}, + key.Path{key.New(int16(0)), key.New(int32(0))}, + key.Path{key.New(int64(0)), key.New(uint8(0)), key.New(uint16(0))}, + }, + result: key.Path{ + key.New(uint32(0)), key.New(uint64(0)), + key.New(int8(0)), key.New(int16(0)), + key.New(int32(0)), key.New(int64(0)), + key.New(uint8(0)), key.New(uint16(0)), + }, + }, + } + for i, tcase := range tcases { + if p := Join(tcase.paths...); !Equal(p, tcase.result) { + t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.result) + } + } +} + +func TestParent(t *testing.T) { + if Parent(key.Path{}) != nil { + t.Fatal("Parent of empty key.Path should be nil") + } + tcases := []struct { + in key.Path + out key.Path + }{ + { + in: key.Path{key.New("foo")}, + out: key.Path{}, + }, { + in: key.Path{key.New("foo"), key.New("bar")}, + out: key.Path{key.New("foo")}, + }, { + in: key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, + out: key.Path{key.New("foo"), key.New("bar")}, + }, + } + for _, tcase := range tcases { + if !Equal(Parent(tcase.in), tcase.out) { + t.Fatalf("Parent of %#v != %#v", tcase.in, tcase.out) + } + } +} + +func TestBase(t *testing.T) { + if Base(key.Path{}) != nil { + t.Fatal("Base of empty key.Path should be nil") + } + tcases := []struct { + in key.Path + out key.Key + }{ + { + in: key.Path{key.New("foo")}, + out: key.New("foo"), + }, { + in: key.Path{key.New("foo"), key.New("bar")}, + out: key.New("bar"), + }, + } + for _, tcase := range tcases { + if !Base(tcase.in).Equal(tcase.out) { + t.Fatalf("Base of %#v != %#v", tcase.in, tcase.out) } } } @@ -117,176 +217,407 @@ var ( b = 1 ) -func TestPathEquality(t *testing.T) { +func TestEqual(t *testing.T) { tcases := []struct { - base Path - other Path - expected bool + a key.Path + b key.Path + result bool }{ { - base: Path{}, - other: Path{}, - expected: true, + a: nil, + b: nil, + result: true, }, { - base: Path{}, - other: Path{key.New("")}, - expected: false, + a: nil, + b: key.Path{}, + result: true, }, { - base: Path{key.New("foo")}, - other: Path{key.New("foo")}, - expected: true, + a: key.Path{}, + b: nil, + result: true, }, { - base: Path{key.New("foo")}, - other: Path{key.New("bar")}, - expected: false, + a: key.Path{}, + b: key.Path{}, + result: true, }, { - base: Path{key.New("foo"), key.New("bar")}, - other: Path{key.New("foo")}, - expected: false, + a: key.Path{}, + b: key.Path{key.New("")}, + result: false, }, { - base: Path{key.New("foo"), key.New("bar")}, - other: Path{key.New("bar"), key.New("foo")}, - expected: false, + a: key.Path{Wildcard}, + b: key.Path{key.New("foo")}, + result: false, }, { - base: Path{key.New("foo"), key.New("bar"), key.New("baz")}, - other: Path{key.New("foo"), key.New("bar"), key.New("baz")}, - expected: true, + a: key.Path{Wildcard}, + b: key.Path{Wildcard}, + result: true, + }, { + a: key.Path{key.New("foo")}, + b: key.Path{key.New("foo")}, + result: true, + }, { + a: key.Path{key.New(true)}, + b: key.Path{key.New(false)}, + result: false, + }, { + a: key.Path{key.New(int32(5))}, + b: key.Path{key.New(int64(5))}, + result: false, + }, { + a: key.Path{key.New("foo")}, + b: key.Path{key.New("foo"), key.New("bar")}, + result: false, + }, { + a: key.Path{key.New("foo"), key.New("bar")}, + b: key.Path{key.New("foo")}, + result: false, + }, { + a: key.Path{key.New(uint8(0)), key.New(int8(0))}, + b: key.Path{key.New(int8(0)), key.New(uint8(0))}, + result: false, }, // Ensure that we check deep equality. { - base: Path{key.New(map[string]interface{}{})}, - other: Path{key.New(map[string]interface{}{})}, - expected: true, + a: key.Path{key.New(map[string]interface{}{})}, + b: key.Path{key.New(map[string]interface{}{})}, + result: true, }, { - base: Path{key.New(customKey{i: &a})}, - other: Path{key.New(customKey{i: &b})}, - expected: true, + a: key.Path{key.New(customKey{i: &a})}, + b: key.Path{key.New(customKey{i: &b})}, + result: true, }, } for i, tcase := range tcases { - if result := tcase.base.Equal(tcase.other); result != tcase.expected { - t.Fatalf("Test %d failed: base: %#v; other: %#v, expected: %t", - i, tcase.base, tcase.other, tcase.expected) + if result := Equal(tcase.a, tcase.b); result != tcase.result { + t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t", + i, tcase.a, tcase.b, tcase.result) } } } -func TestPathHasPrefix(t *testing.T) { +func TestMatch(t *testing.T) { tcases := []struct { - base Path - prefix Path - expected bool + a key.Path + b key.Path + result bool }{ { - base: Path{}, - prefix: Path{}, - expected: true, + a: nil, + b: nil, + result: true, }, { - base: Path{key.New("foo")}, - prefix: Path{}, - expected: true, + a: nil, + b: key.Path{}, + result: true, }, { - base: Path{key.New("foo"), key.New("bar")}, - prefix: Path{key.New("foo")}, - expected: true, + a: key.Path{}, + b: nil, + result: true, }, { - base: Path{key.New("foo"), key.New("bar")}, - prefix: Path{key.New("bar")}, - expected: false, + a: key.Path{}, + b: key.Path{}, + result: true, }, { - base: Path{key.New("foo"), key.New("bar")}, - prefix: Path{key.New("bar"), key.New("foo")}, - expected: false, + a: key.Path{}, + b: key.Path{key.New("foo")}, + result: false, }, { - base: Path{key.New("foo"), key.New("bar")}, - prefix: Path{key.New("foo"), key.New("bar")}, - expected: true, + a: key.Path{Wildcard}, + b: key.Path{key.New("foo")}, + result: true, }, { - base: Path{key.New("foo"), key.New("bar")}, - prefix: Path{key.New("foo"), key.New("bar"), key.New("baz")}, - expected: false, + a: key.Path{key.New("foo")}, + b: key.Path{Wildcard}, + result: false, + }, { + a: key.Path{Wildcard}, + b: key.Path{key.New("foo"), key.New("bar")}, + result: false, + }, { + a: key.Path{Wildcard, Wildcard}, + b: key.Path{key.New(int64(0))}, + result: false, + }, { + a: key.Path{Wildcard, Wildcard}, + b: key.Path{key.New(int64(0)), key.New(int32(0))}, + result: true, + }, { + a: key.Path{Wildcard, key.New(false)}, + b: key.Path{key.New(true), Wildcard}, + result: false, }, } for i, tcase := range tcases { - if result := tcase.base.HasPrefix(tcase.prefix); result != tcase.expected { - t.Fatalf("Test %d failed: base: %#v; prefix: %#v, expected: %t", - i, tcase.base, tcase.prefix, tcase.expected) + if result := Match(tcase.a, tcase.b); result != tcase.result { + t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t", + i, tcase.a, tcase.b, tcase.result) } } } -func TestPathFromString(t *testing.T) { +func TestHasElement(t *testing.T) { + tcases := []struct { + a key.Path + b key.Key + result bool + }{ + { + a: nil, + b: nil, + result: false, + }, { + a: nil, + b: key.New("foo"), + result: false, + }, { + a: key.Path{}, + b: nil, + result: false, + }, { + a: key.Path{key.New("foo")}, + b: nil, + result: false, + }, { + a: key.Path{key.New("foo")}, + b: key.New("foo"), + result: true, + }, { + a: key.Path{key.New(true)}, + b: key.New("true"), + result: false, + }, { + a: key.Path{key.New("foo"), key.New("bar")}, + b: key.New("bar"), + result: true, + }, { + a: key.Path{key.New(map[string]interface{}{})}, + b: key.New(map[string]interface{}{}), + result: true, + }, { + a: key.Path{key.New(map[string]interface{}{"foo": "a"})}, + b: key.New(map[string]interface{}{"bar": "a"}), + result: false, + }, + } + for i, tcase := range tcases { + if result := HasElement(tcase.a, tcase.b); result != tcase.result { + t.Errorf("Test %d failed: a: %#v; b: %#v, result: %t, expected: %t", + i, tcase.a, tcase.b, result, tcase.result) + } + } +} + +func TestHasPrefix(t *testing.T) { + tcases := []struct { + a key.Path + b key.Path + result bool + }{ + { + a: nil, + b: nil, + result: true, + }, { + a: nil, + b: key.Path{}, + result: true, + }, { + a: key.Path{}, + b: nil, + result: true, + }, { + a: key.Path{}, + b: key.Path{}, + result: true, + }, { + a: key.Path{}, + b: key.Path{key.New("foo")}, + result: false, + }, { + a: key.Path{key.New("foo")}, + b: key.Path{}, + result: true, + }, { + a: key.Path{key.New(true)}, + b: key.Path{key.New(false)}, + result: false, + }, { + a: key.Path{key.New("foo"), key.New("bar")}, + b: key.Path{key.New("bar"), key.New("foo")}, + result: false, + }, { + a: key.Path{key.New(int8(0)), key.New(uint8(0))}, + b: key.Path{key.New(uint8(0)), key.New(uint8(0))}, + result: false, + }, { + a: key.Path{key.New(true), key.New(true)}, + b: key.Path{key.New(true), key.New(true), key.New(true)}, + result: false, + }, { + a: key.Path{key.New(true), key.New(true), key.New(true)}, + b: key.Path{key.New(true), key.New(true)}, + result: true, + }, { + a: key.Path{Wildcard, key.New(int32(0)), Wildcard}, + b: key.Path{key.New(int64(0)), Wildcard}, + result: false, + }, + } + for i, tcase := range tcases { + if result := HasPrefix(tcase.a, tcase.b); result != tcase.result { + t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t", + i, tcase.a, tcase.b, tcase.result) + } + } +} + +func TestMatchPrefix(t *testing.T) { + tcases := []struct { + a key.Path + b key.Path + result bool + }{ + { + a: nil, + b: nil, + result: true, + }, { + a: nil, + b: key.Path{}, + result: true, + }, { + a: key.Path{}, + b: nil, + result: true, + }, { + a: key.Path{}, + b: key.Path{}, + result: true, + }, { + a: key.Path{}, + b: key.Path{key.New("foo")}, + result: false, + }, { + a: key.Path{key.New("foo")}, + b: key.Path{}, + result: true, + }, { + a: key.Path{key.New("foo")}, + b: key.Path{Wildcard}, + result: false, + }, { + a: key.Path{Wildcard}, + b: key.Path{key.New("foo")}, + result: true, + }, { + a: key.Path{Wildcard}, + b: key.Path{key.New("foo"), key.New("bar")}, + result: false, + }, { + a: key.Path{Wildcard, key.New(true)}, + b: key.Path{key.New(false), Wildcard}, + result: false, + }, { + a: key.Path{Wildcard, key.New(int32(0)), key.New(int16(0))}, + b: key.Path{key.New(int64(0)), key.New(int32(0))}, + result: true, + }, + } + for i, tcase := range tcases { + if result := MatchPrefix(tcase.a, tcase.b); result != tcase.result { + t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t", + i, tcase.a, tcase.b, tcase.result) + } + } +} + +func TestFromString(t *testing.T) { tcases := []struct { in string - out Path + out key.Path }{ { in: "", - out: Path{}, + out: key.Path{}, }, { in: "/", - out: Path{key.New("")}, + out: key.Path{}, }, { in: "//", - out: Path{key.New(""), key.New("")}, + out: key.Path{key.New(""), key.New("")}, + }, { + in: "foo", + out: key.Path{key.New("foo")}, }, { in: "/foo", - out: Path{key.New("foo")}, + out: key.Path{key.New("foo")}, + }, { + in: "foo/bar", + out: key.Path{key.New("foo"), key.New("bar")}, }, { in: "/foo/bar", - out: Path{key.New("foo"), key.New("bar")}, + out: key.Path{key.New("foo"), key.New("bar")}, + }, { + in: "foo/bar/baz", + out: key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, }, { in: "/foo/bar/baz", - out: Path{key.New("foo"), key.New("bar"), key.New("baz")}, + out: key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, + }, { + in: "0/123/456/789", + out: key.Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")}, }, { in: "/0/123/456/789", - out: Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")}, + out: key.Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")}, + }, { + in: "`~!@#$%^&*()_+{}\\/|[];':\"<>?,./", + out: key.Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")}, }, { in: "/`~!@#$%^&*()_+{}\\/|[];':\"<>?,./", - out: Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")}, + out: key.Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")}, }, } for i, tcase := range tcases { - if p := FromString(tcase.in); !p.Equal(tcase.out) { + if p := FromString(tcase.in); !Equal(p, tcase.out) { t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.out) } } } -func TestPathToString(t *testing.T) { +func TestString(t *testing.T) { tcases := []struct { - in Path + in key.Path out string }{ { - in: Path{}, - out: "", - }, { - in: Path{key.New("")}, + in: key.Path{}, out: "/", }, { - in: Path{key.New("foo")}, + in: key.Path{key.New("")}, + out: "/", + }, { + in: key.Path{key.New("foo")}, out: "/foo", }, { - in: Path{key.New("foo"), key.New("bar")}, + in: key.Path{key.New("foo"), key.New("bar")}, out: "/foo/bar", }, { - in: Path{key.New("/foo"), key.New("bar")}, + in: key.Path{key.New("/foo"), key.New("bar")}, out: "//foo/bar", }, { - in: Path{key.New("foo"), key.New("bar/")}, + in: key.Path{key.New("foo"), key.New("bar/")}, out: "/foo/bar/", }, { - in: Path{key.New(""), key.New("foo"), key.New("bar")}, + in: key.Path{key.New(""), key.New("foo"), key.New("bar")}, out: "//foo/bar", }, { - in: Path{key.New("foo"), key.New("bar"), key.New("")}, + in: key.Path{key.New("foo"), key.New("bar"), key.New("")}, out: "/foo/bar/", }, { - in: Path{key.New("/"), key.New("foo"), key.New("bar")}, + in: key.Path{key.New("/"), key.New("foo"), key.New("bar")}, out: "///foo/bar", }, { - in: Path{key.New("foo"), key.New("bar"), key.New("/")}, + in: key.Path{key.New("foo"), key.New("bar"), key.New("/")}, out: "/foo/bar//", }, } @@ -296,3 +627,59 @@ func TestPathToString(t *testing.T) { } } } + +func BenchmarkJoin(b *testing.B) { + generate := func(n int) []key.Path { + paths := make([]key.Path, 0, n) + for i := 0; i < n; i++ { + paths = append(paths, key.Path{key.New("foo")}) + } + return paths + } + benchmarks := map[string][]key.Path{ + "10 key.Paths": generate(10), + "100 key.Paths": generate(100), + "1000 key.Paths": generate(1000), + "10000 key.Paths": generate(10000), + } + for name, benchmark := range benchmarks { + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + Join(benchmark...) + } + }) + } +} + +func BenchmarkHasElement(b *testing.B) { + element := key.New("waldo") + generate := func(n, loc int) key.Path { + path := make(key.Path, n) + for i := 0; i < n; i++ { + if i == loc { + path[i] = element + } else { + path[i] = key.New(int8(0)) + } + } + return path + } + benchmarks := map[string]key.Path{ + "10 Elements Index 0": generate(10, 0), + "10 Elements Index 4": generate(10, 4), + "10 Elements Index 9": generate(10, 9), + "100 Elements Index 0": generate(100, 0), + "100 Elements Index 49": generate(100, 49), + "100 Elements Index 99": generate(100, 99), + "1000 Elements Index 0": generate(1000, 0), + "1000 Elements Index 499": generate(1000, 499), + "1000 Elements Index 999": generate(1000, 999), + } + for name, benchmark := range benchmarks { + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + HasElement(benchmark, element) + } + }) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/path/wildcard.go b/vendor/github.com/aristanetworks/goarista/path/wildcard.go new file mode 100644 index 00000000..78099756 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/path/wildcard.go @@ -0,0 +1,36 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package path + +import "github.com/aristanetworks/goarista/key" + +// Wildcard is a special element in a path that is used by Map +// and the Match* functions to match any other element. +var Wildcard = key.New(WildcardType{}) + +// WildcardType is the type used to construct a Wildcard. It +// implements the value.Value interface so it can be used as +// a key.Key. +type WildcardType struct{} + +func (w WildcardType) String() string { + return "*" +} + +// Equal implements the key.Comparable interface. +func (w WildcardType) Equal(other interface{}) bool { + _, ok := other.(WildcardType) + return ok +} + +// ToBuiltin implements the value.Value interface. +func (w WildcardType) ToBuiltin() interface{} { + return WildcardType{} +} + +// MarshalJSON implements the value.Value interface. +func (w WildcardType) MarshalJSON() ([]byte, error) { + return []byte(`{"_wildcard":{}}`), nil +} diff --git a/vendor/github.com/aristanetworks/goarista/path/wildcard_test.go b/vendor/github.com/aristanetworks/goarista/path/wildcard_test.go new file mode 100644 index 00000000..3bebb3b2 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/path/wildcard_test.go @@ -0,0 +1,79 @@ +// Copyright (c) 2018 Arista Networks, Inc. +// Use of this source code is governed by the Apache License 2.0 +// that can be found in the COPYING file. + +package path + +import ( + "encoding/json" + "testing" + + "github.com/aristanetworks/goarista/key" + "github.com/aristanetworks/goarista/value" +) + +type pseudoWildcard struct{} + +func (w pseudoWildcard) Key() interface{} { + return struct{}{} +} + +func (w pseudoWildcard) String() string { + return "*" +} + +func (w pseudoWildcard) Equal(other interface{}) bool { + o, ok := other.(pseudoWildcard) + return ok && w == o +} + +func TestWildcardUniqueness(t *testing.T) { + if Wildcard.Equal(pseudoWildcard{}) { + t.Fatal("Wildcard is not unique") + } + if Wildcard.Equal(struct{}{}) { + t.Fatal("Wildcard is not unique") + } + if Wildcard.Equal(key.New("*")) { + t.Fatal("Wildcard is not unique") + } +} + +func TestWildcardTypeIsNotAKey(t *testing.T) { + var intf interface{} = WildcardType{} + _, ok := intf.(key.Key) + if ok { + t.Error("WildcardType should not implement key.Key") + } +} + +func TestWildcardTypeEqual(t *testing.T) { + k1 := key.New(WildcardType{}) + k2 := key.New(WildcardType{}) + if !k1.Equal(k2) { + t.Error("They should be equal") + } + if !Wildcard.Equal(k1) { + t.Error("They should be equal") + } +} + +func TestWildcardTypeAsValue(t *testing.T) { + var k value.Value = WildcardType{} + w := WildcardType{} + if k.ToBuiltin() != w { + t.Error("WildcardType.ToBuiltin is not correct") + } +} + +func TestWildcardMarshalJSON(t *testing.T) { + b, err := json.Marshal(Wildcard) + if err != nil { + t.Fatal(err) + } + expected := `{"_wildcard":{}}` + if string(b) != expected { + t.Errorf("Invalid Wildcard json representation.\nExpected: %s\nReceived: %s", + expected, string(b)) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/pathmap/pathmap.go b/vendor/github.com/aristanetworks/goarista/pathmap/pathmap.go deleted file mode 100644 index c6e620b3..00000000 --- a/vendor/github.com/aristanetworks/goarista/pathmap/pathmap.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) 2016 Arista Networks, Inc. -// Use of this source code is governed by the Apache License 2.0 -// that can be found in the COPYING file. - -package pathmap - -import ( - "bytes" - "fmt" - "sort" -) - -// PathMap associates Paths to a values. It allows wildcards. The -// primary use of PathMap is to be able to register handlers to paths -// that can be efficiently looked up every time a path is updated. -// -// For example: -// -// m.Set({"interfaces", "*", "adminStatus"}, AdminStatusHandler) -// m.Set({"interface", "Management1", "adminStatus"}, Management1AdminStatusHandler) -// -// m.Visit({"interfaces", "Ethernet3/32/1", "adminStatus"}, HandlerExecutor) -// >> AdminStatusHandler gets passed to HandlerExecutor -// m.Visit({"interfaces", "Management1", "adminStatus"}, HandlerExecutor) -// >> AdminStatusHandler and Management1AdminStatusHandler gets passed to HandlerExecutor -// -// Note, Visit performance is typically linearly with the length of -// the path. But, it can be as bad as O(2^len(Path)) when TreeMap -// nodes have children and a wildcard associated with it. For example, -// if these paths were registered: -// -// m.Set([]string{"foo", "bar", "baz"}, 1) -// m.Set([]string{"*", "bar", "baz"}, 2) -// m.Set([]string{"*", "*", "baz"}, 3) -// m.Set([]string{"*", "*", "*"}, 4) -// m.Set([]string{"foo", "*", "*"}, 5) -// m.Set([]string{"foo", "bar", "*"}, 6) -// m.Set([]string{"foo", "*", "baz"}, 7) -// m.Set([]string{"*", "bar", "*"}, 8) -// -// m.Visit([]{"foo","bar","baz"}, Foo) // 2^3 nodes traversed -// -// This shouldn't be a concern with our paths because it is likely -// that a TreeMap node will either have a wildcard or children, not -// both. A TreeMap node that corresponds to a collection will often be a -// wildcard, otherwise it will have specific children. -type PathMap interface { - // Visit calls f for every registration in the PathMap that - // matches path. For example, - // - // m.Set({"foo", "bar"}, 1) - // m.Set({"*", "bar"}, 2) - // - // m.Visit({"foo", "bar"}, Printer) - // >> Calls Printer(1) and Printer(2) - Visit(path []string, f VisitorFunc) error - - // VisitPrefix calls f for every registration in the PathMap that - // is a prefix of path. For example, - // - // m.Set({}, 0) - // m.Set({"foo"}, 1) - // m.Set({"foo", "bar"}, 2) - // m.Set({"foo", "quux"}, 3) - // m.Set({"*", "bar"}, 4) - // - // m.VisitPrefix({"foo", "bar", "baz"}, Printer) - // >> Calls Printer on values 0, 1, 2, and 4 - VisitPrefix(path []string, f VisitorFunc) error - - // Get returns the mapping for path. This returns the exact - // mapping for path. For example, if you register two paths - // - // m.Set({"foo", "bar"}, 1) - // m.Set({"*", "bar"}, 2) - // - // m.Get({"foo", "bar"}) => 1 - // m.Get({"*", "bar"}) => 2 - Get(path []string) interface{} - - // Set a mapping of path to value. Path may contain wildcards. Set - // replaces what was there before. - Set(path []string, v interface{}) - - // Delete removes the mapping for path - Delete(path []string) bool -} - -// Wildcard is a special string representing any possible path -const Wildcard string = "*" - -type node struct { - val interface{} - wildcard *node - children map[string]*node -} - -// New creates a new PathMap -func New() PathMap { - return &node{} -} - -// VisitorFunc is the func type passed to Visit -type VisitorFunc func(v interface{}) error - -// Visit calls f for every matching registration in the PathMap -func (n *node) Visit(path []string, f VisitorFunc) error { - for i, element := range path { - if n.wildcard != nil { - if err := n.wildcard.Visit(path[i+1:], f); err != nil { - return err - } - } - next, ok := n.children[element] - if !ok { - return nil - } - n = next - } - if n.val == nil { - return nil - } - return f(n.val) -} - -// VisitPrefix calls f for every registered path that is a prefix of -// the path -func (n *node) VisitPrefix(path []string, f VisitorFunc) error { - for i, element := range path { - // Call f on each node we visit - if n.val != nil { - if err := f(n.val); err != nil { - return err - } - } - if n.wildcard != nil { - if err := n.wildcard.VisitPrefix(path[i+1:], f); err != nil { - return err - } - } - next, ok := n.children[element] - if !ok { - return nil - } - n = next - } - if n.val == nil { - return nil - } - // Call f on the final node - return f(n.val) -} - -// Get returns the mapping for path -func (n *node) Get(path []string) interface{} { - for _, element := range path { - if element == Wildcard { - if n.wildcard == nil { - return nil - } - n = n.wildcard - continue - } - next, ok := n.children[element] - if !ok { - return nil - } - n = next - } - return n.val -} - -// Set a mapping of path to value. Path may contain wildcards. Set -// replaces what was there before. -func (n *node) Set(path []string, v interface{}) { - for _, element := range path { - if element == Wildcard { - if n.wildcard == nil { - n.wildcard = &node{} - } - n = n.wildcard - continue - } - if n.children == nil { - n.children = map[string]*node{} - } - next, ok := n.children[element] - if !ok { - next = &node{} - n.children[element] = next - } - n = next - } - n.val = v -} - -// Delete removes the mapping for path -func (n *node) Delete(path []string) bool { - nodes := make([]*node, len(path)+1) - for i, element := range path { - nodes[i] = n - if element == Wildcard { - if n.wildcard == nil { - return false - } - n = n.wildcard - continue - } - next, ok := n.children[element] - if !ok { - return false - } - n = next - } - n.val = nil - nodes[len(path)] = n - - // See if we can delete any node objects - for i := len(path); i > 0; i-- { - n = nodes[i] - if n.val != nil || n.wildcard != nil || len(n.children) > 0 { - break - } - parent := nodes[i-1] - element := path[i-1] - if element == Wildcard { - parent.wildcard = nil - } else { - delete(parent.children, element) - } - - } - return true -} - -func (n *node) String() string { - var b bytes.Buffer - n.write(&b, "") - return b.String() -} - -func (n *node) write(b *bytes.Buffer, indent string) { - if n.val != nil { - b.WriteString(indent) - fmt.Fprintf(b, "Val: %v", n.val) - b.WriteString("\n") - } - if n.wildcard != nil { - b.WriteString(indent) - fmt.Fprintf(b, "Child %q:\n", Wildcard) - n.wildcard.write(b, indent+" ") - } - children := make([]string, 0, len(n.children)) - for name := range n.children { - children = append(children, name) - } - sort.Strings(children) - - for _, name := range children { - child := n.children[name] - b.WriteString(indent) - fmt.Fprintf(b, "Child %q:\n", name) - child.write(b, indent+" ") - } -} diff --git a/vendor/github.com/aristanetworks/goarista/pathmap/pathmap_test.go b/vendor/github.com/aristanetworks/goarista/pathmap/pathmap_test.go deleted file mode 100644 index 9ef6ea01..00000000 --- a/vendor/github.com/aristanetworks/goarista/pathmap/pathmap_test.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright (c) 2016 Arista Networks, Inc. -// Use of this source code is governed by the Apache License 2.0 -// that can be found in the COPYING file. - -package pathmap - -import ( - "errors" - "fmt" - "testing" - - "github.com/aristanetworks/goarista/test" -) - -func accumulator(counter map[int]int) VisitorFunc { - return func(val interface{}) error { - counter[val.(int)]++ - return nil - } -} - -func TestVisit(t *testing.T) { - m := New() - m.Set([]string{"foo", "bar", "baz"}, 1) - m.Set([]string{"*", "bar", "baz"}, 2) - m.Set([]string{"*", "*", "baz"}, 3) - m.Set([]string{"*", "*", "*"}, 4) - m.Set([]string{"foo", "*", "*"}, 5) - m.Set([]string{"foo", "bar", "*"}, 6) - m.Set([]string{"foo", "*", "baz"}, 7) - m.Set([]string{"*", "bar", "*"}, 8) - - m.Set([]string{}, 10) - - m.Set([]string{"*"}, 20) - m.Set([]string{"foo"}, 21) - - m.Set([]string{"zap", "zip"}, 30) - m.Set([]string{"zap", "zip"}, 31) - - m.Set([]string{"zip", "*"}, 40) - m.Set([]string{"zip", "*"}, 41) - - testCases := []struct { - path []string - expected map[int]int - }{{ - path: []string{"foo", "bar", "baz"}, - expected: map[int]int{1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, - }, { - path: []string{"qux", "bar", "baz"}, - expected: map[int]int{2: 1, 3: 1, 4: 1, 8: 1}, - }, { - path: []string{"foo", "qux", "baz"}, - expected: map[int]int{3: 1, 4: 1, 5: 1, 7: 1}, - }, { - path: []string{"foo", "bar", "qux"}, - expected: map[int]int{4: 1, 5: 1, 6: 1, 8: 1}, - }, { - path: []string{}, - expected: map[int]int{10: 1}, - }, { - path: []string{"foo"}, - expected: map[int]int{20: 1, 21: 1}, - }, { - path: []string{"foo", "bar"}, - expected: map[int]int{}, - }, { - path: []string{"zap", "zip"}, - expected: map[int]int{31: 1}, - }, { - path: []string{"zip", "zap"}, - expected: map[int]int{41: 1}, - }} - - for _, tc := range testCases { - result := make(map[int]int, len(tc.expected)) - m.Visit(tc.path, accumulator(result)) - if diff := test.Diff(tc.expected, result); diff != "" { - t.Errorf("Test case %v: %s", tc.path, diff) - } - } -} - -func TestVisitError(t *testing.T) { - m := New() - m.Set([]string{"foo", "bar"}, 1) - m.Set([]string{"*", "bar"}, 2) - - errTest := errors.New("Test") - - err := m.Visit([]string{"foo", "bar"}, func(v interface{}) error { return errTest }) - if err != errTest { - t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err) - } - err = m.VisitPrefix([]string{"foo", "bar", "baz"}, func(v interface{}) error { return errTest }) - if err != errTest { - t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err) - } -} - -func TestGet(t *testing.T) { - m := New() - m.Set([]string{}, 0) - m.Set([]string{"foo", "bar"}, 1) - m.Set([]string{"foo", "*"}, 2) - m.Set([]string{"*", "bar"}, 3) - m.Set([]string{"zap", "zip"}, 4) - - testCases := []struct { - path []string - expected interface{} - }{{ - path: []string{}, - expected: 0, - }, { - path: []string{"foo", "bar"}, - expected: 1, - }, { - path: []string{"foo", "*"}, - expected: 2, - }, { - path: []string{"*", "bar"}, - expected: 3, - }, { - path: []string{"bar", "foo"}, - expected: nil, - }, { - path: []string{"zap", "*"}, - expected: nil, - }} - - for _, tc := range testCases { - got := m.Get(tc.path) - if got != tc.expected { - t.Errorf("Test case %v: Expected %v, Got %v", - tc.path, tc.expected, got) - } - } -} - -func countNodes(n *node) int { - if n == nil { - return 0 - } - count := 1 - count += countNodes(n.wildcard) - for _, child := range n.children { - count += countNodes(child) - } - return count -} - -func TestDelete(t *testing.T) { - m := New() - m.Set([]string{}, 0) - m.Set([]string{"*"}, 1) - m.Set([]string{"foo", "bar"}, 2) - m.Set([]string{"foo", "*"}, 3) - - n := countNodes(m.(*node)) - if n != 5 { - t.Errorf("Initial count wrong. Expected: 5, Got: %d", n) - } - - testCases := []struct { - del []string // Path to delete - expected bool // expected return value of Delete - visit []string // Path to Visit - before map[int]int // Expected to find items before deletion - after map[int]int // Expected to find items after deletion - count int // Count of nodes - }{{ - del: []string{"zap"}, // A no-op Delete - expected: false, - visit: []string{"foo", "bar"}, - before: map[int]int{2: 1, 3: 1}, - after: map[int]int{2: 1, 3: 1}, - count: 5, - }, { - del: []string{"foo", "bar"}, - expected: true, - visit: []string{"foo", "bar"}, - before: map[int]int{2: 1, 3: 1}, - after: map[int]int{3: 1}, - count: 4, - }, { - del: []string{"*"}, - expected: true, - visit: []string{"foo"}, - before: map[int]int{1: 1}, - after: map[int]int{}, - count: 3, - }, { - del: []string{"*"}, - expected: false, - visit: []string{"foo"}, - before: map[int]int{}, - after: map[int]int{}, - count: 3, - }, { - del: []string{"foo", "*"}, - expected: true, - visit: []string{"foo", "bar"}, - before: map[int]int{3: 1}, - after: map[int]int{}, - count: 1, // Should have deleted "foo" and "bar" nodes - }, { - del: []string{}, - expected: true, - visit: []string{}, - before: map[int]int{0: 1}, - after: map[int]int{}, - count: 1, // Root node can't be deleted - }} - - for i, tc := range testCases { - beforeResult := make(map[int]int, len(tc.before)) - m.Visit(tc.visit, accumulator(beforeResult)) - if diff := test.Diff(tc.before, beforeResult); diff != "" { - t.Errorf("Test case %d (%v): %s", i, tc.del, diff) - } - - if got := m.Delete(tc.del); got != tc.expected { - t.Errorf("Test case %d (%v): Unexpected return. Expected %t, Got: %t", - i, tc.del, tc.expected, got) - } - - afterResult := make(map[int]int, len(tc.after)) - m.Visit(tc.visit, accumulator(afterResult)) - if diff := test.Diff(tc.after, afterResult); diff != "" { - t.Errorf("Test case %d (%v): %s", i, tc.del, diff) - } - } -} - -func TestVisitPrefix(t *testing.T) { - m := New() - m.Set([]string{}, 0) - m.Set([]string{"foo"}, 1) - m.Set([]string{"foo", "bar"}, 2) - m.Set([]string{"foo", "bar", "baz"}, 3) - m.Set([]string{"foo", "bar", "baz", "quux"}, 4) - m.Set([]string{"quux", "bar"}, 5) - m.Set([]string{"foo", "quux"}, 6) - m.Set([]string{"*"}, 7) - m.Set([]string{"foo", "*"}, 8) - m.Set([]string{"*", "bar"}, 9) - m.Set([]string{"*", "quux"}, 10) - m.Set([]string{"quux", "quux", "quux", "quux"}, 11) - - testCases := []struct { - path []string - expected map[int]int - }{{ - path: []string{"foo", "bar", "baz"}, - expected: map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 7: 1, 8: 1, 9: 1}, - }, { - path: []string{"zip", "zap"}, - expected: map[int]int{0: 1, 7: 1}, - }, { - path: []string{"foo", "zap"}, - expected: map[int]int{0: 1, 1: 1, 8: 1, 7: 1}, - }, { - path: []string{"quux", "quux", "quux"}, - expected: map[int]int{0: 1, 7: 1, 10: 1}, - }} - - for _, tc := range testCases { - result := make(map[int]int, len(tc.expected)) - m.VisitPrefix(tc.path, accumulator(result)) - if diff := test.Diff(tc.expected, result); diff != "" { - t.Errorf("Test case %v: %s", tc.path, diff) - } - } -} - -func TestString(t *testing.T) { - m := New() - m.Set([]string{}, 0) - m.Set([]string{"foo", "bar"}, 1) - m.Set([]string{"foo", "quux"}, 2) - m.Set([]string{"foo", "*"}, 3) - - expected := `Val: 0 -Child "foo": - Child "*": - Val: 3 - Child "bar": - Val: 1 - Child "quux": - Val: 2 -` - got := fmt.Sprint(m) - - if expected != got { - t.Errorf("Unexpected string. Expected:\n\n%s\n\nGot:\n\n%s", expected, got) - } -} - -func genWords(count, wordLength int) []string { - chars := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - if count+wordLength > len(chars) { - panic("need more chars") - } - result := make([]string, count) - for i := 0; i < count; i++ { - result[i] = string(chars[i : i+wordLength]) - } - return result -} - -func benchmarkPathMap(pathLength, pathDepth int, b *testing.B) { - m := New() - - // Push pathDepth paths, each of length pathLength - path := genWords(pathLength, 10) - words := genWords(pathDepth, 10) - n := m.(*node) - for _, element := range path { - n.children = map[string]*node{} - for _, word := range words { - n.children[word] = &node{} - } - n = n.children[element] - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - m.Visit(path, func(v interface{}) error { return nil }) - } -} - -func BenchmarkPathMap1x25(b *testing.B) { benchmarkPathMap(1, 25, b) } -func BenchmarkPathMap10x50(b *testing.B) { benchmarkPathMap(10, 25, b) } -func BenchmarkPathMap20x50(b *testing.B) { benchmarkPathMap(20, 25, b) } diff --git a/vendor/github.com/aristanetworks/goarista/sizeof/sizeof.go b/vendor/github.com/aristanetworks/goarista/sizeof/sizeof.go new file mode 100644 index 00000000..413b642d --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/sizeof/sizeof.go @@ -0,0 +1,387 @@ +// Copyright (c) 2017 Arista Networks, Inc. All rights reserved. +// Arista Networks, Inc. Confidential and Proprietary. +// Subject to Arista Networks, Inc.'s EULA. +// FOR INTERNAL USE ONLY. NOT FOR DISTRIBUTION. + +package sizeof + +import ( + "errors" + "reflect" + "unsafe" + + "github.com/aristanetworks/goarista/areflect" +) + +// blocks are used to keep track of which memory areas were already +// been visited. +type block struct { + start uintptr + end uintptr +} + +func (b block) size() uintptr { + return b.end - b.start +} + +// DeepSizeof returns total memory occupied by each type for val. +// The value passed in argument must be a pointer. +func DeepSizeof(val interface{}) (map[string]uintptr, error) { + value := reflect.ValueOf(val) + // We want to force val to be a pointer to the original value, because if we get a copy, we + // can get some pointers that will point back to our original value. + if value.Kind() != reflect.Ptr { + return nil, errors.New("cannot get the deep size of a non-pointer value") + } + m := make(map[string]uintptr) + ptrsTypes := make(map[uintptr]map[string]struct{}) + sizeof(value.Elem(), m, ptrsTypes, false, block{start: uintptr(value.Pointer())}, nil) + return m, nil +} + +// Check if curBlock overlap tmpBlock +func isOverlapping(curBlock, tmpBlock block) bool { + return curBlock.start <= tmpBlock.end && tmpBlock.start <= curBlock.end +} + +func getOverlappingBlocks(curBlock block, seen []block) ([]block, int) { + var tmp []block + for idx, a := range seen { + if a.start > curBlock.end { + return tmp, idx + } + if isOverlapping(curBlock, a) { + tmp = append(tmp, a) + } + } + return tmp, len(seen) +} + +func insertBlock(curBlock block, idxToInsert int, seen []block) []block { + seen = append(seen, block{}) + copy(seen[idxToInsert+1:], seen[idxToInsert:]) + seen[idxToInsert] = curBlock + return seen +} + +// get the size of our current block that is not overlapping other blocks. +func getUnseenSizeOfCurrentBlock(curBlock block, overlappingBlocks []block) uintptr { + var size uintptr + for idx, a := range overlappingBlocks { + if idx == 0 && curBlock.start < a.start { + size += a.start - curBlock.start + } + if idx == len(overlappingBlocks)-1 { + if curBlock.end > a.end { + size += curBlock.end - a.end + } + } else { + size += overlappingBlocks[idx+1].start - a.end + } + } + return size +} + +func updateSeenBlocks(curBlock block, seen []block) ([]block, uintptr) { + if len(seen) == 0 { + return []block{curBlock}, curBlock.size() + } + overlappingBlocks, idx := getOverlappingBlocks(curBlock, seen) + if len(overlappingBlocks) == 0 { + // No overlap, so we will insert our new block in our list. + return insertBlock(curBlock, idx, seen), curBlock.size() + } + unseenSize := getUnseenSizeOfCurrentBlock(curBlock, overlappingBlocks) + idxFirstOverlappingBlock := idx - len(overlappingBlocks) + firstOverlappingBlock := &seen[idxFirstOverlappingBlock] + lastOverlappingBlock := seen[idx-1] + if firstOverlappingBlock.start > curBlock.start { + firstOverlappingBlock.start = curBlock.start + } + if lastOverlappingBlock.end < curBlock.end { + firstOverlappingBlock.end = curBlock.end + } else { + firstOverlappingBlock.end = lastOverlappingBlock.end + } + tailLen := len(seen[idx:]) + copy(seen[idxFirstOverlappingBlock+1:], seen[idx:]) + return seen[:idxFirstOverlappingBlock+1+tailLen], unseenSize +} + +// Check if this current block is already fully contained in our list of seen blocks +func isKnownBlock(curBlock block, seen []block) bool { + for _, a := range seen { + if a.start <= curBlock.start && + a.end >= curBlock.end { + // curBlock is fully contained in an other block + // that we already know + return true + } + if a.start > curBlock.start { + // Our slice of seens block is order by pointer address. + // That means, if curBlock was not contained in a previous known + // block, there is no need to continue. + return false + } + } + return false +} + +func sizeof(v reflect.Value, m map[string]uintptr, ptrsTypes map[uintptr]map[string]struct{}, + counted bool, curBlock block, seen []block) []block { + if !v.IsValid() { + return seen + } + vn := v.Type().String() + vs := v.Type().Size() + curBlock.end = vs + curBlock.start + if counted { + // already accounted for the size (field in struct, in array, etc) + vs = 0 + } + if curBlock.start != 0 { + // A pointer can point to the same memory area than a previous pointer, + // but its type should be different (see tests struct_5 and struct_6). + if types, ok := ptrsTypes[curBlock.start]; ok { + if _, ok := types[vn]; ok { + return seen + } + types[vn] = struct{}{} + } else { + ptrsTypes[curBlock.start] = make(map[string]struct{}) + } + if isKnownBlock(curBlock, seen) { + // we don't want to count this size if we have a known block + vs = 0 + } else { + var tmpVs uintptr + seen, tmpVs = updateSeenBlocks(curBlock, seen) + if !counted { + vs = tmpVs + } + } + } + switch v.Kind() { + case reflect.Interface: + seen = sizeof(v.Elem(), m, ptrsTypes, false, block{}, seen) + case reflect.Ptr: + if v.IsNil() { + break + } + seen = sizeof(v.Elem(), m, ptrsTypes, false, block{start: uintptr(v.Pointer())}, seen) + case reflect.Array: + // get size of all elements in the array in case there are pointers + l := v.Len() + for i := 0; i < l; i++ { + seen = sizeof(v.Index(i), m, ptrsTypes, true, block{}, seen) + } + case reflect.Slice: + // get size of all elements in the slice in case there are pointers + // TODO: count elements that are not accessible after reslicing + l := v.Len() + vLen := v.Type().Elem().Size() + for i := 0; i < l; i++ { + e := v.Index(i) + eStart := uintptr(e.UnsafeAddr()) + eBlock := block{ + start: eStart, + end: eStart + vLen, + } + if !isKnownBlock(eBlock, seen) { + vs += vLen + seen = sizeof(e, m, ptrsTypes, true, eBlock, seen) + } + } + capStart := uintptr(v.Pointer()) + (v.Type().Elem().Size() * uintptr(v.Len())) + capEnd := uintptr(v.Pointer()) + (v.Type().Elem().Size() * uintptr(v.Cap())) + capBlock := block{start: capStart, end: capEnd} + if isKnownBlock(capBlock, seen) { + break + } + var tmpSize uintptr + seen, tmpSize = updateSeenBlocks(capBlock, seen) + vs += tmpSize + case reflect.Map: + if v.IsNil() { + break + } + var tmpSize uintptr + if tmpSize, seen = sizeofmap(v, seen); tmpSize == 0 { + // we saw this map + break + } + vs += tmpSize + for _, k := range v.MapKeys() { + kv := v.MapIndex(k) + seen = sizeof(k, m, ptrsTypes, true, block{}, seen) + seen = sizeof(kv, m, ptrsTypes, true, block{}, seen) + } + case reflect.Struct: + for i, n := 0, v.NumField(); i < n; i++ { + vf := areflect.ForceExport(v.Field(i)) + seen = sizeof(vf, m, ptrsTypes, true, block{}, seen) + } + case reflect.String: + str := v.String() + strHdr := (*reflect.StringHeader)(unsafe.Pointer(&str)) + tmpSize := uintptr(strHdr.Len) + strBlock := block{start: strHdr.Data, end: strHdr.Data + tmpSize} + if isKnownBlock(strBlock, seen) { + break + } + seen, tmpSize = updateSeenBlocks(strBlock, seen) + vs += tmpSize + case reflect.Chan: + var tmpSize uintptr + tmpSize, seen = sizeofChan(v, m, ptrsTypes, seen) + vs += tmpSize + } + if vs != 0 { + m[vn] += vs + } + return seen +} + +//go:linkname typesByString reflect.typesByString +func typesByString(s string) []unsafe.Pointer + +func sizeofmap(v reflect.Value, seen []block) (uintptr, []block) { + // get field typ *rtype of our Value v and store it in an interface + var ti interface{} = v.Type() + tp := (*unsafe.Pointer)(unsafe.Pointer(&ti)) + // we know that this pointer rtype point at the begining of struct + // mapType defined in /go/src/reflect/type.go, so we can change the underlying + // type of the interface to be a pointer to runtime.maptype because it as the + // exact same definition as reflect.mapType. + *tp = typesByString("*runtime.maptype")[0] + maptypev := reflect.ValueOf(ti) + maptypev = reflect.Indirect(maptypev) + // now we can access field bucketsize in struct maptype + bucketsize := maptypev.FieldByName("bucketsize").Uint() + // get hmap + var m interface{} = v.Interface() + hmap := (*unsafe.Pointer)(unsafe.Pointer(&m)) + *hmap = typesByString("*runtime.hmap")[0] + + hmapv := reflect.ValueOf(m) + // account for the size of the hmap, buckets and oldbuckets + hmapv = reflect.Indirect(hmapv) + mapBlock := block{ + start: hmapv.UnsafeAddr(), + end: hmapv.UnsafeAddr() + hmapv.Type().Size(), + } + // is it a map we already saw? + if isKnownBlock(mapBlock, seen) { + return 0, seen + } + seen, _ = updateSeenBlocks(mapBlock, seen) + B := hmapv.FieldByName("B").Uint() + oldbuckets := hmapv.FieldByName("oldbuckets").Pointer() + buckets := hmapv.FieldByName("buckets").Pointer() + noverflow := int16(hmapv.FieldByName("noverflow").Uint()) + nb := 2 + if B == 0 { + nb = 1 + } + size := uint64((nb << B)) * bucketsize + if noverflow != 0 { + size += uint64(noverflow) * bucketsize + } + seen, _ = updateSeenBlocks(block{start: buckets, end: buckets + uintptr(size)}, + seen) + // As defined in /go/src/runtime/hashmap.go in struct hmap, oldbuckets is the + // previous bucket array that is half the size of the current one. We need to + // also take that in consideration since there is still a pointer to this previous bucket. + if oldbuckets != 0 { + tmp := (2 << (B - 1)) * bucketsize + size += tmp + seen, _ = updateSeenBlocks(block{ + start: oldbuckets, + end: oldbuckets + uintptr(tmp), + }, seen) + } + return hmapv.Type().Size() + uintptr(size), seen +} + +func getSliceToChanBuffer(buff unsafe.Pointer, buffLen uint, dataSize uint) []byte { + var slice []byte + sliceHdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice)) + sliceHdr.Len = int(buffLen * dataSize) + sliceHdr.Cap = sliceHdr.Len + sliceHdr.Data = uintptr(buff) + return slice +} + +func sizeofChan(v reflect.Value, m map[string]uintptr, ptrsTypes map[uintptr]map[string]struct{}, + seen []block) (uintptr, []block) { + var c interface{} = v.Interface() + hchan := (*unsafe.Pointer)(unsafe.Pointer(&c)) + *hchan = typesByString("*runtime.hchan")[0] + + hchanv := reflect.ValueOf(c) + hchanv = reflect.Indirect(hchanv) + chanBlock := block{ + start: hchanv.UnsafeAddr(), + end: hchanv.UnsafeAddr() + hchanv.Type().Size(), + } + // is it a chan we already saw? + if isKnownBlock(chanBlock, seen) { + return 0, seen + } + seen, _ = updateSeenBlocks(chanBlock, seen) + elemType := unsafe.Pointer(hchanv.FieldByName("elemtype").Pointer()) + buff := unsafe.Pointer(hchanv.FieldByName("buf").Pointer()) + buffLen := hchanv.FieldByName("dataqsiz").Uint() + elemSize := uint16(hchanv.FieldByName("elemsize").Uint()) + seen, _ = updateSeenBlocks(block{ + start: uintptr(buff), + end: uintptr(buff) + uintptr(buffLen*uint64(elemSize)), + }, seen) + + buffSlice := getSliceToChanBuffer(buff, uint(buffLen), uint(elemSize)) + recvx := hchanv.FieldByName("recvx").Uint() + qcount := hchanv.FieldByName("qcount").Uint() + + var tmp interface{} + eface := (*struct { + typ unsafe.Pointer + ptr unsafe.Pointer + })(unsafe.Pointer(&tmp)) + eface.typ = elemType + for i := uint64(0); buffLen > 0 && i < qcount; i++ { + idx := (recvx + i) % buffLen + // get the pointer to the data inside the chan buffer. + elem := unsafe.Pointer(&buffSlice[uint64(elemSize)*idx]) + eface.ptr = elem + ev := reflect.ValueOf(tmp) + var blk block + k := ev.Kind() + if k == reflect.Ptr || k == reflect.Chan || k == reflect.Map || k == reflect.Func { + // let's say our chan is a chan *whatEver, or chan chan whatEver or + // chan map[whatEver]whatEver. In this case elemType will + // be either of type *whatEver, chan whatEver or map[whatEver]whatEver + // but what we set eface.ptr = elem above, we make it point to a pointer + // to where the data is sotred in the buffer of our channel. + // So the interface tmp would look like: + // chan *whatEver -> (type=*whatEver, ptr=**whatEver) + // chan chan whatEver -> (type= chan whatEver, ptr=*chan whatEver) + // chan map[whatEver]whatEver -> (type= map[whatEver]whatEver{}, + // ptr=*map[whatEver]whatEver) + // So we need to take the ptr which is stored into the buffer and replace + // the ptr to the data of our interface tmp. + ptr := (*unsafe.Pointer)(elem) + eface.ptr = *ptr + ev = reflect.ValueOf(tmp) + ev = reflect.Indirect(ev) + blk.start = uintptr(*ptr) + } + // It seems that when the chan is of type chan *whatEver, the type in eface + // will be whatEver and not *whatEver, but ev.Kind() will be a reflect.ptr. + // So if k is a reflect.Ptr (i.e. a pointer) to a struct, then we want to take + // the size of the struct into account because + // vs := v.Type().Size() will return us the size of the struct and not the size + // of the pointer that is in the channel's buffer. + seen = sizeof(ev, m, ptrsTypes, true && k != reflect.Ptr, blk, seen) + } + return hchanv.Type().Size() + uintptr(uint64(elemSize)*buffLen), seen +} diff --git a/vendor/github.com/aristanetworks/goarista/sizeof/sizeof.s b/vendor/github.com/aristanetworks/goarista/sizeof/sizeof.s new file mode 100644 index 00000000..fa230f48 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/sizeof/sizeof.s @@ -0,0 +1,8 @@ +// Copyright (c) 2017 Arista Networks, Inc. All rights reserved. +// Arista Networks, Inc. Confidential and Proprietary. +// Subject to Arista Networks, Inc.'s EULA. +// FOR INTERNAL USE ONLY. NOT FOR DISTRIBUTION. + +// This file is intentionally empty. +// It's a workaround for https://github.com/golang/go/issues/15006 + diff --git a/vendor/github.com/aristanetworks/goarista/sizeof/sizeof_test.go b/vendor/github.com/aristanetworks/goarista/sizeof/sizeof_test.go new file mode 100644 index 00000000..c93a8826 --- /dev/null +++ b/vendor/github.com/aristanetworks/goarista/sizeof/sizeof_test.go @@ -0,0 +1,573 @@ +// Copyright (c) 2017 Arista Networks, Inc. All rights reserved. +// Arista Networks, Inc. Confidential and Proprietary. +// Subject to Arista Networks, Inc.'s EULA. +// FOR INTERNAL USE ONLY. NOT FOR DISTRIBUTION. + +package sizeof + +import ( + "fmt" + "strconv" + "testing" + "unsafe" + + "github.com/aristanetworks/goarista/test" +) + +type yolo struct { + i int32 + a [3]int8 + p unsafe.Pointer +} + +func (y yolo) String() string { + return "Yolo" +} + +func TestDeepSizeof(t *testing.T) { + ptrSize := uintptr(unsafe.Sizeof(unsafe.Pointer(t))) + // hmapStructSize represent the size of struct hmap defined in + // file /go/src/runtime/hashmap.go + hmapStructSize := uintptr(unsafe.Sizeof(int(0)) + 2*1 + 2 + 4 + + 2*ptrSize + ptrSize + ptrSize) + var alignement uintptr = 4 + if ptrSize == 4 { + alignement = 0 + } + strHdrSize := unsafe.Sizeof("") // int + ptr to data + sliceHdrSize := 3 * ptrSize // ptr to data + 2 * int + + // struct hchan is defined in /go/src/runtime/chan.go + chanHdrSize := 2*ptrSize + ptrSize + 2 + 2 /* padding */ + 4 + ptrSize + 2*ptrSize + + 2*(2*ptrSize) + ptrSize + yoloSize := unsafe.Sizeof(yolo{}) + interfaceSize := 2 * ptrSize + topHashSize := uintptr(8) + tests := map[string]struct { + getStruct func() interface{} + expectedSize uintptr + }{ + "bool": { + getStruct: func() interface{} { + var test bool + return &test + }, + expectedSize: 1, + }, + "int8": { + getStruct: func() interface{} { + test := int8(4) + return &test + }, + expectedSize: 1, + }, + "int16": { + getStruct: func() interface{} { + test := int16(4) + return &test + }, + expectedSize: 2, + }, + "int32": { + getStruct: func() interface{} { + test := int32(4) + return &test + }, + expectedSize: 4, + }, + "int64": { + getStruct: func() interface{} { + test := int64(4) + return &test + }, + expectedSize: 8, + }, + "uint": { + getStruct: func() interface{} { + test := uint(4) + return &test + }, + expectedSize: ptrSize, + }, + "uint8": { + getStruct: func() interface{} { + test := uint8(4) + return &test + }, + expectedSize: 1, + }, + "uint16": { + getStruct: func() interface{} { + test := uint16(4) + return &test + }, + expectedSize: 2, + }, + "uint32": { + getStruct: func() interface{} { + test := uint32(4) + return &test + }, + expectedSize: 4, + }, + "uint64": { + getStruct: func() interface{} { + test := uint64(4) + return &test + }, + expectedSize: 8, + }, + "uintptr": { + getStruct: func() interface{} { + test := uintptr(4) + return &test + }, + expectedSize: ptrSize, + }, + "float32": { + getStruct: func() interface{} { + test := float32(4) + return &test + }, + expectedSize: 4, + }, + "float64": { + getStruct: func() interface{} { + test := float64(4) + return &test + }, + expectedSize: 8, + }, + "complex64": { + getStruct: func() interface{} { + test := complex64(4 + 1i) + return &test + }, + expectedSize: 8, + }, + "complex128": { + getStruct: func() interface{} { + test := complex128(4 + 1i) + return &test + }, + expectedSize: 16, + }, + "string": { + getStruct: func() interface{} { + test := "Hello Dolly!" + return &test + }, + expectedSize: strHdrSize + 12, + }, + "unsafe_Pointer": { + getStruct: func() interface{} { + tmp := uint64(54) + var test unsafe.Pointer + test = unsafe.Pointer(&tmp) + return &test + }, + expectedSize: ptrSize, + }, "rune": { + getStruct: func() interface{} { + test := rune('A') + return &test + }, + expectedSize: 4, + }, "intPtr": { + getStruct: func() interface{} { + test := int(4) + return &test + }, + expectedSize: ptrSize, + }, "FuncPtr": { + getStruct: func() interface{} { + test := TestDeepSizeof + return &test + }, + expectedSize: ptrSize, + }, "struct_1": { + getStruct: func() interface{} { + v := struct { + a uint32 + b *uint32 + c struct { + e [8]byte + d string + } + f string + }{ + a: 10, + c: struct { + e [8]byte + d string + }{ + e: [8]byte{0, 1, 2, 3, 4, 5, 6, 7}, + d: "Hello Test!", + }, + f: "Hello Test!", + } + a := uint32(47) + v.b = &a + return &v + }, + expectedSize: 4 + alignement + ptrSize + 8 + strHdrSize*2 + + 11 /* "Hello Test!" */ + 4, /* uint32(47) */ + }, "struct_2": { + getStruct: func() interface{} { + v := struct { + a []byte + b []byte + c []byte + }{ + c: make([]byte, 32, 64), + } + v.a = v.c[20:32] + v.b = v.c[10:20] + return &v + }, + expectedSize: 3*sliceHdrSize + 64, /*slice capacity*/ + }, "struct_3": { + getStruct: func() interface{} { + type test struct { + a *byte + c []byte + } + tmp := make([]byte, 64, 128) + v := (*test)(unsafe.Pointer(&tmp[16])) + v.c = tmp + v.a = (*byte)(unsafe.Pointer(&tmp[5])) + return v + }, + // we expect to see 128 bytes as struct test is part of the bytes slice + // and field c point to it. + expectedSize: 128, + }, "map_string_interface": { + getStruct: func() interface{} { + return &map[string]interface{}{} + }, + expectedSize: ptrSize + topHashSize + hmapStructSize + + (8*(strHdrSize+interfaceSize) + ptrSize), + }, "map_interface_interface": { + getStruct: func() interface{} { + // All the map will use only one bucket because there is less than 8 + // entries in each map. Also for amd64 and i386 the bucket size is + // computed like in function bucketOf in /go/src/reflect/type.go: + return &map[interface{}]interface{}{ + // 2 + (8 + 4) 386 + // 2 + (16 + 4) amd64 + uint16(123): "yolo", + // (4 + 8) + (4 + 28 + 140) + (4 for SWAG) 386 + // (4 + 16) + (8 + 48 + 272) + (4 for SWAG) amd64 + "meow": map[string]string{"SWAG": "yolo"}, + // (12) + (4 + 12) 386 + // (16) + (8 + 16) amd64 + yolo{i: 523}: &yolo{i: 126}, + // (12) + (12) 386 + // (16) + (16) amd64 + fmt.Stringer(yolo{i: 123}): yolo{i: 234}, + } + }, + // Total + // 386: (4 + 28 + 140) + 2 + (8 + 4) + (4 + 8) + (4 + 28 + 140) + 4 + (12) + + // (4 + 12) + 12 + 12 + // amd64: (8 + 48 + 272) + 2 + (16 + 4) + (4 + 16) + (8 + 48 + 272) + (4) + + // (16) + (8 + 16) + (16) + (16) + expectedSize: (ptrSize + topHashSize + hmapStructSize + + (8*(2*interfaceSize) + ptrSize)) + + (unsafe.Sizeof(uint16(123)) + strHdrSize + 4 /* "yolo" */) + + (strHdrSize + 4 /* "meow" */ + + (ptrSize + hmapStructSize + topHashSize + + (8*(2*strHdrSize) + ptrSize)) /*map[string]string*/ + + 4 /* "SWAG" */) + + (yoloSize /* obj: */ + (ptrSize + yoloSize) /* &obj */) + + yoloSize*2, + }, "struct_4": { + getStruct: func() interface{} { + return &struct { + a map[interface{}]interface{} + c string + d []string + }{ + a: map[interface{}]interface{}{ + uint16(123): "yolo", + "meow": map[string]string{"SWAG": "yolo"}, + yolo{i: 127}: &yolo{i: 124}, + fmt.Stringer(yolo{i: 123}): yolo{i: 234}, + }, // 4 (386) or 8 (amd64) + c: "Hello", // 8 (386) or 16 (amd64) + d: []string{"Bonjour", "Hello", "Hola"}, // 12 (386) or 24 (amd64) + } + }, + // Total + // 386: sizeof(tmp map) + 8(test.c) + 12(test.d) + + // 3 * 8 (strSlice) + 16(len("Bonjour") + len("Hello")...) + // amd64: sizeof(tmp map) + 8 (test.b) + 16(test.c) + 24(test.d) + + // 3 * 16 (strSlice) + 16(len("Bonjour") + len("Hello")...) + expectedSize: (ptrSize + strHdrSize + sliceHdrSize) + (hmapStructSize + + topHashSize + (8*(2*2*ptrSize /* interface size */) + ptrSize) + + unsafe.Sizeof(uint16(123)) + + strHdrSize + 4 /* "yolo" */ + strHdrSize + 4 /* "meow" */ + + +(ptrSize + hmapStructSize + topHashSize + (8*(2*strHdrSize) + ptrSize) + + 4 /* "SWAG" */) + yoloSize /* obj */ + (ptrSize + yoloSize) /* &obj */ + + yoloSize*2) + 5 /* "Hello" */ + + 3*strHdrSize /*strings in strSlice*/ + 11, /* "Bonjour" + "Hola" */ + }, "chan_int": { + getStruct: func() interface{} { + test := make(chan int) + return &test + }, + // The expected size should be equal to the size of the struct hchan + // defined in /go/src/runtime/chan.go + expectedSize: ptrSize + chanHdrSize, + }, "chan_int_16": { + getStruct: func() interface{} { + test := make(chan int, 16) + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*ptrSize, + }, "chan_yoloPtr_16": { + getStruct: func() interface{} { + test := make(chan *yolo, 16) + for i := 0; i < 16; i++ { + tmp := &yolo{ + i: int32(i), + } + tmp.p = unsafe.Pointer(&tmp.i) + test <- tmp + } + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*(ptrSize+yoloSize), + }, "struct_5": { + getStruct: func() interface{} { + tmp := make([]byte, 32) + test := struct { + a []byte + b **uint32 + }{ + a: tmp, + } + bob := uint32(42) + ptrInt := (*uintptr)(unsafe.Pointer(&tmp[0])) + *ptrInt = uintptr(unsafe.Pointer(&bob)) + test.b = (**uint32)(unsafe.Pointer(&tmp[0])) + return &test + }, + expectedSize: sliceHdrSize + ptrSize + 32 + 4, + }, "struct_6": { + getStruct: func() interface{} { + type A struct { + a uintptr + b *yolo + } + type B struct { + a *A + b uintptr + } + tmp := make([]byte, 32) + test := struct { + a []byte + b *B + }{ + a: tmp, + } + y := yolo{i: 42} + test.b = (*B)(unsafe.Pointer(&tmp[0])) + test.b.a = (*A)(unsafe.Pointer(&tmp[0])) + test.b.a.b = &y + return &test + }, + expectedSize: sliceHdrSize + ptrSize + 32 + yoloSize, + }, "chan_chan_int_16": { + getStruct: func() interface{} { + test := make(chan chan int, 16) + for i := 0; i < 16; i++ { + tmp := make(chan int) + test <- tmp + } + return &test + }, + expectedSize: ptrSize + chanHdrSize*17 + 16*ptrSize, + }, "chan_yolo_16": { + getStruct: func() interface{} { + test := make(chan yolo, 16) + for i := 0; i < 16; i++ { + tmp := yolo{ + i: int32(i), + } + test <- tmp + } + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*yoloSize, + }, "chan_map_string_interface_16)": { + getStruct: func() interface{} { + test := make(chan map[string]interface{}, 16) + for i := 0; i < 16; i++ { + tmp := make(map[string]interface{}) + test <- tmp + } + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*(ptrSize+hmapStructSize+ + (8*(1+strHdrSize+interfaceSize)+ptrSize)), + }, "chan_unsafe_Pointer_16": { + getStruct: func() interface{} { + test := make(chan unsafe.Pointer, 16) + for i := 0; i < 16; i++ { + var a int + ptrToA := (unsafe.Pointer)(unsafe.Pointer(&a)) + test <- ptrToA + } + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*ptrSize, + }, "chan_[]int_16": { + getStruct: func() interface{} { + test := make(chan []int, 16) + for i := 0; i < 8; i++ { + intSlice := make([]int, 16) + test <- intSlice + } + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*sliceHdrSize + 8*16*ptrSize, + }, "chan_func": { + getStruct: func() interface{} { + test := make(chan func(), 16) + f := func() { + fmt.Printf("Hello!") + } + for i := 0; i < 8; i++ { + test <- f + } + return &test + }, + expectedSize: ptrSize + chanHdrSize + 16*ptrSize, + }, + } + + for key, tcase := range tests { + t.Run(key, func(t *testing.T) { + v := tcase.getStruct() + m, err := DeepSizeof(v) + if err != nil { + t.Fatal(err) + } + var totalSize uintptr + for _, size := range m { + totalSize += size + } + expectedSize := tcase.expectedSize + if totalSize != expectedSize { + t.Fatalf("Expected size: %v, but got %v", expectedSize, totalSize) + } + }) + } +} + +func TestUpdateSeenAreas(t *testing.T) { + tests := []struct { + seen []block + expectedSeen []block + expectedSize uintptr + update block + }{{ + seen: []block{ + {start: 0x100000, end: 0x100050}, + }, + expectedSeen: []block{ + {start: 0x100000, end: 0x100050}, + {start: 0x100100, end: 0x100150}, + }, + expectedSize: 0x50, + update: block{start: 0x100100, end: 0x100150}, + }, { + seen: []block{ + {start: 0x100000, end: 0x100050}, + }, + expectedSeen: []block{ + {start: 0x100, end: 0x150}, + {start: 0x100000, end: 0x100050}, + }, + expectedSize: 0x50, + update: block{start: 0x100, end: 0x150}, + }, { + seen: []block{ + {start: 0x100000, end: 0x100500}, + }, + expectedSeen: []block{ + {start: 0x100000, end: 0x100750}, + }, + expectedSize: 0x250, + update: block{start: 0x100250, end: 0x100750}, + }, { + seen: []block{ + {start: 0x100250, end: 0x100750}, + }, + expectedSeen: []block{ + {start: 0x100000, end: 0x100750}, + }, + expectedSize: 0x250, + update: block{start: 0x100000, end: 0x100500}, + }, { + seen: []block{ + {start: 0x1000, end: 0x1250}, + {start: 0x1500, end: 0x1750}, + }, + expectedSeen: []block{ + {start: 0x1000, end: 0x1750}, + }, + expectedSize: 0x2B0, + update: block{start: 0x1200, end: 0x1700}, + }, { + seen: []block{ + {start: 0x1000, end: 0x1250}, + {start: 0x1500, end: 0x1750}, + {start: 0x1F50, end: 0x21A0}, + }, + expectedSeen: []block{ + {start: 0xF00, end: 0x1F00}, + {start: 0x1F50, end: 0x21A0}, + }, + expectedSize: 0xB60, + update: block{start: 0xF00, end: 0x1F00}, + }, { + seen: []block{ + {start: 0x1000, end: 0x1250}, + {start: 0x1500, end: 0x1750}, + {start: 0x1F00, end: 0x2150}, + }, + expectedSeen: []block{ + {start: 0xF00, end: 0x2150}, + }, + expectedSize: 0xB60, + update: block{start: 0xF00, end: 0x1F00}, + }, { + seen: []block{ + {start: 0x1000, end: 0x1250}, + {start: 0x1500, end: 0x1750}, + {start: 0x1F00, end: 0x2150}, + }, + expectedSeen: []block{ + {start: 0x1000, end: 0x1750}, + {start: 0x1F00, end: 0x2150}, + }, + expectedSize: 0x2B0, + update: block{start: 0x1250, end: 0x1500}, + }} + + for i, tcase := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + seen, size := updateSeenBlocks(tcase.update, tcase.seen) + if !test.DeepEqual(seen, tcase.expectedSeen) { + t.Fatalf("seen blocks %x for iterration %v are different than the "+ + "one expected:\n %x", seen, i, tcase.expectedSeen) + } + if size != tcase.expectedSize { + t.Fatalf("Size does not match, expected 0x%x got 0x%x", + tcase.expectedSize, size) + } + }) + } +} diff --git a/vendor/github.com/aristanetworks/goarista/test/data_test.go b/vendor/github.com/aristanetworks/goarista/test/data_test.go index 0f35dd01..3cb30f99 100644 --- a/vendor/github.com/aristanetworks/goarista/test/data_test.go +++ b/vendor/github.com/aristanetworks/goarista/test/data_test.go @@ -5,7 +5,6 @@ package test import ( - "regexp" "testing" "github.com/aristanetworks/goarista/key" @@ -357,21 +356,21 @@ func getDeepEqualTests(t *testing.T) []deepEqualTestCase { b: complexCompare{}, }, { a: complexCompare{ - m: map[builtinCompare]int8{builtinCompare{1, "foo"}: 42}}, + m: map[builtinCompare]int8{{1, "foo"}: 42}}, b: complexCompare{ - m: map[builtinCompare]int8{builtinCompare{1, "foo"}: 42}}, + m: map[builtinCompare]int8{{1, "foo"}: 42}}, }, { a: complexCompare{ - m: map[builtinCompare]int8{builtinCompare{1, "foo"}: 42}}, + m: map[builtinCompare]int8{{1, "foo"}: 42}}, b: complexCompare{ - m: map[builtinCompare]int8{builtinCompare{1, "foo"}: 51}}, + m: map[builtinCompare]int8{{1, "foo"}: 51}}, diff: `attributes "m" are different: for key test.builtinCompare{a:uint32(1),` + ` b:"foo"} in map, values are different: int8(42) != int8(51)`, }, { a: complexCompare{ - m: map[builtinCompare]int8{builtinCompare{1, "foo"}: 42}}, + m: map[builtinCompare]int8{{1, "foo"}: 42}}, b: complexCompare{ - m: map[builtinCompare]int8{builtinCompare{1, "bar"}: 42}}, + m: map[builtinCompare]int8{{1, "bar"}: 42}}, diff: `attributes "m" are different: key test.builtinCompare{a:uint32(1),` + ` b:"foo"} in map is missing in the actual map`, }, { @@ -404,16 +403,16 @@ func getDeepEqualTests(t *testing.T) []deepEqualTestCase { a: partialCompare{a: 42, b: "foo"}, b: partialCompare{a: 42, b: "bar"}, }, { - a: map[*builtinCompare]uint32{&builtinCompare{1, "foo"}: 42}, - b: map[*builtinCompare]uint32{&builtinCompare{1, "foo"}: 42}, + a: map[*builtinCompare]uint32{{1, "foo"}: 42}, + b: map[*builtinCompare]uint32{{1, "foo"}: 42}, }, { - a: map[*builtinCompare]uint32{&builtinCompare{1, "foo"}: 42}, - b: map[*builtinCompare]uint32{&builtinCompare{2, "foo"}: 42}, + a: map[*builtinCompare]uint32{{1, "foo"}: 42}, + b: map[*builtinCompare]uint32{{2, "foo"}: 42}, diff: `complex key *test.builtinCompare{a:uint32(1), b:"foo"}` + ` in map is missing in the actual map`, }, { - a: map[*builtinCompare]uint32{&builtinCompare{1, "foo"}: 42}, - b: map[*builtinCompare]uint32{&builtinCompare{1, "foo"}: 51}, + a: map[*builtinCompare]uint32{{1, "foo"}: 42}, + b: map[*builtinCompare]uint32{{1, "foo"}: 51}, diff: `for complex key *test.builtinCompare{a:uint32(1), b:"foo"}` + ` in map, values are different: uint32(42) != uint32(51)`, }, { @@ -436,10 +435,11 @@ func getDeepEqualTests(t *testing.T) []deepEqualTestCase { b: key.New(map[string]interface{}{ "a": map[key.Key]interface{}{key.New(map[string]interface{}{"k": 51}): true}}), diff: `Comparable types are different: ` + - `key.composite{sentinel:uintptr(18379810577513696751), m:map[string]interface {}` + - `{"a":map[key.Key]interface {}{:}}} vs` + - ` key.composite{sentinel:uintptr(18379810577513696751), m:map[string]interface {}` + - `{"a":map[key.Key]interface {}{:}}}`, + `key.compositeKey{sentinel:uintptr(18379810577513696751), m:map[string]interface {}` + + `{"a":map[key.Key]interface {}{:}}, s:[]interface {}{}}` + + ` vs key.compositeKey{sentinel:uintptr(18379810577513696751), ` + + `m:map[string]interface {}{"a":map[key.Key]interface {}` + + `{:}}, s:[]interface {}{}}`, }, { a: code(42), b: code(42), @@ -464,8 +464,5 @@ func getDeepEqualTests(t *testing.T) []deepEqualTestCase { }, { a: embedder{builtinCompare: builtinCompare{}}, b: embedder{builtinCompare: builtinCompare{}}, - }, { - a: regexp.MustCompile("foo.*bar"), - b: regexp.MustCompile("foo.*bar"), }} } diff --git a/vendor/github.com/aristanetworks/goarista/test/fileutil.go b/vendor/github.com/aristanetworks/goarista/test/fileutil.go index b0846a11..f5bd7a78 100644 --- a/vendor/github.com/aristanetworks/goarista/test/fileutil.go +++ b/vendor/github.com/aristanetworks/goarista/test/fileutil.go @@ -6,12 +6,14 @@ package test import ( "io" + "io/ioutil" "os" "testing" ) // CopyFile copies a file func CopyFile(t *testing.T, srcPath, dstPath string) { + t.Helper() src, err := os.Open(srcPath) if err != nil { t.Fatal(err) @@ -27,3 +29,14 @@ func CopyFile(t *testing.T, srcPath, dstPath string) { t.Fatal(err) } } + +// TempDir creates a temporary directory under the default directory for temporary files (see +// os.TempDir) and returns the path of the new directory or fails the test trying. +func TempDir(t *testing.T, dirName string) string { + t.Helper() + tempDir, err := ioutil.TempDir("", dirName) + if err != nil { + t.Fatal(err) + } + return tempDir +} diff --git a/vendor/github.com/aristanetworks/goarista/test/panic.go b/vendor/github.com/aristanetworks/goarista/test/panic.go index ff9504f7..8eb67538 100644 --- a/vendor/github.com/aristanetworks/goarista/test/panic.go +++ b/vendor/github.com/aristanetworks/goarista/test/panic.go @@ -12,7 +12,9 @@ import ( // ShouldPanic will test is a function is panicking func ShouldPanic(t *testing.T, fn func()) { + t.Helper() defer func() { + t.Helper() if r := recover(); r == nil { t.Errorf("%sThe function %p should have panicked", getCallerInfo(), fn) @@ -24,10 +26,12 @@ func ShouldPanic(t *testing.T, fn func()) { // ShouldPanicWith will test is a function is panicking with a specific message func ShouldPanicWith(t *testing.T, msg interface{}, fn func()) { + t.Helper() defer func() { + t.Helper() if r := recover(); r == nil { - t.Errorf("%sThe function %p should have panicked", - getCallerInfo(), fn) + t.Errorf("%sThe function %p should have panicked with %#v", + getCallerInfo(), fn, msg) } else if d := Diff(msg, r); len(d) != 0 { t.Errorf("%sThe function %p panicked with the wrong message.\n"+ "Expected: %#v\nReceived: %#v\nDiff:%s", diff --git a/vendor/github.com/btcsuite/btcd/.travis.yml b/vendor/github.com/btcsuite/btcd/.travis.yml index d0244683..0d4fb385 100644 --- a/vendor/github.com/btcsuite/btcd/.travis.yml +++ b/vendor/github.com/btcsuite/btcd/.travis.yml @@ -1,7 +1,7 @@ language: go go: - - 1.8.x - - 1.9.x + - "1.9.5" + - "1.10.1" sudo: false install: - GLIDE_TAG=v0.12.3 @@ -10,8 +10,8 @@ install: - export PATH=$PATH:$PWD/linux-amd64/ - glide install - go install . ./cmd/... - - go get -v github.com/alecthomas/gometalinter - - gometalinter --install + - go get -u gopkg.in/alecthomas/gometalinter.v2 + - gometalinter.v2 --install script: - export PATH=$PATH:$HOME/gopath/bin - ./goclean.sh diff --git a/vendor/github.com/btcsuite/btcd/CHANGES b/vendor/github.com/btcsuite/btcd/CHANGES index 99b2fc13..6f7013e9 100644 --- a/vendor/github.com/btcsuite/btcd/CHANGES +++ b/vendor/github.com/btcsuite/btcd/CHANGES @@ -570,8 +570,8 @@ Changes in 0.8.0-beta (Sun May 25 2014) - btcctl utility changes: - Add createencryptedwallet command - Add getblockchaininfo command - - Add importwallet commmand - - Add addmultisigaddress commmand + - Add importwallet command + - Add addmultisigaddress command - Add setgenerate command - Accept --testnet and --wallet flags which automatically select the appropriate port and TLS certificates needed to communicate diff --git a/vendor/github.com/btcsuite/btcd/README.md b/vendor/github.com/btcsuite/btcd/README.md index 0e8152a2..72e73a55 100644 --- a/vendor/github.com/btcsuite/btcd/README.md +++ b/vendor/github.com/btcsuite/btcd/README.md @@ -92,7 +92,7 @@ $ go install . ./cmd/... ## Getting Started -btcd has several configuration options avilable to tweak how it runs, but all +btcd has several configuration options available to tweak how it runs, but all of the basic operations described in the intro section work with zero configuration. diff --git a/vendor/github.com/btcsuite/btcd/blockchain/README.md b/vendor/github.com/btcsuite/btcd/blockchain/README.md index 275c2b4f..de5611bc 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/README.md +++ b/vendor/github.com/btcsuite/btcd/blockchain/README.md @@ -63,7 +63,7 @@ is by no means exhaustive: * [ProcessBlock Example](http://godoc.org/github.com/btcsuite/btcd/blockchain#example-BlockChain-ProcessBlock) Demonstrates how to create a new chain instance and use ProcessBlock to - attempt to attempt add a block to the chain. This example intentionally + attempt to add a block to the chain. This example intentionally attempts to insert a duplicate genesis block to illustrate how an invalid block is handled. @@ -73,7 +73,7 @@ is by no means exhaustive: typical hex notation. * [BigToCompact Example](http://godoc.org/github.com/btcsuite/btcd/blockchain#example-BigToCompact) - Demonstrates how to convert how to convert a target difficulty into the + Demonstrates how to convert a target difficulty into the compact "bits" in a block header which represent that target difficulty. ## GPG Verification Key diff --git a/vendor/github.com/btcsuite/btcd/blockchain/accept.go b/vendor/github.com/btcsuite/btcd/blockchain/accept.go index 963a4fd0..f85d6558 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/accept.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/accept.go @@ -54,23 +54,24 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) // such as making blocks that never become part of the main chain or // blocks that fail to connect available for further analysis. err = b.db.Update(func(dbTx database.Tx) error { - return dbMaybeStoreBlock(dbTx, block) + return dbStoreBlock(dbTx, block) }) if err != nil { return false, err } - // Create a new block node for the block and add it to the in-memory - // block chain (could be either a side chain or the main chain). + // Create a new block node for the block and add it to the node index. Even + // if the block ultimately gets connected to the main chain, it starts out + // on a side chain. blockHeader := &block.MsgBlock().Header - newNode := newBlockNode(blockHeader, blockHeight) + newNode := newBlockNode(blockHeader, prevNode) newNode.status = statusDataStored - if prevNode != nil { - newNode.parent = prevNode - newNode.height = blockHeight - newNode.workSum.Add(prevNode.workSum, newNode.workSum) - } + b.index.AddNode(newNode) + err = b.index.flushToDB() + if err != nil { + return false, err + } // Connect the passed block to the chain while respecting proper chain // selection according to the chain with the most proof of work. This diff --git a/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go b/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go index 642b658e..2ff2fa27 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go @@ -101,33 +101,33 @@ type blockNode struct { status blockStatus } -// initBlockNode initializes a block node from the given header and height. The -// node is completely disconnected from the chain and the workSum value is just -// the work for the passed block. The work sum must be updated accordingly when -// the node is inserted into a chain. -// +// initBlockNode initializes a block node from the given header and parent node, +// calculating the height and workSum from the respective fields on the parent. // This function is NOT safe for concurrent access. It must only be called when // initially creating a node. -func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, height int32) { +func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) { *node = blockNode{ hash: blockHeader.BlockHash(), workSum: CalcWork(blockHeader.Bits), - height: height, version: blockHeader.Version, bits: blockHeader.Bits, nonce: blockHeader.Nonce, timestamp: blockHeader.Timestamp.Unix(), merkleRoot: blockHeader.MerkleRoot, } + if parent != nil { + node.parent = parent + node.height = parent.height + 1 + node.workSum = node.workSum.Add(parent.workSum, node.workSum) + } } -// newBlockNode returns a new block node for the given block header. It is -// completely disconnected from the chain and the workSum value is just the work -// for the passed block. The work sum must be updated accordingly when the node -// is inserted into a chain. -func newBlockNode(blockHeader *wire.BlockHeader, height int32) *blockNode { +// newBlockNode returns a new block node for the given block header and parent +// node, calculating the height and workSum from the respective fields on the +// parent. This function is NOT safe for concurrent access. +func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode { var node blockNode - initBlockNode(&node, blockHeader, height) + initBlockNode(&node, blockHeader, parent) return &node } @@ -136,7 +136,7 @@ func newBlockNode(blockHeader *wire.BlockHeader, height int32) *blockNode { // This function is safe for concurrent access. func (node *blockNode) Header() wire.BlockHeader { // No lock is needed because all accessed fields are immutable. - prevHash := zeroHash + prevHash := &zeroHash if node.parent != nil { prevHash = &node.parent.hash } @@ -231,6 +231,7 @@ type blockIndex struct { sync.RWMutex index map[chainhash.Hash]*blockNode + dirty map[*blockNode]struct{} } // newBlockIndex returns a new empty instance of a block index. The index will @@ -241,6 +242,7 @@ func newBlockIndex(db database.DB, chainParams *chaincfg.Params) *blockIndex { db: db, chainParams: chainParams, index: make(map[chainhash.Hash]*blockNode), + dirty: make(map[*blockNode]struct{}), } } @@ -265,16 +267,25 @@ func (bi *blockIndex) LookupNode(hash *chainhash.Hash) *blockNode { return node } -// AddNode adds the provided node to the block index. Duplicate entries are not -// checked so it is up to caller to avoid adding them. +// AddNode adds the provided node to the block index and marks it as dirty. +// Duplicate entries are not checked so it is up to caller to avoid adding them. // // This function is safe for concurrent access. func (bi *blockIndex) AddNode(node *blockNode) { bi.Lock() - bi.index[node.hash] = node + bi.addNode(node) + bi.dirty[node] = struct{}{} bi.Unlock() } +// addNode adds the provided node to the block index, but does not mark it as +// dirty. This can be used while initializing the block index. +// +// This function is NOT safe for concurrent access. +func (bi *blockIndex) addNode(node *blockNode) { + bi.index[node.hash] = node +} + // NodeStatus provides concurrent-safe access to the status field of a node. // // This function is safe for concurrent access. @@ -293,6 +304,7 @@ func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus { func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) { bi.Lock() node.status |= flags + bi.dirty[node] = struct{}{} bi.Unlock() } @@ -303,5 +315,34 @@ func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) { func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) { bi.Lock() node.status &^= flags + bi.dirty[node] = struct{}{} bi.Unlock() } + +// flushToDB writes all dirty block nodes to the database. If all writes +// succeed, this clears the dirty set. +func (bi *blockIndex) flushToDB() error { + bi.Lock() + if len(bi.dirty) == 0 { + bi.Unlock() + return nil + } + + err := bi.db.Update(func(dbTx database.Tx) error { + for node := range bi.dirty { + err := dbStoreBlockNode(dbTx, node) + if err != nil { + return err + } + } + return nil + }) + + // If write was successful, clear the dirty set. + if err == nil { + bi.dirty = make(map[*blockNode]struct{}) + } + + bi.Unlock() + return err +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chain.go b/vendor/github.com/btcsuite/btcd/blockchain/chain.go index bd24b1e1..71c1b2ee 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/chain.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/chain.go @@ -1,4 +1,5 @@ -// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2013-2018 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -399,7 +400,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView nextHeight := node.height + 1 for txInIndex, txIn := range mTx.TxIn { - utxo := utxoView.LookupEntry(&txIn.PreviousOutPoint.Hash) + utxo := utxoView.LookupEntry(txIn.PreviousOutPoint) if utxo == nil { str := fmt.Sprintf("output %v referenced from "+ "transaction %s:%d either does not exist or "+ @@ -495,6 +496,8 @@ func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 { // passed node is the new end of the main chain. The lists will be empty if the // passed node is not on a side chain. // +// This function may modify node statuses in the block index without flushing. +// // This function MUST be called with the chain state lock held (for reads). func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List) { attachNodes := list.New() @@ -544,20 +547,6 @@ func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List return detachNodes, attachNodes } -// dbMaybeStoreBlock stores the provided block in the database if it's not -// already there. -func dbMaybeStoreBlock(dbTx database.Tx, block *btcutil.Block) error { - hasBlock, err := dbTx.HasBlock(block.Hash()) - if err != nil { - return err - } - if hasBlock { - return nil - } - - return dbTx.StoreBlock(block) -} - // connectBlock handles connecting the passed node/block to the end of the main // (best) chain. // @@ -569,7 +558,9 @@ func dbMaybeStoreBlock(dbTx database.Tx, block *btcutil.Block) error { // it would be inefficient to repeat it. // // This function MUST be called with the chain state lock held (for writes). -func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint, stxos []spentTxOut) error { +func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, + view *UtxoViewpoint, stxos []SpentTxOut) error { + // Make sure it's extending the end of the best chain. prevHash := &block.MsgBlock().Header.PrevBlock if !prevHash.IsEqual(&b.bestChain.Tip().hash) { @@ -599,6 +590,12 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *U } } + // Write any block status changes to DB before updating best state. + err := b.index.flushToDB() + if err != nil { + return err + } + // Generate a new best state snapshot that will be used to update the // database and later memory if all database updates are successful. b.stateLock.RLock() @@ -611,7 +608,7 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *U curTotalTxns+numTxns, node.CalcPastMedianTime()) // Atomically insert info into the database. - err := b.db.Update(func(dbTx database.Tx) error { + err = b.db.Update(func(dbTx database.Tx) error { // Update best block state. err := dbPutBestState(dbTx, state, node.workSum) if err != nil { @@ -644,7 +641,7 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *U // optional indexes with the block being connected so they can // update themselves accordingly. if b.indexManager != nil { - err := b.indexManager.ConnectBlock(dbTx, block, view) + err := b.indexManager.ConnectBlock(dbTx, block, stxos) if err != nil { return err } @@ -705,6 +702,12 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view return err } + // Write any block status changes to DB before updating best state. + err = b.index.flushToDB() + if err != nil { + return err + } + // Generate a new best state snapshot that will be used to update the // database and later memory if all database updates are successful. b.stateLock.RLock() @@ -739,8 +742,15 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view return err } + // Before we delete the spend journal entry for this back, + // we'll fetch it as is so the indexers can utilize if needed. + stxos, err := dbFetchSpendJournalEntry(dbTx, block) + if err != nil { + return err + } + // Update the transaction spend journal by removing the record - // that contains all txos spent by the block . + // that contains all txos spent by the block. err = dbRemoveSpendJournalEntry(dbTx, block.Hash()) if err != nil { return err @@ -750,7 +760,7 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view // optional indexes with the block being disconnected so they // can update themselves accordingly. if b.indexManager != nil { - err := b.indexManager.DisconnectBlock(dbTx, block, view) + err := b.indexManager.DisconnectBlock(dbTx, block, stxos) if err != nil { return err } @@ -806,15 +816,49 @@ func countSpentOutputs(block *btcutil.Block) int { // the chain) and nodes the are being attached must be in forwards order // (think pushing them onto the end of the chain). // +// This function may modify node statuses in the block index without flushing. +// // This function MUST be called with the chain state lock held (for writes). func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error { + // Nothing to do if no reorganize nodes were provided. + if detachNodes.Len() == 0 && attachNodes.Len() == 0 { + return nil + } + + // Ensure the provided nodes match the current best chain. + tip := b.bestChain.Tip() + if detachNodes.Len() != 0 { + firstDetachNode := detachNodes.Front().Value.(*blockNode) + if firstDetachNode.hash != tip.hash { + return AssertError(fmt.Sprintf("reorganize nodes to detach are "+ + "not for the current best chain -- first detach node %v, "+ + "current chain %v", &firstDetachNode.hash, &tip.hash)) + } + } + + // Ensure the provided nodes are for the same fork point. + if attachNodes.Len() != 0 && detachNodes.Len() != 0 { + firstAttachNode := attachNodes.Front().Value.(*blockNode) + lastDetachNode := detachNodes.Back().Value.(*blockNode) + if firstAttachNode.parent.hash != lastDetachNode.parent.hash { + return AssertError(fmt.Sprintf("reorganize nodes do not have the "+ + "same fork point -- first attach parent %v, last detach "+ + "parent %v", &firstAttachNode.parent.hash, + &lastDetachNode.parent.hash)) + } + } + + // Track the old and new best chains heads. + oldBest := tip + newBest := tip + // All of the blocks to detach and related spend journal entries needed // to unspend transaction outputs in the blocks being disconnected must // be loaded from the database during the reorg check phase below and // then they are needed again when doing the actual database updates. // Rather than doing two loads, cache the loaded data into these slices. detachBlocks := make([]*btcutil.Block, 0, detachNodes.Len()) - detachSpentTxOuts := make([][]spentTxOut, 0, detachNodes.Len()) + detachSpentTxOuts := make([][]SpentTxOut, 0, detachNodes.Len()) attachBlocks := make([]*btcutil.Block, 0, attachNodes.Len()) // Disconnect all of the blocks back to the point of the fork. This @@ -822,7 +866,7 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // database and using that information to unspend all of the spent txos // and remove the utxos created by the blocks. view := NewUtxoViewpoint() - view.SetBestHash(&b.bestChain.Tip().hash) + view.SetBestHash(&oldBest.hash) for e := detachNodes.Front(); e != nil; e = e.Next() { n := e.Value.(*blockNode) var block *btcutil.Block @@ -834,6 +878,11 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error if err != nil { return err } + if n.hash != *block.Hash() { + return AssertError(fmt.Sprintf("detach block node hash %v (height "+ + "%v) does not match previous parent block hash %v", &n.hash, + n.height, block.Hash())) + } // Load all of the utxos referenced by the block that aren't // already in the view. @@ -844,9 +893,9 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // Load all of the spent txos for the block from the spend // journal. - var stxos []spentTxOut + var stxos []SpentTxOut err = b.db.View(func(dbTx database.Tx) error { - stxos, err = dbFetchSpendJournalEntry(dbTx, block, view) + stxos, err = dbFetchSpendJournalEntry(dbTx, block) return err }) if err != nil { @@ -857,10 +906,19 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error detachBlocks = append(detachBlocks, block) detachSpentTxOuts = append(detachSpentTxOuts, stxos) - err = view.disconnectTransactions(block, stxos) + err = view.disconnectTransactions(b.db, block, stxos) if err != nil { return err } + + newBest = n.parent + } + + // Set the fork point only if there are nodes to attach since otherwise + // blocks are only being disconnected and thus there is no fork point. + var forkNode *blockNode + if attachNodes.Len() > 0 { + forkNode = newBest } // Perform several checks to verify each block that needs to be attached @@ -875,17 +933,9 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // at least a couple of ways accomplish that rollback, but both involve // tweaking the chain and/or database. This approach catches these // issues before ever modifying the chain. - var validationError error for e := attachNodes.Front(); e != nil; e = e.Next() { n := e.Value.(*blockNode) - // If any previous nodes in attachNodes failed validation, - // mark this one as having an invalid ancestor. - if validationError != nil { - b.index.SetStatusFlags(n, statusInvalidAncestor) - continue - } - var block *btcutil.Block err := b.db.View(func(dbTx database.Tx) error { var err error @@ -911,6 +961,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error if err != nil { return err } + + newBest = n continue } @@ -918,23 +970,24 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // thus will not be generated. This is done because the state // is not being immediately written to the database, so it is // not needed. + // + // In the case the block is determined to be invalid due to a + // rule violation, mark it as invalid and mark all of its + // descendants as having an invalid ancestor. err = b.checkConnectBlock(n, block, view, nil) if err != nil { - // If the block failed validation mark it as invalid, then - // continue to loop through remaining nodes, marking them as - // having an invalid ancestor. if _, ok := err.(RuleError); ok { b.index.SetStatusFlags(n, statusValidateFailed) - validationError = err - continue + for de := e.Next(); de != nil; de = de.Next() { + dn := de.Value.(*blockNode) + b.index.SetStatusFlags(dn, statusInvalidAncestor) + } } return err } b.index.SetStatusFlags(n, statusValid) - } - if validationError != nil { - return validationError + newBest = n } // Reset the view for the actual connection code below. This is @@ -959,7 +1012,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // Update the view to unspend all of the spent txos and remove // the utxos created by the block. - err = view.disconnectTransactions(block, detachSpentTxOuts[i]) + err = view.disconnectTransactions(b.db, block, + detachSpentTxOuts[i]) if err != nil { return err } @@ -987,7 +1041,7 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // as spent and add all transactions being created by this block // to it. Also, provide an stxo slice so the spent txout // details are generated. - stxos := make([]spentTxOut, 0, countSpentOutputs(block)) + stxos := make([]SpentTxOut, 0, countSpentOutputs(block)) err = view.connectTransactions(block, &stxos) if err != nil { return err @@ -1002,12 +1056,14 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // Log the point where the chain forked and old and new best chain // heads. - firstAttachNode := attachNodes.Front().Value.(*blockNode) - firstDetachNode := detachNodes.Front().Value.(*blockNode) - lastAttachNode := attachNodes.Back().Value.(*blockNode) - log.Infof("REORGANIZE: Chain forks at %v", firstAttachNode.parent.hash) - log.Infof("REORGANIZE: Old best chain head was %v", firstDetachNode.hash) - log.Infof("REORGANIZE: New best chain head is %v", lastAttachNode.hash) + if forkNode != nil { + log.Infof("REORGANIZE: Chain forks at %v (height %v)", forkNode.hash, + forkNode.height) + } + log.Infof("REORGANIZE: Old best chain head was %v (height %v)", + &oldBest.hash, oldBest.height) + log.Infof("REORGANIZE: New best chain head is %v (height %v)", + newBest.hash, newBest.height) return nil } @@ -1029,6 +1085,17 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) (bool, error) { fastAdd := flags&BFFastAdd == BFFastAdd + flushIndexState := func() { + // Intentionally ignore errors writing updated node status to DB. If + // it fails to write, it's not the end of the world. If the block is + // valid, we flush in connectBlock and if the block is invalid, the + // worst that can happen is we revalidate the block after a restart. + if writeErr := b.index.flushToDB(); writeErr != nil { + log.Warnf("Error flushing block index changes to disk: %v", + writeErr) + } + } + // We are extending the main (best) chain with a new block. This is the // most common case. parentHash := &block.MsgBlock().Header.PrevBlock @@ -1041,16 +1108,22 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla // actually connecting the block. view := NewUtxoViewpoint() view.SetBestHash(parentHash) - stxos := make([]spentTxOut, 0, countSpentOutputs(block)) + stxos := make([]SpentTxOut, 0, countSpentOutputs(block)) if !fastAdd { err := b.checkConnectBlock(node, block, view, &stxos) - if err != nil { - if _, ok := err.(RuleError); ok { - b.index.SetStatusFlags(node, statusValidateFailed) - } + if err == nil { + b.index.SetStatusFlags(node, statusValid) + } else if _, ok := err.(RuleError); ok { + b.index.SetStatusFlags(node, statusValidateFailed) + } else { + return false, err + } + + flushIndexState() + + if err != nil { return false, err } - b.index.SetStatusFlags(node, statusValid) } // In the fast add case the code to check the block connection @@ -1071,9 +1144,28 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla // Connect the block to the main chain. err := b.connectBlock(node, block, view, stxos) if err != nil { + // If we got hit with a rule error, then we'll mark + // that status of the block as invalid and flush the + // index state to disk before returning with the error. + if _, ok := err.(RuleError); ok { + b.index.SetStatusFlags( + node, statusValidateFailed, + ) + } + + flushIndexState() + return false, err } + // If this is fast add, or this block node isn't yet marked as + // valid, then we'll update its status and flush the state to + // disk again. + if fastAdd || !b.index.NodeStatus(node).KnownValid() { + b.index.SetStatusFlags(node, statusValid) + flushIndexState() + } + return true, nil } if fastAdd { @@ -1111,11 +1203,16 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla // Reorganize the chain. log.Infof("REORGANIZE: Block %v is causing a reorganize.", node.hash) err := b.reorganizeChain(detachNodes, attachNodes) - if err != nil { - return false, err + + // Either getReorganizeNodes or reorganizeChain could have made unsaved + // changes to the block index, so flush regardless of whether there was an + // error. The index would only be dirty if the block failed to connect, so + // we can ignore any errors writing. + if writeErr := b.index.flushToDB(); writeErr != nil { + log.Warnf("Error flushing block index changes to disk: %v", writeErr) } - return true, nil + return err == nil, err } // isCurrent returns whether or not the chain believes it is current. Several @@ -1168,25 +1265,17 @@ func (b *BlockChain) BestSnapshot() *BestState { return snapshot } -// FetchHeader returns the block header identified by the given hash or an error -// if it doesn't exist. -func (b *BlockChain) FetchHeader(hash *chainhash.Hash) (wire.BlockHeader, error) { - // Reconstruct the header from the block index if possible. - if node := b.index.LookupNode(hash); node != nil { - return node.Header(), nil - } - - // Fall back to loading it from the database. - var header *wire.BlockHeader - err := b.db.View(func(dbTx database.Tx) error { - var err error - header, err = dbFetchHeaderByHash(dbTx, hash) - return err - }) - if err != nil { +// HeaderByHash returns the block header identified by the given hash or an +// error if it doesn't exist. Note that this will return headers from both the +// main and side chains. +func (b *BlockChain) HeaderByHash(hash *chainhash.Hash) (wire.BlockHeader, error) { + node := b.index.LookupNode(hash) + if node == nil { + err := fmt.Errorf("block %s is not known", hash) return wire.BlockHeader{}, err } - return *header, nil + + return node.Header(), nil } // MainChainHasBlock returns whether or not the block with the given hash is in @@ -1302,6 +1391,87 @@ func (b *BlockChain) HeightRange(startHeight, endHeight int32) ([]chainhash.Hash return hashes, nil } +// HeightToHashRange returns a range of block hashes for the given start height +// and end hash, inclusive on both ends. The hashes are for all blocks that are +// ancestors of endHash with height greater than or equal to startHeight. The +// end hash must belong to a block that is known to be valid. +// +// This function is safe for concurrent access. +func (b *BlockChain) HeightToHashRange(startHeight int32, + endHash *chainhash.Hash, maxResults int) ([]chainhash.Hash, error) { + + endNode := b.index.LookupNode(endHash) + if endNode == nil { + return nil, fmt.Errorf("no known block header with hash %v", endHash) + } + if !b.index.NodeStatus(endNode).KnownValid() { + return nil, fmt.Errorf("block %v is not yet validated", endHash) + } + endHeight := endNode.height + + if startHeight < 0 { + return nil, fmt.Errorf("start height (%d) is below 0", startHeight) + } + if startHeight > endHeight { + return nil, fmt.Errorf("start height (%d) is past end height (%d)", + startHeight, endHeight) + } + + resultsLength := int(endHeight - startHeight + 1) + if resultsLength > maxResults { + return nil, fmt.Errorf("number of results (%d) would exceed max (%d)", + resultsLength, maxResults) + } + + // Walk backwards from endHeight to startHeight, collecting block hashes. + node := endNode + hashes := make([]chainhash.Hash, resultsLength) + for i := resultsLength - 1; i >= 0; i-- { + hashes[i] = node.hash + node = node.parent + } + return hashes, nil +} + +// IntervalBlockHashes returns hashes for all blocks that are ancestors of +// endHash where the block height is a positive multiple of interval. +// +// This function is safe for concurrent access. +func (b *BlockChain) IntervalBlockHashes(endHash *chainhash.Hash, interval int, +) ([]chainhash.Hash, error) { + + endNode := b.index.LookupNode(endHash) + if endNode == nil { + return nil, fmt.Errorf("no known block header with hash %v", endHash) + } + if !b.index.NodeStatus(endNode).KnownValid() { + return nil, fmt.Errorf("block %v is not yet validated", endHash) + } + endHeight := endNode.height + + resultsLength := int(endHeight) / interval + hashes := make([]chainhash.Hash, resultsLength) + + b.bestChain.mtx.Lock() + defer b.bestChain.mtx.Unlock() + + blockNode := endNode + for index := int(endHeight) / interval; index > 0; index-- { + // Use the bestChain chainView for faster lookups once lookup intersects + // the best chain. + blockHeight := int32(index * interval) + if b.bestChain.contains(blockNode) { + blockNode = b.bestChain.nodeByHeight(blockHeight) + } else { + blockNode = blockNode.Ancestor(blockHeight) + } + + hashes[index-1] = blockNode.hash + } + + return hashes, nil +} + // locateInventory returns the node of the block after the first known block in // the locator along with the number of subsequent nodes needed to either reach // the provided stop hash or the provided max number of entries. @@ -1467,12 +1637,16 @@ type IndexManager interface { Init(*BlockChain, <-chan struct{}) error // ConnectBlock is invoked when a new block has been connected to the - // main chain. - ConnectBlock(database.Tx, *btcutil.Block, *UtxoViewpoint) error + // main chain. The set of output spent within a block is also passed in + // so indexers can access the previous output scripts input spent if + // required. + ConnectBlock(database.Tx, *btcutil.Block, []SpentTxOut) error // DisconnectBlock is invoked when a block has been disconnected from - // the main chain. - DisconnectBlock(database.Tx, *btcutil.Block, *UtxoViewpoint) error + // the main chain. The set of outputs scripts that were spent within + // this block is also returned so indexers can clean up the prior index + // state for this block. + DisconnectBlock(database.Tx, *btcutil.Block, []SpentTxOut) error } // Config is a descriptor which specifies the blockchain instance configuration. @@ -1601,6 +1775,11 @@ func New(config *Config) (*BlockChain, error) { return nil, err } + // Perform any upgrades to the various chain-specific buckets as needed. + if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil { + return nil, err + } + // Initialize and catch up all of the currently active optional indexes // as needed. if config.IndexManager != nil { diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chain_test.go b/vendor/github.com/btcsuite/btcd/blockchain/chain_test.go index afb07f9a..7de323bc 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/chain_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/chain_test.go @@ -800,3 +800,167 @@ func TestLocateInventory(t *testing.T) { } } } + +// TestHeightToHashRange ensures that fetching a range of block hashes by start +// height and end hash works as expected. +func TestHeightToHashRange(t *testing.T) { + // Construct a synthetic block chain with a block index consisting of + // the following structure. + // genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18 + // \-> 16a -> 17a -> 18a (unvalidated) + tip := tstTip + chain := newFakeChain(&chaincfg.MainNetParams) + branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18) + branch1Nodes := chainedNodes(branch0Nodes[14], 3) + for _, node := range branch0Nodes { + chain.index.SetStatusFlags(node, statusValid) + chain.index.AddNode(node) + } + for _, node := range branch1Nodes { + if node.height < 18 { + chain.index.SetStatusFlags(node, statusValid) + } + chain.index.AddNode(node) + } + chain.bestChain.SetTip(tip(branch0Nodes)) + + tests := []struct { + name string + startHeight int32 // locator for requested inventory + endHash chainhash.Hash // stop hash for locator + maxResults int // max to locate, 0 = wire const + hashes []chainhash.Hash // expected located hashes + expectError bool + }{ + { + name: "blocks below tip", + startHeight: 11, + endHash: branch0Nodes[14].hash, + maxResults: 10, + hashes: nodeHashes(branch0Nodes, 10, 11, 12, 13, 14), + }, + { + name: "blocks on main chain", + startHeight: 15, + endHash: branch0Nodes[17].hash, + maxResults: 10, + hashes: nodeHashes(branch0Nodes, 14, 15, 16, 17), + }, + { + name: "blocks on stale chain", + startHeight: 15, + endHash: branch1Nodes[1].hash, + maxResults: 10, + hashes: append(nodeHashes(branch0Nodes, 14), + nodeHashes(branch1Nodes, 0, 1)...), + }, + { + name: "invalid start height", + startHeight: 19, + endHash: branch0Nodes[17].hash, + maxResults: 10, + expectError: true, + }, + { + name: "too many results", + startHeight: 1, + endHash: branch0Nodes[17].hash, + maxResults: 10, + expectError: true, + }, + { + name: "unvalidated block", + startHeight: 15, + endHash: branch1Nodes[2].hash, + maxResults: 10, + expectError: true, + }, + } + for _, test := range tests { + hashes, err := chain.HeightToHashRange(test.startHeight, &test.endHash, + test.maxResults) + if err != nil { + if !test.expectError { + t.Errorf("%s: unexpected error: %v", test.name, err) + } + continue + } + + if !reflect.DeepEqual(hashes, test.hashes) { + t.Errorf("%s: unxpected hashes -- got %v, want %v", + test.name, hashes, test.hashes) + } + } +} + +// TestIntervalBlockHashes ensures that fetching block hashes at specified +// intervals by end hash works as expected. +func TestIntervalBlockHashes(t *testing.T) { + // Construct a synthetic block chain with a block index consisting of + // the following structure. + // genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18 + // \-> 16a -> 17a -> 18a (unvalidated) + tip := tstTip + chain := newFakeChain(&chaincfg.MainNetParams) + branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18) + branch1Nodes := chainedNodes(branch0Nodes[14], 3) + for _, node := range branch0Nodes { + chain.index.SetStatusFlags(node, statusValid) + chain.index.AddNode(node) + } + for _, node := range branch1Nodes { + if node.height < 18 { + chain.index.SetStatusFlags(node, statusValid) + } + chain.index.AddNode(node) + } + chain.bestChain.SetTip(tip(branch0Nodes)) + + tests := []struct { + name string + endHash chainhash.Hash + interval int + hashes []chainhash.Hash + expectError bool + }{ + { + name: "blocks on main chain", + endHash: branch0Nodes[17].hash, + interval: 8, + hashes: nodeHashes(branch0Nodes, 7, 15), + }, + { + name: "blocks on stale chain", + endHash: branch1Nodes[1].hash, + interval: 8, + hashes: append(nodeHashes(branch0Nodes, 7), + nodeHashes(branch1Nodes, 0)...), + }, + { + name: "no results", + endHash: branch0Nodes[17].hash, + interval: 20, + hashes: []chainhash.Hash{}, + }, + { + name: "unvalidated block", + endHash: branch1Nodes[2].hash, + interval: 8, + expectError: true, + }, + } + for _, test := range tests { + hashes, err := chain.IntervalBlockHashes(&test.endHash, test.interval) + if err != nil { + if !test.expectError { + t.Errorf("%s: unexpected error: %v", test.name, err) + } + continue + } + + if !reflect.DeepEqual(hashes, test.hashes) { + t.Errorf("%s: unxpected hashes -- got %v, want %v", + test.name, hashes, test.hashes) + } + } +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chainio.go b/vendor/github.com/btcsuite/btcd/blockchain/chainio.go index 6c629c60..8d76d3ca 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/chainio.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/chainio.go @@ -9,7 +9,7 @@ import ( "encoding/binary" "fmt" "math/big" - "sort" + "sync" "time" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -18,7 +18,27 @@ import ( "github.com/btcsuite/btcutil" ) +const ( + // blockHdrSize is the size of a block header. This is simply the + // constant from wire and is only provided here for convenience since + // wire.MaxBlockHeaderPayload is quite long. + blockHdrSize = wire.MaxBlockHeaderPayload + + // latestUtxoSetBucketVersion is the current version of the utxo set + // bucket that is used to track all unspent outputs. + latestUtxoSetBucketVersion = 2 + + // latestSpendJournalBucketVersion is the current version of the spend + // journal bucket that is used to track all spent transactions for use + // in reorgs. + latestSpendJournalBucketVersion = 1 +) + var ( + // blockIndexBucketName is the name of the db bucket used to house to the + // block headers and contextual information. + blockIndexBucketName = []byte("blockheaderidx") + // hashIndexBucketName is the name of the db bucket used to house to the // block hash -> block height index. hashIndexBucketName = []byte("hashidx") @@ -31,13 +51,21 @@ var ( // chain state. chainStateKeyName = []byte("chainstate") + // spendJournalVersionKeyName is the name of the db key used to store + // the version of the spend journal currently in the database. + spendJournalVersionKeyName = []byte("spendjournalversion") + // spendJournalBucketName is the name of the db bucket used to house // transactions outputs that are spent in each block. spendJournalBucketName = []byte("spendjournal") + // utxoSetVersionKeyName is the name of the db key used to store the + // version of the utxo set currently in the database. + utxoSetVersionKeyName = []byte("utxosetversion") + // utxoSetBucketName is the name of the db bucket used to house the // unspent transaction output set. - utxoSetBucketName = []byte("utxoset") + utxoSetBucketName = []byte("utxosetv2") // byteOrder is the preferred byte order used for serializing numeric // fields for storage in the database. @@ -83,6 +111,45 @@ func isDbBucketNotFoundErr(err error) bool { return ok && dbErr.ErrorCode == database.ErrBucketNotFound } +// dbFetchVersion fetches an individual version with the given key from the +// metadata bucket. It is primarily used to track versions on entities such as +// buckets. It returns zero if the provided key does not exist. +func dbFetchVersion(dbTx database.Tx, key []byte) uint32 { + serialized := dbTx.Metadata().Get(key) + if serialized == nil { + return 0 + } + + return byteOrder.Uint32(serialized[:]) +} + +// dbPutVersion uses an existing database transaction to update the provided +// key in the metadata bucket to the given version. It is primarily used to +// track versions on entities such as buckets. +func dbPutVersion(dbTx database.Tx, key []byte, version uint32) error { + var serialized [4]byte + byteOrder.PutUint32(serialized[:], version) + return dbTx.Metadata().Put(key, serialized[:]) +} + +// dbFetchOrCreateVersion uses an existing database transaction to attempt to +// fetch the provided key from the metadata bucket as a version and in the case +// it doesn't exist, it adds the entry with the provided default version and +// returns that. This is useful during upgrades to automatically handle loading +// and adding version keys as necessary. +func dbFetchOrCreateVersion(dbTx database.Tx, key []byte, defaultVersion uint32) (uint32, error) { + version := dbFetchVersion(dbTx, key) + if version == 0 { + version = defaultVersion + err := dbPutVersion(dbTx, key, version) + if err != nil { + return 0, err + } + } + + return version, nil +} + // ----------------------------------------------------------------------------- // The transaction spend journal consists of an entry for each block connected // to the main chain which contains the transaction outputs the block spends @@ -99,18 +166,23 @@ func isDbBucketNotFoundErr(err error) bool { // // NOTE: This format is NOT self describing. The additional details such as // the number of entries (transaction inputs) are expected to come from the -// block itself and the utxo set. The rationale in doing this is to save a -// significant amount of space. This is also the reason the spent outputs are -// serialized in the reverse order they are spent because later transactions -// are allowed to spend outputs from earlier ones in the same block. +// block itself and the utxo set (for legacy entries). The rationale in doing +// this is to save space. This is also the reason the spent outputs are +// serialized in the reverse order they are spent because later transactions are +// allowed to spend outputs from earlier ones in the same block. +// +// The reserved field below used to keep track of the version of the containing +// transaction when the height in the header code was non-zero, however the +// height is always non-zero now, but keeping the extra reserved field allows +// backwards compatibility. // // The serialized format is: // -// [
],... +// [
],... // // Field Type Size // header code VLQ variable -// version VLQ variable +// reserved byte 1 // compressed txout // compressed amount VLQ variable // compressed script []byte variable @@ -119,23 +191,17 @@ func isDbBucketNotFoundErr(err error) bool { // bit 0 - containing transaction is a coinbase // bits 1-x - height of the block that contains the spent txout // -// NOTE: The header code and version are only encoded when the spent txout was -// the final unspent output of the containing transaction. Otherwise, the -// header code will be 0 and the version is not serialized at all. This is -// done because that information is only needed when the utxo set no longer -// has it. -// // Example 1: // From block 170 in main blockchain. // -// 1301320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c +// 1300320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c // <><><------------------------------------------------------------------> // | | | -// | version compressed txout +// | reserved compressed txout // header code // // - header code: 0x13 (coinbase, height 9) -// - transaction version: 1 +// - reserved: 0x00 // - compressed txout 0: // - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) // - 0x05: special script type pay-to-pubkey @@ -144,60 +210,81 @@ func isDbBucketNotFoundErr(err error) bool { // Example 2: // Adapted from block 100025 in main blockchain. // -// 0091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e868b99700186c64700b2fb57eadf61e106a100a7445a8c3f67898841ec -// <><----------------------------------------------><----><><----------------------------------------------> -// | | | | | -// | compressed txout | version compressed txout -// header code header code +// 8b99700091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e868b99700086c64700b2fb57eadf61e106a100a7445a8c3f67898841ec +// <----><><----------------------------------------------><----><><----------------------------------------------> +// | | | | | | +// | reserved compressed txout | reserved compressed txout +// header code header code // // - Last spent output: -// - header code: 0x00 (was not the final unspent output for containing tx) -// - transaction version: Nothing since header code is 0 +// - header code: 0x8b9970 (not coinbase, height 100024) +// - reserved: 0x00 // - compressed txout: // - 0x91f20f: VLQ-encoded compressed amount for 34405000000 (344.05 BTC) // - 0x00: special script type pay-to-pubkey-hash // - 0x6e...86: pubkey hash // - Second to last spent output: // - header code: 0x8b9970 (not coinbase, height 100024) -// - transaction version: 1 +// - reserved: 0x00 // - compressed txout: // - 0x86c647: VLQ-encoded compressed amount for 13761000000 (137.61 BTC) // - 0x00: special script type pay-to-pubkey-hash // - 0xb2...ec: pubkey hash // ----------------------------------------------------------------------------- -// spentTxOut contains a spent transaction output and potentially additional +// SpentTxOut contains a spent transaction output and potentially additional // contextual information such as whether or not it was contained in a coinbase // transaction, the version of the transaction it was contained in, and which // block height the containing transaction was included in. As described in // the comments above, the additional contextual information will only be valid // when this spent txout is spending the last unspent output of the containing // transaction. -type spentTxOut struct { - compressed bool // The amount and public key script are compressed. - version int32 // The version of creating tx. - amount int64 // The amount of the output. - pkScript []byte // The public key script for the output. +type SpentTxOut struct { + // Amount is the amount of the output. + Amount int64 - // These fields are only set when this is spending the final output of - // the creating tx. - height int32 // Height of the the block containing the creating tx. - isCoinBase bool // Whether creating tx is a coinbase. + // PkScipt is the the public key script for the output. + PkScript []byte + + // Height is the height of the the block containing the creating tx. + Height int32 + + // Denotes if the creating tx is a coinbase. + IsCoinBase bool +} + +// FetchSpendJournal attempts to retrieve the spend journal, or the set of +// outputs spent for the target block. This provides a view of all the outputs +// that will be consumed once the target block is connected to the end of the +// main chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) FetchSpendJournal(targetBlock *btcutil.Block) ([]SpentTxOut, error) { + b.chainLock.RLock() + defer b.chainLock.RUnlock() + + var spendEntries []SpentTxOut + err := b.db.View(func(dbTx database.Tx) error { + var err error + + spendEntries, err = dbFetchSpendJournalEntry(dbTx, targetBlock) + return err + }) + if err != nil { + return nil, err + } + + return spendEntries, nil } // spentTxOutHeaderCode returns the calculated header code to be used when // serializing the provided stxo entry. -func spentTxOutHeaderCode(stxo *spentTxOut) uint64 { - // The header code is 0 when there is no height set for the stxo. - if stxo.height == 0 { - return 0 - } - +func spentTxOutHeaderCode(stxo *SpentTxOut) uint64 { // As described in the serialization format comments, the header code // encodes the height shifted over one bit and the coinbase flag in the // lowest bit. - headerCode := uint64(stxo.height) << 1 - if stxo.isCoinBase { + headerCode := uint64(stxo.Height) << 1 + if stxo.IsCoinBase { headerCode |= 0x01 } @@ -206,43 +293,38 @@ func spentTxOutHeaderCode(stxo *spentTxOut) uint64 { // spentTxOutSerializeSize returns the number of bytes it would take to // serialize the passed stxo according to the format described above. -func spentTxOutSerializeSize(stxo *spentTxOut) int { - headerCode := spentTxOutHeaderCode(stxo) - size := serializeSizeVLQ(headerCode) - if headerCode != 0 { - size += serializeSizeVLQ(uint64(stxo.version)) +func spentTxOutSerializeSize(stxo *SpentTxOut) int { + size := serializeSizeVLQ(spentTxOutHeaderCode(stxo)) + if stxo.Height > 0 { + // The legacy v1 spend journal format conditionally tracked the + // containing transaction version when the height was non-zero, + // so this is required for backwards compat. + size += serializeSizeVLQ(0) } - return size + compressedTxOutSize(uint64(stxo.amount), stxo.pkScript, - stxo.version, stxo.compressed) + return size + compressedTxOutSize(uint64(stxo.Amount), stxo.PkScript) } // putSpentTxOut serializes the passed stxo according to the format described // above directly into the passed target byte slice. The target byte slice must // be at least large enough to handle the number of bytes returned by the -// spentTxOutSerializeSize function or it will panic. -func putSpentTxOut(target []byte, stxo *spentTxOut) int { +// SpentTxOutSerializeSize function or it will panic. +func putSpentTxOut(target []byte, stxo *SpentTxOut) int { headerCode := spentTxOutHeaderCode(stxo) offset := putVLQ(target, headerCode) - if headerCode != 0 { - offset += putVLQ(target[offset:], uint64(stxo.version)) + if stxo.Height > 0 { + // The legacy v1 spend journal format conditionally tracked the + // containing transaction version when the height was non-zero, + // so this is required for backwards compat. + offset += putVLQ(target[offset:], 0) } - return offset + putCompressedTxOut(target[offset:], uint64(stxo.amount), - stxo.pkScript, stxo.version, stxo.compressed) + return offset + putCompressedTxOut(target[offset:], uint64(stxo.Amount), + stxo.PkScript) } // decodeSpentTxOut decodes the passed serialized stxo entry, possibly followed // by other data, into the passed stxo struct. It returns the number of bytes // read. -// -// Since the serialized stxo entry does not contain the height, version, or -// coinbase flag of the containing transaction when it still has utxos, the -// caller is responsible for passing in the containing transaction version in -// that case. The provided version is ignore when it is serialized as a part of -// the stxo. -// -// An error will be returned if the version is not serialized as a part of the -// stxo and is also not provided to the function. -func decodeSpentTxOut(serialized []byte, stxo *spentTxOut, txVersion int32) (int, error) { +func decodeSpentTxOut(serialized []byte, stxo *SpentTxOut) (int, error) { // Ensure there are bytes to decode. if len(serialized) == 0 { return 0, errDeserialize("no serialized bytes") @@ -255,47 +337,34 @@ func decodeSpentTxOut(serialized []byte, stxo *spentTxOut, txVersion int32) (int "header code") } - // Decode the header code and deserialize the containing transaction - // version if needed. + // Decode the header code. // // Bit 0 indicates containing transaction is a coinbase. // Bits 1-x encode height of containing transaction. - if code != 0 { - version, bytesRead := deserializeVLQ(serialized[offset:]) + stxo.IsCoinBase = code&0x01 != 0 + stxo.Height = int32(code >> 1) + if stxo.Height > 0 { + // The legacy v1 spend journal format conditionally tracked the + // containing transaction version when the height was non-zero, + // so this is required for backwards compat. + _, bytesRead := deserializeVLQ(serialized[offset:]) offset += bytesRead if offset >= len(serialized) { return offset, errDeserialize("unexpected end of data " + - "after version") + "after reserved") } - - stxo.isCoinBase = code&0x01 != 0 - stxo.height = int32(code >> 1) - stxo.version = int32(version) - } else { - // Ensure a tx version was specified if the stxo did not encode - // it. This should never happen unless there is database - // corruption or this function is being called without the - // proper state. - if txVersion == -1 { - return offset, AssertError("decodeSpentTxOut called " + - "without a containing tx version when the " + - "serialized stxo that does not encode the " + - "version") - } - stxo.version = txVersion } // Decode the compressed txout. - compAmount, compScript, bytesRead, err := decodeCompressedTxOut( - serialized[offset:], stxo.version) + amount, pkScript, bytesRead, err := decodeCompressedTxOut( + serialized[offset:]) offset += bytesRead if err != nil { return offset, errDeserialize(fmt.Sprintf("unable to decode "+ "txout: %v", err)) } - stxo.amount = int64(compAmount) - stxo.pkScript = compScript - stxo.compressed = true + stxo.Amount = int64(amount) + stxo.PkScript = pkScript return offset, nil } @@ -304,9 +373,8 @@ func decodeSpentTxOut(serialized []byte, stxo *spentTxOut, txVersion int32) (int // // Since the serialization format is not self describing, as noted in the // format comments, this function also requires the transactions that spend the -// txouts and a utxo view that contains any remaining existing utxos in the -// transactions referenced by the inputs to the passed transasctions. -func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx, view *UtxoViewpoint) ([]spentTxOut, error) { +// txouts. +func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx) ([]SpentTxOut, error) { // Calculate the total number of stxos. var numStxos int for _, tx := range txns { @@ -330,9 +398,8 @@ func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx, view *U // Loop backwards through all transactions so everything is read in // reverse order to match the serialization order. stxoIdx := numStxos - 1 - stxoInFlight := make(map[chainhash.Hash]int) offset := 0 - stxos := make([]spentTxOut, numStxos) + stxos := make([]SpentTxOut, numStxos) for txIdx := len(txns) - 1; txIdx > -1; txIdx-- { tx := txns[txIdx] @@ -343,36 +410,7 @@ func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx, view *U stxo := &stxos[stxoIdx] stxoIdx-- - // Get the transaction version for the stxo based on - // whether or not it should be serialized as a part of - // the stxo. Recall that it is only serialized when the - // stxo spends the final utxo of a transaction. Since - // they are deserialized in reverse order, this means - // the first time an entry for a given containing tx is - // encountered that is not already in the utxo view it - // must have been the final spend and thus the extra - // data will be serialized with the stxo. Otherwise, - // the version must be pulled from the utxo entry. - // - // Since the view is not actually modified as the stxos - // are read here and it's possible later entries - // reference earlier ones, an inflight map is maintained - // to detect this case and pull the tx version from the - // entry that contains the version information as just - // described. - txVersion := int32(-1) - originHash := &txIn.PreviousOutPoint.Hash - entry := view.LookupEntry(originHash) - if entry != nil { - txVersion = entry.Version() - } else if idx, ok := stxoInFlight[*originHash]; ok { - txVersion = stxos[idx].version - } else { - stxoInFlight[*originHash] = stxoIdx + 1 - } - - n, err := decodeSpentTxOut(serialized[offset:], stxo, - txVersion) + n, err := decodeSpentTxOut(serialized[offset:], stxo) offset += n if err != nil { return nil, errDeserialize(fmt.Sprintf("unable "+ @@ -387,7 +425,7 @@ func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx, view *U // serializeSpendJournalEntry serializes all of the passed spent txouts into a // single byte slice according to the format described in detail above. -func serializeSpendJournalEntry(stxos []spentTxOut) []byte { +func serializeSpendJournalEntry(stxos []SpentTxOut) []byte { if len(stxos) == 0 { return nil } @@ -409,17 +447,18 @@ func serializeSpendJournalEntry(stxos []spentTxOut) []byte { return serialized } -// dbFetchSpendJournalEntry fetches the spend journal entry for the passed -// block and deserializes it into a slice of spent txout entries. The provided -// view MUST have the utxos referenced by all of the transactions available for -// the passed block since that information is required to reconstruct the spent -// txouts. -func dbFetchSpendJournalEntry(dbTx database.Tx, block *btcutil.Block, view *UtxoViewpoint) ([]spentTxOut, error) { +// dbFetchSpendJournalEntry fetches the spend journal entry for the passed block +// and deserializes it into a slice of spent txout entries. +// +// NOTE: Legacy entries will not have the coinbase flag or height set unless it +// was the final output spend in the containing transaction. It is up to the +// caller to handle this properly by looking the information up in the utxo set. +func dbFetchSpendJournalEntry(dbTx database.Tx, block *btcutil.Block) ([]SpentTxOut, error) { // Exclude the coinbase transaction since it can't spend anything. spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) serialized := spendBucket.Get(block.Hash()[:]) blockTxns := block.MsgBlock().Transactions[1:] - stxos, err := deserializeSpendJournalEntry(serialized, blockTxns, view) + stxos, err := deserializeSpendJournalEntry(serialized, blockTxns) if err != nil { // Ensure any deserialization errors are returned as database // corruption errors. @@ -442,7 +481,7 @@ func dbFetchSpendJournalEntry(dbTx database.Tx, block *btcutil.Block, view *Utxo // spend journal entry for the given block hash using the provided slice of // spent txouts. The spent txouts slice must contain an entry for every txout // the transactions in the block spend in the order they are spent. -func dbPutSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash, stxos []spentTxOut) error { +func dbPutSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash, stxos []SpentTxOut) error { spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) serialized := serializeSpendJournalEntry(stxos) return spendBucket.Put(blockHash[:], serialized) @@ -457,219 +496,161 @@ func dbRemoveSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash) erro // ----------------------------------------------------------------------------- // The unspent transaction output (utxo) set consists of an entry for each -// transaction which contains a utxo serialized using a format that is highly -// optimized to reduce space using domain specific compression algorithms. This -// format is a slightly modified version of the format used in Bitcoin Core. +// unspent output using a format that is optimized to reduce space using domain +// specific compression algorithms. This format is a slightly modified version +// of the format used in Bitcoin Core. // -// The serialized format is: +// Each entry is keyed by an outpoint as specified below. It is important to +// note that the key encoding uses a VLQ, which employs an MSB encoding so +// iteration of utxos when doing byte-wise comparisons will produce them in +// order. // -//
[,...] +// The serialized key format is: +// +// +// Field Type Size +// hash chainhash.Hash chainhash.HashSize +// output index VLQ variable +// +// The serialized value format is: +// +//
// // Field Type Size -// version VLQ variable -// block height VLQ variable // header code VLQ variable -// unspentness bitmap []byte variable -// compressed txouts +// compressed txout // compressed amount VLQ variable // compressed script []byte variable // // The serialized header code format is: // bit 0 - containing transaction is a coinbase -// bit 1 - output zero is unspent -// bit 2 - output one is unspent -// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2 -// are unset, it encodes N-1 since there must be at least one unspent -// output. -// -// The rationale for the header code scheme is as follows: -// - Transactions which only pay to a single output and a change output are -// extremely common, thus an extra byte for the unspentness bitmap can be -// avoided for them by encoding those two outputs in the low order bits. -// - Given it is encoded as a VLQ which can encode values up to 127 with a -// single byte, that leaves 4 bits to represent the number of bytes in the -// unspentness bitmap while still only consuming a single byte for the -// header code. In other words, an unspentness bitmap with up to 120 -// transaction outputs can be encoded with a single-byte header code. -// This covers the vast majority of transactions. -// - Encoding N-1 bytes when both bits 1 and 2 are unset allows an additional -// 8 outpoints to be encoded before causing the header code to require an -// additional byte. +// bits 1-x - height of the block that contains the unspent txout // // Example 1: // From tx in main blockchain: -// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 +// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098:0 // -// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 -// <><><><------------------------------------------------------------------> -// | | \--------\ | -// | height | compressed txout 0 -// version header code +// 03320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 +// <><------------------------------------------------------------------> +// | | +// header code compressed txout // -// - version: 1 -// - height: 1 -// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness) -// - unspentness: Nothing since it is zero bytes -// - compressed txout 0: +// - header code: 0x03 (coinbase, height 1) +// - compressed txout: // - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) // - 0x04: special script type pay-to-pubkey // - 0x96...52: x-coordinate of the pubkey // // Example 2: // From tx in main blockchain: -// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f +// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f:2 // -// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 -// <><----><><><------------------------------------------><--------------------------------------------> -// | | | \-------------------\ | | -// version | \--------\ unspentness | compressed txout 2 -// height header code compressed txout 0 +// 8cf316800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 +// <----><------------------------------------------> +// | | +// header code compressed txout // -// - version: 1 -// - height: 113931 -// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap) -// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent) -// NOTE: It's +2 since the first two outputs are encoded in the header code -// - compressed txout 0: -// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC) -// - 0x00: special script type pay-to-pubkey-hash -// - 0xe2...8a: pubkey hash -// - compressed txout 2: +// - header code: 0x8cf316 (not coinbase, height 113931) +// - compressed txout: // - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC) // - 0x00: special script type pay-to-pubkey-hash // - 0xb8...58: pubkey hash // // Example 3: // From tx in main blockchain: -// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620 +// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620:22 // -// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 -// <><----><><----><--------------------------------------------------> -// | | | \-----------------\ | -// version | \--------\ unspentness | -// height header code compressed txout 22 +// a8a2588ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 +// <----><--------------------------------------------------> +// | | +// header code compressed txout // -// - version: 1 -// - height: 338156 -// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap) -// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded. -// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent) -// NOTE: It's +2 since the first two outputs are encoded in the header code -// - compressed txout 22: +// - header code: 0xa8a258 (not coinbase, height 338156) +// - compressed txout: // - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC) // - 0x01: special script type pay-to-script-hash // - 0x1d...e6: script hash // ----------------------------------------------------------------------------- +// maxUint32VLQSerializeSize is the maximum number of bytes a max uint32 takes +// to serialize as a VLQ. +var maxUint32VLQSerializeSize = serializeSizeVLQ(1<<32 - 1) + +// outpointKeyPool defines a concurrent safe free list of byte slices used to +// provide temporary buffers for outpoint database keys. +var outpointKeyPool = sync.Pool{ + New: func() interface{} { + b := make([]byte, chainhash.HashSize+maxUint32VLQSerializeSize) + return &b // Pointer to slice to avoid boxing alloc. + }, +} + +// outpointKey returns a key suitable for use as a database key in the utxo set +// while making use of a free list. A new buffer is allocated if there are not +// already any available on the free list. The returned byte slice should be +// returned to the free list by using the recycleOutpointKey function when the +// caller is done with it _unless_ the slice will need to live for longer than +// the caller can calculate such as when used to write to the database. +func outpointKey(outpoint wire.OutPoint) *[]byte { + // A VLQ employs an MSB encoding, so they are useful not only to reduce + // the amount of storage space, but also so iteration of utxos when + // doing byte-wise comparisons will produce them in order. + key := outpointKeyPool.Get().(*[]byte) + idx := uint64(outpoint.Index) + *key = (*key)[:chainhash.HashSize+serializeSizeVLQ(idx)] + copy(*key, outpoint.Hash[:]) + putVLQ((*key)[chainhash.HashSize:], idx) + return key +} + +// recycleOutpointKey puts the provided byte slice, which should have been +// obtained via the outpointKey function, back on the free list. +func recycleOutpointKey(key *[]byte) { + outpointKeyPool.Put(key) +} + // utxoEntryHeaderCode returns the calculated header code to be used when -// serializing the provided utxo entry and the number of bytes needed to encode -// the unspentness bitmap. -func utxoEntryHeaderCode(entry *UtxoEntry, highestOutputIndex uint32) (uint64, int, error) { - // The first two outputs are encoded separately, so offset the index - // accordingly to calculate the correct number of bytes needed to encode - // up to the highest unspent output index. - numBitmapBytes := int((highestOutputIndex + 6) / 8) - - // As previously described, one less than the number of bytes is encoded - // when both output 0 and 1 are spent because there must be at least one - // unspent output. Adjust the number of bytes to encode accordingly and - // encode the value by shifting it over 3 bits. - output0Unspent := !entry.IsOutputSpent(0) - output1Unspent := !entry.IsOutputSpent(1) - var numBitmapBytesAdjustment int - if !output0Unspent && !output1Unspent { - if numBitmapBytes == 0 { - return 0, 0, AssertError("attempt to serialize utxo " + - "header for fully spent transaction") - } - numBitmapBytesAdjustment = 1 - } - headerCode := uint64(numBitmapBytes-numBitmapBytesAdjustment) << 3 - - // Set the coinbase, output 0, and output 1 bits in the header code - // accordingly. - if entry.isCoinBase { - headerCode |= 0x01 // bit 0 - } - if output0Unspent { - headerCode |= 0x02 // bit 1 - } - if output1Unspent { - headerCode |= 0x04 // bit 2 +// serializing the provided utxo entry. +func utxoEntryHeaderCode(entry *UtxoEntry) (uint64, error) { + if entry.IsSpent() { + return 0, AssertError("attempt to serialize spent utxo header") } - return headerCode, numBitmapBytes, nil + // As described in the serialization format comments, the header code + // encodes the height shifted over one bit and the coinbase flag in the + // lowest bit. + headerCode := uint64(entry.BlockHeight()) << 1 + if entry.IsCoinBase() { + headerCode |= 0x01 + } + + return headerCode, nil } // serializeUtxoEntry returns the entry serialized to a format that is suitable // for long-term storage. The format is described in detail above. func serializeUtxoEntry(entry *UtxoEntry) ([]byte, error) { - // Fully spent entries have no serialization. - if entry.IsFullySpent() { + // Spent outputs have no serialization. + if entry.IsSpent() { return nil, nil } - // Determine the output order by sorting the sparse output index keys. - outputOrder := make([]int, 0, len(entry.sparseOutputs)) - for outputIndex := range entry.sparseOutputs { - outputOrder = append(outputOrder, int(outputIndex)) - } - sort.Ints(outputOrder) - - // Encode the header code and determine the number of bytes the - // unspentness bitmap needs. - highIndex := uint32(outputOrder[len(outputOrder)-1]) - headerCode, numBitmapBytes, err := utxoEntryHeaderCode(entry, highIndex) + // Encode the header code. + headerCode, err := utxoEntryHeaderCode(entry) if err != nil { return nil, err } // Calculate the size needed to serialize the entry. - size := serializeSizeVLQ(uint64(entry.version)) + - serializeSizeVLQ(uint64(entry.blockHeight)) + - serializeSizeVLQ(headerCode) + numBitmapBytes - for _, outputIndex := range outputOrder { - out := entry.sparseOutputs[uint32(outputIndex)] - if out.spent { - continue - } - size += compressedTxOutSize(uint64(out.amount), out.pkScript, - entry.version, out.compressed) - } + size := serializeSizeVLQ(headerCode) + + compressedTxOutSize(uint64(entry.Amount()), entry.PkScript()) - // Serialize the version, block height of the containing transaction, - // and header code. + // Serialize the header code followed by the compressed unspent + // transaction output. serialized := make([]byte, size) - offset := putVLQ(serialized, uint64(entry.version)) - offset += putVLQ(serialized[offset:], uint64(entry.blockHeight)) - offset += putVLQ(serialized[offset:], headerCode) - - // Serialize the unspentness bitmap. - for i := uint32(0); i < uint32(numBitmapBytes); i++ { - unspentBits := byte(0) - for j := uint32(0); j < 8; j++ { - // The first 2 outputs are encoded via the header code, - // so adjust the output index accordingly. - if !entry.IsOutputSpent(2 + i*8 + j) { - unspentBits |= 1 << uint8(j) - } - } - serialized[offset] = unspentBits - offset++ - } - - // Serialize the compressed unspent transaction outputs. Outputs that - // are already compressed are serialized without modifications. - for _, outputIndex := range outputOrder { - out := entry.sparseOutputs[uint32(outputIndex)] - if out.spent { - continue - } - - offset += putCompressedTxOut(serialized[offset:], - uint64(out.amount), out.pkScript, entry.version, - out.compressed) - } + offset := putVLQ(serialized, headerCode) + offset += putCompressedTxOut(serialized[offset:], uint64(entry.Amount()), + entry.PkScript()) return serialized, nil } @@ -678,23 +659,8 @@ func serializeUtxoEntry(entry *UtxoEntry) ([]byte, error) { // slice into a new UtxoEntry using a format that is suitable for long-term // storage. The format is described in detail above. func deserializeUtxoEntry(serialized []byte) (*UtxoEntry, error) { - // Deserialize the version. - version, bytesRead := deserializeVLQ(serialized) - offset := bytesRead - if offset >= len(serialized) { - return nil, errDeserialize("unexpected end of data after version") - } - - // Deserialize the block height. - blockHeight, bytesRead := deserializeVLQ(serialized[offset:]) - offset += bytesRead - if offset >= len(serialized) { - return nil, errDeserialize("unexpected end of data after height") - } - // Deserialize the header code. - code, bytesRead := deserializeVLQ(serialized[offset:]) - offset += bytesRead + code, offset := deserializeVLQ(serialized) if offset >= len(serialized) { return nil, errDeserialize("unexpected end of data after header") } @@ -702,101 +668,83 @@ func deserializeUtxoEntry(serialized []byte) (*UtxoEntry, error) { // Decode the header code. // // Bit 0 indicates whether the containing transaction is a coinbase. - // Bit 1 indicates output 0 is unspent. - // Bit 2 indicates output 1 is unspent. - // Bits 3-x encodes the number of non-zero unspentness bitmap bytes that - // follow. When both output 0 and 1 are spent, it encodes N-1. + // Bits 1-x encode height of containing transaction. isCoinBase := code&0x01 != 0 - output0Unspent := code&0x02 != 0 - output1Unspent := code&0x04 != 0 - numBitmapBytes := code >> 3 - if !output0Unspent && !output1Unspent { - numBitmapBytes++ + blockHeight := int32(code >> 1) + + // Decode the compressed unspent transaction output. + amount, pkScript, _, err := decodeCompressedTxOut(serialized[offset:]) + if err != nil { + return nil, errDeserialize(fmt.Sprintf("unable to decode "+ + "utxo: %v", err)) } - // Ensure there are enough bytes left to deserialize the unspentness - // bitmap. - if uint64(len(serialized[offset:])) < numBitmapBytes { - return nil, errDeserialize("unexpected end of data for " + - "unspentness bitmap") + entry := &UtxoEntry{ + amount: int64(amount), + pkScript: pkScript, + blockHeight: blockHeight, + packedFlags: 0, } - - // Create a new utxo entry with the details deserialized above to house - // all of the utxos. - entry := newUtxoEntry(int32(version), isCoinBase, int32(blockHeight)) - - // Add sparse output for unspent outputs 0 and 1 as needed based on the - // details provided by the header code. - var outputIndexes []uint32 - if output0Unspent { - outputIndexes = append(outputIndexes, 0) - } - if output1Unspent { - outputIndexes = append(outputIndexes, 1) - } - - // Decode the unspentness bitmap adding a sparse output for each unspent - // output. - for i := uint32(0); i < uint32(numBitmapBytes); i++ { - unspentBits := serialized[offset] - for j := uint32(0); j < 8; j++ { - if unspentBits&0x01 != 0 { - // The first 2 outputs are encoded via the - // header code, so adjust the output number - // accordingly. - outputNum := 2 + i*8 + j - outputIndexes = append(outputIndexes, outputNum) - } - unspentBits >>= 1 - } - offset++ - } - - // Decode and add all of the utxos. - for i, outputIndex := range outputIndexes { - // Decode the next utxo. The script and amount fields of the - // utxo output are left compressed so decompression can be - // avoided on those that are not accessed. This is done since - // it is quite common for a redeeming transaction to only - // reference a single utxo from a referenced transaction. - compAmount, compScript, bytesRead, err := decodeCompressedTxOut( - serialized[offset:], int32(version)) - if err != nil { - return nil, errDeserialize(fmt.Sprintf("unable to "+ - "decode utxo at index %d: %v", i, err)) - } - offset += bytesRead - - entry.sparseOutputs[outputIndex] = &utxoOutput{ - spent: false, - compressed: true, - pkScript: compScript, - amount: int64(compAmount), - } + if isCoinBase { + entry.packedFlags |= tfCoinBase } return entry, nil } -// dbFetchUtxoEntry uses an existing database transaction to fetch all unspent -// outputs for the provided Bitcoin transaction hash from the utxo set. +// dbFetchUtxoEntryByHash attempts to find and fetch a utxo for the given hash. +// It uses a cursor and seek to try and do this as efficiently as possible. // -// When there is no entry for the provided hash, nil will be returned for the +// When there are no entries for the provided hash, nil will be returned for the // both the entry and the error. -func dbFetchUtxoEntry(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error) { +func dbFetchUtxoEntryByHash(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error) { + // Attempt to find an entry by seeking for the hash along with a zero + // index. Due to the fact the keys are serialized as , + // where the index uses an MSB encoding, if there are any entries for + // the hash at all, one will be found. + cursor := dbTx.Metadata().Bucket(utxoSetBucketName).Cursor() + key := outpointKey(wire.OutPoint{Hash: *hash, Index: 0}) + ok := cursor.Seek(*key) + recycleOutpointKey(key) + if !ok { + return nil, nil + } + + // An entry was found, but it could just be an entry with the next + // highest hash after the requested one, so make sure the hashes + // actually match. + cursorKey := cursor.Key() + if len(cursorKey) < chainhash.HashSize { + return nil, nil + } + if !bytes.Equal(hash[:], cursorKey[:chainhash.HashSize]) { + return nil, nil + } + + return deserializeUtxoEntry(cursor.Value()) +} + +// dbFetchUtxoEntry uses an existing database transaction to fetch the specified +// transaction output from the utxo set. +// +// When there is no entry for the provided output, nil will be returned for both +// the entry and the error. +func dbFetchUtxoEntry(dbTx database.Tx, outpoint wire.OutPoint) (*UtxoEntry, error) { // Fetch the unspent transaction output information for the passed - // transaction hash. Return now when there is no entry. + // transaction output. Return now when there is no entry. + key := outpointKey(outpoint) utxoBucket := dbTx.Metadata().Bucket(utxoSetBucketName) - serializedUtxo := utxoBucket.Get(hash[:]) + serializedUtxo := utxoBucket.Get(*key) + recycleOutpointKey(key) if serializedUtxo == nil { return nil, nil } // A non-nil zero-length entry means there is an entry in the database - // for a fully spent transaction which should never be the case. + // for a spent transaction output which should never be the case. if len(serializedUtxo) == 0 { return nil, AssertError(fmt.Sprintf("database contains entry "+ - "for fully spent tx %v", hash)) + "for spent tx output %v", outpoint)) } // Deserialize the utxo entry and return it. @@ -808,7 +756,7 @@ func dbFetchUtxoEntry(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error return nil, database.Error{ ErrorCode: database.ErrCorruption, Description: fmt.Sprintf("corrupt utxo entry "+ - "for %v: %v", hash, err), + "for %v: %v", outpoint, err), } } @@ -824,36 +772,35 @@ func dbFetchUtxoEntry(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error // to the database. func dbPutUtxoView(dbTx database.Tx, view *UtxoViewpoint) error { utxoBucket := dbTx.Metadata().Bucket(utxoSetBucketName) - for txHashIter, entry := range view.entries { + for outpoint, entry := range view.entries { // No need to update the database if the entry was not modified. - if entry == nil || !entry.modified { + if entry == nil || !entry.isModified() { continue } - // Serialize the utxo entry without any entries that have been - // spent. - serialized, err := serializeUtxoEntry(entry) - if err != nil { - return err - } - - // Make a copy of the hash because the iterator changes on each - // loop iteration and thus slicing it directly would cause the - // data to change out from under the put/delete funcs below. - txHash := txHashIter - - // Remove the utxo entry if it is now fully spent. - if serialized == nil { - if err := utxoBucket.Delete(txHash[:]); err != nil { + // Remove the utxo entry if it is spent. + if entry.IsSpent() { + key := outpointKey(outpoint) + err := utxoBucket.Delete(*key) + recycleOutpointKey(key) + if err != nil { return err } continue } - // At this point the utxo entry is not fully spent, so store its - // serialization in the database. - err = utxoBucket.Put(txHash[:], serialized) + // Serialize and store the utxo entry. + serialized, err := serializeUtxoEntry(entry) + if err != nil { + return err + } + key := outpointKey(outpoint) + err = utxoBucket.Put(*key, serialized) + // NOTE: The key is intentionally not recycled here since the + // database interface contract prohibits modifications. It will + // be garbage collected normally when the database is done with + // it. if err != nil { return err } @@ -1058,13 +1005,14 @@ func dbPutBestState(dbTx database.Tx, snapshot *BestState, workSum *big.Int) err func (b *BlockChain) createChainState() error { // Create a new node from the genesis block and set it as the best node. genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock) + genesisBlock.SetHeight(0) header := &genesisBlock.MsgBlock().Header - node := newBlockNode(header, 0) + node := newBlockNode(header, nil) node.status = statusDataStored | statusValid b.bestChain.SetTip(node) // Add the new node to the index which is used for faster lookups. - b.index.AddNode(node) + b.index.addNode(node) // Initialize the state related to the best block. Since it is the // genesis block, use its timestamp for the median time. @@ -1077,10 +1025,17 @@ func (b *BlockChain) createChainState() error { // Create the initial the database chain state including creating the // necessary index buckets and inserting the genesis block. err := b.db.Update(func(dbTx database.Tx) error { + meta := dbTx.Metadata() + + // Create the bucket that houses the block index data. + _, err := meta.CreateBucket(blockIndexBucketName) + if err != nil { + return err + } + // Create the bucket that houses the chain block hash to height // index. - meta := dbTx.Metadata() - _, err := meta.CreateBucket(hashIndexBucketName) + _, err = meta.CreateBucket(hashIndexBucketName) if err != nil { return err } @@ -1092,19 +1047,37 @@ func (b *BlockChain) createChainState() error { return err } - // Create the bucket that houses the spend journal data. + // Create the bucket that houses the spend journal data and + // store its version. _, err = meta.CreateBucket(spendJournalBucketName) if err != nil { return err } + err = dbPutVersion(dbTx, utxoSetVersionKeyName, + latestUtxoSetBucketVersion) + if err != nil { + return err + } - // Create the bucket that houses the utxo set. Note that the - // genesis block coinbase transaction is intentionally not - // inserted here since it is not spendable by consensus rules. + // Create the bucket that houses the utxo set and store its + // version. Note that the genesis block coinbase transaction is + // intentionally not inserted here since it is not spendable by + // consensus rules. _, err = meta.CreateBucket(utxoSetBucketName) if err != nil { return err } + err = dbPutVersion(dbTx, spendJournalVersionKeyName, + latestSpendJournalBucketVersion) + if err != nil { + return err + } + + // Save the genesis block to the block index database. + err = dbStoreBlockNode(dbTx, node) + if err != nil { + return err + } // Add the genesis block hash to height and height to hash // mappings to the index. @@ -1120,7 +1093,7 @@ func (b *BlockChain) createChainState() error { } // Store the genesis block into the database. - return dbTx.StoreBlock(genesisBlock) + return dbStoreBlock(dbTx, genesisBlock) }) return err } @@ -1129,17 +1102,38 @@ func (b *BlockChain) createChainState() error { // database. When the db does not yet contain any chain state, both it and the // chain state are initialized to the genesis block. func (b *BlockChain) initChainState() error { - // Attempt to load the chain state from the database. - var isStateInitialized bool + // Determine the state of the chain database. We may need to initialize + // everything from scratch or upgrade certain buckets. + var initialized, hasBlockIndex bool err := b.db.View(func(dbTx database.Tx) error { + initialized = dbTx.Metadata().Get(chainStateKeyName) != nil + hasBlockIndex = dbTx.Metadata().Bucket(blockIndexBucketName) != nil + return nil + }) + if err != nil { + return err + } + + if !initialized { + // At this point the database has not already been initialized, so + // initialize both it and the chain state to the genesis block. + return b.createChainState() + } + + if !hasBlockIndex { + err := migrateBlockIndex(b.db) + if err != nil { + return nil + } + } + + // Attempt to load the chain state from the database. + err = b.db.View(func(dbTx database.Tx) error { // Fetch the stored chain state from the database metadata. // When it doesn't exist, it means the database hasn't been // initialized for use with chain yet, so break out now to allow // that to happen under a writable database transaction. serializedData := dbTx.Metadata().Get(chainStateKeyName) - if serializedData == nil { - return nil - } log.Tracef("Serialized chain state: %x", serializedData) state, err := deserializeBestChainState(serializedData) if err != nil { @@ -1151,42 +1145,68 @@ func (b *BlockChain) initChainState() error { // number of nodes are already known, perform a single alloc // for them versus a whole bunch of little ones to reduce // pressure on the GC. - log.Infof("Loading block index. This might take a while...") - bestHeight := int32(state.height) - blockNodes := make([]blockNode, bestHeight+1) - var tip *blockNode - for height := int32(0); height <= bestHeight; height++ { - header, err := dbFetchHeaderByHeight(dbTx, height) + log.Infof("Loading block index...") + + blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName) + + // Determine how many blocks will be loaded into the index so we can + // allocate the right amount. + var blockCount int32 + cursor := blockIndexBucket.Cursor() + for ok := cursor.First(); ok; ok = cursor.Next() { + blockCount++ + } + blockNodes := make([]blockNode, blockCount) + + var i int32 + var lastNode *blockNode + cursor = blockIndexBucket.Cursor() + for ok := cursor.First(); ok; ok = cursor.Next() { + header, status, err := deserializeBlockRow(cursor.Value()) if err != nil { return err } + // Determine the parent block node. Since we iterate block headers + // in order of height, if the blocks are mostly linear there is a + // very good chance the previous header processed is the parent. + var parent *blockNode + if lastNode == nil { + blockHash := header.BlockHash() + if !blockHash.IsEqual(b.chainParams.GenesisHash) { + return AssertError(fmt.Sprintf("initChainState: Expected "+ + "first entry in block index to be genesis block, "+ + "found %s", blockHash)) + } + } else if header.PrevBlock == lastNode.hash { + // Since we iterate block headers in order of height, if the + // blocks are mostly linear there is a very good chance the + // previous header processed is the parent. + parent = lastNode + } else { + parent = b.index.LookupNode(&header.PrevBlock) + if parent == nil { + return AssertError(fmt.Sprintf("initChainState: Could "+ + "not find parent for block %s", header.BlockHash())) + } + } + // Initialize the block node for the block, connect it, // and add it to the block index. - node := &blockNodes[height] - initBlockNode(node, header, height) - node.status = statusDataStored | statusValid - if tip != nil { - node.parent = tip - node.workSum = node.workSum.Add(tip.workSum, - node.workSum) - } - b.index.AddNode(node) + node := &blockNodes[i] + initBlockNode(node, header, parent) + node.status = status + b.index.addNode(node) - // This node is now the end of the best chain. - tip = node + lastNode = node + i++ } - // Ensure the resulting best chain matches the stored best state - // hash and set the best chain view accordingly. - if tip == nil || tip.hash != state.hash { - var tipHash chainhash.Hash - if tip != nil { - tipHash = tip.hash - } - return AssertError(fmt.Sprintf("initChainState: block "+ - "index chain tip %s does not match stored "+ - "best state %s", tipHash, state.hash)) + // Set the best chain view to the stored best state. + tip := b.index.LookupNode(&state.hash) + if tip == nil { + return AssertError(fmt.Sprintf("initChainState: cannot find "+ + "chain tip %s in block index", state.hash)) } b.bestChain.SetTip(tip) @@ -1201,13 +1221,31 @@ func (b *BlockChain) initChainState() error { return err } + // As a final consistency check, we'll run through all the + // nodes which are ancestors of the current chain tip, and mark + // them as valid if they aren't already marked as such. This + // is a safe assumption as all the block before the current tip + // are valid by definition. + for iterNode := tip; iterNode != nil; iterNode = iterNode.parent { + // If this isn't already marked as valid in the index, then + // we'll mark it as valid now to ensure consistency once + // we're up and running. + if !iterNode.status.KnownValid() { + log.Infof("Block %v (height=%v) ancestor of "+ + "chain tip not marked as valid, "+ + "upgrading to valid for consistency", + iterNode.hash, iterNode.height) + + b.index.SetStatusFlags(iterNode, statusValid) + } + } + // Initialize the state related to the best block. blockSize := uint64(len(blockBytes)) blockWeight := uint64(GetBlockWeight(btcutil.NewBlock(&block))) numTxns := uint64(len(block.Transactions)) b.stateSnapshot = newBestState(tip, blockSize, blockWeight, numTxns, state.totalTxns, tip.CalcPastMedianTime()) - isStateInitialized = true return nil }) @@ -1215,14 +1253,29 @@ func (b *BlockChain) initChainState() error { return err } - // There is nothing more to do if the chain state was initialized. - if isStateInitialized { - return nil + // As we might have updated the index after it was loaded, we'll + // attempt to flush the index to the DB. This will only result in a + // write if the elements are dirty, so it'll usually be a noop. + return b.index.flushToDB() +} + +// deserializeBlockRow parses a value in the block index bucket into a block +// header and block status bitfield. +func deserializeBlockRow(blockRow []byte) (*wire.BlockHeader, blockStatus, error) { + buffer := bytes.NewReader(blockRow) + + var header wire.BlockHeader + err := header.Deserialize(buffer) + if err != nil { + return nil, statusNone, err } - // At this point the database has not already been initialized, so - // initialize both it and the chain state to the genesis block. - return b.createChainState() + statusByte, err := buffer.ReadByte() + if err != nil { + return nil, statusNone, err + } + + return &header, blockStatus(statusByte), nil } // dbFetchHeaderByHash uses an existing database transaction to retrieve the @@ -1273,6 +1326,51 @@ func dbFetchBlockByNode(dbTx database.Tx, node *blockNode) (*btcutil.Block, erro return block, nil } +// dbStoreBlockNode stores the block header and validation status to the block +// index bucket. This overwrites the current entry if there exists one. +func dbStoreBlockNode(dbTx database.Tx, node *blockNode) error { + // Serialize block data to be stored. + w := bytes.NewBuffer(make([]byte, 0, blockHdrSize+1)) + header := node.Header() + err := header.Serialize(w) + if err != nil { + return err + } + err = w.WriteByte(byte(node.status)) + if err != nil { + return err + } + value := w.Bytes() + + // Write block header data to block index bucket. + blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName) + key := blockIndexKey(&node.hash, uint32(node.height)) + return blockIndexBucket.Put(key, value) +} + +// dbStoreBlock stores the provided block in the database if it is not already +// there. The full block data is written to ffldb. +func dbStoreBlock(dbTx database.Tx, block *btcutil.Block) error { + hasBlock, err := dbTx.HasBlock(block.Hash()) + if err != nil { + return err + } + if hasBlock { + return nil + } + return dbTx.StoreBlock(block) +} + +// blockIndexKey generates the binary key for an entry in the block index +// bucket. The key is composed of the block height encoded as a big-endian +// 32-bit unsigned int followed by the 32 byte block hash. +func blockIndexKey(blockHash *chainhash.Hash, blockHeight uint32) []byte { + indexKey := make([]byte, chainhash.HashSize+4) + binary.BigEndian.PutUint32(indexKey[0:4], blockHeight) + copy(indexKey[4:chainhash.HashSize+4], blockHash[:]) + return indexKey +} + // BlockByHeight returns the block at the given height in the main chain. // // This function is safe for concurrent access. diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chainio_test.go b/vendor/github.com/btcsuite/btcd/blockchain/chainio_test.go index a3fcb5af..630af14e 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/chainio_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/chainio_test.go @@ -11,7 +11,6 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/database" "github.com/btcsuite/btcd/wire" ) @@ -38,19 +37,6 @@ func TestErrNotInMainChain(t *testing.T) { } } -// maybeDecompress decompresses the amount and public key script fields of the -// stxo and marks it decompressed if needed. -func (o *spentTxOut) maybeDecompress(version int32) { - // Nothing to do if it's not compressed. - if !o.compressed { - return - } - - o.amount = int64(decompressTxOutAmount(uint64(o.amount))) - o.pkScript = decompressScript(o.pkScript, version) - o.compressed = false -} - // TestStxoSerialization ensures serializing and deserializing spent transaction // output entries works as expected. func TestStxoSerialization(t *testing.T) { @@ -58,43 +44,38 @@ func TestStxoSerialization(t *testing.T) { tests := []struct { name string - stxo spentTxOut - txVersion int32 // When the txout is not fully spent. + stxo SpentTxOut serialized []byte }{ // From block 170 in main blockchain. { name: "Spends last output of coinbase", - stxo: spentTxOut{ - amount: 5000000000, - pkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac"), - isCoinBase: true, - height: 9, - version: 1, + stxo: SpentTxOut{ + Amount: 5000000000, + PkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac"), + IsCoinBase: true, + Height: 9, }, - serialized: hexToBytes("1301320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"), + serialized: hexToBytes("1300320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"), }, // Adapted from block 100025 in main blockchain. { name: "Spends last output of non coinbase", - stxo: spentTxOut{ - amount: 13761000000, - pkScript: hexToBytes("76a914b2fb57eadf61e106a100a7445a8c3f67898841ec88ac"), - isCoinBase: false, - height: 100024, - version: 1, + stxo: SpentTxOut{ + Amount: 13761000000, + PkScript: hexToBytes("76a914b2fb57eadf61e106a100a7445a8c3f67898841ec88ac"), + IsCoinBase: false, + Height: 100024, }, - serialized: hexToBytes("8b99700186c64700b2fb57eadf61e106a100a7445a8c3f67898841ec"), + serialized: hexToBytes("8b99700086c64700b2fb57eadf61e106a100a7445a8c3f67898841ec"), }, // Adapted from block 100025 in main blockchain. { - name: "Does not spend last output", - stxo: spentTxOut{ - amount: 34405000000, - pkScript: hexToBytes("76a9146edbc6c4d31bae9f1ccc38538a114bf42de65e8688ac"), - version: 1, + name: "Does not spend last output, legacy format", + stxo: SpentTxOut{ + Amount: 34405000000, + PkScript: hexToBytes("76a9146edbc6c4d31bae9f1ccc38538a114bf42de65e8688ac"), }, - txVersion: 1, serialized: hexToBytes("0091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e86"), }, } @@ -104,7 +85,7 @@ func TestStxoSerialization(t *testing.T) { // actually serializing it is calculated properly. gotSize := spentTxOutSerializeSize(&test.stxo) if gotSize != len(test.serialized) { - t.Errorf("spentTxOutSerializeSize (%s): did not get "+ + t.Errorf("SpentTxOutSerializeSize (%s): did not get "+ "expected size - got %d, want %d", test.name, gotSize, len(test.serialized)) continue @@ -129,15 +110,13 @@ func TestStxoSerialization(t *testing.T) { // Ensure the serialized bytes are decoded back to the expected // stxo. - var gotStxo spentTxOut - gotBytesRead, err := decodeSpentTxOut(test.serialized, &gotStxo, - test.txVersion) + var gotStxo SpentTxOut + gotBytesRead, err := decodeSpentTxOut(test.serialized, &gotStxo) if err != nil { t.Errorf("decodeSpentTxOut (%s): unexpected error: %v", test.name, err) continue } - gotStxo.maybeDecompress(test.stxo.version) if !reflect.DeepEqual(gotStxo, test.stxo) { t.Errorf("decodeSpentTxOut (%s) mismatched entries - "+ "got %v, want %v", test.name, gotStxo, test.stxo) @@ -159,53 +138,43 @@ func TestStxoDecodeErrors(t *testing.T) { tests := []struct { name string - stxo spentTxOut - txVersion int32 // When the txout is not fully spent. + stxo SpentTxOut serialized []byte bytesRead int // Expected number of bytes read. errType error }{ { name: "nothing serialized", - stxo: spentTxOut{}, + stxo: SpentTxOut{}, serialized: hexToBytes(""), errType: errDeserialize(""), bytesRead: 0, }, { - name: "no data after header code w/o version", - stxo: spentTxOut{}, + name: "no data after header code w/o reserved", + stxo: SpentTxOut{}, serialized: hexToBytes("00"), errType: errDeserialize(""), bytesRead: 1, }, { - name: "no data after header code with version", - stxo: spentTxOut{}, + name: "no data after header code with reserved", + stxo: SpentTxOut{}, serialized: hexToBytes("13"), errType: errDeserialize(""), bytesRead: 1, }, { - name: "no data after version", - stxo: spentTxOut{}, - serialized: hexToBytes("1301"), + name: "no data after reserved", + stxo: SpentTxOut{}, + serialized: hexToBytes("1300"), errType: errDeserialize(""), bytesRead: 2, }, - { - name: "no serialized tx version and passed -1", - stxo: spentTxOut{}, - txVersion: -1, - serialized: hexToBytes("003205"), - errType: AssertError(""), - bytesRead: 1, - }, { name: "incomplete compressed txout", - stxo: spentTxOut{}, - txVersion: 1, - serialized: hexToBytes("0032"), + stxo: SpentTxOut{}, + serialized: hexToBytes("1332"), errType: errDeserialize(""), bytesRead: 2, }, @@ -214,7 +183,7 @@ func TestStxoDecodeErrors(t *testing.T) { for _, test := range tests { // Ensure the expected error type is returned. gotBytesRead, err := decodeSpentTxOut(test.serialized, - &test.stxo, test.txVersion) + &test.stxo) if reflect.TypeOf(err) != reflect.TypeOf(test.errType) { t.Errorf("decodeSpentTxOut (%s): expected error type "+ "does not match - got %T, want %T", test.name, @@ -239,9 +208,8 @@ func TestSpendJournalSerialization(t *testing.T) { tests := []struct { name string - entry []spentTxOut + entry []SpentTxOut blockTxns []*wire.MsgTx - utxoView *UtxoViewpoint serialized []byte }{ // From block 2 in main blockchain. @@ -249,18 +217,16 @@ func TestSpendJournalSerialization(t *testing.T) { name: "No spends", entry: nil, blockTxns: nil, - utxoView: NewUtxoViewpoint(), serialized: nil, }, // From block 170 in main blockchain. { name: "One tx with one input spends last output of coinbase", - entry: []spentTxOut{{ - amount: 5000000000, - pkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac"), - isCoinBase: true, - height: 9, - version: 1, + entry: []SpentTxOut{{ + Amount: 5000000000, + PkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac"), + IsCoinBase: true, + Height: 9, }}, blockTxns: []*wire.MsgTx{{ // Coinbase omitted. Version: 1, @@ -281,22 +247,21 @@ func TestSpendJournalSerialization(t *testing.T) { }}, LockTime: 0, }}, - utxoView: NewUtxoViewpoint(), - serialized: hexToBytes("1301320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"), + serialized: hexToBytes("1300320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"), }, // Adapted from block 100025 in main blockchain. { name: "Two txns when one spends last output, one doesn't", - entry: []spentTxOut{{ - amount: 34405000000, - pkScript: hexToBytes("76a9146edbc6c4d31bae9f1ccc38538a114bf42de65e8688ac"), - version: 1, + entry: []SpentTxOut{{ + Amount: 34405000000, + PkScript: hexToBytes("76a9146edbc6c4d31bae9f1ccc38538a114bf42de65e8688ac"), + IsCoinBase: false, + Height: 100024, }, { - amount: 13761000000, - pkScript: hexToBytes("76a914b2fb57eadf61e106a100a7445a8c3f67898841ec88ac"), - isCoinBase: false, - height: 100024, - version: 1, + Amount: 13761000000, + PkScript: hexToBytes("76a914b2fb57eadf61e106a100a7445a8c3f67898841ec88ac"), + IsCoinBase: false, + Height: 100024, }}, blockTxns: []*wire.MsgTx{{ // Coinbase omitted. Version: 1, @@ -335,73 +300,7 @@ func TestSpendJournalSerialization(t *testing.T) { }}, LockTime: 0, }}, - utxoView: &UtxoViewpoint{entries: map[chainhash.Hash]*UtxoEntry{ - *newHashFromStr("c0ed017828e59ad5ed3cf70ee7c6fb0f426433047462477dc7a5d470f987a537"): { - version: 1, - isCoinBase: false, - blockHeight: 100024, - sparseOutputs: map[uint32]*utxoOutput{ - 1: { - amount: 34405000000, - pkScript: hexToBytes("76a9142084541c3931677527a7eafe56fd90207c344eb088ac"), - }, - }, - }, - }}, - serialized: hexToBytes("8b99700186c64700b2fb57eadf61e106a100a7445a8c3f67898841ec0091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e86"), - }, - // Hand crafted. - { - name: "One tx, two inputs from same tx, neither spend last output", - entry: []spentTxOut{{ - amount: 165125632, - pkScript: hexToBytes("51"), - version: 1, - }, { - amount: 154370000, - pkScript: hexToBytes("51"), - version: 1, - }}, - blockTxns: []*wire.MsgTx{{ // Coinbase omitted. - Version: 1, - TxIn: []*wire.TxIn{{ - PreviousOutPoint: wire.OutPoint{ - Hash: *newHashFromStr("c0ed017828e59ad5ed3cf70ee7c6fb0f426433047462477dc7a5d470f987a537"), - Index: 1, - }, - SignatureScript: hexToBytes(""), - Sequence: 0xffffffff, - }, { - PreviousOutPoint: wire.OutPoint{ - Hash: *newHashFromStr("c0ed017828e59ad5ed3cf70ee7c6fb0f426433047462477dc7a5d470f987a537"), - Index: 2, - }, - SignatureScript: hexToBytes(""), - Sequence: 0xffffffff, - }}, - TxOut: []*wire.TxOut{{ - Value: 165125632, - PkScript: hexToBytes("51"), - }, { - Value: 154370000, - PkScript: hexToBytes("51"), - }}, - LockTime: 0, - }}, - utxoView: &UtxoViewpoint{entries: map[chainhash.Hash]*UtxoEntry{ - *newHashFromStr("c0ed017828e59ad5ed3cf70ee7c6fb0f426433047462477dc7a5d470f987a537"): { - version: 1, - isCoinBase: false, - blockHeight: 100000, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - amount: 165712179, - pkScript: hexToBytes("51"), - }, - }, - }, - }}, - serialized: hexToBytes("0087bc3707510084c3d19a790751"), + serialized: hexToBytes("8b99700086c64700b2fb57eadf61e106a100a7445a8c3f67898841ec8b99700091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e86"), }, } @@ -417,16 +316,12 @@ func TestSpendJournalSerialization(t *testing.T) { // Deserialize to a spend journal entry. gotEntry, err := deserializeSpendJournalEntry(test.serialized, - test.blockTxns, test.utxoView) + test.blockTxns) if err != nil { t.Errorf("deserializeSpendJournalEntry #%d (%s) "+ "unexpected error: %v", i, test.name, err) continue } - for stxoIdx := range gotEntry { - stxo := &gotEntry[stxoIdx] - stxo.maybeDecompress(test.entry[stxoIdx].version) - } // Ensure that the deserialized spend journal entry has the // correct properties. @@ -447,7 +342,6 @@ func TestSpendJournalErrors(t *testing.T) { tests := []struct { name string blockTxns []*wire.MsgTx - utxoView *UtxoViewpoint serialized []byte errType error }{ @@ -466,7 +360,6 @@ func TestSpendJournalErrors(t *testing.T) { }}, LockTime: 0, }}, - utxoView: NewUtxoViewpoint(), serialized: hexToBytes(""), errType: AssertError(""), }, @@ -484,7 +377,6 @@ func TestSpendJournalErrors(t *testing.T) { }}, LockTime: 0, }}, - utxoView: NewUtxoViewpoint(), serialized: hexToBytes("1301320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a"), errType: errDeserialize(""), }, @@ -494,7 +386,7 @@ func TestSpendJournalErrors(t *testing.T) { // Ensure the expected error type is returned and the returned // slice is nil. stxos, err := deserializeSpendJournalEntry(test.serialized, - test.blockTxns, test.utxoView) + test.blockTxns) if reflect.TypeOf(err) != reflect.TypeOf(test.errType) { t.Errorf("deserializeSpendJournalEntry (%s): expected "+ "error type does not match - got %T, want %T", @@ -521,186 +413,52 @@ func TestUtxoSerialization(t *testing.T) { serialized []byte }{ // From tx in main blockchain: - // 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 + // 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098:0 { - name: "Only output 0, coinbase", + name: "height 1, coinbase", entry: &UtxoEntry{ - version: 1, - isCoinBase: true, + amount: 5000000000, + pkScript: hexToBytes("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac"), blockHeight: 1, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - amount: 5000000000, - pkScript: hexToBytes("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac"), - }, - }, + packedFlags: tfCoinBase, }, - serialized: hexToBytes("010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52"), + serialized: hexToBytes("03320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52"), }, // From tx in main blockchain: - // 8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb + // 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098:0 { - name: "Only output 1, not coinbase", + name: "height 1, coinbase, spent", entry: &UtxoEntry{ - version: 1, - isCoinBase: false, - blockHeight: 100001, - sparseOutputs: map[uint32]*utxoOutput{ - 1: { - amount: 1000000, - pkScript: hexToBytes("76a914ee8bd501094a7d5ca318da2506de35e1cb025ddc88ac"), - }, - }, - }, - serialized: hexToBytes("01858c21040700ee8bd501094a7d5ca318da2506de35e1cb025ddc"), - }, - // Adapted from tx in main blockchain: - // df3f3f442d9699857f7f49de4ff0b5d0f3448bec31cdc7b5bf6d25f2abd637d5 - { - name: "Only output 2, coinbase", - entry: &UtxoEntry{ - version: 1, - isCoinBase: true, - blockHeight: 99004, - sparseOutputs: map[uint32]*utxoOutput{ - 2: { - amount: 100937281, - pkScript: hexToBytes("76a914da33f77cee27c2a975ed5124d7e4f7f97513510188ac"), - }, - }, - }, - serialized: hexToBytes("0185843c010182b095bf4100da33f77cee27c2a975ed5124d7e4f7f975135101"), - }, - // Adapted from tx in main blockchain: - // 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f - { - name: "outputs 0 and 2 not coinbase", - entry: &UtxoEntry{ - version: 1, - isCoinBase: false, - blockHeight: 113931, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - amount: 20000000, - pkScript: hexToBytes("76a914e2ccd6ec7c6e2e581349c77e067385fa8236bf8a88ac"), - }, - 2: { - amount: 15000000, - pkScript: hexToBytes("76a914b8025be1b3efc63b0ad48e7f9f10e87544528d5888ac"), - }, - }, - }, - serialized: hexToBytes("0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58"), - }, - // Adapted from tx in main blockchain: - // 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f - { - name: "outputs 0 and 2, not coinbase, 1 marked spent", - entry: &UtxoEntry{ - version: 1, - isCoinBase: false, - blockHeight: 113931, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - amount: 20000000, - pkScript: hexToBytes("76a914e2ccd6ec7c6e2e581349c77e067385fa8236bf8a88ac"), - }, - 1: { // This won't be serialized. - spent: true, - amount: 1000000, - pkScript: hexToBytes("76a914e43031c3e46f20bf1ccee9553ce815de5a48467588ac"), - }, - 2: { - amount: 15000000, - pkScript: hexToBytes("76a914b8025be1b3efc63b0ad48e7f9f10e87544528d5888ac"), - }, - }, - }, - serialized: hexToBytes("0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58"), - }, - // Adapted from tx in main blockchain: - // 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f - { - name: "outputs 0 and 2, not coinbase, output 2 compressed", - entry: &UtxoEntry{ - version: 1, - isCoinBase: false, - blockHeight: 113931, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - amount: 20000000, - pkScript: hexToBytes("76a914e2ccd6ec7c6e2e581349c77e067385fa8236bf8a88ac"), - }, - 2: { - // Uncompressed Amount: 15000000 - // Uncompressed PkScript: 76a914b8025be1b3efc63b0ad48e7f9f10e87544528d5888ac - compressed: true, - amount: 137, - pkScript: hexToBytes("00b8025be1b3efc63b0ad48e7f9f10e87544528d58"), - }, - }, - }, - serialized: hexToBytes("0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58"), - }, - // Adapted from tx in main blockchain: - // 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f - { - name: "outputs 0 and 2, not coinbase, output 2 compressed, packed indexes reversed", - entry: &UtxoEntry{ - version: 1, - isCoinBase: false, - blockHeight: 113931, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - amount: 20000000, - pkScript: hexToBytes("76a914e2ccd6ec7c6e2e581349c77e067385fa8236bf8a88ac"), - }, - 2: { - // Uncompressed Amount: 15000000 - // Uncompressed PkScript: 76a914b8025be1b3efc63b0ad48e7f9f10e87544528d5888ac - compressed: true, - amount: 137, - pkScript: hexToBytes("00b8025be1b3efc63b0ad48e7f9f10e87544528d58"), - }, - }, - }, - serialized: hexToBytes("0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58"), - }, - // From tx in main blockchain: - // 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 - { - name: "Only output 0, coinbase, fully spent", - entry: &UtxoEntry{ - version: 1, - isCoinBase: true, + amount: 5000000000, + pkScript: hexToBytes("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac"), blockHeight: 1, - sparseOutputs: map[uint32]*utxoOutput{ - 0: { - spent: true, - amount: 5000000000, - pkScript: hexToBytes("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac"), - }, - }, + packedFlags: tfCoinBase | tfSpent, }, serialized: nil, }, - // Adapted from tx in main blockchain: - // 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620 + // From tx in main blockchain: + // 8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb:1 { - name: "Only output 22, not coinbase", + name: "height 100001, not coinbase", entry: &UtxoEntry{ - version: 1, - isCoinBase: false, - blockHeight: 338156, - sparseOutputs: map[uint32]*utxoOutput{ - 22: { - spent: false, - amount: 366875659, - pkScript: hexToBytes("a9141dd46a006572d820e448e12d2bbb38640bc718e687"), - }, - }, + amount: 1000000, + pkScript: hexToBytes("76a914ee8bd501094a7d5ca318da2506de35e1cb025ddc88ac"), + blockHeight: 100001, + packedFlags: 0, }, - serialized: hexToBytes("0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6"), + serialized: hexToBytes("8b99420700ee8bd501094a7d5ca318da2506de35e1cb025ddc"), + }, + // From tx in main blockchain: + // 8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb:1 + { + name: "height 100001, not coinbase, spent", + entry: &UtxoEntry{ + amount: 1000000, + pkScript: hexToBytes("76a914ee8bd501094a7d5ca318da2506de35e1cb025ddc88ac"), + blockHeight: 100001, + packedFlags: tfSpent, + }, + serialized: nil, }, } @@ -719,9 +477,9 @@ func TestUtxoSerialization(t *testing.T) { continue } - // Don't try to deserialize if the test entry was fully spent - // since it will have a nil serialization. - if test.entry.IsFullySpent() { + // Don't try to deserialize if the test entry was spent since it + // will have a nil serialization. + if test.entry.IsSpent() { continue } @@ -733,12 +491,33 @@ func TestUtxoSerialization(t *testing.T) { continue } - // Ensure that the deserialized utxo entry has the same - // properties for the containing transaction and block height. - if utxoEntry.Version() != test.entry.Version() { + // The deserialized entry must not be marked spent since unspent + // entries are not serialized. + if utxoEntry.IsSpent() { + t.Errorf("deserializeUtxoEntry #%d (%s) output should "+ + "not be marked spent", i, test.name) + continue + } + + // Ensure the deserialized entry has the same properties as the + // ones in the test entry. + if utxoEntry.Amount() != test.entry.Amount() { t.Errorf("deserializeUtxoEntry #%d (%s) mismatched "+ - "version: got %d, want %d", i, test.name, - utxoEntry.Version(), test.entry.Version()) + "amounts: got %d, want %d", i, test.name, + utxoEntry.Amount(), test.entry.Amount()) + continue + } + + if !bytes.Equal(utxoEntry.PkScript(), test.entry.PkScript()) { + t.Errorf("deserializeUtxoEntry #%d (%s) mismatched "+ + "scripts: got %x, want %x", i, test.name, + utxoEntry.PkScript(), test.entry.PkScript()) + continue + } + if utxoEntry.BlockHeight() != test.entry.BlockHeight() { + t.Errorf("deserializeUtxoEntry #%d (%s) mismatched "+ + "block height: got %d, want %d", i, test.name, + utxoEntry.BlockHeight(), test.entry.BlockHeight()) continue } if utxoEntry.IsCoinBase() != test.entry.IsCoinBase() { @@ -747,71 +526,6 @@ func TestUtxoSerialization(t *testing.T) { utxoEntry.IsCoinBase(), test.entry.IsCoinBase()) continue } - if utxoEntry.BlockHeight() != test.entry.BlockHeight() { - t.Errorf("deserializeUtxoEntry #%d (%s) mismatched "+ - "block height: got %d, want %d", i, test.name, - utxoEntry.BlockHeight(), - test.entry.BlockHeight()) - continue - } - if utxoEntry.IsFullySpent() != test.entry.IsFullySpent() { - t.Errorf("deserializeUtxoEntry #%d (%s) mismatched "+ - "fully spent: got %v, want %v", i, test.name, - utxoEntry.IsFullySpent(), - test.entry.IsFullySpent()) - continue - } - - // Ensure all of the outputs in the test entry match the - // spentness of the output in the deserialized entry and the - // deserialized entry does not contain any additional utxos. - var numUnspent int - for outputIndex := range test.entry.sparseOutputs { - gotSpent := utxoEntry.IsOutputSpent(outputIndex) - wantSpent := test.entry.IsOutputSpent(outputIndex) - if !wantSpent { - numUnspent++ - } - if gotSpent != wantSpent { - t.Errorf("deserializeUtxoEntry #%d (%s) output "+ - "#%d: mismatched spent: got %v, want "+ - "%v", i, test.name, outputIndex, - gotSpent, wantSpent) - continue - - } - } - if len(utxoEntry.sparseOutputs) != numUnspent { - t.Errorf("deserializeUtxoEntry #%d (%s): mismatched "+ - "number of unspent outputs: got %d, want %d", i, - test.name, len(utxoEntry.sparseOutputs), - numUnspent) - continue - } - - // Ensure all of the amounts and scripts of the utxos in the - // deserialized entry match the ones in the test entry. - for outputIndex := range utxoEntry.sparseOutputs { - gotAmount := utxoEntry.AmountByIndex(outputIndex) - wantAmount := test.entry.AmountByIndex(outputIndex) - if gotAmount != wantAmount { - t.Errorf("deserializeUtxoEntry #%d (%s) "+ - "output #%d: mismatched amounts: got "+ - "%d, want %d", i, test.name, - outputIndex, gotAmount, wantAmount) - continue - } - - gotPkScript := utxoEntry.PkScriptByIndex(outputIndex) - wantPkScript := test.entry.PkScriptByIndex(outputIndex) - if !bytes.Equal(gotPkScript, wantPkScript) { - t.Errorf("deserializeUtxoEntry #%d (%s) "+ - "output #%d mismatched scripts: got "+ - "%x, want %x", i, test.name, - outputIndex, gotPkScript, wantPkScript) - continue - } - } } } @@ -821,23 +535,21 @@ func TestUtxoEntryHeaderCodeErrors(t *testing.T) { t.Parallel() tests := []struct { - name string - entry *UtxoEntry - code uint64 - bytesRead int // Expected number of bytes read. - errType error + name string + entry *UtxoEntry + code uint64 + errType error }{ { - name: "Force assertion due to fully spent tx", - entry: &UtxoEntry{}, - errType: AssertError(""), - bytesRead: 0, + name: "Force assertion due to spent output", + entry: &UtxoEntry{packedFlags: tfSpent}, + errType: AssertError(""), }, } for _, test := range tests { // Ensure the expected error type is returned and the code is 0. - code, gotBytesRead, err := utxoEntryHeaderCode(test.entry, 0) + code, err := utxoEntryHeaderCode(test.entry) if reflect.TypeOf(err) != reflect.TypeOf(test.errType) { t.Errorf("utxoEntryHeaderCode (%s): expected error "+ "type does not match - got %T, want %T", @@ -849,14 +561,6 @@ func TestUtxoEntryHeaderCodeErrors(t *testing.T) { "on error - got %d, want 0", test.name, code) continue } - - // Ensure the expected number of bytes read is returned. - if gotBytesRead != test.bytesRead { - t.Errorf("utxoEntryHeaderCode (%s): unexpected number "+ - "of bytes read - got %d, want %d", test.name, - gotBytesRead, test.bytesRead) - continue - } } } @@ -870,29 +574,14 @@ func TestUtxoEntryDeserializeErrors(t *testing.T) { serialized []byte errType error }{ - { - name: "no data after version", - serialized: hexToBytes("01"), - errType: errDeserialize(""), - }, - { - name: "no data after block height", - serialized: hexToBytes("0101"), - errType: errDeserialize(""), - }, { name: "no data after header code", - serialized: hexToBytes("010102"), - errType: errDeserialize(""), - }, - { - name: "not enough bytes for unspentness bitmap", - serialized: hexToBytes("01017800"), + serialized: hexToBytes("02"), errType: errDeserialize(""), }, { name: "incomplete compressed txout", - serialized: hexToBytes("01010232"), + serialized: hexToBytes("0232"), errType: errDeserialize(""), }, } diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chainview_test.go b/vendor/github.com/btcsuite/btcd/blockchain/chainview_test.go index 964da607..c59004fd 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/chainview_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/chainview_test.go @@ -27,16 +27,11 @@ func chainedNodes(parent *blockNode, numNodes int) []*blockNode { // This is invalid, but all that is needed is enough to get the // synthetic tests to work. header := wire.BlockHeader{Nonce: testNoncePrng.Uint32()} - height := int32(0) if tip != nil { header.PrevBlock = tip.hash - height = tip.height + 1 } - node := newBlockNode(&header, height) - node.parent = tip - tip = node - - nodes[i] = node + nodes[i] = newBlockNode(&header, tip) + tip = nodes[i] } return nodes } @@ -74,7 +69,7 @@ func zipLocators(locators ...BlockLocator) BlockLocator { } // TestChainView ensures all of the exported functionality of chain views works -// as intended with the expection of some special cases which are handled in +// as intended with the exception of some special cases which are handled in // other tests. func TestChainView(t *testing.T) { // Construct a synthetic block index consisting of the following diff --git a/vendor/github.com/btcsuite/btcd/blockchain/common_test.go b/vendor/github.com/btcsuite/btcd/blockchain/common_test.go index 38191c25..dd392a66 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/common_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/common_test.go @@ -190,10 +190,10 @@ func chainSetup(dbName string, params *chaincfg.Params) (*BlockChain, func(), er // loadUtxoView returns a utxo view loaded from a file. func loadUtxoView(filename string) (*UtxoViewpoint, error) { // The utxostore file format is: - // + // // - // The serialized utxo len is a little endian uint32 and the serialized - // utxo uses the format described in chainio.go. + // The output index and serialized utxo len are little endian uint32s + // and the serialized utxo uses the format described in chainio.go. filename = filepath.Join("testdata", filename) fi, err := os.Open(filename) @@ -223,7 +223,14 @@ func loadUtxoView(filename string) (*UtxoViewpoint, error) { return nil, err } - // Num of serialize utxo entry bytes. + // Output index of the utxo entry. + var index uint32 + err = binary.Read(r, binary.LittleEndian, &index) + if err != nil { + return nil, err + } + + // Num of serialized utxo entry bytes. var numBytes uint32 err = binary.Read(r, binary.LittleEndian, &numBytes) if err != nil { @@ -238,16 +245,98 @@ func loadUtxoView(filename string) (*UtxoViewpoint, error) { } // Deserialize it and add it to the view. - utxoEntry, err := deserializeUtxoEntry(serialized) + entry, err := deserializeUtxoEntry(serialized) if err != nil { return nil, err } - view.Entries()[hash] = utxoEntry + view.Entries()[wire.OutPoint{Hash: hash, Index: index}] = entry } return view, nil } +// convertUtxoStore reads a utxostore from the legacy format and writes it back +// out using the latest format. It is only useful for converting utxostore data +// used in the tests, which has already been done. However, the code is left +// available for future reference. +func convertUtxoStore(r io.Reader, w io.Writer) error { + // The old utxostore file format was: + // + // + // The serialized utxo len was a little endian uint32 and the serialized + // utxo uses the format described in upgrade.go. + + littleEndian := binary.LittleEndian + for { + // Hash of the utxo entry. + var hash chainhash.Hash + _, err := io.ReadAtLeast(r, hash[:], len(hash[:])) + if err != nil { + // Expected EOF at the right offset. + if err == io.EOF { + break + } + return err + } + + // Num of serialized utxo entry bytes. + var numBytes uint32 + err = binary.Read(r, littleEndian, &numBytes) + if err != nil { + return err + } + + // Serialized utxo entry. + serialized := make([]byte, numBytes) + _, err = io.ReadAtLeast(r, serialized, int(numBytes)) + if err != nil { + return err + } + + // Deserialize the entry. + entries, err := deserializeUtxoEntryV0(serialized) + if err != nil { + return err + } + + // Loop through all of the utxos and write them out in the new + // format. + for outputIdx, entry := range entries { + // Reserialize the entries using the new format. + serialized, err := serializeUtxoEntry(entry) + if err != nil { + return err + } + + // Write the hash of the utxo entry. + _, err = w.Write(hash[:]) + if err != nil { + return err + } + + // Write the output index of the utxo entry. + err = binary.Write(w, littleEndian, outputIdx) + if err != nil { + return err + } + + // Write num of serialized utxo entry bytes. + err = binary.Write(w, littleEndian, uint32(len(serialized))) + if err != nil { + return err + } + + // Write the serialized utxo. + _, err = w.Write(serialized) + if err != nil { + return err + } + } + } + + return nil +} + // TstSetCoinbaseMaturity makes the ability to set the coinbase maturity // available when running tests. func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) { @@ -261,7 +350,7 @@ func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) { func newFakeChain(params *chaincfg.Params) *BlockChain { // Create a genesis block node and block index index populated with it // for use when creating the fake chain below. - node := newBlockNode(¶ms.GenesisBlock.Header, 0) + node := newBlockNode(¶ms.GenesisBlock.Header, nil) index := newBlockIndex(nil, params) index.AddNode(node) @@ -291,8 +380,5 @@ func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp t Bits: bits, Timestamp: timestamp, } - node := newBlockNode(header, parent.height+1) - node.parent = parent - node.workSum.Add(parent.workSum, node.workSum) - return node + return newBlockNode(header, parent) } diff --git a/vendor/github.com/btcsuite/btcd/blockchain/compress.go b/vendor/github.com/btcsuite/btcd/blockchain/compress.go index 87328d0f..611b9f09 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/compress.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/compress.go @@ -241,7 +241,7 @@ func isPubKey(script []byte) (bool, []byte) { // compressedScriptSize returns the number of bytes the passed script would take // when encoded with the domain specific compression algorithm described above. -func compressedScriptSize(pkScript []byte, version int32) int { +func compressedScriptSize(pkScript []byte) int { // Pay-to-pubkey-hash script. if valid, _ := isPubKeyHash(pkScript); valid { return 21 @@ -268,7 +268,7 @@ func compressedScriptSize(pkScript []byte, version int32) int { // script, possibly followed by other data, and returns the number of bytes it // occupies taking into account the special encoding of the script size by the // domain specific compression algorithm described above. -func decodeCompressedScriptSize(serialized []byte, version int32) int { +func decodeCompressedScriptSize(serialized []byte) int { scriptSize, bytesRead := deserializeVLQ(serialized) if bytesRead == 0 { return 0 @@ -296,7 +296,7 @@ func decodeCompressedScriptSize(serialized []byte, version int32) int { // target byte slice. The target byte slice must be at least large enough to // handle the number of bytes returned by the compressedScriptSize function or // it will panic. -func putCompressedScript(target, pkScript []byte, version int32) int { +func putCompressedScript(target, pkScript []byte) int { // Pay-to-pubkey-hash script. if valid, hash := isPubKeyHash(pkScript); valid { target[0] = cstPayToPubKeyHash @@ -344,7 +344,7 @@ func putCompressedScript(target, pkScript []byte, version int32) int { // NOTE: The script parameter must already have been proven to be long enough // to contain the number of bytes returned by decodeCompressedScriptSize or it // will panic. This is acceptable since it is only an internal function. -func decompressScript(compressedPkScript []byte, version int32) []byte { +func decompressScript(compressedPkScript []byte) []byte { // In practice this function will not be called with a zero-length or // nil script since the nil script encoding includes the length, however // the code below assumes the length exists, so just return nil now if @@ -542,43 +542,27 @@ func decompressTxOutAmount(amount uint64) uint64 { // ----------------------------------------------------------------------------- // compressedTxOutSize returns the number of bytes the passed transaction output -// fields would take when encoded with the format described above. The -// preCompressed flag indicates the provided amount and script are already -// compressed. This is useful since loaded utxo entries are not decompressed -// until the output is accessed. -func compressedTxOutSize(amount uint64, pkScript []byte, version int32, preCompressed bool) int { - if preCompressed { - return serializeSizeVLQ(amount) + len(pkScript) - } - +// fields would take when encoded with the format described above. +func compressedTxOutSize(amount uint64, pkScript []byte) int { return serializeSizeVLQ(compressTxOutAmount(amount)) + - compressedScriptSize(pkScript, version) + compressedScriptSize(pkScript) } -// putCompressedTxOut potentially compresses the passed amount and script -// according to their domain specific compression algorithms and encodes them -// directly into the passed target byte slice with the format described above. -// The preCompressed flag indicates the provided amount and script are already -// compressed in which case the values are not modified. This is useful since -// loaded utxo entries are not decompressed until the output is accessed. The -// target byte slice must be at least large enough to handle the number of bytes -// returned by the compressedTxOutSize function or it will panic. -func putCompressedTxOut(target []byte, amount uint64, pkScript []byte, version int32, preCompressed bool) int { - if preCompressed { - offset := putVLQ(target, amount) - copy(target[offset:], pkScript) - return offset + len(pkScript) - } - +// putCompressedTxOut compresses the passed amount and script according to their +// domain specific compression algorithms and encodes them directly into the +// passed target byte slice with the format described above. The target byte +// slice must be at least large enough to handle the number of bytes returned by +// the compressedTxOutSize function or it will panic. +func putCompressedTxOut(target []byte, amount uint64, pkScript []byte) int { offset := putVLQ(target, compressTxOutAmount(amount)) - offset += putCompressedScript(target[offset:], pkScript, version) + offset += putCompressedScript(target[offset:], pkScript) return offset } // decodeCompressedTxOut decodes the passed compressed txout, possibly followed -// by other data, into its compressed amount and compressed script and returns -// them along with the number of bytes they occupied. -func decodeCompressedTxOut(serialized []byte, version int32) (uint64, []byte, int, error) { +// by other data, into its uncompressed amount and script and returns them along +// with the number of bytes they occupied prior to decompression. +func decodeCompressedTxOut(serialized []byte) (uint64, []byte, int, error) { // Deserialize the compressed amount and ensure there are bytes // remaining for the compressed script. compressedAmount, bytesRead := deserializeVLQ(serialized) @@ -589,15 +573,14 @@ func decodeCompressedTxOut(serialized []byte, version int32) (uint64, []byte, in // Decode the compressed script size and ensure there are enough bytes // left in the slice for it. - scriptSize := decodeCompressedScriptSize(serialized[bytesRead:], version) + scriptSize := decodeCompressedScriptSize(serialized[bytesRead:]) if len(serialized[bytesRead:]) < scriptSize { return 0, nil, bytesRead, errDeserialize("unexpected end of " + "data after script size") } - // Make a copy of the compressed script so the original serialized data - // can be released as soon as possible. - compressedScript := make([]byte, scriptSize) - copy(compressedScript, serialized[bytesRead:bytesRead+scriptSize]) - return compressedAmount, compressedScript, bytesRead + scriptSize, nil + // Decompress and return the amount and script. + amount := decompressTxOutAmount(compressedAmount) + script := decompressScript(serialized[bytesRead : bytesRead+scriptSize]) + return amount, script, bytesRead + scriptSize, nil } diff --git a/vendor/github.com/btcsuite/btcd/blockchain/compress_test.go b/vendor/github.com/btcsuite/btcd/blockchain/compress_test.go index 10a7747b..b1a6ff27 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/compress_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/compress_test.go @@ -109,79 +109,66 @@ func TestScriptCompression(t *testing.T) { tests := []struct { name string - version int32 uncompressed []byte compressed []byte }{ { name: "nil", - version: 1, uncompressed: nil, compressed: hexToBytes("06"), }, { name: "pay-to-pubkey-hash 1", - version: 1, uncompressed: hexToBytes("76a9141018853670f9f3b0582c5b9ee8ce93764ac32b9388ac"), compressed: hexToBytes("001018853670f9f3b0582c5b9ee8ce93764ac32b93"), }, { name: "pay-to-pubkey-hash 2", - version: 1, uncompressed: hexToBytes("76a914e34cce70c86373273efcc54ce7d2a491bb4a0e8488ac"), compressed: hexToBytes("00e34cce70c86373273efcc54ce7d2a491bb4a0e84"), }, { name: "pay-to-script-hash 1", - version: 1, uncompressed: hexToBytes("a914da1745e9b549bd0bfa1a569971c77eba30cd5a4b87"), compressed: hexToBytes("01da1745e9b549bd0bfa1a569971c77eba30cd5a4b"), }, { name: "pay-to-script-hash 2", - version: 1, uncompressed: hexToBytes("a914f815b036d9bbbce5e9f2a00abd1bf3dc91e9551087"), compressed: hexToBytes("01f815b036d9bbbce5e9f2a00abd1bf3dc91e95510"), }, { name: "pay-to-pubkey compressed 0x02", - version: 1, uncompressed: hexToBytes("2102192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4ac"), compressed: hexToBytes("02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), }, { name: "pay-to-pubkey compressed 0x03", - version: 1, uncompressed: hexToBytes("2103b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65ac"), compressed: hexToBytes("03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), }, { name: "pay-to-pubkey uncompressed 0x04 even", - version: 1, uncompressed: hexToBytes("4104192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b40d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453eac"), compressed: hexToBytes("04192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), }, { name: "pay-to-pubkey uncompressed 0x04 odd", - version: 1, uncompressed: hexToBytes("410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac"), compressed: hexToBytes("0511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"), }, { name: "pay-to-pubkey invalid pubkey", - version: 1, uncompressed: hexToBytes("3302aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"), compressed: hexToBytes("293302aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"), }, { name: "null data", - version: 1, uncompressed: hexToBytes("6a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), compressed: hexToBytes("286a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), }, { name: "requires 2 size bytes - data push 200 bytes", - version: 1, uncompressed: append(hexToBytes("4cc8"), bytes.Repeat([]byte{0x00}, 200)...), // [0x80, 0x50] = 208 as a variable length quantity // [0x4c, 0xc8] = OP_PUSHDATA1 200 @@ -192,7 +179,7 @@ func TestScriptCompression(t *testing.T) { for _, test := range tests { // Ensure the function to calculate the serialized size without // actually serializing the value is calculated properly. - gotSize := compressedScriptSize(test.uncompressed, test.version) + gotSize := compressedScriptSize(test.uncompressed) if gotSize != len(test.compressed) { t.Errorf("compressedScriptSize (%s): did not get "+ "expected size - got %d, want %d", test.name, @@ -203,7 +190,7 @@ func TestScriptCompression(t *testing.T) { // Ensure the script compresses to the expected bytes. gotCompressed := make([]byte, gotSize) gotBytesWritten := putCompressedScript(gotCompressed, - test.uncompressed, test.version) + test.uncompressed) if !bytes.Equal(gotCompressed, test.compressed) { t.Errorf("putCompressedScript (%s): did not get "+ "expected bytes - got %x, want %x", test.name, @@ -220,8 +207,7 @@ func TestScriptCompression(t *testing.T) { // Ensure the compressed script size is properly decoded from // the compressed script. - gotDecodedSize := decodeCompressedScriptSize(test.compressed, - test.version) + gotDecodedSize := decodeCompressedScriptSize(test.compressed) if gotDecodedSize != len(test.compressed) { t.Errorf("decodeCompressedScriptSize (%s): did not get "+ "expected size - got %d, want %d", test.name, @@ -230,7 +216,7 @@ func TestScriptCompression(t *testing.T) { } // Ensure the script decompresses to the expected bytes. - gotDecompressed := decompressScript(test.compressed, test.version) + gotDecompressed := decompressScript(test.compressed) if !bytes.Equal(gotDecompressed, test.uncompressed) { t.Errorf("decompressScript (%s): did not get expected "+ "bytes - got %x, want %x", test.name, @@ -246,13 +232,13 @@ func TestScriptCompressionErrors(t *testing.T) { t.Parallel() // A nil script must result in a decoded size of 0. - if gotSize := decodeCompressedScriptSize(nil, 1); gotSize != 0 { + if gotSize := decodeCompressedScriptSize(nil); gotSize != 0 { t.Fatalf("decodeCompressedScriptSize with nil script did not "+ "return 0 - got %d", gotSize) } // A nil script must result in a nil decompressed script. - if gotScript := decompressScript(nil, 1); gotScript != nil { + if gotScript := decompressScript(nil); gotScript != nil { t.Fatalf("decompressScript with nil script did not return nil "+ "decompressed script - got %x", gotScript) } @@ -261,7 +247,7 @@ func TestScriptCompressionErrors(t *testing.T) { // in an invalid pubkey must result in a nil decompressed script. compressedScript := hexToBytes("04012d74d0cb94344c9569c2e77901573d8d" + "7903c3ebec3a957724895dca52c6b4") - if gotScript := decompressScript(compressedScript, 1); gotScript != nil { + if gotScript := decompressScript(compressedScript); gotScript != nil { t.Fatalf("decompressScript with compressed pay-to-"+ "uncompressed-pubkey that is invalid did not return "+ "nil decompressed script - got %x", gotScript) @@ -352,48 +338,35 @@ func TestCompressedTxOut(t *testing.T) { t.Parallel() tests := []struct { - name string - amount uint64 - compAmount uint64 - pkScript []byte - compPkScript []byte - version int32 - compressed []byte + name string + amount uint64 + pkScript []byte + compressed []byte }{ { - name: "nulldata with 0 BTC", - amount: 0, - compAmount: 0, - pkScript: hexToBytes("6a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), - compPkScript: hexToBytes("286a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), - version: 1, - compressed: hexToBytes("00286a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), + name: "nulldata with 0 BTC", + amount: 0, + pkScript: hexToBytes("6a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), + compressed: hexToBytes("00286a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"), }, { - name: "pay-to-pubkey-hash dust", - amount: 546, - compAmount: 4911, - pkScript: hexToBytes("76a9141018853670f9f3b0582c5b9ee8ce93764ac32b9388ac"), - compPkScript: hexToBytes("001018853670f9f3b0582c5b9ee8ce93764ac32b93"), - version: 1, - compressed: hexToBytes("a52f001018853670f9f3b0582c5b9ee8ce93764ac32b93"), + name: "pay-to-pubkey-hash dust", + amount: 546, + pkScript: hexToBytes("76a9141018853670f9f3b0582c5b9ee8ce93764ac32b9388ac"), + compressed: hexToBytes("a52f001018853670f9f3b0582c5b9ee8ce93764ac32b93"), }, { - name: "pay-to-pubkey uncompressed 1 BTC", - amount: 100000000, - compAmount: 9, - pkScript: hexToBytes("4104192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b40d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453eac"), - compPkScript: hexToBytes("04192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), - version: 1, - compressed: hexToBytes("0904192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), + name: "pay-to-pubkey uncompressed 1 BTC", + amount: 100000000, + pkScript: hexToBytes("4104192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b40d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453eac"), + compressed: hexToBytes("0904192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), }, } for _, test := range tests { // Ensure the function to calculate the serialized size without // actually serializing the txout is calculated properly. - gotSize := compressedTxOutSize(test.amount, test.pkScript, - test.version, false) + gotSize := compressedTxOutSize(test.amount, test.pkScript) if gotSize != len(test.compressed) { t.Errorf("compressedTxOutSize (%s): did not get "+ "expected size - got %d, want %d", test.name, @@ -404,7 +377,7 @@ func TestCompressedTxOut(t *testing.T) { // Ensure the txout compresses to the expected value. gotCompressed := make([]byte, gotSize) gotBytesWritten := putCompressedTxOut(gotCompressed, - test.amount, test.pkScript, test.version, false) + test.amount, test.pkScript) if !bytes.Equal(gotCompressed, test.compressed) { t.Errorf("compressTxOut (%s): did not get expected "+ "bytes - got %x, want %x", test.name, @@ -420,24 +393,24 @@ func TestCompressedTxOut(t *testing.T) { } // Ensure the serialized bytes are decoded back to the expected - // compressed values. + // uncompressed values. gotAmount, gotScript, gotBytesRead, err := decodeCompressedTxOut( - test.compressed, test.version) + test.compressed) if err != nil { t.Errorf("decodeCompressedTxOut (%s): unexpected "+ "error: %v", test.name, err) continue } - if gotAmount != test.compAmount { + if gotAmount != test.amount { t.Errorf("decodeCompressedTxOut (%s): did not get "+ "expected amount - got %d, want %d", - test.name, gotAmount, test.compAmount) + test.name, gotAmount, test.amount) continue } - if !bytes.Equal(gotScript, test.compPkScript) { + if !bytes.Equal(gotScript, test.pkScript) { t.Errorf("decodeCompressedTxOut (%s): did not get "+ "expected script - got %x, want %x", - test.name, gotScript, test.compPkScript) + test.name, gotScript, test.pkScript) continue } if gotBytesRead != len(test.compressed) { @@ -446,23 +419,6 @@ func TestCompressedTxOut(t *testing.T) { test.name, gotBytesRead, len(test.compressed)) continue } - - // Ensure the compressed values decompress to the expected - // txout. - gotAmount = decompressTxOutAmount(gotAmount) - if gotAmount != test.amount { - t.Errorf("decompressTxOut (%s): did not get expected "+ - "value - got %d, want %d", test.name, gotAmount, - test.amount) - continue - } - gotScript = decompressScript(gotScript, test.version) - if !bytes.Equal(gotScript, test.pkScript) { - t.Errorf("decompressTxOut (%s): did not get expected "+ - "script - got %x, want %x", test.name, - gotScript, test.pkScript) - continue - } } } @@ -473,7 +429,7 @@ func TestTxOutCompressionErrors(t *testing.T) { // A compressed txout with missing compressed script must error. compressedTxOut := hexToBytes("00") - _, _, _, err := decodeCompressedTxOut(compressedTxOut, 1) + _, _, _, err := decodeCompressedTxOut(compressedTxOut) if !isDeserializeErr(err) { t.Fatalf("decodeCompressedTxOut with missing compressed script "+ "did not return expected error type - got %T, want "+ @@ -482,7 +438,7 @@ func TestTxOutCompressionErrors(t *testing.T) { // A compressed txout with short compressed script must error. compressedTxOut = hexToBytes("0010") - _, _, _, err = decodeCompressedTxOut(compressedTxOut, 1) + _, _, _, err = decodeCompressedTxOut(compressedTxOut) if !isDeserializeErr(err) { t.Fatalf("decodeCompressedTxOut with short compressed script "+ "did not return expected error type - got %T, want "+ diff --git a/vendor/github.com/btcsuite/btcd/blockchain/example_test.go b/vendor/github.com/btcsuite/btcd/blockchain/example_test.go index c7163e0e..691d0927 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/example_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/example_test.go @@ -18,7 +18,7 @@ import ( ) // This example demonstrates how to create a new chain instance and use -// ProcessBlock to attempt to attempt add a block to the chain. As the package +// ProcessBlock to attempt to add a block to the chain. As the package // overview documentation describes, this includes all of the Bitcoin consensus // rules. This example intentionally attempts to insert a duplicate genesis // block to illustrate how an invalid block is handled. diff --git a/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/README.md b/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/README.md index 1caca027..41f4b934 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/README.md +++ b/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/README.md @@ -15,7 +15,7 @@ independent versions over the peer-to-peer network. This package has intentionally been designed so it can be used as a standalone package for any projects needing to test their implementation against a full set -of blocks that excerise the consensus validation rules. +of blocks that exercise the consensus validation rules. ## Installation and Updating diff --git a/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/doc.go b/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/doc.go index 83b9c115..bfedc43d 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/doc.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/fullblocktests/doc.go @@ -15,6 +15,6 @@ independent versions over the peer-to-peer network. This package has intentionally been designed so it can be used as a standalone package for any projects needing to test their implementation against a full set -of blocks that excerise the consensus validation rules. +of blocks that exercise the consensus validation rules. */ package fullblocktests diff --git a/vendor/github.com/btcsuite/btcd/blockchain/indexers/addrindex.go b/vendor/github.com/btcsuite/btcd/blockchain/indexers/addrindex.go index d512c32f..29d9030a 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/indexers/addrindex.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/indexers/addrindex.go @@ -651,7 +651,7 @@ func (idx *AddrIndex) Create(dbTx database.Tx) error { } // writeIndexData represents the address index data to be written for one block. -// It consistens of the address mapped to an ordered list of the transactions +// It consists of the address mapped to an ordered list of the transactions // that involve the address in block. It is ordered so the transactions can be // stored in the order they appear in the block. type writeIndexData map[[addrKeySize]byte][]int @@ -690,27 +690,28 @@ func (idx *AddrIndex) indexPkScript(data writeIndexData, pkScript []byte, txIdx } // indexBlock extract all of the standard addresses from all of the transactions -// in the passed block and maps each of them to the assocaited transaction using +// in the passed block and maps each of them to the associated transaction using // the passed map. -func (idx *AddrIndex) indexBlock(data writeIndexData, block *btcutil.Block, view *blockchain.UtxoViewpoint) { +func (idx *AddrIndex) indexBlock(data writeIndexData, block *btcutil.Block, + stxos []blockchain.SpentTxOut) { + + stxoIndex := 0 for txIdx, tx := range block.Transactions() { // Coinbases do not reference any inputs. Since the block is // required to have already gone through full validation, it has // already been proven on the first transaction in the block is // a coinbase. if txIdx != 0 { - for _, txIn := range tx.MsgTx().TxIn { - // The view should always have the input since - // the index contract requires it, however, be - // safe and simply ignore any missing entries. - origin := &txIn.PreviousOutPoint - entry := view.LookupEntry(&origin.Hash) - if entry == nil { - continue - } - - pkScript := entry.PkScriptByIndex(origin.Index) + for range tx.MsgTx().TxIn { + // We'll access the slice of all the + // transactions spent in this block properly + // ordered to fetch the previous input script. + pkScript := stxos[stxoIndex].PkScript idx.indexPkScript(data, pkScript, txIdx) + + // With an input indexed, we'll advance the + // stxo coutner. + stxoIndex++ } } @@ -725,7 +726,9 @@ func (idx *AddrIndex) indexBlock(data writeIndexData, block *btcutil.Block, view // the transactions in the block involve. // // This is part of the Indexer interface. -func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, + stxos []blockchain.SpentTxOut) error { + // The offset and length of the transactions within the serialized // block. txLocs, err := block.TxLoc() @@ -741,7 +744,7 @@ func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view // Build all of the address to transaction mappings in a local map. addrsToTxns := make(writeIndexData) - idx.indexBlock(addrsToTxns, block, view) + idx.indexBlock(addrsToTxns, block, stxos) // Add all of the index entries for each address. addrIdxBucket := dbTx.Metadata().Bucket(addrIndexKey) @@ -763,10 +766,12 @@ func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view // each transaction in the block involve. // // This is part of the Indexer interface. -func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, + stxos []blockchain.SpentTxOut) error { + // Build all of the address to transaction mappings in a local map. addrsToTxns := make(writeIndexData) - idx.indexBlock(addrsToTxns, block, view) + idx.indexBlock(addrsToTxns, block, stxos) // Remove all of the index entries for each address. bucket := dbTx.Metadata().Bucket(addrIndexKey) @@ -872,15 +877,14 @@ func (idx *AddrIndex) AddUnconfirmedTx(tx *btcutil.Tx, utxoView *blockchain.Utxo // transaction has already been validated and thus all inputs are // already known to exist. for _, txIn := range tx.MsgTx().TxIn { - entry := utxoView.LookupEntry(&txIn.PreviousOutPoint.Hash) + entry := utxoView.LookupEntry(txIn.PreviousOutPoint) if entry == nil { // Ignore missing entries. This should never happen // in practice since the function comments specifically // call out all inputs must be available. continue } - pkScript := entry.PkScriptByIndex(txIn.PreviousOutPoint.Index) - idx.indexUnconfirmedAddresses(pkScript, tx) + idx.indexUnconfirmedAddresses(entry.PkScript(), tx) } // Index addresses of all created outputs. diff --git a/vendor/github.com/btcsuite/btcd/blockchain/indexers/cfindex.go b/vendor/github.com/btcsuite/btcd/blockchain/indexers/cfindex.go new file mode 100644 index 00000000..8ea14728 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/indexers/cfindex.go @@ -0,0 +1,357 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package indexers + +import ( + "errors" + + "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcutil/gcs" + "github.com/btcsuite/btcutil/gcs/builder" +) + +const ( + // cfIndexName is the human-readable name for the index. + cfIndexName = "committed filter index" +) + +// Committed filters come in one flavor currently: basic. They are generated +// and dropped in pairs, and both are indexed by a block's hash. Besides +// holding different content, they also live in different buckets. +var ( + // cfIndexParentBucketKey is the name of the parent bucket used to + // house the index. The rest of the buckets live below this bucket. + cfIndexParentBucketKey = []byte("cfindexparentbucket") + + // cfIndexKeys is an array of db bucket names used to house indexes of + // block hashes to cfilters. + cfIndexKeys = [][]byte{ + []byte("cf0byhashidx"), + } + + // cfHeaderKeys is an array of db bucket names used to house indexes of + // block hashes to cf headers. + cfHeaderKeys = [][]byte{ + []byte("cf0headerbyhashidx"), + } + + // cfHashKeys is an array of db bucket names used to house indexes of + // block hashes to cf hashes. + cfHashKeys = [][]byte{ + []byte("cf0hashbyhashidx"), + } + + maxFilterType = uint8(len(cfHeaderKeys) - 1) + + // zeroHash is the chainhash.Hash value of all zero bytes, defined here + // for convenience. + zeroHash chainhash.Hash +) + +// dbFetchFilterIdxEntry retrieves a data blob from the filter index database. +// An entry's absence is not considered an error. +func dbFetchFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) { + idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key) + return idx.Get(h[:]), nil +} + +// dbStoreFilterIdxEntry stores a data blob in the filter index database. +func dbStoreFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash, f []byte) error { + idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key) + return idx.Put(h[:], f) +} + +// dbDeleteFilterIdxEntry deletes a data blob from the filter index database. +func dbDeleteFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) error { + idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key) + return idx.Delete(h[:]) +} + +// CfIndex implements a committed filter (cf) by hash index. +type CfIndex struct { + db database.DB + chainParams *chaincfg.Params +} + +// Ensure the CfIndex type implements the Indexer interface. +var _ Indexer = (*CfIndex)(nil) + +// Ensure the CfIndex type implements the NeedsInputser interface. +var _ NeedsInputser = (*CfIndex)(nil) + +// NeedsInputs signals that the index requires the referenced inputs in order +// to properly create the index. +// +// This implements the NeedsInputser interface. +func (idx *CfIndex) NeedsInputs() bool { + return true +} + +// Init initializes the hash-based cf index. This is part of the Indexer +// interface. +func (idx *CfIndex) Init() error { + return nil // Nothing to do. +} + +// Key returns the database key to use for the index as a byte slice. This is +// part of the Indexer interface. +func (idx *CfIndex) Key() []byte { + return cfIndexParentBucketKey +} + +// Name returns the human-readable name of the index. This is part of the +// Indexer interface. +func (idx *CfIndex) Name() string { + return cfIndexName +} + +// Create is invoked when the indexer manager determines the index needs to +// be created for the first time. It creates buckets for the two hash-based cf +// indexes (regular only currently). +func (idx *CfIndex) Create(dbTx database.Tx) error { + meta := dbTx.Metadata() + + cfIndexParentBucket, err := meta.CreateBucket(cfIndexParentBucketKey) + if err != nil { + return err + } + + for _, bucketName := range cfIndexKeys { + _, err = cfIndexParentBucket.CreateBucket(bucketName) + if err != nil { + return err + } + } + + for _, bucketName := range cfHeaderKeys { + _, err = cfIndexParentBucket.CreateBucket(bucketName) + if err != nil { + return err + } + } + + for _, bucketName := range cfHashKeys { + _, err = cfIndexParentBucket.CreateBucket(bucketName) + if err != nil { + return err + } + } + + return nil +} + +// storeFilter stores a given filter, and performs the steps needed to +// generate the filter's header. +func storeFilter(dbTx database.Tx, block *btcutil.Block, f *gcs.Filter, + filterType wire.FilterType) error { + if uint8(filterType) > maxFilterType { + return errors.New("unsupported filter type") + } + + // Figure out which buckets to use. + fkey := cfIndexKeys[filterType] + hkey := cfHeaderKeys[filterType] + hashkey := cfHashKeys[filterType] + + // Start by storing the filter. + h := block.Hash() + filterBytes, err := f.NBytes() + if err != nil { + return err + } + err = dbStoreFilterIdxEntry(dbTx, fkey, h, filterBytes) + if err != nil { + return err + } + + // Next store the filter hash. + filterHash, err := builder.GetFilterHash(f) + if err != nil { + return err + } + err = dbStoreFilterIdxEntry(dbTx, hashkey, h, filterHash[:]) + if err != nil { + return err + } + + // Then fetch the previous block's filter header. + var prevHeader *chainhash.Hash + ph := &block.MsgBlock().Header.PrevBlock + if ph.IsEqual(&zeroHash) { + prevHeader = &zeroHash + } else { + pfh, err := dbFetchFilterIdxEntry(dbTx, hkey, ph) + if err != nil { + return err + } + + // Construct the new block's filter header, and store it. + prevHeader, err = chainhash.NewHash(pfh) + if err != nil { + return err + } + } + + fh, err := builder.MakeHeaderForFilter(f, *prevHeader) + if err != nil { + return err + } + return dbStoreFilterIdxEntry(dbTx, hkey, h, fh[:]) +} + +// ConnectBlock is invoked by the index manager when a new block has been +// connected to the main chain. This indexer adds a hash-to-cf mapping for +// every passed block. This is part of the Indexer interface. +func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, + stxos []blockchain.SpentTxOut) error { + + prevScripts := make([][]byte, len(stxos)) + for i, stxo := range stxos { + prevScripts[i] = stxo.PkScript + } + + f, err := builder.BuildBasicFilter(block.MsgBlock(), prevScripts) + if err != nil { + return err + } + + return storeFilter(dbTx, block, f, wire.GCSFilterRegular) +} + +// DisconnectBlock is invoked by the index manager when a block has been +// disconnected from the main chain. This indexer removes the hash-to-cf +// mapping for every passed block. This is part of the Indexer interface. +func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, + _ []blockchain.SpentTxOut) error { + + for _, key := range cfIndexKeys { + err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash()) + if err != nil { + return err + } + } + + for _, key := range cfHeaderKeys { + err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash()) + if err != nil { + return err + } + } + + for _, key := range cfHashKeys { + err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash()) + if err != nil { + return err + } + } + + return nil +} + +// entryByBlockHash fetches a filter index entry of a particular type +// (eg. filter, filter header, etc) for a filter type and block hash. +func (idx *CfIndex) entryByBlockHash(filterTypeKeys [][]byte, + filterType wire.FilterType, h *chainhash.Hash) ([]byte, error) { + + if uint8(filterType) > maxFilterType { + return nil, errors.New("unsupported filter type") + } + key := filterTypeKeys[filterType] + + var entry []byte + err := idx.db.View(func(dbTx database.Tx) error { + var err error + entry, err = dbFetchFilterIdxEntry(dbTx, key, h) + return err + }) + return entry, err +} + +// entriesByBlockHashes batch fetches a filter index entry of a particular type +// (eg. filter, filter header, etc) for a filter type and slice of block hashes. +func (idx *CfIndex) entriesByBlockHashes(filterTypeKeys [][]byte, + filterType wire.FilterType, blockHashes []*chainhash.Hash) ([][]byte, error) { + + if uint8(filterType) > maxFilterType { + return nil, errors.New("unsupported filter type") + } + key := filterTypeKeys[filterType] + + entries := make([][]byte, 0, len(blockHashes)) + err := idx.db.View(func(dbTx database.Tx) error { + for _, blockHash := range blockHashes { + entry, err := dbFetchFilterIdxEntry(dbTx, key, blockHash) + if err != nil { + return err + } + entries = append(entries, entry) + } + return nil + }) + return entries, err +} + +// FilterByBlockHash returns the serialized contents of a block's basic or +// committed filter. +func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, + filterType wire.FilterType) ([]byte, error) { + return idx.entryByBlockHash(cfIndexKeys, filterType, h) +} + +// FiltersByBlockHashes returns the serialized contents of a block's basic or +// committed filter for a set of blocks by hash. +func (idx *CfIndex) FiltersByBlockHashes(blockHashes []*chainhash.Hash, + filterType wire.FilterType) ([][]byte, error) { + return idx.entriesByBlockHashes(cfIndexKeys, filterType, blockHashes) +} + +// FilterHeaderByBlockHash returns the serialized contents of a block's basic +// committed filter header. +func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash, + filterType wire.FilterType) ([]byte, error) { + return idx.entryByBlockHash(cfHeaderKeys, filterType, h) +} + +// FilterHeadersByBlockHashes returns the serialized contents of a block's +// basic committed filter header for a set of blocks by hash. +func (idx *CfIndex) FilterHeadersByBlockHashes(blockHashes []*chainhash.Hash, + filterType wire.FilterType) ([][]byte, error) { + return idx.entriesByBlockHashes(cfHeaderKeys, filterType, blockHashes) +} + +// FilterHashByBlockHash returns the serialized contents of a block's basic +// committed filter hash. +func (idx *CfIndex) FilterHashByBlockHash(h *chainhash.Hash, + filterType wire.FilterType) ([]byte, error) { + return idx.entryByBlockHash(cfHashKeys, filterType, h) +} + +// FilterHashesByBlockHashes returns the serialized contents of a block's basic +// committed filter hash for a set of blocks by hash. +func (idx *CfIndex) FilterHashesByBlockHashes(blockHashes []*chainhash.Hash, + filterType wire.FilterType) ([][]byte, error) { + return idx.entriesByBlockHashes(cfHashKeys, filterType, blockHashes) +} + +// NewCfIndex returns a new instance of an indexer that is used to create a +// mapping of the hashes of all blocks in the blockchain to their respective +// committed filters. +// +// It implements the Indexer interface which plugs into the IndexManager that +// in turn is used by the blockchain package. This allows the index to be +// seamlessly maintained along with the chain. +func NewCfIndex(db database.DB, chainParams *chaincfg.Params) *CfIndex { + return &CfIndex{db: db, chainParams: chainParams} +} + +// DropCfIndex drops the CF index from the provided database if exists. +func DropCfIndex(db database.DB, interrupt <-chan struct{}) error { + return dropIndex(db, cfIndexParentBucketKey, cfIndexName, interrupt) +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/indexers/common.go b/vendor/github.com/btcsuite/btcd/blockchain/indexers/common.go index 9b0320dc..a912bb4c 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/indexers/common.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/indexers/common.go @@ -50,13 +50,17 @@ type Indexer interface { // every load, including the case the index was just created. Init() error - // ConnectBlock is invoked when the index manager is notified that a new - // block has been connected to the main chain. - ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error + // ConnectBlock is invoked when a new block has been connected to the + // main chain. The set of output spent within a block is also passed in + // so indexers can access the pevious output scripts input spent if + // required. + ConnectBlock(database.Tx, *btcutil.Block, []blockchain.SpentTxOut) error - // DisconnectBlock is invoked when the index manager is notified that a - // block has been disconnected from the main chain. - DisconnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error + // DisconnectBlock is invoked when a block has been disconnected from + // the main chain. The set of outputs scripts that were spent within + // this block is also returned so indexers can clean up the prior index + // state for this block + DisconnectBlock(database.Tx, *btcutil.Block, []blockchain.SpentTxOut) error } // AssertError identifies an error that indicates an internal code consistency diff --git a/vendor/github.com/btcsuite/btcd/blockchain/indexers/manager.go b/vendor/github.com/btcsuite/btcd/blockchain/indexers/manager.go index cc996dd8..bc0804f8 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/indexers/manager.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/indexers/manager.go @@ -68,7 +68,9 @@ func dbFetchIndexerTip(dbTx database.Tx, idxKey []byte) (*chainhash.Hash, int32, // given block using the provided indexer and updates the tip of the indexer // accordingly. An error will be returned if the current tip for the indexer is // not the previous block for the passed block. -func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block, + stxo []blockchain.SpentTxOut) error { + // Assert that the block being connected properly connects to the // current tip of the index. idxKey := indexer.Key() @@ -84,7 +86,7 @@ func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block } // Notify the indexer with the connected block so it can index it. - if err := indexer.ConnectBlock(dbTx, block, view); err != nil { + if err := indexer.ConnectBlock(dbTx, block, stxo); err != nil { return err } @@ -96,7 +98,9 @@ func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block // given block using the provided indexer and updates the tip of the indexer // accordingly. An error will be returned if the current tip for the indexer is // not the passed block. -func dbIndexDisconnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func dbIndexDisconnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block, + stxo []blockchain.SpentTxOut) error { + // Assert that the block being disconnected is the current tip of the // index. idxKey := indexer.Key() @@ -113,7 +117,7 @@ func dbIndexDisconnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Bl // Notify the indexer with the disconnected block so it can remove all // of the appropriate entries. - if err := indexer.DisconnectBlock(dbTx, block, view); err != nil { + if err := indexer.DisconnectBlock(dbTx, block, stxo); err != nil { return err } @@ -299,34 +303,38 @@ func (m *Manager) Init(chain *blockchain.BlockChain, interrupt <-chan struct{}) // loaded directly since it is no longer in the main // chain and thus the chain.BlockByHash function would // error. - err = m.db.Update(func(dbTx database.Tx) error { + var block *btcutil.Block + err := m.db.View(func(dbTx database.Tx) error { blockBytes, err := dbTx.FetchBlock(hash) if err != nil { return err } - block, err := btcutil.NewBlockFromBytes(blockBytes) + block, err = btcutil.NewBlockFromBytes(blockBytes) if err != nil { return err } block.SetHeight(height) + return err + }) + if err != nil { + return err + } - // When the index requires all of the referenced - // txouts they need to be retrieved from the - // transaction index. - var view *blockchain.UtxoViewpoint - if indexNeedsInputs(indexer) { - var err error - view, err = makeUtxoView(dbTx, block, - interrupt) - if err != nil { - return err - } - } + // We'll also grab the set of outputs spent by this + // block so we can remove them from the index. + spentTxos, err := chain.FetchSpendJournal(block) + if err != nil { + return err + } + // With the block and stxo set for that block retrieved, + // we can now update the index itself. + err = m.db.Update(func(dbTx database.Tx) error { // Remove all of the index entries associated // with the block and update the indexer tip. - err = dbIndexDisconnectBlock(dbTx, indexer, - block, view) + err = dbIndexDisconnectBlock( + dbTx, indexer, block, spentTxos, + ) if err != nil { return err } @@ -407,7 +415,7 @@ func (m *Manager) Init(chain *blockchain.BlockChain, interrupt <-chan struct{}) } // Connect the block for all indexes that need it. - var view *blockchain.UtxoViewpoint + var spentTxos []blockchain.SpentTxOut for i, indexer := range m.enabledIndexes { // Skip indexes that don't need to be updated with this // block. @@ -415,21 +423,20 @@ func (m *Manager) Init(chain *blockchain.BlockChain, interrupt <-chan struct{}) continue } - err := m.db.Update(func(dbTx database.Tx) error { - // When the index requires all of the referenced - // txouts and they haven't been loaded yet, they - // need to be retrieved from the transaction - // index. - if view == nil && indexNeedsInputs(indexer) { - var err error - view, err = makeUtxoView(dbTx, block, - interrupt) - if err != nil { - return err - } + // When the index requires all of the referenced txouts + // and they haven't been loaded yet, they need to be + // retrieved from the spend journal. + if spentTxos == nil && indexNeedsInputs(indexer) { + spentTxos, err = chain.FetchSpendJournal(block) + if err != nil { + return err } - return dbIndexConnectBlock(dbTx, indexer, block, - view) + } + + err := m.db.Update(func(dbTx database.Tx) error { + return dbIndexConnectBlock( + dbTx, indexer, block, spentTxos, + ) }) if err != nil { return err @@ -487,52 +494,18 @@ func dbFetchTx(dbTx database.Tx, hash *chainhash.Hash) (*wire.MsgTx, error) { return &msgTx, nil } -// makeUtxoView creates a mock unspent transaction output view by using the -// transaction index in order to look up all inputs referenced by the -// transactions in the block. This is sometimes needed when catching indexes up -// because many of the txouts could actually already be spent however the -// associated scripts are still required to index them. -func makeUtxoView(dbTx database.Tx, block *btcutil.Block, interrupt <-chan struct{}) (*blockchain.UtxoViewpoint, error) { - view := blockchain.NewUtxoViewpoint() - for txIdx, tx := range block.Transactions() { - // Coinbases do not reference any inputs. Since the block is - // required to have already gone through full validation, it has - // already been proven on the first transaction in the block is - // a coinbase. - if txIdx == 0 { - continue - } - - // Use the transaction index to load all of the referenced - // inputs and add their outputs to the view. - for _, txIn := range tx.MsgTx().TxIn { - originOut := &txIn.PreviousOutPoint - originTx, err := dbFetchTx(dbTx, &originOut.Hash) - if err != nil { - return nil, err - } - - view.AddTxOuts(btcutil.NewTx(originTx), 0) - } - - if interruptRequested(interrupt) { - return nil, errInterruptRequested - } - } - - return view, nil -} - // ConnectBlock must be invoked when a block is extending the main chain. It // keeps track of the state of each index it is managing, performs some sanity // checks, and invokes each indexer. // // This is part of the blockchain.IndexManager interface. -func (m *Manager) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func (m *Manager) ConnectBlock(dbTx database.Tx, block *btcutil.Block, + stxos []blockchain.SpentTxOut) error { + // Call each of the currently active optional indexes with the block // being connected so they can update accordingly. for _, index := range m.enabledIndexes { - err := dbIndexConnectBlock(dbTx, index, block, view) + err := dbIndexConnectBlock(dbTx, index, block, stxos) if err != nil { return err } @@ -546,11 +519,13 @@ func (m *Manager) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blo // the index entries associated with the block. // // This is part of the blockchain.IndexManager interface. -func (m *Manager) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func (m *Manager) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, + stxo []blockchain.SpentTxOut) error { + // Call each of the currently active optional indexes with the block // being disconnected so they can update accordingly. for _, index := range m.enabledIndexes { - err := dbIndexDisconnectBlock(dbTx, index, block, view) + err := dbIndexDisconnectBlock(dbTx, index, block, stxo) if err != nil { return err } @@ -609,37 +584,90 @@ func dropIndex(db database.DB, idxKey []byte, idxName string, interrupt <-chan s // the bucket in a single database transaction would result in massive // memory usage and likely crash many systems due to ulimits. In order // to avoid this, use a cursor to delete a maximum number of entries out - // of the bucket at a time. + // of the bucket at a time. Recurse buckets depth-first to delete any + // sub-buckets. const maxDeletions = 2000000 var totalDeleted uint64 - for numDeleted := maxDeletions; numDeleted == maxDeletions; { - numDeleted = 0 - err := db.Update(func(dbTx database.Tx) error { - bucket := dbTx.Metadata().Bucket(idxKey) - cursor := bucket.Cursor() - for ok := cursor.First(); ok; ok = cursor.Next() && - numDeleted < maxDeletions { - if err := cursor.Delete(); err != nil { - return err - } - numDeleted++ - } - return nil - }) - if err != nil { - return err + // Recurse through all buckets in the index, cataloging each for + // later deletion. + var subBuckets [][][]byte + var subBucketClosure func(database.Tx, []byte, [][]byte) error + subBucketClosure = func(dbTx database.Tx, + subBucket []byte, tlBucket [][]byte) error { + // Get full bucket name and append to subBuckets for later + // deletion. + var bucketName [][]byte + if (tlBucket == nil) || (len(tlBucket) == 0) { + bucketName = append(bucketName, subBucket) + } else { + bucketName = append(tlBucket, subBucket) } + subBuckets = append(subBuckets, bucketName) + // Recurse sub-buckets to append to subBuckets slice. + bucket := dbTx.Metadata() + for _, subBucketName := range bucketName { + bucket = bucket.Bucket(subBucketName) + } + return bucket.ForEachBucket(func(k []byte) error { + return subBucketClosure(dbTx, k, bucketName) + }) + } - if numDeleted > 0 { - totalDeleted += uint64(numDeleted) - log.Infof("Deleted %d keys (%d total) from %s", - numDeleted, totalDeleted, idxName) + // Call subBucketClosure with top-level bucket. + err = db.View(func(dbTx database.Tx) error { + return subBucketClosure(dbTx, idxKey, nil) + }) + if err != nil { + return nil + } + + // Iterate through each sub-bucket in reverse, deepest-first, deleting + // all keys inside them and then dropping the buckets themselves. + for i := range subBuckets { + bucketName := subBuckets[len(subBuckets)-1-i] + // Delete maxDeletions key/value pairs at a time. + for numDeleted := maxDeletions; numDeleted == maxDeletions; { + numDeleted = 0 + err := db.Update(func(dbTx database.Tx) error { + subBucket := dbTx.Metadata() + for _, subBucketName := range bucketName { + subBucket = subBucket.Bucket(subBucketName) + } + cursor := subBucket.Cursor() + for ok := cursor.First(); ok; ok = cursor.Next() && + numDeleted < maxDeletions { + + if err := cursor.Delete(); err != nil { + return err + } + numDeleted++ + } + return nil + }) + if err != nil { + return err + } + + if numDeleted > 0 { + totalDeleted += uint64(numDeleted) + log.Infof("Deleted %d keys (%d total) from %s", + numDeleted, totalDeleted, idxName) + } } if interruptRequested(interrupt) { return errInterruptRequested } + + // Drop the bucket itself. + err = db.Update(func(dbTx database.Tx) error { + bucket := dbTx.Metadata() + for j := 0; j < len(bucketName)-1; j++ { + bucket = bucket.Bucket(bucketName[j]) + } + return bucket.DeleteBucket(bucketName[len(bucketName)-1]) + }) } // Call extra index specific deinitialization for the transaction index. @@ -658,10 +686,6 @@ func dropIndex(db database.DB, idxKey []byte, idxName string, interrupt <-chan s return err } - if err := meta.DeleteBucket(idxKey); err != nil { - return err - } - return indexesBucket.Delete(indexDropKey(idxKey)) }) if err != nil { diff --git a/vendor/github.com/btcsuite/btcd/blockchain/indexers/txindex.go b/vendor/github.com/btcsuite/btcd/blockchain/indexers/txindex.go index 9b1826cc..00cfd006 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/indexers/txindex.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/indexers/txindex.go @@ -40,7 +40,7 @@ var ( // ----------------------------------------------------------------------------- // The transaction index consists of an entry for every transaction in the main -// chain. In order to significanly optimize the space requirements a separate +// chain. In order to significantly optimize the space requirements a separate // index which provides an internal mapping between each block that has been // indexed and a unique ID for use within the hash to location mappings. The ID // is simply a sequentially incremented uint32. This is useful because it is @@ -388,7 +388,9 @@ func (idx *TxIndex) Create(dbTx database.Tx) error { // for every transaction in the passed block. // // This is part of the Indexer interface. -func (idx *TxIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func (idx *TxIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, + stxos []blockchain.SpentTxOut) error { + // Increment the internal block ID to use for the block being connected // and add all of the transactions in the block to the index. newBlockID := idx.curBlockID + 1 @@ -411,7 +413,9 @@ func (idx *TxIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *b // hash-to-transaction mapping for every transaction in the block. // // This is part of the Indexer interface. -func (idx *TxIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { +func (idx *TxIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, + stxos []blockchain.SpentTxOut) error { + // Remove all of the transactions in the block from the index. if err := dbRemoveTxIndexEntries(dbTx, block); err != nil { return err diff --git a/vendor/github.com/btcsuite/btcd/blockchain/mediantime_test.go b/vendor/github.com/btcsuite/btcd/blockchain/mediantime_test.go index f5d74a75..948d0310 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/mediantime_test.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/mediantime_test.go @@ -45,7 +45,7 @@ func TestMedianTime(t *testing.T) { // be ignored. {in: []int64{-4201, 4202, -4203, 4204, -4205}, wantOffset: 0}, - // Excerise the condition where the median offset is greater + // Exercise the condition where the median offset is greater // than the max allowed adjustment, but there is at least one // sample that is close enough to the current time to avoid // triggering a warning about an invalid local clock. diff --git a/vendor/github.com/btcsuite/btcd/blockchain/scriptval.go b/vendor/github.com/btcsuite/btcd/blockchain/scriptval.go index f7c76011..8ba59a42 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/scriptval.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/scriptval.go @@ -55,31 +55,16 @@ out: for { select { case txVI := <-v.validateChan: - // Ensure the referenced input transaction is available. + // Ensure the referenced input utxo is available. txIn := txVI.txIn - originTxHash := &txIn.PreviousOutPoint.Hash - originTxIndex := txIn.PreviousOutPoint.Index - txEntry := v.utxoView.LookupEntry(originTxHash) - if txEntry == nil { - str := fmt.Sprintf("unable to find input "+ - "transaction %v referenced from "+ - "transaction %v", originTxHash, - txVI.tx.Hash()) - err := ruleError(ErrMissingTxOut, str) - v.sendResult(err) - break out - } - - // Ensure the referenced input transaction public key - // script is available. - pkScript := txEntry.PkScriptByIndex(originTxIndex) - if pkScript == nil { + utxo := v.utxoView.LookupEntry(txIn.PreviousOutPoint) + if utxo == nil { str := fmt.Sprintf("unable to find unspent "+ - "output %v script referenced from "+ + "output %v referenced from "+ "transaction %s:%d", txIn.PreviousOutPoint, txVI.tx.Hash(), txVI.txInIndex) - err := ruleError(ErrBadTxInput, str) + err := ruleError(ErrMissingTxOut, str) v.sendResult(err) break out } @@ -87,18 +72,19 @@ out: // Create a new script engine for the script pair. sigScript := txIn.SignatureScript witness := txIn.Witness - inputAmount := txEntry.AmountByIndex(originTxIndex) + pkScript := utxo.PkScript() + inputAmount := utxo.Amount() vm, err := txscript.NewEngine(pkScript, txVI.tx.MsgTx(), txVI.txInIndex, v.flags, v.sigCache, txVI.sigHashes, inputAmount) if err != nil { str := fmt.Sprintf("failed to parse input "+ - "%s:%d which references output %s:%d - "+ + "%s:%d which references output %v - "+ "%v (input witness %x, input script "+ "bytes %x, prev output script bytes %x)", - txVI.tx.Hash(), txVI.txInIndex, originTxHash, - originTxIndex, err, witness, sigScript, - pkScript) + txVI.tx.Hash(), txVI.txInIndex, + txIn.PreviousOutPoint, err, witness, + sigScript, pkScript) err := ruleError(ErrScriptMalformed, str) v.sendResult(err) break out @@ -107,12 +93,12 @@ out: // Execute the script pair. if err := vm.Execute(); err != nil { str := fmt.Sprintf("failed to validate input "+ - "%s:%d which references output %s:%d - "+ + "%s:%d which references output %v - "+ "%v (input witness %x, input script "+ "bytes %x, prev output script bytes %x)", txVI.tx.Hash(), txVI.txInIndex, - originTxHash, originTxIndex, err, - witness, sigScript, pkScript) + txIn.PreviousOutPoint, err, witness, + sigScript, pkScript) err := ruleError(ErrScriptValidation, str) v.sendResult(err) break out diff --git a/vendor/github.com/btcsuite/btcd/blockchain/testdata/277647.utxostore.bz2 b/vendor/github.com/btcsuite/btcd/blockchain/testdata/277647.utxostore.bz2 index 3807a712..c12b65e2 100644 Binary files a/vendor/github.com/btcsuite/btcd/blockchain/testdata/277647.utxostore.bz2 and b/vendor/github.com/btcsuite/btcd/blockchain/testdata/277647.utxostore.bz2 differ diff --git a/vendor/github.com/btcsuite/btcd/blockchain/thresholdstate.go b/vendor/github.com/btcsuite/btcd/blockchain/thresholdstate.go index b9f39294..35a76255 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/thresholdstate.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/thresholdstate.go @@ -85,7 +85,7 @@ type thresholdConditionChecker interface { // Condition returns whether or not the rule change activation condition // has been met. This typically involves checking whether or not the - // bit assocaited with the condition is set, but can be more complex as + // bit associated with the condition is set, but can be more complex as // needed. Condition(*blockNode) (bool, error) } diff --git a/vendor/github.com/btcsuite/btcd/blockchain/upgrade.go b/vendor/github.com/btcsuite/btcd/blockchain/upgrade.go new file mode 100644 index 00000000..253ca62e --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/upgrade.go @@ -0,0 +1,604 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package blockchain + +import ( + "bytes" + "container/list" + "errors" + "fmt" + "time" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/wire" +) + +const ( + // blockHdrOffset defines the offsets into a v1 block index row for the + // block header. + // + // The serialized block index row format is: + // + blockHdrOffset = 12 +) + +// errInterruptRequested indicates that an operation was cancelled due +// to a user-requested interrupt. +var errInterruptRequested = errors.New("interrupt requested") + +// interruptRequested returns true when the provided channel has been closed. +// This simplifies early shutdown slightly since the caller can just use an if +// statement instead of a select. +func interruptRequested(interrupted <-chan struct{}) bool { + select { + case <-interrupted: + return true + default: + } + + return false +} + +// blockChainContext represents a particular block's placement in the block +// chain. This is used by the block index migration to track block metadata that +// will be written to disk. +type blockChainContext struct { + parent *chainhash.Hash + children []*chainhash.Hash + height int32 + mainChain bool +} + +// migrateBlockIndex migrates all block entries from the v1 block index bucket +// to the v2 bucket. The v1 bucket stores all block entries keyed by block hash, +// whereas the v2 bucket stores the exact same values, but keyed instead by +// block height + hash. +func migrateBlockIndex(db database.DB) error { + // Hardcoded bucket names so updates to the global values do not affect + // old upgrades. + v1BucketName := []byte("ffldb-blockidx") + v2BucketName := []byte("blockheaderidx") + + err := db.Update(func(dbTx database.Tx) error { + v1BlockIdxBucket := dbTx.Metadata().Bucket(v1BucketName) + if v1BlockIdxBucket == nil { + return fmt.Errorf("Bucket %s does not exist", v1BucketName) + } + + log.Info("Re-indexing block information in the database. This might take a while...") + + v2BlockIdxBucket, err := + dbTx.Metadata().CreateBucketIfNotExists(v2BucketName) + if err != nil { + return err + } + + // Get tip of the main chain. + serializedData := dbTx.Metadata().Get(chainStateKeyName) + state, err := deserializeBestChainState(serializedData) + if err != nil { + return err + } + tip := &state.hash + + // Scan the old block index bucket and construct a mapping of each block + // to parent block and all child blocks. + blocksMap, err := readBlockTree(v1BlockIdxBucket) + if err != nil { + return err + } + + // Use the block graph to calculate the height of each block. + err = determineBlockHeights(blocksMap) + if err != nil { + return err + } + + // Find blocks on the main chain with the block graph and current tip. + determineMainChainBlocks(blocksMap, tip) + + // Now that we have heights for all blocks, scan the old block index + // bucket and insert all rows into the new one. + return v1BlockIdxBucket.ForEach(func(hashBytes, blockRow []byte) error { + endOffset := blockHdrOffset + blockHdrSize + headerBytes := blockRow[blockHdrOffset:endOffset:endOffset] + + var hash chainhash.Hash + copy(hash[:], hashBytes[0:chainhash.HashSize]) + chainContext := blocksMap[hash] + + if chainContext.height == -1 { + return fmt.Errorf("Unable to calculate chain height for "+ + "stored block %s", hash) + } + + // Mark blocks as valid if they are part of the main chain. + status := statusDataStored + if chainContext.mainChain { + status |= statusValid + } + + // Write header to v2 bucket + value := make([]byte, blockHdrSize+1) + copy(value[0:blockHdrSize], headerBytes) + value[blockHdrSize] = byte(status) + + key := blockIndexKey(&hash, uint32(chainContext.height)) + err := v2BlockIdxBucket.Put(key, value) + if err != nil { + return err + } + + // Delete header from v1 bucket + truncatedRow := blockRow[0:blockHdrOffset:blockHdrOffset] + return v1BlockIdxBucket.Put(hashBytes, truncatedRow) + }) + }) + if err != nil { + return err + } + + log.Infof("Block database migration complete") + return nil +} + +// readBlockTree reads the old block index bucket and constructs a mapping of +// each block to its parent block and all child blocks. This mapping represents +// the full tree of blocks. This function does not populate the height or +// mainChain fields of the returned blockChainContext values. +func readBlockTree(v1BlockIdxBucket database.Bucket) (map[chainhash.Hash]*blockChainContext, error) { + blocksMap := make(map[chainhash.Hash]*blockChainContext) + err := v1BlockIdxBucket.ForEach(func(_, blockRow []byte) error { + var header wire.BlockHeader + endOffset := blockHdrOffset + blockHdrSize + headerBytes := blockRow[blockHdrOffset:endOffset:endOffset] + err := header.Deserialize(bytes.NewReader(headerBytes)) + if err != nil { + return err + } + + blockHash := header.BlockHash() + prevHash := header.PrevBlock + + if blocksMap[blockHash] == nil { + blocksMap[blockHash] = &blockChainContext{height: -1} + } + if blocksMap[prevHash] == nil { + blocksMap[prevHash] = &blockChainContext{height: -1} + } + + blocksMap[blockHash].parent = &prevHash + blocksMap[prevHash].children = + append(blocksMap[prevHash].children, &blockHash) + return nil + }) + return blocksMap, err +} + +// determineBlockHeights takes a map of block hashes to a slice of child hashes +// and uses it to compute the height for each block. The function assigns a +// height of 0 to the genesis hash and explores the tree of blocks +// breadth-first, assigning a height to every block with a path back to the +// genesis block. This function modifies the height field on the blocksMap +// entries. +func determineBlockHeights(blocksMap map[chainhash.Hash]*blockChainContext) error { + queue := list.New() + + // The genesis block is included in blocksMap as a child of the zero hash + // because that is the value of the PrevBlock field in the genesis header. + preGenesisContext, exists := blocksMap[zeroHash] + if !exists || len(preGenesisContext.children) == 0 { + return fmt.Errorf("Unable to find genesis block") + } + + for _, genesisHash := range preGenesisContext.children { + blocksMap[*genesisHash].height = 0 + queue.PushBack(genesisHash) + } + + for e := queue.Front(); e != nil; e = queue.Front() { + queue.Remove(e) + hash := e.Value.(*chainhash.Hash) + height := blocksMap[*hash].height + + // For each block with this one as a parent, assign it a height and + // push to queue for future processing. + for _, childHash := range blocksMap[*hash].children { + blocksMap[*childHash].height = height + 1 + queue.PushBack(childHash) + } + } + + return nil +} + +// determineMainChainBlocks traverses the block graph down from the tip to +// determine which block hashes that are part of the main chain. This function +// modifies the mainChain field on the blocksMap entries. +func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, tip *chainhash.Hash) { + for nextHash := tip; *nextHash != zeroHash; nextHash = blocksMap[*nextHash].parent { + blocksMap[*nextHash].mainChain = true + } +} + +// deserializeUtxoEntryV0 decodes a utxo entry from the passed serialized byte +// slice according to the legacy version 0 format into a map of utxos keyed by +// the output index within the transaction. The map is necessary because the +// previous format encoded all unspent outputs for a transaction using a single +// entry, whereas the new format encodes each unspent output individually. +// +// The legacy format is as follows: +// +//
[,...] +// +// Field Type Size +// version VLQ variable +// block height VLQ variable +// header code VLQ variable +// unspentness bitmap []byte variable +// compressed txouts +// compressed amount VLQ variable +// compressed script []byte variable +// +// The serialized header code format is: +// bit 0 - containing transaction is a coinbase +// bit 1 - output zero is unspent +// bit 2 - output one is unspent +// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2 +// are unset, it encodes N-1 since there must be at least one unspent +// output. +// +// The rationale for the header code scheme is as follows: +// - Transactions which only pay to a single output and a change output are +// extremely common, thus an extra byte for the unspentness bitmap can be +// avoided for them by encoding those two outputs in the low order bits. +// - Given it is encoded as a VLQ which can encode values up to 127 with a +// single byte, that leaves 4 bits to represent the number of bytes in the +// unspentness bitmap while still only consuming a single byte for the +// header code. In other words, an unspentness bitmap with up to 120 +// transaction outputs can be encoded with a single-byte header code. +// This covers the vast majority of transactions. +// - Encoding N-1 bytes when both bits 1 and 2 are unset allows an additional +// 8 outpoints to be encoded before causing the header code to require an +// additional byte. +// +// Example 1: +// From tx in main blockchain: +// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 +// +// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 +// <><><><------------------------------------------------------------------> +// | | \--------\ | +// | height | compressed txout 0 +// version header code +// +// - version: 1 +// - height: 1 +// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness) +// - unspentness: Nothing since it is zero bytes +// - compressed txout 0: +// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) +// - 0x04: special script type pay-to-pubkey +// - 0x96...52: x-coordinate of the pubkey +// +// Example 2: +// From tx in main blockchain: +// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f +// +// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 +// <><----><><><------------------------------------------><--------------------------------------------> +// | | | \-------------------\ | | +// version | \--------\ unspentness | compressed txout 2 +// height header code compressed txout 0 +// +// - version: 1 +// - height: 113931 +// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap) +// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent) +// NOTE: It's +2 since the first two outputs are encoded in the header code +// - compressed txout 0: +// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC) +// - 0x00: special script type pay-to-pubkey-hash +// - 0xe2...8a: pubkey hash +// - compressed txout 2: +// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC) +// - 0x00: special script type pay-to-pubkey-hash +// - 0xb8...58: pubkey hash +// +// Example 3: +// From tx in main blockchain: +// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620 +// +// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 +// <><----><><----><--------------------------------------------------> +// | | | \-----------------\ | +// version | \--------\ unspentness | +// height header code compressed txout 22 +// +// - version: 1 +// - height: 338156 +// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap) +// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded. +// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent) +// NOTE: It's +2 since the first two outputs are encoded in the header code +// - compressed txout 22: +// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC) +// - 0x01: special script type pay-to-script-hash +// - 0x1d...e6: script hash +func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) { + // Deserialize the version. + // + // NOTE: Ignore version since it is no longer used in the new format. + _, bytesRead := deserializeVLQ(serialized) + offset := bytesRead + if offset >= len(serialized) { + return nil, errDeserialize("unexpected end of data after version") + } + + // Deserialize the block height. + blockHeight, bytesRead := deserializeVLQ(serialized[offset:]) + offset += bytesRead + if offset >= len(serialized) { + return nil, errDeserialize("unexpected end of data after height") + } + + // Deserialize the header code. + code, bytesRead := deserializeVLQ(serialized[offset:]) + offset += bytesRead + if offset >= len(serialized) { + return nil, errDeserialize("unexpected end of data after header") + } + + // Decode the header code. + // + // Bit 0 indicates whether the containing transaction is a coinbase. + // Bit 1 indicates output 0 is unspent. + // Bit 2 indicates output 1 is unspent. + // Bits 3-x encodes the number of non-zero unspentness bitmap bytes that + // follow. When both output 0 and 1 are spent, it encodes N-1. + isCoinBase := code&0x01 != 0 + output0Unspent := code&0x02 != 0 + output1Unspent := code&0x04 != 0 + numBitmapBytes := code >> 3 + if !output0Unspent && !output1Unspent { + numBitmapBytes++ + } + + // Ensure there are enough bytes left to deserialize the unspentness + // bitmap. + if uint64(len(serialized[offset:])) < numBitmapBytes { + return nil, errDeserialize("unexpected end of data for " + + "unspentness bitmap") + } + + // Add sparse output for unspent outputs 0 and 1 as needed based on the + // details provided by the header code. + var outputIndexes []uint32 + if output0Unspent { + outputIndexes = append(outputIndexes, 0) + } + if output1Unspent { + outputIndexes = append(outputIndexes, 1) + } + + // Decode the unspentness bitmap adding a sparse output for each unspent + // output. + for i := uint32(0); i < uint32(numBitmapBytes); i++ { + unspentBits := serialized[offset] + for j := uint32(0); j < 8; j++ { + if unspentBits&0x01 != 0 { + // The first 2 outputs are encoded via the + // header code, so adjust the output number + // accordingly. + outputNum := 2 + i*8 + j + outputIndexes = append(outputIndexes, outputNum) + } + unspentBits >>= 1 + } + offset++ + } + + // Map to hold all of the converted outputs. + entries := make(map[uint32]*UtxoEntry) + + // All entries will need to potentially be marked as a coinbase. + var packedFlags txoFlags + if isCoinBase { + packedFlags |= tfCoinBase + } + + // Decode and add all of the utxos. + for i, outputIndex := range outputIndexes { + // Decode the next utxo. + amount, pkScript, bytesRead, err := decodeCompressedTxOut( + serialized[offset:]) + if err != nil { + return nil, errDeserialize(fmt.Sprintf("unable to "+ + "decode utxo at index %d: %v", i, err)) + } + offset += bytesRead + + // Create a new utxo entry with the details deserialized above. + entries[outputIndex] = &UtxoEntry{ + amount: int64(amount), + pkScript: pkScript, + blockHeight: int32(blockHeight), + packedFlags: packedFlags, + } + } + + return entries, nil +} + +// upgradeUtxoSetToV2 migrates the utxo set entries from version 1 to 2 in +// batches. It is guaranteed to updated if this returns without failure. +func upgradeUtxoSetToV2(db database.DB, interrupt <-chan struct{}) error { + // Hardcoded bucket names so updates to the global values do not affect + // old upgrades. + var ( + v1BucketName = []byte("utxoset") + v2BucketName = []byte("utxosetv2") + ) + + log.Infof("Upgrading utxo set to v2. This will take a while...") + start := time.Now() + + // Create the new utxo set bucket as needed. + err := db.Update(func(dbTx database.Tx) error { + _, err := dbTx.Metadata().CreateBucketIfNotExists(v2BucketName) + return err + }) + if err != nil { + return err + } + + // doBatch contains the primary logic for upgrading the utxo set from + // version 1 to 2 in batches. This is done because the utxo set can be + // huge and thus attempting to migrate in a single database transaction + // would result in massive memory usage and could potentially crash on + // many systems due to ulimits. + // + // It returns the number of utxos processed. + const maxUtxos = 200000 + doBatch := func(dbTx database.Tx) (uint32, error) { + v1Bucket := dbTx.Metadata().Bucket(v1BucketName) + v2Bucket := dbTx.Metadata().Bucket(v2BucketName) + v1Cursor := v1Bucket.Cursor() + + // Migrate utxos so long as the max number of utxos for this + // batch has not been exceeded. + var numUtxos uint32 + for ok := v1Cursor.First(); ok && numUtxos < maxUtxos; ok = + v1Cursor.Next() { + + // Old key was the transaction hash. + oldKey := v1Cursor.Key() + var txHash chainhash.Hash + copy(txHash[:], oldKey) + + // Deserialize the old entry which included all utxos + // for the given transaction. + utxos, err := deserializeUtxoEntryV0(v1Cursor.Value()) + if err != nil { + return 0, err + } + + // Add an entry for each utxo into the new bucket using + // the new format. + for txOutIdx, utxo := range utxos { + reserialized, err := serializeUtxoEntry(utxo) + if err != nil { + return 0, err + } + + key := outpointKey(wire.OutPoint{ + Hash: txHash, + Index: txOutIdx, + }) + err = v2Bucket.Put(*key, reserialized) + // NOTE: The key is intentionally not recycled + // here since the database interface contract + // prohibits modifications. It will be garbage + // collected normally when the database is done + // with it. + if err != nil { + return 0, err + } + } + + // Remove old entry. + err = v1Bucket.Delete(oldKey) + if err != nil { + return 0, err + } + + numUtxos += uint32(len(utxos)) + + if interruptRequested(interrupt) { + // No error here so the database transaction + // is not cancelled and therefore outstanding + // work is written to disk. + break + } + } + + return numUtxos, nil + } + + // Migrate all entries in batches for the reasons mentioned above. + var totalUtxos uint64 + for { + var numUtxos uint32 + err := db.Update(func(dbTx database.Tx) error { + var err error + numUtxos, err = doBatch(dbTx) + return err + }) + if err != nil { + return err + } + + if interruptRequested(interrupt) { + return errInterruptRequested + } + + if numUtxos == 0 { + break + } + + totalUtxos += uint64(numUtxos) + log.Infof("Migrated %d utxos (%d total)", numUtxos, totalUtxos) + } + + // Remove the old bucket and update the utxo set version once it has + // been fully migrated. + err = db.Update(func(dbTx database.Tx) error { + err := dbTx.Metadata().DeleteBucket(v1BucketName) + if err != nil { + return err + } + + return dbPutVersion(dbTx, utxoSetVersionKeyName, 2) + }) + if err != nil { + return err + } + + seconds := int64(time.Since(start) / time.Second) + log.Infof("Done upgrading utxo set. Total utxos: %d in %d seconds", + totalUtxos, seconds) + return nil +} + +// maybeUpgradeDbBuckets checks the database version of the buckets used by this +// package and performs any needed upgrades to bring them to the latest version. +// +// All buckets used by this package are guaranteed to be the latest version if +// this function returns without error. +func (b *BlockChain) maybeUpgradeDbBuckets(interrupt <-chan struct{}) error { + // Load or create bucket versions as needed. + var utxoSetVersion uint32 + err := b.db.Update(func(dbTx database.Tx) error { + // Load the utxo set version from the database or create it and + // initialize it to version 1 if it doesn't exist. + var err error + utxoSetVersion, err = dbFetchOrCreateVersion(dbTx, + utxoSetVersionKeyName, 1) + return err + }) + if err != nil { + return err + } + + // Update the utxo set to v2 if needed. + if utxoSetVersion < 2 { + if err := upgradeUtxoSetToV2(b.db, interrupt); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/upgrade_test.go b/vendor/github.com/btcsuite/btcd/blockchain/upgrade_test.go new file mode 100644 index 00000000..97e7f55c --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/upgrade_test.go @@ -0,0 +1,116 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package blockchain + +import ( + "reflect" + "testing" +) + +// TestDeserializeUtxoEntryV0 ensures deserializing unspent trasaction output +// entries from the legacy version 0 format works as expected. +func TestDeserializeUtxoEntryV0(t *testing.T) { + tests := []struct { + name string + entries map[uint32]*UtxoEntry + serialized []byte + }{ + // From tx in main blockchain: + // 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 + { + name: "Only output 0, coinbase", + entries: map[uint32]*UtxoEntry{ + 0: { + amount: 5000000000, + pkScript: hexToBytes("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac"), + blockHeight: 1, + packedFlags: tfCoinBase, + }, + }, + serialized: hexToBytes("010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52"), + }, + // From tx in main blockchain: + // 8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb + { + name: "Only output 1, not coinbase", + entries: map[uint32]*UtxoEntry{ + 1: { + amount: 1000000, + pkScript: hexToBytes("76a914ee8bd501094a7d5ca318da2506de35e1cb025ddc88ac"), + blockHeight: 100001, + packedFlags: 0, + }, + }, + serialized: hexToBytes("01858c21040700ee8bd501094a7d5ca318da2506de35e1cb025ddc"), + }, + // Adapted from tx in main blockchain: + // df3f3f442d9699857f7f49de4ff0b5d0f3448bec31cdc7b5bf6d25f2abd637d5 + { + name: "Only output 2, coinbase", + entries: map[uint32]*UtxoEntry{ + 2: { + amount: 100937281, + pkScript: hexToBytes("76a914da33f77cee27c2a975ed5124d7e4f7f97513510188ac"), + blockHeight: 99004, + packedFlags: tfCoinBase, + }, + }, + serialized: hexToBytes("0185843c010182b095bf4100da33f77cee27c2a975ed5124d7e4f7f975135101"), + }, + // Adapted from tx in main blockchain: + // 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f + { + name: "outputs 0 and 2 not coinbase", + entries: map[uint32]*UtxoEntry{ + 0: { + amount: 20000000, + pkScript: hexToBytes("76a914e2ccd6ec7c6e2e581349c77e067385fa8236bf8a88ac"), + blockHeight: 113931, + packedFlags: 0, + }, + 2: { + amount: 15000000, + pkScript: hexToBytes("76a914b8025be1b3efc63b0ad48e7f9f10e87544528d5888ac"), + blockHeight: 113931, + packedFlags: 0, + }, + }, + serialized: hexToBytes("0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58"), + }, + // Adapted from tx in main blockchain: + // 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620 + { + name: "Only output 22, not coinbase", + entries: map[uint32]*UtxoEntry{ + 22: { + amount: 366875659, + pkScript: hexToBytes("a9141dd46a006572d820e448e12d2bbb38640bc718e687"), + blockHeight: 338156, + packedFlags: 0, + }, + }, + serialized: hexToBytes("0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6"), + }, + } + + for i, test := range tests { + // Deserialize to map of utxos keyed by the output index. + entries, err := deserializeUtxoEntryV0(test.serialized) + if err != nil { + t.Errorf("deserializeUtxoEntryV0 #%d (%s) unexpected "+ + "error: %v", i, test.name, err) + continue + } + + // Ensure the deserialized entry has the same properties as the + // ones in the test entry. + if !reflect.DeepEqual(entries, test.entries) { + t.Errorf("deserializeUtxoEntryV0 #%d (%s) unexpected "+ + "entries: got %v, want %v", i, test.name, + entries, test.entries) + continue + } + } +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/utxoviewpoint.go b/vendor/github.com/btcsuite/btcd/blockchain/utxoviewpoint.go index f3d45cbb..08005d27 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/utxoviewpoint.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/utxoviewpoint.go @@ -10,179 +10,104 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/database" "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" ) -// utxoOutput houses details about an individual unspent transaction output such -// as whether or not it is spent, its public key script, and how much it pays. -// -// Standard public key scripts are stored in the database using a compressed -// format. Since the vast majority of scripts are of the standard form, a fairly -// significant savings is achieved by discarding the portions of the standard -// scripts that can be reconstructed. -// -// Also, since it is common for only a specific output in a given utxo entry to -// be referenced from a redeeming transaction, the script and amount for a given -// output is not uncompressed until the first time it is accessed. This -// provides a mechanism to avoid the overhead of needlessly uncompressing all -// outputs for a given utxo entry at the time of load. -type utxoOutput struct { - spent bool // Output is spent. - compressed bool // The amount and public key script are compressed. - amount int64 // The amount of the output. - pkScript []byte // The public key script for the output. -} +// txoFlags is a bitmask defining additional information and state for a +// transaction output in a utxo view. +type txoFlags uint8 -// maybeDecompress decompresses the amount and public key script fields of the -// utxo and marks it decompressed if needed. -func (o *utxoOutput) maybeDecompress(version int32) { - // Nothing to do if it's not compressed. - if !o.compressed { - return - } +const ( + // tfCoinBase indicates that a txout was contained in a coinbase tx. + tfCoinBase txoFlags = 1 << iota - o.amount = int64(decompressTxOutAmount(uint64(o.amount))) - o.pkScript = decompressScript(o.pkScript, version) - o.compressed = false -} + // tfSpent indicates that a txout is spent. + tfSpent -// UtxoEntry contains contextual information about an unspent transaction such -// as whether or not it is a coinbase transaction, which block it was found in, -// and the spent status of its outputs. + // tfModified indicates that a txout has been modified since it was + // loaded. + tfModified +) + +// UtxoEntry houses details about an individual transaction output in a utxo +// view such as whether or not it was contained in a coinbase tx, the height of +// the block that contains the tx, whether or not it is spent, its public key +// script, and how much it pays. type UtxoEntry struct { - modified bool // Entry changed since load. - version int32 // The version of this tx. - isCoinBase bool // Whether entry is a coinbase tx. - blockHeight int32 // Height of block containing tx. - sparseOutputs map[uint32]*utxoOutput // Sparse map of unspent outputs. + // NOTE: Additions, deletions, or modifications to the order of the + // definitions in this struct should not be changed without considering + // how it affects alignment on 64-bit platforms. The current order is + // specifically crafted to result in minimal padding. There will be a + // lot of these in memory, so a few extra bytes of padding adds up. + + amount int64 + pkScript []byte // The public key script for the output. + blockHeight int32 // Height of block containing tx. + + // packedFlags contains additional info about output such as whether it + // is a coinbase, whether it is spent, and whether it has been modified + // since it was loaded. This approach is used in order to reduce memory + // usage since there will be a lot of these in memory. + packedFlags txoFlags } -// Version returns the version of the transaction the utxo represents. -func (entry *UtxoEntry) Version() int32 { - return entry.version +// isModified returns whether or not the output has been modified since it was +// loaded. +func (entry *UtxoEntry) isModified() bool { + return entry.packedFlags&tfModified == tfModified } -// IsCoinBase returns whether or not the transaction the utxo entry represents -// is a coinbase. +// IsCoinBase returns whether or not the output was contained in a coinbase +// transaction. func (entry *UtxoEntry) IsCoinBase() bool { - return entry.isCoinBase + return entry.packedFlags&tfCoinBase == tfCoinBase } -// BlockHeight returns the height of the block containing the transaction the -// utxo entry represents. +// BlockHeight returns the height of the block containing the output. func (entry *UtxoEntry) BlockHeight() int32 { return entry.blockHeight } -// IsOutputSpent returns whether or not the provided output index has been -// spent based upon the current state of the unspent transaction output view -// the entry was obtained from. -// -// Returns true if the output index references an output that does not exist -// either due to it being invalid or because the output is not part of the view -// due to previously being spent/pruned. -func (entry *UtxoEntry) IsOutputSpent(outputIndex uint32) bool { - output, ok := entry.sparseOutputs[outputIndex] - if !ok { - return true - } - - return output.spent +// IsSpent returns whether or not the output has been spent based upon the +// current state of the unspent transaction output view it was obtained from. +func (entry *UtxoEntry) IsSpent() bool { + return entry.packedFlags&tfSpent == tfSpent } -// SpendOutput marks the output at the provided index as spent. Specifying an -// output index that does not exist will not have any effect. -func (entry *UtxoEntry) SpendOutput(outputIndex uint32) { - output, ok := entry.sparseOutputs[outputIndex] - if !ok { - return - } - +// Spend marks the output as spent. Spending an output that is already spent +// has no effect. +func (entry *UtxoEntry) Spend() { // Nothing to do if the output is already spent. - if output.spent { + if entry.IsSpent() { return } - entry.modified = true - output.spent = true + // Mark the output as spent and modified. + entry.packedFlags |= tfSpent | tfModified } -// IsFullySpent returns whether or not the transaction the utxo entry represents -// is fully spent. -func (entry *UtxoEntry) IsFullySpent() bool { - // The entry is not fully spent if any of the outputs are unspent. - for _, output := range entry.sparseOutputs { - if !output.spent { - return false - } - } - - return true +// Amount returns the amount of the output. +func (entry *UtxoEntry) Amount() int64 { + return entry.amount } -// AmountByIndex returns the amount of the provided output index. -// -// Returns 0 if the output index references an output that does not exist -// either due to it being invalid or because the output is not part of the view -// due to previously being spent/pruned. -func (entry *UtxoEntry) AmountByIndex(outputIndex uint32) int64 { - output, ok := entry.sparseOutputs[outputIndex] - if !ok { - return 0 - } - - // Ensure the output is decompressed before returning the amount. - output.maybeDecompress(entry.version) - return output.amount +// PkScript returns the public key script for the output. +func (entry *UtxoEntry) PkScript() []byte { + return entry.pkScript } -// PkScriptByIndex returns the public key script for the provided output index. -// -// Returns nil if the output index references an output that does not exist -// either due to it being invalid or because the output is not part of the view -// due to previously being spent/pruned. -func (entry *UtxoEntry) PkScriptByIndex(outputIndex uint32) []byte { - output, ok := entry.sparseOutputs[outputIndex] - if !ok { - return nil - } - - // Ensure the output is decompressed before returning the script. - output.maybeDecompress(entry.version) - return output.pkScript -} - -// Clone returns a deep copy of the utxo entry. +// Clone returns a shallow copy of the utxo entry. func (entry *UtxoEntry) Clone() *UtxoEntry { if entry == nil { return nil } - newEntry := &UtxoEntry{ - version: entry.version, - isCoinBase: entry.isCoinBase, - blockHeight: entry.blockHeight, - sparseOutputs: make(map[uint32]*utxoOutput), - } - for outputIndex, output := range entry.sparseOutputs { - newEntry.sparseOutputs[outputIndex] = &utxoOutput{ - spent: output.spent, - compressed: output.compressed, - amount: output.amount, - pkScript: output.pkScript, - } - } - return newEntry -} - -// newUtxoEntry returns a new unspent transaction output entry with the provided -// coinbase flag and block height ready to have unspent outputs added. -func newUtxoEntry(version int32, isCoinBase bool, blockHeight int32) *UtxoEntry { return &UtxoEntry{ - version: version, - isCoinBase: isCoinBase, - blockHeight: blockHeight, - sparseOutputs: make(map[uint32]*utxoOutput), + amount: entry.amount, + pkScript: entry.pkScript, + blockHeight: entry.blockHeight, + packedFlags: entry.packedFlags, } } @@ -194,7 +119,7 @@ func newUtxoEntry(version int32, isCoinBase bool, blockHeight int32) *UtxoEntry // The unspent outputs are needed by other transactions for things such as // script validation and double spend prevention. type UtxoViewpoint struct { - entries map[chainhash.Hash]*UtxoEntry + entries map[wire.OutPoint]*UtxoEntry bestHash chainhash.Hash } @@ -210,17 +135,60 @@ func (view *UtxoViewpoint) SetBestHash(hash *chainhash.Hash) { view.bestHash = *hash } -// LookupEntry returns information about a given transaction according to the -// current state of the view. It will return nil if the passed transaction -// hash does not exist in the view or is otherwise not available such as when -// it has been disconnected during a reorg. -func (view *UtxoViewpoint) LookupEntry(txHash *chainhash.Hash) *UtxoEntry { - entry, ok := view.entries[*txHash] - if !ok { - return nil +// LookupEntry returns information about a given transaction output according to +// the current state of the view. It will return nil if the passed output does +// not exist in the view or is otherwise not available such as when it has been +// disconnected during a reorg. +func (view *UtxoViewpoint) LookupEntry(outpoint wire.OutPoint) *UtxoEntry { + return view.entries[outpoint] +} + +// addTxOut adds the specified output to the view if it is not provably +// unspendable. When the view already has an entry for the output, it will be +// marked unspent. All fields will be updated for existing entries since it's +// possible it has changed during a reorg. +func (view *UtxoViewpoint) addTxOut(outpoint wire.OutPoint, txOut *wire.TxOut, isCoinBase bool, blockHeight int32) { + // Don't add provably unspendable outputs. + if txscript.IsUnspendable(txOut.PkScript) { + return } - return entry + // Update existing entries. All fields are updated because it's + // possible (although extremely unlikely) that the existing entry is + // being replaced by a different transaction with the same hash. This + // is allowed so long as the previous transaction is fully spent. + entry := view.LookupEntry(outpoint) + if entry == nil { + entry = new(UtxoEntry) + view.entries[outpoint] = entry + } + + entry.amount = txOut.Value + entry.pkScript = txOut.PkScript + entry.blockHeight = blockHeight + entry.packedFlags = tfModified + if isCoinBase { + entry.packedFlags |= tfCoinBase + } +} + +// AddTxOut adds the specified output of the passed transaction to the view if +// it exists and is not provably unspendable. When the view already has an +// entry for the output, it will be marked unspent. All fields will be updated +// for existing entries since it's possible it has changed during a reorg. +func (view *UtxoViewpoint) AddTxOut(tx *btcutil.Tx, txOutIdx uint32, blockHeight int32) { + // Can't add an output for an out of bounds index. + if txOutIdx >= uint32(len(tx.MsgTx().TxOut)) { + return + } + + // Update existing entries. All fields are updated because it's + // possible (although extremely unlikely) that the existing entry is + // being replaced by a different transaction with the same hash. This + // is allowed so long as the previous transaction is fully spent. + prevOut := wire.OutPoint{Hash: *tx.Hash(), Index: txOutIdx} + txOut := tx.MsgTx().TxOut[txOutIdx] + view.addTxOut(prevOut, txOut, IsCoinBase(tx), blockHeight) } // AddTxOuts adds all outputs in the passed transaction which are not provably @@ -228,45 +196,18 @@ func (view *UtxoViewpoint) LookupEntry(txHash *chainhash.Hash) *UtxoEntry { // outputs, they are simply marked unspent. All fields will be updated for // existing entries since it's possible it has changed during a reorg. func (view *UtxoViewpoint) AddTxOuts(tx *btcutil.Tx, blockHeight int32) { - // When there are not already any utxos associated with the transaction, - // add a new entry for it to the view. - entry := view.LookupEntry(tx.Hash()) - if entry == nil { - entry = newUtxoEntry(tx.MsgTx().Version, IsCoinBase(tx), - blockHeight) - view.entries[*tx.Hash()] = entry - } else { - entry.blockHeight = blockHeight - } - entry.modified = true - // Loop all of the transaction outputs and add those which are not // provably unspendable. + isCoinBase := IsCoinBase(tx) + prevOut := wire.OutPoint{Hash: *tx.Hash()} for txOutIdx, txOut := range tx.MsgTx().TxOut { - if txscript.IsUnspendable(txOut.PkScript) { - continue - } - // Update existing entries. All fields are updated because it's // possible (although extremely unlikely) that the existing // entry is being replaced by a different transaction with the // same hash. This is allowed so long as the previous // transaction is fully spent. - if output, ok := entry.sparseOutputs[uint32(txOutIdx)]; ok { - output.spent = false - output.compressed = false - output.amount = txOut.Value - output.pkScript = txOut.PkScript - continue - } - - // Add the unspent transaction output. - entry.sparseOutputs[uint32(txOutIdx)] = &utxoOutput{ - spent: false, - compressed: false, - amount: txOut.Value, - pkScript: txOut.PkScript, - } + prevOut.Index = uint32(txOutIdx) + view.addTxOut(prevOut, txOut, isCoinBase, blockHeight) } } @@ -275,7 +216,7 @@ func (view *UtxoViewpoint) AddTxOuts(tx *btcutil.Tx, blockHeight int32) { // spent. In addition, when the 'stxos' argument is not nil, it will be updated // to append an entry for each spent txout. An error will be returned if the // view does not contain the required utxos. -func (view *UtxoViewpoint) connectTransaction(tx *btcutil.Tx, blockHeight int32, stxos *[]spentTxOut) error { +func (view *UtxoViewpoint) connectTransaction(tx *btcutil.Tx, blockHeight int32, stxos *[]SpentTxOut) error { // Coinbase transactions don't have any inputs to spend. if IsCoinBase(tx) { // Add the transaction's outputs as available utxos. @@ -287,39 +228,30 @@ func (view *UtxoViewpoint) connectTransaction(tx *btcutil.Tx, blockHeight int32, // if a slice was provided for the spent txout details, append an entry // to it. for _, txIn := range tx.MsgTx().TxIn { - originIndex := txIn.PreviousOutPoint.Index - entry := view.entries[txIn.PreviousOutPoint.Hash] - // Ensure the referenced utxo exists in the view. This should // never happen unless there is a bug is introduced in the code. + entry := view.entries[txIn.PreviousOutPoint] if entry == nil { return AssertError(fmt.Sprintf("view missing input %v", txIn.PreviousOutPoint)) } - entry.SpendOutput(originIndex) - // Don't create the stxo details if not requested. - if stxos == nil { - continue + // Only create the stxo details if requested. + if stxos != nil { + // Populate the stxo details using the utxo entry. + var stxo = SpentTxOut{ + Amount: entry.Amount(), + PkScript: entry.PkScript(), + Height: entry.BlockHeight(), + IsCoinBase: entry.IsCoinBase(), + } + *stxos = append(*stxos, stxo) } - // Populate the stxo details using the utxo entry. When the - // transaction is fully spent, set the additional stxo fields - // accordingly since those details will no longer be available - // in the utxo set. - var stxo = spentTxOut{ - compressed: false, - version: entry.Version(), - amount: entry.AmountByIndex(originIndex), - pkScript: entry.PkScriptByIndex(originIndex), - } - if entry.IsFullySpent() { - stxo.height = entry.BlockHeight() - stxo.isCoinBase = entry.IsCoinBase() - } - - // Append the entry to the provided spent txouts slice. - *stxos = append(*stxos, stxo) + // Mark the entry as spent. This is not done until after the + // relevant details have been accessed since spending it might + // clear the fields from memory in the future. + entry.Spend() } // Add the transaction's outputs as available utxos. @@ -332,7 +264,7 @@ func (view *UtxoViewpoint) connectTransaction(tx *btcutil.Tx, blockHeight int32, // spend as spent, and setting the best hash for the view to the passed block. // In addition, when the 'stxos' argument is not nil, it will be updated to // append an entry for each spent txout. -func (view *UtxoViewpoint) connectTransactions(block *btcutil.Block, stxos *[]spentTxOut) error { +func (view *UtxoViewpoint) connectTransactions(block *btcutil.Block, stxos *[]SpentTxOut) error { for _, tx := range block.Transactions() { err := view.connectTransaction(tx, block.Height(), stxos) if err != nil { @@ -346,11 +278,37 @@ func (view *UtxoViewpoint) connectTransactions(block *btcutil.Block, stxos *[]sp return nil } +// fetchEntryByHash attempts to find any available utxo for the given hash by +// searching the entire set of possible outputs for the given hash. It checks +// the view first and then falls back to the database if needed. +func (view *UtxoViewpoint) fetchEntryByHash(db database.DB, hash *chainhash.Hash) (*UtxoEntry, error) { + // First attempt to find a utxo with the provided hash in the view. + prevOut := wire.OutPoint{Hash: *hash} + for idx := uint32(0); idx < MaxOutputsPerBlock; idx++ { + prevOut.Index = idx + entry := view.LookupEntry(prevOut) + if entry != nil { + return entry, nil + } + } + + // Check the database since it doesn't exist in the view. This will + // often by the case since only specifically referenced utxos are loaded + // into the view. + var entry *UtxoEntry + err := db.View(func(dbTx database.Tx) error { + var err error + entry, err = dbFetchUtxoEntryByHash(dbTx, hash) + return err + }) + return entry, err +} + // disconnectTransactions updates the view by removing all of the transactions // created by the passed block, restoring all utxos the transactions spent by // using the provided spent txo information, and setting the best hash for the // view to the block before the passed block. -func (view *UtxoViewpoint) disconnectTransactions(block *btcutil.Block, stxos []spentTxOut) error { +func (view *UtxoViewpoint) disconnectTransactions(db database.DB, block *btcutil.Block, stxos []SpentTxOut) error { // Sanity check the correct number of stxos are provided. if len(stxos) != countSpentOutputs(block) { return AssertError("disconnectTransactions called with bad " + @@ -365,25 +323,52 @@ func (view *UtxoViewpoint) disconnectTransactions(block *btcutil.Block, stxos [] for txIdx := len(transactions) - 1; txIdx > -1; txIdx-- { tx := transactions[txIdx] - // Clear this transaction from the view if it already exists or - // create a new empty entry for when it does not. This is done - // because the code relies on its existence in the view in order - // to signal modifications have happened. - isCoinbase := txIdx == 0 - entry := view.entries[*tx.Hash()] - if entry == nil { - entry = newUtxoEntry(tx.MsgTx().Version, isCoinbase, - block.Height()) - view.entries[*tx.Hash()] = entry + // All entries will need to potentially be marked as a coinbase. + var packedFlags txoFlags + isCoinBase := txIdx == 0 + if isCoinBase { + packedFlags |= tfCoinBase + } + + // Mark all of the spendable outputs originally created by the + // transaction as spent. It is instructive to note that while + // the outputs aren't actually being spent here, rather they no + // longer exist, since a pruned utxo set is used, there is no + // practical difference between a utxo that does not exist and + // one that has been spent. + // + // When the utxo does not already exist in the view, add an + // entry for it and then mark it spent. This is done because + // the code relies on its existence in the view in order to + // signal modifications have happened. + txHash := tx.Hash() + prevOut := wire.OutPoint{Hash: *txHash} + for txOutIdx, txOut := range tx.MsgTx().TxOut { + if txscript.IsUnspendable(txOut.PkScript) { + continue + } + + prevOut.Index = uint32(txOutIdx) + entry := view.entries[prevOut] + if entry == nil { + entry = &UtxoEntry{ + amount: txOut.Value, + pkScript: txOut.PkScript, + blockHeight: block.Height(), + packedFlags: packedFlags, + } + + view.entries[prevOut] = entry + } + + entry.Spend() } - entry.modified = true - entry.sparseOutputs = make(map[uint32]*utxoOutput) // Loop backwards through all of the transaction inputs (except // for the coinbase which has no inputs) and unspend the // referenced txos. This is necessary to match the order of the // spent txout entries. - if isCoinbase { + if isCoinBase { continue } for txInIdx := len(tx.MsgTx().TxIn) - 1; txInIdx > -1; txInIdx-- { @@ -393,40 +378,57 @@ func (view *UtxoViewpoint) disconnectTransactions(block *btcutil.Block, stxos [] stxoIdx-- // When there is not already an entry for the referenced - // transaction in the view, it means it was fully spent, + // output in the view, it means it was previously spent, // so create a new utxo entry in order to resurrect it. - txIn := tx.MsgTx().TxIn[txInIdx] - originHash := &txIn.PreviousOutPoint.Hash - originIndex := txIn.PreviousOutPoint.Index - entry := view.entries[*originHash] + originOut := &tx.MsgTx().TxIn[txInIdx].PreviousOutPoint + entry := view.entries[*originOut] if entry == nil { - entry = newUtxoEntry(stxo.version, - stxo.isCoinBase, stxo.height) - view.entries[*originHash] = entry + entry = new(UtxoEntry) + view.entries[*originOut] = entry } - // Mark the entry as modified since it is either new - // or will be changed below. - entry.modified = true - - // Restore the specific utxo using the stxo data from - // the spend journal if it doesn't already exist in the - // view. - output, ok := entry.sparseOutputs[originIndex] - if !ok { - // Add the unspent transaction output. - entry.sparseOutputs[originIndex] = &utxoOutput{ - spent: false, - compressed: stxo.compressed, - amount: stxo.amount, - pkScript: stxo.pkScript, + // The legacy v1 spend journal format only stored the + // coinbase flag and height when the output was the last + // unspent output of the transaction. As a result, when + // the information is missing, search for it by scanning + // all possible outputs of the transaction since it must + // be in one of them. + // + // It should be noted that this is quite inefficient, + // but it realistically will almost never run since all + // new entries include the information for all outputs + // and thus the only way this will be hit is if a long + // enough reorg happens such that a block with the old + // spend data is being disconnected. The probability of + // that in practice is extremely low to begin with and + // becomes vanishingly small the more new blocks are + // connected. In the case of a fresh database that has + // only ever run with the new v2 format, this code path + // will never run. + if stxo.Height == 0 { + utxo, err := view.fetchEntryByHash(db, txHash) + if err != nil { + return err } - continue + if utxo == nil { + return AssertError(fmt.Sprintf("unable "+ + "to resurrect legacy stxo %v", + *originOut)) + } + + stxo.Height = utxo.BlockHeight() + stxo.IsCoinBase = utxo.IsCoinBase() } - // Mark the existing referenced transaction output as - // unspent. - output.spent = false + // Restore the utxo using the stxo data from the spend + // journal and mark it as modified. + entry.amount = stxo.Amount + entry.pkScript = stxo.PkScript + entry.blockHeight = stxo.Height + entry.packedFlags = tfModified + if stxo.IsCoinBase { + entry.packedFlags |= tfCoinBase + } } } @@ -436,88 +438,94 @@ func (view *UtxoViewpoint) disconnectTransactions(block *btcutil.Block, stxos [] return nil } +// RemoveEntry removes the given transaction output from the current state of +// the view. It will have no effect if the passed output does not exist in the +// view. +func (view *UtxoViewpoint) RemoveEntry(outpoint wire.OutPoint) { + delete(view.entries, outpoint) +} + // Entries returns the underlying map that stores of all the utxo entries. -func (view *UtxoViewpoint) Entries() map[chainhash.Hash]*UtxoEntry { +func (view *UtxoViewpoint) Entries() map[wire.OutPoint]*UtxoEntry { return view.entries } // commit prunes all entries marked modified that are now fully spent and marks // all entries as unmodified. func (view *UtxoViewpoint) commit() { - for txHash, entry := range view.entries { - if entry == nil || (entry.modified && entry.IsFullySpent()) { - delete(view.entries, txHash) + for outpoint, entry := range view.entries { + if entry == nil || (entry.isModified() && entry.IsSpent()) { + delete(view.entries, outpoint) continue } - entry.modified = false + entry.packedFlags ^= tfModified } } // fetchUtxosMain fetches unspent transaction output data about the provided -// set of transactions from the point of view of the end of the main chain at -// the time of the call. +// set of outpoints from the point of view of the end of the main chain at the +// time of the call. // // Upon completion of this function, the view will contain an entry for each -// requested transaction. Fully spent transactions, or those which otherwise -// don't exist, will result in a nil entry in the view. -func (view *UtxoViewpoint) fetchUtxosMain(db database.DB, txSet map[chainhash.Hash]struct{}) error { - // Nothing to do if there are no requested hashes. - if len(txSet) == 0 { +// requested outpoint. Spent outputs, or those which otherwise don't exist, +// will result in a nil entry in the view. +func (view *UtxoViewpoint) fetchUtxosMain(db database.DB, outpoints map[wire.OutPoint]struct{}) error { + // Nothing to do if there are no requested outputs. + if len(outpoints) == 0 { return nil } - // Load the unspent transaction output information for the requested set - // of transactions from the point of view of the end of the main chain. + // Load the requested set of unspent transaction outputs from the point + // of view of the end of the main chain. // // NOTE: Missing entries are not considered an error here and instead // will result in nil entries in the view. This is intentionally done - // since other code uses the presence of an entry in the store as a way - // to optimize spend and unspend updates to apply only to the specific - // utxos that the caller needs access to. + // so other code can use the presence of an entry in the store as a way + // to unnecessarily avoid attempting to reload it from the database. return db.View(func(dbTx database.Tx) error { - for hash := range txSet { - hashCopy := hash - entry, err := dbFetchUtxoEntry(dbTx, &hashCopy) + for outpoint := range outpoints { + entry, err := dbFetchUtxoEntry(dbTx, outpoint) if err != nil { return err } - view.entries[hash] = entry + view.entries[outpoint] = entry } return nil }) } -// fetchUtxos loads utxo details about provided set of transaction hashes into -// the view from the database as needed unless they already exist in the view in -// which case they are ignored. -func (view *UtxoViewpoint) fetchUtxos(db database.DB, txSet map[chainhash.Hash]struct{}) error { - // Nothing to do if there are no requested hashes. - if len(txSet) == 0 { +// fetchUtxos loads the unspent transaction outputs for the provided set of +// outputs into the view from the database as needed unless they already exist +// in the view in which case they are ignored. +func (view *UtxoViewpoint) fetchUtxos(db database.DB, outpoints map[wire.OutPoint]struct{}) error { + // Nothing to do if there are no requested outputs. + if len(outpoints) == 0 { return nil } // Filter entries that are already in the view. - txNeededSet := make(map[chainhash.Hash]struct{}) - for hash := range txSet { + neededSet := make(map[wire.OutPoint]struct{}) + for outpoint := range outpoints { // Already loaded into the current view. - if _, ok := view.entries[hash]; ok { + if _, ok := view.entries[outpoint]; ok { continue } - txNeededSet[hash] = struct{}{} + neededSet[outpoint] = struct{}{} } // Request the input utxos from the database. - return view.fetchUtxosMain(db, txNeededSet) + return view.fetchUtxosMain(db, neededSet) } -// fetchInputUtxos loads utxo details about the input transactions referenced -// by the transactions in the given block into the view from the database as -// needed. In particular, referenced entries that are earlier in the block are -// added to the view and entries that are already in the view are not modified. +// fetchInputUtxos loads the unspent transaction outputs for the inputs +// referenced by the transactions in the given block into the view from the +// database as needed. In particular, referenced entries that are earlier in +// the block are added to the view and entries that are already in the view are +// not modified. func (view *UtxoViewpoint) fetchInputUtxos(db database.DB, block *btcutil.Block) error { // Build a map of in-flight transactions because some of the inputs in // this block could be referencing other transactions earlier in this @@ -531,7 +539,7 @@ func (view *UtxoViewpoint) fetchInputUtxos(db database.DB, block *btcutil.Block) // Loop through all of the transaction inputs (except for the coinbase // which has no inputs) collecting them into sets of what is needed and // what is already known (in-flight). - txNeededSet := make(map[chainhash.Hash]struct{}) + neededSet := make(map[wire.OutPoint]struct{}) for i, tx := range transactions[1:] { for _, txIn := range tx.MsgTx().TxIn { // It is acceptable for a transaction input to reference @@ -556,72 +564,74 @@ func (view *UtxoViewpoint) fetchInputUtxos(db database.DB, block *btcutil.Block) // Don't request entries that are already in the view // from the database. - if _, ok := view.entries[*originHash]; ok { + if _, ok := view.entries[txIn.PreviousOutPoint]; ok { continue } - txNeededSet[*originHash] = struct{}{} + neededSet[txIn.PreviousOutPoint] = struct{}{} } } // Request the input utxos from the database. - return view.fetchUtxosMain(db, txNeededSet) + return view.fetchUtxosMain(db, neededSet) } // NewUtxoViewpoint returns a new empty unspent transaction output view. func NewUtxoViewpoint() *UtxoViewpoint { return &UtxoViewpoint{ - entries: make(map[chainhash.Hash]*UtxoEntry), + entries: make(map[wire.OutPoint]*UtxoEntry), } } -// FetchUtxoView loads utxo details about the input transactions referenced by +// FetchUtxoView loads unspent transaction outputs for the inputs referenced by // the passed transaction from the point of view of the end of the main chain. -// It also attempts to fetch the utxo details for the transaction itself so the -// returned view can be examined for duplicate unspent transaction outputs. +// It also attempts to fetch the utxos for the outputs of the transaction itself +// so the returned view can be examined for duplicate transactions. // // This function is safe for concurrent access however the returned view is NOT. func (b *BlockChain) FetchUtxoView(tx *btcutil.Tx) (*UtxoViewpoint, error) { - b.chainLock.RLock() - defer b.chainLock.RUnlock() - - // Create a set of needed transactions based on those referenced by the - // inputs of the passed transaction. Also, add the passed transaction - // itself as a way for the caller to detect duplicates that are not - // fully spent. - txNeededSet := make(map[chainhash.Hash]struct{}) - txNeededSet[*tx.Hash()] = struct{}{} + // Create a set of needed outputs based on those referenced by the + // inputs of the passed transaction and the outputs of the transaction + // itself. + neededSet := make(map[wire.OutPoint]struct{}) + prevOut := wire.OutPoint{Hash: *tx.Hash()} + for txOutIdx := range tx.MsgTx().TxOut { + prevOut.Index = uint32(txOutIdx) + neededSet[prevOut] = struct{}{} + } if !IsCoinBase(tx) { for _, txIn := range tx.MsgTx().TxIn { - txNeededSet[txIn.PreviousOutPoint.Hash] = struct{}{} + neededSet[txIn.PreviousOutPoint] = struct{}{} } } // Request the utxos from the point of view of the end of the main // chain. view := NewUtxoViewpoint() - err := view.fetchUtxosMain(b.db, txNeededSet) + b.chainLock.RLock() + err := view.fetchUtxosMain(b.db, neededSet) + b.chainLock.RUnlock() return view, err } -// FetchUtxoEntry loads and returns the unspent transaction output entry for the -// passed hash from the point of view of the end of the main chain. +// FetchUtxoEntry loads and returns the requested unspent transaction output +// from the point of view of the end of the main chain. // -// NOTE: Requesting a hash for which there is no data will NOT return an error. -// Instead both the entry and the error will be nil. This is done to allow -// pruning of fully spent transactions. In practice this means the caller must -// check if the returned entry is nil before invoking methods on it. +// NOTE: Requesting an output for which there is no data will NOT return an +// error. Instead both the entry and the error will be nil. This is done to +// allow pruning of spent transaction outputs. In practice this means the +// caller must check if the returned entry is nil before invoking methods on it. // // This function is safe for concurrent access however the returned entry (if // any) is NOT. -func (b *BlockChain) FetchUtxoEntry(txHash *chainhash.Hash) (*UtxoEntry, error) { +func (b *BlockChain) FetchUtxoEntry(outpoint wire.OutPoint) (*UtxoEntry, error) { b.chainLock.RLock() defer b.chainLock.RUnlock() var entry *UtxoEntry err := b.db.View(func(dbTx database.Tx) error { var err error - entry, err = dbFetchUtxoEntry(dbTx, txHash) + entry, err = dbFetchUtxoEntry(dbTx, outpoint) return err }) if err != nil { diff --git a/vendor/github.com/btcsuite/btcd/blockchain/validate.go b/vendor/github.com/btcsuite/btcd/blockchain/validate.go index 1e966049..b971337f 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/validate.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/validate.go @@ -47,7 +47,7 @@ var ( // zeroHash is the zero value for a chainhash.Hash and is defined as // a package level variable to avoid the need to create a new instance // every time a check is needed. - zeroHash = &chainhash.Hash{} + zeroHash chainhash.Hash // block91842Hash is one of the two nodes which violate the rules // set forth in BIP0030. It is defined as a package level variable to @@ -63,7 +63,7 @@ var ( // isNullOutpoint determines whether or not a previous transaction output point // is set. func isNullOutpoint(outpoint *wire.OutPoint) bool { - if outpoint.Index == math.MaxUint32 && outpoint.Hash.IsEqual(zeroHash) { + if outpoint.Index == math.MaxUint32 && outpoint.Hash == zeroHash { return true } return false @@ -95,7 +95,7 @@ func IsCoinBaseTx(msgTx *wire.MsgTx) bool { // The previous output of a coin base must have a max value index and // a zero hash. prevOut := &msgTx.TxIn[0].PreviousOutPoint - if prevOut.Index != math.MaxUint32 || !prevOut.Hash.IsEqual(zeroHash) { + if prevOut.Index != math.MaxUint32 || prevOut.Hash != zeroHash { return false } @@ -286,8 +286,7 @@ func CheckTransactionSanity(tx *btcutil.Tx) error { // Previous transaction outputs referenced by the inputs to this // transaction must not be null. for _, txIn := range msgTx.TxIn { - prevOut := &txIn.PreviousOutPoint - if isNullOutpoint(prevOut) { + if isNullOutpoint(&txIn.PreviousOutPoint) { return ruleError(ErrBadTxInput, "transaction "+ "input refers to previous output that "+ "is null") @@ -385,10 +384,8 @@ func CountP2SHSigOps(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint) totalSigOps := 0 for txInIndex, txIn := range msgTx.TxIn { // Ensure the referenced input transaction is available. - originTxHash := &txIn.PreviousOutPoint.Hash - originTxIndex := txIn.PreviousOutPoint.Index - txEntry := utxoView.LookupEntry(originTxHash) - if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) { + utxo := utxoView.LookupEntry(txIn.PreviousOutPoint) + if utxo == nil || utxo.IsSpent() { str := fmt.Sprintf("output %v referenced from "+ "transaction %s:%d either does not exist or "+ "has already been spent", txIn.PreviousOutPoint, @@ -398,7 +395,7 @@ func CountP2SHSigOps(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint) // We're only interested in pay-to-script-hash types, so skip // this input if it's not one. - pkScript := txEntry.PkScriptByIndex(originTxIndex) + pkScript := utxo.PkScript() if !txscript.IsPayToScriptHash(pkScript) { continue } @@ -791,7 +788,7 @@ func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode } // If segwit is active, then we'll need to fully validate the - // new witness commitment for adherance to the rules. + // new witness commitment for adherence to the rules. if segwitState == ThresholdActive { // Validate the witness commitment (if any) within the // block. This involves asserting that if the coinbase @@ -827,16 +824,21 @@ func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode // duplicated to effectively revert the overwritten transactions to a single // confirmation thereby making them vulnerable to a double spend. // -// For more details, see https://en.bitcoin.it/wiki/BIP_0030 and +// For more details, see +// https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki and // http://r6.ca/blog/20120206T005236Z.html. // // This function MUST be called with the chain state lock held (for reads). func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block, view *UtxoViewpoint) error { - // Fetch utxo details for all of the transactions in this block. - // Typically, there will not be any utxos for any of the transactions. - fetchSet := make(map[chainhash.Hash]struct{}) + // Fetch utxos for all of the transaction ouputs in this block. + // Typically, there will not be any utxos for any of the outputs. + fetchSet := make(map[wire.OutPoint]struct{}) for _, tx := range block.Transactions() { - fetchSet[*tx.Hash()] = struct{}{} + prevOut := wire.OutPoint{Hash: *tx.Hash()} + for txOutIdx := range tx.MsgTx().TxOut { + prevOut.Index = uint32(txOutIdx) + fetchSet[prevOut] = struct{}{} + } } err := view.fetchUtxos(b.db, fetchSet) if err != nil { @@ -845,12 +847,12 @@ func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block, view *U // Duplicate transactions are only allowed if the previous transaction // is fully spent. - for _, tx := range block.Transactions() { - txEntry := view.LookupEntry(tx.Hash()) - if txEntry != nil && !txEntry.IsFullySpent() { + for outpoint := range fetchSet { + utxo := view.LookupEntry(outpoint) + if utxo != nil && !utxo.IsSpent() { str := fmt.Sprintf("tried to overwrite transaction %v "+ "at block height %d that is not fully spent", - tx.Hash(), txEntry.blockHeight) + outpoint.Hash, utxo.BlockHeight()) return ruleError(ErrOverwriteTx, str) } } @@ -879,10 +881,8 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo var totalSatoshiIn int64 for txInIndex, txIn := range tx.MsgTx().TxIn { // Ensure the referenced input transaction is available. - originTxHash := &txIn.PreviousOutPoint.Hash - originTxIndex := txIn.PreviousOutPoint.Index - utxoEntry := utxoView.LookupEntry(originTxHash) - if utxoEntry == nil || utxoEntry.IsOutputSpent(originTxIndex) { + utxo := utxoView.LookupEntry(txIn.PreviousOutPoint) + if utxo == nil || utxo.IsSpent() { str := fmt.Sprintf("output %v referenced from "+ "transaction %s:%d either does not exist or "+ "has already been spent", txIn.PreviousOutPoint, @@ -892,15 +892,15 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo // Ensure the transaction is not spending coins which have not // yet reached the required coinbase maturity. - if utxoEntry.IsCoinBase() { - originHeight := utxoEntry.BlockHeight() + if utxo.IsCoinBase() { + originHeight := utxo.BlockHeight() blocksSincePrev := txHeight - originHeight coinbaseMaturity := int32(chainParams.CoinbaseMaturity) if blocksSincePrev < coinbaseMaturity { str := fmt.Sprintf("tried to spend coinbase "+ - "transaction %v from height %v at "+ - "height %v before required maturity "+ - "of %v blocks", originTxHash, + "transaction output %v from height %v "+ + "at height %v before required maturity "+ + "of %v blocks", txIn.PreviousOutPoint, originHeight, txHeight, coinbaseMaturity) return 0, ruleError(ErrImmatureSpend, str) @@ -913,7 +913,7 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo // a transaction are in a unit value known as a satoshi. One // bitcoin is a quantity of satoshi as defined by the // SatoshiPerBitcoin constant. - originTxSatoshi := utxoEntry.AmountByIndex(originTxIndex) + originTxSatoshi := utxo.Amount() if originTxSatoshi < 0 { str := fmt.Sprintf("transaction output has negative "+ "value of %v", btcutil.Amount(originTxSatoshi)) @@ -986,7 +986,7 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo // with that node. // // This function MUST be called with the chain state lock held (for writes). -func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint, stxos *[]spentTxOut) error { +func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint, stxos *[]SpentTxOut) error { // If the side chain blocks end up in the database, a call to // CheckBlockSanity should be done here in case a previous version // allowed a block that is no longer valid. However, since the @@ -1274,8 +1274,6 @@ func (b *BlockChain) CheckConnectBlockTemplate(block *btcutil.Block) error { // is not needed and thus extra work can be avoided. view := NewUtxoViewpoint() view.SetBestHash(&tip.hash) - newNode := newBlockNode(&header, tip.height+1) - newNode.parent = tip - newNode.workSum = newNode.workSum.Add(tip.workSum, newNode.workSum) + newNode := newBlockNode(&header, tip) return b.checkConnectBlock(newNode, block, view, nil) } diff --git a/vendor/github.com/btcsuite/btcd/blockchain/weight.go b/vendor/github.com/btcsuite/btcd/blockchain/weight.go index 286a9197..6f6292a1 100644 --- a/vendor/github.com/btcsuite/btcd/blockchain/weight.go +++ b/vendor/github.com/btcsuite/btcd/blockchain/weight.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -8,6 +8,7 @@ import ( "fmt" "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" ) @@ -27,13 +28,21 @@ const ( // MaxBlockSigOpsCost is the maximum number of signature operations // allowed for a block. It is calculated via a weighted algorithm which - // weights segragated witness sig ops lower than regular sig ops. + // weights segregated witness sig ops lower than regular sig ops. MaxBlockSigOpsCost = 80000 // WitnessScaleFactor determines the level of "discount" witness data // receives compared to "base" data. A scale factor of 4, denotes that // witness data is 1/4 as cheap as regular non-witness data. WitnessScaleFactor = 4 + + // MinTxOutputWeight is the minimum possible weight for a transaction + // output. + MinTxOutputWeight = WitnessScaleFactor * wire.MinTxOutPayload + + // MaxOutputsPerBlock is the maximum number of transaction outputs there + // can be in a block of max weight size. + MaxOutputsPerBlock = MaxBlockWeight / MinTxOutputWeight ) // GetBlockWeight computes the value of the weight metric for a given block. @@ -71,9 +80,7 @@ func GetTransactionWeight(tx *btcutil.Tx) int64 { // legacy sig op count scaled according to the WitnessScaleFactor, the sig op // count for all p2sh inputs scaled by the WitnessScaleFactor, and finally the // unscaled sig op count for any inputs spending witness programs. -func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, - bip16, segWit bool) (int, error) { - +func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, bip16, segWit bool) (int, error) { numSigOps := CountSigOps(tx) * WitnessScaleFactor if bip16 { numP2SHSigOps, err := CountP2SHSigOps(tx, isCoinBaseTx, utxoView) @@ -86,11 +93,10 @@ func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, if segWit && !isCoinBaseTx { msgTx := tx.MsgTx() for txInIndex, txIn := range msgTx.TxIn { - // Ensure the referenced input transaction is available. - originTxHash := &txIn.PreviousOutPoint.Hash - originTxIndex := txIn.PreviousOutPoint.Index - txEntry := utxoView.LookupEntry(originTxHash) - if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) { + // Ensure the referenced output is available and hasn't + // already been spent. + utxo := utxoView.LookupEntry(txIn.PreviousOutPoint) + if utxo == nil || utxo.IsSpent() { str := fmt.Sprintf("output %v referenced from "+ "transaction %s:%d either does not "+ "exist or has already been spent", @@ -101,7 +107,7 @@ func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, witness := txIn.Witness sigScript := txIn.SignatureScript - pkScript := txEntry.PkScriptByIndex(originTxIndex) + pkScript := utxo.PkScript() numSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness) } diff --git a/vendor/github.com/btcsuite/btcd/btcd.go b/vendor/github.com/btcsuite/btcd/btcd.go index 2395974b..a0ccb3ea 100644 --- a/vendor/github.com/btcsuite/btcd/btcd.go +++ b/vendor/github.com/btcsuite/btcd/btcd.go @@ -135,6 +135,14 @@ func btcdMain(serverChan chan<- *server) error { return nil } + if cfg.DropCfIndex { + if err := indexers.DropCfIndex(db, interrupt); err != nil { + btcdLog.Errorf("%v", err) + return err + } + + return nil + } // Create server and start it. server, err := newServer(cfg.Listeners, db, activeNetParams.Params, @@ -202,10 +210,10 @@ func blockDbPath(dbType string) string { return dbPath } -// warnMultipeDBs shows a warning if multiple block database types are detected. +// warnMultipleDBs shows a warning if multiple block database types are detected. // This is not a situation most users want. It is handy for development however // to support multiple side-by-side databases. -func warnMultipeDBs() { +func warnMultipleDBs() { // This is intentionally not using the known db types which depend // on the database types compiled into the binary since we want to // detect legacy db types as well. @@ -253,7 +261,7 @@ func loadBlockDB() (database.DB, error) { return db, nil } - warnMultipeDBs() + warnMultipleDBs() // The database name is based on the database type. dbPath := blockDbPath(cfg.DbType) diff --git a/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go b/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go index 6f140271..42a69037 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go +++ b/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go @@ -8,8 +8,6 @@ package btcec import ( "crypto/rand" - "crypto/sha1" - "encoding/hex" "fmt" "math/big" "testing" @@ -889,163 +887,3 @@ func TestNAFRand(t *testing.T) { } } } - -// These test vectors were taken from -// http://csrc.nist.gov/groups/STM/cavp/documents/dss/ecdsatestvectors.zip -var testVectors = []struct { - msg string - Qx, Qy string - r, s string - ok bool -}{ -/* - * All of these tests are disabled since they are for P224, not sec256k1. - * they are left here as an example of test vectors for when some *real* - * vectors may be found. - * - oga@conformal.com - { - "09626b45493672e48f3d1226a3aff3201960e577d33a7f72c7eb055302db8fe8ed61685dd036b554942a5737cd1512cdf811ee0c00e6dd2f08c69f08643be396e85dafda664801e772cdb7396868ac47b172245b41986aa2648cb77fbbfa562581be06651355a0c4b090f9d17d8f0ab6cced4e0c9d386cf465a516630f0231bd", - "9504b5b82d97a264d8b3735e0568decabc4b6ca275bc53cbadfc1c40", - "03426f80e477603b10dee670939623e3da91a94267fc4e51726009ed", - "81d3ac609f9575d742028dd496450a58a60eea2dcf8b9842994916e1", - "96a8c5f382c992e8f30ccce9af120b067ec1d74678fa8445232f75a5", - false, - }, - { - "96b2b6536f6df29be8567a72528aceeaccbaa66c66c534f3868ca9778b02faadb182e4ed34662e73b9d52ecbe9dc8e875fc05033c493108b380689ebf47e5b062e6a0cdb3dd34ce5fe347d92768d72f7b9b377c20aea927043b509c078ed2467d7113405d2ddd458811e6faf41c403a2a239240180f1430a6f4330df5d77de37", - "851e3100368a22478a0029353045ae40d1d8202ef4d6533cfdddafd8", - "205302ac69457dd345e86465afa72ee8c74ca97e2b0b999aec1f10c2", - "4450c2d38b697e990721aa2dbb56578d32b4f5aeb3b9072baa955ee0", - "e26d4b589166f7b4ba4b1c8fce823fa47aad22f8c9c396b8c6526e12", - false, - }, - { - "86778dbb4a068a01047a8d245d632f636c11d2ad350740b36fad90428b454ad0f120cb558d12ea5c8a23db595d87543d06d1ef489263d01ee529871eb68737efdb8ff85bc7787b61514bed85b7e01d6be209e0a4eb0db5c8df58a5c5bf706d76cb2bdf7800208639e05b89517155d11688236e6a47ed37d8e5a2b1e0adea338e", - "ad5bda09d319a717c1721acd6688d17020b31b47eef1edea57ceeffc", - "c8ce98e181770a7c9418c73c63d01494b8b80a41098c5ea50692c984", - "de5558c257ab4134e52c19d8db3b224a1899cbd08cc508ce8721d5e9", - "745db7af5a477e5046705c0a5eff1f52cb94a79d481f0c5a5e108ecd", - true, - }, - { - "4bc6ef1958556686dab1e39c3700054a304cbd8f5928603dcd97fafd1f29e69394679b638f71c9344ce6a535d104803d22119f57b5f9477e253817a52afa9bfbc9811d6cc8c8be6b6566c6ef48b439bbb532abe30627548c598867f3861ba0b154dc1c3deca06eb28df8efd28258554b5179883a36fbb1eecf4f93ee19d41e3d", - "cc5eea2edf964018bdc0504a3793e4d2145142caa09a72ac5fb8d3e8", - "a48d78ae5d08aa725342773975a00d4219cf7a8029bb8cf3c17c374a", - "67b861344b4e416d4094472faf4272f6d54a497177fbc5f9ef292836", - "1d54f3fcdad795bf3b23408ecbac3e1321d1d66f2e4e3d05f41f7020", - false, - }, - { - "bb658732acbf3147729959eb7318a2058308b2739ec58907dd5b11cfa3ecf69a1752b7b7d806fe00ec402d18f96039f0b78dbb90a59c4414fb33f1f4e02e4089de4122cd93df5263a95be4d7084e2126493892816e6a5b4ed123cb705bf930c8f67af0fb4514d5769232a9b008a803af225160ce63f675bd4872c4c97b146e5e", - "6234c936e27bf141fc7534bfc0a7eedc657f91308203f1dcbd642855", - "27983d87ca785ef4892c3591ef4a944b1deb125dd58bd351034a6f84", - "e94e05b42d01d0b965ffdd6c3a97a36a771e8ea71003de76c4ecb13f", - "1dc6464ffeefbd7872a081a5926e9fc3e66d123f1784340ba17737e9", - false, - }, - { - "7c00be9123bfa2c4290be1d8bc2942c7f897d9a5b7917e3aabd97ef1aab890f148400a89abd554d19bec9d8ed911ce57b22fbcf6d30ca2115f13ce0a3f569a23bad39ee645f624c49c60dcfc11e7d2be24de9c905596d8f23624d63dc46591d1f740e46f982bfae453f107e80db23545782be23ce43708245896fc54e1ee5c43", - "9f3f037282aaf14d4772edffff331bbdda845c3f65780498cde334f1", - "8308ee5a16e3bcb721b6bc30000a0419bc1aaedd761be7f658334066", - "6381d7804a8808e3c17901e4d283b89449096a8fba993388fa11dc54", - "8e858f6b5b253686a86b757bad23658cda53115ac565abca4e3d9f57", - false, - }, - { - "cffc122a44840dc705bb37130069921be313d8bde0b66201aebc48add028ca131914ef2e705d6bedd19dc6cf9459bbb0f27cdfe3c50483808ffcdaffbeaa5f062e097180f07a40ef4ab6ed03fe07ed6bcfb8afeb42c97eafa2e8a8df469de07317c5e1494c41547478eff4d8c7d9f0f484ad90fedf6e1c35ee68fa73f1691601", - "a03b88a10d930002c7b17ca6af2fd3e88fa000edf787dc594f8d4fd4", - "e0cf7acd6ddc758e64847fe4df9915ebda2f67cdd5ec979aa57421f5", - "387b84dcf37dc343c7d2c5beb82f0bf8bd894b395a7b894565d296c1", - "4adc12ce7d20a89ce3925e10491c731b15ddb3f339610857a21b53b4", - false, - }, - { - "26e0e0cafd85b43d16255908ccfd1f061c680df75aba3081246b337495783052ba06c60f4a486c1591a4048bae11b4d7fec4f161d80bdc9a7b79d23e44433ed625eab280521a37f23dd3e1bdc5c6a6cfaa026f3c45cf703e76dab57add93fe844dd4cda67dc3bddd01f9152579e49df60969b10f09ce9372fdd806b0c7301866", - "9a8983c42f2b5a87c37a00458b5970320d247f0c8a88536440173f7d", - "15e489ec6355351361900299088cfe8359f04fe0cab78dde952be80c", - "929a21baa173d438ec9f28d6a585a2f9abcfc0a4300898668e476dc0", - "59a853f046da8318de77ff43f26fe95a92ee296fa3f7e56ce086c872", - true, - }, - { - "1078eac124f48ae4f807e946971d0de3db3748dd349b14cca5c942560fb25401b2252744f18ad5e455d2d97ed5ae745f55ff509c6c8e64606afe17809affa855c4c4cdcaf6b69ab4846aa5624ed0687541aee6f2224d929685736c6a23906d974d3c257abce1a3fb8db5951b89ecb0cda92b5207d93f6618fd0f893c32cf6a6e", - "d6e55820bb62c2be97650302d59d667a411956138306bd566e5c3c2b", - "631ab0d64eaf28a71b9cbd27a7a88682a2167cee6251c44e3810894f", - "65af72bc7721eb71c2298a0eb4eed3cec96a737cc49125706308b129", - "bd5a987c78e2d51598dbd9c34a9035b0069c580edefdacee17ad892a", - false, - }, - { - "919deb1fdd831c23481dfdb2475dcbe325b04c34f82561ced3d2df0b3d749b36e255c4928973769d46de8b95f162b53cd666cad9ae145e7fcfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82130761231f536e6a3d59792f784902c469aa897aabf9a0678f93446610d56d5e0981e4c8a563556b", - "269b455b1024eb92d860a420f143ac1286b8cce43031562ae7664574", - "baeb6ca274a77c44a0247e5eb12ca72bdd9a698b3f3ae69c9f1aaa57", - "cb4ec2160f04613eb0dfe4608486091a25eb12aa4dec1afe91cfb008", - "40b01d8cd06589481574f958b98ca08ade9d2a8fe31024375c01bb40", - false, - }, - { - "6e012361250dacf6166d2dd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33f", - "6d2d695efc6b43b13c14111f2109608f1020e3e03b5e21cfdbc82fcd", - "26a4859296b7e360b69cf40be7bd97ceaffa3d07743c8489fc47ca1b", - "9a8cb5f2fdc288b7183c5b32d8e546fc2ed1ca4285eeae00c8b572ad", - "8c623f357b5d0057b10cdb1a1593dab57cda7bdec9cf868157a79b97", - true, - }, - { - "bf6bd7356a52b234fe24d25557200971fc803836f6fec3cade9642b13a8e7af10ab48b749de76aada9d8927f9b12f75a2c383ca7358e2566c4bb4f156fce1fd4e87ef8c8d2b6b1bdd351460feb22cdca0437ac10ca5e0abbbce9834483af20e4835386f8b1c96daaa41554ceee56730aac04f23a5c765812efa746051f396566", - "14250131b2599939cf2d6bc491be80ddfe7ad9de644387ee67de2d40", - "b5dc473b5d014cd504022043c475d3f93c319a8bdcb7262d9e741803", - "4f21642f2201278a95339a80f75cc91f8321fcb3c9462562f6cbf145", - "452a5f816ea1f75dee4fd514fa91a0d6a43622981966c59a1b371ff8", - false, - }, - { - "0eb7f4032f90f0bd3cf9473d6d9525d264d14c031a10acd31a053443ed5fe919d5ac35e0be77813071b4062f0b5fdf58ad5f637b76b0b305aec18f82441b6e607b44cdf6e0e3c7c57f24e6fd565e39430af4a6b1d979821ed0175fa03e3125506847654d7e1ae904ce1190ae38dc5919e257bdac2db142a6e7cd4da6c2e83770", - "d1f342b7790a1667370a1840255ac5bbbdc66f0bc00ae977d99260ac", - "76416cabae2de9a1000b4646338b774baabfa3db4673790771220cdb", - "bc85e3fc143d19a7271b2f9e1c04b86146073f3fab4dda1c3b1f35ca", - "9a5c70ede3c48d5f43307a0c2a4871934424a3303b815df4bb0f128e", - false, - }, - { - "5cc25348a05d85e56d4b03cec450128727bc537c66ec3a9fb613c151033b5e86878632249cba83adcefc6c1e35dcd31702929c3b57871cda5c18d1cf8f9650a25b917efaed56032e43b6fc398509f0d2997306d8f26675f3a8683b79ce17128e006aa0903b39eeb2f1001be65de0520115e6f919de902b32c38d691a69c58c92", - "7e49a7abf16a792e4c7bbc4d251820a2abd22d9f2fc252a7bf59c9a6", - "44236a8fb4791c228c26637c28ae59503a2f450d4cfb0dc42aa843b9", - "084461b4050285a1a85b2113be76a17878d849e6bc489f4d84f15cd8", - "079b5bddcc4d45de8dbdfd39f69817c7e5afa454a894d03ee1eaaac3", - false, - }, - { - "1951533ce33afb58935e39e363d8497a8dd0442018fd96dff167b3b23d7206a3ee182a3194765df4768a3284e23b8696c199b4686e670d60c9d782f08794a4bccc05cffffbd1a12acd9eb1cfa01f7ebe124da66ecff4599ea7720c3be4bb7285daa1a86ebf53b042bd23208d468c1b3aa87381f8e1ad63e2b4c2ba5efcf05845", - "31945d12ebaf4d81f02be2b1768ed80784bf35cf5e2ff53438c11493", - "a62bebffac987e3b9d3ec451eb64c462cdf7b4aa0b1bbb131ceaa0a4", - "bc3c32b19e42b710bca5c6aaa128564da3ddb2726b25f33603d2af3c", - "ed1a719cc0c507edc5239d76fe50e2306c145ad252bd481da04180c0", - false, - }, -*/ -} - -func TestVectors(t *testing.T) { - sha := sha1.New() - - for i, test := range testVectors { - pub := PublicKey{ - Curve: S256(), - X: fromHex(test.Qx), - Y: fromHex(test.Qy), - } - msg, _ := hex.DecodeString(test.msg) - sha.Reset() - sha.Write(msg) - hashed := sha.Sum(nil) - sig := Signature{R: fromHex(test.r), S: fromHex(test.s)} - if verified := sig.Verify(hashed, &pub); verified != test.ok { - t.Errorf("%d: bad result %v instead of %v", i, verified, - test.ok) - } - if testing.Short() { - break - } - } -} diff --git a/vendor/github.com/btcsuite/btcd/btcec/pubkey.go b/vendor/github.com/btcsuite/btcd/btcec/pubkey.go index b7491771..cf498075 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/pubkey.go +++ b/vendor/github.com/btcsuite/btcd/btcec/pubkey.go @@ -32,8 +32,9 @@ func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, erro x3 := new(big.Int).Mul(x, x) x3.Mul(x3, x) x3.Add(x3, curve.Params().B) + x3.Mod(x3, curve.Params().P) - // now calculate sqrt mod p of x2 + B + // Now calculate sqrt mod p of x^3 + B // This code used to do a full sqrt based on tonelli/shanks, // but this was replaced by the algorithms referenced in // https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294 @@ -42,9 +43,19 @@ func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, erro if ybit != isOdd(y) { y.Sub(curve.Params().P, y) } + + // Check that y is a square root of x^3 + B. + y2 := new(big.Int).Mul(y, y) + y2.Mod(y2, curve.Params().P) + if y2.Cmp(x3) != 0 { + return nil, fmt.Errorf("invalid square root") + } + + // Verify that y-coord has expected parity. if ybit != isOdd(y) { return nil, fmt.Errorf("ybit doesn't match oddness") } + return y, nil } diff --git a/vendor/github.com/btcsuite/btcd/btcec/signature.go b/vendor/github.com/btcsuite/btcd/btcec/signature.go index 4392ab41..6026c424 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/signature.go +++ b/vendor/github.com/btcsuite/btcd/btcec/signature.go @@ -269,7 +269,7 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int { return ret } -// recoverKeyFromSignature recoves a public key from the signature "sig" on the +// recoverKeyFromSignature recovers a public key from the signature "sig" on the // given message hash "msg". Based on the algorithm found in section 5.1.5 of // SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details // in the inner loop in Step 1. The counter provided is actually the j parameter diff --git a/vendor/github.com/btcsuite/btcd/btcec/signature_test.go b/vendor/github.com/btcsuite/btcd/btcec/signature_test.go index a8b3e1e9..a4b86bb8 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/signature_test.go +++ b/vendor/github.com/btcsuite/btcd/btcec/signature_test.go @@ -11,6 +11,7 @@ import ( "encoding/hex" "fmt" "math/big" + "reflect" "testing" ) @@ -523,6 +524,67 @@ func TestSignCompact(t *testing.T) { } } +// recoveryTests assert basic tests for public key recovery from signatures. +// The cases are borrowed from github.com/fjl/btcec-issue. +var recoveryTests = []struct { + msg string + sig string + pub string + err error +}{ + { + // Valid curve point recovered. + msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", + sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc93", + pub: "04E32DF42865E97135ACFB65F3BAE71BDC86F4D49150AD6A440B6F15878109880A0A2B2667F7E725CEEA70C673093BF67663E0312623C8E091B13CF2C0F11EF652", + }, + { + // Invalid curve point recovered. + msg: "00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c", + sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", + err: fmt.Errorf("invalid square root"), + }, + { + // Low R and S values. + msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f", + sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004", + pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3", + }, +} + +func TestRecoverCompact(t *testing.T) { + for i, test := range recoveryTests { + msg := decodeHex(test.msg) + sig := decodeHex(test.sig) + + // Magic DER constant. + sig[0] += 27 + + pub, _, err := RecoverCompact(S256(), sig, msg) + + // Verify that returned error matches as expected. + if !reflect.DeepEqual(test.err, err) { + t.Errorf("unexpected error returned from pubkey "+ + "recovery #%d: wanted %v, got %v", + i, test.err, err) + continue + } + + // If check succeeded because a proper error was returned, we + // ignore the returned pubkey. + if err != nil { + continue + } + + // Otherwise, ensure the correct public key was recovered. + exPub, _ := ParsePubKey(decodeHex(test.pub), S256()) + if !exPub.IsEqual(pub) { + t.Errorf("unexpected recovered public key #%d: "+ + "want %v, got %v", i, exPub, pub) + } + } +} + func TestRFC6979(t *testing.T) { // Test vectors matching Trezor and CoreBitcoin implementations. // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 diff --git a/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds.go b/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds.go index 83c417eb..a5e56471 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds.go @@ -10,6 +10,8 @@ package btcjson import ( "encoding/json" "fmt" + + "github.com/btcsuite/btcd/wire" ) // AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the @@ -279,6 +281,37 @@ func NewGetBlockTemplateCmd(request *TemplateRequest) *GetBlockTemplateCmd { } } +// GetCFilterCmd defines the getcfilter JSON-RPC command. +type GetCFilterCmd struct { + Hash string + FilterType wire.FilterType +} + +// NewGetCFilterCmd returns a new instance which can be used to issue a +// getcfilter JSON-RPC command. +func NewGetCFilterCmd(hash string, filterType wire.FilterType) *GetCFilterCmd { + return &GetCFilterCmd{ + Hash: hash, + FilterType: filterType, + } +} + +// GetCFilterHeaderCmd defines the getcfilterheader JSON-RPC command. +type GetCFilterHeaderCmd struct { + Hash string + FilterType wire.FilterType +} + +// NewGetCFilterHeaderCmd returns a new instance which can be used to issue a +// getcfilterheader JSON-RPC command. +func NewGetCFilterHeaderCmd(hash string, + filterType wire.FilterType) *GetCFilterHeaderCmd { + return &GetCFilterHeaderCmd{ + Hash: hash, + FilterType: filterType, + } +} + // GetChainTipsCmd defines the getchaintips JSON-RPC command. type GetChainTipsCmd struct{} @@ -756,6 +789,8 @@ func init() { MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags) MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags) MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags) + MustRegisterCmd("getcfilter", (*GetCFilterCmd)(nil), flags) + MustRegisterCmd("getcfilterheader", (*GetCFilterHeaderCmd)(nil), flags) MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags) MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags) MustRegisterCmd("getdifficulty", (*GetDifficultyCmd)(nil), flags) diff --git a/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds_test.go b/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds_test.go index d623012b..8cb4ee76 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds_test.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds_test.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/wire" ) // TestChainSvrCmds tests all of the chain server commands marshal and unmarshal @@ -317,6 +318,38 @@ func TestChainSvrCmds(t *testing.T) { }, }, }, + { + name: "getcfilter", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getcfilter", "123", + wire.GCSFilterRegular) + }, + staticCmd: func() interface{} { + return btcjson.NewGetCFilterCmd("123", + wire.GCSFilterRegular) + }, + marshalled: `{"jsonrpc":"1.0","method":"getcfilter","params":["123",0],"id":1}`, + unmarshalled: &btcjson.GetCFilterCmd{ + Hash: "123", + FilterType: wire.GCSFilterRegular, + }, + }, + { + name: "getcfilterheader", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getcfilterheader", "123", + wire.GCSFilterRegular) + }, + staticCmd: func() interface{} { + return btcjson.NewGetCFilterHeaderCmd("123", + wire.GCSFilterRegular) + }, + marshalled: `{"jsonrpc":"1.0","method":"getcfilterheader","params":["123",0],"id":1}`, + unmarshalled: &btcjson.GetCFilterHeaderCmd{ + Hash: "123", + FilterType: wire.GCSFilterRegular, + }, + }, { name: "getchaintips", newCmd: func() (interface{}, error) { @@ -1158,8 +1191,8 @@ func TestChainSvrCmdErrors(t *testing.T) { for i, test := range tests { err := json.Unmarshal([]byte(test.marshalled), &test.result) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+ - "want %T", i, test.name, err, test.err) + t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+ + "want %T", i, test.name, err, err, test.err) continue } diff --git a/vendor/github.com/btcsuite/btcd/btcjson/chainsvrresults.go b/vendor/github.com/btcsuite/btcd/btcjson/chainsvrresults.go index 33d54d38..30c6369a 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/chainsvrresults.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/chainsvrresults.go @@ -11,7 +11,7 @@ import "encoding/json" // returns a hex-encoded string. type GetBlockHeaderVerboseResult struct { Hash string `json:"hash"` - Confirmations uint64 `json:"confirmations"` + Confirmations int64 `json:"confirmations"` Height int32 `json:"height"` Version int32 `json:"version"` VersionHex string `json:"versionHex"` @@ -29,7 +29,7 @@ type GetBlockHeaderVerboseResult struct { // hex-encoded string. type GetBlockVerboseResult struct { Hash string `json:"hash"` - Confirmations uint64 `json:"confirmations"` + Confirmations int64 `json:"confirmations"` StrippedSize int32 `json:"strippedsize"` Size int32 `json:"size"` Weight int32 `json:"weight"` @@ -289,7 +289,6 @@ type GetTxOutResult struct { Confirmations int64 `json:"confirmations"` Value float64 `json:"value"` ScriptPubKey ScriptPubKeyResult `json:"scriptPubKey"` - Version int32 `json:"version"` Coinbase bool `json:"coinbase"` } diff --git a/vendor/github.com/btcsuite/btcd/btcjson/cmdinfo_test.go b/vendor/github.com/btcsuite/btcd/btcjson/cmdinfo_test.go index b3336e64..04404027 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/cmdinfo_test.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/cmdinfo_test.go @@ -183,7 +183,7 @@ func TestMethodUsageText(t *testing.T) { continue } - // Get the usage again to excerise caching. + // Get the usage again to exercise caching. usage, err = btcjson.MethodUsageText(test.method) if err != nil { t.Errorf("Test #%d (%s) unexpected error: %v", i, diff --git a/vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go b/vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go index abe52e36..48c6278a 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go @@ -183,7 +183,7 @@ func typesMaybeCompatible(dest reflect.Type, src reflect.Type) bool { return true } - // When both types are numeric, they are potentially compatibile. + // When both types are numeric, they are potentially compatible. srcKind := src.Kind() destKind := dest.Kind() if isNumeric(destKind) && isNumeric(srcKind) { diff --git a/vendor/github.com/btcsuite/btcd/btcjson/cmdparse_test.go b/vendor/github.com/btcsuite/btcd/btcjson/cmdparse_test.go index 2f8fa1fb..7c13a0bb 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/cmdparse_test.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/cmdparse_test.go @@ -387,8 +387,8 @@ func TestNewCmdErrors(t *testing.T) { for i, test := range tests { _, err := btcjson.NewCmd(test.method, test.args...) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+ - "want %T", i, test.name, err, test.err) + t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+ + "want %T", i, test.name, err, err, test.err) continue } gotErrorCode := err.(btcjson.Error).ErrorCode @@ -435,8 +435,8 @@ func TestMarshalCmdErrors(t *testing.T) { for i, test := range tests { _, err := btcjson.MarshalCmd(test.id, test.cmd) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+ - "want %T", i, test.name, err, test.err) + t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+ + "want %T", i, test.name, err, err, test.err) continue } gotErrorCode := err.(btcjson.Error).ErrorCode @@ -504,8 +504,8 @@ func TestUnmarshalCmdErrors(t *testing.T) { for i, test := range tests { _, err := btcjson.UnmarshalCmd(&test.request) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+ - "want %T", i, test.name, err, test.err) + t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+ + "want %T", i, test.name, err, err, test.err) continue } gotErrorCode := err.(btcjson.Error).ErrorCode diff --git a/vendor/github.com/btcsuite/btcd/btcjson/help_test.go b/vendor/github.com/btcsuite/btcd/btcjson/help_test.go index 265e0c2c..918aa144 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/help_test.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/help_test.go @@ -699,8 +699,8 @@ func TestGenerateHelpErrors(t *testing.T) { _, err := btcjson.GenerateHelp(test.method, nil, test.resultTypes...) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+ - "want %T", i, test.name, err, test.err) + t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+ + "want %T", i, test.name, err, err, test.err) continue } gotErrorCode := err.(btcjson.Error).ErrorCode diff --git a/vendor/github.com/btcsuite/btcd/btcjson/jsonrpcerr.go b/vendor/github.com/btcsuite/btcd/btcjson/jsonrpcerr.go index b3a48c0d..c9431c5a 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/jsonrpcerr.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/jsonrpcerr.go @@ -71,6 +71,7 @@ const ( ErrRPCDifficulty RPCErrorCode = -5 ErrRPCOutOfRange RPCErrorCode = -1 ErrRPCNoTxInfo RPCErrorCode = -5 + ErrRPCNoCFIndex RPCErrorCode = -5 ErrRPCNoNewestBlockInfo RPCErrorCode = -5 ErrRPCInvalidTxVout RPCErrorCode = -5 ErrRPCRawTxString RPCErrorCode = -32602 diff --git a/vendor/github.com/btcsuite/btcd/btcjson/register_test.go b/vendor/github.com/btcsuite/btcd/btcjson/register_test.go index 4cac9c7a..3832678a 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/register_test.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/register_test.go @@ -247,7 +247,7 @@ func TestMustRegisterCmdPanic(t *testing.T) { func TestRegisteredCmdMethods(t *testing.T) { t.Parallel() - // Ensure the registerd methods are returned. + // Ensure the registered methods are returned. methods := btcjson.RegisteredCmdMethods() if len(methods) == 0 { t.Fatal("RegisteredCmdMethods: no methods") diff --git a/vendor/github.com/btcsuite/btcd/btcjson/walletsvrwsntfns.go b/vendor/github.com/btcsuite/btcd/btcjson/walletsvrwsntfns.go index 26dc1508..8df8ebe6 100644 --- a/vendor/github.com/btcsuite/btcd/btcjson/walletsvrwsntfns.go +++ b/vendor/github.com/btcsuite/btcd/btcjson/walletsvrwsntfns.go @@ -21,7 +21,7 @@ const ( WalletLockStateNtfnMethod = "walletlockstate" // NewTxNtfnMethod is the method used to notify that a wallet server has - // added a new transaction to the transaciton store. + // added a new transaction to the transaction store. NewTxNtfnMethod = "newtx" ) diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md index 41eeef70..fc49d9cd 100644 --- a/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md +++ b/vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md @@ -4,6 +4,7 @@ chainhash [![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/chaincfg/chainhash) +======= chainhash provides a generic hash type and associated functions that allows the specific hash algorithm to be abstracted. diff --git a/vendor/github.com/btcsuite/btcd/chaincfg/params.go b/vendor/github.com/btcsuite/btcd/chaincfg/params.go index 60c99ac3..9da7102b 100644 --- a/vendor/github.com/btcsuite/btcd/chaincfg/params.go +++ b/vendor/github.com/btcsuite/btcd/chaincfg/params.go @@ -87,12 +87,12 @@ const ( DeploymentTestDummy = iota // DeploymentCSV defines the rule change deployment ID for the CSV - // soft-fork package. The CSV package includes the depolyment of BIPS + // soft-fork package. The CSV package includes the deployment of BIPS // 68, 112, and 113. DeploymentCSV // DeploymentSegwit defines the rule change deployment ID for the - // Segragated Witness (segwit) soft-fork package. The segwit package + // Segregated Witness (segwit) soft-fork package. The segwit package // includes the deployment of BIPS 141, 142, 144, 145, 147 and 173. DeploymentSegwit @@ -379,7 +379,7 @@ var RegressionNetParams = Params{ // Human-readable part for Bech32 encoded segwit addresses, as defined in // BIP 173. - Bech32HRPSegwit: "tb", // always tb for test net + Bech32HRPSegwit: "bcrt", // always bcrt for reg test net // Address encoding magics PubKeyHashAddrID: 0x6f, // starts with m or n diff --git a/vendor/github.com/btcsuite/btcd/config.go b/vendor/github.com/btcsuite/btcd/config.go index 1192be4f..e004e428 100644 --- a/vendor/github.com/btcsuite/btcd/config.go +++ b/vendor/github.com/btcsuite/btcd/config.go @@ -27,6 +27,7 @@ import ( "github.com/btcsuite/btcd/database" _ "github.com/btcsuite/btcd/database/ffldb" "github.com/btcsuite/btcd/mempool" + "github.com/btcsuite/btcd/peer" "github.com/btcsuite/btcutil" "github.com/btcsuite/go-socks/socks" flags "github.com/jessevdk/go-flags" @@ -47,6 +48,7 @@ const ( defaultMaxRPCConcurrentReqs = 20 defaultDbType = "ffldb" defaultFreeTxRelayLimit = 15.0 + defaultTrickleInterval = peer.DefaultTrickleInterval defaultBlockMinSize = 0 defaultBlockMaxSize = 750000 defaultBlockMinWeight = 0 @@ -140,6 +142,7 @@ type config struct { MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in BTC/kB to be considered a non-zero fee."` FreeTxRelayLimit float64 `long:"limitfreerelay" description:"Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute"` NoRelayPriority bool `long:"norelaypriority" description:"Do not require free or low-fee transactions to have high priority for relaying"` + TrickleInterval time.Duration `long:"trickleinterval" description:"Minimum time between attempts to send new inventory to a connected peer"` MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"` Generate bool `long:"generate" description:"Generate (mine) bitcoins using the CPU"` MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"` @@ -150,6 +153,8 @@ type config struct { BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"` UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"` + NoCFilters bool `long:"nocfilters" description:"Disable committed filtering (CF) support"` + DropCfIndex bool `long:"dropcfindex" description:"Deletes the index used for committed filtering (CF) support from the database on start up and then exits."` SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"` BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."` TxIndex bool `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"` @@ -413,6 +418,7 @@ func loadConfig() (*config, []string, error) { RPCCert: defaultRPCCertFile, MinRelayTxFee: mempool.DefaultMinRelayTxFee.ToBTC(), FreeTxRelayLimit: defaultFreeTxRelayLimit, + TrickleInterval: defaultTrickleInterval, BlockMinSize: defaultBlockMinSize, BlockMaxSize: defaultBlockMaxSize, BlockMinWeight: defaultBlockMinWeight, diff --git a/vendor/github.com/btcsuite/btcd/connmgr/connmanager.go b/vendor/github.com/btcsuite/btcd/connmgr/connmanager.go index 5f056b33..4acc0b2d 100644 --- a/vendor/github.com/btcsuite/btcd/connmgr/connmanager.go +++ b/vendor/github.com/btcsuite/btcd/connmgr/connmanager.go @@ -46,9 +46,10 @@ type ConnState uint8 // connection which was disconnected is categorized as disconnected. const ( ConnPending ConnState = iota + ConnFailing + ConnCanceled ConnEstablished ConnDisconnected - ConnFailed ) // ConnReq is the connection request to a network address. If permanent, the @@ -143,6 +144,15 @@ type Config struct { Dial func(net.Addr) (net.Conn, error) } +// registerPending is used to register a pending connection attempt. By +// registering pending connection attempts we allow callers to cancel pending +// connection attempts before their successful or in the case they're not +// longer wanted. +type registerPending struct { + c *ConnReq + done chan struct{} +} + // handleConnected is used to queue a successful connection. type handleConnected struct { c *ConnReq @@ -216,15 +226,40 @@ func (cm *ConnManager) handleFailedConn(c *ConnReq) { // connections so that we remain connected to the network. Connection requests // are processed and mapped by their assigned ids. func (cm *ConnManager) connHandler() { - conns := make(map[uint64]*ConnReq, cm.cfg.TargetOutbound) + + var ( + // pending holds all registered conn requests that have yet to + // succeed. + pending = make(map[uint64]*ConnReq) + + // conns represents the set of all actively connected peers. + conns = make(map[uint64]*ConnReq, cm.cfg.TargetOutbound) + ) + out: for { select { case req := <-cm.requests: switch msg := req.(type) { + case registerPending: + connReq := msg.c + connReq.updateState(ConnPending) + pending[msg.c.id] = connReq + close(msg.done) + case handleConnected: connReq := msg.c + + if _, ok := pending[connReq.id]; !ok { + if msg.conn != nil { + msg.conn.Close() + } + log.Debugf("Ignoring connection for "+ + "canceled connreq=%v", connReq) + continue + } + connReq.updateState(ConnEstablished) connReq.conn = msg.conn conns[connReq.id] = connReq @@ -232,34 +267,83 @@ out: connReq.retryCount = 0 cm.failedAttempts = 0 + delete(pending, connReq.id) + if cm.cfg.OnConnection != nil { go cm.cfg.OnConnection(connReq, msg.conn) } case handleDisconnected: - if connReq, ok := conns[msg.id]; ok { + connReq, ok := conns[msg.id] + if !ok { + connReq, ok = pending[msg.id] + if !ok { + log.Errorf("Unknown connid=%d", + msg.id) + continue + } + + // Pending connection was found, remove + // it from pending map if we should + // ignore a later, successful + // connection. + connReq.updateState(ConnCanceled) + log.Debugf("Canceling: %v", connReq) + delete(pending, msg.id) + continue + + } + + // An existing connection was located, mark as + // disconnected and execute disconnection + // callback. + log.Debugf("Disconnected from %v", connReq) + delete(conns, msg.id) + + if connReq.conn != nil { + connReq.conn.Close() + } + + if cm.cfg.OnDisconnection != nil { + go cm.cfg.OnDisconnection(connReq) + } + + // All internal state has been cleaned up, if + // this connection is being removed, we will + // make no further attempts with this request. + if !msg.retry { connReq.updateState(ConnDisconnected) - if connReq.conn != nil { - connReq.conn.Close() - } - log.Debugf("Disconnected from %v", connReq) - delete(conns, msg.id) + continue + } - if cm.cfg.OnDisconnection != nil { - go cm.cfg.OnDisconnection(connReq) - } + // Otherwise, we will attempt a reconnection if + // we do not have enough peers, or if this is a + // persistent peer. The connection request is + // re added to the pending map, so that + // subsequent processing of connections and + // failures do not ignore the request. + if uint32(len(conns)) < cm.cfg.TargetOutbound || + connReq.Permanent { - if uint32(len(conns)) < cm.cfg.TargetOutbound && msg.retry { - cm.handleFailedConn(connReq) - } - } else { - log.Errorf("Unknown connection: %d", msg.id) + connReq.updateState(ConnPending) + log.Debugf("Reconnecting to %v", + connReq) + pending[msg.id] = connReq + cm.handleFailedConn(connReq) } case handleFailed: connReq := msg.c - connReq.updateState(ConnFailed) - log.Debugf("Failed to connect to %v: %v", connReq, msg.err) + + if _, ok := pending[connReq.id]; !ok { + log.Debugf("Ignoring connection for "+ + "canceled conn req: %v", connReq) + continue + } + + connReq.updateState(ConnFailing) + log.Debugf("Failed to connect to %v: %v", + connReq, msg.err) cm.handleFailedConn(connReq) } @@ -285,9 +369,31 @@ func (cm *ConnManager) NewConnReq() { c := &ConnReq{} atomic.StoreUint64(&c.id, atomic.AddUint64(&cm.connReqCount, 1)) + // Submit a request of a pending connection attempt to the connection + // manager. By registering the id before the connection is even + // established, we'll be able to later cancel the connection via the + // Remove method. + done := make(chan struct{}) + select { + case cm.requests <- registerPending{c, done}: + case <-cm.quit: + return + } + + // Wait for the registration to successfully add the pending conn req to + // the conn manager's internal state. + select { + case <-done: + case <-cm.quit: + return + } + addr, err := cm.cfg.GetNewAddress() if err != nil { - cm.requests <- handleFailed{c, err} + select { + case cm.requests <- handleFailed{c, err}: + case <-cm.quit: + } return } @@ -304,13 +410,41 @@ func (cm *ConnManager) Connect(c *ConnReq) { } if atomic.LoadUint64(&c.id) == 0 { atomic.StoreUint64(&c.id, atomic.AddUint64(&cm.connReqCount, 1)) + + // Submit a request of a pending connection attempt to the + // connection manager. By registering the id before the + // connection is even established, we'll be able to later + // cancel the connection via the Remove method. + done := make(chan struct{}) + select { + case cm.requests <- registerPending{c, done}: + case <-cm.quit: + return + } + + // Wait for the registration to successfully add the pending + // conn req to the conn manager's internal state. + select { + case <-done: + case <-cm.quit: + return + } } + log.Debugf("Attempting to connect to %v", c) + conn, err := cm.cfg.Dial(c.Addr) if err != nil { - cm.requests <- handleFailed{c, err} - } else { - cm.requests <- handleConnected{c, conn} + select { + case cm.requests <- handleFailed{c, err}: + case <-cm.quit: + } + return + } + + select { + case cm.requests <- handleConnected{c, conn}: + case <-cm.quit: } } @@ -321,16 +455,27 @@ func (cm *ConnManager) Disconnect(id uint64) { if atomic.LoadInt32(&cm.stop) != 0 { return } - cm.requests <- handleDisconnected{id, true} + + select { + case cm.requests <- handleDisconnected{id, true}: + case <-cm.quit: + } } -// Remove removes the connection corresponding to the given connection -// id from known connections. +// Remove removes the connection corresponding to the given connection id from +// known connections. +// +// NOTE: This method can also be used to cancel a lingering connection attempt +// that hasn't yet succeeded. func (cm *ConnManager) Remove(id uint64) { if atomic.LoadInt32(&cm.stop) != 0 { return } - cm.requests <- handleDisconnected{id, false} + + select { + case cm.requests <- handleDisconnected{id, false}: + case <-cm.quit: + } } // listenHandler accepts incoming connections on a given listener. It must be diff --git a/vendor/github.com/btcsuite/btcd/connmgr/connmanager_test.go b/vendor/github.com/btcsuite/btcd/connmgr/connmanager_test.go index 03b6dd2e..67769deb 100644 --- a/vendor/github.com/btcsuite/btcd/connmgr/connmanager_test.go +++ b/vendor/github.com/btcsuite/btcd/connmgr/connmanager_test.go @@ -6,6 +6,7 @@ package connmgr import ( "errors" + "fmt" "io" "net" "sync/atomic" @@ -266,7 +267,7 @@ func TestRetryPermanent(t *testing.T) { t.Fatalf("retry: %v - want ID %v, got ID %v", cr.Addr, wantID, gotID) } gotState = cr.State() - wantState = ConnDisconnected + wantState = ConnPending if gotState != wantState { t.Fatalf("retry: %v - want state %v, got state %v", cr.Addr, wantState, gotState) } @@ -421,6 +422,136 @@ func TestStopFailed(t *testing.T) { cmgr.Wait() } +// TestRemovePendingConnection tests that it's possible to cancel a pending +// connection, removing its internal state from the ConnMgr. +func TestRemovePendingConnection(t *testing.T) { + // Create a ConnMgr instance with an instance of a dialer that'll never + // succeed. + wait := make(chan struct{}) + indefiniteDialer := func(addr net.Addr) (net.Conn, error) { + <-wait + return nil, fmt.Errorf("error") + } + cmgr, err := New(&Config{ + Dial: indefiniteDialer, + }) + if err != nil { + t.Fatalf("New error: %v", err) + } + cmgr.Start() + + // Establish a connection request to a random IP we've chosen. + cr := &ConnReq{ + Addr: &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 18555, + }, + Permanent: true, + } + go cmgr.Connect(cr) + + time.Sleep(10 * time.Millisecond) + + if cr.State() != ConnPending { + t.Fatalf("pending request hasn't been registered, status: %v", + cr.State()) + } + + // The request launched above will actually never be able to establish + // a connection. So we'll cancel it _before_ it's able to be completed. + cmgr.Remove(cr.ID()) + + time.Sleep(10 * time.Millisecond) + + // Now examine the status of the connection request, it should read a + // status of failed. + if cr.State() != ConnCanceled { + t.Fatalf("request wasn't canceled, status is: %v", cr.State()) + } + + close(wait) + cmgr.Stop() +} + +// TestCancelIgnoreDelayedConnection tests that a canceled connection request will +// not execute the on connection callback, even if an outstanding retry +// succeeds. +func TestCancelIgnoreDelayedConnection(t *testing.T) { + retryTimeout := 10 * time.Millisecond + + // Setup a dialer that will continue to return an error until the + // connect chan is signaled, the dial attempt immediately after will + // succeed in returning a connection. + connect := make(chan struct{}) + failingDialer := func(addr net.Addr) (net.Conn, error) { + select { + case <-connect: + return mockDialer(addr) + default: + } + + return nil, fmt.Errorf("error") + } + + connected := make(chan *ConnReq) + cmgr, err := New(&Config{ + Dial: failingDialer, + RetryDuration: retryTimeout, + OnConnection: func(c *ConnReq, conn net.Conn) { + connected <- c + }, + }) + if err != nil { + t.Fatalf("New error: %v", err) + } + cmgr.Start() + defer cmgr.Stop() + + // Establish a connection request to a random IP we've chosen. + cr := &ConnReq{ + Addr: &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 18555, + }, + } + cmgr.Connect(cr) + + // Allow for the first retry timeout to elapse. + time.Sleep(2 * retryTimeout) + + // Connection be marked as failed, even after reattempting to + // connect. + if cr.State() != ConnFailing { + t.Fatalf("failing request should have status failed, status: %v", + cr.State()) + } + + // Remove the connection, and then immediately allow the next connection + // to succeed. + cmgr.Remove(cr.ID()) + close(connect) + + // Allow the connection manager to process the removal. + time.Sleep(5 * time.Millisecond) + + // Now examine the status of the connection request, it should read a + // status of canceled. + if cr.State() != ConnCanceled { + t.Fatalf("request wasn't canceled, status is: %v", cr.State()) + } + + // Finally, the connection manager should not signal the on-connection + // callback, since we explicitly canceled this request. We give a + // generous window to ensure the connection manager's lienar backoff is + // allowed to properly elapse. + select { + case <-connected: + t.Fatalf("on-connect should not be called for canceled req") + case <-time.After(5 * retryTimeout): + } + +} + // mockListener implements the net.Listener interface and is used to test // code that deals with net.Listeners without having to actually make any real // connections. diff --git a/vendor/github.com/btcsuite/btcd/database/README.md b/vendor/github.com/btcsuite/btcd/database/README.md index ea997223..c51c9cc6 100644 --- a/vendor/github.com/btcsuite/btcd/database/README.md +++ b/vendor/github.com/btcsuite/btcd/database/README.md @@ -13,7 +13,7 @@ one entity can have the database open at a time (for most database backends), and that entity will be btcd. When a client wants programmatic access to the data provided by btcd, they'll -likely want to use the [btcrpcclient](https://github.com/btcsuite/btcrpcclient) +likely want to use the [rpcclient](https://github.com/btcsuite/btcd/tree/master/rpcclient) package which makes use of the [JSON-RPC API](https://github.com/btcsuite/btcd/tree/master/docs/json_rpc_api.md). However, this package could be extremely useful for any applications requiring diff --git a/vendor/github.com/btcsuite/btcd/database/ffldb/README.md b/vendor/github.com/btcsuite/btcd/database/ffldb/README.md index 5609aa5e..ebaa5a7e 100644 --- a/vendor/github.com/btcsuite/btcd/database/ffldb/README.md +++ b/vendor/github.com/btcsuite/btcd/database/ffldb/README.md @@ -4,6 +4,7 @@ ffldb [![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)](https://travis-ci.org/btcsuite/btcd) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![GoDoc](https://godoc.org/github.com/btcsuite/btcd/database/ffldb?status.png)](http://godoc.org/github.com/btcsuite/btcd/database/ffldb) +======= Package ffldb implements a driver for the database package that uses leveldb for the backing metadata and flat files for block storage. diff --git a/vendor/github.com/btcsuite/btcd/database/ffldb/db.go b/vendor/github.com/btcsuite/btcd/database/ffldb/db.go index 599f2427..fd1ff895 100644 --- a/vendor/github.com/btcsuite/btcd/database/ffldb/db.go +++ b/vendor/github.com/btcsuite/btcd/database/ffldb/db.go @@ -1255,27 +1255,11 @@ func (tx *transaction) fetchBlockRow(hash *chainhash.Hash) ([]byte, error) { // // This function is part of the database.Tx interface implementation. func (tx *transaction) FetchBlockHeader(hash *chainhash.Hash) ([]byte, error) { - // Ensure transaction state is valid. - if err := tx.checkClosed(); err != nil { - return nil, err - } - - // When the block is pending to be written on commit return the bytes - // from there. - if idx, exists := tx.pendingBlocks[*hash]; exists { - blockBytes := tx.pendingBlockData[idx].bytes - return blockBytes[0:blockHdrSize:blockHdrSize], nil - } - - // Fetch the block index row and slice off the header. Notice the use - // of the cap on the subslice to prevent the caller from accidentally - // appending into the db data. - blockRow, err := tx.fetchBlockRow(hash) - if err != nil { - return nil, err - } - endOffset := blockLocSize + blockHdrSize - return blockRow[blockLocSize:endOffset:endOffset], nil + return tx.FetchBlockRegion(&database.BlockRegion{ + Hash: hash, + Offset: 0, + Len: blockHdrSize, + }) } // FetchBlockHeaders returns the raw serialized bytes for the block headers @@ -1294,41 +1278,13 @@ func (tx *transaction) FetchBlockHeader(hash *chainhash.Hash) ([]byte, error) { // // This function is part of the database.Tx interface implementation. func (tx *transaction) FetchBlockHeaders(hashes []chainhash.Hash) ([][]byte, error) { - // Ensure transaction state is valid. - if err := tx.checkClosed(); err != nil { - return nil, err - } - - // NOTE: This could check for the existence of all blocks before loading - // any of the headers which would be faster in the failure case, however - // callers will not typically be calling this function with invalid - // values, so optimize for the common case. - - // Load the headers. - headers := make([][]byte, len(hashes)) + regions := make([]database.BlockRegion, len(hashes)) for i := range hashes { - hash := &hashes[i] - - // When the block is pending to be written on commit return the - // bytes from there. - if idx, exists := tx.pendingBlocks[*hash]; exists { - blkBytes := tx.pendingBlockData[idx].bytes - headers[i] = blkBytes[0:blockHdrSize:blockHdrSize] - continue - } - - // Fetch the block index row and slice off the header. Notice - // the use of the cap on the subslice to prevent the caller - // from accidentally appending into the db data. - blockRow, err := tx.fetchBlockRow(hash) - if err != nil { - return nil, err - } - endOffset := blockLocSize + blockHdrSize - headers[i] = blockRow[blockLocSize:endOffset:endOffset] + regions[i].Hash = &hashes[i] + regions[i].Offset = 0 + regions[i].Len = blockHdrSize } - - return headers, nil + return tx.FetchBlockRegions(regions) } // FetchBlock returns the raw serialized bytes for the block identified by the @@ -1656,19 +1612,6 @@ func (tx *transaction) close() { } } -// serializeBlockRow serializes a block row into a format suitable for storage -// into the block index. -func serializeBlockRow(blockLoc blockLocation, blockHdr []byte) []byte { - // The serialized block index row format is: - // - // [0:blockLocSize] Block location - // [blockLocSize:blockLocSize+blockHdrSize] Block header - serializedRow := make([]byte, blockLocSize+blockHdrSize) - copy(serializedRow, serializeBlockLoc(blockLoc)) - copy(serializedRow[blockHdrOffset:], blockHdr) - return serializedRow -} - // writePendingAndCommit writes pending block data to the flat block files, // updates the metadata with their locations as well as the new current write // location, and commits the metadata to the memory database cache. It also @@ -1706,8 +1649,7 @@ func (tx *transaction) writePendingAndCommit() error { // includes the location information needed to locate the block // on the filesystem as well as the block header since they are // so commonly needed. - blockHdr := blockData.bytes[0:blockHdrSize] - blockRow := serializeBlockRow(location, blockHdr) + blockRow := serializeBlockLoc(location) err = tx.blockIdxBucket.Put(blockData.hash[:], blockRow) if err != nil { rollback() diff --git a/vendor/github.com/btcsuite/btcd/doc.go b/vendor/github.com/btcsuite/btcd/doc.go index 631568ff..ace26b0f 100644 --- a/vendor/github.com/btcsuite/btcd/doc.go +++ b/vendor/github.com/btcsuite/btcd/doc.go @@ -112,6 +112,7 @@ Application Options: --blockprioritysize= Size in bytes for high-priority/low-fee transactions when creating a block (50000) --nopeerbloomfilters Disable bloom filtering support. + --nocfilters Disable committed filtering (CF) support. --sigcachemaxsize= The maximum number of entries in the signature verification cache. --blocksonly Do not accept transactions from remote peers. diff --git a/vendor/github.com/btcsuite/btcd/docs/README.md b/vendor/github.com/btcsuite/btcd/docs/README.md index ee208dd0..c00d295e 100644 --- a/vendor/github.com/btcsuite/btcd/docs/README.md +++ b/vendor/github.com/btcsuite/btcd/docs/README.md @@ -268,9 +268,9 @@ information. * The btcsuite Bitcoin-related Go Packages: - * [btcrpcclient](https://github.com/btcsuite/btcrpcclient) - Implements a + * [btcrpcclient](https://github.com/btcsuite/btcd/tree/master/rpcclient) - Implements a robust and easy to use Websocket-enabled Bitcoin JSON-RPC client - * [btcjson](https://github.com/btcsuite/btcjson) - Provides an extensive API + * [btcjson](https://github.com/btcsuite/btcd/tree/master/btcjson) - Provides an extensive API for the underlying JSON-RPC command and return values * [wire](https://github.com/btcsuite/btcd/tree/master/wire) - Implements the Bitcoin wire protocol diff --git a/vendor/github.com/btcsuite/btcd/glide.lock b/vendor/github.com/btcsuite/btcd/glide.lock index f4480be1..7d4dca90 100644 --- a/vendor/github.com/btcsuite/btcd/glide.lock +++ b/vendor/github.com/btcsuite/btcd/glide.lock @@ -1,13 +1,18 @@ -hash: 976decfaf173d97d2e4572399490637aa12e217312a7d8b28813780a738e1151 -updated: 2017-08-24T17:28:45.8117156-05:00 +hash: 4d4efdd452d746ef15b66d35caadb3cbd58bb299e9c1f5172e90b2f3f272863f +updated: 2018-08-23T22:38:49.421147894-07:00 imports: +- name: github.com/aead/siphash + version: 83563a290f60225eb120d724600b9690c3fb536f - name: github.com/btcsuite/btclog version: 84c8d2346e9fc8c7b947e243b9c24e6df9fd206a - name: github.com/btcsuite/btcutil - version: 501929d3d046174c3d39f0ea54ece471aa17238c + version: ab6388e0c60ae4834a1f57511e20c17b5f78be4b subpackages: - base58 + - bech32 - bloom + - gcs + - gcs/builder - hdkeychain - name: github.com/btcsuite/go-socks version: 4720035b7bfd2a9bb130b1c184f8bbe41b6f0d0f @@ -41,7 +46,7 @@ imports: - svc - winapi - name: github.com/davecgh/go-spew - version: 346938d642f2ec3594ed81d874461961cd0faa76 + version: ecdeabc65495df2dec95d7c4a4c3e021903035e5 subpackages: - spew - name: github.com/jessevdk/go-flags @@ -50,8 +55,10 @@ imports: version: a93b200c26cbae3bb09dd0dc2c7c7fe1468a034a subpackages: - rotator +- name: github.com/kkdai/bstream + version: f391b8402d23024e7c0f624b31267a89998fca95 - name: golang.org/x/crypto - version: 122d919ec1efcfb58483215da23f815853e24b81 + version: 9419663f5a44be8b34ca85f08abc5fe1be11f8a3 subpackages: - ripemd160 testImports: [] diff --git a/vendor/github.com/btcsuite/btcd/glide.yaml b/vendor/github.com/btcsuite/btcd/glide.yaml index f42ad703..32c5ed61 100644 --- a/vendor/github.com/btcsuite/btcd/glide.yaml +++ b/vendor/github.com/btcsuite/btcd/glide.yaml @@ -2,6 +2,7 @@ package: github.com/btcsuite/btcd import: - package: github.com/btcsuite/btclog - package: github.com/btcsuite/btcutil + version: ab6388e0c60ae4834a1f57511e20c17b5f78be4b subpackages: - bloom - hdkeychain @@ -32,3 +33,5 @@ import: - package: github.com/jessevdk/go-flags version: 1679536dcc895411a9f5848d9a0250be7856448c - package: github.com/jrick/logrotate +- package: github.com/aead/siphash + version: 83563a290f60225eb120d724600b9690c3fb536f diff --git a/vendor/github.com/btcsuite/btcd/goclean.sh b/vendor/github.com/btcsuite/btcd/goclean.sh index bcbd5240..548baf8b 100755 --- a/vendor/github.com/btcsuite/btcd/goclean.sh +++ b/vendor/github.com/btcsuite/btcd/goclean.sh @@ -21,14 +21,14 @@ fi # Make sure gometalinter is installed and $GOPATH/bin is in your path. # $ go get -v github.com/alecthomas/gometalinter" # $ gometalinter --install" -if [ ! -x "$(type -p gometalinter)" ]; then +if [ ! -x "$(type -p gometalinter.v2)" ]; then exit 1 fi linter_targets=$(glide novendor) # Automatic checks -test -z "$(gometalinter -j 4 --disable-all \ +test -z "$(gometalinter.v2 -j 4 --disable-all \ --enable=gofmt \ --enable=golint \ --enable=vet \ diff --git a/vendor/github.com/btcsuite/btcd/integration/csv_fork_test.go b/vendor/github.com/btcsuite/btcd/integration/csv_fork_test.go index d7da7be7..345217c8 100644 --- a/vendor/github.com/btcsuite/btcd/integration/csv_fork_test.go +++ b/vendor/github.com/btcsuite/btcd/integration/csv_fork_test.go @@ -53,7 +53,7 @@ func makeTestOutput(r *rpctest.Harness, t *testing.T, output := &wire.TxOut{PkScript: selfAddrScript, Value: 1e8} // Next, create and broadcast a transaction paying to the output. - fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { return nil, nil, nil, err } @@ -88,7 +88,7 @@ func makeTestOutput(r *rpctest.Harness, t *testing.T, return key, utxo, selfAddrScript, nil } -// TestBIP0113Activation tests for proper adherance of the BIP 113 rule +// TestBIP0113Activation tests for proper adherence of the BIP 113 rule // constraint which requires all transaction finality tests to use the MTP of // the last 11 blocks, rather than the timestamp of the block which includes // them. @@ -188,7 +188,7 @@ func TestBIP0113Activation(t *testing.T) { // At this point, the block height should be 103: we mined 101 blocks // to create a single mature output, then an additional block to create // a new output, and then mined a single block above to include our - // transation. + // transaction. assertChainHeight(r, t, 103) // Next, mine enough blocks to ensure that the soft-fork becomes @@ -316,7 +316,7 @@ func createCSVOutput(r *rpctest.Harness, t *testing.T, // Finally create a valid transaction which creates the output crafted // above. - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { return nil, nil, nil, err } diff --git a/vendor/github.com/btcsuite/btcd/integration/rpctest/blockgen.go b/vendor/github.com/btcsuite/btcd/integration/rpctest/blockgen.go index bf092f61..de5821b0 100644 --- a/vendor/github.com/btcsuite/btcd/integration/rpctest/blockgen.go +++ b/vendor/github.com/btcsuite/btcd/integration/rpctest/blockgen.go @@ -45,12 +45,20 @@ func solveBlock(header *wire.BlockHeader, targetDifficulty *big.Int) bool { hdr.Nonce = i hash := hdr.BlockHash() if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 { - results <- sbResult{true, i} - return + select { + case results <- sbResult{true, i}: + return + case <-quit: + return + } } } } - results <- sbResult{false, 0} + select { + case results <- sbResult{false, 0}: + case <-quit: + return + } } startNonce := uint32(0) @@ -88,7 +96,8 @@ func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, e // createCoinbaseTx returns a coinbase transaction paying an appropriate // subsidy based on the passed block height to the provided address. func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int32, - addr btcutil.Address, net *chaincfg.Params) (*btcutil.Tx, error) { + addr btcutil.Address, mineTo []wire.TxOut, + net *chaincfg.Params) (*btcutil.Tx, error) { // Create the script to pay to the provided payment address. pkScript, err := txscript.PayToAddrScript(addr) @@ -105,10 +114,16 @@ func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int32, SignatureScript: coinbaseScript, Sequence: wire.MaxTxInSequenceNum, }) - tx.AddTxOut(&wire.TxOut{ - Value: blockchain.CalcBlockSubsidy(nextBlockHeight, net), - PkScript: pkScript, - }) + if len(mineTo) == 0 { + tx.AddTxOut(&wire.TxOut{ + Value: blockchain.CalcBlockSubsidy(nextBlockHeight, net), + PkScript: pkScript, + }) + } else { + for i := range mineTo { + tx.AddTxOut(&mineTo[i]) + } + } return btcutil.NewTx(tx), nil } @@ -118,8 +133,8 @@ func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int32, // second is used. Passing nil for the previous block results in a block that // builds off of the genesis block for the specified chain. func CreateBlock(prevBlock *btcutil.Block, inclusionTxs []*btcutil.Tx, - blockVersion int32, blockTime time.Time, - miningAddr btcutil.Address, net *chaincfg.Params) (*btcutil.Block, error) { + blockVersion int32, blockTime time.Time, miningAddr btcutil.Address, + mineTo []wire.TxOut, net *chaincfg.Params) (*btcutil.Block, error) { var ( prevHash *chainhash.Hash @@ -156,7 +171,7 @@ func CreateBlock(prevBlock *btcutil.Block, inclusionTxs []*btcutil.Tx, return nil, err } coinbaseTx, err := createCoinbaseTx(coinbaseScript, blockHeight, - miningAddr, net) + miningAddr, mineTo, net) if err != nil { return nil, err } diff --git a/vendor/github.com/btcsuite/btcd/integration/rpctest/memwallet.go b/vendor/github.com/btcsuite/btcd/integration/rpctest/memwallet.go index 9b2999f3..f1613075 100644 --- a/vendor/github.com/btcsuite/btcd/integration/rpctest/memwallet.go +++ b/vendor/github.com/btcsuite/btcd/integration/rpctest/memwallet.go @@ -56,6 +56,7 @@ func (u *utxo) isMature(height int32) bool { type chainUpdate struct { blockHeight int32 filteredTxns []*btcutil.Tx + isConnect bool // True if connect, false if disconnect } // undoEntry is functionally the opposite of a chainUpdate. An undoEntry is @@ -176,13 +177,14 @@ func (m *memWallet) SetRPCClient(rpcClient *rpcclient.Client) { } // IngestBlock is a call-back which is to be triggered each time a new block is -// connected to the main chain. Ingesting a block updates the wallet's internal -// utxo state based on the outputs created and destroyed within each block. +// connected to the main chain. It queues the update for the chain syncer, +// calling the private version in sequential order. func (m *memWallet) IngestBlock(height int32, header *wire.BlockHeader, filteredTxns []*btcutil.Tx) { // Append this new chain update to the end of the queue of new chain // updates. m.chainMtx.Lock() - m.chainUpdates = append(m.chainUpdates, &chainUpdate{height, filteredTxns}) + m.chainUpdates = append(m.chainUpdates, &chainUpdate{height, + filteredTxns, true}) m.chainMtx.Unlock() // Launch a goroutine to signal the chainSyncer that a new update is @@ -193,6 +195,30 @@ func (m *memWallet) IngestBlock(height int32, header *wire.BlockHeader, filtered }() } +// ingestBlock updates the wallet's internal utxo state based on the outputs +// created and destroyed within each block. +func (m *memWallet) ingestBlock(update *chainUpdate) { + // Update the latest synced height, then process each filtered + // transaction in the block creating and destroying utxos within + // the wallet as a result. + m.currentHeight = update.blockHeight + undo := &undoEntry{ + utxosDestroyed: make(map[wire.OutPoint]*utxo), + } + for _, tx := range update.filteredTxns { + mtx := tx.MsgTx() + isCoinbase := blockchain.IsCoinBaseTx(mtx) + txHash := mtx.TxHash() + m.evalOutputs(mtx.TxOut, &txHash, isCoinbase, undo) + m.evalInputs(mtx.TxIn, undo) + } + + // Finally, record the undo entry for this block so we can + // properly update our internal state in response to the block + // being re-org'd from the main chain. + m.reorgJournal[update.blockHeight] = undo +} + // chainSyncer is a goroutine dedicated to processing new blocks in order to // keep the wallet's utxo state up to date. // @@ -209,26 +235,12 @@ func (m *memWallet) chainSyncer() { m.chainUpdates = m.chainUpdates[1:] m.chainMtx.Unlock() - // Update the latest synced height, then process each filtered - // transaction in the block creating and destroying utxos within - // the wallet as a result. m.Lock() - m.currentHeight = update.blockHeight - undo := &undoEntry{ - utxosDestroyed: make(map[wire.OutPoint]*utxo), + if update.isConnect { + m.ingestBlock(update) + } else { + m.unwindBlock(update) } - for _, tx := range update.filteredTxns { - mtx := tx.MsgTx() - isCoinbase := blockchain.IsCoinBaseTx(mtx) - txHash := mtx.TxHash() - m.evalOutputs(mtx.TxOut, &txHash, isCoinbase, undo) - m.evalInputs(mtx.TxIn, undo) - } - - // Finally, record the undo entry for this block so we can - // properly update our internal state in response to the block - // being re-org'd from the main chain. - m.reorgJournal[update.blockHeight] = undo m.Unlock() } } @@ -285,13 +297,28 @@ func (m *memWallet) evalInputs(inputs []*wire.TxIn, undo *undoEntry) { } // UnwindBlock is a call-back which is to be executed each time a block is -// disconnected from the main chain. Unwinding a block undoes the effect that a -// particular block had on the wallet's internal utxo state. +// disconnected from the main chain. It queues the update for the chain syncer, +// calling the private version in sequential order. func (m *memWallet) UnwindBlock(height int32, header *wire.BlockHeader) { - m.Lock() - defer m.Unlock() + // Append this new chain update to the end of the queue of new chain + // updates. + m.chainMtx.Lock() + m.chainUpdates = append(m.chainUpdates, &chainUpdate{height, + nil, false}) + m.chainMtx.Unlock() - undo := m.reorgJournal[height] + // Launch a goroutine to signal the chainSyncer that a new update is + // available. We do this in a new goroutine in order to avoid blocking + // the main loop of the rpc client. + go func() { + m.chainUpdateSignal <- struct{}{} + }() +} + +// unwindBlock undoes the effect that a particular block had on the wallet's +// internal utxo state. +func (m *memWallet) unwindBlock(update *chainUpdate) { + undo := m.reorgJournal[update.blockHeight] for _, utxo := range undo.utxosCreated { delete(m.utxos, utxo) @@ -301,7 +328,7 @@ func (m *memWallet) UnwindBlock(height int32, header *wire.BlockHeader) { m.utxos[outPoint] = utxo } - delete(m.reorgJournal, height) + delete(m.reorgJournal, update.blockHeight) } // newAddress returns a new address from the wallet's hd key chain. It also @@ -347,12 +374,15 @@ func (m *memWallet) NewAddress() (btcutil.Address, error) { } // fundTx attempts to fund a transaction sending amt bitcoin. The coins are -// selected such that the final amount spent pays enough fees as dictated by -// the passed fee rate. The passed fee rate should be expressed in -// satoshis-per-byte. +// selected such that the final amount spent pays enough fees as dictated by the +// passed fee rate. The passed fee rate should be expressed in +// satoshis-per-byte. The transaction being funded can optionally include a +// change output indicated by the change boolean. // // NOTE: The memWallet's mutex must be held when this function is called. -func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.Amount) error { +func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, + feeRate btcutil.Amount, change bool) error { + const ( // spendSize is the largest number of bytes of a sigScript // which spends a p2pkh output: OP_DATA_73 OP_DATA_33 @@ -388,10 +418,11 @@ func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.A continue } - // If we have any change left over, then add an additional - // output to the transaction reserved for change. + // If we have any change left over and we should create a change + // output, then add an additional output to the transaction + // reserved for it. changeVal := amtSelected - amt - reqFee - if changeVal > 0 { + if changeVal > 0 && change { addr, err := m.newAddress() if err != nil { return err @@ -421,7 +452,21 @@ func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.A func (m *memWallet) SendOutputs(outputs []*wire.TxOut, feeRate btcutil.Amount) (*chainhash.Hash, error) { - tx, err := m.CreateTransaction(outputs, feeRate) + tx, err := m.CreateTransaction(outputs, feeRate, true) + if err != nil { + return nil, err + } + + return m.rpc.SendRawTransaction(tx, true) +} + +// SendOutputsWithoutChange creates and sends a transaction that pays to the +// specified outputs while observing the passed fee rate and ignoring a change +// output. The passed fee rate should be expressed in sat/b. +func (m *memWallet) SendOutputsWithoutChange(outputs []*wire.TxOut, + feeRate btcutil.Amount) (*chainhash.Hash, error) { + + tx, err := m.CreateTransaction(outputs, feeRate, false) if err != nil { return nil, err } @@ -431,10 +476,13 @@ func (m *memWallet) SendOutputs(outputs []*wire.TxOut, // CreateTransaction returns a fully signed transaction paying to the specified // outputs while observing the desired fee rate. The passed fee rate should be -// expressed in satoshis-per-byte. +// expressed in satoshis-per-byte. The transaction being created can optionally +// include a change output indicated by the change boolean. // // This function is safe for concurrent access. -func (m *memWallet) CreateTransaction(outputs []*wire.TxOut, feeRate btcutil.Amount) (*wire.MsgTx, error) { +func (m *memWallet) CreateTransaction(outputs []*wire.TxOut, + feeRate btcutil.Amount, change bool) (*wire.MsgTx, error) { + m.Lock() defer m.Unlock() @@ -449,7 +497,7 @@ func (m *memWallet) CreateTransaction(outputs []*wire.TxOut, feeRate btcutil.Amo } // Attempt to fund the transaction with spendable utxos. - if err := m.fundTx(tx, outputAmt, feeRate); err != nil { + if err := m.fundTx(tx, outputAmt, feeRate, change); err != nil { return nil, err } diff --git a/vendor/github.com/btcsuite/btcd/integration/rpctest/node.go b/vendor/github.com/btcsuite/btcd/integration/rpctest/node.go index 4d224130..6aec2b11 100644 --- a/vendor/github.com/btcsuite/btcd/integration/rpctest/node.go +++ b/vendor/github.com/btcsuite/btcd/integration/rpctest/node.go @@ -44,7 +44,7 @@ type nodeConfig struct { func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, error) { btcdPath, err := btcdExecutablePath() if err != nil { - return nil, err + btcdPath = "btcd" } a := &nodeConfig{ @@ -115,10 +115,6 @@ func (n *nodeConfig) arguments() []string { args = append(args, fmt.Sprintf("--rpccert=%s", n.certFile)) // --rpckey args = append(args, fmt.Sprintf("--rpckey=%s", n.keyFile)) - // --txindex - args = append(args, "--txindex") - // --addrindex - args = append(args, "--addrindex") if n.dataDir != "" { // --datadir args = append(args, fmt.Sprintf("--datadir=%s", n.dataDir)) diff --git a/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness.go b/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness.go index 653a3782..1c2612e4 100644 --- a/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness.go +++ b/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness.go @@ -356,20 +356,32 @@ func (h *Harness) SendOutputs(targetOutputs []*wire.TxOut, return h.wallet.SendOutputs(targetOutputs, feeRate) } +// SendOutputsWithoutChange creates and sends a transaction that pays to the +// specified outputs while observing the passed fee rate and ignoring a change +// output. The passed fee rate should be expressed in sat/b. +// +// This function is safe for concurrent access. +func (h *Harness) SendOutputsWithoutChange(targetOutputs []*wire.TxOut, + feeRate btcutil.Amount) (*chainhash.Hash, error) { + + return h.wallet.SendOutputsWithoutChange(targetOutputs, feeRate) +} + // CreateTransaction returns a fully signed transaction paying to the specified // outputs while observing the desired fee rate. The passed fee rate should be -// expressed in satoshis-per-byte. Any unspent outputs selected as inputs for -// the crafted transaction are marked as unspendable in order to avoid -// potential double-spends by future calls to this method. If the created -// transaction is cancelled for any reason then the selected inputs MUST be -// freed via a call to UnlockOutputs. Otherwise, the locked inputs won't be +// expressed in satoshis-per-byte. The transaction being created can optionally +// include a change output indicated by the change boolean. Any unspent outputs +// selected as inputs for the crafted transaction are marked as unspendable in +// order to avoid potential double-spends by future calls to this method. If the +// created transaction is cancelled for any reason then the selected inputs MUST +// be freed via a call to UnlockOutputs. Otherwise, the locked inputs won't be // returned to the pool of spendable outputs. // // This function is safe for concurrent access. func (h *Harness) CreateTransaction(targetOutputs []*wire.TxOut, - feeRate btcutil.Amount) (*wire.MsgTx, error) { + feeRate btcutil.Amount, change bool) (*wire.MsgTx, error) { - return h.wallet.CreateTransaction(targetOutputs, feeRate) + return h.wallet.CreateTransaction(targetOutputs, feeRate, change) } // UnlockOutputs unlocks any outputs which were previously marked as @@ -406,6 +418,27 @@ func (h *Harness) P2PAddress() string { // This function is safe for concurrent access. func (h *Harness) GenerateAndSubmitBlock(txns []*btcutil.Tx, blockVersion int32, blockTime time.Time) (*btcutil.Block, error) { + return h.GenerateAndSubmitBlockWithCustomCoinbaseOutputs(txns, + blockVersion, blockTime, []wire.TxOut{}) +} + +// GenerateAndSubmitBlockWithCustomCoinbaseOutputs creates a block whose +// contents include the passed coinbase outputs and transactions and submits +// it to the running simnet node. For generating blocks with only a coinbase tx, +// callers can simply pass nil instead of transactions to be mined. +// Additionally, a custom block version can be set by the caller. A blockVersion +// of -1 indicates that the current default block version should be used. An +// uninitialized time.Time should be used for the blockTime parameter if one +// doesn't wish to set a custom time. The mineTo list of outputs will be added +// to the coinbase; this is not checked for correctness until the block is +// submitted; thus, it is the caller's responsibility to ensure that the outputs +// are correct. If the list is empty, the coinbase reward goes to the wallet +// managed by the Harness. +// +// This function is safe for concurrent access. +func (h *Harness) GenerateAndSubmitBlockWithCustomCoinbaseOutputs( + txns []*btcutil.Tx, blockVersion int32, blockTime time.Time, + mineTo []wire.TxOut) (*btcutil.Block, error) { h.Lock() defer h.Unlock() @@ -427,7 +460,7 @@ func (h *Harness) GenerateAndSubmitBlock(txns []*btcutil.Tx, blockVersion int32, // Create a new block including the specified transactions newBlock, err := CreateBlock(prevBlock, txns, blockVersion, - blockTime, h.wallet.coinbaseAddr, h.ActiveNet) + blockTime, h.wallet.coinbaseAddr, mineTo, h.ActiveNet) if err != nil { return nil, err } diff --git a/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness_test.go b/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness_test.go index c3fc18b4..717f8f45 100644 --- a/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness_test.go +++ b/vendor/github.com/btcsuite/btcd/integration/rpctest/rpc_harness_test.go @@ -206,7 +206,7 @@ func testJoinMempools(r *Harness, t *testing.T) { t.Fatalf("unable to generate pkscript to addr: %v", err) } output := wire.NewTxOut(5e8, addrScript) - testTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + testTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("coinbase spend failed: %v", err) } @@ -340,7 +340,7 @@ func testGenerateAndSubmitBlock(r *Harness, t *testing.T) { const numTxns = 5 txns := make([]*btcutil.Tx, 0, numTxns) for i := 0; i < numTxns; i++ { - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("unable to create tx: %v", err) } @@ -391,6 +391,81 @@ func testGenerateAndSubmitBlock(r *Harness, t *testing.T) { } } +func testGenerateAndSubmitBlockWithCustomCoinbaseOutputs(r *Harness, + t *testing.T) { + // Generate a few test spend transactions. + addr, err := r.NewAddress() + if err != nil { + t.Fatalf("unable to generate new address: %v", err) + } + pkScript, err := txscript.PayToAddrScript(addr) + if err != nil { + t.Fatalf("unable to create script: %v", err) + } + output := wire.NewTxOut(btcutil.SatoshiPerBitcoin, pkScript) + + const numTxns = 5 + txns := make([]*btcutil.Tx, 0, numTxns) + for i := 0; i < numTxns; i++ { + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) + if err != nil { + t.Fatalf("unable to create tx: %v", err) + } + + txns = append(txns, btcutil.NewTx(tx)) + } + + // Now generate a block with the default block version, a zero'd out + // time, and a burn output. + block, err := r.GenerateAndSubmitBlockWithCustomCoinbaseOutputs(txns, + -1, time.Time{}, []wire.TxOut{{ + Value: 0, + PkScript: []byte{}, + }}) + if err != nil { + t.Fatalf("unable to generate block: %v", err) + } + + // Ensure that all created transactions were included, and that the + // block version was properly set to the default. + numBlocksTxns := len(block.Transactions()) + if numBlocksTxns != numTxns+1 { + t.Fatalf("block did not include all transactions: "+ + "expected %v, got %v", numTxns+1, numBlocksTxns) + } + blockVersion := block.MsgBlock().Header.Version + if blockVersion != BlockVersion { + t.Fatalf("block version is not default: expected %v, got %v", + BlockVersion, blockVersion) + } + + // Next generate a block with a "non-standard" block version along with + // time stamp a minute after the previous block's timestamp. + timestamp := block.MsgBlock().Header.Timestamp.Add(time.Minute) + targetBlockVersion := int32(1337) + block, err = r.GenerateAndSubmitBlockWithCustomCoinbaseOutputs(nil, + targetBlockVersion, timestamp, []wire.TxOut{{ + Value: 0, + PkScript: []byte{}, + }}) + if err != nil { + t.Fatalf("unable to generate block: %v", err) + } + + // Finally ensure that the desired block version and timestamp were set + // properly. + header := block.MsgBlock().Header + blockVersion = header.Version + if blockVersion != targetBlockVersion { + t.Fatalf("block version mismatch: expected %v, got %v", + targetBlockVersion, blockVersion) + } + if !timestamp.Equal(header.Timestamp) { + t.Fatalf("header time stamp mismatch: expected %v, got %v", + timestamp, header.Timestamp) + } +} + func testMemWalletReorg(r *Harness, t *testing.T) { // Create a fresh harness, we'll be using the main harness to force a // re-org on this local harness. @@ -447,7 +522,7 @@ func testMemWalletLockedOutputs(r *Harness, t *testing.T) { } outputAmt := btcutil.Amount(50 * btcutil.SatoshiPerBitcoin) output := wire.NewTxOut(int64(outputAmt), pkScript) - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("unable to create transaction: %v", err) } @@ -478,6 +553,7 @@ var harnessTestCases = []HarnessTestCase{ testJoinBlocks, testJoinMempools, // Depends on results of testJoinBlocks testGenerateAndSubmitBlock, + testGenerateAndSubmitBlockWithCustomCoinbaseOutputs, testMemWalletReorg, testMemWalletLockedOutputs, } diff --git a/vendor/github.com/btcsuite/btcd/log.go b/vendor/github.com/btcsuite/btcd/log.go index ae413a18..71accc7c 100644 --- a/vendor/github.com/btcsuite/btcd/log.go +++ b/vendor/github.com/btcsuite/btcd/log.go @@ -21,6 +21,7 @@ import ( "github.com/btcsuite/btcd/netsync" "github.com/btcsuite/btcd/peer" "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btclog" "github.com/jrick/logrotate/rotator" ) diff --git a/vendor/github.com/btcsuite/btcd/mempool/README.md b/vendor/github.com/btcsuite/btcd/mempool/README.md index 7ad0a68c..d9b8d73b 100644 --- a/vendor/github.com/btcsuite/btcd/mempool/README.md +++ b/vendor/github.com/btcsuite/btcd/mempool/README.md @@ -18,7 +18,7 @@ further filtered based upon a configurable policy. One of the policy configuration options controls whether or not "standard" transactions are accepted. In essence, a "standard" transaction is one that -satisfies a fairly strict set of requirements that are largley intended to help +satisfies a fairly strict set of requirements that are largely intended to help provide fair use of the system to all users. It is important to note that what is considered a "standard" transaction changes over time. For some insight, at the time of this writing, an example of _some_ of the criteria that are required diff --git a/vendor/github.com/btcsuite/btcd/mempool/doc.go b/vendor/github.com/btcsuite/btcd/mempool/doc.go index 9bd9f41f..3adad018 100644 --- a/vendor/github.com/btcsuite/btcd/mempool/doc.go +++ b/vendor/github.com/btcsuite/btcd/mempool/doc.go @@ -16,7 +16,7 @@ further filtered based upon a configurable policy. One of the policy configuration options controls whether or not "standard" transactions are accepted. In essence, a "standard" transaction is one that -satisfies a fairly strict set of requirements that are largley intended to help +satisfies a fairly strict set of requirements that are largely intended to help provide fair use of the system to all users. It is important to note that what is considered a "standard" transaction changes over time. For some insight, at the time of this writing, an example of SOME of the criteria that are required diff --git a/vendor/github.com/btcsuite/btcd/mempool/estimatefee.go b/vendor/github.com/btcsuite/btcd/mempool/estimatefee.go new file mode 100644 index 00000000..53933469 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/mempool/estimatefee.go @@ -0,0 +1,749 @@ +// Copyright (c) 2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package mempool + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "math/rand" + "sort" + "strings" + "sync" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/mining" + "github.com/btcsuite/btcutil" +) + +// TODO incorporate Alex Morcos' modifications to Gavin's initial model +// https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2014-October/006824.html + +const ( + // estimateFeeDepth is the maximum number of blocks before a transaction + // is confirmed that we want to track. + estimateFeeDepth = 25 + + // estimateFeeBinSize is the number of txs stored in each bin. + estimateFeeBinSize = 100 + + // estimateFeeMaxReplacements is the max number of replacements that + // can be made by the txs found in a given block. + estimateFeeMaxReplacements = 10 + + // DefaultEstimateFeeMaxRollback is the default number of rollbacks + // allowed by the fee estimator for orphaned blocks. + DefaultEstimateFeeMaxRollback = 2 + + // DefaultEstimateFeeMinRegisteredBlocks is the default minimum + // number of blocks which must be observed by the fee estimator before + // it will provide fee estimations. + DefaultEstimateFeeMinRegisteredBlocks = 3 + + bytePerKb = 1000 + + btcPerSatoshi = 1E-8 +) + +var ( + // EstimateFeeDatabaseKey is the key that we use to + // store the fee estimator in the database. + EstimateFeeDatabaseKey = []byte("estimatefee") +) + +// SatoshiPerByte is number with units of satoshis per byte. +type SatoshiPerByte float64 + +// BtcPerKilobyte is number with units of bitcoins per kilobyte. +type BtcPerKilobyte float64 + +// ToBtcPerKb returns a float value that represents the given +// SatoshiPerByte converted to satoshis per kb. +func (rate SatoshiPerByte) ToBtcPerKb() BtcPerKilobyte { + // If our rate is the error value, return that. + if rate == SatoshiPerByte(-1.0) { + return -1.0 + } + + return BtcPerKilobyte(float64(rate) * bytePerKb * btcPerSatoshi) +} + +// Fee returns the fee for a transaction of a given size for +// the given fee rate. +func (rate SatoshiPerByte) Fee(size uint32) btcutil.Amount { + // If our rate is the error value, return that. + if rate == SatoshiPerByte(-1) { + return btcutil.Amount(-1) + } + + return btcutil.Amount(float64(rate) * float64(size)) +} + +// NewSatoshiPerByte creates a SatoshiPerByte from an Amount and a +// size in bytes. +func NewSatoshiPerByte(fee btcutil.Amount, size uint32) SatoshiPerByte { + return SatoshiPerByte(float64(fee) / float64(size)) +} + +// observedTransaction represents an observed transaction and some +// additional data required for the fee estimation algorithm. +type observedTransaction struct { + // A transaction hash. + hash chainhash.Hash + + // The fee per byte of the transaction in satoshis. + feeRate SatoshiPerByte + + // The block height when it was observed. + observed int32 + + // The height of the block in which it was mined. + // If the transaction has not yet been mined, it is zero. + mined int32 +} + +func (o *observedTransaction) Serialize(w io.Writer) { + binary.Write(w, binary.BigEndian, o.hash) + binary.Write(w, binary.BigEndian, o.feeRate) + binary.Write(w, binary.BigEndian, o.observed) + binary.Write(w, binary.BigEndian, o.mined) +} + +func deserializeObservedTransaction(r io.Reader) (*observedTransaction, error) { + ot := observedTransaction{} + + // The first 32 bytes should be a hash. + binary.Read(r, binary.BigEndian, &ot.hash) + + // The next 8 are SatoshiPerByte + binary.Read(r, binary.BigEndian, &ot.feeRate) + + // And next there are two uint32's. + binary.Read(r, binary.BigEndian, &ot.observed) + binary.Read(r, binary.BigEndian, &ot.mined) + + return &ot, nil +} + +// registeredBlock has the hash of a block and the list of transactions +// it mined which had been previously observed by the FeeEstimator. It +// is used if Rollback is called to reverse the effect of registering +// a block. +type registeredBlock struct { + hash chainhash.Hash + transactions []*observedTransaction +} + +func (rb *registeredBlock) serialize(w io.Writer, txs map[*observedTransaction]uint32) { + binary.Write(w, binary.BigEndian, rb.hash) + + binary.Write(w, binary.BigEndian, uint32(len(rb.transactions))) + for _, o := range rb.transactions { + binary.Write(w, binary.BigEndian, txs[o]) + } +} + +// FeeEstimator manages the data necessary to create +// fee estimations. It is safe for concurrent access. +type FeeEstimator struct { + maxRollback uint32 + binSize int32 + + // The maximum number of replacements that can be made in a single + // bin per block. Default is estimateFeeMaxReplacements + maxReplacements int32 + + // The minimum number of blocks that can be registered with the fee + // estimator before it will provide answers. + minRegisteredBlocks uint32 + + // The last known height. + lastKnownHeight int32 + + // The number of blocks that have been registered. + numBlocksRegistered uint32 + + mtx sync.RWMutex + observed map[chainhash.Hash]*observedTransaction + bin [estimateFeeDepth][]*observedTransaction + + // The cached estimates. + cached []SatoshiPerByte + + // Transactions that have been removed from the bins. This allows us to + // revert in case of an orphaned block. + dropped []*registeredBlock +} + +// NewFeeEstimator creates a FeeEstimator for which at most maxRollback blocks +// can be unregistered and which returns an error unless minRegisteredBlocks +// have been registered with it. +func NewFeeEstimator(maxRollback, minRegisteredBlocks uint32) *FeeEstimator { + return &FeeEstimator{ + maxRollback: maxRollback, + minRegisteredBlocks: minRegisteredBlocks, + lastKnownHeight: mining.UnminedHeight, + binSize: estimateFeeBinSize, + maxReplacements: estimateFeeMaxReplacements, + observed: make(map[chainhash.Hash]*observedTransaction), + dropped: make([]*registeredBlock, 0, maxRollback), + } +} + +// ObserveTransaction is called when a new transaction is observed in the mempool. +func (ef *FeeEstimator) ObserveTransaction(t *TxDesc) { + ef.mtx.Lock() + defer ef.mtx.Unlock() + + // If we haven't seen a block yet we don't know when this one arrived, + // so we ignore it. + if ef.lastKnownHeight == mining.UnminedHeight { + return + } + + hash := *t.Tx.Hash() + if _, ok := ef.observed[hash]; !ok { + size := uint32(GetTxVirtualSize(t.Tx)) + + ef.observed[hash] = &observedTransaction{ + hash: hash, + feeRate: NewSatoshiPerByte(btcutil.Amount(t.Fee), size), + observed: t.Height, + mined: mining.UnminedHeight, + } + } +} + +// RegisterBlock informs the fee estimator of a new block to take into account. +func (ef *FeeEstimator) RegisterBlock(block *btcutil.Block) error { + ef.mtx.Lock() + defer ef.mtx.Unlock() + + // The previous sorted list is invalid, so delete it. + ef.cached = nil + + height := block.Height() + if height != ef.lastKnownHeight+1 && ef.lastKnownHeight != mining.UnminedHeight { + return fmt.Errorf("intermediate block not recorded; current height is %d; new height is %d", + ef.lastKnownHeight, height) + } + + // Update the last known height. + ef.lastKnownHeight = height + ef.numBlocksRegistered++ + + // Randomly order txs in block. + transactions := make(map[*btcutil.Tx]struct{}) + for _, t := range block.Transactions() { + transactions[t] = struct{}{} + } + + // Count the number of replacements we make per bin so that we don't + // replace too many. + var replacementCounts [estimateFeeDepth]int + + // Keep track of which txs were dropped in case of an orphan block. + dropped := ®isteredBlock{ + hash: *block.Hash(), + transactions: make([]*observedTransaction, 0, 100), + } + + // Go through the txs in the block. + for t := range transactions { + hash := *t.Hash() + + // Have we observed this tx in the mempool? + o, ok := ef.observed[hash] + if !ok { + continue + } + + // Put the observed tx in the oppropriate bin. + blocksToConfirm := height - o.observed - 1 + + // This shouldn't happen if the fee estimator works correctly, + // but return an error if it does. + if o.mined != mining.UnminedHeight { + log.Error("Estimate fee: transaction ", hash.String(), " has already been mined") + return errors.New("Transaction has already been mined") + } + + // This shouldn't happen but check just in case to avoid + // an out-of-bounds array index later. + if blocksToConfirm >= estimateFeeDepth { + continue + } + + // Make sure we do not replace too many transactions per min. + if replacementCounts[blocksToConfirm] == int(ef.maxReplacements) { + continue + } + + o.mined = height + + replacementCounts[blocksToConfirm]++ + + bin := ef.bin[blocksToConfirm] + + // Remove a random element and replace it with this new tx. + if len(bin) == int(ef.binSize) { + // Don't drop transactions we have just added from this same block. + l := int(ef.binSize) - replacementCounts[blocksToConfirm] + drop := rand.Intn(l) + dropped.transactions = append(dropped.transactions, bin[drop]) + + bin[drop] = bin[l-1] + bin[l-1] = o + } else { + bin = append(bin, o) + } + ef.bin[blocksToConfirm] = bin + } + + // Go through the mempool for txs that have been in too long. + for hash, o := range ef.observed { + if o.mined == mining.UnminedHeight && height-o.observed >= estimateFeeDepth { + delete(ef.observed, hash) + } + } + + // Add dropped list to history. + if ef.maxRollback == 0 { + return nil + } + + if uint32(len(ef.dropped)) == ef.maxRollback { + ef.dropped = append(ef.dropped[1:], dropped) + } else { + ef.dropped = append(ef.dropped, dropped) + } + + return nil +} + +// LastKnownHeight returns the height of the last block which was registered. +func (ef *FeeEstimator) LastKnownHeight() int32 { + ef.mtx.Lock() + defer ef.mtx.Unlock() + + return ef.lastKnownHeight +} + +// Rollback unregisters a recently registered block from the FeeEstimator. +// This can be used to reverse the effect of an orphaned block on the fee +// estimator. The maximum number of rollbacks allowed is given by +// maxRollbacks. +// +// Note: not everything can be rolled back because some transactions are +// deleted if they have been observed too long ago. That means the result +// of Rollback won't always be exactly the same as if the last block had not +// happened, but it should be close enough. +func (ef *FeeEstimator) Rollback(hash *chainhash.Hash) error { + ef.mtx.Lock() + defer ef.mtx.Unlock() + + // Find this block in the stack of recent registered blocks. + var n int + for n = 1; n <= len(ef.dropped); n++ { + if ef.dropped[len(ef.dropped)-n].hash.IsEqual(hash) { + break + } + } + + if n > len(ef.dropped) { + return errors.New("no such block was recently registered") + } + + for i := 0; i < n; i++ { + ef.rollback() + } + + return nil +} + +// rollback rolls back the effect of the last block in the stack +// of registered blocks. +func (ef *FeeEstimator) rollback() { + // The previous sorted list is invalid, so delete it. + ef.cached = nil + + // pop the last list of dropped txs from the stack. + last := len(ef.dropped) - 1 + if last == -1 { + // Cannot really happen because the exported calling function + // only rolls back a block already known to be in the list + // of dropped transactions. + return + } + + dropped := ef.dropped[last] + + // where we are in each bin as we replace txs? + var replacementCounters [estimateFeeDepth]int + + // Go through the txs in the dropped block. + for _, o := range dropped.transactions { + // Which bin was this tx in? + blocksToConfirm := o.mined - o.observed - 1 + + bin := ef.bin[blocksToConfirm] + + var counter = replacementCounters[blocksToConfirm] + + // Continue to go through that bin where we left off. + for { + if counter >= len(bin) { + // Panic, as we have entered an unrecoverable invalid state. + panic(errors.New("illegal state: cannot rollback dropped transaction")) + } + + prev := bin[counter] + + if prev.mined == ef.lastKnownHeight { + prev.mined = mining.UnminedHeight + + bin[counter] = o + + counter++ + break + } + + counter++ + } + + replacementCounters[blocksToConfirm] = counter + } + + // Continue going through bins to find other txs to remove + // which did not replace any other when they were entered. + for i, j := range replacementCounters { + for { + l := len(ef.bin[i]) + if j >= l { + break + } + + prev := ef.bin[i][j] + + if prev.mined == ef.lastKnownHeight { + prev.mined = mining.UnminedHeight + + newBin := append(ef.bin[i][0:j], ef.bin[i][j+1:l]...) + // TODO This line should prevent an unintentional memory + // leak but it causes a panic when it is uncommented. + // ef.bin[i][j] = nil + ef.bin[i] = newBin + + continue + } + + j++ + } + } + + ef.dropped = ef.dropped[0:last] + + // The number of blocks the fee estimator has seen is decrimented. + ef.numBlocksRegistered-- + ef.lastKnownHeight-- +} + +// estimateFeeSet is a set of txs that can that is sorted +// by the fee per kb rate. +type estimateFeeSet struct { + feeRate []SatoshiPerByte + bin [estimateFeeDepth]uint32 +} + +func (b *estimateFeeSet) Len() int { return len(b.feeRate) } + +func (b *estimateFeeSet) Less(i, j int) bool { + return b.feeRate[i] > b.feeRate[j] +} + +func (b *estimateFeeSet) Swap(i, j int) { + b.feeRate[i], b.feeRate[j] = b.feeRate[j], b.feeRate[i] +} + +// estimateFee returns the estimated fee for a transaction +// to confirm in confirmations blocks from now, given +// the data set we have collected. +func (b *estimateFeeSet) estimateFee(confirmations int) SatoshiPerByte { + if confirmations <= 0 { + return SatoshiPerByte(math.Inf(1)) + } + + if confirmations > estimateFeeDepth { + return 0 + } + + // We don't have any transactions! + if len(b.feeRate) == 0 { + return 0 + } + + var min, max int = 0, 0 + for i := 0; i < confirmations-1; i++ { + min += int(b.bin[i]) + } + + max = min + int(b.bin[confirmations-1]) - 1 + if max < min { + max = min + } + feeIndex := (min + max) / 2 + if feeIndex >= len(b.feeRate) { + feeIndex = len(b.feeRate) - 1 + } + + return b.feeRate[feeIndex] +} + +// newEstimateFeeSet creates a temporary data structure that +// can be used to find all fee estimates. +func (ef *FeeEstimator) newEstimateFeeSet() *estimateFeeSet { + set := &estimateFeeSet{} + + capacity := 0 + for i, b := range ef.bin { + l := len(b) + set.bin[i] = uint32(l) + capacity += l + } + + set.feeRate = make([]SatoshiPerByte, capacity) + + i := 0 + for _, b := range ef.bin { + for _, o := range b { + set.feeRate[i] = o.feeRate + i++ + } + } + + sort.Sort(set) + + return set +} + +// estimates returns the set of all fee estimates from 1 to estimateFeeDepth +// confirmations from now. +func (ef *FeeEstimator) estimates() []SatoshiPerByte { + set := ef.newEstimateFeeSet() + + estimates := make([]SatoshiPerByte, estimateFeeDepth) + for i := 0; i < estimateFeeDepth; i++ { + estimates[i] = set.estimateFee(i + 1) + } + + return estimates +} + +// EstimateFee estimates the fee per byte to have a tx confirmed a given +// number of blocks from now. +func (ef *FeeEstimator) EstimateFee(numBlocks uint32) (BtcPerKilobyte, error) { + ef.mtx.Lock() + defer ef.mtx.Unlock() + + // If the number of registered blocks is below the minimum, return + // an error. + if ef.numBlocksRegistered < ef.minRegisteredBlocks { + return -1, errors.New("not enough blocks have been observed") + } + + if numBlocks == 0 { + return -1, errors.New("cannot confirm transaction in zero blocks") + } + + if numBlocks > estimateFeeDepth { + return -1, fmt.Errorf( + "can only estimate fees for up to %d blocks from now", + estimateFeeBinSize) + } + + // If there are no cached results, generate them. + if ef.cached == nil { + ef.cached = ef.estimates() + } + + return ef.cached[int(numBlocks)-1].ToBtcPerKb(), nil +} + +// In case the format for the serialized version of the FeeEstimator changes, +// we use a version number. If the version number changes, it does not make +// sense to try to upgrade a previous version to a new version. Instead, just +// start fee estimation over. +const estimateFeeSaveVersion = 1 + +func deserializeRegisteredBlock(r io.Reader, txs map[uint32]*observedTransaction) (*registeredBlock, error) { + var lenTransactions uint32 + + rb := ®isteredBlock{} + binary.Read(r, binary.BigEndian, &rb.hash) + binary.Read(r, binary.BigEndian, &lenTransactions) + + rb.transactions = make([]*observedTransaction, lenTransactions) + + for i := uint32(0); i < lenTransactions; i++ { + var index uint32 + binary.Read(r, binary.BigEndian, &index) + rb.transactions[i] = txs[index] + } + + return rb, nil +} + +// FeeEstimatorState represents a saved FeeEstimator that can be +// restored with data from an earlier session of the program. +type FeeEstimatorState []byte + +// observedTxSet is a set of txs that can that is sorted +// by hash. It exists for serialization purposes so that +// a serialized state always comes out the same. +type observedTxSet []*observedTransaction + +func (q observedTxSet) Len() int { return len(q) } + +func (q observedTxSet) Less(i, j int) bool { + return strings.Compare(q[i].hash.String(), q[j].hash.String()) < 0 +} + +func (q observedTxSet) Swap(i, j int) { + q[i], q[j] = q[j], q[i] +} + +// Save records the current state of the FeeEstimator to a []byte that +// can be restored later. +func (ef *FeeEstimator) Save() FeeEstimatorState { + ef.mtx.Lock() + defer ef.mtx.Unlock() + + // TODO figure out what the capacity should be. + w := bytes.NewBuffer(make([]byte, 0)) + + binary.Write(w, binary.BigEndian, uint32(estimateFeeSaveVersion)) + + // Insert basic parameters. + binary.Write(w, binary.BigEndian, &ef.maxRollback) + binary.Write(w, binary.BigEndian, &ef.binSize) + binary.Write(w, binary.BigEndian, &ef.maxReplacements) + binary.Write(w, binary.BigEndian, &ef.minRegisteredBlocks) + binary.Write(w, binary.BigEndian, &ef.lastKnownHeight) + binary.Write(w, binary.BigEndian, &ef.numBlocksRegistered) + + // Put all the observed transactions in a sorted list. + var txCount uint32 + ots := make([]*observedTransaction, len(ef.observed)) + for hash := range ef.observed { + ots[txCount] = ef.observed[hash] + txCount++ + } + + sort.Sort(observedTxSet(ots)) + + txCount = 0 + observed := make(map[*observedTransaction]uint32) + binary.Write(w, binary.BigEndian, uint32(len(ef.observed))) + for _, ot := range ots { + ot.Serialize(w) + observed[ot] = txCount + txCount++ + } + + // Save all the right bins. + for _, list := range ef.bin { + + binary.Write(w, binary.BigEndian, uint32(len(list))) + + for _, o := range list { + binary.Write(w, binary.BigEndian, observed[o]) + } + } + + // Dropped transactions. + binary.Write(w, binary.BigEndian, uint32(len(ef.dropped))) + for _, registered := range ef.dropped { + registered.serialize(w, observed) + } + + // Commit the tx and return. + return FeeEstimatorState(w.Bytes()) +} + +// RestoreFeeEstimator takes a FeeEstimatorState that was previously +// returned by Save and restores it to a FeeEstimator +func RestoreFeeEstimator(data FeeEstimatorState) (*FeeEstimator, error) { + r := bytes.NewReader([]byte(data)) + + // Check version + var version uint32 + err := binary.Read(r, binary.BigEndian, &version) + if err != nil { + return nil, err + } + if version != estimateFeeSaveVersion { + return nil, fmt.Errorf("Incorrect version: expected %d found %d", estimateFeeSaveVersion, version) + } + + ef := &FeeEstimator{ + observed: make(map[chainhash.Hash]*observedTransaction), + } + + // Read basic parameters. + binary.Read(r, binary.BigEndian, &ef.maxRollback) + binary.Read(r, binary.BigEndian, &ef.binSize) + binary.Read(r, binary.BigEndian, &ef.maxReplacements) + binary.Read(r, binary.BigEndian, &ef.minRegisteredBlocks) + binary.Read(r, binary.BigEndian, &ef.lastKnownHeight) + binary.Read(r, binary.BigEndian, &ef.numBlocksRegistered) + + // Read transactions. + var numObserved uint32 + observed := make(map[uint32]*observedTransaction) + binary.Read(r, binary.BigEndian, &numObserved) + for i := uint32(0); i < numObserved; i++ { + ot, err := deserializeObservedTransaction(r) + if err != nil { + return nil, err + } + observed[i] = ot + ef.observed[ot.hash] = ot + } + + // Read bins. + for i := 0; i < estimateFeeDepth; i++ { + var numTransactions uint32 + binary.Read(r, binary.BigEndian, &numTransactions) + bin := make([]*observedTransaction, numTransactions) + for j := uint32(0); j < numTransactions; j++ { + var index uint32 + binary.Read(r, binary.BigEndian, &index) + + var exists bool + bin[j], exists = observed[index] + if !exists { + return nil, fmt.Errorf("Invalid transaction reference %d", index) + } + } + ef.bin[i] = bin + } + + // Read dropped transactions. + var numDropped uint32 + binary.Read(r, binary.BigEndian, &numDropped) + ef.dropped = make([]*registeredBlock, numDropped) + for i := uint32(0); i < numDropped; i++ { + var err error + ef.dropped[int(i)], err = deserializeRegisteredBlock(r, observed) + if err != nil { + return nil, err + } + } + + return ef, nil +} diff --git a/vendor/github.com/btcsuite/btcd/mempool/estimatefee_test.go b/vendor/github.com/btcsuite/btcd/mempool/estimatefee_test.go new file mode 100644 index 00000000..16dcfadc --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/mempool/estimatefee_test.go @@ -0,0 +1,424 @@ +// Copyright (c) 2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package mempool + +import ( + "bytes" + "math/rand" + "testing" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/mining" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" +) + +// newTestFeeEstimator creates a feeEstimator with some different parameters +// for testing purposes. +func newTestFeeEstimator(binSize, maxReplacements, maxRollback uint32) *FeeEstimator { + return &FeeEstimator{ + maxRollback: maxRollback, + lastKnownHeight: 0, + binSize: int32(binSize), + minRegisteredBlocks: 0, + maxReplacements: int32(maxReplacements), + observed: make(map[chainhash.Hash]*observedTransaction), + dropped: make([]*registeredBlock, 0, maxRollback), + } +} + +// lastBlock is a linked list of the block hashes which have been +// processed by the test FeeEstimator. +type lastBlock struct { + hash *chainhash.Hash + prev *lastBlock +} + +// estimateFeeTester interacts with the FeeEstimator to keep track +// of its expected state. +type estimateFeeTester struct { + ef *FeeEstimator + t *testing.T + version int32 + height int32 + last *lastBlock +} + +func (eft *estimateFeeTester) testTx(fee btcutil.Amount) *TxDesc { + eft.version++ + return &TxDesc{ + TxDesc: mining.TxDesc{ + Tx: btcutil.NewTx(&wire.MsgTx{ + Version: eft.version, + }), + Height: eft.height, + Fee: int64(fee), + }, + StartingPriority: 0, + } +} + +func expectedFeePerKilobyte(t *TxDesc) BtcPerKilobyte { + size := float64(t.TxDesc.Tx.MsgTx().SerializeSize()) + fee := float64(t.TxDesc.Fee) + + return SatoshiPerByte(fee / size).ToBtcPerKb() +} + +func (eft *estimateFeeTester) newBlock(txs []*wire.MsgTx) { + eft.height++ + + block := btcutil.NewBlock(&wire.MsgBlock{ + Transactions: txs, + }) + block.SetHeight(eft.height) + + eft.last = &lastBlock{block.Hash(), eft.last} + + eft.ef.RegisterBlock(block) +} + +func (eft *estimateFeeTester) rollback() { + if eft.last == nil { + return + } + + err := eft.ef.Rollback(eft.last.hash) + + if err != nil { + eft.t.Errorf("Could not rollback: %v", err) + } + + eft.height-- + eft.last = eft.last.prev +} + +// TestEstimateFee tests basic functionality in the FeeEstimator. +func TestEstimateFee(t *testing.T) { + ef := newTestFeeEstimator(5, 3, 1) + eft := estimateFeeTester{ef: ef, t: t} + + // Try with no txs and get zero for all queries. + expected := BtcPerKilobyte(0.0) + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f when estimator is empty; got %f", expected, estimated) + } + } + + // Now insert a tx. + tx := eft.testTx(1000000) + ef.ObserveTransaction(tx) + + // Expected should still be zero because this is still in the mempool. + expected = BtcPerKilobyte(0.0) + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f when estimator has one tx in mempool; got %f", expected, estimated) + } + } + + // Change minRegisteredBlocks to make sure that works. Error return + // value expected. + ef.minRegisteredBlocks = 1 + expected = BtcPerKilobyte(-1.0) + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f before any blocks have been registered; got %f", expected, estimated) + } + } + + // Record a block with the new tx. + eft.newBlock([]*wire.MsgTx{tx.Tx.MsgTx()}) + expected = expectedFeePerKilobyte(tx) + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f when one tx is binned; got %f", expected, estimated) + } + } + + // Roll back the last block; this was an orphan block. + ef.minRegisteredBlocks = 0 + eft.rollback() + expected = BtcPerKilobyte(0.0) + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f after rolling back block; got %f", expected, estimated) + } + } + + // Record an empty block and then a block with the new tx. + // This test was made because of a bug that only appeared when there + // were no transactions in the first bin. + eft.newBlock([]*wire.MsgTx{}) + eft.newBlock([]*wire.MsgTx{tx.Tx.MsgTx()}) + expected = expectedFeePerKilobyte(tx) + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f when one tx is binned; got %f", expected, estimated) + } + } + + // Create some more transactions. + txA := eft.testTx(500000) + txB := eft.testTx(2000000) + txC := eft.testTx(4000000) + ef.ObserveTransaction(txA) + ef.ObserveTransaction(txB) + ef.ObserveTransaction(txC) + + // Record 7 empty blocks. + for i := 0; i < 7; i++ { + eft.newBlock([]*wire.MsgTx{}) + } + + // Mine the first tx. + eft.newBlock([]*wire.MsgTx{txA.Tx.MsgTx()}) + + // Now the estimated amount should depend on the value + // of the argument to estimate fee. + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + if i > 2 { + expected = expectedFeePerKilobyte(txA) + } else { + expected = expectedFeePerKilobyte(tx) + } + if estimated != expected { + t.Errorf("Estimate fee error: expected %f on round %d; got %f", expected, i, estimated) + } + } + + // Record 5 more empty blocks. + for i := 0; i < 5; i++ { + eft.newBlock([]*wire.MsgTx{}) + } + + // Mine the next tx. + eft.newBlock([]*wire.MsgTx{txB.Tx.MsgTx()}) + + // Now the estimated amount should depend on the value + // of the argument to estimate fee. + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + if i <= 2 { + expected = expectedFeePerKilobyte(txB) + } else if i <= 8 { + expected = expectedFeePerKilobyte(tx) + } else { + expected = expectedFeePerKilobyte(txA) + } + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f on round %d; got %f", expected, i, estimated) + } + } + + // Record 9 more empty blocks. + for i := 0; i < 10; i++ { + eft.newBlock([]*wire.MsgTx{}) + } + + // Mine txC. + eft.newBlock([]*wire.MsgTx{txC.Tx.MsgTx()}) + + // This should have no effect on the outcome because too + // many blocks have been mined for txC to be recorded. + for i := uint32(1); i <= estimateFeeDepth; i++ { + estimated, _ := ef.EstimateFee(i) + if i <= 2 { + expected = expectedFeePerKilobyte(txC) + } else if i <= 8 { + expected = expectedFeePerKilobyte(txB) + } else if i <= 8+6 { + expected = expectedFeePerKilobyte(tx) + } else { + expected = expectedFeePerKilobyte(txA) + } + + if estimated != expected { + t.Errorf("Estimate fee error: expected %f on round %d; got %f", expected, i, estimated) + } + } +} + +func (eft *estimateFeeTester) estimates() [estimateFeeDepth]BtcPerKilobyte { + + // Generate estimates + var estimates [estimateFeeDepth]BtcPerKilobyte + for i := 0; i < estimateFeeDepth; i++ { + estimates[i], _ = eft.ef.EstimateFee(uint32(i + 1)) + } + + // Check that all estimated fee results go in descending order. + for i := 1; i < estimateFeeDepth; i++ { + if estimates[i] > estimates[i-1] { + eft.t.Error("Estimates not in descending order; got ", + estimates[i], " for estimate ", i, " and ", estimates[i-1], " for ", (i - 1)) + panic("invalid state.") + } + } + + return estimates +} + +func (eft *estimateFeeTester) round(txHistory [][]*TxDesc, + estimateHistory [][estimateFeeDepth]BtcPerKilobyte, + txPerRound, txPerBlock uint32) ([][]*TxDesc, [][estimateFeeDepth]BtcPerKilobyte) { + + // generate new txs. + var newTxs []*TxDesc + for i := uint32(0); i < txPerRound; i++ { + newTx := eft.testTx(btcutil.Amount(rand.Intn(1000000))) + eft.ef.ObserveTransaction(newTx) + newTxs = append(newTxs, newTx) + } + + // Generate mempool. + mempool := make(map[*observedTransaction]*TxDesc) + for _, h := range txHistory { + for _, t := range h { + if o, exists := eft.ef.observed[*t.Tx.Hash()]; exists && o.mined == mining.UnminedHeight { + mempool[o] = t + } + } + } + + // generate new block, with no duplicates. + i := uint32(0) + newBlockList := make([]*wire.MsgTx, 0, txPerBlock) + for _, t := range mempool { + newBlockList = append(newBlockList, t.TxDesc.Tx.MsgTx()) + i++ + + if i == txPerBlock { + break + } + } + + // Register a new block. + eft.newBlock(newBlockList) + + // return results. + estimates := eft.estimates() + + // Return results + return append(txHistory, newTxs), append(estimateHistory, estimates) +} + +// TestEstimateFeeRollback tests the rollback function, which undoes the +// effect of a adding a new block. +func TestEstimateFeeRollback(t *testing.T) { + txPerRound := uint32(7) + txPerBlock := uint32(5) + binSize := uint32(6) + maxReplacements := uint32(4) + stepsBack := 2 + rounds := 30 + + eft := estimateFeeTester{ef: newTestFeeEstimator(binSize, maxReplacements, uint32(stepsBack)), t: t} + var txHistory [][]*TxDesc + estimateHistory := [][estimateFeeDepth]BtcPerKilobyte{eft.estimates()} + + for round := 0; round < rounds; round++ { + // Go forward a few rounds. + for step := 0; step <= stepsBack; step++ { + txHistory, estimateHistory = + eft.round(txHistory, estimateHistory, txPerRound, txPerBlock) + } + + // Now go back. + for step := 0; step < stepsBack; step++ { + eft.rollback() + + // After rolling back, we should have the same estimated + // fees as before. + expected := estimateHistory[len(estimateHistory)-step-2] + estimates := eft.estimates() + + // Ensure that these are both the same. + for i := 0; i < estimateFeeDepth; i++ { + if expected[i] != estimates[i] { + t.Errorf("Rollback value mismatch. Expected %f, got %f. ", + expected[i], estimates[i]) + return + } + } + } + + // Erase history. + txHistory = txHistory[0 : len(txHistory)-stepsBack] + estimateHistory = estimateHistory[0 : len(estimateHistory)-stepsBack] + } +} + +func (eft *estimateFeeTester) checkSaveAndRestore( + previousEstimates [estimateFeeDepth]BtcPerKilobyte) { + + // Get the save state. + save := eft.ef.Save() + + // Save and restore database. + var err error + eft.ef, err = RestoreFeeEstimator(save) + if err != nil { + eft.t.Fatalf("Could not restore database: %s", err) + } + + // Save again and check that it matches the previous one. + redo := eft.ef.Save() + if !bytes.Equal(save, redo) { + eft.t.Fatalf("Restored states do not match: %v %v", save, redo) + } + + // Check that the results match. + newEstimates := eft.estimates() + + for i, prev := range previousEstimates { + if prev != newEstimates[i] { + eft.t.Error("Mismatch in estimate ", i, " after restore; got ", newEstimates[i], " but expected ", prev) + } + } +} + +// TestSave tests saving and restoring to a []byte. +func TestDatabase(t *testing.T) { + + txPerRound := uint32(7) + txPerBlock := uint32(5) + binSize := uint32(6) + maxReplacements := uint32(4) + rounds := 8 + + eft := estimateFeeTester{ef: newTestFeeEstimator(binSize, maxReplacements, uint32(rounds)+1), t: t} + var txHistory [][]*TxDesc + estimateHistory := [][estimateFeeDepth]BtcPerKilobyte{eft.estimates()} + + for round := 0; round < rounds; round++ { + eft.checkSaveAndRestore(estimateHistory[len(estimateHistory)-1]) + + // Go forward one step. + txHistory, estimateHistory = + eft.round(txHistory, estimateHistory, txPerRound, txPerBlock) + } + + // Reverse the process and try again. + for round := 1; round <= rounds; round++ { + eft.rollback() + eft.checkSaveAndRestore(estimateHistory[len(estimateHistory)-round-1]) + } +} diff --git a/vendor/github.com/btcsuite/btcd/mempool/mempool.go b/vendor/github.com/btcsuite/btcd/mempool/mempool.go index 31d294a6..7bb70445 100644 --- a/vendor/github.com/btcsuite/btcd/mempool/mempool.go +++ b/vendor/github.com/btcsuite/btcd/mempool/mempool.go @@ -89,6 +89,10 @@ type Config struct { // indexing the unconfirmed transactions in the memory pool. // This can be nil if the address index is not enabled. AddrIndex *indexers.AddrIndex + + // FeeEstimatator provides a feeEstimator. If it is not nil, the mempool + // records all new transactions it observes into the feeEstimator. + FeeEstimator *FeeEstimator } // Policy houses the policy (configuration parameters) which is used to @@ -523,12 +527,12 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil Added: time.Now(), Height: height, Fee: fee, - FeePerKB: fee * 1000 / int64(tx.MsgTx().SerializeSize()), + FeePerKB: fee * 1000 / GetTxVirtualSize(tx), }, StartingPriority: mining.CalcPriority(tx.MsgTx(), utxoView, height), } - mp.pool[*tx.Hash()] = txD + mp.pool[*tx.Hash()] = txD for _, txIn := range tx.MsgTx().TxIn { mp.outpoints[txIn.PreviousOutPoint] = tx } @@ -540,6 +544,11 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil mp.cfg.AddrIndex.AddUnconfirmedTx(tx, utxoView) } + // Record this tx for fee estimation if enabled. + if mp.cfg.FeeEstimator != nil { + mp.cfg.FeeEstimator.ObserveTransaction(txD) + } + return txD } @@ -562,6 +571,17 @@ func (mp *TxPool) checkPoolDoubleSpend(tx *btcutil.Tx) error { return nil } +// CheckSpend checks whether the passed outpoint is already spent by a +// transaction in the mempool. If that's the case the spending transaction will +// be returned, if not nil will be returned. +func (mp *TxPool) CheckSpend(op wire.OutPoint) *btcutil.Tx { + mp.mtx.RLock() + txR := mp.outpoints[op] + mp.mtx.RUnlock() + + return txR +} + // fetchInputUtxos loads utxo details about the input transactions referenced by // the passed transaction. First, it loads the details form the viewpoint of // the main chain, then it adjusts them based upon the contents of the @@ -575,15 +595,21 @@ func (mp *TxPool) fetchInputUtxos(tx *btcutil.Tx) (*blockchain.UtxoViewpoint, er } // Attempt to populate any missing inputs from the transaction pool. - for originHash, entry := range utxoView.Entries() { - if entry != nil && !entry.IsFullySpent() { + for _, txIn := range tx.MsgTx().TxIn { + prevOut := &txIn.PreviousOutPoint + entry := utxoView.LookupEntry(*prevOut) + if entry != nil && !entry.IsSpent() { continue } - if poolTxDesc, exists := mp.pool[originHash]; exists { - utxoView.AddTxOuts(poolTxDesc.Tx, mining.UnminedHeight) + if poolTxDesc, exists := mp.pool[prevOut.Hash]; exists { + // AddTxOut ignores out of range index values, so it is + // safe to call without bounds checking here. + utxoView.AddTxOut(poolTxDesc.Tx, prevOut.Index, + mining.UnminedHeight) } } + return utxoView, nil } @@ -713,25 +739,29 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec // Don't allow the transaction if it exists in the main chain and is not // not already fully spent. - txEntry := utxoView.LookupEntry(txHash) - if txEntry != nil && !txEntry.IsFullySpent() { - return nil, nil, txRuleError(wire.RejectDuplicate, - "transaction already exists") + prevOut := wire.OutPoint{Hash: *txHash} + for txOutIdx := range tx.MsgTx().TxOut { + prevOut.Index = uint32(txOutIdx) + entry := utxoView.LookupEntry(prevOut) + if entry != nil && !entry.IsSpent() { + return nil, nil, txRuleError(wire.RejectDuplicate, + "transaction already exists") + } + utxoView.RemoveEntry(prevOut) } - delete(utxoView.Entries(), *txHash) - // Transaction is an orphan if any of the referenced input transactions - // don't exist. Adding orphans to the orphan pool is not handled by - // this function, and the caller should use maybeAddOrphan if this - // behavior is desired. + // Transaction is an orphan if any of the referenced transaction outputs + // don't exist or are already spent. Adding orphans to the orphan pool + // is not handled by this function, and the caller should use + // maybeAddOrphan if this behavior is desired. var missingParents []*chainhash.Hash - for originHash, entry := range utxoView.Entries() { - if entry == nil || entry.IsFullySpent() { + for outpoint, entry := range utxoView.Entries() { + if entry == nil || entry.IsSpent() { // Must make a copy of the hash here since the iterator // is replaced and taking its address directly would // result in all of the entries pointing to the same // memory location and thus all be the final hash. - hashCopy := originHash + hashCopy := outpoint.Hash missingParents = append(missingParents, &hashCopy) } } diff --git a/vendor/github.com/btcsuite/btcd/mempool/mempool_test.go b/vendor/github.com/btcsuite/btcd/mempool/mempool_test.go index c557d61f..7a29598b 100644 --- a/vendor/github.com/btcsuite/btcd/mempool/mempool_test.go +++ b/vendor/github.com/btcsuite/btcd/mempool/mempool_test.go @@ -23,7 +23,7 @@ import ( // fakeChain is used by the pool harness to provide generated test utxos and // a current faked chain height to the pool callbacks. This, in turn, allows -// transations to be appear as though they are spending completely valid utxos. +// transactions to appear as though they are spending completely valid utxos. type fakeChain struct { sync.RWMutex utxos *blockchain.UtxoViewpoint @@ -31,10 +31,10 @@ type fakeChain struct { medianTimePast time.Time } -// FetchUtxoView loads utxo details about the input transactions referenced by -// the passed transaction from the point of view of the fake chain. -// It also attempts to fetch the utxo details for the transaction itself so the -// returned view can be examined for duplicate unspent transaction outputs. +// FetchUtxoView loads utxo details about the inputs referenced by the passed +// transaction from the point of view of the fake chain. It also attempts to +// fetch the utxos for the outputs of the transaction itself so the returned +// view can be examined for duplicate transactions. // // This function is safe for concurrent access however the returned view is NOT. func (s *fakeChain) FetchUtxoView(tx *btcutil.Tx) (*blockchain.UtxoViewpoint, error) { @@ -46,14 +46,17 @@ func (s *fakeChain) FetchUtxoView(tx *btcutil.Tx) (*blockchain.UtxoViewpoint, er // Add an entry for the tx itself to the new view. viewpoint := blockchain.NewUtxoViewpoint() - entry := s.utxos.LookupEntry(tx.Hash()) - viewpoint.Entries()[*tx.Hash()] = entry.Clone() + prevOut := wire.OutPoint{Hash: *tx.Hash()} + for txOutIdx := range tx.MsgTx().TxOut { + prevOut.Index = uint32(txOutIdx) + entry := s.utxos.LookupEntry(prevOut) + viewpoint.Entries()[prevOut] = entry.Clone() + } // Add entries for all of the inputs to the tx to the new view. for _, txIn := range tx.MsgTx().TxIn { - originHash := &txIn.PreviousOutPoint.Hash - entry := s.utxos.LookupEntry(originHash) - viewpoint.Entries()[*originHash] = entry.Clone() + entry := s.utxos.LookupEntry(txIn.PreviousOutPoint) + viewpoint.Entries()[txIn.PreviousOutPoint] = entry.Clone() } return viewpoint, nil @@ -794,3 +797,72 @@ func TestMultiInputOrphanDoubleSpend(t *testing.T) { // was not moved to the transaction pool. testPoolMembership(tc, doubleSpendTx, false, false) } + +// TestCheckSpend tests that CheckSpend returns the expected spends found in +// the mempool. +func TestCheckSpend(t *testing.T) { + t.Parallel() + + harness, outputs, err := newPoolHarness(&chaincfg.MainNetParams) + if err != nil { + t.Fatalf("unable to create test pool: %v", err) + } + + // The mempool is empty, so none of the spendable outputs should have a + // spend there. + for _, op := range outputs { + spend := harness.txPool.CheckSpend(op.outPoint) + if spend != nil { + t.Fatalf("Unexpeced spend found in pool: %v", spend) + } + } + + // Create a chain of transactions rooted with the first spendable + // output provided by the harness. + const txChainLength = 5 + chainedTxns, err := harness.CreateTxChain(outputs[0], txChainLength) + if err != nil { + t.Fatalf("unable to create transaction chain: %v", err) + } + for _, tx := range chainedTxns { + _, err := harness.txPool.ProcessTransaction(tx, true, + false, 0) + if err != nil { + t.Fatalf("ProcessTransaction: failed to accept "+ + "tx: %v", err) + } + } + + // The first tx in the chain should be the spend of the spendable + // output. + op := outputs[0].outPoint + spend := harness.txPool.CheckSpend(op) + if spend != chainedTxns[0] { + t.Fatalf("expected %v to be spent by %v, instead "+ + "got %v", op, chainedTxns[0], spend) + } + + // Now all but the last tx should be spent by the next. + for i := 0; i < len(chainedTxns)-1; i++ { + op = wire.OutPoint{ + Hash: *chainedTxns[i].Hash(), + Index: 0, + } + expSpend := chainedTxns[i+1] + spend = harness.txPool.CheckSpend(op) + if spend != expSpend { + t.Fatalf("expected %v to be spent by %v, instead "+ + "got %v", op, expSpend, spend) + } + } + + // The last tx should have no spend. + op = wire.OutPoint{ + Hash: *chainedTxns[txChainLength-1].Hash(), + Index: 0, + } + spend = harness.txPool.CheckSpend(op) + if spend != nil { + t.Fatalf("Unexpeced spend found in pool: %v", spend) + } +} diff --git a/vendor/github.com/btcsuite/btcd/mempool/policy.go b/vendor/github.com/btcsuite/btcd/mempool/policy.go index 89cd7a50..f4e3b51e 100644 --- a/vendor/github.com/btcsuite/btcd/mempool/policy.go +++ b/vendor/github.com/btcsuite/btcd/mempool/policy.go @@ -98,9 +98,8 @@ func checkInputsStandard(tx *btcutil.Tx, utxoView *blockchain.UtxoViewpoint) err // It is safe to elide existence and index checks here since // they have already been checked prior to calling this // function. - prevOut := txIn.PreviousOutPoint - entry := utxoView.LookupEntry(&prevOut.Hash) - originPkScript := entry.PkScriptByIndex(prevOut.Index) + entry := utxoView.LookupEntry(txIn.PreviousOutPoint) + originPkScript := entry.PkScript() switch txscript.GetScriptClass(originPkScript) { case txscript.ScriptHashTy: numSigOps := txscript.GetPreciseSigOpCount( diff --git a/vendor/github.com/btcsuite/btcd/mining/cpuminer/README.md b/vendor/github.com/btcsuite/btcd/mining/cpuminer/README.md index 899a5aed..205b8f03 100644 --- a/vendor/github.com/btcsuite/btcd/mining/cpuminer/README.md +++ b/vendor/github.com/btcsuite/btcd/mining/cpuminer/README.md @@ -4,6 +4,7 @@ cpuminer [![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/mining/cpuminer) +======= ## Overview diff --git a/vendor/github.com/btcsuite/btcd/mining/mining.go b/vendor/github.com/btcsuite/btcd/mining/mining.go index 09aa391f..44ec7dc7 100644 --- a/vendor/github.com/btcsuite/btcd/mining/mining.go +++ b/vendor/github.com/btcsuite/btcd/mining/mining.go @@ -219,17 +219,17 @@ type BlockTemplate struct { WitnessCommitment []byte } -// mergeUtxoView adds all of the entries in view to viewA. The result is that +// mergeUtxoView adds all of the entries in viewB to viewA. The result is that // viewA will contain all of its original entries plus all of the entries // in viewB. It will replace any entries in viewB which also exist in viewA -// if the entry in viewA is fully spent. +// if the entry in viewA is spent. func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) { viewAEntries := viewA.Entries() - for hash, entryB := range viewB.Entries() { - if entryA, exists := viewAEntries[hash]; !exists || - entryA == nil || entryA.IsFullySpent() { + for outpoint, entryB := range viewB.Entries() { + if entryA, exists := viewAEntries[outpoint]; !exists || + entryA == nil || entryA.IsSpent() { - viewAEntries[hash] = entryB + viewAEntries[outpoint] = entryB } } } @@ -291,11 +291,9 @@ func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockH // which are not provably unspendable as available unspent transaction outputs. func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32) error { for _, txIn := range tx.MsgTx().TxIn { - originHash := &txIn.PreviousOutPoint.Hash - originIndex := txIn.PreviousOutPoint.Index - entry := utxoView.LookupEntry(originHash) + entry := utxoView.LookupEntry(txIn.PreviousOutPoint) if entry != nil { - entry.SpendOutput(originIndex) + entry.Spend() } } @@ -540,9 +538,8 @@ mempoolLoop: prioItem := &txPrioItem{tx: tx} for _, txIn := range tx.MsgTx().TxIn { originHash := &txIn.PreviousOutPoint.Hash - originIndex := txIn.PreviousOutPoint.Index - utxoEntry := utxos.LookupEntry(originHash) - if utxoEntry == nil || utxoEntry.IsOutputSpent(originIndex) { + entry := utxos.LookupEntry(txIn.PreviousOutPoint) + if entry == nil || entry.IsSpent() { if !g.txSource.HaveTransaction(originHash) { log.Tracef("Skipping tx %s because it "+ "references unspent output %s "+ @@ -828,7 +825,7 @@ mempoolLoop: // witness preimage generated above. With the commitment // generated, the witness script for the output is: OP_RETURN // OP_DATA_36 {0xaa21a9ed || witnessCommitment}. The leading - // prefix is refered to as the "witness magic bytes". + // prefix is referred to as the "witness magic bytes". witnessCommitment = chainhash.DoubleHashB(witnessPreimage[:]) witnessScript := append(blockchain.WitnessMagicBytes, witnessCommitment...) diff --git a/vendor/github.com/btcsuite/btcd/mining/policy.go b/vendor/github.com/btcsuite/btcd/mining/policy.go index 54b5305f..c3f059c5 100644 --- a/vendor/github.com/btcsuite/btcd/mining/policy.go +++ b/vendor/github.com/btcsuite/btcd/mining/policy.go @@ -67,16 +67,14 @@ func calcInputValueAge(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextB for _, txIn := range tx.TxIn { // Don't attempt to accumulate the total input age if the // referenced transaction output doesn't exist. - originHash := &txIn.PreviousOutPoint.Hash - originIndex := txIn.PreviousOutPoint.Index - txEntry := utxoView.LookupEntry(originHash) - if txEntry != nil && !txEntry.IsOutputSpent(originIndex) { + entry := utxoView.LookupEntry(txIn.PreviousOutPoint) + if entry != nil && !entry.IsSpent() { // Inputs with dependencies currently in the mempool // have their block height set to a special constant. // Their input age should computed as zero since their // parent hasn't made it into a block yet. var inputAge int32 - originHeight := txEntry.BlockHeight() + originHeight := entry.BlockHeight() if originHeight == UnminedHeight { inputAge = 0 } else { @@ -84,7 +82,7 @@ func calcInputValueAge(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextB } // Sum the input value times age. - inputValue := txEntry.AmountByIndex(originIndex) + inputValue := entry.Amount() totalInputAge += float64(inputValue * int64(inputAge)) } } diff --git a/vendor/github.com/btcsuite/btcd/netsync/interface.go b/vendor/github.com/btcsuite/btcd/netsync/interface.go index 61a230ac..3e6ca1c1 100644 --- a/vendor/github.com/btcsuite/btcd/netsync/interface.go +++ b/vendor/github.com/btcsuite/btcd/netsync/interface.go @@ -36,4 +36,6 @@ type Config struct { DisableCheckpoints bool MaxPeers int + + FeeEstimator *mempool.FeeEstimator } diff --git a/vendor/github.com/btcsuite/btcd/netsync/manager.go b/vendor/github.com/btcsuite/btcd/netsync/manager.go index 7f1d3605..d75dd961 100644 --- a/vendor/github.com/btcsuite/btcd/netsync/manager.go +++ b/vendor/github.com/btcsuite/btcd/netsync/manager.go @@ -167,6 +167,9 @@ type SyncManager struct { headerList *list.List startHeader *list.Element nextCheckpoint *chaincfg.Checkpoint + + // An optional fee estimator. + feeEstimator *mempool.FeeEstimator } // resetHeaderState sets the headers-first mode state to values appropriate for @@ -895,12 +898,26 @@ func (sm *SyncManager) haveInventory(invVect *wire.InvVect) (bool, error) { } // Check if the transaction exists from the point of view of the - // end of the main chain. - entry, err := sm.chain.FetchUtxoEntry(&invVect.Hash) - if err != nil { - return false, err + // end of the main chain. Note that this is only a best effort + // since it is expensive to check existence of every output and + // the only purpose of this check is to avoid downloading + // already known transactions. Only the first two outputs are + // checked because the vast majority of transactions consist of + // two outputs where one is some form of "pay-to-somebody-else" + // and the other is a change output. + prevOut := wire.OutPoint{Hash: invVect.Hash} + for i := uint32(0); i < 2; i++ { + prevOut.Index = i + entry, err := sm.chain.FetchUtxoEntry(prevOut) + if err != nil { + return false, err + } + if entry != nil && !entry.IsSpent() { + return true, nil + } } - return entry != nil && !entry.IsFullySpent(), nil + + return false, nil } // The requested inventory is is an unsupported type, so just claim @@ -1249,6 +1266,20 @@ func (sm *SyncManager) handleBlockchainNotification(notification *blockchain.Not sm.peerNotifier.AnnounceNewTransactions(acceptedTxs) } + // Register block with the fee estimator, if it exists. + if sm.feeEstimator != nil { + err := sm.feeEstimator.RegisterBlock(block) + + // If an error is somehow generated then the fee estimator + // has entered an invalid state. Since it doesn't know how + // to recover, create a new one. + if err != nil { + sm.feeEstimator = mempool.NewFeeEstimator( + mempool.DefaultEstimateFeeMaxRollback, + mempool.DefaultEstimateFeeMinRegisteredBlocks) + } + } + // A block has been disconnected from the main block chain. case blockchain.NTBlockDisconnected: block, ok := notification.Data.(*btcutil.Block) @@ -1269,6 +1300,11 @@ func (sm *SyncManager) handleBlockchainNotification(notification *blockchain.Not sm.txMemPool.RemoveTransaction(tx, true) } } + + // Rollback previous block recorded by the fee estimator. + if sm.feeEstimator != nil { + sm.feeEstimator.Rollback(block.Hash()) + } } } @@ -1417,6 +1453,7 @@ func New(config *Config) (*SyncManager, error) { msgChan: make(chan interface{}, config.MaxPeers*3), headerList: list.New(), quit: make(chan struct{}), + feeEstimator: config.FeeEstimator, } best := sm.chain.BestSnapshot() diff --git a/vendor/github.com/btcsuite/btcd/peer/example_test.go b/vendor/github.com/btcsuite/btcd/peer/example_test.go index e4429f85..a549fe21 100644 --- a/vendor/github.com/btcsuite/btcd/peer/example_test.go +++ b/vendor/github.com/btcsuite/btcd/peer/example_test.go @@ -23,6 +23,7 @@ func mockRemotePeer() error { UserAgentName: "peer", // User agent name to advertise. UserAgentVersion: "1.0.0", // User agent version to advertise. ChainParams: &chaincfg.SimNetParams, + TrickleInterval: time.Second * 10, } // Accept connections on the simnet port. @@ -69,6 +70,7 @@ func Example_newOutboundPeer() { UserAgentVersion: "1.0.0", // User agent version to advertise. ChainParams: &chaincfg.SimNetParams, Services: 0, + TrickleInterval: time.Second * 10, Listeners: peer.MessageListeners{ OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) { fmt.Println("outbound: received version") diff --git a/vendor/github.com/btcsuite/btcd/peer/peer.go b/vendor/github.com/btcsuite/btcd/peer/peer.go index 4075c435..4fa77cf7 100644 --- a/vendor/github.com/btcsuite/btcd/peer/peer.go +++ b/vendor/github.com/btcsuite/btcd/peer/peer.go @@ -1,4 +1,5 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2018 The btcsuite developers +// Copyright (c) 2016-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -29,6 +30,10 @@ const ( // MaxProtocolVersion is the max protocol version the peer supports. MaxProtocolVersion = wire.FeeFilterVersion + // DefaultTrickleInterval is the min time between attempts to send an + // inv message to a peer. + DefaultTrickleInterval = 10 * time.Second + // minAcceptableProtocolVersion is the lowest protocol version that a // connected peer may support. minAcceptableProtocolVersion = wire.MultipleAddressVersion @@ -64,10 +69,6 @@ const ( // stalling. The deadlines are adjusted for callback running times and // only checked on each stall tick interval. stallResponseTimeout = 30 * time.Second - - // trickleTimeout is the duration of the ticker which trickles down the - // inventory to a peer. - trickleTimeout = 10 * time.Second ) var ( @@ -123,6 +124,17 @@ type MessageListeners struct { // OnBlock is invoked when a peer receives a block bitcoin message. OnBlock func(p *Peer, msg *wire.MsgBlock, buf []byte) + // OnCFilter is invoked when a peer receives a cfilter bitcoin message. + OnCFilter func(p *Peer, msg *wire.MsgCFilter) + + // OnCFHeaders is invoked when a peer receives a cfheaders bitcoin + // message. + OnCFHeaders func(p *Peer, msg *wire.MsgCFHeaders) + + // OnCFCheckpt is invoked when a peer receives a cfcheckpt bitcoin + // message. + OnCFCheckpt func(p *Peer, msg *wire.MsgCFCheckpt) + // OnInv is invoked when a peer receives an inv bitcoin message. OnInv func(p *Peer, msg *wire.MsgInv) @@ -144,6 +156,18 @@ type MessageListeners struct { // message. OnGetHeaders func(p *Peer, msg *wire.MsgGetHeaders) + // OnGetCFilters is invoked when a peer receives a getcfilters bitcoin + // message. + OnGetCFilters func(p *Peer, msg *wire.MsgGetCFilters) + + // OnGetCFHeaders is invoked when a peer receives a getcfheaders + // bitcoin message. + OnGetCFHeaders func(p *Peer, msg *wire.MsgGetCFHeaders) + + // OnGetCFCheckpt is invoked when a peer receives a getcfcheckpt + // bitcoin message. + OnGetCFCheckpt func(p *Peer, msg *wire.MsgGetCFCheckpt) + // OnFeeFilter is invoked when a peer receives a feefilter bitcoin message. OnFeeFilter func(p *Peer, msg *wire.MsgFeeFilter) @@ -245,6 +269,10 @@ type Config struct { // Listeners houses callback functions to be invoked on receiving peer // messages. Listeners MessageListeners + + // TrickleInterval is the duration of the ticker which trickles down the + // inventory to a peer. + TrickleInterval time.Duration } // minUint32 is a helper function to return the minimum of two uint32s. @@ -778,85 +806,6 @@ func (p *Peer) IsWitnessEnabled() bool { return witnessEnabled } -// localVersionMsg creates a version message that can be used to send to the -// remote peer. -func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) { - var blockNum int32 - if p.cfg.NewestBlock != nil { - var err error - _, blockNum, err = p.cfg.NewestBlock() - if err != nil { - return nil, err - } - } - - theirNA := p.na - - // If we are behind a proxy and the connection comes from the proxy then - // we return an unroutable address as their address. This is to prevent - // leaking the tor proxy address. - if p.cfg.Proxy != "" { - proxyaddress, _, err := net.SplitHostPort(p.cfg.Proxy) - // invalid proxy means poorly configured, be on the safe side. - if err != nil || p.na.IP.String() == proxyaddress { - theirNA = wire.NewNetAddressIPPort(net.IP([]byte{0, 0, 0, 0}), 0, 0) - } - } - - // Create a wire.NetAddress with only the services set to use as the - // "addrme" in the version message. - // - // Older nodes previously added the IP and port information to the - // address manager which proved to be unreliable as an inbound - // connection from a peer didn't necessarily mean the peer itself - // accepted inbound connections. - // - // Also, the timestamp is unused in the version message. - ourNA := &wire.NetAddress{ - Services: p.cfg.Services, - } - - // Generate a unique nonce for this peer so self connections can be - // detected. This is accomplished by adding it to a size-limited map of - // recently seen nonces. - nonce := uint64(rand.Int63()) - sentNonces.Add(nonce) - - // Version message. - msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum) - msg.AddUserAgent(p.cfg.UserAgentName, p.cfg.UserAgentVersion, - p.cfg.UserAgentComments...) - - // XXX: bitcoind appears to always enable the full node services flag - // of the remote peer netaddress field in the version message regardless - // of whether it knows it supports it or not. Also, bitcoind sets - // the services field of the local peer to 0 regardless of support. - // - // Realistically, this should be set as follows: - // - For outgoing connections: - // - Set the local netaddress services to what the local peer - // actually supports - // - Set the remote netaddress services to 0 to indicate no services - // as they are still unknown - // - For incoming connections: - // - Set the local netaddress services to what the local peer - // actually supports - // - Set the remote netaddress services to the what was advertised by - // by the remote peer in its version message - msg.AddrYou.Services = wire.SFNodeNetwork - - // Advertise the services flag - msg.Services = p.cfg.Services - - // Advertise our max supported protocol version. - msg.ProtocolVersion = int32(p.cfg.ProtocolVersion) - - // Advertise if inv messages for transactions are desired. - msg.DisableRelayTx = p.cfg.DisableRelayTx - - return msg, nil -} - // PushAddrMsg sends an addr message to the connected peer using the provided // addresses. This function is useful over manually sending the message via // QueueMessage since it automatically limits the addresses to the maximum @@ -1018,72 +967,6 @@ func (p *Peer) PushRejectMsg(command string, code wire.RejectCode, reason string <-doneChan } -// handleRemoteVersionMsg is invoked when a version bitcoin message is received -// from the remote peer. It will return an error if the remote peer's version -// is not compatible with ours. -func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error { - // Detect self connections. - if !allowSelfConns && sentNonces.Exists(msg.Nonce) { - return errors.New("disconnecting peer connected to self") - } - - // Notify and disconnect clients that have a protocol version that is - // too old. - // - // NOTE: If minAcceptableProtocolVersion is raised to be higher than - // wire.RejectVersion, this should send a reject packet before - // disconnecting. - if uint32(msg.ProtocolVersion) < minAcceptableProtocolVersion { - reason := fmt.Sprintf("protocol version must be %d or greater", - minAcceptableProtocolVersion) - return errors.New(reason) - } - - // Updating a bunch of stats including block based stats, and the - // peer's time offset. - p.statsMtx.Lock() - p.lastBlock = msg.LastBlock - p.startingHeight = msg.LastBlock - p.timeOffset = msg.Timestamp.Unix() - time.Now().Unix() - p.statsMtx.Unlock() - - // Negotiate the protocol version. - p.flagsMtx.Lock() - p.advertisedProtoVer = uint32(msg.ProtocolVersion) - p.protocolVersion = minUint32(p.protocolVersion, p.advertisedProtoVer) - p.versionKnown = true - log.Debugf("Negotiated protocol version %d for peer %s", - p.protocolVersion, p) - - // Set the peer's ID. - p.id = atomic.AddInt32(&nodeCount, 1) - - // Set the supported services for the peer to what the remote peer - // advertised. - p.services = msg.Services - - // Set the remote peer's user agent. - p.userAgent = msg.UserAgent - - // Determine if the peer would like to receive witness data with - // transactions, or not. - if p.services&wire.SFNodeWitness == wire.SFNodeWitness { - p.witnessEnabled = true - } - p.flagsMtx.Unlock() - - // Once the version message has been exchanged, we're able to determine - // if this peer knows how to encode witness data over the wire - // protocol. If so, then we'll switch to a decoding mode which is - // prepared for the new transaction format introduced as part of - // BIP0144. - if p.services&wire.SFNodeWitness == wire.SFNodeWitness { - p.wireEncoding = wire.WitnessEncoding - } - - return nil -} - // handlePingMsg is invoked when a peer receives a ping bitcoin message. For // recent clients (protocol version > BIP0031Version), it replies with a pong // message. For older clients, it does nothing and anything other than failure @@ -1579,6 +1462,31 @@ out: p.cfg.Listeners.OnGetHeaders(p, msg) } + case *wire.MsgGetCFilters: + if p.cfg.Listeners.OnGetCFilters != nil { + p.cfg.Listeners.OnGetCFilters(p, msg) + } + + case *wire.MsgGetCFHeaders: + if p.cfg.Listeners.OnGetCFHeaders != nil { + p.cfg.Listeners.OnGetCFHeaders(p, msg) + } + + case *wire.MsgGetCFCheckpt: + if p.cfg.Listeners.OnGetCFCheckpt != nil { + p.cfg.Listeners.OnGetCFCheckpt(p, msg) + } + + case *wire.MsgCFilter: + if p.cfg.Listeners.OnCFilter != nil { + p.cfg.Listeners.OnCFilter(p, msg) + } + + case *wire.MsgCFHeaders: + if p.cfg.Listeners.OnCFHeaders != nil { + p.cfg.Listeners.OnCFHeaders(p, msg) + } + case *wire.MsgFeeFilter: if p.cfg.Listeners.OnFeeFilter != nil { p.cfg.Listeners.OnFeeFilter(p, msg) @@ -1645,7 +1553,7 @@ out: func (p *Peer) queueHandler() { pendingMsgs := list.New() invSendQueue := list.New() - trickleTicker := time.NewTicker(trickleTimeout) + trickleTicker := time.NewTicker(p.cfg.TrickleInterval) defer trickleTicker.Stop() // We keep the waiting flag so that we know if we have a message queued @@ -1692,7 +1600,19 @@ out: case iv := <-p.outputInvChan: // No handshake? They'll find out soon enough. if p.VersionKnown() { - invSendQueue.PushBack(iv) + // If this is a new block, then we'll blast it + // out immediately, sipping the inv trickle + // queue. + if iv.Type == wire.InvTypeBlock || + iv.Type == wire.InvTypeWitnessBlock { + + invMsg := wire.NewMsgInvSizeHint(1) + invMsg.AddInvVect(iv) + waiting = queuePacket(outMsg{msg: invMsg}, + pendingMsgs, waiting) + } else { + invSendQueue.PushBack(iv) + } } case <-trickleTicker.C: @@ -1932,40 +1852,6 @@ func (p *Peer) QueueInventory(invVect *wire.InvVect) { p.outputInvChan <- invVect } -// AssociateConnection associates the given conn to the peer. Calling this -// function when the peer is already connected will have no effect. -func (p *Peer) AssociateConnection(conn net.Conn) { - // Already connected? - if !atomic.CompareAndSwapInt32(&p.connected, 0, 1) { - return - } - - p.conn = conn - p.timeConnected = time.Now() - - if p.inbound { - p.addr = p.conn.RemoteAddr().String() - - // Set up a NetAddress for the peer to be used with AddrManager. We - // only do this inbound because outbound set this up at connection time - // and no point recomputing. - na, err := newNetAddress(p.conn.RemoteAddr(), p.services) - if err != nil { - log.Errorf("Cannot create remote net address: %v", err) - p.Disconnect() - return - } - p.na = na - } - - go func() { - if err := p.start(); err != nil { - log.Debugf("Cannot start peer %v: %v", p, err) - p.Disconnect() - } - }() -} - // Connected returns whether or not the peer is currently connected. // // This function is safe for concurrent access. @@ -1989,51 +1875,72 @@ func (p *Peer) Disconnect() { close(p.quit) } -// start begins processing input and output messages. -func (p *Peer) start() error { - log.Tracef("Starting peer %s", p) - - negotiateErr := make(chan error) - go func() { - if p.inbound { - negotiateErr <- p.negotiateInboundProtocol() - } else { - negotiateErr <- p.negotiateOutboundProtocol() - } - }() - - // Negotiate the protocol within the specified negotiateTimeout. - select { - case err := <-negotiateErr: - if err != nil { - return err - } - case <-time.After(negotiateTimeout): - return errors.New("protocol negotiation timeout") +// handleRemoteVersionMsg is invoked when a version bitcoin message is received +// from the remote peer. It will return an error if the remote peer's version +// is not compatible with ours. +func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error { + // Detect self connections. + if !allowSelfConns && sentNonces.Exists(msg.Nonce) { + return errors.New("disconnecting peer connected to self") } - log.Debugf("Connected to %s", p.Addr()) - // The protocol has been negotiated successfully so start processing input - // and output messages. - go p.stallHandler() - go p.inHandler() - go p.queueHandler() - go p.outHandler() - go p.pingHandler() + // Notify and disconnect clients that have a protocol version that is + // too old. + // + // NOTE: If minAcceptableProtocolVersion is raised to be higher than + // wire.RejectVersion, this should send a reject packet before + // disconnecting. + if uint32(msg.ProtocolVersion) < minAcceptableProtocolVersion { + reason := fmt.Sprintf("protocol version must be %d or greater", + minAcceptableProtocolVersion) + return errors.New(reason) + } + + // Updating a bunch of stats including block based stats, and the + // peer's time offset. + p.statsMtx.Lock() + p.lastBlock = msg.LastBlock + p.startingHeight = msg.LastBlock + p.timeOffset = msg.Timestamp.Unix() - time.Now().Unix() + p.statsMtx.Unlock() + + // Negotiate the protocol version. + p.flagsMtx.Lock() + p.advertisedProtoVer = uint32(msg.ProtocolVersion) + p.protocolVersion = minUint32(p.protocolVersion, p.advertisedProtoVer) + p.versionKnown = true + log.Debugf("Negotiated protocol version %d for peer %s", + p.protocolVersion, p) + + // Set the peer's ID. + p.id = atomic.AddInt32(&nodeCount, 1) + + // Set the supported services for the peer to what the remote peer + // advertised. + p.services = msg.Services + + // Set the remote peer's user agent. + p.userAgent = msg.UserAgent + + // Determine if the peer would like to receive witness data with + // transactions, or not. + if p.services&wire.SFNodeWitness == wire.SFNodeWitness { + p.witnessEnabled = true + } + p.flagsMtx.Unlock() + + // Once the version message has been exchanged, we're able to determine + // if this peer knows how to encode witness data over the wire + // protocol. If so, then we'll switch to a decoding mode which is + // prepared for the new transaction format introduced as part of + // BIP0144. + if p.services&wire.SFNodeWitness == wire.SFNodeWitness { + p.wireEncoding = wire.WitnessEncoding + } - // Send our verack message now that the IO processing machinery has started. - p.QueueMessage(wire.NewMsgVerAck(), nil) return nil } -// WaitForDisconnect waits until the peer has completely disconnected and all -// resources are cleaned up. This will happen if either the local or remote -// side has been disconnected or the peer is forcibly disconnected via -// Disconnect. -func (p *Peer) WaitForDisconnect() { - <-p.quit -} - // readRemoteVersionMsg waits for the next message to arrive from the remote // peer. If the next message is not a version message or the version is not // acceptable then return an error. @@ -2064,6 +1971,85 @@ func (p *Peer) readRemoteVersionMsg() error { return nil } +// localVersionMsg creates a version message that can be used to send to the +// remote peer. +func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) { + var blockNum int32 + if p.cfg.NewestBlock != nil { + var err error + _, blockNum, err = p.cfg.NewestBlock() + if err != nil { + return nil, err + } + } + + theirNA := p.na + + // If we are behind a proxy and the connection comes from the proxy then + // we return an unroutable address as their address. This is to prevent + // leaking the tor proxy address. + if p.cfg.Proxy != "" { + proxyaddress, _, err := net.SplitHostPort(p.cfg.Proxy) + // invalid proxy means poorly configured, be on the safe side. + if err != nil || p.na.IP.String() == proxyaddress { + theirNA = wire.NewNetAddressIPPort(net.IP([]byte{0, 0, 0, 0}), 0, 0) + } + } + + // Create a wire.NetAddress with only the services set to use as the + // "addrme" in the version message. + // + // Older nodes previously added the IP and port information to the + // address manager which proved to be unreliable as an inbound + // connection from a peer didn't necessarily mean the peer itself + // accepted inbound connections. + // + // Also, the timestamp is unused in the version message. + ourNA := &wire.NetAddress{ + Services: p.cfg.Services, + } + + // Generate a unique nonce for this peer so self connections can be + // detected. This is accomplished by adding it to a size-limited map of + // recently seen nonces. + nonce := uint64(rand.Int63()) + sentNonces.Add(nonce) + + // Version message. + msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum) + msg.AddUserAgent(p.cfg.UserAgentName, p.cfg.UserAgentVersion, + p.cfg.UserAgentComments...) + + // XXX: bitcoind appears to always enable the full node services flag + // of the remote peer netaddress field in the version message regardless + // of whether it knows it supports it or not. Also, bitcoind sets + // the services field of the local peer to 0 regardless of support. + // + // Realistically, this should be set as follows: + // - For outgoing connections: + // - Set the local netaddress services to what the local peer + // actually supports + // - Set the remote netaddress services to 0 to indicate no services + // as they are still unknown + // - For incoming connections: + // - Set the local netaddress services to what the local peer + // actually supports + // - Set the remote netaddress services to the what was advertised by + // by the remote peer in its version message + msg.AddrYou.Services = wire.SFNodeNetwork + + // Advertise the services flag + msg.Services = p.cfg.Services + + // Advertise our max supported protocol version. + msg.ProtocolVersion = int32(p.cfg.ProtocolVersion) + + // Advertise if inv messages for transactions are desired. + msg.DisableRelayTx = p.cfg.DisableRelayTx + + return msg, nil +} + // writeLocalVersionMsg writes our version message to the remote peer. func (p *Peer) writeLocalVersionMsg() error { localVerMsg, err := p.localVersionMsg() @@ -2096,6 +2082,85 @@ func (p *Peer) negotiateOutboundProtocol() error { return p.readRemoteVersionMsg() } +// start begins processing input and output messages. +func (p *Peer) start() error { + log.Tracef("Starting peer %s", p) + + negotiateErr := make(chan error, 1) + go func() { + if p.inbound { + negotiateErr <- p.negotiateInboundProtocol() + } else { + negotiateErr <- p.negotiateOutboundProtocol() + } + }() + + // Negotiate the protocol within the specified negotiateTimeout. + select { + case err := <-negotiateErr: + if err != nil { + return err + } + case <-time.After(negotiateTimeout): + return errors.New("protocol negotiation timeout") + } + log.Debugf("Connected to %s", p.Addr()) + + // The protocol has been negotiated successfully so start processing input + // and output messages. + go p.stallHandler() + go p.inHandler() + go p.queueHandler() + go p.outHandler() + go p.pingHandler() + + // Send our verack message now that the IO processing machinery has started. + p.QueueMessage(wire.NewMsgVerAck(), nil) + return nil +} + +// AssociateConnection associates the given conn to the peer. Calling this +// function when the peer is already connected will have no effect. +func (p *Peer) AssociateConnection(conn net.Conn) { + // Already connected? + if !atomic.CompareAndSwapInt32(&p.connected, 0, 1) { + return + } + + p.conn = conn + p.timeConnected = time.Now() + + if p.inbound { + p.addr = p.conn.RemoteAddr().String() + + // Set up a NetAddress for the peer to be used with AddrManager. We + // only do this inbound because outbound set this up at connection time + // and no point recomputing. + na, err := newNetAddress(p.conn.RemoteAddr(), p.services) + if err != nil { + log.Errorf("Cannot create remote net address: %v", err) + p.Disconnect() + return + } + p.na = na + } + + go func() { + if err := p.start(); err != nil { + log.Debugf("Cannot start peer %v: %v", p, err) + p.Disconnect() + } + }() +} + +// WaitForDisconnect waits until the peer has completely disconnected and all +// resources are cleaned up. This will happen if either the local or remote +// side has been disconnected or the peer is forcibly disconnected via +// Disconnect. +func (p *Peer) WaitForDisconnect() { + <-p.quit +} + // newPeerBase returns a new base bitcoin peer based on the inbound flag. This // is used by the NewInboundPeer and NewOutboundPeer functions to perform base // setup needed by both types of peers. @@ -2112,6 +2177,11 @@ func newPeerBase(origCfg *Config, inbound bool) *Peer { cfg.ChainParams = &chaincfg.TestNet3Params } + // Set the trickle interval if a non-positive value is specified. + if cfg.TrickleInterval <= 0 { + cfg.TrickleInterval = DefaultTrickleInterval + } + p := Peer{ inbound: inbound, wireEncoding: wire.BaseEncoding, diff --git a/vendor/github.com/btcsuite/btcd/peer/peer_test.go b/vendor/github.com/btcsuite/btcd/peer/peer_test.go index 590c95dc..daf87ab8 100644 --- a/vendor/github.com/btcsuite/btcd/peer/peer_test.go +++ b/vendor/github.com/btcsuite/btcd/peer/peer_test.go @@ -236,6 +236,7 @@ func TestPeerConnection(t *testing.T) { ChainParams: &chaincfg.MainNetParams, ProtocolVersion: wire.RejectVersion, // Configure with older version Services: 0, + TrickleInterval: time.Second * 10, } peer2Cfg := &peer.Config{ Listeners: peer1Cfg.Listeners, @@ -244,6 +245,7 @@ func TestPeerConnection(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: wire.SFNodeNetwork | wire.SFNodeWitness, + TrickleInterval: time.Second * 10, } wantStats1 := peerStats{ @@ -399,6 +401,21 @@ func TestPeerListeners(t *testing.T) { OnGetHeaders: func(p *peer.Peer, msg *wire.MsgGetHeaders) { ok <- msg }, + OnGetCFilters: func(p *peer.Peer, msg *wire.MsgGetCFilters) { + ok <- msg + }, + OnGetCFHeaders: func(p *peer.Peer, msg *wire.MsgGetCFHeaders) { + ok <- msg + }, + OnGetCFCheckpt: func(p *peer.Peer, msg *wire.MsgGetCFCheckpt) { + ok <- msg + }, + OnCFilter: func(p *peer.Peer, msg *wire.MsgCFilter) { + ok <- msg + }, + OnCFHeaders: func(p *peer.Peer, msg *wire.MsgCFHeaders) { + ok <- msg + }, OnFeeFilter: func(p *peer.Peer, msg *wire.MsgFeeFilter) { ok <- msg }, @@ -432,6 +449,7 @@ func TestPeerListeners(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: wire.SFNodeBloom, + TrickleInterval: time.Second * 10, } inConn, outConn := pipe( &conn{raddr: "10.0.0.1:8333"}, @@ -522,6 +540,27 @@ func TestPeerListeners(t *testing.T) { "OnGetHeaders", wire.NewMsgGetHeaders(), }, + { + "OnGetCFilters", + wire.NewMsgGetCFilters(wire.GCSFilterRegular, 0, &chainhash.Hash{}), + }, + { + "OnGetCFHeaders", + wire.NewMsgGetCFHeaders(wire.GCSFilterRegular, 0, &chainhash.Hash{}), + }, + { + "OnGetCFCheckpt", + wire.NewMsgGetCFCheckpt(wire.GCSFilterRegular, &chainhash.Hash{}), + }, + { + "OnCFilter", + wire.NewMsgCFilter(wire.GCSFilterRegular, &chainhash.Hash{}, + []byte("payload")), + }, + { + "OnCFHeaders", + wire.NewMsgCFHeaders(), + }, { "OnFeeFilter", wire.NewMsgFeeFilter(15000), @@ -581,6 +620,7 @@ func TestOutboundPeer(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: 0, + TrickleInterval: time.Second * 10, } r, w := io.Pipe() @@ -721,6 +761,7 @@ func TestUnsupportedVersionPeer(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: 0, + TrickleInterval: time.Second * 10, } localNA := wire.NewNetAddressIPPort( diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/README.md b/vendor/github.com/btcsuite/btcd/rpcclient/README.md index 4d644110..06be0d69 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/README.md +++ b/vendor/github.com/btcsuite/btcd/rpcclient/README.md @@ -19,15 +19,15 @@ implement and the API is not stable yet. ## Documentation * [API Reference](http://godoc.org/github.com/btcsuite/btcd/rpcclient) -* [btcd Websockets Example](https://github.com/btcsuite/btcd/tree/master/rpcclient/examples/btcdwebsockets) +* [btcd Websockets Example](https://github.com/btcsuite/btcd/tree/master/rpcclient/examples/btcdwebsockets) Connects to a btcd RPC server using TLS-secured websockets, registers for block connected and block disconnected notifications, and gets the current block count -* [btcwallet Websockets Example](https://github.com/btcsuite/btcd/tree/master/rpcclient/examples/btcwalletwebsockets) +* [btcwallet Websockets Example](https://github.com/btcsuite/btcd/tree/master/rpcclient/examples/btcwalletwebsockets) Connects to a btcwallet RPC server using TLS-secured websockets, registers for notifications about changes to account balances, and gets a list of unspent transaction outputs (utxos) the wallet can sign -* [Bitcoin Core HTTP POST Example](https://github.com/btcsuite/btcd/tree/master/rpcclient/examples/bitcoincorehttp) +* [Bitcoin Core HTTP POST Example](https://github.com/btcsuite/btcd/tree/master/rpcclient/examples/bitcoincorehttp) Connects to a bitcoin core RPC server using HTTP POST mode with TLS disabled and gets the current block count diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/chain.go b/vendor/github.com/btcsuite/btcd/rpcclient/chain.go index 2539bc80..c2166891 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/chain.go +++ b/vendor/github.com/btcsuite/btcd/rpcclient/chain.go @@ -557,6 +557,43 @@ func (c *Client) GetRawMempoolVerbose() (map[string]btcjson.GetRawMempoolVerbose return c.GetRawMempoolVerboseAsync().Receive() } +// FutureEstimateFeeResult is a future promise to deliver the result of a +// EstimateFeeAsync RPC invocation (or an applicable error). +type FutureEstimateFeeResult chan *response + +// Receive waits for the response promised by the future and returns the info +// provided by the server. +func (r FutureEstimateFeeResult) Receive() (float64, error) { + res, err := receiveFuture(r) + if err != nil { + return -1, err + } + + // Unmarshal result as a getinfo result object. + var fee float64 + err = json.Unmarshal(res, &fee) + if err != nil { + return -1, err + } + + return fee, nil +} + +// EstimateFeeAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See EstimateFee for the blocking version and more details. +func (c *Client) EstimateFeeAsync(numBlocks int64) FutureEstimateFeeResult { + cmd := btcjson.NewEstimateFeeCmd(numBlocks) + return c.sendCmd(cmd) +} + +// EstimateFee provides an estimated fee in bitcoins per kilobyte. +func (c *Client) EstimateFee(numBlocks int64) (float64, error) { + return c.EstimateFeeAsync(numBlocks).Receive() +} + // FutureVerifyChainResult is a future promise to deliver the result of a // VerifyChainAsync, VerifyChainLevelAsyncRPC, or VerifyChainBlocksAsync // invocation (or an applicable error). @@ -781,3 +818,112 @@ func (c *Client) InvalidateBlockAsync(blockHash *chainhash.Hash) FutureInvalidat func (c *Client) InvalidateBlock(blockHash *chainhash.Hash) error { return c.InvalidateBlockAsync(blockHash).Receive() } + +// FutureGetCFilterResult is a future promise to deliver the result of a +// GetCFilterAsync RPC invocation (or an applicable error). +type FutureGetCFilterResult chan *response + +// Receive waits for the response promised by the future and returns the raw +// filter requested from the server given its block hash. +func (r FutureGetCFilterResult) Receive() (*wire.MsgCFilter, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + // Unmarshal result as a string. + var filterHex string + err = json.Unmarshal(res, &filterHex) + if err != nil { + return nil, err + } + + // Decode the serialized cf hex to raw bytes. + serializedFilter, err := hex.DecodeString(filterHex) + if err != nil { + return nil, err + } + + // Assign the filter bytes to the correct field of the wire message. + // We aren't going to set the block hash or extended flag, since we + // don't actually get that back in the RPC response. + var msgCFilter wire.MsgCFilter + msgCFilter.Data = serializedFilter + return &msgCFilter, nil +} + +// GetCFilterAsync returns an instance of a type that can be used to get the +// result of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See GetCFilter for the blocking version and more details. +func (c *Client) GetCFilterAsync(blockHash *chainhash.Hash, + filterType wire.FilterType) FutureGetCFilterResult { + hash := "" + if blockHash != nil { + hash = blockHash.String() + } + + cmd := btcjson.NewGetCFilterCmd(hash, filterType) + return c.sendCmd(cmd) +} + +// GetCFilter returns a raw filter from the server given its block hash. +func (c *Client) GetCFilter(blockHash *chainhash.Hash, + filterType wire.FilterType) (*wire.MsgCFilter, error) { + return c.GetCFilterAsync(blockHash, filterType).Receive() +} + +// FutureGetCFilterHeaderResult is a future promise to deliver the result of a +// GetCFilterHeaderAsync RPC invocation (or an applicable error). +type FutureGetCFilterHeaderResult chan *response + +// Receive waits for the response promised by the future and returns the raw +// filter header requested from the server given its block hash. +func (r FutureGetCFilterHeaderResult) Receive() (*wire.MsgCFHeaders, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + // Unmarshal result as a string. + var headerHex string + err = json.Unmarshal(res, &headerHex) + if err != nil { + return nil, err + } + + // Assign the decoded header into a hash + headerHash, err := chainhash.NewHashFromStr(headerHex) + if err != nil { + return nil, err + } + + // Assign the hash to a headers message and return it. + msgCFHeaders := wire.MsgCFHeaders{PrevFilterHeader: *headerHash} + return &msgCFHeaders, nil + +} + +// GetCFilterHeaderAsync returns an instance of a type that can be used to get +// the result of the RPC at some future time by invoking the Receive function +// on the returned instance. +// +// See GetCFilterHeader for the blocking version and more details. +func (c *Client) GetCFilterHeaderAsync(blockHash *chainhash.Hash, + filterType wire.FilterType) FutureGetCFilterHeaderResult { + hash := "" + if blockHash != nil { + hash = blockHash.String() + } + + cmd := btcjson.NewGetCFilterHeaderCmd(hash, filterType) + return c.sendCmd(cmd) +} + +// GetCFilterHeader returns a raw filter header from the server given its block +// hash. +func (c *Client) GetCFilterHeader(blockHash *chainhash.Hash, + filterType wire.FilterType) (*wire.MsgCFHeaders, error) { + return c.GetCFilterHeaderAsync(blockHash, filterType).Receive() +} diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/extensions.go b/vendor/github.com/btcsuite/btcd/rpcclient/extensions.go index 916ddb5f..d16cd525 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/extensions.go +++ b/vendor/github.com/btcsuite/btcd/rpcclient/extensions.go @@ -422,7 +422,7 @@ func (c *Client) Session() (*btcjson.SessionResult, error) { return c.SessionAsync().Receive() } -// FutureVersionResult is a future promise to delivere the result of a version +// FutureVersionResult is a future promise to deliver the result of a version // RPC invocation (or an applicable error). // // NOTE: This is a btcsuite extension ported from diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/infrastructure.go b/vendor/github.com/btcsuite/btcd/rpcclient/infrastructure.go index 24f0ae99..27f7f21f 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/infrastructure.go +++ b/vendor/github.com/btcsuite/btcd/rpcclient/infrastructure.go @@ -310,6 +310,8 @@ func (c *Client) handleMessage(msg []byte) { // Attempt to unmarshal the message as either a notification or // response. var in inMessage + in.rawResponse = new(rawResponse) + in.rawNotification = new(rawNotification) err := json.Unmarshal(msg, &in) if err != nil { log.Warnf("Remote server sent invalid message: %v", err) @@ -1106,7 +1108,7 @@ type ConnConfig struct { // flag can be set to true to use basic HTTP POST requests instead. HTTPPostMode bool - // EnableBCInfoHacks is an option provided to enable compatiblity hacks + // EnableBCInfoHacks is an option provided to enable compatibility hacks // when connecting to blockchain.info RPC server EnableBCInfoHacks bool } diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/notify.go b/vendor/github.com/btcsuite/btcd/rpcclient/notify.go index 9a0a3568..2454a946 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/notify.go +++ b/vendor/github.com/btcsuite/btcd/rpcclient/notify.go @@ -28,7 +28,7 @@ var ( "to use this feature") ) -// notificationState is used to track the current state of successfuly +// notificationState is used to track the current state of successfully // registered notification so the state can be automatically re-established on // reconnect. type notificationState struct { diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/rawtransactions.go b/vendor/github.com/btcsuite/btcd/rpcclient/rawtransactions.go index 3bd6e5d3..e886f225 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/rawtransactions.go +++ b/vendor/github.com/btcsuite/btcd/rpcclient/rawtransactions.go @@ -624,3 +624,41 @@ func (c *Client) SearchRawTransactionsVerbose(address btcutil.Address, skip, return c.SearchRawTransactionsVerboseAsync(address, skip, count, includePrevOut, reverse, &filterAddrs).Receive() } + +// FutureDecodeScriptResult is a future promise to deliver the result +// of a DecodeScriptAsync RPC invocation (or an applicable error). +type FutureDecodeScriptResult chan *response + +// Receive waits for the response promised by the future and returns information +// about a script given its serialized bytes. +func (r FutureDecodeScriptResult) Receive() (*btcjson.DecodeScriptResult, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + // Unmarshal result as a decodescript result object. + var decodeScriptResult btcjson.DecodeScriptResult + err = json.Unmarshal(res, &decodeScriptResult) + if err != nil { + return nil, err + } + + return &decodeScriptResult, nil +} + +// DecodeScriptAsync returns an instance of a type that can be used to +// get the result of the RPC at some future time by invoking the Receive +// function on the returned instance. +// +// See DecodeScript for the blocking version and more details. +func (c *Client) DecodeScriptAsync(serializedScript []byte) FutureDecodeScriptResult { + scriptHex := hex.EncodeToString(serializedScript) + cmd := btcjson.NewDecodeScriptCmd(scriptHex) + return c.sendCmd(cmd) +} + +// DecodeScript returns information about a script given its serialized bytes. +func (c *Client) DecodeScript(serializedScript []byte) (*btcjson.DecodeScriptResult, error) { + return c.DecodeScriptAsync(serializedScript).Receive() +} diff --git a/vendor/github.com/btcsuite/btcd/rpcclient/wallet.go b/vendor/github.com/btcsuite/btcd/rpcclient/wallet.go index caea70b8..10c12f1f 100644 --- a/vendor/github.com/btcsuite/btcd/rpcclient/wallet.go +++ b/vendor/github.com/btcsuite/btcd/rpcclient/wallet.go @@ -148,7 +148,7 @@ type FutureListUnspentResult chan *response // Receive waits for the response promised by the future and returns all // unspent wallet transaction outputs returned by the RPC call. If the -// future wac returnd by a call to ListUnspentMinAsync, ListUnspentMinMaxAsync, +// future wac returned by a call to ListUnspentMinAsync, ListUnspentMinMaxAsync, // or ListUnspentMinMaxAddressesAsync, the range may be limited by the // parameters of the RPC invocation. func (r FutureListUnspentResult) Receive() ([]btcjson.ListUnspentResult, error) { @@ -943,6 +943,44 @@ func (c *Client) GetRawChangeAddress(account string) (btcutil.Address, error) { return c.GetRawChangeAddressAsync(account).Receive() } +// FutureAddWitnessAddressResult is a future promise to deliver the result of +// a AddWitnessAddressAsync RPC invocation (or an applicable error). +type FutureAddWitnessAddressResult chan *response + +// Receive waits for the response promised by the future and returns the new +// address. +func (r FutureAddWitnessAddressResult) Receive() (btcutil.Address, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + // Unmarshal result as a string. + var addr string + err = json.Unmarshal(res, &addr) + if err != nil { + return nil, err + } + + return btcutil.DecodeAddress(addr, &chaincfg.MainNetParams) +} + +// AddWitnessAddressAsync returns an instance of a type that can be used to get +// the result of the RPC at some future time by invoking the Receive function on +// the returned instance. +// +// See AddWitnessAddress for the blocking version and more details. +func (c *Client) AddWitnessAddressAsync(address string) FutureAddWitnessAddressResult { + cmd := btcjson.NewAddWitnessAddressCmd(address) + return c.sendCmd(cmd) +} + +// AddWitnessAddress adds a witness address for a script and returns the new +// address (P2SH of the witness script). +func (c *Client) AddWitnessAddress(address string) (btcutil.Address, error) { + return c.AddWitnessAddressAsync(address).Receive() +} + // FutureGetAccountAddressResult is a future promise to deliver the result of a // GetAccountAddressAsync RPC invocation (or an applicable error). type FutureGetAccountAddressResult chan *response @@ -1397,7 +1435,7 @@ func (r FutureGetBalanceResult) Receive() (btcutil.Amount, error) { // FutureGetBalanceParseResult is same as FutureGetBalanceResult except // that the result is expected to be a string which is then parsed into // a float64 value -// This is required for compatiblity with servers like blockchain.info +// This is required for compatibility with servers like blockchain.info type FutureGetBalanceParseResult chan *response // Receive waits for the response promised by the future and returns the diff --git a/vendor/github.com/btcsuite/btcd/rpcserver.go b/vendor/github.com/btcsuite/btcd/rpcserver.go index 0ba2c4bc..6ade888d 100644 --- a/vendor/github.com/btcsuite/btcd/rpcserver.go +++ b/vendor/github.com/btcsuite/btcd/rpcserver.go @@ -132,6 +132,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "debuglevel": handleDebugLevel, "decoderawtransaction": handleDecodeRawTransaction, "decodescript": handleDecodeScript, + "estimatefee": handleEstimateFee, "generate": handleGenerate, "getaddednodeinfo": handleGetAddedNodeInfo, "getbestblock": handleGetBestBlock, @@ -142,6 +143,8 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getblockhash": handleGetBlockHash, "getblockheader": handleGetBlockHeader, "getblocktemplate": handleGetBlockTemplate, + "getcfilter": handleGetCFilter, + "getcfilterheader": handleGetCFilterHeader, "getconnectioncount": handleGetConnectionCount, "getcurrentnet": handleGetCurrentNet, "getdifficulty": handleGetDifficulty, @@ -222,7 +225,6 @@ var rpcAskWallet = map[string]struct{}{ // Commands that are currently unimplemented, but should ultimately be. var rpcUnimplemented = map[string]struct{}{ - "estimatefee": {}, "estimatepriority": {}, "getchaintips": {}, "getmempoolentry": {}, @@ -252,12 +254,15 @@ var rpcLimited = map[string]struct{}{ "createrawtransaction": {}, "decoderawtransaction": {}, "decodescript": {}, + "estimatefee": {}, "getbestblock": {}, "getbestblockhash": {}, "getblock": {}, "getblockcount": {}, "getblockhash": {}, "getblockheader": {}, + "getcfilter": {}, + "getcfilterheader": {}, "getcurrentnet": {}, "getdifficulty": {}, "getheaders": {}, @@ -849,6 +854,28 @@ func handleDecodeScript(s *rpcServer, cmd interface{}, closeChan <-chan struct{} return reply, nil } +// handleEstimateFee handles estimatefee commands. +func handleEstimateFee(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*btcjson.EstimateFeeCmd) + + if s.cfg.FeeEstimator == nil { + return nil, errors.New("Fee estimation disabled") + } + + if c.NumBlocks <= 0 { + return -1.0, errors.New("Parameter NumBlocks must be positive") + } + + feeRate, err := s.cfg.FeeEstimator.EstimateFee(uint32(c.NumBlocks)) + + if err != nil { + return -1.0, err + } + + // Convert to satoshis per kb. + return float64(feeRate), nil +} + // handleGenerate handles generate commands. func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { // Respond with an error if there are no addresses to pay the @@ -868,7 +895,7 @@ func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i Code: btcjson.ErrRPCDifficulty, Message: fmt.Sprintf("No support for `generate` on "+ "the current network, %s, as it's unlikely to "+ - "be possible to main a block with the CPU.", + "be possible to mine a block with the CPU.", s.cfg.ChainParams.Net), } } @@ -1099,7 +1126,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i PreviousHash: blockHeader.PrevBlock.String(), Nonce: blockHeader.Nonce, Time: blockHeader.Timestamp.Unix(), - Confirmations: uint64(1 + best.Height - blockHeight), + Confirmations: int64(1 + best.Height - blockHeight), Height: int64(blockHeight), Size: int32(len(blkBytes)), StrippedSize: int32(blk.MsgBlock().SerializeSizeStripped()), @@ -1293,7 +1320,7 @@ func handleGetBlockHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct if err != nil { return nil, rpcDecodeHexError(c.Hash) } - blockHeader, err := s.cfg.Chain.FetchHeader(hash) + blockHeader, err := s.cfg.Chain.HeaderByHash(hash) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCBlockNotFound, @@ -1337,7 +1364,7 @@ func handleGetBlockHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct params := s.cfg.ChainParams blockHeaderReply := btcjson.GetBlockHeaderVerboseResult{ Hash: c.Hash, - Confirmations: uint64(1 + best.Height - blockHeight), + Confirmations: int64(1 + best.Height - blockHeight), Height: blockHeight, Version: blockHeader.Version, VersionHex: fmt.Sprintf("%08x", blockHeader.Version), @@ -2144,6 +2171,66 @@ func handleGetBlockTemplate(s *rpcServer, cmd interface{}, closeChan <-chan stru } } +// handleGetCFilter implements the getcfilter command. +func handleGetCFilter(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + if s.cfg.CfIndex == nil { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCNoCFIndex, + Message: "The CF index must be enabled for this command", + } + } + + c := cmd.(*btcjson.GetCFilterCmd) + hash, err := chainhash.NewHashFromStr(c.Hash) + if err != nil { + return nil, rpcDecodeHexError(c.Hash) + } + + filterBytes, err := s.cfg.CfIndex.FilterByBlockHash(hash, c.FilterType) + if err != nil { + rpcsLog.Debugf("Could not find committed filter for %v: %v", + hash, err) + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCBlockNotFound, + Message: "Block not found", + } + } + + rpcsLog.Debugf("Found committed filter for %v", hash) + return hex.EncodeToString(filterBytes), nil +} + +// handleGetCFilterHeader implements the getcfilterheader command. +func handleGetCFilterHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + if s.cfg.CfIndex == nil { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCNoCFIndex, + Message: "The CF index must be enabled for this command", + } + } + + c := cmd.(*btcjson.GetCFilterHeaderCmd) + hash, err := chainhash.NewHashFromStr(c.Hash) + if err != nil { + return nil, rpcDecodeHexError(c.Hash) + } + + headerBytes, err := s.cfg.CfIndex.FilterHeaderByBlockHash(hash, c.FilterType) + if len(headerBytes) > 0 { + rpcsLog.Debugf("Found header of committed filter for %v", hash) + } else { + rpcsLog.Debugf("Could not find header of committed filter for %v: %v", + hash, err) + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCBlockNotFound, + Message: "Block not found", + } + } + + hash.SetBytes(headerBytes) + return hash.String(), nil +} + // handleGetConnectionCount implements the getconnectioncount command. func handleGetConnectionCount(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { return s.cfg.ConnMgr.ConnectedCount(), nil @@ -2355,7 +2442,7 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru } // Fetch the header from chain. - header, err := s.cfg.Chain.FetchHeader(hash) + header, err := s.cfg.Chain.HeaderByHash(hash) if err != nil { context := "Failed to fetch block header" return nil, internalRPCError(err.Error(), context) @@ -2547,7 +2634,7 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str var chainHeight int32 if blkHash != nil { // Fetch the header from chain. - header, err := s.cfg.Chain.FetchHeader(blkHash) + header, err := s.cfg.Chain.HeaderByHash(blkHash) if err != nil { context := "Failed to fetch block header" return nil, internalRPCError(err.Error(), context) @@ -2580,7 +2667,6 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i // from there, otherwise attempt to fetch from the block database. var bestBlockHash string var confirmations int32 - var txVersion int32 var value int64 var pkScript []byte var isCoinbase bool @@ -2615,12 +2701,12 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i best := s.cfg.Chain.BestSnapshot() bestBlockHash = best.Hash.String() confirmations = 0 - txVersion = mtx.Version value = txOut.Value pkScript = txOut.PkScript isCoinbase = blockchain.IsCoinBaseTx(mtx) } else { - entry, err := s.cfg.Chain.FetchUtxoEntry(txHash) + out := wire.OutPoint{Hash: *txHash, Index: c.Vout} + entry, err := s.cfg.Chain.FetchUtxoEntry(out) if err != nil { return nil, rpcNoTxInfoError(txHash) } @@ -2630,16 +2716,15 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i // transaction already in the main chain. Mined transactions // that are spent by a mempool transaction are not affected by // this. - if entry == nil || entry.IsOutputSpent(c.Vout) { + if entry == nil || entry.IsSpent() { return nil, nil } best := s.cfg.Chain.BestSnapshot() bestBlockHash = best.Hash.String() confirmations = 1 + best.Height - entry.BlockHeight() - txVersion = entry.Version() - value = entry.AmountByIndex(c.Vout) - pkScript = entry.PkScriptByIndex(c.Vout) + value = entry.Amount() + pkScript = entry.PkScript() isCoinbase = entry.IsCoinBase() } @@ -2662,7 +2747,6 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i BestBlock: bestBlockHash, Confirmations: int64(confirmations), Value: btcutil.Amount(value).ToBTC(), - Version: txVersion, ScriptPubKey: btcjson.ScriptPubKeyResult{ Asm: disbuf, Hex: hex.EncodeToString(pkScript), @@ -3178,7 +3262,7 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan var blkHeight int32 if blkHash := rtx.blkHash; blkHash != nil { // Fetch the header from chain. - header, err := s.cfg.Chain.FetchHeader(blkHash) + header, err := s.cfg.Chain.HeaderByHash(blkHash) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCBlockNotFound, @@ -4182,6 +4266,11 @@ type rpcserverConfig struct { // of to provide additional data when queried. TxIndex *indexers.TxIndex AddrIndex *indexers.AddrIndex + CfIndex *indexers.CfIndex + + // The fee estimator keeps track of how long transactions are left in + // the mempool before they are mined into blocks. + FeeEstimator *mempool.FeeEstimator } // newRPCServer returns a new instance of the rpcServer struct. diff --git a/vendor/github.com/btcsuite/btcd/rpcserverhelp.go b/vendor/github.com/btcsuite/btcd/rpcserverhelp.go index c615d039..c875d217 100644 --- a/vendor/github.com/btcsuite/btcd/rpcserverhelp.go +++ b/vendor/github.com/btcsuite/btcd/rpcserverhelp.go @@ -115,6 +115,15 @@ var helpDescsEnUS = map[string]string{ "decodescript--synopsis": "Returns a JSON object with information about the provided hex-encoded script.", "decodescript-hexscript": "Hex-encoded script", + // EstimateFeeCmd help. + "estimatefee--synopsis": "Estimate the fee per kilobyte in satoshis " + + "required for a transaction to be mined before a certain number of " + + "blocks have been generated.", + "estimatefee-numblocks": "The maximum number of blocks which can be " + + "generated before the transaction is mined.", + "estimatefee--result0": "Estimated fee per kilobyte in satoshis for a block to " + + "be mined in the next NumBlocks blocks.", + // GenerateCmd help "generate--synopsis": "Generates a set number of blocks (simnet or regtest only) and returns a JSON\n" + " array of their hashes.", @@ -196,7 +205,7 @@ var helpDescsEnUS = map[string]string{ "txrawresult-confirmations": "Number of confirmations of the block", "txrawresult-time": "Transaction time in seconds since 1 Jan 1970 GMT", "txrawresult-blocktime": "Block time in seconds since the 1 Jan 1970 GMT", - "txrawresult-size": "The size of the transation in bytes", + "txrawresult-size": "The size of the transaction in bytes", "txrawresult-vsize": "The virtual size of the transaction in bytes", "txrawresult-hash": "The wtxid of the transaction", @@ -221,7 +230,7 @@ var helpDescsEnUS = map[string]string{ "getblockverboseresult-size": "The size of the block", "getblockverboseresult-height": "The height of the block in the block chain", "getblockverboseresult-version": "The block version", - "getblockverboseresult-versionHex": "The block version in hexidecimal", + "getblockverboseresult-versionHex": "The block version in hexadecimal", "getblockverboseresult-merkleroot": "Root hash of the merkle tree", "getblockverboseresult-tx": "The transaction hashes (only when verbosetx=false)", "getblockverboseresult-rawtx": "The transactions as JSON objects (only when verbosetx=true)", @@ -256,7 +265,7 @@ var helpDescsEnUS = map[string]string{ "getblockheaderverboseresult-confirmations": "The number of confirmations", "getblockheaderverboseresult-height": "The height of the block in the block chain", "getblockheaderverboseresult-version": "The block version", - "getblockheaderverboseresult-versionHex": "The block version in hexidecimal", + "getblockheaderverboseresult-versionHex": "The block version in hexadecimal", "getblockheaderverboseresult-merkleroot": "Root hash of the merkle tree", "getblockheaderverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT", "getblockheaderverboseresult-nonce": "The block nonce", @@ -323,6 +332,18 @@ var helpDescsEnUS = map[string]string{ "getblocktemplate--condition2": "mode=proposal, accepted", "getblocktemplate--result1": "An error string which represents why the proposal was rejected or nothing if accepted", + // GetCFilterCmd help. + "getcfilter--synopsis": "Returns a block's committed filter given its hash.", + "getcfilter-filtertype": "The type of filter to return (0=regular)", + "getcfilter-hash": "The hash of the block", + "getcfilter--result0": "The block's committed filter", + + // GetCFilterHeaderCmd help. + "getcfilterheader--synopsis": "Returns a block's compact filter header given its hash.", + "getcfilterheader-filtertype": "The type of filter header to return (0=regular)", + "getcfilterheader-hash": "The hash of the block", + "getcfilterheader--result0": "The block's gcs filter header", + // GetConnectionCountCmd help. "getconnectioncount--synopsis": "Returns the number of active connections to other peers.", "getconnectioncount--result0": "The number of connections", @@ -658,6 +679,7 @@ var rpcResultTypes = map[string][]interface{}{ "debuglevel": {(*string)(nil), (*string)(nil)}, "decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)}, "decodescript": {(*btcjson.DecodeScriptResult)(nil)}, + "estimatefee": {(*float64)(nil)}, "generate": {(*[]string)(nil)}, "getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)}, "getbestblock": {(*btcjson.GetBestBlockResult)(nil)}, @@ -668,6 +690,8 @@ var rpcResultTypes = map[string][]interface{}{ "getblockheader": {(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)}, "getblocktemplate": {(*btcjson.GetBlockTemplateResult)(nil), (*string)(nil), nil}, "getblockchaininfo": {(*btcjson.GetBlockChainInfoResult)(nil)}, + "getcfilter": {(*string)(nil)}, + "getcfilterheader": {(*string)(nil)}, "getconnectioncount": {(*int32)(nil)}, "getcurrentnet": {(*uint32)(nil)}, "getdifficulty": {(*float64)(nil)}, diff --git a/vendor/github.com/btcsuite/btcd/rpcwebsocket.go b/vendor/github.com/btcsuite/btcd/rpcwebsocket.go index fcdcce2e..8b9d06b4 100644 --- a/vendor/github.com/btcsuite/btcd/rpcwebsocket.go +++ b/vendor/github.com/btcsuite/btcd/rpcwebsocket.go @@ -883,7 +883,7 @@ func (m *wsNotificationManager) RegisterSpentRequests(wsc *wsClient, ops []*wire // addSpentRequests modifies a map of watched outpoints to sets of websocket // clients to add a new request watch all of the outpoints in ops and create // and send a notification when spent to the websocket client wsc. -func (*wsNotificationManager) addSpentRequests(opMap map[wire.OutPoint]map[chan struct{}]*wsClient, +func (m *wsNotificationManager) addSpentRequests(opMap map[wire.OutPoint]map[chan struct{}]*wsClient, wsc *wsClient, ops []*wire.OutPoint) { for _, op := range ops { @@ -900,6 +900,22 @@ func (*wsNotificationManager) addSpentRequests(opMap map[wire.OutPoint]map[chan } cmap[wsc.quit] = wsc } + + // Check if any transactions spending these outputs already exists in + // the mempool, if so send the notification immediately. + spends := make(map[chainhash.Hash]*btcutil.Tx) + for _, op := range ops { + spend := m.server.cfg.TxMemPool.CheckSpend(*op) + if spend != nil { + rpcsLog.Debugf("Found existing mempool spend for "+ + "outpoint<%v>: %v", op, spend.Hash()) + spends[*spend.Hash()] = spend + } + } + + for _, spend := range spends { + m.notifyForTx(opMap, nil, spend, nil) + } } // UnregisterSpentRequest removes a request from the passed websocket client diff --git a/vendor/github.com/btcsuite/btcd/sample-btcd.conf b/vendor/github.com/btcsuite/btcd/sample-btcd.conf index ead8d06a..4508e387 100644 --- a/vendor/github.com/btcsuite/btcd/sample-btcd.conf +++ b/vendor/github.com/btcsuite/btcd/sample-btcd.conf @@ -167,6 +167,9 @@ ; Must not include characters '/', ':', '(' and ')'. ; uacomment= +; Disable committed peer filtering (CF). +; nocfilters=1 + ; ------------------------------------------------------------------------------ ; RPC server options - The following options control the built-in RPC server ; which is used to control and query information from a running btcd process. @@ -262,16 +265,6 @@ ; rejectnonstd=1 -; ------------------------------------------------------------------------------ -; Optional Transaction Indexes -; ------------------------------------------------------------------------------ - -; Build and maintain a full address-based transaction index. -; addrindex=1 -; Delete the entire address index on start up, then exit. -; dropaddrindex=0 - - ; ------------------------------------------------------------------------------ ; Optional Indexes ; ------------------------------------------------------------------------------ @@ -284,6 +277,9 @@ ; searchrawtransactions RPC available. ; addrindex=1 +; Delete the entire address index on start up, then exit. +; dropaddrindex=0 + ; ------------------------------------------------------------------------------ ; Signature Verification Cache @@ -302,7 +298,7 @@ ; Enable built-in CPU mining. ; ; NOTE: This is typically only useful for testing purposes such as testnet or -; simnet since the difficutly on mainnet is far too high for CPU mining to be +; simnet since the difficulty on mainnet is far too high for CPU mining to be ; worth your while. ; generate=false diff --git a/vendor/github.com/btcsuite/btcd/server.go b/vendor/github.com/btcsuite/btcd/server.go index 5b3c8385..7ac619a8 100644 --- a/vendor/github.com/btcsuite/btcd/server.go +++ b/vendor/github.com/btcsuite/btcd/server.go @@ -43,7 +43,8 @@ import ( const ( // defaultServices describes the default services that are supported by // the server. - defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom | wire.SFNodeWitness + defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom | + wire.SFNodeWitness | wire.SFNodeCF // defaultRequiredServices describes the default services that are // required to be supported by outbound peers. @@ -185,6 +186,13 @@ func (ps *peerState) forAllPeers(closure func(sp *serverPeer)) { ps.forAllOutboundPeers(closure) } +// cfHeaderKV is a tuple of a filter header and its associated block hash. The +// struct is used to cache cfcheckpt responses. +type cfHeaderKV struct { + blockHash chainhash.Hash + filterHeader chainhash.Hash +} + // server provides a bitcoin server for handling communications to and from // bitcoin peers. type server struct { @@ -228,6 +236,16 @@ type server struct { // do not need to be protected for concurrent access. txIndex *indexers.TxIndex addrIndex *indexers.AddrIndex + cfIndex *indexers.CfIndex + + // The fee estimator keeps track of how long transactions are left in + // the mempool before they are mined into blocks. + feeEstimator *mempool.FeeEstimator + + // cfCheckptCaches stores a cached slice of filter headers for cfcheckpt + // messages for each filter type. + cfCheckptCaches map[wire.FilterType][]cfHeaderKV + cfCheckptCachesMtx sync.RWMutex } // serverPeer extends the peer to maintain state shared by the server and @@ -724,10 +742,6 @@ func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) { // This mirrors the behavior in the reference implementation. chain := sp.server.chain headers := chain.LocateHeaders(msg.BlockLocatorHashes, &msg.HashStop) - if len(headers) == 0 { - // Nothing to send. - return - } // Send found headers to the requesting peer. blockHeaders := make([]*wire.BlockHeader, len(headers)) @@ -737,6 +751,330 @@ func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) { sp.QueueMessage(&wire.MsgHeaders{Headers: blockHeaders}, nil) } +// OnGetCFilters is invoked when a peer receives a getcfilters bitcoin message. +func (sp *serverPeer) OnGetCFilters(_ *peer.Peer, msg *wire.MsgGetCFilters) { + // Ignore getcfilters requests if not in sync. + if !sp.server.syncManager.IsCurrent() { + return + } + + // We'll also ensure that the remote party is requesting a set of + // filters that we actually currently maintain. + switch msg.FilterType { + case wire.GCSFilterRegular: + break + + default: + peerLog.Debug("Filter request for unknown filter: %v", + msg.FilterType) + return + } + + hashes, err := sp.server.chain.HeightToHashRange( + int32(msg.StartHeight), &msg.StopHash, wire.MaxGetCFiltersReqRange, + ) + if err != nil { + peerLog.Debugf("Invalid getcfilters request: %v", err) + return + } + + // Create []*chainhash.Hash from []chainhash.Hash to pass to + // FiltersByBlockHashes. + hashPtrs := make([]*chainhash.Hash, len(hashes)) + for i := range hashes { + hashPtrs[i] = &hashes[i] + } + + filters, err := sp.server.cfIndex.FiltersByBlockHashes( + hashPtrs, msg.FilterType, + ) + if err != nil { + peerLog.Errorf("Error retrieving cfilters: %v", err) + return + } + + for i, filterBytes := range filters { + if len(filterBytes) == 0 { + peerLog.Warnf("Could not obtain cfilter for %v", + hashes[i]) + return + } + + filterMsg := wire.NewMsgCFilter( + msg.FilterType, &hashes[i], filterBytes, + ) + sp.QueueMessage(filterMsg, nil) + } +} + +// OnGetCFHeaders is invoked when a peer receives a getcfheader bitcoin message. +func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) { + // Ignore getcfilterheader requests if not in sync. + if !sp.server.syncManager.IsCurrent() { + return + } + + // We'll also ensure that the remote party is requesting a set of + // headers for filters that we actually currently maintain. + switch msg.FilterType { + case wire.GCSFilterRegular: + break + + default: + peerLog.Debug("Filter request for unknown headers for "+ + "filter: %v", msg.FilterType) + return + } + + startHeight := int32(msg.StartHeight) + maxResults := wire.MaxCFHeadersPerMsg + + // If StartHeight is positive, fetch the predecessor block hash so we + // can populate the PrevFilterHeader field. + if msg.StartHeight > 0 { + startHeight-- + maxResults++ + } + + // Fetch the hashes from the block index. + hashList, err := sp.server.chain.HeightToHashRange( + startHeight, &msg.StopHash, maxResults, + ) + if err != nil { + peerLog.Debugf("Invalid getcfheaders request: %v", err) + } + + // This is possible if StartHeight is one greater that the height of + // StopHash, and we pull a valid range of hashes including the previous + // filter header. + if len(hashList) == 0 || (msg.StartHeight > 0 && len(hashList) == 1) { + peerLog.Debug("No results for getcfheaders request") + return + } + + // Create []*chainhash.Hash from []chainhash.Hash to pass to + // FilterHeadersByBlockHashes. + hashPtrs := make([]*chainhash.Hash, len(hashList)) + for i := range hashList { + hashPtrs[i] = &hashList[i] + } + + // Fetch the raw filter hash bytes from the database for all blocks. + filterHashes, err := sp.server.cfIndex.FilterHashesByBlockHashes( + hashPtrs, msg.FilterType, + ) + if err != nil { + peerLog.Errorf("Error retrieving cfilter hashes: %v", err) + return + } + + // Generate cfheaders message and send it. + headersMsg := wire.NewMsgCFHeaders() + + // Populate the PrevFilterHeader field. + if msg.StartHeight > 0 { + prevBlockHash := &hashList[0] + + // Fetch the raw committed filter header bytes from the + // database. + headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash( + prevBlockHash, msg.FilterType) + if err != nil { + peerLog.Errorf("Error retrieving CF header: %v", err) + return + } + if len(headerBytes) == 0 { + peerLog.Warnf("Could not obtain CF header for %v", prevBlockHash) + return + } + + // Deserialize the hash into PrevFilterHeader. + err = headersMsg.PrevFilterHeader.SetBytes(headerBytes) + if err != nil { + peerLog.Warnf("Committed filter header deserialize "+ + "failed: %v", err) + return + } + + hashList = hashList[1:] + filterHashes = filterHashes[1:] + } + + // Populate HeaderHashes. + for i, hashBytes := range filterHashes { + if len(hashBytes) == 0 { + peerLog.Warnf("Could not obtain CF hash for %v", hashList[i]) + return + } + + // Deserialize the hash. + filterHash, err := chainhash.NewHash(hashBytes) + if err != nil { + peerLog.Warnf("Committed filter hash deserialize "+ + "failed: %v", err) + return + } + + headersMsg.AddCFHash(filterHash) + } + + headersMsg.FilterType = msg.FilterType + headersMsg.StopHash = msg.StopHash + + sp.QueueMessage(headersMsg, nil) +} + +// OnGetCFCheckpt is invoked when a peer receives a getcfcheckpt bitcoin message. +func (sp *serverPeer) OnGetCFCheckpt(_ *peer.Peer, msg *wire.MsgGetCFCheckpt) { + // Ignore getcfcheckpt requests if not in sync. + if !sp.server.syncManager.IsCurrent() { + return + } + + // We'll also ensure that the remote party is requesting a set of + // checkpoints for filters that we actually currently maintain. + switch msg.FilterType { + case wire.GCSFilterRegular: + break + + default: + peerLog.Debug("Filter request for unknown checkpoints for "+ + "filter: %v", msg.FilterType) + return + } + + // Now that we know the client is fetching a filter that we know of, + // we'll fetch the block hashes et each check point interval so we can + // compare against our cache, and create new check points if necessary. + blockHashes, err := sp.server.chain.IntervalBlockHashes( + &msg.StopHash, wire.CFCheckptInterval, + ) + if err != nil { + peerLog.Debugf("Invalid getcfilters request: %v", err) + return + } + + checkptMsg := wire.NewMsgCFCheckpt( + msg.FilterType, &msg.StopHash, len(blockHashes), + ) + + // Fetch the current existing cache so we can decide if we need to + // extend it or if its adequate as is. + sp.server.cfCheckptCachesMtx.RLock() + checkptCache := sp.server.cfCheckptCaches[msg.FilterType] + + // If the set of block hashes is beyond the current size of the cache, + // then we'll expand the size of the cache and also retain the write + // lock. + var updateCache bool + if len(blockHashes) > len(checkptCache) { + // Now that we know we'll need to modify the size of the cache, + // we'll release the read lock and grab the write lock to + // possibly expand the cache size. + sp.server.cfCheckptCachesMtx.RUnlock() + + sp.server.cfCheckptCachesMtx.Lock() + defer sp.server.cfCheckptCachesMtx.Unlock() + + // Now that we have the write lock, we'll check again as it's + // possible that the cache has already been expanded. + checkptCache = sp.server.cfCheckptCaches[msg.FilterType] + + // If we still need to expand the cache, then We'll mark that + // we need to update the cache for below and also expand the + // size of the cache in place. + if len(blockHashes) > len(checkptCache) { + updateCache = true + + additionalLength := len(blockHashes) - len(checkptCache) + newEntries := make([]cfHeaderKV, additionalLength) + + peerLog.Infof("Growing size of checkpoint cache from %v to %v "+ + "block hashes", len(checkptCache), len(blockHashes)) + + checkptCache = append( + sp.server.cfCheckptCaches[msg.FilterType], + newEntries..., + ) + } + } else { + // Otherwise, we'll hold onto the read lock for the remainder + // of this method. + defer sp.server.cfCheckptCachesMtx.RUnlock() + + peerLog.Tracef("Serving stale cache of size %v", + len(checkptCache)) + } + + // Now that we know the cache is of an appropriate size, we'll iterate + // backwards until the find the block hash. We do this as it's possible + // a re-org has occurred so items in the db are now in the main china + // while the cache has been partially invalidated. + var forkIdx int + for forkIdx = len(blockHashes); forkIdx > 0; forkIdx-- { + if checkptCache[forkIdx-1].blockHash == blockHashes[forkIdx-1] { + break + } + } + + // Now that we know the how much of the cache is relevant for this + // query, we'll populate our check point message with the cache as is. + // Shortly below, we'll populate the new elements of the cache. + for i := 0; i < forkIdx; i++ { + checkptMsg.AddCFHeader(&checkptCache[i].filterHeader) + } + + // We'll now collect the set of hashes that are beyond our cache so we + // can look up the filter headers to populate the final cache. + blockHashPtrs := make([]*chainhash.Hash, 0, len(blockHashes)-forkIdx) + for i := forkIdx; i < len(blockHashes); i++ { + blockHashPtrs = append(blockHashPtrs, &blockHashes[i]) + } + filterHeaders, err := sp.server.cfIndex.FilterHeadersByBlockHashes( + blockHashPtrs, msg.FilterType, + ) + if err != nil { + peerLog.Errorf("Error retrieving cfilter headers: %v", err) + return + } + + // Now that we have the full set of filter headers, we'll add them to + // the checkpoint message, and also update our cache in line. + for i, filterHeaderBytes := range filterHeaders { + if len(filterHeaderBytes) == 0 { + peerLog.Warnf("Could not obtain CF header for %v", + blockHashPtrs[i]) + return + } + + filterHeader, err := chainhash.NewHash(filterHeaderBytes) + if err != nil { + peerLog.Warnf("Committed filter header deserialize "+ + "failed: %v", err) + return + } + + checkptMsg.AddCFHeader(filterHeader) + + // If the new main chain is longer than what's in the cache, + // then we'll override it beyond the fork point. + if updateCache { + checkptCache[forkIdx+i] = cfHeaderKV{ + blockHash: blockHashes[forkIdx+i], + filterHeader: *filterHeader, + } + } + } + + // Finally, we'll update the cache if we need to, and send the final + // message back to the requesting peer. + if updateCache { + sp.server.cfCheckptCaches[msg.FilterType] = checkptCache + } + + sp.QueueMessage(checkptMsg, nil) +} + // enforceNodeBloomFlag disconnects the peer if the server is not configured to // allow bloom filters. Additionally, if the peer has negotiated to a protocol // version that is high enough to observe the bloom filter service support bit, @@ -799,7 +1137,7 @@ func (sp *serverPeer) OnFilterAdd(_ *peer.Peer, msg *wire.MsgFilterAdd) { return } - if sp.filter.IsLoaded() { + if !sp.filter.IsLoaded() { peerLog.Debugf("%s sent a filteradd request with no filter "+ "loaded -- disconnecting", sp) sp.Disconnect() @@ -902,7 +1240,7 @@ func (sp *serverPeer) OnAddr(_ *peer.Peer, msg *wire.MsgAddr) { // A message that has no addresses is invalid. if len(msg.AddrList) == 0 { peerLog.Errorf("Command [%s] from %s does not contain any addresses", - msg.Command(), sp) + msg.Command(), sp.Peer) sp.Disconnect() return } @@ -1575,23 +1913,26 @@ func disconnectPeer(peerList map[int32]*serverPeer, compareFunc func(*serverPeer func newPeerConfig(sp *serverPeer) *peer.Config { return &peer.Config{ Listeners: peer.MessageListeners{ - OnVersion: sp.OnVersion, - OnMemPool: sp.OnMemPool, - OnTx: sp.OnTx, - OnBlock: sp.OnBlock, - OnInv: sp.OnInv, - OnHeaders: sp.OnHeaders, - OnGetData: sp.OnGetData, - OnGetBlocks: sp.OnGetBlocks, - OnGetHeaders: sp.OnGetHeaders, - OnFeeFilter: sp.OnFeeFilter, - OnFilterAdd: sp.OnFilterAdd, - OnFilterClear: sp.OnFilterClear, - OnFilterLoad: sp.OnFilterLoad, - OnGetAddr: sp.OnGetAddr, - OnAddr: sp.OnAddr, - OnRead: sp.OnRead, - OnWrite: sp.OnWrite, + OnVersion: sp.OnVersion, + OnMemPool: sp.OnMemPool, + OnTx: sp.OnTx, + OnBlock: sp.OnBlock, + OnInv: sp.OnInv, + OnHeaders: sp.OnHeaders, + OnGetData: sp.OnGetData, + OnGetBlocks: sp.OnGetBlocks, + OnGetHeaders: sp.OnGetHeaders, + OnGetCFilters: sp.OnGetCFilters, + OnGetCFHeaders: sp.OnGetCFHeaders, + OnGetCFCheckpt: sp.OnGetCFCheckpt, + OnFeeFilter: sp.OnFeeFilter, + OnFilterAdd: sp.OnFilterAdd, + OnFilterClear: sp.OnFilterClear, + OnFilterLoad: sp.OnFilterLoad, + OnGetAddr: sp.OnGetAddr, + OnAddr: sp.OnAddr, + OnRead: sp.OnRead, + OnWrite: sp.OnWrite, // Note: The reference client currently bans peers that send alerts // not signed with its key. We could verify against their key, but @@ -1609,6 +1950,7 @@ func newPeerConfig(sp *serverPeer) *peer.Config { Services: sp.server.services, DisableRelayTx: cfg.BlocksOnly, ProtocolVersion: peer.MaxProtocolVersion, + TrickleInterval: cfg.TrickleInterval, } } @@ -1953,6 +2295,14 @@ func (s *server) Stop() error { s.rpcServer.Stop() } + // Save fee estimator state in the database. + s.db.Update(func(tx database.Tx) error { + metadata := tx.Metadata() + metadata.Put(mempool.EstimateFeeDatabaseKey, s.feeEstimator.Save()) + + return nil + }) + // Signal the remaining goroutines to quit. close(s.quit) return nil @@ -2101,7 +2451,7 @@ out: s.wg.Done() } -// setupRPCListeners returns a slice of listners that are configured for use +// setupRPCListeners returns a slice of listeners that are configured for use // with the RPC server depending on the configuration settings for listen // addresses and TLS. func setupRPCListeners() ([]net.Listener, error) { @@ -2158,6 +2508,9 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param if cfg.NoPeerBloomFilters { services &^= wire.SFNodeBloom } + if cfg.NoCFilters { + services &^= wire.SFNodeCF + } amgr := addrmgr.New(cfg.DataDir, btcdLookup) @@ -2192,6 +2545,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param services: services, sigCache: txscript.NewSigCache(cfg.SigCacheMaxSize), hashCache: txscript.NewHashCache(cfg.SigCacheMaxSize), + cfCheckptCaches: make(map[wire.FilterType][]cfHeaderKV), } // Create the transaction and address indexes if needed. @@ -2220,6 +2574,11 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param s.addrIndex = indexers.NewAddrIndex(db, chainParams) indexes = append(indexes, s.addrIndex) } + if !cfg.NoCFilters { + indxLog.Info("Committed filter index is enabled") + s.cfIndex = indexers.NewCfIndex(db, chainParams) + indexes = append(indexes, s.cfIndex) + } // Create an index manager if any of the optional indexes are enabled. var indexManager blockchain.IndexManager @@ -2249,6 +2608,36 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param return nil, err } + // Search for a FeeEstimator state in the database. If none can be found + // or if it cannot be loaded, create a new one. + db.Update(func(tx database.Tx) error { + metadata := tx.Metadata() + feeEstimationData := metadata.Get(mempool.EstimateFeeDatabaseKey) + if feeEstimationData != nil { + // delete it from the database so that we don't try to restore the + // same thing again somehow. + metadata.Delete(mempool.EstimateFeeDatabaseKey) + + // If there is an error, log it and make a new fee estimator. + var err error + s.feeEstimator, err = mempool.RestoreFeeEstimator(feeEstimationData) + + if err != nil { + peerLog.Errorf("Failed to restore fee estimator %v", err) + } + } + + return nil + }) + + // If no feeEstimator has been found, or if the one that has been found + // is behind somehow, create a new one and start over. + if s.feeEstimator == nil || s.feeEstimator.LastKnownHeight() != s.chain.BestSnapshot().Height { + s.feeEstimator = mempool.NewFeeEstimator( + mempool.DefaultEstimateFeeMaxRollback, + mempool.DefaultEstimateFeeMinRegisteredBlocks) + } + txC := mempool.Config{ Policy: mempool.Policy{ DisableRelayPriority: cfg.NoRelayPriority, @@ -2271,6 +2660,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param SigCache: s.sigCache, HashCache: s.hashCache, AddrIndex: s.addrIndex, + FeeEstimator: s.feeEstimator, } s.txMemPool = mempool.New(&txC) @@ -2281,6 +2671,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param ChainParams: s.chainParams, DisableCheckpoints: cfg.DisableCheckpoints, MaxPeers: cfg.MaxPeers, + FeeEstimator: s.feeEstimator, }) if err != nil { return nil, err @@ -2405,19 +2796,21 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param } s.rpcServer, err = newRPCServer(&rpcserverConfig{ - Listeners: rpcListeners, - StartupTime: s.startupTime, - ConnMgr: &rpcConnManager{&s}, - SyncMgr: &rpcSyncMgr{&s, s.syncManager}, - TimeSource: s.timeSource, - Chain: s.chain, - ChainParams: chainParams, - DB: db, - TxMemPool: s.txMemPool, - Generator: blockTemplateGenerator, - CPUMiner: s.cpuMiner, - TxIndex: s.txIndex, - AddrIndex: s.addrIndex, + Listeners: rpcListeners, + StartupTime: s.startupTime, + ConnMgr: &rpcConnManager{&s}, + SyncMgr: &rpcSyncMgr{&s, s.syncManager}, + TimeSource: s.timeSource, + Chain: s.chain, + ChainParams: chainParams, + DB: db, + TxMemPool: s.txMemPool, + Generator: blockTemplateGenerator, + CPUMiner: s.cpuMiner, + TxIndex: s.txIndex, + AddrIndex: s.addrIndex, + CfIndex: s.cfIndex, + FeeEstimator: s.feeEstimator, }) if err != nil { return nil, err diff --git a/vendor/github.com/btcsuite/btcd/txscript/engine.go b/vendor/github.com/btcsuite/btcd/txscript/engine.go index 3fd7d5d9..b5aef52a 100644 --- a/vendor/github.com/btcsuite/btcd/txscript/engine.go +++ b/vendor/github.com/btcsuite/btcd/txscript/engine.go @@ -821,7 +821,7 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags } // The clean stack flag (ScriptVerifyCleanStack) is not allowed without - // either the the pay-to-script-hash (P2SH) evaluation (ScriptBip16) + // either the pay-to-script-hash (P2SH) evaluation (ScriptBip16) // flag or the Segregated Witness (ScriptVerifyWitness) flag. // // Recall that evaluating a P2SH script without the flag set results in diff --git a/vendor/github.com/btcsuite/btcd/txscript/script.go b/vendor/github.com/btcsuite/btcd/txscript/script.go index 1c3939b0..aac3d4aa 100644 --- a/vendor/github.com/btcsuite/btcd/txscript/script.go +++ b/vendor/github.com/btcsuite/btcd/txscript/script.go @@ -129,9 +129,9 @@ func IsWitnessProgram(script []byte) bool { // isWitnessProgram returns true if the passed script is a witness program, and // false otherwise. A witness program MUST adhere to the following constraints: -// there must be excatly two pops (program version and the program itself), the +// there must be exactly two pops (program version and the program itself), the // first opcode MUST be a small integer (0-16), the push data MUST be -// cannonical, and finally the size of the push data must be between 2 and 40 +// canonical, and finally the size of the push data must be between 2 and 40 // bytes. func isWitnessProgram(pops []parsedOpcode) bool { return len(pops) == 2 && @@ -582,6 +582,17 @@ func shallowCopyTx(tx *wire.MsgTx) wire.MsgTx { return txCopy } +// CalcSignatureHash will, given a script and hash type for the current script +// engine instance, calculate the signature hash to be used for signing and +// verification. +func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx int) ([]byte, error) { + parsedScript, err := parseScript(script) + if err != nil { + return nil, fmt.Errorf("cannot parse output script: %v", err) + } + return calcSignatureHash(parsedScript, hashType, tx, idx), nil +} + // calcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. diff --git a/vendor/github.com/btcsuite/btcd/txscript/sign.go b/vendor/github.com/btcsuite/btcd/txscript/sign.go index 09ba8d1f..42af9686 100644 --- a/vendor/github.com/btcsuite/btcd/txscript/sign.go +++ b/vendor/github.com/btcsuite/btcd/txscript/sign.go @@ -74,11 +74,10 @@ func WitnessSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int, amt int64 func RawTxInSignature(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, key *btcec.PrivateKey) ([]byte, error) { - parsedScript, err := parseScript(subScript) + hash, err := CalcSignatureHash(subScript, hashType, tx, idx) if err != nil { - return nil, fmt.Errorf("cannot parse output script: %v", err) + return nil, err } - hash := calcSignatureHash(parsedScript, hashType, tx, idx) signature, err := key.Sign(hash) if err != nil { return nil, fmt.Errorf("cannot sign tx input: %s", err) diff --git a/vendor/github.com/btcsuite/btcd/txscript/standard.go b/vendor/github.com/btcsuite/btcd/txscript/standard.go index 2ba5c8d9..a7e929d1 100644 --- a/vendor/github.com/btcsuite/btcd/txscript/standard.go +++ b/vendor/github.com/btcsuite/btcd/txscript/standard.go @@ -629,6 +629,7 @@ type AtomicSwapDataPushes struct { RecipientHash160 [20]byte RefundHash160 [20]byte SecretHash [32]byte + SecretSize int64 LockTime int64 } @@ -643,47 +644,61 @@ type AtomicSwapDataPushes struct { // // This function is only defined in the txscript package due to API limitations // which prevent callers using txscript to parse nonstandard scripts. -func ExtractAtomicSwapDataPushes(pkScript []byte) (*AtomicSwapDataPushes, error) { +func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDataPushes, error) { pops, err := parseScript(pkScript) if err != nil { return nil, err } - if len(pops) != 17 { + if len(pops) != 20 { return nil, nil } isAtomicSwap := pops[0].opcode.value == OP_IF && - pops[1].opcode.value == OP_SHA256 && - pops[2].opcode.value == OP_DATA_32 && + pops[1].opcode.value == OP_SIZE && + canonicalPush(pops[2]) && pops[3].opcode.value == OP_EQUALVERIFY && - pops[4].opcode.value == OP_DUP && - pops[5].opcode.value == OP_HASH160 && - pops[6].opcode.value == OP_DATA_20 && - pops[7].opcode.value == OP_ELSE && - canonicalPush(pops[8]) && - pops[9].opcode.value == OP_CHECKLOCKTIMEVERIFY && - pops[10].opcode.value == OP_DROP && - pops[11].opcode.value == OP_DUP && - pops[12].opcode.value == OP_HASH160 && - pops[13].opcode.value == OP_DATA_20 && - pops[14].opcode.value == OP_ENDIF && - pops[15].opcode.value == OP_EQUALVERIFY && - pops[16].opcode.value == OP_CHECKSIG + pops[4].opcode.value == OP_SHA256 && + pops[5].opcode.value == OP_DATA_32 && + pops[6].opcode.value == OP_EQUALVERIFY && + pops[7].opcode.value == OP_DUP && + pops[8].opcode.value == OP_HASH160 && + pops[9].opcode.value == OP_DATA_20 && + pops[10].opcode.value == OP_ELSE && + canonicalPush(pops[11]) && + pops[12].opcode.value == OP_CHECKLOCKTIMEVERIFY && + pops[13].opcode.value == OP_DROP && + pops[14].opcode.value == OP_DUP && + pops[15].opcode.value == OP_HASH160 && + pops[16].opcode.value == OP_DATA_20 && + pops[17].opcode.value == OP_ENDIF && + pops[18].opcode.value == OP_EQUALVERIFY && + pops[19].opcode.value == OP_CHECKSIG if !isAtomicSwap { return nil, nil } pushes := new(AtomicSwapDataPushes) - copy(pushes.SecretHash[:], pops[2].data) - copy(pushes.RecipientHash160[:], pops[6].data) - copy(pushes.RefundHash160[:], pops[13].data) - if pops[8].data != nil { - locktime, err := makeScriptNum(pops[8].data, true, 5) + copy(pushes.SecretHash[:], pops[5].data) + copy(pushes.RecipientHash160[:], pops[9].data) + copy(pushes.RefundHash160[:], pops[16].data) + if pops[2].data != nil { + locktime, err := makeScriptNum(pops[2].data, true, 5) + if err != nil { + return nil, nil + } + pushes.SecretSize = int64(locktime) + } else if op := pops[2].opcode; isSmallInt(op) { + pushes.SecretSize = int64(asSmallInt(op)) + } else { + return nil, nil + } + if pops[11].data != nil { + locktime, err := makeScriptNum(pops[11].data, true, 5) if err != nil { return nil, nil } pushes.LockTime = int64(locktime) - } else if op := pops[8].opcode; isSmallInt(op) { + } else if op := pops[11].opcode; isSmallInt(op) { pushes.LockTime = int64(asSmallInt(op)) } else { return nil, nil diff --git a/vendor/github.com/btcsuite/btcd/txscript/standard_test.go b/vendor/github.com/btcsuite/btcd/txscript/standard_test.go index 02826ab5..e24d5f61 100644 --- a/vendor/github.com/btcsuite/btcd/txscript/standard_test.go +++ b/vendor/github.com/btcsuite/btcd/txscript/standard_test.go @@ -568,13 +568,13 @@ func TestCalcScriptInfo(t *testing.T) { // unsupported address types are handled properly. type bogusAddress struct{} -// EncodeAddress simply returns an empty string. It exists to satsify the +// EncodeAddress simply returns an empty string. It exists to satisfy the // btcutil.Address interface. func (b *bogusAddress) EncodeAddress() string { return "" } -// ScriptAddress simply returns an empty byte slice. It exists to satsify the +// ScriptAddress simply returns an empty byte slice. It exists to satisfy the // btcutil.Address interface. func (b *bogusAddress) ScriptAddress() []byte { return nil @@ -585,7 +585,7 @@ func (b *bogusAddress) IsForNet(chainParams *chaincfg.Params) bool { return true // why not? } -// String simply returns an empty string. It exists to satsify the +// String simply returns an empty string. It exists to satisfy the // btcutil.Address interface. func (b *bogusAddress) String() string { return "" diff --git a/vendor/github.com/btcsuite/btcd/wire/README.md b/vendor/github.com/btcsuite/btcd/wire/README.md index a720b644..646bc0a3 100644 --- a/vendor/github.com/btcsuite/btcd/wire/README.md +++ b/vendor/github.com/btcsuite/btcd/wire/README.md @@ -4,6 +4,7 @@ wire [![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/wire) +======= Package wire implements the bitcoin wire protocol. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. diff --git a/vendor/github.com/btcsuite/btcd/wire/blockheader.go b/vendor/github.com/btcsuite/btcd/wire/blockheader.go index 892cf3ca..9c9c2237 100644 --- a/vendor/github.com/btcsuite/btcd/wire/blockheader.go +++ b/vendor/github.com/btcsuite/btcd/wire/blockheader.go @@ -23,7 +23,7 @@ type BlockHeader struct { // Version of the block. This is not the same as the protocol version. Version int32 - // Hash of the previous block in the block chain. + // Hash of the previous block header in the block chain. PrevBlock chainhash.Hash // Merkle tree reference to hash of all transactions for the block. diff --git a/vendor/github.com/btcsuite/btcd/wire/common.go b/vendor/github.com/btcsuite/btcd/wire/common.go index 85c9df83..42c1797b 100644 --- a/vendor/github.com/btcsuite/btcd/wire/common.go +++ b/vendor/github.com/btcsuite/btcd/wire/common.go @@ -630,8 +630,8 @@ func WriteVarString(w io.Writer, pver uint32, str string) error { // ReadVarBytes reads a variable length byte array. A byte array is encoded // as a varInt containing the length of the array followed by the bytes // themselves. An error is returned if the length is greater than the -// passed maxAllowed parameter which helps protect against memory exhuastion -// attacks and forced panics thorugh malformed messages. The fieldName +// passed maxAllowed parameter which helps protect against memory exhaustion +// attacks and forced panics through malformed messages. The fieldName // parameter is only used for the error message so it provides more context in // the error. func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32, diff --git a/vendor/github.com/btcsuite/btcd/wire/message.go b/vendor/github.com/btcsuite/btcd/wire/message.go index 80e9fe3c..4f03cf56 100644 --- a/vendor/github.com/btcsuite/btcd/wire/message.go +++ b/vendor/github.com/btcsuite/btcd/wire/message.go @@ -28,29 +28,35 @@ const MaxMessagePayload = (1024 * 1024 * 32) // 32MB // Commands used in bitcoin message headers which describe the type of message. const ( - CmdVersion = "version" - CmdVerAck = "verack" - CmdGetAddr = "getaddr" - CmdAddr = "addr" - CmdGetBlocks = "getblocks" - CmdInv = "inv" - CmdGetData = "getdata" - CmdNotFound = "notfound" - CmdBlock = "block" - CmdTx = "tx" - CmdGetHeaders = "getheaders" - CmdHeaders = "headers" - CmdPing = "ping" - CmdPong = "pong" - CmdAlert = "alert" - CmdMemPool = "mempool" - CmdFilterAdd = "filteradd" - CmdFilterClear = "filterclear" - CmdFilterLoad = "filterload" - CmdMerkleBlock = "merkleblock" - CmdReject = "reject" - CmdSendHeaders = "sendheaders" - CmdFeeFilter = "feefilter" + CmdVersion = "version" + CmdVerAck = "verack" + CmdGetAddr = "getaddr" + CmdAddr = "addr" + CmdGetBlocks = "getblocks" + CmdInv = "inv" + CmdGetData = "getdata" + CmdNotFound = "notfound" + CmdBlock = "block" + CmdTx = "tx" + CmdGetHeaders = "getheaders" + CmdHeaders = "headers" + CmdPing = "ping" + CmdPong = "pong" + CmdAlert = "alert" + CmdMemPool = "mempool" + CmdFilterAdd = "filteradd" + CmdFilterClear = "filterclear" + CmdFilterLoad = "filterload" + CmdMerkleBlock = "merkleblock" + CmdReject = "reject" + CmdSendHeaders = "sendheaders" + CmdFeeFilter = "feefilter" + CmdGetCFilters = "getcfilters" + CmdGetCFHeaders = "getcfheaders" + CmdGetCFCheckpt = "getcfcheckpt" + CmdCFilter = "cfilter" + CmdCFHeaders = "cfheaders" + CmdCFCheckpt = "cfcheckpt" ) // MessageEncoding represents the wire message encoding format to be used. @@ -156,6 +162,24 @@ func makeEmptyMessage(command string) (Message, error) { case CmdFeeFilter: msg = &MsgFeeFilter{} + case CmdGetCFilters: + msg = &MsgGetCFilters{} + + case CmdGetCFHeaders: + msg = &MsgGetCFHeaders{} + + case CmdGetCFCheckpt: + msg = &MsgGetCFCheckpt{} + + case CmdCFilter: + msg = &MsgCFilter{} + + case CmdCFHeaders: + msg = &MsgCFHeaders{} + + case CmdCFCheckpt: + msg = &MsgCFCheckpt{} + default: return nil, fmt.Errorf("unhandled command [%s]", command) } diff --git a/vendor/github.com/btcsuite/btcd/wire/message_test.go b/vendor/github.com/btcsuite/btcd/wire/message_test.go index 83005f4d..3a422e66 100644 --- a/vendor/github.com/btcsuite/btcd/wire/message_test.go +++ b/vendor/github.com/btcsuite/btcd/wire/message_test.go @@ -69,6 +69,13 @@ func TestMessage(t *testing.T) { bh := NewBlockHeader(1, &chainhash.Hash{}, &chainhash.Hash{}, 0, 0) msgMerkleBlock := NewMsgMerkleBlock(bh) msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block") + msgGetCFilters := NewMsgGetCFilters(GCSFilterRegular, 0, &chainhash.Hash{}) + msgGetCFHeaders := NewMsgGetCFHeaders(GCSFilterRegular, 0, &chainhash.Hash{}) + msgGetCFCheckpt := NewMsgGetCFCheckpt(GCSFilterRegular, &chainhash.Hash{}) + msgCFilter := NewMsgCFilter(GCSFilterRegular, &chainhash.Hash{}, + []byte("payload")) + msgCFHeaders := NewMsgCFHeaders() + msgCFCheckpt := NewMsgCFCheckpt(GCSFilterRegular, &chainhash.Hash{}, 0) tests := []struct { in Message // Value to encode @@ -98,6 +105,12 @@ func TestMessage(t *testing.T) { {msgFilterLoad, msgFilterLoad, pver, MainNet, 35}, {msgMerkleBlock, msgMerkleBlock, pver, MainNet, 110}, {msgReject, msgReject, pver, MainNet, 79}, + {msgGetCFilters, msgGetCFilters, pver, MainNet, 61}, + {msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 61}, + {msgGetCFCheckpt, msgGetCFCheckpt, pver, MainNet, 57}, + {msgCFilter, msgCFilter, pver, MainNet, 65}, + {msgCFHeaders, msgCFHeaders, pver, MainNet, 90}, + {msgCFCheckpt, msgCFCheckpt, pver, MainNet, 58}, } t.Logf("Running %d tests", len(tests)) diff --git a/vendor/github.com/btcsuite/btcd/wire/msgcfcheckpt.go b/vendor/github.com/btcsuite/btcd/wire/msgcfcheckpt.go new file mode 100644 index 00000000..fc3fd532 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/wire/msgcfcheckpt.go @@ -0,0 +1,164 @@ +// Copyright (c) 2018 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "errors" + "fmt" + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +const ( + // CFCheckptInterval is the gap (in number of blocks) between each + // filter header checkpoint. + CFCheckptInterval = 1000 + + // maxCFHeadersLen is the max number of filter headers we will attempt + // to decode. + maxCFHeadersLen = 100000 +) + +// ErrInsaneCFHeaderCount signals that we were asked to decode an +// unreasonable number of cfilter headers. +var ErrInsaneCFHeaderCount = errors.New( + "refusing to decode unreasonable number of filter headers") + +// MsgCFCheckpt implements the Message interface and represents a bitcoin +// cfcheckpt message. It is used to deliver committed filter header information +// in response to a getcfcheckpt message (MsgGetCFCheckpt). See MsgGetCFCheckpt +// for details on requesting the headers. +type MsgCFCheckpt struct { + FilterType FilterType + StopHash chainhash.Hash + FilterHeaders []*chainhash.Hash +} + +// AddCFHeader adds a new committed filter header to the message. +func (msg *MsgCFCheckpt) AddCFHeader(header *chainhash.Hash) error { + if len(msg.FilterHeaders) == cap(msg.FilterHeaders) { + str := fmt.Sprintf("FilterHeaders has insufficient capacity for "+ + "additional header: len = %d", len(msg.FilterHeaders)) + return messageError("MsgCFCheckpt.AddCFHeader", str) + } + + msg.FilterHeaders = append(msg.FilterHeaders, header) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { + // Read filter type + err := readElement(r, &msg.FilterType) + if err != nil { + return err + } + + // Read stop hash + err = readElement(r, &msg.StopHash) + if err != nil { + return err + } + + // Read number of filter headers + count, err := ReadVarInt(r, pver) + if err != nil { + return err + } + + // Refuse to decode an insane number of cfheaders. + if count > maxCFHeadersLen { + return ErrInsaneCFHeaderCount + } + + // Create a contiguous slice of hashes to deserialize into in order to + // reduce the number of allocations. + msg.FilterHeaders = make([]*chainhash.Hash, count) + for i := uint64(0); i < count; i++ { + var cfh chainhash.Hash + err := readElement(r, &cfh) + if err != nil { + return err + } + msg.FilterHeaders[i] = &cfh + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { + // Write filter type + err := writeElement(w, msg.FilterType) + if err != nil { + return err + } + + // Write stop hash + err = writeElement(w, msg.StopHash) + if err != nil { + return err + } + + // Write length of FilterHeaders slice + count := len(msg.FilterHeaders) + err = WriteVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, cfh := range msg.FilterHeaders { + err := writeElement(w, cfh) + if err != nil { + return err + } + } + + return nil +} + +// Deserialize decodes a filter header from r into the receiver using a format +// that is suitable for long-term storage such as a database. This function +// differs from BtcDecode in that BtcDecode decodes from the bitcoin wire +// protocol as it was sent across the network. The wire encoding can +// technically differ depending on the protocol version and doesn't even really +// need to match the format of a stored filter header at all. As of the time +// this comment was written, the encoded filter header is the same in both +// instances, but there is a distinct difference and separating the two allows +// the API to be flexible enough to deal with changes. +func (msg *MsgCFCheckpt) Deserialize(r io.Reader) error { + // At the current time, there is no difference between the wire encoding + // and the stable long-term storage format. As a result, make use of + // BtcDecode. + return msg.BtcDecode(r, 0, BaseEncoding) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgCFCheckpt) Command() string { + return CmdCFCheckpt +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgCFCheckpt) MaxPayloadLength(pver uint32) uint32 { + // Message size depends on the blockchain height, so return general limit + // for all messages. + return MaxMessagePayload +} + +// NewMsgCFCheckpt returns a new bitcoin cfheaders message that conforms to +// the Message interface. See MsgCFCheckpt for details. +func NewMsgCFCheckpt(filterType FilterType, stopHash *chainhash.Hash, + headersCount int) *MsgCFCheckpt { + return &MsgCFCheckpt{ + FilterType: filterType, + StopHash: *stopHash, + FilterHeaders: make([]*chainhash.Hash, 0, headersCount), + } +} diff --git a/vendor/github.com/btcsuite/btcd/wire/msgcfheaders.go b/vendor/github.com/btcsuite/btcd/wire/msgcfheaders.go new file mode 100644 index 00000000..40d30f9b --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/wire/msgcfheaders.go @@ -0,0 +1,180 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "fmt" + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +const ( + // MaxCFHeaderPayload is the maximum byte size of a committed + // filter header. + MaxCFHeaderPayload = chainhash.HashSize + + // MaxCFHeadersPerMsg is the maximum number of committed filter headers + // that can be in a single bitcoin cfheaders message. + MaxCFHeadersPerMsg = 2000 +) + +// MsgCFHeaders implements the Message interface and represents a bitcoin +// cfheaders message. It is used to deliver committed filter header information +// in response to a getcfheaders message (MsgGetCFHeaders). The maximum number +// of committed filter headers per message is currently 2000. See +// MsgGetCFHeaders for details on requesting the headers. +type MsgCFHeaders struct { + FilterType FilterType + StopHash chainhash.Hash + PrevFilterHeader chainhash.Hash + FilterHashes []*chainhash.Hash +} + +// AddCFHash adds a new filter hash to the message. +func (msg *MsgCFHeaders) AddCFHash(hash *chainhash.Hash) error { + if len(msg.FilterHashes)+1 > MaxCFHeadersPerMsg { + str := fmt.Sprintf("too many block headers in message [max %v]", + MaxBlockHeadersPerMsg) + return messageError("MsgCFHeaders.AddCFHash", str) + } + + msg.FilterHashes = append(msg.FilterHashes, hash) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { + // Read filter type + err := readElement(r, &msg.FilterType) + if err != nil { + return err + } + + // Read stop hash + err = readElement(r, &msg.StopHash) + if err != nil { + return err + } + + // Read prev filter header + err = readElement(r, &msg.PrevFilterHeader) + if err != nil { + return err + } + + // Read number of filter headers + count, err := ReadVarInt(r, pver) + if err != nil { + return err + } + + // Limit to max committed filter headers per message. + if count > MaxCFHeadersPerMsg { + str := fmt.Sprintf("too many committed filter headers for "+ + "message [count %v, max %v]", count, + MaxBlockHeadersPerMsg) + return messageError("MsgCFHeaders.BtcDecode", str) + } + + // Create a contiguous slice of hashes to deserialize into in order to + // reduce the number of allocations. + msg.FilterHashes = make([]*chainhash.Hash, 0, count) + for i := uint64(0); i < count; i++ { + var cfh chainhash.Hash + err := readElement(r, &cfh) + if err != nil { + return err + } + msg.AddCFHash(&cfh) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { + // Write filter type + err := writeElement(w, msg.FilterType) + if err != nil { + return err + } + + // Write stop hash + err = writeElement(w, msg.StopHash) + if err != nil { + return err + } + + // Write prev filter header + err = writeElement(w, msg.PrevFilterHeader) + if err != nil { + return err + } + + // Limit to max committed headers per message. + count := len(msg.FilterHashes) + if count > MaxCFHeadersPerMsg { + str := fmt.Sprintf("too many committed filter headers for "+ + "message [count %v, max %v]", count, + MaxBlockHeadersPerMsg) + return messageError("MsgCFHeaders.BtcEncode", str) + } + + err = WriteVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, cfh := range msg.FilterHashes { + err := writeElement(w, cfh) + if err != nil { + return err + } + } + + return nil +} + +// Deserialize decodes a filter header from r into the receiver using a format +// that is suitable for long-term storage such as a database. This function +// differs from BtcDecode in that BtcDecode decodes from the bitcoin wire +// protocol as it was sent across the network. The wire encoding can +// technically differ depending on the protocol version and doesn't even really +// need to match the format of a stored filter header at all. As of the time +// this comment was written, the encoded filter header is the same in both +// instances, but there is a distinct difference and separating the two allows +// the API to be flexible enough to deal with changes. +func (msg *MsgCFHeaders) Deserialize(r io.Reader) error { + // At the current time, there is no difference between the wire encoding + // and the stable long-term storage format. As a result, make use of + // BtcDecode. + return msg.BtcDecode(r, 0, BaseEncoding) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgCFHeaders) Command() string { + return CmdCFHeaders +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgCFHeaders) MaxPayloadLength(pver uint32) uint32 { + // Hash size + filter type + num headers (varInt) + + // (header size * max headers). + return 1 + chainhash.HashSize + chainhash.HashSize + MaxVarIntPayload + + (MaxCFHeaderPayload * MaxCFHeadersPerMsg) +} + +// NewMsgCFHeaders returns a new bitcoin cfheaders message that conforms to +// the Message interface. See MsgCFHeaders for details. +func NewMsgCFHeaders() *MsgCFHeaders { + return &MsgCFHeaders{ + FilterHashes: make([]*chainhash.Hash, 0, MaxCFHeadersPerMsg), + } +} diff --git a/vendor/github.com/btcsuite/btcd/wire/msgcfilter.go b/vendor/github.com/btcsuite/btcd/wire/msgcfilter.go new file mode 100644 index 00000000..097590b2 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/wire/msgcfilter.go @@ -0,0 +1,119 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "fmt" + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// FilterType is used to represent a filter type. +type FilterType uint8 + +const ( + // GCSFilterRegular is the regular filter type. + GCSFilterRegular FilterType = iota +) + +const ( + // MaxCFilterDataSize is the maximum byte size of a committed filter. + // The maximum size is currently defined as 256KiB. + MaxCFilterDataSize = 256 * 1024 +) + +// MsgCFilter implements the Message interface and represents a bitcoin cfilter +// message. It is used to deliver a committed filter in response to a +// getcfilters (MsgGetCFilters) message. +type MsgCFilter struct { + FilterType FilterType + BlockHash chainhash.Hash + Data []byte +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { + // Read filter type + err := readElement(r, &msg.FilterType) + if err != nil { + return err + } + + // Read the hash of the filter's block + err = readElement(r, &msg.BlockHash) + if err != nil { + return err + } + + // Read filter data + msg.Data, err = ReadVarBytes(r, pver, MaxCFilterDataSize, + "cfilter data") + return err +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { + size := len(msg.Data) + if size > MaxCFilterDataSize { + str := fmt.Sprintf("cfilter size too large for message "+ + "[size %v, max %v]", size, MaxCFilterDataSize) + return messageError("MsgCFilter.BtcEncode", str) + } + + err := writeElement(w, msg.FilterType) + if err != nil { + return err + } + + err = writeElement(w, msg.BlockHash) + if err != nil { + return err + } + + return WriteVarBytes(w, pver, msg.Data) +} + +// Deserialize decodes a filter from r into the receiver using a format that is +// suitable for long-term storage such as a database. This function differs +// from BtcDecode in that BtcDecode decodes from the bitcoin wire protocol as +// it was sent across the network. The wire encoding can technically differ +// depending on the protocol version and doesn't even really need to match the +// format of a stored filter at all. As of the time this comment was written, +// the encoded filter is the same in both instances, but there is a distinct +// difference and separating the two allows the API to be flexible enough to +// deal with changes. +func (msg *MsgCFilter) Deserialize(r io.Reader) error { + // At the current time, there is no difference between the wire encoding + // and the stable long-term storage format. As a result, make use of + // BtcDecode. + return msg.BtcDecode(r, 0, BaseEncoding) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgCFilter) Command() string { + return CmdCFilter +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgCFilter) MaxPayloadLength(pver uint32) uint32 { + return uint32(VarIntSerializeSize(MaxCFilterDataSize)) + + MaxCFilterDataSize + chainhash.HashSize + 1 +} + +// NewMsgCFilter returns a new bitcoin cfilter message that conforms to the +// Message interface. See MsgCFilter for details. +func NewMsgCFilter(filterType FilterType, blockHash *chainhash.Hash, + data []byte) *MsgCFilter { + return &MsgCFilter{ + FilterType: filterType, + BlockHash: *blockHash, + Data: data, + } +} diff --git a/vendor/github.com/btcsuite/btcd/wire/msggetcfcheckpt.go b/vendor/github.com/btcsuite/btcd/wire/msggetcfcheckpt.go new file mode 100644 index 00000000..c30a86ce --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/wire/msggetcfcheckpt.go @@ -0,0 +1,64 @@ +// Copyright (c) 2018 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// MsgGetCFCheckpt is a request for filter headers at evenly spaced intervals +// throughout the blockchain history. It allows to set the FilterType field to +// get headers in the chain of basic (0x00) or extended (0x01) headers. +type MsgGetCFCheckpt struct { + FilterType FilterType + StopHash chainhash.Hash +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { + err := readElement(r, &msg.FilterType) + if err != nil { + return err + } + + return readElement(r, &msg.StopHash) +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { + err := writeElement(w, msg.FilterType) + if err != nil { + return err + } + + return writeElement(w, &msg.StopHash) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetCFCheckpt) Command() string { + return CmdGetCFCheckpt +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetCFCheckpt) MaxPayloadLength(pver uint32) uint32 { + // Filter type + uint32 + block hash + return 1 + chainhash.HashSize +} + +// NewMsgGetCFCheckpt returns a new bitcoin getcfcheckpt message that conforms +// to the Message interface using the passed parameters and defaults for the +// remaining fields. +func NewMsgGetCFCheckpt(filterType FilterType, stopHash *chainhash.Hash) *MsgGetCFCheckpt { + return &MsgGetCFCheckpt{ + FilterType: filterType, + StopHash: *stopHash, + } +} diff --git a/vendor/github.com/btcsuite/btcd/wire/msggetcfheaders.go b/vendor/github.com/btcsuite/btcd/wire/msggetcfheaders.go new file mode 100644 index 00000000..03a1caf7 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/wire/msggetcfheaders.go @@ -0,0 +1,77 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// MsgGetCFHeaders is a message similar to MsgGetHeaders, but for committed +// filter headers. It allows to set the FilterType field to get headers in the +// chain of basic (0x00) or extended (0x01) headers. +type MsgGetCFHeaders struct { + FilterType FilterType + StartHeight uint32 + StopHash chainhash.Hash +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { + err := readElement(r, &msg.FilterType) + if err != nil { + return err + } + + err = readElement(r, &msg.StartHeight) + if err != nil { + return err + } + + return readElement(r, &msg.StopHash) +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { + err := writeElement(w, msg.FilterType) + if err != nil { + return err + } + + err = writeElement(w, &msg.StartHeight) + if err != nil { + return err + } + + return writeElement(w, &msg.StopHash) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetCFHeaders) Command() string { + return CmdGetCFHeaders +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetCFHeaders) MaxPayloadLength(pver uint32) uint32 { + // Filter type + uint32 + block hash + return 1 + 4 + chainhash.HashSize +} + +// NewMsgGetCFHeaders returns a new bitcoin getcfheader message that conforms to +// the Message interface using the passed parameters and defaults for the +// remaining fields. +func NewMsgGetCFHeaders(filterType FilterType, startHeight uint32, + stopHash *chainhash.Hash) *MsgGetCFHeaders { + return &MsgGetCFHeaders{ + FilterType: filterType, + StartHeight: startHeight, + StopHash: *stopHash, + } +} diff --git a/vendor/github.com/btcsuite/btcd/wire/msggetcfilters.go b/vendor/github.com/btcsuite/btcd/wire/msggetcfilters.go new file mode 100644 index 00000000..80024138 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/wire/msggetcfilters.go @@ -0,0 +1,81 @@ +// Copyright (c) 2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// MaxGetCFiltersReqRange the maximum number of filters that may be requested in +// a getcfheaders message. +const MaxGetCFiltersReqRange = 1000 + +// MsgGetCFilters implements the Message interface and represents a bitcoin +// getcfilters message. It is used to request committed filters for a range of +// blocks. +type MsgGetCFilters struct { + FilterType FilterType + StartHeight uint32 + StopHash chainhash.Hash +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetCFilters) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { + err := readElement(r, &msg.FilterType) + if err != nil { + return err + } + + err = readElement(r, &msg.StartHeight) + if err != nil { + return err + } + + return readElement(r, &msg.StopHash) +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetCFilters) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error { + err := writeElement(w, msg.FilterType) + if err != nil { + return err + } + + err = writeElement(w, &msg.StartHeight) + if err != nil { + return err + } + + return writeElement(w, &msg.StopHash) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetCFilters) Command() string { + return CmdGetCFilters +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetCFilters) MaxPayloadLength(pver uint32) uint32 { + // Filter type + uint32 + block hash + return 1 + 4 + chainhash.HashSize +} + +// NewMsgGetCFilters returns a new bitcoin getcfilters message that conforms to +// the Message interface using the passed parameters and defaults for the +// remaining fields. +func NewMsgGetCFilters(filterType FilterType, startHeight uint32, + stopHash *chainhash.Hash) *MsgGetCFilters { + return &MsgGetCFilters{ + FilterType: filterType, + StartHeight: startHeight, + StopHash: *stopHash, + } +} diff --git a/vendor/github.com/btcsuite/btcd/wire/msggetdata_test.go b/vendor/github.com/btcsuite/btcd/wire/msggetdata_test.go index ea11262e..a2dd4651 100644 --- a/vendor/github.com/btcsuite/btcd/wire/msggetdata_test.go +++ b/vendor/github.com/btcsuite/btcd/wire/msggetdata_test.go @@ -78,7 +78,7 @@ func TestGetDataWire(t *testing.T) { t.Errorf("NewHashFromStr: %v", err) } - // Transation 1 of Block 203707 hash. + // Transaction 1 of Block 203707 hash. hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" txHash, err := chainhash.NewHashFromStr(hashStr) if err != nil { diff --git a/vendor/github.com/btcsuite/btcd/wire/msginv_test.go b/vendor/github.com/btcsuite/btcd/wire/msginv_test.go index ea01fc11..b7c7c6ae 100644 --- a/vendor/github.com/btcsuite/btcd/wire/msginv_test.go +++ b/vendor/github.com/btcsuite/btcd/wire/msginv_test.go @@ -78,7 +78,7 @@ func TestInvWire(t *testing.T) { t.Errorf("NewHashFromStr: %v", err) } - // Transation 1 of Block 203707 hash. + // Transaction 1 of Block 203707 hash. hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" txHash, err := chainhash.NewHashFromStr(hashStr) if err != nil { diff --git a/vendor/github.com/btcsuite/btcd/wire/msgmerkleblock_test.go b/vendor/github.com/btcsuite/btcd/wire/msgmerkleblock_test.go index 430c1fbb..9837f8a9 100644 --- a/vendor/github.com/btcsuite/btcd/wire/msgmerkleblock_test.go +++ b/vendor/github.com/btcsuite/btcd/wire/msgmerkleblock_test.go @@ -405,7 +405,7 @@ var merkleBlockOne = MsgMerkleBlock{ } // merkleBlockOneBytes is the serialized bytes for a merkle block created from -// block one of the block chain where the first transation matches. +// block one of the block chain where the first transaction matches. var merkleBlockOneBytes = []byte{ 0x01, 0x00, 0x00, 0x00, // Version 1 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, diff --git a/vendor/github.com/btcsuite/btcd/wire/msgnotfound_test.go b/vendor/github.com/btcsuite/btcd/wire/msgnotfound_test.go index 07da74e8..69b9d07a 100644 --- a/vendor/github.com/btcsuite/btcd/wire/msgnotfound_test.go +++ b/vendor/github.com/btcsuite/btcd/wire/msgnotfound_test.go @@ -69,7 +69,7 @@ func TestNotFoundWire(t *testing.T) { t.Errorf("NewHashFromStr: %v", err) } - // Transation 1 of Block 203707 hash. + // Transaction 1 of Block 203707 hash. hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" txHash, err := chainhash.NewHashFromStr(hashStr) if err != nil { diff --git a/vendor/github.com/btcsuite/btcd/wire/msgtx.go b/vendor/github.com/btcsuite/btcd/wire/msgtx.go index af8abf61..4f10ef9f 100644 --- a/vendor/github.com/btcsuite/btcd/wire/msgtx.go +++ b/vendor/github.com/btcsuite/btcd/wire/msgtx.go @@ -62,13 +62,13 @@ const ( // a transaction which fits into a message could possibly have. maxTxInPerMessage = (MaxMessagePayload / minTxInPayload) + 1 - // minTxOutPayload is the minimum payload size for a transaction output. + // MinTxOutPayload is the minimum payload size for a transaction output. // Value 8 bytes + Varint for PkScript length 1 byte. - minTxOutPayload = 9 + MinTxOutPayload = 9 // maxTxOutPerMessage is the maximum number of transactions outputs that // a transaction which fits into a message could possibly have. - maxTxOutPerMessage = (MaxMessagePayload / minTxOutPayload) + 1 + maxTxOutPerMessage = (MaxMessagePayload / MinTxOutPayload) + 1 // minTxPayload is the minimum payload size for a transaction. Note // that any realistically usable transaction must have at least one @@ -923,7 +923,7 @@ func writeOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error // script. It is encoded as a varInt containing the length of the array // followed by the bytes themselves. An error is returned if the length is // greater than the passed maxAllowed parameter which helps protect against -// memory exhuastion attacks and forced panics thorugh malformed messages. The +// memory exhaustion attacks and forced panics through malformed messages. The // fieldName parameter is only used for the error message so it provides more // context in the error. func readScript(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) ([]byte, error) { diff --git a/vendor/github.com/btcsuite/btcd/wire/protocol.go b/vendor/github.com/btcsuite/btcd/wire/protocol.go index 30fdb01e..8cc9838a 100644 --- a/vendor/github.com/btcsuite/btcd/wire/protocol.go +++ b/vendor/github.com/btcsuite/btcd/wire/protocol.go @@ -10,6 +10,7 @@ import ( "strings" ) +// XXX pedro: we will probably need to bump this. const ( // ProtocolVersion is the latest protocol version this package supports. ProtocolVersion uint32 = 70013 @@ -70,6 +71,21 @@ const ( // SFNodeWitness is a flag used to indicate a peer supports blocks // and transactions including witness data (BIP0144). SFNodeWitness + + // SFNodeXthin is a flag used to indicate a peer supports xthin blocks. + SFNodeXthin + + // SFNodeBit5 is a flag used to indicate a peer supports a service + // defined by bit 5. + SFNodeBit5 + + // SFNodeCF is a flag used to indicate a peer supports committed + // filters (CFs). + SFNodeCF + + // SFNode2X is a flag used to indicate a peer is running the Segwit2X + // software. + SFNode2X ) // Map of service flags back to their constant names for pretty printing. @@ -78,6 +94,10 @@ var sfStrings = map[ServiceFlag]string{ SFNodeGetUTXO: "SFNodeGetUTXO", SFNodeBloom: "SFNodeBloom", SFNodeWitness: "SFNodeWitness", + SFNodeXthin: "SFNodeXthin", + SFNodeBit5: "SFNodeBit5", + SFNodeCF: "SFNodeCF", + SFNode2X: "SFNode2X", } // orderedSFStrings is an ordered list of service flags from highest to @@ -87,6 +107,10 @@ var orderedSFStrings = []ServiceFlag{ SFNodeGetUTXO, SFNodeBloom, SFNodeWitness, + SFNodeXthin, + SFNodeBit5, + SFNodeCF, + SFNode2X, } // String returns the ServiceFlag in human-readable form. diff --git a/vendor/github.com/btcsuite/btcd/wire/protocol_test.go b/vendor/github.com/btcsuite/btcd/wire/protocol_test.go index db9991f4..60bd0533 100644 --- a/vendor/github.com/btcsuite/btcd/wire/protocol_test.go +++ b/vendor/github.com/btcsuite/btcd/wire/protocol_test.go @@ -17,7 +17,11 @@ func TestServiceFlagStringer(t *testing.T) { {SFNodeGetUTXO, "SFNodeGetUTXO"}, {SFNodeBloom, "SFNodeBloom"}, {SFNodeWitness, "SFNodeWitness"}, - {0xffffffff, "SFNodeNetwork|SFNodeGetUTXO|SFNodeBloom|SFNodeWitness|0xfffffff0"}, + {SFNodeXthin, "SFNodeXthin"}, + {SFNodeBit5, "SFNodeBit5"}, + {SFNodeCF, "SFNodeCF"}, + {SFNode2X, "SFNode2X"}, + {0xffffffff, "SFNodeNetwork|SFNodeGetUTXO|SFNodeBloom|SFNodeWitness|SFNodeXthin|SFNodeBit5|SFNodeCF|SFNode2X|0xffffff00"}, } t.Logf("Running %d tests", len(tests)) diff --git a/vendor/github.com/dave/jennifer/.gitignore b/vendor/github.com/dave/jennifer/.gitignore new file mode 100644 index 00000000..f5730045 --- /dev/null +++ b/vendor/github.com/dave/jennifer/.gitignore @@ -0,0 +1,30 @@ +*.iml + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +.DS_Store +.idea/ +coverage.out diff --git a/vendor/github.com/dave/jennifer/.travis.yml b/vendor/github.com/dave/jennifer/.travis.yml new file mode 100644 index 00000000..1b62d095 --- /dev/null +++ b/vendor/github.com/dave/jennifer/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: + - 1.x +notificaitons: + email: + recipients: dave@brophy.uk + on_failure: always +install: + - go get -u github.com/dave/courtney + - go get -t -v ./... +script: + - courtney -e +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/dave/jennifer/LICENSE b/vendor/github.com/dave/jennifer/LICENSE new file mode 100644 index 00000000..17ab1ced --- /dev/null +++ b/vendor/github.com/dave/jennifer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 David Brophy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/dave/jennifer/README.md b/vendor/github.com/dave/jennifer/README.md new file mode 100644 index 00000000..2d9060cd --- /dev/null +++ b/vendor/github.com/dave/jennifer/README.md @@ -0,0 +1,1052 @@ +[![Build Status](https://travis-ci.org/dave/jennifer.svg?branch=master)](https://travis-ci.org/dave/jennifer) [![Go Report Card](https://goreportcard.com/badge/github.com/dave/jennifer)](https://goreportcard.com/report/github.com/dave/jennifer) [![codecov](https://img.shields.io/badge/codecov-100%25-brightgreen.svg)](https://codecov.io/gh/dave/jennifer) ![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg) [![Sourcegraph](https://sourcegraph.com/github.com/dave/jennifer/jen/-/badge.svg)](https://sourcegraph.com/github.com/dave/jennifer?badge) + +# Jennifer +Jennifer is a code generator for Go. + +```go +package main + +import ( + "fmt" + + . "github.com/dave/jennifer/jen" +) + +func main() { + f := NewFile("main") + f.Func().Id("main").Params().Block( + Qual("fmt", "Println").Call(Lit("Hello, world")), + ) + fmt.Printf("%#v", f) +} +``` +Output: +```go +package main + +import "fmt" + +func main() { + fmt.Println("Hello, world") +} +``` + +### Install +``` +go get -u github.com/dave/jennifer/jen +``` + +### Need help? +If you get stuck, have a question, would like a code review, or just want a +chat: I'm happy to help! Feel free to open an issue, email me or mention @dave +in your PR. + +### Examples +Jennifer has a comprehensive suite of examples - see [godoc](https://godoc.org/github.com/dave/jennifer/jen#pkg-examples) for an index. Here's some examples of jennifer being used in the real-world: + +* [genjen](genjen/render.go) (which generates much of jennifer, using data in [data.go](genjen/data.go)) +* [zerogen](https://github.com/mrsinham/zerogen/blob/master/generator.go) +* [go-contentful-generator](https://github.com/nicolai86/go-contentful-generator) + +### Rendering +For testing, a File or Statement can be rendered with the fmt package +using the %#v verb. + +```go +c := Id("a").Call(Lit("b")) +fmt.Printf("%#v", c) +// Output: +// a("b") +``` + +This is not recommended for use in production because any error will cause a +panic. For production use, [File.Render](#render) or [File.Save](#save) are +preferred. + +# Identifiers +**Identifiers** [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Id +Id renders an identifier. + +```go +c := If(Id("i").Op("==").Id("j")).Block( + Return(Id("i")), +) +fmt.Printf("%#v", c) +// Output: +// if i == j { +// return i +// } +``` + +### Dot +Dot renders a period followed by an identifier. Use for fields and selectors. + +```go +c := Qual("a.b/c", "Foo").Call().Dot("Bar").Index(Lit(0)).Dot("Baz") +fmt.Printf("%#v", c) +// Output: +// c.Foo().Bar[0].Baz +``` + +### Qual +Qual renders a qualified identifier. + +```go +c := Qual("encoding/gob", "NewEncoder").Call() +fmt.Printf("%#v", c) +// Output: +// gob.NewEncoder() +``` + +Imports are automatically added when +used with a File. If the path matches the local path, the package name is +omitted. If package names conflict they are automatically renamed. + +```go +f := NewFilePath("a.b/c") +f.Func().Id("init").Params().Block( + Qual("a.b/c", "Foo").Call().Comment("Local package - name is omitted."), + Qual("d.e/f", "Bar").Call().Comment("Import is automatically added."), + Qual("g.h/f", "Baz").Call().Comment("Colliding package name is renamed."), +) +fmt.Printf("%#v", f) +// Output: +// package c +// +// import ( +// f "d.e/f" +// f1 "g.h/f" +// ) +// +// func init() { +// Foo() // Local package - name is omitted. +// f.Bar() // Import is automatically added. +// f1.Baz() // Colliding package name is renamed. +// } +``` + +Note that +it is not possible to reliably determine the package name given an arbitrary +package path, so a sensible name is guessed from the path and added as an +alias. The names of all standard library packages are known so these do not +need to be aliased. If more control is needed of the aliases, see +[File.ImportName](#importname) or [File.ImportAlias](#importalias). + +### List +List renders a comma separated list. Use for multiple return functions. + +```go +c := List(Id("a"), Err()).Op(":=").Id("b").Call() +fmt.Printf("%#v", c) +// Output: +// a, err := b() +``` + +# Keywords +[Identifiers](#identifiers) **Keywords** [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Simple keywords, predeclared identifiers and built-in functions are self +explanatory: + +| Construct | Name | +| ---------------- | ---- | +| Keywords | Break, Chan, Const, Continue, Default, Defer, Else, Fallthrough, Func, Go, Goto, Range, Select, Type, Var | +| Functions | Append, Cap, Close, Complex, Copy, Delete, Imag, Len, Make, New, Panic, Print, Println, Real, Recover | +| Types | Bool, Byte, Complex64, Complex128, Error, Float32, Float64, Int, Int8, Int16, Int32, Int64, Rune, String, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr | +| Constants | True, False, Iota, Nil | +| Helpers | Err | + +Built-in functions take a list of parameters and render them appropriately: + +```go +c := Id("a").Op("=").Append(Id("a"), Id("b").Op("...")) +fmt.Printf("%#v", c) +// Output: +// a = append(a, b...) +``` + +Special cases for [If, For](#if-for), [Interface, Struct](#interface-struct), [Switch, Case](#switch-select), [Return](#return) and [Map](#map) are explained below. + +# Operators +[Identifiers](#identifiers) [Keywords](#keywords) **Operators** [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Op renders the provided operator / token. + +```go +c := Id("a").Op(":=").Id("b").Call() +fmt.Printf("%#v", c) +// Output: +// a := b() +``` + +```go +c := Id("a").Op("=").Op("*").Id("b") +fmt.Printf("%#v", c) +// Output: +// a = *b +``` + +```go +c := Id("a").Call(Id("b").Op("...")) +fmt.Printf("%#v", c) +// Output: +// a(b...) +``` + +```go +c := If(Parens(Id("a").Op("||").Id("b")).Op("&&").Id("c")).Block() +fmt.Printf("%#v", c) +// Output: +// if (a || b) && c { +// } +``` + +# Braces +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) **Braces** [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Several methods render curly braces, summarized below: + +| Name | Prefix | Separator | Example | +| ------------------------------ | ------------ | --------- | -------------------------------------| +| [Block](#block) | | `\n` | `func a() { ... }` or `if a { ... }` | +| [Interface](#interface-struct) | `interface` | `\n` | `interface { ... }` | +| [Struct](#interface-struct) | `struct` | `\n` | `struct { ... }` | +| [Values](#values) | | `,` | `[]int{1, 2}` or `A{B: "c"}` | + +### Block +Block renders a statement list enclosed by curly braces. Use for code blocks. + +```go +c := Func().Id("foo").Params().String().Block( + Id("a").Op("=").Id("b"), + Id("b").Op("++"), + Return(Id("b")), +) +fmt.Printf("%#v", c) +// Output: +// func foo() string { +// a = b +// b++ +// return b +// } +``` + +```go +c := If(Id("a").Op(">").Lit(10)).Block( + Id("a").Op("=").Id("a").Op("/").Lit(2), +) +fmt.Printf("%#v", c) +// Output: +// if a > 10 { +// a = a / 2 +// } +``` + +A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. [See example](#switch-select). + +### Interface, Struct +Interface and Struct render the keyword followed by a statement list enclosed +by curly braces. + +```go +c := Var().Id("a").Interface() +fmt.Printf("%#v", c) +// Output: +// var a interface{} +``` + +```go +c := Type().Id("a").Interface( + Id("b").Params().String(), +) +fmt.Printf("%#v", c) +// Output: +// type a interface { +// b() string +// } +``` + +```go +c := Id("c").Op(":=").Make(Chan().Struct()) +fmt.Printf("%#v", c) +// Output: +// c := make(chan struct{}) +``` + +```go +c := Type().Id("foo").Struct( + List(Id("x"), Id("y")).Int(), + Id("u").Float32(), +) +fmt.Printf("%#v", c) +// Output: +// type foo struct { +// x, y int +// u float32 +// } +``` + +# Parentheses +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) **Parentheses** [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Several methods output parenthesis, summarized below: + +| Name | Prefix | Separator | Example | +| ----------------- | ------ | --------- | --------------------------------- | +| [Call](#call) | | `,` | `fmt.Println(b, c)` | +| [Params](#params) | | `,` | `func (a *A) Foo(i int) { ... }` | +| [Defs](#defs) | | `\n` | `const ( ... )` | +| [Parens](#parens) | | | `[]byte(s)` or `a / (b + c)` | +| [Assert](#assert) | `.` | | `s, ok := i.(string)` | + +### Call +Call renders a comma separated list enclosed by parenthesis. Use for function calls. + +```go +c := Qual("fmt", "Printf").Call( + Lit("%#v: %T\n"), + Id("a"), + Id("b"), +) +fmt.Printf("%#v", c) +// Output: +// fmt.Printf("%#v: %T\n", a, b) +``` + +### Params +Params renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. + +```go +c := Func().Params( + Id("a").Id("A"), +).Id("foo").Params( + Id("b"), + Id("c").String(), +).String().Block( + Return(Id("b").Op("+").Id("c")), +) +fmt.Printf("%#v", c) +// Output: +// func (a A) foo(b, c string) string { +// return b + c +// } +``` + +### Defs +Defs renders a statement list enclosed in parenthesis. Use for definition lists. + +```go +c := Const().Defs( + Id("a").Op("=").Lit("a"), + Id("b").Op("=").Lit("b"), +) +fmt.Printf("%#v", c) +// Output: +// const ( +// a = "a" +// b = "b" +// ) +``` + +### Parens +Parens renders a single item in parenthesis. Use for type conversion or to specify evaluation order. + +```go +c := Id("b").Op(":=").Index().Byte().Parens(Id("s")) +fmt.Printf("%#v", c) +// Output: +// b := []byte(s) +``` + +```go +c := Id("a").Op("/").Parens(Id("b").Op("+").Id("c")) +fmt.Printf("%#v", c) +// Output: +// a / (b + c) +``` + +### Assert +Assert renders a period followed by a single item enclosed by parenthesis. Use for type assertions. + +```go +c := List(Id("b"), Id("ok")).Op(":=").Id("a").Assert(Bool()) +fmt.Printf("%#v", c) +// Output: +// b, ok := a.(bool) +``` + +# Control flow +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) **Control flow** [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### If, For +If and For render the keyword followed by a semicolon separated list. + +```go +c := If( + Err().Op(":=").Id("a").Call(), + Err().Op("!=").Nil(), +).Block( + Return(Err()), +) +fmt.Printf("%#v", c) +// Output: +// if err := a(); err != nil { +// return err +// } +``` + +```go +c := For( + Id("i").Op(":=").Lit(0), + Id("i").Op("<").Lit(10), + Id("i").Op("++"), +).Block( + Qual("fmt", "Println").Call(Id("i")), +) +fmt.Printf("%#v", c) +// Output: +// for i := 0; i < 10; i++ { +// fmt.Println(i) +// } +``` + +### Switch, Select +Switch, Select, Case and Block are used to build switch or select statements: + +```go +c := Switch(Id("value").Dot("Kind").Call()).Block( + Case(Qual("reflect", "Float32"), Qual("reflect", "Float64")).Block( + Return(Lit("float")), + ), + Case(Qual("reflect", "Bool")).Block( + Return(Lit("bool")), + ), + Case(Qual("reflect", "Uintptr")).Block( + Fallthrough(), + ), + Default().Block( + Return(Lit("none")), + ), +) +fmt.Printf("%#v", c) +// Output: +// switch value.Kind() { +// case reflect.Float32, reflect.Float64: +// return "float" +// case reflect.Bool: +// return "bool" +// case reflect.Uintptr: +// fallthrough +// default: +// return "none" +// } +``` + +### Return +Return renders the keyword followed by a comma separated list. + +```go +c := Return(Id("a"), Id("b")) +fmt.Printf("%#v", c) +// Output: +// return a, b +``` + +# Collections +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) **Collections** [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Map +Map renders the keyword followed by a single item enclosed by square brackets. Use for map definitions. + +```go +c := Id("a").Op(":=").Map(String()).String().Values() +fmt.Printf("%#v", c) +// Output: +// a := map[string]string{} +``` + +### Index +Index renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. + +```go +c := Var().Id("a").Index().String() +fmt.Printf("%#v", c) +// Output: +// var a []string +``` + +```go +c := Id("a").Op(":=").Id("b").Index(Lit(0), Lit(1)) +fmt.Printf("%#v", c) +// Output: +// a := b[0:1] +``` + +```go +c := Id("a").Op(":=").Id("b").Index(Lit(1), Empty()) +fmt.Printf("%#v", c) +// Output: +// a := b[1:] +``` + +### Values +Values renders a comma separated list enclosed by curly braces. Use for slice or composite literals. + +```go +c := Index().String().Values(Lit("a"), Lit("b")) +fmt.Printf("%#v", c) +// Output: +// []string{"a", "b"} +``` + +Dict renders as key/value pairs. Use with Values for map or composite +literals. + +```go +c := Map(String()).String().Values(Dict{ + Lit("a"): Lit("b"), + Lit("c"): Lit("d"), +}) +fmt.Printf("%#v", c) +// Output: +// map[string]string{ +// "a": "b", +// "c": "d", +// } +``` + +```go +c := Op("&").Id("Person").Values(Dict{ + Id("Age"): Lit(1), + Id("Name"): Lit("a"), +}) +fmt.Printf("%#v", c) +// Output: +// &Person{ +// Age: 1, +// Name: "a", +// } +``` + +DictFunc executes a func(Dict) to generate the value. + +```go +c := Id("a").Op(":=").Map(String()).String().Values(DictFunc(func(d Dict) { + d[Lit("a")] = Lit("b") + d[Lit("c")] = Lit("d") +})) +fmt.Printf("%#v", c) +// Output: +// a := map[string]string{ +// "a": "b", +// "c": "d", +// } +``` + +Note: the items are ordered by key when rendered to ensure repeatable code. + +# Literals +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) **Literals** [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Lit +Lit renders a literal. Lit supports only built-in types (bool, string, int, complex128, float64, +float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +Passing any other type will panic. + +```go +c := Id("a").Op(":=").Lit("a") +fmt.Printf("%#v", c) +// Output: +// a := "a" +``` + +```go +c := Id("a").Op(":=").Lit(1.5) +fmt.Printf("%#v", c) +// Output: +// a := 1.5 +``` + +LitFunc generates the value to render by executing the provided +function. + +```go +c := Id("a").Op(":=").LitFunc(func() interface{} { return 1 + 1 }) +fmt.Printf("%#v", c) +// Output: +// a := 2 +``` + +For the default constant types (bool, int, float64, string, complex128), Lit +will render the untyped constant. + +| Code | Output | +| ------------- | ---------- | +| `Lit(true)` | `true` | +| `Lit(1)` | `1` | +| `Lit(1.0)` | `1.0` | +| `Lit("foo")` | `"foo"` | +| `Lit(0 + 1i)` | `(0 + 1i)` | + +For all other built-in types (float32, int8, int16, int32, int64, uint, uint8, +uint16, uint32, uint64, uintptr, complex64), Lit will also render the type. + +| Code | Output | +| ------------------------ | ------------------- | +| `Lit(float32(1))` | `float32(1)` | +| `Lit(int16(1))` | `int16(1)` | +| `Lit(uint8(0x1))` | `uint8(0x1)` | +| `Lit(complex64(0 + 1i))` | `complex64(0 + 1i)` | + +The built-in alias types byte and rune need a special case. LitRune and LitByte +render rune and byte literals. + +| Code | Output | +| ------------------------ | ----------- | +| `LitRune('x')` | `'x'` | +| `LitByte(byte(0x1))` | `byte(0x1)` | + +# Comments +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) **Comments** [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Comment +Comment adds a comment. If the provided string contains a newline, the +comment is formatted in multiline style. + +```go +f := NewFile("a") +f.Comment("Foo returns the string \"foo\"") +f.Func().Id("Foo").Params().String().Block( + Return(Lit("foo")).Comment("return the string foo"), +) +fmt.Printf("%#v", f) +// Output: +// package a +// +// // Foo returns the string "foo" +// func Foo() string { +// return "foo" // return the string foo +// } +``` + +```go +c := Comment("a\nb") +fmt.Printf("%#v", c) +// Output: +// /* +// a +// b +// */ +``` + +If the comment string starts +with "//" or "/*", the automatic formatting is disabled and the string is +rendered directly. + +```go +c := Id("foo").Call(Comment("/* inline */")).Comment("//no-space") +fmt.Printf("%#v", c) +// Output: +// foo( /* inline */ ) //no-space +``` + +### Commentf +Commentf adds a comment, using a format string and a list of parameters. + +```go +name := "foo" +val := "bar" +c := Id(name).Op(":=").Lit(val).Commentf("%s is the string \"%s\"", name, val) +fmt.Printf("%#v", c) +// Output: +// foo := "bar" // foo is the string "bar" +``` + +# Helpers +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) **Helpers** [Misc](#misc) [File](#file) + +### Func methods +All constructs that accept a variadic list of items are paired with GroupFunc +functions that accept a func(*Group). Use for embedding logic. + +```go +c := Id("numbers").Op(":=").Index().Int().ValuesFunc(func(g *Group) { + for i := 0; i <= 5; i++ { + g.Lit(i) + } +}) +fmt.Printf("%#v", c) +// Output: +// numbers := []int{0, 1, 2, 3, 4, 5} +``` + +```go +increment := true +name := "a" +c := Func().Id("a").Params().BlockFunc(func(g *Group) { + g.Id(name).Op("=").Lit(1) + if increment { + g.Id(name).Op("++") + } else { + g.Id(name).Op("--") + } +}) +fmt.Printf("%#v", c) +// Output: +// func a() { +// a = 1 +// a++ +// } +``` + +### Add +Add appends the provided items to the statement. + +```go +ptr := Op("*") +c := Id("a").Op("=").Add(ptr).Id("b") +fmt.Printf("%#v", c) +// Output: +// a = *b +``` + +```go +a := Id("a") +i := Int() +c := Var().Add(a, i) +fmt.Printf("%#v", c) +// Output: +// var a int +``` + +### Do +Do calls the provided function with the statement as a parameter. Use for +embedding logic. + +```go +f := func(name string, isMap bool) *Statement { + return Id(name).Op(":=").Do(func(s *Statement) { + if isMap { + s.Map(String()).String() + } else { + s.Index().String() + } + }).Values() +} +fmt.Printf("%#v\n%#v", f("a", true), f("b", false)) +// Output: +// a := map[string]string{} +// b := []string{} +``` + +# Misc +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) **Misc** [File](#file) + +### Tag +Tag renders a struct tag + +```go +c := Type().Id("foo").Struct( + Id("A").String().Tag(map[string]string{"json": "a"}), + Id("B").Int().Tag(map[string]string{"json": "b", "bar": "baz"}), +) +fmt.Printf("%#v", c) +// Output: +// type foo struct { +// A string `json:"a"` +// B int `bar:"baz" json:"b"` +// } +``` + +Note: the items are ordered by key when rendered to ensure repeatable code. + +### Null +Null adds a null item. Null items render nothing and are not followed by a +separator in lists. + +In lists, nil will produce the same effect. + +```go +c := Func().Id("foo").Params( + nil, + Id("s").String(), + Null(), + Id("i").Int(), +).Block() +fmt.Printf("%#v", c) +// Output: +// func foo(s string, i int) {} +``` + +### Empty +Empty adds an empty item. Empty items render nothing but are followed by a +separator in lists. + +```go +c := Id("a").Op(":=").Id("b").Index(Lit(1), Empty()) +fmt.Printf("%#v", c) +// Output: +// a := b[1:] +``` + +### Line +Line inserts a blank line. + +### Clone +Be careful when passing *Statement. Consider the following... + +```go +a := Id("a") +c := Block( + a.Call(), + a.Call(), +) +fmt.Printf("%#v", c) +// Output: +// { +// a()() +// a()() +// } +``` + +Id("a") returns a *Statement, which the Call() method appends to twice. To +avoid this, use Clone. Clone makes a copy of the Statement, so further tokens can be appended +without affecting the original. + +```go +a := Id("a") +c := Block( + a.Clone().Call(), + a.Clone().Call(), +) +fmt.Printf("%#v", c) +// Output: +// { +// a() +// a() +// } +``` + +### Cgo +The cgo "C" pseudo-package is a special case, and always renders without a package alias. The +import can be added with `Qual`, `Anon` or by supplying a preamble. The preamble is added with +`File.CgoPreamble` which has the same semantics as [Comment](#comments). If a preamble is provided, +the import is separated, and preceded by the preamble. + +```go +f := NewFile("a") +f.CgoPreamble(`#include +#include + +void myprint(char* s) { +printf("%s\n", s); +} +`) +f.Func().Id("init").Params().Block( + Id("cs").Op(":=").Qual("C", "CString").Call(Lit("Hello from stdio\n")), + Qual("C", "myprint").Call(Id("cs")), + Qual("C", "free").Call(Qual("unsafe", "Pointer").Parens(Id("cs"))), +) +fmt.Printf("%#v", f) +// Output: +// package a +// +// import "unsafe" +// +// /* +// #include +// #include +// +// void myprint(char* s) { +// printf("%s\n", s); +// } +// */ +// import "C" +// +// func init() { +// cs := C.CString("Hello from stdio\n") +// C.myprint(cs) +// C.free(unsafe.Pointer(cs)) +// } +``` + +# File +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) **File** + +File represents a single source file. Package imports are managed +automaticaly by File. + +### NewFile +NewFile Creates a new file, with the specified package name. + +### NewFilePath +NewFilePath creates a new file while specifying the package path - the +package name is inferred from the path. + +### NewFilePathName +NewFilePathName creates a new file with the specified package path and name. + +```go +f := NewFilePathName("a.b/c", "main") +f.Func().Id("main").Params().Block( + Qual("a.b/c", "Foo").Call(), +) +fmt.Printf("%#v", f) +// Output: +// package main +// +// func main() { +// Foo() +// } +``` + +### Save +Save renders the file and saves to the filename provided. + +### Render +Render renders the file to the provided writer. + +```go +f := NewFile("a") +f.Func().Id("main").Params().Block() +buf := &bytes.Buffer{} +err := f.Render(buf) +if err != nil { + fmt.Println(err.Error()) +} else { + fmt.Println(buf.String()) +} +// Output: +// package a +// +// func main() {} +``` + +### Anon +Anon adds an anonymous import. + +```go +f := NewFile("c") +f.Anon("a") +f.Func().Id("init").Params().Block() +fmt.Printf("%#v", f) +// Output: +// package c +// +// import _ "a" +// +// func init() {} +``` + +### ImportName +ImportName provides the package name for a path. If specified, the alias will be omitted from the +import block. This is optional. If not specified, a sensible package name is used based on the path +and this is added as an alias in the import block. + +```go +f := NewFile("main") + +// package a should use name "a" +f.ImportName("github.com/foo/a", "a") + +// package b is not used in the code so will not be included +f.ImportName("github.com/foo/b", "b") + +f.Func().Id("main").Params().Block( + Qual("github.com/foo/a", "A").Call(), +) +fmt.Printf("%#v", f) + +// Output: +// package main +// +// import "github.com/foo/a" +// +// func main() { +// a.A() +// } +``` + +### ImportNames +ImportNames allows multiple names to be imported as a map. Use the [gennames](gennames) command to +automatically generate a go file containing a map of a selection of package names. + +### ImportAlias +ImportAlias provides the alias for a package path that should be used in the import block. A +period can be used to force a dot-import. + +```go +f := NewFile("main") + +// package a should be aliased to "b" +f.ImportAlias("github.com/foo/a", "b") + +// package c is not used in the code so will not be included +f.ImportAlias("github.com/foo/c", "c") + +f.Func().Id("main").Params().Block( + Qual("github.com/foo/a", "A").Call(), +) +fmt.Printf("%#v", f) + +// Output: +// package main +// +// import b "github.com/foo/a" +// +// func main() { +// b.A() +// } +``` + +### Comments +PackageComment adds a comment to the top of the file, above the package +keyword. + +HeaderComment adds a comment to the top of the file, above any package +comments. A blank line is rendered below the header comments, ensuring +header comments are not included in the package doc. + +CanonicalPath adds a canonical import path annotation to the package clause. + +```go +f := NewFile("c") +f.CanonicalPath = "d.e/f" +f.HeaderComment("Code generated by...") +f.PackageComment("Package c implements...") +f.Func().Id("init").Params().Block() +fmt.Printf("%#v", f) +// Output: +// // Code generated by... +// +// // Package c implements... +// package c // import "d.e/f" +// +// func init() {} +``` + +CgoPreamble adds a cgo preamble comment that is rendered directly before the "C" pseudo-package +import. + +### PackagePrefix +If you're worried about generated package aliases conflicting with local variable names, you +can set a prefix here. Package foo becomes {prefix}_foo. + +```go +f := NewFile("a") +f.PackagePrefix = "pkg" +f.Func().Id("main").Params().Block( + Qual("b.c/d", "E").Call(), +) +fmt.Printf("%#v", f) +// Output: +// package a +// +// import pkg_d "b.c/d" +// +// func main() { +// pkg_d.E() +// } +``` diff --git a/vendor/github.com/dave/jennifer/README.md.tpl b/vendor/github.com/dave/jennifer/README.md.tpl new file mode 100644 index 00000000..9000ca1d --- /dev/null +++ b/vendor/github.com/dave/jennifer/README.md.tpl @@ -0,0 +1,422 @@ +[![Build Status](https://travis-ci.org/dave/jennifer.svg?branch=master)](https://travis-ci.org/dave/jennifer) [![Go Report Card](https://goreportcard.com/badge/github.com/dave/jennifer)](https://goreportcard.com/report/github.com/dave/jennifer) [![codecov](https://img.shields.io/badge/codecov-100%25-brightgreen.svg)](https://codecov.io/gh/dave/jennifer) ![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg) [![Sourcegraph](https://sourcegraph.com/github.com/dave/jennifer/jen/-/badge.svg)](https://sourcegraph.com/github.com/dave/jennifer?badge) + +# Jennifer +Jennifer is a code generator for Go. + +```go +package main + +import ( + "fmt" + + . "github.com/dave/jennifer/jen" +) + +func main() {{ "ExampleNewFile" | code }} +``` +Output: +```go +{{ "ExampleNewFile" | output }} +``` + +### Install +``` +go get -u github.com/dave/jennifer/jen +``` + +### Need help? +If you get stuck, have a question, would like a code review, or just want a +chat: I'm happy to help! Feel free to open an issue, email me or mention @dave +in your PR. + +### Examples +Jennifer has a comprehensive suite of examples - see [godoc](https://godoc.org/github.com/dave/jennifer/jen#pkg-examples) for an index. Here's some examples of jennifer being used in the real-world: + +* [genjen](genjen/render.go) (which generates much of jennifer, using data in [data.go](genjen/data.go)) +* [zerogen](https://github.com/mrsinham/zerogen/blob/master/generator.go) +* [go-contentful-generator](https://github.com/nicolai86/go-contentful-generator) + +### Rendering +For testing, a File or Statement can be rendered with the fmt package +using the %#v verb. + +{{ "ExampleCall_fmt" | example }} + +This is not recommended for use in production because any error will cause a +panic. For production use, [File.Render](#render) or [File.Save](#save) are +preferred. + +# Identifiers +**Identifiers** [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Id +{{ "Id" | doc }} + +{{ "ExampleId" | example }} + +### Dot +{{ "Dot" | doc }} + +{{ "ExampleDot" | example }} + +### Qual +{{ "Qual[0]" | doc }} + +{{ "ExampleQual" | example }} + +{{ "Qual[1:4]" | doc }} + +{{ "ExampleQual_file" | example }} + +{{ "Qual[4:]" | doc }} + +### List +{{ "List" | doc }} + +{{ "ExampleList" | example }} + +# Keywords +[Identifiers](#identifiers) **Keywords** [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Simple keywords, predeclared identifiers and built-in functions are self +explanatory: + +| Construct | Name | +| ---------------- | ---- | +| Keywords | Break, Chan, Const, Continue, Default, Defer, Else, Fallthrough, Func, Go, Goto, Range, Select, Type, Var | +| Functions | Append, Cap, Close, Complex, Copy, Delete, Imag, Len, Make, New, Panic, Print, Println, Real, Recover | +| Types | Bool, Byte, Complex64, Complex128, Error, Float32, Float64, Int, Int8, Int16, Int32, Int64, Rune, String, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr | +| Constants | True, False, Iota, Nil | +| Helpers | Err | + +Built-in functions take a list of parameters and render them appropriately: + +{{ "ExampleAppend_more" | example }} + +Special cases for [If, For](#if-for), [Interface, Struct](#interface-struct), [Switch, Case](#switch-select), [Return](#return) and [Map](#map) are explained below. + +# Operators +[Identifiers](#identifiers) [Keywords](#keywords) **Operators** [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +{{ "Op" | doc }} + +{{ "ExampleOp" | example }} + +{{ "ExampleOp_star" | example }} + +{{ "ExampleOp_variadic" | example }} + +{{ "ExampleOp_complex_conditions" | example }} + +# Braces +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) **Braces** [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Several methods render curly braces, summarized below: + +| Name | Prefix | Separator | Example | +| ------------------------------ | ------------ | --------- | -------------------------------------| +| [Block](#block) | | `\n` | `func a() { ... }` or `if a { ... }` | +| [Interface](#interface-struct) | `interface` | `\n` | `interface { ... }` | +| [Struct](#interface-struct) | `struct` | `\n` | `struct { ... }` | +| [Values](#values) | | `,` | `[]int{1, 2}` or `A{B: "c"}` | + +### Block +{{ "Block[:2]" | doc }} + +{{ "ExampleBlock" | example }} + +{{ "ExampleBlock_if" | example }} + +{{ "Block[2:]" | doc }} [See example](#switch-select). + +### Interface, Struct +Interface and Struct render the keyword followed by a statement list enclosed +by curly braces. + +{{ "ExampleInterface_empty" | example }} + +{{ "ExampleInterface" | example }} + +{{ "ExampleStruct_empty" | example }} + +{{ "ExampleStruct" | example }} + +# Parentheses +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) **Parentheses** [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +Several methods output parenthesis, summarized below: + +| Name | Prefix | Separator | Example | +| ----------------- | ------ | --------- | --------------------------------- | +| [Call](#call) | | `,` | `fmt.Println(b, c)` | +| [Params](#params) | | `,` | `func (a *A) Foo(i int) { ... }` | +| [Defs](#defs) | | `\n` | `const ( ... )` | +| [Parens](#parens) | | | `[]byte(s)` or `a / (b + c)` | +| [Assert](#assert) | `.` | | `s, ok := i.(string)` | + +### Call +{{ "Call" | doc }} + +{{ "ExampleCall" | example }} + +### Params +{{ "Params" | doc }} + +{{ "ExampleParams" | example }} + +### Defs +{{ "Defs" | doc }} + +{{ "ExampleDefs" | example }} + +### Parens +{{ "Parens" | doc }} + +{{ "ExampleParens" | example }} + +{{ "ExampleParens_order" | example }} + +### Assert +{{ "Assert" | doc }} + +{{ "ExampleAssert" | example }} + +# Control flow +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) **Control flow** [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### If, For +If and For render the keyword followed by a semicolon separated list. + +{{ "ExampleIf" | example }} + +{{ "ExampleFor" | example }} + +### Switch, Select +Switch, Select, Case and Block are used to build switch or select statements: + +{{ "ExampleSwitch" | example }} + +### Return +{{ "Return" | doc }} + +{{ "ExampleReturn" | example }} + +# Collections +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) **Collections** [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Map +{{ "Map" | doc }} + +{{ "ExampleMap" | example }} + +### Index +{{ "Index" | doc }} + +{{ "ExampleIndex" | example }} + +{{ "ExampleIndex_index" | example }} + +{{ "ExampleIndex_empty" | example }} + +### Values +{{ "Values" | doc }} + +{{ "ExampleValues" | example }} + +{{ "Dict" | doc }} + +{{ "ExampleValues_dict_multiple" | example }} + +{{ "ExampleValues_dict_composite" | example }} + +{{ "DictFunc[0]" | doc }} + +{{ "ExampleDictFunc" | example }} + +Note: the items are ordered by key when rendered to ensure repeatable code. + +# Literals +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) **Literals** [Comments](#comments) [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Lit +{{ "Lit" | doc }} + +{{ "ExampleLit" | example }} + +{{ "ExampleLit_float" | example }} + +{{ "LitFunc[1:2]" | doc }} + +{{ "ExampleLitFunc" | example }} + +For the default constant types (bool, int, float64, string, complex128), Lit +will render the untyped constant. + +| Code | Output | +| ------------- | ---------- | +| `Lit(true)` | `true` | +| `Lit(1)` | `1` | +| `Lit(1.0)` | `1.0` | +| `Lit("foo")` | `"foo"` | +| `Lit(0 + 1i)` | `(0 + 1i)` | + +For all other built-in types (float32, int8, int16, int32, int64, uint, uint8, +uint16, uint32, uint64, uintptr, complex64), Lit will also render the type. + +| Code | Output | +| ------------------------ | ------------------- | +| `Lit(float32(1))` | `float32(1)` | +| `Lit(int16(1))` | `int16(1)` | +| `Lit(uint8(0x1))` | `uint8(0x1)` | +| `Lit(complex64(0 + 1i))` | `complex64(0 + 1i)` | + +The built-in alias types byte and rune need a special case. LitRune and LitByte +render rune and byte literals. + +| Code | Output | +| ------------------------ | ----------- | +| `LitRune('x')` | `'x'` | +| `LitByte(byte(0x1))` | `byte(0x1)` | + +# Comments +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) **Comments** [Helpers](#helpers) [Misc](#misc) [File](#file) + +### Comment +{{ "Comment[:2]" | doc }} + +{{ "ExampleComment" | example }} + +{{ "ExampleComment_multiline" | example }} + +{{ "Comment[2:]" | doc }} + +{{ "ExampleComment_formatting_disabled" | example }} + +### Commentf +{{ "Commentf[0]" | doc }} + +{{ "ExampleCommentf" | example }} + +# Helpers +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) **Helpers** [Misc](#misc) [File](#file) + +### Func methods +All constructs that accept a variadic list of items are paired with GroupFunc +functions that accept a func(*Group). Use for embedding logic. + +{{ "ExampleValuesFunc" | example }} + +{{ "ExampleBlockFunc" | example }} + +### Add +{{ "Add" | doc }} + +{{ "ExampleAdd" | example }} + +{{ "ExampleAdd_var" | example }} + +### Do +{{ "Do" | doc }} + +{{ "ExampleDo" | example }} + +# Misc +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) **Misc** [File](#file) + +### Tag +{{ "Tag" | doc }} + +{{ "ExampleTag" | example }} + +Note: the items are ordered by key when rendered to ensure repeatable code. + +### Null +{{ "Null" | doc }} + +In lists, nil will produce the same effect. + +{{ "ExampleNull_and_nil" | example }} + +### Empty +{{ "Empty" | doc }} + +{{ "ExampleEmpty" | example }} + +### Line +{{ "Line" | doc }} + +### Clone +Be careful when passing *Statement. Consider the following... + +{{ "ExampleStatement_Clone_broken" | example }} + +Id("a") returns a *Statement, which the Call() method appends to twice. To +avoid this, use Clone. {{ "Statement.Clone" | doc }} + +{{ "ExampleStatement_Clone_fixed" | example }} + +### Cgo +The cgo "C" pseudo-package is a special case, and always renders without a package alias. The +import can be added with `Qual`, `Anon` or by supplying a preamble. The preamble is added with +`File.CgoPreamble` which has the same semantics as [Comment](#comments). If a preamble is provided, +the import is separated, and preceded by the preamble. + +{{ "ExampleFile_CgoPreamble" | example }} + +# File +[Identifiers](#identifiers) [Keywords](#keywords) [Operators](#operators) [Braces](#braces) [Parentheses](#parentheses) [Control flow](#control-flow) [Collections](#collections) [Literals](#literals) [Comments](#comments) [Helpers](#helpers) [Misc](#misc) **File** + +{{ "File" | doc }} + +### NewFile +{{ "NewFile" | doc }} + +### NewFilePath +{{ "NewFilePath" | doc }} + +### NewFilePathName +{{ "NewFilePathName" | doc }} + +{{ "ExampleNewFilePathName" | example }} + +### Save +{{ "File.Save" | doc }} + +### Render +{{ "File.Render" | doc }} + +{{ "ExampleFile_Render" | example }} + +### Anon +{{ "File.Anon" | doc }} + +{{ "ExampleFile_Anon" | example }} + +### ImportName +{{ "File.ImportName" | doc }} + +{{ "ExampleFile_ImportName" | example }} + +### ImportNames +{{ "File.ImportNames" | doc }} + +### ImportAlias +{{ "File.ImportAlias" | doc }} + +{{ "ExampleFile_ImportAlias" | example }} + +### Comments +{{ "File.PackageComment" | doc }} + +{{ "File.HeaderComment" | doc }} + +{{ "File.CanonicalPath" | doc }} + +{{ "ExampleFile_HeaderAndPackageComments" | example }} + +{{ "File.CgoPreamble" | doc }} + +### PackagePrefix +{{ "File.PackagePrefix" | doc }} + +{{ "ExampleFile_PackagePrefix" | example }} diff --git a/vendor/github.com/dave/jennifer/genjen/data.go b/vendor/github.com/dave/jennifer/genjen/data.go new file mode 100644 index 00000000..ff8b39a7 --- /dev/null +++ b/vendor/github.com/dave/jennifer/genjen/data.go @@ -0,0 +1,307 @@ +package main + +var keywords = []string{"break", "default", "func", "select", "chan", "else", "const", "fallthrough", "type", "continue", "var", "goto", "defer", "go", "range"} + +var identifiers = []string{"bool", "byte", "complex64", "complex128", "error", "float32", "float64", "int", "int8", "int16", "int32", "int64", "rune", "string", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "true", "false", "iota", "nil", "err"} + +var groups = []struct { + name string // name of the function / method + comment string // comment appended to name + variadic bool // is the parameter variadic? + opening string // opening token + closing string // closing token + separator string // separator token + multi bool // items are always on multiple lines + parameters []string // parameter names + preventFunc bool // prevent the fooFunc function/method +}{ + { + name: "Parens", + comment: "renders a single item in parenthesis. Use for type conversion or to specify evaluation order.", + variadic: false, + opening: "(", + closing: ")", + separator: "", + parameters: []string{"item"}, + }, + { + name: "List", + comment: "renders a comma separated list. Use for multiple return functions.", + variadic: true, + opening: "", + closing: "", + separator: ",", + parameters: []string{"items"}, + }, + { + name: "Values", + comment: "renders a comma separated list enclosed by curly braces. Use for slice or composite literals.", + variadic: true, + opening: "{", + closing: "}", + separator: ",", + parameters: []string{"values"}, + }, + { + name: "Index", + comment: "renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions.", + variadic: true, + opening: "[", + closing: "]", + separator: ":", + parameters: []string{"items"}, + }, + { + name: "Block", + comment: "renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements.", + variadic: true, + opening: "{", + closing: "}", + multi: true, + parameters: []string{"statements"}, + }, + { + name: "Defs", + comment: "renders a statement list enclosed in parenthesis. Use for definition lists.", + variadic: true, + opening: "(", + closing: ")", + multi: true, + parameters: []string{"definitions"}, + }, + { + name: "Call", + comment: "renders a comma separated list enclosed by parenthesis. Use for function calls.", + variadic: true, + opening: "(", + closing: ")", + separator: ",", + parameters: []string{"params"}, + }, + { + name: "Params", + comment: "renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers.", + variadic: true, + opening: "(", + closing: ")", + separator: ",", + parameters: []string{"params"}, + }, + { + name: "Assert", + comment: "renders a period followed by a single item enclosed by parenthesis. Use for type assertions.", + variadic: false, + opening: ".(", + closing: ")", + separator: "", + parameters: []string{"typ"}, + }, + { + name: "Map", + comment: "renders the keyword followed by a single item enclosed by square brackets. Use for map definitions.", + variadic: false, + opening: "map[", + closing: "]", + separator: "", + parameters: []string{"typ"}, + }, + { + name: "If", + comment: "renders the keyword followed by a semicolon separated list.", + variadic: true, + opening: "if ", + closing: "", + separator: ";", + parameters: []string{"conditions"}, + }, + { + name: "Return", + comment: "renders the keyword followed by a comma separated list.", + variadic: true, + opening: "return ", + closing: "", + separator: ",", + parameters: []string{"results"}, + }, + { + name: "For", + comment: "renders the keyword followed by a semicolon separated list.", + variadic: true, + opening: "for ", + closing: "", + separator: ";", + parameters: []string{"conditions"}, + }, + { + name: "Switch", + comment: "renders the keyword followed by a semicolon separated list.", + variadic: true, + opening: "switch ", + closing: "", + separator: ";", + parameters: []string{"conditions"}, + }, + { + name: "Interface", + comment: "renders the keyword followed by a method list enclosed by curly braces.", + variadic: true, + opening: "interface{", + closing: "}", + multi: true, + parameters: []string{"methods"}, + }, + { + name: "Struct", + comment: "renders the keyword followed by a field list enclosed by curly braces.", + variadic: true, + opening: "struct{", + closing: "}", + multi: true, + parameters: []string{"fields"}, + }, + { + name: "Case", + comment: "renders the keyword followed by a comma separated list.", + variadic: true, + opening: "case ", + closing: ":", + separator: ",", + parameters: []string{"cases"}, + }, + { + name: "Append", + comment: "renders the append built-in function.", + variadic: true, + opening: "append(", + closing: ")", + separator: ",", + parameters: []string{"args"}, + }, + { + name: "Cap", + comment: "renders the cap built-in function.", + variadic: false, + opening: "cap(", + closing: ")", + separator: ",", + parameters: []string{"v"}, + }, + { + name: "Close", + comment: "renders the close built-in function.", + variadic: false, + opening: "close(", + closing: ")", + separator: ",", + parameters: []string{"c"}, + }, + { + name: "Complex", + comment: "renders the complex built-in function.", + variadic: false, + opening: "complex(", + closing: ")", + separator: ",", + parameters: []string{"r", "i"}, + }, + { + name: "Copy", + comment: "renders the copy built-in function.", + variadic: false, + opening: "copy(", + closing: ")", + separator: ",", + parameters: []string{"dst", "src"}, + }, + { + name: "Delete", + comment: "renders the delete built-in function.", + variadic: false, + opening: "delete(", + closing: ")", + separator: ",", + parameters: []string{"m", "key"}, + }, + { + name: "Imag", + comment: "renders the imag built-in function.", + variadic: false, + opening: "imag(", + closing: ")", + separator: ",", + parameters: []string{"c"}, + }, + { + name: "Len", + comment: "renders the len built-in function.", + variadic: false, + opening: "len(", + closing: ")", + separator: ",", + parameters: []string{"v"}, + }, + { + name: "Make", + comment: "renders the make built-in function. The final parameter of the make function is optional, so it is represented by a variadic parameter list.", + variadic: true, + opening: "make(", + closing: ")", + separator: ",", + parameters: []string{"args"}, + preventFunc: true, // the underlying function is not variadic, so we prevent the MakeFunc variation + }, + { + name: "New", + comment: "renders the new built-in function.", + variadic: false, + opening: "new(", + closing: ")", + separator: ",", + parameters: []string{"typ"}, + }, + { + name: "Panic", + comment: "renders the panic built-in function.", + variadic: false, + opening: "panic(", + closing: ")", + separator: ",", + parameters: []string{"v"}, + }, + { + name: "Print", + comment: "renders the print built-in function.", + variadic: true, + opening: "print(", + closing: ")", + separator: ",", + parameters: []string{"args"}, + }, + { + name: "Println", + comment: "renders the println built-in function.", + variadic: true, + opening: "println(", + closing: ")", + separator: ",", + parameters: []string{"args"}, + }, + { + name: "Real", + comment: "renders the real built-in function.", + variadic: false, + opening: "real(", + closing: ")", + separator: ",", + parameters: []string{"c"}, + }, + { + name: "Recover", + comment: "renders the recover built-in function.", + variadic: false, + opening: "recover(", + closing: ")", + separator: ",", + parameters: []string{}, + }, +} diff --git a/vendor/github.com/dave/jennifer/genjen/main.go b/vendor/github.com/dave/jennifer/genjen/main.go new file mode 100644 index 00000000..ff73434c --- /dev/null +++ b/vendor/github.com/dave/jennifer/genjen/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "bytes" + "io/ioutil" +) + +func main() { + // notest + buf := &bytes.Buffer{} + if err := render(buf); err != nil { + panic(err) + } + if err := ioutil.WriteFile("./jen/generated.go", buf.Bytes(), 0644); err != nil { + panic(err) + } +} diff --git a/vendor/github.com/dave/jennifer/genjen/render.go b/vendor/github.com/dave/jennifer/genjen/render.go new file mode 100644 index 00000000..3ab0e93a --- /dev/null +++ b/vendor/github.com/dave/jennifer/genjen/render.go @@ -0,0 +1,260 @@ +package main + +import ( + "io" + "strings" + + . "github.com/dave/jennifer/jen" +) + +func render(w io.Writer) error { + file := NewFile("jen") + + file.HeaderComment("This file is generated - do not edit.") + file.Line() + + for _, b := range groups { + b := b // b used in closures + comment := Commentf("%s %s", b.name, b.comment) + + if b.variadic && len(b.parameters) > 1 { + panic("should not have variadic function with multiple params") + } + + var variadic Code + if b.variadic { + variadic = Op("...") + } + var funcParams []Code + var callParams []Code + for _, name := range b.parameters { + funcParams = append(funcParams, Id(name).Add(variadic).Id("Code")) + callParams = append(callParams, Id(name).Add(variadic)) + } + + addFunctionAndGroupMethod( + file, + b.name, + comment, + funcParams, + callParams, + false, + ) + + /* + // + func (s *Statement) () *Statement { + g := &Group{ + items: []Code{}|, + name: "", + open: "", + close: "", + separator: "", + multi: , + } + *s = append(*s, g) + return s + } + */ + file.Add(comment) + file.Func().Params( + Id("s").Op("*").Id("Statement"), + ).Id(b.name).Params( + funcParams..., + ).Op("*").Id("Statement").Block( + Id("g").Op(":=").Op("&").Id("Group").Values(Dict{ + Id("items"): Do(func(s *Statement) { + if b.variadic { + s.Id(b.parameters[0]) + } else { + s.Index().Id("Code").ValuesFunc(func(g *Group) { + for _, name := range b.parameters { + g.Id(name) + } + }) + } + }), + Id("name"): Lit(strings.ToLower(b.name)), + Id("open"): Lit(b.opening), + Id("close"): Lit(b.closing), + Id("separator"): Lit(b.separator), + Id("multi"): Lit(b.multi), + }), + Op("*").Id("s").Op("=").Append(Op("*").Id("s"), Id("g")), + Return(Id("s")), + ) + + if b.variadic && !b.preventFunc { + + funcName := b.name + "Func" + funcComment := Commentf("%sFunc %s", b.name, b.comment) + funcFuncParams := []Code{Id("f").Func().Params(Op("*").Id("Group"))} + funcCallParams := []Code{Id("f")} + + addFunctionAndGroupMethod( + file, + funcName, + funcComment, + funcFuncParams, + funcCallParams, + false, + ) + + /* + // + func (s *Statement) (f func(*Group)) *Statement { + g := &Group{ + name: "", + open: "", + close: "", + separator: "", + multi: , + } + f(g) + *s = append(*s, g) + return s + } + */ + file.Add(funcComment) + file.Func().Params( + Id("s").Op("*").Id("Statement"), + ).Id(funcName).Params( + funcFuncParams..., + ).Op("*").Id("Statement").Block( + Id("g").Op(":=").Op("&").Id("Group").Values(Dict{ + Id("name"): Lit(strings.ToLower(b.name)), + Id("open"): Lit(b.opening), + Id("close"): Lit(b.closing), + Id("separator"): Lit(b.separator), + Id("multi"): Lit(b.multi), + }), + Id("f").Call(Id("g")), + Op("*").Id("s").Op("=").Append(Op("*").Id("s"), Id("g")), + Return(Id("s")), + ) + } + } + + type tkn struct { + token string + name string + tokenType string + tokenDesc string + } + tokens := []tkn{} + for _, v := range identifiers { + tokens = append(tokens, tkn{ + token: v, + name: strings.ToUpper(v[:1]) + v[1:], + tokenType: "identifierToken", + tokenDesc: "identifier", + }) + } + for _, v := range keywords { + tokens = append(tokens, tkn{ + token: v, + name: strings.ToUpper(v[:1]) + v[1:], + tokenType: "keywordToken", + tokenDesc: "keyword", + }) + } + + for i, t := range tokens { + t := t // used in closures + comment := Commentf( + "%s renders the %s %s.", + t.name, + t.token, + t.tokenDesc, + ) + addFunctionAndGroupMethod( + file, + t.name, + comment, + nil, + nil, + i != 0, // only enforce test coverage on one item + ) + + /* + // + func (s *Statement) () *Statement { + t := token{ + typ: , + content: "", + } + *s = append(*s, t) + return s + } + */ + file.Add(comment) + file.Func().Params( + Id("s").Op("*").Id("Statement"), + ).Id(t.name).Params().Op("*").Id("Statement").Block( + Do(func(s *Statement) { + if i != 0 { + // only enforce test coverage on one item + s.Comment("notest") + } + }), + Id("t").Op(":=").Id("token").Values(Dict{ + Id("typ"): Id(t.tokenType), + Id("content"): Lit(t.token), + }), + Op("*").Id("s").Op("=").Append(Op("*").Id("s"), Id("t")), + Return(Id("s")), + ) + } + + return file.Render(w) +} + +// For each method on *Statement, this generates a package level +// function and a method on *Group, both with the same name. +func addFunctionAndGroupMethod( + file *File, + name string, + comment *Statement, + funcParams []Code, + callParams []Code, + notest bool, +) { + /* + // + func () *Statement { + return newStatement().() + } + */ + file.Add(comment) + file.Func().Id(name).Params(funcParams...).Op("*").Id("Statement").Block( + Do(func(s *Statement) { + if notest { + // only enforce test coverage on one item + s.Comment("notest") + } + }), + Return(Id("newStatement").Call().Dot(name).Call(callParams...)), + ) + /* + // + func (g *Group) () *Statement { + s := () + g.items = append(g.items, s) + return s + } + */ + file.Add(comment) + file.Func().Params( + Id("g").Op("*").Id("Group"), + ).Id(name).Params(funcParams...).Op("*").Id("Statement").Block( + Do(func(s *Statement) { + if notest { + // only enforce test coverage on one item + s.Comment("notest") + } + }), + Id("s").Op(":=").Id(name).Params(callParams...), + Id("g").Dot("items").Op("=").Append(Id("g").Dot("items"), Id("s")), + Return(Id("s")), + ) +} diff --git a/vendor/github.com/dave/jennifer/genjen/render_test.go b/vendor/github.com/dave/jennifer/genjen/render_test.go new file mode 100644 index 00000000..2b549d91 --- /dev/null +++ b/vendor/github.com/dave/jennifer/genjen/render_test.go @@ -0,0 +1,35 @@ +package main + +import ( + "io/ioutil" + "regexp" + "testing" + + "bytes" +) + +func TestRender(t *testing.T) { + + buf := &bytes.Buffer{} + if err := render(buf); err != nil { + t.Fatal(err.Error()) + } + generatedString := buf.String() + + existingFilePath := "../jen/generated.go" + existingBytes, err := ioutil.ReadFile(existingFilePath) + if err != nil { + t.Fatal(err.Error()) + } + existingString := string(existingBytes) + + // The "goimports" tool will often re-order the imports, so this is a + // kludge to remove it before comparing. This is not ideal! + importsRegex := regexp.MustCompile(`(?ms:\nimport \(\n.*\n\)\n)`) + generatedString = importsRegex.ReplaceAllString(generatedString, "-") + existingString = importsRegex.ReplaceAllString(existingString, "-") + + if generatedString != existingString { + t.Fatalf("Generated code is not what is present:\n%s", generatedString) + } +} diff --git a/vendor/github.com/dave/jennifer/gennames/README.md b/vendor/github.com/dave/jennifer/gennames/README.md new file mode 100644 index 00000000..ef60cfe0 --- /dev/null +++ b/vendor/github.com/dave/jennifer/gennames/README.md @@ -0,0 +1,52 @@ +# gennames +For large projects, it may be useful to generate an index of package names for commonly used packages. +The index of names can be added to each generated file using `File.ImportNames`. The `gennames` command +is used internally to generate the list of standard library package names. + +### Usage + +``` +Usage of gennames: + -filter string + Regex to filter paths (operates on full path including vendor directory) (default ".*") + -name string + Name of the variable to define (default "PackageNames") + -novendor + Exclude packages in vendor directories + -output string + Output filename to write (default "./package-names.go") + -package string + Package name in generated file (default "main") + -path string + Path to pass to go list command (default "all") + -standard + Use standard library packages +``` + +### Path +Supply a `path` to pass to the `go list` command. You may use the wildcard `/...` to recursively return +packages, but it's worth remembering that vendored packages are not returned by this method unless the +path itself is a vendored path. Use `all` to return all packages in your `GOPATH` (including vendored +packages), however remember this may take some time for a large `GOPATH`. + +### Filter +Supply a regex `filter` to limit the packages that are returned by the `go list` command. The filter +operates on the full vendored package path (e.g. `github.com/foo/bar/vendor/github.com/baz/qux`), however +the package path added to the index is unvendored (e.g. `github.com/baz/qux`). + +### Examples + +``` +gennames -filter "foo|bar" +``` + +Create a file named `package-names.go` with `package main` listing the names of all packages with paths +containing `foo` or `bar`. + +``` +gennames -output "foo/names.go" -package "foo" -path "github.com/foo/bar/vendor/..." +``` + +Create a file named `foo/names.go` with `package foo` listing the names of all packages that are vendored +inside `github.com/foo/bar`. + diff --git a/vendor/github.com/dave/jennifer/gennames/hints.go b/vendor/github.com/dave/jennifer/gennames/hints.go new file mode 100644 index 00000000..51288f1e --- /dev/null +++ b/vendor/github.com/dave/jennifer/gennames/hints.go @@ -0,0 +1,141 @@ +package main + +import ( + "fmt" + "go/build" + "io" + "os/exec" + "strings" + + "regexp" + + "path/filepath" + + . "github.com/dave/jennifer/jen" +) + +func hints(w io.Writer, pkg, name, goListPath, filter string, standard, novendor bool) error { + + // notest + + file := NewFile(pkg) + + file.HeaderComment("This file is generated - do not edit.") + file.Line() + + packages, err := getPackages(goListPath, filter, standard, novendor) + if err != nil { + return err + } + /* + // contains package name hints + var = map[string]string{ + ... + } + */ + file.Commentf("%s contains package name hints", name) + file.Var().Id(name).Op("=").Map(String()).String().Values(DictFunc(func(d Dict) { + for path, name := range packages { + d[Lit(path)] = Lit(name) + } + })) + + return file.Render(w) +} + +func getPackages(goListPath, filter string, standard, novendor bool) (map[string]string, error) { + + // notest + + r, err := regexp.Compile(filter) + if err != nil { + return nil, err + } + + cmd := exec.Command("go", "list", "-e", "-f", "{{ .Standard }} {{ .ImportPath }} {{ .Name }}", goListPath) + cmd.Env = []string{ + fmt.Sprintf("GOPATH=%s", build.Default.GOPATH), + fmt.Sprintf("GOROOT=%s", build.Default.GOROOT), + } + if standard { + cmd.Dir = filepath.Join(build.Default.GOROOT, "src") + } else { + cmd.Dir = filepath.Join(build.Default.GOPATH, "src") + } + b, err := cmd.Output() + if err != nil { + if x, ok := err.(*exec.ExitError); ok { + return nil, fmt.Errorf("go list command returned an error - %s: %s", err.Error(), string(x.Stderr)) + } + return nil, fmt.Errorf("go list command returned an error: %s", err.Error()) + } + all := strings.Split(strings.TrimSpace(string(b)), "\n") + + packages := map[string]string{} + for _, j := range all { + + parts := strings.Split(j, " ") + + isStandard := parts[0] == "true" + if isStandard != standard { + continue + } + + path := parts[1] + name := parts[2] + + if novendor && hasVendor(path) { + continue + } + + if name == "main" { + continue + } + + if !r.MatchString(path) { + continue + } + + path = unvendorPath(path) + + if packages[path] != "" { + continue + } + + packages[path] = name + } + return packages, nil +} + +func unvendorPath(path string) string { + // notest + i, ok := findVendor(path) + if !ok { + return path + } + return path[i+len("vendor/"):] +} + +// FindVendor looks for the last non-terminating "vendor" path element in the given import path. +// If there isn't one, FindVendor returns ok=false. +// Otherwise, FindVendor returns ok=true and the index of the "vendor". +// Copied from cmd/go/internal/load +func findVendor(path string) (index int, ok bool) { + // notest + // Two cases, depending on internal at start of string or not. + // The order matters: we must return the index of the final element, + // because the final one is where the effective import path starts. + switch { + case strings.Contains(path, "/vendor/"): + return strings.LastIndex(path, "/vendor/") + 1, true + case strings.HasPrefix(path, "vendor/"): + return 0, true + } + return 0, false +} + +func hasVendor(path string) bool { + // notest + _, v := findVendor(path) + return v +} diff --git a/vendor/github.com/dave/jennifer/gennames/main.go b/vendor/github.com/dave/jennifer/gennames/main.go new file mode 100644 index 00000000..1ff8e51a --- /dev/null +++ b/vendor/github.com/dave/jennifer/gennames/main.go @@ -0,0 +1,29 @@ +package main + +import ( + "bytes" + "flag" + "io/ioutil" + "log" +) + +func main() { + // notest + + var out = flag.String("output", "./package-names.go", "Output filename to write") + var pkg = flag.String("package", "main", "Package name in generated file") + var name = flag.String("name", "PackageNames", "Name of the variable to define") + var filter = flag.String("filter", ".*", "Regex to filter paths (operates on full path including vendor directory)") + var standard = flag.Bool("standard", false, "Use standard library packages") + var novendor = flag.Bool("novendor", false, "Exclude packages in vendor directories") + var goListPath = flag.String("path", "all", "Path to pass to go list command") + flag.Parse() + + buf := &bytes.Buffer{} + if err := hints(buf, *pkg, *name, *goListPath, *filter, *standard, *novendor); err != nil { + log.Fatal(err.Error()) + } + if err := ioutil.WriteFile(*out, buf.Bytes(), 0644); err != nil { + log.Fatal(err.Error()) + } +} diff --git a/vendor/github.com/dave/jennifer/jen/add.go b/vendor/github.com/dave/jennifer/jen/add.go new file mode 100644 index 00000000..2efb3f6d --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/add.go @@ -0,0 +1,19 @@ +package jen + +// Add appends the provided items to the statement. +func Add(code ...Code) *Statement { + return newStatement().Add(code...) +} + +// Add appends the provided items to the statement. +func (g *Group) Add(code ...Code) *Statement { + s := Add(code...) + g.items = append(g.items, s) + return s +} + +// Add appends the provided items to the statement. +func (s *Statement) Add(code ...Code) *Statement { + *s = append(*s, code...) + return s +} diff --git a/vendor/github.com/dave/jennifer/jen/comments.go b/vendor/github.com/dave/jennifer/jen/comments.go new file mode 100644 index 00000000..886e885b --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/comments.go @@ -0,0 +1,108 @@ +package jen + +import ( + "fmt" + "io" + "strings" +) + +// Comment adds a comment. If the provided string contains a newline, the +// comment is formatted in multiline style. If the comment string starts +// with "//" or "/*", the automatic formatting is disabled and the string is +// rendered directly. +func Comment(str string) *Statement { + return newStatement().Comment(str) +} + +// Comment adds a comment. If the provided string contains a newline, the +// comment is formatted in multiline style. If the comment string starts +// with "//" or "/*", the automatic formatting is disabled and the string is +// rendered directly. +func (g *Group) Comment(str string) *Statement { + s := Comment(str) + g.items = append(g.items, s) + return s +} + +// Comment adds a comment. If the provided string contains a newline, the +// comment is formatted in multiline style. If the comment string starts +// with "//" or "/*", the automatic formatting is disabled and the string is +// rendered directly. +func (s *Statement) Comment(str string) *Statement { + c := comment{ + comment: str, + } + *s = append(*s, c) + return s +} + +// Commentf adds a comment, using a format string and a list of parameters. If +// the provided string contains a newline, the comment is formatted in +// multiline style. If the comment string starts with "//" or "/*", the +// automatic formatting is disabled and the string is rendered directly. +func Commentf(format string, a ...interface{}) *Statement { + return newStatement().Commentf(format, a...) +} + +// Commentf adds a comment, using a format string and a list of parameters. If +// the provided string contains a newline, the comment is formatted in +// multiline style. If the comment string starts with "//" or "/*", the +// automatic formatting is disabled and the string is rendered directly. +func (g *Group) Commentf(format string, a ...interface{}) *Statement { + s := Commentf(format, a...) + g.items = append(g.items, s) + return s +} + +// Commentf adds a comment, using a format string and a list of parameters. If +// the provided string contains a newline, the comment is formatted in +// multiline style. If the comment string starts with "//" or "/*", the +// automatic formatting is disabled and the string is rendered directly. +func (s *Statement) Commentf(format string, a ...interface{}) *Statement { + c := comment{ + comment: fmt.Sprintf(format, a...), + } + *s = append(*s, c) + return s +} + +type comment struct { + comment string +} + +func (c comment) isNull(f *File) bool { + return false +} + +func (c comment) render(f *File, w io.Writer, s *Statement) error { + if strings.HasPrefix(c.comment, "//") || strings.HasPrefix(c.comment, "/*") { + // automatic formatting disabled. + if _, err := w.Write([]byte(c.comment)); err != nil { + return err + } + return nil + } + if strings.Contains(c.comment, "\n") { + if _, err := w.Write([]byte("/*\n")); err != nil { + return err + } + } else { + if _, err := w.Write([]byte("// ")); err != nil { + return err + } + } + if _, err := w.Write([]byte(c.comment)); err != nil { + return err + } + if strings.Contains(c.comment, "\n") { + if !strings.HasSuffix(c.comment, "\n") { + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + } + if _, err := w.Write([]byte("*/")); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/dave/jennifer/jen/custom.go b/vendor/github.com/dave/jennifer/jen/custom.go new file mode 100644 index 00000000..4966a070 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/custom.go @@ -0,0 +1,61 @@ +package jen + +// Options specifies options for the Custom method +type Options struct { + Open string + Close string + Separator string + Multi bool +} + +// Custom renders a customized statement list. Pass in options to specify multi-line, and tokens for open, close, separator. +func Custom(options Options, statements ...Code) *Statement { + return newStatement().Custom(options, statements...) +} + +// Custom renders a customized statement list. Pass in options to specify multi-line, and tokens for open, close, separator. +func (g *Group) Custom(options Options, statements ...Code) *Statement { + s := Custom(options, statements...) + g.items = append(g.items, s) + return s +} + +// Custom renders a customized statement list. Pass in options to specify multi-line, and tokens for open, close, separator. +func (s *Statement) Custom(options Options, statements ...Code) *Statement { + g := &Group{ + close: options.Close, + items: statements, + multi: options.Multi, + name: "custom", + open: options.Open, + separator: options.Separator, + } + *s = append(*s, g) + return s +} + +// CustomFunc renders a customized statement list. Pass in options to specify multi-line, and tokens for open, close, separator. +func CustomFunc(options Options, f func(*Group)) *Statement { + return newStatement().CustomFunc(options, f) +} + +// CustomFunc renders a customized statement list. Pass in options to specify multi-line, and tokens for open, close, separator. +func (g *Group) CustomFunc(options Options, f func(*Group)) *Statement { + s := CustomFunc(options, f) + g.items = append(g.items, s) + return s +} + +// CustomFunc renders a customized statement list. Pass in options to specify multi-line, and tokens for open, close, separator. +func (s *Statement) CustomFunc(options Options, f func(*Group)) *Statement { + g := &Group{ + close: options.Close, + multi: options.Multi, + name: "custom", + open: options.Open, + separator: options.Separator, + } + f(g) + *s = append(*s, g) + return s +} diff --git a/vendor/github.com/dave/jennifer/jen/dict.go b/vendor/github.com/dave/jennifer/jen/dict.go new file mode 100644 index 00000000..260cf928 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/dict.go @@ -0,0 +1,81 @@ +package jen + +import ( + "bytes" + "io" + "sort" +) + +// Dict renders as key/value pairs. Use with Values for map or composite +// literals. +type Dict map[Code]Code + +// DictFunc executes a func(Dict) to generate the value. Use with Values for +// map or composite literals. +func DictFunc(f func(Dict)) Dict { + d := Dict{} + f(d) + return d +} + +func (d Dict) render(f *File, w io.Writer, s *Statement) error { + first := true + // must order keys to ensure repeatable source + type kv struct { + k Code + v Code + } + lookup := map[string]kv{} + keys := []string{} + for k, v := range d { + if k.isNull(f) || v.isNull(f) { + continue + } + buf := &bytes.Buffer{} + if err := k.render(f, buf, nil); err != nil { + return err + } + keys = append(keys, buf.String()) + lookup[buf.String()] = kv{k: k, v: v} + } + sort.Strings(keys) + for _, key := range keys { + k := lookup[key].k + v := lookup[key].v + if first && len(keys) > 1 { + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + first = false + } + if err := k.render(f, w, nil); err != nil { + return err + } + if _, err := w.Write([]byte(":")); err != nil { + return err + } + if err := v.render(f, w, nil); err != nil { + return err + } + if len(keys) > 1 { + if _, err := w.Write([]byte(",\n")); err != nil { + return err + } + } + } + return nil +} + +func (d Dict) isNull(f *File) bool { + if d == nil || len(d) == 0 { + return true + } + for k, v := range d { + if !k.isNull(f) && !v.isNull(f) { + // if any of the key/value pairs are both not null, the Dict is not + // null + return false + } + } + return true +} diff --git a/vendor/github.com/dave/jennifer/jen/do.go b/vendor/github.com/dave/jennifer/jen/do.go new file mode 100644 index 00000000..c1bceab5 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/do.go @@ -0,0 +1,22 @@ +package jen + +// Do calls the provided function with the statement as a parameter. Use for +// embedding logic. +func Do(f func(*Statement)) *Statement { + return newStatement().Do(f) +} + +// Do calls the provided function with the statement as a parameter. Use for +// embedding logic. +func (g *Group) Do(f func(*Statement)) *Statement { + s := Do(f) + g.items = append(g.items, s) + return s +} + +// Do calls the provided function with the statement as a parameter. Use for +// embedding logic. +func (s *Statement) Do(f func(*Statement)) *Statement { + f(s) + return s +} diff --git a/vendor/github.com/dave/jennifer/jen/examples_test.go b/vendor/github.com/dave/jennifer/jen/examples_test.go new file mode 100644 index 00000000..d6316b5f --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/examples_test.go @@ -0,0 +1,1610 @@ +package jen_test + +import ( + "fmt" + + "bytes" + + . "github.com/dave/jennifer/jen" +) + +func ExampleCaseBug() { + c := Switch(Id("a")).Block( + Case(Lit(1)).Block( + Var().Id("i").Int(), + Var().Id("j").Int(), + ), + ) + fmt.Printf("%#v", c) + // Output: + // switch a { + // case 1: + // var i int + // var j int + // } +} + +func ExampleCustom() { + multiLineCall := Options{ + Close: ")", + Multi: true, + Open: "(", + Separator: ",", + } + c := Id("foo").Custom(multiLineCall, Lit("a"), Lit("b"), Lit("c")) + fmt.Printf("%#v", c) + // Output: + // foo( + // "a", + // "b", + // "c", + // ) +} + +func ExampleCustomFunc() { + multiLineCall := Options{ + Close: ")", + Multi: true, + Open: "(", + Separator: ",", + } + c := Id("foo").CustomFunc(multiLineCall, func(g *Group) { + g.Lit("a") + g.Lit("b") + g.Lit("c") + }) + fmt.Printf("%#v", c) + // Output: + // foo( + // "a", + // "b", + // "c", + // ) +} + +func ExampleFile_ImportName_conflict() { + f := NewFile("main") + + // We provide a hint that package foo/a should use name "a", but because package bar/a already + // registers the required name, foo/a is aliased. + f.ImportName("github.com/foo/a", "a") + + f.Func().Id("main").Params().Block( + Qual("github.com/bar/a", "Bar").Call(), + Qual("github.com/foo/a", "Foo").Call(), + ) + fmt.Printf("%#v", f) + + // Output: + // package main + // + // import ( + // a "github.com/bar/a" + // a1 "github.com/foo/a" + // ) + // + // func main() { + // a.Bar() + // a1.Foo() + // } +} + +func ExampleFile_ImportAlias_conflict() { + f := NewFile("main") + + // We provide a hint that package foo/a should use alias "b", but because package bar/b already + // registers the required name, foo/a is aliased using the requested alias as a base. + f.ImportName("github.com/foo/a", "b") + + f.Func().Id("main").Params().Block( + Qual("github.com/bar/b", "Bar").Call(), + Qual("github.com/foo/a", "Foo").Call(), + ) + fmt.Printf("%#v", f) + + // Output: + // package main + // + // import ( + // b "github.com/bar/b" + // b1 "github.com/foo/a" + // ) + // + // func main() { + // b.Bar() + // b1.Foo() + // } +} + +func ExampleFile_ImportName() { + f := NewFile("main") + + // package a should use name "a" + f.ImportName("github.com/foo/a", "a") + + // package b is not used in the code so will not be included + f.ImportName("github.com/foo/b", "b") + + f.Func().Id("main").Params().Block( + Qual("github.com/foo/a", "A").Call(), + ) + fmt.Printf("%#v", f) + + // Output: + // package main + // + // import "github.com/foo/a" + // + // func main() { + // a.A() + // } +} + +func ExampleFile_ImportNames() { + + // package a should use name "a", package b is not used in the code so will not be included + names := map[string]string{ + "github.com/foo/a": "a", + "github.com/foo/b": "b", + } + + f := NewFile("main") + f.ImportNames(names) + f.Func().Id("main").Params().Block( + Qual("github.com/foo/a", "A").Call(), + ) + fmt.Printf("%#v", f) + + // Output: + // package main + // + // import "github.com/foo/a" + // + // func main() { + // a.A() + // } +} + +func ExampleFile_ImportAlias() { + f := NewFile("main") + + // package a should be aliased to "b" + f.ImportAlias("github.com/foo/a", "b") + + // package c is not used in the code so will not be included + f.ImportAlias("github.com/foo/c", "c") + + f.Func().Id("main").Params().Block( + Qual("github.com/foo/a", "A").Call(), + ) + fmt.Printf("%#v", f) + + // Output: + // package main + // + // import b "github.com/foo/a" + // + // func main() { + // b.A() + // } +} + +func ExampleFile_ImportAliasDot() { + f := NewFile("main") + + // package a should be a dot-import + f.ImportAlias("github.com/foo/a", ".") + + // package b should be a dot-import + f.ImportAlias("github.com/foo/b", ".") + + // package c is not used in the code so will not be included + f.ImportAlias("github.com/foo/c", ".") + + f.Func().Id("main").Params().Block( + Qual("github.com/foo/a", "A").Call(), + Qual("github.com/foo/b", "B").Call(), + ) + fmt.Printf("%#v", f) + + // Output: + // package main + // + // import ( + // . "github.com/foo/a" + // . "github.com/foo/b" + // ) + // + // func main() { + // A() + // B() + // } +} + +func ExampleFile_CgoPreamble() { + f := NewFile("a") + f.CgoPreamble(`#include +#include + +void myprint(char* s) { + printf("%s\n", s); +} +`) + f.Func().Id("init").Params().Block( + Id("cs").Op(":=").Qual("C", "CString").Call(Lit("Hello from stdio\n")), + Qual("C", "myprint").Call(Id("cs")), + Qual("C", "free").Call(Qual("unsafe", "Pointer").Parens(Id("cs"))), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // import "unsafe" + // + // /* + // #include + // #include + // + // void myprint(char* s) { + // printf("%s\n", s); + // } + // */ + // import "C" + // + // func init() { + // cs := C.CString("Hello from stdio\n") + // C.myprint(cs) + // C.free(unsafe.Pointer(cs)) + // } +} + +func ExampleFile_CgoPreamble_anon() { + f := NewFile("a") + f.CgoPreamble(`#include `) + f.Func().Id("init").Params().Block( + Qual("foo.bar/a", "A"), + Qual("foo.bar/b", "B"), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // import ( + // a "foo.bar/a" + // b "foo.bar/b" + // ) + // + // // #include + // import "C" + // + // func init() { + // a.A + // b.B + // } +} + +func ExampleFile_CgoPreamble_no_preamble() { + f := NewFile("a") + f.Func().Id("init").Params().Block( + Qual("C", "Foo").Call(), + Qual("fmt", "Print").Call(), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // import ( + // "C" + // "fmt" + // ) + // + // func init() { + // C.Foo() + // fmt.Print() + // } +} + +func ExampleFile_CgoPreamble_no_preamble_single() { + f := NewFile("a") + f.Func().Id("init").Params().Block( + Qual("C", "Foo").Call(), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // import "C" + // + // func init() { + // C.Foo() + // } +} + +func ExampleFile_CgoPreamble_no_preamble_single_anon() { + f := NewFile("a") + f.Anon("C") + f.Func().Id("init").Params().Block() + fmt.Printf("%#v", f) + // Output: + // package a + // + // import "C" + // + // func init() {} +} + +func ExampleFile_CgoPreamble_no_preamble_anon() { + f := NewFile("a") + f.Anon("C") + f.Func().Id("init").Params().Block( + Qual("fmt", "Print").Call(), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // import ( + // "C" + // "fmt" + // ) + // + // func init() { + // fmt.Print() + // } +} + +func ExampleOp_complex_conditions() { + c := If(Parens(Id("a").Op("||").Id("b")).Op("&&").Id("c")).Block() + fmt.Printf("%#v", c) + // Output: + // if (a || b) && c { + // } +} + +func ExampleLit_bool_true() { + c := Lit(true) + fmt.Printf("%#v", c) + // Output: + // true +} + +func ExampleLit_bool_false() { + c := Lit(false) + fmt.Printf("%#v", c) + // Output: + // false +} + +func ExampleLit_byte() { + // Lit can't tell the difference between byte and uint8. Use LitByte to + // render byte literals. + c := Lit(byte(0x1)) + fmt.Printf("%#v", c) + // Output: + // uint8(0x1) +} + +func ExampleLit_complex64() { + c := Lit(complex64(0 + 0i)) + fmt.Printf("%#v", c) + // Output: + // complex64(0 + 0i) +} + +func ExampleLit_complex128() { + c := Lit(0 + 0i) + fmt.Printf("%#v", c) + // Output: + // (0 + 0i) +} + +func ExampleLit_float32() { + c := Lit(float32(1)) + fmt.Printf("%#v", c) + // Output: + // float32(1) +} + +func ExampleLit_float64_one_point_zero() { + c := Lit(1.0) + fmt.Printf("%#v", c) + // Output: + // 1.0 +} + +func ExampleLit_float64_zero() { + c := Lit(0.0) + fmt.Printf("%#v", c) + // Output: + // 0.0 +} + +func ExampleLit_float64_negative() { + c := Lit(-0.1) + fmt.Printf("%#v", c) + // Output: + // -0.1 +} + +func ExampleLit_float64_negative_whole() { + c := Lit(-1.0) + fmt.Printf("%#v", c) + // Output: + // -1.0 +} + +func ExampleLit_int() { + c := Lit(1) + fmt.Printf("%#v", c) + // Output: + // 1 +} + +func ExampleLit_int8() { + c := Lit(int8(1)) + fmt.Printf("%#v", c) + // Output: + // int8(1) +} + +func ExampleLit_int16() { + c := Lit(int16(1)) + fmt.Printf("%#v", c) + // Output: + // int16(1) +} + +func ExampleLit_int32() { + c := Lit(int32(1)) + fmt.Printf("%#v", c) + // Output: + // int32(1) +} + +func ExampleLit_int64() { + c := Lit(int64(1)) + fmt.Printf("%#v", c) + // Output: + // int64(1) +} + +func ExampleLit_uint() { + c := Lit(uint(0x1)) + fmt.Printf("%#v", c) + // Output: + // uint(0x1) +} + +func ExampleLit_uint8() { + c := Lit(uint8(0x1)) + fmt.Printf("%#v", c) + // Output: + // uint8(0x1) +} + +func ExampleLit_uint16() { + c := Lit(uint16(0x1)) + fmt.Printf("%#v", c) + // Output: + // uint16(0x1) +} + +func ExampleLit_uint32() { + c := Lit(uint32(0x1)) + fmt.Printf("%#v", c) + // Output: + // uint32(0x1) +} + +func ExampleLit_uint64() { + c := Lit(uint64(0x1)) + fmt.Printf("%#v", c) + // Output: + // uint64(0x1) +} + +func ExampleLit_uintptr() { + c := Lit(uintptr(0x1)) + fmt.Printf("%#v", c) + // Output: + // uintptr(0x1) +} + +func ExampleLit_rune() { + // Lit can't tell the difference between rune and int32. Use LitRune to + // render rune literals. + c := Lit('x') + fmt.Printf("%#v", c) + // Output: + // int32(120) +} + +func ExampleLitRune() { + c := LitRune('x') + fmt.Printf("%#v", c) + // Output: + // 'x' +} + +func ExampleLitRuneFunc() { + c := LitRuneFunc(func() rune { + return '\t' + }) + fmt.Printf("%#v", c) + // Output: + // '\t' +} + +func ExampleLitByte() { + c := LitByte(byte(1)) + fmt.Printf("%#v", c) + // Output: + // byte(0x1) +} + +func ExampleLitByteFunc() { + c := LitByteFunc(func() byte { + return byte(2) + }) + fmt.Printf("%#v", c) + // Output: + // byte(0x2) +} + +func ExampleLit_string() { + c := Lit("foo") + fmt.Printf("%#v", c) + // Output: + // "foo" +} + +func ExampleValues_dict_single() { + c := Map(String()).String().Values(Dict{ + Lit("a"): Lit("b"), + }) + fmt.Printf("%#v", c) + // Output: + // map[string]string{"a": "b"} +} + +func ExampleValues_dict_multiple() { + c := Map(String()).String().Values(Dict{ + Lit("a"): Lit("b"), + Lit("c"): Lit("d"), + }) + fmt.Printf("%#v", c) + // Output: + // map[string]string{ + // "a": "b", + // "c": "d", + // } +} + +func ExampleValues_dict_composite() { + c := Op("&").Id("Person").Values(Dict{ + Id("Age"): Lit(1), + Id("Name"): Lit("a"), + }) + fmt.Printf("%#v", c) + // Output: + // &Person{ + // Age: 1, + // Name: "a", + // } +} + +func ExampleAdd() { + ptr := Op("*") + c := Id("a").Op("=").Add(ptr).Id("b") + fmt.Printf("%#v", c) + // Output: + // a = *b +} + +func ExampleAdd_var() { + a := Id("a") + i := Int() + c := Var().Add(a, i) + fmt.Printf("%#v", c) + // Output: + // var a int +} + +func ExampleAppend() { + c := Append(Id("a"), Id("b")) + fmt.Printf("%#v", c) + // Output: + // append(a, b) +} + +func ExampleAppend_more() { + c := Id("a").Op("=").Append(Id("a"), Id("b").Op("...")) + fmt.Printf("%#v", c) + // Output: + // a = append(a, b...) +} + +func ExampleAssert() { + c := List(Id("b"), Id("ok")).Op(":=").Id("a").Assert(Bool()) + fmt.Printf("%#v", c) + // Output: + // b, ok := a.(bool) +} + +func ExampleBlock() { + c := Func().Id("foo").Params().String().Block( + Id("a").Op("=").Id("b"), + Id("b").Op("++"), + Return(Id("b")), + ) + fmt.Printf("%#v", c) + // Output: + // func foo() string { + // a = b + // b++ + // return b + // } +} + +func ExampleBlock_if() { + c := If(Id("a").Op(">").Lit(10)).Block( + Id("a").Op("=").Id("a").Op("/").Lit(2), + ) + fmt.Printf("%#v", c) + // Output: + // if a > 10 { + // a = a / 2 + // } +} + +func ExampleValuesFunc() { + c := Id("numbers").Op(":=").Index().Int().ValuesFunc(func(g *Group) { + for i := 0; i <= 5; i++ { + g.Lit(i) + } + }) + fmt.Printf("%#v", c) + // Output: + // numbers := []int{0, 1, 2, 3, 4, 5} +} + +func ExampleBlockFunc() { + increment := true + name := "a" + c := Func().Id("a").Params().BlockFunc(func(g *Group) { + g.Id(name).Op("=").Lit(1) + if increment { + g.Id(name).Op("++") + } else { + g.Id(name).Op("--") + } + }) + fmt.Printf("%#v", c) + // Output: + // func a() { + // a = 1 + // a++ + // } +} + +func ExampleBool() { + c := Var().Id("b").Bool() + fmt.Printf("%#v", c) + // Output: + // var b bool +} + +func ExampleBreak() { + c := For( + Id("i").Op(":=").Lit(0), + Id("i").Op("<").Lit(10), + Id("i").Op("++"), + ).Block( + If(Id("i").Op(">").Lit(5)).Block( + Break(), + ), + ) + fmt.Printf("%#v", c) + // Output: + // for i := 0; i < 10; i++ { + // if i > 5 { + // break + // } + // } +} + +func ExampleByte() { + c := Id("b").Op(":=").Id("a").Assert(Byte()) + fmt.Printf("%#v", c) + // Output: + // b := a.(byte) +} + +func ExampleCall() { + c := Qual("fmt", "Printf").Call( + Lit("%#v: %T\n"), + Id("a"), + Id("b"), + ) + fmt.Printf("%#v", c) + // Output: + // fmt.Printf("%#v: %T\n", a, b) +} + +func ExampleCall_fmt() { + c := Id("a").Call(Lit("b")) + fmt.Printf("%#v", c) + // Output: + // a("b") +} + +func ExampleCallFunc() { + f := func(name string, second string) { + c := Id("foo").CallFunc(func(g *Group) { + g.Id(name) + if second != "" { + g.Lit(second) + } + }) + fmt.Printf("%#v\n", c) + } + f("a", "b") + f("c", "") + // Output: + // foo(a, "b") + // foo(c) +} + +func ExampleCap() { + c := Id("i").Op(":=").Cap(Id("v")) + fmt.Printf("%#v", c) + // Output: + // i := cap(v) +} + +func ExampleCase() { + c := Switch(Id("person")).Block( + Case(Id("John"), Id("Peter")).Block( + Return(Lit("male")), + ), + Case(Id("Gill")).Block( + Return(Lit("female")), + ), + ) + fmt.Printf("%#v", c) + // Output: + // switch person { + // case John, Peter: + // return "male" + // case Gill: + // return "female" + // } +} + +func ExampleBlock_case() { + c := Select().Block( + Case(Op("<-").Id("done")).Block( + Return(Nil()), + ), + Case(List(Err(), Id("open")).Op(":=").Op("<-").Id("fail")).Block( + If(Op("!").Id("open")).Block( + Return(Err()), + ), + ), + ) + fmt.Printf("%#v", c) + // Output: + // select { + // case <-done: + // return nil + // case err, open := <-fail: + // if !open { + // return err + // } + // } +} + +func ExampleBlockFunc_case() { + preventExitOnError := true + c := Select().Block( + Case(Op("<-").Id("done")).Block( + Return(Nil()), + ), + Case(Err().Op(":=").Op("<-").Id("fail")).BlockFunc(func(g *Group) { + if !preventExitOnError { + g.Return(Err()) + } else { + g.Qual("fmt", "Println").Call(Err()) + } + }), + ) + fmt.Printf("%#v", c) + // Output: + // select { + // case <-done: + // return nil + // case err := <-fail: + // fmt.Println(err) + // } +} + +func ExampleCaseFunc() { + samIsMale := false + c := Switch(Id("person")).Block( + CaseFunc(func(g *Group) { + g.Id("John") + g.Id("Peter") + if samIsMale { + g.Id("Sam") + } + }).Block( + Return(Lit("male")), + ), + CaseFunc(func(g *Group) { + g.Id("Gill") + if !samIsMale { + g.Id("Sam") + } + }).Block( + Return(Lit("female")), + ), + ) + fmt.Printf("%#v", c) + // Output: + // switch person { + // case John, Peter: + // return "male" + // case Gill, Sam: + // return "female" + // } +} + +func ExampleChan() { + c := Func().Id("init").Params().Block( + Id("c").Op(":=").Make(Chan().Qual("os", "Signal"), Lit(1)), + Qual("os/signal", "Notify").Call(Id("c"), Qual("os", "Interrupt")), + Qual("os/signal", "Notify").Call(Id("c"), Qual("syscall", "SIGTERM")), + Go().Func().Params().Block( + Op("<-").Id("c"), + Id("cancel").Call(), + ).Call(), + ) + fmt.Printf("%#v", c) + // Output: + // func init() { + // c := make(chan os.Signal, 1) + // signal.Notify(c, os.Interrupt) + // signal.Notify(c, syscall.SIGTERM) + // go func() { + // <-c + // cancel() + // }() + // } +} + +func ExampleClose() { + c := Block( + Id("ch").Op(":=").Make(Chan().Struct()), + Go().Func().Params().Block( + Op("<-").Id("ch"), + Qual("fmt", "Println").Call(Lit("done.")), + ).Call(), + Close(Id("ch")), + ) + fmt.Printf("%#v", c) + // Output: + // { + // ch := make(chan struct{}) + // go func() { + // <-ch + // fmt.Println("done.") + // }() + // close(ch) + // } +} + +func ExampleComment() { + f := NewFile("a") + f.Comment("Foo returns the string \"foo\"") + f.Func().Id("Foo").Params().String().Block( + Return(Lit("foo")).Comment("return the string foo"), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // // Foo returns the string "foo" + // func Foo() string { + // return "foo" // return the string foo + // } +} + +func ExampleComment_multiline() { + c := Comment("a\nb") + fmt.Printf("%#v", c) + // Output: + // /* + // a + // b + // */ +} + +func ExampleComment_formatting_disabled() { + c := Id("foo").Call(Comment("/* inline */")).Comment("//no-space") + fmt.Printf("%#v", c) + // Output: + // foo( /* inline */ ) //no-space +} + +func ExampleCommentf() { + name := "foo" + val := "bar" + c := Id(name).Op(":=").Lit(val).Commentf("%s is the string \"%s\"", name, val) + fmt.Printf("%#v", c) + // Output: + // foo := "bar" // foo is the string "bar" +} + +func ExampleComplex() { + c := Func().Id("main").Params().Block( + Id("c1").Op(":=").Lit(1+3.75i), + Id("c2").Op(":=").Complex(Lit(1), Lit(3.75)), + Qual("fmt", "Println").Call(Id("c1").Op("==").Id("c2")), + ) + fmt.Printf("%#v", c) + // Output: + // func main() { + // c1 := (1 + 3.75i) + // c2 := complex(1, 3.75) + // fmt.Println(c1 == c2) + // } +} + +func ExampleComplex128() { + c := Func().Id("main").Params().Block( + Var().Id("c").Complex128(), + Id("c").Op("=").Lit(1+2i), + Qual("fmt", "Println").Call(Id("c")), + ) + fmt.Printf("%#v", c) + // Output: + // func main() { + // var c complex128 + // c = (1 + 2i) + // fmt.Println(c) + // } +} + +func ExampleComplex64() { + c := Func().Id("main").Params().Block( + Var().Id("c64").Complex64(), + Id("c64").Op("=").Complex(Lit(5), Float32().Parens(Lit(2))), + Qual("fmt", "Printf").Call(Lit("%T\n"), Id("c64")), + ) + fmt.Printf("%#v", c) + // Output: + // func main() { + // var c64 complex64 + // c64 = complex(5, float32(2)) + // fmt.Printf("%T\n", c64) + // } +} + +func ExampleParams() { + c := Func().Params( + Id("a").Id("A"), + ).Id("foo").Params( + Id("b"), + Id("c").String(), + ).String().Block( + Return(Id("b").Op("+").Id("c")), + ) + fmt.Printf("%#v", c) + // Output: + // func (a A) foo(b, c string) string { + // return b + c + // } +} + +func ExampleIndex() { + c := Var().Id("a").Index().String() + fmt.Printf("%#v", c) + // Output: + // var a []string +} + +func ExampleIndex_index() { + c := Id("a").Op(":=").Id("b").Index(Lit(0), Lit(1)) + fmt.Printf("%#v", c) + // Output: + // a := b[0:1] +} + +func ExampleIndex_empty() { + c := Id("a").Op(":=").Id("b").Index(Lit(1), Empty()) + fmt.Printf("%#v", c) + // Output: + // a := b[1:] +} + +func ExampleOp() { + c := Id("a").Op(":=").Id("b").Call() + fmt.Printf("%#v", c) + // Output: + // a := b() +} + +func ExampleOp_star() { + c := Id("a").Op("=").Op("*").Id("b") + fmt.Printf("%#v", c) + // Output: + // a = *b +} + +func ExampleOp_variadic() { + c := Id("a").Call(Id("b").Op("...")) + fmt.Printf("%#v", c) + // Output: + // a(b...) +} + +func ExampleNewFilePath() { + f := NewFilePath("a.b/c") + f.Func().Id("init").Params().Block( + Qual("a.b/c", "Foo").Call().Comment("Local package - alias is omitted."), + Qual("d.e/f", "Bar").Call().Comment("Import is automatically added."), + Qual("g.h/f", "Baz").Call().Comment("Colliding package name is automatically renamed."), + ) + fmt.Printf("%#v", f) + // Output: + // package c + // + // import ( + // f "d.e/f" + // f1 "g.h/f" + // ) + // + // func init() { + // Foo() // Local package - alias is omitted. + // f.Bar() // Import is automatically added. + // f1.Baz() // Colliding package name is automatically renamed. + // } +} + +func ExampleStruct_empty() { + c := Id("c").Op(":=").Make(Chan().Struct()) + fmt.Printf("%#v", c) + // Output: + // c := make(chan struct{}) +} + +func ExampleStruct() { + c := Type().Id("foo").Struct( + List(Id("x"), Id("y")).Int(), + Id("u").Float32(), + ) + fmt.Printf("%#v", c) + // Output: + // type foo struct { + // x, y int + // u float32 + // } +} + +func ExampleDefer() { + c := Defer().Id("foo").Call() + fmt.Printf("%#v", c) + // Output: + // defer foo() +} + +func ExampleGoto() { + c := Goto().Id("Outer") + fmt.Printf("%#v", c) + // Output: + // goto Outer +} + +func ExampleStatement_Clone_broken() { + a := Id("a") + c := Block( + a.Call(), + a.Call(), + ) + fmt.Printf("%#v", c) + // Output: + // { + // a()() + // a()() + // } +} + +func ExampleStatement_Clone_fixed() { + a := Id("a") + c := Block( + a.Clone().Call(), + a.Clone().Call(), + ) + fmt.Printf("%#v", c) + // Output: + // { + // a() + // a() + // } +} + +func ExampleFile_Render() { + f := NewFile("a") + f.Func().Id("main").Params().Block() + buf := &bytes.Buffer{} + err := f.Render(buf) + if err != nil { + fmt.Println(err.Error()) + } else { + fmt.Println(buf.String()) + } + // Output: + // package a + // + // func main() {} +} + +func ExampleLit() { + c := Id("a").Op(":=").Lit("a") + fmt.Printf("%#v", c) + // Output: + // a := "a" +} + +func ExampleLit_float() { + c := Id("a").Op(":=").Lit(1.5) + fmt.Printf("%#v", c) + // Output: + // a := 1.5 +} + +func ExampleLitFunc() { + c := Id("a").Op(":=").LitFunc(func() interface{} { return 1 + 1 }) + fmt.Printf("%#v", c) + // Output: + // a := 2 +} + +func ExampleDot() { + c := Qual("a.b/c", "Foo").Call().Dot("Bar").Index(Lit(0)).Dot("Baz") + fmt.Printf("%#v", c) + // Output: + // c.Foo().Bar[0].Baz +} + +func ExampleList() { + c := List(Id("a"), Err()).Op(":=").Id("b").Call() + fmt.Printf("%#v", c) + // Output: + // a, err := b() +} + +func ExampleQual() { + c := Qual("encoding/gob", "NewEncoder").Call() + fmt.Printf("%#v", c) + // Output: + // gob.NewEncoder() +} + +func ExampleQual_file() { + f := NewFilePath("a.b/c") + f.Func().Id("init").Params().Block( + Qual("a.b/c", "Foo").Call().Comment("Local package - name is omitted."), + Qual("d.e/f", "Bar").Call().Comment("Import is automatically added."), + Qual("g.h/f", "Baz").Call().Comment("Colliding package name is renamed."), + ) + fmt.Printf("%#v", f) + // Output: + // package c + // + // import ( + // f "d.e/f" + // f1 "g.h/f" + // ) + // + // func init() { + // Foo() // Local package - name is omitted. + // f.Bar() // Import is automatically added. + // f1.Baz() // Colliding package name is renamed. + // } +} + +func ExampleQual_local() { + f := NewFilePath("a.b/c") + f.Func().Id("main").Params().Block( + Qual("a.b/c", "D").Call(), + ) + fmt.Printf("%#v", f) + // Output: + // package c + // + // func main() { + // D() + // } +} + +func ExampleId() { + c := If(Id("i").Op("==").Id("j")).Block( + Return(Id("i")), + ) + fmt.Printf("%#v", c) + // Output: + // if i == j { + // return i + // } +} + +func ExampleErr() { + c := If( + Err().Op(":=").Id("foo").Call(), + Err().Op("!=").Nil(), + ).Block( + Return(Err()), + ) + fmt.Printf("%#v", c) + // Output: + // if err := foo(); err != nil { + // return err + // } +} + +func ExampleSwitch() { + c := Switch(Id("value").Dot("Kind").Call()).Block( + Case(Qual("reflect", "Float32"), Qual("reflect", "Float64")).Block( + Return(Lit("float")), + ), + Case(Qual("reflect", "Bool")).Block( + Return(Lit("bool")), + ), + Case(Qual("reflect", "Uintptr")).Block( + Fallthrough(), + ), + Default().Block( + Return(Lit("none")), + ), + ) + fmt.Printf("%#v", c) + // Output: + // switch value.Kind() { + // case reflect.Float32, reflect.Float64: + // return "float" + // case reflect.Bool: + // return "bool" + // case reflect.Uintptr: + // fallthrough + // default: + // return "none" + // } +} + +func ExampleTag() { + c := Type().Id("foo").Struct( + Id("A").String().Tag(map[string]string{"json": "a"}), + Id("B").Int().Tag(map[string]string{"json": "b", "bar": "baz"}), + ) + fmt.Printf("%#v", c) + // Output: + // type foo struct { + // A string `json:"a"` + // B int `bar:"baz" json:"b"` + // } +} + +func ExampleNull_and_nil() { + c := Func().Id("foo").Params( + nil, + Id("s").String(), + Null(), + Id("i").Int(), + ).Block() + fmt.Printf("%#v", c) + // Output: + // func foo(s string, i int) {} +} + +func ExampleNull_index() { + c := Id("a").Op(":=").Id("b").Index(Lit(1), Null()) + fmt.Printf("%#v", c) + // Output: + // a := b[1] +} + +func ExampleEmpty() { + c := Id("a").Op(":=").Id("b").Index(Lit(1), Empty()) + fmt.Printf("%#v", c) + // Output: + // a := b[1:] +} + +func ExampleBlock_complex() { + collection := func(name string, key Code, value Code) *Statement { + if key == nil { + // slice + return Var().Id(name).Index().Add(value) + } else { + // map + return Var().Id(name).Map(key).Add(value) + } + } + c := Func().Id("main").Params().Block( + collection("foo", nil, String()), + collection("bar", String(), Int()), + ) + fmt.Printf("%#v", c) + // Output: + // func main() { + // var foo []string + // var bar map[string]int + // } +} + +func ExampleFunc_declaration() { + c := Func().Id("a").Params().Block() + fmt.Printf("%#v", c) + // Output: + // func a() {} +} + +func ExampleFunc_literal() { + c := Id("a").Op(":=").Func().Params().Block() + fmt.Printf("%#v", c) + // Output: + // a := func() {} +} + +func ExampleInterface() { + c := Type().Id("a").Interface( + Id("b").Params().String(), + ) + fmt.Printf("%#v", c) + // Output: + // type a interface { + // b() string + // } +} + +func ExampleInterface_empty() { + c := Var().Id("a").Interface() + fmt.Printf("%#v", c) + // Output: + // var a interface{} +} + +func ExampleParens() { + c := Id("b").Op(":=").Index().Byte().Parens(Id("s")) + fmt.Printf("%#v", c) + // Output: + // b := []byte(s) +} + +func ExampleParens_order() { + c := Id("a").Op("/").Parens(Id("b").Op("+").Id("c")) + fmt.Printf("%#v", c) + // Output: + // a / (b + c) +} + +func ExampleValues() { + c := Index().String().Values(Lit("a"), Lit("b")) + fmt.Printf("%#v", c) + // Output: + // []string{"a", "b"} +} + +func ExampleDo() { + f := func(name string, isMap bool) *Statement { + return Id(name).Op(":=").Do(func(s *Statement) { + if isMap { + s.Map(String()).String() + } else { + s.Index().String() + } + }).Values() + } + fmt.Printf("%#v\n%#v", f("a", true), f("b", false)) + // Output: + // a := map[string]string{} + // b := []string{} +} + +func ExampleReturn() { + c := Return(Id("a"), Id("b")) + fmt.Printf("%#v", c) + // Output: + // return a, b +} + +func ExampleMap() { + c := Id("a").Op(":=").Map(String()).String().Values() + fmt.Printf("%#v", c) + // Output: + // a := map[string]string{} +} + +func ExampleDict() { + c := Id("a").Op(":=").Map(String()).String().Values(Dict{ + Lit("a"): Lit("b"), + Lit("c"): Lit("d"), + }) + fmt.Printf("%#v", c) + // Output: + // a := map[string]string{ + // "a": "b", + // "c": "d", + // } +} + +func ExampleDict_nil() { + c := Id("a").Op(":=").Map(String()).String().Values() + fmt.Printf("%#v", c) + // Output: + // a := map[string]string{} +} + +func ExampleDictFunc() { + c := Id("a").Op(":=").Map(String()).String().Values(DictFunc(func(d Dict) { + d[Lit("a")] = Lit("b") + d[Lit("c")] = Lit("d") + })) + fmt.Printf("%#v", c) + // Output: + // a := map[string]string{ + // "a": "b", + // "c": "d", + // } +} + +func ExampleDefs() { + c := Const().Defs( + Id("a").Op("=").Lit("a"), + Id("b").Op("=").Lit("b"), + ) + fmt.Printf("%#v", c) + // Output: + // const ( + // a = "a" + // b = "b" + // ) +} + +func ExampleIf() { + c := If( + Err().Op(":=").Id("a").Call(), + Err().Op("!=").Nil(), + ).Block( + Return(Err()), + ) + fmt.Printf("%#v", c) + // Output: + // if err := a(); err != nil { + // return err + // } +} + +func ExampleId_local() { + c := Id("a").Op(":=").Lit(1) + fmt.Printf("%#v", c) + // Output: + // a := 1 +} + +func ExampleId_select() { + c := Id("a").Dot("b").Dot("c").Call() + fmt.Printf("%#v", c) + // Output: + // a.b.c() +} + +func ExampleId_remote() { + f := NewFile("main") + f.Func().Id("main").Params().Block( + Qual("fmt", "Println").Call( + Lit("Hello, world"), + ), + ) + fmt.Printf("%#v", f) + // Output: + // package main + // + // import "fmt" + // + // func main() { + // fmt.Println("Hello, world") + // } +} + +func ExampleFor() { + c := For( + Id("i").Op(":=").Lit(0), + Id("i").Op("<").Lit(10), + Id("i").Op("++"), + ).Block( + Qual("fmt", "Println").Call(Id("i")), + ) + fmt.Printf("%#v", c) + // Output: + // for i := 0; i < 10; i++ { + // fmt.Println(i) + // } +} + +func ExampleNewFile() { + f := NewFile("main") + f.Func().Id("main").Params().Block( + Qual("fmt", "Println").Call(Lit("Hello, world")), + ) + fmt.Printf("%#v", f) + // Output: + // package main + // + // import "fmt" + // + // func main() { + // fmt.Println("Hello, world") + // } +} + +func ExampleNewFilePathName() { + f := NewFilePathName("a.b/c", "main") + f.Func().Id("main").Params().Block( + Qual("a.b/c", "Foo").Call(), + ) + fmt.Printf("%#v", f) + // Output: + // package main + // + // func main() { + // Foo() + // } +} + +func ExampleFile_HeaderAndPackageComments() { + f := NewFile("c") + f.CanonicalPath = "d.e/f" + f.HeaderComment("Code generated by...") + f.PackageComment("Package c implements...") + f.Func().Id("init").Params().Block() + fmt.Printf("%#v", f) + // Output: + // // Code generated by... + // + // // Package c implements... + // package c // import "d.e/f" + // + // func init() {} +} + +func ExampleFile_Anon() { + f := NewFile("c") + f.Anon("a") + f.Func().Id("init").Params().Block() + fmt.Printf("%#v", f) + // Output: + // package c + // + // import _ "a" + // + // func init() {} +} + +func ExampleFile_PackagePrefix() { + f := NewFile("a") + f.PackagePrefix = "pkg" + f.Func().Id("main").Params().Block( + Qual("b.c/d", "E").Call(), + ) + fmt.Printf("%#v", f) + // Output: + // package a + // + // import pkg_d "b.c/d" + // + // func main() { + // pkg_d.E() + // } +} diff --git a/vendor/github.com/dave/jennifer/jen/file.go b/vendor/github.com/dave/jennifer/jen/file.go new file mode 100644 index 00000000..1ce442b9 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/file.go @@ -0,0 +1,262 @@ +package jen + +import ( + "bytes" + "fmt" + "regexp" + "strings" +) + +// NewFile Creates a new file, with the specified package name. +func NewFile(packageName string) *File { + return &File{ + Group: &Group{ + multi: true, + }, + name: packageName, + imports: map[string]importdef{}, + hints: map[string]importdef{}, + } +} + +// NewFilePath creates a new file while specifying the package path - the +// package name is inferred from the path. +func NewFilePath(packagePath string) *File { + return &File{ + Group: &Group{ + multi: true, + }, + name: guessAlias(packagePath), + path: packagePath, + imports: map[string]importdef{}, + hints: map[string]importdef{}, + } +} + +// NewFilePathName creates a new file with the specified package path and name. +func NewFilePathName(packagePath, packageName string) *File { + return &File{ + Group: &Group{ + multi: true, + }, + name: packageName, + path: packagePath, + imports: map[string]importdef{}, + hints: map[string]importdef{}, + } +} + +// File represents a single source file. Package imports are managed +// automaticaly by File. +type File struct { + *Group + name string + path string + imports map[string]importdef + hints map[string]importdef + comments []string + headers []string + cgoPreamble []string + // If you're worried about generated package aliases conflicting with local variable names, you + // can set a prefix here. Package foo becomes {prefix}_foo. + PackagePrefix string + // CanonicalPath adds a canonical import path annotation to the package clause. + CanonicalPath string +} + +// importdef is used to differentiate packages where we know the package name from packages where the +// import is aliased. If alias == false, then name is the actual package name, and the import will be +// rendered without an alias. If used == false, the import has not been used in code yet and should be +// excluded from the import block. +type importdef struct { + name string + alias bool +} + +// HeaderComment adds a comment to the top of the file, above any package +// comments. A blank line is rendered below the header comments, ensuring +// header comments are not included in the package doc. +func (f *File) HeaderComment(comment string) { + f.headers = append(f.headers, comment) +} + +// PackageComment adds a comment to the top of the file, above the package +// keyword. +func (f *File) PackageComment(comment string) { + f.comments = append(f.comments, comment) +} + +// CgoPreamble adds a cgo preamble comment that is rendered directly before the "C" pseudo-package +// import. +func (f *File) CgoPreamble(comment string) { + f.cgoPreamble = append(f.cgoPreamble, comment) +} + +// Anon adds an anonymous import. +func (f *File) Anon(paths ...string) { + for _, p := range paths { + f.imports[p] = importdef{name: "_", alias: true} + } +} + +// ImportName provides the package name for a path. If specified, the alias will be omitted from the +// import block. This is optional. If not specified, a sensible package name is used based on the path +// and this is added as an alias in the import block. +func (f *File) ImportName(path, name string) { + f.hints[path] = importdef{name: name, alias: false} +} + +// ImportNames allows multiple names to be imported as a map. Use the [gennames](gennames) command to +// automatically generate a go file containing a map of a selection of package names. +func (f *File) ImportNames(names map[string]string) { + for path, name := range names { + f.hints[path] = importdef{name: name, alias: false} + } +} + +// ImportAlias provides the alias for a package path that should be used in the import block. A +// period can be used to force a dot-import. +func (f *File) ImportAlias(path, alias string) { + f.hints[path] = importdef{name: alias, alias: true} +} + +func (f *File) isLocal(path string) bool { + return f.path == path +} + +var reserved = []string{ + /* keywords */ + "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", + /* predeclared */ + "bool", "byte", "complex64", "complex128", "error", "float32", "float64", "int", "int8", "int16", "int32", "int64", "rune", "string", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "true", "false", "iota", "nil", "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", "panic", "print", "println", "real", "recover", + /* common variables */ + "err", +} + +func isReservedWord(alias string) bool { + for _, name := range reserved { + if alias == name { + return true + } + } + return false +} + +func (f *File) isValidAlias(alias string) bool { + // multiple dot-imports are ok + if alias == "." { + return true + } + // the import alias is invalid if it's a reserved word + if isReservedWord(alias) { + return false + } + // the import alias is invalid if it's already been registered + for _, v := range f.imports { + if alias == v.name { + return false + } + } + return true +} + +func (f *File) isDotImport(path string) bool { + if id, ok := f.hints[path]; ok { + return id.name == "." && id.alias + } + return false +} + +func (f *File) register(path string) string { + if f.isLocal(path) { + // notest + // should never get here becasue in Qual the packageToken will be null, + // so render will never be called. + return "" + } + + // if the path has been registered previously, simply return the name + def := f.imports[path] + if def.name != "" && def.name != "_" { + return def.name + } + + // special case for "C" pseudo-package + if path == "C" { + f.imports["C"] = importdef{name: "C", alias: false} + return "C" + } + + var name string + var alias bool + + if hint := f.hints[path]; hint.name != "" { + // look up the path in the list of provided package names and aliases by ImportName / ImportAlias + name = hint.name + alias = hint.alias + } else if standardLibraryHints[path] != "" { + // look up the path in the list of standard library packages + name = standardLibraryHints[path] + alias = false + } else { + // if a hint is not found for the package, guess the alias from the package path + name = guessAlias(path) + alias = true + } + + // If the name is invalid or has been registered already, make it unique by appending a number + unique := name + i := 0 + for !f.isValidAlias(unique) { + i++ + unique = fmt.Sprintf("%s%d", name, i) + } + + // If we've changed the name to make it unique, it should definitely be an alias + if unique != name { + alias = true + } + + // Only add a prefix if the name is an alias + if f.PackagePrefix != "" && alias { + unique = f.PackagePrefix + "_" + unique + } + + // Register the eventual name + f.imports[path] = importdef{name: unique, alias: alias} + + return unique +} + +// GoString renders the File for testing. Any error will cause a panic. +func (f *File) GoString() string { + buf := &bytes.Buffer{} + if err := f.Render(buf); err != nil { + panic(err) + } + return buf.String() +} + +func guessAlias(path string) string { + alias := path + + if strings.HasSuffix(alias, "/") { + // training slashes are usually tolerated, so we can get rid of one if + // it exists + alias = alias[:len(alias)-1] + } + + if strings.Contains(alias, "/") { + // if the path contains a "/", use the last part + alias = alias[strings.LastIndex(alias, "/")+1:] + } + + // alias should be lower case + alias = strings.ToLower(alias) + + // alias should now only contain alphanumerics + importsRegex := regexp.MustCompile(`[^a-z0-9]`) + alias = importsRegex.ReplaceAllString(alias, "") + + return alias +} diff --git a/vendor/github.com/dave/jennifer/jen/file_test.go b/vendor/github.com/dave/jennifer/jen/file_test.go new file mode 100644 index 00000000..798faf63 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/file_test.go @@ -0,0 +1,48 @@ +package jen + +import ( + "fmt" + "testing" +) + +func TestGuessAlias(t *testing.T) { + + data := map[string]string{ + "A": "a", + "a": "a", + "a$": "a", + "a/b": "b", + "a/b/c": "c", + "a/b/c-d": "cd", + "a/b/c-d/": "cd", + "a.b": "ab", + "a/b.c": "bc", + "a/b-c.d": "bcd", + "a/bb-ccc.dddd": "bbcccdddd", + "a/foo-go": "foogo", + } + for path, expected := range data { + if guessAlias(path) != expected { + fmt.Printf("guessAlias test failed %s should return %s but got %s\n", path, expected, guessAlias(path)) + t.Fail() + } + } +} + +func TestValidAlias(t *testing.T) { + data := map[string]bool{ + "a": true, // ok + "b": false, // already registered + "go": false, // keyword + "int": false, // predeclared + "err": false, // common name + } + f := NewFile("test") + f.register("b") + for alias, expected := range data { + if f.isValidAlias(alias) != expected { + fmt.Printf("isValidAlias test failed %s should return %t but got %t\n", alias, expected, f.isValidAlias(alias)) + t.Fail() + } + } +} diff --git a/vendor/github.com/dave/jennifer/jen/generated.go b/vendor/github.com/dave/jennifer/jen/generated.go new file mode 100644 index 00000000..3983cf97 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/generated.go @@ -0,0 +1,2274 @@ +// This file is generated - do not edit. + +package jen + +// Parens renders a single item in parenthesis. Use for type conversion or to specify evaluation order. +func Parens(item Code) *Statement { + return newStatement().Parens(item) +} + +// Parens renders a single item in parenthesis. Use for type conversion or to specify evaluation order. +func (g *Group) Parens(item Code) *Statement { + s := Parens(item) + g.items = append(g.items, s) + return s +} + +// Parens renders a single item in parenthesis. Use for type conversion or to specify evaluation order. +func (s *Statement) Parens(item Code) *Statement { + g := &Group{ + close: ")", + items: []Code{item}, + multi: false, + name: "parens", + open: "(", + separator: "", + } + *s = append(*s, g) + return s +} + +// List renders a comma separated list. Use for multiple return functions. +func List(items ...Code) *Statement { + return newStatement().List(items...) +} + +// List renders a comma separated list. Use for multiple return functions. +func (g *Group) List(items ...Code) *Statement { + s := List(items...) + g.items = append(g.items, s) + return s +} + +// List renders a comma separated list. Use for multiple return functions. +func (s *Statement) List(items ...Code) *Statement { + g := &Group{ + close: "", + items: items, + multi: false, + name: "list", + open: "", + separator: ",", + } + *s = append(*s, g) + return s +} + +// ListFunc renders a comma separated list. Use for multiple return functions. +func ListFunc(f func(*Group)) *Statement { + return newStatement().ListFunc(f) +} + +// ListFunc renders a comma separated list. Use for multiple return functions. +func (g *Group) ListFunc(f func(*Group)) *Statement { + s := ListFunc(f) + g.items = append(g.items, s) + return s +} + +// ListFunc renders a comma separated list. Use for multiple return functions. +func (s *Statement) ListFunc(f func(*Group)) *Statement { + g := &Group{ + close: "", + multi: false, + name: "list", + open: "", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Values renders a comma separated list enclosed by curly braces. Use for slice or composite literals. +func Values(values ...Code) *Statement { + return newStatement().Values(values...) +} + +// Values renders a comma separated list enclosed by curly braces. Use for slice or composite literals. +func (g *Group) Values(values ...Code) *Statement { + s := Values(values...) + g.items = append(g.items, s) + return s +} + +// Values renders a comma separated list enclosed by curly braces. Use for slice or composite literals. +func (s *Statement) Values(values ...Code) *Statement { + g := &Group{ + close: "}", + items: values, + multi: false, + name: "values", + open: "{", + separator: ",", + } + *s = append(*s, g) + return s +} + +// ValuesFunc renders a comma separated list enclosed by curly braces. Use for slice or composite literals. +func ValuesFunc(f func(*Group)) *Statement { + return newStatement().ValuesFunc(f) +} + +// ValuesFunc renders a comma separated list enclosed by curly braces. Use for slice or composite literals. +func (g *Group) ValuesFunc(f func(*Group)) *Statement { + s := ValuesFunc(f) + g.items = append(g.items, s) + return s +} + +// ValuesFunc renders a comma separated list enclosed by curly braces. Use for slice or composite literals. +func (s *Statement) ValuesFunc(f func(*Group)) *Statement { + g := &Group{ + close: "}", + multi: false, + name: "values", + open: "{", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Index renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. +func Index(items ...Code) *Statement { + return newStatement().Index(items...) +} + +// Index renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. +func (g *Group) Index(items ...Code) *Statement { + s := Index(items...) + g.items = append(g.items, s) + return s +} + +// Index renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. +func (s *Statement) Index(items ...Code) *Statement { + g := &Group{ + close: "]", + items: items, + multi: false, + name: "index", + open: "[", + separator: ":", + } + *s = append(*s, g) + return s +} + +// IndexFunc renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. +func IndexFunc(f func(*Group)) *Statement { + return newStatement().IndexFunc(f) +} + +// IndexFunc renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. +func (g *Group) IndexFunc(f func(*Group)) *Statement { + s := IndexFunc(f) + g.items = append(g.items, s) + return s +} + +// IndexFunc renders a colon separated list enclosed by square brackets. Use for array / slice indexes and definitions. +func (s *Statement) IndexFunc(f func(*Group)) *Statement { + g := &Group{ + close: "]", + multi: false, + name: "index", + open: "[", + separator: ":", + } + f(g) + *s = append(*s, g) + return s +} + +// Block renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. +func Block(statements ...Code) *Statement { + return newStatement().Block(statements...) +} + +// Block renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. +func (g *Group) Block(statements ...Code) *Statement { + s := Block(statements...) + g.items = append(g.items, s) + return s +} + +// Block renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. +func (s *Statement) Block(statements ...Code) *Statement { + g := &Group{ + close: "}", + items: statements, + multi: true, + name: "block", + open: "{", + separator: "", + } + *s = append(*s, g) + return s +} + +// BlockFunc renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. +func BlockFunc(f func(*Group)) *Statement { + return newStatement().BlockFunc(f) +} + +// BlockFunc renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. +func (g *Group) BlockFunc(f func(*Group)) *Statement { + s := BlockFunc(f) + g.items = append(g.items, s) + return s +} + +// BlockFunc renders a statement list enclosed by curly braces. Use for code blocks. A special case applies when used directly after Case or Default, where the braces are omitted. This allows use in switch and select statements. +func (s *Statement) BlockFunc(f func(*Group)) *Statement { + g := &Group{ + close: "}", + multi: true, + name: "block", + open: "{", + separator: "", + } + f(g) + *s = append(*s, g) + return s +} + +// Defs renders a statement list enclosed in parenthesis. Use for definition lists. +func Defs(definitions ...Code) *Statement { + return newStatement().Defs(definitions...) +} + +// Defs renders a statement list enclosed in parenthesis. Use for definition lists. +func (g *Group) Defs(definitions ...Code) *Statement { + s := Defs(definitions...) + g.items = append(g.items, s) + return s +} + +// Defs renders a statement list enclosed in parenthesis. Use for definition lists. +func (s *Statement) Defs(definitions ...Code) *Statement { + g := &Group{ + close: ")", + items: definitions, + multi: true, + name: "defs", + open: "(", + separator: "", + } + *s = append(*s, g) + return s +} + +// DefsFunc renders a statement list enclosed in parenthesis. Use for definition lists. +func DefsFunc(f func(*Group)) *Statement { + return newStatement().DefsFunc(f) +} + +// DefsFunc renders a statement list enclosed in parenthesis. Use for definition lists. +func (g *Group) DefsFunc(f func(*Group)) *Statement { + s := DefsFunc(f) + g.items = append(g.items, s) + return s +} + +// DefsFunc renders a statement list enclosed in parenthesis. Use for definition lists. +func (s *Statement) DefsFunc(f func(*Group)) *Statement { + g := &Group{ + close: ")", + multi: true, + name: "defs", + open: "(", + separator: "", + } + f(g) + *s = append(*s, g) + return s +} + +// Call renders a comma separated list enclosed by parenthesis. Use for function calls. +func Call(params ...Code) *Statement { + return newStatement().Call(params...) +} + +// Call renders a comma separated list enclosed by parenthesis. Use for function calls. +func (g *Group) Call(params ...Code) *Statement { + s := Call(params...) + g.items = append(g.items, s) + return s +} + +// Call renders a comma separated list enclosed by parenthesis. Use for function calls. +func (s *Statement) Call(params ...Code) *Statement { + g := &Group{ + close: ")", + items: params, + multi: false, + name: "call", + open: "(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// CallFunc renders a comma separated list enclosed by parenthesis. Use for function calls. +func CallFunc(f func(*Group)) *Statement { + return newStatement().CallFunc(f) +} + +// CallFunc renders a comma separated list enclosed by parenthesis. Use for function calls. +func (g *Group) CallFunc(f func(*Group)) *Statement { + s := CallFunc(f) + g.items = append(g.items, s) + return s +} + +// CallFunc renders a comma separated list enclosed by parenthesis. Use for function calls. +func (s *Statement) CallFunc(f func(*Group)) *Statement { + g := &Group{ + close: ")", + multi: false, + name: "call", + open: "(", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Params renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. +func Params(params ...Code) *Statement { + return newStatement().Params(params...) +} + +// Params renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. +func (g *Group) Params(params ...Code) *Statement { + s := Params(params...) + g.items = append(g.items, s) + return s +} + +// Params renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. +func (s *Statement) Params(params ...Code) *Statement { + g := &Group{ + close: ")", + items: params, + multi: false, + name: "params", + open: "(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// ParamsFunc renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. +func ParamsFunc(f func(*Group)) *Statement { + return newStatement().ParamsFunc(f) +} + +// ParamsFunc renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. +func (g *Group) ParamsFunc(f func(*Group)) *Statement { + s := ParamsFunc(f) + g.items = append(g.items, s) + return s +} + +// ParamsFunc renders a comma separated list enclosed by parenthesis. Use for function parameters and method receivers. +func (s *Statement) ParamsFunc(f func(*Group)) *Statement { + g := &Group{ + close: ")", + multi: false, + name: "params", + open: "(", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Assert renders a period followed by a single item enclosed by parenthesis. Use for type assertions. +func Assert(typ Code) *Statement { + return newStatement().Assert(typ) +} + +// Assert renders a period followed by a single item enclosed by parenthesis. Use for type assertions. +func (g *Group) Assert(typ Code) *Statement { + s := Assert(typ) + g.items = append(g.items, s) + return s +} + +// Assert renders a period followed by a single item enclosed by parenthesis. Use for type assertions. +func (s *Statement) Assert(typ Code) *Statement { + g := &Group{ + close: ")", + items: []Code{typ}, + multi: false, + name: "assert", + open: ".(", + separator: "", + } + *s = append(*s, g) + return s +} + +// Map renders the keyword followed by a single item enclosed by square brackets. Use for map definitions. +func Map(typ Code) *Statement { + return newStatement().Map(typ) +} + +// Map renders the keyword followed by a single item enclosed by square brackets. Use for map definitions. +func (g *Group) Map(typ Code) *Statement { + s := Map(typ) + g.items = append(g.items, s) + return s +} + +// Map renders the keyword followed by a single item enclosed by square brackets. Use for map definitions. +func (s *Statement) Map(typ Code) *Statement { + g := &Group{ + close: "]", + items: []Code{typ}, + multi: false, + name: "map", + open: "map[", + separator: "", + } + *s = append(*s, g) + return s +} + +// If renders the keyword followed by a semicolon separated list. +func If(conditions ...Code) *Statement { + return newStatement().If(conditions...) +} + +// If renders the keyword followed by a semicolon separated list. +func (g *Group) If(conditions ...Code) *Statement { + s := If(conditions...) + g.items = append(g.items, s) + return s +} + +// If renders the keyword followed by a semicolon separated list. +func (s *Statement) If(conditions ...Code) *Statement { + g := &Group{ + close: "", + items: conditions, + multi: false, + name: "if", + open: "if ", + separator: ";", + } + *s = append(*s, g) + return s +} + +// IfFunc renders the keyword followed by a semicolon separated list. +func IfFunc(f func(*Group)) *Statement { + return newStatement().IfFunc(f) +} + +// IfFunc renders the keyword followed by a semicolon separated list. +func (g *Group) IfFunc(f func(*Group)) *Statement { + s := IfFunc(f) + g.items = append(g.items, s) + return s +} + +// IfFunc renders the keyword followed by a semicolon separated list. +func (s *Statement) IfFunc(f func(*Group)) *Statement { + g := &Group{ + close: "", + multi: false, + name: "if", + open: "if ", + separator: ";", + } + f(g) + *s = append(*s, g) + return s +} + +// Return renders the keyword followed by a comma separated list. +func Return(results ...Code) *Statement { + return newStatement().Return(results...) +} + +// Return renders the keyword followed by a comma separated list. +func (g *Group) Return(results ...Code) *Statement { + s := Return(results...) + g.items = append(g.items, s) + return s +} + +// Return renders the keyword followed by a comma separated list. +func (s *Statement) Return(results ...Code) *Statement { + g := &Group{ + close: "", + items: results, + multi: false, + name: "return", + open: "return ", + separator: ",", + } + *s = append(*s, g) + return s +} + +// ReturnFunc renders the keyword followed by a comma separated list. +func ReturnFunc(f func(*Group)) *Statement { + return newStatement().ReturnFunc(f) +} + +// ReturnFunc renders the keyword followed by a comma separated list. +func (g *Group) ReturnFunc(f func(*Group)) *Statement { + s := ReturnFunc(f) + g.items = append(g.items, s) + return s +} + +// ReturnFunc renders the keyword followed by a comma separated list. +func (s *Statement) ReturnFunc(f func(*Group)) *Statement { + g := &Group{ + close: "", + multi: false, + name: "return", + open: "return ", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// For renders the keyword followed by a semicolon separated list. +func For(conditions ...Code) *Statement { + return newStatement().For(conditions...) +} + +// For renders the keyword followed by a semicolon separated list. +func (g *Group) For(conditions ...Code) *Statement { + s := For(conditions...) + g.items = append(g.items, s) + return s +} + +// For renders the keyword followed by a semicolon separated list. +func (s *Statement) For(conditions ...Code) *Statement { + g := &Group{ + close: "", + items: conditions, + multi: false, + name: "for", + open: "for ", + separator: ";", + } + *s = append(*s, g) + return s +} + +// ForFunc renders the keyword followed by a semicolon separated list. +func ForFunc(f func(*Group)) *Statement { + return newStatement().ForFunc(f) +} + +// ForFunc renders the keyword followed by a semicolon separated list. +func (g *Group) ForFunc(f func(*Group)) *Statement { + s := ForFunc(f) + g.items = append(g.items, s) + return s +} + +// ForFunc renders the keyword followed by a semicolon separated list. +func (s *Statement) ForFunc(f func(*Group)) *Statement { + g := &Group{ + close: "", + multi: false, + name: "for", + open: "for ", + separator: ";", + } + f(g) + *s = append(*s, g) + return s +} + +// Switch renders the keyword followed by a semicolon separated list. +func Switch(conditions ...Code) *Statement { + return newStatement().Switch(conditions...) +} + +// Switch renders the keyword followed by a semicolon separated list. +func (g *Group) Switch(conditions ...Code) *Statement { + s := Switch(conditions...) + g.items = append(g.items, s) + return s +} + +// Switch renders the keyword followed by a semicolon separated list. +func (s *Statement) Switch(conditions ...Code) *Statement { + g := &Group{ + close: "", + items: conditions, + multi: false, + name: "switch", + open: "switch ", + separator: ";", + } + *s = append(*s, g) + return s +} + +// SwitchFunc renders the keyword followed by a semicolon separated list. +func SwitchFunc(f func(*Group)) *Statement { + return newStatement().SwitchFunc(f) +} + +// SwitchFunc renders the keyword followed by a semicolon separated list. +func (g *Group) SwitchFunc(f func(*Group)) *Statement { + s := SwitchFunc(f) + g.items = append(g.items, s) + return s +} + +// SwitchFunc renders the keyword followed by a semicolon separated list. +func (s *Statement) SwitchFunc(f func(*Group)) *Statement { + g := &Group{ + close: "", + multi: false, + name: "switch", + open: "switch ", + separator: ";", + } + f(g) + *s = append(*s, g) + return s +} + +// Interface renders the keyword followed by a method list enclosed by curly braces. +func Interface(methods ...Code) *Statement { + return newStatement().Interface(methods...) +} + +// Interface renders the keyword followed by a method list enclosed by curly braces. +func (g *Group) Interface(methods ...Code) *Statement { + s := Interface(methods...) + g.items = append(g.items, s) + return s +} + +// Interface renders the keyword followed by a method list enclosed by curly braces. +func (s *Statement) Interface(methods ...Code) *Statement { + g := &Group{ + close: "}", + items: methods, + multi: true, + name: "interface", + open: "interface{", + separator: "", + } + *s = append(*s, g) + return s +} + +// InterfaceFunc renders the keyword followed by a method list enclosed by curly braces. +func InterfaceFunc(f func(*Group)) *Statement { + return newStatement().InterfaceFunc(f) +} + +// InterfaceFunc renders the keyword followed by a method list enclosed by curly braces. +func (g *Group) InterfaceFunc(f func(*Group)) *Statement { + s := InterfaceFunc(f) + g.items = append(g.items, s) + return s +} + +// InterfaceFunc renders the keyword followed by a method list enclosed by curly braces. +func (s *Statement) InterfaceFunc(f func(*Group)) *Statement { + g := &Group{ + close: "}", + multi: true, + name: "interface", + open: "interface{", + separator: "", + } + f(g) + *s = append(*s, g) + return s +} + +// Struct renders the keyword followed by a field list enclosed by curly braces. +func Struct(fields ...Code) *Statement { + return newStatement().Struct(fields...) +} + +// Struct renders the keyword followed by a field list enclosed by curly braces. +func (g *Group) Struct(fields ...Code) *Statement { + s := Struct(fields...) + g.items = append(g.items, s) + return s +} + +// Struct renders the keyword followed by a field list enclosed by curly braces. +func (s *Statement) Struct(fields ...Code) *Statement { + g := &Group{ + close: "}", + items: fields, + multi: true, + name: "struct", + open: "struct{", + separator: "", + } + *s = append(*s, g) + return s +} + +// StructFunc renders the keyword followed by a field list enclosed by curly braces. +func StructFunc(f func(*Group)) *Statement { + return newStatement().StructFunc(f) +} + +// StructFunc renders the keyword followed by a field list enclosed by curly braces. +func (g *Group) StructFunc(f func(*Group)) *Statement { + s := StructFunc(f) + g.items = append(g.items, s) + return s +} + +// StructFunc renders the keyword followed by a field list enclosed by curly braces. +func (s *Statement) StructFunc(f func(*Group)) *Statement { + g := &Group{ + close: "}", + multi: true, + name: "struct", + open: "struct{", + separator: "", + } + f(g) + *s = append(*s, g) + return s +} + +// Case renders the keyword followed by a comma separated list. +func Case(cases ...Code) *Statement { + return newStatement().Case(cases...) +} + +// Case renders the keyword followed by a comma separated list. +func (g *Group) Case(cases ...Code) *Statement { + s := Case(cases...) + g.items = append(g.items, s) + return s +} + +// Case renders the keyword followed by a comma separated list. +func (s *Statement) Case(cases ...Code) *Statement { + g := &Group{ + close: ":", + items: cases, + multi: false, + name: "case", + open: "case ", + separator: ",", + } + *s = append(*s, g) + return s +} + +// CaseFunc renders the keyword followed by a comma separated list. +func CaseFunc(f func(*Group)) *Statement { + return newStatement().CaseFunc(f) +} + +// CaseFunc renders the keyword followed by a comma separated list. +func (g *Group) CaseFunc(f func(*Group)) *Statement { + s := CaseFunc(f) + g.items = append(g.items, s) + return s +} + +// CaseFunc renders the keyword followed by a comma separated list. +func (s *Statement) CaseFunc(f func(*Group)) *Statement { + g := &Group{ + close: ":", + multi: false, + name: "case", + open: "case ", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Append renders the append built-in function. +func Append(args ...Code) *Statement { + return newStatement().Append(args...) +} + +// Append renders the append built-in function. +func (g *Group) Append(args ...Code) *Statement { + s := Append(args...) + g.items = append(g.items, s) + return s +} + +// Append renders the append built-in function. +func (s *Statement) Append(args ...Code) *Statement { + g := &Group{ + close: ")", + items: args, + multi: false, + name: "append", + open: "append(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// AppendFunc renders the append built-in function. +func AppendFunc(f func(*Group)) *Statement { + return newStatement().AppendFunc(f) +} + +// AppendFunc renders the append built-in function. +func (g *Group) AppendFunc(f func(*Group)) *Statement { + s := AppendFunc(f) + g.items = append(g.items, s) + return s +} + +// AppendFunc renders the append built-in function. +func (s *Statement) AppendFunc(f func(*Group)) *Statement { + g := &Group{ + close: ")", + multi: false, + name: "append", + open: "append(", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Cap renders the cap built-in function. +func Cap(v Code) *Statement { + return newStatement().Cap(v) +} + +// Cap renders the cap built-in function. +func (g *Group) Cap(v Code) *Statement { + s := Cap(v) + g.items = append(g.items, s) + return s +} + +// Cap renders the cap built-in function. +func (s *Statement) Cap(v Code) *Statement { + g := &Group{ + close: ")", + items: []Code{v}, + multi: false, + name: "cap", + open: "cap(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Close renders the close built-in function. +func Close(c Code) *Statement { + return newStatement().Close(c) +} + +// Close renders the close built-in function. +func (g *Group) Close(c Code) *Statement { + s := Close(c) + g.items = append(g.items, s) + return s +} + +// Close renders the close built-in function. +func (s *Statement) Close(c Code) *Statement { + g := &Group{ + close: ")", + items: []Code{c}, + multi: false, + name: "close", + open: "close(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Complex renders the complex built-in function. +func Complex(r Code, i Code) *Statement { + return newStatement().Complex(r, i) +} + +// Complex renders the complex built-in function. +func (g *Group) Complex(r Code, i Code) *Statement { + s := Complex(r, i) + g.items = append(g.items, s) + return s +} + +// Complex renders the complex built-in function. +func (s *Statement) Complex(r Code, i Code) *Statement { + g := &Group{ + close: ")", + items: []Code{r, i}, + multi: false, + name: "complex", + open: "complex(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Copy renders the copy built-in function. +func Copy(dst Code, src Code) *Statement { + return newStatement().Copy(dst, src) +} + +// Copy renders the copy built-in function. +func (g *Group) Copy(dst Code, src Code) *Statement { + s := Copy(dst, src) + g.items = append(g.items, s) + return s +} + +// Copy renders the copy built-in function. +func (s *Statement) Copy(dst Code, src Code) *Statement { + g := &Group{ + close: ")", + items: []Code{dst, src}, + multi: false, + name: "copy", + open: "copy(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Delete renders the delete built-in function. +func Delete(m Code, key Code) *Statement { + return newStatement().Delete(m, key) +} + +// Delete renders the delete built-in function. +func (g *Group) Delete(m Code, key Code) *Statement { + s := Delete(m, key) + g.items = append(g.items, s) + return s +} + +// Delete renders the delete built-in function. +func (s *Statement) Delete(m Code, key Code) *Statement { + g := &Group{ + close: ")", + items: []Code{m, key}, + multi: false, + name: "delete", + open: "delete(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Imag renders the imag built-in function. +func Imag(c Code) *Statement { + return newStatement().Imag(c) +} + +// Imag renders the imag built-in function. +func (g *Group) Imag(c Code) *Statement { + s := Imag(c) + g.items = append(g.items, s) + return s +} + +// Imag renders the imag built-in function. +func (s *Statement) Imag(c Code) *Statement { + g := &Group{ + close: ")", + items: []Code{c}, + multi: false, + name: "imag", + open: "imag(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Len renders the len built-in function. +func Len(v Code) *Statement { + return newStatement().Len(v) +} + +// Len renders the len built-in function. +func (g *Group) Len(v Code) *Statement { + s := Len(v) + g.items = append(g.items, s) + return s +} + +// Len renders the len built-in function. +func (s *Statement) Len(v Code) *Statement { + g := &Group{ + close: ")", + items: []Code{v}, + multi: false, + name: "len", + open: "len(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Make renders the make built-in function. The final parameter of the make function is optional, so it is represented by a variadic parameter list. +func Make(args ...Code) *Statement { + return newStatement().Make(args...) +} + +// Make renders the make built-in function. The final parameter of the make function is optional, so it is represented by a variadic parameter list. +func (g *Group) Make(args ...Code) *Statement { + s := Make(args...) + g.items = append(g.items, s) + return s +} + +// Make renders the make built-in function. The final parameter of the make function is optional, so it is represented by a variadic parameter list. +func (s *Statement) Make(args ...Code) *Statement { + g := &Group{ + close: ")", + items: args, + multi: false, + name: "make", + open: "make(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// New renders the new built-in function. +func New(typ Code) *Statement { + return newStatement().New(typ) +} + +// New renders the new built-in function. +func (g *Group) New(typ Code) *Statement { + s := New(typ) + g.items = append(g.items, s) + return s +} + +// New renders the new built-in function. +func (s *Statement) New(typ Code) *Statement { + g := &Group{ + close: ")", + items: []Code{typ}, + multi: false, + name: "new", + open: "new(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Panic renders the panic built-in function. +func Panic(v Code) *Statement { + return newStatement().Panic(v) +} + +// Panic renders the panic built-in function. +func (g *Group) Panic(v Code) *Statement { + s := Panic(v) + g.items = append(g.items, s) + return s +} + +// Panic renders the panic built-in function. +func (s *Statement) Panic(v Code) *Statement { + g := &Group{ + close: ")", + items: []Code{v}, + multi: false, + name: "panic", + open: "panic(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Print renders the print built-in function. +func Print(args ...Code) *Statement { + return newStatement().Print(args...) +} + +// Print renders the print built-in function. +func (g *Group) Print(args ...Code) *Statement { + s := Print(args...) + g.items = append(g.items, s) + return s +} + +// Print renders the print built-in function. +func (s *Statement) Print(args ...Code) *Statement { + g := &Group{ + close: ")", + items: args, + multi: false, + name: "print", + open: "print(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// PrintFunc renders the print built-in function. +func PrintFunc(f func(*Group)) *Statement { + return newStatement().PrintFunc(f) +} + +// PrintFunc renders the print built-in function. +func (g *Group) PrintFunc(f func(*Group)) *Statement { + s := PrintFunc(f) + g.items = append(g.items, s) + return s +} + +// PrintFunc renders the print built-in function. +func (s *Statement) PrintFunc(f func(*Group)) *Statement { + g := &Group{ + close: ")", + multi: false, + name: "print", + open: "print(", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Println renders the println built-in function. +func Println(args ...Code) *Statement { + return newStatement().Println(args...) +} + +// Println renders the println built-in function. +func (g *Group) Println(args ...Code) *Statement { + s := Println(args...) + g.items = append(g.items, s) + return s +} + +// Println renders the println built-in function. +func (s *Statement) Println(args ...Code) *Statement { + g := &Group{ + close: ")", + items: args, + multi: false, + name: "println", + open: "println(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// PrintlnFunc renders the println built-in function. +func PrintlnFunc(f func(*Group)) *Statement { + return newStatement().PrintlnFunc(f) +} + +// PrintlnFunc renders the println built-in function. +func (g *Group) PrintlnFunc(f func(*Group)) *Statement { + s := PrintlnFunc(f) + g.items = append(g.items, s) + return s +} + +// PrintlnFunc renders the println built-in function. +func (s *Statement) PrintlnFunc(f func(*Group)) *Statement { + g := &Group{ + close: ")", + multi: false, + name: "println", + open: "println(", + separator: ",", + } + f(g) + *s = append(*s, g) + return s +} + +// Real renders the real built-in function. +func Real(c Code) *Statement { + return newStatement().Real(c) +} + +// Real renders the real built-in function. +func (g *Group) Real(c Code) *Statement { + s := Real(c) + g.items = append(g.items, s) + return s +} + +// Real renders the real built-in function. +func (s *Statement) Real(c Code) *Statement { + g := &Group{ + close: ")", + items: []Code{c}, + multi: false, + name: "real", + open: "real(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Recover renders the recover built-in function. +func Recover() *Statement { + return newStatement().Recover() +} + +// Recover renders the recover built-in function. +func (g *Group) Recover() *Statement { + s := Recover() + g.items = append(g.items, s) + return s +} + +// Recover renders the recover built-in function. +func (s *Statement) Recover() *Statement { + g := &Group{ + close: ")", + items: []Code{}, + multi: false, + name: "recover", + open: "recover(", + separator: ",", + } + *s = append(*s, g) + return s +} + +// Bool renders the bool identifier. +func Bool() *Statement { + return newStatement().Bool() +} + +// Bool renders the bool identifier. +func (g *Group) Bool() *Statement { + s := Bool() + g.items = append(g.items, s) + return s +} + +// Bool renders the bool identifier. +func (s *Statement) Bool() *Statement { + t := token{ + content: "bool", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Byte renders the byte identifier. +func Byte() *Statement { + // notest + return newStatement().Byte() +} + +// Byte renders the byte identifier. +func (g *Group) Byte() *Statement { + // notest + s := Byte() + g.items = append(g.items, s) + return s +} + +// Byte renders the byte identifier. +func (s *Statement) Byte() *Statement { + // notest + t := token{ + content: "byte", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Complex64 renders the complex64 identifier. +func Complex64() *Statement { + // notest + return newStatement().Complex64() +} + +// Complex64 renders the complex64 identifier. +func (g *Group) Complex64() *Statement { + // notest + s := Complex64() + g.items = append(g.items, s) + return s +} + +// Complex64 renders the complex64 identifier. +func (s *Statement) Complex64() *Statement { + // notest + t := token{ + content: "complex64", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Complex128 renders the complex128 identifier. +func Complex128() *Statement { + // notest + return newStatement().Complex128() +} + +// Complex128 renders the complex128 identifier. +func (g *Group) Complex128() *Statement { + // notest + s := Complex128() + g.items = append(g.items, s) + return s +} + +// Complex128 renders the complex128 identifier. +func (s *Statement) Complex128() *Statement { + // notest + t := token{ + content: "complex128", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Error renders the error identifier. +func Error() *Statement { + // notest + return newStatement().Error() +} + +// Error renders the error identifier. +func (g *Group) Error() *Statement { + // notest + s := Error() + g.items = append(g.items, s) + return s +} + +// Error renders the error identifier. +func (s *Statement) Error() *Statement { + // notest + t := token{ + content: "error", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Float32 renders the float32 identifier. +func Float32() *Statement { + // notest + return newStatement().Float32() +} + +// Float32 renders the float32 identifier. +func (g *Group) Float32() *Statement { + // notest + s := Float32() + g.items = append(g.items, s) + return s +} + +// Float32 renders the float32 identifier. +func (s *Statement) Float32() *Statement { + // notest + t := token{ + content: "float32", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Float64 renders the float64 identifier. +func Float64() *Statement { + // notest + return newStatement().Float64() +} + +// Float64 renders the float64 identifier. +func (g *Group) Float64() *Statement { + // notest + s := Float64() + g.items = append(g.items, s) + return s +} + +// Float64 renders the float64 identifier. +func (s *Statement) Float64() *Statement { + // notest + t := token{ + content: "float64", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Int renders the int identifier. +func Int() *Statement { + // notest + return newStatement().Int() +} + +// Int renders the int identifier. +func (g *Group) Int() *Statement { + // notest + s := Int() + g.items = append(g.items, s) + return s +} + +// Int renders the int identifier. +func (s *Statement) Int() *Statement { + // notest + t := token{ + content: "int", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Int8 renders the int8 identifier. +func Int8() *Statement { + // notest + return newStatement().Int8() +} + +// Int8 renders the int8 identifier. +func (g *Group) Int8() *Statement { + // notest + s := Int8() + g.items = append(g.items, s) + return s +} + +// Int8 renders the int8 identifier. +func (s *Statement) Int8() *Statement { + // notest + t := token{ + content: "int8", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Int16 renders the int16 identifier. +func Int16() *Statement { + // notest + return newStatement().Int16() +} + +// Int16 renders the int16 identifier. +func (g *Group) Int16() *Statement { + // notest + s := Int16() + g.items = append(g.items, s) + return s +} + +// Int16 renders the int16 identifier. +func (s *Statement) Int16() *Statement { + // notest + t := token{ + content: "int16", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Int32 renders the int32 identifier. +func Int32() *Statement { + // notest + return newStatement().Int32() +} + +// Int32 renders the int32 identifier. +func (g *Group) Int32() *Statement { + // notest + s := Int32() + g.items = append(g.items, s) + return s +} + +// Int32 renders the int32 identifier. +func (s *Statement) Int32() *Statement { + // notest + t := token{ + content: "int32", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Int64 renders the int64 identifier. +func Int64() *Statement { + // notest + return newStatement().Int64() +} + +// Int64 renders the int64 identifier. +func (g *Group) Int64() *Statement { + // notest + s := Int64() + g.items = append(g.items, s) + return s +} + +// Int64 renders the int64 identifier. +func (s *Statement) Int64() *Statement { + // notest + t := token{ + content: "int64", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Rune renders the rune identifier. +func Rune() *Statement { + // notest + return newStatement().Rune() +} + +// Rune renders the rune identifier. +func (g *Group) Rune() *Statement { + // notest + s := Rune() + g.items = append(g.items, s) + return s +} + +// Rune renders the rune identifier. +func (s *Statement) Rune() *Statement { + // notest + t := token{ + content: "rune", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// String renders the string identifier. +func String() *Statement { + // notest + return newStatement().String() +} + +// String renders the string identifier. +func (g *Group) String() *Statement { + // notest + s := String() + g.items = append(g.items, s) + return s +} + +// String renders the string identifier. +func (s *Statement) String() *Statement { + // notest + t := token{ + content: "string", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Uint renders the uint identifier. +func Uint() *Statement { + // notest + return newStatement().Uint() +} + +// Uint renders the uint identifier. +func (g *Group) Uint() *Statement { + // notest + s := Uint() + g.items = append(g.items, s) + return s +} + +// Uint renders the uint identifier. +func (s *Statement) Uint() *Statement { + // notest + t := token{ + content: "uint", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Uint8 renders the uint8 identifier. +func Uint8() *Statement { + // notest + return newStatement().Uint8() +} + +// Uint8 renders the uint8 identifier. +func (g *Group) Uint8() *Statement { + // notest + s := Uint8() + g.items = append(g.items, s) + return s +} + +// Uint8 renders the uint8 identifier. +func (s *Statement) Uint8() *Statement { + // notest + t := token{ + content: "uint8", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Uint16 renders the uint16 identifier. +func Uint16() *Statement { + // notest + return newStatement().Uint16() +} + +// Uint16 renders the uint16 identifier. +func (g *Group) Uint16() *Statement { + // notest + s := Uint16() + g.items = append(g.items, s) + return s +} + +// Uint16 renders the uint16 identifier. +func (s *Statement) Uint16() *Statement { + // notest + t := token{ + content: "uint16", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Uint32 renders the uint32 identifier. +func Uint32() *Statement { + // notest + return newStatement().Uint32() +} + +// Uint32 renders the uint32 identifier. +func (g *Group) Uint32() *Statement { + // notest + s := Uint32() + g.items = append(g.items, s) + return s +} + +// Uint32 renders the uint32 identifier. +func (s *Statement) Uint32() *Statement { + // notest + t := token{ + content: "uint32", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Uint64 renders the uint64 identifier. +func Uint64() *Statement { + // notest + return newStatement().Uint64() +} + +// Uint64 renders the uint64 identifier. +func (g *Group) Uint64() *Statement { + // notest + s := Uint64() + g.items = append(g.items, s) + return s +} + +// Uint64 renders the uint64 identifier. +func (s *Statement) Uint64() *Statement { + // notest + t := token{ + content: "uint64", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Uintptr renders the uintptr identifier. +func Uintptr() *Statement { + // notest + return newStatement().Uintptr() +} + +// Uintptr renders the uintptr identifier. +func (g *Group) Uintptr() *Statement { + // notest + s := Uintptr() + g.items = append(g.items, s) + return s +} + +// Uintptr renders the uintptr identifier. +func (s *Statement) Uintptr() *Statement { + // notest + t := token{ + content: "uintptr", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// True renders the true identifier. +func True() *Statement { + // notest + return newStatement().True() +} + +// True renders the true identifier. +func (g *Group) True() *Statement { + // notest + s := True() + g.items = append(g.items, s) + return s +} + +// True renders the true identifier. +func (s *Statement) True() *Statement { + // notest + t := token{ + content: "true", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// False renders the false identifier. +func False() *Statement { + // notest + return newStatement().False() +} + +// False renders the false identifier. +func (g *Group) False() *Statement { + // notest + s := False() + g.items = append(g.items, s) + return s +} + +// False renders the false identifier. +func (s *Statement) False() *Statement { + // notest + t := token{ + content: "false", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Iota renders the iota identifier. +func Iota() *Statement { + // notest + return newStatement().Iota() +} + +// Iota renders the iota identifier. +func (g *Group) Iota() *Statement { + // notest + s := Iota() + g.items = append(g.items, s) + return s +} + +// Iota renders the iota identifier. +func (s *Statement) Iota() *Statement { + // notest + t := token{ + content: "iota", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Nil renders the nil identifier. +func Nil() *Statement { + // notest + return newStatement().Nil() +} + +// Nil renders the nil identifier. +func (g *Group) Nil() *Statement { + // notest + s := Nil() + g.items = append(g.items, s) + return s +} + +// Nil renders the nil identifier. +func (s *Statement) Nil() *Statement { + // notest + t := token{ + content: "nil", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Err renders the err identifier. +func Err() *Statement { + // notest + return newStatement().Err() +} + +// Err renders the err identifier. +func (g *Group) Err() *Statement { + // notest + s := Err() + g.items = append(g.items, s) + return s +} + +// Err renders the err identifier. +func (s *Statement) Err() *Statement { + // notest + t := token{ + content: "err", + typ: identifierToken, + } + *s = append(*s, t) + return s +} + +// Break renders the break keyword. +func Break() *Statement { + // notest + return newStatement().Break() +} + +// Break renders the break keyword. +func (g *Group) Break() *Statement { + // notest + s := Break() + g.items = append(g.items, s) + return s +} + +// Break renders the break keyword. +func (s *Statement) Break() *Statement { + // notest + t := token{ + content: "break", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Default renders the default keyword. +func Default() *Statement { + // notest + return newStatement().Default() +} + +// Default renders the default keyword. +func (g *Group) Default() *Statement { + // notest + s := Default() + g.items = append(g.items, s) + return s +} + +// Default renders the default keyword. +func (s *Statement) Default() *Statement { + // notest + t := token{ + content: "default", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Func renders the func keyword. +func Func() *Statement { + // notest + return newStatement().Func() +} + +// Func renders the func keyword. +func (g *Group) Func() *Statement { + // notest + s := Func() + g.items = append(g.items, s) + return s +} + +// Func renders the func keyword. +func (s *Statement) Func() *Statement { + // notest + t := token{ + content: "func", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Select renders the select keyword. +func Select() *Statement { + // notest + return newStatement().Select() +} + +// Select renders the select keyword. +func (g *Group) Select() *Statement { + // notest + s := Select() + g.items = append(g.items, s) + return s +} + +// Select renders the select keyword. +func (s *Statement) Select() *Statement { + // notest + t := token{ + content: "select", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Chan renders the chan keyword. +func Chan() *Statement { + // notest + return newStatement().Chan() +} + +// Chan renders the chan keyword. +func (g *Group) Chan() *Statement { + // notest + s := Chan() + g.items = append(g.items, s) + return s +} + +// Chan renders the chan keyword. +func (s *Statement) Chan() *Statement { + // notest + t := token{ + content: "chan", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Else renders the else keyword. +func Else() *Statement { + // notest + return newStatement().Else() +} + +// Else renders the else keyword. +func (g *Group) Else() *Statement { + // notest + s := Else() + g.items = append(g.items, s) + return s +} + +// Else renders the else keyword. +func (s *Statement) Else() *Statement { + // notest + t := token{ + content: "else", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Const renders the const keyword. +func Const() *Statement { + // notest + return newStatement().Const() +} + +// Const renders the const keyword. +func (g *Group) Const() *Statement { + // notest + s := Const() + g.items = append(g.items, s) + return s +} + +// Const renders the const keyword. +func (s *Statement) Const() *Statement { + // notest + t := token{ + content: "const", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Fallthrough renders the fallthrough keyword. +func Fallthrough() *Statement { + // notest + return newStatement().Fallthrough() +} + +// Fallthrough renders the fallthrough keyword. +func (g *Group) Fallthrough() *Statement { + // notest + s := Fallthrough() + g.items = append(g.items, s) + return s +} + +// Fallthrough renders the fallthrough keyword. +func (s *Statement) Fallthrough() *Statement { + // notest + t := token{ + content: "fallthrough", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Type renders the type keyword. +func Type() *Statement { + // notest + return newStatement().Type() +} + +// Type renders the type keyword. +func (g *Group) Type() *Statement { + // notest + s := Type() + g.items = append(g.items, s) + return s +} + +// Type renders the type keyword. +func (s *Statement) Type() *Statement { + // notest + t := token{ + content: "type", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Continue renders the continue keyword. +func Continue() *Statement { + // notest + return newStatement().Continue() +} + +// Continue renders the continue keyword. +func (g *Group) Continue() *Statement { + // notest + s := Continue() + g.items = append(g.items, s) + return s +} + +// Continue renders the continue keyword. +func (s *Statement) Continue() *Statement { + // notest + t := token{ + content: "continue", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Var renders the var keyword. +func Var() *Statement { + // notest + return newStatement().Var() +} + +// Var renders the var keyword. +func (g *Group) Var() *Statement { + // notest + s := Var() + g.items = append(g.items, s) + return s +} + +// Var renders the var keyword. +func (s *Statement) Var() *Statement { + // notest + t := token{ + content: "var", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Goto renders the goto keyword. +func Goto() *Statement { + // notest + return newStatement().Goto() +} + +// Goto renders the goto keyword. +func (g *Group) Goto() *Statement { + // notest + s := Goto() + g.items = append(g.items, s) + return s +} + +// Goto renders the goto keyword. +func (s *Statement) Goto() *Statement { + // notest + t := token{ + content: "goto", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Defer renders the defer keyword. +func Defer() *Statement { + // notest + return newStatement().Defer() +} + +// Defer renders the defer keyword. +func (g *Group) Defer() *Statement { + // notest + s := Defer() + g.items = append(g.items, s) + return s +} + +// Defer renders the defer keyword. +func (s *Statement) Defer() *Statement { + // notest + t := token{ + content: "defer", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Go renders the go keyword. +func Go() *Statement { + // notest + return newStatement().Go() +} + +// Go renders the go keyword. +func (g *Group) Go() *Statement { + // notest + s := Go() + g.items = append(g.items, s) + return s +} + +// Go renders the go keyword. +func (s *Statement) Go() *Statement { + // notest + t := token{ + content: "go", + typ: keywordToken, + } + *s = append(*s, t) + return s +} + +// Range renders the range keyword. +func Range() *Statement { + // notest + return newStatement().Range() +} + +// Range renders the range keyword. +func (g *Group) Range() *Statement { + // notest + s := Range() + g.items = append(g.items, s) + return s +} + +// Range renders the range keyword. +func (s *Statement) Range() *Statement { + // notest + t := token{ + content: "range", + typ: keywordToken, + } + *s = append(*s, t) + return s +} diff --git a/vendor/github.com/dave/jennifer/jen/generated_test.go b/vendor/github.com/dave/jennifer/jen/generated_test.go new file mode 100644 index 00000000..fce14c70 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/generated_test.go @@ -0,0 +1,808 @@ +package jen_test + +import ( + "testing" + + . "github.com/dave/jennifer/jen" +) + +var gencases = []tc{ + { + desc: `bool group`, + code: BlockFunc(func(g *Group) { + g.Bool() + }), + expect: `{ + bool + }`, + }, + { + desc: `recover func`, + code: Recover(), + expect: `recover()`, + }, + { + desc: `recover statement`, + code: Null().Recover(), + expect: `recover()`, + }, + { + desc: `recover group`, + code: BlockFunc(func(g *Group) { + g.Recover() + }), + expect: `{ + recover() + }`, + }, + { + desc: `real func`, + code: Real(Id("a")), + expect: `real(a)`, + }, + { + desc: `real statement`, + code: Null().Real(Id("a")), + expect: `real(a)`, + }, + { + desc: `real group`, + code: BlockFunc(func(g *Group) { + g.Real(Id("a")) + }), + expect: `{ + real(a) + }`, + }, + { + desc: `printlnfunc func`, + code: PrintlnFunc(func(g *Group) { g.Id("a") }), + expect: `println(a)`, + }, + { + desc: `printlnfunc statement`, + code: Null().PrintlnFunc(func(g *Group) { g.Id("a") }), + expect: `println(a)`, + }, + { + desc: `printlnfunc group`, + code: BlockFunc(func(bg *Group) { + bg.PrintlnFunc(func(pg *Group) { pg.Id("a") }) + }), + expect: `{ + println(a) + }`, + }, + { + desc: `println func`, + code: Println(Id("a")), + expect: `println(a)`, + }, + { + desc: `println statement`, + code: Null().Println(Id("a")), + expect: `println(a)`, + }, + { + desc: `println group`, + code: BlockFunc(func(g *Group) { + g.Println(Id("a")) + }), + expect: `{ + println(a) + }`, + }, + { + desc: `printfunc func`, + code: PrintFunc(func(g *Group) { g.Id("a") }), + expect: `print(a)`, + }, + { + desc: `printfunc statement`, + code: Null().PrintFunc(func(g *Group) { g.Id("a") }), + expect: `print(a)`, + }, + { + desc: `printfunc group`, + code: BlockFunc(func(bg *Group) { + bg.PrintFunc(func(pg *Group) { pg.Id("a") }) + }), + expect: `{ + print(a) + }`, + }, + { + desc: `print func`, + code: Print(Id("a")), + expect: `print(a)`, + }, + { + desc: `print statement`, + code: Null().Print(Id("a")), + expect: `print(a)`, + }, + { + desc: `print group`, + code: BlockFunc(func(g *Group) { + g.Print(Id("a")) + }), + expect: `{ + print(a) + }`, + }, + { + desc: `panic func`, + code: Panic(Id("a")), + expect: `panic(a)`, + }, + { + desc: `panic statement`, + code: Null().Panic(Id("a")), + expect: `panic(a)`, + }, + { + desc: `panic group`, + code: BlockFunc(func(g *Group) { + g.Panic(Id("a")) + }), + expect: `{ + panic(a) + }`, + }, + { + desc: `new func`, + code: New(Id("a")), + expect: `new(a)`, + }, + { + desc: `new statement`, + code: Id("a").Op(":=").New(Id("a")), + expect: `a := new(a)`, + }, + { + desc: `new group`, + code: BlockFunc(func(g *Group) { + g.New(Id("a")) + }), + expect: `{ + new(a) + }`, + }, + { + desc: `make func`, + code: Make(Id("a")), + expect: `make(a)`, + }, + { + desc: `make statement`, + code: Id("a").Op(":=").Make(Id("a")), + expect: `a := make(a)`, + }, + { + desc: `make group`, + code: BlockFunc(func(g *Group) { + g.Make(Id("a")) + }), + expect: `{ + make(a) + }`, + }, + { + desc: `len func`, + code: Len(Id("a")), + expect: `len(a)`, + }, + { + desc: `len statement`, + code: Id("a").Op(":=").Len(Id("a")), + expect: `a := len(a)`, + }, + { + desc: `len group`, + code: BlockFunc(func(g *Group) { + g.Len(Id("a")) + }), + expect: `{ + len(a) + }`, + }, + { + desc: `imag func`, + code: Imag(Id("a")), + expect: `imag(a)`, + }, + { + desc: `imag statement`, + code: Id("a").Op(":=").Imag(Id("a")), + expect: `a := imag(a)`, + }, + { + desc: `imag group`, + code: BlockFunc(func(g *Group) { + g.Imag(Id("a")) + }), + expect: `{ + imag(a) + }`, + }, + { + desc: `delete func`, + code: Delete(Id("a"), Id("b")), + expect: `delete(a, b)`, + }, + { + desc: `delete statement`, + code: Null().Delete(Id("a"), Id("b")), + expect: `delete(a, b)`, + }, + { + desc: `delete group`, + code: BlockFunc(func(g *Group) { + g.Delete(Id("a"), Id("b")) + }), + expect: `{ + delete(a, b) + }`, + }, + { + desc: `copy func`, + code: Copy(Id("a"), Id("b")), + expect: `copy(a, b)`, + }, + { + desc: `copy statement`, + code: Id("a").Op(":=").Copy(Id("a"), Id("b")), + expect: `a := copy(a, b)`, + }, + { + desc: `copy group`, + code: BlockFunc(func(g *Group) { + g.Copy(Id("a"), Id("b")) + }), + expect: `{ + copy(a, b) + }`, + }, + { + desc: `complex func`, + code: Complex(Id("a"), Id("b")), + expect: `complex(a, b)`, + }, + { + desc: `complex statement`, + code: Id("a").Op(":=").Complex(Id("a"), Id("b")), + expect: `a := complex(a, b)`, + }, + { + desc: `complex group`, + code: BlockFunc(func(g *Group) { + g.Complex(Id("a"), Id("b")) + }), + expect: `{ + complex(a, b) + }`, + }, + { + desc: `close group`, + code: BlockFunc(func(g *Group) { g.Close(Id("a")) }), + expect: `{ + close(a) + }`, + }, + { + desc: `cap func`, + code: Cap(Id("a")), + expect: `cap(a)`, + }, + { + desc: `cap statement`, + code: Id("a").Op(":=").Cap(Id("b")), + expect: `a := cap(b)`, + }, + { + desc: `cap group`, + code: BlockFunc(func(g *Group) { + g.Cap(Id("a")) + }), + expect: `{ + cap(a) + }`, + }, + { + desc: `append group`, + code: BlockFunc(func(g *Group) { + g.Append(Id("a")) + }), + expect: `{ + append(a) + }`, + }, + { + desc: `appendfunc statement`, + code: Id("a").Op("=").AppendFunc(func(ag *Group) { ag.Id("a") }), + expect: `a = append(a)`, + }, + { + desc: `appendfunc func`, + code: AppendFunc(func(ag *Group) { ag.Id("a") }), + expect: `append(a)`, + }, + { + desc: `appendfunc group`, + code: BlockFunc(func(bg *Group) { + bg.AppendFunc(func(ag *Group) { ag.Id("a") }) + }), + expect: `{ + append(a) + }`, + }, + { + desc: `casefunc group`, + code: Switch().BlockFunc(func(g *Group) { + g.CaseFunc(func(g *Group) { g.Id("a") }).Block() + }), + expect: `switch { + case a: + }`, + }, + { + desc: `case group`, + code: Switch().BlockFunc(func(g *Group) { + g.Case(Id("a")).Block() + }), + expect: `switch { + case a: + }`, + }, + { + desc: `structfunc statement`, + code: Id("a").Op(":=").StructFunc(func(g *Group) {}).Values(), + expect: `a := struct{}{}`, + }, + { + desc: `structfunc group`, + // Don't do this! ListFunc used to kludge Group.Struct usage + // without syntax error. + code: Id("a").Op(":=").ListFunc(func(g *Group) { g.StructFunc(func(g *Group) {}) }).Values(), + expect: `a := struct{}{}`, + }, + { + desc: `structfunc func`, + code: Id("a").Op(":=").Add(StructFunc(func(g *Group) {})).Values(), + expect: `a := struct{}{}`, + }, + { + desc: `struct group`, + // Don't do this! ListFunc used to kludge Group.Struct usage + // without syntax error. + code: Id("a").Op(":=").ListFunc(func(g *Group) { g.Struct() }).Values(), + expect: `a := struct{}{}`, + }, + { + desc: `struct func`, + code: Id("a").Op(":=").Add(Struct()).Values(), + expect: `a := struct{}{}`, + }, + { + desc: `interfacefunc func`, + code: Id("a").Assert(InterfaceFunc(func(g *Group) { + g.Id("a").Call().Int() + g.Id("b").Call().Int() + })), + expect: `a.(interface{ + a() int + b() int + })`, + }, + { + desc: `interfacefunc statement`, + code: Id("a").Assert(Null().InterfaceFunc(func(g *Group) { + g.Id("a").Call().Int() + g.Id("b").Call().Int() + })), + expect: `a.(interface{ + a() int + b() int + })`, + }, + { + desc: `interfacefunc group`, + // Don't do this! ListFunc used to kludge Group.InterfaceFunc usage + // without syntax error. + code: Id("a").Assert(ListFunc(func(lg *Group) { + lg.InterfaceFunc(func(ig *Group) { + ig.Id("a").Call().Int() + ig.Id("b").Call().Int() + }) + })), + expect: `a.(interface{ + a() int + b() int + })`, + }, + { + desc: `interface func`, + code: Interface().Parens(Id("a")), + expect: `interface{}(a)`, + }, + { + desc: `interface group`, + code: BlockFunc(func(g *Group) { + g.Interface().Parens(Id("a")) + }), + expect: `{ + interface{}(a) + }`, + }, + { + desc: `interface statement`, + code: Null().Interface().Parens(Id("a")), + expect: `interface{}(a)`, + }, + { + desc: `switchfunc func`, + code: SwitchFunc(func(rg *Group) { + rg.Id("a") + }).Block(), + expect: `switch a {}`, + }, + { + desc: `switchfunc statement`, + code: Null().SwitchFunc(func(rg *Group) { + rg.Id("a") + }).Block(), + expect: `switch a { + }`, + }, + { + desc: `switchfunc group`, + code: BlockFunc(func(bg *Group) { + bg.SwitchFunc(func(rg *Group) { + rg.Id("a") + }).Block() + }), + expect: `{ + switch a { + } + }`, + }, + { + desc: `switch group`, + code: BlockFunc(func(bg *Group) { + bg.Switch().Block() + }), + expect: `{ + switch { + } + }`, + }, + { + desc: `forfunc func`, + code: ForFunc(func(rg *Group) { + rg.Id("a") + }).Block(), + expect: `for a {}`, + }, + { + desc: `forfunc statement`, + code: Null().ForFunc(func(rg *Group) { + rg.Id("a") + }).Block(), + expect: `for a { + }`, + }, + { + desc: `forfunc group`, + code: BlockFunc(func(bg *Group) { + bg.ForFunc(func(rg *Group) { + rg.Id("a") + }).Block() + }), + expect: `{ + for a { + } + }`, + }, + { + desc: `for group`, + code: BlockFunc(func(g *Group) { + g.For(Id("a")).Block() + }), + expect: `{ + for a {} + }`, + }, + { + desc: `returnfunc func`, + code: ReturnFunc(func(rg *Group) { + rg.Lit(1) + rg.Lit(2) + }), + expect: `return 1, 2`, + }, + { + desc: `returnfunc statement`, + code: Empty().ReturnFunc(func(rg *Group) { + rg.Lit(1) + rg.Lit(2) + }), + expect: `return 1, 2`, + }, + { + desc: `returnfunc group`, + code: BlockFunc(func(bg *Group) { + bg.ReturnFunc(func(rg *Group) { + rg.Lit(1) + rg.Lit(2) + }) + }), + expect: `{ + return 1, 2 + }`, + }, + { + desc: `return group`, + code: BlockFunc(func(g *Group) { + g.Return() + }), + expect: `{ + return + }`, + }, + { + desc: `iffunc group`, + code: BlockFunc(func(bg *Group) { + bg.IfFunc(func(ig *Group) { + ig.Id("a") + }).Block() + }), + expect: `{ + if a {} + }`, + }, + { + desc: `iffunc func`, + code: IfFunc(func(ig *Group) { + ig.Id("a") + }).Block(), + expect: `if a {}`, + }, + { + desc: `iffunc statement`, + code: Null().IfFunc(func(ig *Group) { + ig.Id("a") + }).Block(), + expect: `if a {}`, + }, + { + desc: `if group`, + code: BlockFunc(func(g *Group) { g.If(Id("a")).Block() }), + expect: `{ + if a {} + }`, + }, + { + desc: `map group`, + code: BlockFunc(func(g *Group) { g.Map(Int()).Int().Values(Dict{Lit(1): Lit(1)}) }), + expect: `{ + map[int]int{1:1} + }`, + }, + { + desc: `assert group`, + // Don't do this! ListFunc used to kludge Group.Assert usage without + // syntax error. + code: Id("a").ListFunc(func(g *Group) { g.Assert(Id("b")) }), + expect: `a.(b)`, + }, + { + desc: `assert func`, + code: Id("a").Add(Assert(Id("b"))), + expect: `a.(b)`, + }, + { + desc: `paramsfunc group`, + // Don't do this! ListFunc used to kludge Group.ParamsFunc usage without + // syntax error. + code: Id("a").ListFunc(func(lg *Group) { lg.ParamsFunc(func(cg *Group) { cg.Lit(1) }) }), + expect: `a(1)`, + }, + { + desc: `paramsfunc func`, + code: Id("a").Add(ParamsFunc(func(g *Group) { g.Lit(1) })), + expect: `a(1)`, + }, + { + desc: `paramsfunc statement`, + code: Id("a").ParamsFunc(func(g *Group) { g.Lit(1) }), + expect: `a(1)`, + }, + { + desc: `params group`, + // Don't do this! ListFunc used to kludge Group.Params usage without + // syntax error. + code: Id("a").ListFunc(func(g *Group) { g.Params(Lit(1)) }), + expect: `a(1)`, + }, + { + desc: `params func`, + code: Id("a").Add(Params(Lit(1))), + expect: `a(1)`, + }, + { + desc: `callfunc group`, + // Don't do this! ListFunc used to kludge Group.CallFunc usage without + // syntax error. + code: Id("a").ListFunc(func(lg *Group) { lg.CallFunc(func(cg *Group) { cg.Lit(1) }) }), + expect: `a(1)`, + }, + { + desc: `callfunc func`, + code: Id("a").Add(CallFunc(func(g *Group) { g.Lit(1) })), + expect: `a(1)`, + }, + { + desc: `call group`, + // Don't do this! ListFunc used to kludge Group.Call usage without + // syntax error. + code: Id("a").ListFunc(func(g *Group) { g.Call(Lit(1)) }), + expect: `a(1)`, + }, + { + desc: `call func`, + code: Id("a").Add(Call(Lit(1))), + expect: `a(1)`, + }, + { + desc: `defsfunc statement`, + code: Const().DefsFunc(func(g *Group) { g.Id("a").Op("=").Lit(1) }), + expect: `const ( + a = 1 + )`, + }, + { + desc: `defsfunc func`, + code: Const().Add(DefsFunc(func(g *Group) { g.Id("a").Op("=").Lit(1) })), + expect: `const ( + a = 1 + )`, + }, + { + desc: `defsfunc group`, + // Don't do this! ListFunc used to kludge Group.DefsFunc usage without + // syntax error. + code: Const().ListFunc(func(lg *Group) { lg.DefsFunc(func(dg *Group) { dg.Id("a").Op("=").Lit(1) }) }), + expect: `const ( + a = 1 + )`, + }, + { + desc: `defs group`, + // Don't do this! ListFunc used to kludge Group.Defs usage without + // syntax error. + code: Const().ListFunc(func(g *Group) { g.Defs(Id("a").Op("=").Lit(1)) }), + expect: `const ( + a = 1 + )`, + }, + { + desc: `defs func`, + code: Const().Add(Defs(Id("a").Op("=").Lit(1))), + expect: `const ( + a = 1 + )`, + }, + { + desc: `blockfunc group`, + code: BlockFunc(func(g *Group) { g.BlockFunc(func(g *Group) {}) }), + expect: `{{}}`, + }, + { + desc: `block group`, + code: BlockFunc(func(g *Group) { g.Block() }), + expect: `{{}}`, + }, + { + desc: `indexfunc group`, + code: BlockFunc(func(g *Group) { g.IndexFunc(func(g *Group) { g.Lit(1) }).Int().Values(Lit(1)) }), + expect: `{[1]int{1}}`, + }, + { + desc: `indexfunc statement`, + code: Id("a").IndexFunc(func(g *Group) { g.Lit(1) }), + expect: `a[1]`, + }, + { + desc: `indexfunc func`, + code: Id("a").Add(IndexFunc(func(g *Group) { g.Lit(1) })), + expect: `a[1]`, + }, + { + desc: `index group`, + code: BlockFunc(func(g *Group) { g.Index(Lit(1)).Int().Values(Lit(1)) }), + expect: `{[1]int{1}}`, + }, + { + desc: `index func`, + code: Id("a").Add(Index(Lit(1))), + expect: `a[1]`, + }, + { + desc: `valuesfunc func`, + code: ValuesFunc(func(vg *Group) { + vg.Lit(1) + }), + expect: `{1}`, + }, + { + desc: `valuesfunc group`, + code: BlockFunc(func(bg *Group) { + bg.ValuesFunc(func(vg *Group) { + vg.Lit(1) + }) + }), + expect: `{ + {1} + }`, + }, + { + desc: `values group`, + code: BlockFunc(func(g *Group) { + g.Values(Lit(1)) + }), + expect: `{ + {1} + }`, + }, + { + desc: `listfunc statement`, + code: Add(Null()).ListFunc(func(lg *Group) { + lg.Id("a") + lg.Id("b") + }).Op("=").Id("c"), + expect: `a, b = c`, + }, + { + desc: `listfunc func`, + code: ListFunc(func(lg *Group) { + lg.Id("a") + lg.Id("b") + }).Op("=").Id("c"), + expect: `a, b = c`, + }, + { + desc: `listfunc group`, + code: BlockFunc(func(bg *Group) { + bg.ListFunc(func(lg *Group) { + lg.Id("a") + lg.Id("b") + }).Op("=").Id("c") + }), + expect: `{ + a, b = c + }`, + }, + { + desc: `list group`, + code: BlockFunc(func(g *Group) { g.List(Id("a"), Id("b")).Op("=").Id("c") }), + expect: `{ + a, b = c + }`, + }, + { + desc: `parens func`, + code: Parens(Lit(1)), + expect: `(1)`, + }, + { + desc: `parens group`, + code: BlockFunc(func(g *Group) { g.Parens(Lit(1)) }), + expect: `{ + (1) + }`, + }, +} + +func TestGen(t *testing.T) { + caseTester(t, gencases) +} diff --git a/vendor/github.com/dave/jennifer/jen/group.go b/vendor/github.com/dave/jennifer/jen/group.go new file mode 100644 index 00000000..0b85c901 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/group.go @@ -0,0 +1,147 @@ +package jen + +import ( + "bytes" + "fmt" + "go/format" + "io" +) + +// Group represents a list of Code items, separated by tokens with an optional +// open and close token. +type Group struct { + name string + items []Code + open string + close string + separator string + multi bool +} + +func (g *Group) isNull(f *File) bool { + if g == nil { + return true + } + if g.open != "" || g.close != "" { + return false + } + for _, c := range g.items { + if !c.isNull(f) { + return false + } + } + return true +} + +func (g *Group) render(f *File, w io.Writer, s *Statement) error { + if g.name == "block" && s != nil { + // Special CaseBlock format for then the previous item in the statement + // is a Case group or the default keyword. + prev := s.previous(g) + grp, isGrp := prev.(*Group) + tkn, isTkn := prev.(token) + if isGrp && grp.name == "case" || isTkn && tkn.content == "default" { + g.open = "" + g.close = "" + } + } + if g.open != "" { + if _, err := w.Write([]byte(g.open)); err != nil { + return err + } + } + isNull, err := g.renderItems(f, w) + if err != nil { + return err + } + if !isNull && g.multi && g.close != "" { + // For multi-line blocks with a closing token, we insert a new line after the last item (but + // not if all items were null). This is to ensure that if the statement finishes with a comment, + // the closing token is not commented out. + s := "\n" + if g.separator == "," { + // We also insert add trailing comma if the separator was ",". + s = ",\n" + } + if _, err := w.Write([]byte(s)); err != nil { + return err + } + } + if g.close != "" { + if _, err := w.Write([]byte(g.close)); err != nil { + return err + } + } + return nil +} + +func (g *Group) renderItems(f *File, w io.Writer) (isNull bool, err error) { + first := true + for _, code := range g.items { + if pt, ok := code.(token); ok && pt.typ == packageToken { + // Special case for package tokens in Qual groups - for dot-imports, the package token + // will be null, so will not render and will not be registered in the imports block. + // This ensures all packageTokens that are rendered are registered. + f.register(pt.content.(string)) + } + if code == nil || code.isNull(f) { + // Null() token produces no output but also + // no separator. Empty() token products no + // output but adds a separator. + continue + } + if g.name == "values" { + if _, ok := code.(Dict); ok && len(g.items) > 1 { + panic("Error in Values: if Dict is used, must be one item only") + } + } + if !first && g.separator != "" { + // The separator token is added before each non-null item, but not before the first item. + if _, err := w.Write([]byte(g.separator)); err != nil { + return false, err + } + } + if g.multi { + // For multi-line blocks, we insert a new line before each non-null item. + if _, err := w.Write([]byte("\n")); err != nil { + return false, err + } + } + if err := code.render(f, w, nil); err != nil { + return false, err + } + first = false + } + return first, nil +} + +// Render renders the Group to the provided writer. +func (g *Group) Render(writer io.Writer) error { + return g.RenderWithFile(writer, NewFile("")) +} + +// GoString renders the Group for testing. Any error will cause a panic. +func (g *Group) GoString() string { + buf := bytes.Buffer{} + if err := g.Render(&buf); err != nil { + panic(err) + } + return buf.String() +} + +// RenderWithFile renders the Group to the provided writer, using imports from the provided file. +func (g *Group) RenderWithFile(writer io.Writer, file *File) error { + buf := &bytes.Buffer{} + if err := g.render(file, buf, nil); err != nil { + return err + } + b, err := format.Source(buf.Bytes()) + if err != nil { + return fmt.Errorf("Error %s while formatting source:\n%s", err, buf.String()) + } + if _, err := writer.Write(b); err != nil { + return err + } + return nil +} + diff --git a/vendor/github.com/dave/jennifer/jen/group_test.go b/vendor/github.com/dave/jennifer/jen/group_test.go new file mode 100644 index 00000000..0e9489e4 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/group_test.go @@ -0,0 +1,35 @@ +package jen_test + +import ( + "bytes" + "testing" + + . "github.com/dave/jennifer/jen" +) + +func TestGroup_Render(t *testing.T) { + file := NewFile("main") + file.ImportAlias("fmt", "fmtalias") + + var g *Group + BlockFunc(func(group *Group) { + g = group + }) + + g.Qual("fmt", "Errorf").Call(Lit("error")) + + expect := `{ + fmtalias.Errorf("error") +}` + + var got bytes.Buffer + + err := g.RenderWithFile(&got, file) + if err != nil { + t.Fatal(err) + } + + if got.String() != expect { + t.Fatalf("Got: %v, expect: %v", got.String(), expect) + } +} diff --git a/vendor/github.com/dave/jennifer/jen/hints.go b/vendor/github.com/dave/jennifer/jen/hints.go new file mode 100644 index 00000000..7bc307a6 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/hints.go @@ -0,0 +1,273 @@ +// This file is generated - do not edit. + +package jen + +// standardLibraryHints contains package name hints +var standardLibraryHints = map[string]string{ + "archive/tar": "tar", + "archive/zip": "zip", + "bufio": "bufio", + "builtin": "builtin", + "bytes": "bytes", + "cmd/asm/internal/arch": "arch", + "cmd/asm/internal/asm": "asm", + "cmd/asm/internal/flags": "flags", + "cmd/asm/internal/lex": "lex", + "cmd/compile/internal/amd64": "amd64", + "cmd/compile/internal/arm": "arm", + "cmd/compile/internal/arm64": "arm64", + "cmd/compile/internal/gc": "gc", + "cmd/compile/internal/mips": "mips", + "cmd/compile/internal/mips64": "mips64", + "cmd/compile/internal/ppc64": "ppc64", + "cmd/compile/internal/s390x": "s390x", + "cmd/compile/internal/ssa": "ssa", + "cmd/compile/internal/syntax": "syntax", + "cmd/compile/internal/test": "test", + "cmd/compile/internal/types": "types", + "cmd/compile/internal/wasm": "wasm", + "cmd/compile/internal/x86": "x86", + "cmd/go/internal/base": "base", + "cmd/go/internal/bug": "bug", + "cmd/go/internal/cache": "cache", + "cmd/go/internal/cfg": "cfg", + "cmd/go/internal/clean": "clean", + "cmd/go/internal/cmdflag": "cmdflag", + "cmd/go/internal/dirhash": "dirhash", + "cmd/go/internal/doc": "doc", + "cmd/go/internal/envcmd": "envcmd", + "cmd/go/internal/fix": "fix", + "cmd/go/internal/fmtcmd": "fmtcmd", + "cmd/go/internal/generate": "generate", + "cmd/go/internal/get": "get", + "cmd/go/internal/help": "help", + "cmd/go/internal/imports": "imports", + "cmd/go/internal/list": "list", + "cmd/go/internal/load": "load", + "cmd/go/internal/modcmd": "modcmd", + "cmd/go/internal/modconv": "modconv", + "cmd/go/internal/modfetch": "modfetch", + "cmd/go/internal/modfetch/codehost": "codehost", + "cmd/go/internal/modfile": "modfile", + "cmd/go/internal/modget": "modget", + "cmd/go/internal/modinfo": "modinfo", + "cmd/go/internal/modload": "modload", + "cmd/go/internal/module": "module", + "cmd/go/internal/mvs": "mvs", + "cmd/go/internal/par": "par", + "cmd/go/internal/run": "run", + "cmd/go/internal/search": "search", + "cmd/go/internal/semver": "semver", + "cmd/go/internal/str": "str", + "cmd/go/internal/test": "test", + "cmd/go/internal/tool": "tool", + "cmd/go/internal/txtar": "txtar", + "cmd/go/internal/version": "version", + "cmd/go/internal/vet": "vet", + "cmd/go/internal/web": "web", + "cmd/go/internal/web2": "web2", + "cmd/go/internal/webtest": "webtest", + "cmd/go/internal/work": "work", + "cmd/internal/bio": "bio", + "cmd/internal/browser": "browser", + "cmd/internal/buildid": "buildid", + "cmd/internal/dwarf": "dwarf", + "cmd/internal/edit": "edit", + "cmd/internal/gcprog": "gcprog", + "cmd/internal/goobj": "goobj", + "cmd/internal/obj": "obj", + "cmd/internal/obj/arm": "arm", + "cmd/internal/obj/arm64": "arm64", + "cmd/internal/obj/mips": "mips", + "cmd/internal/obj/ppc64": "ppc64", + "cmd/internal/obj/s390x": "s390x", + "cmd/internal/obj/wasm": "wasm", + "cmd/internal/obj/x86": "x86", + "cmd/internal/objabi": "objabi", + "cmd/internal/objfile": "objfile", + "cmd/internal/src": "src", + "cmd/internal/sys": "sys", + "cmd/internal/test2json": "test2json", + "cmd/link/internal/amd64": "amd64", + "cmd/link/internal/arm": "arm", + "cmd/link/internal/arm64": "arm64", + "cmd/link/internal/ld": "ld", + "cmd/link/internal/loadelf": "loadelf", + "cmd/link/internal/loadmacho": "loadmacho", + "cmd/link/internal/loadpe": "loadpe", + "cmd/link/internal/mips": "mips", + "cmd/link/internal/mips64": "mips64", + "cmd/link/internal/objfile": "objfile", + "cmd/link/internal/ppc64": "ppc64", + "cmd/link/internal/s390x": "s390x", + "cmd/link/internal/sym": "sym", + "cmd/link/internal/wasm": "wasm", + "cmd/link/internal/x86": "x86", + "cmd/vet/internal/cfg": "cfg", + "cmd/vet/internal/whitelist": "whitelist", + "compress/bzip2": "bzip2", + "compress/flate": "flate", + "compress/gzip": "gzip", + "compress/lzw": "lzw", + "compress/zlib": "zlib", + "container/heap": "heap", + "container/list": "list", + "container/ring": "ring", + "context": "context", + "crypto": "crypto", + "crypto/aes": "aes", + "crypto/cipher": "cipher", + "crypto/des": "des", + "crypto/dsa": "dsa", + "crypto/ecdsa": "ecdsa", + "crypto/elliptic": "elliptic", + "crypto/hmac": "hmac", + "crypto/internal/randutil": "randutil", + "crypto/internal/subtle": "subtle", + "crypto/md5": "md5", + "crypto/rand": "rand", + "crypto/rc4": "rc4", + "crypto/rsa": "rsa", + "crypto/sha1": "sha1", + "crypto/sha256": "sha256", + "crypto/sha512": "sha512", + "crypto/subtle": "subtle", + "crypto/tls": "tls", + "crypto/x509": "x509", + "crypto/x509/pkix": "pkix", + "database/sql": "sql", + "database/sql/driver": "driver", + "debug/dwarf": "dwarf", + "debug/elf": "elf", + "debug/gosym": "gosym", + "debug/macho": "macho", + "debug/pe": "pe", + "debug/plan9obj": "plan9obj", + "encoding": "encoding", + "encoding/ascii85": "ascii85", + "encoding/asn1": "asn1", + "encoding/base32": "base32", + "encoding/base64": "base64", + "encoding/binary": "binary", + "encoding/csv": "csv", + "encoding/gob": "gob", + "encoding/hex": "hex", + "encoding/json": "json", + "encoding/pem": "pem", + "encoding/xml": "xml", + "errors": "errors", + "expvar": "expvar", + "flag": "flag", + "fmt": "fmt", + "go/ast": "ast", + "go/build": "build", + "go/constant": "constant", + "go/doc": "doc", + "go/format": "format", + "go/importer": "importer", + "go/internal/gccgoimporter": "gccgoimporter", + "go/internal/gcimporter": "gcimporter", + "go/internal/srcimporter": "srcimporter", + "go/parser": "parser", + "go/printer": "printer", + "go/scanner": "scanner", + "go/token": "token", + "go/types": "types", + "hash": "hash", + "hash/adler32": "adler32", + "hash/crc32": "crc32", + "hash/crc64": "crc64", + "hash/fnv": "fnv", + "html": "html", + "html/template": "template", + "image": "image", + "image/color": "color", + "image/color/palette": "palette", + "image/draw": "draw", + "image/gif": "gif", + "image/internal/imageutil": "imageutil", + "image/jpeg": "jpeg", + "image/png": "png", + "index/suffixarray": "suffixarray", + "internal/bytealg": "bytealg", + "internal/cpu": "cpu", + "internal/nettrace": "nettrace", + "internal/poll": "poll", + "internal/race": "race", + "internal/singleflight": "singleflight", + "internal/syscall/unix": "unix", + "internal/syscall/windows": "windows", + "internal/syscall/windows/registry": "registry", + "internal/syscall/windows/sysdll": "sysdll", + "internal/testenv": "testenv", + "internal/testlog": "testlog", + "internal/trace": "trace", + "io": "io", + "io/ioutil": "ioutil", + "log": "log", + "log/syslog": "syslog", + "math": "math", + "math/big": "big", + "math/bits": "bits", + "math/cmplx": "cmplx", + "math/rand": "rand", + "mime": "mime", + "mime/multipart": "multipart", + "mime/quotedprintable": "quotedprintable", + "net": "net", + "net/http": "http", + "net/http/cgi": "cgi", + "net/http/cookiejar": "cookiejar", + "net/http/fcgi": "fcgi", + "net/http/httptest": "httptest", + "net/http/httptrace": "httptrace", + "net/http/httputil": "httputil", + "net/http/internal": "internal", + "net/http/pprof": "pprof", + "net/internal/socktest": "socktest", + "net/mail": "mail", + "net/rpc": "rpc", + "net/rpc/jsonrpc": "jsonrpc", + "net/smtp": "smtp", + "net/textproto": "textproto", + "net/url": "url", + "os": "os", + "os/exec": "exec", + "os/signal": "signal", + "os/signal/internal/pty": "pty", + "os/user": "user", + "path": "path", + "path/filepath": "filepath", + "plugin": "plugin", + "reflect": "reflect", + "regexp": "regexp", + "regexp/syntax": "syntax", + "runtime": "runtime", + "runtime/cgo": "cgo", + "runtime/debug": "debug", + "runtime/internal/atomic": "atomic", + "runtime/internal/sys": "sys", + "runtime/pprof": "pprof", + "runtime/pprof/internal/profile": "profile", + "runtime/race": "race", + "runtime/trace": "trace", + "sort": "sort", + "strconv": "strconv", + "strings": "strings", + "sync": "sync", + "sync/atomic": "atomic", + "syscall": "syscall", + "testing": "testing", + "testing/internal/testdeps": "testdeps", + "testing/iotest": "iotest", + "testing/quick": "quick", + "text/scanner": "scanner", + "text/tabwriter": "tabwriter", + "text/template": "template", + "text/template/parse": "parse", + "time": "time", + "unicode": "unicode", + "unicode/utf16": "utf16", + "unicode/utf8": "utf8", + "unsafe": "unsafe", +} diff --git a/vendor/github.com/dave/jennifer/jen/jen.go b/vendor/github.com/dave/jennifer/jen/jen.go new file mode 100644 index 00000000..4cf480a1 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/jen.go @@ -0,0 +1,168 @@ +// Package jen is a code generator for Go +package jen + +import ( + "bytes" + "fmt" + "go/format" + "io" + "io/ioutil" + "sort" + "strconv" +) + +// Code represents an item of code that can be rendered. +type Code interface { + render(f *File, w io.Writer, s *Statement) error + isNull(f *File) bool +} + +// Save renders the file and saves to the filename provided. +func (f *File) Save(filename string) error { + // notest + buf := &bytes.Buffer{} + if err := f.Render(buf); err != nil { + return err + } + if err := ioutil.WriteFile(filename, buf.Bytes(), 0644); err != nil { + return err + } + return nil +} + +// Render renders the file to the provided writer. +func (f *File) Render(w io.Writer) error { + body := &bytes.Buffer{} + if err := f.render(f, body, nil); err != nil { + return err + } + source := &bytes.Buffer{} + if len(f.headers) > 0 { + for _, c := range f.headers { + if err := Comment(c).render(f, source, nil); err != nil { + return err + } + if _, err := fmt.Fprint(source, "\n"); err != nil { + return err + } + } + // Append an extra newline so that header comments don't get lumped in + // with package comments. + if _, err := fmt.Fprint(source, "\n"); err != nil { + return err + } + } + for _, c := range f.comments { + if err := Comment(c).render(f, source, nil); err != nil { + return err + } + if _, err := fmt.Fprint(source, "\n"); err != nil { + return err + } + } + if _, err := fmt.Fprintf(source, "package %s", f.name); err != nil { + return err + } + if f.CanonicalPath != "" { + if _, err := fmt.Fprintf(source, " // import %q", f.CanonicalPath); err != nil { + return err + } + } + if _, err := fmt.Fprint(source, "\n\n"); err != nil { + return err + } + if err := f.renderImports(source); err != nil { + return err + } + if _, err := source.Write(body.Bytes()); err != nil { + return err + } + formatted, err := format.Source(source.Bytes()) + if err != nil { + return fmt.Errorf("Error %s while formatting source:\n%s", err, source.String()) + } + if _, err := w.Write(formatted); err != nil { + return err + } + return nil +} + +func (f *File) renderImports(source io.Writer) error { + + // Render the "C" import if it's been used in a `Qual`, `Anon` or if there's a preamble comment + hasCgo := f.imports["C"].name != "" || len(f.cgoPreamble) > 0 + + // Only separate the import from the main imports block if there's a preamble + separateCgo := hasCgo && len(f.cgoPreamble) > 0 + + filtered := map[string]importdef{} + for path, def := range f.imports { + // filter out the "C" pseudo-package so it's not rendered in a block with the other + // imports, but only if it is accompanied by a preamble comment + if path == "C" && separateCgo { + continue + } + filtered[path] = def + } + + if len(filtered) == 1 { + for path, def := range filtered { + if def.alias && path != "C" { + // "C" package should be rendered without alias even when used as an anonymous import + // (e.g. should never have an underscore). + if _, err := fmt.Fprintf(source, "import %s %s\n\n", def.name, strconv.Quote(path)); err != nil { + return err + } + } else { + if _, err := fmt.Fprintf(source, "import %s\n\n", strconv.Quote(path)); err != nil { + return err + } + } + } + } else if len(filtered) > 1 { + if _, err := fmt.Fprint(source, "import (\n"); err != nil { + return err + } + // We must sort the imports to ensure repeatable + // source. + paths := []string{} + for path := range filtered { + paths = append(paths, path) + } + sort.Strings(paths) + for _, path := range paths { + def := filtered[path] + if def.alias && path != "C" { + // "C" package should be rendered without alias even when used as an anonymous import + // (e.g. should never have an underscore). + if _, err := fmt.Fprintf(source, "%s %s\n", def.name, strconv.Quote(path)); err != nil { + return err + } + + } else { + if _, err := fmt.Fprintf(source, "%s\n", strconv.Quote(path)); err != nil { + return err + } + } + } + if _, err := fmt.Fprint(source, ")\n\n"); err != nil { + return err + } + } + + if separateCgo { + for _, c := range f.cgoPreamble { + if err := Comment(c).render(f, source, nil); err != nil { + return err + } + if _, err := fmt.Fprint(source, "\n"); err != nil { + return err + } + } + if _, err := fmt.Fprint(source, "import \"C\"\n\n"); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/dave/jennifer/jen/jen_test.go b/vendor/github.com/dave/jennifer/jen/jen_test.go new file mode 100644 index 00000000..ade18362 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/jen_test.go @@ -0,0 +1,550 @@ +package jen_test + +import ( + "fmt" + "go/format" + "strings" + "testing" + + . "github.com/dave/jennifer/jen" +) + +var o1 = Options{ + Close: ")", + Multi: true, + Open: "(", + Separator: ",", +} + +var o2 = Options{ + Close: "", + Multi: false, + Open: "", + Separator: ",", +} + +var cases = []tc{ + { + desc: `scientific notation`, + code: Lit(1e3), + expect: `1000.0`, + }, + { + desc: `big float`, + code: Lit(1000000.0), + expect: `1e+06`, + }, + { + desc: `lit float whole numbers`, + code: Index().Float64().Values(Lit(-10.0), Lit(-2.0), Lit(-1.0), Lit(0.0), Lit(1.0), Lit(2.0), Lit(10.0)), + expect: "[]float64{-10.0, -2.0, -1.0, 0.0, 1.0, 2.0, 10.0}", + }, + { + desc: `custom func group`, + code: ListFunc(func(g *Group) { + g.CustomFunc(o2, func(g *Group) { + g.Id("a") + g.Id("b") + g.Id("c") + }) + }).Op("=").Id("foo").Call(), + expect: `a, b, c = foo()`, + }, + { + desc: `custom group`, + code: ListFunc(func(g *Group) { g.Custom(o2, Id("a"), Id("b"), Id("c")) }).Op("=").Id("foo").Call(), + expect: `a, b, c = foo()`, + }, + { + desc: `custom function`, + code: Id("foo").Add(Custom(o1, Lit("a"), Lit("b"), Lit("c"))), + expect: `foo( + "a", + "b", + "c", + )`, + }, + { + desc: `custom function`, + code: Id("foo").Add(Custom(o1, Lit("a"), Lit("b"), Lit("c"))), + expect: `foo( + "a", + "b", + "c", + )`, + }, + { + desc: `line statement`, + code: Block(Lit(1).Line(), Lit(2)), + expect: `{ + 1 + + 2 + }`, + }, + { + desc: `line func`, + code: Block(Lit(1), Line(), Lit(2)), + expect: `{ + 1 + + 2 + }`, + }, + { + desc: `line group`, + code: BlockFunc(func(g *Group) { + g.Id("a") + g.Line() + g.Id("b") + }), + expect: `{ + a + + b + }`, + }, + { + desc: `op group`, + code: BlockFunc(func(g *Group) { + g.Op("*").Id("a") + }), + expect: `{*a}`, + }, + { + desc: `empty group`, + code: BlockFunc(func(g *Group) { + g.Empty() + }), + expect: `{ + + }`, + }, + { + desc: `null group`, + code: BlockFunc(func(g *Group) { + g.Null() + }), + expect: `{}`, + }, + { + desc: `tag no backquote`, + code: Tag(map[string]string{"a": "`b`"}), + expect: "\"a:\\\"`b`\\\"\"", + }, + { + desc: `tag null`, + code: Tag(map[string]string{}), + expect: ``, + }, + { + desc: `litrunefunc group`, + code: BlockFunc(func(g *Group) { + g.LitByteFunc(func() byte { return byte(0xab) }) + }), + expect: `{byte(0xab)}`, + }, + { + desc: `litbyte group`, + code: BlockFunc(func(g *Group) { + g.LitByte(byte(0xab)) + }), + expect: `{byte(0xab)}`, + }, + { + desc: `litrunefunc group`, + code: BlockFunc(func(g *Group) { + g.LitRuneFunc(func() rune { return 'a' }) + }), + expect: `{'a'}`, + }, + { + desc: `litrune group`, + code: BlockFunc(func(g *Group) { + g.LitRune('a') + }), + expect: `{'a'}`, + }, + { + desc: `litfunc group`, + code: BlockFunc(func(g *Group) { + g.LitFunc(func() interface{} { + return 1 + 1 + }) + }), + expect: `{2}`, + }, + { + desc: `litfunc func`, + code: LitFunc(func() interface{} { + return 1 + 1 + }), + expect: `2`, + }, + { + desc: `group all null`, + code: List(Null(), Null()), + expect: ``, + }, + { + desc: `do group`, + code: BlockFunc(func(g *Group) { g.Do(func(s *Statement) { s.Lit(1) }) }), + expect: `{1}`, + }, + { + desc: `do func`, + code: Do(func(s *Statement) { s.Lit(1) }), + expect: `1`, + }, + { + desc: `dict empty`, + code: Values(Dict{}), + expect: `{}`, + }, + { + desc: `dict null`, + code: Values(Dict{Null(): Null()}), + expect: `{}`, + }, + { + desc: `commentf group`, + code: BlockFunc(func(g *Group) { g.Commentf("%d", 1) }), + expect: `{ + // 1 + }`, + }, + { + desc: `commentf func`, + code: Commentf("%d", 1), + expect: `// 1`, + }, + { + desc: `add func`, + code: Add(Lit(1)), + expect: `1`, + }, + { + desc: `add group`, + code: BlockFunc(func(g *Group) { g.Add(Lit(1)) }), + expect: `{1}`, + }, + { + desc: `empty block`, + code: Block(), + expect: `{}`, + }, + { + desc: `string literal`, + code: Lit("a"), + expect: `"a"`, + }, + { + desc: `int literal`, + code: Lit(1), + expect: `1`, + }, + { + desc: `simple id`, + code: Id("a"), + expect: `a`, + }, + { + desc: `foreign id`, + code: Qual("x.y/z", "a"), + expect: `z.a`, + expectImports: map[string]string{ + "x.y/z": "z", + }, + }, + { + desc: `var decl`, + code: Var().Id("a").Op("=").Lit("b"), + expect: `var a = "b"`, + }, + { + desc: `short var decl`, + code: Id("a").Op(":=").Lit("b"), + expect: `a := "b"`, + }, + { + desc: `simple if`, + code: If(Id("a").Op("==").Lit("b")).Block(), + expect: `if a == "b" {}`, + }, + { + desc: `simple if`, + code: If(Id("a").Op("==").Lit("b")).Block( + Id("a").Op("++"), + ), + expect: `if a == "b" { a++ }`, + }, + { + desc: `pointer`, + code: Op("*").Id("a"), + expect: `*a`, + }, + { + desc: `address`, + code: Op("&").Id("a"), + expect: `&a`, + }, + { + desc: `simple call`, + code: Id("a").Call( + Lit("b"), + Lit("c"), + ), + expect: `a("b", "c")`, + }, + { + desc: `call fmt.Sprintf`, + code: Qual("fmt", "Sprintf").Call( + Lit("b"), + Id("c"), + ), + expect: `fmt.Sprintf("b", c)`, + }, + { + desc: `slices`, + code: Id("a").Index( + Lit(1), + Empty(), + ), + expect: `a[1:]`, + }, + { + desc: `return`, + code: Return(Id("a")), + expect: `return a`, + }, + { + desc: `double return`, + code: Return(Id("a"), Id("b")), + expect: `return a, b`, + }, + { + desc: `func`, + code: Func().Id("a").Params( + Id("a").String(), + ).Block( + Return(Id("a")), + ), + expect: `func a(a string){ + return a + }`, + }, + { + desc: `built in func`, + code: New(Id("a")), + expect: `new(a)`, + }, + { + desc: `multip`, + code: Id("a").Op("*").Id("b"), + expect: `a * b`, + }, + { + desc: `multip ptr`, + code: Id("a").Op("*").Op("*").Id("b"), + expect: `a * *b`, + }, + { + desc: `field`, + code: Id("a").Dot("b"), + expect: `a.b`, + }, + { + desc: `method`, + code: Id("a").Dot("b").Call(Id("c"), Id("d")), + expect: `a.b(c, d)`, + }, + { + desc: `if else`, + code: If(Id("a").Op("==").Lit(1)).Block( + Id("b").Op("=").Lit(1), + ).Else().If(Id("a").Op("==").Lit(2)).Block( + Id("b").Op("=").Lit(2), + ).Else().Block( + Id("b").Op("=").Lit(3), + ), + expect: `if a == 1 { b = 1 } else if a == 2 { b = 2 } else { b = 3 }`, + }, + { + desc: `literal array`, + code: Index().String().Values(Lit("a"), Lit("b")), + expect: `[]string{"a", "b"}`, + }, + { + desc: `comment`, + code: Comment("a"), + expect: `// a`, + }, + { + desc: `null`, + code: Id("a").Params(Id("b"), Null(), Id("c")), + expect: `a(b, c)`, + }, + { + desc: `map literal single`, + code: Id("a").Values(Dict{ + Id("b"): Id("c"), + }), + expect: `a{b: c}`, + }, + { + desc: `map literal null`, + code: Id("a").Values(Dict{ + Null(): Id("c"), + Id("b"): Null(), + Id("b"): Id("c"), + }), + expect: `a{b: c}`, + }, + { + desc: `map literal multiple`, + code: Id("a").Values(Dict{ + Id("b"): Id("c"), + Id("d"): Id("e"), + }), + expect: `a{ + b: c, + d: e, + }`, + }, + { + desc: `map literal func single`, + code: Id("a").Values(DictFunc(func(d Dict) { + d[Id("b")] = Id("c") + })), + expect: `a{b: c}`, + }, + { + desc: `map literal func single null`, + code: Id("a").Values(DictFunc(func(d Dict) { + d[Null()] = Id("c") + d[Id("b")] = Null() + d[Id("b")] = Id("c") + })), + expect: `a{b: c}`, + }, + { + desc: `map literal func multiple`, + code: Id("a").Values(DictFunc(func(d Dict) { + d[Id("b")] = Id("c") + d[Id("d")] = Id("e") + })), + expect: `a{ + b: c, + d: e, + }`, + }, + { + desc: `literal func`, + code: Id("a").Op(":=").LitFunc(func() interface{} { + return "b" + }), + expect: `a := "b"`, + }, + { + desc: `dot`, + code: Id("a").Dot("b").Dot("c"), + expect: `a.b.c`, + }, + { + desc: `do`, + code: Id("a").Do(func(s *Statement) { s.Dot("b") }), + expect: `a.b`, + }, + { + desc: `tags should be ordered`, + code: Tag(map[string]string{"z": "1", "a": "2"}), + expect: "`a:\"2\" z:\"1\"`", + }, + { + desc: `dict should be ordered`, + code: Map(String()).Int().Values(Dict{Id("z"): Lit(1), Id("a"): Lit(2)}), + expect: `map[string]int{ + a:2, + z:1, + }`, + }, +} + +func TestJen(t *testing.T) { + caseTester(t, cases) +} + +func caseTester(t *testing.T, cases []tc) { + for i, c := range cases { + onlyTest := "" + if onlyTest != "" && c.desc != onlyTest { + continue + } + rendered := fmt.Sprintf("%#v", c.code) + + expected, err := format.Source([]byte(c.expect)) + if err != nil { + panic(fmt.Sprintf("Error formatting expected source in test case %d. Description: %s\nError:\n%s", i, c.desc, err)) + } + + if strings.TrimSpace(string(rendered)) != strings.TrimSpace(string(expected)) { + t.Errorf("Test case %d failed. Description: %s\nExpected:\n%s\nOutput:\n%s", i, c.desc, expected, rendered) + } + + //if c.expectImports != nil { + // f := FromContext(ctx) + // if !reflect.DeepEqual(f.Imports, c.expectImports) { + // t.Errorf("Test case %d failed. Description: %s\nImports expected:\n%s\nOutput:\n%s", i, c.desc, c.expectImports, f.Imports) + // } + //} + } +} + +// a test case +type tc struct { + // path + path string + // description for locating the test case + desc string + // code to generate + code Code + // expected generated source + expect string + // expected imports + expectImports map[string]string +} + +func TestNilStatement(t *testing.T) { + var s *Statement + c := Func().Id("a").Params( + s, + ) + got := fmt.Sprintf("%#v", c) + expect := "func a()" + if got != expect { + t.Fatalf("Got: %s, expect: %s", got, expect) + } +} + +func TestNilGroup(t *testing.T) { + var g *Group + c := Func().Id("a").Params( + g, + ) + got := fmt.Sprintf("%#v", c) + expect := "func a()" + if got != expect { + t.Fatalf("Got: %s, expect: %s", got, expect) + } +} + +func TestGroup_GoString(t *testing.T) { + BlockFunc(func(g *Group) { + g.Lit(1) + got := fmt.Sprintf("%#v", g) + expect := "{\n\t1\n}" + if got != expect { + t.Fatalf("Got: %s, expect: %s", got, expect) + } + }) +} diff --git a/vendor/github.com/dave/jennifer/jen/lit.go b/vendor/github.com/dave/jennifer/jen/lit.go new file mode 100644 index 00000000..9791f1d2 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/lit.go @@ -0,0 +1,154 @@ +package jen + +// Lit renders a literal. Lit supports only built-in types (bool, string, int, complex128, float64, +// float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +// Passing any other type will panic. +func Lit(v interface{}) *Statement { + return newStatement().Lit(v) +} + +// Lit renders a literal. Lit supports only built-in types (bool, string, int, complex128, float64, +// float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +// Passing any other type will panic. +func (g *Group) Lit(v interface{}) *Statement { + s := Lit(v) + g.items = append(g.items, s) + return s +} + +// Lit renders a literal. Lit supports only built-in types (bool, string, int, complex128, float64, +// float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +// Passing any other type will panic. +func (s *Statement) Lit(v interface{}) *Statement { + t := token{ + typ: literalToken, + content: v, + } + *s = append(*s, t) + return s +} + +// LitFunc renders a literal. LitFunc generates the value to render by executing the provided +// function. LitFunc supports only built-in types (bool, string, int, complex128, float64, float32, +// int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +// Returning any other type will panic. +func LitFunc(f func() interface{}) *Statement { + return newStatement().LitFunc(f) +} + +// LitFunc renders a literal. LitFunc generates the value to render by executing the provided +// function. LitFunc supports only built-in types (bool, string, int, complex128, float64, float32, +// int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +// Returning any other type will panic. +func (g *Group) LitFunc(f func() interface{}) *Statement { + s := LitFunc(f) + g.items = append(g.items, s) + return s +} + +// LitFunc renders a literal. LitFunc generates the value to render by executing the provided +// function. LitFunc supports only built-in types (bool, string, int, complex128, float64, float32, +// int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr and complex64). +// Returning any other type will panic. +func (s *Statement) LitFunc(f func() interface{}) *Statement { + t := token{ + typ: literalToken, + content: f(), + } + *s = append(*s, t) + return s +} + +// LitRune renders a rune literal. +func LitRune(v rune) *Statement { + return newStatement().LitRune(v) +} + +// LitRune renders a rune literal. +func (g *Group) LitRune(v rune) *Statement { + s := LitRune(v) + g.items = append(g.items, s) + return s +} + +// LitRune renders a rune literal. +func (s *Statement) LitRune(v rune) *Statement { + t := token{ + typ: literalRuneToken, + content: v, + } + *s = append(*s, t) + return s +} + +// LitRuneFunc renders a rune literal. LitRuneFunc generates the value to +// render by executing the provided function. +func LitRuneFunc(f func() rune) *Statement { + return newStatement().LitRuneFunc(f) +} + +// LitRuneFunc renders a rune literal. LitRuneFunc generates the value to +// render by executing the provided function. +func (g *Group) LitRuneFunc(f func() rune) *Statement { + s := LitRuneFunc(f) + g.items = append(g.items, s) + return s +} + +// LitRuneFunc renders a rune literal. LitRuneFunc generates the value to +// render by executing the provided function. +func (s *Statement) LitRuneFunc(f func() rune) *Statement { + t := token{ + typ: literalRuneToken, + content: f(), + } + *s = append(*s, t) + return s +} + +// LitByte renders a byte literal. +func LitByte(v byte) *Statement { + return newStatement().LitByte(v) +} + +// LitByte renders a byte literal. +func (g *Group) LitByte(v byte) *Statement { + s := LitByte(v) + g.items = append(g.items, s) + return s +} + +// LitByte renders a byte literal. +func (s *Statement) LitByte(v byte) *Statement { + t := token{ + typ: literalByteToken, + content: v, + } + *s = append(*s, t) + return s +} + +// LitByteFunc renders a byte literal. LitByteFunc generates the value to +// render by executing the provided function. +func LitByteFunc(f func() byte) *Statement { + return newStatement().LitByteFunc(f) +} + +// LitByteFunc renders a byte literal. LitByteFunc generates the value to +// render by executing the provided function. +func (g *Group) LitByteFunc(f func() byte) *Statement { + s := LitByteFunc(f) + g.items = append(g.items, s) + return s +} + +// LitByteFunc renders a byte literal. LitByteFunc generates the value to +// render by executing the provided function. +func (s *Statement) LitByteFunc(f func() byte) *Statement { + t := token{ + typ: literalByteToken, + content: f(), + } + *s = append(*s, t) + return s +} diff --git a/vendor/github.com/dave/jennifer/jen/statement.go b/vendor/github.com/dave/jennifer/jen/statement.go new file mode 100644 index 00000000..aa9ec497 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/statement.go @@ -0,0 +1,101 @@ +package jen + +import ( + "bytes" + "fmt" + "go/format" + "io" +) + +// Statement represents a simple list of code items. When rendered the items +// are separated by spaces. +type Statement []Code + +func newStatement() *Statement { + return &Statement{} +} + +// Clone makes a copy of the Statement, so further tokens can be appended +// without affecting the original. +func (s *Statement) Clone() *Statement { + return &Statement{s} +} + +func (s *Statement) previous(c Code) Code { + index := -1 + for i, item := range *s { + if item == c { + index = i + break + } + } + if index > 0 { + return (*s)[index-1] + } + return nil +} + +func (s *Statement) isNull(f *File) bool { + if s == nil { + return true + } + for _, c := range *s { + if !c.isNull(f) { + return false + } + } + return true +} + +func (s *Statement) render(f *File, w io.Writer, _ *Statement) error { + first := true + for _, code := range *s { + if code == nil || code.isNull(f) { + // Null() token produces no output but also + // no separator. Empty() token products no + // output but adds a separator. + continue + } + if !first { + if _, err := w.Write([]byte(" ")); err != nil { + return err + } + } + if err := code.render(f, w, s); err != nil { + return err + } + first = false + } + return nil +} + +// Render renders the Statement to the provided writer. +func (s *Statement) Render(writer io.Writer) error { + return s.RenderWithFile(writer, NewFile("")) +} + +// GoString renders the Statement for testing. Any error will cause a panic. +func (s *Statement) GoString() string { + buf := bytes.Buffer{} + if err := s.Render(&buf); err != nil { + panic(err) + } + return buf.String() +} + +// RenderWithFile renders the Statement to the provided writer, using imports from the provided file. +func (s *Statement) RenderWithFile(writer io.Writer, file *File) error { + buf := &bytes.Buffer{} + if err := s.render(file, buf, nil); err != nil { + return err + } + b, err := format.Source(buf.Bytes()) + if err != nil { + return fmt.Errorf("Error %s while formatting source:\n%s", err, buf.String()) + } + if _, err := writer.Write(b); err != nil { + return err + } + return nil +} + diff --git a/vendor/github.com/dave/jennifer/jen/statement_test.go b/vendor/github.com/dave/jennifer/jen/statement_test.go new file mode 100644 index 00000000..d774f6e9 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/statement_test.go @@ -0,0 +1,32 @@ +package jen_test + +import ( + "bytes" + "testing" + + . "github.com/dave/jennifer/jen" +) + +func TestStatement_Render(t *testing.T) { + file := NewFile("main") + file.ImportAlias("fmt", "fmtalias") + + statement := file.Func().Id("main").Params().Block( + Qual("fmt", "Println").Call(Lit("something")), + ) + + expect := `func main() { + fmtalias.Println("something") +}` + + var got bytes.Buffer + + err := statement.RenderWithFile(&got, file) + if err != nil { + t.Fatal(err) + } + + if got.String() != expect { + t.Fatalf("Got: %v, expect: %v", got.String(), expect) + } +} diff --git a/vendor/github.com/dave/jennifer/jen/tag.go b/vendor/github.com/dave/jennifer/jen/tag.go new file mode 100644 index 00000000..ad99aafd --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/tag.go @@ -0,0 +1,76 @@ +package jen + +import ( + "fmt" + "io" + "sort" + "strconv" +) + +// Tag renders a struct tag +func Tag(items map[string]string) *Statement { + return newStatement().Tag(items) +} + +// Tag renders a struct tag +func (g *Group) Tag(items map[string]string) *Statement { + // notest + // don't think this can ever be used in valid code? + s := Tag(items) + g.items = append(g.items, s) + return s +} + +// Tag renders a struct tag +func (s *Statement) Tag(items map[string]string) *Statement { + c := tag{ + items: items, + } + *s = append(*s, c) + return s +} + +type tag struct { + items map[string]string +} + +func (t tag) isNull(f *File) bool { + return len(t.items) == 0 +} + +func (t tag) render(f *File, w io.Writer, s *Statement) error { + + if t.isNull(f) { + // notest + // render won't be called if t is null + return nil + } + + var str string + + var sorted []string + for k := range t.items { + sorted = append(sorted, k) + } + sort.Strings(sorted) + + for _, k := range sorted { + v := t.items[k] + if len(str) > 0 { + str += " " + } + str += fmt.Sprintf(`%s:"%s"`, k, v) + } + + if strconv.CanBackquote(str) { + str = "`" + str + "`" + } else { + str = strconv.Quote(str) + } + + if _, err := w.Write([]byte(str)); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/dave/jennifer/jen/tokens.go b/vendor/github.com/dave/jennifer/jen/tokens.go new file mode 100644 index 00000000..287a3cd6 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/tokens.go @@ -0,0 +1,301 @@ +package jen + +import ( + "fmt" + "io" + "strconv" + "strings" +) + +type tokenType string + +const ( + packageToken tokenType = "package" + identifierToken tokenType = "identifier" + qualifiedToken tokenType = "qualified" + keywordToken tokenType = "keyword" + operatorToken tokenType = "operator" + delimiterToken tokenType = "delimiter" + literalToken tokenType = "literal" + literalRuneToken tokenType = "literal_rune" + literalByteToken tokenType = "literal_byte" + nullToken tokenType = "null" + layoutToken tokenType = "layout" +) + +type token struct { + typ tokenType + content interface{} +} + +func (t token) isNull(f *File) bool { + if t.typ == packageToken { + // package token is null if the path is a dot-import or the local package path + return f.isDotImport(t.content.(string)) || f.isLocal(t.content.(string)) + } + return t.typ == nullToken +} + +func (t token) render(f *File, w io.Writer, s *Statement) error { + switch t.typ { + case literalToken: + var out string + switch t.content.(type) { + case bool, string, int, complex128: + // default constant types can be left bare + out = fmt.Sprintf("%#v", t.content) + case float64: + out = fmt.Sprintf("%#v", t.content) + if !strings.Contains(out, ".") && !strings.Contains(out, "e") { + // If the formatted value is not in scientific notation, and does not have a dot, then + // we add ".0". Otherwise it will be interpreted as an int. + // See: + // https://github.com/dave/jennifer/issues/39 + // https://github.com/golang/go/issues/26363 + out += ".0" + } + case float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr: + // other built-in types need specific type info + out = fmt.Sprintf("%T(%#v)", t.content, t.content) + case complex64: + // fmt package already renders parenthesis for complex64 + out = fmt.Sprintf("%T%#v", t.content, t.content) + default: + panic(fmt.Sprintf("unsupported type for literal: %T", t.content)) + } + if _, err := w.Write([]byte(out)); err != nil { + return err + } + case literalRuneToken: + if _, err := w.Write([]byte(strconv.QuoteRune(t.content.(rune)))); err != nil { + return err + } + case literalByteToken: + if _, err := w.Write([]byte(fmt.Sprintf("byte(%#v)", t.content))); err != nil { + return err + } + case keywordToken, operatorToken, layoutToken, delimiterToken: + if _, err := w.Write([]byte(fmt.Sprintf("%s", t.content))); err != nil { + return err + } + if t.content.(string) == "default" { + // Special case for Default, which must always be followed by a colon + if _, err := w.Write([]byte(":")); err != nil { + return err + } + } + case packageToken: + path := t.content.(string) + alias := f.register(path) + if _, err := w.Write([]byte(alias)); err != nil { + return err + } + case identifierToken: + if _, err := w.Write([]byte(t.content.(string))); err != nil { + return err + } + case nullToken: // notest + // do nothing (should never render a null token) + } + return nil +} + +// Null adds a null item. Null items render nothing and are not followed by a +// separator in lists. +func Null() *Statement { + return newStatement().Null() +} + +// Null adds a null item. Null items render nothing and are not followed by a +// separator in lists. +func (g *Group) Null() *Statement { + s := Null() + g.items = append(g.items, s) + return s +} + +// Null adds a null item. Null items render nothing and are not followed by a +// separator in lists. +func (s *Statement) Null() *Statement { + t := token{ + typ: nullToken, + } + *s = append(*s, t) + return s +} + +// Empty adds an empty item. Empty items render nothing but are followed by a +// separator in lists. +func Empty() *Statement { + return newStatement().Empty() +} + +// Empty adds an empty item. Empty items render nothing but are followed by a +// separator in lists. +func (g *Group) Empty() *Statement { + s := Empty() + g.items = append(g.items, s) + return s +} + +// Empty adds an empty item. Empty items render nothing but are followed by a +// separator in lists. +func (s *Statement) Empty() *Statement { + t := token{ + typ: operatorToken, + content: "", + } + *s = append(*s, t) + return s +} + +// Op renders the provided operator / token. +func Op(op string) *Statement { + return newStatement().Op(op) +} + +// Op renders the provided operator / token. +func (g *Group) Op(op string) *Statement { + s := Op(op) + g.items = append(g.items, s) + return s +} + +// Op renders the provided operator / token. +func (s *Statement) Op(op string) *Statement { + t := token{ + typ: operatorToken, + content: op, + } + *s = append(*s, t) + return s +} + +// Dot renders a period followed by an identifier. Use for fields and selectors. +func Dot(name string) *Statement { + // notest + // don't think this can be used in valid code? + return newStatement().Dot(name) +} + +// Dot renders a period followed by an identifier. Use for fields and selectors. +func (g *Group) Dot(name string) *Statement { + // notest + // don't think this can be used in valid code? + s := Dot(name) + g.items = append(g.items, s) + return s +} + +// Dot renders a period followed by an identifier. Use for fields and selectors. +func (s *Statement) Dot(name string) *Statement { + d := token{ + typ: delimiterToken, + content: ".", + } + t := token{ + typ: identifierToken, + content: name, + } + *s = append(*s, d, t) + return s +} + +// Id renders an identifier. +func Id(name string) *Statement { + return newStatement().Id(name) +} + +// Id renders an identifier. +func (g *Group) Id(name string) *Statement { + s := Id(name) + g.items = append(g.items, s) + return s +} + +// Id renders an identifier. +func (s *Statement) Id(name string) *Statement { + t := token{ + typ: identifierToken, + content: name, + } + *s = append(*s, t) + return s +} + +// Qual renders a qualified identifier. Imports are automatically added when +// used with a File. If the path matches the local path, the package name is +// omitted. If package names conflict they are automatically renamed. Note that +// it is not possible to reliably determine the package name given an arbitrary +// package path, so a sensible name is guessed from the path and added as an +// alias. The names of all standard library packages are known so these do not +// need to be aliased. If more control is needed of the aliases, see +// [File.ImportName](#importname) or [File.ImportAlias](#importalias). +func Qual(path, name string) *Statement { + return newStatement().Qual(path, name) +} + +// Qual renders a qualified identifier. Imports are automatically added when +// used with a File. If the path matches the local path, the package name is +// omitted. If package names conflict they are automatically renamed. Note that +// it is not possible to reliably determine the package name given an arbitrary +// package path, so a sensible name is guessed from the path and added as an +// alias. The names of all standard library packages are known so these do not +// need to be aliased. If more control is needed of the aliases, see +// [File.ImportName](#importname) or [File.ImportAlias](#importalias). +func (g *Group) Qual(path, name string) *Statement { + s := Qual(path, name) + g.items = append(g.items, s) + return s +} + +// Qual renders a qualified identifier. Imports are automatically added when +// used with a File. If the path matches the local path, the package name is +// omitted. If package names conflict they are automatically renamed. Note that +// it is not possible to reliably determine the package name given an arbitrary +// package path, so a sensible name is guessed from the path and added as an +// alias. The names of all standard library packages are known so these do not +// need to be aliased. If more control is needed of the aliases, see +// [File.ImportName](#importname) or [File.ImportAlias](#importalias). +func (s *Statement) Qual(path, name string) *Statement { + g := &Group{ + close: "", + items: []Code{ + token{ + typ: packageToken, + content: path, + }, + token{ + typ: identifierToken, + content: name, + }, + }, + name: "qual", + open: "", + separator: ".", + } + *s = append(*s, g) + return s +} + +// Line inserts a blank line. +func Line() *Statement { + return newStatement().Line() +} + +// Line inserts a blank line. +func (g *Group) Line() *Statement { + s := Line() + g.items = append(g.items, s) + return s +} + +// Line inserts a blank line. +func (s *Statement) Line() *Statement { + t := token{ + typ: layoutToken, + content: "\n", + } + *s = append(*s, t) + return s +} diff --git a/vendor/github.com/dave/jennifer/jennifer.go b/vendor/github.com/dave/jennifer/jennifer.go new file mode 100644 index 00000000..37efad44 --- /dev/null +++ b/vendor/github.com/dave/jennifer/jennifer.go @@ -0,0 +1,9 @@ +// Package jennifer is a code generator for Go +package jennifer + +//go:generate go get github.com/dave/jennifer/genjen +//go:generate genjen +//go:generate go get github.com/dave/jennifer/gennames +//go:generate gennames -output "jen/hints.go" -package "jen" -name "standardLibraryHints" -standard -novendor -path "./..." +//go:generate go get github.com/dave/rebecca/cmd/becca +//go:generate becca -package=github.com/dave/jennifer/jen diff --git a/vendor/github.com/ethereum/go-ethereum/.github/CODEOWNERS b/vendor/github.com/ethereum/go-ethereum/.github/CODEOWNERS index 9a61d393..959b5015 100644 --- a/vendor/github.com/ethereum/go-ethereum/.github/CODEOWNERS +++ b/vendor/github.com/ethereum/go-ethereum/.github/CODEOWNERS @@ -2,34 +2,16 @@ # Each line is a file pattern followed by one or more owners. accounts/usbwallet @karalabe +accounts/abi @gballet consensus @karalabe core/ @karalabe @holiman eth/ @karalabe +graphql/ @gballet les/ @zsfelfoldi light/ @zsfelfoldi mobile/ @karalabe p2p/ @fjl @zsfelfoldi -p2p/simulations @lmars -p2p/protocols @zelig -swarm/api/http @justelad -swarm/bmt @zelig -swarm/dev @lmars -swarm/fuse @jmozah @holisticode -swarm/grafana_dashboards @nonsense -swarm/metrics @nonsense @holisticode -swarm/multihash @nolash -swarm/network/bitvector @zelig @janos -swarm/network/priorityqueue @zelig @janos -swarm/network/simulations @zelig @janos -swarm/network/stream @janos @zelig @holisticode @justelad -swarm/network/stream/intervals @janos -swarm/network/stream/testing @zelig -swarm/pot @zelig -swarm/pss @nolash @zelig @nonsense -swarm/services @zelig -swarm/state @justelad -swarm/storage/encryption @zelig @nagydani -swarm/storage/mock @janos -swarm/storage/feed @nolash @jpeletier -swarm/testutil @lmars +p2p/simulations @zelig @nonsense @janos @justelad +p2p/protocols @zelig @nonsense @janos @justelad +p2p/testing @zelig @nonsense @janos @justelad whisper/ @gballet @gluk256 diff --git a/vendor/github.com/ethereum/go-ethereum/.github/no-response.yml b/vendor/github.com/ethereum/go-ethereum/.github/no-response.yml index b6e96efd..903d4ce8 100644 --- a/vendor/github.com/ethereum/go-ethereum/.github/no-response.yml +++ b/vendor/github.com/ethereum/go-ethereum/.github/no-response.yml @@ -1,7 +1,7 @@ # Number of days of inactivity before an Issue is closed for lack of response daysUntilClose: 30 # Label requiring a response -responseRequiredLabel: more-information-needed +responseRequiredLabel: "need:more-information" # Comment to post when closing an Issue for lack of response. Set to `false` to disable closeComment: > This issue has been automatically closed because there has been no response diff --git a/vendor/github.com/ethereum/go-ethereum/.github/stale.yml b/vendor/github.com/ethereum/go-ethereum/.github/stale.yml index c621939c..6d921cc7 100644 --- a/vendor/github.com/ethereum/go-ethereum/.github/stale.yml +++ b/vendor/github.com/ethereum/go-ethereum/.github/stale.yml @@ -7,7 +7,7 @@ exemptLabels: - pinned - security # Label to use when marking an issue as stale -staleLabel: stale +staleLabel: "status:inactive" # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had diff --git a/vendor/github.com/ethereum/go-ethereum/.gitignore b/vendor/github.com/ethereum/go-ethereum/.gitignore index 3e0009e1..3016face 100644 --- a/vendor/github.com/ethereum/go-ethereum/.gitignore +++ b/vendor/github.com/ethereum/go-ethereum/.gitignore @@ -42,6 +42,7 @@ profile.cov /dashboard/assets/node_modules /dashboard/assets/stats.json /dashboard/assets/bundle.js +/dashboard/assets/bundle.js.map /dashboard/assets/package-lock.json **/yarn-error.log diff --git a/vendor/github.com/ethereum/go-ethereum/.travis.yml b/vendor/github.com/ethereum/go-ethereum/.travis.yml index c1cc7c4a..8ff5fa3c 100644 --- a/vendor/github.com/ethereum/go-ethereum/.travis.yml +++ b/vendor/github.com/ethereum/go-ethereum/.travis.yml @@ -14,7 +14,6 @@ matrix: - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES - # These are the latest Go versions. - os: linux dist: trusty sudo: required @@ -26,9 +25,29 @@ matrix: - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES - - os: osx - go: 1.11.x + # These are the latest Go versions. + - os: linux + dist: trusty + sudo: required + go: 1.12.x script: + - sudo modprobe fuse + - sudo chmod 666 /dev/fuse + - sudo chown root:$USER /etc/fuse.conf + - go run build/ci.go install + - go run build/ci.go test -coverage $TEST_PACKAGES + + - os: osx + go: 1.12.x + script: + - echo "Increase the maximum number of open file descriptors on macOS" + - NOFILE=20480 + - sudo sysctl -w kern.maxfiles=$NOFILE + - sudo sysctl -w kern.maxfilesperproc=$NOFILE + - sudo launchctl limit maxfiles $NOFILE $NOFILE + - sudo launchctl limit maxfiles + - ulimit -S -n $NOFILE + - ulimit -n - unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703 - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES @@ -36,7 +55,7 @@ matrix: # This builder only tests code linters on latest version of Go - os: linux dist: trusty - go: 1.11.x + go: 1.12.x env: - lint git: @@ -45,10 +64,10 @@ matrix: - go run build/ci.go lint # This builder does the Ubuntu PPA upload - - if: type = push + - if: repo = ethereum/go-ethereum AND type = push os: linux dist: trusty - go: 1.11.x + go: 1.12.x env: - ubuntu-ppa git: @@ -60,15 +79,18 @@ matrix: - debhelper - dput - fakeroot + - python-bzrlib + - python-paramiko script: - - go run build/ci.go debsrc -signer "Go Ethereum Linux Builder " -upload ppa:ethereum/ethereum + - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts + - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " # This builder does the Linux Azure uploads - - if: type = push + - if: repo = ethereum/go-ethereum AND type = push os: linux dist: trusty sudo: required - go: 1.11.x + go: 1.12.x env: - azure-linux git: @@ -98,12 +120,12 @@ matrix: - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds # This builder does the Linux Azure MIPS xgo uploads - - if: type = push + - if: repo = ethereum/go-ethereum AND type = push os: linux dist: trusty services: - docker - go: 1.11.x + go: 1.12.x env: - azure-linux-mips git: @@ -126,7 +148,7 @@ matrix: - go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds # This builder does the Android Maven and Azure uploads - - if: type = push + - if: repo = ethereum/go-ethereum AND type = push os: linux dist: trusty addons: @@ -148,25 +170,24 @@ matrix: git: submodules: false # avoid cloning ethereum/tests before_install: - - curl https://storage.googleapis.com/golang/go1.11.2.linux-amd64.tar.gz | tar -xz + - curl https://dl.google.com/go/go1.12.linux-amd64.tar.gz | tar -xz - export PATH=`pwd`/go/bin:$PATH - export GOROOT=`pwd`/go - export GOPATH=$HOME/go script: # Build the Android archive and upload it to Maven Central and Azure - - curl https://dl.google.com/android/repository/android-ndk-r17b-linux-x86_64.zip -o android-ndk-r17b.zip - - unzip -q android-ndk-r17b.zip && rm android-ndk-r17b.zip - - mv android-ndk-r17b $HOME - - export ANDROID_NDK=$HOME/android-ndk-r17b + - curl https://dl.google.com/android/repository/android-ndk-r19b-linux-x86_64.zip -o android-ndk-r19b.zip + - unzip -q android-ndk-r19b.zip && rm android-ndk-r19b.zip + - mv android-ndk-r19b $ANDROID_HOME/ndk-bundle - mkdir -p $GOPATH/src/github.com/ethereum - - ln -s `pwd` $GOPATH/src/github.com/ethereum + - ln -s `pwd` $GOPATH/src/github.com/ethereum/go-ethereum - go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds # This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads - - if: type = push + - if: repo = ethereum/go-ethereum AND type = push os: osx - go: 1.11.x + go: 1.12.x env: - azure-osx - azure-ios @@ -193,13 +214,22 @@ matrix: - go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds # This builder does the Azure archive purges to avoid accumulating junk - - if: type = cron + - if: repo = ethereum/go-ethereum AND type = cron os: linux dist: trusty - go: 1.11.x + go: 1.12.x env: - azure-purge git: submodules: false # avoid cloning ethereum/tests script: - go run build/ci.go purge -store gethstore/builds -days 14 + + - name: Race Detector for Swarm + if: repo = ethersphere/go-ethereum + os: linux + dist: trusty + go: 1.12.x + git: + submodules: false # avoid cloning ethereum/tests + script: ./build/travis_keepalive.sh go test -timeout 20m -race ./swarm... ./p2p/{protocols,simulations,testing}/... diff --git a/vendor/github.com/ethereum/go-ethereum/Dockerfile b/vendor/github.com/ethereum/go-ethereum/Dockerfile index e87dd35d..4b205d64 100644 --- a/vendor/github.com/ethereum/go-ethereum/Dockerfile +++ b/vendor/github.com/ethereum/go-ethereum/Dockerfile @@ -1,5 +1,5 @@ # Build Geth in a stock Go builder container -FROM golang:1.11-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache make gcc musl-dev linux-headers diff --git a/vendor/github.com/ethereum/go-ethereum/Dockerfile.alltools b/vendor/github.com/ethereum/go-ethereum/Dockerfile.alltools index e984a1b0..4a4a26f8 100644 --- a/vendor/github.com/ethereum/go-ethereum/Dockerfile.alltools +++ b/vendor/github.com/ethereum/go-ethereum/Dockerfile.alltools @@ -1,5 +1,5 @@ # Build Geth in a stock Go builder container -FROM golang:1.11-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache make gcc musl-dev linux-headers diff --git a/vendor/github.com/ethereum/go-ethereum/README.md b/vendor/github.com/ethereum/go-ethereum/README.md index f308fb10..ea8b0a49 100644 --- a/vendor/github.com/ethereum/go-ethereum/README.md +++ b/vendor/github.com/ethereum/go-ethereum/README.md @@ -1,6 +1,6 @@ ## Go Ethereum -Official golang implementation of the Ethereum protocol. +Official Golang implementation of the Ethereum protocol. [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 @@ -18,7 +18,7 @@ For prerequisites and detailed build instructions please read the [Installation Instructions](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum) on the wiki. -Building geth requires both a Go (version 1.7 or later) and a C compiler. +Building geth requires both a Go (version 1.10 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run @@ -35,12 +35,12 @@ The go-ethereum project comes with several wrappers/executables found in the `cm | Command | Description | |:----------:|-------------| | **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. | +| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. | | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). | | `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. | -| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | -| `swarm` | Swarm daemon and tools. This is the entrypoint for the Swarm network. `swarm --help` for command line options and subcommands. See [Swarm README](https://github.com/ethereum/go-ethereum/tree/master/swarm) for more information. | +| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | +| `swarm` | Swarm daemon and tools. This is the entry point for the Swarm network. `swarm --help` for command line options and subcommands. See [Swarm README](https://github.com/ethereum/go-ethereum/tree/master/swarm) for more information. | | `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | ## Running geth @@ -72,7 +72,7 @@ This command will: This tool is optional and if you leave it out you can always attach to an already running Geth instance with `geth attach`. -### Full node on the Ethereum test network +### A Full node on the Ethereum test network Transitioning towards developers, if you'd like to play around with creating Ethereum contracts, you almost certainly would like to do that without any real money involved until you get the hang of the @@ -83,10 +83,10 @@ network with your node, which is fully equivalent to the main network, but with $ geth --testnet console ``` -The `console` subcommand have the exact same meaning as above and they are equally useful on the -testnet too. Please see above for their explanations if you've skipped to here. +The `console` subcommand has the exact same meaning as above and they are equally useful on the +testnet too. Please see above for their explanations if you've skipped here. -Specifying the `--testnet` flag however will reconfigure your Geth instance a bit: +Specifying the `--testnet` flag, however, will reconfigure your Geth instance a bit: * Instead of using the default data directory (`~/.ethereum` on Linux for example), Geth will nest itself one level deeper into a `testnet` subfolder (`~/.ethereum/testnet` on Linux). Note, on OSX @@ -103,7 +103,7 @@ separate the two networks and will not make any accounts available between them. ### Full node on the Rinkeby test network -The above test network is a cross client one based on the ethash proof-of-work consensus algorithm. As such, it has certain extra overhead and is more susceptible to reorganization attacks due to the network's low difficulty / security. Go Ethereum also supports connecting to a proof-of-authority based test network called [*Rinkeby*](https://www.rinkeby.io) (operated by members of the community). This network is lighter, more secure, but is only supported by go-ethereum. +The above test network is a cross-client one based on the ethash proof-of-work consensus algorithm. As such, it has certain extra overhead and is more susceptible to reorganization attacks due to the network's low difficulty/security. Go Ethereum also supports connecting to a proof-of-authority based test network called [*Rinkeby*](https://www.rinkeby.io) (operated by members of the community). This network is lighter, more secure, but is only supported by go-ethereum. ``` $ geth --rinkeby console @@ -139,13 +139,13 @@ This will start geth in fast-sync mode with a DB memory allowance of 1GB just as Do not forget `--rpcaddr 0.0.0.0`, if you want to access RPC from other containers and/or hosts. By default, `geth` binds to the local interface and RPC endpoints is not accessible from the outside. -### Programatically interfacing Geth nodes +### Programmatically interfacing Geth nodes As a developer, sooner rather than later you'll want to start interacting with Geth and the Ethereum network via your own programs and not manually through the console. To aid this, Geth has built-in support for a JSON-RPC based APIs ([standard APIs](https://github.com/ethereum/wiki/wiki/JSON-RPC) and [Geth specific APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)). These can be -exposed via HTTP, WebSockets and IPC (unix sockets on unix based platforms, and named pipes on Windows). +exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based platforms, and named pipes on Windows). The IPC interface is enabled by default and exposes all the APIs supported by Geth, whereas the HTTP and WS interfaces need to manually be enabled and only expose a subset of APIs due to security reasons. @@ -168,12 +168,12 @@ HTTP based JSON-RPC API options: * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) You'll need to use your own programming environments' capabilities (libraries, tools, etc) to connect -via HTTP, WS or IPC to a Geth node configured with the above flags and you'll need to speak [JSON-RPC](http://www.jsonrpc.org/specification) +via HTTP, WS or IPC to a Geth node configured with the above flags and you'll need to speak [JSON-RPC](https://www.jsonrpc.org/specification) on all transports. You can reuse the same connection for multiple requests! **Note: Please understand the security implications of opening up an HTTP/WS based transport before doing so! Hackers on the internet are actively trying to subvert Ethereum nodes with exposed APIs! -Further, all browser tabs can access locally running webservers, so malicious webpages could try to +Further, all browser tabs can access locally running web servers, so malicious web pages could try to subvert locally available APIs!** ### Operating a private network @@ -241,7 +241,7 @@ that other nodes can use to connect to it and exchange peer information. Make su displayed IP address information (most probably `[::]`) with your externally accessible IP to get the actual `enode` URL. -*Note: You could also use a full fledged Geth node as a bootnode, but it's the less recommended way.* +*Note: You could also use a full-fledged Geth node as a bootnode, but it's the less recommended way.* #### Starting up your member nodes @@ -264,7 +264,7 @@ an OpenCL or CUDA enabled `ethminer` instance. For information on such a setup, [EtherMining subreddit](https://www.reddit.com/r/EtherMining/) and the [Genoil miner](https://github.com/Genoil/cpp-ethereum) repository. -In a private network setting however, a single CPU miner instance is more than enough for practical +In a private network setting, however a single CPU miner instance is more than enough for practical purposes as it can produce a stable stream of blocks at the correct intervals without needing heavy resources (consider running on a single thread, no need for multiple ones either). To start a Geth instance for mining, run it with all your usual flags, extended by: @@ -298,7 +298,7 @@ Please make sure your contributions adhere to our coding guidelines: * E.g. "eth, rpc: make trace configs optional" Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide) -for more details on configuring your environment, managing project dependencies and testing procedures. +for more details on configuring your environment, managing project dependencies, and testing procedures. ## License diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi.go index d1fa3685..c5fbc1e7 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi.go @@ -58,13 +58,11 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { return nil, err } return arguments, nil - } method, exist := abi.Methods[name] if !exist { return nil, fmt.Errorf("method '%s' not found", name) } - arguments, err := method.Inputs.Pack(args...) if err != nil { return nil, err @@ -74,37 +72,39 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { } // Unpack output in v according to the abi specification -func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { - if len(output) == 0 { +func (abi ABI) Unpack(v interface{}, name string, data []byte) (err error) { + if len(data) == 0 { return fmt.Errorf("abi: unmarshalling empty output") } // since there can't be naming collisions with contracts and events, // we need to decide whether we're calling a method or an event if method, ok := abi.Methods[name]; ok { - if len(output)%32 != 0 { - return fmt.Errorf("abi: improperly formatted output") + if len(data)%32 != 0 { + return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data) } - return method.Outputs.Unpack(v, output) - } else if event, ok := abi.Events[name]; ok { - return event.Inputs.Unpack(v, output) + return method.Outputs.Unpack(v, data) + } + if event, ok := abi.Events[name]; ok { + return event.Inputs.Unpack(v, data) } return fmt.Errorf("abi: could not locate named method or event") } -// Unpack output into a map according to the abi specification -func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, output []byte) (err error) { - if len(output) == 0 { +// UnpackIntoMap unpacks a log into the provided map[string]interface{} +func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) { + if len(data) == 0 { return fmt.Errorf("abi: unmarshalling empty output") } // since there can't be naming collisions with contracts and events, // we need to decide whether we're calling a method or an event if method, ok := abi.Methods[name]; ok { - if len(output)%32 != 0 { + if len(data)%32 != 0 { return fmt.Errorf("abi: improperly formatted output") } - return method.Outputs.UnpackIntoMap(v, output) - } else if event, ok := abi.Events[name]; ok { - return event.Inputs.UnpackIntoMap(v, output) + return method.Outputs.UnpackIntoMap(v, data) + } + if event, ok := abi.Events[name]; ok { + return event.Inputs.UnpackIntoMap(v, data) } return fmt.Errorf("abi: could not locate named method or event") } @@ -156,7 +156,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { // returns nil if none found func (abi *ABI) MethodById(sigdata []byte) (*Method, error) { if len(sigdata) < 4 { - return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata)) + return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata)) } for _, method := range abi.Methods { if bytes.Equal(method.Id(), sigdata[:4]) { diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi_test.go index 59ba79cb..42b60a63 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi_test.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/abi_test.go @@ -22,11 +22,10 @@ import ( "fmt" "log" "math/big" + "reflect" "strings" "testing" - "reflect" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -52,11 +51,14 @@ const jsondata2 = ` { "type" : "function", "name" : "slice", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, { "type" : "function", "name" : "slice256", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, { "type" : "function", "name" : "sliceAddress", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, - { "type" : "function", "name" : "sliceMultiAddress", "constant" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] } + { "type" : "function", "name" : "sliceMultiAddress", "constant" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] }, + { "type" : "function", "name" : "nestedArray", "constant" : false, "inputs" : [ { "name" : "a", "type" : "uint256[2][2]" }, { "name" : "b", "type" : "address[]" } ] }, + { "type" : "function", "name" : "nestedArray2", "constant" : false, "inputs" : [ { "name" : "a", "type" : "uint8[][2]" } ] }, + { "type" : "function", "name" : "nestedSlice", "constant" : false, "inputs" : [ { "name" : "a", "type" : "uint8[][]" } ] } ]` func TestReader(t *testing.T) { - Uint256, _ := NewType("uint256") + Uint256, _ := NewType("uint256", nil) exp := ABI{ Methods: map[string]Method{ "balance": { @@ -177,7 +179,7 @@ func TestTestSlice(t *testing.T) { } func TestMethodSignature(t *testing.T) { - String, _ := NewType("string") + String, _ := NewType("string", nil) m := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil} exp := "foo(string,string)" if m.Sig() != exp { @@ -189,12 +191,31 @@ func TestMethodSignature(t *testing.T) { t.Errorf("expected ids to match %x != %x", m.Id(), idexp) } - uintt, _ := NewType("uint256") + uintt, _ := NewType("uint256", nil) m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil} exp = "foo(uint256)" if m.Sig() != exp { t.Error("signature mismatch", exp, "!=", m.Sig()) } + + // Method with tuple arguments + s, _ := NewType("tuple", []ArgumentMarshaling{ + {Name: "a", Type: "int256"}, + {Name: "b", Type: "int256[]"}, + {Name: "c", Type: "tuple[]", Components: []ArgumentMarshaling{ + {Name: "x", Type: "int256"}, + {Name: "y", Type: "int256"}, + }}, + {Name: "d", Type: "tuple[2]", Components: []ArgumentMarshaling{ + {Name: "x", Type: "int256"}, + {Name: "y", Type: "int256"}, + }}, + }) + m = Method{"foo", false, []Argument{{"s", s, false}, {"bar", String, false}}, nil} + exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)" + if m.Sig() != exp { + t.Error("signature mismatch", exp, "!=", m.Sig()) + } } func TestMultiPack(t *testing.T) { @@ -564,11 +585,13 @@ func TestBareEvents(t *testing.T) { const definition = `[ { "type" : "event", "name" : "balance" }, { "type" : "event", "name" : "anon", "anonymous" : true}, - { "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] } + { "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] }, + { "type" : "event", "name" : "tuple", "inputs" : [{ "indexed":false, "name":"t", "type":"tuple", "components":[{"name":"a", "type":"uint256"}] }, { "indexed":true, "name":"arg1", "type":"address" }] } ]` - arg0, _ := NewType("uint256") - arg1, _ := NewType("address") + arg0, _ := NewType("uint256", nil) + arg1, _ := NewType("address", nil) + tuple, _ := NewType("tuple", []ArgumentMarshaling{{Name: "a", Type: "uint256"}}) expectedEvents := map[string]struct { Anonymous bool @@ -580,6 +603,10 @@ func TestBareEvents(t *testing.T) { {Name: "arg0", Type: arg0, Indexed: false}, {Name: "arg1", Type: arg1, Indexed: true}, }}, + "tuple": {false, []Argument{ + {Name: "t", Type: tuple, Indexed: false}, + {Name: "arg1", Type: arg1, Indexed: true}, + }}, } abi, err := JSON(strings.NewReader(definition)) @@ -646,28 +673,210 @@ func TestUnpackEvent(t *testing.T) { } type ReceivedEvent struct { - Address common.Address - Amount *big.Int - Memo []byte + Sender common.Address + Amount *big.Int + Memo []byte } var ev ReceivedEvent err = abi.Unpack(&ev, "received", data) if err != nil { t.Error(err) - } else { - t.Logf("len(data): %d; received event: %+v", len(data), ev) } type ReceivedAddrEvent struct { - Address common.Address + Sender common.Address } var receivedAddrEv ReceivedAddrEvent err = abi.Unpack(&receivedAddrEv, "receivedAddr", data) if err != nil { t.Error(err) - } else { - t.Logf("len(data): %d; received event: %+v", len(data), receivedAddrEv) + } +} + +func TestUnpackEventIntoMap(t *testing.T) { + const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` + abi, err := JSON(strings.NewReader(abiJSON)) + if err != nil { + t.Fatal(err) + } + + const hexdata = `000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158` + data, err := hex.DecodeString(hexdata) + if err != nil { + t.Fatal(err) + } + if len(data)%32 == 0 { + t.Errorf("len(data) is %d, want a non-multiple of 32", len(data)) + } + + receivedMap := map[string]interface{}{} + expectedReceivedMap := map[string]interface{}{ + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err := abi.UnpackIntoMap(receivedMap, "received", data); err != nil { + t.Error(err) + } + if len(receivedMap) != 3 { + t.Error("unpacked `received` map expected to have length 3") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked `received` map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked `received` map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked `received` map does not match expected map") + } + + receivedAddrMap := map[string]interface{}{} + if err = abi.UnpackIntoMap(receivedAddrMap, "receivedAddr", data); err != nil { + t.Error(err) + } + if len(receivedAddrMap) != 1 { + t.Error("unpacked `receivedAddr` map expected to have length 1") + } + if receivedAddrMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked `receivedAddr` map does not match expected map") + } +} + +func TestUnpackMethodIntoMap(t *testing.T) { + const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]` + abi, err := JSON(strings.NewReader(abiJSON)) + if err != nil { + t.Fatal(err) + } + const hexdata = `00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000015800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000158000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000015800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000158` + data, err := hex.DecodeString(hexdata) + if err != nil { + t.Fatal(err) + } + if len(data)%32 != 0 { + t.Errorf("len(data) is %d, want a multiple of 32", len(data)) + } + + // Tests a method with no outputs + receiveMap := map[string]interface{}{} + if err = abi.UnpackIntoMap(receiveMap, "receive", data); err != nil { + t.Error(err) + } + if len(receiveMap) > 0 { + t.Error("unpacked `receive` map expected to have length 0") + } + + // Tests a method with only outputs + sendMap := map[string]interface{}{} + if err = abi.UnpackIntoMap(sendMap, "send", data); err != nil { + t.Error(err) + } + if len(sendMap) != 1 { + t.Error("unpacked `send` map expected to have length 1") + } + if sendMap["amount"].(*big.Int).Cmp(big.NewInt(1)) != 0 { + t.Error("unpacked `send` map expected `amount` value of 1") + } + + // Tests a method with outputs and inputs + getMap := map[string]interface{}{} + if err = abi.UnpackIntoMap(getMap, "get", data); err != nil { + t.Error(err) + } + if len(sendMap) != 1 { + t.Error("unpacked `get` map expected to have length 1") + } + expectedBytes := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 88, 0} + if !bytes.Equal(getMap["hash"].([]byte), expectedBytes) { + t.Errorf("unpacked `get` map expected `hash` value of %v", expectedBytes) + } +} + +func TestUnpackIntoMapNamingConflict(t *testing.T) { + // Two methods have the same name + var abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"get","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]` + abi, err := JSON(strings.NewReader(abiJSON)) + if err != nil { + t.Fatal(err) + } + var hexdata = `00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158` + data, err := hex.DecodeString(hexdata) + if err != nil { + t.Fatal(err) + } + if len(data)%32 == 0 { + t.Errorf("len(data) is %d, want a non-multiple of 32", len(data)) + } + getMap := map[string]interface{}{} + if err = abi.UnpackIntoMap(getMap, "get", data); err == nil { + t.Error("naming conflict between two methods; error expected") + } + + // Two events have the same name + abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"received","type":"event"}]` + abi, err = JSON(strings.NewReader(abiJSON)) + if err != nil { + t.Fatal(err) + } + hexdata = `000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158` + data, err = hex.DecodeString(hexdata) + if err != nil { + t.Fatal(err) + } + if len(data)%32 == 0 { + t.Errorf("len(data) is %d, want a non-multiple of 32", len(data)) + } + receivedMap := map[string]interface{}{} + if err = abi.UnpackIntoMap(receivedMap, "received", data); err != nil { + t.Error("naming conflict between two events; no error expected") + } + if len(receivedMap) != 1 { + t.Error("naming conflict between two events; event defined latest in the abi expected to be used") + } + + // Method and event have the same name + abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"received","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` + abi, err = JSON(strings.NewReader(abiJSON)) + if err != nil { + t.Fatal(err) + } + if len(data)%32 == 0 { + t.Errorf("len(data) is %d, want a non-multiple of 32", len(data)) + } + if err = abi.UnpackIntoMap(receivedMap, "received", data); err == nil { + t.Error("naming conflict between an event and a method; error expected") + } + + // Conflict is case sensitive + abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"received","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` + abi, err = JSON(strings.NewReader(abiJSON)) + if err != nil { + t.Fatal(err) + } + if len(data)%32 == 0 { + t.Errorf("len(data) is %d, want a non-multiple of 32", len(data)) + } + expectedReceivedMap := map[string]interface{}{ + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err = abi.UnpackIntoMap(receivedMap, "Received", data); err != nil { + t.Error(err) + } + if len(receivedMap) != 3 { + t.Error("unpacked `received` map expected to have length 3") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked `received` map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked `received` map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked `received` map does not match expected map") } } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/argument.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/argument.go index b1eee394..501cb162 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/argument.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/argument.go @@ -33,24 +33,27 @@ type Argument struct { type Arguments []Argument +type ArgumentMarshaling struct { + Name string + Type string + Components []ArgumentMarshaling + Indexed bool +} + // UnmarshalJSON implements json.Unmarshaler interface func (argument *Argument) UnmarshalJSON(data []byte) error { - var extarg struct { - Name string - Type string - Indexed bool - } - err := json.Unmarshal(data, &extarg) + var arg ArgumentMarshaling + err := json.Unmarshal(data, &arg) if err != nil { return fmt.Errorf("argument json err: %v", err) } - argument.Type, err = NewType(extarg.Type) + argument.Type, err = NewType(arg.Type, arg.Components) if err != nil { return err } - argument.Name = extarg.Name - argument.Indexed = extarg.Indexed + argument.Name = arg.Name + argument.Indexed = arg.Indexed return nil } @@ -85,7 +88,6 @@ func (arguments Arguments) isTuple() bool { // Unpack performs the operation hexdata -> Go format func (arguments Arguments) Unpack(v interface{}, data []byte) error { - // make sure the passed value is arguments pointer if reflect.Ptr != reflect.ValueOf(v).Kind() { return fmt.Errorf("abi: Unpack(non-pointer %T)", v) @@ -97,71 +99,78 @@ func (arguments Arguments) Unpack(v interface{}, data []byte) error { if arguments.isTuple() { return arguments.unpackTuple(v, marshalledValues) } - return arguments.unpackAtomic(v, marshalledValues) + return arguments.unpackAtomic(v, marshalledValues[0]) } -// Unpack performs the operation hexdata -> Go map +// UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) error { marshalledValues, err := arguments.UnpackValues(data) if err != nil { return err } + return arguments.unpackIntoMap(v, marshalledValues) } -func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { - +// unpack sets the unmarshalled value to go format. +// Note the dst here must be settable. +func unpack(t *Type, dst interface{}, src interface{}) error { var ( - value = reflect.ValueOf(v).Elem() - typ = value.Type() - kind = value.Kind() + dstVal = reflect.ValueOf(dst).Elem() + srcVal = reflect.ValueOf(src) ) - if err := requireUnpackKind(value, typ, kind, arguments); err != nil { - return err + if t.T != TupleTy && !((t.T == SliceTy || t.T == ArrayTy) && t.Elem.T == TupleTy) { + return set(dstVal, srcVal) } - // If the interface is a struct, get of abi->struct_field mapping - - var abi2struct map[string]string - if kind == reflect.Struct { - var err error - abi2struct, err = mapAbiToStructFields(arguments, value) + switch t.T { + case TupleTy: + if dstVal.Kind() != reflect.Struct { + return fmt.Errorf("abi: invalid dst value for unpack, want struct, got %s", dstVal.Kind()) + } + fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, dstVal) if err != nil { return err } - } - for i, arg := range arguments.NonIndexed() { - - reflectValue := reflect.ValueOf(marshalledValues[i]) - - switch kind { - case reflect.Struct: - if structField, ok := abi2struct[arg.Name]; ok { - if err := set(value.FieldByName(structField), reflectValue, arg); err != nil { - return err - } + for i, elem := range t.TupleElems { + fname := fieldmap[t.TupleRawNames[i]] + field := dstVal.FieldByName(fname) + if !field.IsValid() { + return fmt.Errorf("abi: field %s can't found in the given value", t.TupleRawNames[i]) } - case reflect.Slice, reflect.Array: - if value.Len() < i { - return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) - } - v := value.Index(i) - if err := requireAssignable(v, reflectValue); err != nil { + if err := unpack(elem, field.Addr().Interface(), srcVal.Field(i).Interface()); err != nil { return err } - - if err := set(v.Elem(), reflectValue, arg); err != nil { - return err - } - default: - return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) } + return nil + case SliceTy: + if dstVal.Kind() != reflect.Slice { + return fmt.Errorf("abi: invalid dst value for unpack, want slice, got %s", dstVal.Kind()) + } + slice := reflect.MakeSlice(dstVal.Type(), srcVal.Len(), srcVal.Len()) + for i := 0; i < slice.Len(); i++ { + if err := unpack(t.Elem, slice.Index(i).Addr().Interface(), srcVal.Index(i).Interface()); err != nil { + return err + } + } + dstVal.Set(slice) + case ArrayTy: + if dstVal.Kind() != reflect.Array { + return fmt.Errorf("abi: invalid dst value for unpack, want array, got %s", dstVal.Kind()) + } + array := reflect.New(dstVal.Type()).Elem() + for i := 0; i < array.Len(); i++ { + if err := unpack(t.Elem, array.Index(i).Addr().Interface(), srcVal.Index(i).Interface()); err != nil { + return err + } + } + dstVal.Set(array) } return nil } -// Unpack arguments into map +// unpackIntoMap unpacks marshalledValues into the provided map[string]interface{} func (arguments Arguments) unpackIntoMap(v map[string]interface{}, marshalledValues []interface{}) error { // Make sure map is not nil if v == nil { @@ -175,45 +184,80 @@ func (arguments Arguments) unpackIntoMap(v map[string]interface{}, marshalledVal } // unpackAtomic unpacks ( hexdata -> go ) a single value -func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error { - if len(marshalledValues) != 1 { - return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) - } - - elem := reflect.ValueOf(v).Elem() - kind := elem.Kind() - reflectValue := reflect.ValueOf(marshalledValues[0]) - - var abi2struct map[string]string - if kind == reflect.Struct { - var err error - if abi2struct, err = mapAbiToStructFields(arguments, elem); err != nil { - return err - } - arg := arguments.NonIndexed()[0] - if structField, ok := abi2struct[arg.Name]; ok { - return set(elem.FieldByName(structField), reflectValue, arg) - } +func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error { + if arguments.LengthNonIndexed() == 0 { return nil } + argument := arguments.NonIndexed()[0] + elem := reflect.ValueOf(v).Elem() - return set(elem, reflectValue, arguments.NonIndexed()[0]) - + if elem.Kind() == reflect.Struct { + fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem) + if err != nil { + return err + } + field := elem.FieldByName(fieldmap[argument.Name]) + if !field.IsValid() { + return fmt.Errorf("abi: field %s can't be found in the given value", argument.Name) + } + return unpack(&argument.Type, field.Addr().Interface(), marshalledValues) + } + return unpack(&argument.Type, elem.Addr().Interface(), marshalledValues) } -// Computes the full size of an array; -// i.e. counting nested arrays, which count towards size for unpacking. -func getArraySize(arr *Type) int { - size := arr.Size - // Arrays can be nested, with each element being the same size - arr = arr.Elem - for arr.T == ArrayTy { - // Keep multiplying by elem.Size while the elem is an array. - size *= arr.Size - arr = arr.Elem +// unpackTuple unpacks ( hexdata -> go ) a batch of values. +func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { + var ( + value = reflect.ValueOf(v).Elem() + typ = value.Type() + kind = value.Kind() + ) + if err := requireUnpackKind(value, typ, kind, arguments); err != nil { + return err } - // Now we have the full array size, including its children. - return size + + // If the interface is a struct, get of abi->struct_field mapping + var abi2struct map[string]string + if kind == reflect.Struct { + var ( + argNames []string + err error + ) + for _, arg := range arguments.NonIndexed() { + argNames = append(argNames, arg.Name) + } + abi2struct, err = mapArgNamesToStructFields(argNames, value) + if err != nil { + return err + } + } + for i, arg := range arguments.NonIndexed() { + switch kind { + case reflect.Struct: + field := value.FieldByName(abi2struct[arg.Name]) + if !field.IsValid() { + return fmt.Errorf("abi: field %s can't be found in the given value", arg.Name) + } + if err := unpack(&arg.Type, field.Addr().Interface(), marshalledValues[i]); err != nil { + return err + } + case reflect.Slice, reflect.Array: + if value.Len() < i { + return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len()) + } + v := value.Index(i) + if err := requireAssignable(v, reflect.ValueOf(marshalledValues[i])); err != nil { + return err + } + if err := unpack(&arg.Type, v.Addr().Interface(), marshalledValues[i]); err != nil { + return err + } + default: + return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ) + } + } + return nil + } // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, @@ -224,7 +268,7 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { virtualArgs := 0 for index, arg := range arguments.NonIndexed() { marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) - if arg.Type.T == ArrayTy { + if arg.Type.T == ArrayTy && !isDynamicType(arg.Type) { // If we have a static array, like [3]uint256, these are coded as // just like uint256,uint256,uint256. // This means that we need to add two 'virtual' arguments when @@ -235,7 +279,11 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { // // Calculate the full array size to get the correct offset for the next argument. // Decrement it by 1, as the normal index increment is still applied. - virtualArgs += getArraySize(&arg.Type) - 1 + virtualArgs += getTypeSize(arg.Type)/32 - 1 + } else if arg.Type.T == TupleTy && !isDynamicType(arg.Type) { + // If we have a static tuple, like (uint256, bool, uint256), these are + // coded as just like uint256,bool,uint256 + virtualArgs += getTypeSize(arg.Type)/32 - 1 } if err != nil { return nil, err @@ -265,11 +313,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { // input offset is the bytes offset for packed output inputOffset := 0 for _, abiArg := range abiArgs { - if abiArg.Type.T == ArrayTy { - inputOffset += 32 * abiArg.Type.Size - } else { - inputOffset += 32 - } + inputOffset += getTypeSize(abiArg.Type) } var ret []byte for i, a := range args { @@ -279,14 +323,13 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { if err != nil { return nil, err } - // check for a slice type (string, bytes, slice) - if input.Type.requiresLengthPrefix() { - // calculate the offset - offset := inputOffset + len(variableInput) + // check for dynamic types + if isDynamicType(input.Type) { // set the offset - ret = append(ret, packNum(reflect.ValueOf(offset))...) - // Append the packed output to the variable input. The variable input - // will be appended at the end of the input. + ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) + // calculate next offset + inputOffset += len(packed) + // append to variable input variableInput = append(variableInput, packed...) } else { // append the packed value to the input @@ -299,14 +342,13 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { return ret, nil } -// capitalise makes the first character of a string upper case, also removing any -// prefixing underscores from the variable names. -func capitalise(input string) string { - for len(input) > 0 && input[0] == '_' { - input = input[1:] +// ToCamelCase converts an under-score string to a camel-case string +func ToCamelCase(input string) string { + parts := strings.Split(input, "_") + for i, s := range parts { + if len(s) > 0 { + parts[i] = strings.ToUpper(s[:1]) + s[1:] + } } - if len(input) == 0 { - return "" - } - return strings.ToUpper(input[:1]) + input[1:] + return strings.Join(parts, "") } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go index 6f46fc14..7371dfb1 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go @@ -66,7 +66,7 @@ type SimulatedBackend struct { // NewSimulatedBackend creates a new binding backend using a simulated blockchain // for testing purposes. func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { - database := ethdb.NewMemDatabase() + database := rawdb.NewMemoryDatabase() genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} genesis.MustCommit(database) blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil) @@ -164,6 +164,25 @@ func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common return receipt, nil } +// TransactionByHash checks the pool of pending transactions in addition to the +// blockchain. The isPending return value indicates whether the transaction has been +// mined yet. Note that the transaction may not be part of the canonical chain even if +// it's not pending. +func (b *SimulatedBackend) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + b.mu.Lock() + defer b.mu.Unlock() + + tx := b.pendingBlock.Transaction(txHash) + if tx != nil { + return tx, true, nil + } + tx, _, _, _ = rawdb.ReadTransaction(b.database, txHash) + if tx != nil { + return tx, false, nil + } + return nil, false, ethereum.NotFound +} + // PendingCodeAt returns the code associated with an account in the pending state. func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { b.mu.Lock() diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated_test.go new file mode 100644 index 00000000..bd75807d --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated_test.go @@ -0,0 +1,82 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package backends_test + +import ( + "context" + "math/big" + "testing" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" +) + +func TestSimulatedBackend(t *testing.T) { + var gasLimit uint64 = 8000029 + key, _ := crypto.GenerateKey() // nolint: gosec + auth := bind.NewKeyedTransactor(key) + genAlloc := make(core.GenesisAlloc) + genAlloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(9223372036854775807)} + + sim := backends.NewSimulatedBackend(genAlloc, gasLimit) + + // should return an error if the tx is not found + txHash := common.HexToHash("2") + _, isPending, err := sim.TransactionByHash(context.Background(), txHash) + + if isPending { + t.Fatal("transaction should not be pending") + } + if err != ethereum.NotFound { + t.Fatalf("err should be `ethereum.NotFound` but received %v", err) + } + + // generate a transaction and confirm you can retrieve it + code := `6060604052600a8060106000396000f360606040526008565b00` + var gas uint64 = 3000000 + tx := types.NewContractCreation(0, big.NewInt(0), gas, big.NewInt(1), common.FromHex(code)) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, key) + + err = sim.SendTransaction(context.Background(), tx) + if err != nil { + t.Fatal("error sending transaction") + } + + txHash = tx.Hash() + _, isPending, err = sim.TransactionByHash(context.Background(), txHash) + if err != nil { + t.Fatalf("error getting transaction with hash: %v", txHash.String()) + } + if !isPending { + t.Fatal("transaction should have pending status") + } + + sim.Commit() + tx, isPending, err = sim.TransactionByHash(context.Background(), txHash) + if err != nil { + t.Fatalf("error getting transaction with hash: %v", txHash.String()) + } + if isPending { + t.Fatal("transaction should not have pending status") + } + +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base.go index 2da4f449..f70f911d 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base.go @@ -36,10 +36,10 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra // CallOpts is the collection of options to fine tune a contract call request. type CallOpts struct { - Pending bool // Whether to operate on the pending state or the last known one - From common.Address // Optional the sender address, otherwise the first account is used - - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) + Pending bool // Whether to operate on the pending state or the last known one + From common.Address // Optional the sender address, otherwise the first account is used + BlockNumber *big.Int // Optional the block number on which the call should be performed + Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) } // TransactOpts is the collection of authorization data required to create a @@ -148,10 +148,10 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, } } } else { - output, err = c.caller.CallContract(ctx, msg, nil) + output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber) if err == nil && len(output) == 0 { // Make sure we have a contract to operate on, and bail out otherwise. - if code, err = c.caller.CodeAt(ctx, c.address, nil); err != nil { + if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil { return err } else if len(code) == 0 { return ErrNoCode diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base_test.go new file mode 100644 index 00000000..f65c9e9b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/base_test.go @@ -0,0 +1,373 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package bind_test + +import ( + "bytes" + "context" + "math/big" + "strings" + "testing" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +type mockCaller struct { + codeAtBlockNumber *big.Int + callContractBlockNumber *big.Int +} + +func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { + mc.codeAtBlockNumber = blockNumber + return []byte{1, 2, 3}, nil +} + +func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + mc.callContractBlockNumber = blockNumber + return nil, nil +} +func TestPassingBlockNumber(t *testing.T) { + + mc := &mockCaller{} + + bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{ + Methods: map[string]abi.Method{ + "something": { + Name: "something", + Outputs: abi.Arguments{}, + }, + }, + }, mc, nil, nil) + var ret string + + blockNumber := big.NewInt(42) + + bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something") + + if mc.callContractBlockNumber != blockNumber { + t.Fatalf("CallContract() was not passed the block number") + } + + if mc.codeAtBlockNumber != blockNumber { + t.Fatalf("CodeAt() was not passed the block number") + } + + bc.Call(&bind.CallOpts{}, &ret, "something") + + if mc.callContractBlockNumber != nil { + t.Fatalf("CallContract() was passed a block number when it should not have been") + } + + if mc.codeAtBlockNumber != nil { + t.Fatalf("CodeAt() was passed a block number when it should not have been") + } +} + +const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158" + +func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { + hash := crypto.Keccak256Hash([]byte("testName")) + mockLog := types.Log{ + Address: common.HexToAddress("0x0"), + Topics: []common.Hash{ + common.HexToHash("0x0"), + hash, + }, + Data: hexutil.MustDecode(hexData), + BlockNumber: uint64(26), + TxHash: common.HexToHash("0x0"), + TxIndex: 111, + BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), + Index: 7, + Removed: false, + } + + abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + receivedMap := make(map[string]interface{}) + expectedReceivedMap := map[string]interface{}{ + "name": hash, + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { + t.Error(err) + } + + if len(receivedMap) != 4 { + t.Fatal("unpacked map expected to have length 4") + } + if receivedMap["name"] != expectedReceivedMap["name"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked map does not match expected map") + } +} + +func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { + sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) + if err != nil { + t.Fatal(err) + } + hash := crypto.Keccak256Hash(sliceBytes) + mockLog := types.Log{ + Address: common.HexToAddress("0x0"), + Topics: []common.Hash{ + common.HexToHash("0x0"), + hash, + }, + Data: hexutil.MustDecode(hexData), + BlockNumber: uint64(26), + TxHash: common.HexToHash("0x0"), + TxIndex: 111, + BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), + Index: 7, + Removed: false, + } + + abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"names","type":"string[]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + receivedMap := make(map[string]interface{}) + expectedReceivedMap := map[string]interface{}{ + "names": hash, + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { + t.Error(err) + } + + if len(receivedMap) != 4 { + t.Fatal("unpacked map expected to have length 4") + } + if receivedMap["names"] != expectedReceivedMap["names"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked map does not match expected map") + } +} + +func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { + arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")}) + if err != nil { + t.Fatal(err) + } + hash := crypto.Keccak256Hash(arrBytes) + mockLog := types.Log{ + Address: common.HexToAddress("0x0"), + Topics: []common.Hash{ + common.HexToHash("0x0"), + hash, + }, + Data: hexutil.MustDecode(hexData), + BlockNumber: uint64(26), + TxHash: common.HexToHash("0x0"), + TxIndex: 111, + BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), + Index: 7, + Removed: false, + } + + abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"addresses","type":"address[2]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + receivedMap := make(map[string]interface{}) + expectedReceivedMap := map[string]interface{}{ + "addresses": hash, + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { + t.Error(err) + } + + if len(receivedMap) != 4 { + t.Fatal("unpacked map expected to have length 4") + } + if receivedMap["addresses"] != expectedReceivedMap["addresses"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked map does not match expected map") + } +} + +func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { + mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2") + addrBytes := mockAddress.Bytes() + hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)")) + functionSelector := hash[:4] + functionTyBytes := append(addrBytes, functionSelector...) + var functionTy [24]byte + copy(functionTy[:], functionTyBytes[0:24]) + mockLog := types.Log{ + Address: common.HexToAddress("0x0"), + Topics: []common.Hash{ + common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), + common.BytesToHash(functionTyBytes), + }, + Data: hexutil.MustDecode(hexData), + BlockNumber: uint64(26), + TxHash: common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), + TxIndex: 111, + BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), + Index: 7, + Removed: false, + } + + abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"function","type":"function"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + receivedMap := make(map[string]interface{}) + expectedReceivedMap := map[string]interface{}{ + "function": functionTy, + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { + t.Error(err) + } + + if len(receivedMap) != 4 { + t.Fatal("unpacked map expected to have length 4") + } + if receivedMap["function"] != expectedReceivedMap["function"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked map does not match expected map") + } +} + +func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { + byts := []byte{1, 2, 3, 4, 5} + hash := crypto.Keccak256Hash(byts) + mockLog := types.Log{ + Address: common.HexToAddress("0x0"), + Topics: []common.Hash{ + common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"), + hash, + }, + Data: hexutil.MustDecode(hexData), + BlockNumber: uint64(26), + TxHash: common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), + TxIndex: 111, + BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), + Index: 7, + Removed: false, + } + + abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + receivedMap := make(map[string]interface{}) + expectedReceivedMap := map[string]interface{}{ + "content": hash, + "sender": common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2"), + "amount": big.NewInt(1), + "memo": []byte{88}, + } + if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err != nil { + t.Error(err) + } + + if len(receivedMap) != 4 { + t.Fatal("unpacked map expected to have length 4") + } + if receivedMap["content"] != expectedReceivedMap["content"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["sender"] != expectedReceivedMap["sender"] { + t.Error("unpacked map does not match expected map") + } + if receivedMap["amount"].(*big.Int).Cmp(expectedReceivedMap["amount"].(*big.Int)) != 0 { + t.Error("unpacked map does not match expected map") + } + if !bytes.Equal(receivedMap["memo"].([]byte), expectedReceivedMap["memo"].([]byte)) { + t.Error("unpacked map does not match expected map") + } +} + +func TestUnpackIntoMapNamingConflict(t *testing.T) { + hash := crypto.Keccak256Hash([]byte("testName")) + mockLog := types.Log{ + Address: common.HexToAddress("0x0"), + Topics: []common.Hash{ + common.HexToHash("0x0"), + hash, + }, + Data: hexutil.MustDecode(hexData), + BlockNumber: uint64(26), + TxHash: common.HexToHash("0x0"), + TxIndex: 111, + BlockHash: common.BytesToHash([]byte{1, 2, 3, 4, 5}), + Index: 7, + Removed: false, + } + + abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + receivedMap := make(map[string]interface{}) + if err := bc.UnpackLogIntoMap(receivedMap, "received", mockLog); err == nil { + t.Error("naming conflict between two events; error expected") + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind.go index 4dca4b4e..5ee30d02 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind.go @@ -381,54 +381,23 @@ func namedTypeJava(javaKind string, solKind abi.Type) string { // methodNormalizer is a name transformer that modifies Solidity method names to // conform to target language naming concentions. var methodNormalizer = map[Lang]func(string) string{ - LangGo: capitalise, + LangGo: abi.ToCamelCase, LangJava: decapitalise, } // capitalise makes a camel-case string which starts with an upper case character. func capitalise(input string) string { - for len(input) > 0 && input[0] == '_' { - input = input[1:] - } - if len(input) == 0 { - return "" - } - return toCamelCase(strings.ToUpper(input[:1]) + input[1:]) + return abi.ToCamelCase(input) } // decapitalise makes a camel-case string which starts with a lower case character. func decapitalise(input string) string { - for len(input) > 0 && input[0] == '_' { - input = input[1:] - } if len(input) == 0 { - return "" + return input } - return toCamelCase(strings.ToLower(input[:1]) + input[1:]) -} -// toCamelCase converts an under-score string to a camel-case string -func toCamelCase(input string) string { - toupper := false - - result := "" - for k, v := range input { - switch { - case k == 0: - result = strings.ToUpper(string(input[0])) - - case toupper: - result += strings.ToUpper(string(v)) - toupper = false - - case v == '_': - toupper = true - - default: - result += string(v) - } - } - return result + goForm := abi.ToCamelCase(input) + return strings.ToLower(goForm[:1]) + goForm[1:] } // structured checks whether a list of ABI data types has enough information to diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind_test.go index 46e0b38d..eae12b3f 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind_test.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind_test.go @@ -670,7 +670,7 @@ var bindTests = []struct { `Eventer`, ` contract Eventer { - event SimpleEvent ( + event SimpleEvent ( address indexed Addr, bytes32 indexed Id, bool indexed Flag, @@ -698,10 +698,18 @@ var bindTests = []struct { function raiseDynamicEvent(string str, bytes blob) { DynamicEvent(str, blob, str, blob); } + + event FixedBytesEvent ( + bytes24 indexed IndexedBytes, + bytes24 NonIndexedBytes + ); + function raiseFixedBytesEvent(bytes24 blob) { + FixedBytesEvent(blob, blob); + } } `, - `6060604052341561000f57600080fd5b61042c8061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063528300ff1461005c578063630c31e2146100fc578063c7d116dd14610156575b600080fd5b341561006757600080fd5b6100fa600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610194565b005b341561010757600080fd5b610154600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035600019169060200190919080351515906020019091908035906020019091905050610367565b005b341561016157600080fd5b610192600480803590602001909190803560010b90602001909190803563ffffffff169060200190919050506103c3565b005b806040518082805190602001908083835b6020831015156101ca57805182526020820191506020810190506020830392506101a5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020826040518082805190602001908083835b60208310151561022d5780518252602082019150602081019050602083039250610208565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f3281fd4f5e152dd3385df49104a3f633706e21c9e80672e88d3bcddf33101f008484604051808060200180602001838103835285818151815260200191508051906020019080838360005b838110156102c15780820151818401526020810190506102a6565b50505050905090810190601f1680156102ee5780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b8381101561032757808201518184015260208101905061030c565b50505050905090810190601f1680156103545780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a35050565b81151583600019168573ffffffffffffffffffffffffffffffffffffffff167f1f097de4289df643bd9c11011cc61367aa12983405c021056e706eb5ba1250c8846040518082815260200191505060405180910390a450505050565b8063ffffffff168260010b847f3ca7f3a77e5e6e15e781850bc82e32adfa378a2a609370db24b4d0fae10da2c960405160405180910390a45050505600a165627a7a72305820d1f8a8bbddbc5bb29f285891d6ae1eef8420c52afdc05e1573f6114d8e1714710029`, - `[{"constant":false,"inputs":[{"name":"str","type":"string"},{"name":"blob","type":"bytes"}],"name":"raiseDynamicEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"id","type":"bytes32"},{"name":"flag","type":"bool"},{"name":"value","type":"uint256"}],"name":"raiseSimpleEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"number","type":"uint256"},{"name":"short","type":"int16"},{"name":"long","type":"uint32"}],"name":"raiseNodataEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Addr","type":"address"},{"indexed":true,"name":"Id","type":"bytes32"},{"indexed":true,"name":"Flag","type":"bool"},{"indexed":false,"name":"Value","type":"uint256"}],"name":"SimpleEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Number","type":"uint256"},{"indexed":true,"name":"Short","type":"int16"},{"indexed":true,"name":"Long","type":"uint32"}],"name":"NodataEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexedString","type":"string"},{"indexed":true,"name":"IndexedBytes","type":"bytes"},{"indexed":false,"name":"NonIndexedString","type":"string"},{"indexed":false,"name":"NonIndexedBytes","type":"bytes"}],"name":"DynamicEvent","type":"event"}]`, + `608060405234801561001057600080fd5b5061043f806100206000396000f3006080604052600436106100615763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663528300ff8114610066578063630c31e2146100ff5780636cc6b94014610138578063c7d116dd1461015b575b600080fd5b34801561007257600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526100fd94369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506101829650505050505050565b005b34801561010b57600080fd5b506100fd73ffffffffffffffffffffffffffffffffffffffff60043516602435604435151560643561033c565b34801561014457600080fd5b506100fd67ffffffffffffffff1960043516610394565b34801561016757600080fd5b506100fd60043560243560010b63ffffffff604435166103d6565b806040518082805190602001908083835b602083106101b25780518252601f199092019160209182019101610193565b51815160209384036101000a6000190180199092169116179052604051919093018190038120875190955087945090928392508401908083835b6020831061020b5780518252601f1990920191602091820191016101ec565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f3281fd4f5e152dd3385df49104a3f633706e21c9e80672e88d3bcddf33101f008484604051808060200180602001838103835285818151815260200191508051906020019080838360005b8381101561029c578181015183820152602001610284565b50505050905090810190601f1680156102c95780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b838110156102fc5781810151838201526020016102e4565b50505050905090810190601f1680156103295780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a35050565b60408051828152905183151591859173ffffffffffffffffffffffffffffffffffffffff8816917f1f097de4289df643bd9c11011cc61367aa12983405c021056e706eb5ba1250c8919081900360200190a450505050565b6040805167ffffffffffffffff19831680825291517fcdc4c1b1aed5524ffb4198d7a5839a34712baef5fa06884fac7559f4a5854e0a9181900360200190a250565b8063ffffffff168260010b847f3ca7f3a77e5e6e15e781850bc82e32adfa378a2a609370db24b4d0fae10da2c960405160405180910390a45050505600a165627a7a72305820468b5843bf653145bd924b323c64ef035d3dd922c170644b44d61aa666ea6eee0029`, + `[{"constant":false,"inputs":[{"name":"str","type":"string"},{"name":"blob","type":"bytes"}],"name":"raiseDynamicEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"id","type":"bytes32"},{"name":"flag","type":"bool"},{"name":"value","type":"uint256"}],"name":"raiseSimpleEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"blob","type":"bytes24"}],"name":"raiseFixedBytesEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"number","type":"uint256"},{"name":"short","type":"int16"},{"name":"long","type":"uint32"}],"name":"raiseNodataEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Addr","type":"address"},{"indexed":true,"name":"Id","type":"bytes32"},{"indexed":true,"name":"Flag","type":"bool"},{"indexed":false,"name":"Value","type":"uint256"}],"name":"SimpleEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Number","type":"uint256"},{"indexed":true,"name":"Short","type":"int16"},{"indexed":true,"name":"Long","type":"uint32"}],"name":"NodataEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexedString","type":"string"},{"indexed":true,"name":"IndexedBytes","type":"bytes"},{"indexed":false,"name":"NonIndexedString","type":"string"},{"indexed":false,"name":"NonIndexedBytes","type":"bytes"}],"name":"DynamicEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexedBytes","type":"bytes24"},{"indexed":false,"name":"NonIndexedBytes","type":"bytes24"}],"name":"FixedBytesEvent","type":"event"}]`, ` "math/big" "time" @@ -812,6 +820,33 @@ var bindTests = []struct { if err = dit.Error(); err != nil { t.Fatalf("dynamic event iteration failed: %v", err) } + // Test raising and filtering for events with fixed bytes components + var fblob [24]byte + copy(fblob[:], []byte("Fixed Bytes")) + + if _, err := eventer.RaiseFixedBytesEvent(auth, fblob); err != nil { + t.Fatalf("failed to raise fixed bytes event: %v", err) + } + sim.Commit() + + fit, err := eventer.FilterFixedBytesEvent(nil, [][24]byte{fblob}) + if err != nil { + t.Fatalf("failed to filter for fixed bytes events: %v", err) + } + defer fit.Close() + + if !fit.Next() { + t.Fatalf("fixed bytes log not found: %v", fit.Error()) + } + if fit.Event.NonIndexedBytes != fblob || fit.Event.IndexedBytes != fblob { + t.Errorf("fixed bytes log content mismatch: have %v, want {'%x', '%x'}", fit.Event, fblob, fblob) + } + if fit.Next() { + t.Errorf("unexpected fixed bytes event found: %+v", fit.Event) + } + if err = fit.Error(); err != nil { + t.Fatalf("fixed bytes event iteration failed: %v", err) + } // Test subscribing to an event and raising it afterwards ch := make(chan *EventerSimpleEvent, 16) sub, err := eventer.WatchSimpleEvent(nil, ch, nil, nil, nil) diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics.go index cd84fb16..c7657b4a 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics.go @@ -17,6 +17,7 @@ package bind import ( + "encoding/binary" "errors" "fmt" "math/big" @@ -83,8 +84,10 @@ func makeTopics(query ...[]interface{}) ([][]common.Hash, error) { val := reflect.ValueOf(rule) switch { + + // static byte array case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8: - reflect.Copy(reflect.ValueOf(topic[common.HashLength-val.Len():]), val) + reflect.Copy(reflect.ValueOf(topic[:val.Len()]), val) default: return nil, fmt.Errorf("unsupported indexed type: %T", rule) @@ -175,8 +178,10 @@ func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) er default: // Ran out of custom types, try the crazies switch { + + // static byte array case arg.Type.T == abi.FixedBytesTy: - reflect.Copy(field, reflect.ValueOf(topics[0][common.HashLength-arg.Type.Size:])) + reflect.Copy(field, reflect.ValueOf(topics[0][:arg.Type.Size])) default: return fmt.Errorf("unsupported indexed type: %v", arg.Type) @@ -188,7 +193,7 @@ func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) er return nil } -// parseTopics converts the indexed topic field-value pairs into map key-value pairs +// parseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics []common.Hash) error { // Sanity check that the fields and topics match up if len(fields) != len(topics) { @@ -202,11 +207,7 @@ func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics switch arg.Type.T { case abi.BoolTy: - if topics[0][common.HashLength-1] == 1 { - out[arg.Name] = true - } else { - out[arg.Name] = false - } + out[arg.Name] = topics[0][common.HashLength-1] == 1 case abi.IntTy, abi.UintTy: num := new(big.Int).SetBytes(topics[0][:]) out[arg.Name] = num @@ -216,9 +217,21 @@ func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics out[arg.Name] = addr case abi.HashTy: out[arg.Name] = topics[0] - case abi.BytesTy, abi.FixedBytesTy: + case abi.FixedBytesTy: out[arg.Name] = topics[0][:] - default: + case abi.StringTy, abi.BytesTy, abi.SliceTy, abi.ArrayTy: + // Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash + // whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash + out[arg.Name] = topics[0] + case abi.FunctionTy: + if garbage := binary.BigEndian.Uint64(topics[0][0:8]); garbage != 0 { + return fmt.Errorf("bind: got improperly encoded function type, got %v", topics[0].Bytes()) + } + var tmp [24]byte + copy(tmp[:], topics[0][8:32]) + out[arg.Name] = tmp + default: // Not handling tuples + return fmt.Errorf("unsupported indexed type: %v", arg.Type) } topics = topics[1:] diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics_test.go new file mode 100644 index 00000000..e6f745a1 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/topics_test.go @@ -0,0 +1,103 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package bind + +import ( + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +func TestMakeTopics(t *testing.T) { + type args struct { + query [][]interface{} + } + tests := []struct { + name string + args args + want [][]common.Hash + wantErr bool + }{ + { + "support fixed byte types, right padded to 32 bytes", + args{[][]interface{}{{[5]byte{1, 2, 3, 4, 5}}}}, + [][]common.Hash{{common.Hash{1, 2, 3, 4, 5}}}, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := makeTopics(tt.args.query...) + if (err != nil) != tt.wantErr { + t.Errorf("makeTopics() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("makeTopics() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestParseTopics(t *testing.T) { + type bytesStruct struct { + StaticBytes [5]byte + } + bytesType, _ := abi.NewType("bytes5", nil) + type args struct { + createObj func() interface{} + resultObj func() interface{} + fields abi.Arguments + topics []common.Hash + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "support fixed byte types, right padded to 32 bytes", + args: args{ + createObj: func() interface{} { return &bytesStruct{} }, + resultObj: func() interface{} { return &bytesStruct{StaticBytes: [5]byte{1, 2, 3, 4, 5}} }, + fields: abi.Arguments{abi.Argument{ + Name: "staticBytes", + Type: bytesType, + Indexed: true, + }}, + topics: []common.Hash{ + {1, 2, 3, 4, 5}, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + createObj := tt.args.createObj() + if err := parseTopics(createObj, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr { + t.Errorf("parseTopics() error = %v, wantErr %v", err, tt.wantErr) + } + resultObj := tt.args.resultObj() + if !reflect.DeepEqual(createObj, resultObj) { + t.Errorf("parseTopics() = %v, want %v", createObj, resultObj) + } + }) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/event.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/event.go index a3f6be97..9392c199 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/event.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/event.go @@ -36,12 +36,12 @@ type Event struct { func (e Event) String() string { inputs := make([]string, len(e.Inputs)) for i, input := range e.Inputs { - inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) + inputs[i] = fmt.Sprintf("%v %v", input.Type, input.Name) if input.Indexed { - inputs[i] = fmt.Sprintf("%v indexed %v", input.Name, input.Type) + inputs[i] = fmt.Sprintf("%v indexed %v", input.Type, input.Name) } } - return fmt.Sprintf("e %v(%v)", e.Name, strings.Join(inputs, ", ")) + return fmt.Sprintf("event %v(%v)", e.Name, strings.Join(inputs, ", ")) } // Id returns the canonical representation of the event's signature used by the diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/event_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/event_test.go index 3bfdd7c0..e735cceb 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/event_test.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/event_test.go @@ -87,12 +87,12 @@ func TestEventId(t *testing.T) { }{ { definition: `[ - { "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, - { "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] } + { "type" : "event", "name" : "Balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, + { "type" : "event", "name" : "Check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] } ]`, expectations: map[string]common.Hash{ - "balance": crypto.Keccak256Hash([]byte("balance(uint256)")), - "check": crypto.Keccak256Hash([]byte("check(address,uint256)")), + "Balance": crypto.Keccak256Hash([]byte("Balance(uint256)")), + "Check": crypto.Keccak256Hash([]byte("Check(address,uint256)")), }, }, } @@ -111,6 +111,39 @@ func TestEventId(t *testing.T) { } } +func TestEventString(t *testing.T) { + var table = []struct { + definition string + expectations map[string]string + }{ + { + definition: `[ + { "type" : "event", "name" : "Balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, + { "type" : "event", "name" : "Check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] }, + { "type" : "event", "name" : "Transfer", "inputs": [{ "name": "from", "type": "address", "indexed": true }, { "name": "to", "type": "address", "indexed": true }, { "name": "value", "type": "uint256" }] } + ]`, + expectations: map[string]string{ + "Balance": "event Balance(uint256 in)", + "Check": "event Check(address t, uint256 b)", + "Transfer": "event Transfer(address indexed from, address indexed to, uint256 value)", + }, + }, + } + + for _, test := range table { + abi, err := JSON(strings.NewReader(test.definition)) + if err != nil { + t.Fatal(err) + } + + for name, event := range abi.Events { + if event.String() != test.expectations[name] { + t.Errorf("expected string to be %s, got %s", test.expectations[name], event.String()) + } + } + } +} + // TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array. func TestEventMultiValueWithArrayUnpack(t *testing.T) { definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/method.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/method.go index 58310576..2d8d3d65 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/method.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/method.go @@ -56,14 +56,14 @@ func (method Method) Sig() string { func (method Method) String() string { inputs := make([]string, len(method.Inputs)) for i, input := range method.Inputs { - inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) + inputs[i] = fmt.Sprintf("%v %v", input.Type, input.Name) } outputs := make([]string, len(method.Outputs)) for i, output := range method.Outputs { + outputs[i] = output.Type.String() if len(output.Name) > 0 { - outputs[i] = fmt.Sprintf("%v ", output.Name) + outputs[i] += fmt.Sprintf(" %v", output.Name) } - outputs[i] += output.Type.String() } constant := "" if method.Const { diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/method_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/method_test.go new file mode 100644 index 00000000..a98f1cd3 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/method_test.go @@ -0,0 +1,61 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package abi + +import ( + "strings" + "testing" +) + +const methoddata = ` +[ + { "type" : "function", "name" : "balance", "constant" : true }, + { "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, + { "type" : "function", "name" : "transfer", "constant" : false, "inputs" : [ { "name" : "from", "type" : "address" }, { "name" : "to", "type" : "address" }, { "name" : "value", "type" : "uint256" } ], "outputs" : [ { "name" : "success", "type" : "bool" } ] } +]` + +func TestMethodString(t *testing.T) { + var table = []struct { + method string + expectation string + }{ + { + method: "balance", + expectation: "function balance() constant returns()", + }, + { + method: "send", + expectation: "function send(uint256 amount) returns()", + }, + { + method: "transfer", + expectation: "function transfer(address from, address to, uint256 value) returns(bool success)", + }, + } + + abi, err := JSON(strings.NewReader(methoddata)) + if err != nil { + t.Fatal(err) + } + + for _, test := range table { + got := abi.Methods[test.method].String() + if got != test.expectation { + t.Errorf("expected string to be %s, got %s", test.expectation, got) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/pack_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/pack_test.go index 58a5b7a5..10cd3a39 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/pack_test.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/pack_test.go @@ -29,314 +29,601 @@ import ( func TestPack(t *testing.T) { for i, test := range []struct { - typ string - - input interface{} - output []byte + typ string + components []ArgumentMarshaling + input interface{} + output []byte }{ { "uint8", + nil, uint8(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "uint8[]", + nil, []uint8{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint16", + nil, uint16(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "uint16[]", + nil, []uint16{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint32", + nil, uint32(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "uint32[]", + nil, []uint32{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint64", + nil, uint64(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "uint64[]", + nil, []uint64{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint256", + nil, big.NewInt(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "uint256[]", + nil, []*big.Int{big.NewInt(1), big.NewInt(2)}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int8", + nil, int8(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "int8[]", + nil, []int8{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int16", + nil, int16(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "int16[]", + nil, []int16{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int32", + nil, int32(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "int32[]", + nil, []int32{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int64", + nil, int64(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "int64[]", + nil, []int64{1, 2}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int256", + nil, big.NewInt(2), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"), }, { "int256[]", + nil, []*big.Int{big.NewInt(1), big.NewInt(2)}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "bytes1", + nil, [1]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes2", + nil, [2]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes3", + nil, [3]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes4", + nil, [4]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes5", + nil, [5]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes6", + nil, [6]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes7", + nil, [7]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes8", + nil, [8]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes9", + nil, [9]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes10", + nil, [10]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes11", + nil, [11]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes12", + nil, [12]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes13", + nil, [13]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes14", + nil, [14]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes15", + nil, [15]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes16", + nil, [16]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes17", + nil, [17]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes18", + nil, [18]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes19", + nil, [19]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes20", + nil, [20]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes21", + nil, [21]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes22", + nil, [22]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes23", + nil, [23]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes24", - [24]byte{1}, - common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), - }, - { - "bytes24", + nil, [24]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes25", + nil, [25]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes26", + nil, [26]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes27", + nil, [27]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes28", + nil, [28]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes29", + nil, [29]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes30", + nil, [30]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes31", + nil, [31]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "bytes32", + nil, [32]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "uint32[2][3][4]", + nil, [4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"), }, { "address[]", + nil, []common.Address{{1}, {2}}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), }, { "bytes32[]", + nil, []common.Hash{{1}, {2}}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"), }, { "function", + nil, [24]byte{1}, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), }, { "string", + nil, "foobar", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"), }, + { + "string[]", + nil, + []string{"hello", "foobar"}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0 + "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i = 1 + "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 + "68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0] + "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 + "666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1] + }, + { + "string[2]", + nil, + []string{"hello", "foobar"}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to i = 0 + "0000000000000000000000000000000000000000000000000000000000000080" + // offset to i = 1 + "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 + "68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0] + "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 + "666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1] + }, + { + "bytes32[][]", + nil, + [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0 + "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 + "0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1] + "0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3 + "0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2] + }, + + { + "bytes32[][2]", + nil, + [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0 + "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 + "0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1] + "0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3 + "0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2] + }, + + { + "bytes32[3][2]", + nil, + [][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}}, + common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1] + "0300000000000000000000000000000000000000000000000000000000000000" + // array[0][2] + "0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2] + }, + { + // static tuple + "tuple", + []ArgumentMarshaling{ + {Name: "a", Type: "int64"}, + {Name: "b", Type: "int256"}, + {Name: "c", Type: "int256"}, + {Name: "d", Type: "bool"}, + {Name: "e", Type: "bytes32[3][2]"}, + }, + struct { + A int64 + B *big.Int + C *big.Int + D bool + E [][]common.Hash + }{1, big.NewInt(1), big.NewInt(-1), true, [][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}}}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001" + // struct[a] + "0000000000000000000000000000000000000000000000000000000000000001" + // struct[b] + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // struct[c] + "0000000000000000000000000000000000000000000000000000000000000001" + // struct[d] + "0100000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][1] + "0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[0][2] + "0300000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // struct[e] array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // struct[e] array[1][2] + }, + { + // dynamic tuple + "tuple", + []ArgumentMarshaling{ + {Name: "a", Type: "string"}, + {Name: "b", Type: "int64"}, + {Name: "c", Type: "bytes"}, + {Name: "d", Type: "string[]"}, + {Name: "e", Type: "int256[]"}, + {Name: "f", Type: "address[]"}, + }, + struct { + FieldA string `abi:"a"` // Test whether abi tag works + FieldB int64 `abi:"b"` + C []byte + D []string + E []*big.Int + F []common.Address + }{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}}, + common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset + "0000000000000000000000000000000000000000000000000000000000000001" + // struct[b] + "0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset + "0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset + "0000000000000000000000000000000000000000000000000000000000000220" + // struct[e] offset + "0000000000000000000000000000000000000000000000000000000000000280" + // struct[f] offset + "0000000000000000000000000000000000000000000000000000000000000006" + // struct[a] length + "666f6f6261720000000000000000000000000000000000000000000000000000" + // struct[a] "foobar" + "0000000000000000000000000000000000000000000000000000000000000001" + // struct[c] length + "0100000000000000000000000000000000000000000000000000000000000000" + // []byte{1} + "0000000000000000000000000000000000000000000000000000000000000002" + // struct[d] length + "0000000000000000000000000000000000000000000000000000000000000040" + // foo offset + "0000000000000000000000000000000000000000000000000000000000000080" + // bar offset + "0000000000000000000000000000000000000000000000000000000000000003" + // foo length + "666f6f0000000000000000000000000000000000000000000000000000000000" + // foo + "0000000000000000000000000000000000000000000000000000000000000003" + // bar offset + "6261720000000000000000000000000000000000000000000000000000000000" + // bar + "0000000000000000000000000000000000000000000000000000000000000002" + // struct[e] length + "0000000000000000000000000000000000000000000000000000000000000001" + // 1 + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // -1 + "0000000000000000000000000000000000000000000000000000000000000002" + // struct[f] length + "0000000000000000000000000100000000000000000000000000000000000000" + // common.Address{1} + "0000000000000000000000000200000000000000000000000000000000000000"), // common.Address{2} + }, + { + // nested tuple + "tuple", + []ArgumentMarshaling{ + {Name: "a", Type: "tuple", Components: []ArgumentMarshaling{{Name: "a", Type: "uint256"}, {Name: "b", Type: "uint256[]"}}}, + {Name: "b", Type: "int256[]"}, + }, + struct { + A struct { + FieldA *big.Int `abi:"a"` + B []*big.Int + } + B []*big.Int + }{ + A: struct { + FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple + B []*big.Int + }{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(0)}}, + B: []*big.Int{big.NewInt(1), big.NewInt(0)}}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // a offset + "00000000000000000000000000000000000000000000000000000000000000e0" + // b offset + "0000000000000000000000000000000000000000000000000000000000000001" + // a.a value + "0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset + "0000000000000000000000000000000000000000000000000000000000000002" + // a.b length + "0000000000000000000000000000000000000000000000000000000000000001" + // a.b[0] value + "0000000000000000000000000000000000000000000000000000000000000000" + // a.b[1] value + "0000000000000000000000000000000000000000000000000000000000000002" + // b length + "0000000000000000000000000000000000000000000000000000000000000001" + // b[0] value + "0000000000000000000000000000000000000000000000000000000000000000"), // b[1] value + }, + { + // tuple slice + "tuple[]", + []ArgumentMarshaling{ + {Name: "a", Type: "int256"}, + {Name: "b", Type: "int256[]"}, + }, + []struct { + A *big.Int + B []*big.Int + }{ + {big.NewInt(-1), []*big.Int{big.NewInt(1), big.NewInt(0)}}, + {big.NewInt(1), []*big.Int{big.NewInt(2), big.NewInt(-1)}}, + }, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // tuple length + "0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset + "00000000000000000000000000000000000000000000000000000000000000e0" + // tuple[1] offset + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A + "0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0].B offset + "0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].B length + "0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].B[0] value + "0000000000000000000000000000000000000000000000000000000000000000" + // tuple[0].B[1] value + "0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A + "0000000000000000000000000000000000000000000000000000000000000040" + // tuple[1].B offset + "0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B length + "0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].B[0] value + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].B[1] value + }, + { + // static tuple array + "tuple[2]", + []ArgumentMarshaling{ + {Name: "a", Type: "int256"}, + {Name: "b", Type: "int256"}, + }, + [2]struct { + A *big.Int + B *big.Int + }{ + {big.NewInt(-1), big.NewInt(1)}, + {big.NewInt(1), big.NewInt(-1)}, + }, + common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].a + "0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].b + "0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].a + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].b + }, + { + // dynamic tuple array + "tuple[2]", + []ArgumentMarshaling{ + {Name: "a", Type: "int256[]"}, + }, + [2]struct { + A []*big.Int + }{ + {[]*big.Int{big.NewInt(-1), big.NewInt(1)}}, + {[]*big.Int{big.NewInt(1), big.NewInt(-1)}}, + }, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // tuple[0] offset + "00000000000000000000000000000000000000000000000000000000000000c0" + // tuple[1] offset + "0000000000000000000000000000000000000000000000000000000000000020" + // tuple[0].A offset + "0000000000000000000000000000000000000000000000000000000000000002" + // tuple[0].A length + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + // tuple[0].A[0] + "0000000000000000000000000000000000000000000000000000000000000001" + // tuple[0].A[1] + "0000000000000000000000000000000000000000000000000000000000000020" + // tuple[1].A offset + "0000000000000000000000000000000000000000000000000000000000000002" + // tuple[1].A length + "0000000000000000000000000000000000000000000000000000000000000001" + // tuple[1].A[0] + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), // tuple[1].A[1] + }, } { - typ, err := NewType(test.typ) + typ, err := NewType(test.typ, test.components) if err != nil { t.Fatalf("%v failed. Unexpected parse error: %v", i, err) } - output, err := typ.pack(reflect.ValueOf(test.input)) if err != nil { t.Fatalf("%v failed. Unexpected pack error: %v", i, err) } if !bytes.Equal(output, test.output) { - t.Errorf("%d failed. Expected bytes: '%x' Got: '%x'", i, test.output, output) + t.Errorf("input %d for typ: %v failed. Expected bytes: '%x' Got: '%x'", i, typ.String(), test.output, output) } } } @@ -406,6 +693,59 @@ func TestMethodPack(t *testing.T) { if !bytes.Equal(packed, sig) { t.Errorf("expected %x got %x", sig, packed) } + + a := [2][2]*big.Int{{big.NewInt(1), big.NewInt(1)}, {big.NewInt(2), big.NewInt(0)}} + sig = abi.Methods["nestedArray"].Id() + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0xa0}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes(addrC[:], 32)...) + sig = append(sig, common.LeftPadBytes(addrD[:], 32)...) + packed, err = abi.Pack("nestedArray", a, []common.Address{addrC, addrD}) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(packed, sig) { + t.Errorf("expected %x got %x", sig, packed) + } + + sig = abi.Methods["nestedArray2"].Id() + sig = append(sig, common.LeftPadBytes([]byte{0x20}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0x40}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0x80}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + packed, err = abi.Pack("nestedArray2", [2][]uint8{{1}, {1}}) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(packed, sig) { + t.Errorf("expected %x got %x", sig, packed) + } + + sig = abi.Methods["nestedSlice"].Id() + sig = append(sig, common.LeftPadBytes([]byte{0x20}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0x02}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0x40}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{0xa0}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + packed, err = abi.Pack("nestedSlice", [][]uint8{{1, 2}, {1, 2}}) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(packed, sig) { + t.Errorf("expected %x got %x", sig, packed) + } } func TestPackNumber(t *testing.T) { diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect.go index 0193517a..ccc6a659 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect.go @@ -71,22 +71,36 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value { // // set is a bit more lenient when it comes to assignment and doesn't force an as // strict ruleset as bare `reflect` does. -func set(dst, src reflect.Value, output Argument) error { - dstType := dst.Type() - srcType := src.Type() +func set(dst, src reflect.Value) error { + dstType, srcType := dst.Type(), src.Type() switch { - case dstType.AssignableTo(srcType): + case dstType.Kind() == reflect.Interface && dst.Elem().IsValid(): + return set(dst.Elem(), src) + case dstType.Kind() == reflect.Ptr && dstType.Elem() != derefbigT: + return set(dst.Elem(), src) + case srcType.AssignableTo(dstType) && dst.CanSet(): dst.Set(src) - case dstType.Kind() == reflect.Interface: - dst.Set(src) - case dstType.Kind() == reflect.Ptr: - return set(dst.Elem(), src, output) + case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice: + return setSlice(dst, src) default: return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) } return nil } +// setSlice attempts to assign src to dst when slices are not assignable by default +// e.g. src: [][]byte -> dst: [][15]byte +func setSlice(dst, src reflect.Value) error { + slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len()) + for i := 0; i < src.Len(); i++ { + v := src.Index(i) + reflect.Copy(slice.Index(i), v) + } + + dst.Set(slice) + return nil +} + // requireAssignable assures that `dest` is a pointer and it's not an interface. func requireAssignable(dst, src reflect.Value) error { if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface { @@ -112,14 +126,14 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, return nil } -// mapAbiToStringField maps abi to struct fields. +// mapArgNamesToStructFields maps a slice of argument names to struct fields. // first round: for each Exportable field that contains a `abi:""` tag -// and this field name exists in the arguments, pair them together. -// second round: for each argument field that has not been already linked, +// and this field name exists in the given argument name list, pair them together. +// second round: for each argument name that has not been already linked, // find what variable is expected to be mapped into, if it exists and has not been // used, pair them. -func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]string, error) { - +// Note this function assumes the given value is a struct value. +func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) { typ := value.Type() abi2struct := make(map[string]string) @@ -133,45 +147,39 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin if structFieldName[:1] != strings.ToUpper(structFieldName[:1]) { continue } - // skip fields that have no abi:"" tag. var ok bool var tagName string if tagName, ok = typ.Field(i).Tag.Lookup("abi"); !ok { continue } - // check if tag is empty. if tagName == "" { return nil, fmt.Errorf("struct: abi tag in '%s' is empty", structFieldName) } - // check which argument field matches with the abi tag. found := false - for _, abiField := range args.NonIndexed() { - if abiField.Name == tagName { - if abi2struct[abiField.Name] != "" { + for _, arg := range argNames { + if arg == tagName { + if abi2struct[arg] != "" { return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName) } // pair them - abi2struct[abiField.Name] = structFieldName - struct2abi[structFieldName] = abiField.Name + abi2struct[arg] = structFieldName + struct2abi[structFieldName] = arg found = true } } - // check if this tag has been mapped. if !found { return nil, fmt.Errorf("struct: abi tag '%s' defined but not found in abi", tagName) } - } // second round ~~~ - for _, arg := range args { + for _, argName := range argNames { - abiFieldName := arg.Name - structFieldName := capitalise(abiFieldName) + structFieldName := ToCamelCase(argName) if structFieldName == "" { return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") @@ -181,11 +189,11 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin // struct field with the same field name. If so, raise an error: // abi: [ { "name": "value" } ] // struct { Value *big.Int , Value1 *big.Int `abi:"value"`} - if abi2struct[abiFieldName] != "" { - if abi2struct[abiFieldName] != structFieldName && + if abi2struct[argName] != "" { + if abi2struct[argName] != structFieldName && struct2abi[structFieldName] == "" && value.FieldByName(structFieldName).IsValid() { - return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", abiFieldName) + return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", argName) } continue } @@ -197,16 +205,14 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin if value.FieldByName(structFieldName).IsValid() { // pair them - abi2struct[abiFieldName] = structFieldName - struct2abi[structFieldName] = abiFieldName + abi2struct[argName] = structFieldName + struct2abi[structFieldName] = argName } else { // not paired, but annotate as used, to detect cases like // abi : [ { "name": "value" }, { "name": "_value" } ] // struct { Value *big.Int } - struct2abi[structFieldName] = abiFieldName + struct2abi[structFieldName] = argName } - } - return abi2struct, nil } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect_test.go new file mode 100644 index 00000000..c425e6e5 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect_test.go @@ -0,0 +1,191 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package abi + +import ( + "reflect" + "testing" +) + +type reflectTest struct { + name string + args []string + struc interface{} + want map[string]string + err string +} + +var reflectTests = []reflectTest{ + { + name: "OneToOneCorrespondance", + args: []string{"fieldA"}, + struc: struct { + FieldA int `abi:"fieldA"` + }{}, + want: map[string]string{ + "fieldA": "FieldA", + }, + }, + { + name: "MissingFieldsInStruct", + args: []string{"fieldA", "fieldB"}, + struc: struct { + FieldA int `abi:"fieldA"` + }{}, + want: map[string]string{ + "fieldA": "FieldA", + }, + }, + { + name: "MoreFieldsInStructThanArgs", + args: []string{"fieldA"}, + struc: struct { + FieldA int `abi:"fieldA"` + FieldB int + }{}, + want: map[string]string{ + "fieldA": "FieldA", + }, + }, + { + name: "MissingFieldInArgs", + args: []string{"fieldA"}, + struc: struct { + FieldA int `abi:"fieldA"` + FieldB int `abi:"fieldB"` + }{}, + err: "struct: abi tag 'fieldB' defined but not found in abi", + }, + { + name: "NoAbiDescriptor", + args: []string{"fieldA"}, + struc: struct { + FieldA int + }{}, + want: map[string]string{ + "fieldA": "FieldA", + }, + }, + { + name: "NoArgs", + args: []string{}, + struc: struct { + FieldA int `abi:"fieldA"` + }{}, + err: "struct: abi tag 'fieldA' defined but not found in abi", + }, + { + name: "DifferentName", + args: []string{"fieldB"}, + struc: struct { + FieldA int `abi:"fieldB"` + }{}, + want: map[string]string{ + "fieldB": "FieldA", + }, + }, + { + name: "DifferentName", + args: []string{"fieldB"}, + struc: struct { + FieldA int `abi:"fieldB"` + }{}, + want: map[string]string{ + "fieldB": "FieldA", + }, + }, + { + name: "MultipleFields", + args: []string{"fieldA", "fieldB"}, + struc: struct { + FieldA int `abi:"fieldA"` + FieldB int `abi:"fieldB"` + }{}, + want: map[string]string{ + "fieldA": "FieldA", + "fieldB": "FieldB", + }, + }, + { + name: "MultipleFieldsABIMissing", + args: []string{"fieldA", "fieldB"}, + struc: struct { + FieldA int `abi:"fieldA"` + FieldB int + }{}, + want: map[string]string{ + "fieldA": "FieldA", + "fieldB": "FieldB", + }, + }, + { + name: "NameConflict", + args: []string{"fieldB"}, + struc: struct { + FieldA int `abi:"fieldB"` + FieldB int + }{}, + err: "abi: multiple variables maps to the same abi field 'fieldB'", + }, + { + name: "Underscored", + args: []string{"_"}, + struc: struct { + FieldA int + }{}, + err: "abi: purely underscored output cannot unpack to struct", + }, + { + name: "DoubleMapping", + args: []string{"fieldB", "fieldC", "fieldA"}, + struc: struct { + FieldA int `abi:"fieldC"` + FieldB int + }{}, + err: "abi: multiple outputs mapping to the same struct field 'FieldA'", + }, + { + name: "AlreadyMapped", + args: []string{"fieldB", "fieldB"}, + struc: struct { + FieldB int `abi:"fieldB"` + }{}, + err: "struct: abi tag in 'FieldB' already mapped", + }, +} + +func TestReflectNameToStruct(t *testing.T) { + for _, test := range reflectTests { + t.Run(test.name, func(t *testing.T) { + m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc)) + if len(test.err) > 0 { + if err == nil || err.Error() != test.err { + t.Fatalf("Invalid error: expected %v, got %v", test.err, err) + } + } else { + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + for fname := range test.want { + if m[fname] != test.want[fname] { + t.Fatalf("Incorrect value for field %s: expected %v, got %v", fname, test.want[fname], m[fname]) + } + } + } + }) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/type.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/type.go index dce89d2b..1a371823 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/type.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/type.go @@ -17,6 +17,7 @@ package abi import ( + "errors" "fmt" "reflect" "regexp" @@ -32,6 +33,7 @@ const ( StringTy SliceTy ArrayTy + TupleTy AddressTy FixedBytesTy BytesTy @@ -43,13 +45,16 @@ const ( // Type is the reflection of the supported argument type type Type struct { Elem *Type - Kind reflect.Kind Type reflect.Type Size int T byte // Our own type checking stringKind string // holds the unparsed string for deriving signatures + + // Tuple relative fields + TupleElems []*Type // Type information of all tuple fields + TupleRawNames []string // Raw field name of all tuple fields } var ( @@ -58,7 +63,7 @@ var ( ) // NewType creates a new reflection type of abi type given in t. -func NewType(t string) (typ Type, err error) { +func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) { // check that array brackets are equal if they exist if strings.Count(t, "[") != strings.Count(t, "]") { return Type{}, fmt.Errorf("invalid arg type in abi") @@ -71,7 +76,7 @@ func NewType(t string) (typ Type, err error) { if strings.Count(t, "[") != 0 { i := strings.LastIndex(t, "[") // recursively embed the type - embeddedType, err := NewType(t[:i]) + embeddedType, err := NewType(t[:i], components) if err != nil { return Type{}, err } @@ -87,6 +92,9 @@ func NewType(t string) (typ Type, err error) { typ.Kind = reflect.Slice typ.Elem = &embeddedType typ.Type = reflect.SliceOf(embeddedType.Type) + if embeddedType.T == TupleTy { + typ.stringKind = embeddedType.stringKind + sliced + } } else if len(intz) == 1 { // is a array typ.T = ArrayTy @@ -97,6 +105,9 @@ func NewType(t string) (typ Type, err error) { return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) } typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) + if embeddedType.T == TupleTy { + typ.stringKind = embeddedType.stringKind + sliced + } } else { return Type{}, fmt.Errorf("invalid formatting of array type") } @@ -158,6 +169,41 @@ func NewType(t string) (typ Type, err error) { typ.Size = varSize typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) } + case "tuple": + var ( + fields []reflect.StructField + elems []*Type + names []string + expression string // canonical parameter expression + ) + expression += "(" + for idx, c := range components { + cType, err := NewType(c.Type, c.Components) + if err != nil { + return Type{}, err + } + if ToCamelCase(c.Name) == "" { + return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") + } + fields = append(fields, reflect.StructField{ + Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field. + Type: cType.Type, + Tag: reflect.StructTag("json:\"" + c.Name + "\""), + }) + elems = append(elems, &cType) + names = append(names, c.Name) + expression += cType.stringKind + if idx != len(components)-1 { + expression += "," + } + } + expression += ")" + typ.Kind = reflect.Struct + typ.Type = reflect.StructOf(fields) + typ.TupleElems = elems + typ.TupleRawNames = names + typ.T = TupleTy + typ.stringKind = expression case "function": typ.Kind = reflect.Array typ.T = FunctionTy @@ -178,28 +224,82 @@ func (t Type) String() (out string) { func (t Type) pack(v reflect.Value) ([]byte, error) { // dereference pointer first if it's a pointer v = indirect(v) - if err := typeCheck(t, v); err != nil { return nil, err } - if t.T == SliceTy || t.T == ArrayTy { - var packed []byte + switch t.T { + case SliceTy, ArrayTy: + var ret []byte + if t.requiresLengthPrefix() { + // append length + ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) + } + + // calculate offset if any + offset := 0 + offsetReq := isDynamicType(*t.Elem) + if offsetReq { + offset = getTypeSize(*t.Elem) * v.Len() + } + var tail []byte for i := 0; i < v.Len(); i++ { val, err := t.Elem.pack(v.Index(i)) if err != nil { return nil, err } - packed = append(packed, val...) + if !offsetReq { + ret = append(ret, val...) + continue + } + ret = append(ret, packNum(reflect.ValueOf(offset))...) + offset += len(val) + tail = append(tail, val...) } - if t.T == SliceTy { - return packBytesSlice(packed, v.Len()), nil - } else if t.T == ArrayTy { - return packed, nil + return append(ret, tail...), nil + case TupleTy: + // (T1,...,Tk) for k >= 0 and any types T1, …, Tk + // enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k)) + // where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static + // type as + // head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string) + // and as + // head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1)))) + // tail(X(i)) = enc(X(i)) + // otherwise, i.e. if Ti is a dynamic type. + fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v) + if err != nil { + return nil, err } + // Calculate prefix occupied size. + offset := 0 + for _, elem := range t.TupleElems { + offset += getTypeSize(*elem) + } + var ret, tail []byte + for i, elem := range t.TupleElems { + field := v.FieldByName(fieldmap[t.TupleRawNames[i]]) + if !field.IsValid() { + return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i]) + } + val, err := elem.pack(field) + if err != nil { + return nil, err + } + if isDynamicType(*elem) { + ret = append(ret, packNum(reflect.ValueOf(offset))...) + tail = append(tail, val...) + offset += len(val) + } else { + ret = append(ret, val...) + } + } + return append(ret, tail...), nil + + default: + return packElement(t, v), nil } - return packElement(t, v), nil } // requireLengthPrefix returns whether the type requires any sort of length @@ -207,3 +307,47 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { func (t Type) requiresLengthPrefix() bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy } + +// isDynamicType returns true if the type is dynamic. +// The following types are called “dynamic”: +// * bytes +// * string +// * T[] for any T +// * T[k] for any dynamic T and any k >= 0 +// * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k +func isDynamicType(t Type) bool { + if t.T == TupleTy { + for _, elem := range t.TupleElems { + if isDynamicType(*elem) { + return true + } + } + return false + } + return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) +} + +// getTypeSize returns the size that this type needs to occupy. +// We distinguish static and dynamic types. Static types are encoded in-place +// and dynamic types are encoded at a separately allocated location after the +// current block. +// So for a static variable, the size returned represents the size that the +// variable actually occupies. +// For a dynamic variable, the returned size is fixed 32 bytes, which is used +// to store the location reference for actual value storage. +func getTypeSize(t Type) int { + if t.T == ArrayTy && !isDynamicType(*t.Elem) { + // Recursively calculate type size if it is a nested array + if t.Elem.T == ArrayTy { + return t.Size * getTypeSize(*t.Elem) + } + return t.Size * 32 + } else if t.T == TupleTy && !isDynamicType(t) { + total := 0 + for _, elem := range t.TupleElems { + total += getTypeSize(*elem) + } + return total + } + return 32 +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/type_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/type_test.go index f6b36f18..5023456a 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/type_test.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/type_test.go @@ -32,72 +32,81 @@ type typeWithoutStringer Type // Tests that all allowed types get recognized by the type parser. func TestTypeRegexp(t *testing.T) { tests := []struct { - blob string - kind Type + blob string + components []ArgumentMarshaling + kind Type }{ - {"bool", Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}}, - {"bool[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool(nil)), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}}, - {"bool[2]", Type{Size: 2, Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}}, - {"bool[2][]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][]"}}, - {"bool[][]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][]"}}, - {"bool[][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][2]"}}, - {"bool[2][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][2]"}}, - {"bool[2][][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][][2]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][]"}, stringKind: "bool[2][][2]"}}, - {"bool[2][2][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][2]"}, stringKind: "bool[2][2][2]"}}, - {"bool[][][]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][]"}, stringKind: "bool[][][]"}}, - {"bool[][2][]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][2][]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][2]"}, stringKind: "bool[][2][]"}}, - {"int8", Type{Kind: reflect.Int8, Type: int8T, Size: 8, T: IntTy, stringKind: "int8"}}, - {"int16", Type{Kind: reflect.Int16, Type: int16T, Size: 16, T: IntTy, stringKind: "int16"}}, - {"int32", Type{Kind: reflect.Int32, Type: int32T, Size: 32, T: IntTy, stringKind: "int32"}}, - {"int64", Type{Kind: reflect.Int64, Type: int64T, Size: 64, T: IntTy, stringKind: "int64"}}, - {"int256", Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: IntTy, stringKind: "int256"}}, - {"int8[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8T, Size: 8, T: IntTy, stringKind: "int8"}, stringKind: "int8[]"}}, - {"int8[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8T, Size: 8, T: IntTy, stringKind: "int8"}, stringKind: "int8[2]"}}, - {"int16[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int16{}), Elem: &Type{Kind: reflect.Int16, Type: int16T, Size: 16, T: IntTy, stringKind: "int16"}, stringKind: "int16[]"}}, - {"int16[2]", Type{Size: 2, Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]int16{}), Elem: &Type{Kind: reflect.Int16, Type: int16T, Size: 16, T: IntTy, stringKind: "int16"}, stringKind: "int16[2]"}}, - {"int32[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int32{}), Elem: &Type{Kind: reflect.Int32, Type: int32T, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}}, - {"int32[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int32{}), Elem: &Type{Kind: reflect.Int32, Type: int32T, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}}, - {"int64[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int64{}), Elem: &Type{Kind: reflect.Int64, Type: int64T, Size: 64, T: IntTy, stringKind: "int64"}, stringKind: "int64[]"}}, - {"int64[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int64{}), Elem: &Type{Kind: reflect.Int64, Type: int64T, Size: 64, T: IntTy, stringKind: "int64"}, stringKind: "int64[2]"}}, - {"int256[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}}, - {"int256[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}}, - {"uint8", Type{Kind: reflect.Uint8, Type: uint8T, Size: 8, T: UintTy, stringKind: "uint8"}}, - {"uint16", Type{Kind: reflect.Uint16, Type: uint16T, Size: 16, T: UintTy, stringKind: "uint16"}}, - {"uint32", Type{Kind: reflect.Uint32, Type: uint32T, Size: 32, T: UintTy, stringKind: "uint32"}}, - {"uint64", Type{Kind: reflect.Uint64, Type: uint64T, Size: 64, T: UintTy, stringKind: "uint64"}}, - {"uint256", Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: UintTy, stringKind: "uint256"}}, - {"uint8[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8T, Size: 8, T: UintTy, stringKind: "uint8"}, stringKind: "uint8[]"}}, - {"uint8[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8T, Size: 8, T: UintTy, stringKind: "uint8"}, stringKind: "uint8[2]"}}, - {"uint16[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint16{}), Elem: &Type{Kind: reflect.Uint16, Type: uint16T, Size: 16, T: UintTy, stringKind: "uint16"}, stringKind: "uint16[]"}}, - {"uint16[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint16{}), Elem: &Type{Kind: reflect.Uint16, Type: uint16T, Size: 16, T: UintTy, stringKind: "uint16"}, stringKind: "uint16[2]"}}, - {"uint32[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint32{}), Elem: &Type{Kind: reflect.Uint32, Type: uint32T, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}}, - {"uint32[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint32{}), Elem: &Type{Kind: reflect.Uint32, Type: uint32T, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}}, - {"uint64[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint64{}), Elem: &Type{Kind: reflect.Uint64, Type: uint64T, Size: 64, T: UintTy, stringKind: "uint64"}, stringKind: "uint64[]"}}, - {"uint64[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint64{}), Elem: &Type{Kind: reflect.Uint64, Type: uint64T, Size: 64, T: UintTy, stringKind: "uint64"}, stringKind: "uint64[2]"}}, - {"uint256[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}}, - {"uint256[2]", Type{Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]*big.Int{}), Size: 2, Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}}, - {"bytes32", Type{Kind: reflect.Array, T: FixedBytesTy, Size: 32, Type: reflect.TypeOf([32]byte{}), stringKind: "bytes32"}}, - {"bytes[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][]byte{}), Elem: &Type{Kind: reflect.Slice, Type: reflect.TypeOf([]byte{}), T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[]"}}, - {"bytes[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]byte{}), Elem: &Type{T: BytesTy, Type: reflect.TypeOf([]byte{}), Kind: reflect.Slice, stringKind: "bytes"}, stringKind: "bytes[2]"}}, - {"bytes32[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][32]byte{}), Elem: &Type{Kind: reflect.Array, Type: reflect.TypeOf([32]byte{}), T: FixedBytesTy, Size: 32, stringKind: "bytes32"}, stringKind: "bytes32[]"}}, - {"bytes32[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][32]byte{}), Elem: &Type{Kind: reflect.Array, T: FixedBytesTy, Size: 32, Type: reflect.TypeOf([32]byte{}), stringKind: "bytes32"}, stringKind: "bytes32[2]"}}, - {"string", Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}}, - {"string[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]string{}), Elem: &Type{Kind: reflect.String, Type: reflect.TypeOf(""), T: StringTy, stringKind: "string"}, stringKind: "string[]"}}, - {"string[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]string{}), Elem: &Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}, stringKind: "string[2]"}}, - {"address", Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}}, - {"address[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}}, - {"address[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}}, + {"bool", nil, Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}}, + {"bool[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool(nil)), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}}, + {"bool[2]", nil, Type{Size: 2, Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}}, + {"bool[2][]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][]"}}, + {"bool[][]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][]"}}, + {"bool[][2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][2]"}}, + {"bool[2][2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][2]"}}, + {"bool[2][][2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][][2]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][]"}, stringKind: "bool[2][][2]"}}, + {"bool[2][2][2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][2]"}, stringKind: "bool[2][2][2]"}}, + {"bool[][][]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][]"}, stringKind: "bool[][][]"}}, + {"bool[][2][]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][2][]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][2]"}, stringKind: "bool[][2][]"}}, + {"int8", nil, Type{Kind: reflect.Int8, Type: int8T, Size: 8, T: IntTy, stringKind: "int8"}}, + {"int16", nil, Type{Kind: reflect.Int16, Type: int16T, Size: 16, T: IntTy, stringKind: "int16"}}, + {"int32", nil, Type{Kind: reflect.Int32, Type: int32T, Size: 32, T: IntTy, stringKind: "int32"}}, + {"int64", nil, Type{Kind: reflect.Int64, Type: int64T, Size: 64, T: IntTy, stringKind: "int64"}}, + {"int256", nil, Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: IntTy, stringKind: "int256"}}, + {"int8[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8T, Size: 8, T: IntTy, stringKind: "int8"}, stringKind: "int8[]"}}, + {"int8[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8T, Size: 8, T: IntTy, stringKind: "int8"}, stringKind: "int8[2]"}}, + {"int16[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int16{}), Elem: &Type{Kind: reflect.Int16, Type: int16T, Size: 16, T: IntTy, stringKind: "int16"}, stringKind: "int16[]"}}, + {"int16[2]", nil, Type{Size: 2, Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]int16{}), Elem: &Type{Kind: reflect.Int16, Type: int16T, Size: 16, T: IntTy, stringKind: "int16"}, stringKind: "int16[2]"}}, + {"int32[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int32{}), Elem: &Type{Kind: reflect.Int32, Type: int32T, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}}, + {"int32[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int32{}), Elem: &Type{Kind: reflect.Int32, Type: int32T, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}}, + {"int64[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int64{}), Elem: &Type{Kind: reflect.Int64, Type: int64T, Size: 64, T: IntTy, stringKind: "int64"}, stringKind: "int64[]"}}, + {"int64[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int64{}), Elem: &Type{Kind: reflect.Int64, Type: int64T, Size: 64, T: IntTy, stringKind: "int64"}, stringKind: "int64[2]"}}, + {"int256[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}}, + {"int256[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}}, + {"uint8", nil, Type{Kind: reflect.Uint8, Type: uint8T, Size: 8, T: UintTy, stringKind: "uint8"}}, + {"uint16", nil, Type{Kind: reflect.Uint16, Type: uint16T, Size: 16, T: UintTy, stringKind: "uint16"}}, + {"uint32", nil, Type{Kind: reflect.Uint32, Type: uint32T, Size: 32, T: UintTy, stringKind: "uint32"}}, + {"uint64", nil, Type{Kind: reflect.Uint64, Type: uint64T, Size: 64, T: UintTy, stringKind: "uint64"}}, + {"uint256", nil, Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: UintTy, stringKind: "uint256"}}, + {"uint8[]", nil, Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8T, Size: 8, T: UintTy, stringKind: "uint8"}, stringKind: "uint8[]"}}, + {"uint8[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8T, Size: 8, T: UintTy, stringKind: "uint8"}, stringKind: "uint8[2]"}}, + {"uint16[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint16{}), Elem: &Type{Kind: reflect.Uint16, Type: uint16T, Size: 16, T: UintTy, stringKind: "uint16"}, stringKind: "uint16[]"}}, + {"uint16[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint16{}), Elem: &Type{Kind: reflect.Uint16, Type: uint16T, Size: 16, T: UintTy, stringKind: "uint16"}, stringKind: "uint16[2]"}}, + {"uint32[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint32{}), Elem: &Type{Kind: reflect.Uint32, Type: uint32T, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}}, + {"uint32[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint32{}), Elem: &Type{Kind: reflect.Uint32, Type: uint32T, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}}, + {"uint64[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint64{}), Elem: &Type{Kind: reflect.Uint64, Type: uint64T, Size: 64, T: UintTy, stringKind: "uint64"}, stringKind: "uint64[]"}}, + {"uint64[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint64{}), Elem: &Type{Kind: reflect.Uint64, Type: uint64T, Size: 64, T: UintTy, stringKind: "uint64"}, stringKind: "uint64[2]"}}, + {"uint256[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}}, + {"uint256[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]*big.Int{}), Size: 2, Elem: &Type{Kind: reflect.Ptr, Type: bigT, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}}, + {"bytes32", nil, Type{Kind: reflect.Array, T: FixedBytesTy, Size: 32, Type: reflect.TypeOf([32]byte{}), stringKind: "bytes32"}}, + {"bytes[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][]byte{}), Elem: &Type{Kind: reflect.Slice, Type: reflect.TypeOf([]byte{}), T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[]"}}, + {"bytes[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]byte{}), Elem: &Type{T: BytesTy, Type: reflect.TypeOf([]byte{}), Kind: reflect.Slice, stringKind: "bytes"}, stringKind: "bytes[2]"}}, + {"bytes32[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][32]byte{}), Elem: &Type{Kind: reflect.Array, Type: reflect.TypeOf([32]byte{}), T: FixedBytesTy, Size: 32, stringKind: "bytes32"}, stringKind: "bytes32[]"}}, + {"bytes32[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][32]byte{}), Elem: &Type{Kind: reflect.Array, T: FixedBytesTy, Size: 32, Type: reflect.TypeOf([32]byte{}), stringKind: "bytes32"}, stringKind: "bytes32[2]"}}, + {"string", nil, Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}}, + {"string[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]string{}), Elem: &Type{Kind: reflect.String, Type: reflect.TypeOf(""), T: StringTy, stringKind: "string"}, stringKind: "string[]"}}, + {"string[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]string{}), Elem: &Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}, stringKind: "string[2]"}}, + {"address", nil, Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}}, + {"address[]", nil, Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}}, + {"address[2]", nil, Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}}, // TODO when fixed types are implemented properly - // {"fixed", Type{}}, - // {"fixed128x128", Type{}}, - // {"fixed[]", Type{}}, - // {"fixed[2]", Type{}}, - // {"fixed128x128[]", Type{}}, - // {"fixed128x128[2]", Type{}}, + // {"fixed", nil, Type{}}, + // {"fixed128x128", nil, Type{}}, + // {"fixed[]", nil, Type{}}, + // {"fixed[2]", nil, Type{}}, + // {"fixed128x128[]", nil, Type{}}, + // {"fixed128x128[2]", nil, Type{}}, + {"tuple", []ArgumentMarshaling{{Name: "a", Type: "int64"}}, Type{Kind: reflect.Struct, T: TupleTy, Type: reflect.TypeOf(struct { + A int64 `json:"a"` + }{}), stringKind: "(int64)", + TupleElems: []*Type{{Kind: reflect.Int64, T: IntTy, Type: reflect.TypeOf(int64(0)), Size: 64, stringKind: "int64"}}, TupleRawNames: []string{"a"}}}, + {"tuple with long name", []ArgumentMarshaling{{Name: "aTypicalParamName", Type: "int64"}}, Type{Kind: reflect.Struct, T: TupleTy, Type: reflect.TypeOf(struct { + ATypicalParamName int64 `json:"aTypicalParamName"` + }{}), stringKind: "(int64)", + TupleElems: []*Type{{Kind: reflect.Int64, T: IntTy, Type: reflect.TypeOf(int64(0)), Size: 64, stringKind: "int64"}}, TupleRawNames: []string{"aTypicalParamName"}}}, } for _, tt := range tests { - typ, err := NewType(tt.blob) + typ, err := NewType(tt.blob, tt.components) if err != nil { t.Errorf("type %q: failed to parse type string: %v", tt.blob, err) } @@ -109,154 +118,170 @@ func TestTypeRegexp(t *testing.T) { func TestTypeCheck(t *testing.T) { for i, test := range []struct { - typ string - input interface{} - err string + typ string + components []ArgumentMarshaling + input interface{} + err string }{ - {"uint", big.NewInt(1), "unsupported arg type: uint"}, - {"int", big.NewInt(1), "unsupported arg type: int"}, - {"uint256", big.NewInt(1), ""}, - {"uint256[][3][]", [][3][]*big.Int{{{}}}, ""}, - {"uint256[][][3]", [3][][]*big.Int{{{}}}, ""}, - {"uint256[3][][]", [][][3]*big.Int{{{}}}, ""}, - {"uint256[3][3][3]", [3][3][3]*big.Int{{{}}}, ""}, - {"uint8[][]", [][]uint8{}, ""}, - {"int256", big.NewInt(1), ""}, - {"uint8", uint8(1), ""}, - {"uint16", uint16(1), ""}, - {"uint32", uint32(1), ""}, - {"uint64", uint64(1), ""}, - {"int8", int8(1), ""}, - {"int16", int16(1), ""}, - {"int32", int32(1), ""}, - {"int64", int64(1), ""}, - {"uint24", big.NewInt(1), ""}, - {"uint40", big.NewInt(1), ""}, - {"uint48", big.NewInt(1), ""}, - {"uint56", big.NewInt(1), ""}, - {"uint72", big.NewInt(1), ""}, - {"uint80", big.NewInt(1), ""}, - {"uint88", big.NewInt(1), ""}, - {"uint96", big.NewInt(1), ""}, - {"uint104", big.NewInt(1), ""}, - {"uint112", big.NewInt(1), ""}, - {"uint120", big.NewInt(1), ""}, - {"uint128", big.NewInt(1), ""}, - {"uint136", big.NewInt(1), ""}, - {"uint144", big.NewInt(1), ""}, - {"uint152", big.NewInt(1), ""}, - {"uint160", big.NewInt(1), ""}, - {"uint168", big.NewInt(1), ""}, - {"uint176", big.NewInt(1), ""}, - {"uint184", big.NewInt(1), ""}, - {"uint192", big.NewInt(1), ""}, - {"uint200", big.NewInt(1), ""}, - {"uint208", big.NewInt(1), ""}, - {"uint216", big.NewInt(1), ""}, - {"uint224", big.NewInt(1), ""}, - {"uint232", big.NewInt(1), ""}, - {"uint240", big.NewInt(1), ""}, - {"uint248", big.NewInt(1), ""}, - {"int24", big.NewInt(1), ""}, - {"int40", big.NewInt(1), ""}, - {"int48", big.NewInt(1), ""}, - {"int56", big.NewInt(1), ""}, - {"int72", big.NewInt(1), ""}, - {"int80", big.NewInt(1), ""}, - {"int88", big.NewInt(1), ""}, - {"int96", big.NewInt(1), ""}, - {"int104", big.NewInt(1), ""}, - {"int112", big.NewInt(1), ""}, - {"int120", big.NewInt(1), ""}, - {"int128", big.NewInt(1), ""}, - {"int136", big.NewInt(1), ""}, - {"int144", big.NewInt(1), ""}, - {"int152", big.NewInt(1), ""}, - {"int160", big.NewInt(1), ""}, - {"int168", big.NewInt(1), ""}, - {"int176", big.NewInt(1), ""}, - {"int184", big.NewInt(1), ""}, - {"int192", big.NewInt(1), ""}, - {"int200", big.NewInt(1), ""}, - {"int208", big.NewInt(1), ""}, - {"int216", big.NewInt(1), ""}, - {"int224", big.NewInt(1), ""}, - {"int232", big.NewInt(1), ""}, - {"int240", big.NewInt(1), ""}, - {"int248", big.NewInt(1), ""}, - {"uint30", uint8(1), "abi: cannot use uint8 as type ptr as argument"}, - {"uint8", uint16(1), "abi: cannot use uint16 as type uint8 as argument"}, - {"uint8", uint32(1), "abi: cannot use uint32 as type uint8 as argument"}, - {"uint8", uint64(1), "abi: cannot use uint64 as type uint8 as argument"}, - {"uint8", int8(1), "abi: cannot use int8 as type uint8 as argument"}, - {"uint8", int16(1), "abi: cannot use int16 as type uint8 as argument"}, - {"uint8", int32(1), "abi: cannot use int32 as type uint8 as argument"}, - {"uint8", int64(1), "abi: cannot use int64 as type uint8 as argument"}, - {"uint16", uint16(1), ""}, - {"uint16", uint8(1), "abi: cannot use uint8 as type uint16 as argument"}, - {"uint16[]", []uint16{1, 2, 3}, ""}, - {"uint16[]", [3]uint16{1, 2, 3}, ""}, - {"uint16[]", []uint32{1, 2, 3}, "abi: cannot use []uint32 as type [0]uint16 as argument"}, - {"uint16[3]", [3]uint32{1, 2, 3}, "abi: cannot use [3]uint32 as type [3]uint16 as argument"}, - {"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, - {"uint16[3]", []uint16{1, 2, 3}, ""}, - {"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, - {"address[]", []common.Address{{1}}, ""}, - {"address[1]", []common.Address{{1}}, ""}, - {"address[1]", [1]common.Address{{1}}, ""}, - {"address[2]", [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"}, - {"bytes32", [32]byte{}, ""}, - {"bytes31", [31]byte{}, ""}, - {"bytes30", [30]byte{}, ""}, - {"bytes29", [29]byte{}, ""}, - {"bytes28", [28]byte{}, ""}, - {"bytes27", [27]byte{}, ""}, - {"bytes26", [26]byte{}, ""}, - {"bytes25", [25]byte{}, ""}, - {"bytes24", [24]byte{}, ""}, - {"bytes23", [23]byte{}, ""}, - {"bytes22", [22]byte{}, ""}, - {"bytes21", [21]byte{}, ""}, - {"bytes20", [20]byte{}, ""}, - {"bytes19", [19]byte{}, ""}, - {"bytes18", [18]byte{}, ""}, - {"bytes17", [17]byte{}, ""}, - {"bytes16", [16]byte{}, ""}, - {"bytes15", [15]byte{}, ""}, - {"bytes14", [14]byte{}, ""}, - {"bytes13", [13]byte{}, ""}, - {"bytes12", [12]byte{}, ""}, - {"bytes11", [11]byte{}, ""}, - {"bytes10", [10]byte{}, ""}, - {"bytes9", [9]byte{}, ""}, - {"bytes8", [8]byte{}, ""}, - {"bytes7", [7]byte{}, ""}, - {"bytes6", [6]byte{}, ""}, - {"bytes5", [5]byte{}, ""}, - {"bytes4", [4]byte{}, ""}, - {"bytes3", [3]byte{}, ""}, - {"bytes2", [2]byte{}, ""}, - {"bytes1", [1]byte{}, ""}, - {"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"}, - {"bytes32", common.Hash{1}, ""}, - {"bytes31", common.Hash{1}, "abi: cannot use common.Hash as type [31]uint8 as argument"}, - {"bytes31", [32]byte{}, "abi: cannot use [32]uint8 as type [31]uint8 as argument"}, - {"bytes", []byte{0, 1}, ""}, - {"bytes", [2]byte{0, 1}, "abi: cannot use array as type slice as argument"}, - {"bytes", common.Hash{1}, "abi: cannot use array as type slice as argument"}, - {"string", "hello world", ""}, - {"string", string(""), ""}, - {"string", []byte{}, "abi: cannot use slice as type string as argument"}, - {"bytes32[]", [][32]byte{{}}, ""}, - {"function", [24]byte{}, ""}, - {"bytes20", common.Address{}, ""}, - {"address", [20]byte{}, ""}, - {"address", common.Address{}, ""}, - {"bytes32[]]", "", "invalid arg type in abi"}, - {"invalidType", "", "unsupported arg type: invalidType"}, - {"invalidSlice[]", "", "unsupported arg type: invalidSlice"}, + {"uint", nil, big.NewInt(1), "unsupported arg type: uint"}, + {"int", nil, big.NewInt(1), "unsupported arg type: int"}, + {"uint256", nil, big.NewInt(1), ""}, + {"uint256[][3][]", nil, [][3][]*big.Int{{{}}}, ""}, + {"uint256[][][3]", nil, [3][][]*big.Int{{{}}}, ""}, + {"uint256[3][][]", nil, [][][3]*big.Int{{{}}}, ""}, + {"uint256[3][3][3]", nil, [3][3][3]*big.Int{{{}}}, ""}, + {"uint8[][]", nil, [][]uint8{}, ""}, + {"int256", nil, big.NewInt(1), ""}, + {"uint8", nil, uint8(1), ""}, + {"uint16", nil, uint16(1), ""}, + {"uint32", nil, uint32(1), ""}, + {"uint64", nil, uint64(1), ""}, + {"int8", nil, int8(1), ""}, + {"int16", nil, int16(1), ""}, + {"int32", nil, int32(1), ""}, + {"int64", nil, int64(1), ""}, + {"uint24", nil, big.NewInt(1), ""}, + {"uint40", nil, big.NewInt(1), ""}, + {"uint48", nil, big.NewInt(1), ""}, + {"uint56", nil, big.NewInt(1), ""}, + {"uint72", nil, big.NewInt(1), ""}, + {"uint80", nil, big.NewInt(1), ""}, + {"uint88", nil, big.NewInt(1), ""}, + {"uint96", nil, big.NewInt(1), ""}, + {"uint104", nil, big.NewInt(1), ""}, + {"uint112", nil, big.NewInt(1), ""}, + {"uint120", nil, big.NewInt(1), ""}, + {"uint128", nil, big.NewInt(1), ""}, + {"uint136", nil, big.NewInt(1), ""}, + {"uint144", nil, big.NewInt(1), ""}, + {"uint152", nil, big.NewInt(1), ""}, + {"uint160", nil, big.NewInt(1), ""}, + {"uint168", nil, big.NewInt(1), ""}, + {"uint176", nil, big.NewInt(1), ""}, + {"uint184", nil, big.NewInt(1), ""}, + {"uint192", nil, big.NewInt(1), ""}, + {"uint200", nil, big.NewInt(1), ""}, + {"uint208", nil, big.NewInt(1), ""}, + {"uint216", nil, big.NewInt(1), ""}, + {"uint224", nil, big.NewInt(1), ""}, + {"uint232", nil, big.NewInt(1), ""}, + {"uint240", nil, big.NewInt(1), ""}, + {"uint248", nil, big.NewInt(1), ""}, + {"int24", nil, big.NewInt(1), ""}, + {"int40", nil, big.NewInt(1), ""}, + {"int48", nil, big.NewInt(1), ""}, + {"int56", nil, big.NewInt(1), ""}, + {"int72", nil, big.NewInt(1), ""}, + {"int80", nil, big.NewInt(1), ""}, + {"int88", nil, big.NewInt(1), ""}, + {"int96", nil, big.NewInt(1), ""}, + {"int104", nil, big.NewInt(1), ""}, + {"int112", nil, big.NewInt(1), ""}, + {"int120", nil, big.NewInt(1), ""}, + {"int128", nil, big.NewInt(1), ""}, + {"int136", nil, big.NewInt(1), ""}, + {"int144", nil, big.NewInt(1), ""}, + {"int152", nil, big.NewInt(1), ""}, + {"int160", nil, big.NewInt(1), ""}, + {"int168", nil, big.NewInt(1), ""}, + {"int176", nil, big.NewInt(1), ""}, + {"int184", nil, big.NewInt(1), ""}, + {"int192", nil, big.NewInt(1), ""}, + {"int200", nil, big.NewInt(1), ""}, + {"int208", nil, big.NewInt(1), ""}, + {"int216", nil, big.NewInt(1), ""}, + {"int224", nil, big.NewInt(1), ""}, + {"int232", nil, big.NewInt(1), ""}, + {"int240", nil, big.NewInt(1), ""}, + {"int248", nil, big.NewInt(1), ""}, + {"uint30", nil, uint8(1), "abi: cannot use uint8 as type ptr as argument"}, + {"uint8", nil, uint16(1), "abi: cannot use uint16 as type uint8 as argument"}, + {"uint8", nil, uint32(1), "abi: cannot use uint32 as type uint8 as argument"}, + {"uint8", nil, uint64(1), "abi: cannot use uint64 as type uint8 as argument"}, + {"uint8", nil, int8(1), "abi: cannot use int8 as type uint8 as argument"}, + {"uint8", nil, int16(1), "abi: cannot use int16 as type uint8 as argument"}, + {"uint8", nil, int32(1), "abi: cannot use int32 as type uint8 as argument"}, + {"uint8", nil, int64(1), "abi: cannot use int64 as type uint8 as argument"}, + {"uint16", nil, uint16(1), ""}, + {"uint16", nil, uint8(1), "abi: cannot use uint8 as type uint16 as argument"}, + {"uint16[]", nil, []uint16{1, 2, 3}, ""}, + {"uint16[]", nil, [3]uint16{1, 2, 3}, ""}, + {"uint16[]", nil, []uint32{1, 2, 3}, "abi: cannot use []uint32 as type [0]uint16 as argument"}, + {"uint16[3]", nil, [3]uint32{1, 2, 3}, "abi: cannot use [3]uint32 as type [3]uint16 as argument"}, + {"uint16[3]", nil, [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, + {"uint16[3]", nil, []uint16{1, 2, 3}, ""}, + {"uint16[3]", nil, []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, + {"address[]", nil, []common.Address{{1}}, ""}, + {"address[1]", nil, []common.Address{{1}}, ""}, + {"address[1]", nil, [1]common.Address{{1}}, ""}, + {"address[2]", nil, [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"}, + {"bytes32", nil, [32]byte{}, ""}, + {"bytes31", nil, [31]byte{}, ""}, + {"bytes30", nil, [30]byte{}, ""}, + {"bytes29", nil, [29]byte{}, ""}, + {"bytes28", nil, [28]byte{}, ""}, + {"bytes27", nil, [27]byte{}, ""}, + {"bytes26", nil, [26]byte{}, ""}, + {"bytes25", nil, [25]byte{}, ""}, + {"bytes24", nil, [24]byte{}, ""}, + {"bytes23", nil, [23]byte{}, ""}, + {"bytes22", nil, [22]byte{}, ""}, + {"bytes21", nil, [21]byte{}, ""}, + {"bytes20", nil, [20]byte{}, ""}, + {"bytes19", nil, [19]byte{}, ""}, + {"bytes18", nil, [18]byte{}, ""}, + {"bytes17", nil, [17]byte{}, ""}, + {"bytes16", nil, [16]byte{}, ""}, + {"bytes15", nil, [15]byte{}, ""}, + {"bytes14", nil, [14]byte{}, ""}, + {"bytes13", nil, [13]byte{}, ""}, + {"bytes12", nil, [12]byte{}, ""}, + {"bytes11", nil, [11]byte{}, ""}, + {"bytes10", nil, [10]byte{}, ""}, + {"bytes9", nil, [9]byte{}, ""}, + {"bytes8", nil, [8]byte{}, ""}, + {"bytes7", nil, [7]byte{}, ""}, + {"bytes6", nil, [6]byte{}, ""}, + {"bytes5", nil, [5]byte{}, ""}, + {"bytes4", nil, [4]byte{}, ""}, + {"bytes3", nil, [3]byte{}, ""}, + {"bytes2", nil, [2]byte{}, ""}, + {"bytes1", nil, [1]byte{}, ""}, + {"bytes32", nil, [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"}, + {"bytes32", nil, common.Hash{1}, ""}, + {"bytes31", nil, common.Hash{1}, "abi: cannot use common.Hash as type [31]uint8 as argument"}, + {"bytes31", nil, [32]byte{}, "abi: cannot use [32]uint8 as type [31]uint8 as argument"}, + {"bytes", nil, []byte{0, 1}, ""}, + {"bytes", nil, [2]byte{0, 1}, "abi: cannot use array as type slice as argument"}, + {"bytes", nil, common.Hash{1}, "abi: cannot use array as type slice as argument"}, + {"string", nil, "hello world", ""}, + {"string", nil, string(""), ""}, + {"string", nil, []byte{}, "abi: cannot use slice as type string as argument"}, + {"bytes32[]", nil, [][32]byte{{}}, ""}, + {"function", nil, [24]byte{}, ""}, + {"bytes20", nil, common.Address{}, ""}, + {"address", nil, [20]byte{}, ""}, + {"address", nil, common.Address{}, ""}, + {"bytes32[]]", nil, "", "invalid arg type in abi"}, + {"invalidType", nil, "", "unsupported arg type: invalidType"}, + {"invalidSlice[]", nil, "", "unsupported arg type: invalidSlice"}, + // simple tuple + {"tuple", []ArgumentMarshaling{{Name: "a", Type: "uint256"}, {Name: "b", Type: "uint256"}}, struct { + A *big.Int + B *big.Int + }{}, ""}, + // tuple slice + {"tuple[]", []ArgumentMarshaling{{Name: "a", Type: "uint256"}, {Name: "b", Type: "uint256"}}, []struct { + A *big.Int + B *big.Int + }{}, ""}, + // tuple array + {"tuple[2]", []ArgumentMarshaling{{Name: "a", Type: "uint256"}, {Name: "b", Type: "uint256"}}, []struct { + A *big.Int + B *big.Int + }{{big.NewInt(0), big.NewInt(0)}, {big.NewInt(0), big.NewInt(0)}}, ""}, } { - typ, err := NewType(test.typ) + typ, err := NewType(test.typ, test.components) if err != nil && len(test.err) == 0 { t.Fatal("unexpected parse error:", err) } else if err != nil && len(test.err) != 0 { diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack.go index d5875140..b2e61d06 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack.go @@ -115,17 +115,6 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) { } -func getFullElemSize(elem *Type) int { - //all other should be counted as 32 (slices have pointers to respective elements) - size := 32 - //arrays wrap it, each element being the same size - for elem.T == ArrayTy { - size *= elem.Size - elem = elem.Elem - } - return size -} - // iteratively unpack elements func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { if size < 0 { @@ -150,13 +139,9 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) // Arrays have packed elements, resulting in longer unpack steps. // Slices have just 32 bytes per element (pointing to the contents). - elemSize := 32 - if t.T == ArrayTy { - elemSize = getFullElemSize(t.Elem) - } + elemSize := getTypeSize(*t.Elem) for i, j := start, 0; j < size; i, j = i+elemSize, j+1 { - inter, err := toGoType(i, *t.Elem, output) if err != nil { return nil, err @@ -170,6 +155,36 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) return refSlice.Interface(), nil } +func forTupleUnpack(t Type, output []byte) (interface{}, error) { + retval := reflect.New(t.Type).Elem() + virtualArgs := 0 + for index, elem := range t.TupleElems { + marshalledValue, err := toGoType((index+virtualArgs)*32, *elem, output) + if elem.T == ArrayTy && !isDynamicType(*elem) { + // If we have a static array, like [3]uint256, these are coded as + // just like uint256,uint256,uint256. + // This means that we need to add two 'virtual' arguments when + // we count the index from now on. + // + // Array values nested multiple levels deep are also encoded inline: + // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256 + // + // Calculate the full array size to get the correct offset for the next argument. + // Decrement it by 1, as the normal index increment is still applied. + virtualArgs += getTypeSize(*elem)/32 - 1 + } else if elem.T == TupleTy && !isDynamicType(*elem) { + // If we have a static tuple, like (uint256, bool, uint256), these are + // coded as just like uint256,bool,uint256 + virtualArgs += getTypeSize(*elem)/32 - 1 + } + if err != nil { + return nil, err + } + retval.Field(index).Set(reflect.ValueOf(marshalledValue)) + } + return retval.Interface(), nil +} + // toGoType parses the output bytes and recursively assigns the value of these bytes // into a go type with accordance with the ABI spec. func toGoType(index int, t Type, output []byte) (interface{}, error) { @@ -178,14 +193,14 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { } var ( - returnOutput []byte - begin, end int - err error + returnOutput []byte + begin, length int + err error ) // if we require a length prefix, find the beginning word and size returned. if t.requiresLengthPrefix() { - begin, end, err = lengthPrefixPointsTo(index, output) + begin, length, err = lengthPrefixPointsTo(index, output) if err != nil { return nil, err } @@ -194,12 +209,26 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { } switch t.T { + case TupleTy: + if isDynamicType(t) { + begin, err := tuplePointsTo(index, output) + if err != nil { + return nil, err + } + return forTupleUnpack(t, output[begin:]) + } else { + return forTupleUnpack(t, output[index:]) + } case SliceTy: - return forEachUnpack(t, output, begin, end) + return forEachUnpack(t, output[begin:], 0, length) case ArrayTy: - return forEachUnpack(t, output, index, t.Size) + if isDynamicType(*t.Elem) { + offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:])) + return forEachUnpack(t, output[offset:], 0, t.Size) + } + return forEachUnpack(t, output[index:], 0, t.Size) case StringTy: // variable arrays are written at the end of the return bytes - return string(output[begin : begin+end]), nil + return string(output[begin : begin+length]), nil case IntTy, UintTy: return readInteger(t.T, t.Kind, returnOutput), nil case BoolTy: @@ -209,7 +238,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { case HashTy: return common.BytesToHash(returnOutput), nil case BytesTy: - return output[begin : begin+end], nil + return output[begin : begin+length], nil case FixedBytesTy: return readFixedBytes(t, returnOutput) case FunctionTy: @@ -240,7 +269,7 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err totalSize.Add(totalSize, bigOffsetEnd) totalSize.Add(totalSize, lengthBig) if totalSize.BitLen() > 63 { - return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize) + return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize) } if totalSize.Cmp(outputLength) > 0 { @@ -250,3 +279,17 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err length = int(lengthBig.Uint64()) return } + +// tuplePointsTo resolves the location reference for dynamic tuple. +func tuplePointsTo(index int, output []byte) (start int, err error) { + offset := big.NewInt(0).SetBytes(output[index : index+32]) + outputLen := big.NewInt(int64(len(output))) + + if offset.Cmp(big.NewInt(int64(len(output)))) > 0 { + return 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", offset, outputLen) + } + if offset.BitLen() > 63 { + return 0, fmt.Errorf("abi offset larger than int64: %v", offset) + } + return int(offset.Uint64()), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack_test.go index 97552b90..fa8a69d0 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack_test.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack_test.go @@ -173,9 +173,14 @@ var unpackTests = []unpackTest{ // multi dimensional, if these pass, all types that don't require length prefix should pass { def: `[{"type": "uint8[][]"}]`, - enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", want: [][]uint8{{1, 2}, {1, 2}}, }, + { + def: `[{"type": "uint8[][]"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", + want: [][]uint8{{1, 2}, {1, 2, 3}}, + }, { def: `[{"type": "uint8[2][2]"}]`, enc: "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", @@ -183,7 +188,7 @@ var unpackTests = []unpackTest{ }, { def: `[{"type": "uint8[][2]"}]`, - enc: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", + enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", want: [2][]uint8{{1}, {1}}, }, { @@ -191,6 +196,11 @@ var unpackTests = []unpackTest{ enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", want: [][2]uint8{{1, 2}}, }, + { + def: `[{"type": "uint8[2][]"}]`, + enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: [][2]uint8{{1, 2}, {1, 2}}, + }, { def: `[{"type": "uint16[]"}]`, enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", @@ -236,6 +246,26 @@ var unpackTests = []unpackTest{ enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, }, + { + def: `[{"type": "string[4]"}]`, + enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b476f2d657468657265756d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000", + want: [4]string{"Hello", "World", "Go-ethereum", "Ethereum"}, + }, + { + def: `[{"type": "string[]"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000", + want: []string{"Ethereum", "go-ethereum"}, + }, + { + def: `[{"type": "bytes[]"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003f0f0f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f0f0f00000000000000000000000000000000000000000000000000000000000", + want: [][]byte{{0xf0, 0xf0, 0xf0}, {0xf0, 0xf0, 0xf0}}, + }, + { + def: `[{"type": "uint256[2][][]"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e8", + want: [][][2]*big.Int{{{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}, {{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}}, + }, { def: `[{"type": "int8[]"}]`, enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", @@ -295,6 +325,53 @@ var unpackTests = []unpackTest{ Int2 *big.Int }{big.NewInt(1), big.NewInt(2)}, }, + { + def: `[{"name":"int_one","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + }{big.NewInt(1)}, + }, + { + def: `[{"name":"int__one","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + }{big.NewInt(1)}, + }, + { + def: `[{"name":"int_one_","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + }{big.NewInt(1)}, + }, + { + def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + Intone *big.Int + }{big.NewInt(1), big.NewInt(2)}, + }, + { + def: `[{"name":"___","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + Intone *big.Int + }{}, + err: "abi: purely underscored output cannot unpack to struct", + }, + { + def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{}, + err: "abi: multiple outputs mapping to the same struct field 'IntOne'", + }, { def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`, enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", @@ -359,6 +436,55 @@ func TestUnpack(t *testing.T) { } } +func TestUnpackSetDynamicArrayOutput(t *testing.T) { + abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`)) + if err != nil { + t.Fatal(err) + } + + var ( + marshalledReturn32 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783132333435363738393000000000000000000000000000000000000000003078303938373635343332310000000000000000000000000000000000000000") + marshalledReturn15 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783031323334350000000000000000000000000000000000000000000000003078393837363534000000000000000000000000000000000000000000000000") + + out32 [][32]byte + out15 [][15]byte + ) + + // test 32 + err = abi.Unpack(&out32, "testDynamicFixedBytes32", marshalledReturn32) + if err != nil { + t.Fatal(err) + } + if len(out32) != 2 { + t.Fatalf("expected array with 2 values, got %d", len(out32)) + } + expected := common.Hex2Bytes("3078313233343536373839300000000000000000000000000000000000000000") + if !bytes.Equal(out32[0][:], expected) { + t.Errorf("expected %x, got %x\n", expected, out32[0]) + } + expected = common.Hex2Bytes("3078303938373635343332310000000000000000000000000000000000000000") + if !bytes.Equal(out32[1][:], expected) { + t.Errorf("expected %x, got %x\n", expected, out32[1]) + } + + // test 15 + err = abi.Unpack(&out15, "testDynamicFixedBytes32", marshalledReturn15) + if err != nil { + t.Fatal(err) + } + if len(out15) != 2 { + t.Fatalf("expected array with 2 values, got %d", len(out15)) + } + expected = common.Hex2Bytes("307830313233343500000000000000") + if !bytes.Equal(out15[0][:], expected) { + t.Errorf("expected %x, got %x\n", expected, out15[0]) + } + expected = common.Hex2Bytes("307839383736353400000000000000") + if !bytes.Equal(out15[1][:], expected) { + t.Errorf("expected %x, got %x\n", expected, out15[1]) + } +} + type methodMultiOutput struct { Int *big.Int String string @@ -386,6 +512,11 @@ func TestMethodMultiReturn(t *testing.T) { Int *big.Int } + newInterfaceSlice := func(len int) interface{} { + slice := make([]interface{}, len) + return &slice + } + abi, data, expected := methodMultiReturn(require.New(t)) bigint := new(big.Int) var testCases = []struct { @@ -413,6 +544,16 @@ func TestMethodMultiReturn(t *testing.T) { &[2]interface{}{&expected.Int, &expected.String}, "", "Can unpack into an array", + }, { + &[2]interface{}{}, + &[2]interface{}{expected.Int, expected.String}, + "", + "Can unpack into interface array", + }, { + newInterfaceSlice(2), + &[]interface{}{expected.Int, expected.String}, + "", + "Can unpack into interface slice", }, { &[]interface{}{new(int), new(int)}, &[]interface{}{&expected.Int, &expected.String}, @@ -462,6 +603,68 @@ func TestMultiReturnWithArray(t *testing.T) { } } +func TestMultiReturnWithStringArray(t *testing.T) { + const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]` + abi, err := JSON(strings.NewReader(definition)) + if err != nil { + t.Fatal(err) + } + buff := new(bytes.Buffer) + buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000005c1b78ea0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000ab1257528b3782fb40d7ed5f72e624b744dffb2f00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001048656c6c6f2c20457468657265756d2100000000000000000000000000000000")) + temp, _ := big.NewInt(0).SetString("30000000000000000000", 10) + ret1, ret1Exp := new([3]*big.Int), [3]*big.Int{big.NewInt(1545304298), big.NewInt(6), temp} + ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f") + ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"} + ret4, ret4Exp := new(bool), false + if err := abi.Unpack(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(*ret1, ret1Exp) { + t.Error("big.Int array result", *ret1, "!= Expected", ret1Exp) + } + if !reflect.DeepEqual(*ret2, ret2Exp) { + t.Error("address result", *ret2, "!= Expected", ret2Exp) + } + if !reflect.DeepEqual(*ret3, ret3Exp) { + t.Error("string array result", *ret3, "!= Expected", ret3Exp) + } + if !reflect.DeepEqual(*ret4, ret4Exp) { + t.Error("bool result", *ret4, "!= Expected", ret4Exp) + } +} + +func TestMultiReturnWithStringSlice(t *testing.T) { + const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]` + abi, err := JSON(strings.NewReader(definition)) + if err != nil { + t.Fatal(err) + } + buff := new(bytes.Buffer) + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) // output[0] offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000120")) // output[1] offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // output[0] length + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) // output[0][0] offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000080")) // output[0][1] offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000008")) // output[0][0] length + buff.Write(common.Hex2Bytes("657468657265756d000000000000000000000000000000000000000000000000")) // output[0][0] value + buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000b")) // output[0][1] length + buff.Write(common.Hex2Bytes("676f2d657468657265756d000000000000000000000000000000000000000000")) // output[0][1] value + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // output[1] length + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000064")) // output[1][0] value + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000065")) // output[1][1] value + ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"} + ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)} + if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(*ret1, ret1Exp) { + t.Error("string slice result", *ret1, "!= Expected", ret1Exp) + } + if !reflect.DeepEqual(*ret2, ret2Exp) { + t.Error("uint256 slice result", *ret2, "!= Expected", ret2Exp) + } +} + func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { // Similar to TestMultiReturnWithArray, but with a special case in mind: // values of nested static arrays count towards the size as well, and any element following @@ -751,6 +954,108 @@ func TestUnmarshal(t *testing.T) { } } +func TestUnpackTuple(t *testing.T) { + const simpleTuple = `[{"name":"tuple","constant":false,"outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]` + abi, err := JSON(strings.NewReader(simpleTuple)) + if err != nil { + t.Fatal(err) + } + buff := new(bytes.Buffer) + + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // ret[a] = 1 + buff.Write(common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) // ret[b] = -1 + + v := struct { + Ret struct { + A *big.Int + B *big.Int + } + }{Ret: struct { + A *big.Int + B *big.Int + }{new(big.Int), new(big.Int)}} + + err = abi.Unpack(&v, "tuple", buff.Bytes()) + if err != nil { + t.Error(err) + } else { + if v.Ret.A.Cmp(big.NewInt(1)) != 0 { + t.Errorf("unexpected value unpacked: want %x, got %x", 1, v.Ret.A) + } + if v.Ret.B.Cmp(big.NewInt(-1)) != 0 { + t.Errorf("unexpected value unpacked: want %x, got %x", v.Ret.B, -1) + } + } + + // Test nested tuple + const nestedTuple = `[{"name":"tuple","constant":false,"outputs":[ + {"type":"tuple","name":"s","components":[{"type":"uint256","name":"a"},{"type":"uint256[]","name":"b"},{"type":"tuple[]","name":"c","components":[{"name":"x", "type":"uint256"},{"name":"y","type":"uint256"}]}]}, + {"type":"tuple","name":"t","components":[{"name":"x", "type":"uint256"},{"name":"y","type":"uint256"}]}, + {"type":"uint256","name":"a"} + ]}]` + + abi, err = JSON(strings.NewReader(nestedTuple)) + if err != nil { + t.Fatal(err) + } + buff.Reset() + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000080")) // s offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")) // t.X = 0 + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // t.Y = 1 + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // a = 1 + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // s.A = 1 + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060")) // s.B offset + buff.Write(common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000c0")) // s.C offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // s.B length + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // s.B[0] = 1 + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // s.B[0] = 2 + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // s.C length + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // s.C[0].X + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // s.C[0].Y + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // s.C[1].X + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // s.C[1].Y + + type T struct { + X *big.Int `abi:"x"` + Z *big.Int `abi:"y"` // Test whether the abi tag works. + } + + type S struct { + A *big.Int + B []*big.Int + C []T + } + + type Ret struct { + FieldS S `abi:"s"` + FieldT T `abi:"t"` + A *big.Int + } + var ret Ret + var expected = Ret{ + FieldS: S{ + A: big.NewInt(1), + B: []*big.Int{big.NewInt(1), big.NewInt(2)}, + C: []T{ + {big.NewInt(1), big.NewInt(2)}, + {big.NewInt(2), big.NewInt(1)}, + }, + }, + FieldT: T{ + big.NewInt(0), big.NewInt(1), + }, + A: big.NewInt(1), + } + + err = abi.Unpack(&ret, "tuple", buff.Bytes()) + if err != nil { + t.Error(err) + } + if reflect.DeepEqual(ret, expected) { + t.Error("unexpected unpack value") + } +} + func TestOOMMaliciousInput(t *testing.T) { oomTests := []unpackTest{ { diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/accounts.go b/vendor/github.com/ethereum/go-ethereum/accounts/accounts.go index cb1eae28..a52aa425 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/accounts.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/accounts.go @@ -18,12 +18,14 @@ package accounts import ( + "fmt" "math/big" ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" + "golang.org/x/crypto/sha3" ) // Account represents an Ethereum account located at a specific location defined @@ -33,6 +35,13 @@ type Account struct { URL URL `json:"url"` // Optional resource locator within a backend } +const ( + MimetypeTextWithValidator = "text/validator" + MimetypeTypedData = "data/typed" + MimetypeClique = "application/x-clique-header" + MimetypeTextPlain = "text/plain" +) + // Wallet represents a software or hardware wallet that might contain one or more // accounts (derived from the same seed). type Wallet interface { @@ -87,8 +96,26 @@ type Wallet interface { // chain state reader. SelfDerive(base DerivationPath, chain ethereum.ChainStateReader) - // SignHash requests the wallet to sign the given hash. + // SignData requests the wallet to sign the hash of the given data + // It looks up the account specified either solely via its address contained within, + // or optionally with the aid of any location metadata from the embedded URL field. // + // If the wallet requires additional authentication to sign the request (e.g. + // a password to decrypt the account, or a PIN code o verify the transaction), + // an AuthNeededError instance will be returned, containing infos for the user + // about which fields or actions are needed. The user may retry by providing + // the needed details via SignDataWithPassphrase, or by other means (e.g. unlock + // the account in a keystore). + SignData(account Account, mimeType string, data []byte) ([]byte, error) + + // SignDataWithPassphrase is identical to SignData, but also takes a password + // NOTE: there's an chance that an erroneous call might mistake the two strings, and + // supply password in the mimetype field, or vice versa. Thus, an implementation + // should never echo the mimetype or return the mimetype in the error-response + SignDataWithPassphrase(account Account, passphrase, mimeType string, data []byte) ([]byte, error) + + // SignText requests the wallet to sign the hash of a given piece of data, prefixed + // by the Ethereum prefix scheme // It looks up the account specified either solely via its address contained within, // or optionally with the aid of any location metadata from the embedded URL field. // @@ -98,7 +125,10 @@ type Wallet interface { // about which fields or actions are needed. The user may retry by providing // the needed details via SignHashWithPassphrase, or by other means (e.g. unlock // the account in a keystore). - SignHash(account Account, hash []byte) ([]byte, error) + SignText(account Account, text []byte) ([]byte, error) + + // SignTextWithPassphrase is identical to Signtext, but also takes a password + SignTextWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error) // SignTx requests the wallet to sign the given transaction. // @@ -113,18 +143,7 @@ type Wallet interface { // the account in a keystore). SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) - // SignHashWithPassphrase requests the wallet to sign the given hash with the - // given passphrase as extra authentication information. - // - // It looks up the account specified either solely via its address contained within, - // or optionally with the aid of any location metadata from the embedded URL field. - SignHashWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error) - - // SignTxWithPassphrase requests the wallet to sign the given transaction, with the - // given passphrase as extra authentication information. - // - // It looks up the account specified either solely via its address contained within, - // or optionally with the aid of any location metadata from the embedded URL field. + // SignTxWithPassphrase is identical to SignTx, but also takes a password SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) } @@ -148,6 +167,32 @@ type Backend interface { Subscribe(sink chan<- WalletEvent) event.Subscription } +// TextHash is a helper function that calculates a hash for the given message that can be +// safely used to calculate a signature from. +// +// The hash is calulcated as +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +// +// This gives context to the signed message and prevents signing of transactions. +func TextHash(data []byte) []byte { + hash, _ := TextAndHash(data) + return hash +} + +// TextAndHash is a helper function that calculates a hash for the given message that can be +// safely used to calculate a signature from. +// +// The hash is calulcated as +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +// +// This gives context to the signed message and prevents signing of transactions. +func TextAndHash(data []byte) ([]byte, string) { + msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data)) + hasher := sha3.NewLegacyKeccak256() + hasher.Write([]byte(msg)) + return hasher.Sum(nil), msg +} + // WalletEventType represents the different event types that can be fired by // the wallet subscription subsystem. type WalletEventType int diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/config.go b/vendor/github.com/ethereum/go-ethereum/accounts/accounts_test.go similarity index 66% rename from vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/config.go rename to vendor/github.com/ethereum/go-ethereum/accounts/accounts_test.go index fcc23070..a49e3954 100644 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/config.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/accounts_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,14 +14,19 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisperv5 +package accounts -type Config struct { - MaxMessageSize uint32 `toml:",omitempty"` - MinimumAcceptedPOW float64 `toml:",omitempty"` -} +import ( + "bytes" + "testing" -var DefaultConfig = Config{ - MaxMessageSize: DefaultMaxMessageSize, - MinimumAcceptedPOW: DefaultMinimumPoW, + "github.com/ethereum/go-ethereum/common/hexutil" +) + +func TestTextHash(t *testing.T) { + hash := TextHash([]byte("Hello Joe")) + want := hexutil.MustDecode("0xa080337ae51c4e064c189e113edd0ba391df9206e2f49db658bb32cf2911730b") + if !bytes.Equal(hash, want) { + t.Fatalf("wrong hash: %x", hash) + } } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/external/backend.go b/vendor/github.com/ethereum/go-ethereum/accounts/external/backend.go new file mode 100644 index 00000000..21a313b6 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/accounts/external/backend.go @@ -0,0 +1,228 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package external + +import ( + "fmt" + "math/big" + "sync" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/signer/core" +) + +type ExternalBackend struct { + signers []accounts.Wallet +} + +func (eb *ExternalBackend) Wallets() []accounts.Wallet { + return eb.signers +} + +func NewExternalBackend(endpoint string) (*ExternalBackend, error) { + signer, err := NewExternalSigner(endpoint) + if err != nil { + return nil, err + } + return &ExternalBackend{ + signers: []accounts.Wallet{signer}, + }, nil +} + +func (eb *ExternalBackend) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription { + return event.NewSubscription(func(quit <-chan struct{}) error { + <-quit + return nil + }) +} + +// ExternalSigner provides an API to interact with an external signer (clef) +// It proxies request to the external signer while forwarding relevant +// request headers +type ExternalSigner struct { + client *rpc.Client + endpoint string + status string + cacheMu sync.RWMutex + cache []accounts.Account +} + +func NewExternalSigner(endpoint string) (*ExternalSigner, error) { + client, err := rpc.Dial(endpoint) + if err != nil { + return nil, err + } + extsigner := &ExternalSigner{ + client: client, + endpoint: endpoint, + } + // Check if reachable + version, err := extsigner.pingVersion() + if err != nil { + return nil, err + } + extsigner.status = fmt.Sprintf("ok [version=%v]", version) + return extsigner, nil +} + +func (api *ExternalSigner) URL() accounts.URL { + return accounts.URL{ + Scheme: "extapi", + Path: api.endpoint, + } +} + +func (api *ExternalSigner) Status() (string, error) { + return api.status, nil +} + +func (api *ExternalSigner) Open(passphrase string) error { + return fmt.Errorf("operation not supported on external signers") +} + +func (api *ExternalSigner) Close() error { + return fmt.Errorf("operation not supported on external signers") +} + +func (api *ExternalSigner) Accounts() []accounts.Account { + var accnts []accounts.Account + res, err := api.listAccounts() + if err != nil { + log.Error("account listing failed", "error", err) + return accnts + } + for _, addr := range res { + accnts = append(accnts, accounts.Account{ + URL: accounts.URL{ + Scheme: "extapi", + Path: api.endpoint, + }, + Address: addr, + }) + } + api.cacheMu.Lock() + api.cache = accnts + api.cacheMu.Unlock() + return accnts +} + +func (api *ExternalSigner) Contains(account accounts.Account) bool { + api.cacheMu.RLock() + defer api.cacheMu.RUnlock() + for _, a := range api.cache { + if a.Address == account.Address && (account.URL == (accounts.URL{}) || account.URL == api.URL()) { + return true + } + } + return false +} + +func (api *ExternalSigner) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) { + return accounts.Account{}, fmt.Errorf("operation not supported on external signers") +} + +func (api *ExternalSigner) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) { + log.Error("operation SelfDerive not supported on external signers") +} + +func (api *ExternalSigner) signHash(account accounts.Account, hash []byte) ([]byte, error) { + return []byte{}, fmt.Errorf("operation not supported on external signers") +} + +// SignData signs keccak256(data). The mimetype parameter describes the type of data being signed +func (api *ExternalSigner) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) { + var res hexutil.Bytes + var signAddress = common.NewMixedcaseAddress(account.Address) + if err := api.client.Call(&res, "account_signData", + mimeType, + &signAddress, // Need to use the pointer here, because of how MarshalJSON is defined + hexutil.Encode(data)); err != nil { + return nil, err + } + // If V is on 27/28-form, convert to to 0/1 for Clique + if mimeType == accounts.MimetypeClique && (res[64] == 27 || res[64] == 28) { + res[64] -= 27 // Transform V from 27/28 to 0/1 for Clique use + } + return res, nil +} + +func (api *ExternalSigner) SignText(account accounts.Account, text []byte) ([]byte, error) { + var res hexutil.Bytes + var signAddress = common.NewMixedcaseAddress(account.Address) + if err := api.client.Call(&res, "account_signData", + accounts.MimetypeTextPlain, + &signAddress, // Need to use the pointer here, because of how MarshalJSON is defined + hexutil.Encode(text)); err != nil { + return nil, err + } + return res, nil +} + +func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + res := ethapi.SignTransactionResult{} + to := common.NewMixedcaseAddress(*tx.To()) + data := hexutil.Bytes(tx.Data()) + args := &core.SendTxArgs{ + Data: &data, + Nonce: hexutil.Uint64(tx.Nonce()), + Value: hexutil.Big(*tx.Value()), + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: hexutil.Big(*tx.GasPrice()), + To: &to, + From: common.NewMixedcaseAddress(account.Address), + } + + if err := api.client.Call(&res, "account_signTransaction", args); err != nil { + return nil, err + } + return res.Tx, nil +} + +func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { + return []byte{}, fmt.Errorf("passphrase-operations not supported on external signers") +} + +func (api *ExternalSigner) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + return nil, fmt.Errorf("passphrase-operations not supported on external signers") +} +func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) { + return nil, fmt.Errorf("passphrase-operations not supported on external signers") +} + +func (api *ExternalSigner) listAccounts() ([]common.Address, error) { + var res []common.Address + if err := api.client.Call(&res, "account_list"); err != nil { + return nil, err + } + return res, nil +} + +func (api *ExternalSigner) pingVersion() (string, error) { + var v string + if err := api.client.Call(&v, "account_version"); err != nil { + return "", err + } + return v, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/account_cache.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/account_cache.go index da3a46eb..8f660e28 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/account_cache.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/account_cache.go @@ -265,7 +265,10 @@ func (ac *accountCache) scanAccounts() error { case (addr == common.Address{}): log.Debug("Failed to decode keystore key", "path", path, "err", "missing or zero address") default: - return &accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}} + return &accounts.Account{ + Address: addr, + URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}, + } } return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/key.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/key.go index 0564751c..84d8df0c 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/key.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/key.go @@ -171,7 +171,10 @@ func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Accou if err != nil { return nil, accounts.Account{}, err } - a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}} + a := accounts.Account{ + Address: key.Address, + URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}, + } if err := ks.StoreKey(a.URL.Path, key, auth); err != nil { zeroKey(key.PrivateKey) return nil, a, err @@ -224,5 +227,6 @@ func toISO8601(t time.Time) string { } else { tz = fmt.Sprintf("%03d00", offset/3600) } - return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz) + return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", + t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz) } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore.go index 2918047c..434e0350 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore.go @@ -137,8 +137,10 @@ func (ks *KeyStore) refreshWallets() { accs := ks.cache.accounts() // Transform the current list of wallets into the new one - wallets := make([]accounts.Wallet, 0, len(accs)) - events := []accounts.WalletEvent{} + var ( + wallets = make([]accounts.Wallet, 0, len(accs)) + events []accounts.WalletEvent + ) for _, account := range accs { // Drop wallets while they were in front of the next account diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go similarity index 99% rename from vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase.go rename to vendor/github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go index 9794f32f..a0b6cf53 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/passphrase.go @@ -233,6 +233,7 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) { PrivateKey: key, }, nil } + func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) { if cryptoJson.Cipher != "aes-128-ctr" { return nil, fmt.Errorf("Cipher not supported: %v", cryptoJson.Cipher) diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/passphrase_test.go similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_passphrase_test.go rename to vendor/github.com/ethereum/go-ethereum/accounts/keystore/passphrase_test.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_plain.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/plain.go similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_plain.go rename to vendor/github.com/ethereum/go-ethereum/accounts/keystore/plain.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_plain_test.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/plain_test.go similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_plain_test.go rename to vendor/github.com/ethereum/go-ethereum/accounts/keystore/plain_test.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/presale.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/presale.go index 1554294e..03055245 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/presale.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/presale.go @@ -38,7 +38,13 @@ func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (accou return accounts.Account{}, nil, err } key.Id = uuid.NewRandom() - a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: keyStore.JoinPath(keyFileName(key.Address))}} + a := accounts.Account{ + Address: key.Address, + URL: accounts.URL{ + Scheme: KeyStoreScheme, + Path: keyStore.JoinPath(keyFileName(key.Address)), + }, + } err = keyStore.StoreKey(a.URL.Path, key, password) return a, key, err } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_wallet.go b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/wallet.go similarity index 77% rename from vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_wallet.go rename to vendor/github.com/ethereum/go-ethereum/accounts/keystore/wallet.go index 758fdfe3..1b36b6df 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/keystore/keystore_wallet.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/keystore/wallet.go @@ -22,6 +22,7 @@ import ( ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" ) // keystoreWallet implements the accounts.Wallet interface for the original @@ -52,8 +53,8 @@ func (w *keystoreWallet) Status() (string, error) { // is no connection or decryption step necessary to access the list of accounts. func (w *keystoreWallet) Open(passphrase string) error { return nil } -// Close implements accounts.Wallet, but is a noop for plain wallets since is no -// meaningful open operation. +// Close implements accounts.Wallet, but is a noop for plain wallets since there +// is no meaningful open operation. func (w *keystoreWallet) Close() error { return nil } // Accounts implements accounts.Wallet, returning an account list consisting of @@ -78,60 +79,67 @@ func (w *keystoreWallet) Derive(path accounts.DerivationPath, pin bool) (account // there is no notion of hierarchical account derivation for plain keystore accounts. func (w *keystoreWallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {} -// SignHash implements accounts.Wallet, attempting to sign the given hash with +// signHash attempts to sign the given hash with // the given account. If the wallet does not wrap this particular account, an // error is returned to avoid account leakage (even though in theory we may be // able to sign via our shared keystore backend). -func (w *keystoreWallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) { +func (w *keystoreWallet) signHash(account accounts.Account, hash []byte) ([]byte, error) { // Make sure the requested account is contained within - if account.Address != w.account.Address { - return nil, accounts.ErrUnknownAccount - } - if account.URL != (accounts.URL{}) && account.URL != w.account.URL { + if !w.Contains(account) { return nil, accounts.ErrUnknownAccount } // Account seems valid, request the keystore to sign return w.keystore.SignHash(account, hash) } +// SignData signs keccak256(data). The mimetype parameter describes the type of data being signed +func (w *keystoreWallet) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) { + return w.signHash(account, crypto.Keccak256(data)) +} + +// SignDataWithPassphrase signs keccak256(data). The mimetype parameter describes the type of data being signed +func (w *keystoreWallet) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) { + // Make sure the requested account is contained within + if !w.Contains(account) { + return nil, accounts.ErrUnknownAccount + } + // Account seems valid, request the keystore to sign + return w.keystore.SignHashWithPassphrase(account, passphrase, crypto.Keccak256(data)) +} + +func (w *keystoreWallet) SignText(account accounts.Account, text []byte) ([]byte, error) { + return w.signHash(account, accounts.TextHash(text)) +} + +// SignTextWithPassphrase implements accounts.Wallet, attempting to sign the +// given hash with the given account using passphrase as extra authentication. +func (w *keystoreWallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { + // Make sure the requested account is contained within + if !w.Contains(account) { + return nil, accounts.ErrUnknownAccount + } + // Account seems valid, request the keystore to sign + return w.keystore.SignHashWithPassphrase(account, passphrase, accounts.TextHash(text)) +} + // SignTx implements accounts.Wallet, attempting to sign the given transaction // with the given account. If the wallet does not wrap this particular account, // an error is returned to avoid account leakage (even though in theory we may // be able to sign via our shared keystore backend). func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { // Make sure the requested account is contained within - if account.Address != w.account.Address { - return nil, accounts.ErrUnknownAccount - } - if account.URL != (accounts.URL{}) && account.URL != w.account.URL { + if !w.Contains(account) { return nil, accounts.ErrUnknownAccount } // Account seems valid, request the keystore to sign return w.keystore.SignTx(account, tx, chainID) } -// SignHashWithPassphrase implements accounts.Wallet, attempting to sign the -// given hash with the given account using passphrase as extra authentication. -func (w *keystoreWallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) { - // Make sure the requested account is contained within - if account.Address != w.account.Address { - return nil, accounts.ErrUnknownAccount - } - if account.URL != (accounts.URL{}) && account.URL != w.account.URL { - return nil, accounts.ErrUnknownAccount - } - // Account seems valid, request the keystore to sign - return w.keystore.SignHashWithPassphrase(account, passphrase, hash) -} - // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given // transaction with the given account using passphrase as extra authentication. func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { // Make sure the requested account is contained within - if account.Address != w.account.Address { - return nil, accounts.ErrUnknownAccount - } - if account.URL != (accounts.URL{}) && account.URL != w.account.URL { + if !w.Contains(account) { return nil, accounts.ErrUnknownAccount } // Account seems valid, request the keystore to sign diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/hub.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/hub.go index 640320bc..a91340b4 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/hub.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/hub.go @@ -150,8 +150,10 @@ func (hub *Hub) refreshWallets() { // Transform the current list of wallets into the new one hub.stateLock.Lock() - wallets := make([]accounts.Wallet, 0, len(devices)) - events := []accounts.WalletEvent{} + var ( + wallets = make([]accounts.Wallet, 0, len(devices)) + events []accounts.WalletEvent + ) for _, device := range devices { url := accounts.URL{Scheme: hub.scheme, Path: device.Path} diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/ledger.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/ledger.go index 7d5f6790..c30903b5 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/ledger.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/ledger.go @@ -257,7 +257,9 @@ func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, er // Decode the hex sting into an Ethereum address and return var address common.Address - hex.Decode(address[:], hexstr) + if _, err = hex.Decode(address[:], hexstr); err != nil { + return common.Address{}, err + } return address, nil } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor.go index a9d2e995..d3e17aba 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor.go @@ -28,7 +28,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor" + "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -41,6 +41,9 @@ import ( // encoded passphrase. var ErrTrezorPINNeeded = errors.New("trezor: pin needed") +// ErrTrezorPassphraseNeeded is returned if opening the trezor requires a passphrase +var ErrTrezorPassphraseNeeded = errors.New("trezor: passphrase needed") + // errTrezorReplyInvalidHeader is the error message returned by a Trezor data exchange // if the device replies with a mismatching header. This usually means the device // is in browser mode. @@ -48,12 +51,13 @@ var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header") // trezorDriver implements the communication with a Trezor hardware wallet. type trezorDriver struct { - device io.ReadWriter // USB device connection to communicate through - version [3]uint32 // Current version of the Trezor firmware - label string // Current textual label of the Trezor device - pinwait bool // Flags whether the device is waiting for PIN entry - failure error // Any failure that would make the device unusable - log log.Logger // Contextual logger to tag the trezor with its id + device io.ReadWriter // USB device connection to communicate through + version [3]uint32 // Current version of the Trezor firmware + label string // Current textual label of the Trezor device + pinwait bool // Flags whether the device is waiting for PIN entry + passphrasewait bool // Flags whether the device is waiting for passphrase entry + failure error // Any failure that would make the device unusable + log log.Logger // Contextual logger to tag the trezor with its id } // newTrezorDriver creates a new instance of a Trezor USB protocol driver. @@ -79,7 +83,7 @@ func (w *trezorDriver) Status() (string, error) { } // Open implements usbwallet.driver, attempting to initialize the connection to -// the Trezor hardware wallet. Initializing the Trezor is a two phase operation: +// the Trezor hardware wallet. Initializing the Trezor is a two or three phase operation: // * The first phase is to initialize the connection and read the wallet's // features. This phase is invoked is the provided passphrase is empty. The // device will display the pinpad as a result and will return an appropriate @@ -87,11 +91,13 @@ func (w *trezorDriver) Status() (string, error) { // * The second phase is to unlock access to the Trezor, which is done by the // user actually providing a passphrase mapping a keyboard keypad to the pin // number of the user (shuffled according to the pinpad displayed). +// * If needed the device will ask for passphrase which will require calling +// open again with the actual passphrase (3rd phase) func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error { w.device, w.failure = device, nil // If phase 1 is requested, init the connection and wait for user callback - if passphrase == "" { + if passphrase == "" && !w.passphrasewait { // If we're already waiting for a PIN entry, insta-return if w.pinwait { return ErrTrezorPINNeeded @@ -104,26 +110,46 @@ func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error { w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()} w.label = features.GetLabel() - // Do a manual ping, forcing the device to ask for its PIN + // Do a manual ping, forcing the device to ask for its PIN and Passphrase askPin := true - res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin}, new(trezor.PinMatrixRequest), new(trezor.Success)) + askPassphrase := true + res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin, PassphraseProtection: &askPassphrase}, new(trezor.PinMatrixRequest), new(trezor.PassphraseRequest), new(trezor.Success)) if err != nil { return err } // Only return the PIN request if the device wasn't unlocked until now - if res == 1 { - return nil // Device responded with trezor.Success + switch res { + case 0: + w.pinwait = true + return ErrTrezorPINNeeded + case 1: + w.pinwait = false + w.passphrasewait = true + return ErrTrezorPassphraseNeeded + case 2: + return nil // responded with trezor.Success } - w.pinwait = true - return ErrTrezorPINNeeded } // Phase 2 requested with actual PIN entry - w.pinwait = false - - if _, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success)); err != nil { - w.failure = err - return err + if w.pinwait { + w.pinwait = false + res, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success), new(trezor.PassphraseRequest)) + if err != nil { + w.failure = err + return err + } + if res == 1 { + w.passphrasewait = true + return ErrTrezorPassphraseNeeded + } + } else if w.passphrasewait { + w.passphrasewait = false + if _, err := w.trezorExchange(&trezor.PassphraseAck{Passphrase: &passphrase}, new(trezor.Success)); err != nil { + w.failure = err + return err + } } + return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/messages.pb.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/messages.pb.go similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/messages.pb.go rename to vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/messages.pb.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/messages.proto b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/messages.proto similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/messages.proto rename to vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/messages.proto diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/trezor.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/trezor.go similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/trezor.go rename to vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/trezor.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/types.pb.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/types.pb.go similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/types.pb.go rename to vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/types.pb.go diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/types.proto b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/types.proto similarity index 100% rename from vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor/types.proto rename to vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/trezor/types.proto diff --git a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/wallet.go b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/wallet.go index 6cef6e0f..2ddfa30a 100644 --- a/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/wallet.go +++ b/vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/wallet.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/karalabe/hid" ) @@ -273,9 +274,7 @@ func (w *wallet) close() error { w.device = nil w.accounts, w.paths = nil, nil - w.driver.Close() - - return nil + return w.driver.Close() } // Accounts implements accounts.Wallet, returning the list of accounts pinned to @@ -495,12 +494,28 @@ func (w *wallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainSt w.deriveChain = chain } -// SignHash implements accounts.Wallet, however signing arbitrary data is not +// signHash implements accounts.Wallet, however signing arbitrary data is not // supported for hardware wallets, so this method will always return an error. -func (w *wallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) { +func (w *wallet) signHash(account accounts.Account, hash []byte) ([]byte, error) { return nil, accounts.ErrNotSupported } +// SignData signs keccak256(data). The mimetype parameter describes the type of data being signed +func (w *wallet) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) { + return w.signHash(account, crypto.Keccak256(data)) +} + +// SignDataWithPassphrase implements accounts.Wallet, attempting to sign the given +// data with the given account using passphrase as extra authentication. +// Since USB wallets don't rely on passphrases, these are silently ignored. +func (w *wallet) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) { + return w.SignData(account, mimeType, data) +} + +func (w *wallet) SignText(account accounts.Account, text []byte) ([]byte, error) { + return w.signHash(account, accounts.TextHash(text)) +} + // SignTx implements accounts.Wallet. It sends the transaction over to the Ledger // wallet to request a confirmation from the user. It returns either the signed // transaction or a failure if the user denied the transaction. @@ -550,8 +565,8 @@ func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID // SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary // data is not supported for Ledger wallets, so this method will always return // an error. -func (w *wallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) { - return w.SignHash(account, hash) +func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { + return w.SignText(account, accounts.TextHash(text)) } // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given diff --git a/vendor/github.com/ethereum/go-ethereum/appveyor.yml b/vendor/github.com/ethereum/go-ethereum/appveyor.yml index e5126b25..0eb9163d 100644 --- a/vendor/github.com/ethereum/go-ethereum/appveyor.yml +++ b/vendor/github.com/ethereum/go-ethereum/appveyor.yml @@ -23,8 +23,8 @@ environment: install: - git submodule update --init - rmdir C:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.2.windows-%GETH_ARCH%.zip - - 7z x go1.11.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL + - appveyor DownloadFile https://dl.google.com/go/go1.12.1.windows-%GETH_ARCH%.zip + - 7z x go1.12.1.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - go version - gcc --version diff --git a/vendor/github.com/ethereum/go-ethereum/build/ci-notes.md b/vendor/github.com/ethereum/go-ethereum/build/ci-notes.md index f5b0e869..13e1fd23 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/ci-notes.md +++ b/vendor/github.com/ethereum/go-ethereum/build/ci-notes.md @@ -7,27 +7,34 @@ Canonical. Packages of develop branch commits have suffix -unstable and cannot be installed alongside the stable version. Switching between release streams requires user intervention. +## Launchpad + The packages are built and served by launchpad.net. We generate a Debian source package for each distribution and upload it. Their builder picks up the source package, builds it and installs the new version into the PPA repository. Launchpad requires a valid signature -by a team member for source package uploads. The signing key is stored in an environment -variable which Travis CI makes available to certain builds. +by a team member for source package uploads. + +The signing key is stored in an environment variable which Travis CI makes available to +certain builds. Since Travis CI doesn't support FTP, SFTP is used to transfer the +packages. To set this up yourself, you need to create a Launchpad user and add a GPG key +and SSH key to it. Then encode both keys as base64 and configure 'secret' environment +variables `PPA_SIGNING_KEY` and `PPA_SSH_KEY` on Travis. We want to build go-ethereum with the most recent version of Go, irrespective of the Go version that is available in the main Ubuntu repository. In order to make this possible, our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on -golang-1.10, which is co-installable alongside the regular golang package. PPA dependencies +golang-1.11, which is co-installable alongside the regular golang package. PPA dependencies can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies ## Building Packages Locally (for testing) You need to run Ubuntu to do test packaging. -Add the gophers PPA and install Go 1.10 and Debian packaging tools: +Add the gophers PPA and install Go 1.11 and Debian packaging tools: $ sudo apt-add-repository ppa:gophers/ubuntu/archive $ sudo apt-get update - $ sudo apt-get install build-essential golang-1.10 devscripts debhelper + $ sudo apt-get install build-essential golang-1.11 devscripts debhelper python-bzrlib python-paramiko Create the source packages: diff --git a/vendor/github.com/ethereum/go-ethereum/build/ci.go b/vendor/github.com/ethereum/go-ethereum/build/ci.go index 1bbc9447..f5553fd3 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/ci.go +++ b/vendor/github.com/ethereum/go-ethereum/build/ci.go @@ -80,6 +80,7 @@ var ( executablePath("puppeth"), executablePath("rlpdump"), executablePath("wnode"), + executablePath("clef"), } // Files that end up in the swarm*.zip archive. @@ -118,6 +119,10 @@ var ( BinaryName: "wnode", Description: "Ethereum Whisper diagnostic tool", }, + { + BinaryName: "clef", + Description: "Ethereum account management tool.", + }, } // A debian package is created for all executables listed here. @@ -156,7 +161,7 @@ var ( // Note: yakkety is unsupported because it was officially deprecated on lanchpad. // Note: zesty is unsupported because it was officially deprecated on lanchpad. // Note: artful is unsupported because it was officially deprecated on lanchpad. - debDistros = []string{"trusty", "xenial", "bionic", "cosmic"} + debDistros = []string{"trusty", "xenial", "bionic", "cosmic", "disco"} ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -441,11 +446,8 @@ func archiveBasename(arch string, archiveVersion string) string { func archiveUpload(archive string, blobstore string, signer string) error { // If signing was requested, generate the signature files if signer != "" { - pgpkey, err := base64.StdEncoding.DecodeString(os.Getenv(signer)) - if err != nil { - return fmt.Errorf("invalid base64 %s", signer) - } - if err := build.PGPSignFile(archive, archive+".asc", string(pgpkey)); err != nil { + key := getenvBase64(signer) + if err := build.PGPSignFile(archive, archive+".asc", string(key)); err != nil { return err } } @@ -488,7 +490,8 @@ func maybeSkipArchive(env build.Environment) { func doDebianSource(cmdline []string) { var ( signer = flag.String("signer", "", `Signing key name, also used as package author`) - upload = flag.String("upload", "", `Where to upload the source package (usually "ppa:ethereum/ethereum")`) + upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`) + sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "geth-ci")`) workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`) now = time.Now() ) @@ -498,11 +501,7 @@ func doDebianSource(cmdline []string) { maybeSkipArchive(env) // Import the signing key. - if b64key := os.Getenv("PPA_SIGNING_KEY"); b64key != "" { - key, err := base64.StdEncoding.DecodeString(b64key) - if err != nil { - log.Fatal("invalid base64 PPA_SIGNING_KEY") - } + if key := getenvBase64("PPA_SIGNING_KEY"); len(key) > 0 { gpg := exec.Command("gpg", "--import") gpg.Stdin = bytes.NewReader(key) build.MustRun(gpg) @@ -513,22 +512,58 @@ func doDebianSource(cmdline []string) { for _, distro := range debDistros { meta := newDebMetadata(distro, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables) pkgdir := stageDebianSource(*workdir, meta) - debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc") + debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc", "-d", "-Zxz") debuild.Dir = pkgdir build.MustRun(debuild) - changes := fmt.Sprintf("%s_%s_source.changes", meta.Name(), meta.VersionString()) - changes = filepath.Join(*workdir, changes) + var ( + basename = fmt.Sprintf("%s_%s", meta.Name(), meta.VersionString()) + source = filepath.Join(*workdir, basename+".tar.xz") + dsc = filepath.Join(*workdir, basename+".dsc") + changes = filepath.Join(*workdir, basename+"_source.changes") + ) if *signer != "" { build.MustRunCommand("debsign", changes) } if *upload != "" { - build.MustRunCommand("dput", *upload, changes) + ppaUpload(*workdir, *upload, *sshUser, []string{source, dsc, changes}) } } } } +func ppaUpload(workdir, ppa, sshUser string, files []string) { + p := strings.Split(ppa, "/") + if len(p) != 2 { + log.Fatal("-upload PPA name must contain single /") + } + if sshUser == "" { + sshUser = p[0] + } + incomingDir := fmt.Sprintf("~%s/ubuntu/%s", p[0], p[1]) + // Create the SSH identity file if it doesn't exist. + var idfile string + if sshkey := getenvBase64("PPA_SSH_KEY"); len(sshkey) > 0 { + idfile = filepath.Join(workdir, "sshkey") + if _, err := os.Stat(idfile); os.IsNotExist(err) { + ioutil.WriteFile(idfile, sshkey, 0600) + } + } + // Upload + dest := sshUser + "@ppa.launchpad.net" + if err := build.UploadSFTP(idfile, dest, incomingDir, files); err != nil { + log.Fatal(err) + } +} + +func getenvBase64(variable string) []byte { + dec, err := base64.StdEncoding.DecodeString(os.Getenv(variable)) + if err != nil { + log.Fatal("invalid base64 " + variable) + } + return []byte(dec) +} + func makeWorkdir(wdflag string) string { var err error if wdflag != "" { @@ -770,12 +805,8 @@ func doAndroidArchive(cmdline []string) { if os.Getenv("ANDROID_HOME") == "" { log.Fatal("Please ensure ANDROID_HOME points to your Android SDK") } - if os.Getenv("ANDROID_NDK") == "" { - log.Fatal("Please ensure ANDROID_NDK points to your Android NDK") - } // Build the Android archive and Maven resources build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) - build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK"))) build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) if *local { @@ -800,15 +831,10 @@ func doAndroidArchive(cmdline []string) { os.Rename(archive, meta.Package+".aar") if *signer != "" && *deploy != "" { // Import the signing key into the local GPG instance - b64key := os.Getenv(*signer) - key, err := base64.StdEncoding.DecodeString(b64key) - if err != nil { - log.Fatalf("invalid base64 %s", *signer) - } + key := getenvBase64(*signer) gpg := exec.Command("gpg", "--import") gpg.Stdin = bytes.NewReader(key) build.MustRun(gpg) - keyID, err := build.PGPKeyID(string(key)) if err != nil { log.Fatal(err) diff --git a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.control b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.control index 8cd325bf..b0ced141 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.control +++ b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.control @@ -2,7 +2,7 @@ Source: {{.Name}} Section: science Priority: extra Maintainer: {{.Author}} -Build-Depends: debhelper (>= 8.0.0), golang-1.10 +Build-Depends: debhelper (>= 8.0.0), golang-1.11 Standards-Version: 3.9.5 Homepage: https://ethereum.org Vcs-Git: git://github.com/ethereum/go-ethereum.git diff --git a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.rules b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.rules index 7f286569..5280e0e5 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.rules +++ b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum-swarm/deb.rules @@ -4,8 +4,11 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 +# Launchpad rejects Go's access to $HOME/.cache, use custom folder +export GOCACHE=/tmp/go-build + override_dh_auto_build: - build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} + build/env.sh /usr/lib/go-1.11/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} override_dh_auto_test: diff --git a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.control b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.control index defb106f..018067a1 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.control +++ b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.control @@ -2,7 +2,7 @@ Source: {{.Name}} Section: science Priority: extra Maintainer: {{.Author}} -Build-Depends: debhelper (>= 8.0.0), golang-1.10 +Build-Depends: debhelper (>= 8.0.0), golang-1.11 Standards-Version: 3.9.5 Homepage: https://ethereum.org Vcs-Git: git://github.com/ethereum/go-ethereum.git diff --git a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.rules b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.rules index 7f286569..5280e0e5 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.rules +++ b/vendor/github.com/ethereum/go-ethereum/build/deb/ethereum/deb.rules @@ -4,8 +4,11 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 +# Launchpad rejects Go's access to $HOME/.cache, use custom folder +export GOCACHE=/tmp/go-build + override_dh_auto_build: - build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} + build/env.sh /usr/lib/go-1.11/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} override_dh_auto_test: diff --git a/vendor/github.com/ethereum/go-ethereum/build/travis_keepalive.sh b/vendor/github.com/ethereum/go-ethereum/build/travis_keepalive.sh new file mode 100755 index 00000000..77cc623e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/build/travis_keepalive.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# travis_keepalive runs the given command and preserves its return value, +# while it forks a child process what periodically produces a log line, +# so that Travis won't abort the build after 10 minutes. + +# Why? +# `t.Log()` in Go holds the buffer until the test does not pass or fail, +# and `-race` can increase the execution time by 2-20x. + +set -euo pipefail + +readonly KEEPALIVE_INTERVAL=300 # seconds => 5m + +main() { + keepalive + $@ +} + +# Keepalive produces a log line in each KEEPALIVE_INTERVAL. +keepalive() { + local child_pid + # Note: We fork here! + repeat "keepalive" & + child_pid=$! + ensureChildOnEXIT "${child_pid}" +} + +repeat() { + local this="$1" + while true; do + echo "${this}" + sleep "${KEEPALIVE_INTERVAL}" + done +} + +# Ensures that the child gets killed on normal program exit. +ensureChildOnEXIT() { + # Note: SIGINT and SIGTERM are forwarded to the child process by Bash + # automatically, so we don't have to deal with signals. + + local child_pid="$1" + trap "kill ${child_pid}" EXIT +} + +main "$@" diff --git a/vendor/github.com/ethereum/go-ethereum/build/update-license.go b/vendor/github.com/ethereum/go-ethereum/build/update-license.go index 22e40334..e3e00d4c 100644 --- a/vendor/github.com/ethereum/go-ethereum/build/update-license.go +++ b/vendor/github.com/ethereum/go-ethereum/build/update-license.go @@ -1,3 +1,19 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + // +build none /* diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/abigen/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/abigen/main.go index d19164b1..b6ec04ce 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/abigen/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/abigen/main.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify @@ -37,6 +37,9 @@ var ( solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested") excFlag = flag.String("exc", "", "Comma separated types to exclude from binding") + vyFlag = flag.String("vy", "", "Path to the Ethereum contract Vyper source to build and bind") + vyperFlag = flag.String("vyper", "vyper", "Vyper compiler to use if source builds are requested") + pkgFlag = flag.String("pkg", "", "Package name to generate the binding into") outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)") langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)") @@ -46,11 +49,14 @@ func main() { // Parse and ensure all needed inputs are specified flag.Parse() - if *abiFlag == "" && *solFlag == "" { - fmt.Printf("No contract ABI (--abi) or Solidity source (--sol) specified\n") + if *abiFlag == "" && *solFlag == "" && *vyFlag == "" { + fmt.Printf("No contract ABI (--abi), Solidity source (--sol), or Vyper source (--vy) specified\n") os.Exit(-1) - } else if (*abiFlag != "" || *binFlag != "" || *typFlag != "") && *solFlag != "" { - fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity source (--sol) flag\n") + } else if (*abiFlag != "" || *binFlag != "" || *typFlag != "") && (*solFlag != "" || *vyFlag != "") { + fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity (--sol) and Vyper (--vy) flags\n") + os.Exit(-1) + } else if *solFlag != "" && *vyFlag != "" { + fmt.Printf("Solidity (--sol) and Vyper (--vy) flags are mutually exclusive\n") os.Exit(-1) } if *pkgFlag == "" { @@ -75,7 +81,7 @@ func main() { bins []string types []string ) - if *solFlag != "" || (*abiFlag == "-" && *pkgFlag == "") { + if *solFlag != "" || *vyFlag != "" || (*abiFlag == "-" && *pkgFlag == "") { // Generate the list of types to exclude from binding exclude := make(map[string]bool) for _, kind := range strings.Split(*excFlag, ",") { @@ -84,13 +90,21 @@ func main() { var contracts map[string]*compiler.Contract var err error - if *solFlag != "" { + + switch { + case *solFlag != "": contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag) if err != nil { fmt.Printf("Failed to build Solidity contract: %v\n", err) os.Exit(-1) } - } else { + case *vyFlag != "": + contracts, err = compiler.CompileVyper(*vyperFlag, *vyFlag) + if err != nil { + fmt.Printf("Failed to build Vyper contract: %v\n", err) + os.Exit(-1) + } + default: contracts, err = contractsFromStdin() if err != nil { fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err) @@ -102,7 +116,11 @@ func main() { if exclude[strings.ToLower(name)] { continue } - abi, _ := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse + abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse + if err != nil { + fmt.Printf("Failed to parse ABIs from compiler output: %v\n", err) + os.Exit(-1) + } abis = append(abis, string(abi)) bins = append(bins, contract.Code) @@ -124,7 +142,7 @@ func main() { } abis = append(abis, string(abi)) - bin := []byte{} + var bin []byte if *binFlag != "" { if bin, err = ioutil.ReadFile(*binFlag); err != nil { fmt.Printf("Failed to read input bytecode: %v\n", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/bootnode/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/bootnode/main.go index 32f7d63b..a40b32b6 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/bootnode/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/bootnode/main.go @@ -112,12 +112,13 @@ func main() { if !realaddr.IP.IsLoopback() { go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") } - // TODO: react to external IP changes over time. if ext, err := natm.ExternalIP(); err == nil { realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port} } } + printNotice(&nodeKey.PublicKey, *realaddr) + if *runv5 { if _, err := discv5.ListenUDP(nodeKey, conn, "", restrictList); err != nil { utils.Fatalf("%v", err) @@ -136,3 +137,13 @@ func main() { select {} } + +func printNotice(nodeKey *ecdsa.PublicKey, addr net.UDPAddr) { + if addr.IP.IsUnspecified() { + addr.IP = net.IP{127, 0, 0, 1} + } + n := enode.NewV4(nodeKey, addr.IP, 0, addr.Port) + fmt.Println(n.String()) + fmt.Println("Note: you're using cmd/bootnode, a developer tool.") + fmt.Println("We recommend using a regular node as bootstrap node for production deployments.") +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/README.md b/vendor/github.com/ethereum/go-ethereum/cmd/clef/README.md index c9461be1..956957f3 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/clef/README.md +++ b/vendor/github.com/ethereum/go-ethereum/cmd/clef/README.md @@ -16,7 +16,8 @@ Check out * the [tutorial](tutorial.md) for some concrete examples on how the signer works. * the [setup docs](docs/setup.md) for some information on how to configure it to work on QubesOS or USBArmory. - +* the [data types](datatypes.md) for detailed information on the json types used in the communication between + clef and an external UI ## Command line flags Clef accepts the following command line options: @@ -24,28 +25,34 @@ Clef accepts the following command line options: COMMANDS: init Initialize the signer, generate secret storage attest Attest that a js-file is to be used - addpw Store a credential for a keystore file + setpw Store a credential for a keystore file + gendoc Generate documentation about json-rpc format help Shows a list of commands or help for one command - + GLOBAL OPTIONS: --loglevel value log level to emit to the screen (default: 4) --keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore") - --configdir value Directory for clef configuration (default: "$HOME/.clef") - --networkid value Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1) + --configdir value Directory for Clef configuration (default: "$HOME/.clef") + --chainid value Chain id to use for signing (1=mainnet, 3=ropsten, 4=rinkeby, 5=Goerli) (default: 1) --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength --nousb Disables monitoring for and managing USB hardware wallets --rpcaddr value HTTP-RPC server listening interface (default: "localhost") + --rpcvhosts value Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost") + --ipcdisable Disable the IPC-RPC server + --ipcpath Filename for IPC socket/pipe within the datadir (explicit paths escape it) + --rpc Enable the HTTP-RPC server --rpcport value HTTP-RPC server listening port (default: 8550) - --signersecret value A file containing the password used to encrypt signer credentials, e.g. keystore credentials and ruleset hash + --signersecret value A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash --4bytedb value File containing 4byte-identifiers (default: "./4byte.json") --4bytedb-custom value File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json") --auditlog value File used to emit audit logs. Set to "" to disable (default: "audit.log") --rules value Enable rule-engine (default: "rules.json") - --stdio-ui Use STDIN/STDOUT as a channel for an external UI. This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user interface, and can be used when the signer is started by an external process. - --stdio-ui-test Mechanism to test interface between signer and UI. Requires 'stdio-ui'. + --stdio-ui Use STDIN/STDOUT as a channel for an external UI. This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user interface, and can be used when Clef is started by an external process. + --stdio-ui-test Mechanism to test interface between Clef and UI. Requires 'stdio-ui'. + --advanced If enabled, issues warnings instead of rejections for suspicious requests. Default off --help, -h show help --version, -v print the version - + ``` @@ -189,7 +196,9 @@ None "method": "account_new", "params": [] } - +``` +Response +``` { "id": 0, "jsonrpc": "2.0", @@ -222,7 +231,9 @@ None "jsonrpc": "2.0", "method": "account_list" } - +``` +Response +``` { "id": 1, "jsonrpc": "2.0", @@ -285,8 +296,8 @@ Response ```json { + "id": 2, "jsonrpc": "2.0", - "id": 67, "error": { "code": -32000, "message": "Request denied" @@ -298,6 +309,7 @@ Response ```json { + "id": 67, "jsonrpc": "2.0", "method": "account_signTransaction", "params": [ @@ -311,8 +323,7 @@ Response "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012" }, "safeSend(address)" - ], - "id": 67 + ] } ``` Response @@ -346,15 +357,18 @@ Bash example: {"jsonrpc":"2.0","id":67,"result":{"raw":"0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","tx":{"nonce":"0x0","gasPrice":"0x1","gas":"0x333","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0","value":"0x0","input":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012","v":"0x26","r":"0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e","s":"0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","hash":"0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"}}} ``` - -### account_sign +### account_signData #### Sign data Signs a chunk of data and returns the calculated signature. #### Arguments + - content type [string]: type of signed data + - `text/validator`: hex data with custom validator defined in a contract + - `application/clique`: [clique](https://github.com/ethereum/EIPs/issues/225) headers + - `text/plain`: simple hex data validated by `account_ecRecover` - account [address]: account to sign with - - data [data]: data to sign + - data [object]: data to sign #### Result - calculated signature [data] @@ -364,8 +378,9 @@ Bash example: { "id": 3, "jsonrpc": "2.0", - "method": "account_sign", + "method": "account_signData", "params": [ + "data/plain", "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db", "0xaabbccdd" ] @@ -381,11 +396,109 @@ Response } ``` +### account_signTypedData + +#### Sign data + Signs a chunk of structured data conformant to [EIP712]([EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md)) and returns the calculated signature. + +#### Arguments + - account [address]: account to sign with + - data [object]: data to sign + +#### Result + - calculated signature [data] + +#### Sample call +```json +{ + "id": 68, + "jsonrpc": "2.0", + "method": "account_signTypedData", + "params": [ + "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826", + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } + ] +} +``` +Response + +```json +{ + "id": 1, + "jsonrpc": "2.0", + "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c" +} +``` + ### account_ecRecover -#### Recover address - Derive the address from the account that was used to sign data from the data and signature. - +#### Sign data + +Derive the address from the account that was used to sign data with content type `text/plain` and the signature. + #### Arguments - data [data]: data that was signed - signature [data]: the signature to verify @@ -400,6 +513,7 @@ Response "jsonrpc": "2.0", "method": "account_ecRecover", "params": [ + "data/plain", "0xaabbccdd", "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c" ] @@ -413,7 +527,6 @@ Response "jsonrpc": "2.0", "result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db" } - ``` ### account_import @@ -458,7 +571,7 @@ Response }, "id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9", "version": 3 - }, + } ] } ``` @@ -548,7 +661,7 @@ OBS! A slight deviation from `json` standard is in place: every request and resp Whereas the `json` specification allows for linebreaks, linebreaks __should not__ be used in this communication channel, to make things simpler for both parties. -### ApproveTx +### ApproveTx / `ui_approveTx` Invoked when there's a transaction for approval. @@ -560,13 +673,13 @@ Here's a method invocation: curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/ ``` - +Results in the following invocation on the UI: ```json { "jsonrpc": "2.0", "id": 1, - "method": "ApproveTx", + "method": "ui_approveTx", "params": [ { "transaction": { @@ -611,7 +724,7 @@ curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","me { "jsonrpc": "2.0", "id": 1, - "method": "ApproveTx", + "method": "ui_approveTx", "params": [ { "transaction": { @@ -654,7 +767,7 @@ One which has missing `to`, but with no `data`: { "jsonrpc": "2.0", "id": 3, - "method": "ApproveTx", + "method": "ui_approveTx", "params": [ { "transaction": { @@ -683,33 +796,7 @@ One which has missing `to`, but with no `data`: } ``` -### ApproveExport - -Invoked when a request to export an account has been made. - -#### Sample call - -```json - -{ - "jsonrpc": "2.0", - "id": 7, - "method": "ApproveExport", - "params": [ - { - "address": "0x0000000000000000000000000000000000000000", - "meta": { - "remote": "signer binary", - "local": "main", - "scheme": "in-proc" - } - } - ] -} - -``` - -### ApproveListing +### ApproveListing / `ui_approveListing` Invoked when a request for account listing has been made. @@ -720,7 +807,7 @@ Invoked when a request for account listing has been made. { "jsonrpc": "2.0", "id": 5, - "method": "ApproveListing", + "method": "ui_approveListing", "params": [ { "accounts": [ @@ -747,7 +834,7 @@ Invoked when a request for account listing has been made. ``` -### ApproveSignData +### ApproveSignData / `ui_approveSignData` #### Sample call @@ -755,7 +842,7 @@ Invoked when a request for account listing has been made. { "jsonrpc": "2.0", "id": 4, - "method": "ApproveSignData", + "method": "ui_approveSignData", "params": [ { "address": "0x123409812340981234098123409812deadbeef42", @@ -773,7 +860,7 @@ Invoked when a request for account listing has been made. ``` -### ShowInfo +### ShowInfo / `ui_showInfo` The UI should show the info to the user. Does not expect response. @@ -783,7 +870,7 @@ The UI should show the info to the user. Does not expect response. { "jsonrpc": "2.0", "id": 9, - "method": "ShowInfo", + "method": "ui_showInfo", "params": [ { "text": "Tests completed" @@ -793,7 +880,7 @@ The UI should show the info to the user. Does not expect response. ``` -### ShowError +### ShowError / `ui_showError` The UI should show the info to the user. Does not expect response. @@ -812,7 +899,7 @@ The UI should show the info to the user. Does not expect response. ``` -### OnApproved +### OnApprovedTx / `ui_onApprovedTx` `OnApprovedTx` is called when a transaction has been approved and signed. The call contains the return value that will be sent to the external caller. The return value from this method is ignored - the reason for having this callback is to allow the ruleset to keep track of approved transactions. @@ -820,7 +907,7 @@ When implementing rate-limited rules, this callback should be used. TLDR; Use this method to keep track of signed transactions, instead of using the data in `ApproveTx`. -### OnSignerStartup +### OnSignerStartup / `ui_onSignerStartup` This method provide the UI with information about what API version the signer uses (both internal and external) aswell as build-info and external api, in k/v-form. @@ -831,7 +918,7 @@ Example call: { "jsonrpc": "2.0", "id": 1, - "method": "OnSignerStartup", + "method": "ui_onSignerStartup", "params": [ { "info": { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/datatypes.md b/vendor/github.com/ethereum/go-ethereum/cmd/clef/datatypes.md new file mode 100644 index 00000000..a26c1c93 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/clef/datatypes.md @@ -0,0 +1,224 @@ +## UI Client interface + +These data types are defined in the channel between clef and the UI +### SignDataRequest + +SignDataRequest contains information about a pending request to sign some data. The data to be signed can be of various types, defined by content-type. Clef has done most of the work in canonicalizing and making sense of the data, and it's up to the UI to presentthe user with the contents of the `message` + +Example: +```json +{ + "content_type": "text/plain", + "address": "0xDEADbEeF000000000000000000000000DeaDbeEf", + "raw_data": "GUV0aGVyZXVtIFNpZ25lZCBNZXNzYWdlOgoxMWhlbGxvIHdvcmxk", + "message": [ + { + "name": "message", + "value": "\u0019Ethereum Signed Message:\n11hello world", + "type": "text/plain" + } + ], + "hash": "0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68", + "meta": { + "remote": "localhost:9999", + "local": "localhost:8545", + "scheme": "http", + "User-Agent": "Firefox 3.2", + "Origin": "www.malicious.ru" + } +} +``` +### SignDataResponse - approve + +Response to SignDataRequest + +Example: +```json +{ + "approved": true +} +``` +### SignDataResponse - deny + +Response to SignDataRequest + +Example: +```json +{ + "approved": false +} +``` +### SignTxRequest + +SignTxRequest contains information about a pending request to sign a transaction. Aside from the transaction itself, there is also a `call_info`-struct. That struct contains messages of various types, that the user should be informed of. + +As in any request, it's important to consider that the `meta` info also contains untrusted data. + +The `transaction` (on input into clef) can have either `data` or `input` -- if both are set, they must be identical, otherwise an error is generated. However, Clef will always use `data` when passing this struct on (if Clef does otherwise, please file a ticket) + +Example: +```json +{ + "transaction": { + "from": "0xDEADbEeF000000000000000000000000DeaDbeEf", + "to": null, + "gas": "0x3e8", + "gasPrice": "0x5", + "value": "0x6", + "nonce": "0x1", + "data": "0x01020304" + }, + "call_info": [ + { + "type": "Warning", + "message": "Something looks odd, show this message as a warning" + }, + { + "type": "Info", + "message": "User should see this aswell" + } + ], + "meta": { + "remote": "localhost:9999", + "local": "localhost:8545", + "scheme": "http", + "User-Agent": "Firefox 3.2", + "Origin": "www.malicious.ru" + } +} +``` +### SignTxResponse - approve + +Response to request to sign a transaction. This response needs to contain the `transaction`, because the UI is free to make modifications to the transaction. + +Example: +```json +{ + "transaction": { + "from": "0xDEADbEeF000000000000000000000000DeaDbeEf", + "to": null, + "gas": "0x3e8", + "gasPrice": "0x5", + "value": "0x6", + "nonce": "0x4", + "data": "0x04030201" + }, + "approved": true +} +``` +### SignTxResponse - deny + +Response to SignTxRequest. When denying a request, there's no need to provide the transaction in return + +Example: +```json +{ + "transaction": { + "from": "0x", + "to": null, + "gas": "0x0", + "gasPrice": "0x0", + "value": "0x0", + "nonce": "0x0", + "data": null + }, + "approved": false +} +``` +### OnApproved - SignTransactionResult + +SignTransactionResult is used in the call `clef` -> `OnApprovedTx(result)` + +This occurs _after_ successful completion of the entire signing procedure, but right before the signed transaction is passed to the external caller. This method (and data) can be used by the UI to signal to the user that the transaction was signed, but it is primarily useful for ruleset implementations. + +A ruleset that implements a rate limitation needs to know what transactions are sent out to the external interface. By hooking into this methods, the ruleset can maintain track of that count. + +**OBS:** Note that if an attacker can restore your `clef` data to a previous point in time (e.g through a backup), the attacker can reset such windows, even if he/she is unable to decrypt the content. + +The `OnApproved` method cannot be responded to, it's purely informative + +Example: +```json +{ + "raw": "0xf85d640101948a8eafb1cf62bfbeb1741769dae1a9dd47996192018026a0716bd90515acb1e68e5ac5867aa11a1e65399c3349d479f5fb698554ebc6f293a04e8a4ebfff434e971e0ef12c5bf3a881b06fd04fc3f8b8a7291fb67a26a1d4ed", + "tx": { + "nonce": "0x64", + "gasPrice": "0x1", + "gas": "0x1", + "to": "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192", + "value": "0x1", + "input": "0x", + "v": "0x26", + "r": "0x716bd90515acb1e68e5ac5867aa11a1e65399c3349d479f5fb698554ebc6f293", + "s": "0x4e8a4ebfff434e971e0ef12c5bf3a881b06fd04fc3f8b8a7291fb67a26a1d4ed", + "hash": "0x662f6d772692dd692f1b5e8baa77a9ff95bbd909362df3fc3d301aafebde5441" + } +} +``` +### UserInputRequest + +Sent when clef needs the user to provide data. If 'password' is true, the input field should be treated accordingly (echo-free) + +Example: +```json +{ + "prompt": "The question to ask the user", + "title": "The title here", + "isPassword": true +} +``` +### UserInputResponse + +Response to UserInputRequest + +Example: +```json +{ + "text": "The textual response from user" +} +``` +### ListRequest + +Sent when a request has been made to list addresses. The UI is provided with the full `account`s, including local directory names. Note: this information is not passed back to the external caller, who only sees the `address`es. + +Example: +```json +{ + "accounts": [ + { + "address": "0xdeadbeef000000000000000000000000deadbeef", + "url": "keystore:///path/to/keyfile/a" + }, + { + "address": "0x1111111122222222222233333333334444444444", + "url": "keystore:///path/to/keyfile/b" + } + ], + "meta": { + "remote": "localhost:9999", + "local": "localhost:8545", + "scheme": "http", + "User-Agent": "Firefox 3.2", + "Origin": "www.malicious.ru" + } +} +``` +### ListResponse + +Response to list request. The response contains a list of all addresses to show to the caller. Note: the UI is free to respond with any address the caller, regardless of whether it exists or not + +Example: +```json +{ + "accounts": [ + { + "address": "0x0000000000000000000000000000000000000000", + "url": ".. ignored .." + }, + { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "url": "" + } + ] +} +``` diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt1.png b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt1.png new file mode 100644 index 00000000..e40e532f Binary files /dev/null and b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt1.png differ diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt2.png b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt2.png new file mode 100644 index 00000000..f617d755 Binary files /dev/null and b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt2.png differ diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt3.png b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt3.png new file mode 100644 index 00000000..b9d69544 Binary files /dev/null and b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt3.png differ diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt4.png b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt4.png new file mode 100644 index 00000000..a6cb3b4d Binary files /dev/null and b/vendor/github.com/ethereum/go-ethereum/cmd/clef/docs/clef_architecture_pt4.png differ diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/extapi_changelog.md b/vendor/github.com/ethereum/go-ethereum/cmd/clef/extapi_changelog.md index 6c2c3e81..dc7e65c0 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/clef/extapi_changelog.md +++ b/vendor/github.com/ethereum/go-ethereum/cmd/clef/extapi_changelog.md @@ -1,5 +1,20 @@ ### Changelog for external API +### 6.0.0 + +* `New` was changed to deliver only an address, not the full `Account` data +* `Export` was moved from External API to the UI Server API + +#### 5.0.0 + +* The external `account_EcRecover`-method was reimplemented. +* The external method `account_sign(address, data)` was replaced with `account_signData(contentType, address, data)`. +The addition of `contentType` makes it possible to use the method for different types of objects, such as: + * signing data with an intended validator (not yet implemented) + * signing clique headers, + * signing plain personal messages, +* The external method `account_signTypedData` implements [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) and makes it possible to sign typed data. + #### 4.0.0 * The external `account_Ecrecover`-method was removed. diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/intapi_changelog.md b/vendor/github.com/ethereum/go-ethereum/cmd/clef/intapi_changelog.md index 92a39a26..b7d4937c 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/clef/intapi_changelog.md +++ b/vendor/github.com/ethereum/go-ethereum/cmd/clef/intapi_changelog.md @@ -1,5 +1,75 @@ ### Changelog for internal API (ui-api) +### 6.0.0 + +Removed `password` from responses to operations which require them. This is for two reasons, + +- Consistency between how rulesets operate and how manual processing works. A rule can `Approve` but require the actual password to be stored in the clef storage. +With this change, the same stored password can be used even if rulesets are not enabled, but storage is. +- It also removes the usability-shortcut that a UI might otherwise want to implement; remembering passwords. Since we now will not require the +password on every `Approve`, there's no need for the UI to cache it locally. + - In a future update, we'll likely add `clef_storePassword` to the internal API, so the user can store it via his UI (currently only CLI works). + +Affected datatypes: +- `SignTxResponse` +- `SignDataResponse` +- `NewAccountResponse` + +If `clef` requires a password, the `OnInputRequired` will be used to collect it. + + +### 5.0.0 + +Changed the namespace format to adhere to the legacy ethereum format: `name_methodName`. Changes: + +* `ApproveTx` -> `ui_approveTx` +* `ApproveSignData` -> `ui_approveSignData` +* `ApproveExport` -> `removed` +* `ApproveImport` -> `removed` +* `ApproveListing` -> `ui_approveListing` +* `ApproveNewAccount` -> `ui_approveNewAccount` +* `ShowError` -> `ui_showError` +* `ShowInfo` -> `ui_showInfo` +* `OnApprovedTx` -> `ui_onApprovedTx` +* `OnSignerStartup` -> `ui_onSignerStartup` +* `OnInputRequired` -> `ui_onInputRequired` + + +### 4.0.0 + +* Bidirectional communication implemented, so the UI can query `clef` via the stdin/stdout RPC channel. Methods implemented are: + - `clef_listWallets` + - `clef_listAccounts` + - `clef_listWallets` + - `clef_deriveAccount` + - `clef_importRawKey` + - `clef_openWallet` + - `clef_chainId` + - `clef_setChainId` + - `clef_export` + - `clef_import` + +* The type `Account` was modified (the json-field `type` was removed), to consist of + +```golang +type Account struct { + Address common.Address `json:"address"` // Ethereum account address derived from the key + URL URL `json:"url"` // Optional resource locator within a backend +} +``` + + +### 3.2.0 + +* Make `ShowError`, `OnApprovedTx`, `OnSignerStartup` be json-rpc [notifications](https://www.jsonrpc.org/specification#notification): + +> A Notification is a Request object without an "id" member. A Request object that is a Notification signifies the Client's lack of interest in the corresponding Response object, and as such no Response object needs to be returned to the client. The Server MUST NOT reply to a Notification, including those that are within a batch request. +> +> Notifications are not confirmable by definition, since they do not have a Response object to be returned. As such, the Client would not be aware of any errors (like e.g. "Invalid params","Internal error" +### 3.1.0 + +* Add `ContentType` `string` to `SignDataRequest` to accommodate the latest EIP-191 and EIP-712 implementations. + ### 3.0.0 * Make use of `OnInputRequired(info UserInputRequest)` for obtaining master password during startup diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/clef/main.go index 519d63b3..a9003124 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/clef/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/clef/main.go @@ -28,6 +28,7 @@ import ( "fmt" "io" "io/ioutil" + "math/big" "os" "os/signal" "os/user" @@ -35,13 +36,19 @@ import ( "runtime" "strings" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/console" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/signer/core" "github.com/ethereum/go-ethereum/signer/rules" @@ -49,12 +56,6 @@ import ( "gopkg.in/urfave/cli.v1" ) -// ExternalAPIVersion -- see extapi_changelog.md -const ExternalAPIVersion = "4.0.0" - -// InternalAPIVersion -- see intapi_changelog.md -const InternalAPIVersion = "3.0.0" - const legalWarning = ` WARNING! @@ -86,6 +87,11 @@ var ( Value: DefaultConfigDir(), Usage: "Directory for Clef configuration", } + chainIdFlag = cli.Int64Flag{ + Name: "chainid", + Value: params.MainnetChainConfig.ChainID.Int64(), + Usage: "Chain id to use for signing (1=mainnet, 3=ropsten, 4=rinkeby, 5=Goerli)", + } rpcPortFlag = cli.IntFlag{ Name: "rpcport", Usage: "HTTP-RPC server listening port", @@ -113,7 +119,7 @@ var ( ruleFlag = cli.StringFlag{ Name: "rules", Usage: "Enable rule-engine", - Value: "rules.json", + Value: "", } stdiouiFlag = cli.BoolFlag{ Name: "stdio-ui", @@ -168,10 +174,16 @@ Clef that the file is 'safe' to execute.`, signerSecretFlag, }, Description: ` - The setpw command stores a password for a given address (keyfile). If you enter a blank passphrase, it will +The setpw command stores a password for a given address (keyfile). If you enter a blank passphrase, it will remove any stored credential for that address (keyfile) -`, - } +`} + gendocCommand = cli.Command{ + Action: GenDoc, + Name: "gendoc", + Usage: "Generate documentation about json-rpc format", + Description: ` +The gendoc generates example structures of the json-rpc communication types. +`} ) func init() { @@ -181,7 +193,7 @@ func init() { logLevelFlag, keystoreFlag, configdirFlag, - utils.NetworkIdFlag, + chainIdFlag, utils.LightKDFFlag, utils.NoUSBFlag, utils.RPCListenAddrFlag, @@ -200,7 +212,7 @@ func init() { advancedMode, } app.Action = signer - app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand} + app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, gendocCommand} } func main() { @@ -341,7 +353,7 @@ func signer(c *cli.Context) error { return err } var ( - ui core.SignerUI + ui core.UIClientAPI ) if c.GlobalBool(stdiouiFlag.Name) { log.Info("Using stdin/stdout as UI-channel") @@ -359,17 +371,14 @@ func signer(c *cli.Context) error { log.Info("Loaded 4byte db", "signatures", db.Size(), "file", fourByteDb, "local", fourByteLocal) var ( - api core.ExternalAPI + api core.ExternalAPI + pwStorage storage.Storage = &storage.NoStorage{} ) configDir := c.GlobalString(configdirFlag.Name) if stretchedKey, err := readMasterKey(c, ui); err != nil { log.Info("No master seed provided, rules disabled", "error", err) } else { - - if err != nil { - utils.Fatalf(err.Error()) - } vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) // Generate domain specific keys @@ -378,41 +387,49 @@ func signer(c *cli.Context) error { confkey := crypto.Keccak256([]byte("config"), stretchedKey) // Initialize the encrypted storages - pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey) + pwStorage = storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey) jsStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "jsstorage.json"), jskey) configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confkey) //Do we have a rule-file? - ruleJS, err := ioutil.ReadFile(c.GlobalString(ruleFlag.Name)) - if err != nil { - log.Info("Could not load rulefile, rules not enabled", "file", "rulefile") - } else { - hasher := sha256.New() - hasher.Write(ruleJS) - shasum := hasher.Sum(nil) - storedShasum := configStorage.Get("ruleset_sha256") - if storedShasum != hex.EncodeToString(shasum) { - log.Info("Could not validate ruleset hash, rules not enabled", "got", hex.EncodeToString(shasum), "expected", storedShasum) + if ruleFile := c.GlobalString(ruleFlag.Name); ruleFile != "" { + ruleJS, err := ioutil.ReadFile(c.GlobalString(ruleFile)) + if err != nil { + log.Info("Could not load rulefile, rules not enabled", "file", "rulefile") } else { - // Initialize rules - ruleEngine, err := rules.NewRuleEvaluator(ui, jsStorage, pwStorage) - if err != nil { - utils.Fatalf(err.Error()) + shasum := sha256.Sum256(ruleJS) + foundShaSum := hex.EncodeToString(shasum[:]) + storedShasum := configStorage.Get("ruleset_sha256") + if storedShasum != foundShaSum { + log.Info("Could not validate ruleset hash, rules not enabled", "got", foundShaSum, "expected", storedShasum) + } else { + // Initialize rules + ruleEngine, err := rules.NewRuleEvaluator(ui, jsStorage) + if err != nil { + utils.Fatalf(err.Error()) + } + ruleEngine.Init(string(ruleJS)) + ui = ruleEngine + log.Info("Rule engine configured", "file", c.String(ruleFlag.Name)) } - ruleEngine.Init(string(ruleJS)) - ui = ruleEngine - log.Info("Rule engine configured", "file", c.String(ruleFlag.Name)) } } } + var ( + chainId = c.GlobalInt64(chainIdFlag.Name) + ksLoc = c.GlobalString(keystoreFlag.Name) + lightKdf = c.GlobalBool(utils.LightKDFFlag.Name) + advanced = c.GlobalBool(advancedMode.Name) + nousb = c.GlobalBool(utils.NoUSBFlag.Name) + ) + log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc, + "light-kdf", lightKdf, "advanced", advanced) + am := core.StartClefAccountManager(ksLoc, nousb, lightKdf) + apiImpl := core.NewSignerAPI(am, chainId, nousb, ui, db, advanced, pwStorage) - apiImpl := core.NewSignerAPI( - c.GlobalInt64(utils.NetworkIdFlag.Name), - c.GlobalString(keystoreFlag.Name), - c.GlobalBool(utils.NoUSBFlag.Name), - ui, db, - c.GlobalBool(utils.LightKDFFlag.Name), - c.GlobalBool(advancedMode.Name)) + // Establish the bidirectional communication, by creating a new UI backend and registering + // it with the UI. + ui.RegisterUIServer(core.NewUIServerAPI(apiImpl)) api = apiImpl // Audit logging if logfile := c.GlobalString(auditLogFlag.Name); logfile != "" { @@ -479,8 +496,8 @@ func signer(c *cli.Context) error { } ui.OnSignerStartup(core.StartupInfo{ Info: map[string]interface{}{ - "extapi_version": ExternalAPIVersion, - "intapi_version": InternalAPIVersion, + "extapi_version": core.ExternalAPIVersion, + "intapi_version": core.InternalAPIVersion, "extapi_http": extapiURL, "extapi_ipc": ipcapiURL, }, @@ -514,7 +531,12 @@ func DefaultConfigDir() string { if runtime.GOOS == "darwin" { return filepath.Join(home, "Library", "Signer") } else if runtime.GOOS == "windows" { - return filepath.Join(home, "AppData", "Roaming", "Signer") + appdata := os.Getenv("APPDATA") + if appdata != "" { + return filepath.Join(appdata, "Signer") + } else { + return filepath.Join(home, "AppData", "Roaming", "Signer") + } } else { return filepath.Join(home, ".clef") } @@ -532,7 +554,7 @@ func homeDir() string { } return "" } -func readMasterKey(ctx *cli.Context, ui core.SignerUI) ([]byte, error) { +func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) { var ( file string configDir = ctx.GlobalString(configdirFlag.Name) @@ -616,42 +638,123 @@ func testExternalUI(api *core.SignerAPI) { ctx := context.WithValue(context.Background(), "remote", "clef binary") ctx = context.WithValue(ctx, "scheme", "in-proc") ctx = context.WithValue(ctx, "local", "main") - errs := make([]string, 0) - api.UI.ShowInfo("Testing 'ShowInfo'") - api.UI.ShowError("Testing 'ShowError'") + a := common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef") - checkErr := func(method string, err error) { - if err != nil && err != core.ErrRequestDenied { - errs = append(errs, fmt.Sprintf("%v: %v", method, err.Error())) + queryUser := func(q string) string { + resp, err := api.UI.OnInputRequired(core.UserInputRequest{ + Title: "Testing", + Prompt: q, + }) + if err != nil { + errs = append(errs, err.Error()) + } + return resp.Text + } + expectResponse := func(testcase, question, expect string) { + if got := queryUser(question); got != expect { + errs = append(errs, fmt.Sprintf("%s: got %v, expected %v", testcase, got, expect)) } } - var err error - - _, err = api.SignTransaction(ctx, core.SendTxArgs{From: common.MixedcaseAddress{}}, nil) - checkErr("SignTransaction", err) - _, err = api.Sign(ctx, common.MixedcaseAddress{}, common.Hex2Bytes("01020304")) - checkErr("Sign", err) - _, err = api.List(ctx) - checkErr("List", err) - _, err = api.New(ctx) - checkErr("New", err) - _, err = api.Export(ctx, common.Address{}) - checkErr("Export", err) - _, err = api.Import(ctx, json.RawMessage{}) - checkErr("Import", err) - - api.UI.ShowInfo("Tests completed") - - if len(errs) > 0 { - log.Error("Got errors") - for _, e := range errs { - log.Error(e) + expectApprove := func(testcase string, err error) { + if err == nil || err == accounts.ErrUnknownAccount { + return } - } else { - log.Info("No errors") + errs = append(errs, fmt.Sprintf("%v: expected no error, got %v", testcase, err.Error())) } + expectDeny := func(testcase string, err error) { + if err == nil || err != core.ErrRequestDenied { + errs = append(errs, fmt.Sprintf("%v: expected ErrRequestDenied, got %v", testcase, err)) + } + } + + // Test display of info and error + { + api.UI.ShowInfo("If you see this message, enter 'yes' to next question") + expectResponse("showinfo", "Did you see the message? [yes/no]", "yes") + api.UI.ShowError("If you see this message, enter 'yes' to the next question") + expectResponse("showerror", "Did you see the message? [yes/no]", "yes") + } + { // Sign data test - clique header + api.UI.ShowInfo("Please approve the next request for signing a clique header") + cliqueHeader := types.Header{ + common.HexToHash("0000H45H"), + common.HexToHash("0000H45H"), + common.HexToAddress("0000H45H"), + common.HexToHash("0000H00H"), + common.HexToHash("0000H45H"), + common.HexToHash("0000H45H"), + types.Bloom{}, + big.NewInt(1337), + big.NewInt(1337), + 1338, + 1338, + big.NewInt(1338), + []byte("Extra data Extra data Extra data Extra data Extra data Extra data Extra data Extra data"), + common.HexToHash("0x0000H45H"), + types.BlockNonce{}, + } + cliqueRlp, err := rlp.EncodeToBytes(cliqueHeader) + if err != nil { + utils.Fatalf("Should not error: %v", err) + } + addr, _ := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") + _, err = api.SignData(ctx, accounts.MimetypeClique, *addr, hexutil.Encode(cliqueRlp)) + expectApprove("signdata - clique header", err) + } + { // Sign data test - plain text + api.UI.ShowInfo("Please approve the next request for signing text") + addr, _ := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") + _, err := api.SignData(ctx, accounts.MimetypeTextPlain, *addr, hexutil.Encode([]byte("hello world"))) + expectApprove("signdata - text", err) + } + { // Sign data test - plain text reject + api.UI.ShowInfo("Please deny the next request for signing text") + addr, _ := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") + _, err := api.SignData(ctx, accounts.MimetypeTextPlain, *addr, hexutil.Encode([]byte("hello world"))) + expectDeny("signdata - text", err) + } + { // Sign transaction + + api.UI.ShowInfo("Please reject next transaction") + data := hexutil.Bytes([]byte{}) + to := common.NewMixedcaseAddress(a) + tx := core.SendTxArgs{ + Data: &data, + Nonce: 0x1, + Value: hexutil.Big(*big.NewInt(6)), + From: common.NewMixedcaseAddress(a), + To: &to, + GasPrice: hexutil.Big(*big.NewInt(5)), + Gas: 1000, + Input: nil, + } + _, err := api.SignTransaction(ctx, tx, nil) + expectDeny("signtransaction [1]", err) + expectResponse("signtransaction [2]", "Did you see any warnings for the last transaction? (yes/no)", "no") + } + { // Listing + api.UI.ShowInfo("Please reject listing-request") + _, err := api.List(ctx) + expectDeny("list", err) + } + { // Import + api.UI.ShowInfo("Please reject new account-request") + _, err := api.New(ctx) + expectDeny("newaccount", err) + } + { // Metadata + api.UI.ShowInfo("Please check if you see the Origin in next listing (approve or deny)") + api.List(context.WithValue(ctx, "Origin", "origin.com")) + expectResponse("metadata - origin", "Did you see origin (origin.com)? [yes/no] ", "yes") + } + + for _, e := range errs { + log.Error(e) + } + result := fmt.Sprintf("Tests completed. %d errors:\n%s\n", len(errs), strings.Join(errs, "\n")) + api.UI.ShowInfo(result) } @@ -708,6 +811,154 @@ func decryptSeed(keyjson []byte, auth string) ([]byte, error) { return seed, err } +// GenDoc outputs examples of all structures used in json-rpc communication +func GenDoc(ctx *cli.Context) { + + var ( + a = common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef") + b = common.HexToAddress("0x1111111122222222222233333333334444444444") + meta = core.Metadata{ + Scheme: "http", + Local: "localhost:8545", + Origin: "www.malicious.ru", + Remote: "localhost:9999", + UserAgent: "Firefox 3.2", + } + output []string + add = func(name, desc string, v interface{}) { + if data, err := json.MarshalIndent(v, "", " "); err == nil { + output = append(output, fmt.Sprintf("### %s\n\n%s\n\nExample:\n```json\n%s\n```", name, desc, data)) + } else { + log.Error("Error generating output", err) + } + } + ) + + { // Sign plain text request + desc := "SignDataRequest contains information about a pending request to sign some data. " + + "The data to be signed can be of various types, defined by content-type. Clef has done most " + + "of the work in canonicalizing and making sense of the data, and it's up to the UI to present" + + "the user with the contents of the `message`" + sighash, msg := accounts.TextAndHash([]byte("hello world")) + message := []*core.NameValueType{{"message", msg, accounts.MimetypeTextPlain}} + + add("SignDataRequest", desc, &core.SignDataRequest{ + Address: common.NewMixedcaseAddress(a), + Meta: meta, + ContentType: accounts.MimetypeTextPlain, + Rawdata: []byte(msg), + Message: message, + Hash: sighash}) + } + { // Sign plain text response + add("SignDataResponse - approve", "Response to SignDataRequest", + &core.SignDataResponse{Approved: true}) + add("SignDataResponse - deny", "Response to SignDataRequest", + &core.SignDataResponse{}) + } + { // Sign transaction request + desc := "SignTxRequest contains information about a pending request to sign a transaction. " + + "Aside from the transaction itself, there is also a `call_info`-struct. That struct contains " + + "messages of various types, that the user should be informed of." + + "\n\n" + + "As in any request, it's important to consider that the `meta` info also contains untrusted data." + + "\n\n" + + "The `transaction` (on input into clef) can have either `data` or `input` -- if both are set, " + + "they must be identical, otherwise an error is generated. " + + "However, Clef will always use `data` when passing this struct on (if Clef does otherwise, please file a ticket)" + + data := hexutil.Bytes([]byte{0x01, 0x02, 0x03, 0x04}) + add("SignTxRequest", desc, &core.SignTxRequest{ + Meta: meta, + Callinfo: []core.ValidationInfo{ + {"Warning", "Something looks odd, show this message as a warning"}, + {"Info", "User should see this aswell"}, + }, + Transaction: core.SendTxArgs{ + Data: &data, + Nonce: 0x1, + Value: hexutil.Big(*big.NewInt(6)), + From: common.NewMixedcaseAddress(a), + To: nil, + GasPrice: hexutil.Big(*big.NewInt(5)), + Gas: 1000, + Input: nil, + }}) + } + { // Sign tx response + data := hexutil.Bytes([]byte{0x04, 0x03, 0x02, 0x01}) + add("SignTxResponse - approve", "Response to request to sign a transaction. This response needs to contain the `transaction`"+ + ", because the UI is free to make modifications to the transaction.", + &core.SignTxResponse{Approved: true, + Transaction: core.SendTxArgs{ + Data: &data, + Nonce: 0x4, + Value: hexutil.Big(*big.NewInt(6)), + From: common.NewMixedcaseAddress(a), + To: nil, + GasPrice: hexutil.Big(*big.NewInt(5)), + Gas: 1000, + Input: nil, + }}) + add("SignTxResponse - deny", "Response to SignTxRequest. When denying a request, there's no need to "+ + "provide the transaction in return", + &core.SignTxResponse{}) + } + { // WHen a signed tx is ready to go out + desc := "SignTransactionResult is used in the call `clef` -> `OnApprovedTx(result)`" + + "\n\n" + + "This occurs _after_ successful completion of the entire signing procedure, but right before the signed " + + "transaction is passed to the external caller. This method (and data) can be used by the UI to signal " + + "to the user that the transaction was signed, but it is primarily useful for ruleset implementations." + + "\n\n" + + "A ruleset that implements a rate limitation needs to know what transactions are sent out to the external " + + "interface. By hooking into this methods, the ruleset can maintain track of that count." + + "\n\n" + + "**OBS:** Note that if an attacker can restore your `clef` data to a previous point in time" + + " (e.g through a backup), the attacker can reset such windows, even if he/she is unable to decrypt the content. " + + "\n\n" + + "The `OnApproved` method cannot be responded to, it's purely informative" + + rlpdata := common.FromHex("0xf85d640101948a8eafb1cf62bfbeb1741769dae1a9dd47996192018026a0716bd90515acb1e68e5ac5867aa11a1e65399c3349d479f5fb698554ebc6f293a04e8a4ebfff434e971e0ef12c5bf3a881b06fd04fc3f8b8a7291fb67a26a1d4ed") + var tx types.Transaction + rlp.DecodeBytes(rlpdata, &tx) + add("OnApproved - SignTransactionResult", desc, ðapi.SignTransactionResult{Raw: rlpdata, Tx: &tx}) + + } + { // User input + add("UserInputRequest", "Sent when clef needs the user to provide data. If 'password' is true, the input field should be treated accordingly (echo-free)", + &core.UserInputRequest{IsPassword: true, Title: "The title here", Prompt: "The question to ask the user"}) + add("UserInputResponse", "Response to UserInputRequest", + &core.UserInputResponse{Text: "The textual response from user"}) + } + { // List request + add("ListRequest", "Sent when a request has been made to list addresses. The UI is provided with the "+ + "full `account`s, including local directory names. Note: this information is not passed back to the external caller, "+ + "who only sees the `address`es. ", + &core.ListRequest{ + Meta: meta, + Accounts: []accounts.Account{ + {a, accounts.URL{Scheme: "keystore", Path: "/path/to/keyfile/a"}}, + {b, accounts.URL{Scheme: "keystore", Path: "/path/to/keyfile/b"}}}, + }) + + add("ListResponse", "Response to list request. The response contains a list of all addresses to show to the caller. "+ + "Note: the UI is free to respond with any address the caller, regardless of whether it exists or not", + &core.ListResponse{ + Accounts: []accounts.Account{ + {common.HexToAddress("0xcowbeef000000cowbeef00000000000000000c0w"), accounts.URL{Path: ".. ignored .."}}, + {common.HexToAddress("0xffffffffffffffffffffffffffffffffffffffff"), accounts.URL{}}, + }}) + } + + fmt.Println(`## UI Client interface + +These data types are defined in the channel between clef and the UI`) + for _, elem := range output { + fmt.Println(elem) + } +} + /** //Create Account diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/clef/tests/testsigner.js b/vendor/github.com/ethereum/go-ethereum/cmd/clef/tests/testsigner.js new file mode 100644 index 00000000..86b2c453 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/clef/tests/testsigner.js @@ -0,0 +1,73 @@ +// This file is a test-utility for testing clef-functionality +// +// Start clef with +// +// build/bin/clef --4bytedb=./cmd/clef/4byte.json --rpc +// +// Start geth with +// +// build/bin/geth --nodiscover --maxpeers 0 --signer http://localhost:8550 console --preload=cmd/clef/tests/testsigner.js +// +// and in the console simply invoke +// +// > test() +// +// You can reload the file via `reload()` + +function reload(){ + loadScript("./cmd/clef/tests/testsigner.js"); +} + +function init(){ + if (typeof accts == 'undefined' || accts.length == 0){ + accts = eth.accounts + console.log("Got accounts ", accts); + } +} +init() +function testTx(){ + if( accts && accts.length > 0) { + var a = accts[0] + var txdata = eth.signTransaction({from: a, to: a, value: 1, nonce: 1, gas: 1, gasPrice: 1}) + var v = parseInt(txdata.tx.v) + console.log("V value: ", v) + if (v == 37 || v == 38){ + console.log("Mainnet 155-protected chainid was used") + } + if (v == 27 || v == 28){ + throw new Error("Mainnet chainid was used, but without replay protection!") + } + } +} +function testSignText(){ + if( accts && accts.length > 0){ + var a = accts[0] + var r = eth.sign(a, "0x68656c6c6f20776f726c64"); //hello world + console.log("signing response", r) + } +} +function testClique(){ + if( accts && accts.length > 0){ + var a = accts[0] + var r = debug.testSignCliqueBlock(a, 0); // Sign genesis + console.log("signing response", r) + if( a != r){ + throw new Error("Requested signing by "+a+ " but got sealer "+r) + } + } +} + +function test(){ + var tests = [ + testTx, + testSignText, + testClique, + ] + for( i in tests){ + try{ + tests[i]() + }catch(err){ + console.log(err) + } + } + } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/evm/internal/compiler/compiler.go b/vendor/github.com/ethereum/go-ethereum/cmd/evm/internal/compiler/compiler.go index 753ca622..54981b66 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/evm/internal/compiler/compiler.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/evm/internal/compiler/compiler.go @@ -25,7 +25,7 @@ import ( func Compile(fn string, src []byte, debug bool) (string, error) { compiler := asm.NewCompiler(debug) - compiler.Feed(asm.Lex(fn, src, debug)) + compiler.Feed(asm.Lex(src, debug)) bin, compileErrors := compiler.Compile() if len(compileErrors) > 0 { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go index a59cb1fb..ebac2047 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go @@ -110,6 +110,11 @@ var ( Name: "nostack", Usage: "disable stack output", } + EVMInterpreterFlag = cli.StringFlag{ + Name: "vm.evm", + Usage: "External EVM configuration (default = built-in interpreter)", + Value: "", + } ) func init() { @@ -133,6 +138,7 @@ func init() { ReceiverFlag, DisableMemoryFlag, DisableStackFlag, + EVMInterpreterFlag, } app.Commands = []cli.Command{ compileCommand, diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/evm/runner.go b/vendor/github.com/ethereum/go-ethereum/cmd/evm/runner.go index 962fc021..bc5d00cf 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/evm/runner.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/evm/runner.go @@ -31,10 +31,10 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" cli "gopkg.in/urfave/cli.v1" @@ -89,7 +89,7 @@ func runCmd(ctx *cli.Context) error { genesisConfig *core.Genesis ) if ctx.GlobalBool(MachineFlag.Name) { - tracer = NewJSONLogger(logconfig, os.Stdout) + tracer = vm.NewJSONLogger(logconfig, os.Stdout) } else if ctx.GlobalBool(DebugFlag.Name) { debugLogger = vm.NewStructLogger(logconfig) tracer = debugLogger @@ -99,12 +99,12 @@ func runCmd(ctx *cli.Context) error { if ctx.GlobalString(GenesisFlag.Name) != "" { gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) genesisConfig = gen - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() genesis := gen.ToBlock(db) statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) chainConfig = gen.Config } else { - statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) genesisConfig = new(core.Genesis) } if ctx.GlobalString(SenderFlag.Name) != "" { @@ -171,8 +171,9 @@ func runCmd(ctx *cli.Context) error { Coinbase: genesisConfig.Coinbase, BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ - Tracer: tracer, - Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + Tracer: tracer, + Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + EVMInterpreter: ctx.GlobalString(EVMInterpreterFlag.Name), }, } @@ -206,6 +207,7 @@ func runCmd(ctx *cli.Context) error { execTime := time.Since(tstart) if ctx.GlobalBool(DumpFlag.Name) { + statedb.Commit(true) statedb.IntermediateRoot(true) fmt.Println(string(statedb.Dump())) } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/evm/staterunner.go b/vendor/github.com/ethereum/go-ethereum/cmd/evm/staterunner.go index 06c9be38..b3c69d9b 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/evm/staterunner.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/evm/staterunner.go @@ -68,7 +68,7 @@ func stateTestCmd(ctx *cli.Context) error { ) switch { case ctx.GlobalBool(MachineFlag.Name): - tracer = NewJSONLogger(config, os.Stderr) + tracer = vm.NewJSONLogger(config, os.Stderr) case ctx.GlobalBool(DebugFlag.Name): debugger = vm.NewStructLogger(config) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/faucet/faucet.go b/vendor/github.com/ethereum/go-ethereum/cmd/faucet/faucet.go index 2ffe1227..5e4b77a6 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/faucet/faucet.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/faucet/faucet.go @@ -256,7 +256,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u } for _, boot := range enodes { old, err := enode.ParseV4(boot.String()) - if err != nil { + if err == nil { stack.Server().AddPeer(old) } } @@ -282,7 +282,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u // close terminates the Ethereum connection and tears down the faucet. func (f *faucet) close() error { - return f.stack.Stop() + return f.stack.Close() } // listenAndServe registers the HTTP handlers for the faucet and boots it up diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go index 562c7e0d..72aace1c 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go @@ -29,14 +29,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/trie" - "github.com/syndtr/goleveldb/leveldb/util" "gopkg.in/urfave/cli.v1" ) @@ -190,8 +188,10 @@ func initGenesis(ctx *cli.Context) error { } // Open an initialise both full and light databases stack := makeFullNode(ctx) + defer stack.Close() + for _, name := range []string{"chaindata", "lightchaindata"} { - chaindb, err := stack.OpenDatabase(name, 0, 0) + chaindb, err := stack.OpenDatabase(name, 0, 0, "") if err != nil { utils.Fatalf("Failed to open database: %v", err) } @@ -199,6 +199,7 @@ func initGenesis(ctx *cli.Context) error { if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } + chaindb.Close() log.Info("Successfully wrote genesis state", "database", name, "hash", hash) } return nil @@ -209,8 +210,10 @@ func importChain(ctx *cli.Context) error { utils.Fatalf("This command requires an argument.") } stack := makeFullNode(ctx) - chain, chainDb := utils.MakeChain(ctx, stack) - defer chainDb.Close() + defer stack.Close() + + chain, db := utils.MakeChain(ctx, stack) + defer db.Close() // Start periodically gathering memory profiles var peakMemAlloc, peakMemSys uint64 @@ -245,23 +248,18 @@ func importChain(ctx *cli.Context) error { fmt.Printf("Import done in %v.\n\n", time.Since(start)) // Output pre-compaction stats mostly to see the import trashing - db := chainDb.(*ethdb.LDBDatabase) - - stats, err := db.LDB().GetProperty("leveldb.stats") + stats, err := db.Stat("leveldb.stats") if err != nil { utils.Fatalf("Failed to read database stats: %v", err) } fmt.Println(stats) - ioStats, err := db.LDB().GetProperty("leveldb.iostats") + ioStats, err := db.Stat("leveldb.iostats") if err != nil { utils.Fatalf("Failed to read database iostats: %v", err) } fmt.Println(ioStats) - fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses()) - fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads()) - // Print the memory statistics used by the importing mem := new(runtime.MemStats) runtime.ReadMemStats(mem) @@ -278,23 +276,22 @@ func importChain(ctx *cli.Context) error { // Compact the entire database to more accurately measure disk io and print the stats start = time.Now() fmt.Println("Compacting entire database...") - if err = db.LDB().CompactRange(util.Range{}); err != nil { + if err = db.Compact(nil, nil); err != nil { utils.Fatalf("Compaction failed: %v", err) } fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - stats, err = db.LDB().GetProperty("leveldb.stats") + stats, err = db.Stat("leveldb.stats") if err != nil { utils.Fatalf("Failed to read database stats: %v", err) } fmt.Println(stats) - ioStats, err = db.LDB().GetProperty("leveldb.iostats") + ioStats, err = db.Stat("leveldb.iostats") if err != nil { utils.Fatalf("Failed to read database iostats: %v", err) } fmt.Println(ioStats) - return nil } @@ -303,6 +300,8 @@ func exportChain(ctx *cli.Context) error { utils.Fatalf("This command requires an argument.") } stack := makeFullNode(ctx) + defer stack.Close() + chain, _ := utils.MakeChain(ctx, stack) start := time.Now() @@ -336,10 +335,12 @@ func importPreimages(ctx *cli.Context) error { utils.Fatalf("This command requires an argument.") } stack := makeFullNode(ctx) - diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase) + defer stack.Close() + db := utils.MakeChainDatabase(ctx, stack) start := time.Now() - if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil { + + if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil { utils.Fatalf("Import error: %v\n", err) } fmt.Printf("Import done in %v\n", time.Since(start)) @@ -352,10 +353,12 @@ func exportPreimages(ctx *cli.Context) error { utils.Fatalf("This command requires an argument.") } stack := makeFullNode(ctx) - diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase) + defer stack.Close() + db := utils.MakeChainDatabase(ctx, stack) start := time.Now() - if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil { + + if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil { utils.Fatalf("Export error: %v\n", err) } fmt.Printf("Export done in %v\n", time.Since(start)) @@ -369,13 +372,14 @@ func copyDb(ctx *cli.Context) error { } // Initialize a new chain for the running node to sync into stack := makeFullNode(ctx) - chain, chainDb := utils.MakeChain(ctx, stack) + defer stack.Close() + chain, chainDb := utils.MakeChain(ctx, stack) syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode) dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil) // Create a source peer to satisfy downloader requests from - db, err := ethdb.NewLDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256) + db, err := rawdb.NewLevelDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256, "") if err != nil { return err } @@ -402,11 +406,10 @@ func copyDb(ctx *cli.Context) error { // Compact the entire database to remove any sync overhead start = time.Now() fmt.Println("Compacting entire database...") - if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil { + if err = db.Compact(nil, nil); err != nil { utils.Fatalf("Compaction failed: %v", err) } fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - return nil } @@ -441,6 +444,8 @@ func removeDB(ctx *cli.Context) error { func dump(ctx *cli.Context) error { stack := makeFullNode(ctx) + defer stack.Close() + chain, chainDb := utils.MakeChain(ctx, stack) for _, arg := range ctx.Args() { var block *types.Block diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/config.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/config.go index b0749d23..f316380c 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/config.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/config.go @@ -20,7 +20,7 @@ import ( "bufio" "errors" "fmt" - "io" + "math/big" "os" "reflect" "unicode" @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/dashboard" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/graphql" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" @@ -124,6 +125,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } // Apply flags. + utils.SetULC(ctx, &cfg.Eth) utils.SetNodeConfig(ctx, &cfg.Node) stack, err := node.New(&cfg.Node) if err != nil { @@ -152,7 +154,9 @@ func enableWhisper(ctx *cli.Context) bool { func makeFullNode(ctx *cli.Context) *node.Node { stack, cfg := makeConfigNode(ctx) - + if ctx.GlobalIsSet(utils.ConstantinopleOverrideFlag.Name) { + cfg.Eth.ConstantinopleOverride = new(big.Int).SetUint64(ctx.GlobalUint64(utils.ConstantinopleOverrideFlag.Name)) + } utils.RegisterEthService(stack, &cfg.Eth) if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { @@ -174,6 +178,13 @@ func makeFullNode(ctx *cli.Context) *node.Node { utils.RegisterShhService(stack, &cfg.Shh) } + // Configure GraphQL if required + if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) { + if err := graphql.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts); err != nil { + utils.Fatalf("Failed to register the Ethereum service: %v", err) + } + } + // Add the Ethereum Stats daemon if requested. if cfg.Ethstats.URL != "" { utils.RegisterEthStatsService(stack, cfg.Ethstats.URL) @@ -195,7 +206,17 @@ func dumpConfig(ctx *cli.Context) error { if err != nil { return err } - io.WriteString(os.Stdout, comment) - os.Stdout.Write(out) + + dump := os.Stdout + if ctx.NArg() > 0 { + dump, err = os.OpenFile(ctx.Args().Get(0), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer dump.Close() + } + dump.WriteString(comment) + dump.Write(out) + return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go index 2500a969..d4443b32 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go @@ -79,7 +79,7 @@ func localConsole(ctx *cli.Context) error { // Create and start the node based on the CLI flags node := makeFullNode(ctx) startNode(ctx, node) - defer node.Stop() + defer node.Close() // Attach to the newly started node and start the JavaScript console client, err := node.Attach() @@ -180,7 +180,7 @@ func ephemeralConsole(ctx *cli.Context) error { // Create and start the node based on the CLI flags node := makeFullNode(ctx) startNode(ctx, node) - defer node.Stop() + defer node.Close() // Attach to the newly started node and start the JavaScript console client, err := node.Attach() diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/dao_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/dao_test.go index 52983ff2..cb06038e 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/dao_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/dao_test.go @@ -25,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -121,7 +120,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc } // Retrieve the DAO config flag from the database path := filepath.Join(datadir, "geth", "chaindata") - db, err := ethdb.NewLDBDatabase(path, 0, 0) + db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "") if err != nil { t.Fatalf("test %d: failed to open test database: %v", test, err) } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go index 0288b338..83847fc5 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go @@ -31,14 +31,16 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" - "gopkg.in/urfave/cli.v1" + cli "gopkg.in/urfave/cli.v1" ) const ( @@ -60,6 +62,7 @@ var ( utils.BootnodesV5Flag, utils.DataDirFlag, utils.KeyStoreDirFlag, + utils.ExternalSignerFlag, utils.NoUSBFlag, utils.DashboardEnabledFlag, utils.DashboardAddrFlag, @@ -82,15 +85,23 @@ var ( utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, + utils.ULCModeConfigFlag, + utils.OnlyAnnounceModeFlag, + utils.ULCTrustedNodesFlag, + utils.ULCMinTrustedFractionFlag, utils.SyncModeFlag, + utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.LightServFlag, + utils.LightBandwidthInFlag, + utils.LightBandwidthOutFlag, utils.LightPeersFlag, utils.LightKDFFlag, + utils.WhitelistFlag, utils.CacheFlag, utils.CacheDatabaseFlag, + utils.CacheTrieFlag, utils.CacheGCFlag, - utils.TrieCacheGenFlag, utils.ListenPortFlag, utils.MaxPeersFlag, utils.MaxPendingPeersFlag, @@ -119,12 +130,13 @@ var ( utils.DeveloperPeriodFlag, utils.TestnetFlag, utils.RinkebyFlag, + utils.GoerliFlag, utils.VMEnableDebugFlag, utils.NetworkIdFlag, + utils.ConstantinopleOverrideFlag, utils.RPCCORSDomainFlag, utils.RPCVirtualHostsFlag, utils.EthStatsURLFlag, - utils.MetricsEnabledFlag, utils.FakePoWFlag, utils.NoCompactionFlag, utils.GpoBlocksFlag, @@ -138,6 +150,11 @@ var ( utils.RPCEnabledFlag, utils.RPCListenAddrFlag, utils.RPCPortFlag, + utils.GraphQLEnabledFlag, + utils.GraphQLListenAddrFlag, + utils.GraphQLPortFlag, + utils.GraphQLCORSDomainFlag, + utils.GraphQLVirtualHostsFlag, utils.RPCApiFlag, utils.WSEnabledFlag, utils.WSListenAddrFlag, @@ -156,12 +173,14 @@ var ( } metricsFlags = []cli.Flag{ + utils.MetricsEnabledFlag, + utils.MetricsEnabledExpensiveFlag, utils.MetricsEnableInfluxDBFlag, utils.MetricsInfluxDBEndpointFlag, utils.MetricsInfluxDBDatabaseFlag, utils.MetricsInfluxDBUsernameFlag, utils.MetricsInfluxDBPasswordFlag, - utils.MetricsInfluxDBHostTagFlag, + utils.MetricsInfluxDBTagsFlag, } ) @@ -169,7 +188,7 @@ func init() { // Initialize the CLI app and start Geth app.Action = geth app.HideVersion = true // we have a command to print the version - app.Copyright = "Copyright 2013-2018 The go-ethereum Authors" + app.Copyright = "Copyright 2013-2019 The go-ethereum Authors" app.Commands = []cli.Command{ // See chaincmd.go: initCommand, @@ -262,6 +281,7 @@ func geth(ctx *cli.Context) error { return fmt.Errorf("invalid command: %q", args[0]) } node := makeFullNode(ctx) + defer node.Close() startNode(ctx, node) node.Wait() return nil @@ -277,13 +297,14 @@ func startNode(ctx *cli.Context, stack *node.Node) { utils.StartNode(stack) // Unlock any account specifically requested - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - - passwords := utils.MakePasswordList(ctx) - unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") - for i, account := range unlocks { - if trimmed := strings.TrimSpace(account); trimmed != "" { - unlockAccount(ctx, ks, trimmed, i, passwords) + if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { + ks := keystores[0].(*keystore.KeyStore) + passwords := utils.MakePasswordList(ctx) + unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") + for i, account := range unlocks { + if trimmed := strings.TrimSpace(account); trimmed != "" { + unlockAccount(ctx, ks, trimmed, i, passwords) + } } } // Register wallet event handlers to open and auto-derive wallets @@ -327,6 +348,32 @@ func startNode(ctx *cli.Context, stack *node.Node) { } } }() + + // Spawn a standalone goroutine for status synchronization monitoring, + // close the node when synchronization is complete if user required. + if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) { + go func() { + sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) + defer sub.Unsubscribe() + for { + event := <-sub.Chan() + if event == nil { + continue + } + done, ok := event.Data.(downloader.DoneEvent) + if !ok { + continue + } + if timestamp := time.Unix(done.Latest.Time.Int64(), 0); time.Since(timestamp) < 10*time.Minute { + log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(), + "age", common.PrettyAge(timestamp)) + stack.Stop() + } + + } + }() + } + // Start auxiliary services if enabled if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { // Mining only makes sense if a full Ethereum node is running diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go index e4ba96a7..34e090e1 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/monitorcmd.go @@ -169,7 +169,7 @@ func retrieveMetrics(client *rpc.Client) (map[string]interface{}, error) { // resolveMetrics takes a list of input metric patterns, and resolves each to one // or more canonical metric names. func resolveMetrics(metrics map[string]interface{}, patterns []string) []string { - res := []string{} + var res []string for _, pattern := range patterns { res = append(res, resolveMetric(metrics, pattern, "")...) } @@ -179,7 +179,7 @@ func resolveMetrics(metrics map[string]interface{}, patterns []string) []string // resolveMetrics takes a single of input metric pattern, and resolves it to one // or more canonical metric names. func resolveMetric(metrics map[string]interface{}, pattern string, path string) []string { - results := []string{} + var results []string // If a nested metric was requested, recurse optionally branching (via comma) parts := strings.SplitN(pattern, "/", 2) @@ -215,7 +215,7 @@ func resolveMetric(metrics map[string]interface{}, pattern string, path string) // expandMetrics expands the entire tree of metrics into a flat list of paths. func expandMetrics(metrics map[string]interface{}, path string) []string { // Iterate over all fields and expand individually - list := []string{} + var list []string for name, metric := range metrics { switch metric := metric.(type) { case float64: diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/geth/usage.go b/vendor/github.com/ethereum/go-ethereum/cmd/geth/usage.go index 8b0491ce..8658a3fd 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/geth/usage.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/geth/usage.go @@ -26,14 +26,14 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/internal/debug" - "gopkg.in/urfave/cli.v1" + cli "gopkg.in/urfave/cli.v1" ) // AppHelpTemplate is the test template for the default, global app help topic. var AppHelpTemplate = `NAME: {{.App.Name}} - {{.App.Usage}} - Copyright 2013-2018 The go-ethereum Authors + Copyright 2013-2019 The go-ethereum Authors USAGE: {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} @@ -74,13 +74,18 @@ var AppHelpFlagGroups = []flagGroup{ utils.NetworkIdFlag, utils.TestnetFlag, utils.RinkebyFlag, + utils.GoerliFlag, utils.SyncModeFlag, + utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.EthStatsURLFlag, utils.IdentityFlag, utils.LightServFlag, + utils.LightBandwidthInFlag, + utils.LightBandwidthOutFlag, utils.LightPeersFlag, utils.LightKDFFlag, + utils.WhitelistFlag, }, }, { @@ -132,8 +137,8 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.CacheFlag, utils.CacheDatabaseFlag, + utils.CacheTrieFlag, utils.CacheGCFlag, - utils.TrieCacheGenFlag, }, }, { @@ -141,6 +146,7 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.UnlockedAccountFlag, utils.PasswordFileFlag, + utils.ExternalSignerFlag, }, }, { @@ -219,16 +225,8 @@ var AppHelpFlagGroups = []flagGroup{ }, debug.Flags...), }, { - Name: "METRICS AND STATS", - Flags: []cli.Flag{ - utils.MetricsEnabledFlag, - utils.MetricsEnableInfluxDBFlag, - utils.MetricsInfluxDBEndpointFlag, - utils.MetricsInfluxDBDatabaseFlag, - utils.MetricsInfluxDBUsernameFlag, - utils.MetricsInfluxDBPasswordFlag, - utils.MetricsInfluxDBHostTagFlag, - }, + Name: "METRICS AND STATS", + Flags: metricsFlags, }, { Name: "WHISPER (EXPERIMENTAL)", @@ -303,7 +301,7 @@ func init() { categorized[flag.String()] = struct{}{} } } - uncategorized := []cli.Flag{} + var uncategorized []cli.Flag for _, flag := range data.(*cli.App).Flags { if _, ok := categorized[flag.String()]; !ok { if strings.HasPrefix(flag.GetName(), "dashboard") { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis.go index 5f39a889..ae7675cd 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis.go @@ -20,35 +20,41 @@ import ( "encoding/binary" "errors" "math" + "math/big" + "strings" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + math2 "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/params" ) -// cppEthereumGenesisSpec represents the genesis specification format used by the +// alethGenesisSpec represents the genesis specification format used by the // C++ Ethereum implementation. -type cppEthereumGenesisSpec struct { +type alethGenesisSpec struct { SealEngine string `json:"sealEngine"` Params struct { - AccountStartNonce hexutil.Uint64 `json:"accountStartNonce"` - HomesteadForkBlock hexutil.Uint64 `json:"homesteadForkBlock"` - EIP150ForkBlock hexutil.Uint64 `json:"EIP150ForkBlock"` - EIP158ForkBlock hexutil.Uint64 `json:"EIP158ForkBlock"` - ByzantiumForkBlock hexutil.Uint64 `json:"byzantiumForkBlock"` - ConstantinopleForkBlock hexutil.Uint64 `json:"constantinopleForkBlock"` - NetworkID hexutil.Uint64 `json:"networkID"` - ChainID hexutil.Uint64 `json:"chainID"` - MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` - MinGasLimit hexutil.Uint64 `json:"minGasLimit"` - MaxGasLimit hexutil.Uint64 `json:"maxGasLimit"` - GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"` - MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` - DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` - DurationLimit *hexutil.Big `json:"durationLimit"` - BlockReward *hexutil.Big `json:"blockReward"` + AccountStartNonce math2.HexOrDecimal64 `json:"accountStartNonce"` + MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` + HomesteadForkBlock hexutil.Uint64 `json:"homesteadForkBlock"` + DaoHardforkBlock math2.HexOrDecimal64 `json:"daoHardforkBlock"` + EIP150ForkBlock hexutil.Uint64 `json:"EIP150ForkBlock"` + EIP158ForkBlock hexutil.Uint64 `json:"EIP158ForkBlock"` + ByzantiumForkBlock hexutil.Uint64 `json:"byzantiumForkBlock"` + ConstantinopleForkBlock hexutil.Uint64 `json:"constantinopleForkBlock"` + MinGasLimit hexutil.Uint64 `json:"minGasLimit"` + MaxGasLimit hexutil.Uint64 `json:"maxGasLimit"` + TieBreakingGas bool `json:"tieBreakingGas"` + GasLimitBoundDivisor math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"` + MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` + DifficultyBoundDivisor *math2.HexOrDecimal256 `json:"difficultyBoundDivisor"` + DurationLimit *math2.HexOrDecimal256 `json:"durationLimit"` + BlockReward *hexutil.Big `json:"blockReward"` + NetworkID hexutil.Uint64 `json:"networkID"` + ChainID hexutil.Uint64 `json:"chainID"` + AllowFutureBlocks bool `json:"allowFutureBlocks"` } `json:"params"` Genesis struct { @@ -62,57 +68,68 @@ type cppEthereumGenesisSpec struct { GasLimit hexutil.Uint64 `json:"gasLimit"` } `json:"genesis"` - Accounts map[common.Address]*cppEthereumGenesisSpecAccount `json:"accounts"` + Accounts map[common.UnprefixedAddress]*alethGenesisSpecAccount `json:"accounts"` } -// cppEthereumGenesisSpecAccount is the prefunded genesis account and/or precompiled +// alethGenesisSpecAccount is the prefunded genesis account and/or precompiled // contract definition. -type cppEthereumGenesisSpecAccount struct { - Balance *hexutil.Big `json:"balance"` - Nonce uint64 `json:"nonce,omitempty"` - Precompiled *cppEthereumGenesisSpecBuiltin `json:"precompiled,omitempty"` +type alethGenesisSpecAccount struct { + Balance *math2.HexOrDecimal256 `json:"balance"` + Nonce uint64 `json:"nonce,omitempty"` + Precompiled *alethGenesisSpecBuiltin `json:"precompiled,omitempty"` } -// cppEthereumGenesisSpecBuiltin is the precompiled contract definition. -type cppEthereumGenesisSpecBuiltin struct { - Name string `json:"name,omitempty"` - StartingBlock hexutil.Uint64 `json:"startingBlock,omitempty"` - Linear *cppEthereumGenesisSpecLinearPricing `json:"linear,omitempty"` +// alethGenesisSpecBuiltin is the precompiled contract definition. +type alethGenesisSpecBuiltin struct { + Name string `json:"name,omitempty"` + StartingBlock hexutil.Uint64 `json:"startingBlock,omitempty"` + Linear *alethGenesisSpecLinearPricing `json:"linear,omitempty"` } -type cppEthereumGenesisSpecLinearPricing struct { +type alethGenesisSpecLinearPricing struct { Base uint64 `json:"base"` Word uint64 `json:"word"` } -// newCppEthereumGenesisSpec converts a go-ethereum genesis block into a Parity specific +// newAlethGenesisSpec converts a go-ethereum genesis block into a Aleth-specific // chain specification format. -func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEthereumGenesisSpec, error) { - // Only ethash is currently supported between go-ethereum and cpp-ethereum +func newAlethGenesisSpec(network string, genesis *core.Genesis) (*alethGenesisSpec, error) { + // Only ethash is currently supported between go-ethereum and aleth if genesis.Config.Ethash == nil { return nil, errors.New("unsupported consensus engine") } - // Reconstruct the chain spec in Parity's format - spec := &cppEthereumGenesisSpec{ + // Reconstruct the chain spec in Aleth format + spec := &alethGenesisSpec{ SealEngine: "Ethash", } + // Some defaults spec.Params.AccountStartNonce = 0 + spec.Params.TieBreakingGas = false + spec.Params.AllowFutureBlocks = false + spec.Params.DaoHardforkBlock = 0 + spec.Params.HomesteadForkBlock = (hexutil.Uint64)(genesis.Config.HomesteadBlock.Uint64()) spec.Params.EIP150ForkBlock = (hexutil.Uint64)(genesis.Config.EIP150Block.Uint64()) spec.Params.EIP158ForkBlock = (hexutil.Uint64)(genesis.Config.EIP158Block.Uint64()) - spec.Params.ByzantiumForkBlock = (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()) - spec.Params.ConstantinopleForkBlock = (hexutil.Uint64)(math.MaxUint64) + + // Byzantium + if num := genesis.Config.ByzantiumBlock; num != nil { + spec.setByzantium(num) + } + // Constantinople + if num := genesis.Config.ConstantinopleBlock; num != nil { + spec.setConstantinople(num) + } spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) - spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) - spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxUint64) + spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxInt64) spec.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) - spec.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor) - spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor) - spec.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit) + spec.Params.DifficultyBoundDivisor = (*math2.HexOrDecimal256)(params.DifficultyBoundDivisor) + spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor) + spec.Params.DurationLimit = (*math2.HexOrDecimal256)(params.DurationLimit) spec.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward) spec.Genesis.Nonce = (hexutil.Bytes)(make([]byte, 8)) @@ -126,77 +143,109 @@ func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEther spec.Genesis.ExtraData = (hexutil.Bytes)(genesis.ExtraData) spec.Genesis.GasLimit = (hexutil.Uint64)(genesis.GasLimit) - spec.Accounts = make(map[common.Address]*cppEthereumGenesisSpecAccount) for address, account := range genesis.Alloc { - spec.Accounts[address] = &cppEthereumGenesisSpecAccount{ - Balance: (*hexutil.Big)(account.Balance), - Nonce: account.Nonce, - } - } - spec.Accounts[common.BytesToAddress([]byte{1})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "ecrecover", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 3000}, - } - spec.Accounts[common.BytesToAddress([]byte{2})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "sha256", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 60, Word: 12}, - } - spec.Accounts[common.BytesToAddress([]byte{3})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "ripemd160", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 600, Word: 120}, - } - spec.Accounts[common.BytesToAddress([]byte{4})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "identity", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 15, Word: 3}, + spec.setAccount(address, account) } + + spec.setPrecompile(1, &alethGenesisSpecBuiltin{Name: "ecrecover", + Linear: &alethGenesisSpecLinearPricing{Base: 3000}}) + spec.setPrecompile(2, &alethGenesisSpecBuiltin{Name: "sha256", + Linear: &alethGenesisSpecLinearPricing{Base: 60, Word: 12}}) + spec.setPrecompile(3, &alethGenesisSpecBuiltin{Name: "ripemd160", + Linear: &alethGenesisSpecLinearPricing{Base: 600, Word: 120}}) + spec.setPrecompile(4, &alethGenesisSpecBuiltin{Name: "identity", + Linear: &alethGenesisSpecLinearPricing{Base: 15, Word: 3}}) if genesis.Config.ByzantiumBlock != nil { - spec.Accounts[common.BytesToAddress([]byte{5})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "modexp", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), - } - spec.Accounts[common.BytesToAddress([]byte{6})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "alt_bn128_G1_add", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), Linear: &cppEthereumGenesisSpecLinearPricing{Base: 500}, - } - spec.Accounts[common.BytesToAddress([]byte{7})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "alt_bn128_G1_mul", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), Linear: &cppEthereumGenesisSpecLinearPricing{Base: 40000}, - } - spec.Accounts[common.BytesToAddress([]byte{8})].Precompiled = &cppEthereumGenesisSpecBuiltin{ - Name: "alt_bn128_pairing_product", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), - } + spec.setPrecompile(5, &alethGenesisSpecBuiltin{Name: "modexp", + StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())}) + spec.setPrecompile(6, &alethGenesisSpecBuiltin{Name: "alt_bn128_G1_add", + StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), + Linear: &alethGenesisSpecLinearPricing{Base: 500}}) + spec.setPrecompile(7, &alethGenesisSpecBuiltin{Name: "alt_bn128_G1_mul", + StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), + Linear: &alethGenesisSpecLinearPricing{Base: 40000}}) + spec.setPrecompile(8, &alethGenesisSpecBuiltin{Name: "alt_bn128_pairing_product", + StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())}) } return spec, nil } +func (spec *alethGenesisSpec) setPrecompile(address byte, data *alethGenesisSpecBuiltin) { + if spec.Accounts == nil { + spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount) + } + addr := common.UnprefixedAddress(common.BytesToAddress([]byte{address})) + if _, exist := spec.Accounts[addr]; !exist { + spec.Accounts[addr] = &alethGenesisSpecAccount{} + } + spec.Accounts[addr].Precompiled = data +} + +func (spec *alethGenesisSpec) setAccount(address common.Address, account core.GenesisAccount) { + if spec.Accounts == nil { + spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount) + } + + a, exist := spec.Accounts[common.UnprefixedAddress(address)] + if !exist { + a = &alethGenesisSpecAccount{} + spec.Accounts[common.UnprefixedAddress(address)] = a + } + a.Balance = (*math2.HexOrDecimal256)(account.Balance) + a.Nonce = account.Nonce + +} + +func (spec *alethGenesisSpec) setByzantium(num *big.Int) { + spec.Params.ByzantiumForkBlock = hexutil.Uint64(num.Uint64()) +} + +func (spec *alethGenesisSpec) setConstantinople(num *big.Int) { + spec.Params.ConstantinopleForkBlock = hexutil.Uint64(num.Uint64()) +} + // parityChainSpec is the chain specification format used by Parity. type parityChainSpec struct { - Name string `json:"name"` - Engine struct { + Name string `json:"name"` + Datadir string `json:"dataDir"` + Engine struct { Ethash struct { Params struct { - MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` - DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` - DurationLimit *hexutil.Big `json:"durationLimit"` - BlockReward *hexutil.Big `json:"blockReward"` - HomesteadTransition uint64 `json:"homesteadTransition"` - EIP150Transition uint64 `json:"eip150Transition"` - EIP160Transition uint64 `json:"eip160Transition"` - EIP161abcTransition uint64 `json:"eip161abcTransition"` - EIP161dTransition uint64 `json:"eip161dTransition"` - EIP649Reward *hexutil.Big `json:"eip649Reward"` - EIP100bTransition uint64 `json:"eip100bTransition"` - EIP649Transition uint64 `json:"eip649Transition"` + MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` + DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` + DurationLimit *hexutil.Big `json:"durationLimit"` + BlockReward map[string]string `json:"blockReward"` + DifficultyBombDelays map[string]string `json:"difficultyBombDelays"` + HomesteadTransition hexutil.Uint64 `json:"homesteadTransition"` + EIP100bTransition hexutil.Uint64 `json:"eip100bTransition"` } `json:"params"` } `json:"Ethash"` } `json:"engine"` Params struct { - MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` - MinGasLimit hexutil.Uint64 `json:"minGasLimit"` - GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"` - NetworkID hexutil.Uint64 `json:"networkID"` - MaxCodeSize uint64 `json:"maxCodeSize"` - EIP155Transition uint64 `json:"eip155Transition"` - EIP98Transition uint64 `json:"eip98Transition"` - EIP86Transition uint64 `json:"eip86Transition"` - EIP140Transition uint64 `json:"eip140Transition"` - EIP211Transition uint64 `json:"eip211Transition"` - EIP214Transition uint64 `json:"eip214Transition"` - EIP658Transition uint64 `json:"eip658Transition"` + AccountStartNonce hexutil.Uint64 `json:"accountStartNonce"` + MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` + MinGasLimit hexutil.Uint64 `json:"minGasLimit"` + GasLimitBoundDivisor math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"` + NetworkID hexutil.Uint64 `json:"networkID"` + ChainID hexutil.Uint64 `json:"chainID"` + MaxCodeSize hexutil.Uint64 `json:"maxCodeSize"` + MaxCodeSizeTransition hexutil.Uint64 `json:"maxCodeSizeTransition"` + EIP98Transition hexutil.Uint64 `json:"eip98Transition"` + EIP150Transition hexutil.Uint64 `json:"eip150Transition"` + EIP160Transition hexutil.Uint64 `json:"eip160Transition"` + EIP161abcTransition hexutil.Uint64 `json:"eip161abcTransition"` + EIP161dTransition hexutil.Uint64 `json:"eip161dTransition"` + EIP155Transition hexutil.Uint64 `json:"eip155Transition"` + EIP140Transition hexutil.Uint64 `json:"eip140Transition"` + EIP211Transition hexutil.Uint64 `json:"eip211Transition"` + EIP214Transition hexutil.Uint64 `json:"eip214Transition"` + EIP658Transition hexutil.Uint64 `json:"eip658Transition"` + EIP145Transition hexutil.Uint64 `json:"eip145Transition"` + EIP1014Transition hexutil.Uint64 `json:"eip1014Transition"` + EIP1052Transition hexutil.Uint64 `json:"eip1052Transition"` + EIP1283Transition hexutil.Uint64 `json:"eip1283Transition"` + EIP1283DisableTransition hexutil.Uint64 `json:"eip1283DisableTransition"` } `json:"params"` Genesis struct { @@ -215,22 +264,22 @@ type parityChainSpec struct { GasLimit hexutil.Uint64 `json:"gasLimit"` } `json:"genesis"` - Nodes []string `json:"nodes"` - Accounts map[common.Address]*parityChainSpecAccount `json:"accounts"` + Nodes []string `json:"nodes"` + Accounts map[common.UnprefixedAddress]*parityChainSpecAccount `json:"accounts"` } // parityChainSpecAccount is the prefunded genesis account and/or precompiled // contract definition. type parityChainSpecAccount struct { - Balance *hexutil.Big `json:"balance"` - Nonce uint64 `json:"nonce,omitempty"` + Balance math2.HexOrDecimal256 `json:"balance"` + Nonce math2.HexOrDecimal64 `json:"nonce,omitempty"` Builtin *parityChainSpecBuiltin `json:"builtin,omitempty"` } // parityChainSpecBuiltin is the precompiled contract definition. type parityChainSpecBuiltin struct { Name string `json:"name,omitempty"` - ActivateAt uint64 `json:"activate_at,omitempty"` + ActivateAt math2.HexOrDecimal64 `json:"activate_at,omitempty"` Pricing *parityChainSpecPricing `json:"pricing,omitempty"` } @@ -265,34 +314,56 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin } // Reconstruct the chain spec in Parity's format spec := &parityChainSpec{ - Name: network, - Nodes: bootnodes, + Name: network, + Nodes: bootnodes, + Datadir: strings.ToLower(network), } + spec.Engine.Ethash.Params.BlockReward = make(map[string]string) + spec.Engine.Ethash.Params.DifficultyBombDelays = make(map[string]string) + // Frontier spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor) spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit) - spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward) - spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64() - spec.Engine.Ethash.Params.EIP150Transition = genesis.Config.EIP150Block.Uint64() - spec.Engine.Ethash.Params.EIP160Transition = genesis.Config.EIP155Block.Uint64() - spec.Engine.Ethash.Params.EIP161abcTransition = genesis.Config.EIP158Block.Uint64() - spec.Engine.Ethash.Params.EIP161dTransition = genesis.Config.EIP158Block.Uint64() - spec.Engine.Ethash.Params.EIP649Reward = (*hexutil.Big)(ethash.ByzantiumBlockReward) - spec.Engine.Ethash.Params.EIP100bTransition = genesis.Config.ByzantiumBlock.Uint64() - spec.Engine.Ethash.Params.EIP649Transition = genesis.Config.ByzantiumBlock.Uint64() + spec.Engine.Ethash.Params.BlockReward["0x0"] = hexutil.EncodeBig(ethash.FrontierBlockReward) + + // Homestead + spec.Engine.Ethash.Params.HomesteadTransition = hexutil.Uint64(genesis.Config.HomesteadBlock.Uint64()) + + // Tangerine Whistle : 150 + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-608.md + spec.Params.EIP150Transition = hexutil.Uint64(genesis.Config.EIP150Block.Uint64()) + + // Spurious Dragon: 155, 160, 161, 170 + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-607.md + spec.Params.EIP155Transition = hexutil.Uint64(genesis.Config.EIP155Block.Uint64()) + spec.Params.EIP160Transition = hexutil.Uint64(genesis.Config.EIP155Block.Uint64()) + spec.Params.EIP161abcTransition = hexutil.Uint64(genesis.Config.EIP158Block.Uint64()) + spec.Params.EIP161dTransition = hexutil.Uint64(genesis.Config.EIP158Block.Uint64()) + + // Byzantium + if num := genesis.Config.ByzantiumBlock; num != nil { + spec.setByzantium(num) + } + // Constantinople + if num := genesis.Config.ConstantinopleBlock; num != nil { + spec.setConstantinople(num) + } + // ConstantinopleFix (remove eip-1283) + if num := genesis.Config.PetersburgBlock; num != nil { + spec.setConstantinopleFix(num) + } spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) - spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor) + spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor) spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) + spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) spec.Params.MaxCodeSize = params.MaxCodeSize - spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64() - spec.Params.EIP98Transition = math.MaxUint64 - spec.Params.EIP86Transition = math.MaxUint64 - spec.Params.EIP140Transition = genesis.Config.ByzantiumBlock.Uint64() - spec.Params.EIP211Transition = genesis.Config.ByzantiumBlock.Uint64() - spec.Params.EIP214Transition = genesis.Config.ByzantiumBlock.Uint64() - spec.Params.EIP658Transition = genesis.Config.ByzantiumBlock.Uint64() + // geth has it set from zero + spec.Params.MaxCodeSizeTransition = 0 + + // Disable this one + spec.Params.EIP98Transition = math.MaxInt64 spec.Genesis.Seal.Ethereum.Nonce = (hexutil.Bytes)(make([]byte, 8)) binary.LittleEndian.PutUint64(spec.Genesis.Seal.Ethereum.Nonce[:], genesis.Nonce) @@ -305,42 +376,81 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin spec.Genesis.ExtraData = (hexutil.Bytes)(genesis.ExtraData) spec.Genesis.GasLimit = (hexutil.Uint64)(genesis.GasLimit) - spec.Accounts = make(map[common.Address]*parityChainSpecAccount) + spec.Accounts = make(map[common.UnprefixedAddress]*parityChainSpecAccount) for address, account := range genesis.Alloc { - spec.Accounts[address] = &parityChainSpecAccount{ - Balance: (*hexutil.Big)(account.Balance), - Nonce: account.Nonce, + bal := math2.HexOrDecimal256(*account.Balance) + + spec.Accounts[common.UnprefixedAddress(address)] = &parityChainSpecAccount{ + Balance: bal, + Nonce: math2.HexOrDecimal64(account.Nonce), } } - spec.Accounts[common.BytesToAddress([]byte{1})].Builtin = &parityChainSpecBuiltin{ - Name: "ecrecover", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 3000}}, - } - spec.Accounts[common.BytesToAddress([]byte{2})].Builtin = &parityChainSpecBuiltin{ + spec.setPrecompile(1, &parityChainSpecBuiltin{Name: "ecrecover", + Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 3000}}}) + + spec.setPrecompile(2, &parityChainSpecBuiltin{ Name: "sha256", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 60, Word: 12}}, - } - spec.Accounts[common.BytesToAddress([]byte{3})].Builtin = &parityChainSpecBuiltin{ + }) + spec.setPrecompile(3, &parityChainSpecBuiltin{ Name: "ripemd160", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 600, Word: 120}}, - } - spec.Accounts[common.BytesToAddress([]byte{4})].Builtin = &parityChainSpecBuiltin{ + }) + spec.setPrecompile(4, &parityChainSpecBuiltin{ Name: "identity", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 15, Word: 3}}, - } + }) if genesis.Config.ByzantiumBlock != nil { - spec.Accounts[common.BytesToAddress([]byte{5})].Builtin = &parityChainSpecBuiltin{ - Name: "modexp", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{ModExp: &parityChainSpecModExpPricing{Divisor: 20}}, - } - spec.Accounts[common.BytesToAddress([]byte{6})].Builtin = &parityChainSpecBuiltin{ - Name: "alt_bn128_add", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 500}}, - } - spec.Accounts[common.BytesToAddress([]byte{7})].Builtin = &parityChainSpecBuiltin{ - Name: "alt_bn128_mul", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 40000}}, - } - spec.Accounts[common.BytesToAddress([]byte{8})].Builtin = &parityChainSpecBuiltin{ - Name: "alt_bn128_pairing", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{AltBnPairing: &parityChainSpecAltBnPairingPricing{Base: 100000, Pair: 80000}}, - } + blnum := math2.HexOrDecimal64(genesis.Config.ByzantiumBlock.Uint64()) + spec.setPrecompile(5, &parityChainSpecBuiltin{ + Name: "modexp", ActivateAt: blnum, Pricing: &parityChainSpecPricing{ModExp: &parityChainSpecModExpPricing{Divisor: 20}}, + }) + spec.setPrecompile(6, &parityChainSpecBuiltin{ + Name: "alt_bn128_add", ActivateAt: blnum, Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 500}}, + }) + spec.setPrecompile(7, &parityChainSpecBuiltin{ + Name: "alt_bn128_mul", ActivateAt: blnum, Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 40000}}, + }) + spec.setPrecompile(8, &parityChainSpecBuiltin{ + Name: "alt_bn128_pairing", ActivateAt: blnum, Pricing: &parityChainSpecPricing{AltBnPairing: &parityChainSpecAltBnPairingPricing{Base: 100000, Pair: 80000}}, + }) } return spec, nil } +func (spec *parityChainSpec) setPrecompile(address byte, data *parityChainSpecBuiltin) { + if spec.Accounts == nil { + spec.Accounts = make(map[common.UnprefixedAddress]*parityChainSpecAccount) + } + a := common.UnprefixedAddress(common.BytesToAddress([]byte{address})) + if _, exist := spec.Accounts[a]; !exist { + spec.Accounts[a] = &parityChainSpecAccount{} + } + spec.Accounts[a].Builtin = data +} + +func (spec *parityChainSpec) setByzantium(num *big.Int) { + spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ByzantiumBlockReward) + spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(3000000) + n := hexutil.Uint64(num.Uint64()) + spec.Engine.Ethash.Params.EIP100bTransition = n + spec.Params.EIP140Transition = n + spec.Params.EIP211Transition = n + spec.Params.EIP214Transition = n + spec.Params.EIP658Transition = n +} + +func (spec *parityChainSpec) setConstantinople(num *big.Int) { + spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ConstantinopleBlockReward) + spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(2000000) + n := hexutil.Uint64(num.Uint64()) + spec.Params.EIP145Transition = n + spec.Params.EIP1014Transition = n + spec.Params.EIP1052Transition = n + spec.Params.EIP1283Transition = n +} + +func (spec *parityChainSpec) setConstantinopleFix(num *big.Int) { + spec.Params.EIP1283DisableTransition = hexutil.Uint64(num.Uint64()) +} + // pyEthereumGenesisSpec represents the genesis specification format used by the // Python Ethereum implementation. type pyEthereumGenesisSpec struct { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis_test.go new file mode 100644 index 00000000..83e73836 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis_test.go @@ -0,0 +1,109 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "reflect" + "strings" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/ethereum/go-ethereum/core" +) + +// Tests the go-ethereum to Aleth chainspec conversion for the Stureby testnet. +func TestAlethSturebyConverter(t *testing.T) { + blob, err := ioutil.ReadFile("testdata/stureby_geth.json") + if err != nil { + t.Fatalf("could not read file: %v", err) + } + var genesis core.Genesis + if err := json.Unmarshal(blob, &genesis); err != nil { + t.Fatalf("failed parsing genesis: %v", err) + } + spec, err := newAlethGenesisSpec("stureby", &genesis) + if err != nil { + t.Fatalf("failed creating chainspec: %v", err) + } + + expBlob, err := ioutil.ReadFile("testdata/stureby_aleth.json") + if err != nil { + t.Fatalf("could not read file: %v", err) + } + expspec := &alethGenesisSpec{} + if err := json.Unmarshal(expBlob, expspec); err != nil { + t.Fatalf("failed parsing genesis: %v", err) + } + if !reflect.DeepEqual(expspec, spec) { + t.Errorf("chainspec mismatch") + c := spew.ConfigState{ + DisablePointerAddresses: true, + SortKeys: true, + } + exp := strings.Split(c.Sdump(expspec), "\n") + got := strings.Split(c.Sdump(spec), "\n") + for i := 0; i < len(exp) && i < len(got); i++ { + if exp[i] != got[i] { + fmt.Printf("got: %v\nexp: %v\n", exp[i], got[i]) + } + } + } +} + +// Tests the go-ethereum to Parity chainspec conversion for the Stureby testnet. +func TestParitySturebyConverter(t *testing.T) { + blob, err := ioutil.ReadFile("testdata/stureby_geth.json") + if err != nil { + t.Fatalf("could not read file: %v", err) + } + var genesis core.Genesis + if err := json.Unmarshal(blob, &genesis); err != nil { + t.Fatalf("failed parsing genesis: %v", err) + } + spec, err := newParityChainSpec("Stureby", &genesis, []string{}) + if err != nil { + t.Fatalf("failed creating chainspec: %v", err) + } + + expBlob, err := ioutil.ReadFile("testdata/stureby_parity.json") + if err != nil { + t.Fatalf("could not read file: %v", err) + } + expspec := &parityChainSpec{} + if err := json.Unmarshal(expBlob, expspec); err != nil { + t.Fatalf("failed parsing genesis: %v", err) + } + expspec.Nodes = []string{} + + if !reflect.DeepEqual(expspec, spec) { + t.Errorf("chainspec mismatch") + c := spew.ConfigState{ + DisablePointerAddresses: true, + SortKeys: true, + } + exp := strings.Split(c.Sdump(expspec), "\n") + got := strings.Split(c.Sdump(spec), "\n") + for i := 0; i < len(exp) && i < len(got); i++ { + if exp[i] != got[i] { + fmt.Printf("got: %v\nexp: %v\n", exp[i], got[i]) + } + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_dashboard.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_dashboard.go index d22bd811..9a77587b 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_dashboard.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_dashboard.go @@ -608,30 +608,31 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da bootPython[i] = "'" + boot + "'" } template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{ - "Network": network, - "NetworkID": conf.Genesis.Config.ChainID, - "NetworkTitle": strings.Title(network), - "EthstatsPage": config.ethstats, - "ExplorerPage": config.explorer, - "WalletPage": config.wallet, - "FaucetPage": config.faucet, - "GethGenesis": network + ".json", - "Bootnodes": conf.bootnodes, - "BootnodesFlat": strings.Join(conf.bootnodes, ","), - "Ethstats": statsLogin, - "Ethash": conf.Genesis.Config.Ethash != nil, - "CppGenesis": network + "-cpp.json", - "CppBootnodes": strings.Join(bootCpp, " "), - "HarmonyGenesis": network + "-harmony.json", - "HarmonyBootnodes": strings.Join(bootHarmony, " "), - "ParityGenesis": network + "-parity.json", - "PythonGenesis": network + "-python.json", - "PythonBootnodes": strings.Join(bootPython, ","), - "Homestead": conf.Genesis.Config.HomesteadBlock, - "Tangerine": conf.Genesis.Config.EIP150Block, - "Spurious": conf.Genesis.Config.EIP155Block, - "Byzantium": conf.Genesis.Config.ByzantiumBlock, - "Constantinople": conf.Genesis.Config.ConstantinopleBlock, + "Network": network, + "NetworkID": conf.Genesis.Config.ChainID, + "NetworkTitle": strings.Title(network), + "EthstatsPage": config.ethstats, + "ExplorerPage": config.explorer, + "WalletPage": config.wallet, + "FaucetPage": config.faucet, + "GethGenesis": network + ".json", + "Bootnodes": conf.bootnodes, + "BootnodesFlat": strings.Join(conf.bootnodes, ","), + "Ethstats": statsLogin, + "Ethash": conf.Genesis.Config.Ethash != nil, + "CppGenesis": network + "-cpp.json", + "CppBootnodes": strings.Join(bootCpp, " "), + "HarmonyGenesis": network + "-harmony.json", + "HarmonyBootnodes": strings.Join(bootHarmony, " "), + "ParityGenesis": network + "-parity.json", + "PythonGenesis": network + "-python.json", + "PythonBootnodes": strings.Join(bootPython, ","), + "Homestead": conf.Genesis.Config.HomesteadBlock, + "Tangerine": conf.Genesis.Config.EIP150Block, + "Spurious": conf.Genesis.Config.EIP155Block, + "Byzantium": conf.Genesis.Config.ByzantiumBlock, + "Constantinople": conf.Genesis.Config.ConstantinopleBlock, + "ConstantinopleFix": conf.Genesis.Config.PetersburgBlock, }) files[filepath.Join(workdir, "index.html")] = indexfile.Bytes() @@ -640,7 +641,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da files[filepath.Join(workdir, network+".json")] = genesis if conf.Genesis.Config.Ethash != nil { - cppSpec, err := newCppEthereumGenesisSpec(network, conf.Genesis) + cppSpec, err := newAlethGenesisSpec(network, conf.Genesis) if err != nil { return nil, err } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_ethstats.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_ethstats.go index a7d99a29..58ecb839 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_ethstats.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_ethstats.go @@ -43,7 +43,8 @@ version: '2' services: ethstats: build: . - image: {{.Network}}/ethstats{{if not .VHost}} + image: {{.Network}}/ethstats + container_name: {{.Network}}_ethstats_1{{if not .VHost}} ports: - "{{.Port}}:3000"{{end}} environment: diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_explorer.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_explorer.go index e916deaf..e465fa04 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_explorer.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_explorer.go @@ -77,6 +77,7 @@ services: explorer: build: . image: {{.Network}}/explorer + container_name: {{.Network}}_explorer_1 ports: - "{{.NodePort}}:{{.NodePort}}" - "{{.NodePort}}:{{.NodePort}}/udp"{{if not .VHost}} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_faucet.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_faucet.go index 06c9fc0f..3a06bf3c 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_faucet.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_faucet.go @@ -56,8 +56,10 @@ services: faucet: build: . image: {{.Network}}/faucet + container_name: {{.Network}}_faucet_1 ports: - - "{{.EthPort}}:{{.EthPort}}"{{if not .VHost}} + - "{{.EthPort}}:{{.EthPort}}" + - "{{.EthPort}}:{{.EthPort}}/udp"{{if not .VHost}} - "{{.ApiPort}}:8080"{{end}} volumes: - {{.Datadir}}:/root/.faucet diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_nginx.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_nginx.go index 7f87661d..1b1ae61f 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_nginx.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_nginx.go @@ -40,6 +40,7 @@ services: nginx: build: . image: {{.Network}}/nginx + container_name: {{.Network}}_nginx_1 ports: - "{{.Port}}:80" volumes: diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_node.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_node.go index 069adfe4..5d9ef465 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_node.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_node.go @@ -55,6 +55,7 @@ services: {{.Type}}: build: . image: {{.Network}}/{{.Type}} + container_name: {{.Network}}_{{.Type}}_1 ports: - "{{.Port}}:{{.Port}}" - "{{.Port}}:{{.Port}}/udp" diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_wallet.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_wallet.go index 90812c4a..ebaa5b6a 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_wallet.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_wallet.go @@ -57,6 +57,7 @@ services: wallet: build: . image: {{.Network}}/wallet + container_name: {{.Network}}_wallet_1 ports: - "{{.NodePort}}:{{.NodePort}}" - "{{.NodePort}}:{{.NodePort}}/udp" diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/puppeth.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/puppeth.go index f9b8fe48..c3de5f93 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/puppeth.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/puppeth.go @@ -43,18 +43,23 @@ func main() { Usage: "log level to emit to the screen", }, } - app.Action = func(c *cli.Context) error { + app.Before = func(c *cli.Context) error { // Set up the logger to print everything and the random generator log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) rand.Seed(time.Now().UnixNano()) - network := c.String("network") - if strings.Contains(network, " ") || strings.Contains(network, "-") { - log.Crit("No spaces or hyphens allowed in network name") - } - // Start the wizard and relinquish control - makeWizard(c.String("network")).run() return nil } + app.Action = runWizard app.Run(os.Args) } + +// runWizard start the wizard and relinquish control to it. +func runWizard(c *cli.Context) error { + network := c.String("network") + if strings.Contains(network, " ") || strings.Contains(network, "-") || strings.ToLower(network) != network { + log.Crit("No spaces, hyphens or capital letters allowed in network name") + } + makeWizard(c.String("network")).run() + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_aleth.json b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_aleth.json new file mode 100644 index 00000000..1ef1d8ae --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_aleth.json @@ -0,0 +1,112 @@ +{ + "sealEngine":"Ethash", + "params":{ + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "homesteadForkBlock":"0x2710", + "daoHardforkBlock":"0x00", + "EIP150ForkBlock":"0x3a98", + "EIP158ForkBlock":"0x59d8", + "byzantiumForkBlock":"0x7530", + "constantinopleForkBlock":"0x9c40", + "minGasLimit":"0x1388", + "maxGasLimit":"0x7fffffffffffffff", + "tieBreakingGas":false, + "gasLimitBoundDivisor":"0x0400", + "minimumDifficulty":"0x20000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "blockReward":"0x4563918244F40000", + "networkID":"0x4cb2e", + "chainID":"0x4cb2e", + "allowFutureBlocks":false + }, + "genesis":{ + "nonce":"0x0000000000000000", + "difficulty":"0x20000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x59a4e76d", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"0x0000000000000000000000000000000000000000000000000000000b4dc0ffee", + "gasLimit":"0x47b760" + }, + "accounts":{ + "0000000000000000000000000000000000000001":{ + "balance":"1", + "precompiled":{ + "name":"ecrecover", + "linear":{ + "base":3000, + "word":0 + } + } + }, + "0000000000000000000000000000000000000002":{ + "balance":"1", + "precompiled":{ + "name":"sha256", + "linear":{ + "base":60, + "word":12 + } + } + }, + "0000000000000000000000000000000000000003":{ + "balance":"1", + "precompiled":{ + "name":"ripemd160", + "linear":{ + "base":600, + "word":120 + } + } + }, + "0000000000000000000000000000000000000004":{ + "balance":"1", + "precompiled":{ + "name":"identity", + "linear":{ + "base":15, + "word":3 + } + } + }, + "0000000000000000000000000000000000000005":{ + "balance":"1", + "precompiled":{ + "name":"modexp", + "startingBlock":"0x7530" + } + }, + "0000000000000000000000000000000000000006":{ + "balance":"1", + "precompiled":{ + "name":"alt_bn128_G1_add", + "startingBlock":"0x7530", + "linear":{ + "base":500, + "word":0 + } + } + }, + "0000000000000000000000000000000000000007":{ + "balance":"1", + "precompiled":{ + "name":"alt_bn128_G1_mul", + "startingBlock":"0x7530", + "linear":{ + "base":40000, + "word":0 + } + } + }, + "0000000000000000000000000000000000000008":{ + "balance":"1", + "precompiled":{ + "name":"alt_bn128_pairing_product", + "startingBlock":"0x7530" + } + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_geth.json b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_geth.json new file mode 100644 index 00000000..c8c3b3c9 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_geth.json @@ -0,0 +1,47 @@ +{ + "config": { + "ethash":{}, + "chainId": 314158, + "homesteadBlock": 10000, + "eip150Block": 15000, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 23000, + "eip158Block": 23000, + "byzantiumBlock": 30000, + "constantinopleBlock": 40000 + }, + "nonce": "0x0", + "timestamp": "0x59a4e76d", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x0000000000000000000000000000000000000000000000000000000b4dc0ffee", + "gasLimit": "0x47b760", + "difficulty": "0x20000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000001": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000002": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000003": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000004": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000005": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000006": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000007": { + "balance": "0x01" + }, + "0000000000000000000000000000000000000008": { + "balance": "0x01" + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_parity.json b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_parity.json new file mode 100644 index 00000000..f3fa8386 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/testdata/stureby_parity.json @@ -0,0 +1,181 @@ +{ + "name":"Stureby", + "dataDir":"stureby", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x20000", + "difficultyBoundDivisor":"0x800", + "durationLimit":"0xd", + "blockReward":{ + "0x0":"0x4563918244f40000", + "0x7530":"0x29a2241af62c0000", + "0x9c40":"0x1bc16d674ec80000" + }, + "homesteadTransition":"0x2710", + "eip100bTransition":"0x7530", + "difficultyBombDelays":{ + "0x7530":"0x2dc6c0", + "0x9c40":"0x1e8480" + } + } + } + }, + "params":{ + "accountStartNonce":"0x0", + "maximumExtraDataSize":"0x20", + "gasLimitBoundDivisor":"0x400", + "minGasLimit":"0x1388", + "networkID":"0x4cb2e", + "chainID":"0x4cb2e", + "maxCodeSize":"0x6000", + "maxCodeSizeTransition":"0x0", + "eip98Transition": "0x7fffffffffffffff", + "eip150Transition":"0x3a98", + "eip160Transition":"0x59d8", + "eip161abcTransition":"0x59d8", + "eip161dTransition":"0x59d8", + "eip155Transition":"0x59d8", + "eip140Transition":"0x7530", + "eip211Transition":"0x7530", + "eip214Transition":"0x7530", + "eip658Transition":"0x7530", + "eip145Transition":"0x9c40", + "eip1014Transition":"0x9c40", + "eip1052Transition":"0x9c40", + "eip1283Transition":"0x9c40" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x0000000000000000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty":"0x20000", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x59a4e76d", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"0x0000000000000000000000000000000000000000000000000000000b4dc0ffee", + "gasLimit":"0x47b760" + }, + "nodes":[ + "enode://dfa7aca3f5b635fbfe7d0b20575f25e40d9e27b4bfbb3cf74364a42023ad9f25c1a4383bcc8cced86ee511a7d03415345a4df05be37f1dff040e4c780699f1c0@168.61.153.255:31303", + "enode://ef441b20dd70aeabf0eac35c3b8a2854e5ce04db0e30be9152ea9fd129359dcbb3f803993303ff5781c755dfd7223f3fe43505f583cccb740949407677412ba9@40.74.91.252:31303", + "enode://953b5ea1c8987cf46008232a0160324fd00d41320ecf00e23af86ec8f5396b19eb57ddab37c78141be56f62e9077de4f4dfa0747fa768ed8c8531bbfb1046237@40.70.214.166:31303", + "enode://276e613dd4b277a66591e565711e6c8bb107f0905248a9f8f8228c1a87992e156e5114bb9937c02824a9d9d25f76340442cf86e2028bf5293cae19904fb2b98e@35.178.251.52:30303", + "enode://064c820d41e52ed7d426ac64b60506c2998235bedc7e67cb497c6faf7bb4fc54fe56fc82d0add3180b747c0c4f40a1108a6f84d7d0629ed606d504528e61cc57@3.8.5.3:30303", + "enode://90069fdabcc5e684fa5d59430bebbb12755d9362dfe5006a1485b13d71a78a3812d36e74dd7d88e50b51add01e097ea80f16263aeaa4f0230db6c79e2a97e7ca@217.29.191.142:30303", + "enode://0aac74b7fd28726275e466acb5e03bc88a95927e9951eb66b5efb239b2f798ada0690853b2f2823fe4efa408f0f3d4dd258430bc952a5ff70677b8625b3e3b14@40.115.33.57:40404", + "enode://0b96415a10f835106d83e090a0528eed5e7887e5c802a6d084e9f1993a9d0fc713781e6e4101f6365e9b91259712f291acc0a9e6e667e22023050d602c36fbe2@40.115.33.57:40414" + ], + "accounts":{ + "0000000000000000000000000000000000000001":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"ecrecover", + "pricing":{ + "linear":{ + "base":3000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000002":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"sha256", + "pricing":{ + "linear":{ + "base":60, + "word":12 + } + } + } + }, + "0000000000000000000000000000000000000003":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"ripemd160", + "pricing":{ + "linear":{ + "base":600, + "word":120 + } + } + } + }, + "0000000000000000000000000000000000000004":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"identity", + "pricing":{ + "linear":{ + "base":15, + "word":3 + } + } + } + }, + "0000000000000000000000000000000000000005":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"modexp", + "activate_at":"0x7530", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x7530", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x7530", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "balance":"1", + "nonce":"0", + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x7530", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard.go index b88a61de..83536506 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard.go @@ -23,6 +23,7 @@ import ( "io/ioutil" "math/big" "net" + "net/url" "os" "path/filepath" "sort" @@ -118,6 +119,47 @@ func (w *wizard) readDefaultString(def string) string { return def } +// readDefaultYesNo reads a single line from stdin, trimming if from spaces and +// interpreting it as a 'yes' or a 'no'. If an empty line is entered, the default +// value is returned. +func (w *wizard) readDefaultYesNo(def bool) bool { + for { + fmt.Printf("> ") + text, err := w.in.ReadString('\n') + if err != nil { + log.Crit("Failed to read user input", "err", err) + } + if text = strings.ToLower(strings.TrimSpace(text)); text == "" { + return def + } + if text == "y" || text == "yes" { + return true + } + if text == "n" || text == "no" { + return false + } + log.Error("Invalid input, expected 'y', 'yes', 'n', 'no' or empty") + } +} + +// readURL reads a single line from stdin, trimming if from spaces and trying to +// interpret it as a URL (http, https or file). +func (w *wizard) readURL() *url.URL { + for { + fmt.Printf("> ") + text, err := w.in.ReadString('\n') + if err != nil { + log.Crit("Failed to read user input", "err", err) + } + uri, err := url.Parse(strings.TrimSpace(text)) + if err != nil { + log.Error("Invalid input, expected URL", "err", err) + continue + } + return uri + } +} + // readInt reads a single line from stdin, trimming if from spaces, enforcing it // to parse into an integer. func (w *wizard) readInt() int { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_dashboard.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_dashboard.go index 1a01631f..8a837084 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_dashboard.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_dashboard.go @@ -137,14 +137,14 @@ func (w *wizard) deployDashboard() { if w.conf.ethstats != "" { fmt.Println() fmt.Println("Include ethstats secret on dashboard (y/n)? (default = yes)") - infos.trusted = w.readDefaultString("y") == "y" + infos.trusted = w.readDefaultYesNo(true) } // Try to deploy the dashboard container on the host nocache := false if existed { fmt.Println() fmt.Printf("Should the dashboard be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } if out, err := deployDashboard(client, w.network, &w.conf, infos, nocache); err != nil { log.Error("Failed to deploy dashboard container", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_ethstats.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_ethstats.go index fb2529c2..58ff3efb 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_ethstats.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_ethstats.go @@ -67,11 +67,11 @@ func (w *wizard) deployEthstats() { if existed { fmt.Println() fmt.Printf("Keep existing IP %v blacklist (y/n)? (default = yes)\n", infos.banned) - if w.readDefaultString("y") != "y" { + if !w.readDefaultYesNo(true) { // The user might want to clear the entire list, although generally probably not fmt.Println() fmt.Printf("Clear out blacklist and start over (y/n)? (default = no)\n") - if w.readDefaultString("n") != "n" { + if w.readDefaultYesNo(false) { infos.banned = nil } // Offer the user to explicitly add/remove certain IP addresses @@ -106,7 +106,7 @@ func (w *wizard) deployEthstats() { if existed { fmt.Println() fmt.Printf("Should the ethstats be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } trusted := make([]string, 0, len(w.servers)) for _, client := range w.servers { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_explorer.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_explorer.go index 413511c1..a128fb9f 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_explorer.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_explorer.go @@ -100,7 +100,7 @@ func (w *wizard) deployExplorer() { if existed { fmt.Println() fmt.Printf("Should the explorer be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } if out, err := deployExplorer(client, w.network, chain, infos, nocache); err != nil { log.Error("Failed to deploy explorer container", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_faucet.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_faucet.go index 6f084089..9068c1d3 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_faucet.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_faucet.go @@ -81,7 +81,7 @@ func (w *wizard) deployFaucet() { if infos.captchaToken != "" { fmt.Println() fmt.Println("Reuse previous reCaptcha API authorization (y/n)? (default = yes)") - if w.readDefaultString("y") != "y" { + if !w.readDefaultYesNo(true) { infos.captchaToken, infos.captchaSecret = "", "" } } @@ -89,7 +89,7 @@ func (w *wizard) deployFaucet() { // No previous authorization (or old one discarded) fmt.Println() fmt.Println("Enable reCaptcha protection against robots (y/n)? (default = no)") - if w.readDefaultString("n") == "n" { + if !w.readDefaultYesNo(false) { log.Warn("Users will be able to requests funds via automated scripts") } else { // Captcha protection explicitly requested, read the site and secret keys @@ -132,7 +132,7 @@ func (w *wizard) deployFaucet() { } else { fmt.Println() fmt.Printf("Reuse previous (%s) funding account (y/n)? (default = yes)\n", key.Address.Hex()) - if w.readDefaultString("y") != "y" { + if !w.readDefaultYesNo(true) { infos.node.keyJSON, infos.node.keyPass = "", "" } } @@ -166,7 +166,7 @@ func (w *wizard) deployFaucet() { if existed { fmt.Println() fmt.Printf("Should the faucet be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } if out, err := deployFaucet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil { log.Error("Failed to deploy faucet container", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_genesis.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_genesis.go index 6c4cd571..6aed09f1 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_genesis.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_genesis.go @@ -20,9 +20,13 @@ import ( "bytes" "encoding/json" "fmt" + "io" "io/ioutil" "math/big" "math/rand" + "net/http" + "os" + "path/filepath" "time" "github.com/ethereum/go-ethereum/common" @@ -40,11 +44,12 @@ func (w *wizard) makeGenesis() { Difficulty: big.NewInt(524288), Alloc: make(core.GenesisAlloc), Config: ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(1), - EIP150Block: big.NewInt(2), - EIP155Block: big.NewInt(3), - EIP158Block: big.NewInt(3), - ByzantiumBlock: big.NewInt(4), + HomesteadBlock: big.NewInt(1), + EIP150Block: big.NewInt(2), + EIP155Block: big.NewInt(3), + EIP158Block: big.NewInt(3), + ByzantiumBlock: big.NewInt(4), + ConstantinopleBlock: big.NewInt(5), }, } // Figure out which consensus engine to choose @@ -114,9 +119,13 @@ func (w *wizard) makeGenesis() { } break } - // Add a batch of precompile balances to avoid them getting deleted - for i := int64(0); i < 256; i++ { - genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)} + fmt.Println() + fmt.Println("Should the precompile-addresses (0x1 .. 0xff) be pre-funded with 1 wei? (advisable yes)") + if w.readDefaultYesNo(true) { + // Add a batch of precompile balances to avoid them getting deleted + for i := int64(0); i < 256; i++ { + genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)} + } } // Query the user for some custom extras fmt.Println() @@ -130,53 +139,138 @@ func (w *wizard) makeGenesis() { w.conf.flush() } +// importGenesis imports a Geth genesis spec into puppeth. +func (w *wizard) importGenesis() { + // Request the genesis JSON spec URL from the user + fmt.Println() + fmt.Println("Where's the genesis file? (local file or http/https url)") + url := w.readURL() + + // Convert the various allowed URLs to a reader stream + var reader io.Reader + + switch url.Scheme { + case "http", "https": + // Remote web URL, retrieve it via an HTTP client + res, err := http.Get(url.String()) + if err != nil { + log.Error("Failed to retrieve remote genesis", "err", err) + return + } + defer res.Body.Close() + reader = res.Body + + case "": + // Schemaless URL, interpret as a local file + file, err := os.Open(url.String()) + if err != nil { + log.Error("Failed to open local genesis", "err", err) + return + } + defer file.Close() + reader = file + + default: + log.Error("Unsupported genesis URL scheme", "scheme", url.Scheme) + return + } + // Parse the genesis file and inject it successful + var genesis core.Genesis + if err := json.NewDecoder(reader).Decode(&genesis); err != nil { + log.Error("Invalid genesis spec: %v", err) + return + } + log.Info("Imported genesis block") + + w.conf.Genesis = &genesis + w.conf.flush() +} + // manageGenesis permits the modification of chain configuration parameters in // a genesis config and the export of the entire genesis spec. func (w *wizard) manageGenesis() { // Figure out whether to modify or export the genesis fmt.Println() fmt.Println(" 1. Modify existing fork rules") - fmt.Println(" 2. Export genesis configuration") + fmt.Println(" 2. Export genesis configurations") fmt.Println(" 3. Remove genesis configuration") choice := w.read() - switch { - case choice == "1": + switch choice { + case "1": // Fork rule updating requested, iterate over each fork fmt.Println() fmt.Printf("Which block should Homestead come into effect? (default = %v)\n", w.conf.Genesis.Config.HomesteadBlock) w.conf.Genesis.Config.HomesteadBlock = w.readDefaultBigInt(w.conf.Genesis.Config.HomesteadBlock) fmt.Println() - fmt.Printf("Which block should EIP150 come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block) + fmt.Printf("Which block should EIP150 (Tangerine Whistle) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block) w.conf.Genesis.Config.EIP150Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP150Block) fmt.Println() - fmt.Printf("Which block should EIP155 come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block) + fmt.Printf("Which block should EIP155 (Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block) w.conf.Genesis.Config.EIP155Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP155Block) fmt.Println() - fmt.Printf("Which block should EIP158 come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block) + fmt.Printf("Which block should EIP158/161 (also Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block) w.conf.Genesis.Config.EIP158Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP158Block) fmt.Println() fmt.Printf("Which block should Byzantium come into effect? (default = %v)\n", w.conf.Genesis.Config.ByzantiumBlock) w.conf.Genesis.Config.ByzantiumBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ByzantiumBlock) + fmt.Println() + fmt.Printf("Which block should Constantinople come into effect? (default = %v)\n", w.conf.Genesis.Config.ConstantinopleBlock) + w.conf.Genesis.Config.ConstantinopleBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ConstantinopleBlock) + if w.conf.Genesis.Config.PetersburgBlock == nil { + w.conf.Genesis.Config.PetersburgBlock = w.conf.Genesis.Config.ConstantinopleBlock + } + fmt.Println() + fmt.Printf("Which block should Constantinople-Fix (remove EIP-1283) come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) + w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock) + out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") fmt.Printf("Chain configuration updated:\n\n%s\n", out) - case choice == "2": + w.conf.flush() + + case "2": // Save whatever genesis configuration we currently have fmt.Println() - fmt.Printf("Which file to save the genesis into? (default = %s.json)\n", w.network) - out, _ := json.MarshalIndent(w.conf.Genesis, "", " ") - if err := ioutil.WriteFile(w.readDefaultString(fmt.Sprintf("%s.json", w.network)), out, 0644); err != nil { - log.Error("Failed to save genesis file", "err", err) - } - log.Info("Exported existing genesis block") + fmt.Printf("Which folder to save the genesis specs into? (default = current)\n") + fmt.Printf(" Will create %s.json, %s-aleth.json, %s-harmony.json, %s-parity.json\n", w.network, w.network, w.network, w.network) - case choice == "3": + folder := w.readDefaultString(".") + if err := os.MkdirAll(folder, 0755); err != nil { + log.Error("Failed to create spec folder", "folder", folder, "err", err) + return + } + out, _ := json.MarshalIndent(w.conf.Genesis, "", " ") + + // Export the native genesis spec used by puppeth and Geth + gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network)) + if err := ioutil.WriteFile((gethJson), out, 0644); err != nil { + log.Error("Failed to save genesis file", "err", err) + return + } + log.Info("Saved native genesis chain spec", "path", gethJson) + + // Export the genesis spec used by Aleth (formerly C++ Ethereum) + if spec, err := newAlethGenesisSpec(w.network, w.conf.Genesis); err != nil { + log.Error("Failed to create Aleth chain spec", "err", err) + } else { + saveGenesis(folder, w.network, "aleth", spec) + } + // Export the genesis spec used by Parity + if spec, err := newParityChainSpec(w.network, w.conf.Genesis, []string{}); err != nil { + log.Error("Failed to create Parity chain spec", "err", err) + } else { + saveGenesis(folder, w.network, "parity", spec) + } + // Export the genesis spec used by Harmony (formerly EthereumJ + saveGenesis(folder, w.network, "harmony", w.conf.Genesis) + + case "3": // Make sure we don't have any services running if len(w.conf.servers()) > 0 { log.Error("Genesis reset requires all services and servers torn down") @@ -186,8 +280,20 @@ func (w *wizard) manageGenesis() { w.conf.Genesis = nil w.conf.flush() - default: log.Error("That's not something I can do") + return } } + +// saveGenesis JSON encodes an arbitrary genesis spec into a pre-defined file. +func saveGenesis(folder, network, client string, spec interface{}) { + path := filepath.Join(folder, fmt.Sprintf("%s-%s.json", network, client)) + + out, _ := json.Marshal(spec) + if err := ioutil.WriteFile(path, out, 0644); err != nil { + log.Error("Failed to save genesis file", "client", client, "err", err) + return + } + log.Info("Saved genesis chain spec", "client", client, "path", path) +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_intro.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_intro.go index 60aa0f7f..75fb04b7 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_intro.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_intro.go @@ -61,14 +61,14 @@ func (w *wizard) run() { // Make sure we have a good network name to work with fmt.Println() // Docker accepts hyphens in image names, but doesn't like it for container names if w.network == "" { - fmt.Println("Please specify a network name to administer (no spaces or hyphens, please)") + fmt.Println("Please specify a network name to administer (no spaces, hyphens or capital letters please)") for { w.network = w.readString() - if !strings.Contains(w.network, " ") && !strings.Contains(w.network, "-") { + if !strings.Contains(w.network, " ") && !strings.Contains(w.network, "-") && strings.ToLower(w.network) == w.network { fmt.Printf("\nSweet, you can set this via --network=%s next time!\n\n", w.network) break } - log.Error("I also like to live dangerously, still no spaces or hyphens") + log.Error("I also like to live dangerously, still no spaces, hyphens or capital letters") } } log.Info("Administering Ethereum network", "name", w.network) @@ -131,7 +131,20 @@ func (w *wizard) run() { case choice == "2": if w.conf.Genesis == nil { - w.makeGenesis() + fmt.Println() + fmt.Println("What would you like to do? (default = create)") + fmt.Println(" 1. Create new genesis from scratch") + fmt.Println(" 2. Import already existing genesis") + + choice := w.read() + switch { + case choice == "" || choice == "1": + w.makeGenesis() + case choice == "2": + w.importGenesis() + default: + log.Error("That's not something I can do") + } } else { w.manageGenesis() } @@ -149,7 +162,6 @@ func (w *wizard) run() { } else { w.manageComponents() } - default: log.Error("That's not something I can do") } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_nginx.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_nginx.go index 4eeae93a..8397b7fd 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_nginx.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_nginx.go @@ -41,12 +41,12 @@ func (w *wizard) ensureVirtualHost(client *sshClient, port int, def string) (str // Reverse proxy is not running, offer to deploy a new one fmt.Println() fmt.Println("Allow sharing the port with other services (y/n)? (default = yes)") - if w.readDefaultString("y") == "y" { + if w.readDefaultYesNo(true) { nocache := false if proxy != nil { fmt.Println() fmt.Printf("Should the reverse-proxy be rebuilt from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } if out, err := deployNginx(client, w.network, port, nocache); err != nil { log.Error("Failed to deploy reverse-proxy", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_node.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_node.go index 49b10a02..e37297f6 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_node.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_node.go @@ -126,7 +126,7 @@ func (w *wizard) deployNode(boot bool) { } else { fmt.Println() fmt.Printf("Reuse previous (%s) signing account (y/n)? (default = yes)\n", key.Address.Hex()) - if w.readDefaultString("y") != "y" { + if !w.readDefaultYesNo(true) { infos.keyJSON, infos.keyPass = "", "" } } @@ -165,7 +165,7 @@ func (w *wizard) deployNode(boot bool) { if existed { fmt.Println() fmt.Printf("Should the node be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } if out, err := deployNode(client, w.network, w.conf.bootnodes, infos, nocache); err != nil { log.Error("Failed to deploy Ethereum node container", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_wallet.go b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_wallet.go index 7624d11e..ca1ea5bd 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_wallet.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_wallet.go @@ -96,7 +96,7 @@ func (w *wizard) deployWallet() { if existed { fmt.Println() fmt.Printf("Should the wallet be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultString("n") != "n" + nocache = w.readDefaultYesNo(false) } if out, err := deployWallet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil { log.Error("Failed to deploy wallet container", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access.go index 072541b6..cc0cc820 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access.go @@ -178,8 +178,8 @@ func accessNewACT(ctx *cli.Context) { accessKey []byte err error ref = args[0] - pkGrantees = []string{} - passGrantees = []string{} + pkGrantees []string + passGrantees []string pkGranteesFilename = ctx.String(SwarmAccessGrantKeysFlag.Name) passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name) privateKey = getPrivKey(ctx) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access_test.go index e812cd8f..0898d33b 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/access_test.go @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . -// +build !windows - package main import ( @@ -28,18 +26,18 @@ import ( gorand "math/rand" "net/http" "os" + "runtime" "strings" "testing" "time" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/swarm/api" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" + swarmapi "github.com/ethereum/go-ethereum/swarm/api/client" "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/crypto/sha3" ) const ( @@ -49,22 +47,41 @@ const ( var DefaultCurve = crypto.S256() -// TestAccessPassword tests for the correct creation of an ACT manifest protected by a password. +func TestACT(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + initCluster(t) + + cases := []struct { + name string + f func(t *testing.T) + }{ + {"Password", testPassword}, + {"PK", testPK}, + {"ACTWithoutBogus", testACTWithoutBogus}, + {"ACTWithBogus", testACTWithBogus}, + } + + for _, tc := range cases { + t.Run(tc.name, tc.f) + } +} + +// testPassword tests for the correct creation of an ACT manifest protected by a password. // The test creates bogus content, uploads it encrypted, then creates the wrapping manifest with the Access entry // The parties participating - node (publisher), uploads to second node then disappears. Content which was uploaded // is then fetched through 2nd node. since the tested code is not key-aware - we can just // fetch from the 2nd node using HTTP BasicAuth -func TestAccessPassword(t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - +func testPassword(t *testing.T) { dataFilename := testutil.TempFileWithContent(t, data) defer os.RemoveAll(dataFilename) // upload the file with 'swarm up' and expect a hash up := runSwarm(t, "--bzzapi", - srv.URL, //it doesn't matter through which node we upload content + cluster.Nodes[0].URL, "up", "--encrypt", dataFilename) @@ -138,16 +155,17 @@ func TestAccessPassword(t *testing.T) { if a.Publisher != "" { t.Fatal("should be empty") } - client := swarm.NewClient(srv.URL) + + client := swarmapi.NewClient(cluster.Nodes[0].URL) hash, err := client.UploadManifest(&m, false) if err != nil { t.Fatal(err) } - httpClient := &http.Client{} + url := cluster.Nodes[0].URL + "/" + "bzz:/" + hash - url := srv.URL + "/" + "bzz:/" + hash + httpClient := &http.Client{} response, err := httpClient.Get(url) if err != nil { t.Fatal(err) @@ -189,7 +207,7 @@ func TestAccessPassword(t *testing.T) { //download file with 'swarm down' with wrong password up = runSwarm(t, "--bzzapi", - srv.URL, + cluster.Nodes[0].URL, "down", "bzz:/"+hash, tmp, @@ -203,16 +221,12 @@ func TestAccessPassword(t *testing.T) { up.ExpectExit() } -// TestAccessPK tests for the correct creation of an ACT manifest between two parties (publisher and grantee). +// testPK tests for the correct creation of an ACT manifest between two parties (publisher and grantee). // The test creates bogus content, uploads it encrypted, then creates the wrapping manifest with the Access entry // The parties participating - node (publisher), uploads to second node (which is also the grantee) then disappears. // Content which was uploaded is then fetched through the grantee's http proxy. Since the tested code is private-key aware, // the test will fail if the proxy's given private key is not granted on the ACT. -func TestAccessPK(t *testing.T) { - // Setup Swarm and upload a test file to it - cluster := newTestCluster(t, 2) - defer cluster.Shutdown() - +func testPK(t *testing.T) { dataFilename := testutil.TempFileWithContent(t, data) defer os.RemoveAll(dataFilename) @@ -318,7 +332,7 @@ func TestAccessPK(t *testing.T) { if a.Publisher != pkComp { t.Fatal("publisher key did not match") } - client := swarm.NewClient(cluster.Nodes[0].URL) + client := swarmapi.NewClient(cluster.Nodes[0].URL) hash, err := client.UploadManifest(&m, false) if err != nil { @@ -344,29 +358,24 @@ func TestAccessPK(t *testing.T) { } } -// TestAccessACT tests the creation of the ACT manifest end-to-end, without any bogus entries (i.e. default scenario = 3 nodes 1 unauthorized) -func TestAccessACT(t *testing.T) { - testAccessACT(t, 0) +// testACTWithoutBogus tests the creation of the ACT manifest end-to-end, without any bogus entries (i.e. default scenario = 3 nodes 1 unauthorized) +func testACTWithoutBogus(t *testing.T) { + testACT(t, 0) } -// TestAccessACTScale tests the creation of the ACT manifest end-to-end, with 1000 bogus entries (i.e. 1000 EC keys + default scenario = 3 nodes 1 unauthorized = 1003 keys in the ACT manifest) -func TestAccessACTScale(t *testing.T) { - testAccessACT(t, 1000) +// testACTWithBogus tests the creation of the ACT manifest end-to-end, with 100 bogus entries (i.e. 100 EC keys + default scenario = 3 nodes 1 unauthorized = 103 keys in the ACT manifest) +func testACTWithBogus(t *testing.T) { + testACT(t, 100) } -// TestAccessACT tests the e2e creation, uploading and downloading of an ACT access control with both EC keys AND password protection +// testACT tests the e2e creation, uploading and downloading of an ACT access control with both EC keys AND password protection // the test fires up a 3 node cluster, then randomly picks 2 nodes which will be acting as grantees to the data // set and also protects the ACT with a password. the third node should fail decoding the reference as it will not be granted access. // the third node then then tries to download using a correct password (and succeeds) then uses a wrong password and fails. // the publisher uploads through one of the nodes then disappears. -func testAccessACT(t *testing.T, bogusEntries int) { - // Setup Swarm and upload a test file to it - const clusterSize = 3 - cluster := newTestCluster(t, clusterSize) - defer cluster.Shutdown() - +func testACT(t *testing.T, bogusEntries int) { var uploadThroughNode = cluster.Nodes[0] - client := swarm.NewClient(uploadThroughNode.URL) + client := swarmapi.NewClient(uploadThroughNode.URL) r1 := gorand.New(gorand.NewSource(time.Now().UnixNano())) nodeToSkip := r1.Intn(clusterSize) // a number between 0 and 2 (node indices in `cluster`) @@ -388,7 +397,7 @@ func testAccessACT(t *testing.T, bogusEntries int) { } ref := matches[0] - grantees := []string{} + var grantees []string for i, v := range cluster.Nodes { if i == nodeToSkip { continue @@ -399,7 +408,7 @@ func testAccessACT(t *testing.T, bogusEntries int) { } if bogusEntries > 0 { - bogusGrantees := []string{} + var bogusGrantees []string for i := 0; i < bogusEntries; i++ { prv, err := ecies.GenerateKey(rand.Reader, DefaultCurve, nil) @@ -589,7 +598,7 @@ func TestKeypairSanity(t *testing.T) { t.Fatal(err) } - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() hasher.Write(salt) shared, err := hex.DecodeString(sharedSecret) if err != nil { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/bootnodes.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/bootnodes.go index cbba9970..ce3cd528 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/bootnodes.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/bootnodes.go @@ -17,61 +17,8 @@ package main var SwarmBootnodes = []string{ - // Foundation Swarm Gateway Cluster - "enode://e5c6f9215c919a5450a7b8c14c22535607b69f2c8e1e7f6f430cb25d7a2c27cd1df4c4f18ad7c1d7e5162e271ffcd3f20b1a1467fb6e790e7d727f3b2193de97@52.232.7.187:30399", - "enode://9b2fe07e69ccc7db5fef15793dab7d7d2e697ed92132d6e9548218e68a34613a8671ad03a6658d862b468ed693cae8a0f8f8d37274e4a657ffb59ca84676e45b@52.232.7.187:30400", - "enode://76c1059162c93ef9df0f01097c824d17c492634df211ef4c806935b349082233b63b90c23970254b3b7138d630400f7cf9b71e80355a446a8b733296cb04169a@52.232.7.187:30401", - "enode://ce46bbe2a8263145d65252d52da06e000ad350ed09c876a71ea9544efa42f63c1e1b6cc56307373aaad8f9dd069c90d0ed2dd1530106200e16f4ca681dd8ae2d@52.232.7.187:30402", - "enode://f431e0d6008a6c35c6e670373d828390c8323e53da8158e7bfc43cf07e632cc9e472188be8df01decadea2d4a068f1428caba769b632554a8fb0607bc296988f@52.232.7.187:30403", - "enode://174720abfff83d7392f121108ae50ea54e04889afe020df883655c0f6cb95414db945a0228d8982fe000d86fc9f4b7669161adc89cd7cd56f78f01489ab2b99b@52.232.7.187:30404", - "enode://2ae89be4be61a689b6f9ecee4360a59e185e010ab750f14b63b4ae43d4180e872e18e3437d4386ce44875dc7cc6eb761acba06412fe3178f3dac1dab3b65703e@52.232.7.187:30405", - "enode://24abebe1c0e6d75d6052ce3219a87be8573fd6397b4cb51f0773b83abba9b3d872bfb273cdc07389715b87adfac02f5235f5241442c5089802cbd8d42e310fce@52.232.7.187:30406", - "enode://d08dfa46bfbbdbcaafbb6e34abee4786610f6c91e0b76d7881f0334ac10dda41d8c1f2b6eedffb4493293c335c0ad46776443b2208d1fbbb9e1a90b25ee4eef2@52.232.7.187:30407", - "enode://8d95eb0f837d27581a43668ed3b8783d69dc4e84aa3edd7a0897e026155c8f59c8702fdc0375ee7bac15757c9c78e1315d9b73e4ce59c936db52ea4ae2f501c7@52.232.7.187:30408", - "enode://a5967cc804aebd422baaaba9f06f27c9e695ccab335b61088130f8cbe64e3cdf78793868c7051dfc06eecfe844fad54bc7f6dfaed9db3c7ecef279cb829c25fb@52.232.7.187:30409", - "enode://5f00134d81a8f2ebcc46f8766f627f492893eda48138f811b7de2168308171968f01710bca6da05764e74f14bae41652f554e6321f1aed85fa3461e89d075dbf@52.232.7.187:30410", - "enode://b2142b79b01a5aa66a5e23cc35e78219a8e97bc2412a6698cee24ae02e87078b725d71730711bd62e25ff1aa8658c6633778af8ac14c63814a337c3dd0ebda9f@52.232.7.187:30411", - "enode://1ffa7651094867d6486ce3ef46d27a052c2cb968b618346c6df7040322c7efc3337547ba85d4cbba32e8b31c42c867202554735c06d4c664b9afada2ed0c4b3c@52.232.7.187:30412", - "enode://129e0c3d5f5df12273754f6f703d2424409fa4baa599e0b758c55600169313887855e75b082028d2302ec034b303898cd697cc7ae8256ba924ce927510da2c8d@52.232.7.187:30413", - "enode://419e2dc0d2f5b022cf16b0e28842658284909fa027a0fbbb5e2b755e7f846ea02a8f0b66a7534981edf6a7bcf8a14855344c6668e2cd4476ccd35a11537c9144@52.232.7.187:30414", - "enode://23d55ad900583231b91f2f62e3f72eb498b342afd58b682be3af052eed62b5651094471065981de33d8786f075f05e3cca499503b0ac8ae84b2a06e99f5b0723@52.232.7.187:30415", - "enode://bc56e4158c00e9f616d7ea533def20a89bef959df4e62a768ff238ff4e1e9223f57ecff969941c20921bad98749baae311c0fbebce53bf7bbb9d3dc903640990@52.232.7.187:30416", - "enode://433ce15199c409875e7e72fffd69fdafe746f17b20f0d5555281722a65fde6c80328fab600d37d8624509adc072c445ce0dad4a1c01cff6acf3132c11d429d4d@52.232.7.187:30417", - "enode://632ee95b8f0eac51ef89ceb29313fef3a60050181d66a6b125583b1a225a7694b252edc016efb58aa3b251da756cb73280842a022c658ed405223b2f58626343@52.232.7.187:30418", - "enode://4a0f9bcff7a4b9ee453fb298d0fb222592efe121512e30cd72fef631beb8c6a15153a1456eb073ee18551c0e003c569651a101892dc4124e90b933733a498bb5@52.232.7.187:30419", - "enode://f0d80fbc72d16df30e19aac3051eb56a7aff0c8367686702e01ea132d8b0b3ee00cadd6a859d2cca98ec68d3d574f8a8a87dba2347ec1e2818dc84bc3fa34fae@52.232.7.187:30420", - "enode://a199146906e4f9f2b94b195a8308d9a59a3564b92efaab898a4243fe4c2ad918b7a8e4853d9d901d94fad878270a2669d644591299c3d43de1b298c00b92b4a7@52.232.7.187:30421", - "enode://052036ea8736b37adbfb684d90ce43e11b3591b51f31489d7c726b03618dea4f73b1e659deb928e6bf40564edcdcf08351643f42db3d4ca1c2b5db95dad59e94@52.232.7.187:30422", - "enode://460e2b8c6da8f12fac96c836e7d108f4b7ec55a1c64631bb8992339e117e1c28328fee83af863196e20af1487a655d13e5ceba90e980e92502d5bac5834c1f71@52.232.7.187:30423", - "enode://6d2cdd13741b2e72e9031e1b93c6d9a4e68de2844aa4e939f6a8a8498a7c1d7e2ee4c64217e92a6df08c9a32c6764d173552810ef1bd2ecb356532d389dd2136@52.232.7.187:30424", - "enode://62105fc25ce2cd5b299647f47eaa9211502dc76f0e9f461df915782df7242ac3223e3db04356ae6ed2977ccac20f0b16864406e9ca514a40a004cb6a5d0402aa@52.232.7.187:30425", - "enode://e0e388fc520fd493c33f0ce16685e6f98fb6aec28f2edc14ee6b179594ee519a896425b0025bb6f0e182dd3e468443f19c70885fbc66560d000093a668a86aa8@52.232.7.187:30426", - "enode://63f3353a72521ea10022127a4fe6b4acbef197c3fe668fd9f4805542d8a6fcf79f6335fbab62d180a35e19b739483e740858b113fdd7c13a26ad7b4e318a5aef@52.232.7.187:30427", - "enode://33a42b927085678d4aefd4e70b861cfca6ef5f6c143696c4f755973fd29e64c9e658cad57a66a687a7a156da1e3688b1fbdd17bececff2ee009fff038fa5666b@52.232.7.187:30428", - "enode://259ab5ab5c1daee3eab7e3819ab3177b82d25c29e6c2444fdd3f956e356afae79a72840ccf2d0665fe82c81ebc3b3734da1178ac9fd5d62c67e674b69f86b6be@52.232.7.187:30429", - "enode://558bccad7445ce3fd8db116ed6ab4aed1324fdbdac2348417340c1764dc46d46bffe0728e5b7d5c36f12e794c289f18f57f08f085d2c65c9910a5c7a65b6a66a@52.232.7.187:30430", - "enode://abe60937a0657ffded718e3f84a32987286983be257bdd6004775c4b525747c2b598f4fac49c8de324de5ce75b22673fa541a7ce2d555fb7f8ca325744ae3577@52.232.7.187:30431", - "enode://bce6f0aaa5b230742680084df71d4f026b3eff7f564265599216a1b06b765303fdc9325de30ffd5dfdaf302ce4b14322891d2faea50ce2ca298d7409f5858339@52.232.7.187:30432", - "enode://21b957c4e03277d42be6660730ec1b93f540764f26c6abdb54d006611139c7081248486206dfbf64fcaffd62589e9c6b8ea77a5297e4b21a605f1bcf49483ed0@52.232.7.187:30433", - "enode://ff104e30e64f24c3d7328acee8b13354e5551bc8d60bb25ecbd9632d955c7e34bb2d969482d173355baad91c8282f8b592624eb3929151090da3b4448d4d58fb@52.232.7.187:30434", - "enode://c76e2b5f81a521bceaec1518926a21380a345df9cf463461562c6845795512497fb67679e155fc96a74350f8b78de8f4c135dd52b106dbbb9795452021d09ea5@52.232.7.187:30435", - "enode://3288fd860105164f3e9b69934c4eb18f7146cfab31b5a671f994e21a36e9287766e5f9f075aefbc404538c77f7c2eb2a4495020a7633a1c3970d94e9fa770aeb@52.232.7.187:30436", - "enode://6cea859c7396d46b20cfcaa80f9a11cd112f8684f2f782f7b4c0e1e0af9212113429522075101923b9b957603e6c32095a6a07b5e5e35183c521952ee108dfaf@52.232.7.187:30437", - "enode://f628ec56e4ca8317cc24cc4ac9b27b95edcce7b96e1c7f3b53e30de4a8580fe44f2f0694a513bdb0a431acaf2824074d6ace4690247bbc34c14f426af8c056ea@52.232.7.187:30438", - "enode://055ec8b26fc105c4f97970a1cce9773a5e34c03f511b839db742198a1c571e292c54aa799e9afb991cc8a560529b8cdf3e0c344bc6c282aff2f68eec59361ddf@52.232.7.187:30439", - "enode://48cb0d430c328974226aa33a931d8446cd5a8d40f3ead8f4ce7ad60faa1278192eb6d58bed91258d63e81f255fc107eec2425ce2ae8b22350dd556076e160610@52.232.7.187:30440", - "enode://3fadb7af7f770d5ffc6b073b8d42834bebb18ce1fe8a4fe270d2b799e7051327093960dc61d9a18870db288f7746a0e6ea2a013cd6ab0e5f97ca08199473aace@52.232.7.187:30441", - "enode://a5d7168024c9992769cf380ffa559a64b4f39a29d468f579559863814eb0ae0ed689ac0871a3a2b4c78b03297485ec322d578281131ef5d5c09a4beb6200a97a@52.232.7.187:30442", - "enode://9c57744c5b2c2d71abcbe80512652f9234d4ab041b768a2a886ab390fe6f184860f40e113290698652d7e20a8ac74d27ac8671db23eb475b6c5e6253e4693bf8@52.232.7.187:30443", - "enode://daca9ff0c3176045a0e0ed228dee00ec86bc0939b135dc6b1caa23745d20fd0332e1ee74ad04020e89df56c7146d831a91b89d15ca3df05ba7618769fefab376@52.232.7.187:30444", - "enode://a3f6af59428cb4b9acb198db15ef5554fa43c2b0c18e468a269722d64a27218963a2975eaf82750b6262e42192b5e3669ea51337b4cda62b33987981bc5e0c1a@52.232.7.187:30445", - "enode://fe571422fa4651c3354c85dac61911a6a6520dd3c0332967a49d4133ca30e16a8a4946fa73ca2cb5de77917ea701a905e1c3015b2f4defcd53132b61cc84127a@52.232.7.187:30446", - - // Mainframe - "enode://ee9a5a571ea6c8a59f9a8bb2c569c865e922b41c91d09b942e8c1d4dd2e1725bd2c26149da14de1f6321a2c6fdf1e07c503c3e093fb61696daebf74d6acd916b@54.186.219.160:30399", - "enode://a03f0562ecb8a992ad5242345535e73483cdc18ab934d36bf24b567d43447c2cea68f89f1d51d504dd13acc30f24ebce5a150bea2ccb1b722122ce4271dc199d@52.67.248.147:30399", - "enode://e2cbf9eafd85903d3b1c56743035284320695e0072bc8d7396e0542aa5e1c321b236f67eab66b79c2f15d4447fa4bbe74dd67d0467da23e7eb829f60ec8a812b@13.58.169.1:30399", - "enode://8b8c6bda6047f1cad9fab2db4d3d02b7aa26279902c32879f7bcd4a7d189fee77fdc36ee151ce6b84279b4792e72578fd529d2274d014132465758fbfee51cee@13.209.13.15:30399", - "enode://63f6a8818927e429585287cf2ca0cb9b11fa990b7b9b331c2962cdc6f21807a2473b26e8256225c26caff70d7218e59586d704d49061452c6852e382c885d03c@35.154.106.174:30399", - "enode://ed4bd3b794ed73f18e6dcc70c6624dfec63b5654f6ab54e8f40b16eff8afbd342d4230e099ddea40e84423f81b2d2ea79799dc345257b1fec6f6c422c9d008f7@52.213.20.99:30399", + // EF Swarm Bootnode - AWS - eu-central-1 + "enode://4c113504601930bf2000c29bcd98d1716b6167749f58bad703bae338332fe93cc9d9204f08afb44100dc7bea479205f5d162df579f9a8f76f8b402d339709023@3.122.203.99:30301", + // EF Swarm Bootnode - AWS - us-west-2 + "enode://89f2ede3371bff1ad9f2088f2012984e280287a4e2b68007c2a6ad994909c51886b4a8e9e2ecc97f9910aca538398e0a5804b0ee80a187fde1ba4f32626322ba@52.35.212.179:30301", } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config.go index 3eea3057..32cd442a 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config.go @@ -59,29 +59,31 @@ var ( //constants for environment variables const ( - SWARM_ENV_CHEQUEBOOK_ADDR = "SWARM_CHEQUEBOOK_ADDR" - SWARM_ENV_ACCOUNT = "SWARM_ACCOUNT" - SWARM_ENV_LISTEN_ADDR = "SWARM_LISTEN_ADDR" - SWARM_ENV_PORT = "SWARM_PORT" - SWARM_ENV_NETWORK_ID = "SWARM_NETWORK_ID" - SWARM_ENV_SWAP_ENABLE = "SWARM_SWAP_ENABLE" - SWARM_ENV_SWAP_API = "SWARM_SWAP_API" - SWARM_ENV_SYNC_DISABLE = "SWARM_SYNC_DISABLE" - SWARM_ENV_SYNC_UPDATE_DELAY = "SWARM_ENV_SYNC_UPDATE_DELAY" - SWARM_ENV_MAX_STREAM_PEER_SERVERS = "SWARM_ENV_MAX_STREAM_PEER_SERVERS" - SWARM_ENV_LIGHT_NODE_ENABLE = "SWARM_LIGHT_NODE_ENABLE" - SWARM_ENV_DELIVERY_SKIP_CHECK = "SWARM_DELIVERY_SKIP_CHECK" - SWARM_ENV_ENS_API = "SWARM_ENS_API" - SWARM_ENV_ENS_ADDR = "SWARM_ENS_ADDR" - SWARM_ENV_CORS = "SWARM_CORS" - SWARM_ENV_BOOTNODES = "SWARM_BOOTNODES" - SWARM_ENV_PSS_ENABLE = "SWARM_PSS_ENABLE" - SWARM_ENV_STORE_PATH = "SWARM_STORE_PATH" - SWARM_ENV_STORE_CAPACITY = "SWARM_STORE_CAPACITY" - SWARM_ENV_STORE_CACHE_CAPACITY = "SWARM_STORE_CACHE_CAPACITY" - SWARM_ACCESS_PASSWORD = "SWARM_ACCESS_PASSWORD" - SWARM_AUTO_DEFAULTPATH = "SWARM_AUTO_DEFAULTPATH" - GETH_ENV_DATADIR = "GETH_DATADIR" + SwarmEnvChequebookAddr = "SWARM_CHEQUEBOOK_ADDR" + SwarmEnvAccount = "SWARM_ACCOUNT" + SwarmEnvListenAddr = "SWARM_LISTEN_ADDR" + SwarmEnvPort = "SWARM_PORT" + SwarmEnvNetworkID = "SWARM_NETWORK_ID" + SwarmEnvSwapEnable = "SWARM_SWAP_ENABLE" + SwarmEnvSwapAPI = "SWARM_SWAP_API" + SwarmEnvSyncDisable = "SWARM_SYNC_DISABLE" + SwarmEnvSyncUpdateDelay = "SWARM_ENV_SYNC_UPDATE_DELAY" + SwarmEnvMaxStreamPeerServers = "SWARM_ENV_MAX_STREAM_PEER_SERVERS" + SwarmEnvLightNodeEnable = "SWARM_LIGHT_NODE_ENABLE" + SwarmEnvDeliverySkipCheck = "SWARM_DELIVERY_SKIP_CHECK" + SwarmEnvENSAPI = "SWARM_ENS_API" + SwarmEnvENSAddr = "SWARM_ENS_ADDR" + SwarmEnvCORS = "SWARM_CORS" + SwarmEnvBootnodes = "SWARM_BOOTNODES" + SwarmEnvPSSEnable = "SWARM_PSS_ENABLE" + SwarmEnvStorePath = "SWARM_STORE_PATH" + SwarmEnvStoreCapacity = "SWARM_STORE_CAPACITY" + SwarmEnvStoreCacheCapacity = "SWARM_STORE_CACHE_CAPACITY" + SwarmEnvBootnodeMode = "SWARM_BOOTNODE_MODE" + SwarmAccessPassword = "SWARM_ACCESS_PASSWORD" + SwarmAutoDefaultPath = "SWARM_AUTO_DEFAULTPATH" + SwarmGlobalstoreAPI = "SWARM_GLOBALSTORE_API" + GethEnvDataDir = "GETH_DATADIR" ) // These settings ensure that TOML keys use the same names as Go struct fields. @@ -121,18 +123,22 @@ func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) { } //finally, after the configuration build phase is finished, initialize -func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) { +func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context, nodeconfig *node.Config) error { //at this point, all vars should be set in the Config //get the account for the provided swarm account prvkey := getAccount(config.BzzAccount, ctx, stack) //set the resolved config path (geth --datadir) config.Path = expandPath(stack.InstanceDir()) //finally, initialize the configuration - config.Init(prvkey) + err := config.Init(prvkey, nodeconfig.NodeKey()) + if err != nil { + return err + } //configuration phase completed here log.Debug("Starting Swarm with the following parameters:") //after having created the config, print it to screen log.Debug(printConfig(config)) + return nil } //configFileOverride overrides the current config with the config file, if a config file has been provided @@ -164,10 +170,9 @@ func configFileOverride(config *bzzapi.Config, ctx *cli.Context) (*bzzapi.Config return config, err } -//override the current config with whatever is provided through the command line -//most values are not allowed a zero value (empty string), if not otherwise noted +// cmdLineOverride overrides the current config with whatever is provided through the command line +// most values are not allowed a zero value (empty string), if not otherwise noted func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Config { - if keyid := ctx.GlobalString(SwarmAccountFlag.Name); keyid != "" { currentConfig.BzzAccount = keyid } @@ -226,7 +231,7 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con currentConfig.SwapAPI = ctx.GlobalString(SwarmSwapAPIFlag.Name) if currentConfig.SwapEnabled && currentConfig.SwapAPI == "" { - utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) + utils.Fatalf(SwarmErrSwapSetNoAPI) } if ctx.GlobalIsSet(EnsAPIFlag.Name) { @@ -254,116 +259,135 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con currentConfig.LocalStoreParams.DbCapacity = storeCapacity } - if storeCacheCapacity := ctx.GlobalUint(SwarmStoreCacheCapacity.Name); storeCacheCapacity != 0 { - currentConfig.LocalStoreParams.CacheCapacity = storeCacheCapacity + if ctx.GlobalIsSet(SwarmStoreCacheCapacity.Name) { + currentConfig.LocalStoreParams.CacheCapacity = ctx.GlobalUint(SwarmStoreCacheCapacity.Name) + } + + if ctx.GlobalIsSet(SwarmBootnodeModeFlag.Name) { + currentConfig.BootnodeMode = ctx.GlobalBool(SwarmBootnodeModeFlag.Name) + } + + if ctx.GlobalIsSet(SwarmGlobalStoreAPIFlag.Name) { + currentConfig.GlobalStoreAPI = ctx.GlobalString(SwarmGlobalStoreAPIFlag.Name) } return currentConfig } -//override the current config with whatver is provided in environment variables -//most values are not allowed a zero value (empty string), if not otherwise noted +// envVarsOverride overrides the current config with whatver is provided in environment variables +// most values are not allowed a zero value (empty string), if not otherwise noted func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) { - - if keyid := os.Getenv(SWARM_ENV_ACCOUNT); keyid != "" { + if keyid := os.Getenv(SwarmEnvAccount); keyid != "" { currentConfig.BzzAccount = keyid } - if chbookaddr := os.Getenv(SWARM_ENV_CHEQUEBOOK_ADDR); chbookaddr != "" { + if chbookaddr := os.Getenv(SwarmEnvChequebookAddr); chbookaddr != "" { currentConfig.Contract = common.HexToAddress(chbookaddr) } - if networkid := os.Getenv(SWARM_ENV_NETWORK_ID); networkid != "" { + if networkid := os.Getenv(SwarmEnvNetworkID); networkid != "" { id, err := strconv.ParseUint(networkid, 10, 64) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_NETWORK_ID, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvNetworkID, err) } if id != 0 { currentConfig.NetworkID = id } } - if datadir := os.Getenv(GETH_ENV_DATADIR); datadir != "" { + if datadir := os.Getenv(GethEnvDataDir); datadir != "" { currentConfig.Path = expandPath(datadir) } - bzzport := os.Getenv(SWARM_ENV_PORT) + bzzport := os.Getenv(SwarmEnvPort) if len(bzzport) > 0 { currentConfig.Port = bzzport } - if bzzaddr := os.Getenv(SWARM_ENV_LISTEN_ADDR); bzzaddr != "" { + if bzzaddr := os.Getenv(SwarmEnvListenAddr); bzzaddr != "" { currentConfig.ListenAddr = bzzaddr } - if swapenable := os.Getenv(SWARM_ENV_SWAP_ENABLE); swapenable != "" { + if swapenable := os.Getenv(SwarmEnvSwapEnable); swapenable != "" { swap, err := strconv.ParseBool(swapenable) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_SWAP_ENABLE, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSwapEnable, err) } currentConfig.SwapEnabled = swap } - if syncdisable := os.Getenv(SWARM_ENV_SYNC_DISABLE); syncdisable != "" { + if syncdisable := os.Getenv(SwarmEnvSyncDisable); syncdisable != "" { sync, err := strconv.ParseBool(syncdisable) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_SYNC_DISABLE, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSyncDisable, err) } currentConfig.SyncEnabled = !sync } - if v := os.Getenv(SWARM_ENV_DELIVERY_SKIP_CHECK); v != "" { + if v := os.Getenv(SwarmEnvDeliverySkipCheck); v != "" { skipCheck, err := strconv.ParseBool(v) if err != nil { currentConfig.DeliverySkipCheck = skipCheck } } - if v := os.Getenv(SWARM_ENV_SYNC_UPDATE_DELAY); v != "" { + if v := os.Getenv(SwarmEnvSyncUpdateDelay); v != "" { d, err := time.ParseDuration(v) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_SYNC_UPDATE_DELAY, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSyncUpdateDelay, err) } currentConfig.SyncUpdateDelay = d } - if max := os.Getenv(SWARM_ENV_MAX_STREAM_PEER_SERVERS); max != "" { + if max := os.Getenv(SwarmEnvMaxStreamPeerServers); max != "" { m, err := strconv.Atoi(max) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_MAX_STREAM_PEER_SERVERS, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvMaxStreamPeerServers, err) } currentConfig.MaxStreamPeerServers = m } - if lne := os.Getenv(SWARM_ENV_LIGHT_NODE_ENABLE); lne != "" { + if lne := os.Getenv(SwarmEnvLightNodeEnable); lne != "" { lightnode, err := strconv.ParseBool(lne) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_LIGHT_NODE_ENABLE, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvLightNodeEnable, err) } currentConfig.LightNodeEnabled = lightnode } - if swapapi := os.Getenv(SWARM_ENV_SWAP_API); swapapi != "" { + if swapapi := os.Getenv(SwarmEnvSwapAPI); swapapi != "" { currentConfig.SwapAPI = swapapi } if currentConfig.SwapEnabled && currentConfig.SwapAPI == "" { - utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) + utils.Fatalf(SwarmErrSwapSetNoAPI) } - if ensapi := os.Getenv(SWARM_ENV_ENS_API); ensapi != "" { + if ensapi := os.Getenv(SwarmEnvENSAPI); ensapi != "" { currentConfig.EnsAPIs = strings.Split(ensapi, ",") } - if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" { + if ensaddr := os.Getenv(SwarmEnvENSAddr); ensaddr != "" { currentConfig.EnsRoot = common.HexToAddress(ensaddr) } - if cors := os.Getenv(SWARM_ENV_CORS); cors != "" { + if cors := os.Getenv(SwarmEnvCORS); cors != "" { currentConfig.Cors = cors } + if bm := os.Getenv(SwarmEnvBootnodeMode); bm != "" { + bootnodeMode, err := strconv.ParseBool(bm) + if err != nil { + utils.Fatalf("invalid environment variable %s: %v", SwarmEnvBootnodeMode, err) + } + currentConfig.BootnodeMode = bootnodeMode + } + + if api := os.Getenv(SwarmGlobalstoreAPI); api != "" { + currentConfig.GlobalStoreAPI = api + } + return currentConfig } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config_test.go index 02198f87..869edd0f 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/config_test.go @@ -26,14 +26,14 @@ import ( "testing" "time" + "github.com/docker/docker/pkg/reexec" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm" "github.com/ethereum/go-ethereum/swarm/api" - - "github.com/docker/docker/pkg/reexec" ) -func TestDumpConfig(t *testing.T) { +func TestConfigDump(t *testing.T) { swarm := runSwarm(t, "dumpconfig") defaultConf := api.NewConfig() out, err := tomlSettings.Marshal(&defaultConf) @@ -52,7 +52,7 @@ func TestConfigFailsSwapEnabledNoSwapApi(t *testing.T) { } swarm := runSwarm(t, flags...) - swarm.Expect("Fatal: " + SWARM_ERR_SWAP_SET_NO_API + "\n") + swarm.Expect("Fatal: " + SwarmErrSwapSetNoAPI + "\n") swarm.ExpectExit() } @@ -63,7 +63,7 @@ func TestConfigFailsNoBzzAccount(t *testing.T) { } swarm := runSwarm(t, flags...) - swarm.Expect("Fatal: " + SWARM_ERR_NO_BZZACCOUNT + "\n") + swarm.Expect("Fatal: " + SwarmErrNoBZZAccount + "\n") swarm.ExpectExit() } @@ -91,8 +91,8 @@ func TestConfigCmdLineOverrides(t *testing.T) { fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), fmt.Sprintf("--%s", SwarmDeliverySkipCheckFlag.Name), fmt.Sprintf("--%s", EnsAPIFlag.Name), "", - "--datadir", dir, - "--ipcpath", conf.IPCPath, + fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, } node.Cmd = runSwarm(t, flags...) node.Cmd.InputLine(testPassphrase) @@ -189,9 +189,9 @@ func TestConfigFileOverrides(t *testing.T) { flags := []string{ fmt.Sprintf("--%s", SwarmTomlConfigPathFlag.Name), f.Name(), fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - "--ens-api", "", - "--ipcpath", conf.IPCPath, - "--datadir", dir, + fmt.Sprintf("--%s", EnsAPIFlag.Name), "", + fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, } node.Cmd = runSwarm(t, flags...) node.Cmd.InputLine(testPassphrase) @@ -407,9 +407,9 @@ func TestConfigCmdLineOverridesFile(t *testing.T) { fmt.Sprintf("--%s", SwarmSyncDisabledFlag.Name), fmt.Sprintf("--%s", SwarmTomlConfigPathFlag.Name), f.Name(), fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - "--ens-api", "", - "--datadir", dir, - "--ipcpath", conf.IPCPath, + fmt.Sprintf("--%s", EnsAPIFlag.Name), "", + fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, } node.Cmd = runSwarm(t, flags...) node.Cmd.InputLine(testPassphrase) @@ -466,7 +466,7 @@ func TestConfigCmdLineOverridesFile(t *testing.T) { node.Shutdown() } -func TestValidateConfig(t *testing.T) { +func TestConfigValidate(t *testing.T) { for _, c := range []struct { cfg *api.Config err string diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/explore.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/explore.go new file mode 100644 index 00000000..5b5b8bf4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/explore.go @@ -0,0 +1,59 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +// Command bzzhash computes a swarm tree hash. +package main + +import ( + "context" + "fmt" + "os" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/swarm/storage" + "gopkg.in/urfave/cli.v1" +) + +var hashesCommand = cli.Command{ + Action: hashes, + CustomHelpTemplate: helpTemplate, + Name: "hashes", + Usage: "print all hashes of a file to STDOUT", + ArgsUsage: "", + Description: "Prints all hashes of a file to STDOUT", +} + +func hashes(ctx *cli.Context) { + args := ctx.Args() + if len(args) < 1 { + utils.Fatalf("Usage: swarm hashes ") + } + f, err := os.Open(args[0]) + if err != nil { + utils.Fatalf("Error opening file " + args[1]) + } + defer f.Close() + + fileStore := storage.NewFileStore(&storage.FakeChunkStore{}, storage.NewFileStoreParams()) + refs, err := fileStore.GetAllReferences(context.TODO(), f, false) + if err != nil { + utils.Fatalf("%v\n", err) + } else { + for _, r := range refs { + fmt.Println(r.String()) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/export_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/export_test.go index f1bc2f26..e8671eea 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/export_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/export_test.go @@ -43,8 +43,8 @@ func TestCLISwarmExportImport(t *testing.T) { } cluster := newTestCluster(t, 1) - // generate random 10mb file - content := testutil.RandomBytes(1, 10000000) + // generate random 1mb file + content := testutil.RandomBytes(1, 1000000) fileName := testutil.TempFileWithContent(t, string(content)) defer os.Remove(fileName) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds.go index f26a8cc7..6cd971a9 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds.go @@ -169,7 +169,6 @@ func feedUpdate(ctx *cli.Context) { query = new(feed.Query) query.User = signer.Address() query.Topic = getTopic(ctx) - } // Retrieve a feed update request @@ -178,6 +177,11 @@ func feedUpdate(ctx *cli.Context) { utils.Fatalf("Error retrieving feed status: %s", err.Error()) } + // Check that the provided signer matches the request to sign + if updateRequest.User != signer.Address() { + utils.Fatalf("Signer address does not match the update request") + } + // set the new data updateRequest.SetData(data) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds_test.go index fc3f72ab..4c40f62a 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/feeds_test.go @@ -19,7 +19,6 @@ package main import ( "bytes" "encoding/json" - "fmt" "io/ioutil" "os" "testing" @@ -36,7 +35,6 @@ import ( ) func TestCLIFeedUpdate(t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, func(api *api.API) swarmhttp.TestServer { return swarmhttp.NewServer(api, "") }, nil) @@ -44,7 +42,6 @@ func TestCLIFeedUpdate(t *testing.T) { defer srv.Close() // create a private key file for signing - privkeyHex := "0000000000000000000000000000000000000000000000000000000000001979" privKey, _ := crypto.HexToECDSA(privkeyHex) address := crypto.PubkeyToAddress(privKey.PublicKey) @@ -71,7 +68,7 @@ func TestCLIFeedUpdate(t *testing.T) { hexData} // create an update and expect an exit without errors - log.Info(fmt.Sprintf("updating a feed with 'swarm feed update'")) + log.Info("updating a feed with 'swarm feed update'") cmd := runSwarm(t, flags...) cmd.ExpectExit() @@ -118,7 +115,7 @@ func TestCLIFeedUpdate(t *testing.T) { "--user", address.Hex(), } - log.Info(fmt.Sprintf("getting feed info with 'swarm feed info'")) + log.Info("getting feed info with 'swarm feed info'") cmd = runSwarm(t, flags...) _, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout cmd.ExpectExit() @@ -143,9 +140,9 @@ func TestCLIFeedUpdate(t *testing.T) { "--topic", topic.Hex(), } - log.Info(fmt.Sprintf("Publishing manifest with 'swarm feed create'")) + log.Info("Publishing manifest with 'swarm feed create'") cmd = runSwarm(t, flags...) - _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) // regex hack to extract stdout + _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) cmd.ExpectExit() manifestAddress := matches[0] // read the received feed manifest @@ -164,4 +161,36 @@ func TestCLIFeedUpdate(t *testing.T) { if !bytes.Equal(data, retrieved) { t.Fatalf("Received %s, expected %s", retrieved, data) } + + // test publishing a manifest for a different user + flags = []string{ + "--bzzapi", srv.URL, + "feed", "create", + "--topic", topic.Hex(), + "--user", "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // different user + } + + log.Info("Publishing manifest with 'swarm feed create' for a different user") + cmd = runSwarm(t, flags...) + _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) + cmd.ExpectExit() + + manifestAddress = matches[0] // read the received feed manifest + + // now let's try to update that user's manifest which we don't have the private key for + flags = []string{ + "--bzzapi", srv.URL, + "--bzzaccount", pkFileName, + "feed", "update", + "--manifest", manifestAddress, + hexData} + + // create an update and expect an error given there is a user mismatch + log.Info("updating a feed with 'swarm feed update'") + cmd = runSwarm(t, flags...) + cmd.ExpectRegexp("Fatal:.*") // best way so far to detect a failure. + cmd.ExpectExit() + if cmd.ExitStatus() == 0 { + t.Fatal("Expected nonzero exit code when updating a manifest with the wrong user. Got 0.") + } } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/flags.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/flags.go index 0dedca67..5e1ada63 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/flags.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/flags.go @@ -23,68 +23,68 @@ var ( ChequebookAddrFlag = cli.StringFlag{ Name: "chequebook", Usage: "chequebook contract address", - EnvVar: SWARM_ENV_CHEQUEBOOK_ADDR, + EnvVar: SwarmEnvChequebookAddr, } SwarmAccountFlag = cli.StringFlag{ Name: "bzzaccount", Usage: "Swarm account key file", - EnvVar: SWARM_ENV_ACCOUNT, + EnvVar: SwarmEnvAccount, } SwarmListenAddrFlag = cli.StringFlag{ Name: "httpaddr", Usage: "Swarm HTTP API listening interface", - EnvVar: SWARM_ENV_LISTEN_ADDR, + EnvVar: SwarmEnvListenAddr, } SwarmPortFlag = cli.StringFlag{ Name: "bzzport", Usage: "Swarm local http api port", - EnvVar: SWARM_ENV_PORT, + EnvVar: SwarmEnvPort, } SwarmNetworkIdFlag = cli.IntFlag{ Name: "bzznetworkid", Usage: "Network identifier (integer, default 3=swarm testnet)", - EnvVar: SWARM_ENV_NETWORK_ID, + EnvVar: SwarmEnvNetworkID, } SwarmSwapEnabledFlag = cli.BoolFlag{ Name: "swap", Usage: "Swarm SWAP enabled (default false)", - EnvVar: SWARM_ENV_SWAP_ENABLE, + EnvVar: SwarmEnvSwapEnable, } SwarmSwapAPIFlag = cli.StringFlag{ Name: "swap-api", Usage: "URL of the Ethereum API provider to use to settle SWAP payments", - EnvVar: SWARM_ENV_SWAP_API, + EnvVar: SwarmEnvSwapAPI, } SwarmSyncDisabledFlag = cli.BoolTFlag{ Name: "nosync", Usage: "Disable swarm syncing", - EnvVar: SWARM_ENV_SYNC_DISABLE, + EnvVar: SwarmEnvSyncDisable, } SwarmSyncUpdateDelay = cli.DurationFlag{ Name: "sync-update-delay", Usage: "Duration for sync subscriptions update after no new peers are added (default 15s)", - EnvVar: SWARM_ENV_SYNC_UPDATE_DELAY, + EnvVar: SwarmEnvSyncUpdateDelay, } SwarmMaxStreamPeerServersFlag = cli.IntFlag{ Name: "max-stream-peer-servers", Usage: "Limit of Stream peer servers, 0 denotes unlimited", - EnvVar: SWARM_ENV_MAX_STREAM_PEER_SERVERS, + EnvVar: SwarmEnvMaxStreamPeerServers, Value: 10000, // A very large default value is possible as stream servers have very small memory footprint } SwarmLightNodeEnabled = cli.BoolFlag{ Name: "lightnode", Usage: "Enable Swarm LightNode (default false)", - EnvVar: SWARM_ENV_LIGHT_NODE_ENABLE, + EnvVar: SwarmEnvLightNodeEnable, } SwarmDeliverySkipCheckFlag = cli.BoolFlag{ Name: "delivery-skip-check", Usage: "Skip chunk delivery check (default false)", - EnvVar: SWARM_ENV_DELIVERY_SKIP_CHECK, + EnvVar: SwarmEnvDeliverySkipCheck, } EnsAPIFlag = cli.StringSliceFlag{ Name: "ens-api", Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url", - EnvVar: SWARM_ENV_ENS_API, + EnvVar: SwarmEnvENSAPI, } SwarmApiFlag = cli.StringFlag{ Name: "bzzapi", @@ -126,7 +126,7 @@ var ( SwarmAccessPasswordFlag = cli.StringFlag{ Name: "password", Usage: "Password", - EnvVar: SWARM_ACCESS_PASSWORD, + EnvVar: SwarmAccessPassword, } SwarmDryRunFlag = cli.BoolFlag{ Name: "dry-run", @@ -135,27 +135,32 @@ var ( CorsStringFlag = cli.StringFlag{ Name: "corsdomain", Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')", - EnvVar: SWARM_ENV_CORS, + EnvVar: SwarmEnvCORS, } SwarmStorePath = cli.StringFlag{ Name: "store.path", Usage: "Path to leveldb chunk DB (default <$GETH_ENV_DIR>/swarm/bzz-<$BZZ_KEY>/chunks)", - EnvVar: SWARM_ENV_STORE_PATH, + EnvVar: SwarmEnvStorePath, } SwarmStoreCapacity = cli.Uint64Flag{ Name: "store.size", Usage: "Number of chunks (5M is roughly 20-25GB) (default 5000000)", - EnvVar: SWARM_ENV_STORE_CAPACITY, + EnvVar: SwarmEnvStoreCapacity, } SwarmStoreCacheCapacity = cli.UintFlag{ Name: "store.cache.size", - Usage: "Number of recent chunks cached in memory (default 5000)", - EnvVar: SWARM_ENV_STORE_CACHE_CAPACITY, + Usage: "Number of recent chunks cached in memory", + EnvVar: SwarmEnvStoreCacheCapacity, + Value: 10000, } SwarmCompressedFlag = cli.BoolFlag{ Name: "compressed", Usage: "Prints encryption keys in compressed form", } + SwarmBootnodeModeFlag = cli.BoolFlag{ + Name: "bootnode-mode", + Usage: "Run Swarm in Bootnode mode", + } SwarmFeedNameFlag = cli.StringFlag{ Name: "name", Usage: "User-defined name for the new feed, limited to 32 characters. If combined with topic, it will refer to a subtopic with this name", @@ -164,10 +169,6 @@ var ( Name: "topic", Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters", } - SwarmFeedDataOnCreateFlag = cli.StringFlag{ - Name: "data", - Usage: "Initializes the feed with the given hex-encoded data. Data must be prefixed by 0x", - } SwarmFeedManifestFlag = cli.StringFlag{ Name: "manifest", Usage: "Refers to the feed through a manifest", @@ -176,4 +177,9 @@ var ( Name: "user", Usage: "Indicates the user who updates the feed", } + SwarmGlobalStoreAPIFlag = cli.StringFlag{ + Name: "globalstore-api", + Usage: "URL of the Global Store API provider (only for testing)", + EnvVar: SwarmGlobalstoreAPI, + } ) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs.go index b970b2e8..7f156523 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs.go @@ -24,7 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm/fuse" "gopkg.in/urfave/cli.v1" @@ -41,27 +41,24 @@ var fsCommand = cli.Command{ Action: mount, CustomHelpTemplate: helpTemplate, Name: "mount", - Flags: []cli.Flag{utils.IPCPathFlag}, Usage: "mount a swarm hash to a mount point", - ArgsUsage: "swarm fs mount --ipcpath ", + ArgsUsage: "swarm fs mount ", Description: "Mounts a Swarm manifest hash to a given mount point. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", }, { Action: unmount, CustomHelpTemplate: helpTemplate, Name: "unmount", - Flags: []cli.Flag{utils.IPCPathFlag}, Usage: "unmount a swarmfs mount", - ArgsUsage: "swarm fs unmount --ipcpath ", + ArgsUsage: "swarm fs unmount ", Description: "Unmounts a swarmfs mount residing at . This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", }, { Action: listMounts, CustomHelpTemplate: helpTemplate, Name: "list", - Flags: []cli.Flag{utils.IPCPathFlag}, Usage: "list swarmfs mounts", - ArgsUsage: "swarm fs list --ipcpath ", + ArgsUsage: "swarm fs list", Description: "Lists all mounted swarmfs volumes. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", }, }, @@ -70,7 +67,7 @@ var fsCommand = cli.Command{ func mount(cliContext *cli.Context) { args := cliContext.Args() if len(args) < 2 { - utils.Fatalf("Usage: swarm fs mount --ipcpath ") + utils.Fatalf("Usage: swarm fs mount ") } client, err := dialRPC(cliContext) @@ -97,7 +94,7 @@ func unmount(cliContext *cli.Context) { args := cliContext.Args() if len(args) < 1 { - utils.Fatalf("Usage: swarm fs unmount --ipcpath ") + utils.Fatalf("Usage: swarm fs unmount ") } client, err := dialRPC(cliContext) if err != nil { @@ -126,7 +123,7 @@ func listMounts(cliContext *cli.Context) { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - mf := []fuse.MountInfo{} + var mf []fuse.MountInfo err = client.CallContext(ctx, &mf, "swarmfs_listmounts") if err != nil { utils.Fatalf("encountered an error calling the RPC endpoint while listing mounts: %v", err) @@ -145,20 +142,21 @@ func listMounts(cliContext *cli.Context) { } func dialRPC(ctx *cli.Context) (*rpc.Client, error) { - var endpoint string + endpoint := getIPCEndpoint(ctx) + log.Info("IPC endpoint", "path", endpoint) + return rpc.Dial(endpoint) +} - if ctx.IsSet(utils.IPCPathFlag.Name) { - endpoint = ctx.String(utils.IPCPathFlag.Name) - } else { - utils.Fatalf("swarm ipc endpoint not specified") - } +func getIPCEndpoint(ctx *cli.Context) string { + cfg := defaultNodeConfig + utils.SetNodeConfig(ctx, &cfg) - if endpoint == "" { - endpoint = node.DefaultIPCEndpoint(clientIdentifier) - } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { + endpoint := cfg.IPCEndpoint() + + if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { // Backwards compatibility with geth < 1.5 which required // these prefixes. endpoint = endpoint[4:] } - return rpc.Dial(endpoint) + return endpoint } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs_test.go index 3b722515..5f58d6c0 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/fs_test.go @@ -20,6 +20,7 @@ package main import ( "bytes" + "fmt" "io" "io/ioutil" "os" @@ -28,20 +29,35 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/log" - colorable "github.com/mattn/go-colorable" ) -func init() { - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - type testFile struct { filePath string content string } +// TestCLISwarmFsDefaultIPCPath tests if the most basic fs command, i.e., list +// can find and correctly connect to a running Swarm node on the default +// IPCPath. +func TestCLISwarmFsDefaultIPCPath(t *testing.T) { + cluster := newTestCluster(t, 1) + defer cluster.Shutdown() + + handlingNode := cluster.Nodes[0] + list := runSwarm(t, []string{ + "--datadir", handlingNode.Dir, + "fs", + "list", + }...) + + list.WaitExit() + if list.Err != nil { + t.Fatal(list.Err) + } +} + // TestCLISwarmFs is a high-level test of swarmfs // // This test fails on travis for macOS as this executable exits with code 1 @@ -65,9 +81,9 @@ func TestCLISwarmFs(t *testing.T) { log.Debug("swarmfs cli test: mounting first run", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) mount := runSwarm(t, []string{ + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), "fs", "mount", - "--ipcpath", filepath.Join(handlingNode.Dir, handlingNode.IpcPath), mhash, mountPoint, }...) @@ -107,9 +123,9 @@ func TestCLISwarmFs(t *testing.T) { log.Debug("swarmfs cli test: unmounting first run...", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) unmount := runSwarm(t, []string{ + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), "fs", "unmount", - "--ipcpath", filepath.Join(handlingNode.Dir, handlingNode.IpcPath), mountPoint, }...) _, matches := unmount.ExpectRegexp(hashRegexp) @@ -142,9 +158,9 @@ func TestCLISwarmFs(t *testing.T) { //remount, check files newMount := runSwarm(t, []string{ + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), "fs", "mount", - "--ipcpath", filepath.Join(handlingNode.Dir, handlingNode.IpcPath), hash, // the latest hash secondMountPoint, }...) @@ -178,9 +194,9 @@ func TestCLISwarmFs(t *testing.T) { log.Debug("swarmfs cli test: unmounting second run", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) unmountSec := runSwarm(t, []string{ + fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), "fs", "unmount", - "--ipcpath", filepath.Join(handlingNode.Dir, handlingNode.IpcPath), secondMountPoint, }...) diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/explorer.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/explorer.go new file mode 100644 index 00000000..634ff1eb --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/explorer.go @@ -0,0 +1,66 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "fmt" + "net" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + "github.com/ethereum/go-ethereum/swarm/storage/mock/explorer" + cli "gopkg.in/urfave/cli.v1" +) + +// serveChunkExplorer starts an http server in background with chunk explorer handler +// using the provided global store. Server is started if the returned shutdown function +// is not nil. +func serveChunkExplorer(ctx *cli.Context, globalStore mock.GlobalStorer) (shutdown func(), err error) { + if !ctx.IsSet("explorer-address") { + return nil, nil + } + + corsOrigins := ctx.StringSlice("explorer-cors-origin") + server := &http.Server{ + Handler: explorer.NewHandler(globalStore, corsOrigins), + IdleTimeout: 30 * time.Minute, + ReadTimeout: 2 * time.Minute, + WriteTimeout: 2 * time.Minute, + } + listener, err := net.Listen("tcp", ctx.String("explorer-address")) + if err != nil { + return nil, fmt.Errorf("explorer: %v", err) + } + log.Info("chunk explorer http", "address", listener.Addr().String(), "origins", corsOrigins) + + go func() { + if err := server.Serve(listener); err != nil { + log.Error("chunk explorer", "err", err) + } + }() + + return func() { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := server.Shutdown(ctx); err != nil { + log.Error("chunk explorer: shutdown", "err", err) + } + }, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/explorer_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/explorer_test.go new file mode 100644 index 00000000..2e4928c8 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/explorer_test.go @@ -0,0 +1,254 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "encoding/json" + "fmt" + "net/http" + "sort" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage/mock/explorer" + mockRPC "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" +) + +// TestExplorer validates basic chunk explorer functionality by storing +// a small set of chunk and making http requests on exposed endpoint. +// Full chunk explorer validation is done in mock/explorer package. +func TestExplorer(t *testing.T) { + addr := findFreeTCPAddress(t) + explorerAddr := findFreeTCPAddress(t) + testCmd := runGlobalStore(t, "ws", "--addr", addr, "--explorer-address", explorerAddr) + defer testCmd.Kill() + + client := websocketClient(t, addr) + + store := mockRPC.NewGlobalStore(client) + defer store.Close() + + nodeKeys := map[string][]string{ + "a1": {"b1", "b2", "b3"}, + "a2": {"b3", "b4", "b5"}, + } + + keyNodes := make(map[string][]string) + + for addr, keys := range nodeKeys { + for _, key := range keys { + keyNodes[key] = append(keyNodes[key], addr) + } + } + + invalidAddr := "c1" + invalidKey := "d1" + + for addr, keys := range nodeKeys { + for _, key := range keys { + err := store.Put(common.HexToAddress(addr), common.Hex2Bytes(key), []byte("data")) + if err != nil { + t.Fatal(err) + } + } + } + + endpoint := "http://" + explorerAddr + + t.Run("has key", func(t *testing.T) { + for addr, keys := range nodeKeys { + for _, key := range keys { + testStatusResponse(t, endpoint+"/api/has-key/"+addr+"/"+key, http.StatusOK) + testStatusResponse(t, endpoint+"/api/has-key/"+invalidAddr+"/"+key, http.StatusNotFound) + } + testStatusResponse(t, endpoint+"/api/has-key/"+addr+"/"+invalidKey, http.StatusNotFound) + } + testStatusResponse(t, endpoint+"/api/has-key/"+invalidAddr+"/"+invalidKey, http.StatusNotFound) + }) + + t.Run("keys", func(t *testing.T) { + var keys []string + for key := range keyNodes { + keys = append(keys, key) + } + sort.Strings(keys) + testKeysResponse(t, endpoint+"/api/keys", explorer.KeysResponse{ + Keys: keys, + }) + }) + + t.Run("nodes", func(t *testing.T) { + var nodes []string + for addr := range nodeKeys { + nodes = append(nodes, common.HexToAddress(addr).Hex()) + } + sort.Strings(nodes) + testNodesResponse(t, endpoint+"/api/nodes", explorer.NodesResponse{ + Nodes: nodes, + }) + }) + + t.Run("node keys", func(t *testing.T) { + for addr, keys := range nodeKeys { + testKeysResponse(t, endpoint+"/api/keys?node="+addr, explorer.KeysResponse{ + Keys: keys, + }) + } + testKeysResponse(t, endpoint+"/api/keys?node="+invalidAddr, explorer.KeysResponse{}) + }) + + t.Run("key nodes", func(t *testing.T) { + for key, addrs := range keyNodes { + var nodes []string + for _, addr := range addrs { + nodes = append(nodes, common.HexToAddress(addr).Hex()) + } + sort.Strings(nodes) + testNodesResponse(t, endpoint+"/api/nodes?key="+key, explorer.NodesResponse{ + Nodes: nodes, + }) + } + testNodesResponse(t, endpoint+"/api/nodes?key="+invalidKey, explorer.NodesResponse{}) + }) +} + +// TestExplorer_CORSOrigin validates if chunk explorer returns +// correct CORS origin header in GET and OPTIONS requests. +func TestExplorer_CORSOrigin(t *testing.T) { + origin := "http://localhost/" + addr := findFreeTCPAddress(t) + explorerAddr := findFreeTCPAddress(t) + testCmd := runGlobalStore(t, "ws", + "--addr", addr, + "--explorer-address", explorerAddr, + "--explorer-cors-origin", origin, + ) + defer testCmd.Kill() + + // wait until the server is started + waitHTTPEndpoint(t, explorerAddr) + + url := "http://" + explorerAddr + "/api/keys" + + t.Run("get", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Origin", origin) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + header := resp.Header.Get("Access-Control-Allow-Origin") + if header != origin { + t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, origin) + } + }) + + t.Run("preflight", func(t *testing.T) { + req, err := http.NewRequest(http.MethodOptions, url, nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Origin", origin) + req.Header.Set("Access-Control-Request-Method", "GET") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + header := resp.Header.Get("Access-Control-Allow-Origin") + if header != origin { + t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, origin) + } + }) +} + +// testStatusResponse makes an http request to provided url +// and validates if response is explorer.StatusResponse for +// the expected status code. +func testStatusResponse(t *testing.T, url string, code int) { + t.Helper() + + resp, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + if resp.StatusCode != code { + t.Errorf("got status code %v, want %v", resp.StatusCode, code) + } + var r explorer.StatusResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + t.Fatal(err) + } + if r.Code != code { + t.Errorf("got response code %v, want %v", r.Code, code) + } + if r.Message != http.StatusText(code) { + t.Errorf("got response message %q, want %q", r.Message, http.StatusText(code)) + } +} + +// testKeysResponse makes an http request to provided url +// and validates if response machhes expected explorer.KeysResponse. +func testKeysResponse(t *testing.T, url string, want explorer.KeysResponse) { + t.Helper() + + resp, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) + } + var r explorer.KeysResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + t.Fatal(err) + } + if fmt.Sprint(r.Keys) != fmt.Sprint(want.Keys) { + t.Errorf("got keys %v, want %v", r.Keys, want.Keys) + } + if r.Next != want.Next { + t.Errorf("got next %s, want %s", r.Next, want.Next) + } +} + +// testNodeResponse makes an http request to provided url +// and validates if response machhes expected explorer.NodeResponse. +func testNodesResponse(t *testing.T, url string, want explorer.NodesResponse) { + t.Helper() + + resp, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) + } + var r explorer.NodesResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + t.Fatal(err) + } + if fmt.Sprint(r.Nodes) != fmt.Sprint(want.Nodes) { + t.Errorf("got nodes %v, want %v", r.Nodes, want.Nodes) + } + if r.Next != want.Next { + t.Errorf("got next %s, want %s", r.Next, want.Next) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/global_store.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/global_store.go new file mode 100644 index 00000000..f93b464d --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/global_store.go @@ -0,0 +1,120 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "io" + "net" + "net/http" + "os" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + "github.com/ethereum/go-ethereum/swarm/storage/mock/db" + "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" + cli "gopkg.in/urfave/cli.v1" +) + +// startHTTP starts a global store with HTTP RPC server. +// It is used for "http" cli command. +func startHTTP(ctx *cli.Context) (err error) { + server, cleanup, err := newServer(ctx) + if err != nil { + return err + } + defer cleanup() + + listener, err := net.Listen("tcp", ctx.String("addr")) + if err != nil { + return err + } + log.Info("http", "address", listener.Addr().String()) + + return http.Serve(listener, server) +} + +// startWS starts a global store with WebSocket RPC server. +// It is used for "websocket" cli command. +func startWS(ctx *cli.Context) (err error) { + server, cleanup, err := newServer(ctx) + if err != nil { + return err + } + defer cleanup() + + listener, err := net.Listen("tcp", ctx.String("addr")) + if err != nil { + return err + } + origins := ctx.StringSlice("origins") + log.Info("websocket", "address", listener.Addr().String(), "origins", origins) + + return http.Serve(listener, server.WebsocketHandler(origins)) +} + +// newServer creates a global store and starts a chunk explorer server if configured. +// Returned cleanup function should be called only if err is nil. +func newServer(ctx *cli.Context) (server *rpc.Server, cleanup func(), err error) { + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(false)))) + + cleanup = func() {} + var globalStore mock.GlobalStorer + dir := ctx.String("dir") + if dir != "" { + dbStore, err := db.NewGlobalStore(dir) + if err != nil { + return nil, nil, err + } + cleanup = func() { + if err := dbStore.Close(); err != nil { + log.Error("global store: close", "err", err) + } + } + globalStore = dbStore + log.Info("database global store", "dir", dir) + } else { + globalStore = mem.NewGlobalStore() + log.Info("in-memory global store") + } + + server = rpc.NewServer() + if err := server.RegisterName("mockStore", globalStore); err != nil { + cleanup() + return nil, nil, err + } + + shutdown, err := serveChunkExplorer(ctx, globalStore) + if err != nil { + cleanup() + return nil, nil, err + } + if shutdown != nil { + cleanup = func() { + shutdown() + + if c, ok := globalStore.(io.Closer); ok { + if err := c.Close(); err != nil { + log.Error("global store: close", "err", err) + } + } + } + } + + return server, cleanup, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/global_store_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/global_store_test.go new file mode 100644 index 00000000..c437c9d4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/global_store_test.go @@ -0,0 +1,207 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "io/ioutil" + "net" + "net/http" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rpc" + mockRPC "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" +) + +// TestHTTP_InMemory tests in-memory global store that exposes +// HTTP server. +func TestHTTP_InMemory(t *testing.T) { + testHTTP(t, true) +} + +// TestHTTP_Database tests global store with persisted database +// that exposes HTTP server. +func TestHTTP_Database(t *testing.T) { + dir, err := ioutil.TempDir("", "swarm-global-store-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // create a fresh global store + testHTTP(t, true, "--dir", dir) + + // check if data saved by the previous global store instance + testHTTP(t, false, "--dir", dir) +} + +// testWebsocket starts global store binary with HTTP server +// and validates that it can store and retrieve data. +// If put is false, no data will be stored, only retrieved, +// giving the possibility to check if data is present in the +// storage directory. +func testHTTP(t *testing.T, put bool, args ...string) { + addr := findFreeTCPAddress(t) + testCmd := runGlobalStore(t, append([]string{"http", "--addr", addr}, args...)...) + defer testCmd.Kill() + + client, err := rpc.DialHTTP("http://" + addr) + if err != nil { + t.Fatal(err) + } + + // wait until global store process is started as + // rpc.DialHTTP is actually not connecting + waitHTTPEndpoint(t, addr) + + store := mockRPC.NewGlobalStore(client) + defer store.Close() + + node := store.NewNodeStore(common.HexToAddress("123abc")) + + wantKey := "key" + wantValue := "value" + + if put { + err = node.Put([]byte(wantKey), []byte(wantValue)) + if err != nil { + t.Fatal(err) + } + } + + gotValue, err := node.Get([]byte(wantKey)) + if err != nil { + t.Fatal(err) + } + + if string(gotValue) != wantValue { + t.Errorf("got value %s for key %s, want %s", string(gotValue), wantKey, wantValue) + } +} + +// TestWebsocket_InMemory tests in-memory global store that exposes +// WebSocket server. +func TestWebsocket_InMemory(t *testing.T) { + testWebsocket(t, true) +} + +// TestWebsocket_Database tests global store with persisted database +// that exposes HTTP server. +func TestWebsocket_Database(t *testing.T) { + dir, err := ioutil.TempDir("", "swarm-global-store-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // create a fresh global store + testWebsocket(t, true, "--dir", dir) + + // check if data saved by the previous global store instance + testWebsocket(t, false, "--dir", dir) +} + +// testWebsocket starts global store binary with WebSocket server +// and validates that it can store and retrieve data. +// If put is false, no data will be stored, only retrieved, +// giving the possibility to check if data is present in the +// storage directory. +func testWebsocket(t *testing.T, put bool, args ...string) { + addr := findFreeTCPAddress(t) + testCmd := runGlobalStore(t, append([]string{"ws", "--addr", addr}, args...)...) + defer testCmd.Kill() + + client := websocketClient(t, addr) + + store := mockRPC.NewGlobalStore(client) + defer store.Close() + + node := store.NewNodeStore(common.HexToAddress("123abc")) + + wantKey := "key" + wantValue := "value" + + if put { + err := node.Put([]byte(wantKey), []byte(wantValue)) + if err != nil { + t.Fatal(err) + } + } + + gotValue, err := node.Get([]byte(wantKey)) + if err != nil { + t.Fatal(err) + } + + if string(gotValue) != wantValue { + t.Errorf("got value %s for key %s, want %s", string(gotValue), wantKey, wantValue) + } +} + +// findFreeTCPAddress returns a local address (IP:Port) to which +// global store can listen on. +func findFreeTCPAddress(t *testing.T) (addr string) { + t.Helper() + + listener, err := net.Listen("tcp", "") + if err != nil { + t.Fatal(err) + } + defer listener.Close() + + return listener.Addr().String() +} + +// websocketClient waits until global store process is started +// and returns rpc client. +func websocketClient(t *testing.T, addr string) (client *rpc.Client) { + t.Helper() + + var err error + for i := 0; i < 1000; i++ { + client, err = rpc.DialWebsocket(context.Background(), "ws://"+addr, "") + if err == nil { + break + } + time.Sleep(10 * time.Millisecond) + } + if err != nil { + t.Fatal(err) + } + return client +} + +// waitHTTPEndpoint retries http requests to a provided +// address until the connection is established. +func waitHTTPEndpoint(t *testing.T, addr string) { + t.Helper() + + var err error + for i := 0; i < 1000; i++ { + _, err = http.Get("http://" + addr) + if err == nil { + break + } + time.Sleep(10 * time.Millisecond) + } + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/main.go new file mode 100644 index 00000000..52fafc8f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/main.go @@ -0,0 +1,120 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "os" + + "github.com/ethereum/go-ethereum/log" + cli "gopkg.in/urfave/cli.v1" +) + +var ( + version = "0.1" + gitCommit string // Git SHA1 commit hash of the release (set via linker flags) +) + +func main() { + err := newApp().Run(os.Args) + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } +} + +// newApp construct a new instance of Swarm Global Store. +// Method Run is called on it in the main function and in tests. +func newApp() (app *cli.App) { + app = cli.NewApp() + app.Name = "global-store" + app.Version = version + if len(gitCommit) >= 8 { + app.Version += "-" + gitCommit[:8] + } + app.Usage = "Swarm Global Store" + + // app flags (for all commands) + app.Flags = []cli.Flag{ + cli.IntFlag{ + Name: "verbosity", + Value: 3, + Usage: "Verbosity level.", + }, + cli.StringFlag{ + Name: "explorer-address", + Value: "", + Usage: "Chunk explorer HTTP listener address.", + }, + cli.StringSliceFlag{ + Name: "explorer-cors-origin", + Value: nil, + Usage: "Chunk explorer CORS origin (can be specified multiple times).", + }, + } + + app.Commands = []cli.Command{ + { + Name: "http", + Aliases: []string{"h"}, + Usage: "Start swarm global store with HTTP server.", + Action: startHTTP, + // Flags only for "start" command. + // Allow app flags to be specified after the + // command argument. + Flags: append(app.Flags, + cli.StringFlag{ + Name: "dir", + Value: "", + Usage: "Data directory.", + }, + cli.StringFlag{ + Name: "addr", + Value: "0.0.0.0:3033", + Usage: "Address to listen for HTTP connections.", + }, + ), + }, + { + Name: "websocket", + Aliases: []string{"ws"}, + Usage: "Start swarm global store with WebSocket server.", + Action: startWS, + // Flags only for "start" command. + // Allow app flags to be specified after the + // command argument. + Flags: append(app.Flags, + cli.StringFlag{ + Name: "dir", + Value: "", + Usage: "Data directory.", + }, + cli.StringFlag{ + Name: "addr", + Value: "0.0.0.0:3033", + Usage: "Address to listen for WebSocket connections.", + }, + cli.StringSliceFlag{ + Name: "origin", + Value: nil, + Usage: "WebSocket CORS origin (can be specified multiple times).", + }, + ), + }, + } + + return app +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/run_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/run_test.go new file mode 100644 index 00000000..d7ef626e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/global-store/run_test.go @@ -0,0 +1,49 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "os" + "testing" + + "github.com/docker/docker/pkg/reexec" + "github.com/ethereum/go-ethereum/internal/cmdtest" +) + +func init() { + reexec.Register("swarm-global-store", func() { + if err := newApp().Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Exit(0) + }) +} + +func runGlobalStore(t *testing.T, args ...string) *cmdtest.TestCmd { + tt := cmdtest.NewTestCmd(t, nil) + tt.Run("swarm-global-store", args...) + return tt +} + +func TestMain(m *testing.M) { + if reexec.Init() { + return + } + os.Exit(m.Run()) +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/hash.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/hash.go index 471feb53..2df02c0e 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/hash.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/hash.go @@ -19,10 +19,13 @@ package main import ( "context" + "encoding/hex" "fmt" "os" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/ens" "github.com/ethereum/go-ethereum/swarm/storage" "gopkg.in/urfave/cli.v1" ) @@ -34,7 +37,33 @@ var hashCommand = cli.Command{ Usage: "print the swarm hash of a file or directory", ArgsUsage: "", Description: "Prints the swarm hash of file or directory", -} + Subcommands: []cli.Command{ + { + CustomHelpTemplate: helpTemplate, + Name: "ens", + Usage: "converts a swarm hash to an ens EIP1577 compatible CIDv1 hash", + ArgsUsage: "", + Description: "", + Subcommands: []cli.Command{ + { + Action: encodeEipHash, + CustomHelpTemplate: helpTemplate, + Name: "contenthash", + Usage: "converts a swarm hash to an ens EIP1577 compatible CIDv1 hash", + ArgsUsage: "", + Description: "", + }, + { + Action: ensNodeHash, + CustomHelpTemplate: helpTemplate, + Name: "node", + Usage: "converts an ens name to an ENS node hash", + ArgsUsage: "", + Description: "", + }, + }, + }, + }} func hash(ctx *cli.Context) { args := ctx.Args() @@ -56,3 +85,31 @@ func hash(ctx *cli.Context) { fmt.Printf("%v\n", addr) } } +func ensNodeHash(ctx *cli.Context) { + args := ctx.Args() + if len(args) < 1 { + utils.Fatalf("Usage: swarm hash ens node ") + } + ensName := args[0] + + hash := ens.EnsNode(ensName) + + stringHex := hex.EncodeToString(hash[:]) + fmt.Println(stringHex) +} +func encodeEipHash(ctx *cli.Context) { + args := ctx.Args() + if len(args) < 1 { + utils.Fatalf("Usage: swarm hash ens ") + } + swarmHash := args[0] + + hash := common.HexToHash(swarmHash) + ensHash, err := ens.EncodeSwarmHash(hash) + if err != nil { + utils.Fatalf("error converting swarm hash", err) + } + + stringHex := hex.EncodeToString(ensHash) + fmt.Println(stringHex) +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/main.go index ccbb24ee..a4041eb3 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/main.go @@ -39,13 +39,16 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm" bzzapi "github.com/ethereum/go-ethereum/swarm/api" swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + mockrpc "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" "github.com/ethereum/go-ethereum/swarm/tracing" sv "github.com/ethereum/go-ethereum/swarm/version" - "gopkg.in/urfave/cli.v1" + cli "gopkg.in/urfave/cli.v1" ) const clientIdentifier = "swarm" @@ -66,14 +69,15 @@ OPTIONS: {{end}}{{end}} ` -var ( - gitCommit string // Git SHA1 commit hash of the release (set via linker flags) -) +// Git SHA1 commit hash of the release (set via linker flags) +// this variable will be assigned if corresponding parameter is passed with install, but not with test +// e.g.: go install -ldflags "-X main.gitCommit=ed1312d01b19e04ef578946226e5d8069d5dfd5a" ./cmd/swarm +var gitCommit string //declare a few constant error messages, useful for later error check comparisons in test var ( - SWARM_ERR_NO_BZZACCOUNT = "bzzaccount option is required but not set; check your config file, command line or environment variables" - SWARM_ERR_SWAP_SET_NO_API = "SWAP is enabled but --swap-api is not set" + SwarmErrNoBZZAccount = "bzzaccount option is required but not set; check your config file, command line or environment variables" + SwarmErrSwapSetNoAPI = "SWAP is enabled but --swap-api is not set" ) // this help command gets added to any subcommand that does not define it explicitly @@ -89,6 +93,7 @@ var defaultNodeConfig = node.DefaultConfig // This init function sets defaults so cmd/swarm can run alongside geth. func init() { + sv.GitCommit = gitCommit defaultNodeConfig.Name = clientIdentifier defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit) defaultNodeConfig.P2P.ListenAddr = ":30399" @@ -140,6 +145,8 @@ func init() { dbCommand, // See config.go DumpConfigCommand, + // hashesCommand + hashesCommand, } // append a hidden help subcommand to all commands that have subcommands @@ -154,7 +161,6 @@ func init() { utils.BootnodesFlag, utils.KeyStoreDirFlag, utils.ListenPortFlag, - utils.NoDiscoverFlag, utils.DiscoveryV5Flag, utils.NetrestrictFlag, utils.NodeKeyFileFlag, @@ -187,10 +193,13 @@ func init() { SwarmUploadDefaultPath, SwarmUpFromStdinFlag, SwarmUploadMimeType, + // bootnode mode + SwarmBootnodeModeFlag, // storage flags SwarmStorePath, SwarmStoreCapacity, SwarmStoreCacheCapacity, + SwarmGlobalStoreAPIFlag, } rpcFlags := []cli.Flag{ utils.WSEnabledFlag, @@ -227,12 +236,17 @@ func main() { func keys(ctx *cli.Context) error { privateKey := getPrivKey(ctx) - pub := hex.EncodeToString(crypto.FromECDSAPub(&privateKey.PublicKey)) + pubkey := crypto.FromECDSAPub(&privateKey.PublicKey) + pubkeyhex := hex.EncodeToString(pubkey) pubCompressed := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)) + bzzkey := crypto.Keccak256Hash(pubkey).Hex() + if !ctx.Bool(SwarmCompressedFlag.Name) { - fmt.Println(fmt.Sprintf("publicKey=%s", pub)) + fmt.Println(fmt.Sprintf("bzzkey=%s", bzzkey[2:])) + fmt.Println(fmt.Sprintf("publicKey=%s", pubkeyhex)) } fmt.Println(fmt.Sprintf("publicKeyCompressed=%s", pubCompressed)) + return nil } @@ -272,14 +286,22 @@ func bzzd(ctx *cli.Context) error { setSwarmBootstrapNodes(ctx, &cfg) //setup the ethereum node utils.SetNodeConfig(ctx, &cfg) + + //disable dynamic dialing from p2p/discovery + cfg.P2P.NoDial = true + stack, err := node.New(&cfg) if err != nil { utils.Fatalf("can't create node: %v", err) } + defer stack.Close() //a few steps need to be done after the config phase is completed, //due to overriding behavior - initSwarmNode(bzzconfig, stack, ctx) + err = initSwarmNode(bzzconfig, stack, ctx, &cfg) + if err != nil { + return err + } //register BZZ as node.Service in the ethereum node registerBzzService(bzzconfig, stack) //start the node @@ -294,6 +316,15 @@ func bzzd(ctx *cli.Context) error { stack.Stop() }() + // add swarm bootnodes, because swarm doesn't use p2p package's discovery discv5 + go func() { + s := stack.Server() + + for _, n := range cfg.P2P.BootstrapNodes { + s.AddPeer(n) + } + }() + stack.Wait() return nil } @@ -301,8 +332,18 @@ func bzzd(ctx *cli.Context) error { func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) { //define the swarm service boot function boot := func(_ *node.ServiceContext) (node.Service, error) { - // In production, mockStore must be always nil. - return swarm.NewSwarm(bzzconfig, nil) + var nodeStore *mock.NodeStore + if bzzconfig.GlobalStoreAPI != "" { + // connect to global store + client, err := rpc.Dial(bzzconfig.GlobalStoreAPI) + if err != nil { + return nil, fmt.Errorf("global store: %v", err) + } + globalStore := mockrpc.NewGlobalStore(client) + // create a node store for this swarm key on global store + nodeStore = globalStore.NewNodeStore(common.HexToAddress(bzzconfig.BzzKey)) + } + return swarm.NewSwarm(bzzconfig, nodeStore) } //register within the ethereum node if err := stack.Register(boot); err != nil { @@ -313,7 +354,7 @@ func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) { func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { //an account is mandatory if bzzaccount == "" { - utils.Fatalf(SWARM_ERR_NO_BZZACCOUNT) + utils.Fatalf(SwarmErrNoBZZAccount) } // Try to load the arg as a hex key file. if key, err := crypto.LoadECDSA(bzzaccount); err == nil { @@ -344,6 +385,8 @@ func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey { if err != nil { utils.Fatalf("can't create node: %v", err) } + defer stack.Close() + return getAccount(bzzconfig.BzzAccount, ctx, stack) } @@ -428,5 +471,5 @@ func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) { } cfg.P2P.BootstrapNodes = append(cfg.P2P.BootstrapNodes, node) } - log.Debug("added default swarm bootnodes", "length", len(cfg.P2P.BootstrapNodes)) + } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/run_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/run_test.go index 416fa7a5..9681c899 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/run_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/run_test.go @@ -57,6 +57,17 @@ func init() { }) } +const clusterSize = 3 + +var clusteronce sync.Once +var cluster *testCluster + +func initCluster(t *testing.T) { + clusteronce.Do(func() { + cluster = newTestCluster(t, clusterSize) + }) +} + func serverFunc(api *api.API) swarmhttp.TestServer { return swarmhttp.NewServer(api, "") } @@ -71,6 +82,18 @@ func TestMain(m *testing.M) { func runSwarm(t *testing.T, args ...string) *cmdtest.TestCmd { tt := cmdtest.NewTestCmd(t, nil) + found := false + for _, v := range args { + if v == "--bootnodes" { + found = true + break + } + } + + if !found { + args = append([]string{"--bootnodes", ""}, args...) + } + // Boot "swarm". This actually runs the test binary but the TestMain // function will prevent any tests from running. tt.Run("swarm-test", args...) @@ -241,9 +264,9 @@ func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode { // start the node node.Cmd = runSwarm(t, + "--bootnodes", "", "--port", p2pPort, "--nat", "extip:127.0.0.1", - "--nodiscover", "--datadir", dir, "--ipcpath", conf.IPCPath, "--ens-api", "", @@ -317,9 +340,9 @@ func newTestNode(t *testing.T, dir string) *testNode { // start the node node.Cmd = runSwarm(t, + "--bootnodes", "", "--port", p2pPort, "--nat", "extip:127.0.0.1", - "--nodiscover", "--datadir", dir, "--ipcpath", conf.IPCPath, "--ens-api", "", diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/feed_upload_and_sync.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/feed_upload_and_sync.go index 1371d665..6b3fed0c 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/feed_upload_and_sync.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/feed_upload_and_sync.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "io/ioutil" - "net/http" "os" "os/exec" "strings" @@ -16,9 +15,9 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/multihash" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/swarm/storage/feed" - colorable "github.com/mattn/go-colorable" + "github.com/ethereum/go-ethereum/swarm/testutil" "github.com/pborman/uuid" cli "gopkg.in/urfave/cli.v1" ) @@ -27,16 +26,28 @@ const ( feedRandomDataLength = 8 ) -// TODO: retrieve with manifest + extract repeating code -func cliFeedUploadAndSync(c *cli.Context) error { +func feedUploadAndSyncCmd(ctx *cli.Context, tuid string) error { + errc := make(chan error) - log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(verbosity), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))) + go func() { + errc <- feedUploadAndSync(ctx, tuid) + }() - defer func(now time.Time) { log.Info("total time", "time", time.Since(now), "size (kb)", filesize) }(time.Now()) + select { + case err := <-errc: + if err != nil { + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) + } + return err + case <-time.After(time.Duration(timeout) * time.Second): + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) - generateEndpoints(scheme, cluster, from, to) + return fmt.Errorf("timeout after %v sec", timeout) + } +} - log.Info("generating and uploading MRUs to " + endpoints[0] + " and syncing") +func feedUploadAndSync(c *cli.Context, tuid string) error { + log.Info("generating and uploading feeds to " + httpEndpoint(hosts[0]) + " and syncing") // create a random private key to sign updates with and derive the address pkFile, err := ioutil.TempFile("", "swarm-feed-smoke-test") @@ -90,7 +101,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { // create feed manifest, topic only var out bytes.Buffer - cmd := exec.Command("swarm", "--bzzapi", endpoints[0], "feed", "create", "--topic", topicHex, "--user", userHex) + cmd := exec.Command("swarm", "--bzzapi", httpEndpoint(hosts[0]), "feed", "create", "--topic", topicHex, "--user", userHex) cmd.Stdout = &out log.Debug("create feed manifest topic cmd", "cmd", cmd) err = cmd.Run() @@ -105,7 +116,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { out.Reset() // create feed manifest, subtopic only - cmd = exec.Command("swarm", "--bzzapi", endpoints[0], "feed", "create", "--name", subTopicHex, "--user", userHex) + cmd = exec.Command("swarm", "--bzzapi", httpEndpoint(hosts[0]), "feed", "create", "--name", subTopicHex, "--user", userHex) cmd.Stdout = &out log.Debug("create feed manifest subtopic cmd", "cmd", cmd) err = cmd.Run() @@ -120,7 +131,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { out.Reset() // create feed manifest, merged topic - cmd = exec.Command("swarm", "--bzzapi", endpoints[0], "feed", "create", "--topic", topicHex, "--name", subTopicHex, "--user", userHex) + cmd = exec.Command("swarm", "--bzzapi", httpEndpoint(hosts[0]), "feed", "create", "--topic", topicHex, "--name", subTopicHex, "--user", userHex) cmd.Stdout = &out log.Debug("create feed manifest mergetopic cmd", "cmd", cmd) err = cmd.Run() @@ -146,7 +157,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { dataHex := hexutil.Encode(data) // update with topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, dataHex) + cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, dataHex) cmd.Stdout = &out log.Debug("update feed manifest topic cmd", "cmd", cmd) err = cmd.Run() @@ -157,7 +168,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { out.Reset() // update with subtopic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--name", subTopicHex, dataHex) + cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--name", subTopicHex, dataHex) cmd.Stdout = &out log.Debug("update feed manifest subtopic cmd", "cmd", cmd) err = cmd.Run() @@ -168,7 +179,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { out.Reset() // update with merged topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, "--name", subTopicHex, dataHex) + cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, "--name", subTopicHex, dataHex) cmd.Stdout = &out log.Debug("update feed manifest merged topic cmd", "cmd", cmd) err = cmd.Run() @@ -182,14 +193,14 @@ func cliFeedUploadAndSync(c *cli.Context) error { // retrieve the data wg := sync.WaitGroup{} - for _, endpoint := range endpoints { + for _, host := range hosts { // raw retrieve, topic only for _, hex := range []string{topicHex, subTopicOnlyHex, mergedSubTopicHex} { wg.Add(1) ruid := uuid.New()[:8] go func(hex string, endpoint string, ruid string) { for { - err := fetchFeed(hex, userHex, endpoint, dataHash, ruid) + err := fetchFeed(hex, userHex, httpEndpoint(host), dataHash, ruid) if err != nil { continue } @@ -197,20 +208,18 @@ func cliFeedUploadAndSync(c *cli.Context) error { wg.Done() return } - }(hex, endpoint, ruid) - + }(hex, httpEndpoint(host), ruid) } } wg.Wait() log.Info("all endpoints synced random data successfully") // upload test file - log.Info("uploading to " + endpoints[0] + " and syncing") + log.Info("feed uploading to "+httpEndpoint(hosts[0])+" and syncing", "seed", seed) - f, cleanup := generateRandomFile(filesize * 1000) - defer cleanup() + randomBytes := testutil.RandomBytes(seed, filesize*1000) - hash, err := upload(f, endpoints[0]) + hash, err := upload(randomBytes, httpEndpoint(hosts[0])) if err != nil { return err } @@ -218,17 +227,13 @@ func cliFeedUploadAndSync(c *cli.Context) error { if err != nil { return err } - multihashHex := hexutil.Encode(multihash.ToMultihash(hashBytes)) - - fileHash, err := digest(f) - if err != nil { - return err - } + multihashHex := hexutil.Encode(hashBytes) + fileHash := h.Sum(nil) log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fileHash)) // update file with topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, multihashHex) + cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, multihashHex) cmd.Stdout = &out err = cmd.Run() if err != nil { @@ -238,7 +243,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { out.Reset() // update file with subtopic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--name", subTopicHex, multihashHex) + cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--name", subTopicHex, multihashHex) cmd.Stdout = &out err = cmd.Run() if err != nil { @@ -248,7 +253,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { out.Reset() // update file with merged topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, "--name", subTopicHex, multihashHex) + cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, "--name", subTopicHex, multihashHex) cmd.Stdout = &out err = cmd.Run() if err != nil { @@ -259,7 +264,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { time.Sleep(3 * time.Second) - for _, endpoint := range endpoints { + for _, host := range hosts { // manifest retrieve, topic only for _, url := range []string{manifestWithTopic, manifestWithSubTopic, manifestWithMergedTopic} { @@ -267,7 +272,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { ruid := uuid.New()[:8] go func(url string, endpoint string, ruid string) { for { - err := fetch(url, endpoint, fileHash, ruid) + err := fetch(url, endpoint, fileHash, ruid, "") if err != nil { continue } @@ -275,7 +280,7 @@ func cliFeedUploadAndSync(c *cli.Context) error { wg.Done() return } - }(url, endpoint, ruid) + }(url, httpEndpoint(host), ruid) } } @@ -284,37 +289,3 @@ func cliFeedUploadAndSync(c *cli.Context) error { return nil } - -func fetchFeed(topic string, user string, endpoint string, original []byte, ruid string) error { - log.Trace("sleeping", "ruid", ruid) - time.Sleep(3 * time.Second) - - log.Trace("http get request (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user) - res, err := http.Get(endpoint + "/bzz-feed:/?topic=" + topic + "&user=" + user) - if err != nil { - return err - } - log.Trace("http get response (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user, "code", res.StatusCode, "len", res.ContentLength) - - if res.StatusCode != 200 { - return fmt.Errorf("expected status code %d, got %v (ruid %v)", 200, res.StatusCode, ruid) - } - - defer res.Body.Close() - - rdigest, err := digest(res.Body) - if err != nil { - log.Warn(err.Error(), "ruid", ruid) - return err - } - - if !bytes.Equal(rdigest, original) { - err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) - log.Warn(err.Error(), "ruid", ruid) - return err - } - - log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) - - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/main.go index 97054dd4..860fbcc1 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/main.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/main.go @@ -17,23 +17,37 @@ package main import ( + "fmt" "os" "sort" + "github.com/ethereum/go-ethereum/cmd/utils" + gethmetrics "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/metrics/influxdb" + swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics" + "github.com/ethereum/go-ethereum/swarm/tracing" + "github.com/ethereum/go-ethereum/log" cli "gopkg.in/urfave/cli.v1" ) var ( - endpoints []string - includeLocalhost bool - cluster string - scheme string - filesize int - from int - to int - verbosity int + gitCommit string // Git SHA1 commit hash of the release (set via linker flags) +) + +var ( + allhosts string + hosts []string + filesize int + inputSeed int + syncDelay int + httpPort int + wsPort int + verbosity int + timeout int + single bool + trackTimeout int ) func main() { @@ -44,33 +58,28 @@ func main() { app.Flags = []cli.Flag{ cli.StringFlag{ - Name: "cluster-endpoint", - Value: "testing", - Usage: "cluster to point to (local, open or testing)", - Destination: &cluster, + Name: "hosts", + Value: "", + Usage: "comma-separated list of swarm hosts", + Destination: &allhosts, }, cli.IntFlag{ - Name: "cluster-from", - Value: 8501, - Usage: "swarm node (from)", - Destination: &from, + Name: "http-port", + Value: 80, + Usage: "http port", + Destination: &httpPort, }, cli.IntFlag{ - Name: "cluster-to", - Value: 8512, - Usage: "swarm node (to)", - Destination: &to, + Name: "ws-port", + Value: 8546, + Usage: "ws port", + Destination: &wsPort, }, - cli.StringFlag{ - Name: "cluster-scheme", - Value: "http", - Usage: "http or https", - Destination: &scheme, - }, - cli.BoolFlag{ - Name: "include-localhost", - Usage: "whether to include localhost:8500 as an endpoint", - Destination: &includeLocalhost, + cli.IntFlag{ + Name: "seed", + Value: 0, + Usage: "input seed in case we need deterministic upload", + Destination: &inputSeed, }, cli.IntFlag{ Name: "filesize", @@ -78,34 +87,111 @@ func main() { Usage: "file size for generated random file in KB", Destination: &filesize, }, + cli.IntFlag{ + Name: "sync-delay", + Value: 5, + Usage: "duration of delay in seconds to wait for content to be synced", + Destination: &syncDelay, + }, cli.IntFlag{ Name: "verbosity", Value: 1, Usage: "verbosity", Destination: &verbosity, }, + cli.IntFlag{ + Name: "timeout", + Value: 120, + Usage: "timeout in seconds after which kill the process", + Destination: &timeout, + }, + cli.BoolFlag{ + Name: "single", + Usage: "whether to fetch content from a single node or from all nodes", + Destination: &single, + }, + cli.IntFlag{ + Name: "track-timeout", + Value: 5, + Usage: "timeout in seconds to wait for GetAllReferences to return", + Destination: &trackTimeout, + }, } + app.Flags = append(app.Flags, []cli.Flag{ + utils.MetricsEnabledFlag, + swarmmetrics.MetricsInfluxDBEndpointFlag, + swarmmetrics.MetricsInfluxDBDatabaseFlag, + swarmmetrics.MetricsInfluxDBUsernameFlag, + swarmmetrics.MetricsInfluxDBPasswordFlag, + swarmmetrics.MetricsInfluxDBTagsFlag, + }...) + + app.Flags = append(app.Flags, tracing.Flags...) + app.Commands = []cli.Command{ { Name: "upload_and_sync", Aliases: []string{"c"}, Usage: "upload and sync", - Action: cliUploadAndSync, + Action: wrapCliCommand("upload-and-sync", uploadAndSyncCmd), }, { Name: "feed_sync", Aliases: []string{"f"}, Usage: "feed update generate, upload and sync", - Action: cliFeedUploadAndSync, + Action: wrapCliCommand("feed-and-sync", feedUploadAndSyncCmd), + }, + { + Name: "upload_speed", + Aliases: []string{"u"}, + Usage: "measure upload speed", + Action: wrapCliCommand("upload-speed", uploadSpeedCmd), + }, + { + Name: "sliding_window", + Aliases: []string{"s"}, + Usage: "measure network aggregate capacity", + Action: wrapCliCommand("sliding-window", slidingWindowCmd), }, } sort.Sort(cli.FlagsByName(app.Flags)) sort.Sort(cli.CommandsByName(app.Commands)) + app.Before = func(ctx *cli.Context) error { + tracing.Setup(ctx) + return nil + } + + app.After = func(ctx *cli.Context) error { + return emitMetrics(ctx) + } + err := app.Run(os.Args) if err != nil { log.Error(err.Error()) + + os.Exit(1) } } + +func emitMetrics(ctx *cli.Context) error { + if gethmetrics.Enabled { + var ( + endpoint = ctx.GlobalString(swarmmetrics.MetricsInfluxDBEndpointFlag.Name) + database = ctx.GlobalString(swarmmetrics.MetricsInfluxDBDatabaseFlag.Name) + username = ctx.GlobalString(swarmmetrics.MetricsInfluxDBUsernameFlag.Name) + password = ctx.GlobalString(swarmmetrics.MetricsInfluxDBPasswordFlag.Name) + tags = ctx.GlobalString(swarmmetrics.MetricsInfluxDBTagsFlag.Name) + ) + + tagsMap := utils.SplitTagsFlag(tags) + tagsMap["version"] = gitCommit + tagsMap["filesize"] = fmt.Sprintf("%v", filesize) + + return influxdb.InfluxDBWithTagsOnce(gethmetrics.DefaultRegistry, endpoint, database, username, password, "swarm-smoke.", tagsMap) + } + + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/sliding_window.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/sliding_window.go new file mode 100644 index 00000000..d589124b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/sliding_window.go @@ -0,0 +1,145 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "fmt" + "math/rand" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/testutil" + "github.com/pborman/uuid" + + cli "gopkg.in/urfave/cli.v1" +) + +type uploadResult struct { + hash string + digest []byte +} + +func slidingWindowCmd(ctx *cli.Context, tuid string) error { + errc := make(chan error) + + go func() { + errc <- slidingWindow(ctx, tuid) + }() + + err := <-errc + if err != nil { + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) + } + return err +} + +func slidingWindow(ctx *cli.Context, tuid string) error { + var hashes []uploadResult //swarm hashes of the uploads + nodes := len(hosts) + log.Info("sliding window test started", "tuid", tuid, "nodes", nodes, "filesize(kb)", filesize, "timeout", timeout) + uploadedBytes := 0 + networkDepth := 0 + errored := false + +outer: + for { + seed = int(time.Now().UTC().UnixNano()) + log.Info("uploading to "+httpEndpoint(hosts[0])+" and syncing", "seed", seed) + + t1 := time.Now() + + randomBytes := testutil.RandomBytes(seed, filesize*1000) + + hash, err := upload(randomBytes, httpEndpoint(hosts[0])) + if err != nil { + log.Error(err.Error()) + return err + } + + metrics.GetOrRegisterResettingTimer("sliding-window.upload-time", nil).UpdateSince(t1) + metrics.GetOrRegisterGauge("sliding-window.upload-depth", nil).Update(int64(len(hashes))) + + fhash, err := digest(bytes.NewReader(randomBytes)) + if err != nil { + log.Error(err.Error()) + return err + } + + log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash), "sleeping", syncDelay) + hashes = append(hashes, uploadResult{hash: hash, digest: fhash}) + time.Sleep(time.Duration(syncDelay) * time.Second) + uploadedBytes += filesize * 1000 + q := make(chan struct{}, 1) + d := make(chan struct{}) + defer close(q) + defer close(d) + for i, v := range hashes { + timeoutC := time.After(time.Duration(timeout) * time.Second) + errored = false + + task: + for { + select { + case q <- struct{}{}: + go func() { + var start time.Time + done := false + for !done { + log.Info("trying to retrieve hash", "hash", v.hash) + idx := 1 + rand.Intn(len(hosts)-1) + ruid := uuid.New()[:8] + start = time.Now() + // fetch hangs when swarm dies out, so we have to jump through a bit more hoops to actually + // catch the timeout, but also allow this retry logic + err := fetch(v.hash, httpEndpoint(hosts[idx]), v.digest, ruid, "") + if err != nil { + log.Error("error fetching hash", "err", err) + continue + } + done = true + } + metrics.GetOrRegisterResettingTimer("sliding-window.single.fetch-time", nil).UpdateSince(start) + d <- struct{}{} + }() + case <-d: + <-q + break task + case <-timeoutC: + errored = true + log.Error("error retrieving hash. timeout", "hash idx", i) + metrics.GetOrRegisterCounter("sliding-window.single.error", nil).Inc(1) + break outer + default: + } + } + + networkDepth = i + metrics.GetOrRegisterGauge("sliding-window.network-depth", nil).Update(int64(networkDepth)) + log.Info("sliding window test successfully fetched file", "currentDepth", networkDepth) + // this test might take a long time to finish - but we'd like to see metrics while they accumulate and not just when + // the test finishes. therefore emit the metrics on each iteration + emitMetrics(ctx) + } + } + + log.Info("sliding window test finished", "errored?", errored, "networkDepth", networkDepth, "networkDepth(kb)", networkDepth*filesize) + log.Info("stats", "uploadedFiles", len(hashes), "uploadedKb", uploadedBytes/1000, "filesizeKb", filesize) + + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_and_sync.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_and_sync.go index 358141c7..6c20a4fa 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_and_sync.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_and_sync.go @@ -18,186 +18,190 @@ package main import ( "bytes" - "crypto/md5" - crand "crypto/rand" - "errors" + "context" "fmt" - "io" "io/ioutil" - "net/http" + "math/rand" "os" - "os/exec" "strings" "sync" "time" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/testutil" "github.com/pborman/uuid" cli "gopkg.in/urfave/cli.v1" ) -func generateEndpoints(scheme string, cluster string, from int, to int) { - if cluster == "prod" { - cluster = "" - } else if cluster == "local" { - for port := from; port <= to; port++ { - endpoints = append(endpoints, fmt.Sprintf("%s://localhost:%v", scheme, port)) +func uploadAndSyncCmd(ctx *cli.Context, tuid string) error { + // use input seed if it has been set + if inputSeed != 0 { + seed = inputSeed + } + + randomBytes := testutil.RandomBytes(seed, filesize*1000) + + errc := make(chan error) + + go func() { + errc <- uploadAndSync(ctx, randomBytes, tuid) + }() + + var err error + select { + case err = <-errc: + if err != nil { + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) } - return - } else { - cluster = cluster + "." + case <-time.After(time.Duration(timeout) * time.Second): + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) + + err = fmt.Errorf("timeout after %v sec", timeout) } - for port := from; port <= to; port++ { - endpoints = append(endpoints, fmt.Sprintf("%s://%v.%sswarm-gateways.net", scheme, port, cluster)) + // trigger debug functionality on randomBytes + e := trackChunks(randomBytes[:]) + if e != nil { + log.Error(e.Error()) } - if includeLocalhost { - endpoints = append(endpoints, "http://localhost:8500") - } + return err } -func cliUploadAndSync(c *cli.Context) error { - defer func(now time.Time) { log.Info("total time", "time", time.Since(now), "size (kb)", filesize) }(time.Now()) +func trackChunks(testData []byte) error { + addrs, err := getAllRefs(testData) + if err != nil { + return err + } - generateEndpoints(scheme, cluster, from, to) + for i, ref := range addrs { + log.Trace(fmt.Sprintf("ref %d", i), "ref", ref) + } - log.Info("uploading to " + endpoints[0] + " and syncing") + for _, host := range hosts { + httpHost := fmt.Sprintf("ws://%s:%d", host, 8546) - f, cleanup := generateRandomFile(filesize * 1000) - defer cleanup() + hostChunks := []string{} - hash, err := upload(f, endpoints[0]) + rpcClient, err := rpc.Dial(httpHost) + if err != nil { + log.Error("error dialing host", "err", err, "host", httpHost) + continue + } + + var hasInfo []api.HasInfo + err = rpcClient.Call(&hasInfo, "bzz_has", addrs) + if err != nil { + log.Error("error calling rpc client", "err", err, "host", httpHost) + continue + } + + count := 0 + for _, info := range hasInfo { + if info.Has { + hostChunks = append(hostChunks, "1") + } else { + hostChunks = append(hostChunks, "0") + count++ + } + } + + if count == 0 { + log.Info("host reported to have all chunks", "host", host) + } + + log.Trace("chunks", "chunks", strings.Join(hostChunks, ""), "host", host) + } + return nil +} + +func getAllRefs(testData []byte) (storage.AddressCollection, error) { + datadir, err := ioutil.TempDir("", "chunk-debug") + if err != nil { + return nil, fmt.Errorf("unable to create temp dir: %v", err) + } + defer os.RemoveAll(datadir) + fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32)) + if err != nil { + return nil, err + } + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(trackTimeout)*time.Second) + defer cancel() + + reader := bytes.NewReader(testData) + return fileStore.GetAllReferences(ctx, reader, false) +} + +func uploadAndSync(c *cli.Context, randomBytes []byte, tuid string) error { + log.Info("uploading to "+httpEndpoint(hosts[0])+" and syncing", "tuid", tuid, "seed", seed) + + t1 := time.Now() + hash, err := upload(randomBytes, httpEndpoint(hosts[0])) + if err != nil { + log.Error(err.Error()) + return err + } + t2 := time.Since(t1) + metrics.GetOrRegisterResettingTimer("upload-and-sync.upload-time", nil).Update(t2) + + fhash, err := digest(bytes.NewReader(randomBytes)) if err != nil { log.Error(err.Error()) return err } - fhash, err := digest(f) - if err != nil { - log.Error(err.Error()) - return err - } + log.Info("uploaded successfully", "tuid", tuid, "hash", hash, "took", t2, "digest", fmt.Sprintf("%x", fhash)) - log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash)) - - time.Sleep(3 * time.Second) + time.Sleep(time.Duration(syncDelay) * time.Second) wg := sync.WaitGroup{} - for _, endpoint := range endpoints { + if single { + randIndex := 1 + rand.Intn(len(hosts)-1) ruid := uuid.New()[:8] wg.Add(1) go func(endpoint string, ruid string) { for { - err := fetch(hash, endpoint, fhash, ruid) + start := time.Now() + err := fetch(hash, endpoint, fhash, ruid, tuid) if err != nil { continue } + ended := time.Since(start) + metrics.GetOrRegisterResettingTimer("upload-and-sync.single.fetch-time", nil).Update(ended) + log.Info("fetch successful", "tuid", tuid, "ruid", ruid, "took", ended, "endpoint", endpoint) wg.Done() return } - }(endpoint, ruid) + }(httpEndpoint(hosts[randIndex]), ruid) + } else { + for _, endpoint := range hosts[1:] { + ruid := uuid.New()[:8] + wg.Add(1) + go func(endpoint string, ruid string) { + for { + start := time.Now() + err := fetch(hash, endpoint, fhash, ruid, tuid) + if err != nil { + continue + } + ended := time.Since(start) + + metrics.GetOrRegisterResettingTimer("upload-and-sync.each.fetch-time", nil).Update(ended) + log.Info("fetch successful", "tuid", tuid, "ruid", ruid, "took", ended, "endpoint", endpoint) + wg.Done() + return + } + }(httpEndpoint(endpoint), ruid) + } } wg.Wait() - log.Info("all endpoints synced random file successfully") + log.Info("all hosts synced random file successfully") return nil } - -// fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file -func fetch(hash string, endpoint string, original []byte, ruid string) error { - log.Trace("sleeping", "ruid", ruid) - time.Sleep(3 * time.Second) - - log.Trace("http get request", "ruid", ruid, "api", endpoint, "hash", hash) - res, err := http.Get(endpoint + "/bzz:/" + hash + "/") - if err != nil { - log.Warn(err.Error(), "ruid", ruid) - return err - } - log.Trace("http get response", "ruid", ruid, "api", endpoint, "hash", hash, "code", res.StatusCode, "len", res.ContentLength) - - if res.StatusCode != 200 { - err := fmt.Errorf("expected status code %d, got %v", 200, res.StatusCode) - log.Warn(err.Error(), "ruid", ruid) - return err - } - - defer res.Body.Close() - - rdigest, err := digest(res.Body) - if err != nil { - log.Warn(err.Error(), "ruid", ruid) - return err - } - - if !bytes.Equal(rdigest, original) { - err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) - log.Warn(err.Error(), "ruid", ruid) - return err - } - - log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) - - return nil -} - -// upload is uploading a file `f` to `endpoint` via the `swarm up` cmd -func upload(f *os.File, endpoint string) (string, error) { - var out bytes.Buffer - cmd := exec.Command("swarm", "--bzzapi", endpoint, "up", f.Name()) - cmd.Stdout = &out - err := cmd.Run() - if err != nil { - return "", err - } - hash := strings.TrimRight(out.String(), "\r\n") - return hash, nil -} - -func digest(r io.Reader) ([]byte, error) { - h := md5.New() - _, err := io.Copy(h, r) - if err != nil { - return nil, err - } - return h.Sum(nil), nil -} - -// generates random data in heap buffer -func generateRandomData(datasize int) ([]byte, error) { - b := make([]byte, datasize) - c, err := crand.Read(b) - if err != nil { - return nil, err - } else if c != datasize { - return nil, errors.New("short read") - } - return b, nil -} - -// generateRandomFile is creating a temporary file with the requested byte size -func generateRandomFile(size int) (f *os.File, teardown func()) { - // create a tmp file - tmp, err := ioutil.TempFile("", "swarm-test") - if err != nil { - panic(err) - } - - // callback for tmp file cleanup - teardown = func() { - tmp.Close() - os.Remove(tmp.Name()) - } - - buf := make([]byte, size) - _, err = crand.Read(buf) - if err != nil { - panic(err) - } - ioutil.WriteFile(tmp.Name(), buf, 0755) - - return tmp, teardown -} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_speed.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_speed.go new file mode 100644 index 00000000..20bf7b86 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/upload_speed.go @@ -0,0 +1,73 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/testutil" + + cli "gopkg.in/urfave/cli.v1" +) + +func uploadSpeedCmd(ctx *cli.Context, tuid string) error { + log.Info("uploading to "+hosts[0], "tuid", tuid, "seed", seed) + randomBytes := testutil.RandomBytes(seed, filesize*1000) + + errc := make(chan error) + + go func() { + errc <- uploadSpeed(ctx, tuid, randomBytes) + }() + + select { + case err := <-errc: + if err != nil { + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) + } + return err + case <-time.After(time.Duration(timeout) * time.Second): + metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) + + // trigger debug functionality on randomBytes + + return fmt.Errorf("timeout after %v sec", timeout) + } +} + +func uploadSpeed(c *cli.Context, tuid string, data []byte) error { + t1 := time.Now() + hash, err := upload(data, hosts[0]) + if err != nil { + log.Error(err.Error()) + return err + } + metrics.GetOrRegisterCounter("upload-speed.upload-time", nil).Inc(int64(time.Since(t1))) + + fhash, err := digest(bytes.NewReader(data)) + if err != nil { + log.Error(err.Error()) + return err + } + + log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash)) + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/util.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/util.go new file mode 100644 index 00000000..87abb44b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-smoke/util.go @@ -0,0 +1,235 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "context" + "crypto/md5" + crand "crypto/rand" + "errors" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net/http" + "net/http/httptrace" + "os" + "strings" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/api/client" + "github.com/ethereum/go-ethereum/swarm/spancontext" + opentracing "github.com/opentracing/opentracing-go" + "github.com/pborman/uuid" + cli "gopkg.in/urfave/cli.v1" +) + +var ( + commandName = "" + seed = int(time.Now().UTC().UnixNano()) +) + +func init() { + rand.Seed(int64(seed)) +} + +func httpEndpoint(host string) string { + return fmt.Sprintf("http://%s:%d", host, httpPort) +} + +func wsEndpoint(host string) string { + return fmt.Sprintf("ws://%s:%d", host, wsPort) +} + +func wrapCliCommand(name string, command func(*cli.Context, string) error) func(*cli.Context) error { + return func(ctx *cli.Context) error { + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(verbosity), log.StreamHandler(os.Stdout, log.TerminalFormat(false)))) + + // test uuid + tuid := uuid.New()[:8] + + commandName = name + + hosts = strings.Split(allhosts, ",") + + defer func(now time.Time) { + totalTime := time.Since(now) + log.Info("total time", "tuid", tuid, "time", totalTime, "kb", filesize) + metrics.GetOrRegisterResettingTimer(name+".total-time", nil).Update(totalTime) + }(time.Now()) + + log.Info("smoke test starting", "tuid", tuid, "task", name, "timeout", timeout) + metrics.GetOrRegisterCounter(name, nil).Inc(1) + + return command(ctx, tuid) + } +} + +func fetchFeed(topic string, user string, endpoint string, original []byte, ruid string) error { + ctx, sp := spancontext.StartSpan(context.Background(), "feed-and-sync.fetch") + defer sp.Finish() + + log.Trace("sleeping", "ruid", ruid) + time.Sleep(3 * time.Second) + + log.Trace("http get request (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user) + + var tn time.Time + reqUri := endpoint + "/bzz-feed:/?topic=" + topic + "&user=" + user + req, _ := http.NewRequest("GET", reqUri, nil) + + opentracing.GlobalTracer().Inject( + sp.Context(), + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(req.Header)) + + trace := client.GetClientTrace("feed-and-sync - http get", "feed-and-sync", ruid, &tn) + + req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) + transport := http.DefaultTransport + + //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + tn = time.Now() + res, err := transport.RoundTrip(req) + if err != nil { + log.Error(err.Error(), "ruid", ruid) + return err + } + + log.Trace("http get response (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user, "code", res.StatusCode, "len", res.ContentLength) + + if res.StatusCode != 200 { + return fmt.Errorf("expected status code %d, got %v (ruid %v)", 200, res.StatusCode, ruid) + } + + defer res.Body.Close() + + rdigest, err := digest(res.Body) + if err != nil { + log.Warn(err.Error(), "ruid", ruid) + return err + } + + if !bytes.Equal(rdigest, original) { + err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) + log.Warn(err.Error(), "ruid", ruid) + return err + } + + log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) + + return nil +} + +// fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file +func fetch(hash string, endpoint string, original []byte, ruid string, tuid string) error { + ctx, sp := spancontext.StartSpan(context.Background(), "upload-and-sync.fetch") + defer sp.Finish() + + log.Info("http get request", "tuid", tuid, "ruid", ruid, "endpoint", endpoint, "hash", hash) + + var tn time.Time + reqUri := endpoint + "/bzz:/" + hash + "/" + req, _ := http.NewRequest("GET", reqUri, nil) + + opentracing.GlobalTracer().Inject( + sp.Context(), + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(req.Header)) + + trace := client.GetClientTrace(commandName+" - http get", commandName, ruid, &tn) + + req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) + transport := http.DefaultTransport + + //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + tn = time.Now() + res, err := transport.RoundTrip(req) + if err != nil { + log.Error(err.Error(), "ruid", ruid) + return err + } + log.Info("http get response", "tuid", tuid, "ruid", ruid, "endpoint", endpoint, "hash", hash, "code", res.StatusCode, "len", res.ContentLength) + + if res.StatusCode != 200 { + err := fmt.Errorf("expected status code %d, got %v", 200, res.StatusCode) + log.Warn(err.Error(), "ruid", ruid) + return err + } + + defer res.Body.Close() + + rdigest, err := digest(res.Body) + if err != nil { + log.Warn(err.Error(), "ruid", ruid) + return err + } + + if !bytes.Equal(rdigest, original) { + err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) + log.Warn(err.Error(), "ruid", ruid) + return err + } + + log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) + + return nil +} + +// upload an arbitrary byte as a plaintext file to `endpoint` using the api client +func upload(data []byte, endpoint string) (string, error) { + swarm := client.NewClient(endpoint) + f := &client.File{ + ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), + ManifestEntry: api.ManifestEntry{ + ContentType: "text/plain", + Mode: 0660, + Size: int64(len(data)), + }, + } + + // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded. + return swarm.Upload(f, "", false) +} + +func digest(r io.Reader) ([]byte, error) { + h := md5.New() + _, err := io.Copy(h, r) + if err != nil { + return nil, err + } + return h.Sum(nil), nil +} + +// generates random data in heap buffer +func generateRandomData(datasize int) ([]byte, error) { + b := make([]byte, datasize) + c, err := crand.Read(b) + if err != nil { + return nil, err + } else if c != datasize { + return nil, errors.New("short read") + } + return b, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/create.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/create.go new file mode 100644 index 00000000..434561a4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/create.go @@ -0,0 +1,160 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/simulations" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/network/simulation" + cli "gopkg.in/urfave/cli.v1" +) + +// create is used as the entry function for "create" app command. +func create(ctx *cli.Context) error { + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) + + if len(ctx.Args()) < 1 { + return errors.New("argument should be the filename to verify or write-to") + } + filename, err := touchPath(ctx.Args()[0]) + if err != nil { + return err + } + return createSnapshot(filename, ctx.Int("nodes"), strings.Split(ctx.String("services"), ",")) +} + +// createSnapshot creates a new snapshot on filesystem with provided filename, +// number of nodes and service names. +func createSnapshot(filename string, nodes int, services []string) (err error) { + log.Debug("create snapshot", "filename", filename, "nodes", nodes, "services", services) + + sim := simulation.New(map[string]simulation.ServiceFunc{ + "bzz": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) { + addr := network.NewAddr(ctx.Config.Node()) + kad := network.NewKademlia(addr.Over(), network.NewKadParams()) + hp := network.NewHiveParams() + hp.KeepAliveInterval = time.Duration(200) * time.Millisecond + hp.Discovery = true // discovery must be enabled when creating a snapshot + + // store the kademlia in the bucket, needed later in the WaitTillHealthy function + bucket.Store(simulation.BucketKeyKademlia, kad) + + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + return network.NewBzz(config, kad, nil, nil, nil), nil, nil + }, + }) + defer sim.Close() + + ids, err := sim.AddNodes(nodes) + if err != nil { + return fmt.Errorf("add nodes: %v", err) + } + + err = sim.Net.ConnectNodesRing(ids) + if err != nil { + return fmt.Errorf("connect nodes: %v", err) + } + + ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancelSimRun() + if _, err := sim.WaitTillHealthy(ctx); err != nil { + return fmt.Errorf("wait for healthy kademlia: %v", err) + } + + var snap *simulations.Snapshot + if len(services) > 0 { + // If service names are provided, include them in the snapshot. + // But, check if "bzz" service is not among them to remove it + // form the snapshot as it exists on snapshot creation. + var removeServices []string + var wantBzz bool + for _, s := range services { + if s == "bzz" { + wantBzz = true + break + } + } + if !wantBzz { + removeServices = []string{"bzz"} + } + snap, err = sim.Net.SnapshotWithServices(services, removeServices) + } else { + snap, err = sim.Net.Snapshot() + } + if err != nil { + return fmt.Errorf("create snapshot: %v", err) + } + jsonsnapshot, err := json.Marshal(snap) + if err != nil { + return fmt.Errorf("json encode snapshot: %v", err) + } + return ioutil.WriteFile(filename, jsonsnapshot, 0666) +} + +// touchPath creates an empty file and all subdirectories +// that are missing. +func touchPath(filename string) (string, error) { + if path.IsAbs(filename) { + if _, err := os.Stat(filename); err == nil { + // path exists, overwrite + return filename, nil + } + } + + d, f := path.Split(filename) + dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + return "", err + } + + _, err = os.Stat(path.Join(dir, filename)) + if err == nil { + // path exists, overwrite + return filename, nil + } + + dirPath := path.Join(dir, d) + filePath := path.Join(dirPath, f) + if d != "" { + err = os.MkdirAll(dirPath, os.ModeDir) + if err != nil { + return "", err + } + } + + return filePath, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/create_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/create_test.go new file mode 100644 index 00000000..b2e30c20 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/create_test.go @@ -0,0 +1,143 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "runtime" + "sort" + "strconv" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/p2p/simulations" +) + +// TestSnapshotCreate is a high level e2e test that tests for snapshot generation. +// It runs a few "create" commands with different flag values and loads generated +// snapshot files to validate their content. +func TestSnapshotCreate(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + for _, v := range []struct { + name string + nodes int + services string + }{ + { + name: "defaults", + }, + { + name: "more nodes", + nodes: defaultNodes + 4, + }, + { + name: "services", + services: "stream,pss,zorglub", + }, + { + name: "services with bzz", + services: "bzz,pss", + }, + } { + t.Run(v.name, func(t *testing.T) { + t.Parallel() + + file, err := ioutil.TempFile("", "swarm-snapshot") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + + if err = file.Close(); err != nil { + t.Error(err) + } + + args := []string{"create"} + if v.nodes > 0 { + args = append(args, "--nodes", strconv.Itoa(v.nodes)) + } + if v.services != "" { + args = append(args, "--services", v.services) + } + testCmd := runSnapshot(t, append(args, file.Name())...) + + testCmd.WaitExit() + if code := testCmd.ExitStatus(); code != 0 { + t.Fatalf("command exit code %v, expected 0", code) + } + + f, err := os.Open(file.Name()) + if err != nil { + t.Fatal(err) + } + defer func() { + err := f.Close() + if err != nil { + t.Error("closing snapshot file", "err", err) + } + }() + + b, err := ioutil.ReadAll(f) + if err != nil { + t.Fatal(err) + } + var snap simulations.Snapshot + err = json.Unmarshal(b, &snap) + if err != nil { + t.Fatal(err) + } + + wantNodes := v.nodes + if wantNodes == 0 { + wantNodes = defaultNodes + } + gotNodes := len(snap.Nodes) + if gotNodes != wantNodes { + t.Errorf("got %v nodes, want %v", gotNodes, wantNodes) + } + + if len(snap.Conns) == 0 { + t.Error("no connections in a snapshot") + } + + var wantServices []string + if v.services != "" { + wantServices = strings.Split(v.services, ",") + } else { + wantServices = []string{"bzz"} + } + // sort service names so they can be comparable + // as strings to every node sorted services + sort.Strings(wantServices) + + for i, n := range snap.Nodes { + gotServices := n.Node.Config.Services + sort.Strings(gotServices) + if fmt.Sprint(gotServices) != fmt.Sprint(wantServices) { + t.Errorf("got services %v for node %v, want %v", gotServices, i, wantServices) + } + } + + }) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/main.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/main.go new file mode 100644 index 00000000..136295e5 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/main.go @@ -0,0 +1,82 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "os" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/log" + cli "gopkg.in/urfave/cli.v1" +) + +var gitCommit string // Git SHA1 commit hash of the release (set via linker flags) + +// default value for "create" command --nodes flag +const defaultNodes = 8 + +func main() { + err := newApp().Run(os.Args) + if err != nil { + log.Error(err.Error()) + os.Exit(1) + } +} + +// newApp construct a new instance of Swarm Snapshot Utility. +// Method Run is called on it in the main function and in tests. +func newApp() (app *cli.App) { + app = utils.NewApp(gitCommit, "Swarm Snapshot Utility") + + app.Name = "swarm-snapshot" + app.Usage = "" + + // app flags (for all commands) + app.Flags = []cli.Flag{ + cli.IntFlag{ + Name: "verbosity", + Value: 1, + Usage: "verbosity level", + }, + } + + app.Commands = []cli.Command{ + { + Name: "create", + Aliases: []string{"c"}, + Usage: "create a swarm snapshot", + Action: create, + // Flags only for "create" command. + // Allow app flags to be specified after the + // command argument. + Flags: append(app.Flags, + cli.IntFlag{ + Name: "nodes", + Value: defaultNodes, + Usage: "number of nodes", + }, + cli.StringFlag{ + Name: "services", + Value: "bzz", + Usage: "comma separated list of services to boot the nodes with", + }, + ), + }, + } + + return app +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/run_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/run_test.go new file mode 100644 index 00000000..d9a04159 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/swarm-snapshot/run_test.go @@ -0,0 +1,49 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "os" + "testing" + + "github.com/docker/docker/pkg/reexec" + "github.com/ethereum/go-ethereum/internal/cmdtest" +) + +func init() { + reexec.Register("swarm-snapshot", func() { + if err := newApp().Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Exit(0) + }) +} + +func runSnapshot(t *testing.T, args ...string) *cmdtest.TestCmd { + tt := cmdtest.NewTestCmd(t, nil) + tt.Run("swarm-snapshot", args...) + return tt +} + +func TestMain(m *testing.M) { + if reexec.Init() { + return + } + os.Exit(m.Run()) +} diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload.go index 992f2d6e..ab079083 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload.go @@ -60,10 +60,10 @@ func upload(ctx *cli.Context) { autoDefaultPath = false file string ) - if autoDefaultPathString := os.Getenv(SWARM_AUTO_DEFAULTPATH); autoDefaultPathString != "" { + if autoDefaultPathString := os.Getenv(SwarmAutoDefaultPath); autoDefaultPathString != "" { b, err := strconv.ParseBool(autoDefaultPathString) if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SWARM_AUTO_DEFAULTPATH, err) + utils.Fatalf("invalid environment variable %s: %v", SwarmAutoDefaultPath, err) } autoDefaultPath = b } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload_test.go index 5f984495..616486e3 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload_test.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/swarm/upload_test.go @@ -31,8 +31,7 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" + swarmapi "github.com/ethereum/go-ethereum/swarm/api/client" "github.com/ethereum/go-ethereum/swarm/testutil" "github.com/mattn/go-colorable" ) @@ -42,42 +41,50 @@ func init() { log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) } -// TestCLISwarmUp tests that running 'swarm up' makes the resulting file +func TestSwarmUp(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + initCluster(t) + + cases := []struct { + name string + f func(t *testing.T) + }{ + {"NoEncryption", testNoEncryption}, + {"Encrypted", testEncrypted}, + {"RecursiveNoEncryption", testRecursiveNoEncryption}, + {"RecursiveEncrypted", testRecursiveEncrypted}, + {"DefaultPathAll", testDefaultPathAll}, + } + + for _, tc := range cases { + t.Run(tc.name, tc.f) + } +} + +// testNoEncryption tests that running 'swarm up' makes the resulting file // available from all nodes via the HTTP API -func TestCLISwarmUp(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - testCLISwarmUp(false, t) -} -func TestCLISwarmUpRecursive(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - testCLISwarmUpRecursive(false, t) +func testNoEncryption(t *testing.T) { + testDefault(false, t) } -// TestCLISwarmUpEncrypted tests that running 'swarm encrypted-up' makes the resulting file +// testEncrypted tests that running 'swarm up --encrypted' makes the resulting file // available from all nodes via the HTTP API -func TestCLISwarmUpEncrypted(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - testCLISwarmUp(true, t) -} -func TestCLISwarmUpEncryptedRecursive(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - testCLISwarmUpRecursive(true, t) +func testEncrypted(t *testing.T) { + testDefault(true, t) } -func testCLISwarmUp(toEncrypt bool, t *testing.T) { - log.Info("starting 3 node cluster") - cluster := newTestCluster(t, 3) - defer cluster.Shutdown() +func testRecursiveNoEncryption(t *testing.T) { + testRecursive(false, t) +} +func testRecursiveEncrypted(t *testing.T) { + testRecursive(true, t) +} + +func testDefault(toEncrypt bool, t *testing.T) { tmpFileName := testutil.TempFileWithContent(t, data) defer os.Remove(tmpFileName) @@ -182,11 +189,7 @@ func testCLISwarmUp(toEncrypt bool, t *testing.T) { } } -func testCLISwarmUpRecursive(toEncrypt bool, t *testing.T) { - fmt.Println("starting 3 node cluster") - cluster := newTestCluster(t, 3) - defer cluster.Shutdown() - +func testRecursive(toEncrypt bool, t *testing.T) { tmpUploadDir, err := ioutil.TempDir("", "swarm-test") if err != nil { t.Fatal(err) @@ -253,7 +256,7 @@ func testCLISwarmUpRecursive(toEncrypt bool, t *testing.T) { switch mode := fi.Mode(); { case mode.IsRegular(): - if file, err := swarm.Open(path.Join(tmpDownload, v.Name())); err != nil { + if file, err := swarmapi.Open(path.Join(tmpDownload, v.Name())); err != nil { t.Fatalf("encountered an error opening the file returned from the CLI: %v", err) } else { ff := make([]byte, len(data)) @@ -274,22 +277,16 @@ func testCLISwarmUpRecursive(toEncrypt bool, t *testing.T) { } } -// TestCLISwarmUpDefaultPath tests swarm recursive upload with relative and absolute +// testDefaultPathAll tests swarm recursive upload with relative and absolute // default paths and with encryption. -func TestCLISwarmUpDefaultPath(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - testCLISwarmUpDefaultPath(false, false, t) - testCLISwarmUpDefaultPath(false, true, t) - testCLISwarmUpDefaultPath(true, false, t) - testCLISwarmUpDefaultPath(true, true, t) +func testDefaultPathAll(t *testing.T) { + testDefaultPath(false, false, t) + testDefaultPath(false, true, t) + testDefaultPath(true, false, t) + testDefaultPath(true, true, t) } -func testCLISwarmUpDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - +func testDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T) { tmp, err := ioutil.TempDir("", "swarm-defaultpath-test") if err != nil { t.Fatal(err) @@ -312,7 +309,7 @@ func testCLISwarmUpDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T args := []string{ "--bzzapi", - srv.URL, + cluster.Nodes[0].URL, "--recursive", "--defaultpath", defaultPath, @@ -329,7 +326,7 @@ func testCLISwarmUpDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T up.ExpectExit() hash := matches[0] - client := swarm.NewClient(srv.URL) + client := swarmapi.NewClient(cluster.Nodes[0].URL) m, isEncrypted, err := client.DownloadManifest(hash) if err != nil { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/utils/cmd.go b/vendor/github.com/ethereum/go-ethereum/cmd/utils/cmd.go index f23aa577..74a8c7f3 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/utils/cmd.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/utils/cmd.go @@ -238,7 +238,7 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las } // ImportPreimages imports a batch of exported hash preimages into the database. -func ImportPreimages(db *ethdb.LDBDatabase, fn string) error { +func ImportPreimages(db ethdb.Database, fn string) error { log.Info("Importing preimages", "file", fn) // Open the file handle and potentially unwrap the gzip stream @@ -285,7 +285,7 @@ func ImportPreimages(db *ethdb.LDBDatabase, fn string) error { // ExportPreimages exports all known hash preimages into the specified file, // truncating any data already present in the file. -func ExportPreimages(db *ethdb.LDBDatabase, fn string) error { +func ExportPreimages(db ethdb.Database, fn string) error { log.Info("Exporting preimages", "file", fn) // Open the file handle and potentially wrap with a gzip stream diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go b/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go index 429c2bbb..bf433242 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go +++ b/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go @@ -19,6 +19,7 @@ package utils import ( "crypto/ecdsa" + "encoding/json" "fmt" "io/ioutil" "math/big" @@ -36,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/dashboard" @@ -57,7 +57,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" - "gopkg.in/urfave/cli.v1" + cli "gopkg.in/urfave/cli.v1" ) var ( @@ -140,6 +140,14 @@ var ( Name: "rinkeby", Usage: "Rinkeby network: pre-configured proof-of-authority test network", } + GoerliFlag = cli.BoolFlag{ + Name: "goerli", + Usage: "Görli network: pre-configured proof-of-authority test network", + } + ConstantinopleOverrideFlag = cli.Uint64Flag{ + Name: "override.constantinople", + Usage: "Manually specify constantinople fork-block, overriding the bundled setting", + } DeveloperFlag = cli.BoolFlag{ Name: "dev", Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", @@ -157,6 +165,26 @@ var ( Usage: "Document Root for HTTPClient file scheme", Value: DirectoryString{homeDir()}, } + ExitWhenSyncedFlag = cli.BoolFlag{ + Name: "exitwhensynced", + Usage: "Exists syncing after block synchronisation", + } + ULCModeConfigFlag = cli.StringFlag{ + Name: "ulc.config", + Usage: "Config file to use for ultra light client mode", + } + OnlyAnnounceModeFlag = cli.BoolFlag{ + Name: "ulc.onlyannounce", + Usage: "ULC server sends announcements only", + } + ULCMinTrustedFractionFlag = cli.IntFlag{ + Name: "ulc.fraction", + Usage: "Minimum % of trusted ULC servers required to announce a new head", + } + ULCTrustedNodesFlag = cli.StringFlag{ + Name: "ulc.trusted", + Usage: "List of trusted ULC servers", + } defaultSyncMode = eth.DefaultConfig.SyncMode SyncModeFlag = TextMarshalerFlag{ Name: "syncmode", @@ -170,9 +198,19 @@ var ( } LightServFlag = cli.IntFlag{ Name: "lightserv", - Usage: "Maximum percentage of time allowed for serving LES requests (0-90)", + Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)", Value: 0, } + LightBandwidthInFlag = cli.IntFlag{ + Name: "lightbwin", + Usage: "Incoming bandwidth limit for light server (1000 bytes/sec, 0 = unlimited)", + Value: 1000, + } + LightBandwidthOutFlag = cli.IntFlag{ + Name: "lightbwout", + Usage: "Outgoing bandwidth limit for light server (1000 bytes/sec, 0 = unlimited)", + Value: 5000, + } LightPeersFlag = cli.IntFlag{ Name: "lightpeers", Usage: "Maximum number of LES client peers", @@ -182,9 +220,13 @@ var ( Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", } + WhitelistFlag = cli.StringFlag{ + Name: "whitelist", + Usage: "Comma separated block number-to-hash mappings to enforce (=)", + } // Dashboard settings DashboardEnabledFlag = cli.BoolFlag{ - Name: metrics.DashboardEnabledFlag, + Name: "dashboard", Usage: "Enable the dashboard", } DashboardAddrFlag = cli.StringFlag{ @@ -295,18 +337,18 @@ var ( CacheDatabaseFlag = cli.IntFlag{ Name: "cache.database", Usage: "Percentage of cache memory allowance to use for database io", - Value: 75, + Value: 50, + } + CacheTrieFlag = cli.IntFlag{ + Name: "cache.trie", + Usage: "Percentage of cache memory allowance to use for trie caching (default = 25% full mode, 50% archive mode)", + Value: 25, } CacheGCFlag = cli.IntFlag{ Name: "cache.gc", - Usage: "Percentage of cache memory allowance to use for trie pruning", + Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", Value: 25, } - TrieCacheGenFlag = cli.IntFlag{ - Name: "trie-cache-gens", - Usage: "Number of trie node generations to keep in memory", - Value: int(state.MaxTrieCacheGen), - } // Miner settings MiningEnabledFlag = cli.BoolFlag{ Name: "mine", @@ -389,7 +431,11 @@ var ( Usage: "Password file to use for non-interactive password input", Value: "", } - + ExternalSignerFlag = cli.StringFlag{ + Name: "signer", + Usage: "External signer (url or path to ipc file)", + Value: "", + } VMEnableDebugFlag = cli.BoolFlag{ Name: "vmdebug", Usage: "Record information useful for VM and contract debugging", @@ -422,6 +468,30 @@ var ( Usage: "HTTP-RPC server listening port", Value: node.DefaultHTTPPort, } + GraphQLEnabledFlag = cli.BoolFlag{ + Name: "graphql", + Usage: "Enable the GraphQL server", + } + GraphQLListenAddrFlag = cli.StringFlag{ + Name: "graphql.addr", + Usage: "GraphQL server listening interface", + Value: node.DefaultGraphQLHost, + } + GraphQLPortFlag = cli.IntFlag{ + Name: "graphql.port", + Usage: "GraphQL server listening port", + Value: node.DefaultGraphQLPort, + } + GraphQLCORSDomainFlag = cli.StringFlag{ + Name: "graphql.rpccorsdomain", + Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", + Value: "", + } + GraphQLVirtualHostsFlag = cli.StringFlag{ + Name: "graphql.rpcvhosts", + Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", + Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), + } RPCCORSDomainFlag = cli.StringFlag{ Name: "rpccorsdomain", Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", @@ -574,9 +644,13 @@ var ( // Metrics flags MetricsEnabledFlag = cli.BoolFlag{ - Name: metrics.MetricsEnabledFlag, + Name: "metrics", Usage: "Enable metrics collection and reporting", } + MetricsEnabledExpensiveFlag = cli.BoolFlag{ + Name: "metrics.expensive", + Usage: "Enable expensive metrics collection and reporting", + } MetricsEnableInfluxDBFlag = cli.BoolFlag{ Name: "metrics.influxdb", Usage: "Enable metrics export/push to an external InfluxDB database", @@ -601,14 +675,14 @@ var ( Usage: "Password to authorize access to the database", Value: "test", } - // The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. - // It is used so that we can group all nodes and average a measurement across all of them, but also so - // that we can select a specific node and inspect its measurements. + // Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. + // For example `host` tag could be used so that we can group all nodes and average a measurement + // across all of them, but also so that we can select a specific node and inspect its measurements. // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key - MetricsInfluxDBHostTagFlag = cli.StringFlag{ - Name: "metrics.influxdb.host.tag", - Usage: "InfluxDB `host` tag attached to all measurements", - Value: "localhost", + MetricsInfluxDBTagsFlag = cli.StringFlag{ + Name: "metrics.influxdb.tags", + Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", + Value: "host=localhost", } EWASMInterpreterFlag = cli.StringFlag{ @@ -634,6 +708,9 @@ func MakeDataDir(ctx *cli.Context) string { if ctx.GlobalBool(RinkebyFlag.Name) { return filepath.Join(path, "rinkeby") } + if ctx.GlobalBool(GoerliFlag.Name) { + return filepath.Join(path, "goerli") + } return path } Fatalf("Cannot determine default data directory, please set manually (--datadir)") @@ -688,17 +765,22 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.TestnetBootnodes case ctx.GlobalBool(RinkebyFlag.Name): urls = params.RinkebyBootnodes + case ctx.GlobalBool(GoerliFlag.Name): + urls = params.GoerliBootnodes case cfg.BootstrapNodes != nil: return // already set, don't apply defaults. } cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) for _, url := range urls { - node, err := enode.ParseV4(url) - if err != nil { - log.Crit("Bootstrap URL invalid", "enode", url, "err", err) + if url != "" { + node, err := enode.ParseV4(url) + if err != nil { + log.Crit("Bootstrap URL invalid", "enode", url, "err", err) + continue + } + cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) } - cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) } } @@ -715,18 +797,22 @@ func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { } case ctx.GlobalBool(RinkebyFlag.Name): urls = params.RinkebyBootnodes + case ctx.GlobalBool(GoerliFlag.Name): + urls = params.GoerliBootnodes case cfg.BootstrapNodesV5 != nil: return // already set, don't apply defaults. } cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls)) for _, url := range urls { - node, err := discv5.ParseNode(url) - if err != nil { - log.Error("Bootstrap URL invalid", "enode", url, "err", err) - continue + if url != "" { + node, err := discv5.ParseNode(url) + if err != nil { + log.Error("Bootstrap URL invalid", "enode", url, "err", err) + continue + } + cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) } - cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) } } @@ -783,6 +869,24 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) { } } +// setGraphQL creates the GraphQL listener interface string from the set +// command line flags, returning empty if the GraphQL endpoint is disabled. +func setGraphQL(ctx *cli.Context, cfg *node.Config) { + if ctx.GlobalBool(GraphQLEnabledFlag.Name) && cfg.GraphQLHost == "" { + cfg.GraphQLHost = "127.0.0.1" + if ctx.GlobalIsSet(GraphQLListenAddrFlag.Name) { + cfg.GraphQLHost = ctx.GlobalString(GraphQLListenAddrFlag.Name) + } + } + cfg.GraphQLPort = ctx.GlobalInt(GraphQLPortFlag.Name) + if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) { + cfg.GraphQLCors = splitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name)) + } + if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) { + cfg.GraphQLVirtualHosts = splitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name)) + } +} + // setWS creates the WebSocket RPC listener interface string from the set // command line flags, returning empty if the HTTP endpoint is disabled. func setWS(ctx *cli.Context, cfg *node.Config) { @@ -816,22 +920,52 @@ func setIPC(ctx *cli.Context, cfg *node.Config) { } } +// SetULC setup ULC config from file if given. +func SetULC(ctx *cli.Context, cfg *eth.Config) { + // ULC config isn't loaded from global config and ULC config and ULC trusted nodes are not defined. + if cfg.ULC == nil && !(ctx.GlobalIsSet(ULCModeConfigFlag.Name) || ctx.GlobalIsSet(ULCTrustedNodesFlag.Name)) { + return + } + cfg.ULC = ð.ULCConfig{} + + path := ctx.GlobalString(ULCModeConfigFlag.Name) + if path != "" { + cfgData, err := ioutil.ReadFile(path) + if err != nil { + Fatalf("Failed to unmarshal ULC configuration: %v", err) + } + + err = json.Unmarshal(cfgData, &cfg.ULC) + if err != nil { + Fatalf("Failed to unmarshal ULC configuration: %s", err.Error()) + } + } + + if trustedNodes := ctx.GlobalString(ULCTrustedNodesFlag.Name); trustedNodes != "" { + cfg.ULC.TrustedServers = strings.Split(trustedNodes, ",") + } + + if trustedFraction := ctx.GlobalInt(ULCMinTrustedFractionFlag.Name); trustedFraction > 0 { + cfg.ULC.MinTrustedFraction = trustedFraction + } + if cfg.ULC.MinTrustedFraction <= 0 && cfg.ULC.MinTrustedFraction > 100 { + log.Error("MinTrustedFraction is invalid", "MinTrustedFraction", cfg.ULC.MinTrustedFraction, "Changed to default", eth.DefaultULCMinTrustedFraction) + cfg.ULC.MinTrustedFraction = eth.DefaultULCMinTrustedFraction + } +} + // makeDatabaseHandles raises out the number of allowed file handles per process // for Geth and returns half of the allowance to assign to the database. func makeDatabaseHandles() int { - limit, err := fdlimit.Current() + limit, err := fdlimit.Maximum() if err != nil { Fatalf("Failed to retrieve file descriptor allowance: %v", err) } - if limit < 2048 { - if err := fdlimit.Raise(2048); err != nil { - Fatalf("Failed to raise file descriptor allowance: %v", err) - } + raised, err := fdlimit.Raise(uint64(limit)) + if err != nil { + Fatalf("Failed to raise file descriptor allowance: %v", err) } - if limit > 2048 { // cap database file descriptors even if more is available - limit = 2048 - } - return limit / 2 // Leave half for networking and other stuff + return int(raised / 2) // Leave half for networking and other stuff } // MakeAddress converts an account specified directly as a hex encoded string or @@ -872,11 +1006,15 @@ func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { } // Convert the etherbase into an address and configure it if etherbase != "" { - account, err := MakeAddress(ks, etherbase) - if err != nil { - Fatalf("Invalid miner etherbase: %v", err) + if ks != nil { + account, err := MakeAddress(ks, etherbase) + if err != nil { + Fatalf("Invalid miner etherbase: %v", err) + } + cfg.Etherbase = account.Address + } else { + Fatalf("No etherbase configured") } - cfg.Etherbase = account.Address } } @@ -970,18 +1108,13 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { SetP2PConfig(ctx, &cfg.P2P) setIPC(ctx, cfg) setHTTP(ctx, cfg) + setGraphQL(ctx, cfg) setWS(ctx, cfg) setNodeUserIdent(ctx, cfg) + setDataDir(ctx, cfg) - switch { - case ctx.GlobalIsSet(DataDirFlag.Name): - cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) - case ctx.GlobalBool(DeveloperFlag.Name): - cfg.DataDir = "" // unless explicitly requested, use memory databases - case ctx.GlobalBool(TestnetFlag.Name): - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") - case ctx.GlobalBool(RinkebyFlag.Name): - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") + if ctx.GlobalIsSet(ExternalSignerFlag.Name) { + cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) } if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { @@ -995,6 +1128,21 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { } } +func setDataDir(ctx *cli.Context, cfg *node.Config) { + switch { + case ctx.GlobalIsSet(DataDirFlag.Name): + cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) + case ctx.GlobalBool(DeveloperFlag.Name): + cfg.DataDir = "" // unless explicitly requested, use memory databases + case ctx.GlobalBool(TestnetFlag.Name): + cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") + case ctx.GlobalBool(RinkebyFlag.Name): + cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") + case ctx.GlobalBool(GoerliFlag.Name): + cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") + } +} + func setGPO(ctx *cli.Context, cfg *gasprice.Config) { if ctx.GlobalIsSet(GpoBlocksFlag.Name) { cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) @@ -1068,6 +1216,29 @@ func setEthash(ctx *cli.Context, cfg *eth.Config) { } } +func setWhitelist(ctx *cli.Context, cfg *eth.Config) { + whitelist := ctx.GlobalString(WhitelistFlag.Name) + if whitelist == "" { + return + } + cfg.Whitelist = make(map[uint64]common.Hash) + for _, entry := range strings.Split(whitelist, ",") { + parts := strings.Split(entry, "=") + if len(parts) != 2 { + Fatalf("Invalid whitelist entry: %s", entry) + } + number, err := strconv.ParseUint(parts[0], 0, 64) + if err != nil { + Fatalf("Invalid whitelist block number %s: %v", parts[0], err) + } + var hash common.Hash + if err = hash.UnmarshalText([]byte(parts[1])); err != nil { + Fatalf("Invalid whitelist hash %s: %v", parts[1], err) + } + cfg.Whitelist[number] = hash + } +} + // checkExclusive verifies that only a single instance of the provided flags was // set by the user. Each flag might optionally be followed by a string type to // specialize it further. @@ -1125,14 +1296,19 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { // Avoid conflicting network flags - checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag) + checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag) checkExclusive(ctx, LightServFlag, SyncModeFlag, "light") - - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + // Can't use both ephemeral unlocked and external signer + checkExclusive(ctx, DeveloperFlag, ExternalSignerFlag) + var ks *keystore.KeyStore + if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { + ks = keystores[0].(*keystore.KeyStore) + } setEtherbase(ctx, ks, cfg) setGPO(ctx, &cfg.GPO) setTxPool(ctx, &cfg.TxPool) setEthash(ctx, cfg) + setWhitelist(ctx, cfg) if ctx.GlobalIsSet(SyncModeFlag.Name) { cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) @@ -1140,13 +1316,17 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { if ctx.GlobalIsSet(LightServFlag.Name) { cfg.LightServ = ctx.GlobalInt(LightServFlag.Name) } + cfg.LightBandwidthIn = ctx.GlobalInt(LightBandwidthInFlag.Name) + cfg.LightBandwidthOut = ctx.GlobalInt(LightBandwidthOutFlag.Name) if ctx.GlobalIsSet(LightPeersFlag.Name) { cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) } + if ctx.GlobalIsSet(OnlyAnnounceModeFlag.Name) { + cfg.OnlyAnnounce = ctx.GlobalBool(OnlyAnnounceModeFlag.Name) + } if ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 } @@ -1157,8 +1337,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { } cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" + if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { + cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 + } if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { - cfg.TrieCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 } if ctx.GlobalIsSet(MinerNotifyFlag.Name) { cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") @@ -1218,6 +1401,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { cfg.NetworkId = 4 } cfg.Genesis = core.DefaultRinkebyGenesisBlock() + case ctx.GlobalBool(GoerliFlag.Name): + if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + cfg.NetworkId = 5 + } + cfg.Genesis = core.DefaultGoerliGenesisBlock() case ctx.GlobalBool(DeveloperFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 @@ -1245,10 +1433,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { cfg.MinerGasPrice = big.NewInt(1) } } - // TODO(fjl): move trie cache generations into config - if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 { - state.MaxTrieCacheGen = uint16(gen) - } } // SetDashboardConfig applies dashboard related command line flags to the config. @@ -1322,18 +1506,35 @@ func SetupMetrics(ctx *cli.Context) { database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) - hosttag = ctx.GlobalString(MetricsInfluxDBHostTagFlag.Name) ) if enableExport { + tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) + log.Info("Enabling metrics export to InfluxDB") - go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", map[string]string{ - "host": hosttag, - }) + + go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) } } } +func SplitTagsFlag(tagsFlag string) map[string]string { + tags := strings.Split(tagsFlag, ",") + tagsMap := map[string]string{} + + for _, t := range tags { + if t != "" { + kv := strings.Split(t, "=") + + if len(kv) == 2 { + tagsMap[kv[0]] = kv[1] + } + } + } + + return tagsMap +} + // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { var ( @@ -1344,7 +1545,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { if ctx.GlobalString(SyncModeFlag.Name) == "light" { name = "lightchaindata" } - chainDb, err := stack.OpenDatabase(name, cache, handles) + chainDb, err := stack.OpenDatabase(name, cache, handles, "") if err != nil { Fatalf("Could not open database: %v", err) } @@ -1358,6 +1559,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { genesis = core.DefaultTestnetGenesisBlock() case ctx.GlobalBool(RinkebyFlag.Name): genesis = core.DefaultRinkebyGenesisBlock() + case ctx.GlobalBool(GoerliFlag.Name): + genesis = core.DefaultGoerliGenesisBlock() case ctx.GlobalBool(DeveloperFlag.Name): Fatalf("Developer chains are ephemeral") } @@ -1368,7 +1571,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { var err error chainDb = MakeChainDatabase(ctx, stack) - config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) if err != nil { Fatalf("%v", err) @@ -1393,12 +1595,16 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } cache := &core.CacheConfig{ - Disabled: ctx.GlobalString(GCModeFlag.Name) == "archive", - TrieNodeLimit: eth.DefaultConfig.TrieCache, - TrieTimeLimit: eth.DefaultConfig.TrieTimeout, + Disabled: ctx.GlobalString(GCModeFlag.Name) == "archive", + TrieCleanLimit: eth.DefaultConfig.TrieCleanCache, + TrieDirtyLimit: eth.DefaultConfig.TrieDirtyCache, + TrieTimeLimit: eth.DefaultConfig.TrieTimeout, + } + if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { + cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 } if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { - cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 } vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil) @@ -1416,7 +1622,7 @@ func MakeConsolePreloads(ctx *cli.Context) []string { return nil } // Otherwise resolve absolute paths and return them - preloads := []string{} + var preloads []string assets := ctx.GlobalString(JSpathFlag.Name) for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags_test.go b/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags_test.go new file mode 100644 index 00000000..adfdd090 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/cmd/utils/flags_test.go @@ -0,0 +1,64 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +// Package utils contains internal helper functions for go-ethereum commands. +package utils + +import ( + "reflect" + "testing" +) + +func Test_SplitTagsFlag(t *testing.T) { + tests := []struct { + name string + args string + want map[string]string + }{ + { + "2 tags case", + "host=localhost,bzzkey=123", + map[string]string{ + "host": "localhost", + "bzzkey": "123", + }, + }, + { + "1 tag case", + "host=localhost123", + map[string]string{ + "host": "localhost123", + }, + }, + { + "empty case", + "", + map[string]string{}, + }, + { + "garbage", + "smth=smthelse=123", + map[string]string{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SplitTagsFlag(tt.args); !reflect.DeepEqual(got, tt.want) { + t.Errorf("splitTagsFlag() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/helpers.go b/vendor/github.com/ethereum/go-ethereum/common/compiler/helpers.go new file mode 100644 index 00000000..4de706f6 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/helpers.go @@ -0,0 +1,64 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package compiler wraps the Solidity and Vyper compiler executables (solc; vyper). +package compiler + +import ( + "bytes" + "io/ioutil" + "regexp" +) + +var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`) + +// Contract contains information about a compiled contract, alongside its code and runtime code. +type Contract struct { + Code string `json:"code"` + RuntimeCode string `json:"runtime-code"` + Info ContractInfo `json:"info"` +} + +// ContractInfo contains information about a compiled contract, including access +// to the ABI definition, source mapping, user and developer docs, and metadata. +// +// Depending on the source, language version, compiler version, and compiler +// options will provide information about how the contract was compiled. +type ContractInfo struct { + Source string `json:"source"` + Language string `json:"language"` + LanguageVersion string `json:"languageVersion"` + CompilerVersion string `json:"compilerVersion"` + CompilerOptions string `json:"compilerOptions"` + SrcMap interface{} `json:"srcMap"` + SrcMapRuntime string `json:"srcMapRuntime"` + AbiDefinition interface{} `json:"abiDefinition"` + UserDoc interface{} `json:"userDoc"` + DeveloperDoc interface{} `json:"developerDoc"` + Metadata string `json:"metadata"` +} + +func slurpFiles(files []string) (string, error) { + var concat bytes.Buffer + for _, file := range files { + content, err := ioutil.ReadFile(file) + if err != nil { + return "", err + } + concat.Write(content) + } + return concat.String(), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity.go b/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity.go index b7c8ec56..7ed9c263 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity.go +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package compiler wraps the Solidity compiler executable (solc). +// Package compiler wraps the Solidity and Vyper compiler executables (solc; vyper). package compiler import ( @@ -22,41 +22,11 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os/exec" - "regexp" "strconv" "strings" ) -var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`) - -// Contract contains information about a compiled contract, alongside its code and runtime code. -type Contract struct { - Code string `json:"code"` - RuntimeCode string `json:"runtime-code"` - Info ContractInfo `json:"info"` -} - -// ContractInfo contains information about a compiled contract, including access -// to the ABI definition, source mapping, user and developer docs, and metadata. -// -// Depending on the source, language version, compiler version, and compiler -// options will provide information about how the contract was compiled. -type ContractInfo struct { - Source string `json:"source"` - Language string `json:"language"` - LanguageVersion string `json:"languageVersion"` - CompilerVersion string `json:"compilerVersion"` - CompilerOptions string `json:"compilerOptions"` - SrcMap string `json:"srcMap"` - SrcMapRuntime string `json:"srcMapRuntime"` - AbiDefinition interface{} `json:"abiDefinition"` - UserDoc interface{} `json:"userDoc"` - DeveloperDoc interface{} `json:"developerDoc"` - Metadata string `json:"metadata"` -} - // Solidity contains information about the solidity compiler. type Solidity struct { Path, Version, FullVersion string @@ -208,15 +178,3 @@ func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion strin } return contracts, nil } - -func slurpFiles(files []string) (string, error) { - var concat bytes.Buffer - for _, file := range files { - content, err := ioutil.ReadFile(file) - if err != nil { - return "", err - } - concat.Write(content) - } - return concat.String(), nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity_test.go b/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity_test.go index 0da3bb33..6be2bda5 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity_test.go +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/solidity_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -23,9 +23,10 @@ import ( const ( testSource = ` +pragma solidity >0.0.0; contract test { /// @notice Will multiply ` + "`a`" + ` by 7. - function multiply(uint a) returns(uint d) { + function multiply(uint a) public returns(uint d) { return a * 7; } } @@ -38,7 +39,7 @@ func skipWithoutSolc(t *testing.T) { } } -func TestCompiler(t *testing.T) { +func TestSolidityCompiler(t *testing.T) { skipWithoutSolc(t) contracts, err := CompileSolidityString("", testSource) @@ -66,7 +67,7 @@ func TestCompiler(t *testing.T) { } } -func TestCompileError(t *testing.T) { +func TestSolidityCompileError(t *testing.T) { skipWithoutSolc(t) contracts, err := CompileSolidityString("", testSource[4:]) diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/test.v.py b/vendor/github.com/ethereum/go-ethereum/common/compiler/test.v.py new file mode 100644 index 00000000..35af56c8 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/test.v.py @@ -0,0 +1,3 @@ +@public +def test(): + hello: int128 diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/test_bad.v.py b/vendor/github.com/ethereum/go-ethereum/common/compiler/test_bad.v.py new file mode 100644 index 00000000..443ef782 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/test_bad.v.py @@ -0,0 +1,3 @@ +lic +def test(): + hello: int128 diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/vyper.go b/vendor/github.com/ethereum/go-ethereum/common/compiler/vyper.go new file mode 100644 index 00000000..a9bca95e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/vyper.go @@ -0,0 +1,144 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package compiler wraps the Solidity and Vyper compiler executables (solc; vyper). +package compiler + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "os/exec" + "strconv" + "strings" +) + +// Vyper contains information about the vyper compiler. +type Vyper struct { + Path, Version, FullVersion string + Major, Minor, Patch int +} + +func (s *Vyper) makeArgs() []string { + p := []string{ + "-f", "combined_json", + } + return p +} + +// VyperVersion runs vyper and parses its version output. +func VyperVersion(vyper string) (*Vyper, error) { + if vyper == "" { + vyper = "vyper" + } + var out bytes.Buffer + cmd := exec.Command(vyper, "--version") + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return nil, err + } + matches := versionRegexp.FindStringSubmatch(out.String()) + if len(matches) != 4 { + return nil, fmt.Errorf("can't parse vyper version %q", out.String()) + } + s := &Vyper{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]} + if s.Major, err = strconv.Atoi(matches[1]); err != nil { + return nil, err + } + if s.Minor, err = strconv.Atoi(matches[2]); err != nil { + return nil, err + } + if s.Patch, err = strconv.Atoi(matches[3]); err != nil { + return nil, err + } + return s, nil +} + +// CompileVyper compiles all given Vyper source files. +func CompileVyper(vyper string, sourcefiles ...string) (map[string]*Contract, error) { + if len(sourcefiles) == 0 { + return nil, errors.New("vyper: no source files") + } + source, err := slurpFiles(sourcefiles) + if err != nil { + return nil, err + } + s, err := VyperVersion(vyper) + if err != nil { + return nil, err + } + args := s.makeArgs() + cmd := exec.Command(s.Path, append(args, sourcefiles...)...) + return s.run(cmd, source) +} + +func (s *Vyper) run(cmd *exec.Cmd, source string) (map[string]*Contract, error) { + var stderr, stdout bytes.Buffer + cmd.Stderr = &stderr + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("vyper: %v\n%s", err, stderr.Bytes()) + } + + return ParseVyperJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " ")) +} + +// ParseVyperJSON takes the direct output of a vyper --f combined_json run and +// parses it into a map of string contract name to Contract structs. The +// provided source, language and compiler version, and compiler options are all +// passed through into the Contract structs. +// +// The vyper output is expected to contain ABI and source mapping. +// +// Returns an error if the JSON is malformed or missing data, or if the JSON +// embedded within the JSON is malformed. +func ParseVyperJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) { + var output map[string]interface{} + if err := json.Unmarshal(combinedJSON, &output); err != nil { + return nil, err + } + + // Compilation succeeded, assemble and return the contracts. + contracts := make(map[string]*Contract) + for name, info := range output { + // Parse the individual compilation results. + if name == "version" { + continue + } + c := info.(map[string]interface{}) + + contracts[name] = &Contract{ + Code: c["bytecode"].(string), + RuntimeCode: c["bytecode_runtime"].(string), + Info: ContractInfo{ + Source: source, + Language: "Vyper", + LanguageVersion: languageVersion, + CompilerVersion: compilerVersion, + CompilerOptions: compilerOptions, + SrcMap: c["source_map"], + SrcMapRuntime: "", + AbiDefinition: c["abi"], + UserDoc: "", + DeveloperDoc: "", + Metadata: "", + }, + } + } + return contracts, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/common/compiler/vyper_test.go b/vendor/github.com/ethereum/go-ethereum/common/compiler/vyper_test.go new file mode 100644 index 00000000..7761c92a --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/common/compiler/vyper_test.go @@ -0,0 +1,71 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package compiler + +import ( + "os/exec" + "testing" +) + +func skipWithoutVyper(t *testing.T) { + if _, err := exec.LookPath("vyper"); err != nil { + t.Skip(err) + } +} + +func TestVyperCompiler(t *testing.T) { + skipWithoutVyper(t) + + testSource := []string{"test.v.py"} + source, err := slurpFiles(testSource) + if err != nil { + t.Error("couldn't read test files") + } + contracts, err := CompileVyper("", testSource...) + if err != nil { + t.Fatalf("error compiling test.v.py. result %v: %v", contracts, err) + } + if len(contracts) != 1 { + t.Errorf("one contract expected, got %d", len(contracts)) + } + c, ok := contracts["test.v.py"] + if !ok { + c, ok = contracts[":test"] + if !ok { + t.Fatal("info for contract 'test.v.py' not present in result") + } + } + if c.Code == "" { + t.Error("empty code") + } + if c.Info.Source != source { + t.Error("wrong source") + } + if c.Info.CompilerVersion == "" { + t.Error("empty version") + } +} + +func TestVyperCompileError(t *testing.T) { + skipWithoutVyper(t) + + contracts, err := CompileVyper("", "test_bad.v.py") + if err == nil { + t.Errorf("error expected compiling test_bad.v.py. got none. result %v", contracts) + } + t.Logf("error: %v", err) +} diff --git a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_darwin.go b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_darwin.go new file mode 100644 index 00000000..88dd0f56 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_darwin.go @@ -0,0 +1,71 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package fdlimit + +import "syscall" + +// hardlimit is the number of file descriptors allowed at max by the kernel. +const hardlimit = 10240 + +// Raise tries to maximize the file descriptor allowance of this process +// to the maximum hard-limit allowed by the OS. +// Returns the size it was set to (may differ from the desired 'max') +func Raise(max uint64) (uint64, error) { + // Get the current limit + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + // Try to update the limit to the max allowance + limit.Cur = limit.Max + if limit.Cur > max { + limit.Cur = max + } + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + // MacOS can silently apply further caps, so retrieve the actually set limit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + return limit.Cur, nil +} + +// Current retrieves the number of file descriptors allowed to be opened by this +// process. +func Current() (int, error) { + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + return int(limit.Cur), nil +} + +// Maximum retrieves the maximum number of file descriptors this process is +// allowed to request for itself. +func Maximum() (int, error) { + // Retrieve the maximum allowed by dynamic OS limits + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + // Cap it to OPEN_MAX (10240) because macos is a special snowflake + if limit.Max > hardlimit { + limit.Max = hardlimit + } + return int(limit.Max), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_freebsd.go b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_freebsd.go index c126b0c2..0d872713 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_freebsd.go +++ b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_freebsd.go @@ -26,11 +26,11 @@ import "syscall" // Raise tries to maximize the file descriptor allowance of this process // to the maximum hard-limit allowed by the OS. -func Raise(max uint64) error { +func Raise(max uint64) (uint64, error) { // Get the current limit var limit syscall.Rlimit if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { - return err + return 0, err } // Try to update the limit to the max allowance limit.Cur = limit.Max @@ -38,9 +38,12 @@ func Raise(max uint64) error { limit.Cur = int64(max) } if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { - return err + return 0, err } - return nil + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + return uint64(limit.Cur), nil } // Current retrieves the number of file descriptors allowed to be opened by this diff --git a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_test.go b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_test.go index a9ee9ab3..21362b84 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_test.go +++ b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_test.go @@ -36,7 +36,7 @@ func TestFileDescriptorLimits(t *testing.T) { if limit, err := Current(); err != nil || limit <= 0 { t.Fatalf("failed to retrieve file descriptor limit (%d): %v", limit, err) } - if err := Raise(uint64(target)); err != nil { + if _, err := Raise(uint64(target)); err != nil { t.Fatalf("failed to raise file allowance") } if limit, err := Current(); err != nil || limit < target { diff --git a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_unix.go b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_unix.go index a2581323..e5a575f7 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_unix.go +++ b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_unix.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build linux darwin netbsd openbsd solaris +// +build linux netbsd openbsd solaris package fdlimit @@ -22,11 +22,12 @@ import "syscall" // Raise tries to maximize the file descriptor allowance of this process // to the maximum hard-limit allowed by the OS. -func Raise(max uint64) error { +// Returns the size it was set to (may differ from the desired 'max') +func Raise(max uint64) (uint64, error) { // Get the current limit var limit syscall.Rlimit if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { - return err + return 0, err } // Try to update the limit to the max allowance limit.Cur = limit.Max @@ -34,9 +35,13 @@ func Raise(max uint64) error { limit.Cur = max } if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { - return err + return 0, err } - return nil + // MacOS can silently apply further caps, so retrieve the actually set limit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + return limit.Cur, nil } // Current retrieves the number of file descriptors allowed to be opened by this diff --git a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_windows.go b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_windows.go index 863c58be..f4721536 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_windows.go +++ b/vendor/github.com/ethereum/go-ethereum/common/fdlimit/fdlimit_windows.go @@ -16,28 +16,31 @@ package fdlimit -import "errors" +import "fmt" + +// hardlimit is the number of file descriptors allowed at max by the kernel. +const hardlimit = 16384 // Raise tries to maximize the file descriptor allowance of this process // to the maximum hard-limit allowed by the OS. -func Raise(max uint64) error { +func Raise(max uint64) (uint64, error) { // This method is NOP by design: // * Linux/Darwin counterparts need to manually increase per process limits // * On Windows Go uses the CreateFile API, which is limited to 16K files, non // changeable from within a running process // This way we can always "request" raising the limits, which will either have // or not have effect based on the platform we're running on. - if max > 16384 { - return errors.New("file descriptor limit (16384) reached") + if max > hardlimit { + return hardlimit, fmt.Errorf("file descriptor limit (%d) reached", hardlimit) } - return nil + return max, nil } // Current retrieves the number of file descriptors allowed to be opened by this // process. func Current() (int, error) { // Please see Raise for the reason why we use hard coded 16K as the limit - return 16384, nil + return hardlimit, nil } // Maximum retrieves the maximum number of file descriptors this process is diff --git a/vendor/github.com/ethereum/go-ethereum/common/hexutil/json.go b/vendor/github.com/ethereum/go-ethereum/common/hexutil/json.go index fbc21241..777b08ec 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/hexutil/json.go +++ b/vendor/github.com/ethereum/go-ethereum/common/hexutil/json.go @@ -72,6 +72,25 @@ func (b Bytes) String() string { return Encode(b) } +// ImplementsGraphQLType returns true if Bytes implements the specified GraphQL type. +func (b Bytes) ImplementsGraphQLType(name string) bool { return name == "Bytes" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (b *Bytes) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + data, err := Decode(input) + if err != nil { + return err + } + *b = data + default: + err = fmt.Errorf("Unexpected type for Bytes: %v", input) + } + return err +} + // UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length of out // determines the required input length. This function is commonly used to implement the // UnmarshalJSON method for fixed-size types. @@ -187,6 +206,25 @@ func (b *Big) String() string { return EncodeBig(b.ToInt()) } +// ImplementsGraphQLType returns true if Big implements the provided GraphQL type. +func (b Big) ImplementsGraphQLType(name string) bool { return name == "BigInt" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (b *Big) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + return b.UnmarshalText([]byte(input)) + case int32: + var num big.Int + num.SetInt64(int64(input)) + *b = Big(num) + default: + err = fmt.Errorf("Unexpected type for BigInt: %v", input) + } + return err +} + // Uint64 marshals/unmarshals as a JSON string with 0x prefix. // The zero value marshals as "0x0". type Uint64 uint64 @@ -234,6 +272,23 @@ func (b Uint64) String() string { return EncodeUint64(uint64(b)) } +// ImplementsGraphQLType returns true if Uint64 implements the provided GraphQL type. +func (b Uint64) ImplementsGraphQLType(name string) bool { return name == "Long" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (b *Uint64) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + return b.UnmarshalText([]byte(input)) + case int32: + *b = Uint64(input) + default: + err = fmt.Errorf("Unexpected type for Long: %v", input) + } + return err +} + // Uint marshals/unmarshals as a JSON string with 0x prefix. // The zero value marshals as "0x0". type Uint uint diff --git a/vendor/github.com/ethereum/go-ethereum/common/size.go b/vendor/github.com/ethereum/go-ethereum/common/size.go index bd0fc85c..6381499a 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/size.go +++ b/vendor/github.com/ethereum/go-ethereum/common/size.go @@ -26,10 +26,10 @@ type StorageSize float64 // String implements the stringer interface. func (s StorageSize) String() string { - if s > 1000000 { - return fmt.Sprintf("%.2f mB", s/1000000) - } else if s > 1000 { - return fmt.Sprintf("%.2f kB", s/1000) + if s > 1048576 { + return fmt.Sprintf("%.2f MiB", s/1048576) + } else if s > 1024 { + return fmt.Sprintf("%.2f KiB", s/1024) } else { return fmt.Sprintf("%.2f B", s) } @@ -38,10 +38,10 @@ func (s StorageSize) String() string { // TerminalString implements log.TerminalStringer, formatting a string for console // output during logging. func (s StorageSize) TerminalString() string { - if s > 1000000 { - return fmt.Sprintf("%.2fmB", s/1000000) - } else if s > 1000 { - return fmt.Sprintf("%.2fkB", s/1000) + if s > 1048576 { + return fmt.Sprintf("%.2fMiB", s/1048576) + } else if s > 1024 { + return fmt.Sprintf("%.2fKiB", s/1024) } else { return fmt.Sprintf("%.2fB", s) } diff --git a/vendor/github.com/ethereum/go-ethereum/common/size_test.go b/vendor/github.com/ethereum/go-ethereum/common/size_test.go index f5b6c725..0938d483 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/size_test.go +++ b/vendor/github.com/ethereum/go-ethereum/common/size_test.go @@ -25,8 +25,8 @@ func TestStorageSizeString(t *testing.T) { size StorageSize str string }{ - {2381273, "2.38 mB"}, - {2192, "2.19 kB"}, + {2381273, "2.27 MiB"}, + {2192, "2.14 KiB"}, {12, "12.00 B"}, } diff --git a/vendor/github.com/ethereum/go-ethereum/common/types.go b/vendor/github.com/ethereum/go-ethereum/common/types.go index a4b99952..98c83edd 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/types.go +++ b/vendor/github.com/ethereum/go-ethereum/common/types.go @@ -27,7 +27,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto/sha3" + "golang.org/x/crypto/sha3" ) // Lengths of hashes and addresses in bytes. @@ -141,6 +141,21 @@ func (h Hash) Value() (driver.Value, error) { return h[:], nil } +// ImplementsGraphQLType returns true if Hash implements the specified GraphQL type. +func (_ Hash) ImplementsGraphQLType(name string) bool { return name == "Bytes32" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (h *Hash) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + *h = HexToHash(input) + default: + err = fmt.Errorf("Unexpected type for Bytes32: %v", input) + } + return err +} + // UnprefixedHash allows marshaling a Hash without 0x prefix. type UnprefixedHash Hash @@ -187,16 +202,13 @@ func IsHexAddress(s string) bool { // Bytes gets the string representation of the underlying address. func (a Address) Bytes() []byte { return a[:] } -// Big converts an address to a big integer. -func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) } - // Hash converts an address to a hash by left-padding it with zeros. func (a Address) Hash() Hash { return BytesToHash(a[:]) } // Hex returns an EIP55-compliant hex string representation of the address. func (a Address) Hex() string { unchecksummed := hex.EncodeToString(a[:]) - sha := sha3.NewKeccak256() + sha := sha3.NewLegacyKeccak256() sha.Write([]byte(unchecksummed)) hash := sha.Sum(nil) @@ -268,6 +280,21 @@ func (a Address) Value() (driver.Value, error) { return a[:], nil } +// ImplementsGraphQLType returns true if Hash implements the specified GraphQL type. +func (a Address) ImplementsGraphQLType(name string) bool { return name == "Address" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (a *Address) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + *a = HexToAddress(input) + default: + err = fmt.Errorf("Unexpected type for Address: %v", input) + } + return err +} + // UnprefixedAddress allows marshaling an Address without 0x prefix. type UnprefixedAddress Address diff --git a/vendor/github.com/ethereum/go-ethereum/common/types_test.go b/vendor/github.com/ethereum/go-ethereum/common/types_test.go index 7095ccd0..fffd673c 100644 --- a/vendor/github.com/ethereum/go-ethereum/common/types_test.go +++ b/vendor/github.com/ethereum/go-ethereum/common/types_test.go @@ -114,8 +114,8 @@ func TestAddressUnmarshalJSON(t *testing.T) { if test.ShouldErr { t.Errorf("test #%d: expected error, got none", i) } - if v.Big().Cmp(test.Output) != 0 { - t.Errorf("test #%d: address mismatch: have %v, want %v", i, v.Big(), test.Output) + if got := new(big.Int).SetBytes(v.Bytes()); got.Cmp(test.Output) != 0 { + t.Errorf("test #%d: address mismatch: have %v, want %v", i, got, test.Output) } } } diff --git a/vendor/github.com/ethereum/go-ethereum/consensus/clique/clique.go b/vendor/github.com/ethereum/go-ethereum/consensus/clique/clique.go index eae09f91..967a843d 100644 --- a/vendor/github.com/ethereum/go-ethereum/consensus/clique/clique.go +++ b/vendor/github.com/ethereum/go-ethereum/consensus/clique/clique.go @@ -20,6 +20,7 @@ package clique import ( "bytes" "errors" + "io" "math/big" "math/rand" "sync" @@ -33,13 +34,13 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" lru "github.com/hashicorp/golang-lru" + "golang.org/x/crypto/sha3" ) const ( @@ -136,40 +137,9 @@ var ( errRecentlySigned = errors.New("recently signed") ) -// SignerFn is a signer callback function to request a hash to be signed by a +// SignerFn is a signer callback function to request a header to be signed by a // backing account. -type SignerFn func(accounts.Account, []byte) ([]byte, error) - -// sigHash returns the hash which is used as input for the proof-of-authority -// signing. It is the hash of the entire header apart from the 65 byte signature -// contained at the end of the extra data. -// -// Note, the method requires the extra data to be at least 65 bytes, otherwise it -// panics. This is done to avoid accidentally using both forms (signature present -// or not), which could be abused to produce different hashes for the same header. -func sigHash(header *types.Header) (hash common.Hash) { - hasher := sha3.NewKeccak256() - - rlp.Encode(hasher, []interface{}{ - header.ParentHash, - header.UncleHash, - header.Coinbase, - header.Root, - header.TxHash, - header.ReceiptHash, - header.Bloom, - header.Difficulty, - header.Number, - header.GasLimit, - header.GasUsed, - header.Time, - header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short - header.MixDigest, - header.Nonce, - }) - hasher.Sum(hash[:0]) - return hash -} +type SignerFn func(accounts.Account, string, []byte) ([]byte, error) // ecrecover extracts the Ethereum account address from a signed header. func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) { @@ -185,7 +155,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er signature := header.Extra[len(header.Extra)-extraSeal:] // Recover the public key and the Ethereum address - pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature) + pubkey, err := crypto.Ecrecover(SealHash(header).Bytes(), signature) if err != nil { return common.Address{}, err } @@ -646,7 +616,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle)) } // Sign all the things! - sighash, err := signFn(accounts.Account{Address: signer}, sigHash(header).Bytes()) + sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeClique, CliqueRLP(header)) if err != nil { return err } @@ -663,7 +633,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c select { case results <- block.WithSeal(header): default: - log.Warn("Sealing result is not read by miner", "sealhash", c.SealHash(header)) + log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header)) } }() @@ -693,10 +663,10 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int { // SealHash returns the hash of a block prior to it being sealed. func (c *Clique) SealHash(header *types.Header) common.Hash { - return sigHash(header) + return SealHash(header) } -// Close implements consensus.Engine. It's a noop for clique as there is are no background threads. +// Close implements consensus.Engine. It's a noop for clique as there are no background threads. func (c *Clique) Close() error { return nil } @@ -711,3 +681,47 @@ func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API { Public: false, }} } + +// SealHash returns the hash of a block prior to it being sealed. +func SealHash(header *types.Header) (hash common.Hash) { + hasher := sha3.NewLegacyKeccak256() + encodeSigHeader(hasher, header) + hasher.Sum(hash[:0]) + return hash +} + +// CliqueRLP returns the rlp bytes which needs to be signed for the proof-of-authority +// sealing. The RLP to sign consists of the entire header apart from the 65 byte signature +// contained at the end of the extra data. +// +// Note, the method requires the extra data to be at least 65 bytes, otherwise it +// panics. This is done to avoid accidentally using both forms (signature present +// or not), which could be abused to produce different hashes for the same header. +func CliqueRLP(header *types.Header) []byte { + b := new(bytes.Buffer) + encodeSigHeader(b, header) + return b.Bytes() +} + +func encodeSigHeader(w io.Writer, header *types.Header) { + err := rlp.Encode(w, []interface{}{ + header.ParentHash, + header.UncleHash, + header.Coinbase, + header.Root, + header.TxHash, + header.ReceiptHash, + header.Bloom, + header.Difficulty, + header.Number, + header.GasLimit, + header.GasUsed, + header.Time, + header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short + header.MixDigest, + header.Nonce, + }) + if err != nil { + panic("can't encode: " + err.Error()) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/consensus/clique/snapshot_test.go b/vendor/github.com/ethereum/go-ethereum/consensus/clique/snapshot_test.go index 41dae142..fc08722e 100644 --- a/vendor/github.com/ethereum/go-ethereum/consensus/clique/snapshot_test.go +++ b/vendor/github.com/ethereum/go-ethereum/consensus/clique/snapshot_test.go @@ -24,10 +24,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -80,7 +80,7 @@ func (ap *testerAccountPool) sign(header *types.Header, signer string) { ap.accounts[signer], _ = crypto.GenerateKey() } // Sign the header and embed the signature in extra data - sig, _ := crypto.Sign(sigHash(header).Bytes(), ap.accounts[signer]) + sig, _ := crypto.Sign(SealHash(header).Bytes(), ap.accounts[signer]) copy(header.Extra[len(header.Extra)-extraSeal:], sig) } @@ -246,10 +246,10 @@ func TestClique(t *testing.T) { // Votes from deauthorized signers are discarded immediately (auth votes) signers: []string{"A", "B", "C"}, votes: []testerVote{ - {signer: "C", voted: "B", auth: false}, + {signer: "C", voted: "D", auth: true}, {signer: "A", voted: "C", auth: false}, {signer: "B", voted: "C", auth: false}, - {signer: "A", voted: "B", auth: false}, + {signer: "A", voted: "D", auth: true}, }, results: []string{"A", "B"}, }, { @@ -400,7 +400,7 @@ func TestClique(t *testing.T) { copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) } // Create a pristine blockchain with the genesis injected - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() genesis.Commit(db) // Assemble a chain of headers from the cast votes diff --git a/vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm.go b/vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm.go index f252a7f3..d6c87109 100644 --- a/vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm.go +++ b/vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm.go @@ -30,8 +30,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/log" + "golang.org/x/crypto/sha3" ) const ( @@ -123,7 +123,7 @@ func seedHash(block uint64) []byte { if block < epochLength { return seed } - keccak256 := makeHasher(sha3.NewKeccak256()) + keccak256 := makeHasher(sha3.NewLegacyKeccak256()) for i := 0; i < int(block/epochLength); i++ { keccak256(seed, seed) } @@ -177,7 +177,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { } }() // Create a hasher to reuse between invocations - keccak512 := makeHasher(sha3.NewKeccak512()) + keccak512 := makeHasher(sha3.NewLegacyKeccak512()) // Sequentially produce the initial dataset keccak512(cache, seed) @@ -301,7 +301,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) { defer pend.Done() // Create a hasher to reuse between invocations - keccak512 := makeHasher(sha3.NewKeccak512()) + keccak512 := makeHasher(sha3.NewLegacyKeccak512()) // Calculate the data segment this thread should generate batch := uint32((size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads))) @@ -375,7 +375,7 @@ func hashimoto(hash []byte, nonce uint64, size uint64, lookup func(index uint32) // in-memory cache) in order to produce our final value for a particular header // hash and nonce. func hashimotoLight(size uint64, cache []uint32, hash []byte, nonce uint64) ([]byte, []byte) { - keccak512 := makeHasher(sha3.NewKeccak512()) + keccak512 := makeHasher(sha3.NewLegacyKeccak512()) lookup := func(index uint32) []uint32 { rawData := generateDatasetItem(cache, index, keccak512) diff --git a/vendor/github.com/ethereum/go-ethereum/consensus/ethash/consensus.go b/vendor/github.com/ethereum/go-ethereum/consensus/ethash/consensus.go index 548c57cd..62e3f8fc 100644 --- a/vendor/github.com/ethereum/go-ethereum/consensus/ethash/consensus.go +++ b/vendor/github.com/ethereum/go-ethereum/consensus/ethash/consensus.go @@ -31,9 +31,9 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) // Ethash proof-of-work protocol constants. @@ -575,7 +575,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header // SealHash returns the hash of a block prior to it being sealed. func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() rlp.Encode(hasher, []interface{}{ header.ParentHash, diff --git a/vendor/github.com/ethereum/go-ethereum/console/bridge.go b/vendor/github.com/ethereum/go-ethereum/console/bridge.go index b0b4d379..33277cf6 100644 --- a/vendor/github.com/ethereum/go-ethereum/console/bridge.go +++ b/vendor/github.com/ethereum/go-ethereum/console/bridge.go @@ -105,9 +105,37 @@ func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) { return val } // Wallet open failed, report error unless it's a PIN entry - if !strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPINNeeded.Error()) { + if strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPINNeeded.Error()) { + val, err = b.readPinAndReopenWallet(call) + if err == nil { + return val + } + } + // Check if the user needs to input a passphrase + if !strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPassphraseNeeded.Error()) { throwJSException(err.Error()) } + val, err = b.readPassphraseAndReopenWallet(call) + if err != nil { + throwJSException(err.Error()) + } + return val +} + +func (b *bridge) readPassphraseAndReopenWallet(call otto.FunctionCall) (otto.Value, error) { + var passwd otto.Value + wallet := call.Argument(0) + if input, err := b.prompter.PromptPassword("Please enter your passphrase: "); err != nil { + throwJSException(err.Error()) + } else { + passwd, _ = otto.ToValue(input) + } + return call.Otto.Call("jeth.openWallet", nil, wallet, passwd) +} + +func (b *bridge) readPinAndReopenWallet(call otto.FunctionCall) (otto.Value, error) { + var passwd otto.Value + wallet := call.Argument(0) // Trezor PIN matrix input requested, display the matrix to the user and fetch the data fmt.Fprintf(b.printer, "Look at the device for number positions\n\n") fmt.Fprintf(b.printer, "7 | 8 | 9\n") @@ -121,10 +149,7 @@ func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) { } else { passwd, _ = otto.ToValue(input) } - if val, err = call.Otto.Call("jeth.openWallet", nil, wallet, passwd); err != nil { - throwJSException(err.Error()) - } - return val + return call.Otto.Call("jeth.openWallet", nil, wallet, passwd) } // UnlockAccount is a wrapper around the personal.unlockAccount RPC method that diff --git a/vendor/github.com/ethereum/go-ethereum/console/console.go b/vendor/github.com/ethereum/go-ethereum/console/console.go index 3c397f80..50196d7f 100644 --- a/vendor/github.com/ethereum/go-ethereum/console/console.go +++ b/vendor/github.com/ethereum/go-ethereum/console/console.go @@ -120,10 +120,10 @@ func (c *Console) init(preload []string) error { consoleObj.Object().Set("error", c.consoleOutput) // Load all the internal utility JavaScript libraries - if err := c.jsre.Compile("bignumber.js", jsre.BigNumber_JS); err != nil { + if err := c.jsre.Compile("bignumber.js", jsre.BignumberJs); err != nil { return fmt.Errorf("bignumber.js: %v", err) } - if err := c.jsre.Compile("web3.js", jsre.Web3_JS); err != nil { + if err := c.jsre.Compile("web3.js", jsre.Web3Js); err != nil { return fmt.Errorf("web3.js: %v", err) } if _, err := c.jsre.Run("var Web3 = require('web3');"); err != nil { @@ -236,7 +236,7 @@ func (c *Console) clearHistory() { // consoleOutput is an override for the console.log and console.error methods to // stream the output into the configured output stream instead of stdout. func (c *Console) consoleOutput(call otto.FunctionCall) otto.Value { - output := []string{} + var output []string for _, argument := range call.ArgumentList { output = append(output, fmt.Sprintf("%v", argument)) } diff --git a/vendor/github.com/ethereum/go-ethereum/console/console_test.go b/vendor/github.com/ethereum/go-ethereum/console/console_test.go index 26465ca6..55d79972 100644 --- a/vendor/github.com/ethereum/go-ethereum/console/console_test.go +++ b/vendor/github.com/ethereum/go-ethereum/console/console_test.go @@ -149,8 +149,8 @@ func (env *tester) Close(t *testing.T) { if err := env.console.Stop(false); err != nil { t.Errorf("failed to stop embedded console: %v", err) } - if err := env.stack.Stop(); err != nil { - t.Errorf("failed to stop embedded node: %v", err) + if err := env.stack.Close(); err != nil { + t.Errorf("failed to tear down embedded node: %v", err) } os.RemoveAll(env.workspace) } diff --git a/vendor/github.com/ethereum/go-ethereum/containers/docker/develop-alpine/Dockerfile b/vendor/github.com/ethereum/go-ethereum/containers/docker/develop-alpine/Dockerfile deleted file mode 100644 index 1f3e1112..00000000 --- a/vendor/github.com/ethereum/go-ethereum/containers/docker/develop-alpine/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM alpine:3.7 - -RUN \ - apk add --update go git make gcc musl-dev linux-headers ca-certificates && \ - git clone --depth 1 https://github.com/ethereum/go-ethereum && \ - (cd go-ethereum && make geth) && \ - cp go-ethereum/build/bin/geth /geth && \ - apk del go git make gcc musl-dev linux-headers && \ - rm -rf /go-ethereum && rm -rf /var/cache/apk/* - -EXPOSE 8545 -EXPOSE 30303 - -ENTRYPOINT ["/geth"] diff --git a/vendor/github.com/ethereum/go-ethereum/containers/docker/develop-ubuntu/Dockerfile b/vendor/github.com/ethereum/go-ethereum/containers/docker/develop-ubuntu/Dockerfile deleted file mode 100644 index 8c4fe9f5..00000000 --- a/vendor/github.com/ethereum/go-ethereum/containers/docker/develop-ubuntu/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM ubuntu:xenial - -ENV PATH=/usr/lib/go-1.9/bin:$PATH - -RUN \ - apt-get update && apt-get upgrade -q -y && \ - apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates && \ - git clone --depth 1 https://github.com/ethereum/go-ethereum && \ - (cd go-ethereum && make geth) && \ - cp go-ethereum/build/bin/geth /geth && \ - apt-get remove -y golang-1.9 git make gcc libc-dev && apt autoremove -y && apt-get clean && \ - rm -rf /go-ethereum - -EXPOSE 8545 -EXPOSE 30303 - -ENTRYPOINT ["/geth"] diff --git a/vendor/github.com/ethereum/go-ethereum/containers/docker/master-alpine/Dockerfile b/vendor/github.com/ethereum/go-ethereum/containers/docker/master-alpine/Dockerfile deleted file mode 100644 index 8d4e7fe8..00000000 --- a/vendor/github.com/ethereum/go-ethereum/containers/docker/master-alpine/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM alpine:3.7 - -RUN \ - apk add --update go git make gcc musl-dev linux-headers ca-certificates && \ - git clone --depth 1 --branch release/1.8 https://github.com/ethereum/go-ethereum && \ - (cd go-ethereum && make geth) && \ - cp go-ethereum/build/bin/geth /geth && \ - apk del go git make gcc musl-dev linux-headers && \ - rm -rf /go-ethereum && rm -rf /var/cache/apk/* - -EXPOSE 8545 -EXPOSE 30303 - -ENTRYPOINT ["/geth"] diff --git a/vendor/github.com/ethereum/go-ethereum/containers/docker/master-ubuntu/Dockerfile b/vendor/github.com/ethereum/go-ethereum/containers/docker/master-ubuntu/Dockerfile deleted file mode 100644 index 4cfc4f58..00000000 --- a/vendor/github.com/ethereum/go-ethereum/containers/docker/master-ubuntu/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM ubuntu:xenial - -ENV PATH=/usr/lib/go-1.9/bin:$PATH - -RUN \ - apt-get update && apt-get upgrade -q -y && \ - apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates && \ - git clone --depth 1 --branch release/1.8 https://github.com/ethereum/go-ethereum && \ - (cd go-ethereum && make geth) && \ - cp go-ethereum/build/bin/geth /geth && \ - apt-get remove -y golang-1.9 git make gcc libc-dev && apt autoremove -y && apt-get clean && \ - rm -rf /go-ethereum - -EXPOSE 8545 -EXPOSE 30303 - -ENTRYPOINT ["/geth"] diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/api.go b/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/api.go index b2b2365f..fb708030 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/api.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/api.go @@ -27,40 +27,40 @@ const Version = "1.0" var errNoChequebook = errors.New("no chequebook") -type Api struct { +type API struct { chequebookf func() *Chequebook } -func NewApi(ch func() *Chequebook) *Api { - return &Api{ch} +func NewAPI(ch func() *Chequebook) *API { + return &API{ch} } -func (self *Api) Balance() (string, error) { - ch := self.chequebookf() +func (a *API) Balance() (string, error) { + ch := a.chequebookf() if ch == nil { return "", errNoChequebook } return ch.Balance().String(), nil } -func (self *Api) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) { - ch := self.chequebookf() +func (a *API) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) { + ch := a.chequebookf() if ch == nil { return nil, errNoChequebook } return ch.Issue(beneficiary, amount) } -func (self *Api) Cash(cheque *Cheque) (txhash string, err error) { - ch := self.chequebookf() +func (a *API) Cash(cheque *Cheque) (txhash string, err error) { + ch := a.chequebookf() if ch == nil { return "", errNoChequebook } return ch.Cash(cheque) } -func (self *Api) Deposit(amount *big.Int) (txhash string, err error) { - ch := self.chequebookf() +func (a *API) Deposit(amount *big.Int) (txhash string, err error) { + ch := a.chequebookf() if ch == nil { return "", errNoChequebook } diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/cheque.go b/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/cheque.go index 92bd896e..32e84067 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/cheque.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/cheque.go @@ -75,8 +75,8 @@ type Cheque struct { Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey) } -func (self *Cheque) String() string { - return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", self.Contract.Hex(), self.Beneficiary.Hex(), self.Amount, self.Sig) +func (ch *Cheque) String() string { + return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", ch.Contract.Hex(), ch.Beneficiary.Hex(), ch.Amount, ch.Sig) } type Params struct { @@ -109,12 +109,12 @@ type Chequebook struct { log log.Logger // contextual logger with the contract address embedded } -func (self *Chequebook) String() string { - return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", self.contractAddr.Hex(), self.owner.Hex(), self.balance, self.prvKey.PublicKey) +func (cb *Chequebook) String() string { + return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", cb.contractAddr.Hex(), cb.owner.Hex(), cb.balance, cb.prvKey.PublicKey) } // NewChequebook creates a new Chequebook. -func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (self *Chequebook, err error) { +func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (*Chequebook, error) { balance := new(big.Int) sent := make(map[common.Address]*big.Int) @@ -128,7 +128,7 @@ func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.Priva TransactOpts: *transactOpts, } - self = &Chequebook{ + cb := &Chequebook{ prvKey: prvKey, balance: balance, contractAddr: contractAddr, @@ -140,42 +140,39 @@ func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.Priva session: session, log: log.New("contract", contractAddr), } - if (contractAddr != common.Address{}) { - self.setBalanceFromBlockChain() - self.log.Trace("New chequebook initialised", "owner", self.owner, "balance", self.balance) + cb.setBalanceFromBlockChain() + cb.log.Trace("New chequebook initialised", "owner", cb.owner, "balance", cb.balance) } - return + return cb, nil } -func (self *Chequebook) setBalanceFromBlockChain() { - balance, err := self.backend.BalanceAt(context.TODO(), self.contractAddr, nil) +func (cb *Chequebook) setBalanceFromBlockChain() { + balance, err := cb.backend.BalanceAt(context.TODO(), cb.contractAddr, nil) if err != nil { log.Error("Failed to retrieve chequebook balance", "err", err) } else { - self.balance.Set(balance) + cb.balance.Set(balance) } } // LoadChequebook loads a chequebook from disk (file path). -func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (self *Chequebook, err error) { - var data []byte - data, err = ioutil.ReadFile(path) - if err != nil { - return - } - self, _ = NewChequebook(path, common.Address{}, prvKey, backend) - - err = json.Unmarshal(data, self) +func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (*Chequebook, error) { + data, err := ioutil.ReadFile(path) if err != nil { return nil, err } + cb, _ := NewChequebook(path, common.Address{}, prvKey, backend) + + if err = json.Unmarshal(data, cb); err != nil { + return nil, err + } if checkBalance { - self.setBalanceFromBlockChain() + cb.setBalanceFromBlockChain() } log.Trace("Loaded chequebook from disk", "path", path) - return + return cb, nil } // chequebookFile is the JSON representation of a chequebook. @@ -187,19 +184,19 @@ type chequebookFile struct { } // UnmarshalJSON deserialises a chequebook. -func (self *Chequebook) UnmarshalJSON(data []byte) error { +func (cb *Chequebook) UnmarshalJSON(data []byte) error { var file chequebookFile err := json.Unmarshal(data, &file) if err != nil { return err } - _, ok := self.balance.SetString(file.Balance, 10) + _, ok := cb.balance.SetString(file.Balance, 10) if !ok { return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance) } - self.contractAddr = common.HexToAddress(file.Contract) + cb.contractAddr = common.HexToAddress(file.Contract) for addr, sent := range file.Sent { - self.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10) + cb.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10) if !ok { return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent) } @@ -208,14 +205,14 @@ func (self *Chequebook) UnmarshalJSON(data []byte) error { } // MarshalJSON serialises a chequebook. -func (self *Chequebook) MarshalJSON() ([]byte, error) { +func (cb *Chequebook) MarshalJSON() ([]byte, error) { var file = &chequebookFile{ - Balance: self.balance.String(), - Contract: self.contractAddr.Hex(), - Owner: self.owner.Hex(), + Balance: cb.balance.String(), + Contract: cb.contractAddr.Hex(), + Owner: cb.owner.Hex(), Sent: make(map[string]string), } - for addr, sent := range self.sent { + for addr, sent := range cb.sent { file.Sent[addr.Hex()] = sent.String() } return json.Marshal(file) @@ -223,76 +220,78 @@ func (self *Chequebook) MarshalJSON() ([]byte, error) { // Save persists the chequebook on disk, remembering balance, contract address and // cumulative amount of funds sent for each beneficiary. -func (self *Chequebook) Save() (err error) { - data, err := json.MarshalIndent(self, "", " ") +func (cb *Chequebook) Save() error { + data, err := json.MarshalIndent(cb, "", " ") if err != nil { return err } - self.log.Trace("Saving chequebook to disk", self.path) + cb.log.Trace("Saving chequebook to disk", cb.path) - return ioutil.WriteFile(self.path, data, os.ModePerm) + return ioutil.WriteFile(cb.path, data, os.ModePerm) } // Stop quits the autodeposit go routine to terminate -func (self *Chequebook) Stop() { - defer self.lock.Unlock() - self.lock.Lock() - if self.quit != nil { - close(self.quit) - self.quit = nil +func (cb *Chequebook) Stop() { + defer cb.lock.Unlock() + cb.lock.Lock() + if cb.quit != nil { + close(cb.quit) + cb.quit = nil } } // Issue creates a cheque signed by the chequebook owner's private key. The // signer commits to a contract (one that they own), a beneficiary and amount. -func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) { - defer self.lock.Unlock() - self.lock.Lock() +func (cb *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (*Cheque, error) { + defer cb.lock.Unlock() + cb.lock.Lock() if amount.Sign() <= 0 { return nil, fmt.Errorf("amount must be greater than zero (%v)", amount) } - if self.balance.Cmp(amount) < 0 { - err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance) + var ( + ch *Cheque + err error + ) + if cb.balance.Cmp(amount) < 0 { + err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, cb.balance) } else { var sig []byte - sent, found := self.sent[beneficiary] + sent, found := cb.sent[beneficiary] if !found { sent = new(big.Int) - self.sent[beneficiary] = sent + cb.sent[beneficiary] = sent } sum := new(big.Int).Set(sent) sum.Add(sum, amount) - sig, err = crypto.Sign(sigHash(self.contractAddr, beneficiary, sum), self.prvKey) + sig, err = crypto.Sign(sigHash(cb.contractAddr, beneficiary, sum), cb.prvKey) if err == nil { ch = &Cheque{ - Contract: self.contractAddr, + Contract: cb.contractAddr, Beneficiary: beneficiary, Amount: sum, Sig: sig, } sent.Set(sum) - self.balance.Sub(self.balance, amount) // subtract amount from balance + cb.balance.Sub(cb.balance, amount) // subtract amount from balance } } - // auto deposit if threshold is set and balance is less then threshold // note this is called even if issuing cheque fails // so we reattempt depositing - if self.threshold != nil { - if self.balance.Cmp(self.threshold) < 0 { - send := new(big.Int).Sub(self.buffer, self.balance) - self.deposit(send) + if cb.threshold != nil { + if cb.balance.Cmp(cb.threshold) < 0 { + send := new(big.Int).Sub(cb.buffer, cb.balance) + cb.deposit(send) } } - - return + return ch, err } // Cash is a convenience method to cash any cheque. -func (self *Chequebook) Cash(ch *Cheque) (txhash string, err error) { - return ch.Cash(self.session) +func (cb *Chequebook) Cash(ch *Cheque) (string, error) { + return ch.Cash(cb.session) } // data to sign: contract address, beneficiary, cumulative amount of funds ever sent @@ -309,73 +308,73 @@ func sigHash(contract, beneficiary common.Address, sum *big.Int) []byte { } // Balance returns the current balance of the chequebook. -func (self *Chequebook) Balance() *big.Int { - defer self.lock.Unlock() - self.lock.Lock() - return new(big.Int).Set(self.balance) +func (cb *Chequebook) Balance() *big.Int { + defer cb.lock.Unlock() + cb.lock.Lock() + return new(big.Int).Set(cb.balance) } // Owner returns the owner account of the chequebook. -func (self *Chequebook) Owner() common.Address { - return self.owner +func (cb *Chequebook) Owner() common.Address { + return cb.owner } // Address returns the on-chain contract address of the chequebook. -func (self *Chequebook) Address() common.Address { - return self.contractAddr +func (cb *Chequebook) Address() common.Address { + return cb.contractAddr } // Deposit deposits money to the chequebook account. -func (self *Chequebook) Deposit(amount *big.Int) (string, error) { - defer self.lock.Unlock() - self.lock.Lock() - return self.deposit(amount) +func (cb *Chequebook) Deposit(amount *big.Int) (string, error) { + defer cb.lock.Unlock() + cb.lock.Lock() + return cb.deposit(amount) } // deposit deposits amount to the chequebook account. -// The caller must hold self.lock. -func (self *Chequebook) deposit(amount *big.Int) (string, error) { +// The caller must hold lock. +func (cb *Chequebook) deposit(amount *big.Int) (string, error) { // since the amount is variable here, we do not use sessions - depositTransactor := bind.NewKeyedTransactor(self.prvKey) + depositTransactor := bind.NewKeyedTransactor(cb.prvKey) depositTransactor.Value = amount - chbookRaw := &contract.ChequebookRaw{Contract: self.contract} + chbookRaw := &contract.ChequebookRaw{Contract: cb.contract} tx, err := chbookRaw.Transfer(depositTransactor) if err != nil { - self.log.Warn("Failed to fund chequebook", "amount", amount, "balance", self.balance, "target", self.buffer, "err", err) + cb.log.Warn("Failed to fund chequebook", "amount", amount, "balance", cb.balance, "target", cb.buffer, "err", err) return "", err } // assume that transaction is actually successful, we add the amount to balance right away - self.balance.Add(self.balance, amount) - self.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", self.balance, "target", self.buffer) + cb.balance.Add(cb.balance, amount) + cb.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", cb.balance, "target", cb.buffer) return tx.Hash().Hex(), nil } // AutoDeposit (re)sets interval time and amount which triggers sending funds to the // chequebook. Contract backend needs to be set if threshold is not less than buffer, then // deposit will be triggered on every new cheque issued. -func (self *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - defer self.lock.Unlock() - self.lock.Lock() - self.threshold = threshold - self.buffer = buffer - self.autoDeposit(interval) +func (cb *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { + defer cb.lock.Unlock() + cb.lock.Lock() + cb.threshold = threshold + cb.buffer = buffer + cb.autoDeposit(interval) } // autoDeposit starts a goroutine that periodically sends funds to the chequebook // contract caller holds the lock the go routine terminates if Chequebook.quit is closed. -func (self *Chequebook) autoDeposit(interval time.Duration) { - if self.quit != nil { - close(self.quit) - self.quit = nil +func (cb *Chequebook) autoDeposit(interval time.Duration) { + if cb.quit != nil { + close(cb.quit) + cb.quit = nil } // if threshold >= balance autodeposit after every cheque issued - if interval == time.Duration(0) || self.threshold != nil && self.buffer != nil && self.threshold.Cmp(self.buffer) >= 0 { + if interval == time.Duration(0) || cb.threshold != nil && cb.buffer != nil && cb.threshold.Cmp(cb.buffer) >= 0 { return } ticker := time.NewTicker(interval) - self.quit = make(chan bool) - quit := self.quit + cb.quit = make(chan bool) + quit := cb.quit go func() { for { @@ -383,15 +382,15 @@ func (self *Chequebook) autoDeposit(interval time.Duration) { case <-quit: return case <-ticker.C: - self.lock.Lock() - if self.balance.Cmp(self.buffer) < 0 { - amount := new(big.Int).Sub(self.buffer, self.balance) - txhash, err := self.deposit(amount) + cb.lock.Lock() + if cb.balance.Cmp(cb.buffer) < 0 { + amount := new(big.Int).Sub(cb.buffer, cb.balance) + txhash, err := cb.deposit(amount) if err == nil { - self.txhash = txhash + cb.txhash = txhash } } - self.lock.Unlock() + cb.lock.Unlock() } } }() @@ -404,26 +403,26 @@ type Outbox struct { } // NewOutbox creates an outbox. -func NewOutbox(chbook *Chequebook, beneficiary common.Address) *Outbox { - return &Outbox{chbook, beneficiary} +func NewOutbox(cb *Chequebook, beneficiary common.Address) *Outbox { + return &Outbox{cb, beneficiary} } // Issue creates cheque. -func (self *Outbox) Issue(amount *big.Int) (swap.Promise, error) { - return self.chequeBook.Issue(self.beneficiary, amount) +func (o *Outbox) Issue(amount *big.Int) (swap.Promise, error) { + return o.chequeBook.Issue(o.beneficiary, amount) } // AutoDeposit enables auto-deposits on the underlying chequebook. -func (self *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - self.chequeBook.AutoDeposit(interval, threshold, buffer) +func (o *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { + o.chequeBook.AutoDeposit(interval, threshold, buffer) } // Stop helps satisfy the swap.OutPayment interface. -func (self *Outbox) Stop() {} +func (o *Outbox) Stop() {} // String implements fmt.Stringer. -func (self *Outbox) String() string { - return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.chequeBook.Address().Hex(), self.beneficiary.Hex(), self.chequeBook.Balance()) +func (o *Outbox) String() string { + return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", o.chequeBook.Address().Hex(), o.beneficiary.Hex(), o.chequeBook.Balance()) } // Inbox can deposit, verify and cash cheques from a single contract to a single @@ -445,7 +444,7 @@ type Inbox struct { // NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated // from blockchain when first cheque is received. -func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (self *Inbox, err error) { +func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (*Inbox, error) { if signer == nil { return nil, fmt.Errorf("signer is null") } @@ -461,7 +460,7 @@ func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address } sender := transactOpts.From - self = &Inbox{ + inbox := &Inbox{ contract: contractAddr, beneficiary: beneficiary, sender: sender, @@ -470,59 +469,61 @@ func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address cashed: new(big.Int).Set(common.Big0), log: log.New("contract", contractAddr), } - self.log.Trace("New chequebook inbox initialized", "beneficiary", self.beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer))) - return + inbox.log.Trace("New chequebook inbox initialized", "beneficiary", inbox.beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer))) + return inbox, nil } -func (self *Inbox) String() string { - return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.contract.Hex(), self.beneficiary.Hex(), self.cheque.Amount) +func (i *Inbox) String() string { + return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", i.contract.Hex(), i.beneficiary.Hex(), i.cheque.Amount) } // Stop quits the autocash goroutine. -func (self *Inbox) Stop() { - defer self.lock.Unlock() - self.lock.Lock() - if self.quit != nil { - close(self.quit) - self.quit = nil +func (i *Inbox) Stop() { + defer i.lock.Unlock() + i.lock.Lock() + if i.quit != nil { + close(i.quit) + i.quit = nil } } // Cash attempts to cash the current cheque. -func (self *Inbox) Cash() (txhash string, err error) { - if self.cheque != nil { - txhash, err = self.cheque.Cash(self.session) - self.log.Trace("Cashing in chequebook cheque", "amount", self.cheque.Amount, "beneficiary", self.beneficiary) - self.cashed = self.cheque.Amount +func (i *Inbox) Cash() (string, error) { + if i.cheque == nil { + return "", nil } - return + txhash, err := i.cheque.Cash(i.session) + i.log.Trace("Cashing in chequebook cheque", "amount", i.cheque.Amount, "beneficiary", i.beneficiary) + i.cashed = i.cheque.Amount + + return txhash, err } // AutoCash (re)sets maximum time and amount which triggers cashing of the last uncashed // cheque if maxUncashed is set to 0, then autocash on receipt. -func (self *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) { - defer self.lock.Unlock() - self.lock.Lock() - self.maxUncashed = maxUncashed - self.autoCash(cashInterval) +func (i *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) { + defer i.lock.Unlock() + i.lock.Lock() + i.maxUncashed = maxUncashed + i.autoCash(cashInterval) } // autoCash starts a loop that periodically clears the last cheque // if the peer is trusted. Clearing period could be 24h or a week. -// The caller must hold self.lock. -func (self *Inbox) autoCash(cashInterval time.Duration) { - if self.quit != nil { - close(self.quit) - self.quit = nil +// The caller must hold lock. +func (i *Inbox) autoCash(cashInterval time.Duration) { + if i.quit != nil { + close(i.quit) + i.quit = nil } // if maxUncashed is set to 0, then autocash on receipt - if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Sign() == 0 { + if cashInterval == time.Duration(0) || i.maxUncashed != nil && i.maxUncashed.Sign() == 0 { return } ticker := time.NewTicker(cashInterval) - self.quit = make(chan bool) - quit := self.quit + i.quit = make(chan bool) + quit := i.quit go func() { for { @@ -530,14 +531,14 @@ func (self *Inbox) autoCash(cashInterval time.Duration) { case <-quit: return case <-ticker.C: - self.lock.Lock() - if self.cheque != nil && self.cheque.Amount.Cmp(self.cashed) != 0 { - txhash, err := self.Cash() + i.lock.Lock() + if i.cheque != nil && i.cheque.Amount.Cmp(i.cashed) != 0 { + txhash, err := i.Cash() if err == nil { - self.txhash = txhash + i.txhash = txhash } } - self.lock.Unlock() + i.lock.Unlock() } } }() @@ -545,56 +546,56 @@ func (self *Inbox) autoCash(cashInterval time.Duration) { // Receive is called to deposit the latest cheque to the incoming Inbox. // The given promise must be a *Cheque. -func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) { +func (i *Inbox) Receive(promise swap.Promise) (*big.Int, error) { ch := promise.(*Cheque) - defer self.lock.Unlock() - self.lock.Lock() + defer i.lock.Unlock() + i.lock.Lock() var sum *big.Int - if self.cheque == nil { + if i.cheque == nil { // the sum is checked against the blockchain once a cheque is received - tally, err := self.session.Sent(self.beneficiary) + tally, err := i.session.Sent(i.beneficiary) if err != nil { return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err) } sum = tally } else { - sum = self.cheque.Amount + sum = i.cheque.Amount } - amount, err := ch.Verify(self.signer, self.contract, self.beneficiary, sum) + amount, err := ch.Verify(i.signer, i.contract, i.beneficiary, sum) var uncashed *big.Int if err == nil { - self.cheque = ch + i.cheque = ch - if self.maxUncashed != nil { - uncashed = new(big.Int).Sub(ch.Amount, self.cashed) - if self.maxUncashed.Cmp(uncashed) < 0 { - self.Cash() + if i.maxUncashed != nil { + uncashed = new(big.Int).Sub(ch.Amount, i.cashed) + if i.maxUncashed.Cmp(uncashed) < 0 { + i.Cash() } } - self.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed) + i.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed) } return amount, err } // Verify verifies cheque for signer, contract, beneficiary, amount, valid signature. -func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) { - log.Trace("Verifying chequebook cheque", "cheque", self, "sum", sum) +func (ch *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) { + log.Trace("Verifying chequebook cheque", "cheque", ch, "sum", sum) if sum == nil { return nil, fmt.Errorf("invalid amount") } - if self.Beneficiary != beneficiary { - return nil, fmt.Errorf("beneficiary mismatch: %v != %v", self.Beneficiary.Hex(), beneficiary.Hex()) + if ch.Beneficiary != beneficiary { + return nil, fmt.Errorf("beneficiary mismatch: %v != %v", ch.Beneficiary.Hex(), beneficiary.Hex()) } - if self.Contract != contract { - return nil, fmt.Errorf("contract mismatch: %v != %v", self.Contract.Hex(), contract.Hex()) + if ch.Contract != contract { + return nil, fmt.Errorf("contract mismatch: %v != %v", ch.Contract.Hex(), contract.Hex()) } - amount := new(big.Int).Set(self.Amount) + amount := new(big.Int).Set(ch.Amount) if sum != nil { amount.Sub(amount, sum) if amount.Sign() <= 0 { @@ -602,7 +603,7 @@ func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary com } } - pubKey, err := crypto.SigToPub(sigHash(self.Contract, beneficiary, self.Amount), self.Sig) + pubKey, err := crypto.SigToPub(sigHash(ch.Contract, beneficiary, ch.Amount), ch.Sig) if err != nil { return nil, fmt.Errorf("invalid signature: %v", err) } @@ -621,9 +622,9 @@ func sig2vrs(sig []byte) (v byte, r, s [32]byte) { } // Cash cashes the cheque by sending an Ethereum transaction. -func (self *Cheque) Cash(session *contract.ChequebookSession) (string, error) { - v, r, s := sig2vrs(self.Sig) - tx, err := session.Cash(self.Beneficiary, self.Amount, v, r, s) +func (ch *Cheque) Cash(session *contract.ChequebookSession) (string, error) { + v, r, s := sig2vrs(ch.Sig) + tx, err := session.Cash(ch.Beneficiary, ch.Amount, v, r, s) if err != nil { return "", err } @@ -632,7 +633,7 @@ func (self *Cheque) Cash(session *contract.ChequebookSession) (string, error) { // ValidateCode checks that the on-chain code at address matches the expected chequebook // contract code. This is used to detect suicided chequebooks. -func ValidateCode(ctx context.Context, b Backend, address common.Address) (ok bool, err error) { +func ValidateCode(ctx context.Context, b Backend, address common.Address) (bool, error) { code, err := b.CodeAt(ctx, address, nil) if err != nil { return false, err diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/contract/chequebook.go b/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/contract/chequebook.go index e275ac9b..3129b811 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/contract/chequebook.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/chequebook/contract/chequebook.go @@ -205,22 +205,22 @@ func (_Chequebook *ChequebookCallerSession) Sent(arg0 common.Address) (*big.Int, // Cash is a paid mutator transaction binding the contract method 0xfbf788d6. // // Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookTransactor) Cash(opts *bind.TransactOpts, beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) { - return _Chequebook.contract.Transact(opts, "cash", beneficiary, amount, sig_v, sig_r, sig_s) +func (_Chequebook *ChequebookTransactor) Cash(opts *bind.TransactOpts, beneficiary common.Address, amount *big.Int, sigV uint8, sigR [32]byte, sigS [32]byte) (*types.Transaction, error) { + return _Chequebook.contract.Transact(opts, "cash", beneficiary, amount, sigV, sigR, sigS) } // Cash is a paid mutator transaction binding the contract method 0xfbf788d6. // // Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookSession) Cash(beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) { - return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sig_v, sig_r, sig_s) +func (_Chequebook *ChequebookSession) Cash(beneficiary common.Address, amount *big.Int, sigV uint8, sigR [32]byte, sigS [32]byte) (*types.Transaction, error) { + return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sigV, sigR, sigS) } // Cash is a paid mutator transaction binding the contract method 0xfbf788d6. // // Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookTransactorSession) Cash(beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) { - return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sig_v, sig_r, sig_s) +func (_Chequebook *ChequebookTransactorSession) Cash(beneficiary common.Address, amount *big.Int, sigV uint8, sigR [32]byte, sigS [32]byte) (*types.Transaction, error) { + return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sigV, sigR, sigS) } // Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/README.md b/vendor/github.com/ethereum/go-ethereum/contracts/ens/README.md index c09b47e3..f2ea1330 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/README.md +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/README.md @@ -18,3 +18,13 @@ The go bindings for ENS contracts are generated using `abigen` via the go genera ```shell go generate ./contracts/ens ``` + +## Fallback contract support + +In order to better support content resolution on different service providers (such as Swarm and IPFS), [EIP-1577](https://eips.ethereum.org/EIPS/eip-1577) +was introduced and with it changes that allow applications to know _where_ content hashes are stored (i.e. if the +requested hash resides on Swarm or IPFS). + +The code under `contracts/ens/contract` reflects the new Public Resolver changes and the code under `fallback_contract` allows +us to support the old contract resolution in cases where the ENS name owner did not update her Resolver contract, until the migration +period ends (date arbitrarily set to June 1st, 2019). diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/cid.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/cid.go new file mode 100644 index 00000000..673e8203 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/cid.go @@ -0,0 +1,121 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package ens + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" +) + +const ( + cidv1 = 0x1 + + nsIpfs = 0xe3 + nsSwarm = 0xe4 + + swarmTypecode = 0xfa // swarm manifest, see https://github.com/multiformats/multicodec/blob/master/table.csv + swarmHashtype = 0x1b // keccak256, see https://github.com/multiformats/multicodec/blob/master/table.csv + + hashLength = 32 +) + +// deocodeEIP1577ContentHash decodes a chain-stored content hash from an ENS record according to EIP-1577 +// a successful decode will result the different parts of the content hash in accordance to the CID spec +// Note: only CIDv1 is supported +func decodeEIP1577ContentHash(buf []byte) (storageNs, contentType, hashType, hashLength uint64, hash []byte, err error) { + if len(buf) < 10 { + return 0, 0, 0, 0, nil, errors.New("buffer too short") + } + + storageNs, n := binary.Uvarint(buf) + + buf = buf[n:] + vers, n := binary.Uvarint(buf) + + if vers != 1 { + return 0, 0, 0, 0, nil, fmt.Errorf("expected cid v1, got: %d", vers) + } + buf = buf[n:] + contentType, n = binary.Uvarint(buf) + + buf = buf[n:] + hashType, n = binary.Uvarint(buf) + + buf = buf[n:] + hashLength, n = binary.Uvarint(buf) + + hash = buf[n:] + + if len(hash) != int(hashLength) { + return 0, 0, 0, 0, nil, errors.New("hash length mismatch") + } + return storageNs, contentType, hashType, hashLength, hash, nil +} + +func extractContentHash(buf []byte) (common.Hash, error) { + storageNs, _ /*contentType*/, _ /* hashType*/, decodedHashLength, hashBytes, err := decodeEIP1577ContentHash(buf) + + if err != nil { + return common.Hash{}, err + } + + if storageNs != nsSwarm { + return common.Hash{}, errors.New("unknown storage system") + } + + //todo: for the time being we implement loose enforcement for the EIP rules until ENS manager is updated + /*if contentType != swarmTypecode { + return common.Hash{}, errors.New("unknown content type") + } + + if hashType != swarmHashtype { + return common.Hash{}, errors.New("unknown multihash type") + }*/ + + if decodedHashLength != hashLength { + return common.Hash{}, errors.New("odd hash length, swarm expects 32 bytes") + } + + if len(hashBytes) != int(hashLength) { + return common.Hash{}, errors.New("hash length mismatch") + } + + return common.BytesToHash(buf), nil +} + +func EncodeSwarmHash(hash common.Hash) ([]byte, error) { + var cidBytes []byte + var headerBytes = []byte{ + nsSwarm, //swarm namespace + cidv1, // CIDv1 + swarmTypecode, // swarm hash + swarmHashtype, // keccak256 hash + hashLength, //hash length. 32 bytes + } + + varintbuf := make([]byte, binary.MaxVarintLen64) + for _, v := range headerBytes { + n := binary.PutUvarint(varintbuf, uint64(v)) + cidBytes = append(cidBytes, varintbuf[:n]...) + } + + cidBytes = append(cidBytes, hash[:]...) + return cidBytes, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/cid_test.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/cid_test.go new file mode 100644 index 00000000..7d0e6785 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/cid_test.go @@ -0,0 +1,158 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package ens + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// Tests for the decoding of the example ENS +func TestEIPSpecCidDecode(t *testing.T) { + const ( + eipSpecHash = "e3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" + eipHash = "29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" + dagPb = 0x70 + sha2256 = 0x12 + ) + b, err := hex.DecodeString(eipSpecHash) + if err != nil { + t.Fatal(err) + } + hashBytes, err := hex.DecodeString(eipHash) + + if err != nil { + t.Fatal(err) + } + + storageNs, contentType, hashType, hashLength, decodedHashBytes, err := decodeEIP1577ContentHash(b) + + if err != nil { + t.Fatal(err) + } + if storageNs != nsIpfs { + t.Fatal("wrong ns") + } + if contentType != dagPb { + t.Fatal("should be ipfs typecode") + } + if hashType != sha2256 { + t.Fatal("should be sha2-256") + } + if hashLength != 32 { + t.Fatal("should be 32") + } + if !bytes.Equal(hashBytes, decodedHashBytes) { + t.Fatal("should be equal") + } + +} +func TestManualCidDecode(t *testing.T) { + // call cid encode method with hash. expect byte slice returned, compare according to spec + + for _, v := range []struct { + name string + headerBytes []byte + wantErr bool + }{ + { + name: "values correct, should not fail", + headerBytes: []byte{0xe4, 0x01, 0xfa, 0x1b, 0x20}, + wantErr: false, + }, + { + name: "cid version wrong, should fail", + headerBytes: []byte{0xe4, 0x00, 0xfa, 0x1b, 0x20}, + wantErr: true, + }, + { + name: "hash length wrong, should fail", + headerBytes: []byte{0xe4, 0x01, 0xfa, 0x1b, 0x1f}, + wantErr: true, + }, + { + name: "values correct for ipfs, should fail", + headerBytes: []byte{0xe3, 0x01, 0x70, 0x12, 0x20}, + wantErr: true, + }, + { + name: "loose values for swarm, todo remove, should not fail", + headerBytes: []byte{0xe4, 0x01, 0x70, 0x12, 0x20}, + wantErr: false, + }, + { + name: "loose values for swarm, todo remove, should not fail", + headerBytes: []byte{0xe4, 0x01, 0x99, 0x99, 0x20}, + wantErr: false, + }, + } { + t.Run(v.name, func(t *testing.T) { + const eipHash = "29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" + + var bb []byte + buf := make([]byte, binary.MaxVarintLen64) + for _, vv := range v.headerBytes { + n := binary.PutUvarint(buf, uint64(vv)) + bb = append(bb, buf[:n]...) + } + + h := common.HexToHash(eipHash) + bb = append(bb, h[:]...) + str := hex.EncodeToString(bb) + fmt.Println(str) + decodedHash, e := extractContentHash(bb) + switch v.wantErr { + case true: + if e == nil { + t.Fatal("the decode should fail") + } + case false: + if e != nil { + t.Fatalf("the deccode shouldnt fail: %v", e) + } + if !bytes.Equal(decodedHash[:], h[:]) { + t.Fatal("hashes not equal") + } + } + }) + } +} + +func TestManuelCidEncode(t *testing.T) { + // call cid encode method with hash. expect byte slice returned, compare according to spec + const eipHash = "29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" + cidBytes, err := EncodeSwarmHash(common.HexToHash(eipHash)) + if err != nil { + t.Fatal(err) + } + + // logic in extractContentHash is unit tested thoroughly + // hence we just check that the returned hash is equal + h, err := extractContentHash(cidBytes) + if err != nil { + t.Fatal(err) + } + + if bytes.Equal(h[:], cidBytes) { + t.Fatal("should be equal") + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/AbstractENS.sol b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ENS.sol similarity index 55% rename from vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/AbstractENS.sol rename to vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ENS.sol index b80a1b0e..5ab8c92b 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/AbstractENS.sol +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ENS.sol @@ -1,13 +1,6 @@ -pragma solidity ^0.4.0; +pragma solidity >=0.4.24; -contract AbstractENS { - function owner(bytes32 node) constant returns(address); - function resolver(bytes32 node) constant returns(address); - function ttl(bytes32 node) constant returns(uint64); - function setOwner(bytes32 node, address owner); - function setSubnodeOwner(bytes32 node, bytes32 label, address owner); - function setResolver(bytes32 node, address resolver); - function setTTL(bytes32 node, uint64 ttl); +interface ENS { // Logged when the owner of a node assigns a new owner to a subnode. event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); @@ -20,4 +13,14 @@ contract AbstractENS { // Logged when the TTL of a node changes event NewTTL(bytes32 indexed node, uint64 ttl); -} + + + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external; + function setResolver(bytes32 node, address resolver) external; + function setOwner(bytes32 node, address owner) external; + function setTTL(bytes32 node, uint64 ttl) external; + function owner(bytes32 node) external view returns (address); + function resolver(bytes32 node) external view returns (address); + function ttl(bytes32 node) external view returns (uint64); + +} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ENSRegistry.sol b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ENSRegistry.sol new file mode 100644 index 00000000..fa19131d --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ENSRegistry.sol @@ -0,0 +1,99 @@ +pragma solidity ^0.5.0; + +import "./ENS.sol"; + +/** + * The ENS registry contract. + */ +contract ENSRegistry is ENS { + struct Record { + address owner; + address resolver; + uint64 ttl; + } + + mapping (bytes32 => Record) records; + + // Permits modifications only by the owner of the specified node. + modifier only_owner(bytes32 node) { + require(records[node].owner == msg.sender); + _; + } + + /** + * @dev Constructs a new ENS registrar. + */ + constructor() public { + records[0x0].owner = msg.sender; + } + + /** + * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node. + * @param node The node to transfer ownership of. + * @param owner The address of the new owner. + */ + function setOwner(bytes32 node, address owner) external only_owner(node) { + emit Transfer(node, owner); + records[node].owner = owner; + } + + /** + * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node. + * @param node The parent node. + * @param label The hash of the label specifying the subnode. + * @param owner The address of the new owner. + */ + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external only_owner(node) { + bytes32 subnode = keccak256(abi.encodePacked(node, label)); + emit NewOwner(node, label, owner); + records[subnode].owner = owner; + } + + /** + * @dev Sets the resolver address for the specified node. + * @param node The node to update. + * @param resolver The address of the resolver. + */ + function setResolver(bytes32 node, address resolver) external only_owner(node) { + emit NewResolver(node, resolver); + records[node].resolver = resolver; + } + + /** + * @dev Sets the TTL for the specified node. + * @param node The node to update. + * @param ttl The TTL in seconds. + */ + function setTTL(bytes32 node, uint64 ttl) external only_owner(node) { + emit NewTTL(node, ttl); + records[node].ttl = ttl; + } + + /** + * @dev Returns the address that owns the specified node. + * @param node The specified node. + * @return address of the owner. + */ + function owner(bytes32 node) external view returns (address) { + return records[node].owner; + } + + /** + * @dev Returns the address of the resolver for the specified node. + * @param node The specified node. + * @return address of the resolver. + */ + function resolver(bytes32 node) external view returns (address) { + return records[node].resolver; + } + + /** + * @dev Returns the TTL of a node, and any records associated with it. + * @param node The specified node. + * @return ttl of the node. + */ + function ttl(bytes32 node) external view returns (uint64) { + return records[node].ttl; + } + +} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/FIFSRegistrar.sol b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/FIFSRegistrar.sol index 51629c2b..19287408 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/FIFSRegistrar.sol +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/FIFSRegistrar.sol @@ -1,20 +1,17 @@ -pragma solidity ^0.4.0; +pragma solidity ^0.5.0; -import './AbstractENS.sol'; +import "./ENS.sol"; /** * A registrar that allocates subdomains to the first person to claim them. */ contract FIFSRegistrar { - AbstractENS ens; + ENS ens; bytes32 rootNode; - modifier only_owner(bytes32 subnode) { - var node = sha3(rootNode, subnode); - var currentOwner = ens.owner(node); - - if (currentOwner != 0 && currentOwner != msg.sender) throw; - + modifier only_owner(bytes32 label) { + address currentOwner = ens.owner(keccak256(abi.encodePacked(rootNode, label))); + require(currentOwner == address(0x0) || currentOwner == msg.sender); _; } @@ -23,17 +20,17 @@ contract FIFSRegistrar { * @param ensAddr The address of the ENS registry. * @param node The node that this registrar administers. */ - function FIFSRegistrar(AbstractENS ensAddr, bytes32 node) { + constructor(ENS ensAddr, bytes32 node) public { ens = ensAddr; rootNode = node; } /** * Register a name, or change the owner of an existing registration. - * @param subnode The hash of the label to register. + * @param label The hash of the label to register. * @param owner The address of the new owner. */ - function register(bytes32 subnode, address owner) only_owner(subnode) { - ens.setSubnodeOwner(rootNode, subnode, owner); + function register(bytes32 label, address owner) public only_owner(label) { + ens.setSubnodeOwner(rootNode, label, owner); } -} +} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/PublicResolver.sol b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/PublicResolver.sol index 9dcc9568..cfcd5dd6 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/PublicResolver.sol +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/PublicResolver.sol @@ -1,26 +1,27 @@ -pragma solidity ^0.4.0; +pragma solidity >=0.4.25; -import './AbstractENS.sol'; +import "./ENS.sol"; /** * A simple resolver anyone can use; only allows the owner of a node to set its * address. */ contract PublicResolver { + bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; - bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5; bytes4 constant NAME_INTERFACE_ID = 0x691f3431; bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; + bytes4 constant CONTENTHASH_INTERFACE_ID = 0xbc1c58d1; event AddrChanged(bytes32 indexed node, address a); - event ContentChanged(bytes32 indexed node, bytes32 hash); event NameChanged(bytes32 indexed node, string name); event ABIChanged(bytes32 indexed node, uint256 indexed contentType); event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); - event TextChanged(bytes32 indexed node, string indexed indexedKey, string key); + event TextChanged(bytes32 indexed node, string indexedKey, string key); + event ContenthashChanged(bytes32 indexed node, bytes hash); struct PublicKey { bytes32 x; @@ -29,18 +30,19 @@ contract PublicResolver { struct Record { address addr; - bytes32 content; string name; PublicKey pubkey; mapping(string=>string) text; mapping(uint256=>bytes) abis; + bytes contenthash; } - AbstractENS ens; - mapping(bytes32=>Record) records; + ENS ens; - modifier only_owner(bytes32 node) { - if (ens.owner(node) != msg.sender) throw; + mapping (bytes32 => Record) records; + + modifier onlyOwner(bytes32 node) { + require(ens.owner(node) == msg.sender); _; } @@ -48,77 +50,30 @@ contract PublicResolver { * Constructor. * @param ensAddr The ENS registrar contract. */ - function PublicResolver(AbstractENS ensAddr) { + constructor(ENS ensAddr) public { ens = ensAddr; } - /** - * Returns true if the resolver implements the interface specified by the provided hash. - * @param interfaceID The ID of the interface to check for. - * @return True if the contract implements the requested interface. - */ - function supportsInterface(bytes4 interfaceID) constant returns (bool) { - return interfaceID == ADDR_INTERFACE_ID || - interfaceID == CONTENT_INTERFACE_ID || - interfaceID == NAME_INTERFACE_ID || - interfaceID == ABI_INTERFACE_ID || - interfaceID == PUBKEY_INTERFACE_ID || - interfaceID == TEXT_INTERFACE_ID || - interfaceID == INTERFACE_META_ID; - } - - /** - * Returns the address associated with an ENS node. - * @param node The ENS node to query. - * @return The associated address. - */ - function addr(bytes32 node) constant returns (address ret) { - ret = records[node].addr; - } - /** * Sets the address associated with an ENS node. * May only be called by the owner of that node in the ENS registry. * @param node The node to update. * @param addr The address to set. */ - function setAddr(bytes32 node, address addr) only_owner(node) { + function setAddr(bytes32 node, address addr) external onlyOwner(node) { records[node].addr = addr; - AddrChanged(node, addr); + emit AddrChanged(node, addr); } /** - * Returns the content hash associated with an ENS node. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The ENS node to query. - * @return The associated content hash. - */ - function content(bytes32 node) constant returns (bytes32 ret) { - ret = records[node].content; - } - - /** - * Sets the content hash associated with an ENS node. + * Sets the contenthash associated with an ENS node. * May only be called by the owner of that node in the ENS registry. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. * @param node The node to update. - * @param hash The content hash to set + * @param hash The contenthash to set */ - function setContent(bytes32 node, bytes32 hash) only_owner(node) { - records[node].content = hash; - ContentChanged(node, hash); - } - - /** - * Returns the name associated with an ENS node, for reverse records. - * Defined in EIP181. - * @param node The ENS node to query. - * @return The associated name. - */ - function name(bytes32 node) constant returns (string ret) { - ret = records[node].name; + function setContenthash(bytes32 node, bytes calldata hash) external onlyOwner(node) { + records[node].contenthash = hash; + emit ContenthashChanged(node, hash); } /** @@ -127,28 +82,9 @@ contract PublicResolver { * @param node The node to update. * @param name The name to set. */ - function setName(bytes32 node, string name) only_owner(node) { + function setName(bytes32 node, string calldata name) external onlyOwner(node) { records[node].name = name; - NameChanged(node, name); - } - - /** - * Returns the ABI associated with an ENS node. - * Defined in EIP205. - * @param node The ENS node to query - * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. - * @return contentType The content type of the return value - * @return data The ABI data - */ - function ABI(bytes32 node, uint256 contentTypes) constant returns (uint256 contentType, bytes data) { - var record = records[node]; - for(contentType = 1; contentType <= contentTypes; contentType <<= 1) { - if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { - data = record.abis[contentType]; - return; - } - } - contentType = 0; + emit NameChanged(node, name); } /** @@ -159,22 +95,12 @@ contract PublicResolver { * @param contentType The content type of the ABI * @param data The ABI data. */ - function setABI(bytes32 node, uint256 contentType, bytes data) only_owner(node) { + function setABI(bytes32 node, uint256 contentType, bytes calldata data) external onlyOwner(node) { // Content types must be powers of 2 - if (((contentType - 1) & contentType) != 0) throw; + require(((contentType - 1) & contentType) == 0); records[node].abis[contentType] = data; - ABIChanged(node, contentType); - } - - /** - * Returns the SECP256k1 public key associated with an ENS node. - * Defined in EIP 619. - * @param node The ENS node to query - * @return x, y the X and Y coordinates of the curve point for the public key. - */ - function pubkey(bytes32 node) constant returns (bytes32 x, bytes32 y) { - return (records[node].pubkey.x, records[node].pubkey.y); + emit ABIChanged(node, contentType); } /** @@ -183,19 +109,9 @@ contract PublicResolver { * @param x the X coordinate of the curve point for the public key. * @param y the Y coordinate of the curve point for the public key. */ - function setPubkey(bytes32 node, bytes32 x, bytes32 y) only_owner(node) { + function setPubkey(bytes32 node, bytes32 x, bytes32 y) external onlyOwner(node) { records[node].pubkey = PublicKey(x, y); - PubkeyChanged(node, x, y); - } - - /** - * Returns the text data associated with an ENS node and key. - * @param node The ENS node to query. - * @param key The text data key to query. - * @return The associated text data. - */ - function text(bytes32 node, string key) constant returns (string ret) { - ret = records[node].text[key]; + emit PubkeyChanged(node, x, y); } /** @@ -205,8 +121,92 @@ contract PublicResolver { * @param key The key to set. * @param value The text data value to set. */ - function setText(bytes32 node, string key, string value) only_owner(node) { + function setText(bytes32 node, string calldata key, string calldata value) external onlyOwner(node) { records[node].text[key] = value; - TextChanged(node, key, key); + emit TextChanged(node, key, key); + } + + /** + * Returns the text data associated with an ENS node and key. + * @param node The ENS node to query. + * @param key The text data key to query. + * @return The associated text data. + */ + function text(bytes32 node, string calldata key) external view returns (string memory) { + return records[node].text[key]; + } + + /** + * Returns the SECP256k1 public key associated with an ENS node. + * Defined in EIP 619. + * @param node The ENS node to query + * @return x, y the X and Y coordinates of the curve point for the public key. + */ + function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) { + return (records[node].pubkey.x, records[node].pubkey.y); + } + + /** + * Returns the ABI associated with an ENS node. + * Defined in EIP205. + * @param node The ENS node to query + * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. + * @return contentType The content type of the return value + * @return data The ABI data + */ + function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) { + Record storage record = records[node]; + + for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) { + if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { + return (contentType, record.abis[contentType]); + } + } + + bytes memory empty; + return (0, empty); + } + + /** + * Returns the name associated with an ENS node, for reverse records. + * Defined in EIP181. + * @param node The ENS node to query. + * @return The associated name. + */ + function name(bytes32 node) external view returns (string memory) { + return records[node].name; + } + + /** + * Returns the address associated with an ENS node. + * @param node The ENS node to query. + * @return The associated address. + */ + function addr(bytes32 node) external view returns (address) { + return records[node].addr; + } + + /** + * Returns the contenthash associated with an ENS node. + * @param node The ENS node to query. + * @return The associated contenthash. + */ + function contenthash(bytes32 node) external view returns (bytes memory) { + return records[node].contenthash; + } + + /** + * Returns true if the resolver implements the interface specified by the provided hash. + * @param interfaceID The ID of the interface to check for. + * @return True if the contract implements the requested interface. + */ + function supportsInterface(bytes4 interfaceID) external pure returns (bool) { + return interfaceID == ADDR_INTERFACE_ID || + interfaceID == NAME_INTERFACE_ID || + interfaceID == ABI_INTERFACE_ID || + interfaceID == PUBKEY_INTERFACE_ID || + interfaceID == TEXT_INTERFACE_ID || + interfaceID == CONTENTHASH_INTERFACE_ID || + interfaceID == INTERFACE_META_ID; } } diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.go index cbf6cb05..7c0aed34 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.go @@ -4,6 +4,7 @@ package contract import ( + "math/big" "strings" ethereum "github.com/ethereum/go-ethereum" @@ -14,11 +15,23 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + // ENSABI is the input ABI used to generate the binding from. -const ENSABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"resolver\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setSubnodeOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setTTL\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"setResolver\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"label\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"NewOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"NewResolver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"NewTTL\",\"type\":\"event\"}]" +const ENSABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"resolver\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setSubnodeOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setTTL\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"setResolver\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"label\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"NewOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"NewResolver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"NewTTL\",\"type\":\"event\"}]" // ENSBin is the compiled bytecode used for deploying new contracts. -const ENSBin = `0x6060604052341561000f57600080fd5b60008080526020527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58054600160a060020a033316600160a060020a0319909116179055610503806100626000396000f3006060604052600436106100825763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630178b8bf811461008757806302571be3146100b957806306ab5923146100cf57806314ab9038146100f657806316a25cbd146101195780631896f70a1461014c5780635b0fc9c31461016e575b600080fd5b341561009257600080fd5b61009d600435610190565b604051600160a060020a03909116815260200160405180910390f35b34156100c457600080fd5b61009d6004356101ae565b34156100da57600080fd5b6100f4600435602435600160a060020a03604435166101c9565b005b341561010157600080fd5b6100f460043567ffffffffffffffff6024351661028b565b341561012457600080fd5b61012f600435610357565b60405167ffffffffffffffff909116815260200160405180910390f35b341561015757600080fd5b6100f4600435600160a060020a036024351661038e565b341561017957600080fd5b6100f4600435600160a060020a0360243516610434565b600090815260208190526040902060010154600160a060020a031690565b600090815260208190526040902054600160a060020a031690565b600083815260208190526040812054849033600160a060020a039081169116146101f257600080fd5b8484604051918252602082015260409081019051908190039020915083857fce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e8285604051600160a060020a03909116815260200160405180910390a3506000908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790555050565b600082815260208190526040902054829033600160a060020a039081169116146102b457600080fd5b827f1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa688360405167ffffffffffffffff909116815260200160405180910390a250600091825260208290526040909120600101805467ffffffffffffffff90921674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60009081526020819052604090206001015474010000000000000000000000000000000000000000900467ffffffffffffffff1690565b600082815260208190526040902054829033600160a060020a039081169116146103b757600080fd5b827f335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a083604051600160a060020a03909116815260200160405180910390a250600091825260208290526040909120600101805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03909216919091179055565b600082815260208190526040902054829033600160a060020a0390811691161461045d57600080fd5b827fd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d26683604051600160a060020a03909116815260200160405180910390a250600091825260208290526040909120805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555600a165627a7a72305820f4c798d4c84c9912f389f64631e85e8d16c3e6644f8c2e1579936015c7d5f6660029` +const ENSBin = `0x` // DeployENS deploys a new Ethereum contract, binding an instance of ENS to it. func DeployENS(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ENS, error) { @@ -177,7 +190,7 @@ func (_ENS *ENSTransactorRaw) Transact(opts *bind.TransactOpts, method string, p // Owner is a free data retrieval call binding the contract method 0x02571be3. // -// Solidity: function owner(node bytes32) constant returns(address) +// Solidity: function owner(bytes32 node) constant returns(address) func (_ENS *ENSCaller) Owner(opts *bind.CallOpts, node [32]byte) (common.Address, error) { var ( ret0 = new(common.Address) @@ -189,21 +202,21 @@ func (_ENS *ENSCaller) Owner(opts *bind.CallOpts, node [32]byte) (common.Address // Owner is a free data retrieval call binding the contract method 0x02571be3. // -// Solidity: function owner(node bytes32) constant returns(address) +// Solidity: function owner(bytes32 node) constant returns(address) func (_ENS *ENSSession) Owner(node [32]byte) (common.Address, error) { return _ENS.Contract.Owner(&_ENS.CallOpts, node) } // Owner is a free data retrieval call binding the contract method 0x02571be3. // -// Solidity: function owner(node bytes32) constant returns(address) +// Solidity: function owner(bytes32 node) constant returns(address) func (_ENS *ENSCallerSession) Owner(node [32]byte) (common.Address, error) { return _ENS.Contract.Owner(&_ENS.CallOpts, node) } // Resolver is a free data retrieval call binding the contract method 0x0178b8bf. // -// Solidity: function resolver(node bytes32) constant returns(address) +// Solidity: function resolver(bytes32 node) constant returns(address) func (_ENS *ENSCaller) Resolver(opts *bind.CallOpts, node [32]byte) (common.Address, error) { var ( ret0 = new(common.Address) @@ -215,21 +228,21 @@ func (_ENS *ENSCaller) Resolver(opts *bind.CallOpts, node [32]byte) (common.Addr // Resolver is a free data retrieval call binding the contract method 0x0178b8bf. // -// Solidity: function resolver(node bytes32) constant returns(address) +// Solidity: function resolver(bytes32 node) constant returns(address) func (_ENS *ENSSession) Resolver(node [32]byte) (common.Address, error) { return _ENS.Contract.Resolver(&_ENS.CallOpts, node) } // Resolver is a free data retrieval call binding the contract method 0x0178b8bf. // -// Solidity: function resolver(node bytes32) constant returns(address) +// Solidity: function resolver(bytes32 node) constant returns(address) func (_ENS *ENSCallerSession) Resolver(node [32]byte) (common.Address, error) { return _ENS.Contract.Resolver(&_ENS.CallOpts, node) } // Ttl is a free data retrieval call binding the contract method 0x16a25cbd. // -// Solidity: function ttl(node bytes32) constant returns(uint64) +// Solidity: function ttl(bytes32 node) constant returns(uint64) func (_ENS *ENSCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { var ( ret0 = new(uint64) @@ -241,98 +254,98 @@ func (_ENS *ENSCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { // Ttl is a free data retrieval call binding the contract method 0x16a25cbd. // -// Solidity: function ttl(node bytes32) constant returns(uint64) +// Solidity: function ttl(bytes32 node) constant returns(uint64) func (_ENS *ENSSession) Ttl(node [32]byte) (uint64, error) { return _ENS.Contract.Ttl(&_ENS.CallOpts, node) } // Ttl is a free data retrieval call binding the contract method 0x16a25cbd. // -// Solidity: function ttl(node bytes32) constant returns(uint64) +// Solidity: function ttl(bytes32 node) constant returns(uint64) func (_ENS *ENSCallerSession) Ttl(node [32]byte) (uint64, error) { return _ENS.Contract.Ttl(&_ENS.CallOpts, node) } // SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. // -// Solidity: function setOwner(node bytes32, owner address) returns() +// Solidity: function setOwner(bytes32 node, address owner) returns() func (_ENS *ENSTransactor) SetOwner(opts *bind.TransactOpts, node [32]byte, owner common.Address) (*types.Transaction, error) { return _ENS.contract.Transact(opts, "setOwner", node, owner) } // SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. // -// Solidity: function setOwner(node bytes32, owner address) returns() +// Solidity: function setOwner(bytes32 node, address owner) returns() func (_ENS *ENSSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { return _ENS.Contract.SetOwner(&_ENS.TransactOpts, node, owner) } // SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. // -// Solidity: function setOwner(node bytes32, owner address) returns() +// Solidity: function setOwner(bytes32 node, address owner) returns() func (_ENS *ENSTransactorSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { return _ENS.Contract.SetOwner(&_ENS.TransactOpts, node, owner) } // SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. // -// Solidity: function setResolver(node bytes32, resolver address) returns() +// Solidity: function setResolver(bytes32 node, address resolver) returns() func (_ENS *ENSTransactor) SetResolver(opts *bind.TransactOpts, node [32]byte, resolver common.Address) (*types.Transaction, error) { return _ENS.contract.Transact(opts, "setResolver", node, resolver) } // SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. // -// Solidity: function setResolver(node bytes32, resolver address) returns() +// Solidity: function setResolver(bytes32 node, address resolver) returns() func (_ENS *ENSSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { return _ENS.Contract.SetResolver(&_ENS.TransactOpts, node, resolver) } // SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. // -// Solidity: function setResolver(node bytes32, resolver address) returns() +// Solidity: function setResolver(bytes32 node, address resolver) returns() func (_ENS *ENSTransactorSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { return _ENS.Contract.SetResolver(&_ENS.TransactOpts, node, resolver) } // SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. // -// Solidity: function setSubnodeOwner(node bytes32, label bytes32, owner address) returns() +// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() func (_ENS *ENSTransactor) SetSubnodeOwner(opts *bind.TransactOpts, node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { return _ENS.contract.Transact(opts, "setSubnodeOwner", node, label, owner) } // SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. // -// Solidity: function setSubnodeOwner(node bytes32, label bytes32, owner address) returns() +// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() func (_ENS *ENSSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { return _ENS.Contract.SetSubnodeOwner(&_ENS.TransactOpts, node, label, owner) } // SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. // -// Solidity: function setSubnodeOwner(node bytes32, label bytes32, owner address) returns() +// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() func (_ENS *ENSTransactorSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { return _ENS.Contract.SetSubnodeOwner(&_ENS.TransactOpts, node, label, owner) } // SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. // -// Solidity: function setTTL(node bytes32, ttl uint64) returns() +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() func (_ENS *ENSTransactor) SetTTL(opts *bind.TransactOpts, node [32]byte, ttl uint64) (*types.Transaction, error) { return _ENS.contract.Transact(opts, "setTTL", node, ttl) } // SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. // -// Solidity: function setTTL(node bytes32, ttl uint64) returns() +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() func (_ENS *ENSSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { return _ENS.Contract.SetTTL(&_ENS.TransactOpts, node, ttl) } // SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. // -// Solidity: function setTTL(node bytes32, ttl uint64) returns() +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() func (_ENS *ENSTransactorSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { return _ENS.Contract.SetTTL(&_ENS.TransactOpts, node, ttl) } @@ -392,7 +405,7 @@ func (it *ENSNewOwnerIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *ENSNewOwnerIterator) Error() error { return it.fail } @@ -414,7 +427,7 @@ type ENSNewOwner struct { // FilterNewOwner is a free log retrieval operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. // -// Solidity: event NewOwner(node indexed bytes32, label indexed bytes32, owner address) +// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) func (_ENS *ENSFilterer) FilterNewOwner(opts *bind.FilterOpts, node [][32]byte, label [][32]byte) (*ENSNewOwnerIterator, error) { var nodeRule []interface{} @@ -435,7 +448,7 @@ func (_ENS *ENSFilterer) FilterNewOwner(opts *bind.FilterOpts, node [][32]byte, // WatchNewOwner is a free log subscription operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. // -// Solidity: event NewOwner(node indexed bytes32, label indexed bytes32, owner address) +// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) func (_ENS *ENSFilterer) WatchNewOwner(opts *bind.WatchOpts, sink chan<- *ENSNewOwner, node [][32]byte, label [][32]byte) (event.Subscription, error) { var nodeRule []interface{} @@ -534,7 +547,7 @@ func (it *ENSNewResolverIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *ENSNewResolverIterator) Error() error { return it.fail } @@ -555,7 +568,7 @@ type ENSNewResolver struct { // FilterNewResolver is a free log retrieval operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. // -// Solidity: event NewResolver(node indexed bytes32, resolver address) +// Solidity: event NewResolver(bytes32 indexed node, address resolver) func (_ENS *ENSFilterer) FilterNewResolver(opts *bind.FilterOpts, node [][32]byte) (*ENSNewResolverIterator, error) { var nodeRule []interface{} @@ -572,7 +585,7 @@ func (_ENS *ENSFilterer) FilterNewResolver(opts *bind.FilterOpts, node [][32]byt // WatchNewResolver is a free log subscription operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. // -// Solidity: event NewResolver(node indexed bytes32, resolver address) +// Solidity: event NewResolver(bytes32 indexed node, address resolver) func (_ENS *ENSFilterer) WatchNewResolver(opts *bind.WatchOpts, sink chan<- *ENSNewResolver, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} @@ -667,7 +680,7 @@ func (it *ENSNewTTLIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *ENSNewTTLIterator) Error() error { return it.fail } @@ -688,7 +701,7 @@ type ENSNewTTL struct { // FilterNewTTL is a free log retrieval operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. // -// Solidity: event NewTTL(node indexed bytes32, ttl uint64) +// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) func (_ENS *ENSFilterer) FilterNewTTL(opts *bind.FilterOpts, node [][32]byte) (*ENSNewTTLIterator, error) { var nodeRule []interface{} @@ -705,7 +718,7 @@ func (_ENS *ENSFilterer) FilterNewTTL(opts *bind.FilterOpts, node [][32]byte) (* // WatchNewTTL is a free log subscription operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. // -// Solidity: event NewTTL(node indexed bytes32, ttl uint64) +// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) func (_ENS *ENSFilterer) WatchNewTTL(opts *bind.WatchOpts, sink chan<- *ENSNewTTL, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} @@ -800,7 +813,7 @@ func (it *ENSTransferIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *ENSTransferIterator) Error() error { return it.fail } @@ -821,7 +834,7 @@ type ENSTransfer struct { // FilterTransfer is a free log retrieval operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. // -// Solidity: event Transfer(node indexed bytes32, owner address) +// Solidity: event Transfer(bytes32 indexed node, address owner) func (_ENS *ENSFilterer) FilterTransfer(opts *bind.FilterOpts, node [][32]byte) (*ENSTransferIterator, error) { var nodeRule []interface{} @@ -838,7 +851,7 @@ func (_ENS *ENSFilterer) FilterTransfer(opts *bind.FilterOpts, node [][32]byte) // WatchTransfer is a free log subscription operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. // -// Solidity: event Transfer(node indexed bytes32, owner address) +// Solidity: event Transfer(bytes32 indexed node, address owner) func (_ENS *ENSFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ENSTransfer, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.sol b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.sol deleted file mode 100644 index 47050c19..00000000 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ens.sol +++ /dev/null @@ -1,94 +0,0 @@ -pragma solidity ^0.4.0; - -import './AbstractENS.sol'; - -/** - * The ENS registry contract. - */ -contract ENS is AbstractENS { - struct Record { - address owner; - address resolver; - uint64 ttl; - } - - mapping(bytes32=>Record) records; - - // Permits modifications only by the owner of the specified node. - modifier only_owner(bytes32 node) { - if (records[node].owner != msg.sender) throw; - _; - } - - /** - * Constructs a new ENS registrar. - */ - function ENS() { - records[0].owner = msg.sender; - } - - /** - * Returns the address that owns the specified node. - */ - function owner(bytes32 node) constant returns (address) { - return records[node].owner; - } - - /** - * Returns the address of the resolver for the specified node. - */ - function resolver(bytes32 node) constant returns (address) { - return records[node].resolver; - } - - /** - * Returns the TTL of a node, and any records associated with it. - */ - function ttl(bytes32 node) constant returns (uint64) { - return records[node].ttl; - } - - /** - * Transfers ownership of a node to a new address. May only be called by the current - * owner of the node. - * @param node The node to transfer ownership of. - * @param owner The address of the new owner. - */ - function setOwner(bytes32 node, address owner) only_owner(node) { - Transfer(node, owner); - records[node].owner = owner; - } - - /** - * Transfers ownership of a subnode sha3(node, label) to a new address. May only be - * called by the owner of the parent node. - * @param node The parent node. - * @param label The hash of the label specifying the subnode. - * @param owner The address of the new owner. - */ - function setSubnodeOwner(bytes32 node, bytes32 label, address owner) only_owner(node) { - var subnode = sha3(node, label); - NewOwner(node, label, owner); - records[subnode].owner = owner; - } - - /** - * Sets the resolver address for the specified node. - * @param node The node to update. - * @param resolver The address of the resolver. - */ - function setResolver(bytes32 node, address resolver) only_owner(node) { - NewResolver(node, resolver); - records[node].resolver = resolver; - } - - /** - * Sets the TTL for the specified node. - * @param node The node to update. - * @param ttl The TTL in seconds. - */ - function setTTL(bytes32 node, uint64 ttl) only_owner(node) { - NewTTL(node, ttl); - records[node].ttl = ttl; - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ensregistry.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ensregistry.go new file mode 100644 index 00000000..ca89a87b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/ensregistry.go @@ -0,0 +1,892 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contract + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// ENSRegistryABI is the input ABI used to generate the binding from. +const ENSRegistryABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"resolver\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setSubnodeOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setTTL\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"setResolver\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"label\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"NewOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"NewResolver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"NewTTL\",\"type\":\"event\"}]" + +// ENSRegistryBin is the compiled bytecode used for deploying new contracts. +const ENSRegistryBin = `0x608060405234801561001057600080fd5b5060008080526020527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58054600160a060020a0319163317905561059d806100596000396000f3fe6080604052600436106100825763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630178b8bf811461008757806302571be3146100cd57806306ab5923146100f757806314ab90381461013857806316a25cbd146101725780631896f70a146101b95780635b0fc9c3146101f2575b600080fd5b34801561009357600080fd5b506100b1600480360360208110156100aa57600080fd5b503561022b565b60408051600160a060020a039092168252519081900360200190f35b3480156100d957600080fd5b506100b1600480360360208110156100f057600080fd5b5035610249565b34801561010357600080fd5b506101366004803603606081101561011a57600080fd5b5080359060208101359060400135600160a060020a0316610264565b005b34801561014457600080fd5b506101366004803603604081101561015b57600080fd5b508035906020013567ffffffffffffffff1661032e565b34801561017e57600080fd5b5061019c6004803603602081101561019557600080fd5b50356103f7565b6040805167ffffffffffffffff9092168252519081900360200190f35b3480156101c557600080fd5b50610136600480360360408110156101dc57600080fd5b5080359060200135600160a060020a031661042e565b3480156101fe57600080fd5b506101366004803603604081101561021557600080fd5b5080359060200135600160a060020a03166104d1565b600090815260208190526040902060010154600160a060020a031690565b600090815260208190526040902054600160a060020a031690565b6000838152602081905260409020548390600160a060020a0316331461028957600080fd5b6040805160208082018790528183018690528251808303840181526060830180855281519190920120600160a060020a0386169091529151859187917fce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e829181900360800190a36000908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039390931692909217909155505050565b6000828152602081905260409020548290600160a060020a0316331461035357600080fd5b6040805167ffffffffffffffff84168152905184917f1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68919081900360200190a250600091825260208290526040909120600101805467ffffffffffffffff90921674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60009081526020819052604090206001015474010000000000000000000000000000000000000000900467ffffffffffffffff1690565b6000828152602081905260409020548290600160a060020a0316331461045357600080fd5b60408051600160a060020a0384168152905184917f335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0919081900360200190a250600091825260208290526040909120600101805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03909216919091179055565b6000828152602081905260409020548290600160a060020a031633146104f657600080fd5b60408051600160a060020a0384168152905184917fd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266919081900360200190a250600091825260208290526040909120805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390921691909117905556fea165627a7a723058208be97eda88107945616fbd44aa4f2f1ce188b1a930a4bc5f8e1fb7924395d1650029` + +// DeployENSRegistry deploys a new Ethereum contract, binding an instance of ENSRegistry to it. +func DeployENSRegistry(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ENSRegistry, error) { + parsed, err := abi.JSON(strings.NewReader(ENSRegistryABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ENSRegistryBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ENSRegistry{ENSRegistryCaller: ENSRegistryCaller{contract: contract}, ENSRegistryTransactor: ENSRegistryTransactor{contract: contract}, ENSRegistryFilterer: ENSRegistryFilterer{contract: contract}}, nil +} + +// ENSRegistry is an auto generated Go binding around an Ethereum contract. +type ENSRegistry struct { + ENSRegistryCaller // Read-only binding to the contract + ENSRegistryTransactor // Write-only binding to the contract + ENSRegistryFilterer // Log filterer for contract events +} + +// ENSRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. +type ENSRegistryCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ENSRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ENSRegistryTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ENSRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ENSRegistryFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ENSRegistrySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ENSRegistrySession struct { + Contract *ENSRegistry // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ENSRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ENSRegistryCallerSession struct { + Contract *ENSRegistryCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ENSRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ENSRegistryTransactorSession struct { + Contract *ENSRegistryTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ENSRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. +type ENSRegistryRaw struct { + Contract *ENSRegistry // Generic contract binding to access the raw methods on +} + +// ENSRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ENSRegistryCallerRaw struct { + Contract *ENSRegistryCaller // Generic read-only contract binding to access the raw methods on +} + +// ENSRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ENSRegistryTransactorRaw struct { + Contract *ENSRegistryTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewENSRegistry creates a new instance of ENSRegistry, bound to a specific deployed contract. +func NewENSRegistry(address common.Address, backend bind.ContractBackend) (*ENSRegistry, error) { + contract, err := bindENSRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ENSRegistry{ENSRegistryCaller: ENSRegistryCaller{contract: contract}, ENSRegistryTransactor: ENSRegistryTransactor{contract: contract}, ENSRegistryFilterer: ENSRegistryFilterer{contract: contract}}, nil +} + +// NewENSRegistryCaller creates a new read-only instance of ENSRegistry, bound to a specific deployed contract. +func NewENSRegistryCaller(address common.Address, caller bind.ContractCaller) (*ENSRegistryCaller, error) { + contract, err := bindENSRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ENSRegistryCaller{contract: contract}, nil +} + +// NewENSRegistryTransactor creates a new write-only instance of ENSRegistry, bound to a specific deployed contract. +func NewENSRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*ENSRegistryTransactor, error) { + contract, err := bindENSRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ENSRegistryTransactor{contract: contract}, nil +} + +// NewENSRegistryFilterer creates a new log filterer instance of ENSRegistry, bound to a specific deployed contract. +func NewENSRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*ENSRegistryFilterer, error) { + contract, err := bindENSRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ENSRegistryFilterer{contract: contract}, nil +} + +// bindENSRegistry binds a generic wrapper to an already deployed contract. +func bindENSRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ENSRegistryABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ENSRegistry *ENSRegistryRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _ENSRegistry.Contract.ENSRegistryCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ENSRegistry *ENSRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ENSRegistry.Contract.ENSRegistryTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ENSRegistry *ENSRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ENSRegistry.Contract.ENSRegistryTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ENSRegistry *ENSRegistryCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _ENSRegistry.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ENSRegistry *ENSRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ENSRegistry.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ENSRegistry *ENSRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ENSRegistry.Contract.contract.Transact(opts, method, params...) +} + +// Owner is a free data retrieval call binding the contract method 0x02571be3. +// +// Solidity: function owner(bytes32 node) constant returns(address) +func (_ENSRegistry *ENSRegistryCaller) Owner(opts *bind.CallOpts, node [32]byte) (common.Address, error) { + var ( + ret0 = new(common.Address) + ) + out := ret0 + err := _ENSRegistry.contract.Call(opts, out, "owner", node) + return *ret0, err +} + +// Owner is a free data retrieval call binding the contract method 0x02571be3. +// +// Solidity: function owner(bytes32 node) constant returns(address) +func (_ENSRegistry *ENSRegistrySession) Owner(node [32]byte) (common.Address, error) { + return _ENSRegistry.Contract.Owner(&_ENSRegistry.CallOpts, node) +} + +// Owner is a free data retrieval call binding the contract method 0x02571be3. +// +// Solidity: function owner(bytes32 node) constant returns(address) +func (_ENSRegistry *ENSRegistryCallerSession) Owner(node [32]byte) (common.Address, error) { + return _ENSRegistry.Contract.Owner(&_ENSRegistry.CallOpts, node) +} + +// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. +// +// Solidity: function resolver(bytes32 node) constant returns(address) +func (_ENSRegistry *ENSRegistryCaller) Resolver(opts *bind.CallOpts, node [32]byte) (common.Address, error) { + var ( + ret0 = new(common.Address) + ) + out := ret0 + err := _ENSRegistry.contract.Call(opts, out, "resolver", node) + return *ret0, err +} + +// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. +// +// Solidity: function resolver(bytes32 node) constant returns(address) +func (_ENSRegistry *ENSRegistrySession) Resolver(node [32]byte) (common.Address, error) { + return _ENSRegistry.Contract.Resolver(&_ENSRegistry.CallOpts, node) +} + +// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. +// +// Solidity: function resolver(bytes32 node) constant returns(address) +func (_ENSRegistry *ENSRegistryCallerSession) Resolver(node [32]byte) (common.Address, error) { + return _ENSRegistry.Contract.Resolver(&_ENSRegistry.CallOpts, node) +} + +// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. +// +// Solidity: function ttl(bytes32 node) constant returns(uint64) +func (_ENSRegistry *ENSRegistryCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { + var ( + ret0 = new(uint64) + ) + out := ret0 + err := _ENSRegistry.contract.Call(opts, out, "ttl", node) + return *ret0, err +} + +// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. +// +// Solidity: function ttl(bytes32 node) constant returns(uint64) +func (_ENSRegistry *ENSRegistrySession) Ttl(node [32]byte) (uint64, error) { + return _ENSRegistry.Contract.Ttl(&_ENSRegistry.CallOpts, node) +} + +// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. +// +// Solidity: function ttl(bytes32 node) constant returns(uint64) +func (_ENSRegistry *ENSRegistryCallerSession) Ttl(node [32]byte) (uint64, error) { + return _ENSRegistry.Contract.Ttl(&_ENSRegistry.CallOpts, node) +} + +// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. +// +// Solidity: function setOwner(bytes32 node, address owner) returns() +func (_ENSRegistry *ENSRegistryTransactor) SetOwner(opts *bind.TransactOpts, node [32]byte, owner common.Address) (*types.Transaction, error) { + return _ENSRegistry.contract.Transact(opts, "setOwner", node, owner) +} + +// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. +// +// Solidity: function setOwner(bytes32 node, address owner) returns() +func (_ENSRegistry *ENSRegistrySession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetOwner(&_ENSRegistry.TransactOpts, node, owner) +} + +// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. +// +// Solidity: function setOwner(bytes32 node, address owner) returns() +func (_ENSRegistry *ENSRegistryTransactorSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetOwner(&_ENSRegistry.TransactOpts, node, owner) +} + +// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. +// +// Solidity: function setResolver(bytes32 node, address resolver) returns() +func (_ENSRegistry *ENSRegistryTransactor) SetResolver(opts *bind.TransactOpts, node [32]byte, resolver common.Address) (*types.Transaction, error) { + return _ENSRegistry.contract.Transact(opts, "setResolver", node, resolver) +} + +// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. +// +// Solidity: function setResolver(bytes32 node, address resolver) returns() +func (_ENSRegistry *ENSRegistrySession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetResolver(&_ENSRegistry.TransactOpts, node, resolver) +} + +// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. +// +// Solidity: function setResolver(bytes32 node, address resolver) returns() +func (_ENSRegistry *ENSRegistryTransactorSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetResolver(&_ENSRegistry.TransactOpts, node, resolver) +} + +// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. +// +// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() +func (_ENSRegistry *ENSRegistryTransactor) SetSubnodeOwner(opts *bind.TransactOpts, node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _ENSRegistry.contract.Transact(opts, "setSubnodeOwner", node, label, owner) +} + +// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. +// +// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() +func (_ENSRegistry *ENSRegistrySession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetSubnodeOwner(&_ENSRegistry.TransactOpts, node, label, owner) +} + +// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. +// +// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() +func (_ENSRegistry *ENSRegistryTransactorSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetSubnodeOwner(&_ENSRegistry.TransactOpts, node, label, owner) +} + +// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. +// +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() +func (_ENSRegistry *ENSRegistryTransactor) SetTTL(opts *bind.TransactOpts, node [32]byte, ttl uint64) (*types.Transaction, error) { + return _ENSRegistry.contract.Transact(opts, "setTTL", node, ttl) +} + +// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. +// +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() +func (_ENSRegistry *ENSRegistrySession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetTTL(&_ENSRegistry.TransactOpts, node, ttl) +} + +// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. +// +// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() +func (_ENSRegistry *ENSRegistryTransactorSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { + return _ENSRegistry.Contract.SetTTL(&_ENSRegistry.TransactOpts, node, ttl) +} + +// ENSRegistryNewOwnerIterator is returned from FilterNewOwner and is used to iterate over the raw logs and unpacked data for NewOwner events raised by the ENSRegistry contract. +type ENSRegistryNewOwnerIterator struct { + Event *ENSRegistryNewOwner // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ENSRegistryNewOwnerIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ENSRegistryNewOwner) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ENSRegistryNewOwner) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ENSRegistryNewOwnerIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ENSRegistryNewOwnerIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ENSRegistryNewOwner represents a NewOwner event raised by the ENSRegistry contract. +type ENSRegistryNewOwner struct { + Node [32]byte + Label [32]byte + Owner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNewOwner is a free log retrieval operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. +// +// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) +func (_ENSRegistry *ENSRegistryFilterer) FilterNewOwner(opts *bind.FilterOpts, node [][32]byte, label [][32]byte) (*ENSRegistryNewOwnerIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + var labelRule []interface{} + for _, labelItem := range label { + labelRule = append(labelRule, labelItem) + } + + logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "NewOwner", nodeRule, labelRule) + if err != nil { + return nil, err + } + return &ENSRegistryNewOwnerIterator{contract: _ENSRegistry.contract, event: "NewOwner", logs: logs, sub: sub}, nil +} + +// WatchNewOwner is a free log subscription operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. +// +// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) +func (_ENSRegistry *ENSRegistryFilterer) WatchNewOwner(opts *bind.WatchOpts, sink chan<- *ENSRegistryNewOwner, node [][32]byte, label [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + var labelRule []interface{} + for _, labelItem := range label { + labelRule = append(labelRule, labelItem) + } + + logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "NewOwner", nodeRule, labelRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ENSRegistryNewOwner) + if err := _ENSRegistry.contract.UnpackLog(event, "NewOwner", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ENSRegistryNewResolverIterator is returned from FilterNewResolver and is used to iterate over the raw logs and unpacked data for NewResolver events raised by the ENSRegistry contract. +type ENSRegistryNewResolverIterator struct { + Event *ENSRegistryNewResolver // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ENSRegistryNewResolverIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ENSRegistryNewResolver) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ENSRegistryNewResolver) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ENSRegistryNewResolverIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ENSRegistryNewResolverIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ENSRegistryNewResolver represents a NewResolver event raised by the ENSRegistry contract. +type ENSRegistryNewResolver struct { + Node [32]byte + Resolver common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNewResolver is a free log retrieval operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. +// +// Solidity: event NewResolver(bytes32 indexed node, address resolver) +func (_ENSRegistry *ENSRegistryFilterer) FilterNewResolver(opts *bind.FilterOpts, node [][32]byte) (*ENSRegistryNewResolverIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "NewResolver", nodeRule) + if err != nil { + return nil, err + } + return &ENSRegistryNewResolverIterator{contract: _ENSRegistry.contract, event: "NewResolver", logs: logs, sub: sub}, nil +} + +// WatchNewResolver is a free log subscription operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. +// +// Solidity: event NewResolver(bytes32 indexed node, address resolver) +func (_ENSRegistry *ENSRegistryFilterer) WatchNewResolver(opts *bind.WatchOpts, sink chan<- *ENSRegistryNewResolver, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "NewResolver", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ENSRegistryNewResolver) + if err := _ENSRegistry.contract.UnpackLog(event, "NewResolver", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ENSRegistryNewTTLIterator is returned from FilterNewTTL and is used to iterate over the raw logs and unpacked data for NewTTL events raised by the ENSRegistry contract. +type ENSRegistryNewTTLIterator struct { + Event *ENSRegistryNewTTL // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ENSRegistryNewTTLIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ENSRegistryNewTTL) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ENSRegistryNewTTL) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ENSRegistryNewTTLIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ENSRegistryNewTTLIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ENSRegistryNewTTL represents a NewTTL event raised by the ENSRegistry contract. +type ENSRegistryNewTTL struct { + Node [32]byte + Ttl uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNewTTL is a free log retrieval operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. +// +// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) +func (_ENSRegistry *ENSRegistryFilterer) FilterNewTTL(opts *bind.FilterOpts, node [][32]byte) (*ENSRegistryNewTTLIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "NewTTL", nodeRule) + if err != nil { + return nil, err + } + return &ENSRegistryNewTTLIterator{contract: _ENSRegistry.contract, event: "NewTTL", logs: logs, sub: sub}, nil +} + +// WatchNewTTL is a free log subscription operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. +// +// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) +func (_ENSRegistry *ENSRegistryFilterer) WatchNewTTL(opts *bind.WatchOpts, sink chan<- *ENSRegistryNewTTL, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "NewTTL", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ENSRegistryNewTTL) + if err := _ENSRegistry.contract.UnpackLog(event, "NewTTL", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ENSRegistryTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the ENSRegistry contract. +type ENSRegistryTransferIterator struct { + Event *ENSRegistryTransfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ENSRegistryTransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ENSRegistryTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ENSRegistryTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ENSRegistryTransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ENSRegistryTransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ENSRegistryTransfer represents a Transfer event raised by the ENSRegistry contract. +type ENSRegistryTransfer struct { + Node [32]byte + Owner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. +// +// Solidity: event Transfer(bytes32 indexed node, address owner) +func (_ENSRegistry *ENSRegistryFilterer) FilterTransfer(opts *bind.FilterOpts, node [][32]byte) (*ENSRegistryTransferIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "Transfer", nodeRule) + if err != nil { + return nil, err + } + return &ENSRegistryTransferIterator{contract: _ENSRegistry.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. +// +// Solidity: event Transfer(bytes32 indexed node, address owner) +func (_ENSRegistry *ENSRegistryFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ENSRegistryTransfer, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "Transfer", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ENSRegistryTransfer) + if err := _ENSRegistry.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/fifsregistrar.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/fifsregistrar.go index a08380ad..97263cbe 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/fifsregistrar.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/fifsregistrar.go @@ -4,19 +4,34 @@ package contract import ( + "math/big" "strings" + ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription ) // FIFSRegistrarABI is the input ABI used to generate the binding from. -const FIFSRegistrarABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"subnode\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"},{\"name\":\"node\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" +const FIFSRegistrarABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"},{\"name\":\"node\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" // FIFSRegistrarBin is the compiled bytecode used for deploying new contracts. -const FIFSRegistrarBin = `0x6060604052341561000f57600080fd5b604051604080610224833981016040528080519190602001805160008054600160a060020a03909516600160a060020a03199095169490941790935550506001556101c58061005f6000396000f3006060604052600436106100275763ffffffff60e060020a600035041663d22057a9811461002c575b600080fd5b341561003757600080fd5b61004e600435600160a060020a0360243516610050565b005b816000806001548360405191825260208201526040908101905190819003902060008054919350600160a060020a03909116906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b15156100c857600080fd5b6102c65a03f115156100d957600080fd5b5050506040518051915050600160a060020a0381161580159061010e575033600160a060020a031681600160a060020a031614155b1561011857600080fd5b600054600154600160a060020a03909116906306ab592390878760405160e060020a63ffffffff861602815260048101939093526024830191909152600160a060020a03166044820152606401600060405180830381600087803b151561017e57600080fd5b6102c65a03f1151561018f57600080fd5b50505050505050505600a165627a7a723058206fb963cb168d5e3a51af12cd6bb23e324dbd32dd4954f43653ba27e66b68ea650029` +const FIFSRegistrarBin = `0x608060405234801561001057600080fd5b506040516040806102cc8339810180604052604081101561003057600080fd5b50805160209091015160008054600160a060020a031916600160a060020a0390931692909217825560015561026190819061006b90396000f3fe6080604052600436106100405763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663d22057a98114610045575b600080fd5b34801561005157600080fd5b5061008b6004803603604081101561006857600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff1661008d565b005b6000805460015460408051602080820193909352808201879052815180820383018152606082018084528151918501919091207f02571be3000000000000000000000000000000000000000000000000000000009091526064820152905186949373ffffffffffffffffffffffffffffffffffffffff16926302571be39260848082019391829003018186803b15801561012657600080fd5b505afa15801561013a573d6000803e3d6000fd5b505050506040513d602081101561015057600080fd5b5051905073ffffffffffffffffffffffffffffffffffffffff8116158061018c575073ffffffffffffffffffffffffffffffffffffffff811633145b151561019757600080fd5b60008054600154604080517f06ab592300000000000000000000000000000000000000000000000000000000815260048101929092526024820188905273ffffffffffffffffffffffffffffffffffffffff878116604484015290519216926306ab59239260648084019382900301818387803b15801561021757600080fd5b505af115801561022b573d6000803e3d6000fd5b505050505050505056fea165627a7a723058200f21424d48c6fc6f2bc79f5b36b3a0e3067a97d4ce084ab0e0f9106303a3ee520029` // DeployFIFSRegistrar deploys a new Ethereum contract, binding an instance of FIFSRegistrar to it. func DeployFIFSRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address, node [32]byte) (common.Address, *types.Transaction, *FIFSRegistrar, error) { @@ -175,21 +190,21 @@ func (_FIFSRegistrar *FIFSRegistrarTransactorRaw) Transact(opts *bind.TransactOp // Register is a paid mutator transaction binding the contract method 0xd22057a9. // -// Solidity: function register(subnode bytes32, owner address) returns() -func (_FIFSRegistrar *FIFSRegistrarTransactor) Register(opts *bind.TransactOpts, subnode [32]byte, owner common.Address) (*types.Transaction, error) { - return _FIFSRegistrar.contract.Transact(opts, "register", subnode, owner) +// Solidity: function register(bytes32 label, address owner) returns() +func (_FIFSRegistrar *FIFSRegistrarTransactor) Register(opts *bind.TransactOpts, label [32]byte, owner common.Address) (*types.Transaction, error) { + return _FIFSRegistrar.contract.Transact(opts, "register", label, owner) } // Register is a paid mutator transaction binding the contract method 0xd22057a9. // -// Solidity: function register(subnode bytes32, owner address) returns() -func (_FIFSRegistrar *FIFSRegistrarSession) Register(subnode [32]byte, owner common.Address) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, subnode, owner) +// Solidity: function register(bytes32 label, address owner) returns() +func (_FIFSRegistrar *FIFSRegistrarSession) Register(label [32]byte, owner common.Address) (*types.Transaction, error) { + return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, label, owner) } // Register is a paid mutator transaction binding the contract method 0xd22057a9. // -// Solidity: function register(subnode bytes32, owner address) returns() -func (_FIFSRegistrar *FIFSRegistrarTransactorSession) Register(subnode [32]byte, owner common.Address) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, subnode, owner) +// Solidity: function register(bytes32 label, address owner) returns() +func (_FIFSRegistrar *FIFSRegistrarTransactorSession) Register(label [32]byte, owner common.Address) (*types.Transaction, error) { + return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, label, owner) } diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/publicresolver.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/publicresolver.go index c567d588..01bfce5e 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/publicresolver.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/contract/publicresolver.go @@ -15,11 +15,23 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + // PublicResolverABI is the input ABI used to generate the binding from. -const PublicResolverABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceID\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setText\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentTypes\",\"type\":\"uint256\"}],\"name\":\"ABI\",\"outputs\":[{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"setPubkey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"content\",\"outputs\":[{\"name\":\"ret\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"ret\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"text\",\"outputs\":[{\"name\":\"ret\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"setABI\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"ret\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setName\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"setContent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"pubkey\",\"outputs\":[{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAddr\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address\"}],\"name\":\"AddrChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"ContentChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NameChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"contentType\",\"type\":\"uint256\"}],\"name\":\"ABIChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"x\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"PubkeyChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"indexedKey\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"key\",\"type\":\"string\"}],\"name\":\"TextChanged\",\"type\":\"event\"}]" +const PublicResolverABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceID\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setText\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentTypes\",\"type\":\"uint256\"}],\"name\":\"ABI\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"setPubkey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"hash\",\"type\":\"bytes\"}],\"name\":\"setContenthash\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"text\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"setABI\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setName\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"contenthash\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"pubkey\",\"outputs\":[{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAddr\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address\"}],\"name\":\"AddrChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NameChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"contentType\",\"type\":\"uint256\"}],\"name\":\"ABIChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"x\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"PubkeyChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"indexedKey\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"key\",\"type\":\"string\"}],\"name\":\"TextChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"hash\",\"type\":\"bytes\"}],\"name\":\"ContenthashChanged\",\"type\":\"event\"}]" // PublicResolverBin is the compiled bytecode used for deploying new contracts. -const PublicResolverBin = `0x6060604052341561000f57600080fd5b6040516020806111b28339810160405280805160008054600160a060020a03909216600160a060020a0319909216919091179055505061115e806100546000396000f3006060604052600436106100ab5763ffffffff60e060020a60003504166301ffc9a781146100b057806310f13a8c146100e45780632203ab561461017e57806329cd62ea146102155780632dff6941146102315780633b3b57de1461025957806359d1d43c1461028b578063623195b014610358578063691f3431146103b457806377372213146103ca578063c3d014d614610420578063c869023314610439578063d5fa2b0014610467575b600080fd5b34156100bb57600080fd5b6100d0600160e060020a031960043516610489565b604051901515815260200160405180910390f35b34156100ef57600080fd5b61017c600480359060446024803590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f0160208091040260200160405190810160405281815292919060208401838380828437509496506105f695505050505050565b005b341561018957600080fd5b610197600435602435610807565b60405182815260406020820181815290820183818151815260200191508051906020019080838360005b838110156101d95780820151838201526020016101c1565b50505050905090810190601f1680156102065780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561022057600080fd5b61017c600435602435604435610931565b341561023c57600080fd5b610247600435610a30565b60405190815260200160405180910390f35b341561026457600080fd5b61026f600435610a46565b604051600160a060020a03909116815260200160405180910390f35b341561029657600080fd5b6102e1600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610a6195505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561031d578082015183820152602001610305565b50505050905090810190601f16801561034a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561036357600080fd5b61017c600480359060248035919060649060443590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610b8095505050505050565b34156103bf57600080fd5b6102e1600435610c7c565b34156103d557600080fd5b61017c600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610d4295505050505050565b341561042b57600080fd5b61017c600435602435610e8c565b341561044457600080fd5b61044f600435610f65565b60405191825260208201526040908101905180910390f35b341561047257600080fd5b61017c600435600160a060020a0360243516610f82565b6000600160e060020a031982167f3b3b57de0000000000000000000000000000000000000000000000000000000014806104ec5750600160e060020a031982167fd8389dc500000000000000000000000000000000000000000000000000000000145b806105205750600160e060020a031982167f691f343100000000000000000000000000000000000000000000000000000000145b806105545750600160e060020a031982167f2203ab5600000000000000000000000000000000000000000000000000000000145b806105885750600160e060020a031982167fc869023300000000000000000000000000000000000000000000000000000000145b806105bc5750600160e060020a031982167f59d1d43c00000000000000000000000000000000000000000000000000000000145b806105f05750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561064f57600080fd5b6102c65a03f1151561066057600080fd5b50505060405180519050600160a060020a031614151561067f57600080fd5b6000848152600160205260409081902083916005909101908590518082805190602001908083835b602083106106c65780518252601f1990920191602091820191016106a7565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902090805161070a929160200190611085565b50826040518082805190602001908083835b6020831061073b5780518252601f19909201916020918201910161071c565b6001836020036101000a0380198251168184511617909252505050919091019250604091505051908190039020847fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a75508560405160208082528190810183818151815260200191508051906020019080838360005b838110156107c75780820151838201526020016107af565b50505050905090810190601f1680156107f45780820380516001836020036101000a031916815260200191505b509250505060405180910390a350505050565b6000610811611103565b60008481526001602081905260409091209092505b838311610924578284161580159061085f5750600083815260068201602052604081205460026000196101006001841615020190911604115b15610919578060060160008481526020019081526020016000208054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561090d5780601f106108e25761010080835404028352916020019161090d565b820191906000526020600020905b8154815290600101906020018083116108f057829003601f168201915b50505050509150610929565b600290920291610826565b600092505b509250929050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561098a57600080fd5b6102c65a03f1151561099b57600080fd5b50505060405180519050600160a060020a03161415156109ba57600080fd5b6040805190810160409081528482526020808301859052600087815260019091522060030181518155602082015160019091015550837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46848460405191825260208201526040908101905180910390a250505050565b6000908152600160208190526040909120015490565b600090815260016020526040902054600160a060020a031690565b610a69611103565b60008381526001602052604090819020600501908390518082805190602001908083835b60208310610aac5780518252601f199092019160209182019101610a8d565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b735780601f10610b4857610100808354040283529160200191610b73565b820191906000526020600020905b815481529060010190602001808311610b5657829003601f168201915b5050505050905092915050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610bd957600080fd5b6102c65a03f11515610bea57600080fd5b50505060405180519050600160a060020a0316141515610c0957600080fd5b6000198301831615610c1a57600080fd5b60008481526001602090815260408083208684526006019091529020828051610c47929160200190611085565b5082847faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a350505050565b610c84611103565b6001600083600019166000191681526020019081526020016000206002018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610d365780601f10610d0b57610100808354040283529160200191610d36565b820191906000526020600020905b815481529060010190602001808311610d1957829003601f168201915b50505050509050919050565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610d9b57600080fd5b6102c65a03f11515610dac57600080fd5b50505060405180519050600160a060020a0316141515610dcb57600080fd5b6000838152600160205260409020600201828051610ded929160200190611085565b50827fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f78360405160208082528190810183818151815260200191508051906020019080838360005b83811015610e4d578082015183820152602001610e35565b50505050905090810190601f168015610e7a5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505050565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610ee557600080fd5b6102c65a03f11515610ef657600080fd5b50505060405180519050600160a060020a0316141515610f1557600080fd5b6000838152600160208190526040918290200183905583907f0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc9084905190815260200160405180910390a2505050565b600090815260016020526040902060038101546004909101549091565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610fdb57600080fd5b6102c65a03f11515610fec57600080fd5b50505060405180519050600160a060020a031614151561100b57600080fd5b60008381526001602052604090819020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03851617905583907f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd290849051600160a060020a03909116815260200160405180910390a2505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106110c657805160ff19168380011785556110f3565b828001600101855582156110f3579182015b828111156110f35782518255916020019190600101906110d8565b506110ff929150611115565b5090565b60206040519081016040526000815290565b61112f91905b808211156110ff576000815560010161111b565b905600a165627a7a723058201ecacbc445b9fbcd91b0ab164389f69d7283b856883bc7437eeed1008345a4920029` +const PublicResolverBin = `0x608060405234801561001057600080fd5b506040516020806112ce8339810180604052602081101561003057600080fd5b505160008054600160a060020a03909216600160a060020a031990921691909117905561126c806100626000396000f3fe6080604052600436106100c45763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301ffc9a781146100c957806310f13a8c146101115780632203ab56146101e957806329cd62ea14610298578063304e6ade146102ce5780633b3b57de1461035257806359d1d43c14610398578063623195b014610491578063691f34311461051a5780637737221314610544578063bc1c58d1146105c8578063c8690233146105f2578063d5fa2b0014610635575b600080fd5b3480156100d557600080fd5b506100fd600480360360208110156100ec57600080fd5b5035600160e060020a03191661066e565b604080519115158252519081900360200190f35b34801561011d57600080fd5b506101e76004803603606081101561013457600080fd5b8135919081019060408101602082013564010000000081111561015657600080fd5b82018360208201111561016857600080fd5b8035906020019184600183028401116401000000008311171561018a57600080fd5b9193909290916020810190356401000000008111156101a857600080fd5b8201836020820111156101ba57600080fd5b803590602001918460018302840111640100000000831117156101dc57600080fd5b5090925090506107db565b005b3480156101f557600080fd5b506102196004803603604081101561020c57600080fd5b508035906020013561094d565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561025c578181015183820152602001610244565b50505050905090810190601f1680156102895780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156102a457600080fd5b506101e7600480360360608110156102bb57600080fd5b5080359060208101359060400135610a65565b3480156102da57600080fd5b506101e7600480360360408110156102f157600080fd5b8135919081019060408101602082013564010000000081111561031357600080fd5b82018360208201111561032557600080fd5b8035906020019184600183028401116401000000008311171561034757600080fd5b509092509050610b65565b34801561035e57600080fd5b5061037c6004803603602081101561037557600080fd5b5035610c7b565b60408051600160a060020a039092168252519081900360200190f35b3480156103a457600080fd5b5061041c600480360360408110156103bb57600080fd5b813591908101906040810160208201356401000000008111156103dd57600080fd5b8201836020820111156103ef57600080fd5b8035906020019184600183028401116401000000008311171561041157600080fd5b509092509050610c96565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561045657818101518382015260200161043e565b50505050905090810190601f1680156104835780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561049d57600080fd5b506101e7600480360360608110156104b457600080fd5b8135916020810135918101906060810160408201356401000000008111156104db57600080fd5b8201836020820111156104ed57600080fd5b8035906020019184600183028401116401000000008311171561050f57600080fd5b509092509050610d60565b34801561052657600080fd5b5061041c6004803603602081101561053d57600080fd5b5035610e5f565b34801561055057600080fd5b506101e76004803603604081101561056757600080fd5b8135919081019060408101602082013564010000000081111561058957600080fd5b82018360208201111561059b57600080fd5b803590602001918460018302840111640100000000831117156105bd57600080fd5b509092509050610f01565b3480156105d457600080fd5b5061041c600480360360208110156105eb57600080fd5b5035611018565b3480156105fe57600080fd5b5061061c6004803603602081101561061557600080fd5b5035611084565b6040805192835260208301919091528051918290030190f35b34801561064157600080fd5b506101e76004803603604081101561065857600080fd5b5080359060200135600160a060020a03166110a1565b6000600160e060020a031982167f3b3b57de0000000000000000000000000000000000000000000000000000000014806106d15750600160e060020a031982167f691f343100000000000000000000000000000000000000000000000000000000145b806107055750600160e060020a031982167f2203ab5600000000000000000000000000000000000000000000000000000000145b806107395750600160e060020a031982167fc869023300000000000000000000000000000000000000000000000000000000145b8061076d5750600160e060020a031982167f59d1d43c00000000000000000000000000000000000000000000000000000000145b806107a15750600160e060020a031982167fbc1c58d100000000000000000000000000000000000000000000000000000000145b806107d55750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6000546040805160e060020a6302571be302815260048101889052905187923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b15801561082e57600080fd5b505afa158015610842573d6000803e3d6000fd5b505050506040513d602081101561085857600080fd5b5051600160a060020a03161461086d57600080fd5b8282600160008981526020019081526020016000206004018787604051808383808284378083019250505092505050908152602001604051809103902091906108b79291906111a5565b50857fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550868688886040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a2505050505050565b600082815260016020819052604082206060915b848111610a53578085161580159061099a5750600081815260058301602052604081205460026000196101006001841615020190911604115b15610a4b57600081815260058301602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845284939192839190830182828015610a395780601f10610a0e57610100808354040283529160200191610a39565b820191906000526020600020905b815481529060010190602001808311610a1c57829003601f168201915b50505050509050935093505050610a5e565b600202610961565b506000925060609150505b9250929050565b6000546040805160e060020a6302571be302815260048101869052905185923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610ab857600080fd5b505afa158015610acc573d6000803e3d6000fd5b505050506040513d6020811015610ae257600080fd5b5051600160a060020a031614610af757600080fd5b604080518082018252848152602080820185815260008881526001835284902092516002840155516003909201919091558151858152908101849052815186927f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46928290030190a250505050565b6000546040805160e060020a6302571be302815260048101869052905185923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610bb857600080fd5b505afa158015610bcc573d6000803e3d6000fd5b505050506040513d6020811015610be257600080fd5b5051600160a060020a031614610bf757600080fd5b6000848152600160205260409020610c139060060184846111a5565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d7578848460405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a250505050565b600090815260016020526040902054600160a060020a031690565b6060600160008581526020019081526020016000206004018383604051808383808284379190910194855250506040805160209481900385018120805460026001821615610100026000190190911604601f81018790048702830187019093528282529094909350909150830182828015610d525780601f10610d2757610100808354040283529160200191610d52565b820191906000526020600020905b815481529060010190602001808311610d3557829003601f168201915b505050505090509392505050565b6000546040805160e060020a6302571be302815260048101879052905186923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610db357600080fd5b505afa158015610dc7573d6000803e3d6000fd5b505050506040513d6020811015610ddd57600080fd5b5051600160a060020a031614610df257600080fd5b6000198401841615610e0357600080fd5b60008581526001602090815260408083208784526005019091529020610e2a9084846111a5565b50604051849086907faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe390600090a35050505050565b600081815260016020818152604092839020820180548451600294821615610100026000190190911693909304601f81018390048302840183019094528383526060939091830182828015610ef55780601f10610eca57610100808354040283529160200191610ef5565b820191906000526020600020905b815481529060010190602001808311610ed857829003601f168201915b50505050509050919050565b6000546040805160e060020a6302571be302815260048101869052905185923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610f5457600080fd5b505afa158015610f68573d6000803e3d6000fd5b505050506040513d6020811015610f7e57600080fd5b5051600160a060020a031614610f9357600080fd5b6000848152600160208190526040909120610fb0910184846111a5565b50837fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7848460405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a250505050565b60008181526001602081815260409283902060060180548451600294821615610100026000190190911693909304601f81018390048302840183019094528383526060939091830182828015610ef55780601f10610eca57610100808354040283529160200191610ef5565b600090815260016020526040902060028101546003909101549091565b6000546040805160e060020a6302571be302815260048101859052905184923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b1580156110f457600080fd5b505afa158015611108573d6000803e3d6000fd5b505050506040513d602081101561111e57600080fd5b5051600160a060020a03161461113357600080fd5b600083815260016020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0386169081179091558251908152915185927f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd292908290030190a2505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106111e65782800160ff19823516178555611213565b82800160010185558215611213579182015b828111156112135782358255916020019190600101906111f8565b5061121f929150611223565b5090565b61123d91905b8082111561121f5760008155600101611229565b9056fea165627a7a7230582047f310fc746ab2e282cf63ba794d20abb361f9284c6c5f2a2e26151e5b7fab600029` // DeployPublicResolver deploys a new Ethereum contract, binding an instance of PublicResolver to it. func DeployPublicResolver(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address) (common.Address, *types.Transaction, *PublicResolver, error) { @@ -178,43 +190,37 @@ func (_PublicResolver *PublicResolverTransactorRaw) Transact(opts *bind.Transact // ABI is a free data retrieval call binding the contract method 0x2203ab56. // -// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) -func (_PublicResolver *PublicResolverCaller) ABI(opts *bind.CallOpts, node [32]byte, contentTypes *big.Int) (struct { - ContentType *big.Int - Data []byte -}, error) { - ret := new(struct { - ContentType *big.Int - Data []byte - }) - out := ret +// Solidity: function ABI(bytes32 node, uint256 contentTypes) constant returns(uint256, bytes) +func (_PublicResolver *PublicResolverCaller) ABI(opts *bind.CallOpts, node [32]byte, contentTypes *big.Int) (*big.Int, []byte, error) { + var ( + ret0 = new(*big.Int) + ret1 = new([]byte) + ) + out := &[]interface{}{ + ret0, + ret1, + } err := _PublicResolver.contract.Call(opts, out, "ABI", node, contentTypes) - return *ret, err + return *ret0, *ret1, err } // ABI is a free data retrieval call binding the contract method 0x2203ab56. // -// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) -func (_PublicResolver *PublicResolverSession) ABI(node [32]byte, contentTypes *big.Int) (struct { - ContentType *big.Int - Data []byte -}, error) { +// Solidity: function ABI(bytes32 node, uint256 contentTypes) constant returns(uint256, bytes) +func (_PublicResolver *PublicResolverSession) ABI(node [32]byte, contentTypes *big.Int) (*big.Int, []byte, error) { return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) } // ABI is a free data retrieval call binding the contract method 0x2203ab56. // -// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) -func (_PublicResolver *PublicResolverCallerSession) ABI(node [32]byte, contentTypes *big.Int) (struct { - ContentType *big.Int - Data []byte -}, error) { +// Solidity: function ABI(bytes32 node, uint256 contentTypes) constant returns(uint256, bytes) +func (_PublicResolver *PublicResolverCallerSession) ABI(node [32]byte, contentTypes *big.Int) (*big.Int, []byte, error) { return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) } // Addr is a free data retrieval call binding the contract method 0x3b3b57de. // -// Solidity: function addr(node bytes32) constant returns(ret address) +// Solidity: function addr(bytes32 node) constant returns(address) func (_PublicResolver *PublicResolverCaller) Addr(opts *bind.CallOpts, node [32]byte) (common.Address, error) { var ( ret0 = new(common.Address) @@ -226,47 +232,47 @@ func (_PublicResolver *PublicResolverCaller) Addr(opts *bind.CallOpts, node [32] // Addr is a free data retrieval call binding the contract method 0x3b3b57de. // -// Solidity: function addr(node bytes32) constant returns(ret address) +// Solidity: function addr(bytes32 node) constant returns(address) func (_PublicResolver *PublicResolverSession) Addr(node [32]byte) (common.Address, error) { return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) } // Addr is a free data retrieval call binding the contract method 0x3b3b57de. // -// Solidity: function addr(node bytes32) constant returns(ret address) +// Solidity: function addr(bytes32 node) constant returns(address) func (_PublicResolver *PublicResolverCallerSession) Addr(node [32]byte) (common.Address, error) { return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) } -// Content is a free data retrieval call binding the contract method 0x2dff6941. +// Contenthash is a free data retrieval call binding the contract method 0xbc1c58d1. // -// Solidity: function content(node bytes32) constant returns(ret bytes32) -func (_PublicResolver *PublicResolverCaller) Content(opts *bind.CallOpts, node [32]byte) ([32]byte, error) { +// Solidity: function contenthash(bytes32 node) constant returns(bytes) +func (_PublicResolver *PublicResolverCaller) Contenthash(opts *bind.CallOpts, node [32]byte) ([]byte, error) { var ( - ret0 = new([32]byte) + ret0 = new([]byte) ) out := ret0 - err := _PublicResolver.contract.Call(opts, out, "content", node) + err := _PublicResolver.contract.Call(opts, out, "contenthash", node) return *ret0, err } -// Content is a free data retrieval call binding the contract method 0x2dff6941. +// Contenthash is a free data retrieval call binding the contract method 0xbc1c58d1. // -// Solidity: function content(node bytes32) constant returns(ret bytes32) -func (_PublicResolver *PublicResolverSession) Content(node [32]byte) ([32]byte, error) { - return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node) +// Solidity: function contenthash(bytes32 node) constant returns(bytes) +func (_PublicResolver *PublicResolverSession) Contenthash(node [32]byte) ([]byte, error) { + return _PublicResolver.Contract.Contenthash(&_PublicResolver.CallOpts, node) } -// Content is a free data retrieval call binding the contract method 0x2dff6941. +// Contenthash is a free data retrieval call binding the contract method 0xbc1c58d1. // -// Solidity: function content(node bytes32) constant returns(ret bytes32) -func (_PublicResolver *PublicResolverCallerSession) Content(node [32]byte) ([32]byte, error) { - return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node) +// Solidity: function contenthash(bytes32 node) constant returns(bytes) +func (_PublicResolver *PublicResolverCallerSession) Contenthash(node [32]byte) ([]byte, error) { + return _PublicResolver.Contract.Contenthash(&_PublicResolver.CallOpts, node) } // Name is a free data retrieval call binding the contract method 0x691f3431. // -// Solidity: function name(node bytes32) constant returns(ret string) +// Solidity: function name(bytes32 node) constant returns(string) func (_PublicResolver *PublicResolverCaller) Name(opts *bind.CallOpts, node [32]byte) (string, error) { var ( ret0 = new(string) @@ -278,21 +284,21 @@ func (_PublicResolver *PublicResolverCaller) Name(opts *bind.CallOpts, node [32] // Name is a free data retrieval call binding the contract method 0x691f3431. // -// Solidity: function name(node bytes32) constant returns(ret string) +// Solidity: function name(bytes32 node) constant returns(string) func (_PublicResolver *PublicResolverSession) Name(node [32]byte) (string, error) { return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) } // Name is a free data retrieval call binding the contract method 0x691f3431. // -// Solidity: function name(node bytes32) constant returns(ret string) +// Solidity: function name(bytes32 node) constant returns(string) func (_PublicResolver *PublicResolverCallerSession) Name(node [32]byte) (string, error) { return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) } // Pubkey is a free data retrieval call binding the contract method 0xc8690233. // -// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) +// Solidity: function pubkey(bytes32 node) constant returns(bytes32 x, bytes32 y) func (_PublicResolver *PublicResolverCaller) Pubkey(opts *bind.CallOpts, node [32]byte) (struct { X [32]byte Y [32]byte @@ -308,7 +314,7 @@ func (_PublicResolver *PublicResolverCaller) Pubkey(opts *bind.CallOpts, node [3 // Pubkey is a free data retrieval call binding the contract method 0xc8690233. // -// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) +// Solidity: function pubkey(bytes32 node) constant returns(bytes32 x, bytes32 y) func (_PublicResolver *PublicResolverSession) Pubkey(node [32]byte) (struct { X [32]byte Y [32]byte @@ -318,7 +324,7 @@ func (_PublicResolver *PublicResolverSession) Pubkey(node [32]byte) (struct { // Pubkey is a free data retrieval call binding the contract method 0xc8690233. // -// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) +// Solidity: function pubkey(bytes32 node) constant returns(bytes32 x, bytes32 y) func (_PublicResolver *PublicResolverCallerSession) Pubkey(node [32]byte) (struct { X [32]byte Y [32]byte @@ -328,7 +334,7 @@ func (_PublicResolver *PublicResolverCallerSession) Pubkey(node [32]byte) (struc // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceID) constant returns(bool) func (_PublicResolver *PublicResolverCaller) SupportsInterface(opts *bind.CallOpts, interfaceID [4]byte) (bool, error) { var ( ret0 = new(bool) @@ -340,21 +346,21 @@ func (_PublicResolver *PublicResolverCaller) SupportsInterface(opts *bind.CallOp // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceID) constant returns(bool) func (_PublicResolver *PublicResolverSession) SupportsInterface(interfaceID [4]byte) (bool, error) { return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceID) constant returns(bool) func (_PublicResolver *PublicResolverCallerSession) SupportsInterface(interfaceID [4]byte) (bool, error) { return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) } // Text is a free data retrieval call binding the contract method 0x59d1d43c. // -// Solidity: function text(node bytes32, key string) constant returns(ret string) +// Solidity: function text(bytes32 node, string key) constant returns(string) func (_PublicResolver *PublicResolverCaller) Text(opts *bind.CallOpts, node [32]byte, key string) (string, error) { var ( ret0 = new(string) @@ -366,140 +372,140 @@ func (_PublicResolver *PublicResolverCaller) Text(opts *bind.CallOpts, node [32] // Text is a free data retrieval call binding the contract method 0x59d1d43c. // -// Solidity: function text(node bytes32, key string) constant returns(ret string) +// Solidity: function text(bytes32 node, string key) constant returns(string) func (_PublicResolver *PublicResolverSession) Text(node [32]byte, key string) (string, error) { return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) } // Text is a free data retrieval call binding the contract method 0x59d1d43c. // -// Solidity: function text(node bytes32, key string) constant returns(ret string) +// Solidity: function text(bytes32 node, string key) constant returns(string) func (_PublicResolver *PublicResolverCallerSession) Text(node [32]byte, key string) (string, error) { return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) } // SetABI is a paid mutator transaction binding the contract method 0x623195b0. // -// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() +// Solidity: function setABI(bytes32 node, uint256 contentType, bytes data) returns() func (_PublicResolver *PublicResolverTransactor) SetABI(opts *bind.TransactOpts, node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { return _PublicResolver.contract.Transact(opts, "setABI", node, contentType, data) } // SetABI is a paid mutator transaction binding the contract method 0x623195b0. // -// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() +// Solidity: function setABI(bytes32 node, uint256 contentType, bytes data) returns() func (_PublicResolver *PublicResolverSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) } // SetABI is a paid mutator transaction binding the contract method 0x623195b0. // -// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() +// Solidity: function setABI(bytes32 node, uint256 contentType, bytes data) returns() func (_PublicResolver *PublicResolverTransactorSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) } // SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. // -// Solidity: function setAddr(node bytes32, addr address) returns() +// Solidity: function setAddr(bytes32 node, address addr) returns() func (_PublicResolver *PublicResolverTransactor) SetAddr(opts *bind.TransactOpts, node [32]byte, addr common.Address) (*types.Transaction, error) { return _PublicResolver.contract.Transact(opts, "setAddr", node, addr) } // SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. // -// Solidity: function setAddr(node bytes32, addr address) returns() +// Solidity: function setAddr(bytes32 node, address addr) returns() func (_PublicResolver *PublicResolverSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) } // SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. // -// Solidity: function setAddr(node bytes32, addr address) returns() +// Solidity: function setAddr(bytes32 node, address addr) returns() func (_PublicResolver *PublicResolverTransactorSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) } -// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. +// SetContenthash is a paid mutator transaction binding the contract method 0x304e6ade. // -// Solidity: function setContent(node bytes32, hash bytes32) returns() -func (_PublicResolver *PublicResolverTransactor) SetContent(opts *bind.TransactOpts, node [32]byte, hash [32]byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setContent", node, hash) +// Solidity: function setContenthash(bytes32 node, bytes hash) returns() +func (_PublicResolver *PublicResolverTransactor) SetContenthash(opts *bind.TransactOpts, node [32]byte, hash []byte) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setContenthash", node, hash) } -// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. +// SetContenthash is a paid mutator transaction binding the contract method 0x304e6ade. // -// Solidity: function setContent(node bytes32, hash bytes32) returns() -func (_PublicResolver *PublicResolverSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash) +// Solidity: function setContenthash(bytes32 node, bytes hash) returns() +func (_PublicResolver *PublicResolverSession) SetContenthash(node [32]byte, hash []byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetContenthash(&_PublicResolver.TransactOpts, node, hash) } -// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. +// SetContenthash is a paid mutator transaction binding the contract method 0x304e6ade. // -// Solidity: function setContent(node bytes32, hash bytes32) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash) +// Solidity: function setContenthash(bytes32 node, bytes hash) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetContenthash(node [32]byte, hash []byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetContenthash(&_PublicResolver.TransactOpts, node, hash) } // SetName is a paid mutator transaction binding the contract method 0x77372213. // -// Solidity: function setName(node bytes32, name string) returns() +// Solidity: function setName(bytes32 node, string name) returns() func (_PublicResolver *PublicResolverTransactor) SetName(opts *bind.TransactOpts, node [32]byte, name string) (*types.Transaction, error) { return _PublicResolver.contract.Transact(opts, "setName", node, name) } // SetName is a paid mutator transaction binding the contract method 0x77372213. // -// Solidity: function setName(node bytes32, name string) returns() +// Solidity: function setName(bytes32 node, string name) returns() func (_PublicResolver *PublicResolverSession) SetName(node [32]byte, name string) (*types.Transaction, error) { return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) } // SetName is a paid mutator transaction binding the contract method 0x77372213. // -// Solidity: function setName(node bytes32, name string) returns() +// Solidity: function setName(bytes32 node, string name) returns() func (_PublicResolver *PublicResolverTransactorSession) SetName(node [32]byte, name string) (*types.Transaction, error) { return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) } // SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. // -// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() +// Solidity: function setPubkey(bytes32 node, bytes32 x, bytes32 y) returns() func (_PublicResolver *PublicResolverTransactor) SetPubkey(opts *bind.TransactOpts, node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { return _PublicResolver.contract.Transact(opts, "setPubkey", node, x, y) } // SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. // -// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() +// Solidity: function setPubkey(bytes32 node, bytes32 x, bytes32 y) returns() func (_PublicResolver *PublicResolverSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) } // SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. // -// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() +// Solidity: function setPubkey(bytes32 node, bytes32 x, bytes32 y) returns() func (_PublicResolver *PublicResolverTransactorSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) } // SetText is a paid mutator transaction binding the contract method 0x10f13a8c. // -// Solidity: function setText(node bytes32, key string, value string) returns() +// Solidity: function setText(bytes32 node, string key, string value) returns() func (_PublicResolver *PublicResolverTransactor) SetText(opts *bind.TransactOpts, node [32]byte, key string, value string) (*types.Transaction, error) { return _PublicResolver.contract.Transact(opts, "setText", node, key, value) } // SetText is a paid mutator transaction binding the contract method 0x10f13a8c. // -// Solidity: function setText(node bytes32, key string, value string) returns() +// Solidity: function setText(bytes32 node, string key, string value) returns() func (_PublicResolver *PublicResolverSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) } // SetText is a paid mutator transaction binding the contract method 0x10f13a8c. // -// Solidity: function setText(node bytes32, key string, value string) returns() +// Solidity: function setText(bytes32 node, string key, string value) returns() func (_PublicResolver *PublicResolverTransactorSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) } @@ -559,7 +565,7 @@ func (it *PublicResolverABIChangedIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *PublicResolverABIChangedIterator) Error() error { return it.fail } @@ -580,7 +586,7 @@ type PublicResolverABIChanged struct { // FilterABIChanged is a free log retrieval operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. // -// Solidity: event ABIChanged(node indexed bytes32, contentType indexed uint256) +// Solidity: event ABIChanged(bytes32 indexed node, uint256 indexed contentType) func (_PublicResolver *PublicResolverFilterer) FilterABIChanged(opts *bind.FilterOpts, node [][32]byte, contentType []*big.Int) (*PublicResolverABIChangedIterator, error) { var nodeRule []interface{} @@ -601,7 +607,7 @@ func (_PublicResolver *PublicResolverFilterer) FilterABIChanged(opts *bind.Filte // WatchABIChanged is a free log subscription operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. // -// Solidity: event ABIChanged(node indexed bytes32, contentType indexed uint256) +// Solidity: event ABIChanged(bytes32 indexed node, uint256 indexed contentType) func (_PublicResolver *PublicResolverFilterer) WatchABIChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverABIChanged, node [][32]byte, contentType []*big.Int) (event.Subscription, error) { var nodeRule []interface{} @@ -700,7 +706,7 @@ func (it *PublicResolverAddrChangedIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *PublicResolverAddrChangedIterator) Error() error { return it.fail } @@ -721,7 +727,7 @@ type PublicResolverAddrChanged struct { // FilterAddrChanged is a free log retrieval operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. // -// Solidity: event AddrChanged(node indexed bytes32, a address) +// Solidity: event AddrChanged(bytes32 indexed node, address a) func (_PublicResolver *PublicResolverFilterer) FilterAddrChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverAddrChangedIterator, error) { var nodeRule []interface{} @@ -738,7 +744,7 @@ func (_PublicResolver *PublicResolverFilterer) FilterAddrChanged(opts *bind.Filt // WatchAddrChanged is a free log subscription operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. // -// Solidity: event AddrChanged(node indexed bytes32, a address) +// Solidity: event AddrChanged(bytes32 indexed node, address a) func (_PublicResolver *PublicResolverFilterer) WatchAddrChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverAddrChanged, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} @@ -778,9 +784,9 @@ func (_PublicResolver *PublicResolverFilterer) WatchAddrChanged(opts *bind.Watch }), nil } -// PublicResolverContentChangedIterator is returned from FilterContentChanged and is used to iterate over the raw logs and unpacked data for ContentChanged events raised by the PublicResolver contract. -type PublicResolverContentChangedIterator struct { - Event *PublicResolverContentChanged // Event containing the contract specifics and raw log +// PublicResolverContenthashChangedIterator is returned from FilterContenthashChanged and is used to iterate over the raw logs and unpacked data for ContenthashChanged events raised by the PublicResolver contract. +type PublicResolverContenthashChangedIterator struct { + Event *PublicResolverContenthashChanged // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -794,7 +800,7 @@ type PublicResolverContentChangedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *PublicResolverContentChangedIterator) Next() bool { +func (it *PublicResolverContenthashChangedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -803,7 +809,7 @@ func (it *PublicResolverContentChangedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(PublicResolverContentChanged) + it.Event = new(PublicResolverContenthashChanged) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -818,7 +824,7 @@ func (it *PublicResolverContentChangedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(PublicResolverContentChanged) + it.Event = new(PublicResolverContenthashChanged) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -833,53 +839,53 @@ func (it *PublicResolverContentChangedIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverContentChangedIterator) Error() error { +// Error returns any retrieval or parsing error occurred during filtering. +func (it *PublicResolverContenthashChangedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *PublicResolverContentChangedIterator) Close() error { +func (it *PublicResolverContenthashChangedIterator) Close() error { it.sub.Unsubscribe() return nil } -// PublicResolverContentChanged represents a ContentChanged event raised by the PublicResolver contract. -type PublicResolverContentChanged struct { +// PublicResolverContenthashChanged represents a ContenthashChanged event raised by the PublicResolver contract. +type PublicResolverContenthashChanged struct { Node [32]byte - Hash [32]byte + Hash []byte Raw types.Log // Blockchain specific contextual infos } -// FilterContentChanged is a free log retrieval operation binding the contract event 0x0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc. +// FilterContenthashChanged is a free log retrieval operation binding the contract event 0xe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d7578. // -// Solidity: event ContentChanged(node indexed bytes32, hash bytes32) -func (_PublicResolver *PublicResolverFilterer) FilterContentChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverContentChangedIterator, error) { +// Solidity: event ContenthashChanged(bytes32 indexed node, bytes hash) +func (_PublicResolver *PublicResolverFilterer) FilterContenthashChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverContenthashChangedIterator, error) { var nodeRule []interface{} for _, nodeItem := range node { nodeRule = append(nodeRule, nodeItem) } - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ContentChanged", nodeRule) + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ContenthashChanged", nodeRule) if err != nil { return nil, err } - return &PublicResolverContentChangedIterator{contract: _PublicResolver.contract, event: "ContentChanged", logs: logs, sub: sub}, nil + return &PublicResolverContenthashChangedIterator{contract: _PublicResolver.contract, event: "ContenthashChanged", logs: logs, sub: sub}, nil } -// WatchContentChanged is a free log subscription operation binding the contract event 0x0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc. +// WatchContenthashChanged is a free log subscription operation binding the contract event 0xe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d7578. // -// Solidity: event ContentChanged(node indexed bytes32, hash bytes32) -func (_PublicResolver *PublicResolverFilterer) WatchContentChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverContentChanged, node [][32]byte) (event.Subscription, error) { +// Solidity: event ContenthashChanged(bytes32 indexed node, bytes hash) +func (_PublicResolver *PublicResolverFilterer) WatchContenthashChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverContenthashChanged, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} for _, nodeItem := range node { nodeRule = append(nodeRule, nodeItem) } - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ContentChanged", nodeRule) + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ContenthashChanged", nodeRule) if err != nil { return nil, err } @@ -889,8 +895,8 @@ func (_PublicResolver *PublicResolverFilterer) WatchContentChanged(opts *bind.Wa select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(PublicResolverContentChanged) - if err := _PublicResolver.contract.UnpackLog(event, "ContentChanged", log); err != nil { + event := new(PublicResolverContenthashChanged) + if err := _PublicResolver.contract.UnpackLog(event, "ContenthashChanged", log); err != nil { return err } event.Raw = log @@ -966,7 +972,7 @@ func (it *PublicResolverNameChangedIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *PublicResolverNameChangedIterator) Error() error { return it.fail } @@ -987,7 +993,7 @@ type PublicResolverNameChanged struct { // FilterNameChanged is a free log retrieval operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. // -// Solidity: event NameChanged(node indexed bytes32, name string) +// Solidity: event NameChanged(bytes32 indexed node, string name) func (_PublicResolver *PublicResolverFilterer) FilterNameChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverNameChangedIterator, error) { var nodeRule []interface{} @@ -1004,7 +1010,7 @@ func (_PublicResolver *PublicResolverFilterer) FilterNameChanged(opts *bind.Filt // WatchNameChanged is a free log subscription operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. // -// Solidity: event NameChanged(node indexed bytes32, name string) +// Solidity: event NameChanged(bytes32 indexed node, string name) func (_PublicResolver *PublicResolverFilterer) WatchNameChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverNameChanged, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} @@ -1099,7 +1105,7 @@ func (it *PublicResolverPubkeyChangedIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *PublicResolverPubkeyChangedIterator) Error() error { return it.fail } @@ -1121,7 +1127,7 @@ type PublicResolverPubkeyChanged struct { // FilterPubkeyChanged is a free log retrieval operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. // -// Solidity: event PubkeyChanged(node indexed bytes32, x bytes32, y bytes32) +// Solidity: event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y) func (_PublicResolver *PublicResolverFilterer) FilterPubkeyChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverPubkeyChangedIterator, error) { var nodeRule []interface{} @@ -1138,7 +1144,7 @@ func (_PublicResolver *PublicResolverFilterer) FilterPubkeyChanged(opts *bind.Fi // WatchPubkeyChanged is a free log subscription operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. // -// Solidity: event PubkeyChanged(node indexed bytes32, x bytes32, y bytes32) +// Solidity: event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y) func (_PublicResolver *PublicResolverFilterer) WatchPubkeyChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverPubkeyChanged, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} @@ -1233,7 +1239,7 @@ func (it *PublicResolverTextChangedIterator) Next() bool { } } -// Error retruned any retrieval or parsing error occurred during filtering. +// Error returns any retrieval or parsing error occurred during filtering. func (it *PublicResolverTextChangedIterator) Error() error { return it.fail } @@ -1248,26 +1254,22 @@ func (it *PublicResolverTextChangedIterator) Close() error { // PublicResolverTextChanged represents a TextChanged event raised by the PublicResolver contract. type PublicResolverTextChanged struct { Node [32]byte - IndexedKey common.Hash + IndexedKey string Key string Raw types.Log // Blockchain specific contextual infos } // FilterTextChanged is a free log retrieval operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. // -// Solidity: event TextChanged(node indexed bytes32, indexedKey indexed string, key string) -func (_PublicResolver *PublicResolverFilterer) FilterTextChanged(opts *bind.FilterOpts, node [][32]byte, indexedKey []string) (*PublicResolverTextChangedIterator, error) { +// Solidity: event TextChanged(bytes32 indexed node, string indexedKey, string key) +func (_PublicResolver *PublicResolverFilterer) FilterTextChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverTextChangedIterator, error) { var nodeRule []interface{} for _, nodeItem := range node { nodeRule = append(nodeRule, nodeItem) } - var indexedKeyRule []interface{} - for _, indexedKeyItem := range indexedKey { - indexedKeyRule = append(indexedKeyRule, indexedKeyItem) - } - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "TextChanged", nodeRule, indexedKeyRule) + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "TextChanged", nodeRule) if err != nil { return nil, err } @@ -1276,19 +1278,15 @@ func (_PublicResolver *PublicResolverFilterer) FilterTextChanged(opts *bind.Filt // WatchTextChanged is a free log subscription operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. // -// Solidity: event TextChanged(node indexed bytes32, indexedKey indexed string, key string) -func (_PublicResolver *PublicResolverFilterer) WatchTextChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverTextChanged, node [][32]byte, indexedKey []string) (event.Subscription, error) { +// Solidity: event TextChanged(bytes32 indexed node, string indexedKey, string key) +func (_PublicResolver *PublicResolverFilterer) WatchTextChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverTextChanged, node [][32]byte) (event.Subscription, error) { var nodeRule []interface{} for _, nodeItem := range node { nodeRule = append(nodeRule, nodeItem) } - var indexedKeyRule []interface{} - for _, indexedKeyItem := range indexedKey { - indexedKeyRule = append(indexedKeyRule, indexedKeyItem) - } - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "TextChanged", nodeRule, indexedKeyRule) + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "TextChanged", nodeRule) if err != nil { return nil, err } diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens.go index b7448c47..6fed172d 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens.go @@ -16,26 +16,36 @@ package ens -//go:generate abigen --sol contract/ENS.sol --exc contract/AbstractENS.sol:AbstractENS --pkg contract --out contract/ens.go -//go:generate abigen --sol contract/FIFSRegistrar.sol --exc contract/AbstractENS.sol:AbstractENS --pkg contract --out contract/fifsregistrar.go -//go:generate abigen --sol contract/PublicResolver.sol --exc contract/AbstractENS.sol:AbstractENS --pkg contract --out contract/publicresolver.go +//go:generate abigen --sol contract/ENS.sol --pkg contract --out contract/ens.go +//go:generate abigen --sol contract/ENSRegistry.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/ensregistry.go +//go:generate abigen --sol contract/FIFSRegistrar.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/fifsregistrar.go +//go:generate abigen --sol contract/PublicResolver.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/publicresolver.go import ( + "encoding/binary" "strings" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/ens/contract" + "github.com/ethereum/go-ethereum/contracts/ens/fallback_contract" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" ) var ( - MainNetAddress = common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b") - TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010") + MainNetAddress = common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b") + TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010") + contentHash_Interface_Id [4]byte ) -// swarm domain name registry and resolver +const contentHash_Interface_Id_Spec = 0xbc1c58d1 + +func init() { + binary.BigEndian.PutUint32(contentHash_Interface_Id[:], contentHash_Interface_Id_Spec) +} + +// ENS is the swarm domain name registry and resolver type ENS struct { *contract.ENSSession contractBackend bind.ContractBackend @@ -48,7 +58,6 @@ func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contra if err != nil { return nil, err } - return &ENS{ &contract.ENSSession{ Contract: ens, @@ -60,27 +69,24 @@ func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contra // DeployENS deploys an instance of the ENS nameservice, with a 'first-in, first-served' root registrar. func DeployENS(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (common.Address, *ENS, error) { - // Deploy the ENS registry. - ensAddr, _, _, err := contract.DeployENS(transactOpts, contractBackend) + // Deploy the ENS registry + ensAddr, _, _, err := contract.DeployENSRegistry(transactOpts, contractBackend) if err != nil { return ensAddr, nil, err } - ens, err := NewENS(transactOpts, ensAddr, contractBackend) if err != nil { return ensAddr, nil, err } - - // Deploy the registrar. + // Deploy the registrar regAddr, _, _, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{}) if err != nil { return ensAddr, nil, err } - // Set the registrar as owner of the ENS root. + // Set the registrar as owner of the ENS root if _, err = ens.SetOwner([32]byte{}, regAddr); err != nil { return ensAddr, nil, err } - return ensAddr, ens, nil } @@ -89,10 +95,9 @@ func ensParentNode(name string) (common.Hash, common.Hash) { label := crypto.Keccak256Hash([]byte(parts[0])) if len(parts) == 1 { return [32]byte{}, label - } else { - parentNode, parentLabel := ensParentNode(parts[1]) - return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label } + parentNode, parentLabel := ensParentNode(parts[1]) + return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label } func EnsNode(name string) common.Hash { @@ -100,111 +105,159 @@ func EnsNode(name string) common.Hash { return crypto.Keccak256Hash(parentNode[:], parentLabel[:]) } -func (self *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) { - resolverAddr, err := self.Resolver(node) +func (ens *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) { + resolverAddr, err := ens.Resolver(node) if err != nil { return nil, err } - - resolver, err := contract.NewPublicResolver(resolverAddr, self.contractBackend) + resolver, err := contract.NewPublicResolver(resolverAddr, ens.contractBackend) if err != nil { return nil, err } - return &contract.PublicResolverSession{ Contract: resolver, - TransactOpts: self.TransactOpts, + TransactOpts: ens.TransactOpts, }, nil } -func (self *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) { - registrarAddr, err := self.Owner(node) +func (ens *ENS) getFallbackResolver(node [32]byte) (*fallback_contract.PublicResolverSession, error) { + resolverAddr, err := ens.Resolver(node) if err != nil { return nil, err } - - registrar, err := contract.NewFIFSRegistrar(registrarAddr, self.contractBackend) + resolver, err := fallback_contract.NewPublicResolver(resolverAddr, ens.contractBackend) if err != nil { return nil, err } + return &fallback_contract.PublicResolverSession{ + Contract: resolver, + TransactOpts: ens.TransactOpts, + }, nil +} +func (ens *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) { + registrarAddr, err := ens.Owner(node) + if err != nil { + return nil, err + } + registrar, err := contract.NewFIFSRegistrar(registrarAddr, ens.contractBackend) + if err != nil { + return nil, err + } return &contract.FIFSRegistrarSession{ Contract: registrar, - TransactOpts: self.TransactOpts, + TransactOpts: ens.TransactOpts, }, nil } // Resolve is a non-transactional call that returns the content hash associated with a name. -func (self *ENS) Resolve(name string) (common.Hash, error) { +func (ens *ENS) Resolve(name string) (common.Hash, error) { node := EnsNode(name) - resolver, err := self.getResolver(node) + resolver, err := ens.getResolver(node) if err != nil { return common.Hash{}, err } - ret, err := resolver.Content(node) + // IMPORTANT: The old contract is deprecated. This code should be removed latest on June 1st 2019 + supported, err := resolver.SupportsInterface(contentHash_Interface_Id) if err != nil { return common.Hash{}, err } - return common.BytesToHash(ret[:]), nil + if !supported { + resolver, err := ens.getFallbackResolver(node) + if err != nil { + return common.Hash{}, err + } + ret, err := resolver.Content(node) + if err != nil { + return common.Hash{}, err + } + return common.BytesToHash(ret[:]), nil + } + + // END DEPRECATED CODE + + contentHash, err := resolver.Contenthash(node) + if err != nil { + return common.Hash{}, err + } + + return extractContentHash(contentHash) } // Addr is a non-transactional call that returns the address associated with a name. -func (self *ENS) Addr(name string) (common.Address, error) { +func (ens *ENS) Addr(name string) (common.Address, error) { node := EnsNode(name) - resolver, err := self.getResolver(node) + resolver, err := ens.getResolver(node) if err != nil { return common.Address{}, err } - ret, err := resolver.Addr(node) if err != nil { return common.Address{}, err } - return common.BytesToAddress(ret[:]), nil } // SetAddress sets the address associated with a name. Only works if the caller // owns the name, and the associated resolver implements a `setAddress` function. -func (self *ENS) SetAddr(name string, addr common.Address) (*types.Transaction, error) { +func (ens *ENS) SetAddr(name string, addr common.Address) (*types.Transaction, error) { node := EnsNode(name) - resolver, err := self.getResolver(node) + resolver, err := ens.getResolver(node) if err != nil { return nil, err } - - opts := self.TransactOpts + opts := ens.TransactOpts opts.GasLimit = 200000 return resolver.Contract.SetAddr(&opts, node, addr) } // Register registers a new domain name for the caller, making them the owner of the new name. // Only works if the registrar for the parent domain implements the FIFS registrar protocol. -func (self *ENS) Register(name string) (*types.Transaction, error) { +func (ens *ENS) Register(name string) (*types.Transaction, error) { parentNode, label := ensParentNode(name) - registrar, err := self.getRegistrar(parentNode) + registrar, err := ens.getRegistrar(parentNode) if err != nil { return nil, err } - return registrar.Contract.Register(&self.TransactOpts, label, self.TransactOpts.From) + return registrar.Contract.Register(&ens.TransactOpts, label, ens.TransactOpts.From) } // SetContentHash sets the content hash associated with a name. Only works if the caller -// owns the name, and the associated resolver implements a `setContent` function. -func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) { +// owns the name, and the associated resolver implements a `setContenthash` function. +func (ens *ENS) SetContentHash(name string, hash []byte) (*types.Transaction, error) { node := EnsNode(name) - resolver, err := self.getResolver(node) + resolver, err := ens.getResolver(node) if err != nil { return nil, err } - opts := self.TransactOpts + opts := ens.TransactOpts opts.GasLimit = 200000 - return resolver.Contract.SetContent(&opts, node, hash) + + // IMPORTANT: The old contract is deprecated. This code should be removed latest on June 1st 2019 + supported, err := resolver.SupportsInterface(contentHash_Interface_Id) + if err != nil { + return nil, err + } + + if !supported { + resolver, err := ens.getFallbackResolver(node) + if err != nil { + return nil, err + } + opts := ens.TransactOpts + opts.GasLimit = 200000 + var b [32]byte + copy(b[:], hash) + return resolver.Contract.SetContent(&opts, node, b) + } + + // END DEPRECATED CODE + return resolver.Contract.SetContenthash(&opts, node, hash) } diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens_test.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens_test.go index cd64fbf1..c65df836 100644 --- a/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens_test.go +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/ens_test.go @@ -24,16 +24,18 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/ens/contract" + "github.com/ethereum/go-ethereum/contracts/ens/fallback_contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" ) var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - name = "my name on ENS" - hash = crypto.Keccak256Hash([]byte("my content")) - addr = crypto.PubkeyToAddress(key.PublicKey) - testAddr = common.HexToAddress("0x1234123412341234123412341234123412341234") + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + name = "my name on ENS" + hash = crypto.Keccak256Hash([]byte("my content")) + fallbackHash = crypto.Keccak256Hash([]byte("my content hash")) + addr = crypto.PubkeyToAddress(key.PublicKey) + testAddr = common.HexToAddress("0x1234123412341234123412341234123412341234") ) func TestENS(t *testing.T) { @@ -57,24 +59,29 @@ func TestENS(t *testing.T) { if err != nil { t.Fatalf("can't deploy resolver: %v", err) } + if _, err := ens.SetResolver(EnsNode(name), resolverAddr); err != nil { t.Fatalf("can't set resolver: %v", err) } contractBackend.Commit() // Set the content hash for the name. - if _, err = ens.SetContentHash(name, hash); err != nil { + cid, err := EncodeSwarmHash(hash) + if err != nil { + t.Fatal(err) + } + if _, err = ens.SetContentHash(name, cid); err != nil { t.Fatalf("can't set content hash: %v", err) } contractBackend.Commit() // Try to resolve the name. - vhost, err := ens.Resolve(name) + resolvedHash, err := ens.Resolve(name) if err != nil { t.Fatalf("expected no error, got %v", err) } - if vhost != hash { - t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), vhost.Hex()) + if resolvedHash.Hex() != hash.Hex() { + t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), resolvedHash.Hex()) } // set the address for the name @@ -88,7 +95,32 @@ func TestENS(t *testing.T) { if err != nil { t.Fatalf("expected no error, got %v", err) } - if vhost != hash { + if testAddr.Hex() != recoveredAddr.Hex() { t.Fatalf("resolve error, expected %v, got %v", testAddr.Hex(), recoveredAddr.Hex()) } + + // deploy the fallback contract and see that the fallback mechanism works + fallbackResolverAddr, _, _, err := fallback_contract.DeployPublicResolver(transactOpts, contractBackend, ensAddr) + if err != nil { + t.Fatalf("can't deploy resolver: %v", err) + } + if _, err := ens.SetResolver(EnsNode(name), fallbackResolverAddr); err != nil { + t.Fatalf("can't set resolver: %v", err) + } + contractBackend.Commit() + + // Set the content hash for the name. + if _, err = ens.SetContentHash(name, fallbackHash.Bytes()); err != nil { + t.Fatalf("can't set content hash: %v", err) + } + contractBackend.Commit() + + // Try to resolve the name. + fallbackResolvedHash, err := ens.Resolve(name) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if fallbackResolvedHash.Hex() != fallbackHash.Hex() { + t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), resolvedHash.Hex()) + } } diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/fallback_contract/PublicResolver.sol b/vendor/github.com/ethereum/go-ethereum/contracts/ens/fallback_contract/PublicResolver.sol new file mode 100644 index 00000000..9dcc9568 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/fallback_contract/PublicResolver.sol @@ -0,0 +1,212 @@ +pragma solidity ^0.4.0; + +import './AbstractENS.sol'; + +/** + * A simple resolver anyone can use; only allows the owner of a node to set its + * address. + */ +contract PublicResolver { + bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; + bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; + bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5; + bytes4 constant NAME_INTERFACE_ID = 0x691f3431; + bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; + bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; + bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; + + event AddrChanged(bytes32 indexed node, address a); + event ContentChanged(bytes32 indexed node, bytes32 hash); + event NameChanged(bytes32 indexed node, string name); + event ABIChanged(bytes32 indexed node, uint256 indexed contentType); + event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); + event TextChanged(bytes32 indexed node, string indexed indexedKey, string key); + + struct PublicKey { + bytes32 x; + bytes32 y; + } + + struct Record { + address addr; + bytes32 content; + string name; + PublicKey pubkey; + mapping(string=>string) text; + mapping(uint256=>bytes) abis; + } + + AbstractENS ens; + mapping(bytes32=>Record) records; + + modifier only_owner(bytes32 node) { + if (ens.owner(node) != msg.sender) throw; + _; + } + + /** + * Constructor. + * @param ensAddr The ENS registrar contract. + */ + function PublicResolver(AbstractENS ensAddr) { + ens = ensAddr; + } + + /** + * Returns true if the resolver implements the interface specified by the provided hash. + * @param interfaceID The ID of the interface to check for. + * @return True if the contract implements the requested interface. + */ + function supportsInterface(bytes4 interfaceID) constant returns (bool) { + return interfaceID == ADDR_INTERFACE_ID || + interfaceID == CONTENT_INTERFACE_ID || + interfaceID == NAME_INTERFACE_ID || + interfaceID == ABI_INTERFACE_ID || + interfaceID == PUBKEY_INTERFACE_ID || + interfaceID == TEXT_INTERFACE_ID || + interfaceID == INTERFACE_META_ID; + } + + /** + * Returns the address associated with an ENS node. + * @param node The ENS node to query. + * @return The associated address. + */ + function addr(bytes32 node) constant returns (address ret) { + ret = records[node].addr; + } + + /** + * Sets the address associated with an ENS node. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param addr The address to set. + */ + function setAddr(bytes32 node, address addr) only_owner(node) { + records[node].addr = addr; + AddrChanged(node, addr); + } + + /** + * Returns the content hash associated with an ENS node. + * Note that this resource type is not standardized, and will likely change + * in future to a resource type based on multihash. + * @param node The ENS node to query. + * @return The associated content hash. + */ + function content(bytes32 node) constant returns (bytes32 ret) { + ret = records[node].content; + } + + /** + * Sets the content hash associated with an ENS node. + * May only be called by the owner of that node in the ENS registry. + * Note that this resource type is not standardized, and will likely change + * in future to a resource type based on multihash. + * @param node The node to update. + * @param hash The content hash to set + */ + function setContent(bytes32 node, bytes32 hash) only_owner(node) { + records[node].content = hash; + ContentChanged(node, hash); + } + + /** + * Returns the name associated with an ENS node, for reverse records. + * Defined in EIP181. + * @param node The ENS node to query. + * @return The associated name. + */ + function name(bytes32 node) constant returns (string ret) { + ret = records[node].name; + } + + /** + * Sets the name associated with an ENS node, for reverse records. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param name The name to set. + */ + function setName(bytes32 node, string name) only_owner(node) { + records[node].name = name; + NameChanged(node, name); + } + + /** + * Returns the ABI associated with an ENS node. + * Defined in EIP205. + * @param node The ENS node to query + * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. + * @return contentType The content type of the return value + * @return data The ABI data + */ + function ABI(bytes32 node, uint256 contentTypes) constant returns (uint256 contentType, bytes data) { + var record = records[node]; + for(contentType = 1; contentType <= contentTypes; contentType <<= 1) { + if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { + data = record.abis[contentType]; + return; + } + } + contentType = 0; + } + + /** + * Sets the ABI associated with an ENS node. + * Nodes may have one ABI of each content type. To remove an ABI, set it to + * the empty string. + * @param node The node to update. + * @param contentType The content type of the ABI + * @param data The ABI data. + */ + function setABI(bytes32 node, uint256 contentType, bytes data) only_owner(node) { + // Content types must be powers of 2 + if (((contentType - 1) & contentType) != 0) throw; + + records[node].abis[contentType] = data; + ABIChanged(node, contentType); + } + + /** + * Returns the SECP256k1 public key associated with an ENS node. + * Defined in EIP 619. + * @param node The ENS node to query + * @return x, y the X and Y coordinates of the curve point for the public key. + */ + function pubkey(bytes32 node) constant returns (bytes32 x, bytes32 y) { + return (records[node].pubkey.x, records[node].pubkey.y); + } + + /** + * Sets the SECP256k1 public key associated with an ENS node. + * @param node The ENS node to query + * @param x the X coordinate of the curve point for the public key. + * @param y the Y coordinate of the curve point for the public key. + */ + function setPubkey(bytes32 node, bytes32 x, bytes32 y) only_owner(node) { + records[node].pubkey = PublicKey(x, y); + PubkeyChanged(node, x, y); + } + + /** + * Returns the text data associated with an ENS node and key. + * @param node The ENS node to query. + * @param key The text data key to query. + * @return The associated text data. + */ + function text(bytes32 node, string key) constant returns (string ret) { + ret = records[node].text[key]; + } + + /** + * Sets the text data associated with an ENS node and key. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param key The key to set. + * @param value The text data value to set. + */ + function setText(bytes32 node, string key, string value) only_owner(node) { + records[node].text[key] = value; + TextChanged(node, key, key); + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/contracts/ens/fallback_contract/publicresolver.go b/vendor/github.com/ethereum/go-ethereum/contracts/ens/fallback_contract/publicresolver.go new file mode 100644 index 00000000..a2a4be1c --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/contracts/ens/fallback_contract/publicresolver.go @@ -0,0 +1,1321 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package fallback_contract + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// PublicResolverABI is the input ABI used to generate the binding from. +const PublicResolverABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceID\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setText\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentTypes\",\"type\":\"uint256\"}],\"name\":\"ABI\",\"outputs\":[{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"setPubkey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"content\",\"outputs\":[{\"name\":\"ret\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"ret\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"text\",\"outputs\":[{\"name\":\"ret\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"setABI\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"ret\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setName\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"setContent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"pubkey\",\"outputs\":[{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAddr\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address\"}],\"name\":\"AddrChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"ContentChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NameChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"contentType\",\"type\":\"uint256\"}],\"name\":\"ABIChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"x\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"PubkeyChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"indexedKey\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"key\",\"type\":\"string\"}],\"name\":\"TextChanged\",\"type\":\"event\"}]" + +// PublicResolverBin is the compiled bytecode used for deploying new contracts. +const PublicResolverBin = `0x6060604052341561000f57600080fd5b6040516020806111b28339810160405280805160008054600160a060020a03909216600160a060020a0319909216919091179055505061115e806100546000396000f3006060604052600436106100ab5763ffffffff60e060020a60003504166301ffc9a781146100b057806310f13a8c146100e45780632203ab561461017e57806329cd62ea146102155780632dff6941146102315780633b3b57de1461025957806359d1d43c1461028b578063623195b014610358578063691f3431146103b457806377372213146103ca578063c3d014d614610420578063c869023314610439578063d5fa2b0014610467575b600080fd5b34156100bb57600080fd5b6100d0600160e060020a031960043516610489565b604051901515815260200160405180910390f35b34156100ef57600080fd5b61017c600480359060446024803590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f0160208091040260200160405190810160405281815292919060208401838380828437509496506105f695505050505050565b005b341561018957600080fd5b610197600435602435610807565b60405182815260406020820181815290820183818151815260200191508051906020019080838360005b838110156101d95780820151838201526020016101c1565b50505050905090810190601f1680156102065780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561022057600080fd5b61017c600435602435604435610931565b341561023c57600080fd5b610247600435610a30565b60405190815260200160405180910390f35b341561026457600080fd5b61026f600435610a46565b604051600160a060020a03909116815260200160405180910390f35b341561029657600080fd5b6102e1600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610a6195505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561031d578082015183820152602001610305565b50505050905090810190601f16801561034a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561036357600080fd5b61017c600480359060248035919060649060443590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610b8095505050505050565b34156103bf57600080fd5b6102e1600435610c7c565b34156103d557600080fd5b61017c600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610d4295505050505050565b341561042b57600080fd5b61017c600435602435610e8c565b341561044457600080fd5b61044f600435610f65565b60405191825260208201526040908101905180910390f35b341561047257600080fd5b61017c600435600160a060020a0360243516610f82565b6000600160e060020a031982167f3b3b57de0000000000000000000000000000000000000000000000000000000014806104ec5750600160e060020a031982167fd8389dc500000000000000000000000000000000000000000000000000000000145b806105205750600160e060020a031982167f691f343100000000000000000000000000000000000000000000000000000000145b806105545750600160e060020a031982167f2203ab5600000000000000000000000000000000000000000000000000000000145b806105885750600160e060020a031982167fc869023300000000000000000000000000000000000000000000000000000000145b806105bc5750600160e060020a031982167f59d1d43c00000000000000000000000000000000000000000000000000000000145b806105f05750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561064f57600080fd5b6102c65a03f1151561066057600080fd5b50505060405180519050600160a060020a031614151561067f57600080fd5b6000848152600160205260409081902083916005909101908590518082805190602001908083835b602083106106c65780518252601f1990920191602091820191016106a7565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902090805161070a929160200190611085565b50826040518082805190602001908083835b6020831061073b5780518252601f19909201916020918201910161071c565b6001836020036101000a0380198251168184511617909252505050919091019250604091505051908190039020847fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a75508560405160208082528190810183818151815260200191508051906020019080838360005b838110156107c75780820151838201526020016107af565b50505050905090810190601f1680156107f45780820380516001836020036101000a031916815260200191505b509250505060405180910390a350505050565b6000610811611103565b60008481526001602081905260409091209092505b838311610924578284161580159061085f5750600083815260068201602052604081205460026000196101006001841615020190911604115b15610919578060060160008481526020019081526020016000208054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561090d5780601f106108e25761010080835404028352916020019161090d565b820191906000526020600020905b8154815290600101906020018083116108f057829003601f168201915b50505050509150610929565b600290920291610826565b600092505b509250929050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561098a57600080fd5b6102c65a03f1151561099b57600080fd5b50505060405180519050600160a060020a03161415156109ba57600080fd5b6040805190810160409081528482526020808301859052600087815260019091522060030181518155602082015160019091015550837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46848460405191825260208201526040908101905180910390a250505050565b6000908152600160208190526040909120015490565b600090815260016020526040902054600160a060020a031690565b610a69611103565b60008381526001602052604090819020600501908390518082805190602001908083835b60208310610aac5780518252601f199092019160209182019101610a8d565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b735780601f10610b4857610100808354040283529160200191610b73565b820191906000526020600020905b815481529060010190602001808311610b5657829003601f168201915b5050505050905092915050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610bd957600080fd5b6102c65a03f11515610bea57600080fd5b50505060405180519050600160a060020a0316141515610c0957600080fd5b6000198301831615610c1a57600080fd5b60008481526001602090815260408083208684526006019091529020828051610c47929160200190611085565b5082847faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a350505050565b610c84611103565b6001600083600019166000191681526020019081526020016000206002018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610d365780601f10610d0b57610100808354040283529160200191610d36565b820191906000526020600020905b815481529060010190602001808311610d1957829003601f168201915b50505050509050919050565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610d9b57600080fd5b6102c65a03f11515610dac57600080fd5b50505060405180519050600160a060020a0316141515610dcb57600080fd5b6000838152600160205260409020600201828051610ded929160200190611085565b50827fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f78360405160208082528190810183818151815260200191508051906020019080838360005b83811015610e4d578082015183820152602001610e35565b50505050905090810190601f168015610e7a5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505050565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610ee557600080fd5b6102c65a03f11515610ef657600080fd5b50505060405180519050600160a060020a0316141515610f1557600080fd5b6000838152600160208190526040918290200183905583907f0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc9084905190815260200160405180910390a2505050565b600090815260016020526040902060038101546004909101549091565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610fdb57600080fd5b6102c65a03f11515610fec57600080fd5b50505060405180519050600160a060020a031614151561100b57600080fd5b60008381526001602052604090819020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03851617905583907f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd290849051600160a060020a03909116815260200160405180910390a2505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106110c657805160ff19168380011785556110f3565b828001600101855582156110f3579182015b828111156110f35782518255916020019190600101906110d8565b506110ff929150611115565b5090565b60206040519081016040526000815290565b61112f91905b808211156110ff576000815560010161111b565b905600a165627a7a723058201ecacbc445b9fbcd91b0ab164389f69d7283b856883bc7437eeed1008345a4920029` + +// DeployPublicResolver deploys a new Ethereum contract, binding an instance of PublicResolver to it. +func DeployPublicResolver(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address) (common.Address, *types.Transaction, *PublicResolver, error) { + parsed, err := abi.JSON(strings.NewReader(PublicResolverABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(PublicResolverBin), backend, ensAddr) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}, PublicResolverFilterer: PublicResolverFilterer{contract: contract}}, nil +} + +// PublicResolver is an auto generated Go binding around an Ethereum contract. +type PublicResolver struct { + PublicResolverCaller // Read-only binding to the contract + PublicResolverTransactor // Write-only binding to the contract + PublicResolverFilterer // Log filterer for contract events +} + +// PublicResolverCaller is an auto generated read-only Go binding around an Ethereum contract. +type PublicResolverCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// PublicResolverTransactor is an auto generated write-only Go binding around an Ethereum contract. +type PublicResolverTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// PublicResolverFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type PublicResolverFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// PublicResolverSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type PublicResolverSession struct { + Contract *PublicResolver // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// PublicResolverCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type PublicResolverCallerSession struct { + Contract *PublicResolverCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// PublicResolverTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type PublicResolverTransactorSession struct { + Contract *PublicResolverTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// PublicResolverRaw is an auto generated low-level Go binding around an Ethereum contract. +type PublicResolverRaw struct { + Contract *PublicResolver // Generic contract binding to access the raw methods on +} + +// PublicResolverCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type PublicResolverCallerRaw struct { + Contract *PublicResolverCaller // Generic read-only contract binding to access the raw methods on +} + +// PublicResolverTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type PublicResolverTransactorRaw struct { + Contract *PublicResolverTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewPublicResolver creates a new instance of PublicResolver, bound to a specific deployed contract. +func NewPublicResolver(address common.Address, backend bind.ContractBackend) (*PublicResolver, error) { + contract, err := bindPublicResolver(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}, PublicResolverFilterer: PublicResolverFilterer{contract: contract}}, nil +} + +// NewPublicResolverCaller creates a new read-only instance of PublicResolver, bound to a specific deployed contract. +func NewPublicResolverCaller(address common.Address, caller bind.ContractCaller) (*PublicResolverCaller, error) { + contract, err := bindPublicResolver(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &PublicResolverCaller{contract: contract}, nil +} + +// NewPublicResolverTransactor creates a new write-only instance of PublicResolver, bound to a specific deployed contract. +func NewPublicResolverTransactor(address common.Address, transactor bind.ContractTransactor) (*PublicResolverTransactor, error) { + contract, err := bindPublicResolver(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &PublicResolverTransactor{contract: contract}, nil +} + +// NewPublicResolverFilterer creates a new log filterer instance of PublicResolver, bound to a specific deployed contract. +func NewPublicResolverFilterer(address common.Address, filterer bind.ContractFilterer) (*PublicResolverFilterer, error) { + contract, err := bindPublicResolver(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &PublicResolverFilterer{contract: contract}, nil +} + +// bindPublicResolver binds a generic wrapper to an already deployed contract. +func bindPublicResolver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(PublicResolverABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_PublicResolver *PublicResolverRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _PublicResolver.Contract.PublicResolverCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_PublicResolver *PublicResolverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _PublicResolver.Contract.PublicResolverTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_PublicResolver *PublicResolverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _PublicResolver.Contract.PublicResolverTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_PublicResolver *PublicResolverCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _PublicResolver.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_PublicResolver *PublicResolverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _PublicResolver.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_PublicResolver *PublicResolverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _PublicResolver.Contract.contract.Transact(opts, method, params...) +} + +// ABI is a free data retrieval call binding the contract method 0x2203ab56. +// +// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) +func (_PublicResolver *PublicResolverCaller) ABI(opts *bind.CallOpts, node [32]byte, contentTypes *big.Int) (struct { + ContentType *big.Int + Data []byte +}, error) { + ret := new(struct { + ContentType *big.Int + Data []byte + }) + out := ret + err := _PublicResolver.contract.Call(opts, out, "ABI", node, contentTypes) + return *ret, err +} + +// ABI is a free data retrieval call binding the contract method 0x2203ab56. +// +// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) +func (_PublicResolver *PublicResolverSession) ABI(node [32]byte, contentTypes *big.Int) (struct { + ContentType *big.Int + Data []byte +}, error) { + return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) +} + +// ABI is a free data retrieval call binding the contract method 0x2203ab56. +// +// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) +func (_PublicResolver *PublicResolverCallerSession) ABI(node [32]byte, contentTypes *big.Int) (struct { + ContentType *big.Int + Data []byte +}, error) { + return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) +} + +// Addr is a free data retrieval call binding the contract method 0x3b3b57de. +// +// Solidity: function addr(node bytes32) constant returns(ret address) +func (_PublicResolver *PublicResolverCaller) Addr(opts *bind.CallOpts, node [32]byte) (common.Address, error) { + var ( + ret0 = new(common.Address) + ) + out := ret0 + err := _PublicResolver.contract.Call(opts, out, "addr", node) + return *ret0, err +} + +// Addr is a free data retrieval call binding the contract method 0x3b3b57de. +// +// Solidity: function addr(node bytes32) constant returns(ret address) +func (_PublicResolver *PublicResolverSession) Addr(node [32]byte) (common.Address, error) { + return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) +} + +// Addr is a free data retrieval call binding the contract method 0x3b3b57de. +// +// Solidity: function addr(node bytes32) constant returns(ret address) +func (_PublicResolver *PublicResolverCallerSession) Addr(node [32]byte) (common.Address, error) { + return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) +} + +// Content is a free data retrieval call binding the contract method 0x2dff6941. +// +// Solidity: function content(node bytes32) constant returns(ret bytes32) +func (_PublicResolver *PublicResolverCaller) Content(opts *bind.CallOpts, node [32]byte) ([32]byte, error) { + var ( + ret0 = new([32]byte) + ) + out := ret0 + err := _PublicResolver.contract.Call(opts, out, "content", node) + return *ret0, err +} + +// Content is a free data retrieval call binding the contract method 0x2dff6941. +// +// Solidity: function content(node bytes32) constant returns(ret bytes32) +func (_PublicResolver *PublicResolverSession) Content(node [32]byte) ([32]byte, error) { + return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node) +} + +// Content is a free data retrieval call binding the contract method 0x2dff6941. +// +// Solidity: function content(node bytes32) constant returns(ret bytes32) +func (_PublicResolver *PublicResolverCallerSession) Content(node [32]byte) ([32]byte, error) { + return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node) +} + +// Name is a free data retrieval call binding the contract method 0x691f3431. +// +// Solidity: function name(node bytes32) constant returns(ret string) +func (_PublicResolver *PublicResolverCaller) Name(opts *bind.CallOpts, node [32]byte) (string, error) { + var ( + ret0 = new(string) + ) + out := ret0 + err := _PublicResolver.contract.Call(opts, out, "name", node) + return *ret0, err +} + +// Name is a free data retrieval call binding the contract method 0x691f3431. +// +// Solidity: function name(node bytes32) constant returns(ret string) +func (_PublicResolver *PublicResolverSession) Name(node [32]byte) (string, error) { + return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) +} + +// Name is a free data retrieval call binding the contract method 0x691f3431. +// +// Solidity: function name(node bytes32) constant returns(ret string) +func (_PublicResolver *PublicResolverCallerSession) Name(node [32]byte) (string, error) { + return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) +} + +// Pubkey is a free data retrieval call binding the contract method 0xc8690233. +// +// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) +func (_PublicResolver *PublicResolverCaller) Pubkey(opts *bind.CallOpts, node [32]byte) (struct { + X [32]byte + Y [32]byte +}, error) { + ret := new(struct { + X [32]byte + Y [32]byte + }) + out := ret + err := _PublicResolver.contract.Call(opts, out, "pubkey", node) + return *ret, err +} + +// Pubkey is a free data retrieval call binding the contract method 0xc8690233. +// +// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) +func (_PublicResolver *PublicResolverSession) Pubkey(node [32]byte) (struct { + X [32]byte + Y [32]byte +}, error) { + return _PublicResolver.Contract.Pubkey(&_PublicResolver.CallOpts, node) +} + +// Pubkey is a free data retrieval call binding the contract method 0xc8690233. +// +// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) +func (_PublicResolver *PublicResolverCallerSession) Pubkey(node [32]byte) (struct { + X [32]byte + Y [32]byte +}, error) { + return _PublicResolver.Contract.Pubkey(&_PublicResolver.CallOpts, node) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) +func (_PublicResolver *PublicResolverCaller) SupportsInterface(opts *bind.CallOpts, interfaceID [4]byte) (bool, error) { + var ( + ret0 = new(bool) + ) + out := ret0 + err := _PublicResolver.contract.Call(opts, out, "supportsInterface", interfaceID) + return *ret0, err +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) +func (_PublicResolver *PublicResolverSession) SupportsInterface(interfaceID [4]byte) (bool, error) { + return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) +func (_PublicResolver *PublicResolverCallerSession) SupportsInterface(interfaceID [4]byte) (bool, error) { + return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) +} + +// Text is a free data retrieval call binding the contract method 0x59d1d43c. +// +// Solidity: function text(node bytes32, key string) constant returns(ret string) +func (_PublicResolver *PublicResolverCaller) Text(opts *bind.CallOpts, node [32]byte, key string) (string, error) { + var ( + ret0 = new(string) + ) + out := ret0 + err := _PublicResolver.contract.Call(opts, out, "text", node, key) + return *ret0, err +} + +// Text is a free data retrieval call binding the contract method 0x59d1d43c. +// +// Solidity: function text(node bytes32, key string) constant returns(ret string) +func (_PublicResolver *PublicResolverSession) Text(node [32]byte, key string) (string, error) { + return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) +} + +// Text is a free data retrieval call binding the contract method 0x59d1d43c. +// +// Solidity: function text(node bytes32, key string) constant returns(ret string) +func (_PublicResolver *PublicResolverCallerSession) Text(node [32]byte, key string) (string, error) { + return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) +} + +// SetABI is a paid mutator transaction binding the contract method 0x623195b0. +// +// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() +func (_PublicResolver *PublicResolverTransactor) SetABI(opts *bind.TransactOpts, node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setABI", node, contentType, data) +} + +// SetABI is a paid mutator transaction binding the contract method 0x623195b0. +// +// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() +func (_PublicResolver *PublicResolverSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) +} + +// SetABI is a paid mutator transaction binding the contract method 0x623195b0. +// +// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) +} + +// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. +// +// Solidity: function setAddr(node bytes32, addr address) returns() +func (_PublicResolver *PublicResolverTransactor) SetAddr(opts *bind.TransactOpts, node [32]byte, addr common.Address) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setAddr", node, addr) +} + +// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. +// +// Solidity: function setAddr(node bytes32, addr address) returns() +func (_PublicResolver *PublicResolverSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { + return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) +} + +// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. +// +// Solidity: function setAddr(node bytes32, addr address) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { + return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) +} + +// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. +// +// Solidity: function setContent(node bytes32, hash bytes32) returns() +func (_PublicResolver *PublicResolverTransactor) SetContent(opts *bind.TransactOpts, node [32]byte, hash [32]byte) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setContent", node, hash) +} + +// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. +// +// Solidity: function setContent(node bytes32, hash bytes32) returns() +func (_PublicResolver *PublicResolverSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash) +} + +// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. +// +// Solidity: function setContent(node bytes32, hash bytes32) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash) +} + +// SetName is a paid mutator transaction binding the contract method 0x77372213. +// +// Solidity: function setName(node bytes32, name string) returns() +func (_PublicResolver *PublicResolverTransactor) SetName(opts *bind.TransactOpts, node [32]byte, name string) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setName", node, name) +} + +// SetName is a paid mutator transaction binding the contract method 0x77372213. +// +// Solidity: function setName(node bytes32, name string) returns() +func (_PublicResolver *PublicResolverSession) SetName(node [32]byte, name string) (*types.Transaction, error) { + return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) +} + +// SetName is a paid mutator transaction binding the contract method 0x77372213. +// +// Solidity: function setName(node bytes32, name string) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetName(node [32]byte, name string) (*types.Transaction, error) { + return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) +} + +// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. +// +// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() +func (_PublicResolver *PublicResolverTransactor) SetPubkey(opts *bind.TransactOpts, node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setPubkey", node, x, y) +} + +// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. +// +// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() +func (_PublicResolver *PublicResolverSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) +} + +// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. +// +// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { + return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) +} + +// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. +// +// Solidity: function setText(node bytes32, key string, value string) returns() +func (_PublicResolver *PublicResolverTransactor) SetText(opts *bind.TransactOpts, node [32]byte, key string, value string) (*types.Transaction, error) { + return _PublicResolver.contract.Transact(opts, "setText", node, key, value) +} + +// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. +// +// Solidity: function setText(node bytes32, key string, value string) returns() +func (_PublicResolver *PublicResolverSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { + return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) +} + +// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. +// +// Solidity: function setText(node bytes32, key string, value string) returns() +func (_PublicResolver *PublicResolverTransactorSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { + return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) +} + +// PublicResolverABIChangedIterator is returned from FilterABIChanged and is used to iterate over the raw logs and unpacked data for ABIChanged events raised by the PublicResolver contract. +type PublicResolverABIChangedIterator struct { + Event *PublicResolverABIChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *PublicResolverABIChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(PublicResolverABIChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(PublicResolverABIChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error retruned any retrieval or parsing error occurred during filtering. +func (it *PublicResolverABIChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *PublicResolverABIChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// PublicResolverABIChanged represents a ABIChanged event raised by the PublicResolver contract. +type PublicResolverABIChanged struct { + Node [32]byte + ContentType *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterABIChanged is a free log retrieval operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. +// +// Solidity: event ABIChanged(node indexed bytes32, contentType indexed uint256) +func (_PublicResolver *PublicResolverFilterer) FilterABIChanged(opts *bind.FilterOpts, node [][32]byte, contentType []*big.Int) (*PublicResolverABIChangedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + var contentTypeRule []interface{} + for _, contentTypeItem := range contentType { + contentTypeRule = append(contentTypeRule, contentTypeItem) + } + + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ABIChanged", nodeRule, contentTypeRule) + if err != nil { + return nil, err + } + return &PublicResolverABIChangedIterator{contract: _PublicResolver.contract, event: "ABIChanged", logs: logs, sub: sub}, nil +} + +// WatchABIChanged is a free log subscription operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. +// +// Solidity: event ABIChanged(node indexed bytes32, contentType indexed uint256) +func (_PublicResolver *PublicResolverFilterer) WatchABIChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverABIChanged, node [][32]byte, contentType []*big.Int) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + var contentTypeRule []interface{} + for _, contentTypeItem := range contentType { + contentTypeRule = append(contentTypeRule, contentTypeItem) + } + + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ABIChanged", nodeRule, contentTypeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(PublicResolverABIChanged) + if err := _PublicResolver.contract.UnpackLog(event, "ABIChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// PublicResolverAddrChangedIterator is returned from FilterAddrChanged and is used to iterate over the raw logs and unpacked data for AddrChanged events raised by the PublicResolver contract. +type PublicResolverAddrChangedIterator struct { + Event *PublicResolverAddrChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *PublicResolverAddrChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(PublicResolverAddrChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(PublicResolverAddrChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error retruned any retrieval or parsing error occurred during filtering. +func (it *PublicResolverAddrChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *PublicResolverAddrChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// PublicResolverAddrChanged represents a AddrChanged event raised by the PublicResolver contract. +type PublicResolverAddrChanged struct { + Node [32]byte + A common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterAddrChanged is a free log retrieval operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. +// +// Solidity: event AddrChanged(node indexed bytes32, a address) +func (_PublicResolver *PublicResolverFilterer) FilterAddrChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverAddrChangedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "AddrChanged", nodeRule) + if err != nil { + return nil, err + } + return &PublicResolverAddrChangedIterator{contract: _PublicResolver.contract, event: "AddrChanged", logs: logs, sub: sub}, nil +} + +// WatchAddrChanged is a free log subscription operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. +// +// Solidity: event AddrChanged(node indexed bytes32, a address) +func (_PublicResolver *PublicResolverFilterer) WatchAddrChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverAddrChanged, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "AddrChanged", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(PublicResolverAddrChanged) + if err := _PublicResolver.contract.UnpackLog(event, "AddrChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// PublicResolverContentChangedIterator is returned from FilterContentChanged and is used to iterate over the raw logs and unpacked data for ContentChanged events raised by the PublicResolver contract. +type PublicResolverContentChangedIterator struct { + Event *PublicResolverContentChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *PublicResolverContentChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(PublicResolverContentChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(PublicResolverContentChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error retruned any retrieval or parsing error occurred during filtering. +func (it *PublicResolverContentChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *PublicResolverContentChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// PublicResolverContentChanged represents a ContentChanged event raised by the PublicResolver contract. +type PublicResolverContentChanged struct { + Node [32]byte + Hash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterContentChanged is a free log retrieval operation binding the contract event 0x0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc. +// +// Solidity: event ContentChanged(node indexed bytes32, hash bytes32) +func (_PublicResolver *PublicResolverFilterer) FilterContentChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverContentChangedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ContentChanged", nodeRule) + if err != nil { + return nil, err + } + return &PublicResolverContentChangedIterator{contract: _PublicResolver.contract, event: "ContentChanged", logs: logs, sub: sub}, nil +} + +// WatchContentChanged is a free log subscription operation binding the contract event 0x0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc. +// +// Solidity: event ContentChanged(node indexed bytes32, hash bytes32) +func (_PublicResolver *PublicResolverFilterer) WatchContentChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverContentChanged, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ContentChanged", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(PublicResolverContentChanged) + if err := _PublicResolver.contract.UnpackLog(event, "ContentChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// PublicResolverNameChangedIterator is returned from FilterNameChanged and is used to iterate over the raw logs and unpacked data for NameChanged events raised by the PublicResolver contract. +type PublicResolverNameChangedIterator struct { + Event *PublicResolverNameChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *PublicResolverNameChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(PublicResolverNameChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(PublicResolverNameChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error retruned any retrieval or parsing error occurred during filtering. +func (it *PublicResolverNameChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *PublicResolverNameChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// PublicResolverNameChanged represents a NameChanged event raised by the PublicResolver contract. +type PublicResolverNameChanged struct { + Node [32]byte + Name string + Raw types.Log // Blockchain specific contextual infos +} + +// FilterNameChanged is a free log retrieval operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. +// +// Solidity: event NameChanged(node indexed bytes32, name string) +func (_PublicResolver *PublicResolverFilterer) FilterNameChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverNameChangedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "NameChanged", nodeRule) + if err != nil { + return nil, err + } + return &PublicResolverNameChangedIterator{contract: _PublicResolver.contract, event: "NameChanged", logs: logs, sub: sub}, nil +} + +// WatchNameChanged is a free log subscription operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. +// +// Solidity: event NameChanged(node indexed bytes32, name string) +func (_PublicResolver *PublicResolverFilterer) WatchNameChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverNameChanged, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "NameChanged", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(PublicResolverNameChanged) + if err := _PublicResolver.contract.UnpackLog(event, "NameChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// PublicResolverPubkeyChangedIterator is returned from FilterPubkeyChanged and is used to iterate over the raw logs and unpacked data for PubkeyChanged events raised by the PublicResolver contract. +type PublicResolverPubkeyChangedIterator struct { + Event *PublicResolverPubkeyChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *PublicResolverPubkeyChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(PublicResolverPubkeyChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(PublicResolverPubkeyChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error retruned any retrieval or parsing error occurred during filtering. +func (it *PublicResolverPubkeyChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *PublicResolverPubkeyChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// PublicResolverPubkeyChanged represents a PubkeyChanged event raised by the PublicResolver contract. +type PublicResolverPubkeyChanged struct { + Node [32]byte + X [32]byte + Y [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterPubkeyChanged is a free log retrieval operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. +// +// Solidity: event PubkeyChanged(node indexed bytes32, x bytes32, y bytes32) +func (_PublicResolver *PublicResolverFilterer) FilterPubkeyChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverPubkeyChangedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "PubkeyChanged", nodeRule) + if err != nil { + return nil, err + } + return &PublicResolverPubkeyChangedIterator{contract: _PublicResolver.contract, event: "PubkeyChanged", logs: logs, sub: sub}, nil +} + +// WatchPubkeyChanged is a free log subscription operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. +// +// Solidity: event PubkeyChanged(node indexed bytes32, x bytes32, y bytes32) +func (_PublicResolver *PublicResolverFilterer) WatchPubkeyChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverPubkeyChanged, node [][32]byte) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "PubkeyChanged", nodeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(PublicResolverPubkeyChanged) + if err := _PublicResolver.contract.UnpackLog(event, "PubkeyChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// PublicResolverTextChangedIterator is returned from FilterTextChanged and is used to iterate over the raw logs and unpacked data for TextChanged events raised by the PublicResolver contract. +type PublicResolverTextChangedIterator struct { + Event *PublicResolverTextChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *PublicResolverTextChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(PublicResolverTextChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(PublicResolverTextChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error retruned any retrieval or parsing error occurred during filtering. +func (it *PublicResolverTextChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *PublicResolverTextChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// PublicResolverTextChanged represents a TextChanged event raised by the PublicResolver contract. +type PublicResolverTextChanged struct { + Node [32]byte + IndexedKey common.Hash + Key string + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTextChanged is a free log retrieval operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. +// +// Solidity: event TextChanged(node indexed bytes32, indexedKey indexed string, key string) +func (_PublicResolver *PublicResolverFilterer) FilterTextChanged(opts *bind.FilterOpts, node [][32]byte, indexedKey []string) (*PublicResolverTextChangedIterator, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + var indexedKeyRule []interface{} + for _, indexedKeyItem := range indexedKey { + indexedKeyRule = append(indexedKeyRule, indexedKeyItem) + } + + logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "TextChanged", nodeRule, indexedKeyRule) + if err != nil { + return nil, err + } + return &PublicResolverTextChangedIterator{contract: _PublicResolver.contract, event: "TextChanged", logs: logs, sub: sub}, nil +} + +// WatchTextChanged is a free log subscription operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. +// +// Solidity: event TextChanged(node indexed bytes32, indexedKey indexed string, key string) +func (_PublicResolver *PublicResolverFilterer) WatchTextChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverTextChanged, node [][32]byte, indexedKey []string) (event.Subscription, error) { + + var nodeRule []interface{} + for _, nodeItem := range node { + nodeRule = append(nodeRule, nodeItem) + } + var indexedKeyRule []interface{} + for _, indexedKeyItem := range indexedKey { + indexedKeyRule = append(indexedKeyRule, indexedKeyItem) + } + + logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "TextChanged", nodeRule, indexedKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(PublicResolverTextChanged) + if err := _PublicResolver.contract.UnpackLog(event, "TextChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/asm/lex_test.go b/vendor/github.com/ethereum/go-ethereum/core/asm/lex_test.go index e6901d4e..16e0ad45 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/asm/lex_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/asm/lex_test.go @@ -22,7 +22,7 @@ import ( ) func lexAll(src string) []token { - ch := Lex("test.asm", []byte(src), false) + ch := Lex([]byte(src), false) var tokens []token for i := range ch { diff --git a/vendor/github.com/ethereum/go-ethereum/core/asm/lexer.go b/vendor/github.com/ethereum/go-ethereum/core/asm/lexer.go index 91caeb27..00526242 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/asm/lexer.go +++ b/vendor/github.com/ethereum/go-ethereum/core/asm/lexer.go @@ -95,7 +95,7 @@ type lexer struct { // lex lexes the program by name with the given source. It returns a // channel on which the tokens are delivered. -func Lex(name string, source []byte, debug bool) <-chan token { +func Lex(source []byte, debug bool) <-chan token { ch := make(chan token) l := &lexer{ input: string(source), diff --git a/vendor/github.com/ethereum/go-ethereum/core/bench_test.go b/vendor/github.com/ethereum/go-ethereum/core/bench_test.go index 53cba051..e0ccef78 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/bench_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/bench_test.go @@ -150,14 +150,14 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Create the database in memory or in a temporary directory. var db ethdb.Database if !disk { - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() } else { dir, err := ioutil.TempDir("", "eth-core-bench") if err != nil { b.Fatalf("cannot create temporary directory: %v", err) } defer os.RemoveAll(dir) - db, err = ethdb.NewLDBDatabase(dir, 128, 128) + db, err = rawdb.NewLevelDBDatabase(dir, 128, 128, "") if err != nil { b.Fatalf("cannot create temporary database: %v", err) } @@ -255,7 +255,7 @@ func benchWriteChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("cannot create temporary directory: %v", err) } - db, err := ethdb.NewLDBDatabase(dir, 128, 1024) + db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "") if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } @@ -272,7 +272,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { } defer os.RemoveAll(dir) - db, err := ethdb.NewLDBDatabase(dir, 128, 1024) + db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "") if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } @@ -283,7 +283,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { b.ResetTimer() for i := 0; i < b.N; i++ { - db, err := ethdb.NewLDBDatabase(dir, 128, 1024) + db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "") if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } diff --git a/vendor/github.com/ethereum/go-ethereum/core/block_validator.go b/vendor/github.com/ethereum/go-ethereum/core/block_validator.go index 3b9496fe..b36ca56d 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/block_validator.go +++ b/vendor/github.com/ethereum/go-ethereum/core/block_validator.go @@ -77,7 +77,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // transition, such as amount of used gas, the receipt roots and the state root // itself. ValidateState returns a database batch if the validation was a success // otherwise nil and an error is returned. -func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) diff --git a/vendor/github.com/ethereum/go-ethereum/core/block_validator_test.go b/vendor/github.com/ethereum/go-ethereum/core/block_validator_test.go index 9319a783..06e2ba1a 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/block_validator_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/block_validator_test.go @@ -22,9 +22,9 @@ import ( "time" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -32,7 +32,7 @@ import ( func TestHeaderVerification(t *testing.T) { // Create a simple chain to verify var ( - testdb = ethdb.NewMemDatabase() + testdb = rawdb.NewMemoryDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) @@ -84,7 +84,7 @@ func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVeri func testHeaderConcurrentVerification(t *testing.T, threads int) { // Create a simple chain to verify var ( - testdb = ethdb.NewMemDatabase() + testdb = rawdb.NewMemoryDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) @@ -156,7 +156,7 @@ func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion func testHeaderConcurrentAbortion(t *testing.T, threads int) { // Create a simple chain to verify var ( - testdb = ethdb.NewMemDatabase() + testdb = rawdb.NewMemoryDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil) diff --git a/vendor/github.com/ethereum/go-ethereum/core/blockchain.go b/vendor/github.com/ethereum/go-ethereum/core/blockchain.go index 26ac75b8..745f67d8 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/blockchain.go +++ b/vendor/github.com/ethereum/go-ethereum/core/blockchain.go @@ -43,11 +43,24 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru" ) var ( - blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil) + accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil) + accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil) + accountUpdateTimer = metrics.NewRegisteredTimer("chain/account/updates", nil) + accountCommitTimer = metrics.NewRegisteredTimer("chain/account/commits", nil) + + storageReadTimer = metrics.NewRegisteredTimer("chain/storage/reads", nil) + storageHashTimer = metrics.NewRegisteredTimer("chain/storage/hashes", nil) + storageUpdateTimer = metrics.NewRegisteredTimer("chain/storage/updates", nil) + storageCommitTimer = metrics.NewRegisteredTimer("chain/storage/commits", nil) + + blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil) + blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil) + blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) + blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil) ErrNoGenesis = errors.New("Genesis not found in chain") ) @@ -62,15 +75,22 @@ const ( triesInMemory = 128 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. - BlockChainVersion = 3 + // + // During the process of upgrading the database version from 3 to 4, + // the following incompatible database changes were added. + // * the `BlockNumber`, `TxHash`, `TxIndex`, `BlockHash` and `Index` fields of log are deleted + // * the `Bloom` field of receipt is deleted + // * the `BlockIndex` and `TxIndex` fields of txlookup are deleted + BlockChainVersion uint64 = 4 ) // CacheConfig contains the configuration values for the trie caching/pruning // that's resident in a blockchain. type CacheConfig struct { - Disabled bool // Whether to disable trie write caching (archive node) - TrieNodeLimit int // Memory limit (MB) at which to flush the current in-memory trie to disk - TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk + Disabled bool // Whether to disable trie write caching (archive node) + TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory + TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk + TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk } // BlockChain represents the canonical chain given a database with a genesis @@ -101,10 +121,10 @@ type BlockChain struct { chainSideFeed event.Feed chainHeadFeed event.Feed logsFeed event.Feed + blockProcFeed event.Feed scope event.SubscriptionScope genesisBlock *types.Block - mu sync.RWMutex // global mutex for locking chain operations chainmu sync.RWMutex // blockchain insertion lock procmu sync.RWMutex // block processor lock @@ -140,8 +160,9 @@ type BlockChain struct { func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = &CacheConfig{ - TrieNodeLimit: 256, - TrieTimeLimit: 5 * time.Minute, + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, } } bodyCache, _ := lru.New(bodyCacheLimit) @@ -156,7 +177,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par cacheConfig: cacheConfig, db: db, triegc: prque.New(nil), - stateCache: state.NewDatabase(db), + stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit), quit: make(chan struct{}), shouldPreserve: shouldPreserve, bodyCache: bodyCache, @@ -205,6 +226,11 @@ func (bc *BlockChain) getProcInterrupt() bool { return atomic.LoadInt32(&bc.procInterrupt) == 1 } +// GetVMConfig returns the block chain VM config. +func (bc *BlockChain) GetVMConfig() *vm.Config { + return &bc.vmConfig +} + // loadLastState loads the last known chain state from the database. This method // assumes that the chain manager mutex is held. func (bc *BlockChain) loadLastState() error { @@ -271,11 +297,11 @@ func (bc *BlockChain) loadLastState() error { func (bc *BlockChain) SetHead(head uint64) error { log.Warn("Rewinding blockchain", "target", head) - bc.mu.Lock() - defer bc.mu.Unlock() + bc.chainmu.Lock() + defer bc.chainmu.Unlock() // Rewind the header chain, deleting all block bodies until then - delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) { + delFn := func(db ethdb.Writer, hash common.Hash, num uint64) { rawdb.DeleteBody(db, hash, num) } bc.hc.SetHead(head, delFn) @@ -326,13 +352,13 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error { if block == nil { return fmt.Errorf("non existent block [%x…]", hash[:4]) } - if _, err := trie.NewSecure(block.Root(), bc.stateCache.TrieDB(), 0); err != nil { + if _, err := trie.NewSecure(block.Root(), bc.stateCache.TrieDB()); err != nil { return err } // If all checks out, manually set the head block - bc.mu.Lock() + bc.chainmu.Lock() bc.currentBlock.Store(block) - bc.mu.Unlock() + bc.chainmu.Unlock() log.Info("Committed new head block", "number", block.Number(), "hash", hash) return nil @@ -393,6 +419,11 @@ func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { return state.New(root, bc.stateCache) } +// StateCache returns the caching database underpinning the blockchain instance. +func (bc *BlockChain) StateCache() state.Database { + return bc.stateCache +} + // Reset purges the entire blockchain, restoring it to its genesis state. func (bc *BlockChain) Reset() error { return bc.ResetWithGenesisBlock(bc.genesisBlock) @@ -405,8 +436,8 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { if err := bc.SetHead(0); err != nil { return err } - bc.mu.Lock() - defer bc.mu.Unlock() + bc.chainmu.Lock() + defer bc.chainmu.Unlock() // Prepare the genesis block and reinitialise the chain if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { @@ -438,7 +469,11 @@ func (bc *BlockChain) repair(head **types.Block) error { return nil } // Otherwise rewind one block and recheck state availability there - (*head) = bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1) + block := bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1) + if block == nil { + return fmt.Errorf("missing block %d [%x]", (*head).NumberU64()-1, (*head).ParentHash()) + } + *head = block } } @@ -449,8 +484,8 @@ func (bc *BlockChain) Export(w io.Writer) error { // ExportN writes a subset of the active chain to the given writer. func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { - bc.mu.RLock() - defer bc.mu.RUnlock() + bc.chainmu.RLock() + defer bc.chainmu.RUnlock() if first > last { return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last) @@ -471,7 +506,6 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { reported = time.Now() } } - return nil } @@ -554,6 +588,17 @@ func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool { return rawdb.HasBody(bc.db, hash, number) } +// HasFastBlock checks if a fast block is fully present in the database or not. +func (bc *BlockChain) HasFastBlock(hash common.Hash, number uint64) bool { + if !bc.HasBlock(hash, number) { + return false + } + if bc.receiptsCache.Contains(hash) { + return true + } + return rawdb.HasReceipts(bc.db, hash, number) +} + // HasState checks if state trie is fully present in the database or not. func (bc *BlockChain) HasState(hash common.Hash) bool { _, err := bc.stateCache.OpenTrie(hash) @@ -611,13 +656,14 @@ func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { if receipts, ok := bc.receiptsCache.Get(hash); ok { return receipts.(types.Receipts) } - number := rawdb.ReadHeaderNumber(bc.db, hash) if number == nil { return nil } - receipts := rawdb.ReadReceipts(bc.db, hash, *number) + if receipts == nil { + return nil + } bc.receiptsCache.Add(hash, receipts) return receipts } @@ -728,8 +774,8 @@ const ( // Rollback is designed to remove a chain of links from the database that aren't // certain enough to be valid. func (bc *BlockChain) Rollback(chain []common.Hash) { - bc.mu.Lock() - defer bc.mu.Unlock() + bc.chainmu.Lock() + defer bc.chainmu.Unlock() for i := len(chain) - 1; i >= 0; i-- { hash := chain[i] @@ -764,6 +810,11 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty // The transaction hash can be retrieved from the transaction itself receipts[j].TxHash = transactions[j].Hash() + // block location fields + receipts[j].BlockHash = block.Hash() + receipts[j].BlockNumber = block.Number() + receipts[j].TransactionIndex = uint(j) + // The contract address can be derived from the transaction itself if transactions[j].To() == nil { // Deriving the signer is expensive, only do if it's actually needed @@ -853,7 +904,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } // Update the head fast sync block if better - bc.mu.Lock() + bc.chainmu.Lock() head := blockChain[len(blockChain)-1] if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case currentFastBlock := bc.CurrentFastBlock() @@ -862,7 +913,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ bc.currentFastBlock.Store(head) } } - bc.mu.Unlock() + bc.chainmu.Unlock() context := []interface{}{ "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), @@ -896,6 +947,15 @@ func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (e // WriteBlockWithState writes the block and all associated state to the database. func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { + bc.chainmu.Lock() + defer bc.chainmu.Unlock() + + return bc.writeBlockWithState(block, receipts, state) +} + +// writeBlockWithState writes the block and all associated state to the database, +// but is expects the chain mutex to be held. +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { bc.wg.Add(1) defer bc.wg.Done() @@ -905,9 +965,6 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. return NonStatTy, consensus.ErrUnknownAncestor } // Make sure no inconsistent state is leaked during insertion - bc.mu.Lock() - defer bc.mu.Unlock() - currentBlock := bc.CurrentBlock() localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) externTd := new(big.Int).Add(block.Difficulty(), ptd) @@ -938,26 +995,32 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( nodes, imgs = triedb.Size() - limit = common.StorageSize(bc.cacheConfig.TrieNodeLimit) * 1024 * 1024 + limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 ) if nodes > limit || imgs > 4*1024*1024 { triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit - header := bc.GetHeaderByNumber(current - triesInMemory) - chosen := header.Number.Uint64() + chosen := current - triesInMemory // If we exceeded out time allowance, flush an entire trie to disk if bc.gcproc > bc.cacheConfig.TrieTimeLimit { - // If we're exceeding limits but haven't reached a large enough memory gap, - // warn the user that the system is becoming unstable. - if chosen < lastWrite+triesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { - log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory) + // If the header is missing (canonical chain behind), we're reorging a low + // diff sidechain. Suspend committing until this operation is completed. + header := bc.GetHeaderByNumber(chosen) + if header == nil { + log.Warn("Reorg in progress, trie commit postponed", "number", chosen) + } else { + // If we're exceeding limits but haven't reached a large enough memory gap, + // warn the user that the system is becoming unstable. + if chosen < lastWrite+triesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { + log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory) + } + // Flush an entire trie and restart the counters + triedb.Commit(header.Root, true) + lastWrite = chosen + bc.gcproc = 0 } - // Flush an entire trie and restart the counters - triedb.Commit(header.Root, true) - lastWrite = chosen - bc.gcproc = 0 } // Garbage collect anything below our required write retention for !bc.triegc.Empty() { @@ -1020,6 +1083,18 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. return status, nil } +// addFutureBlock checks if the block is within the max allowed window to get +// accepted for future processing, and returns an error if the block is too far +// ahead and was not added. +func (bc *BlockChain) addFutureBlock(block *types.Block) error { + max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks) + if block.Time().Cmp(max) > 0 { + return fmt.Errorf("future block timestamp %v > allowed %v", block.Time(), max) + } + bc.futureBlocks.Add(block.Hash(), block) + return nil +} + // InsertChain attempts to insert the given batch of blocks in to the canonical // chain or, otherwise, create a fork. If an error is returned it will return // the index number of the failing block as well an error describing what went @@ -1027,36 +1102,57 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. // // After insertion is done, all accumulated events will be fired. func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { - n, events, logs, err := bc.insertChain(chain) - bc.PostChainEvents(events, logs) - return n, err -} - -// insertChain will execute the actual chain insertion and event aggregation. The -// only reason this method exists as a separate one is to make locking cleaner -// with deferred statements. -func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*types.Log, error) { // Sanity check that we have something meaningful to import if len(chain) == 0 { - return 0, nil, nil, nil + return 0, nil } + + bc.blockProcFeed.Send(true) + defer bc.blockProcFeed.Send(false) + + // Remove already known canon-blocks + var ( + block, prev *types.Block + ) // Do a sanity check that the provided chain is actually ordered and linked for i := 1; i < len(chain); i++ { - if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() { + block = chain[i] + prev = chain[i-1] + if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() { // Chain broke ancestry, log a message (programming error) and skip insertion - log.Error("Non contiguous block insert", "number", chain[i].Number(), "hash", chain[i].Hash(), - "parent", chain[i].ParentHash(), "prevnumber", chain[i-1].Number(), "prevhash", chain[i-1].Hash()) + log.Error("Non contiguous block insert", "number", block.Number(), "hash", block.Hash(), + "parent", block.ParentHash(), "prevnumber", prev.Number(), "prevhash", prev.Hash()) - return 0, nil, nil, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].NumberU64(), - chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4]) + return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, prev.NumberU64(), + prev.Hash().Bytes()[:4], i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4]) } } // Pre-checks passed, start the full block imports bc.wg.Add(1) - defer bc.wg.Done() - bc.chainmu.Lock() - defer bc.chainmu.Unlock() + n, events, logs, err := bc.insertChain(chain, true) + bc.chainmu.Unlock() + bc.wg.Done() + + bc.PostChainEvents(events, logs) + return n, err +} + +// insertChain is the internal implementation of insertChain, which assumes that +// 1) chains are contiguous, and 2) The chain mutex is held. +// +// This method is split out so that import batches that require re-injecting +// historical blocks can do so without releasing the lock, which could lead to +// racey behaviour. If a sidechain import is in progress, and the historic state +// is imported, but then new canon-head is added before the actual sidechain +// completes, then the historic state could be pruned again +func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []interface{}, []*types.Log, error) { + // If the chain is terminating, don't even bother starting u + if atomic.LoadInt32(&bc.procInterrupt) == 1 { + return 0, nil, nil, nil + } + // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) + senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) // A queued approach to delivering events. This is generally // faster than direct delivery and requires much less mutex @@ -1073,16 +1169,58 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty for i, block := range chain { headers[i] = block.Header() - seals[i] = true + seals[i] = verifySeals } abort, results := bc.engine.VerifyHeaders(bc, headers, seals) defer close(abort) - // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) - senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) + // Peek the error for the first block to decide the directing import logic + it := newInsertIterator(chain, results, bc.Validator()) - // Iterate over the blocks and insert when the verifier permits - for i, block := range chain { + block, err := it.next() + + // Left-trim all the known blocks + if err == ErrKnownBlock { + // First block (and state) is known + // 1. We did a roll-back, and should now do a re-import + // 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot + // from the canonical chain, which has not been verified. + // Skip all known blocks that are behind us + current := bc.CurrentBlock().NumberU64() + for block != nil && err == ErrKnownBlock && current >= block.NumberU64() { + stats.ignored++ + block, err = it.next() + } + // Falls through to the block import + } + + switch { + // First block is pruned, insert as sidechain and reorg only if TD grows enough + case err == consensus.ErrPrunedAncestor: + return bc.insertSidechain(block, it) + + // First block is future, shove it (and all children) to the future queue (unknown ancestor) + case err == consensus.ErrFutureBlock || (err == consensus.ErrUnknownAncestor && bc.futureBlocks.Contains(it.first().ParentHash())): + for block != nil && (it.index == 0 || err == consensus.ErrUnknownAncestor) { + if err := bc.addFutureBlock(block); err != nil { + return it.index, events, coalescedLogs, err + } + block, err = it.next() + } + stats.queued += it.processed() + stats.ignored += it.remaining() + + // If there are any still remaining, mark as ignored + return it.index, events, coalescedLogs, err + + // Some other error occurred, abort + case err != nil: + stats.ignored += len(it.chain) + bc.reportBlock(block, nil, err) + return it.index, events, coalescedLogs, err + } + // No validation errors for the first block (or chain prefix skipped) + for ; block != nil && err == nil; block, err = it.next() { // If the chain is terminating, stop processing blocks if atomic.LoadInt32(&bc.procInterrupt) == 1 { log.Debug("Premature abort during blocks processing") @@ -1091,115 +1229,73 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty // If the header is a banned one, straight out abort if BadHashes[block.Hash()] { bc.reportBlock(block, nil, ErrBlacklistedHash) - return i, events, coalescedLogs, ErrBlacklistedHash + return it.index, events, coalescedLogs, ErrBlacklistedHash } - // Wait for the block's verification to complete - bstart := time.Now() + // Retrieve the parent block and it's state to execute on top + start := time.Now() - err := <-results - if err == nil { - err = bc.Validator().ValidateBody(block) + parent := it.previous() + if parent == nil { + parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) } - switch { - case err == ErrKnownBlock: - // Block and state both already known. However if the current block is below - // this number we did a rollback and we should reimport it nonetheless. - if bc.CurrentBlock().NumberU64() >= block.NumberU64() { - stats.ignored++ - continue - } - - case err == consensus.ErrFutureBlock: - // Allow up to MaxFuture second in the future blocks. If this limit is exceeded - // the chain is discarded and processed at a later time if given. - max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks) - if block.Time().Cmp(max) > 0 { - return i, events, coalescedLogs, fmt.Errorf("future block: %v > %v", block.Time(), max) - } - bc.futureBlocks.Add(block.Hash(), block) - stats.queued++ - continue - - case err == consensus.ErrUnknownAncestor && bc.futureBlocks.Contains(block.ParentHash()): - bc.futureBlocks.Add(block.Hash(), block) - stats.queued++ - continue - - case err == consensus.ErrPrunedAncestor: - // Block competing with the canonical chain, store in the db, but don't process - // until the competitor TD goes above the canonical TD - currentBlock := bc.CurrentBlock() - localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) - externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty()) - if localTd.Cmp(externTd) > 0 { - if err = bc.WriteBlockWithoutState(block, externTd); err != nil { - return i, events, coalescedLogs, err - } - continue - } - // Competitor chain beat canonical, gather all blocks from the common ancestor - var winner []*types.Block - - parent := bc.GetBlock(block.ParentHash(), block.NumberU64()-1) - for !bc.HasState(parent.Root()) { - winner = append(winner, parent) - parent = bc.GetBlock(parent.ParentHash(), parent.NumberU64()-1) - } - for j := 0; j < len(winner)/2; j++ { - winner[j], winner[len(winner)-1-j] = winner[len(winner)-1-j], winner[j] - } - // Import all the pruned blocks to make the state available - bc.chainmu.Unlock() - _, evs, logs, err := bc.insertChain(winner) - bc.chainmu.Lock() - events, coalescedLogs = evs, logs - - if err != nil { - return i, events, coalescedLogs, err - } - - case err != nil: - bc.reportBlock(block, nil, err) - return i, events, coalescedLogs, err - } - // Create a new statedb using the parent block and report an - // error if it fails. - var parent *types.Block - if i == 0 { - parent = bc.GetBlock(block.ParentHash(), block.NumberU64()-1) - } else { - parent = chain[i-1] - } - state, err := state.New(parent.Root(), bc.stateCache) + state, err := state.New(parent.Root, bc.stateCache) if err != nil { - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } // Process block using the parent state as reference point. + substart := time.Now() receipts, logs, usedGas, err := bc.processor.Process(block, state, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } + // Update the metrics touched during block processing + accountReadTimer.Update(state.AccountReads) // Account reads are complete, we can mark them + storageReadTimer.Update(state.StorageReads) // Storage reads are complete, we can mark them + accountUpdateTimer.Update(state.AccountUpdates) // Account updates are complete, we can mark them + storageUpdateTimer.Update(state.StorageUpdates) // Storage updates are complete, we can mark them + + triehash := state.AccountHashes + state.StorageHashes // Save to not double count in validation + trieproc := state.AccountReads + state.AccountUpdates + trieproc += state.StorageReads + state.StorageUpdates + + blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash) + // Validate the state using the default validator - err = bc.Validator().ValidateState(block, parent, state, receipts, usedGas) - if err != nil { + substart = time.Now() + if err := bc.Validator().ValidateState(block, state, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } - proctime := time.Since(bstart) + proctime := time.Since(start) + + // Update the metrics touched during block validation + accountHashTimer.Update(state.AccountHashes) // Account hashes are complete, we can mark them + storageHashTimer.Update(state.StorageHashes) // Storage hashes are complete, we can mark them + + blockValidationTimer.Update(time.Since(substart) - (state.AccountHashes + state.StorageHashes - triehash)) // Write the block to the chain and get the status. - status, err := bc.WriteBlockWithState(block, receipts, state) + substart = time.Now() + status, err := bc.writeBlockWithState(block, receipts, state) if err != nil { - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } + // Update the metrics touched during block commit + accountCommitTimer.Update(state.AccountCommits) // Account commits are complete, we can mark them + storageCommitTimer.Update(state.StorageCommits) // Storage commits are complete, we can mark them + + blockWriteTimer.Update(time.Since(substart) - state.AccountCommits - state.StorageCommits) + blockInsertTimer.UpdateSince(start) + switch status { case CanonStatTy: - log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(bstart))) + log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), + "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), + "elapsed", common.PrettyDuration(time.Since(start)), + "root", block.Root()) coalescedLogs = append(coalescedLogs, logs...) - blockInsertTimer.UpdateSince(bstart) events = append(events, ChainEvent{block, block.Hash(), logs}) lastCanon = block @@ -1207,78 +1303,157 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty bc.gcproc += proctime case SideStatTy: - log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed", - common.PrettyDuration(time.Since(bstart)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles())) - - blockInsertTimer.UpdateSince(bstart) + log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), + "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), + "root", block.Root()) events = append(events, ChainSideEvent{block}) } stats.processed++ stats.usedGas += usedGas - cache, _ := bc.stateCache.TrieDB().Size() - stats.report(chain, i, cache) + dirty, _ := bc.stateCache.TrieDB().Size() + stats.report(chain, it.index, dirty) } + // Any blocks remaining here? The only ones we care about are the future ones + if block != nil && err == consensus.ErrFutureBlock { + if err := bc.addFutureBlock(block); err != nil { + return it.index, events, coalescedLogs, err + } + block, err = it.next() + + for ; block != nil && err == consensus.ErrUnknownAncestor; block, err = it.next() { + if err := bc.addFutureBlock(block); err != nil { + return it.index, events, coalescedLogs, err + } + stats.queued++ + } + } + stats.ignored += it.remaining() + // Append a single chain head event if we've progressed the chain if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() { events = append(events, ChainHeadEvent{lastCanon}) } - return 0, events, coalescedLogs, nil + return it.index, events, coalescedLogs, err } -// insertStats tracks and reports on block insertion. -type insertStats struct { - queued, processed, ignored int - usedGas uint64 - lastIndex int - startTime mclock.AbsTime -} - -// statsReportLimit is the time limit during import and export after which we -// always print out progress. This avoids the user wondering what's going on. -const statsReportLimit = 8 * time.Second - -// report prints statistics if some number of blocks have been processed -// or more than a few seconds have passed since the last message. -func (st *insertStats) report(chain []*types.Block, index int, cache common.StorageSize) { - // Fetch the timings for the batch +// insertSidechain is called when an import batch hits upon a pruned ancestor +// error, which happens when a sidechain with a sufficiently old fork-block is +// found. +// +// The method writes all (header-and-body-valid) blocks to disk, then tries to +// switch over to the new chain if the TD exceeded the current chain. +func (bc *BlockChain) insertSidechain(block *types.Block, it *insertIterator) (int, []interface{}, []*types.Log, error) { var ( - now = mclock.Now() - elapsed = time.Duration(now) - time.Duration(st.startTime) + externTd *big.Int + current = bc.CurrentBlock() ) - // If we're at the last block of the batch or report period reached, log - if index == len(chain)-1 || elapsed >= statsReportLimit { - var ( - end = chain[index] - txs = countTransactions(chain[st.lastIndex : index+1]) - ) - context := []interface{}{ - "blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000, - "elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed), - "number", end.Number(), "hash", end.Hash(), - } - if timestamp := time.Unix(end.Time().Int64(), 0); time.Since(timestamp) > time.Minute { - context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) - } - context = append(context, []interface{}{"cache", cache}...) + // The first sidechain block error is already verified to be ErrPrunedAncestor. + // Since we don't import them here, we expect ErrUnknownAncestor for the remaining + // ones. Any other errors means that the block is invalid, and should not be written + // to disk. + err := consensus.ErrPrunedAncestor + for ; block != nil && (err == consensus.ErrPrunedAncestor); block, err = it.next() { + // Check the canonical state root for that number + if number := block.NumberU64(); current.NumberU64() >= number { + canonical := bc.GetBlockByNumber(number) + if canonical != nil && canonical.Hash() == block.Hash() { + // Not a sidechain block, this is a re-import of a canon block which has it's state pruned + continue + } + if canonical != nil && canonical.Root() == block.Root() { + // This is most likely a shadow-state attack. When a fork is imported into the + // database, and it eventually reaches a block height which is not pruned, we + // just found that the state already exist! This means that the sidechain block + // refers to a state which already exists in our canon chain. + // + // If left unchecked, we would now proceed importing the blocks, without actually + // having verified the state of the previous blocks. + log.Warn("Sidechain ghost-state attack detected", "number", block.NumberU64(), "sideroot", block.Root(), "canonroot", canonical.Root()) - if st.queued > 0 { - context = append(context, []interface{}{"queued", st.queued}...) + // If someone legitimately side-mines blocks, they would still be imported as usual. However, + // we cannot risk writing unverified blocks to disk when they obviously target the pruning + // mechanism. + return it.index, nil, nil, errors.New("sidechain ghost-state attack") + } } - if st.ignored > 0 { - context = append(context, []interface{}{"ignored", st.ignored}...) + if externTd == nil { + externTd = bc.GetTd(block.ParentHash(), block.NumberU64()-1) } - log.Info("Imported new chain segment", context...) + externTd = new(big.Int).Add(externTd, block.Difficulty()) - *st = insertStats{startTime: now, lastIndex: index + 1} + if !bc.HasBlock(block.Hash(), block.NumberU64()) { + start := time.Now() + if err := bc.WriteBlockWithoutState(block, externTd); err != nil { + return it.index, nil, nil, err + } + log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(), + "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), + "root", block.Root()) + } } -} - -func countTransactions(chain []*types.Block) (c int) { - for _, b := range chain { - c += len(b.Transactions()) + // At this point, we've written all sidechain blocks to database. Loop ended + // either on some other error or all were processed. If there was some other + // error, we can ignore the rest of those blocks. + // + // If the externTd was larger than our local TD, we now need to reimport the previous + // blocks to regenerate the required state + localTd := bc.GetTd(current.Hash(), current.NumberU64()) + if localTd.Cmp(externTd) > 0 { + log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd) + return it.index, nil, nil, err } - return c + // Gather all the sidechain hashes (full blocks may be memory heavy) + var ( + hashes []common.Hash + numbers []uint64 + ) + parent := it.previous() + for parent != nil && !bc.HasState(parent.Root) { + hashes = append(hashes, parent.Hash()) + numbers = append(numbers, parent.Number.Uint64()) + + parent = bc.GetHeader(parent.ParentHash, parent.Number.Uint64()-1) + } + if parent == nil { + return it.index, nil, nil, errors.New("missing parent") + } + // Import all the pruned blocks to make the state available + var ( + blocks []*types.Block + memory common.StorageSize + ) + for i := len(hashes) - 1; i >= 0; i-- { + // Append the next block to our batch + block := bc.GetBlock(hashes[i], numbers[i]) + + blocks = append(blocks, block) + memory += block.Size() + + // If memory use grew too large, import and continue. Sadly we need to discard + // all raised events and logs from notifications since we're too heavy on the + // memory here. + if len(blocks) >= 2048 || memory > 64*1024*1024 { + log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64()) + if _, _, _, err := bc.insertChain(blocks, false); err != nil { + return 0, nil, nil, err + } + blocks, memory = blocks[:0], 0 + + // If the chain is terminating, stop processing blocks + if atomic.LoadInt32(&bc.procInterrupt) == 1 { + log.Debug("Premature abort during blocks processing") + return 0, nil, nil, nil + } + } + } + if len(blocks) > 0 { + log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64()) + return bc.insertChain(blocks, false) + } + return 0, nil, nil, nil } // reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them @@ -1453,8 +1628,10 @@ func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, e bc.addBadBlock(block) var receiptString string - for _, receipt := range receipts { - receiptString += fmt.Sprintf("\t%v\n", receipt) + for i, receipt := range receipts { + receiptString += fmt.Sprintf("\t %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n", + i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), + receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) } log.Error(fmt.Sprintf(` ########## BAD BLOCK ######### @@ -1491,36 +1668,12 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i defer bc.wg.Done() whFunc := func(header *types.Header) error { - bc.mu.Lock() - defer bc.mu.Unlock() - _, err := bc.hc.WriteHeader(header) return err } - return bc.hc.InsertHeaderChain(chain, whFunc, start) } -// writeHeader writes a header into the local chain, given that its parent is -// already known. If the total difficulty of the newly inserted header becomes -// greater than the current known TD, the canonical chain is re-routed. -// -// Note: This method is not concurrent-safe with inserting blocks simultaneously -// into the chain, as side effects caused by reorganisations cannot be emulated -// without the real blocks. Hence, writing headers directly should only be done -// in two scenarios: pure-header mode of operation (light clients), or properly -// separated header/block phases (non-archive clients). -func (bc *BlockChain) writeHeader(header *types.Header) error { - bc.wg.Add(1) - defer bc.wg.Done() - - bc.mu.Lock() - defer bc.mu.Unlock() - - _, err := bc.hc.WriteHeader(header) - return err -} - // CurrentHeader retrieves the current head header of the canonical chain. The // header is retrieved from the HeaderChain's internal cache. func (bc *BlockChain) CurrentHeader() *types.Header { @@ -1569,8 +1722,8 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com // // Note: ancestor == 0 returns the same block, 1 returns its parent and so on. func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { - bc.chainmu.Lock() - defer bc.chainmu.Unlock() + bc.chainmu.RLock() + defer bc.chainmu.RUnlock() return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical) } @@ -1611,3 +1764,9 @@ func (bc *BlockChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.Su func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return bc.scope.Track(bc.logsFeed.Subscribe(ch)) } + +// SubscribeBlockProcessingEvent registers a subscription of bool where true means +// block processing has started while false means it has stopped. +func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription { + return bc.scope.Track(bc.blockProcFeed.Subscribe(ch)) +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/blockchain_insert.go b/vendor/github.com/ethereum/go-ethereum/core/blockchain_insert.go new file mode 100644 index 00000000..e2a38516 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/core/blockchain_insert.go @@ -0,0 +1,135 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package core + +import ( + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" +) + +// insertStats tracks and reports on block insertion. +type insertStats struct { + queued, processed, ignored int + usedGas uint64 + lastIndex int + startTime mclock.AbsTime +} + +// statsReportLimit is the time limit during import and export after which we +// always print out progress. This avoids the user wondering what's going on. +const statsReportLimit = 8 * time.Second + +// report prints statistics if some number of blocks have been processed +// or more than a few seconds have passed since the last message. +func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize) { + // Fetch the timings for the batch + var ( + now = mclock.Now() + elapsed = time.Duration(now) - time.Duration(st.startTime) + ) + // If we're at the last block of the batch or report period reached, log + if index == len(chain)-1 || elapsed >= statsReportLimit { + // Count the number of transactions in this segment + var txs int + for _, block := range chain[st.lastIndex : index+1] { + txs += len(block.Transactions()) + } + end := chain[index] + + // Assemble the log context and send it to the logger + context := []interface{}{ + "blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000, + "elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed), + "number", end.Number(), "hash", end.Hash(), + } + if timestamp := time.Unix(end.Time().Int64(), 0); time.Since(timestamp) > time.Minute { + context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) + } + context = append(context, []interface{}{"dirty", dirty}...) + + if st.queued > 0 { + context = append(context, []interface{}{"queued", st.queued}...) + } + if st.ignored > 0 { + context = append(context, []interface{}{"ignored", st.ignored}...) + } + log.Info("Imported new chain segment", context...) + + // Bump the stats reported to the next section + *st = insertStats{startTime: now, lastIndex: index + 1} + } +} + +// insertIterator is a helper to assist during chain import. +type insertIterator struct { + chain types.Blocks + results <-chan error + index int + validator Validator +} + +// newInsertIterator creates a new iterator based on the given blocks, which are +// assumed to be a contiguous chain. +func newInsertIterator(chain types.Blocks, results <-chan error, validator Validator) *insertIterator { + return &insertIterator{ + chain: chain, + results: results, + index: -1, + validator: validator, + } +} + +// next returns the next block in the iterator, along with any potential validation +// error for that block. When the end is reached, it will return (nil, nil). +func (it *insertIterator) next() (*types.Block, error) { + if it.index+1 >= len(it.chain) { + it.index = len(it.chain) + return nil, nil + } + it.index++ + if err := <-it.results; err != nil { + return it.chain[it.index], err + } + return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index]) +} + +// previous returns the previous header that was being processed, or nil. +func (it *insertIterator) previous() *types.Header { + if it.index < 1 { + return nil + } + return it.chain[it.index-1].Header() +} + +// first returns the first block in the it. +func (it *insertIterator) first() *types.Block { + return it.chain[0] +} + +// remaining returns the number of remaining blocks. +func (it *insertIterator) remaining() int { + return len(it.chain) - it.index +} + +// processed returns the number of processed blocks. +func (it *insertIterator) processed() int { + return it.index + 1 +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/blockchain_test.go b/vendor/github.com/ethereum/go-ethereum/core/blockchain_test.go index aef81005..d1681ce3 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/blockchain_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/blockchain_test.go @@ -17,7 +17,6 @@ package core import ( - "fmt" "math/big" "math/rand" "sync" @@ -47,7 +46,7 @@ var ( // header only chain. func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { var ( - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() genesis = new(Genesis).MustCommit(db) ) @@ -126,13 +125,6 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara comparator(tdPre, tdPost) } -func printChain(bc *BlockChain) { - for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- { - b := bc.GetBlockByNumber(uint64(i)) - fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty()) - } -} - // testBlockChainImport tries to process a chain of blocks, writing them into // the database if successful. func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { @@ -157,16 +149,16 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas) + err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) if err != nil { blockchain.reportBlock(block, receipts, err) return err } - blockchain.mu.Lock() + blockchain.chainmu.Lock() rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) rawdb.WriteBlock(blockchain.db, block) statedb.Commit(false) - blockchain.mu.Unlock() + blockchain.chainmu.Unlock() } return nil } @@ -180,23 +172,14 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error return err } // Manually insert the header into the database, but don't reorganise (allows subsequent testing) - blockchain.mu.Lock() + blockchain.chainmu.Lock() rawdb.WriteTd(blockchain.db, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash))) rawdb.WriteHeader(blockchain.db, header) - blockchain.mu.Unlock() + blockchain.chainmu.Unlock() } return nil } -func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) { - _, err := blockchain.InsertChain(chain) - if err != nil { - fmt.Println(err) - t.FailNow() - } - done <- true -} - func TestLastBlock(t *testing.T) { _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) if err != nil { @@ -579,11 +562,11 @@ func testInsertNonceError(t *testing.T, full bool) { blockchain.hc.engine = blockchain.engine failRes, err = blockchain.InsertHeaderChain(headers, 1) } - // Check that the returned error indicates the failure. + // Check that the returned error indicates the failure if failRes != failAt { - t.Errorf("test %d: failure index mismatch: have %d, want %d", i, failRes, failAt) + t.Errorf("test %d: failure (%v) index mismatch: have %d, want %d", i, err, failRes, failAt) } - // Check that all no blocks after the failing block have been inserted. + // Check that all blocks after the failing block have been inserted for j := 0; j < i-failAt; j++ { if full { if block := blockchain.GetBlockByNumber(failNum + uint64(j)); block != nil { @@ -603,7 +586,7 @@ func testInsertNonceError(t *testing.T, full bool) { func TestFastVsFullChains(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = ethdb.NewMemDatabase() + gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) @@ -633,7 +616,7 @@ func TestFastVsFullChains(t *testing.T) { } }) // Import the chain as an archive node for the comparison baseline - archiveDb := ethdb.NewMemDatabase() + archiveDb := rawdb.NewMemoryDatabase() gspec.MustCommit(archiveDb) archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer archive.Stop() @@ -642,7 +625,7 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to process block %d: %v", n, err) } // Fast import the chain as a non-archive node to test - fastDb := ethdb.NewMemDatabase() + fastDb := rawdb.NewMemoryDatabase() gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() @@ -691,7 +674,7 @@ func TestFastVsFullChains(t *testing.T) { func TestLightVsFastVsFullChainHeads(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = ethdb.NewMemDatabase() + gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) @@ -719,7 +702,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { } } // Import the chain as an archive node and ensure all pointers are updated - archiveDb := ethdb.NewMemDatabase() + archiveDb := rawdb.NewMemoryDatabase() gspec.MustCommit(archiveDb) archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) @@ -733,7 +716,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { assert(t, "archive", archive, height/2, height/2, height/2) // Import the chain as a non-archive node and ensure all pointers are updated - fastDb := ethdb.NewMemDatabase() + fastDb := rawdb.NewMemoryDatabase() gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() @@ -753,7 +736,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { assert(t, "fast", fast, height/2, height/2, 0) // Import the chain as a light node and ensure all pointers are updated - lightDb := ethdb.NewMemDatabase() + lightDb := rawdb.NewMemoryDatabase() gspec.MustCommit(lightDb) light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) @@ -776,7 +759,7 @@ func TestChainTxReorgs(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec = &Genesis{ Config: params.TestChainConfig, GasLimit: 3141592, @@ -888,7 +871,7 @@ func TestLogReorgs(t *testing.T) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() // this code generates a log code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}} @@ -932,7 +915,7 @@ func TestLogReorgs(t *testing.T) { func TestReorgSideEvent(t *testing.T) { var ( - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{ @@ -1060,7 +1043,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) { func TestEIP155Transition(t *testing.T) { // Configure and generate a sample block chain var ( - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) @@ -1163,7 +1146,7 @@ func TestEIP155Transition(t *testing.T) { func TestEIP161AccountRemoval(t *testing.T) { // Configure and generate a sample block chain var ( - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) @@ -1235,7 +1218,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() genesis := new(Genesis).MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) @@ -1251,7 +1234,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { } // Import the canonical and fork chain side by side, verifying the current block // and current header consistency - diskdb := ethdb.NewMemDatabase() + diskdb := rawdb.NewMemoryDatabase() new(Genesis).MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) @@ -1280,7 +1263,7 @@ func TestTrieForkGC(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() genesis := new(Genesis).MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) @@ -1295,7 +1278,7 @@ func TestTrieForkGC(t *testing.T) { forks[i] = fork[0] } // Import the canonical and fork chain side by side, forcing the trie cache to cache both - diskdb := ethdb.NewMemDatabase() + diskdb := rawdb.NewMemoryDatabase() new(Genesis).MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) @@ -1326,7 +1309,7 @@ func TestLargeReorgTrieGC(t *testing.T) { // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() genesis := new(Genesis).MustCommit(db) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) @@ -1334,7 +1317,7 @@ func TestLargeReorgTrieGC(t *testing.T) { competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one - diskdb := ethdb.NewMemDatabase() + diskdb := rawdb.NewMemoryDatabase() new(Genesis).MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) @@ -1345,7 +1328,7 @@ func TestLargeReorgTrieGC(t *testing.T) { t.Fatalf("failed to insert shared chain: %v", err) } if _, err := chain.InsertChain(original); err != nil { - t.Fatalf("failed to insert shared chain: %v", err) + t.Fatalf("failed to insert original chain: %v", err) } // Ensure that the state associated with the forking point is pruned away if node, _ := chain.stateCache.TrieDB().Node(shared[len(shared)-1].Root()); node != nil { @@ -1394,7 +1377,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in ) // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() genesis := gspec.MustCommit(db) blockGenerator := func(i int, block *BlockGen) { @@ -1416,7 +1399,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in b.ResetTimer() for i := 0; i < b.N; i++ { // Import the shared chain and the original canonical one - diskdb := ethdb.NewMemDatabase() + diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) @@ -1429,7 +1412,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in } b.StopTimer() if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { - b.Fatalf("Transactions were not included, expected %d, got %d", (numTxs * numBlocks), got) + b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) } } @@ -1483,3 +1466,140 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) } + +// Tests that importing a very large side fork, which is larger than the canon chain, +// but where the difficulty per block is kept low: this means that it will not +// overtake the 'canon' chain until after it's passed canon by about 200 blocks. +// +// Details at: +// - https://github.com/ethereum/go-ethereum/issues/18977 +// - https://github.com/ethereum/go-ethereum/pull/18988 +func TestLowDiffLongChain(t *testing.T) { + // Generate a canonical chain to act as the main dataset + engine := ethash.NewFaker() + db := rawdb.NewMemoryDatabase() + genesis := new(Genesis).MustCommit(db) + + // We must use a pretty long chain to ensure that the fork doesn't overtake us + // until after at least 128 blocks post tip + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*triesInMemory, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + b.OffsetTime(-9) + }) + + // Import the canonical chain + diskdb := rawdb.NewMemoryDatabase() + new(Genesis).MustCommit(diskdb) + + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + // Generate fork chain, starting from an early block + parent := blocks[10] + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*triesInMemory, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{2}) + }) + + // And now import the fork + if i, err := chain.InsertChain(fork); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", i, err) + } + head := chain.CurrentBlock() + if got := fork[len(fork)-1].Hash(); got != head.Hash() { + t.Fatalf("head wrong, expected %x got %x", head.Hash(), got) + } + // Sanity check that all the canonical numbers are present + header := chain.CurrentHeader() + for number := head.NumberU64(); number > 0; number-- { + if hash := chain.GetHeaderByNumber(number).Hash(); hash != header.Hash() { + t.Fatalf("header %d: canonical hash mismatch: have %x, want %x", number, hash, header.Hash()) + } + header = chain.GetHeader(header.ParentHash, number-1) + } +} + +// Tests that importing a sidechain (S), where +// - S is sidechain, containing blocks [Sn...Sm] +// - C is canon chain, containing blocks [G..Cn..Cm] +// - A common ancestor is placed at prune-point + blocksBetweenCommonAncestorAndPruneblock +// - The sidechain S is prepended with numCanonBlocksInSidechain blocks from the canon chain +func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommonAncestorAndPruneblock int) { + + // Generate a canonical chain to act as the main dataset + engine := ethash.NewFaker() + db := rawdb.NewMemoryDatabase() + genesis := new(Genesis).MustCommit(db) + + // Generate and import the canonical chain + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, nil) + diskdb := rawdb.NewMemoryDatabase() + new(Genesis).MustCommit(diskdb) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + lastPrunedIndex := len(blocks) - triesInMemory - 1 + lastPrunedBlock := blocks[lastPrunedIndex] + firstNonPrunedBlock := blocks[len(blocks)-triesInMemory] + + // Verify pruning of lastPrunedBlock + if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { + t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) + } + // Verify firstNonPrunedBlock is not pruned + if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { + t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) + } + // Generate the sidechain + // First block should be a known block, block after should be a pruned block. So + // canon(pruned), side, side... + + // Generate fork chain, make it longer than canon + parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock + parent := blocks[parentIndex] + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{2}) + }) + // Prepend the parent(s) + var sidechain []*types.Block + for i := numCanonBlocksInSidechain; i > 0; i-- { + sidechain = append(sidechain, blocks[parentIndex+1-i]) + } + sidechain = append(sidechain, fork...) + _, err = chain.InsertChain(sidechain) + if err != nil { + t.Errorf("Got error, %v", err) + } + head := chain.CurrentBlock() + if got := fork[len(fork)-1].Hash(); got != head.Hash() { + t.Fatalf("head wrong, expected %x got %x", head.Hash(), got) + } +} + +// Tests that importing a sidechain (S), where +// - S is sidechain, containing blocks [Sn...Sm] +// - C is canon chain, containing blocks [G..Cn..Cm] +// - The common ancestor Cc is pruned +// - The first block in S: Sn, is == Cn +// That is: the sidechain for import contains some blocks already present in canon chain. +// So the blocks are +// [ Cn, Cn+1, Cc, Sn+3 ... Sm] +// ^ ^ ^ pruned +func TestPrunedImportSide(t *testing.T) { + //glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) + //glogger.Verbosity(3) + //log.Root().SetHandler(log.Handler(glogger)) + testSideImport(t, 3, 3) + testSideImport(t, 3, -3) + testSideImport(t, 10, 0) + testSideImport(t, 1, 10) + testSideImport(t, 1, -10) +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/chain_indexer.go b/vendor/github.com/ethereum/go-ethereum/core/chain_indexer.go index 1adde1fc..26538260 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/chain_indexer.go +++ b/vendor/github.com/ethereum/go-ethereum/core/chain_indexer.go @@ -97,7 +97,7 @@ type ChainIndexer struct { // NewChainIndexer creates a new chain indexer to do background processing on // chain segments of a given size after certain number of confirmations passed. // The throttling parameter might be used to prevent database thrashing. -func NewChainIndexer(chainDb, indexDb ethdb.Database, backend ChainIndexerBackend, section, confirm uint64, throttling time.Duration, kind string) *ChainIndexer { +func NewChainIndexer(chainDb ethdb.Database, indexDb ethdb.Database, backend ChainIndexerBackend, section, confirm uint64, throttling time.Duration, kind string) *ChainIndexer { c := &ChainIndexer{ chainDb: chainDb, indexDb: indexDb, diff --git a/vendor/github.com/ethereum/go-ethereum/core/chain_indexer_test.go b/vendor/github.com/ethereum/go-ethereum/core/chain_indexer_test.go index a029dec6..abf5b3cc 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/chain_indexer_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/chain_indexer_test.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" ) // Runs multiple tests with randomized parameters. @@ -49,7 +48,7 @@ func TestChainIndexerWithChildren(t *testing.T) { // multiple backends. The section size and required confirmation count parameters // are randomized. func testChainIndexer(t *testing.T, count int) { - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() defer db.Close() // Create a chain of indexers and ensure they all report empty @@ -60,7 +59,7 @@ func testChainIndexer(t *testing.T, count int) { confirmsReq = uint64(rand.Intn(10)) ) backends[i] = &testChainIndexBackend{t: t, processCh: make(chan uint64)} - backends[i].indexer = NewChainIndexer(db, ethdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i)) + backends[i].indexer = NewChainIndexer(db, rawdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i)) if sections, _, _ := backends[i].indexer.Sections(); sections != 0 { t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0) diff --git a/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go b/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go index e3a5537a..0b5a3d18 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go +++ b/vendor/github.com/ethereum/go-ethereum/core/chain_makers.go @@ -149,7 +149,7 @@ func (b *BlockGen) PrevBlock(index int) *types.Block { // associated difficulty. It's useful to test scenarios where forking is not // tied to chain length directly. func (b *BlockGen) OffsetTime(seconds int64) { - b.header.Time.Add(b.header.Time, new(big.Int).SetInt64(seconds)) + b.header.Time.Add(b.header.Time, big.NewInt(seconds)) if b.header.Time.Cmp(b.parent.Header().Time) <= 0 { panic("block time out of range") } diff --git a/vendor/github.com/ethereum/go-ethereum/core/chain_makers_test.go b/vendor/github.com/ethereum/go-ethereum/core/chain_makers_test.go index 64b64fd6..32e3888d 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/chain_makers_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/chain_makers_test.go @@ -21,10 +21,10 @@ import ( "math/big" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -36,7 +36,7 @@ func ExampleGenerateChain() { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() ) // Ensure that key1 has some funds in the genesis block. diff --git a/vendor/github.com/ethereum/go-ethereum/core/dao_test.go b/vendor/github.com/ethereum/go-ethereum/core/dao_test.go index 966139bc..4e8dba9e 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/dao_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/dao_test.go @@ -21,8 +21,8 @@ import ( "testing" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -32,13 +32,13 @@ func TestDAOForkRangeExtradata(t *testing.T) { forkBlock := big.NewInt(32) // Generate a common prefix for both pro-forkers and non-forkers - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() gspec := new(Genesis) genesis := gspec.MustCommit(db) prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) // Create the concurrent, conflicting two nodes - proDb := ethdb.NewMemDatabase() + proDb := rawdb.NewMemoryDatabase() gspec.MustCommit(proDb) proConf := *params.TestChainConfig @@ -48,7 +48,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer proBc.Stop() - conDb := ethdb.NewMemDatabase() + conDb := rawdb.NewMemoryDatabase() gspec.MustCommit(conDb) conConf := *params.TestChainConfig @@ -67,7 +67,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() @@ -92,7 +92,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } // Create a no-fork block, and try to feed into the pro-fork chain - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() @@ -118,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { } } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() @@ -138,7 +138,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() diff --git a/vendor/github.com/ethereum/go-ethereum/core/genesis.go b/vendor/github.com/ethereum/go-ethereum/core/genesis.go index 6e71afd6..4aa12996 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/genesis.go +++ b/vendor/github.com/ethereum/go-ethereum/core/genesis.go @@ -134,7 +134,7 @@ type GenesisMismatchError struct { } func (e *GenesisMismatchError) Error() string { - return fmt.Sprintf("database already contains an incompatible genesis block (have %x, new %x)", e.Stored[:8], e.New[:8]) + return fmt.Sprintf("database contains incompatible genesis (have %x, new %x)", e.Stored, e.New) } // SetupGenesisBlock writes or updates the genesis block in db. @@ -151,10 +151,12 @@ func (e *GenesisMismatchError) Error() string { // // The returned chain configuration is never nil. func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { + return SetupGenesisBlockWithOverride(db, genesis, nil) +} +func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, constantinopleOverride *big.Int) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } - // Just commit the new block if there is no stored genesis block. stored := rawdb.ReadCanonicalHash(db, 0) if (stored == common.Hash{}) { @@ -178,6 +180,10 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig // Get the existing chain configuration. newcfg := genesis.configOrDefault(stored) + if constantinopleOverride != nil { + newcfg.ConstantinopleBlock = constantinopleOverride + newcfg.PetersburgBlock = constantinopleOverride + } storedcfg := rawdb.ReadChainConfig(db, stored) if storedcfg == nil { log.Warn("Found genesis block without chain config") @@ -222,7 +228,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { // to the given database (or discards it if nil). func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { if db == nil { - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() } statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) for addr, account := range g.Alloc { @@ -333,6 +339,18 @@ func DefaultRinkebyGenesisBlock() *Genesis { } } +// DefaultGoerliGenesisBlock returns the Görli network genesis block. +func DefaultGoerliGenesisBlock() *Genesis { + return &Genesis{ + Config: params.GoerliChainConfig, + Timestamp: 1548854791, + ExtraData: hexutil.MustDecode("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 10485760, + Difficulty: big.NewInt(1), + Alloc: decodePrealloc(goerliAllocData), + } +} + // DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must // be seeded with the func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { diff --git a/vendor/github.com/ethereum/go-ethereum/core/genesis_alloc.go b/vendor/github.com/ethereum/go-ethereum/core/genesis_alloc.go index 4cb7d683..81477a6f 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/genesis_alloc.go +++ b/vendor/github.com/ethereum/go-ethereum/core/genesis_alloc.go @@ -24,3 +24,4 @@ package core const mainnetAllocData = "\xfa\x04]X\u0793\r\x83b\x011\x8e\u0189\x9agT\x06\x908'\x80t2\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x17bC\x0e\xa9\u00e2nWI\xaf\xdbp\xda_x\u077b\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x1d\x14\x80K9\x9cn\xf8\x0edWoev`\x80O\xec\v\x89\u3bb5sr@\xa0\x00\x00\u07932@5\x87\x94{\x9f\x15b*h\xd1\x04\xd5M3\xdb\xd1\u0349\x043\x87Oc,\xc6\x00\x00\u0793I~\x92\xcd\xc0\xe0\xb9c\xd7R\xb2)j\u02c7\u0682\x8b$\x89\n\x8fd\x9f\xe7\xc6\x18\x00\x00\u0793K\xfb\xe1Tk\xc6\xc6[\\~\xaaU0K8\xbb\xfe\xc6\u04c9lk\x93[\x8b\xbd@\x00\x00\u0793Z\x9c\x03\xf6\x9d\x17\xd6l\xbb\x8a\xd7!\x00\x8a\x9e\xbb\xb86\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u0793]\x0e\xe8\x15^\xc0\xa6\xffh\bU,\xa5\xf1k\xb5\xbe2:\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u0793v\"\xd8J#K\xb8\xb0x#\x0f\u03c4\xb6z\u9a2c\xae\x89%\xe1\xccQ\x99R\xf8\x00\x00\u0793{\x9f\xc3\x19\x05\xb4\x99K\x04\xc9\xe2\xcf\xdc^'pP?B\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u0793\u007fJ#\xca\x00\xcd\x04=%\u0088\x8c\x1a\xa5h\x8f\x81\xa3D\x89)\xf0\xa9[\xfb\xf7)\x00\x00\u0793\x869\u06bb\u3bac\x88{]\xc0\xe4>\x13\xbc\u0487\xd7l\x89\x10\xd0\xe3\xc8}n,\x00\x00\u0793\x89P\x86y\xab\xf8\xc7\x1b\xf6x\x16\x87\x12\x0e>j\x84XM\x89a\x94\x04\x9f0\xf7 \x00\x00\u0793\x8f\xc7\u02ed\xff\xbd\r\u007f\xe4O\x8d\xfd`\xa7\x9dr\x1a\x1c\x9c\x8965\u026d\xc5\u07a0\x00\x00\u0793\x95`\xa3\xdebxh\xf9\x1f\xa8\xbf\xe1\xc1\xb7\xaf\xaf\b\x18k\x89\x1cg\xf5\xf7\xba\xa0\xb0\x00\x00\u0793\x96\x97G\xf7\xa5\xb3\x06E\xfe\x00\xe4I\x01CZ\xce$\xcc7\x89\\(=A\x03\x94\x10\x00\x00\u0793\x9am}\xb3&g\x9bw\xc9\x03\x91\xa7Gm#\x8f;\xa3>\x89\n\xdaUGK\x814\x00\x00\u0793\x9e\xef\n\b\x86\x05n?i!\x18S\xb9\xb7E\u007f7\x82\u4262\xa8x\x06\x9b(\xe0\x00\x00\u0793\x9f\xdb\xf4N\x1fJcb\xb7i\u00daG_\x95\xa9l+\u01c9\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d3\xa5y\u007fR\xc9\u054f\x18\x9f6\xb1\xd4]\x1b\xf6\x04\x1f/k\x8a\x01'\u0473F\x1a\xcd\x1a\x00\x00\u0793\xaaS\x81\xb2\x13\x8e\xbe\xff\xc1\x91\xd5\xd8\u00d1u;p\x98\u04895\xab\xb0\x9f\xfe\u07b6\x80\x00\u0793\xaa\xda%\xea\"\x86p\x9a\xbbB-A\x92?\u04c0\xcd\x04\u01c9#=\xf3)\x9far\x00\x00\u0793\xac\xbf\xb2\xf2ZT\x85\xc79\xefp\xa4N\xee\xeb|e\xa6o\x89\x05k\xc7^-c\x10\x00\x00\u07d3\xac\xc6\xf0\x82\xa4B\x82\x87d\xd1\x1fX\u0589J\xe4\b\xf0s\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u0793\xb2w\xb0\x99\xa8\xe8f\xca\x0e\xc6[\u02c7(O\xd1B\xa5\x82\x89j\xcb=\xf2~\x1f\x88\x00\x00\u0753\xbd\xd4\x01:\xa3\x1c\x04al+\xc9x_'\x88\xf9\x15g\x9b\x88\xb9\xf6]\x00\xf6<\x00\x00\u0793\xc2}c\xfd\xe2K\x92\xee\x8a\x1e~\xd5\xd2m\x8d\xc5\xc8;\x03\x89lk\x93[\x8b\xbd@\x00\x00\u0553\xc4\x0f\xe2\tT#P\x9b\x9f\u0677T21X\xaf#\x10\xf3\x80\u0793\xd7^\xd6\fwO\x8b:ZQs\xfb\x183\xadq\x05\xa2\u0649l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d3\u05cd\x89\xb3_G'\x16\xec\xea\xfe\xbf`\x05'\u04e1\xf9i\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u0793\xda\xe2{5\v\xae \xc5e!$\xaf]\x8b\\\xba\x00\x1e\xc1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u0793\xdc\x01\xcb\xf4Ix\xa4.\x8d\xe8\xe46\xed\xf9B\x05\u03f6\xec\x89O\x0f\xeb\xbc\u068c\xb4\x00\x00\u07d3\u607c-\x10\xdbb\u0785\x84\x83$I\"P4\x8e\x90\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d3\xf4c\xe17\xdc\xf6%\xfb\U000fc8de\u0298\u04b9h\xcf\u007f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\x01\x00\a9K\x8bue\xa1e\x8a\xf8\x8c\xe4cI\x915\u05b7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x01\r\xf1\xdfK\xed#v\r-\x1c\x03x\x15\x86\xdd\xf7\x91\x8eT\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x01\x0fJ\x98\u07e1\xd9y\x9b\xf5\u01d6\xfbU\x0e\xfb\xe7\xec\xd8w\x8a\x01\xb2\xf2\x92#b\x92\xc7\x00\x00\u07d4\x01\x15PW\x00/k\r\x18\xac\xb98\x8d;\xc8\x12\x9f\x8fz \x89H\xa4\xa9\x0f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01k`\xbbmg\x92\x8c)\xfd\x03\x13\xc6f\u068f\x16\x98\xd9\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\x01l\x85\xe1a;\x90\x0f\xa3W\xb8(;\x12\x0ee\xae\xfc\xdd\b\x89+]\x97\x84\xa9|\xd5\x00\x00\u07d4\x01\x84\x92H\x8b\xa1\xa2\x924\"G\xb3\x18U\xa5Y\x05\xfe\xf2i\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x01\x8f \xa2{'\xecD\x1a\xf7#\xfd\x90\x99\xf2\u02f7\x9dbc\x89uy*\x8a\xbd\xef|\x00\x00\u07d4\x01\x91\xebT~{\xf6\x97k\x9b\x1bWuFv\x1d\xe6V\"\xe2\x89lkLM\xa6\u077e\x00\x00\u07d4\x01\x9dp\x95y\xffK\xc0\x9f\xdc\xdd\xe41\xdc\x14G\xd2\xc2`\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x01\xa2Z_Z\xf0\x16\x9b0\x86L;\xe4\xd7V<\xcdD\xf0\x9e\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\x01\xa7\xd9\xfa}\x0e\xb1\x18\\g\xe5M\xa8<.u\xdbi\u37ca\x01\x9dJ\xdd\xd0\u063c\x96\x00\x00\u07d4\x01\xa8\x18\x13ZAB\x10\xc3|b\xb6%\xac\xa1\xa5F\x11\xac6\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x01\xb1\xca\xe9\x1a;\x95Y\xaf\xb3<\xdcmh\x94B\xfd\xbf\xe07\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xb5\xb5\xbcZ\x11\u007f\xa0\x8b4\xed\x1d\xb9D\x06\bYz\xc5H\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xbb\xc1Og\xaf\x069\xaa\xb1D\x1ej\b\xd4\xceqb\t\x0f\x89F\xfc\xf6\x8f\xf8\xbe\x06\x00\x00\xe0\x94\x01\xd08\x15\xc6\x1fAkq\xa2a\n-\xab\xa5\x9f\xf6\xa6\xde[\x8a\x02\x05\xdf\xe5\v\x81\xc8.\x00\x00\u07d4\x01\u0559\xee\r_\x8c8\xab-9.,e\xb7L<\xe3\x18 \x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\x01\xe4\x05!\x12%0\u066c\x91\x11<\x06\xa0\x19\vmc\x85\v\x89Hz\x9a0E9D\x00\x00\u07d4\x01\xe6A]X{\x06T\x90\xf1\xed\u007f!\xd6\xe0\xf3\x86\xeegG\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x01\xe8d\xd3Tt\x1bB>oB\x85\x17$F\x8ct\xf5\xaa\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x01\xed_\xba\x8d.\xabg:\xec\x04-0\xe4\xe8\xa6\x11\xd8\xc5Z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01\xfb\x8e\xc1$%\xa0O\x81>F\xc5L\x05t\x8c\xa6\xb2\x9a\xa9\x89\x0e\x15s\x03\x85F|\x00\x00\u07d4\x01\xff\x1e\xb1\u07adP\xa7\xf2\xf9c\x8f\xde\xe6\xec\xcf:{*\u0209 \x86\xac5\x10R`\x00\x00\u07d4\x02\x03b\u00ed\xe8x\u0290\u05b2\u0609\xa4\xccU\x10\xee\xd5\xf3\x898\x88\xe8\xb3\x11\xad\xb3\x80\x00\u07d4\x02\x03\xae\x01\xd4\xc4\x1c\xae\x18e\xe0K\x1f[S\xcd\xfa\xec\xae1\x896\x89\xcd\u03b2\x8c\xd7\x00\x00\u07d4\x02\b\x93a\xa3\xfetQ\xfb\x1f\x87\xf0\x1a-\x86fS\xdc\v\a\x89\x02*\xc7H2\xb5\x04\x00\x00\u07d4\x02\x1fi\x04=\xe8\x8cI\x17\xca\x10\xf1\x84(\x97\xee\xc0X\x9c|\x89kD\u03f8\x14\x87\xf4\x00\x00\u07d4\x02)\x0f\xb5\xf9\xa5\x17\xf8(E\xac\xde\xca\x0f\xc8F\x03\x9b\xe23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x029\xb4\xf2\x1f\x8e\x05\xcd\x01Q++\xe7\xa0\xe1\x8am\x97F\a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x02Gr\x12\xff\xddu\xe5\x15VQ\xb7e\x06\xb1dfq\xa1\xeb\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x02J\t\x8a\xe7\x02\xbe\xf5@l\x9c\"\xb7\x8b\xd4\xeb,\u01e2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x02K\xdd,{\xfdP\x0e\xe7@O\u007f\xb3\xe9\xfb1\xdd \xfb\u0449\t\xc2\x00vQ\xb2P\x00\x00\u07d4\x02Sg\x96\x03\x04\xbe\xee4Y\x11\x18\xe9\xac-\x13X\xd8\x02\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x02V\x14\x9f[Pc\xbe\xa1N\x15f\x1f\xfbX\xf9\xb4Y\xa9W\x89&)\xf6n\fS\x00\x00\x00\u07d4\x02`=z;\xb2\x97\xc6|\x87~]4\xfb\u0579\x13\xd4\xc6:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x02a\xad:\x17*\xbf\x13\x15\xf0\xff\xec2p\x98j\x84\t\xcb%\x89\v\b!;\u03cf\xfe\x00\x00\u07d4\x02d2\xaf7\xdcQ\x13\xf1\xf4mH\nM\u0c80R#~\x89\x13I\xb7\x86\xe4\v\xfc\x00\x00\u07d4\x02f\xab\x1ck\x02\x16#\v\x93\x95D=_\xa7^hEh\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x02u\x1d\u018c\xb5\xbdsp'\xab\xf7\u0777s\x90\xcdw\xc1k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x02w\x8e9\x0f\xa1u\x10\xa3B\x8a\xf2\x87\fBsT}8l\x8a\x03lw\x80\x18\x8b\xf0\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x037|\x0eUkd\x01\x03(\x9aa\x89\u1baecI4g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03IcM\u00a9\xe8\f?w!\xee+PF\xae\xaa\xed\xfb\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x03U\xbc\xac\xbd!D\x1e\x95\xad\xee\xdc0\xc1r\x18\u0224\b\u0389\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x03n\xef\xf5\xba\x90\xa6\x87\x9a\x14\xdf\xf4\xc5\x04;\x18\xca\x04`\u0249\x05k\xc7^-c\x10\x00\x00\xe0\x94\x03qKA\u04a6\xf7Q\x00\x8e\xf8\xddM+)\xae\u02b8\xf3n\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x03r\xe8RX.\t44J\x0f\xed!x0M\xf2]F(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03r\xeeU\b\xbf\x81c\xed(N^\xef\x94\xceMsg\xe5\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x03}\xd0V\xe7\xfd\xbdd\x1d\xb5\xb6\xbe\xa2\xa8x\n\x83\xfa\u1009\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\x03\x83#\xb1\x84\xcf\xf7\xa8*\xe2\u1f67y?\xe41\x9c\xa0\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03\x87y\xca-\xbef>c\xdb?\xe7V\x83\xea\x0e\xc6.#\x83\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x03\x8eE\xea\xdd=\x88\xb8\u007f\xe4\u06b0fh\x05\"\xf0\xdf\xc8\xf9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x03\x92T\x9ar\u007f\x81eT)\u02d2\x8bR\x9f%\xdfM\x13\x85\x89\x01lC\xa0\xee\xa0t\x00\x00\u07d4\x03\x94\xb9\x0f\xad\xb8`O\x86\xf4?\xc1\xe3]1$\xb3*Y\x89\x89)j\xa1@'\x8ep\x00\x00\u0794\x03\x9ezN\xbc(N,\xcdB\xb1\xbd\xd6\v\xd6Q\x1c\x0fw\x06\x88\xf0\x15\xf2W6B\x00\x00\u07d4\x03\x9e\xf1\xceR\xfeyc\xf1f\u0562u\u0131\x06\x9f\xe3\xa82\x89\x15\xaf9\u4ab2t\x00\x00\u07d4\x03\xa2l\xfcL\x181op\u055e\x9e\x1ay\xee>\x8b\x96/L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xaab(\x81#m\xd0\xf4\x94\f$\xc3$\xff\x8b{~!\x86\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\x03\xafz\xd9\xd5\"<\xf7\xc8\xc1? \xdfg\xeb\xe5\xff\u017bA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xb0\xf1|\xd4F\x9d\xdc\u03f7\xdai~\x82\xa9\x1a_\x9ewt\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xb4\x1bQ\xf4\x1d\xf2\r\xd2y\xba\xe1\x8c\x12w_w\xadw\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x03\xbe[F)\xae\xfb\xbc\xab\x9d\xe2m9Wl\xb7\xf6\x91\xd7d\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x03\xc6G\xa9\xf9)\xb0x\x1f\xe9\xae\x01\u02a3\xe1\x83\xe8vw~\x89\x18*\xb7\xc2\f\xe5$\x00\x00\u07d4\x03\xc9\x1d\x92\x946\x03\xe7R >\x054\x0eV`\x13\xb9\x00E\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x03\xcbLOE\x16\xc4\xffy\xa1\xb6$O\xbfW.\x1c\u007f\xeay\x89\x94\x89#z\u06daP\x00\x00\u07d4\x03\u02d8\u05ec\xd8\x17\u079d\x88m\"\xfa\xb3\xf1\xb5}\x92\xa6\b\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x03\u031d-!\xf8k\x84\xac\x8c\xea\xf9q\u06e7\x8a\x90\xe6%p\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x03\xd1rO\xd0\x0eT\xaa\xbc\xd2\xde*\x91\xe8F+\x10I\xdd:\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\x03\xde\xdf\xcd\v<.\x17\xc7\x05\xda$\x87\x90\uf626\xbdWQ\x89Hz\x9a0E9D\x00\x00\u07d4\x03\u8c04SuW\xe7\t\xea\xe2\xe1\u1966\xbc\xe1\xef\x83\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xeam&\u0400\xe5z\xee9&\xb1\x8e\x8e\xd7:N[(&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xeb<\xb8`\xf6\x02\x8d\xa5T\xd3D\xa2\xbbZP\n\xe8\xb8o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xeb\xc6?\xdaf`\xa4e\x04^#_\xben\\\xf1\x95s_\x89\a\xb0l\xe8\u007f\xddh\x00\x00\xe0\x94\x03\xefj\xd2\x0f\xf7\xbdO\x00+\xacX\xd4uD\u03c7\x9a\xe7(\x8a\x01u\xc7X\u0439n\\\x00\x00\u07d4\x03\xf7\xb9 \b\x81:\xe0\xa6v\xeb!(\x14\xaf\xab5\"\x10i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\x11p\xf5\x81\u0780\xe5\x8b*\x04\\\x8f|\x14\x93\xb0\x01\xb7\u02c90\xc8\xeca2\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\x04i\xe8\xc4@E\v\x0eQ&&\xfe\x81~gT\xa8\x15(0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04m'K\x1a\xf6\x15\xfbPZvJ\xd8\u0767p\xb1\xdb/=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x04}Z&\u05ed\x8f\x8ep`\x0fp\xa3\x98\u076a\x1c-\xb2o\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x04~\x87\xc8\xf7\xd1\xfc\xe3\xb0\x13S\xa8Xb\xa9H\xac\x04\x9f>\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x04\u007f\x9b\xf1R\x9d\xaf\x87\xd4\a\x17^o\x17\x1b^Y\xe9\xff>\x89#<\x8f\xe4'\x03\xe8\x00\x00\xe0\x94\x04\x85'2\xb4\xc6R\xf6\xc2\u53b3e\x87\xe6\nb\xda\x14\u06ca\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x04\x8a\x89p\xeaAE\xc6MU\x17\xb8\xde[F\xd0YZ\xad\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x04\x9c]K\xc6\xf2]NEli{R\xa0x\x11\xcc\u045f\xb1\x89\x10D\x00\xa2G\x0eh\x00\x00\u07d4\x04\xa1\xca\xda\x1c\xc7Q\b/\xf8\u0692\x8e<\xfa\x00\b \xa9\xe9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x04\xa8\n\xfa\xd5>\xf1\xf8Ae\xcf\xd8R\xb0\xfd\xf1\xb1\xc2K\xa8\x89\x03$\xe9d\xb3\xec\xa8\x00\x00\u07d4\x04\xaa\xfc\x8a\xe5\xceoI\x03\u021d\u007f\xac\x9c\xb1\x95\x12\"Gw\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x04\xbaK\xb8q@\x02,!Jo\xacB\xdbZ\x16\u0755@E\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xba\x8a?\x03\xf0\x8b\x89P\x95\x99M\xdaa\x9e\u06ac\xee>z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xc2\xc6K\xb5L>\xcc\xd0U\x85\xe1\x0e\xc6\xf9\x9a\f\xdb\x01\xa3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x04\xceE\xf6\x00\xdb\x18\xa9\u0405\x1b)\xd99>\xbd\xaa\xfe=\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x04\u05b8\xd4\u0686t\a\xbb\x99wI\u07bb\xcd\xc0\xb3XS\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xd78\x96\xcfe\x93\xa6\x91\x97*\x13\xa6\xe4\x87\x1f\xf2\xc4+\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xd8*\xf9\xe0\x1a\x93m\x97\xf8\xf8Y@\xb9p\xf9\xd4\u06d96\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x04\xe5\xf5\xbc|\x92?\xd1\xe3\x175\xe7.\xf9h\xfdg\x11\fn\x89WU\x1d\xbc\x8ebL\x00\x00\u07d4\x04\xec\xa5\x01c\n\xbc\xe3R\x18\xb1t\x95k\x89\x1b\xa2^\xfb#\x8966\x9e\xd7t}&\x00\x00\u07d4\x05\x05\xa0\x8e\"\xa1\t\x01Z\"\xf6\x850STf*U1\u0549\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x05\x14\x95L\xe8\x81\xc807\x03d\x00\x89lO\xd1\xee$nx\x00\x00\u07d4\x05\x1dBBv\xb2\x129fQ\x86\x13=e;\xb8\xb1\x86/\x89\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05!\xbc:\x9f\x87\x11\xfe\xcb\x10\xf5\a\x97\xd7\x10\x83\xe3A\ub749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05#mL\x90\xd0e\xf9\u34c3X\xaa\xff\xd7w\xb8j\xecI\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x05*X\xe05\xf1\xfe\x9c\xdd\x16\x9b\xcf \x97\x03E\xd1+\x9cQ\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x05.\xab\x1fa\xb6\xd4U\x17(?A\xd1D\x18$\x87\x87I\u0409\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x053n\x9ar'(\xd9c\xe7\xa1\xcf'Y\xfd\x02tS\x0f\u02891\xa2D?\x88\x8ay\x80\x00\u07d4\x054q\u035aA\x92[9\x04\xa5\xa8\xff\xca6Y\xe04\xbe#\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4\x056\x1d\x8e\xb6\x94\x1dN\x90\xfb~\x14\x18\xa9Z2\xd5%w2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05B:T\xc8\xd0\xf9p~pAs\xd9#\xb9F\xed\xc8\xe7\x00\x89\x06\xea\x03\u00bf\x8b\xa5\x80\x00\u07d4\x05D\f[\a;R\x9bH) \x9d\xff\x88\t\x0e\a\xc4\xf6\xf5\x89E\u04977\xe2/ \x00\x00\u07d4\x05Z\xb6X\xc6\xf0\xedO\x87^\xd6t.K\xc7)-\x1a\xbb\xf0\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x05[\xd0,\xaf\x19\xd6 +\xbc\u0703m\x18{\xd1\xc0\x1c\xf2a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05^\xacO\x1a\xd3\xf5\x8f\v\xd0$\u058e\xa6\r\xbe\x01\u01af\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05fQU\xccI\xcb\xf6\xaa\xbd\u056e\x92\xcb\xfa\xad\x82\xb8\xc0\xc1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x05f\x86\a\x8f\xb6\xbc\xf9\xba\n\x8a\x8d\xc6:\x90o_\xea\xc0\xea\x89\x1b\x18\x1eK\xf24<\x00\x00\u07d4\x05iks\x91k\xd3\x03>\x05R\x1e2\x11\xdf\xec\x02n\x98\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x05k\x15F\x89O\x9a\x85\xe2\x03\xfb3m\xb5i\xb1l%\xe0O\x89\t.\xdb\t\xff\b\u0600\x00\u07d4\x05yI\xe1\xca\x05pF\x9eL\xe3\u0190\xaea:k\x01\xc5Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x05}\u049f-\x19\xaa=\xa4#'\xeaP\xbc\xe8o\xf5\xc9\x11\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x05\u007f\u007f\x81\xcdz@o\xc4Y\x94@\x8bPI\x91,Vdc\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x05\x91]N\"Zf\x81b\xae\xe7\xd6\xc2_\xcf\xc6\xed\x18\xdb\x03\x89\x03\x98\xc3ry%\x9e\x00\x00\u07d4\x05\x96\xa2}\xc3\xee\x11_\xce/\x94\xb4\x81\xbc z\x9e&\x15%\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05\xa80rC\x02\xbc\x0fn\xbd\xaa\x1e\xbe\xee\xb4nl\xe0\v9\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\x05\xae\u007f\u053b\u0300\xca\x11\xa9\n\x1e\u01e3\x01\xf7\xcc\u0303\u06c91T\xc9r\x9d\x05x\x00\x00\u07d4\x05\xbbd\xa9\x16\xbef\xf4`\xf5\xe3\xb6C2\x11\r \x9e\x19\xae\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\x05\xbfO\xcf\xe7r\xe4[\x82dC\x85.l5\x13P\xcer\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\x05\xc6@\x04\xa9\xa8&\xe9N^N\xe2g\xfa*v2\xddNo\x8a\x03m\xc4.\xbf\xf9\v\u007f\x80\x00\xe0\x94\x05\xc76\xd3e\xaa7\xb5\xc0\xbe\x9c\x12\u022d\\\xd9\x03\xc3,\xf9\x8a\x01E^{\x80\n\x86\x88\x00\x00\xe0\x94\x05\xcbl;\x00r\xd3\x11ga\xb52\xb2\x18D;S\xe8\xf6\u014a\x1e\x02\xc3\xd7\xfc\xa9\xb6(\x00\x00\u07d4\x05\xd0\xf4\xd7(\xeb\xe8.\x84\xbfYu\x15\xadA\xb6\v\xf2\x8b9\x89\u3bb5sr@\xa0\x00\x00\u07d4\x05\u058d\xada\u04fb\u07f3\xf7y&\\IGJ\xff?\xcd0\x89\x02\"\xc5]\xc1Q\x9d\x80\x00\u07d4\x05\xe6q\xdeU\xaf\xec\x96K\aM\xe5t\xd5\x15\x8d]!\xb0\xa3\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x05\xe9{\tI,\u058fc\xb1+\x89.\xd1\xd1\x1d\x15,\x0e\u02897\b\xba\xed=h\x90\x00\x00\u07d4\x05\xf3c\x1fVd\xbd\xad]\x012\xc88\x8d6\xd7\u0612\t\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x06\t\xd8:l\xe1\xff\u0276\x90\xf3\xe9\xa8\x1e\x98>\x8b\xdcM\x9d\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4\x06\x1e\xa4\x87|\u0409D\xebd\u0096n\x9d\xb8\xde\xdc\xfe\xc0k\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06%\xd0`V\x96\x8b\x00\"\x06\xff\x91\x98\x01@$+\xfa\xa4\x99\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06(\xbf\xbeU5x/\xb5\x88@k\xc9f`\xa4\x9b\x01\x1a\xf5\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x061\u044b\xbb\xbd0\xd9\xe1s+\xf3n\xda\xe2\u0389\x01\xab\x80\x89\xa3\xf9\x88U\xec9\x90\x00\x00\u07d4\x061\xdc@\xd7NP\x95\xe3r\x9e\xdd\xf4\x95D\xec\xd49og\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\x067Y\xdd\x1cN6.\xb1\x93\x98\x95\x1f\xf9\xf8\xfa\xd1\xd3\x10h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06_\xf5u\xfd\x9c\x16\xd3\xcbo\u058f\xfc\x8fH?\xc3.\xc85\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06a\x8e\x9dWb\xdfb\x02\x86\x01\xa8\x1dD\x87\u05a0\xec\xb8\x0e\x89Hz\x9a0E9D\x00\x00\xe0\x94\x06fG\xcf\xc8]#\xd3v\x05W= \x8c\xa1T\xb2D\xd7l\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06xeJ\xc6v\x1d\xb9\x04\xa2\xf7\xe8Y^\xc1\xea\xacsC\b\x89/\x98\xb2\x9c(\x18\xf8\x00\x00\u07d4\x06\x86\n\x93RYU\xffbI@\xfa\xdc\xff\xb8\xe1I\xfdY\x9c\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94\x06\x8c\xe8\xbdn\x90*E\u02c3\xb5\x15A\xb4\x0f9\xc4F\x97\x12\x8a\x01\x1c\x0f\x9b\xadJF\xe0\x00\x00\u07d4\x06\x8e)\xb3\xf1\x91\xc8\x12\xa699\x18\xf7\x1a\xb93\xaehG\xf2\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x06\x8eeWf\xb9D\xfb&6\x19e\x87@\xb8P\xc9J\xfa1\x89\x01\xe8\u007f\x85\x80\x9d\xc0\x00\x00\u0794\x06\x96N-\x17\xe9\x18\x9f\x88\xa8 96\xb4\n\xc9nS<\x06\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x06\x99L\xd8:\xa2d\n\x97\xb2`\vA3\x9d\x1e\r>\xdel\x89\r\x8drkqw\xa8\x00\x00\u07d4\x06\x9e\u042bz\xa7}\xe5q\xf1a\x06\x05\x1d\x92\xaf\xe1\x95\xf2\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06\xac&\xad\x92\u02c5\x9b\u0550]\xdc\xe4&j\xa0\xecP\xa9\u0149*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x06\xb0\xc1\xe3\u007fZ^\u013b\xf5\b@T\x8f\x9d:\xc0(\x88\x97\x89\xd8\u0602\u148e}\x00\x00\u07d4\x06\xb0\xff\x83@s\xcc\xe1\xcb\xc9\xeaU~\xa8{`Yc\u8d09\x10CV\x1a\x88)0\x00\x00\xe0\x94\x06\xb1\x06d\x9a\xa8\xc4!\xdd\xcd\x1b\x8c2\xcd\x04\x18\xcf0\xda\x1f\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x06\xb5\xed\xe6\xfd\xf1\xd6\xe9\xa3G!7\x9a\xea\xa1|q=\xd8*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x06\xcb\xfa\b\xcd\xd4\xfb\xa77\xba\xc4\a\xbe\x82$\xf4\xee\xf3X(\x89 +\xe5\xe88.\x8b\x80\x00\u07d4\x06\xd6\xcb0\x84\x81\xc36\xa6\xe1\xa2%\xa9\x12\xf6\xe65Y@\xa1\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x06\xdc\u007f\x18\xce\xe7\xed\xab[yS7\xb1\xdfj\x9e\x8b\u062eY\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x06\xf6\x8d\xe3\xd79\xdbA\x12\x1e\xac\xf7y\xaa\xda=\xe8v!\a\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x06\xf7\u070d\x1b\x94b\xce\xf6\xfe\xb13h\xa7\xe3\x97K\t\u007f\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\a\x01\xf9\xf1G\xecHhV\xf5\xe1\xb7\x1d\xe9\xf1\x17\xe9\x9e!\x05\x89\te\xdaq\u007f\u0578\x00\x00\u07d4\a\r]6L\xb7\xbb\xf8\"\xfc,\xa9\x1a5\xbd\xd4A\xb2\x15\u0549lk\x93[\x8b\xbd@\x00\x00\xe0\x94\a\x1d\xd9\r\x14\xd4\x1fO\xf7\xc4\x13\xc2B8\xd35\x9c\xd6\x1a\a\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4\a&\xc4.\x00\xf4T\x04\x83n\xb1\xe2\x80\xd0s\xe7\x05\x96\x87\xf5\x89X\x00>?\xb9G\xa3\x80\x00\xe0\x94\a'\xbe\n*\x00! H\xb5R\x0f\xbe\xfb\x95>\xbc\x9dT\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a)\xa8\xa4\xa5\xba#\xf5y\xd0\x02[\x1a\xd0\xf8\xa0\xd3\\\xdf\u048a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\a)\xb4\xb4|\t\xeb\x16\x15\x84d\u022a\u007f\xd9i\vC\x889\x89lh\xcc\u041b\x02,\x00\x00\u0794\a4\xa0\xa8\x1c\x95b\xf4\xd9\xe9\xe1\n\x85\x03\xda\x15\xdbF\xd7n\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\a\xa7\xef[G\x00\x00\xe0\x94\ap\xc6\x1b\xe7\x87r#\f\xb5\xa3\xbb$)\xa7&\x14\xa0\xb36\x8a\x01n\u0899\xb7\x13A\x80\x00\u07d4\ar><0\xe8\xb71\xeeEj)\x1e\xe0\u7630 Jw\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\as\xee\xac\xc0P\xf7G \xb4\xa1\xbdW\x89[\x1c\xce\xebI]\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a\x80\r/\x80h\xe4H\u01daOi\xb1\xf1^\xf6\x82\xaa\xe5\xf6\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\a\xa8\xda\xde\xc1BW\x1a}S\xa4)pQxm\a,\xbaU\x89\x01;m\xa1\x13\x9b\u0680\x00\u07d4\a\xaf\x93\x8c\x127\xa2|\x900\tM\xcf$\aP$n=,\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\a\xb1\xa3\x06\xcbC\x12\xdffH,,\xaer\xd1\xe0a@\x0f\u034a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\a\xb7\xa5p3\xf8\xf1\x130\xe4f^\x18]#N\x83\xec\x14\v\x89\xea~\xe9*\f\x9a\v\x80\x00\u07d4\a\xbc,\xc8\xee\xdc\x01\x97\a\x00\xef\xc9\xc4\xfb6s^\x98\xcdq\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd4\x12\x17\xba\u0725\xe0\xe6\x03'\xd8E\xa3FO\x0f'\xf8J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd43N\u00c5\xe8\xaaT\xee\xda\xea\xdb0\x02/\f\u07e4\xab\x89\x8e\x91\xd5 \xf2\xeby\x00\x00\u07d4\a\xda\xe6\"c\r\x1168\x193\u04adk\"\xb89\xd8!\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\a\xdc+\xf8;\u01af\x19\xa8B\xff\xeaf\x1a\xf5\xb4\x1bg\xfd\xa1\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\a\u070c\x8b\x92z\xdb\xed\xfa\x8f]c\x9bCR5\x1f/6\u0489\x11\n\xed;U0\xdb\x00\x00\u07d4\a\xdd\xd0B,\x86\xefe\xbf\f\u007f\xc3E(b\xb1\"\x8b\b\xb8\x89o\xf5\u04aa\x8f\x9f\xcf\x00\x00\u07d4\a\xe1\x16,\xea\xe3\xcf!\xa3\xf6-\x10Y\x900.0\u007fN;\x89R\xf1\x03\xed\xb6k\xa8\x00\x00\u07d4\a\xe2\xb4\xcd\xee\xd9\u0407\xb1.Um\x9ew\f\x13\xc0\x99a_\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\a\xfe\xefT\xc16\x85\b)\xba\xdcKI\xc3\xf2\xa7<\x89\xfb\x9e\x89\x06hZ\xc1\xbf\xe3,\x00\x00\u07d4\b\x05FP\x8a=&\x82\u0239\x88O\x13c{\x88G\xb4M\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\t\bv\xba\xad\xfe\xe6\\=6;\xa5S\x12t\x8c\xfa\x87=\x89\\*\x997\x1c\xff\xe1\x00\x00\u07d4\b\x16o\x021?\xea\u12f0D\xe7\x87|\x80\x8bU\xb5\xbfX\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b)\xd0\xf7\xbb|Dl\xfb\xb0\u07ad\xb29M\x9d\xb7$\x9a\x87\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\b0m\xe5\x19\x81\u7b21\x85hY\xb7\xc7xijki\xf9\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\b7S\x9b_jR*H,\xdc\u04e9\xbbpC\xaf9\xbd\u048a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\b8\xa7v\x8d\x9c*\u028b\xa2y\xad\xfe\xe4\xb1\xf4\x91\xe3&\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\bA\x16R\xc8qq6\t\xaf\x00b\xa8\xa1(\x1b\xf1\xbb\xcf\u0649K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\bM\x102Tu\x9b4<\xb2\xb9\xc2\xd8\xff\x9e\x1a\xc5\xf1E\x96\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4\bPO\x05d?\xabY\x19\xf5\xee\xa5Y%\u05e3\xed}\x80z\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b[J\xb7]\x83b\xd9\x14C\\\xed\xee\x1d\xaa+\x1e\xe1\xa2;\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\b[\xa6_\xeb\xe2>\xef\xc2\xc8\x02fj\xb1&#\x82\xcf\u0114\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\bt\x98\xc0FFh\xf3\x11P\xf4\xd3\u013c\u0765\"\x1b\xa1\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\bw\uebabx\xd5\xc0\x0e\x83\xc3+-\x98\xfay\xadQH/\x89\x17\xd2-q\xdab&\x00\x00\u0794\b\x93j7\u07c5\xb3\xa1X\xca\xfd\x9d\xe0!\xf5\x817h\x13G\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\b\xa9\xa4N\x1fA\xde=\xbb\xa7\xa3c\xa3\xabA,\x12L\xd1^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xb7\xbd\u03d4MUp\x83\x8b\xe7\x04`$:\x86\x94HXX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xb8E6\xb7L\x8c\x01T=\xa8\x8b\x84\u05cb\xb9WG\xd8\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xc2\xf26\xacJ\xdc\xd3\xfd\xa9\xfb\xc6\xe4S\"S\xf9\xda;\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b\xc8\x02\xf8wX4\x9f\xa0>k\xc2\xe2\xfd\a\x91\x19~\ua689lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xc9\U0007fd89\xfd\xf8\x04\xd7i\xf8!#6\x02\x15\xaf\xf9;\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b\xca\u0215&A\xd8\xfcRn\xc1\xabO-\xf8&\xa5\xe7q\x0f\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\b\xcc\xdaP\xe4\xb2j\x0f\xfc\x0e\xf9.\x92\x051\a\x06\xbe\xc2\u01ca\x01Iul8W\xc6\x00\x00\x00\u07d4\b\u0406M\xc3/\x9a\xcb6\xbfN\xa4G\xe8\xddg&\x90j\x15\x89lnY\xe6|xT\x00\x00\u07d4\b\xd4&\u007f\xeb\x15\u0697\x00\xf7\xcc\xc3\xc8J\x89\x18\xbf\x17\xcf\u0789a\t=|,m8\x00\x00\xe0\x94\b\xd41\x1c\x9c\x1b\xba\xf8\u007f\xab\xe1\xa1\xd0\x14c\x82\x8d]\x98\u038a\x13\x0e\xe8\xe7\x17\x90D@\x00\x00\u07d4\b\xd5N\x83\xadHj\x93L\xfa\xea\u20e3>\xfd\"|\x0e\x99\x898S\x05\x83$^\xdc\x00\x00\u07d4\b\xd9~\xad\xfc\xb7\xb0d\xe1\xcc\xd9\u0217\x9f\xbe\xe5\xe7z\x97\x19\x89\x0el]\xa8\xd6z\xc1\x80\x00\u07d4\b\xda:z\x0fE!a\u03fc\xec1\x1b\xb6\x8e\xbf\xde\xe1~\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xe3\x8e\xe0\xceH\xc9\xcad\\\x10\x19\xf7;SUX\x1cV\xe6\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\b\xef?\xa4\xc4<\xcd\xc5{\"\xa4\xb9\xb23\x1a\x82\xe58\x18\xf2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\td\x8c\x18\xa3\xce[\xaez\x04~\xc2\xf8h\xd2L\u0768\x1d\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\t\f\xd6{`\xe8\x1dT\xe7\xb5\xf6\a\x8f>\x02\x1b\xa6[\x9a\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\f\xeb\xef),>\xb0\x81\xa0_\u062a\xf7\u04db\xf0{\x89\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\x0f\xa96{\xdaW\xd0\xd3%:\n\x8f\xf7l\xe0\xb8\xe1\x9as\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x14n\xa3\x88Qv\xf0w\x82\xe1\xfe0\xdc\xe3\xce$\u011e\x1f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\t!`_\x99\x16N;\xcc(\xf3\x1c\xae\xcex\x971\x82V\x1d\x89+\ai*\x90e\xa8\x00\x00\xe0\x94\t&\x1f\x9a\xcbE\x1c7\x88\x84O\f\x14Q\xa3[\xadP\x98\xe3\x8a\x01\u056d'P) `\x00\x00\xe0\x94\t'\"\x04\x92\x19K.\u069f\u013b\xe3\x8f%\u0581\xdf\xd3l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\t*\xcbbK\b\xc0U\x10\x18\x9b\xbb\xe2\x1ee$\xd6D\u032d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t.\x81UX@-g\xf9\rk\xfem\xa0\xb2\xff\xfa\x91EZ\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\tP0\xe4\xb8&\x92\xdc\xf8\xb8\u0411$\x94\xb9\xb3x\xec\x93(\x89H\xa4zu\x80\x00\u07d4\t\x89\xc2\x00D\v\x87\x89\x91\xb6\x9d`\x95\xdf\xe6\x9e3\xa2.p\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\t\x90\xe8\x1c\u05c5Y\x9e\xa26\xbd\x19f\xcfRc\x02\xc3[\x9c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x98\xd8'1\x15\xb5j\xf4%\xff\xc8>!\x8c\x1e\n\xfe\x89(\u01c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t\xaeI\xe3\u007f\x12\x1d\xf5\xdc\x15\x8c\xfd\xe8\x06\xf1s\xa0k\f\u007f\x89\xd80\x9e&\xab\xa1\xd0\x00\x00\u07d4\t\xaf\xa7;\xc0G\xefF\xb9w\xfd\x97c\xf8r\x86\xa6\xbeh\u0189\x1b/\xb5\xe8\xf0jf\x00\x00\u07d4\t\xb4f\x86\x96\xf8j\b\x0f\x8b\xeb\xb9\x1d\xb8\xe6\xf8p\x15\x91Z\x89#\x8f\xf7\xb3O`\x01\x00\x00\xe0\x94\t\xb5\x9b\x86\x98\xa7\xfb\xd3\xd2\xf8\xc7:\x00\x89\x88\xde>@k+\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\t\xb7\xa9\x88\xd1?\xf8\x91\x86so\x03\xfd\xf4au\xb5=\x16\xe0\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xc1w\xf1\xaeD$\x11\u076c\xf1\x87\xd4m\xb9V\x14\x83`\xe7\x8a\x01\xe5.3l\xde\"\x18\x00\x00\xe0\x94\t\u020f\x91~Mj\xd4s\xfa\x12\u93a3\xc4G*^\xd6\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\t\u0438\xcd\a|i\xd9\xf3-\x9c\xcaC\xb3\xc2\b\xa2\x1e\u050b\x89\b!\xd2!\xb5)\x1f\x80\x00\xe0\x94\t\xd6\xce\xfdu\xb0\u0133\xf8\xf1\u0587\xa5\"\xc9a#\xf1\xf59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xe47\xd4H\x86\x12(\xa22\xb6.\xe8\xd3ye\xa9\x04\ud70a\x04\x98\xcf@\x1d\xf8\x84.\x80\x00\u07d4\t\xee\x12\xb1\xb4+\x05\xaf\x9c\xf2\a\xd5\xfc\xac%[.\xc4\x11\xf2\x89\x031\xcd\xddG\xe0\xfe\x80\x00\u07d4\t\xf3\xf6\x01\xf6\x05D\x11@Xl\xe0eo\xa2J\xa5\xb1\u066e\x89Sswo\xe8\xc4T\x00\x00\u07d4\t\xf9W[\xe5}\x00G\x93\u01e4\ub137\x15\x87\xf9|\xbbj\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\x06P\x86\x1fx^\xd8\xe4\xbf\x10\x05\xc4P\xbb\xd0n\xb4\x8f\xb6\x89\xa6A;y\x14N~\x00\x00\u07d4\n\x06\xfa\xd7\xdc\u05e4\x92\xcb\xc0S\xee\xab\xdei4\xb3\x9d\x867\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n\a}\xb1?\xfe\xb0\x94\x84\xc2\x17p\x9dX\x86\xb8\xbf\x9cZ\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n\x0e\u0366cow\x16\xef\x19saF\x87\xfd\x89\xa8 \xa7\x06\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\n)\xa8\xa4\xd5\xfd\x95\x00u\xff\xb3Mw\xaf\xeb-\x82;\u0589\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n*\u0795\xb2\xe8\xc6m\x8a\xe6\xf0\xbad\xcaW\u05c3\xbemD\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n+O\xc5\xd8\x1a\xceg\xdcK\xba\x03\xf7\xb4UA=F\xfe=\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\n-\xcbzg\x17\x01\u06f8\xf4\x95r\x80\x88&Xs5l\x8e\x89\b?\x16\xce\b\xa0l\x00\x00\u07d4\n=\xe1U\xd5\xec\xd8\xe8\x1c\x1f\xf9\xbb\xf07\x83\x01\xf8\xd4\xc6#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\nG\xad\x90Y\xa2I\xfc\x93k&b5=\xa6\x90_u\u00b9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\nH)ov1p\x8c\x95\u04b7Iu\xbcJ\xb8\x8a\xc19*\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\nJ\x01\x19\x95\u0181\xbc\x99\x9f\xddyuN\x9a2J\xe3\xb3y\x8a\b\xc1\x9a\xb0n\xb8\x9a\xf6\x00\x00\u07d4\nX\xfd\xddq\x89\x8d\xe7s\xa7O\xda\xe4^{\xd8N\xf46F\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n[y\xd8\xf2;d\x83\xdb\u2f6ab\xb1\x06L\xc7cf\xae\x89j\u0202\x10\tR\u01c0\x00\u07d4\ne.*\x8bw\xbd\x97\xa7\x90\xd0\xe9\x13a\u0248\x90\u06f0N\x8965\u026d\xc5\u07a0\x00\x00\u07d4\nn\xber;n\xd1\xf9\xa8ji\xdd\xdah\xdcGF\\+\x1b\x89@=-\xb5\x99\xd5\xe4\x00\x00\u07d4\nw\xe7\xf7+C{WO\x00\x12\x8b!\xf2\xac&Q3R\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\n\x91\u007f;\\\xb0\xb8\x83\x04\u007f\u0676Y=\xbc\xd5W\xf4S\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\n\x93\x1bD\x9e\xa8\xf1,\xdb\xd5\xe2\xc8\xccv\xba\xd2\xc2|\x069\x89\x01?\x9e\x8cy\xfe\x05\x80\x00\u0794\n\x98\x04\x13x\x03\xbahh\xd9:U\xf9\x98_\xcdT\x04Q\u4239\x8b\xc8)\xa6\xf9\x00\x00\u07d4\n\x9a\xb2c\x8b\x1c\xfdeM%\u06b0\x18\xa0\xae\xbd\u07c5\xfdU\x89\x01.\x8c\xb5\xfeLJ\x80\x00\u07d4\n\xb3f\xe6\xe7\u056b\xbc\xe6\xb4JC\x8di\xa1\u02bb\x90\xd13\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\n\xb4(\x1e\xbb1\x85\x90\xab\xb8\x9a\x81\xdf\a\xfa:\xf9\x04%\x8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\n\xb5\x9d9\a\x02\xc9\xc0Y\xdb\x14\x8e\xb4\xf3\xfc\xfa}\x04\xc7\xe7\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\n\xbf\xb3\x9b\x11HmyW(f\x19[\xa2lc\vg\x84\u06ca\x19\xba\x877\xf9i(\xf0\x00\x00\u07d4\n\u029aV&\x91;\b\xcf\u0266m@P\x8d\xceR\xb6\x0f\x87\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\n\xd3\xe4M<\x00\x1f\xa2\x90\xb3\x93ap0TA\b\xacn\xb9\x89j\xbd\xa0\xbc0\xb2\u07c0\x00\u07d4\n\xec.Bn\xd6\xcc\f\xf3\xc2I\xc1\x89~\xacG\xa7\xfa\xa9\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\xf6_\x14xNU\xa6\xf9Vg\xfds%*\x1c\x94\a-*\x89\nv;\x8e\x02\xd4O\x80\x00\u07d4\n\xf6\xc8\xd59\xc9mP%\x9e\x1b\xa6q\x9e\x9c\x80`\xf3\x88\u008965\u026d\xc5\u07a0\x00\x00\u07d4\v\x069\x0f$7\xb2\x0e\u0123\xd3C\x1b2y\xc6X>^\u05c9\n\x84Jt$\xd9\xc8\x00\x00\u07d4\v\v8b\x11*\xee\u00e04\x92\xb1\xb0_D\x0e\xcaT%n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\x0e\x05[(\xcb\xd0=\xc5\xffD\xaad\xf3\xdc\xe0O^c\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x11\x9d\xf9\x9ck\x8d\xe5\x8a\x1e,?)zgD\xbfU\"w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x14\x89\x19\x99\xa6\\\x9e\xf73\b\xef\xe3\x10\f\xa1\xb2\x0e\x81\x92\x89+^:\xf1k\x18\x80\x00\x00\u07d4\v!\x13PE4d*\x1d\xaf\x10.\xee\x10\xb9\xeb\xdev\xe2a\x89\x94,\xdd|\x95\xf2\xbd\x80\x00\xe0\x94\v(\x8aZ\x8bu\xf3\xdcA\x91\xeb\x04W\xe1\xc8=\xbd M%\x8a\x01\a\x14\xe7{\xb4:\xb4\x00\x00\u07d4\v6\x9e\x00.\x1bLy\x13\xfc\xf0\x0f-^\x19\u0141eG\x8f\x89\x03\u007fe\x16(\x8c4\x00\x00\u07d4\vC\xbd#\x91\x02U\x81\u0615l\xe4*\a%y\u02ff\xcb\x14\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\vP|\xf5SV\x8d\xaa\xf6U\x04\xaeN\xaa\x17\xa8\xea<\xdb\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v]f\xb1<\x87\xb3\x92\xe9M\x91\xd5\xf7l\rE\nU(C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v^ \x11\xeb\xc2Z\x00\u007f!6)`I\x8a\xfb\x8a\xf2\x80\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vd\x9d\xa3\xb9j\x10,\xdcm\xb6R\xa0\xc0}e\xb1\xe4C\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vi \xa6K6;\x8d]\x90\x80$\x94\xcfVKT|C\r\x89A\rXj \xa4\xc0\x00\x00\u07d4\vp\x11\x01\xa4\x10\x9f\x9c\xb3`\xdcW\xb7tBg=^Y\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vq\xf5T\x12$i\uf5ce/\x1f\xef\xd7\u02f4\x10\x98'r\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\xe0\x94\v{\xb3B\xf0\x1b\u0248\x8ej\x9a\xf4\xa8\x87\xcb\xf4\xc2\xdd,\xaf\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\v}3\x93q\xe5\xbeg'\xe6\xe31\xb5\x82\x1f\xa2K\u06ddZ\x89.\u007f\x81\x86\x82b\x01\x00\x00\u07d4\v\u007f\xc9\xdd\xf7\x05v\xf63\x06i\xea\xaaq\xb6\xa81\xe9\x95(\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\v\x80\xfcp(,\xbd\xd5\xfd\xe3[\xf7\x89\x84\xdb;\xdb\x12\x01\x88\x8968\x02\x1c\xec\u06b0\x00\x00\u07d4\v\x92M\xf0\a\xe9\xc0\x87\x84\x17\xcf\xe6;\x97n\xa1\xa3\x82\xa8\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\v\x93\xfc\xa4\xa4\xf0\x9c\xac \xdb`\xe0e\xed\xcc\xcc\x11\u0976\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\v\x9d\xf8\x0f\xbe# \t\xda\xcf\n\xa8\xca\u0153v\xe2Gb\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xa6\xe4j\xf2Z\x13\xf5qi%Z4\xa4\xda\xc7\xce\x12\xbe\x04\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\v\xa8p[\xf5\\\xf2\x19\xc0\x95k^?\xc0\x1cDt\xa6\xcd\xc1\x89\x05%\xe0Y]Mk\x80\x00\u07d4\v\xafn\u0379\x1a\xcb6\x06\xa85|\v\xc4\xf4\\\xfd-~o\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xb0_r$\xbbX\x04\x85eV\xc0~\xea\xdb\ud1fa\x8f|\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\v\xb0\xc1&\x82\xa2\xf1\\\x9bWA\xb28\\\xbeA\xf04\x06\x8e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\v\xb2\\\xa7\u0448\xe7\x1eMi={\x17\a\x17\xd6\xf8\xf0\xa7\n\x89\x12C\x02\xa8/\xad\xd7\x00\x00\u07d4\v\xb2e\x0e\xa0\x1a\xcau[\xc0\xc0\x17\xb6K\x1a\xb5\xa6m\x82\xe3\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb5Lr\xfdf\x10\xbf\xa463\x97\xe0 8K\x02+\fI\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb7\x16\n\xba)7b\xf8sO>\x03&\xff\u0264\xca\xc1\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xc9\\\xb3-\xbbWL\x83/\xa8\x17J\x815m8\xbc\x92\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xd6}\xbd\xe0z\x85n\xbd\x89;^\xdcO:[\xe4 &\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xdb\xc5L\u023d\xbb\xb4\x02\xa0\x89\x11\xe2#*T`\u0386k\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\v\xddX\xb9n|\x91m\xd2\xfb05o*\xeb\xfa\xaf\x1d\x860\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\v\u1f39\x03C\xfa\xe501s\xf4a\xbd\x91JH9\x05l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\v\xe1\xfd\xf6&\xeea\x89\x10-p\xd1;1\x01,\x95\xcd\x1c\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xe2\xb9J\xd9P\xa2\xa6&@\xc3[\xfc\xcdlg\xda\xe4P\xf6\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\v\u681eC\a\xfeH\xd4\x12\xb8\u0461\xa8(M\xceHba\x8a\x04\x0f\xbf\xf8\\\x0180\x00\x00\u07d4\v\xef\xb5G\a\xf6\x1b,\x9f\xb0G\x15\xab\x02n\x1b\xb7 B\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\xf0dB\x8f\x83bg\"\xa7\xb5\xb2j\x9a\xb2\x04!\xa7r>\x89\a?u\u0460\x85\xba\x00\x00\u07d4\v\xfb\xb6\x92]\xc7^R\xcf&\x84\"K\xbe\x05P\xfe\xa6\x85\u04c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\f\b\x80\x06\xc6K0\xc4\u076f\xbc6\xcb_\x05F\x9e\xb6(4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f s\xbaD\xd3\u077d\xb69\xc0N\x19\x109\xa7\x17\x16#\u007f\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\f\",|A\u0270H\xef\xcc\xe0\xa22CCb\xe1-g;\x8a\x02\x1e\x83Yivw8\x00\x00\xe0\x94\f(\b\xb9Q\ud787-{2y\x0f\xccY\x94\xaeA\xff\u070a\x15\x99n[<\u05b3\xc0\x00\x00\u07d4\f(\x84~O\t\xdf\xce_\x9b%\xaf|NS\x0fY\u0200\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f-\\\x92\x058\xe9S\u02af$\xf0s\u007fUL\u0192wB\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f0\xca\xcc?r&\x9f\x8bO\x04\xcf\a=+\x05\xa8=\x9a\u0449lyt\x12?d\xa4\x00\x00\u07d4\f29\xe2\xe8A$-\xb9\x89\xa6\x15\x18\xc2\"G\xe8\xc5R\b\x89\x0eJ\xf6G\x174d\x00\x00\xe0\x94\fH\r\xe9\xf7F\x10\x02\x90\x8bI\xf6\x0f\xc6\x1e+b\xd3\x14\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\fH\xaeb\xd1S\x97\x88\xeb\xa0\x13\xd7^\xa6\vd\xee\xbaN\x80\x89w\xfb\xdcC\xe00\x99\x80\x00\u07d4\fU\x89\xa7\xa8\x9b\x9a\xd1[\x02u\x190AYH\xa8u\xfb\xef\x89\x06\u0519\xeclc8\x00\x00\u07d4\fg\x03=\xd8\xee\u007f\f\x8a\xe54\xd4*Q\xf7\xd9\xd4\xf7\x97\x8f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\fhE\xbfA\xd5\xee'<>\u6d70\u059fo\xd5\xea\xbb\xf7\x89\xa2\xa1\xb9h.X\t\x00\x00\xe0\x94\f\u007f\x86\x9f\x8e\x90\xd5?\xdc\x03\u8c81\x9b\x01k\x9d\x18\xeb&\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\f\x86\x92\xee\xff*S\xd6\xd1h\x8e\xd5j\x9d\u06fdh\u06bb\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\x8ff\xc6\x01{\xce[ 4r\x04\xb6\x02\xb7C\xba\u05cd`\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\f\x8f\xd7w^T\xa6\xd9\u0263\xbf\x89\x0ev\x1fewi?\xf0\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\f\x92Z\xd5\xeb5,\x8e\xf7m\f\"-\x11[\a\x91\xb9b\xa1\x89\xacc]\u007f\xa3N0\x00\x00\u07d4\f\x96~0a\xb8zu>\x84P~\xb6\t\x86x,\x8f0\x13\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\f\xa1*\xb0\xb9fl\xf0\xce\xc6g\x1a\x15)/&SGj\xb2\x8a,x'\xc4-\"\xd0|\x00\x00\u07d4\f\xa6p\xeb,\x8b\x96\u02e3y!\u007fY)\u00b8\x92\xf3\x9e\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\xae\x10\x8em\xb9\x9b\x9ecxv\xb0d\xc60>\u068ae\u0209\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\f\xbd\x92\x1d\xbe\x12\x15c\xb9\x8ahq\xfe\xcb\x14\xf1\xcc~\x88\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\f\xbf\x87p\xf0\xd1\b.\\ \u016e\xad4\xe5\xfc\xa9\xaez\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f\xc6\u007f\x82s\xe1\xba\xe0\x86\u007f\xd4.\x8b\x81\x93\xd7&y\xdb\xf8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\f\u05a1A\x91\x8d\x12k\x10m\x9f.\xbfi\xe1\x02\xdeM2w\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\f\xda\x12\xbfr\xd4a\xbb\xc4y\xeb\x92\xe6I\x1d\x05~kZ\u044a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\f\u0716\v\x99\x8c\x14\x19\x98\x16\r\xc1y\xb3l\x15\u0484p\xed\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\f\xfb\x17#5\xb1l\x87\xd5\x19\xcd\x14uS\r W\u007f^\x0e\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\r\x1f*Wq>\xbcn\x94\xde)\x84n\x88D\xd3vfWc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\r2e\xd3\u7f79=^\x8e\x8b\x1c\xa4\u007f!\ny>\u030e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r5@\x8f\"ef\x11o\xb8\xac\u06a9\xe2\xc9\u055bvh?\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\rU\x1e\xc1\xa2\x13<\x98\x1d_\u01a8\xc8\x17?\x9e|OG\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r]\x98V\\d|\xa5\xf1w\xa2\xad\xb9\xd3\x02/\xac(\u007f!\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\re\x80\x14\xa1\x99\x06\x1c\xf6\xb3\x943\x14\x03\x03\xc2\x0f\xfdNZ\x8a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\rg\x87\x06\xd07\x18\u007f>\"\xe6\xf6\x9b\x99\xa5\x92\xd1\x1e\xbcY\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\ri\x10\f9\\\xe6\xc5\xea\xad\xf9]\x05\xd8r\x83~\xde\xdd!\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\rt~\u559b\xf7\x9dW8\x1do\xe3\xa2@l\xd0\xd8\xce'\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\r\x80#\x92\x9d\x91r4\xae@Q+\x1a\xab\xb5\xe8\xa4Q'q\x89\b\x05\xe9\x9f\xdc\xc5\xd0\x00\x00\xe0\x94\r\x8a\xab\x8ft\xea\x86,\xdfvh\x05\x00\x9d?>B\xd8\xd0\v\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\r\x8c@\xa7\x9e\x18\x99O\xf9\x9e\xc2Q\xee\x10\u0408\u00d1.\x80\x89\x066d\xfc\u04bb\xc4\x00\x00\u07d4\r\x8e\xd7\xd0\xd1V83\x0e\xd7\xe4\xea\u032b\x8aE\x8dus~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\x92X/\u06e0^\xab\xc3\xe5\x158\xc5m\xb8\x817\x85\xb3(\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\r\x94C\xa7\x94h\xa5\xbb\xf7\xc1\xe5\xb9\x15\xb3d\x87\xf9\x16\x1f\x19\x84m\x10\x1431\x8a\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\r\xbdA|7+\x8b\r\x01\xbc\xd9Dpk\xd3.`\xae(\u0449\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\r\xc1\x00\xb1\a\x01\x1c\u007f\xc0\xa13\x96\x12\xa1l\xce\xc3(R\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\u03dd\x8c\x98\x04E\x9fd|\x14\x13\x8e\xd5\x0f\xadV;AT\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\r\xcf\xe87\xea\x1c\xf2\x8ce\xfc\xce\u00fe\xf1\xf8NY\xd1P\xc0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r\xd4\xe6t\xbb\xad\xb1\xb0\u0702D\x98q=\xce;QV\xda)\x89\t79SM(h\x00\x00\u07d4\r\xfb\u0501pP\xd9\x1d\x9db\\\x02\x05<\xf6\x1a>\xe2\x85r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x0e\x02N\u007f\x02\x9cj\xaf:\x8b\x91\x0f^\b\bs\xb8W\x95\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\tdl\x99\xafC\x8e\x99\xfa'L\xb2\xf9\xc8V\xcbe\xf76\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x0e\f\x9d\x00^\xa0\x16\u0095\xcdy\\\xc9!>\x87\xfe\xbc3\xeb\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\x0e\rf3\xdb\x1e\f\u007f#Jm\xf1c\xa1\x0e\n\xb3\x9c \x0f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x0e\x11\xd7z\x89w\xfa\xc3\r&\x84E\xe51\x14\x9b1T\x1a$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x12=}\xa6\xd1\xe6\xfa\xc2\u072d\xd2p)$\v\xb3\x90R\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\x18\x01\xe7\vbb\x86\x1b\x114\u033c9\x1fV\x8a\xfc\x92\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e \x94\xac\x16T\xa4k\xa1\xc4\u04e4\v\xb8\xc1}\xa7\U000d6209\x13h?\u007f<\x15\xd8\x00\x00\u07d4\x0e!\xaf\x1b\x8d\xbf'\xfc\xf6?7\xe0G\xb8z\x82\\\xbe|'\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x0e.PJ-\x11\"\xb5\xa9\xfe\xee\\\xb1E\x1b\xf4\u00ac\xe8{\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x0e/\x8e(\xa6\x81\xf7|X;\xd0\xec\xde\x16cK\xdd~\x00\u0349\x05'8\xf6Y\xbc\xa2\x00\x00\u07d4\x0e2\x02\x19\x83\x8e\x85\x9b/\x9f\x18\xb7.=@s\xcaP\xb3}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e3\xfc\xbb\xc0\x03Q\v\xe3W\x85\xb5*\x9c]!k\xc0\x05\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x0e6\x96\xcf\x1fB\x17\xb1c\u047c\x12\xa5\xeas\x0f\x1c2\xa1J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e9\x0fD\x05=\xdf\xce\xf0\xd6\b\xb3^M\x9c,\xbe\x98q\xbb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x0e:(\xc1\u07ef\xb0P[\xdc\xe1\x9f\xe0%\xf5\x06\xa6\xd0\x1c\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e=\xd7\xd4\xe4)\xfe90\xa6A@5\xf5+\xdcY\x9dxM\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\x0eGey\x03Rek\xc6Vh,$\xfc^\xf3\xe7j#\u01c9\x02\x86\xd7\xfc\f\xb4\xf5\x00\x00\u07d4\x0eI\x88\x00Dqw\xb8\u022f\xc3\xfd\xfa\u007fi\xf4\x05\x1b\xb6)\x89t\x05\xb6\x9b\x8d\xe5a\x00\x00\u07d4\x0ek\xaa\xa3\u07b9\x89\xf2\x89b\x00vf\x86\x18\xe9\xac3(e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x0el\xd6d\xad\x9c\x1e\xd6K\xf9\x87I\xf4\x06D\xb6&\xe3y,\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\xe0\x94\x0em\xfdU;.\x87=*\xec\x15\xbd_\xbb?\x84r\xd8\u04d4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\x0en\xc3\x137bq\xdf\xf5T#\xabT\"\xcc:\x8b\x06\xb2+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x0en\u0399\x11\x1c\xad\x19a\xc7H\xed=\xf5\x1e\xddi\u04a3\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x0e\x83\xb8PH\x1a\xb4MI\xe0\xa2)\xa2\xe4d\x90,iS\x9b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\x89\xed\xdd?\xa0\xd7\x1d\x8a\xb0\xff\x8d\xa5X\x06\x86\xe3\xd4\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x90\x96\xd3C\xc0`\xdbX\x1a\x12\x01\x12\xb2x`~\xc6\xe5+\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x0e\x9cQ\x18d\xa1w\xf4\x9b\xe7\x82\x02w?`H\x9f\xe0NR\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x0e\xa2\xa2\x101+>\x86~\xe0\xd1\xcch,\xe1\xd6f\xf1\x8e\u054a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0e\xb1\x89\xef,-Wb\xa9c\u05b7\xbd\xf9i\x8e\xa8\u7d0a\x89Hz\x9a0E9D\x00\x00\xe0\x94\x0e\xb5\xb6b\xa1\xc7\x18`\x8f\xd5/\f%\xf97\x880\x17\x85\x19\x8a\x01J7(\x1aa.t\x00\x00\xe0\x94\x0e\xc4f\x96\xff\xac\x1fX\x00_\xa8C\x98$\xf0\x8e\xed\x1d\xf8\x9b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x0e\xc5\n\xa8#\xf4e\xb9FK\v\xc0\u0125w$\xa5U\xf5\u058a\f\x83\xd1Bj\u01f1\xf0\x00\x00\u07d4\x0e\xc50\x8b1(.!\x8f\xc9\xe7Y\xd4\xfe\xc5\xdb7\b\xce\u01096C\xaady\x86\x04\x00\x00\u07d4\x0e\xcc\xf6\x17\x84O\xd6\x1f\xbab\xcb\x0eD[z\u018b\xcc\x1f\xbe\x89\x14\xfeO\xe65e\xc6\x00\x00\u07d4\x0e\u04fb:N\xb5T\xcf\u0297\x94}WU\a\xcd\xfdm!\u0609\x1d\xb3 _\xcc#\u0540\x00\u07d4\x0e\xd7l,;]P\xff\x8f\xb5\v>\xea\xcdh\x15\x90\xbe\x1c-\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\u0680\xf4\xed\aJ\xeaiz\xed\xdf(;c\xdb\xca=\xc4\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\xddKX\x0f\xf1\x0f\xe0lJ\x03\x11b9\xef\x96b+\xae5\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x0e\xe3\x91\xf0^\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0f\x92\x9c\xf8\x95\xdb\x01z\xf7\x9f>\xad\"\x16\xb1\xbdi\xc3}\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa0\x10\xce\fs\x1d;b\x8e6\xb9\x1fW\x13\x00\u477e\xab\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\x0f\xa5\xd8\u0173\xf2\x94\xef\u0515\xabi\xd7h\xf8\x18rP\x85H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa6\u01f0\x97=\v\xae)@T\x0e$}6'\xe3|\xa3G\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0f\xad\x05P|\u070f$\xb2\xbeL\xb7\xfa]\x92}\u06d1\x1b\x88\x89\xa2\xdf\x13\xf4A\xf0\t\x80\x00\u07d4\x0f\xb5\xd2\xc6s\xbf\xb1\xdd\xca\x14\x1b\x98\x94\xfdm?\x05\xdag \x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0f\u0260\xe3AE\xfb\xfd\xd2\xc9\u04a4\x99\xb6\x17\u05e0)i\xb9\x89\t\xc2\x00vQ\xb2P\x00\x00\xe0\x94\x0f\xcf\xc4\x06P\b\xcf\xd3#0_b\x86\xb5zM\xd7\xee\xe2;\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x0f\xdde@#\x95\u07db\u045f\xeeE\a\xefSE\xf7E\x10L\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x0f\xecN\xe0\xd7\xca\x18\x02\x90\xb6\xbd \xf9\x99#B\xf6\x0f\xf6\x8d\x89\x12 \u007f\x0e\xdc\xe9q\x80\x00\u07d4\x0f\ue06c3\x1e\xfd\x8f\x81\x16\x1cW8+\xb4P{\xb9\xeb\xec\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\u07d4\x0f\xfe\xa0mq\x13\xfbj\xec(i\xf4\xa9\u07f0\x90\a\xfa\xce\xf4\x89\f8F\x81\xb1\xe1t\x00\x00\u07d4\x10\tq\x98\xb4\xe7\xee\x91\xff\x82\xcc/;\xd9_\xeds\xc5@\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x10\vM\tw\xfc\xba\xd4\u07bd^d\xa0Iz\xea\xe5\x16\x8f\xab\x89\x11\f\x90s\xb5$Z\x00\x00\xe0\x94\x10\x1a\nd\xf9\xaf\xccD\x8a\x8a\x13\rM\xfc\xbe\xe8\x957\xd8T\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\u07d4\x10,G}i\xaa\u06e9\xa0\xb0\xf6+tY\xe1\u007f\xbb\x1c\x15a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x101\xe0\xec\xb5I\x85\xae!\xaf\x17\x93\x95\r\xc8\x11\x88\x8f\xde|\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x104d\x14\xbe\xc6\xd3\xdc\xc4NP\xe5MT\u00b8\xc3sN>\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x108\x98X\xb8\x00\xe8\xc0\xec2\xf5\x1e\xd6\x1a5YF\xcc@\x9b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x10Y\xcb\xc6>6\xc4>\x88\xf3\x00\b\xac\xa7\xce\x05\x8e\ua816\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\x10n\xd5\xc7\x19\xb5&\x14w\x89\x04%\xaeuQ\xdcY\xbd%\\\x8a\x02\x89jX\xc9[\xe5\x88\x00\x00\u07d4\x10q\x1c=\xda21x\x85\xf0\xa2\xfd\x8a\xe9.\x82\x06\x9b\r\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x10sy\xd4\xc4gFO#[\xc1\x8eU\x93\x8a\xad>h\x8a\u05c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x10v!-Ou\x8c\x8e\xc7\x12\x1c\x1c}t%I&E\x92\x84\x8a\ai[Y\xb5\xc1{L\x00\x00\u07d4\x10x\xd7\xf6\x1b\x0eV\xc7N\xe6c[.\x18\x19\xef\x1e=\x87\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x10z\x03\xcf\bB\xdb\u07b0a\x8f\xb5\x87\xcai\x18\x9e\xc9/\xf5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x10\x80\xc1\xd85\x8a\x15\xbc\x84\xda\xc8%\x89\u0392\xb9\x81\x89t\xc1\xfa\xb8\xad\xb4T\x00\x00\u07d4\x10\xe1\xe37x\x85\xc4-}\xf2\x18R.\xe7vh\x87\xc0^j\x89\x10C\xc4<\xde\x1d9\x80\x00\u07d4\x10\u342d+\xa3=\x82\xb3s\x88\u041cED\u01b0\"]\xe5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x10\xf4\xbf\xf0\u02a5\x02|\nj-\xcf\xc9R\x82M\xe2\x94\t\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\x00\x1b\x89\xed\x87>:\xae\xc1\x15V4\xb4h\x16C\x98c#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x11\x027\u03d1\x17\xe7g\x92/\u0121\xb7\x8dyd\u0682\xdf \x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x11\x11\xe5\xdb\xf4^o\x90mb\x86o\x17\b\x10\x17\x88\xdd\xd5q\x89F{\xe6S>\xc2\xe4\x00\x00\xe0\x94\x11\x17+'\x8d\xddD\xee\xa2\xfd\xf4\xcb\x1d\x16\x96#\x91\xc4S\u064a\xc6/=\x9b\xfdH\x95\xf0\x00\x00\u07d4\x11&4\xb4\xec0\xffxn\x02AY\xf7\x96\xa5y9\xea\x14N\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x110l}WX\x867x\x0f\xc9\xfd\xe8\xe9\x8e\xcb\x00\x8f\x01d\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x116\x12\xbc;\xa0\xeeH\x98\xb4\x9d\xd2\x023\x90_/E\x8fb\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x11A_\xaba\xe0\xdf\u0539\x06v\x14\x1aUz\x86\x9b\xa0\xbd\xe9\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x11L\xbb\xbfo\xb5*\xc4\x14\xbe~\xc6\x1f{\xb7\x14\x95\xce\x1d\xfa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x11L\xfe\xfeP\x17\r\xd9z\xe0\x8f\nDTIx\u0159T\x8d\x89.\u0207\xe7\xa1J\x1c\x00\x00\u07d4\x11a\b\xc1 \x84a.\xed\xa7\xa9=\xdc\xf8\xd2`.'\x9e\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11d\u02aa\x8c\u0157z\xfe\x1f\xad\x8a}`(\xce-W)\x9b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x11gZ%UF\a\xa3\xb6\xc9*\x9e\xe8\xf3ou\xed\xd3\xe36\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x11j\t\xdff\xcb\x15\x0e\x97W\x8e)\u007f\xb0n\x13\x04\f\x89<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11o\xef^`\x16B\xc9\x18\u02c9\x16\x0f\xc2);\xa7\x1d\xa96\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x11xP\x1f\xf9J\xdd\x1cX\x81\xfe\x88a6\xf6\xdf\xdb\xe6\x1a\x94\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x11y\xc6\r\xbd\x06\x8b\x15\v\aM\xa4\xbe#\x03; \u0185X\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\x11}\x9a\xa3\xc4\xd1;\xee\x12\xc7P\x0f\t\xf5\xdd\x1cf\xc4e\x04\x89\v*\xd3\x04\x90\xb2x\x00\x00\xe0\x94\x11}\xb867\u007f\xe1TU\xe0,.\xbd\xa4\v\x1c\xebU\x1b\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x11\x8c\x18\xb2\xdc\xe1p\xe8\xf4Eu;\xa5\xd7Q<\xb7cm-\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\x11\x8f\xbdu;\x97\x929Z\xefzMx\xd2c\xcd\u02ab\xd4\xf7\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94\x11\x92\x83x\xd2}U\xc5 \xce\xed\xf2L\xeb\x1e\x82-\x89\r\xf0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x11\x9a\xa6M[}\x18\x1d\xae\x9d<\xb4I\x95\\\x89\xc1\xf9c\xfa\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\x11\xc05\x8a\xa6G\x9d\xe2\x18f\xfe!\a\x19$\xb6^p\xf8\xb9\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\xe0\x94\x11\xd2$z\"\x1ep\xc2\xd6m\x17\xee\x13\x8d8\xc5_\xfb\x86@\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x11\u05c4JG\x1e\xf8\x9a\x8d\x87uUX<\xee\xbd\x149\xea&\x8a\x02#i\u6e80\u0188\x00\x00\u07d4\x11\xdda\x85\u0668\xd7=\xdf\u06a7\x1e\x9bwtC\x1cM\xfe\u008965\u026d\xc5\u07a0\x00\x00\u07d4\x11\xe7\x99~\u0750E\x03\xd7}\xa6\x03\x8a\xb0\xa4\xc84\xbb\xd5c\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x11\xec\x00\xf8I\xb61\x9c\xf5\x1a\xa8\u074ff\xb3U)\xc0\xbew\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\ufe22\x04Q\x16\x1bdJ\x8c\u03bb\xc1\xd3C\xa3\xbb\xcbR\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\x11\xfe\xfb]\xc1\xa4Y\x8a\xa7\x12d\fQwu\u07e1\xd9\x1f\x8c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x12\x0f\x9d\xe6\xe0\xaf~\xc0*\a\xc6\t\u0284G\xf1W\xe64L\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x12\x10\xf8\v\u06c2l\x17Tb\xab\a\x16\xe6\x9eF\xc2J\xd0v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12\x13N\u007fk\x01{\xf4\x8e\x85Z9\x9c\xa5\x8e.\x89/\xa5\u020965\u026d\xc5\u07a0\x00\x00\u07d4\x12\x170t\x98\x01S\xae\xaaK\r\xcb\xc7\x13.\xad\xce\xc2\x1bd\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\x12\x1f\x85[p\x14\x9a\xc84s\xb9po\xb4MG\x82\x8b\x98;\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x12'\xe1\nM\xbf\x9c\xac\xa3\x1b\x17\x80#\x9fUv\x15\xfc5\xc1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x12-\xcf\xd8\x1a\u0779}\x1a\x0eI%\u0135I\x80n\x9f;\xeb\x89R 5\xccn\x01!\x00\x00\u07d4\x12/V\x12%I\xd1h\xa5\xc5\xe2g\xf5&b\xe5\xc5\xcc\xe5\u0209\n\ad\a\xd3\xf7D\x00\x00\xe0\x94\x121o\xc7\xf1x\xea\xc2.\xb2\xb2Z\xed\xea\xdf=u\xd0\x01w\x8a\x04<3\xbe\x05\xf6\xbf\xb9\x80\x00\xe0\x94\x127Y\xf33\xe1>0i\xe2\x03KO\x059\x89\x18\x11\x9d6\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x12\\\xc5\xe4\xd5k+\xcc.\xe1\xc7\t\xfb\x9eh\xfb\x17t@\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x12c#\x88\xb2v^\xe4E+P\x16\x1d\x1f\xff\xd9\x1a\xb8\x1fJ\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\x12h\x97\xa3\x11\xa1J\xd4;x\xe0\x92\x01\x00\xc4Bk\xfdk\u07494\xc7&\x89?-\x94\x80\x00\u07d4\x12m\x91\xf7\xad\x86\u07bb\x05W\xc6\x12\xca'n\xb7\xf9m\x00\xa1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12}?\xc5\x00;\xf6<\r\x83\xe99W\x83e\x15\xfd'\x90E\x89\x06\x10\xc9\".nu\x00\x00\xe0\x94\x12}\xb1\xca\xdf\x1bw\x1c\xbdtu\xe1\xb2ri\x0fU\x8c\x85e\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x12\x84\xf0\xce\xe9\xd2\xff)\x89\xb6Ut\xd0o\xfd\x9a\xb0\xf7\xb8\x05\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x12\x8b\x90\x8f\xe7C\xa44 =\xe2\x94\xc4A\xc7\xe2\n\x86\xeag\x89&\xab\x14\xe0\xc0\xe1<\x00\x00\xe0\x94\x12\x93\u01cc}jD;\x9dt\xb0\xba^\xe7\xbbG\xfdA\x85\x88\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x12\x96\xac\xde\xd1\xe0c\xaf9\xfe\x8b\xa0\xb4\xb6=\xf7\x89\xf7\x05\x17\x89\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\x12\xaa}\x86\xdd\xfb\xad0\x16\x92\xfe\xac\x8a\b\xf8A\xcb!\\7\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94\x12\xaf\xbc\xba\x14'\xa6\xa3\x9e{\xa4\x84\x9fz\xb1\xc45\x8a\xc3\x1b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x12\xb5\xe2\x89E\xbb)i\xf9\xc6Lc\xcc\x05\xb6\xf1\xf8\xd6\xf4\u054a\x01\xa2\x9e\x86\x91;t\x05\x00\x00\u0794\x12\u03cb\x0eFR\x13!\x1a[S\u07f0\xdd'\x1a(,\x12\u0248\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x12\xd2\a\x90\xb7\xd3\xdb\u060c\x81\xa2y\xb8\x12\x03\x9e\x8a`;\u0409V\xf9\x85\u04c6D\xb8\x00\x00\xe0\x94\x12\xd6\re\xb7\xd9\xfcH\x84\v\xe5\xf8\x91\xc7E\xcev\xeeP\x1e\x8a\x04\x85\xe58\x8d\fv\x84\x00\x00\u0794\x12\xd9\x1a\x92\xd7O\xc8a\xa7)dm\xb1\x92\xa1%\xb7\x9fSt\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\x12\u992d*\xd5t\x84\xddp\x05e\xbd\xdbFB;\u067d1\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x12\xf3,\n\x1f-\xaa\xb6v\xfei\xab\xd9\xe0\x185-L\xcdE\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x12\xf4`\xaedl\xd2x\x0f\xd3\\P\xa6\xafK\x9a\xcc\xfa\x85\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x12\xff\xc1\x12\x86\x05\xcb\f\x13p\x9ar\x90Po&\x90\x97q\x93\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x13\x03$F\xe7\xd6\x10\xaa\x00\xec\x8cV\u0275t\xd3l\xa1\xc0\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\x1cy,\x19}\x18\xbd\x04]p$\x93|\x1f\x84\xb6\x0fD8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x1d\xf8\xd30\xeb|\xc7\x14}\nUWo\x05\u078d&\xa8\xb7\x89\n1\x06+\xee\xedp\x00\x00\u07d4\x13\x1f\xae\xd1%a\xbbz\xee\x04\xe5\x18Z\xf8\x02\xb1\xc3C\x8d\x9b\x89\v\xdf\x0e\u0733\x90\xc9\xc8V\b\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13!\xcc\xf2\x979\xb9t\xe5\xa5\x16\xf1\x8f:\x846q\xe3\x96B\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13'\xd7Y\xd5n\n\xb8z\xf3~\xcfc\xfe\x01\xf3\x10\xbe\x10\n\x89#\xbc<\xdbh\xa1\x80\x00\x00\u07d4\x13)\xdd\x19\xcdK\xaa\x9f\xc6C\x10\xef\xec\xea\xb2!\x17%\x1f\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x137\x1f\x92\xa5n\xa88\x1eC\x05\x9a\x95\x12\x8b\xdcMC\u0166\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x13O\x15\xe1\xe3\x9cSCY0\xaa\xed\xf3\xe0\xfeV\xfd\xe8C\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x13Ac\xbe\x9f\xbb\xe1\xc5in\xe2U\xe9\v\x13%C\x95\xc3\x18\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x13\\\xec\xd9U\xe5y\x83pv\x920\x15\x93\x03\u0671\x83\x9ff\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x13]\x17\x19\xbf\x03\xe3\xf8f1$y\xfe3\x81\x18\xcd8~p\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x13^\xb8\xc0\xe9\xe1\x01\xde\xed\xec\x11\xf2\xec\xdbf\xae\x1a\xae\x88g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x13`\xe8}\xf2Li\xeemQ\xc7nsv\u007f\xfe\x19\xa2\x13\x1c\x89\x04\xfc\xc1\xa8\x90'\xf0\x00\x00\u07d4\x13l\x83K\xf1\x112m s\x95)[.X>\xa7\xf35r\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x13mKf+\xbd\x10\x80\xcf\xe4D[\x0f\xa2\x13\x86D5\xb7\xf1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13oI\a\u02b4\x1e'\bK\x98E\x06\x9f\xf2\xfd\f\x9a\xdey\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13t\xfa\xcd{?\x8dhd\x9d`\xd4U\x0e\xe6\x9f\xf0HA3\x89\x0e\x9e\xd6\xe1\x11r\xda\x00\x00\u07d4\x13|\xf3A\xe8Ql\x81X\x14\xeb\xcds\xe6V\x9a\xf1L\xf7\xbc\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x13\x84\x8bF\xeau\xbe\xb7\xea\xa8_Y\xd8f\xd7\u007f\xd2L\xf2\x1a\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x13\x9d51\u0252*\xd5bi\xf60\x9a\xa7\x89\xfb$\x85\xf9\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x9eG\x97d\xb4\x99\xd6f \x8cJ\x8a\x04z\x97\x041c\u0749 w!*\xffm\xf0\x00\x00\u07d4\x13\xa5\xee\xcb80]\xf9Iq\xef-\x9e\x17\x9a\xe6\u03ba\xb37\x89\x11\u3ac3\x95\xc6\xe8\x00\x00\u07d4\x13\xac\xad\xa8\x98\n\xff\xc7PI!\xbe\x84\xebID\xc8\xfb\xb2\xbd\x89V\u04aa:\\\t\xa0\x00\x00\u07d4\x13\xb9\xb1\a\x15qL\t\xcf\xd6\x10\u03dc\x98F\x05\x1c\xb1\xd5\x13\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x13\xce3-\xffe\xa6\xab\x938\x97X\x8a\xa2>\x00\t\x80\xfa\x82\x89\x0e\x02\x056\xf0(\xf0\x00\x00\u07d4\x13\xd6z~%\xf2\xb1,\u06c5XP\t\xf8\xac\u011b\x96s\x01\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x13\xde\xe0>7\x99\x95-\a8\x84=K\xe8\xfc\n\x80?\xb2\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe0/\xb4H\xd6\xc8J\xe1}\xb3\x10\xad(m\x05a`\u0695\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe3!r\x8c\x9cWb\x80X\xe9?\xc8f\xa02\xdd\v\u0690\x89&\xbc\xca#\xfe.\xa2\x00\x00\u07d4\x13\xec\x81\"\x84\x02n@\x9b\xc0f\xdf\xeb\xf9\u0564\xa2\xbf\x80\x1e\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\x14\x01)\xea\xa7f\xb5\xa2\x9f[:\xf2WND\t\xf8\xf6\xd3\xf1\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u07d4\x14\x05\x18\xa3\x19K\xad\x13P\xb8\x94\x9ee\x05e\u07bem\xb3\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\x06\x85M\x14\x9e\b\x1a\xc0\x9c\xb4\xcaV\r\xa4c\xf3\x120Y\x89Hz\x9a0E9D\x00\x00\u07d4\x14\f\xa2\x8f\xf3;\x9ff\xd7\xf1\xfc\x00x\xf8\xc1\xee\xf6\x9a\x1b\xc0\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x14\x0f\xbaX\xdb\xc0H\x03\xd8L!0\xf0\x19x\xf9\xe0\xc71)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x14\x1a^9\xee/h\n`\x0f\xbfo\xa2\x97\u0790\xf3\"\\\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x14%N\xa1&\xb5-\x01B\xda\n~\x18\x8c\xe2U\xd8\xc4qx\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x14+\x87\xc5\x04?\xfbZ\x91\xdf\x18\xc2\xe1\t\xce\xd6\xfeJq\u06c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\x87\xf5\xa5$\u0288Q^\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\x14\xa75 f6D\x04\xdbP\xf0\xd0\u05cduJ\"\x19\x8e\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x14\xab\x16K;RL\x82\u05ab\xfb\xc0\u0783\x11&\xae\x8d\x13u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\xb1`>\xc6+ \x02 3\xee\xc4\xd6\xd6eZ\xc2J\x01Z\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x14\xc6;\xa2\u0731\xddM\xf3=\u06b1\x1cO\x00\a\xfa\x96\xa6-\x8a\x03HA\xb6\x05z\xfa\xb0\x00\x00\xe0\x94\x14\xcd\u077c\x8b\t\xe6gZ\x9e\x9e\x05\t\x1c\xb9\"8\u00de\x1e\x8a\x01\x14x\xb7\xc3\n\xbc0\x00\x00\u07d4\x14\xd0\n\xad9\xa0\xa7\u045c\xa0SP\xf7\xb07'\xf0\x8d\xd8.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x14\xee\xc0\x9b\xf0>5+\xd6\xff\x1b\x1e\x87k\xe6d\xce\xff\xd0\u03c9\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\x14\xf2!\x15\x95\x18x;\u0127\x06go\xc4\xf3\xc5\xee@X)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\xfc\xd19\x1e}s/Avl\xda\u0344\xfa\x1d\xeb\x9f\xfd\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x0e=\xbc\xbc\xfc\x84\xcc\xf8\x9bsBwc\xa5e\xc2>`\u0409\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\x15\x18b{\x885\x1f\xed\xe7\x96\xd3\xf3\b3d\xfb\u0508{\f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u0794\x15\"J\xd1\xc0\xfa\xceF\xf9\xf5V\xe4wJ0%\xad\x06\xbdR\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x15/+\xd2)\xdd\xf3\xcb\x0f\xda\xf4U\xc1\x83 \x9c\x0e\x1e9\xa2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15/N\x86\x0e\xf3\xee\x80jP'w\xa1\xb8\xdb\xc9\x1a\x90vh\x89 \x86\xac5\x10R`\x00\x00\u07d4\x15<\b\xaa\x8b\x96\xa6\x11\xefc\xc0%>*C4\x82\x9eW\x9d\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x15<\xf2\x84,\xb9\u0787l'o\xa6Gg\u0468\xec\xf5s\xbb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15>\xf5\x8a\x1e.z>\xb6\xb4Y\xa8\n\xb2\xa5G\xc9A\x82\xa2\x8a\x14T+\xa1*3|\x00\x00\x00\u07d4\x15DY\xfa/!1\x8e44D\x97\x89\xd8&\xcd\xc1W\f\xe5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15G\xb9\xbfz\xd6bt\xf3A8'#\x1b\xa4\x05\ue308\xc1\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\x15H\xb7p\xa5\x11\x8e\u0787\u06e2\xf6\x903\u007fam\u60eb\x89\x1c\x99V\x85\u0fc7\x00\x00\u07d4\x15R\x83P\xe0\xd9g\n.\xa2\u007f{J3\xb9\xc0\xf9b\x1d!\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x15[7y\xbbmV4./\u0681{[-\x81\xc7\xf4\x13'\x89\x02\xb8\xaa:\al\x9c\x00\x00\u07d4\x15e\xaf\x83~\xf3\xb0\xbdN+#V\x8dP#\xcd4\xb1d\x98\x89\x15Q\xe9rJ\u013a\x00\x00\u07d4\x15f\x91\x80\xde\u2558\x86\x9b\b\xa7!\xc7\xd2LL\x0e\xe6?\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x15r\xcd\xfa\xb7*\x01\u0396\x8ex\xf5\xb5D\x8d\xa2\x98S\xfb\u074a\x01\x12blI\x06\x0f\xa6\x00\x00\xe0\x94\x15uY\xad\xc5Wd\xccm\xf7\x93#\t%4\xe3\xd6dZf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x15x\xbd\xbc7\x1bM$8E3\x05V\xff\xf2\xd5\xefM\xffg\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x15~\xb3\xd3\x11;\u04f5\x97qM:\x95N\xdd\x01\x89\x82\xa5\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x84\xa2\xc0f\xb7\xa4U\xdb\u05ae(\a\xa73N\x83\xc3_\xa5\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\u07d4\x15\x87F\x86\xb6s=\x10\xd7\x03\xc9\xf9\xbe\xc6\xc5.\xb8b\x8dg\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x8a\ra\x92S\xbfD2\xb5\xcd\x02\u01f8b\xf7\u00b7V6\x89\a[\xac|[\x12\x18\x80\x00\u07d4\x15\x98\x12y\x82\xf2\xf8\xad;k\x8f\xc3\xcf'\xbfax\x01\xba+\x89\t`\xdbwh\x1e\x94\x00\x00\xe0\x94\x15\x9a\xdc\xe2z\xa1\vG#d)\xa3JZ\xc4,\xad[d\x16\x8a\x06\xbf\x90\xa9n\xdb\xfaq\x80\x00\u07d4\x15\xa0\xae\xc3\u007f\xf9\xff=T\t\xf2\xa4\xf0\xc1!*\xac\xcb\x02\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x15\xaaS\r\xc3iX\xb4\xed\xb3\x8e\xeem\xd9\xe3\xc7}L\x91E\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\xac\xb6\x15h\xecJ\xf7\xea(\x198a\x81\xb1\x16\xa6\xc5\xeep\x8a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\x15\xb9o0\xc2;\x86d\xe7I\x06Q\x06k\x00\xc49\x1f\xbf\x84\x89\x16B\xe9\xdfHv)\x00\x00\u07d4\x15\xc7\xed\xb8\x11\x8e\xe2{4\"\x85\xebY&\xb4z\x85[\u01e5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x15\u0654hPz\xa0A?\xb6\r\xca*\xdc\u007fV\x9c\xb3kT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\u06f4\x8c\x980\x97d\xf9\x9c\xed6\x92\xdc\xca5\xee0k\xac\x8a\x1f\u00c4+\xd1\xf0q\xc0\x00\x00\xe0\x94\x15\u072f\xcc+\xac\xe7\xb5[T\xc0\x1a\x1cQF&\xbfa\xeb\u060a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x15\u3d44\x05kb\xc9s\xcf^\xb0\x96\xf1s>T\xc1\\\x91\x892\xc7Z\x02#\xdd\xf3\x00\x00\u07d4\x15\xeb\xd1\xc7\xca\u04af\xf1\x92u\xc6W\xc4\xd8\b\xd0\x10\xef\xa0\xf5\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x15\xee\x0f\xc6>\xbf\x1b\x1f\u011d{\xb3\x8f\x88c\x82:.\x17\u0489g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x15\xf1\xb3R\x11\rh\x90\x1d\x8fg\xaa\xc4jl\xfa\xfe\x03\x14w\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x15\xf2\xb7\xb1d2\xeeP\xa5\xf5[A#/c4\xedX\xbd\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x16\x01\x9aM\xaf\xabC\xf4\u067fAc\xfa\xe0\x84}\x84\x8a\xfc\xa2\x89\x01[\xc7\x019\xf7J\x00\x00\u07d4\x16\x02&\xef\xe7\xb5:\x8a\xf4b\xd1\x17\xa0\x10\x80\x89\xbd\xec\xc2\u0449\n\xdf0\xbap\u0217\x00\x00\u07d4\x16\f\xebo\x98\x0e\x041_S\xc4\xfc\x98\x8b+\xf6\x9e(M}\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94\x16\x1c\xafZ\x97*\u0383y\xa6\u0420J\xe6\xe1c\xfe!\xdf+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x16\x1d&\xefgY\xba[\x9f \xfd\xcdf\xf1a2\xc3RA^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16!\x10\xf2\x9e\xac_}\x02\xb5C\xd8\xdc\u057bY\xa5\xe3;s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16+\xa5\x03'b\x14\xb5\t\xf9u\x86\xbd\x84!\x10\xd1\x03\xd5\x17\x8a\x01\xe7\xff\u0609\\\"h\x00\x00\u07d4\x16-v\xc2\xe6QJ:\xfbo\xe3\xd3\u02d3\xa3\\Z\xe7\x83\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16;\xadJ\x12+E}d\xe8\x15\nA>\xaeM\a\x02>k\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\x16<\u023e\"vF\xcb\tq\x91Y\xf2\x8e\u041c]\xc0\xdc\xe0\x89Hz\x9a0E9D\x00\x00\u07d4\x16=\xcas\xd7\xd6\xea?>`b2*\x874\x18\f\vx\uf25ft \x03\xcb}\xfc\x00\x00\u07d4\x16Mz\xac>\xec\xba\uc86dQ\x91\xb7S\xf1s\xfe\x12\xec3\x89(VR\xb8\xa4hi\x00\x00\u07d4\x16Rl\x9e\u07d4>\xfaOm\x0f\v\xae\x81\xe1\x8b1\xc5@y\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x16S\x05\xb7\x872.%\xdcj\xd0\xce\xfelo3Fx\xd5i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16e\xab\x179\xd7\x11\x19\xeea2\xab\xbd\x92j'\x9f\xe6yH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x16k\xf6\u06b2-\x84\x1bHl8\xe7\xbaj\xb3:\x14\x87\ud30a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x16v\x99\xf4\x8ax\xc6\x15Q%\x15s\x99X\x993\x12WO\a\x89\x02\x1d;\xd5^\x80<\x00\x00\u07d4\x16x\xc5\xf2\xa5\"92%\x19ca\x89OS\xccu/\xe2\xf3\x89h\xf3e\xae\xa1\xe4@\x00\x00\u07d4\x16|\xe7\xdee\xe8G\bYZRT\x97\xa3\xeb^ZfPs\x89\x1f1Gsfo\xc4\x00\x00\u07d4\x16~>:\xe2\x003HE\x93\x92\xf7\xdf\xceD\xaf|!\xadY\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x16\x80\xce\xc5\x02\x1e\xe90P\xf8\xae\x12rQ\x83\x9et\xc1\xf1\xfd\x8a\x02\xc6\x14a\xe5\xd7C\u0580\x00\u07d4\x16\x81j\xac\x0e\xde\r-<\xd4B\xday\xe0c\x88\x0f\x0f\x1dg\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16\x8bP\x19\xb8\x18i\x16D\x83_\xe6\x9b\xf2)\xe1q\x12\xd5,\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\u07d4\x16\x8b\xde\xc8\x18\xea\xfcm)\x92\xe5\xefT\xaa\x0e\x16\x01\xe3\xc5a\x8967Pz0\xab\xeb\x00\x00\u07d4\x16\x8d0\xe5?\xa6\x81\t+R\xe9\xba\xe1Z\r\xcbA\xa8\u027b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x16\x9b\xbe\xfcA\xcf\xd7\xd7\u02f8\xdf\xc60 \xe9\xfb\x06\u0515F\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xa5\x8e\x98]\xcc\xd7\a\xa5\x94\u0453\xe7\u0327\x8b]\x02xI\x89I\xb9\u029aiC@\x00\x00\u07d4\x16\xa9\xe9\xb7:\u92c6M\x17(y\x8b\x87f\xdb\xc6\xea\x8d\x12\x893\xe7\xb4K\r\xb5\x04\x00\x00\u07d4\x16\xaaR\xcb\vUG#\xe7\x06\x0f!\xf3'\xb0\xa6\x83\x15\xfe\xa3\x89\r\x8drkqw\xa8\x00\x00\u07d4\x16\xab\xb8\xb0!\xa7\x10\xbd\u01ce\xa54\x94\xb2\x06\x14\xffN\xaf\xe8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x16\xaf\xa7\x87\xfc\x9f\x94\xbd\xffiv\xb1\xa4/C\n\x8b\xf6\xfb\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xba\xe5\xd2N\xff\x91w\x8c\u064bM:\x1c\xc3\x16/D\xaaw\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\x16\xbc@!Z\xbb\u066e](\v\x95\xb8\x01\vE\x14\xff\x12\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x16\xbeu\u9299Z9R\"\xd0\v\u05df\xf4\xb6\xe68\u144a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\x16\xc1\xbf[}\xc9\xc8<\x17\x9e\xfa\xcb\xcf.\xb1t\xe3V\x1c\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x16\u01f3\x1e\x8c7b\x82\xac\"qr\x8c1\xc9^5\xd9R\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xf3\x13\u03ca\xd0\x00\x91J\n\x17m\u01a44+y\xec%8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xff\xac\x84\x03)@\xf0\x12\x1a\tf\x8b\x85\x8a~y\xff\xa3\xbb\x89\xd2J\xdan\x10\x87\x11\x00\x00\xe0\x94\x17\x03\xb4\xb2\x92\xb8\xa9\xde\xdd\xed\xe8\x1b\xb2]\x89\x17\x9fdF\xb6\x8a\x04+e\xa4U\xe8\xb1h\x00\x00\u07d4\x17\x04\x93\x11\x10\x1d\x81~\xfb\x1de\x91\x0ff6b\xa6\x99\u024c\x89lh\xcc\u041b\x02,\x00\x00\u07d4\x17\x04\xce\xfc\xfb\x131\xeczx8\x8b)9>\x85\xc1\xafy\x16\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\n\x88\xa8\x99\u007f\x92\xd287\x0f\x1a\xff\xde\xe64pP\xb0\x13\x89\xa2\xacw5\x14\x880\x00\x00\u07d4\x17\x10\x8d\xab,P\xf9\x9d\xe1\x10\u1cf3\xb4\u0342\xf5\xdf(\xe7\x895 ;g\xbc\xca\xd0\x00\x00\xe0\x94\x17\x12[Y\xacQ\xce\xe0)\xe4\xbdx\xd7\xf5\x94}\x1e\xa4\x9b\xb2\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4\x17\x1a\u0660K\xed\u0238a\xe8\xedK\xdd\xf5qx\x13\xb1\xbbH\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\x1c\xa0*\x8bmb\xbfL\xa4~\x90i\x14\a\x98a\x97,\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\"\xc4\xcb\xe7\n\x94\xb6U\x9dBP\x84\xca\xee\xd4\xd6\xe6n!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17X\vvotSR\\\xa4\u01a8\x8b\x01\xb5\x05p\xea\b\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x17X\x9al\x00jT\xca\xd7\x01\x03\x12:\xae\n\x82\x13_\u07b4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x17Z\x18::#_\xfb\xb0;\xa85gRg\"\x94\x17\xa0\x91\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x17_\xee\xea*\xa4\xe0\xef\xda\x12\xe1X\x8d/H2\x90\xed\xe8\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x17e6\x1c.\xc2\xf86\x16\u0383c\xaa\xe2\x10%\xf2Vo@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17gR\\_Z\"\xed\x80\xe9\xd4\xd7q\x0f\x03b\u049e\xfa3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17v%`\xe8*\x93\xb3\xf5\"\xe0\xe5$\xad\xb8a,:tp\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x17}\xaex\xbc\x01\x13\xd8\u04dcD\x02\xf2\xa6A\xae*\x10Z\xb8\x89b\x92BV \xb4H\x00\x00\xe0\x94\x17\x84\x94\x8b\xf9\x98H\u021eDV8PM\u0598'\x1bY$\x8a\x01GLA\r\x87\xba\xee\x00\x00\u07d4\x17\x88\u069bW\xfd\x05\xed\xc4\xff\x99\xe7\xfe\xf3\x01Q\x9c\x8a\n\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\x8e\xafk\x85T\xc4]\xfd\xe1kx\xce\f\x15\u007f.\xe3\x13Q\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x17\x96\x1dc;\xcf \xa7\xb0)\xa7\xd9K}\xf4\xda.\xc5B\u007f\x89\fo\xf0p\U000532c0\x00\u07d4\x17\x96\xbc\xc9{\x8a\xbcq\u007fKJ|k\x106\xea!\x82c\x9f\x89\x13A\xf9\x1c\xd8\xe3Q\x00\x00\u07d4\x17\x99=1*\xa1\x10iW\x86\x8fjU\xa5\xe8\xf1/w\xc8C\x89\x18e\xe8\x14\xf4\x14.\x80\x00\u07d4\x17\x9a\x82^\x0f\x1fn\x98S\tf\x84e\xcf\xfe\xd46\xf6\xae\xa9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xb2\xd6\xcfe\xc6\xf4\xa3G\xdd\xc6W&U5M\x8aA+)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xb8\a\xaf\xa3\xdd\xd6G\xe7#T.{R\xfe\xe3\x95'\xf3\x06\x89\x15\xaf@\xff\xa7\xfc\x01\x00\x00\u07d4\x17\xc0G\x86W\xe1\xd3\xd1z\xaa3\x1d\xd4)\xce\u03d1\xf8\xae]\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\x17\xc0\xfe\xf6\x98l\xfb.@A\xf9\x97\x9d\x99@\xb6\x9d\xff=\xe2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17\u0511\x8d\xfa\xc1]w\xc4\u007f\x9e\xd4\x00\xa8P\x19\rd\xf1Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xd5!\xa8\xd9w\x90#\xf7\x16M#<;d \xff\xd2#\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xd91\xd4\xc5b\x94\u073ew\xc8e[\xe4i_\x00mJ<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xdfIQ\x8ds\xb1)\xf0\xda6\xb1\u0274\f\xb6d \xfd\u01ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x17\xe4\xa0\xe5+\xac>\xe4N\xfe\tT\xe7S\u0538]dN\x05\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xe5\x84\xe8\x10\xe5gp,a\xd5]CK4\u0375\xee0\xf6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17\xe8.px\xdcO\xd9\xe8y\xfb\x8aPf\u007fS\xa5\xc5E\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\xe8o;[0\xc0\xbaY\xf2\xb2\xe8XB[\xa8\x9f\n\x10\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xee\x9fT\xd4\xdd\xc8Mg\x0e\xff\x11\xe5Je\x9f\xd7/DU\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94\x17\xefJ\xcc\x1b\xf1G\xe3&t\x9d\x10\xe6w\xdc\xff\xd7o\x9e\x06\x8a\bwQ\xf4\xe0\xe1\xb50\x00\x00\u07d4\x17\xf1F2\xa7\xe2\x82\v\xe6\xe8\xf6\u07c25X(=\xad\xab-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xf5#\xf1\x17\xbc\x9f\xe9x\xaaH\x1e\xb4\xf5V\x17\x117\x1b\u0209li\xf7>)\x13N\x00\x00\u07d4\x17\xfd\x9bU\x1a\x98\xcba\xc2\xe0\u007f\xbfA\xd3\xe8\u02650\u02e5\x89\x01v\x8c0\x81\x93\x04\x80\x00\u07d4\x18\x04x\xa6U\u05cd\x0f;\fO +aH[\xc4\x00/\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\x13l\x9d\xf1g\xaa\x17\xb6\xf1\x8e\"\xa7\x02\u020fK\u0082E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x18\x15'\x9d\xff\x99R\xda;\xe8\xf7rI\xdb\xe2\"C7{\xe7\x8a\x01\x01|\xb7n{&d\x00\x00\u07d4\x18\x1f\xbb\xa8R\xa7\xf5\x01x\xb1\xc7\xf0>\xd9\xe5\x8dT\x16))\x89$\x1a\x9bOaz(\x00\x00\xe0\x94\x18'\x03\x9f\tW\x02\x94\b\x8f\xdd\xf0G\x16\\3\u65a4\x92\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x18-\xb8R\x93\xf6\x06\u8248\xc3pL\xb3\xf0\xc0\xbb\xbf\xcaZ\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18H\x00<%\xbf\u052a\x90\xe7\xfc\xb5\u05f1k\xcd\f\xff\xc0\u060965\u026d\xc5\u07a0\x00\x00\xe0\x94\x18JO\v\xebq\xff\xd5X\xa6\xb6\xe8\xf2(\xb7\x87\x96\xc4\xcf>\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94\x18M\x86\xf3Fj\xe6h;\x19r\x99\x82\xe7\xa7\u1903G\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x18Q\xa0c\xcc\xdb0T\x90w\xf1\xd19\xe7-\xe7\x97\x11\x97\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18UF\xe8v\x8dPhs\x81\x8a\xc9u\x1c\x1f\x12\x11j;\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x18X\xcf\x11\xae\xa7\x9fS\x98\xad+\xb2\"g\xb5\xa3\xc9R\xeat\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\xe0\x94\x18Z\u007f\u012c\xe3h\xd23\xe6 \xb2\xa4Y5f\x12\x92\xbd\xf2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x18d\xa3\u01f4\x81UD\x8cT\u020cp\x8f\x16g\tsm1\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18j\xfd\xc0\x85\xf2\xa3\xdc\xe4a^\xdf\xfb\xad\xf7\x1a\x11x\x0fP\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x18k\x95\xf8\xe5\xef\xfd\xdc\xc9O\x1a1[\xf0)];\x1e\xa5\x88\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x18}\x9f\f\a\xf8\xebt\xfa\xaa\xd1^\xbc{\x80Dt\x17\xf7\x82\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x18\x95\xa0\xebJCrr/\xcb\u016f\xe6\x93o(\x9c\x88\xa4\x19\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x18\x99\xf6\x9fe;\x05\xa5\xa6\xe8\x1fH\a\x11\u041b\xbf\x97X\x8c\x89i\xfb\x13=\xf7P\xac\x00\x00\u07d4\x18\xa6\xd2\xfcR\xbes\b@#\xc9\x18\x02\xf0[\xc2JK\xe0\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\xb0@|\xda\xd4\xceR`\x06#\xbd^\x1fj\x81\xaba\xf0&\x89\x11Q\xcc\xf0\xc6T\u0180\x00\u07d4\x18\xb8\xbc\xf9\x83!\xdaa\xfbN>\xac\xc1\xecT\x17'-\xc2~\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\x18\xc6r:gS)\x9c\xb9\x14G}\x04\xa3\xbd!\x8d\xf8\xc7u\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x18\xe1\x13\xd8\x17|i\x1aa\xbexXR\xfa[\xb4z\uef6f\x89Hz\x9a0E9D\x00\x00\xe0\x94\x18\xe4\xceGH;S\x04\n\u06eb5\x17,\x01\xefdPn\f\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x18\xe52C\x98\x1a\xab\xc8v}\xa1\fsD\x9f\x13\x91V\x0e\xaa\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x18\xfa\x86%\xc9\u0704>\x00\x15\x9e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\x193\xe34\xc4\x0f:\u02ed\f\v\x85\x11X i$\xbe\xca:\x8a\x01\x99^\xaf\x01\xb8\x96\x18\x80\x00\xe0\x94\x197\xc5\xc5\x15\x05uS\u033dF\u0546dU\xcef)\x02\x84\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u07d4\x19:\xc6Q\x83e\x18\x00\xe25\x80\xf8\xf0\xea\u04fbY~\xb8\xa4\x89\x02\xb6*\xbc\xfb\x91\n\x00\x00\u07d4\x19=7\xed4}\x1c/N55\r\x9aDK\xc5|\xa4\xdbC\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x19@\u0713d\xa8R\x16_GAN'\xf5\x00$E\xa4\xf1C\x8a\x02L-\xffj<|H\x00\x00\u07d4\x19E\xfe7\u007f\xe6\u0537\x1e>y\x1fo\x17\xdb$<\x9b\x8b\x0f\x89vy\u7fb9\x886\x00\x00\u07d4\x19Jk\xb3\x02\xb8\xab\xa7\xa5\xb5y\u07d3\xe0\xdf\x15t\x96v%\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x19L\ubd12\x98\x82\xbf;K\xf9\x86L+\x1b\x0fb\u0083\xf9\x89\x1e\xf8aS\x1ft\xaa\x00\x00\u07d4\x19O\xf4J\xef\xc1{\xd2\x0e\xfdz LG\xd1b\f\x86\xdb]\x89\xa2\x99\th\u007fj\xa4\x00\x00\xe0\x94\x19O\xfex\xbb\xf5\xd2\r\u044a\x1f\x01\xdaU.\x00\xb7\xb1\x1d\xb1\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x19S1>*\xd7F#\x9c\xb2'\x0fH\xaf4\u063b\x9cDe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19W\x1a+\x8f\x81\u01bc\xf6j\xb3\xa1\x00\x83)V\x17\x15\x00\x03\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\x19h}\xaa9\xc3h\x13\x9bn{\xe6\r\xc1u:\x9f\f\xbe\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x19l\x02!\nE\n\xb0\xb3cpe_qz\xa8{\xd1\xc0\x04\x89\x0e\x10\xac\xe1W\xdb\xc0\x00\x00\u07d4\x19n\x85\xdf~s+J\x8f\x0e\xd06#\xf4\u06dd\xb0\xb8\xfa1\x89\x01%\xb9/\\\xef$\x80\x00\u07d4\x19s+\xf9s\x05]\xbd\x91\xa4S:\u06a2\x14\x9a\x91\u04c3\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19vr\xfd9\xd6\xf2F\xcef\xa7\x90\xd1:\xa9\"\xd7\x0e\xa1\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x19y\x8c\xbd\xa7\x15\ua69b\x9dj\xab\x94,U\x12\x1e\x98\xbf\x91\x89A\rXj \xa4\xc0\x00\x00\u07d4\x19\x8b\xfc\xf1\xb0z\xe3\b\xfa,\x02\x06\x9a\xc9\xda\xfeq5\xfbG\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x19\x8e\xf1\xec2Z\x96\xcc5Lrf\xa08\xbe\x8b\\U\x8fg\x8a\x80\xd1\xe47>\u007f!\xda\x00\x00\xe0\x94\x19\x91\x8a\xa0\x9e}IN\x98\xff\xa5\xdbP5\b\x92\xf7\x15j\u018a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x19\xb3k\f\x87\xeafN\xd8\x03\x18\xdcw\xb6\x88\xdd\xe8}\x95\xa5\x89i\x9fI\x98\x020=\x00\x00\u07d4\x19\u07d4E\xa8\x1c\x1b=\x80J\xea\xebon NB6f?\x89\x02\x06\xd9NjI\x87\x80\x00\u07d4\x19\xe5\u07a37\n,tj\xae4\xa3|S\x1fA\xda&N\x83\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x19\xe7\xf3\xeb{\xf6\u007f5\x99 \x9e\xbe\b\xb6*\xd32\u007f\x8c\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xe9Nb\x00P\xaa\xd7f\xb9\xe1\xba\xd91#\x83\x12\u053fI\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4\x19\xec\xf2\xab\xf4\f\x9e\x85{%/\xe1\xdb\xfd=L]\x8f\x81n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xf5\xca\xf4\xc4\x0ei\b\x81<\aE\xb0\xae\xa9Xm\x9d\xd91\x89#\xfe\xd9\xe1\xfa+`\x00\x00\u07d4\x19\xf6C\xe1\xa8\xfa\x04\xae\x16\x00`(\x13\x833\xa5\x9a\x96\u0787\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x19\xf9\x9f,\vF\u0389\x06\x87]\xc9\xf9\n\xe1\x04\xda\xe3U\x94\x89\xf4WZ]M\x16*\x00\x00\u07d4\x19\xff$O\xcf\xe3\xd4\xfa/O\u065f\x87\xe5[\xb3\x15\xb8\x1e\xb6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1a\x04\xce\xc4 \xadC\"\x15$mw\xfe\x17\x8d3\x9e\u0435\x95\x89\x11!a\x85\u009fp\x00\x00\xe0\x94\x1a\x04\xd58\x9e\xb0\x06\xf9\u0388\f0\xd1SS\xf8\xd1\x1cK1\x8a\x03\x9d\x84\xb2\x18m\xc9\x10\x00\x00\u07d4\x1a\bA\xb9*\u007fpuV\x9d\xc4b~kv\u02b0Z\u0791\x89Rf<\u02b1\xe1\xc0\x00\x00\xe0\x94\x1a\b]C\xec\x92AN\xa2{\x91O\xe7g\xb6\xd4k\x1e\xefD\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\x1a\t\xfd\xc2\u01e2\x0e#WK\x97\u019e\x93\u07bag\xd3r \x89lO\xd1\xee$nx\x00\x00\u07d4\x1a\n\x1d\u07f01\xe5\xc8\xcc\x1dF\xcf\x05\x84-P\xfd\xdcq0\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1a\x1c\x9a&\xe0\xe0$\x18\xa5\xcfh}\xa7Z'\\b,\x94@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1a \x1bC'\u03a7\xf3\x99\x04bF\xa3\xc8~n\x03\xa3\u0368\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a$4\xccwD\"\u050dS\u055c]V,\u0384\a\xc9K\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\x1a%\xe1\u017c~_P\xec\x16\xf8\x88_!\x0e\xa1\xb98\x80\x0e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1a&\x94\xec\a\xcf^Mh\xba@\xf3\xe7\xa1LS\xf3\x03\x8cn\x8966\xcd\x06\xe2\xdb:\x80\x00\u07d4\x1a5 E5\x82\xc7\x18\xa2\x1cB7[\xc5\as%RS\xe1\x89*\xd3s\xcef\x8e\x98\x00\x00\xe0\x94\x1a7n\x1b-/Y\ai\xbb\x85\x8dEu2\rN\x14\x99p\x8a\x01\x06q%v9\x1d\x18\x00\x00\u07d4\x1a:3\x0eO\xcbi\xdb\xef^i\x01x;\xf5\x0f\xd1\xc1SB\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1aN\u01a0\xae\u007fZ\x94'\xd2=\xb9rL\r\f\xff\xb2\xab/\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\x1aP^b\xa7N\x87\xe5wG>O:\xfa\x16\xbe\xdd<\xfaR\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x1a^\xe53\xac\xbf\xb3\xa2\xd7m[hRw\xb7\x96\xc5j\x05+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1adJP\xcb\u00ae\xe8#\xbd+\xf2C\xe8%\xbeMG\xdf\x02\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x1apD\xe28?\x87\b0[I[\xd1\x17k\x92\xe7\xef\x04:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1ay\xc7\xf4\x03\x9cg\xa3\x9du\x13\x88L\xdc\x0e,4\"$\x90\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\x89\x89\x9c\xbe\xbd\xbbd\xbb&\xa1\x95\xa6<\bI\x1f\u035e\xee\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\x8a\\\xe4\x14\u079c\xd1r\x93~7\xf2\u055c\xffq\xceW\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1a\x95\xa8\xa8\b.FR\xe4\x17\r\xf9'\x1c\xb4\xbbC\x05\xf0\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x1a\x95\u0277Tk]\x17\x86\u00c5\x8f\xb1#dF\xbc\f\xa4\u0389j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1a\x98~?\x83\xdeu\xa4/\x1b\xde|\x99|\x19!{J_$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1a\x9ep/8]\xcd\x10^\x8b\x9f\xa4(\xee\xa2\x1cW\xffR\x8a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1a\xa1\x02\x1fU\n\xf1X\xc7Gf\x8d\xd1;F1`\xf9Z@\x89O\xb0Y\x1b\x9b08\x00\x00\u07d4\x1a\xa2v\x99\xca\u068d\u00e7oy3\xaaf\xc7\x19\x19\x04\x0e\x88\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x1a\xa4\x02p\xd2\x1e\\\u0786\xb61m\x1a\xc3\xc53IKy\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\xb5:\x11\xbc\xc6=\u07ea@\xa0+\x9e\x18d\x96\u037b\x8a\xff\x89l?*\xac\x80\f\x00\x00\x00\u07d4\x1a\xbcN%;\b\n\xebCy\x84\xab\x05\xbc\xa0\x97\x9a\xa4>\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xc0\x89\u00fcM\x82\xf0j \x05\x1a\x9ds-\xc0\xe74\xcba\x89%\xf6\x9dc\xa6\xce\x0e\x00\x00\xe0\x94\x1a\xd4V>\xa5xk\xe1\x15\x995\xab\xb0\xf1\u0547\x9c>sr\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xd7- \xa7n\u007f\xcckv@X\xf4\x8dA}Io\xa6\u0349lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\xda\xf4\xab\xfa\x86}\xb1\u007f\x99\xafj\xbe\xbfpz<\xf5]\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xf6\x03C6\x0e\v-u%R\x107W \xdf!\xdb\\}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xfc\u0145\x89l\xd0\xed\xe1)\xee-\xe5\xc1\x9e\xa8\x11T\vd\x89\xaf*\xba\f\x8e[\xef\x80\x00\u07d4\x1b\x05\xeajj\u022f|\xb6\xa8\xb9\x11\xa8\xcc\xe8\xfe\x1a*\xcf\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\v1\xaf\xffKm\xf3e:\x94\xd7\xc8yx\xae5\xf3J\xae\x89\x139\x10E?\xa9\x84\x00\x00\u07d4\x1b\r\ah\x17\xe8\u058e\xe2\xdfN\x1d\xa1\xc1\x14-\x19\x8cD5\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x1b\x13\ro\xa5\x1d\\H\xec\x8d\x1dR\u070a\"{\xe8s\\\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b#\u02c6cUHq\xfb\xbe\r\x9e`9~\xfbo\xae\xdc>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1b&9X\x8bU\xc3D\xb0#\xe8\xde_\xd4\b{\x1f\x04\x03a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x1b9 \xd0\x01\xc4>r\xb2N|\xa4o\x0f\xd6\xe0\xc2\n_\xf2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1b<\xb8\x1eQ\x01\x1bT\x9dx\xbfr\v\r\x92J\xc7c\xa7\u008av\x95\xa9, \xd6\xfe\x00\x00\x00\u07d4\x1bC#,\xcdH\x80\xd6\xf4o\xa7Q\xa9l\xd8$s1XA\x89\x04V9\x18$O@\x00\x00\u07d4\x1bK\xbc\xb1\x81e!\x1b&[(\a\x16\xcb?\x1f!!v\xe8\x89\x19\x9a\xd3}\x03\xd0`\x80\x00\u07d4\x1bM\a\xac\u04c1\x83\xa6\x1b\xb2x=+{\x17\x8d\xd5\x02\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1bckzIo\x04MsYYn5:\x10F\x16Cok\x89\x13\x88\xea\x95\xc3?\x1d\x00\x00\u07d4\x1bd\x95\x89\x12@\xe6NYD\x93\xc2f!q\xdb^0\xce\x13\x89\tX\x87\u0595\xedX\x00\x00\u07d4\x1bf\x10\xfbh\xba\xd6\xed\x1c\xfa\xa0\xbb\xe3:$\xeb.\x96\xfa\xfb\x89\b=lz\xabc`\x00\x00\u07d4\x1by\x903\xefm\xc7\x12x\"\xf7EB\xbb\"\xdb\xfc\t\xa3\b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1b~\xd9t\xb6\xe24\u0381$t\x98B\x9a[\u0520\xa2\xd19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x82o\xb3\xc0\x12\xb0\xd1Y\u253a[\x8aI\x9f\xf3\xc0\xe0<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x8a\xa0\x16\f\u05df\x00_\x88Q\nqI\x13\xd7\n\u04fe3\x89\n\xef\xfb\x83\a\x9a\xd0\x00\x00\xe0\x94\x1b\x8b\xd6\xd2\xec\xa2\x01\x85\xa7\x8e}\x98\xe8\xe1\x85g\x8d\xacH0\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x1b\x9b-\u0096\x0eL\xb9@\x8ft\x05\x82|\x9bY\a\x16\x12\xfd\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1b\xa9\"\x8d8\x87'\xf3\x89\x15\x0e\xa0;s\xc8-\xe8\xeb.\t\x8a\x01\x89t\xfb\xe1w\xc9(\x00\x00\u07d4\x1b\xa9\xf7\x99~S\x87\xb6\xb2\xaa\x015\xac$R\xfe6\xb4\xc2\r\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\x1b\xba\x03\xffkJ\u057f\x18\x18J\xcb!\xb1\x88\xa3\x99\xe9\xebJ\x89a\t=|,m8\x00\x00\u07d4\x1b\xbc\x19\x9eXg\x90\xbe\x87\xaf\xed\xc8I\xc0G&t\\]{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1b\xbc`\xbc\xc8\x0e\\\xdc5\xc5Aj\x1f\n@\xa8=\xae\x86{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xc4L\x87a#\x1b\xa1\xf1\x1f_\xaa@\xfaf\x9a\x01>\x12\u0389\v\tR\xc4Z\xea\xad\x00\x00\u07d4\x1b\xcf4A\xa8f\xbd\xbe\x960\t\xce3\xc8\x1c\xbb\x02a\xb0,\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\x1b\u048c\xd5\u01ca\xeeQ5|\x95\xc1\xef\x925\xe7\xc1\x8b\xc8T\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xd8\xeb\xaavt\xbb\x18\u1458\xdb$OW\x03\x13\a_C\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\x1b\xd9\t\xac\rJ\x11\x02\xec\x98\xdc\xf2\u0329j\n\xdc\u05e9Q\x89\x01\x16Q\xac>zu\x80\x00\u07d4\x1b\xe3T,6\x13hte\xf1Zp\xae\xeb\x81f+e\u0328\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xeaM\xf5\x12/\xaf\u07b3`~\xdd\xda\x1e\xa4\xff\u06da\xbf*\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4\x1b\xecM\x02\u0385\xfcH\xfe\xb6$\x89\x84\x1d\x85\xb1pXj\x9b\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\x1b\xf9t\u0650OE\u0381\xa8E\xe1\x1e\xf4\xcb\xcf'\xafq\x9e\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x1c\x04VI\xcdS\xdc#T\x1f\x8e\xd4\xd3A\x81(\b\xd5\u075c\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1c\x12\x8b\xd6\u0365\xfc\xa2uu\xe4\xb4;2S\xc8\xc4\x17*\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\x13\u04c67\xb9\xa4|\xe7\x9d7\xa8oP\xfb@\x9c\x06\a(\x89Hz\x9a0E9D\x00\x00\u07d4\x1c \x10\xbdf-\xf4\x17\xf2\xa2q\x87\x9a\xfb\x13\xefL\x88\xa3\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1c%z\u0525Q\x05\xea;X\xed7K\x19\x8d\xa2f\xc8_c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x1c.6\a\xe1'\xca\xca\x0f\xbd\\YH\xad\xad}\xd80\xb2\x85\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x1c5l\xfd\xb9_\xeb\xb7\x14c;(\xd5\xc12\u0744\xa9\xb46\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4\x1c5\xaa\xb6\x88\xa0\u034e\xf8.vT\x1b\xa7\xac9R\u007ft;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x1c>\xf0]\xae\x9d\xcb\u0509\xf3\x02D\bf\x9d\xe2D\xc5*\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x1cJ\xf0\xe8c\xd2el\x865\xbco\xfe\xc8\u0759(\x90\x8c\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c`\x19\x93x\x92\a\xf9e\xbb\x86\\\xbbL\xd6W\xcc\xe7o\xc0\x89\x05T\x1ap7P?\x00\x00\u07d4\x1cc\xfa\x9e,\xbb\xf21a\xda3\xa1\xda}\xf7\r\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1c\xb6\xb2\xd7\xcf\xc5Y\xb7\xf4\x1eoV\xab\x95\xc7\xc9X\xcd\x0eL\x89Hz\x9a0E9D\x00\x00\u07d4\x1c\xc1\xd3\xc1O\x0f\xb8d\x0e6rM\xc42)\xd2\xeaz\x1eH\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x1c\xc9\bv\x00A\t\xcdy\xa3\u07a8f\u02c4\n\xc3d\xba\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xd1\xf0\xa3\x14\u02f2\x00\xde\n\f\xb1\xef\x97\xe9 p\x9d\x97\u0089lk\x93[\x8b\xbd@\x00\x00\u0794\x1c\xdaA\x1b\xd5\x16;\xae\xca\x1eU\x85c`\x1c\xe7 \xe2N\xe1\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1c\xe8\x1d1\xa7\x920\"\xe1%\xbfH\xa3\xe06\x93\xb9\x8d\xc9\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xeb\xf0\x98]\u007fh\n\xaa\x91\\D\xccb\xed\xb4\x9e\xab&\x9e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1c\xedg\x15\xf8b\xb1\xff\x86\x05\x82\x01\xfc\xceP\x82\xb3nb\xb2\x8a\x01j^`\xbe\xe2s\xb1\x00\x00\u07d4\x1c\xf0L\xb1C\x80\x05\x9e\xfd?#\x8be\u057e\xb8j\xfa\x14\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1c\xf1\x05\xab#\x02;ULX>\x86\u05d2\x11y\xee\x83\x16\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1c\xf2\xebz\x8c\xca\u00ad\xea\xef\x0e\xe8sG\xd55\u04f9@X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xfc\xf7Q\u007f\f\bE\x97 \x94+dz\u0452\xaa\x9c\x88(\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x1d\t\xad$\x12i\x1c\u0141\xc1\xab6\xb6\xf9CL\xd4\xf0\x8bT\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1d\x15|Xv\xc5\xca\xd5S\xc9\x12\xca\xf6\xce-Rw\xe0\\s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1d&\x15\xf8\xb6\xcaP\x12\xb6c\xbd\u0414\xb0\xc5\x13|w\x8d\u07ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1d)\u01ea\xb4+ H\u04b2R%\u0518\u06e6z\x03\xfb\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794\x1d4\x1f\xa5\xa3\xa1\xbd\x05\x1f}\xb8\a\xb6\xdb/\u01faO\x9bE\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1d4N\x96%g\xcb'\xe4M\xb9\xf2\xfa\u01f6\x8d\xf1\xc1\xe6\xf7\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x1d6h0c\xb7\xe9\xeb\x99F-\xab\xd5i\xbd\xdc\xe7\x16\x86\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d7aky?\x94\x91\x188\xac\x8e\x19\xee\x94I\u07d2\x1e\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94\x1d9[0\xad\xda\x1c\xf2\x1f\t\x1aOJ{u3q\x18\x94A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x1dEXn\xb8\x03\xca!\x90e\v\xf7H\xa2\xb1t1+\xb5\a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1dW.\xdd-\x87\xca'\x1ag\x14\xc1Z;7v\x1d\u0320\x05\x89\x06\xeb\xd5*\x8d\xdd9\x00\x00\u07d4\x1dc0\x97\xa8R%\xa1\xffC!\xb1)\x88\xfd\xd5\\+8D\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1di\xc8=(\xff\x04t\xce\xeb\xea\xcb:\xd2'\xa1D\xec\u78ca\x01(\xcc\x03\x92\nb\u0480\x00\u07d4\x1d\x96\xbc\u0544W\xbb\xf1\xd3\u00a4o\xfa\xf1m\xbf}\x83hY\x89\tIr\t\xd8F~\x80\x00\u07d4\x1d\x9ej\xaf\x80\x19\xa0_#\x0e]\xef\x05\xaf]\x88\x9b\xd4\xd0\xf2\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x1d\xab\x17.\xff\xa6\xfb\xeeSL\x94\xb1~yN\xda\xc5OU\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1d\xb9\xac\x9a\x9e\xae\xec\nR7W\x05\fq\xf4rx\xc7-P\x89Hz\x9a0E9D\x00\x00\u07d4\x1d\xbe\x8e\x1c+\x8a\x00\x9f\x85\xf1\xad<\xe8\r.\x055\x0e\u3709\aW\rn\x9e\xbb\xe4\x00\x00\u07d4\x1d\xc7\xf7\xda\xd8]\xf5?\x12q\x15$\x03\xf4\xe1\xe4\xfd\xb3\xaf\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1d\u03bc\xb7em\xf5\u072a3h\xa0U\xd2/\x9e\xd6\xcd\xd9@\x89\x1b\x18\x1eK\xf24<\x00\x00\xe0\x94\x1d\xd7tA\x84J\xfe\x9c\xc1\x8f\x15\xd8\xc7{\xcc\xfbe^\xe04\x8a\x01\x06\xebEW\x99D\x88\x00\x00\u07d4\x1d\xde\xfe\xfd5\xab\x8fe\x8b$q\xe5G\x90\xbc\x17\xaf\x98\u07a4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d\xee\xc0\x1a\xbe\\\r\x95-\xe9\x10l=\xc3\x069\xd8P\x05\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1d\xf6\x91\x16rg\x9b\xb0\xef5\t\x03\x8c\f'\xe3\x94\xfd\xfe0\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\x1d\xfa\xee\ar\x12\xf1\xbe\xaf\x0eo/\x18@Sz\xe1T\xad\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1e\x06\r\xc6\xc5\xf1\u02cc\xc7\xe1E.\x02\xee\x16u\b\xb5eB\x8a\x02\xb1O\x02\xc8d\xc7~\x00\x00\xe0\x94\x1e\x13\xecQ\x14,\ubde2`\x83A,<\xe3QD\xbaV\xa1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1e\x1aH(\x11\x9b\xe3\t\xbd\x88#nMH+PM\xc5W\x11\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x1e\x1a\ud178leb\u02cf\xa1\xebo\x8f;\xc9\u072eny\x89\xf4\xd2\u0744%\x9b$\x00\x00\u07d4\x1e\x1ccQwj\xc3\x10\x919~\xcf\x16\x00-\x97\x9a\x1b-Q\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1e\x1dz_$h\xb9N\xa8&\x98-\xbf!%yR*\xb7\xdf\n\u02ac\x9e\xee\xd3Y09\xe5\xacuy\x8a+\x14F\xddj\xef\xe4\x1c\x00\x00\u07d4\x1e{^M\x1fW+\xec\xf2\xc0\x0f\xc9\f\xb4v{Jn3\u0509\x06\x1f\xc6\x10u\x93\xe1\x00\x00\u07d4\x1e\x8eh\x9b\x02\x91|\xdc)$]\f\x9ch\xb0\x94\xb4\x1a\x9e\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xa34\xb5u\b\a\xeat\xaa\u016b\x86\x94\xec_(\xaaw\u03c9\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x1e\xa4qU\x04\u01af\x10{\x01\x94\xf4\xf7\xb1\xcbo\xcc\xcdoK\x89 \x041\x97\xe0\xb0'\x00\x00\u07d4\x1e\xa4\x92\xbc\xe1\xad\x10~3\u007fK\u0527\xac\x9a{\xab\xcc\u036b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1e\xa6\xbf/\x15\xae\x9c\x1d\xbcd\u06a7\xf8\xeaM\r\x81\xaa\xd3\xeb\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1e\xb4\xbfs\x15j\x82\xa0\xa6\x82 \x80\xc6\xed\xf4\x9cF\x9a\xf8\xb9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\x1e\xba\xcbxD\xfd\xc3\"\xf8\x05\x90O\xbf\x19b\x80-\xb1S|\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1e\xc4\xecKw\xbf\x19\u0411\xa8h\xe6\xf4\x91T\x18\x05A\xf9\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xd0n\xe5\x16b\xa8lcE\x88\xfbb\xdcC\xc8\xf2~|\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1e\u063b?\x06w\x8b\x03\x9e\x99a\xd8\x1c\xb7\x1as\xe6x|\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xda\bNye\x00\xba\x14\xc5\x12\x1c\r\x90\x84of\xe4\xbeb\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4\x1e\xeel\xbe\xe4\xfe\x96\xadaZ\x9c\xf5\x85zdy@\u07ccx\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4\x1e\xf2\u073f\xe0\xa5\x00A\x1d\x95n\xb8\u0213\x9c=l\xfef\x9d\x89*\x11)\u0413g \x00\x00\xe0\x94\x1e\xf5\xc9\xc76P\u03fb\xde\\\x88U1\xd4'\xc7\xc3\xfeUD\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1f\x04\x12\xbf\xed\u0356N\x83}\t,q\xa5\xfc\xba\xf3\x01&\xe2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x17O@\xa0Dr4\xe6fS\x91Mu\xbc\x00>V\x90\u0709\b\xacr0H\x9e\x80\x00\x00\u07d4\x1f!\x86\xde\xd2>\f\xf9R\x16\x94\xe4\xe1dY>i\n\x96\x85\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x1f*\xfc\n\xed\x11\xbf\xc7\x1ew\xa9\ae{6\xeav\xe3\xfb\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x1f9Y\xfc)\x11\x10\xe8\x822\xc3kvg\xfcx\xa3ya?\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1f=\xa6\x8f\xe8~\xafC\xa8)\xabm~\u0166\xe0\t\xb2\x04\xfb\x89\x1e\x16\x01u\x8c,~\x00\x00\u07d4\x1fI\xb8m\r9EY\x06\x98\xa6\xaa\xf1g<7u\\\xa8\r\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\x1f_;4\xbd\x13K'\x81\xaf\xe5\xa0BJ\u0144l\xde\xfd\x11\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\u07d4\x1fo\x0004\x97R\x06\x1c\x96\a+\xc3\xd6\xeb5I \x8dk\x89\x01K\x8d\xe1\xeb\x88\u06c0\x00\u07d4\x1f}\x8e\x86\xd6\xee\xb0%E\xaa\xd9\x0e\x912{\xd3i\xd7\xd2\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x81\x16\xbd\n\xf5W\x0e\xaf\fV\u011cz\xb5\xe3zX\x04X\x89lk\x93[\x8b\xbd@\x00\x00\u0794\x1f\x88\xf8\xa13\x8f\xc7\xc1\tv\xab\xcd?\xb8\u04c5T\xb5\uc708\xb9\xf6]\x00\xf6<\x00\x00\u07d4\x1f\x9c2hE\x8d\xa3\x01\xa2\xbeZ\xb0\x82W\xf7{\xb5\xa9\x8a\xa4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1f\xa21\x9f\xed\x8c-F*\xdf.\x17\xfe\xecjo0Qn\x95\x89\x06\xca\xe3\x06!\xd4r\x00\x00\u07d4\x1f\xb4c\xa08\x99\x83\xdf}Y?{\xddmxI\u007f\xed\x88y\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\xb7\xbd1\r\x95\xf2\xa6\u067a\xaf\x8a\x8aC\n\x9a\x04E:\x8b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x1f\xcc|\xe6\xa8HX\x95\xa3\x19\x9e\x16H\x1fr\xe1\xf7b\xde\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1f\xcf\xd1\xd5\u007f\x87\"\x90V\f\xb6-`\x0e\x1d\xef\xbe\xfc\xcc\x1c\x89P\xc5\xe7a\xa4D\b\x00\x00\u0794\x1f\u0496\xbe\x03\xads|\x92\xf9\u0186\x9e\x8d\x80\xa7\x1cW\x14\xaa\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x1f\xdd\xd8_\u024b\xe9\xc4\x04Ya\xf4\x0f\x93\x80^\xccEI\xe5\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4 \x01\xbe\xf7{f\xf5\x1e\x15\x99\xb0/\xb1\x10\x19J\x00\x99\xb7\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \x02d\xa0\x9f\x8ch\xe3\xe6b\x97\x95(\x0fV%O\x86@\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x03qy\a\xa7%`\xf40\u007f\x1b\xee\xccT6\xf4=!\xe7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \r\xfc\vq\xe3Y\xb2\xb4eD\n6\xa6\xcd\xc3Rw0\a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4 \x13L\xbf\xf8\x8b\xfa\xdcFkR\xec\ua9d8W\x89\x1d\x83\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4 \x14&\x1f\x01\b\x9fSyV0\xba\x9d\xd2O\x9a4\xc2\xd9B\x89Hz\x9a0E9D\x00\x00\u07d4 \x16\x89]\xf3,\x8e\xd5G\x82iF\x84#\xae\xa7\xb7\xfb\xceP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x18\x1cKA\xf6\xf9r\xb6iX!_\x19\xf5p\xc1]\xdf\xf1\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4 \x18d\xa8\xf7\x84\xc2'{\v|\x9e\xe74\xf7\xb3w\xea\xb6H\x89\xf2(\x14\x00\xd1\xd5\xec\x00\x00\u07d4 \xb8\x1a\xe59&\xac\xe9\xf7\xd7AZ\x05\f\x03\x1dX_ \x89\x12\u007f\x19\xe8>\xb3H\x00\x00\xe0\x94 \x1d\x9e\xc1\xbc\v\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4 \xa1RV\xd5\f\xe0X\xbf\x0e\xacC\xaaS:\xa1n\u0273\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \xa2\x9cPy\xe2k?\x181\x8b\xb2\xe5\x0e\x8e\x8b4n[\xe8\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4 \xa8\x16\x80\xe4e\xf8\x87\x90\xf0\aO`\xb4\xf3_]\x1ej\xa5\x89Ea\x80'\x8f\fw\x80\x00\u07d4 \xb9\xa9\u6f48\x80\u0659J\xe0\r\u0439(*\v\xea\xb8\x16\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \u0084\xba\x10\xa2\b0\xfc=i\x9e\xc9}-\xfa'\xe1\xb9^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \xd1A\u007f\x99\xc5i\u3fb0\x95\x85e0\xfe\x12\xd0\xfc\uaa89@\x15\xf9K\x11\x83i\x80\x00\u07d4 \u074f\u02f4n\xa4o\u3066\x8b\x8c\xa0\xea[\xe2\x1f\u9949lk\x93[\x8b\xbd@\x00\x00\xe0\x94 \xff>\u078c\xad\xb5\xc3{H\xcb\x14X\x0f\xb6^#\t\n{\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\xe0\x94!\x008\x1d`\xa5\xb5J\xdc\t\u0456\x83\xa8\xf6\u057bK\xfb\u02ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x18\xc1\x16\xab\f\xdfo\xd1\x1dT\xa40\x93\a\xb4w\xc3\xfc\x0f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x1b)\xce\xfcy\xae\x97gD\xfd\xeb\u03bd<\xbb2\xc5\x13\x03\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4! l\xe2.\xa4\x80\xe8Y@\xd3\x13\x14\xe0\xd6ONM:\x04\x8965\u026d\xc5\u07a0\x00\x00\u07d4!2\xc0Qj.\x17\x17J\xc5G\xc4;{\x00 \xd1\xebLY\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94!@\x8bMz,\x0en\xcaAC\xf2\xca\u037b\u033a\x12\x1b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d4!Kt9U\xa5\x12\xden\r\x88j\x8c\xbd\x02\x82\xbe\xe6\u04a2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!L\x89\u017d\x8e}\"\xbcWK\xb3^H\x95\x02\x11\xc6\xf7v\x89\x01\x06T\xf2X\xfd5\x80\x00\xe0\x94!Ti\x14\xdf\u04ef*\xddA\xb0\xff>\x83\xff\xdat\x14\xe1\xe0\x8a\x01C\x95\xe78ZP.\x00\x00\u07d4!X.\x99\xe5\x02\xcb\xf3\xd3\xc2;\xdf\xfbv\xe9\x01\xacmV\xb2\x89\x05k\xc7^-c\x10\x00\x00\u07d4!Y$\b\x13\xa70\x95\xa7\xeb\xf7\u00f3t>\x80(\xae_\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!`\xb4\xc0,\xac\n\x81\u0791\b\xdeCE\x90\xa8\xbf\xe6\x875\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94!nA\x86N\xf9\x8f\x06\r\xa0\x8e\xca\xe1\x9a\xd1\x16j\x17\xd06\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4!\x84o/\xdfZA\xed\x8d\xf3n^\xd8TM\xf7Y\x88\xec\xe3\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94!\xa6\xdbe'F{\xc6\xda\xd5K\xc1n\x9f\xe2\x95;g\x94\xed\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4!\xa6\xfe\xb6\xab\x11\xc7f\xfd\xd9w\xf8\xdfA!\x15_G\xa1\xc0\x89\x03\x19\xcf8\xf1\x00X\x00\x00\u07d4!\xb1\x82\xf2\xda+8D\x93\xcf_5\xf8=\x9d\x1e\xe1O*!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xbf\xe1\xb4\\\xac\xdebt\xfd\x86\b\u0661x\xbf>\xebn\u0709l\xee\x06\u077e\x15\xec\x00\x00\u07d4!\xc0s\x80HOl\xbc\x87$\xad2\xbc\x86L;Z\xd5\x00\xb7\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94!\u00e8\xbb\xa2g\xc8\u0322{\x1a\x9a\xfa\xba\xd8o`z\xf7\b\x8a\x01\xe4\xa3lI\u06580\x00\x00\u07d4!\xcem[\x90\x18\xce\xc0J\u0596yD\xbe\xa3\x9e\x800\xb6\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4!\xd0'\x05\xf3\xf6I\x05\xd8\x0e\xd9\x14y\x13\xea\x8cs\a\u0595\x89I\xed\xb1\xc0\x98\x876\x00\x00\u07d4!\xd1?\f@$\xe9g\xd9G\a\x91\xb5\x0f\"\xde:\xfe\xcf\x1b\x89\xf1Z\xd3^.1\xe5\x00\x00\xe0\x94!\xdb\u06c1z\r\x84\x04\u01bd\xd6\x15\x047N\x9cC\xc9!\x0e\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\xe0\x94!\xdf\x1e\xc2KNK\xfey\xb0\xc0\x95\u03ba\xe1\x98\xf2\x91\xfb\u044a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94!\xdf-\u036ft\xb2\xbf\x804\x04\xddM\xe6\xa3^\xab\xec\x1b\xbd\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4!\xe2\x19\u021c\xa8\xac\x14\xaeL\xbaa0\xee\xb7}\x9em9b\x89*\u035f\xaa\xa08\xee\x00\x00\u07d4!\xe5\u04ba\xe9\x95\xcc\xfd\b\xa5\xc1k\xb5$\xe1\xf60D\x8f\x82\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4!\xe5\xd7s 0L \x1c\x1eS\xb2a\xa1#\u0421\x06>\x81\x89\x04\xb6\xfa\x9d3\xddF\x00\x00\xe0\x94!\xea\xe6\xfe\xff\xa9\xfb\xf4\u0347OG9\xac\xe50\u033eY7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4!\xec\xb2\u07e6Wy\xc7Y-\x04\x1c\xd2\x10Z\x81\xf4\xfdNF\x8965\u026d\xc5\u07a0\x00\x00\u07d4!\uff20\x9b5\x80\xb9\x8es\xf5\xb2\xf7\xf4\xdc\v\xf0,R\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xfd\v\xad\xe5\xf4\xeftt\xd0X\xb7\xf3\xd8T\xcb\x13\x00RN\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94!\xfdG\xc5%`\x12\x19\x8f\xa5\xab\xf11\xc0mj\xa1\x96_u\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4!\xfdl]\x97\xf9\xc6\x00\xb7h!\xdd\xd4\xe7v5\x0f\xce+\xe0\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\"\r\u018d\xf0\x19\xb6\xb0\u033f\xfbxKZZ\xb4\xb1]@`\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\"\x0e+\x92\xc0\xf6\xc9\x02\xb5\x13\xd9\xf1\xe6\xfa\xb6\xa8\xb0\xde\xf3\u05c9+^:\xf1k\x18\x80\x00\x00\u07d4\"V\x1cY1\x14560\x9c\x17\xe82X{b\\9\v\x9a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"W\xfc\xa1jn\\*d|<)\xf3l\xe2)\xab\x93\xb1~\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"]5\xfa\xed\xb3\x91\u01fc-\xb7\xfa\x90q\x16\x04\x05\x99m\x00\x89\t\x18T\xfc\x18bc\x00\x00\u07d4\"_\x9e\xb3\xfbo\xf3\xe9\xe3\xc8D~\x14\xa6n\x8dO7y\xf6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\"r\x18n\xf2}\xcb\xe2\xf5\xfc70P\xfd\xae\u007f*\xce#\x16\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4\"s\xba\u05fcNHv\"\xd1u\xefzf\x98\x8bj\x93\xc4\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\"v&K\xec\x85&\xc0\xc0\xf2pgz\xba\xf4\xf0\xe4A\xe1g\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\"\x82B\xf83n\xec\xd8$.\x1f\x00\x0fA\x93~q\xdf\xfb\xbf\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\"\x84*\xb80\xdaP\x99\x13\xf8\x1d\xd1\xf0O\x10\xaf\x9e\xdd\x1cU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x94O\xbc\xa9\xb5yc\bN\xb8M\xf7\xc8_\xb9\xbc\u07f8V\x89\xfc\x11\x8f\uf43a8\x80\x00\u07d4\"\x9c\xc4q\x1bbu^\xa2\x96DZ\u00f7\u007f\xc63\x82\x1c\xf2\x89\x02#\xe8\xb0R\x192\x80\x00\u0794\"\x9eC\r\xe2\xb7OD&Q\xdd\u0377\x01v\xbc\x05L\xadT\x88\xbb\xf9\x81\xbcJ\xaa\x80\x00\u07d4\"\x9fO\x1a*OT\atP[G\a\xa8\x1d\xe4D\x10%[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x9f\xf8\v\xf5p\x80\t\xa9\xf79\xe0\xf8\xb5`\x91@\x16\u0566\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4\"\xa2X\x12\xabV\xdc\xc4#\x17^\xd1\u062d\xac\xce3\xcd\x18\x10\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\"\xb9j\xb2\xca\xd5]\xb1\x00\xb50\x01\xf9\xe4\xdb7\x81\x04\xc8\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\"\xbd\xff\xc2@\xa8\x8f\xf7C\x1a\xf3\xbf\xf5\x0e\x14\xda7\xd5\x18>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xce4\x91Y\xee\xb1D\xef\x06\xff&6X\x8a\xefy\xf6(2\x89\n1\x06+\xee\xedp\x00\x00\u07d4\"\xdbU\x9f,<\x14u\xa2\xe6\xff\xe8:YyY\x91\x96\xa7\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xe1QX\xb5\xee>\x86\xeb\x032\xe3\u6a6cl\u0675^\u0349\b\xacr0H\x9e\x80\x00\x00\u07d4\"\xe2H\x8e-\xa2jI\xae\x84\xc0\x1b\xd5K!\xf2\x94x\x91\u0189]\u0212\xaa\x111\xc8\x00\x00\u07d4\"\xe5\x12\x14\x9a\x18\xd3i\xb7\x86\xc9\xed\xab\xaf\x1d\x89N\xe0.g\x14a\\\x00\x00\u07d4\"\xeb}\xb0\xbaV\xb0\xf8\xb8\x16\u0332\x06\xe6\x15\xd9)\x18[\r\x89\x04])s~\"\xf2\x00\x00\u07d4\"\xee\xd3'\xf8\xeb\x1d\x138\xa3\xcb{\x0f\x8aK\xaaY\a\u0355\x89\x01E]_Hw\b\x80\x00\xe0\x94\"\xf0\x04\u07cd\xe9\xe6\xeb\xf5#\u032c\xe4W\xac\xcb&\xf9r\x81\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\"\xf2\xdc\xffZ\u05cc>\xb6\x85\v\\\xb9Q\x12{e\x95\"\u623e -j\x0e\xda\x00\x00\u07d4\"\xf3\xc7y\xddy\x02>\xa9*x\xb6\\\x1a\x17\x80\xf6-\\J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\"\xfe\x88M\x907)\x1bMR\xe6(Z\xe6\x8d\xea\v\xe9\xff\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x06\u07d3\x1a\x94\rX\xc0\x16e\xfaM\b\x00\x80,\x02\xed\xfe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94#\t\xd3@\x91D[22Y\v\xd7\x0fO\x10\x02[,\x95\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#\x12\x00F\xf6\x83!\x02\xa7R\xa7fVi\x1c\x86>\x17\u5709\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4#\x1a\x15\xac\xc1\x99\u021f\xa9\xcb\"D\x1c\xc7\x030\xbd\xcc\xe6\x17\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4#\x1d\x94\x15]\xbc\xfe*\x93\xa3\x19\xb6\x17\x1fc\xb2\v\u04b6\xfa\x89\xcf\x14{\xb9\x06\xe2\xf8\x00\x00\u07d4#(2\xcdYw\xe0\nL0\xd0\x16?.$\xf0\x88\xa6\xcb\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4#,m\x03\xb5\xb6\xe6q\x1e\xff\xf1\x90\xe4\x9c(\xee\xf3l\x82\xb0\x89Hz\x9a0E9D\x00\x00\xe0\x94#,\xb1\xcdI\x99<\x14J?\x88\xb3a\x1e#5i\xa8k\u058a\x03L`lB\u042c`\x00\x00\u07d4#,\xe7\x82Pb%\xfd\x98`\xa2\xed\xc1Jz0Gsm\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4#/R]U\x85\x9b}N`\x8d H\u007f\xaa\xdb\x00)15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94#4\u0150\u01e4\x87i\x100E\u0176SL\x8a4i\xf4J\x8a\x03\xb1\x99\a=\xf7-\xc0\x00\x00\u07d4#7n\u02bftl\xe53!\xcfB\xc8fI\xb9+g\xb2\xff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#7\x8fB\x92m\x01\x84\xb7\x93\xb0\xc8'\xa6\xdd>=3O\u0349\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4#8B\xb1\xd0i/\xd1\x11@\xcfZ\u0364\xbf\x960\xba\xe5\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#9\xe9I(p\xaf\xea%7\xf3\x89\xac/\x83\x83\x02\xa3<\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#;\xdd\xdd]\xa9HR\xf4\xad\xe8\xd2\x12\x88V\x82\xd9\ak\u0189\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#OF\xba\xb7?\xe4]1\xbf\x87\xf0\xa1\xe0Fa\x99\xf2\ubb09\x1aJ\xba\"\\ t\x00\x00\u07d4#U\x1fV\x97_\xe9+1\xfaF\x9cI\xeaf\xeefb\xf4\x1e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4#V\x95B\xc9}V`\x18\xc9\a\xac\xfc\xf3\x91\xd1@g\xe8~\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94#_\xa6l\x02^\xf5T\x00p\xeb\xcf\r7-\x81w\xc4g\xab\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\xe0\x94#r\xc4\xc1\u0253\x9fz\xafl\xfa\xc0@\x90\xf0\x04t\x84\n\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#s\f5z\x91\x02nD\xb1\xd0\xe2\xfc*Q\xd0q\xd8\xd7{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#v\xad\xa9\x033\xb1\u0441\bL\x97\xe6E\xe8\x10\xaa[v\xf1\x89(\xa8WBTf\xf8\x00\x00\u07d4#x\xfdC\x82Q\x1e\x96\x8e\u0452\x10g7\xd3$\xf4T\xb55\x8965\u026d\xc5\u07a0\x00\x00\u07d4#\x82\xa9\u050e\xc8>\xa3e(\x90\xfd\x0e\u7710{[-\xc1\x89\a?u\u0460\x85\xba\x00\x00\u07d4#\x83\xc2\"\xe6~\x96\x91\x90\xd3!\x9e\xf1M\xa3xP\xe2lU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x8akv5%/RDHl\n\xf0\xa7: s\x85\xe09\x89JD\x91\xbdm\xcd(\x00\x00\u07d4#\x9as>k\x85Z\u0152\xd6c\x15a\x86\xa8\xa1t\xd2D\x9e\x89X\xbe7X\xb2A\xf6\x00\x00\xe0\x94#\xab\t\xe7?\x87\xaa\x0f;\xe0\x13\x9d\xf0\xc8\xebk\xe5cO\x95\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94#\xab\xd9\xe9>yW\xe5\xb66\xbeey\x05\x1c\x15\xe5\xce\v\x0e\x8a\x03\xa3\xc8\xf7\xcb\xf4,8\x00\x00\u07d4#\xb1\u0111\u007f\xbd\x93\xee=H8\x93\x06\x95s\x84\xa5Il\xbf\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94#\xba8d\xdaX=\xabV\xf4 \x87<7g\x96\x90\xe0/\x00\x8a\x02\x13BR\r_\xec \x00\x00\u07d4#\xc5Z\xebW9\x87o\n\xc8\xd7\xeb\xea\x13\xber\x96\x85\xf0\x00\x89Hz\x9a0E9D\x00\x00\u07d4#\u025b\xa0\x87D\x8e\x19\xc9p\x1d\xf6n\f\xabR6\x831\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xcc\xc3\u01ac\xd8\\.F\fO\xfd\xd8+\xc7]\xc8I\xea\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#\xcd%\x98\xa2\x0e\x14\x9e\xad*\u0593yWn\xce\xdb`\u3389lk\x93[\x8b\xbd@\x00\x00\u07d4#\u07cfH\xee\x00\x92V\xeay~\x1f\xa3i\xbe\xeb\xcfk\xc6c\x89|\xd3\xfa\xc2m\x19\x81\x80\x00\u07d4#\xe2\u01a8\xbe\x8e\n\u03e5\xc4\xdf^6\x05\x8b\xb7\u02ecZ\x81\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xeaf\x9e5d\x81\x9a\x83\xb0\xc2l\x00\xa1m\x9e\x82olF\x89M\x8dl\xa9h\xca\x13\x00\x00\u07d4#\xebo\xd8Vq\xa9\x06:\xb7g\x8e\xbe&Z \xf6\x1a\x02\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xf9\xec\xf3\xe5\xdd\u0723\x88\x15\xd3\xe5\x9e\xd3K[\x90\xb4\xa3S\x89\v\x17\x81\xa3\xf0\xbb \x00\x00\u07d4#\xfa~\xb5\x1aH\"\x95\x98\xf9~v+\xe0\x86\x96R\xdf\xfcf\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94$\x03\x05rs\x13\xd0\x1esT,w_\xf5\x9d\x11\xcd5\xf8\x19\x8a\x01A\x88Vf\x80\u007f\\\x80\x00\u07d4$\x04k\x91\u069ba\xb6)\u02cb\x8e\xc0\xc3Q\xa0~\a\x03\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\x0eU\x9e'J\xae\xf0\xc2X\x99\x8c\x97\x9fg\x1d\x11s\xb8\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94$\x13aU\x9f\xee\xf8\x0e\xf170!S\xbd\x9e\xd2\xf2]\xb3\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94$;;\xcaj)\x93Y\xe8\x86\xce3\xa3\x03A\xfa\xfeMW=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4$<\x84\xd1$ W\f\xc4\xef;\xab\xa1\xc9Y\u0083$\x95 \x89\u007f\x1fi\x93\xa8S\x04\x00\x00\xe0\x94$CJ>2\xe5N\xcf'/\xe3G\v_oQ/gU \x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4$HYo\x91\xc0\x9b\xaa0\xbc\x96\x10j-7\xb5p^](\x89lk\x93[\x8b\xbd@\x00\x00\u0794$Xn\xc5E\x175\xee\xaa\xebG\r\xc8sj\xaeu/\x82\xe5\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4$X\xd6U_\xf9\x8a\x12\x9c\xce@7\x95=\x00 n\xffB\x87\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4$b\x91\x16[Y3-\xf5\xf1\x8c\xe5\u0248V\xfa\xe9X\x97\u0589\\(=A\x03\x94\x10\x00\x00\u07d4$g\u01a5\u0196\xed\xe9\xa1\xe5B\xbf\x1a\xd0k\xccK\x06\xac\xa0\x89\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4$v\xb2\xbbu\x1c\xe7H\xe1\xa4\xc4\xff{#\v\xe0\xc1]\"E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4$z\n\x11\xc5\u007f\x03\x83\xb9I\xdeT\vf\xde\xe6\x86\x04\xb0\xa1\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4$\x87\xc3\u013e\x86\xa2r=\x91|\x06\xb4XU\x01p\xc3\xed\xba\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x89\xac\x12i4\xd4\u05a9M\xf0\x87C\xda{v\x91\xe9y\x8e\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x9d\xb2\x9d\xbc\x19\xd1#]\xa7)\x8a\x04\b\x1c1WB\u9b09a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4$\xa4\xeb6\xa7\xe4\x98\xc3o\x99\x97\\\x1a\x8dr\x9f\u05b3\x05\u05c9\r\xfcx!\x0e\xb2\xc8\x00\x00\u07d4$\xa7P\xea\xe5\x87G\x11\x11m\xd7\xd4{q\x86\u0399\r1\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xaa\x11Q\xbbv_\xa3\xa8\x9c\xa5\x0e\xb6\xe1\xb1\xc7\x06A\u007f\u0509\xa8\r$g~\xfe\xf0\x00\x00\u0794$\xac\xa0\x8d[\xe8^\xbb\x9f12\xdf\xc1\xb6 \x82N\xdf\xed\xf9\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4$\xb2\xbe\x11\x8b\x16\u0632\x17Gi\xd1{L\xf8O\a\u0294m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\xb8\xb4F\u07bd\x19G\x95]\u0404\xf2\xc5D\x933F\u04ed\x89\xeaim\x90@9\xbd\x80\x00\u07d4$\xb9^\xbe\xf7\x95\x00\xba\xa0\xed\xa7.w\xf8wA]\xf7\\3\x891T\xc9r\x9d\x05x\x00\x00\u07d4$\xb9\xe6dOk\xa4\xcd\xe1&'\r\x81\xf6\xab`\xf2\x86\xdf\xf4\x89\a?u\u0460\x85\xba\x00\x00\u07d4$\xbdY\x04\x05\x90\x91\xd2\xf9\xe1-j&\xa0\x10\xca\"\xab\x14\xe8\x89e\xea=\xb7UF`\x00\x00\u07d4$\xc0\u020bT\xa3TG\t\x82\x8a\xb4\xab\x06\x84\x05Y\xf6\xc5\u2250\xf54`\x8ar\x88\x00\x00\u07d4$\xc1\x17\xd1\u04b3\xa9z\xb1\x1aFy\u025awJ\x9e\xad\xe8\u044965\u026d\xc5\u07a0\x00\x00\u07d4$\xcf\xf0\xe93j\x9f\x80\xf9\xb1\u02d6\x8c\xafk\x1d\x1cI2\xa4\x89\n\xdaUGK\x814\x00\x00\u07d4$\u06aa\xdd\xf7\xb0k\xbc\ua6c0Y\x00\x85\xa8\x85gh+N\x89\x11K \x15\u04bb\xd0\x00\x00\u07d4$\xdc\xc2K\xd9\xc7!\f\xea\u03f3\r\xa9\x8a\xe0JM{\x8a\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\xf7E\r\xdb\xf1\x8b\x02\x0f\xeb\x1a 2\xd9\xd5Kc>\xdf7\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4$\xfcs\xd2\a\x93\t\x8e\t\u076bW\x98Pb$\xfa\x1e\x18P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xfd\x9al\x87L/\xab?\xf3n\x9a\xfb\xf8\xce\r2\xc7\u0792\x89Hz\x9a0E9D\x00\x00\u07d4%\n@\xce\xf3 #\x97\xf2@F\x95H\xbe\xb5bj\xf4\xf2<\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\u07d4%\niC\av\xf64w\x03\xf9R\x97\x83\x95Za\x97\xb6\x82\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4%\x0e\xb7\xc6o\x86\x9d\xdfI\u0685\xf39>\x98\f\x02\x9a\xa44\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x10j\xb6u]\xf8mkc\xa1\x87p;\f\xfe\xa0\u5520\x89\x01|@Z\xd4\x1d\xb4\x00\x00\xe0\x94%\x18_2Z\xcf-dP\x06\x98\xf6\\v\x9d\xdfh0\x16\x02\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x1c\x12r,hy\"y\x92\xa3\x04\xeb5v\xcd\x18CN\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\x1eh8\xf7\xce\u0173\x83\xc1\xd9\x01F4\x12t\xda\xf8\xe5\x02\x89\a\xff\x1c\xcbua\xdf\x00\x00\u07d4%%\x9d\x97Z!\xd8:\xe3\x0e3\xf8\x00\xf5?7\u07e0\x198\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4%({\x81_\\\x828\ns\xb0\xb1?\xba\xf9\x82\xbe$\xc4\u04c9\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94%+eU\xaf\u0700\xf2\xd9m\x97-\x17\u06c4\xeaZ\xd5!\xac\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4%8S)6\x81<\x91\xe6S(O\x01|\x80\u00f8\xf8\xa3o\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94%>2\xb7N\xa4I\n\xb9&\x06\xfd\xa0\xaa%{\xf2=\u02cb\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94%?\x1et*,\uc1b0\u05f3\x06\xe5\xea\xcbl\xcb/\x85T\x8a\x04>^\xde\x1f\x87\x8c \x00\x00\u07d4%A1J\v@\x8e\x95\xa6\x94DIwq*Pq5\x91\xab\x89X\x9e\x1a]\xf4\u05f5\x00\x00\u07d4%L\x1e\xccc\f(w\u0780\x95\xf0\xa8\u06e1\xe8\xbf\x1fU\f\x89\\(=A\x03\x94\x10\x00\x00\u07d4%Z\xbc\x8d\b\xa0\x96\xa8\x8f=j\xb5_\xbcsR\xbd\u0739\u0389\x04t6\x821>\u0780\x00\u07d4%[\xdddt\u0302b\xf2j\"\u00cfE\x94\x0e\x1c\ue99b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%`\xb0\x9b\x89\xa4\xaehI\xedZ<\x99XBf1qDf\x89\\(=A\x03\x94\x10\x00\x00\u07d4%a\xa18\xdc\xf8;\xd8\x13\xe0\xe7\xf1\bd+\xe3\xde=o\x05\x8964\xf4\x84\x17@\x1a\x00\x00\u0794%a\xec\x0f7\x92\x18\xfe^\xd4\xe0(\xa3\xf7D\xaaAuLr\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u0794%b\x92\xa1\x91\xbd\xda4\xc4\xdakk\u0591G\xbfu\u2a6b\x88\xc2\xff.\r\xfb\x03\x80\x00\u07d4%i~\xf2\f\u032ap\xd3-7o\x82r\xd9\xc1\a\f=x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%o\xa1P\u0307\xb5\x05j\a\xd0\x04\xef\xc8E$s\x9eb\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%r\x1c\x87\xb0\xdc!7|r\x00\xe5$\xb1J\"\xf0\xafi\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x899\xbb\xf0\f\x9d\xe9\xafS8\xf5\xd7\x14\xab\xf6\xd0\xc1\xc6q\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94%\x90\x12hp\xe0\xbd\xe8\xa6c\xab\x04\nr\xa5W=\x8dA\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x9e\xc4\xd2e\xf3\xabSk|p\xfa\x97\xac\xa1Bi,\x13\xfc\x89\x01\x1b\x1b[\xea\x89\xf8\x00\x00\xe0\x94%\xa5\x00\xee\xeczf*\x84\x15R\xb5\x16\x8bp{\r\xe2\x1e\x9e\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\xe0\x94%\xa5\xa4M8\xa2\xf4Lj\x9d\xb9\u037ck\x1e.\x97\xab\xb5\t\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4%\xa7L*\xc7]\u023a\xa8\xb3\x1a\x9c|\xb4\xb7\x82\x9b$V\u0689lk\x93[\x8b\xbd@\x00\x00\xe0\x94%\xad\xb8\xf9o9I,\x9b\xb4|^\u0708bNF\aV\x97\x8a\x05\xa9\x94\v\xc5hyP\x00\x00\u07d4%\xae\xe6\x8d\t\xaf\xb7\x1d\x88\x17\xf3\xf1\x84\xecV/x\x97\xb74\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xb0S;\x81\xd0*a{\x92)\xc7\xec]o/g.[Z\x8965\u026d\xc5\u07a0\x00\x00\u07d4%\xb7\x8c\x9f\xad\x85\xb43C\xf0\xbf\xcd\x0f\xac\x11\u0254\x9c\xa5\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xbcI\xef(\x8c\xd1e\xe5%\xc6a\xa8\x12\u03c4\xfb\xec\x8f3\x89\x12Y!\xae\xbd\xa9\xd0\x00\x00\u07d4%\xbd\xfa>\xe2o8Ia{#\x00bX\x8a\x97\xe3\xca\xe7\x01\x8965\xe6\x19\xbb\x04\xd4\x00\x00\u07d4%\xc1\xa3~\xe5\xf0\x82e\xa1\xe1\r=\x90\xd5G)U\xf9x\x06\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4%\xc6\xe7O\xf1\xd9(\u07d8\x13z\xf4\u07c40\xdf$\xf0|\u05c9\x15$VU\xb1\x02X\x00\x00\xe0\x94%\xcf\xc4\xe2\\5\xc1;i\xf7\xe7}\xbf\xb0\x8b\xafXuk\x8d\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94%\xda\u0515\xa1\x1a\x86\xb9\xee\xec\xe1\xee\xec\x80^W\xf1W\xfa\xff\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94%\xe07\xf0\n\x18'\v\xa5\xec4 \"\x9d\xdb\n,\u33e2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4%\xe6a\xc99\x86:\xcc\x04No\x17\xb5i\x8c\xce7\x9e\xc3\u0309JD\x91\xbdm\xcd(\x00\x00\u07d4&\x04\x8f\xe8M\x9b\x01\nb\xe71b~I\xbc.\xb7?@\x8f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\x06\u00f3\xb4\xca\x1b\t\x14\x98`,\xb1\x97\x8b\xf3\xb9R!\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4&\n#\x0eDe\a~\v\x14\xeeDB\xa4\x82\u0570\xc9\x14\xbf\x89Z\xf6\x06\xa0k[\x11\x80\x00\u07d4&\r\xf8\x94:\x8c\x9a]\xbayE2\u007f\xd7\xe0\x83|\x11\xad\a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4&\x14\xf4-]\xa8D7ux\xe6\xb4H\xdc$0[\xef+\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\x15\x10\x0e\xa7\xe2[\xba\x9b\xcat`X\xaf\xbb\xb4\xff\xbeBD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4&\x15u\xe9\xcfY\xc8\"o\xa7\xaa\xf9\x1d\xe8o\xb7\x0fZ\u00ee\x89\x10C\xa4CjR?\x00\x00\xe0\x94&\x1e\x0f\xa6LQ\x13te\xee\xcf[\x90\xf1\x97\xf7\x93\u007f\xdb\x05\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4&*\x8b\xfd}\x9d\xc5\xdd:\u05c1a\xb6\xbbV\b$76U\x89?j\x83\x84\a+v\x00\x00\xe0\x94&*\xedK\xc0\xf4\xa4\xb2\xc6\xfb5y>\x83ZI\x18\x9c\xdf\xec\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94&-\xc16L\xcfm\xf8\\C&\x8e\xe1\x82UM\xaei.)\x8a\x01\v /\xect\xce\xd8\x00\x00\u07d4&8\x140\x9d\xe4\xe65\xcfX^\r6Tw\xfc@\xe6l\xf7\x89\a\xea(2uw\b\x00\x00\u07d4&9\xee\xe9\x87<\xee\xc2o\u0314T\xb5H\xb9\xe7\xc5J\xa6\\\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94&>W\xda\xcb\xe0\x14\x9f\x82\xfee\xa2fH\x98\x86o\xf5\xb4c\x8a\b\v\xfb\xef\xcb_\v\xc0\x00\x00\u07d4>\x19\xc0m_\x14z\xa5\x97$\x8e\xb4l\xf7\xbe\xfad\xa5\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4&L\xc8\bj\x87\x10\xf9\x1b!r\t\x05\x91,\u05d6J\xe8h\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94&S\x83\u058bR\xd04\x16\x1b\xfa\xb0\x1a\xe1\xb0G\x94/\xbc2\x8a\x04rq\xde\xe2\rt\\\x00\x00\u07d4&Y\xfa\xcb\x1e\x83CeS\xb5\xb4)\x89\xad\xb8\a_\x99S\xed\x89\x01\x97evw\x1a^\x00\x00\xe0\x94&o-\xa7\xf0\b^\xf3\xf3\xfa\t\xba\xee#+\x93\xc7D\xdb.\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4&qH\xfdr\xc5Ob\nY/\xb9'\x991\x9c\xc4S+\\\x89\x169\u46fa\x16(\x00\x00\xe0\x94&xJ\u0791\u0228:\x8e9e\x8c\x8d\x82wA<\u0319T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4&z~n\x82\xe1\xb9\x1dQ\xde\u0776D\xf0\xe9m\xbb\x1f\u007f~\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\x80q=@\x80\x8e*P\xed\x011P\xa2\xa6\x94\xb9j\u007f\x1d\x89a\t=|,m8\x00\x00\u07d4&\x97\xb39\x81;\f-\x96K$q\xeb\x1c`oN\u02d6\x16\x89>\x8e\xf7\x95\u0610\xc8\x00\x00\u07d4&\xa6\x8e\xab\x90Z\x8b=\xce\x00\xe3\x170\x82%\u06b1\xb9\xf6\xb8\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4&\xb1\x1d\x06e\x88\xcet\xa5r\xa8Zc(s\x92\x12\xaa\x8b@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xba\xbfB\xb2g\xfd\xcf8a\xfd\xd4#j^GHH\xb3X\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xc0\x05Kp\r:|-\xcb\xe2uh\x9dOL\xad\x16\xa35\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xc2\xff\xc3\x0e\xfd\xc5'>v\x18:\x16\xc2i\x8dnS\x12\x86\x89*\x11)\u0413g \x00\x00\u07d4&\u025f\x88I\u0240+\x83\xc8a!\u007f\xd0z\x9e\x84\u0377\x9d\x89\x10CV\x1a\x88)0\x00\x00\u07d4&\xcf\xff\xd0R\x15+\xb3\xf9W\xb4x\xd5\xf9\x8b#:|+\x92\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\u0521h\x91\xf5)\"x\x92\x17\xfc\u0606\xf7\xfc\xe2\x96\xd4\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xd4\xec\x17\xd5\u03b2\u0214\xbd\u015d\nji]\xad+C\u0309\x9f\x1fxv\x1d4\x1a\x00\x00\u07d4&\xe8\x01\xb6,\x82q\x91\xddh\xd3\x1a\x01\x19\x90\x94\u007f\xd0\xeb\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\xe9\xe2\xadr\x97\x02bd\x17\xef%\xde\r\xc8\x00\xf7\xa7y\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xf9\xf7\xce\xfd~9K\x9d9$A+\xf2\u0083\x1f\xaf\x1f\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94&\xfe\x17L\xbfRfP\xe0\xcd\x00\x9b\xd6\x12e\x02\u038ehM\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\xe0\x94&\xff\nQ\xe7\xce\u0384\x00'ix\xdb\xd6#n\xf1b\xc0\xe6\x8a\x15.\x18V'T\nP\x00\x00\u07d4'\x10\x1a\x0fV\u04da\x88\u0168O\x9b2L\xdd\xe3>\\\xb6\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x14L\xa9\xa7w\x1a\x83j\xd5\x0f\x80?d\xd8i\xb2\xae+ \x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4'\x14i\x13V:\xa7E\xe2X\x840\xd94\x8e\x86\xea|5\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4'\x1d=H\x1c\xb8\x8evq\xad!iI\xb66^\x060=\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4' \xf9\xcaBn\xf2\xf2\xcb\xd2\xfe\xcd9\x92\fO\x1a\x89\xe1m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'*\x13\x1aZejz:\xca5\u023d \"\"\xa7Y\"X\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4'D\xffgFA!\xe3Z\xfc)\"\x17qd\xfa/\xcb\x02g\x89\x05k\xc7^-c\x10\x00\x00\u07d4'J=w\x1a=p\x97\x96\xfb\xc4\xd5\xf4\x8f\xce/\xe3\x8cy\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4'Mi\x17\x0f\xe7\x14\x14\x01\x88+\x88j\xc4a\x8cj\xe4\x0e\u06c93\xc5I\x901r\f\x00\x00\u07d4'R\x1d\xeb;n\xf1An\xa4\u01c1\xa2\xe5\u05f3n\xe8\x1ca\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'Xu\xffO\xbb\f\xf3\xa40!1'H\u007fv\b\xd0L\xba\x89\x1b\x1c\x01\x0evmX\x00\x00\u07d4'j\x00n0(\xec\xd4L\xdbb\xba\nw\u0394\xeb\xd9\xf1\x0f\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4'k\x05!\xb0\xe6\x8b'}\xf0\xbb2\xf3\xfdH2cP\xbf\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4'o\xd7\xd2O\x8f\x88?Zz()[\xf1qQ\u01e8K\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'p\xf1N\xfb\x16]\u07bay\xc1\v\xb0\xaf1\xc3\x1eY3L\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4'vw\xab\xa1\xe5,;S\xbf\xa2\a\x1dN\x85\x9a\n\xf7\xe8\xe1\x8965\u026d\xc5\u07a0\x00\x00\u07d4'\x82Ff\xd2x\xd7\x04#\xf0=\xfe\x1d\u01e3\xf0/C\u2d4966\xc2^f\xec\xe7\x00\x00\u07d4'\x83\f_`#\xaf\xaa\xf7\x97Egl J\x0f\xac\u0360\xba\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94'\x84\x90?\x1d|\x1b\\\xd9\x01\xf8\x87]\x14\xa7\x9b<\xbe*V\x8a\x04\xbd\xa7\xe9\xd7J\xd5P\x00\x00\u07d4'\x8c\v\xdec\x0e\u00d3\xb1\xe7&\u007f\xc9\xd7\xd9p\x19\xe4\x14[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x98q\x10\"\x1a\x88\b&\xad\xb2\xe7\xab^\xcax\xc6\xe3\x1a\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94'\xac\a;\xe7\x9c\xe6W\xa9:\xa6\x93\xeeC\xbf\x0f\xa4\x1f\xef\x04\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4'\xb1iN\xaf\xa1e\xeb\xd7\xcc{\u025et\x81J\x95\x14\x19\u0709+^:\xf1k\x18\x80\x00\x00\u07d4'\xb6(\x16\xe1\xe3\xb8\u045by\xd1Q=]\xfa\x85[\f:*\x89\x05j\xf5\xc1\xfdiP\x80\x00\u07d4'\xbf\x94<\x163\xfe2\xf8\xbc\xcc\xdbc\x02\xb4\a\xa5rND\x892\xf8Lm\xf4\b\xc0\x80\x00\u07d4'\xbf\x9fD\xba}\x05\xc35@\u00e5;\xb0,\xbb\xff\xe7\xc3\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4'\xc2\xd7\xcaPM\xaa=\x90f\xdc\t\x13}\xc4/:\xaa\xb4R\x89 \x86\xac5\x10R`\x00\x00\u07d4'\xd1X\xac=>\x11\t\xabnW\x0e\x90\xe8]8\x92\xcdv\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4'\xe69\x89\xca\x1e\x90;\xc6 \xcf\x1b\x9c?g\xb9\xe2\xaee\x81\x89Hz\x9a0E9D\x00\x00\xe0\x94'\xf0<\xf1\xab\xc5\xe1\xb5\x1d\xbcDK(\x9eT,\x9d\u07f0\xe6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4'\xfc\x85\xa4\x9c\xff\x90\xdb\xcf\xda\u071d\xdd@\u05b9\xa2!\nl\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\x05A^\x1d\u007f\xde\xc6\xde\u07f8\x9eR\x1d\x10Y-t<\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\a>\xfc\x17\xd0\\\xab1\x95\xc2\xdb3+a\x98Gw\xa6\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x12P\xa2\x91!'\nN\xe5\u05cd$\xfe\xaf\xe8,p\xba:\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x13\xd2c\xfc_\xf2G\x9e\x97\x05\x95\u05b6\xb5`\xf8\xd6\xd6\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4(.\x80\xa5T\x87ZVy\x9f\xa0\xa9\u007fU\x10\u7557LN\x8965\u026d\xc5\u07a0\x00\x00\u07d4(3\x96\xce<\xac9\x8b\xcb\xe7\"\u007f2>x\xff\x96\u0407g\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4(4\x9f~\xf9t\xeaU\xfe6\xa1X;4\xce\xc3\xc4Pe\xf0\x89\f\xb63\u051eeY\x00\x00\u07d4(6\x120F\xb2\x84\xe5\xef\x10+\xfd\"\xb1v^P\x81\x16\xad\x89\x16S\xfb\xb5\xc4'\xe4\x00\x00\u07d4(<#\x14(<\x92\u0530d\xf0\xae\xf9\xbbRF\xa7\x00\u007f9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(>\x11 7I\xb1\xfaO2\xfe\xbbq\xe4\x9d\x13Y\x198*\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(>bR\xb4\xef\xcfFT9\x1a\xcbu\xf9\x03\u015bx\xc5\xfb\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94(Q\x0en\xff\x1f\xc8)\xb6WoC(\xbc98\xecze\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4(X\xac\xac\xaf!\xea\x81\u02b7Y\x8f\xdb\xd8kE.\x9e\x8e\x15\x89$\x1a\x9bOaz(\x00\x00\u07d4(Z\xe5\x1b\x95\x00\u014dT\x13e\xd9ui\xf1K\xb2\xa3p\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(f\xb8\x1d\xec\xb0.\xe7\n\xe2P\xce\xe5\xcd\xc7{Y\u05f6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(i\x06\xb6\xbdIr\xe3\xc7\x16U\xe0K\xaf6&\f|\xb1S\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4(k\x18ma\xea\x1f\u05cd\x990\xfe\x12\xb0e7\xb0\\=Q\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(t\xf3\xe2\x98]_{@f'\xe1{\xaaw+\x01\xab\u031e\x8a\x01F\x05\x04\x10v_8\x00\x00\xe0\x94(|\xf9\u0410.\xf8\x19\xa7\xa5\xf1ID[\xf1w^\xe8\xc4|\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4(\x81\x8e\x18\xb6\x10\x00\x13!\xb3\x1d\xf6\xfe}(\x15\u036d\xc9\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x86\x83$3~\x11\xba\x10l\xb4\x81\u0696/:\x84S\x80\x8d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94(\x90K\xb7\xc40)C\xb7\t\xb1Myp\xe4+\x83$\u184a\x02\x1f\x97\x84j\a-~\x00\x00\u07d4(\x95\xe8\t\x99\xd4\x06\xadY.+&'7\xd3_}\xb4\xb6\x99\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4(\x96r\x80!N!\x8a\x12\f]\xda7\x04\x1b\x11\x1e\xa3mt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(\xa3\xda\t\xa8\x19H\x19\xae\x19\x9f.m\x9d\x13\x04\x81~(\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(\xab\x16_\xfbi\xed\xa0\xc5I\xae8\xe9\x82o_\u007f\x92\xf8S\x89FM\xf6\xd7\xc8DY\x00\x00\u07d4(\xb7u\x85\xcb=U\xa1\x99\xab)\x1d:\x18\u018f\u8684\x8a\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94(\xd4\xeb\xf4\x1e=\x95\xf9\xbb\x9a\x89u#\\\x1d\x009>\x80\x00\u07d4)\nV\xd4\x1fn\x9e\xfb\xdc\xea\x03B\u0dd2\x9a\x8c\xdf\xcb\x05\x89\x12\xa5\xf5\x81h\xee`\x00\x00\u07d4)\x15bK\xcbg\x917\xb8\xda\xe9\xabW\xd1\x1bI\x05\xea\xeeK\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4)\x1e\xfe\x00\x81\xdc\xe8\xc1G\x99\xf7\xb2\xa46\x19\xc0\u00f3\xfc\x1f\x89A\rXj \xa4\xc0\x00\x00\u07d4)\x1f\x92\x9c\xa5\x9bT\xf8D>=Mu\xd9]\xee$<\xefx\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x94))\x8c\xcb\xdf\xf6\x89\xf8\u007f\xe4\x1a\xa6\xe9\x8f\u07f5=\xea\xf3z\x8a\x041\\2\xd7\x1a\x9e`\x00\x00\u07d4)/\"\x8b\n\x94t\x8c\x8e\xeca-$o\x98\x93c\xe0\x8f\b\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4)3\x84\xc4+o\x8f)\x05\xceR\xb7 \\\"t7la+\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4)4\xc0\xdf{\xbc\x17+l\x18k\vrTz\u038b\xf7TT\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4)<#\x06\xdf6\x04\xaeO\xda\r z\xbasog\xde\a\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)I\xfd\x1d\xef\\v\xa2\x86\xb3\x87$$\x80\x9a\a\xdb9f\xf3\x8a\x01\x1b\xd9\x06\u06a0\xc9C\x80\x00\u07d4)OIK?.\x14\xa3\xf8\xab\x00\x00\x00\u07d4)U\xc3W\xfd\x8fu\xd5\x15\x9a=\xfai\u0178z5\x9d\ua309lk\x93[\x8b\xbd@\x00\x00\u07d4)a\xfb9\x1ca\x95|\xb5\xc9\xe4\a\u0762\x938\u04f9,\x80\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4)h\x1d\x99\x12\xdd\xd0~\xaa\xbb\x88\xd0]\x90\xf7f\xe8bA}\x8965\u026d\xc5\u07a0\x00\x00\u07d4)kq\xc0\x01X\x19\xc2B\xa7\x86\x1eo\xf7\xed\xed\x8a_q\xe3\x89lh\xcc\u041b\x02,\x00\x00\u07d4)mf\xb5!W\x1aNA\x03\xa7\xf5b\xc5\x11\xe6\xaas-\x81\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4)o\x00\xde\x1d\u00fb\x01\xd4z\x8c\xcd\x1e]\x1d\u0661\xebw\x91\x8965\u026d\xc5\u07a0\x00\x00\u07d4)s\x85\xe8\x864FV\x85\xc21\xa3\x14\xa0\xd5\xdc\xd1F\xaf\x01\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4)v=\xd6\u069a|\x16\x11s\x88\x83!\ub9b6<\x8f\xb8E\x89\x11\xc7\xea\x16.x \x00\x00\u07d4)yt\x11t\xa8\xc1\xea\v\u007f\x9e\xdfe\x81w\x85\x94\x17\xf5\x12\x89\x19\x01\x96l\x84\x96\x83\x80\x00\u07d4)z\x88\x92\x1b_\xca\x10\u5edd\xed`\x02T7\xae\"\x16\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)}]\xbe\"//\xb5%1\xac\xbd\v\x01=\xc4F\xacsh\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\x82N\x94\xccCH\xbc\x962y\xdc\xdfG9\x17\x152L\u04c9i*\xe8\x89p\x81\xd0\x00\x00\u07d4)\x82\xd7j\x15\xf8G\xddA\xf1\x92*\xf3h\xfeg\x8d\x0eh\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\x88\x87\xba\xb5|[\xa4\xf0aR)\xd7R_\xa1\x13\xb7\ua249\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94)\x8e\xc7kD\r\x88\a\xb3\xf7\x8b_\x90\x97\x9b\xeeB\xedC\u06ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4)\x93h`\x90B\xa8X\xd1\xec\xdf\x1f\xc0\xad\xa5\xea\xce\xca)\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4)\x9e\v\xcaU\xe0i\u0785\x04\xe8\x9a\xcan\xca!\u04ca\x9a]\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4)\xac+E\x84T\xa3l~\x96\xc7:\x86g\"*\x12$,q\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xad\u03c3\xb6\xb2\n\u01a44\xab\xb1\x99<\xbd\x05\xc6\x0e\xa2\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94)\xae\xf4\x8d\xe8\xc9\xfb\xadK\x9eL\xa9pyzU3\xebr-\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4)\xb3\xf5a\xeezn%\x94\x1e\x98\xa52[x\xad\u01d7\x85\xf3\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\xbd\xc4\xf2\x8d\xe0\x18\x0fC<&\x94\xebt\xf5PL\xe9C7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\u0300M\x92+\xe9\x1fY\t\xf3H\xb0\xaa\xa5\xd2\x1b`x0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xda>5\xb2;\xb1\xf7/\x8e\"X\xcf\u007fU3Y\xd2K\xac\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94)\xe6y\x90\xe1\xb6\xd5.\x10U\xff\xe0I\xc51\x95\xa8\x15B\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\uab82v\x17b\xf4\xd2\xdbS\xa9\u018b\x0fk\vmNf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\xeb~\xef\xda\xe9\xfe\xb4I\xc6?\xf5\xf2y\xd6u\x10\xeb\x14\"\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4)\xf0\xed\xc6\x038\xe7\x11 \x85\xa1\xd1\x14\u068cB\u038fU\u0589\xa0Z\u007f\x0f\xd8%x\x00\x00\u07d4)\xf8\xfb\xa4\xc3\ar\xb0W\xed\xbb\xe6*\xe7B\f9\x05r\xe1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94)\xf9(l\x0es\x8d\x17!\xa6\x91\u01b9Z\xb3\u0667\x97\xed\xe8\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4*\b^%\xb6Hb\xf5\xe6\x8dv\x8e+\x0fz\x85)\x85\x8e\xee\x89k\x88:\xcdWf\xcd\x00\x00\u07d4**\xb6\xb7Lz\xf1\xd9Gk\xb5\xbc\xb4RG\x97\xbe\xdc5R\x8965\u026d\xc5\u07a0\x00\x00\u07d4*9\x19\nO\u0783\u07f3\xdd\xcbL_\xbb\x83\xaclIu\\\x8965\u026d\xc5\u07a0\x00\x00\u07d4*@\r\xff\x85\x94\xder(\xb4\xfd\x15\xc3#\"\xb7[\xb8}\xa8\x89\x051\xa1\u007f`z-\x00\x00\xe0\x94*D\xa7!\x8f\xe4Me\xa1\xb4\xb7\xa7\u0671\xc2\xc5,\x8c>4\x8a\r-\x06\xc3\x05\xa1\xebW\x80\x00\u07d4*F\xd3Swqv\xff\x8e\x83\xff\xa8\x00\x1fOp\xf9s:\xa5\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4*Y_\x16\xee\xe4\xcb\f\x17\u0662\xd99\xb3\xc1\x0flgrC\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4*Y\xe4~\xa5\xd8\xf0\xe7\xc0(\xa3\xe8\xe0\x93\xa4\x9c\x1bP\xb9\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*[\xa9\xe3L\u054d\xa5L\x9a'\x12f:;\xe2t\xc8\xe4{\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94*^:@\xd2\xcd\x03%vm\xe7:=g\x18\x96\xb3b\xc7;\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94*cY\x0e\xfe\x99\x86\xc3\xfe\xe0\x9b\n\n3\x8b\x15\xbe\xd9\x1f!\x8a\x01^\x1cN\x05\xee&\xd0\x00\x00\u07d4*gf\n\x13h\xef\xcdbn\xf3k+\x1b`\x19\x80\x94\x1c\x05\x89\a?u\u0460\x85\xba\x00\x00\u07d4*t+\x89\x10\x94\x1e\t2\x83\n\x1d\x96\x92\xcf\u0484\x94\xcf@\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4*tl\xd4@'\xaf>\xbd7\xc3x\xc8^\xf7\xf7T\xab_(\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4*\x81\xd2|\xb6\xd4w\x0f\xf4\xf3\u0123\xba\x18\xe5\xe5\u007f\aQ|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*\x91\xa9\xfe\xd4\x1b}\x0e\\\xd2\xd81X\xd3\xe8\xa4\x1a\x9a-q\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94*\x9cW\xfe{k\x13\x8a\x92\rgo{\x1a%\x10\x80\xff\xb9\x8a4\xf0\x86\xf3\xb3;h@\x00\x00\u07d4+p\x1d\x16\xc0\xd3\xcc\x1eL\xd8TE\xe6\xad\x02\ue92c\x01-\x89 \x86\xac5\x10R`\x00\x00\xe0\x94+q|\xd42\xa3#\xa4e\x909\x84\x8d;\x87\xde&\xfc\x95F\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4+t\xc3s\xd0K\xfb\x0f\xd6\n\x18\xa0\x1a\x88\xfb\xe8Gp\u5309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4+w\xa4\u060c\rV\xa3\xdb\xe3\xba\xe0J\x05\xf4\xfc\u0477W\xe1\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94+\x84\x88\xbd-<\x19z=&\x15\x18\x15\xb5\xa7\x98\xd2qh\u070a\x01j\x1f\x9f_\xd7\xd9`\x00\x00\u07d4+\x8a\r\xee\\\xb0\xe1\xe9~\x15\xcf\xcan\x19\xad!\xf9\x95\ufb49\x1bUC\x8d\x9a$\x9b\x00\x00\xe0\x94+\x8f\xe4\x16n#\xd1\x19c\xc0\x93+\x8a\u078e\x01E\xea\ap\x8a\t(\x96R\x9b\xad\u0708\x00\x00\xe0\x94+\x99\xb4.OBa\x9e\xe3k\xaa~J\xf2\xd6^\xac\xfc\xba5\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4+\xab\x0f\xbe(\u0544 \xb5 6w\n\x12\xf9\x95*\xeai\x11\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4+\xad\xe9\x1d\x15E\x17b\x0f\u05349\xac\x97\x15zA\x02\xa9\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4+\xaf\x8dn\"\x11t\x12H \xeeI+\x94Y\xecO\xad\xaf\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xaf\xbf\x9e\x9e\xd2\xc2\x19\xf7\xf2y\x13t\xe7\xd0\\\xb0gw\xe7\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94+\xb3f\xb9\xed\xcb\r\xa6\x80\xf0\xe1\v;n(t\x81\x90\xd6\u00ca\x01:b\u05f5v@d\x00\x00\xe0\x94+\xb6\xf5x\xad\xfb\u7ca1\x16\xb3UO\xac\xf9\x96\x98\x13\xc3\x19\x8a\x01\x91'\xa19\x1e\xa2\xa0\x00\x00\u07d4+\xbeb\xea\xc8\f\xa7\xf4\xd6\xfd\xee~}\x8e(\xb6:\xcfw\x0e\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4+\xbeg*\x18WP\x8fc\x0f*^\xdbV=\x9e\x9d\xe9(\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xc4)\xd6\x18\xa6jL\xf8-\xbb-\x82N\x93V\xef\xfa\x12j\x89lj\xccg\u05f1\xd4\x00\x00\u07d4+\xd2R\xe0\xd72\xff\x1d|x\xf0\xa0.l\xb2T#\xcf\x1b\x1a\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4+\xdd\x03\xbe\xbb\xee';l\xa1\x05\x9b4\x99\x9a[\xbda\xbby\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\x04\x11\\>R\x96\x1b\r\xc0\xb0\xbf1\xfb\xa4ToYf\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94,\x06\u0752+aQJ\xaf\xed\xd8D\x88\xc0\u008em\xcf\x0e\x99\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94,\f\xc3\xf9QH,\u0222\x92X\x15hN\xb9\xf9N\x06\x02\x00\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4,\x0e\xe14\u0633aE\xb4{\xee\u7bcd'8\xdb\xda\b\xe8\x89\n\xe5os\x0em\x84\x00\x00\u07d4,\x0f[\x9d\xf46%y\x8e~\x03\xc1\xa5\xfdjm\t\x1a\xf8+\x89\x01\xb0\xfc\xaa\xb2\x000\x00\x00\u07d4,\x12\x8c\x95\xd9W!Q\x01\xf0C\u074f\u0142EmA\x01m\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4,\x18\x00\xf3_\xa0->\xb6\xff[%(_^J\xdd\x13\xb3\x8d\x891\"\u04ed\xaf\xde\x10\x00\x00\u07d4,\x1c\x19\x11N=m\xe2xQHK\x8d'\x15\xe5\x0f\x8a\x10e\x89\x05k\xc7^-c\x10\x00\x00\u07d4,\x1c\xc6\xe1\x8c\x15$\x88\xba\x11\xc2\xcc\x1b\xce\xfa-\xf3\x06\xab\u0449Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94,\x1d\xf8\xa7oH\xf6\xb5K\u03dc\xafV\xf0\xee\x1c\xf5z\xb3=\x8a\x02$\u007fu\x00\x89\xdaX\x00\x00\u07d4,!G\x94z\xe3?\xb0\x98\xb4\x89\xa5\xc1k\xff\xf9\xab\xcdN*\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,#OP\\\xa8\xdc\xc7}\x9b~\x01\xd2W\xc3\x18\xcc\x199m\x89\x05k\xc7^-c\x10\x00\x00\u07d4,$(\xe4\xa6it\xed\xc8\"\xd5\xdb\xfb$\x1b'(\aQX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,-\x15\xff9V\x1c\x1br\xed\xa1\xcc\x02\u007f\xfe\xf27C\xa1D\x89\u0500\xed\x9e\xf3+@\x00\x00\u07d4,-\xb2\x8c3\t7^\xea1\x82\x1b\x84\xd4\b\x93\x0e\xfa\x1a\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4,Z-\n\xbd\xa0;\xbe!W\x81\xb4\xff)l\x8ca\xbd\xba\xf6\x89\x01\xa8\xe5oH\xc0\"\x80\x00\u07d4,[}{\x19Z7\x1b\xf9\xab\u0774/\xe0O/\x1d\x9a\x99\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,]\xf8ffj\x19K&\u03bb@~J\x1f\xd7> \x8d^\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94,`?\xf0\xfe\x93alCW>\xf2y\xbf\xea@\x88\x8dj\xe7\x8a\x01\x00\xf4\xb6\xd6gW\x90\x00\x00\xe0\x94,hF\xa1\xaa\x99\x9a\"F\xa2\x87\x05`\x00\xbaM\u02e8\xe6=\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\u0794,j\xfc\xd4\x03|\x1e\xd1O\xa7O\xf6u\x8e\tE\xa1\x85\xa8\xe8\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4,ki\x9d\x9e\xad4\x9f\x06\u007fEq\x1a\aJd\x1d\xb6\xa8\x97\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,o\\\x12L\u01c9\xf8\xbb9\x8e?\x88\x97Q\xbcK`-\x9e\x89\x01Y\xf2\v\xed\x00\xf0\x00\x00\u07d4,\x83\xae\xb0/\xcf\x06}e\xa4p\x82\xfd\x97x3\xab\x1c\uc449\b'8#%\x8a\xc0\x00\x00\xe0\x94,\x89\xf5\xfd\xca=\x15T\t\xb68\xb9\x8at.U\xebFR\xb7\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4,\x96HI\xb1\xf6\x9c\xc7\u03a4D%8\xed\x87\xfd\xf1l\xfc\x8f\x89lk\x93[\x8b\xbd@\x00\x00\u0794,\x9f\xa7,\x95\xf3}\b\xe9\xa3`\t\u7930\u007f)\xba\xd4\x1a\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4,\xafk\xf4\xec}Z\x19\xc5\xe0\x89z^\xeb\x01\x1d\xce\xceB\x10\x89\a\x93H5\xa01\x16\x00\x00\u07d4,\xb4\xc3\xc1k\xb1\xc5^|kz\x19\xb1'\xa1\xac\x93\x90\xcc\t\x89\xb8'\x94\xa9$O\f\x80\x00\xe0\x94,\xb5IZPS6\xc2FT\x10\xd1\xca\xe0\x95\xb8\xe1\xba\\\u074a\x04<3\xc1\x93ud\x80\x00\x00\u07d4,\xb6\x15\a:@\xdc\u06d9\xfa\xa8HW.\x98{;\x05n\xfb\x89+X\xad\u06c9\xa2X\x00\x00\u07d4,\xbam]\r\xc2\x04\xea\x8a%\xad\xa2\xe2oVu\xbd_/\u0709H#\xef}\u06da\xf3\x80\x00\u07d4,\xbb\fs\u07d1\xb9\x17@\xb6i;wJ}\x05\x17~\x8eX\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4,\xcbfIM\n\xf6\x89\xab\xf9H=6]x$D\xe7\u07ad\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\xcc\x1f\x1c\xb5\xf4\xa8\x00.\x18k \x88]\x9d\xbc\x03\f\b\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u03c0\xe2\x18\x98\x12^\xb4\xe8\a\u0342\xe0\x9b\x9d(Y/n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u0456\x94\u0452j\x0f\xa9\x18\x9e\u07ba\xfcg\x1c\xf1\xb2\u02a5\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\u04d34\xac~\xacyrW\xab\xe3sa\x95\xf5\xb4\xb5\xce\x0f\x89\x05kGx^7&\x00\x00\u07d4,\u05de\xb5 '\xb1,\x18\x82\x8e>\xaa\xb2\x96\x9b\xfc\u0487\xe9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\xd8xfV\x8d\xd8\x1a\xd4}\x9d:\u0404nZePss\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4,\xdb9De\x06\x16\xe4|\xb1\x82\xe0`2/\xa1Hyx\u0389b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4,\xe1\x1a\x92\xfa\xd0$\xff+>\x87\xe3\xb5B\xe6\xc6\r\xcb\u0656\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4-\x03&\xb2?\x04\t\xc0\xc0\xe9#hc\xa13\aZ\x94\xba\x18\x89\vg\x9b\xe7[\xe6\xae\x00\x00\u07d4-\r\xecQ\xa6\xe8s0\xa6\xa8\xfa*\x0fe\u060dJ\xbc\xdfs\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4-#vkok\x05s}\xad\x80\xa4\x19\xc4\x0e\xdaMw\x10>\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4-+\x03#Y\xb3c\x96O\xc1\x1aQ\x82c\xbf\xd0T1\xe8g\x89\b\x1c\x1d\xf7b\x9ep\x00\x00\u07d4-4\x80\xbf\be\aJr\xc7u\x9e\xe5\x13{Mp\xc5\x1c\xe9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-5\xa9\xdfbu\u007f\u007f\xfa\xd1\x04\x9a\xfb\x06\xcaJ\xfcFLQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-@U\x8b\x06\xf9\n9#\x14U\x92\x12;gt\xe4n1\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4-Bi\x12\xd0Y\xfa\xd9t\v.9\n.\xea\xc0To\xf0\x1b\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4-S-\xf4\xc69\x11\xd1\u0391\xf6\xd1\xfc\xbf\xf7\x96\x0fx\xa8\x85\x89Z\x85\x96\x8aXx\u0680\x00\u07d4-S\x91\xe98\xb3HX\u03d6[\x84\x051\xd5\xef\xdaA\v\t\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94-[B\xfcY\xeb\xda\r\xfdf\xae\x91K\u008c\x1b\nn\xf8:\x8a+\u0235\x9f\xdc\xd86c\x80\x00\u07d4-]s5\xac\xb06+G\u07e3\xa8\xa4\xd3\xf5\x94\x95D\u04c0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-a\xbf\xc5hs\x92<+\x00\t]\xc3\xea\xa0\xf5\x90\u062e\x0f\x8a\x04ef\xdf\xf8\xceU`\x00\x00\u07d4-e\x11\xfdz8\x00\xb2hT\xc7\xec9\xc0\u0735\xf4\xc4\xe8\xe8\x89\x15\xad\u077a/\x9ew\x00\x00\u07d4-}\\@\u076f\xc4P\xb0Jt\xa4\u06bc+\xb5\xd6e\x00.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\x89\xa8\x00jO\x13z \xdc+\xecF\xfe.\xb3\x12\xea\x96T\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-\x8cR2\x9f8\u04a2\xfa\x9c\xba\xf5\u0143\xda\xf1I\v\xb1\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-\x8e\x06\x18\x92\xa5\xdc\xce!\x96j\xe1\xbb\a\x88\xfd>\x8b\xa0Y\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4-\x8e[\xb8\xd3R\x16\x95\xc7~|\x83N\x02\x91\xbf\xac\xeet\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4-\x90\xb4\x15\xa3\x8e.\x19\xcd\xd0/\U000ed069z\xf7\xcb\xf6r\x89\x05\xf3\xc7\xf6A1\xe4\x00\x00\u07d4-\x9b\xado\x1e\xe0*p\xf1\xf1=\xef\\\u0332z\x9a'@1\x89a\t=|,m8\x00\x00\u07d4-\x9c_\xec\u04b4O\xbbj\x1e\xc72\xea\x05\x9fO\x1f\x9d+\\\x896\xca2f\x1d\x1a\xa7\x00\x00\xe0\x94-\xa6\x17iP\t\xccW\xd2j\u0510\xb3*]\xfb\xeb\x93N^\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4-\xa7k|9\xb4 \u323a,\x10 \xb0\x85k\x02pd\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\u01ddn\u007fU\xbc\xe2\xe2\xd0\xc0*\xd0|\uca3bR\x93T\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94-\xca\x0eD\x9a\xb6F\xdb\xdf\u04d3\xa9fb\x96\v\u02b5\xae\x1e\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4-\xd3%\xfd\xff\xb9{\x19\x99R\x84\xaf\xa5\xab\xdbWJ\x1d\xf1j\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4-\xd5x\xf7@}\xfb\xd5H\xd0^\x95\xcc\u00dcHT)bj\x89\u3bb5sr@\xa0\x00\x00\u07d4-\xd8\xee\xef\x87\x19J\xbc,\xe7X]\xa1\xe3[|\xeax\f\xb7\x8965\xc6 G9\u0640\x00\u07d4-\xdf@\x90Wi\xbc\xc4&\xcb,)8\xff\xe0w\xe1\u8758\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4-\xe0\x96D\x00\u0082\xbd\u05ca\x91\x9ck\xf7|k_yay\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\xe3\x1a\xfd\x18\x9a\x13\xa7o\xf6\xfes\xea\xd9\xf7K\xb5\u0126)\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4-\xec\x982\x9d\x1f\x96\u00e5\x9c\xaay\x81uTR\xd4\xdaI\u0549\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\ue422\x8f\x19-gj\x87s#+V\xf1\x8f#\x9e/\xad\x8a\x03\xef\xa7\xe7G\xb6\u046d\x00\x00\xe0\x94.\b\x80\xa3E\x96#\a \xf0Z\xc8\xf0e\xaf\x86\x81\u0736\u008a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4.\fW\xb4qP\xf9Z\xa6\xa7\xe1j\xb9\xb1\xcb\xf5C(\x97\x9a\x89\x05k\xc7^-c\x10\x00\x00\u07d4.\x10\x91\v\xa6\xe0\xbc\x17\xe0UUf\x14\u02c7\t\x0fM~[\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94.$\xb5\x97\x87;\xb1A\xbd\xb27\xea\x8aZ\xb7Gy\x9a\xf0-\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.(\x10\xde\xe4J\xe4\xdf\xf3\xd8cB\xab\x12fW\xd6S\xc36\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.,\xbdz\xd8%G\xb4\xf5\xff\x8b:\xb5o\x94*dE\xa3\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.-~\xa6k\x9fG\xd8\xccR\xc0\x1cR\xb6\u147c}G\x86\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4.C\x93H\u07caBw\xb2*v\x84W\xd1\x15\x8e\x97\xc4\t\x04\x89*\x1e\x9f\xf2o\xbfA\x00\x00\xe0\x94.F\xfc\xeej;\xb1E\xb5\x94\xa2C\xa3\x91?\xce]\xado\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794.G\xf2\x87\xf4\x98#7\x13\x85\r1&\x82<\xc6}\xce\xe2U\x88\u029d\x9e\xa5X\xb4\x00\x00\u07d4.N\u1b99j\xa0\xa1\xd9$(\xd0fR\xa6\xbe\xa6\xd2\xd1]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.R\x91+\xc1\x0e\xa3\x9dT\xe2\x93\xf7\xae\u05b9\x9a\x0fLs\xbe\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4.a\x9fW\xab\xc1\u91ea\x93j\xe3\xa2&Ib\xe7\xeb-\x9a\x89(\xfb\x9b\x8a\x8aSP\x00\x00\u07d4.d\xa8\xd7\x11\x11\xa2/L]\xe1\xe09\xb36\xf6\x8d9\x8a|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.i3T=O,\xc0\vSP\xbd\x80h\xba\x92C\u05be\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94.~\x05\xe2\x9e\u0767\xe4\xae%\xc5\x175C\xef\xd7\x1fm=\x80\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4.\u007fFU \xec5\xcc#\u058eue\x1b\xb6h\x95D\xa1\x96\x898\xec[r\x1a\x1a&\x80\x00\u07d4.\x8e\xb3\nqn_\xe1\\t#>\x03\x9b\xfb\x11\x06\xe8\x1d\x12\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94.\x98$\xb5\xc12\x11\x1b\xca$\xdd\xfb\xa7\xe5u\xa5\xcdr\x96\xc1\x8a\x03\xa4\x84Qnm\u007f\xfe\x00\x00\u07d4.\xa5\xfe\xe6?3z7nK\x91\x8e\xa8!H\xf9MH\xa6&\x89e\x0f\x8e\r\u0493\xc5\x00\x00\u07d4.\xafN*F\xb7\x89\xcc\u0088\xc8\xd1\xd9)N?\xb0\x858\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.\xaf\xf9\xf8\xf8\x110d\u04d5z\xc6\xd6\xe1\x1e\xeeB\xc8\x19]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4.\xba\fn\xe5\xa1\x14\\\x1cW9\x84\x96:`]\x88\nz \x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4.\xc9X\"\xeb\x88{\xc1\x13\xb4q*M\xfd\u007f\x13\xb0\x97\xb5\xe7\x8965\u026d\xc5\u07a0\x00\x00\u07d4.\xcaj<]\x9fD\x9d\tV\xbdC\xfa{M{\xe8CYX\x89lk\xdaip\x9c\xc2\x00\x00\xe0\x94.\xca\xc5\x04\xb23\x86n\xb5\xa4\xa9\x9e{\u0490\x13Y\xe4;=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.\xeb\xf5\x942\xb5(\x92\xf98\v\xd1@\xaa\x99\xdc\xf8\xad\f\x0f\x89\b=lz\xabc`\x00\x00\u07d4.\xee\xd5\x04q\xa1\xa2\xbfS\xee0\xb1#.n\x9d\x80\xef\x86m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4.\xefk\x14\x17\u05f1\x0e\xcf\xc1\x9b\x12:\x8a\x89\xe7>RlX\x89 \x86\xac5\x10R`\x00\x00\u07d4.\xf8i\xf05\vW\xd54x\xd7\x01\xe3\xfe\xe5)\xbc\x91\x1cu\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4.\xf9\xe4eqj\xca\u03f8\xc8%/\xa8\xe7\xbcyi\xeb\xf6\u4255\x9e\xb1\xc0\xe4\xae \x00\x00\xe0\x94.\xfcLd}\xacj\xca\xc3Uw\xad\"\x17X\xfe\xf6ao\xaa\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4/\x13eu&\xb1w\xca\xd5G\u00d0\x8c\x84\x0e\xffd{E\u0649?v\x84\x9c\xf1\xee,\x80\x00\u07d4/\x18}ZpMZ3\x8c[(v\xa0\x90\xdc\xe9d(N)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94/%#\u0303O\x00\x86\x05$\x02bb\x96gQ\x86\xa8\u508a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4/(*\xbb\xb6\u0523\xc3\xcd;\\\xa8\x12\xf7d>\x800_\x06\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4/+\xba\x1b\x17\x96\x82\x1avo\xced\xb8O(\xech\xf1Z\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4/1]\x90\x16\xe8\xee_Sf\x81 /\x90\x84\xb02TMM\x898<\xd1+\x9e\x86<\x00\x00\u07d4/M\xa7SC\x0f\xc0\x9es\xac\xbc\xcd\xcd\xe9\xdad\u007f+]7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/P\x80\xb8?~-\xc0\xa1\xdd\x11\xb0\x92\xad\x04+\xffx\x8fL\x89\xb4\xf8\xfby#\x1d+\x80\x00\u07d4/a\uf941\x9dp_+\x1eN\xe7T\xae\xb8\xa8\x19Pju\x89O%\x91\xf8\x96\xa6P\x00\x00\xe0\x94/f\xbf\xbf\"b\xef\u030d+\xd0DO\u0170ib\x98\xff\x1e\x8a\x02\x1a\xd95\xf7\x9fv\xd0\x00\x00\u07d4/m\xce\x130\u015e\xf9!`!TW-MK\xac\xbd\x04\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4/}2\x90\x85\x1b\xe5\u01b4\xb4?}Et2\x9fa\xa7\x92\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4/\x858\x17\xaf\u04f8\xf3\xb8n\x9f`\xeew\xb5\xd9ws\xc0\xe3\x89N\xae\xeaD\xe3h\xb9\x00\x00\u07d4/\xa4\x91\xfbY \xa6WN\xbd(\x9f9\xc1\xb2C\r-\x9aj\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xb5f\xc9K\xbb\xa4\xe3\xcbg\xcd\xda}_\xadq1S\x91\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xbbPJ]\xc5'\xd3\xe3\xeb\x00\x85\xe2\xfc<}\xd58\xcbz\x89C\u00b1\x8a\xec<\n\x80\x00\u07d4/\xbc\x85y\x8aX5\x98\xb5\"\x16mn\x9d\xda\x12\x1db}\xbc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/\xbc\xef3\x84\xd4 \xe4\xbfa\xa0f\x99\x90\xbcpT\U00065bc9lk\x93[\x8b\xbd@\x00\x00\xe0\x94/\xc8.\xf0v\x93#A&Oaz\f\x80\xddW\x1ej\xe99\x8a\x01\x84$\xf5\xf0\xb1\xb4\xe0\x00\x00\u07d4/\u075by\u07cd\xf50\xadc\xc2\x0eb\xafC\x1a\xe9\x92\x16\xb8\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4/\xe0\x02?W\"e\x0f:\x8a\xc0\x10\t\x12^t\xe3\xf8.\x9b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4/\xe0\xccBKS\xa3\x1f\t\x16\xbe\b\xec\x81\xc5\v\xf8\xea\xb0\xc1\x89 \x86\xac5\x10R`\x00\x00\u07d4/\xe1:\x8d\a\x85\u0787X\xa5\xe4\x18v\xc3n\x91l\xf7Pt\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4/\xea\x1b/\x83O\x02\xfcT3?\x8a\x80\x9f\x048\xe5\x87\n\xa9\x89\x01\x18T\xd0\xf9\xce\xe4\x00\x00\u07d4/\xee6\xa4\x9e\xe5\x0e\xcfqo\x10G\x91VFw\x9f\x8b\xa0?\x899B\"\xc4\u0686\xd7\x00\x00\u07d4/\xef\x81G\x8aK.\x80\x98\xdb_\xf3\x87\xba!S\xf4\xe2+y\x896'\xe8\xf7\x127<\x00\x00\u07d4/\xf1`\xc4Or\xa2\x99\xb5\xec-q\xe2\x8c\xe5Dm/\u02ef\x89\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4/\xf1\xcaU\xfd\x9c\xec\x1b\x1f\xe9\U00029af7LQ<\x1e*\xaa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94/\xf5\u02b1,\r\x95\u007f\xd33\xf3\x82\xee\xb7Q\a\xa6L\xb8\xe8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94/\xf80\xcfU\xfb\x00\u0560\xe05\x14\xfe\xcdD1K\xd6\xd9\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4/\xfe\x93\xec\x1aV6\xe9\xee4\xafp\xdf\xf5&\x82\xe6\xffpy\x89lk\x93[\x8b\xbd@\x00\x00\u07d40\x03y\x88p&q\xac\xbe\x89,\x03\xfeW\x88\xaa\x98\xaf(z\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d40$\x8dX\xe4\x14\xb2\x0f\xed:lH+Y\xd9\xd8\xf5\xa4\xb7\xe2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4019\xbcYd\x03\xd5\u04d3\x1fwLf\u013aFtT\u06c9\\%\xe1J\xea(?\x00\x00\u079408\x00\x87xie\x14\x9e\x81B;\x15\xe3\x13\xba2\xc5\u01c3\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d40:0\xacB\x86\xae\x17\xcfH=\xad{\x87\fk\xd6M{J\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40?\xba\xeb\xbeF\xb3[n[t\x94j_\x99\xbc\x15\x85\xca\xe7\x89/\x9a\xc0i_[\xba\x00\x00\u07d40ADZ3\xba\x15\x87A\x16\r\x9c4N\xb8\x8e\\0o\x94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d40H\x01d\xbc\xd8It\xeb\xc0\xd9\f\x9b\x9a\xfa\xb6&\xcd\x1cs\x89+^:\xf1k\x18\x80\x00\x00\u07d40N\u019atTW!\xd71j\xefM\u03f4\x1a\u015e\xe2\xf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x940Q\x182\x91\x8d\x804\xa7\xbe\xe7.\xf2\xbf\xeeD\x0e\u02fc\xf6\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d40Q?\u029f6\xfdx\x8c\xfe\xa7\xa3@\xe8m\xf9\x82\x94\xa2D\x89\x18;_\x03\xb1G\x9c\x00\x00\u07d40U\xef\xd2`)\xe0\xd1\x1b\x93\r\xf4\xf5;\x16,\x8c?\xd2\u0389\x1b\x1a\b\x927\a=\x00\x00\u07d40]&\xc1\v\xdc\x10?k\x9c!'.\xb7\xcb-\x91\b\xc4~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40_x\xd6\x18\xb9\x90\xb4)[\xac\x8a-\xfa&(\x84\xf8\x04\xea\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x940d\x89\x9a\x96\x1a>\x1d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d40\x98\xb6]\xb9>\xca\xca\xf75\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d40\uc4d2$J!\b\u0247\xbc\\\xdd\xe0\ud7c3z\x81{\x89T\x99%\xf6\xc9\xc5%\x00\x00\xe0\x940\xed\x11\xb7{\xc1~^f\x94\u023c[nG\x98\xf6\x8d\x9c\xa7\x8a\x1eo\xb3B\x1f\xe0)\x9e\x00\x00\u07d40\xf7\xd0%\xd1o{\xee\x10U\x80Ho\x9fV\x1c{\xae?\xef\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x940\xfb\xe5\x88_\x9f\xcc\xe9\xea^\u06c2\xedJ\x11\x96\xdd%\x9a\xed\x8a\x01\x19\xe4\u007f!8\x1f@\x00\x00\u07d41\x04}p?c\xb94$\xfb\xbdn/\x1f\x9et\xde\x13\xe7\t\x89\x9a\x81f\xf7\u6ca7\x80\x00\u07d411?\xfdc[\xf2\xf32HA\xa8\x8c\a\xed\x14aD\xce\xeb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d41Y\xe9\fH\xa9\x15\x90J\xdf\u24b2/\xa5\xfd^ryk\x896\xaf\xe9\x8f&\x06\x10\x00\x00\u07d41]\xb7C\x9f\xa1\u0574#\xaf\xa7\xddq\x98\xc1\xcft\xc9\x18\xbc\x89 \x86\xac5\x10R`\x00\x00\u07d41^\xf2\xdab\x0f\xd30\xd1.\xe5]\xe5\xf3)\xa6\x96\xe0\xa9h\x89\b!\xab\rD\x14\x98\x00\x00\u07d41n\x92\xa9\x1b\xbd\xa6\x8b\x9e/\x98\xb3\xc0H\x93N<\xc0\xb4\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d41n\xb4\xe4}\xf7\x1bB\xe1mo\xe4h%\xb72{\xaf1$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41q\x87~\x9d\x82\f\xc6\x18\xfc\t\x19\xb2\x9e\xfd3?\xdaI4\x8965\u026d\xc5\u07a0\x00\x00\u07d41|\xf4\xa2<\xb1\x91\xcd\xc5c\x12\u009d\x15\xe2\x10\xb3\xb9\xb7\x84\x89\a\xcef\xc5\x0e(@\x00\x00\u07d41\x8b.\xa5\xf0\xaa\xa8y\xc4\xd5\xe5H\xac\x9d\x92\xa0\xc6t\x87\xb7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d41\x8cv\xec\xfd\x8a\xf6\x8dpUSR\xe1\xf6\x01\xe3Y\x88\x04-\x89\x1b1\x19.h\xc7\xf0\x00\x00\u07d41\x8f\x1f\x8b\xd2 \xb0U\x8b\x95\xfb3\x10\x0f\xfd\xbbd\r|\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41\xaa;\x1e\xbe\x8cM\xbc\xb6\xa7\b\xb1\xd7H1\xe6\x0eIv`\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d41\xab\b\x89f\xec\xc7\"\x92X\xf6\t\x8f\xceh\xcf9\xb3\x84\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x941\xadM\x99F\xef\t\xd8\xe9\x88\xd9F\xb1\"\u007f\x91A\x90\x176\x8a\x04\xd8S\xc8\xf8\x90\x89\x80\x00\x00\xe0\x941\xb4;\x01]\x00\x81d~h\x00\x00\u07d424\x86\xcad\xb3uGO\xb2\xb7Y\xa9\xe7\xa15\x85\x9b\xd9\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d427I\xa3\xb9q\x95\x9eF\u0234\x82-\xca\xfa\xf7\xaa\xf9\xbdn\x89\x01\x16q\xa5\xb2Ep\x00\x00\u07d42:\xadA\xdfKo\xc8\xfe\u038c\x93\x95\x8a\xa9\x01\xfah\bC\x894\x95tD\xb8@\xe8\x00\x00\xe0\x942;<\xfe>\xe6+\xbd\xe2\xa2a\xe5<\xb3\xec\xc0X\x10\xf2\u018a\x02\ub3b1\xa1r\u0738\x00\x00\u07d42?\xca^\xd7\u007fi\x9f\x9d\x990\xf5\xce\xef\xf8\xe5oY\xf0<\x89Hz\x9a0E9D\x00\x00\u07d42H\\\x81\x87(\xc1\x97\xfe\xa4\x87\xfb\xb6\xe8)\x15\x9e\xba\x83p\x899!\xb4\x13\xbcN\xc0\x80\x00\xe0\x942P\xe3\xe8X\xc2j\xde\u032d\xf3jVc\xc2*\xa8LAp\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x942Y\xbd/\xdd\xfb\xbco\xba\u04f6\xe8t\xf0\xbb\xc0,\xda\x18\xb5\x8a\x02\x84`VI[\r\x18\x80\x00\u07d42uIo\xd4\u07491\xfdi\xfb\n\v\x04\xc4\xd1\xff\x87\x9e\xf5\x89\x18-~L\xfd\xa08\x00\x00\u07d42{\xb4\x9euOo\xb4\xf73\xc6\xe0o9\x89\xb4\xf6]K\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d42\x82y\x1do\xd7\x13\xf1\xe9OK\xfdV^\xaax\xb3\xa0Y\x9d\x89Hz\x9a0E9D\x00\x00\u07d42\x83\xeb\u007f\x917\xdd9\xbe\xd5_\xfek\x8d\xc8E\xf3\xe1\xa0y\x89\x03\x97\n\xe9!Ux\x00\x00\u07d42\x86\t\x97\xd70\xb2\xd8;s$\x1a%\xd3f}Q\xc9\b\xef\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x942\x86\u047cez1,\x88G\xd9<\xb3\xcbyP\xf2\xb0\xc6\xe3\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x942\xa2\r\x02\x8e,b\x18\xb9\xd9[D\\w\x15$cj\"\xef\x8a\x02\x02\xfe\xfb\xf2\xd7\xc2\xf0\x00\x00\u07d42\xa7\x06\x91%\\\x9f\xc9y\x1aOu\u0238\x1f8\x8e\n%\x03\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d42\xb7\xfe\xeb\xc5\u015b\xf6^\x86\x1cL\v\xe4*v\x11\xa5T\x1a\x89w\u9aa8R\\\x10\x00\x00\xe0\x942\xba\x9a}\x04#\xe0:R_\xe2\xeb\xebf\x1d \x85w\x8b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d42\xbb.\x96\x93\xe4\xe0\x854M/\r\xbdF\xa2\x83\u3807\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x942\xc2\xfd\u2daa\xbb\x80\u5ba2\xb9I\xa2\x17\xf3\xcb\t\"\x83\x8a\x010a`\xaf\xdf 7\x80\x00\u07d42\xd9P\xd5\xe9>\xa1\u0574\x8d\xb4qO\x86{\x03 \xb3\x1c\x0f\x897\b\xba\xed=h\x90\x00\x00\u07d42\u06f6qlT\xe81e\x82\x9aJ\xbb6uxI\xb6\xe4}\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xebd\xbe\x1b]\xed\xe4\b\u01bd\xef\xben@\\\x16\xb7\xed\x02\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d42\xef\\\xdcg\x1d\xf5V*\x90\x1a\xee]\xb7\x16\xb9\xbev\xdc\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d42\xf2\x9e\x87'\xa7LkC\x01\xe3\xff\xff\x06\x87\xc1\xb8p\xda\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xfa\x0e\x86\xcd\b}\u058di1\x90\xf3-\x931\t\t\xedS\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d42\xfb\xee\xd6\xf6&\xfc\xdf\xd5\x1a\xca\xfbs\v\x9e\xef\xf6\x12\xf5d\x89lk\x93[\x8b\xbd@\x00\x00\u07943\x00\xfb\x14\x9a\xde\xd6[\u02e6\xc0N\x9c\u05b7\xa0;\x89;\xb1\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x943\x01\xd9\xca/;\xfe\x02by\xcdh\x19\xf7\x9a)=\x98\x15n\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x943\b\xb04f\xc2z\x17\xdf\xe1\xaa\xfc\xeb\x81\xe1m)4Vo\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07943\x1a\x1c&\xcci\x94\xcd\xd3\xc1K\xec\xe2v\xff\xffK\x9d\xf7|\x88\xfaz\xed\xdfO\x06\x80\x00\xe0\x943&\xb8\x8d\xe8\x06\x18DT\xc4\v'\xf3\t\xd9\xddm\u03f9x\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x943)\xeb;\xafCE\xd6\x00\xce\xd4\x0en\x99ueo\x117B\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d432\r\xd9\x0f+\xaa\x11\r\xd34\x87*\x99\x8f\x14\x84&E<\x8965f3\xeb\xd8\xea\x00\x00\u07d436\xc3\xefn\x8bP\xee\x90\xe07\xb1d\xb7\xa8\xea_\xaa\xc6]\x89\x0e\u0223\xa7\x1c\"T\x00\x00\xe0\x9438\fo\xffZ\xcd&Q0\x96)\u06daq\xbf? \u017a\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d43:\xd1Yd\x01\xe0Z\xea-6\xcaG1\x8e\xf4\xcd,\xb3\u07c9\x9d\xc0\\\xce(\u00b8\x00\x00\u07d43C@\xeeK\x9c\u0701\xf8P\xa7Q\x16\xd5\x0e\u9d98%\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d43H\x1e\x85n\xbe\u050e\xa7\b\xa2t&\xef(\xe8g\xf5|\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943V[\xa9\xda,\x03\xe7x\xce\x12)O\b\x1d\xfe\x81\x06M$\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07943X\x1c\xee#0\x88\xc0\x86\r\x94N\f\xf1\u03ab\xb8&\x1c.\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d43XX\xf7I\xf1i\u02bc\xfeR\xb7\x96\xe3\xc1\x1e\xc4~\xa3\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943^\"\x02[zw\u00e0t\u01cb\x8e=\xfe\a\x13A\x94n\x8a\x02'\xcas\n\xb3\xf6\xac\x00\x00\u07d43b\x9b\xd5/\x0e\x10{\xc0q\x17ld\xdf\x10\x8fdw}I\x89\x01\xcf\xddth!n\x80\x00\u07d43{;\u07c6\xd7\x13\xdb\xd0{]\xbf\xcc\x02+z{\x19F\xae\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d43|\xfe\x11W\xa5\u0191 \x10\xddV\x153y\x17i\u00b6\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xb36\xf5\xba^\xdb{\x1c\xcc~\xb1\xa0\u0644\xc1#\x1d\x0e\u0709lk\x93[\x8b\xbd@\x00\x00\u07d43\xc4\a\x13;\x84\xb3\xcaL=\xed\x1fFX\x90\f8\x10\x16$\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\xe0\x943\xd1r\xab\a\\Q\xdb\x1c\xd4\n\x8c\xa8\xdb\xff\r\x93\xb8C\xbb\x8a\x016x\x05\x10\xd1-\xe3\x80\x00\u07d43\xe9\xb7\x18#\x95.\x1ff\x95\x8c'\x8f\u008b\x11\x96\xa6\u0164\x89\x05k\xc7^-c\x10\x00\x00\u07d43\xeakxU\xe0[\a\xab\x80\u06b1\xe1M\xe9\xb6I\xe9\x9bl\x89\x1c\xd6\xfb\xadW\xdb\xd0\x00\x00\u07d43\xf1R#1\rD\u078bf6h_:L=\x9cVU\xa5\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d43\xf4\xa6G\x1e\xb1\xbc\xa6\xa9\xf8[;Hr\xe1\aU\xc8+\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d43\xfbWzM!O\xe0\x10\xd3,\xca|>\xed\xa6?\x87\xce\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xfdq\x8f\v\x91\xb5\xce\u020a]\xc1^\xec\xf0\xec\xef\xa4\xef=\x89\x17r$\xaa\x84Lr\x00\x00\u07d44\x14\x80\u030c\xb4v\xf8\xd0\x1f\xf3\b\x12\xe7\xc7\x0e\x05\xaf\xaf]\x89lk\x93[\x8b\xbd@\x00\x00\u07d44'-^ut1]\xca\u9afd1{\xac\x90(\x9dGe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x9440\xa1c\x81\xf8i\xf6\xeaT#\x91XU\xe8\x00\x885%\xa9\x8a\x03\xca\\f\u067cD0\x00\x00\u07d441\x86%\x81\x8e\xc1?\x11\x83Z\xe9sS\xce7}oY\n\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d449<]\x91\xb9\xdeYr\x03\xe7[\xacC\t\xb5\xfa=(\u00c9\n\x84Jt$\xd9\xc8\x00\x00\u07d449\x99\x8b$|\xb4\xbf\x8b\xc8\nm+5'\xf1\xdf\xe9\xa6\u0489\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d44C}\x14ed\v\x13l\xb5\x84\x1c?\x93O\x9b\xa0\xb7\t}\x89\t`\xdbwh\x1e\x94\x00\x00\u07d44J\x8d\xb0\x86\xfa\xedN\xfc7\x13\x1b:\"\xb0x-\xadp\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x944fM\"\x0f\xa7\xf3yX\x02J32\u0584\xbc\xc6\xd4\u023d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44f\xf6~9cl\x01\xf4;:!\xa0\xe8R\x93%\xc0\x86$\x89-\xb1\x16vP\xac\xd8\x00\x00\u07d44\x856\x1e\xe6\xbf\x06\xefe\b\xcc\xd2=\x94d\x1f\x81M>/\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x85\xf6!%d3\xb9\x8aB\x00\xda\xd8W\xef\xe5Y7\uc609lk\x93[\x8b\xbd@\x00\x00\u07d44\x95\x8aF\xd3\x0e0\xb2s\xec\xc6\xe5\xd3X\xa2\x12\xe50~\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x97\xddf\xfd\x11\x80q\xa7\x8c,\xb3n@\xb6e\x1c\xc8%\x98\x89\x05\xf1\x01kPv\xd0\x00\x00\xe0\x944\x9a\x81k\x17\xab='\xbb\xc0\xae\x00Q\xf6\xa0p\xbe\x1f\xf2\x9d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44\x9d,\x91\x8f\u041e(\a1\x8ef\xceC)\t\x17k\xd5\v\x89<\xb7\x1fQ\xfcU\x80\x00\x00\u07d44\xa0C\x1f\xff^\xad\x92\u007f\xb6`\f\x1e\xa8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d44\xff&\xeb`\xa8\u0469ZH\x9f\xae\x13n\xe9\x1dNX\bL\x89 \x86\xac5\x10R`\x00\x00\u07d44\xffX)R\xff$E\x8f{\x13\xd5\x1f\vO\x98p\"\xc1\xfe\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d45\x10k\xa9N\x85c\u0533\xcb<\\i,\x10\xe6\x04\xb7\xce\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x945\x14_b\x03\x97\u019c\xb8\xe0\tb\x96\x1f\x0fH\x86d9\x89\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d45\x14t0\xc3\x10e\x00\u77e2\xf5\x02F.\x94p<#\xb1\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x945\x17\x87\x845\x05\xf8\xe4\xef\xf4ef\xcc\u695fM\x1c_\xe7\x8a\x01\xf5q\x89\x87fKH\x00\x00\xe0\x945\x1f\x16\xe5\xe0sZ\xf5gQ\xb0\xe2%\xb2B\x11q9@\x90\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\xe0\x945$\xa0\x00#N\xba\xaf\a\x89\xa14\xa2\xa4\x178<\xe5(*\x8a\x011yU\x94}\x8e,\x00\x00\u07d45&\xee\xce\x1ak\xdc>\xe7\xb4\x00\xfe\x93[HF?1\xbe\u05c9\x04w\x87\x9bm\x140\x00\x00\u07d45*x_J\x92\x162PL\xe5\xd0\x15\xf8\xd7FO\xa3\xdb\x14\xe7r\x92\x13\u03aa7\x8c\t^\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d45\xaf\x04\n\f\xc23zv\xaf(\x81T\xc7V\x1e\x1a#3I\x8965\u026d\xc5\u07a0\x00\x00\u07d45\xb0>\xa4$W6\xf5{\x85\xd2\xebyb\x8f\x03m\xdc\xd7\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xbd$he\xfa\xb4\x90\xac\bz\xc1\xf1\xd4\xf2\xc1\r\f\xda\x03\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x945\xbff\x88R/5Fz\u007fu0#\x14\xc0+\xa1v\x80\x0e\x8a\x03\xafA\x82\x02\xd9T\xe0\x00\x00\u07d45\u022d\xc1\x11%C+;w\xac\xd6F%\xfeX\xeb\xee\x9df\x89lk\x93[\x8b\xbd@\x00\x00\u07d45\u0497\x0fI\xdc\xc8\x1e\xa9\xeep~\x9c\x8a\n\xb2\xa8\xbbtc\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d45\xe0\x96\x12\r\xea\xa5\xc1\xec\xb1d^,\u02cbN\xdb\xd9)\x9a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d45\xea!c\xa3\x8c\u07da\x12?\x82\xa5\xec\x00%\x8d\xae\v\xc7g\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xf1\xda\x12{\x837o\x1b\x88\xc8*3Y\xf6z^g\xddP\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d45\xf2\x94\x9c\xf7\x8b\xc2\x19\xbbO\x01\x90|\xf3\xb4\xb3\u04c6T\x82\x89\x0f\xb5\xc8l\x92\xe44\x00\x00\u07d45\xf5\x86\x01I\xe4\xbb\xc0K\x8a\u0172r\xbeU\xad\x1a\xcaX\xe0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x02E\x8d\xa8omj\x9d\x9e\xb0=\xaf\x97\xfeV\x19\xd4B\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x057-\x93\xa9\x01\t\x88\x01\x8f\x9f1]\x03.\u0448\x0f\xa1\x89\x1b\x1b\xcfQ\x89j}\x00\x00\u07d46\x16\xd4H\x98_]2\xae\xfa\x8b\x93\xa9\x93\xe0\x94\xbd\x85I\x86\x89\v\"\u007fc\xbe\x81<\x00\x00\u07d46\x16\xfbF\xc8\x15x\xc9\xc8\xebM;\xf8\x80E\x1a\x887\x9d}\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x1cu\x93\x16\x96\xbc=B}\x93\xe7lw\xfd\x13\xb2A\xf6\xf4\x89\x1d\xc5\xd8\xfc&m\xd6\x00\x00\u07d46\x1d\x9e\xd8\v[\xd2|\xf9\xf1\"o&u2X\xee_\x9b?\x89\xbfi\x14\xba}r\xc2\x00\x00\u07d46\x1f;\xa9\xed\x95kw\x0f%}6r\xfe\x1f\xf9\xf7\xb0$\f\x89 \x86\xac5\x10R`\x00\x00\u07d46\"|\u07e0\xfd;\x9d~jtF\x85\xf5\xbe\x9a\xa3f\xa7\xf0\x89\n\xc2s\x0e\xe9\xc6\xc1\x80\x00\u07d46/\xbc\xb1\x06b7\n\x06\x8f\xc2e&\x02\xa2Wy7\xcc\xe6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d460\xc5\xe5e\u03aa\x8a\x0f\x0f\xfe2\x87^\xae*l\xe6<\x19\x89\t7r+7t\xd0\x00\x00\u07d463\x9f\x84\xa5\u00b4L\xe5=\xfd\xb6\xd4\xf9}\xf7\x82\x12\xa7\u07c9\x11o\x18\xb8\x17\x15\xa0\x00\x00\u07d464:\xec\xa0{n\u054a\x0eb\xfaN\xcbI\x8a\x12O\xc9q\x89\x10CV\x1a\x88)0\x00\x00\u07d46au@4\x81\xe0\xab\x15\xbbQF\x15\u02f9\x89\xeb\u018f\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d46ro;\x88Z$\xf9)\x96\u0681b^\u022d\x16\xd8\xcb\xe6\x89S\xafu\u0441HW\x80\x00\xe0\x946s\x95C\x99\xf6\u07feg\x18\x18%\x9b\xb2x\xe2\xe9.\xe3\x15\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d46u\x8e\x04\x9c\u064b\u03a1\"w\xa6v\xf9)sb\x89\x00#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d46\u007fY\u0302yS)8NA\xe1(1\x15\xe7\x91\xf2j\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x81\x0f\xf9\xd2\x13\xa2q\xed\xa2\xb8\xaay\x8b\xe6T\xfaK\xbe\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x8cT\x14\xb5k\x84U\x17\x1f\xbf\ab \xc1\u02e4\xb5\xca1\x89\x1e>\xf9\x11\xe8=r\x00\x00\xe0\x946\x90$k\xa3\xc8\x06y\xe2.\xacD\x12\xa1\xae\xfc\xe6\xd7\u0342\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\x92\x8bU\xbc\x86\x15\t\xd5\x1c\x8c\xf1\xd5F\xbf\xecn>\x90\xaf\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d46\x98\"\xf5W\x8b@\xdd\x1fDqpk\"\u0357\x13R\xdak\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d46\x9e\xf7a\x19_:7>$\xec\xe6\xcd\"R\x0f\xe0\xb9\xe8n\x89\x1c\xff\xaf\xc9M\xb2\b\x80\x00\u07d46\xa0\x8f\xd6\xfd\x1a\xc1|\xe1^\xd5~\xef\xb1*+\u2048\xbf\x89Hz\x9a0E9D\x00\x00\u07d46\xa0\xe6\x1e\x1b\xe4\u007f\xa8~0\xd3(\x88\xee\x030\x90\x1c\xa9\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x946\xb2\xc8^:\xee\xeb\xb7\rc\u0124s\f\xe2\xe8\xe8\x8a6$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x946\xbfC\xff5\u07d0\x90\x88$3l\x9b1\xce3\x06~/P\x8aIr\x15\x10\xc1\xc1\xe9H\x00\x00\u07d46\xbf\xe1\xfa;{p\xc1r\xeb\x04/h\x19\xa8\x97%\x95A>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x946\xc5\x10\xbf\x8dnV\x9b\xf2\xf3}G&]\xbc\xb5\x02\xff+\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x946\xd8]\xc3h1V\xe6;\xf8\x80\xa9\xfa\xb7x\x8c\xf8\x14:'\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\u07cf\x88<\x12s\xec\x8a\x17\x1fz3\xcf\xd6I\xb1\xfe`u\x89\fRHJ\xc4\x16\x89\x00\x00\xe0\x946\xe1Va\f\xd8\xffd\xe7\x80\u061d\x00T8\\\xa7gU\xaa\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d46\xfe\xc6,,B^!\x9b\x18D\x8a\xd7W\x00\x9d\x8cT\x02o\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d47\x00\xe3\x02t$\xd99\xdb\xde]B\xfbx\xf6\xc4\xdb\xec\x1a\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d47\x02\xe7\x04\xcc!at9\xadN\xa2zW\x14\xf2\xfd\xa1\xe92\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x035\fMo\xe374,\xdd\xc6[\xf1\xe28k\xf3\xf9\xb2\x89m\x81!\xa1\x94\xd1\x10\x00\x00\xe0\x947\b\xe5\x9d\xe6\xb4\x05P\x88x)\x02\xe0W\x9cr\x01\xa8\xbfP\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d47\x126~^U\xa9mZ\x19\x16\x8fn\xb2\xbc~\x99q\xf8i\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x19Zc]\xccb\xf5jq\x80I\xd4~\x8f\x9f\x96\x83(\x91\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d47'4\x1f&\xc1 \x01\xe3x@^\xe3\x8b-\x84d\xecq@\x89lk\x93[\x8b\xbd@\x00\x00\u07d47.E:kb\x9f'g\x8c\u022e\xb5\xe5|\xe8^\xc0\xae\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d474\xcb\x18t\x91\xed\xe7\x13\xae[;-\x12(J\xf4k\x81\x01\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d477!n\xe9\x1f\x17w2\xfbX\xfa@\x97&r\a\xe2\xcfU\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d47M;\xbb\x057Q\xf9\xf6\x8d\xdb\a\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d48r\xf4\x8d\xc5\xe3\xf8\x17\xbck*\xd2\xd00\xfc^\x04q\x19=\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48~\xea\xfdk@\t\u07af\x8b\u0578Zr\x98:\x8d\xcc4\x87\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48\x81\xde\xfa\xe1\xc0{<\xe0Lx\xab\xe2k\f\u070ds\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d48\x83\xbe\xcc\b\xb9\xbeh\xad;\b6\xaa\u00f6 \xdc\x00\x17\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d48\x85\xfe\xe6q\a\xdc:\xa9\x8a\x1d\x99:t\xdf\\\xd7T\xb9\x8dR\x9a\x89a\t=|,m8\x00\x00\u07d48\xe4m\xe4E<8\xe9A\xe7\x93\x0fC0O\x94\xbb{+\xe8\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d48\xe7\u06e8\xfdO\x1f\x85\r\xbc&I\xd8\xe8O\tR\xe3\xeb<\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d48\xe8\xa3\x1a\xf2\xd2e\xe3\x1a\x9f\xff-\x8fF(m\x12E\xa4g\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d48\xeao[Z{\x88AuQ\xb4\x12=\xc1'\xdf\xe94-\xa6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d48\xee\xc6\xe2\x17\xf4\xd4\x1a\xa9 \xe4$\xb9RQ\x97\x04\x1c\xd4\u0189\xf0\r%\xeb\x92.g\x00\x00\xe0\x948\xf3\x87\xe1\xa4\xedJs\x10n\xf2\xb4b\xe4t\xe2\xe3\x14:\u040a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\x11a\xb0\xe4<0 f\u898d,\xe7\xe1\x99\xec\xdb\x1dW\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x949\x15\uad6b.Yw\xd0u\xde\xc4}\x96\xb6\x8bK\\\xf5\x15\x8a\r\a\x01\x81\x85\x12\x0f@\x00\x00\u07d49\x1aw@\\\t\xa7+^\x846#z\xaa\xf9]h\xda\x17\t\x89\x02\xa9&J\xf3\u0479\x00\x00\u07d49\x1f \x17m\x126\rrMQG\n\x90p6uYJM\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d49$3\xd2\u0383\xd3\xfbJv\x02\u0323\xfa\xcaN\xc1@\xa4\xb0\x89\x02\xc3\xc4e\xcaX\xec\x00\x00\xe0\x949?x;\\\u06c6\"\x1b\xf0)O\xb7\x14\x95\x9c{E\x89\x9c\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d49?\xf4%^\\e\x8f.\u007f\x10\xec\xbd)%rg\x1b\xc2\u0489lk\x93[\x8b\xbd@\x00\x00\u07d49A2`\x0fAU\xe0\u007fME\xbc>\xb8\xd9\xfbr\xdc\u05c4\x89\x9fn\x92\xed\xea\a\xd4\x00\x00\u07d49Q\xe4\x8e<\x86\x9ekr\xa1C\xb6\xa4Ph\u0379\xd4f\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x949T\xbd\xfe\v\xf5\x87\u0195\xa3\x05\xd9$L=[\xdd\xda\u027b\x8a\x04\x10'\x83'\xf9\x85`\x80\x00\u07d49]m%U \xa8\xdb)\xab\xc4}\x83\xa5\u06ca\x1a}\xf0\x87\x89\x05k\xc7^-c\x10\x00\x00\u07d49ck%\x81\x1b\x17j\xbf\xcf\xee\xcad\xbc\x87E/\x1f\xdf\xf4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d49i\xb4\xf7\x1b\xb8u\x1e\xdeC\xc0\x166:zaOv\x11\x8e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x949x/\xfe\x06\xacx\x82*<:\x8a\xfe0^P\xa5a\x88\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d49zn\xf8v:\x18\xf0\x0f\xac!~\x05\\\r0\x94\x10\x10\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d49|\u06cc\x80\xc6yP\xb1\x8deB)a\x0e\x93\xbf\xa6\xee\x1a\x89?\x95\xc8\xe0\x82\x15!\x00\x00\u07d49\x82O\x8b\xce\xd1v\xfd>\xa2.\u01a4\x93\xd0\xcc\xc3?\xc1G\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\x93l'\x19E\v\x94 \xcc%\"\u03d1\xdb\x01\xf2'\xc1\xc1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d49\x95\xe0\x96\xb0\x8aZrh\x00\xfc\xd1}\x9cd\xc6N\b\x8d+\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\x9a\xa6\xf5\xd0x\xcb\tp\x88+\u0259 \x06\xf8\xfb\xdf4q\x8965\u026d\xc5\u07a0\x00\x00\u07d49\xaa\x05\xe5m}28T!\u03d36\xe9\r=\x15\xa9\xf8Y\x89\x01h\u048e?\x00(\x00\x00\u07d49\xaa\xf0\x85M\xb6\xeb9\xbc{.C\x84jv\x17\x1c\x04E\u0789dI\xe8NG\xa8\xa8\x00\x00\u07d49\xb1\xc4q\xae\x94\xe1!dE.\x81\x1f\xbb\xe2\xb3\xcdru\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xb2\x992t\x90\xd7/\x9a\x9e\xdf\xf1\x1b\x83\xaf\xd0\xe9\xd3\xc4P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\xba\u018d\x94xY\xf5\x9e\x92&\b\x9c\x96\xd6.\x9f\xbe<\u0789\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x949\xbf\xd9xh\x9b\xec\x04\x8f\xc7v\xaa\x15$\u007f^\x1d|9\xa2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d49\xc7s6|\x88%\xd3YlhoB\xbf\r\x141\x9e?\x84\x89\a?u\u0460\x85\xba\x00\x00\u07d49\u05291@,\fy\xc4W\x18o$\u07c7)\u03d5p1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\xd6\xca\xca\"\xbc\xcdjr\xf8~\xe7\u05b5\x9e\v\xde!\xd7\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d49\xe0\xdbM`V\x8c\x80\v\x8cU\x00\x02l%\x94\xf5v\x89`\x8965\u026d\xc5\u07a0\x00\x00\xe0\x949\xeeO\xe0\x0f\xbc\xeddph\xd4\xf5|\x01\xcb\"\xa8\v\xcc\u044a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\xf1\x983\x1eK!\xc1\xb7`\xa3\x15_J\xb2\xfe\x00\xa7F\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xf4Fc\xd9%a\t\x1b\x82\xa7\r\xcfY=u@\x05\x97:\x89\n\u05cb.\xdc!Y\x80\x00\u07d4:\x03U\x94\xc7GGmB\xd1\xee\x96l6\"L\xdd\"I\x93\x89\x13J\xf7Ei\xf9\xc5\x00\x00\u07d4:\x04W(G\xd3\x1e\x81\xf7v\\\xa5\xbf\xc9\xd5W\x15\x9f6\x83\x89\a6-\r\xab\xea\xfd\x80\x00\xe0\x94:\x06\xe3\xbb\x1e\xdc\xfd\fD\xc3\aM\xe0\xbb`k\x04\x98\x94\xa2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794:\x10\x88\x8b~\x14\x9c\xae',\x010,2}\n\xf0\x1a\v$\x88\xeb\xec!\xee\x1d\xa4\x00\x00\u07d4:1\b\xc1\u6023;3l!\x13\x134@\x9d\x97\xe5\xad\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4:6\x8e\xfeJ\u05c6\xe2c\x95\xec\x9f\u01adi\x8c\xae)\xfe\x01\x89\"E\x89\x96u\xf9\xf4\x00\x00\u07d4:=\xd1\x04\xcd~\xb0O!\x93/\xd43\xeaz\xff\u04d3i\xf5\x89\x13aO#\xe2B&\x00\x00\u07d4:B\x97\xda\xc4.\x1eO\xb8\xcb1\xec\xddC\xaew<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94:\x99`&m\xf6I cS\x8a\x99\xf4\x87\xc9P\xa3\xa5\uc78a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4:\x9b\x11\x10)\xce\x1f \xc9\x10\x9czt\xee\xee\xf3OO.\xb2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4:\x9eTA\xd4K$;\xe5[u\x02z\x1c\ub7ac\xf5\r\xf2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94:\xa0z4\xa1\xaf\u0216}=\x13\x83\xb9kb\u03d6\xd5\xfa\x90\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94:\xa4,!\xb9\xb3\x1c>'\xcc\xd1~\t\x9a\xf6y\xcd\xf5i\a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4:\xa9H\xea\x029wU\xef\xfb/\x9d\xc99-\xf1\x05\x8f~3\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4:\xad\xf9\x8ba\xe5\u0216\xe7\xd1\x00\xa39\x1d2P\"]a\u07c9\f\xafg\x007\x01h\x00\x00\u07d4:\xaeHr\xfd\x90\x93\xcb\xca\xd1@o\x1e\x80x\xba\xb5\x03Y\xe2\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4:\xbb\x8a\xdf\xc6\x04\xf4\x8dY\x84\x81\x1d\u007f\x1dR\xfe\xf6u\x82p\x89\xf2\x97\x19\xb6o\x11\f\x00\x00\u07d4:\xc2\xf0\xff\x16\x12\xe4\xa1\xc3F\xd53\x82\xab\xf6\u0622[\xaaS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xc9\xdczCj\xe9\x8f\xd0\x1cz\x96!\xaa\x8e\x9d\v\x8bS\x1d\x89a\t=|,m8\x00\x00\xe0\x94:\xd0aI\xb2\x1cU\xff\x86|\xc3\xfb\x97@\u04bc\xc7\x10\x121\x8a)\xb7d2\xb9DQ \x00\x00\u07d4:\xd7\x02C\u060b\xf0@\x0fW\xc8\xc1\xfdW\x81\x18H\xaf\x16*\x89.\x9e\xe5\u00c6S\xf0\x00\x00\u07d4:\xd9\x15\xd5P\xb7#AV \xf5\xa9\xb5\xb8\x8a\x85\xf3\x82\xf05\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xe1`\xe3\xcd`\xae1\xb9\xd6t-h\xe1Nv\xbd\x96\xc5\x17\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4:\xe6+\xd2q\xa7`c\u007f\xady\xc3\x1c\x94\xffb\xb4\xcd\x12\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xeaN\x82\xd2@\x02H\xf9\x98q\xa4\x1c\xa2W\x06\r:\"\x1b\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xf6[>(\x89ZJ\x00\x11S9\x1d\x1ei\xc3\x1f\xb9\xdb9\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4;\a\xdbZ5\u007fZ\xf2HL\xbc\x9dw\xd7;\x1f\xd0Q\x9f\u01c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4;\n\u032fK`|\xfea\xd1s4\xc2\x14\xb7\\\xde\xfd\xbd\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x13c\x1a\x1b\x89\xcbVeH\x89\x9a\x1d`\x91\\\xdc\xc4 [\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x15\x90\x99\aR\a\u0180vc\xb1\xf0\xf7\xed\xa5J\xc8\xcc\xe3\x89j\xc4\xe6[i\xf9-\x80\x00\u07d4;\x197\xd5\u74f8\x9bc\xfb\x8e\xb5\xf1\xb1\xc9\xcak\xa0\xfa\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\"\xda*\x02q\xc8\xef\xe1\x02S'scji\xb1\xc1~\t\x89\x1b6\xa6DJ>\x18\x00\x00\u07d4;\"\u07a3\xc2_\x1bY\u01fd'\xbb\x91\u04e3\xea\xec\xef9\x84\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94;#g\xf8IK_\xe1\x8dh<\x05]\x89\x99\x9c\x9f=\x1b4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;,E\x99\x0e!GDQ\xcfOY\xf0\x19U\xb31\xc7\xd7\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94;A\x00\xe3\ns\xb0\xc74\xb1\x8f\xfa\x84&\u045b\x191/\x1a\x8a\v\xb5\u046ap\n\xfd\x90\x00\x00\u07d4;B\xa6m\x97\x9fX(4tz\x8b`B\x8e\x9bN\xec\xcd#\x89!\xa1\u01d0\xfa\xdcX\x00\x00\u07d4;Gh\xfdq\xe2\xdb,\xbe\u007f\xa0PH<'\xb4\xeb\x93\x1d\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;Vj\x8a\xfa\u0456\x82\xdc,\xe8g\x9a<\xe4D\xa5\xb0\xfdO\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\\%\x1d\u007f\u05c9;\xa2\t\xfeT\x1c\xec\xd0\xce%:\x99\r\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4;^\x8b\x17w\xca\x18A\x896\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\x93\xb1a6\xf1\x1e\xaf\x10\x99l\x95\x99\r;'9\xcc\xea_\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;\xabK\x01\xa7\xc8K\xa1?\uea70\xbb\x19\x1bw\xa3\xaa\u0723\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4;\xb55\x98\xcc \xe2\x05]\xc5S\xb0I@J\u0277\xdd\x1e\x83\x89!W\x1d\xf7|\x00\xbe\x00\x00\u07d4;\xbc\x13\xd0J\xcc\xc0pz\xeb\u072e\xf0\x87\u0438~\v^\u327e\xd1\xd0&=\x9f\x00\x00\x00\u07d4;\xc6\xe3\xeezV\u038f\x14\xa3u2Y\x0fcqk\x99f\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\xc8]ls[\x9c\xdaK\xba_H\xb2K\x13\xe7\x0600{\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4;\xd6$\xb5H\xcbe\x976\x90~\u062a<\fp^$\xb5u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\u0660m\x1b\xd3lN\xdd'\xfc\r\x1f[\b\x8d\xda\xe3\xc7*\x89\x1b\x1azB\v\xa0\r\x00\x00\u0794;\u077c\x814\xf7}UY\u007f\xc9|&\xd2f\x98\t\x06\x04\ub23e -j\x0e\xda\x00\x00\xe0\x94;\xf8n\u0623\x15>\xc93xj\x02\xac\t\x03\x01\x85^Wk\x8a_J\x8c\x83u\xd1U@\x00\x00\u07d4;\xfb\u04c4|\x17\xa6\x1c\xf3\xf1{R\xf8\ub879`\xb3\U000df262\xa1]\tQ\x9b\xe0\x00\x00\u07d4<\x03\xbb\xc0#\xe1\xe9?\xa3\xa3\xa6\xe4(\xcf\f\xd8\xf9^\x1e\u0189Rf<\u02b1\xe1\xc0\x00\x00\u07d4<\f=\ufb1c\xeaz\xcc1\x9a\x96\xc3\v\x8e\x1f\xed\xabEt\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4<\x15\xb3Q\x1d\xf6\xf04.sH\u0309\xaf9\xa1h\xb7s\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x1f\x91\xf3\x01\xf4\xb5e\xbc\xa2GQ\xaa\x1fv\x13\"p\x9d\u0749a\t=|,m8\x00\x00\xe0\x94<(l\xfb0\x14n_\u05d0\xc2\xc8T\x15RW\x8d\xe34\u060a\x02)\x1b\x11\xaa0n\x8c\x00\x00\u07d4<2.a\x1f\u06c2\rG\xc6\xf8\xfcd\xb6\xfa\xd7L\xa9_^\x89\r%\x8e\xce\x1b\x13\x15\x00\x00\u07d4\xa5\xe5\xbfb\xbb\u0309\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4<\x86\x9c\tie#\xce\xd8$\xa0pAF\x05\xbbv#\x1f\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x92V\x19\u02731DF?\x057\u06165\x87\x06\xc5 \xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\x98YK\xf6\x8bW5\x1e\x88\x14\xae\x9em\xfd-%J\xa0o\x89\x10CV\x1a\x88)0\x00\x00\u07d4<\xad\xeb=>\xed?b1\x1dRU>p\xdfJ\xfc\xe5o#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94<\xae\xdbS\x19\xfe\x80eC\xc5nP!\xd3r\xf7\x1b\xe9\x06.\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4<\xaf\xaf^bPV\x15\x06\x8a\xf8\xeb\"\xa1:\u0629\xe5Pp\x89lf\x06E\xaaG\x18\x00\x00\u07d4<\xb1y\xcbH\x01\xa9\x9b\x95\u00f0\xc3$\xa2\xbd\xc1\x01\xa6S`\x89\x01h\u048e?\x00(\x00\x00\u07d4<\xb5a\u0386BK5\x98\x91\xe3d\xec\x92_\xfe\xff'}\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xcbq\xaah\x80\xcb\v\x84\x01-\x90\xe6\a@\xec\x06\xac\u05cf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\xce\xf8\x86yW9G\xe9I\x97y\x8a\x1e2~\b`:e\x89+\xc9\x16\u059f;\x02\x00\x00\xe0\x94<\xd1\xd9s\x1b\xd5H\xc1\xddo\u03a6\x1b\xebu\xd9\x17T\xf7\u04ca\x01\x16\x1d\x01\xb2\x15\xca\xe4\x80\x00\u07d4<\u04e6\xe95y\xc5mIAq\xfcS>z\x90\xe6\xf5\x94d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\u05b7Y<\xbe\xe7x0\xa8\xb1\x9d\b\x01\x95\x8f\xcdK\xc5z\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4<\xd7\xf7\xc7\xc257\x80\xcd\xe0\x81\xee\xecE\x82+%\xf2\x86\f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xe1\u0717\xfc\u05f7\xc4\u04e1\x8aI\xd6\xf2\xa5\xc1\xb1\xa9\x06\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xea0*G*\x94\x03y\xdd9\x8a$\xea\xfd\xba\u07c8\xady\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94<\xec\xa9k\xb1\xcd\xc2\x14\x02\x9c\xbc^\x18\x1d9\x8a\xb9M=A\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4<\xf4\x84RO\xbd\xfa\xda\xe2m\xc1\x85\xe3++c\x0f\xd2\xe7&\x89\x18TR\xcb*\x91\xc3\x00\x00\u07d4<\xf9\xa1\xd4e\xe7\x8bp9\xe3iDx\xe2b{6\xfc\xd1A\x89J`S*\xd5\x1b\xf0\x00\x00\u07d4<\xfb\xf0fVYpc\x9e\x13\r\xf2\xa7\xd1k\x0e\x14\xd6\t\x1c\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94=\th\x8d\x93\xad\a\xf3\xab\xe6\x8cr'#\xcdh\t\x90C^\x8a\x06ZL\xe9\x9fv\x9en\x00\x00\u07d4=1X{_\u0546\x98Ex\x87%\xa6c)\nI\xd3g\x8c\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4=?\xadI\xc9\xe5\xd2u\x9c\x8e\x8eZzM`\xa0\xdd\x13V\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=WO\xcf\x00\xfa\xe1\u064c\u023f\x9d\u07e1\xb3\x95;\x97A\xbc\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4=Z\x8b+\x80\xbe\x8b5\xd8\xec\xf7\x89\xb5\xedz\au\xc5\al\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=f\xcdK\xd6M\\\x8c\x1b^\xea(\x1e\x10m\x1cZ\xad#s\x89i\xc4\xf3\xa8\xa1\x10\xa6\x00\x00\u0794=j\xe0S\xfc\xbc1\x8do\xd0\xfb\xc3S\xb8\xbfT.h\r'\x88\xc6s\xce<@\x16\x00\x00\u07d4=o\xf8,\x93w\x05\x9f\xb3\r\x92\x15r?`\xc7u\u0211\xfe\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4=y\xa8S\xd7\x1b\xe0b\x1bD\xe2\x97Yel\xa0u\xfd\xf4\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=~\xa5\xbf\x03R\x81\x00\xed\x8a\xf8\xae\xd2e>\x92\x1bng%\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\x81?\xf2\xb6\xedW\xb97\u06bf+8\x1d\x14\x8aA\x1f\xa0\x85\x89\x05k\xc7^-c\x10\x00\x00\u07d4=\x88\x143\xf0J}\r'\xf8ID\xe0\x8aQ-\xa3UR\x87\x89A\rXj \xa4\xc0\x00\x00\u07d4=\x89\xe5\x05\xcbF\xe2\x11\xa5?2\xf1g\xa8w\xbe\xc8\u007fK\n\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94=\x8d\a#r\x1es\xa6\xc0\xd8`\xaa\x05W\xab\xd1L\x1e\xe3b\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4=\x8f9\x88\x1b\x9e\xdf\xe9\x12'\xc3?\xa4\xcd\xd9\x1eg\x85D\xb0\x89\x04\xab\a\xbaC\xad\xa9\x80\x00\u07d4=\x9dk\xe5\u007f\xf8>\x06Y\x85fO\x12VD\x83\xf2\xe6\x00\xb2\x89n\xac\xe4?#\xbd\x80\x00\x00\u07d4=\xa3\x9c\xe3\xefJz9f\xb3.\xe7\xeaN\xbc#5\xa8\xf1\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=\xaa\x01\u03b7\x0e\xaf\x95\x91\xfaR\x1b\xa4\xa2~\xa9\xfb\x8e\xdeJ\x89Zc\xd2\u027cvT\x00\x00\u07d4=\xb5\xfejh\xbd6\x12\xac\x15\xa9\x9aa\xe5U\x92\x8e\xec\xea\xf3\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4=\xb9\xed\u007f\x02L~&7/\xea\xcf+\x05\b\x03D^8\x10\x89E\xb1H\xb4\x99j0\x00\x00\u07d4=\xbf\r\xbf\xd7x\x90\x80\x053\xf0\x9d\xea\x83\x01\xb9\xf0%\u04a6\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\xce\U0005c18b\x15\xd3N\xdaBn\xc7\xe0K\x18\xb6\x01p\x02\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94=\xd1.Uj`76\xfe\xbaJo\xa8\xbdJ\xc4]f*\x04\x8a#u{\x91\x83\xe0x(\x00\x00\u07d4=\u078b\x15\xb3\u033a\xa5x\x01\x12\xc3\xd6t\xf3\x13\xbb\xa6\x80&\x89`\x1dQZ>O\x94\x00\x00\xe0\x94=\xde\xdb\xe4\x89#\xfb\xf9\xe56\xbf\x9f\xfb\aG\xc9\xcd\u04de\xef\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4=\xea\xe43'\x91?b\x80\x8f\xaa\x1bbv\xa2\xbdch\xea\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4=\xf7b\x04\x9e\u068a\u0192}\x90Lz\xf4/\x94\xe5Q\x96\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\x04\r@\u02c0\xba\x01%\xf3\xb1_\xde\xfc\xc8?0\x05\xda\x1b\x898E$\xccp\xb7x\x00\x00\u07d4>\v\x8e\xd8n\xd6i\xe1'#\xafur\xfb\xac\xfe\x82\x9b\x1e\x16\x89QM\xe7\xf9\xb8\x12\xdc\x00\x00\xe0\x94>\f\xbejm\xcba\xf1\x10\xc4[\xa2\xaa6\x1d\u007f\xca\xd3\xdas\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4>\x19KN\xce\xf8\xbbq\x1e\xa2\xff$\xfe\xc4\xe8{\xd02\xf7\u0449\x8b\x9d\xc1\xbc\x1a\x03j\x80\x00\xe0\x94>\x1b\"0\xaf\xbb\xd3\x10\xb4\x92jLwmZ\u705cf\x1d\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4>\x1cS0\x0eL\x16\x89\x12\x16<~\x99\xb9]\xa2h\xad(\n\x896b2\\\u044f\xe0\x00\x00\u07d4>\x1c\x96 c\xe0\xd5)YA\xf2\x10\u0723\xabS\x1e\xec\x88\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4>,\xa0\xd24\xba\xf6\a\xadFj\x1b\x85\xf4\xa6H\x8e\xf0\n\xe7\x89\x04\xda!\xa3H=V\x80\x00\u07d4>/&#^\x13zs$\xe4\xdc\x15K]\xf5\xafF\xea\x1aI\x89\x017\xaa\xd8\x03-\xb9\x00\x00\xe0\x94>1a\xf1\xea/\xbf\x12ny\xda\x18\x01\u0695\x12\xb3y\x88\u024a\nm\xd9\f\xaeQ\x14H\x00\x00\xe0\x94>6\xc1rS\xc1\x1c\xf3\x89t\xed\r\xb1\xb7Y\x16\r\xa67\x83\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4><\u04fe\xc0e\x91\xd64o%Kb\x1e\xb4\x1c\x89\x00\x8d1\x895\u07fe\u069f74\x00\x00\u07d4>E\xbdU\u06d0`\xec\xed\x92;\xb9\xcbs<\xb3W?\xb51\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4>M\x13\xc5Z\x84\xe4n\xd7\xe9\u02d0\xfd5^\x8a\u0651\u33c965\u026d\xc5\u07a0\x00\x00\u07d4>N\x92e\"<\x9782L\xf2\v\xd0`\x06\xd0\a>\u06cc\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94>O\xbdf\x10\x15\xf6F\x1e\xd6s\\\xef\xef\x01\xf3\x14E\xde:\x8a\x03n4)\x98\xb8\xb0 \x00\x00\xe0\x94>S\xff!\a\xa8\u07be3(I:\x92\xa5\x86\xa7\xe1\xf4\x97X\x8a\x04\xe6\x9c*q\xa4\x05\xab\x00\x00\u07d4>Z9\xfd\xdap\xdf\x11&\xab\r\u011asx1\x1aSz\x1f\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\xe0\x94>Z\xbd\t\xceZ\xf7\xba\x84\x87\xc3Y\xe0\xf2\xa9:\x98k\v\x18\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4>\\\xb8\x92\x8cAx%\xc0:;\xfc\xc5!\x83\xe5\xc9\x1eB\u05c9\xe71\xd9\xc5,\x96/\x00\x00\u07d4>^\x93\xfbL\x9c\x9d\x12F\xf8\xf2G5\x8e\"\xc3\xc5\xd1{j\x89\b!\xab\rD\x14\x98\x00\x00\u07d4>a\x83P\xfa\x01ez\xb0\xef>\xba\xc8\xe3p\x12\xf8\xfc+o\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d4>c\xce;$\xca(e\xb4\u0166\x87\xb7\xae\xa3Y~\xf6\xe5H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>f\xb8GiVj\xb6yE\xd5\xfa\x8175V\xbc\u00e1\xfa\x89\b=lz\xabc`\x00\x00\xe0\x94>v\xa6-\xb1\x87\xaat\xf68\x17S;0l\xea\xd0\xe8\u03be\x8a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4>z\x96k]\xc3W\xff\xb0~\x9f\xe0g\xc4W\x91\xfd\x8e0I\x89\x034-`\xdf\xf1\x96\x00\x00\xe0\x94>\x81w!u#~\xb4\xcb\xe0\xfe-\xca\xfd\xad\xff\xebj\x19\x99\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4>\x83I\xb6\u007fWED\x9fe\x93g\u066dG\x12\xdb[\x89Z\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4>\x83TO\x00\x82U%r\u01c2\xbe\xe5\xd2\x18\xf1\xef\x06J\x9d\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4>\x84\xb3\\[\"ePpa\xd3\vo\x12\xda\x03?\xe6\xf8\xb9\x89a\t=|,m8\x00\x00\u07d4>\x86A\xd4\x87E\xba2/_\xd6\xcbP\x12N\xc4f\x88\u01e6\x9a\u007f\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4>\x91N0\x18\xac\x00D\x93A\u011d\xa7\x1d\x04\xdf\xee\xedb!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4>\x94\x10\u04f9\xa8~\xd5\xe4Q\xa6\xb9\x1b\xb8\x92?\xe9\x0f\xb2\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4>\x94\xdfS\x13\xfaR\x05p\xef#+\xc31\x1d_b/\xf1\x83\x89lk\x93[\x8b\xbd@\x00\x00\u0794>\x9b4\xa5\u007f3u\xaeY\xc0\xa7^\x19\u0136A\"\x8d\x97\x00\x88\xf8i\x93)g~\x00\x00\u07d4>\xad\xa8\xc9/V\x06~\x1b\xb7<\xe3x\xdaV\xdc,\xdf\xd3e\x89w\xcd\xe9:\xeb\rH\x00\x00\xe0\x94>\xaf\by\xb5\xb6\xdb\x15\x9bX\x9f\x84W\x8bjt\xf6\xc1\x03W\x8a\x01\x898\xb6q\xfae\xa2\x80\x00\u07d4>\xaf1k\x87a]\x88\xf7\xad\xc7|X\xe7\x12\xedMw\x96k\x89\x05m\xbcL\xee$d\x80\x00\u07d4>\xb8\xb3;!\xd2<\u0686\xd8(\x88\x84\xabG\x0e\x16F\x91\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4>\xb9\xef\x06\xd0\xc2Y\x04\x03\x19\x94~\x8czh\x12\xaa\x02S\u0609\t\r\x97/22<\x00\x00\u07d4>\u030e\x16h\xdd\xe9\x95\xdcW\x0f\xe4\x14\xf4B\x11\xc54\xa6\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\u03752\xe3\x97W\x96b\xb2\xa4aA\u73c25\x93j_\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4>\xeeo\x1e\x966\vv\x89\xb3\x06\x9a\xda\xf9\xaf\x8e\xb6\f\u404965\u026d\xc5\u07a0\x00\x00\xe0\x94?\b\u066d\x89O\x81>\x8e!H\xc1`\xd2K5:\x8et\xb0\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4?\f\x83\xaa\xc5qybsN\\\xea\xea\xec\u04db(\xad\x06\xbe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94?\x10\x80\x02\x82\u0477\xdd\u01cf\xa9-\x820\aN\x1b\xf6\xae\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4?\x123qO M\xe9\xdeN\xe9m\a;6\x8d\x81\x97\x98\x9f\x89\x02\x17\xc4\x10t\xe6\xbb\x00\x00\u07d4?\x17:\xa6\xed\xf4i\u0445\xe5\x9b\xd2j\xe4#k\x92\xb4\xd8\xe1\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4?\x1b\xc4 \xc5<\x00,\x9e\x90\x03|D\xfej\x8e\xf4\xdd\xc9b\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4?#a\b\xee\xc7\"\x89\xba\u00e6\\\u0483\xf9^\x04\x1d\x14L\x8964\xbf9\xab\x98x\x80\x00\u07d4?-\xa0\x93\xbb\x16\xeb\x06O\x8b\xfa\x9e0\xb9)\xd1_\x8e\x1cL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?-\xd5]\xb7\xea\xb0\xeb\xeee\xb3>\xd8 ,\x1e\x99.\x95\x8b\x89,s\xc97t,P\x00\x00\u07d4?/8\x14\x91y|\xc5\xc0\u0502\x96\xc1O\xd0\xcd\x00\xcd\xfa-\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4?0\u04fc\x9f`\"2\xbcrB\x88\xcaF\xcd\v\a\x88\xf7\x15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4?<\x8ea\xe5`L\xef\x06\x05\xd46\xdd\"\xac\u0346\"\x17\xfc\x89Hz\x9a0E9D\x00\x00\u07d4??F\xb7\\\xab\xe3{\xfa\u0307`(\x1fCA\xca\u007fF=\x89 \xacD\x825\xfa\xe8\x80\x00\u07d4?G)c\x19x\x83\xbb\xdaZ\x9b}\xfc\xb2-\xb1\x14@\xad1\x89\x1a\x19d<\xb1\xef\xf0\x80\x00\u07d4?L\xd19\x9f\x8a4\xed\u06da\x17\xa4q\xfc\x92+Xp\xaa\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?U\x1b\xa9<\xd5F\x93\xc1\x83\xfb\x9a\xd6\re\xe1`\x96s\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94?bzv\x9ej\x95\x0e\xb8p\x17\xa7\u035c\xa2\bq\x13h1\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4?m\xd3e\x0e\xe4(\u0737u\x95S\xb0\x17\xa9j\x94(j\u0249Hz\x9a0E9D\x00\x00\u07d4?tr7\x80o\xed?\x82\x8ahR\xeb\bg\xf7\x90'\xaf\x89\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4?u\xaea\xcc\x1d\x80Be;[\xae\xc4D>\x05\x1c^z\xbd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4?\xb7\u0457\xb3\xbaO\xe0E\xef\xc2=P\xa1E\x85\xf5X\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94?\xbc\x1eE\x18\xd74\x00\xc6\xd0F5\x949\xfbh\xea\x1aI\xf4\x8a\x03y\v\xb8U\x13v@\x00\x00\u07d4?\xbe\xd6\xe7\xe0\u029c\x84\xfb\xe9\xeb\u03ddN\xf9\xbbIB\x81e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\u043bGy\x8c\xf4L\u07feM3=\xe67\xdfJ\x00\xe4\\\x89\x05lUy\xf7\"\x14\x00\x00\xe0\x94?\xe4\x0f\xbd\x91\x9a\xad(\x18\xdf\x01\xeeM\xf4lF\x84*\xc59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4?\xe8\x01\xe6\x135\xc5\x14\r\xc7\xed\xa2\xefR\x04F\nP\x120\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\xf86\xb6\xf5{\x90\x1bD\f0\xe4\xdb\xd0e\xcf7\xd3\u050c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?\xfc\xb8p\xd4\x02=%]Qg\u0625\a\xce\xfc6kh\xba\x89#4^\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4@s\xfaI\xb8q\x17\u02d0\x8c\xf1\xabQ-\xa7T\xa92\xd4w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4@\x8ai\xa4\a\x15\xe1\xb3\x13\xe15N`\b\x00\xa1\xe6\xdc\x02\xa5\x89\x01\u7e11\u0312T\x00\x00\u07d4@\x9b\xd7P\x85\x82\x1c\x1d\xe7\f\xdc;\x11\xff\xc3\xd9#\xc7@\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\x9dZ\x96.\xde\uefa1x\x01\x8c\x0f8\xb9\u0372\x13\xf2\x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4@\xa31\x19[\x97s%\u00aa(\xfa/B\xcb%\xec<%<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4@\xa7\xf7(g\xa7\u0706w\v\x16+uW\xa44\xedP\xcc\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xab\n>\x83\xd0\u022c\x93f\x91\x05 \xea\xb1w+\xac;\x1a\x894\xf1\f-\xc0^|\x00\x00\u07d4@\xabf\xfe!>\xa5l:\xfb\x12\xc7[\xe3?\x8e2\xfd\b]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94@\xadt\xbc\v\xce*E\xe5/6\xc3\u07bb\x1b:\xda\x1bv\x19\x8a\x01p\x16-\xe1\t\xc6X\x00\x00\u07d4@\u03c9\x05\x91\xea\u484f\x81*)T\xcb)_c3'\xe6\x89\x02\x9b\xf76\xfcY\x1a\x00\x00\u07d4@\u03d0\xef[v\x8c]\xa5\x85\x00,\xcb\xe6avP\xd8\xe87\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94@\xd4]\x9dv%\xd1QV\xc92\xb7q\xca{\x05'\x13\tX\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4@\xdb\x1b\xa5\x85\xce4S\x1e\xde\xc5IHI9\x13\x81\xe6\xcc\u04c9a\t=|,m8\x00\x00\xe0\x94@\xdfI^\xcf?\x8bL\xef*l\x18\x99W$\x8f\u813c+\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4@\xe0\xdb\xf3\xef\uf404\xea\x1c\xd7\xe5\x03\xf4\v;J\x84C\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\xe2D\n\xe1B\u02006j\x12\xc6\xd4\x10/K\x844\xb6*\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xe3\u0083\xf7\xe2M\xe0A\f\x12\x1b\xee`\xa5`\u007f>)\xa6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94@\xeaPD\xb2\x04\xb20v\xb1\xa5\x80;\xf1\xd3\f\x0f\x88\x87\x1a\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94@\xed\xdbD\x8di\x0e\xd7.\x05\xc2%\xd3O\xc85\x0f\xa1\xe4\u014a\x01{x\x83\xc0i\x16`\x00\x00\xe0\x94@\xf4\xf4\xc0ls,\xd3[\x11\x9b\x89;\x12~}\x9d\aq\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\x01\x0f\u023a\xf8C}\x17\xa0Ci\x80\x9a\x16\x8a\x17\xcaV\xfb\x89\x05k\xc7^-c\x10\x00\x00\u07d4A\x03)\x96q\xd4gc\x97\x8f\xa4\xaa\x19\xee4\xb1\xfc\x95'\x84\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4A\x03<\x1bm\x05\xe1\u0289\xb0\x94\x8f\xc6DS\xfb\xe8z\xb2^\x89Hz\x9a0E9D\x00\x00\u07d4A\t\x8a\x81E#\x17\xc1\x9e>\xef\v\xd1#\xbb\xe1x\xe9\xe9\u0289\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4A\x16\x10\xb1x\xd5a}\xfa\xb94\u0493\xf5\x12\xa9>\\\x10\xe1\x89\t79SM(h\x00\x00\u07d4A\x1c\x83\x1c\xc6\xf4O\x19e\xecWW\xabN[<\xa4\xcf\xfd\x1f\x89\x17\n\x0fP@\xe5\x04\x00\x00\xe0\x94A*h\xf6\xc6EU\x9c\xc9w\xfcId\x04z \x1d\x1b\xb0\xe2\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4A?K\x02f\x9c\xcf\xf6\x80k\xc8&\xfc\xb7\xde\xca;\x0e\xa9\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4AE\x99\t.\x87\x9a\xe2Sr\xa8MsZ\xf5\xc4\xe5\x10\xcdm\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4AHV\x12\xd04F\xecL\x05\xe5$NV?\x1c\xba\xe0\xf1\x97\x894\x95tD\xb8@\xe8\x00\x00\u07d4A]\tj\xb0b\x93\x18?<\x03=%\xf6\xcfqx\xac;\u01c9\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4Af\xfc\b\u0285\xf7f\xfd\xe81F\x0e\x9d\xc9<\x0e!\xaal\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ag\x84\xaf`\x960\xb0p\u051a\x8b\xcd\x12#\\d(\xa4\b\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Ag\xcdH\xe73A\x8e\x8f\x99\xff\xd14\x12\x1cJJ\xb2x\u0109\xc5S%\xcat\x15\xe0\x00\x00\u07d4Al\x86\xb7 \x83\xd1\xf8\x90}\x84\xef\xd2\xd2\u05c3\xdf\xfa>\xfb\x89lj\xccg\u05f1\xd4\x00\x00\u07d4AsA\x9d\\\x9fc)U\x1d\xc4\xd3\xd0\u03ac\x1bp\x1b\x86\x9e\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4At\xfa\x1b\xc1*;q\x83\u02eb\xb7z\vYU{\xa5\xf1\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4Axj\x10\xd4G\xf4\x84\xd32D\u0337\xfa\u034bB{[\x8c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Az<\u0454\x96S\nmB\x04\u00f5\xa1|\xe0\xf2\a\xb1\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4A~N&\x88\xb1\xfdf\xd8!R\x9eF\xedOB\xf8\xb3\xdb=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94A\x9aq\xa3l\x11\xd1\x05\xe0\xf2\xae\xf5\xa3\xe5\x98\a\x8e\x85\xc8\v\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94A\x9b\xdes\x16\xcc\x1e\u0495\u0205\xac\xe3B\u01db\xf7\xee3\xea\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4A\xa2\xf2\xe6\xec\xb8c\x94\xec\x0e3\x8c\x0f\xc9~\x9cU\x83\xde\u0489l\xee\x06\u077e\x15\xec\x00\x00\u07d4A\xa8\u0083\x00\x81\xb1\x02\xdfn\x011e|\a\xabc[T\u0389lj\xccg\u05f1\xd4\x00\x00\u07d4A\xa8\xe26\xa3\x0emc\xc1\xffdM\x13*\xa2\\\x89S~\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4A\xa9\xa4\x04\xfc\x9f[\xfe\xe4\x8e\xc2e\xb1%#3\x8e)\xa8\xbf\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4A\xad6\x9fu\x8f\xef8\xa1\x9a\xa3\x14\x93y\x83,\x81\x8e\xf2\xa0\x8966\x9e\xd7t}&\x00\x00\u07d4A\xb2\xd3O\xde\v\x10)&+Ar\xc8\x1c\x15\x90@[\x03\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4A\xb2\xdb\u05dd\u069b\x86Ojp0'T\x19\u00dd>\xfd;\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4A\xc3\xc26u4\xd1;\xa2\xb3?\x18\\\xdb\xe6\xacC\xc2\xfa1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4A\u02d8\x96D_p\xa1\n\x14!R\x96\xda\xf6\x14\xe3,\xf4\u0549g\x8a\x93 b\xe4\x18\x00\x00\u07d4A\xcey\x95\t5\xcf\xf5[\xf7\x8eL\xce\xc2\xfec\x17\x85\u06d5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4A\u04f71\xa3&\xe7hX\xba\xa5\xf4\xbd\x89\xb5{6\x93#C\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94A\xe4\xa2\x02u\xe3\x9b\xdc\xef\xebe\\\x03\"tKvQ@\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\xed-\x8ep\x81H,\x91\x9f\xc2=\x8f\x00\x91\xb3\xc8,F\x85\x89F:\x1ev[\u05ca\x00\x00\xe0\x94A\xf2~tK\u049d\xe2\xb0Y\x8f\x02\xa0\xbb\x9f\x98\xe6\x81\ua90a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4A\xf4\x89\xa1\xect{\u009c>_\x9d\x8d\xb9xw\xd4\u0474\xe9\x89\a?u\u0460\x85\xba\x00\x00\u07d4B\x0f\xb8n}+Q@\x1f\xc5\xe8\xc7 \x15\xde\xcbN\xf8\xfc.\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\x16\x84\xba\xa9\xc0\xb4\xb5\xf5S8\xe6\xf6\xe7\xc8\xe1F\xd4\x1c\xb7\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4B9\x96Y\xac\xa6\xa5\xa8c\xea\"E\xc93\xfe\x9a5\xb7\x88\x0e\x89n\xce2\xc2l\x82p\x00\x00\xe0\x94B;\xcaG\xab\xc0\fpW\xe3\xad4\xfc\xa6>7_\xbd\x8bJ\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4B<1\a\xf4\xba\xceANI\x9cd9\nQ\xf7F\x15\xca^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B<\xc4YL\xf4\xab\xb66\x8d\xe5\x9f\u04b1#\a4a!C\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BD\xf13\x11X\xb9\xce&\xbb\xe0\xb9#k\x92\x03\xca5\x144\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794BQw\xebt\xad\n\x9d\x9aWR\"\x81G\xeemcV\xa6\u6239\x8b\xc8)\xa6\xf9\x00\x00\u07d4BW%\xc0\xf0\x8f\b\x11\xf5\xf0\x06\xee\xc9\x1c\\\\\x12k\x12\xae\x89\b!\xab\rD\x14\x98\x00\x00\xe0\x94BX\xfdf/\xc4\xce2\x95\xf0\xd4\xed\x8f{\xb1D\x96\x00\xa0\xa9\x8a\x01lE.\xd6\b\x8a\xd8\x00\x00\xe0\x94B\\\x18\x16\x86\x8fww\xcc+\xa6\xc6\u048c\x9e\x1eylR\xb3\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\\3\x8a\x13%\xe3\xa1W\x8e\xfa)\x9eW\u0646\xebGO\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BbY\xb0\xa7Vp\x1a\x8bf5(R!V\xc0(\x8f\x0f$\x8a\x02\x18\xae\x19k\x8dO0\x00\x00\u07d4Bm\x15\xf4\a\xa0\x115\xb1:kr\xf8\xf2R\v51\xe3\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Box\xf7\r\xb2Y\xac\x854\x14[)4\xf4\xef\x10\x98\xb5\u0609\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4Bs-\x8e\xf4\x9f\xfd\xa0K\x19x\x0f\xd3\xc1\x84i\xfb7A\x06\x89\x17\v\x00\xe5\u4a7e\x00\x00\u07d4Bt\x17\xbd\x16\xb1\xb3\xd2-\xbb\x90-\x8f\x96W\x01o$\xa6\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Btj\xee\xa1O'\xbe\xff\f\r\xa6BS\xf1\xe7\x97\x18\x90\xa0\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4B{F*\xb8NP\x91\xf4\x8aF\xeb\f\u0712\xdd\xcb&\xe0x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B~GQ\u00fa\xbex\xcf\xf8\x83\b\x86\xfe\xbc\x10\xf9\x90\x8dt\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94B~\xc6h\xac\x94\x04\xe8\x95\u0306\x15\x11\xd1b\nI\x12\xbe\x98\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4B\x80\xa5\x8f\x8b\xb1\v\x94@\u0794\xf4+OY! \x82\x01\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B\x8a\x1e\xe0\xed3\x1dyR\u033e\x1cyt\xb2\x85+\u0453\x8a\x89w\xb7JN\x8d\xe5e\x00\x00\u0794B\x9c\x06\xb4\x87\xe8Tj\xbd\xfc\x95\x8a%\xa3\xf0\xfb\xa5?o\x00\x88\xbbdJ\xf5B\x19\x80\x00\xe0\x94B\xa9\x8b\xf1`'\xceX\x9cN\xd2\xc9X1\xe2rB\x05\x06N\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\xc6\xed\xc5\x15\xd3UW\x80\x8d\x13\xcdD\xdc\xc4@\v%\x04\xe4\x89\n\xba\x14\u015b\xa72\x00\x00\u07d4B\xce\xcf\u0492\x10y\xc2\xd7\xdf?\b\xb0z\xa3\xbe\xee^!\x9a\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\u04669\x9b0\x16\xa8Y\u007f\x8bd\t'\xb8\xaf\xbc\xe4\xb2\x15\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4B\xd3I@\xed\xd2\xe7\x00]F\xe2\x18\x8eL\xfe\u0383\x11\xd7M\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4B\u04e5\xa9\x01\xf2\xf6\xbd\x93V\xf1\x12\xa7\x01\x80\xe5\xa1U\v`\x892$\xf4'#\xd4T\x00\x00\u07d4B\u05b2c\xd9\xe9\xf4\x11lA\x14$\xfc\x99Ux;\xa1\xc5\x1b\x81\x0f\xc4g\u057aM\xeaB\xf7\xa9\x88^i\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94C>\xb9J3\x90\x86\xed\x12\u067d\xe9\xcd\x1dE\x86\x03\xc9}\u058a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4CI\"Zb\xf7\n\xeaH\n\x02\x99\x15\xa0\x1eSy\xe6O\xa5\x89\x8c\xd6~#4\xc0\xd8\x00\x00\u07d4CT\"\x1eb\xdc\t\xe6@d6\x16:\x18^\xf0m\x11J\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94CTC\xb8\x1d\xfd\xb9\xbd\x8cg\x87\xbc%\x18\xe2\xd4~W\xc1_\x8a\x01C\x8d\x93\x97\x88\x1e\xf2\x00\x00\u07d4Ca\u0504o\xaf\xb3w\xb6\xc0\xeeI\xa5\x96\xa7\x8d\xdf5\x16\xa3\x89\xc2\x12z\xf8X\xdap\x00\x00\xe0\x94Cd0\x9a\x9f\xa0p\x95`\x0fy\xed\xc6Q \xcd\xcd#\xdcd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Cg\xaeK\f\xe9d\xf4\xa5J\xfdK\\6\x84\x96\xdb\x16\x9e\x9a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Ct\x89(\xe8\xc3\xecD6\xa1\u0412\xfb\xe4:\xc7I\xbe\x12Q\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4Cv{\xf7\xfd*\xf9[r\xe91-\xa9D<\xb1h\x8eCC\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94Cy\x838\x8a\xb5\x9aO\xfc!_\x8e\x82iF\x10)\xc3\xf1\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4C\x89\x8cI\xa3MP\x9b\xfe\xd4\xf7`A\xee\x91\xca\xf3\xaaj\xa5\x89\x10CV\x1a\x88)0\x00\x00\u07d4C\x8c/T\xff\x8eb\x9b\xab6\xb1D+v\v\x12\xa8\x8f\x02\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\x98b\x8e\xa6c-9>\x92\x9c\xbd\x92\x84d\xc5h\xaaJ\f\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4C\x9d//Q\x10\xa4\u054b\x17W\x93P\x15@\x87@\xfe\xc7\xf8\x89\u03e5\xc5\x15\x0fL\x88\x80\x00\u07d4C\x9d\xee?vy\xff\x100s?\x93@\xc0\x96hkI9\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xb0y\xba\xf0ry\x99\xe6k\xf7C\u057c\xbfwl;\t\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xbc-M\xdc\xd6X;\xe2\u01fc\tK(\xfbr\xe6+\xa8;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xc7\xeb\u0173\xe7\xaf\x16\xf4}\xc5az\xb1\x0e\x0f9\xb4\xaf\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4C\u02d6R\x81\x8coMg\x96\xb0\xe8\x94\t0ly\xdbcI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xcc\b\xd0s*\xa5\x8a\xde\xf7a\x9b\xedFU\x8a\xd7wAs\x89\xf0\xe7\u0730\x12*\x8f\x00\x00\xe0\x94C\u0567\x1c\xe8\xb8\xf8\xae\x02\xb2\xea\xf8\xea\xf2\xca(@\xb9?\xb6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794C\xdb\u007f\xf9Z\bm(\ubff8/\xb8\xfb_#\n^\xbc\u0348\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4C\xe7\xec\x84cX\xd7\xd0\xf97\xad\x1c5\v\xa0i\u05ffr\xbf\x89\x06p\xaeb\x92\x14h\x00\x00\u07d4C\xf1o\x1eu\xc3\xc0j\x94x\xe8\u0157\xa4\n<\xb0\xbf\x04\u0309\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4C\xf4p\xede\x9e)\x91\xc3u\x95~]\xde\u017d\x1d8\"1\x89\x05k\xc7^-c\x10\x00\x00\u07d4C\xf7\xe8n8\x1e\xc5\x1e\u0110m\x14v\u02e9z=\xb5\x84\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4C\xff8t>\xd0\xcdC0\x8c\x06e\t\u030e~r\xc8b\xaa\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94C\xff\x88S\xe9\x8e\xd8@k\x95\x00\n\u0684\x83b\u05a09*\x8a\x04\xae\v\x1cM.\x84\xd0\x00\x00\u07d4D\t\x88f\xa6\x9bh\xc0\xb6\xbc\x16\x82)\xb9`5\x87\x05\x89g\x89\n1\x06+\xee\xedp\x00\x00\u07d4D\x19\xaca\x8d]\xea|\xdc`w o\xb0}\xbd\xd7\x1c\x17\x02\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4D\x1aR\x00\x16a\xfa\xc7\x18\xb2\u05f3Q\xb7\xc6\xfbR\x1az\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94D\x1a\u0282c\x13$\xac\xbf\xa2F\x8b\xda2[\xbdxG{\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4D\x1f7\xe8\xa0)\xfd\x02H/(\x9cI\xb5\xd0m\x00\xe4\b\xa4\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4D \xaa5F[\xe6\x17\xad$\x98\xf3p\xde\n<\xc4\xd20\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4D#/\xf6m\xda\xd1\xfd\x84\x12f8\x006\xaf\xd7\xcf}\u007fB\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D%\rGn\x06$\x84\xe9\b\n9g\xbf:Js*\xd7?\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4D)\xa2\x9f\xee\x19\x84Pg,\f\x1d\a1b%\v\xecdt\x896*\xaf\x82\x02\xf2P\x00\x00\u07d4D5RS\xb2wH\xe3\xf3O\xe9\xca\xe1\xfbq\x8c\x8f$\x95)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D8\xe8\x80\xcb'f\xb0\xc1\u03ae\xc9\xd2A\x8f\u03b9R\xa0D\x89\a?\xa0s\x90?\b\x00\x00\u07d4DL\xafy\xb7\x138\ue6a7\xc73\xb0*\u02a7\xdc\x02YH\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4D\\\xb8\xde^=\xf5 \xb4\x99\xef\u0240\xf5+\xff@\xf5\\v\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Dj\x809\xce\u03dd\xceHy\xcb\xca\xf3I;\xf5E\xa8\x86\x10\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4Dt)\x9d\x0e\xe0\x90\u0710x\x9a\x14\x86H\x9c=\rd^m\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\x8b\xf4\x10\xad\x9b\xbc/\xec\xc4P\x8d\x87\xa7\xfc.K\x85a\xad\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4D\x90\x1e\r\x0e\b\xac=^\x95\xb8\xec\x9d^\x0f\xf5\xf1.\x03\x93\x89\x16\xa1\xf9\xf5\xfd}\x96\x00\x00\xe0\x94D\x93\x12<\x02\x1e\xce;3\xb1\xa4R\xc9&\x8d\xe1@\a\xf9\u04ca\x01je\x02\xf1Z\x1eT\x00\x00\xe0\x94D\x9a\xc4\xfb\xe3\x83\xe3g8\x85^6JW\xf4q\xb2\xbf\xa11\x8a)\xb7d2\xb9DQ \x00\x00\u07d4D\xa0\x1f\xb0J\xc0\xdb,\xce]\xbe(\x1e\x1cF\xe2\x8b9\xd8x\x89lj\xccg\u05f1\xd4\x00\x00\u07d4D\xa6=\x18BE\x87\xb9\xb3\a\xbf\xc3\xc3d\xae\x10\xcd\x04\xc7\x13\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94D\xa8\x98\x9e20\x81!\xf7$f\x97\x8d\xb3\x95\xd1\xf7l:K\x8a\x01\x88P)\x9fB\xb0j\x00\x00\u07d4D\xc1\x11\v\x18\x87\x0e\xc8\x11x\xd9=!X8\xc5Q\u050ed\x89\n\xd6\xf9\x85\x93\xbd\x8f\x00\x00\u07d4D\xc1Ge\x12|\xde\x11\xfa\xb4l],\xf4\u0532\x89\x00#\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94D\xc5N\xaa\x8a\xc9@\xf9\xe8\x0f\x1et\xe8/\xc1O\x16v\x85j\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4D\xcdwSZ\x89?\xa7\xc4\xd5\xeb:$\x0ey\u0419\xa7--\x89,s\xc97t,P\x00\x00\u07d4D\u07faP\xb8)\xbe\xcc_O\x14\u0470J\xab3 \xa2\x95\xe5\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\xe2\xfd\xc6y\xe6\xbe\xe0\x1e\x93\xefJ:\xb1\xbc\xce\x01*\xbc|\x89\x16=\x19I\x00\xc5E\x80\x00\xe0\x94D\xf6/*\xaa\xbc)\xad:k\x04\xe1\xffo\x9c\xe4R\xd1\xc1@\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4D\xff\xf3{\xe0\x1a8\x88\u04f8\xb8\u1200\xa7\xdd\xef\xee\xea\u04c9\x0e\f[\xfc}\xae\x9a\x80\x00\u07d4E\x06\xfe\x19\xfaK\x00k\xaa9\x84R\x9d\x85\x16\xdb++P\xab\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\x1b6\x99G[\xed]y\x05\xf8\x90Z\xa3Eo\x1e\u05c8\xfc\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u0794E\x1bpp%\x9b\u06e2q\x00\xe3n#B\x8aS\xdf\xe3\x04\u9239\x8b\xc8)\xa6\xf9\x00\x00\u07d4E'+\x8fb\xe9\xf9\xfa\x8c\xe0D \u1ba3\xeb\xa9hn\xac\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94E+d\u06ce\xf7\xd6\u07c7\u01c8c\x9c\"\x90\xbe\x84\x82\xd5u\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E>5\x9a3\x97\x94LZ'Z\xb1\xa2\xf7\n^Z?i\x89\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4EI\xb1Yy%_~e\xe9\x9b\rV\x04\u06d8\xdf\xca\u023f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4EKa\xb3D\xc0\xef\x96Qy#\x81U\xf2w\u00c2\x9d\v8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94EO\x01A\xd7!\xd3<\xbd\xc4\x10\x18\xbd\x01\x11\x9a\xa4xH\x18\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4ES3\x90\xe3@\xfe\r\xe3\xb3\xcf_\xb9\xfc\x8e\xa5R\xe2\x9eb\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4ES\x96\xa4\xbb\u067a\u8bdf\xb7\xc4\xd6MG\x1d\xb9\xc2E\x05\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4E[\x92\x96\x92\x1at\xd1\xfcAa\u007fC\xb80>o>\xd7l\x89\u3bb5sr@\xa0\x00\x00\u07d4E\\\xb8\xee9\xff\xbcu#1\xe5\xae\xfcX\x8e\xf0\xeeY4T\x8965F:x\r\xef\x80\x00\u07d4Ej\u0b24\x8e\xbc\xfa\xe1f\x06\x02PR_c\x96^v\x0f\x89\x10CV\x1a\x88)0\x00\x00\u07d4Eo\x8dtf\x82\xb2$g\x93I\x06M\x1b6\x8c|\x05\xb1v\x89\u0213\u041c\x8fQP\x00\x00\u07d4Ep)\xc4i\xc4T\x8d\x16\x8c\xec>e\x87.D(\xd4+g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Eq\xdeg+\x99\x04\xba\xd8t6\x92\xc2\x1cO\xdc\xeaL.\x01\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Ex\x1b\xbew\x14\xa1\xc8\xf7;\x1cty!\xdfO\x84'\x8bp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E{\xce\xf3}\xd3\xd6\v-\xd0\x19\xe3\xfea\xd4k?\x1erR\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94E\x8e<\u025e\x94xD\xa1\x8ejB\x91\x8f\xef~\u007f_^\xb3\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4E\x93\x93\xd6:\x06>\xf3r\x1e\x16\xbd\x9f\xdeE\ue77dw\xfb\x89j\xba\u05a3\xc1S\x05\x00\x00\u07d4E\xa5p\xdc\xc2\t\f\x86\xa6\xb3\xea)\xa6\bc\xdd\xe4\x1f\x13\xb5\x89\f\x9a\x95\xee)\x86R\x00\x00\u07d4E\xa8 \xa0g/\x17\xdct\xa0\x81\x12\xbcd?\xd1\x16w6\u00c9\n\xd6\xc4;(\x15\xed\x80\x00\u07d4E\xb4q\x05\xfeB\xc4q-\xcen*!\xc0[\xff\xd5\xeaG\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\xbb\x82\x96R\u063f\xb5\x8b\x85'\xf0\xec\xb6!\u009e!.\u00c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\xc0\u045f\v\x8e\x05O\x9e\x8986\xd5\xec\xaey\x01\xaf(\x12\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4E\xc4\xec\xb4\xee\x89\x1e\xa9\x84\xa7\xc5\xce\xfd\x8d\xfb\x001\v(P\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4E\u028d\x95f\b\xf9\xe0\n/\x99t\x02\x86@\x88\x84ef\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u0298b\x00;N@\xa3\x17\x1f\xb5\xca\xfa\x90(\xca\xc8\xde\x19\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4E\xd1\xc9\xee\xdf|\xabA\xa7y\x05{y9_T(\xd8\x05(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\u0535M7\xa8\xcfY\x98!#_\x06/\xa9\xd1p\xed\u8909\x11\x90g;_\u0690\x00\x00\xe0\x94E\xdb\x03\xbc\xcf\u05a5\xf4\xd0&k\x82\xa2*6\x87\x92\xc7}\x83\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E\xe3\xa9>r\x14J\u0686\f\xbcV\xff\x85\x14Z\xda8\xc6\u0689WG=\x05\u06ba\xe8\x00\x00\u07d4E\u6378\u06fa\xba_\xc2\xcb3|b\xbc\xd0\xd6\x1b\x05\x91\x89\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u6379L}\n\xb7\xacA\x85zq\xd6qG\x87\x0fNq\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4E\xf4\xfc`\xf0\x8e\xac\xa1\x05\x98\xf03c)\x80\x1e<\x92\xcbF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F\rSU\xb2\xce\xebnb\x10}\x81\xe5\x12p\xb2k\xf4V \x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94F\"O2\xf4\xec\xe5\u0206p\x90\xd4@\x9dU\xe5\v\x18C-\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4F'\xc6\x06\x84&q\xab\u0782\x95\xee]\xd9L\u007fT\x954\xf4\x89\x0f\x89_\xbd\x872\xf4\x00\x00\u07d4F+g\x8bQ\xb5\x84\xf3\xedz\xda\a\v\\\u065c\v\xf7\xb8\u007f\x89\x05k\xc7^-c\x10\x00\x00\u07d4FM\x9c\x89\xcc\xe4\x84\xdf\x00\x02w\x19\x8e\xd8\a_\xa65r\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4FPNj!Z\xc8;\xcc\xf9V\xbe\xfc\x82\xabZg\x93q\u0209\x1c!(\x05\u00b4\xa5\x00\x00\xe0\x94FQ\xdcB\x0e\b\xc3);'\xd2Ix\x90\xebP\":\xe2\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4FS\x1e\x8b\x1b\xde\t\u007f\u07c4\x9dm\x11\x98\x85`\x8a\x00\x8d\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Fb\x92\xf0\xe8\rC\xa7\x87t'u\x90\xa9\xebE\x96\x12\x14\xf4\x894\x95tD\xb8@\xe8\x00\x00\xe0\x94Fb\xa1v^\xe9!\x84-\u0708\x89\x8d\x1d\xc8bu\x97\xbd~\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Fe\xe4s\x96\xc7\u06d7\xeb*\x03\xd9\bc\xd5\u053a1\x9a\x94\x89 \x86\xac5\x10R`\x00\x00\u07d4Fo\xdak\x9bX\xc5S'P0j\x10\xa2\xa8\xc7h\x10;\a\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4Fq$\xae\u007fE/&\xb3\xd5t\xf6\b\x88\x94\xfa]\x1c\xfb;\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u0794Fr*6\xa0\x1e\x84\x1d\x03\xf7\x80\x93^\x91}\x85\u0566z\xbd\x88\xce\xc7o\x0eqR\x00\x00\u07d4Fw\x9aVV\xff\x00\xd7>\xac:\xd0\u00cbl\x850\x94\xfb@\x89\f\x82S\xc9lj\xf0\x00\x00\u07d4Fw\xb0N\x03C\xa3!1\xfdj\xbb9\xb1\xb6\x15k\xba=[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F}Y\x88$\x9ahaG\x16e\x98@\xed\n\xe6\xf6\xf4W\xbc\x89\x15\x01\xa4\x8c\xef\xdf\xde\x00\x00\u07d4F~\x0e\xd5O;v\xae\x066\x17n\aB\b\x15\xa0!sn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F~\xa1\x04E\x82~\xf1\xe5\x02\xda\xf7k\x92\x8a \x9e\r@2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94F\u007f\xbfAD\x16\x00u\u007f\xe1X0\xc8\xcd_O\xfb\xbb\xd5`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94F\x93Xp\x932\xc8+\x88~ \xbc\xdd\xd0\"\x0f\x8e\u06e7\u040a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4F\x97\xba\xaf\x9c\xcb`?\xd3\x040h\x9dCTE\xe9\u024b\xf5\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4F\xa3\v\x8a\x80\x891!tE\xc3\xf5\xa9>\x88,\x03E\xb4&\x89\r\x8d\xb5\xeb\u05f2c\x80\x00\u07d4F\xa40\xa2\u0528\x94\xa0\u062a?\xea\xc6\x156\x14\x15\xc3\xf8\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F\xaaP\x18pg~\u007f\nPHv\xb4\xe8\x80\x1a\n\xd0\x1cF\x89+^:\xf1k\x18\x80\x00\x00\u07d4F\xbf\u0172\a\xeb \x13\xe2\xe6\x0fw_\xec\xd7\x18\x10\u0159\f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4F\xc1\xaa\"D\xb9\u0229W\u028f\xacC\x1b\x05\x95\xa3\xb8h$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4F\xd8\x061(B\x03\xf6(\x8e\xcdNWX\xbb\x9dA\xd0]\xbe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\n\xc5\xd1\xf3\xef\xe2\x8f8\x02\xaf\x92[W\x1ec\x86\x8b9}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\x10\x10\xdaI/@\x18\x83;\b\x8d\x98r\x90\x1e\x06\x12\x91t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4G\x12T\x02e\xcb\xee\u00c4p\"\u015f\x1b1\x8dC@\n\x9e\x89\xbd\xbcA\xe04\x8b0\x00\x00\xe0\x94G\x14\u03e4\xf4k\u05bdps}u\x87\x81\x97\xe0\x8f\x88\xe61\x8a\x02\u007f>\u07f3Nn@\x00\x00\u07d4G H\xcc`\x9a\xeb$!e\uaa87\x05\x85\f\xf3\x12]\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4G!\x92)\xe8\xcdVe\x9ae\u00a9C\xe2\u075a\x8fK\xfd\x89\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4G7\xd0B\xdcj\xe7>\xc7:\xe2Qz\u03a2\xfd\xd9d\x87\u014965\u026d\xc5\u07a0\x00\x00\u07d4GAX\xa1\xa9\xdci<\x13?e\xe4{\\:\xe2\xf7s\xa8o\x89\n\xdaUGK\x814\x00\x00\u07d4GE\xab\x18\x1a6\xaa\x8c\xbf\"\x89\xd0\xc4Qe\xbc~\xbe#\x81\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4GPf\xf9\xad&eQ\x96\xd5SS'\xbb\xeb\x9by)\xcb\x04\x89\xa4\xccy\x95c\u00c0\x00\x00\xe0\x94GR!\x8eT\xdeB?\x86\xc0P\x193\x91z\xea\b\xc8\xfe\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4GZa\x93W-JNY\u05fe\t\u02d6\r\u074cS\x0e/\x89$,\xf7\x8c\xdf\a\xff\x80\x00\u07d4Gd\x8b\xed\x01\xf3\xcd2I\bNc]\x14\u06a9\xe7\xec<\x8a\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4Gh\x84\x10\xff%\xd6T\xd7.\xb2\xbc\x06\xe4\xad$\xf83\xb0\x94\x89\b\xb2\x8da\xf3\u04ec\x00\x00\u07d4GkU\x99\b\x9a?\xb6\xf2\x9clr\xe4\x9b.G@\ua00d\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4Gs\x0f_\x8e\xbf\x89\xacr\xef\x80\xe4l\x12\x19P8\xec\xdcI\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94G{$\xee\u80deO\u045d\x12P\xbd\vfEyJa\u028a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4G\x81\xa1\nM\xf5\uef02\xf4\xcf\xe1\a\xba\x1d\x8av@\xbdf\x89a\t=|,m8\x00\x00\u07d4G\x88Z\xba\xbe\xdfM\x92\x8e\x1c\x88\x83\xa6a\x9cl(\x11\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94G\xe2]\xf8\x82%8\xa8Yk(\xc67\x89kM\x14<5\x1d\x8a\x11\v\xe9\xeb$\xb8\x81P\x00\x00\u07d4G\xf4ik\xd4b\xb2\r\xa0\x9f\xb8>\xd2\x03\x98\x18\xd7v%\xb3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4G\xfe\xf5\x85\x84FRH\xa0\x81\r`F>\xe9>Zn\xe8\u04c9\x0fX\xcd>\x12i\x16\x00\x00\u07d4G\xffo\xebC! `\xbb\x15\x03\u05e3\x97\xfc\b\xf4\xe7\x03R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\xff\xf4,g\x85Q\xd1A\xebu\xa6\xee9\x81\x17\xdf>J\x8d\x89\x05k\xea\xe5\x1f\xd2\xd1\x00\x00\u07d4H\x01\x0e\xf3\xb8\xe9^?0\x8f0\xa8\xcb\u007fN\xb4\xbf`\xd9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4H\n\xf5 v\x00\x9c\xa77\x81\xb7\x0eC\xb9Y\x16\xa6\"\x03\xab\x892\x19r\xf4\b=\x87\x80\x00\u07d4H\x0f1\xb9\x891\x1eA$\u01a7F_ZD\tM6\xf9\u04097\x90\xbb\x85Q7d\x00\x00\xe0\x94H\x11\x15)j\xb7\xdbRI/\xf7\xb6G\xd63)\xfb\\\xbck\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4H\x1e:\x91\xbf\xdc/\x1c\x84(\xa0\x11\x9d\x03\xa4\x16\x01A~\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4H(\xe4\xcb\xe3N\x15\x10\xaf\xb7,+\ueb0aE\x13\xea\xeb\u0649\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94H)\x82\xac\x1f\x1cm\x17!\xfe\xec\u0679\xc9l\xd9I\x80PU\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4H0,1\x1e\xf8\xe5\xdcfAX\xddX<\x81\x19Mn\rX\x89\xb6gl\xe0\xbc\xcb\\\x00\x00\u07d4H;\xa9\x904\xe9\x00\xe3\xae\xdfaI\x9d;+\xce9\xbe\xb7\xaa\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4HT\x8bK\xa6+\xcb/\r4\xa8\x8d\u019ah\x0eS\x9c\xf0F\x89\x05l\xf1\u02fbt2\x00\x00\u07d4Hc\x84\x979&Zc\xb0\xa2\xbf#jY\x13\xe6\xf9Y\xce\x15\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4He\x9d\x8f\x8c\x9a/\xd4Oh\u06a5]#\xa6\b\xfb\xe5\x00\u0709lk\x93[\x8b\xbd@\x00\x00\xe0\x94Hf\x9e\xb5\xa8\x01\u0637_\xb6\xaaX\xc3E\x1bpX\xc2C\xbf\x8a\x06\x8dB\xc18\u06b9\xf0\x00\x00\u07d4Hjl\x85\x83\xa8D\x84\xe3\xdfC\xa1#\x83\u007f\x8c~#\x17\u0409\x11\x87\xc5q\xab\x80E\x00\x00\u07d4Hz\xdf}p\xa6t\x0f\x8dQ\xcb\xddh\xbb?\x91\u0125\xceh\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4H~\x10\x85\x02\xb0\xb1\x89\uf70cm\xa4\xd0\xdbba\xee\xc6\xc0\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94H\x88\xfb%\xcdP\u06f9\xe0H\xf4\x1c\xa4}x\xb7\x8a'\xc7\u064a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u0794H\x934\u00b6\x95\xc8\xee\a\x94\xbd\x86B\x17\xfb\x9f\xd8\xf8\xb15\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4H\xa3\r\xe1\xc9\x19\xd3\xfd1\x80\xe9}_+*\x9d\xbd\x96M-\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4H\xbf\x14\u05f1\xfc\x84\xeb\xf3\xc9k\xe1/{\xce\x01\xaai\xb0>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4H\xc2\ue465\aV\xd8\u039a\xbe\xebu\x89\xd2,o\xee]\xfb\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4H\xc5\u0197\v\x91a\xbb\x1c{z\xdf\xed\x9c\xde\u078a\x1b\xa8d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94H\xd2CKz}\xbb\xff\b\";c\x87\xb0]\xa2\xe5\t1&\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4H\xd4\xf2F\x8f\x96?\u05da\x00a\x98\xbbg\x89]-Z\xa4\u04c9K\xe4\xe7&{j\xe0\x00\x00\u07d4H\xe0\xcb\xd6\u007f\x18\xac\xdbzb\x91\xe1%M\xb3.\trs\u007f\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4H\xf6\n5HO\xe7y+\u030a{c\x93\xd0\u0761\xf6\xb7\x17\x89\xc3(\t>a\xee@\x00\x00\u07d4H\xf8\x83\xe5g\xb46\xa2{\xb5\xa3\x12M\xbc\x84\xde\xc7u\xa8\x00\x89)\xd7n\x86\x9d\u0340\x00\x00\xe0\x94I\x01E\xaf\xa8\xb5E\"\xbb!\xf3R\xf0m\xa5\xa7\x88\xfa\x8f\x1d\x8a\x01\xf4lb\x90\x1a\x03\xfb\x00\x00\u07d4I\t\xb3\x19\x98\xea\xd4\x14\xb8\xfb\x0e\x84k\xd5\xcb\xde995\xbe\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x12\xd9\x02\x93\x16v\xff9\xfc4\xfe<<\xc8\xfb!\x82\xfaz\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4I\x13o\xe6\xe2\x8btS\xfc\xb1kk\xbb\u9aac\xba\x837\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94I\x15a\u06cbo\xaf\xb9\x00~b\xd0P\u0082\xe9,Kk\u020a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4I\x18]\xd7\xc262\xf4lu\x94s\ubb96`\b\xcd5\x98\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4I,\xb5\xf8a\xb1\x87\xf9\xdf!\xcdD\x85\xbe\xd9\vP\xff\xe2-\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4I-\xe4j\xaf\x8f\x1dp\x8dY\u05da\xf1\xd0:\xd2\xcb`\x90/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I.p\xf0M\x18@\x8c\xb4\x1e%`70Pk5\xa2\x87k\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4I:g\xfe#\xde\xccc\xb1\r\xdau\xf3(v\x95\xa8\x1b\u056b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4I=H\xbd\xa0\x15\xa9\xbf\xcf\x16\x03\x93n\xabh\x02L\xe5Q\xe0\x89\x018\xa3\x88\xa4<\x00\x00\x00\xe0\x94IBV\xe9\x9b\x0f\x9c\xd6\xe5\xeb\xca8\x99\x862R\x90\x01e\u020a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4IM\xecM^\xe8\x8a'q\xa8\x15\xf1\xeerd\x94/\xb5\x8b(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I[d\x1b\x1c\u07a3b\u00f4\u02fd\x0f\\\xc5\v\x1e\x17k\x9c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ih\xa2\xce\xdbEuU\xa19)Z\xea(wnT\x00<\x87\x8a\x02#\x1a\xef\u0266b\x8f\x00\x00\u07d4Im6U4S\n_\xc1W|\nRA\u02c8\xc4\xdapr\x89a\t=|,m8\x00\x00\xe0\x94In1\x95\x92\xb3A\xea\xcc\xd7x\u0767\xc8\x19mT\xca\xc7u\x8a\x01\xf5q\x89\x87fKH\x00\x00\u07d4IoXC\xf6\xd2L\u064d%^L#\xd1\xe1\xf0#\"uE\x89_\x17\x9f\u0526\xee\t\x80\x00\xe0\x94Ip\u04ec\xf7+[\x1f2\xa7\x00<\xf1\x02\xc6N\xe0TyA\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\u07d4Iw\xa7\x93\x9d\t9h\x94U\xce&9\xd0\xeeZL\xd9\x10\xed\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4Iy\x19N\xc9\xe9}\xb9\xbe\xe84;|w\xd9\xd7\xf3\xf1\u071f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Iy4c\xe1h\x10\x83\u05ab\xd6\xe7%\u057b\xa7E\xdc\xcd\xe8\x89\x1d\x98\xe9LNG\x1f\x00\x00\u07d4I\x81\xc5\xfff\xccN\x96\x80%\x1f\xc4\xcd/\xf9\a\xcb2xe\x89(\xa8WBTf\xf8\x00\x00\u07d4I\x89\u007f\xe92\xbb\xb3\x15L\x95\u04fc\xe6\xd9;ms)\x04\u0749\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x89\xe1\xab^|\xd0\aF\xb3\x93\x8e\xf0\xf0\xd0d\xa2\x02[\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I\x8a\xbd\xeb\x14\xc2k{r4\xd7\x0f\u03ae\xf3a\xa7m\xffr\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4I\xa6E\xe0f}\xfd{2\xd0u\xcc$g\u074ch\t\a\u0109\a\x06\x01\x95\x8f\u02dc\x00\x00\xe0\x94I\xb7N\x16\x92e\xf0\x1a\x89\xecL\x90r\u0164\xcdr\xe4\xe85\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4I\xbd\xbc{\xa5\xab\xeb\xb68\x9e\x91\xa3(R \xd3E\x1b\xd2S\x8965\u026d\xc5\u07a0\x00\x00\u07d4I\xc9A\xe0\xe5\x01\x87&\xb7)\x0f\xc4s\xb4q\xd4\x1d\xae\x80\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94I\xc9w\x1f\xca\x19\u0579\xd2E\u0211\xf8\x15\x8f\xe4\x9fG\xa0b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4I\xcf\x1eT\xbe61\x06\xb9 r\x9d-\v\xa4o\bg\x98\x9a\x89\x0e\x87?D\x13<\xb0\x00\x00\u07d4I\xd2\u008e\xe9\xbcT^\xaa\xf7\xfd\x14\xc2|@s\xb4\xbb_\x1a\x89O\xe9\xb8\x06\xb4\r\xaf\x00\x00\u07d4I\xdd\xee\x90.\x1d\f\x99\u0471\x1a\xf3\u030a\x96\xf7\x8eM\xcf\x1a\x89\n\u03a5\xe4\xc1\x8cS\x00\x00\u07d4I\xf0(9[Z\x86\xc9\xe0\u007fwxc\x0eL.=7:w\x89\x06\xa7JP8\u06d1\x80\x00\xe0\x94J\x19 5\xe2a\x9b$\xb0p\x9dVY\x0e\x91\x83\xcc\xf2\xc1\u064a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4J@S\xb3\x1d\x0e\xe5\u06ef\xb1\xd0k\u05ec\u007f\xf3\",G\u0589K\xe4\xe7&{j\xe0\x00\x00\u07d4JC\x01p\x15-\xe5\x17&3\u0742b\xd1\a\xa0\xaf\xd9j\x0f\x89\xabM\xcf9\x9a:`\x00\x00\u07d4JG\xfc>\x17\u007fVz\x1e8\x93\xe0\x00\xe3k\xba#R\n\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4JR\xba\xd2\x03W\"\x8f\xaa\x1e\x99k\xedy\f\x93gK\xa7\u0409Hz\x9a0E9D\x00\x00\u07d4JS\xdc\xdbV\xceL\xdc\xe9\xf8.\xc0\xeb\x13\xd6sR\xe7\u020b\x89\u3bb5sr@\xa0\x00\x00\u07d4J_\xae;\x03r\xc20\xc1%\xd6\xd4p\x14\x037\xab\x91VV\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4Jq\x90a\xf5(T\x95\xb3{\x9d~\xf8\xa5\x1b\a\xd6\u6b2c\x89\n\xd4\xc81j\v\f\x00\x00\u07d4Js8\x92\x98\x03\x1b\x88\x16\u0329FB\x1c\x19\x9e\x18\xb3C\u0589\"8h\xb8y\x14o\x00\x00\u07d4Js]\"G\x927m3\x13g\xc0\x93\xd3\x1c\x87\x944\x15\x82\x89f\xff\xcb\xfd^Z0\x00\x00\u07d4Jt\x94\xcc\xe4HU\u0300X(B\xbe\x95\x8a\r\x1c\x00r\ue242\x1a\xb0\xd4AI\x80\x00\x00\u07d4Ju\xc3\xd4\xfao\u033d]\u0567\x03\xc1Sy\xa1\xe7\x83\u9dc9b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94J\x81\xab\xe4\x98L|k\xefc\u0598 \xe5WC\xc6\x1f \x1c\x8a\x03d\x01\x00N\x9a\xa3G\x00\x00\u07d4J\x82iO\xa2\x9d\x9e!2\x02\xa1\xa2\t(]\xf6\xe7E\xc2\t\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\x83\\%\x82LG\xec\xbf\u01d49\xbf?\\4\x81\xaau\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4J\x91\x802C\x91Y\xbb1[g%\xb6\x83\r\xc86\x97s\x9f\x89\x12\xa3.\xf6x3L\x00\x00\u07d4J\x97\xe8\xfc\xf4c^\xa7\xfc^\x96\xeeQu.\u00c8qk`\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4J\x9a&\xfd\n\x8b\xa1\x0f\x97}\xa4\xf7|1\x90\x8d\xabJ\x80\x16\x89a\t=|,m8\x00\x00\u07d4J\xa1H\xc2\xc34\x01\xe6j+Xnew\u0132\x92\xd3\xf2@\x89\v\xb8`\xb2\x85\xf7t\x00\x00\u07d4J\xa6\x93\xb1\"\xf3\x14H*G\xb1\x1c\xc7|h\xa4\x97\x87ab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xb2\xd3O\x04\x83O\xbftyd\x9c\xab\x92=,G%\xc5S\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4J\xc0vs\xe4/d\xc1\xa2^\xc2\xfa-\x86\xe5\xaa+4\xe09\x89lk\x93[\x8b\xbd@\x00\x00\u07d4J\u016c\xad\x00\v\x88w!L\xb1\xae\x00\xea\u0263}Y\xa0\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\u0250ZL\xb6\xab\x1c\xfdbTn\xe5\x91s\x00\xb8|O\u07897\b\xba\xed=h\x90\x00\x00\u07d4J\u03e9\xd9N\xdaf%\xc9\u07e5\xf9\xf4\xf5\xd1\a\xc4\x03\x1f\u07c9\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4J\xd0G\xfa\xe6~\xf1b\xfeh\xfe\xdb\xc2};e\xca\xf1\f6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xd9]\x18\x8dddp\x9a\xdd%U\xfbM\x97\xfe\x1e\xbf1\x1f\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4J\xdb\xf4\xaa\xe0\xe3\xefD\xf7\xddM\x89\x85\u03ef\tn\u010e\x98\x89\b!\xab\rD\x14\x98\x00\x00\u07d4J\xe2\xa0M9\t\xefENTL\xcf\xd6\x14\xbf\xef\xa7\x10\x89\xae\x89\x18\x01\x15\x9d\xf1\xee\xf8\x00\x00\xe0\x94J\xe90\x82\xe4Q\x87\xc2a`\xe6g\x92\xf5\u007f\xad5Q\xc7:\x8a\x04\x96\x15 \xda\xff\x82(\x00\x00\u07d4J\xf0\xdb\a{\xb9\xba^D>!\xe1H\xe5\x9f7\x91\x05\u0152\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x06\x19\xd9\u062a1:\x951\xac}\xbe\x04\xca\rjZ\u0476\x89lk\x93[\x8b\xbd@\x00\x00\u07d4K\v\u062c\xfc\xbcS\xa6\x01\v@\xd4\u040d\xdd-\x9dib-\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\x19\xeb\f5K\xc199`\xeb\x06\x06;\x83\x92o\rg\xb2\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4K)C|\x97\xb4\xa8D\xbeq\u0323\xb6H\xd4\xca\x0f\u075b\xa4\x89\b$q\x984\u03ec\x00\x00\u07d4K1\xbfA\xab\xc7\\\x9a\xe2\u034f\u007f5\x16;n+tPT\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4K:|\u00e7\u05f0\x0e\xd5(\"!\xa6\x02Y\xf2[\xf6S\x8a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K:\xab3^\xbb\xfa\xa8p\xccM`^}.t\xc6h6\x9f\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4K\xcd\xc1\x8a`\x00\x00\u07d4K`\xa3\xe2S\xbf8\xc8\xd5f \x10\xbb\x93\xa4s\xc9e\xc3\xe5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Kt\xf5\xe5\x8e.\xdfv\xda\xf7\x01Q\x96J\v\x8f\x1d\xe0f<\x89\x11\x90\xaeID\xba\x12\x00\x00\u07d4Kv!f\xdd\x11\x18\xe8Ci\xf8\x04\xc7_\x9c\xd6W\xbfs\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Ky.)h>\xb5\x86\u353b3Rl`\x01\xb3\x97\x99\x9e\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x90N\x93K\xd0\u030b p_\x87\x9e\x90[\x93\xea\f\xcc0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94K\x92\x06\xbakT\x9a\x1a\u007f\x96\x9e\x1d]\xba\x86u9\xd1\xfag\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4K\x98N\xf2lWn\x81Z.\xae\xd2\xf5\x17\u007f\a\u06f1\xc4v\x89T\x91YV\xc4\t`\x00\x00\u07d4K\x9e\x06\x8f\xc4h\tv\xe6\x15\x04\x91)\x85\xfd\\\xe9K\xab\r\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\xa0\xd9\xe8\x96\x01w+IhG\xa2\xbbC@\x18g\x87\xd2e\x8965\u026d\xc5\u07a0\x00\x00\u07d4K\xa5:\xb5I\xe2\x01m\xfa\"<\x9e\u0563\x8f\xad\x91(\x8d\a\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94K\xa8\xe0\x11\u007f\xc0\xb6\xa3\xe5k$\xa3\xa5\x8f\xe6\xce\xf4B\xff\x98\x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4K\xac\x84j\xf4\x16\x9f\x1d\x95C\x1b4\x1d\x88\x00\xb2!\x80\xaf\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4K\xb6\xd8k\x83\x14\xc2-\x8d7\xeaQm\x00\x19\xf1V\xaa\xe1-\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K\xb9e\\\xfb*6\xea|cz{\x85\x9bJ1T\xe2n\xbe\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94K\xbc\xbf8\xb3\xc9\x01c\xa8K\x1c\u04a9;X\xb2\xa34\x8d\x87\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94K\xd6\xdd\f\xff#@\x0e\x170\xba{\x89E\x04W}\x14\xe7J\x8a+\xa0\xcc\xdd\xd0\xdfs\xb0\x00\x00\u07d4K\xe8b\x8a\x81T\x87N\x04\x8d\x80\xc1B\x18\x10\"\xb1\x80\xbc\xc1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4K\xe9\rA!)\u0564\xd0BCa\xd6d\x9dNG\xa6#\x16\x897\b\xba\xed=h\x90\x00\x00\xe0\x94K\xea(\x8e\xeaB\u0115^\xb9\xfa\xad*\x9f\xafG\x83\xcb\u076c\x8a\x06\x18\xbe\x16c\u012fI\x00\x00\u07d4K\xf4G\x97\x99\xef\x82\xee\xa2\tC7OV\xa1\xbfT\x00\x1e^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4K\xf8\xbf\x1d5\xa211Wd\xfc\x80\x01\x80\x9a\x94\x92\x94\xfcI\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4K\xf8\xe2oL'\x90\xdae3\xa2\xac\x9a\xba\xc3\u019a\x19\x943\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794L\n\xcaP\x8b<\xaf^\xe0(\xbcp}\xd1\xe8\x00\xb88\xf4S\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94L\v\x15\x15\xdf\xce\u05e1>\x13\xee\x12\xc0\xf5#\xaePO\x03+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4L\x13\x98\f2\xdc\xf3\x92\vx\xa4\xa7\x903\x12\x90|\x1b\x12?\x89\x03A\x00\x15\xfa\xae\f\x00\x00\u07d4L\x15y\xaf3\x12\xe4\xf8\x8a\xe9\x95\xcc9W\xd2R\xce\v\xf0\xc8}[O\"4g.p\x89\x87\x86x2n\xac\x90\x00\x00\u07d4LB1y\x82i\x1d\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4LZ\xfe@\xf1\x8f\xfcH\u04e1\xae\xc4\x1f\u009d\xe1y\xf4\u0497\x89lk\x93[\x8b\xbd@\x00\x00\u07d4L[=\xc0\xe2\xb96\x0f\x91(\x9b\x1f\xe1<\xe1,\x0f\xbd\xa3\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lfk\x86\xf1\xc5\ue324\x12\x85\xf5\xbd\xe4\xf7\x90R\b\x14\x06\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Lik\xe9\x9f:i\x04@\xc3CjY\xa7\xd7\xe97\u05ba\r\x89\xbb\x91%T\"c\x90\x00\x00\u07d4Lj$\x8f\xc9}p]\xefI\\\xa2\aY\x16\x9e\xf0\xd3dq\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4Lj\x9d\xc2\u02b1\n\xbb.|\x13p\x06\xf0\x8f\ucd77y\xe1\x89\x1b\r\x04 /G\xec\x00\x00\u07d4Lk\x93\xa3\xbe\xc1cIT\f\xbf\xca\xe9l\x96!\xd6dP\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lu\x98\x13\xad\x13\x86\xbe\xd2\u007f\xfa\xe9\xe4\x81^60\u0323\x12\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Lv\f\xd9\xe1\x95\xeeO-k\xce%\x00\xff\x96\xda|C\ue44a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4Lv{e\xfd\x91\x16\x1fO\xbd\xccji\xe2\xf6\xadq\x1b\xb9\x18\x89'\b\x01\xd9F\xc9@\x00\x00\u07d4L~.+w\xad\f\xd6\xf4J\xcb(a\xf0\xfb\x8b(u\x0e\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4L\x85\xed6/$\xf6\xb9\xf0L\xdf\xcc\xd0\"\xaeSQG\u02f9\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4L\x93[\xb2Pw\x8b0\x9b==\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4L\xee\x90\x1bJ\u0231V\xc5\xe2\xf8\xa6\xf1\xbe\xf5r\xa7\xdc\xeb~\x8965\u026d\xc5\u07a0\x00\x00\u07d4L\xef\xbe#\x98\xe4}R\u73743L\x8bivu\U00053b89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4L\xf5S{\x85\x84/\x89\xcf\xee5\x9e\xaeP\x0f\xc4I\xd2\x11\x8f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94M\bG\x1dh\x00z\xff*\xe2y\xbc^?\xe4\x15o\xbb\xe3\u078a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4M \x01\x10\x12@\b\xd5ov\x98\x12VB\f\x94jo\xf4\\\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4M$\xb7\xacG\xd2\xf2}\xe9\tt\xba=\xe5\xea\xd2\x03TK\u0349\x05k\xc7^-c\x10\x00\x00\u0794M)\xfcR:,\x16)S!!\u0699\x98\u9d6b\x9d\x1bE\x88\xdbD\xe0I\xbb,\x00\x00\u07d4M8\xd9\x0f\x83\xf4Q\\\x03\xccx2j\x15M5\x8b\u0602\xb7\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4ML\xf5\x80t)a^0\xcd\xfa\xce\x1eZ\xaeM\xad0U\xe6\x89 \x86\xac5\x10R`\x00\x00\u07d4MW\xe7\x16\x87l\f\x95\xef^\xae\xbd5\xc8\xf4\x1b\x06\x9bk\xfe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Mg\U000ab159\xfe\xf5\xfcA9\x99\xaa\x01\xfd\u007f\xcep\xb4=\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Mn\x8f\xe1\t\xcc\xd2\x15\x8eM\xb1\x14\x13/\xe7_\xec\u023e[\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94Mq\xa6\xeb=\u007f2~\x184'\x8e(\v\x03\x9e\xdd\xd3\x1c/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4M|\xfa\xa8L\xb31\x06\x80\n\x8c\x80/\xb8\xaaF8\x96\u0159\x89a\t=|,m8\x00\x00\u07d4M\x80\x10\x93\xc1\x9c\xa9\xb8\xf3B\xe3<\xc9\xc7{\xbdL\x83\x12\u03c9\x12\xb3\xe7\xfb\x95\u0364\x80\x00\u07d4M\x82\x88\x94u/o%\x17]\xaf!w\tD\x87\x95Ko\x9f\x89O!+\xc2\u011c\x83\x80\x00\xe0\x94M\x82\xd7p\f\x12;\xb9\x19A\x9b\xba\xf0Fy\x9ck\x0e,f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4M\x83m\x9d;\x0e,\xbdM\xe0PYo\xaaI\f\xff\xb6\r]\x89\x10CV\x1a\x88)0\x00\x00\u07d4M\x86\x97\xaf\x0f\xbf,\xa3n\x87h\xf4\xaf\"\x135phZ`\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\x92y\x96 )\xa8\xbdEc\x977\xe9\x8bQ\x1e\xff\aL!\x89Hz\x9a0E9D\x00\x00\u07d4M\x93io\xa2HY\xf5\u0493\x9a\xeb\xfaT\xb4\xb5\x1a\xe1\xdc\u0309\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4M\x9cw\xd0u\f^o\xbc$\u007f/\u05d2thl\xb3S\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\xa5\xed\u0188\xb0\xcbb\xe1@=\x17\x00\xd9\u0739\x9f\xfe?\u04c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xa8\x03\ai\x84K\xc3A\x86\xb8\\\xd4\xc74\x88I\xffI\xe9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xb1\xc4:\x0f\x83M}\x04x\xb8\x96\ag\xec\x1a\xc4L\x9a\xeb\x89/Q\x810V'7\x00\x00\u07d4M\xb2\x12\x84\xbc\xd4\xf7\x87\xa7Ue\x00\xd6\xd7\xd8\xf3f#\xcf5\x89i(7Ow\xa3c\x00\x00\u07d4M\xc3\xda\x13\xb2\xb4\xaf\xd4O]\r1\x89\xf4D\xd4\xdd\xf9\x1b\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4M\u013f^u\x89\xc4{(7\x8du\x03\u03d6H\x80a\u06fd\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4M\xc9\u057bK\x19\xce\u0354\xf1\x9e\xc2] \x0e\xa7/%\xd7\xed\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xcd\x11\x81X\x18\xae)\xb8]\x016sI\xa8\xa7\xfb\x12\xd0k\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\u07d4M\xcfb\xa3\xde?\x06\x1d\xb9\x14\x98\xfda\x06\x0f\x1fc\x98\xffs\x89lj\xccg\u05f1\xd4\x00\x00\u07d4M\xd11\xc7J\x06\x8a7\xc9\n\xde\xd4\xf3\t\xc2@\x9fdx\u04c9\x15\xaf9\u4ab2t\x00\x00\xe0\x94M\u0767Xk\"7\xb0S\xa7\xf3(\x9c\xf4`\xdcW\xd3z\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xe3\xfe4\xa6\xfb\xf64\xc0Q\x99\u007fG\xcc\u007fHy\x1fX$\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4M\xf1@\xbaye\x85\xddT\x891[\xcaK\xbah\n\u06f8\x18\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4N\x02\ay\xb5\xdd\xd3\xdf\"\x8a\x00\xcbH\xc2\xfc\x97\x9d\xa6\xae8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N\v\xd3$s\xc4\xc5\x1b\xf2VT\xde\xf6\x9fy|k)\xa22\x89V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4N\"%\xa1\xbbY\xbc\x88\xa21ft\xd33\xb9\xb0\xaf\xcafU\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4N#\x10\x19\x1e\xad\x8d;\xc6H\x98s\xa5\xf0\xc2\xeck\x87\u1f8965\u026d\xc5\u07a0\x00\x00\u07d4N#-S\xb3\u6f8f\x89Sa\xd3\x1c4\xd4v+\x12\xc8.\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4N+\xfaJFo\x82g\x1b\x80\x0e\xeeBj\xd0\f\a\x1b\xa1p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4N>\xda\u0506M\xabd\xca\xe4\xc5Azvw@S\xdcd2\x89 \b\xfbG\x8c\xbf\xa9\x80\x00\u07d4NC\x18\xf5\xe1>\x82JT\xed\xfe0\xa7\xedO&\xcd=\xa5\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N[w\xf9\x06aY\xe6\x15\x93?-\xdatw\xfaNG\xd6H\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94Nf\x00\x80b\x89EJ\u03630\xa2\xa3U`\x10\u07ec\xad\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Ns\xcf#y\xf1$\x86\x0fs\xd6\xd9\x1b\xf5\x9a\xcc\\\xfc\x84[\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94Nz\xa6~\x12\x18>\xf9\xd7F\x8e\xa2\x8a\xd29\xc2\xee\xf7\x1bv\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94N{TGM\x01\xfe\xfd8\x8d\xfc\xd5;\x9ff&$A\x8a\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94N\x89.\x80\x81\xbf6\xe4\x88\xfd\xdb;&0\xf3\xf1\xe8\xda0\u048a\x02\x8a\xba0u$Q\xfc\x00\x00\xe0\x94N\x8amcH\x9c\xcc\x10\xa5\u007f\x88_\x96\xeb\x04\xec\xbbT`$\x8a\x03\xea\xe3\x13\x0e\u0316\x90\x00\x00\u07d4N\x8eG\xae;\x1e\xf5\f\x9dT\xa3\x8e\x14 \x8c\x1a\xbd6\x03\u0089y(\xdb\x12vf\f\x00\x00\u0794N\x90\u03312X\xac\xaa\x9fO\xeb\xc0\xa3B\x92\xf9Y\x91\xe20\x88\xdbD\xe0I\xbb,\x00\x00\u07d4N\xa5n\x11\x12d\x1c\x03\x8d\x05e\xa9\u0096\xc4c\xaf\xef\xc1~\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94N\xa7\x0f\x041?\xaee\xc3\xff\"J\x05\\=-\xab(\xdd\u07ca\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4N\xb1EKW8\x05\u022c\xa3~\xde\xc7\x14\x9aA\xf6\x12\x02\xf4\x89\x10CV\x1a\x88)0\x00\x00\u07d4N\xb8{\xa8x\x8e\xba\r\xf8~[\x9b\xd5\n\x8eE6\x80\x91\xc1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4N\xbcV)\xf9\xa6\xa6k,\xf36:\u0109\\\x03H\u8fc7\x8967\tlK\xcci\x00\x00\u07d4N\xc7h)^\xea\xba\xfcB\x95\x84\x15\xe2+\xe2\x16\xcd\xe7v\x18\x89\x03;\x1d\xbc9\xc5H\x00\x00\u07d4N\xcc\x19\x94\x8d\xd9\u0347\xb4\xc7 \x1a\xb4\x8eu\x8f(\xe7\xccv\x89\x1b\x1d\xaba\u04ead\x00\x00\u07d4N\xd1M\x81\xb6\v#\xfb%\x05M\x89%\u07e5s\u072eah\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94N\xe1<\rA \vF\u045d\xee\\K\xce\xc7\x1d\x82\xbb\x8e8\x8a\x01\xab\xee\x13\u033e\ufbc0\x00\u07d4N\xea\xd4\n\xad\x8cs\xef\b\xfc\x84\xbc\n\x92\xc9\t/j6\xbf\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4N\xeb\xe8\f\xb6\xf3\xaeY\x04\xf6\xf4\xb2\x8d\x90\u007f\x90q\x89\xfc\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4N\xeb\xf1 ]\f\xc2\f\xeel\u007f\x8f\xf3\x11_V\u050f\xba&\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4N\xf1\xc2\x14c:\xd9\xc0p;N#t\xa2\xe3>>B\x92\x91\x89Hz\x9a0E9D\x00\x00\u07d4N\xfc\xd9\u01df\xb43L\xa6${\n3\xbd\x9c\xc32\b\xe2r\x89Hz\x9a0E9D\x00\x00\xe0\x94O\x06$k\x8dK\u0496a\xf4>\x93v\"\x01\u0486\x93Z\xb1\x8a\x01\x059O\xfcF6\x11\x00\x00\u07d4O\x15+/\xb8e\x9dCwn\xbb\x1e\x81g:\xa8Ai\xbe\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4O\x17\u007f\x9dV\x95=\xedq\xa5a\x1f93\"\xc3\x02y\x89\\\x89\rU\uf422\xda\x18\x00\x00\u07d4O\x1a-\xa5JLm\xa1\x9d\x14$\x12\xe5n\x81WA\xdb#%\x89\x05k\xc7^-c\x10\x00\x00\u07d4O#\xb6\xb8\x17\xff\xa5\xc6d\xac\xda\u05db\xb7\xb7&\xd3\n\xf0\xf9\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94O&i\f\x99+z1*\xb1.\x13\x85\xd9J\xcdX(\x8e{\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4O+G\xe2wZ\x1f\xa7\x17\x8d\xad\x92\x98Z[\xbeI;\xa6\u0589\n\u05ce\xbcZ\xc6 \x00\x00\u07d4O:HT\x91\x11E\xea\x01\xc6D\x04K\xdb.Z\x96\n\x98/\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4O?,g0i\xac\x97\xc2\x026\a\x15)\x81\xf5\xcd`c\xa0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94OJ\x9b\xe1\f\xd5\xd3\xfb]\xe4\x8c\x17\xbe)o\x89V\x90d[\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4OR\xadap\xd2[*.\x85\x0e\xad\xbbRA?\xf20>\u007f\x89\xa4\xccy\x95c\u00c0\x00\x00\u07d4OX\x01\xb1\xeb0\xb7\x12\u0620WZ\x9aq\xff\x96]O4\xeb\x89\x10CV\x1a\x88)0\x00\x00\u07d4O]\xf5\xb9CW\u0794\x86\x04\xc5\x1bx\x93\xcd\xdf`v\xba\xad\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4Od\xa8^\x8e\x9a@I\x8c\fu\xfc\xeb\x037\xfbI\b>^\x8965\u026d\xc5\u07a0\x00\x00\u07d4Og9m%S\xf9\x98x_pN\a\xa69\x19}\u0454\x8d\x89\x10DrR\x1b\xa78\x00\x00\u07d4OmG7\u05e9@8$\x87&H\x86i|\xf7c\u007f\x80\x15\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4Os0\toy\xed&N\xe0\x12\u007f]0\xd2\xf7?!\xcb\u007f\x04\x89\x04\x82\xfe&\f\xbc\xa9\x00\x00\u07d4O\xeeP\xc5\xf9\x88 k\t\xa5sF\x9f\xb1\u0434.\xbbm\u0389l\xee\x06\u077e\x15\xec\x00\x00\u07d4O\xf6v\xe2\u007fh\x1a\x98-\x8f\xd9\xd2\x0ed\x8b=\xce\x05\xe9E\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4O\xf6\u007f\xb8\u007fn\xfb\xa9'\x990\u03fd\x1bz4L\u057a\x8bN\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94PFf\u03891\x17^\x11\xa5\xed\x11\xc1\u072a\x06\xe5\u007fNf\x8a\x02\u007f>\u07f3Nn@\x00\x00\u0794PXM\x92\x06\xa4l\xe1\\0\x11\x17\xee(\xf1\\0\xe6\x0eu\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94PZ3\xa1\x864\xddH\x00i)\x13N\x00\x00\u07d4P\u0286\xb5\xeb\x1d\x01\x87M\xf8\xe5\xf3IE\u051cl\x1a\xb8H\x8965\u026d\xc5\u07a0\x00\x00\u07d4P\u0357\xe97\x8b\\\xf1\x8f\x179c#l\x99Q\xeft8\xa5\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4P\u073c'\xbc\xad\x98@\x93\xa2\x12\xa9\xb4\x17\x8e\xab\xe9\x01ua\x89\a\xe3by\v\\\xa4\x00\x00\u07d4P\xe10#\xbd\x9c\xa9j\xd4\xc5?\xdf\xd4\x10\xcbk\x1fB\v\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94P\xe1\xc8\xec\x98A[\xefD&\x18p\x87\x99C{\x86\xe6\xc2\x05\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4P\xf8\xfaK\xb9\xe2g|\x99\nN\xe8\xcep\xdd\x15#%\x1eO\x89\x01i=#\x16Ok\x00\x00\u07d4P\xfb6\xc2q\a\xee,\xa9\xa3#n'F\u0321\x9a\xcekI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4P\xfe\xf2\x96\x95U\x88\u02aet\xc6.\xc3*#\xa4T\xe0\x9a\xb8\x89A\x1d\xff\xab\xc5\a8\x00\x00\u07d4Q\x02\xa4\xa4 w\xe1\x1cX\xdfGs\u3b14F#\xa6m\x9f\x89lp\x15\xfdR\xed@\x80\x00\u07d4Q\x03\x93w\xee\xd0\xc5s\xf9\x86\xc5\xe8\xa9_\xb9\x9aY\xe93\x0f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Q\x03\xbc\t\x93>\x99!\xfdS\xdcSo\x11\xf0]\rG\x10}\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94Q\x04\xec\xc0\xe30\xdd\x1f\x81\xb5\x8a\xc9\u06f1\xa9\xfb\xf8\x8a<\x85\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4Q\r\x81Y\u0314Wh\xc7E\a\x90\xba\a>\xc0\xd9\xf8\x9e0\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u07d4Q\x0e\xdaV\x01I\x9a\r^\x1a\x00k\xff\xfd\x836r\xf2\xe2g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x12dF\xab=\x802U~\x8e\xbaeY}u\xfa\u0701\\\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94Q\x18U}`\r\x05\xc2\xfc\xbf8\x06\xff\xbd\x93\xd0 %\xd70\x8a\x02g\u04ebd#\xf5\x80\x00\x00\u07d4Q\x1e\x0e\xfb\x04\xacN?\xf2\xe6U\x0eI\x82\x95\xbf\xcdV\xff\u0549$=M\x18\"\x9c\xa2\x00\x00\u07d4Q!\x16\x81{\xa9\xaa\xf8C\xd1P|e\xa5\xead\n{\x9e\xec\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4Q&F\ri,q\u026fo\x05WM\x93\x99\x83h\xa27\x99\x89\x02\u0465\x1c~\x00P\x00\x00\u07d4Q'\u007f\xe7\xc8\x1e\xeb\xd2R\xa0=\xf6\x9ak\x9f2n'\"\a\x89\x03@.y\u02b4L\x80\x00\u07d4Q)oPD'\r\x17pvF\x12\x9c\x86\xaa\xd1d^\xad\xc1\x89H|r\xb3\x10\xd4d\x80\x00\xe0\x94Q+\x91\xbb\xfa\xa9\xe5\x81\xefh?\xc9\r\x9d\xb2*\x8fI\xf4\x8b\x8aA\xa5\"8m\x9b\x95\xc0\x00\x00\u07d4Q5\xfb\x87W`\f\xf4tTbR\xf7M\xc0tm\x06&,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4QF2\xef\xbdd,\x04\xdel\xa3B1]@\u0750\xa2\u06e6\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4QKu\x12\u026e^\xa6<\xbf\x11q[c\xf2\x1e\x18\u0496\xc1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4QS\xa0\xc3\u0211(\x81\xbf\x1c5\x01\xbfd\xb4VI\xe4\x82\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94QVQ\xd6\xdbO\xaf\x9e\xcd\x10:\x92\x1b\xbb\xbej\xe9p\xfd\u050a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94Q_0\xbc\x90\xcd\xf4W~\xe4}e\u05c5\xfb\xe2\xe87\u01bc\x8a\x02'\x1b^\x01\x8b\xa0X\x00\x00\u07d4Q`\xeda.\x1bH\xe7??\xc1[\xc42\x1b\x8f#\xb8\xa2K\x89\x1e\x82kB(e\xd8\x00\x00\u07d4Qa\xfdI\xe8G\xf6tU\xf1\u023bz\xbb6\xe9\x85&\r\x03\x89A\rXj \xa4\xc0\x00\x00\u07d4QiT\x02_\xca&\b\xf4}\xa8\x1c!^\xed\xfd\x84J\t\xff\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4Qi\xc6\n\xeeL\xee\u0444\x9a\xb3mfL\xff\x97\x06\x1e\x8e\xa8\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4Q|uC\r\xe4\x01\xc3A\x03&\x86\x11'\x90\xf4mM6\x9e\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4Q|\xd7`\x8e]\r\x83\xa2kq\u007f6\x03\xda\xc2'}\u00e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x86]\xb1H\x88\x19Q\xf5\x12Qq\x0e\x82\xb9\xbe\r~\xad\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x89\x1b,\xcd\xd2\xf5\xa4K*\x8b\u011a]\x9b\xcadw%\x1c\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4Q\x8c\xef'\xb1\x05\x82\xb6\xd1OiH=\u06a0\xdd<\x87\xbb\\\x89 \x86\xac5\x10R`\x00\x00\u07d4Q\xa6\xd6'\xf6j\x89#\u060d`\x94\xc4qS\x80\xd3\x05|\xb6\x89>s\xd2z5\x94\x1e\x00\x00\u07d4Q\xa8\xc2\x166\x02\xa3.\xe2L\xf4\xaa\x97\xfd\x9e\xa4\x14QiA\x89\x03h\xf7\xe6\xb8g,\x00\x00\u07d4Q\xb4u\x8e\x9e\x14P\xe7\xafBh\xc3\u01f1\xe7\xbdo\\uP\x8965\u026d\xc5\u07a0\x00\x00\u07d4Q\u028b\xd4\xdcdO\xacG\xafgUc\u0540J\r\xa2\x1e\xeb\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4Q\xd2K\xc3so\x88\xddc\xb7\" &\x88f0\xb6\ub1cd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\u05cb\x17\x8dp~9n\x87\x10\x96\\OA\xb1\xa1\xd9\x17\x9d\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\u07d4Q\xe3/\x14\xf4\xca^(|\xda\xc0W\xa7y^\xa9\xe0C\x99S\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Q\xe4?\xe0\xd2\\x(`\xaf\x81\xea\x89\xddy<\x13\xf0\u02f1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4Q\xe7\xb5\\/\x98 \xee\xd78\x846\x1bPf\xa5\x9boE\u0189lk\x93[\x8b\xbd@\x00\x00\xe0\x94Q\xea\x1c\t4\xe3\xd0@\"\ud715\xa0\x87\xa1P\xefp^\x81\x8a\x01Tp\x81\xe7\"M \x00\x00\u07d4Q\xee\f\xca;\xcb\x10\xcd>\x987\"\xce\xd8I=\x92l\bf\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94Q\xf4f:\xb4O\xf7\x93E\xf4'\xa0\xf6\xf8\xa6\u0225?\xf24\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Q\xf5^\xf4~dV\xa4\x18\xab2\xb9\"\x1e\xd2}\xbaf\b\xee\x89\u3bb5sr@\xa0\x00\x00\xe0\x94Q\xf9\xc42\xa4\xe5\x9a\xc8b\x82\u05ad\xabL.\xb8\x91\x91`\xeb\x8ap;[\x89\u00e6\xe7@\x00\x00\u07d4R\x0ff\xa0\xe2e\u007f\xf0\xacA\x95\xf2\xf0d\xcf/\xa4\xb2BP\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4R\x10#T\xa6\xac\xa9]\x8a.\x86\xd5\u07bd\xa6\xdei4`v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\x13\xf4Y\xe0x\xad:\xb9Z\t #\x9f\xcf\x163\xdc\x04\u0289\x8c\xf2\x18|*\xfb\x18\x80\x00\u07d4R\x15\x18;\x8f\x80\xa9\xbc\x03\xd2l\xe9\x12\a\x83*\r9\xe6 \x8965\u026d\xc5\u07a0\x00\x00\xe0\x94R!Cx\xb5@\x04\x05j|\xc0\x8c\x89\x13'y\x8a\u01b2H\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\xe0\x94R##\xaa\xd7\x1d\xbc\x96\xd8Z\xf9\x0f\bK\x99\xc3\xf0\x9d\ucdca\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4R>\x14\r\xc8\x11\xb1\x86\xde\xe5\xd6\u020b\xf6\x8e\x90\xb8\xe0\x96\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R?mdi\x0f\xda\u0354(SY\x1b\xb0\xff \xd3em\x95\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4RO\xb2\x10R,^#\xbbg\u07ff\x8c&\xaaam\xa4\x99U\x8965b\xa6m4#\x80\x00\u07d4RU\xdci\x15ZE\xb9p\xc6\x04\xd3\x00G\xe2\xf50i\x0e\u007f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R`\xdcQ\xee\a\xbd\u06ab\xab\xb9\xeetK9<\u007fG\x93\xa6\x89\x01\xd8f_\xa5\xfaL\x00\x00\u07d4Rg\xf4\xd4\x12\x92\xf3p\x86<\x90\u05d3)i\x03\x846%\u01c9K\xe4\xe7&{j\xe0\x00\x00\u07d4Rk\xb53\xb7n \xc8\xee\x1e\xbf\x12?\x1e\x9f\xf4\x14\x8e@\xbe\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Rl\xb0\x9c\u3b63g.\xec\x1d\xebF [\xe8\x9aKV>\x89\x85\xcaa[\xf9\xc0\x10\x00\x00\u07d4Rs\x8c\x90\xd8`\xe0L\xb1/I\x8d\x96\xfd\xb5\xbf6\xfc4\x0e\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4Rz\x8c\xa1&\x863\xa6\xc99\xc5\xde\x1b\x92\x9a\ue4ae\xac\x8d\x890\xca\x02O\x98{\x90\x00\x00\u07d4R\x81\x01\xceF\xb7 \xa2!M\u036ef\x18\xa51w\xff\xa3w\x89\x1b\x96\x12\xb9\xdc\x01\xae\x00\x00\xe0\x94R\x81s4s\xe0\r\x87\xf1\x1e\x99U\u5275\x9fJ\u008ez\x8a\x8b\xd6/\xf4\xee\xc5Y \x00\x00\u07d4R\x98\xab\x18*\x195\x9f\xfc\xec\xaf\xd7\u0475\xfa!-\xed\xe6\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R\x9a\xa0\x02\u0196*:\x85E\x02\u007f\u0630_\"\xb5\xbf\x95d\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4R\x9e\x82O\xa0rX+@2h:\xc7\xee\xcc\x1c\x04\xb4\xca\xc1\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94R\xa5\xe4\xdeC\x93\xee\xcc\xf0X\x1a\xc1\x1bR\u0183\xc7n\xa1]\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4R\xb4%|\xf4\x1bn(\x87\x8dP\xd5{\x99\x91O\xfa\x89\x87:\x89\xd5\r\u026a,Aw\x00\x00\u07d4R\xb8\xa9Y&4\xf70\v|\\Y\xa34[\x83_\x01\xb9\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xbd\u066fYx\x85\v\xc2A\x10q\x8b7#u\x9bC~Y\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4R\xcd @;\xa7\xed\xa6\xbc0z=c\xb5\x91\x1b\x81|\x12c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794R\u04c0Q\x1d\xf1\x9d^\u0080{\xbc\xb6vX\x1bg\xfd7\xa3\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94R\xe1s\x13P\xf9\x83\xcc,A\x89\x84/\xde\x06\x13\xfa\xd5\f\xe1\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4R\xe4g\x832\x9av\x93\x01\xb1u\x00\x9d4gh\xf4\xc8~\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xf0X\xd4aG\xe9\x00m)\xbf,\t0J\xd1\xcd\xddn\x15\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4R\xf1T#2<$\xf1\x9a\xe2\xabg7\x17\"\x9d?t}\x9b\x897\xa04\xcb\xe8\xe3\xf3\x80\x00\u07d4R\xf8\xb5\t\xfe\xe1\xa8t\xabo\x9d\x876\u007f\xbe\xaf\x15\xac\x13\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4R\xfbF\xac]\x00\xc3Q\x8b,:\x1c\x17}D/\x81eU_\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4S\x00w\xc9\xf7\xb9\a\xff\x9c\xec\fw\xa4\x1ap\xe9\x02\x9a\xddJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x03\x19\xdb\n\x8f\x93\xe5\xbb}M\xbfH\x161O\xbe\xd86\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x04}\u022c\x90\x83\xd9\x06r\xe8\xb3G<\x10\f\xcd'\x83#\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4S\va\xe4/9Bm$\b\xd4\bR\xb9\xe3J\xb5\xeb\xeb\u0149\x0e~\xeb\xa3A\vt\x00\x00\u07d4S\x0f\xfa\u00fc4\x12\xe2\xec\x0e\xa4{y\x81\xc7p\xf5\xbb/5\x89\a?u\u0460\x85\xba\x00\x00\u07d4S\x17\xec\xb0#\x05,\xa7\xf5e+\xe2\xfa\x85L\xfeEc\xdfM\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4S\x19M\x8a\xfa>\x885\x02v~\xdb\xc3\x05\x86\xaf3\xb1\x14\u04c9lk\x93[\x8b\xbd@\x00\x00\u07d4S*}\xa0\xa5\xadt\aF\x8d;\xe8\xe0~i\xc7\xddd\xe8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4S-2\xb0\x0f0[\xcc$\xdc\xefV\x81}b/4\xfb,$\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4S4DX@\x82\xeb\xa6T\xe1\xad0\xe1Is\\o{\xa9\"\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4S8\xefp\xea\xc9\u075a\xf5\xa0P;^\xfa\xd1\x03\x9eg\xe7%\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94S9oJ&\u00b4`D\x960lTB\xe7\xfc\xba'.6\x8a\x04?/\b\xd4\x0eZ\xfc\x00\x00\xe0\x94S:s\xa4\xa2\"\x8e\xee\x05\xc4\xff\xd7\x18\xbb\xf3\xf9\xc1\xb1)\xa7\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4S<\x06\x92\x8f\x19\u0429V\xcc(\x86k\xf6\xc8\xd8\xf4\x19\x1a\x94\x89\x0f\xd8\xc1C8\xe60\x00\x00\u07d4S@e6\x1c\xb8T\xfa\xc4+\xfb\\\x9f\xcd\xe0`J\xc9\x19\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4SC\u007f\xec\xf3J\xb9\xd45\xf4\u07b8\xca\x18\x15\x19\xe2Y 5\x89\n1\x06+\xee\xedp\x00\x00\u07d4SR\x01\xa0\xa1\xd74\"\x80\x1fU\xde\xd4\u07ee\xe4\xfb\xaan;\x89\x02&!\x1fy\x15B\x80\x00\xe0\x94S`\x81\x05\xceK\x9e\x11\xf8k\xf4\x97\xff\xca;x\x96{_\x96\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4SnM\x80)\xb7?Uy\u0723>p\xb2N\xba\x89\xe1\x1d~\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Sp\rS%MC\x0f\"x\x1aJv\xa4c\x93;]k\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94S\u007f\x9dM1\xefp\x83\x9d\x84\xb0\xd9\u0377+\x9a\xfe\xdb\xdf5\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\xe0\x94S\x81D\x85\x03\xc0\xc7\x02T+\x1d\xe7\xcc_\xb5\xf6\xab\x1c\xf6\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94S\x94.yI\xd6x\x8b\xb7\x80\xa7\xe8\xa0y'\x81\xb1aK\x84\x8a\x03]\xebFhO\x10\xc8\x00\x00\u07d4S\x95\xa4E]\x95\xd1x\xb4S*\xa4r[\x19?\xfeQ)a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94S\x98\x9e\xd30V?\xd5}\xfe\u027d4<7`\xb0y\x93\x90\x8a\x01P\x89N\x84\x9b9\x00\x00\x00\u07d4S\xa2Dg(\x95H\x0fJ+\x1c\xdf}\xa5\xe5\xa2B\xecM\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4S\xa7\x14\xf9\x9f\xa0\x0f\xefu\x8e#\xa2\xe7F2m\xad$|\xa7\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4S\xaf2\xc2/\uf640?\x17\x8c\xf9\v\x80/\xb5q\xc6\x1c\xb9\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4S\xc0\xbb\u007f\u020e\xa4\"\xd2\xef~T\x0e-\x8f(\xb1\xbb\x81\x83\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94S\xc5\xfe\x01\x19\xe1\xe8Hd\f\xee0\xad\ua594\x0f*]\x8b\x8a\x04\x9a\xda_\xa8\xc1\f\x88\x00\x00\u07d4S\xc9\xec\xa4\ts\xf6;\xb5\x92{\xe0\xbcj\x8a\x8b\xe1\x95\x1ft\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\u0388\xe6lZ\xf2\U0009bf4fY*V\xa3\xd1_ l2\x89\a\xa2\x8c1\xcc6\x04\x00\x00\u07d4S\xce\xc6\u0200\x92\xf7V\xef\xe5o}\xb1\x12(\xa2\xdbE\xb1\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4S\xe3[\x12#\x1f\x19\xc3\xfdwL\x88\xfe\xc8\xcb\xee\xdf\x14\b\xb2\x89\x1b\xc1mgN\xc8\x00\x00\x00\u07d4S\xe4\xd9im\xcb?M{?p\u072aN\xec\xb7\x17\x82\xff\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4S\xfa\xf1e\xbe\x03\x1e\xc1\x830\xd9\xfc\xe5\xbd\x12\x81\xa1\xaf\b\u06c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4T\n\x18\x19\xbd|5\x86\x1ey\x18\x04\xe5\xfb\xb3\xbc\x97\u026b\xb1\x89N\xd7\xda\xc6B0 \x00\x00\xe0\x94T\f\a(\x02\x01N\xf0\xd5a4Z\xecH\x1e\x8e\x11\xcb5p\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94T\f\xf2=\xd9\\MU\x8a'\x9dw\x8d+75\xb3\x16A\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\x10`\xfcX\xc7P\xc4\x05\x12\xf83i\xc0\xa63@\xc1\"\xb6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\x13\xc9\u007f\xfaJn*{\xba\x89a\u071f\u03850\xa7\x87\u05c965\u026d\xc5\u07a0\x00\x00\u07d4T\x1d\xb2\n\x80\xcf;\x17\xf1b\x1f\x1b?\xf7\x9b\x88/P\xde\xf3\x8965\u026d\xc5\u07a0\x00\x00\u07d4T.\x80\x96\xba\xfb\x88\x16&\x06\x00.\x8c\x8a>\u0458\x14\xae\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\v:\xa8\x87\x03\xa7%\u07e5}\xe6\xe6F\x93Qd\x80,\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4T1\xb1\u0447Q\xb9\x8f\xc9\u220a\xc7u\x9f\x155\xa2\xdbG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\xcaB~ae\xa6D\xba\xe3&\xbd\tu\n\x17\x8ce\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T5\xc6\xc1y3\x17\xd3,\xe1;\xbaLO\xfe\xb9s\xb7\x8a\u0709\r\x8ek\x1c\x12\x85\xef\x00\x00\xe0\x94T6)\xc9\\\xde\xf4(\xad7\xd4S\u02958\xa9\xf9\t\x00\xac\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4T9\x1bM\x17mGl\xea\x16N_\xb55\u0197\x00\xcb%5\x89\x05l\xd5_\xc6M\xfe\x00\x00\xe0\x94T:\x8c\x0e\xfb\x8b\xcd\x15\xc5C\u29a4\xf8\aYv1\xad\xef\x8a\x01?\x80\xe7\xe1O-D\x00\x00\u07d4T?\x8cgN$b\xd8\xd5\u06a0\xe8\x01\x95\xa8p\x8e\x11\xa2\x9e\x89\x03wX\x83;:z\x00\x00\xe0\x94TK[5\x1d\x1b\xc8.\x92\x97C\x99H\xcfHa\xda\u026e\x11\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4TM\xdaB\x1d\xc1\xebs\xbb$\xe3\xe5j$\x80\x13\xb8|\x0fD\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4TW\\1\x14u\x1e\x14o\xfe\u00c7nE\xf2\x0e\xe8AJ\u07ba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\xb4B\x9b\x18/\x03w\xbe~bi9\xc5\xdbd@\xf7]z\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\xbc\xb8\xe7\xf7<\xda=s\xf4\u04cb-\bG\xe6\x00\xba\r\xf8\x89:pAX\x82\xdf\x18\x00\x00\u07d4T\xc9>\x03\xa9\xb2\xe8\xe4\xc3g(5\xa9\xeev\xf9a[\xc1N\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4T\u0388'YV\xde\xf5\xf9E\x8e;\x95\xde\xca\xcdH@!\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T\xdb^\x06\xb4\x81]1\xcbV\xa8q\x9b\xa3:\xf2\xd7>rR\x89$R\x1e*0\x17\xb8\x00\x00\xe0\x94T\xe0\x12\x83\u030b8E8\xdddgp\xb3W\xc9`\xd6\xca\u034a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4T\xecs\x00\xb8\x1a\xc8C3\xed\x1b\x03<\xd5\u05e39r\xe24\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4T\xfe\xbc\xce \xfez\x90\x98\xa7U\xbd\x90\x98\x86\x02\xa4\x8c\b\x9e\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4U\n\xad\xae\x12!\xb0z\xfe\xa3\x9f\xba.\xd6.\x05\u5df5\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4U\f0o\x81\xef]\x95\x80\xc0l\xb1\xab \x1b\x95\xc7H\xa6\x91\x89$\x17\xd4\xc4p\xbf\x14\x00\x00\xe0\x94U\x19\x99\xdd\xd2\x05V3'\xb9\xb50xZ\xcf\xf9\xbcs\xa4\xba\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4U\x1ew\x84w\x8e\xf8\xe0H\xe4\x95\xdfI\xf2aO\x84\xa4\xf1\u0709 \x86\xac5\x10R`\x00\x00\xe0\x94U)\x83\na\xc1\xf1<\x19~U\v\xed\xdf\u05bd\x19\\\x9d\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U)\x87\xf0e\x1b\x91[.\x1eS(\xc1!\x96\rK\xddj\xf4\x89a\t=|,m8\x00\x00\u07d4U;k\x1cW\x05\x0e\x88\xcf\f1\x06{\x8dL\xd1\xff\x80\xcb\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U?7\xd9$fU\x0e\x9f\xd7u\xaet6-\xf00\x17\x912\x89lk\x93[\x8b\xbd@\x00\x00\u07d4UC6\xeeN\xa1U\xf9\xf2O\x87\xbc\xa9\xcar\xe2S\xe1,\u0489\x05k\xc7^-c\x10\x00\x00\u0794UC\xddm\x16\x9e\xec\x8a!;\xbfz\x8a\xf9\xff\xd1]O\xf7Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4UG\xfd\xb4\xae\x11\x95>\x01)+x\a\xfa\x92#\xd0\xe4`j\x89\x05]\x11}\xcb\x1d&\x00\x00\u07d4UR\xf4\xb3\xed>\x1d\xa7\x9a/x\xbb\x13\xe8\xaeZh\xa9\xdf;\x8965\u026d\xc5\u07a0\x00\x00\u07d4U\\\xa9\xf0\\\xc14\xabT\xae\x9b\xea\x1c?\xf8z\xa8Q\x98\u0289\x05k\xc7^-c\x10\x00\x00\xe0\x94U]\x8d<\xe1y\x8a\u0290'T\xf1d\xb8\xbe*\x022\x9cl\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U]\xf1\x93\x90\xc1m\x01)\x87r\xba\xe8\xbc:\x11R\x19\x9c\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U^\xbe\x84\u06a4+\xa2V\xeax\x91\x05\xce\u0136\x93\xf1/\x18\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94U\u007f^e\xe0\xda3\x99\x82\x19\xadN\x99W\x05E\xb2\xa9\xd5\x11\x8a\x02U\x9c\xbb\x98XB@\x00\x00\u07d4U\x83` h\x83\xdd\x1bmJYc\x9eV)\xd0\xf0\xc6u\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4U\x84B0P\xe3\xc2\x05\x1f\v\xbd\x8fD\xbdm\xbc'\xec\xb6,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4U\x85)CI)p\xf8\xd6)\xa1Sf\xcd\xda\x06\xa9OE\x13\x89lk\x93[\x8b\xbd@\x00\x00\u0794U\x86d\x86\xec\x16\x8fy\xdb\xe0\u1af1\x88d\u0649\x91\xae,\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4U\x8cTd\x9a\x8an\x94r+\xd6\xd2\x1d\x14qOqx\x054\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\x91\x940O\x14\xb1\xb9:\xfeDO\x06$\xe0S\xc2:\x00\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U\x93\xc9\u0536ds\x0f\xd9<\xa6\x01Q\xc2\\.\xae\xd9<;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U\x97\x06\xc32\xd2\ay\xc4_\x8am\x04ji\x91Y\xb7I!\x89\x14\x9bD.\x85\xa3\u03c0\x00\u07d4U\x98\xb3\xa7\x9aH\xf3+\x1f_\xc9\x15\xb8{d]\x80]\x1a\xfe\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4U\xa3\xdfW\xb7\xaa\xec\x16\xa1b\xfdS\x16\xf3[\xec\b(!\u03c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa4\xca\xc0\u02cbX-\x9f\xef8\xc5\xc9\xff\xf9\xbdS\t=\x1f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa6\x1b\x10\x94\x80\xb5\xb2\xc4\xfc\xfd\xef\x92\xd9\x05\x84\x16\f\r5\x89\x02lVM+S\xf6\x00\x00\u07d4U\xaa]1>\xbb\bM\xa0\xe7\x80\x10\x91\u2792\xc5\xde\u00ea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xab\x99\xb0\xe0\xe5]{\xb8t\xb7\xcf\xe84\xdec\x1c\x97\xec#\x897\xe9\x8c\xe3h\x99\xe4\x00\x00\u07d4U\xaf\t/\x94\xbajy\x91\x8b\f\xf99\xea\xb3\xf0\x1b?Q\u01c9\b \xd5\xe3\x95v\x12\x00\x00\u07d4U\xc5dfAf\xa1\xed\xf3\x91>\x01i\xf1\xcdE\x1f\xdb]\f\x89\x82\x17\xeaIP\x8el\x00\x00\xe0\x94U\xcaj\xbey\xea$\x97\xf4o\u06f804`\x10\xfeF\x9c\xbe\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4U\xca\xffK\xba\x04\xd2 \u0265\xd2\x01\x86r\xec\x85\xe3\x1e\xf8>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xd0W\xbc\xc0K\xd0\xf4\xaf\x96BQ:\xa5\t\v\xb3\xff\x93\xfe\x89;\xfeE,\x8e\xddL\x00\x00\u07d4U\xd4.\xb4\x95\xbfF\xa64\x99{_.\xa3b\x81I\x18\u2c09\x05\xc0\xd2e\xb5\xb2\xa8\x00\x00\u07d4U\u069d\xcd\xcaa\xcb\xfe\x1f\x13<{\xce\xfc\x86{\x9c\x81\"\xf9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4U\xe2 \x87bb\xc2\x18\xafOVxG\x98\xc7\xe5]\xa0\x9e\x91\x89\a=\x99\xc1VE\xd3\x00\x00\u07d4U\xfd\b\u0440d\xbd ,\x0e\xc3\xd2\xcc\xe0\xce\v\x9d\x16\x9cM\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x00s\nU\xf6\xb2\x0e\xbd$\x81\x1f\xaa=\xe9m\x16b\xab\xab\x89e\xea=\xb7UF`\x00\x00\u07d4V\x03$\x1e\xb8\xf0\x8fr\x1e4\x8c\x9d\x9a\xd9/H\u342a$\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4V\x056yJ\x9e+\x00I\xd1\x023\xc4\x1a\xdc_A\x8a&J\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\aY\x00Y\xa9\xfe\xc1\x88\x11I\xa4K6\x94\x9a\xef\x85\xd5`\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V\v\xec\xdfR\xb7\x1f=\x88'\xd9'a\x0f\x1a\x98\x0f3qo\x89\x17GMp_V\u0400\x00\xe0\x94V\r\xa3~\x95m\x86/\x81\xa7_\u0540\xa7\x13\\\x1b$cR\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94V\x0f\xc0\x8d\a\x9f\x04~\xd8\xd7\xdfuU\x1a\xa55\x01\xf5p\x13\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4V\x1b\xe9)\x9b>k>c\xb7\x9b\t\x16\x9d\x1a\x94\x8a\xe6\xdb\x01\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94V \xe3\xedy-/\x185\xfe_UA}Q\x11F\fj\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4V \xf4m\x14Q\xc25=bC\xa5\u0534'\x13\v\xe2\xd4\a\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94V!\x05\xe8+\t\x975\xdeI\xf6&\x92\u0307\xcd8\xa8\xed\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94V*\x8d\u02fe\xee\xf7\xb3`h]'0;\u059e\tJ\xcc\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4V+\xce\u04ca\xb2\xabl\b\x0f;\x05A\xb8Enp\x82K?\x89\"\xca5\x87\xcfN\xb0\x00\x00\xe0\x94V+\xe9Z\xba\x17\xc57\x1f\u2e82\x87\x99\xb1\xf5]!w\u058a\b\x16\xd3~\x87\xb9\xd1\xe0\x00\x00\u07d4V/\x16\u05da\xbf\xce\u00d4>4\xb2\x0f\x05\xf9{\xdf\u0366\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4V7=\xaa\xb4c\x16\xfd~\x15v\xc6\x1ej\xff\xcbeY\xdd\u05c9\v\xacq]\x14l\x9e\x00\x00\u07d4V9v8\xbb<\xeb\xf1\xf6 byK^\xb9B\xf9\x16\x17\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V:\x03\xab\x9cV\xb6\x00\xf6\xd2[f\f!\xe1c5Qzu\x8965\u026d\xc5\u07a0\x00\x00\u07d4V<\xb8\x80<\x1d2\xa2['\xb6A\x14\x85+\xd0M\x9c \u0349\v\x14\x9e\xad\n\xd9\xd8\x00\x00\u07d4VXc\x91\x04\fW\xee\xc6\xf5\xaf\xfd\x8c\u052b\xde\x10\xb5\n\u0309\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Vl\x10\xd68\u8e0bG\xd6\xe6\xa4\x14Iz\xfd\xd0\x06\x00\u0509\x05k9Bc\xa4\f\x00\x00\u07d4Vl(\xe3L8\b\xd9vo\xe8B\x1e\xbfO+\x1cO}w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x8d\xf3\x18Vi\x9b\xb5\xac\xfc\x1f\xe1\u0580\u07d9`\xcaCY\x89J\xcfUR\xf3\xb2I\x80\x00\u07d4V\x91\xdd/gE\xf2\x0e\"\xd2\xe1\u0479U\xaa)\x03\xd6VV\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4V\xa1\xd6\r@\xf5\u007f0\x8e\xeb\xf0\x87\xde\xe3\xb3\u007f\x1e|,\xba\x89>\u072e\xc8-\x06\xf8\x00\x00\u07d4V\xac \xd6;\xd8\x03Y\\\xec\x03m\xa7\xed\x1d\xc6n\n\x9e\a\x89\x03w*S\xcc\xdce\x80\x00\u07d4V\xb6\xc2=\xd2\uc434r\x8f;\xb2\xe7d\xc3\xc5\f\x85\xf1D\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xdf\x05\xba\xd4l?\x00\xaeGn\xcf\x01{\xb8\xc8w8?\xf1\x89\n\xb1]\xaa\xefp@\x00\x00\u07d4V\xee\x19\u007fK\xbf\x9f\x1b\x06b\xe4\x1c+\xbd\x9a\xa1\xf7\x99\xe8F\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xf4\x93\xa3\xd1\b\xaa\xa2\u044d\x98\x92/\x8e\xfe\x16b\u03f7=\x89m\x81!\xa1\x94\xd1\x10\x00\x00\u07d4V\xfc\x1a{\xad@G#|\xe1\x16\x14b\x96#\x8e\a\x8f\x93\xad\x89\t\xa6?\b\xeac\x88\x00\x00\u07d4V\xfe\xbf\x9e\x10\x03\xaf\x15\xb1\xbdI\a\xec\b\x9aJ\x1b\x91\xd2h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4W\x17\u0313\x01Q\x1dJ\x81\xb9\xf5\x83\x14\x8b\xee\xd3\xd3\u0303\t\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4W\x17\xf2\xd8\xf1\x8f\xfc\xc0\xe5\xfe$}:B\x19\x03|:d\x9c\x89\u063beI\xb0+\xb8\x00\x00\u07d4W\x19P\xea,\x90\xc1B}\x93\x9da\xb4\xf2\xdeL\xf1\u03ff\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4W\x19\xf4\x9br\r\xa6\x88V\xf4\xb9\xe7\b\xf2VE\xbd\xbcKA\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4W*\xc1\xab\xa0\xde#\xaeA\xa7\xca\xe1\xdc\bB\u062b\xfc\x10;\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94W-\xd8\xcd?\xe3\x99\xd1\xd0\xec(\x121\xb7\xce\xfc \xb9\u4eca\x023\xc8\xfeBp>\x80\x00\x00\xe0\x94WI!\x83\x8c\xc7}l\x98\xb1}\x90::\xe0\xee\r\xa9[\u040a\vS(\x17\x8a\xd0\xf2\xa0\x00\x00\u07d4WJ\xd95S\x90\u421e\xf4*\xcd\x13\x8b*'\xe7\x8c\x00\xae\x89Tg\xb72\xa9\x134\x00\x00\u07d4WM\xe1\xb3\xf3\x8d\x91XF\xae7\x18VJZ\xda \xc2\xf3\xed\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94W\\\x00\u0081\x82\x10\u0085U\xa0\xff)\x01\x02\x89\xd3\xf8#\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94Ws\xb6\x02g!\xa1\xdd\x04\xb7\x82\x8c\xd6+Y\x1b\xfb4SL\x8a\x05\xb7\xacES\xdez\xe0\x00\x00\xe0\x94WwD\x1c\x83\xe0?\v\xe8\xdd4\v\xdechP\x84|b\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Wx\xff\u071b\x94\u0165\x9e\"N\xb9e\xb6\u0790\xf2\"\xd1p\x89\x12-\u007f\xf3f\x03\xfc\x00\x00\u07d4Wz\xee\xe8\u053c\b\xfc\x97\xab\x15n\xd5\u007f\xb9p\x92Sf\xbe\x89\x12\r\xf1\x14rX\xbf\x00\x00\u07d4W{-\a\xe9\xcfRJ\x18\u04c9\x15Vak\x96\x06g\x00\x00\u07d4W\xd5\xfd\x0e=0I3\x0f\xfc\xdc\xd0 Ei\x17e{\xa2\u0689k\xf2\x01\x95\xf5T\xd4\x00\x00\u07d4W\u0754q\xcb\xfa&'\t\xf5\U00106f37t\xc5\xf5'\xb8\xf8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4W\xdf#\xbe\xbd\xc6^\xb7_\ub732\xfa\xd1\xc0si++\xaf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4X\x00\u03410\x83\x9e\x94I]-\x84\x15\xa8\xea,\x90\xe0\xc5\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94X\x03\xe6\x8b4\xda\x12\x1a\xef\b\xb6\x02\xba\u06ef\xb4\xd1$\x81\u028a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\xe0\x94X\x16\xc2hww\xb6\xd7\u04a2C-Y\xa4\x1f\xa0Y\xe3\xa4\x06\x8a\x1cO\xe4:\xdb\n^\x90\x00\x00\u07d4X\x1a:\xf2\x97\xef\xa4Cj)\xaf\x00r\x92\x9a\xbf\x98&\xf5\x8b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\x1b\x9f\xd6\xea\xe3r\xf3P\x1fB\xeb\x96\x19\xee\xc8 \xb7\x8a\x84\x8a\x04+\xe2\xc0\f\xa5;\x8d\x80\x00\u07d4X\x1b\xdf\x1b\xb2v\xdb\u0746\xae\xdc\xdb9z\x01\xef\xc0\xe0\f[\x8965\u026d\xc5\u07a0\x00\x00\u07d4X\x1f4\xb5#\xe5\xb4\x1c\t\xc8|)\x8e)\x9c\xbc\x0e)\xd0f\x89=X3\xaa\xfd9u\x80\x00\xe0\x94X$\xa7\xe2(8'q40\x8c_KP\u06b6^C\xbb1\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4X+pf\x9c\x97\xaa\xb7\u0581H\xd8\xd4\xe9\x04\x11\xe2\x81\rV\x8965f3\xeb\xd8\xea\x00\x00\u07d4X.|\xc4o\x1d{Nn\x9d\x95\x86\x8b\xfd7\x05s\x17\x8fL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X>\x83\xbaU\xe6~\x13\xe0\xe7o\x83\x92\xd8s\xcd!\xfb\xf7\x98\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Xi\xfb\x86}q\xf18\u007f\x86;i\x8d\t\xfd\xfb\x87\u011b\\\x89\u01bb\xf8X\xb3\x16\b\x00\x00\u07d4X}hI\xb1h\xf6\xc33+z\xba\xe7\xeblB\xc3\u007fH\xbf\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4X\x87\xdcj3\xdf\xedZ\xc1\xed\xef\xe3^\xf9\x1a!b1\xac\x96\x89\r\x8drkqw\xa8\x00\x00\xe0\x94X\x8e\u0650\xa2\xaf\xf4J\x94\x10]X\xc3\x05%w5\xc8h\xac\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4X\xae-\xdc_L\x8a\u0697\xe0l\x00\x86\x17\x17g\xc4#\xf5\u05c9WG=\x05\u06ba\xe8\x00\x00\u07d4X\xae\xd6gJ\xff\xd9\xf6B3'*W\x8d\xd98k\x99\xc2c\x89\xb8Pz\x82\a( \x00\x00\xe0\x94X\xb8\b\xa6[Q\xe63\x89i\xaf\xb9^\xc7\a5\xe4Q\xd5&\x8a\bxK\xc1\xb9\x83z8\x00\x00\u07d4X\xb8\xae\x8fc\xef5\xed\ab\xf0\xb6#=J\xc1Nd\xb6M\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X\xba\x15ie\x0e[\xbb\xb2\x1d5\xd3\xe1u\xc0\u05b0\xc6Q\xa9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4X\xc5U\xbc)<\xdb\x16\xc66.\xd9z\xe9U\v\x92\xea\x18\x0e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4X\xc6P\xce\xd4\v\xb6VA\xb8\xe8\xa9$\xa09\xde\xf4hT\u07c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4X\xc9\aT\xd2\xf2\n\x1c\xb1\xdd3\x06%\xe0KE\xfaa\x9d\\\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xe2\xf1\x12#\xfc\x827\xf6\x9d\x99\xc6(\x9c\x14\x8c\x06\x04\xf7B\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4X\xe5T\xaf=\x87b\x96 \xdaa\xd58\xc7\xf5\xb4\xb5LJ\xfe\x89FP\x9diE4r\x80\x00\u07d4X\xe5\xc9\xe3D\xc8\x06e\r\xac\xfc\x90M3\xed\xbaQ\a\xb0\u0789\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4X\xe6a\u043as\xd6\xcf$\t\x9aUb\xb8\b\xf7\xb3g;h\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xf0[&%`P<\xa7a\xc6\x18\x90\xa4\x03_Lsr\x80\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4X\xfb\x94sd\xe7iWe6\x1e\xbb\x1e\x80\x1f\xfb\x8b\x95\xe6\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Y\x01\x81\xd4E\x00{\u0407Z\xaf\x06\x1c\x8dQ\x159\x00\x83j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x02\xe4J\xf7i\xa8rF\xa2\x1e\a\x9c\b\xbf6\xb0n\xfe\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4Y\n\xcb\xda7)\f\r>\xc8O\xc2\x00\rv\x97\xf9\xa4\xb1]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94Y\f\xcbY\x11\xcfx\xf6\xf6\"\xf55\xc4t7_J\x12\xcf\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y\x10\x10m\xeb\u0491\xa1\u0340\xb0\xfb\xbb\x8d\x8d\x9e\x93\xa7\xcc\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x16\x17I\xfe\xdc\xf1\xc7!\xf2 -\x13\xad\xe2\xab\xcfF\v=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Y\x1b\xef1q\xd1\u0155w\x17\xa4\xe9\x8d\x17\xeb\x14,!NV\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y <\xc3u\x99\xb6H1*|\xc9\xe0m\xac\xb5\x89\xa9\xaej\x89\b\x0fyq\xb6@\x0e\x80\x00\u07d4Y&\x81q\xb83\xe0\xaa\x13\xc5KR\xcc\xc0B.O\xa0:\ub262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94Y'w&\x1e;\xd8R\u010e\u0295\xb3\xa4L[\u007f-B,\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y0Dg\x0f\xae\xff\x00\xa5[Z\xe0Q\xeb{\xe8p\xb1\x16\x94\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94Y;E\xa1\x86J\xc5\xc7\xe8\xf0\u02ae\xba\r\x87<\xd5\xd1\x13\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Y_^\xdajV\xf1N%\xe0\xc6\xf3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Z\x1a3ib\xd6\xe0\xc601\u0303\u01a5\u01a6\xf4G\x8e\u02c965\u026d\xc5\u07a0\x00\x00\u07d4Z\x1d--\x1dR\x03\x04\xb6 \x88IW\x047\xeb0\x91\xbb\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Z&s1\xfa\xcb&-\xaa\xec\xd9\xddc\xa9p\f_RY\u07c9\x05k\xc7^-c\x10\x00\x00\xe0\x94Z(WU9\x1e\x91NX\x02_\xaaH\xcch_O\xd4\xf5\xb8\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4Z)\x16\xb8\xd2\xe8\xcc\x12\xe2\a\xabFMC>#p\xd8#\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4Z+\x1c\x85:\xeb(\xc4U9\xafv\xa0\n\xc2\u0628$(\x96\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4Z-\xaa\xb2\\1\xa6\x1a\x92\xa4\xc8,\x99%\xa1\xd2\xefXX^\x89\f8\r\xa9\u01d5\f\x00\x00\u07d4Z0\xfe\xac7\xac\x9fr\u05f4\xaf\x0f+\xc79R\xc7O\xd5\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4ZTh\xfa\\\xa2&\xc7S.\xcf\x06\xe1\xbc\x1cE\"]~\u0249g\x8a\x93 b\xe4\x18\x00\x00\u07d4ZVR\x857JI\xee\xddPL\x95}Q\bt\xd0\x04U\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4Z^\xe8\xe9\xbb\x0e\x8a\xb2\xfe\xcbK3\u0494x\xbeP\xbb\xd4K\x89*\x11)\u0413g \x00\x00\xe0\x94Z_\x85\b\xda\x0e\xbe\xbb\x90\xbe\x903\xbdM\x9e'A\x05\xae\x00\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4Z`q\xbc\xeb\xfc\xbaJ\xb5\u007fM\xb9o\u01e6\x8b\xec\xe2\xba[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z`\xc9$\x16(s\xfc~\xa4\xda\u007f\x97.5\x01g7`1\x89\x04\x87\xf2w\xa8\x85y\x80\x00\u07d4Zf\x86\xb0\xf1~\a\xed\xfcY\xb7Y\xc7}[\xef\x16M8y\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Zp\x10o \xd6?\x87Re\xe4\x8e\r5\xf0\x0e\x17\xd0+\u0249\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794Zt\xbab\xe7\xc8\x1a4t\xe2}\x89O\xed3\xdd$\xad\x95\xfe\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94Zw5\x00}p\xb0hD\u0699\x01\xcd\xfa\xdb\x11\xa2X,/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Z\x82\xf9l\u0537\xe2\xd9=\x10\xf3\x18]\xc8\xf4=Ku\xaai\x89lc?\xba\xb9\x8c\x04\x00\x00\u07d4Z\x87\xf04\xe6\xf6\x8fNt\xff\xe6\fd\x81\x946\x03l\xf7\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\x89\x11U\xf5\x0eB\aCt\xc79\xba\xad\xf7\xdf&Q\x15:\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\u07d4Z\x9c\x8bi\xfcaMiVI\x99\xb0\r\xcbB\xdbg\xf9~\x90\x89\xb9\xe6\x15\xab\xad:w\x80\x00\xe0\x94Z\xaf\x1c1%Jn\x00_\xba\u007fZ\xb0\xecy\xd7\xfc+c\x0e\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4Z\xb1\xa5aSH\x00\x1c|w]\xc7WHf\x9b\x8b\xe4\xde\x14\x89%jr\xfb)\xe6\x9c\x00\x00\xe1\x94Z\xbf\xec%\xf7L\u06047c\x1aw1\x90i2wcV\xf9\x8b\t\xd8<\xc0\u07e1\x11w\xff\x80\x00\u07d4Z\u0090\x8b\x0f9\x8c\r\xf5\xba\xc2\xcb\x13\xcas\x14\xfb\xa8\xfa=\x89\n\xd4\xc81j\v\f\x00\x00\xe0\x94Z\u025a\u05c1j\xe9\x02\x0f\xf8\xad\xf7\x9f\xa9\x86\x9b|\xeaf\x01\x8a\x04ri\x8bA;C \x00\x00\u07d4Z\xd1,^\xd4\xfa\x82~!P\u03e0\u058c\n\xa3{\x17i\xb8\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94Z\xd5\xe4 uV\x13\x88o5\xaaV\xac@>\xeb\xdf\xe4\xb0\u040a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4Z\xdew\xfd\x81\xc2\\\n\xf7\x13\xb1\a\x02v\x8c\x1e\xb2\xf9u\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Z\xe6N\x85;\xa0\xa5\x12\x82\u02cd\xb5.Aa^|\x9fs?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xed\x0el\xfe\x95\xf9\u0580\xc7dr\xa8\x1a+h\n\u007f\x93\xe2\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Z\xef\x16\xa2&\xddh\a\x1f$\x83\xe1\xdaBY\x83\x19\xf6\x9b,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xf4j%\xac\t\xcbsakS\xb1O\xb4/\xf0\xa5\x1c\u0772\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Z\xf7\xc0r\xb2\u016c\xd7\x1cv\xad\xdc\xceS\\\xf7\xf8\xf95\x85\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\xfd\xa9@\\\x8e\x976QEt\u0692\x8d\xe6tV\x01\t\x18\x8a\x01E\xb8\xb0#\x9aF\x92\x00\x00\u07d4[\x06\xd1\xe6\x93\f\x10Ti+y\xe3\xdb\xe6\xec\xceS\x96d \x89\v\"\u007fc\xbe\x81<\x00\x00\u07d4[%\xca\xe8m\xca\xfa*`\xe7r61\xfc_\xa4\x9c\x1a\xd8}\x89\x87\fXQ\x0e\x85 \x00\x00\u07d4[(|~sB\x99\xe7'bo\x93\xfb\x11\x87\xa6\rPW\xfe\x89\x05|\xd94\xa9\x14\xcb\x00\x00\u07d4[)\f\x01\x96|\x81.M\xc4\xc9\v\x17L\x1b@\x15\xba\xe7\x1e\x89\b \xeb4\x8dR\xb9\x00\x00\u07d4[+d\xe9\xc0X\u30a8\xb2\x99\"N\xec\xaa\x16\xe0\x9c\x8d\x92\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\xe0\x94[./\x16\x18U.\xab\r\xb9\x8a\xddUc|)Q\xf1\xfb\x19\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4[0`\x8cg\x8e\x1a\xc4d\xa8\x99L;3\xe5\xcd\xf3Iq\x12\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[36\x96\xe0L\xca\x16\x92\xe7\x19\x86W\x9c\x92\rk)\x16\xf9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94[C\rw\x96\x96\xa3e?\xc6\x0et\xfb\u02ec\xf6\xb9\u00ba\xf1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4[Cse\xae:\x9a/\xf9|h\xe6\xf9\nv \x18\x8c}\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d4[I\xaf\xcduDx8\xf6\xe7\xce\u068d!w}O\xc1\xc3\xc0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4[L\f`\xf1\x0e\u0489K\xdbB\xd9\xdd\x1d!\x05\x87\x81\n\r\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4[N\xa1m\xb6\x80\x9b\x03R\u0536\xe8\x1c9\x13\xf7jQ\xbb2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[[\xe0\xd8\xc6rv\xba\xab\xd8\xed\xb3\rH\xeaud\v\x8b)\x89,\xb1\xf5_\xb7\xbe\x10\x00\x00\u07d4[]Qp)2\x15b\x11\x1bC\bm\v\x045\x91\x10\x9ap\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94[]\x8c\x8e\xedl\x85\xac!Va\xde\x02fv\x82?\xaa\n\f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4[mU\xf6q)g@\\e\x91)\xf4\xb1\xde\t\xac\xf2\xcb{\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4[p\u011c\u024b=\xf3\xfb\xe2\xb1Y\u007f\\\x1bcG\xa3\x88\xb7\x894\x95tD\xb8@\xe8\x00\x00\u07d4[sn\xb1\x83Sb\x9b\u0796v\xda\xdd\x16P4\xce^\xcch\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[u\x9f\xa1\x10\xa3\x1c\x88F\x9fT\xd4K\xa3\x03\xd5}\xd3\xe1\x0f\x89[F\xdd/\x0e\xa3\xb8\x00\x00\u07d4[w\x84\xca\xea\x01y\x9c\xa3\x02'\x82vg\xce |\\\xbcv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4[x\xec\xa2\u007f\xbd\xeao&\xbe\xfb\xa8\x97+)^x\x146K\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94[\x80\v\xfd\x1b>\u0525}\x87Z\xed&\xd4/\x1aw\b\xd7*\x8a\x01Z\x82\xd1\u057b\x88\xe0\x00\x00\u07d4[\x85\xe6\x0e*\xf0TO/\x01\xc6N 2\x90\x0e\xbd8\xa3\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4[\xa2\xc6\xc3]\xfa\xec)h&Y\x19\x04\xd5DFJ\xea\xbd^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94[\xafmt\x96 \x80>\x83H\xaf7\x10\xe5\xc4\xfb\xf2\x0f\u0214\x8a\x01\x0f@\x02a]\xfe\x90\x00\x00\u07d4[\xc1\xf9U\a\xb1\x01\x86B\xe4\\\xd9\xc0\xe2'3\xb9\xb1\xa3&\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94[\xd25GG\u007fm\t\u05f2\xa0\x05\xc5\xeee\fQ\fV\u05ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4[\xd2J\xac6\x12\xb2\f`\x9e\xb4gy\xbf\x95i\x84\a\xc5|\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[\u0586-Q}M\xe4U\x9dN\xec\n\x06\xca\xd0^/\x94n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4[\xe0EQ*\x02n?\x1c\xeb\xfdZ~\xc0\xcf\xc3o-\xc1k\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94[\xf9\xf2\"nZ\xea\xcf\x1d\x80\xae\nY\xc6\xe3\x808\xbc\x8d\xb5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4[\xfa\xfe\x97\xb1\xdd\x1dq+\xe8mA\xdfy\x89SE\x87Z\x87\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\\\x0f.Q7\x8fk\r{\xabas1X\vn9\xad<\xa5\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\\)\xf9\xe9\xa5#\xc1\xf8f\x94H\xb5\\H\xcb\xd4|%\xe6\x10\x894F\xa0\xda\xd0L\xb0\x00\x00\xe0\x94\\0\x8b\xacHW\xd3;\xae\xa0t\xf3\x95m6!\xd9\xfa(\xe1\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\\1*V\u01c4\xb1\"\t\x9bvM\x05\x9c!\xec\xe9^\x84\u0289\x05&c\u032b\x1e\x1c\x00\x00\u07d4\\1\x99m\xca\xc0\x15\xf9\xbe\x98[a\x1fF\x870\xef$M\x90\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\\24W\xe1\x87v\x1a\x82v\xe3Y\xb7\xb7\xaf?;n=\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\<\x1cd[\x91uC\x11;>l\x1c\x05M\xa1\xfet+\x9a\x89+^:\xf1k\x18\x80\x00\x00\u0794\\=\x19D\x1d\x19l\xb4Cf \xfc\xad\u007f\xbby\xb2\x9ex\x88\xc6s\xce<@\x16\x00\x00\u07d4\\?V\u007f\xaf\xf7\xba\u0475\x12\x00\"\xe8\xcb\u02a8+I\x17\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\\Ch\x91\x8a\xced\t\u01de\u0280\u036a\xe49\x1d+bN\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\\FA\x97y\x1c\x8a=\xa3\xc9%Co'z\xb1;\xf2\xfa\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\\H\x81\x16\\\xb4+\xb8.\x979l\x8e\xf4J\xdb\xf1s\xfb\x99\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\xe0\x94\\H\x92\x90z\a \xdfo\xd3A>c\xffv}k9\x80#\x8a\x02\xcb\x00\x9f\u04f5y\x0f\x80\x00\u07d4\\O$\xe9\x94\ud3c5\x0e\xa7\x81\x8fG\x1c\x8f\xac;\xcf\x04R\x89]\x80h\x8d\x9e1\xc0\x00\x00\u07d4\\T\x19V\\:\xadNqN\a92\x8e5!\u024f\x05\u0309\x1c\x9fx\u0489>@\x00\x00\u07d4\\a6\xe2\x18\xde\na\xa17\xb2\xb3\x96-*a\x12\xb8\t\u05c9\x0f\xf3\u06f6_\xf4\x86\x80\x00\xe0\x94\\a\xaby\xb4\b\xdd2)\xf6bY7\x05\xd7/\x1e\x14{\xb8\x8a\x04\xd0$=4\x98\u0344\x00\x00\u07d4\\m\x04\x1d\xa7\xafD\x87\xb9\xdcH\xe8\xe1\xf6\af\u0425m\xbc\x89O\a\n\x00>\x9ct\x00\x00\u07d4\\o6\xaf\x90\xab\x1aeln\xc8\xc7\xd5!Q'b\xbb\xa3\xe1\x89lh\xcc\u041b\x02,\x00\x00\u07d4\\{\x9e\u01e2C\x8d\x1eD*\x86\x0f\x8a\x02\x1e\x18\x99\xf07z\xea\x00\x00\u07d4\\\xcc\xf1P\x8b\xfd5\xc2\x050\xaad%\x00\xc1\r\xeee\xea\xed\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\\\xcer\xd0h\xc7\xc3\xf5[\x1d(\x19T^w1|\xae\x82@\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\\\xd0\xe4u\xb5D!\xbd\xfc\f\x12\xea\x8e\b+\u05e5\xaf\nj\x89\x032\xca\x1bg\x94\f\x00\x00\u07d4\\\u0548\xa1N\xc6H\xcc\xf6G)\xf9\x16z\xa7\xbf\x8b\xe6\xeb=\x8965\u026d\xc5\u07a0\x00\x00\u07d4\\\u062f`\xdee\xf2M\xc3\xceW0\xba\x92e0\"\xdcYc\x89a\t=|,m8\x00\x00\u07d4\\\xdcG\b\xf1O@\xdc\xc1Zy_}\xc8\xcb\v\u007f\xaa\x9en\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\\\u0d86,\u0391b\xe8~\bI\xe3\x87\xcb]\xf4\xf9\x11\x8c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\\\xe2\xe7\u03aa\xa1\x8a\xf0\xf8\xaa\xfa\u007f\xba\xd7L\u021e<\xd46\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\\\xe4@h\xb8\xf4\xa3\xfey\x9ej\x83\x11\xdb\xfd\xed\xa2\x9d\xee\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u0794\\\xeb\xe3\v*\x95\xf4\xae\xfd\xa6ee\x1d\xc0\xcf~\xf5u\x81\x99\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\\\xf1\x8f\xa7\u0227\xc0\xa2\xb3\xd5\xef\u0459\x0fd\xdd\xc5i$,\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\\\xf4N\x10T\reqd#\xb1\xbc\xb5B\xd2\x1f\xf8:\x94\u034a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\\xf8\xc0>\xb3\xe8r\xe5\x0f|\xfd\f/\x8d;?,\xb5\x18:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\\\xfa\x8dV\x85ue\x8c\xa4\xc1\xa5\x93\xacL]\x0eD\xc6\aE\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\\\xfa\x98w\xf7\x19\u01dd\x9eIJ\b\xd1\xe4\x1c\xf1\x03\xfc\x87\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4]\x1d\xc38{G\xb8E\x1eU\x10l\f\xc6}m\xc7+\u007f\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4]#\x1ap\xc1\xdf\xeb6\n\xbd\x97\xf6\x16\xe2\xd1\r9\xf3\u02b5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4]$\xbd\xbc\x1cG\xf0\xeb\x83\xd1(\xca\xe4\x8a\xc3\xf4\xb5\x02bt\a\xda'/g\x81Jk\xec\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4]\x83\xb2\x1b\xd2q#`Ckg\xa5\x97\xee3x\xdb>z\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94]\x87+\x12.\x99N\xf2|q\xd7\u07b4W\xbfeB\x9e\xcal\x8a\x01\xb1\xad\xed\x81\u04d4\x10\x80\x00\xe0\x94]\x8d1\xfa\xa8d\xe2!Y\xcdoQu\xcc\xec\xc5?\xa5Mr\x8a\x05\xb6\x96\xb7\r\xd5g\x10\x00\x00\xe0\x94]\x95\x8a\x9b\u0449\u0098_\x86\u014a\x8ci\xa7\xa7\x88\x06\xe8\u068a\x02(\xf1o\x86\x15x`\x00\x00\u07d4]\xa2\xa9\xa4\xc2\xc0\xa4\xa9$\xcb\xe0\xa5:\xb9\xd0\xc6'\xa1\u03e0\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4]\xa4\u0288\x93\\'\xf5\\1\x10H\x84\x0eX\x9e\x04\xa8\xa0I\x89\x04V9\x18$O@\x00\x00\u07d4]\xa5G\x85\u027d0W\\\x89\u07b5\x9d A\xd2\n9\xe1{\x89j\xa2\t\xf0\xb9\x1de\x80\x00\xe0\x94]\xb6\x9f\xe9>o\xb6\xfb\xd4P\x96k\x97#\x8b\x11\n\xd8'\x9a\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4]\xb7\xbb\xa1\xf9W?$\x11]\x8c\x8cb\xe9\u0388\x95\x06\x8e\x9f\x89\x02\xb5\xaa\xd7,e \x00\x00\xe0\x94]\xb8D\x00W\x00i\xa9W<\xab\x04\xb4\u6d955\xe2\x02\xb8\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4]\xc3m\xe55\x94P\xa1\xec\t\xcb\fD\xcf+\xb4+:\xe45\x89<\x94m\x89;3\x06\x00\x00\u07d4]\xc6\xf4_\xef&\xb0n3\x021?\x88M\xafH\xe2to\xb9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94]\u0376\xb8zP\xa9\xde\x02C\x80\x00\x00\u07d4^Q\xb8\xa3\xbb\t\xd3\x03\xea|\x86\x05\x15\x82\xfd`\x0f\xb3\xdc\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794^X\xe2U\xfc\x19\x87\n\x040_\xf2\xa0F1\xf2\xff)K\xb1\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4^ZD\x19t\xa8=t\u0187\xeb\xdcc?\xb1\xa4\x9e{\x1a\u05c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^eE\x8b\xe9d\xaeD\x9fqw7\x04\x97\x97f\xf8\x89\x87a\x89\x1c\xa7\xccs[o|\x00\x00\u07d4^g\u07c9i\x10\x1a\u06bd\x91\xac\xcdk\xb1\x99\x12t\xaf\x8d\xf2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4^n\x97G\xe1b\xf8\xb4\\en\x0fl\xaez\x84\xba\xc8\x0eN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^s\x1bU\xce\xd4R\xbb??\xe8q\xdd\xc3\xed~\xe6Q\n\x8f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^t\xed\x80\xe9eW\x88\xe1\xbb&\x97R1\x96g\xfeuNZ\x89\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4^w.'\xf2\x88\x00\xc5\r\u0697;\xb3>\x10v.n\xea \x89a\t=|,m8\x00\x00\u07d4^{\x8cT\xdcW\xb0@ bq\x9d\xee~\xf5\xe3~\xa3]b\x89\x9b\xf9\x81\x0f\xd0\\\x84\x00\x00\u07d4^\u007fp7\x87uX\x9f\xc6j\x81\xd3\xf6S\xe9T\xf5U`\ub243\xf2\x89\x18\x1d\x84\xc8\x00\x00\xe0\x94^\x80n\x84W0\xf8\a>l\xc9\x01\x8e\xe9\x0f\\\x05\xf9\t\xa3\x8a\x02\x01\xe9m\xac\u03af \x00\x00\u07d4^\x8eM\xf1\x8c\xf0\xafw\tx\xa8\u07cd\xac\x90\x93\x15\x10\xa6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^\x90\xc8Xw\x19\x87V\xb06l\x0e\x17\xb2\x8eR\xb4FPZ\x89\x14JJ\x18\xef\xebh\x00\x00\u07d4^\x95\xfe_\xfc\xf9\x98\xf9\xf9\xac\x0e\x9a\x81\u06b8>\xadw\x00=\x89\x1dB\xc2\r2y\u007f\x00\x00\u07d4^\xad)\x03z\x12\x89dx\xb1)j\xb7\x14\xe9\u02d5B\x8c\x81\x89\x03\xe0C\a-@n\x00\x00\u07d4^\xb3q\xc4\a@lB{;}\xe2q\xad<\x1e\x04&\x95y\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^\u037a\xea\xb9\x10o\xfe]{Q\x96\x96`\x9a\x05\xba\ub16d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4^\xd0\xd63\x85Y\xefD\xdcza\xed\xeb\x89?\xa5\xd8?\xa1\xb5\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94^\u04fb\xc0R@\xe0\u04d9\xebm\xdf\xe6\x0fb\xdeM\x95\t\xaf\x8a)\x14\xc0$u\xf9\xd6\xd3\x00\x00\u0594^\xd3\xf1\xeb\xe2\xaegV\xb5\xd8\xdc\x19\xca\xd0,A\x9a\xa5w\x8b\x80\u07d4^\xd5a\x15\xbde\x05\xa8\x82s\xdf\\V\x83\x94p\xd2J-\xb7\x89\x03\x8ee\x91\xeeVf\x80\x00\xe0\x94^\xf8\xc9a\x86\xb3y\x84\xcb\xfe\x04\u0158@n;\n\xc3\x17\x1f\x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4^\xfb\xdf\xe58\x99\x99c<&`Z[\xfc,\x1b\xb5\x95\x93\x93\x89\x03\xc0W\xc9\\\xd9\b\x00\x00\xe0\x94_\x13\x15F1Fm\xcb\x13S\u0210\x93*|\x97\xe0\x87\x8e\x90\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4_\x16z\xa2B\xbcL\x18\x9a\xde\xcb:\u0127\xc4R\xcf\x19/\u03c9lkLM\xa6\u077e\x00\x00\xe0\x94_\x1c\x8a\x04\xc9\rs[\x8a\x15)\t\xae\xaeco\xb0\xce\x16e\x8a\x01{x'a\x8cZ7\x00\x00\u07d4_#\xba\x1f7\xa9lE\xbcI\x02YS\x8aT\u008b\xa3\xb0\u0549A\rXj \xa4\xc0\x00\x00\u07d4_&\xcf4Y\x9b\xc3n\xa6{\x9ez\x9f\x9bC0\xc9\xd5B\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4_)\xc9\xdev]\xde%\x85*\xf0}3\xf2\xceF\x8f\xd2\t\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_/\a\xd2\u0597\xe8\xc5g\xfc\xfd\xfe\x02\x0fI\xf3`\xbe!9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_2\x1b=\xaa\xa2\x96\xca\xdf)C\x9f\x9d\xab\x06*K\xff\xed\u0589\x04p%\x90>\xa7\xae\x00\x00\u07d4_3:;#\x10vZ\r\x182\xb9\xbeL\n\x03pL\x1c\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4_4K\x01\xc7\x19\x1a2\xd0v*\xc1\x88\xf0\xec-\xd4`\x91\x1d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94_6>\n\xb7G\xe0-\x1b;f\xab\xb6\x9e\xa5<{\xafR:\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4_7[\x86`\f@\u0328\xb2gkz\x1a\x1d\x16D\xc5\xf5,\x89\x04F\x18\xd7Lb?\x00\x00\u07d4_>\x1eg9\xb0\xc6\"\x00\xe0\n\x006\x91\xd9\xef\xb28\u061f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_H?\xfb\x8fh\n\xed\xf2\xa3\x8fx3\xaf\xdc\xdeY\xb6\x1eK\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94_J\xceL\x1c\xc13\x91\xe0\x1f\x00\xb1\x98\xe1\xf2\v_\x91\xcb\xf5\x8a\x01\x0f\x0f\xa8\xb9\u04c1\x1a\x00\x00\xe0\x94_R\x12\x82\xe9\xb2x\u070c\x03Lr\xafS\xee)\xe5D=x\x8a\x01as-/\x8f:\xe0\x00\x00\u07d4_h\xa2L~\xb4\x11vgs{39?\xb3\xc2\x14\x8aS\xb6\x89\x02\xce\u0791\x8dE<\x00\x00\u07d4_p\x8e\xaf9\xd8#\x94lQ\xb3\xa3\u9df3\xc0\x03\xe2cA\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4_t.H~:\xb8\x1a\xf2\xf9J\xfd\xbe\x1b\x9b\x8f\\\u0301\xbc\x89u\xc4E\xd4\x11c\xe6\x00\x00\u07d4_t\xed\x0e$\xff\x80\u0672\u0124K\xaa\x99uB\x8c\u05b95\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4_v\xf0\xa3\x06&\x9cx0k=e\r\xc3\xe9\xc3p\x84\xdba\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4_w\xa1\a\xab\x12&\xb3\xf9_\x10\ue0ee\xfcl]\xff>\u0709\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4_{;\xba\xc1m\xab\x83\x1aJ\x0f\xc5;\fT\x9d\xc3l1\u0289i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94_\x93\xff\x83't\xdbQ\x14\xc5[\xb4\xbfD\xcc\U000f53d0?\x8a(\xa9\xc9\x1a&4X)\x00\x00\u07d4_\x96\x16\xc4{Jg\xf4\x06\xb9Z\x14\xfeo\xc2h9o\x17!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4_\x98\x109\xfc\xf5\x02%\xe2\xad\xf7bu!\x12\xd1\xcc&\xb6\xe3\x89\x1b\x1aAj!S\xa5\x00\x00\u07d4_\x99\u070eI\xe6\x1dW\xda\xef`j\xcd\xd9\x1bMp\a2j\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_\xa6\x1f\x15-\xe6\x125\x16\xc7Q$)y(_yj\u01d1\x89\v\x0f\x11\x97)c\xb0\x00\x00\u07d4_\xa7\xbf\xe0C\x88a'\xd4\x01\x1d\x83V\xa4~\x94yc\xac\xa8\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94_\xa8\xa5Nh\x17lO\xe2\xc0\x1c\xf6q\xc5\x15\xbf\xbd\xd5(\xa8\x8aE\xe1U\xfa\x01\x10\xfa@\x00\x00\u07d4_\xad\x96\x0fk,\x84V\x9c\x9fMG\xbf\x19\x85\xfc\xb2\xc6]\xa6\x8965f3\xeb\xd8\xea\x00\x00\u07d4_\xc6\xc1\x14&\xb4\xa1\xea\xe7\xe5\x1d\xd5\x12\xad\x10\x90\xc6\xf1\xa8[\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4_\u0344Th\x96\xdd\b\x1d\xb1\xa3 \xbdM\x8c\x1d\xd1R\x8cL\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4_\u0368G\xaa\xf8\xd7\xfa\x8b\xca\b\x02\x9c\xa2\x84\x91f\xaa\x15\xa3\x89!\u02b8\x12Y\xa3\xbf\x00\x00\u07d4_\xd1\xc3\xe3\x17x'l\xb4.\xa7@\xf5\xea\xe9\xc6A\xdb\xc7\x01\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4_\xd3\xd6w~\xc2b\n\xe8:\x05R\x8e\xd4%\a-<\xa8\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_\xd9s\xaf6j\xa5\x15|Te\x9b\u03f2|\xbf\xa5\xac\x15\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4_\xe7w\x03\x80\x8f\x82>l9\x93R\x10\x8b\xdb,R|\xb8|\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94_\xecI\xc6e\xe6N\xe8\x9d\xd4A\xeet\x05n\x1f\x01\xe9(p\x8a\x01V\x9b\x9es4t\xc0\x00\x00\u07d4_\xf3&\xcd`\xfd\x13k$^)\xe9\bzj\u04e6R\u007f\r\x89e\xea=\xb7UF`\x00\x00\u07d4_\xf9=\xe6\xee\x05L\xadE\x9b-^\xb0\xf6\x87\x03\x89\xdf\xcbt\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4`\x06\xe3m\x92\x9b\xf4]\x8f\x16#\x1b\x12j\x01\x1a\xe2\x83\xd9%\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4`!\xe8Z\x88\x14\xfc\xe1\xe8*A\xab\xd1\u04f2\xda\xd2\xfa\xef\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4`8t\n\xe2\x8df\xba\x93\xb0\xbe\bH+2\x05\xa0\xf7\xa0{\x89\x11!a\x85\u009fp\x00\x00\u07d4`?/\xabz\xfbn\x01{\x94v`i\xa4\xb4;8\x96I#\x89Y\xd2\xdb$\x14\u0699\x00\x00\u07d4`B'm\xf2\x98?\xe2\xbcGY\xdc\x19C\xe1\x8f\xdb\xc3Ow\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4`B\xc6D\xba\xe2\xb9o%\xf9M1\xf6x\xc9\r\xc9f\x90\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4`L\xdf\x18b\x8d\xbf\xa82\x91\x94\xd4x\xddR\x01\xee\xccK\xe7\x89\x01?0j$\t\xfc\x00\x00\u07d4`N\x94w\xeb\xf4r|t[\u02bb\xed\xcbl\xcf)\x99@\"\x8966\x9e\xd7t}&\x00\x00\u07d4`gm\x1f\xa2\x1f\xca\x05\"\x97\xe2K\xf9c\x89\u0171*p\u05c9\r\x17|Zzh\xd6\x00\x00\u07d4`gn\x92\u044b\x00\x05\t\xc6\x1d\xe5@\xe6\xc5\u0776v\xd5\t\x89A\rXj \xa4\xc0\x00\x00\u07d4`o\x17q!\xf7\x85\\!\xa5\x06#0\xc8v\"d\xa9{1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\x86B6\x93\r\x04\xd8@+]\xcb\xeb\x80\u007f<\xafa\x1e\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\xabq\xcd&\xeamnY\xa7\xa0\xf6'\xee\a\x9c\x88^\xbb\xf6\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4`\xaf\x0e\xe1\x18D<\x9b7\xd2\xfe\xadw\xf5\xe5!\u07be\x15s\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4`\xb3X\xcb=\xbe\xfa7\xf4}\xf2\xd76X@\u068e;\u024c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4`\xb8\u05b7;ySO\xb0\x8b\xb8\xcb\xce\xfa\xc7\xf3\x93\xc5{\xfe\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4`\xbeo\x95?*M%\xb6%o\xfd$#\xac\x148%.N\x89\b!\xab\rD\x14\x98\x00\x00\u0794`\xc3qO\xdd\xdbcFY\u48b1\xeaB\xc4r\x8c\u01f8\xba\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4`\xcc=D^\xbd\xf7j}z\xe5q\u0197\x1d\xffh\u0305\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94`\xd5fq@\xd1&\x14\xb2\x1c\x8e^\x8a3\b.2\xdf\xcf#\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4`\xde\"\xa1Pt2\xa4{\x01\xcch\xc5*\v\xf8\xa2\xe0\u0418\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4`\xe0\xbd\u0422Y\xbb\x9c\xb0\x9d?7\xe5\u034b\x9d\xac\uafca\x89JD\x91\xbdm\xcd(\x00\x00\u07d4`\xe3\xccC\xbc\xdb\x02j\xadu\x9cpf\xf5U\xbb\xf2\xacf\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x04+\x80\xfd`\x95\u0478{\xe2\xf0\x0f\x10\x9f\xab\xaf\xd1W\xa6\x89\x05k\xc7^-c\x10\x00\x00\u07d4a\a\xd7\x1d\xd6\xd0\xee\xfb\x11\xd4\xc9\x16@L\xb9\x8cu>\x11}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x0f\xd6\xeeN\xeb\xab\x10\xa8\xc5]\vK\xd2\xe7\xd6\xef\x81qV\x89\x01\x15\x95a\x06]]\x00\x00\u07d4a\x14\xb0\xea\xe5Wi\x03\xf8\v\xfb\x98\x84-$\xed\x92#\u007f\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4a!\xaf9\x8a[-\xa6\x9fe\xc68\x1a\xec\x88\u039c\xc6D\x1f\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4a&g\xf1r\x13[\x95\v,\xd1\xde\x10\xaf\xde\xcehW\xb8s\x8965\u026d\xc5\u07a0\x00\x00\u07d4a,\xed\x8d\xc0\u071e\x89\x9e\xe4oyb33\x15\xf3\xf5^D\x89\x12^5\xf9\xcd=\x9b\x00\x00\u07d4a4\xd9B\xf07\xf2\xcc=BJ#\f`=g\xab\xd3\xed\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a:\xc5;\xe5e\xd4e6\xb8 q[\x9b\x8d:\xe6\x8aK\x95\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4a?\xabD\xb1k\xbeUMD\xaf\xd1x\xab\x1d\x02\xf3z\ua949lk\x93[\x8b\xbd@\x00\x00\u07d4aN\x8b\xef=\xd2\u015bY\xa4\x14Vt@\x10\x185\x18\x84\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4aQ\x84d\xfd\u0637<\x1b\xb6\xacm\xb6\x00eI8\xdb\xf1z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4aT}7nSi\xbc\xf9x\xfc\x16,1\xc9\b\"3\xb8%\xd0%\xbe?{\x10V\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4a\x91\xdd\u0276J\x8e\b\x90\xb427\t\u05e0|H\xb9*d\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4a\x96\xc3\xd3\xc0\x90\x8d%Cf\xb7\xbc\xa5WE\"-\x9dM\xb1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\x9f\x17\x14E\xd4+\x02\xe2\xe0p\x04\xad\x8a\xfeiO\xa5=j\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4a\xad\xf5\x92\x9a^)\x81hN\xa2C\xba\xa0\x1f}\x1f^\x14\x8a\x89\x05\xfa\xbfl\x98O#\x00\x00\u07d4a\xb1\xb8\xc0\x12\xcdLx\xf6\x98\xe4p\xf9\x02V\xe6\xa3\x0fH\u0749\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xb3\xdf.\x9e\x9f\xd9h\x13\x1f\x1e\x88\xf0\xa0\xeb[\xd7eFM\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\xb9\x02\u0166s\x88X&\x82\r\x1f\xe1EI\xe4\x86_\xbd\u0089\x12$\xef\xed*\u1440\x00\u07d4a\xb9\x05\xdef?\xc1s\x86R;:(\xe2\xf7\xd07\xa6U\u0349\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xba\x87\xc7~\x9bYm\xe7\xba\x0e2o\xdd\xfe\xec!c\xeff\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xbf\x84\u056b\x02oX\xc8s\xf8o\xf0\xdf\u0282\xb5W3\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xc4\xee|\x86LMk^7\xea\x131\xc2\x03s\x9e\x82k/\x89\x01\xa15;8*\x91\x80\x00\u07d4a\xc80\xf1eG\x18\xf0u\u032b\xa3\x16\xfa\xac\xb8[}\x12\v\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4a\xc8\xf1\xfaC\xbf\x84i\x99\xec\xf4{+2M\xfbkc\xfe:\x89+^:\xf1k\x18\x80\x00\x00\u07d4a\xc9\xdc\u8c98\x1c\xb4\x0e\x98\xb0@+\xc3\xeb(4\x8f\x03\xac\x89\n\xac\xac\u0679\xe2+\x00\x00\u07d4a\u03a7\x1f\xa4d\xd6*\a\x06?\x92\v\f\xc9\x17S\x973\u0609Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4a\xd1\x01\xa03\xee\x0e.\xbb1\x00\xed\xe7f\xdf\x1a\xd0$IT\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xedU\x96\u0197 \u007f=U\xb2\xa5\x1a\xa7\xd5\x0f\a\xfa\t\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xff\x8eg\xb3M\x9e\xe6\xf7\x8e\xb3o\xfe\xa1\xb9\xf7\xc1W\x87\xaf\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4b\x05\xc2\xd5dtp\x84\x8a8@\xf3\x88~\x9b\x01]4u\\\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4b(\xad\xe9^\x8b\xb1}\x1a\xe2;\xfb\x05\x18AMI~\x0e\xb8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94b)\xdc\xc2\x03\xb1\xed\xcc\xfd\xf0n\x87\x91\fE*\x1fMzr\x8a\x06\xe1\xd4\x1a\x8f\x9e\xc3P\x00\x00\u0794b+\xe4\xb4T\x95\xfc\xd91C\xef\xc4\x12\u0599\xd6\xcd\xc2=\u0148\xf0\x15\xf2W6B\x00\x00\u07d4b3\x1d\xf2\xa3\xcb\xee5 \xe9\x11\u07a9\xf7>\x90_\x89%\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4bVD\xc9Z\x87>\xf8\xc0l\u06de\x9fm\x8dv\x80\x04=b\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4be\xb2\xe7s\x0f6\xb7v\xb5-\f\x9d\x02\xad\xa5]\x8e<\xb6\x8965\u026d\xc5\u07a0\x00\x00\u07d4bh\n\x15\xf8\u0338\xbd\xc0/s`\xc2Z\xd8\u03f5{\x8c\u034965\u026d\xc5\u07a0\x00\x00\u07d4b\x94\xea\xe6\xe4 \xa3\xd5`\n9\xc4\x14\x1f\x83\x8f\xf8\xe7\xccH\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4b\x97\x1b\xf2cL\xee\v\xe3\u0249\x0fQ\xa5`\x99\u06f9Q\x9b\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4b\x9b\xe7\xab\x12jS\x98\xed\xd6\u069f\x18D~x\u0192\xa4\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4b\xb4\xa9\"nah\a\x1el\xbea\x11\xfe\xf0\xbcc\x8a\x03\xba\x19\x10\xbf4\x1b\x00\x00\x00\xe0\x94c\n\x91:\x901\xc9I*\xbdLA\u06f1PT\xcf\xecD\x16\x8a\x014X\xdbg\xaf5\xe0\x00\x00\xe0\x94c\fRs\x12mQ|\xe6q\x01\x81\x1c\xab\x16\xb8SL\xf9\xa8\x8a\x01\xfe\xcc\xc6%s\xbb\u04c0\x00\u07d4c\x100\xa5\xb2{\a(\x8aEio\x18\x9e\x11\x14\xf1*\x81\xc0\x89\x1b\x1azB\v\xa0\r\x00\x00\u07d4c\x10\xb0 \xfd\x98\x04IW\x99P\x92\t\x0f\x17\xf0NR\xcd\xfd\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4c+\x91I\xd7\x01x\xa7364'^\x82\u0555?'\x96{\x89%\xf2s\x93=\xb5p\x00\x00\u07d4c,\xec\xb1\f\xfc\xf3\x8e\u0246\xb4;\x87p\xad\xec\xe9 \x02!\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c1\x02\x8c\xbbZ!H[\xc5\x1bVQB\x99;\xdb%\x82\xa9\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4c3O\xcf\x17E\x84\x0eK\tJ;\xb4\v\xb7o\x96\x04\xc0L\x89\u05e5\xd7\x03\xa7\x17\xe8\x00\x00\u07d4c4\nWqk\xfac\xebl\xd13r\x12\x02W[\xf7\x96\xf0\x89\va\xe0\xa2\f\x12q\x80\x00\u07d4cN\xfc$7\x11\a\xb4\xcb\xf0?y\xa9=\xfd\x93\xe41\xd5\xfd\x89B5\x82\xe0\x8e\xdc\\\x80\x00\xe0\x94c\\\x00\xfd\xf05\xbc\xa1_\xa3a\r\xf38N\x0f\xb7\x90h\xb1\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4ca.xb\xc2{X|\xfbm\xaf\x99\x12\xcb\x05\x1f\x03\n\x9f\x89\x02[\x19\u053f\xe8\xed\x00\x00\u07d4cfgU\xbdA\xb5\x98i\x97x<\x13\x040\b$+<\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4c{\xe7\x1b:\xa8\x15\xffE=VB\xf70tE\vd\xc8*\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94c}g\xd8\u007fXo\nZG\x9e \xee\x13\xea1\n\x10\xb6G\x8a\n:Y&\xaf\xa1\xe70\x00\x00\u07d4c\u007fXi\xd6\xe4i_\x0e\xb9\xe2s\x11\u0107\x8a\xff33\x80\x89j\xc0Nh\xaa\xec\x86\x00\x00\u07d4c\x97|\xad}\r\xcd\xc5+\x9a\xc9\xf2\xff\xa16\xe8d(\x82\xb8\x89\x04\x10\u0546\xa2\nL\x00\x00\u07d4c\xa6\x1d\xc3\n\x8e;0\xa7c\xc4!<\x80\x1c\xbf\x98s\x81x\x8965\u026d\xc5\u07a0\x00\x00\u07d4c\xacT\\\x99\x12C\xfa\x18\xae\xc4\x1dOoY\x8eUP\x15\u0709 \x86\xac5\x10R`\x00\x00\u07d4c\xb9uMu\xd1-8@9\xeci\x06<\v\xe2\x10\xd5\xe0\u3252\v\x86\f\xc8\xec\xfd\x80\x00\u07d4c\xbbfO\x91\x17\x03v(YM\xa7\xe3\xc5\b\x9f\xd6\x18\xb5\xb5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c\u00a3\xd25\xe5\xee\xab\xd0\u0526\xaf\u06c9\xd9F'9d\x95\x89CN\xf0[\x9d\x84\x82\x00\x00\u07d4c\xc8\xdf\xde\v\x8e\x01\xda\xdc.t\x8c\x82L\xc06\x9d\U00010cc9\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4c\xd5Z\u065b\x917\xfd\x1b \xcc+O\x03\xd4,\xba\xdd\xf34\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4c\xd8\x00H\x87u\x96\xe0\u0084\x89\xe6P\xcdJ\xc1\x80\tjI\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94c\xe4\x14`>\x80\xd4\xe5\xa0\xf5\xc1\x87t FB%\x82\b\xe4\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94c\xe8\x8e.S\x9f\xfbE\x03\x86\xb4\xe4g\x89\xb2#\xf5GlE\x8a\x01U\x17\nw\x8e%\xd0\x00\x00\u07d4c\xef/\xbc=\xaf^\xda\xf4\xa2\x95b\x9c\xcf1\xbc\xdf@8\xe5\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4c\xf0\xe5\xa7R\xf7\x9fg\x12N\xedc:\xd3\xfd'\x05\xa3\x97\u0509\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94c\xf5\xb5=y\xbf.A\x14\x89Re0\"8E\xfa\xc6\xf6\x01\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4c\xfc\x93\x00\x13\x05\xad\xfb\u0278])\xd9)\x1a\x05\xf8\xf1A\v\x8965\u026d\xc5\u07a0\x00\x00\u0794c\xfek\xccK\x8a\x98P\xab\xbeu\x8070\xc92%\x1f\x14[\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4d\x03\xd0bT\x96\x90\xc8\xe8\xb6>\xaeA\xd6\xc1\tGn%\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4d\x04+\xa6\x8b\x12\xd4\xc1Qe\x1c\xa2\x81;sR\xbdV\xf0\x8e\x89 \x86\xac5\x10R`\x00\x00\u0794d\x05\xdd\x13\xe9:\xbc\xff7~p\x0e<\x1a\x00\x86\xec\xa2})\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94d\n\xbam\xe9\x84\xd9E\x177x\x03p^\xae\xa7\t_J\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4d\v\xf8t\x15\xe0\xcf@s\x01\xe5Y\x9ah6m\xa0\x9b\xba\u0209\x1a\xbc\x9fA`\x98\x15\x80\x00\u07d4d \xf8\xbc\xc8\x16JaR\xa9\x9dk\x99i0\x05\xcc\xf7\xe0S\x8965f3\xeb\xd8\xea\x00\x00\u07d4d$\x1axD)\x0e\n\xb8U\xf1\u052au\xb5SE\x03\"$\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4d&J\xed\xd5-\xca\xe9\x18\xa0\x12\xfb\xcd\f\x03\x0e\xe6\xf7\x18!\x8965\u026d\xc5\u07a0\x00\x00\u07d4d7\x0e\x87 &E\x12Z5\xb2\a\xaf\x121\xfb`r\xf9\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4d=\x9a\xee\u0531\x80\x94~\u04b9 |\xceL=\xdcU\xe1\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4dC\xb8\xaec\x9d\xe9\x1c\xf7\xf0p\xa5G\x03\xb7\x18NH'l\\\x00w\xefK4\x89\x11X\xe4`\x91=\x00\x00\x00\xe0\x94d\xe2\xde! \v\x18\x99\u00e0\xc0e;P@\x13m\r\xc8B\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4d\xec\x8a[t?4y\xe7\a\xda\xe9\xee \u076aO@\xf1\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e\x03\x86\v\x19\x10\b\xc1U\x83\xbf\u0201X\t\x93\x01v((\x8965\u026d\xc5\u07a0\x00\x00\u07d4e\x051\x911\x9e\x06z%\xe66\x1dG\xf3\u007fc\x18\xf84\x19\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4e\t;#\x9b\xbf\xba#\xc7w\\\xa7\xdaZ\x86H\xa9\xf5L\xf7\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4e\t\xee\xb14~\x84/\xfbA>7\x15^,\xbcs\x82s\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94e\vBUU\xe4\xe4\xc5\x17\x18\x14h6\xa2\xc1\xeew\xa5\xb4!\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4e\f\xf6}\xb0`\xcc\xe1uh\xd5\xf2\xa4#h|Idv\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4e\x10\xdfB\xa5\x99\xbc\xb0\xa5\x19\u0329a\xb4\x88u\x9aogw\x89lk\x93[\x8b\xbd@\x00\x00\u07d4e6u\xb8B\xd7\u0634a\xf7\"\xb4\x11|\xb8\x1d\xac\x8ec\x9d\x89\x01\xae6\x1f\xc1E\x1c\x00\x00\u07d4eK~\x80\x87\x99\xa8=r\x87\xc6w\x06\xf2\xab\xf4\x9aId\x04\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94eORHG\xb3\xa6\xac\xc0\xd3\xd5\xf1\xf3b\xb6\x03\xed\xf6_\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4eY4\u068etN\xaa=\xe3M\xbb\xc0\x89LN\xda\va\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e]\\\xd7H\x96)\xe2ANIb?\xabb\xa1~M6\x11\x89\x05\fL\xb2\xa1\f`\x00\x00\u07d4e\xaf\x8d\x8b[\x1d\x1e\xed\xfaw\xbc\xbc\x96\xc1\xb13\xf83\x06\u07c9\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4e\xaf\x90\x87\xe0QgqT\x97\u0265\xa7I\x18\x94\x89\x00M\xef\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u0794e\xb4/\xae\xcc\x1e\u07f1B\x83\u0297\x9a\xf5E\xf6;0\xe6\f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u0794e\xd3>\xb3\x9c\xdadS\xb1\x9ea\xc1\xfeM\xb91p\xef\x9d4\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4e\xd8\xddN%\x1c\xbc\x02\x1f\x05\xb0\x10\xf2\xd5\xdcR\f8r\xe0\x89-CW\x9a6\xa9\x0e\x00\x00\u07d4e\xea&\xea\xbb\xe2\xf6L\xcc\xcf\xe0h)\xc2]F7R\x02%\x89%\xf2s\x93=\xb5p\x00\x00\u07d4e\xeag\xad?\xb5j\xd5\xfb\x948}\u04ce\xb3\x83\x00\x1d|h\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94e\xeb\xae\xd2~\u06dd\xcc\x19W\xae\xe5\xf4R\xac!\x05\xa6\\\x0e\x8a\t7\u07ed\xae%\u26c0\x00\u07d4e\xee \xb0m\x9a\u0549\xa7\xe7\xce\x04\xb9\xf5\xf7\x95\xf4\x02\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4e\xf544m/\xfbx\u007f\xa9\xcf\x18]t[\xa4)\x86\xbdn\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94e\xf5\x87\x0f&\xbc\xe0\x89g}\xfc#\xb5\x00\x1e\xe4\x92H4(\x8a\x01\x12\xb1\xf1U\xaa2\xa3\x00\x00\u07d4e\xfd\x02\xd7\x04\xa1*M\xac\xe9G\x1b\x06E\xf9b\xa8\x96q\u0209\x01\x8d\x1c\xe6\xe4'\u0340\x00\u07d4e\xff\x87O\xaf\xceM\xa3\x18\xd6\xc9=W\xe2\u00ca\rs\xe8 \x8968\x02\x1c\xec\u06b0\x00\x00\xe0\x94f\x05W\xbbC\xf4\xbe:\x1b\x8b\x85\xe7\xdf{<[\xcdT\x80W\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4f\b,u\xa8\xde1\xa59\x13\xbb\xd4M\xe3\xa07O\u007f\xaaA\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4f\x11\xceY\xa9\x8b\a*\xe9Y\xdcI\xadQ\x1d\xaa\xaa\xa1\x9dk\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4f \x1b\xd2'\xaem\u01bd\xfe\xd5\xfb\u0781\x1f\xec\xfe^\x9d\u0649 >\x9e\x84\x92x\x8c\x00\x00\u07d4f#4\x81G$\x93[y1\xdd\xcaa\x00\xe0\rFw'\u0349\"\x88&\x9d\a\x83\xd4\x00\x00\u07d4f'O\xea\x82\xcd0\xb6\u009b#5\x0eOO=1\nX\x99\x89p7\x05P\xab\x82\x98\x00\x00\u07d4f,\xfa\x03\x8f\xab7\xa0\x17E\xa3d\u1e41'\xc5\x03tm\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4f5\xb4oq\x1d-\xa6\xf0\xe1cp\u034e\xe4>\xfb,-R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4f6\x04\xb0P0F\xe6$\xcd&\xa8\xb6\xfbGB\xdc\xe0*o\x89\x03\x8b\x9by~\xf6\x8c\x00\x00\u07d4f6\u05ecczH\xf6\x1d8\xb1L\xfdHe\xd3m\x14(\x05\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f@\xcc\xf0SU\\\x13\n\xe2\xb6Vd~\xa6\xe3\x167\xb9\xab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4fBK\xd8x[\x8c\xb4a\x10*\x90\x02\x83\xc3]\xfa\a\xefj\x89\x02.-\xb2ff\xfc\x80\x00\u07d4fL\xd6}\xcc\u026c\x82(\xb4\\U\u06cdvU\ve\x9c\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4fNC\x11\x98p\xaf\x10zD\x8d\xb1'\x8b\x04H8\xff\u036f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4fQso\xb5\x9b\x91\xfe\xe9\xc9:\xa0\xbdn\xa2\xf7\xb2Pa\x80\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f[\x00\x0f\vw'P\xcc\x89k\x91\x8a\xacIK\x16\x80\x00\xe0\x94g]\\\xaa`\x9b\xf7\n\x18\xac\xa5\x80F]\x8f\xb71\r\x1b\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4gc F\u0732ZT\x93i(\xa9oB?3 \xcb\ud489lk\x93[\x8b\xbd@\x00\x00\u07d4ge\xdf%(\x0e\x8eO8\u0531\xcfDo\xc5\xd7\xebe\x9e4\x89\x05k\xc7^-c\x10\x00\x00\u07d4gv\xe13\xd9\xdc5L\x12\xa9Q\b{c\x96P\xf59\xa43\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4g\x85Q<\xf72\xe4~\x87g\ap\xb5A\x9b\xe1\f\xd1\xfct\x89lk\x93[\x8b\xbd@\x00\x00\u07d4g\x947\xea\xcfCxx\xdc)=H\xa3\x9c\x87\xb7B\x1a!l\x89\x03\u007f\x81\x82\x1d\xb2h\x00\x00\u07d4g\x9b\x9a\x10\x990Q~\x89\x99\t\x9c\xcf*\x91LL\x8d\xd94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4g\xa8\x0e\x01\x90r\x1f\x949\rh\x02r\x9d\xd1,1\xa8\x95\xad\x89lk\x13u\xbc\x91V\x00\x00\u07d4g\xb8\xa6\xe9\x0f\xdf\n\x1c\xacD\x17\x930\x1e\x87P\xa9\xfayW\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4g\xbc\x85\xe8}\xc3LN\x80\xaa\xfa\x06k\xa8\u049d\xbb\x8eC\x8e\x89\x15\xd1\xcfAv\xae\xba\x00\x00\u07d4g\xc9&\t>\x9b\x89'\x938\x10\u0642\"\xd6.+\x82\x06\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4g\xcf\xdanp\xbfvW\u04d0Y\xb5\x97\x90\xe5\x14Z\xfd\xbea\x89#\x05\r\tXfX\x00\x00\u07d4g\u0582\xa2\x82\xefs\xfb\x8dn\x90q\xe2aOG\xab\x1d\x0f^\x8965\u026d\xc5\u07a0\x00\x00\u07d4g\u05a8\xaa\x1b\xf8\xd6\xea\xf78N\x99=\xfd\xf1\x0f\n\xf6\x8aa\x89\n\xbc\xbbW\x18\x97K\x80\x00\u07d4g\u0692.\xff\xa4r\xa6\xb1$\xe8N\xa8\xf8k$\xe0\xf5\x15\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4g\xdf$-$\r\u0538\a\x1dr\xf8\xfc\xf3[\xb3\x80\x9dq\xe8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4g\xee@n\xa4\xa7\xaej:8\x1e\xb4\xed\xd2\xf0\x9f\x17KI(\x898)c_\th\xb0\x00\x00\u07d4g\xf2\xbbx\xb8\xd3\xe1\x1f|E\x8a\x10\xb5\xc8\xe0\xa1\xd3tF}\x89a\t=|,m8\x00\x00\u07d4g\xfcR}\xce\x17\x85\xf0\xfb\x8b\xc7\xe5\x18\xb1\xc6i\xf7\xec\u07f5\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4h\x02}\x19U\x8e\xd73\x9a\b\xae\xe8\xde5Y\xbe\x06>\xc2\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\x06@\x83\x8b\xd0zD{\x16\x8dm\x92;\x90\xcflC\xcd\u0289]\u0212\xaa\x111\xc8\x00\x00\u07d4h\a\xdd\u020d\xb4\x89\xb03\xe6\xb2\xf9\xa8\x15SW\x1a\xb3\xc8\x05\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94h\rY\x11\xed\x8d\xd9\xee\xc4\\\x06\f\"?\x89\xa7\xf6 \xbb\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4h\x11\xb5L\u0456c\xb1\x1b\x94\xda\x1d\xe2D\x82\x85\u035fh\u0649;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4h\x19\f\xa8\x85\xdaB1\x87L\x1c\xfbB\xb1X\n!s\u007f8\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94h(\x97\xbcO\x8e\x89\x02\x91 \xfc\xff\xb7\x87\xc0\x1a\x93\xe6A\x84\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h)^\x8e\xa5\xaf\xd9\t?\xc0\xa4e\xd1W\x92+]*\xe24\x89\x01\x15NS!}\xdb\x00\x00\u07d4h.\x96'oQ\x8d1\xd7\xe5n0\u07f0\t\xc1!\x82\x01\xbd\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4h5\xc8\xe8\xb7J,\xa2\xae?J\x8d\x0fk\x95J>*\x83\x92\x89\x03B\x9c3]W\xfe\x00\x00\u07d4h63\x01\n\x88hk\xeaZ\x98\xeaS\xe8y\x97\xcb\xf7>i\x89\x05k9Bc\xa4\f\x00\x00\u07d4h=\xba6\xf7\xe9O@\xeaj\xea\ry\xb8\xf5!\xdeU\an\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4hA\x9cm\xd2\xd3\xceo\u02f3\xc7>/\xa0y\xf0`Q\xbd\xe6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4hG;z}\x96Y\x04\xbe\u06e5V\u07fc\x17\x13l\xd5\xd44\x89\x05k\xc7^-c\x10\x00\x00\u07d4hG\x82[\xde\xe8$\x0e(\x04,\x83\xca\xd6B\U000868fd\u0709QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94hJD\xc0i3\x9d\b\xe1\x9auf\x8b\u06e3\x03\xbe\x85S2\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4hS\x1fM\u0680\x8fS vz\x03\x114(\xca\f\xe2\xf3\x89\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4hy'\xe3\x04\x8b\xb5\x16*\xe7\xc1\\\xf7k\xd1$\xf9I{\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94h\x80\x9a\xf5\xd52\xa1\x1c\x1aMn2\xaa\xc7\\LR\xb0\x8e\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h\x86\xad\xa7\xbb\xb0a{\u0684!\x91\u018c\x92.\xa3\xa8\xac\x82\x89>\xe2;\xde\x0e} \x00\x00\xe0\x94h\x88>\x15.V`\xfe\xe5\x96&\xe7\xe3\xb4\xf0Q\x10\xe6\"/\x8a\v\x94c;\xe9u\xa6*\x00\x00\u07d4h\x8aV\x9e\x96U$\xeb\x1d\n\xc3\xd3s>\xab\x90\x9f\xb3\xd6\x1e\x89G\x8e\xae\x0eW\x1b\xa0\x00\x00\xe0\x94h\x8e\xb3\x85;\xbc\xc5\x0e\xcf\xee\x0f\xa8\u007f\n\xb6\x93\u02bd\xef\x02\x8a\x06\xb1\n\x18@\x06G\xc0\x00\x00\u07d4h\xa7B_\xe0\x9e\xb2\x8c\xf8n\xb1y>A\xb2\x11\xe5{\u058d\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4h\xa8l@#\x88\xfd\xdcY\x02\x8f\xecp!\u933f\x83\x0e\xac\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94h\xac\u06a9\xfb\x17\xd3\xc3\t\x91\x1aw\xb0_S\x91\xfa\x03N\xe9\x8a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4h\xad\xdf\x01\x9dk\x9c\xabp\xac\xb1?\v1\x17\x99\x9f\x06.\x12\x89\x02\xb5\x12\x12\xe6\xb7\u0200\x00\u07d4h\xb3\x186\xa3\n\x01j\xda\x15{c\x8a\xc1]\xa7?\x18\xcf\u0789\x01h\u048e?\x00(\x00\x00\xe0\x94h\xb6\x85G\x88\xa7\xc6Il\xdb\xf5\xf8K\x9e\xc5\xef9+x\xbb\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4h\xc0\x84\x90\u021b\xf0\u05b6\xf3 \xb1\xac\xa9\\\x83\x12\xc0\x06\b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4h\xc7\xd1q\x1b\x01\x1a3\xf1o\x1fU\xb5\xc9\x02\xcc\xe9p\xbd\u05c9\b=lz\xabc`\x00\x00\u07d4h\xc8y\x1d\xc3B\xc3sv\x9e\xa6\x1f\xb7\xb5\x10\xf2Q\xd3 \x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\u07d4|I[\ubbb8\u8273\xf9S\xd53\x87K\xf1\x06\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4h\xe8\x02'@\xf4\xaf)\xebH\xdb2\xbc\xec\xdd\xfd\x14\x8d=\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\xecy\u057eqUql@\x94\x1cy\u05cd\x17\u079e\xf8\x03\x89\x1b#8w\xb5 \x8c\x00\x00\u07d4h\xee\xc1\u222c1\xb6\xea\xba~\x1f\xbdO\x04\xadW\x9ak]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\xf5%\x92\x1d\xc1\x1c2\x9buO\xbf>R\x9f\xc7#\xc84\u0349WG=\x05\u06ba\xe8\x00\x00\u07d4h\xf7\x19\xae4+\xd7\xfe\xf1\x8a\x05\u02f0/pZ\u04ce\u0572\x898\xeb\xad\\\u0710(\x00\x00\xe0\x94h\xf7W<\xd4W\xe1L\x03\xfe\xa4>0-04|\x10p\\\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4h\xf8\xf4QU\xe9\x8cP)\xa4\xeb\u0175'\xa9.\x9f\xa81 \x89\xf0{D\xb4\a\x93 \x80\x00\u07d4h\xfe\x13W!\x8d\tXI\xcdW\x98B\u012a\x02\xff\x88\x8d\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x02(\xe4\xbb\x12\xa8\u0535\u09d7\xb0\xc5\xcf*u\t\x13\x1e\x89e\xea=\xb7UF`\x00\x00\u07d4i\x05\x94\xd3\x06a<\xd3\xe2\xfd$\xbc\xa9\x99J\u064a=s\xf8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94i\a2ir\x9ed\x14\xb2n\xc8\xdc\x0f\xd95\xc7;W\x9f\x1e\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94i\x19\xdd^]\xfb\x1a\xfa@G\x03\xb9\xfa\xea\x8c\xee5\xd0\rp\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4i4\x92\xa5\xc5\x13\x96\xa4\x82\x88\x16i\xcc\xf6\xd8\xd7y\xf0\tQ\x89\x12\xbfPP:\xe3\x03\x80\x00\u07d4i=\x83\xbe\tE\x9e\xf89\v.0\xd7\xf7\u008d\xe4\xb4(N\x89lk\x93[\x8b\xbd@\x00\x00\u07d4iQp\x83\xe3\x03\xd4\xfb\xb6\xc2\x11E\x14!]i\xbcF\xa2\x99\x89\x05k\xc7^-c\x10\x00\x00\u07d4iUPel\xbf\x90\xb7]\x92\xad\x91\"\xd9\r#\xcah\xcaM\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94iX\xf8;\xb2\xfd\xfb'\xce\x04\t\xcd\x03\xf9\xc5\xed\xbfL\xbe\u074a\x04<3\xc1\x93ud\x80\x00\x00\u0794i[\x0fRBu7\x01\xb2d\xa6pq\xa2\u0708\b6\xb8\u06c8\u3601\x1b\xech\x00\x00\xe0\x94i[L\xce\bXV\xd9\xe1\xf9\xff>y\x94 #5\x9e_\xbc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94if\x06:\xa5\xde\x1d\xb5\xc6q\xf3\xddi\x9dZ\xbe!>\xe9\x02\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4it\u0224\x14\u03ae\xfd<.M\xfd\xbe\xf40V\x8d\x9a\x96\v\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\xe0\x94iximQP\xa9\xa2cQ?\x8ft\u0196\xf8\xb19|\xab\x8a\x01g\xf4\x82\xd3\u0171\xc0\x00\x00\xe0\x94iy{\xfb\x12\u027e\u0582\xb9\x1f\xbcY5\x91\xd5\xe4\x027(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94i\u007fUSk\xf8Z\xdaQ\x84\x1f\x02\x87b:\x9f\x0e\u041a\x17\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4i\x82\xfe\x8a\x86~\x93\xebJ\v\xd0QX\x93\x99\xf2\xec\x9aR\x92\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x8a\x8ao\x01\xf9\xabh/c|yi\xbe\x88_lS\x02\xbf\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4i\x8a\xb9\xa2\xf33\x81\xe0|\fGC=\r!\xd6\xf36\xb1'\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4i\x94\xfb21\xd7\xe4\x1dI\x1a\x9dh\xd1\xfaL\xae,\xc1Y`\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\x9c\x9e\xe4q\x95Q\x1f5\xf8b\xcaL\"\xfd5\xae\x8f\xfb\xf4\x89\x04V9\x18$O@\x00\x00\u07d4i\x9f\xc6\u058aGuW<\x1d\u036e\xc80\xfe\xfdP9|N\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4i\xaf(\xb0tl\xac\r\xa1p\x84\xb99\x8c^6\xbb:\r\xf2\x896w\x03n\xdf\n\xf6\x00\x00\u07d4i\xb8\x0e\xd9\x0f\x84\x83J\xfa?\xf8.\xb9dp;V\tw\u0589\x01s\x17\x90SM\xf2\x00\x00\xe0\x94i\xb8\x1dY\x81\x14\x1e\u01e7\x14\x10`\xdf\u03cf5\x99\xff\xc6>\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4i\xbc\xfc\x1dC\xb4\xba\x19\xde{'K\xdf\xfb5\x13\x94\x12\xd3\u05c95e\x9e\xf9?\x0f\xc4\x00\x00\u07d4i\xbd%\xad\xe1\xa34lY\xc4\xe90\xdb*\x9dq^\xf0\xa2z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\xc0\x8dtGT\xdep\x9c\xe9n\x15\xae\r\x1d9[:\"c\x8965\u026d\xc5\u07a0\x00\x00\u07d4i\xc2\xd85\xf1>\xe9\x05\x80@\x8ej2\x83\xc8\u0326\xa44\xa2\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4i\xc9N\a\u0129\xbe3\x84\xd9]\xfa<\xb9)\x00Q\x87;{\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4i\xcb>!S\x99\x8d\x86\xe5\xee \xc1\xfc\u0466\xba\uec86?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\u04ddQ\b\x89\xe5R\xa3\x96\x13[\xfc\xdb\x06\xe3~8v3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94i\u064f8\xa3\xba=\xbc\x01\xfa\\,\x14'\xd8b\x83//p\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94i\xe2\xe2\xe7\x040|\xcc[\\\xa3\xf1d\xfe\xce.\xa7\xb2\xe5\x12\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4i\xffB\x90t\u02dblc\xbc\x91B\x84\xbc\xe5\xf0\xc8\xfb\xf7\u0409\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4i\xff\x89\x01\xb5Av?\x81|_)\x98\xf0-\xcf\xc1\xdf)\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4j\x02:\xf5}XM\x84^i\x876\xf10\u06dd\xb4\r\xfa\x9a\x89\x05[ \x1c\x89\x00\x98\x00\x00\u07d4j\x04\xf5\xd5?\xc0\xf5\x15\xbe\x94+\x8f\x12\xa9\xcbz\xb0\xf3\x97x\x89\xa9\xaa\xb3E\x9b\xe1\x94\x00\x00\u07d4j\x05\xb2\x1cO\x17\xf9\xd7?_\xb2\xb0\u02c9\xffSV\xa6\xcc~\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94j\x0f\x05`f\xc2\xd5f(\x85\x02s\xd7\xec\xb7\xf8\xe6\xe9\x12\x9e\x8a\x01\x0f\r)<\u01e5\x88\x00\x00\u07d4j\x13\xd5\xe3,\x1f\xd2m~\x91\xffn\x051`\xa8\x9b,\x8a\xad\x89\x02\xe6/ \xa6\x9b\xe4\x00\x00\u07d4j.\x86F\x9a[\xf3|\xee\x82\xe8\x8bL8c\x89](\xfc\xaf\x89\x1c\"\x92f8[\xbc\x00\x00\u07d4j6\x94BL|\u01b8\xbc\u067c\u02baT\f\xc1\xf5\xdf\x18\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94jB\u0297\x1cex\u056d\xe2\x95\xc3\xe7\xf4\xad3\x1d\xd3BN\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4jD\xaf\x96\xb3\xf02\xaed\x1b\xebg\xf4\xb6\xc83B\xd3|]\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4jL\x89\a\xb6\x00$\x80W\xb1\xe4cT\xb1\x9b\u0705\x9c\x99\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jQNbB\xf6\xb6\x8c\x13~\x97\xfe\xa1\u73b5U\xa7\xe5\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jS\xd4\x1a\xe4\xa7R\xb2\x1a\xbe\xd57FI\x95:Q=\xe5\xe5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4jaY\aJ\xb5s\xe0\xeeX\x1f\x0f=\xf2\u05a5\x94b\x9bt\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4jc7\x83?\x8fjk\xf1\f\xa7\xec!\xaa\x81\x0e\xd4D\xf4\u02c97\xbd$4\\\xe8\xa4\x00\x00\u07d4jcS\xb9qX\x9f\x18\xf2\x95\\\xba(\xab\xe8\xac\xcejWa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4jc\xfc\x89\xab\xc7\xf3n(-\x80x{{\x04\xaf\xd6U>q\x89\b\xacr0H\x9e\x80\x00\x00\u07d4jg\x9e7\x8f\xdc\xe6\xbf\xd9\u007f\xe6/\x04)Z$\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4j\x8c\xea-\xe8J\x8d\xf9\x97\xfd?\x84\xe3\b=\x93\xdeW\u0369\x89\x05k\xe0<\xa3\xe4}\x80\x00\xe0\x94j\x97Xt;`>\xea:\xa0RKB\x88\x97#\xc4\x159H\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4j\xa5s/;\x86\xfb\x8c\x81\xef\xbek[G\xb5cs\v\x06\u020965\u026d\xc5\u07a0\x00\x00\u07d4j\xb3#\xaePV\xed\nE0r\u016b\xe2\xe4/\xcf]q9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4j\xb5\xb4\xc4\x1c\u0778)i\f/\xda\u007f \xc8^b\x9d\xd5\u0549d\u052fqL2\x90\x00\x00\u07d4j\xc4\x0fS-\xfe\xe5\x11\x81\x17\u04ad5-\xa7}Om\xa2\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xc4\u053e-\xb0\u065d\xa3\xfa\xaa\xf7RZ\xf2\x82\x05\x1dj\x90\x89\x04X\xcaX\xa9b\xb2\x80\x00\u07d4j\xcd\u0723\xcd+I\x90\xe2\\\xd6\\$\x14\x9d\t\x12\t\x9ey\x89\xa2\xa1\xe0|\x9fl\x90\x80\x00\u07d4j\xd9\v\xe2R\xd9\xcdFM\x99\x81%\xfa\xb6\x93\x06\v\xa8\xe4)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4j\u0753!\x93\xcd8IJ\xa3\xf0:\xec\xccKz\xb7\xfa\xbc\xa2\x89\x04\xdbs%Gc\x00\x00\x00\xe0\x94j\xe5\u007f'\x91|V*\x13*M\x1b\xf7\xec\n\u01c5\x83)&\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4j\xeb\x9ftt.\xa4\x91\x81=\xbb\xf0\xd6\xfc\xde\x1a\x13\x1dM\xb3\x89\x17\xe5T0\x8a\xa00\x00\x00\u07d4j\xf25\u04bb\xe0P\xe6)\x16\x15\xb7\x1c\xa5\x82\x96X\x81\x01B\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf6\xc7\xee\x99\xdf'\x1b\xa1[\xf3\x84\xc0\xb7d\xad\xcbM\xa1\x82\x8965f3\xeb\xd8\xea\x00\x00\u07d4j\xf8\xe5Yih,q_H\xadO\xc0\xfb\xb6~\xb5\x97\x95\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4j\xf9@\xf6>\u0278\xd8v'*\u0296\xfe\xf6\\\xda\xce\xcd\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf9\xf0\xdf\uebbb_d\xbf\x91\xabw\x16i\xbf\x05)US\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xff\x14f\xc2b6u\xe3\xcb\x0eu\xe4#\xd3z%\xe4B\xeb\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94k\r\xa2Z\xf2g\u05c3l\"k\xca\xe8\xd8r\xd2\xceR\xc9A\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4k\x10\xf8\xf8\xb3\xe3\xb6\r\xe9\n\xa1-\x15_\x9f\xf5\xff\xb2,P\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x17Y\x8a\x8e\xf5Oyz\xe5\x15\u0336Q}\x18Y\xbf\x80\x11\x89\x05k\xc7^-c\x10\x00\x00\u07d4k \xc0\x80`jy\xc7;\xd8\xe7[\x11qzN\x8d\xb3\xf1\u00c9\x10?sX\x03\xf0\x14\x00\x00\u07d4k\"\x84D\x02!\xce\x16\xa88-\xe5\xff\x02)G\"i\xde\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4k0\xf1\x829\x10\xb8m:\xcbZj\xfc\x9d\xef\xb6\xf3\xa3\v\xf8\x89\u3bb5sr@\xa0\x00\x00\u07d4k8\u0784\x1f\xad\u007fS\xfe\x02\xda\x11[\xd8j\xaff$f\xbd\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4kK\x99\xcb?\xa9\xf7\xb7L\u3903\x17\xb1\xcd\x13\t\n\x1az\x89\x03\x1b2~i]\xe2\x00\x00\u07d4kZ\xe7\xbfx\xecu\xe9\f\xb5\x03\xc7x\xcc\u04f2KO\x1a\xaf\x89+^:\xf1k\x18\x80\x00\x00\u07d4kc\xa2\u07f2\xbc\xd0\xca\xec\x00\"\xb8\x8b\xe3\f\x14Q\xeaV\xaa\x89+\xdbk\xf9\x1f\u007fL\x80\x00\u07d4kew\xf3\x90\x9aMm\xe0\xf4\x11R-Ep8d\x004\\\x89e\xea=\xb7UF`\x00\x00\u07d4kr\xa8\xf0a\xcf\xe6\x99j\xd4G\xd3\xc7,(\xc0\xc0\x8a\xb3\xa7\x89\xe7\x8cj\u01d9\x12b\x00\x00\u07d4kv\rHw\xe6\xa6'\xc1\xc9g\xbe\xe4Q\xa8P}\xdd\u06eb\x891T\xc9r\x9d\x05x\x00\x00\u07d4k\x83\xba\xe7\xb5e$EXU[\xcfK\xa8\xda \x11\x89\x1c\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x92]\xd5\xd8\xeda2\xabm\b`\xb8,D\xe1\xa5\x1f\x1f\xee\x89P; >\x9f\xba \x00\x00\xe0\x94k\x94a]\xb7Pej\u00cc~\x1c\xf2\x9a\x9d\x13g\u007fN\x15\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4k\x95\x1aC'N\xea\xfc\x8a\t\x03\xb0\xaf.\xc9+\xf1\xef\xc89\x89\x05k\xc7^-c\x10\x00\x00\u07d4k\x99%!\xec\x85#p\x84\x8a\u0597\xcc-\xf6Nc\xcc\x06\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xa8\xf7\xe2_\xc2\xd8qa\x8e$\xe4\x01\x84\x19\x917\xf9\xf6\xaa\x89\x15\xafd\x86\x9ak\xc2\x00\x00\u07d4k\xa9\xb2\x1b5\x10k\xe1Y\xd1\xc1\xc2ez\xc5l\u049f\xfdD\x89\xf2\xdc}G\xf1V\x00\x00\x00\u07d4k\xafz*\x02\xaex\x80\x1e\x89\x04\xadz\xc0Q\b\xfcV\xcf\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94k\xb2\xac\xa2?\xa1bm\x18\xef\xd6w\u007f\xb9}\xb0-\x8e\n\xe4\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4k\xb4\xa6a\xa3:q\xd4$\u051b\xb5\xdf(b.\xd4\xdf\xfc\xf4\x89\",\x8e\xb3\xfff@\x00\x00\u07d4k\xb5\b\x13\x14j\x9a\xddB\xee\"\x03\x8c\x9f\x1fti\xd4\u007fG\x89\n\xdaUGK\x814\x00\x00\u07d4k\xbc?5\x8af\x8d\u0461\x1f\x03\x80\xf3\xf71\bBj\xbdJ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4k\xbd\x1eq\x93\x90\xe6\xb9\x10C\xf8\xb6\xb9\u07c9\x8e\xa8\x00\x1b4\x89llO\xa6\xc3\xdaX\x80\x00\u07d4k\xc8Z\xcdY(r.\xf5\tS1\xee\x88\xf4\x84\xb8\u03c3W\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4k\xd3\xe5\x9f#\x9f\xaf\xe4wk\xb9\xbd\xddk\ue0fa]\x9d\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xd4W\xad\xe0Qy]\xf3\xf2F\\89\xae\xd3\xc5\xde\xe9x\x8964\xbf9\xab\x98x\x80\x00\u07d4k\xe1c\x13d>\xbc\x91\xff\x9b\xb1\xa2\xe1\x16\xb8T\xea\x93:E\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4k\xe7Y^\xa0\xf0hH\x9a'\x01\xecFI\x15\x8d\xdcC\xe1x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\xe9\x03\x0e\xe6\xe2\xfb\u0111\xac\xa3\xde@\"\xd3\x01w+{}\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94k\xec1\x1a\xd0P\b\xb4\xaf5<\x95\x8c@\xbd\x06s\x9a?\xf3\x8a\x03w\xf6*\x0f\nbp\x00\x00\u07d4k\xf7\xb3\xc0e\xf2\xc1\xe7\xc6\xeb\t+\xa0\xd1Pf\xf3\x93\u0478\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4k\xf8o\x1e/+\x802\xa9\\Mw8\xa1\t\xd3\xd0\xed\x81\x04\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4l\x05\xe3N^\xf2\xf4.\u041d\xef\xf1\x02l\xd6k\xcbi`\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4l\b\xa6\xdc\x01s\xc74)U\xd1\xd3\xf2\xc0e\xd6/\x83\xae\u01c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\n\xe9\xf0C\xc84\xd4Bq\xf14\x06Y=\xfe\tO8\x9f\x89RD*\xe13\xb6*\x80\x00\u07d4l\f\xc9\x17\xcb\xee}|\t\x97c\xf1Nd\xdf}4\xe2\xbf\t\x89\r\x8drkqw\xa8\x00\x00\xe0\x94l\x0eq/@\\Yr_\xe8)\xe9wK\xf4\xdf\u007fM\xd9e\x8a\f(h\x88\x9c\xa6\x8aD\x00\x00\xe0\x94l\x10\x12\x05\xb3#\xd7uD\xd6\xdcR\xaf7\xac\xa3\xce\xc6\xf7\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4l\x15\xec5 \xbf\x8e\xbb\xc8 \xbd\x0f\xf1\x97x7T\x94\u03dd\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94l\x1d\xdd3\xc8\x19f\u0706!w`q\xa4\x12\x94\x82\xf2\xc6_\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4l%2\u007f\x8d\u02f2\xf4^V\x1e\x86\xe3]\x88P\xe5:\xb0Y\x89;\xcd\xf9\xba\xfe\xf2\xf0\x00\x00\u07d4l.\x9b\xe6\u052bE\x0f\xd1%1\xf3?\x02\x8caFt\xf1\x97\x89\xc2\x12z\xf8X\xdap\x00\x00\u07d4l5\x9eX\xa1=Ex\xa93\x8e3\\g\xe7c\x9f_\xb4\u05c9\v\xd1[\x94\xfc\x8b(\x00\x00\u07d4l=\x18pA&\xaa\x99\xee3B\xce`\xf5\xd4\xc8_\x18g\u0349\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4lGK\xc6jTx\x00f\xaaOQ.\xef\xa7s\xab\xf9\x19\u01c9\x05\x18\x83\x15\xf7v\xb8\x00\x00\u07d4lNBn\x8d\xc0\x05\u07e3Ql\xb8\xa6\x80\xb0.\ua56e\x8e\x89Hz\x9a0E9D\x00\x00\u07d4lR\xcf\b\x95\xbb5\xe6V\x16\x1eM\xc4j\xe0\xe9m\xd3\xe6,\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4lT\"\xfbK\x14\xe6\u064b`\x91\xfd\xecq\xf1\xf0\x86@A\x9d\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4l\\:T\u0367\xc2\xf1\x18\xed\xbaCN\xd8\x1en\xbb\x11\xddz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4lc\xf8EV\u0490\xbf\u0359\xe44\ue657\xbf\xd7yWz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4lc\xfc\x85\x02\x9a&T\u05db+\xeaM\xe3I\xe4REw\u0149#\xc7W\a+\x8d\xd0\x00\x00\u07d4led\xe5\xc9\xc2N\xaa\xa7D\xc9\xc7\xc9h\xc9\xe2\xc9\xf1\xfb\xae\x89I\x9bB\xa2\x119d\x00\x00\xe0\x94lg\xd6\xdb\x1d\x03Ql\x12\x8b\x8f\xf24\xbf=I\xb2m)A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4lg\xe0\u05f6.*\bPiE\xa5\xdf\xe3\x82c3\x9f\x1f\"\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4lj\xa0\xd3\vdr\x19\x90\xb9PJ\x86?\xa0\xbf\xb5\xe5}\xa7\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u07d4lqJX\xff\xf6\xe9}\x14\xb8\xa5\xe3\x05\xeb$@eh\x8b\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4l\x80\rKI\xba\a%\x04`\xf9\x93\xb8\xcb\xe0\v&j%S\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4l\x80\x8c\xab\xb8\xff_\xbbc\x12\xd9\xc8\xe8J\xf8\xcf\x12\xef\bu\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94l\x82 )!\x8a\xc8\xe9\x8a&\f\x1e\x06@)4\x889\x87[\x8a\x01\x0f\x97\xb7\x87\xe1\xe3\b\x00\x00\u07d4l\x84\u02e7|m\xb4\xf7\xf9\x0e\xf1=^\xe2\x1e\x8c\xfc\u007f\x83\x14\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\x86\x87\xe3Aw\x10\xbb\x8a\x93U\x90!\xa1F\x9ej\x86\xbcw\x8a\x02[-\xa2x\xd9k{\x80\x00\xe0\x94l\x88,'s,\xef\\|\x13\xa6\x86\xf0\xa2\xeawUZ\u0089\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4l\xa5\xde\x00\x81}\xe0\xce\xdc\xe5\xfd\x00\x01(\xde\xde\x12d\x8b<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\xa6\xa12\xce\x1c\u0488\xbe\xe3\x0e\xc7\xcf\xef\xfb\x85\xc1\xf5\nT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\xb1\x1e\xcb2\xd3\u0382\x96\x011\x066\xf5\xa1\f\xf7\u03db_\x8a\x04?\u851c8\x01\xf5\x00\x00\u07d4l\xc1\xc8x\xfal\u078a\x9a\v\x83\x11$~t\x1eFB\xfem\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94l\xcb\x03\xac\xf7\xf5<\xe8z\xad\xcc!\xa9\x93-\xe9\x15\xf8\x98\x04\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4l\xd2\x12\xae\xe0N\x01?=*\xba\u04a0#`k\xfb\\j\u01c9lj\xccg\u05f1\xd4\x00\x00\u07d4l\xd2(\xdcq!i0\u007f\xe2|\xebtw\xb4\x8c\xfc\x82r\xe5\x89\x044\xea\x94\u06caP\x00\x00\u07d4l\xe1\xb0\xf6\xad\xc4pQ\xe8\xab8\xb3\x9e\xdbA\x86\xb0;\xab\u0309Ay\x97\x94\xcd$\xcc\x00\x00\u07d4l\xea\xe3s=\x8f\xa4=l\xd8\f\x1a\x96\xe8\xeb\x93\x10\x9c\x83\xb7\x89\x10'\x94\xad \xdah\x00\x00\u07d4m\x05i\xe5U\x8f\xc7\xdf'f\xf2\xba\x15\u070a\xef\xfc[\xebu\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4m\x12\x0f\f\xaa\xe4O\xd9K\xca\xfeU\xe2\xe2y\uf5ba\\z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\x14V\xff\xf0\x10N\xe8D\xa31G7\x8438\xd2L\xd6l\x89\a\xb0l\xe8\u007f\xddh\x00\x00\u07d4m \xef\x97\x04g\nP\v\xb2i\xb5\x83.\x85\x98\x02\x04\x9f\x01\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\xe0\x94m/\x97g4\xb9\xd0\a\r\x18\x83\xcfz\u02b8\xb3\xe4\x92\x0f\xc1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m9\xa9\u93c1\xf7i\xd7:\xad,\xea\xd2v\xac\x13\x87\xba\xbe\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4m;x6\xa2\xb9\u0619r\x1aM#{R#\x85\xdc\xe8\xdf\u034966\xc2^f\xec\xe7\x00\x00\u07d4m?+\xa8V\u033b\x027\xfava\x15k\x14\xb0\x13\xf2\x12@\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94m@\b\xb4\xa8\x88\xa8&\xf2H\xeej\v\r\xfd\xe9\xf92\x10\xb9\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4m@\xca'\x82m\x97s\x1b>\x86\xef\xfc\u05f9*Aa\xfe\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mD\x97J1\u0447\xed\xa1m\xddG\xb9\xc7\xecP\x02\xd6\x1f\xbe\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94mK\\\x05\xd0j \x95~\x17H\xabm\xf2\x06\xf3C\xf9/\x01\x8a\x02\x1f6\x06\x99\xbf\x82_\x80\x00\xe0\x94mL\xbf=\x82\x84\x83:\xe9\x93D0>\b\xb4\xd6\x14\xbf\xda;\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4mY\xb2\x1c\xd0\xe2t\x88\x04\u066b\xe0d\xea\u00be\xf0\xc9_'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mc\u04ce\xe8\xb9\x0e\x0en\xd8\xf1\x92\xed\xa0Q\xb2\u05a5\x8b\xfd\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4mf4\xb5\xb8\xa4\x01\x95\xd9I\x02z\xf4\x82\x88\x02\t,\ued89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94m}\x1c\x94\x95\x11\xf8\x83\x03\x80\x8c`\xc5\xea\x06@\xfc\xc0&\x83\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m\x84m\xc1&W\xe9\x1a\xf2P\bQ\x9c>\x85\u007fQp}\u0589\xf8\xd3\v\xc9#B\xf8\x00\x00\u07d4m\x91\x93\x99k\x19F\x17!\x11\x06\xd1c^\xb2l\u0136ll\x89\x15\xaa\x1e~\x9d\xd5\x1c\x00\x00\u07d4m\x99\x97P\x98\x82\x02~\xa9G#\x14$\xbe\xde\xde)e\u043a\x89l\x81\u01f3\x11\x95\xe0\x00\x00\u07d4m\xa0\xed\x8f\x1di3\x9f\x05\x9f*\x0e\x02G\x1c\xb4O\xb8\u00fb\x892\xbc8\xbbc\xa8\x16\x00\x00\u07d4m\xb7+\xfdC\xfe\xf4e\xcaV2\xb4Z\xabra@N\x13\xbf\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xbe\x8a\xbf\xa1t(\x06&9\x817\x1b\xf3\xd3U\x90\x80kn\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xc3\xf9+\xaa\x1d!\u06b78+\x892a\xa05o\xa7\xc1\x87\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4m\xc7\x05:q\x86\x16\xcf\u01cb\xeec\x82\xeeQ\xad\xd0\xc7\x030\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xcc~d\xfc\xaf\xcb\xc2\xdcl\x0e^f,\xb3G\xbf\xfc\xd7\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xda_x\x8alh\x8d\u07d2\x1f\xa3\x85.\xb6\xd6\xc6\xc6)f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4m\xdb`\x92w\x9dXB\xea\xd3x\xe2\x1e\x81 \xfdLk\xc12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4m\xdf\xefc\x91U\u06ab\n\\\xb4\x95:\xa8\u016f\xaa\x88\x04S\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4m\xe0/-\xd6~\xfd\xb794\x02\xfa\x9e\xaa\xcb\xcfX\x9d.V\x89@\x13\x8b\x91~\u07f8\x00\x00\u07d4m\u4d418\\\xf7\xfc\x9f\xe8\xc7}\x13\x1f\xe2\xeew$\xc7j\x89})\x97s=\xcc\xe4\x00\x00\u07d4m\xe4\xd1R\x19\x18/\xaf:\xa2\xc5\xd4\xd2Y_\xf20\x91\xa7'\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4m\xed\xf6.t?M,*K\x87\xa7\x87\xf5BJz\xeb9<\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4m\xf2Of\x85\xa6/y\x1b\xa37\xbf?\xf6~\x91\xf3\u053c:\x89ukI\xd4\nH\x18\x00\x00\u07d4m\xf5\xc8O{\x90\x9a\xab>a\xfe\x0e\xcb\x1b;\xf2`\"*\u0489\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\xff\x90\xe6\xdc5\x9d%\x90\x88+\x14\x83\xed\xbc\xf8\x87\xc0\xe4#\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\x01\xe4\xadV\x9c\x95\xd0\a\xad\xa3\r^-\xb1(\x88I\"\x94\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\a;f\u0478\xc6gD\u0600\x96\xa8\u0759\xec~\x02(\u0689\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x0e\xe7\x06\x12\xc9v(}I\x9d\u07e6\xc0\xdc\xc1,\x06\xde\xea\x89\a\v\u0579V!F\x00\x00\xe0\x94n\x12\xb5\x1e\"[JCr\xe5\x9a\u05e2\xa1\xa1>\xa3\u04e17\x8a\x03\x00F\xc8\xccw_\x04\x00\x00\u07d4n\x1a\x04l\xaf[JW\xf4\xfdK\xc1sb!&\xb4\xe2\xfd\x86\x89a\t=|,m8\x00\x00\u07d4n\x1e\xa4\xb1\x83\xe2R\u027bwg\xa0\x06\u05346\x96\u02ca\xe9\x89\x0f\xf3x<\x85\xee\u0400\x00\u07d4n%[p\n\xe7\x13\x8aK\xac\xf2(\x88\xa9\xe2\xc0\n(^\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n'\n\xd5)\xf1\xf0\xb8\xd9\xcbm$'\xec\x1b~-\xc6Jt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4n.\xab\x85\u0709\xfe)\xdc\n\xa1\x852G\u06b4:R=V\x89\x04V9\x18$O@\x00\x00\u07d4n:Q\xdbt=3M/\xe8\x82$\xb5\xfe|\x00\x8e\x80\xe6$\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4nL*\xb7\xdb\x02i9\xdb\u04fch8J\xf6`\xa6\x18\x16\xb2\x89\t\r\x97/22<\x00\x00\u07d4nM.9\u0203f)\u5d07\xb1\x91\x8af\x9a\xeb\u07556\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\\-\x9b\x1cTj\x86\xee\xfd]\nQ \xc9\xe4\xe70\x19\x0e\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4n`\xae\u19cf\x8e\u068bBLs\xe3S5J\xe6|0B\x89\xbd5\xa4\x8d\x99\x19\xe6\x00\x00\u07d4nd\xe6\x12\x9f\"N7\x8c\x0ensj~z\x06\xc2\x11\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4nm[\xbb\xb9\x05;\x89\xd7D\xa2s\x16\u00a7\xb8\xc0\x9bT}\x891Rq\n\x02>m\x80\x00\u07d4nr\xb2\xa1\x18j\x8e)\x16T;\x1c\xb3jh\x87\x0e\xa5\u0457\x89\n\x15D\xbe\x87\x9e\xa8\x00\x00\u07d4nv\x1e\xaa\x0f4_w{TA\xb7:\x0f\xa5\xb5k\x85\xf2-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4ny\xed\u0504[\anL\u060d\x18\x8bnC-\xd9?5\xaa\x893\xc5I\x901r\f\x00\x00\u07d4n\x82\x12\xb7\"\xaf\xd4\b\xa7\xa7>\xd3\xe29^\xe6EJ\x030\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\u07d4n\x84\x87m\xbb\x95\xc4\vfV\xe4+\xa9\xae\xa0\x8a\x99;T\u0709;\xbc`\xe3\xb6\u02fe\x00\x00\u07d4n\x84\xc2\xfd\x18\xd8\tW\x14\xa9h\x17\x18\x9c\xa2\x1c\xcab\xba\xb1\x89\x12{lp&!\u0340\x00\u07d4n\x86m\x03-@Z\xbd\xd6\\\xf6QA\x1d\x807\x96\xc2#\x11\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94n\x89\x9eY\xa9\xb4\x1a\xb7\xeaA\xdfu\x17\x86\x0f*\xcbY\xf4\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4n\x89\xc5\x1e\xa6\xde\x13\xe0l\xdct\x8bg\xc4A\x0f\u9f2b\x03\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x8a&h\x9fz/\xde\xfd\x00\x9c\xba\xaaS\x10%4P\u06ba\x89o!7\x17\xba\xd8\xd3\x00\x00\u07d4n\x96\xfa\xed\xa3\x05C\x02\xc4_X\xf1a2L\x99\xa3\xee\xbbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xb0\xa5\xa9\xae\x96\xd2,\xf0\x1d\x8f\xd6H;\x9f8\xf0\x8c,\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xb3\x81\x96\x17@@X&\x8f\f<\xff5\x96\xbf\xe9\x14\x8c\x1c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94n\xb5W\x8ak\xb7\xc3!S\x19[\r\x80 \xa6\x91HR\xc0Y\x8a\x8b\u00ab\xf4\x02!\xf4\x80\x00\x00\u07d4n\xbb^iW\xaa\x82\x1e\xf6Y\xb6\x01\x8a9:PL\xaeDP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\xbc\xf9\x95\u007f_\xc5\u916d\xd4u\";\x04\xb8\xc1Jz\xed\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4n\xc3e\x95q\xb1\x1f\x88\x9d\xd49\xbc\xd4\xd6u\x10\xa2[\xe5~\x89\x06\xaa\xf7\xc8Qm\f\x00\x00\u07d4n\u021b9\xf9\xf5'jU>\x8d\xa3\x0en\xc1z\xa4~\xef\u01c9\x18BO_\v\x1bN\x00\x00\u07d4n\xc9m\x13\xbd\xb2M\u01e5W)?\x02\x9e\x02\xddt\xb9zU\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xca\xef\xa6\xfc>\xe54bm\xb0,o\x85\xa0\u00d5W\x1ew\x89 \x86\xac5\x10R`\x00\x00\u07d4n\u04a1+\x02\xf8\u0188\u01f5\u04e6\xea\x14\xd66\x87\u06b3\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\u0604E\x9f\x80\x9d\xfa\x10\x16\xe7p\xed\xaf>\x9f\xefF\xfa0\x89\xb8R\xd6x \x93\xf1\x00\x00\xe0\x94n\xdf\u007fR\x83r\\\x95>\xe6C\x17\xf6a\x88\xaf\x11\x84\xb03\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4n\xe8\xaa\xd7\xe0\xa0e\u0605-|;\x9an_\xdcK\xf5\f\x00\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xef\u0705\x0e\x87\xb7\x15\xc7'\x91w<\x03\x16\xc3U\x9bX\xa4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xf9\xe8\u0276!}Vv\x9a\xf9}\xbb\x1c\x8e\x1b\x8b\xe7\x99\u0489\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4n\xfb\xa8\xfb*\u0176s\a)\xa9r\xec\"D&\xa2\x87\u00ed\x89\x0fY\x85\xfb\xcb\xe1h\x00\x00\xe0\x94n\xfd\x90\xb55\xe0\v\xbd\x88\x9f\xda~\x9c1\x84\xf8y\xa1Q\u06ca\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4o\x05\x16f\xcbO{\u04b1\x90r!\xb8)\xb5U\u05e3\xdbt\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4o\x0e\xdd#\xbc\xd8_`\x15\xf9(\x9c(\x84\x1f\xe0L\x83\xef\xeb\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4o\x13zq\xa6\xf1\x97\xdf,\xbb\xf0\x10\u073d\x89a\t=|,m8\x00\x00\u07d4p\x10\xbe-\xf5{\u042b\x9a\xe8\x19l\xd5\n\xb0\xc5!\xab\xa9\xf9\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4p#\xc7\tV\xe0J\x92\xd7\x00%\xaa\u0497\xb59\xaf5Xi\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p%\x96]+\x88\xda\x19}DY\xbe=\xc98cD\xcc\x1f1\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d4p(\x02\xf3m\x00%\x0f\xabS\xad\xbc\u0596\xf0\x17oc\x8aI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pH\x19\xd2\xe4Mn\xd1\xda%\xbf\u0384\u011f\u0322V\x13\xe5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4pJn\xb4\x1b\xa3O\x13\xad\xdd\xe7\xd2\xdb}\xf0I\x15\u01e2!\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4pJ\xb1\x15\r^\x10\xf5\xe3I\x95\b\xf0\xbfpe\x0f\x02\x8dK\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4pJ\xe2\x1dv-n\x1d\xde(\xc25\xd11\x04Yr6\xdb\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pM$<)x\xe4l,\x86\xad\xbe\xcd$n;)_\xf63\x89m\x12\x1b\xeb\xf7\x95\xf0\x00\x00\u07d4pM]\xe4\x84m9\xb5<\xd2\x1d\x1cI\xf0\x96\xdb\\\x19\xba)\x89\b=lz\xabc`\x00\x00\u07d4p]\xdd85T\x82\xb8\xc7\u04f5\x15\xbd\xa1P\r\xd7\u05e8\x17\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94pan(\x92\xfa&\x97\x05\xb2\x04k\x8f\xe3\xe7/\xa5X\x16\u04ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4pg\x0f\xbb\x05\xd30\x14DK\x8d\x1e\x8ew\x00%\x8b\x8c\xaam\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\x81\xfak\xaa\xd6\u03f7\xf5\x1b,\xca\x16\xfb\x89p\x99\x1ad\xba\x89\f\xae\xc0\x05\xf6\xc0\xf6\x80\x00\xe0\x94p\x85\xae~~M\x93!\x97\xb5\u01c5\x8c\x00\xa3gF&\xb7\xa5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4p\x86\xb4\xbd\xe3\xe3]J\xeb$\xb8%\xf1\xa2\x15\xf9\x9d\x85\xf7E\x89lh\xcc\u041b\x02,\x00\x00\u07d4p\x8a*\xf4%\u03b0\x1e\x87\xff\xc1\xbeT\xc0\xf52\xb2\x0e\xac\u0589\aE\u0503\xb1\xf5\xa1\x80\x00\u07d4p\x8e\xa7\a\xba\xe45\u007f\x1e\xbe\xa9Y\u00e2P\xac\u05aa!\xb3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794p\x8f\xa1\x1f\xe3=\x85\xad\x1b\xef\u02ee8\x18\xac\xb7\x1fj}~\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4p\x9101\x16\xd5\xf28\x9b##\x8bMej\x85\x96\u0644\u04c9;N~\x80\xaaX3\x00\x00\u07d4p\x99\xd1/n\xc6V\x89\x9b\x04\x9avW\x06]b\x99h\x92\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4p\x9f\xe9\xd2\xc1\xf1\xceB |\x95\x85\x04J`\x89\x9f5\x94/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xa05I\xaaah\xe9~\x88\xa5\b3\nZ\v\xeatq\x1a\x89Hz\x9a0E9D\x00\x00\u07d4p\xa4\x06}D\x8c\xc2]\xc8\xe7\x0ee\x1c\xea|\xf8N\x92\x10\x9e\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4p\xab4\xbc\x17\xb6o\x9c;c\xf1Q'O*r|S\x92c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xc2\x13H\x8a\x02\f<\xfb9\x01N\xf5\xbad\x04rK\u02a3\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4p\xd2^\xd2\u022d\xa5\x9c\b\x8c\xf7\r\xd2+\xf2\u06d3\xac\xc1\x8a\x899GEE\u4b7c\x00\x00\u07d4p\xe5\xe9\xdas_\xf0w$\x9d\u02da\xaf=\xb2\xa4\x8d\x94\x98\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4p\xfe\xe0\x8b\x00\xc6\xc2\xc0Jp\xc0\xce=\x92\u03ca\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794q\v\xe8\xfd^)\x18F\x8b\u2abe\xa8\r\x82\x845\u05d6\x12\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4q\x13]\x8f\x05\x96<\x90ZJ\a\x92)\t#Z\x89jR\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4q\x1e\xcfw\xd7\x1b=\x0e\xa9\\\xe4u\x8a\xfe\u0379\xc11\a\x9d\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4q!?\xca14\x04 N\u02e8q\x97t\x1a\xa9\xdf\xe9c8\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94q+vQ\x02\x14\xdcb\x0fl:\x1d\u049a\xa2+\xf6\xd2\x14\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4q/\xf77\n\x13\xed6\ts\xfe\u071f\xf5\xd2\xc9:P^\x9e\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4q3\x84:x\xd99\u019dD\x86\xe1\x0e\xbc{`*4\x9f\xf7\x89\x11\xd5\xca\xcc\xe2\x1f\x84\x00\x00\u07d4qH\xae\xf32a\xd8\x03\x1f\xac?q\x82\xff5\x92\x8d\xafT\u0649\xdeB\xee\x15D\u0750\x00\x00\u07d4qcu\x8c\xbblLR^\x04\x14\xa4\n\x04\x9d\xcc\xcc\xe9\x19\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4qh\xb3\xbb\x8c\x16s!\u067d\xb0#\xa6\xe9\xfd\x11\xaf\u026f\u0649a\t=|,m8\x00\x00\u07d4qirN\xe7\"q\xc54\xca\xd6B\x0f\xb0N\xe6D\u02c6\xfe\x89\x16<+@\u06e5R\x00\x00\u07d4qj\xd3\xc3:\x9b\x9a\n\x18\x96sW\x96\x9b\x94\xee}*\xbc\x10\x89\x1a!\x17\xfeA*H\x00\x00\xe0\x94qk\xa0\x1e\xad*\x91'\x065\xf9_%\xbf\xaf-\xd6\x10\xca#\x8a\ty\xe7\x01 V\xaax\x00\x00\u07d4qmP\u0320\x1e\x93\x85\x00\xe6B\x1c\xc0p\xc3P|g\u04c7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qv,cg\x8c\x18\xd1\xc67\x8c\xe0h\xe6f8\x13\x15\x14~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qxL\x10Q\x17\xc1\xf6\x895y\u007f\xe1Y\xab\xc7NC\xd1j\x89l\x81\u01f3\x11\x95\xe0\x00\x00\xe0\x94qyro\\q\xae\x1bm\x16\xa6\x84(\x17Nk4\xb26F\x8a\x01\x8e\xa2P\t|\xba\xf6\x00\x00\xe0\x94q|\xf9\xbe\xab680\x8d\xed~\x19^\f\x86\x13-\x16?\xed\x8a\x032n\xe6\xf8e\xf4\"\x00\x00\u07d4q\x80\xb8>\xe5WC\x17\xf2\x1c\x80r\xb1\x91\u0615\xd4aS\u00c9\x18\xef\xc8J\xd0\u01f0\x00\x00\u07d4q\x94kq\x17\xfc\x91^\xd1\a8_B\u065d\xda\xc62I\u0089lk\x93[\x8b\xbd@\x00\x00\xe0\x94q\x9e\x89\x1f\xbc\xc0\xa3>\x19\xc1-\xc0\xf0 9\xca\x05\xb8\x01\u07ca\x01OU8F:\x1bT\x00\x00\u07d4q\xc7#\n\x1d5\xbd\u0581\x9e\u0539\xa8\x8e\x94\xa0\xeb\a\x86\u0749\uc80b5=$\x14\x00\x00\u07d4q\xd2\xccm\x02W\x8ce\xf7\r\xf1\x1bH\xbe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4r\x83\xcdFu\xdaX\u0116UaQ\xda\xfd\x80\xc7\xf9\x95\xd3\x18\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4r\x86\xe8\x9c\xd9\u078fz\x8a\x00\xc8o\xfd\xb59\x92\u0752Q\u0449i*\xe8\x89p\x81\xd0\x00\x00\u07d4r\x8f\x9a\xb0\x80\x15}\xb3\a1V\xdb\xca\x1a\x16\x9e\xf3\x17\x94\a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4r\x94\xc9\x18\xb1\xae\xfbM%\x92~\xf9\u05d9\xe7\x1f\x93\xa2\x8e\x85\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94r\x94\uc763\x10\xbckK\xbd\xf5C\xb0\xefE\xab\xfc>\x1bM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4r\x9a\xadF'tNS\xf5\xd6c\t\xaatD\x8b:\xcd\xf4o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xa2\xfc\x86u\xfe\xb9r\xfaA\xb5\r\xff\u06fa\xe7\xfa*\u07f7\x89\x9a\xb4\xfcg\xb5(\xc8\x00\x00\u07d4r\xa8&\b&)G&\xa7[\xf3\x9c\u066a\x9e\a\xa3\xea\x14\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb0Yb\xfb*\u0549\xd6Z\xd1j\"U\x9e\xba\x14X\xf3\x87\x89\a?u\u0460\x85\xba\x00\x00\u07d4r\xb5c?\xe4w\xfeT.t/\xac\xfdi\f\x13xT\xf2\x16\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4r\xb7\xa0=\xda\x14\u029cf\x1a\x1dF\x9f\xd376\xf6s\xc8\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb9\x04D\x0e\x90\xe7 \u05ac\x1c*\u05dc2\x1d\xcc\x1c\x1a\x86\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94r\xb9\nM\xc0\x97#\x94\x92\u0179w}\xcd\x1eR\xba+\xe2\u008a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4r\xbb'\u02d9\xf3\xe2\xc2\u03d0\xa9\x8fp}0\xe4\xa2\x01\xa0q\x89X\xe7\x92n\xe8X\xa0\x00\x00\xe0\x94r\xc0\x83\xbe\xad\xbd\xc2'\xc5\xfbC\x88\x15\x97\xe3.\x83\xc2`V\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4r\xcd\x04\x8a\x11\x05tH)\x83I-\xfb\x1b\xd2yB\xa6\x96\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xd0=M\xfa\xb3P\f\xf8\x9b\x86\x86o\x15\xd4R\x8e\x14\xa1\x95\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4r\u06bb[n\ud799\xbe\x91X\x88\xf6V\x80V8\x16\b\xf8\x89\vL\x96\xc5,\xb4\xfe\x80\x00\u07d4r\xfbI\u009d#\xa1\x89P\u0132\xdc\r\xdfA\x0fS-oS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xfe\xaf\x12EyR9Td[\u007f\xaf\xff\x03x\xd1\xc8$.\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\x01\xdcL\xf2mq\x86\xf2\xa1\x1b\xf8\xb0\x8b\xf2)F?d\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x04G\xf9|\xe9\xb2_\"\xba\x1a\xfb6\xdf'\xf9Xk\ub6c9,s\xc97t,P\x00\x00\u07d4s\x06\xde\x0e(\x8bV\xcf\u07d8~\xf0\xd3\xcc)f\a\x93\xf6\u0749\x1b\x8a\xbf\xb6.\xc8\xf6\x00\x00\xe0\x94s\r\x87c\u01a4\xfd\x82J\xb8\xb8Y\x16\x1e\xf7\xe3\xa9j\x12\x00\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4s\x12\x81sH\x95(\x01.v\xb4\x1a^(\u018b\xa4\xe3\xa9\u050965\u026d\xc5\u07a0\x00\x00\u07d4s\x13F\x12\bETUFTE\xa4Y\xb0l7s\xb0\xeb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s/\xea\xd6\x0f{\xfd\u05a9\xde\u0101%\xe3s]\xb1\xb6eO\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sB#\xd2\u007f\xf2>Y\x06\xca\xed\"YW\x01\xbb4\x83\f\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4sG>r\x11Q\x10\xd0\xc3\xf1\x17\b\xf8nw\xbe+\xb0\x98<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sRXm\x02\x1a\xd0\xcfw\xe0\xe9(@JY\xf3t\xffE\x82\x89\xb8Pz\x82\a( \x00\x00\u07d4sU\v\xebs+\xa9\u076f\xdaz\xe4\x06\xe1\x8f\u007f\xeb\x0f\x8b\xb2\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4s[\x97\xf2\xfc\x1b\xd2K\x12\an\xfa\xf3\xd1(\x80s\xd2\f\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4s^2\x86f\xedV7\x14+3\x06\xb7|\xccT`\xe7,=\x89j\xb8\xf3xy\u0251\x00\x00\u07d4sc\u0350\xfb\xab[\xb8\u011a\xc2\x0f\xc6,9\x8f\xe6\xfbtL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4skDP=\xd2\xf6\xddTi\xffL[-\xb8\xeaO\xece\u0409\x11\x04\xeeu\x9f!\xe3\x00\x00\xe0\x94sk\xf1@,\x83\x80\x0f\x89>X1\x92X*\x13N\xb52\xe9\x8a\x02\x1e\x19\u0493\xc0\x1f&\x00\x00\xe0\x94s\x8c\xa9M\xb7\u038b\xe1\xc3\x05l\u0598\x8e\xb3v5\x9f3S\x8a\x05f[\x96\xcf5\xac\xf0\x00\x00\u07d4s\x91K\"\xfc/\x13\x15\x84$}\x82\xbeO\ucfd7\x8a\u053a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x93'\t\xa9\u007f\x02\u024eQ\xb0\x911(e\x12#\x85\xae\x8e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4s\x93\xcb\xe7\xf9\xba!e\xe5\xa7U5\x00\xb6\xe7]\xa3\xc3:\xbf\x89\x05k\xc7^-c\x10\x00\x00\u07d4s\xb4\u0519\xde?8\xbf5\xaa\xf7i\xa6\xe3\x18\xbcm\x126\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\xbe\xddo\xda{\xa3'!\x85\b{cQ\xfc\x13=HN7\x8a\x01\x12&\xbf\x9d\xceYx\x00\x00\u07d4s\xbf\xe7q\x0f1\u02b9I\xb7\xa2`O\xbfR9\xce\xe7\x90\x15\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\u03c0\xae\x96\x88\xe1X\x0eh\xe7\x82\xcd\b\x11\xf7\xaaIM,\x8a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\xe0\x94s\xd7&\x9f\xf0l\x9f\xfd3uL\xe5\x88\xf7J\x96j\xbb\xbb\xba\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4s\xd8\xfe\xe3\u02c6M\xce\"\xbb&\u029c/\bm^\x95\xe6;\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\xdf<>yU\xf4\xf2\xd8Y\x83\x1b\xe3\x80\x00\xb1\ak8\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4s\u48b6\f\U0010e2ef+w~\x17Z[\x1eM\f-\x8f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94t\n\xf1\xee\xfd3e\u05cb\xa7\xb1,\xb1\xa6s\xe0j\arF\x8a\x04+\xf0kx\xed;P\x00\x00\xe0\x94t\v\xfdR\xe0\x16g\xa3A\x9b\x02\x9a\x1b\x8eEWj\x86\xa2\u06ca\x03\x8e\xba\xd5\xcd\xc9\x02\x80\x00\x00\u07d4t\x0fd\x16\x14w\x9d\u03e8\x8e\xd1\xd4%\xd6\r\xb4*\x06\f\xa6\x896\"\xc6v\b\x10W\x00\x00\u07d4t\x12\u027c0\xb4\xdfC\x9f\x021\x00\xe69$\x06j\xfdS\xaf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4t\x16\x93\xc3\x03vP\x85\x13\b \xcc+c\xe9\xfa\x92\x13\x1b\x89A\rXj \xa4\xc0\x00\x00\u07d4t!\xce[\xe3\x81s\x8d\u0703\xf0&!\x97O\xf0hly\xb8\x89Xx\x8c\xb9K\x1d\x80\x00\x00\u07d4t1j\xdf%7\x8c\x10\xf5v\u0574\x1aoG\xfa\x98\xfc\xe3=\x89\x128\x13\x1e\\z\xd5\x00\x00\u07d4t6Q\xb5^\xf8B\x9d\xf5\f\xf8\x198\xc2P\x8d\xe5\u0207\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t=\xe5\x00&\xcag\xc9M\xf5O\x06b`\xe1\xd1J\xcc\x11\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tE /\ft)z\x00N\xb3rj\xa6\xa8-\xd7\xc0/\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tK\x03\xbb\xa8X*\xe5I\x8e-\xc2-\x19\x94\x94g\xabS\xfc\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4tL\fw\xba\u007f#i \xd1\xe44\xde]\xa3>H\xeb\xf0,\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4tP\xff\u007f\x99\xea\xa9\x11bu\u07ach\xe4(\xdf[\xbc\u0639\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tV\u0172\xc5Cn>W\x10\b\x93?\x18\x05\xcc\xfe4\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4tZ\u04eb\xc6\xee\xeb$qh\x9bS\x9ex\x9c\xe2\xb8&\x83\x06\x89=A\x94\xbe\xa0\x11\x92\x80\x00\xe0\x94tZ\xec\xba\xf9\xbb9\xb7Jg\xea\x1c\xe6#\xde6\x84\x81\xba\xa6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4t\\\xcf-\x81\x9e\u06fd\u07a8\x11{\\I\xed<*\x06n\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4tb\u021c\xaa\x9d\x8dx\x91\xb2T]\xef!otd\u057b!\x89\x05\xea\xedT\xa2\x8b1\x00\x00\u07d4td\x8c\xaa\xc7H\xdd\x13\\\xd9\x1e\xa1L(\xe1\xbdM\u007f\xf6\xae\x89\xa8\r$g~\xfe\xf0\x00\x00\xe0\x94tq\xf7.\xeb0\x06$\xeb(.\xabM\x03r\x00\x00\x00\xe0\x94t\x84\xd2k\xec\xc1\xee\xa8\xc61^\xc3\xee\nE\x01\x17\u0706\xa0\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4t\x86:\xce\xc7]\x03\xd5>\x86\x0ed\x00/,\x16^S\x83w\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x89\u030a\xbeu\u0364\xef\r\x01\xce\xf2`^G\xed\xa6z\xb1\x89\a?u\u0460\x85\xba\x00\x00\u07d4t\x8c(^\xf1#?\xe4\xd3\x1c\x8f\xb17\x833r\x1c\x12\xe2z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\x90\x87\xac\x0fZ\x97\xc6\xfa\xd0!S\x8b\xf1\xd6\u0361\x8e\r\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x95\xaex\xc0\xd9\x02a\xe2\x14\x0e\xf2\x061\x04s\x1a`\xd1\xed\x89\x01\xdbPq\x89%!\x00\x00\u07d4t\x9aJv\x8b_#rH\x93\x8a\x12\xc6#\x84{\xd4\xe6\x88\u0709\x03\xe73b\x87\x14 \x00\x00\u07d4t\x9a\xd6\xf2\xb5pk\xbe/h\x9aD\u0136@\xb5\x8e\x96\xb9\x92\x89\x05k\xc7^-c\x10\x00\x00\u07d4t\xa1\u007f\x06K4N\x84\xdbce\u0695\x91\xff\x16(%vC\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4t\xae\xec\x91]\xe0\x1c\u019b,\xb5\xa65o\xee\xa1FX\xc6\u0149\f\x9a\x95\xee)\x86R\x00\x00\u07d4t\xaf\xe5I\x02\xd6\x15x%v\xf8\xba\xac\x13\xac\x97\f\x05\x0fn\x89\t\xa1\xaa\xa3\xa9\xfb\xa7\x00\x00\u07d4t\xb7\xe0\"\x8b\xae\xd6YW\xae\xbbM\x91m3:\xae\x16O\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbcJ^ E\xf4\xff\x8d\xb1\x84\xcf:\x9b\f\x06Z\xd8\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbc\xe9\xec86-l\x94\u032c&\xd5\xc0\xe1:\x8b;\x1d@\x8965&A\x04B\xf5\x00\x00\u07d4t\xbfzZ\xb5\x92\x93\x14\x9b\\`\xcf6Bc\xe5\xeb\xf1\xaa\r\x89\x06G\f>w\x1e<\x00\x00\xe0\x94t\xc7<\x90R\x8a\x15s6\xf1\xe7\xea b\n\xe5?\xd2G(\x8a\x01\xe6:.S\x8f\x16\xe3\x00\x00\u07d4t\u0464\xd0\xc7RN\x01\x8dN\x06\xed;d\x80\x92\xb5\xb6\xaf,\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94t\xd3f\xb0{/VG}|pw\xaco\xe4\x97\xe0\xebeY\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4t\xd3zQt{\xf8\xb7q\xbf\xbfC\x9493\xd1\x00\xd2\x14\x83\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xd6q\u065c\xbe\xa1\xabW\x90cu\xb6?\xf4+PE\x1d\x17\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xeb\xf4BVF\xe6\u03c1\xb1\t\xce{\xf4\xa2\xa6=\x84\x81_\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4t\xed3\xac\xf4?5\xb9\x8c\x920\xb9\xe6d.\xcbS0\x83\x9e\x89$\xf6\xdf\xfbI\x8d(\x00\x00\u07d4t\xef(i\xcb\xe6\b\x85`E\xd8\xc2\x04\x11\x18W\x9f\"6\xea\x89\x03<\xd6E\x91\x95n\x00\x00\u07d4t\xfcZ\x99\xc0\xc5F\x05\x03\xa1;\x05\tE\x9d\xa1\x9c\xe7\u0350\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4u\v\xbb\x8c\x06\xbb\xbf$\bC\xccux.\xe0/\b\xa9tS\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4u\x14\xad\xbd\xc6?H?0M\x8e\x94\xb6\u007f\xf30\x9f\x18\v\x82\x89!\u0120n-\x13Y\x80\x00\u0794u\x17\xf1l(\xd12\xbb@\xe3\xba6\u01ae\xf11\xc4b\xda\x17\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4u\x1a,\xa3Nq\x87\xc1c\u048e6\x18\xdb(\xb1<\x19m&\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94u\x1a\xbc\xb6\xcc\x030Y\x91\x18\x15\xc9o\u04516\n\xb0D-\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4u&\xe4\x82R\x9f\n\x14\xee\u0248q\xdd\xdd\x0er\x1b\f\u0662\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4u)\xf3y{\xb6\xa2\x0f~\xa6I$\x19\xc8L\x86vA\xd8\x1c\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94u*^\xe22a,\xd3\x00_\xb2n[Y}\xe1\x9fwk\xe6\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4u,\x9f\xeb\xf4/f\xc4x{\xfa~\xb1|\xf53;\xbaPp\x89j\x99\xf2\xb5O\xddX\x00\x00\u07d4u930F\u07b1\xef\x8e\u07b9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94u\xc1\xad#\xd2?$\xb3\x84\xd0\xc3\x14\x91w\xe8f\x97a\r!\x8a\x01\\[\xcdl(\x8b\xbd\x00\x00\u07d4u\xc2\xff\xa1\xbe\xf5I\x19\xd2\t\u007fz\x14-.\x14\xf9\xb0JX\x89\x90\xf3XP@2\xa1\x00\x00\u07d4u\xd6|\xe1N\x8d)\xe8\xc2\xff\u3051{\x93\v\x1a\xff\x1a\x87\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4u\xde~\x93R\xe9\v\x13\xa5\x9aXx\xff\xec\u01c3\x1c\xacM\x82\x89\x94\x89#z\u06daP\x00\x00\u07d4u\xf7S\x9d0\x9e\x909\x98\x9e\xfe.\x8b-\xbd\x86Z\r\xf0\x88\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4v\b\xf47\xb3\x1f\x18\xbc\vd\u04c1\xae\x86\xfd\x97\x8e\u05f3\x1f\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94v\x0f\xf35N\x0f\u0793\x8d\x0f\xb5\xb8,\xef[\xa1\\=)\x16\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v\x1an6,\x97\xfb\xbd|Yw\xac\xba-\xa7F\x876_I\x89\t\xf7J\xe1\xf9S\xd0\x00\x00\u07d4v\x1el\xae\xc1\x89\xc20\xa1b\xec\x00e0\x19>g\u03dd\x19\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94v\x1f\x8a:*\U00028f7e\x1d\xa0\t2\x1f\xb2\x97d\xebb\xa1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v)\x98\xe1\xd7R'\xfc\xedzp\xbe\x10\x9aL\vN\xd8d\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v-o0\u06b9\x915\xe4\xec\xa5\x1dRC\xd6\xc8b\x11\x02\u0549\x0fI\x89A\xe6d(\x00\x00\u07d4v3\x1e0yl\xe6d\xb2p\x0e\rASp\x0e\u0706\x97w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v8\x86\xe33\xc5o\xef\xf8[\xe3\x95\x1a\xb0\xb8\x89\xce&.\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v:|\xba\xb7\rzd\u0427\xe5)\x80\xf6\x81G%\x93I\f\x89 \x86\xac5\x10R`\x00\x00\u07d4v>\xec\u0c0a\u021e2\xbf\xa4\xbe\xcev\x95\x14\xd8\xcb[\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4v@\xa3\u007f\x80R\x98\x15\x15\xbc\xe0x\u0693\xaf\xa4x\x9bW4\x89lk\x93[\x8b\xbd@\x00\x00\u0794vA\xf7\xd2j\x86\xcd\xdb+\xe10\x81\x81\x0e\x01\xc9\xc8E\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94vO\xc4mB\x8bm\xbc\"\x8a\x0f_U\xc9P\x8cw.\xab\x9f\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4vPn\xb4\xa7\x80\xc9Q\xc7J\x06\xb0=;\x83b\xf0\x99\x9dq\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94v[\xe2\xe1/b\x9ecI\xb9}!\xb6*\x17\xb7\xc80\xed\xab\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94vb\x81P\xe2\x99[['\x9f\xc8>\r\xd5\xf1\x02\xa6q\xdd\x1c\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4vk7Y\xe8yN\x92m\xacG=\x91:\x8f\xb6\x1a\xd0\xc2\u0249\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4vp\xb0/,<\xf8\xfdOG0\xf38\x1aq\xeaC\x1c3\u01c9\x0e~\xeb\xa3A\vt\x00\x00\u07d4vz\x03eZ\xf3`\x84\x1e\x81\r\x83\xf5\xe6\x1f\xb4\x0fL\xd1\x13\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4vz\u0190y\x1c.#E\x10\x89\xfelp\x83\xfeU\u07b6+\x89,s\xc97t,P\x00\x00\u07d4v\u007f\xd7y}Qi\xa0_sd2\x1c\x19\x84:\x8c4\x8e\x1e\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u0794v\x84o\r\xe0;Zv\x97\x1e\xad)\x8c\xdd\b\x84:K\xc6\u0188\xd7\x1b\x0f\u088e\x00\x00\xe0\x94v\x84\x98\x93N7\xe9\x05\xf1\xd0\xe7{D\xb5t\xbc\xf3\xecJ\xe8\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4v\x8c\xe0\u06a0)\xb7\xde\xd0\"\xe5\xfcWM\x11\xcd\xe3\xec\xb5\x17\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94v\x93\xbd\xebo\xc8+[\xcar\x13U\"1u\xd4z\bKM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4v\xaa\xf8\xc1\xac\x01/\x87R\xd4\xc0\x9b\xb4f\a\xb6e\x1d\\\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v\xab\x87\xddZ\x05\xad\x83\x9aN/\xc8\xc8Z\xa6\xba\x05d\x170\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v\xaf\xc2%\xf4\xfa0}\xe4\x84U+\xbe\x1d\x9d?\x15\aLJ\x89\xa2\x90\xb5\u01ed9h\x00\x00\xe0\x94v\xbe\xca\xe4\xa3\x1d6\xf3\xcbW\u007f*CYO\xb1\xab\xc1\xbb\x96\x8a\x05C\xa9\xce\x0e\x132\xf0\x00\x00\u07d4v\xc2u5\xbc\xb5\x9c\xe1\xfa-\x8c\x91\x9c\xab\xebJk\xba\x01\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4v\xca\"\xbc\xb8y\x9eS'\u012a*}\tI\xa1\xfc\xce_)\x89R\xa0?\"\x8cZ\xe2\x00\x00\u07d4v\xca\u0108\x11\x1aO\u0555\xf5h\xae:\x85\x87p\xfc\x91]_\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94v\u02dc\x8bi\xf48vu\u0102S\xe24\xcb~\rt\xa4&\x8a\x01\x90\xf4H.\xb9\x1d\xae\x00\x00\u07d4v\xf8:\xc3\xda0\xf7\t&(\xc73\x9f \x8b\xfc\x14,\xb1\ue25a\x18\xff\xe7B}d\x00\x00\xe0\x94v\xf9\xad=\x9b\xbd\x04\xae\x05\\\x14w\xc0\xc3^u\x92\xcb* \x8a\b\x83?\x11\xe3E\x8f \x00\x00\u07d4v\xff\xc1W\xadk\xf8\xd5m\x9a\x1a\u007f\u077c\x0f\xea\x01\n\xab\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\x02\x8e@\x9c\xc4:;\xd3=!\xa9\xfcS\xec`n\x94\x91\x0e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4w\f/\xb2\u0128\x17S\xac\x01\x82\xeaF\x0e\xc0\x9c\x90\xa5\x16\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\r\x98\xd3\x1bCS\xfc\xee\xe8V\fL\u03c0>\x88\xc0\xc4\xe0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94w\x13\xab\x807A\x1c\t\xbah\u007fo\x93d\xf0\xd3#\x9f\xac(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4w\x15\a\xae\xeej%]\xc2\u035d\xf5QT\x06-\b\x97\xb2\x97\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4w\x19\x88\x87\x95\xadtY$\xc7W`\u0771\x82}\xff\xd8\u0368\x89lkLM\xa6\u077e\x00\x00\u07d4w'\xaf\x10\x1f\n\xab\xa4\xd2:\x1c\xaf\xe1|n\xb5\u06b1\xc6\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4w,)\u007f\n\u0454H.\xe8\xc3\xf06\xbd\xeb\x01\xc2\x01\xd5\u0309\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94w0o\xfe.J\x8f<\xa8&\xc1\xa2I\xf7!-\xa4:\xef\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4w1A\x12}\x8c\xf3\x18\xae\xbf\x886Z\xdd=U'\xd8[j\x8966\u05ef^\u024e\x00\x00\u07d4wF\xb6\xc6i\x9c\x8f4\xca'h\xa8 \xf1\xff\xa4\xc2\a\xfe\x05\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4wQ\xf3c\xa0\xa7\xfd\x053\x19\b\t\u076f\x93@\xd8\xd1\x12\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4wW\xa4\xb9\xcc=\x02G\u032a\xeb\x99\t\xa0\xe5n\x1d\xd6\xdc\u0089\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\\\x10\xc9>\r\xb7 [&CE\x823\xc6O\xc3?\xd7[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4wa~\xbcK\xeb\xc5\xf5\xdd\xeb\x1bzp\xcd\xebj\xe2\xff\xa0$\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4wiC\xff\xb2\xef\\\xdd5\xb8<(\xbc\x04k\xd4\xf4gp\x98\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94wp\x1e,I=\xa4|\x1bX\xf4!\xb5I]\xeeE\xbe\xa3\x9b\x8a\x01H\xf6I\xcfaB\xa5\x80\x00\u07d4wy\x8f \x12W\xb9\xc3R\x04\x95pW\xb5Ft\xae\xfaQ\u07c9\b\x13\xcaV\x90m4\x00\x00\u07d4w\x8cC\xd1\x1a\xfe;Xo\xf3t\x19-\x96\xa7\xf2=+\x9b\u007f\x89\x8b\xb4\xfc\xfa;}k\x80\x00\u07d4w\x8cy\xf4\xde\x19S\xeb\u0398\xfe\x80\x06\xd5:\x81\xfbQ@\x12\x8963\x03\"\xd5#\x8c\x00\x00\u07d4w\x92t\xbf\x18\x03\xa36\xe4\u04f0\r\u0753\xf2\xd4\xf5\xf4\xa6.\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xa1q\"\xfa1\xb9\x8f\x17\x11\xd3*\x99\xf0>\xc3&\xf3=\b\x89\\(=A\x03\x94\x10\x00\x00\u07d4w\xa3I\a\xf3\x05\xa5L\x85\xdb\t\xc3c\xfd\xe3\xc4~j\xe2\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4w\xa7i\xfa\xfd\xec\xf4\xa68v-[\xa3\x96\x9d\xf61 \xa4\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xbekd\xd7\xc73\xa46\xad\xec^\x14\xbf\x9a\xd7@+\x1bF\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xbf\xe9<\u0367P\x84~A\xa1\xaf\xfe\xe6\xb2\u0696\xe7!N\x89\x10CV\x1a\x88)0\x00\x00\u07d4w\u0126\x97\xe6\x03\xd4+\x12\x05l\xbb\xa7a\xe7\xf5\x1d\x04C\xf5\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4w\xcc\x02\xf6#\xa9\u03d8S\t\x97\xeag\xd9\\;I\x18Y\xae\x89Is\x03\xc3n\xa0\xc2\x00\x00\u07d4w\xd4?\xa7\xb4\x81\xdb\xf3\xdbS\f\xfb\xf5\xfd\xce\xd0\xe6W\x181\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xda^lr\xfb6\xbc\xe1\xd9y\x8f{\xcd\xf1\u044fE\x9c.\x89\x016\x95\xbbl\xf9>\x00\x00\u07d4w\xf4\xe3\xbd\xf0V\x88<\xc8r\x80\xdb\xe6@\xa1\x8a\r\x02\xa2\a\x89\n\x81\x99:+\xfb[\x00\x00\u0794w\xf6\t\u0287 \xa0#&,U\xc4o-&\xfb90\xaci\x88\xf0\x15\xf2W6B\x00\x00\u07d4w\xf8\x1b\x1b&\xfc\x84\xd6\u0797\uf2df\xbdr\xa310\xccJ\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\x19\xb0E\x8e1N+S\xbf\xe0\f8I_\u0539\xfd\xf8\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4x\x1b\x15\x01dz.\x06\xc0\xedC\xff\x19\u007f\xcc\xec5\xe1p\v\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4x/R\xf0\xa6v\xc7w\x16\xd5t\xc8\x1e\xc4hO\x9a\x02\n\x97\x89.\x14\xe2\x06\xb70\xad\x80\x00\u07d4x5]\xf0\xa20\xf8=\x03,p1TAM\xe3\xee\u06b5W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x6\xf7\xefk\u01fd\x0f\xf3\xac\xafD\x9c\x84\xddk\x1e,\x93\x9f\x89\xe0\x8d\xe7\xa9,\xd9|\x00\x00\u07d4x7\xfc\xb8v\xda\x00\xd1\xeb;\x88\xfe\xb3\xdf?\xa4\x04/\xac\x82\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4x>\uc2a5\xda\xc7{.f#\xedQ\x98\xa41\xab\xba\xee\a\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4x\\\x8e\xa7t\xd70D\xa74\xfay\n\x1b\x1et>w\xed|\x89\f\xf1Rd\f\\\x83\x00\x00\u07d4x`\xa3\xde8\xdf8*\xe4\xa4\xdc\xe1\x8c\f\a\xb9\x8b\xce=\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94xcCq\xe1s\x04\xcb\xf39\xb1E*L\xe48\xdcvL\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4xd\u0719\x9f\xe4\xf8\xe0\x03\xc0\xf4=\xec\u00da\xae\x15\"\xdc\x0f\x89\x05\x1e\x10+\xd8\xec\xe0\x00\x00\u07d4xtj\x95\x8d\xce\xd4\xc7d\xf8vP\x8cAJh4,\uce49\x02\xbe7O\xe8\xe2\xc4\x00\x00\xe0\x94x}1?\xd3k\x05>\xee\xae\xdb\xcet\xb9\xfb\x06x32\x89\x8a\x05\xc0X\xb7\x84'\x19`\x00\x00\u07d4x\x85\x9c[T\x8bp\r\x92\x84\xce\xe4\xb6c=GJ\x8a\x04{\x92\xc4\x15B$-\n\b\xc7\x0f\x99\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4x\u03c36\xb3(\xdb=\x87\x81:G+\x9e\x89\xb7^\f\xf3\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\xd4\xf8\xc7\x1c\x1eh\xa6\x9a\x98\xf5/\xcbE\u068a\xf5n\xa1\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x\xdf&\x81\xd6\xd6\x02\xe2!B\xd5A\x16\u07a1]EIW\xaa\x89\x10'\x94\xad \xdah\x00\x00\u07d4x\xe0\x8b\xc53A<&\u2473\x14?\xfa|\u026f\xb9{x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4x\xe8?\x80\xb3g\x8cz\nN>\x8c\x84\xdc\xcd\xe0dBbw\x89a\t=|,m8\x00\x00\u07d4x\xf5\xc7G\x85\xc5f\x8a\x83\x80r\x04\x8b\xf8\xb4SYM\u06ab\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\x0f\x91\xbd]\x1c\\\xc4s\x9a\xe9\x13\x00\u06c9\xe1\xc10<\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\x17\u5f42\xa9y\x0f\xd6P\xd0C\xcd\xd90\xf7y\x963\u06c9\xd8\xd4`,&\xbfl\x00\x00\u07d4y\x19\xe7b\u007f\x9b}T\xea;\x14\xbbM\xd4d\x9fO9\xde\xe0\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4y\x1f`@\xb4\xe3\xe5\r\xcf5S\xf1\x82\u0357\xa9\x060\xb7]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4y0\xc2\xd9\xcb\xfa\x87\xf5\x10\xf8\xf9\x87w\xff\x8a\x84H\xcaV)\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4yE)\u041d\x01rq5\x970\x02pu\xb8z\xd8=\xaen\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4yKQ\u00deS\xd9\xe7b\xb0a;\x82\x9aD\xb4r\xf4\xff\xf3\x89$5\xe0dxA\u0300\x00\xe0\x94yU\x1c\xed\xe3v\xf7G\xe3ql\x8dy@\rvm.\x01\x95\x8a\t\xcb7\xaf\xa4\xffxh\x00\x00\u07d4y^\xbc&&\xfc9\xb0\xc8b\x94\xe0\xe87\xdc\xf5#U0\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4yn\xbb\xf4\x9b>6\xd6v\x94\xady\xf8\xff6vz\xc6\xfa\xb0\x89\x03K\xc4\xfd\xde'\xc0\x00\x00\u07d4yo\x87\xbaaz)0\xb1g\v\xe9.\xd1(\x1f\xb0\xb3F\xe1\x89\x06\xf5\xe8o\xb5((\x00\x00\u07d4yt'\xe3\xdb\xf0\xfe\xaez%\x06\xf1-\xf1\xdc@2n\x85\x05\x8965\u026d\xc5\u07a0\x00\x00\u07d4yu\x10\xe3\x86\xf5c\x93\xce\xd8\xf4w7\x8aDLHO}\xad\x8965\u026d\xc5\u07a0\x00\x00\u07d4y{\xb7\xf1W\xd9\xfe\xaa\x17\xf7m\xa4\xf7\x04\xb7M\xc1\x03\x83A\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4y\x88\x90\x131\xe3\x87\xf7\x13\xfa\u03b9\x00\\\xb9\xb6Q6\xeb\x14\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4y\x89\u041f8&\xc3\u5bccu*\x81\x15r:\x84\xd8\tp\x89\x16\x86\xf8aL\xf0\xad\x00\x00\xe0\x94y\x95\xbd\x8c\xe2\xe0\xc6{\xf1\u01e51\xd4w\xbc\xa1\xb2\xb9ua\x8a\x01BH\xd6\x17\x82\x9e\xce\x00\x00\u07d4y\xae\xb3Ef\xb9t\xc3ZX\x81\xde\xc0 \x92}\xa7\xdf]%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xb1 \xeb\x88\x06s#!(\x8fgZ'\xa9\"_\x1c\xd2\ub245\xa0\xbf7\xde\xc9\xe4\x00\x00\u07d4y\xb4\x8d-a7\u00c5Ma\x1c\x01\xeaBBz\x0fY{\xb7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4y\xb8\xaa\xd8y\xdd0V~\x87x\xd2\xd21\xc8\xf3z\xb8sN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xbf/{n2\x8a\xaf&\xe0\xbb\t?\xa2-\xa2\x9e\xf2\xf4q\x89a\t=|,m8\x00\x00\u07d4y\xc10\xc7b\xb8v[\x19\u04ab\u0260\x83\xab\x8f:\xady@\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4y\xc1\xbe\x19q\x1fs\xbe\xe4\xe61j\xe7T\x94Y\xaa\u03a2\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\xc6\x00/\x84R\xca\x15\u007f\x13\x17\xe8\n/\xaf$GUY\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4y\xca\xc6IO\x11\xef'\x98t\x8c\xb52\x85\xbd\x8e\"\xf9|\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4y\u03e9x\n\xe6\xd8{,1\x88?\t'i\x86\u021ag5\x8965\u026d\xc5\u07a0\x00\x00\u07d4y\u06e2VG-\xb4\xe0X\xf2\xe4\xcd\xc3\xeaN\x8aBw83\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4y\xed\x10\xcf\x1fm\xb4\x82\x06\xb5\t\x19\xb9\xb6\x97\b\x1f\xbd\xaa\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xf0\x8e\x01\xce\t\x88\xe6<\u007f\x8f)\b\xfa\xdeC\xc7\xf9\xf5\u0248\xfc\x93c\x92\x80\x1c\x00\x00\u07d4y\xfdmH1Pf\xc2\x04\xf9e\x18i\xc1\tl\x14\xfc\x97\x81\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xff\xb4\xac\x13\x81*\vx\u0123{\x82u\">\x17k\xfd\xa5\x88\xf0\x15\xf2W6B\x00\x00\u07d4z\x05\x89\xb1C\xa8\xe5\xe1\a\u026cf\xa9\xf9\xf8Yz\xb3\u7ac9Q\xe92\xd7n\x8f{\x00\x00\u07d4z\nx\xa9\xcc9?\x91\xc3\xd9\xe3\x9ak\x8c\x06\x9f\a^k\xf5\x89Hz\x9a0E9D\x00\x00\u07d4z\x13p\xa7B\xec&\x87\xe7a\xa1\x9a\u0167\x942\x9e\xe6t\x04\x89\xa2\xa12ga\xe2\x92\x00\x00\xe0\x94z-\xfcw\x0e$6\x811\xb7\x84w\x95\xf2\x03\xf3\xd5\r[V\x8a\x02i\xfe\xc7\xf06\x1d \x00\x00\u07d4z3\x83N\x85\x83s>-R\xae\xadX\x9b\u046f\xfb\x1d\xd2V\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94z6\xab\xa5\xc3\x1e\xa0\xca~'{\xaa2\xecF\u0393\xcfu\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94z8\x11\"\xba\xday\x1az\xb1\xf6\x03}\xac\x80C'S\xba\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94zH\xd8w\xb6:\x8f\x8f\x93\x83\xe9\xd0\x1eS\xe8\fR\x8e\x95_\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4zO\x9b\x85\x06\x90\xc7\xc9F\x00\xdb\xee\f\xa4\xb0\xa4\x11\xe9\xc2!\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4zc\x86\x9f\xc7g\xa4\u01b1\xcd\x0e\x06I\xf3cL\xb1!\xd2K\x89\x043\x87Oc,\xc6\x00\x00\u07d4zg\xdd\x04:PO\xc2\xf2\xfcq\x94\xe9\xbe\xcfHL\xec\xb1\xfb\x89\r\x8drkqw\xa8\x00\x00\xe0\x94zk&\xf48\u0663RD\x91U\xb8\x87l\xbd\x17\xc9\u065bd\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4zmx\x1cw\u013a\x1f\xca\xdfhsA\xc1\xe3\x17\x99\xe9='\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4zph\xe1\xc37\\\x0eY\x9d\xb1\xfb\xe6\xb2\xea#\xb8\xf4\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4zt\xce\xe4\xfa\x0fcp\xa7\x89O\x11l\xd0\f\x11G\xb8>Y\x89+^:\xf1k\x18\x80\x00\x00\u07d4zy\xe3\x0f\xf0W\xf7\n=\x01\x91\xf7\xf5?v\x157\xaf}\xff\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94zzO\x80sW\xa4\xbb\xe6\x8e\x1a\xa8\x0692\x10\xc4\x11\u0333\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4z\x85c\x86y\x01 o?+\xf0\xfa>\x1c\x81\t\u02bc\u0345\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94z\x87\x97i\n\xb7{Tp\xbf|\f\x1b\xbaa%\b\xe1\xac}\x8a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4z\x8c\x89\xc0\x14P\x9dV\u05f6\x810f\x8f\xf6\xa3\xec\xecsp\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94z\x94\xb1\x99\x92\u03b8\xcec\xbc\x92\xeeKZ\xde\xd1\fM\x97%\x8a\x03\x8d\x1a\x80d\xbbd\xc8\x00\x00\u07d4z\xa7\x9a\xc0C\x16\u030d\b\xf2\x00e\xba\xa6\xd4\x14(\x97\xd5N\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4z\xadM\xbc\u04ec\xf9\x97\u07d3XiV\xf7+d\u062d\x94\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94z\xb2V\xb2\x04\x80\n\xf2\x017\xfa\xbc\xc9\x16\xa22Xu%\x01\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\xbaV\xf6:H\xbc\b\x17\u05b9p9\x03\x9az\xd6/\xae.\x89 \x86\xac5\x10R`\x00\x00\xe0\x94z\xbb\x10\xf5\xbd\x9b\xc3;\x8e\xc1\xa8-d\xb5[k\x18wuA\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\u010d@\xc6d\u031am\x89\xf1\xc5\xf5\xc8\n\x1cp\xe7D\u6263\x10b\xbe\xee\xd7\x00\x00\x00\u07d4z\u014fo\xfcO\x81\a\xaen07\x8eN\x9f\x99\xc5\u007f\xbb$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4z\xd3\xf3\aao\x19\u0731C\xe6DM\xab\x9c<3a\x1fR\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4z\xd8,\xae\xa1\xa8\xb4\xed\x051\x9b\x9c\x98p\x17<\x81N\x06\xee\x89!d\xb7\xa0J\u0220\x00\x00\u07d4z\xde]f\xb9D\xbb\x86\f\x0e\xfd\xc8bv\u054fFS\xf7\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xdf\xed\xb0m\x91\xf3\xccs\x90E\v\x85U\x02p\x88<{\xb7\x89\x11x\xfa@Q]\xb4\x00\x00\u07d4z\xe1\xc1\x9eS\xc7\x1c\xeeLs\xfa\xe2\xd7\xfcs\xbf\x9a\xb5\u348965\u026d\xc5\u07a0\x00\x00\u07d4z\xe6Y\xeb;\xc4hR\xfa\x86\xfa\xc4\xe2\x1cv\x8dP8\x89E\x89\x0f\x81\f\x1c\xb5\x01\xb8\x00\x00\u07d4z\xea%\xd4+&\x12(n\x99\xc56\x97\u01bcA\x00\xe2\u06ff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xef{U\x1f\v\x9cF\xe7U\xc0\xf3\x8e[:s\xfe\x11\x99\xf5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4{\v1\xffn$t^\xad\x8e\u067b\x85\xfc\v\xf2\xfe\x1dU\u0509+^:\xf1k\x18\x80\x00\x00\xe0\x94{\x0f\xea\x11v\xd5!Y3:\x14<)IC\xda6\xbb\u0774\x8a\x01\xfc}\xa6N\xa1L\x10\x00\x00\u07d4{\x11g<\xc0\x19bk)\f\xbd\xce&\x04o~m\x14\x1e!\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x12!b\xc9\x13\xe7\x14l\xad\v~\xd3z\xff\xc9*\v\xf2\u007f\x89Q\xaf\tk#\x01\u0440\x00\u07d4{\x1b\xf5:\x9c\xbe\x83\xa7\u07a44W\x9f\xe7*\xac\x8d*\f\u0409\n\xd4\xc81j\v\f\x00\x00\u07d4{\x1d\xaf\x14\x89\x1b\x8a\x1e\x1b\xd4)\u0633k\x9aJ\xa1\u066f\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x1f\xe1\xabM\xfd\x00\x88\xcd\xd7\xf6\x01c\xefY\xec*\xee\x06\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4{%\xbb\x9c\xa8\xe7\x02!~\x933\"RP\xe5<6\x80MH\x89e\xea=\xb7UF`\x00\x00\u07d4{'\xd0\xd1\xf3\xdd<\x14\x02\x94\xd0H\x8bx>\xbf@\x15'}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94{@\a\xc4^ZW?\u06f6\xf8\xbdtk\xf9J\xd0J<&\x8a\x038!\xf5\x13]%\x9a\x00\x00\u07d4{C\xc7\xee\xa8\xd6#U\xb0\xa8\xa8\x1d\xa0\x81\xc6Dk3\xe9\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4{M*8&\x90i\xc1\x85Ww\rY\x1d$\xc5\x12\x1f^\x83\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94{au\xec\x9b\xef\xc78$\x955\xdd\xde4h\x8c\xd3n\xdf%\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94{f\x12hy\x84M\xfa4\xfee\xc9\xf2\x88\x11\u007f\xef\xb4I\xad\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4{j\x84q\x8d\xd8nc3\x84)\xac\x81\x1d|\x8a\x86\x0f!\xf1\x89a\t=|,m8\x00\x00\xe0\x94{q,z\xf1\x16v\x00jf\xd2\xfc\\\x1a\xb4\xc4y\xce`7\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4{s$-u\u029a\xd5X\xd6P)\r\xf1v\x92\xd5L\u0638\x89lnY\xe6|xT\x00\x00\u07d4{v\x1f\xeb\u007f\u03e7\xde\xd1\xf0\xeb\x05\x8fJ`\v\xf3\xa7\b\u02c9\xf9]\xd2\xec'\xcc\xe0\x00\x00\xe0\x94{\x82|\xae\u007f\xf4t\t\x18\xf2\xe00\xab&\u02d8\xc4\xf4l\xf5\x8a\x01\x94hL\v9\xde\x10\x00\x00\xe0\x94{\x892\x86B~r\xdb!\x9a!\xfcM\xcd_\xbfY(<1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4{\x92&\xd4o\xe7Q\x94\v\xc4\x16\xa7\x98\xb6\x9c\xcf\r\xfa\xb6g\x89\u3bb5sr@\xa0\x00\x00\u07d4{\x98\xe2<\xb9k\xee\xe8\n\x16\x80i\ube8f \xed\xd5\\\u03c9\v\xa0\xc9\x15\x87\xc1J\x00\x00\u07d4{\xb0\xfd\xf5\xa6c\xb5\xfb\xa2\x8d\x9c\x90*\xf0\xc8\x11\xe2R\xf2\x98\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4{\xb9W\x1f9K\v\x1a\x8e\xbaVd\xe9\u0635\xe8@g{\xea\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94{\xb9\x84\xc6\u06f9\xe2y\x96j\xfa\xfd\xa5\x9c\x01\xd0&'\xc8\x04\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4{\xbb\xec^p\xbd\xea\u063b2\xb4(\x05\x98\x8e\x96H\xc0\xaa\x97\x8966\u05ef^\u024e\x00\x00\u07d4{\xca\x1d\xa6\xc8\nf\xba\xa5\xdbZ\u0245A\u013e'kD}\x89$\xcf\x04\x96\x80\xfa<\x00\x00\u07d4{\u0772\xee\x98\xde\x19\xeeL\x91\xf6a\xee\x8eg\xa9\x1d\x05K\x97\x8965\u026d\xc5\u07a0\x00\x00\u0794{\xe2\xf7h\f\x80-\xa6\x15L\x92\xc0\x19J\xe72Qzqi\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4{\xe7\xf2Eiq\x88;\x9a\x8d\xbeL\x91\xde\xc0\x8a\xc3N\x88b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4{\xe8\u0334\xf1\x1bf\xcan\x1dW\xc0\xb59b!\xa3\x1b\xa5:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94{\xeb\x81\xfb/^\x91Rk*\xc9y^v\u019b\xcf\xf0K\xc0\x8a\x0e\xb2.yO\n\x8d`\x00\x00\u07d4|\b\x83\x05L-\x02\xbcz\x85+\x1f\x86\xc4'w\xd0\xd5\xc8V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\x0f^\a C\xc9\xeet\x02B\x19~x\xccK\x98\xcd\xf9`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|\x1d\xf2JO\u007f\xb2\u01f4r\xe0\xbb\x00l\xb2}\xcd\x16AV\x8965\u026d\xc5\u07a0\x00\x00\u07d4|)\xd4}W\xa73\xf5k\x9b!pc\xb5\x13\xdc;1Y#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4|+\x96\x03\x88JO.FN\u03b9}\x17\x93\x8d\x82\x8b\xc0,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4|8,\x02\x96a.N\x97\xe4@\xe0-8q';U\xf5;\x89\n\xb6@9\x12\x010\x00\x00\u07d4|>\xb7\x13\xc4\xc9\xe08\x1c\xd8\x15L|\x9a}\xb8d\\\xde\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|D\x01\xae\x98\xf1.\xf6\xde9\xae$\u03df\xc5\x1f\x80\xeb\xa1k\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|E\xf0\xf8D*V\xdb\u04dd\xbf\x15\x99\x95A\\R\xedG\x9b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|S-\xb9\xe0\xc0l&\xfd@\xac\xc5j\xc5\\\x1e\xe9-<:\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4|`\xa0_zJ_\x8c\xf2xC\x916.uZ\x83A\xefY\x89f\x94\xf0\x18*7\xae\x00\x00\u07d4|`\xe5\x1f\v\xe2(\xe4\xd5o\xdd)\x92\xc8\x14\xdaw@\u01bc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|i$\xd0|>\xf5\x89\x19f\xfe\nxV\xc8{\xef\x9d 4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|\x8b\xb6Zo\xbbI\xbdA3\x96\xa9\xd7\xe3\x10S\xbb\xb3z\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94|\x9a\x11\f\xb1\x1f%\x98\xb2\xb2\x0e,\xa4\x002^A\xe9\xdb3\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4|\xbc\xa8\x8f\xcaj\x00`\xb9`\x98\\\x9a\xa1\xb0%4\xdc\"\b\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4|\xbe\xb9\x992\xe9~n\x02\x05\x8c\xfcb\u0432k\xc7\u0325+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xc2Jj\x95\x8c \xc7\xd1$\x96`\xf7Xb&\x95\v\r\x9a\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4|\xd2\x0e\u0335\x18\xb6\f\xab\t[r\x0fW\x15p\u02aaD~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\xd5\xd8\x1e\xab7\xe1\x1ebv\xa3\xa1\t\x12Q`~\r~8\x89\x03hM^\xf9\x81\xf4\x00\x00\u07d4|\xdft!9E\x95=\xb3\x9a\xd0\xe8\xa9x\x1a\xddy.M\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xe4hdF\U000547be\xd6r\x15\xeb\rZ\x1d\xd7,\x11\xb8\x89x9\xd3!\xb8\x1a\xb8\x00\x00\u07d4|\xefMC\xaaA\u007f\x9e\xf8\xb7\x87\xf8\xb9\x9dS\xf1\xfe\xa1\ue209g\x8a\x93 b\xe4\x18\x00\x00\u07d4}\x03P\xe4\v3\x8d\xdasfa\x87+\xe3?\x1f\x97R\xd7U\x89\x02\xb4\xf5\xa6\U00051500\x00\xe0\x94}\x04\xd2\xed\xc0X\xa1\xaf\xc7a\xd9\u025a\xe4\xfc\\\x85\xd4\u0226\x8aB\xa9\xc4g\\\x94g\xd0\x00\x00\u07d4}\v%^\xfbW\xe1\x0fp\b\xaa\"\xd4\x0e\x97R\xdf\xcf\x03x\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94}\x13\xd6pX\x84\xab!W\u074d\xccpF\xca\xf5\x8e\xe9K\xe4\x8a\x1d\r\xa0|\xbb>\xe9\xc0\x00\x00\u07d4}'>c~\xf1\xea\u0101\x11\x94\x13\xb9\x1c\x98\x9d\xc5\xea\xc1\"\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4}*R\xa7\xcf\f\x846\xa8\xe0\a\x97kl&\xb7\"\x9d\x1e\x15\x89\x17\xbf\x06\xb3*$\x1c\x00\x00\u07d4}4\x805i\xe0\v\u05b5\x9f\xff\b\x1d\xfa\\\n\xb4\x19zb\x89\\\xd8|\xb7\xb9\xfb\x86\x00\x00\u07d4}4\xffY\xae\x84\nt\x13\u01baL[\xb2\xba,u\xea\xb0\x18\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4}9(R\xf3\xab\xd9/\xf4\xbb[\xb2l\xb6\bt\xf2\xbeg\x95\x8966\xc2^f\xec\xe7\x00\x00\u07d4}DRg\u015a\xb8\u04a2\xd9\xe7\t\x99\x0e\th%\x80\u011f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94}U\x13\x97\xf7\x9a)\x88\xb0d\xaf\xd0\xef\xeb\xee\x80,w!\xbc\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\u07d4}Z\xa3?\xc1KQ\x84\x1a\x06\x90n\xdb+\xb4\x9c*\x11ri\x89\x10D\x00\xa2G\x0eh\x00\x00\xe0\x94}]/s\x94\x9d\xad\xda\bV\xb2\x06\x98\x9d\xf0\a\x8dQ\xa1\xe5\x8a\x02\xc4:H\x1d\xf0M\x01wb\xed\xcb\\\xaab\x9bZ\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4~\x8f\x96\xcc)\xf5{\tu\x12\f\xb5\x93\xb7\u0743=`kS\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4~\x97*\x8a|*D\xc9;!Cl8\xd2\x1b\x92R\xc3E\xfe\x89a\t=|,m8\x00\x00\u07d4~\x99\u07fe\x98\x9d;\xa5)\u0457Q\xb7\xf41\u007f\x89S\xa3\xe2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4~\xa0\xf9n\xe0\xa5s\xa30\xb5h\x97v\x1f=L\x010\xa8\xe3\x89Hz\x9a0E9D\x00\x00\u0794~\xa7\x91\xeb\xab\x04E\xa0\x0e\xfd\xfcNJ\x8e\x9a~ue\x13m\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4~\xab\xa05\xe2\xaf7\x93\xfdtgK\x10%@\xcf\x19\n\u0779\x89E\x02l\x83[`D\x00\x00\xe0\x94~\xb4\xb0\x18\\\x92\xb6C\x9a\b\xe72!h\xcb5<\x8awJ\x8a\x02'\x19l\xa0I\x83\xca\x00\x00\xe0\x94~\xbd\x95\xe9\xc4p\xf7(5\x83\xdcn\x9d,M\xce\v\ua3c4\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4~\u0425\xa8G\xbe\xf9\xa9\xda|\xba\x1dd\x11\xf5\xc3\x161&\x19\x89\x02(\xeb7\xe8u\x1d\x00\x00\u07d4~\xda\xfb\xa8\x98K\xafc\x1a\x82\vk\x92\xbb\xc2\xc56U\xf6\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4~\xdb\x02\xc6\x1a\"r\x87a\x1a\xd9Pici\xccNdzh\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4~\xe5\u0280]\xce#\xaf\x89\xc2\xd4D\xe7\xe4\af\xc5Lt\x04\x89\r\v\xd4\x12\xed\xbd\x82\x00\x00\xe0\x94~\xe6\x04\u01e9\xdc)\t\xce2\x1d\u6e72OWgWuU\x8a\x01+\xf9\u01d8\\\xf6-\x80\x00\u07d4~\xf1o\xd8\xd1[7\x8a\x0f\xba0k\x8d\x03\u0758\xfc\x92a\x9f\x89%\xf2s\x93=\xb5p\x00\x00\u07d4~\xf9\x8bR\xbe\xe9S\xbe\xf9\x92\xf3\x05\xfd\xa0'\xf8\x91\x1cXQ\x89\x1b\xe7\" i\x96\xbc\x80\x00\u07d4~\xfc\x90vj\x00\xbcR7,\xac\x97\xfa\xbd\x8a<\x83\x1f\x8e\u0349\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4~\xfe\xc0\xc6%<\xaf9\u007fq(|\x1c\a\xf6\xc9X+[\x86\x89\x1a,\xbc\xb8O0\u0540\x00\u07d4\u007f\x01\xdc|7G\xca`\x8f\x98=\xfc\x8c\x9b9\xe7U\xa3\xb9\x14\x89\v8l\xad_zZ\x00\x00\u07d4\u007f\x06b\xb4\x10)\x8c\x99\xf3\x11\u04e1EJ\x1e\xed\xba/\xeav\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u007f\x06\u021dY\x80\u007f\xa6\v\xc6\x016\xfc\xf8\x14\u02ef%C\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u007f\v\x90\xa1\xfd\u050f'\xb2h\xfe\xb3\x83\x82\xe5]\xdbP\xef\x0f\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\u007f\x0e\xc3\u06c0F\x92\xd4\xd1\xea2E6Z\xab\x05\x90\a[\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u007f\x0f\x04\xfc\xf3zS\xa4\xe2N\xden\x93\x10Nx\xbe\x1d<\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007f\x13\xd7`I\x8dq\x93\xcahY\xbc\x95\xc9\x018d#\xd7l\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u007f\x15\n\xfb\x1aw\u00b4Y(\xc2h\xc1\u9f74d\x1dG\u0609lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\x16\x19\x98\x8f7\x15\xe9O\xf1\xd2S&-\xc5X\x1d\xb3\xde\x1c\x890\xca\x02O\x98{\x90\x00\x00\u07d4\u007f\x1c\x81\xee\x16\x97\xfc\x14K|\v\xe5I;V\x15\xae\u007f\xdd\u0289\x1b\x1d\xaba\u04ead\x00\x00\u07d4\u007f#\x82\xff\xd8\xf89VFy7\xf9\xbar7F#\xf1\x1b8\x89 \x86\xac5\x10R`\x00\x00\u07d4\u007f7\t9\x1f?\xbe\xba5\x92\xd1u\xc7@\xe8z\tT\x1d\x02\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\u007f8\x9c\x12\xf3\xc6\x16OdFVlwf\x95\x03\xc2y%'\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\u007f:\x1eE\xf6~\x92\u0200\xe5s\xb43y\xd7\x1e\xe0\x89\xdbT\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\u007f=r\x03\u0224G\xf7\xbf6\u060a\xe9\xb6\x06*^\xeex\xae\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u007fF\xbb%F\r\xd7\xda\xe4!\x1c\xa7\xf1Z\xd3\x12\xfc}\xc7\\\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\u007fI\xe7\xa4&\x98\x82\xbd\x87\"\u0526\xf5f4v)b@y\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007fI\xf2\a&G\x1a\xc1\u01e8>\xf1\x06\xe9w\\\xebf%f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\u007fK^'\x85x\xc0F\xcc\xea\xf6W0\xa0\xe0h2\x9e\u0576\x89e\xea=\xb7UF`\x00\x00\u07d4\u007fOY;a\x8c3\v\xa2\xc3\xd5\xf4\x1e\xce\xeb\x92\xe2~Bl\x89\x96n\xdcuk|\xfc\x00\x00\u07d4\u007fT\x14\x91\u04ac\x00\xd2a/\x94\xaa\u007f\v\xcb\x01FQ\xfb\u0509\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\u007fZ\xe0Z\xe0\xf8\xcb\xe5\xdf\xe7!\xf0D\u05e7\xbe\xf4\xc2y\x97\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u007f`:\xec\x17Y\xea_\a\xc7\xf8\xd4\x1a\x14(\xfb\xba\xf9\xe7b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u007falo\x00\x8a\u07e0\x82\xf3M\xa7\xd0e\x04`6\x80u\xfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u007fa\xfal\xf5\xf8\x98\xb4@\xda\u016b\xd8`\rmi\x1f\xde\xf9\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u007fe\\g\x89\xed\xdfE\\\xb4\xb8\x80\x99r\x0698\x9e\ubb0a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u007fk(\u0204!\xe4\x85~E\x92\x81\u05c4ai$\x89\xd3\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007fn\xfboC\x18\x87m.\xe6$\xe2u\x95\xf4DF\xf6\x8e\x93\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u007fq\x92\xc0\xdf\x1c}\xb6\xd9\xede\xd7\x11\x84\xd8\xe4\x15Z\x17\xba\x89\x04Sr\x8d3\x94,\x00\x00\u07d4\u007fz:!\xb3\xf5\xa6]\x81\xe0\xfc\xb7\xd5-\xd0\n\x1a\xa3m\xba\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u007f\x8d\xbc\xe1\x80\xed\x9cV65\xaa\xd2\xd9{L\xbcB\x89\x06\u0649\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\u007f\x99=\xdb~\x02\u0082\xb8\x98\xf6\x15_h\x0e\xf5\xb9\xaf\xf9\a\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u007f\x9f\x9bV\xe4(\x9d\xfbX\xe7\x0f\xd5\xf1*\x97\xb5m5\u01a5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u007f\xa3~\xd6x\x87u\x1aG\x1f\x0e\xb3\x06\xbeD\xe0\xdb\xcd`\x89\x899vt\u007f\xe1\x1a\x10\x00\x00\u07d4\u007f\xaa0\xc3\x15\x19\xb5\x84\xe9rP\xed*<\xf38^\xd5\xfdP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xcf[\xa6fo\x96lTH\xc1{\xf1\xcb\v\xbc\xd8\x01\x9b\x06\x89\x05k\xc3\u042e\xbeI\x80\x00\xe0\x94\u007f\xd6y\xe5\xfb\r\xa2\xa5\xd1\x16\x19M\xcbP\x83\x18\xed\u0140\xf3\x8a\x01c\x9eI\xbb\xa1b\x80\x00\x00\u07d4\u007f\u06e01\u01cf\x9c\tmb\xd0Z6\x9e\uac3c\xccU\u5257\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\u007f\xdb\u00e8D\xe4\r\x96\xb2\xf3\xa652.`e\xf4\xca\x0e\x84\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xdf\u020dx\xbf\x1b(Z\xc6O\x1a\xdb5\xdc\x11\xfc\xb09Q\x89|\x06\xfd\xa0/\xb06\x00\x00\u07d4\u007f\xea\x19b\xe3]b\x05\x97h\xc7I\xbe\u0756\u02b90\xd3x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xef\x8c8w\x9f\xb3\a\xeco\x04K\xeb\xe4\u007f<\xfa\xe7\x96\xf1\x89\t#@\xf8l\xf0\x9e\x80\x00\u07d4\u007f\xf0\xc6?p$\x1b\xec\xe1\x9bs~SA\xb1+\x10\x901\u0609\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\u007f\xfa\xbf\xbc9\f\xbeC\u0389\x18\x8f\bh\xb2}\xcb\x0f\f\xad\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\u007f\xfd\x02\xed7\fp`\xb2\xaeS\xc0x\xc8\x01!\x90\u07fbu\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\x80\x02*\x12\a\xe9\x10\x91\x1f\xc9(I\xb0i\xab\f\xda\xd0C\u04c8\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x80\t\xa7\xcb\u0452\xb3\xae\u052d\xb9\x83\xd5(ER\xc1ltQ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\x0e}c\x1cnW:\x903/\x17\xf7\x1f_\u045bR\x8c\xb9\x89\b=lz\xabc`\x00\x00\u07d4\x80\x15m\x10\ufa320\u0254\x10c\r7\xe2i\xd4\t<\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\x172\xa4\x81\u00c0\xe5~\xd6-l)\u0799\x8a\xf3\xfa;\x13\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x1de\xc5\x18\xb1\x1d\x0e?OG\x02!Ap\x13\xc8\xe5>\u0149\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80&CZ\xacr\x8dI{\x19\xb3\xe7\xe5|(\xc5c\x95O+\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x80-\xc3\xc4\xff-}\x92^\u215fJ\x06\u05fa`\xf10\x8c\x89\x05P\x94\f\x8f\xd3L\x00\x00\u07d4\x800\xb1\x11\u0198?\x04\x85\u076c\xa7b$\xc6\x18\x064x\x9f\x89\x04V9\x18$O@\x00\x00\u07d4\x805\xbc\xff\xae\xfd\xee\xea5\x83\fI}\x14(\x9d6 #\u0789\x10CV\x1a\x88)0\x00\x00\u07d4\x805\xfeNkj\xf2z\u44a5xQ^\x9d9\xfao\xa6[\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80C\xed\"\xf9\x97\u58a4\xc1n6D\x86\xaed\x97V\x92\u0109=I\x04\xff\xc9\x11.\x80\x00\u07d4\x80C\xfd\u043cL\x97=\x16c\xd5_\xc15P\x8e\xc5\xd4\xf4\xfa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80L\xa9IrcOc:Q\xf3V\v\x1d\x06\xc0\xb2\x93\xb3\xb1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x80R-\u07d4N\xc5.'\xd7$\xedL\x93\xe1\xf7\xbe`\x83\u0589\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80Y\x1aB\x17\x9f4\xe6M\x9d\xf7]\xcdF;(hoUt\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x80\\\xe5\x12\x97\xa0y;\x81 g\xf0\x17\xb3\xe7\xb2\u07db\xb1\xf9\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x80]\x84o\xb0\xbc\x02\xa73r&\u0585\xbe\x9e\xe7s\xb9\x19\x8a\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x80c7\x9a{\xf2\u02d2:\x84\xc5\t>h\xda\xc7\xf7T\x81\u0149\x11v\x10.n2\xdf\x00\x00\u07d4\x80hTX\x8e\xcc\xe5AI_\x81\u008a)\x03s\xdf\x02t\xb2\x89\x1f\x8c\xdf\\n\x8dX\x00\x00\u07d4\x80oD\xbd\xebh\x807\x01^\x84\xff!\x80I\xe3\x823*3\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\x80tF\x18\xde9jT1\x97\xeeH\x94\xab\xd0c\x98\xdd|'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80w\xc3\xe4\xc4EXn\tL\xe1\x02\x93\u007f\xa0[s{V\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x90\u007fY1H\xb5|F\xc1w\xe2=%\xab\u012a\xe1\x83a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x97s\x16\x94NYB\xe7\x9b\x0e:\xba\u04cd\xa7F\be\x19\x89\x02\x1auJm\xc5(\x00\x00\xe0\x94\x80\xa0\xf6\xcc\x18l\xf6 \x14\x00sn\x06Z9\x1fR\xa9\xdfJ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x80\xab\xecZ\xa3n\\\x9d\t\x8f\x1b\x94(\x81\xbdZ\xca\u0196=\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb2=8\v\x82\\F\xe098\x99\xa8UVF-\xa0\u1309lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb4-\xe1p\xdb\xd7#\xf4T\xe8\x8fw\x16E-\x92\x98P\x92\x89\x10F#\xc0v-\xd1\x00\x00\u07d4\x80\xb7\x9f3\x83\x90\u047a\x1b77\xa2\x9a\x02W\xe5\xd9\x1e\a1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80\xbf\x99^\u063a\x92p\x1d\x10\xfe\u011f\x9e}\x01M\xbe\xe0&\x89\x1f\x047\xca\x1a~\x12\x80\x00\u07d4\x80\xc0N\xfd1\x0fD\x04\x83\xc7?tK[\x9edY\x9c\xe3\xec\x89A\rXj \xa4\xc0\x00\x00\u07d4\x80\u00e9\xf6\x95\xb1m\xb1Yr\x86\u0473\xa8\xb7il9\xfa'\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\xc5>\xe7\xe35\u007f\x94\xce\rxh\x00\x9c \x8bJ\x13\x01%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xcc!\xbd\x99\xf3\x90\x05\u014f\xe4\xa4H\x90\x92 !\x8ff\u02c966\xc9yd6t\x00\x00\u07d4\x80\xd5\xc4\fY\xc7\xf5N\xa3\xa5_\xcf\xd1uG\x1e\xa3P\x99\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x80\xda/\u0762\x9a\x9e'\xf9\xe1\x15\x97^i\xae\x9c\xfb\xf3\xf2~\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80\xe7\xb3 R0\xa5f\xa1\xf0a\xd9\"\x81\x9b\xb4\xd4\u04a0\xe1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x80\xea\x1a\xcc\x13n\xcaKh\xc8B\xa9Z\xdfk\u007f\xee~\xb8\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\xf0z\xc0\x9e{,<\n=\x1e\x94\x13\xa5D\xc7:A\xbe\u02c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81\r\xb2Vu\xf4^\xa4\xc7\xf3\x17\u007f7\xce)\xe2-g\x99\x9c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81\x13\x9b\xfd\u0326V\xc40 ?r\x95\x8cT;e\x80\xd4\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\x14a\xa2\xb0\u0290\xba\xda\xc0j\x9e\xa1nx{3\xb1\x96\u0309\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\x81\x16M\xeb\x10\x81J\xe0\x83\x91\xf3,\bf{bH\xc2}z\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x81\x18i1\x18A7\xd1\x19*\u020c\xd3\xe1\xe5\xd0\xfd\xb8jt\x89\x9d5\x95\xab$8\xd0\x00\x00\u0794\x81*U\xc4<\xae\xdcYr\x187\x90\x00\xceQ\rT\x886\xfd\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x81.\xa7\xa3\xb2\xc8n\xed2\xffO,sQL\xc6;\xac\xfb\u038965\u026d\xc5\u07a0\x00\x00\u07d4\x814\xdd\x1c\x9d\xf0\xd6\u0225\x81$&\xbbU\xc7a\u0283\x1f\b\x89\x06\xa2\x16\v\xb5|\xcc\x00\x00\u07d4\x81A5\u068f\x98\x11\aW\x83\xbf\x1a\xb6pb\xaf\x8d>\x9f@\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81I\x8c\xa0{\x0f/\x17\xe8\xbb\xc7\xe6\x1a\u007fJ\xe7\xbef\xb7\x8b\x89\x05\x81\xfb\xb5\xb3;\xb0\x00\x00\u07d4\x81Um\xb2sI\xab\x8b'\x00ID\xedP\xa4n\x94\x1a\x0f_\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x81U\xfalQ\xeb1\xd8\bA-t\x8a\xa0\x86\x10P\x18\x12/\x89e\xea=\xb7UF`\x00\x00\xe0\x94\x81V6\v\xbd7\ta\xce\xcakf\x91\xd7P\x06\xad L\xf2\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x81a\xd9@\xc3v\x01\x00\xb9\b\x05)\xf8\xa6\x03%\x03\x0fn\u0709\x10CV\x1a\x88)0\x00\x00\xe0\x94\x81d\xe7\x83\x14\xae\x16\xb2\x89&\xccU=,\xcb\x16\xf3V'\r\x8a\x01\xca\x13N\x95\xfb2\xc8\x00\x00\u07d4\x81e\u02b0\xea\xfbZ2\x8f\xc4\x1a\xc6M\xaeq[.\xef,e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81h\xed\xce\u007f)a\xcf)[\x9f\xcdZE\xc0l\xde\xdan\xf5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81m\x97r\xcf\x119\x91\x16\xcc\x1er\xc2lgt\xc9\xed\xd79\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81s\xc85djg.\x01R\xbe\x10\xff\xe8Ab\xdd%nL\x89\x1a\xab\xdf!E\xb40\x00\x00\u07d4\x81t\x93\u035b\xc6#p*$\xa5o\x9f\x82\xe3\xfdH\xf3\xcd1\x89\x9eK#\xf1-L\xa0\x00\x00\u07d4\x81y\xc8\tp\x18,\u0177\xd8*M\xf0n\xa9M\xb6:%\xf3\x89'o%\x9d\xe6k\xf4\x00\x00\u07d4\x81z\xc3;\xd8\xf8GVsr\x95\x1fJ\x10\u05e9\x1c\xe3\xf40\x89\n\xd7\xc4\x06\xc6m\xc1\x80\x00\xe0\x94\x81\x8f\xfe'\x1f\u00d75e\xc3\x03\xf2\x13\xf6\xd2\u0689\x89~\xbd\x8a\x016\xe0SB\xfe\u1e40\x00\u07d4\x81\x97\x94\x81!s.c\xd9\xc1H\x19N\xca\xd4n0\xb7I\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\x9a\xf9\xa1\xc2s2\xb1\xc3i\xbb\xda\x1b=\xe1\xc6\xe93\xd6@\x89\x11\t\xe6T\xb9\x8fz\x00\x00\xe0\x94\x81\x9c\u06a506x\xef|\xecY\u050c\x82\x16:\xcc`\xb9R\x8a\x03\x13QT_y\x81l\x00\x00\u07d4\x81\x9e\xb4\x99\vZ\xbaUG\t=\xa1+k<\x10\x93\xdfmF\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xa8\x81\x96\xfa\xc5\xf2<>\x12\xa6\x9d\xecK\x88\x0e\xb7\xd9s\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\xbc\xcb\xff\x8fD4~\xb7\xfc\xa9['\xce|\x95$\x92\xaa\xad\x89\b@\xc1!e\xddx\x00\x00\u07d4\x81\xbdu\xab\xd8e\xe0\xc3\xf0J\vO\xdb\xcbt\xd3@\x82\xfb\xb7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\xc1\x8c*#\x8d\xdcL\xba#\n\a-\xd7\xdc\x10\x1eb\x02s\x89Hz\x9a0E9D\x00\x00\u07d4\x81\xc9\xe1\xae\xe2\xd36]S\xbc\xfd\u0356\xc7\xc58\xb0\xfd~\xec\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x81\u03edv\t\x13\xd3\xc3\"\xfc\xc7{I\u00ae9\a\xe7On\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x81\xd6\x19\xffW&\xf2@_\x12\x90Lr\xeb\x1e$\xa0\xaa\xeeO\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x81\xef\u25aev\xc8`\xd1\xc5\xfb\xd3=G\xe8\u0399\x96\xd1W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xf8\xde,(=_\u052f\xbd\xa8]\xed\xf9v\x0e\xab\xbb\xb5r\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x82\f\x19)\x11\x96P[e\x05\x9d\x99\x14\xb7\t\v\xe1\u06c7\u0789\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x82\x1c\xb5\xcd\x05\xc7\uf41f\xe1\xbe`s=\x89c\xd7`\xdcA\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x82\x1dy\x8a\xf1\x99\x89\u00ee[\x84\xa7\xa7(<\xd7\xfd\xa1\xfa\xbe\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x82\x1e\xb9\t\x94\xa2\xfb\xf9K\xdc23\x91\x02\x96\xf7o\x9b\xf6\xe7\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x82$\x9f\xe7\x0fa\u01b1o\x19\xa3$\x84\x0f\xdc\x02\x021\xbb\x02\x8a\x02\x036\xb0\x8a\x93c[\x00\x00\u07d4\x82(\xeb\xc0\x87H\x0f\xd6EG\xca(\x1f^\xac\xe3\x04\x14S\xb9\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\x82)\u03b9\xf0\xd7\b9I\x8dD\xe6\xab\xed\x93\xc5\xca\x05\x9f]\x8a\x1a\x1c\x1b<\x98\x9a \x10\x00\x00\u07d4\x82.\xdf\xf66V:a\x06\xe5.\x9a%\x98\xf7\xe6\xd0\xef'\x82\x89\x01\xf4\xf9i=B\u04c0\x00\u07d4\x822\x19\xa2Yv\xbb*\xa4\xaf\x8b\xadA\xac5&\xb4\x936\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x822\xd1\xf9t.\u07cd\xd9'\xda5;*\xe7\xb4\xcb\xceu\x92\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x824\xf4c\u0444\x85P\x1f\x8f\x85\xac\xe4\x97,\x9bc-\xbc\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x827htg7\xcem\xa3\x12\xd5>TSN\x10o\x96|\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82;\xa7dr8\xd1\x13\xbc\xe9\x96JC\u0420\x98\x11\x8b\xfeM\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x82@t1(\x06\xdaGHCBf\xee\x00!@\u305a\u0089Q\xb1\u04c3\x92a\xac\x00\x00\u07d4\x82C\x8f\u04b3*\x9b\xddgKI\xd8\xcc_\xa2\xef\xf9x\x18G\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82HW(\xd0\xe2\x81V7X\xc7Z\xb2~\xd9\u80a0\x00-\x89\a\xf8\b\xe9)\x1el\x00\x00\u07d4\x82K<\x19)]~\xf6\xfa\xa7\xf3t\xa4y\x84\x86\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82Q5\x8c\xa4\xe0`\u0775Y\xcaX\xbc\v\u077e\xb4\a\x02\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82Q5\xb1\xa7\xfc\x16\x05aL\x8a\xa4\u042cm\xba\u040fH\x0e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\x82S\t\xa7\xd4]\x18\x12\xf5\x1en\x8d\xf5\xa7\xb9ol\x90\x88\x87\x89\x804\xf7\u0671f\xd4\x00\x00\u07d4\x82Z\u007fN\x10\x94\x9c\xb6\xf8\x96Bh\xf1\xfa_W\xe7\x12\xb4\u0109\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82a\xfa#\f\x90\x1dC\xffW\x9fG\x80\u04d9\xf3\x1e`v\xbc\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82b\x16\x9baXp\x13N\xb4\xacl_G\x1ck\xf2\xf7\x89\xfc\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4\x82c\xec\xe5\xd7\t\xe0\u05eeq\u0328h\xed7\xcd/\xef\x80{\x895\xab\x02\x8a\xc1T\xb8\x00\x00\xe0\x94\x82l\xe5y\x052\xe0T\x8ca\x02\xa3\r>\xac\x83k\xd68\x8f\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4\x82n\xb7\xcds\x19\xb8-\xd0z\x1f;@\x90q\xd9n9g\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x82u1\xa6\u0141z\xe3_\x82\xb0\v\x97T\xfc\xf7LU\xe22\x89\xc3(\t>a\xee@\x00\x00\u0794\x82u\xcdhL6y\u0548}\x03fN3\x83E\xdc<\xdd\xe1\x88\xdbD\xe0I\xbb,\x00\x00\u07d4\x82\x84\x92;b\u62ff|+\x9f4\x14\xd1>\xf6\xc8\x12\xa9\x04\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\x82\x8b\xa6Q\u02d3\x0e\xd9xqV)\x9a=\xe4L\u040br\x12\x89Hz\x9a0E9D\x00\x00\u07d4\x82\xa1\\\xef\x1dl\x82`\xea\xf1Y\xea?\x01\x80\xd8g}\xce\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xa8\xb9kl\x9e\x13\xeb\xec\x1e\x9f\x18\xac\x02\xa6\x0e\xa8\x8aH\xff\x89lk\x8c@\x8es\xb3\x00\x00\u07d4\x82\xa8\u02ff\xdf\xf0+.8\xaeK\xbf\xca\x15\xf1\xf0\xe8;\x1a\xea\x89\x04\x9b\x99\x1c'\xefm\x80\x00\u07d4\x82\xe4F\x1e\xb9\xd8I\xf0\x04\x1c\x14\x04!\x9eBr\u0110\n\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xe5w\xb5\x15\xcb+\b`\xaa\xfe\x1c\xe0\x9aY\xe0\x9f\xe7\xd0@\x89 \x86\xac5\x10R`\x00\x00\u07d4\x82\xea\x01\xe3\xbf.\x83\x83nqpN\"\xa2q\x93w\xef\xd9\u00c9\xa4\xccy\x95c\u00c0\x00\x00\u07d4\x82\xf2\xe9\x91\xfd2L_]\x17v\x8e\x9fa3]\xb61\x9dl\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x82\xf3\x9b'X\xaeB'{\x86\u059fu\xe6(\xd9X\xeb\u02b0\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\x82\xf8T\xc9\xc2\xf0\x87\xdf\xfa\x98Z\xc8 \x1ebl\xa5Fv\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x82\xffqo\xdf\x03>\xc7\xe9B\xc9\t\u0643\x18g\xb8\xb6\xe2\xef\x89a\t=|,m8\x00\x00\u07d4\x83\b\xed\n\xf7\xf8\xa3\xc1u\x1f\xaf\xc8w\xb5\xa4*\xf7\xd3X\x82\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x83\x1cD\xb3\b@G\x18K*\xd2\x18h\x06@\x907P\xc4]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x83!\x05\x83\xc1jN\x1e\x1d\xac\x84\xeb\xd3~=\x0f|W\ub909lk\x93[\x8b\xbd@\x00\x00\u07d4\x83,T\x17k\xdfC\xd2\u027c\u05f8\b\xb8\x95V\xb8\x9c\xbf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x833\x16\x98]Gt+\xfe\xd4\x10`J\x91\x95<\x05\xfb\x12\xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x834vK{9zNW\x8fP6M`\xceD\x89\x9b\xff\x94\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\xe0\x94\x83;j\x8e\xc8\xda@\x81\x86\xac\x8a}*m\xd6\x15#\xe7\u0384\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x83=?\xaeT*\xd5\xf8\xb5\f\xe1\x9b\xde+\xecW\x91\x80\u020c\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x83=\xb4,\x14\x16<{\xe4\u02b8j\u0153\xe0bf\u0599\u054a$\xe4\r+iC\xef\x90\x00\x00\xe0\x94\x83V;\xc3d\ud060\xc6\xda;V\xffI\xbb\xf2g\x82z\x9c\x8a\x03\xab\x91\xd1{ \xdeP\x00\x00\u07d4\x83zd]\xc9\\IT\x9f\x89\x9cN\x8b\u03c7S$\xb2\xf5|\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\x83\x8b\xd5e\xf9\x9f\xdeH\x05?y\x17\xfe3<\xf8J\xd5H\xab\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x83\x90\x8a\xa7G\x8am\x1c\x9b\x9b\x02\x81\x14\x8f\x8f\x9f$+\x9f\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x83\x92\xe57vq5x\x01[\xffI@\xcfC\x84\x9d}\u02e1\x89\bM\xf05]V\x17\x00\x00\xe0\x94\x83\x97\xa1\xbcG\xac\xd6GA\x81Y\xb9\x9c\xeaW\xe1\xe6S-n\x8a\x01\xf1\x0f\xa8'\xb5P\xb4\x00\x00\u07d4\x83\x98\xe0~\xbc\xb4\xf7_\xf2\x11m\xe7|\x1c*\x99\xf3\x03\xa4\u03c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xa3\x14\x883\xd9dI\x84\xf7\xc4u\xa7\x85\a\x16\ufd00\xff\x89\xb8Pz\x82\a( \x00\x00\u07d4\x83\xa4\x02C\x8e\x05\x19w=TH2k\xfba\xf8\xb2\f\xf5-\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x83\xa9;[\xa4\x1b\xf8\x87 \xe4\x15y\f\xdc\vg\xb4\xaf4\u0109\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x83\xc2=\x8aP!$\xee\x15\x0f\b\xd7\x1d\xc6rt\x10\xa0\xf9\x01\x8a\a3\x1f;\xfef\x1b\x18\x00\x00\u07d4\x83\u0217\xa8Ki^\xeb\xe4fy\xf7\xda\x19\xd7vb\x1c&\x94\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xd52\u04cdm\xee?`\xad\u018b\x93a3\u01e2\xa1\xb0\u0749\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xdb\xf8\xa1(S\xb4\n\xc6\x19\x96\xf8\xbf\x1d\xc8\xfd\xba\xdd\xd3)\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x83\xdb\xfd\x8e\xda\x01\xd0\u078e\x15\x8b\x16\u0413_\xc28\n]\u01c9 \x86\xac5\x10R`\x00\x00\u07d4\x83\xe4\x80U2|(\xb5\x93o\xd9\xf4D~s\xbd\xb2\xdd3v\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\x83\xfeZ\x1b2\x8b\xaeD\a\x11\xbe\xafj\xad`&\xed\xa6\xd2 \x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x84\x00\x8ar\xf8\x03o?\xeb\xa5B\xe3Px\xc0W\xf3*\x88%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84\x0e\xc8>\xa96!\xf04\xe7\xbb7b\xbb\x8e)\xde\xd4\xc4y\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\x84\x11E\xb4H@\xc9F\xe2\x1d\xbc\x19\x02d\xb8\xe0\xd5\x02\x93i\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4\x84#!\a\x93+\x12\xe01\x86X5%\xce\x02:p>\xf8\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\x84$O\xc9ZiW\xed|\x15\x04\xe4\x9f0\xb8\xc3^\xcaKy\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x841'}{\xdd\x10E}\xc0\x17@\x8c\x8d\xbb\xbdAJ\x8d\xf3\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4\x847Z\xfb\xf5\x9b:\x1da\xa1\xbe2\xd0u\xe0\xe1ZO\xbc\xa5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84;\xd3P/E\xf8\xbcM\xa3p\xb3#\xbd\xac?\xcf_\x19\xa6\x89P\x03\x9dc\xd1\x1c\x90\x00\x00\u07d4\x84P34c\rw\xf7AG\xf6\x8b.\bf\x13\xc8\xf1\xad\xe9\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x84R\x03u\x0fqH\xa9\xaa&)!\xe8mC\xbfd\x19t\xfd\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84a\xec\u0126\xa4^\xb1\xa5\xb9G\xfb\x86\xb8\x80i\xb9\x1f\xcdo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84g^\x91wrmE\xea\xa4k9\x92\xa3@\xba\u007fq\f\x95\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x84hl{\xadv,T\xb6g\u055f\x90\x94<\xd1M\x11z&\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\x89\xf6\xad\x1d\x9a\x94\xa2\x97x\x91V\x89\x9d\xb6AT\xf1\u06f5\x89\x13t\a\xc0<\x8c&\x80\x00\u07d4\x84\x8c\x99Jy\x00?\xe7\xb7\xc2l\xc62\x12\xe1\xfc/\x9c\x19\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x8f\xbd)\xd6|\xf4\xa0\x13\xcb\x02\xa4\xb1v\xef$N\x9e\u6349\x01\x17*ck\xbd\xc2\x00\x00\u07d4\x84\x94\x9d\xbaU\x9ac\xbf\xc8E\xde\xd0n\x9f-\x9b\u007f\x11\xef$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x9a\xb8\a\x90\xb2\x8f\xf1\xff\u05ba9N\xfctc\x10\\6\xf7\x89\x01\xe0+\xe4\xael\x84\x00\x00\u07d4\x84\x9b\x11oYc\x01\xc5\u063bb\xe0\xe9z\x82H\x12n9\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x84\xa7L\xee\xcf\xf6\\\xb9;/\x94\x9dw>\xf1\xad\u007f\xb4\xa2E\x89\x05\n\x9bDF\x85\xc7\x00\x00\u07d4\x84\xaa\xc7\xfa\x19\u007f\xf8\\0\xe0;zS\x82\xb9W\xf4\x1f:\xfb\x89\b\x8b#\xac\xff\u0650\x00\x00\u07d4\x84\xaf\x1b\x15sB\xd5Ch&\r\x17\x87b0\xa54\xb5K\x0e\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x84\xb0\xeek\xb87\u04e4\xc4\xc5\x01\x1c:\"\x8c\x0e\u06b4cJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb4\xb7Nf#\xba\x9d\x15\x83\xe0\u03feId?\x168AI\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb6\xb6\xad\xbe/[>-h,f\xaf\x1b\u0110S@\xc3\xed\x89!\x92\xf8\xd2\"\x15\x00\x80\x00\xe0\x94\x84\xb9\x1e.)\x02\xd0^+Y\x1bA\b;\u05fe\xb2\xd5,t\x8a\x02\x15\xe5\x12\x8bE\x04d\x80\x00\u07d4\x84\xbc\xbf\"\xc0\x96\a\xac\x844\x1d.\xdb\xc0;\xfb\x179\xd7D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x84\xbf\xce\xf0I\x1a\n\xe0iK7\u03ac\x02E\x84\xf2\xaa\x04g\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x84\xcb}\xa0P-\xf4\\\xf5a\x81{\xbd#b\xf4Q\xbe\x02\u0689Hz\x9a0E9D\x00\x00\u07d4\x84\xccxx\xda`_\xdb\x01\x9f\xab\x9bL\xcf\xc1Wp\x9c\u0765\x89Hy\x85\x13\xaf\x04\xc9\x00\x00\u07d4\x84\xdb\x14Y\xbb\x00\x81.\xa6~\xcb=\xc1\x89\xb7!\x87\xd9\xc5\x01\x89\b\x11\xb8\xfb\u0685\xab\x80\x00\u07d4\x84\u9516\x80\xbe\xcehA\xb9\xa7\xe5%\r\b\xac\xd8}\x16\u0349\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84\xe9\u03c1f\xc3j\xbf\xa4\x90S\xb7\xa1\xad@6 &\x81\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\xec\x06\xf2G\x00\xfeBAL\xb9\x89|\x15L\x88\xde/a2\x89Hz\x9a0E9D\x00\x00\xe0\x94\x84\xf5\"\xf0R\x0e\xbaR\xdd\x18\xad!\xfaK\x82\x9f+\x89\u02d7\x8a\x01\fQ\x06\xd5\x13O\x13\x00\x00\u07d4\x85\v\x9d\xb1\x8f\xf8K\xf0\xc7\xdaI\xea7\x81\xd9 \x90\xad~d\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x85\x10\xee\x93O\f\xbc\x90\x0e\x10\a\xeb8\xa2\x1e*Q\x01\xb8\xb2\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4\x85\x16\xfc\xafw\u0213\x97\x0f\xcd\x1a\x95\x8b\xa9\xa0\x0eI\x04@\x19\x89\n\xa3\xeb\x16\x91\xbc\xe5\x80\x00\u07d4\x85\x1a\xa9\x1c\x82\xf4/\xad]\xd8\xe8\xbb^\xa6\x9c\x8f:Yw\u0449\b\x0eV\x1f%xy\x80\x00\u07d4\x85\x1c\rb\xbeF5\xd4w~\x805\xe3~K\xa8Q|a2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x85\x1d\u00ca\xdbE\x93r\x9av\xf3:\x86\x16\u06b6\xf5\xf5\x9aw\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x852I\b\x97\xbb\xb4\u038b\u007fk\x83~L\xba\x84\x8f\xbe\x99v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x85>j\xba\xf4Di\xc7/\x15\x1dN\"8\x19\xac\xedN7(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85F\x91\xceqO2\\\xedU\xceY(\u039b\xa1/\xac\u0478\x89\xedp\xb5\xe9\xc3\xf2\xf0\x00\x00\u07d4\x85L\fF\x9c$k\x83\xb5\u0473\xec\xa4C\xb3\x9a\xf5\xee\x12\x8a\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x85]\x9a\xef,9\xc6#\r\t\u025e\xf6II\x89\xab\u61c5\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x85c\u0113a\xb6%\xe7hw\x1c\x96\x15\x1d\xbf\xbd\x1c\x90iv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85fa\t\x01\xaa\xce8\xb82D\xf3\xa9\xc810jg\xb9\u0709\xb0\x82\x13\xbc\xf8\xff\xe0\x00\x00\xe0\x94\x85j\xa2<\x82\xd7![\xec\x8dW\xf6\n\xd7^\xf1O\xa3_D\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x85nZ\xb3\xf6L\x9a\xb5k\x00\x93\x93\xb0\x16d\xfc\x03$\x05\x0e\x89a\t=|,m8\x00\x00\u07d4\x85n\xb2\x04$\x1a\x87\x83\x0f\xb2)\x03\x13C\xdc0\x85OX\x1a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x85s,\x06\\\xbdd\x11\x99A\xae\xd40\xacYg\vlQ\u0109'\xa5sb\xab\n\x0e\x80\x00\xe0\x94\x85x\xe1\x02\x12\xca\x14\xff\a2\xa8$\x1e7F}\xb8V2\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x85y\xda\xdf\x1a9Z4q\xe2\vov=\x9a\x0f\xf1\x9a?o\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x85\u007f\x10\v\x1aY0\"^\xfc~\x90 \u05c3'\xb4\x1c\x02\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x85\x94mV\xa4\xd3q\xa93hS\x96\x90\xb6\x0e\xc8%\x10tT\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94\x85\x99\xcb\u0566\xa9\xdc\u0539f\xbe8}iw]\xa5\xe3C'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86$_Yf\x91\t>\xce?=<\xa2&>\xac\xe8\x19A\u0649\n1\x06+\xee\xedp\x00\x00\u07d4\x86%i!\x1e\x8cc'\xb5A^:g\xe5s\x8b\x15\xba\xafn\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x86)}s\x0f\xe0\xf7\xa9\xee$\xe0\x8f\xb1\b{1\xad\xb3\x06\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86D\xcc(\x1b\xe32\xcc\xce\xd3m\xa4\x83\xfb*\aF\u067a.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86I\x9a\x12(\xff-~\xe3\au\x93dPo\x8e\x8c\x83\a\xa5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x86K\xecPi\xf8U\xa4\xfdX\x92\xa6\xc4I\x1d\xb0|\x88\xff|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86W\n\xb2Y\u0271\xc3,\x97) /w\xf5\x90\xc0}\xd6\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86c\xa2A\xa0\xa8\x9ep\xe1\x82\xc8E\xe2\x10\\\x8a\xd7&K\u03ca\x03#\xb1=\x83\x98\xf3#\x80\x00\u07d4\x86g\xfa\x11U\xfe\xd72\u03f8\u0725\xa0\xd7e\xce\r\a\x05\xed\x89\x04n\xc9e\u00d3\xb1\x00\x00\u07d4\x86h\xaf\x86\x8a\x1e\x98\x88_\x93\u007f&\x15\xde\xd6u\x18\x04\xeb-\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x86t\nFd\x8e\x84Z]\x96F\x1b\x18\t\x1f\xf5{\xe8\xa1o\x8a\x14\xc0\x974\x85\xbf9@\x00\x00\xe0\x94\x86~\xbaVt\x8aY\x045\r,\xa2\xa5\u039c\xa0\vg\n\x9b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x86\x80dt\xc3X\x04}\x94\x06\xe6\xa0\u007f@\x94[\xc82\x8eg\x8a\x01u.\xb0\xf7\x01=\x10\x00\x00\u07d4\x86\x88=T\xcd9\x15\xe5I\tU0\xf9\xab\x18\x05\xe8\xc5C-\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\x8c#\xbe\x874f\xd4\xc7L\"\n\x19\xb2E\xd1x~\x80\u007f\x89J\x13\xbb\xbd\x92\u020e\x80\x00\xe0\x94\x86\x92O\xb2\x11\xaa\xd2<\xf5\xce`\x0e\n\xae\x80c\x96D@\x87\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\x93\u9e3e\x94B^\xefyi\xbci\xf9\xd4/|\xadg\x1e\x8967\tlK\xcci\x00\x00\xe0\x94\x86\x9f\x1a\xa3\x0eDU\xbe\xb1\x82 \x91\xde\\\xad\xecy\xa8\xf9F\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x86\xa1\xea\xde\xeb0F\x13E\xd9\xefk\xd0R\x16\xfa$|\r\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xa5\xf8%\x9e\u0570\x9e\x18\x8c\xe3F\xee\x92\xd3J\xa5\u0753\xfa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xb7\xbdV<\uad86\xf9bD\xf9\xdd\xc0*\u05f0\xb1K\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\u008bVx\xaf7\xd7'\xec\x05\xe4Dw\x90\xf1_q\xf2\xea\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xc4\xce\x06\u066c\x18[\xb1H\xd9o{z\xbes\xf4A\x00m\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\xc8\xd0\u0642\xb59\xf4\x8f\x980\xf9\x89\x1f\x9d`z\x94&Y\x8a\x02\xce\xd3wa\x82O\xb0\x00\x00\u07d4\x86\xc94\xe3\x8eS\xbe;3\xf2t\xd0S\x9c\xfc\xa1Y\xa4\xd0\u04494\x95tD\xb8@\xe8\x00\x00\xe0\x94\x86\xca\x01E\x95~k\r\xfe6\x87_\xbez\r\xecU\xe1z(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\u02af\xac\xf3*\xa01|\x03*\xc3k\xab\xed\x97G\x91\xdc\x03\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x86\u0377\xe5\x1a\xc4Gr\xbe6\x90\xf6\x1d\x0eYvn\x8b\xfc\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\xdfs\xbd7\u007f,\t\xdec\xc4]g\xf2\x83\xea\xef\xa0\xf4\xab\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86\xe3\xfe\x86\xe9=\xa4\x86\xb1Bf\xea\xdf\x05l\xbf\xa4\xd9\x14C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xe8g\x0e'Y\x8e\xa0\x9c8\x99\xabw\x11\u04f9\xfe\x90\x1c\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xefd&!\x19I\xcc7\xf4\xc7^xP6\x9d\f\xf5\xf4y\x8a\x02\xd6_2\xea\x04Z\xf6\x00\x00\u07d4\x86\xf0]\x19\x06>\x93i\xc6\x00N\xb3\xf1#\x94:|\xffN\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x86\xf2>\x9c\n\xaf\u01cb\x9c@M\xcd`3\x9a\x92[\xff\xa2f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86\xf4\xf4\n\u0644\xfb\xb8\t3\xaebn\x0eB\xf93?\xddA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x86\xf9\\[\x11\xa2\x93\x94\x0e5\xc0\xb8\x98\u0637_\b\xaa\xb0m\x8a\x06D\xe3\xe8u\xfc\xcft\x00\x00\u07d4\x86\xff\xf2 \xe5\x93\x05\xc0\x9fH8`\xd6\xf9N\x96\xfb\xe3/W\x89\x02S[j\xb4\xc0B\x00\x00\u07d4\x87\a\x96\xab\xc0\u06c4\xaf\x82\xdaR\xa0\xedhsM\xe7\xe66\xf5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x87\x0f\x15\xe5\u07cb\x0e\xab\xd0%iSz\x8e\xf9;Vx\\B\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x87\x181`\xd1r\xd2\xe0\x84\xd3'\xb8k\xcb|\x1d\x8eg\x84\xef\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94\x87\x1b\x8a\x8bQ\u07a1\x98\x9aY!\xf1>\xc1\xa9U\xa5\x15\xadG\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x87%\xe8\xc7S\xb3\xac\xbf\u0725_I\x13\\3\x91\x99\x10`)\n\xa7\xf6\u0338\xf8Zx\u06c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x87Pa\xee\x12\xe8 \x04\x1a\x01\x94,\xb0\xe6[\xb4'\xb0\x00`\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x87XJ?a;\xd4\xfa\xc7L\x1ex\v\x86\xd6\xca\xeb\x89\f\xb2\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x87d\xd0'\"\x00\t\x96\xec\xd4u\xb43)\x8e\x9fT\v\x05\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x87l?!\x8bGv\xdf<\xa9\xdb\xfb'\r\xe1R\xd9N\xd2R\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x87u\xa6\x10\xc5\x02\xb9\xf1\xe6\xadL\xda\u06cc\xe2\x9b\xffu\xf6\xe4\x89 \x86\xac5\x10R`\x00\x00\u07d4\x87vN6w\xee\xf6\x04\xcb\u015a\xed$\xab\xdcVk\t\xfc%\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\x87\x87\xd1&w\xa5\xec)\x1eW\xe3\x1f\xfb\xfa\xd1\x05\xc32K\x87\x8a\x02\xa2N\xb52\b\xf3\x12\x80\x00\u07d4\x87\x94\xbfG\xd5E@\xec\xe5\xc7\"7\xa1\xff\xb5\x11\u0777Gb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x87\xa5>\xa3\x9fY\xa3[\xad\xa85%!dU\x94\xa1\xa7\x14\u02c9g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x87\xa7\xc5\b\xefqX-\u0665Cr\xf8\x9c\xb0\x1f%/\xb1\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x87\xaf%\xd3\xf6\xf8\xee\xa1S\x13\xd5\xfeEW\xe8\x10\xc5$\xc0\x83\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x87\xb1\x0f\x9c(\x00\x98\x17\x9a+v\xe9\u0390\xbea\xfc\x84M\r\x89Hz\x9a0E9D\x00\x00\u07d4\x87\xbf|\xd5\u0629)\xe1\u01c5\xf9\xe5D\x91\x06\xac#$c\u0249\x047\xb1\x1f\xccEd\x00\x00\u07d4\x87\u0118\x17\t4\xb8#=\x1a\xd1\xe7i1}\\G_/@\x897\b\xba\xed=h\x90\x00\x00\u07d4\x87\xcf6\xad\x03\xc9\xea\xe9\x05:\xbbRB\u0791\x17\xbb\x0f*\v\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x87\u05ec\x06S\xcc\xc6z\xa9\xc3F\x9e\xefCR\x19?}\xbb\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\x87\xe3\x06+#!\xe9\u07f0\x87\\\u311c\x9b.5\"\xd5\n\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x87\xe6\x03N\xcf#\xf8\xb5c\x9d_\x0e\xa7\n\"S\x8a\x92\x04#\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\x87\xefm\x8bj|\xbf\x9b\\\x8c\x97\xf6~\xe2\xad\u00a7;?w\x89\n\xdd\x1b\xd2<\x00L\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x88F\x92\x8dh2\x89\xa2\xd1\x1d\xf8\xdbz\x94t\x98\x8e\xf0\x13H\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x88I\x80\xebEe\xc1\x04\x83\x17\xa8\xf4\u007f\u06f4a\x96[\u4049\xd8\xd6\x11\x9a\x81F\x05\x00\x00\xe0\x94\x88Jz9\u0411n\x05\xf1\xc2B\xdfU`\u007f7\u07cc_\u068a\x04\xf4\x84<\x15|\x8c\xa0\x00\x00\u07d4\x88T\x93\xbd\xa3j\x042\x97eF\xc1\xdd\xceq\xc3\xf4W\x00!\x89\v\xbfQ\r\xdf\xcb&\x00\x00\xe0\x94\x88`\x9e\nF[n\x99\xfc\xe9\a\x16mW\xe9\xda\b\x14\xf5\u020a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88m\n\x9e\x17\xc9\xc0\x95\xaf.\xa25\x8b\x89\xecpR\x12\ue509\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x88y~Xg^\xd5\xccL\x19\x98\a\x83\xdb\xd0\xc9V\bQS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88|\xacA\xcdpo3E\xf2\xd3J\xc3N\x01u*nY\t\x89 F\\\ue7617\x00\x00\u07d4\x88\x88\x8aW\xbd\x96\x87\xcb\xf9P\xae\xea\u03d7@\xdc\xc4\xd1\xefY\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u0794\x88\x89D\x83\x16\xcc\xf1N\xd8m\xf8\xe2\xf4x\xdcc\xc43\x83@\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x88\x8c\x16\x14I3\x19|\xac&PM\xd7n\x06\xfdf\x00\u01c9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x88\x8e\x94\x91p\x83\xd1R +S\x1699\x86\x9d'\x11u\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\x90\x87\xf6o\xf2\x84\xf8\xb5\xef\xbd)I;pg3\xab\x14G\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\x88\x95\xebrb&\xed\xc3\xf7\x8c\u01a5\x15\a{2\x96\xfd\xb9^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x88\x97Z_\x1e\xf2R\x8c0\v\x83\xc0\xc6\a\xb8\xe8}\u0593\x15\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x88\x9d\xa4\x0f\xb1\xb6\x0f\x9e\xa9\xbdzE>XL\xf7\xb1\xb4\xd9\xf7\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x88\x9d\xa6b\xebJ\n*\x06\x9d+\xc2K\x05\xb4\xee.\x92\xc4\x1b\x89Z,\x8cTV\xc9\xf2\x80\x00\u07d4\x88\xa1\"\xa28,R91\xfbQ\xa0\u032d;\xeb[rY\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xa2\x15D0\xc0\xe4\x11G\xd3\xc1\xfe\u3cf0\x06\xf8Q\xed\xbd\x8965f3\xeb\xd8\xea\x00\x00\u07d4\x88\xb2\x17\u0337\x86\xa2T\xcfM\xc5\u007f]\x9a\xc3\xc4U\xa3\x04\x83\x892$\xf4'#\xd4T\x00\x00\xe0\x94\x88\xbcC\x01.\xdb\x0e\xa9\xf0b\xacCxC%\n9\xb7\x8f\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88\xc2Qj|\xdb\t\xa6'mr\x97\xd3\x0fZM\xb1\xe8K\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\xc3ad\rki7;\b\x1c\xe0\xc43\xbdY\x02\x87\xd5\xec\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x88\xd5A\xc8@\xceC\xce\xfb\xafm\x19\xafk\x98Y\xb5s\xc1E\x89\t79SM(h\x00\x00\u07d4\x88\xde\x13\xb0\x991\x87|\x91\rY1e\xc3d\u0221d\x1b\u04c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x88\xde\u017d?N\xba-\x18\xb8\xaa\xce\xfa{r\x15H\xc3\x19\xba\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\x88\xe6\xf9\xb2G\xf9\x88\xf6\xc0\xfc\x14\xc5o\x1d\xe5>\u019dC\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x88\xee\u007f\x0e\xfc\x8fw\x8ckh~\xc3+\xe9\xe7\xd6\xf0 \xb6t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xf1\x04_\x19\xf2\xd3\x19\x18\x16\xb1\xdf\x18\xbbn\x145\xad\x1b8\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x89\x00\x9e\a\xe3\xfahc\xa7x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89Wr~r\xcfb\x90 \xf4\xe0^\xdfy\x9a\xa7E\x80b\u0409wC\"\x17\xe6\x83`\x00\x00\u07d4\x89]iN\x88\v\x13\xcc\u0404\x8a\x86\xc5\xceA\x1f\x88Gk\xbf\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x89^\xc5TVD\u0dc30\xff\xfa\xb8\xdd\xea\xc9\xe83\x15l\x89 \x86\xac5\x10R`\x00\x00\u07d4\x89`\tRj,{\f\t\xa6\xf6:\x80\xbd\U0009d707\u079c\x89\xbb\xb8k\x82#\xed\xeb\x00\x00\u07d4\x89g\u05f9\xbd\xb7\xb4\xae\xd2.e\xa1]\xc8\x03\xcbz!?\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x89n3\\\xa4z\xf5yb\xfa\x0fM\xbf>E\xe6\x88\u02e5\x84\x89J/\xc0\xab`R\x12\x00\x00\u07d4\x89s\xae\xfd^\xfa\xee\x96\t]\x9e(\x8fj\x04l\x977KC\x89\a\xa4\u0120\xf32\x14\x00\x00\u07d4\x89\x8cr\xddseX\xef\x9eK\xe9\xfd\xc3O\xefT\xd7\xfc~\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\x9b<$\x9f\fK\x81\xdfu\xd2\x12\x00M=m\x95/\xd2#\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x89\xab\x13\xee&mw\x9c5\xe8\xbb\x04\u034a\x90\xcc!\x03\xa9[\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x89\xc43\xd6\x01\xfa\xd7\x14\xdaci0\x8f\xd2l\x1d\u0254+\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89\xd7[\x8e\b1\xe4o\x80\xbc\x17A\x88\x18N\x00o\xde\x0e\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\u3d5a\x15\x86G7\u0513\xc1\xd2<\xc5=\xbf\x8d\xcb\x13b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x89\xfc\x8eM8k\r\v\xb4\xa7\a\xed\xf3\xbdV\r\xf1\xad\x8fN\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x89\xfe\xe3\r\x17(\xd9l\xec\xc1\u06b3\xda.w\x1a\xfb\u03eaA\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8a\x1c\u016c\x11\x1cI\xbf\xcf\xd8H\xf3}\xd7h\xaae\u0208\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x8a \xe5\xb5\xce\xe7\xcd\x1fU\x15\xba\xce;\xf4\xf7\u007f\xfd\xe5\xcc\a\x89\x04V9\x18$O@\x00\x00\xe0\x94\x8a!}\xb3\x8b\xc3_!_\xd9)\x06\xbeBCo\xe7\xe6\xed\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x8a$:\n\x9f\xeaI\xb89TwE\xff-\x11\xaf?K\x05\"\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x8a$}\x18e\x10\x80\x9fq\xcf\xfcEYG\x1c9\x10\x85\x81!\x89a\t=|,m8\x00\x00\u07d4\x8a4p(-^**\xef\u05e7P\x94\xc8\"\xc4\xf5\xae\uf289\r(\xbc`dx\xa5\x80\x00\u07d4\x8a6\x86\x9a\xd4x\x99|\xbfm\x89$\xd2\n<\x80\x18\xe9\x85[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8aC\x14\xfba\u0353\x8f\xc3>\x15\xe8\x16\xb1\x13\U000ac267\xfb\x89\x17vNz\xede\x10\x00\x00\u07d4\x8aOJ\u007fR\xa3U\xba\x10_\xca r\xd3\x06_\xc8\xf7\x94K\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8aX1(,\xe1Jezs\r\xc1\x88&\xf7\xf9\xb9\x9d\xb9h\x89\uaf8a[A\xc16\x00\x00\u07d4\x8a_\xb7W\x93\xd0C\xf1\xbc\xd48\x85\xe07\xbd0\xa5(\xc9'\x89\x13Snm.\x9a\xc2\x00\x00\u07d4\x8af\xab\xbc-0\xce!\xa83\xb0\u06ceV\x1dQ\x05\xe0\xa7,\x89%\xf1\xde\\v\xac\xdf\x00\x00\u07d4\x8atl]g\x06G\x11\xbf\xcah[\x95\xa4\xfe)\x1a'\x02\x8e\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8ax\n\xb8z\x91E\xfe\x10\xed`\xfaGjt\n\xf4\u02b1\u0489\x12\x1b.^ddx\x00\x00\u07d4\x8az\x06\xbe\x19\x9a:X\x01\x9d\x84j\xc9\xcb\xd4\xd9]\xd7W\u0789\xa2\xa4#\x94BV\xf4\x00\x00\u07d4\x8a\x81\x01\x14\xb2\x02]\xb9\xfb\xb5\x00\x99\xa6\xe0\u02de.\xfak\u0709g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8a\x86\xe4\xa5\x1c\x01;\x1f\xb4\xc7k\xcf0f|x\xd5.\xed\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\x9e\u029cZ\xba\x8e\x13\x9f\x80\x03\xed\xf1\x16:\xfbp\xaa:\xa9\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\x8a\xb89\xae\xaf*\xd3|\xb7\x8b\xac\xbb\xb63\xbc\xc5\xc0\x99\xdcF\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\u021b\u06780\x1ek\x06w\xfa%\xfc\xf0\xf5\x8f\f\u01f6\x11\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x8a\xdcS\xef\x8c\x18\xed0Qx]\x88\xe9\x96\xf3\xe4\xb2\x0e\xcdQ\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\u07d4\x8a\xe6\xf8\vp\xe1\xf2<\x91\xfb\u0569f\xb0\xe4\x99\xd9]\xf82\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x8a\xe9\uf30a\x8a\u07e6\xaby\x8a\xb2\xcd\xc4\x05\b*\x1b\xbbp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\xf6&\xa5\xf3'\xd7Pe\x89\xee\xb7\x01\x0f\xf9\xc9D` \u0489K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\x8b\x01\xda4\xd4p\xc1\xd1\x15\xac\xf4\xd8\x11\xe1\x01\xdb\x1e\x14\xec\xc7\xd3\"\xc7+\x8c\x04s\x89\x18\xb2j1>\x8a\xe9\x00\x00\xe0\x94\x8bH\xe1\x9d9\xdd5\xb6nn\x1b\xb6\xb9\xc6W\xcb,\xf5\x9d\x04\x8a\x03\xc7U\xac\x9c\x02J\x01\x80\x00\xe0\x94\x8bP^(q\xf7\u07b7\xa68\x95 \x8e\x82'\u072a\x1b\xff\x05\x8a\f\xf6\x8e\xfc0\x8dy\xbc\x00\x00\u07d4\x8bW\xb2\xbc\x83\u030dM\xe31 N\x89?/;\x1d\xb1\a\x9a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8b\\\x91K\x12\x8b\xf1i\\\b\x89#\xfaF~y\x11\xf3Q\xfa\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\x8b_)\xcc/\xaa&,\xde\xf3\x0e\xf5T\xf5\x0e\xb4\x88\x14n\xac\x8a\x01;hp\\\x97 \x81\x00\x00\u07d4\x8bpV\xf6\xab\xf3\xb1\x18\xd0&\xe9D\xd5\xc0sC<\xa4Q\u05c965\xc6 G9\u0640\x00\u07d4\x8bqE\"\xfa(9b\x04p\xed\xcf\fD\x01\xb7\x13f=\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8bt\xa7\xcb\x1b\xb8\u014f\xce&tf\xa3\x03X\xad\xafR\u007fa\x8a\x02\xe2WxN%\xb4P\x00\x00\u07d4\x8b~\x9fo\x05\xf7\xe3dv\xa1n>q\x00\xc9\x03\x1c\xf4\x04\xaf\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8b\x81\x15ni\x869\x94<\x01\xa7Rr\xad=5\x85\x1a\xb2\x82\x89\x12\xb3\x16_e\xd3\xe5\x00\x00\u07d4\x8b\x95w\x92\x00S\xb1\xa0\x01\x890M\x88\x80\x10\xd9\xef,\xb4\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8b\x98A\x86.w\xfb\xbe\x91\x94p\x93U\x83\xa9<\xf0'\xe4P\x89llS4B\u007f\x1f\x00\x00\u07d4\x8b\x99}\xbc\a\x8a\xd0)a5]\xa0\xa1Y\xf2\x92~\xd4=d\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8b\x9f\xda}\x98\x1f\xe9\xd6B\x87\xf8\\\x94\xd8?\x90t\x84\x9f\u030a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x8b\xb0!/2\x95\xe0)\u02b1\xd9a\xb0A3\xa1\x80\x9e{\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8b\xbe\xac\xfc)\xcf\xe94\x02\xdb\xd6j\x1a\xcbvv\x85c7\xb9;\xf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8b\xf3s\xd0v\x81L\xbcW\xe1\xc6\xd1j\x82\u017e\x13\xc7=7\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8c\x10#\xfd\xe1WM\xb8\xbbT\xf1s\x96p\x15|\xa4}\xa6R\x8a\x01y\u03da\u00e1\xb1w\x00\x00\u07d4\x8c\x1f\xbe_\n\xea5\x9cZ\xa1\xfa\b\u0209T\x12\u028e\x05\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\"B`U\xb7o\x11\xf0\xa2\xde\x1a\u007f\x81\x9aa\x96\x85\xfe`\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4\x8c+}\x8b`\x8d(\xb7\u007f\\\xaa\x9c\xd6E$*\x82>L\u0649b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x8c/\xbe\ue3ac\xc5\xc5\xd7|\x16\xab\xd4b\ue701E\xf3K\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8c:\x9e\xe7\x1fr\x9f#l\xba8g\xb4\u05dd\x8c\xee\xe2]\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8cP\xaa*\x92\x12\xbc\xdeVA\x8a\xe2a\xf0\xb3^z\x9d\xbb\x82\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8cT\xc7\xf8\xb9\x89nu\xd7\xd5\xf5\xc7`%\x86\x99\x95qB\xad\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8c]\x16\xede\xe3\xed~\x8b\x96\u0297+\xc8as\xe3P\v\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8cj\xa8\x82\xee2,\xa8HW\x8c\x06\xcb\x0f\xa9\x11\xd3`\x83\x05\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\x8cj\xe7\xa0Z\x1d\xe5u\x82\xae'h Bv\xc0\xffG\xed\x03\x8a,\v\xb3\xdd0\xc4\xe2\x00\x00\x00\u07d4\x8co\x9fN[z\xe2v\xbfXI{\u05ff*}%$_d\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4\x8cu\x95n\x8f\xedP\xf5\xa7\xdd|\xfd'\xda \x0fgF\xae\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c|\xb4\xe4\x8b%\x03\x1a\xa1\xc4\xf9)%\xd61\xa8\xc3\xed\xc7a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\u007f\xa5\xca\xe8/\xed\xb6\x9a\xb1\x89\xd3\xff'\xae \x92\x93\xfb\x93\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\xe0\x94\x8c\x81A\x0e\xa85L\xc5\xc6\\A\xbe\x8b\xd5\xdes<\v\x11\x1d\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x8c\x83\xd4$\xa3\xcf$\xd5\x1f\x01\x92=\xd5J\x18\u05b6\xfe\xde{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8c\x90\n\x826\xb0\x8c+e@]9\xd7_ \x06*ua\xfd\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\x8c\x93\xc3\xc6\u06dd7q}\xe1e\u00e1\xb4\xfeQ\x95,\b\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8c\x99\x95\x91\xfdr\xefq\x11\xef\xcaz\x9e\x97\xa25k;\x00\n\x89\xddd\xe2\xaa\ngP\x00\x00\u07d4\x8c\xa6\x98\x97F\xb0n2\xe2Hta\xb1\u0399j':\xcf\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8c\xb3\xaa?\xcd!(T\xd7W\x8f\xcc0\xfd\xed\xe6t*1*\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x8c\xc0\xd7\xc0\x16\xfaz\xa9P\x11J\xa1\xdb\tH\x82\xed\xa2t\xea\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x8c\xc6R\xdd\x13\xe7\xfe\x14\u06bb\xb3m]2\r\xb9\xff\xee\x8aT\x89a\t=|,m8\x00\x00\u07d4\x8c\u02bf%\a\u007f:\xa4\x15E4MS\xbe\x1b+\x9c3\x90\x00\x89[\xe8f\xc5b\xc5D\x00\x00\u07d4\x8c\xcf:\xa2\x1a\xb7BWj\xd8\xc4\"\xf7\x1b\xb1\x88Y\x1d\ua28965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\xd0\xcd\"\xe6 \xed\xa7\x9c\x04a\xe8\x96\xc9\xd1b)\x12K_z\xfb\xec\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x8c\xe2/\x9f\xa3rD\x9aB\x06\x10\xb4z\xe0\xc8\xd5eH\x122\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x8c\u451d\x8a\x16T-B<\x17\x98Ng9\xfar\u03b1w\x8a\x05K@Y&\xf4\xa6=\x80\x00\u07d4\x8c\xe5\xe3\xb5\xf5\x91\xd5\uc8ca\xbf\"\x8f.<5\x13K\xda\xc0\x89}\xc3[\x84\x89|8\x00\x00\xe0\x94\x8c\xee8\xd6YW\x88\xa5n?\xb9F4\xb3\xff\xe1\xfb\xdb&\u058a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8c\xee\xa1^\xec;\xda\xd8\x02?\x98\xec\xf2[+\x8f\xef'\xdb)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8c\xf3To\xd1\u0363=X\x84_\xc8\xfc\xfe\u02bc\xa7\xc5d*\x89\x1f\x1e9\x93,\xb3'\x80\x00\u07d4\x8c\xf6\xda\x02\x04\xdb\u0106\vF\xad\x97?\xc1\x11\x00\x8d\x9e\fF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x8c\xfe\xde\xf1\x98\xdb\n\x91C\xf0\x91)\xb3\xfdd\u073b\x9bIV\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x04\xa5\xeb\xfb]\xb4\t\xdb\x06\x17\xc9\xfaV1\xc1\x92\x86\x1fJ\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x8d\x06\xe4d$\\\xadaI9\xe0\xaf\bE\xe6\xd70\xe2\x03t\x89\n\u070a(\xf3\xd8}\x80\x00\u07d4\x8d\a\xd4-\x83\x1c-|\x83\x8a\xa1\x87+:\xd5\xd2w\x17h#\x89\x12\xee\x1f\x9d\xdb\xeeh\x00\x00\u07d4\x8d\v\x9e\xa5?\xd2cA^\xac\x119\x1f|\xe9\x12V\xb9\xfb\x06`\xf6\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8dy\\_JV\x89\xadb\u0696\x16q\xf0(\x06R\x86\xd5T\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x8d\u007f>a)\x9c-\xb9\xb9\xc0H|\xf6'Q\x9e\xd0\n\x91#\x89^t\xa8P^\x80\xa0\x00\x00\xe0\x94\x8d\x89\x17\v\x92\xb2\xbe,\b\xd5|H\xa7\xb1\x90\xa2\xf1Fr\x0f\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x8d\x93\xda\u01c5\xf8\x8f\x1a\x84\xbf\x92}Se+E\xa1T\xcc\u0749\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x8d\x99R\u043bN\xbf\xa0\xef\xd0\x1a:\xa9\xe8\xe8\u007f\x05%t.\x89\xbb\x91%T\"c\x90\x00\x00\u07d4\x8d\x9a\fp\xd2& B\xdf\x10\x17\xd6\xc3\x03\x13 $w'\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x9e\xd7\xf4U0X\xc2ox6\xa3\x80-0d\xeb\x1b6=\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\x8d\xa1\x17\x8fU\xd9wr\xbb\x1d$\x11\x1a@JO\x87\x15\xb9]\x89/\x9a\xc3\xf6\xde\x00\x80\x80\x00\u07d4\x8d\xa1\xd3Y\xbal\xb4\xbc\xc5}zCw \xd5]\xb2\xf0\x1cr\x89\x04V9\x18$O@\x00\x00\u07d4\x8d\xab\x94\x8a\xe8\x1d\xa3\x01\xd9r\xe3\xf6\x17\xa9\x12\xe5\xa7Sq.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8d\xad\xdfR\xef\xbdt\u0695\xb9i\xa5GoO\xbb\xb5c\xbf\u0489-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x8d\xb1\x85\xfe\x1bp\xa9Jj\b\x0e~#\xa8\xbe\xdcJ\xcb\xf3K\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x8d\xb5\x8e@n -\xf9\xbcpl\xb43\xe1\x94\xf4\x0f\x82\xb4\x0f\xaa\xdb\x1f\x8b\x85a\x16\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8d\xc1\xd5\x11\x1d\t\xaf%\xfd\xfc\xacE\\|\xec(>mgu\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\u0504\xff\x8a0sd\xebf\xc5%\xa5q\xaa\xc7\x01\xc5\xc3\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\u05a9\xba\xe5\u007fQ\x85I\xad\xa6wFo\ua2b0O\u0674\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde<\xb8\x11\x85h\xefE\x03\xfe\x99\x8c\xcd\xf56\xbf\x19\xa0\x98\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde`\xeb\b\xa0\x99\xd7\u06a3V\u06aa\xb2G\r{\x02Zk\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8d\xf39!Kj\u0472Fc\xceq`4t\x9dn\xf88\u064a\x02TO\xaaw\x80\x90\xe0\x00\x00\xe0\x94\x8d\xf5=\x96\x19\x14q\xe0Y\xdeQ\xc7\x18\xb9\x83\xe4\xa5\x1d*\xfd\x8a\x06\u01b95\xb8\xbb\xd4\x00\x00\x00\u07d4\x8d\xfb\xaf\xbc\x0e[\\\x86\xcd\x1a\u0597\xfe\xea\x04\xf41\x88\u0796\x89\x15%+\u007f_\xa0\xde\x00\x00\u07d4\x8e\a;\xad%\xe4\"\x18a_J\x0ek.\xa8\xf8\xde\"0\xc0\x89\x82=b\x9d\x02k\xfa\x00\x00\u07d4\x8e\x0f\xee8hZ\x94\xaa\xbc\xd7\u0385{k\x14\t\x82Ou\xb8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e#\xfa\xcd\x12\xc7e\xc3j\xb8\x1am\xd3M\x8a\xa9\xe6\x89\x18\xae\x89\t\x11\u418d\xba\x9b\x00\x00\xe0\x94\x8e/\x904\xc9%G\x19\u00ceP\u026ad0^\u0596\xdf\x1e\x8a\x01\x00N.E\xfb~\xe0\x00\x00\u07d4\x8e2@\xb0\x81\x0e\x1c\xf4\a\xa5\x00\x80G@\u03cdad2\xa4\x89\x02/fU\xef\v8\x80\x00\u07d4\x8eHj\x04B\xd1q\xc8`[\xe3H\xfe\xe5~\xb5\b^\xff\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8eaV3k\xe2\u037e2\x14\r\xf0\x8a+\xa5_\u0425\x84c\x89\x04\t\x9e\x1dcW\x18\x00\x00\u07d4\x8eg\b\x15\xfbg\xae\xae\xa5{\x86SN\xdc\x00\xcd\xf5d\xfe\u5272\xe4\xb3#\xd9\xc5\x10\x00\x00\u07d4\x8emt\x85\xcb\u942c\xc1\xad\x0e\xe9\xe8\xcc\xf3\x9c\f\x93D\x0e\x893\xc5I\x901r\f\x00\x00\xe0\x94\x8et\xe0\u0477~\xbc\x82:\xca\x03\xf1\x19\x85L\xb1 '\xf6\u05ca\x16\xb3R\xda^\x0e\xd3\x00\x00\x00\u07d4\x8ex\xf3QE}\x01oJ\xd2u^\xc7BN\\!\xbamQ\x89\a\xea(2uw\b\x00\x00\u07d4\x8ey6\u0552\x00\x8f\xdcz\xa0N\xde\xebuZ\xb5\x13\u06f8\x9d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\u007f\xd28H\xf4\xdb\a\x90j}\x10\xc0K!\x80;\xb0\x82'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8e\x92\xab\xa3\x8er\xa0\x98\x17\v\x92\x95\x92FSz.UV\xc0\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x8e\x98ve$\xb0\xcf'G\xc5\r\xd4;\x95gYM\x971\u0789lD\xb7\xc2a\x82(\x00\x00\u07d4\x8e\x9b5\xadJ\n\x86\xf7XDo\xff\xde4&\x9d\x94\f\xea\u0349\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8e\x9c\b\xf78f\x1f\x96v#n\xff\x82\xbaba\xdd?H\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\x9cB\x92f\xdf\x05~\xfax\xdd\x1d_w\xfc@t*\xd4f\x89\x10D.\u0475l|\x80\x00\u07d4\x8e\xa6V\xe7\x1e\xc6Q\xbf\xa1|ZWY\xd8`1\xcc5\x99w\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\xae)CU\x98\xba\x8f\x1c\x93B\x8c\xdb>+M1\a\x8e\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb1\xfb\xe4\xe5\xd3\x01\x9c\xd7\xd3\r\xae\x9c\r[Lv\xfbc1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb5\x17t\xaf k\x96k\x89\t\xc4Z\xa6r'H\x80,\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xb8\xc7\x19\x82\xa0\x0f\xb8Bu)2S\xf8\x04ED\xb6kI\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x8e\xcb\u03ec\xbf\xaf\xe9\xf0\f9\"\xa2N,\xf0\x02gV\xca \x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4\x8e\u03b2\xe1$Sl[_\xfcd\x0e\xd1O\xf1^\u0668\xcbq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\u042f\x11\xff(p\xda\x06\x81\x00J\xfe\x18\xb0\x13\xf7\xbd8\x82\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x8e\xd1Cp\x1f/r(\x0f\xd0J{Ad(\x19y\xea\x87\u0248\xc2I\xfd\xd3'x\x00\x00\u07d4\x8e\xd1R\x8bD~\xd4)y\x02\xf69\xc5\x14\u0414J\x88\xf8\u0209\n\xc6\xe7z\xb6c\xa8\x00\x00\u07d4\x8e\xd4(L\x0fGD\x9c\x15\xb8\u0673$]\u8fb6\u0380\xbf\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x8e\xde~=\xc5\aI\xc6\xc5\x0e.(\x16\x84x\xc3M\xb8\x19F\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x8e\xe5\x843}\xdb\xc8\x0f\x9e4\x98\xdfU\xf0\xa2\x1e\xac\xb5\u007f\xb1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\xeb\xec\x1ab\xc0\x8b\x05\xa7\xd1\u0551\x80\xaf\x9f\xf0\u044e?6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xf4\u0622\xc2o\xf7\x14\xb6u\x89\x19\x80\x1c\x83\xb6\xc7\xc0\x00\x00\u07d4\x8fM\x1dAi>F,\xf9\x82\xfd\x81\u042ap\x1d:St\u0249\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fM\x1e~Ea(J4\xfe\xf9g<\r4\xe1*\xf4\xaa\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8fO\xb1\xae\xa7\xcd\x0fW\x0e\xa5\xe6\x1b@\xa4\xf4Q\vbd\xe4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fV\x1bA\xb2\t\xf2H\u0229\x9f\x85\x87\x887bP`\x9c\xf3\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\x8fX\xd84\x8f\xc1\xdcN\r\xd84;eC\xc8W\x04^\xe9@\x8a\x02\xe3\x03\x8d\xf4s\x03(\x00\x00\u07d4\x8f`\x89_\xbe\xbb\xb5\x01\u007f\xcb\xff<\u0763\x97)+\xf2[\xa6\x89\x17D\x06\xff\x9fo\u0480\x00\u07d4\x8fd\xb9\xc1$m\x85x1d1\a\xd3U\xb5\xc7_\xef]O\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8ff\x0f\x8b.L|\u00b4\xac\x9cG\xed(P\x8d_\x8f\x86P\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8fi\xea\xfd\x023\xca\xdb@Y\xabw\x9cF\xed\xf2\xa0PnH\x89`\xf0f \xa8IE\x00\x00\xe0\x94\x8fq~\xc1U/LD\x00\x84\xfb\xa1\x15J\x81\xdc\x00>\xbd\xc0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x8f\x8a\xcb\x10v\a8\x84y\xf6K\xaa\xab\xea\x8f\xf0\a\xad\xa9}\x8a\x05\xc6\xf3\b\n\xd4#\xf4\x00\x00\u07d4\x8f\x8c\xd2n\x82\xe7\xc6\xde\xfd\x02\u07ed\a\x97\x90!\xcb\xf7\x15\f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x8f\x8f7\u042d\x8f3]*q\x01\xb4\x11V\xb6\x88\xa8\x1a\x9c\xbe\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\x8f\x92\x84O(*\x92\x99\x9e\u5d28\xd7s\xd0kiM\xbd\x9f\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8f\xact\x8fxJ\x0f\xedh\u06e43\x19\xb4*u\xb4d\x9cn\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x8f\u0665\xc3:}\x9e\xdc\xe0\x99{\xdfw\xab0d$\xa1\x1e\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xef\xfa\xdb8z\x15G\xfb(M\xa9\xb8\x14\u007f>|m\xc6\u0689-b{\xe4S\x05\b\x00\x00\u07d4\x8f\xf4`Ehw#\xdc3\xe4\u0419\xa0i\x04\xf1\ubd44\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xfa\x06!\"\xac0t\x18\x82\x1a\u06d3\x11\aZ7\x03\xbf\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8f\xfe2)\x97\xb8\xe4\x04B-\x19\xc5J\xad\xb1\x8f[\xc8\u9dc9\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x90\x01\x94\u0131\aC\x05\u045d\xe4\x05\xb0\xacx(\x0e\xca\xf9g\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90\x03\xd2p\x89\x1b\xa2\xdfd=\xa84\x15\x83\x195E\xe3\xe0\x00\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x90\x05z\xf9\xaaf0~\xc9\xf03\xb2\x97$\u04f2\xf4\x1e\xb6\xf9\x8a\x19\xd1\u05aa\xdb,R\xe8\x00\x00\u07d4\x90\x0f\v\x8e5\xb6h\xf8\x1e\xf2R\xb18U\xaaP\a\xd0\x12\xe7\x89\x17\n\x0fP@\xe5\x04\x00\x00\u07d4\x90\x18\xcc\x1fH\xd20\x8e%*\xb6\b\x9f\xb9\x9a|\x1dV\x94\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x90\x1d\x99\xb6\x99\xe5\u0191\x15\x19\xcb v\xb4\xc7c0\xc5M\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x90-t\xa1W\xf7\u04b9\xa37\x8b\x1fVp70\xe0:\x17\x19\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x904\x13\x87\x8a\xea;\xc1\bc\t\xa3\xfev\x8beU\x9e\x8c\xab\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x90If\xcc\"\x13\xb5\xb8\xcb[\xd6\b\x9e\xf9\xcd\xdb\xef~\xdf\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x90L\xaaB\x9ca\x9d\x94\x0f\x8egA\x82j\r\xb6\x92\xb1\x97(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90R\xf2\xe4\xa3\xe3\xc1-\xd1\xc7\x1b\xf7\x8aN\xc3\x04=\u020b~\x89\x0e~\xeb\xa3A\vt\x00\x00\u0794\x90U&V\x8a\xc1#\xaf\xc0\xe8J\xa7\x15\x12O\xeb\xe8=\xc8|\x88\xf8i\x93)g~\x00\x00\u07d4\x90\x92\x91\x87\a\xc6!\xfd\xbd\x1d\x90\xfb\x80\xebx\u007f\xd2osP\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4\x90\x9b^v:9\xdc\u01d5\"=s\xa1\u06f7\xd9L\xa7Z\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x90\xac\xce\xd7\xe4\x8c\b\u01b94dm\xfa\n\xdf)\u0714\aO\x89\x03\vK\x15{\xbdI\x00\x00\u07d4\x90\xb1\xf3p\xf9\xc1\xeb\v\xe0\xfb\x8e+\x8a\xd9jAcq\u074a\x890\xca\x02O\x98{\x90\x00\x00\u07d4\x90\xb6/\x13\x1a_)\xb4UqQ>\xe7\xa7J\x8f\v#\"\x02\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x90\xbdb\xa0P\x84Ra\xfaJ\x9f|\xf2A\xeac\v\x05\ufe09\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x90\xc4\x1e\xba\x00\x8e \xcb\xe9'\xf3F`?\u0206\x98\x12Yi\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x90\u0480\x9a\xe1\xd1\xff\xd8\xf6>\xda\x01\xdeI\xddU-\xf3\u047c\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x90\xdc\t\xf7\x17\xfc*[i\xfd`\xba\b\xeb\xf4\v\xf4\xe8$l\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x90\xe3\x00\xacqE\x1e@\x1f\x88\u007fnw(\x85\x16G\xa8\x0e\a\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x90\xe3Z\xab\xb2\xde\xef@\x8b\xb9\xb5\xac\xefqDW\xdf\xdebr\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\x90\xe7\a\x0fM\x03?\xe6\x91\f\x9e\xfeZ'\x8e\x1f\xc6#M\xef\x89\x05q8\b\x19\xb3\x04\x00\x00\u07d4\x90\xe9>M\xc1q!HyR36\x14\x00+\xe4#VI\x8e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x90\u9a68.\u06a8\x14\u0084\xd22\xb6\u9e90p\x1dIR\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x90\xf7t\xc9\x14}\u0790\x85=\xdcC\xf0\x8f\x16\xd4U\x17\x8b\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x90\xfcS{!\x06Xf\n\x83\xba\xa9\xacJ\x84\x02\xf6WF\xa8\x89e\xea=\xb7UF`\x00\x00\u07d4\x91\x05\n\\\xff\xad\xed\xb4\xbbn\xaa\xfb\xc9\xe5\x014(\xe9l\x80\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x91\x05\x17d\xafk\x80\x8eB\x12\xc7~0\xa5W.\xaa1pp\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x91\v}Wz~9\xaa#\xac\xf6*\xd7\xf1\xef4)4\xb9h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x91\x0e\x99eC4Lh\x15\xfb\x97\u0367\xafK\x86\x98vZ[\x89\x05\x9a\xf6\x98)\xcfd\x00\x00\u07d4\x91\x1f\xee\xa6\x1f\xe0\xedP\u0179\xe5\xa0\xd6`q9\x9d(\xbd\u0189\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x91\x1f\xf23\xe1\xa2\x11\xc0\x17,\x92\xb4l\xf9\x97\x03\x05\x82\xc8:\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x91 \xe7\x11s\xe1\xba\x19\xba\x8f\x9fO\xdb\u072a4\xe1\u05bbx\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91!\x17\x12q\x9f+\bM;8u\xa8Pi\xf4f61A\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91#\x04\x11\x8b\x80G=\x9e\x9f\xe3\xeeE\x8f\xbea\x0f\xfd\xa2\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x91Tky\xec\xf6\x9f\x93kZV\x15\b\xb0\xd7\xe5\f\u0159/\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x91V\u0440)5\x0eG\x04\b\xf1_\x1a\xa3\xbe\x9f\x04\ng\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x91b\x0f>\xb3\x04\xe8\x13\u048b\x02\x97Ume\xdcN]\u5a89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\x91k\xf7\xe3\xc5E\x92\x1d2\x06\xd9\x00\xc2O\x14\x12|\xbd^p\x8a\x03\xd0\u077c}\xf2\xbb\x10\x00\x00\u0794\x91l\xf1}qA(\x05\xf4\xaf\xc3DJ\v\x8d\xd1\xd93\x9d\x16\x88\xc6s\xce<@\x16\x00\x00\u07d4\x91{\x8f\x9f:\x8d\t\xe9 ,R\u009erA\x96\xb8\x97\xd3^\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x91\x89g\x91\x8c\u0617\xdd\x00\x05\xe3m\xc6\u0203\xefC\x8f\xc8\u01c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x91\x89\x8e\xab\x8c\x05\xc0\"(\x83\xcdM\xb2;w\x95\xe1\xa2J\u05c9lk\x93[\x8b\xbd@\x00\x00\u0794\x91\x91\xf9F\x98!\x05\x16\xcfc!\xa1B\a\x0e Yvt\xed\x88\xee\x9d[\xe6\xfc\x11\x00\x00\u07d4\x91\xa4\x14\x9a,{\x1b:g\xea(\xaf\xf3G%\u0fcdu$\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x91\xa7\x87\xbcQ\x96\xf3HW\xfe\f7/M\xf3v\xaa\xa7f\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xa8\xba\xae\xd0\x12\xea.c\x80;Y=\r\f*\xabL[\n\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x91\xac\\\xfeg\xc5J\xa7\xeb\xfb\xa4HflF\x1a;\x1f\xe2\xe1\x89\x15\xc94\x92\xbf\x9d\xfc\x00\x00\u07d4\x91\xbb?y\x02+\xf3\xc4S\xf4\xff%n&\x9b\x15\xcf,\x9c\xbd\x89RX\\\x13\xfe:\\\x00\x00\u07d4\x91\xc7^<\xb4\xaa\x89\xf3F\x19\xa1d\xe2\xa4x\x98\xf5gM\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xc8\f\xaa\b\x1b85\x1d*\x0e\x0e\x00\xf8\n4\xe5dt\xc1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91\xccF\xaa7\x9f\x85jf@\xdc\xcdZd\x8ay\x02\xf8I\u0649\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x91\u04a9\xee\x1am\xb2\x0fS\x17\u0327\xfb\xe218\x95\u06ce\xf8\x8a\x01\xcc\u00e5/0n(\x00\x00\u07d4\x91\xd6n\xa6(\x8f\xaaK=`l*\xa4\\{k\x8a%'9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\u06f6\xaa\xad\x14\x95\x85\xbeG7\\]m\xe5\xff\t\x19\x15\x18\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x91\xe8\x81\x06R\xe8\xe6\x16\x15%\xd6;\xb7u\x1d\xc2\x0fg`v\x89'Mej\xc9\x0e4\x00\x00\u07d4\x91\xf5\x16\x14l\xda (\x17\x19\x97\x80`\u01beAI\x06|\x88\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\xf6$\xb2J\x1f\xa5\xa0V\xfeW\x12)\xe77\x9d\xb1K\x9a\x1e\x8a\x02\x8a\x85\x17\xc6i\xb3W\x00\x00\xe0\x94\x91\xfe\x8aLad\u07cf\xa6\x06\x99]k\xa7\xad\xca\xf1\u0213\u038a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4\x92\x1fRa\xf4\xf6\x12v\a\x06\x89&%\xc7^{\u0396\xb7\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92!\xc9\xce\x01#&et\x10\x96\xac\a#Y\x03\xad\x1f\xe2\xfc\x89\x06\xdbc3U\"b\x80\x00\u07d4\x92%\x988`\xa1\xcbF#\xc7$\x80\xac\x16'+\f\x95\xe5\xf5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x92%\xd4jZ\x80\x949$\xa3\x9e[\x84\xb9m\xa0\xacE\x05\x81\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x92* \u01da\x1d:&\xdd8)g{\xf1\xd4\\\x8fg+\xb6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x92C\x8eR\x03\xb64o\xf8\x86\xd7\xc3b\x88\xaa\xcc\xccx\xce\u028965\u026d\xc5\u07a0\x00\x00\u07d4\x92C\xd7v-w({\x12c\x86\x88\xb9\x85N\x88\xa7i\xb2q\x8965\u026d\xc5\u07a0\x00\x00\u0794\x92K\xcez\x85<\x97\v\xb5\xec{\xb7Y\xba\xeb\x9ct\x10\x85{\x88\xbe -j\x0e\xda\x00\x00\u07d4\x92N\xfam\xb5\x95\xb7\x93\x13'~\x881\x96%\akX\n\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92U\x82&\xb3\x84bl\xadH\xe0\x9d\x96k\xf19^\xe7\xea]\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\x92`\x82\xcb~\xedK\x19\x93\xad$ZGrg\xe1\xc3<\xd5h\x89\x14Jt\xba\u07e4\xb6\x00\x00\u07d4\x92b\t\xb7\xfd\xa5N\x8d\u06dd\x9eM=\x19\xeb\u070e\x88\u009f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92h\xd6&FV6\x11\xdc;\x83*0\xaa#\x94\xc6F\x13\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92i\x8e4Sx\xc6-\x8e\xda\x18M\x946j\x14K\f\x10[\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x92y:\u0173rhwJq0\xde+\xbd3\x04\x05f\x17s\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94\x92y\xb2\"\x8c\xec\x8f{M\xda?2\x0e\x9a\x04f\xc2\xf5\x85\u028a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x92|\xb7\xdc\x18p6\xb5B{\xc7\xe2\x00\xc5\xecE\f\x1d'\u0509\v\xb5\x9a'\x95<`\x00\x00\u07d4\x92|\u00bf\xda\x0e\b\x8d\x02\xef\xf7\v8\xb0\x8a\xa5<\xc3\tA\x89do`\xa1\xf9\x866\x00\x00\xe0\x94\x92\x84\xf9m\xdbG\xb5\x18n\xe5X\xaa12M\xf56\x1c\x0fs\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x92\x9d6\x8e\xb4j-\x1f\xbd\xc8\xff\xa0`~\xdeK\xa8\x8fY\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa7\u0166Cb\xe9\xf8B\xa2=\xec\xa2\x105\x85\u007f\x88\x98\x00\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x92\xa8\x98\xd4o\x19q\x9c8\x12j\x8a<'\x86z\xe2\xce\u5589lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa9q\xa79y\x9f\x8c\xb4\x8e\xa8G]r\xb2\xd2GAr\xe6\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x92\xaa\xe5\x97h\xed\xdf\xf8<\xfe`\xbbQ.s\n\x05\xa1a\u05c9\\\x97xA\fv\u0440\x00\u07d4\x92\xad\x1b=u\xfb\xa6}Tf=\xa9\xfc\x84\x8a\x8a\xde\x10\xfag\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xae[|~\xb4\x92\xff\x1f\xfa\x16\xddB\xad\x9c\xad@\xb7\xf8\u0709.\xe4IU\b\x98\xe4\x00\x00\u07d4\x92\xc0\xf5s\xec\xcfb\xc5H\x10\xeek\xa8\xd1\xf1\x13T+0\x1b\x89\xb7ro\x16\u0331\xe0\x00\x00\u07d4\x92\xc1?\xe0\xd6\u0387\xfdP\xe0=\uf7e6@\x05\t\xbdps\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x92\xc9L( \xdf\xcfqV\xe6\xf10\x88\xec\u754b6v\xfd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\x92\xcf\xd6\x01\x88\xef\u07f2\xf8\xc2\xe7\xb1i\x8a\xbb\x95&\xc1Q\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\u062d\x9aMah;\x80\u0526g.\x84\xc2\rbB\x1e\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x92\u0725\xe1\x02\xb3\xb8\x1b`\xf1\xa5\x04cIG\xc3t\xa8\x8c\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xe454\x0e\x9d%<\x00%c\x89\xf5+\x06}U\x97Nv\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x92\xe49(\x16\xe5\xf2\xef_\xb6X7\xce\xc2\xc22\\\xc6I\"\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x92\xe6X\x1e\x1d\xa1\xf9\xb8F\xe0\x93G3=\xc8\x18\xe2\u04acf\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\x93\x1d\xf3M\x12%\xbc\xd4\"Nch\r\\L\t\xbc\xe75\xa6\x89\x03\xaf\xb0\x87\xb8v\x90\x00\x00\u07d4\x93\x1f\xe7\x12\xf6B\a\xa2\xfdP\"r\x88CT\x8b\xfb\x8c\xbb\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x93#_4\r(c\xe1\x8d/LR\x99e\x16\x13\x8d\"\x02g\x89\x04\x00.D\xfd\xa7\xd4\x00\x00\u07d4\x93%\x82U\xb3|\u007fX\xf4\xb1\x06s\xa92\xdd:\xfd\x90\xf4\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93(\xd5\\\xcb?\xceS\x1f\x19\x93\x823\x9f\x0eWn\xe8@\xa3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x93)\xff\xdc&\x8b\xab\u0788t\xb3f@l\x81D[\x9b-5\x89\x16\xe6/\x8cs\f\xa1\x80\x00\u07d4\x93+\x9c\x04\xd4\r*\xc80\x83\xd9B\x98\x16\x9d\xae\x81\xab.\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4\x9346\xc8G&U\xf6L:\xfa\xaf|Lb\x1c\x83\xa6+8\x8965\u026d\xc5\u07a0\x00\x00\u0794\x93;\xf3?\x82\x99p+:\x90&B\xc3>\v\xfa\xea\\\x1c\xa3\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x93@4\\\xa6\xa3\uaf77sc\xf2X`C\xf2\x948\xce\v\x89\x1c\xc8\x05\xda\r\xff\xf1\x00\x00\xe0\x94\x93@\xb5\xf6x\xe4^\xe0^\xb7\b\xbbz\xbbn\xc8\xf0\x8f\x1bk\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x93J\xf2\x1b~\xbf\xa4g\xe2\xce\xd6Z\xa3N\xdd:\x0e\xc7\x132\x8a\a\x80\x1f>\x80\xcc\x0f\xf0\x00\x00\xe0\x94\x93PiDJj\x98M\xe2\bNFi*\xb9\x9fg\x1f\xc7'\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x93P~\x9e\x81\x19\xcb\xce\u068a\xb0\x87\xe7\xec\xb0q8=i\x81\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x93g\x8a\x00\x00\xe0\x94\x93m\xcf\x00\x01\x94\xe3\xbf\xf5\n\u0174$:;\xa0\x14\xd6a\u060a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x93o8\x13\xf5\xf6\xa1;\x8eO\xfe\xc8?\xe7\xf8&\x18jq\u0349\x1c0s\x1c\xec\x03 \x00\x00\u07d4\x93t\x86\x9dJ\x99\x11\xee\x1e\xafU\x8b\xc4\u00b6>\xc6:\xcf\u074965\u026d\xc5\u07a0\x00\x00\u07d4\x93uc\u0628\x0f\u05657\xb0\xe6m \xa0%%\xd5\u0606`\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\x93v\xdc\xe2\xaf.\xc8\xdc\xdat\x1b~sEfF\x81\xd96h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93\x86\x8d\xdb*yM\x02\xeb\xda/\xa4\x80|v\xe3`\x98X\u0709m\xee\x15\xfc|$\xa7\x80\x00\xe0\x94\x93\x9cC\x13\xd2(\x0e\xdf^\a\x1b\xce\xd8F\x06?\n\x97]T\x8a\x19i6\x89t\xc0[\x00\x00\x00\xe0\x94\x93\xa6\xb3\xabB0\x10\xf9\x81\xa7H\x9dJ\xad%\xe2b\\WA\x8a\x04F\x80\xfej\x1e\xdeN\x80\x00\u07d4\x93\xaa\x8f\x92\xeb\xff\xf9\x91\xfc\x05^\x90ne\x1a\xc7h\xd3+\u02092\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x93\xb4\xbf?\xdf\xf6\xde?NV\xbamw\x99\xdcK\x93\xa6T\x8f\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\x93\xbc}\x9aJ\xbdD\u023b\xb8\xfe\x8b\xa8\x04\xc6\x1a\xd8\xd6Wl\x89\xd8\xd6\x11\x9a\x81F\x05\x00\x00\u07d4\x93\xc2\xe6N]\xe5X\x9e\xd2P\x06\xe8C\x19n\xe9\xb1\xcf\v>\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x93\u020e-\x88b\x1e0\xf5\x8a\x95\x86\xbe\xd4\t\x89\x99\xebg\u074a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4\x93\xe0\xf3~\xcd\xfb\x00\x86\xe3\xe8b\xa9p4D{\x1eM\xec\x1a\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\x93\xe3\x03A\x1a\xfa\xf6\xc1\a\xa4A\x01\u026c[6\xe9\xd6S\x8b\x8a\r\xf9\xdd\xfe\xcd\x03e@\x00\x00\u07d4\x93\xf1\x8c\xd2R`@v\x14\x88\xc5\x13\x17M\x1eycv\x8b,\x89\x82\xff\xac\x9a\u0553r\x00\x00\u07d4\x94\x0fqQ@P\x9f\xfa\xbf\x97EF\xfa\xb3\x90\"\xa4\x19R\u0489K\xe4\xe7&{j\xe0\x00\x00\u07d4\x94,k\x8c\x95[\xc0\u0608\x12g\x8a#g%\xb3'9\xd9G\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x94=7\x86JJS}5\xc8\u0657#\xcdd\x06\xce%b\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94C\x9c\xa9\xcc\x16\x9ay\u0520\x9c\xae^gvJo\x87\x1a!\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x94D\x9c\x01\xb3*\u007f\xa5Z\xf8\x10OB\xcd\xd8D\xaa\x8c\xbc@\x8a\x03\x81\x11\xa1\xf4\xf0<\x10\x00\x00\xe0\x94\x94E\xba\\0\xe9\x89a\xb8`$a\xd08]@\xfb\xd8\x03\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94O\a\xb9o\x90\xc5\xf0\xd7\xc0\u0140S1I\xf3\xf5\x85\xa0x\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\x94T\xb3\xa8\xbf\xf9p\x9f\xd0\u1407~l\xb6\u0219t\xdb\u0589\x90\xf54`\x8ar\x88\x00\x00\u07d4\x94]\x96\xeaW>\x8d\xf7&+\xbf\xa5r\"\x9bK\x16\x01k\x0f\x89\vX\x9e\xf9\x14\xc1B\x00\x00\u07d4\x94^\x18v\x9d~\xe7'\xc7\x01?\x92\xde$\xd1\x17\x96\u007f\xf3\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94a'\x81\x03;W\xb1F\xeet\xe7S\xc6r\x01\u007fS\x85\xe4\x89\xc3(\t>a\xee@\x00\x00\xe0\x94\x94dJ\xd1\x16\xa4\x1c\xe2\xca\u007f\xbe\xc6\t\xbd\xefs\x8a*\xc7\u01ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x94p\xcc6YE\x86\x82\x18!\xc5\u0256\xb6\xed\xc8;mZ2\x89\x01M\x11 \u05f1`\x00\x00\xe0\x94\x94u\xc5\x10\xec\x9a&\x97\x92GtL=\x8c;\x0e\v_D\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94~\x11\xe5\xea)\ro\u00f3\x80H\x97\x9e\f\xd4N\xc7\xc1\u007f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\x83\u064f\x14\xa3?\xdc\x11\x8d@9U\u00995\xed\xfc_p\x89\x18\xea;4\xefQ\x88\x00\x00\u07d4\x94\x911\xf2\x89C\x92\\\xfc\x97\xd4\x1e\f\xea\v&)s\xa70\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x94\x9f\x84\xf0\xb1\xd7\u0127\xcfI\xee\u007f\x8b,J\x13M\xe3(x\x89%\"H\u07b6\xe6\x94\x00\x00\u07d4\x94\x9f\x8c\x10{\xc7\xf0\xac\xea\xa0\xf1pR\xaa\xdb\xd2\xf9s+.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\xa7\u0368\xf4\x81\xf9\u061dB\xc3\x03\xae\x162\xb3\xb7\t\xdb\x1d\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x94\xa9\xa7\x16\x911| d'\x1bQ\xc95?\xbd\xed5\x01\xa8\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x94\xadK\xad\x82K\xd0\ub7a4\x9cX\u03bc\xc0\xff^\b4k\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x94\xbb\xc6}\x13\xf8\x9e\xbc\xa5\x94\xbe\x94\xbcQp\x92\f0\xd9\xf3\x89\x04X\xff\xa3\x15\nT\x00\x00\u07d4\x94\xbe:\xe5Ob\xd6c\xb0\xd4\u031e\x1e\xa8\xfe\x95V\ua7bf\x89\x01C\x13,\xa8C\x18\x00\x00\xe0\x94\x94\xc0U\xe8X5z\xaa0\xcf A\xfa\x90Y\xce\x16J\x1f\x91\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\xe0\x94\x94\xc7B\xfdz\x8by\x06\xb3\xbf\xe4\xf8\x90O\xc0\xbe\\v\x803\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x94\xcaV\xdew\u007f\xd4S\x17\u007f^\x06\x94\xc4x\xe6j\xff\x8a\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x94\xd8\x10t\xdbZ\xe1\x97\u04bb\x13s\xab\x80\xa8}\x12\x1cK\u04ca\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x94\u06c0xs\x86\n\xac=Z\xea\x1e\x88^R\xbf\xf2\x86\x99T\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4\x94\xe1\xf5\u02db\x8a\xba\xce\x03\xa1\xa6B\x82VU;i\f#U\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x94\xef\x8b\xe4Pw\xc7\xd4\xc5e'@\u0794jbbOq?\x89\x05l\xf5Y:\x18\xf8\x80\x00\u07d4\x94\xf1?\x9f\b6\xa3\xee$7\xa8I\"\u0498M\xc0\xf7\xd5;\x89\xa2\xa02\x9b\u00ca\xbe\x00\x00\u07d4\x94\xf8\xf0W\xdb~`\xe6u\xad\x94\x0f\x15X\x85\u0464w4\x8e\x89\x15\xbeat\xe1\x91.\x00\x00\xe0\x94\x94\xfc\u03ad\xfe\\\x10\x9c^\xae\xafF-C\x871B\u020e\"\x8a\x01\x045a\xa8\x82\x93\x00\x00\x00\u07d4\x95\x03N\x16!\x86Q7\xcdG9\xb3F\xdc\x17\xda:'\xc3N\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\x95\fh\xa4\t\x88\x15M#\x93\xff\xf8\xda|\u0369\x96\x14\xf7,\x89\xf9AF\xfd\x8d\xcd\xe5\x80\x00\xe0\x94\x95\x0f\xe9\xc6\xca\xd5\f\x18\xf1\x1a\x9e\xd9\xc4W@\xa6\x18\x06\x12\u040a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x95!\x83\xcf\u04ce5.W\x9d6\xde\xce\u0171\x84P\xf7\xfb\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95'\x8b\b\xde\xe7\xc0\xf2\xc8\xc0\xf7\"\xf9\xfc\xbb\xb9\xa5$\x1f\u0689\x82\x93\t\xf6O\r\xb0\x00\x00\u07d4\x95,W\xd2\xfb\x19Q\a\xd4\xcd\\\xa3\x00wA\x19\u07ed/x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x955r\xf0\xeam\xf9\xb1\x97\xca\xe4\x0eK\x8e\xcc\x05lCq\u014965\u026d\xc5\u07a0\x00\x00\u07d4\x95>\xf6R\xe7\xb7i\xf5=nxjX\x95/\xa9>\xe6\xab\u725b\ny\x1f\x12\x110\x00\x00\u07d4\x95DpF1;/:^\x19\xb9H\xfd;\x8b\xed\xc8,q|\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x95]\xb3\xb7C`\xb9\xa2hg~s\u03a8!f\x8a\xf6\xfa\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\x95`\xe8\xacg\x18\xa6\xa1\xcd\xcf\xf1\x89\xd6\x03\xc9\x06>A=\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x95g\xa0\u0781\x1d\xe6\xff\t[~\xe6N\u007f\x1b\x83\xc2a[\x80\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x95h\x1c\xda\xe6\x9b I\xce\x10\x1e2\\u\x98\x92\xca\xc3\xf8\x11\x89\x9a\xe9*\x9b\xc9L@\x00\x00\xe0\x94\x95h\xb7\xdeuV(\xaf5\x9a\x84T=\xe25\x04\xe1^A\xe6\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x95i\xc6:\x92\x84\xa8\x05bm\xb3\xa3.\x9d#c\x93GaQ\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\x80\x9e\x8d\xa3\xfb\xe4\xb7\xf2\x81\xf0\xb8\xb1q_B\x0f}}c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\x9fW\xfd\xedj\xe3y\x13\xd9\x00\xb8\x1e_H\xa7\x93\"\xc6'\x89\r\xdb&\x10GI\x11\x80\x00\u07d4\x95\x9f\xf1\u007f\x1dQ\xb4s\xb4@\x10\x05'U\xa7\xfa\x8cu\xbdT\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\xa5w\xdc.\xb3\xael\xb9\xdf\xc7z\xf6\x97\xd7\xef\xdf\xe8\x9a\x01\x89\a_a\x0fp\xed \x00\x00\u07d4\x95\xcbm\x8acy\xf9J\xba\x8b\x88ViV,MD\x8eV\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\xd5PB{ZQLu\x1ds\xa0\xf6\u049f\xb6]\"\xed\x10\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x95\u064d\f\x10i\x90\x8f\x06zR\xac\xac+\x8bSM\xa3z\xfd\x89oY\xb60\xa9)p\x80\x00\xe0\x94\x95\xdfN4E\xd7f&$\u010e\xbat\u03de\nS\xe9\xf72\x8a\v\xdb\xc4\x1e\x03H\xb3\x00\x00\x00\u07d4\x95\xe6\xa5K-_g\xa2JHu\xafu\x10|\xa7\xea\x9f\xd2\xfa\x89Hz\x9a0E9D\x00\x00\xe0\x94\x95\xe6\xf9=\xac\"\x8b\xc7XZ%sZ\xc2\xd0v\xcc:@\x17\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x95\xe7ad$\xcd\ta\xa7\x17'$t7\xf0\x06\x92r(\x0e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x95\xe8\n\x82\xc2\f\xbe= `$,\xb9-sX\x10\xd04\xa2\x89\x01\xc3.F?\u0539\x80\x00\u07d4\x95\xf6-\x02C\xed\xe6\x1d\xad\x9a1e\xf59\x05'\rT\xe2B\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x95\xfbZ\xfb\x14\xc1\uf6b7\xd1y\xc5\xc3\x00P?\xd6j^\xe2\x89\x01\xda\xf7\xa0+\r\xbe\x80\x00\u07d4\x96\x10Y\"\x02\u0082\xab\x9b\u0628\x84Q\x8b>\v\xd4u\x817\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x96\x1cY\xad\xc7E\x05\u0446M\x1e\xcf\u02ca\xfa\x04\x12Y<\x93\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x96,\r\xec\x8a=FK\xf3\x9b\x12\x15\xea\xfd&H\n\xe4\x90\u0349l\x82\xe3\xea\xa5\x13\xe8\x00\x00\u07d4\x96,\xd2*\x8e\xdf\x1eONU\xb4\xb1]\xdb\xfb]\x9dT\x19q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x963K\xfe\x04\xff\xfaY\x02\x13\xea\xb3e\x14\xf38\xb8d\xb76\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x967\xdc\x12r=\x9cxX\x85B\uac02fO?\x03\x8d\x9d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96N\xabK'kL\u0618>\x15\xcar\xb1\x06\x90\x0f\xe4\x1f\u0389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96b\xee\x02\x19&h+1\xc5\xf2\x00\xceEz\xbe\xa7ll\xe9\x89$Y\x0e\x85\x89\xebj\x00\x00\xe0\x94\x96l\x04x\x1c\xb5\xe6}\xde25\xd7\xf8b\x0e\x1a\xb6c\xa9\xa5\x8a\x10\r P\xdacQ`\x00\x00\u07d4\x96pv\xa8w\xb1\x8e\xc1ZA[\xb1\x16\xf0n\xf3&E\u06e3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96{\xfa\xf7bC\u0379@\t\xae<\x8d5\x05\xe9\xc0\x80EK\xe0\xe8\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x96\x92A\x91\xb7\xdfe[3\x19\xdcma7\xf4\x81\xa7:\x0f\xf3\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\x96\x96\x05!83\x8cr/\x11@\x81\\\xf7t\x9d\r;:t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96\xa5_\x00\xdf\xf4\x05\xdcM\xe5\xe5\x8cW\xf6\xf6\xf0\xca\xc5]/\x89jf\x167\x9c\x87\xb5\x80\x00\u07d4\x96\xaaW?\xed/#4\x10\u06eeQ\x80\x14[#\xc3\x1a\x02\xf0\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x96\xadW\x9b\xbf\xa8\u06ce\xbe\xc9\u0486\xa7.Fa\xee\xd8\xe3V\x89:\v\xa4+\xeca\x83\x00\x00\u07d4\x96\xb44\xfe\x06W\xe4*\u0302\x12\xb6\x86Q9\xde\xde\x15\x97\x9c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xb9\x06\xear\x9fFU\xaf\xe3\xe5}5'|\x96}\xfa\x15w\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96\xd6-\xfdF\b\u007fb@\x9d\x93\xdd`a\x88\xe7\x0e8\x12W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xd9\u0328\xf5^\xea\x00@\xecn\xb3H\xa1wK\x95\xd9>\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xe7\xc0\xc9\u057f\x10\x82\x1b\xf1@\xc5X\xa1E\xb7\xca\xc2\x13\x97\x899>\xf1\xa5\x12|\x80\x00\x00\u07d4\x96\xeaj\u021a+\xac\x954{Q\u06e6=\x8b\xd5\xeb\xde\xdc\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xea\xfb\xf2\xfboM\xb9\xa46\xa7LE\xb5eDR\xe28\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x96\xebR>\x83/P\n\x01}\xe1>\xc2\u007f]6lV\x0e\xff\x89\x10\xac\u03baC\xee(\x00\x00\u07d4\x96\xf0F*\xe6\xf8\xb9`\x88\xf7\xe9\u018ct\xb9\u062d4\xb3G\x89a\t=|,m8\x00\x00\u07d4\x96\xf8 P\vp\xf4\xa3\xe3#\x9da\x9c\xff\x8f\" u\xb15\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x96\xfeY\xc3\u06f3\xaa|\xc8\xcbbH\fe\xe5nb\x04\xa7\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x96\xffoP\x99h\xf3l\xb4,\xbaH\xdb2\xf2\x1fVv\xab\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x97\t8R*\xfb^\x8f\x99Hs\xc9\xfb\xdc&\xe3\xb3~1L\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\n\xbdS\xa5O\xcaJd) |\x18-MW\xbb9\u0520\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\r\x8b\x8a\x00\x16\xd1C\x05O\x14\x9f\xb3\xb8\xe5P\xdc\a\x97\u01c965\u026d\xc5\u07a0\x00\x00\u07d4\x97,/\x96\xaa\x00\u03ca/ Z\xbc\xf8\x93|\fu\xf5\xd8\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97?N6\x1f\xe5\xde\u0358\x9dL\x8f}|\xc9y\x908]\xaf\x89\x15\x0f\x85C\xa3\x87B\x00\x00\u07d4\x97M\x05A\xabJG\xec\u007fu6\x9c\x00i\xb6J\x1b\x81w\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\x97M/\x17\x89_)\x02\x04\x9d\xea\xae\xcf\t\xc3\x04e\a@-\x88\xcc\x19\u00947\xab\x80\x00\u07d4\x97R\xd1O^\x10\x93\xf0qq\x1c\x1a\xdb\xc4\xe3\xeb\x1e\\W\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97V\xe1v\xc9\xefi>\xe1\xee\u01b9\xf8\xb1Q\xd3\x13\xbe\xb0\x99\x89A\rXj \xa4\xc0\x00\x00\u07d4\x97_7d\xe9{\xbc\xcfv|\xbd;y[\xa8m\x8b\xa9\x84\x0e\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x97j\x18Sj\xf4\x18tBc\b\x87\x1b\xcd\x15\x12\xa7u\xc9\xf8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97n<\xea\xf3\xf1\xafQ\xf8\u009a\xff]\u007f\xa2\x1f\x03\x86\xd8\xee\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x97w\xcca\xcfuk\xe3\xb3\xc2\f\xd4I\x1ci\xd2u\xe7\xa1 \x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97\x81\v\xaf\xc3~\x840c2\xaa\xcb5\xe9*\xd9\x11\xd2=$\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\x8cC\f\xe45\x9b\x06\xbc,\xdf\\)\x85\xfc\x95\x0eP\xd5\u0209\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\x97\x95\xf6C\x19\xfc\x17\xdd\x0f\x82a\xf9\xd2\x06\xfbf\xb6L\xd0\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\x99\xca!\xdb\xcfi\xbf\xa1\xb3\xf7+\xacQ\xb9\xe3\xcaX|\xf9\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x97\x9c\xbf!\xdf\xec\x8a\xce?\x1c\x19m\x82\u07d6%4\xdf9O\x89\x99\x91\xd4x\xddM\x16\x00\x00\u07d4\x97\x9dh\x1ca}\xa1o!\xbc\xac\xa1\x01\xed\x16\xed\x01Z\xb6\x96\x89e\xea=\xb7UF`\x00\x00\u07d4\x97\x9f0\x15\x8bWK\x99\x9a\xab4\x81\a\xb9\xee\xd8[\x1f\xf8\xc1\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x97\xa8o\x01\xce?|\xfdDA3\x0e\x1c\x9b\x19\xe1\xb1\x06\x06\xef\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x97\xb9\x1e\xfesP\xc2\xd5~~@k\xab\x18\xf3a{\xcd\xe1J\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\x97\xd0\xd9r^;p\xe6u\x841s\x93\x8e\xd3q\xb6,\u007f\xac\x89\t79SM(h\x00\x00\u07d4\x97\xd9\xe4jv\x04\u05f5\xa4\xeaN\xe6\x1aB\xb3\xd25\x0f\xc3\xed\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\xdc&\xecg\n1\xe0\"\x1d*u\xbc]\xc9\xf9\f\x1fo\u0509\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x97\xde!\xe4!\xc3\u007f\xe4\xb8\x02_\x9aQ\xb7\xb3\x90\xb5\xdfx\x04\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\x97\xe2\x89s\xb8`\xc5g@(\x00\xfb\xb6<\xe3\x9a\x04\x8a=y\x89\x05B%:\x12l\xe4\x00\x00\u07d4\x97\xe5\xcca'\xc4\xf8\x85\xbe\x02\xf4KB\xd1\u0230\xac\x91\u44c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\xf1\xfeL\x80\x83\xe5\x96!*\x18w(\xdd\\\xf8\n1\xbe\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x97\xf7v\x06W\xc1\xe2\x02u\x90\x86\x96>\xb4!\x1c_\x819\xb9\x8a\n\x8a\t\u007f\xcb=\x17h\x00\x00\xe0\x94\x97\xf9\x9bk\xa3\x13F\u0358\xa9\xfeL0\x8f\x87\u0165\x8cQQ\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x98\n\x84\xb6\x86\xfc1\xbd\xc8<\"\x10XTjq\xb1\x1f\x83\x8a\x89*AUH\xaf\x86\x81\x80\x00\u07d4\x98\x10\xe3J\x94\xdbn\xd1V\xd08\x9a\x0e+\x80\xf4\xfdk\n\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\x1d\xdf\x04\x04\xe4\xd2-\xdaUj\a&\xf0\v-\x98\xab\x95i\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94\x98\x1fq'u\xc0\xda\xd9u\x18\xff\xed\xcbG\xb9\xad\x1dl'b\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x984h!\x80\xb9\x82\xd1f\xba\u06dd\x9d\x1d\x9b\xbf\x01m\x87\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x986\xb4\xd3\x04sd\x1a\xb5j\xee\xe1\x92Bv\x1drrQx\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x989sB\xec_=L\xb8w\xe5N\xf5\xd6\xf1\xd3fs\x1b\u050a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\x98Fd\x886\xa3\a\xa0W\x18O\xd5\x1fb\x8a_\x8c\x12B|\x8a\x04\vi\xbfC\xdc\xe8\xf0\x00\x00\xe0\x94\x98Jy\x85\xe3\xcc~\xb5\xc96\x91\xf6\xf8\xcc{\x8f$]\x01\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x98]p\xd2\a\x89+\xed9\x85\x90\x02N$!\xb1\xcc\x11\x93Y\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x98m\xf4~v\xe4\u05e7\x89\xcd\xee\x91<\u0243\x16P\x93l\x9d\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x98t\x80?\xe1\xf3\xa06^y\"\xb1Bp\xea\xeb\x03,\xc1\xb5\x89<\xf5\x92\x88$\xc6\xc2\x00\x00\u07d4\x98ub4\x95\xa4l\xdb\xf2YS\x0f\xf88\xa1y\x9e\u00c9\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98v\x18\xc8VV |{\xac\x15\a\xc0\xff\xef\xa2\xfbd\xb0\x92\x89\x03}\xfeC1\x89\xe3\x80\x00\u07d4\x98|\x9b\xcdn?9\x90\xa5+\xe3\xed\xa4q\f'Q\x8fOr\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x98\x82\x96|\xeeh\u04a89\xfa\u062bJ|=\xdd\xf6\xc0\xad\u0209Hx\xbe\x1f\xfa\xf9]\x00\x00\u07d4\x98\x85\\}\xfb\xee3SD\x90J\x12\xc4\fs\x17\x95\xb1:T\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4\x98\x9c\f\xcf\xf6T\xda\x03\xae\xb1\x1a\xf7\x01\x05Ea\xd6)~\x1d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xa0\xe5Lm\x9d\u023e\x96'l\xeb\xf4\xfe\xc4`\xf6#]\x85\x89j\u0202\x10\tR\u01c0\x00\u07d4\x98\xb7i\xcc0\\\xec\xfbb\x9a\x00\xc9\a\x06\x9d~\xf9\xbc:\x12\x89\x01h\u048e?\x00(\x00\x00\xe0\x94\x98\xbaN\x9c\xa7/\xdd\xc2\fi\xb49ov\xf8\x18?z*N\x8a\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\x00\u07d4\x98\xbeimQ\xe3\x90\xff\x1cP\x1b\x8a\x0fc1\xb6(\xdd\u016d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbe\u04e7.\xcc\xfb\xaf\xb9#H\x92\x93\xe4)\xe7\x03\xc7\xe2[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbfJ\xf3\x81\v\x84#\x87\xdbp\xc1MF\t\x96&\x00=\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xc1\x0e\xbf,O\x97\u02e5\xa1\xab?*\xaf\xe1\xca\xc4#\xf8\u02c9\x10CV\x1a\x88)0\x00\x00\u07d4\x98\xc1\x9d\xba\x81\v\xa6\x11\xe6\x8f/\x83\xee\x16\xf6\xe7tO\f\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x98\xc5IJ\x03\xac\x91\xa7h\xdf\xfc\x0e\xa1\xdd\u0b3f\x88\x90\x19\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\x98\xd2\x04\xf9\b_\x8c\x8e}\xe2>X\x9bd\xc6\xef\xf6\x92\xccc\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x98\xd3s\x19\x92\xd1\xd4\x0e\x12\x11\xc7\xf75\xf2\x18\x9a\xfa\a\x02\xe0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x98\xe2\xb6\xd6\x06\xfd-i\x91\xc9\xd6\xd4\a\u007f\xdf?\xddE\x85\u06890\xdf\x1ao\x8a\xd6(\x00\x00\u07d4\x98\xe3\xe9\v(\xfc\xca\ue087y\xb8\xd4\nUh\xc4\x11n!\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x98\xe6\xf5G\u06c8\xe7_\x1f\x9c\x8a\xc2\xc5\xcf\x16'\xbaX\v>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x98\xf4\xaf:\xf0\xae\xde_\xaf\xdcB\xa0\x81\xec\xc1\xf8\x9e<\xcf \x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x98\xf6\xb8\xe6!=\xbc\x9aU\x81\xf4\xcc\xe6e_\x95%+\xdb\a\x89\x11Xr\xb0\xbc\xa40\x00\x00\u07d4\x99\te\r\u05719{\x8b\x8b\x0e\xb6\x94\x99\xb2\x91\xb0\xad\x12\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x99\x11s`\x19G\xc2\bJb\xd69R~\x96\x15\x12W\x9a\xf9\x89 \x86\xac5\x10R`\x00\x00\u07d4\x99\x12\x9d[<\f\xdeG\xea\r\xefM\xfc\a\r\x1fJY\x95'\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x99\x17\u058dJ\xf3A\xd6Q\xe7\xf0\a\\m\xe6\xd7\x14Nt\t\x8a\x012\xd4Gl\b\xe6\xf0\x00\x00\u07d4\x99\x1a\xc7\xcap\x97\x11_& ^\xee\x0e\xf7\xd4\x1e\xb4\xe3\x11\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\x99#e\xd7d\xc5\xce5@9\xdd\xfc\x91.\x02:u\xb8\xe1h\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x99&F\xac\x1a\u02ab\xf5\u076b\xa8\xf9B\x9a\xa6\xa9Nt\x96\xa7\x8967Pz0\xab\xeb\x00\x00\u07d4\x99&\x83'\xc3s3.\x06\xc3\xf6\x16B\x87\xd4U\xb9\xd5\xfaK\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99(\xffqZ\xfc:+`\xf8\xebL\u013aN\xe8\u06b6\u5749\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\x992\xef\x1c\x85\xb7Z\x9b*\x80\x05}P\x874\xc5\x10\x85\xbe\u0309\x02\xb8?\xa50\x1dY\x00\x00\xe0\x94\x99?\x14ax`^f\xd5\x17\xbex.\xf0\xb3\xc6\x1aN\x19%\x8a\x01|\x1f\x055\u05e5\x83\x00\x00\xe0\x94\x99A7\x04\xb1\xa3.p\xf3\xbc\ri\u0748\x1c8VkT\u02ca\x05\xcckiF1\xf7\x12\x00\x00\u07d4\x99AR\xfc\x95\xd5\xc1\u028b\x88\x11:\xbb\xadMq\x0e@\xde\xf6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x99D\xfe\xe9\xd3JJ\x88\x00#\u01c92\xc0\vY\xd5\xc8*\x82\x89(\xa8\xa5k6\x90\a\x00\x00\u07d4\x99L\u00b5\"~\xc3\xcf\x04\x85\x12F|A\xb7\xb7\xb7H\x90\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99q\xdf`\xf0\xaef\xdc\xe9\xe8\xc8N\x17\x14\x9f\t\xf9\xc5/d\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x99v\x94~\xff_j\xe5\xda\b\xddT\x11\x92\xf3x\xb4(\xff\x94\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x99}e\x92\xa3\x15\x89\xac\xc3\x1b\x99\x01\xfb\xeb<\xc3\xd6[2\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x82\xa5\x89\x0f\xfbT\x06\u04ec\xa8\u04bf\xc1\xddp\xaa\xa8\n\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x87\x8f\x9dn\n~\u066e\u01c2\x97\xb78y\xa8\x01\x95\xaf\xe0\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d4\x99\x8c\x1f\x93\xbc\xdbo\xf2<\x10\xd0\u0712G(\xb7;\xe2\xff\x9f\x896[\xf3\xa43\xea\xf3\x00\x00\u07d4\x99\x91aL[\xaaG\xddl\x96\x87FE\xf9z\xdd,=\x83\x80\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x99\x92J\x98\x16\xbb}\xdf?\xec\x18D\x82\x8e\x9a\xd7\xd0k\xf4\xe6\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x99\x99vh\xf7\xc1\xa4\xff\x9e1\xf9\x97z\xe3\"K\u02c8z\x85\x89\x0f\xc969(\x01\xc0\x00\x00\u07d4\x99\x9cI\xc1t\xca\x13\xbc\x83l\x1e\n\x92\xbf\xf4\x8b'\x15C\u0289\xb1\xcf$\xdd\u0431@\x00\x00\u07d4\x99\xa4\xde\x19\xde\u05d0\b\xcf\xdc\xd4]\x01M.XK\x89\x14\xa8\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x99\xa9k\xf2$.\xa1\xb3\x9e\xceo\xcc\r\x18\xae\xd0\f\x01y\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x99\xb0\x18\x93+\xca\xd3U\xb6y+%]\xb6p-\xec\x8c\xe5\u0749\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x99\xb7C\xd1\xd9\xef\xf9\r\x9a\x194\xb4\xdb!\xd5\x19\u061bJ8\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x99\xb8\xc8$\x86\x9d\xe9\xed$\xf3\xbf\xf6\x85L\xb6\xddE\xcc?\x9f\x89e\xea=\xb7UF`\x00\x00\u07d4\x99\xc0\x17L\xf8N\a\x83\xc2 \xb4\xebj\xe1\x8f\xe7\x03\x85J\u04c9py\xa2W=\fx\x00\x00\u07d4\x99\xc1\xd9\xf4\fj\xb7\xf8\xa9/\xce/\xdc\xe4zT\xa5\x86\xc5?\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x99\xc26\x14\x1d\xae\xc87\xec\xe0O\xda\xee\x1d\x90\u03cb\xbd\xc1\x04\x89ve\x16\xac\xac\r \x00\x00\u07d4\x99\xc3\x1f\xe7HX7\x87\xcd\xd3\xe5%\xb2\x81\xb2\x18\x96\x179\xe3\x897\b\xba\xed=h\x90\x00\x00\u07d4\x99\xc4u\xbf\x02\xe8\xb9!J\xda_\xad\x02\xfd\xfd\x15\xba6\\\f\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\x99\u0203%\x85F\xcc~N\x97\x1fR.8\x99\x18\xda^\xa6:\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x99\xc9\xf9>E\xfe<\x14\x18\xc3S\xe4\u016c8\x94\xee\xf8\x12\x1e\x89\x05\x85\xba\xf1E\x05\v\x00\x00\xe0\x94\x99\xd1W\x9c\xd4&\x82\xb7dN\x1dOq(D\x1e\xef\xfe3\x9d\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x99\u0475\x85\x96_@jB\xa4\x9a\x1c\xa7\x0fv\x9evZ?\x98\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x99\xdf\xd0PL\x06\xc7C\xe4e4\xfd{U\xf1\xf9\xc7\xec3)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xf4\x14|\xcck\u02c0\u0304.i\xf6\xd0\x0e0\xfaA3\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x99\xf7\u007f\x99\x8b \xe0\xbc\xdc\xd9\xfc\x83\x86ARl\xf2Y\x18\xef\x89a\t=|,m8\x00\x00\u07d4\x99\xfa\xd5\x008\xd0\xd9\xd4\xc3\xfb\xb4\xbc\xe0V\x06\xec\xad\xcdQ!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xfe\r \x12(\xa7S\x14VU\xd4(\xeb\x9f\xd9I\x85\xd3m\x89i \xbf\xf3QZ:\x00\x00\u07d4\x9a\a\x9c\x92\xa6)\xca\x15\xc8\xca\xfa.\xb2\x8d[\xc1z\xf8(\x11\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9a\r<\xee=\x98\x92\xea;7\x00\xa2\u007f\xf8A@\xd9\x02T\x93\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9a$\u038dH\\\xc4\xc8nI\u07b3\x90\"\xf9,t0\xe6~\x89Fy\x1f\xc8N\a\xd0\x00\x00\u07d4\x9a,\xe4;]\x89\u0593k\x8e\x8c5G\x91\xb8\xaf\xff\x96$%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9a9\x01bS^9\x88w\xe4\x16x}b9\xe0uN\x93|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a=\xa6P#\xa10 \xd2!E\xcf\xc1\x8b\xab\x10\xbd\x19\xceN\x89\x18\xbfn\xa3FJ:\x00\x00\xe0\x94\x9a>+\x1b\xf3F\xdd\a\v\x02sW\xfe\xacD\xa4\xb2\xc9}\xb8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9aL\xa8\xb8!\x17\x89NC\xdbr\xb9\xfax\xf0\xb9\xb9:\xce\t\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9aR.R\xc1\x95\xbf\xb7\xcf_\xfa\xae\u06d1\xa3\xbath\x16\x1d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9aZ\xf3\x1c~\x063\x9a\u0234b\x8d|M\xb0\xce\x0fE\u0224\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\x9ac?\xcd\x11,\xce\xebv_\xe0A\x81ps*\x97\x05\u7708\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9ac\u0445\xa7\x91)\xfd\xab\x19\xb5\x8b\xb61\xea6\xa4 TN\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x9ag\b\u0778\x90<(\x9f\x83\xfe\x88\x9c\x1e\xdc\xd6\x1f\x85D#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9ao\xf5\xf6\xa7\xaf{z\xe0\xed\x9c \xec\xecP#\u0481\xb7\x86\x89\x8a\x12\xb9\xbdjg\xec\x00\x00\xe0\x94\x9a\x82\x82m<)H\x1d\xcc+\u0495\x00G\xe8\xb6\x04\x86\xc38\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9a\x8e\xcaA\x89\xffJ\xa8\xff~\u0536\xb7\x03\x9f\t\x02!\x9b\x15\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9a\x95;[\xccp\x93y\xfc\xb5Y\u05f9\x16\xaf\u06a5\f\xad\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x9a\x99\v\x8a\xebX\x8d~\xe7\xec.\xd8\xc2\xe6Os\x82\xa9\xfe\xe2\x89\x01\xd1'\xdbi\xfd\x8b\x00\x00\u07d4\x9a\x9d\x1d\xc0\xba\xa7}n \xc3\xd8I\u01c8b\xdd\x1c\x05L\x87\x89/\xb4t\t\x8fg\xc0\x00\x00\xe0\x94\x9a\xa4\x8cf\xe4\xfbJ\u0419\x93N2\x02.\x82t'\xf2w\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xa80\x8fB\x91\x0eZ\xde\t\xc1\xa5\xe2\x82\xd6\xd9\x17\x10\xbd\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9a\xaa\xfa\x00gd~\u0659\x06kzL\xa5\xb4\xb3\xf3\xfe\xaao\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a\xb9\x88\xb5\x05\xcf\xee\x1d\xbe\x9c\u044e\x9bTs\xb9\xa2\xd4\xf56\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x9a\xb9\x8dm\xbb\x1e\xaa\xe1mE\xa0EhT\x1a\xd3\xd8\xfe\x06\u0309\x0e\xc5\x04d\xfe#\xf3\x80\x00\xe0\x94\x9a\xba+^'\xffx\xba\xaa\xb5\xcd\u0248\xb7\xbe\x85\\\xeb\xbd\u038a\x02\x1e\f\x00\x13\a\n\xdc\x00\x00\u07d4\x9a\xc4\xdaQ\xd2x\"\xd1\xe2\b\xc9n\xa6J\x1e[U)\x97#\x89\x05lUy\xf7\"\x14\x00\x00\u0794\x9a\xc8S\x97y*i\u05cf(k\x86C*\a\xae\u03b6\x0ed\x88\xc6s\xce<@\x16\x00\x00\xe0\x94\x9a\xc9\a\xee\x85\xe6\xf3\xe2#E\x99\x92\xe2V\xa4?\xa0\x8f\xa8\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xd4\u007f\xdc\xf9\u0354-(\xef\xfd[\x84\x11[1\xa6X\xa1>\x89\xb2Y\xec\x00\xd5;(\x00\x00\u07d4\x9a\xdb\u04fc{\n\xfc\x05\xd1\xd2\xed\xa4\x9f\xf8c\x93\x9cH\xdbF\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9a\xdfE\x8b\xff5\x99\xee\xe1\xa2c\x98\x85\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9a\xf9\xdb\xe4t\"\xd1w\xf9E\xbd\xea\xd7\xe6\xd8)05b0\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9a\xfaSkLf\xbc8\xd8u\u0133\x00\x99\xd9&\x1f\xdb8\xeb\x89\v*\x8f\x84*w\xbc\x80\x00\u07d4\x9b\x06\xad\x84\x1d\xff\xbeL\xcfF\xf1\x03\x9f\u00c6\xf3\xc3!Dn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\x11h\u078a\xb6KGU/3\x89\x80\n\x9c\xc0\x8bFf\u03c9]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9b\x18\x11\xc3\x05\x1fF\xe6d\xaeK\xc9\xc8$\u0445\x92\xc4WJ\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9b\x18G\x86U\xa4\x85\x1c\xc9\x06\xe6`\xfe\xaca\xf7\xf4\u023f\xfc\x89\xe2G\x8d8\x90}\x84\x00\x00\u07d4\x9b\"\xa8\r\\{3t\xa0[D`\x81\xf9}\n4\a\x9e\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9b+\xe7\xf5gT\xf5\x05\xe3D\x1a\x10\xf7\xf0\xe2\x0f\xd3\xdd\xf8I\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x9b2\xcfOQ\x15\xf4\xb3J\x00\xa6La}\xe0c\x875C#\x89\x05\xb8\x1e\u0608 |\x80\x00\u07d4\x9bC\u0739_\xde1\x80u\xa5g\xf1\xe6\xb5v\x17\x05^\xf9\xe8\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9bDO\xd37\xe5\xd7R\x93\xad\xcf\xffp\xe1\xea\x01\xdb\x022\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bH$\xff\x9f\xb2\xab\xdaUM\xeeO\xb8\xcfT\x91eW\x061\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bL'\x15x\f\xa4\xe9\x9e`\xeb\xf2\x19\xf1Y\f\x8c\xadP\n\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x9bY\xeb!;\x1eue\xe4PG\xe0N\xa07O\x10v-\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\\9\xf7\xe0\xac\x16\x8c\x8e\xd0\xed4\x04w\x11}\x1bh.\xe9\x89\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4\x9b^\xc1\x8e\x83\x13\x88}\xf4a\u0490.\x81\xe6z\x8f\x11;\xb1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bd\xd3\u034d+s\xf6hA\xb5\xc4k\xb6\x95\xb8\x8a\x9a\xb7]\x89\x01 :Ov\f\x16\x80\x00\u07d4\x9be\x8f\xb3a\xe0F\xd4\xfc\xaa\x8a\xefm\x02\xa9\x91\x11\"6%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9bfA\xb1>\x17/\xc0r\xcaK\x83'\xa3\xbc(\xa1[f\xa9\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94\x9bh\xf6t\x16\xa6;\xf4E\x1a1\x16L\x92\xf6r\xa6\x87Y\xe9\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x9bw6i\xe8}v\x01\x8c\t\x0f\x82U\xe5D\t\xb9\u0728\xb2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bw\xeb\xce\xd7\xe2\x15\xf0\x92\x0e\x8c+\x87\x00$\xf6\xec\xb2\xff1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b|\x88\x10\xcc|\u021e\x80Nm>8\x12\x18PG(w\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\xa5=\xc8\xc9^\x9aG/\xeb\xa2\xc4\xe3,\x1d\xc4\xdd{\xabF\x89Hz\x9a0E9D\x00\x00\xe0\x94\x9b\xac\xd3\xd4\x0f;\x82\xac\x91\xa2d\xd9\u060d\x90\x8e\xac\x86d\xb9\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9b\xb7`\xd5\u0089\xa3\xe1\xdb\x18\xdb\tSE\xcaA;\x9aC\u0089\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x9b\xb7b\x04\x18j\xf2\xf6;\xe7\x91h`\x16\x87\xfc\x9b\xadf\x1f\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9b\xb9\xb0*&\xbf\xe1\xcc\xc3\xf0\xc6!\x9e&\x1c9\u007f\xc5\xcax\x89Hz\x9a0E9D\x00\x00\u07d4\x9b\xc5s\xbc\xda#\xb8\xb2o\x90s\xd9\f#\x0e\x8eq\xe0'\v\x896/u\xa40]\f\x00\x00\u07d4\x9b\xd7\u00caB\x100JMe>\xde\xff\x1b<\xe4_\xcexC\x89\x0fI\x89A\xe6d(\x00\x00\xe0\x94\x9b\u0600h\xe10u\xf3\xa8\xca\xc4d\xa5\xf9I\xd6\xd8\x18\xc0\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9b\xd9\x05\xf1q\x9f\u01ec\xd0\x15\x9dM\xc1\xf8\xdb/!G#8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b\xdb\u071b\x9741\xd1<\x89\xa3\xf9u~\x9b;bu\xbf\u01c9\x1b\x1a}\u03caD\u04c0\x00\u07d4\x9b\xe3\xc3)\xb6*(\xb8\xb0\x88l\xbd\x8b\x99\xf8\xbc\x93\f\xe3\xe6\x89\x04\t\xe5+H6\x9a\x00\x00\xe0\x94\x9b\xf5\x8e\xfb\xea\a\x84\xeb\x06\x8a\xde\u03e0\xbb!P\x84\xc7:5\x8a\x01:k+VHq\xa0\x00\x00\u07d4\x9b\xf6r\xd9y\xb3fR\xfcR\x82Tzjk\xc2\x12\xaeCh\x89#\x8f\xd4,\\\xf0@\x00\x00\xe0\x94\x9b\xf7\x03\xb4\x1c6$\xe1_@T\x96#\x90\xbc\xba0R\xf0\xfd\x8a\x01H>\x01S<.<\x00\x00\u07d4\x9b\xf7\x1f\u007f\xb57\xacT\xf4\xe5\x14\x94\u007f\xa7\xffg(\xf1m/\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\x9b\xf9\xb3\xb2\xf2<\xf4a\xebY\x1f(4\v\xc7\x19\x93\x1c\x83d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9b\xfce\x9c\x9c`\x1e\xa4*k!\xb8\xf1p\x84\xec\x87\xd7\x02\x12\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9b\xff\xf5\r\xb3jxUU\xf0vR\xa1S\xb0\xc4+\x1b\x8bv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\x05\xe9\xd0\xf0u\x8eyS\x03q~1\xda!<\xa1W\u618965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\x1bw\x1f\t\xaf\x88*\xf0d0\x83\xde*\xa7\x9d\xc0\x97\xc4\x0e\x89\x86p\xe9\xece\x98\xc0\x00\x00\u07d4\x9c(\xa2\xc4\b`\x91\xcb]\xa2&\xa6W\xce2H\xe8\xea{o\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\x9c/\xd5@\x89\xaff]\xf5\x97\x1ds\xb8\x04a`9dsu\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c4@\x98\xbaaZ9\x8f\x11\xd0\t\x90[\x17|D\xa7\xb6\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c=\x06\x92\xce\xee\xf8\n\xa4\x96\\\xee\xd2b\xff\xc7\xf0i\xf2\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c@\\\xf6\x97\x95a8\x06^\x11\xc5\xf7U\x9eg$[\u0465\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cE *%\xf6\xad\x00\x11\xf1\x15\xa5\xa7\"\x04\xf2\xf2\x19\x88f\x8a\x01\x0f\xcf:b\xb0\x80\x98\x00\x00\xe0\x94\x9cI\xde\xffG\b_\xc0\x97\x04\u02a2\u0728\u0087\xa9\xa17\u068a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x9cK\xbc\xd5\xf1dJo\aX$\xdd\xfe\x85\xc5q\u05ab\xf6\x9c\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4\x9cRj\x14\x06\x83\xed\xf1C\x1c\xfa\xa1(\xa95\xe2\xb6\x14\u060b\x89\x06\x04o7\xe5\x94\\\x00\x00\xe0\x94\x9cT\xe4\xedG\x9a\x85h)\u01bbB\u069f\vi*u\xf7(\x8a\x01\x97\xa8\xf6\xddU\x19\x80\x00\x00\xe0\x94\x9cX\x1a`\xb6\x10(\xd94\x16y)\xb2-p\xb3\x13\xc3O\u040a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x9c\\\xc1\x11\t,\x12!\x16\xf1\xa8_N\xe3\x14\bt\x1a}/\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x9ck\u0264k\x03\xaeT\x04\xf0C\xdf\xcf!\x88>A\x10\xcc3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cx\x96?\xbc&<\t\xbdr\xe4\xf8\xde\xf7J\x94u\xf7\x05\\\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4\x9cx\xfb\xb4\xdfv\x9c\xe2\xc1V\x92\f\xfe\xdf\xda\x03:\x0e%J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9c{m\xc5\x19\x0f\xe2\x91)c\xfc\xd5yh>\xc79Q\x16\xb0\x89*\x11)\u0413g \x00\x00\u07d4\x9c\x80\xbc\x18\xe9\xf8\u0516\x8b\x18]\xa8\u01df\xa6\xe1\x1f\xfc>#\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x9c\x98\xfd\xf1\xfd\u034b\xa8\xf4\u0170L:\xe8X~\xfd\xf0\xf6\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x9c\x99\xa1\u0691\u0552\v\xc1N\f\xb9\x14\xfd\xf6+\x94\u02c3X\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9c\x99\xb6&\x06(\x1b\\\xef\xab\xf3aV\xc8\xfeb\x83\x9e\xf5\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9c\x9a\a\xa8\xe5|1r\xa9\x19\xefdx\x94tI\x0f\r\x9fQ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\x9d\xe4G$\xa4\x05M\xa0\xea\xa6\x05\xab\u0300&hw\x8b\xea\x89\n\xd7\xd5\xca?\xa5\xa2\x00\x00\u07d4\x9c\x9f;\x8a\x81\x1b!\xf3\xff?\xe2\x0f\xe9p\x05\x1c\xe6j\x82O\x89>\xc2\u07bc\a\u053e\x00\x00\xe0\x94\x9c\x9f\x89\xa3\x91\x0fj*\xe8\xa9\x10G\xa1z\xb7\x88\xbd\xde\xc1p\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\xa0B\x9f\x87O\x8d\xce\xe2\xe9\xc0b\xa9\x02\n\x84*Xz\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xa4.\u7838\x98\xf6\xa5\xcc`\xb5\xa5\u05f1\xbf\xa3\xc321\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xb2\x8a\xc1\xa2\n\x10o\u007f76\x92\xc5\xceLs\xf172\xa1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\xcd\u0732\xcf\u00b2[\br\x9a\n\x98\xd9\xe6\xf0 .\xa2\xc1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9c\xe2\u007f$^\x02\xd1\xc3\x12\xc1\xd5\x00x\x8c\x9d\xefv\x90E;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c\xe56;\x13\xe8#\x8a\xa4\xdd\x15\xac\u0432\xe8\xaf\xe0\x872G\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9c\xf2\x92\x8b\xee\xf0\x9a@\xf9\xbf\xc9S\xbe\x06\xa2Q\x11a\x82\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9d\x06\x91\x97\xd1\xdeP\x04Z\x18o^\xc7D\xac@\u8bd1\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d\x0e}\x92\xfb0XS\u05d8&;\xf1^\x97\xc7+\xf9\xd7\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9d\x0f4~\x82k}\u03aa\xd2y\x06\n5\xc0\x06\x1e\xcf3K\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d u\x17B,\xc0\xd6\r\xe7\xc27\tzMO\xce \x94\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x9d%\n\xe4\xf1\x10\xd7\x1c\xaf\u01f0\xad\xb5.\x8d\x9a\xcbfy\xb8\x8a\x02\x15mn\x99r\x13\xc0\x00\x00\xe0\x94\x9d+\xfc6\x10o\x03\x82P\xc0\x18\x01hW\x85\xb1l\x86\xc6\r\x8aPw\xd7]\xf1\xb6u\x80\x00\x00\xe0\x94\x9d0\xcb#{\xc0\x96\xf1p6\xfc\x80\xdd!\xcah\x99,\xa2\u064a\x06n\xe71\x8f\u070f0\x00\x00\u07d4\x9d2\x96.\xa9\x97\x00\xd92(\xe9\xdb\xda\xd2\xcc7\xbb\x99\xf0~\x89\xb4c+\xed\xd4\xde\xd4\x00\x00\u07d4\x9d4\xda\xc2[\xd1X(\xfa\xef\xaa\xf2\x8fq\aS\xb3\x9e\x89\u0709;\x1cV\xfe\xd0-\xf0\x00\x00\u07d4\x9d6\x91e\xfbp\xb8\x1a:v_\x18\x8f\xd6\f\xbe^{\th\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d@\xe0\x12\xf6\x04%\xa3@\xd8-\x03\xa1\xc7W\xbf\xab\xc7\x06\xfb\x89\t4o:\xdd\u020d\x80\x00\u07d4\x9dAt\xaaj\xf2\x84v\xe2)\xda\xdbF\x18\b\b\xc6u\x05\xc1\x89B\x1a\xfd\xa4.\u0597\x00\x00\u07d4\x9dB\x133\x9a\x01U\x18avL\x87\xa9<\xe8\xf8_\x87\x95\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9dF\f\x1b7\x9d\xdb\x19\xa8\xc8[LgG\x05\r\xdf\x17\xa8u\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x9dG\xba[L\x85\x05\xad\x8d\xa4)4(\va\xa0\xe1\xe8\xb9q\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9dM2\x11w%n\xbd\x9a\xfb\xda0A5\xd5\x17\xc3\xdcV\x93\x89!d\xb7\xa0J\u0220\x00\x00\u07d4\x9dO\xf9\x89\xb7\xbe\u066b\x10\x9d\x10\xc8\xc7\xe5_\x02\xd7g4\xad\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9dQ\x15C\xb3\xd9\xdc`\xd4\u007f\t\u051d\x01\xb6\u0118\xd8 x\x8a\x02a\x97\xb9Qo\u00d4\x00\x00\u07d4\x9dn\u03e0:\xf2\xc6\xe1D\xb7\xc4i*\x86\x95\x1e\x90.\x9e\x1f\x89\xa2\xa5\xaa`\xad$?\x00\x00\u07d4\x9dvU\xe9\xf3\xe5\xba]n\x87\xe4\x12\xae\xbe\x9e\xe0\u0512G\ue24e\t1\x1c\x1d\x80\xfa\x00\x00\u07d4\x9dx1\xe84\xc2\v\x1b\xaaiz\xf1\xd8\xe0\xc6!\u016f\xff\x9a\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\x9dx\xa9u\xb7\xdb^M\x8e(\x84\\\xfb\xe7\xe3\x14\x01\xbe\r\u0649H\xa40k\xa2\u5e5c\x8ahX\u02f5,\f\xf75\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\x9d\u007f\xdapp\xbf>\xe9\xbb\u0664\x1fU\xca\u0505J\xe6\xc2,\x8a\x02U\u02e3\xc4o\xcf\x12\x00\x00\u07d4\x9d\x81\xae\xa6\x9a\xedj\xd0p\x89\xd6\x14E4\x8c\x17\xf3K\xfc[\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9d\x91\x1f6\x82\xf3/\xe0y.\x9f\xb6\xff<\xfcG\xf5\x89\xfc\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\x91;]3\x9c\x95\xd8wEV%c\xfe\xa9\x8b#\xc6\f\u0109\tA0,\u007fM#\x00\x00\u07d4\x9d\x93\xfa\xb6\xe2(E\xf8\xf4Z\aIo\x11\xdeqS\r\xeb\u01c9lO\xd1\xee$nx\x00\x00\u07d4\x9d\x99\xb1\x89\xbb\u0664\x8f\xc2\xe1n\x8f\u0363;\xb9\x9a1{\xbb\x89=\x16\xe1\vm\x8b\xb2\x00\x00\u07d4\x9d\x9cN\xfe\x9fC9\x89\xe2;\xe9@I!S)\xfaU\xb4\u02c9\r\u3c89\x03\u01b5\x80\x00\u07d4\x9d\x9eW\xfd\xe3\x0ePh\xc0>I\x84\x8e\xdc\xe3C\xb7\x02\x83X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9d\xa30\"@\xaf\x05\x11\xc6\xfd\x18W\xe6\u07779Ow\xabk\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\x9d\xa4\xec@pw\xf4\xb9p{-\x9d.\xde^\xa5(+\xf1\u07c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xa6\t\xfa:~l\xf2\xcc\x0ep\u036b\xe7\x8d\xc4\xe3\x82\xe1\x1e\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\x9d\xa6\x1c\xcdb\xbf\x86\x06V\xe02]qW\xe2\xf1`\xd9;\xb5\x8a\x01\x0f\f\xa9V\xf8y\x9e\x00\x00\xe0\x94\x9d\xa6\xe0u\x98\x9ct\x19\tL\xc9\xf6\xd2\u44d3\xbb\x19\x96\x88\x8a\x02Y\xbbq\u056d\xf3\xf0\x00\x00\u07d4\x9d\xa8\xe2,\xa1\x0eg\xfe\xa4NR^GQ\xee\xac6\xa3\x11\x94\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x9d\xb2\xe1\\\xa6\x81\xf4\xc6`H\xf6\xf9\xb7\x94\x1e\u040b\x1f\xf5\x06\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xc1\x0f\xa3\x8f\x9f\xb0h\x10\xe1\x1f`\x17>\xc3\xd2\xfdju\x1e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9d\xd2\x19f$\xa1\xdd\xf1J\x9d7^_\a\x15+\xaf\"\xaf\xa2\x89A\xb0^$c\xa5C\x80\x00\u07d4\x9d\xd4k\x1cm?\x05\u279co\x03~\xed\x9aYZ\xf4\xa9\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9d\xdd5^cN\xe9\x92~K\u007fl\x97\xe7\xbf:/\x1ehz\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9d\xe2\n\xe7j\xa0\x82c\xb2\x05\xd5\x14$a\x96\x1e$\b\xd2f\x89\r\xa93\xd8\xd8\xc6p\x00\x00\u07d4\x9d\xe2\v\xc3~\u007fH\xa8\x0f\xfdz\xd8O\xfb\xf1\xa1\xab\xe1s\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9d\xe78m\xde@\x1c\xe4\xc6{q\xb6U?\x8a\xa3N\xa5\xa1}\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9d\xeb9\x02z\xf8w\x99+\x89\xf2\xecJ\x1f\x82.\xcd\xf1&\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xef\xe5j\x0f\xf1\xa1\x94}\xba\t#\xf7\xdd%\x8d\x8f\x12\xfaE\x8a\x05\xb1*\ufbe8\x04\x00\x00\x00\u07d4\x9d\xf0W\xcd\x03\xa4\xe2~\x8e\x03/\x85y\x85\xfd\u007f\x01\xad\xc8\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xf3*P\x1c\vx\x1c\x02\x81\x02/B\xa1)?\xfd{\x89*\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\x9e\x01vZ\xff\b\xbc\"\x05P\xac\xa5\xea.\x1c\xe8\u5c19#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9e \xe5\xfd6\x1e\xab\xcfc\x89\x1f[\x87\xb0\x92h\xb8\xeb7\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e#,\b\xc1M\xc1\xa6\xed\v\x8a;(h\x97{\xa5\xc1}\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e#\xc5\u4dc2\xb0\n_\xad\U0006eb47\xda\xcf[\x03g\xa1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e59\x90q\xa4\xa1\x01\xe9\x19M\xaa?\t\xf0J\v_\x98p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e>\xb5\t'\x8f\xe0\xdc\xd8\xe0\xbb\xe7\x8a\x19N\x06\xb6\x809C\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x9eBrrQk>g\xd4\xfc\xbf\x82\xf5\x93\x90\xd0L\x8e(\xe5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9eL\xec5:\xc3\u3043^<\t\x91\xf8\xfa\xa5\xb7\u0428\xe6\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\u07d4\x9eX\x11\xb4\v\xe1\xe2\xa1\xe1\u048c;\at\xac\xde\n\t`=\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9eZ1\x1d\x9fi\x89\x8a|j\x9dc`h\x048\xe6z{/\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x9e| P\xa2'\xbb\xfd`\x93~&\x8c\xea>h\xfe\xa8\xd1\xfe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e\u007fe\xa9\x0e\x85\b\x86{\xcc\xc9\x14%j\x1e\xa5t\xcf\a\xe3\x89C8t\xf62\xcc`\x00\x00\xe0\x94\x9e\x81D\xe0\x8e\x89dx\x11\xfekr\xd4E\u05a5\xf8\n\xd2D\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9e\x8fd\xdd\xcd\u9e34Q\xba\xfa\xa25\xa9\xbfQ\x1a%\xac\x91\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\x9e\x95\x1fm\xc5\xe3R\xaf\xb8\xd0B\x99\xd2G\x8aE\x12Y\xbfV\x89\x03\xe7A\x98\x81\xa7:\x00\x00\u07d4\x9e\x96\r\xcd\x03\u057a\x99\xcb\x11]\x17\xffL\t$\x8a\xd4\u043e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9e\xafj2\x8a@v\x02N\xfakg\xb4\x8b!\xee\xdc\xc0\xf0\xb8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x9e\xb1\xffqy\x8f(\xd6\xe9\x89\xfa\x1e\xa0X\x8e'\xba\x86\xcb}\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\x9e\xb2\x81\xc3'\x19\xc4\x0f\xdb>!m\xb0\xf3\u007f\xbcs\xa0&\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e\xb3\xa7\xcb^g&Bz:6\x1c\xfa\x8dad\xdb\u043a\x16\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4\x9e\xb7\x83N\x17\x1dA\xe0i\xa7yG\xfc\xa8v\"\xf0\xbaNH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x9e\xc0>\x02\u51f7v\x9d\xefS\x84\x13\xe9\u007f~U\xbeq\u060a\x04+\xf0kx\xed;P\x00\x00\u07d4\x9e\u02eb\xb0\xb2'\x82\xb3uD)\xe1uz\xab\xa0K\x81\x18\x9f\x89,\xa7\xbb\x06\x1f^\x99\x80\x00\u07d4\x9e\xce\x14\x00\x80\t6\xc7\xc6H_\xcd\xd3b`\x17\u041a\xfb\xf6\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\x9e\xd4\xe6?ReB\xd4O\xdd\xd3MY\xcd%8\x8f\xfdk\u0689\u049b4\xa4cH\x94\x00\x00\u07d4\x9e\xd8\x0e\xda\u007fU\x05M\xb9\xfbR\x82E\x16\x88\xf2k\xb3t\xc1\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9e\u0710\xf4\xbe!\be!J\xb5\xb3^Z\x8d\xd7t\x15'\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e\u07acL\x02k\x93\x05M\u0171\xd6a\fo9`\xf2\xads\x89A\rXj \xa4\xc0\x00\x00\u07d4\x9e\xe9?3\x9eg&\xece\xee\xa4O\x8aK\xfe\x10\xda=2\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9e\xe9v\f\xc2s\xd4pj\xa0\x83u\xc3\xe4o\xa20\xaf\xf3\u054a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4\x9e\xeb\a\xbd+x\x90\x19^}F\xbd\xf2\a\x1bf\x17QM\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x9e\xefD-)\x1aD}t\xc5\xd2S\u011e\xf3$\xea\xc1\xd8\xf0\x89\xb9f\b\xc8\x10;\xf0\x00\x00\u07d4\x9e\xf1\x89k\x00|2\xa1Q\x14\xfb\x89\xd7=\xbdG\xf9\x12+i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9f\x01w\x06\xb80\xfb\x9c0\ufc20\x9fPk\x91WEu4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x10\xf2\xa0F;e\xae0\xb0p\xb3\xdf\x18\xcfF\xf5\x1e\x89\xbd\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x9f\x19\xfa\u0223$7\xd8\n\u0183z\v\xb7\x84\x17)\xf4\x97.\x89#=\xf3)\x9far\x00\x00\u07d4\x9f\x1a\xa8\xfc\xfc\x89\xa1\xa52\x8c\xbdcD\xb7\x1f'\x8a,\xa4\xa0\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9f!0,\xa5\tk\xeat\x02\xb9\x1b\x0f\xd5\x06%O\x99\x9a=\x89C\x97E\x1a\x00=\xd8\x00\x00\u07d4\x9f'\x1d(U\x00\xd78F\xb1\x8fs>%\u074bO]J\x8b\x89'#\xc3F\xae\x18\b\x00\x00\u07d4\x9f4\x97\xf5\xef_\xe60\x95\x83l\x00N\xb9\xce\x02\xe9\x01;K\x89\"V\x86\x1b\xf9\xcf\b\x00\x00\xe0\x94\x9f:t\xfd^~\xdc\xc1\x16)\x93\x17\x13\x81\u02f62\xb7\xcf\xf0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9fF\xe7\xc1\xe9\a\x8c\xae\x860Z\xc7\x06\v\x01F}f\x85\xee\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x9fIl\xb2\x06\x95c\x14M\b\x11g{\xa0\xe4q:\nAC\x89<\xd2\xe0\xbfc\xa4H\x00\x00\u07d4\x9fJq\x95\xac|\x15\x1c\xa2X\xca\xfd\xa0\u02b0\x83\xe0I\xc6\x02\x89SS\x8c2\x18\\\xee\x00\x00\u07d4\x9fJ\xc9\xc9\xe7\xe2L\xb2DJ\x04T\xfa[\x9a\xd9\xd9-8S\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x9f_D\x02kWjJ\xdbA\xe9YaV\x1dA\x03\x9c\xa3\x91\x89\r\x8drkqw\xa8\x00\x00\u07d4\x9f`{?\x12F\x9fDa!\u03bf4u5kq\xb42\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9fa\xbe\xb4o^\x85=\n\x85!\xc7Dnh\xe3L}\ts\x89\x1e[\x8f\xa8\xfe*\xc0\x00\x00\u07d4\x9fd\xa8\xe8\xda\xcfJ\xde0\xd1\x0fMY\xb0\xa3\u056b\xfd\xbft\x8966\x9e\xd7t}&\x00\x00\u07d4\x9ff.\x95'A!\xf1wVncm#\x96L\xf1\xfdho\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9fj2*mF\x99\x81Bj\xe8D\x86]~\xe0\xbb\x15\u01f3\x89\x02\xb5\xeeW\x92\x9f\u06c0\x00\u07d4\x9fy\x86\x92J\xeb\x02h|\xd6A\x89\x18\x9f\xb1g\xde\xd2\xdd\\\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x9fz\x03\x92\xf8Ws.0\x04\xa3u\xe6\xb1\x06\x8dI\xd801\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x82E\u00eb}\x171d\x86\x1c\u04d9\x1b\x94\xf1\xba@\xa9:\x89\x9b\ny\x1f\x12\x110\x00\x00\u07d4\x9f\x83\xa2\x93\xc3$\xd4\x10l\x18\xfa\xa8\x88\x8fd\u0499\x05L\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9f\x86\xa0f\xed\xb6\x1f\xcbXV\u0793\xb7\\\x8cy\x18d\xb9{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x98\xeb4\xd4iy\xb0\xa6\u078b\x05\xaaS:\x89\xb8%\xdc\xf1\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\xe0\x94\x9f\x9f\xe0\xc9_\x10\xfe\xe8z\xf1\xaf r6\xc8\xf3aN\xf0/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9f\xae\xa1\xc5\xe8\x1ez\xcb?\x17\xf1\xc3Q\xee.\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0\b\x01\x98c\xc1\xa7|\x14\x99\xeb9\xbb\u05ff-\u05e3\x1c\xb9\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xa0\t\xbf\ao\x1b\xa3\xfaW\u04a7!r\x18\xbe\xd5VZzz\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0\x1e\x94v\u07c4C\x18%\xc86\xe8\x80:\x97\xe2/\xa5\xa0\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xa0\x1f\x12\xd7\x0fD\xaa{\x11;(\\\"\xdc\xdbE\x874T\xa7\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa0\x1f\u0450j\x90\x85\x06\xde\xda\xe1\xe2\b\x12\x88r\xb5n\u7489\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa0\"\x82@\xf9\x9e\x1d\xe9\xcb2\xd8,\x0f/\xa9\xa3\xd4K\v\xf3\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xa0+\xdedahn\x19\xace\f\x97\r\x06r\xe7m\xcbO\u008a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4\xa0,\x1e4\x06O\x04u\xf7\xfa\x83\x1c\xcb%\x01L:\xa3\x1c\xa2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xa0-\u01aa2\x8b\x88\r\u97acTh#\xfc\xcfw@G\xfb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa0.?\x8fYY\xa7\xaa\xb7A\x86\x12\x12\x9bp\x1c\xa1\xb8\x00\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa04\u007f\n\x98wc\x90\x16\\\x16m2\x96;\xf7M\xcd\n/\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa05\xa3e$x\xf8-\xbdm\x11_\xaa\x8c\xa9F\xec\x9eh\x1d\x89\x05\xf4\xe4-\u052f\xec\x00\x00\u07d4\xa0:=\xc7\xc53\xd1tB\x95\xbe\x95]a\xaf?R\xb5\x1a\xf5\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa0E\x9e\xf3i:\xac\xd1d|\xd5\u0612\x989 L\xefS\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0O*\xe0*\xdd\x14\xc1/\xafe\xcb%\x90\"\u0403\n\x8e&\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xa0l\xd1\xf3\x969l\ndFFQ\xd7\xc2\x05\xef\xaf8|\xa3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa0ri\x1c\x8d\xd7\xcdB7\xffr\xa7\\\x1a\x95\x06\xd0\xce[\x9e\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xa0r\u03beb\xa9\xe9\xf6\x1c\xc3\xfb\xf8\x8a\x9e\xfb\xfe>\x9a\x8dp\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0v\x82\x00\v\x1b\xcf0\x02\xf8\\\x80\xc0\xfa)I\xbd\x1e\x82\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0z\xa1mt\xae\u8a63(\x8dR\xdb\x15Q\u0553\x882\x97\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x8d![[j\xacHa\xa2\x81\xac~@\vx\xfe\xf0L\xbf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa0\x95\x19p\xdf\u0403/\xb8;\xda\x12\xc25E\xe7\x90Aul\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x9fM^\xaae\xa2\xf4\xcbu\nI\x924\x01\xda\u5410\xaf\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\xa0\xa0\xe6R\x04T\x1f\u029b/\xb2\x82\u0355\x13\x8f\xae\x16\xf8\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa0\xaa_\x02\x01\xf0M;\xbe\xb8\x98\x13/|\x11g\x94f\xd9\x01\x89\x01\xfb\xedR\x15\xbbL\x00\x00\u07d4\xa0\xaa\xdb\xd9P\x97\"p_m#X\xa5\u01df7\x97\x0f\x00\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa0\xb7q\x95\x1c\xe1\xde\xee6:\xe2\xb7q\xb7>\a\u0135\xe8\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa0\xde\\`\x1eif5\u0198\xb7\xae\x9c\xa4S\x9f\u01f9A\xec\x89\x12\xc3\xcb\xd7\x04\xc9w\x00\x00\u07d4\xa0\xe8\xbaf\x1bH\x15L\xf8C\xd4\u00a5\xc0\xf7\x92\xd5(\xee)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0\xfc~S\xc5\xeb\xd2z*\xbd\xacE&\x1f\x84\xab;Q\xae\xfb\x89\xa3\x13\xda\xec\x9b\xc0\xd9\x00\x00\xe0\x94\xa0\xff[L\xf0\x16\x02~\x83#I}D(\xd3\xe5\xa8;\x87\x95\x8a\x01e\x98\xd3\xc8>\xc0B\x00\x00\u07d4\xa1\x06F[\xbd\x19\u1dbc\xe5\r\x1b\x11W\xdcY\tZ60\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa1\x06\xe6\x92>\xddS\u028e\xd6P\x96\x8a\x91\b\xd6\xcc\xfd\x96p\x8a\x02\x02\xfe\x15\x05\xaf\uc240\x00\u07d4\xa1\t\u12f0\xa3\x9c\x9e\xf8/\xa1\x95\x97\xfc^\xd8\xe9\xebmX\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xa1\x1a\x03\u013b&\xd2\x1e\xffg}]U\\\x80\xb2TS\xeez\x89\x03\xcb'Y\xbcA\x0f\x80\x00\u07d4\xa1\x1e\xff\xabl\xf0\xf5\x97,\xff\xe4\xd5e\x96\xe9\x89h\x14J\x8f\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xa1 M\xad_V\a(\xa3\\\r\x8f\u01d4\x81\x05{\xf7s\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa1&#\xe6)\u07d3\tg\x04\xb1`\x84\xbe,\u061dV-\xa4\x8a\x01\xcc\xc92E\x11\xe4P\x00\x00\xe0\x94\xa1*l-\x98]\xaf\x0eO_ z\xe8Q\xaa\xf7)\xb32\u034a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa13m\xfb\x96\xb6\xbc\xbeK>\xdf2\x05\xbeW#\xc9\x0f\xadR\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa1;\x9d\x82\xa9\x9b<\x9b\xbaZ\xe7.\xf2\x19\x9e\xdc};\xb3l\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa1<\xfe\x82mm\x18A\u072eD;\xe8\u00c7Q\x816\xb5\xe8\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\xe0\x94\xa1C.\xd2\u01b7wz\x88\xe8\xd4m8\x8epG\u007f \x8c\xa5\x8a\x01\xb1\xa7\xe4\x13\xa1\x96\xc5\x00\x00\u07d4\xa1D\xf6\xb6\x0fr\xd6J!\xe30\xda\xdbb\u0619\n\xde+\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1P%\xf5\x95\xac\xdb\xf3\x11\x0fw\u017f$G~eH\xf9\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1X\x14\x8a.\x0f>\x92\xdc,\xe3\x8f\xeb\xc2\x01\a\xe3%<\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1a`\x85\x1d+\x9c4\x9b\x92\xe4o\x82\x9a\xbf\xb2\x10\x945\x95\x89a\t=|,m8\x00\x00\u07d4\xa1f\xf9\x11\xc6D\xac2\x13\u049e\x0e\x1a\xe0\x10\xf7\x94\u056d&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1m\x9e=c\x98aY\xa8\x00\xb4h7\xf4^\x8b\xb9\x80\xee\v\x89n\x11u\xdaz\xd1 \x00\x00\u07d4\xa1pp\xc2\xe9\u0169@\xa4\xec\x0eIT\xc4\xd7\xd6C\xbe\x8fI\x89lk\x17\x03;6\x1c\x80\x00\u07d4\xa1|\x9eC#\x06\x95\x18\x18\x9dR\a\xa0r\x8d\u02d20j?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\x83`\xe9\x85\xf2\x06.\x8f\x8e\xfe\x02\xad,\xbc\x91\xad\x9aZ\xad\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa1\x91\x14\x05\xcfn\x99\x9e\xd0\x11\xf0\xdd\xcd*O\xf7\u008f%&\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa1\x92i\x80\a\xcc\x11\xaa`=\"\x1d_\xee\xa0v\xbc\xf7\xc3\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\x92\xf0j\xb0R\xd5\xfd\u007f\x94\xee\xa81\x8e\x82x\x15\xfegz\x89\a\x1f\x8a\x93\xd0\x1eT\x00\x00\u07d4\xa1\x99\x81D\x96\x8a\\p\xa6AUT\xce\xfe\u0082F\x90\u0125\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa1\xa1\xf0\xfam \xb5\nyO\x02\xefR\b\\\x9d\x03j\xa6\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\xae\x8dE@\xd4\xdbo\xdd\xe7\x14oA[C\x1e\xb5\\y\x83\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xa1\xb4|M\x0e\xd6\x01\x88B\xe6\xcf\xc8c\n\u00e3\x14.^k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xa1\xc4\xf4Z\x82\xe1\xc4x\xd8E\b.\xb1\x88u\xc4\xeae9\xab\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa1\xdc\xd0\xe5\xb0Z\x97|\x96#\xe5\xae/Y\xb9\xad\xa2\xf3>1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa1\xe48\n;\x1ft\x96s\xe2p\"\x99\x93\xeeU\xf3Vc\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf1\x93\xa0Y/\x1f\xeb\x9f\xdf\xc9\n\xa8\x13xN\xb8\x04q\u0249K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa1\xf2\x85@P\xf8re\x8e\xd8.R\xb0\xad{\xbc\x1c\xb9!\xf6\x89m\x03\x17\xe2\xb3&\xf7\x00\x00\u07d4\xa1\xf5\xb8@\x14\rZ\x9a\xce\xf4\x02\xac<\u00c8jh\xca\xd2H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf7e\xc4O\xe4_y\x06w\x94HD\xbeO-B\x16_\xbd\x89\xc7\xe9\xcf\xdev\x8e\xc7\x00\x00\u07d4\xa1\xf7\xdd\xe1\xd78\xd8\xcdg\x9e\xa1\xee\x96[\xee\"K\xe7\xd0M\x89=\x18DP\xe5\xe9<\x00\x00\u07d4\xa1\xf8\u063c\xf9\x0ew\u007f\x19\xb3\xa6Iu\x9a\xd9P'\xab\xdf\u00c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x02TrB\x80onp\xe7@X\xd6\xe5)-\xef\xc8\xc8\u0509l\x87T\xc8\xf3\f\b\x00\x00\u07d4\xa2\r\a\x1b\x1b\x000cI}y\x90\xe1$\x9d\xab\xf3l5\xf7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\r\x8f\xf6\f\xaa\xe3\x1d\x02\xe0\xb6e\xfaC]v\xf7|\x94B\x89\x1a\x8a\x90\x9d\xfc\xef@\x00\x00\u07d4\xa2\x11\xda\x03\xcc\x0e1\xec\xceS\t\x99\x87\x18QU(\xa0\x90\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x14B\xab\x054\n\xdeh\xc9\x15\xf3\xc39\x9b\x99U\xf3\xf7\xeb\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xa2\"\"Y\u075c>=\xed\x12p\x84\xf8\b\xe9*\x18\x870,\x89\b\xc83\x9d\xaf\xedH\x00\x00\u07d4\xa2*\xde\r\xdb\\n\xf8\xd0\u034d\xe9M\x82\xb1\x10\x82\xcb.\x91\x897KW\xf3\xce\xf2p\x00\x00\u07d4\xa2L:\xb6!\x81\xe9\xa1[x\xc4b\x1eL|X\x81'\xbe&\x89\b\xcd\xe4:\x83\xd31\x00\x00\u07d4\xa2W\xadYK\u0603(\xa7\xd9\x0f\xc0\xa9\a\u07d5\xee\xca\xe3\x16\x89\x1c7\x86\xff8F\x93\x00\x00\u07d4\xa2[\bd7\xfd!\x92\u0420\xf6On\xd0D\xf3\x8e\xf3\xda2\x89\x12)\x0f\x15\x18\v\xdc\x00\x00\u07d4\xa2v\xb0X\u02d8\u060b\xee\xdbg\xe5CPl\x9a\r\x94p\u0609\x90\xaa\xfcv\xe0/\xbe\x00\x00\u07d4\xa2\x82\xe9i\xca\xc9\xf7\xa0\xe1\xc0\u0350\xf5\xd0\xc48\xacW\r\xa3\x89\"\a\xeb\x89\xfc'8\x00\x00\xe0\x94\xa2\x91\xe9\u01d9\rU-\u046e\x16\u03bc?\xca4,\xba\xf1\u044a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa2\x93\x19\xe8\x10i\xe5\xd6\r\xf0\x0f=\xe5\xad\xee5\x05\xec\xd5\xfb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa2\x96\x8f\xc1\xc6K\xac\vz\xe0\u058b\xa9I\x87Mm\xb2S\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa2\x9d[\xdat\xe0\x03GHr\xbdX\x94\xb8\x853\xffd\u00b5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa2\x9df\x1acv\xf6m\vt\xe2\xfe\x9d\x8f&\xc0$~\xc8L\x89\xdf3\x04\a\x9c\x13\xd2\x00\x00\u07d4\xa2\xa45\xdeD\xa0\x1b\xd0\ucc9eD\xe4vD\xe4j\f\xdf\xfb\x89\x1b\x1dDZz\xff\xe7\x80\x00\u07d4\xa2\xac\xe4\u0253\xbb\x1eS\x83\xf8\xact\xe1y\x06n\x81O\x05\x91\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa2\xb7\x01\xf9\xf5\xcd\u041eK\xa6+\xae\xba\u3a02W\x10X\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\u0145O\xf1Y\x9f\x98\x89,W%\xd2b\xbe\x1d\xa9\x8a\xad\xac\x89\x11\t\xff30\x10\xe7\x80\x00\u07d4\xa2\xc7\xea\xff\xdc,\x9d\x93sE l\x90\x9aR\u07f1LG\x8f\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa2\u04aabk\t\xd6\xd4\xe4\xb1?\u007f\xfcZ\x88\xbdz\xd3gB\x89\xfb\x80xPuS\x83\x00\x00\u07d4\xa2\u04cd\xe1\xc79\x06\xf6\xa7\xcan\xfe\xb9|\xf6\xf6\x9c\xc4!\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa2\xdce\xee%kY\xa5\xbdy)wO\x90K5\x8d\U000ed84a\x04\x83\xbc\xe2\x8b\xeb\t\xf8\x00\x00\u07d4\xa2\xe0h:\x80]\xe6\xa0^\xdb/\xfb\xb5\xe9o\x05p\xb67\u00c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa2\u1e2a\x90\x0e\x9c\x13\x9b?\xa1\"5OaV\xd9*\x18\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa2\u2d54\x1e\f\x01\x94K\xfe\x1d_\xb4\xe8\xa3K\x92,\u03f1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xe4`\xa9\x89\xcb\x15V_\x9e\u0327\xd1!\xa1\x8eN\xb4\x05\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa2\xec\xce,I\xf7*\t\x95\xa0\xbd\xa5z\xac\xf1\xe9\xf0\x01\xe2*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa2\xf4r\xfeO\"\xb7}\xb4\x89!\x9e\xa4\x02=\x11X*\x93)\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa2\xf7\x98\xe0w\xb0}\x86\x12N\x14\a\xdf2\x89\r\xbbKcy\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xf8k\xc0a\x88N\x9e\xef\x05d\x0e\xddQ\xa2\xf7\xc0Yli\x89llD\xfeG\xec\x05\x00\x00\u07d4\xa2\xfa\x17\xc0\xfbPl\xe4\x94\x00\x8b\x95W\x84\x1c?d\x1b\x8c\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa3\x04X\x8f\r\x85\f\xd8\u04cfv\xe9\xe8<\x1b\xf6>3>\u0789\x02(V\x01!l\x8c\x00\x00\u07d4\xa3\x05\x8cQszN\x96\xc5_.\xf6\xbd{\xb3X\x16~\u00a7\x89 \xdb:\xe4H\x1a\u0500\x00\u07d4\xa3\t\xdfT\u02bc\xe7\f\x95\xec03\x14\x9c\xd6g\x8ao\xd4\u03c9\f\x1f\x12\xc7Q\x01X\x00\x00\u07d4\xa3\nER\x0eR\x06\xd9\x00@p\xe6\xaf>{\xb2\xe8\xddS\x13\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3\x0e\n\xcbSL\x9b0\x84\xe8P\x1d\xa0\x90\xb4\xeb\x16\xa2\xc0\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3 0\x95\xed\xb7\x02\x8ehq\xce\n\x84\xf5HE\x9f\x830\n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa3!\t\x1d0\x18\x06By\xdb9\x9d+*\x88\xa6\xf4@\xae$\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\xa3#-\x06\x8dP\x06I\x03\xc9\xeb\xc5c\xb5\x15\xac\u0237\xb0\x97\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94\xa3$\x1d\x89\n\x92\xba\xf5)\b\xdcJ\xa0Irk\xe4&\xeb\u04ca\x04<-\xa6a\xca/T\x00\x00\u07d4\xa3)F&\xec)\x84\xc4;C\xdaM]\x8eFi\xb1\x1dKY\x896\xa4\xcfcc\x19\xc0\x00\x00\u07d4\xa3,\xf7\xdd\xe2\f=\xd5g\x9f\xf5\xe3%\x84\\p\u0156&b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa39\xa3\xd8\xca(\x0e'\xd2A[&\xd1\xfcy2(\xb6`C\x896\U00086577\x8f\xf0\x00\x00\u07d4\xa3<\xb4P\xf9[\xb4n%\xaf\xb5\x0f\xe0_\xee\xe6\xfb\x8c\xc8\xea\x89*\x11)\u0413g \x00\x00\u07d4\xa3?p\xdaru\xef\x05q\x04\u07e7\xdbd\xf4r\xe9\xf5\xd5S\x89\x04YF\xb0\xf9\xe9\xd6\x00\x00\u07d4\xa3@v\xf8K\xd9\x17\xf2\x0f\x83B\u024b\xa7\x9eo\xb0\x8e\xcd1\x89\u3bb5sr@\xa0\x00\x00\u07d4\xa3C\x0e\x1fd\u007f2\x1e\xd3G9V##\xc7\xd6#A\vV\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xa3O\x9dV\x8b\xf7\xaf\xd9L*[\x8a_\xf5\\f\xc4\by\x99\x89\x84}P;\"\x0e\xb0\x00\x00\u07d4\xa3V\x06\xd5\x12 \xee\u007f!F\xd4\x11X.\xe4\xeeJEYn\x89\u062a\xbe\b\v\xc9@\x00\x00\u07d4\xa3VU\x1b\xb7}OE\xa6\xd7\xe0\x9f\n\b\x9ey\u0322I\u02c9\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xa3\\\x19\x13,\xac\x195Wj\xbf\xedl\x04\x95\xfb\a\x88\x1b\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3e\x91\x8b\xfe?&'\xb9\xf3\xa8gu\xd8un\x0f\u0629K\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3n\r\x94\xb9Sd\xa8&q\xb6\b\xcb-72Ea)\t\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xa3u\xb4\xbc$\xa2N\x1fyu\x93\xcc0+/3\x10c\xfa\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3v\"\xac\x9b\xbd\xc4\xd8+u\x01]t[\x9f\x8d\xe6Z(\uc25d\xc0\\\xce(\u00b8\x00\x00\xe0\x94\xa3y\xa5\a\fP=/\xac\x89\xb8\xb3\xaf\xa0\x80\xfdE\xedK\xec\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xa3\x80-\x8ae\x9e\x89\xa2\xc4~\x90T0\xb2\xa8'\x97\x89P\xa7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa3\x83\x06\xcbp\xba\xa8\u4446\xbdh\xaap\xa8=$/)\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x84vi\x1d4\x94.\xeak/v\x88\x92#\x04}\xb4az\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x87\xceN\x96\x1axG\xf5`\a\\d\xe1YkVA\xd2\x1c\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xa3\x87\xec\xde\x0e\xe4\xc8\a\x94\x99\xfd\x8e\x03G;\u060a\xd7R*\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\x88:$\xf7\xf1f _\x1aj\x99I\al&\xa7nqx\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xa3\x8b[\xd8\x1a\x9d\xb9\u04b2\x1d^\xc7\xc6\x05R\xcd\x02\xedV\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa3\x90\xca\x12+\x85\x01\xee>^\a\xa8\xcaKA\x9f~M\xae\x15\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x93*1\xd6\xffu\xfb;\x12q\xac\xe7\u02a7\xd5\xe1\xff\x10Q\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa3\x94\xadO\xd9\xe6S\x0eo\\S\xfa\xec\xbe\u0781\xcb\x17-\xa1\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xa3\x97\x9a\x92v\n\x13Z\xdfi\xd7/u\xe1gu_\x1c\xb8\u00c9\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x9b\xfe\xe4\xae\u027du\xbd\"\u01b6r\x89\x8c\xa9\xa1\xe9]2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa3\xa2b\xaf\u0493h\x19#\b\x92\xfd\xe8O-ZYJ\xb2\x83\x89e\xea=\xb7UF`\x00\x00\u07d4\xa3\xa2\xe3\x19\xe7\u04e1D\x8bZ\xa2F\x89S\x16\f-\xbc\xbaq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\xa5{\a\x16\x13(\x04\xd6\n\xac(\x11\x97\xff+=#{\x01\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa3\xa9>\xf9\xdb\xea&6&=\x06\xd8I/jA\u0790|\"\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xa3\xae\x18y\x00}\x80\x1c\xb5\xf3RqjM\u063a'!\xde=\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa3\xba\r:6\x17\xb1\xe3\x1bNB,\xe2i\xe8s\x82\x8d]i\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xa3\xbc\x97\x9bp\x80\t/\xa1\xf9/n\x0f\xb3G\u2359PE\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa3\xbf\xf1\u07e9\x97\x16h6\f\r\x82\x82\x842\xe2{\xf5Ng\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa3\xc1J\xce(\xb1\x92\u02f0b\x14_\u02fdXi\xc6rq\xf6\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa3\xc3:\xfc\x8c\xb4pN#\x15=\xe2\x04\x9d5\xaeq3$r\x89+X\xad\u06c9\xa2X\x00\x00\u07d4\xa3\u0430<\xff\xbb&\x9fyj\u009d\x80\xbf\xb0}\xc7\u01ad\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\u0543\xa7\xb6[#\xf6\vy\x05\xf3\xe4\xaab\xaa\xc8\u007fB'\x898\xbe\xfa\x12mZ\x9f\x80\x00\u07d4\xa3\xdb6J3-\x88K\xa9;&\x17\xaeM\x85\xa1H\x9b\xeaG\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xa3\xe0Q\xfbtJ\xa3A\f;\x88\xf8\x99\xf5\xd5\u007f\x16\x8d\xf1-\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xa3\xe3\xa6\xeaP\x95s\xe2\x1b\xd0#\x9e\xce\x05#\xa7\xb7\u061b/\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\xf4\xad\x14\xe0\xbbD\xe2\xce,\x145\x9cu\xb8\xe72\xd3pT\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3\xfa\xccP\x19\\\vI3\xc8X\x97\xfe\xcc[\xbd\x99\\4\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\x03Z\xb1\xe5\x18\b!\xf0\xf3\x80\xf1\x13\x1bs\x87\xc8\u0641\u0349\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\n\xa2\xbb\xce\fr\xb4\xd0\xdf\xff\xccBq[+T\xb0\x1b\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x19\xa9\x84\x14#c&uuV`\x894\x0e\xea\x0e\xa2\b\x19\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa4!\u06f8\x9b:\aA\x90\x84\xad\x10\xc3\xc1]\xfe\x9b2\xd0\u008a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\"\xe4\xbf\v\xf7AG\u0309[\xed\x8f\x16\xd3\xce\xf3BaT\x89\x12\xef?b\xee\x116\x80\x00\u07d4\xa4%\x9f\x83E\xf7\u3a37+\x0f\xec,\xf7^2\x1f\xdaM\u0089g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xa4)\b\xe7\xfeS\x98\n\x9a\xbf@D\xe9W\xa5Kp\u973e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4)\xfa\x88s\x1f\xdd5\x0e\x8e\xcdn\xa5B\x96\xb6HO\u6549j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\xa40\x99]\xdb\x18[\x98e\xdb\xe6%9\xad\x90\xd2.Ks\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa46\xc7TS\xcc\xcaJ\x1f\x1bb\xe5\u0123\r\x86\xdd\xe4\xbeh\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa47\xfen\xc1\x03\u028d\x15\x8fc\xb34\"N\u032c[>\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4;m\xa6\xcbz\xacW\x1d\xff'\xf0\x9d9\xf8F\xf57i\xb1\x89\x14\x99\x8f2\xacxp\x00\x00\u07d4\xa4;\x81\xf9\x93V\xc0\xaf\x14\x1a\x03\x01\rw\xbd\x04,q\xc1\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4>\x19G\xa9$+5Ua\xc3\n\x82\x9d\xfe\uc881Z\xf8\x89\xd2=\x99\x96\x9f\u0591\x80\x00\u07d4\xa4H\x9aP\xea\xd5\xd5DZ{\xeeM-U6\u00a7lA\xf8\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4O\xe8\x00\xd9o\xca\xd7;qp\xd0\xf6\x10\u02cc\x06\x82\xd6\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa4T2\xa6\xf2\xac\x9dVW{\x93\x8a7\xfa\xba\xc8\xcc|F\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4f\xd7p\u0618\xd8\xc9\xd4\x05\xe4\xa0\xe5Q\xef\xaf\xcd\xe5<\xf9\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\xa4g\a1\x17X\x93\xbb\xcf\xf4\xfa\x85\u0397\xd9O\xc5\x1cK\xa8\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4kC\x87\xfbM\xcc\xe0\x11\xe7nMsT}D\x81\xe0\x9b\xe5\x89Hz\x9a0E9D\x00\x00\u07d4\xa4l\xd27\xb6>\xeaC\x8c\x8e;e\x85\xf6y\xe4\x86\b2\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4wy\u063c\x1c{\xce\x0f\x01\x1c\xcb9\xefh\xb8T\xf8\u078f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4\x82kl8\x82\xfa\xd0\xed\\\x8f\xbb%\xcc@\xccO3u\x9f\x89p\x1bC\xe3D3\xd0\x00\x00\u07d4\xa4\x87Y(E\x8e\xc2\x00]\xbbW\x8c\\\xd35\x80\xf0\xcf\x14R\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x9fR:\xa5\x13d\xcb\xc7\u0655\x16=4\xebY\r\xed/\b\x89\x90'B\x1b*\x9f\xbc\x00\x00\u07d4\xa4\xa4\x9f\v\xc8h\x8c\xc9\xe6\xdc\x04\xe1\xe0\x8dR\x10&\xe6Ut\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4\xa7\xd3\x06\xf5\x10\xcdX5\x94(\xc0\xd2\xf7\xc3`\x9dVt\u05c9\xb5\x8c\xb6\x1c<\xcf4\x00\x00\u07d4\xa4\xa8:\a8y\x9b\x97\x1b\xf2\xdep\x8c.\xbf\x91\x1c\xa7\x9e\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa4\xb0\x9d\xe6\xe7\x13\xdciTnv\xef\n\xcf@\xb9O\x02A\xe6\x89\x11}\xc0b~\xc8p\x00\x00\xe0\x94\xa4\u04b4)\xf1\xadSI\xe3\x17\x04\x96\x9e\xdc_%\xee\x8a\xca\x10\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xa4\xd6\xc8.\u076eYG\xfb\xe9\xcd\xfb\xd5H\xae3\xd9\x1aq\x91\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4\xda4E\r\"\xec\x0f\xfc\xed\xe0\x00K\x02\xf7\x87.\xe0\xb7:\x89\x05\x0fafs\xf0\x83\x00\x00\xe0\x94\xa4\xddY\xab^Q}9\x8eI\xfaS\u007f\x89\x9f\xedL\x15\xe9]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\xe6#E\x1e~\x94\xe7\u86e5\xed\x95\u0228:b\xff\xc4\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\xed\x11\xb0r\u061f\xb16u\x9f\u019bB\x8cH\xaa]L\xed\x89\x0e?\x15'\xa0<\xa8\x00\x00\u07d4\xa4\xfb\x14@\x9ag\xb4V\x88\xa8Y>\\\xc2\xcfYl\xedo\x11\x89a\t=|,m8\x00\x00\xe0\x94\xa5\x14\xd0\x0e\xddq\b\xa6\xbe\x83\x9ac\x8d\xb2AT\x18\x17A\x96\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94\xa5\"\xde~\xb6\xae\x12PR*Q13\xa9;\xd4(IG\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa5$\xa8\xcc\xccIQ\x8d\x17\n2\x82p\xa2\xf8\x813\xfb\xaf]\x89\x0f\xf7\x02-\xac\x10\x8a\x00\x00\u07d4\xa59\xb4\xa4\x01\xb5\x84\xdf\xe0\xf3D\xb1\xb4\"\xc6UC\x16~.\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa5>\xadT\xf7\x85\n\xf2\x148\xcb\xe0z\xf6\x86'\x9a1[\x86\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5C\xa0f\xfb2\xa8f\x8a\xa0sj\f\x9c\xd4\rx\t\x87'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa5gw\vj\xe3 \xbd\xdeP\xf9\x04\xd6c\xe7F\xa6\x1d\xac\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5h\xdbMW\xe4\xd6tb\xd73\u019a\x9e\x0f\xe2n!\x83'\x89;k\xff\x92f\xc0\xae\x00\x00\u07d4\xa5i\x8059\x1eg\xa4\x90\x13\xc0\x00 yY1\x14\xfe\xb3S\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\xa5p\":\xe3\u02a8QA\x8a\x98C\xa1\xacU\xdbH$\xf4\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa5s`\xf0\x02\xe0\xd6M-tE}\x8c\xa4\x85~\xe0\v\xcd\u07c9\x123\xe22\xf6\x18\xaa\x00\x00\u07d4\xa5u\xf2\x89\x1d\xcf\u0368<\\\xf0\x14t\xaf\x11\xee\x01\xb7-\u0089\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\xa5x;\xf342\xff\x82\xacI\x89\x85\xd7\xd4`\xaeg\xec6s\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xa5\x87MuF5\xa7b\xb3\x81\xa5\xc4\u01d2H:\xf8\xf2=\x1d\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa5\xa4\"\u007fl\xf9\x88%\xc0\u057a\xffS\x15u,\xcc\x1a\x13\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5\xabK\xd3X\x8fF\xcb'.V\xe9=\xee\u04c6\xba\x8bu=\x89HB\xf0A\x05\x87,\x80\x00\xe0\x94\xa5\xba\xd8e\t\xfb\xe0\xe0\xe3\xc0\xe9?m8\x1f\x1a\xf6\xe9\u0501\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa5\xc36\b;\x04\xf9G\x1b\x8cn\xd76y\xb7Mf\xc3c\uc263e\nL\x9d \xe2\x00\x00\u07d4\xa5\xcd\x129\x92\x19K4\xc4x\x13\x140;\x03\xc5IH\xf4\xb9\x89l\xfc\xc3\xd9\x1d\xa5c\x00\x00\u07d4\xa5\u0578\xb6-\x00-\xef\x92A7\x10\xd1;o\xf8\xd4\xfc}\u04c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xa5\xd9ni}F5\x8d\x11\x9a\xf7\x81\x9d\xc7\b\u007fj\xe4\u007f\xef\x8a\x03\x17\xbe\xe8\xaf3\x15\xa7\x80\x00\u07d4\xa5\xde^CO\xdc\xddh\x8f\x1c1\xb6\xfbQ,\xb1\x96rG\x01\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xa5\xe0\xfc<:\xff\xed=\xb6q\tG\xd1\xd6\xfb\x01\u007f>'m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9;I\xea|P\x9d\xe7\xc4Ml\xfe\xdd\xefY\x10\u07aa\xf2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9\xcdKt%]\"\xb7\u0672z\xe8\xddC\xedn\xd0%+\x89)\x8d\xb2\xf5D\x11\u0640\x00\xe0\x94\xa5\xf0\a{5\x1flP\\\xd5\x15\u07e6\xd2\xfa\u007f\\L\u0487\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa5\xf0u\xfd@\x135W{f\x83\u0081\xe6\xd1\x01C-\xc6\xe0\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xa5\xfe,\xe9\u007f\x0e\x8c8V\xbe\r\xe5\xf4\u0732\xce]8\x9a\x16\x89\x01=\xb0\xb8\xb6\x86>\x00\x00\u07d4\xa5\xffb\"-\x80\xc0\x13\xce\xc1\xa0\xe8\x85\x0e\xd4\xd3T\xda\xc1m\x89\vA\a\\\x16\x8b\x18\x00\x00\u07d4\xa6\t\xc2m\xd3P\xc25\xe4K+\x9c\x1d\xdd\xcc\u0429\xd9\xf87\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\f\x12\tuO]\x87\xb1\x81\xdaO\b\x17\xa8\x18Y\xef\x9f\u0609\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa6\x10\x1c\x96\x1e\x8e\x1c\x15y\x8f\xfc\xd0\xe3 \x1dw\x86\xec7:\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa6\x13Ei\x96@\x8a\xf1\xc2\xe9>\x17w\x88\xabU\x89^+2\x8a\x01Y\x19\xffG|\x88\xb8\x00\x00\u07d4\xa6\x18\x87\x81\x8f\x91J \xe3\x10w)\v\x83qZk-n\xf9\x89e\xea=\xb7UF`\x00\x00\u07d4\xa6\x1aT\xdfxJD\xd7\x1bw\x1b\x871u\t!\x13\x81\xf2\x00\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\x1c\u06ed\xf0K\x1eT\u0203\xde`\x05\xfc\xdf\x16\xbe\xb8\xeb/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa69\xac\xd9k1\xbaS\xb0\u0407c\"\x9e\x1f\x06\xfd\x10^\x9d\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6BP\x10\x04\xc9\x0e\xa9\xc9\xed\x19\x98\xba\x14\nL\xd6,o_\x89\r\x94\xfb\x8b\x10\xf8\xb1\x80\x00\u07d4\xa6D\xed\x92,\xc27\xa3\xe5\u0117\x9a\x99Tw\xf3nP\xbcb\x89\x1f\xa7=\x84]~\x96\x00\x00\u07d4\xa6F\xa9\\moY\xf1\x04\xc6T\x1dw`uz\xb3\x92\xb0\x8c\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\xa6HL\u0184\xc4\xc9\x1d\xb5>\xb6\x8aM\xa4Zjk\xda0g\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa6N_\xfbpL,\x919\xd7~\xf6\x1d\x8c\u07e3\x1dz\x88\xe9\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xa6T&\xcf\xf3x\xed#%5\x13\xb1\x9fIm\xe4_\xa7\u13ca\x01\x86P\x12|\xc3\u0700\x00\x00\u07d4\xa6jIc\xb2\u007f\x1e\xe1\x93+\x17+\xe5\x96N\r:\xe5KQ\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\xa6\u007f8\x81\x95eB:\xa8_>:\xb6\x1b\xc7c\u02eb\x89\u0749sw\xb0\"\u01be\b\x00\x00\u07d4\xa6\x8c14E\xc2-\x91\x9e\xe4l\xc2\xd0\xcd\xff\x04:uX%\x89\x04\x13t\xfd!\xb0\u0600\x00\u07d4\xa6\x8e\f0\u02e3\xbcZ\x88>T\x03 \xf9\x99\xc7\xcdU\x8e\\\x89a\x9237b\xa5\x8c\x80\x00\u07d4\xa6\x90\xf1\xa4\xb2\n\xb7\xba4b\x86 \u079c\xa0@\xc4<\x19c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa6\x9d|\xd1}HB\xfe\x03\xf6*\x90\xb2\xfb\xf8\xf6\xaf{\xb3\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa6\xa0\x82R\xc8YQw\xcc.`\xfc'Y>#y\xc8\x1f\xb1\x89\x01\x16Q\xac>zu\x80\x00\u07d4\xa6\xa0\xdeB\x1a\xe5Om\x17(\x13\b\xf5dm/9\xf7w]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa6\xb2\xd5s)s`\x10,\a\xa1\x8f\xc2\x1d\xf2\xe7I\x9f\xf4\xeb\x89\xd9o\u0390\u03eb\xcc\x00\x00\xe0\x94\xa6\xc9\x10\xceMIJ\x91\x9c\u036a\xa1\xfc;\x82\xaat\xba\x06\u03ca\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6\u3ea3\x8e\x10J\x1e'\xa4\xd8(i\xaf\xb1\xc0\xaen\xff\x8d\x89\x01\x11@\ueb4bq\x00\x00\u07d4\xa6\xee\xbb\xe4d\u04d1\x87\xbf\x80\u029c\x13\xd7 '\xec[\xa8\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa6\xf6+\x8a=\u007f\x11\"\a\x01\xab\x9f\xff\xfc\xb3'\x95\x9a'\x85\x89\x1bn)\x1f\x18\u06e8\x00\x00\u07d4\xa6\xf93\a\xf8\xbc\xe01\x95\xfe\u0387 C\xe8\xa0?{\xd1\x1a\x89\x9csK\xadQ\x11X\x00\x00\u07d4\xa7\x01\xdfy\xf5\x94\x90\x1a\xfe\x14DH^k \u00fd\xa2\xb9\xb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa7\x02L\xfdt,\x1e\xc1<\x01\xfe\xa1\x8d0B\xe6_\x1d]\xee\x8a\x02c\x11\x9a(\xab\u0430\x80\x00\u07d4\xa7\x18\xaa\xadY\xbf9\\\xba+#\xe0\x9b\x02\xfe\f\x89\x81bG\x8960<\x97\xe4hx\x00\x00\u07d4\xa7$|S\xd0Y\xeb|\x93\x10\xf6(\xd7\xfclj\nw?\b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xa7%7c\xcfJu\u07d2\xca\x1evm\xc4\xee\x8a'E\x14{\x8a\x02F7p\xe9\n\x8fP\x00\x00\u07d4\xa7.\xe6f\u0133^\x82\xa5\x06\x80\x8bD<\xeb\xd5\xc62\xc7\u0749+^:\xf1k\x18\x80\x00\x00\u07d4\xa7DD\xf9\x0f\xbbT\xe5o:\u0276\xcf\u032aH\x19\xe4aJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa7GC\x9a\xd0\u04d3\xb5\xa08a\xd7r\x962m\u8edd\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa7`{BW;\xb6\xf6\xb4\xd4\xf2<~*&\xb3\xa0\xf6\xb6\xf0\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xa7i)\x89\n{G\xfb\x85\x91\x96\x01lo\u0742\x89\u03b7U\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u0794\xa7kt?\x98\x1bi0r\xa11\xb2+\xa5\x10\x96\\/\xef\u05c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa7m?\x15bQ\xb7,\f\xcfKG\xa39<\xbdoI\xa9\u0149Hz\x9a0E9D\x00\x00\u07d4\xa7t(\xbc\xb2\xa0\xdbv\xfc\x8e\xf1\xe2\x0eF\x1a\n2\u016c\x15\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xa7u\x8c\xec\xb6\x0e\x8faL\u0396\x13~\xf7+O\xbd\awJ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7w^J\xf6\xa2:\xfa \x1f\xb7\x8b\x91^Q\xa5\x15\xb7\xa7(\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xa7\u007f>\u1793\x88\xbb\xbb\"\x15\xc6#\x97\xb9e`\x13#`\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa7\x85\x9f\xc0\u007fun\xa7\xdc\xeb\xbc\xcdB\xf0X\x17X-\x97?\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa7\x96lH\x9fLt\x8az\u902a'\xa5t%\x17g\xca\xf9\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa7\xa3\xbba9\xb0\xad\xa0\f\x1f\u007f\x1f\x9fV\u0654\xbaM\x1f\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa7\xa3\xf1S\xcd\u00c8!\xc2\f]\x8c\x82A\xb2\x94\xa3\xf8+$\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7\xa5\x17\u05ed5\x82\v\t\u0517\xfa~U@\xcd\xe9IXS\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa7\xc9\u04c8\xeb\xd8s\xe6k\x17\x13D\x83\x97\xd0\xf3\u007f\x8b\u04e8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa7\u073b\xa9\xb9\xbfgb\xc1EAlPjq\u3d17 \x9c\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa7\xe7O\v\xdb'\x8f\xf0\xa8\x05\xa6Ha\x8e\xc5+\x16o\xf1\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa7\xe87r\xbc \x0f\x90\x06\xaa*&\r\xba\xa8H=\xc5+0\x89\vB\xd56f7\xe5\x00\x00\xe0\x94\xa7\xef5\u0387\xed\xa6\u008d\xf2HxX\x15\x05>\xc9zPE\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xa7\xf9\"\f\x80G\x82k\xd5\xd5\x18?Ngjmw\xbf\xed6\x89\bPh\x97k\xe8\x1c\x00\x00\u07d4\xa8\a\x10O'\x03\xd6y\xf8\u07af\xc4B\xbe\xfe\x84\x9eB\x95\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\f\xb1s\x8b\xac\b\xd4\xf9\xc0\x8bM\xef\xf5\x15T_\xa8XO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa8\x19\xd2\xec\xe1\"\xe0(\xc8\xe8\xa0J\x06M\x02\xb9\x02\x9b\b\xb9\x8965\u026d\xc5\u07a0\x00\x00\u0794\xa8%\xfdZ\xbby&\xa6|\xf3k\xa2F\xa2K\xd2{\xe6\xf6\xed\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4\xa8(U9\x86\x9d\x88\xf8\xa9aS7Uq}~\xb6Uv\xae\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa83\x82\xb6\xe1Rg\x97J\x85P\xb9\x8fqv\xc1\xa3S\xf9\xbe\x89\xbf\xfd\xaf/\xc1\xb1\xa4\x00\x00\xe0\x94\xa8DlG\x81\xa77\xacC(\xb1\xe1[\x8a\v?\xbb\x0f\xd6h\x8a\x04\x87\x94\xd1\xf2F\x19*\x00\x00\u07d4\xa8E[A\x17e\u0590\x1e1\x1erd\x03\t\x1eB\xc5f\x83\x89\xb7:\xec;\xfe\x14P\x00\x00\xe0\x94\xa8f\x13\xe6\u0124\xc9\xc5_\\\x10\xbc\xda2\x17]\u02f4\xaf`\x8a\x02C\xd6\xc2\xe3k\xe6\xae\x00\x00\u07d4\xa8m\xb0}\x9f\x81/G\x96b-@\xe0=\x13Xt\xa8\x8at\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa8\u007fz\xbdo\xa3\x11\x94(\x96x\xef\xb6<\xf5\x84\xee^*a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa8\x80\u2a3f\x88\xa1\xa8&H\xb4\x01W\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\x9d\xf3HY\xed\xd7\xc8 \u06c8w@\xd8\xff\x9e\x15\x15|{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xa4<\x00\x91\x00al\xb4\xaeN\x03?\x1f\xc5\xd7\xe0\xb6\xf1R\x89\u0548\xd0x\xb4?M\x80\x00\u07d4\xa8\xa7\b\xe8O\x82\u06c6\xa3U\x02\x19;Ln\xe9\xa7n\xbe\x8f\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xa8\xa7\xb6\x8a\u06b4\xe3\xea\xdf\xf1\x9f\xfaX\xe3J?\xce\xc0\xd9j\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa8\xa8\xdb\xdd\x1a\x85\u047e\xee%i\xe9\x1c\xccM\t\xae\u007fn\xa1\x8a\x01:k+VHq\xa0\x00\x00\u07d4\xa8\xac\xa7H\xf9\xd3\x12\xect\u007f\x8bex\x14&\x94\xc7\xe9\xf3\x99\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xb6[\xa3\x17\x1a?w\xa65\v\x9d\xaf\x1f\x8dU\xb4\xd2\x01\xeb\x89(b\xf3\xb0\xd2\"\x04\x00\x00\u07d4\xa8\xbe\xb9\x1c+\x99\u0216J\xa9[kJ\x18K\x12i\xfc4\x83\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\xa8\xc0\xb0/\xaf\x02\xcbU\x19\u0768\x84\xde{\xbc\x8c\x88\xa2\u0681\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xa8\xc1\u05aaA\xfe=e\xf6{\xd0\x1d\xe2\xa8f\xed\x1e\u066eR\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xa8\xca\xfa\xc3\"\x80\xd0!\x02\v\xf6\xf2\xa9x(\x83\u05ea\xbe\x12\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa8\xdb\v\x9b \x14S3A<;\fb\xf5\xf5.\u0544\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\xf3\u007f\n\xb3\xa1\xd4H\xa9\xe3\xce@\x96_\x97\xa6F\b:4\x89\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4\xa8\xf8\x9d\xd5\xccnd\u05f1\xee\xac\xe0\a\x02\x02,\xd7\xd2\xf0=\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xa9\x04v\xe2\xef\xdf\xeeO8{\x0f2\xa5\x06x\xb0\xef\xb5s\xb5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\x14PF\xfa6(\xcf_\xd4\xc6\x13\x92{\xe51\xe6\xdb\x1f\u0749\x06\x12O\xee\x99;\xc0\x00\x00\u07d4\xa9\x14\u0375q\xbf\xd9=d\xdaf\xa4\xe1\b\xea\x13NP\xd0\x00\x89M\x878\x99G\x13y\x80\x00\xe0\x94\xa9\x1aZ{4\x1f\x99\xc55\x14N \xbe\x9ck;\xb4\u008eM\x8a\x01&u:\xa2$\xa7\v\x00\x00\u07d4\xa9%%Q\xa6$\xaeQ7\x19\u06beR\a\xfb\xef\xb2\xfdwI\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa9'\u050b\xb6\u02c1K\xc6\t\xcb\u02a9\x15\x1f]E\x9a'\xe1\x89\x0e\xb95\t\x00d\x18\x00\x00\u07d4\xa9)\u023dq\xdb\f0\x8d\xac\x06\b\n\x17G\xf2\x1b\x14e\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa9K\xbb\x82\x14\u03cd\xa0\xc2\xf6h\xa2\xacs\xe8bHR\x8dK\x894\n\xad!\xb3\xb7\x00\x00\x00\u07d4\xa9Q\xb2D\xffP\u03eeY\x1d^\x1a\x14\x8d\xf6\xa98\xef*\x1a\x89^\x00\x15\x84\xdf\xcfX\x00\x00\u07d4\xa9`\xb1\xca\xdd;\\\x1a\x8el\xb3\xab\xca\xf5.\xe7\xc3\xd9\xfa\x88\x89R\x8b\xc3T^Rh\x00\x00\u07d4\xa9a\x17\x1fSB\xb1s\xddp\xe7\xbf\xe5\xb5\xca#\x8b\x13\xbc\u0749\xb8'\x94\xa9$O\f\x80\x00\u07d4\xa9u\xb0w\xfc\xb4\u030e\xfc\xbf\x83\x84Y\xb6\xfa$:AY\u0589\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xa9{\xeb:H\xc4_\x15((L\xb6\xa9_}\xe4S5\x8e\u018a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\xa9~\a!DI\x9f\xe5\xeb\xbd5J\xcc~~\xfbX\x98]\b\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xa9\x86v/zO)O.\v\x172y\xad,\x81\xa2\"4X\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa9\x8f\x10\x985\xf5\xea\xcd\x05Cd|4\xa6\xb2i\xe3\x80/\xac\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa9\x97\xdf\u01d8j'\x05\bH\xfa\x1cd\u05e7\xd6\xe0z\u0322\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa9\x99\x91\u03bd\x98\xd9\xc88\xc2_zt\x16\xd9\xe2D\xca%\r\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa9\xa1\xcd\xc3;\xfd7o\x1c\rv\xfbl\x84\xb6\xb4\xac'Mh\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa9\xa8\xec\xa1\x1a#\xd6F\x89\xa2\xaa>A}\xbb=3k\xb5\x9a\x89\x0e4S\xcd;g\xba\x80\x00\u07d4\xa9\xac\xf6\x00\b\x1b\xb5[\xb6\xbf\xba\xb1\x81_\xfcN\x17\xe8Z\x95\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa9\xad\x19&\xbcf\xbd\xb31X\x8e\xa8\x197\x88SM\x98,\x98\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xa9\xaf!\xac\xbeH/\x811\x89j\"\x806\xbaQ\xb1\x94S\u00c9\x02\xb5\xe0!\x98\f\xc1\x80\x00\xe0\x94\xa9\xb2\xd2\xe0IN\xab\x18\xe0}7\xbb\xb8V\xd8\x0e\x80\xf8L\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\xbaoA;\x82\xfc\xdd\xf3\xaf\xfb\xbd\u0412\x87\xdc\xf5\x04\x15\u0289\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa9\xbe\x88\xad\x1eQ\x8b\v\xbb\x02J\xb1\xd8\xf0\xe7?y\x0e\fv\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa9\xbf\xc4\x10\xdd\xdb q\x1eE\xc0s\x87\xea\xb3\n\x05N\x19\xac\x89>\x99`\x1e\xdfNS\x00\x00\u07d4\xa9\u0522\xbc\xbe[\x9e\bi\xd7\x0f\x0f\xe2\xe1\u05aa\xcdE\xed\u0149\n\xc6\xe7z\xb6c\xa8\x00\x00\xe0\x94\xa9\xd6KO;\xb7\x85\a\"\xb5\x8bG\x8b\xa6\x917^\"NB\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa9\xd6\xf8q\xcax\x1au\x9a \xac:\u06d7,\xf1()\xa2\b\x892$\xf4'#\xd4T\x00\x00\xe0\x94\xa9\xdc\x04$\u0196\x9dy\x83X\xb3\x93\xb1\x93:\x1fQ\xbe\xe0\n\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa9\xe1\x94f\x1a\xacpN\xe9\u07a0C\x97N\x96\x92\xde\xd8J]\x89\x1a&\xa5\x14\"\xa0p\x00\x00\u07d4\xa9\xe2\x837\xe65q\x93\xd9\xe2\xcb#k\x01\xbeD\xb8\x14'\u07c9wC\"\x17\xe6\x83`\x00\x00\u07d4\xa9\xe6\xe2^ekv%Xa\x9f\x14z!\x98[\x88t\xed\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa9\xe9\xdb\xcez,\xb06\x94y\x98\x97\xbe\xd7\xc5M\x15_\u06a8\x89\n\xb5\xae\x8f\u025de\x80\x00\u07d4\xa9\xed7{}n\xc2Yq\xc1\xa5\x97\xa3\xb0\xf3\xbe\xadW\u024f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x02\x00\xf1\xd1~\x9cT\xda\x06G\xbb\x969]W\xa7\x858\u06099>\xf1\xa5\x12|\x80\x00\x00\u07d4\xaa\f\xa3ss7\x17\x8a\f\xaa\xc3\t\x9cXK\x05lV0\x1c\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xaa\x13kG\x96+\xb8\xb4\xfbT\r\xb4\xcc\xf5\xfd\xd0B\xff\xb8\u03c9\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xaa\x14B-o\n\xe5\xa7X\x19N\xd1W\x80\xc88\xd6\u007f\x1e\xe1\x8a\x06\t2\x05lD\x9d\xe8\x00\x00\u07d4\xaa\x16&\x9a\xac\x9c\r\x800h\xd8/\u01d1Q\xda\xdd3Kf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xaa\x16p&\u04da\xb7\xa8V5\x94N\xd9\xed\xb2\xbf\xeb\xa1\x18P\x8a\x01\xc1\xd5\xe2\x1bO\xcfh\x00\x00\u07d4\xaa\x1b7h\xc1m\x82\x1fX\x0ev\xc8\xe4\xc8\xe8m}\u01c8S\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x1d\xf9.Q\xdf\xf7\v\x19s\xe0\xe9$\xc6b\x87\xb4\x94\xa1x\x89\x1c\xf8J0\xa0\xa0\xc0\x00\x00\u07d4\xaa,g\x00\x96\xd3\xf990S%B~\xb9U\xa8\xa6\r\xb3\u0149l\x95Y\x06\x99#-\x00\x00\u07d4\xaa15\xcbT\xf1\x02\xcb\xef\xe0\x9e\x96\x10:\x1ayg\x18\xffT\x89\x03\"\"\xd9\xc31\x94\x00\x00\u07d4\xaa2\x1f\xdb\xd4I\x18\r\xb8\xdd\xd3O\x0f\xe9\x06\xec\x18\xee\t\x14\x89%\"H\u07b6\xe6\x94\x00\x00\xe0\x94\xaa9%\xdc\"\v\xb4\xae!w\xb2\x880x\xb6\xdc4l\xa1\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xaa?)`\x1a\x131t^\x05\xc4(0\xa1^q\x93\x8ab7\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\xaaG\xa4\xff\xc9y622\u025b\x99\xfa\xda\x0f'4\xb0\xae\xee\x8a\x01\xb8H\x9d\xf4\xdb\xff\x94\x00\x00\u07d4\xaaI=?O\xb8fI\x1c\xf8\xf8\x00\xef\xb7\xe22N\xd7\xcf\xe5\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xaaV\xa6]\u012b\xb7/\x11\xba\xe3+o\xbb\aDG\x91\xd5\u0249(\x94\xe9u\xbfIl\x00\x00\xe0\x94\xaaZ\xfc\xfd\x83\t\xc2\u07dd\x15\xbe^jPN}pf$\u014a\x01<\xf4\"\xe3\x05\xa17\x80\x00\u07d4\xaa\x8e\xb0\x82;\a\xb0\xe6\xd2\n\xad\xda\x0e\x95\xcf85\xbe\x19.\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xaa\x91#~t\r%\xa9/\u007f\xa1F\xfa\xa1\x8c\xe5m\xc6\xe1\xf3\x892$\xf4'#\xd4T\x00\x00\u07d4\xaa\x96\x0e\x10\xc5#\x91\xc5N\x158|\xc6z\xf8'\xb51m\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\x9b\xd4X\x955\xdb'\xfa+\xc9\x03\xca\x17\xd6y\xddeH\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xa8\xde\xfe\x11\xe3a?\x11\x06\u007f\xb9\x83bZ\b\x99Z\x8d\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xaa\xe6\x8b2\x14\x02\xc8\xeb\xc14h\xf3A\xc6<\f\xf0?\u0389Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xaa\xad\x1b\xaa\xdeZ\xf0N+\x17C\x9e\x93Y\x87\xbf\x8c+\xb4\xb9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xaa\xb0\n\xbfX(\xd7\xeb\xf2kG\u03ac\u0378\xba\x032Qf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaa\xbd\xb3\\\x15\x14\x98J\x03\x92\x13y?3E\xa1h\xe8\x1f\xf1\x89\x10\xca\u0216\xd29\x00\x00\x00\u07d4\xaa\xca`\xd9\xd7\x00\u7156\xbb\xbb\xb1\xf1\xe2\xf7\x0fF'\xf9\u060965\xbbw\xcbK\x86\x00\x00\u07d4\xaa\xce\u0629V;\x1b\xc3\x11\xdb\xdf\xfc\x1a\xe7\xf5u\x19\xc4D\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\u04b7\xf8\x10f\x95\a\x8el\x13\x8e\xc8\x1at\x86\xaa\xca\x1e\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xe6\x1eC\xcb\r\f\x96\xb3\x06\x99\xf7~\x00\xd7\x11\u0423\x97\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaa\xe72\xed\xa6Y\x88\u00e0\f\u007fG/5\x1cF;\x1c\x96\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xf0#\xfe\U0009091b\xb7\x8b\xb7\xab\xc9]f\x9cP\xd5(\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xaa\xf5\xb2\a\xb8\x8b\r\xe4\xac@\xd7G\xce\xe0n\x17-\xf6\xe7E\x8a\x06\xa7\xb7\x1d\u007fQ\u0410\x00\x00\u07d4\xaa\xf9\xeeK\x88lm\x1e\x95Io\xd2t#[\xf4\xec\xfc\xb0}\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xaa\xfb{\x01:\xa1\xf8T\x1c~2{\xf6P\xad\xbd\x19L \x8f\x89I\x9e\t-\x01\xf4x\x00\x00\xe0\x94\xab\t\x863\xee\xee\f\xce\xfd\xf62\xf9WTV\xf6\u0740\xfc\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xab\f\xedv.\x16a\xfa\xe1\xa9*\xfb\x14\b\x88\x94\x13yH%\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab\x14\xd2!\xe3=TF)\x19\x8c\u0416\xedc\u07e2\x8d\x9fG\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xab \x9f\u0729y\u0426G\x01\n\xf9\xa8\xb5/\xc7\xd2\r\x8c\u044a\x01\xee\xe2S,|-\x04\x00\x00\u07d4\xab'\xbax\xc8\xe5\xe3\xda\xef1\xad\x05\xae\xf0\xff\x03%r\x1e\b\x89\x19^\xce\x00n\x02\xd0\x00\x00\u07d4\xab(q\xe5\a\u01fe9eI\x8e\x8f\xb4b\x02Z\x1a\x1cBd\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xab8a\"o\xfe\xc1(\x91\x87\xfb\x84\xa0\x8e\xc3\xed\x042d\xe8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab=\x86\xbc\x82\x92~\f\xd4!\xd1F\xe0\u007f\x91\x93'\xcd\xf6\xf9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab>b\xe7z\x8b\"^A\x15\x92\xb1\xaf0\aR\xfeA$c\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xab>x)K\xa8\x86\xa0\xcf\xd5\xd3H\u007f\xb3\xa3\a\x8d3\x8dn\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xab@\x04\xc0@?~\xab\xb0\xeaXo!!V\xc4 =g\xf1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xabAo\xe3\rX\xaf\xe5\xd9EL\u007f\xce\u007f\x83\v\xccu\x03V\x89\x0657\x01\xc6\x05\u06c0\x00\u07d4\xabEr\xfb\xb1\xd7+W]i\xecj\xd1s3\x87>\x85R\xfc\x89lj\xc5L\xdahG\x00\x00\u07d4\xabZy\x01av2\ts\xe8\xcd8\xf67U0\x02%1\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab]\xfc\x1e\xa2\x1a\xdcB\u03cc?n6\x1e$?\xd0\xdaa\xe5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xabke\xea\xb8\xdf\xc9\x17\xec\x02Q\xb9\xdb\x0e\u03e0\xfa\x03(I\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xabp\x91\x93.K\u00dd\xbbU#\x80\u0293O\xd7\x16m\x1en\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xabt\x16\xff2%IQ\u02fcbN\xc7\xfbE\xfc~\u02a8r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xab|B\xc5\xe5-d\x1a\a\xadu\t\x9cb\x92\x8b\u007f\x86b/\x89\x126\x1a\xa2\x1d\x14\xba\x00\x00\u07d4\xab}T\xc7\xc6W\x0e\xfc\xa5\xb4\xb8\xcep\xf5*Ws\xe5\xd5;\x89\x0f(:\xbe\x9d\x9f8\x00\x00\u07d4\xab~\v\x83\xed\x9aBLm\x1ejo\x87\xa4\xdb\xf0d\t\xc7\u0589\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xab\x84\xa0\xf1G\xad&T\x00\x00+\x85\x02\x9aA\xfc\x9c\xe5\u007f\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab\x93\xb2n\xce\n\n\xa2\x13e\xaf\xed\x1f\xa9\xae\xa3\x1c\xd5Dh\x89W+{\x98sl \x00\x00\u07d4\xab\x94\x8aJ\xe3y\\\xbc\xa11&\xe1\x92S\xbd\xc2\x1d:\x85\x14\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xab\x9a\xd3n\\t\xce.\x969\x9fW\x83\x941\xd0\u77d6\xab\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xab\xb2\xe6\xa7*@\xban\xd9\b\u037c\xec\x91\xac\xfdwx0\xd1dcG\x8a\xe0\xfcw \x89\a?u\u0460\x85\xba\x00\x00\xe0\x94\xab\u071f\x1b\xcfM\x19\xee\x96Y\x100\xe7r\xc340/}\x83\x8a\b~^\x11\xa8\x1c\xb5\xf8\x00\x00\u07d4\xab\xde\x14{*\xf7\x89\ua946T~f\xc4\xfa&d\xd3(\xa4\x89\rk`\x81\xf3L\x12\x80\x00\xe0\x94\xab\xe0|\xedj\xc5\xdd\xf9\x91\xef\xf6\xc3\xda\"jt\x1b\xd2C\xfe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xab\xf1/\xa1\x9e\x82\xf7lq\x8f\x01\xbd\xca\x00\x03gE#\xef0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xab\xf7(\u03d3\x12\xf2!(\x02NpF\xc2Q\xf5\xdcY\x01\xed\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\xab\xf8\xff\xe0p\x8a\x99\xb5(\xcc\x1e\xd4\xe9\xceK\r\x060\xbe\x8c\x89z\xb5\u00ae\xee\xe68\x00\x00\u07d4\xab\xfc\xf5\xf2P\x91\xceW\x87_\xc6t\xdc\xf1\x04\xe2\xa7=\xd2\xf2\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xab\xfe\x93d%\xdc\u01f7K\x95P\x82\xbb\xaa\xf2\xa1\x1dx\xbc\x05\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xac\x02OYO\x95X\xf0ICa\x8e\xb0\xe6\xb2\xeeP\x1d\xc2r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\x12*\x03\xcd\x05\x8c\x12._\xe1{\x87/Hw\xf9\u07d5r\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xac\x14.\xda\x11W\xb9\xa9\xa6C\x90\xdf~j\xe6\x94\xfa\u0249\x05\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\x1d\xfc\x98Kq\xa1\x99)\xa8\x1d\x81\xf0J|\xbb\x14\a7\x03\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xac!\xc1\xe5\xa3\xd7\xe0\xb5\x06\x81g\x9d\xd6\u01d2\xdb\u0287\xde\u02ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xac(\x89\xb5\x96o\f\u007f\x9e\xdbB\x89\\\xb6\x9d\x1c\x04\xf9#\xa2\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xac(\xb5\xed\xea\x05\xb7o\x8c_\x97\bEA'|\x96ijL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac,\x8e\t\xd0d\x93\xa68XC{\xd2\v\xe0\x19bE\x03e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xac.vm\xac?d\x8fcz\xc6q?\u0770h\xe4\xa4\xf0M\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xac9\x00)\x8d\xd1M|\xc9mJ\xbbB\x8d\xa1\xba\xe2\x13\xff\xed\x8a\x05<\xa1)t\x85\x1c\x01\x00\x00\u07d4\xac=\xa5&\xcf\u0388)s\x02\xf3LI\xcaR\r\xc2q\xf9\xb2\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xacD`\xa7nm\xb2\xb9\xfc\xd1R\xd9\xc7q\x8d\x9a\xc6\xed\x8co\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xacJ\xcf\xc3n\xd6\tJ'\xe1\x18\xec\xc9\x11\xcdG>\x8f\xb9\x1f\x89a\x91>\x14@<\f\x00\x00\u07d4\xacL\xc2V\xaet\xd6$\xac\xe8\r\xb0x\xb2 \u007fW\x19\x8fk\x89lyt\x12?d\xa4\x00\x00\u07d4\xacN\xe9\xd5\x02\xe7\xd2\xd2\xe9\x9eY\xd8\xca}_\x00\xc9KM\u058965\u026d\xc5\u07a0\x00\x00\u07d4\xacR\xb7~\x15fH\x14\xf3\x9eO'\x1b\xe6A0\x8d\x91\xd6\u0309\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4\xacY\x99\xa8\x9d-\u0486\u0568\fm\xee~\x86\xaa\xd4\x0f\x9e\x12\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xac_br1H\r\r\x950.m\x89\xfc2\xcb\x1dO\xe7\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xac`\x8e+\xac\x9d\xd2\a(\u0494~\xff\xbb\xbf\x90\n\x9c\xe9K\x8a\x01EK\r\xb3uh\xfc\x00\x00\u07d4\xacm\x02\xe9\xa4k7\x9f\xacJ\u0271\u05f5\xd4{\xc8P\xce\x16\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xacoh\xe87\xcf\x19a\xcb\x14\xabGDm\xa1h\xa1m\u0789\x89Hz\x9a0E9D\x00\x00\u07d4\xacw\xbd\xf0\x0f\u0558[]\xb1+\xbe\xf8\x008\n\xbc*\x06w\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xac~\x03p'#\xcb\x16\xee'\xe2-\u0438\x15\xdc-\\\xae\x9f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xac\x8bP\x9a\xef\xea\x1d\xbf\xaf+\xb35\x00\xd6W\vo\xd9mQ\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xac\x8e\x87\xdd\xda^x\xfc\xbc\xb9\xfa\u007f\xc3\xce\x03\x8f\x9f}.4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xac\x9f\xffh\xc6\x1b\x01\x1e\xfb\xec\xf08\xedr\u06d7\xbb\x9er\x81\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xac\xa1\xe6\xbcd\xcc1\x80\xf6 \xe9M\u0171\xbc\xfd\x81X\xe4]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xa2\xa883\v\x170-\xa71\xd3\r\xb4\x8a\x04\xf0\xf2\a\xc1\x89Hz\x9a0E9D\x00\x00\u07d4\xac\xaa\xdd\xcb\xf2\x86\xcb\x0e!]\xdaUY\x8f\u007f\xf0\xf4\xad\xa5\u018965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xb9C8UK\u0108\u0308\xae-\x9d\x94\b\rk\u07c4\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xbc-\x19\xe0l;\xab\xbb[o\x05+k\xf7\xfc7\xe0r)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xbd\x18U\x89\xf7\xa6\x8ag\xaaK\x1b\xd6Pw\xf8\xc6NN!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xc0bp,Ya]4D\xefb\x14\xb8\x86+\x00\x9a\x02\xed\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xac\xc0\x90\x9f\xda.\xa6\xb7\xb7\xa8\x8d\xb7\xa0\xaa\xc8h\t\x1d\xdb\xf6\x89\x013v_\x1e&\u01c0\x00\u07d4\xac\xc1\u01c7\x86\xabM+;'q5\xb5\xba\x12>\x04\x00Hk\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xac\xc4j*U\\t\xde\u0522\xbd\tN\x82\x1b\x97\x84;@\xc0\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xac\u015f;0\xce\xff\xc5da\xcc[\x8d\xf4\x89\x02$\x0e\x0e{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xce\x01\xe0\xa7\x06\x10\xdcp\xbb\x91\xe9\x92o\xa9\x95\u007f7/\xba\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\xac\xd8\u0751\xf7\x14vLEg|c\xd8R\xe5n\xb9\xee\xce.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\u2af6;\x06\x04@\x9f\xbd\xe3\xe7\x16\u0487mD\xe8\xe5\u0749\b=lz\xabc`\x00\x00\xe0\x94\xac\xec\x91\xefiA\xcfc\v\xa9\xa3\u71e0\x12\xf4\xa2\xd9\x1d\u050a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xad\nJ\xe4x\xe9cn\x88\xc6\x04\xf2B\xcfT9\xc6\xd4V9\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4\xad\x17\x99\xaa\xd7`+E@\u0343/\x9d\xb5\xf1\x11P\xf1hz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\x1dh\xa08\xfd%\x86\x06~\xf6\xd15\xd9b\x8ey\xc2\xc9$\x89\xfe\t\xa5'\x9e*\xbc\x00\x00\u07d4\xad*\\\x00\xf9#\xaa\xf2\x1a\xb9\xf3\xfb\x06n\xfa\n\x03\xde/\xb2\x8965\xbbw\xcbK\x86\x00\x00\u07d4\xad5e\xd5+h\x8a\xdd\xed\b\x16\x8b-8r\xd1}\n&\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xad7|\xd2^\xb5>\x83\xae\t\x1a\n\x1d+E\x16\xf4\x84\xaf\u0789i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xadAM)\xcb~\xe9s\xfe\xc5N\"\xa3\x88I\x17\x86\xcfT\x02\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xadD5~\x01~$OGi1\u01f8\x18\x9e\xfe\xe8\n]\n\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xadW\xaa\x9d\x00\xd1\fC\x9b5\xef\xcc\v\xec\xac.9U\xc3\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xadY\xa7\x8e\xb9\xa7J\u007f\xbd\xae\xfa\xfa\x82\xea\u0684u\xf0\u007f\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xadZ\x8dV\x01L\xfc\xb3`\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xadr\x81!\x87?\x04V\xd0Q\x8b\x80\xabe\x80\xa2\x03pe\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xads,\x97e\x93\xee\xc4x;N.\xcdy9yx\v\xfe\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xad}\xd0S\x85\x9e\xdf\xf1\xcbo\x9d*\xcb\xedm\xd5\xe32Bo\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xad\x80\xd8e\xb8\\4\xd2\xe6IK.z\xef\xeak\x9a\xf1\x84\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xad\x8b\xfe\xf8\u018aH\x16\xb3\x91o5\xcb{\xfc\xd7\xd3\x04\tv\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xad\x8eH\xa3wi]\xe0\x146:R:(\xb1\xa4\fx\xf2\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xad\x91\n#\u0585\x06\x13eJ\xf7\x863z\u04a7\bh\xacm\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xad\x92~\x03\xd1Y\x9ax\xca+\xf0\xca\u04a1\x83\xdc\xebq\xea\xc0\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xad\x92\xca\x06n\xdb|q\x1d\xfc[\x16a\x92\xd1\xed\xf8\xe7q\x85\x8a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\xad\x94#_\u00f3\xf4z$\x13\xaf1\u8111I\b\xef\fE\x89\x1b\x1b\x01B\xd8\x15\x84\x00\x00\u07d4\xad\x9e\x97\xa0H/5:\x05\xc0\xf7\x92\xb9w\xb6\xc7\xe8\x11\xfa_\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xad\x9fL\x89\n;Q\x1c\xeeQ\xdf\xe6\xcf\xd7\xf1\t;vA,\x89\x1bv|\xbf\xeb\f\xe4\x00\x00\u07d4\xad\xaa\x0eT\x8c\x03Z\xff\xedd\xcag\x8a\x96?\xab\xe9\xa2k\xfd\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xad\xb9H\xb1\xb6\xfe\xfe }\xe6^\x9b\xbc-\xe9\x8e`]\vW\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\xc1\x9e\xc85\xaf\xe3\u5347\u0713\xa8\xa9!<\x90E\x13&\x89j\xdb\xe54\"\x82\x00\x00\x00\u07d4\xad\xc8\"\x8e\xf9(\xe1\x8b*\x80}\x00\xfb1\xfcgX\x15\xaa\x00\x00\u07d4\xad\xff\r\x1d\v\x97G\x1ev\u05c9\xd2\u470at\xf9\xbdT\xff\x89e\xea=\xb7UF`\x00\x00\u07d4\xae\x06,D\x86\x18d0u\xdez\x0004-\xce\xd6=\xba\u05c9,\xc6\u034c\u0082\xb3\x00\x00\xe0\x94\xae\x10\xe2z\x01O\r0k\xaf&mH\x97\u021a\xee\xe2\xe9t\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xae\x12k8,\xf2W\xfa\xd7\xf0\xbc}\x16)~T\xccrg\u0689\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x13\xa0\x85\x11\x11\x0f2\xe5;\xe4\x12xE\xc8C\xa1\xa5|{\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xae\x17\x9aF\r\xb6c&t=$\xe6u#\xa5{$m\xaf\u007f\x8a\x01\x00\a\xae|\xe5\xbb\xe4\x00\x00\u07d4\xae\"(ey\x90y\xaa\xf4\xf0gJ\f\u06ab\x02\xa6\xd5p\xff\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xae#\x9a\xcf\xfdN\xbe.\x1b\xa5\xb4\x17\x05r\xdcy\xcce3\xec\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xae/\x9c\x19\xacv\x13e\x94C#\x93\xb0G\x1d\b\x90!d\u04c9%\xdf\x05\u01a8\x97\xe4\x00\x00\u07d4\xae4\x86\x1d4\"S\x19O\xfcfR\xdf\xdeQ\xabD\xca\xd3\xfe\x89\x19F\bhc\x16\xbd\x80\x00\u07d4\xae6\xf7E!!\x91>\x80\x0e\x0f\xcd\x1ae\xa5G\x1c#\x84o\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xae?\x98\xa4C\xef\xe0\x0f>q\x1dR]\x98\x94\u071aa\x15{\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xaeG\xe2`\x9c\xfa\xfe6\x9df\xd4\x15\xd99\xde\x05\b\x1a\x98r\x8a\x05\xba\xec\xf0%\xf9\xb6P\x00\x00\u07d4\xaeO\x12.5\xc0\xb1\xd1\xe4\x06\x92\x91E|\x83\xc0\u007f\x96_\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaePU\x81L\xb8\xbe\f\x11{\xb8\xb1\xc8\u04b6;F\x98\xb7(\x89\x01\xbc\x93.\xc5s\xa3\x80\x00\u07d4\xaeS\x8cs\u0173\x8d\x8dXM~\xbd\xad\xef\xb1\\\xab\xe4\x83W\x896'\xe8\xf7\x127<\x00\x00\u07d4\xaeW\xcc\x12\x9a\x96\xa8\x99\x81\xda\xc6\r/\xfb\x87}]\xc5\xe42\x89<:#\x94\xb3\x96U\x00\x00\u07d4\xaeZ\xa1\xe6\u00b6\x0fo\xd3\xef\xe7!\xbbJq\x9c\xbe=o]\x89+$\u01b5Z^b\x00\x00\u07d4\xae\\\x9b\xda\xd3\xc5\u0221\"\x04D\xae\xa5\xc2)\xc1\x83\x9f\x1dd\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xae\\\xe35Z{\xa9\xb32v\f\tP\u00bcE\xa8_\xa9\xa0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xae]\"\x1a\xfc\xd3\u0493U\xf5\b\xea\xdf\xca@\x8c\xe3<\xa9\x03\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xaec[\xf781\x11\x9d-)\xc0\xd0O\xf8\xf8\xd8\u0425zF\x89Hz\x9a0E9D\x00\x00\xe0\x94\xaed\x81U\xa6X7\x0f\x92\x9b\xe3\x84\xf7\xe0\x01\x04~I\xddF\x8a\x02\xdf$\xae2\xbe D\x00\x00\xe0\x94\xaeo\fs\xfd\xd7|H\x97'Q!t\u0675\x02\x96a\x1cL\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xaep\xe6\x9d,J\n\xf8\x18\x80{\x1a'\x05\xf7\x9f\u0435\xdb\u01095e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xaew9\x12N\xd1S\x05%\x03\xfc\x10\x14\x10\xd1\xff\xd8\xcd\x13\xb7\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xaex\xbb\x84\x919\xa6\xba8\xae\x92\xa0\x9ai`\x1c\xc4\xcbb\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xae\x84\"\x10\xf4M\x14\u0124\u06d1\xfc\x9d;;P\x01O{\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xae\x84.\x81\x85\x8e\xcf\xed\xf6Plhm\xc2\x04\xac\x15\xbf\x8b$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xae\x89T\xf8\xd6\x16m\xe5\a\xcfa)}\x0f\xc7\xcak\x9eq(\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x9e\xcdk\u0755.\xf4\x97\xc0\x05\n\u0aca\x82\xa9\x18\x98\u0389\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xae\x9f\\?\xbb\xe0\u027c\xbf\x1a\xf8\xfft\xea(\v:]\x8b\b\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xae\xad\x88\u0589Ak\x1c\x91\xf26D!7[}\x82\xd0RR\n\xfb\\Wm\x9f~\xb9>\u048a\r\xd0A \xba\t\xcf\xe6\x00\x00\u07d4\xae\xc2\u007f\xf5\xd7\xf9\xdd\u0691\x18?F\xf9\xd5%C\xb6\xcd+/\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xae\xe4\x9dh\xad\xed\xb0\x81\xfdCpZ_x\xc7x\xfb\x90\xdeH\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xae\xf5\xb1\"X\xa1\x8d\xec\a\xd5\xec.1et\x91\x9dy\xd6\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xae\xfc\xfe\x88\xc8&\xcc\xf11\xd5N\xb4\ua7b8\x0ea\xe1\xee%\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xaf\x06\xf5\xfam\x12\x14\xecC\x96}\x1b\xd4\xdd\xe7J\xb8\x14\xa98\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4\xaf\x11H\xefl\x8e\x10=u0\xef\xc9\x16y\u026c'\x00\t\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaf >\"\x9d~mA\x9d\xf47\x8e\xa9\x87\x15Q_c\x14\x85\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xaf X\xc7(,\xf6|\x8c<\xf90\x13<\x89a|\xe7])\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\xaf&\xf7\u01bfE> x\xf0\x89S\u4c80\x04\xa2\xc1\xe2\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xaf0\x87\xe6.\x04\xbf\x90\rZT\xdc>\x94bt\u0692B;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf6\x14\u0736\x8a6\xe4ZN\x91\x1ebybG\"-Y[\x89z\x81\x06_\x11\x03\xbc\x00\x00\u07d4\xaf6\x15\u01c9\u0431\x15*\xd4\xdb%\xfe]\xcf\"(\x04\xcfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaf<\xb5\x96Y3\xe7\xda\u0603i;\x9c>\x15\xbe\xb6\x8aHs\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xafD\x93\xe8R\x1c\xa8\x9d\x95\xf5&|\x1a\xb6?\x9fEA\x1e\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xafL\xf4\x17\x85\x16\x1fW\x1d\f\xa6\x9c\x94\xf8\x02\x1fA)N\u028a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xafR\x9b\xdbE\x9c\xc1\x85\xbe\xe5\xa1\u014b\xf7\xe8\xcc\xe2\\\x15\r\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xafg\xfd>\x12\u007f\xd9\xdc6\xeb?\xcdj\x80\u01feOu2\xb2\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xafw\x1094Z40\x01\xbc\x0f\x8aY#\xb1&\xb6\rP\x9c\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xaf\u007fy\xcbAZ\x1f\xb8\u06fd\tF\a\xee\x8dA\xfb|Z;\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaf\x87\xd27\x1e\xf3x\x95\u007f\xbd\x05\xba/\x1df\x93\x1b\x01\u2e09%\xf2s\x93=\xb5p\x00\x00\u07d4\xaf\x88\x0f\xc7V}U\x95\xca\xcc\xe1\\?\xc1L\x87B\xc2l\x9e\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xaf\x8e\x1d\xcb1L\x95\r6\x87CM0\x98X\xe1\xa8s\x9c\u0509\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xaf\x99-\xd6i\xc0\x88>U\x15\xd3\xf3\x11*\x13\xf6\x17\xa4\xc3g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xa1\u056d8\xfe\xd4GY\xc0[\x89\x93\xc1\xaa\r\xac\xe1\x9f@\x89\x04V9\x18$O@\x00\x00\xe0\x94\xaf\xa59XnG\x19\x17J;F\xb9\xb3\xe6c\xa7\u0475\xb9\x87\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xa6\x94n\xff\xd5\xffS\x15O\x82\x01\x02S\xdfG\xae(\f\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xaf\xc8\xeb\u860b\xd4\x10Z\xccL\x01\x8eTj\x1e\x8f\x9cx\x88\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xaf\xcc}\xbb\x83V\xd8B\xd4:\xe7\xe2<\x84\"\xb0\"\xa3\b\x03\x8a\x06o\xfc\xbf\xd5\xe5\xa3\x00\x00\x00\u07d4\xaf\xd0\x19\xff6\xa0\x91U4ki\x97H\x15\xa1\xc9\x12\xc9\n\xa4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xda\xc5\xc1\xcbV\xe2E\xbfp3\x00f\xa8\x17\uabecL\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xdd\x1bxab\xb81~ \xf0\xe9y\xf4\xb2\xceHmv]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xf1\x04Z\xdf'\xa1\xaa2\x94a\xb2M\xe1\xba\u950ai\x8b\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\xaf\xf1\a\x96\v~\xc3N\u0590\xb6e\x02M`\x83\x8c\x19\x0fp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xaf\xf1\x1c\xcfi\x93\x04\xd5\xf5\x86*\xf8`\x83E\x1c&\xe7\x9a\xe5\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xaf\xf1at\nm\x90\x9f\xe9\x9cY\xa9\xb7yE\xc9\x1c\xc9\x14H\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xaf\xfc\x99\xd5\ubd28O\xe7x\x8d\x97\xdc\xe2t\xb08$\x048\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xfe\xa0G7\"\xcb\u007f\x0e\x0e\x86\xb9\xe1\x18\x83\xbfB\x8d\x8dT\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xb0\t\x96\xb0Vn\xcb>rC\xb8\"y\x88\u0733R\xc2\x18\x99\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xb0\x1e8\x9b(\xa3\x1d\x8eI\x95\xbd\xd7\xd7\xc8\x1b\xee\xab\x1eA\x19\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0-\x06(s3EE\u03a2\x92\x18\xe4\x05w`Y\x0ft#\x89\xac\xb6\xa1\xc7\xd9:\x88\x00\x00\u07d4\xb0/\xa2\x93\x87\xec\x12\xe3\u007fi\"\xacL\xe9\x8c[\t\xe0\xb0\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb06\x91k\xda\u03d4\xb6\x9eZ\x8ae`)u\xeb\x02a\x04\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb0A1\x0f\xe9\xee\u0586L\xed\u053e\xe5\x8d\xf8\x8e\xb4\xed<\xac\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb0U\xafL\xad\xfc\xfd\xb4%\xcfe\xbad1\a\x8f\a\xec\u056b\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0W\x11S\xdb\x1cN\u05ec\xae\xfe\x13\xec\xdf\xdbr\xe7\xe4\xf0j\x8a\x11\f\xffyj\xc1\x95 \x00\x00\u07d4\xb0n\xab\t\xa6\x10\u01a5=V\xa9F\xb2\xc44\x87\xac\x1d[-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0rI\xe0U\x04J\x91U5\x9a@)7\xbb\xd9T\xfeH\xb6\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0v\x182\x8a\x90\x13\a\xa1\xb7\xa0\xd0X\xfc\xd5xn\x9er\xfe\x8a\x06gI]JC0\xce\x00\x00\u07d4\xb0y\xbbM\x98f\x14:m\xa7*\xe7\xac\x00\"\x06)\x811\\\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4\xb0{\xcc\bZ\xb3\xf7)\xf2D\x00Ah7\xb6\x996\xba\x88s\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xb0{\xcf\x1c\xc5\xd4F.Q$\xc9e\xec\xf0\xd7\r\xc2z\xcau\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xb0|\xb9\xc1$\x05\xb7\x11\x80uC\u0113De\xf8\u007f\x98\xbd-\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb0\u007f\u07af\xf9\x1dD`\xfel\xd0\u8870\xbd\x8d\"\xa6.\x87\x8a\x01\x1d%)\xf3SZ\xb0\x00\x00\xe0\x94\xb0\x9f\xe6\xd44\x9b\x99\xbc7\x93\x80T\x02-T\xfc\xa3f\xf7\xaf\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\xb0\xaa\x00\x95\f\x0e\x81\xfa2\x10\x17>r\x9a\xaf\x16:'\xcdq\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb0\xacN\xfff\x80\xee\x14\x16\x9c\xda\xdb\xff\xdb0\x80Om%\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb0\xb3j\xf9\xae\xee\u07d7\xb6\xb0\"\x80\xf1\x14\xf19\x84\xea2`\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xb0\xb7y\xb9K\xfa<.\x1fX{\u031c~!x\x92\"7\x8f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xb0\xba\xeb0\xe3\x13wlLm$t\x02\xbaAg\xaf\u0361\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb0\xbb)\xa8a\xea\x1dBME\xac\u053f\u0112\xfb\x8e\xd8\t\xb7\x89\x04V9\x18$O@\x00\x00\xe0\x94\xb0\xc1\xb1w\xa2 \xe4\x1f|t\xd0|\u0785i\xc2\x1cu\xc2\xf9\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xb0\xc7\xceL\r\xc3\u00bb\xb9\x9c\xc1\x85{\x8aE_a\x17\x11\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb0\xce\xf8\xe8\xfb\x89\x84\xa6\x01\x9f\x01\xc6y\xf2r\xbb\xe6\x8f\\w\x89\b=lz\xabc`\x00\x00\xe0\x94\xb0\xd3+\xd7\xe4\u6577\xb0\x1a\xa3\xd0Ao\x80U}\xba\x99\x03\x8a\x03s\x9f\xf0\xf6\xe6\x130\x00\x00\xe0\x94\xb0\xd3\u0247+\x85\x05n\xa0\xc0\xe6\xd1\xec\xf7\xa7~<\u6ac5\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xb0\xe4i\u0206Y8\x15\xb3IV8Y]\xae\xf0f_\xaeb\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xb0\xe7`\xbb\a\xc0\x81wsE\xe0W\x8e\x8b\u0218\"mN;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\x040\x04\xec\x19A\xa8\xcfO+\x00\xb1W\x00\u076co\xf1~\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\x05\xdd=\x98|\xff\xd8\x13\xe9\xc8P\n\x80\xa1\xad%}V\u0189lj\xccg\u05f1\xd4\x00\x00\u07d4\xb1\x0f\u04a6G\x10/\x88\x1ft\xc9\xfb\xc3}\xa62\x94\x9f#u\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb1\x15\xee:\xb7d\x1e\x1a\xa6\xd0\x00\xe4\x1b\xfc\x1e\xc7!\f/2\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xb1\x17\x8a\xd4s\x83\xc3\x1c\x814\xa1\x94\x1c\xbc\xd4t\xd0bD\xe2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb1\x17\x95\x89\u1779\xd4\x15W\xbb\xec\x1c\xb2L\xcc-\xec\x1c\u007f\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb1\x19\u76a9\xb9\x16Re\x81\xcb\xf5!\xefGJ\xe8M\xcf\xf4\x89O\xba\x10\x01\xe5\xbe\xfe\x00\x00\u07d4\xb1\x1f\xa7\xfb'\n\xbc\xdfZ.\xab\x95\xaa0\u013566\uffc9+^:\xf1k\x18\x80\x00\x00\u07d4\xb1$\xbc\xb6\xff\xa40\xfc\xae.\x86\xb4_'\xe3\xf2\x1e\x81\xee\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1)\xa5\xcbq\x05\xfe\x81\v\u0615\xdcr\x06\xa9\x91\xa4TT\x88\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\xb1.\xd0{\x8a8\xadU\x066?\xc0z\vmy\x996\xbd\xaf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb14\xc0\x049\x1a\xb4\x99(x3zQ\xec$/B(WB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1?\x93\xaf0\xe8\xd7fs\x81\xb2\xb9[\xc1\xa6\x99\xd5\xe3\xe1)\x89\x16\u012b\xbe\xbe\xa0\x10\x00\x00\u07d4\xb1E\x92\x85\x86>\xa2\xdb7Y\xe5F\u03b3\xfb7a\xf5\x90\x9c\x89<\xd7*\x89@\x87\xe0\x80\x00\u07d4\xb1F\xa0\xb9%U<\xf0o\xca\xf5J\x1bM\xfe\xa6!)\aW\x89lnY\xe6|xT\x00\x00\xe0\x94\xb1Jz\xaa\x8fI\xf2\xfb\x9a\x81\x02\u05bb\xe4\u010a\xe7\xc0o\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1K\xbe\xffpr\tu\xdca\x91\xb2\xa4O\xf4\x9f&r\x87<\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xb1L\xc8\xde3\xd63\x826S\x9aH\x90 \xceFU\xa3+\u018a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1M\xdb\x03\x86\xfb`c\x98\xb8\xccGVZ\xfa\xe0\x0f\xf1\xd6j\x89\xa1*\xff\b>f\xf0\x00\x00\u07d4\xb1S\xf8(\xdd\amJ|\x1c%t\xbb-\xee\x1aD\xa3\x18\xa8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1T\x0e\x94\xcf\xf3F\\\xc3\u0447\xe7\xc8\u3f6f\x98FY\u2262\x15\xe4C\x90\xe33\x00\x00\u07d4\xb1X\xdbC\xfab\xd3\x0ee\xf3\u041b\xf7\x81\u01f6sr\uba89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1ar_\xdc\xed\xd1yR\xd5{#\xef([~K\x11i\xe8\x89\x02\xb6\xdf\xed6d\x95\x80\x00\u07d4\xb1dy\xba\x8e}\xf8\xf6>\x1b\x95\xd1I\u0345)\xd75\xc2\u0689-\xe3:j\xac2T\x80\x00\u07d4\xb1f\xe3}.P\x1a\xe7<\x84\x14+_\xfbZ\xa6U\xddZ\x99\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1\x83\xeb\xeeO\xcbB\xc2 \xe4wt\xf5\x9dlT\xd5\xe3*\xb1\x89V\xf7\xa9\xc3<\x04\xd1\x00\x00\u07d4\xb1\x88\a\x84D\x02~8g\x98\xa8\xaehi\x89\x19\xd5\xcc#\r\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xb1\x89j7\xe5\u0602Z-\x01vZ\xe5\xdeb\x99w\u0783R\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb1\x8eg\xa5\x05\n\x1d\xc9\xfb\x19\t\x19\xa3=\xa88\xefDP\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb1\xa2\xb4:t3\xdd\x15\v\xb8\"'\xedQ\x9c\u05b1B\u04c2\x89\x94mb\rtK\x88\x00\x00\u07d4\xb1\xc0\u040b6\xe1\x84\xf9\x95*@7\xe3\xe5:f}\a\nN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\xc3(\xfb\x98\xf2\xf1\x9a\xb6do\n|\x8cVo\xdaZ\x85@\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\xb1\xc7Qxi9\xbb\xa0\xd6q\xa6w\xa1X\u01ab\xe7&^F\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xb1\xcdK\xdf\xd1\x04H\x9a\x02n\u025dYs\a\xa0By\xf1s\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb1\u03d4\xf8\t\x15\x05\x05_\x01\n\xb4\xba\u0196\xe0\xca\x0fg\xa1\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xb1\u05b0\x1b\x94\xd8T\xfe\x8b7J\xa6^\x89\\\xf2*\xa2V\x0e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\xb1\u06e5%\v\xa9bWU$n\x06yg\xf2\xad/\a\x91\u078a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xb1\xe2\u0755\xe3\x9a\xe9w\\U\xae\xb1?\x12\xc2\xfa#0S\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\xe6\xe8\x10\xc2J\xb0H\x8d\xe9\xe0\x1eWH7\x82\x9f|w\u0409\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1\xe9\xc5\xf1\xd2\x1eauzk.\xe7Y\x13\xfcZ\x1aA\x01\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\x03\u049elV\xb9&\x99\u0139-\x1fo\x84d\x8d\xc4\u03fc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x16\xdcY\xe2|=ry\xf5\xcd[\xb2\xbe\u03f2`n\x14\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x1byy\xbf|\\\xa0\x1f\xa8-\xd6@\xb4\x1c9\xe6\u01bcu\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb2#\xbf\x1f\xbf\x80H\\\xa2\xb5V}\x98\xdb{\xc3SM\xd6i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2-PU\xd9b15\x96\x1ej\xbd'<\x90\xde\xea\x16\xa3\xe7\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb2-\xad\xd7\xe1\xe0R2\xa927\xba\xed\x98\xe0\u07d2\xb1\x86\x9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb24\x03_uDF<\xe1\xe2+\xc5S\x06F\x84\xc5\x13\xcdQ\x89\r\x89\xfa=\u010d\xcf\x00\x00\u07d4\xb2G\u03dcr\xecH*\xf3\xea\xa7Ye\x8fy=g\nW\f\x891p\x8a\xe0\x04T@\x00\x00\u07d4\xb2ghA\xee\x9f-1\xc1r\xe8#\x03\xb0\xfe\x9b\xbf\x9f\x1e\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb2y\xc7\xd3U\u0088\x03\x92\xaa\u046a!\xee\x86|;5\a\u07c9D[\xe3\xf2\uf1d4\x00\x00\u07d4\xb2|\x1a$ L\x1e\x11\x8du\x14\x9d\xd1\t1\x1e\a\xc0s\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb2\x81\x81\xa4X\xa4@\xf1\u01bb\x1d\xe8@\x02\x81\xa3\x14\x8fL5\x89\x14b\fW\xdd\xda\xe0\x00\x00\xe0\x94\xb2\x82E\x03|\xb1\x92\xf7W\x85\u02c6\xcb\xfe|\x93\r\xa2X\xb0\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xb2\x87\xf7\xf8\xd8\u00c7,\x1bXk\xcd}\n\xed\xbf~s'2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb2\x8b\xb3\x9f4fQ|\xd4o\x97\x9c\xf5\x96S\xee}\x8f\x15.\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xb2\x8d\xbf\xc6I\x98\x94\xf7:q\xfa\xa0\n\xbe\x0fK\xc9\u045f*\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\x96\x8f}5\xf2\b\x87\x161\xc6h{?=\xae\xab\xc6al\x89\bu\xc4\u007f(\x9fv\x00\x00\u07d4\xb2\x9f[|\x190\xd9\xf9z\x11^\x06pf\xf0\xb5M\xb4K;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb2\xa1D\xb1\xeag\xb9Q\x0f\"g\xf9\xda9\xd3\xf9=\xe2fB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xa2\xc2\x11\x16\x12\xfb\x8b\xbb\x8e}\xd97\x8dg\xf1\xa3\x84\xf0P\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb2\xa4\x98\xf0;\xd7\x17\x8b\u0627\x89\xa0\x0fR7\xafy\xa3\xe3\xf8\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\xb2\xaa/\x1f\x8e\x93\xe7\x97\x13\xd9,\xea\x9f\xfc\xe9\xa4\n\xf9\xc8-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xb5\x16\xfd\u045e\u007f8d\xb6\xd2\xcf\x1b%*AV\xf1\xb0;\x89\x02\xe9\x83\xc7a\x15\xfc\x00\x00\u07d4\xb2\xb7\u0374\xffKa\u0577\xce\v\"p\xbb\xb5&\x97C\xec\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xbd\xbe\u07d5\x90\x84v\xd7\x14\x8a7\f\u0193t6(\x05\u007f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2\xbf\xaaX\xb5\x19l\\\xb7\xf8\x9d\xe1_G\x9d\x188\xdeq=\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xb2\xc5>\xfa3\xfeJ:\x1a\x80 \\s\xec;\x1d\xbc\xad\x06\x02\x89h\x01\u06b3Y\x18\x93\x80\x00\xe0\x94\xb2\xd06\x05\x15\xf1}\xab\xa9\x0f\u02ec\x82\x05\xd5i\xb9\x15\u05ac\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xb2\xd1\xe9\x9a\xf9\x121\x85\x8epe\xdd\x19\x183\r\xc4\xc7G\u054a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xb2\u066b\x96d\xbc\xf6\xdf <4o\u0192\xfd\x9c\xba\xb9 ^\x89\x17\xbex\x97`e\x18\x00\x00\u07d4\xb2\u0777\x86\xd3yN'\x01\x87\xd0E\x1a\xd6\u0237\x9e\x0e\x87E\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\xe0\x85\xfd\xdd\x14h\xba\aA['NsN\x11#\u007f\xb2\xa9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\xe9\xd7k\xf5\x0f\xc3k\xf7\u04d4Kc\xe9\u0288\x9bi\x99h\x89\x902\xeab\xb7K\x10\x00\x00\xe0\x94\xb2\xf9\xc9r\xc1\xe9swU\xb3\xff\x1b0\x88s\x83\x969[&\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xb2\xfc\x84\xa3\xe5\nP\xaf\x02\xf9M\xa08>\u055fq\xff\x01\u05ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xb3\x05\v\xef\xf9\xde3\xc8\x0e\x1f\xa1R%\xe2\x8f,A:\xe3\x13\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xb3\x11\x96qJH\xdf\xf7&\xea\x943\xcd)\x12\xf1\xa4\x14\xb3\xb3\x89\x91Hx\xa8\xc0^\xe0\x00\x00\xe0\x94\xb3\x14[tPm\x1a\x8d\x04|\xdc\xdcU9*{SPy\x9a\x8a\x1bb)t\x1c\r=]\x80\x00\u07d4\xb3 \x83H6\xd1\xdb\xfd\xa9\xe7\xa3\x18M\x1a\xd1\xfdC \xcc\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3#\u073f.\xdd\xc58.\u4efb \x1c\xa3\x93\x1b\xe8\xb48\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb3$\x00\xfd\x13\xc5P\t\x17\xcb\x03{)\xfe\"\xe7\xd5\"\x8f-\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb3%gL\x01\xe3\xf7)\rR&3\x9f\xbe\xacg\xd2!'\x9f\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xb3(%\xd5\xf3\xdb$\x9e\xf4\xe8\\\xc4\xf31S\x95\x89v\u8f09\x1b-\xf9\xd2\x19\xf5y\x80\x00\u07d4\xb3*\xf3\xd3\xe8\xd0u4I&To.2\x88{\xf9;\x16\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3/\x1c&\x89\xa5\xcey\xf1\xbc\x97\v1XO\x1b\xcf\"\x83\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3<\x03#\xfb\xf9\xc2l\x1d\x8a\xc4N\xf7C\x91\u0400F\x96\u0689\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb3O\x04\xb8\xdbe\xbb\xa9\xc2n\xfcL\xe6\xef\xc5\x04\x81\xf3\xd6]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3U}9\xb5A\x1b\x84D__T\xf3\x8fb\xd2qM\x00\x87\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xb3X\xe9|p\xb6\x05\xb1\xd7\xd7)\u07f6@\xb4<^\xaf\xd1\xe7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xb3^\x8a\x1c\r\xac~\x0ef\u06ecsjY*\xbdD\x01%a\x88\xcf\xceU\xaa\x12\xb3\x00\x00\xe0\x94\xb3fx\x94\xb7\x86<\x06\x8a\xd3D\x87?\xcf\xf4\xb5g\x1e\x06\x89\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3qw1\xda\xd6Q2\xday-\x87`0\xe4j\xc2'\xbb\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3s\x1b\x04l\x8a\u0195\xa1'\xfdy\u0425\xd5\xfaj\xe6\xd1.\x89lO\xd1\xee$nx\x00\x00\u07d4\xb3|+\x9fPc{\xec\xe0\u0295\x92\b\xae\xfe\xe6F;\xa7 \x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb3\x88\xb5\xdf\xec\xd2\xc5\u4d56W|d%V\xdb\xfe'xU\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3\x8cNS{]\xf90\xd6Zt\xd0C\x83\x1dkH[\xbd\xe4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb3\x919Wa\x94\xa0\x86a\x95\x15\x1f3\xf2\x14\n\xd1\u0306\u03ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb3\x9fL\x00\xb2c\f\xab}\xb7)^\xf4=G\xd5\x01\xe1\u007f\u05c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb3\xa6K\x11vrOT\t\xe1AJ5#f\x1b\xae\xe7KJ\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xb3\xa6\xbdA\xf9\xd9\xc3 \x1e\x05\v\x87\x19\x8f\xbd\xa3\x994\"\x10\x89\xc4a\xe1\xdd\x10)\xb5\x80\x00\u07d4\xb3\xa8\xc2\xcb}5\x8eW9\x94\x1d\x94[\xa9\x04Z\x02:\x8b\xbb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xaeT\xfb\xa0\x9d>\xe1\u05bd\xd1\xe9W\x929\x19\x02L5\xfa\x89\x03\x8d,\xeee\xb2*\x80\x00\u07d4\xb3\xb7\xf4\x93\xb4J,\x8d\x80\xecx\xb1\xcd\xc7Ze+s\xb0l\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb3\xc2(s\x1d\x18m-\xed[_\xbe\x00Lfl\x8eF\x9b\x86\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4\xb3\xc2``\x9b\x9d\xf4\t^l]\xff9\x8e\xeb^-\xf4\x99\x85\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xb3\xc6[\x84Z\xbal\xd8\x16\xfb\xaa\xe9\x83\xe0\xe4l\x82\xaa\x86\"\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xc9H\x11\xe7\x17[\x14\x8b(\x1c\x1a\x84[\xfc\x9b\xb6\xfb\xc1\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3\xe2\x0e\xb4\xde\x18\xbd\x06\x02!h\x98\x94\xbe\u5bb2SQ\xee\x89\x03\xfc\x80\xcc\xe5\x16Y\x80\x00\u07d4\xb3\xe3\xc49\x06\x98\x80\x15f\x00\u0089.D\x8dA6\xc9-\x9b\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xb3\xf8*\x87\xe5\x9a9\xd0\u0480\x8f\aQ\xebr\xc22\x9c\xdc\u014a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb3\xfc\x1dh\x81\xab\xfc\xb8\xbe\xcc\v\xb0!\xb8\xb7;r3\u0751\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xb4\x05\x94\xc4\xf3fN\xf8I\u0326\"{\x8a%\xaai\t%\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb4\x1e\xaf]Q\xa5\xba\x1b\xa3\x9b\xb4\x18\u06f5O\xabu\x0e\xfb\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4$\u058d\x9d\r\x00\xce\xc1\x93\x8c\x85N\x15\xff\xb8\x80\xba\x01p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4%bs\x96+\xf61\xd0\x14U\\\xc1\xda\r\xcc1akI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb40g\xfep\u0675Ys\xbaX\xdcd\xdd\u007f1\x1eUBY\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb46W\xa5\x0e\xec\xbc0w\xe0\x05\xd8\xf8\xd9O7xv\xba\u0509\x01\xec\x1b:\x1f\xf7Z\x00\x00\u07d4\xb4<'\xf7\xa0\xa1\"\bK\x98\xf4\x83\x92%A\u0203l\xee,\x89&\u009eG\u0104L\x00\x00\xe0\x94\xb4A5v\x86\x9c\b\xf9Q*\xd3\x11\xfe\x92Y\x88\xa5-4\x14\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb4F\x05U$q\xa6\xee\xe4\u06abq\xff;\xb4\x13&\xd4s\xe0\x89-~=Q\xbaS\xd0\x00\x00\u07d4\xb4GW\x1d\xac\xbb>\u02f6\xd1\xcf\v\f\x8f88\xe5#$\xe2\x89\x01\xa3\x18f\u007f\xb4\x05\x80\x00\u07d4\xb4G\x83\xc8\xe5{H\a\x93\xcb\u059aE\xd9\f{O\fH\xac\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb4H\x15\xa0\xf2\x8eV\x9d\x0e\x92\x1aJ\u078f\xb2d%&Iz\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4\xb4Im\xdb'y\x9a\"$W\xd79y\x11g(\u8844[\x89\x8d\x81\x9e\xa6_\xa6/\x80\x00\xe0\x94\xb4RL\x95\xa7\x86\x0e!\x84\x02\x96\xa6\x16$@\x19B\x1cJ\xba\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb4\\\xca\r6\x82fbh<\xf7\u0432\xfd\xach\u007f\x02\xd0\u010965\u026d\xc5\u07a0\x00\x00\u0794\xb4d@\u01d7\xa5V\xe0L}\x91\x04f\x04\x91\xf9k\xb0v\xbf\x88\xce\xc7o\x0eqR\x00\x00\u07d4\xb4j\u0386^,P\xeaF\x98\xd2\x16\xabE]\xffZ\x11\xcdr\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4m\x11\x82\xe5\xaa\xca\xff\r&\xb2\xfc\xf7/<\x9f\xfb\xcd\xd9}\x89\xaa*`<\xdd\u007f,\x00\x00\u07d4\xb4\x89!\xc9h}U\x10tE\x84\x93n\x88\x86\xbd\xbf-\xf6\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\x98\xbb\x0fR\x00\x05\xb6!jD%\xb7Z\xa9\xad\xc5-b+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb4\xb1\x1d\x10\x9f`\x8f\xa8\xed\xd3\xfe\xa9\xf8\xc3\x15d\x9a\xeb=\x11\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb4\xb1K\xf4TU\u042b\b\x035\x8bu$\xa7+\xe1\xa2\x04[\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb4\xb1\x85\xd9C\xee+Xc\x1e3\xdf\xf5\xafhT\xc1y\x93\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xbf$\u02c3hk\xc4i\x86\x9f\xef\xb0D\xb9\tqi\x93\xe2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb4\xc2\x00@\xcc\u0661\xa3(=\xa4\u0522\xf3e\x82\bC\xd7\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xc8\x17\x0f{*\xb56\xd1\u0662[\xdd :\xe1(\x8d\xc3\u0549\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4\xd8/.i\x94?}\xe0\xf5\xf7t8y@o\xac.\x9c\xec\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb4\xddF\f\xd0\x16rZd\xb2.\xa4\xf8\xe0n\x06gN\x03>\x8a\x01#\x1b\xb8t\x85G\xa8\x00\x00\u07d4\xb4\xddT\x99\xda\xeb%\a\xfb-\xe1\"\x97s\x1dLr\xb1k\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb5\x04l\xb3\xdc\x1d\xed\xbd6E\x14\xa2\x84\x8eD\xc1\xdeN\xd1G\x8a\x03{}\x9b\xb8 @^\x00\x00\xe0\x94\xb5\b\xf9\x87\xb2\xde4\xaeL\xf1\x93\u0785\xbf\xf6\x13\x89b\x1f\x88\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb5\tU\xaan4\x15q\x98f\b\xbd\u0211\xc2\x13\x9fT\f\u07c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5\f\x14\x9a\x19\x06\xfa\xd2xo\xfb\x13Z\xabP\x177\xe9\xe5o\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\xb5\f\x9fW\x89\xaeD\xe2\xdc\xe0\x17\xc7\x14\xca\xf0\f\x83\x00\x84\u0089\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xb5\x14\x88,\x97\x9b\xb6B\xa8\r\u04c7T\u0578\xc8)m\x9a\a\x893\xc5I\x901r\f\x00\x00\u07d4\xb5\x1d\u0734\xddN\x8a\xe6\xbe3m\xd9eIq\xd9\xfe\xc8kA\x89\x16\xd4d\xf8=\u2500\x00\u07d4\xb5\x1eU\x8e\xb5Q/\xbc\xfa\x81\xf8\u043d\x93\x8cy\xeb\xb5$+\x89&\u009eG\u0104L\x00\x00\u07d4\xb5#\xff\xf9t\x98q\xb3S\x88C\x887\xf7\xe6\xe0\u07a9\xcbk\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb5-\xfbE\xde]t\xe3\xdf \x832\xbcW\x1c\x80\x9b\x8d\xcf2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb55\xf8\u06c7\x9f\xc6\u007f\xecX\x82J\\\xbenT\x98\xab\xa6\x92\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xb57\xd3jp\xee\xb8\xd3\xe5\xc8\r\xe8\x15\"\\\x11X\u02d2\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xb5;\xcb\x17L%\x184\x8b\x81\x8a\xec\xe0 6E\x96Fk\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5I>\xf1srDE\xcf4\\\x03]'\x9b\xa7Y\xf2\x8dQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb5S\xd2]kT!\xe8\x1c*\xd0^\v\x8b\xa7Q\xf8\xf0\x10\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5Tt\xbaX\xf0\xf2\xf4\x0el\xba\xbe\xd4\xea\x17n\x01\x1f\xca\u0589j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5U\xd0\x0f\x91\x90\xcc6w\xae\xf3\x14\xac\xd7?\xdc99\x92Y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5W\xab\x949\xefP\xd27\xb5S\xf0%\b6JFj\\\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5jx\x00(\x03\x9c\x81\xca\xf3{gu\xc6 \u7195Gd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5j\u04ae\xc6\xc8\xc3\xf1\x9e\x15\x15\xbb\xb7\u0751(RV\xb69\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5t\x13\x06\n\xf3\xf1N\xb4y\x06_\x1e\x9d\x19\xb3uz\xe8\u0309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xb5uI\xbf\xbc\x9b\xdd\x18\xf76\xb2&P\xe4\x8as`\x1f\xa6\\\x89\x18-~L\xfd\xa08\x00\x00\xe0\x94\xb5w\xb6\xbe\xfa\x05N\x9c\x04\x04a\x85P\x94\xb0\x02\xd7\xf5{\u05ca\x18#\xf3\xcfb\x1d#@\x00\x00\u07d4\xb5{\x04\xfa#\xd1 ?\xae\x06\x1e\xacEB\xcb`\xf3\xa5v7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xb5\x87\f\xe3B\xd43C36s\x03\x8bGd\xa4n\x92_>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\x87\xb4J,\xa7\x9eK\xc1\u074b\xfd\xd4: qP\xf2\xe7\xe0\x89\",\x8e\xb3\xfff@\x00\x00\u07d4\xb5\x89gm\x15\xa0DH4B0\xd4\xff'\xc9^\xdf\x12,I\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb5\x8bR\x86^\xa5]\x806\xf2\xfa\xb2`\x98\xb3R\u0283~\x18\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xb5\x90k\n\u9881X\xe8\xacU\x0e9\xda\bn\xe3\x15v#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xa4g\x96\x85\xfa\x14\x19l.\x920\xc8\xc4\xe3;\xff\xbc\x10\xe2\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb5\xa5\x89\u075f@q\u06f6\xfb\xa8\x9b?]]\xae}\x96\xc1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xa6\x06\xf4\xdd\u02f9G\x1e\xc6\u007fe\x8c\xaf+\x00\xees\x02^\x89\xeaun\xa9*\xfct\x00\x00\u07d4\xb5\xadQW\u0769!\xe6\xba\xfa\u0350\x86\xaes\xae\x1fa\x1d?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xad\xd1\u701f}\x03\x06\x9b\xfe\x88;\n\x93\"\x10\xbe\x87\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\xba)\x91|x\xa1\xd9\xe5\xc5\xc7\x13fl\x1eA\x1d\u007fi:\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb5\xc8\x16\xa8(<\xa4\xdfh\xa1\xa7=c\xbd\x80&\x04\x88\xdf\b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xca\xc5\xed\x03G}9\v\xb2g\xd4\xeb\xd4a\x01\xfb\xc2\xc3\u0689\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xb5\u037cA\x15@oR\u5a85\xd0\xfe\xa1p\u0497\x9c\u01fa\x89Hz\x9a0E9D\x00\x00\u0794\xb5\u0653M{)+\xcf`;(\x80t\x1e\xb7`(\x83\x83\xa0\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xb5\xddP\xa1]\xa3Ih\x89\nS\xb4\xf1?\xe1\xaf\b\x1b\xaa\xaa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb5\xfa\x81\x84\xe4>\xd3\u0e2b\x91!da\xb3R\x8d\x84\xfd\t\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb5\xfb~\xa2\xdd\xc1Y\x8bfz\x9dW\xdd9\xe8Z8\xf3]V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb6\x00B\x97R\xf3\x99\xc8\r\a4tK\xae\n\x02.\xcag\u0189\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x00\xfe\xabJ\xa9lSu\x04\xd9`W\"1Ai,\x19:\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb6\x04|\u07d3-\xb3\xe4\x04_Iv\x12#AS~\u0556\x1e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x15\xe9@\x14>\xb5\u007f\x87X\x93\xbc\x98\xa6\x1b=a\x8c\x1e\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb6\x1c4\xfc\xac\xdap\x1aZ\xa8p$Y\u07b0\u4b83\x8d\xf8\x8a\aiZ\x92\xc2\ro\xe0\x00\x00\xe0\x94\xb60d\xbd3U\xe6\xe0~-7p$\x12Z3wlJ\xfa\x8a\b7Z*\xbc\xca$@\x00\x00\u07d4\xb65\xa4\xbcq\xfb(\xfd\xd5\xd2\xc3\"\x98:V\u0084Bni\x89\t79SM(h\x00\x00\u07d4\xb6F\u07d8\xb4\x94BtkaR\\\x81\xa3\xb0K\xa3\x10bP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb6YA\xd4LP\xd2Ffg\r6Gf\xe9\x91\xc0.\x11\u0089 \x86\xac5\x10R`\x00\x00\xe0\x94\xb6[\u05c0\xc7CA\x15\x16 'VR#\xf4NT\x98\xff\x8c\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xb6d\x11\xe3\xa0-\xed\xb7&\xfay\x10}\xc9\v\xc1\xca\xe6MH\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb6fu\x14.1\x11\xa1\xc2\xea\x1e\xb2A\x9c\xfaB\xaa\xf7\xa24\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb6o\x92\x12K^c\x03XY\xe3\x90b\x88i\xdb\u07a9H^\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xb6rsJ\xfc\xc2$\xe2\xe6\t\xfcQ\xd4\xf0Ys'D\xc9H\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xb6w\x1b\v\xf3B\u007f\x9a\xe7\xa9>|.a\xeec\x94\x1f\xdb\b\x8a\x03\xfb&i)T\xbf\xc0\x00\x00\u07d4\xb6z\x80\xf1p\x19}\x96\xcd\xccJ\xb6\u02e6'\xb4\xaf\xa6\xe1,\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xb6\x88\x99\xe7a\rL\x93\xa255\xbc\xc4H\x94[\xa1fo\x1c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb6\xa8)3\xc9\xea\u06bd\x98\x1e]m`\xa6\x81\x8f\xf8\x06\xe3k\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb6\xaa\u02cc\xb3\v\xab*\xe4\xa2BF&\xe6\xe1+\x02\xd0F\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb6\xb3J&?\x10\xc3\xd2\xec\xeb\n\xccU\x9a{*\xb8\\\xe5e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xbf\xe1\xc3\xef\x94\xe1\x84o\xb9\xe3\xac\xfe\x9bP\xc3\xe9\x06\x923\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb6\xcdt2\xd5\x16\x1b\xe7\x97h\xadE\xde>Dz\a\x98 c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xceM\xc5`\xfcs\xdci\xfbzb\xe3\x88\xdb~r\xeavO\x894]\xf1i\xe9\xa3X\x00\x00\u07d4\xb6\xde\u03c2\x96\x98\x19\xba\x02\xde)\xb9\xb5\x93\xf2\x1bd\xee\xda\x0f\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\xe0\x94\xb6\xe6\xc3\"+ko\x9b\xe2\x87]*\x89\xf1'\xfbd\x10\x0f\xe2\x8a\x01\xb2\x1dS#\xcc0 \x00\x00\u07d4\xb6\xe8\xaf\xd9=\xfa\x9a\xf2\u007f9\xb4\xdf\x06\ag\x10\xbe\xe3\u07eb\x89\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xb6\xf7\x8d\xa4\xf4\xd0A\xb3\xbc\x14\xbc[\xa5\x19\xa5\xba\f2\xf1(\x8a$}\xd3,?\xe1\x95\x04\x80\x00\xe0\x94\xb6\xfb9xbP\b\x14&\xa3B\xc7\rG\xeeR\x1e[\xc5c\x8a\x03-&\xd1.\x98\v`\x00\x00\u07d4\xb7\r\xba\x93\x91h+J6Nw\xfe\x99%c\x01\xa6\xc0\xbf\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x16#\xf3Q\a\xcft1\xa8?\xb3\xd2\x04\xb2\x9e\u0c67\xf4\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xb7\x1a\x13\xba\x8e\x95\x16{\x803\x1bR\u059e7\x05O\xe7\xa8&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x1bb\xf4\xb4H\xc0+\x12\x01\xcb^9J\xe6'\xb0\xa5`\xee\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb7\" \xad\xe3d\xd06\x9f--\xa7\x83\xcaGM{\x9b4\u0389\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\xe0\x94\xb7#\r\x1d\x1f\xf2\xac\xa3f\x969\x14\xa7\x9d\xf9\xf7\xc5\xea,\x98\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xb7$\n\U000af433<\b\xae\x97d\x10>5\xdc\xe3c\x84(\x8a\x01\xca\xdd/\xe9hnc\x80\x00\u07d4\xb7'\xa9\xfc\x82\xe1\xcf\xfc\\\x17_\xa1HZ\x9b\xef\xa2\u037d\u04496'\xe8\xf7\x127<\x00\x00\u07d4\xb7,*\x01\x1c\r\xf5\x0f\xbbn(\xb2\n\xe1\xaa\xd2\x17\x88g\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb78-7\xdb\x03\x98\xacrA\f\xf9\x81=\xe9\xf8\xe1\uc36d\x8966\xc2^f\xec\xe7\x00\x00\u07d4\xb7;O\xf9\x9e\xb8\x8f\u061b\vmW\xa9\xbc3\x8e\x88o\xa0j\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xb7=jwU\x9c\x86\xcfet$)\x039K\xac\xf9n5p\x89\x04\xf1\xa7|\xcd;\xa0\x00\x00\u07d4\xb7Cr\xdb\xfa\x18\x1d\xc9$/9\xbf\x1d71\xdf\xfe+\xda\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7G\x9d\xabP\"\xc4\xd5\u06ea\xf8\xde\x17\x1bN\x95\x1d\u0464W\x89\x04V9\x18$O@\x00\x00\u07d4\xb7I\xb5N\x04\u0571\x9b\xdc\xed\xfb\x84\xdaw\x01\xabG\x8c'\xae\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb7N\xd2f`\x01\xc1c3\xcfz\xf5\x9eJ=H`6;\x9c\x89\n~\xbd^Cc\xa0\x00\x00\u07d4\xb7QI\xe1\x85\xf6\xe3\x92pWs\x90s\xa1\x82*\xe1\xcf\r\xf2\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xb7S\xa7_\x9e\xd1\v!d:\n=\xc0Qz\xc9k\x1a@h\x89\x15\xc8\x18[,\x1f\xf4\x00\x00\xe0\x94\xb7V\xadR\xf3\xbft\xa7\xd2LgG\x1e\b\x87Ci6PL\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb7Wn\x9d1M\xf4\x1e\xc5Pd\x94):\xfb\x1b\xd5\xd3\xf6]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb7X\x89o\x1b\xaa\x86O\x17\xeb\xed\x16\xd9S\x88o\xeeh\xaa\xe6\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb7h\xb5#N\xba:\x99h\xb3Mm\xdbH\x1c\x84\x19\xb3e]\x88\xcf\xceU\xaa\x12\xb3\x00\x00\u07d4\xb7\x82\xbf\xd1\xe2\xdep\xf4gdo\x9b\xc0\x9e\xa5\xb1\xfc\xf4P\xaf\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xb7\xa2\xc1\x03r\x8bs\x05\xb5\xaen\x96\x1c\x94\xee\x99\xc9\xfe\x8e+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xb7\xa3\x1a|8\xf3\xdb\t2.\xae\x11\xd2'!A\xea\"\x99\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xa6y\x1c\x16\xebN!b\xf1Ke7\xa0+=c\xbf\xc6\x02\x89*Rc\x91\xac\x93v\x00\x00\u07d4\xb7\xa7\xf7|4\x8f\x92\xa9\xf1\x10\fk\xd8)\xa8\xacm\u007f\u03d1\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xb7\xc0w\x94ft\xba\x93A\xfbLtz]P\xf5\xd2\xdad\x15\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb7\xc0\xd0\xcc\vM4-@b\xba\xc6$\xcc\xc3\xc7\f\xc6\xda?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb7\xc9\xf1+\x03\x8esCm\x17\xe1\xc1/\xfe\x1a\xec\u0373\xf5\x8c\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xb7\xcck\x1a\xcc2\u0632\x95\xdfh\xed\x9d^`\xb8\xf6L\xb6{\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xb7\xcehK\t\xab\xdaS8\x9a\x87Si\xf7\x19X\xae\xac;\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xd1.\x84\xa2\xe4\u01264Z\xf1\xdd\x1d\xa9\xf2PJ*\x99n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\xd2R\xee\x94\x02\xb0\xee\xf1D)_\x0ei\xf0\xdbXl\bq\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\xb7\u0541\xfe\n\xf1\xec8?;\xce\x00\xaf\x91\x99\xf3\xcf_\xe0\xcc\xe2\x8c\xd1J\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xb8R\x18\xf3B\xf8\x01.\u069f'Nc\xce!R\xb2\xdc\xfd\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb8UP\x10wn<\\\xb3\x11\xa5\xad\xee\xfe\x9e\x92\xbb\x9ad\xb9\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb8_&\xdd\x0er\xd9\u009e\xba\xf6\x97\xa8\xafwG,+X\xb5\x8a\x02\x85\x19\xac\xc7\x19\fp\x00\x00\u07d4\xb8_\xf0>{_\xc4\"\x98\x1f\xae^\x99A\xda\xcb\u06bau\x84\x89Hz\x9a0E9D\x00\x00\xe0\x94\xb8f\a\x02\x1bb\xd3@\xcf&R\xf3\xf9_\xd2\xdcgi\x8b\u07ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb8}\xe1\xbc\u0492i\xd5!\xb8v\x1c\u00dc\xfbC\x19\xd2\xea\u054965\u026d\xc5\u07a0\x00\x00\u07d4\xb8\u007fSv\xc2\xde\vl\xc3\xc1y\xc0`\x87\xaaG=kFt\x89Hz\x9a0E9D\x00\x00\u07d4\xb8\x84\xad\u060d\x83\xdcVJ\xb8\xe0\xe0,\xbd\xb69\x19\xae\xa8D\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x8a7\xc2\u007fx\xa6\x17\xd5\xc0\x91\xb7\u0577:7a\xe6_*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x94x\"\u056c\u79ad\x83&\xe9T\x96\"\x1e\v\xe6\xb7=\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\x9c\x03n\xd7\u0112\x87\x99!\xbeA\xe1\f\xa1i\x81\x98\xa7L\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xb8\x9fF2\xdfY\t\xe5\x8b*\x99d\xf7O\xeb\x9a;\x01\xe0\u014a\x04\x88u\xbc\xc6\xe7\xcb\xeb\x80\x00\u07d4\xb8\xa7\x9c\x84\x94^G\xa9\xc3C\x86\x83\u05b5\x84,\xffv\x84\xb1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\xa9y5'Y\xba\t\xe3Z\xa5\x93]\xf1u\xbf\xf6x\xa1\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\xab9\x80[\xd8!\x18Ol\xbd=$s4{\x12\xbf\x17\\\x89\x06hZ\xc1\xbf\xe3,\x00\x00\xe0\x94\xb8\xac\x11}\x9f\r\xba\x80\x90\x14E\x82:\x92\x11\x03\xa51o\x85Zew\x9d\x1b\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xb9\xe9\f\x11\x92\xb3\xd5\xd3\xe3\xab\a\x00\xf1\xbfe_]\xd44z\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4\xb9\xfd83\xe8\x8e|\xf1\xfa\x98y\xbd\xf5Z\xf4\xb9\x9c\xd5\xce?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xba\x02I\xe0\x1d\x94[\xef\x93\xee^\xc6\x19%\xe0<\\\xa5\t\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\x0f9\x02;\xdb)\xeb\x18b\xa9\xf9\x05\x9c\xab]0nf/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x10\xf2vB\x90\xf8uCCr\xf7\x9d\xbfq8\x01\u02ac\x01\x893\xc5I\x901r\f\x00\x00\u07d4\xba\x151\xfb\x9ey\x18\x96\xbc\xf3\xa8\x05X\xa3Y\xf6\xe7\xc1D\xbd\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xba\x17m\xbe2I\xe3E\xcdO\xa9g\xc0\xed\x13\xb2LG\u5189\x15\xae\xf9\xf1\xc3\x1c\u007f\x00\x00\xe0\x94\xba\x1f\x0e\x03\u02da\xa0!\xf4\xdc\xeb\xfa\x94\xe5\u0209\xc9\u01fc\x9e\x8a\x06\u0450\xc4u\x16\x9a \x00\x00\u07d4\xba\x1f\xca\xf2#\x93~\xf8\x9e\x85gU\x03\xbd\xb7\xcaj\x92\x8bx\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\xe0\x94\xba$\xfcCgS\xa79\xdb,\x8d@\xe6\xd4\xd0LR\x8e\x86\xfa\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xbaB\xf9\xaa\xceL\x18E\x04\xab\xf5BWb\xac\xa2oq\xfb\u0709\x02\a\a}\u0627\x9c\x00\x00\u07d4\xbaF\x9a\xa5\u00c6\xb1\x92\x95\u0521\xb5G;T\x03S9\f\x85\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbad@\xae\xb3s{\x8e\xf0\xf1\xaf\x9b\f\x15\xf4\xc2\x14\xff\xc7\u03c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbam1\xb9\xa2a\xd6@\xb5\u07a5\x1e\xf2\x16,1\t\xf1\uba0a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xbap\xe8\xb4u\x9c\f<\x82\xcc\x00\xacN\x9a\x94\xdd[\xaf\xb2\xb8\x890C\xfa3\xc4\x12\xd7\x00\x00\u07d4\xba\x8ac\xf3\xf4\r\u4a03\x88\xbcP!/\xea\x8e\x06O\xbb\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x8eF\u059d.#C\xd8l`\xd8,\xf4, A\xa0\xc1\u0089\x05k\xc7^-c\x10\x00\x00\u07d4\xba\xa4\xb6L+\x15\xb7\x9f_ BF\xfdp\xbc\xbd\x86\xe4\xa9*\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xba\u0212,J\xcc},\xb6\xfdY\xa1N\xb4\\\xf3\xe7\x02!K\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xba\xd25\xd5\b]\u01f0h\xa6|A&w\xb0>\x186\x88L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\xd4B^\x17\x1c>r\x97^\xb4j\xc0\xa0\x15\xdb1Z]\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xba\xdc*\xef\x9fYQ\xa8\u05cak5\xc3\u0433\xa4\xe6\xe2\xe79\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xba\xdeCY\x9e\x02\xf8OL0\x14W\x1c\x97k\x13\xa3le\xab\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\xe9\xb8/r\x99c\x14\be\x9d\xd7N\x89\x1c\xb8\xf3\x86\x0f\xe5\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xbb\x03f\xa7\u03fd4E\xa7\r\xb7\xfeZ\xe3H\x85uO\xd4h\x8a\x01M\xef,B\xeb\xd6@\x00\x00\u07d4\xbb\aj\xac\x92 \x80i\xea1\x8a1\xff\x8e\xeb\x14\xb7\xe9\x96\xe3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4\xbb\bW\xf1\xc9\x11\xb2K\x86\u0227\x06\x81G?\u6aa1\xcc\xe2\x89\x05k\xc7^-c\x10\x00\x00\u0794\xbb\x19\xbf\x91\u02edt\xcc\xeb_\x81\x1d\xb2~A\x1b\xc2\xea\x06V\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xbb'\u01a7\xf9\x10uGZ\xb2)a\x90@\xf8\x04\xc8\xeczj\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xbb7\x1cr\xc9\xf01l\xea+\xd9\xc6\xfb\xb4\a\x9ewT)\xef\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94\xbb;\x01\v\x18\xe6\xe2\xbe\x115\x87\x10&\xb7\xba\x15\xea\x0f\xde$\x8a\x02 |\x800\x9bwp\x00\x00\xe0\x94\xbb;\x90\x05\xf4o\xd2\xca;0\x16%\x99\x92\x8cw\xd9\xf6\xb6\x01\x8a\x01\xb1\xae\u007f+\x1b\xf7\xdb\x00\x00\u07d4\xbb?\xc0\xa2\x9c\x03Mq\b\x12\xdc\xc7u\xc8\u02b9\u048diu\x899\xd4\xe8D\xd1\xcf_\x00\x00\u07d4\xbbH\xea\xf5\x16\xce-\xec>A\xfe\xb4\xc6y\xe4\x95vA\x16O\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xbbKJKT\x80p\xffAC,\x9e\b\xa0\xcao\xa7\xbc\x9fv\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xbbV\xa4\x04r<\xff \xd0hT\x88\xb0Z\x02\xcd\xc3Z\xac\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbba\x8e%\"\x1a\u0667@\xb2\x99\xed\x14\x06\xbc94\xb0\xb1m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbba\xa0K\xff\xd5|\x10G\rE\u00d1\x03\xf6FP4v\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbbh#\xa1\xbd\x81\x9f\x13QU8&J-\xe0R\xb4D\"\b\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xbbl(J\xac\x8ai\xb7\\\u0770\x0f(\xe1EX;V\xbe\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xbbu\xcbPQ\xa0\xb0\x94KFs\xcau*\x97\x03\u007f|\x8c\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbb\x99;\x96\xee\x92Z\xda}\x99\u05c6W=?\x89\x18\f\u3a89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa3\u0180\x04$\x8eH\x95s\xab\xb2t6w\x06k$\u0227\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa4\xfa\xc3\xc4 9\xd8(\xe7B\xcd\xe0\xef\xff\xe7t\x94\x1b9\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\xbb\xa8\xab\"\xd2\xfe\xdb\xcf\xc6?hL\b\xaf\xdf\x1c\x17P\x90\xb5\x89\x05_)\xf3~N;\x80\x00\u07d4\xbb\xa9v\xf1\xa1!_u\x12\x87\x18\x92\xd4_pH\xac\xd3V\u0209lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbb\xab\x00\v\x04\b\xed\x01Z7\xc0GG\xbcF\x1a\xb1N\x15\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xbb\xab\xf6d;\xebK\xd0\x1c\x12\v\xd0Y\x8a\t\x87\xd8)g\u0449\xb52\x81x\xad\x0f*\x00\x00\u07d4\xbb\xb4\xee\x1d\x82\xf2\xe1VD,\xc938\xa2\xfc(o\xa2\x88d\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\xbb\xb5\xa0\xf4\x80,\x86H\x00\x9e\x8ai\x98\xaf5,\u0787TO\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\xbb\xb6C\xd2\x18{6J\xfc\x10\xa6\xfd6\x8d}U\xf5\r\x1a<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbb\xb8\xff\xe4?\x98\u078e\xae\x18F#\xaeRd\xe4$\u0438\u05c9\x05\xd5?\xfd\xe9(\b\x00\x00\u07d4\xbb\xbdn\u02f5u(\x91\xb4\u03b3\xcc\xe7:\x8fGpY7o\x89\x01\xf3\x99\xb1C\x8a\x10\x00\x00\u07d4\xbb\xbf9\xb1\xb6y\x95\xa4\"APO\x97\x03\u04a1JQV\x96\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbb\xc8\xea\xffc~\x94\xfc\u014d\x91\xdb\\\x89\x12\x1d\x06\xe1/\xff\x98\x80\x00\u07d4\xbc\u065e\xdc!`\xf2\x10\xa0^:\x1f\xa0\xb0CL\xed\x00C\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbc\u07ec\xb9\xd9\x02<4\x17\x18.\x91\x00\xe8\xea\x1d73\x93\xa3\x89\x034-`\xdf\xf1\x96\x00\x00\u07d4\xbc\xe1>\"2*\u03f3U\xcd!\xfd\r\xf6\f\xf9:\xdd&\u0189\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xbc\xe4\x04u\xd3E\xb0q-\xeep=\x87\xcdvW\xfc\u007f;b\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\xbc\xed\xc4&|\u02c9\xb3\x1b\xb7d\xd7!\x11q\x00\x8d\x94\xd4M\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbc\xfc\x98\xe5\xc8+j\xdb\x18\n?\xcb\x12\v\x9av\x90\xc8j?\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\x04;g\xc6>`\xf8A\xcc\xca\x15\xb1)\xcd\xfee\x90\xc8\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd\x04\u007f\xf1\xe6\x9c\u01b2\x9a\xd2d\x97\xa9\xa6\xf2z\x90?\xc4\u0749.\xe4IU\b\x98\xe4\x00\x00\u07d4\xbd\b\xe0\xcd\xde\xc0\x97\xdby\x01\ua05a=\x1f\xd9\u0789Q\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbd\t\x12l\x89\x1cJ\x83\x06\x80Y\xfe\x0e\x15ylFa\xa9\xf4\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xbd\f\\\u05d9\xeb\u0106B\xef\x97\xd7N\x8eB\x90d\xfe\u4489\x11\xac(\xa8\xc7)X\x00\x00\u07d4\xbd\x17\xee\xd8+\x9a%\x92\x01\x9a\x1b\x1b<\x0f\xba\xd4\\@\x8d\"\x89\r\x8drkqw\xa8\x00\x00\u07d4\xbd\x18\x037\v\u0771)\xd29\xfd\x16\xea\x85&\xa6\x18\x8a\u5389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbd+p\xfe\xcc7d\x0fiQO\xc7\xf3@IF\xaa\xd8k\x11\x89A\rXj \xa4\xc0\x00\x00\u07d4\xbd0\x97\xa7\x9b<\r.\xbf\xf0\xe6\xe8j\xb0\xed\xad\xbe\xd4p\x96\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xbd2]@)\xe0\xd8r\x9fm9\x9cG\x82$\xae\x9ez\xe4\x1e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xbdC*9\x16$\x9bG$):\xf9\x14nI\xb8(\n\u007f*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbdG\xf5\xf7n;\x93\x0f\xd9HR\t\xef\xa0\xd4v=\xa0uh\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbdK`\xfa\xect\n!\xe3\a\x13\x91\xf9j\xa54\xf7\xc1\xf4N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xbdK\u0571\"\xd8\xef{|\x8f\x06gE\x03 \xdb!\x16\x14.\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbdQ\xee.\xa1C\u05f1\u05b7~~D\xbd\xd7\xda\x12\U00105b09G~\x06\u0332\xb9(\x00\x00\u07d4\xbdY\tN\aO\x8dy\x14*\xb1H\x9f\x14\x8e2\x15\x1f \x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbdZ\x8c\x94\xbd\x8b\xe6G\x06D\xf7\f\x8f\x8a3\xa8\xa5\\cA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd^G:\xbc\xe8\xf9zi2\xf7|/\xac\xaf\x9c\xc0\xa0\x05\x14\x89<\x92X\xa1\x06\xa6\xb7\x00\x00\u07d4\xbd_F\u02ab,=K(\x93\x96\xbb\xb0\u007f *\x06\x11>\xd4\xc3\xfb\xa1\xa8\x91;\x19@~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\x9eV\xe9\x02\xf4\xbe\x1f\xc8v\x8d\x808\xba\xc6>*\u02ff\x8e\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xbd\xa4\xbe1~~K\xed\x84\xc0I^\xee2\xd6\a\xec8\xcaR\x89}2'yx\xefN\x80\x00\u07d4\xbd\xb6\v\x82:\x11s\xd4Z\a\x92$_\xb4\x96\xf1\xfd3\x01\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xba\xf6CM@\xd65[\x1e\x80\xe4\f\u012b\x9ch\xd9a\x16\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbd\xc0,\xd43\f\x93\xd6\xfb\xdaOm\xb2\xa8]\xf2/C\xc23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc4aF+c\"\xb4b\xbd\xb3?\"y\x9e\x81\b\xe2A}\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xbd\xc79\xa6\x99p\v.\x8e,JL{\x05\x8a\x0eQ=\u07be\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc7Hs\xaf\x92+\x9d\xf4t\x85;\x0f\xa7\xff\v\xf8\xc8&\x95\x89\xd8\xc9F\x00c\xd3\x1c\x00\x00\u07d4\xbd\xca*\x0f\xf3E\x88\xafb_\xa8\xe2\x8f\xc3\x01Z\xb5\xa3\xaa\x00\x89~\xd7?w5R\xfc\x00\x00\u07d4\xbd\xd3%N\x1b:m\xc6\xcc,i}Eq\x1a\xca!\xd5\x16\xb2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbd\u07e3M\x0e\xbf\x1b\x04\xafS\xb9\x9b\x82IJ\x9e=\x8a\xa1\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xbd\xe4\xc7?\x96\x9b\x89\xe9\u03aef\xa2\xb5\x18DH\x0e\x03\x8e\x9a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbd\xe9xj\x84\xe7[H\xf1\x8erm\u05cdp\xe4\xaf>\xd8\x02\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xbd\xed\x11a/\xb5\xc6\u0699\xd1\xe3\x0e2\v\xc0\x99Tf\x14\x1e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xbd\xed~\a\xd0q\x1ehM\xe6Z\u0232\xabW\xc5\\\x1a\x86E\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xbd\xf6\x93\xf83\xc3\xfeG\x17S\x18G\x88\xebK\xfeJ\xdc?\x96\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\xf6\xe6\x8c\f\xd7X@\x80\xe8G\xd7,\xbb#\xaa\xd4j\xeb\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbe\n/8_\t\xdb\xfc\xe9g2\xe1+\xb4\n\xc3I\x87\x1b\xa8\x89WL\x11^\x02\xb8\xbe\x00\x00\u07d4\xbe\f*\x80\xb9\xde\bK\x17(\x94\xa7l\xf4szOR\x9e\x1a\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\x1c\xd7\xf4\xc4r\a\th\xf3\xbd\xe2h6k!\xee\xea\x83!\x89\xe9\x1a|\u045f\xa3\xb0\x00\x00\u07d4\xbe#F\xa2\u007f\xf9\xb7\x02\x04OP\r\xef\xf2\xe7\xff\xe6\x82EA\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbe$q\xa6\u007f`G\x91\x87r\xd0\xe3h9%^\xd9\u0591\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbe+\"\x80R7h\xea\x8a\xc3\\\xd9\xe8\x88\xd6\nq\x93\x00\u0509lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe+2nx\xed\x10\xe5P\xfe\xe8\xef\xa8\xf8\a\x03\x96R/Z\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\xe0\x94\xbe0Zyn3\xbb\xf7\xf9\xae\xaee\x12\x95\x90f\xef\xda\x10\x10\x8a\x02M\xceT\xd3J\x1a\x00\x00\x00\u07d4\xbeG\x8e\x8e=\xdek\xd4\x03\xbb-\x1ce|C\x10\xee\x19'#\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\xbeN}\x98?.*ck\x11\x02\xecp9\xef\xeb\xc8B\u9349\x03\x93\xef\x1aQ'\xc8\x00\x00\u07d4\xbeO\xd0sap\"\xb6\u007f\\\x13I\x9b\x82\u007fv69\xe4\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbeRZ3\xea\x91aw\xf1r\x83\xfc\xa2\x9e\x8b5\v\u007fS\v\x89\x8f\x01\x9a\xafF\xe8x\x00\x00\u07d4\xbeS2/C\xfb\xb5\x84\x94\xd7\xcc\xe1\x9d\xda'+$P\xe8'\x89\n\xd7\u03afB\\\x15\x00\x00\u07d4\xbeS\x82F\xddNo\f \xbfZ\xd17<;F:\x13\x1e\x86\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbeZ`h\x99\x98c\x9a\xd7[\xc1\x05\xa3qt>\xef\x0fy@\x89\x1b2|s\xe1%z\x00\x00\u07d4\xbe\\\xba\x8d7By\x86\xe8\xca&\x00\xe8X\xbb\x03\xc3YR\x0f\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xbe`\x03~\x90qJK\x91~a\xf1\x93\xd84\x90g\x03\xb1:\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbec:77\xf6\x849\xba\xc7\xc9\nR\x14 X\ue38ao\x894\n\xad!\xb3\xb7\x00\x00\x00\xe0\x94\xbee\x9d\x85\xe7\xc3O\x883\xea\u007fH\x8d\xe1\xfb\xb5\xd4\x14\x9b\xef\x8a\x01\xeb\xd2:\xd9\u057br\x00\x00\u07d4\xbes'M\x8cZ\xa4J<\xbe\xfc\x82c\xc3{\xa1!\xb2\n\u04c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbe\x86\u0430C\x84\x19\u03b1\xa081\x927\xbaR\x06\xd7.F\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xbe\x8d\u007f\x18\xad\xfe]l\xc7u9I\x89\xe1\x93\f\x97\x9d\x00}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\x91\x86\xc3JRQJ\xbb\x91\a\x86\x0fgO\x97\xb8!\xbd[\x89\x1b\xa0\x1e\xe4\x06\x03\x10\x00\x00\u07d4\xbe\x93W\x93\xf4[p\xd8\x04]&T\xd8\xdd:\xd2K[a7\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xbe\x98\xa7\u007f\xd4\x10\x97\xb3OY\xd7X\x9b\xaa\xd0!e\x9f\xf7\x12\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xbe\x9b\x8c4\xb7\x8e\xe9G\xff\x81G.\xdaz\xf9\xd2\x04\xbc\x84f\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\xbe\xa0\r\xf1pg\xa4:\x82\xbc\x1d\xae\xca\xfbl\x140\x0e\x89\xe6\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xbe\xa0\xaf\xc9:\xae!\b\xa3\xfa\xc0Yb;\xf8o\xa5\x82\xa7^\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbe\xb35\x8cP\u03dfu\xff\xc7mD<,\u007fU\aZ\x05\x89\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xbe\xb4\xfd1UYC`E\u0739\x9dI\xdc\xec\x03\xf4\fB\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xc2\xe6\xde9\xc0|+\xaeUj\u03fe\xe2\xc4r\x8b\x99\x82\xe3\x89\x1f\x0f\xf8\xf0\x1d\xaa\xd4\x00\x00\u07d4\xbe\xc6d\x0fI\t\xb5\x8c\xbf\x1e\x80cB\x96\x1d`u\x95\tl\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\xc8\xca\xf7\xeeIF\x8f\xeeU.\xff:\xc5#N\xb9\xb1}B\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xce\xf6\x1c\x1cD+\xef|\xe0Ks\xad\xb2I\xa8\xba\x04~\x00\x896;V\u00e7T\xc8\x00\x00\u0794\xbe\xd4d\x9d\xf6F\u2052)\x03-\x88hUo\xe1\xe0S\u04c8\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xbe\xd4\xc8\xf0\x06\xa2|\x1e_|\xe2\x05\xdeu\xf5\x16\xbf\xb9\xf7d\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xbe\xe8\u0430\bB\x19T\xf9-\x00\r9\x0f\xb8\xf8\xe6X\xea\xee\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\xec\u05af\x90\f\x8b\x06J\xfc\xc6\a?-\x85\u055a\xf1\x19V\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe\xef\x94!8y\xe0&\"\x14+\xeaa)\tx\x93\x9a`\u05ca\x016\x85{2\xad\x86\x04\x80\x00\xe0\x94\xbe\xf0}\x97\xc3H\x1f\x9dj\xee\x1c\x98\xf9\xd9\x1a\x18\n2D+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xbe\xfbD\x8c\f_h?\xb6~\xe5p\xba\xf0\xdbV\x86Y\x97Q\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbf\x05\a\f,4!\x93\x11\xc4T\x8b&\x14\xa48\x81\r\xedm\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbf\x05\xff^\xcf\r\xf2\u07c8wY\xfb\x82t\xd928\xac&}\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\xbf\t\xd7pH\xe2p\xb6b3\x0e\x94\x86\xb3\x8bC\xcdx\x14\x95\x8a\\S\x9b{\xf4\xff(\x80\x00\x00\u07d4\xbf\x17\xf3\x97\xf8\xf4o\x1b\xaeE\u0447\x14\x8c\x06\xee\xb9Y\xfaM\x896I\u0156$\xbb0\x00\x00\u07d4\xbf\x186A\xed\xb8\x86\xce`\xb8\x19\x02a\xe1OB\xd9<\xce\x01\x89\x01[5W\xf1\x93\u007f\x80\x00\u07d4\xbf*\xeaZ\x1d\xcfn\u04f5\xe829D\xe9\x83\xfe\xdf\u046c\xfb\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbf@\x96\xbcT}\xbf\xc4\xe7H\t\xa3\x1c\x03\x9e{8\x9d^\x17\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xbfI\xc1H\x981eg\u0637\t\xc2\xe5\x05\x94\xb3f\xc6\u04cc\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4\xbfLs\xa7\xed\xe7\xb1d\xfe\a!\x14\x846T\xe4\xd8x\x1d\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfP\xce.&K\x9f\xe2\xb0h0az\xed\xf5\x02\xb25\x1bE\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfY\xae\xe2\x81\xfaC\xfe\x97\x19CQ\xa9\x85~\x01\xa3\xb8\x97\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbfh\u048a\xaf\x1e\xee\xfe\xf6F\xb6^\x8c\xc8\u0450\xf6\xc6\u069c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfi%\xc0\aQ\x00\x84@\xa6s\x9a\x02\xbf+l\u06ab^:\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfw\x01\xfcb%\u0561x\x15C\x8a\x89A\xd2\x1e\xbc]\x05\x9d\x89e\xea=\xb7UF`\x00\x00\u07d4\xbf\x8b\x80\x05\xd66\xa4\x96d\xf7Bu\xefBC\x8a\xcde\xac\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\x92A\x8a\fl1$M\"\x02`\xcb>\x86}\u05f4\xefI\x89\x05i\x00\xd3<\xa7\xfc\x00\x00\u07d4\xbf\x9a\xcdDE\xd9\xc9UF\x89\u02bb\xba\xb1\x88\x00\xff\x17A\u008965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\x9f'\x1fz~\x12\xe3m\xd2\xfe\x9f\xac\xeb\xf3\x85\xfeaB\xbd\x89\x03f\xf8O{\xb7\x84\x00\x00\u07d4\xbf\xa8\xc8X\xdf\x10,\xb1$!\x00\x8b\n1\xc4\xc7\x19\n\xd5`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\xae\xb9\x10ga}\u03cbD\x17+\x02\xafaVt\x83]\xba\x89\b\xb5\x9e\x88H\x13\b\x80\x00\xe0\x94\xbf\xb0\xea\x02\xfe\xb6\x1d\xec\x9e\"\xa5\a\tY3\x02\x99\xc40r\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xbf\xbc\xa4\x18\xd3R\x9c\xb3\x93\b\x10b\x03*n\x11\x83\u01b2\u070a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xbf\xbe\x05\u831c\xbb\xcc\x0e\x92\xa4\x05\xfa\xc1\xd8]\xe2H\xee$\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xbf\xbf\xbc\xb6V\u0099+\xe8\xfc\u0782\x19\xfb\xc5J\xad\u055f)\x8a\x02\x1e\x18\xd2\xc8!\xc7R\x00\x00\u07d4\xbf\xc5z\xa6f\xfa\u239f\x10zI\xcbP\x89\xa4\xe2!Q\u074965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\u02d70$c\x04p\r\xa9\vAS\xe7\x11Ab.\x1cA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbf\xd9<\x90\u009c\a\xbc_\xb5\xfcI\xae\xeaU\xa4\x0e\x13O5\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\xe0\x94\xbf\xe3\xa1\xfcn$\xc8\xf7\xb3%\x05`\x99\x1f\x93\u02e2\u03c0G\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xbf\u6f30\xf0\xc0xRd3$\xaa]\xf5\xfdb%\xab\xc3\u0289\x04\t\xe5+H6\x9a\x00\x00\u07d4\xbf\xf5\xdfv\x994\xb8\x94<\xa9\x13}\x0e\xfe\xf2\xfen\xbb\xb3N\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbf\xfbi)$\x1fx\x86\x93'>p\"\xe6\x0e>\xab\x1f\xe8O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x06O\x1d\x94t\xab\x91]V\x90l\x9f\xb3 \xa2\xc7\t\x8c\x9b\x89\x13h?\u007f<\x15\xd8\x00\x00\u07d4\xc0\a\xf0\xbd\xb6\xe7\x00\x92\x02\xb7\xaf>\xa9\t\x02i|r\x14\x13\x89\xa2\xa0\xe4>\u007f\xb9\x83\x00\x00\u07d4\xc0\n\xb0\x80\xb6C\xe1\u00ba\xe3c\xe0\u0455\xde.\xff\xfc\x1cD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\xc0 wD\x9a\x13Jz\xd1\xef~M\x92z\xff\xec\ueb75\xae\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc0$q\xe3\xfc.\xa0S&\x15\xa7W\x1dI2\x89\xc1<6\xef\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0-n\xad\xea\xcf\x1bx\xb3\u0285\x03\\c{\xb1\xce\x01\xf4\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc03\xb12Z\n\xf4Tr\xc2U'\x85;\x1f\x1c!\xfa5\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc03\xbe\x10\xcbHa;\xd5\xeb\xcb3\xedI\x02\xf3\x8bX0\x03\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc04[3\xf4\x9c\xe2\u007f\xe8,\xf7\xc8M\x14\x1ch\xf5\x90\xcev\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0=\xe4*\x10\x9bezd\xe9\"$\xc0\x8d\xc1'^\x80\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0@i\u07f1\x8b\tlxg\xf8\xbe\xe7zm\xc7Gz\xd0b\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xc0A?Z|-\x9aK\x81\b(\x9e\xf6\xec\xd2qx\x15$\xf4\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xc0C\xf2E-\u02d6\x02\xefb\xbd6\x0e\x03=\xd29q\xfe\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0OK\xd4\x04\x9f\x04F\x85\xb8\x83\xb6)Y\xaec\x1df~5\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0V\u053dk\xf3\u02ec\xace\xf8\xf5\xa0\xe3\x98\v\x85'@\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0[t\x06 \xf1s\xf1nRG\x1d\u00cb\x9cQJ\v\x15&\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\xc0i\xef\x0e\xb3B\x99\xab\xd2\xe3-\xab\xc4yD\xb2r3H$\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xc0l\xeb\xbb\xf7\xf5\x14\x9af\xf7\xeb\x97k>G\xd5e\x16\xda/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0r^\u00bd\xc3:\x1d\x82`q\u07a2\x9db\xd48Z\x8c%\x8a\b\xa0\x85\x13F:\xa6\x10\x00\x00\u07d4\xc0~8g\xad\xa0\x96\x80z\x05\x1al\x9c4\xcc;?J\xd3J\x89`\xf0f \xa8IE\x00\x00\u07d4\xc0\x89^\xfd\x05m\x9a:\x81\xc3\xdaW\x8a\xda1\x1b\xfb\x93V\u03c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x90\xfe#\xdc\xd8k5\x8c2\xe4\x8d*\xf9\x10$%\x9fef\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x9af\x17*\xea7\r\x9ac\xda\x04\xffq\xff\xbb\xfc\xff\u007f\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x9e<\xfc\x19\xf6\x05\xff>\xc9\xc9\xc7\x0e%@\xd7\xee\x97Cf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc0\xa0*\xb9N\xbeV\xd0E\xb4\x1bb\x9b\x98F.:\x02J\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0\xa3\x93\b\xa8\x0e\x9e\x84\xaa\xaf\x16\xac\x01\xe3\xb0\x1dt\xbdk-\x89\afM\xddL\x1c\v\x80\x00\u07d4\xc0\xa6\u02edwi*=\x88\xd1A\xefv\x9a\x99\xbb\x9e<\x99Q\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xc0\xa7\xe8C]\xff\x14\xc2Uws\x9d\xb5\\$\u057fW\xa3\u064a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xc0\xae\x14\xd7$\x83./\xce'x\xde\u007f{\x8d\xaf{\x12\xa9>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0\xaf\xb7\u0637\x93p\xcf\xd6c\u018c\u01b9p*7\u035e\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0\xb0\xb7\xa8\xa6\xe1\xac\xdd\x05\xe4\u007f\x94\xc0\x96\x88\xaa\x16\u01ed\x8d\x89\x03{m\x02\xacvq\x00\x00\xe0\x94\xc0\xb3\xf2D\xbc\xa7\xb7\xde[H\xa5>\u06dc\xbe\xab\vm\x88\xc0\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0\xc0M\x01\x06\x81\x0e>\xc0\xe5J\x19\U000ab157\xe6\x9aW=\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xc0\xca2w\x94.tE\x87K\xe3\x1c\xeb\x90)rqO\x18#\x89\r\x8drkqw\xa8\x00\x00\u07d4\xc0\u02ed<\xcd\xf6T\xda\"\xcb\xcf\\xe\x97\xca\x19U\xc1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\xcb\xf6\x03/\xa3\x9e|F\xffw\x8a\x94\xf7\xd4E\xfe\"\xcf0\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\xc0\xe0\xb9\x03\b\x8e\fc\xf5=\xd0iWTR\xaf\xf5$\x10\u00c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc0\xe4W\xbdV\xec6\xa1$k\xfa20\xff\xf3\x8eY&\xef\"\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xc0\xed\rJ\xd1\r\xe045\xb1S\xa0\xfc%\xde;\x93\xf4R\x04\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xc0\xf2\x9e\xd0\af\x11\xb5\xe5^\x13\x05G\xe6\x8aH\xe2m\xf5\u4262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc1\x13(x#\\]\u06e5\xd9\xf3\"\x8bR6\xe4p \xdco\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1\x17\r\xba\xad\xb3\xde\xe6\x19\x8e\xa5D\xba\xec\x93%\x18`\xfd\xa5\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\xc1&W=\x87\xb0\x17ZR\x95\xf1\xdd\a\xc5u\u03cc\xfa\x15\xf2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc1'\xaa\xb5\x90e\xa2\x86D\xa5k\xa3\xf1^.\xac\x13\xda)\x95\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xc1+\u007f@\u07da/{\xf9\x83f\x14\"\xab\x84\xc9\xc1\xf5\bX\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc1,\xfb{=\xf7\x0f\xce\xca\x0e\xde&5\x00\xe2xs\xf8\xed\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1/\x88\x1f\xa1\x12\xb8\x19\x9e\xcb\xc7>\xc4\x18W\x90\xe6\x14\xa2\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc18Lnq~\xbeK#\x01NQ\xf3\x1c\x9d\xf7\xe4\xe2[1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1C\x8c\x99\xddQ\xef\x1c\xa88j\xf0\xa3\x17\xe9\xb0AEx\x88\x89\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xc1c\x12(\xef\xbf*.:@\x92\xee\x89\x00\xc69\xed4\xfb\u02093\xc5I\x901r\f\x00\x00\u07d4\xc1u\xbe1\x94\xe6iB-\x15\xfe\xe8\x1e\xb9\xf2\xc5lg\xd9\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\x82v\x86\xc0\x16\x94\x85\xec\x15\xb3\xa7\xc8\xc0\x15\x17\xa2\x87M\xe1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xc1\x8a\xb4g\xfe\xb5\xa0\xaa\xdf\xff\x91#\x0f\xf0VFMx\xd8\x00\x89lk\x93[\x8b\xbd@\x00\x00\u0794\xc1\x95\x05CUM\x8aq0\x03\xf6b\xbba,\x10\xadL\xdf!\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc1\xa4\x1aZ'\x19\x92&\xe4\xc7\xeb\x19\x8b\x03\x1bY\x19o\x98B\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xc1\xb2\xa0\xfb\x9c\xadE\xcdi\x91\x92\xcd'T\v\x88\xd38By\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1\xb2\xaa\x8c\xb2\xbfb\xcd\xc1:G\xec\xc4e\u007f\xac\xaa\x99_\x98\x8967\x93\xfa\x96\u6980\x00\u07d4\xc1\xb5\x00\x01\x1c\xfb\xa9]|\xd66\xe9^l\xbfagFK%\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\xb9\xa5pM5\x1c\xfe\x98?y\xab\xee\xc3\u06fb\xae;\xb6)\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xcb\xd2\xe23*RL\xf2\x19\xb1\r\x87\x1c\xcc \xaf\x1f\xb0\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xc1\xcd\xc6\x01\xf8\x9c\x04(\xb3\x13\x02\u0447\xe0\xdc\b\xad}\x1cW\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xc1\u052f8\xe9\xbay\x90@\x89HI\xb8\xa8!\x93u\xf1\xacx\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc1\xe1@\x9c\xa5,%CQ4\xd0\x06\u00a6\xa8T-\xfbrs\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xc1\xeb\xa5hJ\xa1\xb2L\xbac\x15\x02c\xb7\xa9\x13\x1a\xee\u008d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xec\x81\xdd\x12=K|-\u0674\xd48\xa7\a,\x11\u0707L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc1\xf3\x9b\xd3]\xd9\xce\xc37\xb9oG\xc6w\x81\x81`\xdf7\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xc1\xff\xad\a\u06d6\x13\x8cK*S\x0e\xc1\xc7\xde)\xb8\xa0Y,\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xc2\x1f\xa6d:\x1f\x14\xc0)\x96\xadqD\xb7Y&\xe8~\xcbK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc24\nL\xa9L\x96x\xb7IL<\x85%(\xed\xe5\xeeR\x9f\x89\x02\xa3k\x05\xa3\xfd|\x80\x00\u07d4\xc29\xab\u07ee>\x9a\xf5E\u007fR\xed+\x91\xfd\n\xb4\xd9\xc7\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2;/\x92\x1c\xe4\xa3z%\x9e\u4b4b!X\xd1]fOY\x89\x01`\x89\x95\xe8\xbd?\x80\x00\u07d4\xc2C\x99\xb4\xbf\x86\xf73\x8f\xbfd^;\"\xb0\u0dd79\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2L\u03bc#D\xcc\xe5d\x17\xfbhL\xf8\x16\x13\xf0\xf4\xb9\xbd\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc2Rf\xc7gf2\xf1>\xf2\x9b\xe4U\ud50a\xddVw\x92\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\\\xf8&U\f\x8e\xaf\x10\xaf\"4\xfe\xf9\x04\u0779R\x13\xbe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc2f?\x81E\xdb\xfe\xc6\xc6F\xfc\\I\x96\x13E\xde\x1c\x9f\x11\x89%g\xacp9+\x88\x00\x00\u07d4\xc2pEh\x854+d\vL\xfc\x1bR\x0e\x1aTN\xe0\xd5q\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc2sv\xf4]!\xe1^\xde;&\xf2e_\xce\xe0,\xcc\x0f*\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc2w\x97q\xf0Smy\xa8p\x8fi1\xab\xc4K05\u964a\x047\u04ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc2\xc1>r\xd2h\xe7\x15\r\u01d9\xe7\xc6\xcf\x03\u0209T\xce\u05c9%\xf2s\x93=\xb5p\x00\x00\u07d4\xc2\xcb\x1a\xda]\xa9\xa0B8s\x81G\x93\xf1aD\xef6\xb2\xf3\x89HU~;p\x17\xdf\x00\x00\u07d4\xc2\xd1w\x8e\xf6\xee_\xe4\x88\xc1E\xf3Xkn\xbb\xe3\xfb\xb4E\x89>\x1f\xf1\xe0;U\xa8\x00\x00\xe0\x94\xc2\xd9\xee\xdb\xc9\x01\x92c\xd9\xd1l\u016e\a-\x1d=\xd9\xdb\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc2\xe0XJq4\x8c\xc3\x14\xb7; )\xb6#\v\x92\u06f1\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2\xe2\u0518\xf7\r\xcd\bY\xe5\v\x02:q\nmK!3\xbd\x8989\x11\xf0\f\xbc\xe1\x00\x00\u07d4\xc2\xed_\xfd\u046d\xd8U\xa2i/\xe0b\xb5\xd6\x18t#`\u0509A\rXj \xa4\xc0\x00\x00\u07d4\xc2\xee\x91\xd3\xefX\xc9\u0465\x89\x84N\xa1\xae1%\xd6\u017ai\x894\x95tD\xb8@\xe8\x00\x00\u07d4\xc2\xfa\xfd\xd3\n\xcbmg\x06\xe9)<\xb0&A\xf9\xed\xbe\a\xb5\x89Q\x00\x86\vC\x0fH\x00\x00\u07d4\xc2\xfd\v\xf7\xc7%\xef>\x04~Z\xe1\u009f\xe1\x8f\x12\xa7)\x9c\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\xfe}us\x1fcm\xcd\t\xdb\xda\x06q9;\xa0\xc8*}\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\xc3\x10z\x9a\xf32-R8\xdf\x012A\x911b\x959W}\x89\x1a\xb4\xe4d\xd4\x141\x00\x00\xe0\x94\xc3\x11\v\xe0\x1d\xc9sL\xfcn\x1c\xe0\u007f\x87\xd7}\x13E\xb7\xe1\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xc3 8\xcaR\xae\xe1\x97E\xbe\\1\xfc\xdcT\x14\x8b\xb2\xc4\u0409\x02\xb5\xaa\xd7,e \x00\x00\u07d4\xc3%\xc3R\x80\x1b\xa8\x83\xb3\"l_\xeb\r\xf9\xea\xe2\xd6\xe6S\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xc3.\xc7\xe4*\xd1l\xe3\xe2UZ\xd4\xc5C\x06\xed\xa0\xb2gX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc32\xdfP\xb1<\x014\x90\xa5\xd7\xc7]\xbf\xa3f\u0687\xb6\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc3:\u0373\xba\x1a\xab'P{\x86\xb1]g\xfa\xf9\x1e\xcfb\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3>\u0393Z\x8fN\xf98\xea~\x1b\xac\x87\u02d2]\x84\x90\u028a\a\x03\x8c\x16x\x1fxH\x00\x00\u07d4\xc3@\xf9\xb9\x1c&r\x8c1\xd1!\xd5\xd6\xfc;\xb5m=\x86$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3F\xcb\x1f\xbc\xe2\xab(]\x8eT\x01\xf4-\xd7#M7\xe8m\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\xe0\x94\xc3H=n\x88\xac\x1fJ\xe7<\xc4@\x8dl\x03\xab\xe0\xe4\x9d\u028a\x03\x99\x92d\x8a#\u0220\x00\x00\xe0\x94\xc3H\xfcZF\x13#\xb5{\xe3\x03\u02c96\x1b\x99\x19\x13\xdf(\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc3N;\xa12.\xd0W\x11\x83\xa2O\x94 N\xe4\x9c\x18fA\x89\x03'\xaf\uf927\xbc\x00\x00\xe0\x94\xc3[\x95\xa2\xa3s|\xb8\xf0\xf5\x96\xb3E$\x87+\xd3\r\xa24\x8a\x01\x98\xbe\x85#^-P\x00\x00\xe0\x94\xc3c\x1cv\x98\xb6\xc5\x11\x19\x89\xbfE''\xb3\xf99Zm\xea\x8a\x02C'X\x96d\x1d\xbe\x00\x00\u07d4\xc3l\vc\xbf\xd7\\/\x8e\xfb\x06\b\x83\xd8h\xcc\xcdl\xbd\xb4\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xc3uk\xcd\xcc~\xect\xed\x89j\xdf\xc35'Y0&n\b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u00c4\xacn\xe2|9\xe2\xf2x\xc2 \xbd\xfa[\xae\xd6&\xd9\u04c9 \x86\xac5\x10R`\x00\x00\u07d4\u00e0F\xe3\u04b2\xbfh\x14\x88\x82n2\xd9\xc0aQ\x8c\xfe\x8c\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\u00e9\"j\xe2u\xdf,\xab1+\x91\x10@cJ\x9c\x9c\x9e\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u00f9(\xa7o\xadex\xf0O\x05U\xe69R\xcd!\xd1R\n\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xc2)s)\xa6\xfd\x99\x11~T\xfcj\xf3y\xb4\xd5VT~\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc3\xc3\xc2Q\rg\x80 HZcs]\x13\a\xecL\xa60+\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc3\xcbk6\xafD?,n%\x8bJ9U:\x81\x87G\x81\x1f\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xc3\xdbVW\xbbr\xf1\rX\xf21\xfd\xdf\x11\x98\n\xffg\x86\x93\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xc3\u06df\xb6\xf4lH\n\xf3De\u05d7S\xb4\xe2\xb7Jg\u038a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc3\xddX\x908\x860;\x92\x86%%z\xe1\xa0\x13\xd7\x1a\xe2\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe0G\x1cd\xff5\xfaR2\xcc1!\xd1\u04cd\x1a\x0f\xb7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe2\f\x96\u07cdN8\xf5\v&Z\x98\xa9\x06\xd6\x1b\xc5\x1aq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\u31f0<\xe9\\\xcf\xd7\xfaQ\u0744\x01\x83\xbcCS(\t\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xf8\xf6r\x95\xa5\xcd\x04\x93d\xd0]#P&#\xa3\xe5.\x84\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc4\x01\xc4'\xcc\xcf\xf1\r\xec\xb8d /6\xf5\x80\x83\"\xa0\xa8\x89\xb4{Q\xa6\x9c\xd4\x02\x00\x00\u07d4\xc4\b\x8c\x02_>\x85\x01?T9\xfb4@\xa1s\x01\xe5D\xfe\x89~\t\xdbM\x9f?4\x00\x00\u07d4\xc4\x14a\xa3\u03fd2\u0246UU\xa4\x8117\xc0v1#`\x8965\xc6 G9\u0640\x00\u07d4\xc4 8\x8f\xbe\xe8J\xd6V\xddh\xcd\xc1\xfb\xaa\x93\x92x\v4\x89\n-\xcac\xaa\xf4\u0140\x00\u07d4\xc4\"P\xb0\xfeB\xe6\xb7\xdc\xd5\u0210\xa6\xf0\u020f__\xb5t\x89\b\x1e\xe4\x82SY\x84\x00\x00\u07d4\xc4-j\xebq\x0e:P\xbf\xb4Ml1\t)i\xa1\x1a\xa7\xf3\x89\b\"c\xca\xfd\x8c\xea\x00\x00\xe0\x94\xc4@\xc7\xca/\x96Kir\xeffJ\"a\xdd\xe8\x92a\x9d\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xc4K\xde\xc8\xc3l\\h\xba\xa2\xdd\xf1\xd41i2)rlC\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc4OJ\xb5\xbc`9|s~\xb0h3\x91\xb63\xf8\xa2G\x1b\x12\x1c\xa4\x89 .h\xf2\u00ae\xe4\x00\x00\u07d4\xc4h\x1es\xbb\x0e2\xf6\xb7& H1\xffi\xba\xa4\x87~2\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc4k\xbd\xefv\xd4\xca`\xd3\x16\xc0\u007f]\x1ax\x0e;\x16_~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc4}a\v9\x92P\xf7\x0e\xcf\x13\x89\xba\xb6),\x91&O#\x89\x0f\xa7\xe7\xb5\xdf<\xd0\x00\x00\u07d4\u0100;\xb4\a\xc7b\xf9\vu\x96\xe6\xfd\u1513\x1ev\x95\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0106Q\xc1\xd9\xc1k\xffL\x95T\x88l??&C\x1foh\x89#\xab\x95\x99\xc4?\b\x00\x00\u07d4\u0109\xc8?\xfb\xb0%*\xc0\xdb\xe3R\x12\x17c\x0e\x0fI\x1f\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u010bi<\xac\xef\xdb\xd6\xcb]x\x95\xa4.1\x962~&\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0113H\x9eV\u00fd\xd8)\x00}\xc2\xf9VA)\x06\xf7k\xfa\x89\x02\xa7\x91H\x8eqT\x00\x00\u07d4\u0116\u02f0E\x9aj\x01`\x0f\u0149\xa5Z2\xb4T!\u007f\x9d\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4\u011c\xfa\xa9g\xf3\xaf\xbfU\x03\x10a\xfcL\xef\x88\xf8]\xa5\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0136\xe5\xf0\x9c\xc1\xb9\r\xf0x\x03\xce=M\x13vj\x9cF\xf4\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u013e\xc9c\b\xa2\x0f\x90\u02b1\x83\x99\u0113\xfd=\x06Z\xbfE\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xc4\xc0\x1a\xfc>\x0f\x04R!\xda\x12\x84\u05c7\x85tD/\xb9\xac\x8a\x01\x92\xb5\u0249\x02J\x19\xc1\xbdo\x12\x80\x00\xe0\x94\xc5\x00\xb7 sN\xd2)8\u05cc^H\xb2\xba\x93g\xa5u\xba\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\u07d4\xc5\x0f\xe4\x15\xa6A\xb0\x85lNu\xbf\x96\x05\x15D\x1a\xfa5\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\x13L\xfb\xb1\xdfz \xb0\xedpWb.\xee\u0480\x94}\xad\x89\xcd\xff\x97\xfa\xbc\xb4`\x00\x00\xe0\x94\xc5\x17\xd01\\\x87\x88\x13\xc7\x17\u132f\xa1\xea\xb2eN\x01\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc5\x18y\x9aY%Wb\x13\xe2\x18\x96\xe0S\x9a\xbb\x85\xb0Z\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\"\xe2\x0f\xbf\x04\xed\u007fk\x05\xa3{G\x18\xd6\xfc\xe0\x14.\x1a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc5$\bmF\xc8\x11+\x12\x8b/\xafo|}\x81`\xa88l\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc5-\x1a\fs\u00a1\xbe\x84\x91Q\x85\xf8\xb3O\xaa\n\xdf\x1d\xe3\x89K\xe4\xea\xb3\xfa\x0f\xa6\x80\x00\xe0\x94\xc55\x94\xc7\u03f2\xa0\x8f(L\xc9\u05e6;\xbd\xfc\v1\x972\x8a\nk#(\xff:b\xc0\x00\x00\u07d4\xc57I(\xcd\xf1\x93pTC\xb1L\xc2\r\xa4#G<\xd9\u03c9\a}\x10P\x9b\xb3\xaf\x80\x00\u07d4\xc58\xa0\xff(*\xaa_Ku\u03f6,p\x03~\xe6}O\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5;P\xfd;+r\xbclC\v\xaf\x19JQU\x85\u04d8m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc5=y\xf7\u02dbp\x95/\xd3\x0f\xceX\xd5K\x9f\vY\xf6G\x8a\x01\x13\xe2\xd6tCE\xf8\x00\x00\u07d4\xc5I\u07c3\xc6\xf6^\xec\x0f\x1d\u0260\x93J\\_:P\xfd\x88\x89\x9d\xc0\\\xce(\u00b8\x00\x00\u07d4\xc5P\x05\xa6\xc3~\x8c\xa7\xe5C\xce%\x99s\xa3\xca\u0396\x1aJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5U\xb91V\xf0\x91\x01#\x80\x00\xe0\x94\u0166)\xa3\x96%R\u02ce\xde\u0609cj\xaf\xbd\f\x18\xcee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u016e\x86\xb0\xc6\xc7\xe3\x90\x0f\x13h\x10\\VS\u007f\xaf\x8dt>\x89\n1\x06+\xee\xedp\x00\x00\u07d4\u0170\t\xba\xea\xf7\x88\xa2v\xbd5\x81:\xd6[@\v\x84\x9f;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0175l\xd24&|(\xe8\x9cok\"f\xb0\x86\xa1/\x97\f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xc5\u01a4\x99\x8a3\xfe\xb7dCz\x8b\xe9)\xa7;\xa3J\ad\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x94\xc5\xc7=a\xcc\xe7\xc8\xfeL\x8f\xce)\xf3\x90\x92\xcd\x19>\x0f\xff\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc5\xc7Y\vV!\xec\xf85\x85\x88\u079bh\x90\xf2baC\U000498a1]\tQ\x9b\xe0\x00\x00\u07d4\xc5\xcd\xce\xe0\xe8]\x11}\xab\xbfSj?@i\xbfD?T\xe7\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xc5\u050c\xa2\xdb/\x85\xd8\xc5U\xcb\x0e\x9c\xfe\x82i6x?\x9e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc5\xde\x12\x03\xd3\xcc,\xea1\xc8.\xe2\xdeY\x16\x88\a\x99\xea\xfd\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc5\xe4\x88\xcf+Vw\x939q\xf6L\xb8 -\xd0WR\xa2\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\xe8\x12\xf7o\x15\xf2\xe1\xf2\xf9\xbcH#H<\x88\x04cog\x89\x03\xf5\x14\x19:\xbb\x84\x00\x00\u07d4\xc5\u94d34\xf1%.\u04ba&\x81D\x87\xdf\u0498+1(\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xc5\xebB)^\x9c\xad\xea\xf2\xaf\x12\xde\u078a\x8dS\xc5y\xc4i\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xc5\xed\xbb\xd2\xca\x03WeJ\xd0\xeaG\x93\xf8\xc5\xce\xcd0\xe2T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc5\xf6K\xab\xb7\x031B\xf2\x0eF\u05eab\x01\xed\x86\xf6q\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\xf6\x87qrF\u068a \r \xe5\u9f2c`\xb6\u007f8a\x89\x01\x8d\x99?4\xae\xf1\x00\x00\u07d4\xc6\x04[<5\vL\xe9\xca\fkuO\xb4\x1ai\xb9~\x99\x00\x892$\xf4'#\xd4T\x00\x00\u07d4\xc6\v\x04eN\x00;F\x83\x04\x1f\x1c\xbdk\u00cf\xda|\xdb\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x14F\xb7T\xc2N;\x16B\xd9\xe5\x17e\xb4\xd3\xe4k4\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x18R\x13!\xab\xaf[&Q:J\x95(\bo\"\n\xdco\x89\x01v\xb3D\xf2\xa7\x8c\x00\x00\u07d4\xc6#FW\xa8\a8A&\xf8\x96\x8c\xa1p\x8b\xb0{\xaaI<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6%\xf8\u024d'\xa0\x9a\x1b\u02bdQ(\xb1\u00a9HV\xaf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc65^\xc4v\x8cp\xa4\x9a\xf6\x95\x13\u0343\xa5\xbc\xa7\xe3\xb9\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc6:\xc4\x17\x99.\x9f\x9b`8n\xd9S\xe6\xd7\xdf\xf2\xb0\x90\xe8\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xc6<\u05c8!\x18\xb8\xa9\x1e\aML\x8fK\xa9\x18Q0;\x9a\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xc6R\x87\x1d\x19$\"\u01bc#_\xa0c\xb4J~\x1dC\u3149\bg\x0e\x9e\xc6Y\x8c\x00\x00\xe0\x94\xc6gD\x1e\u007f)y\x9a\xbaadQ\xd5;?H\x9f\x9e\x0fH\x8a\x02\xf2\x9a\xceh\xad\u0740\x00\x00\u07d4\xc6j\xe4\xce\xe8\u007f\xb352\x19\xf7\u007f\x1dd\x86\u0140(\x032\x89\x01\x9a\x16\xb0o\xf8\xcb\x00\x00\u07d4\xc6t\xf2\x8c\x8a\xfd\a?\x8by\x96\x91\xb2\xf0XM\xf9B\xe8D\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0197\xb7\x04w\u02b4.+\x8b&f\x81\xf4\xaesu\xbb%A\x8a\x01.W2\xba\xba\\\x98\x00\x00\u07d4\u019b\x85U9\xce\x1b\x04qG(\xee\xc2Z7\xf3g\x95\x1d\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u019b\xe4@\x13Mb\x80\x98\x01D\xa9\xf6M\x84t\x8a7\xf3I\x89&\u009eG\u0104L\x00\x00\u07d4\u019df<\x8d`\x90\x83\x91\xc8\xd26\x19\x153\xfd\xf7wV\x13\x89\x1aJ\xba\"\\ t\x00\x00\u0794\u01a2\x86\xe0e\xc8_:\xf7H\x12\xed\x8b\u04e8\xce]%\xe2\x1d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\u01a3\x0e\xf5\xbb3 \xf4\r\xc5\xe9\x81#\rR\xae:\xc1\x93\"\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\u01ae(}\xdb\xe1\x14\x9b\xa1m\xdc\xcaO\xe0j\xa2\uaa48\xa9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xc7\xc1\x917\x98\x97\u075c\x9d\x9a3\x83\x9cJ_b\xc0\x89\r\x89\xd8\xd8T\xb2$0h\x80\x00\xe0\x94\xc6\xcdh\xec56,Z\xd8L\x82\xadN\xdc#!%\x91-\x99\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u07d4\xc6\u0615N\x8f?\xc53\xd2\xd20\xff\x02\\\xb4\xdc\xe1O4&\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xdb\u06de\xfd^\xc1\xb3xn\x06q\xeb\"y\xb2S\xf2\x15\xed\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc6\xdf u\xeb\xd2@\xd4Hi\u00bek\u07c2\xe6=N\xf1\xf5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6\xe2\xf5\xaf\x97\x9a\x03\xfdr:\x1bn\xfar\x83\x18\u03dc\x18\x00\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xc6\xe3$\xbe\xeb[6v^\xcdFB`\xf7\xf2`\x06\xc5\xc6.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\xe4\xcc\fr\x83\xfc\x1c\x85\xbcH\x13\xef\xfa\xafr\xb4\x98#\xc0\x89\x0f\x03\x1e\xc9\xc8}\xd3\x00\x00\xe0\x94\xc6\xee5\x93B)i5)\xdcA\u067bq\xa2IfX\xb8\x8e\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xc6\xfb\x1e\xe3t\x17\u0400\xa0\xd0H\x92;\u06ba\xb0\x95\xd0w\u0189\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc7\x05'\xd4D\u0110\xe9\xfc?\\\xc4Nf\xebO0k8\x0f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\r\x85mb\x1e\xc1E0<\nd\x00\xcd\x17\xbb\xd6\xf5\xea\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc7\x0f\xa4Uv\xbf\x9c\x86_\x988\x93\x00,AI&\xf6\x10)\x89\x15\xb4\xaa\x8e\x97\x02h\x00\x00\u07d4\xc7\x11E\xe5)\u01e7\x14\xe6y\x03\xeeb\x06\xe4\xc3\x04+g'\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xc7\x1b*=q5\u04a8_\xb5\xa5q\u073ei^\x13\xfcC\u034965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\x1f\x1du\x87?3\u0732\xddK9\x87\xa1-\a\x91\xa5\xce'\x897\b\xba\xed=h\x90\x00\x00\u07d4\xc7\x1f\x92\xa3\xa5J{\x8c/^\xa4C\x05\xfc\u02c4\xee\xe21H\x89\x02\xb5\x9c\xa11\xd2\x06\x00\x00\u07d4\xc7!\xb2\xa7\xaaD\xc2\x12\x98\xe8P9\xd0\x0e.F\x0eg\v\x9c\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xc7,\xb3\x01%\x8e\x91\xbc\b\x99\x8a\x80]\u0452\xf2\\/\x9a5\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc76\x8b\x97\t\xa5\xc1\xb5\x1c\n\xdf\x18ze\xdf\x14\xe1+}\xba\x8a\x02\x02o\xc7\u007f\x03\u5b80\x00\u07d4\xc79%\x9e\u007f\x85\xf2e\x9b\xef_`\x9e\xd8k=Yl \x1e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc7>!\x12(\"\x15\xdc\ab\xf3+~\x80}\xcd\x1az\xae>\x8a\x01v\f\xbcb;\xb3P\x00\x00\xe0\x94\xc7If\x80B\xe7\x11#\xa6H\x97^\b\xedc\x82\xf8>\x05\xe2\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xc7J9\x95\xf8\a\xde\x1d\xb0\x1a.\xb9\xc6.\x97\xd0T\x8fio\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7Pl\x10\x19\x12\x1f\xf0\x8a,\x8c\x15\x91\xa6^\xb4\xbd\xfbJ?\x89 \x86\xac5\x10R`\x00\x00\u07d4\xc7\\7\xce-\xa0k\xbc@\b\x11Y\u01ba\x0f\x97n9\x93\xb1\x89:y#\x15\x1e\xcfX\x00\x00\u07d4\xc7]\"Y0j\xec}\xf0\"v\x8ci\x89\x9ae!\x85\xdb\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7`\x97\x1b\xbc\x18\x1cj|\xf7tA\xf2BG\u045c\xe9\xb4\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc7a0\xc7<\xb9!\x028\x02\\\x9d\xf9]\v\xe5J\xc6\u007f\xbe\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xc7e\xe0\x04v\x81\tG\x81j\xf1B\xd4m.\u7f28\xccO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc7g^VG\xb9\xd8\xda\xf4\xd3\xdf\xf1\xe5R\xf6\xb0qT\xac8\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xc7{\x01\xa6\xe9\x11\xfa\x98\x8d\x01\xa3\xab3dk\xee\xf9\xc18\xf3\x89'\x1bo\xa5\xdb\xe6\xcc\x00\x00\u07d4\u01c3z\u0420\xbf\x14\x18i7\xac\xe0lUF\xa3j\xa5OF\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01d8\x06\x03+\xc7\xd8(\xf1\x9a\u01a6@\u018e=\x82\x0f\xa4B\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u01d9\xe3N\x88\xff\x88\xbe}\xe2\x8e\x15\xe4\xf2\xa6=\v3\xc4\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u01ddPb\u01d6\xddwa\xf1\xf1>U\x8ds\xa5\x9f\x82\xf3\x8b\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\u01e0\x18\xf0\x96\x8aQ\xd1\xf6`<\\I\xdcT[\xcb\x0f\xf2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01ef\xf9\x19)yt\x89UZ/\xf1\xd1M\\iZ\x10\x83U\x8965\u026d\xc5\u07a0\x00\x00\u0794\u01f1\xc8>c ?\x95G&>\xf6(.}\xa3;n\xd6Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\u01f3\x9b\x06\x04Q\x00\f\xa1\x04\x9b\xa1T\xbc\xfa\x00\xff\x8a\xf2b\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\u01ff\x17\xc4\xc1\x1f\x98\x94\x1fP~w\bO\xff\xbd-\xbd=\xb5\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u01ff.\xd1\xed1)@\xeej\xde\xd1Qn&\x8eJ`HV\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc7\xd4O\xe3,\u007f\x8c\xd5\xf1\xa9t'\xb6\xcd:\xfc\x9eE\x02>\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xc7\xd5\xc7\x05@\x81\xe9\x18\xech{Z\xb3n\x97=\x18\x13)5\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xc7\xde^\x8e\xaf\xb5\xf6+\x1a\n\xf2\x19\\\xf7\x93\u01c9L\x92h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\xe30\xcd\f\x89\n\u025f\xe7q\xfc\xc7\xe7\xb0\t\xb7A=\x8a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\xea\xc3\x1a\xbc\xe6\xd5\xf1\u07a4\"\x02\xb6\xa6t\x15=\xb4z)\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc7\xecb\xb8\x04\xb1\xf6\x9b\x1e0p\xb5\xd3b\xc6/\xb3\t\xb0p\x8a\x02\xc4k\xf5A`f\x11\x00\x00\u07d4\xc7\xf7+\xb7X\x01k7G\x14\u0509\x9b\xce\"\xb4\xae\xc7\n1\x89:&\xc9G\x8f^-\x00\x00\u0794\xc8\v6\u047e\xaf\xba_\xccdM`\xacnF\xed)'\xe7\u0708\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xc8\x11\xc2\xe9\xaa\x1a\xc3F.\xba^\x88\xfc\xb5\x12\x0e\x9fn,\xa2\x89K\xe6\u0607\xbd\x87n\x00\x00\u07d4\xc8\x17\xdf\x1b\x91\xfa\xf3\x0f\xe3%\x15qr|\x97\x11\xb4]\x8f\x06\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xc8\x1f\xb7\xd2\x0f\u0480\x01\x92\xf0\xaa\xc1\x98\xd6\u05a3}?\xcb}\x89\x0e\x11I3\x1c-\xde\x00\x00\u07d4\xc8 \xc7\x11\xf0w\x05'8\a\xaa\xaam\xe4M\x0eKH\xbe.\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4\xc8#\x1b\xa5\xa4\x11\xa1>\"+)\xbf\xc1\b?v1X\xf2&\x8967\tlK\xcci\x00\x00\u07d4\xc86\xe2Jo\xcf)\x94;6\b\xe6b)\n!_e)\xea\x89\x0f\xd4Pd\xea\xee\x10\x00\x00\xe0\x94\xc8;\xa6\u0755I\xbe\x1d2\x87\xa5\xa6T\xd1\x06\xc3Lk]\xa2\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc8>\x9djX%;\uefb7\x93\xe6\xf2\x8b\x05JXI\x1bt\x89\x0fF\u00b6\xf5\xa9\x14\x00\x00\u07d4\xc8A\x88O\xa4x_\xb7s\xb2\x8e\x97\x15\xfa\xe9\x9aQ40]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8M\x9b\xea\n{\x9f\x14\x02 \xfd\x8b\x90\x97\u03ff\xd5\xed\xf5d\x89\x06\xab\x9e\u0091\xad}\x80\x00\u07d4\xc8RB\x8d+Xd\x97\xac\xd3\fV\xaa\x13\xfbU\x82\xf8D\x02\x893B\xd6\r\xff\x19`\x00\x00\u07d4\xc8S![\x9b\x9f-,\xd0t\x1eX^\x98{_\xb8\f!.\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc8S%\uaca5\x9b>\xd8c\xc8j_)\x06\xa0B)\xff\xa9\x89\x19=\u007f}%=\xe0\x00\x00\u07d4\xc8^\xf2}\x82\x04\x03\x80_\xc9\xed%\x9f\xffd\xac\xb8\xd64j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8akN\xc0\x91(\xcd\xff9\xd6\u4e6c\x86\xee\xc4q\xd5\xf2\x89\x01\r:\xa56\xe2\x94\x00\x00\xe0\x94\xc8a\x90\x90K\x8d\a\x9e\xc0\x10\xe4b\xcb\xff\xc9\b4\xff\xaa\\\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4\xc8q\r~\x8bZ;\u059aB\xfe\x0f\xa8\xb8|5\u007f\xdd\xcd\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc8sR\u06e5\x82\xee f\xb9\xc0\x02\xa9b\xe0\x03\x13Ox\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xc8|w\xe3\xc2J\xde\xcd\xcd\x108\xa3\x8bV\xe1\x8d\xea\u04f7\x02\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xc8}:\xe3\u0607\x04\u066b\x00\t\xdc\xc1\xa0\x06q1\xf8\xba<\x89j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\u0201N4R>8\xe1\xf9'\xa7\xdc\xe8FjDz\t6\x03\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0202U\xed\xdc\xf5!\xc6\xf8\x1d\x97\xf5\xa4!\x81\xc9\a=N\xf1\x89\x0f\u00d0D\xd0\n*\x80\x00\u07d4\u0205\xa1\x8a\xab\xf4T\x1b{{~\xcd0\xf6\xfa\u619d\x95i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u020c\xa1\xe6\xe5\xf4\xd5X\xd17\x80\xf4\x88\xf1\rJ\xd3\x13\r4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u020e\xecT\xd3\x05\xc9(\xcc(H\xc2\xfe\xe251\xac\xb9mI\x89lj\u04c2\xd4\xfba\x00\x00\xe0\x94\u021c\xf5\x04\xb9\xf3\xf85\x18\x1f\xd8BO\\\xcb\xc8\xe1\xbd\xdf}\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0222\xc4\xe5\x9e\x1c\u007f\xc5H\x05X\x048\xae\xd3\xe4J\xfd\xf0\x0e\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\u022aI\u301f\b\x99\xf2\x8a\xb5~gCp\x9dXA\x903\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\u022b\x1a<\xf4l\xb8\xb0d\xdf.\"-9`s\x94 2w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0231\x85\x05%\xd9F\xf2\xae\x84\xf3\x17\xb1Q\x88\xc56\xa5\u0706\x89\x91\x8d\xdc:B\xa3\xd4\x00\x00\u07d4\xc8\xd4\xe1Y\x9d\x03\xb7\x98\t\xe0\x13\n\x8d\u00c4\b\xf0^\x8c\u04c9\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xc8\xdd'\xf1k\xf2$P\xf5w\x1b\x9f\xe4\xedO\xfc\xb3\t6\xf4\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xc8\xdezVL\u007f@\x12\xa6\xf6\xd1\x0f\u040fG\x89\x0f\xbf\a\u0509\x10CV\x1a\x88)0\x00\x00\u07d4\xc8\xe2\xad\xebT^I\x9d\x98,\f\x11sc\u03b4\x89\u0171\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xc8\xe5X\xa3\xc5i~o\xb2:%\x94\u0200\xb7\xa1\xb6\x8f\x98`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc8\xf2\xb3 \xe6\xdf\xd7\t\x06\u0157\xba\xd2\xf9P\x13\x12\u01c2Y\x89Q\x93K\x8b:W\xd0\x00\x00\u07d4\xc9\x03\x00\xcb\x1d@w\xe6\xa6\xd7\xe1i\xa4`F\x8c\xf4\xa4\x92\u05c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\f7e\x15k\u028eH\x97\xab\x80$\x19\x15<\xbeR%\xa9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc9\x10\xa9pUl\x97\x16\xeaS\xaff\xdd\xef\x93\x141$\x91=\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94\xc9\x12{\u007ff)\xee\x13\xfc?`\xbc/Dg\xa2\aE\xa7b\x8a\x03|\x9a\xa4\xe7\xceB\x1d\x80\x00\u07d4\xc9\x1b\xb5b\xe4+\xd4a0\xe2\u04eeFR\xb6\xa4\ub1bc\x0f\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\xe0\x94\xc90\x88y\x05m\xfe\x13\x8e\xf8 \x8fy\xa9\x15\u01bc~p\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xc94\xbe\xca\xf7\x1f\"_\x8bJK\xf7\xb1\x97\xf4\xac\x9604\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9?\xbd\xe8\xd4m+\xcc\x0f\xa9\xb3;\u063a\u007f\x80B\x12Ue\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xc9@\x89U:\xe4\xc2,\xa0\x9f\xbc\x98\xf5pu\xcf.\u0155\x04\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc9A\x10\xe7\x1a\xfeW\x8a\xa2\x18\xe4\xfc(d\x03\xb03\n\u038d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc9F\u056c\xc14n\xba\nry\xa0\xac\x1dF\\\x99m\x82~\x8a\x03x=T_\xdf\n\xa4\x00\x00\u07d4\xc9J(\xfb20\xa9\xdd\xfa\x96Nw\x0f,\xe3\xc2S\xa7\xbeO\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc9JXR\x03\xda{\xba\xfd\x93\xe1X\x84\xe6`\u0531\xea\xd8T\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc9O|5\xc0'\xd4}\xf8\xefO\x9d\xf8Z\x92H\xa1}\xd2;\x89\x01\x9f\x8euY\x92L\x00\x00\u07d4\xc9Q\x90\f4\x1a\xbb\xb3\xba\xfb\xf7\xee )7pq\xdb\xc3j\x89\x11\xc2]\x00M\x01\xf8\x00\x00\u07d4\xc9S\xf94\xc0\xeb-\x0f\x14K\u06b0\x04\x83\xfd\x81\x94\x86\\\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9f&r\x8a\xaaLO\xb3\xd3\x1c&\xdf:\xf3\x10\b\x17\x10\u0449\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xc9gQel\n\x8e\xf45{sD2!4\xb9\x83PJ\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\u0240Hh\u007f+\xfc\u027d\x90\xed\x18slW\xed\xd3R\xb6]\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0241\xd3\x12\u0487\xd5X\x87\x1e\u0757:\xbbv\xb9y\xe5\xc3^\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0242Xmc\xb0\xd7L \x1b\x1a\xf8A\x83r\xe3\fv\x16\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u0249CO\x82Z\xaf\x9cU/h^\xba|\x11\xdbJ_\xc7:\x89\x1b(\u014d\x96\x96\xb4\x00\x00\u07d4\u0249\xee\xc3\a\u80db\x9dr7\xcf\xda\b\x82)b\xab\u41c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u0252\xbeY\xc6r\x1c\xafN\x02\x8f\x9e\x8f\x05\xc2\\UQ[\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0255{\xa9L\x1b)\xe5'~\xc3f\"pI\x04\xc6=\xc0#\x89h>\xfcg\x82d,\x00\x00\xe0\x94\u025a\x9c\xd6\xc9\xc1\xbe54\xee\u0352\xec\xc2/\\8\xe9Q[\x8a\x01\x05Y;:\x16\x9dw\x00\x00\xe0\x94\u026c\x01\xc3\xfb\t)\x03?\f\xcc~\x1a\xcf\uaae7\x94]G\x8a\x02\xa3j\x9e\x9c\xa4\xd2\x03\x80\x00\u07d4\u0276\x98\xe8\x98\xd2\rMO@\x8eNM\x06\x19\"\xaa\x85c\a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u0276\xb6\x86\x11\x16\x91\xeej\xa1\x97\xc7#\x1a\x88\xdc`\xbd)]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\u01ec\v\u0753B\xb5\xea\xd46\t#\xf6\x8cr\xa6\xbac:\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\xc8\r\xc1.{\xab\x86\xe9I\xd0\x1eL>\xd3_+\x9b\xba_\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\xd7dF\u056a\xdf\xf8\vh\xb9\x1b\b\u035b\xc8\xf5U\x1a\xc1\x89&\xb4\xbd\x91\x10\xdc\xe8\x00\x00\xe0\x94\xc9\u073b\x05oM\xb7\xd9\xda9\x93b\x02\u017d\x820\xb3\xb4w\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9\xe0&\b\x06h(\x84\x8a\xeb(\xc76r\xa1)%\x18\x1fM\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xca\x042\xcb\x15{Qy\xf0.\xbb\xa5\xc9\u0475O\xecM\x88\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xca\x12,\xf0\U00094216\xb7HC\xf4\x9a\xfe\u043a\x16\x18\xee\u05c9\x1e[\x8f\xa8\xfe*\xc0\x00\x00\xe0\x94\xca\"\u0363`m\xa5\xca\xd0\x13\xb8\aG\x06\xd7\xe9\xe7!\xa5\f\x8a\x01q\x81\xc6\xfa9\x81\x94\x00\x00\u07d4\xca#\xf6-\xff\rd`\x03lb\xe8@\xae\xc5W~\v\xef\u0489\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xca%\xff4\x93L\x19B\xe2*N{\xd5o\x14\x02\x1a\x1a\xf0\x88\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xca7?\xe3\xc9\x06\xb8\xc6U\x9e\xe4\x9c\xcd\a\xf3|\xd4\xfbRf\x89a\t=|,m8\x00\x00\u07d4\xcaA\u032c0\x17 R\xd5\"\xcd//\x95}$\x81S@\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xcaB\x88\x01N\xdd\xc5c/_\xac\xb5\xe3\x85\x17\xa8\xf8\xbc]\x98\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xcaB\x88c\xa5\xca06\x98\x92\xd6\x12\x18>\xf9\xfb\x1a\x04\xbc\xea\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xcaI\xa5\xf5\x8a\xdb\xef\xae#\xeeY\xee\xa2A\xcf\x04\x82b.\xaa\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcaL\xa9\xe4w\x9dS\x0e\u02ec\xd4~j\x80X\xcf\xdee\u064f\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xcae~\xc0o\xe5\xbc\t\xcf#\xe5*\xf7\xf8\f\xc3h\x9en\u07890\xca\x02O\x98{\x90\x00\x00\u07d4\xcaf\xb2(\x0f\xa2\x82\u0176v1\xceU+b\xeeU\xad\x84t\x89j\xc4\"\xf54\x92\x88\x00\x00\xe0\x94\xcal\x81\x8b\xef\xd2Q6\x1e\x02t@h\xbe\x99\u062a`\xb8J\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcap\xf4\u077f\x06\x9d!C\xbdk\xbc\u007fikRx\x9b2\u7262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xcatuvDjL\x8f0\xb0\x83@\xfe\xe1\x98\xdec\xec\x92\u03ca\x01|\x8e\x12\x06r*0\x00\x00\u07d4\xca{\xa3\xffSl~_\x0e\x158\x00\xbd8=\xb81)\x98\xe0\x89\t1\xac=k\xb2@\x00\x00\xe0\x94\u0282v\xc4w\xb4\xa0{\x80\x10{\x845\x94\x18\x96\a\xb5;\xec\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u0284\t\b>\x01\xb3\x97\xcf\x12\x92\x8a\x05\xb6\x84U\xceb\x01\u07c9V\xbcu\xe2\xd61\x00\x00\x00\u07d4\u0298\u01d8\x8e\xfa\b\xe9%\uf719ER\x03&\xe9\xf4;\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u029a\x04*j\x80o\xfc\x92\x17\x95\x00\xd2D)\xe8\xabR\x81\x17\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\u029d\xec\x02\x84\x1a\xdf\\\xc9 WjQ\x87\xed\u04bdCJ\x18\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u029f\xaa\x17T/\xaf\xbb8\x8e\xab!\xbcL\x94\u89f3G\x88\x89lk\x8f\xce\r\x18y\x80\x00\xe0\x94\u02aah\xeel\xdf\r4EJv\x9b\r\xa1H\xa1\xfa\xaa\x18e\x8a\x01\x87.\x1d\xe7\xfeR\xc0\x00\x00\u07d4\u02ad\x9d\xc2\rX\x9c\xe4(\xd8\xfd\xa3\xa9\xd5:`{y\x88\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u02b0\xd3,\xf3v\u007f\xa6\xb3S|\x842\x8b\xaa\x9fPE\x816\x8a\x01\xe5\xb8\xfa\x8f\xe2\xac\x00\x00\x00\u07d4\u02b9\xa3\x01\xe6\xbdF\xe9@5P(\xec\xcd@\xceMZ\x1a\u00c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u02b9\xa9z\xda\x06\\\x87\x81nh`\xa8\xf1Bo\xe6\xb3\xd7u\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u02ba\xb6'N\xd1P\x89s~({\xe8x\xb7W\x93Hd\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u02bd\xaf5OG \xa4f\xa7d\xa5(\xd6\x0e:H*9<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xca\xcbg^\t\x96#T\x04\ufbfb.\u02c1R'\x1bU\xe0\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xca\xd1O\x9e\xbb\xa7f\x80\xeb\x83k\a\x9c\u007f{\xaa\xf4\x81\xedm\x89\f\xef={\xd7\xd04\x00\x00\xe0\x94\xca\xe3\xa2S\xbc\xb2\xcfN\x13\xba\x80\u0098\xab\x04\x02\xda|*\xa0\x8a\x01$\xbc\r\u0752\xe5`\x00\x00\u07d4\xca\xef\x02{\x1a\xb5\x04\xc7?A\xf2\xa1\ty\xb4t\xf9~0\x9f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xca\xf4H\x1d\x9d\xb7\x8d\xc4\xf2_{J\u023d;\x1c\xa0\x10k1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xca\xfd\xe8U\x86L%\x98\xda<\xaf\xc0Z\u064d\U00089380H\x8a\x03\x00\xa8\xed\x96\xffJ\x94\x00\x00\xe0\x94\xcb\r\xd7\xcfN]\x86a\xf6\x02\x89C\xa4\xb9\xb7\\\x91D6\xa7\x8a\x19i6\x89t\xc0[\x00\x00\x00\u07d4\xcb\x1b\xb6\xf1\xda^\xb1\rH\x99\xf7\xe6\x1d\x06\xc1\xb0\x0f\u07f5-\x898E$\xccp\xb7x\x00\x00\u07d4\xcb=vl\x98?\x19+\xce\xca\xc7\x0fN\xe0=\xd9\xffqMQ\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcbB\xb4N\xb5\xfd`\xb5\x83~O\x9e\xb4rgR=\x1a\"\x9c\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xcbG\xbd0\u03e8\xecTh\xaa\xa6\xa9FB\xce\xd9\xc8\x19\xc8\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcbH\xfe\x82e\u066fU\xebp\x06\xbc3VE\xb0\xa3\xa1\x83\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xcbJ\x91M+\xb0)\xf3._\xef\\#LO\xec--\xd5w\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcbJ\xbf\u0082\xae\xd7n]W\xaf\xfd\xa5B\xc1\xf3\x82\xfc\xac\xf4\x8a\x01\xb9\x0f\x11\xc3\x18?\xaa\x00\x00\u07d4\xcbJ\xd0\xc7#\xdaF\xabV\xd5&\xda\f\x1d%\xc7=\xaf\xf1\n\x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\xcbK\xb1\xc6#\xba(\xdcB\xbd\xaa\xa6\xe7N\x1d*\xa1%l*\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xcbPXt\x12\x82#\x04\xeb\u02e0}\xab:\x0f\t\xff\xfe\u4189JD\x91\xbdm\xcd(\x00\x00\u07d4\xcbX\x99\v\u0350\u03ffm\x8f\t\x86\xf6\xfa`\x02v\xb9N-\x8964\xbf9\xab\x98x\x80\x00\u07d4\xcbh\xaeZ\xbe\x02\xdc\xf8\xcb\u016aq\x9c%\x81FQ\xaf\x8b\x85\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xcbty\x10\x9bC\xb2fW\xf4F_M\x18\xc6\xf9t\xbe_B\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xcb}+\x80\x89\xe91,\u026e\xaa's\xf3S\b\xecl*{\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u02c6\xed\xbc\x8b\xbb\x1f\x911\x02+\xe6IV^\xbd\xb0\x9e2\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u02d3\x19\x9b\x9c\x90\xbcI\x15\xbd\x85\x9e=B\x86m\xc8\xc1\x87I\x89\f\x90\xdf\a\xde\xf7\x8c\x00\x00\u07d4\u02d4\xe7o\xeb\xe2\b\x11g3\xe7n\x80]H\xd1\x12\xec\x9f\u028965\u026d\xc5\u07a0\x00\x00\u07d4\u02dbQ\x03\xe4\u0389\xafOd\x91aP\xbf\xf9\xee\u02df\xaa\\\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\\zP<\xc8\xe0\xd0Iq\xca\x05\xc7b\xf9\xb7b\xb4\x8b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\x88\xcd<\x1e\xb4\u055d\xdb\x06\xa6B\x1c\x14\xc3E\xa4{$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u02f3\x18\x9eK\xd7\xf4_\x17\x8b\x1c0\xc7n&1MJK\n\x89\x0f\xfe\vg|e\xa9\x80\x00\xe0\x94\u02f7\xbe\x17\x95?,\u0313\u1f19\x80[\xf4U\x11CNL\x8a\n\xae[\x9d\xf5m/ \x00\x00\xe0\x94\xcb\xc0KM\x8b\x82\xca\xf6p\x99o\x16\f6)@\xd6o\xcf\x1a\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcb\u07974\xb8\xe6\xaaS\x8c)\x1dm\u007f\xac\xed\xb0\xf38\xf8W\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcb\xe1\xb9H\x86M\x84t\xe7e\x14XX\xfc\xa4U\x0fxK\x92\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xe5/\xc53\xd7\xdd`\x8c\x92\xa2`\xb3|?E\u07b4\xeb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcb\xe8\x10\xfe\x0f\xec\xc9dGJ\x1d\xb9w(\xbc\x87\xe9s\xfc\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xf1j\x0f\xe2tRX\xcdR\xdb+\xf2\x19T\xc9u\xfcj\x15\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\xcb\xf3\u007f\xf8T\xa2\xf1\xceS\x93D\x94wx\x92\xd3\xeceW\x82\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xfaj\xf6\u0083\xb0F\xe2w,`c\xb0\xb2\x15S\xc4\x01\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcb\xfav\xdb\x04\xce8\xfb ]7\xb8\xd3w\xcf\x13\x80\xda\x03\x17\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcc\x03I\x85\xd3\xf2\x8c-9\xb1\xa3K\xce\xd4\u04f2\xb6\xca#N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xcc\x04\x8d\u01f9]\xca%\xdf&\xee\xfac\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc+_D\x8f5(\xd3\xfeA\xcc}\x1f\xa9\xc0\xdcv\xf1\xb7v\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc-\x04\xf0\xa4\x01q\x89\xb3@\xcaw\x19\x86A\xdc\xf6Ek\x91\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xccA\x9f\u0651+\x85\x13VY\xe7z\x93\xbc=\xf1\x82\xd4Q\x15\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccE\xfb:U[\xad\x80{8\x8a\x03W\xc8U _|u\xe8\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xccHAM*\xc4\xd4*Yb\xf2\x9e\xeeD\x97\t/C\x13R\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\xccJ/,\xf8l\xf3\xe43u\xf3`\xa4sF\x91\x19_\x14\x90\x89I\x15\x05;\xd1)\t\x80\x00\u07d4\xccO\x0f\xf2\xae\xb6}T\xce;\xc8\xc6Q\v\x9a\xe8>\x9d2\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xccO\xaa\xc0\v\xe6b\x8f\x92\xefk\x8c\xb1\xb1\xe7j\xac\x81\xfa\x18\x89\v\"\xa2\xea\xb0\xf0\xfd\x00\x00\xe0\x94\xccO\xebr\u07d8\xff5\xa18\xe0\x17a\xd1 ?\x9b~\xdf\n\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xcc`oQ\x13\x97\xa3\x8f\u01c7+\u04f0\xbd\x03\xc7\x1b\xbdv\x8b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcc`\xf86\xac\xde\xf3T\x8a\x1f\xef\u0321>\u01a97\xdbD\xa0\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\xccl\x03\xbd`>\t\xdeT\xe9\xc4\u056cmA\xcb\xceqW$\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xccl-\xf0\x0e\x86\xec\xa4\x0f!\xff\xda\x1ag\xa1i\x0fG|e\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\xccm{\x12\x06\x1b\xc9m\x10M`me\xff\xa3+\x006\xeb\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccs\xdd5kIy\xb5y\xb4\x01\xd4\xccz1\xa2h\xdd\xceZ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xccu\x8d\a\x1d%\xa62\n\xf6\x8c]\xc9\xc4\xf6\x95[\xa9E \x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcc{\x04\x81\xcc2\xe6\xfa\xef#\x86\xa0p\"\xbc\xb6\xd2\u00f4\xfc\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\u0314;\xe1\",\xd1@\n#\x99\xdd\x1bE\x94E\xcfmT\xa9\x8a\x02\xa7@\xaee6\xfc\x88\x00\x00\u07d4\u0315\x19\xd1\xf3\x98_k%^\xad\xed\x12\xd5bJ\x97'!\xe1\x8965\u026d\xc5\u07a0\x00\x00\u0794\u031a\xc7\x15\xcdo&\x10\xc5+XgdV\x88B\x97\x01\x8b)\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\u0320{\xb7\x94W\x1dJ\xcf\x04\x1d\xad\x87\xf0\xd1\xef1\x85\xb3\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u032b\xc6\x04\x8aSFD$\xfc\xf7n\xeb\x9en\x18\x01\xfa#\u0509\x02\xab{&\x0f\xf3\xfd\x00\x00\u07d4\u032e\r=\x85*}\xa3\x86\x0f\x066\x15L\nl\xa3\x16(\u0509\x05\xc6\xd1+k\xc1\xa0\x00\x00\u07d4\xcc\xca$\xd8\xc5mn,\a\xdb\bn\xc0~X[\xe2g\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcc\xd5!\x13-\x98l\xb9hi\x84&\"\xa7\u0762l>\xd0W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc\xf49u\xb7k\xfes_\xec<\xb7\xd4\xdd$\xf8\x05\xba\tb\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc\xf6*f?\x13S\xba.\xf8\xe6R\x1d\xc1\xec\xb6s\xec\x8e\xf7\x89\b=lz\xabc`\x00\x00\u07d4\xcc\xf7\x11\r\x1b\u0667K\xfd\x1d}}-\x9dU`~{\x83}\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xcc\xfdrW`\xa6\x88#\xff\x1e\x06/L\xc9~\x13`\xe8\u0657\x89\x15\xacV\xed\xc4\xd1,\x00\x00\u07d4\xcd\x02\x0f\x8e\xdf\xcfRG\x98\xa9\xb7:d\x034\xbb\xf7/\x80\xa5\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xcd\x06\xf8\xc1\xb5\u037d(\xe2\xd9kcF\xc3\xe8Z\x04\x83\xba$\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcd\a.n\x183\x13y\x95\x19m{\xb1r_\xef\x87a\xf6U\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcd\n\x16\x1b\xc3g\xae\t'\xa9*\xac\x9c\xf6\xe5\bg\x14\xef\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\n\xf3GN\"\xf0i\xec4\a\x87\r\xd7pD=[\x12\xb0\x89\x8e^\xb4\xeew\xb2\xef\x00\x00\u07d4\xcd\v\x02W\u70e3\xd2\xc2\u3e9dny\xb7^\xf9\x80$\u0509\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xcd\x10,\xd6\xdb=\xf1J\u05af\x0f\x87\xc7$y\x86\x1b\xfc=$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\x1ef\xedS\x9d\xd9/\xc4\v\xba\xa1\xfa\x16\u078c\x02\xc1ME\x89\fw\xe4%hc\xd8\x00\x00\u07d4\xcd\x1e\xd2c\xfb\xf6\xf6\xf7\xb4\x8a\xef\x8fs=2\x9dC\x82\xc7\u01c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4\xcd*6\xd7S\xe9\xe0\xed\x01*XMqh\aX{A\xd5j\x89\x0e+\xa7[\v\x1f\x1c\x00\x00\u07d4\xcd2\xa4\xa8\xa2\u007f\x1c\xc69T\xaacOxW\x05s4\u01e3\x89:\xd1fWlr\xd4\x00\x00\u07d4\xcd5\xff\x01\x0e\xc5\x01\xa7!\xa1\xb2\xf0z\x9c\xa5\x87}\xfc\xf9Z\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xcdC\x06\xd7\xf6\x94z\xc1tMN\x13\xb8\xef2\xcbe~\x1c\x00\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4\xcdC%\x8bs\x92\xa90\x83\x9aQ\xb2\xef\x8a\xd24\x12\xf7Z\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcdI\xbf\x18^p\xd0E\a\x99\x9f\x92\xa4\xdeDU1('\u040965\u026d\xc5\u07a0\x00\x00\u07d4\xcdU\x10\xa2B\u07f0\x18=\xe9%\xfb\xa8f\xe3\x12\xfa\xbc\x16W\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xcdVj\u05f8\x83\xf0\x1f\u04d9\x8a\x9aX\xa9\xde\xe4rM\u0725\x89\x030\xae\x185\xbe0\x00\x00\xe0\x94\xcdY\xf3\xdd\xe7~\t\x94\v\xef\xb6\xeeX\x03\x19e\xca\xe7\xa36\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcdr]p\xbe\x97\xe6w\xe3\xc8\xe8\\\v&\xef1\xe9\x95PE\x89Hz\x9a0E9D\x00\x00\xe0\x94\xcd~G\x90\x94d\xd8q\xb9\xa6\xdcv\xa8\xe9\x19]\xb3H^z\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xcd~\xce\bkKa\x9b;6\x93R\xee8\xb7\x1d\xdb\x06C\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcd\u007f\t\xd7\xedf\xd0\u00cb\u016dN2\xb7\xf2\xb0\x8d\xc1\xb3\r\x89>;\xb3M\xa2\xa4p\x00\x00\u07d4\u0355)I+\\)\xe4u\xac\xb9A@+=;\xa5\x06\x86\xb0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0355\xfaB=o\xc1 'J\xac\xde\x19\xf4\xee\xb7f\xf1\x04 \x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u035bL\xefs9\f\x83\xa8\xfdq\u05f5@\xa7\xf9\u03cb\x8c\x92\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\u0361t\x11\t\xc0&[?\xb2\xbf\x8d^\xc9\u00b8\xa34kc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0361\xb8\x86\u39d5\u027aw\x91N\n/\xe5go\x0f\\\u03c9\x05\xbf`\xeaB\xc2\x04\x00\x00\u07d4\u0364S\x0fK\x9b\xc5\t\x05\xb7\x9d\x17\u008f\xc4o\x954\x9b\u07c93\x10\xe0I\x11\xf1\xf8\x00\x00\u07d4\u036bF\xa5\x90 \x80do\xbf\x95B\x04 J\xe8\x84\x04\x82+\x89\x1d\x8a\x96\xe5\xc6\x06\xeb\x00\x00\u07d4\u0375\x97)\x900\x18?n-#\x853\xf4d*\xa5\x87T\xb6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xcd\xd5\u0601\xa76,\x90p\a;\u07fcu\xe7$S\xacQ\x0e\x89-\xa5\x18\xea\xe4\x8e\xe8\x00\x00\u07d4\xcd\xd6\rs\xef\xaa\xd8s\u027b\xfb\x17\x8c\xa1\xb7\x10Z\x81\xa6\x81\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xcd\xd9\xef\xacMm`\xbdq\xd9U\x85\xdc\xe5\u0557\x05\xc15d\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcd\xe3m\x81\xd1(\u015d\xa1Ee!\x93\xee\u00bf\xd9e\x86\xef\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcd\xea8o\x9d\x0f\xd8\x04\xd0(\x18\xf27\xb7\xd9\xfavF\xd3^\x89\xa3I\xd3m\x80\xecW\x80\x00\u07d4\xcd\xec\xf5gT3\u0370\xc2\xe5Zh\xdb]\x8b\xbexA\x9d\u0489\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xcd\xfd\x82\x173\x97%\xd7\xeb\xac\x11\xa66U\xf2e\xef\xf1\xcc=\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce\a\x9fQ\x88wt\xd8\x02\x1c\xb3\xb5u\xf5\x8f\x18\xe9\xac\xf9\x84\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xce\x18\x84\u077b\xb8\xe1\x0eM\xbanD\xfe\xee\u00a7\xe5\xf9/\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\x1b\f\xb4j\xae\xcf\u05db\x88\f\xad\x0f-\u068a\x8d\xed\u0431\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xce&\xf9\xa50_\x83\x81\tCT\xdb\xfc\x92fN\x84\xf9\x02\xb5\x89\fz\xaa\xb0Y\x1e\xec\x00\x00\u07d4\xce-\xea\xb5\x1c\n\x9a\xe0\x9c\xd2\x12\xc4\xfaL\xc5+S\xcc\r\xec\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xce.\r\xa8\x93F\x99\xbb\x1aU>U\xa0\xb8\\\x16\x945\xbe\xa3\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce:a\xf0F\x1b\x00\x93^\x85\xfa\x1e\xad\x82\xc4^Zd\u0508\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceK\x06]\xbc\xb20G 2b\xfbH\xc1\x18\x83d\x97tp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceS\xc8\xcd\xd7B\x96\xac\xa9\x87\xb2\xbc\x19\u00b8u\xa4\x87I\u0409\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xce^\x04\xf0\x18Ci\xbc\xfa\x06\xac\xa6o\xfa\x91\xbfY\xfa\x0f\xb9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xce^\xb6:{\xf4\xfb\xc2\xf6\u4ea0\u018a\xb1\xcbL\xf9\x8f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xceb\x12Z\xde\xc37\n\xc5!\x10\x95:Nv\v\xe9E\x1e;\x89\b=lz\xabc`\x00\x00\xe0\x94\xceq\bmL`%T\xb8-\xcb\xfc\xe8\x8d cMS\xccM\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4\u038akmP3\xb1I\x8b\x1f\xfe\xb4\x1aAU\x04\x05\xfa\x03\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0397\x86\xd3q/\xa2\x00\xe9\xf6\x857\xee\xaa\x1a\x06\xa6\xf4ZK\x89a\t=|,m8\x00\x00\u07d4\u039d!\u0192\xcd<\x01\xf2\x01\x1fP_\x87\x006\xfa\x8fl\u0489\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u03a2\x89f#\xf4\x91\x02\x87\xa2\xbd\u017e\x83\xae\xa3\xf2\xe6\xde\b\x8a\x01\xfbZ7Q\xe4\x90\xdc\x00\x00\u07d4\u03a3JM\xd9=\u066e\xfd9\x90\x02\xa9}\x99z\x1bK\x89\u0349QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\u03a4?pu\x81k`\xbb\xfc\u62d9:\xf0\x88\x12p\xf6\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\u03a8t3AS<\xb2\xf0\xb9\xc6\xef\xb8\xfd\xa8\rw\x16(%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u03b0\x89\xec\x8ax3~\x8e\xf8\x8d\xe1\x1bI\xe3\u0751\x0ft\x8f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u03b3=x\xe7Tz\x9d\xa2\xe8}Q\xae\xc5\xf3D\x1c\x87\x92:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u03b3\x898\x1dH\xa8\xaeO\xfcH:\u043b^ L\xfd\xb1\xec\x89('\xe6\xe4\xddb\xba\x80\x00\u07d4\xce\xc6\xfce\x85?\x9c\xce_\x8e\x84Fv6.\x15y\x01_\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xce\xd3\u01fe\x8d\xe7XQ@\x95*\xebP\x1d\xc1\xf8v\ucbf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\xd8\x1e\xc3S?\xf1\xbf\xeb\xf3\xe3\x84>\xe7@\xad\x11u\x8d>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xce\u0733\xa1\u0584?\xb6\xbe\xf6Ca}\xea\U000cf398\xdd_\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xce\xe6\x99\xc0pzx6%+)/\x04|\xe8\xad(\x9b/U\x89\x11\x9a\x1e!\xaaiV\x00\x00\u07d4\xce\xedG\xca[\x89\x9f\xd1b?!\xe9\xbdM\xb6Z\x10\u5c1d\x89\a8w@L\x1e\xee\x00\x00\u07d4\xce\xf7tQ\u07e2\xc6C\xe0\v\x15mlo\xf8N#s\xebf\x89\n1\x06+\xee\xedp\x00\x00\u07d4\xcf\x11i\x04\x1c\x17E\xe4[\x17$5\xa2\xfc\x99\xb4\x9a\xce+\x00\x89\x01\xbb\x88\xba\xab-|\x00\x00\xe0\x94\xcf\x15v\x12vN\x0f\u0596\xc8\xcb_\xba\x85\xdfL\r\xdc<\xb0\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u0794\xcf\x1b\xdby\x9b.\xa6<\xe14f\x8b\xdc\x19\x8bT\x84\x0f\x18\v\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xcf\"\x88\xefN\xbf\x88\xe8m\xb1=\x8a\x0e\v\xf5*\x05e\x82\u00c9\x89Po\xbf\x97@t\x00\x00\u07d4\xcf&Ni%\x13\t\x06\xc4\xd7\xc1\x85\x91\xaaA\xb2\xa6\u007foX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf&\xb4{\xd04\xbcP\x8elK\xcf\xd6\xc7\xd3\x004\x92Wa\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcf.*\xd65\xe9\x86\x1a\xe9\\\xb9\xba\xfc\xca\x03kR\x81\xf5\u038a\at2!~h6\x00\x00\x00\u07d4\xcf.s@B\xa3U\xd0_\xfb.9\x15\xb1h\x11\xf4Zi^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf4\x8f/\xe4{~A<\az{\xaf:u\xfb\xf8B\x86\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcf?\x91(\xb0r\x03\xa3\xe1\r}WU\xc0\u012b\xc6\xe2\xca\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xcf?\xbf\xa1\xfd2\u05e6\xe0\xe6\xf8\xefN\xabW\xbe4\x02\\L\x899\xa1\xc0\xf7YMH\x00\x00\u07d4\xcfAftn\x1d;\xc1\xf8\xd0qK\x01\xf1~\x8ab\xdf\x14d\x896w\x03n\xdf\n\xf6\x00\x00\u07d4\xcfO\x118\xf1\xbdk\xf5\xb6\u0505\xcc\xe4\xc1\x01\u007f\u02c5\xf0}\x89/\u043cw\xc3+\xff\x00\x00\u07d4\xcfZo\x9d\xf7Uy\xc6D\xf7\x94q\x12\x15\xb3\rw\xa0\xce@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf^\x0e\xac\u0473\x9d\x06U\xf2\xf7u5\xeff\b\xeb\x95\v\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcfhM\xfb\x83\x04r\x93U\xb5\x83\x15\xe8\x01\x9b\x1a\xa2\xad\x1b\xac\x89\x17r$\xaa\x84Lr\x00\x00\u07d4\xcfi@\x81\xc7m\x18\xc6L\xa7\x13\x82\xbe\\\xd6;<\xb4v\xf8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcfnR\xe6\xb7t\x80\xb1\x86~\xfe\xc6Dm\x9f\xc3\xcc5w\xe8\x89\f\t\x01\xf6\xbd\x98y\x00\x00\u07d4\u03c8: 2\x96g\xea\"j\x1e\x9a\x92*\x12\xf2\x1f\xaa\x03\x81V\x91\x8cO\u02dc\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xcf\xf7\xf8\x9aMB\x19\xa3\x82\x95%\x131V\x82\x10\xff\xc1\xc14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xcf\xf8\xd0k\x00\xe3\xf5\f\x19\x10\x99\xadV\xbaj\xe2eq\u0348\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcf\xfcI\xc1x~\ubcb5l\xab\xe9$\x04\xb66\x14}EX\x8a\x013\xe00\x8f@\xa3\u0680\x00\u07d4\xd0\bQ;'`J\x89\xba\x17c\xb6\xf8L\u6233F\x94[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x0f\x06r\x86\xc0\xfb\u0402\xf9\xf4\xa6\x10\x83\xecv\u07b3\xce\xe6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x15\xf6\xfc\xb8M\xf7\xbbA\x0e\x8c\x8f\x04\x89J\x88\x1d\xca\xc27\x898E$\xccp\xb7x\x00\x00\u07d4\xd0\x1a\xf9\x13O\xafRW\x17N\x8by\x18oB\xee5Nd-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0!\b\u04ae<\xab\x10\xcb\xcf\x16W\xaf\">\x02|\x82\x10\xf6\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xd0*\xfe\u03ce.\u00b6*\u022d Aa\xfd\x1f\xaew\x1d\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd01\x919\xfb\xab.\x8e*\xcc\xc1\xd9$\u0531\x1d\xf6ilZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd07\xd2\x15\xd1\x1d\x1d\xf3\xd5O\xbd2\x1c\u0495\xc5F^';\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xd0:-\xa4\x1e\x86\x8e\xd3\xfe\xf5t[\x96\xf5\xec\xa4b\xffo\u0689\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xd0?\xc1eWj\xae\xd5%\xe5P,\x8e\x14\x0f\x8b.\x86\x969\x8a\x01sV\u0633%\x01\xc8\x00\x00\u07d4\xd0C\xa0\x11\xecBp\xee~\u0239hsu\x15\xe5\x03\xf80(\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd0K\x86\x1b=\x9a\xccV:\x90\x16\x89\x94\x1a\xb1\xe1\x86\x11a\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd0ZD|\x91\x1d\xbb'[\xfb.Z7\xe5\xa7\x03\xa5o\x99\x97\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd0_\xfb+t\xf8g O\xe51e;\x02H\xe2\x1c\x13TN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0bX\x81q\u03d9\xbb\xebX\xf1&\xb8p\xf9\xa3r\x8da\xec\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\u07d4\xd0c\x8e\xa5q\x89\xa6\xa6\x99\x02J\u05ccq\xd99\xc1\xc2\xff\x8c\x89\x8e\xaeVg\x10\xfc \x00\x00\xe0\x94\xd0d\x8aX\x1b5\b\xe15\xa2\x93]\x12\xc9epE\xd8q\u028a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xd0q\x19)f\xebi\xc3R\x0f\xca:\xa4\xdd\x04)~\xa0KN\x89\x05\xf6\x8e\x811\xec\xf8\x00\x00\u07d4\xd0q\x85 \xea\xe0\xa4\xd6-p\xde\x1b\xe0\xcaC\x1c^\xea$\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd0w]\xba*\xf4\xc3\n:x6Y9\xcdq\xc2\xf9\u0795\u0489i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd0{\xe0\xf9\t\x97\xca\xf9\x03\u022c\x1dS\xcd\xe9\x04\xfb\x19\aA\x8968\x908\xb6\x99\xb4\x00\x00\u07d4\xd0~Q\x18d\xb1\u03d9i\xe3V\x06\x02\x82\x9e2\xfcNq\xf5\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u0400\x94\x98\xc5H\x04z\x1e**\xa6\xa2\x9c\xd6\x1a\x0e\xe2h\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0402'_tZ,\xac\x02v\xfb\xdb\x02\u0532\xa3\xab\x17\x11\xfe\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\u040f\xc0\x9a\x000\xfd\t(\xcd2\x11\x98X\x01\x82\xa7j\xae\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0413\xe8)\x81\x9f\xd2\xe2[\x978\x00\xbb=XA\xdd\x15-\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0414J\xa1\x85\xa13pa\xae \u071d\xd9l\x83\xb2\xbaF\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u0416V[|t\a\xd0e6X\x03U\xfd\xd6\xd29\x14J\xa1\x89\r\x8drkqw\xa8\x00\x00\u07d4\u041c\xb2\xe6\b-i:\x13\xe8\xd2\xf6\x8d\xd1\u0744a\xf5X@\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0426\xc6\xf9\xe9\u0133\x83\xd7\x16\xb3\x1d\xe7\x8dVAM\xe8\xfa\x91\x89\x10CV\x1a\x88)0\x00\x00\u07d4\u0427 \x9b\x80\xcf`\xdbb\xf5}\n]}R\x1ai`fU\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\u0428\xab\xd8\n\x19\x9bT\xb0\x8be\xf0\x1d \x9c'\xfe\xf0\x11[\x8a\x01a\xc6&\xdca\xa2\xef\x80\x00\xe0\x94\u042b\xccp\xc0B\x0e\x0e\x17/\x97\xd4;\x87\xd5\xe8\f3n\xa9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u042es]\x91^\x94hf\xe1\xfe\xa7~^\xa4f\xb5\xca\xdd\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0431\x1do+\u0394^\fjP \u00f5'S\xf8\x03\xf9\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xd0\xc1\x01\xfd\x1f\x01\xc6?k\x1d\x19\xbc\x92\r\x9f\x93#\x14\xb16\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd0\xc5Z\xbf\x97o\xdc=\xb2\xaf\u9f99\u0519HMWl\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\u0422\xadE\xf5\x9a\x9d\xcc\u0195\xd8_%\xcaF\xed1\xa5\xa3\x89-\x89W}}@ \x00\x00\u07d4\xd0\xd6,G\xea`\xfb\x90\xa3c\x92\t\xbb\xfd\xd4\xd93\x99\x1c\u0189\n\x84Jt$\xd9\xc8\x00\x00\u07d4\xd0\xdbEax o\\D0\xfe\x00Pc\x90<=zI\xa7\x89&I\x1eE\xa7S\xc0\x80\x00\u07d4\xd0\xe1\x94\xf3K\x1d\xb6\t(\x85\t\xcc\xd2\xe7;a1\xa2S\x8b\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xd0\xe3^\x04vF\xe7Y\xf4Qp\x93\xd6@\x86BQ\u007f\bM\x89\u054f\xa4h\x18\xec\u02c0\x00\u07d4\xd0\xeeM\x02\xcf$8,0\x90\xd3\xe9\x95`\xde6xs\\\u07c9\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xd0\xf0OR\x10\x9a\xeb\xec\x9a{\x1e\x932v\x1e\x9f\xe2\xb9{\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd0\xf9Yx\x11\xb0\xb9\x92\xbb}7W\xaa%\xb4\xc2V\x1d2\xe2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\x03\x02\xfa\xa1\x92\x9a2i\x04\xd3v\xbf\v\x8d\xc9:\xd0LL\x89a\t=|,m8\x00\x00\xe0\x94\xd1\x10\r\xd0\x0f\xe2\xdd\xf1\x81c\xad\x96M\vi\xf1\xf2\xe9e\x8a\x8a\x01C\x12\tU\xb2Pk\x00\x00\u07d4\xd1\x16\xf3\xdc\xd5\xdbtK\xd0\b\x88v\x87\xaa\x0e\xc9\xfdr\x92\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\x19A|Fs,\xf3M\x1a\x1a\xfby\xc3\xe7\xe2\u034e\xec\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1-w\xae\x01\xa9-5\x11{\xacpZ\xac\u0642\xd0.t\xc1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd15yK\x14\x9a\x18\xe1G\xd1nb\x1ai1\xf0\xa4\n\x96\x9a\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xd1C%8\xe3[vd\x95j\u4563*\xbd\xf0A\xa7\xa2\x1c\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xd1C\x82g#\x17\x04\xfcr\x80\xd5c\xad\xf4v8D\xa8\a\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd1S\x8e\x9a\x87\u5729\xec\x8eX&\xa5\xb7\x93\xf9\x9f\x96\xc4\u00c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd1d\x85\x03\xb1\xcc\u0178\xbe\x03\xfa\x1e\xc4\xf3\xee&~j\xdf{\x8a\x01;\xef\xbfQ\xee\xc0\x90\x00\x00\xe0\x94\xd1h,!Y\x01\x8d\xc3\xd0\u007f\b$\n\x8c`m\xafe\xf8\xe1\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xd1q\xc3\xf2%\x8a\xef5\xe5\x99\xc7\xda\x1a\xa0s\x00#M\xa9\xa6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1w\x8c\x13\xfb\xd9h\xbc\b<\xb7\xd1\x02O\xfe\x1fI\xd0,\xaa\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\xd1\u007f\xbe\"\xd9\x04b\xed7(\x06p\xa2\xea\v0\x86\xa0\xd6\u0589\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\u0441\x1cU\x97i\x80\xf0\x83\x90\x1d\x8a\r\xb2i\"-\xfb\\\xfe\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u044e\xb9\xe1\u0485\u06be\x93\xe5\u053a\xe7k\xee\xfeC\xb5!\xe8\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\u0453\xe5\x83\xd6\a\x05c\xe7\xb8b\xb9aJG\u9509\xf3\xe5\x8965f3\xeb\xd8\xea\x00\x00\u07d4\u0457\x8f.4@\u007f\xab\x1d\xc2\x18=\x95\xcf\xdab`\xb3Y\x82\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4\u045c\xaf9\xbb7\u007f\xdf,\xf1\x9b\xd4\xfbRY\x1c&1\xa6<\x8965\u026d\xc5\u07a0\x00\x00\u0794\u0463\x96\xdc\u06b2\xc7IA0\xb3\xfd0x 4\r\xfd\x8c\x1f\x88\xf9\"P\xe2\xdf\xd0\x00\x00\xe0\x94\u0467\x1b-\bX\xe82p\b]\x95\xa3\xb1T\x96P\x03^#\x8a\x03'\xbb\t\xd0j\xa8P\x00\x00\u07d4\u046c\xb5\xad\xc1\x189s%\x8dk\x85$\xff\xa2\x8f\xfe\xb2=\xe3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0473\u007f\x03\xcb\x10t$\xe9\xc4\xddW\\\xcdOL\xeeW\xe6\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\u0475\xa4T\xac4\x05\xbbAy \x8cl\x84\xde\x00k\u02db\xe9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xc4YT\xa6+\x91\x1a\xd7\x01\xff.\x90\x13\x1e\x8c\xeb\x89\xc9\\\x89K\x91\xa2\xdeE~\x88\x00\x00\u07d4\xd1\xc9np\xf0Z\xe0\xe6\xcd`!\xb2\b7P\xa7q|\xdeV\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\u0571\u007f\xfe-{\xbby\xcc}y0\xbc\xb2\xe5\x18\xfb\x1b\xbf\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd1\xda\f\x8f\xb7\xc2\x10\xe0\xf2\xeca\x8f\x85\xbd\xae}>sK\x1c\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd1\xddy\xfb\x15\x81`\xe5\xb4\xe8\xe2?1.j\x90\u007f\xbcMN\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xdeZ\xad:_\xd8\x03\U00071bb6\x10<\xb8\xe1O\xe7#\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd1\xe1\xf2\xb9\xc1l0\x98t\xde\xe7\xfa\xc3&u\xaf\xf1)\u00d8\x89\x03\xf2M\x8eJ\x00p\x00\x00\xe0\x94\xd1\xe5\xe24\xa9\xf4Bf\xa4\xa6$\x1a\x84\u05e1\xa5Z\u0567\xfe\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd1\xeaMr\xa6{[>\x0f1UY\xf5+\xd0aMq0i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1\xee\x90YW\xfe|\xc7\x0e\xc8\xf2\x86\x8bC\xfeG\xb1?\xeb\xff\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\xd1\xf1iM\"g\x1bZ\xadj\x94\x99\\6\x9f\xbea3go\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\xf4\xdc\x1d\u06ca\xbb\x88H\xa8\xb1N%\xf3\xb5Z\x85\x91\xc2f\x89\r\x8drkqw\xa8\x00\x00\u07d4\xd1\xfe\u042e\xe6\xf5\xdf\xd7\xe2Wi%L<\xfa\xd1Z\xde\u032a\x89'\x92\xc8\xfcKS(\x00\x00\u07d4\xd2\x05\x1c\xb3\xcbg\x04\xf0T\x8c\u0210\xab\n\x19\xdb4\x15\xb4*\x89\x12\x1b.^ddx\x00\x00\u07d4\xd2\x06\xaa\u07736\xd4^yr\xe9<\xb0uG\x1d\x15\x89{]\x89 \x86\xac5\x10R`\x00\x00\u07d4\xd2\tH+\xb5I\xab\xc4w{\xeam\u007fe\x00b\xc9\xc5z\x1c\x89\x11e\x1a\xc3\xe7\xa7X\x00\x00\u07d4\xd2\r\xcb\vxh+\x94\xbc0\x00(\x14H\xd5W\xa2\v\xfc\x83\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4\xd2\x10{57&\u00e2\xb4ef\xea\xa7\xd9\xf8\v]!\xdb\xe3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\x11\xb2\x1f\x1b\x12\xb5\ta\x81Y\r\xe0~\xf8\x1a\x89S~\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd2\x18\xef\xb4\u06d8\x1c\xddjy\u007fK\u050c|&)<\xeb@\x89\xa1Fk1\xc6C\x1c\x00\x00\xe0\x94\xd2\x1asA\xeb\x84\xfd\x15\x10T\xe5\u31fb%\xd3nI\x9c\t\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2$\xf8\x80\xf9G\x9a\x89\xd3/\t\xe5+\u9432\x88\x13\\\xef\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xd2/\f\xa4\xcdG\x9ef\x17u\x05;\xccI\xe3\x90\xf6p\u074a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd21\x92\x975\x13!\x02G\x1b\xa5\x90\a\xb6dL\xc0\xc1\xde>\x8967\tlK\xcci\x00\x00\u07d4\xd25\xd1\\\xb5\xec\xee\xbba)\x9e\x0e\x82\u007f\xa8'H\x91\x1d\x89\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2:$\xd7\xf9F\x83C\xc1C\xa4\x1ds\xb8\x8f|\xbec\xbe^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2=z\xff\xac\xdc>\x9f=\xaez\xfc\xb4\x00oX\xf8\xa4F\x00\x89\xc3(\t>a\xee@\x00\x00\u07d4\xd2C\x18L\x80\x1e]y\xd2\x06?5x\u06ee\x81\u7ce9\u02c9k\u0722h\x1e\x1a\xba\x00\x00\u07d4\xd2KfD\xf49\xc8\x05\x1d\xfcd\u04c1\xb8\xc8lu\xc1u8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2K\xf1--\xdfE}\xec\xb1xt\xef\xde R\xb6\\\xbbI\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2Q\xf9\x03\xae\x18rrY\xee\xe8A\xa1\x89\xa1\xf5i\xa5\xfdv\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd2R\x96\v\v\xf6\xb2\x84\x8f\u07ad\x80\x13m\xb5\xf5\a\xf8\xbe\x02\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2X\x1aU\xce#\xab\x10\u062d\x8cD7\x8fY\a\x9b\xd6\xf6X\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xd2Z\xec\xd7\xeb\x8b\xd64[\x06;]\xbd'\x1cw\xd3QD\x94\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xd2|#O\xf7\xac\xca\xce=\x99g\b\xf8\xf9\xb0Ip\xf9}6\x89Hz\x9a0E9D\x00\x00\u07d4\u0482\x98RM\xf5\xecK$\xb0\xff\xb9\u07c5\x17\n\x14Z\x9e\xb5\x89\x0f\x98\xa3\xb9\xb37\xe2\x00\x00\xe0\x94\u0483\xb8\xed\xb1\n%R\x8aD\x04\xde\x1ce\xe7A\r\xbc\xaag\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u0484\xa5\x03\x82\xf8:am9\xb8\xa9\xc0\xf3\x96\xe0\ubfe9]\x8966\xc2^f\xec\xe7\x00\x00\u07d4\u0488\xe7\xcb{\xa9\xf6 \xab\x0ftR\xe5\bc=\x1cZ\xa2v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u049d\xc0\x8e\xfb\xb3\xd7.&?x\xabv\x10\xd0\"m\xe7k\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u04a00\xac\x89R2_\x9e\x1d\xb3x\xa7\x14\x85\xa2N\x1b\a\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u04a4y@CG\xc5T:\xab)*\xe1\xbbJo\x15\x83W\xfa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u04a5\xa0$#\nW\xcc\xc6fv\v\x89\xb0\xe2l\xaf\u0449\u01ca\n\x96YZ\\n\x8a?\x80\x00\u07d4\u04a8\x03'\xcb\xe5\\L{\xd5\x1f\xf9\xdd\xe4\xcad\x8f\x9e\xb3\xf8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u04a8Oug\\b\xd8\f\x88ulB\x8e\xee+\xcb\x18T!\x89A\rXj \xa4\xc0\x00\x00\u07d4\u04ab\xd8J\x18\x10\x93\xe5\xe2)\x13oB\xd85\xe8#]\xe1\t\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\u04ac\r:X`^\x1d\x0f\x0e\xb3\xde%\xb2\xca\xd1)\xed`X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u04bfg\xa7\xf3\xc6\xceV\xb7\xbeAg]\xbb\xad\xfe~\xa9:3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd2\xdb\xeb\xe8\x9b\x03W\xae\xa9\x8b\xbe\x8eIc8\u07bb(\xe8\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2\xe2\x1e\xd5hh\xfa\xb2\x8e\tG\x92z\xda\xf2\x9f#\xeb\xadl\x89l\x18O\x13U\xd0\xe8\x00\x00\u07d4\xd2\xe8\x17s\x8a\xbf\x1f\xb4\x86X?\x80\xc3P1\x8b\xed\x86\f\x80\x89\r\x02\xce\xcf_]\x81\x00\x00\u07d4\xd2\xed\xd1\xdd\xd6\xd8m\xc0\x05\xba\xebT\x1d\"\xb6@\xd5\xc7\xca\xe5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\xf1\x99\x8e\x1c\xb1X\f\xecOl\x04}\xcd=\xce\xc5L\xf7<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2\xf2A%]\xd7\xc3\xf7<\a\x040q\xec\b\xdd\xd9\xc5\xcd\xe5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd2\xffg \x16\xf6;/\x859\x8fJo\xed\xbb`\xa5\r<\u0389\x12\x91$o[sJ\x00\x00\u07d4\xd3\rLC\xad\xcfU\xb2\xcbS\u0583#&A4I\x8d\x89\u038965\u026d\xc5\u07a0\x00\x00\u07d4\xd3\x0e\xe9\xa1+Mh\xab\xac\xe6\xba\u029a\u05ff\\\xd1\xfa\xf9\x1c\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xd3\x11\x8e\xa3\xc85\x05\xa9\u0613\xbbg\xe2\xde\x14-Sz>\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd3\x11\xbc\u05eaN\x9bO8?\xf3\xd0\u05b6\xe0~!\xe3p]\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd3\x15\xde\xea\x1d\x8c\x12q\xf9\xd11\x12c\xabG\xc0\a\xaf\xb6\xf5\x89\x03\xc8\x1dNeK@\x00\x00\u07d4\xd3+,y\xc3dx\xc5C\x19\x01\xf6\xd7\x00\xb0M\xbe\x9b\x88\x10\x89\x15w\x9a\x9d\xe6\xee\xb0\x00\x00\u07d4\xd3+EVF\x14Ql\x91\xb0\u007f\xa9\xf7-\xcfx|\xceN\x1c\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\xd30r\x811\xfe\x8e:\x15Hz4W<\x93E~*\xfe\x95\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd31\xc8#\x82Z\x9eRc\xd0R\u0611]M\xcd\xe0z\\7\x89\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d4\xd33btE\xf2\u05c7\x90\x1e\xf3;\xb2\xa8\xa3g^'\xff\xec\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3<\xf8+\xf1LY&@\xa0\x86\b\x91L#py\u057e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3Mp\x8ds\x98\x02E3\xa5\xa2\xb20\x9b\x19\xd3\xc5Qq\xbb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3N\x03\xd3j+\xd4\u045a_\xa1b\x18\xd1\xd6\x1e?\xfa\v\x15\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\xd3Pu\xcaa\xfeY\xd1#\x96\x9c6\xa8-\x1a\xb2\xd9\x18\xaa8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xd3g\x00\x9a\xb6X&;b\xc23:\x1c\x9eA@I\x8e\x13\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3g\x9aG\xdf-\x99\xa4\x9b\x01\u024d\x1c>\f\x98|\xe1\xe1X\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u04cf\xa2\xc4\xcc\x14z\xd0j\u0562\xf7Uy(\x1f\"\xa7\xcc\x1f\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\u04da]\xa4`9+\x94\v\u01ee8\xf1e\u007f\x8a\x01f\xc5H\b\x89\xdbw\x00\x00\xe0\x94\xd3\xd6\xe9\xfb\x82T/\u049e\xd9\xea6\t\x89\x1e\x15\x13\x96\xb6\xf7\x8a\voX\x8a\xa7\xbc\xf5\xc0\x00\x00\xe0\x94\xd3\xda\u0476\u040dE\x81\u032ee\xa8s-\xb6\xaci\xf0\u019e\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xd3\xdf;S\xcb;GU\xdeT\xe1\x80E\x1c\xc4L\x9e\x8a\u0a89#\u0114\t\xb9w\x82\x80\x00\u07d4\xd3\xf8s\xbd\x99V\x13W\x89\xab\x00\xeb\xc1\x95\xb9\"\xe9K%\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\x02\xb4\xf6\xa0\x99\xeb\xe7\x16\xcb\x14\xdfOy\xc0\xcd\x01\xc6\a\x1b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd4\r\x00U\xfd\x9a8H\x8a\xff\x92?\xd0=5\xecF\xd7\x11\xb3\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xd4\x0e\xd6j\xb3\xce\xff$\xca\x05\xec\xd4q\ufd12\xc1__\xfa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4\x18\x87\v\xc2\xe4\xfa{\x8aa!\xae\br\xd5RG\xb6%\x01\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xd4\x1d\u007f\xb4\x9f\xe7\x01\xba\xac%qpBl\u0273\x8c\xa3\xa9\xb2\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xd4 U\x92\x84@U\xb3\u01e1\xf8\f\xef\xe3\xb8\xebP\x9b\xcd\xe7\x89\t\xb3\xbf\xd3B\xa9\xfc\x80\x00\u07d4\xd4+ \xbd\x03\x11`\x8bf\xf8\xa6\xd1[*\x95\xe6\xde'\u017f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd44O}\\\xade\xd1~\\-\x0es#\x94=ob\xfe\x92\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xd4>\xe48\xd8=\xe9\xa3ub\xbbN(l\xb1\xbd\x19\xf4\x96M\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd4C4\xb4\xe2:\x16\x9a\f\x16\xbd!\xe8f\xbb\xa5-\x97\x05\x87\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94\xd4M\x81\xe1\x8fF\xe2\u03f5\xc1\xfc\xf5\x04\x1b\xc8V\x97g\xd1\x00\x8a\a\xb4B\xe6\x84\xf6Z\xa4\x00\x00\u07d4\xd4OJ\xc5\xfa\xd7k\xdc\x157\xa3\xb3\xafdr1\x9bA\r\x9d\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xd4O^\xdf+\xcf$3\xf2\x11\xda\xdd\f\xc4P\xdb\x1b\x00\x8e\x14\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xd4Oj\u00d2;_\xd71\xa4\xc4YD\xecO~\xc5*j\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd4[3A\xe8\xf1\\\x802\x93 \u00d7~;\x90\xe7\x82j~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4]]\xaa\x13\x8d\xd1\xd3t\xc7\x1b\x90\x19\x91h\x11\xf4\xb2\nN\x89\x1f9\x9b\x148\xa1\x00\x00\x00\u07d4\xd4`\xa4\xb9\b\xdd+\x05gY\xb4\x88\x85\vf\xa88\xfcw\xa8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd4g\xcf\x06L\bq\x98\x9b\x90\u0632\xeb\x14\xcc\xc6;6\b#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd4k\xaea\xb0'\xe5\xbbB.\x83\xa3\xf9\xc9?<\x8f\xc7}'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4o\x82#E)\x82\xa1\xee\xa0\x19\xa8\x81n\xfc-o\xc0\ah\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xd4uG\u007f\xa5c\x90\xd30\x17Q\x8dg\x11\x02\u007f\x05\U0008dfc9k\x11\x133\xd4\xfdL\x00\x00\u07d4\xd4|$.\xdf\xfe\xa0\x91\xbcT\xd5}\xf5\xd1\xfd\xb91\x01Gl\x89\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4\xd4}\x86\x85\xfa\xee\x14|R\x0f\u0646p\x91u\xbf/\x88k\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\u007fP\u07c9\xa1\xcf\xf9e\x13\xbe\xf1\xb2\xae:)q\xac\xcf,\x89-\x89W}}@ \x00\x00\u07d4\u0502\xe7\xf6\x8eA\xf28\xfeQx)\xde\x15G\u007f\xe0\xf6\xdd\x1d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u0507\x9f\xd1+\x1f:'\xf7\xe1\tv\x1b#\xca4\xfa#\x06K\x1c\xaf\x00Qn(pJ\x82\xa4\xf8\x89Hz\x9a0E9D\x00\x00\u07d4\xd5\x00\xe4\xd1\u0242K\xa9\xf5\xb65\u03e3\xa8\xc2\u00cb\xbdL\xed\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5\b\u04dcp\x91oj\xbcL\xc7\xf9\x99\xf0\x11\xf0w\x10X\x02\x89\x05rM$\xaf\xe7\u007f\x00\x00\u07d4\xd5\x0f\u007f\xa0>8\x98v\u04d0\x8b`\xa57\xa6pc\x04\xfbV\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd5\x13\xa4P\x80\xff/\xeb\xe6,\u0545J\xbe)\xeeDg\xf9\x96\x89\bN\x13\xbcO\xc5\xd8\x00\x00\u07d4\xd5'o\f\xd5\xff\xd5\xff\xb6?\x98\xb5p=U\x94\xed\xe0\x83\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5)KfbB0;m\xf0\xb1\u020d7B\x9b\xc8\xc9e\xaa\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xd5*\xec\xc6I98\xa2\x8c\xa1\xc3g\xb7\x01\xc2\x15\x98\xb6\xa0.\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xd5\x99x\xee \xa3\x8c?I\x8dc\xd5\u007f1\xa3\x9fj\x06\x8a\x022\xb3o\xfcg*\xb0\x00\x00\u07d4\u05568\xd3\xc5\xfa\xa7q\x1b\xf0\x85t_\x9d[\xdc#\u0518\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u055d\x92\xd2\xc8p\x19\x80\xcc\a<7]r\n\xf0dt<\f\x8a\x04\x05\xfd\xf7\u5bc5\xe0\x00\x00\u07d4\u0567\xbe\xc32\xad\xde\x18\xb3\x10KW\x92Tj\xa5\x9b\x87\x9bR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0571\x17\xec\x11n\xb8FA\x89a\xeb~\xdbb\x9c\xd0\xddi\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u0572\x84\x04\x010\xab\xf7\xc1\xd1cq#q\xcc~(\xadf\u0689j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0579\xd2w\u062a\xd2\x06\x97\xa5\x1fv\xe2\tx\x99k\xff\xe0U\x89\a\xc3\xfe<\aj\xb5\x00\x00\u07d4\u057d^\x84U\xc10\x16\x93W\xc4q\xe3\u6077\x99jrv\x89-\x9e(\x8f\x8a\xbb6\x00\x00\u07d4\xd5\u02e5\xb2k\xea]s\xfa\xbb\x1a\xba\xfa\xcd\xef\x85\xde\xf3h\u0309\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd5\xceU\u0476/YC\xc0?\x89\b\xe3\x1f\xe1h\x9d\x8a\x00\x00\u07d4\xd6\x06Q\xe3\x93x4#\xe5\xcc\x1b\xc5\xf8\x89\xe4N\xf7\xea$>\x89\x15\x9ev7\x11)\xc8\x00\x00\u07d4\xd6\t\xbfO\x14n\xeak\r\xc8\xe0m\xdc\xf4D\x8a\x1f\xcc\xc9\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\t\xec\v\xe7\r\n\xd2ong\xc9\xd4v+R\xeeQ\x12,\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6\nRX\a(R\r\xf7Tk\xc1\xe2\x83)\x17\x88\u06ee\f\x8964\x89\xef?\xf0\xd7\x00\x00\u07d4\xd6\v$s!\xa3*Z\xff\xb9k\x1e'\x99'\xccXM\xe9C\x89z\xd0 \xd6\xdd\xd7v\x00\x00\u07d4\xd6\x11\x02v\xcf\xe3\x1eB\x82ZW\u007fkC]\xbc\xc1\f\xf7d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd6\x12Y{\xc3\x17C\u01c63\xf63\xf29\xb1\xe9Bk\xd9%\x8a\x10\x17\xf7\u07d6\xbe\x17\x80\x00\x00\u07d4\xd6#J\xafE\xc6\xf2.f\xa2%\xff\xb9:\xddb\x9bN\xf8\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6.\u06d6\xfc\u259a\xaflT^\x96|\xf1\xc0\xbc\x80R\x05\x89\x04\xa5eSjZ\u0680\x00\u07d4\xd60\v2\x15\xb1\x1d\xe7b\xec\xdeKp\xb7\x92}\x01)\x15\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd69]\xb5\xa4\xbbf\xe6\x0fL\xfb\xcd\xf0\x05{\xb4\xd9xb\xe2\x891T\xc9r\x9d\x05x\x00\x00\xe0\x94\xd6J-P\xf8\x85\x857\x18\x8a$\xe0\xf5\r\xf1h\x1a\xb0~\u05ca\b7Z*\xbc\xca$@\x00\x00\u07d4\xd6X\n\xb5\xedL}\xfaPo\xa6\xfed\xad\\\xe1)pw2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6Y\x8b\x13\x86\xe9<\\\u02d6\x02\xffK\xbb\xec\xdb\xd3p\x1d\u0109\f%\xf4\xec\xb0A\xf0\x00\x00\u07d4\xd6dM@\xe9\v\xc9\u007f\xe7\xdf\xe7\u02bd2i\xfdW\x9b\xa4\xb3\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\xe0\x94\xd6g\f\x03m\xf7T\xbeC\xda\u074fP\xfe\xea(\x9d\x06\x1f\u058a\x01D\xa2\x904H\xce\xf7\x80\x00\u07d4\xd6hR:\x90\xf0)=e\xc58\xd2\xddlWg7\x10\x19n\x89\x02$,0\xb8S\xee\x00\x00\u07d4\xd6j\xb7\x92\x94\aL\x8bb}\x84-\xabA\xe1}\xd7\f]\xe5\x8965\u026d\xc5\u07a0\x00\x00\u0794\xd6j\xcc\r\x11\xb6\x89\u03a6\xd9\xea_\xf4\x01L\"J]\xc7\u0108\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xd6m\xdf\x11Y\xcf\"\xfd\x8czK\xc8\u0540wV\xd43\xc4>\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\u0587\xce\xc0\x05\x90\x87\xfd\xc7\x13\xd4\xd2\xd6^w\xda\xef\xed\xc1_\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u0588\xe7\x85\u024f\x00\xf8K:\xa1S3U\u01e2X\xe8yH\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u05a2.Y\x8d\xab\u04ce\xa6\xe9X\xbdy\u050d\u0756\x04\xf4\u07c965\u026d\xc5\u07a0\x00\x00\u07d4\u05a7\xacM\xe7\xb5\x10\xf0\xe8\xdeQ\x9d\x97?\xa4\xc0\x1b\xa84\x00\x89e\xea=\xb7UF`\x00\x00\u07d4\u05ac\xc2 \xba.Q\xdf\xcf!\xd4C6\x1e\xeav\\\xbd5\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05ac\xff\u043f\u065c8.{\xd5o\xf0\xe6\x14J\x9eR\xb0\x8e\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xd6\xc0\u043c\x93\xa6.%qtp\x0e\x10\xf0$\u0232?\x1f\x87\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd6\xcf\\\x1b\u03dd\xa6b\xbc\xea\"U\x90P\x99\xf9\xd6\xe8M\u030a\x01\u011eB\x01W\xd9\xc2\x00\x00\u07d4\xd6\xd05r\xa4RE\xdb\xd46\x8cO\x82\xc9W\x14\xbd!g\xe2\x89?\x00\xc3\xd6f\x86\xfc\x00\x00\u07d4\xd6\xd6wiX\xee#\x14:\x81\xad\xad\xeb\b8 \t\xe9\x96\u0089\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd6\xd9\xe3\x0f\bB\x01*qv\xa9\x17\xd9\xd2\x04\x8c\xa0s\x87Y\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6\xe0\x9e\x98\xfe\x13\x003!\x04\xc1\xca4\xfb\xfa\xc5T6N\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\xe8\xe9z\u90db\x9e\xe5\a\xee\xdb(\xed\xfbtw\x03\x149\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\uea18\u052e+q\x80'\xa1\x9c\xe9\xa5\xebs\x00\xab\xe3\u0289\x01}J\xce\xeec\u06c0\x00\xe0\x94\xd6\xf1\xe5[\x16\x94\b\x9e\xbc\xb4\xfe}x\x82\xaaf\u0217av\x8a\x04<#\xbd\xbe\x92\x9d\xb3\x00\x00\u07d4\xd6\xf4\xa7\xd0N\x8f\xaf \xe8\xc6\ub15c\xf7\xf7\x8d\xd2=z\x15\x89\a$\xde\xd1\xc7H\x14\x00\x00\u07d4\xd6\xfc\x04F\u01a8\xd4\n\xe3U\x1d\xb7\xe7\x01\xd1\xfa\x87nJI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x03\u01a4\xf1\x1d`\x19Ey\u054c'f\xa7\xef\x16\xc3\n)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x05%\x19uj\xf4%\x90\xf1S\x91\xb7#\xa0?\xa5d\xa9Q\x89\xfa61H\r\x01\xfd\x80\x00\u07d4\xd7\na+\xd6\u0769\xea\xb0\xdd\xdc\xffJ\xafA\"\u04cf\xea\xe4\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xd7\n\xd2\xc4\xe9\uefe67\xefV\xbdHj\u04a1\xe5\xbc\xe0\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x14\f\x8eZC\a\xfa\xb0\xcc'\xba\u0752\x95\x01\x8b\xf8yp\x89\x05\xf1\x01kPv\xd0\x00\x00\u07d4\xd7\x16J\xa2a\xc0\x9a\u0672\xb5\x06\x8dE>\xd8\xebj\xa10\x83\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\x1eC\xa4Qw\xadQ\xcb\xe0\xf7!\x84\xa5\xcbP9\x17(Z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x1f\xb10\xf0\x15\fVRi\xe0\x0e\xfbC\x90+R\xa4U\xa6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\"W8\xdc\xf3W\x848\xf8\xe7\u0233\x83~B\xe0J&/\x89\x18+\x8c\ubec3\xaa\x00\x00\u07d4\xd7'MP\x80M\x9cw\u0693\xfaH\x01V\xef\xe5{\xa5\x01\u0789i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd71\xbbk_<79^\t\u03ac\xcd\x14\xa9\x18\xa6\x06\a\x89\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xd7>\xd2\u0645\xb5\xf2\x1bU\xb2td;\xc6\xda\x03\x1d\x8e\u074d\x8a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xd7D\xac~S\x10\xbeijc\xb0\x03\xc4\v\xd097\x05a\u0189Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\xd7Jn\x8dj\xab4\u0385\x97h\x14\xc12{\xd6\xea\a\x84\u048a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xd7ZP*[gr\x87G\x0fe\u016aQ\xb8|\x10\x15\x05r\x8910\xb4dc\x85t\x00\x00\u07d4\xd7m\xba\xeb\xc3\rN\xf6{\x03\xe6\xe6\xec\xc6\xd8N\x00MP-\x89mv\xb9\x18\x8e\x13\x85\x00\x00\u07d4\xd7q\xd9\xe0\u028a\b\xa1\x13wW1CN\xb3'\x05\x99\xc4\r\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7x\x8e\xf2\x86X\xaa\x06\xccS\xe1\xf3\xf0\xdeX\xe5\xc3q\xbex\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xd7x\x92\xe2';#]v\x89\xe40\xe7\xae\ud73c\xe8\xa1\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u05c1\xf7\xfc\t\x18F\x11V\x85p\xb4\x98n,r\x87+~\u0409\x01\x15\x95a\x06]]\x00\x00\u07d4\u05c5\xa8\xf1\x8c8\xb9\xbcO\xfb\x9b\x8f\xa8\xc7r{\xd6B\xee\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u05ce\xcd%\xad\xc8k\xc2\x05\x1d\x96\xf6Sd\x86kB\xa4&\xb7\x89\xd20X\xbf/&\x12\x00\x00\xe0\x94\u05cf\x84\xe3\x89D\xa0\xe0%_\xae\xceH\xbaIP\u053d9\u048a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u05d4\x83\xf6\xa8DO%I\xd6\x11\xaf\xe0,C-\x15\xe1\x10Q\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05d85\xe4\x04\xfb\x86\xbf\x84_\xba\t\rk\xa2^\f\x88f\xa6\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\u05da\xff\x13\xba-\xa7]F$\f\xac\n$g\xc6V\x94\x98#\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\u05dd\xb5\xabCb\x1az=\xa7\x95\xe5\x89)\xf3\xdd%\xafg\u0649lj\xccg\u05f1\xd4\x00\x00\u07d4\u05e1C\x1e\xe4S\xd1\xe4\x9a\x05P\xd1%hy\xb4\xf5\xd1\x02\x01\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\u05ed\t\xc6\xd3&WhSU\xb5\xc6\uc39fW\xb4\ube42\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u05f7@\xdf\xf8\xc4Wf\x8f\xdft\xf6\xa2f\xbf\xc1\u0737#\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7\u0080>\u05f0\xe0\x83sQA\x1a\x8ef7\xd1h\xbc[\x05\x8a\x06A\xda\xf5\xc9\x1b\xd95\x80\x00\u07d4\xd7\xc6&]\xea\x11\x87l\x90;q\x8eL\u062b$\xfe&[\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xca\u007f\xdc\xfe\xbeE\x88\xef\xf5B\x1d\x15\"\xb6\x13(\xdf{\xf3\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4\xd7\u037dA\xff\xf2\r\xf7'\xc7\vbU\xc1\xbav\x06\x05Th\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xd1W\xe4\xc0\xa9d7\xa6\u0485t\x1d\xd2>\xc46\x1f\xa3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xd2\xc6\xfc\xa8\xad\x1fu9R\x10\xb5}\xe5\xdf\xd6s\x939\t\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94\xd7\xd3\xc7Y Y\x048\xb8,>\x95\x15\xbe.\xb6\xedz\x8b\x1a\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\xd7\xd7\xf2\u02a4b\xa4\x1b;0\xa3J\xeb;\xa6\x10\x10\xe2bo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xe7J\xfd\xba\xd5^\x96\u03bcZ7O,\x8bv\x86\x80\xf2\xb0\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\xe0\x94\xd7\xeb\x901b'\x1c\x1a\xfa5\xfei\xe3s\"\u0224\u049b\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd7\xeb\u0779\xf99\x87w\x9bh\x01U7T8\xdbe\xaf\xcbj\x89\x05t\x1a\xfe\xff\x94L\x00\x00\u07d4\xd7\xef4\x0ef\xb0\u05ef\xcc\xe2\n\x19\xcb{\xfc\x81\xda3\xd9N\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\xf3p\u053e\xd9\xd5|oI\u0259\xder\x9e\xe5i\xd3\xf4\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xfa_\xfb`H\xf9o\xb1\xab\xa0\x9e\xf8{\x1c\x11\xddp\x05\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\x06\x9f\x84\xb5!I?G\x15\x03\u007f2&\xb2_3\xb6\x05\x86\x89g\x8a\x93 b\xe4\x18\x00\x00\u0794\xd8\x15\xe1\xd9\xf4\xe2\xb5\xe5~4\x82k|\xfd\x88\x81\xb8Th\x90\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xd8\x1b\xd5K\xa2\xc4Jok\xeb\x15a\u058b\x80\xb5DNm\u0189?\x17\r~\xe4\"\xf8\x9c\x80-1({\x96q\xe8\x1c\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xd8K\x92/xA\xfcWt\xf0\x0e\x14`J\xe0\xdfB\xc8U\x1e\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xd8U\xb0<\xcb\x02\x9awG\xb1\xf0s\x03\xe0\xa6dy59\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8_\u07af*a\xf9]\xb9\x02\xf9\xb5\xa5<\x9b\x8f\x92f\u00ec\x89l\xf6Z~\x90G(\x00\x00\u07d4\xd8q^\xf9\x17o\x85\v.0\xeb\x8e8'\a\xf7w\xa6\xfb\xe9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8t\xb9\u07eeEj\x92\x9b\xa3\xb1\xa2~W,\x9b,\xec\u07f3\x89\t79SM(h\x00\x00\u07d4\u0613\n9\xc7sW\xc3\n\u04e0`\xf0\v\x06\x04c1\xfdb\x89,s\xc97t,P\x00\x00\u07d4\u061b\xc2q\xb2{\xa3\xabib\xc9JU\x90\x06\xae8\xd5\xf5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0637}\xb9\xb8\x1b\xbe\x90B{b\xf7\x02\xb2\x01\xff\u009f\xf6\x18\x892m\x1eC\x96\xd4\\\x00\x00\u07d4\xd8\xcdd\xe0(N\xecS\xaaF9\xaf\xc4u\b\x10\xb9\u007f\xabV\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xd6C\x84$\x9bwg\x94\x06;V\x98x\xd5\xe3\xb50\xa4\xb2\x89\t\xa0C\u0432\xf9V\x80\x00\u07d4\xd8\xd6T \xc1\x8c#'\xccZ\xf9t%\xf8W\xe4\xa9\xfdQ\xb3\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xd8\xe5\xc9g^\xf4\xde\xed&k\x86\x95o\xc4Y\x0e\xa7\u0522}\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd8\xe8GB\x92\xe7\xa0Q`L\xa1d\xc0pw\x83\xbb(\x85\xe8\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\u07d4\xd8\xebxP>\xc3\x1aT\xa9\x016x\x1a\xe1\t\x00Lt2W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\xee\xf4\xcfK\xeb\x01\xee \xd1\x11t\x8ba\xcbM?d\x1a\x01\x89\x94\x89#z\u06daP\x00\x00\u07d4\xd8\xf4\xba\xe6\xf8M\x91\rm}Z\xc9\x14\xb1\xe6\x83r\xf9A5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd8\xf6 6\xf0;v5\xb8X\xf1\x10?\x8a\x1d\x90\x19\xa8\x92\xb6\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xd8\xf6e\xfd\x8c\xd5\u00bc\xc6\xdd\xc0\xa8\xaeR\x1eM\u01aa``\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xd8\xf9$\fU\xcf\xf05RB\x80\xc0\x9e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xfe\b\x8f\xff\u0394\x8fQ7\xee#\xb0\x1d\x95\x9e\x84\xacB#\x89\f[T\xa9O\xc0\x17\x00\x00\u07d4\xd9\x0f0\t\xdbC~N\x11\u01c0\xbe\u0209os\x8de\xef\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\x10;\xb6\xb6zU\xa7\xfe\xce-\x1a\xf6-E|!x\x94m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\x13\xf0w\x19Iu\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd9D\u0226\x9f\xf2\xca\x12Ii\f\x12)\xc7\x19/6%\x10b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd9JW\x88*Rs\x9b\xbe*\x06G\xc8\f$\xf5\x8a+O\x1c\x89H\xb5N*\xdb\xe1+\x00\x00\xe0\x94\xd9SB\x95<\x8a!\xe8\xb65\xee\xfa\u01c1\x9b\xea0\xf1pG\x8a\x13\xf0l\u007f\xfe\xf0]@\x00\x00\u07d4\xd9\\\x90\xff\xbeT\x84\x86G\x80\xb8gIJ\x83\u0212V\xd6\xe4\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xd9g\x11T\x0e.\x99\x83C\xd4\xf5\x90\xb6\xfc\x8f\xac;\xb8\xb3\x1d\x89_Z@h\xb7\x1c\xb0\x00\x00\u07d4\xd9j\xc2Pt\t\u01e3\x83\xab.\xee\x18\"\xa5\xd78\xb3kV\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd9m\xb3;{Z\x95\f>\xfa-\xc3\x1b\x10\xba\x10\xa52\uf1c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd9wYe\xb7\x16Gfu\xa8\xd5\x13\xeb\x14\xbb\xf7\xb0|\xd1J\x8a\x01\x13.m-#\xc5\xe4\x00\x00\u07d4\xd9{\xc8J\xbdG\xc0[\xbfE{.\xf6Y\xd6\x1c\xa5\xe5\u43c9\x06\x9d\x17\x11\x9d\u0168\x00\x00\u07d4\xd9\u007fE&\u07a9\xb1c\xf8\xe8\xe3:k\u03d2\xfb\x90}\xe6\xec\x89\x0feJ\xafM\xb2\xf0\x00\x00\u07d4\xd9\u007f\xe6\xf5?*X\xf6\xd7mu*\xdft\xa8\xa2\xc1\x8e\x90t\x89\x10\xcd\xf9\xb6\x9aCW\x00\x00\u07d4\u0659\x99\xa2I\r\x94\x94\xa50\xca\xe4\xda\xf3\x85T\xf4\xddc>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\u065d\xf7B\x1b\x93\x82\xe4,\x89\xb0\x06\xc7\xf0\x87p*\aW\xc0\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\xe0\x94\u0677\x83\xd3\x1d2\xad\xc5\x0f\xa3\xea\u02a1]\x92\xb5h\xea\xebG\x8a\a3\xaf\x907L\x1b(\x00\x00\u07d4\xd9\xd3p\xfe\xc65v\xab\x15\xb3\x18\xbf\x9eX6M\u00a3U*\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xd9\xd4/\xd1>\xbdK\xf6\x9c\xac^\x9c~\x82H:\xb4m\xd7\xe9\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xd9\xe2~\xb0}\xfcq\xa7\x06\x06\f\u007f\a\x928\u0293\xe8\x859\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\xe3\x85~\xfd\x1e *D\x17p\xa7w\xa4\x9d\xccE\xe2\xe0\u04c9\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xd9\xec.\xfe\x99\xff\\\xf0\r\x03\xa81{\x92\xa2J\xefD\x1f~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd9\xec\x8f\xe6\x9bw\x16\xc0\x86Z\xf8\x88\xa1\x1b+\x12\xf7 \xed3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\xf1\xb2d\b\xf0\xecg\xad\x1d\ro\xe2.\x85\x15\xe1t\x06$\x89\x01M\x11 \u05f1`\x00\x00\u07d4\xd9\xf5G\xf2\xc1\xde\x0e\u064aS\xd1a\xdfWc]\xd2\x1a\x00\xbd\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xd9\xff\x11]\x01&l\x9fs\xb0c\xc1\xc28\xef5e\xe6;6\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xda\x06\x04N)#&\xffil\x0091h\xceF\xff\xac9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda*\x14\xf9r@\x15\u05d0\x14\xed\x8eY\th\x1dYaH\xf1\x89\x02\xa1\x0f\x0f\x8a\x91\xab\x80\x00\u07d4\xda*\u054ew\xde\xdd\xed\xe2\x18vF\xc4e\x94Z\x8d\xc3\xf6A\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\xda0\x17\xc1P\xdd\r\xce\u007f\u03c8\x1b\nH\xd0\xd1\xc7V\xc4\u01c9\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\xda4\xb2\xea\xe3\v\xaf\xe8\xda\xec\xcd\xe8\x19\xa7\x94\u0349\xe0\x95I\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdaJ_U\u007f;\xab9\n\x92\xf4\x9b\x9b\x90\n\xf3\fF\xae\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdaPU7S\u007f\xfb3\xc4\x15\xfe\xc6Ni\xba\xe0\x90\xc5\xf6\x0f\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdai\x8dd\xc6\\\u007f+,rS\x05\x9c\xd3\u0441\u0619\xb6\xb7\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\u07d4\xdaw2\xf0/.'.\xaf(\u07d7.\xcc\r\xde\xed\x9c\xf4\x98\x89\v \xbf\xbfig\x89\x00\x00\u07d4\xdaz\xd0%\xeb\xde%\xd2\"C\u02c3\x0e\xa1\xd3\xf6JVc#\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\u0685]SG\u007fP^\xc4\xc8\xd5\u8ed1\x80\u04c6\x81\x11\x9c\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\u0687^N/<\xab\xe4\xf3~\x0e\xae\xd7\xd1\xf6\xdc\xc6\xff\xefC\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u068b\xbe\xe1\x82\xe4U\xd2\t\x8a\xcb3\x8amE\xb4\xb1~\u0636\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0698.\x96C\xff\xec\xe7#\aZ@\xfewnZ\xce\x04\xb2\x9b\x89\b\xb8\xb6\u0259\x9b\xf2\x00\x00\u07d4\u069fUF\tF\u05ff\xb5p\xdd\xecu|\xa5w;XB\x9a\x89\x1b\x84]v\x9e\xb4H\x00\x00\u07d4\u06a1\xbdz\x91H\xfb\x86\\\xd6\x12\xdd5\xf1b\x86\x1d\x0f;\u0709\xa68\xabr\xd9,\x13\x80\x00\xe0\x94\u06a6<\xbd\xa4]\u0507\xa3\xf1\xcdJtj\x01\xbb^\x06\v\x90\x8a\x01\x04\x16\u0670*\x89$\x00\x00\u07d4\u06a7v\xa6uDi\u05f9&z\x89\xb8g%\xe7@\xda\x0f\xa0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u06ac\x91\xc1\xe8Y\xd5\xe5~\xd3\bKP \x0f\x97f\xe2\xc5+\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u06ac\xda\xf4\"&\xd1\\\xb1\u03d8\xfa\x15\x04\x8c\u007fL\xee\xfei\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\u06b6\xbc\u06c3\xcf$\xa0\xae\x1c\xb2\x1b;[\x83\xc2\xf3\x82I'\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\u06bb\b\x89\xfc\x04)&\xb0^\xf5{% \x91\n\xbcKAI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06bc\"PB\xa6Y,\xfa\x13\xeb\xe5N\xfaA\x04\bx\xa5\xa2\x89\x0e\x11\xfa\xd5\xd8\\\xa3\x00\x00\u07d4\xda\xc0\xc1w\xf1\x1c\\>>x\xf2\xef\xd6c\xd12!H\x85t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xd16\xb8\x81x\xb4\x83zlx\x0f\xeb\xa2&\xb9\x85i\xa9L\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xda\xdb\xfa\xfd\x8bb\xb9*$\xef\xd7RV\u0743\xab\xdb\u05fb\u06c9\x01\x11du\x9f\xfb2\x00\x00\u07d4\xda\xdc\x00\xaby'`\xaa4\x15i\xfa\x9f\xf5\x98&\x84\x85JJ2\x8an\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xe7 \x1e\xab\x8c\x063\x02\x93\ri9)\xd0\u007f\x95\xe7\x19b\x89\x91\xae\xc0(\xb4\x19\x81\x00\x00\u07d4\xda\xed\u052d\x10{'\x1e\x89Hl\xbf\x80\xeb\xd6!\u0757Ex\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x04\xfa\xd9\u011f\x9e\x88\v\xeb\x8f\xcf\x1d:8\x90\u4cc4o\x89CZ\xe6\xcc\fX\xe5\x00\x00\u07d4\xdb\f\u01cft\u0642{\u070ads'n\xb8O\u0717b\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x12\x93\xa5\x06\xe9\f\xad*Y\xe1\xb8V\x1f^f\x96\x1ag\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x19\xa3\x98\"06\x8f\x01w!\x9c\xb1\f\xb2Y\u0372%|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb#\xa6\xfe\xf1\xaf{X\x1ew,\xf9\x18\x82\u07b2Qo\xc0\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb$O\x97\xd9\xc4K\x15\x8a@\xed\x96\x06\xd9\xf7\xbd8\x9131\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xdb(\x8f\x80\xff\xe22\u00baG\u0314\xc7c\xcfo\u0278+\r\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xdb*\f\x9a\xb6M\xf5\x8d\u07f1\u06ec\xf8\xba\r\x89\xc8[1\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdb4t^\u0785v\xb4\x99\xdb\x01\xbe\xb7\xc1\xec\u0685\xcfJ\xbe\x89\x04V9\x18$O@\x00\x00\u07d4\xdb?%\x8a\xb2\xa3\xc2\xcf3\x9cD\x99\xf7ZK\xd1\xd3G.\x9e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xdbK\xc8;\x0ek\xaa\xdb\x11V\xc5\xcf\x06\xe0\xf7!\x80\x8cR\u01c9/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xdbc\x12-\xe7\x03}\xa4\x97\x151\xfa\u9bc5\x86x\x86\u0192\x89\x0f\x04%\xb0d\x1f4\x00\x00\u07d4\xdbl*s\xda\xc7BJ\xb0\xd01\xb6ga\x12%f\xc0\x10C\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xdbnV\f\x9b\xc6 \u053e\xa3\xa9MG\xf7\x88\v\xf4\u007f-_\x89\x04\xda\x0f\xdf\xcf\x05v\x00\x00\u07d4\xdbo\xf7\x1b=\xb0\x92\x8f\x83\x9e\x05\xa72;\xfbW\u049c\x87\xaa\x891T\xc9r\x9d\x05x\x00\x00\u07d4\xdbsF\vY\xd8\xe8PE\xd5\xe7R\xe6%Y\x87^BP.\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xdbw\xb8\x8d\xcbq/\xd1~\xe9\x1a[\x94t\x8dr\f\x90\xa9\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb}@7\b\x1fle\xf9Gk\x06\x87\xd9\u007f\x1e\x04M\n\x1d\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\u06c8.\xac\xed\xd0\xef\xf2cQ\x1b1*\u06fcY\u01b8\xb2[\x8a\x01\xedO\xdez\"6\xb0\x00\x00\u07d4\u06d3q\xb3\fL\x84NY\xe0>\x92K\xe6\x06\xa98\xd1\xd3\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06e4ym\f\xebM:\x83k\x84\xc9o\x91\n\xfc\x10?[\xa0\x89\t\b\xf4\x93\xf77A\x00\x00\u07d4\u06ed\xc6\x1e\xd5\xf0F\n\u007f\x18\xe5\x1b/\xb2aM\x92d\xa0\xe0\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u06f6\xacH@'\x04\x16B\xbb\xfd\x8d\x80\xf9\xd0\xc1\xcf3\xc1\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06fc\xbby\xbfG\x9aB\xadq\xdb\u02b7{Z\u07ea\x87,X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xdb\xc1\xce\x0eI\xb1\xa7\x05\xd2. 7\xae\xc8x\xee\ru\xc7\x03\x89\r\x8drkqw\xa8\x00\x00\u07d4\xdb\xc1\xd0\xee+\xabS\x11@\xde\x13w\"\xcd6\xbd\xb4\xe4q\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\u015e\u0609s\u07ad1\b\x84\":\xf4\x97c\xc0P0\xf1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xdb\xc6ie\xe4&\xff\x1a\xc8z\xd6\xebx\xc1\xd9Rq\x15\x8f\x9f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xdb\xcb\xcdzW\ua7724\x9b\x87\x8a\xf3K\x1a\xd6B\xa7\xf1\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\xd5\x1c\xdf,;\xfa\xcd\xff\x10b!\xde.\x19\xadmB\x04\x14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdb\xd7\x1e\xfaK\x93\u0209\xe7e\x93\xde`\x9c;\x04\u02ef\xbe\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xdb\xf5\xf0a\xa0\xf4\x8e^ia\x879\xa7}.\xc1\x97h\xd2\x01\x89\b=lz\xabc`\x00\x00\u07d4\xdb\xf8\xb19g\xf5Q%'-\xe0V%6\xc4P\xbaVU\xa0\x89n\xf5x\xf0n\f\xcb\x00\x00\u07d4\xdb\xfb\x1b\xb4d\xb8\xa5\x8eP\r.\xd8\u0797,E\xf5\xf1\xc0\xfb\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xdc\x06~\xd3\xe1-q\x1e\xd4u\xf5\x15n\xf7\xe7\x1a\x80\xd94\xb9\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xdc\b\u007f\x93\x90\xfb\x9e\x97j\xc2:\xb6\x89TJ\tB\xec !\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xdc\x1e\xb9\xb6\xe6CQ\xf5d$P\x96E\xf8>y\xee\xe7l\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\x1f\x19ya_\b!@\xb8\xbbx\xc6{'\xa1\x94'\x13\xb1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xdc#\xb2`\xfc\xc2n}\x10\xf4\xbd\x04J\xf7\x94W\x94`\xd9\u0689\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xdc)\x11\x97E\xd23s \xdaQ\xe1\x91\x00\xc9H\u0640\xb9\x15\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdc-\x15\xa6\x9fk\xb3;$j\xef@E\aQ\xc2\xf6uj\u0489l4\x10\x80\xbd\x1f\xb0\x00\x00\u07d4\xdc=\xaeY\xed\x0f\xe1\x8bXQ\x1eo\xe2\xfbi\xb2\x19h\x94#\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xdc?\x0evr\xf7\x1f\xe7R[\xa3\v\x97U\x18: \xb9\x16j\x8a\x02\b\x9c\xf5{[>\x96\x80\x00\xe0\x94\xdcCE\u0581.\x87\n\xe9\fV\x8cg\xd2\xc5g\u03f4\xf0<\x8a\x01k5-\xa5\xe0\xed0\x00\x00\u07d4\xdcD'[\x17\x15\xba\xea\x1b\x03EsZ)\xacB\xc9\xf5\x1bO\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xdcF\xc13%\u034e\xdf\x020\xd0h\x89d\x86\xf0\a\xbfN\xf1\x89Hz\x9a0E9D\x00\x00\u07d4\xdcQ\xb2\u071d$z\x1d\x0e[\xc3l\xa3\x15oz\xf2\x1f\xf9\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdcS\x05\xb4\x02\n\x06\xb4\x9de||\xa3L5\xc9\x1c_,V\x8a\x01}\xf6\xc1\r\xbe\xba\x97\x00\x00\u07d4\xdcW4[8\xe0\xf0g\u0263\x1d\x9d\xea\xc5'Z\x10\x94\x93!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdcWG}\xaf\xa4/p\\\u007f\xe4\x0e\xae\x9c\x81un\x02%\xf1\x89\x1b\x1b\x81(\xa7An\x00\x00\u07d4\xdc_Z\xd6c\xa6\xf2c2}d\xca\xc9\xcb\x13=,\x96\x05\x97\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdcp:_7\x94\xc8Ml\xb3TI\x18\xca\xe1J5\u00fdO\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\xdcs\x8f\xb2\x17\u03ad/iYL\b\x17\r\xe1\xaf\x10\xc4\x19\xe3\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xdcv\xe8[\xa5\v\x9b1\xec\x1e& \xbc\xe6\xe7\xc8\x05\x8c\x0e\xaf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0703\xb6\xfd\rQ!1 G\a\xea\xf7.\xa0\xc8\u027e\xf9v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u070c)\x12\xf0\x84\xa6\u0444\xaasc\x85\x13\u033c2n\x01\x02\x89F3\xbc6\xcb\xc2\xdc\x00\x00\u07d4\u0711\x1c\xf7\xdc]\u04016Vg\x05(\xe93\x8eg\x03G\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0730;\xfal\x111#NV\xb7\xea|Or\x14\x87Tkz\x89Hz\x9a0E9D\x00\x00\xe0\x94\u0736M\xf47X\xc7\u03d7O\xa6`HO\xbbq\x8f\x8cg\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdc\xc5-\x8f\x8d\x9f\xc7B\xa8\xb8'g\xf0US\x87\xc5c\xef\xff\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xdc\xcb7\x0e\u058a\xa9\"(0C\xef|\xad\x1b\x9d@?\xc3J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\u0324 E\xec>\x16P\x8b`?\xd96\xe7\xfd}\xe5\xf3j\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xdc\xd1\fU\xbb\x85OuD4\xf1!\x9c,\x9a\x98\xac\xe7\x9f\x03\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xdc\u057c\xa2\x00S\x95\xb6u\xfd\xe5\x03VY\xb2k\xfe\xfcI\xee\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xdc\u06fdN&\x04\xe4\x0e\x17\x10\xccg0(\x9d\xcc\xfa\u04c9-\x89\xf9]\xd2\xec'\xcc\xe0\x00\x00\u07d4\xdc\xe3\f1\xf3\xcafr\x1e\xcb!<\x80\x9a\xabV\x1d\x9bR\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdc\xf39eS\x13\x80\x161h\xfc\x11\xf6~\x89\xc6\xf1\xbc\x17\x8a\x89\x12'v\x854\x06\xb0\x80\x00\u07d4\xdc\xf6\xb6W&n\x91\xa4\xda\xe6\x03=\xda\xc1S2\u074d+4\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdc\xf9q\x9b\xe8|oFum\xb4\x89\x1d\xb9\xb6\x11\xd2F\x9cP\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdc\xff\xf3\xe8\xd2<*4\xb5k\u0473\xbdE\u01d3tC\"9\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xdd\x04\xee\xe7N\v\xf3\f?\x8dl,\u007fR\xe0Q\x92\x10\u07d3\x89\x04V9\x18$O@\x00\x00\xe0\x94\xdd&\xb4)\xfdC\xd8N\xc1y\x82S$\xba\u057f\xb9\x16\xb3`\x8a\x01\x16\xbf\x95\xbc\x842\x98\x00\x00\u07d4\xdd*#:\xde\xdef\xfe\x11&\xd6\xc1h#\xb6*\x02\x1f\xed\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd+\u07e9\x17\xc1\xf3\x10\xe6\xfa5\xaa\x8a\xf1i9\xc23\xcd}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xdd5\xcf\xdb\u02d93\x95Sz\xec\xc9\xf5\x90\x85\xa8\xd5\u0776\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xddG\x18\x9a>d9qg\xf0b\x0eHEe\xb7b\xbf\xbb\xf4\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xddM\xd6\xd3`3\xb0co\u030d\t8`\x9fM\xd6OJ\x86\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xddO_\xa2\x11\x1d\xb6\x8fk\xde5\x89\xb60)9[i\xa9-\x89\b\x96=\xd8\xc2\xc5\xe0\x00\x00\xe0\x94\xddc\x04/%\xed2\x88J\xd2n:\xd9Y\xeb\x94\xea6\xbfg\x8a\x04\x84\xd7\xfd\xe7\u0553\xf0\x00\x00\u07d4\xdde\xf6\xe1qc\xb5\xd2\x03d\x1fQ\xcc{$\xb0\x0f\x02\xc8\xfb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xddl\x06!\x93\xea\xc2=/\xdb\xf9\x97\xd5\x06:4k\xb3\xb4p\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdd{\u0366Y$\xaa\xa4\x9b\x80\x98J\xe1su\x02X\xb9(G\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdd\u007f\xf4A\xbao\xfe6q\xf3\xc0\u06bb\xff\x18#\xa5\x043p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0742T\x12\x1an\x94/\xc9\b(\xf2C\x1fQ\x1d\xad\u007f2\u6263\x9b)\xe1\xf3`\xe8\x00\x00\xe0\x94\u074a\xf9\xe7vR#\xf4DoD\xd3\xd5\t\x81\x9a==\xb4\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\u0755\xdb\xe3\x0f\x1f\x18w\xc5\xddv\x84\xae\xef0*\xb6\x88Q\x92\x8a\x01\xc5\xd8\xd6\xeb>2P\x00\x00\xe0\x94\u0756|L_\x8a\xe4~&o\xb4\x16\xaa\u0456N\xe3\xe7\xe8\u00ca\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u075bHZ;\x1c\xd3:j\x9cb\xf1\xe5\xbe\xe9'\x01\x85m%\x89\f3\x83\xed\x03\x1b~\x80\x00\xe0\x94\u0763q\xe6\x00\xd3\x06\x88\xd4q\x0e\b\x8e\x02\xfd\xf2\xb9RM_\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\u0764\xed*X\xa8\xdd \xa72u4{X\rq\xb9[\xf9\x9a\x89\x15\xa1<\xc2\x01\xe4\xdc\x00\x00\xe0\x94\u0764\xff}\xe4\x91\u0187\xdfEt\xdd\x1b\x17\xff\x8f$k\xa3\u044a\x04&\x84\xa4\x1a\xbf\xd8@\x00\x00\u07d4\u076bkQ\xa9\x03\v@\xfb\x95\xcf\vt\x8a\x05\x9c$\x17\xbe\u01c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u076bu\xfb/\xf9\xfe\u02c8\xf8\x94vh\x8e+\x00\xe3g\xeb\xf9\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\xe0\x94\u076b\xf1<<\x8e\xa4\xe3\xd7=x\xecqz\xfa\xfaC\x0eTy\x8a\b\xcf#\xf9\t\xc0\xfa\x00\x00\x00\u07d4\u076c1*\x96UBj\x9c\f\x9e\xfa?\xd8%Y\xefE\x05\xbf\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\u076ck\xf4\xbb\xdd}Y}\x9chm\x06\x95Y;\xed\xcc\xc7\xfa\x89.\xe4IU\b\x98\xe4\x00\x00\xe0\x94\u077d+\x93,v;\xa5\xb1\xb7\xae;6.\xac>\x8d@\x12\x1a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u077d\xdd\x1b\xbd8\xff\xad\xe00]0\xf0 (\xd9.\x9f:\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u077e\xe6\xf0\x94\xea\xe64 \xb0\x03\xfbGW\x14*\xeal\xd0\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd\u059c[\x9b\xf5\xebZ9\xce\xe7\xc34\x1a\x12\r\x97?\xdb4\x89k\xc1K\x8f\x8e\x1b5\x00\x00\xe0\x94\xdd\xdd{\x9en\xab@\x9b\x92&:\xc2r\u0680\x1bfO\x8aW\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4\xdd\xe6p\xd0\x169fuv\xa2-\xd0]2F\xd6\x1f\x06\xe0\x83\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94\xdd\xe7zG@\xba\b\xe7\xf7?\xbe:\x16t\x91)1t.\xeb\x8a\x044\xfeMC\x82\xf1\u0500\x00\u07d4\xdd\xe8\xf0\xc3\x1bt\x15Q\x1d\xce\xd1\xcd}F2>K\xd1\"2\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xdd\xe9i\xae\xf3N\xa8z\u0099\xb7Y~)+J\x01U\u030a\x89\x102\xf2YJ\x01s\x80\x00\u07d4\xdd\xf0\xcc\xe1\xfe\x99m\x91v5\xf0\a\x12\xf4\x05 \x91\xdf\xf9\xea\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdd\xf3\xadv58\x10\xbej\x89\xd71\xb7\x87\xf6\xf1q\x88a+\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xdd\xf5\x81\n\x0e\xb2\xfb.22;\xb2\u0255\t\xab2\x0f$\xac\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x94\xdd\xf9\\\x1e\x99\xce/\x9fV\x98\x05|\x19\xd5\xc9@'\xeeJn\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xdd\xfa\xfd\xbc|\x90\xf12\x0eT\xb9\x8f7F\x17\xfb\xd0\x1d\x10\x9f\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xdd\xfc\xca\x13\xf94\xf0\u03fe#\x1d\xa109\xd7\x04u\xe6\xa1\u040968\"\x16`\xa5\xaa\x80\x00\u07d4\xde\x02~\xfb\xb3\x85\x03\"n\xd8q\t\x9c\xb3\v\xdb\x02\xaf\x135\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xde\x06\xd5\xeawzN\xb1G^`]\xbc\xbfCDN\x807\xea\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xde\a\xfb[zFN;\xa7\xfb\xe0\x9e\x9a\xcb'\x1a\xf53\x8cX\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xde\x11!\x82\x9c\x9a\b(@\x87\xa4?\xbd/\xc1\x14*23\xb4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xde\x17kR\x84\xbc\xee:\x83\x8b\xa2Og\xfc|\xbfg\u05ce\xf6\x89\x02\t\xce\b\xc9b\xb0\x00\x00\u07d4\xde!\"\x93\xf8\xf1\xd21\xfa\x10\xe6\tG\rQ,\xb8\xff\xc5\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde0\xe4\x9eZ\xb3\x13!M/\x01\u072b\u0389@\xb8\x1b\x1cv\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xde3\xd7\b\xa3\xb8\x9e\x90\x9e\xafe;0\xfd\u00e5\xd5\u0334\xb3\x89\t\x9c\x88\"\x9f\xd4\xc2\x00\x00\u07d4\xde7B\x99\xc1\xd0}ySs\x85\x19\x0fD.\xf9\xca$\x06\x1f\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xdeB\xfc\xd2L\xe4#\x93\x830CgY_\x06\x8f\fa\a@\x89\x02r*p\xf1\xa9\xa0\x00\x00\u07d4\xdeP\x86\x8e\xb7\xe3\xc7\x197\xecs\xfa\x89\u074b\x9e\xe1\rE\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdeU\xde\x04X\xf8P\xb3~Mx\xa6A\xdd.\xb2\u074f8\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde[\x00_\xe8\u06ae\x8d\x1f\x05\xde>\xda\x04 f\xc6\xc4i\x1c\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xdea-\a$\xe8N\xa4\xa7\xfe\xaa=!B\xbd^\xe8-2\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdem61\x06\xccb8\xd2\xf0\x92\xf0\xf07!6\xd1\xcdP\u018a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xde}\xee\"\x0f\x04W\xa7\x18}V\xc1\xc4\x1f.\xb0\n\xc5`!\x89\"%\xf3\x9c\x85\x05*\x00\x00\u07d4\u0782\u030dJ\x1b\xb1\xd9CC\x92\x96[>\x80\xba\xd3\xc0=O\x89P\x18nu\u0797\xa6\x00\x00\u07d4\u0797\xf43\a\x00\xb4\x8cImC|\x91\xca\x1d\xe9\u0130\x1b\xa4\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\u07d4\u079e\xffLy\x88\x11\xd9h\xdc\xcbF\r\x9b\x06\x9c\xf3\x02x\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u07b1\xbc4\xd8mJM\xde%\x80\u063e\xaf\aN\xb0\xe1\xa2D\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\u07b2I]j\xca{*j-\x13\x8bn\x1aB\xe2\xdc1\x1f\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\u07b9rTGL\r/Zyp\xdc\xdb/R\xfb\x10\x98\xb8\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07b9\xa4\x9aC\x870 \xf0u\x91\x85\xe2\v\xbbL\U000c1ecf\x89\vx\xed\xb0\xbf.^\x00\x00\u07d4\u07bb\u0743\x1e\x0f \xaen7\x82R\xde\xcd\xf9/|\xf0\xc6X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xc3\xee\xc2d\nu,Fn+~~\u616f\xe9\xacA\xf4\x89G\u0257SYk(\x80\x00\u07d4\xde\xc8#s\xad\xe8\xeb\xcf*\xcbo\x8b\xc2AM\u05eb\xb7\rw\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xde\u0221\xa8\x98\xf1\xb8\x95\xd80\x1f\xe6J\xb3\xad]\xe9A\xf6\x89\x89*\xb4\xf6~\x8as\x0f\x80\x00\u07d4\xde\u025e\x97/\xcaqwP\x8c\x8e\x1aG\xac\"\xd7h\xac\xab|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xd8w7\x84\a\xb9Nx\x1cN\xf4\xaf|\xfc[\xc2 \xb5\x16\x89\x141y\xd8i\x11\x02\x00\x00\u07d4\xde\xe9B\xd5\xca\xf5\xfa\xc1\x14!\xd8k\x01\vE\x8e\\9)\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde\xee&\x89\xfa\x90\x06\xb5\x9c\xf2\x85#}\xe5;:\u007f\xd0\x148\x89\x18ey\xf2\x9e %\x00\x00\u07d4\xde\xfd\xdf\u055b\x8d,\x15N\xec\xf5\xc7\xc1g\xbf\v\xa2\x90]>\x89\x05\x12\xcb^&GB\x00\x00\u07d4\xde\xfe\x91A\xf4pE\x99\x15\x9d{\"=\xe4+\xff\xd8\x04\x96\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xdf\t\x8f^N=\xff\xa5\x1a\xf27\xbd\xa8e,Os\ud726\x89\x1b6\xa6DJ>\x18\x00\x00\xe0\x94\xdf\r\ba{\xd2R\xa9\x11\u07cb\xd4\x1a9\xb8=\u07c0\x96s\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdf\x0f\xf1\xf3\xd2z\x8e\xc9\xfb\x8fk\f\xb2T\xa6;\xba\x82$\xa5\x89\xec\xc5 )E\xd0\x02\x00\x00\u07d4\xdf\x1f\xa2\xe2\x0e1\x98^\xbe,\x0f\f\x93\xb5L\x0f\xb6z&K\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdf!\x1c\xd2\x12\x88\xd6\xc5o\xaef\xc3\xffTb]\u0531T'\x89\x87\x86\xcdvN\x1f,\x00\x00\u07d4\xdf#k\xf6\xab\xf4\xf3)7\x95\xbf\f(q\x8f\x93\u3c73k\x89Hz\x9a0E9D\x00\x00\u07d4\xdf1\x02_VI\xd2\xc6\xee\xa4\x1e\u04fd\xd3G\x1ay\x0fu\x9a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdf7\xc2.`:\xed\xb6\nbrS\xc4}\x8b\xa8f\xf6\xd9r\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xdf;r\u017dq\u0501N\x88\xa6#!\xa9=@\x11\xe3W\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf?W\xb8\xeed4\xd0G\"=\xeft\xb2\x0fc\xf9\xe4\xf9U\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d4\xdfD\xc4\u007f\xc3\x03\xacv\xe7O\x97\x19L\xcag\xb5\xbb<\x02?\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xdfG\xa6\x1brSQ\x93\xc5a\xcc\xccu\xc3\xf3\xce\b\x04\xa2\x0e\x89\x15\x93\\\vN=x\x00\x00\u07d4\xdfG\xa8\xef\x95\xf2\xf4\x9f\x8eoX\x18AT\x14]\x11\xf7'\x97\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xdfS\x003F\xd6\\^zdk\xc04\xf2\xb7\xd3/\xcb\xe5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfW5:\xaf\xf2\xaa\xdb\n\x04\xf9\x01N\x8d\xa7\x88N\x86X\x9c\x89\bH\x86\xa6nO\xb0\x00\x00\u07d4\xdf`\xf1\x8c\x81*\x11\xedN'v\xe7\xa8\x0e\xcf^S\x05\xb3\u05890\xca\x02O\x98{\x90\x00\x00\u07d4\xdfd\x85\xc4)z\xc1R\xb2\x89\xb1\x9d\xde2\xc7~\xc4\x17\xf4}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdff\n\x91\u06b9\xf70\xf6\x19\rP\xc89\x05aP\aV\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfn\xd6\x00jj\xbe\x88n\xd3=\x95\xa4\xde(\xfc\x12\x189'\x891T\xc9r\x9d\x05x\x00\x00\u07d4\u07c5\x10y>\xee\x81\x1c-\xab\x1c\x93\xc6\xf4G?0\xfb\xef[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07cdH\xb1\xeb\a\xb3\xc2\x17y\x0el-\xf0M\xc3\x19\xe7\xe8H\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u07e6\xb8\xb8\xad1\x84\xe3W\xda()Q\u05d1a\u03f0\x89\xbc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u07ef1\xe6\"\xc0=\x9e\x18\xa0\u0778\xbe`\xfb\xe3\xe6a\xbe\n\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\u07f1bn\xf4\x8a\x1d}uR\xa5\xe0)\x8f\x1f\xc2:;H-\x89\\\xe8\x95\u0754\x9e\xfa\x00\x00\xe0\x94\u07f4\u052d\xe5/\u0301\x8a\xccz,k\xb2\xb0\x02$e\x8fx\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u07fdB2\xc1|@z\x98\r\xb8\u007f\xfb\u036060\xe5\xc4Y\x89\x1d\xfc\u007f\x92I#S\x00\x00\u07d4\xdf\xcb\xdf\tEN\x1a^J@\xd3\xee\xf7\xc5\xcf\x1c\xd3\u0794\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf\xdb\xce\xc1\x01K\x96\xda!X\xcaQ>\x9c\x8d;\x9a\xf1\xc3\u0409lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdf\xde\xd2WK'\xd1a:}\x98\xb7\x15\x15\x9b\r\x00\xba\xab(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdf\xdfC9P\x8b\x0fnZ\xb1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe0\x06\x04b\xc4\u007f\xf9g\x9b\xae\xf0qY\xca\xe0\x8c)\xf2t\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\r\x15;\x106\x91C\xf9\u007fT\xb8\xd4\xca\"\x9e\xb3\xe8\xf3$\x89\b=lz\xabc`\x00\x00\u07d4\xe0\x12\xdbE8'\xa5\x8e\x16\xc16V\b\xd3n\xd6Xr\x05\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x15G\xbaB\xfc\xaf\xaf\x93\x93\x8b\xec\xf7i\x9ft)\n\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x16\xdc\x13\x8e%\x81[\x90\xbe?\xe9\xee\xe8\xff\xb2\xe1\x05bO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\x18Y\xf2B\xf1\xa0\xec`/\xa8\xa3\xb0\xb5v@\xec\x89\a^\x89\x1e\x16,\x17{\xe5\xcc\x00\x00\xe0\x94\xe0 \xe8cb\xb4\x87u(6\xa6\xde\v\xc0,\xd8\u061a\x8bj\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xe0#\xf0\x9b(\x87a,|\x9c\xf1\x98\x8e::`+3\x94\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0'\"\x13\xe8\xd2\xfd>\x96\xbdb\x17\xb2KK\xa0\x1bapy\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0+t\xa4v(\xbe1[\x1fv\xb3\x15\x05J\xd4J\xe9qo\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe02 \u0197\xbc\u048f&\xef\vt@J\x8b\xeb\x06\xb2\xba{\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe05/\u07c1\x9b\xa2e\xf1L\x06\xa61\\J\xc1\xfe\x13\x1b.\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe08\x8a\xed\xdd?\xe2\xadV\xf8WH\xe8\x0eq\n4\xb7\xc9.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0<\x00\xd0\x03\x88\xec\xbfO&=\n\xc7x\xbbA\xa5z@\u064966\xc9yd6t\x00\x00\u07d4\xe0I \xdcn\xcc\x1dn\xcc\bO\x88\xaa\n\xf5\u06d7\xbf\x89:\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xe0Ir\xa8<\xa4\x11+\xc8q\xc7-J\xe1al/\a(\u06c9\x0e\x81\xc7\u007f)\xa3/\x00\x00\u07d4\xe0O\xf5\xe5\xa7\u2bd9]\x88W\xce\x02\x90\xb5:+\x0e\xda]\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xe0P)\xac\xeb\axg[\xef\x17A\xab,\u0493\x1e\xf7\xc8K\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0V\xbf?\xf4\x1c&%o\xefQqf\x12\xb9\u04da\u0799\x9c\x89\x05k\xe7W\xa1.\n\x80\x00\u07d4\xe0a\xa4\xf2\xfcw\xb2\x96\u045a\xda#\x8eI\xa5\u02ce\xcb\xfap\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0f>\x8c\xd6g\x92\xa6A\xf5nP\x03f\x01G\x88\x0f\x01\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0f\x8f\xa8,\x14\xd6\xe8\xd9:S\x11>\xf2\x86/\xa8\x15\x81\xbc\x89//9\xfclT\x00\x00\x00\u07d4\xe0i\xc0\x173R\xb1\v\xf6\x83G\x19\xdb[\xed\x01\xad\xf9{\xbc\x89\x01\x064\xf8\xe52;\x00\x00\u07d4\xe0l)\xa8\x15\x17\xe0\u0507\xb6\u007f\xb0\xb6\xaa\xbcOW6\x83\x88\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xe0l\xb6)G\x04\xee\xa7C|/\xc3\xd3\as\xb7\xbf8\x88\x9a\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\xe0q7\xae\r\x11m\x0353\xc4\uad16\xf8\xa9\xfb\tV\x9c\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe0v\xdb0\xabHoy\x19N\xbb\xc4]\x8f\xab\x9a\x92B\xf6T\x8a\x01\x06`~4\x94\xba\xa0\x00\x00\u07d4\xe0~\xbb\xc7\xf4\xdaAnB\xc8\xd4\xf8B\xab\xa1b3\xc1%\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x81\xca\x1fH\x82\xdb`C\u0569\x19\a\x03\xfd\xe0\xab;\xf5m\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x83\xd3Hc\xe0\xe1\u007f\x92ky(\xed\xff1~\x99\x8e\x9cK\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x8b\x9a\xbak\xd9\u048b\xc2\x05gy\xd2\xfb\xf0\xf2\x85Z=\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x8b\u009c+H\xb1i\xff+\xdc\x16qLXnl\xb8\\\u03c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0\x8c`11\x06\xe3\xf93O\xe6\xf7\xe7bM!\x110\xc0w\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xe0\x9ch\xe6\x19\x98\xd9\xc8\x1b\x14\xe4\xee\x80+\xa7\xad\xf6\xd7L\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0\x9f\xeauZ\xee\x1aD\xc0\xa8\x9f\x03\xb5\u07b7b\xba3\x00o\x89;\xa2\x89\xbc\x94O\xf7\x00\x00\xe0\x94\xe0\xa2T\xac\t\xb9r[\xeb\xc8\xe4`C\x1d\xd0s.\xbc\xab\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe0\xaai6UU\xb7?(#3\xd1\xe3\f\x1b\xbd\a(T\xe8\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xe0\xba\u064e\ue598\xdb\xf6\xd7`\x85\xb7\x92=\xe5uN\x90m\x89\t\r\x97/22<\x00\x00\u07d4\xe0\u012b\x90r\xb4\xe6\xe3eJI\xf8\xa8\xdb\x02jK3\x86\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\u0380\xa4a\xb6H\xa5\x01\xfd\v\x82F\x90\u0206\x8b\x0eM\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\xcfi\x8a\x053'\xeb\xd1k}w\x00\t/\xe2\xe8T$F\x89\x05*4\u02f6\x1fW\x80\x00\xe0\x94\xe0\xd21\xe1D\xec\x91\a8l|\x9b\x02\xf1p,\xea\xa4\xf7\x00\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0\xd7kqf\xb1\xf3\xa1+@\x91\xee+)\u078c\xaa}\a\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\xe0\xb2\xe2\x9d\xdes\xafu\x98~\xe4Dl\x82\x9a\x18\x9c\x95\xbc\x89\b\x13\xcaV\x90m4\x00\x00\xe0\x94\xe0\xe9xu=\x98/\u007f\x9d\x1d#\x8a\x18\xbdH\x89\xae\xfeE\x1b\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\xe0\xf3r4|\x96\xb5_}C\x06\x03K\xeb\x83&o\xd9\tf\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\xf9\x03\xc1\xe4\x8a\xc4!\xabHR\x8f=J&H\b\x0f\xe0C\x897\b\xba\xed=h\x90\x00\x00\u07d4\xe0\xff\v\xd9\x15D9\u0125\xb7#>)\x1d}\x86\x8a\xf5?3\x89\x15y!jQ\xbb\xfb\x00\x00\xe0\x94\xe1\n\xc1\x9cTo\xc2T|a\xc19\xf5\xd1\xf4Zff\u0570\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\xe0\x94\xe1\fT\x00\x88\x11?\xa6\xec\x00\xb4\xb2\u0202O\x87\x96\xe9n\u010a2\x0fE\t\xab\x1e\xc7\xc0\x00\x00\xe0\x94\xe1\x17:$})\xd8#\x8d\xf0\x92/M\xf2Z\x05\xf2\xafw\u00ca\bx\xc9]V\x0f0G\x80\x00\xe0\x94\xe1 >\xb3\xa7#\xe9\x9c\" \x11|\xa6\xaf\xebf\xfaBOa\x8a\x02\x00\uf49e2V\xfe\x00\x00\xe0\x94\xe11\xf8~\xfc^\xf0~C\xf0\xf2\xf4\xa7G\xb5Q\xd7P\xd9\xe6\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\u07d4\xe13N\x99\x83y\xdf\xe9\x83\x17pby\x1b\x90\xf8\x0e\xe2-\x8d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe15@\xec\xee\x11\xb2\x12\xe8\xb7u\u070eq\xf3t\xaa\xe9\xb3\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1;=+\xbf\u073c\x87r\xa23\x15rL\x14%\x16|V\x88\x897\xf3y\x14\x1e\xd0K\x80\x00\u07d4\xe1D=\xbd\x95\xccA#\u007fa:HEi\x88\xa0Oh2\x82\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xe1F\x17\xf6\x02%\x01\xe9~{>-\x886\xaaa\xf0\xff-\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe1I\xb5rl\xafm^\xb5\xbf*\xccA\xd4\xe2\xdc2\x8d\u1089i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xe1T\xda\xea\xdbTX8\xcb\u01aa\fUu\x19\x02\xf5(h*\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4\xe1l\xe3Ya\xcdt\xbdY\r\x04\u012dJ\x19\x89\xe0V\x91\u0189\a\xea(2uw\b\x00\x00\u07d4\xe1r\xdf\xc8\xf8\f\xd1\xf8\u03459\xdc&\b \x14\xf5\xa8\xe3\u8262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xe1w\xe0\xc2\x01\xd35\xba9V\x92\x9cW\x15\x88\xb5\x1cR#\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1x\x12\xf6l^e\x94\x1e\x18lF\x92+n{/\x0e\xebF\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe1\x80\u079e\x86\xf5{\xaf\xac\u05d0O\x98&\xb6\xb4\xb2c7\xa3\x89-\x04\x1dpZ,`\x00\x00\xe0\x94\xe1\x92H\x9b\x85\xa9\x82\xc1\x882F\xd9\x15\xb2)\xcb\x13 \u007f8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xe1\x95\xbb\xc6,{tD\x04\x0e\xb9\x96#\x96Ovg\xb3v\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\x06\xfbs$\xe9\u07b7\x9e\x19\x904\x96\u0596\x1b\x9b\xe5f\x03\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe2\aW\x8e\x1fM\u06cf\xf6\u0546{9X-q\xb9\x81*\u0149\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xe2\b\x81*h@\x98\xf3\xdaN\xfej\xba%bV\xad\xfe?\xe6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2\tT\xd0\xf4\x10\x8c\x82\xd4\u0732\x14\x8d&\xbb\xd9$\xf6\xdd$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe2\v\xb9\xf3\x96d\x19\xe1K\xbb\xaa\xaag\x89\xe9$\x96\u03e4y\x89\xbb\xd8%\x03\aRv\x00\x00\u07d4\xe2\r\x1b\xcbq(m\xc7\x12\x8a\x9f\xc7\xc6\xed\u007fs8\x92\xee\xf5\x896d\xf8\xe7\xc2J\xf4\x00\x00\u0794\xe2\x19\x12\x15\x98?3\xfd3\xe2,\u0522I\x00T\xdaS\xfd\u0708\xdbD\xe0I\xbb,\x00\x00\u07d4\xe2\x19\x8c\x8c\xa1\xb3\x99\xf7R\x15a\xfdS\x84\xa7\x13/\xbaHk\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xe2\x1cw\x8e\xf2\xa0\xd7\xf7Q\xea\x8c\aM\x1f\x81\"C\x86>N\x8a\x01\x1f\xc7\x0e,\x8c\x8a\xe1\x80\x00\xe0\x94\xe2)\xe7F\xa8?,\xe2S\xb0\xb0>\xb1G$\x11\xb5~W\x00\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xe2+ \xc7x\x94F;\xafwL\xc2V\u057d\u06ff}\xdd\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe20\xfe\x1b\xff\x03\x18m\x02\x19\xf1]LH\x1b}Y\xbe(j\x89\x01\xfdt\x1e\x80\x88\x97\x00\x00\u07d4\xe27\xba\xa4\xdb\u0252n2\xa3\xd8]\x12d@-T\xdb\x01/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2A\t\xbe/Q=\x87I\x8e\x92j(d\x99uO\x9e\u051e\x890\x0e\xa8\xad\x1f'\xca\x00\x00\u07d4\xe2Fh<\u025d\xb7\u0125+\u02ec\xaa\xb0\xb3/k\xfc\x93\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2Z\x16{\x03\x1e\x84am\x0f\x01?1\xbd\xa9]\xcccP\xb9\x8a\x02\x8c*\xaa\u0243\xd0]\u0187st\xa8\xf4F\xee\xe9\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xe2\x8b\x06\"Y\xe9n\xeb<\x8dA\x04\x94?\x9e\xb3%\x89<\xf5\x89Hz\x9a0E9D\x00\x00\xe0\x94\u237c\x8e\xfd^Ajv.\xc0\xe0\x18\x86K\xb9\xaa\x83({\x8a\x051\xf2\x00\xab>\x03\n\x80\x00\u07d4\xe2\x90K\x1a\xef\xa0V9\x8bb4\xcb5\x81\x12\x88\xd76\xdbg\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u274a\xe4R\xdc\xf3\xb6\xacd^c\x04\t8UQ\xfa\xae\n\x89\x04Z\r\xa4\xad\xf5B\x00\x00\u07d4\xe2\xbb\xf8FA\xe3T\x1fl3\xe6\xedh:cZp\xbd\xe2\xec\x89\x1bA<\xfc\xbfY\xb7\x80\x00\u07d4\xe2\xcf6\n\xa22\x9e\xb7\x9d+\xf7\xca\x04\xa2z\x17\xc52\xe4\u0609\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xe2\xdf#\xf6\xea\x04\xbe\xcfJ\xb7\x01t\x8d\xc0\x961\x84U\\\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2\xe1\\`\xdd8\x1e:K\xe2Pq\xab$\x9aL\\Rd\u0689\u007fk\u011b\x81\xb57\x00\x00\u07d4\xe2\xe2nN\x1d\xcf0\xd0H\xccn\u03ddQ\xec\x12\x05\xa4\xe9&\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe2\xeei\x1f#~\xe6R\x9beW\xf2\xfc\xdd=\xcf\fY\xecc\x8a\x01'r\x9c\x14h| \x00\x00\u07d4\xe2\xef\xa5\xfc\xa7\x958\xce`h\xbf1\xd2\xc5\x16\xd4\xd5<\b\xe5\x89\a\x1c\xc4\b\xdfc@\x00\x00\xe0\x94\xe2\xef\u0429\xbc@~\xce\x03\xd6~\x8e\xc8\xe9\u0483\xf4\x8d*I\x8a\x02\x99\xb3;\xf9\u0144\xe0\x00\x00\u07d4\xe2\xf4\r5\x8f^?\xe7F>\xc7\x04\x80\xbd.\u04d8\xa7\x06;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\xf98=X\x10\xea{C\x18+\x87\x04\xb6+'\xf5\x92]9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe2\xff\x9e\xe4\xb6\xec\xc1AA\xcct\xcaR\xa9\xe7\xa2\xee\x14\xd9\b\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe3\x02\x12\xb2\x01\x1b\xb5k\xdb\xf1\xbc5i\x0f:N\x0f\xd9\x05\xea\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xe3\x03\x16\u007f=I`\xfe\x88\x1b2\x80\n+J\xef\xf1\xb0\x88\u0509lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3\x04\xa3/\x05\xa87btJ\x95B\x97o\xf9\xb7#\xfa1\xea\x89Ur\xf2@\xa3F \x00\x00\u07d4\xe3\bCR\x04y7d\xf5\xfc\xbee\xebQ\x0fZtJeZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3\t\x97L\xe3\x9d`\xaa\xdf.ig2Q\xbf\x0e\x04v\n\x10\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xe3\x1bN\xef\x18L$\xab\t\x8e6\xc8\x02qK\xd4t=\xd0\u0509\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3!\xbbJ\x94j\xda\xfd\xad\xe4W\x1f\xb1\\\x00C\u04de\xe3_\x89Udu8+L\x9e\x00\x00\u07d4\xe3&<\xe8\xafm\xb3\xe4gXE\x02\xedq\t\x12^\xae\"\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3+\x1cG%\xa1\x87TI\u93d7\x0e\xb3\xe5@b\xd1X\x00\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3/\x95vmW\xb5\xcdK\x172\x89\u0587o\x9edU\x81\x94\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe38@\u063c\xa7\u0698\xa6\xf3\u0416\xd8=\xe7\x8bp\xb7\x1e\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe38\xe8Y\xfe.\x8c\x15UHH\xb7\\\xae\u0368w\xa0\xe82\x89a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4\xe3=\x98\x02 \xfa\xb2Y\xafj\x1fK8\xcf\x0e\xf3\xc6\xe2\xea\x1a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe3=\xf4\u0380\u0336*v\xb1+\xcd\xfc\xec\xc4b\x89\x97:\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe3?\xf9\x87T\x1d\xde\\\xde\u0a29m\xcc?3\xc3\xf2L\u008a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xe3A\v\xb7U|\xf9\x1dy\xfai\xd0\xdf\xea\n\xa0u@&Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3Ad-@\u04af\xce.\x91\a\xc6py\xacz&`\bl\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe3TS\xee\xf2\xcc2\x89\x10CR\x8d\t\x84i\x80\x00\xe0\x94\xe5\x10\xd6y\u007f\xba=f\x93\x83Z\x84N\xa2\xadT\x06\x91\x97\x1b\x8a\x03\xae9\xd4s\x83\xe8t\x00\x00\u07d4\xe5\x14!\xf8\xee\"\x10\xc7\x1e\xd8p\xfea\x82v\u0215J\xfb\xe9\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\x1e\xb8~\u007f\xb71\x1fR(\xc4y\xb4\x8e\u0247\x881\xacL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5!V1\xb1BH\xd4Z%R\x96\xbe\xd1\xfb\xfa\x030\xff5\x89G\x03\xe6\xebR\x91\xb8\x00\x00\xe0\x94\xe5(\xa0\xe5\xa2g\xd6g\xe99:e\x84\xe1\x9b4\u071b\xe9s\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xe54%\xd8\xdf\x1f\x11\xc3A\xffX\xae_\x148\xab\xf1\xcaS\u03c9\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\u07d4\xe5No\x9c\xffV\xe1\x9cF\x1e\xb4T\xf9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5A\x02SM\xe8\xf2>\xff\xb0\x93\xb3\x12B\xad;#?\xac\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe5E\xee\x84\xeaH\xe5d\x16\x1e\x94\x82\u055b\xcf@j`,\xa2\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xe5H\x1a\u007f\xedB\xb9\x01\xbb\xed x\x9b\u052d\xe5\r_\x83\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5Y\xb5\xfd3{\x9cUr\xa9\xbf\x9e\x0f%!\xf7\xd4F\xdb\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\\\x80R\n\x1b\x0fu[\x9a,\xd3\xce!Ov%e>\x8a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe5mC\x13$\xc9)\x11\xa1t\x9d\xf2\x92p\x9c\x14\xb7ze\u034a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\xe5})\x95\xb0\xeb\xdf?<\xa6\xc0\x15\xeb\x04&\r\xbb\x98\xb7\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\u51f1j\xbc\x8at\b\x1e6\x13\xe1CB\xc03u\xbf\bG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\x89\xfav\x98M\xb5\xec@\x04\xb4n\u8954\x92\xc3\aD\u0389\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xe5\x8d\xd228\xeen\xa7\xc2\x13\x8d8]\xf5\x00\xc3%\xf3v\xbe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe5\x95?\xeaIq\x04\xef\x9a\xd2\xd4\xe5\x84\x1c'\x1f\a5\x19\u0089&)\xf6n\fS\x00\x00\x00\xe0\x94\u5587\x97F\x8e\xf7g\x10\x1bv\x1dC\x1f\xce\x14\xab\xff\u06f4\x8a\x01\xb3\xd9i\xfaA\x1c\xa0\x00\x00\u07d4\xe5\x97\xf0\x83\xa4i\xc4Y\x1c=+\x1d,w'\x87\xbe\xfe'\xb2\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe5\x9b;\xd3\x00\x89?\x97#>\xf9G\xc4or\x17\xe3\x92\xf7\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xa3e4<\xc4\xeb\x1ew\x03h\xe1\xf1\x14Jw\xb82\xd7\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe5\xa3\xd7\xeb\x13\xb1\\\x10\x01w#m\x1b\xeb0\xd1~\xe1T \x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xaa\v\x83;\xb9\x16\xdc\x19\xa8\xddh?\x0e\xde$\x1d\x98\x8e\xba\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u5def\x14i\x86\xc0\xff\x8f\x85\xd2.l\xc34\a}\x84\xe8$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xb8&\x19l\x0e\x1b\xc1\x11\x9b\x02\x1c\xf6\xd2Y\xa6\x10\u0256p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\xb9o\u026c\x03\xd4H\xc1a:\xc9\x1d\x15\x97\x81E\xdb\xdf\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u5e40\u048e\xec\xe2\xc0o\xcal\x94s\x06\x8b7\u0526\xd6\xe9\x89%\xaf\u058c\xac+\x90\x00\x00\u07d4\u5eb4\xf0\xaf\u0629\u0463\x81\xb4Wa\xaa\x18\xf3\xd3\xcc\xe1\x05\x89Q\xbf\xd7\xc18x\xd1\x00\x00\u07d4\xe5\xbc\u020c;%on\xd5\xfeU\x0eJ\x18\x19\x8b\x943V\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xbd\xf3OL\xccH>L\xa50\xcc|\xf2\xbb\x18\xfe\xbe\x92\xb3\x89\x06\xd85\xa1\v\xbc\xd2\x00\x00\u07d4\xe5\u0713I\xcbR\xe1a\x19a\"\u03c7\xa3\x896\xe2\xc5\u007f4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xe38\x00\xa1\xb2\xe9k\xde\x101c\n\x95\x9a\xa0\a\xf2nQ\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\xe3~\x19@\x8f,\xfb\xec\x834\x9d\u0501S\xa4\xa7\x95\xa0\x8f\x89\u3bb5sr@\xa0\x00\x00\u07d4\xe5\xed\xc7>bo]4A\xa4U9\xb5\xf7\xa3\x98\u0153\xed\xf6\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xe5\xed\xf8\x12?$\x03\xce\x1a\x02\x99\xbe\xcfz\xactM\a_#\x89\n\xdaUGK\x814\x00\x00\u07d4\xe5\xf8\xefm\x97\x066\xb0\u072aO \x0f\xfd\xc9\xe7Z\xf1t\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xfb1\xa5\xca\xeej\x96\xde9;\xdb\xf8\x9f\xbee\xfe\x12[\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xfb\xe3I\x84\xb67\x19o3\x1cg\x9d\f\fG\xd84\x10\xe1\x89llD\xfeG\xec\x05\x00\x00\u07d4\xe6\tU\xdc\v\xc1V\xf6\xc4\x18I\xf6\xbdwk\xa4K\x0e\xf0\xa1\x89\x10C\x16'\xa0\x93;\x00\x00\u07d4\xe6\nU\xf2\u07d9m\u00ee\xdbil\b\xdd\xe09\xb2d\x1d\xe8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6\x11[\x13\xf9y_~\x95e\x02\xd5\aEg\u06b9E\xcek\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xe6\x1f(\t\x15\xc7t\xa3\x1d\"<\xf8\f\x06\x92f\xe5\xad\xf1\x9b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xe6/\x98e\a\x12\xeb\x15\x87S\xd8)r\xb8\u9723\xf6\x18w\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6/\x9d|d\xe8\xe2cZ\xeb\x88=\xd7;\xa6\x84\xee|\x10y\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe6>xt\x14\xb9\x04\x84x\xa5\a35\x9e\xcd\xd7\xe3dz\xa6\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe6FfXr\xe4\v\rz\xa2\xff\x82r\x9c\xaa\xba[\xc3\u8789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe6N\xf0\x12e\x8dT\xf8\xe8`\x9cN\x90#\xc0\x9f\xe8e\xc8;\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\xe6On\x1dd\x01\xb5l\akd\xa1\xb0\x86}\v/1\rN\x89\x02\u02edq\xc5:\xe5\x00\x00\u07d4\xe6g\xf6R\xf9W\u008c\x0ef\u04364\x17\xc8\f\x8c\x9d\xb8x\x89 \x9d\x92/RY\xc5\x00\x00\xe0\x94\xe6w\xc3\x1f\xd9\xcbr\x00u\u0724\x9f\x1a\xbc\xcdY\xec3\xf74\x8a\x01\xa6\u05be\xb1\xd4.\xe0\x00\x00\u07d4\xe6|,\x16e\u02038h\x81\x87b\x9fI\xe9\x9b`\xb2\u04fa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xe6\x9al\xdb:\x8a}\xb8\xe1\xf3\f\x8b\x84\xcds\xba\xe0+\xc0\xf8\x8a\x03\x94\xfd\xc2\xe4R\xf6q\x80\x00\u07d4\xe6\x9d\x1c7\x8bw\x1e\x0f\xef\xf0Q\xdbi\xd9f\xacgy\xf4\xed\x89\x1d\xfaj\xaa\x14\x97\x04\x00\x00\u07d4\xe6\x9f\xcc&\xed\"_{.7\x984\xc5$\xd7\f\x175\u5f09lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\xa3\x01\x0f\x02\x01\xbc\x94\xffg\xa2\xf6\x99\xdf\xc2\x06\xf9\xe7gB\x89/\xa7\xcb\xf6dd\x98\x00\x00\u07d4\xe6\xa6\xf6\xddop\xa4V\xf4\xec\x15\xefz\xd5\xe5\u06f6\x8b\xd7\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe6\xb2\x0f\x98\n\xd8S\xad\x04\xcb\xfc\x88|\xe6`\x1ck\xe0\xb2L\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u6cec?]M\xa5\xa8\x85}\v?0\xfcK+i+w\u05c9O%\x91\xf8\x96\xa6P\x00\x00\u07d4\xe6\xb9T_~\u0406\xe5R\x92F9\xf9\xa9\xed\xbb\xd5T\v>\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\xe0\x94\xe6\xbc\xd3\n\x8f\xa18\xc5\xd9\xe5\xf6\xc7\xd2\u0680i\x92\x81-\u034a7\x0e\xa0\xd4|\xf6\x1a\x80\x00\x00\u07d4\xe6\xc8\x1f\xfc\xec\xb4~\xcd\xc5\\\vq\xe4\x85_>^\x97\xfc\x1e\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\xe6\xcb&\vqmL\n\xb7&\xee\xeb\a\xc8pr\x04\xe2v\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe6\xcb?1$\xc9\xc9\xcc84\xb1'K\xc33dV\xa3\x8b\xac\x89\x17+\x1d\xe0\xa2\x13\xff\x00\x00\xe0\x94\xe6\xd2\"\t\xff\u0438u\t\xad\xe3\xa8\xe2\xefB\x98y\u02c9\xb5\x8a\x03\xa7\xaa\x9e\x18\x99\xca0\x00\x00\u07d4\xe6\u051f\x86\xc2(\xf4sg\xa3^\x88l\xaa\xcb'\x1eS\x94)\x89\x16^\xc0\x9d\xa7\xa1\x98\x00\x00\u07d4\xe6\xe6!\xea\xab\x01\xf2\x0e\xf0\x83k|\xadGFL\xb5\xfd<\x96\x89\x11!\x93B\xaf\xa2K\x00\x00\u07d4\xe6\xe8\x861{jf\xa5\xb4\xf8\x1b\xf1d\xc58\xc2d5\x17e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\u98ddu\x0f\xe9\x949N\xb6\x82\x86\xe5\xeab\xa6\x99x\x82\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xe6\xec\\\xf0\u011b\x9c1~\x1epc\x15\uf7b7\xc0\xbf\x11\xa7\x8a\x03\xa4i\xf3F~\x8e\xc0\x00\x00\u07d4\xe6\xf5\xebd\x9a\xfb\x99Y\x9cAK'\xa9\xc9\xc8U5\u007f\xa8x\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xe6\xfe\n\xfb\x9d\xce\xdd7\xb2\xe2,E\x1b\xa6\xfe\xabg4\x803\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe7\x10\xdc\u041b\x81\x01\xf9C{\xd9}\xb9\ns\xef\x99=\v\xf4\x89\x14\xee6\xc0Z\xc2R\x00\x00\u07d4\xe7'\xe6~\xf9\x11\xb8\x1fl\xf9\xc7?\xcb\xfe\xbc+\x02\xb5\xbf\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7.\x1d3\\\u009a\x96\xb9\xb1\xc0/\x00:\x16\xd9q\xe9\v\x9d\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe71\x1c\x953\xf0\t,rH\xc9s\x9b[,\x86J4\xb1\u0389\x97\xf9}l\xc2m\xfe\x00\x00\u07d4\xe7;\xfe\xad\xa6\xf0\xfd\x01o\xbc\x84>\xbc\xf6\xe3p\xa6[\xe7\f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xe7<\xcfCg%\xc1Q\xe2U\xcc\xf5!\f\xfc\xe5\xa4?\x13\xe3\x89\x01\x15NS!}\xdb\x00\x00\u07d4\xe7B\xb1\xe6\x06\x9a\x8f\xfc'\f\xc6\x1f\xa1d\xac\x15SE\\\x10]\x04\x88~\x14\x89\x06\x96\xd8Y\x00 \xbb\x00\x00\u07d4\xe7\\\x1f\xb1w\b\x9f>X\xb1\x06y5\xa6Yn\xf1s\u007f\xb5\x89\x05j\x87\x9f\xa7uG\x00\x00\u07d4\xe7\\;8\xa5\x8a?3\xd5V\x90\xa5\xa5\x97f\xbe\x18^\x02\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7a\xd2\u007f\xa3P,\xc7k\xb1\xa6\bt\x0e\x14\x03\u03dd\xfci\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe7f\xf3O\xf1o<\xfc\xc9s!r\x1fC\xdd\xf5\xa3\x8b\f\xf4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xe7m\x94Z\xa8\x9d\xf1\xe4W\xaa4+1\x02\x8a^\x910\xb2\u03897\b\xba\xed=h\x90\x00\x00\u07d4\xe7s^\xc7e\x18\xfcj\xa9-\xa8qZ\x9e\xe3\xf6%x\x8f\x13\x89lM\x16\v\xaf\xa1\xb7\x80\x00\xe0\x94\xe7z\x89\xbdE\xdc\x04\xee\xb4\xe4\x1d{Ykp~nQ\xe7L\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xe7}}\uac96\u0234\xfa\a\xca;\xe1\x84\x16=Zm`l\x89\x05\x049\x04\xb6q\x19\x00\x00\u07d4\xe7\u007f\xeb\xab\xdf\b\x0f\x0f]\xca\x1d?Wf\xf2\xa7\x9c\x0f\xfa|\x89K\"\x9d(\xa8Ch\x00\x00\xe0\x94\u7025c\x06\xba\x1ek\xb31\x95,\"S\x9b\x85\x8a\xf9\xf7}\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xe7\x81\xecs-@\x12\x02\xbb\x9b\xd18`\x91\r\xd6\u009a\xc0\xb6\x89C8t\xf62\xcc`\x00\x00\u07d4\xe7\x84\xdc\xc8s\xaa\x8c\x15\x13\xec&\xff6\xbc\x92\xea\xc6\xd4\xc9h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\x91-L\xf4V,W=\xdc[q\xe3s\x10\xe3x\xef\x86\u0249\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xe7\x91\u0545\xb8\x996\xb2])\x8f\x9d5\xf9\xf9\xed\xc2Z)2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\x924\x9c\xe9\xf6\xf1O\x81\xd0g@\x96\xbe\xfa\x1f\x92!\xcd\xea\x89[]#J\r\xb48\x80\x00\u07d4\xe7\x96\xfdN\x83\x9bL\x95\xd7Q\x0f\xb7\xc5\xc7+\x83\xc6\xc3\xe3\u01c9\x1b\xc43\xf2?\x83\x14\x00\x00\xe0\x94\xe7\xa4/Y\xfe\xe0t\xe4\xfb\x13\xea\x9eW\xec\xf1\xccH(\"I\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xe7\xa4V\f\x84\xb2\x0e\x0f\xb5LIg\f)\x03\xb0\xa9lB\xa4\x89 j\xea\u01e9\x03\x98\x00\x00\u07d4\xe7\xa8\xe4q\xea\xfby\x8fET\xccnRg0\xfdV\xe6,}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u7f82\xc6Y<\x1e\xed\xdd*\xe0\xb1P\x01\xff \x1a\xb5{/\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\xe7\u01b5\xfc\x05\xfct\x8e[C\x81rdI\xa1\xc0\xad\x0f\xb0\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\xd1u$\xd0\v\xad\x82I|\x0f'\x15jd\u007f\xf5\x1d'\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe7\xd2\x13\x94\u007f\u02d0J\xd78H\v\x1e\xed/\\2\x9f'\xe8\x89\x01\x03\u00f1\xd3\xe9\xc3\x00\x00\u07d4\xe7\xd6$\x06 \xf4,^\u06f2\xed\xe6\xae\xc4=\xa4\xed\x9bWW\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xda`\x9d@\xcd\xe8\x0f\x00\xce[O\xfbj\xa9\u04304\x94\xfc\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xf0oi\x9b\xe3\x1cD\vC\xb4\xdb\x05\x01\xec\x0e%&\x16D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7\xf4\xd7\xfeoV\x1f\u007f\xa1\xda0\x05\xfd6TQ\xad\x89\u07c9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\xfd\x8f\xd9Y\xae\xd2v~\xa7\xfa\x96\f\xe1\xdbS\xaf\x80%s\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe8\x0e\u007f\xef\x18\xa5\xdb\x15\xb0\x14s\xf3\xadkx\xb2\xa2\xf8\xac\u0649\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe8\x13\u007f\xc1\xb2\xec|\xc7\x10:\xf9!\x89\x9bJ9\xe1\xd9Y\xa1\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xe8\x1c-4l\n\xdfL\xc5g\b\xf69K\xa6\xc8\u0226J\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8,X\xc5yC\x1bg5F\xb5:\x86E\x9a\xca\xf1\u079b\x93\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe84\xc6C\x18 \\\xa7\xddJ!\xab\xcb\b&l\xb2\x1f\xf0,\x8965\xc6 G9\u0640\x00\u07d4\xe86\x04\xe4\xffk\xe7\xf9o`\x18\xd3\xec0r\xecR]\xffk\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94\xe8E\xe3\x87\xc4\xcb\u07d8\"\x80\xf6\xaa\x01\xc4\x0eK\xe9X\u0772\x8a\x05K@\xb1\xf8R\xbd\xa0\x00\x00\u07d4\xe8H\xca~\xbf\xf5\xc2O\x9b\x9c1g\x97\xa4;\xf7\xc3V)-\x89\x06.\x11\\\x00\x8a\x88\x00\x00\u07d4\xe8KU\xb5%\xf1\x03\x9etK\x91\x8c\xb33$\x92\xe4^\xcaz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe8O\x80v\xa0\xf2\x96\x9e\xcd3>\xef\x8d\xe4\x10B\x98b\x91\xf2\x89\x17k4O*x\xc0\x00\x00\u07d4\xe8d\xfe\xc0~\xd1!Je1\x1e\x11\xe3)\xde\x04\r\x04\xf0\xfd\x89Y\u0283\xf5\xc4\x04\x96\x80\x00\u07d4\xe8}\xba\xc66\xa3w!\xdfT\xb0\x8a2\xefIY\xb5\xe4\xff\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe8~\x9b\xbf\xbb\xb7\x1c\x1at\ft\xc7#Bm\xf5]\x06=\u064a\x01\xb1\x92\x8c\x00\u01e68\x00\x00\u07d4\xe8~\xacm`+A\t\xc9g\x1b\xf5{\x95\f,\xfd\xb9\x9dU\x89\x02\xb4\xf2\x19r\xec\xce\x00\x00\xe0\x94\u807b\xbeir-\x81\xef\xec\xaaH\u0455*\x10\xa2\xbf\xac\x8f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xe8\x92Is\x8b~\xce\xd7\xcbfjf\xe4s\xbcv\x82/U\t\x8d\x89\xb9\x1c\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xc3\u04f0\xe1\u007f\x97\xd1\xe7V\xe6\x84\xf9N\x14p\xf9\x9c\x95\xa1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xe8\xc3\xf0E\xbb}8\xc9\xd2\U000d5c3a\x84\x92\xb2S#\t\x01\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\xe8\xccC\xbcO\x8a\xcf9\xbf\xf0N\xbf\xbfB\xaa\xc0j2\x84p\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe8\xd9B\xd8/\x17^\xcb\x1c\x16\xa4\x05\xb1\x01C\xb3\xf4k\x96:\x89\x1e\xd2\xe8\xffm\x97\x1c\x00\x00\u07d4\xe8\u077e\xd72\xeb\xfeu@\x96\xfd\xe9\bk\x8e\xa4\xa4\xcd\xc6\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xder^\xca]\xef\x80_\xf7\x94\x1d1\xac\x1c.4-\xfe\x95\x89\x85~\ro\x1d\xa7j\x00\x00\u07d4\xe8\xe9\x85\x05\x86\xe9OR\x99\xabIK\xb8!\xa5\xf4\f\x00\xbd\x04\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xe8\xea\u047b\x90\xcc\u00ee\xa2\xb0\xdc\u0175\x80VUFU\xd1\u054a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4\xe8\xea\xf1)D\t-\xc3Y\x9b9S\xfa|\xb1\xc9v\x1c\xc2F\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xe8\xedQ\xbb\xb3\xac\xe6\x9e\x06\x02K3\xf8hD\xc4sH\u06de\x8a\"\xf9\xea\x89\xf4\xa7\xd6\xc4\x00\x00\u07d4\xe8\xef\x10\r|\xe0\x89X2\xf2g\x8d\xf7-J\u03cc(\xb8\xe3\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xe8\xf2\x99i\xe7\\e\xe0\x1c\xe3\xd8aT }\n\x9e|v\xf2\x89\xa2/\xa9\xa7:'\x19\x80\x00\u07d4\xe8\xfc6\xb0\x13\x1e\xc1 \xac\x9e\x85\xaf\xc1\f\xe7\vV\u0636\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9\n5L\xec\x04\u059e]\x96\xdd\xc0\xc5\x13\x8d=3\x15\n\xa0\x89\x1b\x1a}\u03caD\u04c0\x00\xe0\x94\xe9\x13>}1\x84]_+f\xa2a\x87\x92\xe8i1\x1a\xcff\x8a\x05\x17\xc0\xcb\xf9\xa3\x90\x88\x00\x00\u07d4\xe9\x1d\xac\x01\x95\xb1\x9e7\xb5\x9bS\xf7\xc0\x17\xc0\xb29[\xa4L\x89e\xea=\xb7UF`\x00\x00\u07d4\xe9\x1f\xa0\xba\xda\u0779\xa9~\x88\xd3\xf4\xdb|U\u05bbt0\xfe\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xe9#\xc0aw\xb3B~\xa4H\xc0\xa6\xff\x01\x9bT\xccT\x8d\x95\x89\x01\xf7\x80\x01Fg\xf2\x80\x00\xe0\x94\xe9=G\xa8\u0288]T\fNRo%\xd5\xc6\xf2\xc1\b\u0138\x8a\x17\xda:\x04\u01f3\xe0\x00\x00\x00\u07d4\xe9E\x8fh\xbb',\xb5g:\x04\xf7\x81\xb4\x03Uo\u04e3\x87\x89\x03N\x8b\x88\xce\xe2\xd4\x00\x00\u07d4\xe9IA\xb6\x03`\x19\xb4\x01j0\xc1\x03}Zi\x03\xba\xba\xad\x89*H\xac\xabb\x04\xb0\x00\x00\u07d4\xe9I[\xa5\x84'(\xc0\ud5fe7\xd0\xe4\"\xb9\x8di ,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe9M\xed\x99\u0735r\xb9\xbb\x1d\u02e3/m\xee\x91\xe0W\x98N\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94\xe9QyR}\uc951l\xa9\xa3\x8f!\\\x1e\x9c\xe77\xb4\u024a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xe9U\x91\x85\xf1f\xfc\x95\x13\xccq\x11aD\xce-\xeb\x0f\x1dK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xe9^\x92\xbb\xc6\xde\a\xbf:f\x0e\xbf_\xeb\x1c\x8a5'\xe1\u0148\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xe9e\u06a3@9\xf7\xf0\xdfb7Z7\u5acar\xb3\x01\xe7\x8a\x01\x03\xfd\xde\u0373\xf5p\x00\x00\u07d4\xe9i\xea\x15\x95\xed\xc5\u0127\a\xcf\xde8\t)c2Q\xa2\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9k\x18N\x1f\x0fT\x92J\xc8t\xf6\v\xbfDptF\xb7+\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\xe0\x94\xe9m}L\xdd\x15U:NM1mmd\x80\xca<\xea\x1e8\x8a\x02\x95]\x02\xe1\xa15\xa0\x00\x00\u07d4\xe9n-8\x13\xef\xd1\x16_\x12\xf6\x02\xf9\u007fJb\x90\x9d\x1b;\xc0\xe9\xaa\"\u007f\x90\x89'\xcaK\xd7\x19\xf0\xb8\x00\x00\u07d4\xea,\x19}&\xe9\x8b\r\xa8>\x1br\u01c7a\x8c\x97\x9d=\xb0\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94\xea7y\xd1J\x13\xf6\u01c5f\xbc\xde@5\x91A:b9\u06ca)\xb7d2\xb9DQ \x00\x00\u07d4\xeaN\x80\x9e&j\xe5\xf1<\xdb\u33dd\x04V\xe68m\x12t\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\xe0\x94\xeaS\xc9T\xf4\xed\x97\xfdH\x10\x11\x1b\u06b6\x9e\xf9\x81\xef%\xb9\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xeaS\xd2ed\x85\x9d\x9e\x90\xbb\x0eS\xb7\xab\xf5`\xe0\x16,8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xea`Ci\x12\xdek\xf1\x87\u04e4r\xff\x8fS3\xa0\xf7\xed\x06\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xea`T\x9e\xc7U?Q\x1d!I\xf2\xd4fl\xbd\x92C\xd9<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeaf\xe7\xb8M\u037f6\xee\xa3\xe7[\x858*u\xf1\xa1]\x96\x89]\xbc\x91\x91&o\x11\x80\x00\u07d4\xeahlPW\t<\x17\x1cf\u06d9\xe0\x1b\x0e\xce\xcb0\x86\x83\x89\x14\u0768],\xe1G\x80\x00\u07d4\xeaj\xfe,\xc9(\xac\x83\x91\xeb\x1e\x16_\xc4\x00@\xe3t!\u7262\u007f\xa0c\xb2\xe2\xe6\x80\x00\u07d4\xeay\x05}\xab\xef^d\xe7\xb4O\u007f\x18d\x8e~S7\x18\u0489\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xea|Mm\xc7)\xcdk\x15|\x03\xad#|\xa1\x9a \x93F\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\x81h\xfb\xf2%\xe7\x86E\x9c\xa6\xbb\x18\xd9c\xd2kPS\t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xea\x81\u02868T\f\xd9\xd4\xd7=\x06\x0f,\xeb\xf2$\x1f\xfc>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xea\x83\x17\x19yYB@A\xd9\xd7\xc6z>\xce\x1d\xbbx\xbbU\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xea\x85'\xfe\xbf\xa1\xad\xe2\x9e&A\x93)\u04d3\xb9@\xbb\xb7\u0709lj\xccg\u05f1\xd4\x00\x00\u07d4\xea\x8f0\xb6\xe4\xc5\xe6R\x90\xfb\x98d%\x9b\u0159\x0f\xa8\ue289\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\x94\xf3(\b\xa2\uf29b\xf0\x86\x1d\x1d$\x04\xf7\xb7\xbe%\x8a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\xa4\\\xea\x02\xd8},\xc8\xfd\xa9CN-\x98[\xd4\x03\x15\x84\x89h\x1f\xc2\xccn+\x8b\x00\x00\xe0\x94\uac3d\x14\x83\t\x18l\xf8\xcb\xd1;r2\xd8\tZ\u02c3:\x8a\x02C\x9a\x88\x1cjq|\x00\x00\u07d4\uaed0\xd3y\x89\xaa\xb3\x1f\xea\xe5G\xe0\xe6\xf3\x99\x9c\xe6\xa3]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xc0\x82~\xff\fn?\xf2\x8a}JT\xf6\\\xb7h\x9d{\x99\x89\x9a\xd9\u67ddGR\x00\x00\u07d4\xea\xc1H(&\xac\xb6\x11\x1e\x19\xd3@\xa4_\xb8QWk\xed`\x89\x01\xbe\x8b\xab\x04\u067e\x80\x00\xe0\x94\xea\xc1{\x81\xedQ\x91\xfb\b\x02\xaaT3s\x13\x83A\a\xaa\xa4\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xea\u00efW\x84\x92\u007f\u9958\xfcN\xec8\xb8\x10/7\xbcX\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xea\u01b9\x88BT.\xa1\v\xb7O&\xd7\xc7H\x8fi\x8bdR\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xea\xc7h\xbf\x14\xb8\xf9C.i\xea\xa8*\x99\xfb\xeb\x94\xcd\f\x9c\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xea\xd2\x1c\x1d\xec\u03ff\x1c\\\xd9f\x88\xa2Gki\xba\a\xceJ\x89\x03\xf2M\x8eJ\x00p\x00\x00\u07d4\xea\xd4\xd2\xee\xfbv\xab\xaeU3\x96\x1e\xdd\x11@\x04\x06\xb2\x98\xfc\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xea\xd6Rb\xed]\x12-\xf2\xb2u\x14\x10\xf9\x8c2\xd1#\x8fQ\x89\x05\x83\x17\xedF\xb9\xb8\x00\x00\u07d4\xea\xd7P\x16\u3801Pr\xb6\xb1\b\xbc\xc1\xb7\x99\xac\xf08>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xea#\xaa\x05r\x00\xe7\xc9\xc1^\x8f\xf1\x90\xd0\xe6l\f\x0e\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xed\x16\xea\xf5\u06ab[\xf0)^^\a\u007fY\xfb\x82U\x90\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xea\xed\xcck\x8bib\xd5\xd9(\x8c\x15lW\x9dG\xc0\xa9\xfc\xff\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xea\xf5#\x88Tn\xc3Z\xcaolc\x93\xd8\xd6\t\xde:K\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xeb\x10E\x8d\xac\xa7\x9eJk$\xb2\x9a\x8a\x8a\xdaq\x1b\u007f.\xb6\x89\u063beI\xb0+\xb8\x00\x00\u07d4\xeb\x1c\xea{E\u047dM\x0e*\x00{\u04ff\xb3Tu\x9e,\x16\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xeb%H\x1f\u035c\"\x1f\x1a\xc7\xe5\xfd\x1e\u0353\a\xa1b\x15\xb8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xeb.\xf3\u04cf\xe6R@<\xd4\xc9\xd8^\xd7\xf0h,\xd7\xc2\u078a\t\x0fSF\b\xa7(\x80\x00\x00\xe0\x94\xeb;\xddY\xdc\u0765\xa9\xbb*\xc1d\x1f\xd0!\x80\xf5\xf3e`\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4\xeb<\xe7\xfc8\x1cQ\xdb}_\xbdi/\x8f\x9e\x05\x8aLp=\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xebE?Z:\xdd\u074a\xb5gP\xfa\xdb\x0f\xe7\xf9M\x9c\x89\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xebO\x00\xe2\x836\xea\t\x94%\x88\ueb12\x18\x11\xc5\"\x14<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebR\xab\x10U4\x922\x9c\x1cT\x83:\xe6\x10\xf3\x98\xa6[\x9d\x89\b=lz\xabc`\x00\x00\u07d4\xebW\r\xba\x97R'\xb1\xc4-n\x8d\xea,V\u026d\x96\x06p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebc\x94\xa7\xbf\xa4\u0489\x11\u0565\xb2>\x93\xf3^4\f\"\x94\x89\x04:w\xaa\xbd\x00x\x00\x00\u07d4\xebh\x10i\x1d\x1a\xe0\u045eG\xbd\"\u03be\u0cfa'\xf8\x8a\x89\x87\x85c\x15\xd8x\x15\x00\x00\u07d4\xebvBL\x0f\u0557\xd3\xe3A\xa9d*\xd1\xee\x11\x8b+W\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb| +F+|\u0145]t\x84u_n&\xefC\xa1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\x83\\\x1a\x91\x18\x17\x87\x8a3\xd1gV\x9e\xa3\xcd\u04c7\xf3(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\ub268\x82g\t\t\xcf7~\x9ex(n\xe9{\xa7\x8dF\u0089+|\xc2\xe9\xc3\"\\\x00\x00\xe0\x94\xeb\x90\u01d3\xb3S\x97a\xe1\xc8\x14\xa2\x96q\x14\x86\x92\x19>\xb4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xeb\x9c\xc9\xfe\bi\xd2\u06b5,\u01ea\xe8\xfdW\xad\xb3_\x9f\xeb\x89j\x93\xbb\x17\xaf\x81\xf8\x00\x00\xe0\x94\ub8c8\xb0\xda'\xc8{\x1c\xc0\xea\xc6\xc5{,Z\vE\x9c\x1a\x8a\x01p\xa0\xf5\x04\x0eP@\x00\x00\u07d4\xeb\xaa!m\xe9\xccZC\x03\x17\a\xd3o\xe6\u057e\xdc\x05\xbd\xf0\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xeb\xac+D\b\xefT1\xa1;\x85\b\xe8bP\x98!\x14\xe1E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb\xb6,\xf8\xe2,\x88K\x1b(\xc6\xfa\x88\xfb\xbc\x17\x93\x8a\xa7\x87\x89+By\x84\x03\u0278\x00\x00\u07d4\xeb\xb7\xd2\xe1\x1b\u01b5\x8f\n\x8dE\xc2\xf6\xde0\x10W\n\u0211\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4\xeb\xbbO,=\xa8\xbe>\xb6-\x1f\xfb\x1f\x95\x02a\u03d8\xec\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\xbdM\xb9\x01\x99R\u058b\x1b\x0fm\x8c\xf0h<\x008{\xb5\x89\x12\x04\x01V=}\x91\x00\x00\u07d4\xeb\xbe\xeb%\x91\x84\xa6\xe0\x1c\xcc\xfc\"\a\xbb\u0603xZ\xc9\n\x89!\x9b\xc1\xb0G\x83\xd3\x00\x00\u07d4\xeb\xd3V\x15j81#4=H\x84;\xff\xeda\x03\xe8f\xb3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xeb\xd3{%ec\xe3\fo\x92\x89\xa8\xe2p/\bR\x88\b3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xeb\xe4l\xc3\xc3L2\xf5\xad\xd6\xc3\x19[\xb4\x86\xc4q>\xb9\x18\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xeb\xff\x84\xbb\xefB0q\xe6\x04\xc3a\xbb\xa6w\xf5Y=\xefN\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xec\t'\xba\xc7\xdc6f\x9c(5J\xb1\xbe\x83\xd7\xee\xc3\t4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\x0e\x18\xa0\x1d\xc4\xdc]\xaa\xe5g\xc3\xfaL\u007f\x8f\x9bY\x02\x05\x89\x11\x1f\xfe@JA\xe6\x00\x00\xe0\x94\xec\x116,\xec\x81\t\x85\xd0\xeb\xbd{sE\x14D\x98[6\x9f\x8a\x06ZNIWpW1\x80\x00\u07d4\xec,\xb8\xb97\x8d\xff1\xae\xc3\xc2.\x0em\xad\xff1J\xb5\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xec0\xad\u0749[\x82\xee1\x9eT\xfb\x04\xcb+\xb09q\xf3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec;\x8bX\xa1'\x03\xe5\x81\xce_\xfd~!\xc5}\x1e\\f?\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xecHg\xd2\x17Z\xb5\xb9F\x93aYUFUF\x84\u0364`\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xecM\b\xaa.GIm\u0287\"]\xe3?+@\xa8\xa5\xb3o\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\xecX\xbc\r\f \xd8\xf4\x94efAS\xc5\xc1\x96\xfeY\u6f89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xec[\x19\x8a\x00\u03f5Z\x97\xb5\xd56D\xcf\xfa\x8a\x04\u04abE\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec]\xf2'\xbf\xa8]z\xd7kBn\x1c\xee\x96;\xc7\xf5\x19\u074965\u026d\xc5\u07a0\x00\x00\xe0\x94\xec_\xea\xfe!\f\x12\xbf\u0265\xd0Y%\xa1#\xf1\xe7?\xbe\xf8\x8a`\x8f\xcf=\x88t\x8d\x00\x00\x00\u07d4\xeci\x04\xba\xe1\xf6\x97\x90Y\x17\t\xb0`\x97\x83s?%s\xe3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xecs\x11L^@o\u06fe\t\xb4\xfab\x1b\xd7\x0e\xd5N\xa1\xef\x8a\x050%\xcd!o\xceP\x00\x00\u07d4\xecs\x83=\xe4\xb8\x10\xbb\x02x\x10\xfc\x8fi\xf5D\xe8<\x12\u044965\u026d\xc5\u07a0\x00\x00\u07d4\xecu\xb4\xa4u\x13\x12\v\xa5\xf8`9\x81O\x19\x98\xe3\x81z\u00c9\t\xb0\xbc\xe2\xe8\xfd\xba\x00\x00\u07d4\xecv\xf1.W\xa6U\x04\x03?,\v\xceo\xc0;\xd7\xfa\n\u0109\xc2\x12z\xf8X\xdap\x00\x00\u0794\xec\x80\x14\xef\xc7\xcb\xe5\xb0\xceP\xf3V,\xf4\xe6\u007f\x85\x93\xcd2\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xec\x82\xf5\r\x06G_hM\xf1\xb3\x92\xe0\r\xa3A\xaa\x14TD\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xec\x83\xe7\x98\u00d6\xb7\xa5^*\"$\xab\u0343K'\xeaE\x9c\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\x89\xf2\xb6x\xa1\xa1[\x914\xec^\xb7\fjb\a\x1f\xba\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\x8c\x1d{j\xac\xcdB\x9d\xb3\xa9\x1e\xe4\xc9\xeb\x1c\xa4\xf6\xf7<\x89\xe6d\x99\"\x88\xf2(\x00\x00\xe0\x94\xec\x98Q\xbd\x91rpa\x02g\xd6\x05\x18\xb5M<\xa2\xb3[\x17\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xec\x99\xe9]\xec\xe4o\xff\xfb\x17^\xb6@\x0f\xbe\xbb\b\ue6d5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xec\xa5\xf5\x87\x92\xb8\xc6-*\xf5Vq~\xe3\xee0(\xbeM\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xabZ\xba[\x82\x8d\xe1pS\x81\xf3\x8b\xc7D\xb3+\xa1\xb47\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\xec\xaf3P\xb7\xce\x14M\x06\x8b\x18`\x10\x85,\x84\xdd\f\xe0\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xb9LV\x8b\xfeY\xad\xe6Pd_O&0lsl\xac\xe4\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xec\xbeB^g\r9\tN \xfbVC\xa9\xd8\x18\xee\xd26\u078a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xec\xbe^\x1c\x9a\u04b1\xdc\xcf\n0_\xc9R/Fi\xdd:\xe7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xec\xcfz\x04W\xb5f\xb3F\xcag:\x18\x0fDA0!j\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4\xec\u0466(\x025\x1aAV\x8d#\x030\x04\xac\xc6\xc0\x05\xa5\u04c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xec\xd2v\xafd\u01dd\x1b\u0669+\x86\xb5\u835a\x95\xeb\x88\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xec\u0506\xfc\x19g\x91\xb9,\xf6\x12\xd3HaO\x91VH\x8b~\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\xda\xf92)\xb4^\xe6r\xf6]\xb5\x06\xfb^\xca\x00\xf7\xfc\xe6\x89W\x01\xf9m\xcc@\xee\x80\x00\u07d4\xec\xe1\x11g\vV<\u037e\xbc\xa5#\x84)\x0e\xcdh\xfe\\\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xec\xe1\x15&\x82\xb7Y\x8f\xe2\xd1\xe2\x1e\xc1U3\x88T5\xac\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xec\xe1)\bw\xb5\x83\xe3a\xa2\xd4\x1b\x00\x93F\xe6'N%8\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xec\xf0]\a\xea\x02n~\xbfIA\x00#5\xba\xf2\xfe\xd0\xf0\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\xf2L\xdd|\"\x92\x8cD\x1eiM\xe4\xaa1\xb0\xfa\xb5\x97x\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xec\xfd\x00M\x02\xf3l\xd4\u0634\xa8\xc1\xa9S;j\xf8\\\xd7\x16\x8a\x01\x0fA\xac\xb4\xbb;\x9c\x00\x00\xe0\x94\xed\x02\x06\xcb#1Q(\xf8\xca\xff&\xf6\xa3\v\x98Tg\xd0\"\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xed\x10e\xdb\u03dds\xc0O\xfcy\b\x87\r\x88\x14h\xc1\xe12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xed\x12vQ;o\u0186(\xa7A\x85\xc2\xe2\f\xbb\xcax\x17\xbf\x89\nZ\xa8P\t\xe3\x9c\x00\x00\xe0\x94\xed\x12\xa1\xba\x1f\xb8\xad\xfc\xb2\r\xfa\x19X.RZ\xa3\xb7E$\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xed\x16\xce9\xfe\xef;\xd7\xf5\xd1b\x04^\x0fg\xc0\xf0\x00F\xbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xed\x1a\\C\xc5t\xd4\xe94)\x9b$\xf1G,\u071f\xd6\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xed\x1b$\xb6\x91-Q\xb34\xac\r\xe6\xe7q\xc7\xc0EF\x95\xea\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xed\x1f\x1e\x11Z\r`\xce\x02\xfb%\xdf\x01M(\x9e:\f\xbe}\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xed10\\1\x9f\x92s\u04d3m\x8f[/q\u9c72)c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xed2z\x14\xd5\u03ed\u0641\x03\xfc\t\x99q\x8d~\xd7\x05(\xea\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d4\xed<\xbc7\x82\u03bdg\x98\x9b0\\A3\xb2\xcd\xe3\"\x11\xeb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xed@\x14S\x8c\xeefJ/\xbc\xb6\xdcf\x9fz\xb1m\v\xa5|\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedA\u188f\\\xaa\x848\x80\xefN\x8b\b\xbdl3\x14\x1e\u07c9*\xd5\xdd\xfaz\x8d\x83\x00\x00\xe0\x94\xedK\xe0J\x05-z\u0333\xdc\u03901\x9d\xba@ \xab,h\x8a\a\xf3zp\xea\xf3b\x17\x80\x00\xe0\x94\xedR\xa2\xcc\bi\u071e\x9f\x84+\u0415|G\xa8\xe9\xb0\xc9\xff\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xed[LA\xe7b\xd9B@Cs\xca\xf2\x1e\xd4a]%\xe6\xc1\x89m-O=\x95%\xb4\x00\x00\u07d4\xed`\u012bnT\x02\x061~5\x94zc\xa9\xcak\x03\xe2\u02c9\x03\x1a\u066d\vF\u007f\x80\x00\u07d4\xedd\x1e\x066\x8f\xb0\xef\xaa\x17\x03\xe0\x1f\xe4\x8fJhS\t\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedfC\xc0\xe8\x88K-2\x11\x857\x85\xa0\x8b\xf8\xf3>\u049f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xedp\xa3|\xdd\x1c\xbd\xa9tm\x93\x96X\xae*a\x81(\x85x\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\xedsFvn\x1agm\r\x06\xec\x82\x18g\xa2v\xa0\x83\xbf1\x89\u064a\t1\xcc-I\x00\x00\u07d4\xed\x86&\x16\xfc\xbf\xb3\xbe\xcbt\x06\xf7<\\\xbf\xf0\f\x94\aU\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xed\x9e\x03\f\xa7\\\xb1\u049e\xa0\x1d\rL\xdf\xdc\xcd8D\xb6\xe4\x89\x01\xac\xc1\x16\u03ef\xb1\x80\x00\xe0\x94\ud7bc\u02e4/\x98\x15\xe7\x823&m\xd6\xe85\xb6\xaf\xc3\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\ud7f1\xf5\xaf/\xbf\u007f\xfcP)\xce\xe4+p\xff\\'[\xf5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xed\xa4\xb2\xfaY\u0584\xb2z\x81\r\xf8\x97\x8as\xdf0\x8ac\u0089\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xed\xb4s59y\xa2\x06\x87\x9d\xe1D\xc1\n:\xcf\x12\xa7'OV9a\xf57R\x9d\x89\xc7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xeer\x88\xd9\x10\x86\xd9\xe2\xeb\x91\x00\x14\u066b\x90\xa0-x\u00a0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xee|=\xed|(\xf4Y\xc9/\xe1;M\x95\xba\xfb\xab\x026}\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xee\x86} \x91k\xd2\xe9\xc9\xec\xe0\x8a\xa0C\x85\xdbf|\x91.\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\ue25b\x02\xcb\xcb99\xcda\xde\x13B\xd5\x04\x82\xab\xb6\x852\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xee\x90m}_\x17H%\x81t\xbeL\xbc8\x93\x03\x02\xab{B\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\ue5ea\x8a\u019e\xdfz\x98}mp\x97\x9f\x8e\xc1\xfb\xcaz\x94\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xee\xa1\xe9y\x88\xdeu\xd8!\xcd(\xadh\"\xb2,\u0398\x8b1\x89\x1c0s\x1c\xec\x03 \x00\x00\xe0\x94\xee\u048c?\x06\x8e\tJ0K\x85<\x95\nh\t\xeb\xcb\x03\xe0\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xee\u04c4\xef-A\xd9\xd2\x03\x97NW\xc1#(\xeav\x0e\b\xea\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xdflB\x80\xe6\xeb\x05\xb94\xac\xe4(\xe1\x1dB1\xb5\x90[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xe7a\x84~3\xfda\u0653\x87\xee\x14b\x86\x94\u047f\xd5%\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xee\xe9\xd0Rn\xda\x01\xe41\x16\xa3\x952-\u0689pW\x8f9\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\xee\xf1\xbb\xb1\xe5\xa8?\u0782H\xf8\x8e\xe3\x01\x8a\xfa-\x132\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xfb\xa1-\xfc\x99gB\xdby\x04d\xca}';\xe6\xe8\x1b>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xfd\x05\xb0\xe3\xc4\x17\xd5[3C\x06\x04\x86\xcd\xd5\xe9*\xa7\xa6\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xef\r\xc7\xddzS\xd6\x12r\x8b\xcb\u04b2|\x19\xddM}fo\x89&A\x1c[5\xf0Z\x00\x00\u07d4\xef\x11RR\xb1\xb8E\u0345\u007f\x00-c\x0f\x1bo\xa3zNP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xef\x1c\x04w\xf1\x18M`\xac\u02b3t\xd3tUz\n>\x10\xf3\x89\b=lz\xabc`\x00\x00\u07d4\xef,4\xbbH}7b\xc3\u0327\x82\xcc\xddz\x8f\xbb\n\x991\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xef5\xf6\u0531\a^j\xa19\x15\x1c\x97K/FX\xf7\x058\x89<;\xc3?\x94\xe5\r\x80\x00\u07d4\xef9\u0291s\xdf\x15S\x1ds\xe6\xb7*hKQ\xba\x0f+\xb4\x89V\xa0\xb4un\xe28\x00\x00\u07d4\xefF<&y\xfb'\x91d\xe2\f=&\x915\x87s\xa0\xad\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xefG\xcf\a>6\xf2q\xd5\"\xd7\xfaNq \xadP\a\xa0\xbc\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\xefa\x15[\xa0\t\xdc\u07be\xf1\v(\xd9\xda=\x1b\xc6\xc9\xce\u0509\x034-`\xdf\xf1\x96\x00\x00\u0794\xefix\x1f2\xff\xce34o,\x9a\xe3\xf0\x84\x93\xf3\xe8/\x89\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xefv\xa4\u034f\xeb\xcb\u0278\x18\xf1x(\xf8\xd94s\xf3\xf3\u02c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\uf4c1\x8fhM\xb0\xc3g^\xc8\x132\xb3\x18>\xcc(\xa4\x95\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94\xef\x9fY\xae\xdaA\x8c\x14\x94h-\x94\x1a\xabI$\xb5\xf4\x92\x9a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\uf9b1\xf0\xdb`57\x82h\x91\xb8\xb4\xbc\x169\x84\xbb@\u03495e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xef\xbdR\xf9}\xa5\xfd:g:F\xcb\xf30D{~\x8a\xad\\\x89\x05l<\x9b\x80\xa0\xa6\x80\x00\xe0\x94\xef\xc8\xcf\x19c\u0269Rg\xb2(\xc0\x86#\x98\x89\xf4\xdf\xd4g\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xef\u02ae\x9f\xf6M,\xd9[RI\xdc\xff\xe7\xfa\xa0\xa0\xc0\xe4M\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xef\xcc\xe0k\xd6\b\x9d\x0eE\x8e\xf5a\xf5\xa6\x89H\n\xfep\x00\x89 \x86\xac5\x10R`\x00\x00\u07d4\xef\xe0g]\xa9\x8a]\xdap\u0356\x19k\x87\xf4\xe7&\xb43H\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xef\xe8\xff\x87\xfc&\x0e\agc\x8d\xd5\xd0/\xc4g.\x0e\xc0m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xeb\x19\x97\xaa\xd2w\xcc3C\x0ea\x11\xed\tCY@H\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xee\xa0\x10uo\x81\xdaK\xa2[r\x17\x87\xf0X\x17\v\uff49\x01\u009c\x9c\xf7p\xef\x00\x00\u07d4\xef\xf5\x1dr\xad\xfa\xe1C\xed\xf3\xa4+\x1a\xecU\xa2\xcc\xdd\v\x90\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xef\xf8kQ#\xbc\xdc\x17\xedL\xe8\xe0[~\x12\xe5\x13\x93\xa1\xf7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xef\xfc\x15\u41f1\xbe\xda\n\x8d\x13%\xbd\xb4\x17\"@\xdcT\n\x89\x03\x8599\xee\xe1\xde\x00\x00\xe0\x94\xf0\x11\x95\xd6W\xef<\x94.l\xb89I\xe5\xa2\v\\\xfa\x8b\x1e\x8a\x05ts\xd0]\xab\xae\x80\x00\x00\u07d4\xf0'\x96)Q\x01gB\x88\xc1\xd94g\x05=\x04\"\x19\xb7\x94\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\xf09h={=\"[\xc7\xd8\u07ed\xefc\x164A\xbeA\xe2\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xf0Jj7\x97\b\xb9B\x8dr*\xa2\xb0kw\xe8\x895\u03c9\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf0M,\x91\xef\xb6\xe9\xc4_\xfb\xe7KCL\x8c_+\x02\x8f\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf0W\xaaf\xcav~\xde\x12J\x1c[\x9c\xc5\xfc\x94\xef\v\x017\x89p\xa2K\u02b6\xf4]\x00\x00\u07d4\xf0[\xa8\u05f6\x859\xd930\v\xc9(\x9c=\x94t\xd0A\x9e\x89\x06\xda'\x02M\xd9`\x00\x00\u07d4\xf0\\\xee\xabeA\x05dp\x99Qw<\x84E\xad\x9fN\u01d7\x89\x10C\x16'\xa0\x93;\x00\x00\xe0\x94\xf0_\xcdL\rs\xaa\x16~US\xc8\xc0\xd6\xd4\xf2\xfa\xa3\x97W\x8a\x02\xd2\xd6l1p\xb2\x98\x00\x00\u07d4\xf0g\xe1\xf1\u0583UjL\xc4\xfd\f\x03\x13#\x9f2\xc4\xcf\u060965\u026d\xc5\u07a0\x00\x00\u07d4\xf0g\xfb\x10\u07f2\x93\u962b\xe5d\xc0U\xe34\x8f\x9f\xbf\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0h\xdf\xe9]\x15\xcd:\u007f\x98\xff\xa6\x88\xb44hB\xbe&\x90\x89D\n\xd8\x19\xe0\x97L\x00\x00\xe0\x94\xf0j\x85J<]\xc3m\x1cI\xf4\xc8}m\xb33\xb5~J\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf0y\xe1\xb1&_P\xe8\u0229\x8e\xc0\u01c1^\xb3\xae\xac\x9e\xb4\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\xe0\x94\xf0{\xd0\xe5\xc2\xcei\xc7\u0127$\xbd&\xbb\xfa\x9d*\x17\xca\x03\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xf0\x83*k\xb2U\x03\xee\xcaC[\xe3\x1b\v\xf9\x05\xca\x1f\xcfW\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf0\x9b>\x87\xf9\x13\xdd\xfdW\xae\x80I\xc71\u06e9\xb66\xdf\u00c9 \xf5\xb1\uab4d\x80\x00\x00\u07d4\xf0\xb14\v\x99oo\v\xf0\xd9V\x1c\x84\x9c\xaf\u007fD0\xbe\xfa\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xb1\xf9\xe2x2\xc6\xdei\x14\xd7\n\xfc#\x8ct\x99\x95\xac\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf0\xb4i\xea\xe8\x9d@\f\xe7\xd5\xd6j\x96\x95\x03p6\xb8\x89\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf0\xb9\u0583\u03a1+\xa6\x00\xba\xac\xe2\x19\xb0\xb3\xc9~\x8c\x00\xe4\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xbe\x0f\xafMy#\xfcDF\"\u0458\f\xf2\u0650\xaa\xb3\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xc0\x81\xdaR\xa9\xae6d*\xdf^\b _\x05\xc5Ah\xa6\x89\x06\x04o7\xe5\x94\\\x00\x00\u07d4\xf0\xc7\r\rm\xabvc\xaa\x9e\xd9\xce\xeaV~\xe2\u01b0'e\x89qC\x8a\u0167\x91\xa0\x80\x00\u07d4\xf0\xcb\xef\x84\xe1ic\x00\x98\xd4\xe3\x01\xb2\x02\b\xef\x05\x84j\u0249\x0e\v\x83EPkN\x00\x00\u07d4\xf0\xd2\x16c\u0630\x17n\x05\xfd\xe1\xb9\x0e\xf3\x1f\x850\xfd\xa9_\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf0\xd5\xc3\x1c\xcbl\xbe0\xc7\xc9\xea\x19\xf2h\xd1Y\x85\x1f\x8c\x9c\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xf0\xd6L\xf9\xdf\tt\x113\xd1pH_\xd2K\x00P\x11\xd5 \x89\x1b\b\x93A\xe1O\xcc\x00\x00\u07d4\xf0\xd8X\x10^\x1bd\x81\x01\xac?\x85\xa0\xf8\"+\xf4\xf8\x1dj\x89 \x86\xac5\x10R`\x00\x00\u07d4\xf0\xdcC\xf2\x05a\x91'P{+\x1c\x1c\xfd\xf3-(1\t \x89\x10^\xb7\x9b\x94\x17\b\x80\x00\u07d4\xf0\xe1\u07e4*\u07ac/\x17\xf6\xfd\xf5\x84\xc9Hb\xfdV3\x93\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf0\xe2d\x9c~j?,]\xfe3\xbb\xfb\xd9'\xca<5\nX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xe7\xfb\x9eB\nS@\xd56\xf4\x04\b4O\xea\xef\xc0j\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf1\x04b\xe5\x8f\xcc\a\U000d5121\x87c\x94Q\x16~\x85\x92\x01\x89\t4\xdd]3\xbc\x97\x00\x00\xe0\x94\xf1\x06a\xff\x94\x14\x0f >zH%rCy8\xbe\xc9\xc3\xf7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xf1\x14\xff\r\x0f$\xef\xf8\x96\xed\xdeTq\u07a4\x84\x82J\x99\xb3\x88\xbe -j\x0e\xda\x00\x00\u07d4\xf1\x16\xb0\xb4h\x0fS\xabr\xc9h\xba\x80.\x10\xaa\x1b\xe1\x1d\u0209\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xf1\x1c\xf5\xd3cto\xeehd\xd3\xca3m\xd8\x06y\xbb\x87\xae\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf1\x1e\x01\u01e9\xd1$\x99\x00_M\xaew\x16\tZ4\x17bw\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf1;\b0\x93\xbaVN-\xc61V\x8c\xf7T\r\x9a\x0e\xc7\x19\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf1O\x0e\xb8m\xb0\xebhu?\x16\x91\x8e]K\x80t7\xbd>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf1Qx\xff\xc4:\xa8\a\x0e\xce2~\x93\x0f\x80\x9a\xb1\xa5O\x9d\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xf1V\xdc\v*\x98\x1e[U\xd3\xf2\xf0;\x814\xe31\u06ed\xb7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf1]\x9dZ!\xb1\x92\x9ey\x03q\xa1\u007f\x16\xd9_\fie\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1^\x18,O\xbb\xady\xbd\x934\"B\xd4\xdc\xcf+\xe5\x89%\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf1bM\x98\ve3o\xea\u0166\xd5A%\x00\\\xfc\xf2\xaa\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1g\xf5\x86\x8d\xcfB3\xa7\x83\x06\th,\xaf-\xf4\xb1\xb8\a\x89\x81\xe5B\xe1\xa78?\x00\x00\u07d4\xf1m\xe1\x89\x1d\x81\x96F\x13\x95\xf9\xb16&[;\x95F\xf6\xef\x89\x01\xb2\x8e\x1f\x98\xbb\u0380\x00\u07d4\xf1z\x92\xe06\x1d\xba\xce\xcd\xc5\xde\r\x18\x94\x95Z\xf6\xa9\xb6\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1z\xdbt\x0fE\u02fd\xe3\tN~\x13qo\x81\x03\xf5c\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x8b\x14\xcb\xf6iC6\xd0\xfe\x12\xac\x1f%\xdf-\xa0\xc0]\xbb\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4\xf1\x9b98\x9dG\xb1\x1b\x8a,?\x1d\xa9\x12M\xec\xff\xbe\xfa\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x9f\x195\b9>M*\x12{ \xb2\x03\x1f9\xc8%\x81\u0189\xbd\xbdz\x83\xbd/l\x00\x00\u07d4\xf1\xa1\xf3 @yd\xfd<\x8f.,\u0224X\r\xa9O\x01\xea\x89ll!wU|D\x00\x00\u07d4\xf1\xb4\xec\xc65%\xf7C,=\x83O\xfe+\x97\x0f\xbe\xb8r\x12\x89\xa2\xa2@h\xfa\u0340\x00\x00\u07d4\U000753ef\xfa\x87\x94\xf5\n\xf8\xe8\x83\t\u01e6&TU\xd5\x1a\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xf1\xc8\u0129A\xb4b\x8c\rl0\xfd\xa5dR\u065c~\x1bd\x89N\x8c\xea\x1e\xdeu\x04\x00\x00\u07d4\xf1\xda@so\x99\xd5\xdf;\x06\x8a]t_\xaf\xc6F?\u0271\x89\x06\x96\xca#\x05\x8d\xa1\x00\x00\u07d4\xf1\u070a\xc8\x10B\xc6z\x9c\\c2!\xa8\xf76>e\x87\f\x9f(t$\u04a9`\x89J\xcfX\xe0rW\x10\x00\x00\u07d4\xf2B\u0684]B\u053fw\x9a\x00\xf2\x95\xb4\aP\xfeI\xea\x13\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2RY\xa5\xc99\xcd%\x96l\x9bc\x03\xd3s\x1cS\u077cL\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf2^Lp\xbcFV2\u021eV%\xa82\xa7r/k\xff\xab\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4\xf2k\xce\xdc\xe3\xfe\xad\u03a3\xbc>\x96\xeb\x10@\xdf\xd8\xff\u1809*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xf2py%v\xf0]QD\x93\xff\xd1\xf5\xe8K\xecK-\xf8\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2s,\xf2\xc1;\x8b\xb8\xe7I*\x98\x8f_\x89\xe3\x82s\xdd\u0209 \x86\xac5\x10R`\x00\x00\xe0\x94\xf2t.hY\xc5i\xd5\xf2\x10\x83Q\xe0\xbfM\xca5*H\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf2\x81:d\xc5&]\x02\x025\u02dc1\x9bl\x96\xf9\x06\xc4\x1e\x89\x12\xf99\u025e\u06b8\x00\x00\u07d4\xf2\x87\xffR\xf4a\x11z\xdb>\x1d\xaaq\x93-\x14\x93\xc6_.\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\xf2\xab\x11au\x02D\xd0\xec\xd0H\xee\r>Q\xab\xb1C\xa2\xfd\x89B\xfe+\x90ss\xbc\x00\x00\u07d4\xf2\xb4\xab,\x94'\xa9\x01^\xf6\xee\xff\xf5\xed\xb6\x019\xb7\x19\u0449&\u06d9*;\x18\x00\x00\x00\u07d4\xf2\xc0>*8\x99\x8c!d\x87`\xf1\xe5\xae~\xa3\a}\x85\"\x89\x8f?q\x93\xab\a\x9c\x00\x00\u0794\xf2\u0090N\x9f\xa6d\xa1\x1e\xe2VV\xd8\xfd,\xc0\u0665\"\xa0\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xf2\xc3b\xb0\xef\x99\x1b\xc8/\xb3nf\xffu\x93*\xe8\u0742%\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\xf2\xd0\xe9\x86\xd8\x14\xea\x13\xc8\xf4f\xa0S\x8cS\u0712&Q\xf0\x89J\xcfX\xe0rW\x10\x00\x00\xe0\x94\xf2\u04775w$\xecL\x03\x18[\x87\x9bc\xf5~&X\x91S\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf2\xd5v<\xe0s\x12~,\xed\xdeo\xab\xa7\x86\xc7<\xa9AA\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\xe0\x94\xf2\u055c\x89#u\x90s\xd6\xf4\x15\xaa\xf8\xeb\x06_\xf2\U000f614a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\xf2\xe9\x9f\\\xbb\x83kz\xd3bGW\x1a0,\xbeKH\x1ci\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf2\xed>w%J\u02c3#\x1d\xc0\x86\x0e\x1a\x11$+\xa6'\u06c9kV\x05\x15\x82\xa9p\x00\x00\xe0\x94\xf2\xed\xde7\xf9\xa8\u00dd\u07a2My\xf4\x01WW\xd0k\xf7\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf2\xef\xe9e`\xc9\xd9{r\xbd6DxC\x88\\\x1d\x90\xc21\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf2\xfb\xb6\u0607\xf8\xb8\xcc:\x86\x9a\xba\x84\u007f=\x1fd\xfcc\x97\xaae\xfbS\xa8\xf0z\x0f\x89:\xae0\xe8\xbc\xee\x89|\xf28\x1fa\x9f\x15\x00\x00\u07d4\xf3@\x83\xec\xea8P\x17\xaa@\xbd\xd3^\xf7\xef\xfbL\xe7v-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf3F\xd7\u0792t\x1c\b\xfcX\xa6M\xb5[\x06-\xde\x01-\x14\x89\x0f\xffk\x1fv\x1em\x00\x00\xe0\x94\xf3U\xd3\xec\f\xfb\x90}\x8d\xbb\x1b\xf3FNE\x81(\x19\v\xac\x8a\x01\v\x04n\u007f\r\x80\x10\x00\x00\u07d4\xf3m\xf0/\xbd\x89`sG\xaf\xce)i\xb9\xc4#jX\xa5\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3s\xe9\u06ac\f\x86u\xf5;yz\x16\x0fo\xc04\xaek#\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3{BeG\xa1d-\x8032H\x14\xf0\xed\xe3\x11O\xc2\x12\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xf3{\xf7\x8cXu\x15G\x11\xcbd\r7\xeam(\xcf\xcb\x12Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf3\x82\xdfX1U\xd8T\x8f?\x93D\f\xd5\xf6\x8c\xb7\x9d`&\x8a8u}\x02\u007f\xc1\xfd\\\x00\x00\xe0\x94\xf3\x82\xe4\xc2\x04\x10\xb9Q\b\x9e\x19\xba\x96\xa2\xfe\xe3\xd9\x1c\xce~\x8a\x01\x11\xfaV\xee\u00a88\x00\x00\xe0\x94\xf3\x8al\xa8\x01hS~\x97M\x14\xe1\xc3\xd19\x90\xa4L,\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xf3\x9a\x9dz\xa3X\x1d\xf0~\xe4'\x9a\xe6\xc3\x12\xef!\x036X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xb6h\xb3\xf1M\x92\x0e\xbc7\x90\x92\u06d8\x03\x1bg\xb2\x19\xb3\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\U000fe679\x10<\xe7U\n\xa7O\xf1\xdb\x18\xe0\x9d\xfe2\xe0\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xc1\xab\u049d\xc5{A\xdc\x19-\x0e8M\x02\x1d\xf0\xb4\xf6\u0509\x97\xae\f\u07cf\x86\xf8\x00\x00\u07d4\xf3\xc4qm\x1e\xe5'\x9a\x86\xd0\x16:\x14a\x81\x81\xe1a6\u01c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf3\u030b\xcbU\x94e\xf8\x1b\xfeX;\u05eb\n#\x06E;\x9e\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf3\u0588\xf0k\xbd\xbfP\xf9\x93,AE\xcb\xe4\x8e\xcd\xf6\x89\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf3\xdb\xcf\x13Z\u02dd\xee\x1aH\x9cY<\x02O\x03\u00bb\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xde_&\xefj\xde\xd6\xf0m;\x91\x13F\xeep@\x1d\xa4\xa0\x89\x13:\xb3}\x9f\x9d\x03\x00\x00\u07d4\xf3\xdfc\xa9q\x99\x93308;>\xd7W\v\x96\u0101#4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xe7OG\f}:?\x003x\x0fv\xa8\x9f>\xf6\x91\xe6\u02c9\xa3\xcf\xe61\xd1Cd\x00\x00\u07d4\xf3\xeb\x19H\xb9Q\xe2-\xf1ax)\xbf;\x8d\x86\x80\xeckh\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xf1\xfa9\x18\xca4\xe2\xcf~\x84g\v\x1fM\x8e\xca\x16\r\xb3\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xf3\xf2O\u009e @?\xc0\xe8\xf5\xeb\xbbU4&\xf7\x82p\xa2\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3\xfar5R\xa5\xd0Q.+b\xf4\x8d\xca{+\x81\x050[\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xf3\xfeQ\xfd\xe3D\x13\xc73\x18\xb9\xc8T7\xfe~\x82\x0fV\x1a\x896b2\\\u044f\xe0\x00\x00\u07d4\xf4\x00\xf9=_\\~?\xc3\x03\x12\x9a\xc8\xfb\f/xd\a\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\v\x13O\xea\"\u01b2\x9c\x84W\xf4\x9f\x00\x0f\x9c\xdax\x9a\u06c9 \x86\xac5\x10R`\x00\x00\u07d4\xf4\x15W\xdf\u07f1\xa1\xbd\xce\xfe\xfe.\xba\x1e!\xfe\nJ\x99B\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\x17z\r\x85\u050b\x0e&B\x11\xce*\xa2\xef\xd3\xf1\xb4\u007f\b\x89\xc2\xcc\xca&\xb7\xe8\x0e\x80\x00\u07d4\xf4/\x90R1\xc7p\xf0\xa4\x06\xf2\xb7h\x87\u007f\xb4\x9e\xee\x0f!\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf42\xb9\u06ef\x11\xbd\xbds\xb6Q\x9f\xc0\xa9\x04\x19\x87q\xaa\u0189\b=lz\xabc`\x00\x00\u07d4\xf4=\xa3\xa4\xe3\xf5\xfa\xb1\x04\u029b\xc1\xa0\xf7\xf3\xbbJV\xf3Q\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf4G\x10\x8b\x98\xdfd\xb5~\x87\x103\x88\\\x1a\xd7\x1d\xb1\xa3\xf9\x8a\x01v\xf4\x9e\xad4\x83P\x80\x00\u07d4\xf4O\x85Q\xac\xe93r\a\x12\xc5\u0111\u0376\xf2\xf9Qsl\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\xf4V\x05Z\x11\xab\x91\xfff\x8e.\xc9\"\x96\x1f*#\xe3\xdb%\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf4V\xa7[\xb9\x96U\xa7A,\xe9}\xa0\x81\x81m\xfd\xb2\xb1\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf4[\x1d\xcb.A\xdc'\xff\xa0$\u06ad\xf6\x19\xc1\x11u\xc0\x87\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xf4c\xa9\f\xb3\xf1>\x1f\x06CB66\xbe\xab\x84\xc1#\xb0m\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf4h\x90n~\xdffJ\xb0\u063e=\x83\xebz\xb3\xf7\xff\xdcx\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xf4i\x80\u3929\u049ajn\x90`E7\xa3\x11K\xcb(\x97\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf4kk\x9c|\xb5R\x82\x9c\x1d=\xfd\x8f\xfb\x11\xaa\xba\xe7\x82\xf6\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xf4v\xe1&\u007f\x86$|\xc9\b\x81o.z\xd58\x8c\x95-\xb0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf4v\xf2\xcbr\b\xa3.\x05\x1f\xd9N\xa8f)\x92c\x82\x87\xa2\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xf4{\xb14\xda0\xa8\x12\xd0\x03\xaf\x8d\u0338\x88\xf4K\xbfW$\x8a\x01\x19Y\xb7\xfe3\x95X\x00\x00\u07d4\xf4\x83\xf6\a\xa2\x1f\xcc(\x10\n\x01\x8cV\x8f\xfb\xe1@8\x04\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf4\x8e\x1f\x13\xf6\xafM\x84\xb3q\xd7\xdeK'=\x03\xa2c'\x8e\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xf4\x9cG\xb3\xef\xd8knj[\xc9A\x8d\x1f\x9f\xec\x81Ki\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xf4\x9fo\x9b\xaa\xbc\x01\x8c\x8f\x8e\x11\x9e\x01\x15\xf4\x91\xfc\x92\xa8\xa4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf4\xa3g\xb1f\u0499\x1a+\xfd\xa9\xf5dc\xa0\x9f%,\x1b\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\xa5\x1f\xceJ\x1d[\x94\xb0q\x83\x89\xbaNx\x14\x13\x9c\xa78\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf4\xa9\xd0\f\xef\xa9{zX\xef\x94\x17\xfcbg\xa5\x06\x909\xee\x89\x01.\x89(\u007f\xa7\x84\x00\x00\u07d4\xf4\xaa\xa3\xa6\x16>7\x06W{I\xc0v~\x94\x8ah\x1e\x16\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\xb1bn$\xf3\v\xca\xd9'!\xb2\x93r\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xf5U\xa2{\xb1\xe2\xfdN,\u01c4\xca\ue493\x9f\xc0n/\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5X\xa2\xb2\xdd&\u0755\x93\xaa\xe0E1\xfd<<\u00c5Kg\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xf5`H\xdd!\x81\u0523od\xfc\xec\xc6!T\x81\xe4*\xbc\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5dB\xf6\x0e!i\x13\x95\u043f\xfa\xa9\x19M\xca\xff\x12\u2dc9\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xf5yqJE\xeb\x8fR\xc3\xd5{\xbd\xef\xd2\xc1[./\x11\u07c9T\x91YV\xc4\t`\x00\x00\u07d4\xf5\x93\xc6R\x85\xeek\xbdf7\U000fe3c9\xad@\u0509\xf6U\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf5\x98\xdb.\t\xa8\xa5\xee}r\r+\\C\xbb\x12m\x11\xec\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf5\x9d\xab\x1b\xf8\xdf\x112~a\xf9\xb7\xa1KV:\x96\xec5T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf5\x9f\x9f\x02\xbb\u024e\xfe\t~\xab\xb7\x82\x10\x97\x90!\x89\x8b\xfd\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\xf5\xa5E\x9f\xcd\xd5\xe5\xb2s\x83\r\xf8\x8e\xeaL\xb7}\xda\u07f9\x89\x04\t\xe5+H6\x9a\x00\x00\u07d4\xf5\xa7gj\xd1H\xae\x9c\x1e\xf8\xb6\xf5\xe5\xa0\xc2\xc4s\xbe\x85\v\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5\xb0h\x98\x9d\xf2\x9c%5w\xd0@Z\xden\x0eu(\xf8\x9e\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xf5\xb6\xe9\x06\x1aN\xb0\x96\x16\aw\xe2gb\xcfH\xbd\u0635]\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xf5\xcf\xfb\xbabN~\xb3!\xbc\x83\xc6\f\xa6\x81\x99\xb4\xe3fq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5\xd1ER\xb1\xdc\xe0\xd6\xdc\x1f2\r\xa6\xff\u02231\xcdo\f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xf5\xd6\x1a\xc4\u0295G^[{\xff\xd5\xf2\xf6\x90\xb3\x16u\x96\x15\x8a\x06\x92\xae\x88\x97\b\x1d\x00\x00\x00\u07d4\xf5\xd9\xcf\x00\xd6X\xddEQzH\xa9\xd3\xf5\xf63T\x1aS=\x89\x06O_\xdfIOx\x00\x00\u07d4\xf5\xea\xdc\xd2\u0478ez\x12\x1f3\xc4X\xa8\xb1>v\xb6U&\x89\r\x8b\x0fZZ\xc2J\x00\x00\u07d4\xf6\a\xc2\x15\r>\x1b\x99\xf2O\xa1\xc7\xd5@\xad\xd3\\N\xbe\x1e\x89\xa7\xf1\xaa\a\xfc\x8f\xaa\x00\x00\u07d4\xf6\v\xd75T>k\xfd.\xa6\xf1\x1b\xffbs@\xbc\x03Z#\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6\f\x1bE\xf1d\xb9X\x0e 'Z\\9\xe1\xd7\x1e5\xf8\x91\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf6\x0fb\xd797\x95?\xef5\x16\x9e\x11\xd8r\xd2\xea1~\xec\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xf6\x12\x83\xb4\xbd\x85\x04\x05\x8c\xa3`\u94d9\x9bb\xcb\xc8\xcdg\x89\r\xd2\xd5\xfc\xf3\xbc\x9c\x00\x00\u07d4\xf6\x17\xb9g\xb9\xbdH_v\x95\xd2\xefQ\xfbw\x92\u0618\xf5\x00\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf6\x18\u0671\x04A\x14\x80\xa8c\xe6#\xfcU#-\x1aOH\xaa\x89\x0eh\x9emD\xb1f\x80\x00\u07d4\xf6\"\u5126b>\xaa\xf9\x9f+\xe4\x9eS\x80\xc5\xcb\xcf\\\u0609\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf62\xad\xffI\r\xa4\xb7-\x126\xd0KQ\x0ft\xd2\xfa\xa3\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4\xf69\xac1\u069fg'\x1b\xd1\x04\x02\xb7eN\\\xe7c\xbdG\x89\x15\xaf\x0fB\xba\xf9&\x00\x00\u07d4\xf6:W\x9b\xc3\xea\u00a9I\x04\x10\x12\x8d\xbc\xeb\xe6\xd9\u0782C\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xf6E\xdd|\x89\x00\x93\xe8\xe4\u022a\x92\xa6\xbb55\"\xd3\u0718\x89\aC\x9f\xa2\t\x9eX\x00\x00\xe0\x94\xf6H\xea\x89\xc2u%q\x01r\x94Ny\xed\xff\x84x\x03\xb7u\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf6JJ\xc8\xd5@\xa9(\x9ch\xd9`\xd5\xfb|\xc4Zw\x83\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6N\xcf!\x17\x93\x1cmSZ1\x1eO\xfe\xae\xf9\u0514\x05\xb8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf6O\xe0\x93\x9a\x8d\x1e\xea*\x0e\u035a\x970\xfdyX\xe31\t\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xf6V\x16\xbe\x9c\x8by~t\x15\"|\x918\xfa\xa0\x89\x17B\u05c9*\xd3s\xcef\x8e\x98\x00\x00\u07d4\xf6W\xfc\xbeh.\xb4\xe8\xdb\x15.\u03c9$V\x00\vQ=\x15\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf6X\x19\xacL\xc1L\x13\u007f\x05\xddyw\xc7\xda\xe0\x8d\x1aJ\xb5\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xf6{\xb8\xe2\x11\x8b\xbc\u0550'fn\xed\xf6\x94>\xc9\xf8\x80\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x84d\xbfd\xf2A\x13V\xe4\xd3%\x0e\xfe\xfe\\P\xa5\xf6[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf6\x86x[\x89r\va\x14_\ua017\x8dj\u030e\v\xc1\x96\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x8c^3\xfa\x97\x13\x9d\xf5\xb2\xe68\x86\xce4\xeb\xf3\u45dc\x89\xb3\xfaAi\xe2\xd8\xe0\x00\x00\u07d4\xf6\xa8cWW\xc5\xe8\xc14\xd2\r\x02\x8c\xf7x\u03c6\t\xe4j\x89O\x1dw/\xae\xc1|\x00\x00\u07d4\xf6\xb7\x82\xf4\xdc\xd7E\xa6\xc0\xe2\xe00`\x0e\x04\xa2K%\xe5B\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xf6\xbc7\xb1\u04a3x\x8dX\x9bm\xe2\x12\xdc\x17\x13\xb2\xf6\u738a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xf6\xc3\u010a\x1a\xc0\xa3G\x99\xf0M\xb8n\u01e9u\xfewh\xf3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf6\xd2]?=\x84m#\x9fR_\xa8\xca\xc9{\xc45x\u06ec\x890\x92\u007ft\xc9\xde\x00\x00\x00\u07d4\xf6\xea\xacp2\u0512\xef\x17\xfd`\x95\xaf\xc1\x1dcOV\xb3\x82\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xf6\xea\xd6}\xbf[~\xb13X\xe1\x0f6\x18\x9dS\xe6C\xcf\u03ca\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf6\xf1\xa4C\t\x05\x1ck%\xe4}\xff\x90\x9b\x17\x9b\xb9\xabY\x1c\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf7\x03(\xef\x97b_\xe7E\xfa\xa4\x9e\xe0\xf9\u052a;\r\xfbi\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\n\x99\x8aq{3\x8d\x1d\u0658T@\x9b\x1a3\x8d\ue930\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\rcz\x84\\\x06\xdbl\u0711\xe67\x1c\xe7\xc48\x8ab\x8e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x15R\x13D\x98\x92tK\xc6\x0f.\x04@\a\x88\xbd\x04\x1f\u0749\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\xe0\x94\xf7\x1bE4\xf2\x86\xe40\x93\xb1\xe1^\xfe\xa7I\xe7Y{\x8bW\x8a\x16\x1c\x13\xd34\x1c\x87(\x00\x00\u07d4\xf74\xec\x03rM\xde\xe5\xbbRy\xaa\x1a\xfc\xf6\x1b\f\xb4H\xa1\x89\xe5\xbf,\u0270\x97\x80\x00\x00\u07d4\xf76\u0716v\x00\x128\x8f\xe8\x8bf\xc0n\xfeW\xe0\xd7\xcf\n\x89q\xd7Z\xb9\xb9 P\x00\x00\u07d4\xf7:\xc4l ;\xe1S\x81\x11\xb1Q\xec\x82 \u01c6\xd8AD\x89\x0f\xf77x\x17\xb8+\x80\x00\u07d4\xf7=\xd9\xc1B\xb7\x1b\xce\x11\xd0n0\xe7\xe7\xd02\xf2\uc71e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf7A\x8a\xa0\xe7\x13\xd2H\"\x87v\xb2\xe7CB\"\xaeu\u3949lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7Nn\x14S\x82\xb4\u06c2\x1f\xe0\xf2\u0643\x88\xf4V\t\u019f\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf7P\f\x16o\x8b\xea/\x824v\x06\xe5\x02K\xe9\xe4\xf4\u0399\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7W\xfc\x87 \xd3\xc4\xfaRw\a^`\xbd\\A\x1a\xeb\xd9w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7[\xb3\x9cy\x97y\xeb\xc0J3m&\r\xa61F\xed\x98\u0409\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xf7h\xf3!\xfdd3\xd9kO5M<\xc1e,\x172\xf5\u007f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf7oi\xce\xe4\xfa\xa0\xa6;0\xae\x1ex\x81\xf4\xf7\x15ep\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf7w6\x1a=\u062bb\xe5\xf1\xb9\xb0GV\x8c\xc0\xb5UpL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7|{\x84QI\xef\xba\x19\xe2a\xbc|u\x15y\b\xaf\xa9\x90\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\u007f\x95\x87\xffz-r\x95\xf1\xf5q\u0206\xbd3\x92jR|\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xf7\x82X\xc1$\x81\xbc\xdd\u06f7*\x8c\xa0\xc0C\tra\xc6\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x98\xd1m\xa4\xe4`\xc4`\xcdH_\xae\x0f\xa0Y\x97\b\ub08965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\xa1\xad\xe2\xd0\xf5)\x12=\x10U\xf1\x9b\x17\x91\x9fV!Ng\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf7\xac\xff\x93K\x84\xda\ti\xdc7\xa8\xfc\xf6C\xb7\xd7\xfb\xedA\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf7\xb1Q\xcc^W\x1c\x17\xc7e9\xdb\xe9\x96L\xbbo\xe5\xdey\x89tq|\xfbh\x83\x10\x00\x00\u07d4\xf7\xb2\x9b\x82\x19\\\x88-\xabx\x97\u00ae\x95\xe7w\x10\xf5xu\x89w5Aa2\xdb\xfc\x00\x00\u07d4\xf7\xbcLD\x91\rZ\xed\xd6n\xd25U8\xa6\xb1\x93\xc3a\xec\x89\x05A\xde,-\x8db\x00\x00\u07d4\xf7\xc0\f\xdb\x1f\x02\x03\x10\u056c\xab{Ij\xaaD\xb7y\b^\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xf7\xc1\xb4C\x96\x8b\x11{]\u0677UW/\xcd9\xca^\xc0K\x89\x18\xb9h\u0092\xf1\xb5\x00\x00\xe0\x94\xf7\xc5\x0f\x92*\xd1ka\xc6\u047a\xa0E\xed\x81h\x15\xba\u010f\x8a\x02\xa99j\x97\x84\xad}\x00\x00\u07d4\xf7\xc7\b\x01Pq\xd4\xfb\n:*\t\xa4]\x15c\x96\xe34\x9e\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf7\xcb\u06e6\xbel\xfeh\xdb\xc2<+\x0f\xf50\xee\x05\"o\x84\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\xd0\xd3\x10\xac\xea\x18@a8\xba\xaa\xbb\xfe\x05q\xe8\r\xe8_\x89Hz\x9a0E9D\x00\x00\u07d4\xf7\u05ef LV\xf3\x1f\xd9C\x98\xe4\r\xf1\x96K\u063f\x12<\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xf7\xdc%\x11\x96\xfb\u02f7|\x94}|\x19F\xb0\xffe\x02\x1c\xea\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf7\xe4Z\x12\xaaq\x1cp\x9a\xce\xfe\x95\xf3;xa-*\xd2*\x8a\x0e\x06U\xe2\xf2k\xc9\x18\x00\x00\u07d4\xf7\xf4\x89\x8cLRm\x95_!\xf0U\xcbnG\xb9\x15\xe5\x19d\x89|\b`\xe5\xa8\r\xc0\x00\x00\u07d4\xf7\xf9\x1ez\xcb[\x81)\xa3\x06\x87|\xe3\x16\x8eoC\x8bf\xa1\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xf7\xfcE\xab\xf7oP\x88\xe2\u5d68\xd12\xf2\x8aMN\xc1\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\x06:\xf4\xcc\x1d\xd9a\x9a\xb5\u063f\xf3\xfc\xd1\xfa\xa8H\x82!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\bnBf\x1e\xa9)\xd2\u0761\xablt\x8c\xe3\x05]\x11\x1e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf8\bw\x86\xb4-\xa0N\xd6\xd1\xe0\xfe&\xf6\xc0\xee\xfe\x1e\x9fZ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf8\r6\x19p/\xa5\x83\x8cH9\x18Y\xa89\xfb\x9c\xe7\x16\x0f\x89l\a\xa7\u0471np\x00\x00\u07d4\xf8\x14y\x9fm\xdfM\xcb)\xc7\xee\x87\x0eu\xf9\xcc-52m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf8\x15\xc1\n\x03-\x13\xc3K\x89v\xfan;\xd2\xc9\x13\x1a\x8b\xa9\x89Hz\x9a0E9D\x00\x00\u07d4\xf8\x16\"\xe5WW\xda\xeafu\x97]\xd958\xda}\x16\x99\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8$\xee3\x1eJ\xc3\xccXv\x939[W\xec\xf6%\xa6\xc0\u0089V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4\xf8'\xd5n\xd2\xd3' \u052b\xf1\x03\xd6\xd0\xefM;\xcdU\x9b\x89\x01l\x80\x06W\x91\xa2\x80\x00\u07d4\xf8)\x85\x91R>P\xb1\x03\xf0\xb7\x01\xd6#\xcb\xf0\xf7EV\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8H\xfc\xe9\xaba\x1c}\x99 n#\xfa\u019a\u0508\xb9O\xe1\x89\x02\xa1\x12\x9d\t6r\x00\x00\u07d4\xf8O\t\n\xdf?\x8d\xb7\u1533P\xfb\xb7u\x00i\x9ff\xfd\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf8Q\xb0\x10\xf63\xc4\n\xf1\xa8\xf0js\ubeabe\az\xb5\x89\xee\x86D/\xcd\x06\xc0\x00\x00\u07d4\xf8X\x17\x1a\x04\xd3W\xa1;IA\xc1n~U\xdd\u0514\x13)\x89\x02F\xa5!\x8f*\x00\x00\x00\u07d4\xf8[\xab\x1c\xb3q\x0f\xc0_\xa1\x9f\xfa\xc2.gR\x1a\v\xa2\x1d\x89l\x955\u007f\xa6\xb3l\x00\x00\u07d4\xf8j>\xa8\a\x1fp\x95\xc7\u06ca\x05\xaePz\x89)\u06f8v\x89\x126\xef\xcb\u02f3@\x00\x00\u07d4\xf8pL\x16\xd2\xfd[\xa3\xa2\xc0\x1d\x0e\xb2\x04\x84\xe6\xec\xfa1\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8p\x99_\xe1\xe5\"2\x1duC7\xa4\\\f\x9d{8\x95\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf8s\xe5ze\xc9;n\x18\xcbu\xf0\xdc\a}[\x893\xdc\\\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf8ua\x9d\x8a#\xe4]\x89\x98\u0444\u0500\xc0t\x89p\x82*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8{\xb0{(\x9d\xf70\x1eT\xc0\xef\xdaj,\xf2\x91\xe8\x92\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u0794\xf8\x89\x00\xdbsyU\xb1Q\x9b\x1a}\x17\n\x18\x86L\xe5\x90\xeb\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf8\x8bX\xdb7B\vFL\v\xe8\x8bE\xee+\x95)\x0f\x8c\xfa\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf8\x96+u\xdb]$\xc7\xe8\xb7\xce\xf1\x06\x8c>g\u03bb0\xa5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xf8\xa0e\xf2\x87\xd9\x1dw\xcdbj\xf3\x8f\xfa\"\r\x9bU*+\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xf8\xa4\x9c\xa29\f\x1fm\\\x0ebQ;\a\x95qt?|\u0189\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf8\xa5\f\xee.h\x8c\xee\u3b24\u0522\x97%\xd4\a,\u0103\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xacJ9\xb5<\x110x \x97;D\x13e\xcf\xfeYof\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xae\x85{g\xa4\xa2\x89:?\xbe|z\x87\xff\x1c\x01\u01a6\xe7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8\xbf\x9c\x04\x87NZw\xf3\x8fL8R~\x80\xc6v\xf7\xb8\x87\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xc7\xf3J8\xb3\x18\x01\xdaC\x064w\xb1+'\xd0\xf2\x03\xff\x89\x1a\u04ba\xbao\xefH\x00\x00\u07d4\xf8\xca3l\x8e\x91\xbd \xe3\x14\xc2\v-\xd4`\x8b\x9c\x8b\x94Y\x89-\u071b\u0173,x\x00\x00\u07d4\xf8\xd1t$\xc7g\xbe\xa3\x12\x05s\x9a+W\xa7'r\x14\uef89\x02F\xdd\xf9yvh\x00\x00\u07d4\xf8\xd5-\xcc_\x96\xcc(\x00{>\u02f4\t\xf7\xe2*dl\xaa\x89\b\x16\x90\xe1\x81(H\x00\x00\u07d4\xf8\xdc\xe8g\xf0\xa3\x9c[\xef\x9e\xeb\xa6\t\"\x9e\xfa\x02g\x8bl\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xf2&\x14*B\x844\xab\x17\xa1\x86J%\x97\xf6J\xab/\x06\x89\tY\x8b/\xb2\xe9\xf2\x80\x00\u07d4\xf8\xf6d^\r\xeedK=\xad\x81\xd5q\uf6ef\x84\x00!\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x01\xc0\x0f\xc1\u06c8\xb6\x9cK\xc3%+\\\xa7\x0e\xa6\xee\\\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9=[\xcb\x06D\xb0\xcc\xe5\xfc\u0763C\xf5\x16\x8f\xfa\xb2\x87}\x89\vb\a\xb6}&\xf9\x00\x00\u07d4\xf9W\x0e\x92L\x95\u07bbpa6\x97\x92\xcf.\xfe\u00a8-^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf9d \x86\xb1\xfb\xaea\xa6\x80M\xbe_\xb1^\xc2\u04b57\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9d\x88i\x85\x90\xdc;,UVB\xb8q4\x8d\xfa\x06z\u0549\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9d\u064d(\x170\xba5\xb2\xe3\xa3\x14yn{B\xfe\xdfg\x89S\xb0\x87`\x98\xd8\f\x00\x00\u07d4\xf9e\ri\x89\xf1\x99\xab\x1c\xc4ycm\xed0\xf2A\x02\x1fe\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xf9h\x83X$Y\x90\x8c\x82v'\xe8o(\xe6F\xf9\xc7\xfcz\x8a\x01\u0127\x877\xcd\u03f8\x00\x00\u07d4\xf9kL\x00voSsj\x85t\xf8\"\xe6GL/!\xda-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9r\x9dH(,\x9e\x87\x16m^\xef-\x01\xed\xa9\xdb\xf7\x88!\x89\x05k\x83\xdd\xc7(T\x80\x00\u07d4\xf9v~N\xcbJY\x80Ru\b\u05fe\xc3\xd4^Ld\x9c\x13\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xf9x\xb0%\xb6B3U\\\xc3\xc1\x9a\xda\u007fA\x99\xc94\x8b\xf7\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4\xf9{V\xeb\u0577z\xbc\x9f\xba\u02eb\u0514\xb9\xd2\xc2!\xcd\x03\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf9\x81\x1f\xa1\x9d\xad\xbf\x02\x9f\x8b\xfeV\x9a\xdb\x18\"\x8c\x80H\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf9\x82Ps\fLa\xc5\u007f\x12\x985\xf2h\b\x94yEB\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xf9\x894gr\x99^\xc1\x90o\xaf\xfe\xba*\u007f\xe7\u079ck\xab\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf9\x98\xca4\x11s\nl\xd1\x0etU\xb0A\x0f\xb0\xf6\xd3\xff\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x9a\xeeDKW\x83\xc0\x93\xcf\xff\xd1\xc4c,\xf9\x90\x9f\xbb\x91\x1d/\x81\x92\xf8B\t\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf9\xbf\xb5\x9dS\x8a\xfcHt\xd4\xf5\x94\x1b\b\xc9s\x0e8\xe2K\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf9\xdd#\x90\b\x18/\xb5\x19\xfb0\xee\xdd \x93\xfe\xd1c\x9b\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9\u07ba\xec\xb5\xf39\xbe\xeaH\x94\xe5 K\xfa4\r\x06\u007f%\x89ZB\x84Fs\xb1d\x00\x00\xe0\x94\xf9\xe3tG@lA!\x97\xb2\u2bbc\x00\x1dn0\u024c`\x8a\x01\xc4y\xbbCI\xc0\xee\x00\x00\u07d4\xf9\xe7\"/\xaa\xf0\xf4\xda@\xc1\u0124\x0607:\t\xbe\u05f6\x89\x9bO\u0730\x94V$\x00\x00\u07d4\xf9\xec\xe0\"\xbc\xcd,\x924i\x11\xe7\x9d\xd5\x03\x03\xc0\x1e\x01\x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfa\x00\xc3v\xe8\x9c\x05\u81c1z\x9d\xd0t\x8d\x96\xf3A\xaa\x89\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xfa\f\x1a\x98\x8c\x8a\x17\xad5(\xeb(\xb3@\x9d\xaaX\"_&\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa\x10_\x1a\x11\xb6\xe4\xb1\xf5`\x12\xa2y\"\xe2\xac-\xa4\x81/\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfa\x14/\xe4~\u0697\xe6P;8k\x18\xa2\xbe\xdds\u0335\xb1\x89.\x15:\xd8\x15H\x10\x00\x00\u07d4\xfa\x14\xb5f#J\xbe\xe70B\xc3\x1d!qq\x82\u02e1J\xa1\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\xfa\x19\xd6\xf7\xa5\x0fO\a\x98\x93\xd1g\xbf\x14\xe2\x1d\x00s\u0456\x89\x1c\xbb:?\xf0\x8d\b\x00\x00\u07d4\xfa\x1f\x19q\xa7u\xc3PO\xefPy\xf6@\xc2\u013c\xe7\xac\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfa'\x9b\xfd\x87g\xf9V\xbf\u007f\xa0\xbdV`\x16\x8d\xa7V\x86\xbd\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xfa'\xccI\xd0\vl\x98s6\xa8u\xae9\xdaX\xfb\x04\x1b.\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfa(2\x99`=\x87X\xe8\u02b0\x82\x12],\x8f}DT)\x8a\x01[\xca\xcb\x1e\x05\x01\xae\x80\x00\u07d4\xfa+\xbc\xa1]?\u37ca2\x8e\x91\xf9\r\xa1Oz\xc6%=\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa/\u049d\x03\xfe\xe9\xa0x\x93\xdf:&\x9fV\xb7/.\x1ed\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfa3U2\x85\xa9sq\x9a\r_\x95o\xf8a\xb2\u061e\xd3\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\fK\x90?n\xa5.\xa7\xab{\x88c\xb6\xa6\x16\xadfP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\x1a\xa4H\x8b5\x1a\xa7V\f\xf5\xeec\n/\xd4\\2\"\x89/\xa4~j\xa74\r\x00\x00\u07d4\xfaA\tq\xad\"\x9c06\xf4\x1a\u03c5/*\u0259(\x19P\x89\u0633\x11\xa8\xdd\xfa|\x00\x00\u07d4\xfaD\xa8U\xe4\x04\xc8m\f\xa8\xef3$%\x1d\xfb4\x9cS\x9e\x89T\"S\xa1&\xce@\x00\x00\xe0\x94\xfaR\x01\xfe\x13B\xaf\x110{\x91B\xa0A$<\xa9./\t\x8a 8\x11j:\xc0C\x98\x00\x00\xe0\x94\xfa`\x86\x8a\xaf\xd4\xffL\\W\x91K\x8e\u054bBWs\u07e9\x8a\x01\xcf\xe5\xc8\b\xf3\x9f\xbc\x00\x00\u07d4\xfag\xb6{O7\xa0\x15\t\x15\x11\x0e\xde\a;\x05\xb8S\xbd\xa2\x89#\x19\xba\x94sq\xad\x00\x00\u07d4\xfah\xe0\xcb>\xdfQ\xf0\xa6\xf2\x11\u0272\xcb^\a<\x9b\xff\xe6\x89\x0f\xc969(\x01\xc0\x00\x00\xe0\x94\xfaj7\xf0\x18\xe9yg\x93\u007f\xc5\xe8a{\xa1\u05c6\xdd_w\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xfav\x06C[5l\xee%{\xd2\xfc\xd3\xd9\xea\xcb<\xd1\xc4\xe1\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfaz\xdff\v\x8d\x99\xce\x15\x93=|_\a/<\xbe\xb9\x9d3\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfa\x86\xca'\xbf(T\u0648p\x83\u007f\xb6\xf6\xdf\xe4\xbfdS\xfc\x89\x11u~\x85%\xcf\x14\x80\x00\u07d4\xfa\x8c\xf4\xe6'i\x8c]W\x88\xab\xb7\x88\x04\x17\xe7P#\x13\x99\x89\xe6\x1a6\x96\xee\xf6\x10\x00\x00\u07d4\xfa\x8e;\x1f\x13C9\x00s}\xaa\xf1\xf6)\x9cH\x87\xf8[_\x89&\u009eG\u0104L\x00\x00\u07d4\xfa\x9e\xc8\xef\xe0\x86\x86\xfaX\xc1\x813Xr\xbai\x85`\ucac9lj\xccg\u05f1\xd4\x00\x00\u07d4\xfa\xad\x90]\x84|{#A\x8a\xee\xcb\xe3\xad\u06cd\xd3\xf8\x92J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xfa\xae\xba\x8f\xc0\xbb\xdaU<\xa7.0\xef=s.&\xe8 A\x89H\x8d(*\xaf\xc9\xf6\x80\x00\u07d4\xfa\xb4\x87P\r\xf2\x0f\xb8>\xbe\xd9\x16y\x1dV\x17r\xad\xbe\xbf\x89lkLM\xa6\u077e\x00\x00\u07d4\xfa\xc5\u0294u\x80x\xfb\xfc\xcd\x19\xdb5X\xda~\u8827h\x897(\xa6+\r\xcf\xf6\x00\x00\u07d4\xfa\xd9j\xb6\xacv\x8a\xd5\t\x94R\xacGw\xbd\x1aG\xed\u010f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfa\xe7g\x19\xd9~\xacA\x87\x04(\xe9@'\x9d\x97\xddW\xb2\xf6\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xfa\u8053pG\x89Zf\f\xf2)v\x0f'\xe6h(\xd6C\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xfa\xe9,\x13p\xe9\u115a]\xf8;V\xd0\xf5\x86\xaa;@L\x89\x05\u0174\xf3\xd8C\x98\x00\x00\xe0\x94\xfa\xf5\xf0\xb7\xb6\xd5X\xf5\t\r\x9e\xa1\xfb-B%\x9cX`x\x8a\x01Z\xff\xb8B\fkd\x00\x00\xe0\x94\xfb\x12o\x0e\xc7i\xf4\x9d\xce\xfc\xa2\xf2\x00(dQX0\x84\xb8\x8a\x01\x0f\xcb\xc25\x03\x96\xbf\x00\x00\xe0\x94\xfb\x13^\xb1Z\x8b\xacr\xb6\x99\x154*`\xbb\xc0k~\a|\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\"<\x1e\"\xea\xc1&\x9b2\xee\x15jS\x85\x92.\xd3o\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb7\xcfkO\x81\xa9\xe2\"\xfb\xa2.\x9b\xd2KP\x98\xb73\u03c9\x02\x1auJm\xc5(\x00\x00\u07d4\xfb8`\xf4\x12\x1cC.\xbd\xc8\xecj\x031\xb1\xb7\ty.\x90\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\xfb9\x18\x9a\xf8v\xe7b\xc7\x1dl>t\x18\x93\xdf\"l\xed\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfb:\v\rkjq\x8fo\xc0)*\x82]\xc9$z\x90\xa5\u0409\n\xd6\xdd\x19\x9e\x97[\x00\x00\xe0\x94\xfb?\xa1\xac\b\xab\xa9\xcc;\xf0\xfe\x9dH8 h\x8fe\xb4\x10\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xfb?\xe0\x9b\xb86\x86\x15)\xd7Q\x8d\xa2v5\xf58PV\x15\x89K\xe3\x92\x16\xfd\xa0p\x00\x00\xe0\x94\xfbQ%\xbf\x0f^\xb0\xb6\xf0 \xe5k\xfc/\xdf=@,\t~\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfbU\x18qL\xef\xc3m\x04\x86]\xe5\x91^\xf0\xffG\xdf\xe7C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb_\xfa\xa0\xf7aW&5x\x91GX\x18\x93\x9d 7\u03d6\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfbh\\\x15\xe49\x96^\xf6&\xbf\r\x83L\u0468\x9f+V\x95\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xfbtK\x95\x1d\tK1\x02b\xc8\xf9\x86\xc8`\u07da\xb1\xdee\x89\x02\xd1\xc5\x15\xf1\xcbJ\x80\x00\u07d4\xfby\xab\u06d2\\U\xb9\xf9\x8e\xfe\xefd\xcf\xc9\xeba\xf5\x1b\xb1\x89a@\xc0V\xfb\n\xc8\x00\x00\u07d4\xfb\x81\x13\xf9M\x91s\xee\xfdZ0s\xf5\x16\x80:\x10\xb2\x86\xae\x89\x04V9\x18$O@\x00\x00\u07d4\xfb\x84,\xa2\xc5\xef\x139\x17\xa26\xa0\u052c@i\x01\x10\xb08\x89\x10\x96\x9ab\xbe\x15\x88\x00\x00\u07d4\xfb\x91\xfb\x1aiUS\xf0\u018e!'m\xec\xf0\xb89\t\xb8m\x89\x05l\x006\x17\xafx\x00\x00\u07d4\xfb\x94s\xcfw\x125\n\x1f\xa09Rs\xfc\x80V\aR\xe4\xfb\x89\x06\xaf!\x98\xba\x85\xaa\x00\x00\xe0\x94\xfb\x94\x9cd\u007f\xdc\xfd%\x14\xc7\u054e1\xf2\x8aS-\x8cX3\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\xa5HmS\xc6\xe2@IBA\xab\xf8~C\xc7`\rA:\x89k\xbfaIIH4\x00\x00\u07d4\xfb\xb1a\xfe\x87_\t)\nK&+\xc6\x01\x10\x84\x8f\r\"&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb\xbb\xeb\u03fe#^W\xdd#\x06\xad\x1a\x9e\u0141\xc7\xf9\xf4\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfb\xc0\x1d\xb5NG\xcd\xc3\xc48iJ\xb7\x17\xa8V\xc2?\xe6\xe9\x8a\x01\xcaqP\xab\x17OG\x00\x00\xe0\x94\xfb\xcf\xccJ{\x0f&\xcf&\xe9\xf33!2\xe2\xfcj#\af\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfb\xe7\x16\"\xbc\xbd1\xc1\xa3iv\xe7\xe5\xf6p\xc0\u007f\xfe\x16\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfb\xed\xe3,4\x9f3\x00\xefL\xd3;M\xe7\xdc\x18\xe4C\xd3&\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xfb\xf2\x04\xc8\x13\xf86\xd89b\u01c7\fx\b\xca4\u007f\xd3>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfb\xf7Y3\xe0\x1bu\xb1T\xef\x06i\ak\xe8\u007fb\xdf\xfa\xe1\x8a\x10\x84cr\xf2I\xd4\xc0\x00\x00\u07d4\xfc\x00\x96\xb2\x1e\x95\xac\xb8\xd6\x19\xd1v\xa4\xa1\xd8\xd5)\xba\xdb\xef\x89\x14\xd9i;\xcb\xec\x02\x80\x00\xe0\x94\xfc\x00\xa4 \xa3a\a\xdf\xd5\xf4\x95\x12\x8a_\u5af2\xdb\x0f4\x8a\x01C\x17\x9d\x86\x91\x10 \x00\x00\xe0\x94\xfc\x01\x8ai\n\xd6tm\xbe:\u03d7\x12\xdd\xcaR\xb6%\x009\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfc\x02s@3\xe5\u007fpQ~\n\xfc~\xe6$a\xf0o\xad\x8e\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfc\x0e\xe6\xf7\u00b3qJ\xe9\x91lEVf\x05\xb6V\xf3$A\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xfc\x10\xb7\xa6{2h\xd53\x1b\xfbj\x14\xde\xf5\xeaJ\x16,\xa3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfc\x15\u02d9\xa8\xd1\x03\v\x12w\n\xdd\x03:y\xee\r\f\x90\x8c\x89\x12\xfa\x00\xbdR\xe6$\x00\x00\u07d4\xfc)R\xb4\u011f\xed\u043c\x05(\xa3\bI^mj\x1cq\u0589lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc,\x1f\x88\x96\x1d\x01\x9c>\x9e\xa30\t\x15.\x06\x93\xfb\xf8\x8a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xfc6\x11\x05\u0750\xf9\xed\xe5fI\x9di\xe9\x13\x03\x95\xf1*\u020aS\xa4\xfe/ N\x80\xe0\x00\x00\u07d4\xfc7/\xf6\x92|\xb3\x96\xd9\xcf)\x805\x00\x11\r\xa62\xbcR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc9\xbeA\tK\x19\x97\xd2\x16\x9e\x82d\xc2\u00fa\xa6\u025b\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc=\"k\xb3jX\xf5&V\x88W\xb0\xbb\x12\xd1\t\xec\x93\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfcC\x82\x9a\u01c7\xff\x88\xaa\xf1\x83\xba5*\xad\xbfZ\x15\xb1\x93\x89\u05ac\n+\x05R\xe0\x00\x00\u07d4\xfcI\xc1C\x9aA\u05b3\xcf&\xbbg\xe06R$\xe5\xe3\x8f_\x8966\u05ef^\u024e\x00\x00\u07d4\xfcU\x00\x82Q\x05\xcfq*1\x8a^\x9c;\xfci\u021d\f\x12\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xfcf\xfa\xba'\u007fK]\xe6J\xd4^\xb1\x9c1\xe0\f\xed>\u054a\x011\xbe\xb9%\xff\xd3 \x00\x00\xe0\x94\xfc~\"\xa5\x03\xecZ\xbe\x9b\b\xc5\v\xd1I\x99\xf5 \xfaH\x84\x8a\x01ZG}\xfb\xe1\xea\x14\x80\x00\u07d4\xfc\x82\x15\xa0\xa6\x99\x13\xf6*C\xbf\x1c\x85\x90\xb9\xdd\xcd\r\x8d\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc\x98\x9c\xb4\x87\xbf\x1a}\x17\xe4\xc1\xb7\u0137\xaa\xfd\xdak\n\x8d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfc\x9b4td\xb2\xf9\x92\x9d\x80~\x03\x9d\xaeH\xd3\u064d\xe3y\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xfc\xa4;\xbc#\xa0\xd3!\xba\x9eF\xb9)s\\\xe7\xd8\xef\f\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfc\xa7>\xff\x87q\xc0\x10;\xa3\xcc\x1a\x9c%\x94H\xc7*\xbf\v\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xad\xa3\x00(?k\xcc\x13J\x91Eg`\xb0\xd7}\xe4\x10\xe0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc\xbc\\q\xac\xe7\x97AE\v\x01,\xf6\xb8\xd3\xf1}\xb6\x8ap\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfc\xbd\x85\xfe\xeajuO\xcf4ID\x9e7\xff\x97\x84\xf7w<\x89\xa7J\xdai\xab\xd7x\x00\x00\xe0\x94\xfc\xc9\u0524&.z\x02z\xb7Q\x91\x10\xd8\x02\u0115\xce\xea9\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\xfc\xcd\r\x1e\xce\xe2z\xdd\xea\x95\xf6\x85z\xee\xc8\u01e0K(\xee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfc\u0434\x82|\xd2\b\xff\xbf^u\x9d\xba\x8c<\xc6\x1d\x8c,<\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfc\xe0\x89c\\\xe9z\xba\xc0kD\x81\x9b\xe5\xbb\n>.\v7\x89\x05\x03\x92\nv0\xa7\x80\x00\u07d4\xfc\xf1\x99\xf8\xb8T\"/\x18.N\x1d\t\x9dN2>*\xae\x01\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xfc:P\x04\xd6xa?\v6\xa6B&\x9a\u007f7\x1c?j\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x19\x1a5\x15}x\x13s\xfbA\x1b\xf9\xf2R\x90\x04|^\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x1f\xaa4{\x0f\u0300L-\xa8l6\xd5\xf1\u044bp\x87\xbb\x89\x02\xd6\xeb$z\x96\xf6\x00\x00\u07d4\xfd\x1f\xb5\xa8\x9a\x89\xa7!\xb8yph\xfb\xc4\u007f>\x9dR\xe1I\x89\f\u0435\x83\u007f\xc6X\x00\x00\u07d4\xfd OOJ\xba%%\xbar\x8a\xfd\xf7\x87\x92\xcb\u07b75\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd'W\xcc5Q\xa0\x95\x87\x8d\x97\x87V\x15\xfe\fj2\xaa\x8a\x89 m\xb1R\x99\xbe\xac\x00\x00\u07d4\xfd(r\u045eW\x85<\xfa\x16\xef\xfe\x93\u0431\xd4{O\x93\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd))'\x1e\x9d \x95\xa2dv~{\r\xf5.\xa0\xd1\xd4\x00\x89\xa2\xa1\xeb%\x1bZ\xe4\x00\x00\u07d4\xfd7z8Rr\x90\f\xb46\xa3\xbbyb\xcd\xff\xe9?]\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd@$+\xb3Jp\x85^\xf0\xfd\x90\xf3\x80-\xec!6\xb3'\x89h\xa8u\a>)$\x00\x00\xe0\x94\xfdE,9i\xec\xe3\x80\x1cT \xf1\xcd\u02a1\xc7\x1e\xd2=\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xfdKU\x1fo\xdb\u0366\xc5\x11\xb5\xbb7\"P\xa6\xb7\x83\xe54\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xfdK\x98\x95X\xae\x11\xbe\f;6\xe2\xd6\xf2\xa5J\x93C\xca.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfdM\xe8\xe3t\x8a(\x9c\xf7\xd0`Q}\x9d88\x8d\xb0\x1f\xb8\x89\r\x8drkqw\xa8\x00\x00\u07d4\xfdZc\x15\u007f\x91O\u04d8\uac5c\x13}\xd9U\v\xb7q\\\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xfd`\u04b5\xaf=5\xf7\xaa\xf0\u00d3\x05.y\xc4\xd8#\u0645\x89\x03\x0e\xb5\r.\x14\b\x00\x00\u07d4\xfdhm\xe5?\xa9\u007f\x99c\x9e%hT\x97 \xbcX\x8c\x9e\xfc\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xfd~\u078fR@\xa0eA\xebi\x9dx,/\x9a\xfb!p\xf6\x89Hz\x9a0E9D\x00\x00\u07d4\xfd\x81+\u019f\xb1p\xefW\xe22~\x80\xaf\xfd\x14\xf8\xe4\xb6\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\x88\xd1\x14\"\x0f\b\x1c\xb3\xd5\xe1[\xe8\x15*\xb0sfWj\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xfd\x91\x856\xa8\xef\xa6\xf6\xce\xfe\x1f\xa1\x159\x95\xfe\xf5\xe3=;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfd\x92\x0fr&\x82\xaf\xb5\xafE\x1b\x05D\xd4\xf4\x1b;\x9dWB\x89~R\x05j\x12?<\x00\x00\u07d4\xfd\x95y\xf1\x19\xbb\xc8\x19\xa0+a\u3348\x03\xc9B\xf2M2\x89\x05\xb9~\x90\x81\xd9@\x00\x00\u07d4\xfd\xa0\xce\x153\a\a\xf1\v\xce2\x01\x17- \x18\xb9\xdd\xeat\x89\x02\xd0A\xd7\x05\xa2\xc6\x00\x00\xe0\x94\xfd\xa3\x04(\x19\xaf>f)\x00\xe1\xb9+CX\xed\xa6\xe9%\x90\x8a\x19\a\xa2\x84\u054fc\xe0\x00\x00\u07d4\xfd\xa6\x81\x0e\xa5\xac\x98]o\xfb\xf1\xc5\x11\xf1\xc1B\xed\xcf\xdd\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd\xb39D\xf26\x06\x15\xe5\xbe#\x95w\u0221\x9b\xa5-\x98\x87\x89 \x9d\x92/RY\xc5\x00\x00\u07d4\xfd\xbaSY\xf7\xec;\xc7p\xacI\x97]\x84N\xc9qbV\xf1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xfd\xc4\xd4vZ\x94/[\xf9i1\xa9\xe8\xccz\xb8\xb7W\xffL\x8a\x12lG\x8a\x0e>\xa8`\x00\x00\xe0\x94\xfd\xcd]\x80\xb1\x05\x89zW\xab\xc4xev\x8b)\x00RB\x95\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794\xfd\xd1\x19_y}O5q}\x15\xe6\xf9\x81\n\x9a?\xf5T`\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xfd\xd5\x02\xa7N\x81;\u03e3U\xce\xda<\x17ojhq\xaf\u007f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfd\u357c\vm\\\xbbL\x1d\x8f\xea>\vK\xffc^\x9d\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xea\xac*\xcf\x1d\x13\x8e\x19\xf2\xfc?\x9f\xb7E\x92\xe3\ud04a\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xfd\xec\xc8-\xdf\xc5a\x92\xe2oV<=h\xcbTJ\x96\xbf\xed\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\xfd\xf4#C\x01\x9b\v\fk\xf2`\xb1s\xaf\xab~E\xb9\xd6!\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xfd\xf4I\xf1\b\xc6\xfbOZ+\b\x1e\xed~E\u645eM%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xfda4\xc0J\x8a\xb7\xeb\x16\xf0\x06C\xf8\xfe\xd7\u06aa\ucc89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfe\x00\xbfC\x99\x11\xa5S\x98-\xb68\x03\x92E\xbc\xf02\xdb\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfe\x01n\xc1~\xc5\xf1\x0e;\xb9\x8f\xf4\xa1\xed\xa0E\x15v\x82\xab\x89\x14_T\x02\xe7\xb2\xe6\x00\x00\u07d4\xfe\x0e0\xe2\x14)\rt=\xd3\x0e\xb0\x82\xf1\xf0\xa5\"Z\xdea\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe!\v\x8f\x04\xdcmOv!j\xcf\xcb\u055b\xa8;\xe9\xb60\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\"\xa0\xb3\x88f\x8d\x1a\xe2d>w\x1d\xac\xf3\x8aCB#\u0309\xd8\xdb^\xbd{&8\x00\x00\u07d4\xfe6&\x88\x84_\xa2D\u0300~K\x110\xeb7A\xa8\x05\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe8'\xd5v0\u03c7a\xd5\x12y{\v\x85\x8eG\x8b\xbd\x12\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfeA\x8bB\x1a\x9cm76\x02y\x04u\xd20>\x11\xa7Y0\x897\b\xba\xed=h\x90\x00\x00\u07d4\xfeBI\x12yP\xe2\xf8\x96\xec\x0e~.=\x05Z\xab\x10U\x0f\x89$=M\x18\"\x9c\xa2\x00\x00\xe0\x94\xfeM\x84\x03!o\xd5qW+\xf1\xbd\xb0\x1d\x00W\x89x\u0588\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xfeS\xb9I\x89\u0619d\xda aS\x95&\xbb\xe9y\xdd.\xa9\x89h\xa8u\a>)$\x00\x00\u07d4\xfeT\x9b\xbf\xe6G@\x18\x98\x92\x93%8\u06afF\u04b6\x1dO\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfea]\x97\\\b\x87\xe0\xc9\x11>\xc7)\x84 \xa7\x93\xaf\x8b\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfee\xc4\x18\x8dy\"Wi\td D\xfd\xc5#\x95V\x01e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfei\u007f\xf2,\xa5G\xbf\xc9^3\xd9`\xda`\\gc\xf3[\x89G\xd4\x11\x9f\xd9`\x94\x00\x00\u07d4\xfej\x89[y\\\xb4\xbf\x85\x90=<\xe0\x9cZ\xa49S\u04ff\x89\xb8Pz\x82\a( \x00\x00\u07d4\xfeo_B\xb6\x19;\x1a\xd1b\x06\u4bf5#\x9dM}\xb4^\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xfep\x11\xb6\x98\xbf3q\x13-tE\xb1\x9e\xb5\xb0\x945j\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x80\xe9#-\xea\xff\x19\xba\xf9\x98i\x88:K\xdf\x00\x04\xe5<\x89.b\xf2\ni\xbe@\x00\x00\u07d4\xfe\x8en6eW\r\xffz\x1b\xdaiz\xa5\x89\xc0\xb4\xe9\x02J\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x8f\x1f\u072b\u007f\xbe\u0266\xa3\xfc\xc5\aa\x96\x00P\\6\xa3\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xfe\x91\xec\xcf+\xd5f\xaf\xa1\x16\x96\xc5\x04\x9f\xa8Lic\nR\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xfe\x96\xc4\xcd8\x15b@\x1a\xa3*\x86\xe6[\x9dR\xfa\x8a\xee'\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\xfe\x98\xc6d\xc3\xe4G\xa9^i\xbdX!q\xb7\x17n\xa2\xa6\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfe\x9a\xd1.\xf0]m\x90&\x1f\x96\xc84\n\x03\x81\x97M\xf4w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x9c\x0f\xff\xef\xb8\x03\b\x12V\xc0\xcfMfY\xe6\xd3>\xb4\xfb\x89R\xd5B\x80O\x1c\xe0\x00\x00\u07d4\xfe\x9c\xfc;\xb2\x93\u0772\x85\xe6%\xf3X/t\xa6\xb0\xa5\xa6\u0349j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xfe\x9e\x11\x97\u05d7JvH\xdc\u01e01\x12\xa8\x8e\xdb\xc9\x04]\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94\xfe\xac\xa2\xactbK\xf3H\xda\u0258QC\xcf\xd6R\xa4\xbeU\x8a\x05\x89\u007f\u02f0)\x14\b\x80\x00\u07d4\xfe\xad\x18\x03\xe5\xe77\xa6\x8e\x18G-\x9a\xc7\x15\xf0\x99L\u00be\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfe\xb8\xb8\xe2\xafqj\xe4\x1f\xc7\xc0K\xcf)T\x01VF\x1ek\x89TQt\xa5(\xa7z\x00\x00\u07d4\xfe\xb9-0\xbf\x01\xff\x9a\x19\x01flUsS+\xfa\a\xee\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe\xbc1s\xbc\x90r\x13cT\x00+{O\xb3\xbf\xc5?\"\xf1\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xfe\xbdH\xd0\xff\xdb\xd5el\xd5\xe6\x866:a\x14R(\xf2y\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xfe\xbd\x9f\x81\xcfx\xbd_\xb6\u0139\xa2K\xd4\x14\xbb\x9b\xfaLN\x89k\xe1\x0f\xb8\xedn\x13\x80\x00\u07d4\xfe\xc0o\xe2{D\u01c4\xb29n\xc9/{\x92:\xd1~\x90w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\xc1NT\x85\xde+>\xef^t\xc4aF\u06ceEN\x035\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\xfe\xd8Gm\x10\u0544\xb3\x8b\xfag7`\x0e\xf1\x9d5\xc4\x1e\u0609b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xfe\xef;n\xab\xc9J\xff\xd31\f\x1cM\x0ee7^\x13\x11\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\xf0\x9dp$?9\xed\x8c\xd8\x00\xbf\x96QG\x9e\x8fJ\xca<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe\xf3\xb3\u07ad\x1ai&\u051a\xa3+\x12\xc2*\xf5M\x9f\xf9\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xff\v|\xb7\x1d\xa9\xd4\xc1\xean\xcc(\xeb\xdaPLc\xf8/\u04498\x8a\x88]\xf2\xfcl\x00\x00\u07d4\xff\f\xc6\u73c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xff'&)AH\xb8lx\xa97$\x97\xe4Y\x89\x8e\xd3\xfe\xe3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xff=\xedz@\u04ef\xf0\u05e8\xc4_\xa6\x13j\xa0C=\xb4W\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xff>\xeeW\xc3Mm\xae\x97\r\x8b1\x11\x17\xc55\x86\xcd5\x02\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xff>\xf6\xba\x15\x1c!\xb5\x99\x86\xaed\xf6\xe8\"\x8b\u0262\xc73\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xffA\xd9\xe1\xb4\xef\xfe\x18\u0630\xd1\xf6?\xc4%_\xb4\xe0l=\x89Hz\x9a0E9D\x00\x00\u07d4\xffE\xcb4\xc9(6M\x9c\xc9\u063b\x0074ta\x8f\x06\xf3\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xffI\xa7u\x81N\xc0\x00Q\xa7\x95\xa8u\xde$Y.\xa4\x00\u050a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xffJ@\x8fP\xe9\xe7!F\xa2\x8c\xe4\xfc\x8d\x90'\x1f\x11n\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xffM\x9c\x84\x84\xc4\x10T\x89H\xa4\x80\xc2?\x80\xc2@\x80\xc2A\x80\xc2B\x80\xc2C\x80\xc2D\x80\xc2E\x80\xc2F\x80\xc2G\x80\xc2H\x80\xc2I\x80\xc2J\x80\xc2K\x80\xc2L\x80\xc2M\x80\xc2N\x80\xc2O\x80\xc2P\x80\xc2Q\x80\xc2R\x80\xc2S\x80\xc2T\x80\xc2U\x80\xc2V\x80\xc2W\x80\xc2X\x80\xc2Y\x80\xc2Z\x80\xc2[\x80\xc2\\\x80\xc2]\x80\xc2^\x80\xc2_\x80\xc2`\x80\xc2a\x80\xc2b\x80\xc2c\x80\xc2d\x80\xc2e\x80\xc2f\x80\xc2g\x80\xc2h\x80\xc2i\x80\xc2j\x80\xc2k\x80\xc2l\x80\xc2m\x80\xc2n\x80\xc2o\x80\xc2p\x80\xc2q\x80\xc2r\x80\xc2s\x80\xc2t\x80\xc2u\x80\xc2v\x80\xc2w\x80\xc2x\x80\xc2y\x80\xc2z\x80\xc2{\x80\xc2|\x80\xc2}\x80\xc2~\x80\xc2\u007f\x80\u00c1\x80\x80\u00c1\x81\x80\u00c1\x82\x80\u00c1\x83\x80\u00c1\x84\x80\u00c1\x85\x80\u00c1\x86\x80\u00c1\x87\x80\u00c1\x88\x80\u00c1\x89\x80\u00c1\x8a\x80\u00c1\x8b\x80\u00c1\x8c\x80\u00c1\x8d\x80\u00c1\x8e\x80\u00c1\x8f\x80\u00c1\x90\x80\u00c1\x91\x80\u00c1\x92\x80\u00c1\x93\x80\u00c1\x94\x80\u00c1\x95\x80\u00c1\x96\x80\u00c1\x97\x80\u00c1\x98\x80\u00c1\x99\x80\u00c1\x9a\x80\u00c1\x9b\x80\u00c1\x9c\x80\u00c1\x9d\x80\u00c1\x9e\x80\u00c1\x9f\x80\u00c1\xa0\x80\u00c1\xa1\x80\u00c1\xa2\x80\u00c1\xa3\x80\u00c1\xa4\x80\u00c1\xa5\x80\u00c1\xa6\x80\u00c1\xa7\x80\u00c1\xa8\x80\u00c1\xa9\x80\u00c1\xaa\x80\u00c1\xab\x80\u00c1\xac\x80\u00c1\xad\x80\u00c1\xae\x80\u00c1\xaf\x80\u00c1\xb0\x80\u00c1\xb1\x80\u00c1\xb2\x80\u00c1\xb3\x80\u00c1\xb4\x80\u00c1\xb5\x80\u00c1\xb6\x80\u00c1\xb7\x80\u00c1\xb8\x80\u00c1\xb9\x80\u00c1\xba\x80\u00c1\xbb\x80\u00c1\xbc\x80\u00c1\xbd\x80\u00c1\xbe\x80\u00c1\xbf\x80\u00c1\xc0\x80\u00c1\xc1\x80\u00c1\u0080\u00c1\u00c0\u00c1\u0100\u00c1\u0140\u00c1\u0180\u00c1\u01c0\u00c1\u0200\u00c1\u0240\u00c1\u0280\u00c1\u02c0\u00c1\u0300\u00c1\u0340\u00c1\u0380\u00c1\u03c0\u00c1\u0400\u00c1\u0440\u00c1\u0480\u00c1\u04c0\u00c1\u0500\u00c1\u0540\u00c1\u0580\u00c1\u05c0\u00c1\u0600\u00c1\u0640\u00c1\u0680\u00c1\u06c0\u00c1\u0700\u00c1\u0740\u00c1\u0780\u00c1\u07c0\u00c1\xe0\x80\u00c1\xe1\x80\u00c1\xe2\x80\u00c1\xe3\x80\u00c1\xe4\x80\u00c1\xe5\x80\u00c1\xe6\x80\u00c1\xe7\x80\u00c1\xe8\x80\u00c1\xe9\x80\u00c1\xea\x80\u00c1\xeb\x80\u00c1\xec\x80\u00c1\xed\x80\u00c1\xee\x80\u00c1\xef\x80\u00c1\xf0\x80\u00c1\xf1\x80\u00c1\xf2\x80\u00c1\xf3\x80\u00c1\xf4\x80\u00c1\xf5\x80\u00c1\xf6\x80\u00c1\xf7\x80\u00c1\xf8\x80\u00c1\xf9\x80\u00c1\xfa\x80\u00c1\xfb\x80\u00c1\xfc\x80\u00c1\xfd\x80\u00c1\xfe\x80\u00c1\xff\x80\u3507KT\xa8\xbd\x15)f\xd6?pk\xae\x1f\xfe\xb0A\x19!\xe5\x8d\f\x9f,\x9c\xd0Ft\xed\xea@\x00\x00\x00" const rinkebyAllocData = "\xf9\x03\xb7\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf6\x941\xb9\x8d\x14\x00{\xde\xe67)\x80\x86\x98\x8a\v\xbd1\x18E#\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +const goerliAllocData = "\xf9\x04\x06\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xe0\x94L*\xe4\x82Y5\x05\xf0\x16<\xde\xfc\a>\x81\xc6<\xdaA\a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa8\xe8\xf1G2e\x8eKQ\xe8q\x191\x05:\x8ai\xba\xf2\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe1\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbJG\xe3\xc1$H\xf4\xad\x00\x00\x00" diff --git a/vendor/github.com/ethereum/go-ethereum/core/genesis_test.go b/vendor/github.com/ethereum/go-ethereum/core/genesis_test.go index c7d54f20..c6bcd0aa 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/genesis_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/genesis_test.go @@ -141,7 +141,7 @@ func TestSetupGenesis(t *testing.T) { } for _, test := range tests { - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() config, hash, err := test.fn(db) // Check the return values. if !reflect.DeepEqual(err, test.wantErr) { diff --git a/vendor/github.com/ethereum/go-ethereum/core/headerchain.go b/vendor/github.com/ethereum/go-ethereum/core/headerchain.go index d2093113..f005b832 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/headerchain.go +++ b/vendor/github.com/ethereum/go-ethereum/core/headerchain.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru" ) const ( @@ -219,14 +219,18 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) // Generate the list of seal verification requests, and start the parallel verifier seals := make([]bool, len(chain)) - for i := 0; i < len(seals)/checkFreq; i++ { - index := i*checkFreq + hc.rand.Intn(checkFreq) - if index >= len(seals) { - index = len(seals) - 1 + if checkFreq != 0 { + // In case of checkFreq == 0 all seals are left false. + for i := 0; i < len(seals)/checkFreq; i++ { + index := i*checkFreq + hc.rand.Intn(checkFreq) + if index >= len(seals) { + index = len(seals) - 1 + } + seals[index] = true } - seals[index] = true + // Last should always be verified to avoid junk. + seals[len(seals)-1] = true } - seals[len(seals)-1] = true // Last should always be verified to avoid junk abort, results := hc.engine.VerifyHeaders(hc, chain, seals) defer close(abort) @@ -451,7 +455,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { // DeleteCallback is a callback function that is called by SetHead before // each header is deleted. -type DeleteCallback func(rawdb.DatabaseDeleter, common.Hash, uint64) +type DeleteCallback func(ethdb.Writer, common.Hash, uint64) // SetHead rewinds the local chain to a new head. Everything above the new head // will be deleted and the new one set. diff --git a/vendor/github.com/ethereum/go-ethereum/core/helper_test.go b/vendor/github.com/ethereum/go-ethereum/core/helper_test.go index 051384d8..e61c92dc 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/helper_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/helper_test.go @@ -19,6 +19,7 @@ package core import ( "container/list" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -78,7 +79,7 @@ func (tm *TestManager) Db() ethdb.Database { func NewTestManager() *TestManager { testManager := &TestManager{} testManager.eventMux = new(event.TypeMux) - testManager.db = ethdb.NewMemDatabase() + testManager.db = rawdb.NewMemoryDatabase() // testManager.txPool = NewTxPool(testManager) // testManager.blockChain = NewBlockChain(testManager) // testManager.stateManager = NewStateManager(testManager) diff --git a/vendor/github.com/ethereum/go-ethereum/core/mkalloc.go b/vendor/github.com/ethereum/go-ethereum/core/mkalloc.go index 565e8c58..5118a4fc 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/mkalloc.go +++ b/vendor/github.com/ethereum/go-ethereum/core/mkalloc.go @@ -52,7 +52,8 @@ func makelist(g *core.Genesis) allocList { if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 { panic(fmt.Sprintf("can't encode account %x", addr)) } - a = append(a, allocItem{addr.Big(), account.Balance}) + bigAddr := new(big.Int).SetBytes(addr.Bytes()) + a = append(a, allocItem{bigAddr, account.Balance}) } sort.Sort(a) return a diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain.go index 6660e17d..64783999 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain.go +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain.go @@ -23,12 +23,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) // ReadCanonicalHash retrieves the hash assigned to a canonical block number. -func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash { +func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash { data, _ := db.Get(headerHashKey(number)) if len(data) == 0 { return common.Hash{} @@ -37,21 +38,21 @@ func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash { } // WriteCanonicalHash stores the hash assigned to a canonical block number. -func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) { +func WriteCanonicalHash(db ethdb.Writer, hash common.Hash, number uint64) { if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil { log.Crit("Failed to store number to hash mapping", "err", err) } } // DeleteCanonicalHash removes the number to hash canonical mapping. -func DeleteCanonicalHash(db DatabaseDeleter, number uint64) { +func DeleteCanonicalHash(db ethdb.Writer, number uint64) { if err := db.Delete(headerHashKey(number)); err != nil { log.Crit("Failed to delete number to hash mapping", "err", err) } } // ReadHeaderNumber returns the header number assigned to a hash. -func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 { +func ReadHeaderNumber(db ethdb.Reader, hash common.Hash) *uint64 { data, _ := db.Get(headerNumberKey(hash)) if len(data) != 8 { return nil @@ -61,7 +62,7 @@ func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 { } // ReadHeadHeaderHash retrieves the hash of the current canonical head header. -func ReadHeadHeaderHash(db DatabaseReader) common.Hash { +func ReadHeadHeaderHash(db ethdb.Reader) common.Hash { data, _ := db.Get(headHeaderKey) if len(data) == 0 { return common.Hash{} @@ -70,14 +71,14 @@ func ReadHeadHeaderHash(db DatabaseReader) common.Hash { } // WriteHeadHeaderHash stores the hash of the current canonical head header. -func WriteHeadHeaderHash(db DatabaseWriter, hash common.Hash) { +func WriteHeadHeaderHash(db ethdb.Writer, hash common.Hash) { if err := db.Put(headHeaderKey, hash.Bytes()); err != nil { log.Crit("Failed to store last header's hash", "err", err) } } // ReadHeadBlockHash retrieves the hash of the current canonical head block. -func ReadHeadBlockHash(db DatabaseReader) common.Hash { +func ReadHeadBlockHash(db ethdb.Reader) common.Hash { data, _ := db.Get(headBlockKey) if len(data) == 0 { return common.Hash{} @@ -86,14 +87,14 @@ func ReadHeadBlockHash(db DatabaseReader) common.Hash { } // WriteHeadBlockHash stores the head block's hash. -func WriteHeadBlockHash(db DatabaseWriter, hash common.Hash) { +func WriteHeadBlockHash(db ethdb.Writer, hash common.Hash) { if err := db.Put(headBlockKey, hash.Bytes()); err != nil { log.Crit("Failed to store last block's hash", "err", err) } } // ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block. -func ReadHeadFastBlockHash(db DatabaseReader) common.Hash { +func ReadHeadFastBlockHash(db ethdb.Reader) common.Hash { data, _ := db.Get(headFastBlockKey) if len(data) == 0 { return common.Hash{} @@ -102,7 +103,7 @@ func ReadHeadFastBlockHash(db DatabaseReader) common.Hash { } // WriteHeadFastBlockHash stores the hash of the current fast-sync head block. -func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) { +func WriteHeadFastBlockHash(db ethdb.Writer, hash common.Hash) { if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil { log.Crit("Failed to store last fast block's hash", "err", err) } @@ -110,7 +111,7 @@ func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) { // ReadFastTrieProgress retrieves the number of tries nodes fast synced to allow // reporting correct numbers across restarts. -func ReadFastTrieProgress(db DatabaseReader) uint64 { +func ReadFastTrieProgress(db ethdb.Reader) uint64 { data, _ := db.Get(fastTrieProgressKey) if len(data) == 0 { return 0 @@ -120,20 +121,20 @@ func ReadFastTrieProgress(db DatabaseReader) uint64 { // WriteFastTrieProgress stores the fast sync trie process counter to support // retrieving it across restarts. -func WriteFastTrieProgress(db DatabaseWriter, count uint64) { +func WriteFastTrieProgress(db ethdb.Writer, count uint64) { if err := db.Put(fastTrieProgressKey, new(big.Int).SetUint64(count).Bytes()); err != nil { log.Crit("Failed to store fast sync trie progress", "err", err) } } // ReadHeaderRLP retrieves a block header in its raw RLP database encoding. -func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { +func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { data, _ := db.Get(headerKey(number, hash)) return data } // HasHeader verifies the existence of a block header corresponding to the hash. -func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool { +func HasHeader(db ethdb.Reader, hash common.Hash, number uint64) bool { if has, err := db.Has(headerKey(number, hash)); !has || err != nil { return false } @@ -141,7 +142,7 @@ func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool { } // ReadHeader retrieves the block header corresponding to the hash. -func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header { +func ReadHeader(db ethdb.Reader, hash common.Hash, number uint64) *types.Header { data := ReadHeaderRLP(db, hash, number) if len(data) == 0 { return nil @@ -156,7 +157,7 @@ func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Heade // WriteHeader stores a block header into the database and also stores the hash- // to-number mapping. -func WriteHeader(db DatabaseWriter, header *types.Header) { +func WriteHeader(db ethdb.Writer, header *types.Header) { // Write the hash -> number mapping var ( hash = header.Hash() @@ -179,30 +180,36 @@ func WriteHeader(db DatabaseWriter, header *types.Header) { } // DeleteHeader removes all block header data associated with a hash. -func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) { - if err := db.Delete(headerKey(number, hash)); err != nil { - log.Crit("Failed to delete header", "err", err) - } +func DeleteHeader(db ethdb.Writer, hash common.Hash, number uint64) { + deleteHeaderWithoutNumber(db, hash, number) if err := db.Delete(headerNumberKey(hash)); err != nil { log.Crit("Failed to delete hash to number mapping", "err", err) } } +// deleteHeaderWithoutNumber removes only the block header but does not remove +// the hash to number mapping. +func deleteHeaderWithoutNumber(db ethdb.Writer, hash common.Hash, number uint64) { + if err := db.Delete(headerKey(number, hash)); err != nil { + log.Crit("Failed to delete header", "err", err) + } +} + // ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. -func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { +func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { data, _ := db.Get(blockBodyKey(number, hash)) return data } // WriteBodyRLP stores an RLP encoded block body into the database. -func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) { +func WriteBodyRLP(db ethdb.Writer, hash common.Hash, number uint64, rlp rlp.RawValue) { if err := db.Put(blockBodyKey(number, hash), rlp); err != nil { log.Crit("Failed to store block body", "err", err) } } // HasBody verifies the existence of a block body corresponding to the hash. -func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool { +func HasBody(db ethdb.Reader, hash common.Hash, number uint64) bool { if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil { return false } @@ -210,7 +217,7 @@ func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool { } // ReadBody retrieves the block body corresponding to the hash. -func ReadBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body { +func ReadBody(db ethdb.Reader, hash common.Hash, number uint64) *types.Body { data := ReadBodyRLP(db, hash, number) if len(data) == 0 { return nil @@ -224,7 +231,7 @@ func ReadBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body { } // WriteBody storea a block body into the database. -func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.Body) { +func WriteBody(db ethdb.Writer, hash common.Hash, number uint64, body *types.Body) { data, err := rlp.EncodeToBytes(body) if err != nil { log.Crit("Failed to RLP encode body", "err", err) @@ -233,15 +240,21 @@ func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.B } // DeleteBody removes all block body data associated with a hash. -func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) { +func DeleteBody(db ethdb.Writer, hash common.Hash, number uint64) { if err := db.Delete(blockBodyKey(number, hash)); err != nil { log.Crit("Failed to delete block body", "err", err) } } -// ReadTd retrieves a block's total difficulty corresponding to the hash. -func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int { +// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding. +func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { data, _ := db.Get(headerTDKey(number, hash)) + return data +} + +// ReadTd retrieves a block's total difficulty corresponding to the hash. +func ReadTd(db ethdb.Reader, hash common.Hash, number uint64) *big.Int { + data := ReadTdRLP(db, hash, number) if len(data) == 0 { return nil } @@ -254,7 +267,7 @@ func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int { } // WriteTd stores the total difficulty of a block into the database. -func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) { +func WriteTd(db ethdb.Writer, hash common.Hash, number uint64, td *big.Int) { data, err := rlp.EncodeToBytes(td) if err != nil { log.Crit("Failed to RLP encode block total difficulty", "err", err) @@ -265,16 +278,31 @@ func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) { } // DeleteTd removes all block total difficulty data associated with a hash. -func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) { +func DeleteTd(db ethdb.Writer, hash common.Hash, number uint64) { if err := db.Delete(headerTDKey(number, hash)); err != nil { log.Crit("Failed to delete block total difficulty", "err", err) } } -// ReadReceipts retrieves all the transaction receipts belonging to a block. -func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts { - // Retrieve the flattened receipt slice +// HasReceipts verifies the existence of all the transaction receipts belonging +// to a block. +func HasReceipts(db ethdb.Reader, hash common.Hash, number uint64) bool { + if has, err := db.Has(blockReceiptsKey(number, hash)); !has || err != nil { + return false + } + return true +} + +// ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding. +func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { data, _ := db.Get(blockReceiptsKey(number, hash)) + return data +} + +// ReadReceipts retrieves all the transaction receipts belonging to a block. +func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64) types.Receipts { + // Retrieve the flattened receipt slice + data := ReadReceiptsRLP(db, hash, number) if len(data) == 0 { return nil } @@ -285,14 +313,27 @@ func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Rece return nil } receipts := make(types.Receipts, len(storageReceipts)) + logIndex := uint(0) for i, receipt := range storageReceipts { + // Assemble deriving fields for log. + for _, log := range receipt.Logs { + log.TxHash = receipt.TxHash + log.BlockHash = hash + log.BlockNumber = number + log.TxIndex = uint(i) + log.Index = logIndex + logIndex += 1 + } receipts[i] = (*types.Receipt)(receipt) + receipts[i].BlockHash = hash + receipts[i].BlockNumber = big.NewInt(0).SetUint64(number) + receipts[i].TransactionIndex = uint(i) } return receipts } // WriteReceipts stores all the transaction receipts belonging to a block. -func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts types.Receipts) { +func WriteReceipts(db ethdb.Writer, hash common.Hash, number uint64, receipts types.Receipts) { // Convert the receipts into their storage form and serialize them storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) for i, receipt := range receipts { @@ -309,7 +350,7 @@ func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts } // DeleteReceipts removes all receipt data associated with a block hash. -func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) { +func DeleteReceipts(db ethdb.Writer, hash common.Hash, number uint64) { if err := db.Delete(blockReceiptsKey(number, hash)); err != nil { log.Crit("Failed to delete block receipts", "err", err) } @@ -321,7 +362,7 @@ func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) { // // Note, due to concurrent download of header and block body the header and thus // canonical hash can be stored in the database but the body data not (yet). -func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block { +func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { header := ReadHeader(db, hash, number) if header == nil { return nil @@ -334,21 +375,30 @@ func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block } // WriteBlock serializes a block into the database, header and body separately. -func WriteBlock(db DatabaseWriter, block *types.Block) { +func WriteBlock(db ethdb.Writer, block *types.Block) { WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) WriteHeader(db, block.Header()) } // DeleteBlock removes all block data associated with a hash. -func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) { +func DeleteBlock(db ethdb.Writer, hash common.Hash, number uint64) { DeleteReceipts(db, hash, number) DeleteHeader(db, hash, number) DeleteBody(db, hash, number) DeleteTd(db, hash, number) } +// deleteBlockWithoutNumber removes all block data associated with a hash, except +// the hash to number mapping. +func deleteBlockWithoutNumber(db ethdb.Writer, hash common.Hash, number uint64) { + DeleteReceipts(db, hash, number) + deleteHeaderWithoutNumber(db, hash, number) + DeleteBody(db, hash, number) + DeleteTd(db, hash, number) +} + // FindCommonAncestor returns the last common ancestor of two block headers -func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header { +func FindCommonAncestor(db ethdb.Reader, a, b *types.Header) *types.Header { for bn := b.Number.Uint64(); a.Number.Uint64() > bn; { a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) if a == nil { diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain_test.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain_test.go index 9ddae6e2..9f6e9cdb 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_chain_test.go @@ -23,14 +23,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/sha3" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) // Tests block header storage and retrieval operations. func TestHeaderStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() // Create a test header to move around the database and make sure it's really new header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")} @@ -47,7 +46,7 @@ func TestHeaderStorage(t *testing.T) { if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { t.Fatalf("Stored header RLP not found") } else { - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() hasher.Write(entry) if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() { @@ -63,12 +62,12 @@ func TestHeaderStorage(t *testing.T) { // Tests block body storage and retrieval operations. func TestBodyStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() // Create a test body to move around the database and make sure it's really new body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() rlp.Encode(hasher, body) hash := common.BytesToHash(hasher.Sum(nil)) @@ -85,7 +84,7 @@ func TestBodyStorage(t *testing.T) { if entry := ReadBodyRLP(db, hash, 0); entry == nil { t.Fatalf("Stored body RLP not found") } else { - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() hasher.Write(entry) if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash { @@ -101,7 +100,7 @@ func TestBodyStorage(t *testing.T) { // Tests block storage and retrieval operations. func TestBlockStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() // Create a test block to move around the database and make sure it's really new block := types.NewBlockWithHeader(&types.Header{ @@ -151,7 +150,7 @@ func TestBlockStorage(t *testing.T) { // Tests that partial block contents don't get reassembled into full blocks. func TestPartialBlockStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() block := types.NewBlockWithHeader(&types.Header{ Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, @@ -185,7 +184,7 @@ func TestPartialBlockStorage(t *testing.T) { // Tests block total difficulty storage and retrieval operations. func TestTdStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() // Create a test TD to move around the database and make sure it's really new hash, td := common.Hash{}, big.NewInt(314) @@ -208,7 +207,7 @@ func TestTdStorage(t *testing.T) { // Tests that canonical numbers can be mapped to hashes and retrieved. func TestCanonicalMappingStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() // Create a test canonical number and assinged hash to move around hash, number := common.Hash{0: 0xff}, uint64(314) @@ -231,7 +230,7 @@ func TestCanonicalMappingStorage(t *testing.T) { // Tests that head headers and head blocks can be assigned, individually. func TestHeadStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) @@ -266,7 +265,7 @@ func TestHeadStorage(t *testing.T) { // Tests that receipts associated with a single block can be stored and retrieved. func TestBlockReceiptStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() receipt1 := &types.Receipt{ Status: types.ReceiptStatusFailed, @@ -279,6 +278,7 @@ func TestBlockReceiptStorage(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), GasUsed: 111111, } + receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) receipt2 := &types.Receipt{ PostState: common.Hash{2}.Bytes(), CumulativeGasUsed: 2, @@ -290,6 +290,7 @@ func TestBlockReceiptStorage(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), GasUsed: 222222, } + receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) receipts := []*types.Receipt{receipt1, receipt2} // Check that no receipt entries are in a pristine database diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes.go index 4ff7e5bd..5c7ad693 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes.go +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes.go @@ -19,88 +19,100 @@ package rawdb import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) // ReadTxLookupEntry retrieves the positional metadata associated with a transaction // hash to allow retrieving the transaction or receipt by hash. -func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) { +func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) common.Hash { data, _ := db.Get(txLookupKey(hash)) if len(data) == 0 { - return common.Hash{}, 0, 0 + return common.Hash{} } - var entry TxLookupEntry + if len(data) == common.HashLength { + return common.BytesToHash(data) + } + // Probably it's legacy txlookup entry data, try to decode it. + var entry LegacyTxLookupEntry if err := rlp.DecodeBytes(data, &entry); err != nil { - log.Error("Invalid transaction lookup entry RLP", "hash", hash, "err", err) - return common.Hash{}, 0, 0 + log.Error("Invalid transaction lookup entry RLP", "hash", hash, "blob", data, "err", err) + return common.Hash{} } - return entry.BlockHash, entry.BlockIndex, entry.Index + return entry.BlockHash } // WriteTxLookupEntries stores a positional metadata for every transaction from // a block, enabling hash based transaction and receipt lookups. -func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) { - for i, tx := range block.Transactions() { - entry := TxLookupEntry{ - BlockHash: block.Hash(), - BlockIndex: block.NumberU64(), - Index: uint64(i), - } - data, err := rlp.EncodeToBytes(entry) - if err != nil { - log.Crit("Failed to encode transaction lookup entry", "err", err) - } - if err := db.Put(txLookupKey(tx.Hash()), data); err != nil { +func WriteTxLookupEntries(db ethdb.Writer, block *types.Block) { + for _, tx := range block.Transactions() { + if err := db.Put(txLookupKey(tx.Hash()), block.Hash().Bytes()); err != nil { log.Crit("Failed to store transaction lookup entry", "err", err) } } } // DeleteTxLookupEntry removes all transaction data associated with a hash. -func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) { +func DeleteTxLookupEntry(db ethdb.Writer, hash common.Hash) { db.Delete(txLookupKey(hash)) } // ReadTransaction retrieves a specific transaction from the database, along with // its added positional metadata. -func ReadTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { - blockHash, blockNumber, txIndex := ReadTxLookupEntry(db, hash) +func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { + blockHash := ReadTxLookupEntry(db, hash) if blockHash == (common.Hash{}) { return nil, common.Hash{}, 0, 0 } - body := ReadBody(db, blockHash, blockNumber) - if body == nil || len(body.Transactions) <= int(txIndex) { - log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash, "index", txIndex) + blockNumber := ReadHeaderNumber(db, blockHash) + if blockNumber == nil { return nil, common.Hash{}, 0, 0 } - return body.Transactions[txIndex], blockHash, blockNumber, txIndex + body := ReadBody(db, blockHash, *blockNumber) + if body == nil { + log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash) + return nil, common.Hash{}, 0, 0 + } + for txIndex, tx := range body.Transactions { + if tx.Hash() == hash { + return tx, blockHash, *blockNumber, uint64(txIndex) + } + } + log.Error("Transaction not found", "number", blockNumber, "hash", blockHash, "txhash", hash) + return nil, common.Hash{}, 0, 0 } // ReadReceipt retrieves a specific transaction receipt from the database, along with // its added positional metadata. -func ReadReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) { - blockHash, blockNumber, receiptIndex := ReadTxLookupEntry(db, hash) +func ReadReceipt(db ethdb.Reader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) { + blockHash := ReadTxLookupEntry(db, hash) if blockHash == (common.Hash{}) { return nil, common.Hash{}, 0, 0 } - receipts := ReadReceipts(db, blockHash, blockNumber) - if len(receipts) <= int(receiptIndex) { - log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex) + blockNumber := ReadHeaderNumber(db, blockHash) + if blockNumber == nil { return nil, common.Hash{}, 0, 0 } - return receipts[receiptIndex], blockHash, blockNumber, receiptIndex + receipts := ReadReceipts(db, blockHash, *blockNumber) + for receiptIndex, receipt := range receipts { + if receipt.TxHash == hash { + return receipt, blockHash, *blockNumber, uint64(receiptIndex) + } + } + log.Error("Receipt not found", "number", blockNumber, "hash", blockHash, "txhash", hash) + return nil, common.Hash{}, 0, 0 } // ReadBloomBits retrieves the compressed bloom bit vector belonging to the given // section and bit index from the. -func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) { +func ReadBloomBits(db ethdb.Reader, bit uint, section uint64, head common.Hash) ([]byte, error) { return db.Get(bloomBitsKey(bit, section, head)) } // WriteBloomBits stores the compressed bloom bits vector belonging to the given // section and bit index. -func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) { +func WriteBloomBits(db ethdb.Writer, bit uint, section uint64, head common.Hash, bits []byte) { if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil { log.Crit("Failed to store bloom bits", "err", err) } diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes_test.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes_test.go index d9c10e14..ca74ba6a 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_indexes_test.go @@ -22,12 +22,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/rlp" ) // Tests that positional lookup metadata can be stored and retrieved. func TestLookupStorage(t *testing.T) { - db := ethdb.NewMemDatabase() + db := NewMemoryDatabase() tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}) tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22}) @@ -65,4 +65,26 @@ func TestLookupStorage(t *testing.T) { t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn) } } + // Insert legacy txlookup and verify the data retrieval + for index, tx := range block.Transactions() { + entry := LegacyTxLookupEntry{ + BlockHash: block.Hash(), + BlockIndex: block.NumberU64(), + Index: uint64(index), + } + data, _ := rlp.EncodeToBytes(entry) + db.Put(txLookupKey(tx.Hash()), data) + } + for i, tx := range txs { + if txn, hash, number, index := ReadTransaction(db, tx.Hash()); txn == nil { + t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash()) + } else { + if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) { + t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i) + } + if tx.Hash() != txn.Hash() { + t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx) + } + } + } } diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_metadata.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_metadata.go index 3b6e6548..1361b0d7 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_metadata.go +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/accessors_metadata.go @@ -20,31 +20,40 @@ import ( "encoding/json" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) // ReadDatabaseVersion retrieves the version number of the database. -func ReadDatabaseVersion(db DatabaseReader) int { - var version int +func ReadDatabaseVersion(db ethdb.Reader) *uint64 { + var version uint64 enc, _ := db.Get(databaseVerisionKey) - rlp.DecodeBytes(enc, &version) + if len(enc) == 0 { + return nil + } + if err := rlp.DecodeBytes(enc, &version); err != nil { + return nil + } - return version + return &version } // WriteDatabaseVersion stores the version number of the database -func WriteDatabaseVersion(db DatabaseWriter, version int) { - enc, _ := rlp.EncodeToBytes(version) - if err := db.Put(databaseVerisionKey, enc); err != nil { +func WriteDatabaseVersion(db ethdb.Writer, version uint64) { + enc, err := rlp.EncodeToBytes(version) + if err != nil { + log.Crit("Failed to encode database version", "err", err) + } + if err = db.Put(databaseVerisionKey, enc); err != nil { log.Crit("Failed to store the database version", "err", err) } } // ReadChainConfig retrieves the consensus settings based on the given genesis hash. -func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig { +func ReadChainConfig(db ethdb.Reader, hash common.Hash) *params.ChainConfig { data, _ := db.Get(configKey(hash)) if len(data) == 0 { return nil @@ -58,7 +67,7 @@ func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig { } // WriteChainConfig writes the chain config settings to the database. -func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConfig) { +func WriteChainConfig(db ethdb.Writer, hash common.Hash, cfg *params.ChainConfig) { if cfg == nil { return } @@ -72,13 +81,13 @@ func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConf } // ReadPreimage retrieves a single preimage of the provided hash. -func ReadPreimage(db DatabaseReader, hash common.Hash) []byte { +func ReadPreimage(db ethdb.Reader, hash common.Hash) []byte { data, _ := db.Get(preimageKey(hash)) return data } // WritePreimages writes the provided set of preimages to the database. -func WritePreimages(db DatabaseWriter, preimages map[common.Hash][]byte) { +func WritePreimages(db ethdb.Writer, preimages map[common.Hash][]byte) { for hash, preimage := range preimages { if err := db.Put(preimageKey(hash), preimage); err != nil { log.Crit("Failed to store trie preimage", "err", err) diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/database.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/database.go new file mode 100644 index 00000000..b4c5dea7 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/database.go @@ -0,0 +1,52 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import ( + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/leveldb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" +) + +// NewDatabase creates a high level database on top of a given key-value data +// store without a freezer moving immutable chain segments into cold storage. +func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { + return db +} + +// NewMemoryDatabase creates an ephemeral in-memory key-value database without a +// freezer moving immutable chain segments into cold storage. +func NewMemoryDatabase() ethdb.Database { + return NewDatabase(memorydb.New()) +} + +// NewMemoryDatabaseWithCap creates an ephemeral in-memory key-value database with +// an initial starting capacity, but without a freezer moving immutable chain +// segments into cold storage. +func NewMemoryDatabaseWithCap(size int) ethdb.Database { + return NewDatabase(memorydb.NewWithCap(size)) +} + +// NewLevelDBDatabase creates a persistent key-value database without a freezer +// moving immutable chain segments into cold storage. +func NewLevelDBDatabase(file string, cache int, handles int, namespace string) (ethdb.Database, error) { + db, err := leveldb.New(file, cache, handles, namespace) + if err != nil { + return nil, err + } + return NewDatabase(db), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/schema.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/schema.go index 8a9921ef..87dbf94f 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/schema.go +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/schema.go @@ -63,9 +63,9 @@ var ( preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) ) -// TxLookupEntry is a positional metadata to help looking up the data content of -// a transaction or receipt given only its hash. -type TxLookupEntry struct { +// LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary +// fields. +type LegacyTxLookupEntry struct { BlockHash common.Hash BlockIndex uint64 Index uint64 @@ -78,6 +78,11 @@ func encodeBlockNumber(number uint64) []byte { return enc } +// headerKeyPrefix = headerPrefix + num (uint64 big endian) +func headerKeyPrefix(number uint64) []byte { + return append(headerPrefix, encodeBlockNumber(number)...) +} + // headerKey = headerPrefix + num (uint64 big endian) + hash func headerKey(number uint64, hash common.Hash) []byte { return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...) diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/table.go b/vendor/github.com/ethereum/go-ethereum/core/rawdb/table.go new file mode 100644 index 00000000..e19649dd --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/core/rawdb/table.go @@ -0,0 +1,155 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import ( + "github.com/ethereum/go-ethereum/ethdb" +) + +// table is a wrapper around a database that prefixes each key access with a pre- +// configured string. +type table struct { + db ethdb.Database + prefix string +} + +// NewTable returns a database object that prefixes all keys with a given string. +func NewTable(db ethdb.Database, prefix string) ethdb.Database { + return &table{ + db: db, + prefix: prefix, + } +} + +// Close is a noop to implement the Database interface. +func (t *table) Close() error { + return nil +} + +// Has retrieves if a prefixed version of a key is present in the database. +func (t *table) Has(key []byte) (bool, error) { + return t.db.Has(append([]byte(t.prefix), key...)) +} + +// Get retrieves the given prefixed key if it's present in the database. +func (t *table) Get(key []byte) ([]byte, error) { + return t.db.Get(append([]byte(t.prefix), key...)) +} + +// Put inserts the given value into the database at a prefixed version of the +// provided key. +func (t *table) Put(key []byte, value []byte) error { + return t.db.Put(append([]byte(t.prefix), key...), value) +} + +// Delete removes the given prefixed key from the database. +func (t *table) Delete(key []byte) error { + return t.db.Delete(append([]byte(t.prefix), key...)) +} + +// NewIterator creates a binary-alphabetical iterator over the entire keyspace +// contained within the database. +func (t *table) NewIterator() ethdb.Iterator { + return t.NewIteratorWithPrefix(nil) +} + +// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset +// of database content with a particular key prefix. +func (t *table) NewIteratorWithPrefix(prefix []byte) ethdb.Iterator { + return t.db.NewIteratorWithPrefix(append([]byte(t.prefix), prefix...)) +} + +// Stat returns a particular internal stat of the database. +func (t *table) Stat(property string) (string, error) { + return t.db.Stat(property) +} + +// Compact flattens the underlying data store for the given key range. In essence, +// deleted and overwritten versions are discarded, and the data is rearranged to +// reduce the cost of operations needed to access them. +// +// A nil start is treated as a key before all keys in the data store; a nil limit +// is treated as a key after all keys in the data store. If both is nil then it +// will compact entire data store. +func (t *table) Compact(start []byte, limit []byte) error { + // If no start was specified, use the table prefix as the first value + if start == nil { + start = []byte(t.prefix) + } + // If no limit was specified, use the first element not matching the prefix + // as the limit + if limit == nil { + limit = []byte(t.prefix) + for i := len(limit) - 1; i >= 0; i-- { + // Bump the current character, stopping if it doesn't overflow + limit[i]++ + if limit[i] > 0 { + break + } + // Character overflown, proceed to the next or nil if the last + if i == 0 { + limit = nil + } + } + } + // Range correctly calculated based on table prefix, delegate down + return t.db.Compact(start, limit) +} + +// NewBatch creates a write-only database that buffers changes to its host db +// until a final write is called, each operation prefixing all keys with the +// pre-configured string. +func (t *table) NewBatch() ethdb.Batch { + return &tableBatch{t.db.NewBatch(), t.prefix} +} + +// tableBatch is a wrapper around a database batch that prefixes each key access +// with a pre-configured string. +type tableBatch struct { + batch ethdb.Batch + prefix string +} + +// Put inserts the given value into the batch for later committing. +func (b *tableBatch) Put(key, value []byte) error { + return b.batch.Put(append([]byte(b.prefix), key...), value) +} + +// Delete inserts the a key removal into the batch for later committing. +func (b *tableBatch) Delete(key []byte) error { + return b.batch.Delete(append([]byte(b.prefix), key...)) +} + +// ValueSize retrieves the amount of data queued up for writing. +func (b *tableBatch) ValueSize() int { + return b.batch.ValueSize() +} + +// Write flushes any accumulated data to disk. +func (b *tableBatch) Write() error { + return b.batch.Write() +} + +// Reset resets the batch for reuse. +func (b *tableBatch) Reset() { + b.batch.Reset() +} + +// Replay replays the batch contents. +func (b *tableBatch) Replay(w ethdb.Writer) error { + return b.batch.Replay(w) +} diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/database.go b/vendor/github.com/ethereum/go-ethereum/core/state/database.go index c1b63099..8798b738 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/database.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/database.go @@ -18,7 +18,6 @@ package state import ( "fmt" - "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" @@ -26,14 +25,7 @@ import ( lru "github.com/hashicorp/golang-lru" ) -// Trie cache generation limit after which to evict trie nodes from memory. -var MaxTrieCacheGen = uint16(120) - const ( - // Number of past tries to keep. This value is chosen such that - // reasonable chain reorg depths will hit an existing trie. - maxPastTries = 12 - // Number of codehash->size associations to keep. codeSizeCacheSize = 100000 ) @@ -59,76 +51,87 @@ type Database interface { TrieDB() *trie.Database } -// Trie is a Ethereum Merkle Trie. +// Trie is a Ethereum Merkle Patricia trie. type Trie interface { + // GetKey returns the sha3 preimage of a hashed key that was previously used + // to store a value. + // + // TODO(fjl): remove this when SecureTrie is removed + GetKey([]byte) []byte + + // TryGet returns the value for key stored in the trie. The value bytes must + // not be modified by the caller. If a node was not found in the database, a + // trie.MissingNodeError is returned. TryGet(key []byte) ([]byte, error) + + // TryUpdate associates key with value in the trie. If value has length zero, any + // existing value is deleted from the trie. The value bytes must not be modified + // by the caller while they are stored in the trie. If a node was not found in the + // database, a trie.MissingNodeError is returned. TryUpdate(key, value []byte) error + + // TryDelete removes any existing value for key from the trie. If a node was not + // found in the database, a trie.MissingNodeError is returned. TryDelete(key []byte) error - Commit(onleaf trie.LeafCallback) (common.Hash, error) + + // Hash returns the root hash of the trie. It does not write to the database and + // can be used even if the trie doesn't have one. Hash() common.Hash + + // Commit writes all nodes to the trie's memory database, tracking the internal + // and external (for account tries) references. + Commit(onleaf trie.LeafCallback) (common.Hash, error) + + // NodeIterator returns an iterator that returns nodes of the trie. Iteration + // starts at the key after the given start key. NodeIterator(startKey []byte) trie.NodeIterator - GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed - Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error + + // Prove constructs a Merkle proof for key. The result contains all encoded nodes + // on the path to the value at key. The value itself is also included in the last + // node and can be retrieved by verifying the proof. + // + // If the trie does not contain a value for key, the returned proof contains all + // nodes of the longest existing prefix of the key (at least the root), ending + // with the node that proves the absence of the key. + Prove(key []byte, fromLevel uint, proofDb ethdb.Writer) error } // NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use and retains cached trie nodes in memory. The pool is an optional -// intermediate trie-node memory pool between the low level storage layer and the -// high level trie abstraction. +// concurrent use, but does not retain any recent trie nodes in memory. To keep some +// historical state in memory, use the NewDatabaseWithCache constructor. func NewDatabase(db ethdb.Database) Database { + return NewDatabaseWithCache(db, 0) +} + +// NewDatabaseWithCache creates a backing store for state. The returned database +// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a +// large memory cache. +func NewDatabaseWithCache(db ethdb.Database, cache int) Database { csc, _ := lru.New(codeSizeCacheSize) return &cachingDB{ - db: trie.NewDatabase(db), + db: trie.NewDatabaseWithCache(db, cache), codeSizeCache: csc, } } type cachingDB struct { db *trie.Database - mu sync.Mutex - pastTries []*trie.SecureTrie codeSizeCache *lru.Cache } -// OpenTrie opens the main account trie. +// OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - db.mu.Lock() - defer db.mu.Unlock() - - for i := len(db.pastTries) - 1; i >= 0; i-- { - if db.pastTries[i].Hash() == root { - return cachedTrie{db.pastTries[i].Copy(), db}, nil - } - } - tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen) - if err != nil { - return nil, err - } - return cachedTrie{tr, db}, nil -} - -func (db *cachingDB) pushTrie(t *trie.SecureTrie) { - db.mu.Lock() - defer db.mu.Unlock() - - if len(db.pastTries) >= maxPastTries { - copy(db.pastTries, db.pastTries[1:]) - db.pastTries[len(db.pastTries)-1] = t - } else { - db.pastTries = append(db.pastTries, t) - } + return trie.NewSecure(root, db.db) } // OpenStorageTrie opens the storage trie of an account. func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { - return trie.NewSecure(root, db.db, 0) + return trie.NewSecure(root, db.db) } // CopyTrie returns an independent copy of the given trie. func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { - case cachedTrie: - return cachedTrie{t.SecureTrie.Copy(), db} case *trie.SecureTrie: return t.Copy() default: @@ -158,21 +161,3 @@ func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, erro func (db *cachingDB) TrieDB() *trie.Database { return db.db } - -// cachedTrie inserts its trie into a cachingDB on commit. -type cachedTrie struct { - *trie.SecureTrie - db *cachingDB -} - -func (m cachedTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) { - root, err := m.SecureTrie.Commit(onleaf) - if err == nil { - m.db.pushTrie(m.SecureTrie) - } - return root, err -} - -func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { - return m.SecureTrie.Prove(key, fromLevel, proofDb) -} diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/iterator_test.go b/vendor/github.com/ethereum/go-ethereum/core/state/iterator_test.go index 9e46c851..69f51c4c 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/iterator_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/iterator_test.go @@ -51,7 +51,9 @@ func TestNodeIteratorCoverage(t *testing.T) { t.Errorf("state entry not reported %x", hash) } } - for _, key := range db.TrieDB().DiskDB().(*ethdb.MemDatabase).Keys() { + it := db.TrieDB().DiskDB().(ethdb.Database).NewIterator() + for it.Next() { + key := it.Key() if bytes.HasPrefix(key, []byte("secure-key-")) { continue } @@ -59,4 +61,5 @@ func TestNodeIteratorCoverage(t *testing.T) { t.Errorf("state entry not reported %x", key) } } + it.Release() } diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/managed_state_test.go b/vendor/github.com/ethereum/go-ethereum/core/state/managed_state_test.go index 3d9c4e86..fdfde96a 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/managed_state_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/managed_state_test.go @@ -20,13 +20,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/core/rawdb" ) var addr = common.BytesToAddress([]byte("test")) func create() (*ManagedState, *account) { - statedb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) ms := ManageState(statedb) ms.StateDB.SetNonce(addr, 100) ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr)) diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go b/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go index f41ab040..7fbb45b3 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/state_object.go @@ -21,9 +21,11 @@ import ( "fmt" "io" "math/big" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" ) @@ -177,6 +179,10 @@ func (self *stateObject) GetCommittedState(db Database, key common.Hash) common. if cached { return value } + // Track the amount of time wasted on reading the storge trie + if metrics.EnabledExpensive { + defer func(start time.Time) { self.db.StorageReads += time.Since(start) }(time.Now()) + } // Otherwise load the value from the database enc, err := self.getTrie(db).TryGet(key[:]) if err != nil { @@ -216,6 +222,11 @@ func (self *stateObject) setState(key, value common.Hash) { // updateTrie writes cached storage modifications into the object's storage trie. func (self *stateObject) updateTrie(db Database) Trie { + // Track the amount of time wasted on updating the storge trie + if metrics.EnabledExpensive { + defer func(start time.Time) { self.db.StorageUpdates += time.Since(start) }(time.Now()) + } + // Update all the dirty slots in the trie tr := self.getTrie(db) for key, value := range self.dirtyStorage { delete(self.dirtyStorage, key) @@ -240,6 +251,11 @@ func (self *stateObject) updateTrie(db Database) Trie { // UpdateRoot sets the trie root to the current root hash of func (self *stateObject) updateRoot(db Database) { self.updateTrie(db) + + // Track the amount of time wasted on hashing the storge trie + if metrics.EnabledExpensive { + defer func(start time.Time) { self.db.StorageHashes += time.Since(start) }(time.Now()) + } self.data.Root = self.trie.Hash() } @@ -250,6 +266,10 @@ func (self *stateObject) CommitTrie(db Database) error { if self.dbErr != nil { return self.dbErr } + // Track the amount of time wasted on committing the storge trie + if metrics.EnabledExpensive { + defer func(start time.Time) { self.db.StorageCommits += time.Since(start) }(time.Now()) + } root, err := self.trie.Commit(nil) if err == nil { self.data.Root = root diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/state_test.go b/vendor/github.com/ethereum/go-ethereum/core/state/state_test.go index a09273f3..606f2a6f 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/state_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/state_test.go @@ -22,13 +22,14 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" checker "gopkg.in/check.v1" ) type StateSuite struct { - db *ethdb.MemDatabase + db ethdb.Database state *StateDB } @@ -87,7 +88,7 @@ func (s *StateSuite) TestDump(c *checker.C) { } func (s *StateSuite) SetUpTest(c *checker.C) { - s.db = ethdb.NewMemDatabase() + s.db = rawdb.NewMemoryDatabase() s.state, _ = New(common.Hash{}, NewDatabase(s.db)) } @@ -141,7 +142,7 @@ func (s *StateSuite) TestSnapshotEmpty(c *checker.C) { // use testing instead of checker because checker does not support // printing/logging in tests (-check.vv does not work) func TestSnapshot2(t *testing.T) { - state, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) + state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) stateobjaddr0 := toAddr([]byte("so0")) stateobjaddr1 := toAddr([]byte("so1")) diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go b/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go index 76e67d83..db2e0d5e 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/statedb.go @@ -22,11 +22,13 @@ import ( "fmt" "math/big" "sort" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -37,8 +39,8 @@ type revision struct { } var ( - // emptyState is the known hash of an empty state trie entry. - emptyState = crypto.Keccak256Hash(nil) + // emptyRoot is the known root hash of an empty trie. + emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") // emptyCode is the known hash of the empty EVM bytecode. emptyCode = crypto.Keccak256Hash(nil) @@ -51,6 +53,10 @@ func (n *proofList) Put(key []byte, value []byte) error { return nil } +func (n *proofList) Delete(key []byte) error { + panic("not supported") +} + // StateDBs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -86,6 +92,16 @@ type StateDB struct { journal *journal validRevisions []revision nextRevisionId int + + // Measurements gathered during execution for debugging purposes + AccountReads time.Duration + AccountHashes time.Duration + AccountUpdates time.Duration + AccountCommits time.Duration + StorageReads time.Duration + StorageHashes time.Duration + StorageUpdates time.Duration + StorageCommits time.Duration } // Create a new state from a given trie. @@ -221,6 +237,16 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 { return 0 } +// TxIndex returns the current transaction index set by Prepare. +func (self *StateDB) TxIndex() int { + return self.txIndex +} + +// BlockHash returns the current block hash set by Prepare. +func (self *StateDB) BlockHash() common.Hash { + return self.bhash +} + func (self *StateDB) GetCode(addr common.Address) []byte { stateObject := self.getStateObject(addr) if stateObject != nil { @@ -386,36 +412,51 @@ func (self *StateDB) Suicide(addr common.Address) bool { // // updateStateObject writes the given object to the trie. -func (self *StateDB) updateStateObject(stateObject *stateObject) { +func (s *StateDB) updateStateObject(stateObject *stateObject) { + // Track the amount of time wasted on updating the account from the trie + if metrics.EnabledExpensive { + defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) + } + // Encode the account and update the account trie addr := stateObject.Address() + data, err := rlp.EncodeToBytes(stateObject) if err != nil { panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) } - self.setError(self.trie.TryUpdate(addr[:], data)) + s.setError(s.trie.TryUpdate(addr[:], data)) } // deleteStateObject removes the given object from the state trie. -func (self *StateDB) deleteStateObject(stateObject *stateObject) { +func (s *StateDB) deleteStateObject(stateObject *stateObject) { + // Track the amount of time wasted on deleting the account from the trie + if metrics.EnabledExpensive { + defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) + } + // Delete the account from the trie stateObject.deleted = true + addr := stateObject.Address() - self.setError(self.trie.TryDelete(addr[:])) + s.setError(s.trie.TryDelete(addr[:])) } // Retrieve a state object given by the address. Returns nil if not found. -func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { - // Prefer 'live' objects. - if obj := self.stateObjects[addr]; obj != nil { +func (s *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { + // Prefer live objects + if obj := s.stateObjects[addr]; obj != nil { if obj.deleted { return nil } return obj } - - // Load the object from the database. - enc, err := self.trie.TryGet(addr[:]) + // Track the amount of time wasted on loading the object from the database + if metrics.EnabledExpensive { + defer func(start time.Time) { s.AccountReads += time.Since(start) }(time.Now()) + } + // Load the object from the database + enc, err := s.trie.TryGet(addr[:]) if len(enc) == 0 { - self.setError(err) + s.setError(err) return nil } var data Account @@ -423,9 +464,9 @@ func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObje log.Error("Failed to decode state object", "addr", addr, "err", err) return nil } - // Insert into the live set. - obj := newObject(self, addr, data) - self.setStateObject(obj) + // Insert into the live set + obj := newObject(s, addr, data) + s.setStateObject(obj) return obj } @@ -468,9 +509,9 @@ func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObjec // // Carrying over the balance ensures that Ether doesn't disappear. func (self *StateDB) CreateAccount(addr common.Address) { - new, prev := self.createObject(addr) + newObj, prev := self.createObject(addr) if prev != nil { - new.setBalance(prev.data.Balance) + newObj.setBalance(prev.data.Balance) } } @@ -502,7 +543,7 @@ func (self *StateDB) Copy() *StateDB { refund: self.refund, logs: make(map[common.Hash][]*types.Log, len(self.logs)), logSize: self.logSize, - preimages: make(map[common.Hash][]byte), + preimages: make(map[common.Hash][]byte, len(self.preimages)), journal: newJournal(), } // Copy the dirty states, logs, and preimages @@ -600,6 +641,11 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // goes into transaction receipts. func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.Finalise(deleteEmptyObjects) + + // Track the amount of time wasted on hashing the account trie + if metrics.EnabledExpensive { + defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) + } return s.trie.Hash() } @@ -624,7 +670,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) for addr := range s.journal.dirties { s.stateObjectsDirty[addr] = struct{}{} } - // Commit objects to the trie. + // Commit objects to the trie, measuring the elapsed time for addr, stateObject := range s.stateObjects { _, isDirty := s.stateObjectsDirty[addr] switch { @@ -647,13 +693,16 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) } delete(s.stateObjectsDirty, addr) } - // Write trie changes. + // Write the account trie changes, measuing the amount of wasted time + if metrics.EnabledExpensive { + defer func(start time.Time) { s.AccountCommits += time.Since(start) }(time.Now()) + } root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error { var account Account if err := rlp.DecodeBytes(leaf, &account); err != nil { return nil } - if account.Root != emptyState { + if account.Root != emptyRoot { s.db.TrieDB().Reference(account.Root, parent) } code := common.BytesToHash(account.CodeHash) @@ -662,6 +711,5 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) } return nil }) - log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads()) return root, err } diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/statedb_test.go b/vendor/github.com/ethereum/go-ethereum/core/state/statedb_test.go index cbd5bc75..c2d2b2f6 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/statedb_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/statedb_test.go @@ -31,15 +31,15 @@ import ( check "gopkg.in/check.v1" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" ) // Tests that updating a state trie does not leak any database writes prior to // actually committing the state. func TestUpdateLeaks(t *testing.T) { // Create an empty state database - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() state, _ := New(common.Hash{}, NewDatabase(db)) // Update it with some accounts @@ -56,18 +56,19 @@ func TestUpdateLeaks(t *testing.T) { state.IntermediateRoot(false) } // Ensure that no data was leaked into the database - for _, key := range db.Keys() { - value, _ := db.Get(key) - t.Errorf("State leaked into database: %x -> %x", key, value) + it := db.NewIterator() + for it.Next() { + t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value()) } + it.Release() } // Tests that no intermediate state of an object is stored into the database, // only the one right before the commit. func TestIntermediateLeaks(t *testing.T) { // Create two state databases, one transitioning to the final state, the other final from the beginning - transDb := ethdb.NewMemDatabase() - finalDb := ethdb.NewMemDatabase() + transDb := rawdb.NewMemoryDatabase() + finalDb := rawdb.NewMemoryDatabase() transState, _ := New(common.Hash{}, NewDatabase(transDb)) finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) @@ -103,16 +104,20 @@ func TestIntermediateLeaks(t *testing.T) { if _, err := finalState.Commit(false); err != nil { t.Fatalf("failed to commit final state: %v", err) } - for _, key := range finalDb.Keys() { + it := finalDb.NewIterator() + for it.Next() { + key := it.Key() if _, err := transDb.Get(key); err != nil { - val, _ := finalDb.Get(key) - t.Errorf("entry missing from the transition database: %x -> %x", key, val) + t.Errorf("entry missing from the transition database: %x -> %x", key, it.Value()) } } - for _, key := range transDb.Keys() { + it.Release() + + it = transDb.NewIterator() + for it.Next() { + key := it.Key() if _, err := finalDb.Get(key); err != nil { - val, _ := transDb.Get(key) - t.Errorf("extra entry in the transition database: %x -> %x", key, val) + t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value()) } } } @@ -122,7 +127,7 @@ func TestIntermediateLeaks(t *testing.T) { // https://github.com/ethereum/go-ethereum/pull/15549. func TestCopy(t *testing.T) { // Create a random state test to copy and modify "independently" - orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) + orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) for i := byte(0); i < 255; i++ { obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) @@ -276,6 +281,15 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { }, args: make([]int64, 1), }, + { + name: "AddPreimage", + fn: func(a testAction, s *StateDB) { + preimage := []byte{1} + hash := common.BytesToHash(preimage) + s.AddPreimage(hash, preimage) + }, + args: make([]int64, 1), + }, } action := actions[r.Intn(len(actions))] var nameargs []string @@ -333,7 +347,7 @@ func (test *snapshotTest) String() string { func (test *snapshotTest) run() bool { // Run all actions and create snapshots. var ( - state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) + state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) snapshotRevs = make([]int, len(test.snapshots)) sindex = 0 ) @@ -424,7 +438,7 @@ func (s *StateSuite) TestTouchDelete(c *check.C) { // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 func TestCopyOfCopy(t *testing.T) { - sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) + sdb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) addr := common.HexToAddress("aaaa") sdb.SetBalance(addr, big.NewInt(42)) diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/sync.go b/vendor/github.com/ethereum/go-ethereum/core/state/sync.go index c566e790..5290411a 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/sync.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/sync.go @@ -20,12 +20,13 @@ import ( "bytes" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) // NewStateSync create a new state trie download scheduler. -func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.Sync { +func NewStateSync(root common.Hash, database ethdb.Reader) *trie.Sync { var syncer *trie.Sync callback := func(leaf []byte, parent common.Hash) error { var obj Account diff --git a/vendor/github.com/ethereum/go-ethereum/core/state/sync_test.go b/vendor/github.com/ethereum/go-ethereum/core/state/sync_test.go index 31774016..ab4718b0 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state/sync_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state/sync_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" @@ -38,7 +39,7 @@ type testAccount struct { // makeTestState create a sample test state to test node-wise reconstruction. func makeTestState() (Database, common.Hash, []*testAccount) { // Create an empty state - db := NewDatabase(ethdb.NewMemDatabase()) + db := NewDatabase(rawdb.NewMemoryDatabase()) state, _ := New(common.Hash{}, db) // Fill it with some arbitrary data @@ -124,7 +125,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { // Tests that an empty state is not scheduled for syncing. func TestEmptyStateSync(t *testing.T) { empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - if req := NewStateSync(empty, ethdb.NewMemDatabase()).Missing(1); len(req) != 0 { + if req := NewStateSync(empty, rawdb.NewMemoryDatabase()).Missing(1); len(req) != 0 { t.Errorf("content requested for empty state: %v", req) } } @@ -139,7 +140,7 @@ func testIterativeStateSync(t *testing.T, batch int) { srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb := ethdb.NewMemDatabase() + dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb) queue := append([]common.Hash{}, sched.Missing(batch)...) @@ -171,7 +172,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb := ethdb.NewMemDatabase() + dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb) queue := append([]common.Hash{}, sched.Missing(0)...) @@ -208,7 +209,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) { srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb := ethdb.NewMemDatabase() + dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb) queue := make(map[common.Hash]struct{}) @@ -248,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb := ethdb.NewMemDatabase() + dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb) queue := make(map[common.Hash]struct{}) @@ -295,7 +296,7 @@ func TestIncompleteStateSync(t *testing.T) { checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot) // Create a destination state and sync with the scheduler - dstDb := ethdb.NewMemDatabase() + dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb) added := []common.Hash{} diff --git a/vendor/github.com/ethereum/go-ethereum/core/state_processor.go b/vendor/github.com/ethereum/go-ethereum/core/state_processor.go index 503a35d1..6f2a4512 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/state_processor.go +++ b/vendor/github.com/ethereum/go-ethereum/core/state_processor.go @@ -121,6 +121,9 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Set the receipt logs and create a bloom for filtering receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.BlockHash = statedb.BlockHash() + receipt.BlockNumber = header.Number + receipt.TransactionIndex = uint(statedb.TxIndex()) return receipt, gas, err } diff --git a/vendor/github.com/ethereum/go-ethereum/core/tx_cacher.go b/vendor/github.com/ethereum/go-ethereum/core/tx_cacher.go index bcaa5ead..b1e5d676 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/tx_cacher.go +++ b/vendor/github.com/ethereum/go-ethereum/core/tx_cacher.go @@ -22,7 +22,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// senderCacher is a concurrent transaction sender recoverer anc cacher. +// senderCacher is a concurrent transaction sender recoverer and cacher. var senderCacher = newTxSenderCacher(runtime.NumCPU()) // txSenderCacherRequest is a request for recovering transaction senders with a diff --git a/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go b/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go index f6da5da2..411143ae 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go +++ b/vendor/github.com/ethereum/go-ethereum/core/tx_pool.go @@ -172,6 +172,26 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig { log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) conf.PriceBump = DefaultTxPoolConfig.PriceBump } + if conf.AccountSlots < 1 { + log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultTxPoolConfig.AccountSlots) + conf.AccountSlots = DefaultTxPoolConfig.AccountSlots + } + if conf.GlobalSlots < 1 { + log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultTxPoolConfig.GlobalSlots) + conf.GlobalSlots = DefaultTxPoolConfig.GlobalSlots + } + if conf.AccountQueue < 1 { + log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultTxPoolConfig.AccountQueue) + conf.AccountQueue = DefaultTxPoolConfig.AccountQueue + } + if conf.GlobalQueue < 1 { + log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultTxPoolConfig.GlobalQueue) + conf.GlobalQueue = DefaultTxPoolConfig.GlobalQueue + } + if conf.Lifetime < 1 { + log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime) + conf.Lifetime = DefaultTxPoolConfig.Lifetime + } return conf } @@ -367,11 +387,26 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { } else { // Reorg seems shallow enough to pull in all transactions into memory var discarded, included types.Transactions - var ( rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) ) + if rem == nil { + // This can happen if a setHead is performed, where we simply discard the old + // head from the chain. + // If that is the case, we don't have the lost transactions any more, and + // there's nothing to add + if newNum < oldNum { + // If the reorg ended up on a lower number, it's indicative of setHead being the cause + log.Debug("Skipping transaction reset caused by setHead", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + } else { + // If we reorged to a same or higher number, then it's not a case of setHead + log.Warn("Transaction pool reset with missing oldhead", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + } + return + } for rem.NumberU64() > add.NumberU64() { discarded = append(discarded, rem.Transactions()...) if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { @@ -798,6 +833,9 @@ func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { // addTx enqueues a single transaction into the pool if it is valid. func (pool *TxPool) addTx(tx *types.Transaction, local bool) error { + // Cache sender in transaction before obtaining lock (pool.signer is immutable) + types.Sender(pool.signer, tx) + pool.mu.Lock() defer pool.mu.Unlock() @@ -816,6 +854,10 @@ func (pool *TxPool) addTx(tx *types.Transaction, local bool) error { // addTxs attempts to queue a batch of transactions if they are valid. func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { + // Cache senders in transactions before obtaining lock (pool.signer is immutable) + for _, tx := range txs { + types.Sender(pool.signer, tx) + } pool.mu.Lock() defer pool.mu.Unlock() @@ -825,7 +867,7 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { // addTxsLocked attempts to queue a batch of transactions if they are valid, // whilst assuming the transaction pool lock is already held. func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error { - // Add the batch of transaction, tracking the accepted ones + // Add the batch of transactions, tracking the accepted ones dirty := make(map[common.Address]struct{}) errs := make([]error, len(txs)) diff --git a/vendor/github.com/ethereum/go-ethereum/core/tx_pool_test.go b/vendor/github.com/ethereum/go-ethereum/core/tx_pool_test.go index 5a592054..50c73cf5 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/tx_pool_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/tx_pool_test.go @@ -27,10 +27,10 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" ) @@ -78,7 +78,7 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec } func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} key, _ := crypto.GenerateKey() @@ -126,7 +126,7 @@ func validateEvents(events chan NewTxsEvent, count int) error { case ev := <-events: received = append(received, ev.Txs...) case <-time.After(time.Second): - return fmt.Errorf("event #%d not fired", received) + return fmt.Errorf("event #%d not fired", len(received)) } } if len(received) > count { @@ -163,7 +163,7 @@ func (c *testChain) State() (*state.StateDB, error) { // a state change between those fetches. stdb := c.statedb if *c.trigger { - c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether)) @@ -181,7 +181,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { var ( key, _ = crypto.GenerateKey() address = crypto.PubkeyToAddress(key.PublicKey) - statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) trigger = false ) @@ -335,7 +335,7 @@ func TestTransactionChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} @@ -364,7 +364,7 @@ func TestTransactionDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} @@ -554,7 +554,7 @@ func TestTransactionPostponing(t *testing.T) { t.Parallel() // Create the pool to test the postponing with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -769,7 +769,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -857,7 +857,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { evictionInterval = time.Second // Create the pool to test the non-expiration enforcement - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1011,7 +1011,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1057,7 +1057,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1091,11 +1091,11 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig - config.GlobalSlots = 0 + config.GlobalSlots = 1 pool := NewTxPool(config, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1139,7 +1139,7 @@ func TestTransactionPoolRepricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -1260,7 +1260,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -1274,14 +1274,14 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { } // Create transaction (both pending and queued) with a linearly growing gasprice for i := uint64(0); i < 500; i++ { - // Add pending - p_tx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2]) - if err := pool.AddLocal(p_tx); err != nil { + // Add pending transaction. + pendingTx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2]) + if err := pool.AddLocal(pendingTx); err != nil { t.Fatal(err) } - // Add queued - q_tx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2]) - if err := pool.AddLocal(q_tx); err != nil { + // Add queued transaction. + queuedTx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2]) + if err := pool.AddLocal(queuedTx); err != nil { t.Fatal(err) } } @@ -1322,7 +1322,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1428,7 +1428,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1494,7 +1494,7 @@ func TestTransactionReplacement(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -1588,7 +1588,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { os.Remove(journal) // Create the original pool to inject transaction into the journal - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1686,7 +1686,7 @@ func TestTransactionStatusCheck(t *testing.T) { t.Parallel() // Create the pool to test the status retrievals with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) diff --git a/vendor/github.com/ethereum/go-ethereum/core/types.go b/vendor/github.com/ethereum/go-ethereum/core/types.go index d0bbaf0a..5c963e66 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types.go @@ -32,7 +32,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error } // Processor is an interface for processing blocks using a given initial state. diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/block.go b/vendor/github.com/ethereum/go-ethereum/core/types/block.go index 8a21bba1..b84e13c6 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/block.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/block.go @@ -21,15 +21,15 @@ import ( "encoding/binary" "io" "math/big" + "reflect" "sort" "sync/atomic" "time" - "unsafe" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) var ( @@ -81,8 +81,8 @@ type Header struct { GasUsed uint64 `json:"gasUsed" gencodec:"required"` Time *big.Int `json:"timestamp" gencodec:"required"` Extra []byte `json:"extraData" gencodec:"required"` - MixDigest common.Hash `json:"mixHash" gencodec:"required"` - Nonce BlockNonce `json:"nonce" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce BlockNonce `json:"nonce"` } // field type overrides for gencodec @@ -102,14 +102,16 @@ func (h *Header) Hash() common.Hash { return rlpHash(h) } +var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size()) + // Size returns the approximate memory used by all internal contents. It is used // to approximate and limit the memory consumption of various caches. func (h *Header) Size() common.StorageSize { - return common.StorageSize(unsafe.Sizeof(*h)) + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+h.Time.BitLen())/8) + return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+h.Time.BitLen())/8) } func rlpHash(x interface{}) (h common.Hash) { - hw := sha3.NewKeccak256() + hw := sha3.NewLegacyKeccak256() rlp.Encode(hw, x) hw.Sum(h[:0]) return h diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/gen_header_json.go b/vendor/github.com/ethereum/go-ethereum/core/types/gen_header_json.go index 1b92cd9c..59a1c9c4 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/gen_header_json.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/gen_header_json.go @@ -13,6 +13,7 @@ import ( var _ = (*headerMarshaling)(nil) +// MarshalJSON marshals as JSON. func (h Header) MarshalJSON() ([]byte, error) { type Header struct { ParentHash common.Hash `json:"parentHash" gencodec:"required"` @@ -28,8 +29,8 @@ func (h Header) MarshalJSON() ([]byte, error) { GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` Time *hexutil.Big `json:"timestamp" gencodec:"required"` Extra hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest common.Hash `json:"mixHash" gencodec:"required"` - Nonce BlockNonce `json:"nonce" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce BlockNonce `json:"nonce"` Hash common.Hash `json:"hash"` } var enc Header @@ -52,6 +53,7 @@ func (h Header) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (h *Header) UnmarshalJSON(input []byte) error { type Header struct { ParentHash *common.Hash `json:"parentHash" gencodec:"required"` @@ -67,8 +69,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` Time *hexutil.Big `json:"timestamp" gencodec:"required"` Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest *common.Hash `json:"mixHash" gencodec:"required"` - Nonce *BlockNonce `json:"nonce" gencodec:"required"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *BlockNonce `json:"nonce"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -126,13 +128,11 @@ func (h *Header) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'extraData' for Header") } h.Extra = *dec.Extra - if dec.MixDigest == nil { - return errors.New("missing required field 'mixHash' for Header") + if dec.MixDigest != nil { + h.MixDigest = *dec.MixDigest } - h.MixDigest = *dec.MixDigest - if dec.Nonce == nil { - return errors.New("missing required field 'nonce' for Header") + if dec.Nonce != nil { + h.Nonce = *dec.Nonce } - h.Nonce = *dec.Nonce return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/gen_log_json.go b/vendor/github.com/ethereum/go-ethereum/core/types/gen_log_json.go index 1b5ae3c6..6e943394 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/gen_log_json.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/gen_log_json.go @@ -12,6 +12,7 @@ import ( var _ = (*logMarshaling)(nil) +// MarshalJSON marshals as JSON. func (l Log) MarshalJSON() ([]byte, error) { type Log struct { Address common.Address `json:"address" gencodec:"required"` @@ -37,6 +38,7 @@ func (l Log) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (l *Log) UnmarshalJSON(input []byte) error { type Log struct { Address *common.Address `json:"address" gencodec:"required"` diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/gen_receipt_json.go b/vendor/github.com/ethereum/go-ethereum/core/types/gen_receipt_json.go index 5c807a4c..790ed65b 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/gen_receipt_json.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/gen_receipt_json.go @@ -5,6 +5,7 @@ package types import ( "encoding/json" "errors" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -23,6 +24,9 @@ func (r Receipt) MarshalJSON() ([]byte, error) { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + BlockHash common.Hash `json:"blockHash,omitempty"` + BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` + TransactionIndex hexutil.Uint `json:"transactionIndex"` } var enc Receipt enc.PostState = r.PostState @@ -33,6 +37,9 @@ func (r Receipt) MarshalJSON() ([]byte, error) { enc.TxHash = r.TxHash enc.ContractAddress = r.ContractAddress enc.GasUsed = hexutil.Uint64(r.GasUsed) + enc.BlockHash = r.BlockHash + enc.BlockNumber = (*hexutil.Big)(r.BlockNumber) + enc.TransactionIndex = hexutil.Uint(r.TransactionIndex) return json.Marshal(&enc) } @@ -47,6 +54,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { TxHash *common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + BlockHash *common.Hash `json:"blockHash,omitempty"` + BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` + TransactionIndex *hexutil.Uint `json:"transactionIndex"` } var dec Receipt if err := json.Unmarshal(input, &dec); err != nil { @@ -81,5 +91,14 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'gasUsed' for Receipt") } r.GasUsed = uint64(*dec.GasUsed) + if dec.BlockHash != nil { + r.BlockHash = *dec.BlockHash + } + if dec.BlockNumber != nil { + r.BlockNumber = (*big.Int)(dec.BlockNumber) + } + if dec.TransactionIndex != nil { + r.TransactionIndex = uint(*dec.TransactionIndex) + } return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/gen_tx_json.go b/vendor/github.com/ethereum/go-ethereum/core/types/gen_tx_json.go index c27da670..e676058e 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/gen_tx_json.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/gen_tx_json.go @@ -13,6 +13,7 @@ import ( var _ = (*txdataMarshaling)(nil) +// MarshalJSON marshals as JSON. func (t txdata) MarshalJSON() ([]byte, error) { type txdata struct { AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` @@ -40,6 +41,7 @@ func (t txdata) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (t *txdata) UnmarshalJSON(input []byte) error { type txdata struct { AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/log.go b/vendor/github.com/ethereum/go-ethereum/core/types/log.go index 717cd2e5..864af5ef 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/log.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/log.go @@ -68,7 +68,11 @@ type rlpLog struct { Data []byte } -type rlpStorageLog struct { +// rlpStorageLog is the storage encoding of a log. +type rlpStorageLog rlpLog + +// LegacyRlpStorageLog is the previous storage encoding of a log including some redundant fields. +type LegacyRlpStorageLog struct { Address common.Address Topics []common.Hash Data []byte @@ -101,31 +105,38 @@ type LogForStorage Log // EncodeRLP implements rlp.Encoder. func (l *LogForStorage) EncodeRLP(w io.Writer) error { return rlp.Encode(w, rlpStorageLog{ - Address: l.Address, - Topics: l.Topics, - Data: l.Data, - BlockNumber: l.BlockNumber, - TxHash: l.TxHash, - TxIndex: l.TxIndex, - BlockHash: l.BlockHash, - Index: l.Index, + Address: l.Address, + Topics: l.Topics, + Data: l.Data, }) } // DecodeRLP implements rlp.Decoder. +// +// Note some redundant fields(e.g. block number, tx hash etc) will be assembled later. func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error { + blob, err := s.Raw() + if err != nil { + return err + } var dec rlpStorageLog - err := s.Decode(&dec) + err = rlp.DecodeBytes(blob, &dec) if err == nil { *l = LogForStorage{ - Address: dec.Address, - Topics: dec.Topics, - Data: dec.Data, - BlockNumber: dec.BlockNumber, - TxHash: dec.TxHash, - TxIndex: dec.TxIndex, - BlockHash: dec.BlockHash, - Index: dec.Index, + Address: dec.Address, + Topics: dec.Topics, + Data: dec.Data, + } + } else { + // Try to decode log with previous definition. + var dec LegacyRlpStorageLog + err = rlp.DecodeBytes(blob, &dec) + if err == nil { + *l = LogForStorage{ + Address: dec.Address, + Topics: dec.Topics, + Data: dec.Data, + } } } return err diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/receipt.go b/vendor/github.com/ethereum/go-ethereum/core/types/receipt.go index 3d1fc95a..72d85a1e 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/receipt.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/receipt.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io" + "math/big" "unsafe" "github.com/ethereum/go-ethereum/common" @@ -44,17 +45,24 @@ const ( // Receipt represents the results of a transaction. type Receipt struct { - // Consensus fields + // Consensus fields: These fields are defined by the Yellow Paper PostState []byte `json:"root"` Status uint64 `json:"status"` CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` - // Implementation fields (don't reorder!) + // Implementation fields: These fields are added by geth when processing a transaction. + // They are stored in the chain database. TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed uint64 `json:"gasUsed" gencodec:"required"` + + // Inclusion information: These fields provide information about the inclusion of the + // transaction corresponding to this receipt. + BlockHash common.Hash `json:"blockHash,omitempty"` + BlockNumber *big.Int `json:"blockNumber,omitempty"` + TransactionIndex uint `json:"transactionIndex"` } type receiptMarshaling struct { @@ -62,6 +70,8 @@ type receiptMarshaling struct { Status hexutil.Uint64 CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 + BlockNumber *hexutil.Big + TransactionIndex hexutil.Uint } // receiptRLP is the consensus encoding of a receipt. @@ -72,7 +82,18 @@ type receiptRLP struct { Logs []*Log } +// receiptStorageRLP is the storage encoding of a receipt. type receiptStorageRLP struct { + PostStateOrStatus []byte + CumulativeGasUsed uint64 + TxHash common.Hash + ContractAddress common.Address + Logs []*LogForStorage + GasUsed uint64 +} + +// LegacyReceiptStorageRLP is the previous storage encoding of a receipt including some unnecessary fields. +type LegacyReceiptStorageRLP struct { PostStateOrStatus []byte CumulativeGasUsed uint64 Bloom Bloom @@ -159,7 +180,6 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { enc := &receiptStorageRLP{ PostStateOrStatus: (*Receipt)(r).statusEncoding(), CumulativeGasUsed: r.CumulativeGasUsed, - Bloom: r.Bloom, TxHash: r.TxHash, ContractAddress: r.ContractAddress, Logs: make([]*LogForStorage, len(r.Logs)), @@ -174,19 +194,34 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation // fields of a receipt from an RLP stream. func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { - var dec receiptStorageRLP - if err := s.Decode(&dec); err != nil { + blob, err := s.Raw() + if err != nil { return err } + var dec receiptStorageRLP + if err := rlp.DecodeBytes(blob, &dec); err != nil { + var sdec LegacyReceiptStorageRLP + if err := rlp.DecodeBytes(blob, &sdec); err != nil { + return err + } + dec.PostStateOrStatus = common.CopyBytes(sdec.PostStateOrStatus) + dec.CumulativeGasUsed = sdec.CumulativeGasUsed + dec.TxHash = sdec.TxHash + dec.ContractAddress = sdec.ContractAddress + dec.Logs = sdec.Logs + dec.GasUsed = sdec.GasUsed + } if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil { return err } // Assign the consensus fields - r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom + r.CumulativeGasUsed = dec.CumulativeGasUsed r.Logs = make([]*Log, len(dec.Logs)) for i, log := range dec.Logs { r.Logs[i] = (*Log)(log) } + + r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) // Assign the implementation fields r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed return nil diff --git a/vendor/github.com/ethereum/go-ethereum/core/types/transaction.go b/vendor/github.com/ethereum/go-ethereum/core/types/transaction.go index 7b53cac2..ba3d5de9 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/types/transaction.go +++ b/vendor/github.com/ethereum/go-ethereum/core/types/transaction.go @@ -234,7 +234,7 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { } // WithSignature returns a new transaction with the given signature. -// This signature needs to be formatted as described in the yellow paper (v+27). +// This signature needs to be in the [R || S || V] format where V is 0 or 1. func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) { r, s, v, err := signer.SignatureValues(tx, sig) if err != nil { diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/common.go b/vendor/github.com/ethereum/go-ethereum/core/vm/common.go index 17de38de..d592a941 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/common.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/common.go @@ -23,13 +23,31 @@ import ( "github.com/ethereum/go-ethereum/common/math" ) -// calculates the memory size required for a step -func calcMemSize(off, l *big.Int) *big.Int { - if l.Sign() == 0 { - return common.Big0 +// calcMemSize64 calculates the required memory size, and returns +// the size and whether the result overflowed uint64 +func calcMemSize64(off, l *big.Int) (uint64, bool) { + if !l.IsUint64() { + return 0, true } + return calcMemSize64WithUint(off, l.Uint64()) +} - return new(big.Int).Add(off, l) +// calcMemSize64WithUint calculates the required memory size, and returns +// the size and whether the result overflowed uint64 +// Identical to calcMemSize64, but length is a uint64 +func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) { + // if length is zero, memsize is always zero, regardless of offset + if length64 == 0 { + return 0, false + } + // Check that offset doesn't overflow + if !off.IsUint64() { + return 0, true + } + offset64 := off.Uint64() + val := offset64 + length64 + // if value < either of it's parts, then it overflowed + return val, val < offset64 } // getData returns a slice from the data based on the start and size and pads @@ -59,7 +77,7 @@ func getDataBig(data []byte, start *big.Int, size *big.Int) []byte { // bigUint64 returns the integer casted to a uint64 and returns whether it // overflowed in the process. func bigUint64(v *big.Int) (uint64, bool) { - return v.Uint64(), v.BitLen() > 64 + return v.Uint64(), !v.IsUint64() } // toWordSize returns the ceiled word size required for memory expansion. diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/evm.go b/vendor/github.com/ethereum/go-ethereum/core/vm/evm.go index 968d2219..70e1cd1b 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/evm.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/evm.go @@ -267,9 +267,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, snapshot = evm.StateDB.Snapshot() to = AccountRef(caller.Address()) ) - // initialise a new contract and set the code that is to be used by the - // EVM. The contract is a scoped environment for this execution context - // only. + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) @@ -333,12 +332,17 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte to = AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) - // Initialise a new contract and set the code that is to be used by the - // EVM. The contract is a scoped environment for this execution context - // only. + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. contract := NewContract(caller, to, new(big.Int), gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + // We do an AddBalance of zero here, just in order to trigger a touch. + // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, + // but is the correct thing to do and matters on other networks, in tests, and potential + // future scenarios + evm.StateDB.AddBalance(addr, bigZero) + // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. @@ -390,9 +394,8 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } evm.Transfer(evm.StateDB, caller.Address(), address, value) - // initialise a new contract and set the code that is to be used by the - // EVM. The contract is a scoped environment for this execution context - // only. + // Initialise a new contract and set the code that is to be used by the EVM. + // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/gas.go b/vendor/github.com/ethereum/go-ethereum/core/vm/gas.go index bba7058c..022a84f2 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/gas.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/gas.go @@ -30,10 +30,6 @@ const ( GasMidStep uint64 = 8 GasSlowStep uint64 = 10 GasExtStep uint64 = 20 - - GasReturn uint64 = 0 - GasStop uint64 = 0 - GasContractByte uint64 = 200 ) // calcGas returns the actual gas cost of the call. @@ -47,11 +43,11 @@ func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big. // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150 // is smaller than the requested amount. Therefor we return the new gas instead // of returning an error. - if callCost.BitLen() > 64 || gas < callCost.Uint64() { + if !callCost.IsUint64() || gas < callCost.Uint64() { return gas, nil } } - if callCost.BitLen() > 64 { + if !callCost.IsUint64() { return 0, errGasUintOverflow } diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/gas_table.go b/vendor/github.com/ethereum/go-ethereum/core/vm/gas_table.go index df79f86e..6400c132 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/gas_table.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/gas_table.go @@ -22,7 +22,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// memoryGasCosts calculates the quadratic gas for memory expansion. It does so +// memoryGasCost calculates the quadratic gas for memory expansion. It does so // only for the memory region that is expanded, not the total memory. func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { @@ -57,12 +57,6 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { return 0, nil } -func constGasFunc(gas uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gas, nil - } -} - func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -121,7 +115,9 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) ) // The legacy gas metering only takes into consideration the current state - if !evm.chainRules.IsConstantinople { + // Legacy rules should be applied if we are in Petersburg (removal of EIP-1283) + // OR Constantinople is not active + if evm.chainRules.IsPetersburg || !evm.chainRules.IsConstantinople { // This checks for 3 scenario's and calculates gas accordingly: // // 1. From a zero-value address to a non-zero value (NEW VALUE) @@ -380,7 +376,7 @@ func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas overflow bool ) - if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow { + if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { return 0, errGasUintOverflow } return gas, nil @@ -519,15 +515,3 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac } return gas, nil } - -func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return GasFastestStep, nil -} - -func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return GasFastestStep, nil -} - -func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return GasFastestStep, nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go b/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go index 6696c6e3..2a062d7e 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/instructions.go @@ -18,14 +18,13 @@ package vm import ( "errors" - "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/params" + "golang.org/x/crypto/sha3" ) var ( @@ -35,6 +34,7 @@ var ( errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errExecutionReverted = errors.New("evm: execution reverted") errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") + errInvalidJump = errors.New("evm: invalid jump destination") ) func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -387,7 +387,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory data := memory.Get(offset.Int64(), size.Int64()) if interpreter.hasher == nil { - interpreter.hasher = sha3.NewKeccak256().(keccakState) + interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState) } else { interpreter.hasher.Reset() } @@ -405,7 +405,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory } func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(contract.Address().Big()) + stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes())) return nil, nil } @@ -416,12 +416,12 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo } func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.evm.Origin.Big()) + stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes())) return nil, nil } func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(contract.Caller().Big()) + stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes())) return nil, nil } @@ -467,7 +467,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac ) defer interpreter.intPool.put(memOffset, dataOffset, length, end) - if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() { + if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() { return nil, errReturnDataOutOfBounds } memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) @@ -572,7 +572,7 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, me } func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.evm.Coinbase.Big()) + stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes())) return nil, nil } @@ -645,8 +645,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos := stack.pop() if !contract.validJumpdest(pos) { - nop := contract.GetOp(pos.Uint64()) - return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) + return nil, errInvalidJump } *pc = pos.Uint64() @@ -658,8 +657,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory pos, cond := stack.pop(), stack.pop() if cond.Sign() != 0 { if !contract.validJumpdest(pos) { - nop := contract.GetOp(pos.Uint64()) - return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) + return nil, errInvalidJump } *pc = pos.Uint64() } else { @@ -711,7 +709,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stack.push(interpreter.intPool.getZero()) } else { - stack.push(addr.Big()) + stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) } contract.Gas += returnGas interpreter.intPool.put(value, offset, size) @@ -739,7 +737,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo if suberr != nil { stack.push(interpreter.intPool.getZero()) } else { - stack.push(addr.Big()) + stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) } contract.Gas += returnGas interpreter.intPool.put(endowment, offset, size, salt) @@ -912,6 +910,21 @@ func makeLog(size int) executionFunc { } } +// opPush1 is a specialized version of pushN +func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + codeLen = uint64(len(contract.Code)) + integer = interpreter.intPool.get() + ) + *pc += 1 + if *pc < codeLen { + stack.push(integer.SetUint64(uint64(contract.Code[*pc]))) + } else { + stack.push(integer.SetUint64(0)) + } + return nil, nil +} + // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/interpreter.go b/vendor/github.com/ethereum/go-ethereum/core/vm/interpreter.go index 952d96dd..41766537 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/interpreter.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/interpreter.go @@ -118,22 +118,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { } } -func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { - if in.evm.chainRules.IsByzantium { - if in.readOnly { - // If the interpreter is operating in readonly mode, make sure no - // state-modifying operation is performed. The 3rd stack item - // for a call operation is the value. Transferring value from one - // account to the others means the state is modified and should also - // return with an error. - if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { - return errWriteProtection - } - } - } - return nil -} - // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occurred. // @@ -182,6 +166,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( pcCopy uint64 // needed for the deferred Tracer gasCopy uint64 // for Tracer to log gas remaining before execution logged bool // deferred Tracer should ignore already logged steps + res []byte // result of the opcode execution function ) contract.Input = input @@ -216,19 +201,35 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if !operation.valid { return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) } - if err := operation.validateStack(stack); err != nil { - return nil, err + // Validate stack + if sLen := stack.len(); sLen < operation.minStack { + return nil, fmt.Errorf("stack underflow (%d <=> %d)", sLen, operation.minStack) + } else if sLen > operation.maxStack { + return nil, fmt.Errorf("stack limit reached %d (%d)", sLen, operation.maxStack) } // If the operation is valid, enforce and write restrictions - if err := in.enforceRestrictions(op, operation, stack); err != nil { - return nil, err + if in.readOnly && in.evm.chainRules.IsByzantium { + // If the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 3rd stack item + // for a call operation is the value. Transferring value from one + // account to the others means the state is modified and should also + // return with an error. + if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) { + return nil, errWriteProtection + } + } + // Static portion of gas + if !contract.UseGas(operation.constantGas) { + return nil, ErrOutOfGas } var memorySize uint64 // calculate the new memory size and expand the memory to fit // the operation + // Memory check needs to be done prior to evaluating the dynamic gas portion, + // to detect calculation overflows if operation.memorySize != nil { - memSize, overflow := bigUint64(operation.memorySize(stack)) + memSize, overflow := operation.memorySize(stack) if overflow { return nil, errGasUintOverflow } @@ -238,11 +239,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( return nil, errGasUintOverflow } } + // Dynamic portion of gas // consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method can get the proper cost - cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) - if err != nil || !contract.UseGas(cost) { - return nil, ErrOutOfGas + if operation.dynamicGas != nil { + cost, err = operation.dynamicGas(in.gasTable, in.evm, contract, stack, mem, memorySize) + if err != nil || !contract.UseGas(cost) { + return nil, ErrOutOfGas + } } if memorySize > 0 { mem.Resize(memorySize) @@ -254,7 +258,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } // execute the operation - res, err := operation.execute(&pc, in, contract, mem, stack) + res, err = operation.execute(&pc, in, contract, mem, stack) // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. if verifyPool { diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/jump_table.go b/vendor/github.com/ethereum/go-ethereum/core/vm/jump_table.go index deedf70c..425436f9 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/jump_table.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/jump_table.go @@ -18,27 +18,30 @@ package vm import ( "errors" - "math/big" "github.com/ethereum/go-ethereum/params" ) type ( - executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) - gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 - stackValidationFunc func(*Stack) error - memorySizeFunc func(*Stack) *big.Int + executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) + gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + // memorySizeFunc returns the required size, and whether the operation overflowed a uint64 + memorySizeFunc func(*Stack) (size uint64, overflow bool) ) var errGasUintOverflow = errors.New("gas uint64 overflow") type operation struct { // execute is the operation function - execute executionFunc - // gasCost is the gas function and returns the gas required for execution - gasCost gasFunc - // validateStack validates the stack (size) for the operation - validateStack stackValidationFunc + execute executionFunc + constantGas uint64 + dynamicGas gasFunc + // minStack tells how many stack items are required + minStack int + // maxStack specifies the max length the stack can have for this operation + // to not overflow the stack. + maxStack int + // memorySize returns the memory size required for the operation memorySize memorySizeFunc @@ -63,37 +66,42 @@ func newConstantinopleInstructionSet() [256]operation { // instructions that can be executed during the byzantium phase. instructionSet := newByzantiumInstructionSet() instructionSet[SHL] = operation{ - execute: opSHL, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSHL, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, } instructionSet[SHR] = operation{ - execute: opSHR, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSHR, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, } instructionSet[SAR] = operation{ - execute: opSAR, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSAR, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, } instructionSet[EXTCODEHASH] = operation{ - execute: opExtCodeHash, - gasCost: gasExtCodeHash, - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opExtCodeHash, + dynamicGas: gasExtCodeHash, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, } instructionSet[CREATE2] = operation{ - execute: opCreate2, - gasCost: gasCreate2, - validateStack: makeStackFunc(4, 1), - memorySize: memoryCreate2, - valid: true, - writes: true, - returns: true, + execute: opCreate2, + dynamicGas: gasCreate2, + minStack: minStack(4, 1), + maxStack: maxStack(4, 1), + memorySize: memoryCreate2, + valid: true, + writes: true, + returns: true, } return instructionSet } @@ -104,34 +112,38 @@ func newByzantiumInstructionSet() [256]operation { // instructions that can be executed during the homestead phase. instructionSet := newHomesteadInstructionSet() instructionSet[STATICCALL] = operation{ - execute: opStaticCall, - gasCost: gasStaticCall, - validateStack: makeStackFunc(6, 1), - memorySize: memoryStaticCall, - valid: true, - returns: true, + execute: opStaticCall, + dynamicGas: gasStaticCall, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryStaticCall, + valid: true, + returns: true, } instructionSet[RETURNDATASIZE] = operation{ - execute: opReturnDataSize, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opReturnDataSize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, } instructionSet[RETURNDATACOPY] = operation{ - execute: opReturnDataCopy, - gasCost: gasReturnDataCopy, - validateStack: makeStackFunc(3, 0), - memorySize: memoryReturnDataCopy, - valid: true, + execute: opReturnDataCopy, + dynamicGas: gasReturnDataCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, } instructionSet[REVERT] = operation{ - execute: opRevert, - gasCost: gasRevert, - validateStack: makeStackFunc(2, 0), - memorySize: memoryRevert, - valid: true, - reverts: true, - returns: true, + execute: opRevert, + dynamicGas: gasRevert, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryRevert, + valid: true, + reverts: true, + returns: true, } return instructionSet } @@ -141,12 +153,13 @@ func newByzantiumInstructionSet() [256]operation { func newHomesteadInstructionSet() [256]operation { instructionSet := newFrontierInstructionSet() instructionSet[DELEGATECALL] = operation{ - execute: opDelegateCall, - gasCost: gasDelegateCall, - validateStack: makeStackFunc(6, 1), - memorySize: memoryDelegateCall, - valid: true, - returns: true, + execute: opDelegateCall, + dynamicGas: gasDelegateCall, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryDelegateCall, + valid: true, + returns: true, } return instructionSet } @@ -156,811 +169,940 @@ func newHomesteadInstructionSet() [256]operation { func newFrontierInstructionSet() [256]operation { return [256]operation{ STOP: { - execute: opStop, - gasCost: constGasFunc(0), - validateStack: makeStackFunc(0, 0), - halts: true, - valid: true, + execute: opStop, + constantGas: 0, + minStack: minStack(0, 0), + maxStack: maxStack(0, 0), + halts: true, + valid: true, }, ADD: { - execute: opAdd, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opAdd, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, MUL: { - execute: opMul, - gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opMul, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SUB: { - execute: opSub, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSub, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, DIV: { - execute: opDiv, - gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opDiv, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SDIV: { - execute: opSdiv, - gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSdiv, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, MOD: { - execute: opMod, - gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opMod, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SMOD: { - execute: opSmod, - gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSmod, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, ADDMOD: { - execute: opAddmod, - gasCost: constGasFunc(GasMidStep), - validateStack: makeStackFunc(3, 1), - valid: true, + execute: opAddmod, + constantGas: GasMidStep, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + valid: true, }, MULMOD: { - execute: opMulmod, - gasCost: constGasFunc(GasMidStep), - validateStack: makeStackFunc(3, 1), - valid: true, + execute: opMulmod, + constantGas: GasMidStep, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + valid: true, }, EXP: { - execute: opExp, - gasCost: gasExp, - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opExp, + dynamicGas: gasExp, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SIGNEXTEND: { - execute: opSignExtend, - gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSignExtend, + constantGas: GasFastStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, LT: { - execute: opLt, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opLt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, GT: { - execute: opGt, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opGt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SLT: { - execute: opSlt, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSlt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SGT: { - execute: opSgt, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opSgt, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, EQ: { - execute: opEq, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opEq, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, ISZERO: { - execute: opIszero, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opIszero, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, AND: { - execute: opAnd, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opAnd, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, XOR: { - execute: opXor, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opXor, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, OR: { - execute: opOr, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opOr, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, NOT: { - execute: opNot, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opNot, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, BYTE: { - execute: opByte, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), - valid: true, + execute: opByte, + constantGas: GasFastestStep, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + valid: true, }, SHA3: { - execute: opSha3, - gasCost: gasSha3, - validateStack: makeStackFunc(2, 1), - memorySize: memorySha3, - valid: true, + execute: opSha3, + dynamicGas: gasSha3, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + memorySize: memorySha3, + valid: true, }, ADDRESS: { - execute: opAddress, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opAddress, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, BALANCE: { - execute: opBalance, - gasCost: gasBalance, - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opBalance, + dynamicGas: gasBalance, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, ORIGIN: { - execute: opOrigin, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opOrigin, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, CALLER: { - execute: opCaller, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opCaller, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, CALLVALUE: { - execute: opCallValue, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opCallValue, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, CALLDATALOAD: { - execute: opCallDataLoad, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opCallDataLoad, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, CALLDATASIZE: { - execute: opCallDataSize, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opCallDataSize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, CALLDATACOPY: { - execute: opCallDataCopy, - gasCost: gasCallDataCopy, - validateStack: makeStackFunc(3, 0), - memorySize: memoryCallDataCopy, - valid: true, + execute: opCallDataCopy, + dynamicGas: gasCallDataCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCallDataCopy, + valid: true, }, CODESIZE: { - execute: opCodeSize, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opCodeSize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, CODECOPY: { - execute: opCodeCopy, - gasCost: gasCodeCopy, - validateStack: makeStackFunc(3, 0), - memorySize: memoryCodeCopy, - valid: true, + execute: opCodeCopy, + dynamicGas: gasCodeCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCodeCopy, + valid: true, }, GASPRICE: { - execute: opGasprice, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opGasprice, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, EXTCODESIZE: { - execute: opExtCodeSize, - gasCost: gasExtCodeSize, - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opExtCodeSize, + dynamicGas: gasExtCodeSize, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, EXTCODECOPY: { - execute: opExtCodeCopy, - gasCost: gasExtCodeCopy, - validateStack: makeStackFunc(4, 0), - memorySize: memoryExtCodeCopy, - valid: true, + execute: opExtCodeCopy, + dynamicGas: gasExtCodeCopy, + minStack: minStack(4, 0), + maxStack: maxStack(4, 0), + memorySize: memoryExtCodeCopy, + valid: true, }, BLOCKHASH: { - execute: opBlockhash, - gasCost: constGasFunc(GasExtStep), - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opBlockhash, + constantGas: GasExtStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, COINBASE: { - execute: opCoinbase, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opCoinbase, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, TIMESTAMP: { - execute: opTimestamp, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opTimestamp, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, NUMBER: { - execute: opNumber, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opNumber, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, DIFFICULTY: { - execute: opDifficulty, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opDifficulty, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, GASLIMIT: { - execute: opGasLimit, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opGasLimit, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, POP: { - execute: opPop, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(1, 0), - valid: true, + execute: opPop, + constantGas: GasQuickStep, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + valid: true, }, MLOAD: { - execute: opMload, - gasCost: gasMLoad, - validateStack: makeStackFunc(1, 1), - memorySize: memoryMLoad, - valid: true, + execute: opMload, + dynamicGas: gasMLoad, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + memorySize: memoryMLoad, + valid: true, }, MSTORE: { - execute: opMstore, - gasCost: gasMStore, - validateStack: makeStackFunc(2, 0), - memorySize: memoryMStore, - valid: true, + execute: opMstore, + dynamicGas: gasMStore, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryMStore, + valid: true, }, MSTORE8: { - execute: opMstore8, - gasCost: gasMStore8, - memorySize: memoryMStore8, - validateStack: makeStackFunc(2, 0), + execute: opMstore8, + dynamicGas: gasMStore8, + memorySize: memoryMStore8, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), valid: true, }, SLOAD: { - execute: opSload, - gasCost: gasSLoad, - validateStack: makeStackFunc(1, 1), - valid: true, + execute: opSload, + dynamicGas: gasSLoad, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, SSTORE: { - execute: opSstore, - gasCost: gasSStore, - validateStack: makeStackFunc(2, 0), - valid: true, - writes: true, + execute: opSstore, + dynamicGas: gasSStore, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + valid: true, + writes: true, }, JUMP: { - execute: opJump, - gasCost: constGasFunc(GasMidStep), - validateStack: makeStackFunc(1, 0), - jumps: true, - valid: true, + execute: opJump, + constantGas: GasMidStep, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + jumps: true, + valid: true, }, JUMPI: { - execute: opJumpi, - gasCost: constGasFunc(GasSlowStep), - validateStack: makeStackFunc(2, 0), - jumps: true, - valid: true, + execute: opJumpi, + constantGas: GasSlowStep, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + jumps: true, + valid: true, }, PC: { - execute: opPc, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opPc, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, MSIZE: { - execute: opMsize, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opMsize, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, GAS: { - execute: opGas, - gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opGas, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, JUMPDEST: { - execute: opJumpdest, - gasCost: constGasFunc(params.JumpdestGas), - validateStack: makeStackFunc(0, 0), - valid: true, + execute: opJumpdest, + constantGas: params.JumpdestGas, + minStack: minStack(0, 0), + maxStack: maxStack(0, 0), + valid: true, }, PUSH1: { - execute: makePush(1, 1), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: opPush1, + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH2: { - execute: makePush(2, 2), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(2, 2), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH3: { - execute: makePush(3, 3), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(3, 3), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH4: { - execute: makePush(4, 4), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(4, 4), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH5: { - execute: makePush(5, 5), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(5, 5), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH6: { - execute: makePush(6, 6), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(6, 6), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH7: { - execute: makePush(7, 7), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(7, 7), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH8: { - execute: makePush(8, 8), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(8, 8), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH9: { - execute: makePush(9, 9), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(9, 9), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH10: { - execute: makePush(10, 10), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(10, 10), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH11: { - execute: makePush(11, 11), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(11, 11), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH12: { - execute: makePush(12, 12), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(12, 12), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH13: { - execute: makePush(13, 13), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(13, 13), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH14: { - execute: makePush(14, 14), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(14, 14), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH15: { - execute: makePush(15, 15), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(15, 15), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH16: { - execute: makePush(16, 16), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(16, 16), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH17: { - execute: makePush(17, 17), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(17, 17), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH18: { - execute: makePush(18, 18), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(18, 18), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH19: { - execute: makePush(19, 19), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(19, 19), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH20: { - execute: makePush(20, 20), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(20, 20), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH21: { - execute: makePush(21, 21), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(21, 21), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH22: { - execute: makePush(22, 22), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(22, 22), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH23: { - execute: makePush(23, 23), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(23, 23), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH24: { - execute: makePush(24, 24), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(24, 24), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH25: { - execute: makePush(25, 25), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(25, 25), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH26: { - execute: makePush(26, 26), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(26, 26), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH27: { - execute: makePush(27, 27), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(27, 27), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH28: { - execute: makePush(28, 28), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(28, 28), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH29: { - execute: makePush(29, 29), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(29, 29), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH30: { - execute: makePush(30, 30), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(30, 30), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH31: { - execute: makePush(31, 31), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(31, 31), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, PUSH32: { - execute: makePush(32, 32), - gasCost: gasPush, - validateStack: makeStackFunc(0, 1), - valid: true, + execute: makePush(32, 32), + constantGas: GasFastestStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + valid: true, }, DUP1: { - execute: makeDup(1), - gasCost: gasDup, - validateStack: makeDupStackFunc(1), - valid: true, + execute: makeDup(1), + constantGas: GasFastestStep, + minStack: minDupStack(1), + maxStack: maxDupStack(1), + valid: true, }, DUP2: { - execute: makeDup(2), - gasCost: gasDup, - validateStack: makeDupStackFunc(2), - valid: true, + execute: makeDup(2), + constantGas: GasFastestStep, + minStack: minDupStack(2), + maxStack: maxDupStack(2), + valid: true, }, DUP3: { - execute: makeDup(3), - gasCost: gasDup, - validateStack: makeDupStackFunc(3), - valid: true, + execute: makeDup(3), + constantGas: GasFastestStep, + minStack: minDupStack(3), + maxStack: maxDupStack(3), + valid: true, }, DUP4: { - execute: makeDup(4), - gasCost: gasDup, - validateStack: makeDupStackFunc(4), - valid: true, + execute: makeDup(4), + constantGas: GasFastestStep, + minStack: minDupStack(4), + maxStack: maxDupStack(4), + valid: true, }, DUP5: { - execute: makeDup(5), - gasCost: gasDup, - validateStack: makeDupStackFunc(5), - valid: true, + execute: makeDup(5), + constantGas: GasFastestStep, + minStack: minDupStack(5), + maxStack: maxDupStack(5), + valid: true, }, DUP6: { - execute: makeDup(6), - gasCost: gasDup, - validateStack: makeDupStackFunc(6), - valid: true, + execute: makeDup(6), + constantGas: GasFastestStep, + minStack: minDupStack(6), + maxStack: maxDupStack(6), + valid: true, }, DUP7: { - execute: makeDup(7), - gasCost: gasDup, - validateStack: makeDupStackFunc(7), - valid: true, + execute: makeDup(7), + constantGas: GasFastestStep, + minStack: minDupStack(7), + maxStack: maxDupStack(7), + valid: true, }, DUP8: { - execute: makeDup(8), - gasCost: gasDup, - validateStack: makeDupStackFunc(8), - valid: true, + execute: makeDup(8), + constantGas: GasFastestStep, + minStack: minDupStack(8), + maxStack: maxDupStack(8), + valid: true, }, DUP9: { - execute: makeDup(9), - gasCost: gasDup, - validateStack: makeDupStackFunc(9), - valid: true, + execute: makeDup(9), + constantGas: GasFastestStep, + minStack: minDupStack(9), + maxStack: maxDupStack(9), + valid: true, }, DUP10: { - execute: makeDup(10), - gasCost: gasDup, - validateStack: makeDupStackFunc(10), - valid: true, + execute: makeDup(10), + constantGas: GasFastestStep, + minStack: minDupStack(10), + maxStack: maxDupStack(10), + valid: true, }, DUP11: { - execute: makeDup(11), - gasCost: gasDup, - validateStack: makeDupStackFunc(11), - valid: true, + execute: makeDup(11), + constantGas: GasFastestStep, + minStack: minDupStack(11), + maxStack: maxDupStack(11), + valid: true, }, DUP12: { - execute: makeDup(12), - gasCost: gasDup, - validateStack: makeDupStackFunc(12), - valid: true, + execute: makeDup(12), + constantGas: GasFastestStep, + minStack: minDupStack(12), + maxStack: maxDupStack(12), + valid: true, }, DUP13: { - execute: makeDup(13), - gasCost: gasDup, - validateStack: makeDupStackFunc(13), - valid: true, + execute: makeDup(13), + constantGas: GasFastestStep, + minStack: minDupStack(13), + maxStack: maxDupStack(13), + valid: true, }, DUP14: { - execute: makeDup(14), - gasCost: gasDup, - validateStack: makeDupStackFunc(14), - valid: true, + execute: makeDup(14), + constantGas: GasFastestStep, + minStack: minDupStack(14), + maxStack: maxDupStack(14), + valid: true, }, DUP15: { - execute: makeDup(15), - gasCost: gasDup, - validateStack: makeDupStackFunc(15), - valid: true, + execute: makeDup(15), + constantGas: GasFastestStep, + minStack: minDupStack(15), + maxStack: maxDupStack(15), + valid: true, }, DUP16: { - execute: makeDup(16), - gasCost: gasDup, - validateStack: makeDupStackFunc(16), - valid: true, + execute: makeDup(16), + constantGas: GasFastestStep, + minStack: minDupStack(16), + maxStack: maxDupStack(16), + valid: true, }, SWAP1: { - execute: makeSwap(1), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(2), - valid: true, + execute: makeSwap(1), + constantGas: GasFastestStep, + minStack: minSwapStack(2), + maxStack: maxSwapStack(2), + valid: true, }, SWAP2: { - execute: makeSwap(2), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(3), - valid: true, + execute: makeSwap(2), + constantGas: GasFastestStep, + minStack: minSwapStack(3), + maxStack: maxSwapStack(3), + valid: true, }, SWAP3: { - execute: makeSwap(3), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(4), - valid: true, + execute: makeSwap(3), + constantGas: GasFastestStep, + minStack: minSwapStack(4), + maxStack: maxSwapStack(4), + valid: true, }, SWAP4: { - execute: makeSwap(4), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(5), - valid: true, + execute: makeSwap(4), + constantGas: GasFastestStep, + minStack: minSwapStack(5), + maxStack: maxSwapStack(5), + valid: true, }, SWAP5: { - execute: makeSwap(5), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(6), - valid: true, + execute: makeSwap(5), + constantGas: GasFastestStep, + minStack: minSwapStack(6), + maxStack: maxSwapStack(6), + valid: true, }, SWAP6: { - execute: makeSwap(6), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(7), - valid: true, + execute: makeSwap(6), + constantGas: GasFastestStep, + minStack: minSwapStack(7), + maxStack: maxSwapStack(7), + valid: true, }, SWAP7: { - execute: makeSwap(7), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(8), - valid: true, + execute: makeSwap(7), + constantGas: GasFastestStep, + minStack: minSwapStack(8), + maxStack: maxSwapStack(8), + valid: true, }, SWAP8: { - execute: makeSwap(8), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(9), - valid: true, + execute: makeSwap(8), + constantGas: GasFastestStep, + minStack: minSwapStack(9), + maxStack: maxSwapStack(9), + valid: true, }, SWAP9: { - execute: makeSwap(9), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(10), - valid: true, + execute: makeSwap(9), + constantGas: GasFastestStep, + minStack: minSwapStack(10), + maxStack: maxSwapStack(10), + valid: true, }, SWAP10: { - execute: makeSwap(10), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(11), - valid: true, + execute: makeSwap(10), + constantGas: GasFastestStep, + minStack: minSwapStack(11), + maxStack: maxSwapStack(11), + valid: true, }, SWAP11: { - execute: makeSwap(11), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(12), - valid: true, + execute: makeSwap(11), + constantGas: GasFastestStep, + minStack: minSwapStack(12), + maxStack: maxSwapStack(12), + valid: true, }, SWAP12: { - execute: makeSwap(12), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(13), - valid: true, + execute: makeSwap(12), + constantGas: GasFastestStep, + minStack: minSwapStack(13), + maxStack: maxSwapStack(13), + valid: true, }, SWAP13: { - execute: makeSwap(13), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(14), - valid: true, + execute: makeSwap(13), + constantGas: GasFastestStep, + minStack: minSwapStack(14), + maxStack: maxSwapStack(14), + valid: true, }, SWAP14: { - execute: makeSwap(14), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(15), - valid: true, + execute: makeSwap(14), + constantGas: GasFastestStep, + minStack: minSwapStack(15), + maxStack: maxSwapStack(15), + valid: true, }, SWAP15: { - execute: makeSwap(15), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(16), - valid: true, + execute: makeSwap(15), + constantGas: GasFastestStep, + minStack: minSwapStack(16), + maxStack: maxSwapStack(16), + valid: true, }, SWAP16: { - execute: makeSwap(16), - gasCost: gasSwap, - validateStack: makeSwapStackFunc(17), - valid: true, + execute: makeSwap(16), + constantGas: GasFastestStep, + minStack: minSwapStack(17), + maxStack: maxSwapStack(17), + valid: true, }, LOG0: { - execute: makeLog(0), - gasCost: makeGasLog(0), - validateStack: makeStackFunc(2, 0), - memorySize: memoryLog, - valid: true, - writes: true, + execute: makeLog(0), + dynamicGas: makeGasLog(0), + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryLog, + valid: true, + writes: true, }, LOG1: { - execute: makeLog(1), - gasCost: makeGasLog(1), - validateStack: makeStackFunc(3, 0), - memorySize: memoryLog, - valid: true, - writes: true, + execute: makeLog(1), + dynamicGas: makeGasLog(1), + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryLog, + valid: true, + writes: true, }, LOG2: { - execute: makeLog(2), - gasCost: makeGasLog(2), - validateStack: makeStackFunc(4, 0), - memorySize: memoryLog, - valid: true, - writes: true, + execute: makeLog(2), + dynamicGas: makeGasLog(2), + minStack: minStack(4, 0), + maxStack: maxStack(4, 0), + memorySize: memoryLog, + valid: true, + writes: true, }, LOG3: { - execute: makeLog(3), - gasCost: makeGasLog(3), - validateStack: makeStackFunc(5, 0), - memorySize: memoryLog, - valid: true, - writes: true, + execute: makeLog(3), + dynamicGas: makeGasLog(3), + minStack: minStack(5, 0), + maxStack: maxStack(5, 0), + memorySize: memoryLog, + valid: true, + writes: true, }, LOG4: { - execute: makeLog(4), - gasCost: makeGasLog(4), - validateStack: makeStackFunc(6, 0), - memorySize: memoryLog, - valid: true, - writes: true, + execute: makeLog(4), + dynamicGas: makeGasLog(4), + minStack: minStack(6, 0), + maxStack: maxStack(6, 0), + memorySize: memoryLog, + valid: true, + writes: true, }, CREATE: { - execute: opCreate, - gasCost: gasCreate, - validateStack: makeStackFunc(3, 1), - memorySize: memoryCreate, - valid: true, - writes: true, - returns: true, + execute: opCreate, + dynamicGas: gasCreate, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + memorySize: memoryCreate, + valid: true, + writes: true, + returns: true, }, CALL: { - execute: opCall, - gasCost: gasCall, - validateStack: makeStackFunc(7, 1), - memorySize: memoryCall, - valid: true, - returns: true, + execute: opCall, + dynamicGas: gasCall, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, }, CALLCODE: { - execute: opCallCode, - gasCost: gasCallCode, - validateStack: makeStackFunc(7, 1), - memorySize: memoryCall, - valid: true, - returns: true, + execute: opCallCode, + dynamicGas: gasCallCode, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, }, RETURN: { - execute: opReturn, - gasCost: gasReturn, - validateStack: makeStackFunc(2, 0), - memorySize: memoryReturn, - halts: true, - valid: true, + execute: opReturn, + dynamicGas: gasReturn, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryReturn, + halts: true, + valid: true, }, SELFDESTRUCT: { - execute: opSuicide, - gasCost: gasSuicide, - validateStack: makeStackFunc(1, 0), - halts: true, - valid: true, - writes: true, + execute: opSuicide, + dynamicGas: gasSuicide, + minStack: minStack(1, 0), + maxStack: maxStack(1, 0), + halts: true, + valid: true, + writes: true, }, } } diff --git a/vendor/github.com/ethereum/go-ethereum/cmd/evm/json_logger.go b/vendor/github.com/ethereum/go-ethereum/core/vm/logger_json.go similarity index 79% rename from vendor/github.com/ethereum/go-ethereum/cmd/evm/json_logger.go rename to vendor/github.com/ethereum/go-ethereum/core/vm/logger_json.go index 50cb4f0e..ff379a4e 100644 --- a/vendor/github.com/ethereum/go-ethereum/cmd/evm/json_logger.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/logger_json.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . -package main +package vm import ( "encoding/json" @@ -24,18 +24,21 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" ) type JSONLogger struct { encoder *json.Encoder - cfg *vm.LogConfig + cfg *LogConfig } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. -func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger { - return &JSONLogger{json.NewEncoder(writer), cfg} +func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger { + l := &JSONLogger{json.NewEncoder(writer), cfg} + if l.cfg == nil { + l.cfg = &LogConfig{} + } + return l } func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error { @@ -43,8 +46,8 @@ func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { - log := vm.StructLog{ +func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { + log := StructLog{ Pc: pc, Op: op, Gas: gas, @@ -65,7 +68,7 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos } // CaptureFault outputs state information on the logger. -func (l *JSONLogger) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { +func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/memory_table.go b/vendor/github.com/ethereum/go-ethereum/core/vm/memory_table.go index 8fa6c90c..4fcb4144 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/memory_table.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/memory_table.go @@ -16,82 +16,98 @@ package vm -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common/math" -) - -func memorySha3(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) +func memorySha3(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } -func memoryCallDataCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) +func memoryCallDataCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) } -func memoryReturnDataCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) +func memoryReturnDataCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) } -func memoryCodeCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) +func memoryCodeCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) } -func memoryExtCodeCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(3)) +func memoryExtCodeCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(3)) } -func memoryMLoad(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big.NewInt(32)) +func memoryMLoad(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 32) } -func memoryMStore8(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big.NewInt(1)) +func memoryMStore8(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 1) } -func memoryMStore(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big.NewInt(32)) +func memoryMStore(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 32) } -func memoryCreate(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(2)) +func memoryCreate(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(2)) } -func memoryCreate2(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(2)) +func memoryCreate2(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(2)) } -func memoryCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(5), stack.Back(6)) - y := calcMemSize(stack.Back(3), stack.Back(4)) - - return math.BigMax(x, y) +func memoryCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(5), stack.Back(6)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(3), stack.Back(4)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false +} +func memoryDelegateCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false } -func memoryDelegateCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(4), stack.Back(5)) - y := calcMemSize(stack.Back(2), stack.Back(3)) - - return math.BigMax(x, y) +func memoryStaticCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false } -func memoryStaticCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(4), stack.Back(5)) - y := calcMemSize(stack.Back(2), stack.Back(3)) - - return math.BigMax(x, y) +func memoryReturn(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } -func memoryReturn(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) +func memoryRevert(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } -func memoryRevert(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) -} - -func memoryLog(stack *Stack) *big.Int { - mSize, mStart := stack.Back(1), stack.Back(0) - return calcMemSize(mStart, mSize) +func memoryLog(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go index cda49a34..db1f6f38 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime.go @@ -22,10 +22,10 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -99,7 +99,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) } var ( address = common.BytesToAddress([]byte("contract")) @@ -129,7 +129,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) } var ( vmenv = NewEnv(cfg) diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime_test.go b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime_test.go index bac06e52..15f545dd 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime_test.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/runtime/runtime_test.go @@ -23,9 +23,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -95,7 +95,7 @@ func TestExecute(t *testing.T) { } func TestCall(t *testing.T) { - state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + state, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) address := common.HexToAddress("0x0a") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, @@ -151,7 +151,7 @@ func BenchmarkCall(b *testing.B) { } func benchmarkEVM_Create(bench *testing.B, code string) { var ( - statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) ) diff --git a/vendor/github.com/ethereum/go-ethereum/core/vm/stack_table.go b/vendor/github.com/ethereum/go-ethereum/core/vm/stack_table.go index a4b1cfcd..10c12901 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/vm/stack_table.go +++ b/vendor/github.com/ethereum/go-ethereum/core/vm/stack_table.go @@ -17,28 +17,26 @@ package vm import ( - "fmt" - "github.com/ethereum/go-ethereum/params" ) -func makeStackFunc(pop, push int) stackValidationFunc { - return func(stack *Stack) error { - if err := stack.require(pop); err != nil { - return err - } - - if stack.len()+push-pop > int(params.StackLimit) { - return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit) - } - return nil - } +func minSwapStack(n int) int { + return minStack(n, n) +} +func maxSwapStack(n int) int { + return maxStack(n, n) } -func makeDupStackFunc(n int) stackValidationFunc { - return makeStackFunc(n, n+1) +func minDupStack(n int) int { + return minStack(n, n+1) +} +func maxDupStack(n int) int { + return maxStack(n, n+1) } -func makeSwapStackFunc(n int) stackValidationFunc { - return makeStackFunc(n, n) +func maxStack(pop, push int) int { + return int(params.StackLimit) + pop - push +} +func minStack(pops, push int) int { + return pops } diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/main_test.go b/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/main_test.go index 0230f1b1..c0c85457 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/main_test.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/main_test.go @@ -13,7 +13,7 @@ func TestRandomG2Marshal(t *testing.T) { t.Error(err) continue } - t.Logf("%d: %x\n", n, g2.Marshal()) + t.Logf("%v: %x\n", n, g2.Marshal()) } } diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/mul_arm64.h b/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/mul_arm64.h index 75d52217..d405eb8f 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/mul_arm64.h +++ b/vendor/github.com/ethereum/go-ethereum/crypto/bn256/cloudflare/mul_arm64.h @@ -12,7 +12,7 @@ UMULH R1, R8, c4 \ ADCS ZR, c4 \ \ - MUL R2, R5, R25 \ + MUL R2, R5, R1 \ UMULH R2, R5, R26 \ MUL R2, R6, R0 \ ADDS R0, R26 \ @@ -24,13 +24,13 @@ ADCS R0, R29 \ UMULH R2, R8, c5 \ ADCS ZR, c5 \ - ADDS R25, c1 \ + ADDS R1, c1 \ ADCS R26, c2 \ ADCS R27, c3 \ ADCS R29, c4 \ ADCS ZR, c5 \ \ - MUL R3, R5, R25 \ + MUL R3, R5, R1 \ UMULH R3, R5, R26 \ MUL R3, R6, R0 \ ADDS R0, R26 \ @@ -42,13 +42,13 @@ ADCS R0, R29 \ UMULH R3, R8, c6 \ ADCS ZR, c6 \ - ADDS R25, c2 \ + ADDS R1, c2 \ ADCS R26, c3 \ ADCS R27, c4 \ ADCS R29, c5 \ ADCS ZR, c6 \ \ - MUL R4, R5, R25 \ + MUL R4, R5, R1 \ UMULH R4, R5, R26 \ MUL R4, R6, R0 \ ADDS R0, R26 \ @@ -60,7 +60,7 @@ ADCS R0, R29 \ UMULH R4, R8, c7 \ ADCS ZR, c7 \ - ADDS R25, c3 \ + ADDS R1, c3 \ ADCS R26, c4 \ ADCS R27, c5 \ ADCS R29, c6 \ @@ -69,15 +69,15 @@ #define gfpReduce() \ \ // m = (T * N') mod R, store m in R1:R2:R3:R4 MOVD ·np+0(SB), R17 \ - MOVD ·np+8(SB), R18 \ + MOVD ·np+8(SB), R25 \ MOVD ·np+16(SB), R19 \ MOVD ·np+24(SB), R20 \ \ MUL R9, R17, R1 \ UMULH R9, R17, R2 \ - MUL R9, R18, R0 \ + MUL R9, R25, R0 \ ADDS R0, R2 \ - UMULH R9, R18, R3 \ + UMULH R9, R25, R3 \ MUL R9, R19, R0 \ ADCS R0, R3 \ UMULH R9, R19, R4 \ @@ -86,9 +86,9 @@ \ MUL R10, R17, R21 \ UMULH R10, R17, R22 \ - MUL R10, R18, R0 \ + MUL R10, R25, R0 \ ADDS R0, R22 \ - UMULH R10, R18, R23 \ + UMULH R10, R25, R23 \ MUL R10, R19, R0 \ ADCS R0, R23 \ ADDS R21, R2 \ @@ -97,7 +97,7 @@ \ MUL R11, R17, R21 \ UMULH R11, R17, R22 \ - MUL R11, R18, R0 \ + MUL R11, R25, R0 \ ADDS R0, R22 \ ADDS R21, R3 \ ADCS R22, R4 \ @@ -107,19 +107,19 @@ \ \ // m * N loadModulus(R5,R6,R7,R8) \ - mul(R17,R18,R19,R20,R21,R22,R23,R24) \ + mul(R17,R25,R19,R20,R21,R22,R23,R24) \ \ \ // Add the 512-bit intermediate to m*N - MOVD ZR, R25 \ + MOVD ZR, R0 \ ADDS R9, R17 \ - ADCS R10, R18 \ + ADCS R10, R25 \ ADCS R11, R19 \ ADCS R12, R20 \ ADCS R13, R21 \ ADCS R14, R22 \ ADCS R15, R23 \ ADCS R16, R24 \ - ADCS ZR, R25 \ + ADCS ZR, R0 \ \ \ // Our output is R21:R22:R23:R24. Reduce mod p if necessary. SUBS R5, R21, R10 \ diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/bn256/google/main_test.go b/vendor/github.com/ethereum/go-ethereum/crypto/bn256/google/main_test.go index 0230f1b1..c0c85457 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/bn256/google/main_test.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/bn256/google/main_test.go @@ -13,7 +13,7 @@ func TestRandomG2Marshal(t *testing.T) { t.Error(err) continue } - t.Logf("%d: %x\n", n, g2.Marshal()) + t.Logf("%v: %x\n", n, g2.Marshal()) } } diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/crypto.go b/vendor/github.com/ethereum/go-ethereum/crypto/crypto.go index 9b3e76d4..4567fafc 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/crypto.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/crypto.go @@ -30,8 +30,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) var ( @@ -43,7 +43,7 @@ var errInvalidPubkey = errors.New("invalid secp256k1 public key") // Keccak256 calculates and returns the Keccak256 hash of the input data. func Keccak256(data ...[]byte) []byte { - d := sha3.NewKeccak256() + d := sha3.NewLegacyKeccak256() for _, b := range data { d.Write(b) } @@ -53,7 +53,7 @@ func Keccak256(data ...[]byte) []byte { // Keccak256Hash calculates and returns the Keccak256 hash of the input data, // converting it to an internal Hash data structure. func Keccak256Hash(data ...[]byte) (h common.Hash) { - d := sha3.NewKeccak256() + d := sha3.NewLegacyKeccak256() for _, b := range data { d.Write(b) } @@ -63,7 +63,7 @@ func Keccak256Hash(data ...[]byte) (h common.Hash) { // Keccak512 calculates and returns the Keccak512 hash of the input data. func Keccak512(data ...[]byte) []byte { - d := sha3.NewKeccak512() + d := sha3.NewLegacyKeccak512() for _, b := range data { d.Write(b) } diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/ecies/ecies_test.go b/vendor/github.com/ethereum/go-ethereum/crypto/ecies/ecies_test.go index f33f204d..6bd57145 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/ecies/ecies_test.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/ecies/ecies_test.go @@ -93,19 +93,6 @@ func cmpPublic(pub1, pub2 PublicKey) bool { return bytes.Equal(pub1Out, pub2Out) } -// cmpPrivate returns true if the two private keys are the same. -func cmpPrivate(prv1, prv2 *PrivateKey) bool { - if prv1 == nil || prv1.D == nil { - return false - } else if prv2 == nil || prv2.D == nil { - return false - } else if prv1.D.Cmp(prv2.D) != 0 { - return false - } else { - return cmpPublic(prv1.PublicKey, prv2.PublicKey) - } -} - // Validate the ECDH component. func TestSharedKey(t *testing.T) { prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/secp256k1/curve.go b/vendor/github.com/ethereum/go-ethereum/crypto/secp256k1/curve.go index 56be235b..5409ee1d 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/secp256k1/curve.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/secp256k1/curve.go @@ -310,7 +310,7 @@ var theCurve = new(BitCurve) func init() { // See SEC 2 section 2.7.1 // curve parameters taken from: - // http://www.secg.org/collateral/sec2_final.pdf + // http://www.secg.org/sec2-v2.pdf theCurve.P, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 0) theCurve.N, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 0) theCurve.B, _ = new(big.Int).SetString("0x0000000000000000000000000000000000000000000000000000000000000007", 0) diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/PATENTS b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/PATENTS deleted file mode 100644 index 73309904..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/doc.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/doc.go deleted file mode 100644 index 3dab530f..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/doc.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package sha3 implements the SHA-3 fixed-output-length hash functions and -// the SHAKE variable-output-length hash functions defined by FIPS-202. -// -// Both types of hash function use the "sponge" construction and the Keccak -// permutation. For a detailed specification see http://keccak.noekeon.org/ -// -// -// Guidance -// -// If you aren't sure what function you need, use SHAKE256 with at least 64 -// bytes of output. The SHAKE instances are faster than the SHA3 instances; -// the latter have to allocate memory to conform to the hash.Hash interface. -// -// If you need a secret-key MAC (message authentication code), prepend the -// secret key to the input, hash with SHAKE256 and read at least 32 bytes of -// output. -// -// -// Security strengths -// -// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security -// strength against preimage attacks of x bits. Since they only produce "x" -// bits of output, their collision-resistance is only "x/2" bits. -// -// The SHAKE-256 and -128 functions have a generic security strength of 256 and -// 128 bits against all attacks, provided that at least 2x bits of their output -// is used. Requesting more than 64 or 32 bytes of output, respectively, does -// not increase the collision-resistance of the SHAKE functions. -// -// -// The sponge construction -// -// A sponge builds a pseudo-random function from a public pseudo-random -// permutation, by applying the permutation to a state of "rate + capacity" -// bytes, but hiding "capacity" of the bytes. -// -// A sponge starts out with a zero state. To hash an input using a sponge, up -// to "rate" bytes of the input are XORed into the sponge's state. The sponge -// is then "full" and the permutation is applied to "empty" it. This process is -// repeated until all the input has been "absorbed". The input is then padded. -// The digest is "squeezed" from the sponge in the same way, except that output -// output is copied out instead of input being XORed in. -// -// A sponge is parameterized by its generic security strength, which is equal -// to half its capacity; capacity + rate is equal to the permutation's width. -// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means -// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. -// -// -// Recommendations -// -// The SHAKE functions are recommended for most new uses. They can produce -// output of arbitrary length. SHAKE256, with an output length of at least -// 64 bytes, provides 256-bit security against all attacks. The Keccak team -// recommends it for most applications upgrading from SHA2-512. (NIST chose a -// much stronger, but much slower, sponge instance for SHA3-512.) -// -// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. -// They produce output of the same length, with the same security strengths -// against all attacks. This means, in particular, that SHA3-256 only has -// 128-bit collision resistance, because its output length is 32 bytes. -package sha3 diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/hashes.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/hashes.go deleted file mode 100644 index fa0d7b43..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/hashes.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// This file provides functions for creating instances of the SHA-3 -// and SHAKE hash functions, as well as utility functions for hashing -// bytes. - -import ( - "hash" -) - -// NewKeccak256 creates a new Keccak-256 hash. -func NewKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } - -// NewKeccak512 creates a new Keccak-512 hash. -func NewKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } - -// New224 creates a new SHA3-224 hash. -// Its generic security strength is 224 bits against preimage attacks, -// and 112 bits against collision attacks. -func New224() hash.Hash { return &state{rate: 144, outputLen: 28, dsbyte: 0x06} } - -// New256 creates a new SHA3-256 hash. -// Its generic security strength is 256 bits against preimage attacks, -// and 128 bits against collision attacks. -func New256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x06} } - -// New384 creates a new SHA3-384 hash. -// Its generic security strength is 384 bits against preimage attacks, -// and 192 bits against collision attacks. -func New384() hash.Hash { return &state{rate: 104, outputLen: 48, dsbyte: 0x06} } - -// New512 creates a new SHA3-512 hash. -// Its generic security strength is 512 bits against preimage attacks, -// and 256 bits against collision attacks. -func New512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x06} } - -// Sum224 returns the SHA3-224 digest of the data. -func Sum224(data []byte) (digest [28]byte) { - h := New224() - h.Write(data) - h.Sum(digest[:0]) - return -} - -// Sum256 returns the SHA3-256 digest of the data. -func Sum256(data []byte) (digest [32]byte) { - h := New256() - h.Write(data) - h.Sum(digest[:0]) - return -} - -// Sum384 returns the SHA3-384 digest of the data. -func Sum384(data []byte) (digest [48]byte) { - h := New384() - h.Write(data) - h.Sum(digest[:0]) - return -} - -// Sum512 returns the SHA3-512 digest of the data. -func Sum512(data []byte) (digest [64]byte) { - h := New512() - h.Write(data) - h.Sum(digest[:0]) - return -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go deleted file mode 100644 index 46d03ed3..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf.go +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64 appengine gccgo - -package sha3 - -// rc stores the round constants for use in the ι step. -var rc = [24]uint64{ - 0x0000000000000001, - 0x0000000000008082, - 0x800000000000808A, - 0x8000000080008000, - 0x000000000000808B, - 0x0000000080000001, - 0x8000000080008081, - 0x8000000000008009, - 0x000000000000008A, - 0x0000000000000088, - 0x0000000080008009, - 0x000000008000000A, - 0x000000008000808B, - 0x800000000000008B, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x000000000000800A, - 0x800000008000000A, - 0x8000000080008081, - 0x8000000000008080, - 0x0000000080000001, - 0x8000000080008008, -} - -// keccakF1600 applies the Keccak permutation to a 1600b-wide -// state represented as a slice of 25 uint64s. -func keccakF1600(a *[25]uint64) { - // Implementation translated from Keccak-inplace.c - // in the keccak reference code. - var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 - - for i := 0; i < 24; i += 4 { - // Combines the 5 steps in each round into 2 steps. - // Unrolls 4 rounds per loop and spreads some steps across rounds. - - // Round 1 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[6] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[12] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[18] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[24] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] - a[6] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[16] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[22] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[3] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[10] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[1] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[7] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[19] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[20] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[11] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[23] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[4] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[5] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[2] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[8] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[14] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[15] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - // Round 2 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[16] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[7] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[23] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[14] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] - a[16] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[11] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[2] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[18] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[20] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[6] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[22] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[4] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[15] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[1] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[8] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[24] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[10] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[12] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[3] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[19] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[5] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - // Round 3 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[11] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[22] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[8] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[19] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] - a[11] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[1] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[12] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[23] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[15] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[16] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[2] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[24] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[5] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[6] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[3] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[14] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[20] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[7] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[18] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[4] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[10] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - // Round 4 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[1] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[2] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[3] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[4] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] - a[1] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[6] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[7] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[8] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[5] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[11] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[12] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[14] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[10] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[16] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[18] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[19] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[15] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[22] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[23] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[24] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[20] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go deleted file mode 100644 index de035c55..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64,!appengine,!gccgo - -package sha3 - -// This function is implemented in keccakf_amd64.s. - -//go:noescape - -func keccakF1600(state *[25]uint64) diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s deleted file mode 100644 index f88533ac..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/keccakf_amd64.s +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64,!appengine,!gccgo - -// This code was translated into a form compatible with 6a from the public -// domain sources at https://github.com/gvanas/KeccakCodePackage - -// Offsets in state -#define _ba (0*8) -#define _be (1*8) -#define _bi (2*8) -#define _bo (3*8) -#define _bu (4*8) -#define _ga (5*8) -#define _ge (6*8) -#define _gi (7*8) -#define _go (8*8) -#define _gu (9*8) -#define _ka (10*8) -#define _ke (11*8) -#define _ki (12*8) -#define _ko (13*8) -#define _ku (14*8) -#define _ma (15*8) -#define _me (16*8) -#define _mi (17*8) -#define _mo (18*8) -#define _mu (19*8) -#define _sa (20*8) -#define _se (21*8) -#define _si (22*8) -#define _so (23*8) -#define _su (24*8) - -// Temporary registers -#define rT1 AX - -// Round vars -#define rpState DI -#define rpStack SP - -#define rDa BX -#define rDe CX -#define rDi DX -#define rDo R8 -#define rDu R9 - -#define rBa R10 -#define rBe R11 -#define rBi R12 -#define rBo R13 -#define rBu R14 - -#define rCa SI -#define rCe BP -#define rCi rBi -#define rCo rBo -#define rCu R15 - -#define MOVQ_RBI_RCE MOVQ rBi, rCe -#define XORQ_RT1_RCA XORQ rT1, rCa -#define XORQ_RT1_RCE XORQ rT1, rCe -#define XORQ_RBA_RCU XORQ rBa, rCu -#define XORQ_RBE_RCU XORQ rBe, rCu -#define XORQ_RDU_RCU XORQ rDu, rCu -#define XORQ_RDA_RCA XORQ rDa, rCa -#define XORQ_RDE_RCE XORQ rDe, rCe - -#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \ - /* Prepare round */ \ - MOVQ rCe, rDa; \ - ROLQ $1, rDa; \ - \ - MOVQ _bi(iState), rCi; \ - XORQ _gi(iState), rDi; \ - XORQ rCu, rDa; \ - XORQ _ki(iState), rCi; \ - XORQ _mi(iState), rDi; \ - XORQ rDi, rCi; \ - \ - MOVQ rCi, rDe; \ - ROLQ $1, rDe; \ - \ - MOVQ _bo(iState), rCo; \ - XORQ _go(iState), rDo; \ - XORQ rCa, rDe; \ - XORQ _ko(iState), rCo; \ - XORQ _mo(iState), rDo; \ - XORQ rDo, rCo; \ - \ - MOVQ rCo, rDi; \ - ROLQ $1, rDi; \ - \ - MOVQ rCu, rDo; \ - XORQ rCe, rDi; \ - ROLQ $1, rDo; \ - \ - MOVQ rCa, rDu; \ - XORQ rCi, rDo; \ - ROLQ $1, rDu; \ - \ - /* Result b */ \ - MOVQ _ba(iState), rBa; \ - MOVQ _ge(iState), rBe; \ - XORQ rCo, rDu; \ - MOVQ _ki(iState), rBi; \ - MOVQ _mo(iState), rBo; \ - MOVQ _su(iState), rBu; \ - XORQ rDe, rBe; \ - ROLQ $44, rBe; \ - XORQ rDi, rBi; \ - XORQ rDa, rBa; \ - ROLQ $43, rBi; \ - \ - MOVQ rBe, rCa; \ - MOVQ rc, rT1; \ - ORQ rBi, rCa; \ - XORQ rBa, rT1; \ - XORQ rT1, rCa; \ - MOVQ rCa, _ba(oState); \ - \ - XORQ rDu, rBu; \ - ROLQ $14, rBu; \ - MOVQ rBa, rCu; \ - ANDQ rBe, rCu; \ - XORQ rBu, rCu; \ - MOVQ rCu, _bu(oState); \ - \ - XORQ rDo, rBo; \ - ROLQ $21, rBo; \ - MOVQ rBo, rT1; \ - ANDQ rBu, rT1; \ - XORQ rBi, rT1; \ - MOVQ rT1, _bi(oState); \ - \ - NOTQ rBi; \ - ORQ rBa, rBu; \ - ORQ rBo, rBi; \ - XORQ rBo, rBu; \ - XORQ rBe, rBi; \ - MOVQ rBu, _bo(oState); \ - MOVQ rBi, _be(oState); \ - B_RBI_RCE; \ - \ - /* Result g */ \ - MOVQ _gu(iState), rBe; \ - XORQ rDu, rBe; \ - MOVQ _ka(iState), rBi; \ - ROLQ $20, rBe; \ - XORQ rDa, rBi; \ - ROLQ $3, rBi; \ - MOVQ _bo(iState), rBa; \ - MOVQ rBe, rT1; \ - ORQ rBi, rT1; \ - XORQ rDo, rBa; \ - MOVQ _me(iState), rBo; \ - MOVQ _si(iState), rBu; \ - ROLQ $28, rBa; \ - XORQ rBa, rT1; \ - MOVQ rT1, _ga(oState); \ - G_RT1_RCA; \ - \ - XORQ rDe, rBo; \ - ROLQ $45, rBo; \ - MOVQ rBi, rT1; \ - ANDQ rBo, rT1; \ - XORQ rBe, rT1; \ - MOVQ rT1, _ge(oState); \ - G_RT1_RCE; \ - \ - XORQ rDi, rBu; \ - ROLQ $61, rBu; \ - MOVQ rBu, rT1; \ - ORQ rBa, rT1; \ - XORQ rBo, rT1; \ - MOVQ rT1, _go(oState); \ - \ - ANDQ rBe, rBa; \ - XORQ rBu, rBa; \ - MOVQ rBa, _gu(oState); \ - NOTQ rBu; \ - G_RBA_RCU; \ - \ - ORQ rBu, rBo; \ - XORQ rBi, rBo; \ - MOVQ rBo, _gi(oState); \ - \ - /* Result k */ \ - MOVQ _be(iState), rBa; \ - MOVQ _gi(iState), rBe; \ - MOVQ _ko(iState), rBi; \ - MOVQ _mu(iState), rBo; \ - MOVQ _sa(iState), rBu; \ - XORQ rDi, rBe; \ - ROLQ $6, rBe; \ - XORQ rDo, rBi; \ - ROLQ $25, rBi; \ - MOVQ rBe, rT1; \ - ORQ rBi, rT1; \ - XORQ rDe, rBa; \ - ROLQ $1, rBa; \ - XORQ rBa, rT1; \ - MOVQ rT1, _ka(oState); \ - K_RT1_RCA; \ - \ - XORQ rDu, rBo; \ - ROLQ $8, rBo; \ - MOVQ rBi, rT1; \ - ANDQ rBo, rT1; \ - XORQ rBe, rT1; \ - MOVQ rT1, _ke(oState); \ - K_RT1_RCE; \ - \ - XORQ rDa, rBu; \ - ROLQ $18, rBu; \ - NOTQ rBo; \ - MOVQ rBo, rT1; \ - ANDQ rBu, rT1; \ - XORQ rBi, rT1; \ - MOVQ rT1, _ki(oState); \ - \ - MOVQ rBu, rT1; \ - ORQ rBa, rT1; \ - XORQ rBo, rT1; \ - MOVQ rT1, _ko(oState); \ - \ - ANDQ rBe, rBa; \ - XORQ rBu, rBa; \ - MOVQ rBa, _ku(oState); \ - K_RBA_RCU; \ - \ - /* Result m */ \ - MOVQ _ga(iState), rBe; \ - XORQ rDa, rBe; \ - MOVQ _ke(iState), rBi; \ - ROLQ $36, rBe; \ - XORQ rDe, rBi; \ - MOVQ _bu(iState), rBa; \ - ROLQ $10, rBi; \ - MOVQ rBe, rT1; \ - MOVQ _mi(iState), rBo; \ - ANDQ rBi, rT1; \ - XORQ rDu, rBa; \ - MOVQ _so(iState), rBu; \ - ROLQ $27, rBa; \ - XORQ rBa, rT1; \ - MOVQ rT1, _ma(oState); \ - M_RT1_RCA; \ - \ - XORQ rDi, rBo; \ - ROLQ $15, rBo; \ - MOVQ rBi, rT1; \ - ORQ rBo, rT1; \ - XORQ rBe, rT1; \ - MOVQ rT1, _me(oState); \ - M_RT1_RCE; \ - \ - XORQ rDo, rBu; \ - ROLQ $56, rBu; \ - NOTQ rBo; \ - MOVQ rBo, rT1; \ - ORQ rBu, rT1; \ - XORQ rBi, rT1; \ - MOVQ rT1, _mi(oState); \ - \ - ORQ rBa, rBe; \ - XORQ rBu, rBe; \ - MOVQ rBe, _mu(oState); \ - \ - ANDQ rBa, rBu; \ - XORQ rBo, rBu; \ - MOVQ rBu, _mo(oState); \ - M_RBE_RCU; \ - \ - /* Result s */ \ - MOVQ _bi(iState), rBa; \ - MOVQ _go(iState), rBe; \ - MOVQ _ku(iState), rBi; \ - XORQ rDi, rBa; \ - MOVQ _ma(iState), rBo; \ - ROLQ $62, rBa; \ - XORQ rDo, rBe; \ - MOVQ _se(iState), rBu; \ - ROLQ $55, rBe; \ - \ - XORQ rDu, rBi; \ - MOVQ rBa, rDu; \ - XORQ rDe, rBu; \ - ROLQ $2, rBu; \ - ANDQ rBe, rDu; \ - XORQ rBu, rDu; \ - MOVQ rDu, _su(oState); \ - \ - ROLQ $39, rBi; \ - S_RDU_RCU; \ - NOTQ rBe; \ - XORQ rDa, rBo; \ - MOVQ rBe, rDa; \ - ANDQ rBi, rDa; \ - XORQ rBa, rDa; \ - MOVQ rDa, _sa(oState); \ - S_RDA_RCA; \ - \ - ROLQ $41, rBo; \ - MOVQ rBi, rDe; \ - ORQ rBo, rDe; \ - XORQ rBe, rDe; \ - MOVQ rDe, _se(oState); \ - S_RDE_RCE; \ - \ - MOVQ rBo, rDi; \ - MOVQ rBu, rDo; \ - ANDQ rBu, rDi; \ - ORQ rBa, rDo; \ - XORQ rBi, rDi; \ - XORQ rBo, rDo; \ - MOVQ rDi, _si(oState); \ - MOVQ rDo, _so(oState) \ - -// func keccakF1600(state *[25]uint64) -TEXT ·keccakF1600(SB), 0, $200-8 - MOVQ state+0(FP), rpState - - // Convert the user state into an internal state - NOTQ _be(rpState) - NOTQ _bi(rpState) - NOTQ _go(rpState) - NOTQ _ki(rpState) - NOTQ _mi(rpState) - NOTQ _sa(rpState) - - // Execute the KeccakF permutation - MOVQ _ba(rpState), rCa - MOVQ _be(rpState), rCe - MOVQ _bu(rpState), rCu - - XORQ _ga(rpState), rCa - XORQ _ge(rpState), rCe - XORQ _gu(rpState), rCu - - XORQ _ka(rpState), rCa - XORQ _ke(rpState), rCe - XORQ _ku(rpState), rCu - - XORQ _ma(rpState), rCa - XORQ _me(rpState), rCe - XORQ _mu(rpState), rCu - - XORQ _sa(rpState), rCa - XORQ _se(rpState), rCe - MOVQ _si(rpState), rDi - MOVQ _so(rpState), rDo - XORQ _su(rpState), rCu - - mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) - - // Revert the internal state to the user state - NOTQ _be(rpState) - NOTQ _bi(rpState) - NOTQ _go(rpState) - NOTQ _ki(rpState) - NOTQ _mi(rpState) - NOTQ _sa(rpState) - - RET diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/register.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/register.go deleted file mode 100644 index 3cf6a22e..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/register.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.4 - -package sha3 - -import ( - "crypto" -) - -func init() { - crypto.RegisterHash(crypto.SHA3_224, New224) - crypto.RegisterHash(crypto.SHA3_256, New256) - crypto.RegisterHash(crypto.SHA3_384, New384) - crypto.RegisterHash(crypto.SHA3_512, New512) -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go deleted file mode 100644 index b12a35c8..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// spongeDirection indicates the direction bytes are flowing through the sponge. -type spongeDirection int - -const ( - // spongeAbsorbing indicates that the sponge is absorbing input. - spongeAbsorbing spongeDirection = iota - // spongeSqueezing indicates that the sponge is being squeezed. - spongeSqueezing -) - -const ( - // maxRate is the maximum size of the internal buffer. SHAKE-256 - // currently needs the largest buffer. - maxRate = 168 -) - -type state struct { - // Generic sponge components. - a [25]uint64 // main state of the hash - buf []byte // points into storage - rate int // the number of bytes of state to use - - // dsbyte contains the "domain separation" bits and the first bit of - // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the - // SHA-3 and SHAKE functions by appending bitstrings to the message. - // Using a little-endian bit-ordering convention, these are "01" for SHA-3 - // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the - // padding rule from section 5.1 is applied to pad the message to a multiple - // of the rate, which involves adding a "1" bit, zero or more "0" bits, and - // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, - // giving 00000110b (0x06) and 00011111b (0x1f). - // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf - // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and - // Extendable-Output Functions (May 2014)" - dsbyte byte - storage [maxRate]byte - - // Specific to SHA-3 and SHAKE. - outputLen int // the default output size in bytes - state spongeDirection // whether the sponge is absorbing or squeezing -} - -// BlockSize returns the rate of sponge underlying this hash function. -func (d *state) BlockSize() int { return d.rate } - -// Size returns the output size of the hash function in bytes. -func (d *state) Size() int { return d.outputLen } - -// Reset clears the internal state by zeroing the sponge state and -// the byte buffer, and setting Sponge.state to absorbing. -func (d *state) Reset() { - // Zero the permutation's state. - for i := range d.a { - d.a[i] = 0 - } - d.state = spongeAbsorbing - d.buf = d.storage[:0] -} - -func (d *state) clone() *state { - ret := *d - if ret.state == spongeAbsorbing { - ret.buf = ret.storage[:len(ret.buf)] - } else { - ret.buf = ret.storage[d.rate-cap(d.buf) : d.rate] - } - - return &ret -} - -// permute applies the KeccakF-1600 permutation. It handles -// any input-output buffering. -func (d *state) permute() { - switch d.state { - case spongeAbsorbing: - // If we're absorbing, we need to xor the input into the state - // before applying the permutation. - xorIn(d, d.buf) - d.buf = d.storage[:0] - keccakF1600(&d.a) - case spongeSqueezing: - // If we're squeezing, we need to apply the permutatin before - // copying more output. - keccakF1600(&d.a) - d.buf = d.storage[:d.rate] - copyOut(d, d.buf) - } -} - -// pads appends the domain separation bits in dsbyte, applies -// the multi-bitrate 10..1 padding rule, and permutes the state. -func (d *state) padAndPermute(dsbyte byte) { - if d.buf == nil { - d.buf = d.storage[:0] - } - // Pad with this instance's domain-separator bits. We know that there's - // at least one byte of space in d.buf because, if it were full, - // permute would have been called to empty it. dsbyte also contains the - // first one bit for the padding. See the comment in the state struct. - d.buf = append(d.buf, dsbyte) - zerosStart := len(d.buf) - d.buf = d.storage[:d.rate] - for i := zerosStart; i < d.rate; i++ { - d.buf[i] = 0 - } - // This adds the final one bit for the padding. Because of the way that - // bits are numbered from the LSB upwards, the final bit is the MSB of - // the last byte. - d.buf[d.rate-1] ^= 0x80 - // Apply the permutation - d.permute() - d.state = spongeSqueezing - d.buf = d.storage[:d.rate] - copyOut(d, d.buf) -} - -// Write absorbs more data into the hash's state. It produces an error -// if more data is written to the ShakeHash after writing -func (d *state) Write(p []byte) (written int, err error) { - if d.state != spongeAbsorbing { - panic("sha3: write to sponge after read") - } - if d.buf == nil { - d.buf = d.storage[:0] - } - written = len(p) - - for len(p) > 0 { - if len(d.buf) == 0 && len(p) >= d.rate { - // The fast path; absorb a full "rate" bytes of input and apply the permutation. - xorIn(d, p[:d.rate]) - p = p[d.rate:] - keccakF1600(&d.a) - } else { - // The slow path; buffer the input until we can fill the sponge, and then xor it in. - todo := d.rate - len(d.buf) - if todo > len(p) { - todo = len(p) - } - d.buf = append(d.buf, p[:todo]...) - p = p[todo:] - - // If the sponge is full, apply the permutation. - if len(d.buf) == d.rate { - d.permute() - } - } - } - - return -} - -// Read squeezes an arbitrary number of bytes from the sponge. -func (d *state) Read(out []byte) (n int, err error) { - // If we're still absorbing, pad and apply the permutation. - if d.state == spongeAbsorbing { - d.padAndPermute(d.dsbyte) - } - - n = len(out) - - // Now, do the squeezing. - for len(out) > 0 { - n := copy(out, d.buf) - d.buf = d.buf[n:] - out = out[n:] - - // Apply the permutation if we've squeezed the sponge dry. - if len(d.buf) == 0 { - d.permute() - } - } - - return -} - -// Sum applies padding to the hash state and then squeezes out the desired -// number of output bytes. -func (d *state) Sum(in []byte) []byte { - // Make a copy of the original hash so that caller can keep writing - // and summing. - dup := d.clone() - hash := make([]byte, dup.outputLen) - dup.Read(hash) - return append(in, hash...) -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3_test.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3_test.go deleted file mode 100644 index 0e33676c..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/sha3_test.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// Tests include all the ShortMsgKATs provided by the Keccak team at -// https://github.com/gvanas/KeccakCodePackage -// -// They only include the zero-bit case of the bitwise testvectors -// published by NIST in the draft of FIPS-202. - -import ( - "bytes" - "compress/flate" - "encoding/hex" - "encoding/json" - "hash" - "os" - "strings" - "testing" -) - -const ( - testString = "brekeccakkeccak koax koax" - katFilename = "testdata/keccakKats.json.deflate" -) - -// Internal-use instances of SHAKE used to test against KATs. -func newHashShake128() hash.Hash { - return &state{rate: 168, dsbyte: 0x1f, outputLen: 512} -} -func newHashShake256() hash.Hash { - return &state{rate: 136, dsbyte: 0x1f, outputLen: 512} -} - -// testDigests contains functions returning hash.Hash instances -// with output-length equal to the KAT length for both SHA-3 and -// SHAKE instances. -var testDigests = map[string]func() hash.Hash{ - "SHA3-224": New224, - "SHA3-256": New256, - "SHA3-384": New384, - "SHA3-512": New512, - "SHAKE128": newHashShake128, - "SHAKE256": newHashShake256, -} - -// testShakes contains functions that return ShakeHash instances for -// testing the ShakeHash-specific interface. -var testShakes = map[string]func() ShakeHash{ - "SHAKE128": NewShake128, - "SHAKE256": NewShake256, -} - -// structs used to marshal JSON test-cases. -type KeccakKats struct { - Kats map[string][]struct { - Digest string `json:"digest"` - Length int64 `json:"length"` - Message string `json:"message"` - } -} - -func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) { - xorInOrig, copyOutOrig := xorIn, copyOut - xorIn, copyOut = xorInGeneric, copyOutGeneric - testf("generic") - if xorImplementationUnaligned != "generic" { - xorIn, copyOut = xorInUnaligned, copyOutUnaligned - testf("unaligned") - } - xorIn, copyOut = xorInOrig, copyOutOrig -} - -// TestKeccakKats tests the SHA-3 and Shake implementations against all the -// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage -// (The testvectors are stored in keccakKats.json.deflate due to their length.) -func TestKeccakKats(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - // Read the KATs. - deflated, err := os.Open(katFilename) - if err != nil { - t.Errorf("error opening %s: %s", katFilename, err) - } - file := flate.NewReader(deflated) - dec := json.NewDecoder(file) - var katSet KeccakKats - err = dec.Decode(&katSet) - if err != nil { - t.Errorf("error decoding KATs: %s", err) - } - - // Do the KATs. - for functionName, kats := range katSet.Kats { - d := testDigests[functionName]() - for _, kat := range kats { - d.Reset() - in, err := hex.DecodeString(kat.Message) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - d.Write(in[:kat.Length/8]) - got := strings.ToUpper(hex.EncodeToString(d.Sum(nil))) - if got != kat.Digest { - t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s", - functionName, impl, kat.Length, kat.Message, got, kat.Digest) - t.Logf("wanted %+v", kat) - t.FailNow() - } - continue - } - } - }) -} - -// TestUnalignedWrite tests that writing data in an arbitrary pattern with -// small input buffers. -func TestUnalignedWrite(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - buf := sequentialBytes(0x10000) - for alg, df := range testDigests { - d := df() - d.Reset() - d.Write(buf) - want := d.Sum(nil) - d.Reset() - for i := 0; i < len(buf); { - // Cycle through offsets which make a 137 byte sequence. - // Because 137 is prime this sequence should exercise all corner cases. - offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1} - for _, j := range offsets { - if v := len(buf) - i; v < j { - j = v - } - d.Write(buf[i : i+j]) - i += j - } - } - got := d.Sum(nil) - if !bytes.Equal(got, want) { - t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want) - } - } - }) -} - -// TestAppend checks that appending works when reallocation is necessary. -func TestAppend(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - d := New224() - - for capacity := 2; capacity <= 66; capacity += 64 { - // The first time around the loop, Sum will have to reallocate. - // The second time, it will not. - buf := make([]byte, 2, capacity) - d.Reset() - d.Write([]byte{0xcc}) - buf = d.Sum(buf) - expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" - if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { - t.Errorf("got %s, want %s", got, expected) - } - } - }) -} - -// TestAppendNoRealloc tests that appending works when no reallocation is necessary. -func TestAppendNoRealloc(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - buf := make([]byte, 1, 200) - d := New224() - d.Write([]byte{0xcc}) - buf = d.Sum(buf) - expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" - if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { - t.Errorf("%s: got %s, want %s", impl, got, expected) - } - }) -} - -// TestSqueezing checks that squeezing the full output a single time produces -// the same output as repeatedly squeezing the instance. -func TestSqueezing(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - for functionName, newShakeHash := range testShakes { - d0 := newShakeHash() - d0.Write([]byte(testString)) - ref := make([]byte, 32) - d0.Read(ref) - - d1 := newShakeHash() - d1.Write([]byte(testString)) - var multiple []byte - for range ref { - one := make([]byte, 1) - d1.Read(one) - multiple = append(multiple, one...) - } - if !bytes.Equal(ref, multiple) { - t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref)) - } - } - }) -} - -// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing. -func sequentialBytes(size int) []byte { - result := make([]byte, size) - for i := range result { - result[i] = byte(i) - } - return result -} - -// BenchmarkPermutationFunction measures the speed of the permutation function -// with no input data. -func BenchmarkPermutationFunction(b *testing.B) { - b.SetBytes(int64(200)) - var lanes [25]uint64 - for i := 0; i < b.N; i++ { - keccakF1600(&lanes) - } -} - -// benchmarkHash tests the speed to hash num buffers of buflen each. -func benchmarkHash(b *testing.B, h hash.Hash, size, num int) { - b.StopTimer() - h.Reset() - data := sequentialBytes(size) - b.SetBytes(int64(size * num)) - b.StartTimer() - - var state []byte - for i := 0; i < b.N; i++ { - for j := 0; j < num; j++ { - h.Write(data) - } - state = h.Sum(state[:0]) - } - b.StopTimer() - h.Reset() -} - -// benchmarkShake is specialized to the Shake instances, which don't -// require a copy on reading output. -func benchmarkShake(b *testing.B, h ShakeHash, size, num int) { - b.StopTimer() - h.Reset() - data := sequentialBytes(size) - d := make([]byte, 32) - - b.SetBytes(int64(size * num)) - b.StartTimer() - - for i := 0; i < b.N; i++ { - h.Reset() - for j := 0; j < num; j++ { - h.Write(data) - } - h.Read(d) - } -} - -func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) } -func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) } -func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) } -func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) } - -func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) } -func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) } -func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) } -func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) } - -func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) } - -func Example_sum() { - buf := []byte("some data to hash") - // A hash needs to be 64 bytes long to have 256-bit collision resistance. - h := make([]byte, 64) - // Compute a 64-byte hash of buf and put it in h. - ShakeSum256(h, buf) -} - -func Example_mac() { - k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long") - buf := []byte("and this is some data to authenticate") - // A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key. - h := make([]byte, 32) - d := NewShake256() - // Write the key into the hash. - d.Write(k) - // Now write the data. - d.Write(buf) - // Read 32 bytes of output from the hash into h. - d.Read(h) -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/shake.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/shake.go deleted file mode 100644 index 841f9860..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/shake.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// This file defines the ShakeHash interface, and provides -// functions for creating SHAKE instances, as well as utility -// functions for hashing bytes to arbitrary-length output. - -import ( - "io" -) - -// ShakeHash defines the interface to hash functions that -// support arbitrary-length output. -type ShakeHash interface { - // Write absorbs more data into the hash's state. It panics if input is - // written to it after output has been read from it. - io.Writer - - // Read reads more output from the hash; reading affects the hash's - // state. (ShakeHash.Read is thus very different from Hash.Sum) - // It never returns an error. - io.Reader - - // Clone returns a copy of the ShakeHash in its current state. - Clone() ShakeHash - - // Reset resets the ShakeHash to its initial state. - Reset() -} - -func (d *state) Clone() ShakeHash { - return d.clone() -} - -// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. -// Its generic security strength is 128 bits against all attacks if at -// least 32 bytes of its output are used. -func NewShake128() ShakeHash { return &state{rate: 168, dsbyte: 0x1f} } - -// NewShake256 creates a new SHAKE128 variable-output-length ShakeHash. -// Its generic security strength is 256 bits against all attacks if -// at least 64 bytes of its output are used. -func NewShake256() ShakeHash { return &state{rate: 136, dsbyte: 0x1f} } - -// ShakeSum128 writes an arbitrary-length digest of data into hash. -func ShakeSum128(hash, data []byte) { - h := NewShake128() - h.Write(data) - h.Read(hash) -} - -// ShakeSum256 writes an arbitrary-length digest of data into hash. -func ShakeSum256(hash, data []byte) { - h := NewShake256() - h.Write(data) - h.Read(hash) -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/testdata/keccakKats.json.deflate b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/testdata/keccakKats.json.deflate deleted file mode 100644 index 62e85ae2..00000000 Binary files a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/testdata/keccakKats.json.deflate and /dev/null differ diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go deleted file mode 100644 index 46a0d63a..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64,!386,!ppc64le appengine - -package sha3 - -var ( - xorIn = xorInGeneric - copyOut = copyOutGeneric - xorInUnaligned = xorInGeneric - copyOutUnaligned = copyOutGeneric -) - -const xorImplementationUnaligned = "generic" diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_generic.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_generic.go deleted file mode 100644 index fd35f02e..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_generic.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -import "encoding/binary" - -// xorInGeneric xors the bytes in buf into the state; it -// makes no non-portable assumptions about memory layout -// or alignment. -func xorInGeneric(d *state, buf []byte) { - n := len(buf) / 8 - - for i := 0; i < n; i++ { - a := binary.LittleEndian.Uint64(buf) - d.a[i] ^= a - buf = buf[8:] - } -} - -// copyOutGeneric copies ulint64s to a byte buffer. -func copyOutGeneric(d *state, b []byte) { - for i := 0; len(b) >= 8; i++ { - binary.LittleEndian.PutUint64(b, d.a[i]) - b = b[8:] - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go b/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go deleted file mode 100644 index 929a486a..00000000 --- a/vendor/github.com/ethereum/go-ethereum/crypto/sha3/xor_unaligned.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64 386 ppc64le -// +build !appengine - -package sha3 - -import "unsafe" - -func xorInUnaligned(d *state, buf []byte) { - bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0])) - n := len(buf) - if n >= 72 { - d.a[0] ^= bw[0] - d.a[1] ^= bw[1] - d.a[2] ^= bw[2] - d.a[3] ^= bw[3] - d.a[4] ^= bw[4] - d.a[5] ^= bw[5] - d.a[6] ^= bw[6] - d.a[7] ^= bw[7] - d.a[8] ^= bw[8] - } - if n >= 104 { - d.a[9] ^= bw[9] - d.a[10] ^= bw[10] - d.a[11] ^= bw[11] - d.a[12] ^= bw[12] - } - if n >= 136 { - d.a[13] ^= bw[13] - d.a[14] ^= bw[14] - d.a[15] ^= bw[15] - d.a[16] ^= bw[16] - } - if n >= 144 { - d.a[17] ^= bw[17] - } - if n >= 168 { - d.a[18] ^= bw[18] - d.a[19] ^= bw[19] - d.a[20] ^= bw[20] - } -} - -func copyOutUnaligned(d *state, buf []byte) { - ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0])) - copy(buf, ab[:]) -} - -var ( - xorIn = xorInUnaligned - copyOut = copyOutUnaligned -) - -const xorImplementationUnaligned = "unaligned" diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/signature_cgo.go b/vendor/github.com/ethereum/go-ethereum/crypto/signature_cgo.go index 340bfc22..aadf028d 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/signature_cgo.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/signature_cgo.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build !nacl,!js,!nocgo +// +build !nacl,!js,cgo package crypto diff --git a/vendor/github.com/ethereum/go-ethereum/crypto/signature_nocgo.go b/vendor/github.com/ethereum/go-ethereum/crypto/signature_nocgo.go index e8fa18ed..90d072cd 100644 --- a/vendor/github.com/ethereum/go-ethereum/crypto/signature_nocgo.go +++ b/vendor/github.com/ethereum/go-ethereum/crypto/signature_nocgo.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build nacl js nocgo +// +build nacl js !cgo package crypto diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets.go b/vendor/github.com/ethereum/go-ethereum/dashboard/assets.go index f3e7cf98..1ce18b28 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets.go +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets.go @@ -2,6 +2,7 @@ // sources: // assets/index.html // assets/bundle.js +// assets/bundle.js.map package dashboard @@ -71,7 +72,7 @@ var _indexHtml = []byte(`
- + `) @@ -87,29936 +88,3379 @@ func indexHtml() (*asset, error) { } info := bindataFileInfo{name: "index.html", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x22, 0xc8, 0x3d, 0x86, 0x2f, 0xb4, 0x6a, 0x1f, 0xda, 0xd, 0x54, 0x14, 0xa3, 0x6e, 0x80, 0x56, 0x28, 0xea, 0x44, 0xcf, 0xf5, 0xf2, 0xe, 0xad, 0x19, 0xf5, 0x93, 0xd6, 0x8d, 0x6d, 0x2f, 0x35}} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6a, 0xe4, 0x19, 0xb4, 0xf4, 0x89, 0xd3, 0x51, 0xa8, 0xde, 0x87, 0x57, 0x96, 0x17, 0x3f, 0x43, 0xa6, 0xa0, 0x7a, 0x6f, 0xba, 0xeb, 0x27, 0xcf, 0x41, 0x28, 0x6e, 0x85, 0x91, 0xa6, 0x48, 0xcf}} return a, nil } //nolint:misspell -var _bundleJs = []byte((((((((((`!function(modules) { - function __webpack_require__(moduleId) { - if (installedModules[moduleId]) return installedModules[moduleId].exports; - var module = installedModules[moduleId] = { - i: moduleId, +var _bundleJs = []byte((((`!function(e) { + var t = {}; + function n(r) { + if (t[r]) return t[r].exports; + var o = t[r] = { + i: r, l: !1, exports: {} }; - return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), - module.l = !0, module.exports; + return e[r].call(o.exports, o, o.exports, n), o.l = !0, o.exports; } - var installedModules = {}; - __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = function(exports, name, getter) { - __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { - configurable: !1, + n.m = e, n.c = t, n.d = function(e, t, r) { + n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, - get: getter + get: r }); - }, __webpack_require__.n = function(module) { - var getter = module && module.__esModule ? function() { - return module.default; + }, n.r = function(e) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { + value: "Module" + }), Object.defineProperty(e, "__esModule", { + value: !0 + }); + }, n.t = function(e, t) { + if (1 & t && (e = n(e)), 8 & t) return e; + if (4 & t && "object" == typeof e && e && e.__esModule) return e; + var r = Object.create(null); + if (n.r(r), Object.defineProperty(r, "default", { + enumerable: !0, + value: e + }), 2 & t && "string" != typeof e) for (var o in e) n.d(r, o, function(t) { + return e[t]; + }.bind(null, o)); + return r; + }, n.n = function(e) { + var t = e && e.__esModule ? function() { + return e.default; } : function() { - return module; + return e; }; - return __webpack_require__.d(getter, "a", getter), getter; - }, __webpack_require__.o = function(object, property) { - return Object.prototype.hasOwnProperty.call(object, property); - }, __webpack_require__.p = "", __webpack_require__(__webpack_require__.s = 375); -}([ function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - "production" === process.env.NODE_ENV ? module.exports = __webpack_require__(376) : module.exports = __webpack_require__(377); - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - (function(process) { - if ("production" !== process.env.NODE_ENV) { - var REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103, isValidElement = function(object) { - return "object" == typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE; - }; - module.exports = __webpack_require__(418)(isValidElement, !0); - } else module.exports = __webpack_require__(419)(); - }).call(exports, __webpack_require__(2)); -}, function(module, exports) { - function defaultSetTimout() { - throw new Error("setTimeout has not been defined"); - } - function defaultClearTimeout() { - throw new Error("clearTimeout has not been defined"); - } - function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) return setTimeout(fun, 0); - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) return cachedSetTimeout = setTimeout, - setTimeout(fun, 0); - try { - return cachedSetTimeout(fun, 0); - } catch (e) { - try { - return cachedSetTimeout.call(null, fun, 0); - } catch (e) { - return cachedSetTimeout.call(this, fun, 0); - } - } - } - function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) return clearTimeout(marker); - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) return cachedClearTimeout = clearTimeout, - clearTimeout(marker); - try { - return cachedClearTimeout(marker); - } catch (e) { - try { - return cachedClearTimeout.call(null, marker); - } catch (e) { - return cachedClearTimeout.call(this, marker); - } - } - } - function cleanUpNextTick() { - draining && currentQueue && (draining = !1, currentQueue.length ? queue = currentQueue.concat(queue) : queueIndex = -1, - queue.length && drainQueue()); - } - function drainQueue() { - if (!draining) { - var timeout = runTimeout(cleanUpNextTick); - draining = !0; - for (var len = queue.length; len; ) { - for (currentQueue = queue, queue = []; ++queueIndex < len; ) currentQueue && currentQueue[queueIndex].run(); - queueIndex = -1, len = queue.length; - } - currentQueue = null, draining = !1, runClearTimeout(timeout); - } - } - function Item(fun, array) { - this.fun = fun, this.array = array; - } - function noop() {} - var cachedSetTimeout, cachedClearTimeout, process = module.exports = {}; - !function() { - try { - cachedSetTimeout = "function" == typeof setTimeout ? setTimeout : defaultSetTimout; - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - cachedClearTimeout = "function" == typeof clearTimeout ? clearTimeout : defaultClearTimeout; - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } - }(); - var currentQueue, queue = [], draining = !1, queueIndex = -1; - process.nextTick = function(fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) for (var i = 1; i < arguments.length; i++) args[i - 1] = arguments[i]; - queue.push(new Item(fun, args)), 1 !== queue.length || draining || runTimeout(drainQueue); - }, Item.prototype.run = function() { - this.fun.apply(null, this.array); - }, process.title = "browser", process.browser = !0, process.env = {}, process.argv = [], - process.version = "", process.versions = {}, process.on = noop, process.addListener = noop, - process.once = noop, process.off = noop, process.removeListener = noop, process.removeAllListeners = noop, - process.emit = noop, process.prependListener = noop, process.prependOnceListener = noop, - process.listeners = function(name) { - return []; - }, process.binding = function(name) { - throw new Error("process.binding is not supported"); - }, process.cwd = function() { - return "/"; - }, process.chdir = function(dir) { - throw new Error("process.chdir is not supported"); - }, process.umask = function() { - return 0; - }; -}, function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; - !function() { + return n.d(t, "a", t), t; + }, n.o = function(e, t) { + return Object.prototype.hasOwnProperty.call(e, t); + }, n.p = "", n(n.s = "./index.jsx"); +}({ + "./common.jsx": function(e, t, n) { "use strict"; - function classNames() { - for (var classes = [], i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - if (arg) { - var argType = typeof arg; - if ("string" === argType || "number" === argType) classes.push(arg); else if (Array.isArray(arg)) classes.push(classNames.apply(null, arg)); else if ("object" === argType) for (var key in arg) hasOwn.call(arg, key) && arg[key] && classes.push(key); + (function(e) { + n.d(t, "b", function() { + return d; + }), n.d(t, "a", function() { + return f; + }), n.d(t, "c", function() { + return p; + }), n.d(t, "g", function() { + return h; + }), n.d(t, "f", function() { + return m; + }), n.d(t, "e", function() { + return y; + }), n.d(t, "d", function() { + return b; + }); + var r, o = n("./node_modules/@fortawesome/free-solid-svg-icons/index.es.js"), a = n("./node_modules/@fortawesome/free-regular-svg-icons/index.es.js"); + function i(e) { + for (var t = 1; t < arguments.length; t++) { + var n = null != arguments[t] ? arguments[t] : {}, r = Object.keys(n); + "function" == typeof Object.getOwnPropertySymbols && (r = r.concat(Object.getOwnPropertySymbols(n).filter(function(e) { + return Object.getOwnPropertyDescriptor(n, e).enumerable; + }))), r.forEach(function(t) { + s(e, t, n[t]); + }); + } + return e; + } + function s(e, t, n) { + return t in e ? Object.defineProperty(e, t, { + value: n, + enumerable: !0, + configurable: !0, + writable: !0 + }) : e[t] = n, e; + } + (r = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : n("./node_modules/react-hot-loader/index.js")).enterModule) && r(e); + var l, u, c = [ { + id: "home", + menu: { + title: "Home", + icon: o.d + } + }, { + id: "chain", + menu: { + title: "Chain", + icon: o.e + } + }, { + id: "txpool", + menu: { + title: "TxPool", + icon: a.b + } + }, { + id: "network", + menu: { + title: "Network", + icon: o.c + } + }, { + id: "system", + menu: { + title: "System", + icon: o.g + } + }, { + id: "logs", + menu: { + title: "Logs", + icon: o.f + } + } ], d = new Map(c.map(function(e) { + var t = e.id; + return [ t, i({ + id: t + }, e.menu) ]; + })), f = 200, p = .2, h = { + light: { + color: "rgba(255, 255, 255, 0.54)" + } + }, _ = [ "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" ], m = function(e) { + for (var t = 0; e > 1024 && t < 8; t++) e /= 1024; + return e.toFixed(2).toString().concat(" ", _[t], "B"); + }, y = [ "#00FF00", "#FFFF00", "#FF7F00", "#FF0000" ], b = [ 0, 2048, 102400, 2097152 ]; + (l = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : n("./node_modules/react-hot-loader/index.js")).default) && (l.register(c, "menuSkeletons", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(d, "MENU", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(f, "DURATION", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(p, "chartStrokeWidth", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(h, "styles", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(_, "unit", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(m, "simplifyBytes", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(y, "hues", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx"), + l.register(b, "hueScale", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx")), + (u = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : n("./node_modules/react-hot-loader/index.js")).leaveModule) && u(e); + }).call(this, n("./node_modules/webpack/buildin/harmony-module.js")(e)); + }, + "./components/Body.jsx": function(module, __webpack_exports__, __webpack_require__) { + "use strict"; + (function(module) { + var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/react/index.js"), react__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__), _SideBar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./components/SideBar.jsx"), _Main__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./components/Main.jsx"), enterModule; + function _typeof(e) { + return (_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { + return typeof e; + } : function(e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e; + })(e); + } + function _classCallCheck(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); + } + function _defineProperties(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), + Object.defineProperty(e, r.key, r); } } - return classes.join(" "); - } - var hasOwn = {}.hasOwnProperty; - void 0 !== module && module.exports ? module.exports = classNames : (__WEBPACK_AMD_DEFINE_ARRAY__ = [], - void 0 !== (__WEBPACK_AMD_DEFINE_RESULT__ = function() { - return classNames; - }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - }(); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _toConsumableArray(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - return arr2; - } - return Array.from(arr); - } - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - __webpack_require__.d(__webpack_exports__, "c", function() { - return PRESENTATION_ATTRIBUTES; - }), __webpack_require__.d(__webpack_exports__, "a", function() { - return EVENT_ATTRIBUTES; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return SCALE_TYPES; - }), __webpack_require__.d(__webpack_exports__, "b", function() { - return LEGEND_TYPES; - }), __webpack_require__.d(__webpack_exports__, "j", function() { - return getDisplayName; - }), __webpack_require__.d(__webpack_exports__, "h", function() { - return findAllByType; - }), __webpack_require__.d(__webpack_exports__, "i", function() { - return findChildByType; - }), __webpack_require__.d(__webpack_exports__, "k", function() { - return getPresentationAttributes; - }), __webpack_require__.d(__webpack_exports__, "e", function() { - return filterEventAttributes; - }), __webpack_require__.d(__webpack_exports__, "f", function() { - return filterEventsOfChild; - }), __webpack_require__.d(__webpack_exports__, "q", function() { - return validateWidthHeight; - }), __webpack_require__.d(__webpack_exports__, "n", function() { - return isSsr; - }), __webpack_require__.d(__webpack_exports__, "g", function() { - return filterSvgElements; - }), __webpack_require__.d(__webpack_exports__, "m", function() { - return isChildrenEqual; - }), __webpack_require__.d(__webpack_exports__, "p", function() { - return renderByOrder; - }), __webpack_require__.d(__webpack_exports__, "l", function() { - return getReactEventByType; - }), __webpack_require__.d(__webpack_exports__, "o", function() { - return parseChildIndex; - }); - var __WEBPACK_IMPORTED_MODULE_0_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_1_lodash_isString__ = __webpack_require__(173), __WEBPACK_IMPORTED_MODULE_1_lodash_isString___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isString__), __WEBPACK_IMPORTED_MODULE_2_lodash_isObject__ = __webpack_require__(32), __WEBPACK_IMPORTED_MODULE_2_lodash_isObject___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isObject__), __WEBPACK_IMPORTED_MODULE_3_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_3_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_4_lodash_isArray__ = __webpack_require__(13), __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_5_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_5_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_react__), __WEBPACK_IMPORTED_MODULE_6_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_6_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6_prop_types__), __WEBPACK_IMPORTED_MODULE_7__DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_8__PureRender__ = __webpack_require__(5), PRESENTATION_ATTRIBUTES = { - alignmentBaseline: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - angle: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - baselineShift: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - clip: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - clipPath: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - clipRule: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - color: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - colorInterpolation: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - colorInterpolationFilters: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - colorProfile: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - colorRendering: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - cursor: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - direction: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "ltr", "rtl", "inherit" ]), - display: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - dominantBaseline: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - enableBackground: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - fill: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - fillOpacity: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number ]), - fillRule: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "nonzero", "evenodd", "inherit" ]), - filter: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - floodColor: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - floodOpacity: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number ]), - font: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - fontFamily: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - fontSize: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - fontSizeAdjust: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - fontStretch: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "normal", "wider", "narrower", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded", "inherit" ]), - fontStyle: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "normal", "italic", "oblique", "inherit" ]), - fontVariant: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "normal", "small-caps", "inherit" ]), - fontWeight: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "normal", "bold", "bolder", "lighter", 100, 200, 300, 400, 500, 600, 700, 800, 900, "inherit" ]), - glyphOrientationHorizontal: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - glyphOrientationVertical: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - imageRendering: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "auto", "optimizeSpeed", "optimizeQuality", "inherit" ]), - kerning: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - letterSpacing: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - lightingColor: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - markerEnd: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - markerMid: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - markerStart: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - mask: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - opacity: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - overflow: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "visible", "hidden", "scroll", "auto", "inherit" ]), - pointerEvents: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "visiblePainted", "visibleFill", "visibleStroke", "visible", "painted", "fill", "stroke", "all", "none", "inherit" ]), - shapeRendering: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "auto", "optimizeSpeed", "crispEdges", "geometricPrecision", "inherit" ]), - stopColor: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - stopOpacity: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - stroke: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - strokeDasharray: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - strokeDashoffset: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - strokeLinecap: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "butt", "round", "square", "inherit" ]), - strokeLinejoin: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "miter", "round", "bevel", "inherit" ]), - strokeMiterlimit: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - strokeOpacity: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - strokeWidth: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - textAnchor: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "start", "middle", "end", "inherit" ]), - textDecoration: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "none", "underline", "overline", "line-through", "blink", "inherit" ]), - textRendering: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision", "inherit" ]), - unicodeBidi: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "normal", "embed", "bidi-override", "inherit" ]), - visibility: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "visible", "hidden", "collapse", "inherit" ]), - wordSpacing: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - writingMode: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "lr-tb", "rl-tb", "tb-rl", "lr", "rl", "tb", "inherit" ]), - transform: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - style: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.object, - width: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - dx: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - dy: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - x: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - y: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - r: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - radius: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.array ]) - }, EVENT_ATTRIBUTES = { - onClick: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseDown: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseUp: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseOver: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseMove: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseOut: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseEnter: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseLeave: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onTouchEnd: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onTouchMove: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onTouchStart: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onTouchCancel: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func - }, REACT_BROWSER_EVENT_MAP = { - click: "onClick", - mousedown: "onMouseDown", - mouseup: "onMouseUp", - mouseover: "onMouseOver", - mousemove: "onMouseMove", - mouseout: "onMouseOut", - mouseenter: "onMouseEnter", - mouseleave: "onMouseLeave", - touchcancel: "onTouchCancel", - touchend: "onTouchEnd", - touchmove: "onTouchMove", - touchstart: "onTouchStart" - }, SCALE_TYPES = [ "auto", "linear", "pow", "sqrt", "log", "identity", "time", "band", "point", "ordinal", "quantile", "quantize", "utcTime", "sequential", "threshold" ], LEGEND_TYPES = [ "plainline", "line", "square", "rect", "circle", "cross", "diamond", "star", "triangle", "wye", "none" ], getDisplayName = function(Comp) { - return Comp ? "string" == typeof Comp ? Comp : Comp.displayName || Comp.name || "Component" : ""; - }, findAllByType = function(children, type) { - var result = [], types = []; - return types = __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(type) ? type.map(function(t) { - return getDisplayName(t); - }) : [ getDisplayName(type) ], __WEBPACK_IMPORTED_MODULE_5_react___default.a.Children.forEach(children, function(child) { - var childType = child && child.type && (child.type.displayName || child.type.name); - -1 !== types.indexOf(childType) && result.push(child); - }), result; - }, findChildByType = function(children, type) { - var result = findAllByType(children, type); - return result && result[0]; - }, getPresentationAttributes = function(el) { - if (!el || __WEBPACK_IMPORTED_MODULE_3_lodash_isFunction___default()(el)) return null; - var props = __WEBPACK_IMPORTED_MODULE_5_react___default.a.isValidElement(el) ? el.props : el; - if (!__WEBPACK_IMPORTED_MODULE_2_lodash_isObject___default()(props)) return null; - var out = null; - for (var i in props) ({}).hasOwnProperty.call(props, i) && PRESENTATION_ATTRIBUTES[i] && (out || (out = {}), - out[i] = props[i]); - return out; - }, getEventHandlerOfElement = function(originalHandler, props) { - return function(e) { - return originalHandler(props, e), null; - }; - }, filterEventAttributes = function(el, newHandler) { - var wrapCallback = arguments.length > 2 && void 0 !== arguments[2] && arguments[2]; - if (!el || __WEBPACK_IMPORTED_MODULE_3_lodash_isFunction___default()(el)) return null; - var props = __WEBPACK_IMPORTED_MODULE_5_react___default.a.isValidElement(el) ? el.props : el; - if (!__WEBPACK_IMPORTED_MODULE_2_lodash_isObject___default()(props)) return null; - var out = null; - for (var i in props) ({}).hasOwnProperty.call(props, i) && EVENT_ATTRIBUTES[i] && (out || (out = {}), - out[i] = newHandler || (wrapCallback ? getEventHandlerOfElement(props[i], props) : props[i])); - return out; - }, getEventHandlerOfChild = function(originalHandler, data, index) { - return function(e) { - return originalHandler(data, index, e), null; - }; - }, filterEventsOfChild = function(props, data, index) { - if (!__WEBPACK_IMPORTED_MODULE_2_lodash_isObject___default()(props)) return null; - var out = null; - for (var i in props) ({}).hasOwnProperty.call(props, i) && EVENT_ATTRIBUTES[i] && __WEBPACK_IMPORTED_MODULE_3_lodash_isFunction___default()(props[i]) && (out || (out = {}), - out[i] = getEventHandlerOfChild(props[i], data, index)); - return out; - }, validateWidthHeight = function(el) { - if (!el || !el.props) return !1; - var _el$props = el.props, width = _el$props.width, height = _el$props.height; - return !(!Object(__WEBPACK_IMPORTED_MODULE_7__DataUtils__.h)(width) || width <= 0 || !Object(__WEBPACK_IMPORTED_MODULE_7__DataUtils__.h)(height) || height <= 0); - }, isSsr = function() { - return !("undefined" != typeof window && window.document && window.document.createElement && window.setTimeout); - }, SVG_TAGS = [ "a", "altGlyph", "altGlyphDef", "altGlyphItem", "animate", "animateColor", "animateMotion", "animateTransform", "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "ellipse", "feBlend", "feColormatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "font", "font-face", "font-face-format", "font-face-name", "font-face-url", "foreignObject", "g", "glyph", "glyphRef", "hkern", "image", "line", "lineGradient", "marker", "mask", "metadata", "missing-glyph", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "script", "set", "stop", "style", "svg", "switch", "symbol", "text", "textPath", "title", "tref", "tspan", "use", "view", "vkern" ], isSvgElement = function(child) { - return child && child.type && __WEBPACK_IMPORTED_MODULE_1_lodash_isString___default()(child.type) && SVG_TAGS.indexOf(child.type) >= 0; - }, filterSvgElements = function(children) { - var svgElements = []; - return __WEBPACK_IMPORTED_MODULE_5_react___default.a.Children.forEach(children, function(entry) { - entry && entry.type && __WEBPACK_IMPORTED_MODULE_1_lodash_isString___default()(entry.type) && SVG_TAGS.indexOf(entry.type) >= 0 && svgElements.push(entry); - }), svgElements; - }, isSingleChildEqual = function(nextChild, prevChild) { - if (__WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(nextChild) && __WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(prevChild)) return !0; - if (!__WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(nextChild) && !__WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(prevChild)) { - var _ref = nextChild.props || {}, nextChildren = _ref.children, nextProps = _objectWithoutProperties(_ref, [ "children" ]), _ref2 = prevChild.props || {}, prevChildren = _ref2.children, prevProps = _objectWithoutProperties(_ref2, [ "children" ]); - return nextChildren && prevChildren ? Object(__WEBPACK_IMPORTED_MODULE_8__PureRender__.b)(nextProps, prevProps) && isChildrenEqual(nextChildren, prevChildren) : !nextChildren && !prevChildren && Object(__WEBPACK_IMPORTED_MODULE_8__PureRender__.b)(nextProps, prevProps); - } - return !1; - }, isChildrenEqual = function isChildrenEqual(nextChildren, prevChildren) { - if (nextChildren === prevChildren) return !0; - if (__WEBPACK_IMPORTED_MODULE_5_react__.Children.count(nextChildren) !== __WEBPACK_IMPORTED_MODULE_5_react__.Children.count(prevChildren)) return !1; - var count = __WEBPACK_IMPORTED_MODULE_5_react__.Children.count(nextChildren); - if (0 === count) return !0; - if (1 === count) return isSingleChildEqual(__WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(nextChildren) ? nextChildren[0] : nextChildren, __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(prevChildren) ? prevChildren[0] : prevChildren); - for (var i = 0; i < count; i++) { - var nextChild = nextChildren[i], prevChild = prevChildren[i]; - if (__WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(nextChild) || __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(prevChild)) { - if (!isChildrenEqual(nextChild, prevChild)) return !1; - } else if (!isSingleChildEqual(nextChild, prevChild)) return !1; - } - return !0; - }, renderByOrder = function(children, renderMap) { - var elements = [], record = {}; - return __WEBPACK_IMPORTED_MODULE_5_react__.Children.forEach(children, function(child, index) { - if (child && isSvgElement(child)) elements.push(child); else if (child && renderMap[getDisplayName(child.type)]) { - var displayName = getDisplayName(child.type), _renderMap$displayNam = renderMap[displayName], handler = _renderMap$displayNam.handler, once = _renderMap$displayNam.once; - if (once && !record[displayName] || !once) { - var results = handler(child, displayName, index); - __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(results) ? elements = [ elements ].concat(_toConsumableArray(results)) : elements.push(results), - record[displayName] = !0; + function _createClass(e, t, n) { + return t && _defineProperties(e.prototype, t), n && _defineProperties(e, n), e; + } + function _possibleConstructorReturn(e, t) { + return !t || "object" !== _typeof(t) && "function" != typeof t ? _assertThisInitialized(e) : t; + } + function _assertThisInitialized(e) { + if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + return e; + } + function _getPrototypeOf(e) { + return (_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function(e) { + return e.__proto__ || Object.getPrototypeOf(e); + })(e); + } + function _inherits(e, t) { + if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); + e.prototype = Object.create(t && t.prototype, { + constructor: { + value: e, + writable: !0, + configurable: !0 + } + }), t && _setPrototypeOf(e, t); + } + function _setPrototypeOf(e, t) { + return (_setPrototypeOf = Object.setPrototypeOf || function(e, t) { + return e.__proto__ = t, e; + })(e, t); + } + enterModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).enterModule, + enterModule && enterModule(module); + var styles = { + body: { + display: "flex", + width: "100%", + height: "92%" + } + }, Body = function(_Component) { + function Body() { + return _classCallCheck(this, Body), _possibleConstructorReturn(this, _getPrototypeOf(Body).apply(this, arguments)); + } + return _inherits(Body, _Component), _createClass(Body, [ { + key: "render", + value: function() { + return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", { + style: styles.body + }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_SideBar__WEBPACK_IMPORTED_MODULE_1__.a, { + opened: this.props.opened, + changeContent: this.props.changeContent + }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Main__WEBPACK_IMPORTED_MODULE_2__.a, { + active: this.props.active, + content: this.props.content, + shouldUpdate: this.props.shouldUpdate, + send: this.props.send + })); + } + }, { + key: "__reactstandin__regenerateByEval", + value: function __reactstandin__regenerateByEval(key, code) { + this[key] = eval(code); + } + } ]), Body; + }(react__WEBPACK_IMPORTED_MODULE_0__.Component), _default = Body, reactHotLoader, leaveModule; + __webpack_exports__.a = _default, reactHotLoader = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).default, + reactHotLoader && (reactHotLoader.register(styles, "styles", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/Body.jsx"), + reactHotLoader.register(Body, "Body", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/Body.jsx"), + reactHotLoader.register(_default, "default", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/Body.jsx")), + leaveModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).leaveModule, + leaveModule && leaveModule(module); + }).call(this, __webpack_require__("./node_modules/webpack/buildin/harmony-module.js")(module)); + }, + "./components/ChartRow.jsx": function(module, __webpack_exports__, __webpack_require__) { + "use strict"; + (function(module) { + var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/react/index.js"), react__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__), _material_ui_core_Grid__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./node_modules/@material-ui/core/Grid/index.js"), _material_ui_core_Grid__WEBPACK_IMPORTED_MODULE_1___default = __webpack_require__.n(_material_ui_core_Grid__WEBPACK_IMPORTED_MODULE_1__), enterModule; + function _typeof(e) { + return (_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { + return typeof e; + } : function(e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e; + })(e); + } + function _classCallCheck(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); + } + function _defineProperties(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), + Object.defineProperty(e, r.key, r); } } - }), elements; - }, getReactEventByType = function(e) { - var type = e && e.type; - return type && REACT_BROWSER_EVENT_MAP[type] ? REACT_BROWSER_EVENT_MAP[type] : null; - }, parseChildIndex = function(child, children) { - var result = -1; - return __WEBPACK_IMPORTED_MODULE_5_react__.Children.forEach(children, function(entry, index) { - entry === child && (result = index); - }), result; - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function shallowEqual(a, b) { - for (var key in a) if ({}.hasOwnProperty.call(a, key) && (!{}.hasOwnProperty.call(b, key) || a[key] !== b[key])) return !1; - for (var _key in b) if ({}.hasOwnProperty.call(b, _key) && !{}.hasOwnProperty.call(a, _key)) return !1; - return !0; - } - function shouldComponentUpdate(props, state) { - return !shallowEqual(props, this.props) || !shallowEqual(state, this.state); - } - function pureRenderDecorator(component) { - component.prototype.shouldComponentUpdate = shouldComponentUpdate; - } - __webpack_exports__.b = shallowEqual, __webpack_exports__.a = pureRenderDecorator; -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0; - var _assign = __webpack_require__(222), _assign2 = function(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - }(_assign); - exports.default = _assign2.default || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0, exports.default = function(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - }; -}, function(module, exports, __webpack_require__) { - function isFunction(value) { - if (!isObject(value)) return !1; - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; - } - var baseGetTag = __webpack_require__(41), isObject = __webpack_require__(32), asyncTag = "[object AsyncFunction]", funcTag = "[object Function]", genTag = "[object GeneratorFunction]", proxyTag = "[object Proxy]"; - module.exports = isFunction; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_require__.d(__webpack_exports__, "j", function() { - return mathSign; - }), __webpack_require__.d(__webpack_exports__, "i", function() { - return isPercent; - }), __webpack_require__.d(__webpack_exports__, "h", function() { - return isNumber; - }), __webpack_require__.d(__webpack_exports__, "g", function() { - return isNumOrStr; - }), __webpack_require__.d(__webpack_exports__, "k", function() { - return uniqueId; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return getPercentValue; - }), __webpack_require__.d(__webpack_exports__, "b", function() { - return getAnyElementOfObject; - }), __webpack_require__.d(__webpack_exports__, "e", function() { - return hasDuplicate; - }), __webpack_require__.d(__webpack_exports__, "f", function() { - return interpolateNumber; - }), __webpack_require__.d(__webpack_exports__, "a", function() { - return findEntryInArray; - }), __webpack_require__.d(__webpack_exports__, "c", function() { - return getLinearRegression; - }); - var __WEBPACK_IMPORTED_MODULE_0_lodash_get__ = __webpack_require__(174), __WEBPACK_IMPORTED_MODULE_0_lodash_get___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_get__), __WEBPACK_IMPORTED_MODULE_1_lodash_isArray__ = __webpack_require__(13), __WEBPACK_IMPORTED_MODULE_1_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__ = __webpack_require__(120), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__), __WEBPACK_IMPORTED_MODULE_3_lodash_isNumber__ = __webpack_require__(272), __WEBPACK_IMPORTED_MODULE_3_lodash_isNumber___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_isNumber__), __WEBPACK_IMPORTED_MODULE_4_lodash_isString__ = __webpack_require__(173), __WEBPACK_IMPORTED_MODULE_4_lodash_isString___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_isString__), mathSign = function(value) { - return 0 === value ? 0 : value > 0 ? 1 : -1; - }, isPercent = function(value) { - return __WEBPACK_IMPORTED_MODULE_4_lodash_isString___default()(value) && value.indexOf("%") === value.length - 1; - }, isNumber = function(value) { - return __WEBPACK_IMPORTED_MODULE_3_lodash_isNumber___default()(value) && !__WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default()(value); - }, isNumOrStr = function(value) { - return isNumber(value) || __WEBPACK_IMPORTED_MODULE_4_lodash_isString___default()(value); - }, idCounter = 0, uniqueId = function(prefix) { - var id = ++idCounter; - return "" + (prefix || "") + id; - }, getPercentValue = function(percent, totalValue) { - var defaultValue = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 0, validate = arguments.length > 3 && void 0 !== arguments[3] && arguments[3]; - if (!isNumber(percent) && !__WEBPACK_IMPORTED_MODULE_4_lodash_isString___default()(percent)) return defaultValue; - var value = void 0; - if (isPercent(percent)) { - var index = percent.indexOf("%"); - value = totalValue * parseFloat(percent.slice(0, index)) / 100; - } else value = +percent; - return __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default()(value) && (value = defaultValue), - validate && value > totalValue && (value = totalValue), value; - }, getAnyElementOfObject = function(obj) { - if (!obj) return null; - var keys = Object.keys(obj); - return keys && keys.length ? obj[keys[0]] : null; - }, hasDuplicate = function(ary) { - if (!__WEBPACK_IMPORTED_MODULE_1_lodash_isArray___default()(ary)) return !1; - for (var len = ary.length, cache = {}, i = 0; i < len; i++) { - if (cache[ary[i]]) return !0; - cache[ary[i]] = !0; - } - return !1; - }, interpolateNumber = function(numberA, numberB) { - return isNumber(numberA) && isNumber(numberB) ? function(t) { - return numberA + t * (numberB - numberA); - } : function() { - return numberB; - }; - }, findEntryInArray = function(ary, specifiedKey, specifiedValue) { - return ary && ary.length ? ary.find(function(entry) { - return entry && __WEBPACK_IMPORTED_MODULE_0_lodash_get___default()(entry, specifiedKey) === specifiedValue; - }) : null; - }, getLinearRegression = function(data) { - if (!data || !data.length) return null; - for (var len = data.length, xsum = 0, ysum = 0, xysum = 0, xxsum = 0, xmin = 1 / 0, xmax = -1 / 0, i = 0; i < len; i++) xsum += data[i].cx, - ysum += data[i].cy, xysum += data[i].cx * data[i].cy, xxsum += data[i].cx * data[i].cx, - xmin = Math.min(xmin, data[i].cx), xmax = Math.max(xmax, data[i].cx); - var a = len * xxsum != xsum * xsum ? (len * xysum - xsum * ysum) / (len * xxsum - xsum * xsum) : 0; - return { - xmin: xmin, - xmax: xmax, - a: a, - b: (ysum - a * xsum) / len - }; - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - function getDefaultTheme() { - return defaultTheme || (defaultTheme = (0, _createMuiTheme2.default)()); - } - Object.defineProperty(exports, "__esModule", { - value: !0 - }), exports.sheetsManager = void 0; - var _keys = __webpack_require__(55), _keys2 = _interopRequireDefault(_keys), _extends2 = __webpack_require__(6), _extends3 = _interopRequireDefault(_extends2), _getPrototypeOf = __webpack_require__(26), _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf), _classCallCheck2 = __webpack_require__(27), _classCallCheck3 = _interopRequireDefault(_classCallCheck2), _createClass2 = __webpack_require__(28), _createClass3 = _interopRequireDefault(_createClass2), _possibleConstructorReturn2 = __webpack_require__(29), _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2), _inherits2 = __webpack_require__(30), _inherits3 = _interopRequireDefault(_inherits2), _objectWithoutProperties2 = __webpack_require__(7), _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2), _map = __webpack_require__(440), _map2 = _interopRequireDefault(_map), _minSafeInteger = __webpack_require__(456), _minSafeInteger2 = _interopRequireDefault(_minSafeInteger), _react = __webpack_require__(0), _react2 = _interopRequireDefault(_react), _propTypes = __webpack_require__(1), _propTypes2 = _interopRequireDefault(_propTypes), _warning = __webpack_require__(11), _warning2 = _interopRequireDefault(_warning), _hoistNonReactStatics = __webpack_require__(162), _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics), _getDisplayName = __webpack_require__(244), _getDisplayName2 = _interopRequireDefault(_getDisplayName), _wrapDisplayName = __webpack_require__(79), _wrapDisplayName2 = _interopRequireDefault(_wrapDisplayName), _contextTypes = __webpack_require__(459), _contextTypes2 = _interopRequireDefault(_contextTypes), _jss = __webpack_require__(246), _ns = __webpack_require__(245), ns = function(obj) { - if (obj && obj.__esModule) return obj; - var newObj = {}; - if (null != obj) for (var key in obj) Object.prototype.hasOwnProperty.call(obj, key) && (newObj[key] = obj[key]); - return newObj.default = obj, newObj; - }(_ns), _jssPreset = __webpack_require__(481), _jssPreset2 = _interopRequireDefault(_jssPreset), _createMuiTheme = __webpack_require__(161), _createMuiTheme2 = _interopRequireDefault(_createMuiTheme), _themeListener = __webpack_require__(160), _themeListener2 = _interopRequireDefault(_themeListener), _createGenerateClassName = __webpack_require__(494), _createGenerateClassName2 = _interopRequireDefault(_createGenerateClassName), _getStylesCreator = __webpack_require__(495), _getStylesCreator2 = _interopRequireDefault(_getStylesCreator), jss = (0, - _jss.create)((0, _jssPreset2.default)()), generateClassName = (0, _createGenerateClassName2.default)(), indexCounter = _minSafeInteger2.default, sheetsManager = exports.sheetsManager = new _map2.default(), noopTheme = {}, defaultTheme = void 0, withStyles = function(stylesOrCreator) { - var options = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; - return function(Component) { - var _options$withTheme = options.withTheme, withTheme = void 0 !== _options$withTheme && _options$withTheme, _options$flip = options.flip, flip = void 0 === _options$flip ? null : _options$flip, name = options.name, styleSheetOptions = (0, - _objectWithoutProperties3.default)(options, [ "withTheme", "flip", "name" ]), stylesCreator = (0, - _getStylesCreator2.default)(stylesOrCreator), listenToTheme = stylesCreator.themingEnabled || withTheme || "string" == typeof name; - indexCounter += 1, stylesCreator.options.index = indexCounter, "production" !== process.env.NODE_ENV && (0, - _warning2.default)(indexCounter < 0, [ "Material-UI: you might have a memory leak.", "The indexCounter is not supposed to grow that much." ].join(" ")); - var WithStyles = function(_React$Component) { - function WithStyles(props, context) { - (0, _classCallCheck3.default)(this, WithStyles); - var _this = (0, _possibleConstructorReturn3.default)(this, (WithStyles.__proto__ || (0, - _getPrototypeOf2.default)(WithStyles)).call(this, props, context)); - _this.state = {}, _this.disableStylesGeneration = !1, _this.jss = null, _this.sheetOptions = null, - _this.sheetsManager = sheetsManager, _this.stylesCreatorSaved = null, _this.theme = null, - _this.unsubscribeId = null, _this.jss = _this.context[ns.jss] || jss; - var muiThemeProviderOptions = _this.context.muiThemeProviderOptions; - return muiThemeProviderOptions && (muiThemeProviderOptions.sheetsManager && (_this.sheetsManager = muiThemeProviderOptions.sheetsManager), - _this.disableStylesGeneration = muiThemeProviderOptions.disableStylesGeneration), - _this.stylesCreatorSaved = stylesCreator, _this.sheetOptions = (0, _extends3.default)({ - generateClassName: generateClassName - }, _this.context[ns.sheetOptions]), _this.theme = listenToTheme ? _themeListener2.default.initial(context) || getDefaultTheme() : noopTheme, - _this; - } - return (0, _inherits3.default)(WithStyles, _React$Component), (0, _createClass3.default)(WithStyles, [ { - key: "componentWillMount", - value: function() { - this.attach(this.theme); - } - }, { - key: "componentDidMount", - value: function() { - var _this2 = this; - listenToTheme && (this.unsubscribeId = _themeListener2.default.subscribe(this.context, function(theme) { - var oldTheme = _this2.theme; - _this2.theme = theme, _this2.attach(_this2.theme), _this2.setState({}, function() { - _this2.detach(oldTheme); - }); - })); - } - }, { - key: "componentWillReceiveProps", - value: function() { - this.stylesCreatorSaved !== stylesCreator && "production" !== process.env.NODE_ENV && (this.detach(this.theme), - this.stylesCreatorSaved = stylesCreator, this.attach(this.theme)); - } - }, { - key: "componentWillUnmount", - value: function() { - this.detach(this.theme), null !== this.unsubscribeId && _themeListener2.default.unsubscribe(this.context, this.unsubscribeId); - } - }, { - key: "attach", - value: function(theme) { - if (!this.disableStylesGeneration) { - var stylesCreatorSaved = this.stylesCreatorSaved, sheetManager = this.sheetsManager.get(stylesCreatorSaved); - sheetManager || (sheetManager = new _map2.default(), this.sheetsManager.set(stylesCreatorSaved, sheetManager)); - var sheetManagerTheme = sheetManager.get(theme); - if (sheetManagerTheme || (sheetManagerTheme = { - refs: 0, - sheet: null - }, sheetManager.set(theme, sheetManagerTheme)), 0 === sheetManagerTheme.refs) { - var styles = stylesCreatorSaved.create(theme, name), meta = name; - "production" === process.env.NODE_ENV || meta || (meta = (0, _getDisplayName2.default)(Component)); - var sheet = this.jss.createStyleSheet(styles, (0, _extends3.default)({ - meta: meta, - classNamePrefix: meta, - flip: "boolean" == typeof flip ? flip : "rtl" === theme.direction, - link: !1 - }, this.sheetOptions, stylesCreatorSaved.options, { - name: name - }, styleSheetOptions)); - sheetManagerTheme.sheet = sheet, sheet.attach(); - var sheetsRegistry = this.context[ns.sheetsRegistry]; - sheetsRegistry && sheetsRegistry.add(sheet); - } - sheetManagerTheme.refs += 1; - } - } - }, { - key: "detach", - value: function(theme) { - if (!this.disableStylesGeneration) { - var stylesCreatorSaved = this.stylesCreatorSaved, sheetManager = this.sheetsManager.get(stylesCreatorSaved), sheetManagerTheme = sheetManager.get(theme); - if (sheetManagerTheme.refs -= 1, 0 === sheetManagerTheme.refs) { - sheetManager.delete(theme), this.jss.removeStyleSheet(sheetManagerTheme.sheet); - var sheetsRegistry = this.context[ns.sheetsRegistry]; - sheetsRegistry && sheetsRegistry.remove(sheetManagerTheme.sheet); - } - } - } - }, { - key: "render", - value: function() { - var _this3 = this, _props = this.props, classesProp = _props.classes, innerRef = _props.innerRef, other = (0, - _objectWithoutProperties3.default)(_props, [ "classes", "innerRef" ]), classes = void 0, renderedClasses = {}; - if (!this.disableStylesGeneration) { - var sheetManager = this.sheetsManager.get(this.stylesCreatorSaved), sheetsManagerTheme = sheetManager.get(this.theme); - renderedClasses = sheetsManagerTheme.sheet.classes; - } - classes = classesProp ? (0, _extends3.default)({}, renderedClasses, (0, _keys2.default)(classesProp).reduce(function(accumulator, key) { - return "production" !== process.env.NODE_ENV && (0, _warning2.default)(renderedClasses[key] || _this3.disableStylesGeneration, [ "Material-UI: the key ` + ("`" + `" + key + "`)) + ("`" + (` provided to the classes property is not implemented in " + (0, - _getDisplayName2.default)(Component) + ".", "You can only override one of the following: " + (0, - _keys2.default)(renderedClasses).join(",") ].join("\n")), "production" !== process.env.NODE_ENV && (0, - _warning2.default)(!classesProp[key] || "string" == typeof classesProp[key], [ "Material-UI: the key ` + "`"))) + ((`" + key + "` + ("`" + ` provided to the classes property is not valid for " + (0, - _getDisplayName2.default)(Component) + ".", "You need to provide a non empty string instead of: " + classesProp[key] + "." ].join("\n")), - classesProp[key] && (accumulator[key] = renderedClasses[key] + " " + classesProp[key]), - accumulator; - }, {})) : renderedClasses; - var more = {}; - return withTheme && (more.theme = this.theme), _react2.default.createElement(Component, (0, - _extends3.default)({ - classes: classes - }, more, other, { - ref: innerRef - })); - } - } ]), WithStyles; - }(_react2.default.Component); - return WithStyles.propTypes = "production" !== process.env.NODE_ENV ? { - classes: _propTypes2.default.object, - innerRef: _propTypes2.default.func - } : {}, WithStyles.contextTypes = (0, _extends3.default)({ - muiThemeProviderOptions: _propTypes2.default.object - }, _contextTypes2.default, listenToTheme ? _themeListener2.default.contextTypes : {}), - "production" !== process.env.NODE_ENV && (WithStyles.displayName = (0, _wrapDisplayName2.default)(Component, "WithStyles")), - (0, _hoistNonReactStatics2.default)(WithStyles, Component), "production" !== process.env.NODE_ENV && (WithStyles.Naked = Component, - WithStyles.options = options), WithStyles; - }; - }; - exports.default = withStyles; - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - var warning = function() {}; - "production" !== process.env.NODE_ENV && (warning = function(condition, format, args) { - var len = arguments.length; - args = new Array(len > 2 ? len - 2 : 0); - for (var key = 2; key < len; key++) args[key - 2] = arguments[key]; - if (void 0 === format) throw new Error("`)) + ("`" + (`warning(condition, format, ...args)` + "`")))) + (((` requires a warning message argument"); - if (format.length < 10 || /^[s\W]*$/.test(format)) throw new Error("The warning format should be able to uniquely identify this warning. Please, use a more descriptive format than: " + format); - if (!condition) { - var argIndex = 0, message = "Warning: " + format.replace(/%s/g, function() { - return args[argIndex++]; - }); - "undefined" != typeof console && console.error(message); - try { - throw new Error(message); - } catch (x) {} + function _createClass(e, t, n) { + return t && _defineProperties(e.prototype, t), n && _defineProperties(e, n), e; } - }), module.exports = warning; - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0; - var _defineProperty = __webpack_require__(154), _defineProperty2 = function(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - }(_defineProperty); - exports.default = function(obj, key, value) { - return key in obj ? (0, _defineProperty2.default)(obj, key, { - value: value, - enumerable: !0, - configurable: !0, - writable: !0 - }) : obj[key] = value, obj; - }; -}, function(module, exports) { - var isArray = Array.isArray; - module.exports = isArray; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - function Layer(props) { - var children = props.children, className = props.className, others = _objectWithoutProperties(props, [ "children", "className" ]), layerClass = __WEBPACK_IMPORTED_MODULE_2_classnames___default()("recharts-layer", className); - return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("g", _extends({ - className: layerClass - }, others), children); - } - var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_2_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_classnames__), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, propTypes = { - className: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, - children: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.node), __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.node ]) - }; - Layer.propTypes = propTypes, __webpack_exports__.a = Layer; -}, function(module, exports, __webpack_require__) { - var global = __webpack_require__(167), core = __webpack_require__(168), hide = __webpack_require__(266), redefine = __webpack_require__(581), ctx = __webpack_require__(584), $export = function(type, name, source) { - var key, own, out, exp, IS_FORCED = type & $export.F, IS_GLOBAL = type & $export.G, IS_STATIC = type & $export.S, IS_PROTO = type & $export.P, IS_BIND = type & $export.B, target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {}).prototype, exports = IS_GLOBAL ? core : core[name] || (core[name] = {}), expProto = exports.prototype || (exports.prototype = {}); - IS_GLOBAL && (source = name); - for (key in source) own = !IS_FORCED && target && void 0 !== target[key], out = (own ? target : source)[key], - exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && "function" == typeof out ? ctx(Function.call, out) : out, - target && redefine(target, key, out, type & $export.U), exports[key] != out && hide(exports, key, exp), - IS_PROTO && expProto[key] != out && (expProto[key] = out); - }; - global.core = core, $export.F = 1, $export.G = 2, $export.S = 4, $export.P = 8, - $export.B = 16, $export.W = 32, $export.U = 64, $export.R = 128, module.exports = $export; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _defineProperty(obj, key, value) { - return key in obj ? Object.defineProperty(obj, key, { - value: value, - enumerable: !0, - configurable: !0, - writable: !0 - }) : obj[key] = value, obj; - } - function _toConsumableArray(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - return arr2; - } - return Array.from(arr); - } - __webpack_require__.d(__webpack_exports__, "w", function() { - return getValueByDataKey; - }), __webpack_require__.d(__webpack_exports__, "n", function() { - return getDomainOfDataByKey; - }), __webpack_require__.d(__webpack_exports__, "b", function() { - return calculateActiveTickIndex; - }), __webpack_require__.d(__webpack_exports__, "r", function() { - return getMainColorOfGraphicItem; - }), __webpack_require__.d(__webpack_exports__, "q", function() { - return getLegendProps; - }), __webpack_require__.d(__webpack_exports__, "i", function() { - return getBarSizeList; - }), __webpack_require__.d(__webpack_exports__, "h", function() { - return getBarPosition; - }), __webpack_require__.d(__webpack_exports__, "a", function() { - return appendOffsetOfLegend; - }), __webpack_require__.d(__webpack_exports__, "z", function() { - return parseErrorBarsOfAxis; - }), __webpack_require__.d(__webpack_exports__, "o", function() { - return getDomainOfItemsWithSameAxis; - }), __webpack_require__.d(__webpack_exports__, "x", function() { - return isCategorialAxis; - }), __webpack_require__.d(__webpack_exports__, "m", function() { - return getCoordinatesOfGrid; - }), __webpack_require__.d(__webpack_exports__, "u", function() { - return getTicksOfAxis; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return combineEventHandlers; - }), __webpack_require__.d(__webpack_exports__, "A", function() { - return parseScale; - }), __webpack_require__.d(__webpack_exports__, "c", function() { - return checkDomainOfScale; - }), __webpack_require__.d(__webpack_exports__, "f", function() { - return findPositionOfBar; - }), __webpack_require__.d(__webpack_exports__, "C", function() { - return truncateByDomain; - }), __webpack_require__.d(__webpack_exports__, "s", function() { - return getStackGroupsByAxisId; - }), __webpack_require__.d(__webpack_exports__, "v", function() { - return getTicksOfScale; - }), __webpack_require__.d(__webpack_exports__, "l", function() { - return getCateCoordinateOfLine; - }), __webpack_require__.d(__webpack_exports__, "k", function() { - return getCateCoordinateOfBar; - }), __webpack_require__.d(__webpack_exports__, "j", function() { - return getBaseValueOfBar; - }), __webpack_require__.d(__webpack_exports__, "e", function() { - return detectReferenceElementsDomain; - }), __webpack_require__.d(__webpack_exports__, "t", function() { - return getStackedDataOfItem; - }), __webpack_require__.d(__webpack_exports__, "p", function() { - return getDomainOfStackGroups; - }), __webpack_require__.d(__webpack_exports__, "B", function() { - return parseSpecifiedDomain; - }), __webpack_require__.d(__webpack_exports__, "D", function() { - return validateCoordinateInRange; - }), __webpack_require__.d(__webpack_exports__, "g", function() { - return getBandSizeOfAxis; - }), __webpack_require__.d(__webpack_exports__, "y", function() { - return parseDomainOfCategoryAxis; - }); - var __WEBPACK_IMPORTED_MODULE_0_lodash_isEqual__ = __webpack_require__(45), __WEBPACK_IMPORTED_MODULE_0_lodash_isEqual___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isEqual__), __WEBPACK_IMPORTED_MODULE_1_lodash_sortBy__ = __webpack_require__(321), __WEBPACK_IMPORTED_MODULE_1_lodash_sortBy___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_sortBy__), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__ = __webpack_require__(120), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__), __WEBPACK_IMPORTED_MODULE_3_lodash_isString__ = __webpack_require__(173), __WEBPACK_IMPORTED_MODULE_3_lodash_isString___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_isString__), __WEBPACK_IMPORTED_MODULE_4_lodash_max__ = __webpack_require__(841), __WEBPACK_IMPORTED_MODULE_4_lodash_max___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_max__), __WEBPACK_IMPORTED_MODULE_5_lodash_min__ = __webpack_require__(328), __WEBPACK_IMPORTED_MODULE_5_lodash_min___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_lodash_min__), __WEBPACK_IMPORTED_MODULE_6_lodash_isArray__ = __webpack_require__(13), __WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_7_lodash_flatMap__ = __webpack_require__(842), __WEBPACK_IMPORTED_MODULE_7_lodash_flatMap___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_7_lodash_flatMap__), __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_8_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_9_lodash_get__ = __webpack_require__(174), __WEBPACK_IMPORTED_MODULE_9_lodash_get___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_9_lodash_get__), __WEBPACK_IMPORTED_MODULE_10_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_10_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_11_recharts_scale__ = __webpack_require__(844), __WEBPACK_IMPORTED_MODULE_12_d3_scale__ = (__webpack_require__.n(__WEBPACK_IMPORTED_MODULE_11_recharts_scale__), - __webpack_require__(331)), __WEBPACK_IMPORTED_MODULE_13_d3_shape__ = __webpack_require__(182), __WEBPACK_IMPORTED_MODULE_14__DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_15__cartesian_ReferenceDot__ = __webpack_require__(364), __WEBPACK_IMPORTED_MODULE_16__cartesian_ReferenceLine__ = __webpack_require__(365), __WEBPACK_IMPORTED_MODULE_17__cartesian_ReferenceArea__ = __webpack_require__(366), __WEBPACK_IMPORTED_MODULE_18__cartesian_ErrorBar__ = __webpack_require__(95), __WEBPACK_IMPORTED_MODULE_19__component_Legend__ = __webpack_require__(180), __WEBPACK_IMPORTED_MODULE_20__ReactUtils__ = __webpack_require__(4), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, getValueByDataKey = function(obj, dataKey, defaultValue) { - return __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(obj) || __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(dataKey) ? defaultValue : Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.g)(dataKey) ? __WEBPACK_IMPORTED_MODULE_9_lodash_get___default()(obj, dataKey, defaultValue) : __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(dataKey) ? dataKey(obj) : defaultValue; - }, getDomainOfDataByKey = function(data, key, type, filterNil) { - var flattenData = __WEBPACK_IMPORTED_MODULE_7_lodash_flatMap___default()(data, function(entry) { - return getValueByDataKey(entry, key); - }); - if ("number" === type) { - var domain = flattenData.filter(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h); - return [ Math.min.apply(null, domain), Math.max.apply(null, domain) ]; - } - return (filterNil ? flattenData.filter(function(entry) { - return !__WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(entry); - }) : flattenData).map(function(entry) { - return Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.g)(entry) ? entry : ""; - }); - }, calculateActiveTickIndex = function(coordinate, ticks, unsortedTicks, axis) { - var index = -1, len = ticks.length; - if (len > 1) { - if (axis && "angleAxis" === axis.axisType && Math.abs(Math.abs(axis.range[1] - axis.range[0]) - 360) <= 1e-6) for (var range = axis.range, i = 0; i < len; i++) { - var before = i > 0 ? unsortedTicks[i - 1].coordinate : unsortedTicks[len - 1].coordinate, cur = unsortedTicks[i].coordinate, after = i >= len - 1 ? unsortedTicks[0].coordinate : unsortedTicks[i + 1].coordinate, sameDirectionCoord = void 0; - if (Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.j)(cur - before) !== Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.j)(after - cur)) { - var diffInterval = []; - if (Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.j)(after - cur) === Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.j)(range[1] - range[0])) { - sameDirectionCoord = after; - var curInRange = cur + range[1] - range[0]; - diffInterval[0] = Math.min(curInRange, (curInRange + before) / 2), diffInterval[1] = Math.max(curInRange, (curInRange + before) / 2); - } else { - sameDirectionCoord = before; - var afterInRange = after + range[1] - range[0]; - diffInterval[0] = Math.min(cur, (afterInRange + cur) / 2), diffInterval[1] = Math.max(cur, (afterInRange + cur) / 2); - } - var sameInterval = [ Math.min(cur, (sameDirectionCoord + cur) / 2), Math.max(cur, (sameDirectionCoord + cur) / 2) ]; - if (coordinate > sameInterval[0] && coordinate <= sameInterval[1] || coordinate >= diffInterval[0] && coordinate <= diffInterval[1]) { - index = unsortedTicks[i].index; - break; - } - } else { - var min = Math.min(before, after), max = Math.max(before, after); - if (coordinate > (min + cur) / 2 && coordinate <= (max + cur) / 2) { - index = unsortedTicks[i].index; - break; + function _possibleConstructorReturn(e, t) { + return !t || "object" !== _typeof(t) && "function" != typeof t ? _assertThisInitialized(e) : t; + } + function _assertThisInitialized(e) { + if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + return e; + } + function _getPrototypeOf(e) { + return (_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function(e) { + return e.__proto__ || Object.getPrototypeOf(e); + })(e); + } + function _inherits(e, t) { + if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); + e.prototype = Object.create(t && t.prototype, { + constructor: { + value: e, + writable: !0, + configurable: !0 } + }), t && _setPrototypeOf(e, t); + } + function _setPrototypeOf(e, t) { + return (_setPrototypeOf = Object.setPrototypeOf || function(e, t) { + return e.__proto__ = t, e; + })(e, t); + } + enterModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).enterModule, + enterModule && enterModule(module); + var styles = { + container: { + flexWrap: "nowrap", + height: "100%", + maxWidth: "100%", + margin: 0 + }, + item: { + flex: 1, + padding: 0 } - } else for (var _i = 0; _i < len; _i++) if (0 === _i && coordinate <= (ticks[_i].coordinate + ticks[_i + 1].coordinate) / 2 || _i > 0 && _i < len - 1 && coordinate > (ticks[_i].coordinate + ticks[_i - 1].coordinate) / 2 && coordinate <= (ticks[_i].coordinate + ticks[_i + 1].coordinate) / 2 || _i === len - 1 && coordinate > (ticks[_i].coordinate + ticks[_i - 1].coordinate) / 2) { - index = ticks[_i].index; - break; + }, ChartRow = function(_Component) { + function ChartRow() { + return _classCallCheck(this, ChartRow), _possibleConstructorReturn(this, _getPrototypeOf(ChartRow).apply(this, arguments)); + } + return _inherits(ChartRow, _Component), _createClass(ChartRow, [ { + key: "render", + value: function() { + return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_material_ui_core_Grid__WEBPACK_IMPORTED_MODULE_1___default.a, { + container: !0, + direction: "row", + style: styles.container, + justify: "space-between" + }, react__WEBPACK_IMPORTED_MODULE_0___default.a.Children.map(this.props.children, function(e) { + return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_material_ui_core_Grid__WEBPACK_IMPORTED_MODULE_1___default.a, { + item: !0, + xs: !0, + style: styles.item + }, e); + })); + } + }, { + key: "__reactstandin__regenerateByEval", + value: function __reactstandin__regenerateByEval(key, code) { + this[key] = eval(code); + } + } ]), ChartRow; + }(react__WEBPACK_IMPORTED_MODULE_0__.Component), _default = ChartRow, reactHotLoader, leaveModule; + __webpack_exports__.a = _default, reactHotLoader = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).default, + reactHotLoader && (reactHotLoader.register(styles, "styles", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx"), + reactHotLoader.register(ChartRow, "ChartRow", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx"), + reactHotLoader.register(_default, "default", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx")), + leaveModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).leaveModule, + leaveModule && leaveModule(module); + }).call(this, __webpack_require__("./node_modules/webpack/buildin/harmony-module.js")(module)); + }, + "./components/CustomTooltip.jsx": function(module, __webpack_exports__, __webpack_require__) { + "use strict"; + (function(module) { + __webpack_require__.d(__webpack_exports__, "d", function() { + return multiplier; + }), __webpack_require__.d(__webpack_exports__, "e", function() { + return percentPlotter; + }), __webpack_require__.d(__webpack_exports__, "b", function() { + return bytePlotter; + }), __webpack_require__.d(__webpack_exports__, "a", function() { + return bytePerSecPlotter; + }); + var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/react/index.js"), react__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__), _material_ui_core_Typography__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./node_modules/@material-ui/core/Typography/index.js"), _material_ui_core_Typography__WEBPACK_IMPORTED_MODULE_1___default = __webpack_require__.n(_material_ui_core_Typography__WEBPACK_IMPORTED_MODULE_1__), _common__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./common.jsx"), enterModule; + function _typeof(e) { + return (_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { + return typeof e; + } : function(e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e; + })(e); } - } else index = 0; - return index; - }, getMainColorOfGraphicItem = function(item) { - var displayName = item.type.displayName, result = void 0; - switch (displayName) { - case "Line": - case "Area": - case "Radar": - result = item.props.stroke; - break; - - default: - result = item.props.fill; - } - return result; - }, getLegendProps = function(_ref) { - var children = _ref.children, formatedGraphicalItems = _ref.formatedGraphicalItems, legendWidth = _ref.legendWidth, legendContent = _ref.legendContent, legendItem = Object(__WEBPACK_IMPORTED_MODULE_20__ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_19__component_Legend__.a); - if (!legendItem) return null; - var legendData = void 0; - return legendData = legendItem.props && legendItem.props.payload ? legendItem.props && legendItem.props.payload : "children" === legendContent ? (formatedGraphicalItems || []).reduce(function(result, _ref2) { - var item = _ref2.item, props = _ref2.props, data = props.sectors || props.data || []; - return result.concat(data.map(function(entry) { + function _classCallCheck(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); + } + function _defineProperties(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), + Object.defineProperty(e, r.key, r); + } + } + function _createClass(e, t, n) { + return t && _defineProperties(e.prototype, t), n && _defineProperties(e, n), e; + } + function _possibleConstructorReturn(e, t) { + return !t || "object" !== _typeof(t) && "function" != typeof t ? _assertThisInitialized(e) : t; + } + function _assertThisInitialized(e) { + if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + return e; + } + function _getPrototypeOf(e) { + return (_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function(e) { + return e.__proto__ || Object.getPrototypeOf(e); + })(e); + } + function _inherits(e, t) { + if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); + e.prototype = Object.create(t && t.prototype, { + constructor: { + value: e, + writable: !0, + configurable: !0 + } + }), t && _setPrototypeOf(e, t); + } + function _setPrototypeOf(e, t) { + return (_setPrototypeOf = Object.setPrototypeOf || function(e, t) { + return e.__proto__ = t, e; + })(e, t); + } + enterModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).enterModule, + enterModule && enterModule(module); + var multiplier = function() { + var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 1; + return function(t) { + return t * e; + }; + }, percentPlotter = function(e) { + var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : multiplier(1); + return function(n) { + var r = t(n); + return "number" != typeof r ? null : react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_material_ui_core_Typography__WEBPACK_IMPORTED_MODULE_1___default.a, { + type: "caption", + color: "inherit" + }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", { + style: _common__WEBPACK_IMPORTED_MODULE_2__.g.light + }, e), " ", r.toFixed(2), " %"); + }; + }, bytePlotter = function(e) { + var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : multiplier(1); + return function(n) { + var r = t(n); + return "number" != typeof r ? null : react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_material_ui_core_Typography__WEBPACK_IMPORTED_MODULE_1___default.a, { + type: "caption", + color: "inherit" + }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", { + style: _common__WEBPACK_IMPORTED_MODULE_2__.g.light + }, e), " ", Object(_common__WEBPACK_IMPORTED_MODULE_2__.f)(r)); + }; + }, bytePerSecPlotter = function(e) { + var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : multiplier(1); + return function(n) { + var r = t(n); + return "number" != typeof r ? null : react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_material_ui_core_Typography__WEBPACK_IMPORTED_MODULE_1___default.a, { + type: "caption", + color: "inherit" + }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", { + style: _common__WEBPACK_IMPORTED_MODULE_2__.g.light + }, e), Object(_common__WEBPACK_IMPORTED_MODULE_2__.f)(r), "/s"); + }; + }, CustomTooltip = function(_Component) { + function CustomTooltip() { + return _classCallCheck(this, CustomTooltip), _possibleConstructorReturn(this, _getPrototypeOf(CustomTooltip).apply(this, arguments)); + } + return _inherits(CustomTooltip, _Component), _createClass(CustomTooltip, [ { + key: "render", + value: function() { + var e = this.props, t = e.active, n = e.payload, r = e.tooltip; + return !t || "function" != typeof r || !Array.isArray(n) || n.length < 1 ? null : r(n[0].value); + } + }, { + key: "__reactstandin__regenerateByEval", + value: function __reactstandin__regenerateByEval(key, code) { + this[key] = eval(code); + } + } ]), CustomTooltip; + }(react__WEBPACK_IMPORTED_MODULE_0__.Component), _default = CustomTooltip, reactHotLoader, leaveModule; + __webpack_exports__.c = _default, reactHotLoader = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).default, + reactHotLoader && (reactHotLoader.register(multiplier, "multiplier", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx"), + reactHotLoader.register(percentPlotter, "percentPlotter", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx"), + reactHotLoader.register(bytePlotter, "bytePlotter", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx"), + reactHotLoader.register(bytePerSecPlotter, "bytePerSecPlotter", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx"), + reactHotLoader.register(CustomTooltip, "CustomTooltip", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx"), + reactHotLoader.register(_default, "default", "/home/misi/Work/src/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx")), + leaveModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).leaveModule, + leaveModule && leaveModule(module); + }).call(this, __webpack_require__("./node_modules/webpack/buildin/harmony-module.js")(module)); + }, + "./components/Dashboard.jsx": function(module, __webpack_exports__, __webpack_require__) { + "use strict"; + (function(module) { + var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/react/index.js"), react__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__), react_hot_loader__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./node_modules/react-hot-loader/index.js"), react_hot_loader__WEBPACK_IMPORTED_MODULE_1___default = __webpack_require__.n(react_hot_loader__WEBPACK_IMPORTED_MODULE_1__), _material_ui_core_styles_withStyles__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./node_modules/@material-ui/core/styles/withStyles.js"), _material_ui_core_styles_withStyles__WEBPACK_IMPORTED_MODULE_2___default = __webpack_require__.n(_material_ui_core_styles_withStyles__WEBPACK_IMPORTED_MODULE_2__), Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__("./components/Header.jsx"), Body__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__("./components/Body.jsx"), Logs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__("./components/Logs.jsx"), Network__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__("./components/Network.jsx"), _common__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__("./common.jsx"), enterModule; + function _typeof(e) { + return (_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { + return typeof e; + } : function(e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e; + })(e); + } + function _classCallCheck(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function"); + } + function _defineProperties(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), + Object.defineProperty(e, r.key, r); + } + } + function _createClass(e, t, n) { + return t && _defineProperties(e.prototype, t), n && _defineProperties(e, n), e; + } + function _possibleConstructorReturn(e, t) { + return !t || "object" !== _typeof(t) && "function" != typeof t ? _assertThisInitialized(e) : t; + } + function _getPrototypeOf(e) { + return (_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function(e) { + return e.__proto__ || Object.getPrototypeOf(e); + })(e); + } + function _assertThisInitialized(e) { + if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + return e; + } + function _inherits(e, t) { + if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); + e.prototype = Object.create(t && t.prototype, { + constructor: { + value: e, + writable: !0, + configurable: !0 + } + }), t && _setPrototypeOf(e, t); + } + function _setPrototypeOf(e, t) { + return (_setPrototypeOf = Object.setPrototypeOf || function(e, t) { + return e.__proto__ = t, e; + })(e, t); + } + function _defineProperty(e, t, n) { + return t in e ? Object.defineProperty(e, t, { + value: n, + enumerable: !0, + configurable: !0, + writable: !0 + }) : e[t] = n, e; + } + function _toConsumableArray(e) { + return _arrayWithoutHoles(e) || _iterableToArray(e) || _nonIterableSpread(); + } + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance"); + } + function _iterableToArray(e) { + if (Symbol.iterator in Object(e) || "[object Arguments]" === Object.prototype.toString.call(e)) return Array.from(e); + } + function _arrayWithoutHoles(e) { + if (Array.isArray(e)) { + for (var t = 0, n = new Array(e.length); t < e.length; t++) n[t] = e[t]; + return n; + } + } + enterModule = ("undefined" != typeof reactHotLoaderGlobal ? reactHotLoaderGlobal : __webpack_require__("./node_modules/react-hot-loader/index.js")).enterModule, + enterModule && enterModule(module); + var deepUpdate = function e(t, n, r) { + if (void 0 === n) return r; + if ("function" == typeof t) return t(n, r); + var o = {}; + return Object.keys(r).forEach(function(a) { + o[a] = e(t[a], n[a], r[a]); + }), o; + }, shouldUpdate = function e(t, n) { + var r = {}; + return Object.keys(n).forEach(function(o) { + r[o] = "function" == typeof t[o] || e(t[o], n[o]); + }), r; + }, replacer = function(e) { + return e; + }, appender = function(e) { + var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : replacer; + return function(n, r) { + return [].concat(_toConsumableArray(r), _toConsumableArray(n.map(function(e) { + return t(e); + }))).slice(-e); + }; + }, defaultContent = function() { return { - type: legendItem.props.iconType || item.props.legendType, - value: entry.name, - color: entry.fill, - payload: entry + general: { + version: null, + commit: null + }, + home: {}, + chain: {}, + txpool: {}, + network: { + peers: { + bundles: {} + }, + diff: [] + }, + system: { + activeMemory: [], + virtualMemory: [], + networkIngress: [], + networkEgress: [], + processCPU: [], + systemCPU: [], + diskRead: [], + diskWrite: [] + }, + logs: { + chunks: [], + endTop: !1, + endBottom: !0, + topChanged: Logs__WEBPACK_IMPORTED_MODULE_5__.a, + bottomChanged: Logs__WEBPACK_IMPORTED_MODULE_5__.a + } }; - })); - }, []) : (formatedGraphicalItems || []).map(function(_ref3) { - var item = _ref3.item, _item$props = item.props, dataKey = _item$props.dataKey, name = _item$props.name, legendType = _item$props.legendType; - return { - inactive: _item$props.hide, - dataKey: dataKey, - type: legendItem.props.iconType || legendType || "square", - color: getMainColorOfGraphicItem(item), - value: name || dataKey, - payload: item.props - }; - }), _extends({}, legendItem.props, __WEBPACK_IMPORTED_MODULE_19__component_Legend__.a.getWithHeight(legendItem, legendWidth), { - payload: legendData, - item: legendItem - }); - }, getBarSizeList = function(_ref4) { - var globalSize = _ref4.barSize, _ref4$stackGroups = _ref4.stackGroups, stackGroups = void 0 === _ref4$stackGroups ? {} : _ref4$stackGroups; - if (!stackGroups) return {}; - for (var result = {}, numericAxisIds = Object.keys(stackGroups), i = 0, len = numericAxisIds.length; i < len; i++) for (var sgs = stackGroups[numericAxisIds[i]].stackGroups, stackIds = Object.keys(sgs), j = 0, sLen = stackIds.length; j < sLen; j++) { - var _sgs$stackIds$j = sgs[stackIds[j]], items = _sgs$stackIds$j.items, cateAxisId = _sgs$stackIds$j.cateAxisId, barItems = items.filter(function(item) { - return Object(__WEBPACK_IMPORTED_MODULE_20__ReactUtils__.j)(item.type).indexOf("Bar") >= 0; - }); - if (barItems && barItems.length) { - var selfSize = barItems[0].props.barSize, cateId = barItems[0].props[cateAxisId]; - result[cateId] || (result[cateId] = []), result[cateId].push({ - item: barItems[0], - stackList: barItems.slice(1), - barSize: __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(selfSize) ? globalSize : selfSize - }); - } - } - return result; - }, getBarPosition = function(_ref5) { - var barGap = _ref5.barGap, barCategoryGap = _ref5.barCategoryGap, bandSize = _ref5.bandSize, _ref5$sizeList = _ref5.sizeList, sizeList = void 0 === _ref5$sizeList ? [] : _ref5$sizeList, maxBarSize = _ref5.maxBarSize, len = sizeList.length; - if (len < 1) return null; - var realBarGap = Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.d)(barGap, bandSize, 0, !0), result = void 0; - if (sizeList[0].barSize === +sizeList[0].barSize) { - var useFull = !1, fullBarSize = bandSize / len, sum = sizeList.reduce(function(res, entry) { - return res + entry.barSize || 0; - }, 0); - sum += (len - 1) * realBarGap, sum >= bandSize && (sum -= (len - 1) * realBarGap, - realBarGap = 0), sum >= bandSize && fullBarSize > 0 && (useFull = !0, fullBarSize *= .9, - sum = len * fullBarSize); - var offset = (bandSize - sum) / 2 >> 0, prev = { - offset: offset - realBarGap, - size: 0 - }; - result = sizeList.reduce(function(res, entry) { - var newRes = [].concat(_toConsumableArray(res), [ { - item: entry.item, - position: { - offset: prev.offset + prev.size + realBarGap, - size: useFull ? fullBarSize : entry.barSize + }, updaters = { + general: { + version: replacer, + commit: replacer + }, + home: null, + chain: null, + txpool: null, + network: Object(Network__WEBPACK_IMPORTED_MODULE_6__.b)(200), + system: { + activeMemory: appender(200), + virtualMemory: appender(200), + networkIngress: appender(200), + networkEgress: appender(200), + processCPU: appender(200), + systemCPU: appender(200), + diskRead: appender(200), + diskWrite: appender(200) + }, + logs: Object(Logs__WEBPACK_IMPORTED_MODULE_5__.c)(5) + }, styles = { + dashboard: { + display: "flex", + flexFlow: "column", + width: "100%", + height: "100%", + zIndex: 1, + overflow: "hidden" + } + }, themeStyles = function(e) { + return { + dashboard: { + background: e.palette.background.default } - } ]); - return prev = newRes[newRes.length - 1].position, entry.stackList && entry.stackList.length && entry.stackList.forEach(function(item) { - newRes.push({ - item: item, - position: prev - }); - }), newRes; - }, []); - } else { - var _offset = Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.d)(barCategoryGap, bandSize, 0, !0); - bandSize - 2 * _offset - (len - 1) * realBarGap <= 0 && (realBarGap = 0); - var originalSize = (bandSize - 2 * _offset - (len - 1) * realBarGap) / len; - originalSize > 1 && (originalSize >>= 0); - var size = maxBarSize === +maxBarSize ? Math.min(originalSize, maxBarSize) : originalSize; - result = sizeList.reduce(function(res, entry, i) { - var newRes = [].concat(_toConsumableArray(res), [ { - item: entry.item, - position: { - offset: _offset + (originalSize + realBarGap) * i + (originalSize - size) / 2, - size: size - } - } ]); - return entry.stackList && entry.stackList.length && entry.stackList.forEach(function(item) { - newRes.push({ - item: item, - position: newRes[newRes.length - 1].position - }); - }), newRes; - }, []); - } - return result; - }, appendOffsetOfLegend = function(offset, items, props, legendBox) { - var children = props.children, width = props.width, height = props.height, margin = props.margin, legendWidth = width - (margin.left || 0) - (margin.right || 0), legendHeight = height - (margin.top || 0) - (margin.bottom || 0), legendProps = getLegendProps({ - children: children, - items: items, - legendWidth: legendWidth, - legendHeight: legendHeight - }), newOffset = offset; - if (legendProps) { - var box = legendBox || {}, align = legendProps.align, verticalAlign = legendProps.verticalAlign, layout = legendProps.layout; - ("vertical" === layout || "horizontal" === layout && "center" === verticalAlign) && Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(offset[align]) && (newOffset = _extends({}, offset, _defineProperty({}, align, newOffset[align] + (box.width || 0)))), - ("horizontal" === layout || "vertical" === layout && "center" === align) && Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(offset[verticalAlign]) && (newOffset = _extends({}, offset, _defineProperty({}, verticalAlign, newOffset[verticalAlign] + (box.height || 0)))); - } - return newOffset; - }, getDomainOfErrorBars = function(data, item, dataKey, axisType) { - var children = item.props.children, errorBars = Object(__WEBPACK_IMPORTED_MODULE_20__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_18__cartesian_ErrorBar__.a).filter(function(errorBarChild) { - var direction = errorBarChild.props.direction; - return !(!__WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(direction) && !__WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(axisType)) || axisType.indexOf(direction) >= 0; - }); - if (errorBars && errorBars.length) { - var keys = errorBars.map(function(errorBarChild) { - return errorBarChild.props.dataKey; - }); - return data.reduce(function(result, entry) { - var entryValue = getValueByDataKey(entry, dataKey, 0), mainValue = __WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default()(entryValue) ? [ __WEBPACK_IMPORTED_MODULE_5_lodash_min___default()(entryValue), __WEBPACK_IMPORTED_MODULE_4_lodash_max___default()(entryValue) ] : [ entryValue, entryValue ], errorDomain = keys.reduce(function(prevErrorArr, k) { - var errorValue = getValueByDataKey(entry, k, 0), lowerValue = mainValue[0] - Math.abs(__WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default()(errorValue) ? errorValue[0] : errorValue), upperValue = mainValue[1] + Math.abs(__WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default()(errorValue) ? errorValue[1] : errorValue); - return [ Math.min(lowerValue, prevErrorArr[0]), Math.max(upperValue, prevErrorArr[1]) ]; - }, [ 1 / 0, -1 / 0 ]); - return [ Math.min(errorDomain[0], result[0]), Math.max(errorDomain[1], result[1]) ]; - }, [ 1 / 0, -1 / 0 ]); - } - return null; - }, parseErrorBarsOfAxis = function(data, items, dataKey, axisType) { - var domains = items.map(function(item) { - return getDomainOfErrorBars(data, item, dataKey, axisType); - }).filter(function(entry) { - return !__WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(entry); - }); - return domains && domains.length ? domains.reduce(function(result, entry) { - return [ Math.min(result[0], entry[0]), Math.max(result[1], entry[1]) ]; - }, [ 1 / 0, -1 / 0 ]) : null; - }, getDomainOfItemsWithSameAxis = function(data, items, type, filterNil) { - var domains = items.map(function(item) { - var dataKey = item.props.dataKey; - return "number" === type && dataKey ? getDomainOfErrorBars(data, item, dataKey) || getDomainOfDataByKey(data, dataKey, type, filterNil) : getDomainOfDataByKey(data, dataKey, type, filterNil); - }); - if ("number" === type) return domains.reduce(function(result, entry) { - return [ Math.min(result[0], entry[0]), Math.max(result[1], entry[1]) ]; - }, [ 1 / 0, -1 / 0 ]); - var tag = {}; - return domains.reduce(function(result, entry) { - for (var i = 0, len = entry.length; i < len; i++) tag[entry[i]] || (tag[entry[i]] = !0, - result.push(entry[i])); - return result; - }, []); - }, isCategorialAxis = function(layout, axisType) { - return "horizontal" === layout && "xAxis" === axisType || "vertical" === layout && "yAxis" === axisType || "centric" === layout && "angleAxis" === axisType || "radial" === layout && "radiusAxis" === axisType; - }, getCoordinatesOfGrid = function(ticks, min, max) { - var hasMin = void 0, hasMax = void 0, values = ticks.map(function(entry) { - return entry.coordinate === min && (hasMin = !0), entry.coordinate === max && (hasMax = !0), - entry.coordinate; - }); - return hasMin || values.push(min), hasMax || values.push(max), values; - }, getTicksOfAxis = function(axis, isGrid, isAll) { - if (!axis) return null; - var scale = axis.scale, duplicateDomain = axis.duplicateDomain, type = axis.type, range = axis.range, offset = (isGrid || isAll) && "category" === type && scale.bandwidth ? scale.bandwidth() / 2 : 0; - return offset = "angleAxis" === axis.axisType ? 2 * Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.j)(range[0] - range[1]) * offset : offset, - isGrid && (axis.ticks || axis.niceTicks) ? (axis.ticks || axis.niceTicks).map(function(entry) { - var scaleContent = duplicateDomain ? duplicateDomain.indexOf(entry) : entry; - return { - coordinate: scale(scaleContent) + offset, - value: entry, - offset: offset - }; - }) : axis.isCategorial && axis.categoricalDomain ? axis.categoricalDomain.map(function(entry, index) { - return { - coordinate: scale(entry), - value: entry, - index: index, - offset: offset - }; - }) : scale.ticks && !isAll ? scale.ticks(axis.tickCount).map(function(entry) { - return { - coordinate: scale(entry) + offset, - value: entry, - offset: offset - }; - }) : scale.domain().map(function(entry, index) { - return { - coordinate: scale(entry) + offset, - value: duplicateDomain ? duplicateDomain[entry] : entry, - index: index, - offset: offset - }; - }); - }, combineEventHandlers = function(defaultHandler, parentHandler, childHandler) { - var customizedHandler = void 0; - return __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(childHandler) ? customizedHandler = childHandler : __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(parentHandler) && (customizedHandler = parentHandler), - __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(defaultHandler) || customizedHandler ? function(arg1, arg2, arg3, arg4) { - __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(defaultHandler) && defaultHandler(arg1, arg2, arg3, arg4), - __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(customizedHandler) && customizedHandler(arg1, arg2, arg3, arg4); - } : null; - }, parseScale = function(axis, chartType) { - var scale = axis.scale, type = axis.type, layout = axis.layout, axisType = axis.axisType; - if ("auto" === scale) return "radial" === layout && "radiusAxis" === axisType ? { - scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scaleBand(), - realScaleType: "band" - } : "radial" === layout && "angleAxis" === axisType ? { - scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scaleLinear(), - realScaleType: "linear" - } : "category" === type && chartType && (chartType.indexOf("LineChart") >= 0 || chartType.indexOf("AreaChart") >= 0) ? { - scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scalePoint(), - realScaleType: "point" - } : "category" === type ? { - scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scaleBand(), - realScaleType: "band" - } : { - scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scaleLinear(), - realScaleType: "linear" - }; - if (__WEBPACK_IMPORTED_MODULE_3_lodash_isString___default()(scale)) { - var name = "scale" + scale.slice(0, 1).toUpperCase() + scale.slice(1); - return { - scale: (__WEBPACK_IMPORTED_MODULE_12_d3_scale__[name] || __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scalePoint)(), - realScaleType: __WEBPACK_IMPORTED_MODULE_12_d3_scale__[name] ? name : "point" - }; - } - return __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(scale) ? { - scale: scale - } : { - scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scalePoint(), - realScaleType: "point" - }; - }, checkDomainOfScale = function(scale) { - var domain = scale.domain(); - if (domain && !(domain.length <= 2)) { - var len = domain.length, range = scale.range(), min = Math.min(range[0], range[1]) - 1e-4, max = Math.max(range[0], range[1]) + 1e-4, first = scale(domain[0]), last = scale(domain[len - 1]); - (first < min || first > max || last < min || last > max) && scale.domain([ domain[0], domain[len - 1] ]); - } - }, findPositionOfBar = function(barPosition, child) { - if (!barPosition) return null; - for (var i = 0, len = barPosition.length; i < len; i++) if (barPosition[i].item === child) return barPosition[i].position; - return null; - }, truncateByDomain = function(value, domain) { - if (!domain || 2 !== domain.length || !Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(domain[0]) || !Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(domain[1])) return value; - var min = Math.min(domain[0], domain[1]), max = Math.max(domain[0], domain[1]), result = [ value[0], value[1] ]; - return (!Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(value[0]) || value[0] < min) && (result[0] = min), - (!Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(value[1]) || value[1] > max) && (result[1] = max), - result[0] > max && (result[0] = max), result[1] < min && (result[1] = min), result; - }, offsetSign = function(series) { - var n = series.length; - if (!(n <= 0)) for (var j = 0, m = series[0].length; j < m; ++j) for (var positive = 0, negative = 0, i = 0; i < n; ++i) { - var value = __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default()(series[i][j][1]) ? series[i][j][0] : series[i][j][1]; - value >= 0 ? (series[i][j][0] = positive, series[i][j][1] = positive + value, positive = series[i][j][1]) : (series[i][j][0] = negative, - series[i][j][1] = negative + value, negative = series[i][j][1]); - } - }, STACK_OFFSET_MAP = { - sign: offsetSign, - expand: __WEBPACK_IMPORTED_MODULE_13_d3_shape__.o, - none: __WEBPACK_IMPORTED_MODULE_13_d3_shape__.p, - silhouette: __WEBPACK_IMPORTED_MODULE_13_d3_shape__.q, - wiggle: __WEBPACK_IMPORTED_MODULE_13_d3_shape__.r - }, getStackedData = function(data, stackItems, offsetType) { - var dataKeys = stackItems.map(function(item) { - return item.props.dataKey; - }); - return Object(__WEBPACK_IMPORTED_MODULE_13_d3_shape__.n)().keys(dataKeys).value(function(d, key) { - return +getValueByDataKey(d, key, 0); - }).order(__WEBPACK_IMPORTED_MODULE_13_d3_shape__.s).offset(STACK_OFFSET_MAP[offsetType])(data); - }, getStackGroupsByAxisId = function(data, _items, numericAxisId, cateAxisId, offsetType, reverseStackOrder) { - if (!data) return null; - var items = reverseStackOrder ? _items.reverse() : _items, stackGroups = items.reduce(function(result, item) { - var _item$props2 = item.props, stackId = _item$props2.stackId; - if (_item$props2.hide) return result; - var axisId = item.props[numericAxisId], parentGroup = result[axisId] || { - hasStack: !1, - stackGroups: {} - }; - if (Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.g)(stackId)) { - var childGroup = parentGroup.stackGroups[stackId] || { - numericAxisId: numericAxisId, - cateAxisId: cateAxisId, - items: [] }; - childGroup.items.push(item), parentGroup.hasStack = !0, parentGroup.stackGroups[stackId] = childGroup; - } else parentGroup.stackGroups[Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.k)("_stackId_")] = { - numericAxisId: numericAxisId, - cateAxisId: cateAxisId, - items: [ item ] - }; - return _extends({}, result, _defineProperty({}, axisId, parentGroup)); - }, {}); - return Object.keys(stackGroups).reduce(function(result, axisId) { - var group = stackGroups[axisId]; - return group.hasStack && (group.stackGroups = Object.keys(group.stackGroups).reduce(function(res, stackId) { - var g = group.stackGroups[stackId]; - return _extends({}, res, _defineProperty({}, stackId, { - numericAxisId: numericAxisId, - cateAxisId: cateAxisId, - items: g.items, - stackedData: getStackedData(data, g.items, offsetType) - })); - }, {})), _extends({}, result, _defineProperty({}, axisId, group)); - }, {}); - }, calculateDomainOfTicks = function(ticks, type) { - return "number" === type ? [ Math.min.apply(null, ticks), Math.max.apply(null, ticks) ] : ticks; - }, getTicksOfScale = function(scale, opts) { - var realScaleType = opts.realScaleType, type = opts.type, tickCount = opts.tickCount, originalDomain = opts.originalDomain, allowDecimals = opts.allowDecimals, scaleType = realScaleType || opts.scale; - if ("auto" !== scaleType && "linear" !== scaleType) return null; - if (tickCount && "number" === type && originalDomain && ("auto" === originalDomain[0] || "auto" === originalDomain[1])) { - var domain = scale.domain(), tickValues = Object(__WEBPACK_IMPORTED_MODULE_11_recharts_scale__.getNiceTickValues)(domain, tickCount, allowDecimals); - return scale.domain(calculateDomainOfTicks(tickValues, type)), { - niceTicks: tickValues - }; - } - if (tickCount && "number" === type) { - var _domain = scale.domain(); - return { - niceTicks: Object(__WEBPACK_IMPORTED_MODULE_11_recharts_scale__.getTickValuesFixedDomain)(_domain, tickCount, allowDecimals) - }; - } - return null; - }, getCateCoordinateOfLine = function(_ref6) { - var axis = _ref6.axis, ticks = _ref6.ticks, bandSize = _ref6.bandSize, entry = _ref6.entry, index = _ref6.index; - if ("category" === axis.type) { - if (!axis.allowDuplicatedCategory && axis.dataKey && !__WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(entry[axis.dataKey])) { - var matchedTick = Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.a)(ticks, "value", entry[axis.dataKey]); - if (matchedTick) return matchedTick.coordinate + bandSize / 2; - } - return ticks[index] ? ticks[index].coordinate + bandSize / 2 : null; - } - var value = getValueByDataKey(entry, axis.dataKey); - return __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(value) ? null : axis.scale(value); - }, getCateCoordinateOfBar = function(_ref7) { - var axis = _ref7.axis, ticks = _ref7.ticks, offset = _ref7.offset, bandSize = _ref7.bandSize, entry = _ref7.entry, index = _ref7.index; - if ("category" === axis.type) return ticks[index] ? ticks[index].coordinate + offset : null; - var value = getValueByDataKey(entry, axis.dataKey, axis.domain[index]); - return __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(value) ? null : axis.scale(value) - bandSize / 2 + offset; - }, getBaseValueOfBar = function(_ref8) { - var numericAxis = _ref8.numericAxis, domain = numericAxis.scale.domain(); - if ("number" === numericAxis.type) { - var min = Math.min(domain[0], domain[1]), max = Math.max(domain[0], domain[1]); - return min <= 0 && max >= 0 ? 0 : max < 0 ? max : min; - } - return domain[0]; - }, detectReferenceElementsDomain = function(children, domain, axisId, axisType, specifiedTicks) { - var lines = Object(__WEBPACK_IMPORTED_MODULE_20__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_16__cartesian_ReferenceLine__.a), dots = Object(__WEBPACK_IMPORTED_MODULE_20__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_15__cartesian_ReferenceDot__.a), elements = lines.concat(dots), areas = Object(__WEBPACK_IMPORTED_MODULE_20__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_17__cartesian_ReferenceArea__.a), idKey = axisType + "Id", valueKey = axisType[0], finalDomain = domain; - if (elements.length && (finalDomain = elements.reduce(function(result, el) { - if (el.props[idKey] === axisId && el.props.alwaysShow && Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(el.props[valueKey])) { - var value = el.props[valueKey]; - return [ Math.min(result[0], value), Math.max(result[1], value) ]; - } - return result; - }, finalDomain)), areas.length) { - var key1 = valueKey + "1", key2 = valueKey + "2"; - finalDomain = areas.reduce(function(result, el) { - if (el.props[idKey] === axisId && el.props.alwaysShow && Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(el.props[key1]) && Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(el.props[key2])) { - var value1 = el.props[key1], value2 = el.props[key2]; - return [ Math.min(result[0], value1, value2), Math.max(result[1], value1, value2) ]; - } - return result; - }, finalDomain); - } - return specifiedTicks && specifiedTicks.length && (finalDomain = specifiedTicks.reduce(function(result, tick) { - return Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(tick) ? [ Math.min(result[0], tick), Math.max(result[1], tick) ] : result; - }, finalDomain)), finalDomain; - }, getStackedDataOfItem = function(item, stackGroups) { - var stackId = item.props.stackId; - if (Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.g)(stackId)) { - var group = stackGroups[stackId]; - if (group && group.items.length) { - for (var itemIndex = -1, i = 0, len = group.items.length; i < len; i++) if (group.items[i] === item) { - itemIndex = i; - break; - } - return itemIndex >= 0 ? group.stackedData[itemIndex] : null; - } - } - return null; - }, getDomainOfSingle = function(data) { - return data.reduce(function(result, entry) { - return [ Math.min.apply(null, entry.concat([ result[0] ]).filter(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)), Math.max.apply(null, entry.concat([ result[1] ]).filter(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)) ]; - }, [ 1 / 0, -1 / 0 ]); - }, getDomainOfStackGroups = function(stackGroups, startIndex, endIndex) { - return Object.keys(stackGroups).reduce(function(result, stackId) { - var group = stackGroups[stackId], stackedData = group.stackedData, domain = stackedData.reduce(function(res, entry) { - var s = getDomainOfSingle(entry.slice(startIndex, endIndex + 1)); - return [ Math.min(res[0], s[0]), Math.max(res[1], s[1]) ]; - }, [ 1 / 0, -1 / 0 ]); - return [ Math.min(domain[0], result[0]), Math.max(domain[1], result[1]) ]; - }, [ 1 / 0, -1 / 0 ]).map(function(result) { - return result === 1 / 0 || result === -1 / 0 ? 0 : result; - }); - }, MIN_VALUE_REG = /^dataMin[\s]*-[\s]*([0-9]+([.]{1}[0-9]+){0,1})$/, MAX_VALUE_REG = /^dataMax[\s]*\+[\s]*([0-9]+([.]{1}[0-9]+){0,1})$/, parseSpecifiedDomain = function(specifiedDomain, dataDomain, allowDataOverflow) { - if (!__WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default()(specifiedDomain)) return dataDomain; - var domain = []; - if (Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(specifiedDomain[0])) domain[0] = allowDataOverflow ? specifiedDomain[0] : Math.min(specifiedDomain[0], dataDomain[0]); else if (MIN_VALUE_REG.test(specifiedDomain[0])) { - var value = +MIN_VALUE_REG.exec(specifiedDomain[0])[1]; - domain[0] = dataDomain[0] - value; - } else __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(specifiedDomain[0]) ? domain[0] = specifiedDomain[0](dataDomain[0]) : domain[0] = dataDomain[0]; - if (Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.h)(specifiedDomain[1])) domain[1] = allowDataOverflow ? specifiedDomain[1] : Math.max(specifiedDomain[1], dataDomain[1]); else if (MAX_VALUE_REG.test(specifiedDomain[1])) { - var _value = +MAX_VALUE_REG.exec(specifiedDomain[1])[1]; - domain[1] = dataDomain[1] + _value; - } else __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(specifiedDomain[1]) ? domain[1] = specifiedDomain[1](dataDomain[1]) : domain[1] = dataDomain[1]; - return domain; - }, validateCoordinateInRange = function(coordinate, scale) { - if (!scale) return !1; - var range = scale.range(), first = range[0], last = range[range.length - 1]; - return first <= last ? coordinate >= first && coordinate <= last : coordinate >= last && coordinate <= first; - }, getBandSizeOfAxis = function(axis, ticks) { - if (axis && axis.scale && axis.scale.bandwidth) return axis.scale.bandwidth(); - if (axis && ticks && ticks.length >= 2) { - for (var orderedTicks = __WEBPACK_IMPORTED_MODULE_1_lodash_sortBy___default()(ticks, function(o) { - return o.coordinate; - }), bandSize = 1 / 0, i = 1, len = orderedTicks.length; i < len; i++) { - var cur = orderedTicks[i], prev = orderedTicks[i - 1]; - bandSize = Math.min((cur.coordinate || 0) - (prev.coordinate || 0), bandSize); - } - return bandSize === 1 / 0 ? 0 : bandSize; - } - return 0; - }, parseDomainOfCategoryAxis = function(specifiedDomain, calculatedDomain, axisChild) { - return specifiedDomain && specifiedDomain.length ? __WEBPACK_IMPORTED_MODULE_0_lodash_isEqual___default()(specifiedDomain, __WEBPACK_IMPORTED_MODULE_9_lodash_get___default()(axisChild, "type.defaultProps.domain")) ? calculatedDomain : specifiedDomain : calculatedDomain; - }; -}, function(module, exports) { - var core = module.exports = { - version: "2.5.7" - }; - "number" == typeof __e && (__e = core); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function newInterval(floori, offseti, count, field) { - function interval(date) { - return floori(date = new Date(+date)), date; - } - return interval.floor = interval, interval.ceil = function(date) { - return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date; - }, interval.round = function(date) { - var d0 = interval(date), d1 = interval.ceil(date); - return date - d0 < d1 - date ? d0 : d1; - }, interval.offset = function(date, step) { - return offseti(date = new Date(+date), null == step ? 1 : Math.floor(step)), date; - }, interval.range = function(start, stop, step) { - var previous, range = []; - if (start = interval.ceil(start), step = null == step ? 1 : Math.floor(step), !(start < stop && step > 0)) return range; - do { - range.push(previous = new Date(+start)), offseti(start, step), floori(start); - } while (previous < start && start < stop); - return range; - }, interval.filter = function(test) { - return newInterval(function(date) { - if (date >= date) for (;floori(date), !test(date); ) date.setTime(date - 1); - }, function(date, step) { - if (date >= date) if (step < 0) for (;++step <= 0; ) for (;offseti(date, -1), !test(date); ) ; else for (;--step >= 0; ) for (;offseti(date, 1), - !test(date); ) ; - }); - }, count && (interval.count = function(start, end) { - return t0.setTime(+start), t1.setTime(+end), floori(t0), floori(t1), Math.floor(count(t0, t1)); - }, interval.every = function(step) { - return step = Math.floor(step), isFinite(step) && step > 0 ? step > 1 ? interval.filter(field ? function(d) { - return field(d) % step == 0; - } : function(d) { - return interval.count(0, d) % step == 0; - }) : interval : null; - }), interval; - } - __webpack_exports__.a = newInterval; - var t0 = new Date(), t1 = new Date(); -}, function(module, exports, __webpack_require__) { - var global = __webpack_require__(24), core = __webpack_require__(17), ctx = __webpack_require__(51), hide = __webpack_require__(39), has = __webpack_require__(54), $export = function(type, name, source) { - var key, own, out, IS_FORCED = type & $export.F, IS_GLOBAL = type & $export.G, IS_STATIC = type & $export.S, IS_PROTO = type & $export.P, IS_BIND = type & $export.B, IS_WRAP = type & $export.W, exports = IS_GLOBAL ? core : core[name] || (core[name] = {}), expProto = exports.prototype, target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {}).prototype; - IS_GLOBAL && (source = name); - for (key in source) (own = !IS_FORCED && target && void 0 !== target[key]) && has(exports, key) || (out = own ? target[key] : source[key], - exports[key] = IS_GLOBAL && "function" != typeof target[key] ? source[key] : IS_BIND && own ? ctx(out, global) : IS_WRAP && target[key] == out ? function(C) { - var F = function(a, b, c) { - if (this instanceof C) { - switch (arguments.length) { - case 0: - return new C(); - - case 1: - return new C(a); - - case 2: - return new C(a, b); - } - return new C(a, b, c); - } - return C.apply(this, arguments); - }; - return F.prototype = C.prototype, F; - }(out) : IS_PROTO && "function" == typeof out ? ctx(Function.call, out) : out, IS_PROTO && ((exports.virtual || (exports.virtual = {}))[key] = out, - type & $export.R && expProto && !expProto[key] && hide(expProto, key, out))); - }; - $export.F = 1, $export.G = 2, $export.S = 4, $export.P = 8, $export.B = 16, $export.W = 32, - $export.U = 64, $export.R = 128, module.exports = $export; -}, function(module, exports) { - function isNil(value) { - return null == value; - } - module.exports = isNil; -}, function(module, exports, __webpack_require__) { - var store = __webpack_require__(151)("wks"), uid = __webpack_require__(103), Symbol = __webpack_require__(24).Symbol, USE_SYMBOL = "function" == typeof Symbol; - (module.exports = function(name) { - return store[name] || (store[name] = USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)("Symbol." + name)); - }).store = store; -}, function(module, exports, __webpack_require__) { - var anObject = __webpack_require__(52), IE8_DOM_DEFINE = __webpack_require__(224), toPrimitive = __webpack_require__(145), dP = Object.defineProperty; - exports.f = __webpack_require__(25) ? Object.defineProperty : function(O, P, Attributes) { - if (anObject(O), P = toPrimitive(P, !0), anObject(Attributes), IE8_DOM_DEFINE) try { - return dP(O, P, Attributes); - } catch (e) {} - if ("get" in Attributes || "set" in Attributes) throw TypeError("Accessors not supported!"); - return "value" in Attributes && (O[P] = Attributes.value), O; - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _defineProperty(obj, key, value) { - return key in obj ? Object.defineProperty(obj, key, { - value: value, - enumerable: !0, - configurable: !0, - writable: !0 - }) : obj[key] = value, obj; - } - __webpack_require__.d(__webpack_exports__, "a", function() { - return RADIAN; - }), __webpack_require__.d(__webpack_exports__, "e", function() { - return polarToCartesian; - }), __webpack_require__.d(__webpack_exports__, "c", function() { - return getMaxRadius; - }), __webpack_require__.d(__webpack_exports__, "b", function() { - return formatAxisMap; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return inRangeOfSector; - }); - var __WEBPACK_IMPORTED_MODULE_0_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_1__DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_2__ChartUtils__ = __webpack_require__(16), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, RADIAN = Math.PI / 180, radianToDegree = function(angleInRadian) { - return 180 * angleInRadian / Math.PI; - }, polarToCartesian = function(cx, cy, radius, angle) { - return { - x: cx + Math.cos(-RADIAN * angle) * radius, - y: cy + Math.sin(-RADIAN * angle) * radius - }; - }, getMaxRadius = function(width, height) { - var offset = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : { - top: 0, - right: 0, - bottom: 0, - left: 0 - }; - return Math.min(Math.abs(width - (offset.left || 0) - (offset.right || 0)), Math.abs(height - (offset.top || 0) - (offset.bottom || 0))) / 2; - }, formatAxisMap = function(props, axisMap, offset, axisType, chartName) { - var width = props.width, height = props.height, startAngle = props.startAngle, endAngle = props.endAngle, cx = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.d)(props.cx, width, width / 2), cy = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.d)(props.cy, height, height / 2), maxRadius = getMaxRadius(width, height, offset), innerRadius = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.d)(props.innerRadius, maxRadius, 0), outerRadius = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.d)(props.outerRadius, maxRadius, .8 * maxRadius); - return Object.keys(axisMap).reduce(function(result, id) { - var axis = axisMap[id], domain = axis.domain, reversed = axis.reversed, range = void 0; - __WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(axis.range) ? ("angleAxis" === axisType ? range = [ startAngle, endAngle ] : "radiusAxis" === axisType && (range = [ innerRadius, outerRadius ]), - reversed && (range = [ range[1], range[0] ])) : (range = axis.range, startAngle = range[0], - endAngle = range[1]); - var _parseScale = Object(__WEBPACK_IMPORTED_MODULE_2__ChartUtils__.A)(axis, chartName), realScaleType = _parseScale.realScaleType, scale = _parseScale.scale; - scale.domain(domain).range(range), Object(__WEBPACK_IMPORTED_MODULE_2__ChartUtils__.c)(scale); - var ticks = Object(__WEBPACK_IMPORTED_MODULE_2__ChartUtils__.v)(scale, _extends({}, axis, { - realScaleType: realScaleType - })), finalAxis = _extends({}, axis, ticks, { - range: range, - radius: outerRadius, - realScaleType: realScaleType, - scale: scale, - cx: cx, - cy: cy, - innerRadius: innerRadius, - outerRadius: outerRadius, - startAngle: startAngle, - endAngle: endAngle - }); - return _extends({}, result, _defineProperty({}, id, finalAxis)); - }, {}); - }, distanceBetweenPoints = function(point, anotherPoint) { - var x1 = point.x, y1 = point.y, x2 = anotherPoint.x, y2 = anotherPoint.y; - return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); - }, getAngleOfPoint = function(_ref, _ref2) { - var x = _ref.x, y = _ref.y, cx = _ref2.cx, cy = _ref2.cy, radius = distanceBetweenPoints({ - x: x, - y: y - }, { - x: cx, - y: cy - }); - if (radius <= 0) return { - radius: radius - }; - var cos = (x - cx) / radius, angleInRadian = Math.acos(cos); - return y > cy && (angleInRadian = 2 * Math.PI - angleInRadian), { - radius: radius, - angle: radianToDegree(angleInRadian), - angleInRadian: angleInRadian - }; - }, formatAngleOfSector = function(_ref3) { - var startAngle = _ref3.startAngle, endAngle = _ref3.endAngle, startCnt = Math.floor(startAngle / 360), endCnt = Math.floor(endAngle / 360), min = Math.min(startCnt, endCnt); - return { - startAngle: startAngle - 360 * min, - endAngle: endAngle - 360 * min - }; - }, reverseFormatAngleOfSetor = function(angle, _ref4) { - var startAngle = _ref4.startAngle, endAngle = _ref4.endAngle, startCnt = Math.floor(startAngle / 360), endCnt = Math.floor(endAngle / 360); - return angle + 360 * Math.min(startCnt, endCnt); - }, inRangeOfSector = function(_ref5, sector) { - var x = _ref5.x, y = _ref5.y, _getAngleOfPoint = getAngleOfPoint({ - x: x, - y: y - }, sector), radius = _getAngleOfPoint.radius, angle = _getAngleOfPoint.angle, innerRadius = sector.innerRadius, outerRadius = sector.outerRadius; - if (radius < innerRadius || radius > outerRadius) return !1; - if (0 === radius) return !0; - var _formatAngleOfSector = formatAngleOfSector(sector), startAngle = _formatAngleOfSector.startAngle, endAngle = _formatAngleOfSector.endAngle, formatAngle = angle, inRange = void 0; - if (startAngle <= endAngle) { - for (;formatAngle > endAngle; ) formatAngle -= 360; - for (;formatAngle < startAngle; ) formatAngle += 360; - inRange = formatAngle >= startAngle && formatAngle <= endAngle; - } else { - for (;formatAngle > startAngle; ) formatAngle -= 360; - for (;formatAngle < endAngle; ) formatAngle += 360; - inRange = formatAngle >= endAngle && formatAngle <= startAngle; - } - return inRange ? _extends({}, sector, { - radius: radius, - angle: reverseFormatAngleOfSetor(formatAngle, sector) - }) : null; - }; -}, function(module, exports) { - var global = module.exports = "undefined" != typeof window && window.Math == Math ? window : "undefined" != typeof self && self.Math == Math ? self : Function("return this")(); - "number" == typeof __g && (__g = global); -}, function(module, exports, __webpack_require__) { - module.exports = !__webpack_require__(53)(function() { - return 7 != Object.defineProperty({}, "a", { - get: function() { - return 7; - } - }).a; - }); -}, function(module, exports, __webpack_require__) { - module.exports = { - default: __webpack_require__(394), - __esModule: !0 - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0, exports.default = function(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0; - var _defineProperty = __webpack_require__(154), _defineProperty2 = function(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - }(_defineProperty); - exports.default = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), (0, _defineProperty2.default)(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(); -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0; - var _typeof2 = __webpack_require__(105), _typeof3 = function(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - }(_typeof2); - exports.default = function(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" !== (void 0 === call ? "undefined" : (0, _typeof3.default)(call)) && "function" != typeof call ? self : call; - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - exports.__esModule = !0; - var _setPrototypeOf = __webpack_require__(411), _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf), _create = __webpack_require__(415), _create2 = _interopRequireDefault(_create), _typeof2 = __webpack_require__(105), _typeof3 = _interopRequireDefault(_typeof2); - exports.default = function(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + (void 0 === superClass ? "undefined" : (0, - _typeof3.default)(superClass))); - subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (_setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass); - }; -}, function(module, exports, __webpack_require__) { - var freeGlobal = __webpack_require__(268), freeSelf = "object" == typeof self && self && self.Object === Object && self, root = freeGlobal || freeSelf || Function("return this")(); - module.exports = root; -}, function(module, exports) { - function isObject(value) { - var type = typeof value; - return null != value && ("object" == type || "function" == type); - } - module.exports = isObject; -}, function(module, exports, __webpack_require__) { - "use strict"; - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - Object.defineProperty(exports, "__esModule", { - value: !0 - }), exports.translateStyle = exports.AnimateGroup = exports.configBezier = exports.configSpring = void 0; - var _Animate = __webpack_require__(287), _Animate2 = _interopRequireDefault(_Animate), _easing = __webpack_require__(305), _util = __webpack_require__(132), _AnimateGroup = __webpack_require__(762), _AnimateGroup2 = _interopRequireDefault(_AnimateGroup); - exports.configSpring = _easing.configSpring, exports.configBezier = _easing.configBezier, - exports.AnimateGroup = _AnimateGroup2.default, exports.translateStyle = _util.translateStyle, - exports.default = _Animate2.default; -}, function(module, exports) { - var isArray = Array.isArray; - module.exports = isArray; -}, function(module, exports) { - module.exports = function(it) { - return "object" == typeof it ? null !== it : "function" == typeof it; - }; -}, function(module, exports, __webpack_require__) { - var freeGlobal = __webpack_require__(292), freeSelf = "object" == typeof self && self && self.Object === Object && self, root = freeGlobal || freeSelf || Function("return this")(); - module.exports = root; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - var __WEBPACK_IMPORTED_MODULE_0__src_bisect__ = __webpack_require__(332); - __webpack_require__.d(__webpack_exports__, "b", function() { - return __WEBPACK_IMPORTED_MODULE_0__src_bisect__.a; - }); - var __WEBPACK_IMPORTED_MODULE_1__src_ascending__ = __webpack_require__(69); - __webpack_require__.d(__webpack_exports__, "a", function() { - return __WEBPACK_IMPORTED_MODULE_1__src_ascending__.a; - }); - var __WEBPACK_IMPORTED_MODULE_2__src_bisector__ = __webpack_require__(333); - __webpack_require__.d(__webpack_exports__, "c", function() { - return __WEBPACK_IMPORTED_MODULE_2__src_bisector__.a; - }); - var __WEBPACK_IMPORTED_MODULE_18__src_quantile__ = (__webpack_require__(848), __webpack_require__(849), - __webpack_require__(335), __webpack_require__(337), __webpack_require__(850), __webpack_require__(853), - __webpack_require__(854), __webpack_require__(341), __webpack_require__(855), __webpack_require__(856), - __webpack_require__(857), __webpack_require__(858), __webpack_require__(342), __webpack_require__(334), - __webpack_require__(859), __webpack_require__(204)); - __webpack_require__.d(__webpack_exports__, "d", function() { - return __WEBPACK_IMPORTED_MODULE_18__src_quantile__.a; - }); - var __WEBPACK_IMPORTED_MODULE_19__src_range__ = __webpack_require__(339); - __webpack_require__.d(__webpack_exports__, "e", function() { - return __WEBPACK_IMPORTED_MODULE_19__src_range__.a; - }); - var __WEBPACK_IMPORTED_MODULE_23__src_ticks__ = (__webpack_require__(860), __webpack_require__(861), - __webpack_require__(862), __webpack_require__(340)); - __webpack_require__.d(__webpack_exports__, "h", function() { - return __WEBPACK_IMPORTED_MODULE_23__src_ticks__.a; - }), __webpack_require__.d(__webpack_exports__, "f", function() { - return __WEBPACK_IMPORTED_MODULE_23__src_ticks__.b; - }), __webpack_require__.d(__webpack_exports__, "g", function() { - return __WEBPACK_IMPORTED_MODULE_23__src_ticks__.c; - }); - __webpack_require__(343), __webpack_require__(336), __webpack_require__(863); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_require__.d(__webpack_exports__, "d", function() { - return durationSecond; - }), __webpack_require__.d(__webpack_exports__, "c", function() { - return durationMinute; - }), __webpack_require__.d(__webpack_exports__, "b", function() { - return durationHour; - }), __webpack_require__.d(__webpack_exports__, "a", function() { - return durationDay; - }), __webpack_require__.d(__webpack_exports__, "e", function() { - return durationWeek; - }); - var durationSecond = 1e3, durationMinute = 6e4, durationHour = 36e5, durationDay = 864e5, durationWeek = 6048e5; -}, function(module, exports, __webpack_require__) { - var dP = __webpack_require__(22), createDesc = __webpack_require__(75); - module.exports = __webpack_require__(25) ? function(object, key, value) { - return dP.f(object, key, createDesc(1, value)); - } : function(object, key, value) { - return object[key] = value, object; - }; -}, function(module, exports) { - var g; - g = function() { - return this; - }(); - try { - g = g || Function("return this")() || (0, eval)("this"); - } catch (e) { - "object" == typeof window && (g = window); - } - module.exports = g; -}, function(module, exports, __webpack_require__) { - function baseGetTag(value) { - return null == value ? void 0 === value ? undefinedTag : nullTag : symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value); - } - var Symbol = __webpack_require__(83), getRawTag = __webpack_require__(603), objectToString = __webpack_require__(604), nullTag = "[object Null]", undefinedTag = "[object Undefined]", symToStringTag = Symbol ? Symbol.toStringTag : void 0; - module.exports = baseGetTag; -}, function(module, exports) { - function isObjectLike(value) { - return null != value && "object" == typeof value; - } - module.exports = isObjectLike; -}, function(module, exports) { - function isObjectLike(value) { - return null != value && "object" == typeof value; - } - module.exports = isObjectLike; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _toConsumableArray(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - return arr2; - } - return Array.from(arr); - } - function Label(props) { - var viewBox = props.viewBox, position = props.position, value = props.value, children = props.children, content = props.content, _props$className = props.className, className = void 0 === _props$className ? "" : _props$className; - if (!viewBox || __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(value) && __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(children) && !Object(__WEBPACK_IMPORTED_MODULE_3_react__.isValidElement)(content) && !__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(content)) return null; - if (Object(__WEBPACK_IMPORTED_MODULE_3_react__.isValidElement)(content)) return Object(__WEBPACK_IMPORTED_MODULE_3_react__.cloneElement)(content, props); - var label = void 0; - if (__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(content)) { - if (label = content(props), Object(__WEBPACK_IMPORTED_MODULE_3_react__.isValidElement)(label)) return label; - } else label = getLabel(props); - var isPolarLabel = isPolar(viewBox), attrs = Object(__WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__.k)(props); - if (isPolarLabel && ("insideStart" === position || "insideEnd" === position || "end" === position)) return renderRadialLabel(props, label, attrs); - var positionAttrs = isPolarLabel ? getAttrsOfPolarLabel(props) : getAttrsOfCartesianLabel(props); - return __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_6__Text__.a, _extends({ - className: __WEBPACK_IMPORTED_MODULE_5_classnames___default()("recharts-label", className) - }, attrs, positionAttrs), label); - } - var __WEBPACK_IMPORTED_MODULE_0_lodash_isObject__ = __webpack_require__(32), __WEBPACK_IMPORTED_MODULE_0_lodash_isObject___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isObject__), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_2_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_3_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_3_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_react__), __WEBPACK_IMPORTED_MODULE_4_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_4_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_prop_types__), __WEBPACK_IMPORTED_MODULE_5_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_5_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_classnames__), __WEBPACK_IMPORTED_MODULE_6__Text__ = __webpack_require__(61), __WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__ = __webpack_require__(4), __WEBPACK_IMPORTED_MODULE_8__util_DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_9__util_PolarUtils__ = __webpack_require__(23), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, cartesianViewBoxShape = __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.shape({ - x: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - y: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - width: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number - }), polarViewBoxShape = __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.shape({ - cx: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - cy: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - innerRadius: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - outerRadius: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - startAngle: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - endAngle: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number - }), propTypes = { - viewBox: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.oneOfType([ cartesianViewBoxShape, polarViewBoxShape ]), - formatter: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.func, - value: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.string ]), - offset: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.number, - position: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.oneOf([ "top", "left", "right", "bottom", "inside", "outside", "insideLeft", "insideRight", "insideTop", "insideBottom", "insideTopLeft", "insideBottomLeft", "insideTopRight", "insideBottomRight", "insideStart", "insideEnd", "end", "center" ]), - children: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.node), __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.node ]), - className: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.string, - content: __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.element, __WEBPACK_IMPORTED_MODULE_4_prop_types___default.a.func ]) - }, defaultProps = { - offset: 5 - }, getLabel = function(props) { - var value = props.value, formatter = props.formatter, label = __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(props.children) ? value : props.children; - return __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(formatter) ? formatter(label) : label; - }, getDeltaAngle = function(startAngle, endAngle) { - return Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.j)(endAngle - startAngle) * Math.min(Math.abs(endAngle - startAngle), 360); - }, renderRadialLabel = function(labelProps, label, attrs) { - var position = labelProps.position, viewBox = labelProps.viewBox, offset = labelProps.offset, className = labelProps.className, cx = viewBox.cx, cy = viewBox.cy, innerRadius = viewBox.innerRadius, outerRadius = viewBox.outerRadius, startAngle = viewBox.startAngle, endAngle = viewBox.endAngle, clockWise = viewBox.clockWise, radius = (innerRadius + outerRadius) / 2, deltaAngle = getDeltaAngle(startAngle, endAngle), sign = deltaAngle >= 0 ? 1 : -1, labelAngle = void 0, direction = void 0; - "insideStart" === position ? (labelAngle = startAngle + sign * offset, direction = clockWise) : "insideEnd" === position ? (labelAngle = endAngle - sign * offset, - direction = !clockWise) : "end" === position && (labelAngle = endAngle + sign * offset, - direction = clockWise), direction = deltaAngle <= 0 ? direction : !direction; - var startPoint = Object(__WEBPACK_IMPORTED_MODULE_9__util_PolarUtils__.e)(cx, cy, radius, labelAngle), endPoint = Object(__WEBPACK_IMPORTED_MODULE_9__util_PolarUtils__.e)(cx, cy, radius, labelAngle + 359 * (direction ? 1 : -1)), path = "M" + startPoint.x + "," + startPoint.y + "\n A" + radius + "," + radius + ",0,1," + (direction ? 0 : 1) + ",\n " + endPoint.x + "," + endPoint.y, id = __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(labelProps.id) ? Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.k)("recharts-radial-line-") : labelProps.id; - return __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement("text", _extends({}, attrs, { - dominantBaseline: "central", - className: __WEBPACK_IMPORTED_MODULE_5_classnames___default()("recharts-radial-bar-label", className) - }), __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement("defs", null, __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement("path", { - id: id, - d: path - })), __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement("textPath", { - xlinkHref: "#" + id - }, label)); - }, getAttrsOfPolarLabel = function(props) { - var viewBox = props.viewBox, offset = props.offset, position = props.position, cx = viewBox.cx, cy = viewBox.cy, innerRadius = viewBox.innerRadius, outerRadius = viewBox.outerRadius, startAngle = viewBox.startAngle, endAngle = viewBox.endAngle, midAngle = (startAngle + endAngle) / 2; - if ("outside" === position) { - var _polarToCartesian = Object(__WEBPACK_IMPORTED_MODULE_9__util_PolarUtils__.e)(cx, cy, outerRadius + offset, midAngle), _x = _polarToCartesian.x; - return { - x: _x, - y: _polarToCartesian.y, - textAnchor: _x >= cx ? "start" : "end", - verticalAnchor: "middle" - }; - } - if ("center" === position) return { - x: cx, - y: cy, - textAnchor: "middle", - verticalAnchor: "middle" - }; - var r = (innerRadius + outerRadius) / 2, _polarToCartesian2 = Object(__WEBPACK_IMPORTED_MODULE_9__util_PolarUtils__.e)(cx, cy, r, midAngle); - return { - x: _polarToCartesian2.x, - y: _polarToCartesian2.y, - textAnchor: "middle", - verticalAnchor: "middle" - }; - }, getAttrsOfCartesianLabel = function(props) { - var viewBox = props.viewBox, offset = props.offset, position = props.position, x = viewBox.x, y = viewBox.y, width = viewBox.width, height = viewBox.height, sign = height >= 0 ? 1 : -1; - return "top" === position ? { - x: x + width / 2, - y: y - sign * offset, - textAnchor: "middle", - verticalAnchor: "end" - } : "bottom" === position ? { - x: x + width / 2, - y: y + height + sign * offset, - textAnchor: "middle", - verticalAnchor: "start" - } : "left" === position ? { - x: x - offset, - y: y + height / 2, - textAnchor: "end", - verticalAnchor: "middle" - } : "right" === position ? { - x: x + width + offset, - y: y + height / 2, - textAnchor: "start", - verticalAnchor: "middle" - } : "insideLeft" === position ? { - x: x + offset, - y: y + height / 2, - textAnchor: "start", - verticalAnchor: "middle" - } : "insideRight" === position ? { - x: x + width - offset, - y: y + height / 2, - textAnchor: "end", - verticalAnchor: "middle" - } : "insideTop" === position ? { - x: x + width / 2, - y: y + sign * offset, - textAnchor: "middle", - verticalAnchor: "start" - } : "insideBottom" === position ? { - x: x + width / 2, - y: y + height - sign * offset, - textAnchor: "middle", - verticalAnchor: "end" - } : "insideTopLeft" === position ? { - x: x + offset, - y: y + sign * offset, - textAnchor: "start", - verticalAnchor: "start" - } : "insideTopRight" === position ? { - x: x + width - offset, - y: y + sign * offset, - textAnchor: "end", - verticalAnchor: "start" - } : "insideBottomLeft" === position ? { - x: x + offset, - y: y + height - sign * offset, - textAnchor: "start", - verticalAnchor: "end" - } : "insideBottomRight" === position ? { - x: x + width - offset, - y: y + height - sign * offset, - textAnchor: "end", - verticalAnchor: "end" - } : __WEBPACK_IMPORTED_MODULE_0_lodash_isObject___default()(position) && (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(position.x) || Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.i)(position.x)) && (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(position.y) || Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.i)(position.y)) ? { - x: x + Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.d)(position.x, width), - y: y + Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.d)(position.y, height), - textAnchor: "end", - verticalAnchor: "end" - } : { - x: x + width / 2, - y: y + height / 2, - textAnchor: "middle", - verticalAnchor: "middle" - }; - }, isPolar = function(viewBox) { - return Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(viewBox.cx); - }; - Label.displayName = "Label", Label.defaultProps = defaultProps, Label.propTypes = propTypes; - var parseViewBox = function(props) { - var cx = props.cx, cy = props.cy, angle = props.angle, startAngle = props.startAngle, endAngle = props.endAngle, r = props.r, radius = props.radius, innerRadius = props.innerRadius, outerRadius = props.outerRadius, x = props.x, y = props.y, top = props.top, left = props.left, width = props.width, height = props.height, clockWise = props.clockWise; - if (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(width) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(height)) { - if (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(x) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(y)) return { - x: x, - y: y, - width: width, - height: height - }; - if (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(top) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(left)) return { - x: top, - y: left, - width: width, - height: height - }; - } - return Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(x) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(y) ? { - x: x, - y: y, - width: 0, - height: 0 - } : Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(cx) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(cy) ? { - cx: cx, - cy: cy, - startAngle: startAngle || angle || 0, - endAngle: endAngle || angle || 0, - innerRadius: innerRadius || 0, - outerRadius: outerRadius || radius || r || 0, - clockWise: clockWise - } : props.viewBox ? props.viewBox : {}; - }, parseLabel = function(label, viewBox) { - return label ? !0 === label ? __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement(Label, { - key: "label-implicit", - viewBox: viewBox - }) : Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(label) ? __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement(Label, { - key: "label-implicit", - viewBox: viewBox, - value: label - }) : Object(__WEBPACK_IMPORTED_MODULE_3_react__.isValidElement)(label) || __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(label) ? __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement(Label, { - key: "label-implicit", - content: label, - viewBox: viewBox - }) : __WEBPACK_IMPORTED_MODULE_0_lodash_isObject___default()(label) ? __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement(Label, _extends({ - viewBox: viewBox - }, label, { - key: "label-implicit" - })) : null : null; - }, renderCallByParent = function(parentProps, viewBox) { - var ckeckPropsLabel = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2]; - if (!parentProps || !parentProps.children && ckeckPropsLabel && !parentProps.label) return null; - var children = parentProps.children, parentViewBox = parseViewBox(parentProps), explicitChilren = Object(__WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__.h)(children, Label).map(function(child, index) { - return Object(__WEBPACK_IMPORTED_MODULE_3_react__.cloneElement)(child, { - viewBox: viewBox || parentViewBox, - key: "label-" + index - }); - }); - return ckeckPropsLabel ? [ parseLabel(parentProps.label, viewBox || parentViewBox) ].concat(_toConsumableArray(explicitChilren)) : explicitChilren; - }; - Label.parseViewBox = parseViewBox, Label.renderCallByParent = renderCallByParent, - __webpack_exports__.a = Label; -}, function(module, exports, __webpack_require__) { - function isEqual(value, other) { - return baseIsEqual(value, other); - } - var baseIsEqual = __webpack_require__(199); - module.exports = isEqual; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - var __WEBPACK_IMPORTED_MODULE_0__src_color__ = __webpack_require__(207); - __webpack_require__.d(__webpack_exports__, "a", function() { - return __WEBPACK_IMPORTED_MODULE_0__src_color__.e; - }), __webpack_require__.d(__webpack_exports__, "f", function() { - return __WEBPACK_IMPORTED_MODULE_0__src_color__.g; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return __WEBPACK_IMPORTED_MODULE_0__src_color__.f; - }); - var __WEBPACK_IMPORTED_MODULE_1__src_lab__ = __webpack_require__(871); - __webpack_require__.d(__webpack_exports__, "e", function() { - return __WEBPACK_IMPORTED_MODULE_1__src_lab__.a; - }), __webpack_require__.d(__webpack_exports__, "c", function() { - return __WEBPACK_IMPORTED_MODULE_1__src_lab__.b; - }); - var __WEBPACK_IMPORTED_MODULE_2__src_cubehelix__ = __webpack_require__(872); - __webpack_require__.d(__webpack_exports__, "b", function() { - return __WEBPACK_IMPORTED_MODULE_2__src_cubehelix__.a; - }); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _toConsumableArray(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - return arr2; - } - return Array.from(arr); - } - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - function LabelList(props) { - var data = props.data, valueAccessor = props.valueAccessor, dataKey = props.dataKey, clockWise = props.clockWise, id = props.id, others = _objectWithoutProperties(props, [ "data", "valueAccessor", "dataKey", "clockWise", "id" ]); - return data && data.length ? __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_8__container_Layer__.a, { - className: "recharts-label-list" - }, data.map(function(entry, index) { - var value = __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(dataKey) ? valueAccessor(entry, index) : Object(__WEBPACK_IMPORTED_MODULE_10__util_ChartUtils__.w)(entry && entry.payload, dataKey), idProps = __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(id) ? {} : { - id: id + "-" + index - }; - return __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_7__Label__.a, _extends({}, Object(__WEBPACK_IMPORTED_MODULE_9__util_ReactUtils__.k)(entry), others, idProps, { - index: index, - value: value, - viewBox: __WEBPACK_IMPORTED_MODULE_7__Label__.a.parseViewBox(__WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default()(clockWise) ? entry : _extends({}, entry, { - clockWise: clockWise - })), - key: "label-" + index - })); - })) : null; - } - var __WEBPACK_IMPORTED_MODULE_0_lodash_isObject__ = __webpack_require__(32), __WEBPACK_IMPORTED_MODULE_0_lodash_isObject___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isObject__), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_2_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_2_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_3_lodash_last__ = __webpack_require__(922), __WEBPACK_IMPORTED_MODULE_3_lodash_last___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_last__), __WEBPACK_IMPORTED_MODULE_4_lodash_isArray__ = __webpack_require__(13), __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_5_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_5_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_react__), __WEBPACK_IMPORTED_MODULE_6_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_6_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6_prop_types__), __WEBPACK_IMPORTED_MODULE_7__Label__ = __webpack_require__(44), __WEBPACK_IMPORTED_MODULE_8__container_Layer__ = __webpack_require__(14), __WEBPACK_IMPORTED_MODULE_9__util_ReactUtils__ = __webpack_require__(4), __WEBPACK_IMPORTED_MODULE_10__util_ChartUtils__ = __webpack_require__(16), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, propTypes = { - id: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - data: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.object), - valueAccessor: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - clockWise: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.bool, - dataKey: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func ]) - }, defaultProps = { - valueAccessor: function(entry) { - return __WEBPACK_IMPORTED_MODULE_4_lodash_isArray___default()(entry.value) ? __WEBPACK_IMPORTED_MODULE_3_lodash_last___default()(entry.value) : entry.value; - } - }; - LabelList.propTypes = propTypes, LabelList.displayName = "LabelList"; - var parseLabelList = function(label, data) { - return label ? !0 === label ? __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(LabelList, { - key: "labelList-implicit", - data: data - }) : __WEBPACK_IMPORTED_MODULE_5_react___default.a.isValidElement(label) || __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(label) ? __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(LabelList, { - key: "labelList-implicit", - data: data, - content: label - }) : __WEBPACK_IMPORTED_MODULE_0_lodash_isObject___default()(label) ? __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(LabelList, _extends({ - data: data - }, label, { - key: "labelList-implicit" - })) : null : null; - }, renderCallByParent = function(parentProps, data) { - var ckeckPropsLabel = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2]; - if (!parentProps || !parentProps.children && ckeckPropsLabel && !parentProps.label) return null; - var children = parentProps.children, explicitChilren = Object(__WEBPACK_IMPORTED_MODULE_9__util_ReactUtils__.h)(children, LabelList).map(function(child, index) { - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(child, { - data: data, - key: "labelList-" + index - }); - }); - return ckeckPropsLabel ? [ parseLabelList(parentProps.label, data) ].concat(_toConsumableArray(explicitChilren)) : explicitChilren; - }; - LabelList.renderCallByParent = renderCallByParent, LabelList.defaultProps = defaultProps, - __webpack_exports__.a = LabelList; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - function _defineProperty(obj, key, value) { - return key in obj ? Object.defineProperty(obj, key, { - value: value, - enumerable: !0, - configurable: !0, - writable: !0 - }) : obj[key] = value, obj; - } - function _toConsumableArray(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - return arr2; - } - return Array.from(arr); - } - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var __WEBPACK_IMPORTED_MODULE_0_lodash_sortBy__ = __webpack_require__(321), __WEBPACK_IMPORTED_MODULE_0_lodash_sortBy___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_sortBy__), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_2_lodash_range__ = __webpack_require__(373), __WEBPACK_IMPORTED_MODULE_2_lodash_range___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_range__), __WEBPACK_IMPORTED_MODULE_3_lodash_throttle__ = __webpack_require__(933), __WEBPACK_IMPORTED_MODULE_3_lodash_throttle___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_throttle__), __WEBPACK_IMPORTED_MODULE_4_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_5_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_5_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_react__), __WEBPACK_IMPORTED_MODULE_6_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_6_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6_prop_types__), __WEBPACK_IMPORTED_MODULE_7_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_7_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_7_classnames__), __WEBPACK_IMPORTED_MODULE_8__container_Surface__ = __webpack_require__(82), __WEBPACK_IMPORTED_MODULE_9__container_Layer__ = __webpack_require__(14), __WEBPACK_IMPORTED_MODULE_10__component_Tooltip__ = __webpack_require__(125), __WEBPACK_IMPORTED_MODULE_11__component_Legend__ = __webpack_require__(180), __WEBPACK_IMPORTED_MODULE_12__shape_Curve__ = __webpack_require__(71), __WEBPACK_IMPORTED_MODULE_13__shape_Cross__ = __webpack_require__(367), __WEBPACK_IMPORTED_MODULE_14__shape_Sector__ = __webpack_require__(139), __WEBPACK_IMPORTED_MODULE_15__shape_Dot__ = __webpack_require__(63), __WEBPACK_IMPORTED_MODULE_16__shape_Rectangle__ = __webpack_require__(70), __WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__ = __webpack_require__(4), __WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__ = __webpack_require__(374), __WEBPACK_IMPORTED_MODULE_19__cartesian_Brush__ = __webpack_require__(372), __WEBPACK_IMPORTED_MODULE_20__util_DOMUtils__ = __webpack_require__(198), __WEBPACK_IMPORTED_MODULE_21__util_DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__ = __webpack_require__(16), __WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__ = __webpack_require__(23), __WEBPACK_IMPORTED_MODULE_24__util_PureRender__ = __webpack_require__(5), __WEBPACK_IMPORTED_MODULE_25__util_Events__ = __webpack_require__(934), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), ORIENT_MAP = { - xAxis: [ "bottom", "top" ], - yAxis: [ "left", "right" ] - }, originCoordinate = { - x: 0, - y: 0 - }, generateCategoricalChart = function(_ref) { - var _class, _temp, _initialiseProps, chartName = _ref.chartName, GraphicalChild = _ref.GraphicalChild, _ref$eventType = _ref.eventType, eventType = void 0 === _ref$eventType ? "axis" : _ref$eventType, axisComponents = _ref.axisComponents, legendContent = _ref.legendContent, formatAxisMap = _ref.formatAxisMap, defaultProps = _ref.defaultProps, propTypes = _ref.propTypes; - return _temp = _class = function(_Component) { - function CategoricalChartWrapper(props) { - _classCallCheck(this, CategoricalChartWrapper); - var _this = _possibleConstructorReturn(this, (CategoricalChartWrapper.__proto__ || Object.getPrototypeOf(CategoricalChartWrapper)).call(this, props)); - _initialiseProps.call(_this); - var defaultState = _this.constructor.createDefaultState(props); - return _this.state = _extends({}, defaultState, { - updateId: 0 - }, _this.updateStateOfAxisMapsOffsetAndStackGroups(_extends({ - props: props - }, defaultState, { - updateId: 0 - }))), _this.uniqueChartId = __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(props.id) ? Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.k)("recharts") : props.id, - props.throttleDelay && (_this.triggeredAfterMouseMove = __WEBPACK_IMPORTED_MODULE_3_lodash_throttle___default()(_this.triggeredAfterMouseMove, props.throttleDelay)), - _this; - } - return _inherits(CategoricalChartWrapper, _Component), _createClass(CategoricalChartWrapper, [ { - key: "componentDidMount", - value: function() { - __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(this.props.syncId) || this.addListener(); - } - }, { - key: "componentWillReceiveProps", - value: function(nextProps) { - var _props = this.props, data = _props.data, children = _props.children, width = _props.width, height = _props.height, layout = _props.layout, stackOffset = _props.stackOffset, margin = _props.margin, updateId = this.state.updateId; - if (nextProps.data === data && nextProps.width === width && nextProps.height === height && nextProps.layout === layout && nextProps.stackOffset === stackOffset && Object(__WEBPACK_IMPORTED_MODULE_24__util_PureRender__.b)(nextProps.margin, margin)) { - if (!Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.m)(nextProps.children, children)) { - var hasGlobalData = !__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(nextProps.data), newUpdateId = hasGlobalData ? updateId : updateId + 1, _state = this.state, dataStartIndex = _state.dataStartIndex, dataEndIndex = _state.dataEndIndex, _defaultState = _extends({}, this.constructor.createDefaultState(nextProps), { - dataEndIndex: dataEndIndex, - dataStartIndex: dataStartIndex + }, Dashboard = function(_Component) { + function Dashboard(e) { + var t; + return _classCallCheck(this, Dashboard), _defineProperty(_assertThisInitialized(t = _possibleConstructorReturn(this, _getPrototypeOf(Dashboard).call(this, e))), "reconnect", function() { + var e = window.location.host, n = new WebSocket("".concat("https:" === window.location.protocol ? "wss://" : "ws://").concat(e, "/api")); + n.onopen = function() { + t.setState({ + content: defaultContent(), + shouldUpdate: {}, + server: n }); - this.setState(_extends({}, _defaultState, { - updateId: newUpdateId - }, this.updateStateOfAxisMapsOffsetAndStackGroups(_extends({ - props: nextProps - }, _defaultState, { - updateId: newUpdateId - })))); - } - } else { - var defaultState = this.constructor.createDefaultState(nextProps); - this.setState(_extends({}, defaultState, { - updateId: updateId + 1 - }, this.updateStateOfAxisMapsOffsetAndStackGroups(_extends({ - props: nextProps - }, defaultState, { - updateId: updateId + 1 - })))); - } - __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(this.props.syncId) && !__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(nextProps.syncId) && this.addListener(), - !__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(this.props.syncId) && __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(nextProps.syncId) && this.removeListener(); - } - }, { - key: "componentWillUnmount", - value: function() { - __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(this.props.syncId) || this.removeListener(), - "function" == typeof this.triggeredAfterMouseMove.cancel && this.triggeredAfterMouseMove.cancel(); - } - }, { - key: "getAxisMap", - value: function(props, _ref2) { - var _ref2$axisType = _ref2.axisType, axisType = void 0 === _ref2$axisType ? "xAxis" : _ref2$axisType, AxisComp = _ref2.AxisComp, graphicalItems = _ref2.graphicalItems, stackGroups = _ref2.stackGroups, dataStartIndex = _ref2.dataStartIndex, dataEndIndex = _ref2.dataEndIndex, children = props.children, axisIdKey = axisType + "Id", axes = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.h)(children, AxisComp), axisMap = {}; - return axes && axes.length ? axisMap = this.getAxisMapByAxes(props, { - axes: axes, - graphicalItems: graphicalItems, - axisType: axisType, - axisIdKey: axisIdKey, - stackGroups: stackGroups, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - }) : graphicalItems && graphicalItems.length && (axisMap = this.getAxisMapByItems(props, { - Axis: AxisComp, - graphicalItems: graphicalItems, - axisType: axisType, - axisIdKey: axisIdKey, - stackGroups: stackGroups, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - })), axisMap; - } - }, { - key: "getAxisMapByAxes", - value: function(props, _ref3) { - var _this2 = this, axes = _ref3.axes, graphicalItems = _ref3.graphicalItems, axisType = _ref3.axisType, axisIdKey = _ref3.axisIdKey, stackGroups = _ref3.stackGroups, dataStartIndex = _ref3.dataStartIndex, dataEndIndex = _ref3.dataEndIndex, layout = props.layout, children = props.children, stackOffset = props.stackOffset, isCategorial = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.x)(layout, axisType); - return axes.reduce(function(result, child) { - var _child$props = child.props, type = _child$props.type, dataKey = _child$props.dataKey, allowDataOverflow = _child$props.allowDataOverflow, allowDuplicatedCategory = _child$props.allowDuplicatedCategory, scale = _child$props.scale, ticks = _child$props.ticks, axisId = child.props[axisIdKey], displayedData = _this2.constructor.getDisplayedData(props, { - graphicalItems: graphicalItems.filter(function(item) { - return item.props[axisIdKey] === axisId; - }), - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - }), len = displayedData.length; - if (!result[axisId]) { - var domain = void 0, duplicateDomain = void 0, categoricalDomain = void 0; - if (dataKey) { - if (domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.n)(displayedData, dataKey, type), - "category" === type && isCategorial) { - var duplicate = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.e)(domain); - allowDuplicatedCategory && duplicate ? (duplicateDomain = domain, domain = __WEBPACK_IMPORTED_MODULE_2_lodash_range___default()(0, len)) : allowDuplicatedCategory || (domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.y)(child.props.domain, domain, child).reduce(function(finalDomain, entry) { - return finalDomain.indexOf(entry) >= 0 ? finalDomain : [].concat(_toConsumableArray(finalDomain), [ entry ]); - }, [])); - } else if ("category" === type) domain = allowDuplicatedCategory ? domain.filter(function(entry) { - return "" !== entry && !__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(entry); - }) : Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.y)(child.props.domain, domain, child).reduce(function(finalDomain, entry) { - return finalDomain.indexOf(entry) >= 0 || "" === entry || __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(entry) ? finalDomain : [].concat(_toConsumableArray(finalDomain), [ entry ]); - }, []); else if ("number" === type) { - var errorBarsDomain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.z)(displayedData, graphicalItems.filter(function(item) { - return item.props[axisIdKey] === axisId && !item.props.hide; - }), dataKey, axisType); - errorBarsDomain && (domain = errorBarsDomain); - } - !isCategorial || "number" !== type && "auto" === scale || (categoricalDomain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.n)(displayedData, dataKey, "category")); - } else domain = isCategorial ? __WEBPACK_IMPORTED_MODULE_2_lodash_range___default()(0, len) : stackGroups && stackGroups[axisId] && stackGroups[axisId].hasStack && "number" === type ? "expand" === stackOffset ? [ 0, 1 ] : Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.p)(stackGroups[axisId].stackGroups, dataStartIndex, dataEndIndex) : Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.o)(displayedData, graphicalItems.filter(function(item) { - return item.props[axisIdKey] === axisId && !item.props.hide; - }), type, !0); - return "number" === type && (domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.e)(children, domain, axisId, axisType, ticks), - child.props.domain && (domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.B)(child.props.domain, domain, allowDataOverflow))), - _extends({}, result, _defineProperty({}, axisId, _extends({}, child.props, { - axisType: axisType, - domain: domain, - categoricalDomain: categoricalDomain, - duplicateDomain: duplicateDomain, - originalDomain: child.props.domain, - isCategorial: isCategorial, - layout: layout - }))); - } - return result; - }, {}); - } - }, { - key: "getAxisMapByItems", - value: function(props, _ref4) { - var graphicalItems = _ref4.graphicalItems, Axis = _ref4.Axis, axisType = _ref4.axisType, axisIdKey = _ref4.axisIdKey, stackGroups = _ref4.stackGroups, dataStartIndex = _ref4.dataStartIndex, dataEndIndex = _ref4.dataEndIndex, layout = props.layout, children = props.children, displayedData = this.constructor.getDisplayedData(props, { - graphicalItems: graphicalItems, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - }), len = displayedData.length, isCategorial = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.x)(layout, axisType), index = -1; - return graphicalItems.reduce(function(result, child) { - var axisId = child.props[axisIdKey]; - if (!result[axisId]) { - index++; - var domain = void 0; - return isCategorial ? domain = __WEBPACK_IMPORTED_MODULE_2_lodash_range___default()(0, len) : stackGroups && stackGroups[axisId] && stackGroups[axisId].hasStack ? (domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.p)(stackGroups[axisId].stackGroups, dataStartIndex, dataEndIndex), - domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.e)(children, domain, axisId, axisType)) : (domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.B)(Axis.defaultProps.domain, Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.o)(displayedData, graphicalItems.filter(function(item) { - return item.props[axisIdKey] === axisId && !item.props.hide; - }), "number"), Axis.defaultProps.allowDataOverflow), domain = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.e)(children, domain, axisId, axisType)), - _extends({}, result, _defineProperty({}, axisId, _extends({ - axisType: axisType - }, Axis.defaultProps, { - hide: !0, - orientation: ORIENT_MAP[axisType] && ORIENT_MAP[axisType][index % 2], - domain: domain, - originalDomain: Axis.defaultProps.domain, - isCategorial: isCategorial, - layout: layout - }))); - } - return result; - }, {}); - } - }, { - key: "getActiveCoordinate", - value: function(tooltipTicks, activeIndex, rangeObj) { - var layout = this.props.layout, entry = tooltipTicks.find(function(tick) { - return tick && tick.index === activeIndex; - }); - if (entry) { - if ("horizontal" === layout) return { - x: entry.coordinate, - y: rangeObj.y + }, n.onmessage = function(e) { + var n = JSON.parse(e.data); + n ? t.update(n) : console.error("Incoming message is ".concat(n)); + }, n.onclose = function() { + t.setState({ + server: null + }), setTimeout(t.reconnect, 3e3); }; - if ("vertical" === layout) return { - x: rangeObj.x, - y: entry.coordinate - }; - if ("centric" === layout) { - var _angle = entry.coordinate, _radius = rangeObj.radius; - return _extends({}, rangeObj, Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.e)(rangeObj.cx, rangeObj.cy, _radius, _angle), { - angle: _angle, - radius: _radius - }); - } - var radius = entry.coordinate, angle = rangeObj.angle; - return _extends({}, rangeObj, Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.e)(rangeObj.cx, rangeObj.cy, radius, angle), { - angle: angle, - radius: radius - }); - } - return originCoordinate; - } - }, { - key: "getMouseInfo", - value: function(event) { - if (!this.container) return null; - var containerOffset = Object(__WEBPACK_IMPORTED_MODULE_20__util_DOMUtils__.b)(this.container), e = Object(__WEBPACK_IMPORTED_MODULE_20__util_DOMUtils__.a)(event, containerOffset), rangeObj = this.inRange(e.chartX, e.chartY); - if (!rangeObj) return null; - var _state2 = this.state, xAxisMap = _state2.xAxisMap, yAxisMap = _state2.yAxisMap; - if ("axis" !== eventType && xAxisMap && yAxisMap) { - var xScale = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(xAxisMap).scale, yScale = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(yAxisMap).scale, xValue = xScale && xScale.invert ? xScale.invert(e.chartX) : null, yValue = yScale && yScale.invert ? yScale.invert(e.chartY) : null; - return _extends({}, e, { - xValue: xValue, - yValue: yValue - }); - } - var _state3 = this.state, ticks = _state3.orderedTooltipTicks, axis = _state3.tooltipAxis, tooltipTicks = _state3.tooltipTicks, pos = this.calculateTooltipPos(rangeObj), activeIndex = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.b)(pos, ticks, tooltipTicks, axis); - if (activeIndex >= 0 && tooltipTicks) { - var activeLabel = tooltipTicks[activeIndex] && tooltipTicks[activeIndex].value, activePayload = this.getTooltipContent(activeIndex, activeLabel), activeCoordinate = this.getActiveCoordinate(ticks, activeIndex, rangeObj); - return _extends({}, e, { - activeTooltipIndex: activeIndex, - activeLabel: activeLabel, - activePayload: activePayload, - activeCoordinate: activeCoordinate - }); - } - return null; - } - }, { - key: "getTooltipContent", - value: function(activeIndex, activeLabel) { - var _state4 = this.state, graphicalItems = _state4.graphicalItems, tooltipAxis = _state4.tooltipAxis, displayedData = this.constructor.getDisplayedData(this.props, this.state); - return activeIndex < 0 || !graphicalItems || !graphicalItems.length || activeIndex >= displayedData.length ? null : graphicalItems.reduce(function(result, child) { - if (child.props.hide) return result; - var _child$props2 = child.props, dataKey = _child$props2.dataKey, name = _child$props2.name, unit = _child$props2.unit, formatter = _child$props2.formatter, data = _child$props2.data, payload = void 0; - return payload = tooltipAxis.dataKey && !tooltipAxis.allowDuplicatedCategory ? Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.a)(data || displayedData, tooltipAxis.dataKey, activeLabel) : displayedData[activeIndex], - payload ? [].concat(_toConsumableArray(result), [ _extends({}, Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.k)(child), { - dataKey: dataKey, - unit: unit, - formatter: formatter, - name: name || dataKey, - color: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.r)(child), - value: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.w)(payload, dataKey), - payload: payload - }) ]) : result; - }, []); - } - }, { - key: "getFormatItems", - value: function(props, currentState) { - var _this3 = this, graphicalItems = currentState.graphicalItems, stackGroups = currentState.stackGroups, offset = currentState.offset, updateId = currentState.updateId, dataStartIndex = currentState.dataStartIndex, dataEndIndex = currentState.dataEndIndex, barSize = props.barSize, layout = props.layout, barGap = props.barGap, barCategoryGap = props.barCategoryGap, globalMaxBarSize = props.maxBarSize, _getAxisNameByLayout = this.getAxisNameByLayout(layout), numericAxisName = _getAxisNameByLayout.numericAxisName, cateAxisName = _getAxisNameByLayout.cateAxisName, hasBar = this.constructor.hasBar(graphicalItems), sizeList = hasBar && Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.i)({ - barSize: barSize, - stackGroups: stackGroups - }), formatedItems = []; - return graphicalItems.forEach(function(item, index) { - var displayedData = _this3.constructor.getDisplayedData(props, { - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - }, item), _item$props = item.props, dataKey = _item$props.dataKey, childMaxBarSize = _item$props.maxBarSize, numericAxisId = item.props[numericAxisName + "Id"], cateAxisId = item.props[cateAxisName + "Id"], axisObj = axisComponents.reduce(function(result, entry) { - var _extends4, axisMap = currentState[entry.axisType + "Map"], id = item.props[entry.axisType + "Id"], axis = axisMap && axisMap[id]; - return _extends({}, result, (_extends4 = {}, _defineProperty(_extends4, entry.axisType, axis), - _defineProperty(_extends4, entry.axisType + "Ticks", Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(axis)), - _extends4)); - }, {}), cateAxis = axisObj[cateAxisName], cateTicks = axisObj[cateAxisName + "Ticks"], stackedData = stackGroups && stackGroups[numericAxisId] && stackGroups[numericAxisId].hasStack && Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.t)(item, stackGroups[numericAxisId].stackGroups), bandSize = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.g)(cateAxis, cateTicks), maxBarSize = __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(childMaxBarSize) ? globalMaxBarSize : childMaxBarSize, barPosition = hasBar && Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.h)({ - barGap: barGap, - barCategoryGap: barCategoryGap, - bandSize: bandSize, - sizeList: sizeList[cateAxisId], - maxBarSize: maxBarSize - }), componsedFn = item && item.type && item.type.getComposedData; - if (componsedFn) { - var _extends5; - formatedItems.push({ - props: _extends({}, componsedFn(_extends({}, axisObj, { - displayedData: displayedData, - props: props, - dataKey: dataKey, - item: item, - bandSize: bandSize, - barPosition: barPosition, - offset: offset, - stackedData: stackedData, - layout: layout, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex, - onItemMouseLeave: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.d)(_this3.handleItemMouseLeave, null, item.props.onMouseLeave), - onItemMouseEnter: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.d)(_this3.handleItemMouseEnter, null, item.props.onMouseEnter) - })), (_extends5 = { - key: item.key || "item-" + index - }, _defineProperty(_extends5, numericAxisName, axisObj[numericAxisName]), _defineProperty(_extends5, cateAxisName, axisObj[cateAxisName]), - _defineProperty(_extends5, "animationId", updateId), _extends5)), - childIndex: Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.o)(item, props.children), - item: item - }); - } - }), formatedItems; - } - }, { - key: "getCursorRectangle", - value: function() { - var layout = this.props.layout, _state5 = this.state, activeCoordinate = _state5.activeCoordinate, offset = _state5.offset, tooltipAxisBandSize = _state5.tooltipAxisBandSize, halfSize = tooltipAxisBandSize / 2; - return { - stroke: "none", - fill: "#ccc", - x: "horizontal" === layout ? activeCoordinate.x - halfSize : offset.left + .5, - y: "horizontal" === layout ? offset.top + .5 : activeCoordinate.y - halfSize, - width: "horizontal" === layout ? tooltipAxisBandSize : offset.width - 1, - height: "horizontal" === layout ? offset.height - 1 : tooltipAxisBandSize - }; - } - }, { - key: "getCursorPoints", - value: function() { - var layout = this.props.layout, _state6 = this.state, activeCoordinate = _state6.activeCoordinate, offset = _state6.offset, x1 = void 0, y1 = void 0, x2 = void 0, y2 = void 0; - if ("horizontal" === layout) x1 = activeCoordinate.x, x2 = x1, y1 = offset.top, - y2 = offset.top + offset.height; else if ("vertical" === layout) y1 = activeCoordinate.y, - y2 = y1, x1 = offset.left, x2 = offset.left + offset.width; else if (!__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(activeCoordinate.cx) || !__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(activeCoordinate.cy)) { - if ("centric" !== layout) { - var _cx = activeCoordinate.cx, _cy = activeCoordinate.cy, radius = activeCoordinate.radius, startAngle = activeCoordinate.startAngle, endAngle = activeCoordinate.endAngle, startPoint = Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.e)(_cx, _cy, radius, startAngle), endPoint = Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.e)(_cx, _cy, radius, endAngle); + }), _defineProperty(_assertThisInitialized(t), "send", function(e) { + null != t.state.server && t.state.server.send(e); + }), _defineProperty(_assertThisInitialized(t), "update", function(e) { + t.setState(function(t) { return { - points: [ startPoint, endPoint ], - cx: _cx, - cy: _cy, - radius: radius, - startAngle: startAngle, - endAngle: endAngle + content: deepUpdate(updaters, e, t.content), + shouldUpdate: shouldUpdate(updaters, e) }; - } - var cx = activeCoordinate.cx, cy = activeCoordinate.cy, innerRadius = activeCoordinate.innerRadius, outerRadius = activeCoordinate.outerRadius, angle = activeCoordinate.angle, innerPoint = Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.e)(cx, cy, innerRadius, angle), outerPoint = Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.e)(cx, cy, outerRadius, angle); - x1 = innerPoint.x, y1 = innerPoint.y, x2 = outerPoint.x, y2 = outerPoint.y; - } - return [ { - x: x1, - y: y1 - }, { - x: x2, - y: y2 - } ]; - } - }, { - key: "getAxisNameByLayout", - value: function(layout) { - return "horizontal" === layout ? { - numericAxisName: "yAxis", - cateAxisName: "xAxis" - } : "vertical" === layout ? { - numericAxisName: "xAxis", - cateAxisName: "yAxis" - } : "centric" === layout ? { - numericAxisName: "radiusAxis", - cateAxisName: "angleAxis" - } : { - numericAxisName: "angleAxis", - cateAxisName: "radiusAxis" - }; - } - }, { - key: "calculateTooltipPos", - value: function(rangeObj) { - var layout = this.props.layout; - return "horizontal" === layout ? rangeObj.x : "vertical" === layout ? rangeObj.y : "centric" === layout ? rangeObj.angle : rangeObj.radius; - } - }, { - key: "inRange", - value: function(x, y) { - var layout = this.props.layout; - if ("horizontal" === layout || "vertical" === layout) { - var offset = this.state.offset; - return x >= offset.left && x <= offset.left + offset.width && y >= offset.top && y <= offset.top + offset.height ? { - x: x, - y: y - } : null; - } - var _state7 = this.state, angleAxisMap = _state7.angleAxisMap, radiusAxisMap = _state7.radiusAxisMap; - if (angleAxisMap && radiusAxisMap) { - var angleAxis = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(angleAxisMap); - return Object(__WEBPACK_IMPORTED_MODULE_23__util_PolarUtils__.d)({ - x: x, - y: y - }, angleAxis); - } - return null; - } - }, { - key: "parseEventsOfWrapper", - value: function() { - var children = this.props.children, tooltipItem = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_10__component_Tooltip__.a), tooltipEvents = tooltipItem && "axis" === eventType ? { - onMouseEnter: this.handleMouseEnter, - onMouseMove: this.handleMouseMove, - onMouseLeave: this.handleMouseLeave, - onTouchMove: this.handleTouchMove - } : {}, outerEvents = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.e)(this.props, this.handleOuterEvent); - return _extends({}, outerEvents, tooltipEvents); - } - }, { - key: "updateStateOfAxisMapsOffsetAndStackGroups", - value: function(_ref5) { - var _this4 = this, props = _ref5.props, dataStartIndex = _ref5.dataStartIndex, dataEndIndex = _ref5.dataEndIndex, updateId = _ref5.updateId; - if (!Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.q)({ - props: props - })) return null; - var children = props.children, layout = props.layout, stackOffset = props.stackOffset, data = props.data, reverseStackOrder = props.reverseStackOrder, _getAxisNameByLayout2 = this.getAxisNameByLayout(layout), numericAxisName = _getAxisNameByLayout2.numericAxisName, cateAxisName = _getAxisNameByLayout2.cateAxisName, graphicalItems = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.h)(children, GraphicalChild), stackGroups = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.s)(data, graphicalItems, numericAxisName + "Id", cateAxisName + "Id", stackOffset, reverseStackOrder), axisObj = axisComponents.reduce(function(result, entry) { - var name = entry.axisType + "Map"; - return _extends({}, result, _defineProperty({}, name, _this4.getAxisMap(props, _extends({}, entry, { - graphicalItems: graphicalItems, - stackGroups: entry.axisType === numericAxisName && stackGroups, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - })))); - }, {}), offset = this.calculateOffset(_extends({}, axisObj, { - props: props, - graphicalItems: graphicalItems - })); - Object.keys(axisObj).forEach(function(key) { - axisObj[key] = formatAxisMap(props, axisObj[key], offset, key.replace("Map", ""), chartName); - }); - var cateAxisMap = axisObj[cateAxisName + "Map"], ticksObj = this.tooltipTicksGenerator(cateAxisMap), formatedGraphicalItems = this.getFormatItems(props, _extends({}, axisObj, { - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex, - updateId: updateId, - graphicalItems: graphicalItems, - stackGroups: stackGroups, - offset: offset - })); - return _extends({ - formatedGraphicalItems: formatedGraphicalItems, - graphicalItems: graphicalItems, - offset: offset, - stackGroups: stackGroups - }, ticksObj, axisObj); - } - }, { - key: "addListener", - value: function() { - __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.on(__WEBPACK_IMPORTED_MODULE_25__util_Events__.a, this.handleReceiveSyncEvent), - __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.setMaxListeners && __WEBPACK_IMPORTED_MODULE_25__util_Events__.b._maxListeners && __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.setMaxListeners(__WEBPACK_IMPORTED_MODULE_25__util_Events__.b._maxListeners + 1); - } - }, { - key: "removeListener", - value: function() { - __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.removeListener(__WEBPACK_IMPORTED_MODULE_25__util_Events__.a, this.handleReceiveSyncEvent), - __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.setMaxListeners && __WEBPACK_IMPORTED_MODULE_25__util_Events__.b._maxListeners && __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.setMaxListeners(__WEBPACK_IMPORTED_MODULE_25__util_Events__.b._maxListeners - 1); - } - }, { - key: "calculateOffset", - value: function(_ref6) { - var props = _ref6.props, graphicalItems = _ref6.graphicalItems, _ref6$xAxisMap = _ref6.xAxisMap, xAxisMap = void 0 === _ref6$xAxisMap ? {} : _ref6$xAxisMap, _ref6$yAxisMap = _ref6.yAxisMap, yAxisMap = void 0 === _ref6$yAxisMap ? {} : _ref6$yAxisMap, width = props.width, height = props.height, children = props.children, margin = props.margin || {}, brushItem = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_19__cartesian_Brush__.a), legendItem = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_11__component_Legend__.a), offsetH = Object.keys(yAxisMap).reduce(function(result, id) { - var entry = yAxisMap[id], orientation = entry.orientation; - return entry.mirror || entry.hide ? result : _extends({}, result, _defineProperty({}, orientation, result[orientation] + entry.width)); - }, { - left: margin.left || 0, - right: margin.right || 0 - }), offsetV = Object.keys(xAxisMap).reduce(function(result, id) { - var entry = xAxisMap[id], orientation = entry.orientation; - return entry.mirror || entry.hide ? result : _extends({}, result, _defineProperty({}, orientation, result[orientation] + entry.height)); - }, { - top: margin.top || 0, - bottom: margin.bottom || 0 - }), offset = _extends({}, offsetV, offsetH), brushBottom = offset.bottom; - if (brushItem && (offset.bottom += brushItem.props.height || __WEBPACK_IMPORTED_MODULE_19__cartesian_Brush__.a.defaultProps.height), - legendItem && this.legendInstance) { - var legendBox = this.legendInstance.getBBox(); - offset = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.a)(offset, graphicalItems, props, legendBox); - } - return _extends({ - brushBottom: brushBottom - }, offset, { - width: width - offset.left - offset.right, - height: height - offset.top - offset.bottom - }); - } - }, { - key: "triggerSyncEvent", - value: function(data) { - var syncId = this.props.syncId; - __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(syncId) || __WEBPACK_IMPORTED_MODULE_25__util_Events__.b.emit(__WEBPACK_IMPORTED_MODULE_25__util_Events__.a, syncId, this.uniqueChartId, data); - } - }, { - key: "filterFormatItem", - value: function(item, displayName, childIndex) { - for (var formatedGraphicalItems = this.state.formatedGraphicalItems, i = 0, len = formatedGraphicalItems.length; i < len; i++) { - var entry = formatedGraphicalItems[i]; - if (entry.item === item || entry.props.key === item.key || displayName === Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.j)(entry.item.type) && childIndex === entry.childIndex) return entry; - } - return null; - } - }, { - key: "renderAxis", - value: function(axisOptions, element, displayName, index) { - var _props2 = this.props, width = _props2.width, height = _props2.height; - return __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__.a, _extends({}, axisOptions, { - className: "recharts-" + axisOptions.axisType + " " + axisOptions.axisType, - key: element.key || displayName + "-" + index, - viewBox: { - x: 0, - y: 0, - width: width, - height: height - }, - ticksGenerator: this.axesTicksGenerator - })); - } - }, { - key: "renderLegend", - value: function() { - var _this5 = this, formatedGraphicalItems = this.state.formatedGraphicalItems, _props3 = this.props, children = _props3.children, width = _props3.width, height = _props3.height, margin = this.props.margin || {}, legendWidth = width - (margin.left || 0) - (margin.right || 0), legendHeight = height - (margin.top || 0) - (margin.bottom || 0), props = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.q)({ - children: children, - formatedGraphicalItems: formatedGraphicalItems, - legendWidth: legendWidth, - legendHeight: legendHeight, - legendContent: legendContent - }); - if (!props) return null; - var item = props.item, otherProps = _objectWithoutProperties(props, [ "item" ]); - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(item, _extends({}, otherProps, { - chartWidth: width, - chartHeight: height, - margin: margin, - ref: function(legend) { - _this5.legendInstance = legend; - }, - onBBoxUpdate: this.handleLegendBBoxUpdate - })); - } - }, { - key: "renderTooltip", - value: function() { - var children = this.props.children, tooltipItem = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_10__component_Tooltip__.a); - if (!tooltipItem) return null; - var _state8 = this.state, isTooltipActive = _state8.isTooltipActive, activeCoordinate = _state8.activeCoordinate, activePayload = _state8.activePayload, activeLabel = _state8.activeLabel, offset = _state8.offset; - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(tooltipItem, { - viewBox: _extends({}, offset, { - x: offset.left, - y: offset.top - }), - active: isTooltipActive, - label: activeLabel, - payload: isTooltipActive ? activePayload : [], - coordinate: activeCoordinate - }); - } - }, { - key: "renderActiveDot", - value: function(option, props) { - var dot = void 0; - return dot = Object(__WEBPACK_IMPORTED_MODULE_5_react__.isValidElement)(option) ? Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(option, props) : __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(option) ? option(props) : __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_15__shape_Dot__.a, props), - __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_9__container_Layer__.a, { - className: "recharts-active-dot", - key: props.key - }, dot); - } - }, { - key: "renderActivePoints", - value: function(_ref7) { - var item = _ref7.item, activePoint = _ref7.activePoint, basePoint = _ref7.basePoint, childIndex = _ref7.childIndex, isRange = _ref7.isRange, result = [], key = item.props.key, _item$item$props = item.item.props, activeDot = _item$item$props.activeDot, dataKey = _item$item$props.dataKey, dotProps = _extends({ - index: childIndex, - dataKey: dataKey, - cx: activePoint.x, - cy: activePoint.y, - r: 4, - fill: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.r)(item.item), - strokeWidth: 2, - stroke: "#fff", - payload: activePoint.payload, - value: activePoint.value, - key: key + "-activePoint-" + childIndex - }, Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.k)(activeDot), Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.e)(activeDot)); - return result.push(this.renderActiveDot(activeDot, dotProps, childIndex)), basePoint ? result.push(this.renderActiveDot(activeDot, _extends({}, dotProps, { - cx: basePoint.x, - cy: basePoint.y, - key: key + "-basePoint-" + childIndex - }), childIndex)) : isRange && result.push(null), result; - } - }, { - key: "render", - value: function() { - var _this6 = this; - if (!Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.q)(this)) return null; - var _props4 = this.props, children = _props4.children, className = _props4.className, width = _props4.width, height = _props4.height, style = _props4.style, compact = _props4.compact, others = _objectWithoutProperties(_props4, [ "children", "className", "width", "height", "style", "compact" ]), attrs = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.k)(others), map = { - CartesianGrid: { - handler: this.renderGrid, - once: !0 - }, - ReferenceArea: { - handler: this.renderReferenceElement - }, - ReferenceLine: { - handler: this.renderReferenceElement - }, - ReferenceDot: { - handler: this.renderReferenceElement - }, - XAxis: { - handler: this.renderXAxis - }, - YAxis: { - handler: this.renderYAxis - }, - Brush: { - handler: this.renderBrush, - once: !0 - }, - Bar: { - handler: this.renderGraphicChild - }, - Line: { - handler: this.renderGraphicChild - }, - Area: { - handler: this.renderGraphicChild - }, - Radar: { - handler: this.renderGraphicChild - }, - RadialBar: { - handler: this.renderGraphicChild - }, - Scatter: { - handler: this.renderGraphicChild - }, - Pie: { - handler: this.renderGraphicChild - }, - Tooltip: { - handler: this.renderCursor, - once: !0 - }, - PolarGrid: { - handler: this.renderPolarGrid, - once: !0 - }, - PolarAngleAxis: { - handler: this.renderPolarAxis - }, - PolarRadiusAxis: { - handler: this.renderPolarAxis - } - }; - if (compact) return __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_8__container_Surface__.a, _extends({}, attrs, { - width: width, - height: height - }), Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.p)(children, map)); - var events = this.parseEventsOfWrapper(); - return __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement("div", _extends({ - className: __WEBPACK_IMPORTED_MODULE_7_classnames___default()("recharts-wrapper", className), - style: _extends({}, style, { - position: "relative", - cursor: "default", - width: width, - height: height - }) - }, events, { - ref: function(node) { - _this6.container = node; - } - }), __WEBPACK_IMPORTED_MODULE_5_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_8__container_Surface__.a, _extends({}, attrs, { - width: width, - height: height - }), Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.p)(children, map)), this.renderLegend(), this.renderTooltip()); - } - } ]), CategoricalChartWrapper; - }(__WEBPACK_IMPORTED_MODULE_5_react__.Component), _class.displayName = chartName, - _class.propTypes = _extends({ - syncId: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number ]), - compact: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.bool, - width: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - data: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.object), - layout: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "horizontal", "vertical" ]), - stackOffset: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOf([ "sign", "expand", "none", "wiggle", "silhouette" ]), - throttleDelay: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - margin: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.shape({ - top: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - right: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - bottom: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - left: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number - }), - barCategoryGap: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - barGap: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - barSize: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string ]), - maxBarSize: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.number, - style: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.object, - className: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string, - children: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.node), __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.node ]), - onClick: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseLeave: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseEnter: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseMove: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseDown: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - onMouseUp: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.func, - reverseStackOrder: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.bool, - id: __WEBPACK_IMPORTED_MODULE_6_prop_types___default.a.string - }, propTypes), _class.defaultProps = _extends({ - layout: "horizontal", - stackOffset: "none", - barCategoryGap: "10%", - barGap: 4, - margin: { - top: 5, - right: 5, - bottom: 5, - left: 5 - }, - reverseStackOrder: !1 - }, defaultProps), _class.createDefaultState = function(props) { - var children = props.children, brushItem = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_19__cartesian_Brush__.a); - return { - chartX: 0, - chartY: 0, - dataStartIndex: brushItem && brushItem.props && brushItem.props.startIndex || 0, - dataEndIndex: brushItem && brushItem.props && brushItem.props.endIndex || props.data && props.data.length - 1 || 0, - activeTooltipIndex: -1, - isTooltipActive: !1 - }; - }, _class.hasBar = function(graphicalItems) { - return !(!graphicalItems || !graphicalItems.length) && graphicalItems.some(function(item) { - var name = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.j)(item && item.type); - return name && name.indexOf("Bar") >= 0; - }); - }, _class.getDisplayedData = function(props, _ref8, item) { - var graphicalItems = _ref8.graphicalItems, dataStartIndex = _ref8.dataStartIndex, dataEndIndex = _ref8.dataEndIndex, itemsData = (graphicalItems || []).reduce(function(result, child) { - var itemData = child.props.data; - return itemData && itemData.length ? [].concat(_toConsumableArray(result), _toConsumableArray(itemData)) : result; - }, []); - if (itemsData && itemsData.length > 0) return itemsData; - if (item && item.props && item.props.data && item.props.data.length > 0) return item.props.data; - var data = props.data; - return data && data.length && Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(dataStartIndex) && Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(dataEndIndex) ? data.slice(dataStartIndex, dataEndIndex + 1) : []; - }, _initialiseProps = function() { - var _this7 = this; - this.handleLegendBBoxUpdate = function(box) { - if (box && _this7.legendInstance) { - var _state9 = _this7.state, dataStartIndex = _state9.dataStartIndex, dataEndIndex = _state9.dataEndIndex, updateId = _state9.updateId; - _this7.setState(_this7.updateStateOfAxisMapsOffsetAndStackGroups({ - props: _this7.props, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex, - updateId: updateId - })); - } - }, this.handleReceiveSyncEvent = function(cId, chartId, data) { - var _props5 = _this7.props, syncId = _props5.syncId, layout = _props5.layout, updateId = _this7.state.updateId; - if (syncId === cId && chartId !== _this7.uniqueChartId) { - var dataStartIndex = data.dataStartIndex, dataEndIndex = data.dataEndIndex; - if (__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(data.dataStartIndex) && __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(data.dataEndIndex)) if (__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(data.activeTooltipIndex)) _this7.setState(data); else { - var chartX = data.chartX, chartY = data.chartY, activeTooltipIndex = data.activeTooltipIndex, _state10 = _this7.state, offset = _state10.offset, tooltipTicks = _state10.tooltipTicks; - if (!offset) return; - var viewBox = _extends({}, offset, { - x: offset.left, - y: offset.top - }), validateChartX = Math.min(chartX, viewBox.x + viewBox.width), validateChartY = Math.min(chartY, viewBox.y + viewBox.height), activeLabel = tooltipTicks[activeTooltipIndex] && tooltipTicks[activeTooltipIndex].value, activePayload = _this7.getTooltipContent(activeTooltipIndex), activeCoordinate = tooltipTicks[activeTooltipIndex] ? { - x: "horizontal" === layout ? tooltipTicks[activeTooltipIndex].coordinate : validateChartX, - y: "horizontal" === layout ? validateChartY : tooltipTicks[activeTooltipIndex].coordinate - } : originCoordinate; - _this7.setState(_extends({}, data, { - activeLabel: activeLabel, - activeCoordinate: activeCoordinate, - activePayload: activePayload - })); - } else _this7.setState(_extends({ - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex - }, _this7.updateStateOfAxisMapsOffsetAndStackGroups({ - props: _this7.props, - dataStartIndex: dataStartIndex, - dataEndIndex: dataEndIndex, - updateId: updateId - }))); - } - }, this.handleBrushChange = function(_ref9) { - var startIndex = _ref9.startIndex, endIndex = _ref9.endIndex; - if (startIndex !== _this7.state.dataStartIndex || endIndex !== _this7.state.dataEndIndex) { - var updateId = _this7.state.updateId; - _this7.setState(function() { - return _extends({ - dataStartIndex: startIndex, - dataEndIndex: endIndex - }, _this7.updateStateOfAxisMapsOffsetAndStackGroups({ - props: _this7.props, - dataStartIndex: startIndex, - dataEndIndex: endIndex, - updateId: updateId - })); - }), _this7.triggerSyncEvent({ - dataStartIndex: startIndex, - dataEndIndex: endIndex - }); - } - }, this.handleMouseEnter = function(e) { - var onMouseEnter = _this7.props.onMouseEnter, mouse = _this7.getMouseInfo(e); - if (mouse) { - var nextState = _extends({}, mouse, { - isTooltipActive: !0 - }); - _this7.setState(nextState), _this7.triggerSyncEvent(nextState), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(onMouseEnter) && onMouseEnter(nextState, e); - } - }, this.triggeredAfterMouseMove = function(e) { - var onMouseMove = _this7.props.onMouseMove, mouse = _this7.getMouseInfo(e), nextState = mouse ? _extends({}, mouse, { - isTooltipActive: !0 - }) : { - isTooltipActive: !1 - }; - _this7.setState(nextState), _this7.triggerSyncEvent(nextState), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(onMouseMove) && onMouseMove(nextState, e); - }, this.handleItemMouseEnter = function(el) { - _this7.setState(function() { - return { - isTooltipActive: !0, - activeItem: el, - activePayload: el.tooltipPayload, - activeCoordinate: el.tooltipPosition || { - x: el.cx, - y: el.cy - } - }; - }); - }, this.handleItemMouseLeave = function() { - _this7.setState(function() { - return { - isTooltipActive: !1 - }; - }); - }, this.handleMouseMove = function(e) { - e && __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(e.persist) && e.persist(), - _this7.triggeredAfterMouseMove(e); - }, this.handleMouseLeave = function(e) { - var onMouseLeave = _this7.props.onMouseLeave, nextState = { - isTooltipActive: !1 - }; - _this7.setState(nextState), _this7.triggerSyncEvent(nextState), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(onMouseLeave) && onMouseLeave(nextState, e); - }, this.handleOuterEvent = function(e) { - var eventName = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.l)(e); - if (eventName && __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(_this7.props[eventName])) { - var mouse = _this7.getMouseInfo(e); - (0, _this7.props[eventName])(mouse, e); - } - }, this.handleClick = function(e) { - var onClick = _this7.props.onClick; - if (__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(onClick)) { - onClick(_this7.getMouseInfo(e), e); - } - }, this.handleMouseDown = function(e) { - var onMouseDown = _this7.props.onMouseDown; - if (__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(onMouseDown)) { - onMouseDown(_this7.getMouseInfo(e), e); - } - }, this.handleMouseUp = function(e) { - var onMouseUp = _this7.props.onMouseUp; - if (__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(onMouseUp)) { - onMouseUp(_this7.getMouseInfo(e), e); - } - }, this.handleTouchMove = function(e) { - null != e.changedTouches && e.changedTouches.length > 0 && _this7.handleMouseMove(e.changedTouches[0]); - }, this.verticalCoordinatesGenerator = function(_ref10) { - var xAxis = _ref10.xAxis, width = _ref10.width, height = _ref10.height, offset = _ref10.offset; - return Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.m)(__WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__.a.getTicks(_extends({}, __WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__.a.defaultProps, xAxis, { - ticks: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(xAxis, !0), - viewBox: { - x: 0, - y: 0, - width: width, - height: height - } - })), offset.left, offset.left + offset.width); - }, this.horizontalCoordinatesGenerator = function(_ref11) { - var yAxis = _ref11.yAxis, width = _ref11.width, height = _ref11.height, offset = _ref11.offset; - return Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.m)(__WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__.a.getTicks(_extends({}, __WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__.a.defaultProps, yAxis, { - ticks: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(yAxis, !0), - viewBox: { - x: 0, - y: 0, - width: width, - height: height - } - })), offset.top, offset.top + offset.height); - }, this.axesTicksGenerator = function(axis) { - return Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(axis, !0); - }, this.tooltipTicksGenerator = function(axisMap) { - var axis = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(axisMap), tooltipTicks = Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(axis, !1, !0); - return { - tooltipTicks: tooltipTicks, - orderedTooltipTicks: __WEBPACK_IMPORTED_MODULE_0_lodash_sortBy___default()(tooltipTicks, function(o) { - return o.coordinate; - }), - tooltipAxis: axis, - tooltipAxisBandSize: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.g)(axis) - }; - }, this.renderCursor = function(element) { - var _state11 = _this7.state, isTooltipActive = _state11.isTooltipActive, activeCoordinate = _state11.activeCoordinate, activePayload = _state11.activePayload, offset = _state11.offset; - if (!(element && element.props.cursor && isTooltipActive && activeCoordinate)) return null; - var layout = _this7.props.layout, restProps = void 0, cursorComp = __WEBPACK_IMPORTED_MODULE_12__shape_Curve__.a; - if ("ScatterChart" === chartName) restProps = activeCoordinate, cursorComp = __WEBPACK_IMPORTED_MODULE_13__shape_Cross__.a; else if ("BarChart" === chartName) restProps = _this7.getCursorRectangle(), - cursorComp = __WEBPACK_IMPORTED_MODULE_16__shape_Rectangle__.a; else if ("radial" === layout) { - var _getCursorPoints = _this7.getCursorPoints(), cx = _getCursorPoints.cx, cy = _getCursorPoints.cy, radius = _getCursorPoints.radius, startAngle = _getCursorPoints.startAngle, endAngle = _getCursorPoints.endAngle; - restProps = { - cx: cx, - cy: cy, - startAngle: startAngle, - endAngle: endAngle, - innerRadius: radius, - outerRadius: radius - }, cursorComp = __WEBPACK_IMPORTED_MODULE_14__shape_Sector__.a; - } else restProps = { - points: _this7.getCursorPoints() - }, cursorComp = __WEBPACK_IMPORTED_MODULE_12__shape_Curve__.a; - var key = element.key || "_recharts-cursor", cursorProps = _extends({ - stroke: "#ccc" - }, offset, restProps, Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.k)(element.props.cursor), { - payload: activePayload, - key: key, - className: "recharts-tooltip-cursor" - }); - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.isValidElement)(element.props.cursor) ? Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element.props.cursor, cursorProps) : Object(__WEBPACK_IMPORTED_MODULE_5_react__.createElement)(cursorComp, cursorProps); - }, this.renderPolarAxis = function(element, displayName, index) { - var axisType = element.type.axisType, axisMap = _this7.state[axisType + "Map"], axisOption = axisMap[element.props[axisType + "Id"]]; - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element, _extends({}, axisOption, { - className: axisType, - key: element.key || displayName + "-" + index, - ticks: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(axisOption, !0) - })); - }, this.renderXAxis = function(element, displayName, index) { - var xAxisMap = _this7.state.xAxisMap, axisObj = xAxisMap[element.props.xAxisId]; - return _this7.renderAxis(axisObj, element, displayName, index); - }, this.renderYAxis = function(element, displayName, index) { - var yAxisMap = _this7.state.yAxisMap, axisObj = yAxisMap[element.props.yAxisId]; - return _this7.renderAxis(axisObj, element, displayName, index); - }, this.renderGrid = function(element) { - var _state12 = _this7.state, xAxisMap = _state12.xAxisMap, yAxisMap = _state12.yAxisMap, offset = _state12.offset, _props6 = _this7.props, width = _props6.width, height = _props6.height, xAxis = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(xAxisMap), yAxis = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(yAxisMap), props = element.props || {}; - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element, { - key: element.key || "grid", - x: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(props.x) ? props.x : offset.left, - y: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(props.y) ? props.y : offset.top, - width: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(props.width) ? props.width : offset.width, - height: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(props.height) ? props.height : offset.height, - xAxis: xAxis, - yAxis: yAxis, - offset: offset, - chartWidth: width, - chartHeight: height, - verticalCoordinatesGenerator: _this7.verticalCoordinatesGenerator, - horizontalCoordinatesGenerator: _this7.horizontalCoordinatesGenerator - }); - }, this.renderPolarGrid = function(element) { - var _state13 = _this7.state, radiusAxisMap = _state13.radiusAxisMap, angleAxisMap = _state13.angleAxisMap, radiusAxis = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(radiusAxisMap), angleAxis = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.b)(angleAxisMap), cx = angleAxis.cx, cy = angleAxis.cy, innerRadius = angleAxis.innerRadius, outerRadius = angleAxis.outerRadius; - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element, { - polarAngles: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(angleAxis, !0).map(function(entry) { - return entry.coordinate; - }), - polarRadius: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.u)(radiusAxis, !0).map(function(entry) { - return entry.coordinate; - }), - cx: cx, - cy: cy, - innerRadius: innerRadius, - outerRadius: outerRadius, - key: element.key || "polar-grid" - }); - }, this.renderBrush = function(element) { - var _props7 = _this7.props, margin = _props7.margin, data = _props7.data, _state14 = _this7.state, offset = _state14.offset, dataStartIndex = _state14.dataStartIndex, dataEndIndex = _state14.dataEndIndex, updateId = _state14.updateId; - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element, { - key: element.key || "_recharts-brush", - onChange: Object(__WEBPACK_IMPORTED_MODULE_22__util_ChartUtils__.d)(_this7.handleBrushChange, null, element.props.onChange), - data: data, - x: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(element.props.x) ? element.props.x : offset.left, - y: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(element.props.y) ? element.props.y : offset.top + offset.height + offset.brushBottom - (margin.bottom || 0), - width: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.h)(element.props.width) ? element.props.width : offset.width, - startIndex: dataStartIndex, - endIndex: dataEndIndex, - updateId: "brush-" + updateId - }); - }, this.renderReferenceElement = function(element, displayName, index) { - if (!element) return null; - var _state15 = _this7.state, xAxisMap = _state15.xAxisMap, yAxisMap = _state15.yAxisMap, offset = _state15.offset, _element$props = element.props, xAxisId = _element$props.xAxisId, yAxisId = _element$props.yAxisId; - return Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element, { - key: element.key || displayName + "-" + index, - xAxis: xAxisMap[xAxisId], - yAxis: yAxisMap[yAxisId], - viewBox: { - x: offset.left, - y: offset.top, - width: offset.width, - height: offset.height - } - }); - }, this.renderGraphicChild = function(element, displayName, index) { - var item = _this7.filterFormatItem(element, displayName, index); - if (!item) return null; - var graphicalItem = Object(__WEBPACK_IMPORTED_MODULE_5_react__.cloneElement)(element, item.props), _state16 = _this7.state, isTooltipActive = _state16.isTooltipActive, tooltipAxis = _state16.tooltipAxis, activeTooltipIndex = _state16.activeTooltipIndex, activeLabel = _state16.activeLabel, children = _this7.props.children, tooltipItem = Object(__WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_10__component_Tooltip__.a), _item$props2 = item.props, points = _item$props2.points, isRange = _item$props2.isRange, baseLine = _item$props2.baseLine, _item$item$props2 = item.item.props, activeDot = _item$item$props2.activeDot; - if (!_item$item$props2.hide && isTooltipActive && tooltipItem && activeDot && activeTooltipIndex >= 0) { - var activePoint = void 0, basePoint = void 0; - if (tooltipAxis.dataKey && !tooltipAxis.allowDuplicatedCategory ? (activePoint = Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.a)(points, "payload." + tooltipAxis.dataKey, activeLabel), - basePoint = isRange && baseLine && Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.a)(baseLine, "payload." + tooltipAxis.dataKey, activeLabel)) : (activePoint = points[activeTooltipIndex], - basePoint = isRange && baseLine && baseLine[activeTooltipIndex]), !__WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(activePoint)) return [ graphicalItem ].concat(_toConsumableArray(_this7.renderActivePoints({ - item: item, - activePoint: activePoint, - basePoint: basePoint, - childIndex: activeTooltipIndex, - isRange: isRange - }))); - } - return isRange ? [ graphicalItem, null, null ] : [ graphicalItem, null ]; - }; - }, _temp; - }; - __webpack_exports__.a = generateCategoricalChart; -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - function invariant(condition, format, a, b, c, d, e, f) { - if (validateFormat(format), !condition) { - var error; - if (void 0 === format) error = new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings."); else { - var args = [ a, b, c, d, e, f ], argIndex = 0; - error = new Error(format.replace(/%s/g, function() { - return args[argIndex++]; - })), error.name = "Invariant Violation"; - } - throw error.framesToPop = 1, error; - } - } - var validateFormat = function(format) {}; - "production" !== process.env.NODE_ENV && (validateFormat = function(format) { - if (void 0 === format) throw new Error("invariant requires an error message argument"); - }), module.exports = invariant; - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - "use strict"; - function makeEmptyFunction(arg) { - return function() { - return arg; - }; - } - var emptyFunction = function() {}; - emptyFunction.thatReturns = makeEmptyFunction, emptyFunction.thatReturnsFalse = makeEmptyFunction(!1), - emptyFunction.thatReturnsTrue = makeEmptyFunction(!0), emptyFunction.thatReturnsNull = makeEmptyFunction(null), - emptyFunction.thatReturnsThis = function() { - return this; - }, emptyFunction.thatReturnsArgument = function(arg) { - return arg; - }, module.exports = emptyFunction; -}, function(module, exports, __webpack_require__) { - var aFunction = __webpack_require__(223); - module.exports = function(fn, that, length) { - if (aFunction(fn), void 0 === that) return fn; - switch (length) { - case 1: - return function(a) { - return fn.call(that, a); - }; - - case 2: - return function(a, b) { - return fn.call(that, a, b); - }; - - case 3: - return function(a, b, c) { - return fn.call(that, a, b, c); - }; - } - return function() { - return fn.apply(that, arguments); - }; - }; -}, function(module, exports, __webpack_require__) { - var isObject = __webpack_require__(35); - module.exports = function(it) { - if (!isObject(it)) throw TypeError(it + " is not an object!"); - return it; - }; -}, function(module, exports) { - module.exports = function(exec) { - try { - return !!exec(); - } catch (e) { - return !0; - } - }; -}, function(module, exports) { - var hasOwnProperty = {}.hasOwnProperty; - module.exports = function(it, key) { - return hasOwnProperty.call(it, key); - }; -}, function(module, exports, __webpack_require__) { - module.exports = { - default: __webpack_require__(421), - __esModule: !0 - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - function capitalize(string) { - if ("production" !== process.env.NODE_ENV && "string" != typeof string) throw new Error("Material-UI: capitalize(string) expects a string argument."); - return string.charAt(0).toUpperCase() + string.slice(1); - } - function contains(obj, pred) { - return (0, _keys2.default)(pred).every(function(key) { - return obj.hasOwnProperty(key) && obj[key] === pred[key]; - }); - } - function findIndex(arr, pred) { - for (var predType = void 0 === pred ? "undefined" : (0, _typeof3.default)(pred), i = 0; i < arr.length; i += 1) { - if ("function" === predType && !0 == !!pred(arr[i], i, arr)) return i; - if ("object" === predType && contains(arr[i], pred)) return i; - if (-1 !== [ "string", "number", "boolean" ].indexOf(predType)) return arr.indexOf(pred); - } - return -1; - } - function find(arr, pred) { - var index = findIndex(arr, pred); - return index > -1 ? arr[index] : void 0; - } - function createChainedFunction() { - for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) funcs[_key] = arguments[_key]; - return funcs.filter(function(func) { - return null != func; - }).reduce(function(acc, func) { - return "production" !== process.env.NODE_ENV && (0, _warning2.default)("function" == typeof func, "Material-UI: invalid Argument Type, must only provide functions, undefined, or null."), - function() { - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) args[_key2] = arguments[_key2]; - acc.apply(this, args), func.apply(this, args); - }; - }, function() {}); - } - Object.defineProperty(exports, "__esModule", { - value: !0 - }); - var _typeof2 = __webpack_require__(105), _typeof3 = _interopRequireDefault(_typeof2), _keys = __webpack_require__(55), _keys2 = _interopRequireDefault(_keys); - exports.capitalize = capitalize, exports.contains = contains, exports.findIndex = findIndex, - exports.find = find, exports.createChainedFunction = createChainedFunction; - var _warning = __webpack_require__(11), _warning2 = _interopRequireDefault(_warning); - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : void 0; - } - var baseIsNative = __webpack_require__(611), getValue = __webpack_require__(614); - module.exports = getNative; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_exports__.a = function(x) { - return function() { - return x; - }; - }; -}, function(module, exports, __webpack_require__) { - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : void 0; - } - var baseIsNative = __webpack_require__(668), getValue = __webpack_require__(673); - module.exports = getNative; -}, function(module, exports, __webpack_require__) { - function baseGetTag(value) { - return null == value ? void 0 === value ? undefinedTag : nullTag : symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value); - } - var Symbol = __webpack_require__(128), getRawTag = __webpack_require__(669), objectToString = __webpack_require__(670), nullTag = "[object Null]", undefinedTag = "[object Undefined]", symToStringTag = Symbol ? Symbol.toStringTag : void 0; - module.exports = baseGetTag; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _temp2, __WEBPACK_IMPORTED_MODULE_0_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_1_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_1_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_react__), __WEBPACK_IMPORTED_MODULE_2_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_2_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_prop_types__), __WEBPACK_IMPORTED_MODULE_3_reduce_css_calc__ = __webpack_require__(771), __WEBPACK_IMPORTED_MODULE_3_reduce_css_calc___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_reduce_css_calc__), __WEBPACK_IMPORTED_MODULE_4_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_4_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_classnames__), __WEBPACK_IMPORTED_MODULE_5__util_DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_6__util_ReactUtils__ = __webpack_require__(4), __WEBPACK_IMPORTED_MODULE_7__util_DOMUtils__ = __webpack_require__(198), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), BREAKING_SPACES = /[ \f\n\r\t\v\u2028\u2029]+/, calculateWordWidths = function(props) { - try { - return { - wordsWithComputedWidth: (__WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(props.children) ? [] : props.children.toString().split(BREAKING_SPACES)).map(function(word) { - return { - word: word, - width: Object(__WEBPACK_IMPORTED_MODULE_7__util_DOMUtils__.c)(word, props.style).width - }; - }), - spaceWidth: Object(__WEBPACK_IMPORTED_MODULE_7__util_DOMUtils__.c)(" ", props.style).width - }; - } catch (e) { - return null; - } - }, Text = (_temp2 = _class = function(_Component) { - function Text() { - var _ref, _temp, _this, _ret; - _classCallCheck(this, Text); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key]; - return _temp = _this = _possibleConstructorReturn(this, (_ref = Text.__proto__ || Object.getPrototypeOf(Text)).call.apply(_ref, [ this ].concat(args))), - _this.state = { - wordsByLines: [] - }, _ret = _temp, _possibleConstructorReturn(_this, _ret); - } - return _inherits(Text, _Component), _createClass(Text, [ { - key: "componentWillMount", - value: function() { - this.updateWordsByLines(this.props, !0); - } - }, { - key: "componentWillReceiveProps", - value: function(nextProps) { - var needCalculate = this.props.children !== nextProps.children || this.props.style !== nextProps.style; - this.updateWordsByLines(nextProps, needCalculate); - } - }, { - key: "updateWordsByLines", - value: function(props, needCalculate) { - if (!props.width && !props.scaleToFit || Object(__WEBPACK_IMPORTED_MODULE_6__util_ReactUtils__.n)()) this.updateWordsWithoutCalculate(props); else { - if (needCalculate) { - var wordWidths = calculateWordWidths(props); - if (!wordWidths) return void this.updateWordsWithoutCalculate(props); - var wordsWithComputedWidth = wordWidths.wordsWithComputedWidth, spaceWidth = wordWidths.spaceWidth; - this.wordsWithComputedWidth = wordsWithComputedWidth, this.spaceWidth = spaceWidth; - } - var wordsByLines = this.calculateWordsByLines(this.wordsWithComputedWidth, this.spaceWidth, props.width); - this.setState({ - wordsByLines: wordsByLines - }); - } - } - }, { - key: "updateWordsWithoutCalculate", - value: function(props) { - var words = __WEBPACK_IMPORTED_MODULE_0_lodash_isNil___default()(props.children) ? [] : props.children.toString().split(BREAKING_SPACES); - this.setState({ - wordsByLines: [ { - words: words - } ] - }); - } - }, { - key: "calculateWordsByLines", - value: function(wordsWithComputedWidth, spaceWidth, lineWidth) { - var scaleToFit = this.props.scaleToFit; - return wordsWithComputedWidth.reduce(function(result, _ref2) { - var word = _ref2.word, width = _ref2.width, currentLine = result[result.length - 1]; - if (currentLine && (null == lineWidth || scaleToFit || currentLine.width + width + spaceWidth < lineWidth)) currentLine.words.push(word), - currentLine.width += width + spaceWidth; else { - var newLine = { - words: [ word ], - width: width - }; - result.push(newLine); - } - return result; - }, []); - } - }, { - key: "render", - value: function() { - var _props = this.props, dx = _props.dx, dy = _props.dy, textAnchor = _props.textAnchor, verticalAnchor = _props.verticalAnchor, scaleToFit = _props.scaleToFit, angle = _props.angle, lineHeight = _props.lineHeight, capHeight = _props.capHeight, className = _props.className, textProps = _objectWithoutProperties(_props, [ "dx", "dy", "textAnchor", "verticalAnchor", "scaleToFit", "angle", "lineHeight", "capHeight", "className" ]), wordsByLines = this.state.wordsByLines; - if (!Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.g)(textProps.x) || !Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.g)(textProps.y)) return null; - var x = textProps.x + (Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.h)(dx) ? dx : 0), y = textProps.y + (Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.h)(dy) ? dy : 0), startDy = void 0; - switch (verticalAnchor) { - case "start": - startDy = __WEBPACK_IMPORTED_MODULE_3_reduce_css_calc___default()("calc(" + capHeight + ")"); - break; - - case "middle": - startDy = __WEBPACK_IMPORTED_MODULE_3_reduce_css_calc___default()("calc(" + (wordsByLines.length - 1) / 2 + " * -" + lineHeight + " + (" + capHeight + " / 2))"); - break; - - default: - startDy = __WEBPACK_IMPORTED_MODULE_3_reduce_css_calc___default()("calc(" + (wordsByLines.length - 1) + " * -" + lineHeight + ")"); - } - var transforms = []; - if (scaleToFit) { - var lineWidth = wordsByLines[0].width; - transforms.push("scale(" + this.props.width / lineWidth + ")"); - } - return angle && transforms.push("rotate(" + angle + ", " + x + ", " + y + ")"), - transforms.length && (textProps.transform = transforms.join(" ")), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("text", _extends({}, Object(__WEBPACK_IMPORTED_MODULE_6__util_ReactUtils__.k)(textProps), { - x: x, - y: y, - className: __WEBPACK_IMPORTED_MODULE_4_classnames___default()("recharts-text", className), - textAnchor: textAnchor - }), wordsByLines.map(function(line, index) { - return __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("tspan", { - x: x, - dy: 0 === index ? startDy : lineHeight, - key: index - }, line.words.join(" ")); - })); - } - } ]), Text; - }(__WEBPACK_IMPORTED_MODULE_1_react__.Component), _class.propTypes = _extends({}, __WEBPACK_IMPORTED_MODULE_6__util_ReactUtils__.c, { - scaleToFit: __WEBPACK_IMPORTED_MODULE_2_prop_types___default.a.bool, - angle: __WEBPACK_IMPORTED_MODULE_2_prop_types___default.a.number, - textAnchor: __WEBPACK_IMPORTED_MODULE_2_prop_types___default.a.oneOf([ "start", "middle", "end", "inherit" ]), - verticalAnchor: __WEBPACK_IMPORTED_MODULE_2_prop_types___default.a.oneOf([ "start", "middle", "end" ]), - style: __WEBPACK_IMPORTED_MODULE_2_prop_types___default.a.object - }), _class.defaultProps = { - x: 0, - y: 0, - lineHeight: "1em", - capHeight: "0.71em", - scaleToFit: !1, - textAnchor: "start", - verticalAnchor: "end" - }, _temp2); - __webpack_exports__.a = Text; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_require__.d(__webpack_exports__, "a", function() { - return map; - }), __webpack_require__.d(__webpack_exports__, "b", function() { - return slice; - }); - var array = Array.prototype, map = array.map, slice = array.slice; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _class2, _temp, __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_2_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_classnames__), __WEBPACK_IMPORTED_MODULE_3__util_PureRender__ = __webpack_require__(5), __WEBPACK_IMPORTED_MODULE_4__util_ReactUtils__ = __webpack_require__(4), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), Dot = Object(__WEBPACK_IMPORTED_MODULE_3__util_PureRender__.a)((_temp = _class2 = function(_Component) { - function Dot() { - return _classCallCheck(this, Dot), _possibleConstructorReturn(this, (Dot.__proto__ || Object.getPrototypeOf(Dot)).apply(this, arguments)); - } - return _inherits(Dot, _Component), _createClass(Dot, [ { - key: "render", - value: function() { - var _props = this.props, cx = _props.cx, cy = _props.cy, r = _props.r, className = _props.className, layerClass = __WEBPACK_IMPORTED_MODULE_2_classnames___default()("recharts-dot", className); - return cx === +cx && cy === +cy && r === +r ? __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("circle", _extends({}, Object(__WEBPACK_IMPORTED_MODULE_4__util_ReactUtils__.k)(this.props), Object(__WEBPACK_IMPORTED_MODULE_4__util_ReactUtils__.e)(this.props, null, !0), { - className: layerClass, - cx: cx, - cy: cy, - r: r - })) : null; - } - } ]), Dot; - }(__WEBPACK_IMPORTED_MODULE_0_react__.Component), _class2.displayName = "Dot", _class2.propTypes = { - className: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, - cx: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - cy: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - r: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number - }, _class = _temp)) || _class; - __webpack_exports__.a = Dot; -}, function(module, exports, __webpack_require__) { - var IObject = __webpack_require__(146), defined = __webpack_require__(148); - module.exports = function(it) { - return IObject(defined(it)); - }; -}, function(module, exports, __webpack_require__) { - var defined = __webpack_require__(148); - module.exports = function(it) { - return Object(defined(it)); - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - Object.defineProperty(exports, "__esModule", { - value: !0 - }); - var _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) { - return typeof obj; - } : function(obj) { - return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), _warning = __webpack_require__(11), _warning2 = _interopRequireDefault(_warning), _toCss = __webpack_require__(163), _toCss2 = _interopRequireDefault(_toCss), _toCssValue = __webpack_require__(110), _toCssValue2 = _interopRequireDefault(_toCssValue), StyleRule = function() { - function StyleRule(key, style, options) { - _classCallCheck(this, StyleRule), this.type = "style", this.isProcessed = !1; - var sheet = options.sheet, Renderer = options.Renderer, selector = options.selector; - this.key = key, this.options = options, this.style = style, selector && (this.selectorText = selector), - this.renderer = sheet ? sheet.renderer : new Renderer(); - } - return _createClass(StyleRule, [ { - key: "prop", - value: function(name, value) { - if (void 0 === value) return this.style[name]; - if (this.style[name] === value) return this; - value = this.options.jss.plugins.onChangeValue(value, name, this); - var isEmpty = null == value || !1 === value, isDefined = name in this.style; - if (isEmpty && !isDefined) return this; - var remove = isEmpty && isDefined; - if (remove ? delete this.style[name] : this.style[name] = value, this.renderable) return remove ? this.renderer.removeProperty(this.renderable, name) : this.renderer.setProperty(this.renderable, name, value), - this; - var sheet = this.options.sheet; - return sheet && sheet.attached && (0, _warning2.default)(!1, 'Rule is not linked. Missing sheet option "link: true".'), - this; - } - }, { - key: "applyTo", - value: function(renderable) { - var json = this.toJSON(); - for (var prop in json) this.renderer.setProperty(renderable, prop, json[prop]); - return this; - } - }, { - key: "toJSON", - value: function() { - var json = {}; - for (var prop in this.style) { - var value = this.style[prop]; - "object" !== (void 0 === value ? "undefined" : _typeof(value)) ? json[prop] = value : Array.isArray(value) && (json[prop] = (0, - _toCssValue2.default)(value)); - } - return json; - } - }, { - key: "toString", - value: function(options) { - var sheet = this.options.sheet, link = !!sheet && sheet.options.link, opts = link ? _extends({}, options, { - allowEmpty: !0 - }) : options; - return (0, _toCss2.default)(this.selector, this.style, opts); - } - }, { - key: "selector", - set: function(selector) { - if (selector !== this.selectorText && (this.selectorText = selector, this.renderable)) { - if (!this.renderer.setSelector(this.renderable, selector) && this.renderable) { - var renderable = this.renderer.replaceRule(this.renderable, this); - renderable && (this.renderable = renderable); - } - } - }, - get: function() { - return this.selectorText; - } - } ]), StyleRule; - }(); - exports.default = StyleRule; -}, function(module, exports, __webpack_require__) { - function isSymbol(value) { - return "symbol" == typeof value || isObjectLike(value) && baseGetTag(value) == symbolTag; - } - var baseGetTag = __webpack_require__(41), isObjectLike = __webpack_require__(42), symbolTag = "[object Symbol]"; - module.exports = isSymbol; -}, function(module, exports) { - function identity(value) { - return value; - } - module.exports = identity; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_exports__.a = function(a, b) { - return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _class2, _temp2, __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_2_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_classnames__), __WEBPACK_IMPORTED_MODULE_3_react_smooth__ = __webpack_require__(33), __WEBPACK_IMPORTED_MODULE_3_react_smooth___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_react_smooth__), __WEBPACK_IMPORTED_MODULE_4__util_PureRender__ = __webpack_require__(5), __WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__ = __webpack_require__(4), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), getRectangePath = function(x, y, width, height, radius) { - var maxRadius = Math.min(Math.abs(width) / 2, Math.abs(height) / 2), sign = height >= 0 ? 1 : -1, clockWise = height >= 0 ? 1 : 0, path = void 0; - if (maxRadius > 0 && radius instanceof Array) { - for (var newRadius = [], i = 0; i < 4; i++) newRadius[i] = radius[i] > maxRadius ? maxRadius : radius[i]; - path = "M" + x + "," + (y + sign * newRadius[0]), newRadius[0] > 0 && (path += "A " + newRadius[0] + "," + newRadius[0] + ",0,0," + clockWise + "," + (x + newRadius[0]) + "," + y), - path += "L " + (x + width - newRadius[1]) + "," + y, newRadius[1] > 0 && (path += "A " + newRadius[1] + "," + newRadius[1] + ",0,0," + clockWise + ",\n " + (x + width) + "," + (y + sign * newRadius[1])), - path += "L " + (x + width) + "," + (y + height - sign * newRadius[2]), newRadius[2] > 0 && (path += "A " + newRadius[2] + "," + newRadius[2] + ",0,0," + clockWise + ",\n " + (x + width - newRadius[2]) + "," + (y + height)), - path += "L " + (x + newRadius[3]) + "," + (y + height), newRadius[3] > 0 && (path += "A " + newRadius[3] + "," + newRadius[3] + ",0,0," + clockWise + ",\n " + x + "," + (y + height - sign * newRadius[3])), - path += "Z"; - } else if (maxRadius > 0 && radius === +radius && radius > 0) { - var _newRadius = Math.min(maxRadius, radius); - path = "M " + x + "," + (y + sign * _newRadius) + "\n A " + _newRadius + "," + _newRadius + ",0,0," + clockWise + "," + (x + _newRadius) + "," + y + "\n L " + (x + width - _newRadius) + "," + y + "\n A " + _newRadius + "," + _newRadius + ",0,0," + clockWise + "," + (x + width) + "," + (y + sign * _newRadius) + "\n L " + (x + width) + "," + (y + height - sign * _newRadius) + "\n A " + _newRadius + "," + _newRadius + ",0,0," + clockWise + "," + (x + width - _newRadius) + "," + (y + height) + "\n L " + (x + _newRadius) + "," + (y + height) + "\n A " + _newRadius + "," + _newRadius + ",0,0," + clockWise + "," + x + "," + (y + height - sign * _newRadius) + " Z"; - } else path = "M " + x + "," + y + " h " + width + " v " + height + " h " + -width + " Z"; - return path; - }, Rectangle = Object(__WEBPACK_IMPORTED_MODULE_4__util_PureRender__.a)((_temp2 = _class2 = function(_Component) { - function Rectangle() { - var _ref, _temp, _this, _ret; - _classCallCheck(this, Rectangle); - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) args[_key] = arguments[_key]; - return _temp = _this = _possibleConstructorReturn(this, (_ref = Rectangle.__proto__ || Object.getPrototypeOf(Rectangle)).call.apply(_ref, [ this ].concat(args))), - _this.state = { - totalLength: -1 - }, _ret = _temp, _possibleConstructorReturn(_this, _ret); - } - return _inherits(Rectangle, _Component), _createClass(Rectangle, [ { - key: "componentDidMount", - value: function() { - if (this.node && this.node.getTotalLength) try { - var totalLength = this.node.getTotalLength(); - totalLength && this.setState({ - totalLength: totalLength - }); - } catch (err) {} - } - }, { - key: "render", - value: function() { - var _this2 = this, _props = this.props, x = _props.x, y = _props.y, width = _props.width, height = _props.height, radius = _props.radius, className = _props.className, totalLength = this.state.totalLength, _props2 = this.props, animationEasing = _props2.animationEasing, animationDuration = _props2.animationDuration, animationBegin = _props2.animationBegin, isAnimationActive = _props2.isAnimationActive, isUpdateAnimationActive = _props2.isUpdateAnimationActive; - if (x !== +x || y !== +y || width !== +width || height !== +height || 0 === width || 0 === height) return null; - var layerClass = __WEBPACK_IMPORTED_MODULE_2_classnames___default()("recharts-rectangle", className); - return isUpdateAnimationActive ? __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_3_react_smooth___default.a, { - canBegin: totalLength > 0, - from: { - width: width, - height: height, - x: x, - y: y - }, - to: { - width: width, - height: height, - x: x, - y: y - }, - duration: animationDuration, - animationEasing: animationEasing, - isActive: isUpdateAnimationActive - }, function(_ref2) { - var currWidth = _ref2.width, currHeight = _ref2.height, currX = _ref2.x, currY = _ref2.y; - return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_3_react_smooth___default.a, { - canBegin: totalLength > 0, - from: "0px " + (-1 === totalLength ? 1 : totalLength) + "px", - to: totalLength + "px 0px", - attributeName: "strokeDasharray", - begin: animationBegin, - duration: animationDuration, - isActive: isAnimationActive, - easing: animationEasing - }, __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("path", _extends({}, Object(__WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__.k)(_this2.props), Object(__WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__.e)(_this2.props), { - className: layerClass, - d: getRectangePath(currX, currY, currWidth, currHeight, radius), - ref: function(node) { - _this2.node = node; - } - }))); - }) : __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("path", _extends({}, Object(__WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__.k)(this.props), Object(__WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__.e)(this.props), { - className: layerClass, - d: getRectangePath(x, y, width, height, radius) - })); - } - } ]), Rectangle; - }(__WEBPACK_IMPORTED_MODULE_0_react__.Component), _class2.displayName = "Rectangle", - _class2.propTypes = _extends({}, __WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__.c, __WEBPACK_IMPORTED_MODULE_5__util_ReactUtils__.a, { - className: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, - x: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - y: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - width: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - radius: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.array ]), - isAnimationActive: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - isUpdateAnimationActive: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - animationBegin: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - animationDuration: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - animationEasing: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "ease", "ease-in", "ease-out", "ease-in-out", "linear" ]) - }), _class2.defaultProps = { - x: 0, - y: 0, - width: 0, - height: 0, - radius: 0, - isAnimationActive: !1, - isUpdateAnimationActive: !1, - animationBegin: 0, - animationDuration: 1500, - animationEasing: "ease" - }, _class = _temp2)) || _class; - __webpack_exports__.a = Rectangle; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _class2, _temp, __WEBPACK_IMPORTED_MODULE_0_lodash_isArray__ = __webpack_require__(13), __WEBPACK_IMPORTED_MODULE_0_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_2_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_2_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_react__), __WEBPACK_IMPORTED_MODULE_3_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_3_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_prop_types__), __WEBPACK_IMPORTED_MODULE_4_d3_shape__ = __webpack_require__(182), __WEBPACK_IMPORTED_MODULE_5_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_5_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_classnames__), __WEBPACK_IMPORTED_MODULE_6__util_PureRender__ = __webpack_require__(5), __WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__ = __webpack_require__(4), __WEBPACK_IMPORTED_MODULE_8__util_DataUtils__ = __webpack_require__(9), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), CURVE_FACTORIES = { - curveBasisClosed: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.c, - curveBasisOpen: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.d, - curveBasis: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.b, - curveLinearClosed: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.f, - curveLinear: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.e, - curveMonotoneX: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.g, - curveMonotoneY: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.h, - curveNatural: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.i, - curveStep: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.j, - curveStepAfter: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.k, - curveStepBefore: __WEBPACK_IMPORTED_MODULE_4_d3_shape__.l - }, defined = function(p) { - return p.x === +p.x && p.y === +p.y; - }, getX = function(p) { - return p.x; - }, getY = function(p) { - return p.y; - }, getCurveFactory = function(type, layout) { - if (__WEBPACK_IMPORTED_MODULE_1_lodash_isFunction___default()(type)) return type; - var name = "curve" + type.slice(0, 1).toUpperCase() + type.slice(1); - return "curveMonotone" === name && layout ? CURVE_FACTORIES[name + ("vertical" === layout ? "Y" : "X")] : CURVE_FACTORIES[name] || __WEBPACK_IMPORTED_MODULE_4_d3_shape__.e; - }, Curve = Object(__WEBPACK_IMPORTED_MODULE_6__util_PureRender__.a)((_temp = _class2 = function(_Component) { - function Curve() { - return _classCallCheck(this, Curve), _possibleConstructorReturn(this, (Curve.__proto__ || Object.getPrototypeOf(Curve)).apply(this, arguments)); - } - return _inherits(Curve, _Component), _createClass(Curve, [ { - key: "getPath", - value: function() { - var _props = this.props, type = _props.type, points = _props.points, baseLine = _props.baseLine, layout = _props.layout, connectNulls = _props.connectNulls, curveFactory = getCurveFactory(type, layout), formatPoints = connectNulls ? points.filter(function(entry) { - return defined(entry); - }) : points, lineFunction = void 0; - if (__WEBPACK_IMPORTED_MODULE_0_lodash_isArray___default()(baseLine)) { - var areaPoints = formatPoints.map(function(entry, index) { - return _extends({}, entry, { - base: baseLine[index] }); - }); - return lineFunction = "vertical" === layout ? Object(__WEBPACK_IMPORTED_MODULE_4_d3_shape__.a)().y(getY).x1(getX).x0(function(d) { - return d.base.x; - }) : Object(__WEBPACK_IMPORTED_MODULE_4_d3_shape__.a)().x(getX).y1(getY).y0(function(d) { - return d.base.y; - }), lineFunction.defined(defined).curve(curveFactory), lineFunction(areaPoints); + }), _defineProperty(_assertThisInitialized(t), "changeContent", function(e) { + t.setState(function(t) { + return t.active !== e ? { + active: e + } : {}; + }); + }), _defineProperty(_assertThisInitialized(t), "switchSideBar", function() { + t.setState(function(e) { + return { + sideBar: !e.sideBar + }; + }); + }), t.state = { + active: _common__WEBPACK_IMPORTED_MODULE_7__.b.get("home").id, + sideBar: !0, + content: defaultContent(), + shouldUpdate: {}, + server: null + }, t; } - return lineFunction = "vertical" === layout && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(baseLine) ? Object(__WEBPACK_IMPORTED_MODULE_4_d3_shape__.a)().y(getY).x1(getX).x0(baseLine) : Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(baseLine) ? Object(__WEBPACK_IMPORTED_MODULE_4_d3_shape__.a)().x(getX).y1(getY).y0(baseLine) : Object(__WEBPACK_IMPORTED_MODULE_4_d3_shape__.m)().x(getX).y(getY), - lineFunction.defined(defined).curve(curveFactory), lineFunction(formatPoints); - } - }, { - key: "render", - value: function() { - var _props2 = this.props, className = _props2.className, points = _props2.points, path = _props2.path, pathRef = _props2.pathRef; - if (!(points && points.length || path)) return null; - var realPath = points && points.length ? this.getPath() : path; - return __WEBPACK_IMPORTED_MODULE_2_react___default.a.createElement("path", _extends({}, Object(__WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__.k)(this.props), Object(__WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__.e)(this.props, null, !0), { - className: __WEBPACK_IMPORTED_MODULE_5_classnames___default()("recharts-curve", className), - d: realPath, - ref: pathRef - })); - } - } ]), Curve; - }(__WEBPACK_IMPORTED_MODULE_2_react__.Component), _class2.displayName = "Curve", - _class2.propTypes = _extends({}, __WEBPACK_IMPORTED_MODULE_7__util_ReactUtils__.c, { - className: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.string, - type: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.oneOf([ "basis", "basisClosed", "basisOpen", "linear", "linearClosed", "natural", "monotoneX", "monotoneY", "monotone", "step", "stepBefore", "stepAfter" ]), __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.func ]), - layout: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.oneOf([ "horizontal", "vertical" ]), - baseLine: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.array ]), - points: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.object), - connectNulls: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.bool, - path: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.string, - pathRef: __WEBPACK_IMPORTED_MODULE_3_prop_types___default.a.func - }), _class2.defaultProps = { - type: "linear", - points: [], - connectNulls: !1 - }, _class = _temp)) || _class; - __webpack_exports__.a = Curve; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _class2, _temp, __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = (__webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), - __webpack_require__(1)), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2__util_PureRender__ = __webpack_require__(5), __WEBPACK_IMPORTED_MODULE_3__util_ReactUtils__ = __webpack_require__(4), _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), XAxis = Object(__WEBPACK_IMPORTED_MODULE_2__util_PureRender__.a)((_temp = _class2 = function(_Component) { - function XAxis() { - return _classCallCheck(this, XAxis), _possibleConstructorReturn(this, (XAxis.__proto__ || Object.getPrototypeOf(XAxis)).apply(this, arguments)); - } - return _inherits(XAxis, _Component), _createClass(XAxis, [ { - key: "render", - value: function() { - return null; - } - } ]), XAxis; - }(__WEBPACK_IMPORTED_MODULE_0_react__.Component), _class2.displayName = "XAxis", - _class2.propTypes = { - allowDecimals: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - allowDuplicatedCategory: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - hide: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - name: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number ]), - unit: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number ]), - xAxisId: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number ]), - domain: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "auto", "dataMin", "dataMax" ]) ])), - dataKey: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func ]), - width: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - mirror: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - orientation: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "top", "bottom" ]), - type: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "number", "category" ]), - ticks: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.array, - tickCount: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - tickFormatter: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, - padding: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.shape({ - left: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - right: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number - }), - allowDataOverflow: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - scale: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf(__WEBPACK_IMPORTED_MODULE_3__util_ReactUtils__.d), __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func ]), - tick: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.element ]), - axisLine: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object ]), - tickLine: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object ]), - minTickGap: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - tickSize: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - interval: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "preserveStart", "preserveEnd", "preserveStartEnd" ]) ]), - reversed: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool - }, _class2.defaultProps = { - allowDecimals: !0, - hide: !1, - orientation: "bottom", - width: 0, - height: 30, - mirror: !1, - xAxisId: 0, - tickCount: 5, - type: "category", - domain: [ 0, "auto" ], - padding: { - left: 0, - right: 0 - }, - allowDataOverflow: !1, - scale: "auto", - reversed: !1, - allowDuplicatedCategory: !0 - }, _class = _temp)) || _class; - __webpack_exports__.a = XAxis; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _class2, _temp, __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = (__webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), - __webpack_require__(1)), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2__util_PureRender__ = __webpack_require__(5), _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), YAxis = Object(__WEBPACK_IMPORTED_MODULE_2__util_PureRender__.a)((_temp = _class2 = function(_Component) { - function YAxis() { - return _classCallCheck(this, YAxis), _possibleConstructorReturn(this, (YAxis.__proto__ || Object.getPrototypeOf(YAxis)).apply(this, arguments)); - } - return _inherits(YAxis, _Component), _createClass(YAxis, [ { - key: "render", - value: function() { - return null; - } - } ]), YAxis; - }(__WEBPACK_IMPORTED_MODULE_0_react__.Component), _class2.displayName = "YAxis", - _class2.propTypes = { - allowDecimals: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - allowDuplicatedCategory: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - hide: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - name: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number ]), - unit: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number ]), - yAxisId: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number ]), - domain: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "auto", "dataMin", "dataMax" ]) ])), - dataKey: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func ]), - ticks: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.array, - tickCount: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - tickFormatter: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, - width: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - mirror: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - orientation: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "left", "right" ]), - type: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "number", "category" ]), - padding: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.shape({ - top: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - bottom: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number - }), - allowDataOverflow: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, - scale: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "auto", "linear", "pow", "sqrt", "log", "identity", "time", "band", "point", "ordinal", "quantile", "quantize", "utcTime", "sequential", "threshold" ]), __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func ]), - tick: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.element ]), - axisLine: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object ]), - tickLine: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object ]), - minTickGap: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - tickSize: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - interval: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOf([ "preserveStart", "preserveEnd", "preserveStartEnd" ]) ]), - reversed: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.bool - }, _class2.defaultProps = { - allowDuplicatedCategory: !0, - allowDecimals: !0, - hide: !1, - orientation: "left", - width: 60, - height: 0, - mirror: !1, - yAxisId: 0, - tickCount: 5, - type: "number", - domain: [ 0, "auto" ], - padding: { - top: 0, - bottom: 0 - }, - allowDataOverflow: !1, - scale: "auto", - reversed: !1 - }, _class = _temp)) || _class; - __webpack_exports__.a = YAxis; -}, function(module, exports, __webpack_require__) { - "use strict"; - function toObject(val) { - if (null === val || void 0 === val) throw new TypeError("Object.assign cannot be called with null or undefined"); - return Object(val); - } - var getOwnPropertySymbols = Object.getOwnPropertySymbols, hasOwnProperty = Object.prototype.hasOwnProperty, propIsEnumerable = Object.prototype.propertyIsEnumerable; - module.exports = function() { - try { - if (!Object.assign) return !1; - var test1 = new String("abc"); - if (test1[5] = "de", "5" === Object.getOwnPropertyNames(test1)[0]) return !1; - for (var test2 = {}, i = 0; i < 10; i++) test2["_" + String.fromCharCode(i)] = i; - if ("0123456789" !== Object.getOwnPropertyNames(test2).map(function(n) { - return test2[n]; - }).join("")) return !1; - var test3 = {}; - return "abcdefghijklmnopqrst".split("").forEach(function(letter) { - test3[letter] = letter; - }), "abcdefghijklmnopqrst" === Object.keys(Object.assign({}, test3)).join(""); - } catch (err) { - return !1; - } - }() ? Object.assign : function(target, source) { - for (var from, symbols, to = toObject(target), s = 1; s < arguments.length; s++) { - from = Object(arguments[s]); - for (var key in from) hasOwnProperty.call(from, key) && (to[key] = from[key]); - if (getOwnPropertySymbols) { - symbols = getOwnPropertySymbols(from); - for (var i = 0; i < symbols.length; i++) propIsEnumerable.call(from, symbols[i]) && (to[symbols[i]] = from[symbols[i]]); - } - } - return to; - }; -}, function(module, exports) { - module.exports = function(bitmap, value) { - return { - enumerable: !(1 & bitmap), - configurable: !(2 & bitmap), - writable: !(4 & bitmap), - value: value - }; - }; -}, function(module, exports, __webpack_require__) { - var $keys = __webpack_require__(226), enumBugKeys = __webpack_require__(152); - module.exports = Object.keys || function(O) { - return $keys(O, enumBugKeys); - }; -}, function(module, exports) { - module.exports = {}; -}, function(module, exports, __webpack_require__) { - "use strict"; - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - function createBreakpoints(breakpoints) { - function up(key) { - return "@media (min-width:" + ("number" == typeof values[key] ? values[key] : key) + unit + ")"; - } - function down(key) { - var endIndex = keys.indexOf(key) + 1, upperbound = values[keys[endIndex]]; - return endIndex === keys.length ? up("xs") : "@media (max-width:" + (("number" == typeof upperbound && endIndex > 0 ? upperbound : key) - step / 100) + unit + ")"; - } - function between(start, end) { - var endIndex = keys.indexOf(end) + 1; - return endIndex === keys.length ? up(start) : "@media (min-width:" + values[start] + unit + ") and (max-width:" + (values[keys[endIndex]] - step / 100) + unit + ")"; - } - function only(key) { - return between(key, key); - } - function width(key) { - return values[key]; - } - var _breakpoints$values = breakpoints.values, values = void 0 === _breakpoints$values ? { - xs: 0, - sm: 600, - md: 960, - lg: 1280, - xl: 1920 - } : _breakpoints$values, _breakpoints$unit = breakpoints.unit, unit = void 0 === _breakpoints$unit ? "px" : _breakpoints$unit, _breakpoints$step = breakpoints.step, step = void 0 === _breakpoints$step ? 5 : _breakpoints$step, other = (0, - _objectWithoutProperties3.default)(breakpoints, [ "values", "unit", "step" ]); - return (0, _extends3.default)({ - keys: keys, - values: values, - up: up, - down: down, - between: between, - only: only, - width: width - }, other); - } - Object.defineProperty(exports, "__esModule", { - value: !0 - }), exports.keys = void 0; - var _extends2 = __webpack_require__(6), _extends3 = _interopRequireDefault(_extends2), _objectWithoutProperties2 = __webpack_require__(7), _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); - exports.default = createBreakpoints; - var keys = exports.keys = [ "xs", "sm", "md", "lg", "xl" ]; -}, function(module, exports, __webpack_require__) { - "use strict"; - exports.__esModule = !0; - var _getDisplayName = __webpack_require__(244), _getDisplayName2 = function(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - }(_getDisplayName), wrapDisplayName = function(BaseComponent, hocName) { - return hocName + "(" + (0, _getDisplayName2.default)(BaseComponent) + ")"; - }; - exports.default = wrapDisplayName; -}, function(module, exports, __webpack_require__) { - "use strict"; - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - Object.defineProperty(exports, "__esModule", { - value: !0 - }); - var _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), _createRule = __webpack_require__(111), _createRule2 = _interopRequireDefault(_createRule), _linkRule = __webpack_require__(249), _linkRule2 = _interopRequireDefault(_linkRule), _StyleRule = __webpack_require__(66), _StyleRule2 = _interopRequireDefault(_StyleRule), _escape = __webpack_require__(467), _escape2 = _interopRequireDefault(_escape), RuleList = function() { - function RuleList(options) { - _classCallCheck(this, RuleList), this.map = {}, this.raw = {}, this.index = [], - this.options = options, this.classes = options.classes; - } - return _createClass(RuleList, [ { - key: "add", - value: function(name, decl, options) { - var _options = this.options, parent = _options.parent, sheet = _options.sheet, jss = _options.jss, Renderer = _options.Renderer, generateClassName = _options.generateClassName; - options = _extends({ - classes: this.classes, - parent: parent, - sheet: sheet, - jss: jss, - Renderer: Renderer, - generateClassName: generateClassName - }, options), !options.selector && this.classes[name] && (options.selector = "." + (0, - _escape2.default)(this.classes[name])), this.raw[name] = decl; - var rule = (0, _createRule2.default)(name, decl, options), className = void 0; - !options.selector && rule instanceof _StyleRule2.default && (className = generateClassName(rule, sheet), - rule.selector = "." + (0, _escape2.default)(className)), this.register(rule, className); - var index = void 0 === options.index ? this.index.length : options.index; - return this.index.splice(index, 0, rule), rule; - } - }, { - key: "get", - value: function(name) { - return this.map[name]; - } - }, { - key: "remove", - value: function(rule) { - this.unregister(rule), this.index.splice(this.indexOf(rule), 1); - } - }, { - key: "indexOf", - value: function(rule) { - return this.index.indexOf(rule); - } - }, { - key: "process", - value: function() { - var plugins = this.options.jss.plugins; - this.index.slice(0).forEach(plugins.onProcessRule, plugins); - } - }, { - key: "register", - value: function(rule, className) { - this.map[rule.key] = rule, rule instanceof _StyleRule2.default && (this.map[rule.selector] = rule, - className && (this.classes[rule.key] = className)); - } - }, { - key: "unregister", - value: function(rule) { - delete this.map[rule.key], rule instanceof _StyleRule2.default && (delete this.map[rule.selector], - delete this.classes[rule.key]); - } - }, { - key: "update", - value: function(name, data) { - var _options2 = this.options, plugins = _options2.jss.plugins, sheet = _options2.sheet; - if ("string" == typeof name) return void plugins.onUpdate(data, this.get(name), sheet); - for (var index = 0; index < this.index.length; index++) plugins.onUpdate(name, this.index[index], sheet); - } - }, { - key: "link", - value: function(cssRules) { - for (var map = this.options.sheet.renderer.getUnescapedKeysMap(this.index), i = 0; i < cssRules.length; i++) { - var cssRule = cssRules[i], _key = this.options.sheet.renderer.getKey(cssRule); - map[_key] && (_key = map[_key]); - var rule = this.map[_key]; - rule && (0, _linkRule2.default)(rule, cssRule); - } - } - }, { - key: "toString", - value: function(options) { - for (var str = "", sheet = this.options.sheet, link = !!sheet && sheet.options.link, index = 0; index < this.index.length; index++) { - var rule = this.index[index], css = rule.toString(options); - (css || link) && (str && (str += "\n"), str += css); - } - return str; - } - } ]), RuleList; - }(); - exports.default = RuleList; -}, function(module, exports, __webpack_require__) { - "use strict"; - Object.defineProperty(exports, "__esModule", { - value: !0 - }); - var _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, menuSkeletons = [ { - id: "home", - menu: { - title: "Home", - icon: "home" - } - }, { - id: "chain", - menu: { - title: "Chain", - icon: "link" - } - }, { - id: "txpool", - menu: { - title: "TxPool", - icon: "credit-card" - } - }, { - id: "network", - menu: { - title: "Network", - icon: "globe" - } - }, { - id: "system", - menu: { - title: "System", - icon: "tachometer" - } - }, { - id: "logs", - menu: { - title: "Logs", - icon: "list" - } - } ]; - exports.MENU = new Map(menuSkeletons.map(function(_ref) { - var id = _ref.id, menu = _ref.menu; - return [ id, _extends({ - id: id - }, menu) ]; - })), exports.DURATION = 200, exports.styles = { - light: { - color: "rgba(255, 255, 255, 0.54)" - } - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - function Surface(props) { - var children = props.children, width = props.width, height = props.height, viewBox = props.viewBox, className = props.className, style = props.style, others = _objectWithoutProperties(props, [ "children", "width", "height", "viewBox", "className", "style" ]), svgView = viewBox || { - width: width, - height: height, - x: 0, - y: 0 - }, layerClass = __WEBPACK_IMPORTED_MODULE_2_classnames___default()("recharts-surface", className), attrs = Object(__WEBPACK_IMPORTED_MODULE_3__util_ReactUtils__.k)(others); - return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("svg", _extends({}, attrs, { - className: layerClass, - width: width, - height: height, - style: style, - viewBox: svgView.x + " " + svgView.y + " " + svgView.width + " " + svgView.height, - version: "1.1" - }), children); - } - var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2_classnames__ = __webpack_require__(3), __WEBPACK_IMPORTED_MODULE_2_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_classnames__), __WEBPACK_IMPORTED_MODULE_3__util_ReactUtils__ = __webpack_require__(4), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, propTypes = { - width: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number.isRequired, - height: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number.isRequired, - viewBox: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.shape({ - x: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - y: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - width: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - height: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number - }), - className: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, - style: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object, - children: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.arrayOf(__WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.node), __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.node ]) - }; - Surface.propTypes = propTypes, __webpack_exports__.a = Surface; -}, function(module, exports, __webpack_require__) { - var root = __webpack_require__(31), Symbol = root.Symbol; - module.exports = Symbol; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - var __WEBPACK_IMPORTED_MODULE_0__src_path__ = __webpack_require__(633); - __webpack_require__.d(__webpack_exports__, "a", function() { - return __WEBPACK_IMPORTED_MODULE_0__src_path__.a; - }); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function acos(x) { - return x > 1 ? 0 : x < -1 ? pi : Math.acos(x); - } - function asin(x) { - return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x); - } - __webpack_require__.d(__webpack_exports__, "a", function() { - return abs; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return atan2; - }), __webpack_require__.d(__webpack_exports__, "e", function() { - return cos; - }), __webpack_require__.d(__webpack_exports__, "h", function() { - return max; - }), __webpack_require__.d(__webpack_exports__, "i", function() { - return min; - }), __webpack_require__.d(__webpack_exports__, "k", function() { - return sin; - }), __webpack_require__.d(__webpack_exports__, "l", function() { - return sqrt; - }), __webpack_require__.d(__webpack_exports__, "f", function() { - return epsilon; - }), __webpack_require__.d(__webpack_exports__, "j", function() { - return pi; - }), __webpack_require__.d(__webpack_exports__, "g", function() { - return halfPi; - }), __webpack_require__.d(__webpack_exports__, "m", function() { - return tau; - }), __webpack_exports__.b = acos, __webpack_exports__.c = asin; - var abs = Math.abs, atan2 = Math.atan2, cos = Math.cos, max = Math.max, min = Math.min, sin = Math.sin, sqrt = Math.sqrt, epsilon = 1e-12, pi = Math.PI, halfPi = pi / 2, tau = 2 * pi; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_exports__.a = function(series, order) { - if ((n = series.length) > 1) for (var j, s0, n, i = 1, s1 = series[order[0]], m = s1.length; i < n; ++i) for (s0 = s1, - s1 = series[order[i]], j = 0; j < m; ++j) s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1]; - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_exports__.a = function(series) { - for (var n = series.length, o = new Array(n); --n >= 0; ) o[n] = n; - return o; - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function Cell() { - return null; - } - var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_1__util_ReactUtils__ = (__webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), - __webpack_require__(4)), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }; - Cell.propTypes = _extends({}, __WEBPACK_IMPORTED_MODULE_1__util_ReactUtils__.c), - Cell.displayName = "Cell", __webpack_exports__.a = Cell; -}, function(module, exports, __webpack_require__) { - function baseIteratee(value) { - return "function" == typeof value ? value : null == value ? identity : "object" == typeof value ? isArray(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value) : property(value); - } - var baseMatches = __webpack_require__(815), baseMatchesProperty = __webpack_require__(818), identity = __webpack_require__(68), isArray = __webpack_require__(13), property = __webpack_require__(822); - module.exports = baseIteratee; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_exports__.a = function(x) { - return null === x ? NaN : +x; - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function linearish(scale) { - var domain = scale.domain; - return scale.ticks = function(count) { - var d = domain(); - return Object(__WEBPACK_IMPORTED_MODULE_0_d3_array__.h)(d[0], d[d.length - 1], null == count ? 10 : count); - }, scale.tickFormat = function(count, specifier) { - return Object(__WEBPACK_IMPORTED_MODULE_3__tickFormat__.a)(domain(), count, specifier); - }, scale.nice = function(count) { - null == count && (count = 10); - var step, d = domain(), i0 = 0, i1 = d.length - 1, start = d[i0], stop = d[i1]; - return stop < start && (step = start, start = stop, stop = step, step = i0, i0 = i1, - i1 = step), step = Object(__WEBPACK_IMPORTED_MODULE_0_d3_array__.f)(start, stop, count), - step > 0 ? (start = Math.floor(start / step) * step, stop = Math.ceil(stop / step) * step, - step = Object(__WEBPACK_IMPORTED_MODULE_0_d3_array__.f)(start, stop, count)) : step < 0 && (start = Math.ceil(start * step) / step, - stop = Math.floor(stop * step) / step, step = Object(__WEBPACK_IMPORTED_MODULE_0_d3_array__.f)(start, stop, count)), - step > 0 ? (d[i0] = Math.floor(start / step) * step, d[i1] = Math.ceil(stop / step) * step, - domain(d)) : step < 0 && (d[i0] = Math.ceil(start * step) / step, d[i1] = Math.floor(stop * step) / step, - domain(d)), scale; - }, scale; - } - function linear() { - var scale = Object(__WEBPACK_IMPORTED_MODULE_2__continuous__.b)(__WEBPACK_IMPORTED_MODULE_2__continuous__.c, __WEBPACK_IMPORTED_MODULE_1_d3_interpolate__.c); - return scale.copy = function() { - return Object(__WEBPACK_IMPORTED_MODULE_2__continuous__.a)(scale, linear()); - }, linearish(scale); - } - __webpack_exports__.b = linearish, __webpack_exports__.a = linear; - var __WEBPACK_IMPORTED_MODULE_0_d3_array__ = __webpack_require__(37), __WEBPACK_IMPORTED_MODULE_1_d3_interpolate__ = __webpack_require__(92), __WEBPACK_IMPORTED_MODULE_2__continuous__ = __webpack_require__(137), __WEBPACK_IMPORTED_MODULE_3__tickFormat__ = __webpack_require__(883); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - var __WEBPACK_IMPORTED_MODULE_0__src_value__ = __webpack_require__(206); - __webpack_require__.d(__webpack_exports__, "a", function() { - return __WEBPACK_IMPORTED_MODULE_0__src_value__.a; - }); - var __WEBPACK_IMPORTED_MODULE_5__src_number__ = (__webpack_require__(349), __webpack_require__(209), - __webpack_require__(347), __webpack_require__(350), __webpack_require__(136)); - __webpack_require__.d(__webpack_exports__, "c", function() { - return __WEBPACK_IMPORTED_MODULE_5__src_number__.a; - }); - var __WEBPACK_IMPORTED_MODULE_7__src_round__ = (__webpack_require__(351), __webpack_require__(873)); - __webpack_require__.d(__webpack_exports__, "d", function() { - return __WEBPACK_IMPORTED_MODULE_7__src_round__.a; - }); - var __WEBPACK_IMPORTED_MODULE_15__src_cubehelix__ = (__webpack_require__(352), __webpack_require__(874), - __webpack_require__(877), __webpack_require__(346), __webpack_require__(878), __webpack_require__(879), - __webpack_require__(880), __webpack_require__(881)); - __webpack_require__.d(__webpack_exports__, "b", function() { - return __WEBPACK_IMPORTED_MODULE_15__src_cubehelix__.a; - }); - __webpack_require__(882); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function linear(a, d) { - return function(t) { - return a + t * d; - }; - } - function exponential(a, b, y) { - return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) { - return Math.pow(a + t * b, y); - }; - } - function hue(a, b) { - var d = b - a; - return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : Object(__WEBPACK_IMPORTED_MODULE_0__constant__.a)(isNaN(a) ? b : a); - } - function gamma(y) { - return 1 == (y = +y) ? nogamma : function(a, b) { - return b - a ? exponential(a, b, y) : Object(__WEBPACK_IMPORTED_MODULE_0__constant__.a)(isNaN(a) ? b : a); - }; - } - function nogamma(a, b) { - var d = b - a; - return d ? linear(a, d) : Object(__WEBPACK_IMPORTED_MODULE_0__constant__.a)(isNaN(a) ? b : a); - } - __webpack_exports__.c = hue, __webpack_exports__.b = gamma, __webpack_exports__.a = nogamma; - var __WEBPACK_IMPORTED_MODULE_0__constant__ = __webpack_require__(348); -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - __webpack_exports__.a = function(s) { - return s.match(/.{6}/g).map(function(x) { - return "#" + x; - }); - }; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _objectWithoutProperties(obj, keys) { - var target = {}; - for (var i in obj) keys.indexOf(i) >= 0 || Object.prototype.hasOwnProperty.call(obj, i) && (target[i] = obj[i]); - return target; - } - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); - } - function _possibleConstructorReturn(self, call) { - if (!self) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !call || "object" != typeof call && "function" != typeof call ? self : call; - } - function _inherits(subClass, superClass) { - if ("function" != typeof superClass && null !== superClass) throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); - } - var _class, _temp, __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0), __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__), __WEBPACK_IMPORTED_MODULE_1_prop_types__ = __webpack_require__(1), __WEBPACK_IMPORTED_MODULE_1_prop_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_prop_types__), __WEBPACK_IMPORTED_MODULE_2__container_Layer__ = __webpack_require__(14), __WEBPACK_IMPORTED_MODULE_3__util_ReactUtils__ = __webpack_require__(4), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, - "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), - Constructor; - }; - }(), ErrorBar = (_temp = _class = function(_Component) { - function ErrorBar() { - return _classCallCheck(this, ErrorBar), _possibleConstructorReturn(this, (ErrorBar.__proto__ || Object.getPrototypeOf(ErrorBar)).apply(this, arguments)); - } - return _inherits(ErrorBar, _Component), _createClass(ErrorBar, [ { - key: "renderErrorBars", - value: function() { - var _props = this.props, offset = _props.offset, layout = _props.layout, width = _props.width, dataKey = _props.dataKey, data = _props.data, dataPointFormatter = _props.dataPointFormatter, xAxis = _props.xAxis, yAxis = _props.yAxis, others = _objectWithoutProperties(_props, [ "offset", "layout", "width", "dataKey", "data", "dataPointFormatter", "xAxis", "yAxis" ]), props = Object(__WEBPACK_IMPORTED_MODULE_3__util_ReactUtils__.k)(others); - return data.map(function(entry, i) { - var _dataPointFormatter = dataPointFormatter(entry, dataKey), x = _dataPointFormatter.x, y = _dataPointFormatter.y, value = _dataPointFormatter.value, errorVal = _dataPointFormatter.errorVal; - if (!errorVal) return null; - var xMid = void 0, yMid = void 0, xMin = void 0, yMin = void 0, xMax = void 0, yMax = void 0, scale = void 0, coordsTop = void 0, coordsMid = void 0, coordsBot = void 0, lowBound = void 0, highBound = void 0; - return Array.isArray(errorVal) ? (lowBound = errorVal[0], highBound = errorVal[1]) : (lowBound = errorVal, - highBound = errorVal), "vertical" === layout ? (scale = xAxis.scale, xMid = value, - yMid = y + offset, xMin = scale(xMid - lowBound), yMin = yMid + width, xMax = scale(xMid + highBound), - yMax = yMid - width, coordsTop = { - x1: xMax, - y1: yMin, - x2: xMax, - y2: yMax - }, coordsMid = { - x1: xMin, - y1: yMid, - x2: xMax, - y2: yMid - }, coordsBot = { - x1: xMin, - y1: yMin, - x2: xMin, - y2: yMax - }) : "horizontal" === layout && (scale = yAxis.scale, xMid = x + offset, yMid = value, - xMin = xMid - width, xMax = xMid + width, yMin = scale(yMid - lowBound), yMax = scale(yMid + highBound), - coordsTop = { - x1: xMin, - y1: yMax, - x2: xMax, - y2: yMax - }, coordsMid = { - x1: xMid, - y1: yMin, - x2: xMid, - y2: yMax - }, coordsBot = { - x1: xMin, - y1: yMin, - x2: xMax, - y2: yMin - }), __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_2__container_Layer__.a, _extends({ - className: "recharts-errorBar", - key: i - }, props), __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("line", coordsTop), __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("line", coordsMid), __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("line", coordsBot)); - }); - } - }, { - key: "render", - value: function() { - return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_2__container_Layer__.a, { - className: "recharts-errorBars" - }, this.renderErrorBars()); - } - } ]), ErrorBar; - }(__WEBPACK_IMPORTED_MODULE_0_react__.Component), _class.propTypes = { - dataKey: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.oneOfType([ __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func ]).isRequired, - data: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.array, - xAxis: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object, - yAxis: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.object, - layout: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, - dataPointFormatter: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.func, - stroke: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.string, - strokeWidth: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - width: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number, - offset: __WEBPACK_IMPORTED_MODULE_1_prop_types___default.a.number - }, _class.defaultProps = { - stroke: "black", - strokeWidth: 1.5, - width: 5, - offset: 0, - layout: "horizontal" - }, _temp); - __webpack_exports__.a = ErrorBar; -}, function(module, __webpack_exports__, __webpack_require__) { - "use strict"; - function _defineProperty(obj, key, value) { - return key in obj ? Object.defineProperty(obj, key, { - value: value, - enumerable: !0, - configurable: !0, - writable: !0 - }) : obj[key] = value, obj; - } - __webpack_require__.d(__webpack_exports__, "a", function() { - return formatAxisMap; - }); - var __WEBPACK_IMPORTED_MODULE_0__ChartUtils__ = __webpack_require__(16), _extends = Object.assign || function(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]); - } - return target; - }, formatAxisMap = function(props, axisMap, offset, axisType, chartName) { - var width = props.width, height = props.height, layout = props.layout, ids = Object.keys(axisMap), steps = { - left: offset.left, - leftMirror: offset.left, - right: width - offset.right, - rightMirror: width - offset.right, - top: offset.top, - topMirror: offset.top, - bottom: height - offset.bottom, - bottomMirror: height - offset.bottom - }; - return ids.reduce(function(result, id) { - var axis = axisMap[id], orientation = axis.orientation, domain = axis.domain, _axis$padding = axis.padding, padding = void 0 === _axis$padding ? {} : _axis$padding, mirror = axis.mirror, reversed = axis.reversed, offsetKey = orientation + (mirror ? "Mirror" : ""), range = void 0, x = void 0, y = void 0, needSpace = void 0; - range = "xAxis" === axisType ? [ offset.left + (padding.left || 0), offset.left + offset.width - (padding.right || 0) ] : "yAxis" === axisType ? "horizontal" === layout ? [ offset.top + offset.height - (padding.bottom || 0), offset.top + (padding.top || 0) ] : [ offset.top + (padding.top || 0), offset.top + offset.height - (padding.bottom || 0) ] : axis.range, - reversed && (range = [ range[1], range[0] ]); - var _parseScale = Object(__WEBPACK_IMPORTED_MODULE_0__ChartUtils__.A)(axis, chartName), scale = _parseScale.scale, realScaleType = _parseScale.realScaleType; - scale.domain(domain).range(range), Object(__WEBPACK_IMPORTED_MODULE_0__ChartUtils__.c)(scale); - var ticks = Object(__WEBPACK_IMPORTED_MODULE_0__ChartUtils__.v)(scale, _extends({}, axis, { - realScaleType: realScaleType - })); - "xAxis" === axisType ? (needSpace = "top" === orientation && !mirror || "bottom" === orientation && mirror, - x = offset.left, y = steps[offsetKey] - needSpace * axis.height) : "yAxis" === axisType && (needSpace = "left" === orientation && !mirror || "right" === orientation && mirror, - x = steps[offsetKey] - needSpace * axis.width, y = offset.top); - var finalAxis = _extends({}, axis, ticks, { - realScaleType: realScaleType, - x: x, - y: y, - scale: scale, - width: "xAxis" === axisType ? offset.width : axis.width, - height: "yAxis" === axisType ? offset.height : axis.height - }); - return finalAxis.bandSize = Object(__WEBPACK_IMPORTED_MODULE_0__ChartUtils__.g)(finalAxis, ticks), - axis.hide || "xAxis" !== axisType ? axis.hide || (steps[offsetKey] += (needSpace ? -1 : 1) * finalAxis.width) : steps[offsetKey] += (needSpace ? -1 : 1) * finalAxis.height, - _extends({}, result, _defineProperty({}, id, finalAxis)); - }, {}); - }; -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - var emptyObject = {}; - "production" !== process.env.NODE_ENV && Object.freeze(emptyObject), module.exports = emptyObject; - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - var emptyFunction = __webpack_require__(50), warning = emptyFunction; - if ("production" !== process.env.NODE_ENV) { - var printWarning = function(format) { - for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) args[_key - 1] = arguments[_key]; - var argIndex = 0, message = "Warning: " + format.replace(/%s/g, function() { - return args[argIndex++]; - }); - "undefined" != typeof console && console.error(message); - try { - throw new Error(message); - } catch (x) {} - }; - warning = function(condition, format) { - if (void 0 === format) throw new Error("` + ("`" + `warning(condition, format, ...args)`)) + ("`" + (` requires a warning message argument"); - if (0 !== format.indexOf("Failed Composite propType: ") && !condition) { - for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) args[_key2 - 2] = arguments[_key2]; - printWarning.apply(void 0, [ format ].concat(args)); - } - }; - } - module.exports = warning; - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - "use strict"; - (function(process) { - function checkDCE() { - if ("undefined" != typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" == typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE) { - if ("production" !== process.env.NODE_ENV) throw new Error("^_^"); - try { - __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE); - } catch (err) { - console.error(err); - } - } - } - "production" === process.env.NODE_ENV ? (checkDCE(), module.exports = __webpack_require__(378)) : module.exports = __webpack_require__(381); - }).call(exports, __webpack_require__(2)); -}, function(module, exports, __webpack_require__) { - "use strict"; - function is(x, y) { - return x === y ? 0 !== x || 0 !== y || 1 / x == 1 / y : x !== x && y !== y; - } - function shallowEqual(objA, objB) { - if (is(objA, objB)) return !0; - if ("object" != typeof objA || null === objA || "object" != typeof objB || null === objB) return !1; - var keysA = Object.keys(objA), keysB = Object.keys(objB); - if (keysA.length !== keysB.length) return !1; - for (var i = 0; i < keysA.length; i++) if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) return !1; - return !0; - } - var hasOwnProperty = Object.prototype.hasOwnProperty; - module.exports = shallowEqual; -}, function(module, exports, __webpack_require__) { - var toInteger = __webpack_require__(149), min = Math.min; - module.exports = function(it) { - return it > 0 ? min(toInteger(it), 9007199254740991) : 0; - }; -}, function(module, exports) { - module.exports = !0; -}, function(module, exports) { - var id = 0, px = Math.random(); - module.exports = function(key) { - return "Symbol(".concat(void 0 === key ? "" : key, ")_", (++id + px).toString(36)); - }; -}, function(module, exports) { - exports.f = {}.propertyIsEnumerable; -}, function(module, exports, __webpack_require__) { - "use strict"; - function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - } - exports.__esModule = !0; - var _iterator = __webpack_require__(396), _iterator2 = _interopRequireDefault(_iterator), _symbol = __webpack_require__(404), _symbol2 = _interopRequireDefault(_symbol), _typeof = "function" == typeof _symbol2.default && "symbol" == typeof _iterator2.default ? function(obj) { - return typeof obj; - } : function(obj) { - return obj && "function" == typeof _symbol2.default && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; - }; - exports.default = "function" == typeof _symbol2.default && "symbol" === _typeof(_iterator2.default) ? function(obj) { - return void 0 === obj ? "undefined" : _typeof(obj); - } : function(obj) { - return obj && "function" == typeof _symbol2.default && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : void 0 === obj ? "undefined" : _typeof(obj); - }; -}, function(module, exports, __webpack_require__) { - var anObject = __webpack_require__(52), dPs = __webpack_require__(400), enumBugKeys = __webpack_require__(152), IE_PROTO = __webpack_require__(150)("IE_PROTO"), Empty = function() {}, createDict = function() { - var iframeDocument, iframe = __webpack_require__(225)("iframe"), i = enumBugKeys.length; - for (iframe.style.display = "none", __webpack_require__(401).appendChild(iframe), - iframe.src = "javascript:", iframeDocument = iframe.contentWindow.document, iframeDocument.open(), - iframeDocument.write("\n if (val === '') return true;\n if (val === 'false') return false;\n if (val === 'true') return true;\n return val;\n}\n\nif (DOCUMENT && typeof DOCUMENT.querySelector === 'function') {\n var attrs = [['data-family-prefix', 'familyPrefix'], ['data-replacement-class', 'replacementClass'], ['data-auto-replace-svg', 'autoReplaceSvg'], ['data-auto-add-css', 'autoAddCss'], ['data-auto-a11y', 'autoA11y'], ['data-search-pseudo-elements', 'searchPseudoElements'], ['data-observe-mutations', 'observeMutations'], ['data-keep-original-source', 'keepOriginalSource'], ['data-measure-performance', 'measurePerformance'], ['data-show-missing-icons', 'showMissingIcons']];\n attrs.forEach(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n attr = _ref2[0],\n key = _ref2[1];\n\n var val = coerce(getAttrConfig(attr));\n\n if (val !== undefined && val !== null) {\n initial[key] = val;\n }\n });\n}\n\nvar _default = {\n familyPrefix: DEFAULT_FAMILY_PREFIX,\n replacementClass: DEFAULT_REPLACEMENT_CLASS,\n autoReplaceSvg: true,\n autoAddCss: true,\n autoA11y: true,\n searchPseudoElements: false,\n observeMutations: true,\n keepOriginalSource: true,\n measurePerformance: false,\n showMissingIcons: true\n};\n\nvar _config = _objectSpread({}, _default, initial);\n\nif (!_config.autoReplaceSvg) _config.observeMutations = false;\n\nvar config = _objectSpread({}, _config);\n\nWINDOW.FontAwesomeConfig = config;\n\nvar w = WINDOW || {};\nif (!w[NAMESPACE_IDENTIFIER]) w[NAMESPACE_IDENTIFIER] = {};\nif (!w[NAMESPACE_IDENTIFIER].styles) w[NAMESPACE_IDENTIFIER].styles = {};\nif (!w[NAMESPACE_IDENTIFIER].hooks) w[NAMESPACE_IDENTIFIER].hooks = {};\nif (!w[NAMESPACE_IDENTIFIER].shims) w[NAMESPACE_IDENTIFIER].shims = [];\nvar namespace = w[NAMESPACE_IDENTIFIER];\n\nvar functions = [];\n\nvar listener = function listener() {\n DOCUMENT.removeEventListener('DOMContentLoaded', listener);\n loaded = 1;\n functions.map(function (fn) {\n return fn();\n });\n};\n\nvar loaded = false;\n\nif (IS_DOM) {\n loaded = (DOCUMENT.documentElement.doScroll ? /^loaded|^c/ : /^loaded|^i|^c/).test(DOCUMENT.readyState);\n if (!loaded) DOCUMENT.addEventListener('DOMContentLoaded', listener);\n}\n\nfunction domready (fn) {\n if (!IS_DOM) return;\n loaded ? setTimeout(fn, 0) : functions.push(fn);\n}\n\nvar PENDING = 'pending';\nvar SETTLED = 'settled';\nvar FULFILLED = 'fulfilled';\nvar REJECTED = 'rejected';\n\nvar NOOP = function NOOP() {};\n\nvar isNode = typeof global !== 'undefined' && typeof global.process !== 'undefined' && typeof global.process.emit === 'function';\nvar asyncSetTimer = typeof setImmediate === 'undefined' ? setTimeout : setImmediate;\nvar asyncQueue = [];\nvar asyncTimer;\n\nfunction asyncFlush() {\n // run promise callbacks\n for (var i = 0; i < asyncQueue.length; i++) {\n asyncQueue[i][0](asyncQueue[i][1]);\n } // reset async asyncQueue\n\n\n asyncQueue = [];\n asyncTimer = false;\n}\n\nfunction asyncCall(callback, arg) {\n asyncQueue.push([callback, arg]);\n\n if (!asyncTimer) {\n asyncTimer = true;\n asyncSetTimer(asyncFlush, 0);\n }\n}\n\nfunction invokeResolver(resolver, promise) {\n function resolvePromise(value) {\n resolve(promise, value);\n }\n\n function rejectPromise(reason) {\n reject(promise, reason);\n }\n\n try {\n resolver(resolvePromise, rejectPromise);\n } catch (e) {\n rejectPromise(e);\n }\n}\n\nfunction invokeCallback(subscriber) {\n var owner = subscriber.owner;\n var settled = owner._state;\n var value = owner._data;\n var callback = subscriber[settled];\n var promise = subscriber.then;\n\n if (typeof callback === 'function') {\n settled = FULFILLED;\n\n try {\n value = callback(value);\n } catch (e) {\n reject(promise, e);\n }\n }\n\n if (!handleThenable(promise, value)) {\n if (settled === FULFILLED) {\n resolve(promise, value);\n }\n\n if (settled === REJECTED) {\n reject(promise, value);\n }\n }\n}\n\nfunction handleThenable(promise, value) {\n var resolved;\n\n try {\n if (promise === value) {\n throw new TypeError('A promises callback cannot return that same promise.');\n }\n\n if (value && (typeof value === 'function' || _typeof(value) === 'object')) {\n // then should be retrieved only once\n var then = value.then;\n\n if (typeof then === 'function') {\n then.call(value, function (val) {\n if (!resolved) {\n resolved = true;\n\n if (value === val) {\n fulfill(promise, val);\n } else {\n resolve(promise, val);\n }\n }\n }, function (reason) {\n if (!resolved) {\n resolved = true;\n reject(promise, reason);\n }\n });\n return true;\n }\n }\n } catch (e) {\n if (!resolved) {\n reject(promise, e);\n }\n\n return true;\n }\n\n return false;\n}\n\nfunction resolve(promise, value) {\n if (promise === value || !handleThenable(promise, value)) {\n fulfill(promise, value);\n }\n}\n\nfunction fulfill(promise, value) {\n if (promise._state === PENDING) {\n promise._state = SETTLED;\n promise._data = value;\n asyncCall(publishFulfillment, promise);\n }\n}\n\nfunction reject(promise, reason) {\n if (promise._state === PENDING) {\n promise._state = SETTLED;\n promise._data = reason;\n asyncCall(publishRejection, promise);\n }\n}\n\nfunction publish(promise) {\n promise._then = promise._then.forEach(invokeCallback);\n}\n\nfunction publishFulfillment(promise) {\n promise._state = FULFILLED;\n publish(promise);\n}\n\nfunction publishRejection(promise) {\n promise._state = REJECTED;\n publish(promise);\n\n if (!promise._handled && isNode) {\n global.process.emit('unhandledRejection', promise._data, promise);\n }\n}\n\nfunction notifyRejectionHandled(promise) {\n global.process.emit('rejectionHandled', promise);\n}\n/**\n * @class\n */\n\n\nfunction P(resolver) {\n if (typeof resolver !== 'function') {\n throw new TypeError('Promise resolver ' + resolver + ' is not a function');\n }\n\n if (this instanceof P === false) {\n throw new TypeError('Failed to construct \\'Promise\\': Please use the \\'new\\' operator, this object constructor cannot be called as a function.');\n }\n\n this._then = [];\n invokeResolver(resolver, this);\n}\n\nP.prototype = {\n constructor: P,\n _state: PENDING,\n _then: null,\n _data: undefined,\n _handled: false,\n then: function then(onFulfillment, onRejection) {\n var subscriber = {\n owner: this,\n then: new this.constructor(NOOP),\n fulfilled: onFulfillment,\n rejected: onRejection\n };\n\n if ((onRejection || onFulfillment) && !this._handled) {\n this._handled = true;\n\n if (this._state === REJECTED && isNode) {\n asyncCall(notifyRejectionHandled, this);\n }\n }\n\n if (this._state === FULFILLED || this._state === REJECTED) {\n // already resolved, call callback async\n asyncCall(invokeCallback, subscriber);\n } else {\n // subscribe\n this._then.push(subscriber);\n }\n\n return subscriber.then;\n },\n catch: function _catch(onRejection) {\n return this.then(null, onRejection);\n }\n};\n\nP.all = function (promises) {\n if (!Array.isArray(promises)) {\n throw new TypeError('You must pass an array to Promise.all().');\n }\n\n return new P(function (resolve, reject) {\n var results = [];\n var remaining = 0;\n\n function resolver(index) {\n remaining++;\n return function (value) {\n results[index] = value;\n\n if (! --remaining) {\n resolve(results);\n }\n };\n }\n\n for (var i = 0, promise; i < promises.length; i++) {\n promise = promises[i];\n\n if (promise && typeof promise.then === 'function') {\n promise.then(resolver(i), reject);\n } else {\n results[i] = promise;\n }\n }\n\n if (!remaining) {\n resolve(results);\n }\n });\n};\n\nP.race = function (promises) {\n if (!Array.isArray(promises)) {\n throw new TypeError('You must pass an array to Promise.race().');\n }\n\n return new P(function (resolve, reject) {\n for (var i = 0, promise; i < promises.length; i++) {\n promise = promises[i];\n\n if (promise && typeof promise.then === 'function') {\n promise.then(resolve, reject);\n } else {\n resolve(promise);\n }\n }\n });\n};\n\nP.resolve = function (value) {\n if (value && _typeof(value) === 'object' && value.constructor === P) {\n return value;\n }\n\n return new P(function (resolve) {\n resolve(value);\n });\n};\n\nP.reject = function (reason) {\n return new P(function (resolve, reject) {\n reject(reason);\n });\n};\n\nvar picked = typeof Promise === 'function' ? Promise : P;\n\nvar d = UNITS_IN_GRID;\nvar meaninglessTransform = {\n size: 16,\n x: 0,\n y: 0,\n rotate: 0,\n flipX: false,\n flipY: false\n};\n\nfunction isReserved(name) {\n return ~RESERVED_CLASSES.indexOf(name);\n}\nfunction insertCss(css) {\n if (!css || !IS_DOM) {\n return;\n }\n\n var style = DOCUMENT.createElement('style');\n style.setAttribute('type', 'text/css');\n style.innerHTML = css;\n var headChildren = DOCUMENT.head.childNodes;\n var beforeChild = null;\n\n for (var i = headChildren.length - 1; i > -1; i--) {\n var child = headChildren[i];\n var tagName = (child.tagName || '').toUpperCase();\n\n if (['STYLE', 'LINK'].indexOf(tagName) > -1) {\n beforeChild = child;\n }\n }\n\n DOCUMENT.head.insertBefore(style, beforeChild);\n return css;\n}\nvar idPool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\nfunction nextUniqueId() {\n var size = 12;\n var id = '';\n\n while (size-- > 0) {\n id += idPool[Math.random() * 62 | 0];\n }\n\n return id;\n}\nfunction toArray(obj) {\n var array = [];\n\n for (var i = (obj || []).length >>> 0; i--;) {\n array[i] = obj[i];\n }\n\n return array;\n}\nfunction classArray(node) {\n if (node.classList) {\n return toArray(node.classList);\n } else {\n return (node.getAttribute('class') || '').split(' ').filter(function (i) {\n return i;\n });\n }\n}\nfunction getIconName(familyPrefix, cls) {\n var parts = cls.split('-');\n var prefix = parts[0];\n var iconName = parts.slice(1).join('-');\n\n if (prefix === familyPrefix && iconName !== '' && !isReserved(iconName)) {\n return iconName;\n } else {\n return null;\n }\n}\nfunction htmlEscape(str) {\n return \"\".concat(str).replace(/&/g, '&').replace(/\"/g, '"').replace(/'/g, ''').replace(//g, '>');\n}\nfunction joinAttributes(attributes) {\n return Object.keys(attributes || {}).reduce(function (acc, attributeName) {\n return acc + \"\".concat(attributeName, \"=\\\"\").concat(htmlEscape(attributes[attributeName]), \"\\\" \");\n }, '').trim();\n}\nfunction joinStyles(styles) {\n return Object.keys(styles || {}).reduce(function (acc, styleName) {\n return acc + \"\".concat(styleName, \": \").concat(styles[styleName], \";\");\n }, '');\n}\nfunction transformIsMeaningful(transform) {\n return transform.size !== meaninglessTransform.size || transform.x !== meaninglessTransform.x || transform.y !== meaninglessTransform.y || transform.rotate !== meaninglessTransform.rotate || transform.flipX || transform.flipY;\n}\nfunction transformForSvg(_ref) {\n var transform = _ref.transform,\n containerWidth = _ref.containerWidth,\n iconWidth = _ref.iconWidth;\n var outer = {\n transform: \"translate(\".concat(containerWidth / 2, \" 256)\")\n };\n var innerTranslate = \"translate(\".concat(transform.x * 32, \", \").concat(transform.y * 32, \") \");\n var innerScale = \"scale(\".concat(transform.size / 16 * (transform.flipX ? -1 : 1), \", \").concat(transform.size / 16 * (transform.flipY ? -1 : 1), \") \");\n var innerRotate = \"rotate(\".concat(transform.rotate, \" 0 0)\");\n var inner = {\n transform: \"\".concat(innerTranslate, \" \").concat(innerScale, \" \").concat(innerRotate)\n };\n var path = {\n transform: \"translate(\".concat(iconWidth / 2 * -1, \" -256)\")\n };\n return {\n outer: outer,\n inner: inner,\n path: path\n };\n}\nfunction transformForCss(_ref2) {\n var transform = _ref2.transform,\n _ref2$width = _ref2.width,\n width = _ref2$width === void 0 ? UNITS_IN_GRID : _ref2$width,\n _ref2$height = _ref2.height,\n height = _ref2$height === void 0 ? UNITS_IN_GRID : _ref2$height,\n _ref2$startCentered = _ref2.startCentered,\n startCentered = _ref2$startCentered === void 0 ? false : _ref2$startCentered;\n var val = '';\n\n if (startCentered && IS_IE) {\n val += \"translate(\".concat(transform.x / d - width / 2, \"em, \").concat(transform.y / d - height / 2, \"em) \");\n } else if (startCentered) {\n val += \"translate(calc(-50% + \".concat(transform.x / d, \"em), calc(-50% + \").concat(transform.y / d, \"em)) \");\n } else {\n val += \"translate(\".concat(transform.x / d, \"em, \").concat(transform.y / d, \"em) \");\n }\n\n val += \"scale(\".concat(transform.size / d * (transform.flipX ? -1 : 1), \", \").concat(transform.size / d * (transform.flipY ? -1 : 1), \") \");\n val += \"rotate(\".concat(transform.rotate, \"deg) \");\n return val;\n}\n\nvar ALL_SPACE = {\n x: 0,\n y: 0,\n width: '100%',\n height: '100%'\n};\nfunction makeIconMasking (_ref) {\n var children = _ref.children,\n attributes = _ref.attributes,\n main = _ref.main,\n mask = _ref.mask,\n transform = _ref.transform;\n var mainWidth = main.width,\n mainPath = main.icon;\n var maskWidth = mask.width,\n maskPath = mask.icon;\n var trans = transformForSvg({\n transform: transform,\n containerWidth: maskWidth,\n iconWidth: mainWidth\n });\n var maskRect = {\n tag: 'rect',\n attributes: _objectSpread({}, ALL_SPACE, {\n fill: 'white'\n })\n };\n var maskInnerGroup = {\n tag: 'g',\n attributes: _objectSpread({}, trans.inner),\n children: [{\n tag: 'path',\n attributes: _objectSpread({}, mainPath.attributes, trans.path, {\n fill: 'black'\n })\n }]\n };\n var maskOuterGroup = {\n tag: 'g',\n attributes: _objectSpread({}, trans.outer),\n children: [maskInnerGroup]\n };\n var maskId = \"mask-\".concat(nextUniqueId());\n var clipId = \"clip-\".concat(nextUniqueId());\n var maskTag = {\n tag: 'mask',\n attributes: _objectSpread({}, ALL_SPACE, {\n id: maskId,\n maskUnits: 'userSpaceOnUse',\n maskContentUnits: 'userSpaceOnUse'\n }),\n children: [maskRect, maskOuterGroup]\n };\n var defs = {\n tag: 'defs',\n children: [{\n tag: 'clipPath',\n attributes: {\n id: clipId\n },\n children: [maskPath]\n }, maskTag]\n };\n children.push(defs, {\n tag: 'rect',\n attributes: _objectSpread({\n fill: 'currentColor',\n 'clip-path': \"url(#\".concat(clipId, \")\"),\n mask: \"url(#\".concat(maskId, \")\")\n }, ALL_SPACE)\n });\n return {\n children: children,\n attributes: attributes\n };\n}\n\nfunction makeIconStandard (_ref) {\n var children = _ref.children,\n attributes = _ref.attributes,\n main = _ref.main,\n transform = _ref.transform,\n styles = _ref.styles;\n var styleString = joinStyles(styles);\n\n if (styleString.length > 0) {\n attributes['style'] = styleString;\n }\n\n if (transformIsMeaningful(transform)) {\n var trans = transformForSvg({\n transform: transform,\n containerWidth: main.width,\n iconWidth: main.width\n });\n children.push({\n tag: 'g',\n attributes: _objectSpread({}, trans.outer),\n children: [{\n tag: 'g',\n attributes: _objectSpread({}, trans.inner),\n children: [{\n tag: main.icon.tag,\n children: main.icon.children,\n attributes: _objectSpread({}, main.icon.attributes, trans.path)\n }]\n }]\n });\n } else {\n children.push(main.icon);\n }\n\n return {\n children: children,\n attributes: attributes\n };\n}\n\nfunction asIcon (_ref) {\n var children = _ref.children,\n main = _ref.main,\n mask = _ref.mask,\n attributes = _ref.attributes,\n styles = _ref.styles,\n transform = _ref.transform;\n\n if (transformIsMeaningful(transform) && main.found && !mask.found) {\n var width = main.width,\n height = main.height;\n var offset = {\n x: width / height / 2,\n y: 0.5\n };\n attributes['style'] = joinStyles(_objectSpread({}, styles, {\n 'transform-origin': \"\".concat(offset.x + transform.x / 16, \"em \").concat(offset.y + transform.y / 16, \"em\")\n }));\n }\n\n return [{\n tag: 'svg',\n attributes: attributes,\n children: children\n }];\n}\n\nfunction asSymbol (_ref) {\n var prefix = _ref.prefix,\n iconName = _ref.iconName,\n children = _ref.children,\n attributes = _ref.attributes,\n symbol = _ref.symbol;\n var id = symbol === true ? \"\".concat(prefix, \"-\").concat(config.familyPrefix, \"-\").concat(iconName) : symbol;\n return [{\n tag: 'svg',\n attributes: {\n style: 'display: none;'\n },\n children: [{\n tag: 'symbol',\n attributes: _objectSpread({}, attributes, {\n id: id\n }),\n children: children\n }]\n }];\n}\n\nfunction makeInlineSvgAbstract(params) {\n var _params$icons = params.icons,\n main = _params$icons.main,\n mask = _params$icons.mask,\n prefix = params.prefix,\n iconName = params.iconName,\n transform = params.transform,\n symbol = params.symbol,\n title = params.title,\n extra = params.extra,\n _params$watchable = params.watchable,\n watchable = _params$watchable === void 0 ? false : _params$watchable;\n\n var _ref = mask.found ? mask : main,\n width = _ref.width,\n height = _ref.height;\n\n var widthClass = \"fa-w-\".concat(Math.ceil(width / height * 16));\n var attrClass = [config.replacementClass, iconName ? \"\".concat(config.familyPrefix, \"-\").concat(iconName) : '', widthClass].filter(function (c) {\n return extra.classes.indexOf(c) === -1;\n }).concat(extra.classes).join(' ');\n var content = {\n children: [],\n attributes: _objectSpread({}, extra.attributes, {\n 'data-prefix': prefix,\n 'data-icon': iconName,\n 'class': attrClass,\n 'role': 'img',\n 'xmlns': 'http://www.w3.org/2000/svg',\n 'viewBox': \"0 0 \".concat(width, \" \").concat(height)\n })\n };\n\n if (watchable) {\n content.attributes[DATA_FA_I2SVG] = '';\n }\n\n if (title) content.children.push({\n tag: 'title',\n attributes: {\n id: content.attributes['aria-labelledby'] || \"title-\".concat(nextUniqueId())\n },\n children: [title]\n });\n\n var args = _objectSpread({}, content, {\n prefix: prefix,\n iconName: iconName,\n main: main,\n mask: mask,\n transform: transform,\n symbol: symbol,\n styles: extra.styles\n });\n\n var _ref2 = mask.found && main.found ? makeIconMasking(args) : makeIconStandard(args),\n children = _ref2.children,\n attributes = _ref2.attributes;\n\n args.children = children;\n args.attributes = attributes;\n\n if (symbol) {\n return asSymbol(args);\n } else {\n return asIcon(args);\n }\n}\nfunction makeLayersTextAbstract(params) {\n var content = params.content,\n width = params.width,\n height = params.height,\n transform = params.transform,\n title = params.title,\n extra = params.extra,\n _params$watchable2 = params.watchable,\n watchable = _params$watchable2 === void 0 ? false : _params$watchable2;\n\n var attributes = _objectSpread({}, extra.attributes, title ? {\n 'title': title\n } : {}, {\n 'class': extra.classes.join(' ')\n });\n\n if (watchable) {\n attributes[DATA_FA_I2SVG] = '';\n }\n\n var styles = _objectSpread({}, extra.styles);\n\n if (transformIsMeaningful(transform)) {\n styles['transform'] = transformForCss({\n transform: transform,\n startCentered: true,\n width: width,\n height: height\n });\n styles['-webkit-transform'] = styles['transform'];\n }\n\n var styleString = joinStyles(styles);\n\n if (styleString.length > 0) {\n attributes['style'] = styleString;\n }\n\n var val = [];\n val.push({\n tag: 'span',\n attributes: attributes,\n children: [content]\n });\n\n if (title) {\n val.push({\n tag: 'span',\n attributes: {\n class: 'sr-only'\n },\n children: [title]\n });\n }\n\n return val;\n}\nfunction makeLayersCounterAbstract(params) {\n var content = params.content,\n title = params.title,\n extra = params.extra;\n\n var attributes = _objectSpread({}, extra.attributes, title ? {\n 'title': title\n } : {}, {\n 'class': extra.classes.join(' ')\n });\n\n var styleString = joinStyles(extra.styles);\n\n if (styleString.length > 0) {\n attributes['style'] = styleString;\n }\n\n var val = [];\n val.push({\n tag: 'span',\n attributes: attributes,\n children: [content]\n });\n\n if (title) {\n val.push({\n tag: 'span',\n attributes: {\n class: 'sr-only'\n },\n children: [title]\n });\n }\n\n return val;\n}\n\nvar noop$1 = function noop() {};\n\nvar p = config.measurePerformance && PERFORMANCE && PERFORMANCE.mark && PERFORMANCE.measure ? PERFORMANCE : {\n mark: noop$1,\n measure: noop$1\n};\nvar preamble = \"FA \\\"5.7.2\\\"\";\n\nvar begin = function begin(name) {\n p.mark(\"\".concat(preamble, \" \").concat(name, \" begins\"));\n return function () {\n return end(name);\n };\n};\n\nvar end = function end(name) {\n p.mark(\"\".concat(preamble, \" \").concat(name, \" ends\"));\n p.measure(\"\".concat(preamble, \" \").concat(name), \"\".concat(preamble, \" \").concat(name, \" begins\"), \"\".concat(preamble, \" \").concat(name, \" ends\"));\n};\n\nvar perf = {\n begin: begin,\n end: end\n};\n\n/**\n * Internal helper to bind a function known to have 4 arguments\n * to a given context.\n */\n\nvar bindInternal4 = function bindInternal4(func, thisContext) {\n return function (a, b, c, d) {\n return func.call(thisContext, a, b, c, d);\n };\n};\n\n/**\n * # Reduce\n *\n * A fast object ` + ("`" + `.reduce()`)) + ("`" + (` implementation.\n *\n * @param {Object} subject The object to reduce over.\n * @param {Function} fn The reducer function.\n * @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].\n * @param {Object} thisContext The context for the reducer.\n * @return {mixed} The final result.\n */\n\n\nvar reduce = function fastReduceObject(subject, fn, initialValue, thisContext) {\n var keys = Object.keys(subject),\n length = keys.length,\n iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,\n i,\n key,\n result;\n\n if (initialValue === undefined) {\n i = 1;\n result = subject[keys[0]];\n } else {\n i = 0;\n result = initialValue;\n }\n\n for (; i < length; i++) {\n key = keys[i];\n result = iterator(result, subject[key], key, subject);\n }\n\n return result;\n};\n\nfunction defineIcons(prefix, icons) {\n var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var _params$skipHooks = params.skipHooks,\n skipHooks = _params$skipHooks === void 0 ? false : _params$skipHooks;\n var normalized = Object.keys(icons).reduce(function (acc, iconName) {\n var icon = icons[iconName];\n var expanded = !!icon.icon;\n\n if (expanded) {\n acc[icon.iconName] = icon.icon;\n } else {\n acc[iconName] = icon;\n }\n\n return acc;\n }, {});\n\n if (typeof namespace.hooks.addPack === 'function' && !skipHooks) {\n namespace.hooks.addPack(prefix, normalized);\n } else {\n namespace.styles[prefix] = _objectSpread({}, namespace.styles[prefix] || {}, normalized);\n }\n /**\n * Font Awesome 4 used the prefix of ` + "`"))))) + ((((`fa` + "`") + (` for all icons. With the introduction\n * of new styles we needed to differentiate between them. Prefix ` + ("`" + `fa`))) + (("`" + (` is now an alias\n * for ` + "`")) + (`fas` + ("`" + ` so we'll easy the upgrade process for our users by automatically defining\n * this as well.\n */\n\n\n if (prefix === 'fas') {\n defineIcons('fa', icons);\n }\n}\n\nvar styles = namespace.styles,\n shims = namespace.shims;\nvar _byUnicode = {};\nvar _byLigature = {};\nvar _byOldName = {};\nvar build = function build() {\n var lookup = function lookup(reducer) {\n return reduce(styles, function (o, style, prefix) {\n o[prefix] = reduce(style, reducer, {});\n return o;\n }, {});\n };\n\n _byUnicode = lookup(function (acc, icon, iconName) {\n if (icon[3]) {\n acc[icon[3]] = iconName;\n }\n\n return acc;\n });\n _byLigature = lookup(function (acc, icon, iconName) {\n var ligatures = icon[2];\n acc[iconName] = iconName;\n ligatures.forEach(function (ligature) {\n acc[ligature] = iconName;\n });\n return acc;\n });\n var hasRegular = 'far' in styles;\n _byOldName = reduce(shims, function (acc, shim) {\n var oldName = shim[0];\n var prefix = shim[1];\n var iconName = shim[2];\n\n if (prefix === 'far' && !hasRegular) {\n prefix = 'fas';\n }\n\n acc[oldName] = {\n prefix: prefix,\n iconName: iconName\n };\n return acc;\n }, {});\n};\nbuild();\nfunction byUnicode(prefix, unicode) {\n return _byUnicode[prefix][unicode];\n}\nfunction byLigature(prefix, ligature) {\n return _byLigature[prefix][ligature];\n}\nfunction byOldName(name) {\n return _byOldName[name] || {\n prefix: null,\n iconName: null\n };\n}\n\nvar styles$1 = namespace.styles;\nvar emptyCanonicalIcon = function emptyCanonicalIcon() {\n return {\n prefix: null,\n iconName: null,\n rest: []\n };\n};\nfunction getCanonicalIcon(values) {\n return values.reduce(function (acc, cls) {\n var iconName = getIconName(config.familyPrefix, cls);\n\n if (styles$1[cls]) {\n acc.prefix = cls;\n } else if (config.autoFetchSvg && ['fas', 'far', 'fal', 'fab', 'fa'].indexOf(cls) > -1) {\n acc.prefix = cls;\n } else if (iconName) {\n var shim = acc.prefix === 'fa' ? byOldName(iconName) : {};\n acc.iconName = shim.iconName || iconName;\n acc.prefix = shim.prefix || acc.prefix;\n } else if (cls !== config.replacementClass && cls.indexOf('fa-w-') !== 0) {\n acc.rest.push(cls);\n }\n\n return acc;\n }, emptyCanonicalIcon());\n}\nfunction iconFromMapping(mapping, prefix, iconName) {\n if (mapping && mapping[prefix] && mapping[prefix][iconName]) {\n return {\n prefix: prefix,\n iconName: iconName,\n icon: mapping[prefix][iconName]\n };\n }\n}\n\nfunction toHtml(abstractNodes) {\n var tag = abstractNodes.tag,\n _abstractNodes$attrib = abstractNodes.attributes,\n attributes = _abstractNodes$attrib === void 0 ? {} : _abstractNodes$attrib,\n _abstractNodes$childr = abstractNodes.children,\n children = _abstractNodes$childr === void 0 ? [] : _abstractNodes$childr;\n\n if (typeof abstractNodes === 'string') {\n return htmlEscape(abstractNodes);\n } else {\n return \"<\".concat(tag, \" \").concat(joinAttributes(attributes), \">\").concat(children.map(toHtml).join(''), \"\");\n }\n}\n\nvar noop$2 = function noop() {};\n\nfunction isWatched(node) {\n var i2svg = node.getAttribute ? node.getAttribute(DATA_FA_I2SVG) : null;\n return typeof i2svg === 'string';\n}\n\nfunction getMutator() {\n if (config.autoReplaceSvg === true) {\n return mutators.replace;\n }\n\n var mutator = mutators[config.autoReplaceSvg];\n return mutator || mutators.replace;\n}\n\nvar mutators = {\n replace: function replace(mutation) {\n var node = mutation[0];\n var abstract = mutation[1];\n var newOuterHTML = abstract.map(function (a) {\n return toHtml(a);\n }).join('\\n');\n\n if (node.parentNode && node.outerHTML) {\n node.outerHTML = newOuterHTML + (config.keepOriginalSource && node.tagName.toLowerCase() !== 'svg' ? \"\") : '');\n } else if (node.parentNode) {\n var newNode = document.createElement('span');\n node.parentNode.replaceChild(newNode, node);\n newNode.outerHTML = newOuterHTML;\n }\n },\n nest: function nest(mutation) {\n var node = mutation[0];\n var abstract = mutation[1]; // If we already have a replaced node we do not want to continue nesting within it.\n // Short-circuit to the standard replacement\n\n if (~classArray(node).indexOf(config.replacementClass)) {\n return mutators.replace(mutation);\n }\n\n var forSvg = new RegExp(\"\".concat(config.familyPrefix, \"-.*\"));\n delete abstract[0].attributes.style;\n var splitClasses = abstract[0].attributes.class.split(' ').reduce(function (acc, cls) {\n if (cls === config.replacementClass || cls.match(forSvg)) {\n acc.toSvg.push(cls);\n } else {\n acc.toNode.push(cls);\n }\n\n return acc;\n }, {\n toNode: [],\n toSvg: []\n });\n abstract[0].attributes.class = splitClasses.toSvg.join(' ');\n var newInnerHTML = abstract.map(function (a) {\n return toHtml(a);\n }).join('\\n');\n node.setAttribute('class', splitClasses.toNode.join(' '));\n node.setAttribute(DATA_FA_I2SVG, '');\n node.innerHTML = newInnerHTML;\n }\n};\nfunction perform(mutations, callback) {\n var callbackFunction = typeof callback === 'function' ? callback : noop$2;\n\n if (mutations.length === 0) {\n callbackFunction();\n } else {\n var frame = WINDOW.requestAnimationFrame || function (op) {\n return op();\n };\n\n frame(function () {\n var mutator = getMutator();\n var mark = perf.begin('mutate');\n mutations.map(mutator);\n mark();\n callbackFunction();\n });\n }\n}\nvar disabled = false;\nfunction disableObservation() {\n disabled = true;\n}\nfunction enableObservation() {\n disabled = false;\n}\nvar mo = null;\nfunction observe(options) {\n if (!MUTATION_OBSERVER) {\n return;\n }\n\n if (!config.observeMutations) {\n return;\n }\n\n var treeCallback = options.treeCallback,\n nodeCallback = options.nodeCallback,\n pseudoElementsCallback = options.pseudoElementsCallback,\n _options$observeMutat = options.observeMutationsRoot,\n observeMutationsRoot = _options$observeMutat === void 0 ? DOCUMENT : _options$observeMutat;\n mo = new MUTATION_OBSERVER(function (objects) {\n if (disabled) return;\n toArray(objects).forEach(function (mutationRecord) {\n if (mutationRecord.type === 'childList' && mutationRecord.addedNodes.length > 0 && !isWatched(mutationRecord.addedNodes[0])) {\n if (config.searchPseudoElements) {\n pseudoElementsCallback(mutationRecord.target);\n }\n\n treeCallback(mutationRecord.target);\n }\n\n if (mutationRecord.type === 'attributes' && mutationRecord.target.parentNode && config.searchPseudoElements) {\n pseudoElementsCallback(mutationRecord.target.parentNode);\n }\n\n if (mutationRecord.type === 'attributes' && isWatched(mutationRecord.target) && ~ATTRIBUTES_WATCHED_FOR_MUTATION.indexOf(mutationRecord.attributeName)) {\n if (mutationRecord.attributeName === 'class') {\n var _getCanonicalIcon = getCanonicalIcon(classArray(mutationRecord.target)),\n prefix = _getCanonicalIcon.prefix,\n iconName = _getCanonicalIcon.iconName;\n\n if (prefix) mutationRecord.target.setAttribute('data-prefix', prefix);\n if (iconName) mutationRecord.target.setAttribute('data-icon', iconName);\n } else {\n nodeCallback(mutationRecord.target);\n }\n }\n });\n });\n if (!IS_DOM) return;\n mo.observe(observeMutationsRoot, {\n childList: true,\n attributes: true,\n characterData: true,\n subtree: true\n });\n}\nfunction disconnect() {\n if (!mo) return;\n mo.disconnect();\n}\n\nfunction styleParser (node) {\n var style = node.getAttribute('style');\n var val = [];\n\n if (style) {\n val = style.split(';').reduce(function (acc, style) {\n var styles = style.split(':');\n var prop = styles[0];\n var value = styles.slice(1);\n\n if (prop && value.length > 0) {\n acc[prop] = value.join(':').trim();\n }\n\n return acc;\n }, {});\n }\n\n return val;\n}\n\nfunction toHex(unicode) {\n var result = '';\n\n for (var i = 0; i < unicode.length; i++) {\n var hex = unicode.charCodeAt(i).toString(16);\n result += ('000' + hex).slice(-4);\n }\n\n return result;\n}\n\nfunction classParser (node) {\n var existingPrefix = node.getAttribute('data-prefix');\n var existingIconName = node.getAttribute('data-icon');\n var innerText = node.innerText !== undefined ? node.innerText.trim() : '';\n var val = getCanonicalIcon(classArray(node));\n\n if (existingPrefix && existingIconName) {\n val.prefix = existingPrefix;\n val.iconName = existingIconName;\n }\n\n if (val.prefix && innerText.length > 1) {\n val.iconName = byLigature(val.prefix, node.innerText);\n } else if (val.prefix && innerText.length === 1) {\n val.iconName = byUnicode(val.prefix, toHex(node.innerText));\n }\n\n return val;\n}\n\nvar parseTransformString = function parseTransformString(transformString) {\n var transform = {\n size: 16,\n x: 0,\n y: 0,\n flipX: false,\n flipY: false,\n rotate: 0\n };\n\n if (!transformString) {\n return transform;\n } else {\n return transformString.toLowerCase().split(' ').reduce(function (acc, n) {\n var parts = n.toLowerCase().split('-');\n var first = parts[0];\n var rest = parts.slice(1).join('-');\n\n if (first && rest === 'h') {\n acc.flipX = true;\n return acc;\n }\n\n if (first && rest === 'v') {\n acc.flipY = true;\n return acc;\n }\n\n rest = parseFloat(rest);\n\n if (isNaN(rest)) {\n return acc;\n }\n\n switch (first) {\n case 'grow':\n acc.size = acc.size + rest;\n break;\n\n case 'shrink':\n acc.size = acc.size - rest;\n break;\n\n case 'left':\n acc.x = acc.x - rest;\n break;\n\n case 'right':\n acc.x = acc.x + rest;\n break;\n\n case 'up':\n acc.y = acc.y - rest;\n break;\n\n case 'down':\n acc.y = acc.y + rest;\n break;\n\n case 'rotate':\n acc.rotate = acc.rotate + rest;\n break;\n }\n\n return acc;\n }, transform);\n }\n};\nfunction transformParser (node) {\n return parseTransformString(node.getAttribute('data-fa-transform'));\n}\n\nfunction symbolParser (node) {\n var symbol = node.getAttribute('data-fa-symbol');\n return symbol === null ? false : symbol === '' ? true : symbol;\n}\n\nfunction attributesParser (node) {\n var extraAttributes = toArray(node.attributes).reduce(function (acc, attr) {\n if (acc.name !== 'class' && acc.name !== 'style') {\n acc[attr.name] = attr.value;\n }\n\n return acc;\n }, {});\n var title = node.getAttribute('title');\n\n if (config.autoA11y) {\n if (title) {\n extraAttributes['aria-labelledby'] = \"\".concat(config.replacementClass, \"-title-\").concat(nextUniqueId());\n } else {\n extraAttributes['aria-hidden'] = 'true';\n extraAttributes['focusable'] = 'false';\n }\n }\n\n return extraAttributes;\n}\n\nfunction maskParser (node) {\n var mask = node.getAttribute('data-fa-mask');\n\n if (!mask) {\n return emptyCanonicalIcon();\n } else {\n return getCanonicalIcon(mask.split(' ').map(function (i) {\n return i.trim();\n }));\n }\n}\n\nfunction blankMeta() {\n return {\n iconName: null,\n title: null,\n prefix: null,\n transform: meaninglessTransform,\n symbol: false,\n mask: null,\n extra: {\n classes: [],\n styles: {},\n attributes: {}\n }\n };\n}\nfunction parseMeta(node) {\n var _classParser = classParser(node),\n iconName = _classParser.iconName,\n prefix = _classParser.prefix,\n extraClasses = _classParser.rest;\n\n var extraStyles = styleParser(node);\n var transform = transformParser(node);\n var symbol = symbolParser(node);\n var extraAttributes = attributesParser(node);\n var mask = maskParser(node);\n return {\n iconName: iconName,\n title: node.getAttribute('title'),\n prefix: prefix,\n transform: transform,\n symbol: symbol,\n mask: mask,\n extra: {\n classes: extraClasses,\n styles: extraStyles,\n attributes: extraAttributes\n }\n };\n}\n\nfunction MissingIcon(error) {\n this.name = 'MissingIcon';\n this.message = error || 'Icon unavailable';\n this.stack = new Error().stack;\n}\nMissingIcon.prototype = Object.create(Error.prototype);\nMissingIcon.prototype.constructor = MissingIcon;\n\nvar FILL = {\n fill: 'currentColor'\n};\nvar ANIMATION_BASE = {\n attributeType: 'XML',\n repeatCount: 'indefinite',\n dur: '2s'\n};\nvar RING = {\n tag: 'path',\n attributes: _objectSpread({}, FILL, {\n d: 'M156.5,447.7l-12.6,29.5c-18.7-9.5-35.9-21.2-51.5-34.9l22.7-22.7C127.6,430.5,141.5,440,156.5,447.7z M40.6,272H8.5 c1.4,21.2,5.4,41.7,11.7,61.1L50,321.2C45.1,305.5,41.8,289,40.6,272z M40.6,240c1.4-18.8,5.2-37,11.1-54.1l-29.5-12.6 C14.7,194.3,10,216.7,8.5,240H40.6z M64.3,156.5c7.8-14.9,17.2-28.8,28.1-41.5L69.7,92.3c-13.7,15.6-25.5,32.8-34.9,51.5 L64.3,156.5z M397,419.6c-13.9,12-29.4,22.3-46.1,30.4l11.9,29.8c20.7-9.9,39.8-22.6,56.9-37.6L397,419.6z M115,92.4 c13.9-12,29.4-22.3,46.1-30.4l-11.9-29.8c-20.7,9.9-39.8,22.6-56.8,37.6L115,92.4z M447.7,355.5c-7.8,14.9-17.2,28.8-28.1,41.5 l22.7,22.7c13.7-15.6,25.5-32.9,34.9-51.5L447.7,355.5z M471.4,272c-1.4,18.8-5.2,37-11.1,54.1l29.5,12.6 c7.5-21.1,12.2-43.5,13.6-66.8H471.4z M321.2,462c-15.7,5-32.2,8.2-49.2,9.4v32.1c21.2-1.4,41.7-5.4,61.1-11.7L321.2,462z M240,471.4c-18.8-1.4-37-5.2-54.1-11.1l-12.6,29.5c21.1,7.5,43.5,12.2,66.8,13.6V471.4z M462,190.8c5,15.7,8.2,32.2,9.4,49.2h32.1 c-1.4-21.2-5.4-41.7-11.7-61.1L462,190.8z M92.4,397c-12-13.9-22.3-29.4-30.4-46.1l-29.8,11.9c9.9,20.7,22.6,39.8,37.6,56.9 L92.4,397z M272,40.6c18.8,1.4,36.9,5.2,54.1,11.1l12.6-29.5C317.7,14.7,295.3,10,272,8.5V40.6z M190.8,50 c15.7-5,32.2-8.2,49.2-9.4V8.5c-21.2,1.4-41.7,5.4-61.1,11.7L190.8,50z M442.3,92.3L419.6,115c12,13.9,22.3,29.4,30.5,46.1 l29.8-11.9C470,128.5,457.3,109.4,442.3,92.3z M397,92.4l22.7-22.7c-15.6-13.7-32.8-25.5-51.5-34.9l-12.6,29.5 C370.4,72.1,384.4,81.5,397,92.4z'\n })\n};\n\nvar OPACITY_ANIMATE = _objectSpread({}, ANIMATION_BASE, {\n attributeName: 'opacity'\n});\n\nvar DOT = {\n tag: 'circle',\n attributes: _objectSpread({}, FILL, {\n cx: '256',\n cy: '364',\n r: '28'\n }),\n children: [{\n tag: 'animate',\n attributes: _objectSpread({}, ANIMATION_BASE, {\n attributeName: 'r',\n values: '28;14;28;28;14;28;'\n })\n }, {\n tag: 'animate',\n attributes: _objectSpread({}, OPACITY_ANIMATE, {\n values: '1;0;1;1;0;1;'\n })\n }]\n};\nvar QUESTION = {\n tag: 'path',\n attributes: _objectSpread({}, FILL, {\n opacity: '1',\n d: 'M263.7,312h-16c-6.6,0-12-5.4-12-12c0-71,77.4-63.9,77.4-107.8c0-20-17.8-40.2-57.4-40.2c-29.1,0-44.3,9.6-59.2,28.7 c-3.9,5-11.1,6-16.2,2.4l-13.1-9.2c-5.6-3.9-6.9-11.8-2.6-17.2c21.2-27.2,46.4-44.7,91.2-44.7c52.3,0,97.4,29.8,97.4,80.2 c0,67.6-77.4,63.5-77.4,107.8C275.7,306.6,270.3,312,263.7,312z'\n }),\n children: [{\n tag: 'animate',\n attributes: _objectSpread({}, OPACITY_ANIMATE, {\n values: '1;0;0;0;0;1;'\n })\n }]\n};\nvar EXCLAMATION = {\n tag: 'path',\n attributes: _objectSpread({}, FILL, {\n opacity: '0',\n d: 'M232.5,134.5l7,168c0.3,6.4,5.6,11.5,12,11.5h9c6.4,0,11.7-5.1,12-11.5l7-168c0.3-6.8-5.2-12.5-12-12.5h-23 C237.7,122,232.2,127.7,232.5,134.5z'\n }),\n children: [{\n tag: 'animate',\n attributes: _objectSpread({}, OPACITY_ANIMATE, {\n values: '0;0;1;1;0;0;'\n })\n }]\n};\nvar missing = {\n tag: 'g',\n children: [RING, DOT, QUESTION, EXCLAMATION]\n};\n\nvar styles$2 = namespace.styles;\nfunction findIcon(iconName, prefix) {\n return new picked(function (resolve, reject) {\n var val = {\n found: false,\n width: 512,\n height: 512,\n icon: missing\n };\n\n if (iconName && prefix && styles$2[prefix] && styles$2[prefix][iconName]) {\n var icon = styles$2[prefix][iconName];\n var width = icon[0];\n var height = icon[1];\n var vectorData = icon.slice(4);\n val = {\n found: true,\n width: width,\n height: height,\n icon: {\n tag: 'path',\n attributes: {\n fill: 'currentColor',\n d: vectorData[0]\n }\n }\n };\n return resolve(val);\n }\n\n if (iconName && prefix && !config.showMissingIcons) {\n reject(new MissingIcon(\"Icon is missing for prefix \".concat(prefix, \" with icon name \").concat(iconName)));\n } else {\n resolve(val);\n }\n });\n}\n\nvar styles$3 = namespace.styles;\n\nfunction generateSvgReplacementMutation(node, nodeMeta) {\n var iconName = nodeMeta.iconName,\n title = nodeMeta.title,\n prefix = nodeMeta.prefix,\n transform = nodeMeta.transform,\n symbol = nodeMeta.symbol,\n mask = nodeMeta.mask,\n extra = nodeMeta.extra;\n return new picked(function (resolve, reject) {\n picked.all([findIcon(iconName, prefix), findIcon(mask.iconName, mask.prefix)]).then(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n main = _ref2[0],\n mask = _ref2[1];\n\n resolve([node, makeInlineSvgAbstract({\n icons: {\n main: main,\n mask: mask\n },\n prefix: prefix,\n iconName: iconName,\n transform: transform,\n symbol: symbol,\n mask: mask,\n title: title,\n extra: extra,\n watchable: true\n })]);\n });\n });\n}\n\nfunction generateLayersText(node, nodeMeta) {\n var title = nodeMeta.title,\n transform = nodeMeta.transform,\n extra = nodeMeta.extra;\n var width = null;\n var height = null;\n\n if (IS_IE) {\n var computedFontSize = parseInt(getComputedStyle(node).fontSize, 10);\n var boundingClientRect = node.getBoundingClientRect();\n width = boundingClientRect.width / computedFontSize;\n height = boundingClientRect.height / computedFontSize;\n }\n\n if (config.autoA11y && !title) {\n extra.attributes['aria-hidden'] = 'true';\n }\n\n return picked.resolve([node, makeLayersTextAbstract({\n content: node.innerHTML,\n width: width,\n height: height,\n transform: transform,\n title: title,\n extra: extra,\n watchable: true\n })]);\n}\n\nfunction generateMutation(node) {\n var nodeMeta = parseMeta(node);\n\n if (~nodeMeta.extra.classes.indexOf(LAYERS_TEXT_CLASSNAME)) {\n return generateLayersText(node, nodeMeta);\n } else {\n return generateSvgReplacementMutation(node, nodeMeta);\n }\n}\n\nfunction onTree(root) {\n var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n if (!IS_DOM) return;\n var htmlClassList = DOCUMENT.documentElement.classList;\n\n var hclAdd = function hclAdd(suffix) {\n return htmlClassList.add(\"\".concat(HTML_CLASS_I2SVG_BASE_CLASS, \"-\").concat(suffix));\n };\n\n var hclRemove = function hclRemove(suffix) {\n return htmlClassList.remove(\"\".concat(HTML_CLASS_I2SVG_BASE_CLASS, \"-\").concat(suffix));\n };\n\n var prefixes = config.autoFetchSvg ? Object.keys(PREFIX_TO_STYLE) : Object.keys(styles$3);\n var prefixesDomQuery = [\".\".concat(LAYERS_TEXT_CLASSNAME, \":not([\").concat(DATA_FA_I2SVG, \"])\")].concat(prefixes.map(function (p) {\n return \".\".concat(p, \":not([\").concat(DATA_FA_I2SVG, \"])\");\n })).join(', ');\n\n if (prefixesDomQuery.length === 0) {\n return;\n }\n\n var candidates = toArray(root.querySelectorAll(prefixesDomQuery));\n\n if (candidates.length > 0) {\n hclAdd('pending');\n hclRemove('complete');\n } else {\n return;\n }\n\n var mark = perf.begin('onTree');\n var mutations = candidates.reduce(function (acc, node) {\n try {\n var mutation = generateMutation(node);\n\n if (mutation) {\n acc.push(mutation);\n }\n } catch (e) {\n if (!PRODUCTION) {\n if (e instanceof MissingIcon) {\n console.error(e);\n }\n }\n }\n\n return acc;\n }, []);\n return new picked(function (resolve, reject) {\n picked.all(mutations).then(function (resolvedMutations) {\n perform(resolvedMutations, function () {\n hclAdd('active');\n hclAdd('complete');\n hclRemove('pending');\n if (typeof callback === 'function') callback();\n mark();\n resolve();\n });\n }).catch(function () {\n mark();\n reject();\n });\n });\n}\nfunction onNode(node) {\n var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n generateMutation(node).then(function (mutation) {\n if (mutation) {\n perform([mutation], callback);\n }\n });\n}\n\nfunction replaceForPosition(node, position) {\n var pendingAttribute = \"\".concat(DATA_FA_PSEUDO_ELEMENT_PENDING).concat(position.replace(':', '-'));\n return new picked(function (resolve, reject) {\n if (node.getAttribute(pendingAttribute) !== null) {\n // This node is already being processed\n return resolve();\n }\n\n var children = toArray(node.children);\n var alreadyProcessedPseudoElement = children.filter(function (c) {\n return c.getAttribute(DATA_FA_PSEUDO_ELEMENT) === position;\n })[0];\n var styles = WINDOW.getComputedStyle(node, position);\n var fontFamily = styles.getPropertyValue('font-family').match(FONT_FAMILY_PATTERN);\n var fontWeight = styles.getPropertyValue('font-weight');\n\n if (alreadyProcessedPseudoElement && !fontFamily) {\n // If we've already processed it but the current computed style does not result in a font-family,\n // that probably means that a class name that was previously present to make the icon has been\n // removed. So we now should delete the icon.\n node.removeChild(alreadyProcessedPseudoElement);\n return resolve();\n } else if (fontFamily) {\n var content = styles.getPropertyValue('content');\n var prefix = ~['Light', 'Regular', 'Solid', 'Brands'].indexOf(fontFamily[1]) ? STYLE_TO_PREFIX[fontFamily[1].toLowerCase()] : FONT_WEIGHT_TO_PREFIX[fontWeight];\n var iconName = byUnicode(prefix, toHex(content.length === 3 ? content.substr(1, 1) : content)); // Only convert the pseudo element in this :before/:after position into an icon if we haven't\n // already done so with the same prefix and iconName\n\n if (!alreadyProcessedPseudoElement || alreadyProcessedPseudoElement.getAttribute(DATA_PREFIX) !== prefix || alreadyProcessedPseudoElement.getAttribute(DATA_ICON) !== iconName) {\n node.setAttribute(pendingAttribute, iconName);\n\n if (alreadyProcessedPseudoElement) {\n // Delete the old one, since we're replacing it with a new one\n node.removeChild(alreadyProcessedPseudoElement);\n }\n\n var meta = blankMeta();\n var extra = meta.extra;\n extra.attributes[DATA_FA_PSEUDO_ELEMENT] = position;\n findIcon(iconName, prefix).then(function (main) {\n var abstract = makeInlineSvgAbstract(_objectSpread({}, meta, {\n icons: {\n main: main,\n mask: emptyCanonicalIcon()\n },\n prefix: prefix,\n iconName: iconName,\n extra: extra,\n watchable: true\n }));\n var element = DOCUMENT.createElement('svg');\n\n if (position === ':before') {\n node.insertBefore(element, node.firstChild);\n } else {\n node.appendChild(element);\n }\n\n element.outerHTML = abstract.map(function (a) {\n return toHtml(a);\n }).join('\\n');\n node.removeAttribute(pendingAttribute);\n resolve();\n }).catch(reject);\n } else {\n resolve();\n }\n } else {\n resolve();\n }\n });\n}\n\nfunction replace(node) {\n return picked.all([replaceForPosition(node, ':before'), replaceForPosition(node, ':after')]);\n}\n\nfunction processable(node) {\n return node.parentNode !== document.head && !~TAGNAMES_TO_SKIP_FOR_PSEUDOELEMENTS.indexOf(node.tagName.toUpperCase()) && !node.getAttribute(DATA_FA_PSEUDO_ELEMENT) && (!node.parentNode || node.parentNode.tagName !== 'svg');\n}\n\nfunction searchPseudoElements (root) {\n if (!IS_DOM) return;\n return new picked(function (resolve, reject) {\n var operations = toArray(root.querySelectorAll('*')).filter(processable).map(replace);\n var end = perf.begin('searchPseudoElements');\n disableObservation();\n picked.all(operations).then(function () {\n end();\n enableObservation();\n resolve();\n }).catch(function () {\n end();\n enableObservation();\n reject();\n });\n });\n}\n\nvar baseStyles = \"svg:not(:root).svg-inline--fa {\\n overflow: visible;\\n}\\n\\n.svg-inline--fa {\\n display: inline-block;\\n font-size: inherit;\\n height: 1em;\\n overflow: visible;\\n vertical-align: -0.125em;\\n}\\n.svg-inline--fa.fa-lg {\\n vertical-align: -0.225em;\\n}\\n.svg-inline--fa.fa-w-1 {\\n width: 0.0625em;\\n}\\n.svg-inline--fa.fa-w-2 {\\n width: 0.125em;\\n}\\n.svg-inline--fa.fa-w-3 {\\n width: 0.1875em;\\n}\\n.svg-inline--fa.fa-w-4 {\\n width: 0.25em;\\n}\\n.svg-inline--fa.fa-w-5 {\\n width: 0.3125em;\\n}\\n.svg-inline--fa.fa-w-6 {\\n width: 0.375em;\\n}\\n.svg-inline--fa.fa-w-7 {\\n width: 0.4375em;\\n}\\n.svg-inline--fa.fa-w-8 {\\n width: 0.5em;\\n}\\n.svg-inline--fa.fa-w-9 {\\n width: 0.5625em;\\n}\\n.svg-inline--fa.fa-w-10 {\\n width: 0.625em;\\n}\\n.svg-inline--fa.fa-w-11 {\\n width: 0.6875em;\\n}\\n.svg-inline--fa.fa-w-12 {\\n width: 0.75em;\\n}\\n.svg-inline--fa.fa-w-13 {\\n width: 0.8125em;\\n}\\n.svg-inline--fa.fa-w-14 {\\n width: 0.875em;\\n}\\n.svg-inline--fa.fa-w-15 {\\n width: 0.9375em;\\n}\\n.svg-inline--fa.fa-w-16 {\\n width: 1em;\\n}\\n.svg-inline--fa.fa-w-17 {\\n width: 1.0625em;\\n}\\n.svg-inline--fa.fa-w-18 {\\n width: 1.125em;\\n}\\n.svg-inline--fa.fa-w-19 {\\n width: 1.1875em;\\n}\\n.svg-inline--fa.fa-w-20 {\\n width: 1.25em;\\n}\\n.svg-inline--fa.fa-pull-left {\\n margin-right: 0.3em;\\n width: auto;\\n}\\n.svg-inline--fa.fa-pull-right {\\n margin-left: 0.3em;\\n width: auto;\\n}\\n.svg-inline--fa.fa-border {\\n height: 1.5em;\\n}\\n.svg-inline--fa.fa-li {\\n width: 2em;\\n}\\n.svg-inline--fa.fa-fw {\\n width: 1.25em;\\n}\\n\\n.fa-layers svg.svg-inline--fa {\\n bottom: 0;\\n left: 0;\\n margin: auto;\\n position: absolute;\\n right: 0;\\n top: 0;\\n}\\n\\n.fa-layers {\\n display: inline-block;\\n height: 1em;\\n position: relative;\\n text-align: center;\\n vertical-align: -0.125em;\\n width: 1em;\\n}\\n.fa-layers svg.svg-inline--fa {\\n -webkit-transform-origin: center center;\\n transform-origin: center center;\\n}\\n\\n.fa-layers-counter, .fa-layers-text {\\n display: inline-block;\\n position: absolute;\\n text-align: center;\\n}\\n\\n.fa-layers-text {\\n left: 50%;\\n top: 50%;\\n -webkit-transform: translate(-50%, -50%);\\n transform: translate(-50%, -50%);\\n -webkit-transform-origin: center center;\\n transform-origin: center center;\\n}\\n\\n.fa-layers-counter {\\n background-color: #ff253a;\\n border-radius: 1em;\\n -webkit-box-sizing: border-box;\\n box-sizing: border-box;\\n color: #fff;\\n height: 1.5em;\\n line-height: 1;\\n max-width: 5em;\\n min-width: 1.5em;\\n overflow: hidden;\\n padding: 0.25em;\\n right: 0;\\n text-overflow: ellipsis;\\n top: 0;\\n -webkit-transform: scale(0.25);\\n transform: scale(0.25);\\n -webkit-transform-origin: top right;\\n transform-origin: top right;\\n}\\n\\n.fa-layers-bottom-right {\\n bottom: 0;\\n right: 0;\\n top: auto;\\n -webkit-transform: scale(0.25);\\n transform: scale(0.25);\\n -webkit-transform-origin: bottom right;\\n transform-origin: bottom right;\\n}\\n\\n.fa-layers-bottom-left {\\n bottom: 0;\\n left: 0;\\n right: auto;\\n top: auto;\\n -webkit-transform: scale(0.25);\\n transform: scale(0.25);\\n -webkit-transform-origin: bottom left;\\n transform-origin: bottom left;\\n}\\n\\n.fa-layers-top-right {\\n right: 0;\\n top: 0;\\n -webkit-transform: scale(0.25);\\n transform: scale(0.25);\\n -webkit-transform-origin: top right;\\n transform-origin: top right;\\n}\\n\\n.fa-layers-top-left {\\n left: 0;\\n right: auto;\\n top: 0;\\n -webkit-transform: scale(0.25);\\n transform: scale(0.25);\\n -webkit-transform-origin: top left;\\n transform-origin: top left;\\n}\\n\\n.fa-lg {\\n font-size: 1.3333333333em;\\n line-height: 0.75em;\\n vertical-align: -0.0667em;\\n}\\n\\n.fa-xs {\\n font-size: 0.75em;\\n}\\n\\n.fa-sm {\\n font-size: 0.875em;\\n}\\n\\n.fa-1x {\\n font-size: 1em;\\n}\\n\\n.fa-2x {\\n font-size: 2em;\\n}\\n\\n.fa-3x {\\n font-size: 3em;\\n}\\n\\n.fa-4x {\\n font-size: 4em;\\n}\\n\\n.fa-5x {\\n font-size: 5em;\\n}\\n\\n.fa-6x {\\n font-size: 6em;\\n}\\n\\n.fa-7x {\\n font-size: 7em;\\n}\\n\\n.fa-8x {\\n font-size: 8em;\\n}\\n\\n.fa-9x {\\n font-size: 9em;\\n}\\n\\n.fa-10x {\\n font-size: 10em;\\n}\\n\\n.fa-fw {\\n text-align: center;\\n width: 1.25em;\\n}\\n\\n.fa-ul {\\n list-style-type: none;\\n margin-left: 2.5em;\\n padding-left: 0;\\n}\\n.fa-ul > li {\\n position: relative;\\n}\\n\\n.fa-li {\\n left: -2em;\\n position: absolute;\\n text-align: center;\\n width: 2em;\\n line-height: inherit;\\n}\\n\\n.fa-border {\\n border: solid 0.08em #eee;\\n border-radius: 0.1em;\\n padding: 0.2em 0.25em 0.15em;\\n}\\n\\n.fa-pull-left {\\n float: left;\\n}\\n\\n.fa-pull-right {\\n float: right;\\n}\\n\\n.fa.fa-pull-left,\\n.fas.fa-pull-left,\\n.far.fa-pull-left,\\n.fal.fa-pull-left,\\n.fab.fa-pull-left {\\n margin-right: 0.3em;\\n}\\n.fa.fa-pull-right,\\n.fas.fa-pull-right,\\n.far.fa-pull-right,\\n.fal.fa-pull-right,\\n.fab.fa-pull-right {\\n margin-left: 0.3em;\\n}\\n\\n.fa-spin {\\n -webkit-animation: fa-spin 2s infinite linear;\\n animation: fa-spin 2s infinite linear;\\n}\\n\\n.fa-pulse {\\n -webkit-animation: fa-spin 1s infinite steps(8);\\n animation: fa-spin 1s infinite steps(8);\\n}\\n\\n@-webkit-keyframes fa-spin {\\n 0% {\\n -webkit-transform: rotate(0deg);\\n transform: rotate(0deg);\\n }\\n 100% {\\n -webkit-transform: rotate(360deg);\\n transform: rotate(360deg);\\n }\\n}\\n\\n@keyframes fa-spin {\\n 0% {\\n -webkit-transform: rotate(0deg);\\n transform: rotate(0deg);\\n }\\n 100% {\\n -webkit-transform: rotate(360deg);\\n transform: rotate(360deg);\\n }\\n}\\n.fa-rotate-90 {\\n -ms-filter: \\\"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\\\";\\n -webkit-transform: rotate(90deg);\\n transform: rotate(90deg);\\n}\\n\\n.fa-rotate-180 {\\n -ms-filter: \\\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\\\";\\n -webkit-transform: rotate(180deg);\\n transform: rotate(180deg);\\n}\\n\\n.fa-rotate-270 {\\n -ms-filter: \\\"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\\\";\\n -webkit-transform: rotate(270deg);\\n transform: rotate(270deg);\\n}\\n\\n.fa-flip-horizontal {\\n -ms-filter: \\\"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\\\";\\n -webkit-transform: scale(-1, 1);\\n transform: scale(-1, 1);\\n}\\n\\n.fa-flip-vertical {\\n -ms-filter: \\\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\\\";\\n -webkit-transform: scale(1, -1);\\n transform: scale(1, -1);\\n}\\n\\n.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {\\n -ms-filter: \\\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\\\";\\n -webkit-transform: scale(-1, -1);\\n transform: scale(-1, -1);\\n}\\n\\n:root .fa-rotate-90,\\n:root .fa-rotate-180,\\n:root .fa-rotate-270,\\n:root .fa-flip-horizontal,\\n:root .fa-flip-vertical,\\n:root .fa-flip-both {\\n -webkit-filter: none;\\n filter: none;\\n}\\n\\n.fa-stack {\\n display: inline-block;\\n height: 2em;\\n position: relative;\\n width: 2.5em;\\n}\\n\\n.fa-stack-1x,\\n.fa-stack-2x {\\n bottom: 0;\\n left: 0;\\n margin: auto;\\n position: absolute;\\n right: 0;\\n top: 0;\\n}\\n\\n.svg-inline--fa.fa-stack-1x {\\n height: 1em;\\n width: 1.25em;\\n}\\n.svg-inline--fa.fa-stack-2x {\\n height: 2em;\\n width: 2.5em;\\n}\\n\\n.fa-inverse {\\n color: #fff;\\n}\\n\\n.sr-only {\\n border: 0;\\n clip: rect(0, 0, 0, 0);\\n height: 1px;\\n margin: -1px;\\n overflow: hidden;\\n padding: 0;\\n position: absolute;\\n width: 1px;\\n}\\n\\n.sr-only-focusable:active, .sr-only-focusable:focus {\\n clip: auto;\\n height: auto;\\n margin: 0;\\n overflow: visible;\\n position: static;\\n width: auto;\\n}\";\n\nfunction css () {\n var dfp = DEFAULT_FAMILY_PREFIX;\n var drc = DEFAULT_REPLACEMENT_CLASS;\n var fp = config.familyPrefix;\n var rc = config.replacementClass;\n var s = baseStyles;\n\n if (fp !== dfp || rc !== drc) {\n var dPatt = new RegExp(\"\\\\.\".concat(dfp, \"\\\\-\"), 'g');\n var rPatt = new RegExp(\"\\\\.\".concat(drc), 'g');\n s = s.replace(dPatt, \".\".concat(fp, \"-\")).replace(rPatt, \".\".concat(rc));\n }\n\n return s;\n}\n\nvar Library =\n/*#__PURE__*/\nfunction () {\n function Library() {\n _classCallCheck(this, Library);\n\n this.definitions = {};\n }\n\n _createClass(Library, [{\n key: \"add\",\n value: function add() {\n var _this = this;\n\n for (var _len = arguments.length, definitions = new Array(_len), _key = 0; _key < _len; _key++) {\n definitions[_key] = arguments[_key];\n }\n\n var additions = definitions.reduce(this._pullDefinitions, {});\n Object.keys(additions).forEach(function (key) {\n _this.definitions[key] = _objectSpread({}, _this.definitions[key] || {}, additions[key]);\n defineIcons(key, additions[key]);\n build();\n });\n }\n }, {\n key: \"reset\",\n value: function reset() {\n this.definitions = {};\n }\n }, {\n key: \"_pullDefinitions\",\n value: function _pullDefinitions(additions, definition) {\n var normalized = definition.prefix && definition.iconName && definition.icon ? {\n 0: definition\n } : definition;\n Object.keys(normalized).map(function (key) {\n var _normalized$key = normalized[key],\n prefix = _normalized$key.prefix,\n iconName = _normalized$key.iconName,\n icon = _normalized$key.icon;\n if (!additions[prefix]) additions[prefix] = {};\n additions[prefix][iconName] = icon;\n });\n return additions;\n }\n }]);\n\n return Library;\n}();\n\nfunction prepIcon(icon) {\n var width = icon[0];\n var height = icon[1];\n var vectorData = icon.slice(4);\n return {\n found: true,\n width: width,\n height: height,\n icon: {\n tag: 'path',\n attributes: {\n fill: 'currentColor',\n d: vectorData[0]\n }\n }\n };\n}\n\nfunction ensureCss() {\n if (config.autoAddCss && !_cssInserted) {\n insertCss(css());\n\n _cssInserted = true;\n }\n}\n\nfunction apiObject(val, abstractCreator) {\n Object.defineProperty(val, 'abstract', {\n get: abstractCreator\n });\n Object.defineProperty(val, 'html', {\n get: function get() {\n return val.abstract.map(function (a) {\n return toHtml(a);\n });\n }\n });\n Object.defineProperty(val, 'node', {\n get: function get() {\n if (!IS_DOM) return;\n var container = DOCUMENT.createElement('div');\n container.innerHTML = val.html;\n return container.children;\n }\n });\n return val;\n}\n\nfunction findIconDefinition(iconLookup) {\n var _iconLookup$prefix = iconLookup.prefix,\n prefix = _iconLookup$prefix === void 0 ? 'fa' : _iconLookup$prefix,\n iconName = iconLookup.iconName;\n if (!iconName) return;\n return iconFromMapping(library.definitions, prefix, iconName) || iconFromMapping(namespace.styles, prefix, iconName);\n}\n\nfunction resolveIcons(next) {\n return function (maybeIconDefinition) {\n var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var iconDefinition = (maybeIconDefinition || {}).icon ? maybeIconDefinition : findIconDefinition(maybeIconDefinition || {});\n var mask = params.mask;\n\n if (mask) {\n mask = (mask || {}).icon ? mask : findIconDefinition(mask || {});\n }\n\n return next(iconDefinition, _objectSpread({}, params, {\n mask: mask\n }));\n };\n}\n\nvar library = new Library();\nvar noAuto = function noAuto() {\n config.autoReplaceSvg = false;\n config.observeMutations = false;\n disconnect();\n};\nvar _cssInserted = false;\nvar dom = {\n i2svg: function i2svg() {\n var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (IS_DOM) {\n ensureCss();\n var _params$node = params.node,\n node = _params$node === void 0 ? DOCUMENT : _params$node,\n _params$callback = params.callback,\n callback = _params$callback === void 0 ? function () {} : _params$callback;\n\n if (config.searchPseudoElements) {\n searchPseudoElements(node);\n }\n\n return onTree(node, callback);\n } else {\n return picked.reject('Operation requires a DOM of some kind.');\n }\n },\n css: css,\n insertCss: function insertCss$$1() {\n if (!_cssInserted) {\n insertCss(css());\n\n _cssInserted = true;\n }\n },\n watch: function watch() {\n var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var autoReplaceSvgRoot = params.autoReplaceSvgRoot,\n observeMutationsRoot = params.observeMutationsRoot;\n\n if (config.autoReplaceSvg === false) {\n config.autoReplaceSvg = true;\n }\n\n config.observeMutations = true;\n domready(function () {\n autoReplace({\n autoReplaceSvgRoot: autoReplaceSvgRoot\n });\n observe({\n treeCallback: onTree,\n nodeCallback: onNode,\n pseudoElementsCallback: searchPseudoElements,\n observeMutationsRoot: observeMutationsRoot\n });\n });\n }\n};\nvar parse = {\n transform: function transform(transformString) {\n return parseTransformString(transformString);\n }\n};\nvar icon = resolveIcons(function (iconDefinition) {\n var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var _params$transform = params.transform,\n transform = _params$transform === void 0 ? meaninglessTransform : _params$transform,\n _params$symbol = params.symbol,\n symbol = _params$symbol === void 0 ? false : _params$symbol,\n _params$mask = params.mask,\n mask = _params$mask === void 0 ? null : _params$mask,\n _params$title = params.title,\n title = _params$title === void 0 ? null : _params$title,\n _params$classes = params.classes,\n classes = _params$classes === void 0 ? [] : _params$classes,\n _params$attributes = params.attributes,\n attributes = _params$attributes === void 0 ? {} : _params$attributes,\n _params$styles = params.styles,\n styles = _params$styles === void 0 ? {} : _params$styles;\n if (!iconDefinition) return;\n var prefix = iconDefinition.prefix,\n iconName = iconDefinition.iconName,\n icon = iconDefinition.icon;\n return apiObject(_objectSpread({\n type: 'icon'\n }, iconDefinition), function () {\n ensureCss();\n\n if (config.autoA11y) {\n if (title) {\n attributes['aria-labelledby'] = \"\".concat(config.replacementClass, \"-title-\").concat(nextUniqueId());\n } else {\n attributes['aria-hidden'] = 'true';\n attributes['focusable'] = 'false';\n }\n }\n\n return makeInlineSvgAbstract({\n icons: {\n main: prepIcon(icon),\n mask: mask ? prepIcon(mask.icon) : {\n found: false,\n width: null,\n height: null,\n icon: {}\n }\n },\n prefix: prefix,\n iconName: iconName,\n transform: _objectSpread({}, meaninglessTransform, transform),\n symbol: symbol,\n title: title,\n extra: {\n attributes: attributes,\n styles: styles,\n classes: classes\n }\n });\n });\n});\nvar text = function text(content) {\n var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var _params$transform2 = params.transform,\n transform = _params$transform2 === void 0 ? meaninglessTransform : _params$transform2,\n _params$title2 = params.title,\n title = _params$title2 === void 0 ? null : _params$title2,\n _params$classes2 = params.classes,\n classes = _params$classes2 === void 0 ? [] : _params$classes2,\n _params$attributes2 = params.attributes,\n attributes = _params$attributes2 === void 0 ? {} : _params$attributes2,\n _params$styles2 = params.styles,\n styles = _params$styles2 === void 0 ? {} : _params$styles2;\n return apiObject({\n type: 'text',\n content: content\n }, function () {\n ensureCss();\n return makeLayersTextAbstract({\n content: content,\n transform: _objectSpread({}, meaninglessTransform, transform),\n title: title,\n extra: {\n attributes: attributes,\n styles: styles,\n classes: [\"\".concat(config.familyPrefix, \"-layers-text\")].concat(_toConsumableArray(classes))\n }\n });\n });\n};\nvar counter = function counter(content) {\n var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var _params$title3 = params.title,\n title = _params$title3 === void 0 ? null : _params$title3,\n _params$classes3 = params.classes,\n classes = _params$classes3 === void 0 ? [] : _params$classes3,\n _params$attributes3 = params.attributes,\n attributes = _params$attributes3 === void 0 ? {} : _params$attributes3,\n _params$styles3 = params.styles,\n styles = _params$styles3 === void 0 ? {} : _params$styles3;\n return apiObject({\n type: 'counter',\n content: content\n }, function () {\n ensureCss();\n return makeLayersCounterAbstract({\n content: content.toString(),\n title: title,\n extra: {\n attributes: attributes,\n styles: styles,\n classes: [\"\".concat(config.familyPrefix, \"-layers-counter\")].concat(_toConsumableArray(classes))\n }\n });\n });\n};\nvar layer = function layer(assembler) {\n return apiObject({\n type: 'layer'\n }, function () {\n ensureCss();\n var children = [];\n assembler(function (args) {\n Array.isArray(args) ? args.map(function (a) {\n children = children.concat(a.abstract);\n }) : children = children.concat(args.abstract);\n });\n return [{\n tag: 'span',\n attributes: {\n class: \"\".concat(config.familyPrefix, \"-layers\")\n },\n children: children\n }];\n });\n};\nvar api = {\n noAuto: noAuto,\n config: config,\n dom: dom,\n library: library,\n parse: parse,\n findIconDefinition: findIconDefinition,\n icon: icon,\n text: text,\n counter: counter,\n layer: layer,\n toHtml: toHtml\n};\n\nvar autoReplace = function autoReplace() {\n var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var _params$autoReplaceSv = params.autoReplaceSvgRoot,\n autoReplaceSvgRoot = _params$autoReplaceSv === void 0 ? DOCUMENT : _params$autoReplaceSv;\n if ((Object.keys(namespace.styles).length > 0 || config.autoFetchSvg) && IS_DOM && config.autoReplaceSvg) api.dom.i2svg({\n node: autoReplaceSvgRoot\n });\n};\n\nexport { icon, noAuto, config, toHtml, layer, text, counter, library, dom, parse, findIconDefinition };\n", + "var prefix = \"far\";\nvar faAddressBook = {\n prefix: 'far',\n iconName: 'address-book',\n icon: [448, 512, [], \"f2b9\", \"M436 160c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20zm-68 304H48V48h320v416zM208 256c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm-89.6 128h179.2c12.4 0 22.4-8.6 22.4-19.2v-19.2c0-31.8-30.1-57.6-67.2-57.6-10.8 0-18.7 8-44.8 8-26.9 0-33.4-8-44.8-8-37.1 0-67.2 25.8-67.2 57.6v19.2c0 10.6 10 19.2 22.4 19.2z\"]\n};\nvar faAddressCard = {\n prefix: 'far',\n iconName: 'address-card',\n icon: [576, 512, [], \"f2bb\", \"M528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm0 400H48V80h480v352zM208 256c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm-89.6 128h179.2c12.4 0 22.4-8.6 22.4-19.2v-19.2c0-31.8-30.1-57.6-67.2-57.6-10.8 0-18.7 8-44.8 8-26.9 0-33.4-8-44.8-8-37.1 0-67.2 25.8-67.2 57.6v19.2c0 10.6 10 19.2 22.4 19.2zM360 320h112c4.4 0 8-3.6 8-8v-16c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8zm0-64h112c4.4 0 8-3.6 8-8v-16c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8zm0-64h112c4.4 0 8-3.6 8-8v-16c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8z\"]\n};\nvar faAngry = {\n prefix: 'far',\n iconName: 'angry',\n icon: [496, 512, [], \"f556\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm0-144c-33.6 0-65.2 14.8-86.8 40.6-8.5 10.2-7.1 25.3 3.1 33.8s25.3 7.2 33.8-3c24.8-29.7 75-29.7 99.8 0 8.1 9.7 23.2 11.9 33.8 3 10.2-8.5 11.5-23.6 3.1-33.8-21.6-25.8-53.2-40.6-86.8-40.6zm-48-72c10.3 0 19.9-6.7 23-17.1 3.8-12.7-3.4-26.1-16.1-29.9l-80-24c-12.8-3.9-26.1 3.4-29.9 16.1-3.8 12.7 3.4 26.1 16.1 29.9l28.2 8.5c-3.1 4.9-5.3 10.4-5.3 16.6 0 17.7 14.3 32 32 32s32-14.4 32-32.1zm199-54.9c-3.8-12.7-17.1-19.9-29.9-16.1l-80 24c-12.7 3.8-19.9 17.2-16.1 29.9 3.1 10.4 12.7 17.1 23 17.1 0 17.7 14.3 32 32 32s32-14.3 32-32c0-6.2-2.2-11.7-5.3-16.6l28.2-8.5c12.7-3.7 19.9-17.1 16.1-29.8z\"]\n};\nvar faArrowAltCircleDown = {\n prefix: 'far',\n iconName: 'arrow-alt-circle-down',\n icon: [512, 512, [], \"f358\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z\"]\n};\nvar faArrowAltCircleLeft = {\n prefix: 'far',\n iconName: 'arrow-alt-circle-left',\n icon: [512, 512, [], \"f359\", \"M8 256c0 137 111 248 248 248s248-111 248-248S393 8 256 8 8 119 8 256zm448 0c0 110.5-89.5 200-200 200S56 366.5 56 256 145.5 56 256 56s200 89.5 200 200zm-72-20v40c0 6.6-5.4 12-12 12H256v67c0 10.7-12.9 16-20.5 8.5l-99-99c-4.7-4.7-4.7-12.3 0-17l99-99c7.6-7.6 20.5-2.2 20.5 8.5v67h116c6.6 0 12 5.4 12 12z\"]\n};\nvar faArrowAltCircleRight = {\n prefix: 'far',\n iconName: 'arrow-alt-circle-right',\n icon: [512, 512, [], \"f35a\", \"M504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256zm72 20v-40c0-6.6 5.4-12 12-12h116v-67c0-10.7 12.9-16 20.5-8.5l99 99c4.7 4.7 4.7 12.3 0 17l-99 99c-7.6 7.6-20.5 2.2-20.5-8.5v-67H140c-6.6 0-12-5.4-12-12z\"]\n};\nvar faArrowAltCircleUp = {\n prefix: 'far',\n iconName: 'arrow-alt-circle-up',\n icon: [512, 512, [], \"f35b\", \"M256 504c137 0 248-111 248-248S393 8 256 8 8 119 8 256s111 248 248 248zm0-448c110.5 0 200 89.5 200 200s-89.5 200-200 200S56 366.5 56 256 145.5 56 256 56zm20 328h-40c-6.6 0-12-5.4-12-12V256h-67c-10.7 0-16-12.9-8.5-20.5l99-99c4.7-4.7 12.3-4.7 17 0l99 99c7.6 7.6 2.2 20.5-8.5 20.5h-67v116c0 6.6-5.4 12-12 12z\"]\n};\nvar faBell = {\n prefix: 'far',\n iconName: 'bell',\n icon: [448, 512, [], \"f0f3\", \"M439.39 362.29c-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84C118.56 68.1 64.08 130.3 64.08 208c0 102.3-36.15 133.53-55.47 154.29-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h383.8c19.12 0 32-15.6 32.1-32 .05-7.55-2.61-15.27-8.61-21.71zM67.53 368c21.22-27.97 44.42-74.33 44.53-159.42 0-.2-.06-.38-.06-.58 0-61.86 50.14-112 112-112s112 50.14 112 112c0 .2-.06.38-.06.58.11 85.1 23.31 131.46 44.53 159.42H67.53zM224 512c35.32 0 63.97-28.65 63.97-64H160.03c0 35.35 28.65 64 63.97 64z\"]\n};\nvar faBellSlash = {\n prefix: 'far',\n iconName: 'bell-slash',\n icon: [640, 512, [], \"f1f6\", \"M633.99 471.02L36 3.51C29.1-2.01 19.03-.9 13.51 6l-10 12.49C-2.02 25.39-.9 35.46 6 40.98l598 467.51c6.9 5.52 16.96 4.4 22.49-2.49l10-12.49c5.52-6.9 4.41-16.97-2.5-22.49zM163.53 368c16.71-22.03 34.48-55.8 41.4-110.58l-45.47-35.55c-3.27 90.73-36.47 120.68-54.84 140.42-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h279.66l-61.4-48H163.53zM320 96c61.86 0 112 50.14 112 112 0 .2-.06.38-.06.58.02 16.84 1.16 31.77 2.79 45.73l59.53 46.54c-8.31-22.13-14.34-51.49-14.34-92.85 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84c-26.02 5.41-49.45 16.94-69.13 32.72l38.17 29.84C275 103.18 296.65 96 320 96zm0 416c35.32 0 63.97-28.65 63.97-64H256.03c0 35.35 28.65 64 63.97 64z\"]\n};\nvar faBookmark = {\n prefix: 'far',\n iconName: 'bookmark',\n icon: [384, 512, [], \"f02e\", \"M336 0H48C21.49 0 0 21.49 0 48v464l192-112 192 112V48c0-26.51-21.49-48-48-48zm0 428.43l-144-84-144 84V54a6 6 0 0 1 6-6h276c3.314 0 6 2.683 6 5.996V428.43z\"]\n};\nvar faBuilding = {\n prefix: 'far',\n iconName: 'building',\n icon: [448, 512, [], \"f1ad\", \"M128 148v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12zm140 12h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm-128 96h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm128 0h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm-76 84v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm76 12h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm180 124v36H0v-36c0-6.6 5.4-12 12-12h19.5V24c0-13.3 10.7-24 24-24h337c13.3 0 24 10.7 24 24v440H436c6.6 0 12 5.4 12 12zM79.5 463H192v-67c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v67h112.5V49L80 48l-.5 415z\"]\n};\nvar faCalendar = {\n prefix: 'far',\n iconName: 'calendar',\n icon: [448, 512, [], \"f133\", \"M400 64h-48V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H160V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V160h352v298c0 3.3-2.7 6-6 6z\"]\n};\nvar faCalendarAlt = {\n prefix: 'far',\n iconName: 'calendar-alt',\n icon: [448, 512, [], \"f073\", \"M148 288h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm108-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 96v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96-260v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCalendarCheck = {\n prefix: 'far',\n iconName: 'calendar-check',\n icon: [448, 512, [], \"f274\", \"M400 64h-48V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v52H160V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v52H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 400H54a6 6 0 0 1-6-6V160h352v298a6 6 0 0 1-6 6zm-52.849-200.65L198.842 404.519c-4.705 4.667-12.303 4.637-16.971-.068l-75.091-75.699c-4.667-4.705-4.637-12.303.068-16.971l22.719-22.536c4.705-4.667 12.303-4.637 16.97.069l44.104 44.461 111.072-110.181c4.705-4.667 12.303-4.637 16.971.068l22.536 22.718c4.667 4.705 4.636 12.303-.069 16.97z\"]\n};\nvar faCalendarMinus = {\n prefix: 'far',\n iconName: 'calendar-minus',\n icon: [448, 512, [], \"f272\", \"M124 328c-6.6 0-12-5.4-12-12v-24c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H124zm324-216v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCalendarPlus = {\n prefix: 'far',\n iconName: 'calendar-plus',\n icon: [448, 512, [], \"f271\", \"M336 292v24c0 6.6-5.4 12-12 12h-76v76c0 6.6-5.4 12-12 12h-24c-6.6 0-12-5.4-12-12v-76h-76c-6.6 0-12-5.4-12-12v-24c0-6.6 5.4-12 12-12h76v-76c0-6.6 5.4-12 12-12h24c6.6 0 12 5.4 12 12v76h76c6.6 0 12 5.4 12 12zm112-180v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCalendarTimes = {\n prefix: 'far',\n iconName: 'calendar-times',\n icon: [448, 512, [], \"f273\", \"M311.7 374.7l-17 17c-4.7 4.7-12.3 4.7-17 0L224 337.9l-53.7 53.7c-4.7 4.7-12.3 4.7-17 0l-17-17c-4.7-4.7-4.7-12.3 0-17l53.7-53.7-53.7-53.7c-4.7-4.7-4.7-12.3 0-17l17-17c4.7-4.7 12.3-4.7 17 0l53.7 53.7 53.7-53.7c4.7-4.7 12.3-4.7 17 0l17 17c4.7 4.7 4.7 12.3 0 17L257.9 304l53.7 53.7c4.8 4.7 4.8 12.3.1 17zM448 112v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCaretSquareDown = {\n prefix: 'far',\n iconName: 'caret-square-down',\n icon: [448, 512, [], \"f150\", \"M125.1 208h197.8c10.7 0 16.1 13 8.5 20.5l-98.9 98.3c-4.7 4.7-12.2 4.7-16.9 0l-98.9-98.3c-7.7-7.5-2.3-20.5 8.4-20.5zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCaretSquareLeft = {\n prefix: 'far',\n iconName: 'caret-square-left',\n icon: [448, 512, [], \"f191\", \"M272 157.1v197.8c0 10.7-13 16.1-20.5 8.5l-98.3-98.9c-4.7-4.7-4.7-12.2 0-16.9l98.3-98.9c7.5-7.7 20.5-2.3 20.5 8.4zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCaretSquareRight = {\n prefix: 'far',\n iconName: 'caret-square-right',\n icon: [448, 512, [], \"f152\", \"M176 354.9V157.1c0-10.7 13-16.1 20.5-8.5l98.3 98.9c4.7 4.7 4.7 12.2 0 16.9l-98.3 98.9c-7.5 7.7-20.5 2.3-20.5-8.4zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faCaretSquareUp = {\n prefix: 'far',\n iconName: 'caret-square-up',\n icon: [448, 512, [], \"f151\", \"M322.9 304H125.1c-10.7 0-16.1-13-8.5-20.5l98.9-98.3c4.7-4.7 12.2-4.7 16.9 0l98.9 98.3c7.7 7.5 2.3 20.5-8.4 20.5zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faChartBar = {\n prefix: 'far',\n iconName: 'chart-bar',\n icon: [512, 512, [], \"f080\", \"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\"]\n};\nvar faCheckCircle = {\n prefix: 'far',\n iconName: 'check-circle',\n icon: [512, 512, [], \"f058\", \"M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 48c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m140.204 130.267l-22.536-22.718c-4.667-4.705-12.265-4.736-16.97-.068L215.346 303.697l-59.792-60.277c-4.667-4.705-12.265-4.736-16.97-.069l-22.719 22.536c-4.705 4.667-4.736 12.265-.068 16.971l90.781 91.516c4.667 4.705 12.265 4.736 16.97.068l172.589-171.204c4.704-4.668 4.734-12.266.067-16.971z\"]\n};\nvar faCheckSquare = {\n prefix: 'far',\n iconName: 'check-square',\n icon: [448, 512, [], \"f14a\", \"M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zm0 400H48V80h352v352zm-35.864-241.724L191.547 361.48c-4.705 4.667-12.303 4.637-16.97-.068l-90.781-91.516c-4.667-4.705-4.637-12.303.069-16.971l22.719-22.536c4.705-4.667 12.303-4.637 16.97.069l59.792 60.277 141.352-140.216c4.705-4.667 12.303-4.637 16.97.068l22.536 22.718c4.667 4.706 4.637 12.304-.068 16.971z\"]\n};\nvar faCircle = {\n prefix: 'far',\n iconName: 'circle',\n icon: [512, 512, [], \"f111\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200z\"]\n};\nvar faClipboard = {\n prefix: 'far',\n iconName: 'clipboard',\n icon: [384, 512, [], \"f328\", \"M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 40c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm144 418c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V118c0-3.3 2.7-6 6-6h42v36c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-36h42c3.3 0 6 2.7 6 6z\"]\n};\nvar faClock = {\n prefix: 'far',\n iconName: 'clock',\n icon: [512, 512, [], \"f017\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z\"]\n};\nvar faClone = {\n prefix: 'far',\n iconName: 'clone',\n icon: [512, 512, [], \"f24d\", \"M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z\"]\n};\nvar faClosedCaptioning = {\n prefix: 'far',\n iconName: 'closed-captioning',\n icon: [512, 512, [], \"f20a\", \"M464 64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm-6 336H54c-3.3 0-6-2.7-6-6V118c0-3.3 2.7-6 6-6h404c3.3 0 6 2.7 6 6v276c0 3.3-2.7 6-6 6zm-211.1-85.7c1.7 2.4 1.5 5.6-.5 7.7-53.6 56.8-172.8 32.1-172.8-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7l-17.5 30.5c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2 0 48 51 70.5 92.2 32.6 2.8-2.5 7.1-2.1 9.2.9l19.6 27.7zm190.4 0c1.7 2.4 1.5 5.6-.5 7.7-53.6 56.9-172.8 32.1-172.8-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7L420 220.2c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2 0 48 51 70.5 92.2 32.6 2.8-2.5 7.1-2.1 9.2.9l19.6 27.7z\"]\n};\nvar faComment = {\n prefix: 'far',\n iconName: 'comment',\n icon: [512, 512, [], \"f075\", \"M256 32C114.6 32 0 125.1 0 240c0 47.6 19.9 91.2 52.9 126.3C38 405.7 7 439.1 6.5 439.5c-6.6 7-8.4 17.2-4.6 26S14.4 480 24 480c61.5 0 110-25.7 139.1-46.3C192 442.8 223.2 448 256 448c141.4 0 256-93.1 256-208S397.4 32 256 32zm0 368c-26.7 0-53.1-4.1-78.4-12.1l-22.7-7.2-19.5 13.8c-14.3 10.1-33.9 21.4-57.5 29 7.3-12.1 14.4-25.7 19.9-40.2l10.6-28.1-20.6-21.8C69.7 314.1 48 282.2 48 240c0-88.2 93.3-160 208-160s208 71.8 208 160-93.3 160-208 160z\"]\n};\nvar faCommentAlt = {\n prefix: 'far',\n iconName: 'comment-alt',\n icon: [512, 512, [], \"f27a\", \"M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm16 352c0 8.8-7.2 16-16 16H288l-12.8 9.6L208 428v-60H64c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h384c8.8 0 16 7.2 16 16v288z\"]\n};\nvar faCommentDots = {\n prefix: 'far',\n iconName: 'comment-dots',\n icon: [512, 512, [], \"f4ad\", \"M144 208c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm112 0c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm112 0c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zM256 32C114.6 32 0 125.1 0 240c0 47.6 19.9 91.2 52.9 126.3C38 405.7 7 439.1 6.5 439.5c-6.6 7-8.4 17.2-4.6 26S14.4 480 24 480c61.5 0 110-25.7 139.1-46.3C192 442.8 223.2 448 256 448c141.4 0 256-93.1 256-208S397.4 32 256 32zm0 368c-26.7 0-53.1-4.1-78.4-12.1l-22.7-7.2-19.5 13.8c-14.3 10.1-33.9 21.4-57.5 29 7.3-12.1 14.4-25.7 19.9-40.2l10.6-28.1-20.6-21.8C69.7 314.1 48 282.2 48 240c0-88.2 93.3-160 208-160s208 71.8 208 160-93.3 160-208 160z\"]\n};\nvar faComments = {\n prefix: 'far',\n iconName: 'comments',\n icon: [576, 512, [], \"f086\", \"M532 386.2c27.5-27.1 44-61.1 44-98.2 0-80-76.5-146.1-176.2-157.9C368.3 72.5 294.3 32 208 32 93.1 32 0 103.6 0 192c0 37 16.5 71 44 98.2-15.3 30.7-37.3 54.5-37.7 54.9-6.3 6.7-8.1 16.5-4.4 25 3.6 8.5 12 14 21.2 14 53.5 0 96.7-20.2 125.2-38.8 9.2 2.1 18.7 3.7 28.4 4.9C208.1 407.6 281.8 448 368 448c20.8 0 40.8-2.4 59.8-6.8C456.3 459.7 499.4 480 553 480c9.2 0 17.5-5.5 21.2-14 3.6-8.5 1.9-18.3-4.4-25-.4-.3-22.5-24.1-37.8-54.8zm-392.8-92.3L122.1 305c-14.1 9.1-28.5 16.3-43.1 21.4 2.7-4.7 5.4-9.7 8-14.8l15.5-31.1L77.7 256C64.2 242.6 48 220.7 48 192c0-60.7 73.3-112 160-112s160 51.3 160 112-73.3 112-160 112c-16.5 0-33-1.9-49-5.6l-19.8-4.5zM498.3 352l-24.7 24.4 15.5 31.1c2.6 5.1 5.3 10.1 8 14.8-14.6-5.1-29-12.3-43.1-21.4l-17.1-11.1-19.9 4.6c-16 3.7-32.5 5.6-49 5.6-54 0-102.2-20.1-131.3-49.7C338 339.5 416 272.9 416 192c0-3.4-.4-6.7-.7-10C479.7 196.5 528 238.8 528 288c0 28.7-16.2 50.6-29.7 64z\"]\n};\nvar faCompass = {\n prefix: 'far',\n iconName: 'compass',\n icon: [496, 512, [], \"f14e\", \"M347.94 129.86L203.6 195.83a31.938 31.938 0 0 0-15.77 15.77l-65.97 144.34c-7.61 16.65 9.54 33.81 26.2 26.2l144.34-65.97a31.938 31.938 0 0 0 15.77-15.77l65.97-144.34c7.61-16.66-9.54-33.81-26.2-26.2zm-77.36 148.72c-12.47 12.47-32.69 12.47-45.16 0-12.47-12.47-12.47-32.69 0-45.16 12.47-12.47 32.69-12.47 45.16 0 12.47 12.47 12.47 32.69 0 45.16zM248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm0 448c-110.28 0-200-89.72-200-200S137.72 56 248 56s200 89.72 200 200-89.72 200-200 200z\"]\n};\nvar faCopy = {\n prefix: 'far',\n iconName: 'copy',\n icon: [448, 512, [], \"f0c5\", \"M433.941 65.941l-51.882-51.882A48 48 0 0 0 348.118 0H176c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48v-48h80c26.51 0 48-21.49 48-48V99.882a48 48 0 0 0-14.059-33.941zM266 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h74v224c0 26.51 21.49 48 48 48h96v42a6 6 0 0 1-6 6zm128-96H182a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h106v88c0 13.255 10.745 24 24 24h88v202a6 6 0 0 1-6 6zm6-256h-64V48h9.632c1.591 0 3.117.632 4.243 1.757l48.368 48.368a6 6 0 0 1 1.757 4.243V112z\"]\n};\nvar faCopyright = {\n prefix: 'far',\n iconName: 'copyright',\n icon: [512, 512, [], \"f1f9\", \"M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 448c-110.532 0-200-89.451-200-200 0-110.531 89.451-200 200-200 110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200zm107.351-101.064c-9.614 9.712-45.53 41.396-104.065 41.396-82.43 0-140.484-61.425-140.484-141.567 0-79.152 60.275-139.401 139.762-139.401 55.531 0 88.738 26.62 97.593 34.779a11.965 11.965 0 0 1 1.936 15.322l-18.155 28.113c-3.841 5.95-11.966 7.282-17.499 2.921-8.595-6.776-31.814-22.538-61.708-22.538-48.303 0-77.916 35.33-77.916 80.082 0 41.589 26.888 83.692 78.277 83.692 32.657 0 56.843-19.039 65.726-27.225 5.27-4.857 13.596-4.039 17.82 1.738l19.865 27.17a11.947 11.947 0 0 1-1.152 15.518z\"]\n};\nvar faCreditCard = {\n prefix: 'far',\n iconName: 'credit-card',\n icon: [576, 512, [], \"f09d\", \"M527.9 32H48.1C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48.1 48h479.8c26.6 0 48.1-21.5 48.1-48V80c0-26.5-21.5-48-48.1-48zM54.1 80h467.8c3.3 0 6 2.7 6 6v42H48.1V86c0-3.3 2.7-6 6-6zm467.8 352H54.1c-3.3 0-6-2.7-6-6V256h479.8v170c0 3.3-2.7 6-6 6zM192 332v40c0 6.6-5.4 12-12 12h-72c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h72c6.6 0 12 5.4 12 12zm192 0v40c0 6.6-5.4 12-12 12H236c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h136c6.6 0 12 5.4 12 12z\"]\n};\nvar faDizzy = {\n prefix: 'far',\n iconName: 'dizzy',\n icon: [496, 512, [], \"f567\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-33.8-217.9c7.8-7.8 7.8-20.5 0-28.3L196.3 192l17.9-17.9c7.8-7.8 7.8-20.5 0-28.3-7.8-7.8-20.5-7.8-28.3 0L168 163.7l-17.8-17.8c-7.8-7.8-20.5-7.8-28.3 0-7.8 7.8-7.8 20.5 0 28.3l17.9 17.9-17.9 17.9c-7.8 7.8-7.8 20.5 0 28.3 7.8 7.8 20.5 7.8 28.3 0l17.8-17.8 17.8 17.8c7.9 7.7 20.5 7.7 28.4-.2zm160-92.2c-7.8-7.8-20.5-7.8-28.3 0L328 163.7l-17.8-17.8c-7.8-7.8-20.5-7.8-28.3 0-7.8 7.8-7.8 20.5 0 28.3l17.9 17.9-17.9 17.9c-7.8 7.8-7.8 20.5 0 28.3 7.8 7.8 20.5 7.8 28.3 0l17.8-17.8 17.8 17.8c7.8 7.8 20.5 7.8 28.3 0 7.8-7.8 7.8-20.5 0-28.3l-17.8-18 17.9-17.9c7.7-7.8 7.7-20.4 0-28.2zM248 272c-35.3 0-64 28.7-64 64s28.7 64 64 64 64-28.7 64-64-28.7-64-64-64z\"]\n};\nvar faDotCircle = {\n prefix: 'far',\n iconName: 'dot-circle',\n icon: [512, 512, [], \"f192\", \"M256 56c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m0-48C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 168c-44.183 0-80 35.817-80 80s35.817 80 80 80 80-35.817 80-80-35.817-80-80-80z\"]\n};\nvar faEdit = {\n prefix: 'far',\n iconName: 'edit',\n icon: [576, 512, [], \"f044\", \"M402.3 344.9l32-32c5-5 13.7-1.5 13.7 5.7V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h273.5c7.1 0 10.7 8.6 5.7 13.7l-32 32c-1.5 1.5-3.5 2.3-5.7 2.3H48v352h352V350.5c0-2.1.8-4.1 2.3-5.6zm156.6-201.8L296.3 405.7l-90.4 10c-26.2 2.9-48.5-19.2-45.6-45.6l10-90.4L432.9 17.1c22.9-22.9 59.9-22.9 82.7 0l43.2 43.2c22.9 22.9 22.9 60 .1 82.8zM460.1 174L402 115.9 216.2 301.8l-7.3 65.3 65.3-7.3L460.1 174zm64.8-79.7l-43.2-43.2c-4.1-4.1-10.8-4.1-14.8 0L436 82l58.1 58.1 30.9-30.9c4-4.2 4-10.8-.1-14.9z\"]\n};\nvar faEnvelope = {\n prefix: 'far',\n iconName: 'envelope',\n icon: [512, 512, [], \"f0e0\", \"M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm0 48v40.805c-22.422 18.259-58.168 46.651-134.587 106.49-16.841 13.247-50.201 45.072-73.413 44.701-23.208.375-56.579-31.459-73.413-44.701C106.18 199.465 70.425 171.067 48 152.805V112h416zM48 400V214.398c22.914 18.251 55.409 43.862 104.938 82.646 21.857 17.205 60.134 55.186 103.062 54.955 42.717.231 80.509-37.199 103.053-54.947 49.528-38.783 82.032-64.401 104.947-82.653V400H48z\"]\n};\nvar faEnvelopeOpen = {\n prefix: 'far',\n iconName: 'envelope-open',\n icon: [512, 512, [], \"f2b6\", \"M494.586 164.516c-4.697-3.883-111.723-89.95-135.251-108.657C337.231 38.191 299.437 0 256 0c-43.205 0-80.636 37.717-103.335 55.859-24.463 19.45-131.07 105.195-135.15 108.549A48.004 48.004 0 0 0 0 201.485V464c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V201.509a48 48 0 0 0-17.414-36.993zM464 458a6 6 0 0 1-6 6H54a6 6 0 0 1-6-6V204.347c0-1.813.816-3.526 2.226-4.665 15.87-12.814 108.793-87.554 132.364-106.293C200.755 78.88 232.398 48 256 48c23.693 0 55.857 31.369 73.41 45.389 23.573 18.741 116.503 93.493 132.366 106.316a5.99 5.99 0 0 1 2.224 4.663V458zm-31.991-187.704c4.249 5.159 3.465 12.795-1.745 16.981-28.975 23.283-59.274 47.597-70.929 56.863C336.636 362.283 299.205 400 256 400c-43.452 0-81.287-38.237-103.335-55.86-11.279-8.967-41.744-33.413-70.927-56.865-5.21-4.187-5.993-11.822-1.745-16.981l15.258-18.528c4.178-5.073 11.657-5.843 16.779-1.726 28.618 23.001 58.566 47.035 70.56 56.571C200.143 320.631 232.307 352 256 352c23.602 0 55.246-30.88 73.41-45.389 11.994-9.535 41.944-33.57 70.563-56.568 5.122-4.116 12.601-3.346 16.778 1.727l15.258 18.526z\"]\n};\nvar faEye = {\n prefix: 'far',\n iconName: 'eye',\n icon: [576, 512, [], \"f06e\", \"M288 144a110.94 110.94 0 0 0-31.24 5 55.4 55.4 0 0 1 7.24 27 56 56 0 0 1-56 56 55.4 55.4 0 0 1-27-7.24A111.71 111.71 0 1 0 288 144zm284.52 97.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400c-98.65 0-189.09-55-237.93-144C98.91 167 189.34 112 288 112s189.09 55 237.93 144C477.1 345 386.66 400 288 400z\"]\n};\nvar faEyeSlash = {\n prefix: 'far',\n iconName: 'eye-slash',\n icon: [640, 512, [], \"f070\", \"M634 471L36 3.51A16 16 0 0 0 13.51 6l-10 12.49A16 16 0 0 0 6 41l598 467.49a16 16 0 0 0 22.49-2.49l10-12.49A16 16 0 0 0 634 471zM296.79 146.47l134.79 105.38C429.36 191.91 380.48 144 320 144a112.26 112.26 0 0 0-23.21 2.47zm46.42 219.07L208.42 260.16C210.65 320.09 259.53 368 320 368a113 113 0 0 0 23.21-2.46zM320 112c98.65 0 189.09 55 237.93 144a285.53 285.53 0 0 1-44 60.2l37.74 29.5a333.7 333.7 0 0 0 52.9-75.11 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64c-36.7 0-71.71 7-104.63 18.81l46.41 36.29c18.94-4.3 38.34-7.1 58.22-7.1zm0 288c-98.65 0-189.08-55-237.93-144a285.47 285.47 0 0 1 44.05-60.19l-37.74-29.5a333.6 333.6 0 0 0-52.89 75.1 32.35 32.35 0 0 0 0 29.19C89.72 376.41 197.08 448 320 448c36.7 0 71.71-7.05 104.63-18.81l-46.41-36.28C359.28 397.2 339.89 400 320 400z\"]\n};\nvar faFile = {\n prefix: 'far',\n iconName: 'file',\n icon: [384, 512, [], \"f15b\", \"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48z\"]\n};\nvar faFileAlt = {\n prefix: 'far',\n iconName: 'file-alt',\n icon: [384, 512, [], \"f15c\", \"M288 248v28c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-28c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm-12 72H108c-6.6 0-12 5.4-12 12v28c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-28c0-6.6-5.4-12-12-12zm108-188.1V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V48C0 21.5 21.5 0 48 0h204.1C264.8 0 277 5.1 286 14.1L369.9 98c9 8.9 14.1 21.2 14.1 33.9zm-128-80V128h76.1L256 51.9zM336 464V176H232c-13.3 0-24-10.7-24-24V48H48v416h288z\"]\n};\nvar faFileArchive = {\n prefix: 'far',\n iconName: 'file-archive',\n icon: [384, 512, [], \"f1c6\", \"M128.3 160v32h32v-32zm64-96h-32v32h32zm-64 32v32h32V96zm64 32h-32v32h32zm177.6-30.1L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM256 51.9l76.1 76.1H256zM336 464H48V48h79.7v16h32V48H208v104c0 13.3 10.7 24 24 24h104zM194.2 265.7c-1.1-5.6-6-9.7-11.8-9.7h-22.1v-32h-32v32l-19.7 97.1C102 385.6 126.8 416 160 416c33.1 0 57.9-30.2 51.5-62.6zm-33.9 124.4c-17.9 0-32.4-12.1-32.4-27s14.5-27 32.4-27 32.4 12.1 32.4 27-14.5 27-32.4 27zm32-198.1h-32v32h32z\"]\n};\nvar faFileAudio = {\n prefix: 'far',\n iconName: 'file-audio',\n icon: [384, 512, [], \"f1c7\", \"M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM332.118 128H256V51.882L332.118 128zM48 464V48h160v104c0 13.255 10.745 24 24 24h104v288H48zm144-76.024c0 10.691-12.926 16.045-20.485 8.485L136 360.486h-28c-6.627 0-12-5.373-12-12v-56c0-6.627 5.373-12 12-12h28l35.515-36.947c7.56-7.56 20.485-2.206 20.485 8.485v135.952zm41.201-47.13c9.051-9.297 9.06-24.133.001-33.439-22.149-22.752 12.235-56.246 34.395-33.481 27.198 27.94 27.212 72.444.001 100.401-21.793 22.386-56.947-10.315-34.397-33.481z\"]\n};\nvar faFileCode = {\n prefix: 'far',\n iconName: 'file-code',\n icon: [384, 512, [], \"f1c9\", \"M149.9 349.1l-.2-.2-32.8-28.9 32.8-28.9c3.6-3.2 4-8.8.8-12.4l-.2-.2-17.4-18.6c-3.4-3.6-9-3.7-12.4-.4l-57.7 54.1c-3.7 3.5-3.7 9.4 0 12.8l57.7 54.1c1.6 1.5 3.8 2.4 6 2.4 2.4 0 4.8-1 6.4-2.8l17.4-18.6c3.3-3.5 3.1-9.1-.4-12.4zm220-251.2L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM256 51.9l76.1 76.1H256zM336 464H48V48h160v104c0 13.3 10.7 24 24 24h104zM209.6 214c-4.7-1.4-9.5 1.3-10.9 6L144 408.1c-1.4 4.7 1.3 9.6 6 10.9l24.4 7.1c4.7 1.4 9.6-1.4 10.9-6L240 231.9c1.4-4.7-1.3-9.6-6-10.9zm24.5 76.9l.2.2 32.8 28.9-32.8 28.9c-3.6 3.2-4 8.8-.8 12.4l.2.2 17.4 18.6c3.3 3.5 8.9 3.7 12.4.4l57.7-54.1c3.7-3.5 3.7-9.4 0-12.8l-57.7-54.1c-3.5-3.3-9.1-3.2-12.4.4l-17.4 18.6c-3.3 3.5-3.1 9.1.4 12.4z\"]\n};\nvar faFileExcel = {\n prefix: 'far',\n iconName: 'file-excel',\n icon: [384, 512, [], \"f1c3\", \"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm212-240h-28.8c-4.4 0-8.4 2.4-10.5 6.3-18 33.1-22.2 42.4-28.6 57.7-13.9-29.1-6.9-17.3-28.6-57.7-2.1-3.9-6.2-6.3-10.6-6.3H124c-9.3 0-15 10-10.4 18l46.3 78-46.3 78c-4.7 8 1.1 18 10.4 18h28.9c4.4 0 8.4-2.4 10.5-6.3 21.7-40 23-45 28.6-57.7 14.9 30.2 5.9 15.9 28.6 57.7 2.1 3.9 6.2 6.3 10.6 6.3H260c9.3 0 15-10 10.4-18L224 320c.7-1.1 30.3-50.5 46.3-78 4.7-8-1.1-18-10.3-18z\"]\n};\nvar faFileImage = {\n prefix: 'far',\n iconName: 'file-image',\n icon: [384, 512, [], \"f1c5\", \"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm32-48h224V288l-23.5-23.5c-4.7-4.7-12.3-4.7-17 0L176 352l-39.5-39.5c-4.7-4.7-12.3-4.7-17 0L80 352v64zm48-240c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z\"]\n};\nvar faFilePdf = {\n prefix: 'far',\n iconName: 'file-pdf',\n icon: [384, 512, [], \"f1c1\", \"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm250.2-143.7c-12.2-12-47-8.7-64.4-6.5-17.2-10.5-28.7-25-36.8-46.3 3.9-16.1 10.1-40.6 5.4-56-4.2-26.2-37.8-23.6-42.6-5.9-4.4 16.1-.4 38.5 7 67.1-10 23.9-24.9 56-35.4 74.4-20 10.3-47 26.2-51 46.2-3.3 15.8 26 55.2 76.1-31.2 22.4-7.4 46.8-16.5 68.4-20.1 18.9 10.2 41 17 55.8 17 25.5 0 28-28.2 17.5-38.7zm-198.1 77.8c5.1-13.7 24.5-29.5 30.4-35-19 30.3-30.4 35.7-30.4 35zm81.6-190.6c7.4 0 6.7 32.1 1.8 40.8-4.4-13.9-4.3-40.8-1.8-40.8zm-24.4 136.6c9.7-16.9 18-37 24.7-54.7 8.3 15.1 18.9 27.2 30.1 35.5-20.8 4.3-38.9 13.1-54.8 19.2zm131.6-5s-5 6-37.3-7.8c35.1-2.6 40.9 5.4 37.3 7.8z\"]\n};\nvar faFilePowerpoint = {\n prefix: 'far',\n iconName: 'file-powerpoint',\n icon: [384, 512, [], \"f1c4\", \"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm72-60V236c0-6.6 5.4-12 12-12h69.2c36.7 0 62.8 27 62.8 66.3 0 74.3-68.7 66.5-95.5 66.5V404c0 6.6-5.4 12-12 12H132c-6.6 0-12-5.4-12-12zm48.5-87.4h23c7.9 0 13.9-2.4 18.1-7.2 8.5-9.8 8.4-28.5.1-37.8-4.1-4.6-9.9-7-17.4-7h-23.9v52z\"]\n};\nvar faFileVideo = {\n prefix: 'far',\n iconName: 'file-video',\n icon: [384, 512, [], \"f1c8\", \"M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM332.118 128H256V51.882L332.118 128zM48 464V48h160v104c0 13.255 10.745 24 24 24h104v288H48zm228.687-211.303L224 305.374V268c0-11.046-8.954-20-20-20H100c-11.046 0-20 8.954-20 20v104c0 11.046 8.954 20 20 20h104c11.046 0 20-8.954 20-20v-37.374l52.687 52.674C286.704 397.318 304 390.28 304 375.986V264.011c0-14.311-17.309-21.319-27.313-11.314z\"]\n};\nvar faFileWord = {\n prefix: 'far',\n iconName: 'file-word',\n icon: [384, 512, [], \"f1c2\", \"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm220.1-208c-5.7 0-10.6 4-11.7 9.5-20.6 97.7-20.4 95.4-21 103.5-.2-1.2-.4-2.6-.7-4.3-.8-5.1.3.2-23.6-99.5-1.3-5.4-6.1-9.2-11.7-9.2h-13.3c-5.5 0-10.3 3.8-11.7 9.1-24.4 99-24 96.2-24.8 103.7-.1-1.1-.2-2.5-.5-4.2-.7-5.2-14.1-73.3-19.1-99-1.1-5.6-6-9.7-11.8-9.7h-16.8c-7.8 0-13.5 7.3-11.7 14.8 8 32.6 26.7 109.5 33.2 136 1.3 5.4 6.1 9.1 11.7 9.1h25.2c5.5 0 10.3-3.7 11.6-9.1l17.9-71.4c1.5-6.2 2.5-12 3-17.3l2.9 17.3c.1.4 12.6 50.5 17.9 71.4 1.3 5.3 6.1 9.1 11.6 9.1h24.7c5.5 0 10.3-3.7 11.6-9.1 20.8-81.9 30.2-119 34.5-136 1.9-7.6-3.8-14.9-11.6-14.9h-15.8z\"]\n};\nvar faFlag = {\n prefix: 'far',\n iconName: 'flag',\n icon: [512, 512, [], \"f024\", \"M336.174 80c-49.132 0-93.305-32-161.913-32-31.301 0-58.303 6.482-80.721 15.168a48.04 48.04 0 0 0 2.142-20.727C93.067 19.575 74.167 1.594 51.201.104 23.242-1.71 0 20.431 0 48c0 17.764 9.657 33.262 24 41.562V496c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-83.443C109.869 395.28 143.259 384 199.826 384c49.132 0 93.305 32 161.913 32 58.479 0 101.972-22.617 128.548-39.981C503.846 367.161 512 352.051 512 335.855V95.937c0-34.459-35.264-57.768-66.904-44.117C409.193 67.309 371.641 80 336.174 80zM464 336c-21.783 15.412-60.824 32-102.261 32-59.945 0-102.002-32-161.913-32-43.361 0-96.379 9.403-127.826 24V128c21.784-15.412 60.824-32 102.261-32 59.945 0 102.002 32 161.913 32 43.271 0 96.32-17.366 127.826-32v240z\"]\n};\nvar faFlushed = {\n prefix: 'far',\n iconName: 'flushed',\n icon: [496, 512, [], \"f579\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm96-312c-44.2 0-80 35.8-80 80s35.8 80 80 80 80-35.8 80-80-35.8-80-80-80zm0 128c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm0-72c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm-112 24c0-44.2-35.8-80-80-80s-80 35.8-80 80 35.8 80 80 80 80-35.8 80-80zm-80 48c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm0-72c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm160 144H184c-13.2 0-24 10.8-24 24s10.8 24 24 24h128c13.2 0 24-10.8 24-24s-10.8-24-24-24z\"]\n};\nvar faFolder = {\n prefix: 'far',\n iconName: 'folder',\n icon: [512, 512, [], \"f07b\", \"M464 128H272l-54.63-54.63c-6-6-14.14-9.37-22.63-9.37H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48zm0 272H48V112h140.12l54.63 54.63c6 6 14.14 9.37 22.63 9.37H464v224z\"]\n};\nvar faFolderOpen = {\n prefix: 'far',\n iconName: 'folder-open',\n icon: [576, 512, [], \"f07c\", \"M527.9 224H480v-48c0-26.5-21.5-48-48-48H272l-64-64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h400c16.5 0 31.9-8.5 40.7-22.6l79.9-128c20-31.9-3-73.4-40.7-73.4zM48 118c0-3.3 2.7-6 6-6h134.1l64 64H426c3.3 0 6 2.7 6 6v42H152c-16.8 0-32.4 8.8-41.1 23.2L48 351.4zm400 282H72l77.2-128H528z\"]\n};\nvar faFontAwesomeLogoFull = {\n prefix: 'far',\n iconName: 'font-awesome-logo-full',\n icon: [3992, 512, [\"Font Awesome\"], \"f4e6\", \"M454.6 0H57.4C25.9 0 0 25.9 0 57.4v397.3C0 486.1 25.9 512 57.4 512h397.3c31.4 0 57.4-25.9 57.4-57.4V57.4C512 25.9 486.1 0 454.6 0zm-58.9 324.9c0 4.8-4.1 6.9-8.9 8.9-19.2 8.1-39.7 15.7-61.5 15.7-40.5 0-68.7-44.8-163.2 2.5v51.8c0 30.3-45.7 30.2-45.7 0v-250c-9-7-15-17.9-15-30.3 0-21 17.1-38.2 38.2-38.2 21 0 38.2 17.1 38.2 38.2 0 12.2-5.8 23.2-14.9 30.2v21c37.1-12 65.5-34.4 146.1-3.4 26.6 11.4 68.7-15.7 76.5-15.7 5.5 0 10.3 4.1 10.3 8.9v160.4zm432.9-174.2h-137v70.1H825c39.8 0 40.4 62.2 0 62.2H691.6v105.6c0 45.5-70.7 46.4-70.7 0V128.3c0-22 18-39.8 39.8-39.8h167.8c39.6 0 40.5 62.2.1 62.2zm191.1 23.4c-169.3 0-169.1 252.4 0 252.4 169.9 0 169.9-252.4 0-252.4zm0 196.1c-81.6 0-82.1-139.8 0-139.8 82.5 0 82.4 139.8 0 139.8zm372.4 53.4c-17.5 0-31.4-13.9-31.4-31.4v-117c0-62.4-72.6-52.5-99.1-16.4v133.4c0 41.5-63.3 41.8-63.3 0V208c0-40 63.1-41.6 63.1 0v3.4c43.3-51.6 162.4-60.4 162.4 39.3v141.5c.3 30.4-31.5 31.4-31.7 31.4zm179.7 2.9c-44.3 0-68.3-22.9-68.3-65.8V235.2H1488c-35.6 0-36.7-55.3 0-55.3h15.5v-37.3c0-41.3 63.8-42.1 63.8 0v37.5h24.9c35.4 0 35.7 55.3 0 55.3h-24.9v108.5c0 29.6 26.1 26.3 27.4 26.3 31.4 0 52.6 56.3-22.9 56.3zM1992 123c-19.5-50.2-95.5-50-114.5 0-107.3 275.7-99.5 252.7-99.5 262.8 0 42.8 58.3 51.2 72.1 14.4l13.5-35.9H2006l13 35.9c14.2 37.7 72.1 27.2 72.1-14.4 0-10.1 5.3 6.8-99.1-262.8zm-108.9 179.1l51.7-142.9 51.8 142.9h-103.5zm591.3-85.6l-53.7 176.3c-12.4 41.2-72 41-84 0l-42.3-135.9-42.3 135.9c-12.4 40.9-72 41.2-84.5 0l-54.2-176.3c-12.5-39.4 49.8-56.1 60.2-16.9L2213 342l45.3-139.5c10.9-32.7 59.6-34.7 71.2 0l45.3 139.5 39.3-142.4c10.3-38.3 72.6-23.8 60.3 16.9zm275.4 75.1c0-42.4-33.9-117.5-119.5-117.5-73.2 0-124.4 56.3-124.4 126 0 77.2 55.3 126.4 128.5 126.4 31.7 0 93-11.5 93-39.8 0-18.3-21.1-31.5-39.3-22.4-49.4 26.2-109 8.4-115.9-43.8h148.3c16.3 0 29.3-13.4 29.3-28.9zM2571 277.7c9.5-73.4 113.9-68.6 118.6 0H2571zm316.7 148.8c-31.4 0-81.6-10.5-96.6-31.9-12.4-17 2.5-39.8 21.8-39.8 16.3 0 36.8 22.9 77.7 22.9 27.4 0 40.4-11 40.4-25.8 0-39.8-142.9-7.4-142.9-102 0-40.4 35.3-75.7 98.6-75.7 31.4 0 74.1 9.9 87.6 29.4 10.8 14.8-1.4 36.2-20.9 36.2-15.1 0-26.7-17.3-66.2-17.3-22.9 0-37.8 10.5-37.8 23.8 0 35.9 142.4 6 142.4 103.1-.1 43.7-37.4 77.1-104.1 77.1zm266.8-252.4c-169.3 0-169.1 252.4 0 252.4 170.1 0 169.6-252.4 0-252.4zm0 196.1c-81.8 0-82-139.8 0-139.8 82.5 0 82.4 139.8 0 139.8zm476.9 22V268.7c0-53.8-61.4-45.8-85.7-10.5v134c0 41.3-63.8 42.1-63.8 0V268.7c0-52.1-59.5-47.4-85.7-10.1v133.6c0 41.5-63.3 41.8-63.3 0V208c0-40 63.1-41.6 63.1 0v3.4c9.9-14.4 41.8-37.3 78.6-37.3 35.3 0 57.7 16.4 66.7 43.8 13.9-21.8 45.8-43.8 82.6-43.8 44.3 0 70.7 23.4 70.7 72.7v145.3c.5 17.3-13.5 31.4-31.9 31.4 3.5.1-31.3 1.1-31.3-31.3zM3992 291.6c0-42.4-32.4-117.5-117.9-117.5-73.2 0-127.5 56.3-127.5 126 0 77.2 58.3 126.4 131.6 126.4 31.7 0 91.5-11.5 91.5-39.8 0-18.3-21.1-31.5-39.3-22.4-49.4 26.2-110.5 8.4-117.5-43.8h149.8c16.3 0 29.1-13.4 29.3-28.9zm-180.5-13.9c9.7-74.4 115.9-68.3 120.1 0h-120.1z\"]\n};\nvar faFrown = {\n prefix: 'far',\n iconName: 'frown',\n icon: [496, 512, [], \"f119\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm-80 128c-40.2 0-78 17.7-103.8 48.6-8.5 10.2-7.1 25.3 3.1 33.8 10.2 8.4 25.3 7.1 33.8-3.1 16.6-19.9 41-31.4 66.9-31.4s50.3 11.4 66.9 31.4c8.1 9.7 23.1 11.9 33.8 3.1 10.2-8.5 11.5-23.6 3.1-33.8C326 321.7 288.2 304 248 304z\"]\n};\nvar faFrownOpen = {\n prefix: 'far',\n iconName: 'frown-open',\n icon: [496, 512, [], \"f57a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-48-248c0-17.7-14.3-32-32-32s-32 14.3-32 32 14.3 32 32 32 32-14.3 32-32zm128-32c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm-80 112c-35.6 0-88.8 21.3-95.8 61.2-2 11.8 9 21.5 20.5 18.1 31.2-9.6 59.4-15.3 75.3-15.3s44.1 5.7 75.3 15.3c11.4 3.5 22.5-6.3 20.5-18.1-7-39.9-60.2-61.2-95.8-61.2z\"]\n};\nvar faFutbol = {\n prefix: 'far',\n iconName: 'futbol',\n icon: [496, 512, [], \"f1e3\", \"M483.8 179.4C449.8 74.6 352.6 8 248.1 8c-25.4 0-51.2 3.9-76.7 12.2C41.2 62.5-30.1 202.4 12.2 332.6 46.2 437.4 143.4 504 247.9 504c25.4 0 51.2-3.9 76.7-12.2 130.2-42.3 201.5-182.2 159.2-312.4zm-74.5 193.7l-52.2 6.4-43.7-60.9 24.4-75.2 71.1-22.1 38.9 36.4c-.2 30.7-7.4 61.1-21.7 89.2-4.7 9.3-10.7 17.8-16.8 26.2zm0-235.4l-10.4 53.1-70.7 22-64.2-46.5V92.5l47.4-26.2c39.2 13 73.4 38 97.9 71.4zM184.9 66.4L232 92.5v73.8l-64.2 46.5-70.6-22-10.1-52.5c24.3-33.4 57.9-58.6 97.8-71.9zM139 379.5L85.9 373c-14.4-20.1-37.3-59.6-37.8-115.3l39-36.4 71.1 22.2 24.3 74.3-43.5 61.7zm48.2 67l-22.4-48.1 43.6-61.7H287l44.3 61.7-22.4 48.1c-6.2 1.8-57.6 20.4-121.7 0z\"]\n};\nvar faGem = {\n prefix: 'far',\n iconName: 'gem',\n icon: [576, 512, [], \"f3a5\", \"M464 0H112c-4 0-7.8 2-10 5.4L2 152.6c-2.9 4.4-2.6 10.2.7 14.2l276 340.8c4.8 5.9 13.8 5.9 18.6 0l276-340.8c3.3-4.1 3.6-9.8.7-14.2L474.1 5.4C471.8 2 468.1 0 464 0zm-19.3 48l63.3 96h-68.4l-51.7-96h56.8zm-202.1 0h90.7l51.7 96H191l51.6-96zm-111.3 0h56.8l-51.7 96H68l63.3-96zm-43 144h51.4L208 352 88.3 192zm102.9 0h193.6L288 435.3 191.2 192zM368 352l68.2-160h51.4L368 352z\"]\n};\nvar faGrimace = {\n prefix: 'far',\n iconName: 'grimace',\n icon: [496, 512, [], \"f57f\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm16 16H152c-26.5 0-48 21.5-48 48v32c0 26.5 21.5 48 48 48h192c26.5 0 48-21.5 48-48v-32c0-26.5-21.5-48-48-48zm-168 96h-24c-8.8 0-16-7.2-16-16v-8h40v24zm0-40h-40v-8c0-8.8 7.2-16 16-16h24v24zm64 40h-48v-24h48v24zm0-40h-48v-24h48v24zm64 40h-48v-24h48v24zm0-40h-48v-24h48v24zm56 24c0 8.8-7.2 16-16 16h-24v-24h40v8zm0-24h-40v-24h24c8.8 0 16 7.2 16 16v8z\"]\n};\nvar faGrin = {\n prefix: 'far',\n iconName: 'grin',\n icon: [496, 512, [], \"f580\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm105.6-151.4c-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.9-3.1-19.4 5.4-17.7 15.3 7.9 47.1 71.3 80 123.3 80s115.3-32.9 123.3-80c1.6-9.8-7.7-18.4-17.7-15.3zM168 240c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32z\"]\n};\nvar faGrinAlt = {\n prefix: 'far',\n iconName: 'grin-alt',\n icon: [496, 512, [], \"f581\", \"M200.3 248c12.4-18.7 15.1-37.3 15.7-56-.5-18.7-3.3-37.3-15.7-56-8-12-25.1-11.4-32.7 0-12.4 18.7-15.1 37.3-15.7 56 .5 18.7 3.3 37.3 15.7 56 8.1 12 25.2 11.4 32.7 0zm128 0c12.4-18.7 15.1-37.3 15.7-56-.5-18.7-3.3-37.3-15.7-56-8-12-25.1-11.4-32.7 0-12.4 18.7-15.1 37.3-15.7 56 .5 18.7 3.3 37.3 15.7 56 8.1 12 25.2 11.4 32.7 0zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm105.6-151.4c-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.9-3.1-19.4 5.3-17.7 15.3 7.9 47.2 71.3 80 123.3 80s115.3-32.9 123.3-80c1.6-9.8-7.7-18.4-17.7-15.3z\"]\n};\nvar faGrinBeam = {\n prefix: 'far',\n iconName: 'grin-beam',\n icon: [496, 512, [], \"f582\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm105.6-151.4c-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.8-3.1-19.4 5.3-17.7 15.3 7.9 47.1 71.3 80 123.3 80s115.3-32.9 123.3-80c1.6-9.8-7.7-18.4-17.7-15.3zm-235.9-72.9c3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3zm160 0c3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3z\"]\n};\nvar faGrinBeamSweat = {\n prefix: 'far',\n iconName: 'grin-beam-sweat',\n icon: [496, 512, [], \"f583\", \"M440 160c29.5 0 53.3-26.3 53.3-58.7 0-25-31.7-75.5-46.2-97.3-3.6-5.3-10.7-5.3-14.2 0-14.5 21.8-46.2 72.3-46.2 97.3 0 32.4 23.8 58.7 53.3 58.7zM248 400c51.9 0 115.3-32.9 123.3-80 1.7-9.9-7.7-18.5-17.7-15.3-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.8-3.1-19.4 5.3-17.7 15.3 8 47.1 71.4 80 123.3 80zm130.3-168.3c3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3 3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.6 6.2 4.6 9.3 3.7zm105.3-52.9c-24.6 15.7-46 12.9-46.4 12.9 6.9 20.2 10.8 41.8 10.8 64.3 0 110.3-89.7 200-200 200S48 366.3 48 256 137.7 56 248 56c39.8 0 76.8 11.8 108 31.9 1.7-9.5 6.3-24.1 17.2-45.7C336.4 20.6 293.7 8 248 8 111 8 0 119 0 256s111 248 248 248 248-111 248-248c0-27-4.4-52.9-12.4-77.2zM168 189.4c12.3 0 23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3 3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.8 19.2-21.6 31.5-21.6z\"]\n};\nvar faGrinHearts = {\n prefix: 'far',\n iconName: 'grin-hearts',\n icon: [496, 512, [], \"f584\", \"M353.6 304.6c-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.8-3.1-19.4 5.3-17.7 15.3 7.9 47.2 71.3 80 123.3 80s115.3-32.9 123.3-80c1.6-9.8-7.7-18.4-17.7-15.3zm-152.8-48.9c4.5 1.2 9.2-1.5 10.5-6l19.4-69.9c5.6-20.3-7.4-41.1-28.8-44.5-18.6-3-36.4 9.8-41.5 27.9l-2 7.1-7.1-1.9c-18.2-4.7-38.2 4.3-44.9 22-7.7 20.2 3.8 41.9 24.2 47.2l70.2 18.1zm188.8-65.3c-6.7-17.6-26.7-26.7-44.9-22l-7.1 1.9-2-7.1c-5-18.1-22.8-30.9-41.5-27.9-21.4 3.4-34.4 24.2-28.8 44.5l19.4 69.9c1.2 4.5 5.9 7.2 10.5 6l70.2-18.2c20.4-5.3 31.9-26.9 24.2-47.1zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200z\"]\n};\nvar faGrinSquint = {\n prefix: 'far',\n iconName: 'grin-squint',\n icon: [496, 512, [], \"f585\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm105.6-151.4c-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.9-3.1-19.4 5.4-17.7 15.3 7.9 47.1 71.3 80 123.3 80s115.3-32.9 123.3-80c1.6-9.8-7.7-18.4-17.7-15.3zm-234.7-40.8c3.6 4.2 9.9 5.7 15.3 2.5l80-48c3.6-2.2 5.8-6.1 5.8-10.3s-2.2-8.1-5.8-10.3l-80-48c-5.1-3-11.4-1.9-15.3 2.5-3.8 4.5-3.8 11-.1 15.5l33.6 40.3-33.6 40.3c-3.8 4.5-3.7 11.1.1 15.5zm242.9 2.5c5.4 3.2 11.7 1.7 15.3-2.5 3.8-4.5 3.8-11 .1-15.5L343.6 208l33.6-40.3c3.8-4.5 3.7-11-.1-15.5-3.8-4.4-10.2-5.4-15.3-2.5l-80 48c-3.6 2.2-5.8 6.1-5.8 10.3s2.2 8.1 5.8 10.3l80 48z\"]\n};\nvar faGrinSquintTears = {\n prefix: 'far',\n iconName: 'grin-squint-tears',\n icon: [512, 512, [], \"f586\", \"M117.1 384.1c-25.8 3.7-84 13.7-100.9 30.6-21.9 21.9-21.5 57.9.9 80.3s58.3 22.8 80.3.9C114.3 479 124.3 420.8 128 395c.8-6.4-4.6-11.8-10.9-10.9zm-41.2-41.7C40.3 268 53 176.1 114.6 114.6 152.4 76.8 202.6 56 256 56c36.2 0 70.8 9.8 101.2 27.7 3.8-20.3 8-36.1 12-48.3C333.8 17.2 294.9 8 256 8 192.5 8 129.1 32.2 80.6 80.6c-74.1 74.1-91.3 183.4-52 274 12.2-4.1 27.7-8.3 47.3-12.2zm352.3-187.6c45 76.6 34.9 176.9-30.8 242.6-37.8 37.8-88 58.6-141.4 58.6-30.5 0-59.8-7-86.4-19.8-3.9 19.5-8 35-12.2 47.2 31.4 13.6 65 20.6 98.7 20.6 63.5 0 126.9-24.2 175.4-72.6 78.1-78.1 93.1-195.4 45.2-288.6-12.3 4-28.2 8.1-48.5 12zm-33.3-26.9c25.8-3.7 84-13.7 100.9-30.6 21.9-21.9 21.5-57.9-.9-80.3s-58.3-22.8-80.3-.9C397.7 33 387.7 91.2 384 117c-.8 6.4 4.6 11.8 10.9 10.9zm-187 108.3c-3-3-7.2-4.2-11.4-3.2L106 255.7c-5.7 1.4-9.5 6.7-9.1 12.6.5 5.8 5.1 10.5 10.9 11l52.3 4.8 4.8 52.3c.5 5.8 5.2 10.4 11 10.9h.9c5.5 0 10.3-3.7 11.7-9.1l22.6-90.5c1-4.2-.2-8.5-3.2-11.5zm39.7-25.1l90.5-22.6c5.7-1.4 9.5-6.7 9.1-12.6-.5-5.8-5.1-10.5-10.9-11l-52.3-4.8-4.8-52.3c-.5-5.8-5.2-10.4-11-10.9-5.6-.1-11.2 3.4-12.6 9.1L233 196.5c-1 4.1.2 8.4 3.2 11.4 5 5 11.3 3.2 11.4 3.2zm52 88.5c-29.1 29.1-59.7 52.9-83.9 65.4-9.2 4.8-10 17.5-1.7 23.4 38.9 27.7 107 6.2 143.7-30.6S416 253 388.3 214.1c-5.8-8.2-18.5-7.6-23.4 1.7-12.3 24.2-36.2 54.7-65.3 83.8z\"]\n};\nvar faGrinStars = {\n prefix: 'far',\n iconName: 'grin-stars',\n icon: [496, 512, [], \"f587\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm105.6-151.4c-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.8-3.1-19.4 5.3-17.7 15.3 7.9 47.2 71.3 80 123.3 80s115.3-32.9 123.3-80c1.6-9.8-7.7-18.4-17.7-15.3zm-227.9-57.5c-1 6.2 5.4 11 11 7.9l31.3-16.3 31.3 16.3c5.6 3.1 12-1.7 11-7.9l-6-34.9 25.4-24.6c4.5-4.5 1.9-12.2-4.3-13.2l-34.9-5-15.5-31.6c-2.9-5.8-11-5.8-13.9 0l-15.5 31.6-34.9 5c-6.2.9-8.9 8.6-4.3 13.2l25.4 24.6-6.1 34.9zm259.7-72.7l-34.9-5-15.5-31.6c-2.9-5.8-11-5.8-13.9 0l-15.5 31.6-34.9 5c-6.2.9-8.9 8.6-4.3 13.2l25.4 24.6-6 34.9c-1 6.2 5.4 11 11 7.9l31.3-16.3 31.3 16.3c5.6 3.1 12-1.7 11-7.9l-6-34.9 25.4-24.6c4.5-4.6 1.8-12.2-4.4-13.2z\"]\n};\nvar faGrinTears = {\n prefix: 'far',\n iconName: 'grin-tears',\n icon: [640, 512, [], \"f588\", \"M117.1 256.1c-25.8 3.7-84 13.7-100.9 30.6-21.9 21.9-21.5 57.9.9 80.3s58.3 22.8 80.3.9C114.3 351 124.3 292.8 128 267c.8-6.4-4.6-11.8-10.9-10.9zm506.7 30.6c-16.9-16.9-75.1-26.9-100.9-30.6-6.3-.9-11.7 4.5-10.8 10.8 3.7 25.8 13.7 84 30.6 100.9 21.9 21.9 57.9 21.5 80.3-.9 22.3-22.3 22.7-58.3.8-80.2zm-126.6 61.7C463.8 412.3 396.9 456 320 456c-76.9 0-143.8-43.7-177.2-107.6-12.5 37.4-25.2 43.9-28.3 46.5C159.1 460.7 234.5 504 320 504s160.9-43.3 205.5-109.1c-3.2-2.7-15.9-9.2-28.3-46.5zM122.7 224.5C137.9 129.2 220.5 56 320 56c99.5 0 182.1 73.2 197.3 168.5 2.1-.2 5.2-2.4 49.5 7C554.4 106 448.7 8 320 8S85.6 106 73.2 231.4c44.5-9.4 47.1-7.2 49.5-6.9zM320 400c51.9 0 115.3-32.9 123.3-80 1.7-9.9-7.7-18.5-17.7-15.3-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.8-3.1-19.4 5.3-17.7 15.3 8 47.1 71.4 80 123.3 80zm130.3-168.3c3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3 3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.6 6.2 4.6 9.3 3.7zM240 189.4c12.3 0 23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3 3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.8 19.2-21.6 31.5-21.6z\"]\n};\nvar faGrinTongue = {\n prefix: 'far',\n iconName: 'grin-tongue',\n icon: [496, 512, [], \"f589\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm64 400c0 35.6-29.1 64.5-64.9 64-35.1-.5-63.1-29.8-63.1-65v-42.8l17.7-8.8c15-7.5 31.5 1.7 34.9 16.5l2.8 12.1c2.1 9.2 15.2 9.2 17.3 0l2.8-12.1c3.4-14.8 19.8-24.1 34.9-16.5l17.7 8.8V408zm28.2 25.3c2.2-8.1 3.8-16.5 3.8-25.3v-43.5c14.2-12.4 24.4-27.5 27.3-44.5 1.7-9.9-7.7-18.5-17.7-15.3-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.9-3.1-19.4 5.3-17.7 15.3 2.9 17 13.1 32.1 27.3 44.5V408c0 8.8 1.6 17.2 3.8 25.3C91.8 399.9 48 333 48 256c0-110.3 89.7-200 200-200s200 89.7 200 200c0 77-43.8 143.9-107.8 177.3zM168 176c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm160 0c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z\"]\n};\nvar faGrinTongueSquint = {\n prefix: 'far',\n iconName: 'grin-tongue-squint',\n icon: [496, 512, [], \"f58a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm64 400c0 35.6-29.1 64.5-64.9 64-35.1-.5-63.1-29.8-63.1-65v-42.8l17.7-8.8c15-7.5 31.5 1.7 34.9 16.5l2.8 12.1c2.1 9.2 15.2 9.2 17.3 0l2.8-12.1c3.4-14.8 19.8-24.1 34.9-16.5l17.7 8.8V408zm28.2 25.3c2.2-8.1 3.8-16.5 3.8-25.3v-43.5c14.2-12.4 24.4-27.5 27.3-44.5 1.7-9.9-7.7-18.5-17.7-15.3-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.9-3.1-19.4 5.3-17.7 15.3 2.9 17 13.1 32.1 27.3 44.5V408c0 8.8 1.6 17.2 3.8 25.3C91.8 399.9 48 333 48 256c0-110.3 89.7-200 200-200s200 89.7 200 200c0 77-43.8 143.9-107.8 177.3zm36.9-281.1c-3.8-4.4-10.3-5.5-15.3-2.5l-80 48c-3.6 2.2-5.8 6.1-5.8 10.3s2.2 8.1 5.8 10.3l80 48c5.4 3.2 11.7 1.7 15.3-2.5 3.8-4.5 3.8-11 .1-15.5L343.6 208l33.6-40.3c3.8-4.5 3.7-11.1-.1-15.5zm-162.9 45.5l-80-48c-5-3-11.4-2-15.3 2.5-3.8 4.5-3.8 11-.1 15.5l33.6 40.3-33.6 40.3c-3.8 4.5-3.7 11 .1 15.5 3.6 4.2 9.9 5.7 15.3 2.5l80-48c3.6-2.2 5.8-6.1 5.8-10.3s-2.2-8.1-5.8-10.3z\"]\n};\nvar faGrinTongueWink = {\n prefix: 'far',\n iconName: 'grin-tongue-wink',\n icon: [496, 512, [], \"f58b\", \"M152 180c-25.7 0-55.9 16.9-59.8 42.1-.8 5 1.7 10 6.1 12.4 4.4 2.4 9.9 1.8 13.7-1.6l9.5-8.5c14.8-13.2 46.2-13.2 61 0l9.5 8.5c2.5 2.2 8 4.7 13.7 1.6 4.4-2.4 6.9-7.4 6.1-12.4-3.9-25.2-34.1-42.1-59.8-42.1zm176-52c-44.2 0-80 35.8-80 80s35.8 80 80 80 80-35.8 80-80-35.8-80-80-80zm0 128c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm0-72c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm64 400c0 35.6-29.1 64.5-64.9 64-35.1-.5-63.1-29.8-63.1-65v-42.8l17.7-8.8c15-7.5 31.5 1.7 34.9 16.5l2.8 12.1c2.1 9.2 15.2 9.2 17.3 0l2.8-12.1c3.4-14.8 19.8-24.1 34.9-16.5l17.7 8.8V408zm28.2 25.3c2.2-8.1 3.8-16.5 3.8-25.3v-43.5c14.2-12.4 24.4-27.5 27.3-44.5 1.7-9.9-7.7-18.5-17.7-15.3-25.9 8.3-64.4 13.1-105.6 13.1s-79.6-4.8-105.6-13.1c-9.9-3.1-19.4 5.3-17.7 15.3 2.9 17 13.1 32.1 27.3 44.5V408c0 8.8 1.6 17.2 3.8 25.3C91.8 399.9 48 333 48 256c0-110.3 89.7-200 200-200s200 89.7 200 200c0 77-43.8 143.9-107.8 177.3z\"]\n};\nvar faGrinWink = {\n prefix: 'far',\n iconName: 'grin-wink',\n icon: [496, 512, [], \"f58c\", \"M328 180c-25.69 0-55.88 16.92-59.86 42.12-1.75 11.22 11.5 18.24 19.83 10.84l9.55-8.48c14.81-13.19 46.16-13.19 60.97 0l9.55 8.48c8.48 7.43 21.56.25 19.83-10.84C383.88 196.92 353.69 180 328 180zm-160 60c17.67 0 32-14.33 32-32s-14.33-32-32-32-32 14.33-32 32 14.33 32 32 32zm185.55 64.64c-25.93 8.3-64.4 13.06-105.55 13.06s-79.62-4.75-105.55-13.06c-9.94-3.13-19.4 5.37-17.71 15.34C132.67 367.13 196.06 400 248 400s115.33-32.87 123.26-80.02c1.68-9.89-7.67-18.48-17.71-15.34zM248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm0 448c-110.28 0-200-89.72-200-200S137.72 56 248 56s200 89.72 200 200-89.72 200-200 200z\"]\n};\nvar faHandLizard = {\n prefix: 'far',\n iconName: 'hand-lizard',\n icon: [576, 512, [], \"f258\", \"M556.686 290.542L410.328 64.829C397.001 44.272 374.417 32 349.917 32H56C25.121 32 0 57.122 0 88v8c0 44.112 35.888 80 80 80h196.042l-18.333 48H144c-48.523 0-88 39.477-88 88 0 30.879 25.121 56 56 56h131.552c2.987 0 5.914.549 8.697 1.631L352 408.418V480h224V355.829c0-23.225-6.679-45.801-19.314-65.287zM528 432H400v-23.582c0-19.948-12.014-37.508-30.604-44.736l-99.751-38.788A71.733 71.733 0 0 0 243.552 320H112c-4.411 0-8-3.589-8-8 0-22.056 17.944-40 40-40h113.709c19.767 0 37.786-12.407 44.84-30.873l24.552-64.281c8.996-23.553-8.428-48.846-33.63-48.846H80c-17.645 0-32-14.355-32-32v-8c0-4.411 3.589-8 8-8h293.917c8.166 0 15.693 4.09 20.137 10.942l146.358 225.715A71.84 71.84 0 0 1 528 355.829V432z\"]\n};\nvar faHandPaper = {\n prefix: 'far',\n iconName: 'hand-paper',\n icon: [448, 512, [], \"f256\", \"M372.57 112.641v-10.825c0-43.612-40.52-76.691-83.039-65.546-25.629-49.5-94.09-47.45-117.982.747C130.269 26.456 89.144 57.945 89.144 102v126.13c-19.953-7.427-43.308-5.068-62.083 8.871-29.355 21.796-35.794 63.333-14.55 93.153L132.48 498.569a32 32 0 0 0 26.062 13.432h222.897c14.904 0 27.835-10.289 31.182-24.813l30.184-130.958A203.637 203.637 0 0 0 448 310.564V179c0-40.62-35.523-71.992-75.43-66.359zm27.427 197.922c0 11.731-1.334 23.469-3.965 34.886L368.707 464h-201.92L51.591 302.303c-14.439-20.27 15.023-42.776 29.394-22.605l27.128 38.079c8.995 12.626 29.031 6.287 29.031-9.283V102c0-25.645 36.571-24.81 36.571.691V256c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16V67c0-25.663 36.571-24.81 36.571.691V256c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16V101.125c0-25.672 36.57-24.81 36.57.691V256c0 8.837 7.163 16 16 16h6.857c8.837 0 16-7.163 16-16v-76.309c0-26.242 36.57-25.64 36.57-.691v131.563z\"]\n};\nvar faHandPeace = {\n prefix: 'far',\n iconName: 'hand-peace',\n icon: [448, 512, [], \"f25b\", \"M362.146 191.976c-13.71-21.649-38.761-34.016-65.006-30.341V74c0-40.804-32.811-74-73.141-74-40.33 0-73.14 33.196-73.14 74L160 168l-18.679-78.85C126.578 50.843 83.85 32.11 46.209 47.208 8.735 62.238-9.571 104.963 5.008 142.85l55.757 144.927c-30.557 24.956-43.994 57.809-24.733 92.218l54.853 97.999C102.625 498.97 124.73 512 148.575 512h205.702c30.744 0 57.558-21.44 64.555-51.797l27.427-118.999a67.801 67.801 0 0 0 1.729-15.203L448 256c0-44.956-43.263-77.343-85.854-64.024zM399.987 326c0 1.488-.169 2.977-.502 4.423l-27.427 119.001c-1.978 8.582-9.29 14.576-17.782 14.576H148.575c-6.486 0-12.542-3.621-15.805-9.449l-54.854-98c-4.557-8.141-2.619-18.668 4.508-24.488l26.647-21.764a16 16 0 0 0 4.812-18.139l-64.09-166.549C37.226 92.956 84.37 74.837 96.51 106.389l59.784 155.357A16 16 0 0 0 171.227 272h11.632c8.837 0 16-7.163 16-16V74c0-34.375 50.281-34.43 50.281 0v182c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16v-28c0-25.122 36.567-25.159 36.567 0v28c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16 0-25.12 36.567-25.16 36.567 0v70z\"]\n};\nvar faHandPointDown = {\n prefix: 'far',\n iconName: 'hand-point-down',\n icon: [448, 512, [], \"f0a7\", \"M188.8 512c45.616 0 83.2-37.765 83.2-83.2v-35.647a93.148 93.148 0 0 0 22.064-7.929c22.006 2.507 44.978-3.503 62.791-15.985C409.342 368.1 448 331.841 448 269.299V248c0-60.063-40-98.512-40-127.2v-2.679c4.952-5.747 8-13.536 8-22.12V32c0-17.673-12.894-32-28.8-32H156.8C140.894 0 128 14.327 128 32v64c0 8.584 3.048 16.373 8 22.12v2.679c0 6.964-6.193 14.862-23.668 30.183l-.148.129-.146.131c-9.937 8.856-20.841 18.116-33.253 25.851C48.537 195.798 0 207.486 0 252.8c0 56.928 35.286 92 83.2 92 8.026 0 15.489-.814 22.4-2.176V428.8c0 45.099 38.101 83.2 83.2 83.2zm0-48c-18.7 0-35.2-16.775-35.2-35.2V270.4c-17.325 0-35.2 26.4-70.4 26.4-26.4 0-35.2-20.625-35.2-44 0-8.794 32.712-20.445 56.1-34.926 14.575-9.074 27.225-19.524 39.875-30.799 18.374-16.109 36.633-33.836 39.596-59.075h176.752C364.087 170.79 400 202.509 400 248v21.299c0 40.524-22.197 57.124-61.325 50.601-8.001 14.612-33.979 24.151-53.625 12.925-18.225 19.365-46.381 17.787-61.05 4.95V428.8c0 18.975-16.225 35.2-35.2 35.2zM328 64c0-13.255 10.745-24 24-24s24 10.745 24 24-10.745 24-24 24-24-10.745-24-24z\"]\n};\nvar faHandPointLeft = {\n prefix: 'far',\n iconName: 'hand-point-left',\n icon: [512, 512, [], \"f0a5\", \"M0 220.8C0 266.416 37.765 304 83.2 304h35.647a93.148 93.148 0 0 0 7.929 22.064c-2.507 22.006 3.503 44.978 15.985 62.791C143.9 441.342 180.159 480 242.701 480H264c60.063 0 98.512-40 127.2-40h2.679c5.747 4.952 13.536 8 22.12 8h64c17.673 0 32-12.894 32-28.8V188.8c0-15.906-14.327-28.8-32-28.8h-64c-8.584 0-16.373 3.048-22.12 8H391.2c-6.964 0-14.862-6.193-30.183-23.668l-.129-.148-.131-.146c-8.856-9.937-18.116-20.841-25.851-33.253C316.202 80.537 304.514 32 259.2 32c-56.928 0-92 35.286-92 83.2 0 8.026.814 15.489 2.176 22.4H83.2C38.101 137.6 0 175.701 0 220.8zm48 0c0-18.7 16.775-35.2 35.2-35.2h158.4c0-17.325-26.4-35.2-26.4-70.4 0-26.4 20.625-35.2 44-35.2 8.794 0 20.445 32.712 34.926 56.1 9.074 14.575 19.524 27.225 30.799 39.875 16.109 18.374 33.836 36.633 59.075 39.596v176.752C341.21 396.087 309.491 432 264 432h-21.299c-40.524 0-57.124-22.197-50.601-61.325-14.612-8.001-24.151-33.979-12.925-53.625-19.365-18.225-17.787-46.381-4.95-61.05H83.2C64.225 256 48 239.775 48 220.8zM448 360c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24z\"]\n};\nvar faHandPointRight = {\n prefix: 'far',\n iconName: 'hand-point-right',\n icon: [512, 512, [], \"f0a4\", \"M428.8 137.6h-86.177a115.52 115.52 0 0 0 2.176-22.4c0-47.914-35.072-83.2-92-83.2-45.314 0-57.002 48.537-75.707 78.784-7.735 12.413-16.994 23.317-25.851 33.253l-.131.146-.129.148C135.662 161.807 127.764 168 120.8 168h-2.679c-5.747-4.952-13.536-8-22.12-8H32c-17.673 0-32 12.894-32 28.8v230.4C0 435.106 14.327 448 32 448h64c8.584 0 16.373-3.048 22.12-8h2.679c28.688 0 67.137 40 127.2 40h21.299c62.542 0 98.8-38.658 99.94-91.145 12.482-17.813 18.491-40.785 15.985-62.791A93.148 93.148 0 0 0 393.152 304H428.8c45.435 0 83.2-37.584 83.2-83.2 0-45.099-38.101-83.2-83.2-83.2zm0 118.4h-91.026c12.837 14.669 14.415 42.825-4.95 61.05 11.227 19.646 1.687 45.624-12.925 53.625 6.524 39.128-10.076 61.325-50.6 61.325H248c-45.491 0-77.21-35.913-120-39.676V215.571c25.239-2.964 42.966-21.222 59.075-39.596 11.275-12.65 21.725-25.3 30.799-39.875C232.355 112.712 244.006 80 252.8 80c23.375 0 44 8.8 44 35.2 0 35.2-26.4 53.075-26.4 70.4h158.4c18.425 0 35.2 16.5 35.2 35.2 0 18.975-16.225 35.2-35.2 35.2zM88 384c0 13.255-10.745 24-24 24s-24-10.745-24-24 10.745-24 24-24 24 10.745 24 24z\"]\n};\nvar faHandPointUp = {\n prefix: 'far',\n iconName: 'hand-point-up',\n icon: [448, 512, [], \"f0a6\", \"M105.6 83.2v86.177a115.52 115.52 0 0 0-22.4-2.176c-47.914 0-83.2 35.072-83.2 92 0 45.314 48.537 57.002 78.784 75.707 12.413 7.735 23.317 16.994 33.253 25.851l.146.131.148.129C129.807 376.338 136 384.236 136 391.2v2.679c-4.952 5.747-8 13.536-8 22.12v64c0 17.673 12.894 32 28.8 32h230.4c15.906 0 28.8-14.327 28.8-32v-64c0-8.584-3.048-16.373-8-22.12V391.2c0-28.688 40-67.137 40-127.2v-21.299c0-62.542-38.658-98.8-91.145-99.94-17.813-12.482-40.785-18.491-62.791-15.985A93.148 93.148 0 0 0 272 118.847V83.2C272 37.765 234.416 0 188.8 0c-45.099 0-83.2 38.101-83.2 83.2zm118.4 0v91.026c14.669-12.837 42.825-14.415 61.05 4.95 19.646-11.227 45.624-1.687 53.625 12.925 39.128-6.524 61.325 10.076 61.325 50.6V264c0 45.491-35.913 77.21-39.676 120H183.571c-2.964-25.239-21.222-42.966-39.596-59.075-12.65-11.275-25.3-21.725-39.875-30.799C80.712 279.645 48 267.994 48 259.2c0-23.375 8.8-44 35.2-44 35.2 0 53.075 26.4 70.4 26.4V83.2c0-18.425 16.5-35.2 35.2-35.2 18.975 0 35.2 16.225 35.2 35.2zM352 424c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24z\"]\n};\nvar faHandPointer = {\n prefix: 'far',\n iconName: 'hand-pointer',\n icon: [448, 512, [], \"f25a\", \"M358.182 179.361c-19.493-24.768-52.679-31.945-79.872-19.098-15.127-15.687-36.182-22.487-56.595-19.629V67c0-36.944-29.736-67-66.286-67S89.143 30.056 89.143 67v161.129c-19.909-7.41-43.272-5.094-62.083 8.872-29.355 21.795-35.793 63.333-14.55 93.152l109.699 154.001C134.632 501.59 154.741 512 176 512h178.286c30.802 0 57.574-21.5 64.557-51.797l27.429-118.999A67.873 67.873 0 0 0 448 326v-84c0-46.844-46.625-79.273-89.818-62.639zM80.985 279.697l27.126 38.079c8.995 12.626 29.031 6.287 29.031-9.283V67c0-25.12 36.571-25.16 36.571 0v175c0 8.836 7.163 16 16 16h6.857c8.837 0 16-7.164 16-16v-35c0-25.12 36.571-25.16 36.571 0v35c0 8.836 7.163 16 16 16H272c8.837 0 16-7.164 16-16v-21c0-25.12 36.571-25.16 36.571 0v21c0 8.836 7.163 16 16 16h6.857c8.837 0 16-7.164 16-16 0-25.121 36.571-25.16 36.571 0v84c0 1.488-.169 2.977-.502 4.423l-27.43 119.001c-1.978 8.582-9.29 14.576-17.782 14.576H176c-5.769 0-11.263-2.878-14.697-7.697l-109.712-154c-14.406-20.223 14.994-42.818 29.394-22.606zM176.143 400v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.733 0-14-7.163-14-16zm75.428 0v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.732 0-14-7.163-14-16zM327 400v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.732 0-14-7.163-14-16z\"]\n};\nvar faHandRock = {\n prefix: 'far',\n iconName: 'hand-rock',\n icon: [512, 512, [], \"f255\", \"M408.864 79.052c-22.401-33.898-66.108-42.273-98.813-23.588-29.474-31.469-79.145-31.093-108.334-.022-47.16-27.02-108.71 5.055-110.671 60.806C44.846 105.407 0 140.001 0 187.429v56.953c0 32.741 14.28 63.954 39.18 85.634l97.71 85.081c4.252 3.702 3.11 5.573 3.11 32.903 0 17.673 14.327 32 32 32h252c17.673 0 32-14.327 32-32 0-23.513-1.015-30.745 3.982-42.37l42.835-99.656c6.094-14.177 9.183-29.172 9.183-44.568V146.963c0-52.839-54.314-88.662-103.136-67.911zM464 261.406a64.505 64.505 0 0 1-5.282 25.613l-42.835 99.655c-5.23 12.171-7.883 25.04-7.883 38.25V432H188v-10.286c0-16.37-7.14-31.977-19.59-42.817l-97.71-85.08C56.274 281.255 48 263.236 48 244.381v-56.953c0-33.208 52-33.537 52 .677v41.228a16 16 0 0 0 5.493 12.067l7 6.095A16 16 0 0 0 139 235.429V118.857c0-33.097 52-33.725 52 .677v26.751c0 8.836 7.164 16 16 16h7c8.836 0 16-7.164 16-16v-41.143c0-33.134 52-33.675 52 .677v40.466c0 8.836 7.163 16 16 16h7c8.837 0 16-7.164 16-16v-27.429c0-33.03 52-33.78 52 .677v26.751c0 8.836 7.163 16 16 16h7c8.837 0 16-7.164 16-16 0-33.146 52-33.613 52 .677v114.445z\"]\n};\nvar faHandScissors = {\n prefix: 'far',\n iconName: 'hand-scissors',\n icon: [512, 512, [], \"f257\", \"M256 480l70-.013c5.114 0 10.231-.583 15.203-1.729l118.999-27.427C490.56 443.835 512 417.02 512 386.277V180.575c0-23.845-13.03-45.951-34.005-57.69l-97.999-54.853c-34.409-19.261-67.263-5.824-92.218 24.733L142.85 37.008c-37.887-14.579-80.612 3.727-95.642 41.201-15.098 37.642 3.635 80.37 41.942 95.112L168 192l-94-9.141c-40.804 0-74 32.811-74 73.14 0 40.33 33.196 73.141 74 73.141h87.635c-3.675 26.245 8.692 51.297 30.341 65.006C178.657 436.737 211.044 480 256 480zm0-48.013c-25.16 0-25.12-36.567 0-36.567 8.837 0 16-7.163 16-16v-6.856c0-8.837-7.163-16-16-16h-28c-25.159 0-25.122-36.567 0-36.567h28c8.837 0 16-7.163 16-16v-6.856c0-8.837-7.163-16-16-16H74c-34.43 0-34.375-50.281 0-50.281h182c8.837 0 16-7.163 16-16v-11.632a16 16 0 0 0-10.254-14.933L106.389 128.51c-31.552-12.14-13.432-59.283 19.222-46.717l166.549 64.091a16.001 16.001 0 0 0 18.139-4.812l21.764-26.647c5.82-7.127 16.348-9.064 24.488-4.508l98 54.854c5.828 3.263 9.449 9.318 9.449 15.805v205.701c0 8.491-5.994 15.804-14.576 17.782l-119.001 27.427a19.743 19.743 0 0 1-4.423.502h-70z\"]\n};\nvar faHandSpock = {\n prefix: 'far',\n iconName: 'hand-spock',\n icon: [512, 512, [], \"f259\", \"M21.096 381.79l129.092 121.513a32 32 0 0 0 21.932 8.698h237.6c14.17 0 26.653-9.319 30.68-22.904l31.815-107.313A115.955 115.955 0 0 0 477 348.811v-36.839c0-4.051.476-8.104 1.414-12.045l31.73-133.41c10.099-42.412-22.316-82.738-65.544-82.525-4.144-24.856-22.543-47.165-49.85-53.992-35.803-8.952-72.227 12.655-81.25 48.75L296.599 184 274.924 52.01c-8.286-36.07-44.303-58.572-80.304-50.296-29.616 6.804-50.138 32.389-51.882 61.295-42.637.831-73.455 40.563-64.071 81.844l31.04 136.508c-27.194-22.515-67.284-19.992-91.482 5.722-25.376 26.961-24.098 69.325 2.871 94.707zm32.068-61.811l.002-.001c7.219-7.672 19.241-7.98 26.856-.813l53.012 49.894C143.225 378.649 160 371.4 160 357.406v-69.479c0-1.193-.134-2.383-.397-3.546l-34.13-150.172c-5.596-24.617 31.502-32.86 37.054-8.421l30.399 133.757a16 16 0 0 0 15.603 12.454h8.604c10.276 0 17.894-9.567 15.594-19.583l-41.62-181.153c-5.623-24.469 31.39-33.076 37.035-8.508l45.22 196.828A16 16 0 0 0 288.956 272h13.217a16 16 0 0 0 15.522-12.119l42.372-169.49c6.104-24.422 42.962-15.159 36.865 9.217L358.805 252.12c-2.521 10.088 5.115 19.88 15.522 19.88h9.694a16 16 0 0 0 15.565-12.295L426.509 146.6c5.821-24.448 42.797-15.687 36.966 8.802L431.72 288.81a100.094 100.094 0 0 0-2.72 23.162v36.839c0 6.548-.943 13.051-2.805 19.328L397.775 464h-219.31L53.978 346.836c-7.629-7.18-7.994-19.229-.814-26.857z\"]\n};\nvar faHandshake = {\n prefix: 'far',\n iconName: 'handshake',\n icon: [640, 512, [], \"f2b5\", \"M519.2 127.9l-47.6-47.6A56.252 56.252 0 0 0 432 64H205.2c-14.8 0-29.1 5.9-39.6 16.3L118 127.9H0v255.7h64c17.6 0 31.8-14.2 31.9-31.7h9.1l84.6 76.4c30.9 25.1 73.8 25.7 105.6 3.8 12.5 10.8 26 15.9 41.1 15.9 18.2 0 35.3-7.4 48.8-24 22.1 8.7 48.2 2.6 64-16.8l26.2-32.3c5.6-6.9 9.1-14.8 10.9-23h57.9c.1 17.5 14.4 31.7 31.9 31.7h64V127.9H519.2zM48 351.6c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16c0 8.9-7.2 16-16 16zm390-6.9l-26.1 32.2c-2.8 3.4-7.8 4-11.3 1.2l-23.9-19.4-30 36.5c-6 7.3-15 4.8-18 2.4l-36.8-31.5-15.6 19.2c-13.9 17.1-39.2 19.7-55.3 6.6l-97.3-88H96V175.8h41.9l61.7-61.6c2-.8 3.7-1.5 5.7-2.3H262l-38.7 35.5c-29.4 26.9-31.1 72.3-4.4 101.3 14.8 16.2 61.2 41.2 101.5 4.4l8.2-7.5 108.2 87.8c3.4 2.8 3.9 7.9 1.2 11.3zm106-40.8h-69.2c-2.3-2.8-4.9-5.4-7.7-7.7l-102.7-83.4 12.5-11.4c6.5-6 7-16.1 1-22.6L367 167.1c-6-6.5-16.1-6.9-22.6-1l-55.2 50.6c-9.5 8.7-25.7 9.4-34.6 0-9.3-9.9-8.5-25.1 1.2-33.9l65.6-60.1c7.4-6.8 17-10.5 27-10.5l83.7-.2c2.1 0 4.1.8 5.5 2.3l61.7 61.6H544v128zm48 47.7c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16c0 8.9-7.2 16-16 16z\"]\n};\nvar faHdd = {\n prefix: 'far',\n iconName: 'hdd',\n icon: [576, 512, [], \"f0a0\", \"M567.403 235.642L462.323 84.589A48 48 0 0 0 422.919 64H153.081a48 48 0 0 0-39.404 20.589L8.597 235.642A48.001 48.001 0 0 0 0 263.054V400c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V263.054c0-9.801-3-19.366-8.597-27.412zM153.081 112h269.838l77.913 112H75.168l77.913-112zM528 400H48V272h480v128zm-32-64c0 17.673-14.327 32-32 32s-32-14.327-32-32 14.327-32 32-32 32 14.327 32 32zm-96 0c0 17.673-14.327 32-32 32s-32-14.327-32-32 14.327-32 32-32 32 14.327 32 32z\"]\n};\nvar faHeart = {\n prefix: 'far',\n iconName: 'heart',\n icon: [512, 512, [], \"f004\", \"M458.4 64.3C400.6 15.7 311.3 23 256 79.3 200.7 23 111.4 15.6 53.6 64.3-21.6 127.6-10.6 230.8 43 285.5l175.4 178.7c10 10.2 23.4 15.9 37.6 15.9 14.3 0 27.6-5.6 37.6-15.8L469 285.6c53.5-54.7 64.7-157.9-10.6-221.3zm-23.6 187.5L259.4 430.5c-2.4 2.4-4.4 2.4-6.8 0L77.2 251.8c-36.5-37.2-43.9-107.6 7.3-150.7 38.9-32.7 98.9-27.8 136.5 10.5l35 35.7 35-35.7c37.8-38.5 97.8-43.2 136.5-10.6 51.1 43.1 43.5 113.9 7.3 150.8z\"]\n};\nvar faHospital = {\n prefix: 'far',\n iconName: 'hospital',\n icon: [448, 512, [], \"f0f8\", \"M128 244v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12zm140 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12zm-76 84v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm76 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12zm180 124v36H0v-36c0-6.627 5.373-12 12-12h19.5V85.035C31.5 73.418 42.245 64 55.5 64H144V24c0-13.255 10.745-24 24-24h112c13.255 0 24 10.745 24 24v40h88.5c13.255 0 24 9.418 24 21.035V464H436c6.627 0 12 5.373 12 12zM79.5 463H192v-67c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v67h112.5V112H304v24c0 13.255-10.745 24-24 24H168c-13.255 0-24-10.745-24-24v-24H79.5v351zM266 64h-26V38a6 6 0 0 0-6-6h-20a6 6 0 0 0-6 6v26h-26a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h26v26a6 6 0 0 0 6 6h20a6 6 0 0 0 6-6V96h26a6 6 0 0 0 6-6V70a6 6 0 0 0-6-6z\"]\n};\nvar faHourglass = {\n prefix: 'far',\n iconName: 'hourglass',\n icon: [384, 512, [], \"f254\", \"M368 48h4c6.627 0 12-5.373 12-12V12c0-6.627-5.373-12-12-12H12C5.373 0 0 5.373 0 12v24c0 6.627 5.373 12 12 12h4c0 80.564 32.188 165.807 97.18 208C47.899 298.381 16 383.9 16 464h-4c-6.627 0-12 5.373-12 12v24c0 6.627 5.373 12 12 12h360c6.627 0 12-5.373 12-12v-24c0-6.627-5.373-12-12-12h-4c0-80.564-32.188-165.807-97.18-208C336.102 213.619 368 128.1 368 48zM64 48h256c0 101.62-57.307 184-128 184S64 149.621 64 48zm256 416H64c0-101.62 57.308-184 128-184s128 82.38 128 184z\"]\n};\nvar faIdBadge = {\n prefix: 'far',\n iconName: 'id-badge',\n icon: [384, 512, [], \"f2c1\", \"M336 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm0 464H48V48h288v416zM144 112h96c8.8 0 16-7.2 16-16s-7.2-16-16-16h-96c-8.8 0-16 7.2-16 16s7.2 16 16 16zm48 176c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm-89.6 128h179.2c12.4 0 22.4-8.6 22.4-19.2v-19.2c0-31.8-30.1-57.6-67.2-57.6-10.8 0-18.7 8-44.8 8-26.9 0-33.4-8-44.8-8-37.1 0-67.2 25.8-67.2 57.6v19.2c0 10.6 10 19.2 22.4 19.2z\"]\n};\nvar faIdCard = {\n prefix: 'far',\n iconName: 'id-card',\n icon: [576, 512, [], \"f2c2\", \"M528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm0 400H303.2c.9-4.5.8 3.6.8-22.4 0-31.8-30.1-57.6-67.2-57.6-10.8 0-18.7 8-44.8 8-26.9 0-33.4-8-44.8-8-37.1 0-67.2 25.8-67.2 57.6 0 26-.2 17.9.8 22.4H48V144h480v288zm-168-80h112c4.4 0 8-3.6 8-8v-16c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8zm0-64h112c4.4 0 8-3.6 8-8v-16c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8zm0-64h112c4.4 0 8-3.6 8-8v-16c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8zm-168 96c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64z\"]\n};\nvar faImage = {\n prefix: 'far',\n iconName: 'image',\n icon: [512, 512, [], \"f03e\", \"M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 336H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v276a6 6 0 0 1-6 6zM128 152c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zM96 352h320v-80l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L192 304l-39.515-39.515c-4.686-4.686-12.284-4.686-16.971 0L96 304v48z\"]\n};\nvar faImages = {\n prefix: 'far',\n iconName: 'images',\n icon: [576, 512, [], \"f302\", \"M480 416v16c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v48H54a6 6 0 0 0-6 6v244a6 6 0 0 0 6 6h372a6 6 0 0 0 6-6v-10h48zm42-336H150a6 6 0 0 0-6 6v244a6 6 0 0 0 6 6h372a6 6 0 0 0 6-6V86a6 6 0 0 0-6-6zm6-48c26.51 0 48 21.49 48 48v256c0 26.51-21.49 48-48 48H144c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h384zM264 144c0 22.091-17.909 40-40 40s-40-17.909-40-40 17.909-40 40-40 40 17.909 40 40zm-72 96l39.515-39.515c4.686-4.686 12.284-4.686 16.971 0L288 240l103.515-103.515c4.686-4.686 12.284-4.686 16.971 0L480 208v80H192v-48z\"]\n};\nvar faKeyboard = {\n prefix: 'far',\n iconName: 'keyboard',\n icon: [576, 512, [], \"f11c\", \"M528 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm8 336c0 4.411-3.589 8-8 8H48c-4.411 0-8-3.589-8-8V112c0-4.411 3.589-8 8-8h480c4.411 0 8 3.589 8 8v288zM170 270v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm-336 82v-28c0-6.627-5.373-12-12-12H82c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm384 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zM122 188v-28c0-6.627-5.373-12-12-12H82c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm-98 158v-16c0-6.627-5.373-12-12-12H180c-6.627 0-12 5.373-12 12v16c0 6.627 5.373 12 12 12h216c6.627 0 12-5.373 12-12z\"]\n};\nvar faKiss = {\n prefix: 'far',\n iconName: 'kiss',\n icon: [496, 512, [], \"f596\", \"M168 176c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm136 132c0-19.2-28.8-41.5-71.5-44-3.8-.4-7.4 2.4-8.2 6.2-.9 3.8 1.1 7.7 4.7 9.2l16.9 7.2c13 5.5 20.8 13.5 20.8 21.5s-7.8 16-20.7 21.5l-17 7.2c-5.7 2.4-6 12.2 0 14.8l16.9 7.2c13 5.5 20.8 13.5 20.8 21.5s-7.8 16-20.7 21.5l-17 7.2c-3.6 1.5-5.6 5.4-4.7 9.2.8 3.6 4.1 6.2 7.8 6.2h.5c42.8-2.5 71.5-24.8 71.5-44 0-13-13.4-27.3-35.2-36C290.6 335.3 304 321 304 308zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm80-280c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z\"]\n};\nvar faKissBeam = {\n prefix: 'far',\n iconName: 'kiss-beam',\n icon: [496, 512, [], \"f597\", \"M168 152c-23.8 0-52.7 29.3-56 71.4-.3 3.7 2 7.2 5.6 8.3 3.5 1 7.5-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 5.9-4.5 5.6-8.3-3.1-42.1-32-71.4-55.8-71.4zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm56-148c0-19.2-28.8-41.5-71.5-44-3.8-.4-7.4 2.4-8.2 6.2-.9 3.8 1.1 7.7 4.7 9.2l16.9 7.2c13 5.5 20.8 13.5 20.8 21.5s-7.8 16-20.7 21.5l-17 7.2c-5.7 2.4-6 12.2 0 14.8l16.9 7.2c13 5.5 20.8 13.5 20.8 21.5s-7.8 16-20.7 21.5l-17 7.2c-3.6 1.5-5.6 5.4-4.7 9.2.8 3.6 4.1 6.2 7.8 6.2h.5c42.8-2.5 71.5-24.8 71.5-44 0-13-13.4-27.3-35.2-36C290.6 335.3 304 321 304 308zm24-156c-23.8 0-52.7 29.3-56 71.4-.3 3.7 2 7.2 5.6 8.3 3.5 1 7.5-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 5.9-4.5 5.6-8.3-3.1-42.1-32-71.4-55.8-71.4z\"]\n};\nvar faKissWinkHeart = {\n prefix: 'far',\n iconName: 'kiss-wink-heart',\n icon: [504, 512, [], \"f598\", \"M304 308.5c0-19.2-28.8-41.5-71.5-44-3.8-.4-7.4 2.4-8.2 6.2-.9 3.8 1.1 7.7 4.7 9.2l16.9 7.2c13 5.5 20.8 13.5 20.8 21.5s-7.8 16-20.7 21.5l-17 7.2c-5.7 2.4-6 12.2 0 14.8l16.9 7.2c13 5.5 20.8 13.5 20.8 21.5s-7.8 16-20.7 21.5l-17 7.2c-3.6 1.5-5.6 5.4-4.7 9.2.8 3.6 4.1 6.2 7.8 6.2h.5c42.8-2.5 71.5-24.8 71.5-44 0-13-13.4-27.3-35.2-36 21.7-9.1 35.1-23.4 35.1-36.4zm70.5-83.5l9.5 8.5c3.8 3.3 9.3 4 13.7 1.6 4.4-2.4 6.9-7.4 6.1-12.4-4-25.2-34.2-42.1-59.8-42.1s-55.9 16.9-59.8 42.1c-.8 5 1.7 10 6.1 12.4 5.8 3.1 11.2.7 13.7-1.6l9.5-8.5c14.8-13.2 46.2-13.2 61 0zM136 208.5c0 17.7 14.3 32 32 32s32-14.3 32-32-14.3-32-32-32-32 14.3-32 32zm365.1 194c-8-20.8-31.5-31.5-53.1-25.9l-8.4 2.2-2.3-8.4c-5.9-21.4-27-36.5-49-33-25.2 4-40.6 28.6-34 52.6l22.9 82.6c1.5 5.3 7 8.5 12.4 7.1l83-21.5c24.1-6.3 37.7-31.8 28.5-55.7zM334 436.3c-26.1 12.5-55.2 19.7-86 19.7-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200c0 22.1-3.7 43.3-10.4 63.2 9 6.4 17 14.2 22.6 23.9 6.4.1 12.6 1.4 18.6 2.9 10.9-27.9 17.1-58.2 17.1-90C496 119 385 8 248 8S0 119 0 256s111 248 248 248c35.4 0 68.9-7.5 99.4-20.9-2.5-7.3 4.3 17.2-13.4-46.8z\"]\n};\nvar faLaugh = {\n prefix: 'far',\n iconName: 'laugh',\n icon: [496, 512, [], \"f599\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm141.4 389.4c-37.8 37.8-88 58.6-141.4 58.6s-103.6-20.8-141.4-58.6S48 309.4 48 256s20.8-103.6 58.6-141.4S194.6 56 248 56s103.6 20.8 141.4 58.6S448 202.6 448 256s-20.8 103.6-58.6 141.4zM328 224c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm-160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm194.4 64H133.6c-8.2 0-14.5 7-13.5 15 7.5 59.2 58.9 105 121.1 105h13.6c62.2 0 113.6-45.8 121.1-105 1-8-5.3-15-13.5-15z\"]\n};\nvar faLaughBeam = {\n prefix: 'far',\n iconName: 'laugh-beam',\n icon: [496, 512, [], \"f59a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm141.4 389.4c-37.8 37.8-88 58.6-141.4 58.6s-103.6-20.8-141.4-58.6S48 309.4 48 256s20.8-103.6 58.6-141.4S194.6 56 248 56s103.6 20.8 141.4 58.6S448 202.6 448 256s-20.8 103.6-58.6 141.4zM328 152c-23.8 0-52.7 29.3-56 71.4-.7 8.6 10.8 11.9 14.9 4.5l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c4.1 7.4 15.6 4 14.9-4.5-3.1-42.1-32-71.4-55.8-71.4zm-201 75.9l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c4.1 7.4 15.6 4 14.9-4.5-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.6 8.5 10.9 11.9 15.1 4.5zM362.4 288H133.6c-8.2 0-14.5 7-13.5 15 7.5 59.2 58.9 105 121.1 105h13.6c62.2 0 113.6-45.8 121.1-105 1-8-5.3-15-13.5-15z\"]\n};\nvar faLaughSquint = {\n prefix: 'far',\n iconName: 'laugh-squint',\n icon: [496, 512, [], \"f59b\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm141.4 389.4c-37.8 37.8-88 58.6-141.4 58.6s-103.6-20.8-141.4-58.6S48 309.4 48 256s20.8-103.6 58.6-141.4S194.6 56 248 56s103.6 20.8 141.4 58.6S448 202.6 448 256s-20.8 103.6-58.6 141.4zM343.6 196l33.6-40.3c8.6-10.3-3.8-24.8-15.4-18l-80 48c-7.8 4.7-7.8 15.9 0 20.6l80 48c11.5 6.8 24-7.6 15.4-18L343.6 196zm-209.4 58.3l80-48c7.8-4.7 7.8-15.9 0-20.6l-80-48c-11.6-6.9-24 7.7-15.4 18l33.6 40.3-33.6 40.3c-8.7 10.4 3.8 24.8 15.4 18zM362.4 288H133.6c-8.2 0-14.5 7-13.5 15 7.5 59.2 58.9 105 121.1 105h13.6c62.2 0 113.6-45.8 121.1-105 1-8-5.3-15-13.5-15z\"]\n};\nvar faLaughWink = {\n prefix: 'far',\n iconName: 'laugh-wink',\n icon: [496, 512, [], \"f59c\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm141.4 389.4c-37.8 37.8-88 58.6-141.4 58.6s-103.6-20.8-141.4-58.6C68.8 359.6 48 309.4 48 256s20.8-103.6 58.6-141.4C144.4 76.8 194.6 56 248 56s103.6 20.8 141.4 58.6c37.8 37.8 58.6 88 58.6 141.4s-20.8 103.6-58.6 141.4zM328 164c-25.7 0-55.9 16.9-59.9 42.1-1.7 11.2 11.5 18.2 19.8 10.8l9.5-8.5c14.8-13.2 46.2-13.2 61 0l9.5 8.5c8.5 7.4 21.6.3 19.8-10.8-3.8-25.2-34-42.1-59.7-42.1zm-160 60c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm194.4 64H133.6c-8.2 0-14.5 7-13.5 15 7.5 59.2 58.9 105 121.1 105h13.6c62.2 0 113.6-45.8 121.1-105 1-8-5.3-15-13.5-15z\"]\n};\nvar faLemon = {\n prefix: 'far',\n iconName: 'lemon',\n icon: [512, 512, [], \"f094\", \"M484.112 27.889C455.989-.233 416.108-8.057 387.059 8.865 347.604 31.848 223.504-41.111 91.196 91.197-41.277 223.672 31.923 347.472 8.866 387.058c-16.922 29.051-9.1 68.932 19.022 97.054 28.135 28.135 68.011 35.938 97.057 19.021 39.423-22.97 163.557 49.969 295.858-82.329 132.474-132.477 59.273-256.277 82.331-295.861 16.922-29.05 9.1-68.931-19.022-97.054zm-22.405 72.894c-38.8 66.609 45.6 165.635-74.845 286.08-120.44 120.443-219.475 36.048-286.076 74.843-22.679 13.207-64.035-27.241-50.493-50.488 38.8-66.609-45.6-165.635 74.845-286.08C245.573 4.702 344.616 89.086 411.219 50.292c22.73-13.24 64.005 27.288 50.488 50.491zm-169.861 8.736c1.37 10.96-6.404 20.957-17.365 22.327-54.846 6.855-135.779 87.787-142.635 142.635-1.373 10.989-11.399 18.734-22.326 17.365-10.961-1.37-18.735-11.366-17.365-22.326 9.162-73.286 104.167-168.215 177.365-177.365 10.953-1.368 20.956 6.403 22.326 17.364z\"]\n};\nvar faLifeRing = {\n prefix: 'far',\n iconName: 'life-ring',\n icon: [512, 512, [], \"f1cd\", \"M256 504c136.967 0 248-111.033 248-248S392.967 8 256 8 8 119.033 8 256s111.033 248 248 248zm-103.398-76.72l53.411-53.411c31.806 13.506 68.128 13.522 99.974 0l53.411 53.411c-63.217 38.319-143.579 38.319-206.796 0zM336 256c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80zm91.28 103.398l-53.411-53.411c13.505-31.806 13.522-68.128 0-99.974l53.411-53.411c38.319 63.217 38.319 143.579 0 206.796zM359.397 84.72l-53.411 53.411c-31.806-13.505-68.128-13.522-99.973 0L152.602 84.72c63.217-38.319 143.579-38.319 206.795 0zM84.72 152.602l53.411 53.411c-13.506 31.806-13.522 68.128 0 99.974L84.72 359.398c-38.319-63.217-38.319-143.579 0-206.796z\"]\n};\nvar faLightbulb = {\n prefix: 'far',\n iconName: 'lightbulb',\n icon: [352, 512, [], \"f0eb\", \"M176 80c-52.94 0-96 43.06-96 96 0 8.84 7.16 16 16 16s16-7.16 16-16c0-35.3 28.72-64 64-64 8.84 0 16-7.16 16-16s-7.16-16-16-16zM96.06 459.17c0 3.15.93 6.22 2.68 8.84l24.51 36.84c2.97 4.46 7.97 7.14 13.32 7.14h78.85c5.36 0 10.36-2.68 13.32-7.14l24.51-36.84c1.74-2.62 2.67-5.7 2.68-8.84l.05-43.18H96.02l.04 43.18zM176 0C73.72 0 0 82.97 0 176c0 44.37 16.45 84.85 43.56 115.78 16.64 18.99 42.74 58.8 52.42 92.16v.06h48v-.12c-.01-4.77-.72-9.51-2.15-14.07-5.59-17.81-22.82-64.77-62.17-109.67-20.54-23.43-31.52-53.15-31.61-84.14-.2-73.64 59.67-128 127.95-128 70.58 0 128 57.42 128 128 0 30.97-11.24 60.85-31.65 84.14-39.11 44.61-56.42 91.47-62.1 109.46a47.507 47.507 0 0 0-2.22 14.3v.1h48v-.05c9.68-33.37 35.78-73.18 52.42-92.16C335.55 260.85 352 220.37 352 176 352 78.8 273.2 0 176 0z\"]\n};\nvar faListAlt = {\n prefix: 'far',\n iconName: 'list-alt',\n icon: [512, 512, [], \"f022\", \"M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zm-6 400H54a6 6 0 0 1-6-6V86a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v340a6 6 0 0 1-6 6zm-42-92v24c0 6.627-5.373 12-12 12H204c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h200c6.627 0 12 5.373 12 12zm0-96v24c0 6.627-5.373 12-12 12H204c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h200c6.627 0 12 5.373 12 12zm0-96v24c0 6.627-5.373 12-12 12H204c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h200c6.627 0 12 5.373 12 12zm-252 12c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36zm0 96c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36zm0 96c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36z\"]\n};\nvar faMap = {\n prefix: 'far',\n iconName: 'map',\n icon: [576, 512, [], \"f279\", \"M560.02 32c-1.96 0-3.98.37-5.96 1.16L384.01 96H384L212 35.28A64.252 64.252 0 0 0 191.76 32c-6.69 0-13.37 1.05-19.81 3.14L20.12 87.95A32.006 32.006 0 0 0 0 117.66v346.32C0 473.17 7.53 480 15.99 480c1.96 0 3.97-.37 5.96-1.16L192 416l172 60.71a63.98 63.98 0 0 0 40.05.15l151.83-52.81A31.996 31.996 0 0 0 576 394.34V48.02c0-9.19-7.53-16.02-15.98-16.02zM224 90.42l128 45.19v285.97l-128-45.19V90.42zM48 418.05V129.07l128-44.53v286.2l-.64.23L48 418.05zm480-35.13l-128 44.53V141.26l.64-.24L528 93.95v288.97z\"]\n};\nvar faMeh = {\n prefix: 'far',\n iconName: 'meh',\n icon: [496, 512, [], \"f11a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm8 144H160c-13.2 0-24 10.8-24 24s10.8 24 24 24h176c13.2 0 24-10.8 24-24s-10.8-24-24-24z\"]\n};\nvar faMehBlank = {\n prefix: 'far',\n iconName: 'meh-blank',\n icon: [496, 512, [], \"f5a4\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-280c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm160 0c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z\"]\n};\nvar faMehRollingEyes = {\n prefix: 'far',\n iconName: 'meh-rolling-eyes',\n icon: [496, 512, [], \"f5a5\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm88-304c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm0 112c-22.1 0-40-17.9-40-40 0-13.6 7.3-25.1 17.7-32.3-1 2.6-1.7 5.3-1.7 8.3 0 13.3 10.7 24 24 24s24-10.7 24-24c0-2.9-.7-5.7-1.7-8.3 10.4 7.2 17.7 18.7 17.7 32.3 0 22.1-17.9 40-40 40zm-104-40c0-39.8-32.2-72-72-72s-72 32.2-72 72 32.2 72 72 72 72-32.2 72-72zm-112 0c0-13.6 7.3-25.1 17.7-32.3-1 2.6-1.7 5.3-1.7 8.3 0 13.3 10.7 24 24 24s24-10.7 24-24c0-2.9-.7-5.7-1.7-8.3 10.4 7.2 17.7 18.7 17.7 32.3 0 22.1-17.9 40-40 40s-40-17.9-40-40zm192 128H184c-13.2 0-24 10.8-24 24s10.8 24 24 24h128c13.2 0 24-10.8 24-24s-10.8-24-24-24z\"]\n};\nvar faMinusSquare = {\n prefix: 'far',\n iconName: 'minus-square',\n icon: [448, 512, [], \"f146\", \"M108 284c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h232c6.6 0 12 5.4 12 12v32c0 6.6-5.4 12-12 12H108zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faMoneyBillAlt = {\n prefix: 'far',\n iconName: 'money-bill-alt',\n icon: [640, 512, [], \"f3d1\", \"M320 144c-53.02 0-96 50.14-96 112 0 61.85 42.98 112 96 112 53 0 96-50.13 96-112 0-61.86-42.98-112-96-112zm40 168c0 4.42-3.58 8-8 8h-64c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h16v-55.44l-.47.31a7.992 7.992 0 0 1-11.09-2.22l-8.88-13.31a7.992 7.992 0 0 1 2.22-11.09l15.33-10.22a23.99 23.99 0 0 1 13.31-4.03H328c4.42 0 8 3.58 8 8v88h16c4.42 0 8 3.58 8 8v16zM608 64H32C14.33 64 0 78.33 0 96v320c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V96c0-17.67-14.33-32-32-32zm-16 272c-35.35 0-64 28.65-64 64H112c0-35.35-28.65-64-64-64V176c35.35 0 64-28.65 64-64h416c0 35.35 28.65 64 64 64v160z\"]\n};\nvar faMoon = {\n prefix: 'far',\n iconName: 'moon',\n icon: [512, 512, [], \"f186\", \"M279.135 512c78.756 0 150.982-35.804 198.844-94.775 28.27-34.831-2.558-85.722-46.249-77.401-82.348 15.683-158.272-47.268-158.272-130.792 0-48.424 26.06-92.292 67.434-115.836 38.745-22.05 28.999-80.788-15.022-88.919A257.936 257.936 0 0 0 279.135 0c-141.36 0-256 114.575-256 256 0 141.36 114.576 256 256 256zm0-464c12.985 0 25.689 1.201 38.016 3.478-54.76 31.163-91.693 90.042-91.693 157.554 0 113.848 103.641 199.2 215.252 177.944C402.574 433.964 344.366 464 279.135 464c-114.875 0-208-93.125-208-208s93.125-208 208-208z\"]\n};\nvar faNewspaper = {\n prefix: 'far',\n iconName: 'newspaper',\n icon: [576, 512, [], \"f1ea\", \"M552 64H112c-20.858 0-38.643 13.377-45.248 32H24c-13.255 0-24 10.745-24 24v272c0 30.928 25.072 56 56 56h496c13.255 0 24-10.745 24-24V88c0-13.255-10.745-24-24-24zM48 392V144h16v248c0 4.411-3.589 8-8 8s-8-3.589-8-8zm480 8H111.422c.374-2.614.578-5.283.578-8V112h416v288zM172 280h136c6.627 0 12-5.373 12-12v-96c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v96c0 6.627 5.373 12 12 12zm28-80h80v40h-80v-40zm-40 140v-24c0-6.627 5.373-12 12-12h136c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H172c-6.627 0-12-5.373-12-12zm192 0v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H364c-6.627 0-12-5.373-12-12zm0-144v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H364c-6.627 0-12-5.373-12-12zm0 72v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H364c-6.627 0-12-5.373-12-12z\"]\n};\nvar faObjectGroup = {\n prefix: 'far',\n iconName: 'object-group',\n icon: [512, 512, [], \"f247\", \"M500 128c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v12H96V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v72c0 6.627 5.373 12 12 12h12v256H12c-6.627 0-12 5.373-12 12v72c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-12h320v12c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-12V128h12zm-52-64h32v32h-32V64zM32 64h32v32H32V64zm32 384H32v-32h32v32zm416 0h-32v-32h32v32zm-40-64h-12c-6.627 0-12 5.373-12 12v12H96v-12c0-6.627-5.373-12-12-12H72V128h12c6.627 0 12-5.373 12-12v-12h320v12c0 6.627 5.373 12 12 12h12v256zm-36-192h-84v-52c0-6.628-5.373-12-12-12H108c-6.627 0-12 5.372-12 12v168c0 6.628 5.373 12 12 12h84v52c0 6.628 5.373 12 12 12h200c6.627 0 12-5.372 12-12V204c0-6.628-5.373-12-12-12zm-268-24h144v112H136V168zm240 176H232v-24h76c6.627 0 12-5.372 12-12v-76h56v112z\"]\n};\nvar faObjectUngroup = {\n prefix: 'far',\n iconName: 'object-ungroup',\n icon: [576, 512, [], \"f248\", \"M564 224c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v12h-88v-24h12c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v12H96V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v72c0 6.627 5.373 12 12 12h12v160H12c-6.627 0-12 5.373-12 12v72c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-12h88v24h-12c-6.627 0-12 5.373-12 12v72c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-12h224v12c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-12V224h12zM352 64h32v32h-32V64zm0 256h32v32h-32v-32zM64 352H32v-32h32v32zm0-256H32V64h32v32zm32 216v-12c0-6.627-5.373-12-12-12H72V128h12c6.627 0 12-5.373 12-12v-12h224v12c0 6.627 5.373 12 12 12h12v160h-12c-6.627 0-12 5.373-12 12v12H96zm128 136h-32v-32h32v32zm280-64h-12c-6.627 0-12 5.373-12 12v12H256v-12c0-6.627-5.373-12-12-12h-12v-24h88v12c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-12v-88h88v12c0 6.627 5.373 12 12 12h12v160zm40 64h-32v-32h32v32zm0-256h-32v-32h32v32z\"]\n};\nvar faPaperPlane = {\n prefix: 'far',\n iconName: 'paper-plane',\n icon: [512, 512, [], \"f1d8\", \"M440 6.5L24 246.4c-34.4 19.9-31.1 70.8 5.7 85.9L144 379.6V464c0 46.4 59.2 65.5 86.6 28.6l43.8-59.1 111.9 46.2c5.9 2.4 12.1 3.6 18.3 3.6 8.2 0 16.3-2.1 23.6-6.2 12.8-7.2 21.6-20 23.9-34.5l59.4-387.2c6.1-40.1-36.9-68.8-71.5-48.9zM192 464v-64.6l36.6 15.1L192 464zm212.6-28.7l-153.8-63.5L391 169.5c10.7-15.5-9.5-33.5-23.7-21.2L155.8 332.6 48 288 464 48l-59.4 387.3z\"]\n};\nvar faPauseCircle = {\n prefix: 'far',\n iconName: 'pause-circle',\n icon: [512, 512, [], \"f28b\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm96-280v160c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16zm-112 0v160c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16z\"]\n};\nvar faPlayCircle = {\n prefix: 'far',\n iconName: 'play-circle',\n icon: [512, 512, [], \"f144\", \"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\"]\n};\nvar faPlusSquare = {\n prefix: 'far',\n iconName: 'plus-square',\n icon: [448, 512, [], \"f0fe\", \"M352 240v32c0 6.6-5.4 12-12 12h-88v88c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-88h-88c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h88v-88c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v88h88c6.6 0 12 5.4 12 12zm96-160v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z\"]\n};\nvar faQuestionCircle = {\n prefix: 'far',\n iconName: 'question-circle',\n icon: [512, 512, [], \"f059\", \"M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 448c-110.532 0-200-89.431-200-200 0-110.495 89.472-200 200-200 110.491 0 200 89.471 200 200 0 110.53-89.431 200-200 200zm107.244-255.2c0 67.052-72.421 68.084-72.421 92.863V300c0 6.627-5.373 12-12 12h-45.647c-6.627 0-12-5.373-12-12v-8.659c0-35.745 27.1-50.034 47.579-61.516 17.561-9.845 28.324-16.541 28.324-29.579 0-17.246-21.999-28.693-39.784-28.693-23.189 0-33.894 10.977-48.942 29.969-4.057 5.12-11.46 6.071-16.666 2.124l-27.824-21.098c-5.107-3.872-6.251-11.066-2.644-16.363C184.846 131.491 214.94 112 261.794 112c49.071 0 101.45 38.304 101.45 88.8zM298 368c0 23.159-18.841 42-42 42s-42-18.841-42-42 18.841-42 42-42 42 18.841 42 42z\"]\n};\nvar faRegistered = {\n prefix: 'far',\n iconName: 'registered',\n icon: [512, 512, [], \"f25d\", \"M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 448c-110.532 0-200-89.451-200-200 0-110.531 89.451-200 200-200 110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200zm110.442-81.791c-53.046-96.284-50.25-91.468-53.271-96.085 24.267-13.879 39.482-41.563 39.482-73.176 0-52.503-30.247-85.252-101.498-85.252h-78.667c-6.617 0-12 5.383-12 12V380c0 6.617 5.383 12 12 12h38.568c6.617 0 12-5.383 12-12v-83.663h31.958l47.515 89.303a11.98 11.98 0 0 0 10.593 6.36h42.81c9.14 0 14.914-9.799 10.51-17.791zM256.933 239.906h-33.875v-64.14h27.377c32.417 0 38.929 12.133 38.929 31.709-.001 20.913-11.518 32.431-32.431 32.431z\"]\n};\nvar faSadCry = {\n prefix: 'far',\n iconName: 'sad-cry',\n icon: [496, 512, [], \"f5b3\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm144 386.4V280c0-13.2-10.8-24-24-24s-24 10.8-24 24v151.4C315.5 447 282.8 456 248 456s-67.5-9-96-24.6V280c0-13.2-10.8-24-24-24s-24 10.8-24 24v114.4c-34.6-36-56-84.7-56-138.4 0-110.3 89.7-200 200-200s200 89.7 200 200c0 53.7-21.4 102.5-56 138.4zM205.8 234.5c4.4-2.4 6.9-7.4 6.1-12.4-4-25.2-34.2-42.1-59.8-42.1s-55.9 16.9-59.8 42.1c-.8 5 1.7 10 6.1 12.4 4.4 2.4 9.9 1.8 13.7-1.6l9.5-8.5c14.8-13.2 46.2-13.2 61 0l9.5 8.5c2.5 2.3 7.9 4.8 13.7 1.6zM344 180c-25.7 0-55.9 16.9-59.8 42.1-.8 5 1.7 10 6.1 12.4 4.5 2.4 9.9 1.8 13.7-1.6l9.5-8.5c14.8-13.2 46.2-13.2 61 0l9.5 8.5c2.5 2.2 8 4.7 13.7 1.6 4.4-2.4 6.9-7.4 6.1-12.4-3.9-25.2-34.1-42.1-59.8-42.1zm-96 92c-30.9 0-56 28.7-56 64s25.1 64 56 64 56-28.7 56-64-25.1-64-56-64z\"]\n};\nvar faSadTear = {\n prefix: 'far',\n iconName: 'sad-tear',\n icon: [496, 512, [], \"f5b4\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm8-152c-13.2 0-24 10.8-24 24s10.8 24 24 24c23.8 0 46.3 10.5 61.6 28.8 8.1 9.8 23.2 11.9 33.8 3.1 10.2-8.5 11.6-23.6 3.1-33.8C330 320.8 294.1 304 256 304zm-88-64c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm-165.6 98.8C151 290.1 126 325.4 126 342.9c0 22.7 18.8 41.1 42 41.1s42-18.4 42-41.1c0-17.5-25-52.8-36.4-68.1-2.8-3.7-8.4-3.7-11.2 0z\"]\n};\nvar faSave = {\n prefix: 'far',\n iconName: 'save',\n icon: [448, 512, [], \"f0c7\", \"M433.941 129.941l-83.882-83.882A48 48 0 0 0 316.118 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V163.882a48 48 0 0 0-14.059-33.941zM272 80v80H144V80h128zm122 352H54a6 6 0 0 1-6-6V86a6 6 0 0 1 6-6h42v104c0 13.255 10.745 24 24 24h176c13.255 0 24-10.745 24-24V83.882l78.243 78.243a6 6 0 0 1 1.757 4.243V426a6 6 0 0 1-6 6zM224 232c-48.523 0-88 39.477-88 88s39.477 88 88 88 88-39.477 88-88-39.477-88-88-88zm0 128c-22.056 0-40-17.944-40-40s17.944-40 40-40 40 17.944 40 40-17.944 40-40 40z\"]\n};\nvar faShareSquare = {\n prefix: 'far',\n iconName: 'share-square',\n icon: [576, 512, [], \"f14d\", \"M561.938 158.06L417.94 14.092C387.926-15.922 336 5.097 336 48.032v57.198c-42.45 1.88-84.03 6.55-120.76 17.99-35.17 10.95-63.07 27.58-82.91 49.42C108.22 199.2 96 232.6 96 271.94c0 61.697 33.178 112.455 84.87 144.76 37.546 23.508 85.248-12.651 71.02-55.74-15.515-47.119-17.156-70.923 84.11-78.76V336c0 42.993 51.968 63.913 81.94 33.94l143.998-144c18.75-18.74 18.75-49.14 0-67.88zM384 336V232.16C255.309 234.082 166.492 255.35 206.31 376 176.79 357.55 144 324.08 144 271.94c0-109.334 129.14-118.947 240-119.85V48l144 144-144 144zm24.74 84.493a82.658 82.658 0 0 0 20.974-9.303c7.976-4.952 18.286.826 18.286 10.214V464c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h132c6.627 0 12 5.373 12 12v4.486c0 4.917-2.987 9.369-7.569 11.152-13.702 5.331-26.396 11.537-38.05 18.585a12.138 12.138 0 0 1-6.28 1.777H54a6 6 0 0 0-6 6v340a6 6 0 0 0 6 6h340a6 6 0 0 0 6-6v-25.966c0-5.37 3.579-10.059 8.74-11.541z\"]\n};\nvar faSmile = {\n prefix: 'far',\n iconName: 'smile',\n icon: [496, 512, [], \"f118\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm4 72.6c-20.8 25-51.5 39.4-84 39.4s-63.2-14.3-84-39.4c-8.5-10.2-23.7-11.5-33.8-3.1-10.2 8.5-11.5 23.6-3.1 33.8 30 36 74.1 56.6 120.9 56.6s90.9-20.6 120.9-56.6c8.5-10.2 7.1-25.3-3.1-33.8-10.1-8.4-25.3-7.1-33.8 3.1z\"]\n};\nvar faSmileBeam = {\n prefix: 'far',\n iconName: 'smile-beam',\n icon: [496, 512, [], \"f5b8\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm84-143.4c-20.8 25-51.5 39.4-84 39.4s-63.2-14.3-84-39.4c-8.5-10.2-23.6-11.5-33.8-3.1-10.2 8.5-11.5 23.6-3.1 33.8 30 36 74.1 56.6 120.9 56.6s90.9-20.6 120.9-56.6c8.5-10.2 7.1-25.3-3.1-33.8-10.2-8.4-25.3-7.1-33.8 3.1zM136.5 211c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4s-52.7 29.3-56 71.4c-.3 3.7 2.1 7.2 5.7 8.3 3.4 1.1 7.4-.5 9.3-3.7l9.5-17zM328 152c-23.8 0-52.7 29.3-56 71.4-.3 3.7 2.1 7.2 5.7 8.3 3.5 1.1 7.4-.5 9.3-3.7l9.5-17c7.7-13.7 19.2-21.6 31.5-21.6s23.8 7.9 31.5 21.6l9.5 17c2.1 3.7 6.2 4.7 9.3 3.7 3.6-1.1 6-4.5 5.7-8.3-3.3-42.1-32.2-71.4-56-71.4z\"]\n};\nvar faSmileWink = {\n prefix: 'far',\n iconName: 'smile-wink',\n icon: [496, 512, [], \"f4da\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm117.8-146.4c-10.2-8.5-25.3-7.1-33.8 3.1-20.8 25-51.5 39.4-84 39.4s-63.2-14.3-84-39.4c-8.5-10.2-23.7-11.5-33.8-3.1-10.2 8.5-11.5 23.6-3.1 33.8 30 36 74.1 56.6 120.9 56.6s90.9-20.6 120.9-56.6c8.5-10.2 7.1-25.3-3.1-33.8zM168 240c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-60c-25.7 0-55.9 16.9-59.9 42.1-1.7 11.2 11.5 18.2 19.8 10.8l9.5-8.5c14.8-13.2 46.2-13.2 61 0l9.5 8.5c8.5 7.4 21.6.3 19.8-10.8-3.8-25.2-34-42.1-59.7-42.1z\"]\n};\nvar faSnowflake = {\n prefix: 'far',\n iconName: 'snowflake',\n icon: [448, 512, [], \"f2dc\", \"M440.1 355.2l-39.2-23 34.1-9.3c8.4-2.3 13.4-11.1 11.1-19.6l-4.1-15.5c-2.2-8.5-10.9-13.6-19.3-11.3L343 298.2 271.2 256l71.9-42.2 79.7 21.7c8.4 2.3 17-2.8 19.3-11.3l4.1-15.5c2.2-8.5-2.7-17.3-11.1-19.6l-34.1-9.3 39.2-23c7.5-4.4 10.1-14.2 5.8-21.9l-7.9-13.9c-4.3-7.7-14-10.3-21.5-5.9l-39.2 23 9.1-34.7c2.2-8.5-2.7-17.3-11.1-19.6l-15.2-4.1c-8.4-2.3-17 2.8-19.3 11.3l-21.3 81-71.9 42.2v-84.5L306 70.4c6.1-6.2 6.1-16.4 0-22.6l-11.1-11.3c-6.1-6.2-16.1-6.2-22.2 0l-24.9 25.4V16c0-8.8-7-16-15.7-16h-15.7c-8.7 0-15.7 7.2-15.7 16v46.1l-24.9-25.4c-6.1-6.2-16.1-6.2-22.2 0L142.1 48c-6.1 6.2-6.1 16.4 0 22.6l58.3 59.3v84.5l-71.9-42.2-21.3-81c-2.2-8.5-10.9-13.6-19.3-11.3L72.7 84c-8.4 2.3-13.4 11.1-11.1 19.6l9.1 34.7-39.2-23c-7.5-4.4-17.1-1.8-21.5 5.9l-7.9 13.9c-4.3 7.7-1.8 17.4 5.8 21.9l39.2 23-34.1 9.1c-8.4 2.3-13.4 11.1-11.1 19.6L6 224.2c2.2 8.5 10.9 13.6 19.3 11.3l79.7-21.7 71.9 42.2-71.9 42.2-79.7-21.7c-8.4-2.3-17 2.8-19.3 11.3l-4.1 15.5c-2.2 8.5 2.7 17.3 11.1 19.6l34.1 9.3-39.2 23c-7.5 4.4-10.1 14.2-5.8 21.9L10 391c4.3 7.7 14 10.3 21.5 5.9l39.2-23-9.1 34.7c-2.2 8.5 2.7 17.3 11.1 19.6l15.2 4.1c8.4 2.3 17-2.8 19.3-11.3l21.3-81 71.9-42.2v84.5l-58.3 59.3c-6.1 6.2-6.1 16.4 0 22.6l11.1 11.3c6.1 6.2 16.1 6.2 22.2 0l24.9-25.4V496c0 8.8 7 16 15.7 16h15.7c8.7 0 15.7-7.2 15.7-16v-46.1l24.9 25.4c6.1 6.2 16.1 6.2 22.2 0l11.1-11.3c6.1-6.2 6.1-16.4 0-22.6l-58.3-59.3v-84.5l71.9 42.2 21.3 81c2.2 8.5 10.9 13.6 19.3 11.3L375 428c8.4-2.3 13.4-11.1 11.1-19.6l-9.1-34.7 39.2 23c7.5 4.4 17.1 1.8 21.5-5.9l7.9-13.9c4.6-7.5 2.1-17.3-5.5-21.7z\"]\n};\nvar faSquare = {\n prefix: 'far',\n iconName: 'square',\n icon: [448, 512, [], \"f0c8\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V86c0-3.3 2.7-6 6-6h340c3.3 0 6 2.7 6 6v340c0 3.3-2.7 6-6 6z\"]\n};\nvar faStar = {\n prefix: 'far',\n iconName: 'star',\n icon: [576, 512, [], \"f005\", \"M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z\"]\n};\nvar faStarHalf = {\n prefix: 'far',\n iconName: 'star-half',\n icon: [576, 512, [], \"f089\", \"M288 385.3l-124.3 65.4 23.7-138.4-100.6-98 139-20.2 62.2-126V0c-11.4 0-22.8 5.9-28.7 17.8L194 150.2 47.9 171.4c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.1 23 46 46.4 33.7L288 439.6v-54.3z\"]\n};\nvar faStickyNote = {\n prefix: 'far',\n iconName: 'sticky-note',\n icon: [448, 512, [], \"f249\", \"M448 348.106V80c0-26.51-21.49-48-48-48H48C21.49 32 0 53.49 0 80v351.988c0 26.51 21.49 48 48 48h268.118a48 48 0 0 0 33.941-14.059l83.882-83.882A48 48 0 0 0 448 348.106zm-128 80v-76.118h76.118L320 428.106zM400 80v223.988H296c-13.255 0-24 10.745-24 24v104H48V80h352z\"]\n};\nvar faStopCircle = {\n prefix: 'far',\n iconName: 'stop-circle',\n icon: [512, 512, [], \"f28d\", \"M504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256zm296-80v160c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16z\"]\n};\nvar faSun = {\n prefix: 'far',\n iconName: 'sun',\n icon: [512, 512, [], \"f185\", \"M494.2 221.9l-59.8-40.5 13.7-71c2.6-13.2-1.6-26.8-11.1-36.4-9.6-9.5-23.2-13.7-36.2-11.1l-70.9 13.7-40.4-59.9c-15.1-22.3-51.9-22.3-67 0l-40.4 59.9-70.8-13.7C98 60.4 84.5 64.5 75 74.1c-9.5 9.6-13.7 23.1-11.1 36.3l13.7 71-59.8 40.5C6.6 229.5 0 242 0 255.5s6.7 26 17.8 33.5l59.8 40.5-13.7 71c-2.6 13.2 1.6 26.8 11.1 36.3 9.5 9.5 22.9 13.7 36.3 11.1l70.8-13.7 40.4 59.9C230 505.3 242.6 512 256 512s26-6.7 33.5-17.8l40.4-59.9 70.9 13.7c13.4 2.7 26.8-1.6 36.3-11.1 9.5-9.5 13.6-23.1 11.1-36.3l-13.7-71 59.8-40.5c11.1-7.5 17.8-20.1 17.8-33.5-.1-13.6-6.7-26.1-17.9-33.7zm-112.9 85.6l17.6 91.2-91-17.6L256 458l-51.9-77-90.9 17.6 17.6-91.2-76.8-52 76.8-52-17.6-91.2 91 17.6L256 53l51.9 76.9 91-17.6-17.6 91.1 76.8 52-76.8 52.1zM256 152c-57.3 0-104 46.7-104 104s46.7 104 104 104 104-46.7 104-104-46.7-104-104-104zm0 160c-30.9 0-56-25.1-56-56s25.1-56 56-56 56 25.1 56 56-25.1 56-56 56z\"]\n};\nvar faSurprise = {\n prefix: 'far',\n iconName: 'surprise',\n icon: [496, 512, [], \"f5c2\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm0-176c-35.3 0-64 28.7-64 64s28.7 64 64 64 64-28.7 64-64-28.7-64-64-64zm-48-72c0-17.7-14.3-32-32-32s-32 14.3-32 32 14.3 32 32 32 32-14.3 32-32zm128-32c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z\"]\n};\nvar faThumbsDown = {\n prefix: 'far',\n iconName: 'thumbs-down',\n icon: [512, 512, [], \"f165\", \"M466.27 225.31c4.674-22.647.864-44.538-8.99-62.99 2.958-23.868-4.021-48.565-17.34-66.99C438.986 39.423 404.117 0 327 0c-7 0-15 .01-22.22.01C201.195.01 168.997 40 128 40h-10.845c-5.64-4.975-13.042-8-21.155-8H32C14.327 32 0 46.327 0 64v240c0 17.673 14.327 32 32 32h64c11.842 0 22.175-6.438 27.708-16h7.052c19.146 16.953 46.013 60.653 68.76 83.4 13.667 13.667 10.153 108.6 71.76 108.6 57.58 0 95.27-31.936 95.27-104.73 0-18.41-3.93-33.73-8.85-46.54h36.48c48.602 0 85.82-41.565 85.82-85.58 0-19.15-4.96-34.99-13.73-49.84zM64 296c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm330.18 16.73H290.19c0 37.82 28.36 55.37 28.36 94.54 0 23.75 0 56.73-47.27 56.73-18.91-18.91-9.46-66.18-37.82-94.54C206.9 342.89 167.28 272 138.92 272H128V85.83c53.611 0 100.001-37.82 171.64-37.82h37.82c35.512 0 60.82 17.12 53.12 65.9 15.2 8.16 26.5 36.44 13.94 57.57 21.581 20.384 18.699 51.065 5.21 65.62 9.45 0 22.36 18.91 22.27 37.81-.09 18.91-16.71 37.82-37.82 37.82z\"]\n};\nvar faThumbsUp = {\n prefix: 'far',\n iconName: 'thumbs-up',\n icon: [512, 512, [], \"f164\", \"M466.27 286.69C475.04 271.84 480 256 480 236.85c0-44.015-37.218-85.58-85.82-85.58H357.7c4.92-12.81 8.85-28.13 8.85-46.54C366.55 31.936 328.86 0 271.28 0c-61.607 0-58.093 94.933-71.76 108.6-22.747 22.747-49.615 66.447-68.76 83.4H32c-17.673 0-32 14.327-32 32v240c0 17.673 14.327 32 32 32h64c14.893 0 27.408-10.174 30.978-23.95 44.509 1.001 75.06 39.94 177.802 39.94 7.22 0 15.22.01 22.22.01 77.117 0 111.986-39.423 112.94-95.33 13.319-18.425 20.299-43.122 17.34-66.99 9.854-18.452 13.664-40.343 8.99-62.99zm-61.75 53.83c12.56 21.13 1.26 49.41-13.94 57.57 7.7 48.78-17.608 65.9-53.12 65.9h-37.82c-71.639 0-118.029-37.82-171.64-37.82V240h10.92c28.36 0 67.98-70.89 94.54-97.46 28.36-28.36 18.91-75.63 37.82-94.54 47.27 0 47.27 32.98 47.27 56.73 0 39.17-28.36 56.72-28.36 94.54h103.99c21.11 0 37.73 18.91 37.82 37.82.09 18.9-12.82 37.81-22.27 37.81 13.489 14.555 16.371 45.236-5.21 65.62zM88 432c0 13.255-10.745 24-24 24s-24-10.745-24-24 10.745-24 24-24 24 10.745 24 24z\"]\n};\nvar faTimesCircle = {\n prefix: 'far',\n iconName: 'times-circle',\n icon: [512, 512, [], \"f057\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z\"]\n};\nvar faTired = {\n prefix: 'far',\n iconName: 'tired',\n icon: [496, 512, [], \"f5c8\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm129.1-303.8c-3.8-4.4-10.3-5.4-15.3-2.5l-80 48c-3.6 2.2-5.8 6.1-5.8 10.3s2.2 8.1 5.8 10.3l80 48c5.4 3.2 11.8 1.6 15.3-2.5 3.8-4.5 3.9-11 .1-15.5L343.6 208l33.6-40.3c3.8-4.5 3.7-11.1-.1-15.5zM220 208c0-4.2-2.2-8.1-5.8-10.3l-80-48c-5-3-11.5-1.9-15.3 2.5-3.8 4.5-3.9 11-.1 15.5l33.6 40.3-33.6 40.3c-3.8 4.5-3.7 11 .1 15.5 3.5 4.1 9.9 5.7 15.3 2.5l80-48c3.6-2.2 5.8-6.1 5.8-10.3zm28 64c-45.4 0-100.9 38.3-107.8 93.3-1.5 11.8 6.9 21.6 15.5 17.9C178.4 373.5 212 368 248 368s69.6 5.5 92.3 15.2c8.5 3.7 17-6 15.5-17.9-6.9-55-62.4-93.3-107.8-93.3z\"]\n};\nvar faTrashAlt = {\n prefix: 'far',\n iconName: 'trash-alt',\n icon: [448, 512, [], \"f2ed\", \"M268 416h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12zM432 80h-82.41l-34-56.7A48 48 0 0 0 274.41 0H173.59a48 48 0 0 0-41.16 23.3L98.41 80H16A16 16 0 0 0 0 96v16a16 16 0 0 0 16 16h16v336a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128h16a16 16 0 0 0 16-16V96a16 16 0 0 0-16-16zM171.84 50.91A6 6 0 0 1 177 48h94a6 6 0 0 1 5.15 2.91L293.61 80H154.39zM368 464H80V128h288zm-212-48h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12z\"]\n};\nvar faUser = {\n prefix: 'far',\n iconName: 'user',\n icon: [448, 512, [], \"f007\", \"M313.6 304c-28.7 0-42.5 16-89.6 16-47.1 0-60.8-16-89.6-16C60.2 304 0 364.2 0 438.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-25.6c0-74.2-60.2-134.4-134.4-134.4zM400 464H48v-25.6c0-47.6 38.8-86.4 86.4-86.4 14.6 0 38.3 16 89.6 16 51.7 0 74.9-16 89.6-16 47.6 0 86.4 38.8 86.4 86.4V464zM224 288c79.5 0 144-64.5 144-144S303.5 0 224 0 80 64.5 80 144s64.5 144 144 144zm0-240c52.9 0 96 43.1 96 96s-43.1 96-96 96-96-43.1-96-96 43.1-96 96-96z\"]\n};\nvar faUserCircle = {\n prefix: 'far',\n iconName: 'user-circle',\n icon: [496, 512, [], \"f2bd\", \"M248 104c-53 0-96 43-96 96s43 96 96 96 96-43 96-96-43-96-96-96zm0 144c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm0-240C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-49.7 0-95.1-18.3-130.1-48.4 14.9-23 40.4-38.6 69.6-39.5 20.8 6.4 40.6 9.6 60.5 9.6s39.7-3.1 60.5-9.6c29.2 1 54.7 16.5 69.6 39.5-35 30.1-80.4 48.4-130.1 48.4zm162.7-84.1c-24.4-31.4-62.1-51.9-105.1-51.9-10.2 0-26 9.6-57.6 9.6-31.5 0-47.4-9.6-57.6-9.6-42.9 0-80.6 20.5-105.1 51.9C61.9 339.2 48 299.2 48 256c0-110.3 89.7-200 200-200s200 89.7 200 200c0 43.2-13.9 83.2-37.3 115.9z\"]\n};\nvar faWindowClose = {\n prefix: 'far',\n iconName: 'window-close',\n icon: [512, 512, [], \"f410\", \"M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm0 394c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V86c0-3.3 2.7-6 6-6h404c3.3 0 6 2.7 6 6v340zM356.5 194.6L295.1 256l61.4 61.4c4.6 4.6 4.6 12.1 0 16.8l-22.3 22.3c-4.6 4.6-12.1 4.6-16.8 0L256 295.1l-61.4 61.4c-4.6 4.6-12.1 4.6-16.8 0l-22.3-22.3c-4.6-4.6-4.6-12.1 0-16.8l61.4-61.4-61.4-61.4c-4.6-4.6-4.6-12.1 0-16.8l22.3-22.3c4.6-4.6 12.1-4.6 16.8 0l61.4 61.4 61.4-61.4c4.6-4.6 12.1-4.6 16.8 0l22.3 22.3c4.7 4.6 4.7 12.1 0 16.8z\"]\n};\nvar faWindowMaximize = {\n prefix: 'far',\n iconName: 'window-maximize',\n icon: [512, 512, [], \"f2d0\", \"M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm0 394c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V192h416v234z\"]\n};\nvar faWindowMinimize = {\n prefix: 'far',\n iconName: 'window-minimize',\n icon: [512, 512, [], \"f2d1\", \"M480 480H32c-17.7 0-32-14.3-32-32s14.3-32 32-32h448c17.7 0 32 14.3 32 32s-14.3 32-32 32z\"]\n};\nvar faWindowRestore = {\n prefix: 'far',\n iconName: 'window-restore',\n icon: [512, 512, [], \"f2d2\", \"M464 0H144c-26.5 0-48 21.5-48 48v48H48c-26.5 0-48 21.5-48 48v320c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h48c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-96 464H48V256h320v208zm96-96h-48V144c0-26.5-21.5-48-48-48H144V48h320v320z\"]\n};\nvar _iconsCache = {\n faAddressBook: faAddressBook,\n faAddressCard: faAddressCard,\n faAngry: faAngry,\n faArrowAltCircleDown: faArrowAltCircleDown,\n faArrowAltCircleLeft: faArrowAltCircleLeft,\n faArrowAltCircleRight: faArrowAltCircleRight,\n faArrowAltCircleUp: faArrowAltCircleUp,\n faBell: faBell,\n faBellSlash: faBellSlash,\n faBookmark: faBookmark,\n faBuilding: faBuilding,\n faCalendar: faCalendar,\n faCalendarAlt: faCalendarAlt,\n faCalendarCheck: faCalendarCheck,\n faCalendarMinus: faCalendarMinus,\n faCalendarPlus: faCalendarPlus,\n faCalendarTimes: faCalendarTimes,\n faCaretSquareDown: faCaretSquareDown,\n faCaretSquareLeft: faCaretSquareLeft,\n faCaretSquareRight: faCaretSquareRight,\n faCaretSquareUp: faCaretSquareUp,\n faChartBar: faChartBar,\n faCheckCircle: faCheckCircle,\n faCheckSquare: faCheckSquare,\n faCircle: faCircle,\n faClipboard: faClipboard,\n faClock: faClock,\n faClone: faClone,\n faClosedCaptioning: faClosedCaptioning,\n faComment: faComment,\n faCommentAlt: faCommentAlt,\n faCommentDots: faCommentDots,\n faComments: faComments,\n faCompass: faCompass,\n faCopy: faCopy,\n faCopyright: faCopyright,\n faCreditCard: faCreditCard,\n faDizzy: faDizzy,\n faDotCircle: faDotCircle,\n faEdit: faEdit,\n faEnvelope: faEnvelope,\n faEnvelopeOpen: faEnvelopeOpen,\n faEye: faEye,\n faEyeSlash: faEyeSlash,\n faFile: faFile,\n faFileAlt: faFileAlt,\n faFileArchive: faFileArchive,\n faFileAudio: faFileAudio,\n faFileCode: faFileCode,\n faFileExcel: faFileExcel,\n faFileImage: faFileImage,\n faFilePdf: faFilePdf,\n faFilePowerpoint: faFilePowerpoint,\n faFileVideo: faFileVideo,\n faFileWord: faFileWord,\n faFlag: faFlag,\n faFlushed: faFlushed,\n faFolder: faFolder,\n faFolderOpen: faFolderOpen,\n faFontAwesomeLogoFull: faFontAwesomeLogoFull,\n faFrown: faFrown,\n faFrownOpen: faFrownOpen,\n faFutbol: faFutbol,\n faGem: faGem,\n faGrimace: faGrimace,\n faGrin: faGrin,\n faGrinAlt: faGrinAlt,\n faGrinBeam: faGrinBeam,\n faGrinBeamSweat: faGrinBeamSweat,\n faGrinHearts: faGrinHearts,\n faGrinSquint: faGrinSquint,\n faGrinSquintTears: faGrinSquintTears,\n faGrinStars: faGrinStars,\n faGrinTears: faGrinTears,\n faGrinTongue: faGrinTongue,\n faGrinTongueSquint: faGrinTongueSquint,\n faGrinTongueWink: faGrinTongueWink,\n faGrinWink: faGrinWink,\n faHandLizard: faHandLizard,\n faHandPaper: faHandPaper,\n faHandPeace: faHandPeace,\n faHandPointDown: faHandPointDown,\n faHandPointLeft: faHandPointLeft,\n faHandPointRight: faHandPointRight,\n faHandPointUp: faHandPointUp,\n faHandPointer: faHandPointer,\n faHandRock: faHandRock,\n faHandScissors: faHandScissors,\n faHandSpock: faHandSpock,\n faHandshake: faHandshake,\n faHdd: faHdd,\n faHeart: faHeart,\n faHospital: faHospital,\n faHourglass: faHourglass,\n faIdBadge: faIdBadge,\n faIdCard: faIdCard,\n faImage: faImage,\n faImages: faImages,\n faKeyboard: faKeyboard,\n faKiss: faKiss,\n faKissBeam: faKissBeam,\n faKissWinkHeart: faKissWinkHeart,\n faLaugh: faLaugh,\n faLaughBeam: faLaughBeam,\n faLaughSquint: faLaughSquint,\n faLaughWink: faLaughWink,\n faLemon: faLemon,\n faLifeRing: faLifeRing,\n faLightbulb: faLightbulb,\n faListAlt: faListAlt,\n faMap: faMap,\n faMeh: faMeh,\n faMehBlank: faMehBlank,\n faMehRollingEyes: faMehRollingEyes,\n faMinusSquare: faMinusSquare,\n faMoneyBillAlt: faMoneyBillAlt,\n faMoon: faMoon,\n faNewspaper: faNewspaper,\n faObjectGroup: faObjectGroup,\n faObjectUngroup: faObjectUngroup,\n faPaperPlane: faPaperPlane,\n faPauseCircle: faPauseCircle,\n faPlayCircle: faPlayCircle,\n faPlusSquare: faPlusSquare,\n faQuestionCircle: faQuestionCircle,\n faRegistered: faRegistered,\n faSadCry: faSadCry,\n faSadTear: faSadTear,\n faSave: faSave,\n faShareSquare: faShareSquare,\n faSmile: faSmile,\n faSmileBeam: faSmileBeam,\n faSmileWink: faSmileWink,\n faSnowflake: faSnowflake,\n faSquare: faSquare,\n faStar: faStar,\n faStarHalf: faStarHalf,\n faStickyNote: faStickyNote,\n faStopCircle: faStopCircle,\n faSun: faSun,\n faSurprise: faSurprise,\n faThumbsDown: faThumbsDown,\n faThumbsUp: faThumbsUp,\n faTimesCircle: faTimesCircle,\n faTired: faTired,\n faTrashAlt: faTrashAlt,\n faUser: faUser,\n faUserCircle: faUserCircle,\n faWindowClose: faWindowClose,\n faWindowMaximize: faWindowMaximize,\n faWindowMinimize: faWindowMinimize,\n faWindowRestore: faWindowRestore\n};\n\nexport { _iconsCache as far, prefix, faAddressBook, faAddressCard, faAngry, faArrowAltCircleDown, faArrowAltCircleLeft, faArrowAltCircleRight, faArrowAltCircleUp, faBell, faBellSlash, faBookmark, faBuilding, faCalendar, faCalendarAlt, faCalendarCheck, faCalendarMinus, faCalendarPlus, faCalendarTimes, faCaretSquareDown, faCaretSquareLeft, faCaretSquareRight, faCaretSquareUp, faChartBar, faCheckCircle, faCheckSquare, faCircle, faClipboard, faClock, faClone, faClosedCaptioning, faComment, faCommentAlt, faCommentDots, faComments, faCompass, faCopy, faCopyright, faCreditCard, faDizzy, faDotCircle, faEdit, faEnvelope, faEnvelopeOpen, faEye, faEyeSlash, faFile, faFileAlt, faFileArchive, faFileAudio, faFileCode, faFileExcel, faFileImage, faFilePdf, faFilePowerpoint, faFileVideo, faFileWord, faFlag, faFlushed, faFolder, faFolderOpen, faFontAwesomeLogoFull, faFrown, faFrownOpen, faFutbol, faGem, faGrimace, faGrin, faGrinAlt, faGrinBeam, faGrinBeamSweat, faGrinHearts, faGrinSquint, faGrinSquintTears, faGrinStars, faGrinTears, faGrinTongue, faGrinTongueSquint, faGrinTongueWink, faGrinWink, faHandLizard, faHandPaper, faHandPeace, faHandPointDown, faHandPointLeft, faHandPointRight, faHandPointUp, faHandPointer, faHandRock, faHandScissors, faHandSpock, faHandshake, faHdd, faHeart, faHospital, faHourglass, faIdBadge, faIdCard, faImage, faImages, faKeyboard, faKiss, faKissBeam, faKissWinkHeart, faLaugh, faLaughBeam, faLaughSquint, faLaughWink, faLemon, faLifeRing, faLightbulb, faListAlt, faMap, faMeh, faMehBlank, faMehRollingEyes, faMinusSquare, faMoneyBillAlt, faMoon, faNewspaper, faObjectGroup, faObjectUngroup, faPaperPlane, faPauseCircle, faPlayCircle, faPlusSquare, faQuestionCircle, faRegistered, faSadCry, faSadTear, faSave, faShareSquare, faSmile, faSmileBeam, faSmileWink, faSnowflake, faSquare, faStar, faStarHalf, faStickyNote, faStopCircle, faSun, faSurprise, faThumbsDown, faThumbsUp, faTimesCircle, faTired, faTrashAlt, faUser, faUserCircle, faWindowClose, faWindowMaximize, faWindowMinimize, faWindowRestore };\n", + "var prefix = \"fas\";\nvar faAd = {\n prefix: 'fas',\n iconName: 'ad',\n icon: [512, 512, [], \"f641\", \"M157.52 272h36.96L176 218.78 157.52 272zM352 256c-13.23 0-24 10.77-24 24s10.77 24 24 24 24-10.77 24-24-10.77-24-24-24zM464 64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM250.58 352h-16.94c-6.81 0-12.88-4.32-15.12-10.75L211.15 320h-70.29l-7.38 21.25A16 16 0 0 1 118.36 352h-16.94c-11.01 0-18.73-10.85-15.12-21.25L140 176.12A23.995 23.995 0 0 1 162.67 160h26.66A23.99 23.99 0 0 1 212 176.13l53.69 154.62c3.61 10.4-4.11 21.25-15.11 21.25zM424 336c0 8.84-7.16 16-16 16h-16c-4.85 0-9.04-2.27-11.98-5.68-8.62 3.66-18.09 5.68-28.02 5.68-39.7 0-72-32.3-72-72s32.3-72 72-72c8.46 0 16.46 1.73 24 4.42V176c0-8.84 7.16-16 16-16h16c8.84 0 16 7.16 16 16v160z\"]\n};\nvar faAddressBook = {\n prefix: 'fas',\n iconName: 'address-book',\n icon: [448, 512, [], \"f2b9\", \"M436 160c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20zm-228-32c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zm112 236.8c0 10.6-10 19.2-22.4 19.2H118.4C106 384 96 375.4 96 364.8v-19.2c0-31.8 30.1-57.6 67.2-57.6h5c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h5c37.1 0 67.2 25.8 67.2 57.6v19.2z\"]\n};\nvar faAddressCard = {\n prefix: 'fas',\n iconName: 'address-card',\n icon: [576, 512, [], \"f2bb\", \"M528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-352 96c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zm112 236.8c0 10.6-10 19.2-22.4 19.2H86.4C74 384 64 375.4 64 364.8v-19.2c0-31.8 30.1-57.6 67.2-57.6h5c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h5c37.1 0 67.2 25.8 67.2 57.6v19.2zM512 312c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16zm0-64c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16zm0-64c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16z\"]\n};\nvar faAdjust = {\n prefix: 'fas',\n iconName: 'adjust',\n icon: [512, 512, [], \"f042\", \"M8 256c0 136.966 111.033 248 248 248s248-111.034 248-248S392.966 8 256 8 8 119.033 8 256zm248 184V72c101.705 0 184 82.311 184 184 0 101.705-82.311 184-184 184z\"]\n};\nvar faAirFreshener = {\n prefix: 'fas',\n iconName: 'air-freshener',\n icon: [384, 512, [], \"f5d0\", \"M378.94 321.41L284.7 224h49.22c15.3 0 23.66-16.6 13.86-27.53L234.45 69.96c3.43-6.61 5.55-14 5.55-21.96 0-26.51-21.49-48-48-48s-48 21.49-48 48c0 7.96 2.12 15.35 5.55 21.96L36.22 196.47C26.42 207.4 34.78 224 50.08 224H99.3L5.06 321.41C-6.69 333.56 3.34 352 21.7 352H160v32H48c-8.84 0-16 7.16-16 16v96c0 8.84 7.16 16 16 16h288c8.84 0 16-7.16 16-16v-96c0-8.84-7.16-16-16-16H224v-32h138.3c18.36 0 28.39-18.44 16.64-30.59zM192 31.98c8.85 0 16.02 7.17 16.02 16.02 0 8.84-7.17 16.02-16.02 16.02S175.98 56.84 175.98 48c0-8.85 7.17-16.02 16.02-16.02zM304 432v32H80v-32h224z\"]\n};\nvar faAlignCenter = {\n prefix: 'fas',\n iconName: 'align-center',\n icon: [448, 512, [], \"f037\", \"M352 44v40c0 8.837-7.163 16-16 16H112c-8.837 0-16-7.163-16-16V44c0-8.837 7.163-16 16-16h224c8.837 0 16 7.163 16 16zM16 228h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 256h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm320-200H112c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16h224c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16z\"]\n};\nvar faAlignJustify = {\n prefix: 'fas',\n iconName: 'align-justify',\n icon: [448, 512, [], \"f039\", \"M0 84V44c0-8.837 7.163-16 16-16h416c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16zm16 144h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 256h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0-128h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z\"]\n};\nvar faAlignLeft = {\n prefix: 'fas',\n iconName: 'align-left',\n icon: [448, 512, [], \"f036\", \"M288 44v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16V44c0-8.837 7.163-16 16-16h256c8.837 0 16 7.163 16 16zM0 172v40c0 8.837 7.163 16 16 16h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16zm16 312h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm256-200H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16z\"]\n};\nvar faAlignRight = {\n prefix: 'fas',\n iconName: 'align-right',\n icon: [448, 512, [], \"f038\", \"M160 84V44c0-8.837 7.163-16 16-16h256c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H176c-8.837 0-16-7.163-16-16zM16 228h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 256h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm160-128h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H176c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z\"]\n};\nvar faAllergies = {\n prefix: 'fas',\n iconName: 'allergies',\n icon: [448, 512, [], \"f461\", \"M416 112c-17.6 0-32 14.4-32 32v72c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8V64c0-17.6-14.4-32-32-32s-32 14.4-32 32v152c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8V32c0-17.6-14.4-32-32-32s-32 14.4-32 32v184c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8V64c0-17.6-14.4-32-32-32S96 46.4 96 64v241l-23.6-32.5c-13-17.9-38-21.8-55.9-8.8s-21.8 38-8.8 55.9l125.6 172.7c9 12.4 23.5 19.8 38.8 19.8h197.6c22.3 0 41.6-15.3 46.7-37l26.5-112.7c3.2-13.7 4.9-28.3 5.1-42.3V144c0-17.6-14.4-32-32-32zM176 416c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm0-96c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm64 128c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm0-96c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm64 32c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm32 64c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm32-128c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16z\"]\n};\nvar faAmbulance = {\n prefix: 'fas',\n iconName: 'ambulance',\n icon: [640, 512, [], \"f0f9\", \"M624 352h-16V243.9c0-12.7-5.1-24.9-14.1-33.9L494 110.1c-9-9-21.2-14.1-33.9-14.1H416V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h16c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM160 464c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm144-248c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8v48zm176 248c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-208H416V144h44.1l99.9 99.9V256z\"]\n};\nvar faAmericanSignLanguageInterpreting = {\n prefix: 'fas',\n iconName: 'american-sign-language-interpreting',\n icon: [640, 512, [], \"f2a3\", \"M290.547 189.039c-20.295-10.149-44.147-11.199-64.739-3.89 42.606 0 71.208 20.475 85.578 50.576 8.576 17.899-5.148 38.071-23.617 38.071 18.429 0 32.211 20.136 23.617 38.071-14.725 30.846-46.123 50.854-80.298 50.854-.557 0-94.471-8.615-94.471-8.615l-66.406 33.347c-9.384 4.693-19.815.379-23.895-7.781L1.86 290.747c-4.167-8.615-1.111-18.897 6.946-23.621l58.072-33.069L108 159.861c6.39-57.245 34.731-109.767 79.743-146.726 11.391-9.448 28.341-7.781 37.51 3.613 9.446 11.394 7.78 28.067-3.612 37.516-12.503 10.559-23.618 22.509-32.509 35.57 21.672-14.729 46.679-24.732 74.186-28.067 14.725-1.945 28.063 8.336 29.73 23.065 1.945 14.728-8.336 28.067-23.062 29.734-16.116 1.945-31.12 7.503-44.178 15.284 26.114-5.713 58.712-3.138 88.079 11.115 13.336 6.669 18.893 22.509 12.224 35.848-6.389 13.06-22.504 18.617-35.564 12.226zm-27.229 69.472c-6.112-12.505-18.338-20.286-32.231-20.286a35.46 35.46 0 0 0-35.565 35.57c0 21.428 17.808 35.57 35.565 35.57 13.893 0 26.119-7.781 32.231-20.286 4.446-9.449 13.614-15.006 23.339-15.284-9.725-.277-18.893-5.835-23.339-15.284zm374.821-37.237c4.168 8.615 1.111 18.897-6.946 23.621l-58.071 33.069L532 352.16c-6.39 57.245-34.731 109.767-79.743 146.726-10.932 9.112-27.799 8.144-37.51-3.613-9.446-11.394-7.78-28.067 3.613-37.516 12.503-10.559 23.617-22.509 32.508-35.57-21.672 14.729-46.679 24.732-74.186 28.067-10.021 2.506-27.552-5.643-29.73-23.065-1.945-14.728 8.336-28.067 23.062-29.734 16.116-1.946 31.12-7.503 44.178-15.284-26.114 5.713-58.712 3.138-88.079-11.115-13.336-6.669-18.893-22.509-12.224-35.848 6.389-13.061 22.505-18.619 35.565-12.227 20.295 10.149 44.147 11.199 64.739 3.89-42.606 0-71.208-20.475-85.578-50.576-8.576-17.899 5.148-38.071 23.617-38.071-18.429 0-32.211-20.136-23.617-38.071 14.033-29.396 44.039-50.887 81.966-50.854l92.803 8.615 66.406-33.347c9.408-4.704 19.828-.354 23.894 7.781l44.455 88.926zm-229.227-18.618c-13.893 0-26.119 7.781-32.231 20.286-4.446 9.449-13.614 15.006-23.339 15.284 9.725.278 18.893 5.836 23.339 15.284 6.112 12.505 18.338 20.286 32.231 20.286a35.46 35.46 0 0 0 35.565-35.57c0-21.429-17.808-35.57-35.565-35.57z\"]\n};\nvar faAnchor = {\n prefix: 'fas',\n iconName: 'anchor',\n icon: [576, 512, [], \"f13d\", \"M12.971 352h32.394C67.172 454.735 181.944 512 288 512c106.229 0 220.853-57.38 242.635-160h32.394c10.691 0 16.045-12.926 8.485-20.485l-67.029-67.029c-4.686-4.686-12.284-4.686-16.971 0l-67.029 67.029c-7.56 7.56-2.206 20.485 8.485 20.485h35.146c-20.29 54.317-84.963 86.588-144.117 94.015V256h52c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-52v-5.47c37.281-13.178 63.995-48.725 64-90.518C384.005 43.772 341.605.738 289.37.01 235.723-.739 192 42.525 192 96c0 41.798 26.716 77.35 64 90.53V192h-52c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h52v190.015c-58.936-7.399-123.82-39.679-144.117-94.015h35.146c10.691 0 16.045-12.926 8.485-20.485l-67.029-67.029c-4.686-4.686-12.284-4.686-16.971 0L4.485 331.515C-3.074 339.074 2.28 352 12.971 352zM288 64c17.645 0 32 14.355 32 32s-14.355 32-32 32-32-14.355-32-32 14.355-32 32-32z\"]\n};\nvar faAngleDoubleDown = {\n prefix: 'fas',\n iconName: 'angle-double-down',\n icon: [320, 512, [], \"f103\", \"M143 256.3L7 120.3c-9.4-9.4-9.4-24.6 0-33.9l22.6-22.6c9.4-9.4 24.6-9.4 33.9 0l96.4 96.4 96.4-96.4c9.4-9.4 24.6-9.4 33.9 0L313 86.3c9.4 9.4 9.4 24.6 0 33.9l-136 136c-9.4 9.5-24.6 9.5-34 .1zm34 192l136-136c9.4-9.4 9.4-24.6 0-33.9l-22.6-22.6c-9.4-9.4-24.6-9.4-33.9 0L160 352.1l-96.4-96.4c-9.4-9.4-24.6-9.4-33.9 0L7 278.3c-9.4 9.4-9.4 24.6 0 33.9l136 136c9.4 9.5 24.6 9.5 34 .1z\"]\n};\nvar faAngleDoubleLeft = {\n prefix: 'fas',\n iconName: 'angle-double-left',\n icon: [448, 512, [], \"f100\", \"M223.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L319.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L393.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34zm-192 34l136 136c9.4 9.4 24.6 9.4 33.9 0l22.6-22.6c9.4-9.4 9.4-24.6 0-33.9L127.9 256l96.4-96.4c9.4-9.4 9.4-24.6 0-33.9L201.7 103c-9.4-9.4-24.6-9.4-33.9 0l-136 136c-9.5 9.4-9.5 24.6-.1 34z\"]\n};\nvar faAngleDoubleRight = {\n prefix: 'fas',\n iconName: 'angle-double-right',\n icon: [448, 512, [], \"f101\", \"M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34zm192-34l-136-136c-9.4-9.4-24.6-9.4-33.9 0l-22.6 22.6c-9.4 9.4-9.4 24.6 0 33.9l96.4 96.4-96.4 96.4c-9.4 9.4-9.4 24.6 0 33.9l22.6 22.6c9.4 9.4 24.6 9.4 33.9 0l136-136c9.4-9.2 9.4-24.4 0-33.8z\"]\n};\nvar faAngleDoubleUp = {\n prefix: 'fas',\n iconName: 'angle-double-up',\n icon: [320, 512, [], \"f102\", \"M177 255.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 351.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 425.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1zm-34-192L7 199.7c-9.4 9.4-9.4 24.6 0 33.9l22.6 22.6c9.4 9.4 24.6 9.4 33.9 0l96.4-96.4 96.4 96.4c9.4 9.4 24.6 9.4 33.9 0l22.6-22.6c9.4-9.4 9.4-24.6 0-33.9l-136-136c-9.2-9.4-24.4-9.4-33.8 0z\"]\n};\nvar faAngleDown = {\n prefix: 'fas',\n iconName: 'angle-down',\n icon: [320, 512, [], \"f107\", \"M143 352.3L7 216.3c-9.4-9.4-9.4-24.6 0-33.9l22.6-22.6c9.4-9.4 24.6-9.4 33.9 0l96.4 96.4 96.4-96.4c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9l-136 136c-9.2 9.4-24.4 9.4-33.8 0z\"]\n};\nvar faAngleLeft = {\n prefix: 'fas',\n iconName: 'angle-left',\n icon: [256, 512, [], \"f104\", \"M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z\"]\n};\nvar faAngleRight = {\n prefix: 'fas',\n iconName: 'angle-right',\n icon: [256, 512, [], \"f105\", \"M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z\"]\n};\nvar faAngleUp = {\n prefix: 'fas',\n iconName: 'angle-up',\n icon: [320, 512, [], \"f106\", \"M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z\"]\n};\nvar faAngry = {\n prefix: 'fas',\n iconName: 'angry',\n icon: [496, 512, [], \"f556\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM136 240c0-9.3 4.1-17.5 10.5-23.4l-31-9.3c-8.5-2.5-13.3-11.5-10.7-19.9 2.5-8.5 11.4-13.2 19.9-10.7l80 24c8.5 2.5 13.3 11.5 10.7 19.9-2.1 6.9-8.4 11.4-15.3 11.4-.5 0-1.1-.2-1.7-.2.7 2.7 1.7 5.3 1.7 8.2 0 17.7-14.3 32-32 32S136 257.7 136 240zm168 154.2c-27.8-33.4-84.2-33.4-112.1 0-13.5 16.3-38.2-4.2-24.6-20.5 20-24 49.4-37.8 80.6-37.8s60.6 13.8 80.6 37.8c13.8 16.5-11.1 36.6-24.5 20.5zm76.6-186.9l-31 9.3c6.3 5.8 10.5 14.1 10.5 23.4 0 17.7-14.3 32-32 32s-32-14.3-32-32c0-2.9.9-5.6 1.7-8.2-.6.1-1.1.2-1.7.2-6.9 0-13.2-4.5-15.3-11.4-2.5-8.5 2.3-17.4 10.7-19.9l80-24c8.4-2.5 17.4 2.3 19.9 10.7 2.5 8.5-2.3 17.4-10.8 19.9z\"]\n};\nvar faAnkh = {\n prefix: 'fas',\n iconName: 'ankh',\n icon: [320, 512, [], \"f644\", \"M296 256h-44.62C272.46 222.01 288 181.65 288 144 288 55.63 230.69 0 160 0S32 55.63 32 144c0 37.65 15.54 78.01 36.62 112H24c-13.25 0-24 10.74-24 24v32c0 13.25 10.75 24 24 24h96v152c0 13.25 10.75 24 24 24h32c13.25 0 24-10.75 24-24V336h96c13.25 0 24-10.75 24-24v-32c0-13.26-10.75-24-24-24zM160 80c29.61 0 48 24.52 48 64 0 34.66-27.14 78.14-48 100.87-20.86-22.72-48-66.21-48-100.87 0-39.48 18.39-64 48-64z\"]\n};\nvar faAppleAlt = {\n prefix: 'fas',\n iconName: 'apple-alt',\n icon: [448, 512, [], \"f5d1\", \"M350.85 129c25.97 4.67 47.27 18.67 63.92 42 14.65 20.67 24.64 46.67 29.96 78 4.67 28.67 4.32 57.33-1 86-7.99 47.33-23.97 87-47.94 119-28.64 38.67-64.59 58-107.87 58-10.66 0-22.3-3.33-34.96-10-8.66-5.33-18.31-8-28.97-8s-20.3 2.67-28.97 8c-12.66 6.67-24.3 10-34.96 10-43.28 0-79.23-19.33-107.87-58-23.97-32-39.95-71.67-47.94-119-5.32-28.67-5.67-57.33-1-86 5.32-31.33 15.31-57.33 29.96-78 16.65-23.33 37.95-37.33 63.92-42 15.98-2.67 37.95-.33 65.92 7 23.97 6.67 44.28 14.67 60.93 24 16.65-9.33 36.96-17.33 60.93-24 27.98-7.33 49.96-9.67 65.94-7zm-54.94-41c-9.32 8.67-21.65 15-36.96 19-10.66 3.33-22.3 5-34.96 5l-14.98-1c-1.33-9.33-1.33-20 0-32 2.67-24 10.32-42.33 22.97-55 9.32-8.67 21.65-15 36.96-19 10.66-3.33 22.3-5 34.96-5l14.98 1 1 15c0 12.67-1.67 24.33-4.99 35-3.99 15.33-10.31 27.67-18.98 37z\"]\n};\nvar faArchive = {\n prefix: 'fas',\n iconName: 'archive',\n icon: [512, 512, [], \"f187\", \"M32 448c0 17.7 14.3 32 32 32h384c17.7 0 32-14.3 32-32V160H32v288zm160-212c0-6.6 5.4-12 12-12h104c6.6 0 12 5.4 12 12v8c0 6.6-5.4 12-12 12H204c-6.6 0-12-5.4-12-12v-8zM480 32H32C14.3 32 0 46.3 0 64v48c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16V64c0-17.7-14.3-32-32-32z\"]\n};\nvar faArchway = {\n prefix: 'fas',\n iconName: 'archway',\n icon: [576, 512, [], \"f557\", \"M560 448h-16V96H32v352H16.02c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16H176c8.84 0 16-7.16 16-16V320c0-53.02 42.98-96 96-96s96 42.98 96 96l.02 160v16c0 8.84 7.16 16 16 16H560c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm0-448H16C7.16 0 0 7.16 0 16v32c0 8.84 7.16 16 16 16h544c8.84 0 16-7.16 16-16V16c0-8.84-7.16-16-16-16z\"]\n};\nvar faArrowAltCircleDown = {\n prefix: 'fas',\n iconName: 'arrow-alt-circle-down',\n icon: [512, 512, [], \"f358\", \"M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM212 140v116h-70.9c-10.7 0-16.1 13-8.5 20.5l114.9 114.3c4.7 4.7 12.2 4.7 16.9 0l114.9-114.3c7.6-7.6 2.2-20.5-8.5-20.5H300V140c0-6.6-5.4-12-12-12h-64c-6.6 0-12 5.4-12 12z\"]\n};\nvar faArrowAltCircleLeft = {\n prefix: 'fas',\n iconName: 'arrow-alt-circle-left',\n icon: [512, 512, [], \"f359\", \"M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zm116-292H256v-70.9c0-10.7-13-16.1-20.5-8.5L121.2 247.5c-4.7 4.7-4.7 12.2 0 16.9l114.3 114.9c7.6 7.6 20.5 2.2 20.5-8.5V300h116c6.6 0 12-5.4 12-12v-64c0-6.6-5.4-12-12-12z\"]\n};\nvar faArrowAltCircleRight = {\n prefix: 'fas',\n iconName: 'arrow-alt-circle-right',\n icon: [512, 512, [], \"f35a\", \"M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zM140 300h116v70.9c0 10.7 13 16.1 20.5 8.5l114.3-114.9c4.7-4.7 4.7-12.2 0-16.9l-114.3-115c-7.6-7.6-20.5-2.2-20.5 8.5V212H140c-6.6 0-12 5.4-12 12v64c0 6.6 5.4 12 12 12z\"]\n};\nvar faArrowAltCircleUp = {\n prefix: 'fas',\n iconName: 'arrow-alt-circle-up',\n icon: [512, 512, [], \"f35b\", \"M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm292 116V256h70.9c10.7 0 16.1-13 8.5-20.5L264.5 121.2c-4.7-4.7-12.2-4.7-16.9 0l-115 114.3c-7.6 7.6-2.2 20.5 8.5 20.5H212v116c0 6.6 5.4 12 12 12h64c6.6 0 12-5.4 12-12z\"]\n};\nvar faArrowCircleDown = {\n prefix: 'fas',\n iconName: 'arrow-circle-down',\n icon: [512, 512, [], \"f0ab\", \"M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zm-143.6-28.9L288 302.6V120c0-13.3-10.7-24-24-24h-16c-13.3 0-24 10.7-24 24v182.6l-72.4-75.5c-9.3-9.7-24.8-9.9-34.3-.4l-10.9 11c-9.4 9.4-9.4 24.6 0 33.9L239 404.3c9.4 9.4 24.6 9.4 33.9 0l132.7-132.7c9.4-9.4 9.4-24.6 0-33.9l-10.9-11c-9.5-9.5-25-9.3-34.3.4z\"]\n};\nvar faArrowCircleLeft = {\n prefix: 'fas',\n iconName: 'arrow-circle-left',\n icon: [512, 512, [], \"f0a8\", \"M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zm28.9-143.6L209.4 288H392c13.3 0 24-10.7 24-24v-16c0-13.3-10.7-24-24-24H209.4l75.5-72.4c9.7-9.3 9.9-24.8.4-34.3l-11-10.9c-9.4-9.4-24.6-9.4-33.9 0L107.7 239c-9.4 9.4-9.4 24.6 0 33.9l132.7 132.7c9.4 9.4 24.6 9.4 33.9 0l11-10.9c9.5-9.5 9.3-25-.4-34.3z\"]\n};\nvar faArrowCircleRight = {\n prefix: 'fas',\n iconName: 'arrow-circle-right',\n icon: [512, 512, [], \"f0a9\", \"M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zm-28.9 143.6l75.5 72.4H120c-13.3 0-24 10.7-24 24v16c0 13.3 10.7 24 24 24h182.6l-75.5 72.4c-9.7 9.3-9.9 24.8-.4 34.3l11 10.9c9.4 9.4 24.6 9.4 33.9 0L404.3 273c9.4-9.4 9.4-24.6 0-33.9L271.6 106.3c-9.4-9.4-24.6-9.4-33.9 0l-11 10.9c-9.5 9.6-9.3 25.1.4 34.4z\"]\n};\nvar faArrowCircleUp = {\n prefix: 'fas',\n iconName: 'arrow-circle-up',\n icon: [512, 512, [], \"f0aa\", \"M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm143.6 28.9l72.4-75.5V392c0 13.3 10.7 24 24 24h16c13.3 0 24-10.7 24-24V209.4l72.4 75.5c9.3 9.7 24.8 9.9 34.3.4l10.9-11c9.4-9.4 9.4-24.6 0-33.9L273 107.7c-9.4-9.4-24.6-9.4-33.9 0L106.3 240.4c-9.4 9.4-9.4 24.6 0 33.9l10.9 11c9.6 9.5 25.1 9.3 34.4-.4z\"]\n};\nvar faArrowDown = {\n prefix: 'fas',\n iconName: 'arrow-down',\n icon: [448, 512, [], \"f063\", \"M413.1 222.5l22.2 22.2c9.4 9.4 9.4 24.6 0 33.9L241 473c-9.4 9.4-24.6 9.4-33.9 0L12.7 278.6c-9.4-9.4-9.4-24.6 0-33.9l22.2-22.2c9.5-9.5 25-9.3 34.3.4L184 343.4V56c0-13.3 10.7-24 24-24h32c13.3 0 24 10.7 24 24v287.4l114.8-120.5c9.3-9.8 24.8-10 34.3-.4z\"]\n};\nvar faArrowLeft = {\n prefix: 'fas',\n iconName: 'arrow-left',\n icon: [448, 512, [], \"f060\", \"M257.5 445.1l-22.2 22.2c-9.4 9.4-24.6 9.4-33.9 0L7 273c-9.4-9.4-9.4-24.6 0-33.9L201.4 44.7c9.4-9.4 24.6-9.4 33.9 0l22.2 22.2c9.5 9.5 9.3 25-.4 34.3L136.6 216H424c13.3 0 24 10.7 24 24v32c0 13.3-10.7 24-24 24H136.6l120.5 114.8c9.8 9.3 10 24.8.4 34.3z\"]\n};\nvar faArrowRight = {\n prefix: 'fas',\n iconName: 'arrow-right',\n icon: [448, 512, [], \"f061\", \"M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z\"]\n};\nvar faArrowUp = {\n prefix: 'fas',\n iconName: 'arrow-up',\n icon: [448, 512, [], \"f062\", \"M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z\"]\n};\nvar faArrowsAlt = {\n prefix: 'fas',\n iconName: 'arrows-alt',\n icon: [512, 512, [], \"f0b2\", \"M352.201 425.775l-79.196 79.196c-9.373 9.373-24.568 9.373-33.941 0l-79.196-79.196c-15.119-15.119-4.411-40.971 16.971-40.97h51.162L228 284H127.196v51.162c0 21.382-25.851 32.09-40.971 16.971L7.029 272.937c-9.373-9.373-9.373-24.569 0-33.941L86.225 159.8c15.119-15.119 40.971-4.411 40.971 16.971V228H228V127.196h-51.23c-21.382 0-32.09-25.851-16.971-40.971l79.196-79.196c9.373-9.373 24.568-9.373 33.941 0l79.196 79.196c15.119 15.119 4.411 40.971-16.971 40.971h-51.162V228h100.804v-51.162c0-21.382 25.851-32.09 40.97-16.971l79.196 79.196c9.373 9.373 9.373 24.569 0 33.941L425.773 352.2c-15.119 15.119-40.971 4.411-40.97-16.971V284H284v100.804h51.23c21.382 0 32.09 25.851 16.971 40.971z\"]\n};\nvar faArrowsAltH = {\n prefix: 'fas',\n iconName: 'arrows-alt-h',\n icon: [512, 512, [], \"f337\", \"M377.941 169.941V216H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.568 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296h243.882v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.568 0-33.941l-86.059-86.059c-15.119-15.12-40.971-4.412-40.971 16.97z\"]\n};\nvar faArrowsAltV = {\n prefix: 'fas',\n iconName: 'arrows-alt-v',\n icon: [256, 512, [], \"f338\", \"M214.059 377.941H168V134.059h46.059c21.382 0 32.09-25.851 16.971-40.971L144.971 7.029c-9.373-9.373-24.568-9.373-33.941 0L24.971 93.088c-15.119 15.119-4.411 40.971 16.971 40.971H88v243.882H41.941c-21.382 0-32.09 25.851-16.971 40.971l86.059 86.059c9.373 9.373 24.568 9.373 33.941 0l86.059-86.059c15.12-15.119 4.412-40.971-16.97-40.971z\"]\n};\nvar faAssistiveListeningSystems = {\n prefix: 'fas',\n iconName: 'assistive-listening-systems',\n icon: [512, 512, [], \"f2a2\", \"M216 260c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-44.112 35.888-80 80-80s80 35.888 80 80c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-13.234-10.767-24-24-24s-24 10.766-24 24zm24-176c-97.047 0-176 78.953-176 176 0 15.464 12.536 28 28 28s28-12.536 28-28c0-66.168 53.832-120 120-120s120 53.832 120 120c0 75.164-71.009 70.311-71.997 143.622L288 404c0 28.673-23.327 52-52 52-15.464 0-28 12.536-28 28s12.536 28 28 28c59.475 0 107.876-48.328 108-107.774.595-34.428 72-48.24 72-144.226 0-97.047-78.953-176-176-176zm-80 236c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zM32 448c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm480-187.993c0-1.518-.012-3.025-.045-4.531C510.076 140.525 436.157 38.47 327.994 1.511c-14.633-4.998-30.549 2.809-35.55 17.442-5 14.633 2.81 30.549 17.442 35.55 85.906 29.354 144.61 110.513 146.077 201.953l.003.188c.026 1.118.033 2.236.033 3.363 0 15.464 12.536 28 28 28s28.001-12.536 28.001-28zM152.971 439.029l-80-80L39.03 392.97l80 80 33.941-33.941z\"]\n};\nvar faAsterisk = {\n prefix: 'fas',\n iconName: 'asterisk',\n icon: [512, 512, [], \"f069\", \"M478.21 334.093L336 256l142.21-78.093c11.795-6.477 15.961-21.384 9.232-33.037l-19.48-33.741c-6.728-11.653-21.72-15.499-33.227-8.523L296 186.718l3.475-162.204C299.763 11.061 288.937 0 275.48 0h-38.96c-13.456 0-24.283 11.061-23.994 24.514L216 186.718 77.265 102.607c-11.506-6.976-26.499-3.13-33.227 8.523l-19.48 33.741c-6.728 11.653-2.562 26.56 9.233 33.037L176 256 33.79 334.093c-11.795 6.477-15.961 21.384-9.232 33.037l19.48 33.741c6.728 11.653 21.721 15.499 33.227 8.523L216 325.282l-3.475 162.204C212.237 500.939 223.064 512 236.52 512h38.961c13.456 0 24.283-11.061 23.995-24.514L296 325.282l138.735 84.111c11.506 6.976 26.499 3.13 33.227-8.523l19.48-33.741c6.728-11.653 2.563-26.559-9.232-33.036z\"]\n};\nvar faAt = {\n prefix: 'fas',\n iconName: 'at',\n icon: [512, 512, [], \"f1fa\", \"M256 8C118.941 8 8 118.919 8 256c0 137.059 110.919 248 248 248 48.154 0 95.342-14.14 135.408-40.223 12.005-7.815 14.625-24.288 5.552-35.372l-10.177-12.433c-7.671-9.371-21.179-11.667-31.373-5.129C325.92 429.757 291.314 440 256 440c-101.458 0-184-82.542-184-184S154.542 72 256 72c100.139 0 184 57.619 184 160 0 38.786-21.093 79.742-58.17 83.693-17.349-.454-16.91-12.857-13.476-30.024l23.433-121.11C394.653 149.75 383.308 136 368.225 136h-44.981a13.518 13.518 0 0 0-13.432 11.993l-.01.092c-14.697-17.901-40.448-21.775-59.971-21.775-74.58 0-137.831 62.234-137.831 151.46 0 65.303 36.785 105.87 96 105.87 26.984 0 57.369-15.637 74.991-38.333 9.522 34.104 40.613 34.103 70.71 34.103C462.609 379.41 504 307.798 504 232 504 95.653 394.023 8 256 8zm-21.68 304.43c-22.249 0-36.07-15.623-36.07-40.771 0-44.993 30.779-72.729 58.63-72.729 22.292 0 35.601 15.241 35.601 40.77 0 45.061-33.875 72.73-58.161 72.73z\"]\n};\nvar faAtlas = {\n prefix: 'fas',\n iconName: 'atlas',\n icon: [448, 512, [], \"f558\", \"M318.38 208h-39.09c-1.49 27.03-6.54 51.35-14.21 70.41 27.71-13.24 48.02-39.19 53.3-70.41zm0-32c-5.29-31.22-25.59-57.17-53.3-70.41 7.68 19.06 12.72 43.38 14.21 70.41h39.09zM224 97.31c-7.69 7.45-20.77 34.42-23.43 78.69h46.87c-2.67-44.26-15.75-71.24-23.44-78.69zm-41.08 8.28c-27.71 13.24-48.02 39.19-53.3 70.41h39.09c1.49-27.03 6.53-51.35 14.21-70.41zm0 172.82c-7.68-19.06-12.72-43.38-14.21-70.41h-39.09c5.28 31.22 25.59 57.17 53.3 70.41zM247.43 208h-46.87c2.66 44.26 15.74 71.24 23.43 78.69 7.7-7.45 20.78-34.43 23.44-78.69zM448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM224 64c70.69 0 128 57.31 128 128s-57.31 128-128 128S96 262.69 96 192 153.31 64 224 64zm160 384H96c-19.2 0-32-12.8-32-32s16-32 32-32h288v64z\"]\n};\nvar faAtom = {\n prefix: 'fas',\n iconName: 'atom',\n icon: [448, 512, [], \"f5d2\", \"M413.03 256c40.13-54.89 41.51-98.62 25.14-128-10.91-19.52-40.54-50.73-116.33-41.88C300.36 34.89 267.64 0 224 0s-76.36 34.89-97.84 86.12C50.43 77.34 20.73 108.48 9.83 128c-16.38 29.4-15 73.09 25.14 128-40.13 54.89-41.51 98.62-25.14 128 29.21 52.34 101.68 43.58 116.33 41.88C147.63 477.1 180.36 512 224 512s76.37-34.9 97.84-86.12c14.64 1.7 87.11 10.46 116.33-41.88 16.38-29.4 15-73.09-25.14-128zM63.38 352c-4.03-7.21-.19-24.8 14.95-48.29 6.96 6.53 14.2 12.89 21.87 19.18 1.71 13.71 4 27.08 6.76 40.08-24.56.89-39.89-4.37-43.58-10.97zm36.82-162.88c-7.66 6.29-14.9 12.65-21.87 19.18-15.13-23.5-18.97-41.09-14.95-48.3 3.41-6.14 16.39-11.47 37.92-11.47 1.71 0 3.87.3 5.69.37a472.191 472.191 0 0 0-6.79 40.22zM224 64c9.47 0 22.2 13.52 33.86 37.26-11.19 3.7-22.44 8-33.86 12.86-11.42-4.86-22.67-9.16-33.86-12.86C201.8 77.52 214.53 64 224 64zm0 384c-9.47 0-22.2-13.52-33.86-37.26 11.19-3.7 22.44-8 33.86-12.86 11.42 4.86 22.67 9.16 33.86 12.86C246.2 434.48 233.47 448 224 448zm62.5-157.33c-26.7 19.08-46.14 29.33-62.5 37.48-16.35-8.14-35.8-18.41-62.5-37.48-1.99-27.79-1.99-41.54 0-69.33 26.67-19.05 46.13-29.32 62.5-37.48 16.39 8.17 35.86 18.44 62.5 37.48 1.98 27.78 1.99 41.53 0 69.33zM384.62 352c-3.67 6.62-19 11.82-43.58 10.95 2.76-13 5.05-26.37 6.76-40.06 7.66-6.29 14.9-12.65 21.87-19.18 15.13 23.49 18.97 41.08 14.95 48.29zm-14.95-143.71c-6.96-6.53-14.2-12.89-21.87-19.18a473.535 473.535 0 0 0-6.79-40.22c1.82-.07 3.97-.37 5.69-.37 21.52 0 34.51 5.34 37.92 11.47 4.02 7.22.18 24.81-14.95 48.3zM224 224c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32z\"]\n};\nvar faAudioDescription = {\n prefix: 'fas',\n iconName: 'audio-description',\n icon: [512, 512, [], \"f29e\", \"M162.925 238.709l8.822 30.655h-25.606l9.041-30.652c1.277-4.421 2.651-9.994 3.872-15.245 1.22 5.251 2.594 10.823 3.871 15.242zm166.474-32.099h-14.523v98.781h14.523c29.776 0 46.175-17.678 46.175-49.776 0-32.239-17.49-49.005-46.175-49.005zM512 112v288c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48zM245.459 336.139l-57.097-168A12.001 12.001 0 0 0 177 160h-35.894a12.001 12.001 0 0 0-11.362 8.139l-57.097 168C70.003 343.922 75.789 352 84.009 352h29.133a12 12 0 0 0 11.535-8.693l8.574-29.906h51.367l8.793 29.977A12 12 0 0 0 204.926 352h29.172c8.22 0 14.006-8.078 11.361-15.861zm184.701-80.525c0-58.977-37.919-95.614-98.96-95.614h-57.366c-6.627 0-12 5.373-12 12v168c0 6.627 5.373 12 12 12H331.2c61.041 0 98.96-36.933 98.96-96.386z\"]\n};\nvar faAward = {\n prefix: 'fas',\n iconName: 'award',\n icon: [384, 512, [], \"f559\", \"M97.12 362.63c-8.69-8.69-4.16-6.24-25.12-11.85-9.51-2.55-17.87-7.45-25.43-13.32L1.2 448.7c-4.39 10.77 3.81 22.47 15.43 22.03l52.69-2.01L105.56 507c8 8.44 22.04 5.81 26.43-4.96l52.05-127.62c-10.84 6.04-22.87 9.58-35.31 9.58-19.5 0-37.82-7.59-51.61-21.37zM382.8 448.7l-45.37-111.24c-7.56 5.88-15.92 10.77-25.43 13.32-21.07 5.64-16.45 3.18-25.12 11.85-13.79 13.78-32.12 21.37-51.62 21.37-12.44 0-24.47-3.55-35.31-9.58L252 502.04c4.39 10.77 18.44 13.4 26.43 4.96l36.25-38.28 52.69 2.01c11.62.44 19.82-11.27 15.43-22.03zM263 340c15.28-15.55 17.03-14.21 38.79-20.14 13.89-3.79 24.75-14.84 28.47-28.98 7.48-28.4 5.54-24.97 25.95-45.75 10.17-10.35 14.14-25.44 10.42-39.58-7.47-28.38-7.48-24.42 0-52.83 3.72-14.14-.25-29.23-10.42-39.58-20.41-20.78-18.47-17.36-25.95-45.75-3.72-14.14-14.58-25.19-28.47-28.98-27.88-7.61-24.52-5.62-44.95-26.41-10.17-10.35-25-14.4-38.89-10.61-27.87 7.6-23.98 7.61-51.9 0-13.89-3.79-28.72.25-38.89 10.61-20.41 20.78-17.05 18.8-44.94 26.41-13.89 3.79-24.75 14.84-28.47 28.98-7.47 28.39-5.54 24.97-25.95 45.75-10.17 10.35-14.15 25.44-10.42 39.58 7.47 28.36 7.48 24.4 0 52.82-3.72 14.14.25 29.23 10.42 39.59 20.41 20.78 18.47 17.35 25.95 45.75 3.72 14.14 14.58 25.19 28.47 28.98C104.6 325.96 106.27 325 121 340c13.23 13.47 33.84 15.88 49.74 5.82a39.676 39.676 0 0 1 42.53 0c15.89 10.06 36.5 7.65 49.73-5.82zM97.66 175.96c0-53.03 42.24-96.02 94.34-96.02s94.34 42.99 94.34 96.02-42.24 96.02-94.34 96.02-94.34-42.99-94.34-96.02z\"]\n};\nvar faBaby = {\n prefix: 'fas',\n iconName: 'baby',\n icon: [384, 512, [], \"f77c\", \"M192 160c44.2 0 80-35.8 80-80S236.2 0 192 0s-80 35.8-80 80 35.8 80 80 80zm-53.4 248.8l25.6-32-61.5-51.2L56.8 383c-11.4 14.2-11.7 34.4-.8 49l48 64c7.9 10.5 19.9 16 32 16 8.3 0 16.8-2.6 24-8 17.7-13.2 21.2-38.3 8-56l-29.4-39.2zm142.7-83.2l-61.5 51.2 25.6 32L216 448c-13.2 17.7-9.7 42.8 8 56 7.2 5.4 15.6 8 24 8 12.2 0 24.2-5.5 32-16l48-64c10.9-14.6 10.6-34.8-.8-49l-45.9-57.4zM376.7 145c-12.7-18.1-37.6-22.4-55.7-9.8l-40.6 28.5c-52.7 37-124.2 37-176.8 0L63 135.3C44.9 122.6 20 127 7.3 145-5.4 163.1-1 188 17 200.7l40.6 28.5c17 11.9 35.4 20.9 54.4 27.9V288h160v-30.8c19-7 37.4-16 54.4-27.9l40.6-28.5c18.1-12.8 22.4-37.7 9.7-55.8z\"]\n};\nvar faBabyCarriage = {\n prefix: 'fas',\n iconName: 'baby-carriage',\n icon: [512, 512, [], \"f77d\", \"M144.8 17c-11.3-17.8-37.2-22.8-54-9.4C35.3 51.9 0 118 0 192h256L144.8 17zM496 96h-48c-35.3 0-64 28.7-64 64v64H0c0 50.6 23 96.4 60.3 130.7C25.7 363.6 0 394.7 0 432c0 44.2 35.8 80 80 80s80-35.8 80-80c0-8.9-1.8-17.2-4.4-25.2 21.6 5.9 44.6 9.2 68.4 9.2s46.9-3.3 68.4-9.2c-2.7 8-4.4 16.3-4.4 25.2 0 44.2 35.8 80 80 80s80-35.8 80-80c0-37.3-25.7-68.4-60.3-77.3C425 320.4 448 274.6 448 224v-64h48c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM80 464c-17.6 0-32-14.4-32-32s14.4-32 32-32 32 14.4 32 32-14.4 32-32 32zm320-32c0 17.6-14.4 32-32 32s-32-14.4-32-32 14.4-32 32-32 32 14.4 32 32z\"]\n};\nvar faBackspace = {\n prefix: 'fas',\n iconName: 'backspace',\n icon: [640, 512, [], \"f55a\", \"M576 64H205.26A63.97 63.97 0 0 0 160 82.75L9.37 233.37c-12.5 12.5-12.5 32.76 0 45.25L160 429.25c12 12 28.28 18.75 45.25 18.75H576c35.35 0 64-28.65 64-64V128c0-35.35-28.65-64-64-64zm-84.69 254.06c6.25 6.25 6.25 16.38 0 22.63l-22.62 22.62c-6.25 6.25-16.38 6.25-22.63 0L384 301.25l-62.06 62.06c-6.25 6.25-16.38 6.25-22.63 0l-22.62-22.62c-6.25-6.25-6.25-16.38 0-22.63L338.75 256l-62.06-62.06c-6.25-6.25-6.25-16.38 0-22.63l22.62-22.62c6.25-6.25 16.38-6.25 22.63 0L384 210.75l62.06-62.06c6.25-6.25 16.38-6.25 22.63 0l22.62 22.62c6.25 6.25 6.25 16.38 0 22.63L429.25 256l62.06 62.06z\"]\n};\nvar faBackward = {\n prefix: 'fas',\n iconName: 'backward',\n icon: [512, 512, [], \"f04a\", \"M11.5 280.6l192 160c20.6 17.2 52.5 2.8 52.5-24.6V96c0-27.4-31.9-41.8-52.5-24.6l-192 160c-15.3 12.8-15.3 36.4 0 49.2zm256 0l192 160c20.6 17.2 52.5 2.8 52.5-24.6V96c0-27.4-31.9-41.8-52.5-24.6l-192 160c-15.3 12.8-15.3 36.4 0 49.2z\"]\n};\nvar faBacon = {\n prefix: 'fas',\n iconName: 'bacon',\n icon: [576, 512, [], \"f7e5\", \"M218.92 336.39c34.89-34.89 44.2-59.7 54.05-86 10.61-28.29 21.59-57.54 61.37-97.34s69.05-50.77 97.35-61.38c23.88-9 46.64-17.68 76.79-45.37L470.81 8.91a31 31 0 0 0-40.18-2.83c-13.64 10.1-25.15 14.39-41 20.3C247 79.52 209.26 191.29 200.65 214.1c-29.75 78.83-89.55 94.68-98.72 98.09-24.86 9.26-54.73 20.38-91.07 50.36C-3 374-3.63 395 9.07 407.61l35.76 35.51C80 410.52 107 400.15 133 390.39c26.27-9.84 51.06-19.12 85.92-54zm348-232l-35.75-35.51c-35.19 32.63-62.18 43-88.25 52.79-26.26 9.85-51.06 19.16-85.95 54s-44.19 59.69-54 86C292.33 290 281.34 319.22 241.55 359s-69 50.73-97.3 61.32c-23.86 9-46.61 17.66-76.72 45.33l37.68 37.43a31 31 0 0 0 40.18 2.82c13.6-10.06 25.09-14.34 40.94-20.24 142.2-53 180-164.1 188.94-187.69C405 219.18 464.8 203.3 474 199.86c24.87-9.27 54.74-20.4 91.11-50.41 13.89-11.4 14.52-32.45 1.82-45.05z\"]\n};\nvar faBalanceScale = {\n prefix: 'fas',\n iconName: 'balance-scale',\n icon: [640, 512, [], \"f24e\", \"M256 336h-.02c0-16.18 1.34-8.73-85.05-181.51-17.65-35.29-68.19-35.36-85.87 0C-2.06 328.75.02 320.33.02 336H0c0 44.18 57.31 80 128 80s128-35.82 128-80zM128 176l72 144H56l72-144zm511.98 160c0-16.18 1.34-8.73-85.05-181.51-17.65-35.29-68.19-35.36-85.87 0-87.12 174.26-85.04 165.84-85.04 181.51H384c0 44.18 57.31 80 128 80s128-35.82 128-80h-.02zM440 320l72-144 72 144H440zm88 128H352V153.25c23.51-10.29 41.16-31.48 46.39-57.25H528c8.84 0 16-7.16 16-16V48c0-8.84-7.16-16-16-16H383.64C369.04 12.68 346.09 0 320 0s-49.04 12.68-63.64 32H112c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h129.61c5.23 25.76 22.87 46.96 46.39 57.25V448H112c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16z\"]\n};\nvar faBan = {\n prefix: 'fas',\n iconName: 'ban',\n icon: [512, 512, [], \"f05e\", \"M256 8C119.034 8 8 119.033 8 256s111.034 248 248 248 248-111.034 248-248S392.967 8 256 8zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676zM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676z\"]\n};\nvar faBandAid = {\n prefix: 'fas',\n iconName: 'band-aid',\n icon: [640, 512, [], \"f462\", \"M0 160v192c0 35.3 28.7 64 64 64h96V96H64c-35.3 0-64 28.7-64 64zm576-64h-96v320h96c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64zM192 416h256V96H192v320zm176-232c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm0 96c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm-96-96c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm0 96c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24z\"]\n};\nvar faBarcode = {\n prefix: 'fas',\n iconName: 'barcode',\n icon: [512, 512, [], \"f02a\", \"M0 448V64h18v384H0zm26.857-.273V64H36v383.727h-9.143zm27.143 0V64h8.857v383.727H54zm44.857 0V64h8.857v383.727h-8.857zm36 0V64h17.714v383.727h-17.714zm44.857 0V64h8.857v383.727h-8.857zm18 0V64h8.857v383.727h-8.857zm18 0V64h8.857v383.727h-8.857zm35.715 0V64h18v383.727h-18zm44.857 0V64h18v383.727h-18zm35.999 0V64h18.001v383.727h-18.001zm36.001 0V64h18.001v383.727h-18.001zm26.857 0V64h18v383.727h-18zm45.143 0V64h26.857v383.727h-26.857zm35.714 0V64h9.143v383.727H476zm18 .273V64h18v384h-18z\"]\n};\nvar faBars = {\n prefix: 'fas',\n iconName: 'bars',\n icon: [448, 512, [], \"f0c9\", \"M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z\"]\n};\nvar faBaseballBall = {\n prefix: 'fas',\n iconName: 'baseball-ball',\n icon: [496, 512, [], \"f433\", \"M368.5 363.9l28.8-13.9c11.1 22.9 26 43.2 44.1 60.9 34-42.5 54.5-96.3 54.5-154.9 0-58.5-20.4-112.2-54.2-154.6-17.8 17.3-32.6 37.1-43.6 59.5l-28.7-14.1c12.8-26 30-49 50.8-69C375.6 34.7 315 8 248 8 181.1 8 120.5 34.6 75.9 77.7c20.7 19.9 37.9 42.9 50.7 68.8l-28.7 14.1c-11-22.3-25.7-42.1-43.5-59.4C20.4 143.7 0 197.4 0 256c0 58.6 20.4 112.3 54.4 154.7 18.2-17.7 33.2-38 44.3-61l28.8 13.9c-12.9 26.7-30.3 50.3-51.5 70.7 44.5 43.1 105.1 69.7 172 69.7 66.8 0 127.3-26.5 171.9-69.5-21.1-20.4-38.5-43.9-51.4-70.6zm-228.3-32l-30.5-9.8c14.9-46.4 12.7-93.8-.6-134l30.4-10c15 45.6 18 99.9.7 153.8zm216.3-153.4l30.4 10c-13.2 40.1-15.5 87.5-.6 134l-30.5 9.8c-17.3-54-14.3-108.3.7-153.8z\"]\n};\nvar faBasketballBall = {\n prefix: 'fas',\n iconName: 'basketball-ball',\n icon: [496, 512, [], \"f434\", \"M212.3 10.3c-43.8 6.3-86.2 24.1-122.2 53.8l77.4 77.4c27.8-35.8 43.3-81.2 44.8-131.2zM248 222L405.9 64.1c-42.4-35-93.6-53.5-145.5-56.1-1.2 63.9-21.5 122.3-58.7 167.7L248 222zM56.1 98.1c-29.7 36-47.5 78.4-53.8 122.2 50-1.5 95.5-17 131.2-44.8L56.1 98.1zm272.2 204.2c45.3-37.1 103.7-57.4 167.7-58.7-2.6-51.9-21.1-103.1-56.1-145.5L282 256l46.3 46.3zM248 290L90.1 447.9c42.4 34.9 93.6 53.5 145.5 56.1 1.3-64 21.6-122.4 58.7-167.7L248 290zm191.9 123.9c29.7-36 47.5-78.4 53.8-122.2-50.1 1.6-95.5 17.1-131.2 44.8l77.4 77.4zM167.7 209.7C122.3 246.9 63.9 267.3 0 268.4c2.6 51.9 21.1 103.1 56.1 145.5L214 256l-46.3-46.3zm116 292c43.8-6.3 86.2-24.1 122.2-53.8l-77.4-77.4c-27.7 35.7-43.2 81.2-44.8 131.2z\"]\n};\nvar faBath = {\n prefix: 'fas',\n iconName: 'bath',\n icon: [512, 512, [], \"f2cd\", \"M488 256H80V112c0-17.645 14.355-32 32-32 11.351 0 21.332 5.945 27.015 14.88-16.492 25.207-14.687 59.576 6.838 83.035-4.176 4.713-4.021 11.916.491 16.428l11.314 11.314c4.686 4.686 12.284 4.686 16.971 0l95.03-95.029c4.686-4.686 4.686-12.284 0-16.971l-11.314-11.314c-4.512-4.512-11.715-4.666-16.428-.491-17.949-16.469-42.294-21.429-64.178-15.365C163.281 45.667 139.212 32 112 32c-44.112 0-80 35.888-80 80v144h-8c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h8v32c0 28.43 12.362 53.969 32 71.547V456c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-8h256v8c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-32.453c19.638-17.578 32-43.117 32-71.547v-32h8c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24z\"]\n};\nvar faBatteryEmpty = {\n prefix: 'fas',\n iconName: 'battery-empty',\n icon: [640, 512, [], \"f244\", \"M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48z\"]\n};\nvar faBatteryFull = {\n prefix: 'fas',\n iconName: 'battery-full',\n icon: [640, 512, [], \"f240\", \"M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-48 96H96v128h416V192z\"]\n};\nvar faBatteryHalf = {\n prefix: 'fas',\n iconName: 'battery-half',\n icon: [640, 512, [], \"f242\", \"M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-240 96H96v128h224V192z\"]\n};\nvar faBatteryQuarter = {\n prefix: 'fas',\n iconName: 'battery-quarter',\n icon: [640, 512, [], \"f243\", \"M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-336 96H96v128h128V192z\"]\n};\nvar faBatteryThreeQuarters = {\n prefix: 'fas',\n iconName: 'battery-three-quarters',\n icon: [640, 512, [], \"f241\", \"M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-144 96H96v128h320V192z\"]\n};\nvar faBed = {\n prefix: 'fas',\n iconName: 'bed',\n icon: [640, 512, [], \"f236\", \"M176 256c44.11 0 80-35.89 80-80s-35.89-80-80-80-80 35.89-80 80 35.89 80 80 80zm352-128H304c-8.84 0-16 7.16-16 16v144H64V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v352c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-48h512v48c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16V240c0-61.86-50.14-112-112-112z\"]\n};\nvar faBeer = {\n prefix: 'fas',\n iconName: 'beer',\n icon: [448, 512, [], \"f0fc\", \"M368 96h-48V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56v400c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24v-42.11l80.606-35.977C429.396 365.063 448 336.388 448 304.86V176c0-44.112-35.888-80-80-80zm16 208.86a16.018 16.018 0 0 1-9.479 14.611L320 343.805V160h48c8.822 0 16 7.178 16 16v128.86zM208 384c-8.836 0-16-7.164-16-16V144c0-8.836 7.164-16 16-16s16 7.164 16 16v224c0 8.836-7.164 16-16 16zm-96 0c-8.836 0-16-7.164-16-16V144c0-8.836 7.164-16 16-16s16 7.164 16 16v224c0 8.836-7.164 16-16 16z\"]\n};\nvar faBell = {\n prefix: 'fas',\n iconName: 'bell',\n icon: [448, 512, [], \"f0f3\", \"M224 512c35.32 0 63.97-28.65 63.97-64H160.03c0 35.35 28.65 64 63.97 64zm215.39-149.71c-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84C118.56 68.1 64.08 130.3 64.08 208c0 102.3-36.15 133.53-55.47 154.29-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h383.8c19.12 0 32-15.6 32.1-32 .05-7.55-2.61-15.27-8.61-21.71z\"]\n};\nvar faBellSlash = {\n prefix: 'fas',\n iconName: 'bell-slash',\n icon: [640, 512, [], \"f1f6\", \"M633.82 458.1l-90.62-70.05c.19-1.38.8-2.66.8-4.06.05-7.55-2.61-15.27-8.61-21.71-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84c-40.33 8.38-74.66 31.07-97.59 62.57L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.35 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.42-6.97 4.17-17.02-2.81-22.45zM157.23 251.54c-8.61 67.96-36.41 93.33-52.62 110.75-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h241.92L157.23 251.54zM320 512c35.32 0 63.97-28.65 63.97-64H256.03c0 35.35 28.65 64 63.97 64z\"]\n};\nvar faBezierCurve = {\n prefix: 'fas',\n iconName: 'bezier-curve',\n icon: [640, 512, [], \"f55b\", \"M368 32h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V64c0-17.67-14.33-32-32-32zM208 88h-84.75C113.75 64.56 90.84 48 64 48 28.66 48 0 76.65 0 112s28.66 64 64 64c26.84 0 49.75-16.56 59.25-40h79.73c-55.37 32.52-95.86 87.32-109.54 152h49.4c11.3-41.61 36.77-77.21 71.04-101.56-3.7-8.08-5.88-16.99-5.88-26.44V88zm-48 232H64c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32zM576 48c-26.84 0-49.75 16.56-59.25 40H432v72c0 9.45-2.19 18.36-5.88 26.44 34.27 24.35 59.74 59.95 71.04 101.56h49.4c-13.68-64.68-54.17-119.48-109.54-152h79.73c9.5 23.44 32.41 40 59.25 40 35.34 0 64-28.65 64-64s-28.66-64-64-64zm0 272h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32z\"]\n};\nvar faBible = {\n prefix: 'fas',\n iconName: 'bible',\n icon: [448, 512, [], \"f647\", \"M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM144 144c0-8.84 7.16-16 16-16h48V80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v48h48c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16h-48v112c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16V192h-48c-8.84 0-16-7.16-16-16v-32zm236.8 304H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8v64z\"]\n};\nvar faBicycle = {\n prefix: 'fas',\n iconName: 'bicycle',\n icon: [640, 512, [], \"f206\", \"M512.509 192.001c-16.373-.064-32.03 2.955-46.436 8.495l-77.68-125.153A24 24 0 0 0 368.001 64h-64c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h50.649l14.896 24H256.002v-16c0-8.837-7.163-16-16-16h-87.459c-13.441 0-24.777 10.999-24.536 24.437.232 13.044 10.876 23.563 23.995 23.563h48.726l-29.417 47.52c-13.433-4.83-27.904-7.483-42.992-7.52C58.094 191.83.412 249.012.002 319.236-.413 390.279 57.055 448 128.002 448c59.642 0 109.758-40.793 123.967-96h52.033a24 24 0 0 0 20.406-11.367L410.37 201.77l14.938 24.067c-25.455 23.448-41.385 57.081-41.307 94.437.145 68.833 57.899 127.051 126.729 127.719 70.606.685 128.181-55.803 129.255-125.996 1.086-70.941-56.526-129.72-127.476-129.996zM186.75 265.772c9.727 10.529 16.673 23.661 19.642 38.228h-43.306l23.664-38.228zM128.002 400c-44.112 0-80-35.888-80-80s35.888-80 80-80c5.869 0 11.586.653 17.099 1.859l-45.505 73.509C89.715 331.327 101.213 352 120.002 352h81.3c-12.37 28.225-40.562 48-73.3 48zm162.63-96h-35.624c-3.96-31.756-19.556-59.894-42.383-80.026L237.371 184h127.547l-74.286 120zm217.057 95.886c-41.036-2.165-74.049-35.692-75.627-76.755-.812-21.121 6.633-40.518 19.335-55.263l44.433 71.586c4.66 7.508 14.524 9.816 22.032 5.156l13.594-8.437c7.508-4.66 9.817-14.524 5.156-22.032l-44.468-71.643a79.901 79.901 0 0 1 19.858-2.497c44.112 0 80 35.888 80 80-.001 45.54-38.252 82.316-84.313 79.885z\"]\n};\nvar faBinoculars = {\n prefix: 'fas',\n iconName: 'binoculars',\n icon: [512, 512, [], \"f1e5\", \"M416 48c0-8.84-7.16-16-16-16h-64c-8.84 0-16 7.16-16 16v48h96V48zM63.91 159.99C61.4 253.84 3.46 274.22 0 404v44c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32V288h32V128H95.84c-17.63 0-31.45 14.37-31.93 31.99zm384.18 0c-.48-17.62-14.3-31.99-31.93-31.99H320v160h32v160c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-44c-3.46-129.78-61.4-150.16-63.91-244.01zM176 32h-64c-8.84 0-16 7.16-16 16v48h96V48c0-8.84-7.16-16-16-16zm48 256h64V128h-64v160z\"]\n};\nvar faBiohazard = {\n prefix: 'fas',\n iconName: 'biohazard',\n icon: [576, 512, [], \"f780\", \"M287.9 112c18.6 0 36.2 3.8 52.8 9.6 13.3-10.3 23.6-24.3 29.5-40.7-25.2-10.9-53-17-82.2-17-29.1 0-56.9 6-82.1 16.9 5.9 16.4 16.2 30.4 29.5 40.7 16.5-5.7 34-9.5 52.5-9.5zM163.6 438.7c12-11.8 20.4-26.4 24.5-42.4-32.9-26.4-54.8-65.3-58.9-109.6-8.5-2.8-17.2-4.6-26.4-4.6-7.6 0-15.2 1-22.5 3.1 4.1 62.8 35.8 118 83.3 153.5zm224.2-42.6c4.1 16 12.5 30.7 24.5 42.5 47.4-35.5 79.1-90.7 83-153.5-7.2-2-14.7-3-22.2-3-9.2 0-18 1.9-26.6 4.7-4.1 44.2-26 82.9-58.7 109.3zm113.5-205c-17.6-10.4-36.3-16.6-55.3-19.9 6-17.7 10-36.4 10-56.2 0-41-14.5-80.8-41-112.2-2.5-3-6.6-3.7-10-1.8-3.3 1.9-4.8 6-3.6 9.7 4.5 13.8 6.6 26.3 6.6 38.5 0 67.8-53.8 122.9-120 122.9S168 117 168 49.2c0-12.1 2.2-24.7 6.6-38.5 1.2-3.7-.3-7.8-3.6-9.7-3.4-1.9-7.5-1.2-10 1.8C134.6 34.2 120 74 120 115c0 19.8 3.9 38.5 10 56.2-18.9 3.3-37.7 9.5-55.3 19.9-34.6 20.5-61 53.3-74.3 92.4-1.3 3.7.2 7.7 3.5 9.8 3.3 2 7.5 1.3 10-1.6 9.4-10.8 19-19.1 29.2-25.1 57.3-33.9 130.8-13.7 163.9 45 33.1 58.7 13.4 134-43.9 167.9-10.2 6.1-22 10.4-35.8 13.4-3.7.8-6.4 4.2-6.4 8.1.1 4 2.7 7.3 6.5 8 39.7 7.8 80.6.8 115.2-19.7 18-10.6 32.9-24.5 45.3-40.1 12.4 15.6 27.3 29.5 45.3 40.1 34.6 20.5 75.5 27.5 115.2 19.7 3.8-.7 6.4-4 6.5-8 0-3.9-2.6-7.3-6.4-8.1-13.9-2.9-25.6-7.3-35.8-13.4-57.3-33.9-77-109.2-43.9-167.9s106.6-78.9 163.9-45c10.2 6.1 19.8 14.3 29.2 25.1 2.5 2.9 6.7 3.6 10 1.6s4.8-6.1 3.5-9.8c-13.1-39.1-39.5-72-74.1-92.4zm-213.4 129c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z\"]\n};\nvar faBirthdayCake = {\n prefix: 'fas',\n iconName: 'birthday-cake',\n icon: [448, 512, [], \"f1fd\", \"M448 384c-28.02 0-31.26-32-74.5-32-43.43 0-46.825 32-74.75 32-27.695 0-31.454-32-74.75-32-42.842 0-47.218 32-74.5 32-28.148 0-31.202-32-74.75-32-43.547 0-46.653 32-74.75 32v-80c0-26.5 21.5-48 48-48h16V112h64v144h64V112h64v144h64V112h64v144h16c26.5 0 48 21.5 48 48v80zm0 128H0v-96c43.356 0 46.767-32 74.75-32 27.951 0 31.253 32 74.75 32 42.843 0 47.217-32 74.5-32 28.148 0 31.201 32 74.75 32 43.357 0 46.767-32 74.75-32 27.488 0 31.252 32 74.5 32v96zM96 96c-17.75 0-32-14.25-32-32 0-31 32-23 32-64 12 0 32 29.5 32 56s-14.25 40-32 40zm128 0c-17.75 0-32-14.25-32-32 0-31 32-23 32-64 12 0 32 29.5 32 56s-14.25 40-32 40zm128 0c-17.75 0-32-14.25-32-32 0-31 32-23 32-64 12 0 32 29.5 32 56s-14.25 40-32 40z\"]\n};\nvar faBlender = {\n prefix: 'fas',\n iconName: 'blender',\n icon: [512, 512, [], \"f517\", \"M416 384H160c-35.35 0-64 28.65-64 64v32c0 17.67 14.33 32 32 32h320c17.67 0 32-14.33 32-32v-32c0-35.35-28.65-64-64-64zm-128 96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm40-416h166.54L512 0H48C21.49 0 0 21.49 0 48v160c0 26.51 21.49 48 48 48h103.27l8.73 96h256l17.46-64H328c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h114.18l17.46-64H328c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h140.36l17.46-64H328c-4.42 0-8-3.58-8-8V72c0-4.42 3.58-8 8-8zM64 192V64h69.82l11.64 128H64z\"]\n};\nvar faBlenderPhone = {\n prefix: 'fas',\n iconName: 'blender-phone',\n icon: [576, 512, [], \"f6b6\", \"M392 64h166.54L576 0H192v352h288l17.46-64H392c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h114.18l17.46-64H392c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h140.36l17.46-64H392c-4.42 0-8-3.58-8-8V72c0-4.42 3.58-8 8-8zM158.8 335.01l-25.78-63.26c-2.78-6.81-9.8-10.99-17.24-10.26l-45.03 4.42c-17.28-46.94-17.65-99.78 0-147.72l45.03 4.42c7.43.73 14.46-3.46 17.24-10.26l25.78-63.26c3.02-7.39.2-15.85-6.68-20.07l-39.28-24.1C98.51-3.87 80.09-.5 68.95 11.97c-92.57 103.6-92 259.55 2.1 362.49 9.87 10.8 29.12 12.48 41.65 4.8l39.41-24.18c6.89-4.22 9.7-12.67 6.69-20.07zM480 384H192c-35.35 0-64 28.65-64 64v32c0 17.67 14.33 32 32 32h352c17.67 0 32-14.33 32-32v-32c0-35.35-28.65-64-64-64zm-144 96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faBlind = {\n prefix: 'fas',\n iconName: 'blind',\n icon: [384, 512, [], \"f29d\", \"M380.15 510.837a8 8 0 0 1-10.989-2.687l-125.33-206.427a31.923 31.923 0 0 0 12.958-9.485l126.048 207.608a8 8 0 0 1-2.687 10.991zM142.803 314.338l-32.54 89.485 36.12 88.285c6.693 16.36 25.377 24.192 41.733 17.501 16.357-6.692 24.193-25.376 17.501-41.734l-62.814-153.537zM96 88c24.301 0 44-19.699 44-44S120.301 0 96 0 52 19.699 52 44s19.699 44 44 44zm154.837 169.128l-120-152c-4.733-5.995-11.75-9.108-18.837-9.112V96H80v.026c-7.146.003-14.217 3.161-18.944 9.24L0 183.766v95.694c0 13.455 11.011 24.791 24.464 24.536C37.505 303.748 48 293.1 48 280v-79.766l16-20.571v140.698L9.927 469.055c-6.04 16.609 2.528 34.969 19.138 41.009 16.602 6.039 34.968-2.524 41.009-19.138L136 309.638V202.441l-31.406-39.816a4 4 0 1 1 6.269-4.971l102.3 129.217c9.145 11.584 24.368 11.339 33.708 3.965 10.41-8.216 12.159-23.334 3.966-33.708z\"]\n};\nvar faBlog = {\n prefix: 'fas',\n iconName: 'blog',\n icon: [512, 512, [], \"f781\", \"M172.2 226.8c-14.6-2.9-28.2 8.9-28.2 23.8V301c0 10.2 7.1 18.4 16.7 22 18.2 6.8 31.3 24.4 31.3 45 0 26.5-21.5 48-48 48s-48-21.5-48-48V120c0-13.3-10.7-24-24-24H24c-13.3 0-24 10.7-24 24v248c0 89.5 82.1 160.2 175 140.7 54.4-11.4 98.3-55.4 109.7-109.7 17.4-82.9-37-157.2-112.5-172.2zM209 0c-9.2-.5-17 6.8-17 16v31.6c0 8.5 6.6 15.5 15 15.9 129.4 7 233.4 112 240.9 241.5.5 8.4 7.5 15 15.9 15h32.1c9.2 0 16.5-7.8 16-17C503.4 139.8 372.2 8.6 209 0zm.3 96c-9.3-.7-17.3 6.7-17.3 16.1v32.1c0 8.4 6.5 15.3 14.8 15.9 76.8 6.3 138 68.2 144.9 145.2.8 8.3 7.6 14.7 15.9 14.7h32.2c9.3 0 16.8-8 16.1-17.3-8.4-110.1-96.5-198.2-206.6-206.7z\"]\n};\nvar faBold = {\n prefix: 'fas',\n iconName: 'bold',\n icon: [384, 512, [], \"f032\", \"M304.793 243.891c33.639-18.537 53.657-54.16 53.657-95.693 0-48.236-26.25-87.626-68.626-104.179C265.138 34.01 240.849 32 209.661 32H24c-8.837 0-16 7.163-16 16v33.049c0 8.837 7.163 16 16 16h33.113v318.53H24c-8.837 0-16 7.163-16 16V464c0 8.837 7.163 16 16 16h195.69c24.203 0 44.834-1.289 66.866-7.584C337.52 457.193 376 410.647 376 350.014c0-52.168-26.573-91.684-71.207-106.123zM142.217 100.809h67.444c16.294 0 27.536 2.019 37.525 6.717 15.828 8.479 24.906 26.502 24.906 49.446 0 35.029-20.32 56.79-53.029 56.79h-76.846V100.809zm112.642 305.475c-10.14 4.056-22.677 4.907-31.409 4.907h-81.233V281.943h84.367c39.645 0 63.057 25.38 63.057 63.057.001 28.425-13.66 52.483-34.782 61.284z\"]\n};\nvar faBolt = {\n prefix: 'fas',\n iconName: 'bolt',\n icon: [320, 512, [], \"f0e7\", \"M296 160H180.6l42.6-129.8C227.2 15 215.7 0 200 0H56C44 0 33.8 8.9 32.2 20.8l-32 240C-1.7 275.2 9.5 288 24 288h118.7L96.6 482.5c-3.6 15.2 8 29.5 23.3 29.5 8.4 0 16.4-4.4 20.8-12l176-304c9.3-15.9-2.2-36-20.7-36z\"]\n};\nvar faBomb = {\n prefix: 'fas',\n iconName: 'bomb',\n icon: [512, 512, [], \"f1e2\", \"M440.5 88.5l-52 52L415 167c9.4 9.4 9.4 24.6 0 33.9l-17.4 17.4c11.8 26.1 18.4 55.1 18.4 85.6 0 114.9-93.1 208-208 208S0 418.9 0 304 93.1 96 208 96c30.5 0 59.5 6.6 85.6 18.4L311 97c9.4-9.4 24.6-9.4 33.9 0l26.5 26.5 52-52 17.1 17zM500 60h-24c-6.6 0-12 5.4-12 12s5.4 12 12 12h24c6.6 0 12-5.4 12-12s-5.4-12-12-12zM440 0c-6.6 0-12 5.4-12 12v24c0 6.6 5.4 12 12 12s12-5.4 12-12V12c0-6.6-5.4-12-12-12zm33.9 55l17-17c4.7-4.7 4.7-12.3 0-17-4.7-4.7-12.3-4.7-17 0l-17 17c-4.7 4.7-4.7 12.3 0 17 4.8 4.7 12.4 4.7 17 0zm-67.8 0c4.7 4.7 12.3 4.7 17 0 4.7-4.7 4.7-12.3 0-17l-17-17c-4.7-4.7-12.3-4.7-17 0-4.7 4.7-4.7 12.3 0 17l17 17zm67.8 34c-4.7-4.7-12.3-4.7-17 0-4.7 4.7-4.7 12.3 0 17l17 17c4.7 4.7 12.3 4.7 17 0 4.7-4.7 4.7-12.3 0-17l-17-17zM112 272c0-35.3 28.7-64 64-64 8.8 0 16-7.2 16-16s-7.2-16-16-16c-52.9 0-96 43.1-96 96 0 8.8 7.2 16 16 16s16-7.2 16-16z\"]\n};\nvar faBone = {\n prefix: 'fas',\n iconName: 'bone',\n icon: [640, 512, [], \"f5d7\", \"M598.88 244.56c25.2-12.6 41.12-38.36 41.12-66.53v-7.64C640 129.3 606.7 96 565.61 96c-32.02 0-60.44 20.49-70.57 50.86-7.68 23.03-11.6 45.14-38.11 45.14H183.06c-27.38 0-31.58-25.54-38.11-45.14C134.83 116.49 106.4 96 74.39 96 33.3 96 0 129.3 0 170.39v7.64c0 28.17 15.92 53.93 41.12 66.53 9.43 4.71 9.43 18.17 0 22.88C15.92 280.04 0 305.8 0 333.97v7.64C0 382.7 33.3 416 74.38 416c32.02 0 60.44-20.49 70.57-50.86 7.68-23.03 11.6-45.14 38.11-45.14h273.87c27.38 0 31.58 25.54 38.11 45.14C505.17 395.51 533.6 416 565.61 416c41.08 0 74.38-33.3 74.38-74.39v-7.64c0-28.18-15.92-53.93-41.12-66.53-9.42-4.71-9.42-18.17.01-22.88z\"]\n};\nvar faBong = {\n prefix: 'fas',\n iconName: 'bong',\n icon: [448, 512, [], \"f55c\", \"M302.5 512c23.18 0 44.43-12.58 56-32.66C374.69 451.26 384 418.75 384 384c0-36.12-10.08-69.81-27.44-98.62L400 241.94l9.38 9.38c6.25 6.25 16.38 6.25 22.63 0l11.3-11.32c6.25-6.25 6.25-16.38 0-22.63l-52.69-52.69c-6.25-6.25-16.38-6.25-22.63 0l-11.31 11.31c-6.25 6.25-6.25 16.38 0 22.63l9.38 9.38-39.41 39.41c-11.56-11.37-24.53-21.33-38.65-29.51V63.74l15.97-.02c8.82-.01 15.97-7.16 15.98-15.98l.04-31.72C320 7.17 312.82-.01 303.97 0L80.03.26c-8.82.01-15.97 7.16-15.98 15.98l-.04 31.73c-.01 8.85 7.17 16.02 16.02 16.01L96 63.96v153.93C38.67 251.1 0 312.97 0 384c0 34.75 9.31 67.27 25.5 95.34C37.08 499.42 58.33 512 81.5 512h221zM120.06 259.43L144 245.56V63.91l96-.11v181.76l23.94 13.87c24.81 14.37 44.12 35.73 56.56 60.57h-257c12.45-24.84 31.75-46.2 56.56-60.57z\"]\n};\nvar faBook = {\n prefix: 'fas',\n iconName: 'book',\n icon: [448, 512, [], \"f02d\", \"M448 360V24c0-13.3-10.7-24-24-24H96C43 0 0 43 0 96v320c0 53 43 96 96 96h328c13.3 0 24-10.7 24-24v-16c0-7.5-3.5-14.3-8.9-18.7-4.2-15.4-4.2-59.3 0-74.7 5.4-4.3 8.9-11.1 8.9-18.6zM128 134c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm0 64c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm253.4 250H96c-17.7 0-32-14.3-32-32 0-17.6 14.4-32 32-32h285.4c-1.9 17.1-1.9 46.9 0 64z\"]\n};\nvar faBookDead = {\n prefix: 'fas',\n iconName: 'book-dead',\n icon: [448, 512, [], \"f6b7\", \"M272 136c8.8 0 16-7.2 16-16s-7.2-16-16-16-16 7.2-16 16 7.2 16 16 16zm176 222.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM240 56c44.2 0 80 28.7 80 64 0 20.9-12.7 39.2-32 50.9V184c0 8.8-7.2 16-16 16h-64c-8.8 0-16-7.2-16-16v-13.1c-19.3-11.7-32-30-32-50.9 0-35.3 35.8-64 80-64zM124.8 223.3l6.3-14.7c1.7-4.1 6.4-5.9 10.5-4.2l98.3 42.1 98.4-42.1c4.1-1.7 8.8.1 10.5 4.2l6.3 14.7c1.7 4.1-.1 8.8-4.2 10.5L280.6 264l70.3 30.1c4.1 1.7 5.9 6.4 4.2 10.5l-6.3 14.7c-1.7 4.1-6.4 5.9-10.5 4.2L240 281.4l-98.3 42.2c-4.1 1.7-8.8-.1-10.5-4.2l-6.3-14.7c-1.7-4.1.1-8.8 4.2-10.5l70.4-30.1-70.5-30.3c-4.1-1.7-5.9-6.4-4.2-10.5zm256 224.7H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8zM208 136c8.8 0 16-7.2 16-16s-7.2-16-16-16-16 7.2-16 16 7.2 16 16 16z\"]\n};\nvar faBookMedical = {\n prefix: 'fas',\n iconName: 'book-medical',\n icon: [448, 512, [], \"f7e6\", \"M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16q0-9.6-9.6-19.2c-3.2-16-3.2-60.8 0-73.6q9.6-4.8 9.6-19.2zM144 168a8 8 0 0 1 8-8h56v-56a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8v56h56a8 8 0 0 1 8 8v48a8 8 0 0 1-8 8h-56v56a8 8 0 0 1-8 8h-48a8 8 0 0 1-8-8v-56h-56a8 8 0 0 1-8-8zm236.8 280H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8z\"]\n};\nvar faBookOpen = {\n prefix: 'fas',\n iconName: 'book-open',\n icon: [576, 512, [], \"f518\", \"M542.22 32.05c-54.8 3.11-163.72 14.43-230.96 55.59-4.64 2.84-7.27 7.89-7.27 13.17v363.87c0 11.55 12.63 18.85 23.28 13.49 69.18-34.82 169.23-44.32 218.7-46.92 16.89-.89 30.02-14.43 30.02-30.66V62.75c.01-17.71-15.35-31.74-33.77-30.7zM264.73 87.64C197.5 46.48 88.58 35.17 33.78 32.05 15.36 31.01 0 45.04 0 62.75V400.6c0 16.24 13.13 29.78 30.02 30.66 49.49 2.6 149.59 12.11 218.77 46.95 10.62 5.35 23.21-1.94 23.21-13.46V100.63c0-5.29-2.62-10.14-7.27-12.99z\"]\n};\nvar faBookReader = {\n prefix: 'fas',\n iconName: 'book-reader',\n icon: [512, 512, [], \"f5da\", \"M352 96c0-53.02-42.98-96-96-96s-96 42.98-96 96 42.98 96 96 96 96-42.98 96-96zM233.59 241.1c-59.33-36.32-155.43-46.3-203.79-49.05C13.55 191.13 0 203.51 0 219.14v222.8c0 14.33 11.59 26.28 26.49 27.05 43.66 2.29 131.99 10.68 193.04 41.43 9.37 4.72 20.48-1.71 20.48-11.87V252.56c-.01-4.67-2.32-8.95-6.42-11.46zm248.61-49.05c-48.35 2.74-144.46 12.73-203.78 49.05-4.1 2.51-6.41 6.96-6.41 11.63v245.79c0 10.19 11.14 16.63 20.54 11.9 61.04-30.72 149.32-39.11 192.97-41.4 14.9-.78 26.49-12.73 26.49-27.06V219.14c-.01-15.63-13.56-28.01-29.81-27.09z\"]\n};\nvar faBookmark = {\n prefix: 'fas',\n iconName: 'bookmark',\n icon: [384, 512, [], \"f02e\", \"M0 512V48C0 21.49 21.49 0 48 0h288c26.51 0 48 21.49 48 48v464L192 400 0 512z\"]\n};\nvar faBowlingBall = {\n prefix: 'fas',\n iconName: 'bowling-ball',\n icon: [496, 512, [], \"f436\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM120 192c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm64-96c0-17.7 14.3-32 32-32s32 14.3 32 32-14.3 32-32 32-32-14.3-32-32zm48 144c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faBox = {\n prefix: 'fas',\n iconName: 'box',\n icon: [512, 512, [], \"f466\", \"M509.5 184.6L458.9 32.8C452.4 13.2 434.1 0 413.4 0H272v192h238.7c-.4-2.5-.4-5-1.2-7.4zM240 0H98.6c-20.7 0-39 13.2-45.5 32.8L2.5 184.6c-.8 2.4-.8 4.9-1.2 7.4H240V0zM0 224v240c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V224H0z\"]\n};\nvar faBoxOpen = {\n prefix: 'fas',\n iconName: 'box-open',\n icon: [640, 512, [], \"f49e\", \"M425.7 256c-16.9 0-32.8-9-41.4-23.4L320 126l-64.2 106.6c-8.7 14.5-24.6 23.5-41.5 23.5-4.5 0-9-.6-13.3-1.9L64 215v178c0 14.7 10 27.5 24.2 31l216.2 54.1c10.2 2.5 20.9 2.5 31 0L551.8 424c14.2-3.6 24.2-16.4 24.2-31V215l-137 39.1c-4.3 1.3-8.8 1.9-13.3 1.9zm212.6-112.2L586.8 41c-3.1-6.2-9.8-9.8-16.7-8.9L320 64l91.7 152.1c3.8 6.3 11.4 9.3 18.5 7.3l197.9-56.5c9.9-2.9 14.7-13.9 10.2-23.1zM53.2 41L1.7 143.8c-4.6 9.2.3 20.2 10.1 23l197.9 56.5c7.1 2 14.7-1 18.5-7.3L320 64 69.8 32.1c-6.9-.8-13.5 2.7-16.6 8.9z\"]\n};\nvar faBoxes = {\n prefix: 'fas',\n iconName: 'boxes',\n icon: [576, 512, [], \"f468\", \"M560 288h-80v96l-32-21.3-32 21.3v-96h-80c-8.8 0-16 7.2-16 16v192c0 8.8 7.2 16 16 16h224c8.8 0 16-7.2 16-16V304c0-8.8-7.2-16-16-16zm-384-64h224c8.8 0 16-7.2 16-16V16c0-8.8-7.2-16-16-16h-80v96l-32-21.3L256 96V0h-80c-8.8 0-16 7.2-16 16v192c0 8.8 7.2 16 16 16zm64 64h-80v96l-32-21.3L96 384v-96H16c-8.8 0-16 7.2-16 16v192c0 8.8 7.2 16 16 16h224c8.8 0 16-7.2 16-16V304c0-8.8-7.2-16-16-16z\"]\n};\nvar faBraille = {\n prefix: 'fas',\n iconName: 'braille',\n icon: [640, 512, [], \"f2a1\", \"M128 256c0 35.346-28.654 64-64 64S0 291.346 0 256s28.654-64 64-64 64 28.654 64 64zM64 384c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-352C28.654 32 0 60.654 0 96s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64zm160 192c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0 160c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-352c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64zm224 192c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0 160c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-352c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64zm160 192c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0 160c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-320c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z\"]\n};\nvar faBrain = {\n prefix: 'fas',\n iconName: 'brain',\n icon: [576, 512, [], \"f5dc\", \"M208 0c-29.87 0-54.74 20.55-61.8 48.22-.75-.02-1.45-.22-2.2-.22-35.34 0-64 28.65-64 64 0 4.84.64 9.51 1.66 14.04C52.54 138 32 166.57 32 200c0 12.58 3.16 24.32 8.34 34.91C16.34 248.72 0 274.33 0 304c0 33.34 20.42 61.88 49.42 73.89-.9 4.57-1.42 9.28-1.42 14.11 0 39.76 32.23 72 72 72 4.12 0 8.1-.55 12.03-1.21C141.61 491.31 168.25 512 200 512c39.77 0 72-32.24 72-72V205.45c-10.91 8.98-23.98 15.45-38.36 18.39-4.97 1.02-9.64-2.82-9.64-7.89v-16.18c0-3.57 2.35-6.78 5.8-7.66 24.2-6.16 42.2-27.95 42.2-54.04V64c0-35.35-28.66-64-64-64zm368 304c0-29.67-16.34-55.28-40.34-69.09 5.17-10.59 8.34-22.33 8.34-34.91 0-33.43-20.54-62-49.66-73.96 1.02-4.53 1.66-9.2 1.66-14.04 0-35.35-28.66-64-64-64-.75 0-1.45.2-2.2.22C422.74 20.55 397.87 0 368 0c-35.34 0-64 28.65-64 64v74.07c0 26.09 17.99 47.88 42.2 54.04 3.46.88 5.8 4.09 5.8 7.66v16.18c0 5.07-4.68 8.91-9.64 7.89-14.38-2.94-27.44-9.41-38.36-18.39V440c0 39.76 32.23 72 72 72 31.75 0 58.39-20.69 67.97-49.21 3.93.67 7.91 1.21 12.03 1.21 39.77 0 72-32.24 72-72 0-4.83-.52-9.54-1.42-14.11 29-12.01 49.42-40.55 49.42-73.89z\"]\n};\nvar faBreadSlice = {\n prefix: 'fas',\n iconName: 'bread-slice',\n icon: [576, 512, [], \"f7ec\", \"M288 0C108 0 0 93.4 0 169.14 0 199.44 24.24 224 64 224v256c0 17.67 16.12 32 36 32h376c19.88 0 36-14.33 36-32V224c39.76 0 64-24.56 64-54.86C576 93.4 468 0 288 0z\"]\n};\nvar faBriefcase = {\n prefix: 'fas',\n iconName: 'briefcase',\n icon: [512, 512, [], \"f0b1\", \"M320 336c0 8.84-7.16 16-16 16h-96c-8.84 0-16-7.16-16-16v-48H0v144c0 25.6 22.4 48 48 48h416c25.6 0 48-22.4 48-48V288H320v48zm144-208h-80V80c0-25.6-22.4-48-48-48H176c-25.6 0-48 22.4-48 48v48H48c-25.6 0-48 22.4-48 48v80h512v-80c0-25.6-22.4-48-48-48zm-144 0H192V96h128v32z\"]\n};\nvar faBriefcaseMedical = {\n prefix: 'fas',\n iconName: 'briefcase-medical',\n icon: [512, 512, [], \"f469\", \"M464 128h-80V80c0-26.5-21.5-48-48-48H176c-26.5 0-48 21.5-48 48v48H48c-26.5 0-48 21.5-48 48v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V176c0-26.5-21.5-48-48-48zM192 96h128v32H192V96zm160 248c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8v48z\"]\n};\nvar faBroadcastTower = {\n prefix: 'fas',\n iconName: 'broadcast-tower',\n icon: [640, 512, [], \"f519\", \"M150.94 192h33.73c11.01 0 18.61-10.83 14.86-21.18-4.93-13.58-7.55-27.98-7.55-42.82s2.62-29.24 7.55-42.82C203.29 74.83 195.68 64 184.67 64h-33.73c-7.01 0-13.46 4.49-15.41 11.23C130.64 92.21 128 109.88 128 128c0 18.12 2.64 35.79 7.54 52.76 1.94 6.74 8.39 11.24 15.4 11.24zM89.92 23.34C95.56 12.72 87.97 0 75.96 0H40.63c-6.27 0-12.14 3.59-14.74 9.31C9.4 45.54 0 85.65 0 128c0 24.75 3.12 68.33 26.69 118.86 2.62 5.63 8.42 9.14 14.61 9.14h34.84c12.02 0 19.61-12.74 13.95-23.37-49.78-93.32-16.71-178.15-.17-209.29zM614.06 9.29C611.46 3.58 605.6 0 599.33 0h-35.42c-11.98 0-19.66 12.66-14.02 23.25 18.27 34.29 48.42 119.42.28 209.23-5.72 10.68 1.8 23.52 13.91 23.52h35.23c6.27 0 12.13-3.58 14.73-9.29C630.57 210.48 640 170.36 640 128s-9.42-82.48-25.94-118.71zM489.06 64h-33.73c-11.01 0-18.61 10.83-14.86 21.18 4.93 13.58 7.55 27.98 7.55 42.82s-2.62 29.24-7.55 42.82c-3.76 10.35 3.85 21.18 14.86 21.18h33.73c7.02 0 13.46-4.49 15.41-11.24 4.9-16.97 7.53-34.64 7.53-52.76 0-18.12-2.64-35.79-7.54-52.76-1.94-6.75-8.39-11.24-15.4-11.24zm-116.3 100.12c7.05-10.29 11.2-22.71 11.2-36.12 0-35.35-28.63-64-63.96-64-35.32 0-63.96 28.65-63.96 64 0 13.41 4.15 25.83 11.2 36.12l-130.5 313.41c-3.4 8.15.46 17.52 8.61 20.92l29.51 12.31c8.15 3.4 17.52-.46 20.91-8.61L244.96 384h150.07l49.2 118.15c3.4 8.16 12.76 12.01 20.91 8.61l29.51-12.31c8.15-3.4 12-12.77 8.61-20.92l-130.5-313.41zM271.62 320L320 203.81 368.38 320h-96.76z\"]\n};\nvar faBroom = {\n prefix: 'fas',\n iconName: 'broom',\n icon: [640, 512, [], \"f51a\", \"M256.47 216.77l86.73 109.18s-16.6 102.36-76.57 150.12C206.66 523.85 0 510.19 0 510.19s3.8-23.14 11-55.43l94.62-112.17c3.97-4.7-.87-11.62-6.65-9.5l-60.4 22.09c14.44-41.66 32.72-80.04 54.6-97.47 59.97-47.76 163.3-40.94 163.3-40.94zM636.53 31.03l-19.86-25c-5.49-6.9-15.52-8.05-22.41-2.56l-232.48 177.8-34.14-42.97c-5.09-6.41-15.14-5.21-18.59 2.21l-25.33 54.55 86.73 109.18 58.8-12.45c8-1.69 11.42-11.2 6.34-17.6l-34.09-42.92 232.48-177.8c6.89-5.48 8.04-15.53 2.55-22.44z\"]\n};\nvar faBrush = {\n prefix: 'fas',\n iconName: 'brush',\n icon: [384, 512, [], \"f55d\", \"M352 0H32C14.33 0 0 14.33 0 32v224h384V32c0-17.67-14.33-32-32-32zM0 320c0 35.35 28.66 64 64 64h64v64c0 35.35 28.66 64 64 64s64-28.65 64-64v-64h64c35.34 0 64-28.65 64-64v-32H0v32zm192 104c13.25 0 24 10.74 24 24 0 13.25-10.75 24-24 24s-24-10.75-24-24c0-13.26 10.75-24 24-24z\"]\n};\nvar faBug = {\n prefix: 'fas',\n iconName: 'bug',\n icon: [512, 512, [], \"f188\", \"M511.988 288.9c-.478 17.43-15.217 31.1-32.653 31.1H424v16c0 21.864-4.882 42.584-13.6 61.145l60.228 60.228c12.496 12.497 12.496 32.758 0 45.255-12.498 12.497-32.759 12.496-45.256 0l-54.736-54.736C345.886 467.965 314.351 480 280 480V236c0-6.627-5.373-12-12-12h-24c-6.627 0-12 5.373-12 12v244c-34.351 0-65.886-12.035-90.636-32.108l-54.736 54.736c-12.498 12.497-32.759 12.496-45.256 0-12.496-12.497-12.496-32.758 0-45.255l60.228-60.228C92.882 378.584 88 357.864 88 336v-16H32.666C15.23 320 .491 306.33.013 288.9-.484 270.816 14.028 256 32 256h56v-58.745l-46.628-46.628c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0L141.255 160h229.489l54.627-54.627c12.498-12.497 32.758-12.497 45.256 0 12.496 12.497 12.496 32.758 0 45.255L424 197.255V256h56c17.972 0 32.484 14.816 31.988 32.9zM257 0c-61.856 0-112 50.144-112 112h224C369 50.144 318.856 0 257 0z\"]\n};\nvar faBuilding = {\n prefix: 'fas',\n iconName: 'building',\n icon: [448, 512, [], \"f1ad\", \"M436 480h-20V24c0-13.255-10.745-24-24-24H56C42.745 0 32 10.745 32 24v456H12c-6.627 0-12 5.373-12 12v20h448v-20c0-6.627-5.373-12-12-12zM128 76c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12V76zm0 96c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12v-40zm52 148h-40c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12zm76 160h-64v-84c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v84zm64-172c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40zm0-96c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40zm0-96c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12V76c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40z\"]\n};\nvar faBullhorn = {\n prefix: 'fas',\n iconName: 'bullhorn',\n icon: [576, 512, [], \"f0a1\", \"M576 240c0-23.63-12.95-44.04-32-55.12V32.01C544 23.26 537.02 0 512 0c-7.12 0-14.19 2.38-19.98 7.02l-85.03 68.03C364.28 109.19 310.66 128 256 128H64c-35.35 0-64 28.65-64 64v96c0 35.35 28.65 64 64 64h33.7c-1.39 10.48-2.18 21.14-2.18 32 0 39.77 9.26 77.35 25.56 110.94 5.19 10.69 16.52 17.06 28.4 17.06h74.28c26.05 0 41.69-29.84 25.9-50.56-16.4-21.52-26.15-48.36-26.15-77.44 0-11.11 1.62-21.79 4.41-32H256c54.66 0 108.28 18.81 150.98 52.95l85.03 68.03a32.023 32.023 0 0 0 19.98 7.02c24.92 0 32-22.78 32-32V295.13C563.05 284.04 576 263.63 576 240zm-96 141.42l-33.05-26.44C392.95 311.78 325.12 288 256 288v-96c69.12 0 136.95-23.78 190.95-66.98L480 98.58v282.84z\"]\n};\nvar faBullseye = {\n prefix: 'fas',\n iconName: 'bullseye',\n icon: [496, 512, [], \"f140\", \"M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm0 432c-101.69 0-184-82.29-184-184 0-101.69 82.29-184 184-184 101.69 0 184 82.29 184 184 0 101.69-82.29 184-184 184zm0-312c-70.69 0-128 57.31-128 128s57.31 128 128 128 128-57.31 128-128-57.31-128-128-128zm0 192c-35.29 0-64-28.71-64-64s28.71-64 64-64 64 28.71 64 64-28.71 64-64 64z\"]\n};\nvar faBurn = {\n prefix: 'fas',\n iconName: 'burn',\n icon: [384, 512, [], \"f46a\", \"M192 0C79.7 101.3 0 220.9 0 300.5 0 425 79 512 192 512s192-87 192-211.5c0-79.9-80.2-199.6-192-300.5zm0 448c-56.5 0-96-39-96-94.8 0-13.5 4.6-61.5 96-161.2 91.4 99.7 96 147.7 96 161.2 0 55.8-39.5 94.8-96 94.8z\"]\n};\nvar faBus = {\n prefix: 'fas',\n iconName: 'bus',\n icon: [512, 512, [], \"f207\", \"M488 128h-8V80c0-44.8-99.2-80-224-80S32 35.2 32 80v48h-8c-13.25 0-24 10.74-24 24v80c0 13.25 10.75 24 24 24h8v160c0 17.67 14.33 32 32 32v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h192v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h6.4c16 0 25.6-12.8 25.6-25.6V256h8c13.25 0 24-10.75 24-24v-80c0-13.26-10.75-24-24-24zM112 400c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm16-112c-17.67 0-32-14.33-32-32V128c0-17.67 14.33-32 32-32h256c17.67 0 32 14.33 32 32v128c0 17.67-14.33 32-32 32H128zm272 112c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faBusAlt = {\n prefix: 'fas',\n iconName: 'bus-alt',\n icon: [512, 512, [], \"f55e\", \"M488 128h-8V80c0-44.8-99.2-80-224-80S32 35.2 32 80v48h-8c-13.25 0-24 10.74-24 24v80c0 13.25 10.75 24 24 24h8v160c0 17.67 14.33 32 32 32v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h192v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h6.4c16 0 25.6-12.8 25.6-25.6V256h8c13.25 0 24-10.75 24-24v-80c0-13.26-10.75-24-24-24zM160 72c0-4.42 3.58-8 8-8h176c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H168c-4.42 0-8-3.58-8-8V72zm-48 328c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm128-112H128c-17.67 0-32-14.33-32-32v-96c0-17.67 14.33-32 32-32h112v160zm32 0V128h112c17.67 0 32 14.33 32 32v96c0 17.67-14.33 32-32 32H272zm128 112c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faBusinessTime = {\n prefix: 'fas',\n iconName: 'business-time',\n icon: [640, 512, [], \"f64a\", \"M496 224c-79.59 0-144 64.41-144 144s64.41 144 144 144 144-64.41 144-144-64.41-144-144-144zm64 150.29c0 5.34-4.37 9.71-9.71 9.71h-60.57c-5.34 0-9.71-4.37-9.71-9.71v-76.57c0-5.34 4.37-9.71 9.71-9.71h12.57c5.34 0 9.71 4.37 9.71 9.71V352h38.29c5.34 0 9.71 4.37 9.71 9.71v12.58zM496 192c5.4 0 10.72.33 16 .81V144c0-25.6-22.4-48-48-48h-80V48c0-25.6-22.4-48-48-48H176c-25.6 0-48 22.4-48 48v48H48c-25.6 0-48 22.4-48 48v80h395.12c28.6-20.09 63.35-32 100.88-32zM320 96H192V64h128v32zm6.82 224H208c-8.84 0-16-7.16-16-16v-48H0v144c0 25.6 22.4 48 48 48h291.43C327.1 423.96 320 396.82 320 368c0-16.66 2.48-32.72 6.82-48z\"]\n};\nvar faCalculator = {\n prefix: 'fas',\n iconName: 'calculator',\n icon: [448, 512, [], \"f1ec\", \"M400 0H48C22.4 0 0 22.4 0 48v416c0 25.6 22.4 48 48 48h352c25.6 0 48-22.4 48-48V48c0-25.6-22.4-48-48-48zM128 435.2c0 6.4-6.4 12.8-12.8 12.8H76.8c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4zm0-128c0 6.4-6.4 12.8-12.8 12.8H76.8c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4zm128 128c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4zm0-128c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4zm128 128c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8V268.8c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v166.4zm0-256c0 6.4-6.4 12.8-12.8 12.8H76.8c-6.4 0-12.8-6.4-12.8-12.8V76.8C64 70.4 70.4 64 76.8 64h294.4c6.4 0 12.8 6.4 12.8 12.8v102.4z\"]\n};\nvar faCalendar = {\n prefix: 'fas',\n iconName: 'calendar',\n icon: [448, 512, [], \"f133\", \"M12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm436-44v-36c0-26.5-21.5-48-48-48h-48V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H160V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H48C21.5 64 0 85.5 0 112v36c0 6.6 5.4 12 12 12h424c6.6 0 12-5.4 12-12z\"]\n};\nvar faCalendarAlt = {\n prefix: 'fas',\n iconName: 'calendar-alt',\n icon: [448, 512, [], \"f073\", \"M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm320-196c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM192 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM64 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z\"]\n};\nvar faCalendarCheck = {\n prefix: 'fas',\n iconName: 'calendar-check',\n icon: [448, 512, [], \"f274\", \"M436 160H12c-6.627 0-12-5.373-12-12v-36c0-26.51 21.49-48 48-48h48V12c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v52h128V12c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v52h48c26.51 0 48 21.49 48 48v36c0 6.627-5.373 12-12 12zM12 192h424c6.627 0 12 5.373 12 12v260c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V204c0-6.627 5.373-12 12-12zm333.296 95.947l-28.169-28.398c-4.667-4.705-12.265-4.736-16.97-.068L194.12 364.665l-45.98-46.352c-4.667-4.705-12.266-4.736-16.971-.068l-28.397 28.17c-4.705 4.667-4.736 12.265-.068 16.97l82.601 83.269c4.667 4.705 12.265 4.736 16.97.068l142.953-141.805c4.705-4.667 4.736-12.265.068-16.97z\"]\n};\nvar faCalendarDay = {\n prefix: 'fas',\n iconName: 'calendar-day',\n icon: [448, 512, [], \"f783\", \"M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm64-192c0-8.8 7.2-16 16-16h96c8.8 0 16 7.2 16 16v96c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16v-96zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z\"]\n};\nvar faCalendarMinus = {\n prefix: 'fas',\n iconName: 'calendar-minus',\n icon: [448, 512, [], \"f272\", \"M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm304 192c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12H132c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h184z\"]\n};\nvar faCalendarPlus = {\n prefix: 'fas',\n iconName: 'calendar-plus',\n icon: [448, 512, [], \"f271\", \"M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm316 140c0-6.6-5.4-12-12-12h-60v-60c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v60h-60c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h60v60c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-60h60c6.6 0 12-5.4 12-12v-40z\"]\n};\nvar faCalendarTimes = {\n prefix: 'fas',\n iconName: 'calendar-times',\n icon: [448, 512, [], \"f273\", \"M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm257.3 160l48.1-48.1c4.7-4.7 4.7-12.3 0-17l-28.3-28.3c-4.7-4.7-12.3-4.7-17 0L224 306.7l-48.1-48.1c-4.7-4.7-12.3-4.7-17 0l-28.3 28.3c-4.7 4.7-4.7 12.3 0 17l48.1 48.1-48.1 48.1c-4.7 4.7-4.7 12.3 0 17l28.3 28.3c4.7 4.7 12.3 4.7 17 0l48.1-48.1 48.1 48.1c4.7 4.7 12.3 4.7 17 0l28.3-28.3c4.7-4.7 4.7-12.3 0-17L269.3 352z\"]\n};\nvar faCalendarWeek = {\n prefix: 'fas',\n iconName: 'calendar-week',\n icon: [448, 512, [], \"f784\", \"M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm64-192c0-8.8 7.2-16 16-16h288c8.8 0 16 7.2 16 16v64c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16v-64zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z\"]\n};\nvar faCamera = {\n prefix: 'fas',\n iconName: 'camera',\n icon: [512, 512, [], \"f030\", \"M512 144v288c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V144c0-26.5 21.5-48 48-48h88l12.3-32.9c7-18.7 24.9-31.1 44.9-31.1h125.5c20 0 37.9 12.4 44.9 31.1L376 96h88c26.5 0 48 21.5 48 48zM376 288c0-66.2-53.8-120-120-120s-120 53.8-120 120 53.8 120 120 120 120-53.8 120-120zm-32 0c0 48.5-39.5 88-88 88s-88-39.5-88-88 39.5-88 88-88 88 39.5 88 88z\"]\n};\nvar faCameraRetro = {\n prefix: 'fas',\n iconName: 'camera-retro',\n icon: [512, 512, [], \"f083\", \"M48 32C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48H48zm0 32h106c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H38c-3.3 0-6-2.7-6-6V80c0-8.8 7.2-16 16-16zm426 96H38c-3.3 0-6-2.7-6-6v-36c0-3.3 2.7-6 6-6h138l30.2-45.3c1.1-1.7 3-2.7 5-2.7H464c8.8 0 16 7.2 16 16v74c0 3.3-2.7 6-6 6zM256 424c-66.2 0-120-53.8-120-120s53.8-120 120-120 120 53.8 120 120-53.8 120-120 120zm0-208c-48.5 0-88 39.5-88 88s39.5 88 88 88 88-39.5 88-88-39.5-88-88-88zm-48 104c-8.8 0-16-7.2-16-16 0-35.3 28.7-64 64-64 8.8 0 16 7.2 16 16s-7.2 16-16 16c-17.6 0-32 14.4-32 32 0 8.8-7.2 16-16 16z\"]\n};\nvar faCampground = {\n prefix: 'fas',\n iconName: 'campground',\n icon: [640, 512, [], \"f6bb\", \"M624 448h-24.68L359.54 117.75l53.41-73.55c5.19-7.15 3.61-17.16-3.54-22.35l-25.9-18.79c-7.15-5.19-17.15-3.61-22.35 3.55L320 63.3 278.83 6.6c-5.19-7.15-15.2-8.74-22.35-3.55l-25.88 18.8c-7.15 5.19-8.74 15.2-3.54 22.35l53.41 73.55L40.68 448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h608c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM320 288l116.36 160H203.64L320 288z\"]\n};\nvar faCandyCane = {\n prefix: 'fas',\n iconName: 'candy-cane',\n icon: [512, 512, [], \"f786\", \"M497.5 92C469.6 33.1 411.8 0 352.4 0c-27.9 0-56.2 7.3-81.8 22.6L243.1 39c-15.2 9.1-20.1 28.7-11 43.9l32.8 54.9c6 10 16.6 15.6 27.5 15.6 5.6 0 11.2-1.5 16.4-4.5l27.5-16.4c5.1-3.1 10.8-4.5 16.4-4.5 10.9 0 21.5 5.6 27.5 15.6 9.1 15.1 4.1 34.8-11 43.9L15.6 397.6c-15.2 9.1-20.1 28.7-11 43.9l32.8 54.9c6 10 16.6 15.6 27.5 15.6 5.6 0 11.2-1.5 16.4-4.5L428.6 301c71.7-42.9 104.6-133.5 68.9-209zm-177.7 13l-2.5 1.5L296.8 45c9.7-4.7 19.8-8.1 30.3-10.2l20.6 61.8c-9.8.8-19.4 3.3-27.9 8.4zM145.9 431.8l-60.5-38.5 30.8-18.3 60.5 38.5-30.8 18.3zm107.5-63.9l-60.5-38.5 30.8-18.3 60.5 38.5-30.8 18.3zM364.3 302l-60.5-38.5 30.8-18.3 60.5 38.5-30.8 18.3zm20.4-197.3l46-46c8.4 6.5 16 14.1 22.6 22.6L407.6 127c-5.7-9.3-13.7-16.9-22.9-22.3zm82.1 107.8l-59.5-19.8c3.2-5.3 5.8-10.9 7.4-17.1 1.1-4.5 1.7-9.1 1.8-13.6l60.4 20.1c-2.1 10.4-5.5 20.6-10.1 30.4z\"]\n};\nvar faCannabis = {\n prefix: 'fas',\n iconName: 'cannabis',\n icon: [512, 512, [], \"f55f\", \"M503.47 360.25c-1.56-.82-32.39-16.89-76.78-25.81 64.25-75.12 84.05-161.67 84.93-165.64 1.18-5.33-.44-10.9-4.3-14.77-3.03-3.04-7.12-4.7-11.32-4.7-1.14 0-2.29.12-3.44.38-3.88.85-86.54 19.59-160.58 79.76.01-1.46.01-2.93.01-4.4 0-118.79-59.98-213.72-62.53-217.7A15.973 15.973 0 0 0 256 0c-5.45 0-10.53 2.78-13.47 7.37-2.55 3.98-62.53 98.91-62.53 217.7 0 1.47.01 2.94.01 4.4-74.03-60.16-156.69-78.9-160.58-79.76-1.14-.25-2.29-.38-3.44-.38-4.2 0-8.29 1.66-11.32 4.7A15.986 15.986 0 0 0 .38 168.8c.88 3.97 20.68 90.52 84.93 165.64-44.39 8.92-75.21 24.99-76.78 25.81a16.003 16.003 0 0 0-.02 28.29c2.45 1.29 60.76 31.72 133.49 31.72 6.14 0 11.96-.1 17.5-.31-11.37 22.23-16.52 38.31-16.81 39.22-1.8 5.68-.29 11.89 3.91 16.11a16.019 16.019 0 0 0 16.1 3.99c1.83-.57 37.72-11.99 77.3-39.29V504c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8v-64.01c39.58 27.3 75.47 38.71 77.3 39.29a16.019 16.019 0 0 0 16.1-3.99c4.2-4.22 5.71-10.43 3.91-16.11-.29-.91-5.45-16.99-16.81-39.22 5.54.21 11.37.31 17.5.31 72.72 0 131.04-30.43 133.49-31.72 5.24-2.78 8.52-8.22 8.51-14.15-.01-5.94-3.29-11.39-8.53-14.15z\"]\n};\nvar faCapsules = {\n prefix: 'fas',\n iconName: 'capsules',\n icon: [576, 512, [], \"f46b\", \"M555.3 300.1L424.2 112.8C401.9 81 366.4 64 330.4 64c-22.6 0-45.5 6.7-65.5 20.7-19.7 13.8-33.7 32.8-41.5 53.8C220.5 79.2 172 32 112 32 50.1 32 0 82.1 0 144v224c0 61.9 50.1 112 112 112s112-50.1 112-112V218.9c3.3 8.6 7.3 17.1 12.8 25L368 431.2c22.2 31.8 57.7 48.8 93.8 48.8 22.7 0 45.5-6.7 65.5-20.7 51.7-36.2 64.2-107.5 28-159.2zM160 256H64V144c0-26.5 21.5-48 48-48s48 21.5 48 48v112zm194.8 44.9l-65.6-93.7c-7.7-11-10.7-24.4-8.3-37.6 2.3-13.2 9.7-24.8 20.7-32.5 8.5-6 18.5-9.1 28.8-9.1 16.5 0 31.9 8 41.3 21.5l65.6 93.7-82.5 57.7z\"]\n};\nvar faCar = {\n prefix: 'fas',\n iconName: 'car',\n icon: [512, 512, [], \"f1b9\", \"M499.99 176h-59.87l-16.64-41.6C406.38 91.63 365.57 64 319.5 64h-127c-46.06 0-86.88 27.63-103.99 70.4L71.87 176H12.01C4.2 176-1.53 183.34.37 190.91l6 24C7.7 220.25 12.5 224 18.01 224h20.07C24.65 235.73 16 252.78 16 272v48c0 16.12 6.16 30.67 16 41.93V416c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h256v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-54.07c9.84-11.25 16-25.8 16-41.93v-48c0-19.22-8.65-36.27-22.07-48H494c5.51 0 10.31-3.75 11.64-9.09l6-24c1.89-7.57-3.84-14.91-11.65-14.91zm-352.06-17.83c7.29-18.22 24.94-30.17 44.57-30.17h127c19.63 0 37.28 11.95 44.57 30.17L384 208H128l19.93-49.83zM96 319.8c-19.2 0-32-12.76-32-31.9S76.8 256 96 256s48 28.71 48 47.85-28.8 15.95-48 15.95zm320 0c-19.2 0-48 3.19-48-15.95S396.8 256 416 256s32 12.76 32 31.9-12.8 31.9-32 31.9z\"]\n};\nvar faCarAlt = {\n prefix: 'fas',\n iconName: 'car-alt',\n icon: [480, 512, [], \"f5de\", \"M438.66 212.33l-11.24-28.1-19.93-49.83C390.38 91.63 349.57 64 303.5 64h-127c-46.06 0-86.88 27.63-103.99 70.4l-19.93 49.83-11.24 28.1C17.22 221.5 0 244.66 0 272v48c0 16.12 6.16 30.67 16 41.93V416c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h256v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-54.07c9.84-11.25 16-25.8 16-41.93v-48c0-27.34-17.22-50.5-41.34-59.67zm-306.73-54.16c7.29-18.22 24.94-30.17 44.57-30.17h127c19.63 0 37.28 11.95 44.57 30.17L368 208H112l19.93-49.83zM80 319.8c-19.2 0-32-12.76-32-31.9S60.8 256 80 256s48 28.71 48 47.85-28.8 15.95-48 15.95zm320 0c-19.2 0-48 3.19-48-15.95S380.8 256 400 256s32 12.76 32 31.9-12.8 31.9-32 31.9z\"]\n};\nvar faCarBattery = {\n prefix: 'fas',\n iconName: 'car-battery',\n icon: [512, 512, [], \"f5df\", \"M480 128h-32V80c0-8.84-7.16-16-16-16h-96c-8.84 0-16 7.16-16 16v48H192V80c0-8.84-7.16-16-16-16H80c-8.84 0-16 7.16-16 16v48H32c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32V160c0-17.67-14.33-32-32-32zM192 264c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h112c4.42 0 8 3.58 8 8v16zm256 0c0 4.42-3.58 8-8 8h-40v40c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-40h-40c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h40v-40c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v40h40c4.42 0 8 3.58 8 8v16z\"]\n};\nvar faCarCrash = {\n prefix: 'fas',\n iconName: 'car-crash',\n icon: [640, 512, [], \"f5e1\", \"M143.25 220.81l-12.42 46.37c-3.01 11.25-3.63 22.89-2.41 34.39l-35.2 28.98c-6.57 5.41-16.31-.43-14.62-8.77l15.44-76.68c1.06-5.26-2.66-10.28-8-10.79l-77.86-7.55c-8.47-.82-11.23-11.83-4.14-16.54l65.15-43.3c4.46-2.97 5.38-9.15 1.98-13.29L21.46 93.22c-5.41-6.57.43-16.3 8.78-14.62l76.68 15.44c5.26 1.06 10.28-2.66 10.8-8l7.55-77.86c.82-8.48 11.83-11.23 16.55-4.14l43.3 65.14c2.97 4.46 9.15 5.38 13.29 1.98l60.4-49.71c6.57-5.41 16.3.43 14.62 8.77L262.1 86.38c-2.71 3.05-5.43 6.09-7.91 9.4l-32.15 42.97-10.71 14.32c-32.73 8.76-59.18 34.53-68.08 67.74zm494.57 132.51l-12.42 46.36c-3.13 11.68-9.38 21.61-17.55 29.36a66.876 66.876 0 0 1-8.76 7l-13.99 52.23c-1.14 4.27-3.1 8.1-5.65 11.38-7.67 9.84-20.74 14.68-33.54 11.25L515 502.62c-17.07-4.57-27.2-22.12-22.63-39.19l8.28-30.91-247.28-66.26-8.28 30.91c-4.57 17.07-22.12 27.2-39.19 22.63l-30.91-8.28c-12.8-3.43-21.7-14.16-23.42-26.51-.57-4.12-.35-8.42.79-12.68l13.99-52.23a66.62 66.62 0 0 1-4.09-10.45c-3.2-10.79-3.65-22.52-.52-34.2l12.42-46.37c5.31-19.8 19.36-34.83 36.89-42.21a64.336 64.336 0 0 1 18.49-4.72l18.13-24.23 32.15-42.97c3.45-4.61 7.19-8.9 11.2-12.84 8-7.89 17.03-14.44 26.74-19.51 4.86-2.54 9.89-4.71 15.05-6.49 10.33-3.58 21.19-5.63 32.24-6.04 11.05-.41 22.31.82 33.43 3.8l122.68 32.87c11.12 2.98 21.48 7.54 30.85 13.43a111.11 111.11 0 0 1 34.69 34.5c8.82 13.88 14.64 29.84 16.68 46.99l6.36 53.29 3.59 30.05a64.49 64.49 0 0 1 22.74 29.93c4.39 11.88 5.29 25.19 1.75 38.39zM255.58 234.34c-18.55-4.97-34.21 4.04-39.17 22.53-4.96 18.49 4.11 34.12 22.65 39.09 18.55 4.97 45.54 15.51 50.49-2.98 4.96-18.49-15.43-53.67-33.97-58.64zm290.61 28.17l-6.36-53.29c-.58-4.87-1.89-9.53-3.82-13.86-5.8-12.99-17.2-23.01-31.42-26.82l-122.68-32.87a48.008 48.008 0 0 0-50.86 17.61l-32.15 42.97 172 46.08 75.29 20.18zm18.49 54.65c-18.55-4.97-53.8 15.31-58.75 33.79-4.95 18.49 23.69 22.86 42.24 27.83 18.55 4.97 34.21-4.04 39.17-22.53 4.95-18.48-4.11-34.12-22.66-39.09z\"]\n};\nvar faCarSide = {\n prefix: 'fas',\n iconName: 'car-side',\n icon: [640, 512, [], \"f5e4\", \"M544 192h-16L419.22 56.02A64.025 64.025 0 0 0 369.24 32H155.33c-26.17 0-49.7 15.93-59.42 40.23L48 194.26C20.44 201.4 0 226.21 0 256v112c0 8.84 7.16 16 16 16h48c0 53.02 42.98 96 96 96s96-42.98 96-96h128c0 53.02 42.98 96 96 96s96-42.98 96-96h48c8.84 0 16-7.16 16-16v-80c0-53.02-42.98-96-96-96zM160 432c-26.47 0-48-21.53-48-48s21.53-48 48-48 48 21.53 48 48-21.53 48-48 48zm72-240H116.93l38.4-96H232v96zm48 0V96h89.24l76.8 96H280zm200 240c-26.47 0-48-21.53-48-48s21.53-48 48-48 48 21.53 48 48-21.53 48-48 48z\"]\n};\nvar faCaretDown = {\n prefix: 'fas',\n iconName: 'caret-down',\n icon: [320, 512, [], \"f0d7\", \"M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z\"]\n};\nvar faCaretLeft = {\n prefix: 'fas',\n iconName: 'caret-left',\n icon: [192, 512, [], \"f0d9\", \"M192 127.338v257.324c0 17.818-21.543 26.741-34.142 14.142L29.196 270.142c-7.81-7.81-7.81-20.474 0-28.284l128.662-128.662c12.599-12.6 34.142-3.676 34.142 14.142z\"]\n};\nvar faCaretRight = {\n prefix: 'fas',\n iconName: 'caret-right',\n icon: [192, 512, [], \"f0da\", \"M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z\"]\n};\nvar faCaretSquareDown = {\n prefix: 'fas',\n iconName: 'caret-square-down',\n icon: [448, 512, [], \"f150\", \"M448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zM92.5 220.5l123 123c4.7 4.7 12.3 4.7 17 0l123-123c7.6-7.6 2.2-20.5-8.5-20.5H101c-10.7 0-16.1 12.9-8.5 20.5z\"]\n};\nvar faCaretSquareLeft = {\n prefix: 'fas',\n iconName: 'caret-square-left',\n icon: [448, 512, [], \"f191\", \"M400 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zM259.515 124.485l-123.03 123.03c-4.686 4.686-4.686 12.284 0 16.971l123.029 123.029c7.56 7.56 20.485 2.206 20.485-8.485V132.971c.001-10.691-12.925-16.045-20.484-8.486z\"]\n};\nvar faCaretSquareRight = {\n prefix: 'fas',\n iconName: 'caret-square-right',\n icon: [448, 512, [], \"f152\", \"M48 32h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48zm140.485 355.515l123.029-123.029c4.686-4.686 4.686-12.284 0-16.971l-123.029-123.03c-7.56-7.56-20.485-2.206-20.485 8.485v246.059c0 10.691 12.926 16.045 20.485 8.486z\"]\n};\nvar faCaretSquareUp = {\n prefix: 'fas',\n iconName: 'caret-square-up',\n icon: [448, 512, [], \"f151\", \"M0 432V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48zm355.515-140.485l-123.03-123.03c-4.686-4.686-12.284-4.686-16.971 0L92.485 291.515c-7.56 7.56-2.206 20.485 8.485 20.485h246.059c10.691 0 16.045-12.926 8.486-20.485z\"]\n};\nvar faCaretUp = {\n prefix: 'fas',\n iconName: 'caret-up',\n icon: [320, 512, [], \"f0d8\", \"M288.662 352H31.338c-17.818 0-26.741-21.543-14.142-34.142l128.662-128.662c7.81-7.81 20.474-7.81 28.284 0l128.662 128.662c12.6 12.599 3.676 34.142-14.142 34.142z\"]\n};\nvar faCarrot = {\n prefix: 'fas',\n iconName: 'carrot',\n icon: [512, 512, [], \"f787\", \"M298.2 156.6c-52.7-25.7-114.5-10.5-150.2 32.8l55.2 55.2c6.3 6.3 6.3 16.4 0 22.6-3.1 3.1-7.2 4.7-11.3 4.7s-8.2-1.6-11.3-4.7L130.4 217 2.3 479.7c-2.9 6-3.1 13.3 0 19.7 5.4 11.1 18.9 15.7 30 10.3l133.6-65.2-49.2-49.2c-6.3-6.2-6.3-16.4 0-22.6 6.3-6.2 16.4-6.2 22.6 0l57 57 102-49.8c24-11.7 44.5-31.3 57.1-57.1 30.1-61.7 4.5-136.1-57.2-166.2zm92.1-34.9C409.8 81 399.7 32.9 360 0c-50.3 41.7-52.5 107.5-7.9 151.9l8 8c44.4 44.6 110.3 42.4 151.9-7.9-32.9-39.7-81-49.8-121.7-30.3z\"]\n};\nvar faCartArrowDown = {\n prefix: 'fas',\n iconName: 'cart-arrow-down',\n icon: [576, 512, [], \"f218\", \"M504.717 320H211.572l6.545 32h268.418c15.401 0 26.816 14.301 23.403 29.319l-5.517 24.276C523.112 414.668 536 433.828 536 456c0 31.202-25.519 56.444-56.824 55.994-29.823-.429-54.35-24.631-55.155-54.447-.44-16.287 6.085-31.049 16.803-41.548H231.176C241.553 426.165 248 440.326 248 456c0 31.813-26.528 57.431-58.67 55.938-28.54-1.325-51.751-24.385-53.251-52.917-1.158-22.034 10.436-41.455 28.051-51.586L93.883 64H24C10.745 64 0 53.255 0 40V24C0 10.745 10.745 0 24 0h102.529c11.401 0 21.228 8.021 23.513 19.19L159.208 64H551.99c15.401 0 26.816 14.301 23.403 29.319l-47.273 208C525.637 312.246 515.923 320 504.717 320zM403.029 192H360v-60c0-6.627-5.373-12-12-12h-24c-6.627 0-12 5.373-12 12v60h-43.029c-10.691 0-16.045 12.926-8.485 20.485l67.029 67.029c4.686 4.686 12.284 4.686 16.971 0l67.029-67.029c7.559-7.559 2.205-20.485-8.486-20.485z\"]\n};\nvar faCartPlus = {\n prefix: 'fas',\n iconName: 'cart-plus',\n icon: [576, 512, [], \"f217\", \"M504.717 320H211.572l6.545 32h268.418c15.401 0 26.816 14.301 23.403 29.319l-5.517 24.276C523.112 414.668 536 433.828 536 456c0 31.202-25.519 56.444-56.824 55.994-29.823-.429-54.35-24.631-55.155-54.447-.44-16.287 6.085-31.049 16.803-41.548H231.176C241.553 426.165 248 440.326 248 456c0 31.813-26.528 57.431-58.67 55.938-28.54-1.325-51.751-24.385-53.251-52.917-1.158-22.034 10.436-41.455 28.051-51.586L93.883 64H24C10.745 64 0 53.255 0 40V24C0 10.745 10.745 0 24 0h102.529c11.401 0 21.228 8.021 23.513 19.19L159.208 64H551.99c15.401 0 26.816 14.301 23.403 29.319l-47.273 208C525.637 312.246 515.923 320 504.717 320zM408 168h-48v-40c0-8.837-7.163-16-16-16h-16c-8.837 0-16 7.163-16 16v40h-48c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h48v40c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-40h48c8.837 0 16-7.163 16-16v-16c0-8.837-7.163-16-16-16z\"]\n};\nvar faCashRegister = {\n prefix: 'fas',\n iconName: 'cash-register',\n icon: [512, 512, [], \"f788\", \"M511.1 378.8l-26.7-160c-2.6-15.4-15.9-26.7-31.6-26.7H208v-64h96c8.8 0 16-7.2 16-16V16c0-8.8-7.2-16-16-16H48c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16h96v64H59.1c-15.6 0-29 11.3-31.6 26.7L.8 378.7c-.6 3.5-.9 7-.9 10.5V480c0 17.7 14.3 32 32 32h448c17.7 0 32-14.3 32-32v-90.7c.1-3.5-.2-7-.8-10.5zM280 248c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16h-16c-8.8 0-16-7.2-16-16v-16zm-32 64h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16h-16c-8.8 0-16-7.2-16-16v-16c0-8.8 7.2-16 16-16zm-32-80c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16h-16c-8.8 0-16-7.2-16-16v-16c0-8.8 7.2-16 16-16h16zM80 80V48h192v32H80zm40 200h-16c-8.8 0-16-7.2-16-16v-16c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16zm16 64v-16c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16h-16c-8.8 0-16-7.2-16-16zm216 112c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h176c4.4 0 8 3.6 8 8v16zm24-112c0 8.8-7.2 16-16 16h-16c-8.8 0-16-7.2-16-16v-16c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16zm48-80c0 8.8-7.2 16-16 16h-16c-8.8 0-16-7.2-16-16v-16c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16z\"]\n};\nvar faCat = {\n prefix: 'fas',\n iconName: 'cat',\n icon: [512, 512, [], \"f6be\", \"M290.59 192c-20.18 0-106.82 1.98-162.59 85.95V192c0-52.94-43.06-96-96-96-17.67 0-32 14.33-32 32s14.33 32 32 32c17.64 0 32 14.36 32 32v256c0 35.3 28.7 64 64 64h176c8.84 0 16-7.16 16-16v-16c0-17.67-14.33-32-32-32h-32l128-96v144c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16V289.86c-10.29 2.67-20.89 4.54-32 4.54-61.81 0-113.52-44.05-125.41-102.4zM448 96h-64l-64-64v134.4c0 53.02 42.98 96 96 96s96-42.98 96-96V32l-64 64zm-72 80c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16zm80 0c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16z\"]\n};\nvar faCertificate = {\n prefix: 'fas',\n iconName: 'certificate',\n icon: [512, 512, [], \"f0a3\", \"M458.622 255.92l45.985-45.005c13.708-12.977 7.316-36.039-10.664-40.339l-62.65-15.99 17.661-62.015c4.991-17.838-11.829-34.663-29.661-29.671l-61.994 17.667-15.984-62.671C337.085.197 313.765-6.276 300.99 7.228L256 53.57 211.011 7.229c-12.63-13.351-36.047-7.234-40.325 10.668l-15.984 62.671-61.995-17.667C74.87 57.907 58.056 74.738 63.046 92.572l17.661 62.015-62.65 15.99C.069 174.878-6.31 197.944 7.392 210.915l45.985 45.005-45.985 45.004c-13.708 12.977-7.316 36.039 10.664 40.339l62.65 15.99-17.661 62.015c-4.991 17.838 11.829 34.663 29.661 29.671l61.994-17.667 15.984 62.671c4.439 18.575 27.696 24.018 40.325 10.668L256 458.61l44.989 46.001c12.5 13.488 35.987 7.486 40.325-10.668l15.984-62.671 61.994 17.667c17.836 4.994 34.651-11.837 29.661-29.671l-17.661-62.015 62.65-15.99c17.987-4.302 24.366-27.367 10.664-40.339l-45.984-45.004z\"]\n};\nvar faChair = {\n prefix: 'fas',\n iconName: 'chair',\n icon: [448, 512, [], \"f6c0\", \"M112 128c0-29.5 16.2-55 40-68.9V256h48V48h48v208h48V59.1c23.8 13.9 40 39.4 40 68.9v128h48V128C384 57.3 326.7 0 256 0h-64C121.3 0 64 57.3 64 128v128h48zm334.3 213.9l-10.7-32c-4.4-13.1-16.6-21.9-30.4-21.9H42.7c-13.8 0-26 8.8-30.4 21.9l-10.7 32C-5.2 362.6 10.2 384 32 384v112c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V384h256v112c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V384c21.8 0 37.2-21.4 30.3-42.1z\"]\n};\nvar faChalkboard = {\n prefix: 'fas',\n iconName: 'chalkboard',\n icon: [640, 512, [], \"f51b\", \"M96 64h448v352h64V40c0-22.06-17.94-40-40-40H72C49.94 0 32 17.94 32 40v376h64V64zm528 384H480v-64H288v64H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h608c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16z\"]\n};\nvar faChalkboardTeacher = {\n prefix: 'fas',\n iconName: 'chalkboard-teacher',\n icon: [640, 512, [], \"f51c\", \"M208 352c-2.39 0-4.78.35-7.06 1.09C187.98 357.3 174.35 360 160 360c-14.35 0-27.98-2.7-40.95-6.91-2.28-.74-4.66-1.09-7.05-1.09C49.94 352-.33 402.48 0 464.62.14 490.88 21.73 512 48 512h224c26.27 0 47.86-21.12 48-47.38.33-62.14-49.94-112.62-112-112.62zm-48-32c53.02 0 96-42.98 96-96s-42.98-96-96-96-96 42.98-96 96 42.98 96 96 96zM592 0H208c-26.47 0-48 22.25-48 49.59V96c23.42 0 45.1 6.78 64 17.8V64h352v288h-64v-64H384v64h-76.24c19.1 16.69 33.12 38.73 39.69 64H592c26.47 0 48-22.25 48-49.59V49.59C640 22.25 618.47 0 592 0z\"]\n};\nvar faChargingStation = {\n prefix: 'fas',\n iconName: 'charging-station',\n icon: [576, 512, [], \"f5e7\", \"M336 448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h320c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm208-320V80c0-8.84-7.16-16-16-16s-16 7.16-16 16v48h-32V80c0-8.84-7.16-16-16-16s-16 7.16-16 16v48h-16c-8.84 0-16 7.16-16 16v32c0 35.76 23.62 65.69 56 75.93v118.49c0 13.95-9.5 26.92-23.26 29.19C431.22 402.5 416 388.99 416 372v-28c0-48.6-39.4-88-88-88h-8V64c0-35.35-28.65-64-64-64H96C60.65 0 32 28.65 32 64v352h288V304h8c22.09 0 40 17.91 40 40v24.61c0 39.67 28.92 75.16 68.41 79.01C481.71 452.05 520 416.41 520 372V251.93c32.38-10.24 56-40.17 56-75.93v-32c0-8.84-7.16-16-16-16h-16zm-283.91 47.76l-93.7 139c-2.2 3.33-6.21 5.24-10.39 5.24-7.67 0-13.47-6.28-11.67-12.92L167.35 224H108c-7.25 0-12.85-5.59-11.89-11.89l16-107C112.9 99.9 117.98 96 124 96h68c7.88 0 13.62 6.54 11.6 13.21L192 160h57.7c9.24 0 15.01 8.78 10.39 15.76z\"]\n};\nvar faChartArea = {\n prefix: 'fas',\n iconName: 'chart-area',\n icon: [512, 512, [], \"f1fe\", \"M500 384c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v308h436zM372.7 159.5L288 216l-85.3-113.7c-5.1-6.8-15.5-6.3-19.9 1L96 248v104h384l-89.9-187.8c-3.2-6.5-11.4-8.7-17.4-4.7z\"]\n};\nvar faChartBar = {\n prefix: 'fas',\n iconName: 'chart-bar',\n icon: [512, 512, [], \"f080\", \"M332.8 320h38.4c6.4 0 12.8-6.4 12.8-12.8V172.8c0-6.4-6.4-12.8-12.8-12.8h-38.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h38.4c6.4 0 12.8-6.4 12.8-12.8V76.8c0-6.4-6.4-12.8-12.8-12.8h-38.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-288 0h38.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-38.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h38.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-38.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zM496 384H64V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16z\"]\n};\nvar faChartLine = {\n prefix: 'fas',\n iconName: 'chart-line',\n icon: [512, 512, [], \"f201\", \"M496 384H64V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM464 96H345.94c-21.38 0-32.09 25.85-16.97 40.97l32.4 32.4L288 242.75l-73.37-73.37c-12.5-12.5-32.76-12.5-45.25 0l-68.69 68.69c-6.25 6.25-6.25 16.38 0 22.63l22.62 22.62c6.25 6.25 16.38 6.25 22.63 0L192 237.25l73.37 73.37c12.5 12.5 32.76 12.5 45.25 0l96-96 32.4 32.4c15.12 15.12 40.97 4.41 40.97-16.97V112c.01-8.84-7.15-16-15.99-16z\"]\n};\nvar faChartPie = {\n prefix: 'fas',\n iconName: 'chart-pie',\n icon: [544, 512, [], \"f200\", \"M527.79 288H290.5l158.03 158.03c6.04 6.04 15.98 6.53 22.19.68 38.7-36.46 65.32-85.61 73.13-140.86 1.34-9.46-6.51-17.85-16.06-17.85zm-15.83-64.8C503.72 103.74 408.26 8.28 288.8.04 279.68-.59 272 7.1 272 16.24V240h223.77c9.14 0 16.82-7.68 16.19-16.8zM224 288V50.71c0-9.55-8.39-17.4-17.84-16.06C86.99 51.49-4.1 155.6.14 280.37 4.5 408.51 114.83 513.59 243.03 511.98c50.4-.63 96.97-16.87 135.26-44.03 7.9-5.6 8.42-17.23 1.57-24.08L224 288z\"]\n};\nvar faCheck = {\n prefix: 'fas',\n iconName: 'check',\n icon: [512, 512, [], \"f00c\", \"M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z\"]\n};\nvar faCheckCircle = {\n prefix: 'fas',\n iconName: 'check-circle',\n icon: [512, 512, [], \"f058\", \"M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z\"]\n};\nvar faCheckDouble = {\n prefix: 'fas',\n iconName: 'check-double',\n icon: [512, 512, [], \"f560\", \"M504.5 171.95l-36.2-36.41c-10-10.05-26.21-10.05-36.2 0L192 377.02 79.9 264.28c-10-10.06-26.21-10.06-36.2 0L7.5 300.69c-10 10.05-10 26.36 0 36.41l166.4 167.36c10 10.06 26.21 10.06 36.2 0l294.4-296.09c10-10.06 10-26.36 0-36.42zM166.57 282.71c6.84 7.02 18.18 7.02 25.21.18L403.85 72.62c7.02-6.84 7.02-18.18.18-25.21L362.08 5.29c-6.84-7.02-18.18-7.02-25.21-.18L179.71 161.19l-68.23-68.77c-6.84-7.02-18.18-7.02-25.2-.18l-42.13 41.77c-7.02 6.84-7.02 18.18-.18 25.2l122.6 123.5z\"]\n};\nvar faCheckSquare = {\n prefix: 'fas',\n iconName: 'check-square',\n icon: [448, 512, [], \"f14a\", \"M400 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zm-204.686-98.059l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.248-16.379-6.249-22.628 0L184 302.745l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.25 16.379 6.25 22.628.001z\"]\n};\nvar faCheese = {\n prefix: 'fas',\n iconName: 'cheese',\n icon: [512, 512, [], \"f7ef\", \"M0 288v160a32 32 0 0 0 32 32h448a32 32 0 0 0 32-32V288zM299.83 32a32 32 0 0 0-21.13 7L0 256h512c0-119.89-94-217.8-212.17-224z\"]\n};\nvar faChess = {\n prefix: 'fas',\n iconName: 'chess',\n icon: [512, 512, [], \"f439\", \"M76.1 210.2h103.7l34.6-95.1c2.8-7.8-3-16.1-11.3-16.1H152V68.8h21.6c3.3 0 6-2.7 6-6V40.4c0-3.3-2.7-6-6-6h-28.4V6c0-3.3-2.7-6-6-6h-22.4c-3.3 0-6 2.7-6 6v28.4H82.4c-3.3 0-6 2.7-6 6v22.4c0 3.3 2.7 6 6 6H104V99H52.8c-8.3 0-14.1 8.3-11.3 16.1zm237.2 90.7l24.9 17c.1 18.1-.2 63.9-11.9 114.5h147.5c-11.7-50.5-12-96.3-11.9-114.5l24.9-16.9c1.1-.7 1.7-1.9 1.7-3.2v-69.9c0-2.1-1.7-3.9-3.9-3.9h-27.7c-2.1 0-3.9 1.7-3.9 3.9v31.5h-22.7v-31.5c0-2.1-1.7-3.9-3.9-3.9h-52.9c-2.1 0-3.9 1.7-3.9 3.9v31.5h-22.7v-31.5c0-2.1-1.7-3.9-3.9-3.9h-27.7c-2.1 0-3.9 1.7-3.9 3.9v69.9c.2 1.2.8 2.4 1.9 3.1zm71.5 52c0-8.4 6.8-15.2 15.2-15.2s15.2 6.8 15.2 15.2v30.3h-30.3v-30.3zm119.8 117.2L491 459.4v-15.6c0-2.1-1.7-3.9-3.9-3.9H312.9c-2.1 0-3.9 1.7-3.9 3.9v15.6L295.3 470c-.9.7-1.5 1.9-1.5 3v35c0 2.1 1.7 3.9 3.9 3.9h204.5c2.1 0 3.9-1.7 3.9-3.9v-35c0-1.1-.5-2.2-1.5-2.9zm-259.8-10.8l-22.1-14.2V417c0-3.3-2.7-6-6-6H39.3c-3.3 0-6 2.7-6 6v28.1l-22.1 14.2c-1.7 1.1-2.8 3-2.8 5.1V506c0 3.3 2.7 6 6 6h227.2c3.3 0 6-2.7 6-6v-41.6c0-2.1-1-4-2.8-5.1zm-45-208.9c3.3 0 6-2.7 6-6v-20.8c0-3.3-2.7-6-6-6H56.2c-3.3 0-6 2.7-6 6v20.8c0 3.3 2.7 6 6 6H82c0 28.8 2.5 95.1-17.4 153.2h126.8c-19.6-57-17.4-121.5-17.4-153.2z\"]\n};\nvar faChessBishop = {\n prefix: 'fas',\n iconName: 'chess-bishop',\n icon: [320, 512, [], \"f43a\", \"M123.158 77.881C107.369 72.53 96 57.597 96 40c0-22.091 17.909-40 40-40h47.796c22.091 0 40 17.909 40 40 0 17.541-11.295 32.434-27.005 37.829 23.993 16.657 48.577 46.839 68.703 82.05L144.929 280.443a6 6 0 0 0 0 8.485l14.142 14.142a6 6 0 0 0 8.485 0L280.9 189.726c17.758 38.297 29.371 79.443 29.371 114.273 0 53.786-22.897 75.788-58.446 86.033V448H68.174v-57.97C32.631 379.784 9.739 357.781 9.739 304c0-78.029 58.281-187.766 113.419-226.119zM320 500v-24c0-6.627-5.373-12-12-12H12c-6.627 0-12 5.373-12 12v24c0 6.627 5.373 12 12 12h296c6.627 0 12-5.373 12-12z\"]\n};\nvar faChessBoard = {\n prefix: 'fas',\n iconName: 'chess-board',\n icon: [512, 512, [], \"f43c\", \"M192 256v64h64v-64zm320 64v-64h-64v64zM0 192v64h64v-64zm512 0v-64h-64v64zm0 256v-64h-64v64zM256 256h64v-64h-64zM0 512h64v-64H0zm128 0h64v-64h-64zM384 0h-64v64h64zM128 0H64v64h64zm128 512h64v-64h-64zM0 64v64h64V64zm0 256v64h64v-64zM256 0h-64v64h64zm128 512h64v-64h-64zM64 384v64h64v-64zm256 0v64h64v-64zm-64-192v-64h-64v64zm128 192h64v-64h-64zM128 256H64v64h64zm256 0h64v-64h-64zM512 0h-64v64h64zM128 128H64v64h64zm256-64v64h64V64zM192 384v64h64v-64zm-64-64v64h64v-64zm128 0v64h64v-64zm-64-128h-64v64h64zm128-64V64h-64v64zm-128 0V64h-64v64zm128 64h64v-64h-64zm0 128h64v-64h-64z\"]\n};\nvar faChessKing = {\n prefix: 'fas',\n iconName: 'chess-king',\n icon: [448, 512, [], \"f43f\", \"M416 476v24c0 6.627-5.373 12-12 12H44c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h360c6.627 0 12 5.373 12 12zm-8.033-324H248v-48h50a6 6 0 0 0 6-6V62a6 6 0 0 0-6-6h-50V6a6 6 0 0 0-6-6h-36a6 6 0 0 0-6 6v50h-50a6 6 0 0 0-6 6v36a6 6 0 0 0 6 6h50v48H40.033c-27.574 0-46.879 27.244-37.738 53.259L87.582 448h272.836l85.287-242.741C454.846 179.244 435.541 152 407.967 152z\"]\n};\nvar faChessKnight = {\n prefix: 'fas',\n iconName: 'chess-knight',\n icon: [384, 512, [], \"f441\", \"M352 224v224H32v-46.557c0-30.302 17.12-58.003 44.223-71.554l57.243-28.622A48 48 0 0 0 160 258.334V208l-22.127 11.063a23.996 23.996 0 0 0-12.55 15.645l-11.835 47.338a12 12 0 0 1-7.185 8.231l-29.601 11.84a11.998 11.998 0 0 1-9.33-.176L7.126 275.167A12 12 0 0 1 0 264.201v-158.26c0-6.365 2.529-12.47 7.03-16.971L16 80 1.789 51.578A16.937 16.937 0 0 1 0 44c0-6.627 5.373-12 12-12h148c106.039 0 192 85.961 192 192zm20 240H12c-6.627 0-12 5.373-12 12v24c0 6.627 5.373 12 12 12h360c6.627 0 12-5.373 12-12v-24c0-6.627-5.373-12-12-12zM52 128c-11.046 0-20 8.954-20 20s8.954 20 20 20 20-8.954 20-20-8.954-20-20-20z\"]\n};\nvar faChessPawn = {\n prefix: 'fas',\n iconName: 'chess-pawn',\n icon: [320, 512, [], \"f443\", \"M264 448H56s60-42.743 60-176H84c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h40.209C95.721 210.56 76 181.588 76 148c0-46.392 37.608-84 84-84s84 37.608 84 84c0 33.588-19.721 62.56-48.209 76H236c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12h-32c0 133.257 60 176 60 176zm28 16H28c-6.627 0-12 5.373-12 12v24c0 6.627 5.373 12 12 12h264c6.627 0 12-5.373 12-12v-24c0-6.627-5.373-12-12-12z\"]\n};\nvar faChessQueen = {\n prefix: 'fas',\n iconName: 'chess-queen',\n icon: [512, 512, [], \"f445\", \"M436 512H76c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h360c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12zM255.579 0c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zm204.568 154.634c-5.768-3.045-12.916-.932-16.082 4.77-8.616 15.516-22.747 37.801-44.065 37.801-28.714 0-30.625-19.804-31.686-57.542-.183-6.492-5.501-11.664-11.995-11.664h-41.006c-5.175 0-9.754 3.328-11.388 8.238-8.89 26.709-26.073 40.992-47.925 40.992s-39.034-14.283-47.925-40.992c-1.634-4.91-6.213-8.238-11.388-8.238h-41.005c-6.495 0-11.813 5.174-11.995 11.667-1.052 37.642-2.934 57.539-31.688 57.539-20.691 0-33.817-20.224-44.425-38.025-3.266-5.48-10.258-7.431-15.899-4.453l-39.179 20.679a12 12 0 0 0-5.51 15.145L112 448h288l105.014-257.448a12 12 0 0 0-5.51-15.145l-39.357-20.773z\"]\n};\nvar faChessRook = {\n prefix: 'fas',\n iconName: 'chess-rook',\n icon: [384, 512, [], \"f447\", \"M81.241 215.027C80.957 258.92 77.411 348.076 48 448h287.982c-29.4-99.604-32.936-188.912-33.221-232.975l45.418-42.312a11.998 11.998 0 0 0 3.82-8.78V44c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v44h-48V44c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v44H96V44c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v119.932c0 3.33 1.384 6.51 3.82 8.78l45.421 42.315zM160 256c0-17.673 14.327-32 32-32 17.673 0 32 14.327 32 32v64.004h-64V256zm224 220v24c0 6.627-5.373 12-12 12H12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h360c6.627 0 12 5.373 12 12z\"]\n};\nvar faChevronCircleDown = {\n prefix: 'fas',\n iconName: 'chevron-circle-down',\n icon: [512, 512, [], \"f13a\", \"M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM273 369.9l135.5-135.5c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L256 285.1 154.4 183.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L239 369.9c9.4 9.4 24.6 9.4 34 0z\"]\n};\nvar faChevronCircleLeft = {\n prefix: 'fas',\n iconName: 'chevron-circle-left',\n icon: [512, 512, [], \"f137\", \"M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zM142.1 273l135.5 135.5c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L226.9 256l101.6-101.6c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L142.1 239c-9.4 9.4-9.4 24.6 0 34z\"]\n};\nvar faChevronCircleRight = {\n prefix: 'fas',\n iconName: 'chevron-circle-right',\n icon: [512, 512, [], \"f138\", \"M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zm113.9 231L234.4 103.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L285.1 256 183.5 357.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L369.9 273c9.4-9.4 9.4-24.6 0-34z\"]\n};\nvar faChevronCircleUp = {\n prefix: 'fas',\n iconName: 'chevron-circle-up',\n icon: [512, 512, [], \"f139\", \"M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z\"]\n};\nvar faChevronDown = {\n prefix: 'fas',\n iconName: 'chevron-down',\n icon: [448, 512, [], \"f078\", \"M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z\"]\n};\nvar faChevronLeft = {\n prefix: 'fas',\n iconName: 'chevron-left',\n icon: [320, 512, [], \"f053\", \"M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z\"]\n};\nvar faChevronRight = {\n prefix: 'fas',\n iconName: 'chevron-right',\n icon: [320, 512, [], \"f054\", \"M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z\"]\n};\nvar faChevronUp = {\n prefix: 'fas',\n iconName: 'chevron-up',\n icon: [448, 512, [], \"f077\", \"M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z\"]\n};\nvar faChild = {\n prefix: 'fas',\n iconName: 'child',\n icon: [384, 512, [], \"f1ae\", \"M120 72c0-39.765 32.235-72 72-72s72 32.235 72 72c0 39.764-32.235 72-72 72s-72-32.236-72-72zm254.627 1.373c-12.496-12.497-32.758-12.497-45.254 0L242.745 160H141.254L54.627 73.373c-12.496-12.497-32.758-12.497-45.254 0-12.497 12.497-12.497 32.758 0 45.255L104 213.254V480c0 17.673 14.327 32 32 32h16c17.673 0 32-14.327 32-32V368h16v112c0 17.673 14.327 32 32 32h16c17.673 0 32-14.327 32-32V213.254l94.627-94.627c12.497-12.497 12.497-32.757 0-45.254z\"]\n};\nvar faChurch = {\n prefix: 'fas',\n iconName: 'church',\n icon: [640, 512, [], \"f51d\", \"M464.46 246.68L352 179.2V128h48c8.84 0 16-7.16 16-16V80c0-8.84-7.16-16-16-16h-48V16c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v48h-48c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h48v51.2l-112.46 67.48A31.997 31.997 0 0 0 160 274.12V512h96v-96c0-35.35 28.65-64 64-64s64 28.65 64 64v96h96V274.12c0-11.24-5.9-21.66-15.54-27.44zM0 395.96V496c0 8.84 7.16 16 16 16h112V320L19.39 366.54A32.024 32.024 0 0 0 0 395.96zm620.61-29.42L512 320v192h112c8.84 0 16-7.16 16-16V395.96c0-12.8-7.63-24.37-19.39-29.42z\"]\n};\nvar faCircle = {\n prefix: 'fas',\n iconName: 'circle',\n icon: [512, 512, [], \"f111\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z\"]\n};\nvar faCircleNotch = {\n prefix: 'fas',\n iconName: 'circle-notch',\n icon: [512, 512, [], \"f1ce\", \"M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z\"]\n};\nvar faCity = {\n prefix: 'fas',\n iconName: 'city',\n icon: [640, 512, [], \"f64f\", \"M616 192H480V24c0-13.26-10.74-24-24-24H312c-13.26 0-24 10.74-24 24v72h-64V16c0-8.84-7.16-16-16-16h-16c-8.84 0-16 7.16-16 16v80h-64V16c0-8.84-7.16-16-16-16H80c-8.84 0-16 7.16-16 16v80H24c-13.26 0-24 10.74-24 24v360c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V216c0-13.26-10.75-24-24-24zM128 404c0 6.63-5.37 12-12 12H76c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12H76c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12H76c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm128 192c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm160 96c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12V76c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm160 288c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40zm0-96c0 6.63-5.37 12-12 12h-40c-6.63 0-12-5.37-12-12v-40c0-6.63 5.37-12 12-12h40c6.63 0 12 5.37 12 12v40z\"]\n};\nvar faClinicMedical = {\n prefix: 'fas',\n iconName: 'clinic-medical',\n icon: [576, 512, [], \"f7f2\", \"M288 115L69.47 307.71c-1.62 1.46-3.69 2.14-5.47 3.35V496a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V311.1c-1.7-1.16-3.72-1.82-5.26-3.2zm96 261a8 8 0 0 1-8 8h-56v56a8 8 0 0 1-8 8h-48a8 8 0 0 1-8-8v-56h-56a8 8 0 0 1-8-8v-48a8 8 0 0 1 8-8h56v-56a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8v56h56a8 8 0 0 1 8 8zm186.69-139.72l-255.94-226a39.85 39.85 0 0 0-53.45 0l-256 226a16 16 0 0 0-1.21 22.6L25.5 282.7a16 16 0 0 0 22.6 1.21L277.42 81.63a16 16 0 0 1 21.17 0L527.91 283.9a16 16 0 0 0 22.6-1.21l21.4-23.82a16 16 0 0 0-1.22-22.59z\"]\n};\nvar faClipboard = {\n prefix: 'fas',\n iconName: 'clipboard',\n icon: [384, 512, [], \"f328\", \"M384 112v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h80c0-35.29 28.71-64 64-64s64 28.71 64 64h80c26.51 0 48 21.49 48 48zM192 40c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24m96 114v-20a6 6 0 0 0-6-6H102a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h180a6 6 0 0 0 6-6z\"]\n};\nvar faClipboardCheck = {\n prefix: 'fas',\n iconName: 'clipboard-check',\n icon: [384, 512, [], \"f46c\", \"M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 40c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm121.2 231.8l-143 141.8c-4.7 4.7-12.3 4.6-17-.1l-82.6-83.3c-4.7-4.7-4.6-12.3.1-17L99.1 285c4.7-4.7 12.3-4.6 17 .1l46 46.4 106-105.2c4.7-4.7 12.3-4.6 17 .1l28.2 28.4c4.7 4.8 4.6 12.3-.1 17z\"]\n};\nvar faClipboardList = {\n prefix: 'fas',\n iconName: 'clipboard-list',\n icon: [384, 512, [], \"f46d\", \"M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM96 424c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24zm0-96c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24zm0-96c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24zm96-192c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm128 368c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16zm0-96c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16zm0-96c0 4.4-3.6 8-8 8H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16z\"]\n};\nvar faClock = {\n prefix: 'fas',\n iconName: 'clock',\n icon: [512, 512, [], \"f017\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm57.1 350.1L224.9 294c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12v137.7l63.5 46.2c5.4 3.9 6.5 11.4 2.6 16.8l-28.2 38.8c-3.9 5.3-11.4 6.5-16.8 2.6z\"]\n};\nvar faClone = {\n prefix: 'fas',\n iconName: 'clone',\n icon: [512, 512, [], \"f24d\", \"M464 0c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48H176c-26.51 0-48-21.49-48-48V48c0-26.51 21.49-48 48-48h288M176 416c-44.112 0-80-35.888-80-80V128H48c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48v-48H176z\"]\n};\nvar faClosedCaptioning = {\n prefix: 'fas',\n iconName: 'closed-captioning',\n icon: [512, 512, [], \"f20a\", \"M464 64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM218.1 287.7c2.8-2.5 7.1-2.1 9.2.9l19.5 27.7c1.7 2.4 1.5 5.6-.5 7.7-53.6 56.8-172.8 32.1-172.8-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7l-17.5 30.5c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2.1 48 51.1 70.5 92.3 32.6zm190.4 0c2.8-2.5 7.1-2.1 9.2.9l19.5 27.7c1.7 2.4 1.5 5.6-.5 7.7-53.5 56.9-172.7 32.1-172.7-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7L420 222.2c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2 0 48 51 70.5 92.2 32.6z\"]\n};\nvar faCloud = {\n prefix: 'fas',\n iconName: 'cloud',\n icon: [640, 512, [], \"f0c2\", \"M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z\"]\n};\nvar faCloudDownloadAlt = {\n prefix: 'fas',\n iconName: 'cloud-download-alt',\n icon: [640, 512, [], \"f381\", \"M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4zm-132.9 88.7L299.3 420.7c-6.2 6.2-16.4 6.2-22.6 0L171.3 315.3c-10.1-10.1-2.9-27.3 11.3-27.3H248V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v112h65.4c14.2 0 21.4 17.2 11.3 27.3z\"]\n};\nvar faCloudMeatball = {\n prefix: 'fas',\n iconName: 'cloud-meatball',\n icon: [512, 512, [], \"f73b\", \"M48 352c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm416 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm-119 11.1c4.6-14.5 1.6-30.8-9.8-42.3-11.5-11.5-27.8-14.4-42.3-9.9-7-13.5-20.7-23-36.9-23s-29.9 9.5-36.9 23c-14.5-4.6-30.8-1.6-42.3 9.9-11.5 11.5-14.4 27.8-9.9 42.3-13.5 7-23 20.7-23 36.9s9.5 29.9 23 36.9c-4.6 14.5-1.6 30.8 9.9 42.3 8.2 8.2 18.9 12.3 29.7 12.3 4.3 0 8.5-1.1 12.6-2.5 7 13.5 20.7 23 36.9 23s29.9-9.5 36.9-23c4.1 1.3 8.3 2.5 12.6 2.5 10.8 0 21.5-4.1 29.7-12.3 11.5-11.5 14.4-27.8 9.8-42.3 13.5-7 23-20.7 23-36.9s-9.5-29.9-23-36.9zM512 224c0-53-43-96-96-96-.6 0-1.1.2-1.6.2 1.1-5.2 1.6-10.6 1.6-16.2 0-44.2-35.8-80-80-80-24.6 0-46.3 11.3-61 28.8C256.4 24.8 219.3 0 176 0 114.1 0 64 50.1 64 112c0 7.3.8 14.3 2.1 21.2C27.8 145.8 0 181.5 0 224c0 53 43 96 96 96h43.4c3.6-8 8.4-15.4 14.8-21.8 13.5-13.5 31.5-21.1 50.8-21.3 13.5-13.2 31.7-20.9 51-20.9s37.5 7.7 51 20.9c19.3.2 37.3 7.8 50.8 21.3 6.4 6.4 11.3 13.8 14.8 21.8H416c53 0 96-43 96-96z\"]\n};\nvar faCloudMoon = {\n prefix: 'fas',\n iconName: 'cloud-moon',\n icon: [576, 512, [], \"f6c3\", \"M342.8 352.7c5.7-9.6 9.2-20.7 9.2-32.7 0-35.3-28.7-64-64-64-17.2 0-32.8 6.9-44.3 17.9-16.3-29.6-47.5-49.9-83.7-49.9-53 0-96 43-96 96 0 2 .5 3.8.6 5.7C27.1 338.8 0 374.1 0 416c0 53 43 96 96 96h240c44.2 0 80-35.8 80-80 0-41.9-32.3-75.8-73.2-79.3zm222.5-54.3c-93.1 17.7-178.5-53.7-178.5-147.7 0-54.2 29-104 76.1-130.8 7.3-4.1 5.4-15.1-2.8-16.7C448.4 1.1 436.7 0 425 0 319.1 0 233.1 85.9 233.1 192c0 8.5.7 16.8 1.8 25 5.9 4.3 11.6 8.9 16.7 14.2 11.4-4.7 23.7-7.2 36.4-7.2 52.9 0 96 43.1 96 96 0 3.6-.2 7.2-.6 10.7 23.6 10.8 42.4 29.5 53.5 52.6 54.4-3.4 103.7-29.3 137.1-70.4 5.3-6.5-.5-16.1-8.7-14.5z\"]\n};\nvar faCloudMoonRain = {\n prefix: 'fas',\n iconName: 'cloud-moon-rain',\n icon: [576, 512, [], \"f73c\", \"M350.5 225.5c-6.9-37.2-39.3-65.5-78.5-65.5-12.3 0-23.9 3-34.3 8-17.4-24.1-45.6-40-77.7-40-53 0-96 43-96 96 0 .5.2 1.1.2 1.6C27.6 232.9 0 265.2 0 304c0 44.2 35.8 80 80 80h256c44.2 0 80-35.8 80-80 0-39.2-28.2-71.7-65.5-78.5zm217.4-1.7c-70.4 13.3-135-40.3-135-110.8 0-40.6 21.9-78 57.5-98.1 5.5-3.1 4.1-11.4-2.1-12.5C479.6.8 470.7 0 461.8 0c-77.9 0-141.1 61.2-144.4 137.9 26.7 11.9 48.2 33.8 58.9 61.7 37.1 14.3 64 47.4 70.2 86.8 5.1.5 10 1.5 15.2 1.5 44.7 0 85.6-20.2 112.6-53.3 4.2-4.8-.2-12-6.4-10.8zM364.5 418.1c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8zm-96 0c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8zm-96 0c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8zm-96 0c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8z\"]\n};\nvar faCloudRain = {\n prefix: 'fas',\n iconName: 'cloud-rain',\n icon: [512, 512, [], \"f73d\", \"M416 128c-.6 0-1.1.2-1.6.2 1.1-5.2 1.6-10.6 1.6-16.2 0-44.2-35.8-80-80-80-24.6 0-46.3 11.3-61 28.8C256.4 24.8 219.3 0 176 0 114.1 0 64 50.1 64 112c0 7.3.8 14.3 2.1 21.2C27.8 145.8 0 181.5 0 224c0 53 43 96 96 96h320c53 0 96-43 96-96s-43-96-96-96zM88 374.2c-12.8 44.4-40 56.4-40 87.7 0 27.7 21.5 50.1 48 50.1s48-22.4 48-50.1c0-31.4-27.2-43.1-40-87.7-2.2-8.1-13.5-8.5-16 0zm160 0c-12.8 44.4-40 56.4-40 87.7 0 27.7 21.5 50.1 48 50.1s48-22.4 48-50.1c0-31.4-27.2-43.1-40-87.7-2.2-8.1-13.5-8.5-16 0zm160 0c-12.8 44.4-40 56.4-40 87.7 0 27.7 21.5 50.1 48 50.1s48-22.4 48-50.1c0-31.4-27.2-43.1-40-87.7-2.2-8.1-13.5-8.5-16 0z\"]\n};\nvar faCloudShowersHeavy = {\n prefix: 'fas',\n iconName: 'cloud-showers-heavy',\n icon: [512, 512, [], \"f740\", \"M183.9 370.1c-7.6-4.4-17.4-1.8-21.8 6l-64 112c-4.4 7.7-1.7 17.5 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l64-112c4.4-7.6 1.7-17.4-6-21.8zm96 0c-7.6-4.4-17.4-1.8-21.8 6l-64 112c-4.4 7.7-1.7 17.5 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l64-112c4.4-7.6 1.7-17.4-6-21.8zm-192 0c-7.6-4.4-17.4-1.8-21.8 6l-64 112c-4.4 7.7-1.7 17.5 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l64-112c4.4-7.6 1.7-17.4-6-21.8zm384 0c-7.6-4.4-17.4-1.8-21.8 6l-64 112c-4.4 7.7-1.7 17.5 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l64-112c4.4-7.6 1.7-17.4-6-21.8zm-96 0c-7.6-4.4-17.4-1.8-21.8 6l-64 112c-4.4 7.7-1.7 17.5 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l64-112c4.4-7.6 1.7-17.4-6-21.8zM416 128c-.6 0-1.1.2-1.6.2 1.1-5.2 1.6-10.6 1.6-16.2 0-44.2-35.8-80-80-80-24.6 0-46.3 11.3-61 28.8C256.4 24.8 219.3 0 176 0 114.2 0 64 50.1 64 112c0 7.3.8 14.3 2.1 21.2C27.8 145.8 0 181.5 0 224c0 53 43 96 96 96h320c53 0 96-43 96-96s-43-96-96-96z\"]\n};\nvar faCloudSun = {\n prefix: 'fas',\n iconName: 'cloud-sun',\n icon: [640, 512, [], \"f6c4\", \"M575.2 325.7c.2-1.9.8-3.7.8-5.6 0-35.3-28.7-64-64-64-12.6 0-24.2 3.8-34.1 10-17.6-38.8-56.5-66-101.9-66-61.8 0-112 50.1-112 112 0 3 .7 5.8.9 8.7-49.6 3.7-88.9 44.7-88.9 95.3 0 53 43 96 96 96h272c53 0 96-43 96-96 0-42.1-27.2-77.4-64.8-90.4zm-430.4-22.6c-43.7-43.7-43.7-114.7 0-158.3 43.7-43.7 114.7-43.7 158.4 0 9.7 9.7 16.9 20.9 22.3 32.7 9.8-3.7 20.1-6 30.7-7.5L386 81.1c4-11.9-7.3-23.1-19.2-19.2L279 91.2 237.5 8.4C232-2.8 216-2.8 210.4 8.4L169 91.2 81.1 61.9C69.3 58 58 69.3 61.9 81.1l29.3 87.8-82.8 41.5c-11.2 5.6-11.2 21.5 0 27.1l82.8 41.4-29.3 87.8c-4 11.9 7.3 23.1 19.2 19.2l76.1-25.3c6.1-12.4 14-23.7 23.6-33.5-13.1-5.4-25.4-13.4-36-24zm-4.8-79.2c0 40.8 29.3 74.8 67.9 82.3 8-4.7 16.3-8.8 25.2-11.7 5.4-44.3 31-82.5 67.4-105C287.3 160.4 258 140 224 140c-46.3 0-84 37.6-84 83.9z\"]\n};\nvar faCloudSunRain = {\n prefix: 'fas',\n iconName: 'cloud-sun-rain',\n icon: [576, 512, [], \"f743\", \"M510.5 225.5c-6.9-37.2-39.3-65.5-78.5-65.5-12.3 0-23.9 3-34.3 8-17.4-24.1-45.6-40-77.7-40-53 0-96 43-96 96 0 .5.2 1.1.2 1.6C187.6 233 160 265.2 160 304c0 44.2 35.8 80 80 80h256c44.2 0 80-35.8 80-80 0-39.2-28.2-71.7-65.5-78.5zm-386.4 34.4c-37.4-37.4-37.4-98.3 0-135.8 34.6-34.6 89.1-36.8 126.7-7.4 20-12.9 43.6-20.7 69.2-20.7.7 0 1.3.2 2 .2l8.9-26.7c3.4-10.2-6.3-19.8-16.5-16.4l-75.3 25.1-35.5-71c-4.8-9.6-18.5-9.6-23.3 0l-35.5 71-75.3-25.1c-10.2-3.4-19.8 6.3-16.4 16.5l25.1 75.3-71 35.5c-9.6 4.8-9.6 18.5 0 23.3l71 35.5-25.1 75.3c-3.4 10.2 6.3 19.8 16.5 16.5l59.2-19.7c-.2-2.4-.7-4.7-.7-7.2 0-12.5 2.3-24.5 6.2-35.9-3.6-2.7-7.1-5.2-10.2-8.3zm69.8-58c4.3-24.5 15.8-46.4 31.9-64-9.8-6.2-21.4-9.9-33.8-9.9-35.3 0-64 28.7-64 64 0 18.7 8.2 35.4 21.1 47.1 11.3-15.9 26.6-28.9 44.8-37.2zm330.6 216.2c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8zm-96 0c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8zm-96 0c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8zm-96 0c-7.6-4.3-17.4-1.8-21.8 6l-36.6 64c-4.4 7.7-1.7 17.4 6 21.8 2.5 1.4 5.2 2.1 7.9 2.1 5.5 0 10.9-2.9 13.9-8.1l36.6-64c4.3-7.7 1.7-17.4-6-21.8z\"]\n};\nvar faCloudUploadAlt = {\n prefix: 'fas',\n iconName: 'cloud-upload-alt',\n icon: [640, 512, [], \"f382\", \"M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4zM393.4 288H328v112c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V288h-65.4c-14.3 0-21.4-17.2-11.3-27.3l105.4-105.4c6.2-6.2 16.4-6.2 22.6 0l105.4 105.4c10.1 10.1 2.9 27.3-11.3 27.3z\"]\n};\nvar faCocktail = {\n prefix: 'fas',\n iconName: 'cocktail',\n icon: [576, 512, [], \"f561\", \"M296 464h-56V338.78l168.74-168.73c15.52-15.52 4.53-42.05-17.42-42.05H24.68c-21.95 0-32.94 26.53-17.42 42.05L176 338.78V464h-56c-22.09 0-40 17.91-40 40 0 4.42 3.58 8 8 8h240c4.42 0 8-3.58 8-8 0-22.09-17.91-40-40-40zM432 0c-62.61 0-115.35 40.2-135.18 96h52.54c16.65-28.55 47.27-48 82.64-48 52.93 0 96 43.06 96 96s-43.07 96-96 96c-14.04 0-27.29-3.2-39.32-8.64l-35.26 35.26C379.23 279.92 404.59 288 432 288c79.53 0 144-64.47 144-144S511.53 0 432 0z\"]\n};\nvar faCode = {\n prefix: 'fas',\n iconName: 'code',\n icon: [640, 512, [], \"f121\", \"M278.9 511.5l-61-17.7c-6.4-1.8-10-8.5-8.2-14.9L346.2 8.7c1.8-6.4 8.5-10 14.9-8.2l61 17.7c6.4 1.8 10 8.5 8.2 14.9L293.8 503.3c-1.9 6.4-8.5 10.1-14.9 8.2zm-114-112.2l43.5-46.4c4.6-4.9 4.3-12.7-.8-17.2L117 256l90.6-79.7c5.1-4.5 5.5-12.3.8-17.2l-43.5-46.4c-4.5-4.8-12.1-5.1-17-.5L3.8 247.2c-5.1 4.7-5.1 12.8 0 17.5l144.1 135.1c4.9 4.6 12.5 4.4 17-.5zm327.2.6l144.1-135.1c5.1-4.7 5.1-12.8 0-17.5L492.1 112.1c-4.8-4.5-12.4-4.3-17 .5L431.6 159c-4.6 4.9-4.3 12.7.8 17.2L523 256l-90.6 79.7c-5.1 4.5-5.5 12.3-.8 17.2l43.5 46.4c4.5 4.9 12.1 5.1 17 .6z\"]\n};\nvar faCodeBranch = {\n prefix: 'fas',\n iconName: 'code-branch',\n icon: [384, 512, [], \"f126\", \"M384 144c0-44.2-35.8-80-80-80s-80 35.8-80 80c0 36.4 24.3 67.1 57.5 76.8-.6 16.1-4.2 28.5-11 36.9-15.4 19.2-49.3 22.4-85.2 25.7-28.2 2.6-57.4 5.4-81.3 16.9v-144c32.5-10.2 56-40.5 56-76.3 0-44.2-35.8-80-80-80S0 35.8 0 80c0 35.8 23.5 66.1 56 76.3v199.3C23.5 365.9 0 396.2 0 432c0 44.2 35.8 80 80 80s80-35.8 80-80c0-34-21.2-63.1-51.2-74.6 3.1-5.2 7.8-9.8 14.9-13.4 16.2-8.2 40.4-10.4 66.1-12.8 42.2-3.9 90-8.4 118.2-43.4 14-17.4 21.1-39.8 21.6-67.9 31.6-10.8 54.4-40.7 54.4-75.9zM80 64c8.8 0 16 7.2 16 16s-7.2 16-16 16-16-7.2-16-16 7.2-16 16-16zm0 384c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm224-320c8.8 0 16 7.2 16 16s-7.2 16-16 16-16-7.2-16-16 7.2-16 16-16z\"]\n};\nvar faCoffee = {\n prefix: 'fas',\n iconName: 'coffee',\n icon: [640, 512, [], \"f0f4\", \"M192 384h192c53 0 96-43 96-96h32c70.6 0 128-57.4 128-128S582.6 32 512 32H120c-13.3 0-24 10.7-24 24v232c0 53 43 96 96 96zM512 96c35.3 0 64 28.7 64 64s-28.7 64-64 64h-32V96h32zm47.7 384H48.3c-47.6 0-61-64-36-64h583.3c25 0 11.8 64-35.9 64z\"]\n};\nvar faCog = {\n prefix: 'fas',\n iconName: 'cog',\n icon: [512, 512, [], \"f013\", \"M487.4 315.7l-42.6-24.6c4.3-23.2 4.3-47 0-70.2l42.6-24.6c4.9-2.8 7.1-8.6 5.5-14-11.1-35.6-30-67.8-54.7-94.6-3.8-4.1-10-5.1-14.8-2.3L380.8 110c-17.9-15.4-38.5-27.3-60.8-35.1V25.8c0-5.6-3.9-10.5-9.4-11.7-36.7-8.2-74.3-7.8-109.2 0-5.5 1.2-9.4 6.1-9.4 11.7V75c-22.2 7.9-42.8 19.8-60.8 35.1L88.7 85.5c-4.9-2.8-11-1.9-14.8 2.3-24.7 26.7-43.6 58.9-54.7 94.6-1.7 5.4.6 11.2 5.5 14L67.3 221c-4.3 23.2-4.3 47 0 70.2l-42.6 24.6c-4.9 2.8-7.1 8.6-5.5 14 11.1 35.6 30 67.8 54.7 94.6 3.8 4.1 10 5.1 14.8 2.3l42.6-24.6c17.9 15.4 38.5 27.3 60.8 35.1v49.2c0 5.6 3.9 10.5 9.4 11.7 36.7 8.2 74.3 7.8 109.2 0 5.5-1.2 9.4-6.1 9.4-11.7v-49.2c22.2-7.9 42.8-19.8 60.8-35.1l42.6 24.6c4.9 2.8 11 1.9 14.8-2.3 24.7-26.7 43.6-58.9 54.7-94.6 1.5-5.5-.7-11.3-5.6-14.1zM256 336c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faCogs = {\n prefix: 'fas',\n iconName: 'cogs',\n icon: [640, 512, [], \"f085\", \"M512.1 191l-8.2 14.3c-3 5.3-9.4 7.5-15.1 5.4-11.8-4.4-22.6-10.7-32.1-18.6-4.6-3.8-5.8-10.5-2.8-15.7l8.2-14.3c-6.9-8-12.3-17.3-15.9-27.4h-16.5c-6 0-11.2-4.3-12.2-10.3-2-12-2.1-24.6 0-37.1 1-6 6.2-10.4 12.2-10.4h16.5c3.6-10.1 9-19.4 15.9-27.4l-8.2-14.3c-3-5.2-1.9-11.9 2.8-15.7 9.5-7.9 20.4-14.2 32.1-18.6 5.7-2.1 12.1.1 15.1 5.4l8.2 14.3c10.5-1.9 21.2-1.9 31.7 0L552 6.3c3-5.3 9.4-7.5 15.1-5.4 11.8 4.4 22.6 10.7 32.1 18.6 4.6 3.8 5.8 10.5 2.8 15.7l-8.2 14.3c6.9 8 12.3 17.3 15.9 27.4h16.5c6 0 11.2 4.3 12.2 10.3 2 12 2.1 24.6 0 37.1-1 6-6.2 10.4-12.2 10.4h-16.5c-3.6 10.1-9 19.4-15.9 27.4l8.2 14.3c3 5.2 1.9 11.9-2.8 15.7-9.5 7.9-20.4 14.2-32.1 18.6-5.7 2.1-12.1-.1-15.1-5.4l-8.2-14.3c-10.4 1.9-21.2 1.9-31.7 0zm-10.5-58.8c38.5 29.6 82.4-14.3 52.8-52.8-38.5-29.7-82.4 14.3-52.8 52.8zM386.3 286.1l33.7 16.8c10.1 5.8 14.5 18.1 10.5 29.1-8.9 24.2-26.4 46.4-42.6 65.8-7.4 8.9-20.2 11.1-30.3 5.3l-29.1-16.8c-16 13.7-34.6 24.6-54.9 31.7v33.6c0 11.6-8.3 21.6-19.7 23.6-24.6 4.2-50.4 4.4-75.9 0-11.5-2-20-11.9-20-23.6V418c-20.3-7.2-38.9-18-54.9-31.7L74 403c-10 5.8-22.9 3.6-30.3-5.3-16.2-19.4-33.3-41.6-42.2-65.7-4-10.9.4-23.2 10.5-29.1l33.3-16.8c-3.9-20.9-3.9-42.4 0-63.4L12 205.8c-10.1-5.8-14.6-18.1-10.5-29 8.9-24.2 26-46.4 42.2-65.8 7.4-8.9 20.2-11.1 30.3-5.3l29.1 16.8c16-13.7 34.6-24.6 54.9-31.7V57.1c0-11.5 8.2-21.5 19.6-23.5 24.6-4.2 50.5-4.4 76-.1 11.5 2 20 11.9 20 23.6v33.6c20.3 7.2 38.9 18 54.9 31.7l29.1-16.8c10-5.8 22.9-3.6 30.3 5.3 16.2 19.4 33.2 41.6 42.1 65.8 4 10.9.1 23.2-10 29.1l-33.7 16.8c3.9 21 3.9 42.5 0 63.5zm-117.6 21.1c59.2-77-28.7-164.9-105.7-105.7-59.2 77 28.7 164.9 105.7 105.7zm243.4 182.7l-8.2 14.3c-3 5.3-9.4 7.5-15.1 5.4-11.8-4.4-22.6-10.7-32.1-18.6-4.6-3.8-5.8-10.5-2.8-15.7l8.2-14.3c-6.9-8-12.3-17.3-15.9-27.4h-16.5c-6 0-11.2-4.3-12.2-10.3-2-12-2.1-24.6 0-37.1 1-6 6.2-10.4 12.2-10.4h16.5c3.6-10.1 9-19.4 15.9-27.4l-8.2-14.3c-3-5.2-1.9-11.9 2.8-15.7 9.5-7.9 20.4-14.2 32.1-18.6 5.7-2.1 12.1.1 15.1 5.4l8.2 14.3c10.5-1.9 21.2-1.9 31.7 0l8.2-14.3c3-5.3 9.4-7.5 15.1-5.4 11.8 4.4 22.6 10.7 32.1 18.6 4.6 3.8 5.8 10.5 2.8 15.7l-8.2 14.3c6.9 8 12.3 17.3 15.9 27.4h16.5c6 0 11.2 4.3 12.2 10.3 2 12 2.1 24.6 0 37.1-1 6-6.2 10.4-12.2 10.4h-16.5c-3.6 10.1-9 19.4-15.9 27.4l8.2 14.3c3 5.2 1.9 11.9-2.8 15.7-9.5 7.9-20.4 14.2-32.1 18.6-5.7 2.1-12.1-.1-15.1-5.4l-8.2-14.3c-10.4 1.9-21.2 1.9-31.7 0zM501.6 431c38.5 29.6 82.4-14.3 52.8-52.8-38.5-29.6-82.4 14.3-52.8 52.8z\"]\n};\nvar faCoins = {\n prefix: 'fas',\n iconName: 'coins',\n icon: [512, 512, [], \"f51e\", \"M0 405.3V448c0 35.3 86 64 192 64s192-28.7 192-64v-42.7C342.7 434.4 267.2 448 192 448S41.3 434.4 0 405.3zM320 128c106 0 192-28.7 192-64S426 0 320 0 128 28.7 128 64s86 64 192 64zM0 300.4V352c0 35.3 86 64 192 64s192-28.7 192-64v-51.6c-41.3 34-116.9 51.6-192 51.6S41.3 334.4 0 300.4zm416 11c57.3-11.1 96-31.7 96-55.4v-42.7c-23.2 16.4-57.3 27.6-96 34.5v63.6zM192 160C86 160 0 195.8 0 240s86 80 192 80 192-35.8 192-80-86-80-192-80zm219.3 56.3c60-10.8 100.7-32 100.7-56.3v-42.7c-35.5 25.1-96.5 38.6-160.7 41.8 29.5 14.3 51.2 33.5 60 57.2z\"]\n};\nvar faColumns = {\n prefix: 'fas',\n iconName: 'columns',\n icon: [512, 512, [], \"f0db\", \"M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM224 416H64V160h160v256zm224 0H288V160h160v256z\"]\n};\nvar faComment = {\n prefix: 'fas',\n iconName: 'comment',\n icon: [512, 512, [], \"f075\", \"M256 32C114.6 32 0 125.1 0 240c0 49.6 21.4 95 57 130.7C44.5 421.1 2.7 466 2.2 466.5c-2.2 2.3-2.8 5.7-1.5 8.7S4.8 480 8 480c66.3 0 116-31.8 140.6-51.4 32.7 12.3 69 19.4 107.4 19.4 141.4 0 256-93.1 256-208S397.4 32 256 32z\"]\n};\nvar faCommentAlt = {\n prefix: 'fas',\n iconName: 'comment-alt',\n icon: [512, 512, [], \"f27a\", \"M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z\"]\n};\nvar faCommentDollar = {\n prefix: 'fas',\n iconName: 'comment-dollar',\n icon: [512, 512, [], \"f651\", \"M256 32C114.62 32 0 125.12 0 240c0 49.56 21.41 95.01 57.02 130.74C44.46 421.05 2.7 465.97 2.2 466.5A7.995 7.995 0 0 0 8 480c66.26 0 115.99-31.75 140.6-51.38C181.29 440.93 217.59 448 256 448c141.38 0 256-93.12 256-208S397.38 32 256 32zm24 302.44V352c0 8.84-7.16 16-16 16h-16c-8.84 0-16-7.16-16-16v-17.73c-11.42-1.35-22.28-5.19-31.78-11.46-6.22-4.11-6.82-13.11-1.55-18.38l17.52-17.52c3.74-3.74 9.31-4.24 14.11-2.03 3.18 1.46 6.66 2.22 10.26 2.22h32.78c4.66 0 8.44-3.78 8.44-8.42 0-3.75-2.52-7.08-6.12-8.11l-50.07-14.3c-22.25-6.35-40.01-24.71-42.91-47.67-4.05-32.07 19.03-59.43 49.32-63.05V128c0-8.84 7.16-16 16-16h16c8.84 0 16 7.16 16 16v17.73c11.42 1.35 22.28 5.19 31.78 11.46 6.22 4.11 6.82 13.11 1.55 18.38l-17.52 17.52c-3.74 3.74-9.31 4.24-14.11 2.03a24.516 24.516 0 0 0-10.26-2.22h-32.78c-4.66 0-8.44 3.78-8.44 8.42 0 3.75 2.52 7.08 6.12 8.11l50.07 14.3c22.25 6.36 40.01 24.71 42.91 47.67 4.05 32.06-19.03 59.42-49.32 63.04z\"]\n};\nvar faCommentDots = {\n prefix: 'fas',\n iconName: 'comment-dots',\n icon: [512, 512, [], \"f4ad\", \"M256 32C114.6 32 0 125.1 0 240c0 49.6 21.4 95 57 130.7C44.5 421.1 2.7 466 2.2 466.5c-2.2 2.3-2.8 5.7-1.5 8.7S4.8 480 8 480c66.3 0 116-31.8 140.6-51.4 32.7 12.3 69 19.4 107.4 19.4 141.4 0 256-93.1 256-208S397.4 32 256 32zM128 272c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm128 0c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm128 0c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faCommentMedical = {\n prefix: 'fas',\n iconName: 'comment-medical',\n icon: [512, 512, [], \"f7f5\", \"M256 32C114.62 32 0 125.12 0 240c0 49.56 21.41 95 57 130.74C44.46 421.05 2.7 466 2.2 466.5A8 8 0 0 0 8 480c66.26 0 116-31.75 140.6-51.38A304.66 304.66 0 0 0 256 448c141.39 0 256-93.12 256-208S397.39 32 256 32zm96 232a8 8 0 0 1-8 8h-56v56a8 8 0 0 1-8 8h-48a8 8 0 0 1-8-8v-56h-56a8 8 0 0 1-8-8v-48a8 8 0 0 1 8-8h56v-56a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8v56h56a8 8 0 0 1 8 8z\"]\n};\nvar faCommentSlash = {\n prefix: 'fas',\n iconName: 'comment-slash',\n icon: [640, 512, [], \"f4b3\", \"M64 240c0 49.6 21.4 95 57 130.7-12.6 50.3-54.3 95.2-54.8 95.8-2.2 2.3-2.8 5.7-1.5 8.7 1.3 2.9 4.1 4.8 7.3 4.8 66.3 0 116-31.8 140.6-51.4 32.7 12.3 69 19.4 107.4 19.4 27.4 0 53.7-3.6 78.4-10L72.9 186.4c-5.6 17.1-8.9 35-8.9 53.6zm569.8 218.1l-114.4-88.4C554.6 334.1 576 289.2 576 240c0-114.9-114.6-208-256-208-65.1 0-124.2 20.1-169.4 52.7L45.5 3.4C38.5-2 28.5-.8 23 6.2L3.4 31.4c-5.4 7-4.2 17 2.8 22.4l588.4 454.7c7 5.4 17 4.2 22.5-2.8l19.6-25.3c5.4-6.8 4.1-16.9-2.9-22.3z\"]\n};\nvar faComments = {\n prefix: 'fas',\n iconName: 'comments',\n icon: [576, 512, [], \"f086\", \"M416 192c0-88.4-93.1-160-208-160S0 103.6 0 192c0 34.3 14.1 65.9 38 92-13.4 30.2-35.5 54.2-35.8 54.5-2.2 2.3-2.8 5.7-1.5 8.7S4.8 352 8 352c36.6 0 66.9-12.3 88.7-25 32.2 15.7 70.3 25 111.3 25 114.9 0 208-71.6 208-160zm122 220c23.9-26 38-57.7 38-92 0-66.9-53.5-124.2-129.3-148.1.9 6.6 1.3 13.3 1.3 20.1 0 105.9-107.7 192-240 192-10.8 0-21.3-.8-31.7-1.9C207.8 439.6 281.8 480 368 480c41 0 79.1-9.2 111.3-25 21.8 12.7 52.1 25 88.7 25 3.2 0 6.1-1.9 7.3-4.8 1.3-2.9.7-6.3-1.5-8.7-.3-.3-22.4-24.2-35.8-54.5z\"]\n};\nvar faCommentsDollar = {\n prefix: 'fas',\n iconName: 'comments-dollar',\n icon: [576, 512, [], \"f653\", \"M416 192c0-88.37-93.12-160-208-160S0 103.63 0 192c0 34.27 14.13 65.95 37.97 91.98C24.61 314.22 2.52 338.16 2.2 338.5A7.995 7.995 0 0 0 8 352c36.58 0 66.93-12.25 88.73-24.98C128.93 342.76 167.02 352 208 352c114.88 0 208-71.63 208-160zm-224 96v-16.29c-11.29-.58-22.27-4.52-31.37-11.35-3.9-2.93-4.1-8.77-.57-12.14l11.75-11.21c2.77-2.64 6.89-2.76 10.13-.73 3.87 2.42 8.26 3.72 12.82 3.72h28.11c6.5 0 11.8-5.92 11.8-13.19 0-5.95-3.61-11.19-8.77-12.73l-45-13.5c-18.59-5.58-31.58-23.42-31.58-43.39 0-24.52 19.05-44.44 42.67-45.07V96c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16.29c11.29.58 22.27 4.51 31.37 11.35 3.9 2.93 4.1 8.77.57 12.14l-11.75 11.21c-2.77 2.64-6.89 2.76-10.13.73-3.87-2.43-8.26-3.72-12.82-3.72h-28.11c-6.5 0-11.8 5.92-11.8 13.19 0 5.95 3.61 11.19 8.77 12.73l45 13.5c18.59 5.58 31.58 23.42 31.58 43.39 0 24.53-19.05 44.44-42.67 45.07V288c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8zm346.01 123.99C561.87 385.96 576 354.27 576 320c0-66.94-53.49-124.2-129.33-148.07.86 6.6 1.33 13.29 1.33 20.07 0 105.87-107.66 192-240 192-10.78 0-21.32-.77-31.73-1.88C207.8 439.63 281.77 480 368 480c40.98 0 79.07-9.24 111.27-24.98C501.07 467.75 531.42 480 568 480c3.2 0 6.09-1.91 7.34-4.84 1.27-2.94.66-6.34-1.55-8.67-.31-.33-22.42-24.24-35.78-54.5z\"]\n};\nvar faCompactDisc = {\n prefix: 'fas',\n iconName: 'compact-disc',\n icon: [496, 512, [], \"f51f\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM88 256H56c0-105.9 86.1-192 192-192v32c-88.2 0-160 71.8-160 160zm160 96c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96zm0-128c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z\"]\n};\nvar faCompass = {\n prefix: 'fas',\n iconName: 'compass',\n icon: [496, 512, [], \"f14e\", \"M225.38 233.37c-12.5 12.5-12.5 32.76 0 45.25 12.49 12.5 32.76 12.5 45.25 0 12.5-12.5 12.5-32.76 0-45.25-12.5-12.49-32.76-12.49-45.25 0zM248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm126.14 148.05L308.17 300.4a31.938 31.938 0 0 1-15.77 15.77l-144.34 65.97c-16.65 7.61-33.81-9.55-26.2-26.2l65.98-144.35a31.938 31.938 0 0 1 15.77-15.77l144.34-65.97c16.65-7.6 33.8 9.55 26.19 26.2z\"]\n};\nvar faCompress = {\n prefix: 'fas',\n iconName: 'compress',\n icon: [448, 512, [], \"f066\", \"M436 192H312c-13.3 0-24-10.7-24-24V44c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v84h84c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm-276-24V44c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v84H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24zm0 300V344c0-13.3-10.7-24-24-24H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-84h84c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12H312c-13.3 0-24 10.7-24 24v124c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12z\"]\n};\nvar faCompressArrowsAlt = {\n prefix: 'fas',\n iconName: 'compress-arrows-alt',\n icon: [512, 512, [], \"f78c\", \"M200 288H88c-21.4 0-32.1 25.8-17 41l32.9 31-99.2 99.3c-6.2 6.2-6.2 16.4 0 22.6l25.4 25.4c6.2 6.2 16.4 6.2 22.6 0L152 408l31.1 33c15.1 15.1 40.9 4.4 40.9-17V312c0-13.3-10.7-24-24-24zm112-64h112c21.4 0 32.1-25.9 17-41l-33-31 99.3-99.3c6.2-6.2 6.2-16.4 0-22.6L481.9 4.7c-6.2-6.2-16.4-6.2-22.6 0L360 104l-31.1-33C313.8 55.9 288 66.6 288 88v112c0 13.3 10.7 24 24 24zm96 136l33-31.1c15.1-15.1 4.4-40.9-17-40.9H312c-13.3 0-24 10.7-24 24v112c0 21.4 25.9 32.1 41 17l31-32.9 99.3 99.3c6.2 6.2 16.4 6.2 22.6 0l25.4-25.4c6.2-6.2 6.2-16.4 0-22.6L408 360zM183 71.1L152 104 52.7 4.7c-6.2-6.2-16.4-6.2-22.6 0L4.7 30.1c-6.2 6.2-6.2 16.4 0 22.6L104 152l-33 31.1C55.9 198.2 66.6 224 88 224h112c13.3 0 24-10.7 24-24V88c0-21.3-25.9-32-41-16.9z\"]\n};\nvar faConciergeBell = {\n prefix: 'fas',\n iconName: 'concierge-bell',\n icon: [512, 512, [], \"f562\", \"M288 130.54V112h16c8.84 0 16-7.16 16-16V80c0-8.84-7.16-16-16-16h-96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h16v18.54C115.49 146.11 32 239.18 32 352h448c0-112.82-83.49-205.89-192-221.46zM496 384H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h480c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16z\"]\n};\nvar faCookie = {\n prefix: 'fas',\n iconName: 'cookie',\n icon: [512, 512, [], \"f563\", \"M510.37 254.79l-12.08-76.26a132.493 132.493 0 0 0-37.16-72.95l-54.76-54.75c-19.73-19.72-45.18-32.7-72.71-37.05l-76.7-12.15c-27.51-4.36-55.69.11-80.52 12.76L107.32 49.6a132.25 132.25 0 0 0-57.79 57.8l-35.1 68.88a132.602 132.602 0 0 0-12.82 80.94l12.08 76.27a132.493 132.493 0 0 0 37.16 72.95l54.76 54.75a132.087 132.087 0 0 0 72.71 37.05l76.7 12.14c27.51 4.36 55.69-.11 80.52-12.75l69.12-35.21a132.302 132.302 0 0 0 57.79-57.8l35.1-68.87c12.71-24.96 17.2-53.3 12.82-80.96zM176 368c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm32-160c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm160 128c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faCookieBite = {\n prefix: 'fas',\n iconName: 'cookie-bite',\n icon: [512, 512, [], \"f564\", \"M510.52 255.82c-69.97-.85-126.47-57.69-126.47-127.86-70.17 0-127-56.49-127.86-126.45-27.26-4.14-55.13.3-79.72 12.82l-69.13 35.22a132.221 132.221 0 0 0-57.79 57.81l-35.1 68.88a132.645 132.645 0 0 0-12.82 80.95l12.08 76.27a132.521 132.521 0 0 0 37.16 72.96l54.77 54.76a132.036 132.036 0 0 0 72.71 37.06l76.71 12.15c27.51 4.36 55.7-.11 80.53-12.76l69.13-35.21a132.273 132.273 0 0 0 57.79-57.81l35.1-68.88c12.56-24.64 17.01-52.58 12.91-79.91zM176 368c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm32-160c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm160 128c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faCopy = {\n prefix: 'fas',\n iconName: 'copy',\n icon: [448, 512, [], \"f0c5\", \"M320 448v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h72v296c0 30.879 25.121 56 56 56h168zm0-344V0H152c-13.255 0-24 10.745-24 24v368c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24V128H344c-13.2 0-24-10.8-24-24zm120.971-31.029L375.029 7.029A24 24 0 0 0 358.059 0H352v96h96v-6.059a24 24 0 0 0-7.029-16.97z\"]\n};\nvar faCopyright = {\n prefix: 'fas',\n iconName: 'copyright',\n icon: [512, 512, [], \"f1f9\", \"M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm117.134 346.753c-1.592 1.867-39.776 45.731-109.851 45.731-84.692 0-144.484-63.26-144.484-145.567 0-81.303 62.004-143.401 143.762-143.401 66.957 0 101.965 37.315 103.422 38.904a12 12 0 0 1 1.238 14.623l-22.38 34.655c-4.049 6.267-12.774 7.351-18.234 2.295-.233-.214-26.529-23.88-61.88-23.88-46.116 0-73.916 33.575-73.916 76.082 0 39.602 25.514 79.692 74.277 79.692 38.697 0 65.28-28.338 65.544-28.625 5.132-5.565 14.059-5.033 18.508 1.053l24.547 33.572a12.001 12.001 0 0 1-.553 14.866z\"]\n};\nvar faCouch = {\n prefix: 'fas',\n iconName: 'couch',\n icon: [640, 512, [], \"f4b8\", \"M160 224v64h320v-64c0-35.3 28.7-64 64-64h32c0-53-43-96-96-96H160c-53 0-96 43-96 96h32c35.3 0 64 28.7 64 64zm416-32h-32c-17.7 0-32 14.3-32 32v96H128v-96c0-17.7-14.3-32-32-32H64c-35.3 0-64 28.7-64 64 0 23.6 13 44 32 55.1V432c0 8.8 7.2 16 16 16h64c8.8 0 16-7.2 16-16v-16h384v16c0 8.8 7.2 16 16 16h64c8.8 0 16-7.2 16-16V311.1c19-11.1 32-31.5 32-55.1 0-35.3-28.7-64-64-64z\"]\n};\nvar faCreditCard = {\n prefix: 'fas',\n iconName: 'credit-card',\n icon: [576, 512, [], \"f09d\", \"M0 432c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V256H0v176zm192-68c0-6.6 5.4-12 12-12h136c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H204c-6.6 0-12-5.4-12-12v-40zm-128 0c0-6.6 5.4-12 12-12h72c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zM576 80v48H0V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48z\"]\n};\nvar faCrop = {\n prefix: 'fas',\n iconName: 'crop',\n icon: [512, 512, [], \"f125\", \"M488 352h-40V109.25l59.31-59.31c6.25-6.25 6.25-16.38 0-22.63L484.69 4.69c-6.25-6.25-16.38-6.25-22.63 0L402.75 64H192v96h114.75L160 306.75V24c0-13.26-10.75-24-24-24H88C74.75 0 64 10.74 64 24v40H24C10.75 64 0 74.74 0 88v48c0 13.25 10.75 24 24 24h40v264c0 13.25 10.75 24 24 24h232v-96H205.25L352 205.25V488c0 13.25 10.75 24 24 24h48c13.25 0 24-10.75 24-24v-40h40c13.25 0 24-10.75 24-24v-48c0-13.26-10.75-24-24-24z\"]\n};\nvar faCropAlt = {\n prefix: 'fas',\n iconName: 'crop-alt',\n icon: [512, 512, [], \"f565\", \"M488 352h-40V96c0-17.67-14.33-32-32-32H192v96h160v328c0 13.25 10.75 24 24 24h48c13.25 0 24-10.75 24-24v-40h40c13.25 0 24-10.75 24-24v-48c0-13.26-10.75-24-24-24zM160 24c0-13.26-10.75-24-24-24H88C74.75 0 64 10.74 64 24v40H24C10.75 64 0 74.74 0 88v48c0 13.25 10.75 24 24 24h40v256c0 17.67 14.33 32 32 32h224v-96H160V24z\"]\n};\nvar faCross = {\n prefix: 'fas',\n iconName: 'cross',\n icon: [384, 512, [], \"f654\", \"M352 128h-96V32c0-17.67-14.33-32-32-32h-64c-17.67 0-32 14.33-32 32v96H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h96v224c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32V256h96c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32z\"]\n};\nvar faCrosshairs = {\n prefix: 'fas',\n iconName: 'crosshairs',\n icon: [512, 512, [], \"f05b\", \"M500 224h-30.364C455.724 130.325 381.675 56.276 288 42.364V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v30.364C130.325 56.276 56.276 130.325 42.364 224H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h30.364C56.276 381.675 130.325 455.724 224 469.636V500c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-30.364C381.675 455.724 455.724 381.675 469.636 288H500c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12zM288 404.634V364c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40.634C165.826 392.232 119.783 346.243 107.366 288H148c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40.634C119.768 165.826 165.757 119.783 224 107.366V148c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40.634C346.174 119.768 392.217 165.757 404.634 224H364c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40.634C392.232 346.174 346.243 392.217 288 404.634zM288 256c0 17.673-14.327 32-32 32s-32-14.327-32-32c0-17.673 14.327-32 32-32s32 14.327 32 32z\"]\n};\nvar faCrow = {\n prefix: 'fas',\n iconName: 'crow',\n icon: [640, 512, [], \"f520\", \"M544 32h-16.36C513.04 12.68 490.09 0 464 0c-44.18 0-80 35.82-80 80v20.98L12.09 393.57A30.216 30.216 0 0 0 0 417.74c0 22.46 23.64 37.07 43.73 27.03L165.27 384h96.49l44.41 120.1c2.27 6.23 9.15 9.44 15.38 7.17l22.55-8.21c6.23-2.27 9.44-9.15 7.17-15.38L312.94 384H352c1.91 0 3.76-.23 5.66-.29l44.51 120.38c2.27 6.23 9.15 9.44 15.38 7.17l22.55-8.21c6.23-2.27 9.44-9.15 7.17-15.38l-41.24-111.53C485.74 352.8 544 279.26 544 192v-80l96-16c0-35.35-42.98-64-96-64zm-80 72c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24z\"]\n};\nvar faCrown = {\n prefix: 'fas',\n iconName: 'crown',\n icon: [640, 512, [], \"f521\", \"M528 448H112c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h416c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm64-320c-26.5 0-48 21.5-48 48 0 7.1 1.6 13.7 4.4 19.8L476 239.2c-15.4 9.2-35.3 4-44.2-11.6L350.3 85C361 76.2 368 63 368 48c0-26.5-21.5-48-48-48s-48 21.5-48 48c0 15 7 28.2 17.7 37l-81.5 142.6c-8.9 15.6-28.9 20.8-44.2 11.6l-72.3-43.4c2.7-6 4.4-12.7 4.4-19.8 0-26.5-21.5-48-48-48S0 149.5 0 176s21.5 48 48 48c2.6 0 5.2-.4 7.7-.8L128 416h384l72.3-192.8c2.5.4 5.1.8 7.7.8 26.5 0 48-21.5 48-48s-21.5-48-48-48z\"]\n};\nvar faCrutch = {\n prefix: 'fas',\n iconName: 'crutch',\n icon: [512, 512, [], \"f7f7\", \"M507.31 185.71l-181-181a16 16 0 0 0-22.62 0L281 27.31a16 16 0 0 0 0 22.63l181 181a16 16 0 0 0 22.63 0l22.62-22.63a16 16 0 0 0 .06-22.6zm-179.54 66.41l-67.89-67.89 55.1-55.1-45.25-45.25-109.67 109.67a96.08 96.08 0 0 0-25.67 46.29L106.65 360.1l-102 102a16 16 0 0 0 0 22.63l22.62 22.62a16 16 0 0 0 22.63 0l102-102 120.25-27.75a95.88 95.88 0 0 0 46.29-25.65l109.68-109.68L382.87 197zm-54.57 54.57a32 32 0 0 1-15.45 8.54l-79.3 18.32 18.3-79.3a32.22 32.22 0 0 1 8.56-15.45l9.31-9.31 67.89 67.89z\"]\n};\nvar faCube = {\n prefix: 'fas',\n iconName: 'cube',\n icon: [512, 512, [], \"f1b2\", \"M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z\"]\n};\nvar faCubes = {\n prefix: 'fas',\n iconName: 'cubes',\n icon: [512, 512, [], \"f1b3\", \"M488.6 250.2L392 214V105.5c0-15-9.3-28.4-23.4-33.7l-100-37.5c-8.1-3.1-17.1-3.1-25.3 0l-100 37.5c-14.1 5.3-23.4 18.7-23.4 33.7V214l-96.6 36.2C9.3 255.5 0 268.9 0 283.9V394c0 13.6 7.7 26.1 19.9 32.2l100 50c10.1 5.1 22.1 5.1 32.2 0l103.9-52 103.9 52c10.1 5.1 22.1 5.1 32.2 0l100-50c12.2-6.1 19.9-18.6 19.9-32.2V283.9c0-15-9.3-28.4-23.4-33.7zM358 214.8l-85 31.9v-68.2l85-37v73.3zM154 104.1l102-38.2 102 38.2v.6l-102 41.4-102-41.4v-.6zm84 291.1l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6zm240 112l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6z\"]\n};\nvar faCut = {\n prefix: 'fas',\n iconName: 'cut',\n icon: [448, 512, [], \"f0c4\", \"M278.06 256L444.48 89.57c4.69-4.69 4.69-12.29 0-16.97-32.8-32.8-85.99-32.8-118.79 0L210.18 188.12l-24.86-24.86c4.31-10.92 6.68-22.81 6.68-35.26 0-53.02-42.98-96-96-96S0 74.98 0 128s42.98 96 96 96c4.54 0 8.99-.32 13.36-.93L142.29 256l-32.93 32.93c-4.37-.61-8.83-.93-13.36-.93-53.02 0-96 42.98-96 96s42.98 96 96 96 96-42.98 96-96c0-12.45-2.37-24.34-6.68-35.26l24.86-24.86L325.69 439.4c32.8 32.8 85.99 32.8 118.79 0 4.69-4.68 4.69-12.28 0-16.97L278.06 256zM96 160c-17.64 0-32-14.36-32-32s14.36-32 32-32 32 14.36 32 32-14.36 32-32 32zm0 256c-17.64 0-32-14.36-32-32s14.36-32 32-32 32 14.36 32 32-14.36 32-32 32z\"]\n};\nvar faDatabase = {\n prefix: 'fas',\n iconName: 'database',\n icon: [448, 512, [], \"f1c0\", \"M448 73.143v45.714C448 159.143 347.667 192 224 192S0 159.143 0 118.857V73.143C0 32.857 100.333 0 224 0s224 32.857 224 73.143zM448 176v102.857C448 319.143 347.667 352 224 352S0 319.143 0 278.857V176c48.125 33.143 136.208 48.572 224 48.572S399.874 209.143 448 176zm0 160v102.857C448 479.143 347.667 512 224 512S0 479.143 0 438.857V336c48.125 33.143 136.208 48.572 224 48.572S399.874 369.143 448 336z\"]\n};\nvar faDeaf = {\n prefix: 'fas',\n iconName: 'deaf',\n icon: [512, 512, [], \"f2a4\", \"M216 260c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-44.112 35.888-80 80-80s80 35.888 80 80c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-13.234-10.767-24-24-24s-24 10.766-24 24zm24-176c-97.047 0-176 78.953-176 176 0 15.464 12.536 28 28 28s28-12.536 28-28c0-66.168 53.832-120 120-120s120 53.832 120 120c0 75.164-71.009 70.311-71.997 143.622L288 404c0 28.673-23.327 52-52 52-15.464 0-28 12.536-28 28s12.536 28 28 28c59.475 0 107.876-48.328 108-107.774.595-34.428 72-48.24 72-144.226 0-97.047-78.953-176-176-176zm268.485-52.201L480.2 3.515c-4.687-4.686-12.284-4.686-16.971 0L376.2 90.544c-4.686 4.686-4.686 12.284 0 16.971l28.285 28.285c4.686 4.686 12.284 4.686 16.97 0l87.03-87.029c4.687-4.688 4.687-12.286 0-16.972zM168.97 314.745c-4.686-4.686-12.284-4.686-16.97 0L3.515 463.23c-4.686 4.686-4.686 12.284 0 16.971L31.8 508.485c4.687 4.686 12.284 4.686 16.971 0L197.256 360c4.686-4.686 4.686-12.284 0-16.971l-28.286-28.284z\"]\n};\nvar faDemocrat = {\n prefix: 'fas',\n iconName: 'democrat',\n icon: [640, 512, [], \"f747\", \"M637.3 256.9l-19.6-29.4c-28.2-42.3-75.3-67.5-126.1-67.5H256l-81.2-81.2c20.1-20.1 22.6-51.1 7.5-73.9-3.4-5.2-10.8-5.9-15.2-1.5l-41.8 41.8L82.4 2.4c-3.6-3.6-9.6-3-12.4 1.2-12.3 18.6-10.3 44 6.1 60.4 3.3 3.3 7.3 5.3 11.3 7.5-2.2 1.7-4.7 3.1-6.4 5.4L6.4 176.2c-7.3 9.7-8.4 22.7-3 33.5l14.3 28.6c5.4 10.8 16.5 17.7 28.6 17.7h31c8.5 0 16.6-3.4 22.6-9.4L138 212l54 108h352v-77.8c16.2 12.2 18.3 17.6 40.1 50.3 4.9 7.4 14.8 9.3 22.2 4.4l26.6-17.7c7.3-5 9.3-14.9 4.4-22.3zm-341.1-13.6l-16.5 16.1 3.9 22.7c.7 4.1-3.6 7.2-7.2 5.3L256 276.7l-20.4 10.7c-3.6 1.9-7.9-1.2-7.2-5.3l3.9-22.7-16.5-16.1c-3-2.9-1.3-7.9 2.8-8.5l22.8-3.3 10.2-20.7c1.8-3.7 7.1-3.7 9 0l10.2 20.7 22.8 3.3c4 .6 5.6 5.6 2.6 8.5zm112 0l-16.5 16.1 3.9 22.7c.7 4.1-3.6 7.2-7.2 5.3L368 276.7l-20.4 10.7c-3.6 1.9-7.9-1.2-7.2-5.3l3.9-22.7-16.5-16.1c-3-2.9-1.3-7.9 2.8-8.5l22.8-3.3 10.2-20.7c1.8-3.7 7.1-3.7 9 0l10.2 20.7 22.8 3.3c4 .6 5.6 5.6 2.6 8.5zm112 0l-16.5 16.1 3.9 22.7c.7 4.1-3.6 7.2-7.2 5.3L480 276.7l-20.4 10.7c-3.6 1.9-7.9-1.2-7.2-5.3l3.9-22.7-16.5-16.1c-3-2.9-1.3-7.9 2.8-8.5l22.8-3.3 10.2-20.7c1.8-3.7 7.1-3.7 9 0l10.2 20.7 22.8 3.3c4 .6 5.6 5.6 2.6 8.5zM192 496c0 8.8 7.2 16 16 16h64c8.8 0 16-7.2 16-16v-80h160v80c0 8.8 7.2 16 16 16h64c8.8 0 16-7.2 16-16V352H192v144z\"]\n};\nvar faDesktop = {\n prefix: 'fas',\n iconName: 'desktop',\n icon: [576, 512, [], \"f108\", \"M528 0H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h192l-16 48h-72c-13.3 0-24 10.7-24 24s10.7 24 24 24h272c13.3 0 24-10.7 24-24s-10.7-24-24-24h-72l-16-48h192c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-16 352H64V64h448v288z\"]\n};\nvar faDharmachakra = {\n prefix: 'fas',\n iconName: 'dharmachakra',\n icon: [512, 512, [], \"f655\", \"M495 225.06l-17.22 1.08c-5.27-39.49-20.79-75.64-43.86-105.84l12.95-11.43c6.92-6.11 7.25-16.79.73-23.31L426.44 64.4c-6.53-6.53-17.21-6.19-23.31.73L391.7 78.07c-30.2-23.06-66.35-38.58-105.83-43.86L286.94 17c.58-9.21-6.74-17-15.97-17h-29.94c-9.23 0-16.54 7.79-15.97 17l1.08 17.22c-39.49 5.27-75.64 20.79-105.83 43.86l-11.43-12.95c-6.11-6.92-16.79-7.25-23.31-.73L64.4 85.56c-6.53 6.53-6.19 17.21.73 23.31l12.95 11.43c-23.06 30.2-38.58 66.35-43.86 105.84L17 225.06c-9.21-.58-17 6.74-17 15.97v29.94c0 9.23 7.79 16.54 17 15.97l17.22-1.08c5.27 39.49 20.79 75.64 43.86 105.83l-12.95 11.43c-6.92 6.11-7.25 16.79-.73 23.31l21.17 21.17c6.53 6.53 17.21 6.19 23.31-.73l11.43-12.95c30.2 23.06 66.35 38.58 105.84 43.86L225.06 495c-.58 9.21 6.74 17 15.97 17h29.94c9.23 0 16.54-7.79 15.97-17l-1.08-17.22c39.49-5.27 75.64-20.79 105.84-43.86l11.43 12.95c6.11 6.92 16.79 7.25 23.31.73l21.17-21.17c6.53-6.53 6.19-17.21-.73-23.31l-12.95-11.43c23.06-30.2 38.58-66.35 43.86-105.83l17.22 1.08c9.21.58 17-6.74 17-15.97v-29.94c-.01-9.23-7.8-16.54-17.01-15.97zM281.84 98.61c24.81 4.07 47.63 13.66 67.23 27.78l-42.62 48.29c-8.73-5.44-18.32-9.54-28.62-11.95l4.01-64.12zm-51.68 0l4.01 64.12c-10.29 2.41-19.89 6.52-28.62 11.95l-42.62-48.29c19.6-14.12 42.42-23.71 67.23-27.78zm-103.77 64.33l48.3 42.61c-5.44 8.73-9.54 18.33-11.96 28.62l-64.12-4.01c4.07-24.81 13.66-47.62 27.78-67.22zm-27.78 118.9l64.12-4.01c2.41 10.29 6.52 19.89 11.95 28.62l-48.29 42.62c-14.12-19.6-23.71-42.42-27.78-67.23zm131.55 131.55c-24.81-4.07-47.63-13.66-67.23-27.78l42.61-48.3c8.73 5.44 18.33 9.54 28.62 11.96l-4 64.12zM256 288c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm25.84 125.39l-4.01-64.12c10.29-2.41 19.89-6.52 28.62-11.96l42.61 48.3c-19.6 14.12-42.41 23.71-67.22 27.78zm103.77-64.33l-48.29-42.62c5.44-8.73 9.54-18.32 11.95-28.62l64.12 4.01c-4.07 24.82-13.66 47.64-27.78 67.23zm-36.34-114.89c-2.41-10.29-6.52-19.89-11.96-28.62l48.3-42.61c14.12 19.6 23.71 42.42 27.78 67.23l-64.12 4z\"]\n};\nvar faDiagnoses = {\n prefix: 'fas',\n iconName: 'diagnoses',\n icon: [640, 512, [], \"f470\", \"M496 256c8.8 0 16-7.2 16-16s-7.2-16-16-16-16 7.2-16 16 7.2 16 16 16zm-176-80c48.5 0 88-39.5 88-88S368.5 0 320 0s-88 39.5-88 88 39.5 88 88 88zM59.8 364c10.2 15.3 29.3 17.8 42.9 9.8 16.2-9.6 56.2-31.7 105.3-48.6V416h224v-90.7c49.1 16.8 89.1 39 105.3 48.6 13.6 8 32.7 5.3 42.9-9.8l17.8-26.7c8.8-13.2 7.6-34.6-10-45.1-11.9-7.1-29.7-17-51.1-27.4-28.1 46.1-99.4 17.8-87.7-35.1C409.3 217.2 365.1 208 320 208c-57 0-112.9 14.5-160 32.2-.2 40.2-47.6 63.3-79.2 36-11.2 6-21.3 11.6-28.7 16-17.6 10.5-18.8 31.8-10 45.1L59.8 364zM368 344c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm-96-96c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm-160 8c8.8 0 16-7.2 16-16s-7.2-16-16-16-16 7.2-16 16 7.2 16 16 16zm512 192H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z\"]\n};\nvar faDice = {\n prefix: 'fas',\n iconName: 'dice',\n icon: [640, 512, [], \"f522\", \"M592 192H473.26c12.69 29.59 7.12 65.2-17 89.32L320 417.58V464c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48V240c0-26.51-21.49-48-48-48zM480 376c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24zm-46.37-186.7L258.7 14.37c-19.16-19.16-50.23-19.16-69.39 0L14.37 189.3c-19.16 19.16-19.16 50.23 0 69.39L189.3 433.63c19.16 19.16 50.23 19.16 69.39 0L433.63 258.7c19.16-19.17 19.16-50.24 0-69.4zM96 248c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24zm128 128c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24zm0-128c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24zm0-128c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24zm128 128c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24z\"]\n};\nvar faDiceD20 = {\n prefix: 'fas',\n iconName: 'dice-d20',\n icon: [480, 512, [], \"f6cf\", \"M106.75 215.06L1.2 370.95c-3.08 5 .1 11.5 5.93 12.14l208.26 22.07-108.64-190.1zM7.41 315.43L82.7 193.08 6.06 147.1c-2.67-1.6-6.06.32-6.06 3.43v162.81c0 4.03 5.29 5.53 7.41 2.09zM18.25 423.6l194.4 87.66c5.3 2.45 11.35-1.43 11.35-7.26v-65.67l-203.55-22.3c-4.45-.5-6.23 5.59-2.2 7.57zm81.22-257.78L179.4 22.88c4.34-7.06-3.59-15.25-10.78-11.14L17.81 110.35c-2.47 1.62-2.39 5.26.13 6.78l81.53 48.69zM240 176h109.21L253.63 7.62C250.5 2.54 245.25 0 240 0s-10.5 2.54-13.63 7.62L130.79 176H240zm233.94-28.9l-76.64 45.99 75.29 122.35c2.11 3.44 7.41 1.94 7.41-2.1V150.53c0-3.11-3.39-5.03-6.06-3.43zm-93.41 18.72l81.53-48.7c2.53-1.52 2.6-5.16.13-6.78l-150.81-98.6c-7.19-4.11-15.12 4.08-10.78 11.14l79.93 142.94zm79.02 250.21L256 438.32v65.67c0 5.84 6.05 9.71 11.35 7.26l194.4-87.66c4.03-1.97 2.25-8.06-2.2-7.56zm-86.3-200.97l-108.63 190.1 208.26-22.07c5.83-.65 9.01-7.14 5.93-12.14L373.25 215.06zM240 208H139.57L240 383.75 340.43 208H240z\"]\n};\nvar faDiceD6 = {\n prefix: 'fas',\n iconName: 'dice-d6',\n icon: [448, 512, [], \"f6d1\", \"M422.19 109.95L256.21 9.07c-19.91-12.1-44.52-12.1-64.43 0L25.81 109.95c-5.32 3.23-5.29 11.27.06 14.46L224 242.55l198.14-118.14c5.35-3.19 5.38-11.22.05-14.46zm13.84 44.63L240 271.46v223.82c0 12.88 13.39 20.91 24.05 14.43l152.16-92.48c19.68-11.96 31.79-33.94 31.79-57.7v-197.7c0-6.41-6.64-10.43-11.97-7.25zM0 161.83v197.7c0 23.77 12.11 45.74 31.79 57.7l152.16 92.47c10.67 6.48 24.05-1.54 24.05-14.43V271.46L11.97 154.58C6.64 151.4 0 155.42 0 161.83z\"]\n};\nvar faDiceFive = {\n prefix: 'fas',\n iconName: 'dice-five',\n icon: [448, 512, [], \"f523\", \"M384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96c0-35.35-28.65-64-64-64zM128 384c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm96 96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm96 96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faDiceFour = {\n prefix: 'fas',\n iconName: 'dice-four',\n icon: [448, 512, [], \"f524\", \"M384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96c0-35.35-28.65-64-64-64zM128 384c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm192 192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faDiceOne = {\n prefix: 'fas',\n iconName: 'dice-one',\n icon: [448, 512, [], \"f525\", \"M384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96c0-35.35-28.65-64-64-64zM224 288c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faDiceSix = {\n prefix: 'fas',\n iconName: 'dice-six',\n icon: [448, 512, [], \"f526\", \"M384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96c0-35.35-28.65-64-64-64zM128 384c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm192 192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faDiceThree = {\n prefix: 'fas',\n iconName: 'dice-three',\n icon: [448, 512, [], \"f527\", \"M384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96c0-35.35-28.65-64-64-64zM128 192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm96 96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm96 96c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faDiceTwo = {\n prefix: 'fas',\n iconName: 'dice-two',\n icon: [448, 512, [], \"f528\", \"M384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96c0-35.35-28.65-64-64-64zM128 192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm192 192c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faDigitalTachograph = {\n prefix: 'fas',\n iconName: 'digital-tachograph',\n icon: [640, 512, [], \"f566\", \"M608 96H32c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V128c0-17.67-14.33-32-32-32zM304 352c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-8c0-4.42 3.58-8 8-8h224c4.42 0 8 3.58 8 8v8zM72 288v-16c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H80c-4.42 0-8-3.58-8-8zm64 0v-16c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8zm64 0v-16c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8zm64 0v-16c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8zm40-64c0 8.84-7.16 16-16 16H80c-8.84 0-16-7.16-16-16v-48c0-8.84 7.16-16 16-16h208c8.84 0 16 7.16 16 16v48zm272 128c0 4.42-3.58 8-8 8H344c-4.42 0-8-3.58-8-8v-8c0-4.42 3.58-8 8-8h224c4.42 0 8 3.58 8 8v8z\"]\n};\nvar faDirections = {\n prefix: 'fas',\n iconName: 'directions',\n icon: [512, 512, [], \"f5eb\", \"M502.61 233.32L278.68 9.39c-12.52-12.52-32.83-12.52-45.36 0L9.39 233.32c-12.52 12.53-12.52 32.83 0 45.36l223.93 223.93c12.52 12.53 32.83 12.53 45.36 0l223.93-223.93c12.52-12.53 12.52-32.83 0-45.36zm-100.98 12.56l-84.21 77.73c-5.12 4.73-13.43 1.1-13.43-5.88V264h-96v64c0 4.42-3.58 8-8 8h-32c-4.42 0-8-3.58-8-8v-80c0-17.67 14.33-32 32-32h112v-53.73c0-6.97 8.3-10.61 13.43-5.88l84.21 77.73c3.43 3.17 3.43 8.59 0 11.76z\"]\n};\nvar faDivide = {\n prefix: 'fas',\n iconName: 'divide',\n icon: [448, 512, [], \"f529\", \"M224 352c-35.35 0-64 28.65-64 64s28.65 64 64 64 64-28.65 64-64-28.65-64-64-64zm0-192c35.35 0 64-28.65 64-64s-28.65-64-64-64-64 28.65-64 64 28.65 64 64 64zm192 48H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"]\n};\nvar faDizzy = {\n prefix: 'fas',\n iconName: 'dizzy',\n icon: [496, 512, [], \"f567\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm-96 206.6l-28.7 28.7c-14.8 14.8-37.8-7.5-22.6-22.6l28.7-28.7-28.7-28.7c-15-15 7.7-37.6 22.6-22.6l28.7 28.7 28.7-28.7c15-15 37.6 7.7 22.6 22.6L174.6 192l28.7 28.7c15.2 15.2-7.9 37.4-22.6 22.6L152 214.6zM248 416c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64zm147.3-195.3c15.2 15.2-7.9 37.4-22.6 22.6L344 214.6l-28.7 28.7c-14.8 14.8-37.8-7.5-22.6-22.6l28.7-28.7-28.7-28.7c-15-15 7.7-37.6 22.6-22.6l28.7 28.7 28.7-28.7c15-15 37.6 7.7 22.6 22.6L366.6 192l28.7 28.7z\"]\n};\nvar faDna = {\n prefix: 'fas',\n iconName: 'dna',\n icon: [448, 512, [], \"f471\", \"M.1 494.1c-1.1 9.5 6.3 17.8 15.9 17.8l32.3.1c8.1 0 14.9-5.9 16-13.9.7-4.9 1.8-11.1 3.4-18.1H380c1.6 6.9 2.9 13.2 3.5 18.1 1.1 8 7.9 14 16 13.9l32.3-.1c9.6 0 17.1-8.3 15.9-17.8-4.6-37.9-25.6-129-118.9-207.7-17.6 12.4-37.1 24.2-58.5 35.4 6.2 4.6 11.4 9.4 17 14.2H159.7c21.3-18.1 47-35.6 78.7-51.4C410.5 199.1 442.1 65.8 447.9 17.9 449 8.4 441.6.1 432 .1L399.6 0c-8.1 0-14.9 5.9-16 13.9-.7 4.9-1.8 11.1-3.4 18.1H67.8c-1.6-7-2.7-13.1-3.4-18.1-1.1-8-7.9-14-16-13.9L16.1.1C6.5.1-1 8.4.1 17.9 5.3 60.8 31.4 171.8 160 256 31.5 340.2 5.3 451.2.1 494.1zM224 219.6c-25.1-13.7-46.4-28.4-64.3-43.6h128.5c-17.8 15.2-39.1 30-64.2 43.6zM355.1 96c-5.8 10.4-12.8 21.1-21 32H114c-8.3-10.9-15.3-21.6-21-32h262.1zM92.9 416c5.8-10.4 12.8-21.1 21-32h219.4c8.3 10.9 15.4 21.6 21.2 32H92.9z\"]\n};\nvar faDog = {\n prefix: 'fas',\n iconName: 'dog',\n icon: [512, 512, [], \"f6d3\", \"M496 96h-64l-7.16-14.31A32 32 0 0 0 396.22 64H342.6l-27.28-27.28C305.23 26.64 288 33.78 288 48.03v149.84l128 45.71V208h32c35.35 0 64-28.65 64-64v-32c0-8.84-7.16-16-16-16zm-112 48c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16zM96 224c-17.64 0-32-14.36-32-32 0-17.67-14.33-32-32-32S0 174.33 0 192c0 41.66 26.83 76.85 64 90.1V496c0 8.84 7.16 16 16 16h64c8.84 0 16-7.16 16-16V384h160v112c0 8.84 7.16 16 16 16h64c8.84 0 16-7.16 16-16V277.55L266.05 224H96z\"]\n};\nvar faDollarSign = {\n prefix: 'fas',\n iconName: 'dollar-sign',\n icon: [288, 512, [], \"f155\", \"M209.2 233.4l-108-31.6C88.7 198.2 80 186.5 80 173.5c0-16.3 13.2-29.5 29.5-29.5h66.3c12.2 0 24.2 3.7 34.2 10.5 6.1 4.1 14.3 3.1 19.5-2l34.8-34c7.1-6.9 6.1-18.4-1.8-24.5C238 74.8 207.4 64.1 176 64V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48h-2.5C45.8 64-5.4 118.7.5 183.6c4.2 46.1 39.4 83.6 83.8 96.6l102.5 30c12.5 3.7 21.2 15.3 21.2 28.3 0 16.3-13.2 29.5-29.5 29.5h-66.3C100 368 88 364.3 78 357.5c-6.1-4.1-14.3-3.1-19.5 2l-34.8 34c-7.1 6.9-6.1 18.4 1.8 24.5 24.5 19.2 55.1 29.9 86.5 30v48c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-48.2c46.6-.9 90.3-28.6 105.7-72.7 21.5-61.6-14.6-124.8-72.5-141.7z\"]\n};\nvar faDolly = {\n prefix: 'fas',\n iconName: 'dolly',\n icon: [576, 512, [], \"f472\", \"M294.2 277.7c18 5 34.7 13.4 49.5 24.7l161.5-53.8c8.4-2.8 12.9-11.9 10.1-20.2L454.9 47.2c-2.8-8.4-11.9-12.9-20.2-10.1l-61.1 20.4 33.1 99.4L346 177l-33.1-99.4-61.6 20.5c-8.4 2.8-12.9 11.9-10.1 20.2l53 159.4zm281 48.7L565 296c-2.8-8.4-11.9-12.9-20.2-10.1l-213.5 71.2c-17.2-22-43.6-36.4-73.5-37L158.4 21.9C154 8.8 141.8 0 128 0H16C7.2 0 0 7.2 0 16v32c0 8.8 7.2 16 16 16h88.9l92.2 276.7c-26.1 20.4-41.7 53.6-36 90.5 6.1 39.4 37.9 72.3 77.3 79.2 60.2 10.7 112.3-34.8 113.4-92.6l213.3-71.2c8.3-2.8 12.9-11.8 10.1-20.2zM256 464c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z\"]\n};\nvar faDollyFlatbed = {\n prefix: 'fas',\n iconName: 'dolly-flatbed',\n icon: [640, 512, [], \"f474\", \"M208 320h384c8.8 0 16-7.2 16-16V48c0-8.8-7.2-16-16-16H448v128l-48-32-48 32V32H208c-8.8 0-16 7.2-16 16v256c0 8.8 7.2 16 16 16zm416 64H128V16c0-8.8-7.2-16-16-16H16C7.2 0 0 7.2 0 16v32c0 8.8 7.2 16 16 16h48v368c0 8.8 7.2 16 16 16h82.9c-1.8 5-2.9 10.4-2.9 16 0 26.5 21.5 48 48 48s48-21.5 48-48c0-5.6-1.2-11-2.9-16H451c-1.8 5-2.9 10.4-2.9 16 0 26.5 21.5 48 48 48s48-21.5 48-48c0-5.6-1.2-11-2.9-16H624c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z\"]\n};\nvar faDonate = {\n prefix: 'fas',\n iconName: 'donate',\n icon: [512, 512, [], \"f4b9\", \"M256 416c114.9 0 208-93.1 208-208S370.9 0 256 0 48 93.1 48 208s93.1 208 208 208zM233.8 97.4V80.6c0-9.2 7.4-16.6 16.6-16.6h11.1c9.2 0 16.6 7.4 16.6 16.6v17c15.5.8 30.5 6.1 43 15.4 5.6 4.1 6.2 12.3 1.2 17.1L306 145.6c-3.8 3.7-9.5 3.8-14 1-5.4-3.4-11.4-5.1-17.8-5.1h-38.9c-9 0-16.3 8.2-16.3 18.3 0 8.2 5 15.5 12.1 17.6l62.3 18.7c25.7 7.7 43.7 32.4 43.7 60.1 0 34-26.4 61.5-59.1 62.4v16.8c0 9.2-7.4 16.6-16.6 16.6h-11.1c-9.2 0-16.6-7.4-16.6-16.6v-17c-15.5-.8-30.5-6.1-43-15.4-5.6-4.1-6.2-12.3-1.2-17.1l16.3-15.5c3.8-3.7 9.5-3.8 14-1 5.4 3.4 11.4 5.1 17.8 5.1h38.9c9 0 16.3-8.2 16.3-18.3 0-8.2-5-15.5-12.1-17.6l-62.3-18.7c-25.7-7.7-43.7-32.4-43.7-60.1.1-34 26.4-61.5 59.1-62.4zM480 352h-32.5c-19.6 26-44.6 47.7-73 64h63.8c5.3 0 9.6 3.6 9.6 8v16c0 4.4-4.3 8-9.6 8H73.6c-5.3 0-9.6-3.6-9.6-8v-16c0-4.4 4.3-8 9.6-8h63.8c-28.4-16.3-53.3-38-73-64H32c-17.7 0-32 14.3-32 32v96c0 17.7 14.3 32 32 32h448c17.7 0 32-14.3 32-32v-96c0-17.7-14.3-32-32-32z\"]\n};\nvar faDoorClosed = {\n prefix: 'fas',\n iconName: 'door-closed',\n icon: [640, 512, [], \"f52a\", \"M624 448H512V50.8C512 22.78 490.47 0 464 0H175.99c-26.47 0-48 22.78-48 50.8V448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h608c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM415.99 288c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32c.01 17.67-14.32 32-32 32z\"]\n};\nvar faDoorOpen = {\n prefix: 'fas',\n iconName: 'door-open',\n icon: [640, 512, [], \"f52b\", \"M624 448h-80V113.45C544 86.19 522.47 64 496 64H384v64h96v384h144c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM312.24 1.01l-192 49.74C105.99 54.44 96 67.7 96 82.92V448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h336V33.18c0-21.58-19.56-37.41-39.76-32.17zM264 288c-13.25 0-24-14.33-24-32s10.75-32 24-32 24 14.33 24 32-10.75 32-24 32z\"]\n};\nvar faDotCircle = {\n prefix: 'fas',\n iconName: 'dot-circle',\n icon: [512, 512, [], \"f192\", \"M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm80 248c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80z\"]\n};\nvar faDove = {\n prefix: 'fas',\n iconName: 'dove',\n icon: [512, 512, [], \"f4ba\", \"M288 167.2v-28.1c-28.2-36.3-47.1-79.3-54.1-125.2-2.1-13.5-19-18.8-27.8-8.3-21.1 24.9-37.7 54.1-48.9 86.5 34.2 38.3 80 64.6 130.8 75.1zM400 64c-44.2 0-80 35.9-80 80.1v59.4C215.6 197.3 127 133 87 41.8c-5.5-12.5-23.2-13.2-29-.9C41.4 76 32 115.2 32 156.6c0 70.8 34.1 136.9 85.1 185.9 13.2 12.7 26.1 23.2 38.9 32.8l-143.9 36C1.4 414-3.4 426.4 2.6 435.7 20 462.6 63 508.2 155.8 512c8 .3 16-2.6 22.1-7.9l65.2-56.1H320c88.4 0 160-71.5 160-159.9V128l32-64H400zm0 96.1c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16z\"]\n};\nvar faDownload = {\n prefix: 'fas',\n iconName: 'download',\n icon: [512, 512, [], \"f019\", \"M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z\"]\n};\nvar faDraftingCompass = {\n prefix: 'fas',\n iconName: 'drafting-compass',\n icon: [512, 512, [], \"f568\", \"M457.01 344.42c-25.05 20.33-52.63 37.18-82.54 49.05l54.38 94.19 53.95 23.04c9.81 4.19 20.89-2.21 22.17-12.8l7.02-58.25-54.98-95.23zm42.49-94.56c4.86-7.67 1.89-17.99-6.05-22.39l-28.07-15.57c-7.48-4.15-16.61-1.46-21.26 5.72C403.01 281.15 332.25 320 256 320c-23.93 0-47.23-4.25-69.41-11.53l67.36-116.68c.7.02 1.34.21 2.04.21s1.35-.19 2.04-.21l51.09 88.5c31.23-8.96 59.56-25.75 82.61-48.92l-51.79-89.71C347.39 128.03 352 112.63 352 96c0-53.02-42.98-96-96-96s-96 42.98-96 96c0 16.63 4.61 32.03 12.05 45.66l-68.3 118.31c-12.55-11.61-23.96-24.59-33.68-39-4.79-7.1-13.97-9.62-21.38-5.33l-27.75 16.07c-7.85 4.54-10.63 14.9-5.64 22.47 15.57 23.64 34.69 44.21 55.98 62.02L0 439.66l7.02 58.25c1.28 10.59 12.36 16.99 22.17 12.8l53.95-23.04 70.8-122.63C186.13 377.28 220.62 384 256 384c99.05 0 190.88-51.01 243.5-134.14zM256 64c17.67 0 32 14.33 32 32s-14.33 32-32 32-32-14.33-32-32 14.33-32 32-32z\"]\n};\nvar faDragon = {\n prefix: 'fas',\n iconName: 'dragon',\n icon: [640, 512, [], \"f6d5\", \"M18.32 255.78L192 223.96l-91.28 68.69c-10.08 10.08-2.94 27.31 11.31 27.31h222.7c-9.44-26.4-14.73-54.47-14.73-83.38v-42.27l-119.73-87.6c-23.82-15.88-55.29-14.01-77.06 4.59L5.81 227.64c-12.38 10.33-3.45 30.42 12.51 28.14zm556.87 34.1l-100.66-50.31A47.992 47.992 0 0 1 448 196.65v-36.69h64l28.09 22.63c6 6 14.14 9.37 22.63 9.37h30.97a32 32 0 0 0 28.62-17.69l14.31-28.62a32.005 32.005 0 0 0-3.02-33.51l-74.53-99.38C553.02 4.7 543.54 0 533.47 0H296.02c-7.13 0-10.7 8.57-5.66 13.61L352 63.96 292.42 88.8c-5.9 2.95-5.9 11.36 0 14.31L352 127.96v108.62c0 72.08 36.03 139.39 96 179.38-195.59 6.81-344.56 41.01-434.1 60.91C5.78 478.67 0 485.88 0 494.2 0 504 7.95 512 17.76 512h499.08c63.29.01 119.61-47.56 122.99-110.76 2.52-47.28-22.73-90.4-64.64-111.36zM489.18 66.25l45.65 11.41c-2.75 10.91-12.47 18.89-24.13 18.26-12.96-.71-25.85-12.53-21.52-29.67z\"]\n};\nvar faDrawPolygon = {\n prefix: 'fas',\n iconName: 'draw-polygon',\n icon: [448, 512, [], \"f5ee\", \"M384 352c-.35 0-.67.1-1.02.1l-39.2-65.32c5.07-9.17 8.22-19.56 8.22-30.78s-3.14-21.61-8.22-30.78l39.2-65.32c.35.01.67.1 1.02.1 35.35 0 64-28.65 64-64s-28.65-64-64-64c-23.63 0-44.04 12.95-55.12 32H119.12C108.04 44.95 87.63 32 64 32 28.65 32 0 60.65 0 96c0 23.63 12.95 44.04 32 55.12v209.75C12.95 371.96 0 392.37 0 416c0 35.35 28.65 64 64 64 23.63 0 44.04-12.95 55.12-32h209.75c11.09 19.05 31.49 32 55.12 32 35.35 0 64-28.65 64-64 .01-35.35-28.64-64-63.99-64zm-288 8.88V151.12A63.825 63.825 0 0 0 119.12 128h208.36l-38.46 64.1c-.35-.01-.67-.1-1.02-.1-35.35 0-64 28.65-64 64s28.65 64 64 64c.35 0 .67-.1 1.02-.1l38.46 64.1H119.12A63.748 63.748 0 0 0 96 360.88zM272 256c0-8.82 7.18-16 16-16s16 7.18 16 16-7.18 16-16 16-16-7.18-16-16zM400 96c0 8.82-7.18 16-16 16s-16-7.18-16-16 7.18-16 16-16 16 7.18 16 16zM64 80c8.82 0 16 7.18 16 16s-7.18 16-16 16-16-7.18-16-16 7.18-16 16-16zM48 416c0-8.82 7.18-16 16-16s16 7.18 16 16-7.18 16-16 16-16-7.18-16-16zm336 16c-8.82 0-16-7.18-16-16s7.18-16 16-16 16 7.18 16 16-7.18 16-16 16z\"]\n};\nvar faDrum = {\n prefix: 'fas',\n iconName: 'drum',\n icon: [576, 512, [], \"f569\", \"M458.08 120.88l102.39-61.43c15.16-9.09 20.06-28.75 10.97-43.91C562.34.39 542.7-4.53 527.53 4.57l-160.69 96.41A629.32 629.32 0 0 0 288 96C128.94 96 0 153.31 0 224v160.83c0 30.46 24.03 58.4 64 80.37v-96.37c0-17.6 14.4-32 32-32s32 14.4 32 32v122.41c37.4 11.13 81 18.44 128 20.75V400.84c0-17.6 14.4-32 32-32s32 14.4 32 32V512c47-2.31 90.6-9.62 128-20.75V368.84c0-17.6 14.4-32 32-32s32 14.4 32 32v96.37c39.97-21.97 64-49.91 64-80.37V224.01c-.01-42.38-46.54-79.84-117.92-103.13zM288 304c-132.55 0-240-35.82-240-80s107.45-80 240-80c2.34 0 4.62.1 6.94.12l-87.41 52.44c-15.16 9.09-20.06 28.75-10.97 43.91 9.56 15.93 29.51 19.61 43.91 10.97l162.71-97.62C477.55 167.41 528 193.74 528 224.01 528 268.19 420.54 304 288 304z\"]\n};\nvar faDrumSteelpan = {\n prefix: 'fas',\n iconName: 'drum-steelpan',\n icon: [576, 512, [], \"f56a\", \"M288 32C128.94 32 0 89.31 0 160v192c0 70.69 128.94 128 288 128s288-57.31 288-128V160c0-70.69-128.94-128-288-128zm-82.99 158.36c-4.45 16.61-14.54 30.57-28.31 40.48C100.23 217.46 48 190.78 48 160c0-30.16 50.11-56.39 124.04-70.03l25.6 44.34c9.86 17.09 12.48 36.99 7.37 56.05zM288 240c-21.08 0-41.41-1-60.89-2.7 8.06-26.13 32.15-45.3 60.89-45.3s52.83 19.17 60.89 45.3C329.41 239 309.08 240 288 240zm64-144c0 35.29-28.71 64-64 64s-64-28.71-64-64V82.96c20.4-1.88 41.8-2.96 64-2.96s43.6 1.08 64 2.96V96zm46.93 134.9c-13.81-9.91-23.94-23.9-28.4-40.54-5.11-19.06-2.49-38.96 7.38-56.04l25.65-44.42C477.72 103.5 528 129.79 528 160c0 30.83-52.4 57.54-129.07 70.9z\"]\n};\nvar faDrumstickBite = {\n prefix: 'fas',\n iconName: 'drumstick-bite',\n icon: [512, 512, [], \"f6d7\", \"M462.8 49.57a169.44 169.44 0 0 0-239.5 0C187.82 85 160.13 128 160.13 192v85.83l-40.62 40.59c-9.7 9.69-24 11.07-36.78 6a60.33 60.33 0 0 0-65 98.72C33 438.39 54.24 442.7 73.85 438.21c-4.5 19.6-.18 40.83 15.1 56.1a60.35 60.35 0 0 0 98.8-65c-5.09-12.73-3.72-27 6-36.75L234.36 352h85.89a187.87 187.87 0 0 0 61.89-10c-39.64-43.89-39.83-110.23 1.05-151.07 34.38-34.36 86.76-39.46 128.74-16.8 1.3-44.96-14.81-90.28-49.13-124.56z\"]\n};\nvar faDumbbell = {\n prefix: 'fas',\n iconName: 'dumbbell',\n icon: [640, 512, [], \"f44b\", \"M104 96H56c-13.3 0-24 10.7-24 24v104H8c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h24v104c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24V120c0-13.3-10.7-24-24-24zm528 128h-24V120c0-13.3-10.7-24-24-24h-48c-13.3 0-24 10.7-24 24v272c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24V288h24c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM456 32h-48c-13.3 0-24 10.7-24 24v168H256V56c0-13.3-10.7-24-24-24h-48c-13.3 0-24 10.7-24 24v400c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24V288h128v168c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24z\"]\n};\nvar faDumpster = {\n prefix: 'fas',\n iconName: 'dumpster',\n icon: [576, 512, [], \"f793\", \"M560 160c10.4 0 18-9.8 15.5-19.9l-24-96C549.7 37 543.3 32 536 32h-98.9l25.6 128H560zM272 32H171.5l-25.6 128H272V32zm132.5 0H304v128h126.1L404.5 32zM16 160h97.3l25.6-128H40c-7.3 0-13.7 5-15.5 12.1l-24 96C-2 150.2 5.6 160 16 160zm544 64h-20l4-32H32l4 32H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h28l20 160v16c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-16h320v16c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-16l20-160h28c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z\"]\n};\nvar faDumpsterFire = {\n prefix: 'fas',\n iconName: 'dumpster-fire',\n icon: [640, 512, [], \"f794\", \"M418.7 104.1l.2-.2-14.4-72H304v128h60.8c16.2-19.3 34.2-38.2 53.9-55.8zM272 32H171.5l-25.6 128H272V32zm189.3 72.1c18.2 16.3 35.5 33.7 51.1 51.5 5.7-5.6 11.4-11.1 17.3-16.3l21.3-19 21.3 19c1.1.9 2.1 2.1 3.1 3.1-.1-.8.2-1.5 0-2.3l-24-96C549.7 37 543.3 32 536 32h-98.9l12.3 61.5 11.9 10.6zM16 160h97.3l25.6-128H40c-7.3 0-13.7 5-15.5 12.1l-24 96C-2 150.2 5.6 160 16 160zm324.6 32H32l4 32H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h28l20 160v16c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-16h208.8c-30.2-33.7-48.8-77.9-48.8-126.4 0-35.9 19.9-82.9 52.6-129.6zm210.5-28.8c-14.9 13.3-28.3 27.2-40.2 41.2-19.5-25.8-43.6-52-71-76.4-70.2 62.7-120 144.3-120 193.6 0 87.5 71.6 158.4 160 158.4s160-70.9 160-158.4c.1-36.6-37-112.2-88.8-158.4zm-18.6 229.4c-14.7 10.7-32.9 17-52.5 17-49 0-88.9-33.5-88.9-88 0-27.1 16.5-51 49.4-91.9 4.7 5.6 67.1 88.1 67.1 88.1l39.8-47c2.8 4.8 5.4 9.5 7.7 14 18.6 36.7 10.8 83.6-22.6 107.8z\"]\n};\nvar faDungeon = {\n prefix: 'fas',\n iconName: 'dungeon',\n icon: [512, 512, [], \"f6d9\", \"M128.73 195.32l-82.81-51.76c-8.04-5.02-18.99-2.17-22.93 6.45A254.19 254.19 0 0 0 .54 239.28C-.05 248.37 7.59 256 16.69 256h97.13c7.96 0 14.08-6.25 15.01-14.16 1.09-9.33 3.24-18.33 6.24-26.94 2.56-7.34.25-15.46-6.34-19.58zM319.03 8C298.86 2.82 277.77 0 256 0s-42.86 2.82-63.03 8c-9.17 2.35-13.91 12.6-10.39 21.39l37.47 104.03A16.003 16.003 0 0 0 235.1 144h41.8c6.75 0 12.77-4.23 15.05-10.58l37.47-104.03c3.52-8.79-1.22-19.03-10.39-21.39zM112 288H16c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h96c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16zm0 128H16c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h96c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16zm77.31-283.67l-36.32-90.8c-3.53-8.83-14.13-12.99-22.42-8.31a257.308 257.308 0 0 0-71.61 59.89c-6.06 7.32-3.85 18.48 4.22 23.52l82.93 51.83c6.51 4.07 14.66 2.62 20.11-2.79 5.18-5.15 10.79-9.85 16.79-14.05 6.28-4.41 9.15-12.17 6.3-19.29zM398.18 256h97.13c9.1 0 16.74-7.63 16.15-16.72a254.135 254.135 0 0 0-22.45-89.27c-3.94-8.62-14.89-11.47-22.93-6.45l-82.81 51.76c-6.59 4.12-8.9 12.24-6.34 19.58 3.01 8.61 5.15 17.62 6.24 26.94.93 7.91 7.05 14.16 15.01 14.16zm54.85-162.89a257.308 257.308 0 0 0-71.61-59.89c-8.28-4.68-18.88-.52-22.42 8.31l-36.32 90.8c-2.85 7.12.02 14.88 6.3 19.28 6 4.2 11.61 8.9 16.79 14.05 5.44 5.41 13.6 6.86 20.11 2.79l82.93-51.83c8.07-5.03 10.29-16.19 4.22-23.51zM496 288h-96c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h96c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16zm0 128h-96c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h96c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16zM240 177.62V472c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8V177.62c-5.23-.89-10.52-1.62-16-1.62s-10.77.73-16 1.62zm-64 41.51V472c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8V189.36c-12.78 7.45-23.84 17.47-32 29.77zm128-29.77V472c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8V219.13c-8.16-12.3-19.22-22.32-32-29.77z\"]\n};\nvar faEdit = {\n prefix: 'fas',\n iconName: 'edit',\n icon: [576, 512, [], \"f044\", \"M402.6 83.2l90.2 90.2c3.8 3.8 3.8 10 0 13.8L274.4 405.6l-92.8 10.3c-12.4 1.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8 83.2c3.8-3.8 10-3.8 13.8 0zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2 0l-35.4 35.4c-3.8 3.8-3.8 10 0 13.8l90.2 90.2c3.8 3.8 10 3.8 13.8 0l35.4-35.4c15.2-15.3 15.2-40 0-55.2zM384 346.2V448H64V128h229.8c3.2 0 6.2-1.3 8.5-3.5l40-40c7.6-7.6 2.2-20.5-8.5-20.5H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V306.2c0-10.7-12.9-16-20.5-8.5l-40 40c-2.2 2.3-3.5 5.3-3.5 8.5z\"]\n};\nvar faEgg = {\n prefix: 'fas',\n iconName: 'egg',\n icon: [384, 512, [], \"f7fb\", \"M192 0C86 0 0 214 0 320s86 192 192 192 192-86 192-192S298 0 192 0z\"]\n};\nvar faEject = {\n prefix: 'fas',\n iconName: 'eject',\n icon: [448, 512, [], \"f052\", \"M448 384v64c0 17.673-14.327 32-32 32H32c-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32h384c17.673 0 32 14.327 32 32zM48.053 320h351.886c41.651 0 63.581-49.674 35.383-80.435L259.383 47.558c-19.014-20.743-51.751-20.744-70.767 0L12.67 239.565C-15.475 270.268 6.324 320 48.053 320z\"]\n};\nvar faEllipsisH = {\n prefix: 'fas',\n iconName: 'ellipsis-h',\n icon: [512, 512, [], \"f141\", \"M328 256c0 39.8-32.2 72-72 72s-72-32.2-72-72 32.2-72 72-72 72 32.2 72 72zm104-72c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm-352 0c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72z\"]\n};\nvar faEllipsisV = {\n prefix: 'fas',\n iconName: 'ellipsis-v',\n icon: [192, 512, [], \"f142\", \"M96 184c39.8 0 72 32.2 72 72s-32.2 72-72 72-72-32.2-72-72 32.2-72 72-72zM24 80c0 39.8 32.2 72 72 72s72-32.2 72-72S135.8 8 96 8 24 40.2 24 80zm0 352c0 39.8 32.2 72 72 72s72-32.2 72-72-32.2-72-72-72-72 32.2-72 72z\"]\n};\nvar faEnvelope = {\n prefix: 'fas',\n iconName: 'envelope',\n icon: [512, 512, [], \"f0e0\", \"M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z\"]\n};\nvar faEnvelopeOpen = {\n prefix: 'fas',\n iconName: 'envelope-open',\n icon: [512, 512, [], \"f2b6\", \"M512 464c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V200.724a48 48 0 0 1 18.387-37.776c24.913-19.529 45.501-35.365 164.2-121.511C199.412 29.17 232.797-.347 256 .003c23.198-.354 56.596 29.172 73.413 41.433 118.687 86.137 139.303 101.995 164.2 121.512A48 48 0 0 1 512 200.724V464zm-65.666-196.605c-2.563-3.728-7.7-4.595-11.339-1.907-22.845 16.873-55.462 40.705-105.582 77.079-16.825 12.266-50.21 41.781-73.413 41.43-23.211.344-56.559-29.143-73.413-41.43-50.114-36.37-82.734-60.204-105.582-77.079-3.639-2.688-8.776-1.821-11.339 1.907l-9.072 13.196a7.998 7.998 0 0 0 1.839 10.967c22.887 16.899 55.454 40.69 105.303 76.868 20.274 14.781 56.524 47.813 92.264 47.573 35.724.242 71.961-32.771 92.263-47.573 49.85-36.179 82.418-59.97 105.303-76.868a7.998 7.998 0 0 0 1.839-10.967l-9.071-13.196z\"]\n};\nvar faEnvelopeOpenText = {\n prefix: 'fas',\n iconName: 'envelope-open-text',\n icon: [512, 512, [], \"f658\", \"M176 216h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16H176c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16zm-16 80c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16H176c-8.84 0-16 7.16-16 16v16zm96 121.13c-16.42 0-32.84-5.06-46.86-15.19L0 250.86V464c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V250.86L302.86 401.94c-14.02 10.12-30.44 15.19-46.86 15.19zm237.61-254.18c-8.85-6.94-17.24-13.47-29.61-22.81V96c0-26.51-21.49-48-48-48h-77.55c-3.04-2.2-5.87-4.26-9.04-6.56C312.6 29.17 279.2-.35 256 0c-23.2-.35-56.59 29.17-73.41 41.44-3.17 2.3-6 4.36-9.04 6.56H96c-26.51 0-48 21.49-48 48v44.14c-12.37 9.33-20.76 15.87-29.61 22.81A47.995 47.995 0 0 0 0 200.72v10.65l96 69.35V96h320v184.72l96-69.35v-10.65c0-14.74-6.78-28.67-18.39-37.77z\"]\n};\nvar faEnvelopeSquare = {\n prefix: 'fas',\n iconName: 'envelope-square',\n icon: [448, 512, [], \"f199\", \"M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM178.117 262.104C87.429 196.287 88.353 196.121 64 177.167V152c0-13.255 10.745-24 24-24h272c13.255 0 24 10.745 24 24v25.167c-24.371 18.969-23.434 19.124-114.117 84.938-10.5 7.655-31.392 26.12-45.883 25.894-14.503.218-35.367-18.227-45.883-25.895zM384 217.775V360c0 13.255-10.745 24-24 24H88c-13.255 0-24-10.745-24-24V217.775c13.958 10.794 33.329 25.236 95.303 70.214 14.162 10.341 37.975 32.145 64.694 32.01 26.887.134 51.037-22.041 64.72-32.025 61.958-44.965 81.325-59.406 95.283-70.199z\"]\n};\nvar faEquals = {\n prefix: 'fas',\n iconName: 'equals',\n icon: [448, 512, [], \"f52c\", \"M416 304H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32zm0-192H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"]\n};\nvar faEraser = {\n prefix: 'fas',\n iconName: 'eraser',\n icon: [512, 512, [], \"f12d\", \"M497.941 273.941c18.745-18.745 18.745-49.137 0-67.882l-160-160c-18.745-18.745-49.136-18.746-67.883 0l-256 256c-18.745 18.745-18.745 49.137 0 67.882l96 96A48.004 48.004 0 0 0 144 480h356c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12H355.883l142.058-142.059zm-302.627-62.627l137.373 137.373L265.373 416H150.628l-80-80 124.686-124.686z\"]\n};\nvar faEthernet = {\n prefix: 'fas',\n iconName: 'ethernet',\n icon: [512, 512, [], \"f796\", \"M496 192h-48v-48c0-8.8-7.2-16-16-16h-48V80c0-8.8-7.2-16-16-16H144c-8.8 0-16 7.2-16 16v48H80c-8.8 0-16 7.2-16 16v48H16c-8.8 0-16 7.2-16 16v224c0 8.8 7.2 16 16 16h80V320h32v128h64V320h32v128h64V320h32v128h64V320h32v128h80c8.8 0 16-7.2 16-16V208c0-8.8-7.2-16-16-16z\"]\n};\nvar faEuroSign = {\n prefix: 'fas',\n iconName: 'euro-sign',\n icon: [320, 512, [], \"f153\", \"M310.706 413.765c-1.314-6.63-7.835-10.872-14.424-9.369-10.692 2.439-27.422 5.413-45.426 5.413-56.763 0-101.929-34.79-121.461-85.449h113.689a12 12 0 0 0 11.708-9.369l6.373-28.36c1.686-7.502-4.019-14.631-11.708-14.631H115.22c-1.21-14.328-1.414-28.287.137-42.245H261.95a12 12 0 0 0 11.723-9.434l6.512-29.755c1.638-7.484-4.061-14.566-11.723-14.566H130.184c20.633-44.991 62.69-75.03 117.619-75.03 14.486 0 28.564 2.25 37.851 4.145 6.216 1.268 12.347-2.498 14.002-8.623l11.991-44.368c1.822-6.741-2.465-13.616-9.326-14.917C290.217 34.912 270.71 32 249.635 32 152.451 32 74.03 92.252 45.075 176H12c-6.627 0-12 5.373-12 12v29.755c0 6.627 5.373 12 12 12h21.569c-1.009 13.607-1.181 29.287-.181 42.245H12c-6.627 0-12 5.373-12 12v28.36c0 6.627 5.373 12 12 12h30.114C67.139 414.692 145.264 480 249.635 480c26.301 0 48.562-4.544 61.101-7.788 6.167-1.595 10.027-7.708 8.788-13.957l-8.818-44.49z\"]\n};\nvar faExchangeAlt = {\n prefix: 'fas',\n iconName: 'exchange-alt',\n icon: [512, 512, [], \"f362\", \"M0 168v-16c0-13.255 10.745-24 24-24h360V80c0-21.367 25.899-32.042 40.971-16.971l80 80c9.372 9.373 9.372 24.569 0 33.941l-80 80C409.956 271.982 384 261.456 384 240v-48H24c-13.255 0-24-10.745-24-24zm488 152H128v-48c0-21.314-25.862-32.08-40.971-16.971l-80 80c-9.372 9.373-9.372 24.569 0 33.941l80 80C102.057 463.997 128 453.437 128 432v-48h360c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24z\"]\n};\nvar faExclamation = {\n prefix: 'fas',\n iconName: 'exclamation',\n icon: [192, 512, [], \"f12a\", \"M176 432c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80zM25.26 25.199l13.6 272C39.499 309.972 50.041 320 62.83 320h66.34c12.789 0 23.331-10.028 23.97-22.801l13.6-272C167.425 11.49 156.496 0 142.77 0H49.23C35.504 0 24.575 11.49 25.26 25.199z\"]\n};\nvar faExclamationCircle = {\n prefix: 'fas',\n iconName: 'exclamation-circle',\n icon: [512, 512, [], \"f06a\", \"M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z\"]\n};\nvar faExclamationTriangle = {\n prefix: 'fas',\n iconName: 'exclamation-triangle',\n icon: [576, 512, [], \"f071\", \"M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z\"]\n};\nvar faExpand = {\n prefix: 'fas',\n iconName: 'expand',\n icon: [448, 512, [], \"f065\", \"M0 180V56c0-13.3 10.7-24 24-24h124c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H64v84c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12zM288 44v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V56c0-13.3-10.7-24-24-24H300c-6.6 0-12 5.4-12 12zm148 276h-40c-6.6 0-12 5.4-12 12v84h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24V332c0-6.6-5.4-12-12-12zM160 468v-40c0-6.6-5.4-12-12-12H64v-84c0-6.6-5.4-12-12-12H12c-6.6 0-12 5.4-12 12v124c0 13.3 10.7 24 24 24h124c6.6 0 12-5.4 12-12z\"]\n};\nvar faExpandArrowsAlt = {\n prefix: 'fas',\n iconName: 'expand-arrows-alt',\n icon: [448, 512, [], \"f31e\", \"M448.1 344v112c0 13.3-10.7 24-24 24h-112c-21.4 0-32.1-25.9-17-41l36.2-36.2L224 295.6 116.8 402.9 153 439c15.1 15.1 4.4 41-17 41H24c-13.3 0-24-10.7-24-24V344c0-21.4 25.9-32.1 41-17l36.2 36.2L184.5 256 77.2 148.7 41 185c-15.1 15.1-41 4.4-41-17V56c0-13.3 10.7-24 24-24h112c21.4 0 32.1 25.9 17 41l-36.2 36.2L224 216.4l107.3-107.3L295.1 73c-15.1-15.1-4.4-41 17-41h112c13.3 0 24 10.7 24 24v112c0 21.4-25.9 32.1-41 17l-36.2-36.2L263.6 256l107.3 107.3 36.2-36.2c15.1-15.2 41-4.5 41 16.9z\"]\n};\nvar faExternalLinkAlt = {\n prefix: 'fas',\n iconName: 'external-link-alt',\n icon: [576, 512, [], \"f35d\", \"M576 24v127.984c0 21.461-25.96 31.98-40.971 16.971l-35.707-35.709-243.523 243.523c-9.373 9.373-24.568 9.373-33.941 0l-22.627-22.627c-9.373-9.373-9.373-24.569 0-33.941L442.756 76.676l-35.703-35.705C391.982 25.9 402.656 0 424.024 0H552c13.255 0 24 10.745 24 24zM407.029 270.794l-16 16A23.999 23.999 0 0 0 384 303.765V448H64V128h264a24.003 24.003 0 0 0 16.97-7.029l16-16C376.089 89.851 365.381 64 344 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V287.764c0-21.382-25.852-32.09-40.971-16.97z\"]\n};\nvar faExternalLinkSquareAlt = {\n prefix: 'fas',\n iconName: 'external-link-square-alt',\n icon: [448, 512, [], \"f360\", \"M448 80v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48zm-88 16H248.029c-21.313 0-32.08 25.861-16.971 40.971l31.984 31.987L67.515 364.485c-4.686 4.686-4.686 12.284 0 16.971l31.029 31.029c4.687 4.686 12.285 4.686 16.971 0l195.526-195.526 31.988 31.991C358.058 263.977 384 253.425 384 231.979V120c0-13.255-10.745-24-24-24z\"]\n};\nvar faEye = {\n prefix: 'fas',\n iconName: 'eye',\n icon: [576, 512, [], \"f06e\", \"M572.52 241.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400a144 144 0 1 1 144-144 143.93 143.93 0 0 1-144 144zm0-240a95.31 95.31 0 0 0-25.31 3.79 47.85 47.85 0 0 1-66.9 66.9A95.78 95.78 0 1 0 288 160z\"]\n};\nvar faEyeDropper = {\n prefix: 'fas',\n iconName: 'eye-dropper',\n icon: [512, 512, [], \"f1fb\", \"M50.75 333.25c-12 12-18.75 28.28-18.75 45.26V424L0 480l32 32 56-32h45.49c16.97 0 33.25-6.74 45.25-18.74l126.64-126.62-128-128L50.75 333.25zM483.88 28.12c-37.47-37.5-98.28-37.5-135.75 0l-77.09 77.09-13.1-13.1c-9.44-9.44-24.65-9.31-33.94 0l-40.97 40.97c-9.37 9.37-9.37 24.57 0 33.94l161.94 161.94c9.44 9.44 24.65 9.31 33.94 0L419.88 288c9.37-9.37 9.37-24.57 0-33.94l-13.1-13.1 77.09-77.09c37.51-37.48 37.51-98.26.01-135.75z\"]\n};\nvar faEyeSlash = {\n prefix: 'fas',\n iconName: 'eye-slash',\n icon: [640, 512, [], \"f070\", \"M320 400c-75.85 0-137.25-58.71-142.9-133.11L72.2 185.82c-13.79 17.3-26.48 35.59-36.72 55.59a32.35 32.35 0 0 0 0 29.19C89.71 376.41 197.07 448 320 448c26.91 0 52.87-4 77.89-10.46L346 397.39a144.13 144.13 0 0 1-26 2.61zm313.82 58.1l-110.55-85.44a331.25 331.25 0 0 0 81.25-102.07 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64a308.15 308.15 0 0 0-147.32 37.7L45.46 3.37A16 16 0 0 0 23 6.18L3.37 31.45A16 16 0 0 0 6.18 53.9l588.36 454.73a16 16 0 0 0 22.46-2.81l19.64-25.27a16 16 0 0 0-2.82-22.45zm-183.72-142l-39.3-30.38A94.75 94.75 0 0 0 416 256a94.76 94.76 0 0 0-121.31-92.21A47.65 47.65 0 0 1 304 192a46.64 46.64 0 0 1-1.54 10l-73.61-56.89A142.31 142.31 0 0 1 320 112a143.92 143.92 0 0 1 144 144c0 21.63-5.29 41.79-13.9 60.11z\"]\n};\nvar faFastBackward = {\n prefix: 'fas',\n iconName: 'fast-backward',\n icon: [512, 512, [], \"f049\", \"M0 436V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v151.9L235.5 71.4C256.1 54.3 288 68.6 288 96v131.9L459.5 71.4C480.1 54.3 512 68.6 512 96v320c0 27.4-31.9 41.7-52.5 24.6L288 285.3V416c0 27.4-31.9 41.7-52.5 24.6L64 285.3V436c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12z\"]\n};\nvar faFastForward = {\n prefix: 'fas',\n iconName: 'fast-forward',\n icon: [512, 512, [], \"f050\", \"M512 76v360c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12V284.1L276.5 440.6c-20.6 17.2-52.5 2.8-52.5-24.6V284.1L52.5 440.6C31.9 457.8 0 443.4 0 416V96c0-27.4 31.9-41.7 52.5-24.6L224 226.8V96c0-27.4 31.9-41.7 52.5-24.6L448 226.8V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12z\"]\n};\nvar faFax = {\n prefix: 'fas',\n iconName: 'fax',\n icon: [512, 512, [], \"f1ac\", \"M64 128H32c-17.67 0-32 14.33-32 32v320c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V160c0-17.67-14.33-32-32-32zm416 32V77.25c0-8.49-3.37-16.62-9.37-22.63L425.37 9.37c-6-6-14.14-9.37-22.63-9.37H160c-17.67 0-32 14.33-32 32v448c0 17.67 14.33 32 32 32h320c17.67 0 32-14.33 32-32V192c0-17.67-14.33-32-32-32zM288 432c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v32zm0-128c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v32zm128 128c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v32zm0-128c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v32zm16-112H176V48h208v32c0 8.84 7.16 16 16 16h32v96z\"]\n};\nvar faFeather = {\n prefix: 'fas',\n iconName: 'feather',\n icon: [512, 512, [], \"f52d\", \"M467.14 44.84c-62.55-62.48-161.67-64.78-252.28 25.73-78.61 78.52-60.98 60.92-85.75 85.66-60.46 60.39-70.39 150.83-63.64 211.17l178.44-178.25c6.26-6.25 16.4-6.25 22.65 0s6.25 16.38 0 22.63L7.04 471.03c-9.38 9.37-9.38 24.57 0 33.94 9.38 9.37 24.6 9.37 33.98 0l66.1-66.03C159.42 454.65 279 457.11 353.95 384h-98.19l147.57-49.14c49.99-49.93 36.38-36.18 46.31-46.86h-97.78l131.54-43.8c45.44-74.46 34.31-148.84-16.26-199.36z\"]\n};\nvar faFeatherAlt = {\n prefix: 'fas',\n iconName: 'feather-alt',\n icon: [512, 512, [], \"f56b\", \"M512 0C460.22 3.56 96.44 38.2 71.01 287.61c-3.09 26.66-4.84 53.44-5.99 80.24l178.87-178.69c6.25-6.25 16.4-6.25 22.65 0s6.25 16.38 0 22.63L7.04 471.03c-9.38 9.37-9.38 24.57 0 33.94 9.38 9.37 24.59 9.37 33.98 0l57.13-57.07c42.09-.14 84.15-2.53 125.96-7.36 53.48-5.44 97.02-26.47 132.58-56.54H255.74l146.79-48.88c11.25-14.89 21.37-30.71 30.45-47.12h-81.14l106.54-53.21C500.29 132.86 510.19 26.26 512 0z\"]\n};\nvar faFemale = {\n prefix: 'fas',\n iconName: 'female',\n icon: [256, 512, [], \"f182\", \"M128 0c35.346 0 64 28.654 64 64s-28.654 64-64 64c-35.346 0-64-28.654-64-64S92.654 0 128 0m119.283 354.179l-48-192A24 24 0 0 0 176 144h-11.36c-22.711 10.443-49.59 10.894-73.28 0H80a24 24 0 0 0-23.283 18.179l-48 192C4.935 369.305 16.383 384 32 384h56v104c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V384h56c15.591 0 27.071-14.671 23.283-29.821z\"]\n};\nvar faFighterJet = {\n prefix: 'fas',\n iconName: 'fighter-jet',\n icon: [640, 512, [], \"f0fb\", \"M544 224l-128-16-48-16h-24L227.158 44h39.509C278.333 44 288 41.375 288 38s-9.667-6-21.333-6H152v12h16v164h-48l-66.667-80H18.667L8 138.667V208h8v16h48v2.666l-64 8v42.667l64 8V288H16v16H8v69.333L18.667 384h34.667L120 304h48v164h-16v12h114.667c11.667 0 21.333-2.625 21.333-6s-9.667-6-21.333-6h-39.509L344 320h24l48-16 128-16c96-21.333 96-26.583 96-32 0-5.417 0-10.667-96-32z\"]\n};\nvar faFile = {\n prefix: 'fas',\n iconName: 'file',\n icon: [384, 512, [], \"f15b\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm160-14.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z\"]\n};\nvar faFileAlt = {\n prefix: 'fas',\n iconName: 'file-alt',\n icon: [384, 512, [], \"f15c\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm64 236c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12v8zm0-64c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12v8zm0-72v8c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm96-114.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z\"]\n};\nvar faFileArchive = {\n prefix: 'fas',\n iconName: 'file-archive',\n icon: [384, 512, [], \"f1c6\", \"M377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zM128.4 336c-17.9 0-32.4 12.1-32.4 27 0 15 14.6 27 32.5 27s32.4-12.1 32.4-27-14.6-27-32.5-27zM224 136V0h-63.6v32h-32V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zM95.9 32h32v32h-32zm32.3 384c-33.2 0-58-30.4-51.4-62.9L96.4 256v-32h32v-32h-32v-32h32v-32h-32V96h32V64h32v32h-32v32h32v32h-32v32h32v32h-32v32h22.1c5.7 0 10.7 4.1 11.8 9.7l17.3 87.7c6.4 32.4-18.4 62.6-51.4 62.6z\"]\n};\nvar faFileAudio = {\n prefix: 'fas',\n iconName: 'file-audio',\n icon: [384, 512, [], \"f1c7\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm-64 268c0 10.7-12.9 16-20.5 8.5L104 376H76c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h28l35.5-36.5c7.6-7.6 20.5-2.2 20.5 8.5v136zm33.2-47.6c9.1-9.3 9.1-24.1 0-33.4-22.1-22.8 12.2-56.2 34.4-33.5 27.2 27.9 27.2 72.4 0 100.4-21.8 22.3-56.9-10.4-34.4-33.5zm86-117.1c54.4 55.9 54.4 144.8 0 200.8-21.8 22.4-57-10.3-34.4-33.5 36.2-37.2 36.3-96.5 0-133.8-22.1-22.8 12.3-56.3 34.4-33.5zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z\"]\n};\nvar faFileCode = {\n prefix: 'fas',\n iconName: 'file-code',\n icon: [384, 512, [], \"f1c9\", \"M384 121.941V128H256V0h6.059c6.365 0 12.47 2.529 16.971 7.029l97.941 97.941A24.005 24.005 0 0 1 384 121.941zM248 160c-13.2 0-24-10.8-24-24V0H24C10.745 0 0 10.745 0 24v464c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V160H248zM123.206 400.505a5.4 5.4 0 0 1-7.633.246l-64.866-60.812a5.4 5.4 0 0 1 0-7.879l64.866-60.812a5.4 5.4 0 0 1 7.633.246l19.579 20.885a5.4 5.4 0 0 1-.372 7.747L101.65 336l40.763 35.874a5.4 5.4 0 0 1 .372 7.747l-19.579 20.884zm51.295 50.479l-27.453-7.97a5.402 5.402 0 0 1-3.681-6.692l61.44-211.626a5.402 5.402 0 0 1 6.692-3.681l27.452 7.97a5.4 5.4 0 0 1 3.68 6.692l-61.44 211.626a5.397 5.397 0 0 1-6.69 3.681zm160.792-111.045l-64.866 60.812a5.4 5.4 0 0 1-7.633-.246l-19.58-20.885a5.4 5.4 0 0 1 .372-7.747L284.35 336l-40.763-35.874a5.4 5.4 0 0 1-.372-7.747l19.58-20.885a5.4 5.4 0 0 1 7.633-.246l64.866 60.812a5.4 5.4 0 0 1-.001 7.879z\"]\n};\nvar faFileContract = {\n prefix: 'fas',\n iconName: 'file-contract',\n icon: [384, 512, [], \"f56c\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zM64 72c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8V72zm0 64c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16zm192.81 248H304c8.84 0 16 7.16 16 16s-7.16 16-16 16h-47.19c-16.45 0-31.27-9.14-38.64-23.86-2.95-5.92-8.09-6.52-10.17-6.52s-7.22.59-10.02 6.19l-7.67 15.34a15.986 15.986 0 0 1-14.31 8.84c-.38 0-.75-.02-1.14-.05-6.45-.45-12-4.75-14.03-10.89L144 354.59l-10.61 31.88c-5.89 17.66-22.38 29.53-41 29.53H80c-8.84 0-16-7.16-16-16s7.16-16 16-16h12.39c4.83 0 9.11-3.08 10.64-7.66l18.19-54.64c3.3-9.81 12.44-16.41 22.78-16.41s19.48 6.59 22.77 16.41l13.88 41.64c19.77-16.19 54.05-9.7 66 14.16 2.02 4.06 5.96 6.5 10.16 6.5zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z\"]\n};\nvar faFileCsv = {\n prefix: 'fas',\n iconName: 'file-csv',\n icon: [384, 512, [], \"f6dd\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm-96 144c0 4.42-3.58 8-8 8h-8c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h8c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8h-8c-26.51 0-48-21.49-48-48v-32c0-26.51 21.49-48 48-48h8c4.42 0 8 3.58 8 8v16zm44.27 104H160c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h12.27c5.95 0 10.41-3.5 10.41-6.62 0-1.3-.75-2.66-2.12-3.84l-21.89-18.77c-8.47-7.22-13.33-17.48-13.33-28.14 0-21.3 19.02-38.62 42.41-38.62H200c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8h-12.27c-5.95 0-10.41 3.5-10.41 6.62 0 1.3.75 2.66 2.12 3.84l21.89 18.77c8.47 7.22 13.33 17.48 13.33 28.14.01 21.29-19 38.62-42.39 38.62zM256 264v20.8c0 20.27 5.7 40.17 16 56.88 10.3-16.7 16-36.61 16-56.88V264c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v20.8c0 35.48-12.88 68.89-36.28 94.09-3.02 3.25-7.27 5.11-11.72 5.11s-8.7-1.86-11.72-5.11c-23.4-25.2-36.28-58.61-36.28-94.09V264c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8zm121-159L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z\"]\n};\nvar faFileDownload = {\n prefix: 'fas',\n iconName: 'file-download',\n icon: [384, 512, [], \"f56d\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm76.45 211.36l-96.42 95.7c-6.65 6.61-17.39 6.61-24.04 0l-96.42-95.7C73.42 337.29 80.54 320 94.82 320H160v-80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v80h65.18c14.28 0 21.4 17.29 11.27 27.36zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z\"]\n};\nvar faFileExcel = {\n prefix: 'fas',\n iconName: 'file-excel',\n icon: [384, 512, [], \"f1c3\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm60.1 106.5L224 336l60.1 93.5c5.1 8-.6 18.5-10.1 18.5h-34.9c-4.4 0-8.5-2.4-10.6-6.3C208.9 405.5 192 373 192 373c-6.4 14.8-10 20-36.6 68.8-2.1 3.9-6.1 6.3-10.5 6.3H110c-9.5 0-15.2-10.5-10.1-18.5l60.3-93.5-60.3-93.5c-5.2-8 .6-18.5 10.1-18.5h34.8c4.4 0 8.5 2.4 10.6 6.3 26.1 48.8 20 33.6 36.6 68.5 0 0 6.1-11.7 36.6-68.5 2.1-3.9 6.2-6.3 10.6-6.3H274c9.5-.1 15.2 10.4 10.1 18.4zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z\"]\n};\nvar faFileExport = {\n prefix: 'fas',\n iconName: 'file-export',\n icon: [576, 512, [], \"f56e\", \"M384 121.9c0-6.3-2.5-12.4-7-16.9L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128zM571 308l-95.7-96.4c-10.1-10.1-27.4-3-27.4 11.3V288h-64v64h64v65.2c0 14.3 17.3 21.4 27.4 11.3L571 332c6.6-6.6 6.6-17.4 0-24zm-379 28v-32c0-8.8 7.2-16 16-16h176V160H248c-13.2 0-24-10.8-24-24V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V352H208c-8.8 0-16-7.2-16-16z\"]\n};\nvar faFileImage = {\n prefix: 'fas',\n iconName: 'file-image',\n icon: [384, 512, [], \"f1c5\", \"M384 121.941V128H256V0h6.059a24 24 0 0 1 16.97 7.029l97.941 97.941a24.002 24.002 0 0 1 7.03 16.971zM248 160c-13.2 0-24-10.8-24-24V0H24C10.745 0 0 10.745 0 24v464c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V160H248zm-135.455 16c26.51 0 48 21.49 48 48s-21.49 48-48 48-48-21.49-48-48 21.491-48 48-48zm208 240h-256l.485-48.485L104.545 328c4.686-4.686 11.799-4.201 16.485.485L160.545 368 264.06 264.485c4.686-4.686 12.284-4.686 16.971 0L320.545 304v112z\"]\n};\nvar faFileImport = {\n prefix: 'fas',\n iconName: 'file-import',\n icon: [512, 512, [], \"f56f\", \"M16 288c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h112v-64zm489-183L407.1 7c-4.5-4.5-10.6-7-17-7H384v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-153 31V0H152c-13.3 0-24 10.7-24 24v264h128v-65.2c0-14.3 17.3-21.4 27.4-11.3L379 308c6.6 6.7 6.6 17.4 0 24l-95.7 96.4c-10.1 10.1-27.4 3-27.4-11.3V352H128v136c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H376c-13.2 0-24-10.8-24-24z\"]\n};\nvar faFileInvoice = {\n prefix: 'fas',\n iconName: 'file-invoice',\n icon: [384, 512, [], \"f570\", \"M288 256H96v64h192v-64zm89-151L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-153 31V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zM64 72c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8V72zm0 64c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16zm256 304c0 4.42-3.58 8-8 8h-80c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16zm0-200v96c0 8.84-7.16 16-16 16H80c-8.84 0-16-7.16-16-16v-96c0-8.84 7.16-16 16-16h224c8.84 0 16 7.16 16 16z\"]\n};\nvar faFileInvoiceDollar = {\n prefix: 'fas',\n iconName: 'file-invoice-dollar',\n icon: [384, 512, [], \"f571\", \"M377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-153 31V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zM64 72c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8V72zm0 80v-16c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8zm144 263.88V440c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-24.29c-11.29-.58-22.27-4.52-31.37-11.35-3.9-2.93-4.1-8.77-.57-12.14l11.75-11.21c2.77-2.64 6.89-2.76 10.13-.73 3.87 2.42 8.26 3.72 12.82 3.72h28.11c6.5 0 11.8-5.92 11.8-13.19 0-5.95-3.61-11.19-8.77-12.73l-45-13.5c-18.59-5.58-31.58-23.42-31.58-43.39 0-24.52 19.05-44.44 42.67-45.07V232c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v24.29c11.29.58 22.27 4.51 31.37 11.35 3.9 2.93 4.1 8.77.57 12.14l-11.75 11.21c-2.77 2.64-6.89 2.76-10.13.73-3.87-2.43-8.26-3.72-12.82-3.72h-28.11c-6.5 0-11.8 5.92-11.8 13.19 0 5.95 3.61 11.19 8.77 12.73l45 13.5c18.59 5.58 31.58 23.42 31.58 43.39 0 24.53-19.05 44.44-42.67 45.07z\"]\n};\nvar faFileMedical = {\n prefix: 'fas',\n iconName: 'file-medical',\n icon: [384, 512, [], \"f477\", \"M377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-153 31V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm64 160v48c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8z\"]\n};\nvar faFileMedicalAlt = {\n prefix: 'fas',\n iconName: 'file-medical-alt',\n icon: [448, 512, [], \"f478\", \"M288 136V0H88C74.7 0 64 10.7 64 24v232H8c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8h140.9c3 0 5.8 1.7 7.2 4.4l19.9 39.8 56.8-113.7c2.9-5.9 11.4-5.9 14.3 0l34.7 69.5H352c8.8 0 16 7.2 16 16s-7.2 16-16 16h-89.9L240 275.8l-56.8 113.7c-2.9 5.9-11.4 5.9-14.3 0L134.1 320H64v168c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H312c-13.2 0-24-10.8-24-24zm153-31L343.1 7c-4.5-4.5-10.6-7-17-7H320v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z\"]\n};\nvar faFilePdf = {\n prefix: 'fas',\n iconName: 'file-pdf',\n icon: [384, 512, [], \"f1c1\", \"M181.9 256.1c-5-16-4.9-46.9-2-46.9 8.4 0 7.6 36.9 2 46.9zm-1.7 47.2c-7.7 20.2-17.3 43.3-28.4 62.7 18.3-7 39-17.2 62.9-21.9-12.7-9.6-24.9-23.4-34.5-40.8zM86.1 428.1c0 .8 13.2-5.4 34.9-40.2-6.7 6.3-29.1 24.5-34.9 40.2zM248 160h136v328c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V24C0 10.7 10.7 0 24 0h200v136c0 13.2 10.8 24 24 24zm-8 171.8c-20-12.2-33.3-29-42.7-53.8 4.5-18.5 11.6-46.6 6.2-64.2-4.7-29.4-42.4-26.5-47.8-6.8-5 18.3-.4 44.1 8.1 77-11.6 27.6-28.7 64.6-40.8 85.8-.1 0-.1.1-.2.1-27.1 13.9-73.6 44.5-54.5 68 5.6 6.9 16 10 21.5 10 17.9 0 35.7-18 61.1-61.8 25.8-8.5 54.1-19.1 79-23.2 21.7 11.8 47.1 19.5 64 19.5 29.2 0 31.2-32 19.7-43.4-13.9-13.6-54.3-9.7-73.6-7.2zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-74.1 255.3c4.1-2.7-2.5-11.9-42.8-9 37.1 15.8 42.8 9 42.8 9z\"]\n};\nvar faFilePowerpoint = {\n prefix: 'fas',\n iconName: 'file-powerpoint',\n icon: [384, 512, [], \"f1c4\", \"M193.7 271.2c8.8 0 15.5 2.7 20.3 8.1 9.6 10.9 9.8 32.7-.2 44.1-4.9 5.6-11.9 8.5-21.1 8.5h-26.9v-60.7h27.9zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-153 31V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm53 165.2c0 90.3-88.8 77.6-111.1 77.6V436c0 6.6-5.4 12-12 12h-30.8c-6.6 0-12-5.4-12-12V236.2c0-6.6 5.4-12 12-12h81c44.5 0 72.9 32.8 72.9 77z\"]\n};\nvar faFilePrescription = {\n prefix: 'fas',\n iconName: 'file-prescription',\n icon: [384, 512, [], \"f572\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm68.53 179.48l11.31 11.31c6.25 6.25 6.25 16.38 0 22.63l-29.9 29.9L304 409.38c6.25 6.25 6.25 16.38 0 22.63l-11.31 11.31c-6.25 6.25-16.38 6.25-22.63 0L240 413.25l-30.06 30.06c-6.25 6.25-16.38 6.25-22.63 0L176 432c-6.25-6.25-6.25-16.38 0-22.63l30.06-30.06L146.74 320H128v48c0 8.84-7.16 16-16 16H96c-8.84 0-16-7.16-16-16V208c0-8.84 7.16-16 16-16h80c35.35 0 64 28.65 64 64 0 24.22-13.62 45.05-33.46 55.92L240 345.38l29.9-29.9c6.25-6.25 16.38-6.25 22.63 0zM176 272h-48v-32h48c8.82 0 16 7.18 16 16s-7.18 16-16 16zm208-150.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z\"]\n};\nvar faFileSignature = {\n prefix: 'fas',\n iconName: 'file-signature',\n icon: [576, 512, [], \"f573\", \"M218.17 424.14c-2.95-5.92-8.09-6.52-10.17-6.52s-7.22.59-10.02 6.19l-7.67 15.34c-6.37 12.78-25.03 11.37-29.48-2.09L144 386.59l-10.61 31.88c-5.89 17.66-22.38 29.53-41 29.53H80c-8.84 0-16-7.16-16-16s7.16-16 16-16h12.39c4.83 0 9.11-3.08 10.64-7.66l18.19-54.64c3.3-9.81 12.44-16.41 22.78-16.41s19.48 6.59 22.77 16.41l13.88 41.64c19.75-16.19 54.06-9.7 66 14.16 1.89 3.78 5.49 5.95 9.36 6.26v-82.12l128-127.09V160H248c-13.2 0-24-10.8-24-24V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24v-40l-128-.11c-16.12-.31-30.58-9.28-37.83-23.75zM384 121.9c0-6.3-2.5-12.4-7-16.9L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1zm-96 225.06V416h68.99l161.68-162.78-67.88-67.88L288 346.96zm280.54-179.63l-31.87-31.87c-9.94-9.94-26.07-9.94-36.01 0l-27.25 27.25 67.88 67.88 27.25-27.25c9.95-9.94 9.95-26.07 0-36.01z\"]\n};\nvar faFileUpload = {\n prefix: 'fas',\n iconName: 'file-upload',\n icon: [384, 512, [], \"f574\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm65.18 216.01H224v80c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-80H94.82c-14.28 0-21.41-17.29-11.27-27.36l96.42-95.7c6.65-6.61 17.39-6.61 24.04 0l96.42 95.7c10.15 10.07 3.03 27.36-11.25 27.36zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z\"]\n};\nvar faFileVideo = {\n prefix: 'fas',\n iconName: 'file-video',\n icon: [384, 512, [], \"f1c8\", \"M384 121.941V128H256V0h6.059c6.365 0 12.47 2.529 16.971 7.029l97.941 97.941A24.005 24.005 0 0 1 384 121.941zM224 136V0H24C10.745 0 0 10.745 0 24v464c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V160H248c-13.2 0-24-10.8-24-24zm96 144.016v111.963c0 21.445-25.943 31.998-40.971 16.971L224 353.941V392c0 13.255-10.745 24-24 24H88c-13.255 0-24-10.745-24-24V280c0-13.255 10.745-24 24-24h112c13.255 0 24 10.745 24 24v38.059l55.029-55.013c15.011-15.01 40.971-4.491 40.971 16.97z\"]\n};\nvar faFileWord = {\n prefix: 'fas',\n iconName: 'file-word',\n icon: [384, 512, [], \"f1c2\", \"M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm57.1 120H305c7.7 0 13.4 7.1 11.7 14.7l-38 168c-1.2 5.5-6.1 9.3-11.7 9.3h-38c-5.5 0-10.3-3.8-11.6-9.1-25.8-103.5-20.8-81.2-25.6-110.5h-.5c-1.1 14.3-2.4 17.4-25.6 110.5-1.3 5.3-6.1 9.1-11.6 9.1H117c-5.6 0-10.5-3.9-11.7-9.4l-37.8-168c-1.7-7.5 4-14.6 11.7-14.6h24.5c5.7 0 10.7 4 11.8 9.7 15.6 78 20.1 109.5 21 122.2 1.6-10.2 7.3-32.7 29.4-122.7 1.3-5.4 6.1-9.1 11.7-9.1h29.1c5.6 0 10.4 3.8 11.7 9.2 24 100.4 28.8 124 29.6 129.4-.2-11.2-2.6-17.8 21.6-129.2 1-5.6 5.9-9.5 11.5-9.5zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z\"]\n};\nvar faFill = {\n prefix: 'fas',\n iconName: 'fill',\n icon: [512, 512, [], \"f575\", \"M502.63 217.06L294.94 9.37C288.69 3.12 280.5 0 272.31 0s-16.38 3.12-22.62 9.37l-81.58 81.58L81.93 4.77c-6.24-6.25-16.38-6.25-22.62 0L36.69 27.38c-6.24 6.25-6.24 16.38 0 22.63l86.19 86.18-94.76 94.76c-37.49 37.49-37.49 98.26 0 135.75l117.19 117.19c18.75 18.74 43.31 28.12 67.87 28.12 24.57 0 49.13-9.37 67.88-28.12l221.57-221.57c12.49-12.5 12.49-32.76 0-45.26zm-116.22 70.97H65.93c1.36-3.84 3.57-7.98 7.43-11.83l13.15-13.15 81.61-81.61 58.61 58.6c12.49 12.49 32.75 12.49 45.24 0 12.49-12.49 12.49-32.75 0-45.24l-58.61-58.6 58.95-58.95 162.45 162.44-48.35 48.34z\"]\n};\nvar faFillDrip = {\n prefix: 'fas',\n iconName: 'fill-drip',\n icon: [576, 512, [], \"f576\", \"M512 320s-64 92.65-64 128c0 35.35 28.66 64 64 64s64-28.65 64-64-64-128-64-128zm-9.37-102.94L294.94 9.37C288.69 3.12 280.5 0 272.31 0s-16.38 3.12-22.62 9.37l-81.58 81.58L81.93 4.76c-6.25-6.25-16.38-6.25-22.62 0L36.69 27.38c-6.24 6.25-6.24 16.38 0 22.62l86.19 86.18-94.76 94.76c-37.49 37.48-37.49 98.26 0 135.75l117.19 117.19c18.74 18.74 43.31 28.12 67.87 28.12 24.57 0 49.13-9.37 67.87-28.12l221.57-221.57c12.5-12.5 12.5-32.75.01-45.25zm-116.22 70.97H65.93c1.36-3.84 3.57-7.98 7.43-11.83l13.15-13.15 81.61-81.61 58.6 58.6c12.49 12.49 32.75 12.49 45.24 0s12.49-32.75 0-45.24l-58.6-58.6 58.95-58.95 162.44 162.44-48.34 48.34z\"]\n};\nvar faFilm = {\n prefix: 'fas',\n iconName: 'film',\n icon: [512, 512, [], \"f008\", \"M488 64h-8v20c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12V64H96v20c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12V64h-8C10.7 64 0 74.7 0 88v336c0 13.3 10.7 24 24 24h8v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h320v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h8c13.3 0 24-10.7 24-24V88c0-13.3-10.7-24-24-24zM96 372c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm272 208c0 6.6-5.4 12-12 12H156c-6.6 0-12-5.4-12-12v-96c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v96zm0-168c0 6.6-5.4 12-12 12H156c-6.6 0-12-5.4-12-12v-96c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v96zm112 152c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40z\"]\n};\nvar faFilter = {\n prefix: 'fas',\n iconName: 'filter',\n icon: [512, 512, [], \"f0b0\", \"M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z\"]\n};\nvar faFingerprint = {\n prefix: 'fas',\n iconName: 'fingerprint',\n icon: [512, 512, [], \"f577\", \"M256.12 245.96c-13.25 0-24 10.74-24 24 1.14 72.25-8.14 141.9-27.7 211.55-2.73 9.72 2.15 30.49 23.12 30.49 10.48 0 20.11-6.92 23.09-17.52 13.53-47.91 31.04-125.41 29.48-224.52.01-13.25-10.73-24-23.99-24zm-.86-81.73C194 164.16 151.25 211.3 152.1 265.32c.75 47.94-3.75 95.91-13.37 142.55-2.69 12.98 5.67 25.69 18.64 28.36 13.05 2.67 25.67-5.66 28.36-18.64 10.34-50.09 15.17-101.58 14.37-153.02-.41-25.95 19.92-52.49 54.45-52.34 31.31.47 57.15 25.34 57.62 55.47.77 48.05-2.81 96.33-10.61 143.55-2.17 13.06 6.69 25.42 19.76 27.58 19.97 3.33 26.81-15.1 27.58-19.77 8.28-50.03 12.06-101.21 11.27-152.11-.88-55.8-47.94-101.88-104.91-102.72zm-110.69-19.78c-10.3-8.34-25.37-6.8-33.76 3.48-25.62 31.5-39.39 71.28-38.75 112 .59 37.58-2.47 75.27-9.11 112.05-2.34 13.05 6.31 25.53 19.36 27.89 20.11 3.5 27.07-14.81 27.89-19.36 7.19-39.84 10.5-80.66 9.86-121.33-.47-29.88 9.2-57.88 28-80.97 8.35-10.28 6.79-25.39-3.49-33.76zm109.47-62.33c-15.41-.41-30.87 1.44-45.78 4.97-12.89 3.06-20.87 15.98-17.83 28.89 3.06 12.89 16 20.83 28.89 17.83 11.05-2.61 22.47-3.77 34-3.69 75.43 1.13 137.73 61.5 138.88 134.58.59 37.88-1.28 76.11-5.58 113.63-1.5 13.17 7.95 25.08 21.11 26.58 16.72 1.95 25.51-11.88 26.58-21.11a929.06 929.06 0 0 0 5.89-119.85c-1.56-98.75-85.07-180.33-186.16-181.83zm252.07 121.45c-2.86-12.92-15.51-21.2-28.61-18.27-12.94 2.86-21.12 15.66-18.26 28.61 4.71 21.41 4.91 37.41 4.7 61.6-.11 13.27 10.55 24.09 23.8 24.2h.2c13.17 0 23.89-10.61 24-23.8.18-22.18.4-44.11-5.83-72.34zm-40.12-90.72C417.29 43.46 337.6 1.29 252.81.02 183.02-.82 118.47 24.91 70.46 72.94 24.09 119.37-.9 181.04.14 246.65l-.12 21.47c-.39 13.25 10.03 24.31 23.28 24.69.23.02.48.02.72.02 12.92 0 23.59-10.3 23.97-23.3l.16-23.64c-.83-52.5 19.16-101.86 56.28-139 38.76-38.8 91.34-59.67 147.68-58.86 69.45 1.03 134.73 35.56 174.62 92.39 7.61 10.86 22.56 13.45 33.42 5.86 10.84-7.62 13.46-22.59 5.84-33.43z\"]\n};\nvar faFire = {\n prefix: 'fas',\n iconName: 'fire',\n icon: [384, 512, [], \"f06d\", \"M216 23.86c0-23.8-30.65-32.77-44.15-13.04C48 191.85 224 200 224 288c0 35.63-29.11 64.46-64.85 63.99-35.17-.45-63.15-29.77-63.15-64.94v-85.51c0-21.7-26.47-32.23-41.43-16.5C27.8 213.16 0 261.33 0 320c0 105.87 86.13 192 192 192s192-86.13 192-192c0-170.29-168-193-168-296.14z\"]\n};\nvar faFireAlt = {\n prefix: 'fas',\n iconName: 'fire-alt',\n icon: [448, 512, [], \"f7e4\", \"M323.56 51.2c-20.8 19.3-39.58 39.59-56.22 59.97C240.08 73.62 206.28 35.53 168 0 69.74 91.17 0 209.96 0 281.6 0 408.85 100.29 512 224 512s224-103.15 224-230.4c0-53.27-51.98-163.14-124.44-230.4zm-19.47 340.65C282.43 407.01 255.72 416 226.86 416 154.71 416 96 368.26 96 290.75c0-38.61 24.31-72.63 72.79-130.75 6.93 7.98 98.83 125.34 98.83 125.34l58.63-66.88c4.14 6.85 7.91 13.55 11.27 19.97 27.35 52.19 15.81 118.97-33.43 153.42z\"]\n};\nvar faFireExtinguisher = {\n prefix: 'fas',\n iconName: 'fire-extinguisher',\n icon: [448, 512, [], \"f134\", \"M434.027 26.329l-168 28C254.693 56.218 256 67.8 256 72h-58.332C208.353 36.108 181.446 0 144 0c-39.435 0-66.368 39.676-52.228 76.203-52.039 13.051-75.381 54.213-90.049 90.884-4.923 12.307 1.063 26.274 13.37 31.197 12.317 4.926 26.279-1.075 31.196-13.37C75.058 112.99 106.964 120 168 120v27.076c-41.543 10.862-72 49.235-72 94.129V488c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24V240c0-44.731-30.596-82.312-72-92.97V120h40c0 2.974-1.703 15.716 10.027 17.671l168 28C441.342 166.89 448 161.25 448 153.834V38.166c0-7.416-6.658-13.056-13.973-11.837zM144 72c-8.822 0-16-7.178-16-16s7.178-16 16-16 16 7.178 16 16-7.178 16-16 16z\"]\n};\nvar faFirstAid = {\n prefix: 'fas',\n iconName: 'first-aid',\n icon: [576, 512, [], \"f479\", \"M0 80v352c0 26.5 21.5 48 48 48h48V32H48C21.5 32 0 53.5 0 80zm128 400h320V32H128v448zm64-248c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8v48c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48zM528 32h-48v448h48c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z\"]\n};\nvar faFish = {\n prefix: 'fas',\n iconName: 'fish',\n icon: [576, 512, [], \"f578\", \"M327.1 96c-89.97 0-168.54 54.77-212.27 101.63L27.5 131.58c-12.13-9.18-30.24.6-27.14 14.66L24.54 256 .35 365.77c-3.1 14.06 15.01 23.83 27.14 14.66l87.33-66.05C158.55 361.23 237.13 416 327.1 416 464.56 416 576 288 576 256S464.56 96 327.1 96zm87.43 184c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24 13.26 0 24 10.74 24 24 0 13.25-10.75 24-24 24z\"]\n};\nvar faFistRaised = {\n prefix: 'fas',\n iconName: 'fist-raised',\n icon: [384, 512, [], \"f6de\", \"M255.98 160V16c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v146.93c5.02-1.78 10.34-2.93 15.97-2.93h48.03zm128 95.99c-.01-35.34-28.66-63.99-63.99-63.99H207.85c-8.78 0-15.9 7.07-15.9 15.85v.56c0 26.27 21.3 47.59 47.57 47.59h35.26c9.68 0 13.2 3.58 13.2 8v16.2c0 4.29-3.59 7.78-7.88 8-44.52 2.28-64.16 24.71-96.05 72.55l-6.31 9.47a7.994 7.994 0 0 1-11.09 2.22l-13.31-8.88a7.994 7.994 0 0 1-2.22-11.09l6.31-9.47c15.73-23.6 30.2-43.26 47.31-58.08-17.27-5.51-31.4-18.12-38.87-34.45-6.59 3.41-13.96 5.52-21.87 5.52h-32c-12.34 0-23.49-4.81-32-12.48C71.48 251.19 60.33 256 48 256H16c-5.64 0-10.97-1.15-16-2.95v77.93c0 33.95 13.48 66.5 37.49 90.51L63.99 448v64h255.98v-63.96l35.91-35.92A96.035 96.035 0 0 0 384 344.21l-.02-88.22zm-32.01-90.09V48c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v112h32c11.28 0 21.94 2.31 32 5.9zM16 224h32c8.84 0 16-7.16 16-16V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v128c0 8.84 7.16 16 16 16zm95.99 0h32c8.84 0 16-7.16 16-16V48c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v160c0 8.84 7.16 16 16 16z\"]\n};\nvar faFlag = {\n prefix: 'fas',\n iconName: 'flag',\n icon: [512, 512, [], \"f024\", \"M349.565 98.783C295.978 98.783 251.721 64 184.348 64c-24.955 0-47.309 4.384-68.045 12.013a55.947 55.947 0 0 0 3.586-23.562C118.117 24.015 94.806 1.206 66.338.048 34.345-1.254 8 24.296 8 56c0 19.026 9.497 35.825 24 45.945V488c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-94.4c28.311-12.064 63.582-22.122 114.435-22.122 53.588 0 97.844 34.783 165.217 34.783 48.169 0 86.667-16.294 122.505-40.858C506.84 359.452 512 349.571 512 339.045v-243.1c0-23.393-24.269-38.87-45.485-29.016-34.338 15.948-76.454 31.854-116.95 31.854z\"]\n};\nvar faFlagCheckered = {\n prefix: 'fas',\n iconName: 'flag-checkered',\n icon: [512, 512, [], \"f11e\", \"M243.2 189.9V258c26.1 5.9 49.3 15.6 73.6 22.3v-68.2c-26-5.8-49.4-15.5-73.6-22.2zm223.3-123c-34.3 15.9-76.5 31.9-117 31.9C296 98.8 251.7 64 184.3 64c-25 0-47.3 4.4-68 12 2.8-7.3 4.1-15.2 3.6-23.6C118.1 24 94.8 1.2 66.3 0 34.3-1.3 8 24.3 8 56c0 19 9.5 35.8 24 45.9V488c0 13.3 10.7 24 24 24h16c13.3 0 24-10.7 24-24v-94.4c28.3-12.1 63.6-22.1 114.4-22.1 53.6 0 97.8 34.8 165.2 34.8 48.2 0 86.7-16.3 122.5-40.9 8.7-6 13.8-15.8 13.8-26.4V95.9c.1-23.3-24.2-38.8-45.4-29zM169.6 325.5c-25.8 2.7-50 8.2-73.6 16.6v-70.5c26.2-9.3 47.5-15 73.6-17.4zM464 191c-23.6 9.8-46.3 19.5-73.6 23.9V286c24.8-3.4 51.4-11.8 73.6-26v70.5c-25.1 16.1-48.5 24.7-73.6 27.1V286c-27 3.7-47.9 1.5-73.6-5.6v67.4c-23.9-7.4-47.3-16.7-73.6-21.3V258c-19.7-4.4-40.8-6.8-73.6-3.8v-70c-22.4 3.1-44.6 10.2-73.6 20.9v-70.5c33.2-12.2 50.1-19.8 73.6-22v71.6c27-3.7 48.4-1.3 73.6 5.7v-67.4c23.7 7.4 47.2 16.7 73.6 21.3v68.4c23.7 5.3 47.6 6.9 73.6 2.7V143c27-4.8 52.3-13.6 73.6-22.5z\"]\n};\nvar faFlagUsa = {\n prefix: 'fas',\n iconName: 'flag-usa',\n icon: [512, 512, [], \"f74d\", \"M32 0C14.3 0 0 14.3 0 32v464c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V32C64 14.3 49.7 0 32 0zm267.9 303.6c-57.2-15.1-111.7-28.8-203.9 11.1V384c185.7-92.2 221.7 53.3 397.5-23.1 11.4-5 18.5-16.5 18.5-28.8v-36c-43.6 17.3-80.2 24.1-112.1 24.1-37.4-.1-68.9-8.4-100-16.6zm0-96c-57.2-15.1-111.7-28.8-203.9 11.1v61.5c94.8-37.6 154.6-22.7 212.1-7.6 57.2 15.1 111.7 28.8 203.9-11.1V200c-43.6 17.3-80.2 24.1-112.1 24.1-37.4 0-68.9-8.3-100-16.5zm9.5-125.9c51.8 15.6 97.4 29 202.6-20.1V30.8c0-25.1-26.8-38.1-49.4-26.6C291.3 91.5 305.4-62.2 96 32.4v151.9c94.8-37.5 154.6-22.7 212.1-7.6 57.2 15 111.7 28.7 203.9-11.1V96.7c-53.6 23.5-93.3 31.4-126.1 31.4s-59-7.8-85.7-15.9c-4-1.2-8.1-2.4-12.1-3.5V75.5c7.2 2 14.3 4.1 21.3 6.2zM160 128.1c-8.8 0-16-7.1-16-16 0-8.8 7.2-16 16-16s16 7.1 16 16-7.2 16-16 16zm0-55.8c-8.8 0-16-7.1-16-16 0-8.8 7.2-16 16-16s16 7.1 16 16c0 8.8-7.2 16-16 16zm64 47.9c-8.8 0-16-7.1-16-16 0-8.8 7.2-16 16-16s16 7.1 16 16c0 8.8-7.2 16-16 16zm0-55.9c-8.8 0-16-7.1-16-16 0-8.8 7.2-16 16-16s16 7.1 16 16c0 8.8-7.2 16-16 16z\"]\n};\nvar faFlask = {\n prefix: 'fas',\n iconName: 'flask',\n icon: [448, 512, [], \"f0c3\", \"M437.2 403.5L320 215V64h8c13.3 0 24-10.7 24-24V24c0-13.3-10.7-24-24-24H120c-13.3 0-24 10.7-24 24v16c0 13.3 10.7 24 24 24h8v151L10.8 403.5C-18.5 450.6 15.3 512 70.9 512h306.2c55.7 0 89.4-61.5 60.1-108.5zM137.9 320l48.2-77.6c3.7-5.2 5.8-11.6 5.8-18.4V64h64v160c0 6.9 2.2 13.2 5.8 18.4l48.2 77.6h-172z\"]\n};\nvar faFlushed = {\n prefix: 'fas',\n iconName: 'flushed',\n icon: [496, 512, [], \"f579\", \"M344 200c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm-192 0c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM80 224c0-39.8 32.2-72 72-72s72 32.2 72 72-32.2 72-72 72-72-32.2-72-72zm232 176H184c-21.2 0-21.2-32 0-32h128c21.2 0 21.2 32 0 32zm32-104c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72-32.2 72-72 72z\"]\n};\nvar faFolder = {\n prefix: 'fas',\n iconName: 'folder',\n icon: [512, 512, [], \"f07b\", \"M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48z\"]\n};\nvar faFolderMinus = {\n prefix: 'fas',\n iconName: 'folder-minus',\n icon: [512, 512, [], \"f65d\", \"M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48zm-96 168c0 8.84-7.16 16-16 16H160c-8.84 0-16-7.16-16-16v-16c0-8.84 7.16-16 16-16h192c8.84 0 16 7.16 16 16v16z\"]\n};\nvar faFolderOpen = {\n prefix: 'fas',\n iconName: 'folder-open',\n icon: [576, 512, [], \"f07c\", \"M572.694 292.093L500.27 416.248A63.997 63.997 0 0 1 444.989 448H45.025c-18.523 0-30.064-20.093-20.731-36.093l72.424-124.155A64 64 0 0 1 152 256h399.964c18.523 0 30.064 20.093 20.73 36.093zM152 224h328v-48c0-26.51-21.49-48-48-48H272l-64-64H48C21.49 64 0 85.49 0 112v278.046l69.077-118.418C86.214 242.25 117.989 224 152 224z\"]\n};\nvar faFolderPlus = {\n prefix: 'fas',\n iconName: 'folder-plus',\n icon: [512, 512, [], \"f65e\", \"M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48zm-96 168c0 8.84-7.16 16-16 16h-72v72c0 8.84-7.16 16-16 16h-16c-8.84 0-16-7.16-16-16v-72h-72c-8.84 0-16-7.16-16-16v-16c0-8.84 7.16-16 16-16h72v-72c0-8.84 7.16-16 16-16h16c8.84 0 16 7.16 16 16v72h72c8.84 0 16 7.16 16 16v16z\"]\n};\nvar faFont = {\n prefix: 'fas',\n iconName: 'font',\n icon: [448, 512, [], \"f031\", \"M432 416h-26.7L275.5 42.7c-2.2-6.4-8.3-10.7-15.1-10.7h-72.8c-6.8 0-12.9 4.3-15.1 10.7L42.7 416H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h136c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16h-24l26.6-80.8h138.2l26.6 80.8H296c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h136c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM174.4 268.3l42-124.1c4.3-15.2 6.6-28.2 7.6-34.6.8 6.5 2.9 19.5 7.7 34.7l41.3 124z\"]\n};\nvar faFontAwesomeLogoFull = {\n prefix: 'fas',\n iconName: 'font-awesome-logo-full',\n icon: [3992, 512, [\"Font Awesome\"], \"f4e6\", \"M454.6 0H57.4C25.9 0 0 25.9 0 57.4v397.3C0 486.1 25.9 512 57.4 512h397.3c31.4 0 57.4-25.9 57.4-57.4V57.4C512 25.9 486.1 0 454.6 0zm-58.9 324.9c0 4.8-4.1 6.9-8.9 8.9-19.2 8.1-39.7 15.7-61.5 15.7-40.5 0-68.7-44.8-163.2 2.5v51.8c0 30.3-45.7 30.2-45.7 0v-250c-9-7-15-17.9-15-30.3 0-21 17.1-38.2 38.2-38.2 21 0 38.2 17.1 38.2 38.2 0 12.2-5.8 23.2-14.9 30.2v21c37.1-12 65.5-34.4 146.1-3.4 26.6 11.4 68.7-15.7 76.5-15.7 5.5 0 10.3 4.1 10.3 8.9v160.4zm432.9-174.2h-137v70.1H825c39.8 0 40.4 62.2 0 62.2H691.6v105.6c0 45.5-70.7 46.4-70.7 0V128.3c0-22 18-39.8 39.8-39.8h167.8c39.6 0 40.5 62.2.1 62.2zm191.1 23.4c-169.3 0-169.1 252.4 0 252.4 169.9 0 169.9-252.4 0-252.4zm0 196.1c-81.6 0-82.1-139.8 0-139.8 82.5 0 82.4 139.8 0 139.8zm372.4 53.4c-17.5 0-31.4-13.9-31.4-31.4v-117c0-62.4-72.6-52.5-99.1-16.4v133.4c0 41.5-63.3 41.8-63.3 0V208c0-40 63.1-41.6 63.1 0v3.4c43.3-51.6 162.4-60.4 162.4 39.3v141.5c.3 30.4-31.5 31.4-31.7 31.4zm179.7 2.9c-44.3 0-68.3-22.9-68.3-65.8V235.2H1488c-35.6 0-36.7-55.3 0-55.3h15.5v-37.3c0-41.3 63.8-42.1 63.8 0v37.5h24.9c35.4 0 35.7 55.3 0 55.3h-24.9v108.5c0 29.6 26.1 26.3 27.4 26.3 31.4 0 52.6 56.3-22.9 56.3zM1992 123c-19.5-50.2-95.5-50-114.5 0-107.3 275.7-99.5 252.7-99.5 262.8 0 42.8 58.3 51.2 72.1 14.4l13.5-35.9H2006l13 35.9c14.2 37.7 72.1 27.2 72.1-14.4 0-10.1 5.3 6.8-99.1-262.8zm-108.9 179.1l51.7-142.9 51.8 142.9h-103.5zm591.3-85.6l-53.7 176.3c-12.4 41.2-72 41-84 0l-42.3-135.9-42.3 135.9c-12.4 40.9-72 41.2-84.5 0l-54.2-176.3c-12.5-39.4 49.8-56.1 60.2-16.9L2213 342l45.3-139.5c10.9-32.7 59.6-34.7 71.2 0l45.3 139.5 39.3-142.4c10.3-38.3 72.6-23.8 60.3 16.9zm275.4 75.1c0-42.4-33.9-117.5-119.5-117.5-73.2 0-124.4 56.3-124.4 126 0 77.2 55.3 126.4 128.5 126.4 31.7 0 93-11.5 93-39.8 0-18.3-21.1-31.5-39.3-22.4-49.4 26.2-109 8.4-115.9-43.8h148.3c16.3 0 29.3-13.4 29.3-28.9zM2571 277.7c9.5-73.4 113.9-68.6 118.6 0H2571zm316.7 148.8c-31.4 0-81.6-10.5-96.6-31.9-12.4-17 2.5-39.8 21.8-39.8 16.3 0 36.8 22.9 77.7 22.9 27.4 0 40.4-11 40.4-25.8 0-39.8-142.9-7.4-142.9-102 0-40.4 35.3-75.7 98.6-75.7 31.4 0 74.1 9.9 87.6 29.4 10.8 14.8-1.4 36.2-20.9 36.2-15.1 0-26.7-17.3-66.2-17.3-22.9 0-37.8 10.5-37.8 23.8 0 35.9 142.4 6 142.4 103.1-.1 43.7-37.4 77.1-104.1 77.1zm266.8-252.4c-169.3 0-169.1 252.4 0 252.4 170.1 0 169.6-252.4 0-252.4zm0 196.1c-81.8 0-82-139.8 0-139.8 82.5 0 82.4 139.8 0 139.8zm476.9 22V268.7c0-53.8-61.4-45.8-85.7-10.5v134c0 41.3-63.8 42.1-63.8 0V268.7c0-52.1-59.5-47.4-85.7-10.1v133.6c0 41.5-63.3 41.8-63.3 0V208c0-40 63.1-41.6 63.1 0v3.4c9.9-14.4 41.8-37.3 78.6-37.3 35.3 0 57.7 16.4 66.7 43.8 13.9-21.8 45.8-43.8 82.6-43.8 44.3 0 70.7 23.4 70.7 72.7v145.3c.5 17.3-13.5 31.4-31.9 31.4 3.5.1-31.3 1.1-31.3-31.3zM3992 291.6c0-42.4-32.4-117.5-117.9-117.5-73.2 0-127.5 56.3-127.5 126 0 77.2 58.3 126.4 131.6 126.4 31.7 0 91.5-11.5 91.5-39.8 0-18.3-21.1-31.5-39.3-22.4-49.4 26.2-110.5 8.4-117.5-43.8h149.8c16.3 0 29.1-13.4 29.3-28.9zm-180.5-13.9c9.7-74.4 115.9-68.3 120.1 0h-120.1z\"]\n};\nvar faFootballBall = {\n prefix: 'fas',\n iconName: 'football-ball',\n icon: [496, 512, [], \"f44e\", \"M481.5 60.3c-4.8-18.2-19.1-32.5-37.3-37.4C420.3 16.5 383 8.9 339.4 8L496 164.8c-.8-43.5-8.2-80.6-14.5-104.5zm-467 391.4c4.8 18.2 19.1 32.5 37.3 37.4 23.9 6.4 61.2 14 104.8 14.9L0 347.2c.8 43.5 8.2 80.6 14.5 104.5zM4.2 283.4L220.4 500c132.5-19.4 248.8-118.7 271.5-271.4L275.6 12C143.1 31.4 26.8 130.7 4.2 283.4zm317.3-123.6c3.1-3.1 8.2-3.1 11.3 0l11.3 11.3c3.1 3.1 3.1 8.2 0 11.3l-28.3 28.3 28.3 28.3c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0l-28.3-28.3-22.6 22.7 28.3 28.3c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0L248 278.6l-22.6 22.6 28.3 28.3c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0l-28.3-28.3-28.3 28.3c-3.1 3.1-8.2 3.1-11.3 0l-11.3-11.3c-3.1-3.1-3.1-8.2 0-11.3l28.3-28.3-28.3-28.2c-3.1-3.1-3.1-8.2 0-11.3l11.3-11.3c3.1-3.1 8.2-3.1 11.3 0l28.3 28.3 22.6-22.6-28.3-28.3c-3.1-3.1-3.1-8.2 0-11.3l11.3-11.3c3.1-3.1 8.2-3.1 11.3 0l28.3 28.3 22.6-22.6-28.3-28.3c-3.1-3.1-3.1-8.2 0-11.3l11.3-11.3c3.1-3.1 8.2-3.1 11.3 0l28.3 28.3 28.3-28.5z\"]\n};\nvar faForward = {\n prefix: 'fas',\n iconName: 'forward',\n icon: [512, 512, [], \"f04e\", \"M500.5 231.4l-192-160C287.9 54.3 256 68.6 256 96v320c0 27.4 31.9 41.8 52.5 24.6l192-160c15.3-12.8 15.3-36.4 0-49.2zm-256 0l-192-160C31.9 54.3 0 68.6 0 96v320c0 27.4 31.9 41.8 52.5 24.6l192-160c15.3-12.8 15.3-36.4 0-49.2z\"]\n};\nvar faFrog = {\n prefix: 'fas',\n iconName: 'frog',\n icon: [576, 512, [], \"f52e\", \"M446.53 97.43C439.67 60.23 407.19 32 368 32c-39.23 0-71.72 28.29-78.54 65.54C126.75 112.96-.5 250.12 0 416.98.11 451.9 29.08 480 64 480h304c8.84 0 16-7.16 16-16 0-17.67-14.33-32-32-32h-79.49l35.8-48.33c24.14-36.23 10.35-88.28-33.71-106.6-23.89-9.93-51.55-4.65-72.24 10.88l-32.76 24.59c-7.06 5.31-17.09 3.91-22.41-3.19-5.3-7.08-3.88-17.11 3.19-22.41l34.78-26.09c36.84-27.66 88.28-27.62 125.13 0 10.87 8.15 45.87 39.06 40.8 93.21L469.62 480H560c8.84 0 16-7.16 16-16 0-17.67-14.33-32-32-32h-53.63l-98.52-104.68 154.44-86.65A58.16 58.16 0 0 0 576 189.94c0-21.4-11.72-40.95-30.48-51.23-40.56-22.22-98.99-41.28-98.99-41.28zM368 136c-13.26 0-24-10.75-24-24 0-13.26 10.74-24 24-24 13.25 0 24 10.74 24 24 0 13.25-10.75 24-24 24z\"]\n};\nvar faFrown = {\n prefix: 'fas',\n iconName: 'frown',\n icon: [496, 512, [], \"f119\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm170.2 218.2C315.8 367.4 282.9 352 248 352s-67.8 15.4-90.2 42.2c-13.5 16.3-38.1-4.2-24.6-20.5C161.7 339.6 203.6 320 248 320s86.3 19.6 114.7 53.8c13.6 16.2-11 36.7-24.5 20.4z\"]\n};\nvar faFrownOpen = {\n prefix: 'fas',\n iconName: 'frown-open',\n icon: [496, 512, [], \"f57a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM136 208c0-17.7 14.3-32 32-32s32 14.3 32 32-14.3 32-32 32-32-14.3-32-32zm187.3 183.3c-31.2-9.6-59.4-15.3-75.3-15.3s-44.1 5.7-75.3 15.3c-11.5 3.5-22.5-6.3-20.5-18.1 7-40 60.1-61.2 95.8-61.2s88.8 21.3 95.8 61.2c2 11.9-9.1 21.6-20.5 18.1zM328 240c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faFunnelDollar = {\n prefix: 'fas',\n iconName: 'funnel-dollar',\n icon: [640, 512, [], \"f662\", \"M433.46 165.94l101.2-111.87C554.61 34.12 540.48 0 512.26 0H31.74C3.52 0-10.61 34.12 9.34 54.07L192 256v155.92c0 12.59 5.93 24.44 16 32l79.99 60c20.86 15.64 48.47 6.97 59.22-13.57C310.8 455.38 288 406.35 288 352c0-89.79 62.05-165.17 145.46-186.06zM480 192c-88.37 0-160 71.63-160 160s71.63 160 160 160 160-71.63 160-160-71.63-160-160-160zm16 239.88V448c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-16.29c-11.29-.58-22.27-4.52-31.37-11.35-3.9-2.93-4.1-8.77-.57-12.14l11.75-11.21c2.77-2.64 6.89-2.76 10.13-.73 3.87 2.42 8.26 3.72 12.82 3.72h28.11c6.5 0 11.8-5.92 11.8-13.19 0-5.95-3.61-11.19-8.77-12.73l-45-13.5c-18.59-5.58-31.58-23.42-31.58-43.39 0-24.52 19.05-44.44 42.67-45.07V256c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16.29c11.29.58 22.27 4.51 31.37 11.35 3.9 2.93 4.1 8.77.57 12.14l-11.75 11.21c-2.77 2.64-6.89 2.76-10.13.73-3.87-2.43-8.26-3.72-12.82-3.72h-28.11c-6.5 0-11.8 5.92-11.8 13.19 0 5.95 3.61 11.19 8.77 12.73l45 13.5c18.59 5.58 31.58 23.42 31.58 43.39 0 24.53-19.04 44.44-42.67 45.07z\"]\n};\nvar faFutbol = {\n prefix: 'fas',\n iconName: 'futbol',\n icon: [512, 512, [], \"f1e3\", \"M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-48 0l-.003-.282-26.064 22.741-62.679-58.5 16.454-84.355 34.303 3.072c-24.889-34.216-60.004-60.089-100.709-73.141l13.651 31.939L256 139l-74.953-41.525 13.651-31.939c-40.631 13.028-75.78 38.87-100.709 73.141l34.565-3.073 16.192 84.355-62.678 58.5-26.064-22.741-.003.282c0 43.015 13.497 83.952 38.472 117.991l7.704-33.897 85.138 10.447 36.301 77.826-29.902 17.786c40.202 13.122 84.29 13.148 124.572 0l-29.902-17.786 36.301-77.826 85.138-10.447 7.704 33.897C442.503 339.952 456 299.015 456 256zm-248.102 69.571l-29.894-91.312L256 177.732l77.996 56.527-29.622 91.312h-96.476z\"]\n};\nvar faGamepad = {\n prefix: 'fas',\n iconName: 'gamepad',\n icon: [640, 512, [], \"f11b\", \"M480 96H160C71.6 96 0 167.6 0 256s71.6 160 160 160c44.8 0 85.2-18.4 114.2-48h91.5c29 29.6 69.5 48 114.2 48 88.4 0 160-71.6 160-160S568.4 96 480 96zM256 276c0 6.6-5.4 12-12 12h-52v52c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-52H76c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h52v-52c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h52c6.6 0 12 5.4 12 12v40zm184 68c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-80c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z\"]\n};\nvar faGasPump = {\n prefix: 'fas',\n iconName: 'gas-pump',\n icon: [512, 512, [], \"f52f\", \"M336 448H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h320c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm157.2-340.7l-81-81c-6.2-6.2-16.4-6.2-22.6 0l-11.3 11.3c-6.2 6.2-6.2 16.4 0 22.6L416 97.9V160c0 28.1 20.9 51.3 48 55.2V376c0 13.2-10.8 24-24 24s-24-10.8-24-24v-32c0-48.6-39.4-88-88-88h-8V64c0-35.3-28.7-64-64-64H96C60.7 0 32 28.7 32 64v352h288V304h8c22.1 0 40 17.9 40 40v27.8c0 37.7 27 72 64.5 75.9 43 4.3 79.5-29.5 79.5-71.7V152.6c0-17-6.8-33.3-18.8-45.3zM256 192H96V64h160v128z\"]\n};\nvar faGavel = {\n prefix: 'fas',\n iconName: 'gavel',\n icon: [512, 512, [], \"f0e3\", \"M504.971 199.362l-22.627-22.627c-9.373-9.373-24.569-9.373-33.941 0l-5.657 5.657L329.608 69.255l5.657-5.657c9.373-9.373 9.373-24.569 0-33.941L312.638 7.029c-9.373-9.373-24.569-9.373-33.941 0L154.246 131.48c-9.373 9.373-9.373 24.569 0 33.941l22.627 22.627c9.373 9.373 24.569 9.373 33.941 0l5.657-5.657 39.598 39.598-81.04 81.04-5.657-5.657c-12.497-12.497-32.758-12.497-45.255 0L9.373 412.118c-12.497 12.497-12.497 32.758 0 45.255l45.255 45.255c12.497 12.497 32.758 12.497 45.255 0l114.745-114.745c12.497-12.497 12.497-32.758 0-45.255l-5.657-5.657 81.04-81.04 39.598 39.598-5.657 5.657c-9.373 9.373-9.373 24.569 0 33.941l22.627 22.627c9.373 9.373 24.569 9.373 33.941 0l124.451-124.451c9.372-9.372 9.372-24.568 0-33.941z\"]\n};\nvar faGem = {\n prefix: 'fas',\n iconName: 'gem',\n icon: [576, 512, [], \"f3a5\", \"M485.5 0L576 160H474.9L405.7 0h79.8zm-128 0l69.2 160H149.3L218.5 0h139zm-267 0h79.8l-69.2 160H0L90.5 0zM0 192h100.7l123 251.7c1.5 3.1-2.7 5.9-5 3.3L0 192zm148.2 0h279.6l-137 318.2c-1 2.4-4.5 2.4-5.5 0L148.2 192zm204.1 251.7l123-251.7H576L357.3 446.9c-2.3 2.7-6.5-.1-5-3.2z\"]\n};\nvar faGenderless = {\n prefix: 'fas',\n iconName: 'genderless',\n icon: [288, 512, [], \"f22d\", \"M144 176c44.1 0 80 35.9 80 80s-35.9 80-80 80-80-35.9-80-80 35.9-80 80-80m0-64C64.5 112 0 176.5 0 256s64.5 144 144 144 144-64.5 144-144-64.5-144-144-144z\"]\n};\nvar faGhost = {\n prefix: 'fas',\n iconName: 'ghost',\n icon: [384, 512, [], \"f6e2\", \"M186.1.09C81.01 3.24 0 94.92 0 200.05v263.92c0 14.26 17.23 21.39 27.31 11.31l24.92-18.53c6.66-4.95 16-3.99 21.51 2.21l42.95 48.35c6.25 6.25 16.38 6.25 22.63 0l40.72-45.85c6.37-7.17 17.56-7.17 23.92 0l40.72 45.85c6.25 6.25 16.38 6.25 22.63 0l42.95-48.35c5.51-6.2 14.85-7.17 21.51-2.21l24.92 18.53c10.08 10.08 27.31 2.94 27.31-11.31V192C384 84 294.83-3.17 186.1.09zM128 224c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm128 0c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faGift = {\n prefix: 'fas',\n iconName: 'gift',\n icon: [512, 512, [], \"f06b\", \"M32 448c0 17.7 14.3 32 32 32h160V320H32v128zm256 32h160c17.7 0 32-14.3 32-32V320H288v160zm192-320h-42.1c6.2-12.1 10.1-25.5 10.1-40 0-48.5-39.5-88-88-88-41.6 0-68.5 21.3-103 68.3-34.5-47-61.4-68.3-103-68.3-48.5 0-88 39.5-88 88 0 14.5 3.8 27.9 10.1 40H32c-17.7 0-32 14.3-32 32v80c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-80c0-17.7-14.3-32-32-32zm-326.1 0c-22.1 0-40-17.9-40-40s17.9-40 40-40c19.9 0 34.6 3.3 86.1 80h-86.1zm206.1 0h-86.1c51.4-76.5 65.7-80 86.1-80 22.1 0 40 17.9 40 40s-17.9 40-40 40z\"]\n};\nvar faGifts = {\n prefix: 'fas',\n iconName: 'gifts',\n icon: [640, 512, [], \"f79c\", \"M240.6 194.1c1.9-30.8 17.3-61.2 44-79.8C279.4 103.5 268.7 96 256 96h-29.4l30.7-22c7.2-5.1 8.9-15.1 3.7-22.3l-9.3-13c-5.1-7.2-15.1-8.9-22.3-3.7l-32 22.9 11.5-30.6c3.1-8.3-1.1-17.5-9.4-20.6l-15-5.6c-8.3-3.1-17.5 1.1-20.6 9.4l-19.9 53-19.9-53.1C121 2.1 111.8-2.1 103.5 1l-15 5.6C80.2 9.7 76 19 79.2 27.2l11.5 30.6L58.6 35c-7.2-5.1-17.2-3.5-22.3 3.7l-9.3 13c-5.1 7.2-3.5 17.2 3.7 22.3l30.7 22H32c-17.7 0-32 14.3-32 32v352c0 17.7 14.3 32 32 32h168.9c-5.5-9.5-8.9-20.3-8.9-32V256c0-29.9 20.8-55 48.6-61.9zM224 480c0 17.7 14.3 32 32 32h160V384H224v96zm224 32h160c17.7 0 32-14.3 32-32v-96H448v128zm160-288h-20.4c2.6-7.6 4.4-15.5 4.4-23.8 0-35.5-27-72.2-72.1-72.2-48.1 0-75.9 47.7-87.9 75.3-12.1-27.6-39.9-75.3-87.9-75.3-45.1 0-72.1 36.7-72.1 72.2 0 8.3 1.7 16.2 4.4 23.8H256c-17.7 0-32 14.3-32 32v96h192V224h15.3l.7-.2.7.2H448v128h192v-96c0-17.7-14.3-32-32-32zm-272 0c-2.7-1.4-5.1-3-7.2-4.8-7.3-6.4-8.8-13.8-8.8-19 0-9.7 6.4-24.2 24.1-24.2 18.7 0 35.6 27.4 44.5 48H336zm199.2-4.8c-2.1 1.8-4.5 3.4-7.2 4.8h-52.6c8.8-20.3 25.8-48 44.5-48 17.7 0 24.1 14.5 24.1 24.2 0 5.2-1.5 12.6-8.8 19z\"]\n};\nvar faGlassCheers = {\n prefix: 'fas',\n iconName: 'glass-cheers',\n icon: [640, 512, [], \"f79f\", \"M639.4 433.6c-8.4-20.4-31.8-30.1-52.2-21.6l-22.1 9.2-38.7-101.9c47.9-35 64.8-100.3 34.5-152.8L474.3 16c-8-13.9-25.1-19.7-40-13.6L320 49.8 205.7 2.4c-14.9-6.2-32-.3-40 13.6L79.1 166.5C48.9 219 65.7 284.3 113.6 319.2L74.9 421.1l-22.1-9.2c-20.4-8.5-43.7 1.2-52.2 21.6-1.7 4.1.2 8.8 4.3 10.5l162.3 67.4c4.1 1.7 8.7-.2 10.4-4.3 8.4-20.4-1.2-43.8-21.6-52.3l-22.1-9.2L173.3 342c4.4.5 8.8 1.3 13.1 1.3 51.7 0 99.4-33.1 113.4-85.3l20.2-75.4 20.2 75.4c14 52.2 61.7 85.3 113.4 85.3 4.3 0 8.7-.8 13.1-1.3L506 445.6l-22.1 9.2c-20.4 8.5-30.1 31.9-21.6 52.3 1.7 4.1 6.4 6 10.4 4.3L635.1 444c4-1.7 6-6.3 4.3-10.4zM275.9 162.1l-112.1-46.5 36.5-63.4 94.5 39.2-18.9 70.7zm88.2 0l-18.9-70.7 94.5-39.2 36.5 63.4-112.1 46.5z\"]\n};\nvar faGlassMartini = {\n prefix: 'fas',\n iconName: 'glass-martini',\n icon: [512, 512, [], \"f000\", \"M502.05 57.6C523.3 36.34 508.25 0 478.2 0H33.8C3.75 0-11.3 36.34 9.95 57.6L224 271.64V464h-56c-22.09 0-40 17.91-40 40 0 4.42 3.58 8 8 8h240c4.42 0 8-3.58 8-8 0-22.09-17.91-40-40-40h-56V271.64L502.05 57.6z\"]\n};\nvar faGlassMartiniAlt = {\n prefix: 'fas',\n iconName: 'glass-martini-alt',\n icon: [512, 512, [], \"f57b\", \"M502.05 57.6C523.3 36.34 508.25 0 478.2 0H33.8C3.75 0-11.3 36.34 9.95 57.6L224 271.64V464h-56c-22.09 0-40 17.91-40 40 0 4.42 3.58 8 8 8h240c4.42 0 8-3.58 8-8 0-22.09-17.91-40-40-40h-56V271.64L502.05 57.6zM443.77 48l-48 48H116.24l-48-48h375.53z\"]\n};\nvar faGlassWhiskey = {\n prefix: 'fas',\n iconName: 'glass-whiskey',\n icon: [512, 512, [], \"f7a0\", \"M480 32H32C12.5 32-2.4 49.2.3 68.5l56 356.5c4.5 31.5 31.5 54.9 63.4 54.9h273c31.8 0 58.9-23.4 63.4-54.9l55.6-356.5C514.4 49.2 499.5 32 480 32zm-37.4 64l-30 192h-313L69.4 96h373.2z\"]\n};\nvar faGlasses = {\n prefix: 'fas',\n iconName: 'glasses',\n icon: [576, 512, [], \"f530\", \"M574.1 280.37L528.75 98.66c-5.91-23.7-21.59-44.05-43-55.81-21.44-11.73-46.97-14.11-70.19-6.33l-15.25 5.08c-8.39 2.79-12.92 11.86-10.12 20.24l5.06 15.18c2.79 8.38 11.85 12.91 20.23 10.12l13.18-4.39c10.87-3.62 23-3.57 33.16 1.73 10.29 5.37 17.57 14.56 20.37 25.82l38.46 153.82c-22.19-6.81-49.79-12.46-81.2-12.46-34.77 0-73.98 7.02-114.85 26.74h-73.18c-40.87-19.74-80.08-26.75-114.86-26.75-31.42 0-59.02 5.65-81.21 12.46l38.46-153.83c2.79-11.25 10.09-20.45 20.38-25.81 10.16-5.3 22.28-5.35 33.15-1.73l13.17 4.39c8.38 2.79 17.44-1.74 20.23-10.12l5.06-15.18c2.8-8.38-1.73-17.45-10.12-20.24l-15.25-5.08c-23.22-7.78-48.75-5.41-70.19 6.33-21.41 11.77-37.09 32.11-43 55.8L1.9 280.37A64.218 64.218 0 0 0 0 295.86v70.25C0 429.01 51.58 480 115.2 480h37.12c60.28 0 110.37-45.94 114.88-105.37l2.93-38.63h35.75l2.93 38.63C313.31 434.06 363.4 480 423.68 480h37.12c63.62 0 115.2-50.99 115.2-113.88v-70.25c0-5.23-.64-10.43-1.9-15.5zm-370.72 89.42c-1.97 25.91-24.4 46.21-51.06 46.21H115.2C86.97 416 64 393.62 64 366.11v-37.54c18.12-6.49 43.42-12.92 72.58-12.92 23.86 0 47.26 4.33 69.93 12.92l-3.13 41.22zM512 366.12c0 27.51-22.97 49.88-51.2 49.88h-37.12c-26.67 0-49.1-20.3-51.06-46.21l-3.13-41.22c22.67-8.59 46.08-12.92 69.95-12.92 29.12 0 54.43 6.44 72.55 12.93v37.54z\"]\n};\nvar faGlobe = {\n prefix: 'fas',\n iconName: 'globe',\n icon: [496, 512, [], \"f0ac\", \"M336.5 160C322 70.7 287.8 8 248 8s-74 62.7-88.5 152h177zM152 256c0 22.2 1.2 43.5 3.3 64h185.3c2.1-20.5 3.3-41.8 3.3-64s-1.2-43.5-3.3-64H155.3c-2.1 20.5-3.3 41.8-3.3 64zm324.7-96c-28.6-67.9-86.5-120.4-158-141.6 24.4 33.8 41.2 84.7 50 141.6h108zM177.2 18.4C105.8 39.6 47.8 92.1 19.3 160h108c8.7-56.9 25.5-107.8 49.9-141.6zM487.4 192H372.7c2.1 21 3.3 42.5 3.3 64s-1.2 43-3.3 64h114.6c5.5-20.5 8.6-41.8 8.6-64s-3.1-43.5-8.5-64zM120 256c0-21.5 1.2-43 3.3-64H8.6C3.2 212.5 0 233.8 0 256s3.2 43.5 8.6 64h114.6c-2-21-3.2-42.5-3.2-64zm39.5 96c14.5 89.3 48.7 152 88.5 152s74-62.7 88.5-152h-177zm159.3 141.6c71.4-21.2 129.4-73.7 158-141.6h-108c-8.8 56.9-25.6 107.8-50 141.6zM19.3 352c28.6 67.9 86.5 120.4 158 141.6-24.4-33.8-41.2-84.7-50-141.6h-108z\"]\n};\nvar faGlobeAfrica = {\n prefix: 'fas',\n iconName: 'globe-africa',\n icon: [496, 512, [], \"f57c\", \"M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm160 215.5v6.93c0 5.87-3.32 11.24-8.57 13.86l-15.39 7.7a15.485 15.485 0 0 1-15.53-.97l-18.21-12.14a15.52 15.52 0 0 0-13.5-1.81l-2.65.88c-9.7 3.23-13.66 14.79-7.99 23.3l13.24 19.86c2.87 4.31 7.71 6.9 12.89 6.9h8.21c8.56 0 15.5 6.94 15.5 15.5v11.34c0 3.35-1.09 6.62-3.1 9.3l-18.74 24.98c-1.42 1.9-2.39 4.1-2.83 6.43l-4.3 22.83c-.62 3.29-2.29 6.29-4.76 8.56a159.608 159.608 0 0 0-25 29.16l-13.03 19.55a27.756 27.756 0 0 1-23.09 12.36c-10.51 0-20.12-5.94-24.82-15.34a78.902 78.902 0 0 1-8.33-35.29V367.5c0-8.56-6.94-15.5-15.5-15.5h-25.88c-14.49 0-28.38-5.76-38.63-16a54.659 54.659 0 0 1-16-38.63v-14.06c0-17.19 8.1-33.38 21.85-43.7l27.58-20.69a54.663 54.663 0 0 1 32.78-10.93h.89c8.48 0 16.85 1.97 24.43 5.77l14.72 7.36c3.68 1.84 7.93 2.14 11.83.84l47.31-15.77c6.33-2.11 10.6-8.03 10.6-14.7 0-8.56-6.94-15.5-15.5-15.5h-10.09c-4.11 0-8.05-1.63-10.96-4.54l-6.92-6.92a15.493 15.493 0 0 0-10.96-4.54H199.5c-8.56 0-15.5-6.94-15.5-15.5v-4.4c0-7.11 4.84-13.31 11.74-15.04l14.45-3.61c3.74-.94 7-3.23 9.14-6.44l8.08-12.11c2.87-4.31 7.71-6.9 12.89-6.9h24.21c8.56 0 15.5-6.94 15.5-15.5v-21.7C359.23 71.63 422.86 131.02 441.93 208H423.5c-8.56 0-15.5 6.94-15.5 15.5z\"]\n};\nvar faGlobeAmericas = {\n prefix: 'fas',\n iconName: 'globe-americas',\n icon: [496, 512, [], \"f57d\", \"M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm82.29 357.6c-3.9 3.88-7.99 7.95-11.31 11.28-2.99 3-5.1 6.7-6.17 10.71-1.51 5.66-2.73 11.38-4.77 16.87l-17.39 46.85c-13.76 3-28 4.69-42.65 4.69v-27.38c1.69-12.62-7.64-36.26-22.63-51.25-6-6-9.37-14.14-9.37-22.63v-32.01c0-11.64-6.27-22.34-16.46-27.97-14.37-7.95-34.81-19.06-48.81-26.11-11.48-5.78-22.1-13.14-31.65-21.75l-.8-.72a114.792 114.792 0 0 1-18.06-20.74c-9.38-13.77-24.66-36.42-34.59-51.14 20.47-45.5 57.36-82.04 103.2-101.89l24.01 12.01C203.48 89.74 216 82.01 216 70.11v-11.3c7.99-1.29 16.12-2.11 24.39-2.42l28.3 28.3c6.25 6.25 6.25 16.38 0 22.63L264 112l-10.34 10.34c-3.12 3.12-3.12 8.19 0 11.31l4.69 4.69c3.12 3.12 3.12 8.19 0 11.31l-8 8a8.008 8.008 0 0 1-5.66 2.34h-8.99c-2.08 0-4.08.81-5.58 2.27l-9.92 9.65a8.008 8.008 0 0 0-1.58 9.31l15.59 31.19c2.66 5.32-1.21 11.58-7.15 11.58h-5.64c-1.93 0-3.79-.7-5.24-1.96l-9.28-8.06a16.017 16.017 0 0 0-15.55-3.1l-31.17 10.39a11.95 11.95 0 0 0-8.17 11.34c0 4.53 2.56 8.66 6.61 10.69l11.08 5.54c9.41 4.71 19.79 7.16 30.31 7.16s22.59 27.29 32 32h66.75c8.49 0 16.62 3.37 22.63 9.37l13.69 13.69a30.503 30.503 0 0 1 8.93 21.57 46.536 46.536 0 0 1-13.72 32.98zM417 274.25c-5.79-1.45-10.84-5-14.15-9.97l-17.98-26.97a23.97 23.97 0 0 1 0-26.62l19.59-29.38c2.32-3.47 5.5-6.29 9.24-8.15l12.98-6.49C440.2 193.59 448 223.87 448 256c0 8.67-.74 17.16-1.82 25.54L417 274.25z\"]\n};\nvar faGlobeAsia = {\n prefix: 'fas',\n iconName: 'globe-asia',\n icon: [496, 512, [], \"f57e\", \"M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm-11.34 240.23c-2.89 4.82-8.1 7.77-13.72 7.77h-.31c-4.24 0-8.31 1.69-11.31 4.69l-5.66 5.66c-3.12 3.12-3.12 8.19 0 11.31l5.66 5.66c3 3 4.69 7.07 4.69 11.31V304c0 8.84-7.16 16-16 16h-6.11c-6.06 0-11.6-3.42-14.31-8.85l-22.62-45.23c-2.44-4.88-8.95-5.94-12.81-2.08l-19.47 19.46c-3 3-7.07 4.69-11.31 4.69H50.81C49.12 277.55 48 266.92 48 256c0-110.28 89.72-200 200-200 21.51 0 42.2 3.51 61.63 9.82l-50.16 38.53c-5.11 3.41-4.63 11.06.86 13.81l10.83 5.41c5.42 2.71 8.84 8.25 8.84 14.31V216c0 4.42-3.58 8-8 8h-3.06c-3.03 0-5.8-1.71-7.15-4.42-1.56-3.12-5.96-3.29-7.76-.3l-17.37 28.95zM408 358.43c0 4.24-1.69 8.31-4.69 11.31l-9.57 9.57c-3 3-7.07 4.69-11.31 4.69h-15.16c-4.24 0-8.31-1.69-11.31-4.69l-13.01-13.01a26.767 26.767 0 0 0-25.42-7.04l-21.27 5.32c-1.27.32-2.57.48-3.88.48h-10.34c-4.24 0-8.31-1.69-11.31-4.69l-11.91-11.91a8.008 8.008 0 0 1-2.34-5.66v-10.2c0-3.27 1.99-6.21 5.03-7.43l39.34-15.74c1.98-.79 3.86-1.82 5.59-3.05l23.71-16.89a7.978 7.978 0 0 1 4.64-1.48h12.09c3.23 0 6.15 1.94 7.39 4.93l5.35 12.85a4 4 0 0 0 3.69 2.46h3.8c1.78 0 3.35-1.18 3.84-2.88l4.2-14.47c.5-1.71 2.06-2.88 3.84-2.88h6.06c2.21 0 4 1.79 4 4v12.93c0 2.12.84 4.16 2.34 5.66l11.91 11.91c3 3 4.69 7.07 4.69 11.31v24.6z\"]\n};\nvar faGlobeEurope = {\n prefix: 'fas',\n iconName: 'globe-europe',\n icon: [496, 512, [], \"f7a2\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm200 248c0 22.5-3.9 44.2-10.8 64.4h-20.3c-4.3 0-8.4-1.7-11.4-4.8l-32-32.6c-4.5-4.6-4.5-12.1.1-16.7l12.5-12.5v-8.7c0-3-1.2-5.9-3.3-8l-9.4-9.4c-2.1-2.1-5-3.3-8-3.3h-16c-6.2 0-11.3-5.1-11.3-11.3 0-3 1.2-5.9 3.3-8l9.4-9.4c2.1-2.1 5-3.3 8-3.3h32c6.2 0 11.3-5.1 11.3-11.3v-9.4c0-6.2-5.1-11.3-11.3-11.3h-36.7c-8.8 0-16 7.2-16 16v4.5c0 6.9-4.4 13-10.9 15.2l-31.6 10.5c-3.3 1.1-5.5 4.1-5.5 7.6v2.2c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8s-3.6-8-8-8H247c-3 0-5.8 1.7-7.2 4.4l-9.4 18.7c-2.7 5.4-8.2 8.8-14.3 8.8H194c-8.8 0-16-7.2-16-16V199c0-4.2 1.7-8.3 4.7-11.3l20.1-20.1c4.6-4.6 7.2-10.9 7.2-17.5 0-3.4 2.2-6.5 5.5-7.6l40-13.3c1.7-.6 3.2-1.5 4.4-2.7l26.8-26.8c2.1-2.1 3.3-5 3.3-8 0-6.2-5.1-11.3-11.3-11.3H258l-16 16v8c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8v-20c0-2.5 1.2-4.9 3.2-6.4l28.9-21.7c1.9-.1 3.8-.3 5.7-.3C358.3 56 448 145.7 448 256zM130.1 149.1c0-3 1.2-5.9 3.3-8l25.4-25.4c2.1-2.1 5-3.3 8-3.3 6.2 0 11.3 5.1 11.3 11.3v16c0 3-1.2 5.9-3.3 8l-9.4 9.4c-2.1 2.1-5 3.3-8 3.3h-16c-6.2 0-11.3-5.1-11.3-11.3zm128 306.4v-7.1c0-8.8-7.2-16-16-16h-20.2c-10.8 0-26.7-5.3-35.4-11.8l-22.2-16.7c-11.5-8.6-18.2-22.1-18.2-36.4v-23.9c0-16 8.4-30.8 22.1-39l42.9-25.7c7.1-4.2 15.2-6.5 23.4-6.5h31.2c10.9 0 21.4 3.9 29.6 10.9l43.2 37.1h18.3c8.5 0 16.6 3.4 22.6 9.4l17.3 17.3c3.4 3.4 8.1 5.3 12.9 5.3H423c-32.4 58.9-93.8 99.5-164.9 103.1z\"]\n};\nvar faGolfBall = {\n prefix: 'fas',\n iconName: 'golf-ball',\n icon: [416, 512, [], \"f450\", \"M96 416h224c0 17.7-14.3 32-32 32h-16c-17.7 0-32 14.3-32 32v20c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-20c0-17.7-14.3-32-32-32h-16c-17.7 0-32-14.3-32-32zm320-208c0 74.2-39 139.2-97.5 176h-221C39 347.2 0 282.2 0 208 0 93.1 93.1 0 208 0s208 93.1 208 208zm-180.1 43.9c18.3 0 33.1-14.8 33.1-33.1 0-14.4-9.3-26.3-22.1-30.9 9.6 26.8-15.6 51.3-41.9 41.9 4.6 12.8 16.5 22.1 30.9 22.1zm49.1 46.9c0-14.4-9.3-26.3-22.1-30.9 9.6 26.8-15.6 51.3-41.9 41.9 4.6 12.8 16.5 22.1 30.9 22.1 18.3 0 33.1-14.9 33.1-33.1zm64-64c0-14.4-9.3-26.3-22.1-30.9 9.6 26.8-15.6 51.3-41.9 41.9 4.6 12.8 16.5 22.1 30.9 22.1 18.3 0 33.1-14.9 33.1-33.1z\"]\n};\nvar faGopuram = {\n prefix: 'fas',\n iconName: 'gopuram',\n icon: [512, 512, [], \"f664\", \"M496 352h-16V240c0-8.8-7.2-16-16-16h-16v-80c0-8.8-7.2-16-16-16h-16V16c0-8.8-7.2-16-16-16s-16 7.2-16 16v16h-64V16c0-8.8-7.2-16-16-16s-16 7.2-16 16v16h-64V16c0-8.8-7.2-16-16-16s-16 7.2-16 16v16h-64V16c0-8.8-7.2-16-16-16S96 7.2 96 16v112H80c-8.8 0-16 7.2-16 16v80H48c-8.8 0-16 7.2-16 16v112H16c-8.8 0-16 7.2-16 16v128c0 8.8 7.2 16 16 16h80V352h32V224h32v-96h32v96h-32v128h-32v160h80v-80c0-8.8 7.2-16 16-16h64c8.8 0 16 7.2 16 16v80h80V352h-32V224h-32v-96h32v96h32v128h32v160h80c8.8 0 16-7.2 16-16V368c0-8.8-7.2-16-16-16zM232 176c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v48h-48zm56 176h-64v-64c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16z\"]\n};\nvar faGraduationCap = {\n prefix: 'fas',\n iconName: 'graduation-cap',\n icon: [640, 512, [], \"f19d\", \"M622.34 153.2L343.4 67.5c-15.2-4.67-31.6-4.67-46.79 0L17.66 153.2c-23.54 7.23-23.54 38.36 0 45.59l48.63 14.94c-10.67 13.19-17.23 29.28-17.88 46.9C38.78 266.15 32 276.11 32 288c0 10.78 5.68 19.85 13.86 25.65L20.33 428.53C18.11 438.52 25.71 448 35.94 448h56.11c10.24 0 17.84-9.48 15.62-19.47L82.14 313.65C90.32 307.85 96 298.78 96 288c0-11.57-6.47-21.25-15.66-26.87.76-15.02 8.44-28.3 20.69-36.72L296.6 284.5c9.06 2.78 26.44 6.25 46.79 0l278.95-85.7c23.55-7.24 23.55-38.36 0-45.6zM352.79 315.09c-28.53 8.76-52.84 3.92-65.59 0l-145.02-44.55L128 384c0 35.35 85.96 64 192 64s192-28.65 192-64l-14.18-113.47-145.03 44.56z\"]\n};\nvar faGreaterThan = {\n prefix: 'fas',\n iconName: 'greater-than',\n icon: [384, 512, [], \"f531\", \"M365.52 209.85L59.22 67.01c-16.06-7.49-35.15-.54-42.64 15.52L3.01 111.61c-7.49 16.06-.54 35.15 15.52 42.64L236.96 256.1 18.49 357.99C2.47 365.46-4.46 384.5 3.01 400.52l13.52 29C24 445.54 43.04 452.47 59.06 445l306.47-142.91a32.003 32.003 0 0 0 18.48-29v-34.23c-.01-12.45-7.21-23.76-18.49-29.01z\"]\n};\nvar faGreaterThanEqual = {\n prefix: 'fas',\n iconName: 'greater-than-equal',\n icon: [448, 512, [], \"f532\", \"M55.22 107.69l175.56 68.09-175.44 68.05c-18.39 6.03-27.88 24.39-21.2 41l12.09 30.08c6.68 16.61 26.99 25.19 45.38 19.15L393.02 214.2c13.77-4.52 22.98-16.61 22.98-30.17v-15.96c0-13.56-9.21-25.65-22.98-30.17L91.3 17.92c-18.29-6-38.51 2.53-45.15 19.06L34.12 66.9c-6.64 16.53 2.81 34.79 21.1 40.79zM424 400H24c-13.25 0-24 10.74-24 24v48c0 13.25 10.75 24 24 24h400c13.25 0 24-10.75 24-24v-48c0-13.26-10.75-24-24-24z\"]\n};\nvar faGrimace = {\n prefix: 'fas',\n iconName: 'grimace',\n icon: [496, 512, [], \"f57f\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM144 400h-8c-17.7 0-32-14.3-32-32v-8h40v40zm0-56h-40v-8c0-17.7 14.3-32 32-32h8v40zm-8-136c0-17.7 14.3-32 32-32s32 14.3 32 32-14.3 32-32 32-32-14.3-32-32zm72 192h-48v-40h48v40zm0-56h-48v-40h48v40zm64 56h-48v-40h48v40zm0-56h-48v-40h48v40zm64 56h-48v-40h48v40zm0-56h-48v-40h48v40zm-8-104c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm64 128c0 17.7-14.3 32-32 32h-8v-40h40v8zm0-24h-40v-40h8c17.7 0 32 14.3 32 32v8z\"]\n};\nvar faGrin = {\n prefix: 'fas',\n iconName: 'grin',\n icon: [496, 512, [], \"f580\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm80 256c-60.6 0-134.5-38.3-143.8-93.3-2-11.8 9.3-21.6 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.3-3.7 22.6 6.1 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3z\"]\n};\nvar faGrinAlt = {\n prefix: 'fas',\n iconName: 'grin-alt',\n icon: [496, 512, [], \"f581\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm63.7 128.7c7.6-11.4 24.7-11.7 32.7 0 12.4 18.4 15.1 36.9 15.7 55.3-.5 18.4-3.3 36.9-15.7 55.3-7.6 11.4-24.7 11.7-32.7 0-12.4-18.4-15.1-36.9-15.7-55.3.5-18.4 3.3-36.9 15.7-55.3zm-160 0c7.6-11.4 24.7-11.7 32.7 0 12.4 18.4 15.1 36.9 15.7 55.3-.5 18.4-3.3 36.9-15.7 55.3-7.6 11.4-24.7 11.7-32.7 0-12.4-18.4-15.1-36.9-15.7-55.3.5-18.4 3.3-36.9 15.7-55.3zM248 432c-60.6 0-134.5-38.3-143.8-93.3-2-11.8 9.3-21.6 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.4-3.7 22.6 6.1 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3z\"]\n};\nvar faGrinBeam = {\n prefix: 'fas',\n iconName: 'grin-beam',\n icon: [496, 512, [], \"f582\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 144c23.8 0 52.7 29.3 56 71.4.7 8.6-10.8 11.9-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.1 7.3-15.6 4-14.9-4.5 3.1-42.1 32-71.4 55.8-71.4zm-160 0c23.8 0 52.7 29.3 56 71.4.7 8.6-10.8 11.9-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.2 7.4-15.6 4-14.9-4.5 3.1-42.1 32-71.4 55.8-71.4zm80 280c-60.6 0-134.5-38.3-143.8-93.3-2-11.9 9.4-21.6 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.4-3.7 22.6 6.1 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3z\"]\n};\nvar faGrinBeamSweat = {\n prefix: 'fas',\n iconName: 'grin-beam-sweat',\n icon: [504, 512, [], \"f583\", \"M456 128c26.5 0 48-21 48-47 0-20-28.5-60.4-41.6-77.8-3.2-4.3-9.6-4.3-12.8 0C436.5 20.6 408 61 408 81c0 26 21.5 47 48 47zm0 32c-44.1 0-80-35.4-80-79 0-4.4.3-14.2 8.1-32.2C345 23.1 298.3 8 248 8 111 8 0 119 0 256s111 248 248 248 248-111 248-248c0-35.1-7.4-68.4-20.5-98.6-6.3 1.5-12.7 2.6-19.5 2.6zm-128-8c23.8 0 52.7 29.3 56 71.4.7 8.6-10.8 12-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.1 7.4-15.6 4-14.9-4.5 3.1-42.1 32-71.4 55.8-71.4zm-160 0c23.8 0 52.7 29.3 56 71.4.7 8.6-10.8 12-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.2 7.4-15.6 4-14.9-4.5 3.1-42.1 32-71.4 55.8-71.4zm80 280c-60.6 0-134.5-38.3-143.8-93.3-2-11.8 9.3-21.6 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.5-3.7 22.6 6.2 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3z\"]\n};\nvar faGrinHearts = {\n prefix: 'fas',\n iconName: 'grin-hearts',\n icon: [496, 512, [], \"f584\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM90.4 183.6c6.7-17.6 26.7-26.7 44.9-21.9l7.1 1.9 2-7.1c5-18.1 22.8-30.9 41.5-27.9 21.4 3.4 34.4 24.2 28.8 44.5L195.3 243c-1.2 4.5-5.9 7.2-10.5 6l-70.2-18.2c-20.4-5.4-31.9-27-24.2-47.2zM248 432c-60.6 0-134.5-38.3-143.8-93.3-2-11.8 9.2-21.5 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.4-3.6 22.6 6.1 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3zm133.4-201.3l-70.2 18.2c-4.5 1.2-9.2-1.5-10.5-6L281.3 173c-5.6-20.3 7.4-41.1 28.8-44.5 18.6-3 36.4 9.8 41.5 27.9l2 7.1 7.1-1.9c18.2-4.7 38.2 4.3 44.9 21.9 7.7 20.3-3.8 41.9-24.2 47.2z\"]\n};\nvar faGrinSquint = {\n prefix: 'fas',\n iconName: 'grin-squint',\n icon: [496, 512, [], \"f585\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm33.8 189.7l80-48c11.6-6.9 24 7.7 15.4 18L343.6 208l33.6 40.3c8.7 10.4-3.9 24.8-15.4 18l-80-48c-7.7-4.7-7.7-15.9 0-20.6zm-163-30c-8.6-10.3 3.8-24.9 15.4-18l80 48c7.8 4.7 7.8 15.9 0 20.6l-80 48c-11.5 6.8-24-7.6-15.4-18l33.6-40.3-33.6-40.3zM248 432c-60.6 0-134.5-38.3-143.8-93.3-2-11.9 9.4-21.6 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.5-3.7 22.6 6.2 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3z\"]\n};\nvar faGrinSquintTears = {\n prefix: 'fas',\n iconName: 'grin-squint-tears',\n icon: [512, 512, [], \"f586\", \"M409.6 111.9c22.6-3.2 73.5-12 88.3-26.8 19.2-19.2 18.9-50.6-.7-70.2S446-5 426.9 14.2c-14.8 14.8-23.5 65.7-26.8 88.3-.8 5.5 3.9 10.2 9.5 9.4zM102.4 400.1c-22.6 3.2-73.5 12-88.3 26.8-19.1 19.1-18.8 50.6.8 70.2s51 19.9 70.2.7c14.8-14.8 23.5-65.7 26.8-88.3.8-5.5-3.9-10.2-9.5-9.4zm311.7-256.5c-33 3.9-48.6-25.1-45.7-45.7 3.4-24 7.4-42.1 11.5-56.5C285.1-13.4 161.8-.5 80.6 80.6-.5 161.7-13.4 285 41.4 379.9c14.4-4.1 32.4-8 56.5-11.5 33.2-3.9 48.6 25.2 45.7 45.7-3.4 24-7.4 42.1-11.5 56.5 94.8 54.8 218.1 41.9 299.3-39.2s94-204.4 39.2-299.3c-14.4 4.1-32.5 8-56.5 11.5zM255.7 106c3.3-13.2 22.4-11.5 23.6 1.8l4.8 52.3 52.3 4.8c13.4 1.2 14.9 20.3 1.8 23.6l-90.5 22.6c-8.9 2.2-16.7-5.9-14.5-14.5l22.5-90.6zm-90.9 230.3L160 284l-52.3-4.8c-13.4-1.2-14.9-20.3-1.8-23.6l90.5-22.6c8.8-2.2 16.7 5.8 14.5 14.5L188.3 338c-3.1 13.2-22.2 11.7-23.5-1.7zm215.7 44.2c-29.3 29.3-75.7 50.4-116.7 50.4-18.9 0-36.6-4.5-51-14.7-9.8-6.9-8.7-21.8 2-27.2 28.3-14.6 63.9-42.4 97.8-76.3s61.7-69.6 76.3-97.8c5.4-10.5 20.2-11.9 27.3-2 32.3 45.3 7.1 124.7-35.7 167.6z\"]\n};\nvar faGrinStars = {\n prefix: 'fas',\n iconName: 'grin-stars',\n icon: [496, 512, [], \"f587\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM94.6 168.9l34.9-5 15.5-31.6c2.9-5.8 11-5.8 13.9 0l15.5 31.6 34.9 5c6.2 1 8.9 8.6 4.3 13.2l-25.4 24.6 6 34.9c1 6.2-5.3 11-11 7.9L152 233.3l-31.3 16.3c-5.7 3.1-12-1.7-11-7.9l6-34.9-25.4-24.6c-4.6-4.7-1.9-12.3 4.3-13.3zM248 432c-60.6 0-134.5-38.3-143.8-93.3-2-11.8 9.3-21.5 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.5-3.7 22.6 6.1 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3zm157.7-249.9l-25.4 24.6 6 34.9c1 6.2-5.3 11-11 7.9L344 233.3l-31.3 16.3c-5.7 3.1-12-1.7-11-7.9l6-34.9-25.4-24.6c-4.5-4.6-1.9-12.2 4.3-13.2l34.9-5 15.5-31.6c2.9-5.8 11-5.8 13.9 0l15.5 31.6 34.9 5c6.3.9 9 8.5 4.4 13.1z\"]\n};\nvar faGrinTears = {\n prefix: 'fas',\n iconName: 'grin-tears',\n icon: [640, 512, [], \"f588\", \"M102.4 256.1c-22.6 3.2-73.5 12-88.3 26.8-19.1 19.1-18.8 50.6.8 70.2s51 19.9 70.2.7c14.8-14.8 23.5-65.7 26.8-88.3.8-5.5-3.9-10.2-9.5-9.4zm523.4 26.8c-14.8-14.8-65.7-23.5-88.3-26.8-5.5-.8-10.3 3.9-9.5 9.5 3.2 22.6 12 73.5 26.8 88.3 19.2 19.2 50.6 18.9 70.2-.7s20-51.2.8-70.3zm-129.4-12.8c-3.8-26.6 19.1-49.5 45.7-45.7 8.9 1.3 16.8 2.7 24.3 4.1C552.7 104.5 447.7 8 320 8S87.3 104.5 73.6 228.5c7.5-1.4 15.4-2.8 24.3-4.1 33.2-3.9 48.6 25.3 45.7 45.7-11.8 82.3-29.9 100.4-35.8 106.4-.9.9-2 1.6-3 2.5 42.7 74.6 123 125 215.2 125s172.5-50.4 215.2-125.1c-1-.9-2.1-1.5-3-2.5-5.9-5.9-24-24-35.8-106.3zM400 152c23.8 0 52.7 29.3 56 71.4.7 8.6-10.8 12-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.2 7.4-15.6 4-14.9-4.5 3.1-42.1 32-71.4 55.8-71.4zm-160 0c23.8 0 52.7 29.3 56 71.4.7 8.6-10.8 12-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.2 7.4-15.6 4-14.9-4.5 3.1-42.1 32-71.4 55.8-71.4zm80 280c-60.6 0-134.5-38.3-143.8-93.3-2-11.7 9.2-21.6 20.7-17.9C227.1 330.5 272 336 320 336s92.9-5.5 123.1-15.2c11.4-3.7 22.6 6.1 20.7 17.9-9.3 55-83.2 93.3-143.8 93.3z\"]\n};\nvar faGrinTongue = {\n prefix: 'fas',\n iconName: 'grin-tongue',\n icon: [496, 512, [], \"f589\", \"M248 8C111 8 0 119 0 256c0 106.3 67 196.7 161 232-5.6-12.2-9-25.7-9-40v-45.5c-24.7-16.2-43.5-38.1-47.8-63.8-2-11.8 9.3-21.5 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.4-3.6 22.6 6.1 20.7 17.9-4.3 25.7-23.1 47.6-47.8 63.8V448c0 14.3-3.4 27.8-9 40 94-35.3 161-125.7 161-232C496 119 385 8 248 8zm-80 232c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm160 0c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm-34.9 134.6c-14.4-6.5-31.1 2.2-34.6 17.6l-1.8 7.8c-2.1 9.2-15.2 9.2-17.3 0l-1.8-7.8c-3.5-15.4-20.2-24.1-34.6-17.6-.9.4.3-.2-18.9 9.4v63c0 35.2 28 64.5 63.1 64.9 35.7.5 64.9-28.4 64.9-64v-64c-19.5-9.6-18.2-8.9-19-9.3z\"]\n};\nvar faGrinTongueSquint = {\n prefix: 'fas',\n iconName: 'grin-tongue-squint',\n icon: [496, 512, [], \"f58a\", \"M293.1 374.6c-14.4-6.5-31.1 2.2-34.6 17.6l-1.8 7.8c-2.1 9.2-15.2 9.2-17.3 0l-1.8-7.8c-3.5-15.4-20.2-24.1-34.6-17.6-.9.4.3-.2-18.9 9.4v63c0 35.2 28 64.5 63.1 64.9 35.7.5 64.9-28.4 64.9-64v-64c-19.5-9.6-18.2-8.9-19-9.3zM248 8C111 8 0 119 0 256c0 106.3 67 196.7 161 232-5.6-12.2-9-25.7-9-40v-45.5c-24.7-16.2-43.5-38.1-47.8-63.8-2-11.8 9.2-21.5 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.4-3.7 22.6 6.1 20.7 17.9-4.3 25.7-23.1 47.6-47.8 63.8V448c0 14.3-3.4 27.8-9 40 94-35.3 161-125.7 161-232C496 119 385 8 248 8zm-33.8 210.3l-80 48c-11.5 6.8-24-7.6-15.4-18l33.6-40.3-33.6-40.3c-8.6-10.3 3.8-24.9 15.4-18l80 48c7.7 4.7 7.7 15.9 0 20.6zm163 30c8.7 10.4-3.9 24.8-15.4 18l-80-48c-7.8-4.7-7.8-15.9 0-20.6l80-48c11.7-6.9 23.9 7.7 15.4 18L343.6 208l33.6 40.3z\"]\n};\nvar faGrinTongueWink = {\n prefix: 'fas',\n iconName: 'grin-tongue-wink',\n icon: [496, 512, [], \"f58b\", \"M344 184c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zM248 8C111 8 0 119 0 256c0 106.3 67 196.7 161 232-5.6-12.2-9-25.7-9-40v-45.5c-24.7-16.2-43.5-38.1-47.8-63.8-2-11.8 9.3-21.5 20.7-17.9C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.5-3.7 22.6 6.1 20.7 17.9-4.3 25.7-23.1 47.6-47.8 63.8V448c0 14.3-3.4 27.8-9 40 94-35.3 161-125.7 161-232C496 119 385 8 248 8zm-56 225l-9.5-8.5c-14.8-13.2-46.2-13.2-61 0L112 233c-8.5 7.4-21.6.3-19.8-10.8 4-25.2 34.2-42.1 59.9-42.1S208 197 212 222.2c1.6 11.1-11.6 18.2-20 10.8zm152 39c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64zm-50.9 102.6c-14.4-6.5-31.1 2.2-34.6 17.6l-1.8 7.8c-2.1 9.2-15.2 9.2-17.3 0l-1.8-7.8c-3.5-15.4-20.2-24.1-34.6-17.6-.9.4.3-.2-18.9 9.4v63c0 35.2 28 64.5 63.1 64.9 35.7.5 64.9-28.4 64.9-64v-64c-19.5-9.6-18.2-8.9-19-9.3z\"]\n};\nvar faGrinWink = {\n prefix: 'fas',\n iconName: 'grin-wink',\n icon: [496, 512, [], \"f58c\", \"M0 256c0 137 111 248 248 248s248-111 248-248S385 8 248 8 0 119 0 256zm200-48c0 17.7-14.3 32-32 32s-32-14.3-32-32 14.3-32 32-32 32 14.3 32 32zm168 25l-9.5-8.5c-14.8-13.2-46.2-13.2-61 0L288 233c-8.3 7.4-21.6.4-19.8-10.8 4-25.2 34.2-42.1 59.9-42.1S384 197 388 222.2c1.6 11-11.5 18.2-20 10.8zm-243.1 87.8C155.1 330.5 200 336 248 336s92.9-5.5 123.1-15.2c11.3-3.7 22.6 6 20.7 17.9-9.2 55-83.2 93.3-143.8 93.3s-134.5-38.3-143.8-93.3c-2-11.9 9.3-21.6 20.7-17.9z\"]\n};\nvar faGripHorizontal = {\n prefix: 'fas',\n iconName: 'grip-horizontal',\n icon: [448, 512, [], \"f58d\", \"M96 288H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zM96 96H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32z\"]\n};\nvar faGripLines = {\n prefix: 'fas',\n iconName: 'grip-lines',\n icon: [512, 512, [], \"f7a4\", \"M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z\"]\n};\nvar faGripLinesVertical = {\n prefix: 'fas',\n iconName: 'grip-lines-vertical',\n icon: [256, 512, [], \"f7a5\", \"M96 496V16c0-8.8-7.2-16-16-16H48c-8.8 0-16 7.2-16 16v480c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16zm128 0V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v480c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16z\"]\n};\nvar faGripVertical = {\n prefix: 'fas',\n iconName: 'grip-vertical',\n icon: [320, 512, [], \"f58e\", \"M96 32H32C14.33 32 0 46.33 0 64v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32V64c0-17.67-14.33-32-32-32zm0 160H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm0 160H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zM288 32h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32V64c0-17.67-14.33-32-32-32zm0 160h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm0 160h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32z\"]\n};\nvar faGuitar = {\n prefix: 'fas',\n iconName: 'guitar',\n icon: [512, 512, [], \"f7a6\", \"M502.6 54.6L457.4 9.4c-12.5-12.5-32.8-12.5-45.3 0l-67.9 67.9c-12.5 12.5-12.5 32.8 0 45.3L290 176.7c-45.4-29-100.4-28.9-133.5 4.2-9.7 9.7-16.4 21.2-20.5 33.9-6.1 18.8-23.5 33.1-42.7 34.9-24 2.3-46.3 11.6-63.4 28.8C-16.3 324.6-8 407.6 48.2 463.8c56.2 56.2 139.2 64.4 185.3 18.3 17.2-17.1 26.5-39.4 28.8-63.5 1.8-19.1 16.1-36.6 34.9-42.7 12.7-4.1 24.2-10.8 33.9-20.5 33.1-33.1 33.1-88.1 4.2-133.5l54.2-54.2c12.5 12.5 32.8 12.5 45.3 0l67.9-67.9c12.4-12.4 12.4-32.7-.1-45.2zM208 352c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z\"]\n};\nvar faHSquare = {\n prefix: 'fas',\n iconName: 'h-square',\n icon: [448, 512, [], \"f0fd\", \"M448 80v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48zm-112 48h-32c-8.837 0-16 7.163-16 16v80H160v-80c0-8.837-7.163-16-16-16h-32c-8.837 0-16 7.163-16 16v224c0 8.837 7.163 16 16 16h32c8.837 0 16-7.163 16-16v-80h128v80c0 8.837 7.163 16 16 16h32c8.837 0 16-7.163 16-16V144c0-8.837-7.163-16-16-16z\"]\n};\nvar faHamburger = {\n prefix: 'fas',\n iconName: 'hamburger',\n icon: [512, 512, [], \"f805\", \"M464 256H48a48 48 0 0 0 0 96h416a48 48 0 0 0 0-96zm16 128H32a16 16 0 0 0-16 16v16a64 64 0 0 0 64 64h352a64 64 0 0 0 64-64v-16a16 16 0 0 0-16-16zM58.64 224h394.72c34.57 0 54.62-43.9 34.82-75.88C448 83.2 359.55 32.1 256 32c-103.54.1-192 51.2-232.18 116.11C4 180.09 24.07 224 58.64 224zM384 112a16 16 0 1 1-16 16 16 16 0 0 1 16-16zM256 80a16 16 0 1 1-16 16 16 16 0 0 1 16-16zm-128 32a16 16 0 1 1-16 16 16 16 0 0 1 16-16z\"]\n};\nvar faHammer = {\n prefix: 'fas',\n iconName: 'hammer',\n icon: [576, 512, [], \"f6e3\", \"M571.31 193.94l-22.63-22.63c-6.25-6.25-16.38-6.25-22.63 0l-11.31 11.31-28.9-28.9c5.63-21.31.36-44.9-16.35-61.61l-45.25-45.25c-62.48-62.48-163.79-62.48-226.28 0l90.51 45.25v18.75c0 16.97 6.74 33.25 18.75 45.25l49.14 49.14c16.71 16.71 40.3 21.98 61.61 16.35l28.9 28.9-11.31 11.31c-6.25 6.25-6.25 16.38 0 22.63l22.63 22.63c6.25 6.25 16.38 6.25 22.63 0l90.51-90.51c6.23-6.24 6.23-16.37-.02-22.62zm-286.72-15.2c-3.7-3.7-6.84-7.79-9.85-11.95L19.64 404.96c-25.57 23.88-26.26 64.19-1.53 88.93s65.05 24.05 88.93-1.53l238.13-255.07c-3.96-2.91-7.9-5.87-11.44-9.41l-49.14-49.14z\"]\n};\nvar faHamsa = {\n prefix: 'fas',\n iconName: 'hamsa',\n icon: [512, 512, [], \"f665\", \"M509.34 307.25C504.28 295.56 492.75 288 480 288h-64V80c0-22-18-40-40-40s-40 18-40 40v134c0 5.52-4.48 10-10 10h-20c-5.52 0-10-4.48-10-10V40c0-22-18-40-40-40s-40 18-40 40v174c0 5.52-4.48 10-10 10h-20c-5.52 0-10-4.48-10-10V80c0-22-18-40-40-40S96 58 96 80v208H32c-12.75 0-24.28 7.56-29.34 19.25a31.966 31.966 0 0 0 5.94 34.58l102.69 110.03C146.97 490.08 199.69 512 256 512s109.03-21.92 144.72-60.14L503.4 341.83a31.966 31.966 0 0 0 5.94-34.58zM256 416c-53.02 0-96-64-96-64s42.98-64 96-64 96 64 96 64-42.98 64-96 64zm0-96c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32z\"]\n};\nvar faHandHolding = {\n prefix: 'fas',\n iconName: 'hand-holding',\n icon: [576, 512, [], \"f4bd\", \"M565.3 328.1c-11.8-10.7-30.2-10-42.6 0L430.3 402c-11.3 9.1-25.4 14-40 14H272c-8.8 0-16-7.2-16-16s7.2-16 16-16h78.3c15.9 0 30.7-10.9 33.3-26.6 3.3-20-12.1-37.4-31.6-37.4H192c-27 0-53.1 9.3-74.1 26.3L71.4 384H16c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16h356.8c14.5 0 28.6-4.9 40-14L564 377c15.2-12.1 16.4-35.3 1.3-48.9z\"]\n};\nvar faHandHoldingHeart = {\n prefix: 'fas',\n iconName: 'hand-holding-heart',\n icon: [576, 512, [], \"f4be\", \"M275.3 250.5c7 7.4 18.4 7.4 25.5 0l108.9-114.2c31.6-33.2 29.8-88.2-5.6-118.8-30.8-26.7-76.7-21.9-104.9 7.7L288 36.9l-11.1-11.6C248.7-4.4 202.8-9.2 172 17.5c-35.3 30.6-37.2 85.6-5.6 118.8l108.9 114.2zm290 77.6c-11.8-10.7-30.2-10-42.6 0L430.3 402c-11.3 9.1-25.4 14-40 14H272c-8.8 0-16-7.2-16-16s7.2-16 16-16h78.3c15.9 0 30.7-10.9 33.3-26.6 3.3-20-12.1-37.4-31.6-37.4H192c-27 0-53.1 9.3-74.1 26.3L71.4 384H16c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16h356.8c14.5 0 28.6-4.9 40-14L564 377c15.2-12.1 16.4-35.3 1.3-48.9z\"]\n};\nvar faHandHoldingUsd = {\n prefix: 'fas',\n iconName: 'hand-holding-usd',\n icon: [544, 512, [], \"f4c0\", \"M257.6 144.3l50 14.3c3.6 1 6.1 4.4 6.1 8.1 0 4.6-3.8 8.4-8.4 8.4h-32.8c-3.6 0-7.1-.8-10.3-2.2-4.8-2.2-10.4-1.7-14.1 2l-17.5 17.5c-5.3 5.3-4.7 14.3 1.5 18.4 9.5 6.3 20.3 10.1 31.8 11.5V240c0 8.8 7.2 16 16 16h16c8.8 0 16-7.2 16-16v-17.6c30.3-3.6 53.3-31 49.3-63-2.9-23-20.7-41.3-42.9-47.7l-50-14.3c-3.6-1-6.1-4.4-6.1-8.1 0-4.6 3.8-8.4 8.4-8.4h32.8c3.6 0 7.1.8 10.3 2.2 4.8 2.2 10.4 1.7 14.1-2l17.5-17.5c5.3-5.3 4.7-14.3-1.5-18.4-9.5-6.3-20.3-10.1-31.8-11.5V16c0-8.8-7.2-16-16-16h-16c-8.8 0-16 7.2-16 16v17.6c-30.3 3.6-53.3 31-49.3 63 2.9 23 20.7 41.3 42.9 47.7zm276.3 183.8c-11.2-10.7-28.5-10-40.3 0L406.4 402c-10.7 9.1-24 14-37.8 14H256.9c-8.3 0-15.1-7.2-15.1-16s6.8-16 15.1-16h73.9c15.1 0 29-10.9 31.4-26.6 3.1-20-11.5-37.4-29.8-37.4H181.3c-25.5 0-50.2 9.3-69.9 26.3L67.5 384H15.1C6.8 384 0 391.2 0 400v96c0 8.8 6.8 16 15.1 16H352c13.7 0 27-4.9 37.8-14l142.8-121c14.4-12.1 15.5-35.3 1.3-48.9z\"]\n};\nvar faHandLizard = {\n prefix: 'fas',\n iconName: 'hand-lizard',\n icon: [576, 512, [], \"f258\", \"M384 480h192V363.778a95.998 95.998 0 0 0-14.833-51.263L398.127 54.368A48 48 0 0 0 357.544 32H24C10.745 32 0 42.745 0 56v16c0 30.928 25.072 56 56 56h229.981c12.844 0 21.556 13.067 16.615 24.923l-21.41 51.385A32 32 0 0 1 251.648 224H128c-35.346 0-64 28.654-64 64v8c0 13.255 10.745 24 24 24h147.406a47.995 47.995 0 0 1 25.692 7.455l111.748 70.811A24.001 24.001 0 0 1 384 418.539V480z\"]\n};\nvar faHandMiddleFinger = {\n prefix: 'fas',\n iconName: 'hand-middle-finger',\n icon: [512, 512, [], \"f806\", \"M479.93 317.12a37.33 37.33 0 0 0-28.28-36.19L416 272v-49.59c0-11.44-9.69-21.29-23.15-23.54l-38.4-6.4C336.63 189.5 320 200.86 320 216v32a8 8 0 0 1-16 0V50c0-26.28-20.25-49.2-46.52-50A48 48 0 0 0 208 48v200a8 8 0 0 1-16 0v-32c0-15.15-16.63-26.51-34.45-23.54l-30.68 5.12c-18 3-30.87 16.12-30.87 31.38V376a8 8 0 0 1-16 0v-76l-27.36 15A37.34 37.34 0 0 0 32 348.4v73.47a37.31 37.31 0 0 0 10.93 26.39l30.93 30.93A112 112 0 0 0 153.05 512h215A112 112 0 0 0 480 400z\"]\n};\nvar faHandPaper = {\n prefix: 'fas',\n iconName: 'hand-paper',\n icon: [448, 512, [], \"f256\", \"M408.781 128.007C386.356 127.578 368 146.36 368 168.79V256h-8V79.79c0-22.43-18.356-41.212-40.781-40.783C297.488 39.423 280 57.169 280 79v177h-8V40.79C272 18.36 253.644-.422 231.219.007 209.488.423 192 18.169 192 40v216h-8V80.79c0-22.43-18.356-41.212-40.781-40.783C121.488 40.423 104 58.169 104 80v235.992l-31.648-43.519c-12.993-17.866-38.009-21.817-55.877-8.823-17.865 12.994-21.815 38.01-8.822 55.877l125.601 172.705A48 48 0 0 0 172.073 512h197.59c22.274 0 41.622-15.324 46.724-37.006l26.508-112.66a192.011 192.011 0 0 0 5.104-43.975V168c.001-21.831-17.487-39.577-39.218-39.993z\"]\n};\nvar faHandPeace = {\n prefix: 'fas',\n iconName: 'hand-peace',\n icon: [448, 512, [], \"f25b\", \"M408 216c-22.092 0-40 17.909-40 40h-8v-32c0-22.091-17.908-40-40-40s-40 17.909-40 40v32h-8V48c0-26.51-21.49-48-48-48s-48 21.49-48 48v208h-13.572L92.688 78.449C82.994 53.774 55.134 41.63 30.461 51.324 5.787 61.017-6.356 88.877 3.337 113.551l74.765 190.342-31.09 24.872c-15.381 12.306-19.515 33.978-9.741 51.081l64 112A39.998 39.998 0 0 0 136 512h240c18.562 0 34.686-12.77 38.937-30.838l32-136A39.97 39.97 0 0 0 448 336v-80c0-22.091-17.908-40-40-40z\"]\n};\nvar faHandPointDown = {\n prefix: 'fas',\n iconName: 'hand-point-down',\n icon: [384, 512, [], \"f0a7\", \"M91.826 467.2V317.966c-8.248 5.841-16.558 10.57-24.918 14.153C35.098 345.752-.014 322.222 0 288c.008-18.616 10.897-32.203 29.092-40 28.286-12.122 64.329-78.648 77.323-107.534 7.956-17.857 25.479-28.453 43.845-28.464l.001-.002h171.526c11.812 0 21.897 8.596 23.703 20.269 7.25 46.837 38.483 61.76 38.315 123.731-.007 2.724.195 13.254.195 16 0 50.654-22.122 81.574-71.263 72.6-9.297 18.597-39.486 30.738-62.315 16.45-21.177 24.645-53.896 22.639-70.944 6.299V467.2c0 24.15-20.201 44.8-43.826 44.8-23.283 0-43.826-21.35-43.826-44.8zM112 72V24c0-13.255 10.745-24 24-24h192c13.255 0 24 10.745 24 24v48c0 13.255-10.745 24-24 24H136c-13.255 0-24-10.745-24-24zm212-24c0-11.046-8.954-20-20-20s-20 8.954-20 20 8.954 20 20 20 20-8.954 20-20z\"]\n};\nvar faHandPointLeft = {\n prefix: 'fas',\n iconName: 'hand-point-left',\n icon: [512, 512, [], \"f0a5\", \"M44.8 155.826h149.234c-5.841-8.248-10.57-16.558-14.153-24.918C166.248 99.098 189.778 63.986 224 64c18.616.008 32.203 10.897 40 29.092 12.122 28.286 78.648 64.329 107.534 77.323 17.857 7.956 28.453 25.479 28.464 43.845l.002.001v171.526c0 11.812-8.596 21.897-20.269 23.703-46.837 7.25-61.76 38.483-123.731 38.315-2.724-.007-13.254.195-16 .195-50.654 0-81.574-22.122-72.6-71.263-18.597-9.297-30.738-39.486-16.45-62.315-24.645-21.177-22.639-53.896-6.299-70.944H44.8c-24.15 0-44.8-20.201-44.8-43.826 0-23.283 21.35-43.826 44.8-43.826zM440 176h48c13.255 0 24 10.745 24 24v192c0 13.255-10.745 24-24 24h-48c-13.255 0-24-10.745-24-24V200c0-13.255 10.745-24 24-24zm24 212c11.046 0 20-8.954 20-20s-8.954-20-20-20-20 8.954-20 20 8.954 20 20 20z\"]\n};\nvar faHandPointRight = {\n prefix: 'fas',\n iconName: 'hand-point-right',\n icon: [512, 512, [], \"f0a4\", \"M512 199.652c0 23.625-20.65 43.826-44.8 43.826h-99.851c16.34 17.048 18.346 49.766-6.299 70.944 14.288 22.829 2.147 53.017-16.45 62.315C353.574 425.878 322.654 448 272 448c-2.746 0-13.276-.203-16-.195-61.971.168-76.894-31.065-123.731-38.315C120.596 407.683 112 397.599 112 385.786V214.261l.002-.001c.011-18.366 10.607-35.889 28.464-43.845 28.886-12.994 95.413-49.038 107.534-77.323 7.797-18.194 21.384-29.084 40-29.092 34.222-.014 57.752 35.098 44.119 66.908-3.583 8.359-8.312 16.67-14.153 24.918H467.2c23.45 0 44.8 20.543 44.8 43.826zM96 200v192c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V200c0-13.255 10.745-24 24-24h48c13.255 0 24 10.745 24 24zM68 368c0-11.046-8.954-20-20-20s-20 8.954-20 20 8.954 20 20 20 20-8.954 20-20z\"]\n};\nvar faHandPointUp = {\n prefix: 'fas',\n iconName: 'hand-point-up',\n icon: [384, 512, [], \"f0a6\", \"M135.652 0c23.625 0 43.826 20.65 43.826 44.8v99.851c17.048-16.34 49.766-18.346 70.944 6.299 22.829-14.288 53.017-2.147 62.315 16.45C361.878 158.426 384 189.346 384 240c0 2.746-.203 13.276-.195 16 .168 61.971-31.065 76.894-38.315 123.731C343.683 391.404 333.599 400 321.786 400H150.261l-.001-.002c-18.366-.011-35.889-10.607-43.845-28.464C93.421 342.648 57.377 276.122 29.092 264 10.897 256.203.008 242.616 0 224c-.014-34.222 35.098-57.752 66.908-44.119 8.359 3.583 16.67 8.312 24.918 14.153V44.8c0-23.45 20.543-44.8 43.826-44.8zM136 416h192c13.255 0 24 10.745 24 24v48c0 13.255-10.745 24-24 24H136c-13.255 0-24-10.745-24-24v-48c0-13.255 10.745-24 24-24zm168 28c-11.046 0-20 8.954-20 20s8.954 20 20 20 20-8.954 20-20-8.954-20-20-20z\"]\n};\nvar faHandPointer = {\n prefix: 'fas',\n iconName: 'hand-pointer',\n icon: [448, 512, [], \"f25a\", \"M448 240v96c0 3.084-.356 6.159-1.063 9.162l-32 136C410.686 499.23 394.562 512 376 512H168a40.004 40.004 0 0 1-32.35-16.473l-127.997-176c-12.993-17.866-9.043-42.883 8.822-55.876 17.867-12.994 42.884-9.043 55.877 8.823L104 315.992V40c0-22.091 17.908-40 40-40s40 17.909 40 40v200h8v-40c0-22.091 17.908-40 40-40s40 17.909 40 40v40h8v-24c0-22.091 17.908-40 40-40s40 17.909 40 40v24h8c0-22.091 17.908-40 40-40s40 17.909 40 40zm-256 80h-8v96h8v-96zm88 0h-8v96h8v-96zm88 0h-8v96h8v-96z\"]\n};\nvar faHandRock = {\n prefix: 'fas',\n iconName: 'hand-rock',\n icon: [512, 512, [], \"f255\", \"M464.8 80c-26.9-.4-48.8 21.2-48.8 48h-8V96.8c0-26.3-20.9-48.3-47.2-48.8-26.9-.4-48.8 21.2-48.8 48v32h-8V80.8c0-26.3-20.9-48.3-47.2-48.8-26.9-.4-48.8 21.2-48.8 48v48h-8V96.8c0-26.3-20.9-48.3-47.2-48.8-26.9-.4-48.8 21.2-48.8 48v136l-8-7.1v-48.1c0-26.3-20.9-48.3-47.2-48.8C21.9 127.6 0 149.2 0 176v66.4c0 27.4 11.7 53.5 32.2 71.8l111.7 99.3c10.2 9.1 16.1 22.2 16.1 35.9v6.7c0 13.3 10.7 24 24 24h240c13.3 0 24-10.7 24-24v-2.9c0-12.8 2.6-25.5 7.5-37.3l49-116.3c5-11.8 7.5-24.5 7.5-37.3V128.8c0-26.3-20.9-48.4-47.2-48.8z\"]\n};\nvar faHandScissors = {\n prefix: 'fas',\n iconName: 'hand-scissors',\n icon: [512, 512, [], \"f257\", \"M216 440c0-22.092 17.909-40 40-40v-8h-32c-22.091 0-40-17.908-40-40s17.909-40 40-40h32v-8H48c-26.51 0-48-21.49-48-48s21.49-48 48-48h208v-13.572l-177.551-69.74c-24.674-9.694-36.818-37.555-27.125-62.228 9.693-24.674 37.554-36.817 62.228-27.124l190.342 74.765 24.872-31.09c12.306-15.381 33.978-19.515 51.081-9.741l112 64A40.002 40.002 0 0 1 512 168v240c0 18.562-12.77 34.686-30.838 38.937l-136 32A39.982 39.982 0 0 1 336 480h-80c-22.091 0-40-17.908-40-40z\"]\n};\nvar faHandSpock = {\n prefix: 'fas',\n iconName: 'hand-spock',\n icon: [512, 512, [], \"f259\", \"M481.3 97.1c-21.5-5.1-43.1 8.2-48.2 29.6L402.3 256h-11.1l43.6-174.3c5.4-21.4-7.7-43.1-29.1-48.5s-43.1 7.7-48.5 29.1L308.8 256h-15.1L242 31.1c-5-21.6-26.4-35-48-30.1-21.5 4.9-35 26.4-30 47.9l47.6 207h-9.8L167 103.1c-4.9-21.5-26.3-35-47.9-30.1-21.5 4.9-35 26.3-30.1 47.9l39 171.6v79.4l-60.6-57c-16.1-15.1-41.4-14.4-56.5 1.7s-14.4 41.4 1.7 56.5L146.3 499c8.9 8.4 20.7 13 32.9 13h216.7c21.3 0 40-14 46-34.4l26.2-88.3c2.6-8.9 4-18 4-27.3v-42c0-7.5.9-15 2.6-22.2L511 145.3c5-21.5-8.3-43.1-29.7-48.2z\"]\n};\nvar faHands = {\n prefix: 'fas',\n iconName: 'hands',\n icon: [640, 512, [], \"f4c2\", \"M204.8 230.4c-10.6-14.1-30.7-17-44.8-6.4-14.1 10.6-17 30.7-6.4 44.8l38.1 50.8c4.8 6.4 4.1 15.3-1.5 20.9l-12.8 12.8c-6.7 6.7-17.6 6.2-23.6-1.1L64 244.4V96c0-17.7-14.3-32-32-32S0 78.3 0 96v218.4c0 10.9 3.7 21.5 10.5 30l104.1 134.3c5 6.5 8.4 13.9 10.4 21.7 1.8 6.9 8.1 11.6 15.3 11.6H272c8.8 0 16-7.2 16-16V384c0-27.7-9-54.6-25.6-76.8l-57.6-76.8zM608 64c-17.7 0-32 14.3-32 32v148.4l-89.8 107.8c-6 7.2-17 7.7-23.6 1.1l-12.8-12.8c-5.6-5.6-6.3-14.5-1.5-20.9l38.1-50.8c10.6-14.1 7.7-34.2-6.4-44.8-14.1-10.6-34.2-7.7-44.8 6.4l-57.6 76.8C361 329.4 352 356.3 352 384v112c0 8.8 7.2 16 16 16h131.7c7.1 0 13.5-4.7 15.3-11.6 2-7.8 5.4-15.2 10.4-21.7l104.1-134.3c6.8-8.5 10.5-19.1 10.5-30V96c0-17.7-14.3-32-32-32z\"]\n};\nvar faHandsHelping = {\n prefix: 'fas',\n iconName: 'hands-helping',\n icon: [640, 512, [], \"f4c4\", \"M488 192H336v56c0 39.7-32.3 72-72 72s-72-32.3-72-72V126.4l-64.9 39C107.8 176.9 96 197.8 96 220.2v47.3l-80 46.2C.7 322.5-4.6 342.1 4.3 357.4l80 138.6c8.8 15.3 28.4 20.5 43.7 11.7L231.4 448H368c35.3 0 64-28.7 64-64h16c17.7 0 32-14.3 32-32v-64h8c13.3 0 24-10.7 24-24v-48c0-13.3-10.7-24-24-24zm147.7-37.4L555.7 16C546.9.7 527.3-4.5 512 4.3L408.6 64H306.4c-12 0-23.7 3.4-33.9 9.7L239 94.6c-9.4 5.8-15 16.1-15 27.1V248c0 22.1 17.9 40 40 40s40-17.9 40-40v-88h184c30.9 0 56 25.1 56 56v28.5l80-46.2c15.3-8.9 20.5-28.4 11.7-43.7z\"]\n};\nvar faHandshake = {\n prefix: 'fas',\n iconName: 'handshake',\n icon: [640, 512, [], \"f2b5\", \"M434.7 64h-85.9c-8 0-15.7 3-21.6 8.4l-98.3 90c-.1.1-.2.3-.3.4-16.6 15.6-16.3 40.5-2.1 56 12.7 13.9 39.4 17.6 56.1 2.7.1-.1.3-.1.4-.2l79.9-73.2c6.5-5.9 16.7-5.5 22.6 1 6 6.5 5.5 16.6-1 22.6l-26.1 23.9L504 313.8c2.9 2.4 5.5 5 7.9 7.7V128l-54.6-54.6c-5.9-6-14.1-9.4-22.6-9.4zM544 128.2v223.9c0 17.7 14.3 32 32 32h64V128.2h-96zm48 223.9c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zM0 384h64c17.7 0 32-14.3 32-32V128.2H0V384zm48-63.9c8.8 0 16 7.2 16 16s-7.2 16-16 16-16-7.2-16-16c0-8.9 7.2-16 16-16zm435.9 18.6L334.6 217.5l-30 27.5c-29.7 27.1-75.2 24.5-101.7-4.4-26.9-29.4-24.8-74.9 4.4-101.7L289.1 64h-83.8c-8.5 0-16.6 3.4-22.6 9.4L128 128v223.9h18.3l90.5 81.9c27.4 22.3 67.7 18.1 90-9.3l.2-.2 17.9 15.5c15.9 13 39.4 10.5 52.3-5.4l31.4-38.6 5.4 4.4c13.7 11.1 33.9 9.1 45-4.7l9.5-11.7c11.2-13.8 9.1-33.9-4.6-45.1z\"]\n};\nvar faHanukiah = {\n prefix: 'fas',\n iconName: 'hanukiah',\n icon: [640, 512, [], \"f6e6\", \"M232 160c-4.42 0-8 3.58-8 8v120h32V168c0-4.42-3.58-8-8-8h-16zm-64 0c-4.42 0-8 3.58-8 8v120h32V168c0-4.42-3.58-8-8-8h-16zm224 0c-4.42 0-8 3.58-8 8v120h32V168c0-4.42-3.58-8-8-8h-16zm64 0c-4.42 0-8 3.58-8 8v120h32V168c0-4.42-3.58-8-8-8h-16zm88 8c0-4.42-3.58-8-8-8h-16c-4.42 0-8 3.58-8 8v120h32V168zm-440-8c-4.42 0-8 3.58-8 8v120h32V168c0-4.42-3.58-8-8-8h-16zm520 0h-32c-8.84 0-16 7.16-16 16v112c0 17.67-14.33 32-32 32H352V128c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v192H96c-17.67 0-32-14.33-32-32V176c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v112c0 53.02 42.98 96 96 96h192v64H112c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16H352v-64h192c53.02 0 96-42.98 96-96V176c0-8.84-7.16-16-16-16zm-16-32c13.25 0 24-11.94 24-26.67S608 48 608 48s-24 38.61-24 53.33S594.75 128 608 128zm-576 0c13.25 0 24-11.94 24-26.67S32 48 32 48 8 86.61 8 101.33 18.75 128 32 128zm288-48c13.25 0 24-11.94 24-26.67S320 0 320 0s-24 38.61-24 53.33S306.75 80 320 80zm-208 48c13.25 0 24-11.94 24-26.67S112 48 112 48s-24 38.61-24 53.33S98.75 128 112 128zm64 0c13.25 0 24-11.94 24-26.67S176 48 176 48s-24 38.61-24 53.33S162.75 128 176 128zm64 0c13.25 0 24-11.94 24-26.67S240 48 240 48s-24 38.61-24 53.33S226.75 128 240 128zm160 0c13.25 0 24-11.94 24-26.67S400 48 400 48s-24 38.61-24 53.33S386.75 128 400 128zm64 0c13.25 0 24-11.94 24-26.67S464 48 464 48s-24 38.61-24 53.33S450.75 128 464 128zm64 0c13.25 0 24-11.94 24-26.67S528 48 528 48s-24 38.61-24 53.33S514.75 128 528 128z\"]\n};\nvar faHardHat = {\n prefix: 'fas',\n iconName: 'hard-hat',\n icon: [512, 512, [], \"f807\", \"M480 288c0-80.25-49.28-148.92-119.19-177.62L320 192V80a16 16 0 0 0-16-16h-96a16 16 0 0 0-16 16v112l-40.81-81.62C81.28 139.08 32 207.75 32 288v64h448zm16 96H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h480a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z\"]\n};\nvar faHashtag = {\n prefix: 'fas',\n iconName: 'hashtag',\n icon: [448, 512, [], \"f292\", \"M440.667 182.109l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l14.623-81.891C377.123 38.754 371.468 32 363.997 32h-40.632a12 12 0 0 0-11.813 9.891L296.175 128H197.54l14.623-81.891C213.477 38.754 207.822 32 200.35 32h-40.632a12 12 0 0 0-11.813 9.891L132.528 128H53.432a12 12 0 0 0-11.813 9.891l-7.143 40C33.163 185.246 38.818 192 46.289 192h74.81L98.242 320H19.146a12 12 0 0 0-11.813 9.891l-7.143 40C-1.123 377.246 4.532 384 12.003 384h74.81L72.19 465.891C70.877 473.246 76.532 480 84.003 480h40.632a12 12 0 0 0 11.813-9.891L151.826 384h98.634l-14.623 81.891C234.523 473.246 240.178 480 247.65 480h40.632a12 12 0 0 0 11.813-9.891L315.472 384h79.096a12 12 0 0 0 11.813-9.891l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l22.857-128h79.096a12 12 0 0 0 11.813-9.891zM261.889 320h-98.634l22.857-128h98.634l-22.857 128z\"]\n};\nvar faHatWizard = {\n prefix: 'fas',\n iconName: 'hat-wizard',\n icon: [512, 512, [], \"f6e8\", \"M496 448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h480c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm-304-64l-64-32 64-32 32-64 32 64 64 32-64 32-16 32h208l-86.41-201.63a63.955 63.955 0 0 1-1.89-45.45L416 0 228.42 107.19a127.989 127.989 0 0 0-53.46 59.15L64 416h144l-16-32zm64-224l16-32 16 32 32 16-32 16-16 32-16-32-32-16 32-16z\"]\n};\nvar faHaykal = {\n prefix: 'fas',\n iconName: 'haykal',\n icon: [512, 512, [], \"f666\", \"M496.25 202.52l-110-15.44 41.82-104.34c6.67-16.64-11.6-32.18-26.59-22.63L307.44 120 273.35 12.82C270.64 4.27 263.32 0 256 0c-7.32 0-14.64 4.27-17.35 12.82l-34.09 107.19-94.04-59.89c-14.99-9.55-33.25 5.99-26.59 22.63l41.82 104.34-110 15.43c-17.54 2.46-21.68 26.27-6.03 34.67l98.16 52.66-74.48 83.54c-10.92 12.25-1.72 30.93 13.29 30.93 1.31 0 2.67-.14 4.07-.45l108.57-23.65-4.11 112.55c-.43 11.65 8.87 19.22 18.41 19.22 5.15 0 10.39-2.21 14.2-7.18l68.18-88.9 68.18 88.9c3.81 4.97 9.04 7.18 14.2 7.18 9.54 0 18.84-7.57 18.41-19.22l-4.11-112.55 108.57 23.65c17.36 3.76 29.21-17.2 17.35-30.49l-74.48-83.54 98.16-52.66c15.64-8.39 11.5-32.2-6.04-34.66zM338.51 311.68l-51.89-11.3 1.97 53.79L256 311.68l-32.59 42.49 1.96-53.79-51.89 11.3 35.6-39.93-46.92-25.17 52.57-7.38-19.99-49.87 44.95 28.62L256 166.72l16.29 51.23 44.95-28.62-19.99 49.87 52.57 7.38-46.92 25.17 35.61 39.93z\"]\n};\nvar faHdd = {\n prefix: 'fas',\n iconName: 'hdd',\n icon: [576, 512, [], \"f0a0\", \"M576 304v96c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48v-96c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48zm-48-80a79.557 79.557 0 0 1 30.777 6.165L462.25 85.374A48.003 48.003 0 0 0 422.311 64H153.689a48 48 0 0 0-39.938 21.374L17.223 230.165A79.557 79.557 0 0 1 48 224h480zm-48 96c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm-96 0c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z\"]\n};\nvar faHeading = {\n prefix: 'fas',\n iconName: 'heading',\n icon: [512, 512, [], \"f1dc\", \"M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z\"]\n};\nvar faHeadphones = {\n prefix: 'fas',\n iconName: 'headphones',\n icon: [512, 512, [], \"f025\", \"M256 32C114.52 32 0 146.496 0 288v48a32 32 0 0 0 17.689 28.622l14.383 7.191C34.083 431.903 83.421 480 144 480h24c13.255 0 24-10.745 24-24V280c0-13.255-10.745-24-24-24h-24c-31.342 0-59.671 12.879-80 33.627V288c0-105.869 86.131-192 192-192s192 86.131 192 192v1.627C427.671 268.879 399.342 256 368 256h-24c-13.255 0-24 10.745-24 24v176c0 13.255 10.745 24 24 24h24c60.579 0 109.917-48.098 111.928-108.187l14.382-7.191A32 32 0 0 0 512 336v-48c0-141.479-114.496-256-256-256z\"]\n};\nvar faHeadphonesAlt = {\n prefix: 'fas',\n iconName: 'headphones-alt',\n icon: [512, 512, [], \"f58f\", \"M160 288h-16c-35.35 0-64 28.7-64 64.12v63.76c0 35.41 28.65 64.12 64 64.12h16c17.67 0 32-14.36 32-32.06V320.06c0-17.71-14.33-32.06-32-32.06zm208 0h-16c-17.67 0-32 14.35-32 32.06v127.88c0 17.7 14.33 32.06 32 32.06h16c35.35 0 64-28.71 64-64.12v-63.76c0-35.41-28.65-64.12-64-64.12zM256 32C112.91 32 4.57 151.13 0 288v112c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16V288c0-114.67 93.33-207.8 208-207.82 114.67.02 208 93.15 208 207.82v112c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16V288C507.43 151.13 399.09 32 256 32z\"]\n};\nvar faHeadset = {\n prefix: 'fas',\n iconName: 'headset',\n icon: [512, 512, [], \"f590\", \"M192 208c0-17.67-14.33-32-32-32h-16c-35.35 0-64 28.65-64 64v48c0 35.35 28.65 64 64 64h16c17.67 0 32-14.33 32-32V208zm176 144c35.35 0 64-28.65 64-64v-48c0-35.35-28.65-64-64-64h-16c-17.67 0-32 14.33-32 32v112c0 17.67 14.33 32 32 32h16zM256 0C113.18 0 4.58 118.83 0 256v16c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16v-16c0-114.69 93.31-208 208-208s208 93.31 208 208h-.12c.08 2.43.12 165.72.12 165.72 0 23.35-18.93 42.28-42.28 42.28H320c0-26.51-21.49-48-48-48h-32c-26.51 0-48 21.49-48 48s21.49 48 48 48h181.72c49.86 0 90.28-40.42 90.28-90.28V256C507.42 118.83 398.82 0 256 0z\"]\n};\nvar faHeart = {\n prefix: 'fas',\n iconName: 'heart',\n icon: [512, 512, [], \"f004\", \"M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z\"]\n};\nvar faHeartBroken = {\n prefix: 'fas',\n iconName: 'heart-broken',\n icon: [512, 512, [], \"f7a9\", \"M473.7 73.8l-2.4-2.5c-46-47-118-51.7-169.6-14.8L336 159.9l-96 64 48 128-144-144 96-64-28.6-86.5C159.7 19.6 87 24 40.7 71.4l-2.4 2.4C-10.4 123.6-12.5 202.9 31 256l212.1 218.6c7.1 7.3 18.6 7.3 25.7 0L481 255.9c43.5-53 41.4-132.3-7.3-182.1z\"]\n};\nvar faHeartbeat = {\n prefix: 'fas',\n iconName: 'heartbeat',\n icon: [512, 512, [], \"f21e\", \"M320.2 243.8l-49.7 99.4c-6 12.1-23.4 11.7-28.9-.6l-56.9-126.3-30 71.7H60.6l182.5 186.5c7.1 7.3 18.6 7.3 25.7 0L451.4 288H342.3l-22.1-44.2zM473.7 73.9l-2.4-2.5c-51.5-52.6-135.8-52.6-187.4 0L256 100l-27.9-28.5c-51.5-52.7-135.9-52.7-187.4 0l-2.4 2.4C-10.4 123.7-12.5 203 31 256h102.4l35.9-86.2c5.4-12.9 23.6-13.2 29.4-.4l58.2 129.3 49-97.9c5.9-11.8 22.7-11.8 28.6 0l27.6 55.2H481c43.5-53 41.4-132.3-7.3-182.1z\"]\n};\nvar faHelicopter = {\n prefix: 'fas',\n iconName: 'helicopter',\n icon: [640, 512, [], \"f533\", \"M304 384h272c17.67 0 32-14.33 32-32 0-123.71-100.29-224-224-224V64h176c8.84 0 16-7.16 16-16V16c0-8.84-7.16-16-16-16H144c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h176v64H112L68.8 70.4C65.78 66.37 61.03 64 56 64H16.01C5.6 64-2.04 73.78.49 83.88L32 192l160 64 86.4 115.2A31.992 31.992 0 0 0 304 384zm112-188.49C478.55 208.3 528.03 257.44 540.79 320H416V195.51zm219.37 263.3l-22.15-22.2c-6.25-6.26-16.24-6.1-22.64.01-7.09 6.77-13.84 11.25-24.64 11.25H240c-8.84 0-16 7.18-16 16.03v32.06c0 8.85 7.16 16.03 16 16.03h325.94c14.88 0 35.3-.47 68.45-29.52 7.02-6.14 7.57-17.05.98-23.66z\"]\n};\nvar faHighlighter = {\n prefix: 'fas',\n iconName: 'highlighter',\n icon: [544, 512, [], \"f591\", \"M0 479.98L99.92 512l35.45-35.45-67.04-67.04L0 479.98zm124.61-240.01a36.592 36.592 0 0 0-10.79 38.1l13.05 42.83-50.93 50.94 96.23 96.23 50.86-50.86 42.74 13.08c13.73 4.2 28.65-.01 38.15-10.78l35.55-41.64-173.34-173.34-41.52 35.44zm403.31-160.7l-63.2-63.2c-20.49-20.49-53.38-21.52-75.12-2.35L190.55 183.68l169.77 169.78L530.27 154.4c19.18-21.74 18.15-54.63-2.35-75.13z\"]\n};\nvar faHiking = {\n prefix: 'fas',\n iconName: 'hiking',\n icon: [384, 512, [], \"f6ec\", \"M80.95 472.23c-4.28 17.16 6.14 34.53 23.28 38.81 2.61.66 5.22.95 7.8.95 14.33 0 27.37-9.7 31.02-24.23l25.24-100.97-52.78-52.78-34.56 138.22zm14.89-196.12L137 117c2.19-8.42-3.14-16.95-11.92-19.06-43.88-10.52-88.35 15.07-99.32 57.17L.49 253.24c-2.19 8.42 3.14 16.95 11.92 19.06l63.56 15.25c8.79 2.1 17.68-3.02 19.87-11.44zM368 160h-16c-8.84 0-16 7.16-16 16v16h-34.75l-46.78-46.78C243.38 134.11 228.61 128 212.91 128c-27.02 0-50.47 18.3-57.03 44.52l-26.92 107.72a32.012 32.012 0 0 0 8.42 30.39L224 397.25V480c0 17.67 14.33 32 32 32s32-14.33 32-32v-82.75c0-17.09-6.66-33.16-18.75-45.25l-46.82-46.82c.15-.5.49-.89.62-1.41l19.89-79.57 22.43 22.43c6 6 14.14 9.38 22.62 9.38h48v240c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16V176c.01-8.84-7.15-16-15.99-16zM240 96c26.51 0 48-21.49 48-48S266.51 0 240 0s-48 21.49-48 48 21.49 48 48 48z\"]\n};\nvar faHippo = {\n prefix: 'fas',\n iconName: 'hippo',\n icon: [640, 512, [], \"f6ed\", \"M581.12 96.2c-27.67-.15-52.5 17.58-76.6 26.62C489.98 88.27 455.83 64 416 64c-11.28 0-21.95 2.3-32 5.88V56c0-13.26-10.75-24-24-24h-16c-13.25 0-24 10.74-24 24v48.98C286.01 79.58 241.24 64 192 64 85.96 64 0 135.64 0 224v240c0 8.84 7.16 16 16 16h64c8.84 0 16-7.16 16-16v-70.79C128.35 407.57 166.72 416 208 416s79.65-8.43 112-22.79V464c0 8.84 7.16 16 16 16h64c8.84 0 16-7.16 16-16V288h128v32c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-32c17.67 0 32-14.33 32-32v-92.02c0-34.09-24.79-67.59-58.88-67.78zM448 176c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16z\"]\n};\nvar faHistory = {\n prefix: 'fas',\n iconName: 'history',\n icon: [512, 512, [], \"f1da\", \"M504 255.531c.253 136.64-111.18 248.372-247.82 248.468-59.015.042-113.223-20.53-155.822-54.911-11.077-8.94-11.905-25.541-1.839-35.607l11.267-11.267c8.609-8.609 22.353-9.551 31.891-1.984C173.062 425.135 212.781 440 256 440c101.705 0 184-82.311 184-184 0-101.705-82.311-184-184-184-48.814 0-93.149 18.969-126.068 49.932l50.754 50.754c10.08 10.08 2.941 27.314-11.313 27.314H24c-8.837 0-16-7.163-16-16V38.627c0-14.254 17.234-21.393 27.314-11.314l49.372 49.372C129.209 34.136 189.552 8 256 8c136.81 0 247.747 110.78 248 247.531zm-180.912 78.784l9.823-12.63c8.138-10.463 6.253-25.542-4.21-33.679L288 256.349V152c0-13.255-10.745-24-24-24h-16c-13.255 0-24 10.745-24 24v135.651l65.409 50.874c10.463 8.137 25.541 6.253 33.679-4.21z\"]\n};\nvar faHockeyPuck = {\n prefix: 'fas',\n iconName: 'hockey-puck',\n icon: [512, 512, [], \"f453\", \"M0 160c0-53 114.6-96 256-96s256 43 256 96-114.6 96-256 96S0 213 0 160zm0 82.2V352c0 53 114.6 96 256 96s256-43 256-96V242.2c-113.4 82.3-398.5 82.4-512 0z\"]\n};\nvar faHollyBerry = {\n prefix: 'fas',\n iconName: 'holly-berry',\n icon: [448, 512, [], \"f7aa\", \"M144 192c26.5 0 48-21.5 48-48s-21.5-48-48-48-48 21.5-48 48 21.5 48 48 48zm112-48c0 26.5 21.5 48 48 48s48-21.5 48-48-21.5-48-48-48-48 21.5-48 48zm-32-48c26.5 0 48-21.5 48-48S250.5 0 224 0s-48 21.5-48 48 21.5 48 48 48zm-16.2 139.1c.1-12.4-13.1-20.1-23.8-13.7-34.3 20.3-71.4 32.7-108.7 36.2-9.7.9-15.6 11.3-11.6 20.2 6.2 13.9 11.1 28.6 14.7 43.8 3.6 15.2-5.3 30.6-20.2 35.1-14.9 4.5-30.1 7.6-45.3 9.1-9.7 1-15.7 11.3-11.7 20.2 15 32.8 22.9 69.5 23 107.7.1 14.4 15.2 23.1 27.6 16 33.2-19 68.9-30.5 104.8-33.9 9.7-.9 15.6-11.3 11.6-20.2-6.2-13.9-11.1-28.6-14.7-43.8-3.6-15.2 5.3-30.6 20.2-35.1 14.9-4.5 30.1-7.6 45.3-9.1 9.7-1 15.7-11.3 11.7-20.2-15.5-34.2-23.3-72.5-22.9-112.3zM435 365.6c-15.2-1.6-30.3-4.7-45.3-9.1-14.9-4.5-23.8-19.9-20.2-35.1 3.6-15.2 8.5-29.8 14.7-43.8 4-8.9-1.9-19.3-11.6-20.2-37.3-3.5-74.4-15.9-108.7-36.2-10.7-6.3-23.9 1.4-23.8 13.7 0 1.6-.2 3.2-.2 4.9.2 33.3 7 65.7 19.9 94 5.7 12.4 5.2 26.6-.6 38.9 4.9 1.2 9.9 2.2 14.8 3.7 14.9 4.5 23.8 19.9 20.2 35.1-3.6 15.2-8.5 29.8-14.7 43.8-4 8.9 1.9 19.3 11.6 20.2 35.9 3.4 71.6 14.9 104.8 33.9 12.5 7.1 27.6-1.6 27.6-16 .2-38.2 8-75 23-107.7 4.3-8.7-1.8-19.1-11.5-20.1z\"]\n};\nvar faHome = {\n prefix: 'fas',\n iconName: 'home',\n icon: [576, 512, [], \"f015\", \"M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z\"]\n};\nvar faHorse = {\n prefix: 'fas',\n iconName: 'horse',\n icon: [576, 512, [], \"f6f0\", \"M575.92 76.6c-.01-8.13-3.02-15.87-8.58-21.8-3.78-4.03-8.58-9.12-13.69-14.5 11.06-6.84 19.5-17.49 22.18-30.66C576.85 4.68 572.96 0 567.9 0H447.92c-70.69 0-128 57.31-128 128H160c-28.84 0-54.4 12.98-72 33.11V160c-48.53 0-88 39.47-88 88v56c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16v-56c0-13.22 6.87-24.39 16.78-31.68-.21 2.58-.78 5.05-.78 7.68 0 27.64 11.84 52.36 30.54 69.88l-25.72 68.6a63.945 63.945 0 0 0-2.16 37.99l24.85 99.41A15.982 15.982 0 0 0 107.02 512h65.96c10.41 0 18.05-9.78 15.52-19.88l-26.31-105.26 23.84-63.59L320 345.6V496c0 8.84 7.16 16 16 16h64c8.84 0 16-7.16 16-16V318.22c19.74-20.19 32-47.75 32-78.22 0-.22-.07-.42-.08-.64V136.89l16 7.11 18.9 37.7c7.45 14.87 25.05 21.55 40.49 15.37l32.55-13.02a31.997 31.997 0 0 0 20.12-29.74l-.06-77.71zm-64 19.4c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16z\"]\n};\nvar faHorseHead = {\n prefix: 'fas',\n iconName: 'horse-head',\n icon: [512, 512, [], \"f7ab\", \"M509.8 332.5l-69.9-164.3c-14.9-41.2-50.4-71-93-79.2 18-10.6 46.3-35.9 34.2-82.3-1.3-5-7.1-7.9-12-6.1L166.9 76.3C35.9 123.4 0 238.9 0 398.8V480c0 17.7 14.3 32 32 32h236.2c23.8 0 39.3-25 28.6-46.3L256 384v-.7c-45.6-3.5-84.6-30.7-104.3-69.6-1.6-3.1-.9-6.9 1.6-9.3l12.1-12.1c3.9-3.9 10.6-2.7 12.9 2.4 14.8 33.7 48.2 57.4 87.4 57.4 17.2 0 33-5.1 46.8-13.2l46 63.9c6 8.4 15.7 13.3 26 13.3h50.3c8.5 0 16.6-3.4 22.6-9.4l45.3-39.8c8.9-9.1 11.7-22.6 7.1-34.4zM328 224c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24-10.7 24-24 24z\"]\n};\nvar faHospital = {\n prefix: 'fas',\n iconName: 'hospital',\n icon: [448, 512, [], \"f0f8\", \"M448 492v20H0v-20c0-6.627 5.373-12 12-12h20V120c0-13.255 10.745-24 24-24h88V24c0-13.255 10.745-24 24-24h112c13.255 0 24 10.745 24 24v72h88c13.255 0 24 10.745 24 24v360h20c6.627 0 12 5.373 12 12zM308 192h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12zm-168 64h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12zm104 128h-40c-6.627 0-12 5.373-12 12v84h64v-84c0-6.627-5.373-12-12-12zm64-96h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12zm-116 12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40zM182 96h26v26a6 6 0 0 0 6 6h20a6 6 0 0 0 6-6V96h26a6 6 0 0 0 6-6V70a6 6 0 0 0-6-6h-26V38a6 6 0 0 0-6-6h-20a6 6 0 0 0-6 6v26h-26a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6z\"]\n};\nvar faHospitalAlt = {\n prefix: 'fas',\n iconName: 'hospital-alt',\n icon: [576, 512, [], \"f47d\", \"M544 96H416V32c0-17.7-14.3-32-32-32H192c-17.7 0-32 14.3-32 32v64H32c-17.7 0-32 14.3-32 32v368c0 8.8 7.2 16 16 16h544c8.8 0 16-7.2 16-16V128c0-17.7-14.3-32-32-32zM160 436c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-128c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm160 128c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-128c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm16-170c0 3.3-2.7 6-6 6h-26v26c0 3.3-2.7 6-6 6h-20c-3.3 0-6-2.7-6-6v-26h-26c-3.3 0-6-2.7-6-6v-20c0-3.3 2.7-6 6-6h26V86c0-3.3 2.7-6 6-6h20c3.3 0 6 2.7 6 6v26h26c3.3 0 6 2.7 6 6v20zm144 298c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-128c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40z\"]\n};\nvar faHospitalSymbol = {\n prefix: 'fas',\n iconName: 'hospital-symbol',\n icon: [512, 512, [], \"f47e\", \"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256 256-114.6 256-256S397.4 0 256 0zm112 376c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-88h-96v88c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V136c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v88h96v-88c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v240z\"]\n};\nvar faHotTub = {\n prefix: 'fas',\n iconName: 'hot-tub',\n icon: [512, 512, [], \"f593\", \"M414.21 177.65c1.02 8.21 7.75 14.35 15.75 14.35h16.12c9.51 0 17.08-8.57 16-18.35-4.34-39.11-22.4-74.53-50.13-97.16-17.37-14.17-28.82-36.75-31.98-62.15C378.96 6.14 372.22 0 364.23 0h-16.12c-9.51 0-17.09 8.57-16 18.35 4.34 39.11 22.4 74.53 50.13 97.16 17.36 14.17 28.82 36.75 31.97 62.14zm-108 0c1.02 8.21 7.75 14.35 15.75 14.35h16.12c9.51 0 17.08-8.57 16-18.35-4.34-39.11-22.4-74.53-50.13-97.16-17.37-14.17-28.82-36.75-31.98-62.15C270.96 6.14 264.22 0 256.23 0h-16.12c-9.51 0-17.09 8.57-16 18.35 4.34 39.11 22.4 74.53 50.13 97.16 17.36 14.17 28.82 36.75 31.97 62.14zM480 256H256l-110.93-83.2a63.99 63.99 0 0 0-38.4-12.8H64c-35.35 0-64 28.65-64 64v224c0 35.35 28.65 64 64 64h384c35.35 0 64-28.65 64-64V288c0-17.67-14.33-32-32-32zM128 440c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8V328c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v112zm96 0c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8V328c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v112zm96 0c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8V328c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v112zm96 0c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8V328c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v112zM64 128c35.35 0 64-28.65 64-64S99.35 0 64 0 0 28.65 0 64s28.65 64 64 64z\"]\n};\nvar faHotdog = {\n prefix: 'fas',\n iconName: 'hotdog',\n icon: [512, 512, [], \"f80f\", \"M488.56 23.44a80 80 0 0 0-113.12 0l-352 352a80 80 0 1 0 113.12 113.12l352-352a80 80 0 0 0 0-113.12zm-49.93 95.19c-19.6 19.59-37.52 22.67-51.93 25.14C373.76 146 364.4 147.6 352 160s-14 21.76-16.23 34.71c-2.48 14.4-5.55 32.33-25.15 51.92s-37.52 22.67-51.92 25.15C245.75 274 236.4 275.6 224 288s-14 21.75-16.23 34.7c-2.47 14.4-5.54 32.33-25.14 51.92s-37.53 22.68-51.93 25.15C117.76 402 108.4 403.6 96 416a16 16 0 0 1-22.63-22.63c19.6-19.59 37.52-22.67 51.92-25.14 13-2.22 22.3-3.82 34.71-16.23s14-21.75 16.22-34.7c2.48-14.4 5.55-32.33 25.15-51.92s37.52-22.67 51.92-25.14c13-2.22 22.3-3.83 34.7-16.23s14-21.76 16.24-34.71c2.47-14.4 5.54-32.33 25.14-51.92s37.52-22.68 51.92-25.15C394.24 110 403.59 108.41 416 96a16 16 0 0 1 22.63 22.63zM31.44 322.18L322.18 31.44l-11.54-11.55c-25-25-63.85-26.66-86.79-3.72L16.17 223.85c-22.94 22.94-21.27 61.79 3.72 86.78zm449.12-132.36L189.82 480.56l11.54 11.55c25 25 63.85 26.66 86.79 3.72l207.68-207.68c22.94-22.94 21.27-61.79-3.72-86.79z\"]\n};\nvar faHotel = {\n prefix: 'fas',\n iconName: 'hotel',\n icon: [576, 512, [], \"f594\", \"M560 64c8.84 0 16-7.16 16-16V16c0-8.84-7.16-16-16-16H16C7.16 0 0 7.16 0 16v32c0 8.84 7.16 16 16 16h15.98v384H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h240v-80c0-8.8 7.2-16 16-16h32c8.8 0 16 7.2 16 16v80h240c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16h-16V64h16zm-304 44.8c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4zm0 96c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4zm-128-96c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4zM179.2 256h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4c0 6.4-6.4 12.8-12.8 12.8zM192 384c0-53.02 42.98-96 96-96s96 42.98 96 96H192zm256-140.8c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4zm0-96c0 6.4-6.4 12.8-12.8 12.8h-38.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h38.4c6.4 0 12.8 6.4 12.8 12.8v38.4z\"]\n};\nvar faHourglass = {\n prefix: 'fas',\n iconName: 'hourglass',\n icon: [384, 512, [], \"f254\", \"M360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64z\"]\n};\nvar faHourglassEnd = {\n prefix: 'fas',\n iconName: 'hourglass-end',\n icon: [384, 512, [], \"f253\", \"M360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64zM192 208c-57.787 0-104-66.518-104-144h208c0 77.945-46.51 144-104 144z\"]\n};\nvar faHourglassHalf = {\n prefix: 'fas',\n iconName: 'hourglass-half',\n icon: [384, 512, [], \"f252\", \"M360 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24zm-75.078 384H99.08c17.059-46.797 52.096-80 92.92-80 40.821 0 75.862 33.196 92.922 80zm.019-256H99.078C91.988 108.548 88 86.748 88 64h208c0 22.805-3.987 44.587-11.059 64z\"]\n};\nvar faHourglassStart = {\n prefix: 'fas',\n iconName: 'hourglass-start',\n icon: [384, 512, [], \"f251\", \"M360 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24zm-64 448H88c0-77.458 46.204-144 104-144 57.786 0 104 66.517 104 144z\"]\n};\nvar faHouseDamage = {\n prefix: 'fas',\n iconName: 'house-damage',\n icon: [576, 512, [], \"f6f1\", \"M288 114.96L69.47 307.71c-1.62 1.46-3.69 2.14-5.47 3.35V496c0 8.84 7.16 16 16 16h149.23L192 439.19l104.11-64-60.16-119.22L384 392.75l-104.11 64L319.81 512H496c8.84 0 16-7.16 16-16V311.1c-1.7-1.16-3.72-1.82-5.26-3.2L288 114.96zm282.69 121.32L512 184.45V48c0-8.84-7.16-16-16-16h-64c-8.84 0-16 7.16-16 16v51.69L314.75 10.31C307.12 3.45 297.56.01 288 0s-19.1 3.41-26.7 10.27L5.31 236.28c-6.57 5.91-7.12 16.02-1.21 22.6l21.4 23.82c5.9 6.57 16.02 7.12 22.6 1.21L277.42 81.63c6.05-5.33 15.12-5.33 21.17 0L527.91 283.9c6.57 5.9 16.69 5.36 22.6-1.21l21.4-23.82c5.9-6.57 5.36-16.69-1.22-22.59z\"]\n};\nvar faHryvnia = {\n prefix: 'fas',\n iconName: 'hryvnia',\n icon: [384, 512, [], \"f6f2\", \"M368 240c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16h-41.86c13.41-28.63 13.74-63.33-4.13-94.05C303.34 49.84 267.1 32 229.96 32h-78.82c-24.32 0-47.86 8.53-66.54 24.09L72.83 65.9c-10.18 8.49-11.56 23.62-3.07 33.8l20.49 24.59c8.49 10.19 23.62 11.56 33.81 3.07l11.73-9.78c4.32-3.6 9.77-5.57 15.39-5.57h83.62c11.69 0 21.2 9.52 21.2 21.2 0 5.91-2.48 11.58-6.81 15.58L219.7 176H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h134.37l-34.67 32H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h41.86c-13.41 28.63-13.74 63.33 4.13 94.05C80.66 462.15 116.9 480 154.04 480h78.82c24.32 0 47.86-8.53 66.54-24.09l11.77-9.81c10.18-8.49 11.56-23.62 3.07-33.8l-20.49-24.59c-8.49-10.19-23.62-11.56-33.81-3.07l-11.75 9.8a23.992 23.992 0 0 1-15.36 5.56H149.2c-11.69 0-21.2-9.52-21.2-21.2 0-5.91 2.48-11.58 6.81-15.58L164.3 336H368c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16H233.63l34.67-32H368z\"]\n};\nvar faICursor = {\n prefix: 'fas',\n iconName: 'i-cursor',\n icon: [256, 512, [], \"f246\", \"M256 52.048V12.065C256 5.496 250.726.148 244.158.066 211.621-.344 166.469.011 128 37.959 90.266.736 46.979-.114 11.913.114 5.318.157 0 5.519 0 12.114v39.645c0 6.687 5.458 12.078 12.145 11.998C38.111 63.447 96 67.243 96 112.182V224H60c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h36v112c0 44.932-56.075 48.031-83.95 47.959C5.404 447.942 0 453.306 0 459.952v39.983c0 6.569 5.274 11.917 11.842 11.999 32.537.409 77.689.054 116.158-37.894 37.734 37.223 81.021 38.073 116.087 37.845 6.595-.043 11.913-5.405 11.913-12V460.24c0-6.687-5.458-12.078-12.145-11.998C217.889 448.553 160 444.939 160 400V288h36c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-36V112.182c0-44.932 56.075-48.213 83.95-48.142 6.646.018 12.05-5.346 12.05-11.992z\"]\n};\nvar faIceCream = {\n prefix: 'fas',\n iconName: 'ice-cream',\n icon: [448, 512, [], \"f810\", \"M368 160h-.94a144 144 0 1 0-286.12 0H80a48 48 0 0 0 0 96h288a48 48 0 0 0 0-96zM195.38 493.69a31.52 31.52 0 0 0 57.24 0L352 288H96z\"]\n};\nvar faIcicles = {\n prefix: 'fas',\n iconName: 'icicles',\n icon: [512, 512, [], \"f7ad\", \"M511.4 37.9C515.1 18.2 500 0 480 0H32C10.6 0-4.8 20.7 1.4 41.2l87.1 273.4c2.5 7.2 12.7 7.2 15.1 0L140 190.5l44.2 187.3c1.9 8.3 13.7 8.3 15.6 0l46.5-196.9 34.1 133.4c2.3 7.6 13 7.6 15.3 0l45.8-172.5 66.7 363.8c1.7 8.6 14 8.6 15.7 0l87.5-467.7z\"]\n};\nvar faIdBadge = {\n prefix: 'fas',\n iconName: 'id-badge',\n icon: [384, 512, [], \"f2c1\", \"M336 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM144 32h96c8.8 0 16 7.2 16 16s-7.2 16-16 16h-96c-8.8 0-16-7.2-16-16s7.2-16 16-16zm48 128c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zm112 236.8c0 10.6-10 19.2-22.4 19.2H102.4C90 416 80 407.4 80 396.8v-19.2c0-31.8 30.1-57.6 67.2-57.6h5c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h5c37.1 0 67.2 25.8 67.2 57.6v19.2z\"]\n};\nvar faIdCard = {\n prefix: 'fas',\n iconName: 'id-card',\n icon: [576, 512, [], \"f2c2\", \"M528 32H48C21.5 32 0 53.5 0 80v16h576V80c0-26.5-21.5-48-48-48zM0 432c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V128H0v304zm352-232c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-16zm0 64c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-16zm0 64c0-4.4 3.6-8 8-8h144c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-16zM176 192c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zM67.1 396.2C75.5 370.5 99.6 352 128 352h8.2c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h8.2c28.4 0 52.5 18.5 60.9 44.2 3.2 9.9-5.2 19.8-15.6 19.8H82.7c-10.4 0-18.8-10-15.6-19.8z\"]\n};\nvar faIdCardAlt = {\n prefix: 'fas',\n iconName: 'id-card-alt',\n icon: [576, 512, [], \"f47f\", \"M528 64H384v96H192V64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM288 224c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zm93.3 224H194.7c-10.4 0-18.8-10-15.6-19.8 8.3-25.6 32.4-44.2 60.9-44.2h8.2c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h8.2c28.4 0 52.5 18.5 60.9 44.2 3.2 9.8-5.2 19.8-15.6 19.8zM352 32c0-17.7-14.3-32-32-32h-64c-17.7 0-32 14.3-32 32v96h128V32z\"]\n};\nvar faIgloo = {\n prefix: 'fas',\n iconName: 'igloo',\n icon: [576, 512, [], \"f7ae\", \"M320 33.9c-10.5-1.2-21.2-1.9-32-1.9-99.8 0-187.8 50.8-239.4 128H320V33.9zM96 192H30.3C11.1 230.6 0 274 0 320h96V192zM352 39.4V160h175.4C487.2 99.9 424.8 55.9 352 39.4zM480 320h96c0-46-11.1-89.4-30.3-128H480v128zm-64 64v96h128c17.7 0 32-14.3 32-32v-96H411.5c2.6 10.3 4.5 20.9 4.5 32zm32-192H128v128h49.8c22.2-38.1 63-64 110.2-64s88 25.9 110.2 64H448V192zM0 448c0 17.7 14.3 32 32 32h128v-96c0-11.1 1.9-21.7 4.5-32H0v96zm288-160c-53 0-96 43-96 96v96h192v-96c0-53-43-96-96-96z\"]\n};\nvar faImage = {\n prefix: 'fas',\n iconName: 'image',\n icon: [512, 512, [], \"f03e\", \"M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z\"]\n};\nvar faImages = {\n prefix: 'fas',\n iconName: 'images',\n icon: [576, 512, [], \"f302\", \"M480 416v16c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v208c0 44.112 35.888 80 80 80h336zm96-80V80c0-26.51-21.49-48-48-48H144c-26.51 0-48 21.49-48 48v256c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48zM256 128c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-96 144l55.515-55.515c4.686-4.686 12.284-4.686 16.971 0L272 256l135.515-135.515c4.686-4.686 12.284-4.686 16.971 0L512 208v112H160v-48z\"]\n};\nvar faInbox = {\n prefix: 'fas',\n iconName: 'inbox',\n icon: [576, 512, [], \"f01c\", \"M567.938 243.908L462.25 85.374A48.003 48.003 0 0 0 422.311 64H153.689a48 48 0 0 0-39.938 21.374L8.062 243.908A47.994 47.994 0 0 0 0 270.533V400c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V270.533a47.994 47.994 0 0 0-8.062-26.625zM162.252 128h251.497l85.333 128H376l-32 64H232l-32-64H76.918l85.334-128z\"]\n};\nvar faIndent = {\n prefix: 'fas',\n iconName: 'indent',\n icon: [448, 512, [], \"f03c\", \"M0 84V44c0-8.837 7.163-16 16-16h416c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16zm176 144h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H176c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM16 484h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm160-128h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H176c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm-52.687-111.313l-96-95.984C17.266 138.652 0 145.776 0 160.016v191.975c0 14.329 17.325 21.304 27.313 11.313l96-95.992c6.249-6.247 6.249-16.377 0-22.625z\"]\n};\nvar faIndustry = {\n prefix: 'fas',\n iconName: 'industry',\n icon: [512, 512, [], \"f275\", \"M475.115 163.781L336 252.309v-68.28c0-18.916-20.931-30.399-36.885-20.248L160 252.309V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56v400c0 13.255 10.745 24 24 24h464c13.255 0 24-10.745 24-24V184.029c0-18.917-20.931-30.399-36.885-20.248z\"]\n};\nvar faInfinity = {\n prefix: 'fas',\n iconName: 'infinity',\n icon: [640, 512, [], \"f534\", \"M471.1 96C405 96 353.3 137.3 320 174.6 286.7 137.3 235 96 168.9 96 75.8 96 0 167.8 0 256s75.8 160 168.9 160c66.1 0 117.8-41.3 151.1-78.6 33.3 37.3 85 78.6 151.1 78.6 93.1 0 168.9-71.8 168.9-160S564.2 96 471.1 96zM168.9 320c-40.2 0-72.9-28.7-72.9-64s32.7-64 72.9-64c38.2 0 73.4 36.1 94 64-20.4 27.6-55.9 64-94 64zm302.2 0c-38.2 0-73.4-36.1-94-64 20.4-27.6 55.9-64 94-64 40.2 0 72.9 28.7 72.9 64s-32.7 64-72.9 64z\"]\n};\nvar faInfo = {\n prefix: 'fas',\n iconName: 'info',\n icon: [192, 512, [], \"f129\", \"M20 424.229h20V279.771H20c-11.046 0-20-8.954-20-20V212c0-11.046 8.954-20 20-20h112c11.046 0 20 8.954 20 20v212.229h20c11.046 0 20 8.954 20 20V492c0 11.046-8.954 20-20 20H20c-11.046 0-20-8.954-20-20v-47.771c0-11.046 8.954-20 20-20zM96 0C56.235 0 24 32.235 24 72s32.235 72 72 72 72-32.235 72-72S135.764 0 96 0z\"]\n};\nvar faInfoCircle = {\n prefix: 'fas',\n iconName: 'info-circle',\n icon: [512, 512, [], \"f05a\", \"M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z\"]\n};\nvar faItalic = {\n prefix: 'fas',\n iconName: 'italic',\n icon: [320, 512, [], \"f033\", \"M204.758 416h-33.849l62.092-320h40.725a16 16 0 0 0 15.704-12.937l6.242-32C297.599 41.184 290.034 32 279.968 32H120.235a16 16 0 0 0-15.704 12.937l-6.242 32C96.362 86.816 103.927 96 113.993 96h33.846l-62.09 320H46.278a16 16 0 0 0-15.704 12.935l-6.245 32C22.402 470.815 29.967 480 40.034 480h158.479a16 16 0 0 0 15.704-12.935l6.245-32c1.927-9.88-5.638-19.065-15.704-19.065z\"]\n};\nvar faJedi = {\n prefix: 'fas',\n iconName: 'jedi',\n icon: [544, 512, [], \"f669\", \"M479.99 352l58.88-58.87c3.29-16.8 5.13-34.12 5.13-51.86 0-5.81-.68-11.51-1.05-17.27H496l41.25-41.24c-14.5-64.79-52.43-123.05-107.91-162.27-2.77-1.96-5.97-2.99-9.25-2.99-5.37 0-10.41 2.71-13.49 7.24-3.05 4.49-3.64 9.99-1.61 15.09 6.55 16.46 9.86 33.73 9.86 51.31 0 45.12-21.03 86.57-57.69 113.73-4.02 2.98-6.46 7.5-6.7 12.4-.24 4.92 1.76 9.66 5.49 13.03 32.93 29.75 47.35 73.51 38.57 117.07-9.74 48.35-48.84 87.1-97.31 96.5l-2.5-65.34L321.88 397c2.98 2.06 7.39 1.69 10.02-.8a8.002 8.002 0 0 0 1.34-9.92l-20.11-33.73 42.07-8.72c3.7-.75 6.38-4.05 6.38-7.83 0-3.77-2.69-7.06-6.38-7.83l-42.07-8.73 20.13-33.77c1.92-3.23 1.34-7.31-1.38-9.91-2.7-2.55-6.97-2.89-10-.8l-30.39 20.67L279.96 7.7a7.964 7.964 0 0 0-8-7.7c-4.33 0-7.84 3.38-8 7.67l-11.52 287.97-30.39-20.66c-3.14-2.12-7.27-1.83-10 .78-2.72 2.59-3.3 6.67-1.36 9.94l20.11 33.73-42.07 8.73c-3.7.75-6.38 4.05-6.38 7.83s2.67 7.08 6.38 7.83l42.07 8.72-20.13 33.77c-1.92 3.23-1.34 7.33 1.39 9.94 2.59 2.45 7.03 2.75 10 .75l27.16-18.48-2.5 65.26c-56.94-11.64-99.89-61.89-99.89-121.92 0-35.08 14.62-67.6 41.17-91.58 3.72-3.36 5.72-8.11 5.48-13.01-.24-4.9-2.68-9.41-6.69-12.38-36.67-27.16-57.71-68.62-57.71-113.74 0-17.56 3.31-34.81 9.84-51.26 2.02-5.09 1.43-10.59-1.62-15.09-3.08-4.54-8.13-7.25-13.51-7.25-3.3 0-6.5 1.04-9.27 3-55.87 39.52-93.6 97.37-107.97 162.07L47.93 224H.72c-.63 9.92-.97 19.91-.5 29.99.62 13.43 2.54 26.53 5.11 39.41l58.6 58.6H24.02c41.25 90.23 131.13 154.94 235.1 159.71 4.3.2 8.59.29 12.85.29 110.34 0 205.35-65.83 247.98-160h-39.96z\"]\n};\nvar faJoint = {\n prefix: 'fas',\n iconName: 'joint',\n icon: [640, 512, [], \"f595\", \"M444.34 181.1c22.38 15.68 35.66 41.16 35.66 68.59V280c0 4.42 3.58 8 8 8h48c4.42 0 8-3.58 8-8v-30.31c0-43.24-21.01-83.41-56.34-108.06C463.85 125.02 448 99.34 448 70.31V8c0-4.42-3.58-8-8-8h-48c-4.42 0-8 3.58-8 8v66.4c0 43.69 24.56 81.63 60.34 106.7zM194.97 358.98C126.03 370.07 59.69 394.69 0 432c83.65 52.28 180.3 80 278.94 80h88.57L254.79 380.49c-14.74-17.2-37.45-25.11-59.82-21.51zM553.28 87.09c-5.67-3.8-9.28-9.96-9.28-16.78V8c0-4.42-3.58-8-8-8h-48c-4.42 0-8 3.58-8 8v62.31c0 22.02 10.17 43.41 28.64 55.39C550.79 153.04 576 199.54 576 249.69V280c0 4.42 3.58 8 8 8h48c4.42 0 8-3.58 8-8v-30.31c0-65.44-32.41-126.19-86.72-162.6zM360.89 352.05c-34.4.06-86.81.15-88.21.17l117.8 137.43A63.987 63.987 0 0 0 439.07 512h88.45L409.57 374.4a63.955 63.955 0 0 0-48.68-22.35zM616 352H432l117.99 137.65A63.987 63.987 0 0 0 598.58 512H616c13.25 0 24-10.75 24-24V376c0-13.26-10.75-24-24-24z\"]\n};\nvar faJournalWhills = {\n prefix: 'fas',\n iconName: 'journal-whills',\n icon: [448, 512, [], \"f66a\", \"M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM133.08 144.39l21.26 21.26c1.56 1.56 3.61 2.34 5.66 2.34s4.09-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-26.42-26.42c10-20.9 26.24-37.97 46.37-49.26C179.62 88.4 176 99.74 176 112c0 19.96 9.33 37.57 23.66 49.31C190.01 171.37 184 184.96 184 200c0 26.94 19.04 49.4 44.38 54.76l1.36-32.71-10.37 7.04c-.69.45-1.47.69-2.25.69-1 0-1.98-.38-2.75-1.09a4.006 4.006 0 0 1-.69-4.95l8.54-14.31-17.91-3.72c-1.86-.39-3.19-2.03-3.19-3.92s1.33-3.53 3.19-3.92l17.91-3.72-8.54-14.31c-.95-1.61-.67-3.67.69-4.95 1.36-1.3 3.44-1.44 5-.41l12.01 8.16L236 71.83c.09-2.14 1.86-3.83 4-3.83s3.91 1.69 4 3.83l4.68 112.29 14.2-9.65a4.067 4.067 0 0 1 5 .41 4.006 4.006 0 0 1 .69 4.95l-8.54 14.31 17.91 3.72c1.86.39 3.19 2.03 3.19 3.92s-1.33 3.53-3.19 3.92l-17.91 3.72 8.54 14.31c.95 1.61.67 3.67-.69 4.95-.77.72-1.77 1.09-2.75 1.09-.78 0-1.56-.23-2.25-.69l-12.68-8.62 1.43 34.28C276.96 249.4 296 226.94 296 200c0-15.04-6.01-28.63-15.66-38.69C294.67 149.57 304 131.96 304 112c0-12.26-3.62-23.6-9.6-33.33 20.13 11.28 36.37 28.36 46.37 49.26l-26.42 26.42c-3.12 3.12-3.12 8.19 0 11.31 1.56 1.56 3.61 2.34 5.66 2.34s4.09-.78 5.66-2.34l21.26-21.26c2.97 10.08 5.07 20.55 5.07 31.6 0 .52-.14.99-.15 1.51l-37.11 32.47a7.975 7.975 0 0 0-.75 11.28 7.97 7.97 0 0 0 6.02 2.73c1.88 0 3.75-.66 5.27-1.98l23.59-20.64C337.32 250.96 293.09 288 240 288s-97.32-37.04-108.86-86.62l23.59 20.64A7.957 7.957 0 0 0 160 224c2.22 0 4.44-.92 6.02-2.73 2.92-3.33 2.58-8.38-.75-11.28l-37.11-32.47c-.01-.52-.15-.99-.15-1.51-.01-11.06 2.09-21.53 5.07-31.62zM380.8 448H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8v64z\"]\n};\nvar faKaaba = {\n prefix: 'fas',\n iconName: 'kaaba',\n icon: [576, 512, [], \"f66b\", \"M554.12 83.51L318.36 4.93a95.962 95.962 0 0 0-60.71 0L21.88 83.51A32.006 32.006 0 0 0 0 113.87v49.01l265.02-79.51c15.03-4.5 30.92-4.5 45.98 0l265 79.51v-49.01c0-13.77-8.81-26-21.88-30.36zm-279.9 30.52L0 196.3v228.38c0 15 10.42 27.98 25.06 31.24l242.12 53.8a95.937 95.937 0 0 0 41.65 0l242.12-53.8c14.64-3.25 25.06-16.24 25.06-31.24V196.29l-274.2-82.26c-9.04-2.72-18.59-2.72-27.59 0zM128 230.11c0 3.61-2.41 6.77-5.89 7.72l-80 21.82C37.02 261.03 32 257.2 32 251.93v-16.58c0-3.61 2.41-6.77 5.89-7.72l80-21.82c5.09-1.39 10.11 2.44 10.11 7.72v16.58zm144-39.28c0 3.61-2.41 6.77-5.89 7.72l-96 26.18c-5.09 1.39-10.11-2.44-10.11-7.72v-16.58c0-3.61 2.41-6.77 5.89-7.72l96-26.18c5.09-1.39 10.11 2.44 10.11 7.72v16.58zm176 22.7c0-5.28 5.02-9.11 10.11-7.72l80 21.82c3.48.95 5.89 4.11 5.89 7.72v16.58c0 5.28-5.02 9.11-10.11 7.72l-80-21.82a7.997 7.997 0 0 1-5.89-7.72v-16.58zm-144-39.27c0-5.28 5.02-9.11 10.11-7.72l96 26.18c3.48.95 5.89 4.11 5.89 7.72v16.58c0 5.28-5.02 9.11-10.11 7.72l-96-26.18a7.997 7.997 0 0 1-5.89-7.72v-16.58z\"]\n};\nvar faKey = {\n prefix: 'fas',\n iconName: 'key',\n icon: [512, 512, [], \"f084\", \"M512 176.001C512 273.203 433.202 352 336 352c-11.22 0-22.19-1.062-32.827-3.069l-24.012 27.014A23.999 23.999 0 0 1 261.223 384H224v40c0 13.255-10.745 24-24 24h-40v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-78.059c0-6.365 2.529-12.47 7.029-16.971l161.802-161.802C163.108 213.814 160 195.271 160 176 160 78.798 238.797.001 335.999 0 433.488-.001 512 78.511 512 176.001zM336 128c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48-48 21.49-48 48z\"]\n};\nvar faKeyboard = {\n prefix: 'fas',\n iconName: 'keyboard',\n icon: [576, 512, [], \"f11c\", \"M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z\"]\n};\nvar faKhanda = {\n prefix: 'fas',\n iconName: 'khanda',\n icon: [512, 512, [], \"f66d\", \"M415.81 66c-6.37-3.5-14.37-2.33-19.36 3.02a15.974 15.974 0 0 0-1.91 19.52c16.49 26.16 25.2 56.39 25.2 87.41-.19 53.25-26.77 102.69-71.27 132.41l-76.63 53.35v-20.1l44.05-36.09c3.92-4.2 5-10.09 2.81-15.28L310.85 273c33.84-19.26 56.94-55.25 56.94-96.99 0-40.79-22.02-76.13-54.59-95.71l5.22-11.44c2.34-5.53.93-11.83-3.57-16.04L255.86 0l-58.99 52.81c-4.5 4.21-5.9 10.51-3.57 16.04l5.22 11.44c-32.57 19.58-54.59 54.93-54.59 95.72 0 41.75 23.09 77.73 56.94 96.99l-7.85 17.24c-2.19 5.18-1.1 11.07 2.81 15.28l44.05 36.09v19.9l-76.59-53.33C119.02 278.62 92.44 229.19 92.26 176c0-31.08 8.71-61.31 25.2-87.47 3.87-6.16 2.4-13.77-2.59-19.08-5-5.34-13.68-6.2-20.02-2.7C16.32 109.6-22.3 205.3 13.36 295.99c7.07 17.99 17.89 34.38 30.46 49.06l55.97 65.36c4.87 5.69 13.04 7.24 19.65 3.72l79.35-42.23L228 392.23l-47.08 32.78c-1.67-.37-3.23-1.01-5.01-1.01-13.25 0-23.99 10.74-23.99 24 0 13.25 10.74 24 23.99 24 12.1 0 21.69-9.11 23.33-20.76l40.63-28.28v29.95c-9.39 5.57-15.99 15.38-15.99 27.1 0 17.67 14.32 32 31.98 32s31.98-14.33 31.98-32c0-11.71-6.61-21.52-15.99-27.1v-30.15l40.91 28.48C314.41 462.89 324 472 336.09 472c13.25 0 23.99-10.75 23.99-24 0-13.26-10.74-24-23.99-24-1.78 0-3.34.64-5.01 1.01L284 392.23l29.21-20.34 79.35 42.23c6.61 3.52 14.78 1.97 19.65-3.71l52.51-61.31c18.87-22.02 34-47.5 41.25-75.59 21.62-83.66-16.45-167.27-90.16-207.51zm-95.99 110c0 22.3-11.49 41.92-28.83 53.38l-5.65-12.41c-8.75-24.52-8.75-51.04 0-75.56l7.83-17.18c16.07 11.65 26.65 30.45 26.65 51.77zm-127.93 0c0-21.32 10.58-40.12 26.66-51.76l7.83 17.18c8.75 24.52 8.75 51.03 0 75.56l-5.65 12.41c-17.34-11.46-28.84-31.09-28.84-53.39z\"]\n};\nvar faKiss = {\n prefix: 'fas',\n iconName: 'kiss',\n icon: [496, 512, [], \"f596\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm-80 232c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm136 156c0 19.2-28.7 41.5-71.5 44-8.5.8-12.1-11.8-3.6-15.4l17-7.2c13-5.5 20.8-13.5 20.8-21.5s-7.8-16-20.8-21.5l-17-7.2c-6-2.5-6.1-12.2 0-14.8l17-7.2c13-5.5 20.8-13.5 20.8-21.5s-7.8-16-20.8-21.5l-17-7.2c-8.6-3.6-4.8-16.5 3.6-15.4 42.8 2.5 71.5 24.8 71.5 44 0 13-13.4 27.3-35.2 36C290.6 368.7 304 383 304 396zm24-156c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faKissBeam = {\n prefix: 'fas',\n iconName: 'kiss-beam',\n icon: [496, 512, [], \"f597\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm-39 219.9l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.2 7.4-15.6 4-14.9-4.5 3.3-42.1 32.2-71.4 56-71.4s52.7 29.3 56 71.4c.5 8.5-10.9 12-15.1 4.5zM304 396c0 19.2-28.7 41.5-71.5 44-8.5.8-12.1-11.8-3.6-15.4l17-7.2c13-5.5 20.8-13.5 20.8-21.5s-7.8-16-20.8-21.5l-17-7.2c-6-2.5-6.1-12.2 0-14.8l17-7.2c13-5.5 20.8-13.5 20.8-21.5s-7.8-16-20.8-21.5l-17-7.2c-8.6-3.6-4.8-16.5 3.6-15.4 42.8 2.5 71.5 24.8 71.5 44 0 13-13.4 27.3-35.2 36C290.6 368.7 304 383 304 396zm65-168.1l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.1 7.3-15.6 4-14.9-4.5 3.3-42.1 32.2-71.4 56-71.4s52.7 29.3 56 71.4c.5 8.5-10.9 12-15.1 4.5z\"]\n};\nvar faKissWinkHeart = {\n prefix: 'fas',\n iconName: 'kiss-wink-heart',\n icon: [504, 512, [], \"f598\", \"M501.1 402.5c-8-20.8-31.5-31.5-53.1-25.9l-8.4 2.2-2.3-8.4c-5.9-21.4-27-36.5-49-33-25.2 4-40.6 28.6-34 52.6l22.9 82.6c1.5 5.3 7 8.5 12.4 7.1l83-21.5c24.1-6.3 37.7-31.8 28.5-55.7zm-177.6-4c-5.6-20.3-2.3-42 9-59.7 29.7-46.3 98.7-45.5 127.8 4.3 6.4.1 12.6 1.4 18.6 2.9 10.9-27.9 17.1-58.2 17.1-90C496 119 385 8 248 8S0 119 0 256s111 248 248 248c35.4 0 68.9-7.5 99.4-20.9-.3-.7-23.9-84.6-23.9-84.6zM168 240c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm120 156c0 19.2-28.7 41.5-71.5 44-8.5.8-12.1-11.8-3.6-15.4l17-7.2c13-5.5 20.8-13.5 20.8-21.5s-7.8-16-20.8-21.5l-17-7.2c-6-2.5-5.7-12.3 0-14.8l17-7.2c13-5.5 20.8-13.5 20.8-21.5s-7.8-16-20.8-21.5l-17-7.2c-8.8-3.7-4.6-16.6 3.6-15.4 42.8 2.5 71.5 24.8 71.5 44 0 13-13.4 27.3-35.2 36C274.6 368.7 288 383 288 396zm16-179c-8.3 7.4-21.6.4-19.8-10.8 4-25.2 34.2-42.1 59.9-42.1S400 181 404 206.2c1.7 11.1-11.3 18.3-19.8 10.8l-9.5-8.5c-14.8-13.2-46.2-13.2-61 0L304 217z\"]\n};\nvar faKiwiBird = {\n prefix: 'fas',\n iconName: 'kiwi-bird',\n icon: [576, 512, [], \"f535\", \"M575.81 217.98C572.64 157.41 518.28 112 457.63 112h-9.37c-52.82 0-104.25-16.25-147.74-46.24-41.99-28.96-96.04-41.62-153.21-28.7C129.3 41.12-.08 78.24 0 224c.04 70.95 38.68 132.8 95.99 166.01V464c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16v-54.26c15.36 3.96 31.4 6.26 48 6.26 5.44 0 10.68-.73 16-1.18V464c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16v-59.43c14.24-5.06 27.88-11.39 40.34-19.51C342.07 355.25 393.86 336 448.46 336c25.48 0 16.01-.31 23.05-.78l74.41 136.44c2.86 5.23 8.3 8.34 14.05 8.34 1.31 0 2.64-.16 3.95-.5 7.09-1.8 12.05-8.19 12.05-15.5 0 0 .14-240.24-.16-246.02zM463.97 248c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24zm80 153.25l-39.86-73.08c15.12-5.83 28.73-14.6 39.86-25.98v99.06z\"]\n};\nvar faLandmark = {\n prefix: 'fas',\n iconName: 'landmark',\n icon: [512, 512, [], \"f66f\", \"M501.62 92.11L267.24 2.04a31.958 31.958 0 0 0-22.47 0L10.38 92.11A16.001 16.001 0 0 0 0 107.09V144c0 8.84 7.16 16 16 16h480c8.84 0 16-7.16 16-16v-36.91c0-6.67-4.14-12.64-10.38-14.98zM64 192v160H48c-8.84 0-16 7.16-16 16v48h448v-48c0-8.84-7.16-16-16-16h-16V192h-64v160h-96V192h-64v160h-96V192H64zm432 256H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h480c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16z\"]\n};\nvar faLanguage = {\n prefix: 'fas',\n iconName: 'language',\n icon: [640, 512, [], \"f1ab\", \"M152.1 236.2c-3.5-12.1-7.8-33.2-7.8-33.2h-.5s-4.3 21.1-7.8 33.2l-11.1 37.5H163zM616 96H336v320h280c13.3 0 24-10.7 24-24V120c0-13.3-10.7-24-24-24zm-24 120c0 6.6-5.4 12-12 12h-11.4c-6.9 23.6-21.7 47.4-42.7 69.9 8.4 6.4 17.1 12.5 26.1 18 5.5 3.4 7.3 10.5 4.1 16.2l-7.9 13.9c-3.4 5.9-10.9 7.8-16.7 4.3-12.6-7.8-24.5-16.1-35.4-24.9-10.9 8.7-22.7 17.1-35.4 24.9-5.8 3.5-13.3 1.6-16.7-4.3l-7.9-13.9c-3.2-5.6-1.4-12.8 4.2-16.2 9.3-5.7 18-11.7 26.1-18-7.9-8.4-14.9-17-21-25.7-4-5.7-2.2-13.6 3.7-17.1l6.5-3.9 7.3-4.3c5.4-3.2 12.4-1.7 16 3.4 5 7 10.8 14 17.4 20.9 13.5-14.2 23.8-28.9 30-43.2H412c-6.6 0-12-5.4-12-12v-16c0-6.6 5.4-12 12-12h64v-16c0-6.6 5.4-12 12-12h16c6.6 0 12 5.4 12 12v16h64c6.6 0 12 5.4 12 12zM0 120v272c0 13.3 10.7 24 24 24h280V96H24c-13.3 0-24 10.7-24 24zm58.9 216.1L116.4 167c1.7-4.9 6.2-8.1 11.4-8.1h32.5c5.1 0 9.7 3.3 11.4 8.1l57.5 169.1c2.6 7.8-3.1 15.9-11.4 15.9h-22.9a12 12 0 0 1-11.5-8.6l-9.4-31.9h-60.2l-9.1 31.8c-1.5 5.1-6.2 8.7-11.5 8.7H70.3c-8.2 0-14-8.1-11.4-15.9z\"]\n};\nvar faLaptop = {\n prefix: 'fas',\n iconName: 'laptop',\n icon: [640, 512, [], \"f109\", \"M624 416H381.54c-.74 19.81-14.71 32-32.74 32H288c-18.69 0-33.02-17.47-32.77-32H16c-8.8 0-16 7.2-16 16v16c0 35.2 28.8 64 64 64h512c35.2 0 64-28.8 64-64v-16c0-8.8-7.2-16-16-16zM576 48c0-26.4-21.6-48-48-48H112C85.6 0 64 21.6 64 48v336h512V48zm-64 272H128V64h384v256z\"]\n};\nvar faLaptopCode = {\n prefix: 'fas',\n iconName: 'laptop-code',\n icon: [640, 512, [], \"f5fc\", \"M255.03 261.65c6.25 6.25 16.38 6.25 22.63 0l11.31-11.31c6.25-6.25 6.25-16.38 0-22.63L253.25 192l35.71-35.72c6.25-6.25 6.25-16.38 0-22.63l-11.31-11.31c-6.25-6.25-16.38-6.25-22.63 0l-58.34 58.34c-6.25 6.25-6.25 16.38 0 22.63l58.35 58.34zm96.01-11.3l11.31 11.31c6.25 6.25 16.38 6.25 22.63 0l58.34-58.34c6.25-6.25 6.25-16.38 0-22.63l-58.34-58.34c-6.25-6.25-16.38-6.25-22.63 0l-11.31 11.31c-6.25 6.25-6.25 16.38 0 22.63L386.75 192l-35.71 35.72c-6.25 6.25-6.25 16.38 0 22.63zM624 416H381.54c-.74 19.81-14.71 32-32.74 32H288c-18.69 0-33.02-17.47-32.77-32H16c-8.8 0-16 7.2-16 16v16c0 35.2 28.8 64 64 64h512c35.2 0 64-28.8 64-64v-16c0-8.8-7.2-16-16-16zM576 48c0-26.4-21.6-48-48-48H112C85.6 0 64 21.6 64 48v336h512V48zm-64 272H128V64h384v256z\"]\n};\nvar faLaptopMedical = {\n prefix: 'fas',\n iconName: 'laptop-medical',\n icon: [640, 512, [], \"f812\", \"M232 224h56v56a8 8 0 0 0 8 8h48a8 8 0 0 0 8-8v-56h56a8 8 0 0 0 8-8v-48a8 8 0 0 0-8-8h-56v-56a8 8 0 0 0-8-8h-48a8 8 0 0 0-8 8v56h-56a8 8 0 0 0-8 8v48a8 8 0 0 0 8 8zM576 48a48.14 48.14 0 0 0-48-48H112a48.14 48.14 0 0 0-48 48v336h512zm-64 272H128V64h384zm112 96H381.54c-.74 19.81-14.71 32-32.74 32H288c-18.69 0-33-17.47-32.77-32H16a16 16 0 0 0-16 16v16a64.19 64.19 0 0 0 64 64h512a64.19 64.19 0 0 0 64-64v-16a16 16 0 0 0-16-16z\"]\n};\nvar faLaugh = {\n prefix: 'fas',\n iconName: 'laugh',\n icon: [496, 512, [], \"f599\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 152c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm88 272h-16c-73.4 0-134-55-142.9-126-1.2-9.5 6.3-18 15.9-18h270c9.6 0 17.1 8.4 15.9 18-8.9 71-69.5 126-142.9 126z\"]\n};\nvar faLaughBeam = {\n prefix: 'fas',\n iconName: 'laugh-beam',\n icon: [496, 512, [], \"f59a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm24 199.4c3.3-42.1 32.2-71.4 56-71.4s52.7 29.3 56 71.4c.7 8.6-10.8 11.9-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.2 7.4-15.8 4.1-15.1-4.5zm-160 0c3.3-42.1 32.2-71.4 56-71.4s52.7 29.3 56 71.4c.7 8.6-10.8 11.9-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.3 7.4-15.8 4-15.1-4.5zM398.9 306C390 377 329.4 432 256 432h-16c-73.4 0-134-55-142.9-126-1.2-9.5 6.3-18 15.9-18h270c9.6 0 17.1 8.4 15.9 18z\"]\n};\nvar faLaughSquint = {\n prefix: 'fas',\n iconName: 'laugh-squint',\n icon: [496, 512, [], \"f59b\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm33.8 161.7l80-48c11.6-6.9 24 7.7 15.4 18L343.6 180l33.6 40.3c8.7 10.4-3.9 24.8-15.4 18l-80-48c-7.7-4.7-7.7-15.9 0-20.6zm-163-30c-8.6-10.3 3.8-24.9 15.4-18l80 48c7.8 4.7 7.8 15.9 0 20.6l-80 48c-11.5 6.8-24-7.6-15.4-18l33.6-40.3-33.6-40.3zM398.9 306C390 377 329.4 432 256 432h-16c-73.4 0-134-55-142.9-126-1.2-9.5 6.3-18 15.9-18h270c9.6 0 17.1 8.4 15.9 18z\"]\n};\nvar faLaughWink = {\n prefix: 'fas',\n iconName: 'laugh-wink',\n icon: [496, 512, [], \"f59c\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm20.1 198.1c4-25.2 34.2-42.1 59.9-42.1s55.9 16.9 59.9 42.1c1.7 11.1-11.4 18.3-19.8 10.8l-9.5-8.5c-14.8-13.2-46.2-13.2-61 0L288 217c-8.4 7.4-21.6.3-19.9-10.9zM168 160c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm230.9 146C390 377 329.4 432 256 432h-16c-73.4 0-134-55-142.9-126-1.2-9.5 6.3-18 15.9-18h270c9.6 0 17.1 8.4 15.9 18z\"]\n};\nvar faLayerGroup = {\n prefix: 'fas',\n iconName: 'layer-group',\n icon: [512, 512, [], \"f5fd\", \"M12.41 148.02l232.94 105.67c6.8 3.09 14.49 3.09 21.29 0l232.94-105.67c16.55-7.51 16.55-32.52 0-40.03L266.65 2.31a25.607 25.607 0 0 0-21.29 0L12.41 107.98c-16.55 7.51-16.55 32.53 0 40.04zm487.18 88.28l-58.09-26.33-161.64 73.27c-7.56 3.43-15.59 5.17-23.86 5.17s-16.29-1.74-23.86-5.17L70.51 209.97l-58.1 26.33c-16.55 7.5-16.55 32.5 0 40l232.94 105.59c6.8 3.08 14.49 3.08 21.29 0L499.59 276.3c16.55-7.5 16.55-32.5 0-40zm0 127.8l-57.87-26.23-161.86 73.37c-7.56 3.43-15.59 5.17-23.86 5.17s-16.29-1.74-23.86-5.17L70.29 337.87 12.41 364.1c-16.55 7.5-16.55 32.5 0 40l232.94 105.59c6.8 3.08 14.49 3.08 21.29 0L499.59 404.1c16.55-7.5 16.55-32.5 0-40z\"]\n};\nvar faLeaf = {\n prefix: 'fas',\n iconName: 'leaf',\n icon: [576, 512, [], \"f06c\", \"M546.2 9.7c-5.6-12.5-21.6-13-28.3-1.2C486.9 62.4 431.4 96 368 96h-80C182 96 96 182 96 288c0 7 .8 13.7 1.5 20.5C161.3 262.8 253.4 224 384 224c8.8 0 16 7.2 16 16s-7.2 16-16 16C132.6 256 26 410.1 2.4 468c-6.6 16.3 1.2 34.9 17.5 41.6 16.4 6.8 35-1.1 41.8-17.3 1.5-3.6 20.9-47.9 71.9-90.6 32.4 43.9 94 85.8 174.9 77.2C465.5 467.5 576 326.7 576 154.3c0-50.2-10.8-102.2-29.8-144.6z\"]\n};\nvar faLemon = {\n prefix: 'fas',\n iconName: 'lemon',\n icon: [512, 512, [], \"f094\", \"M489.038 22.963C465.944-.13 434.648-5.93 413.947 6.129c-58.906 34.312-181.25-53.077-321.073 86.746S40.441 355.041 6.129 413.945c-12.059 20.702-6.26 51.999 16.833 75.093 23.095 23.095 54.392 28.891 75.095 16.832 58.901-34.31 181.246 53.079 321.068-86.743S471.56 156.96 505.871 98.056c12.059-20.702 6.261-51.999-16.833-75.093zM243.881 95.522c-58.189 14.547-133.808 90.155-148.358 148.358-1.817 7.27-8.342 12.124-15.511 12.124-1.284 0-2.59-.156-3.893-.481-8.572-2.144-13.784-10.83-11.642-19.403C81.901 166.427 166.316 81.93 236.119 64.478c8.575-2.143 17.261 3.069 19.403 11.642s-3.069 17.259-11.641 19.402z\"]\n};\nvar faLessThan = {\n prefix: 'fas',\n iconName: 'less-than',\n icon: [384, 512, [], \"f536\", \"M365.46 357.74L147.04 255.89l218.47-101.88c16.02-7.47 22.95-26.51 15.48-42.53l-13.52-29C360 66.46 340.96 59.53 324.94 67L18.48 209.91a32.014 32.014 0 0 0-18.48 29v34.24c0 12.44 7.21 23.75 18.48 29l306.31 142.83c16.06 7.49 35.15.54 42.64-15.52l13.56-29.08c7.49-16.06.54-35.15-15.53-42.64z\"]\n};\nvar faLessThanEqual = {\n prefix: 'fas',\n iconName: 'less-than-equal',\n icon: [448, 512, [], \"f537\", \"M54.98 214.2l301.41 119.87c18.39 6.03 38.71-2.54 45.38-19.15l12.09-30.08c6.68-16.61-2.82-34.97-21.21-41l-175.44-68.05 175.56-68.09c18.29-6 27.74-24.27 21.1-40.79l-12.03-29.92c-6.64-16.53-26.86-25.06-45.15-19.06L54.98 137.89C41.21 142.41 32 154.5 32 168.07v15.96c0 13.56 9.21 25.65 22.98 30.17zM424 400H24c-13.25 0-24 10.74-24 24v48c0 13.25 10.75 24 24 24h400c13.25 0 24-10.75 24-24v-48c0-13.26-10.75-24-24-24z\"]\n};\nvar faLevelDownAlt = {\n prefix: 'fas',\n iconName: 'level-down-alt',\n icon: [320, 512, [], \"f3be\", \"M313.553 392.331L209.587 504.334c-9.485 10.214-25.676 10.229-35.174 0L70.438 392.331C56.232 377.031 67.062 352 88.025 352H152V80H68.024a11.996 11.996 0 0 1-8.485-3.515l-56-56C-4.021 12.926 1.333 0 12.024 0H208c13.255 0 24 10.745 24 24v328h63.966c20.878 0 31.851 24.969 17.587 40.331z\"]\n};\nvar faLevelUpAlt = {\n prefix: 'fas',\n iconName: 'level-up-alt',\n icon: [320, 512, [], \"f3bf\", \"M313.553 119.669L209.587 7.666c-9.485-10.214-25.676-10.229-35.174 0L70.438 119.669C56.232 134.969 67.062 160 88.025 160H152v272H68.024a11.996 11.996 0 0 0-8.485 3.515l-56 56C-4.021 499.074 1.333 512 12.024 512H208c13.255 0 24-10.745 24-24V160h63.966c20.878 0 31.851-24.969 17.587-40.331z\"]\n};\nvar faLifeRing = {\n prefix: 'fas',\n iconName: 'life-ring',\n icon: [512, 512, [], \"f1cd\", \"M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm173.696 119.559l-63.399 63.399c-10.987-18.559-26.67-34.252-45.255-45.255l63.399-63.399a218.396 218.396 0 0 1 45.255 45.255zM256 352c-53.019 0-96-42.981-96-96s42.981-96 96-96 96 42.981 96 96-42.981 96-96 96zM127.559 82.304l63.399 63.399c-18.559 10.987-34.252 26.67-45.255 45.255l-63.399-63.399a218.372 218.372 0 0 1 45.255-45.255zM82.304 384.441l63.399-63.399c10.987 18.559 26.67 34.252 45.255 45.255l-63.399 63.399a218.396 218.396 0 0 1-45.255-45.255zm302.137 45.255l-63.399-63.399c18.559-10.987 34.252-26.67 45.255-45.255l63.399 63.399a218.403 218.403 0 0 1-45.255 45.255z\"]\n};\nvar faLightbulb = {\n prefix: 'fas',\n iconName: 'lightbulb',\n icon: [352, 512, [], \"f0eb\", \"M96.06 454.35c.01 6.29 1.87 12.45 5.36 17.69l17.09 25.69a31.99 31.99 0 0 0 26.64 14.28h61.71a31.99 31.99 0 0 0 26.64-14.28l17.09-25.69a31.989 31.989 0 0 0 5.36-17.69l.04-38.35H96.01l.05 38.35zM0 176c0 44.37 16.45 84.85 43.56 115.78 16.52 18.85 42.36 58.23 52.21 91.45.04.26.07.52.11.78h160.24c.04-.26.07-.51.11-.78 9.85-33.22 35.69-72.6 52.21-91.45C335.55 260.85 352 220.37 352 176 352 78.61 272.91-.3 175.45 0 73.44.31 0 82.97 0 176zm176-80c-44.11 0-80 35.89-80 80 0 8.84-7.16 16-16 16s-16-7.16-16-16c0-61.76 50.24-112 112-112 8.84 0 16 7.16 16 16s-7.16 16-16 16z\"]\n};\nvar faLink = {\n prefix: 'fas',\n iconName: 'link',\n icon: [512, 512, [], \"f0c1\", \"M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z\"]\n};\nvar faLiraSign = {\n prefix: 'fas',\n iconName: 'lira-sign',\n icon: [384, 512, [], \"f195\", \"M371.994 256h-48.019C317.64 256 312 260.912 312 267.246 312 368 230.179 416 144 416V256.781l134.603-29.912A12 12 0 0 0 288 215.155v-40.976c0-7.677-7.109-13.38-14.603-11.714L144 191.219V160.78l134.603-29.912A12 12 0 0 0 288 119.154V78.179c0-7.677-7.109-13.38-14.603-11.714L144 95.219V44c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v68.997L9.397 125.131A12 12 0 0 0 0 136.845v40.976c0 7.677 7.109 13.38 14.603 11.714L64 178.558v30.439L9.397 221.131A12 12 0 0 0 0 232.845v40.976c0 7.677 7.109 13.38 14.603 11.714L64 274.558V468c0 6.627 5.373 12 12 12h79.583c134.091 0 223.255-77.834 228.408-211.592.261-6.782-5.211-12.408-11.997-12.408z\"]\n};\nvar faList = {\n prefix: 'fas',\n iconName: 'list',\n icon: [512, 512, [], \"f03a\", \"M128 116V76c0-8.837 7.163-16 16-16h352c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H144c-8.837 0-16-7.163-16-16zm16 176h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM16 144h64c8.837 0 16-7.163 16-16V64c0-8.837-7.163-16-16-16H16C7.163 48 0 55.163 0 64v64c0 8.837 7.163 16 16 16zm0 160h64c8.837 0 16-7.163 16-16v-64c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16zm0 160h64c8.837 0 16-7.163 16-16v-64c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16z\"]\n};\nvar faListAlt = {\n prefix: 'fas',\n iconName: 'list-alt',\n icon: [512, 512, [], \"f022\", \"M464 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zM128 120c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm0 96c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm0 96c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm288-136v-32c0-6.627-5.373-12-12-12H204c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h200c6.627 0 12-5.373 12-12zm0 96v-32c0-6.627-5.373-12-12-12H204c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h200c6.627 0 12-5.373 12-12zm0 96v-32c0-6.627-5.373-12-12-12H204c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h200c6.627 0 12-5.373 12-12z\"]\n};\nvar faListOl = {\n prefix: 'fas',\n iconName: 'list-ol',\n icon: [512, 512, [], \"f0cb\", \"M3.263 139.527c0-7.477 3.917-11.572 11.573-11.572h15.131V88.078c0-5.163.534-10.503.534-10.503h-.356s-1.779 2.67-2.848 3.738c-4.451 4.273-10.504 4.451-15.666-1.068l-5.518-6.231c-5.342-5.341-4.984-11.216.534-16.379l21.72-19.938C32.815 33.602 36.732 32 42.785 32H54.89c7.656 0 11.749 3.916 11.749 11.572v84.384h15.488c7.655 0 11.572 4.094 11.572 11.572v8.901c0 7.477-3.917 11.572-11.572 11.572H14.836c-7.656 0-11.573-4.095-11.573-11.572v-8.902zM2.211 304.591c0-47.278 50.955-56.383 50.955-69.165 0-7.18-5.954-8.755-9.28-8.755-3.153 0-6.479 1.051-9.455 3.852-5.079 4.903-10.507 7.004-16.111 2.451l-8.579-6.829c-5.779-4.553-7.18-9.805-2.803-15.409C13.592 201.981 26.025 192 47.387 192c19.437 0 44.476 10.506 44.476 39.573 0 38.347-46.753 46.402-48.679 56.909h39.049c7.529 0 11.557 4.027 11.557 11.382v8.755c0 7.354-4.028 11.382-11.557 11.382h-67.94c-7.005 0-12.083-4.028-12.083-11.382v-4.028zM5.654 454.61l5.603-9.28c3.853-6.654 9.105-7.004 15.584-3.152 4.903 2.101 9.63 3.152 14.359 3.152 10.155 0 14.358-3.502 14.358-8.23 0-6.654-5.604-9.106-15.934-9.106h-4.728c-5.954 0-9.28-2.101-12.258-7.88l-1.05-1.926c-2.451-4.728-1.226-9.806 2.801-14.884l5.604-7.004c6.829-8.405 12.257-13.483 12.257-13.483v-.35s-4.203 1.051-12.608 1.051H16.685c-7.53 0-11.383-4.028-11.383-11.382v-8.755c0-7.53 3.853-11.382 11.383-11.382h58.484c7.529 0 11.382 4.027 11.382 11.382v3.327c0 5.778-1.401 9.806-5.079 14.183l-17.509 20.137c19.611 5.078 28.716 20.487 28.716 34.845 0 21.363-14.358 44.126-48.503 44.126-16.636 0-28.192-4.728-35.896-9.455-5.779-4.202-6.304-9.805-2.626-15.934zM144 132h352c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z\"]\n};\nvar faListUl = {\n prefix: 'fas',\n iconName: 'list-ul',\n icon: [512, 512, [], \"f0ca\", \"M96 96c0 26.51-21.49 48-48 48S0 122.51 0 96s21.49-48 48-48 48 21.49 48 48zM48 208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm0 160c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm96-236h352c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z\"]\n};\nvar faLocationArrow = {\n prefix: 'fas',\n iconName: 'location-arrow',\n icon: [512, 512, [], \"f124\", \"M444.52 3.52L28.74 195.42c-47.97 22.39-31.98 92.75 19.19 92.75h175.91v175.91c0 51.17 70.36 67.17 92.75 19.19l191.9-415.78c15.99-38.39-25.59-79.97-63.97-63.97z\"]\n};\nvar faLock = {\n prefix: 'fas',\n iconName: 'lock',\n icon: [448, 512, [], \"f023\", \"M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z\"]\n};\nvar faLockOpen = {\n prefix: 'fas',\n iconName: 'lock-open',\n icon: [576, 512, [], \"f3c1\", \"M423.5 0C339.5.3 272 69.5 272 153.5V224H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48h-48v-71.1c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v80c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-80C576 68 507.5-.3 423.5 0z\"]\n};\nvar faLongArrowAltDown = {\n prefix: 'fas',\n iconName: 'long-arrow-alt-down',\n icon: [256, 512, [], \"f309\", \"M168 345.941V44c0-6.627-5.373-12-12-12h-56c-6.627 0-12 5.373-12 12v301.941H41.941c-21.382 0-32.09 25.851-16.971 40.971l86.059 86.059c9.373 9.373 24.569 9.373 33.941 0l86.059-86.059c15.119-15.119 4.411-40.971-16.971-40.971H168z\"]\n};\nvar faLongArrowAltLeft = {\n prefix: 'fas',\n iconName: 'long-arrow-alt-left',\n icon: [448, 512, [], \"f30a\", \"M134.059 296H436c6.627 0 12-5.373 12-12v-56c0-6.627-5.373-12-12-12H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.569 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296z\"]\n};\nvar faLongArrowAltRight = {\n prefix: 'fas',\n iconName: 'long-arrow-alt-right',\n icon: [448, 512, [], \"f30b\", \"M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z\"]\n};\nvar faLongArrowAltUp = {\n prefix: 'fas',\n iconName: 'long-arrow-alt-up',\n icon: [256, 512, [], \"f30c\", \"M88 166.059V468c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12V166.059h46.059c21.382 0 32.09-25.851 16.971-40.971l-86.059-86.059c-9.373-9.373-24.569-9.373-33.941 0l-86.059 86.059c-15.119 15.119-4.411 40.971 16.971 40.971H88z\"]\n};\nvar faLowVision = {\n prefix: 'fas',\n iconName: 'low-vision',\n icon: [576, 512, [], \"f2a8\", \"M569.344 231.631C512.96 135.949 407.81 72 288 72c-28.468 0-56.102 3.619-82.451 10.409L152.778 10.24c-7.601-10.858-22.564-13.5-33.423-5.9l-13.114 9.178c-10.86 7.601-13.502 22.566-5.9 33.426l43.131 58.395C89.449 131.73 40.228 174.683 6.682 231.581c-.01.017-.023.033-.034.05-8.765 14.875-8.964 33.528 0 48.739 38.5 65.332 99.742 115.862 172.859 141.349L55.316 244.302A272.194 272.194 0 0 1 83.61 208.39l119.4 170.58h.01l40.63 58.04a330.055 330.055 0 0 0 78.94 1.17l-189.98-271.4a277.628 277.628 0 0 1 38.777-21.563l251.836 356.544c7.601 10.858 22.564 13.499 33.423 5.9l13.114-9.178c10.86-7.601 13.502-22.567 5.9-33.426l-43.12-58.377-.007-.009c57.161-27.978 104.835-72.04 136.81-126.301a47.938 47.938 0 0 0 .001-48.739zM390.026 345.94l-19.066-27.23c24.682-32.567 27.711-76.353 8.8-111.68v.03c0 23.65-19.17 42.82-42.82 42.82-23.828 0-42.82-19.349-42.82-42.82 0-23.65 19.17-42.82 42.82-42.82h.03c-24.75-13.249-53.522-15.643-79.51-7.68l-19.068-27.237C253.758 123.306 270.488 120 288 120c75.162 0 136 60.826 136 136 0 34.504-12.833 65.975-33.974 89.94z\"]\n};\nvar faLuggageCart = {\n prefix: 'fas',\n iconName: 'luggage-cart',\n icon: [640, 512, [], \"f59d\", \"M224 320h32V96h-32c-17.67 0-32 14.33-32 32v160c0 17.67 14.33 32 32 32zm352-32V128c0-17.67-14.33-32-32-32h-32v224h32c17.67 0 32-14.33 32-32zm48 96H128V16c0-8.84-7.16-16-16-16H16C7.16 0 0 7.16 0 16v32c0 8.84 7.16 16 16 16h48v368c0 8.84 7.16 16 16 16h82.94c-1.79 5.03-2.94 10.36-2.94 16 0 26.51 21.49 48 48 48s48-21.49 48-48c0-5.64-1.15-10.97-2.94-16h197.88c-1.79 5.03-2.94 10.36-2.94 16 0 26.51 21.49 48 48 48s48-21.49 48-48c0-5.64-1.15-10.97-2.94-16H624c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM480 96V48c0-26.51-21.49-48-48-48h-96c-26.51 0-48 21.49-48 48v272h192V96zm-48 0h-96V48h96v48z\"]\n};\nvar faMagic = {\n prefix: 'fas',\n iconName: 'magic',\n icon: [512, 512, [], \"f0d0\", \"M224 96l16-32 32-16-32-16-16-32-16 32-32 16 32 16 16 32zM80 160l26.66-53.33L160 80l-53.34-26.67L80 0 53.34 53.33 0 80l53.34 26.67L80 160zm352 128l-26.66 53.33L352 368l53.34 26.67L432 448l26.66-53.33L512 368l-53.34-26.67L432 288zm70.62-193.77L417.77 9.38C411.53 3.12 403.34 0 395.15 0c-8.19 0-16.38 3.12-22.63 9.38L9.38 372.52c-12.5 12.5-12.5 32.76 0 45.25l84.85 84.85c6.25 6.25 14.44 9.37 22.62 9.37 8.19 0 16.38-3.12 22.63-9.37l363.14-363.15c12.5-12.48 12.5-32.75 0-45.24zM359.45 203.46l-50.91-50.91 86.6-86.6 50.91 50.91-86.6 86.6z\"]\n};\nvar faMagnet = {\n prefix: 'fas',\n iconName: 'magnet',\n icon: [512, 512, [], \"f076\", \"M164.1 160H12c-6.6 0-12-5.4-12-12V68c0-19.9 16.1-36 36-36h104c19.9 0 36 16.1 36 36v80c.1 6.6-5.3 12-11.9 12zm348-12V67.9c0-19.9-16.1-36-36-36h-104c-19.9 0-36 16.1-36 36v80c0 6.6 5.4 12 12 12h152c6.6.1 12-5.3 12-11.9zm-164 44c-6.6 0-12 5.4-12 12v52c0 128.1-160 127.9-160 0v-52c0-6.6-5.4-12-12-12h-152c-6.7 0-12 5.4-12 12.1.1 21.4.6 40.3 0 53.3C.1 408 136.3 504 256.9 504 377.5 504 512 408 512 257.3c-.6-12.8-.2-33 0-53.2 0-6.7-5.3-12.1-12-12.1H348.1z\"]\n};\nvar faMailBulk = {\n prefix: 'fas',\n iconName: 'mail-bulk',\n icon: [576, 512, [], \"f674\", \"M160 448c-25.6 0-51.2-22.4-64-32-64-44.8-83.2-60.8-96-70.4V480c0 17.67 14.33 32 32 32h256c17.67 0 32-14.33 32-32V345.6c-12.8 9.6-32 25.6-96 70.4-12.8 9.6-38.4 32-64 32zm128-192H32c-17.67 0-32 14.33-32 32v16c25.6 19.2 22.4 19.2 115.2 86.4 9.6 6.4 28.8 25.6 44.8 25.6s35.2-19.2 44.8-22.4c92.8-67.2 89.6-67.2 115.2-86.4V288c0-17.67-14.33-32-32-32zm256-96H224c-17.67 0-32 14.33-32 32v32h96c33.21 0 60.59 25.42 63.71 57.82l.29-.22V416h192c17.67 0 32-14.33 32-32V192c0-17.67-14.33-32-32-32zm-32 128h-64v-64h64v64zm-352-96c0-35.29 28.71-64 64-64h224V32c0-17.67-14.33-32-32-32H96C78.33 0 64 14.33 64 32v192h96v-32z\"]\n};\nvar faMale = {\n prefix: 'fas',\n iconName: 'male',\n icon: [192, 512, [], \"f183\", \"M96 0c35.346 0 64 28.654 64 64s-28.654 64-64 64-64-28.654-64-64S60.654 0 96 0m48 144h-11.36c-22.711 10.443-49.59 10.894-73.28 0H48c-26.51 0-48 21.49-48 48v136c0 13.255 10.745 24 24 24h16v136c0 13.255 10.745 24 24 24h64c13.255 0 24-10.745 24-24V352h16c13.255 0 24-10.745 24-24V192c0-26.51-21.49-48-48-48z\"]\n};\nvar faMap = {\n prefix: 'fas',\n iconName: 'map',\n icon: [576, 512, [], \"f279\", \"M0 117.66v346.32c0 11.32 11.43 19.06 21.94 14.86L160 416V32L20.12 87.95A32.006 32.006 0 0 0 0 117.66zM192 416l192 64V96L192 32v384zM554.06 33.16L416 96v384l139.88-55.95A31.996 31.996 0 0 0 576 394.34V48.02c0-11.32-11.43-19.06-21.94-14.86z\"]\n};\nvar faMapMarked = {\n prefix: 'fas',\n iconName: 'map-marked',\n icon: [576, 512, [], \"f59f\", \"M288 0c-69.59 0-126 56.41-126 126 0 56.26 82.35 158.8 113.9 196.02 6.39 7.54 17.82 7.54 24.2 0C331.65 284.8 414 182.26 414 126 414 56.41 357.59 0 288 0zM20.12 215.95A32.006 32.006 0 0 0 0 245.66v250.32c0 11.32 11.43 19.06 21.94 14.86L160 448V214.92c-8.84-15.98-16.07-31.54-21.25-46.42L20.12 215.95zM288 359.67c-14.07 0-27.38-6.18-36.51-16.96-19.66-23.2-40.57-49.62-59.49-76.72v182l192 64V266c-18.92 27.09-39.82 53.52-59.49 76.72-9.13 10.77-22.44 16.95-36.51 16.95zm266.06-198.51L416 224v288l139.88-55.95A31.996 31.996 0 0 0 576 426.34V176.02c0-11.32-11.43-19.06-21.94-14.86z\"]\n};\nvar faMapMarkedAlt = {\n prefix: 'fas',\n iconName: 'map-marked-alt',\n icon: [576, 512, [], \"f5a0\", \"M288 0c-69.59 0-126 56.41-126 126 0 56.26 82.35 158.8 113.9 196.02 6.39 7.54 17.82 7.54 24.2 0C331.65 284.8 414 182.26 414 126 414 56.41 357.59 0 288 0zm0 168c-23.2 0-42-18.8-42-42s18.8-42 42-42 42 18.8 42 42-18.8 42-42 42zM20.12 215.95A32.006 32.006 0 0 0 0 245.66v250.32c0 11.32 11.43 19.06 21.94 14.86L160 448V214.92c-8.84-15.98-16.07-31.54-21.25-46.42L20.12 215.95zM288 359.67c-14.07 0-27.38-6.18-36.51-16.96-19.66-23.2-40.57-49.62-59.49-76.72v182l192 64V266c-18.92 27.09-39.82 53.52-59.49 76.72-9.13 10.77-22.44 16.95-36.51 16.95zm266.06-198.51L416 224v288l139.88-55.95A31.996 31.996 0 0 0 576 426.34V176.02c0-11.32-11.43-19.06-21.94-14.86z\"]\n};\nvar faMapMarker = {\n prefix: 'fas',\n iconName: 'map-marker',\n icon: [384, 512, [], \"f041\", \"M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z\"]\n};\nvar faMapMarkerAlt = {\n prefix: 'fas',\n iconName: 'map-marker-alt',\n icon: [384, 512, [], \"f3c5\", \"M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0zM192 272c44.183 0 80-35.817 80-80s-35.817-80-80-80-80 35.817-80 80 35.817 80 80 80z\"]\n};\nvar faMapPin = {\n prefix: 'fas',\n iconName: 'map-pin',\n icon: [288, 512, [], \"f276\", \"M112 316.94v156.69l22.02 33.02c4.75 7.12 15.22 7.12 19.97 0L176 473.63V316.94c-10.39 1.92-21.06 3.06-32 3.06s-21.61-1.14-32-3.06zM144 0C64.47 0 0 64.47 0 144s64.47 144 144 144 144-64.47 144-144S223.53 0 144 0zm0 76c-37.5 0-68 30.5-68 68 0 6.62-5.38 12-12 12s-12-5.38-12-12c0-50.73 41.28-92 92-92 6.62 0 12 5.38 12 12s-5.38 12-12 12z\"]\n};\nvar faMapSigns = {\n prefix: 'fas',\n iconName: 'map-signs',\n icon: [512, 512, [], \"f277\", \"M507.31 84.69L464 41.37c-6-6-14.14-9.37-22.63-9.37H288V16c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v16H56c-13.25 0-24 10.75-24 24v80c0 13.25 10.75 24 24 24h385.37c8.49 0 16.62-3.37 22.63-9.37l43.31-43.31c6.25-6.26 6.25-16.38 0-22.63zM224 496c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16V384h-64v112zm232-272H288v-32h-64v32H70.63c-8.49 0-16.62 3.37-22.63 9.37L4.69 276.69c-6.25 6.25-6.25 16.38 0 22.63L48 342.63c6 6 14.14 9.37 22.63 9.37H456c13.25 0 24-10.75 24-24v-80c0-13.25-10.75-24-24-24z\"]\n};\nvar faMarker = {\n prefix: 'fas',\n iconName: 'marker',\n icon: [512, 512, [], \"f5a1\", \"M93.95 290.03A327.038 327.038 0 0 0 .17 485.11l-.03.23c-1.7 15.28 11.21 28.2 26.49 26.51a327.02 327.02 0 0 0 195.34-93.8l75.4-75.4-128.02-128.02-75.4 75.4zM485.49 26.51c-35.35-35.35-92.67-35.35-128.02 0l-21.76 21.76-36.56-36.55c-15.62-15.62-40.95-15.62-56.56 0L138.47 115.84c-6.25 6.25-6.25 16.38 0 22.63l22.62 22.62c6.25 6.25 16.38 6.25 22.63 0l87.15-87.15 19.59 19.59L191.98 192 320 320.02l165.49-165.49c35.35-35.35 35.35-92.66 0-128.02z\"]\n};\nvar faMars = {\n prefix: 'fas',\n iconName: 'mars',\n icon: [384, 512, [], \"f222\", \"M372 64h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-80.7 80.7c-22.2-14-48.5-22.1-76.7-22.1C64.5 160 0 224.5 0 304s64.5 144 144 144 144-64.5 144-144c0-28.2-8.1-54.5-22.1-76.7l80.7-80.7 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V76c0-6.6-5.4-12-12-12zM144 384c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faMarsDouble = {\n prefix: 'fas',\n iconName: 'mars-double',\n icon: [512, 512, [], \"f227\", \"M340 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-48.7 48.7C198.5 72.1 172.2 64 144 64 64.5 64 0 128.5 0 208s64.5 144 144 144 144-64.5 144-144c0-28.2-8.1-54.5-22.1-76.7l48.7-48.7 16.9 16.9c2.4 2.4 5.5 3.5 8.4 3.5 6.2 0 12.1-4.8 12.1-12V12c0-6.6-5.4-12-12-12zM144 288c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80zm356-128.1h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-48.7 48.7c-18.2-11.4-39-18.9-61.5-21.3-2.1 21.8-8.2 43.3-18.4 63.3 1.1 0 2.2-.1 3.2-.1 44.1 0 80 35.9 80 80s-35.9 80-80 80-80-35.9-80-80c0-1.1 0-2.2.1-3.2-20 10.2-41.5 16.4-63.3 18.4C168.4 455.6 229.6 512 304 512c79.5 0 144-64.5 144-144 0-28.2-8.1-54.5-22.1-76.7l48.7-48.7 16.9 16.9c2.4 2.4 5.4 3.5 8.4 3.5 6.2 0 12.1-4.8 12.1-12v-79c0-6.7-5.4-12.1-12-12.1z\"]\n};\nvar faMarsStroke = {\n prefix: 'fas',\n iconName: 'mars-stroke',\n icon: [384, 512, [], \"f229\", \"M372 64h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-17.5 17.5-14.1-14.1c-4.7-4.7-12.3-4.7-17 0L224.5 133c-4.7 4.7-4.7 12.3 0 17l14.1 14.1-18 18c-22.2-14-48.5-22.1-76.7-22.1C64.5 160 0 224.5 0 304s64.5 144 144 144 144-64.5 144-144c0-28.2-8.1-54.5-22.1-76.7l18-18 14.1 14.1c4.7 4.7 12.3 4.7 17 0l28.3-28.3c4.7-4.7 4.7-12.3 0-17L329.2 164l17.5-17.5 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V76c-.1-6.6-5.5-12-12.1-12zM144 384c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faMarsStrokeH = {\n prefix: 'fas',\n iconName: 'mars-stroke-h',\n icon: [480, 512, [], \"f22b\", \"M476.2 247.5l-55.9-55.9c-7.6-7.6-20.5-2.2-20.5 8.5V224H376v-20c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v20h-27.6c-5.8-25.6-18.7-49.9-38.6-69.8C189.6 98 98.4 98 42.2 154.2c-56.2 56.2-56.2 147.4 0 203.6 56.2 56.2 147.4 56.2 203.6 0 19.9-19.9 32.8-44.2 38.6-69.8H312v20c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-20h23.9v23.9c0 10.7 12.9 16 20.5 8.5l55.9-55.9c4.6-4.7 4.6-12.3-.1-17zm-275.6 65.1c-31.2 31.2-81.9 31.2-113.1 0-31.2-31.2-31.2-81.9 0-113.1 31.2-31.2 81.9-31.2 113.1 0 31.2 31.1 31.2 81.9 0 113.1z\"]\n};\nvar faMarsStrokeV = {\n prefix: 'fas',\n iconName: 'mars-stroke-v',\n icon: [288, 512, [], \"f22a\", \"M245.8 234.2c-19.9-19.9-44.2-32.8-69.8-38.6v-25.4h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20V81.4h23.9c10.7 0 16-12.9 8.5-20.5L152.5 5.1c-4.7-4.7-12.3-4.7-17 0L79.6 61c-7.6 7.6-2.2 20.5 8.5 20.5H112v24.7H92c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h20v25.4c-25.6 5.8-49.9 18.7-69.8 38.6-56.2 56.2-56.2 147.4 0 203.6 56.2 56.2 147.4 56.2 203.6 0 56.3-56.2 56.3-147.4 0-203.6zm-45.2 158.4c-31.2 31.2-81.9 31.2-113.1 0-31.2-31.2-31.2-81.9 0-113.1 31.2-31.2 81.9-31.2 113.1 0 31.2 31.1 31.2 81.9 0 113.1z\"]\n};\nvar faMask = {\n prefix: 'fas',\n iconName: 'mask',\n icon: [640, 512, [], \"f6fa\", \"M320.67 64c-442.6 0-357.57 384-158.46 384 39.9 0 77.47-20.69 101.42-55.86l25.73-37.79c15.66-22.99 46.97-22.99 62.63 0l25.73 37.79C401.66 427.31 439.23 448 479.13 448c189.86 0 290.63-384-158.46-384zM184 308.36c-41.06 0-67.76-25.66-80.08-41.05-5.23-6.53-5.23-16.09 0-22.63 12.32-15.4 39.01-41.05 80.08-41.05s67.76 25.66 80.08 41.05c5.23 6.53 5.23 16.09 0 22.63-12.32 15.4-39.02 41.05-80.08 41.05zm272 0c-41.06 0-67.76-25.66-80.08-41.05-5.23-6.53-5.23-16.09 0-22.63 12.32-15.4 39.01-41.05 80.08-41.05s67.76 25.66 80.08 41.05c5.23 6.53 5.23 16.09 0 22.63-12.32 15.4-39.02 41.05-80.08 41.05z\"]\n};\nvar faMedal = {\n prefix: 'fas',\n iconName: 'medal',\n icon: [512, 512, [], \"f5a2\", \"M223.75 130.75L154.62 15.54A31.997 31.997 0 0 0 127.18 0H16.03C3.08 0-4.5 14.57 2.92 25.18l111.27 158.96c29.72-27.77 67.52-46.83 109.56-53.39zM495.97 0H384.82c-11.24 0-21.66 5.9-27.44 15.54l-69.13 115.21c42.04 6.56 79.84 25.62 109.56 53.38L509.08 25.18C516.5 14.57 508.92 0 495.97 0zM256 160c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm92.52 157.26l-37.93 36.96 8.97 52.22c1.6 9.36-8.26 16.51-16.65 12.09L256 393.88l-46.9 24.65c-8.4 4.45-18.25-2.74-16.65-12.09l8.97-52.22-37.93-36.96c-6.82-6.64-3.05-18.23 6.35-19.59l52.43-7.64 23.43-47.52c2.11-4.28 6.19-6.39 10.28-6.39 4.11 0 8.22 2.14 10.33 6.39l23.43 47.52 52.43 7.64c9.4 1.36 13.17 12.95 6.35 19.59z\"]\n};\nvar faMedkit = {\n prefix: 'fas',\n iconName: 'medkit',\n icon: [512, 512, [], \"f0fa\", \"M96 480h320V128h-32V80c0-26.51-21.49-48-48-48H176c-26.51 0-48 21.49-48 48v48H96v352zm96-384h128v32H192V96zm320 80v256c0 26.51-21.49 48-48 48h-16V128h16c26.51 0 48 21.49 48 48zM64 480H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v352zm288-208v32c0 8.837-7.163 16-16 16h-48v48c0 8.837-7.163 16-16 16h-32c-8.837 0-16-7.163-16-16v-48h-48c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h48v-48c0-8.837 7.163-16 16-16h32c8.837 0 16 7.163 16 16v48h48c8.837 0 16 7.163 16 16z\"]\n};\nvar faMeh = {\n prefix: 'fas',\n iconName: 'meh',\n icon: [496, 512, [], \"f11a\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm-80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm176 192H152c-21.2 0-21.2-32 0-32h192c21.2 0 21.2 32 0 32zm-16-128c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faMehBlank = {\n prefix: 'fas',\n iconName: 'meh-blank',\n icon: [496, 512, [], \"f5a4\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm-80 232c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm160 0c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faMehRollingEyes = {\n prefix: 'fas',\n iconName: 'meh-rolling-eyes',\n icon: [496, 512, [], \"f5a5\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM88 224c0-24.3 13.7-45.2 33.6-56-.7 2.6-1.6 5.2-1.6 8 0 17.7 14.3 32 32 32s32-14.3 32-32c0-2.8-.9-5.4-1.6-8 19.9 10.8 33.6 31.7 33.6 56 0 35.3-28.7 64-64 64s-64-28.7-64-64zm224 176H184c-21.2 0-21.2-32 0-32h128c21.2 0 21.2 32 0 32zm32-112c-35.3 0-64-28.7-64-64 0-24.3 13.7-45.2 33.6-56-.7 2.6-1.6 5.2-1.6 8 0 17.7 14.3 32 32 32s32-14.3 32-32c0-2.8-.9-5.4-1.6-8 19.9 10.8 33.6 31.7 33.6 56 0 35.3-28.7 64-64 64z\"]\n};\nvar faMemory = {\n prefix: 'fas',\n iconName: 'memory',\n icon: [640, 512, [], \"f538\", \"M640 130.94V96c0-17.67-14.33-32-32-32H32C14.33 64 0 78.33 0 96v34.94c18.6 6.61 32 24.19 32 45.06s-13.4 38.45-32 45.06V320h640v-98.94c-18.6-6.61-32-24.19-32-45.06s13.4-38.45 32-45.06zM224 256h-64V128h64v128zm128 0h-64V128h64v128zm128 0h-64V128h64v128zM0 448h64v-26.67c0-8.84 7.16-16 16-16s16 7.16 16 16V448h128v-26.67c0-8.84 7.16-16 16-16s16 7.16 16 16V448h128v-26.67c0-8.84 7.16-16 16-16s16 7.16 16 16V448h128v-26.67c0-8.84 7.16-16 16-16s16 7.16 16 16V448h64v-96H0v96z\"]\n};\nvar faMenorah = {\n prefix: 'fas',\n iconName: 'menorah',\n icon: [640, 512, [], \"f676\", \"M144 128h-32c-8.84 0-16 7.16-16 16v144h64V144c0-8.84-7.16-16-16-16zm96 0h-32c-8.84 0-16 7.16-16 16v144h64V144c0-8.84-7.16-16-16-16zm192 0h-32c-8.84 0-16 7.16-16 16v144h64V144c0-8.84-7.16-16-16-16zm96 0h-32c-8.84 0-16 7.16-16 16v144h64V144c0-8.84-7.16-16-16-16zm80-32c17.67 0 32-14.33 32-32S608 0 608 0s-32 46.33-32 64 14.33 32 32 32zm-96 0c17.67 0 32-14.33 32-32S512 0 512 0s-32 46.33-32 64 14.33 32 32 32zm-96 0c17.67 0 32-14.33 32-32S416 0 416 0s-32 46.33-32 64 14.33 32 32 32zm-96 0c17.67 0 32-14.33 32-32S320 0 320 0s-32 46.33-32 64 14.33 32 32 32zm-96 0c17.67 0 32-14.33 32-32S224 0 224 0s-32 46.33-32 64 14.33 32 32 32zm-96 0c17.67 0 32-14.33 32-32S128 0 128 0 96 46.33 96 64s14.33 32 32 32zm-96 0c17.67 0 32-14.33 32-32S32 0 32 0 0 46.33 0 64s14.33 32 32 32zm544 192c0 17.67-14.33 32-32 32H352V144c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v176H96c-17.67 0-32-14.33-32-32V144c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v144c0 53.02 42.98 96 96 96h192v64H112c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16H352v-64h192c53.02 0 96-42.98 96-96V144c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v144z\"]\n};\nvar faMercury = {\n prefix: 'fas',\n iconName: 'mercury',\n icon: [288, 512, [], \"f223\", \"M288 208c0-44.2-19.9-83.7-51.2-110.1 2.5-1.8 4.9-3.8 7.2-5.8 24.7-21.2 39.8-48.8 43.2-78.8.9-7.1-4.7-13.3-11.9-13.3h-40.5C229 0 224.1 4.1 223 9.8c-2.4 12.5-9.6 24.3-20.7 33.8C187 56.8 166.3 64 144 64s-43-7.2-58.4-20.4C74.5 34.1 67.4 22.3 64.9 9.8 63.8 4.1 58.9 0 53.2 0H12.7C5.5 0-.1 6.2.8 13.3 4.2 43.4 19.2 71 44 92.2c2.3 2 4.7 3.9 7.2 5.8C19.9 124.3 0 163.8 0 208c0 68.5 47.9 125.9 112 140.4V400H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.5 112-71.9 112-140.4zm-224 0c0-44.1 35.9-80 80-80s80 35.9 80 80-35.9 80-80 80-80-35.9-80-80z\"]\n};\nvar faMeteor = {\n prefix: 'fas',\n iconName: 'meteor',\n icon: [512, 512, [], \"f753\", \"M491.2.7C452.5 12.3 379.4 35 303.5 62c-2.1-7-4-13.5-5.6-18.6-3-9.7-13.9-14.2-22.9-9.5C232.6 56 122.2 116.5 60.6 176.4c-1.1 1-2.5 2-3.5 3C19 217.4 0 267.3 0 317.2 0 367 19 416.9 57 455c38 38 87.9 57.1 137.8 57 49.9 0 99.8-19 137.9-57.1 1-1 2-2.4 3-3.5 59.8-61.6 120.4-172.1 142.5-214.4 4.7-9 .2-19.9-9.5-22.9-5.2-1.6-11.6-3.5-18.6-5.6 27-76 49.7-149 61.3-187.7C515 8.4 503.6-3 491.2.7zM192 448c-70.7 0-128-57.3-128-128s57.3-128 128-128 128 57.3 128 128-57.3 128-128 128zm-32-192c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm48 96c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16z\"]\n};\nvar faMicrochip = {\n prefix: 'fas',\n iconName: 'microchip',\n icon: [512, 512, [], \"f2db\", \"M416 48v416c0 26.51-21.49 48-48 48H144c-26.51 0-48-21.49-48-48V48c0-26.51 21.49-48 48-48h224c26.51 0 48 21.49 48 48zm96 58v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42V88h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zm0 96v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42v-48h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zm0 96v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42v-48h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zm0 96v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42v-48h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zM30 376h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6zm0-96h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6zm0-96h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6zm0-96h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6z\"]\n};\nvar faMicrophone = {\n prefix: 'fas',\n iconName: 'microphone',\n icon: [352, 512, [], \"f130\", \"M176 352c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96zm160-160h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16z\"]\n};\nvar faMicrophoneAlt = {\n prefix: 'fas',\n iconName: 'microphone-alt',\n icon: [352, 512, [], \"f3c9\", \"M336 192h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16zM176 352c53.02 0 96-42.98 96-96h-85.33c-5.89 0-10.67-3.58-10.67-8v-16c0-4.42 4.78-8 10.67-8H272v-32h-85.33c-5.89 0-10.67-3.58-10.67-8v-16c0-4.42 4.78-8 10.67-8H272v-32h-85.33c-5.89 0-10.67-3.58-10.67-8v-16c0-4.42 4.78-8 10.67-8H272c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96z\"]\n};\nvar faMicrophoneAltSlash = {\n prefix: 'fas',\n iconName: 'microphone-alt-slash',\n icon: [640, 512, [], \"f539\", \"M633.82 458.1L476.26 336.33C488.74 312.21 496 284.98 496 256v-48c0-8.84-7.16-16-16-16h-16c-8.84 0-16 7.16-16 16v48c0 17.92-3.96 34.8-10.72 50.2l-26.55-20.52c3.1-9.4 5.28-19.22 5.28-29.67h-43.67l-41.4-32H416v-32h-85.33c-5.89 0-10.67-3.58-10.67-8v-16c0-4.42 4.78-8 10.67-8H416v-32h-85.33c-5.89 0-10.67-3.58-10.67-8v-16c0-4.42 4.78-8 10.67-8H416c0-53.02-42.98-96-96-96s-96 42.98-96 96v45.36L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.36 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.41-6.97 4.16-17.02-2.82-22.45zM400 464h-56v-33.78c11.71-1.62 23.1-4.28 33.96-8.08l-50.4-38.96c-6.71.4-13.41.87-20.35.2-55.85-5.45-98.74-48.63-111.18-101.85L144 241.31v6.85c0 89.64 63.97 169.55 152 181.69V464h-56c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16z\"]\n};\nvar faMicrophoneSlash = {\n prefix: 'fas',\n iconName: 'microphone-slash',\n icon: [640, 512, [], \"f131\", \"M633.82 458.1l-157.8-121.96C488.61 312.13 496 285.01 496 256v-48c0-8.84-7.16-16-16-16h-16c-8.84 0-16 7.16-16 16v48c0 17.92-3.96 34.8-10.72 50.2l-26.55-20.52c3.1-9.4 5.28-19.22 5.28-29.67V96c0-53.02-42.98-96-96-96s-96 42.98-96 96v45.36L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.36 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.41-6.97 4.16-17.02-2.82-22.45zM400 464h-56v-33.77c11.66-1.6 22.85-4.54 33.67-8.31l-50.11-38.73c-6.71.4-13.41.87-20.35.2-55.85-5.45-98.74-48.63-111.18-101.85L144 241.31v6.85c0 89.64 63.97 169.55 152 181.69V464h-56c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16z\"]\n};\nvar faMicroscope = {\n prefix: 'fas',\n iconName: 'microscope',\n icon: [512, 512, [], \"f610\", \"M160 320h12v16c0 8.84 7.16 16 16 16h40c8.84 0 16-7.16 16-16v-16h12c17.67 0 32-14.33 32-32V64c0-17.67-14.33-32-32-32V16c0-8.84-7.16-16-16-16h-64c-8.84 0-16 7.16-16 16v16c-17.67 0-32 14.33-32 32v224c0 17.67 14.33 32 32 32zm304 128h-1.29C493.24 413.99 512 369.2 512 320c0-105.88-86.12-192-192-192v64c70.58 0 128 57.42 128 128s-57.42 128-128 128H48c-26.51 0-48 21.49-48 48 0 8.84 7.16 16 16 16h480c8.84 0 16-7.16 16-16 0-26.51-21.49-48-48-48zm-360-32h208c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8H104c-4.42 0-8 3.58-8 8v16c0 4.42 3.58 8 8 8z\"]\n};\nvar faMinus = {\n prefix: 'fas',\n iconName: 'minus',\n icon: [448, 512, [], \"f068\", \"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"]\n};\nvar faMinusCircle = {\n prefix: 'fas',\n iconName: 'minus-circle',\n icon: [512, 512, [], \"f056\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z\"]\n};\nvar faMinusSquare = {\n prefix: 'fas',\n iconName: 'minus-square',\n icon: [448, 512, [], \"f146\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM92 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H92z\"]\n};\nvar faMitten = {\n prefix: 'fas',\n iconName: 'mitten',\n icon: [448, 512, [], \"f7b5\", \"M368 416H48c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h320c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16zm57-209.1c-27.2-22.6-67.5-19-90.1 8.2l-20.9 25-29.6-128.4c-18-77.5-95.4-125.9-172.8-108C34.2 21.6-14.2 98.9 3.7 176.4L51.6 384h309l72.5-87c22.7-27.2 19-67.5-8.1-90.1z\"]\n};\nvar faMobile = {\n prefix: 'fas',\n iconName: 'mobile',\n icon: [320, 512, [], \"f10b\", \"M272 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h224c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM160 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faMobileAlt = {\n prefix: 'fas',\n iconName: 'mobile-alt',\n icon: [320, 512, [], \"f3cd\", \"M272 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h224c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM160 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm112-108c0 6.6-5.4 12-12 12H60c-6.6 0-12-5.4-12-12V60c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v312z\"]\n};\nvar faMoneyBill = {\n prefix: 'fas',\n iconName: 'money-bill',\n icon: [640, 512, [], \"f0d6\", \"M608 64H32C14.33 64 0 78.33 0 96v320c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V96c0-17.67-14.33-32-32-32zM48 400v-64c35.35 0 64 28.65 64 64H48zm0-224v-64h64c0 35.35-28.65 64-64 64zm272 176c-44.19 0-80-42.99-80-96 0-53.02 35.82-96 80-96s80 42.98 80 96c0 53.03-35.83 96-80 96zm272 48h-64c0-35.35 28.65-64 64-64v64zm0-224c-35.35 0-64-28.65-64-64h64v64z\"]\n};\nvar faMoneyBillAlt = {\n prefix: 'fas',\n iconName: 'money-bill-alt',\n icon: [640, 512, [], \"f3d1\", \"M352 288h-16v-88c0-4.42-3.58-8-8-8h-13.58c-4.74 0-9.37 1.4-13.31 4.03l-15.33 10.22a7.994 7.994 0 0 0-2.22 11.09l8.88 13.31a7.994 7.994 0 0 0 11.09 2.22l.47-.31V288h-16c-4.42 0-8 3.58-8 8v16c0 4.42 3.58 8 8 8h64c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8zM608 64H32C14.33 64 0 78.33 0 96v320c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V96c0-17.67-14.33-32-32-32zM48 400v-64c35.35 0 64 28.65 64 64H48zm0-224v-64h64c0 35.35-28.65 64-64 64zm272 192c-53.02 0-96-50.15-96-112 0-61.86 42.98-112 96-112s96 50.14 96 112c0 61.87-43 112-96 112zm272 32h-64c0-35.35 28.65-64 64-64v64zm0-224c-35.35 0-64-28.65-64-64h64v64z\"]\n};\nvar faMoneyBillWave = {\n prefix: 'fas',\n iconName: 'money-bill-wave',\n icon: [640, 512, [], \"f53a\", \"M621.16 54.46C582.37 38.19 543.55 32 504.75 32c-123.17-.01-246.33 62.34-369.5 62.34-30.89 0-61.76-3.92-92.65-13.72-3.47-1.1-6.95-1.62-10.35-1.62C15.04 79 0 92.32 0 110.81v317.26c0 12.63 7.23 24.6 18.84 29.46C57.63 473.81 96.45 480 135.25 480c123.17 0 246.34-62.35 369.51-62.35 30.89 0 61.76 3.92 92.65 13.72 3.47 1.1 6.95 1.62 10.35 1.62 17.21 0 32.25-13.32 32.25-31.81V83.93c-.01-12.64-7.24-24.6-18.85-29.47zM48 132.22c20.12 5.04 41.12 7.57 62.72 8.93C104.84 170.54 79 192.69 48 192.69v-60.47zm0 285v-47.78c34.37 0 62.18 27.27 63.71 61.4-22.53-1.81-43.59-6.31-63.71-13.62zM320 352c-44.19 0-80-42.99-80-96 0-53.02 35.82-96 80-96s80 42.98 80 96c0 53.03-35.83 96-80 96zm272 27.78c-17.52-4.39-35.71-6.85-54.32-8.44 5.87-26.08 27.5-45.88 54.32-49.28v57.72zm0-236.11c-30.89-3.91-54.86-29.7-55.81-61.55 19.54 2.17 38.09 6.23 55.81 12.66v48.89z\"]\n};\nvar faMoneyBillWaveAlt = {\n prefix: 'fas',\n iconName: 'money-bill-wave-alt',\n icon: [640, 512, [], \"f53b\", \"M621.16 54.46C582.37 38.19 543.55 32 504.75 32c-123.17-.01-246.33 62.34-369.5 62.34-30.89 0-61.76-3.92-92.65-13.72-3.47-1.1-6.95-1.62-10.35-1.62C15.04 79 0 92.32 0 110.81v317.26c0 12.63 7.23 24.6 18.84 29.46C57.63 473.81 96.45 480 135.25 480c123.17 0 246.34-62.35 369.51-62.35 30.89 0 61.76 3.92 92.65 13.72 3.47 1.1 6.95 1.62 10.35 1.62 17.21 0 32.25-13.32 32.25-31.81V83.93c-.01-12.64-7.24-24.6-18.85-29.47zM320 352c-44.19 0-80-42.99-80-96 0-53.02 35.82-96 80-96s80 42.98 80 96c0 53.03-35.83 96-80 96z\"]\n};\nvar faMoneyCheck = {\n prefix: 'fas',\n iconName: 'money-check',\n icon: [640, 512, [], \"f53c\", \"M0 448c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V128H0v320zm448-208c0-8.84 7.16-16 16-16h96c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16h-96c-8.84 0-16-7.16-16-16v-32zm0 120c0-4.42 3.58-8 8-8h112c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H456c-4.42 0-8-3.58-8-8v-16zM64 264c0-4.42 3.58-8 8-8h304c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16zm0 96c0-4.42 3.58-8 8-8h176c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16zM624 32H16C7.16 32 0 39.16 0 48v48h640V48c0-8.84-7.16-16-16-16z\"]\n};\nvar faMoneyCheckAlt = {\n prefix: 'fas',\n iconName: 'money-check-alt',\n icon: [640, 512, [], \"f53d\", \"M608 32H32C14.33 32 0 46.33 0 64v384c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V64c0-17.67-14.33-32-32-32zM176 327.88V344c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-16.29c-11.29-.58-22.27-4.52-31.37-11.35-3.9-2.93-4.1-8.77-.57-12.14l11.75-11.21c2.77-2.64 6.89-2.76 10.13-.73 3.87 2.42 8.26 3.72 12.82 3.72h28.11c6.5 0 11.8-5.92 11.8-13.19 0-5.95-3.61-11.19-8.77-12.73l-45-13.5c-18.59-5.58-31.58-23.42-31.58-43.39 0-24.52 19.05-44.44 42.67-45.07V152c0-4.42 3.58-8 8-8h16c4.42 0 8 3.58 8 8v16.29c11.29.58 22.27 4.51 31.37 11.35 3.9 2.93 4.1 8.77.57 12.14l-11.75 11.21c-2.77 2.64-6.89 2.76-10.13.73-3.87-2.43-8.26-3.72-12.82-3.72h-28.11c-6.5 0-11.8 5.92-11.8 13.19 0 5.95 3.61 11.19 8.77 12.73l45 13.5c18.59 5.58 31.58 23.42 31.58 43.39 0 24.53-19.05 44.44-42.67 45.07zM416 312c0 4.42-3.58 8-8 8H296c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h112c4.42 0 8 3.58 8 8v16zm160 0c0 4.42-3.58 8-8 8h-80c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h80c4.42 0 8 3.58 8 8v16zm0-96c0 4.42-3.58 8-8 8H296c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h272c4.42 0 8 3.58 8 8v16z\"]\n};\nvar faMonument = {\n prefix: 'fas',\n iconName: 'monument',\n icon: [384, 512, [], \"f5a6\", \"M368 448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h352c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm-78.86-347.26a31.97 31.97 0 0 0-9.21-19.44L203.31 4.69c-6.25-6.25-16.38-6.25-22.63 0l-76.6 76.61a31.97 31.97 0 0 0-9.21 19.44L64 416h256l-30.86-315.26zM240 307.2c0 6.4-6.4 12.8-12.8 12.8h-70.4c-6.4 0-12.8-6.4-12.8-12.8v-38.4c0-6.4 6.4-12.8 12.8-12.8h70.4c6.4 0 12.8 6.4 12.8 12.8v38.4z\"]\n};\nvar faMoon = {\n prefix: 'fas',\n iconName: 'moon',\n icon: [512, 512, [], \"f186\", \"M283.211 512c78.962 0 151.079-35.925 198.857-94.792 7.068-8.708-.639-21.43-11.562-19.35-124.203 23.654-238.262-71.576-238.262-196.954 0-72.222 38.662-138.635 101.498-174.394 9.686-5.512 7.25-20.197-3.756-22.23A258.156 258.156 0 0 0 283.211 0c-141.309 0-256 114.511-256 256 0 141.309 114.511 256 256 256z\"]\n};\nvar faMortarPestle = {\n prefix: 'fas',\n iconName: 'mortar-pestle',\n icon: [512, 512, [], \"f5a7\", \"M501.54 60.91c17.22-17.22 12.51-46.25-9.27-57.14a35.696 35.696 0 0 0-37.37 3.37L251.09 160h151.37l99.08-99.09zM496 192H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h16c0 80.98 50.2 150.11 121.13 178.32-12.76 16.87-21.72 36.8-24.95 58.69-1.46 9.92 6.04 18.98 16.07 18.98h223.5c10.03 0 17.53-9.06 16.07-18.98-3.22-21.89-12.18-41.82-24.95-58.69C429.8 406.11 480 336.98 480 256h16c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16z\"]\n};\nvar faMosque = {\n prefix: 'fas',\n iconName: 'mosque',\n icon: [640, 512, [], \"f678\", \"M0 480c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32V160H0v320zm579.16-192c17.86-17.39 28.84-37.34 28.84-58.91 0-52.86-41.79-93.79-87.92-122.9-41.94-26.47-80.63-57.77-111.96-96.22L400 0l-8.12 9.97c-31.33 38.45-70.01 69.76-111.96 96.22C233.79 135.3 192 176.23 192 229.09c0 21.57 10.98 41.52 28.84 58.91h358.32zM608 320H192c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h32v-64c0-17.67 14.33-32 32-32s32 14.33 32 32v64h64v-72c0-48 48-72 48-72s48 24 48 72v72h64v-64c0-17.67 14.33-32 32-32s32 14.33 32 32v64h32c17.67 0 32-14.33 32-32V352c0-17.67-14.33-32-32-32zM64 0S0 32 0 96v32h128V96c0-64-64-96-64-96z\"]\n};\nvar faMotorcycle = {\n prefix: 'fas',\n iconName: 'motorcycle',\n icon: [640, 512, [], \"f21c\", \"M512.9 192c-14.9-.1-29.1 2.3-42.4 6.9L437.6 144H520c13.3 0 24-10.7 24-24V88c0-13.3-10.7-24-24-24h-45.3c-6.8 0-13.3 2.9-17.8 7.9l-37.5 41.7-22.8-38C392.2 68.4 384.4 64 376 64h-80c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h66.4l19.2 32H227.9c-17.7-23.1-44.9-40-99.9-40H72.5C59 104 47.7 115 48 128.5c.2 13 10.9 23.5 24 23.5h56c24.5 0 38.7 10.9 47.8 24.8l-11.3 20.5c-13-3.9-26.9-5.7-41.3-5.2C55.9 194.5 1.6 249.6 0 317c-1.6 72.1 56.3 131 128 131 59.6 0 109.7-40.8 124-96h84.2c13.7 0 24.6-11.4 24-25.1-2.1-47.1 17.5-93.7 56.2-125l12.5 20.8c-27.6 23.7-45.1 58.9-44.8 98.2.5 69.6 57.2 126.5 126.8 127.1 71.6.7 129.8-57.5 129.2-129.1-.7-69.6-57.6-126.4-127.2-126.9zM128 400c-44.1 0-80-35.9-80-80s35.9-80 80-80c4.2 0 8.4.3 12.5 1L99 316.4c-8.8 16 2.8 35.6 21 35.6h81.3c-12.4 28.2-40.6 48-73.3 48zm463.9-75.6c-2.2 40.6-35 73.4-75.5 75.5-46.1 2.5-84.4-34.3-84.4-79.9 0-21.4 8.4-40.8 22.1-55.1l49.4 82.4c4.5 7.6 14.4 10 22 5.5l13.7-8.2c7.6-4.5 10-14.4 5.5-22l-48.6-80.9c5.2-1.1 10.5-1.6 15.9-1.6 45.6-.1 82.3 38.2 79.9 84.3z\"]\n};\nvar faMountain = {\n prefix: 'fas',\n iconName: 'mountain',\n icon: [640, 512, [], \"f6fc\", \"M634.92 462.7l-288-448C341.03 5.54 330.89 0 320 0s-21.03 5.54-26.92 14.7l-288 448a32.001 32.001 0 0 0-1.17 32.64A32.004 32.004 0 0 0 32 512h576c11.71 0 22.48-6.39 28.09-16.67a31.983 31.983 0 0 0-1.17-32.63zM320 91.18L405.39 224H320l-64 64-38.06-38.06L320 91.18z\"]\n};\nvar faMousePointer = {\n prefix: 'fas',\n iconName: 'mouse-pointer',\n icon: [320, 512, [], \"f245\", \"M302.189 329.126H196.105l55.831 135.993c3.889 9.428-.555 19.999-9.444 23.999l-49.165 21.427c-9.165 4-19.443-.571-23.332-9.714l-53.053-129.136-86.664 89.138C18.729 472.71 0 463.554 0 447.977V18.299C0 1.899 19.921-6.096 30.277 5.443l284.412 292.542c11.472 11.179 3.007 31.141-12.5 31.141z\"]\n};\nvar faMugHot = {\n prefix: 'fas',\n iconName: 'mug-hot',\n icon: [512, 512, [], \"f7b6\", \"M127.1 146.5c1.3 7.7 8 13.5 16 13.5h16.5c9.8 0 17.6-8.5 16.3-18-3.8-28.2-16.4-54.2-36.6-74.7-14.4-14.7-23.6-33.3-26.4-53.5C111.8 5.9 105 0 96.8 0H80.4C70.6 0 63 8.5 64.1 18c3.9 31.9 18 61.3 40.6 84.4 12 12.2 19.7 27.5 22.4 44.1zm112 0c1.3 7.7 8 13.5 16 13.5h16.5c9.8 0 17.6-8.5 16.3-18-3.8-28.2-16.4-54.2-36.6-74.7-14.4-14.7-23.6-33.3-26.4-53.5C223.8 5.9 217 0 208.8 0h-16.4c-9.8 0-17.5 8.5-16.3 18 3.9 31.9 18 61.3 40.6 84.4 12 12.2 19.7 27.5 22.4 44.1zM400 192H32c-17.7 0-32 14.3-32 32v192c0 53 43 96 96 96h192c53 0 96-43 96-96h16c61.8 0 112-50.2 112-112s-50.2-112-112-112zm0 160h-16v-96h16c26.5 0 48 21.5 48 48s-21.5 48-48 48z\"]\n};\nvar faMusic = {\n prefix: 'fas',\n iconName: 'music',\n icon: [512, 512, [], \"f001\", \"M511.99 32.01c0-21.71-21.1-37.01-41.6-30.51L150.4 96c-13.3 4.2-22.4 16.5-22.4 30.5v261.42c-10.05-2.38-20.72-3.92-32-3.92-53.02 0-96 28.65-96 64s42.98 64 96 64 96-28.65 96-64V214.31l256-75.02v184.63c-10.05-2.38-20.72-3.92-32-3.92-53.02 0-96 28.65-96 64s42.98 64 96 64 96-28.65 96-64l-.01-351.99z\"]\n};\nvar faNetworkWired = {\n prefix: 'fas',\n iconName: 'network-wired',\n icon: [640, 512, [], \"f6ff\", \"M640 264v-16c0-8.84-7.16-16-16-16H344v-40h72c17.67 0 32-14.33 32-32V32c0-17.67-14.33-32-32-32H224c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h72v40H16c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h104v40H64c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h160c17.67 0 32-14.33 32-32V352c0-17.67-14.33-32-32-32h-56v-40h304v40h-56c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h160c17.67 0 32-14.33 32-32V352c0-17.67-14.33-32-32-32h-56v-40h104c8.84 0 16-7.16 16-16zM256 128V64h128v64H256zm-64 320H96v-64h96v64zm352 0h-96v-64h96v64z\"]\n};\nvar faNeuter = {\n prefix: 'fas',\n iconName: 'neuter',\n icon: [288, 512, [], \"f22c\", \"M288 176c0-79.5-64.5-144-144-144S0 96.5 0 176c0 68.5 47.9 125.9 112 140.4V468c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V316.4c64.1-14.5 112-71.9 112-140.4zm-144 80c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faNewspaper = {\n prefix: 'fas',\n iconName: 'newspaper',\n icon: [576, 512, [], \"f1ea\", \"M552 64H88c-13.255 0-24 10.745-24 24v8H24c-13.255 0-24 10.745-24 24v272c0 30.928 25.072 56 56 56h472c26.51 0 48-21.49 48-48V88c0-13.255-10.745-24-24-24zM56 400a8 8 0 0 1-8-8V144h16v248a8 8 0 0 1-8 8zm236-16H140c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm208 0H348c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm-208-96H140c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm208 0H348c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm0-96H140c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h360c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12z\"]\n};\nvar faNotEqual = {\n prefix: 'fas',\n iconName: 'not-equal',\n icon: [448, 512, [], \"f53e\", \"M416 208c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32h-23.88l51.87-66.81c5.37-7.02 4.04-17.06-2.97-22.43L415.61 3.3c-7.02-5.38-17.06-4.04-22.44 2.97L311.09 112H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h204.56l-74.53 96H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h55.49l-51.87 66.81c-5.37 7.01-4.04 17.05 2.97 22.43L64 508.7c7.02 5.38 17.06 4.04 22.43-2.97L168.52 400H416c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32H243.05l74.53-96H416z\"]\n};\nvar faNotesMedical = {\n prefix: 'fas',\n iconName: 'notes-medical',\n icon: [384, 512, [], \"f481\", \"M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 40c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm96 304c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8v48zm0-192c0 4.4-3.6 8-8 8H104c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h176c4.4 0 8 3.6 8 8v16z\"]\n};\nvar faObjectGroup = {\n prefix: 'fas',\n iconName: 'object-group',\n icon: [512, 512, [], \"f247\", \"M480 128V96h20c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v20H64V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v40c0 6.627 5.373 12 12 12h20v320H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-20h384v20c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20V128zM96 276V140c0-6.627 5.373-12 12-12h168c6.627 0 12 5.373 12 12v136c0 6.627-5.373 12-12 12H108c-6.627 0-12-5.373-12-12zm320 96c0 6.627-5.373 12-12 12H236c-6.627 0-12-5.373-12-12v-52h72c13.255 0 24-10.745 24-24v-72h84c6.627 0 12 5.373 12 12v136z\"]\n};\nvar faObjectUngroup = {\n prefix: 'fas',\n iconName: 'object-ungroup',\n icon: [576, 512, [], \"f248\", \"M64 320v26a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6v-52a6 6 0 0 1 6-6h26V96H6a6 6 0 0 1-6-6V38a6 6 0 0 1 6-6h52a6 6 0 0 1 6 6v26h288V38a6 6 0 0 1 6-6h52a6 6 0 0 1 6 6v52a6 6 0 0 1-6 6h-26v192h26a6 6 0 0 1 6 6v52a6 6 0 0 1-6 6h-52a6 6 0 0 1-6-6v-26H64zm480-64v-32h26a6 6 0 0 0 6-6v-52a6 6 0 0 0-6-6h-52a6 6 0 0 0-6 6v26H408v72h8c13.255 0 24 10.745 24 24v64c0 13.255-10.745 24-24 24h-64c-13.255 0-24-10.745-24-24v-8H192v72h-26a6 6 0 0 0-6 6v52a6 6 0 0 0 6 6h52a6 6 0 0 0 6-6v-26h288v26a6 6 0 0 0 6 6h52a6 6 0 0 0 6-6v-52a6 6 0 0 0-6-6h-26V256z\"]\n};\nvar faOilCan = {\n prefix: 'fas',\n iconName: 'oil-can',\n icon: [640, 512, [], \"f613\", \"M629.8 160.31L416 224l-50.49-25.24a64.07 64.07 0 0 0-28.62-6.76H280v-48h56c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16H176c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h56v48h-56L37.72 166.86a31.9 31.9 0 0 0-5.79-.53C14.67 166.33 0 180.36 0 198.34v94.95c0 15.46 11.06 28.72 26.28 31.48L96 337.46V384c0 17.67 14.33 32 32 32h274.63c8.55 0 16.75-3.42 22.76-9.51l212.26-214.75c1.5-1.5 2.34-3.54 2.34-5.66V168c.01-5.31-5.08-9.15-10.19-7.69zM96 288.67l-48-8.73v-62.43l48 8.73v62.43zm453.33 84.66c0 23.56 19.1 42.67 42.67 42.67s42.67-19.1 42.67-42.67S592 288 592 288s-42.67 61.77-42.67 85.33z\"]\n};\nvar faOm = {\n prefix: 'fas',\n iconName: 'om',\n icon: [512, 512, [], \"f679\", \"M360.6 60.94a10.43 10.43 0 0 0 14.76 0l21.57-21.56a10.43 10.43 0 0 0 0-14.76L375.35 3.06c-4.08-4.07-10.68-4.07-14.76 0l-21.57 21.56a10.43 10.43 0 0 0 0 14.76l21.58 21.56zM412.11 192c-26.69 0-51.77 10.39-70.64 29.25l-24.25 24.25c-6.78 6.77-15.78 10.5-25.38 10.5H245c10.54-22.1 14.17-48.11 7.73-75.23-10.1-42.55-46.36-76.11-89.52-83.19-36.15-5.93-70.9 5.04-96.01 28.78-7.36 6.96-6.97 18.85 1.12 24.93l26.15 19.63c5.72 4.3 13.66 4.32 19.2-.21 8.45-6.9 19.02-10.71 30.27-10.71 26.47 0 48.01 21.53 48.01 48s-21.54 48-48.01 48h-31.9c-11.96 0-19.74 12.58-14.39 23.28l16.09 32.17c2.53 5.06 7.6 8.1 13.17 8.55h33.03c35.3 0 64.01 28.7 64.01 64s-28.71 64-64.01 64c-96.02 0-122.35-54.02-145.15-92.03-4.53-7.55-14.77-3.58-14.79 5.22C-.09 416 41.13 512 159.94 512c70.59 0 128.02-57.42 128.02-128 0-23.42-6.78-45.1-17.81-64h21.69c26.69 0 51.77-10.39 70.64-29.25l24.25-24.25c6.78-6.77 15.78-10.5 25.38-10.5 19.78 0 35.88 16.09 35.88 35.88V392c0 13.23-18.77 24-32.01 24-39.4 0-66.67-24.24-81.82-42.89-4.77-5.87-14.2-2.54-14.2 5.02V416s0 64 96.02 64c48.54 0 96.02-39.47 96.02-88V291.88c0-55.08-44.8-99.88-99.89-99.88zm42.18-124.73c-85.55 65.12-169.05 2.75-172.58.05-6.02-4.62-14.44-4.38-20.14.55-5.74 4.92-7.27 13.17-3.66 19.8 1.61 2.95 40.37 72.34 118.8 72.34 79.92 0 98.78-31.36 101.75-37.66 1.02-2.12 1.53-4.47 1.53-6.83V80c0-13.22-15.14-20.69-25.7-12.73z\"]\n};\nvar faOtter = {\n prefix: 'fas',\n iconName: 'otter',\n icon: [640, 512, [], \"f700\", \"M608 32h-32l-13.25-13.25A63.97 63.97 0 0 0 517.49 0H497c-11.14 0-22.08 2.91-31.75 8.43L312 96h-56C149.96 96 64 181.96 64 288v1.61c0 32.75-16 62.14-39.56 84.89-18.19 17.58-28.1 43.68-23.19 71.8 6.76 38.8 42.9 65.7 82.28 65.7H192c17.67 0 32-14.33 32-32s-14.33-32-32-32H80c-8.83 0-16-7.17-16-16s7.17-16 16-16h224c8.84 0 16-7.16 16-16v-16c0-17.67-14.33-32-32-32h-64l149.49-80.5L448 416h80c8.84 0 16-7.16 16-16v-16c0-17.67-14.33-32-32-32h-28.22l-55.11-110.21L521.14 192H544c53.02 0 96-42.98 96-96V64c0-17.67-14.33-32-32-32zm-96 16c8.84 0 16 7.16 16 16s-7.16 16-16 16-16-7.16-16-16 7.16-16 16-16zm32 96h-34.96L407.2 198.84l-13.77-27.55L512 112h77.05c-6.62 18.58-24.22 32-45.05 32z\"]\n};\nvar faOutdent = {\n prefix: 'fas',\n iconName: 'outdent',\n icon: [448, 512, [], \"f03b\", \"M0 84V44c0-8.837 7.163-16 16-16h416c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16zm208 144h224c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H208c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM16 484h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm192-128h224c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H208c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM4.687 267.313l96 95.984C110.734 373.348 128 366.224 128 351.984V160.008c0-14.329-17.325-21.304-27.313-11.313l-96 95.992c-6.249 6.248-6.249 16.378 0 22.626z\"]\n};\nvar faPager = {\n prefix: 'fas',\n iconName: 'pager',\n icon: [512, 512, [], \"f815\", \"M448 64H64a64 64 0 0 0-64 64v256a64 64 0 0 0 64 64h384a64 64 0 0 0 64-64V128a64 64 0 0 0-64-64zM160 368H80a16 16 0 0 1-16-16v-16a16 16 0 0 1 16-16h80zm128-16a16 16 0 0 1-16 16h-80v-48h80a16 16 0 0 1 16 16zm160-128a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32v-64a32 32 0 0 1 32-32h320a32 32 0 0 1 32 32z\"]\n};\nvar faPaintBrush = {\n prefix: 'fas',\n iconName: 'paint-brush',\n icon: [512, 512, [], \"f1fc\", \"M167.02 309.34c-40.12 2.58-76.53 17.86-97.19 72.3-2.35 6.21-8 9.98-14.59 9.98-11.11 0-45.46-27.67-55.25-34.35C0 439.62 37.93 512 128 512c75.86 0 128-43.77 128-120.19 0-3.11-.65-6.08-.97-9.13l-88.01-73.34zM457.89 0c-15.16 0-29.37 6.71-40.21 16.45C213.27 199.05 192 203.34 192 257.09c0 13.7 3.25 26.76 8.73 38.7l63.82 53.18c7.21 1.8 14.64 3.03 22.39 3.03 62.11 0 98.11-45.47 211.16-256.46 7.38-14.35 13.9-29.85 13.9-45.99C512 20.64 486 0 457.89 0z\"]\n};\nvar faPaintRoller = {\n prefix: 'fas',\n iconName: 'paint-roller',\n icon: [512, 512, [], \"f5aa\", \"M416 128V32c0-17.67-14.33-32-32-32H32C14.33 0 0 14.33 0 32v96c0 17.67 14.33 32 32 32h352c17.67 0 32-14.33 32-32zm32-64v128c0 17.67-14.33 32-32 32H256c-35.35 0-64 28.65-64 64v32c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32V352c0-17.67-14.33-32-32-32v-32h160c53.02 0 96-42.98 96-96v-64c0-35.35-28.65-64-64-64z\"]\n};\nvar faPalette = {\n prefix: 'fas',\n iconName: 'palette',\n icon: [512, 512, [], \"f53f\", \"M204.3 5C104.9 24.4 24.8 104.3 5.2 203.4c-37 187 131.7 326.4 258.8 306.7 41.2-6.4 61.4-54.6 42.5-91.7-23.1-45.4 9.9-98.4 60.9-98.4h79.7c35.8 0 64.8-29.6 64.9-65.3C511.5 97.1 368.1-26.9 204.3 5zM96 320c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm32-128c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm128-64c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm128 64c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faPallet = {\n prefix: 'fas',\n iconName: 'pallet',\n icon: [640, 512, [], \"f482\", \"M144 256h352c8.8 0 16-7.2 16-16V16c0-8.8-7.2-16-16-16H384v128l-64-32-64 32V0H144c-8.8 0-16 7.2-16 16v224c0 8.8 7.2 16 16 16zm480 128c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h48v64H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16h-48v-64h48zm-336 64H128v-64h160v64zm224 0H352v-64h160v64z\"]\n};\nvar faPaperPlane = {\n prefix: 'fas',\n iconName: 'paper-plane',\n icon: [512, 512, [], \"f1d8\", \"M476 3.2L12.5 270.6c-18.1 10.4-15.8 35.6 2.2 43.2L121 358.4l287.3-253.2c5.5-4.9 13.3 2.6 8.6 8.3L176 407v80.5c0 23.6 28.5 32.9 42.5 15.8L282 426l124.6 52.2c14.2 6 30.4-2.9 33-18.2l72-432C515 7.8 493.3-6.8 476 3.2z\"]\n};\nvar faPaperclip = {\n prefix: 'fas',\n iconName: 'paperclip',\n icon: [448, 512, [], \"f0c6\", \"M43.246 466.142c-58.43-60.289-57.341-157.511 1.386-217.581L254.392 34c44.316-45.332 116.351-45.336 160.671 0 43.89 44.894 43.943 117.329 0 162.276L232.214 383.128c-29.855 30.537-78.633 30.111-107.982-.998-28.275-29.97-27.368-77.473 1.452-106.953l143.743-146.835c6.182-6.314 16.312-6.422 22.626-.241l22.861 22.379c6.315 6.182 6.422 16.312.241 22.626L171.427 319.927c-4.932 5.045-5.236 13.428-.648 18.292 4.372 4.634 11.245 4.711 15.688.165l182.849-186.851c19.613-20.062 19.613-52.725-.011-72.798-19.189-19.627-49.957-19.637-69.154 0L90.39 293.295c-34.763 35.56-35.299 93.12-1.191 128.313 34.01 35.093 88.985 35.137 123.058.286l172.06-175.999c6.177-6.319 16.307-6.433 22.626-.256l22.877 22.364c6.319 6.177 6.434 16.307.256 22.626l-172.06 175.998c-59.576 60.938-155.943 60.216-214.77-.485z\"]\n};\nvar faParachuteBox = {\n prefix: 'fas',\n iconName: 'parachute-box',\n icon: [512, 512, [], \"f4cd\", \"M511.9 175c-9.1-75.6-78.4-132.4-158.3-158.7C390 55.7 416 116.9 416 192h28.1L327.5 321.5c-2.5-.6-4.8-1.5-7.5-1.5h-48V192h112C384 76.8 315.1 0 256 0S128 76.8 128 192h112v128h-48c-2.7 0-5 .9-7.5 1.5L67.9 192H96c0-75.1 26-136.3 62.4-175.7C78.5 42.7 9.2 99.5.1 175c-1.1 9.1 6.8 17 16 17h8.7l136.7 151.9c-.7 2.6-1.6 5.2-1.6 8.1v128c0 17.7 14.3 32 32 32h128c17.7 0 32-14.3 32-32V352c0-2.9-.9-5.4-1.6-8.1L487.1 192h8.7c9.3 0 17.2-7.8 16.1-17z\"]\n};\nvar faParagraph = {\n prefix: 'fas',\n iconName: 'paragraph',\n icon: [448, 512, [], \"f1dd\", \"M408 32H177.531C88.948 32 16.045 103.335 16 191.918 15.956 280.321 87.607 352 176 352v104c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V112h32v344c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V112h40c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24z\"]\n};\nvar faParking = {\n prefix: 'fas',\n iconName: 'parking',\n icon: [448, 512, [], \"f540\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM240 320h-48v48c0 8.8-7.2 16-16 16h-32c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h96c52.9 0 96 43.1 96 96s-43.1 96-96 96zm0-128h-48v64h48c17.6 0 32-14.4 32-32s-14.4-32-32-32z\"]\n};\nvar faPassport = {\n prefix: 'fas',\n iconName: 'passport',\n icon: [448, 512, [], \"f5ab\", \"M129.62 176h39.09c1.49-27.03 6.54-51.35 14.21-70.41-27.71 13.24-48.02 39.19-53.3 70.41zm0 32c5.29 31.22 25.59 57.17 53.3 70.41-7.68-19.06-12.72-43.38-14.21-70.41h-39.09zM224 286.69c7.69-7.45 20.77-34.42 23.43-78.69h-46.87c2.67 44.26 15.75 71.24 23.44 78.69zM200.57 176h46.87c-2.66-44.26-15.74-71.24-23.43-78.69-7.7 7.45-20.78 34.43-23.44 78.69zm64.51 102.41c27.71-13.24 48.02-39.19 53.3-70.41h-39.09c-1.49 27.03-6.53 51.35-14.21 70.41zM416 0H64C28.65 0 0 28.65 0 64v384c0 35.35 28.65 64 64 64h352c17.67 0 32-14.33 32-32V32c0-17.67-14.33-32-32-32zm-80 416H112c-8.8 0-16-7.2-16-16s7.2-16 16-16h224c8.8 0 16 7.2 16 16s-7.2 16-16 16zm-112-96c-70.69 0-128-57.31-128-128S153.31 64 224 64s128 57.31 128 128-57.31 128-128 128zm41.08-214.41c7.68 19.06 12.72 43.38 14.21 70.41h39.09c-5.28-31.22-25.59-57.17-53.3-70.41z\"]\n};\nvar faPastafarianism = {\n prefix: 'fas',\n iconName: 'pastafarianism',\n icon: [640, 512, [], \"f67b\", \"M624.54 347.67c-32.7-12.52-57.36 4.25-75.37 16.45-17.06 11.53-23.25 14.42-31.41 11.36-8.12-3.09-10.83-9.38-15.89-29.38-3.33-13.15-7.44-29.32-17.95-42.65 2.24-2.91 4.43-5.79 6.38-8.57C500.47 304.45 513.71 312 532 312c33.95 0 50.87-25.78 62.06-42.83 10.59-16.14 15-21.17 21.94-21.17 13.25 0 24-10.75 24-24s-10.75-24-24-24c-33.95 0-50.87 25.78-62.06 42.83-10.6 16.14-15 21.17-21.94 21.17-17.31 0-37.48-61.43-97.26-101.91l17.25-34.5C485.43 125.5 512 97.98 512 64c0-35.35-28.65-64-64-64s-64 28.65-64 64c0 13.02 3.94 25.1 10.62 35.21l-18.15 36.3c-16.98-4.6-35.6-7.51-56.46-7.51s-39.49 2.91-56.46 7.51l-18.15-36.3C252.06 89.1 256 77.02 256 64c0-35.35-28.65-64-64-64s-64 28.65-64 64c0 33.98 26.56 61.5 60.02 63.6l17.25 34.5C145.68 202.44 125.15 264 108 264c-6.94 0-11.34-5.03-21.94-21.17C74.88 225.78 57.96 200 24 200c-13.25 0-24 10.75-24 24s10.75 24 24 24c6.94 0 11.34 5.03 21.94 21.17C57.13 286.22 74.05 312 108 312c18.29 0 31.53-7.55 41.7-17.11 1.95 2.79 4.14 5.66 6.38 8.57-10.51 13.33-14.62 29.5-17.95 42.65-5.06 20-7.77 26.28-15.89 29.38-8.11 3.06-14.33.17-31.41-11.36-18.03-12.2-42.72-28.92-75.37-16.45-12.39 4.72-18.59 18.58-13.87 30.97 4.72 12.41 18.61 18.61 30.97 13.88 8.16-3.09 14.34-.19 31.39 11.36 13.55 9.16 30.83 20.86 52.42 20.84 7.17 0 14.83-1.28 22.97-4.39 32.66-12.44 39.98-41.33 45.33-62.44 2.21-8.72 3.99-14.49 5.95-18.87 16.62 13.61 36.95 25.88 61.64 34.17-9.96 37-32.18 90.8-60.26 90.8-13.25 0-24 10.75-24 24s10.75 24 24 24c66.74 0 97.05-88.63 107.42-129.14 6.69.6 13.42 1.14 20.58 1.14s13.89-.54 20.58-1.14C350.95 423.37 381.26 512 448 512c13.25 0 24-10.75 24-24s-10.75-24-24-24c-27.94 0-50.21-53.81-60.22-90.81 24.69-8.29 45-20.56 61.62-34.16 1.96 4.38 3.74 10.15 5.95 18.87 5.34 21.11 12.67 50 45.33 62.44 8.14 3.11 15.8 4.39 22.97 4.39 21.59 0 38.87-11.69 52.42-20.84 17.05-11.55 23.28-14.45 31.39-11.36 12.39 4.75 26.27-1.47 30.97-13.88 4.71-12.4-1.49-26.26-13.89-30.98zM448 48c8.82 0 16 7.18 16 16s-7.18 16-16 16-16-7.18-16-16 7.18-16 16-16zm-256 0c8.82 0 16 7.18 16 16s-7.18 16-16 16-16-7.18-16-16 7.18-16 16-16z\"]\n};\nvar faPaste = {\n prefix: 'fas',\n iconName: 'paste',\n icon: [448, 512, [], \"f0ea\", \"M128 184c0-30.879 25.122-56 56-56h136V56c0-13.255-10.745-24-24-24h-80.61C204.306 12.89 183.637 0 160 0s-44.306 12.89-55.39 32H24C10.745 32 0 42.745 0 56v336c0 13.255 10.745 24 24 24h104V184zm32-144c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24zm184 248h104v200c0 13.255-10.745 24-24 24H184c-13.255 0-24-10.745-24-24V184c0-13.255 10.745-24 24-24h136v104c0 13.2 10.8 24 24 24zm104-38.059V256h-96v-96h6.059a24 24 0 0 1 16.97 7.029l65.941 65.941a24.002 24.002 0 0 1 7.03 16.971z\"]\n};\nvar faPause = {\n prefix: 'fas',\n iconName: 'pause',\n icon: [448, 512, [], \"f04c\", \"M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z\"]\n};\nvar faPauseCircle = {\n prefix: 'fas',\n iconName: 'pause-circle',\n icon: [512, 512, [], \"f28b\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm-16 328c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v160zm112 0c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v160z\"]\n};\nvar faPaw = {\n prefix: 'fas',\n iconName: 'paw',\n icon: [512, 512, [], \"f1b0\", \"M256 224c-79.41 0-192 122.76-192 200.25 0 34.9 26.81 55.75 71.74 55.75 48.84 0 81.09-25.08 120.26-25.08 39.51 0 71.85 25.08 120.26 25.08 44.93 0 71.74-20.85 71.74-55.75C448 346.76 335.41 224 256 224zm-147.28-12.61c-10.4-34.65-42.44-57.09-71.56-50.13-29.12 6.96-44.29 40.69-33.89 75.34 10.4 34.65 42.44 57.09 71.56 50.13 29.12-6.96 44.29-40.69 33.89-75.34zm84.72-20.78c30.94-8.14 46.42-49.94 34.58-93.36s-46.52-72.01-77.46-63.87-46.42 49.94-34.58 93.36c11.84 43.42 46.53 72.02 77.46 63.87zm281.39-29.34c-29.12-6.96-61.15 15.48-71.56 50.13-10.4 34.65 4.77 68.38 33.89 75.34 29.12 6.96 61.15-15.48 71.56-50.13 10.4-34.65-4.77-68.38-33.89-75.34zm-156.27 29.34c30.94 8.14 65.62-20.45 77.46-63.87 11.84-43.42-3.64-85.21-34.58-93.36s-65.62 20.45-77.46 63.87c-11.84 43.42 3.64 85.22 34.58 93.36z\"]\n};\nvar faPeace = {\n prefix: 'fas',\n iconName: 'peace',\n icon: [496, 512, [], \"f67c\", \"M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm184 248c0 31.93-8.2 61.97-22.57 88.17L280 240.63V74.97c86.23 15.21 152 90.5 152 181.03zM216 437.03c-33.86-5.97-64.49-21.2-89.29-43.02L216 322.57v114.46zm64-114.46L369.29 394c-24.8 21.82-55.43 37.05-89.29 43.02V322.57zm-64-247.6v165.66L86.57 344.17C72.2 317.97 64 287.93 64 256c0-90.53 65.77-165.82 152-181.03z\"]\n};\nvar faPen = {\n prefix: 'fas',\n iconName: 'pen',\n icon: [512, 512, [], \"f304\", \"M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z\"]\n};\nvar faPenAlt = {\n prefix: 'fas',\n iconName: 'pen-alt',\n icon: [512, 512, [], \"f305\", \"M497.94 74.17l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.75 18.75-49.15 0-67.91zm-246.8-20.53c-15.62-15.62-40.94-15.62-56.56 0L75.8 172.43c-6.25 6.25-6.25 16.38 0 22.62l22.63 22.63c6.25 6.25 16.38 6.25 22.63 0l101.82-101.82 22.63 22.62L93.95 290.03A327.038 327.038 0 0 0 .17 485.11l-.03.23c-1.7 15.28 11.21 28.2 26.49 26.51a327.02 327.02 0 0 0 195.34-93.8l196.79-196.79-82.77-82.77-84.85-84.85z\"]\n};\nvar faPenFancy = {\n prefix: 'fas',\n iconName: 'pen-fancy',\n icon: [512, 512, [], \"f5ac\", \"M79.18 282.94a32.005 32.005 0 0 0-20.24 20.24L0 480l4.69 4.69 92.89-92.89c-.66-2.56-1.57-5.03-1.57-7.8 0-17.67 14.33-32 32-32s32 14.33 32 32-14.33 32-32 32c-2.77 0-5.24-.91-7.8-1.57l-92.89 92.89L32 512l176.82-58.94a31.983 31.983 0 0 0 20.24-20.24l33.07-84.07-98.88-98.88-84.07 33.07zM369.25 28.32L186.14 227.81l97.85 97.85 199.49-183.11C568.4 67.48 443.73-55.94 369.25 28.32z\"]\n};\nvar faPenNib = {\n prefix: 'fas',\n iconName: 'pen-nib',\n icon: [512, 512, [], \"f5ad\", \"M136.6 138.79a64.003 64.003 0 0 0-43.31 41.35L0 460l14.69 14.69L164.8 324.58c-2.99-6.26-4.8-13.18-4.8-20.58 0-26.51 21.49-48 48-48s48 21.49 48 48-21.49 48-48 48c-7.4 0-14.32-1.81-20.58-4.8L37.31 497.31 52 512l279.86-93.29a64.003 64.003 0 0 0 41.35-43.31L416 224 288 96l-151.4 42.79zm361.34-64.62l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.75 18.75-49.15 0-67.91z\"]\n};\nvar faPenSquare = {\n prefix: 'fas',\n iconName: 'pen-square',\n icon: [448, 512, [], \"f14b\", \"M400 480H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zM238.1 177.9L102.4 313.6l-6.3 57.1c-.8 7.6 5.6 14.1 13.3 13.3l57.1-6.3L302.2 242c2.3-2.3 2.3-6.1 0-8.5L246.7 178c-2.5-2.4-6.3-2.4-8.6-.1zM345 165.1L314.9 135c-9.4-9.4-24.6-9.4-33.9 0l-23.1 23.1c-2.3 2.3-2.3 6.1 0 8.5l55.5 55.5c2.3 2.3 6.1 2.3 8.5 0L345 199c9.3-9.3 9.3-24.5 0-33.9z\"]\n};\nvar faPencilAlt = {\n prefix: 'fas',\n iconName: 'pencil-alt',\n icon: [512, 512, [], \"f303\", \"M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z\"]\n};\nvar faPencilRuler = {\n prefix: 'fas',\n iconName: 'pencil-ruler',\n icon: [512, 512, [], \"f5ae\", \"M109.46 244.04l134.58-134.56-44.12-44.12-61.68 61.68a7.919 7.919 0 0 1-11.21 0l-11.21-11.21c-3.1-3.1-3.1-8.12 0-11.21l61.68-61.68-33.64-33.65C131.47-3.1 111.39-3.1 99 9.29L9.29 99c-12.38 12.39-12.39 32.47 0 44.86l100.17 100.18zm388.47-116.8c18.76-18.76 18.75-49.17 0-67.93l-45.25-45.25c-18.76-18.76-49.18-18.76-67.95 0l-46.02 46.01 113.2 113.2 46.02-46.03zM316.08 82.71l-297 296.96L.32 487.11c-2.53 14.49 10.09 27.11 24.59 24.56l107.45-18.84L429.28 195.9 316.08 82.71zm186.63 285.43l-33.64-33.64-61.68 61.68c-3.1 3.1-8.12 3.1-11.21 0l-11.21-11.21c-3.09-3.1-3.09-8.12 0-11.21l61.68-61.68-44.14-44.14L267.93 402.5l100.21 100.2c12.39 12.39 32.47 12.39 44.86 0l89.71-89.7c12.39-12.39 12.39-32.47 0-44.86z\"]\n};\nvar faPeopleCarry = {\n prefix: 'fas',\n iconName: 'people-carry',\n icon: [640, 512, [], \"f4ce\", \"M128 96c26.5 0 48-21.5 48-48S154.5 0 128 0 80 21.5 80 48s21.5 48 48 48zm384 0c26.5 0 48-21.5 48-48S538.5 0 512 0s-48 21.5-48 48 21.5 48 48 48zm125.7 372.1l-44-110-41.1 46.4-2 18.2 27.7 69.2c5 12.5 17 20.1 29.7 20.1 4 0 8-.7 11.9-2.3 16.4-6.6 24.4-25.2 17.8-41.6zm-34.2-209.8L585 178.1c-4.6-20-18.6-36.8-37.5-44.9-18.5-8-39-6.7-56.1 3.3-22.7 13.4-39.7 34.5-48.1 59.4L432 229.8 416 240v-96c0-8.8-7.2-16-16-16H240c-8.8 0-16 7.2-16 16v96l-16.1-10.2-11.3-33.9c-8.3-25-25.4-46-48.1-59.4-17.2-10-37.6-11.3-56.1-3.3-18.9 8.1-32.9 24.9-37.5 44.9l-18.4 80.2c-4.6 20 .7 41.2 14.4 56.7l67.2 75.9 10.1 92.6C130 499.8 143.8 512 160 512c1.2 0 2.3-.1 3.5-.2 17.6-1.9 30.2-17.7 28.3-35.3l-10.1-92.8c-1.5-13-6.9-25.1-15.6-35l-43.3-49 17.6-70.3 6.8 20.4c4.1 12.5 11.9 23.4 24.5 32.6l51.1 32.5c4.6 2.9 12.1 4.6 17.2 5h160c5.1-.4 12.6-2.1 17.2-5l51.1-32.5c12.6-9.2 20.4-20 24.5-32.6l6.8-20.4 17.6 70.3-43.3 49c-8.7 9.9-14.1 22-15.6 35l-10.1 92.8c-1.9 17.6 10.8 33.4 28.3 35.3 1.2.1 2.3.2 3.5.2 16.1 0 30-12.1 31.8-28.5l10.1-92.6 67.2-75.9c13.6-15.5 19-36.7 14.4-56.7zM46.3 358.1l-44 110c-6.6 16.4 1.4 35 17.8 41.6 16.8 6.6 35.1-1.7 41.6-17.8l27.7-69.2-2-18.2-41.1-46.4z\"]\n};\nvar faPepperHot = {\n prefix: 'fas',\n iconName: 'pepper-hot',\n icon: [512, 512, [], \"f816\", \"M330.67 263.12V173.4l-52.75-24.22C219.44 218.76 197.58 400 56 400a56 56 0 0 0 0 112c212.64 0 370.65-122.87 419.18-210.34l-37.05-38.54zm131.09-128.37C493.92 74.91 477.18 26.48 458.62 3a8 8 0 0 0-11.93-.59l-22.9 23a8.06 8.06 0 0 0-.89 10.23c6.86 10.36 17.05 35.1-1.4 72.32A142.85 142.85 0 0 0 364.34 96c-28 0-54 8.54-76.34 22.59l74.67 34.29v78.24h89.09L506.44 288c3.26-12.62 5.56-25.63 5.56-39.31a154 154 0 0 0-50.24-113.94z\"]\n};\nvar faPercent = {\n prefix: 'fas',\n iconName: 'percent',\n icon: [448, 512, [], \"f295\", \"M112 224c61.9 0 112-50.1 112-112S173.9 0 112 0 0 50.1 0 112s50.1 112 112 112zm0-160c26.5 0 48 21.5 48 48s-21.5 48-48 48-48-21.5-48-48 21.5-48 48-48zm224 224c-61.9 0-112 50.1-112 112s50.1 112 112 112 112-50.1 112-112-50.1-112-112-112zm0 160c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zM392.3.2l31.6-.1c19.4-.1 30.9 21.8 19.7 37.8L77.4 501.6a23.95 23.95 0 0 1-19.6 10.2l-33.4.1c-19.5 0-30.9-21.9-19.7-37.8l368-463.7C377.2 4 384.5.2 392.3.2z\"]\n};\nvar faPercentage = {\n prefix: 'fas',\n iconName: 'percentage',\n icon: [384, 512, [], \"f541\", \"M109.25 173.25c24.99-24.99 24.99-65.52 0-90.51-24.99-24.99-65.52-24.99-90.51 0-24.99 24.99-24.99 65.52 0 90.51 25 25 65.52 25 90.51 0zm256 165.49c-24.99-24.99-65.52-24.99-90.51 0-24.99 24.99-24.99 65.52 0 90.51 24.99 24.99 65.52 24.99 90.51 0 25-24.99 25-65.51 0-90.51zm-1.94-231.43l-22.62-22.62c-12.5-12.5-32.76-12.5-45.25 0L20.69 359.44c-12.5 12.5-12.5 32.76 0 45.25l22.62 22.62c12.5 12.5 32.76 12.5 45.25 0l274.75-274.75c12.5-12.49 12.5-32.75 0-45.25z\"]\n};\nvar faPersonBooth = {\n prefix: 'fas',\n iconName: 'person-booth',\n icon: [576, 512, [], \"f756\", \"M192 496c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320h-64v176zm32-272h-50.9l-45.2-45.3C115.8 166.6 99.7 160 82.7 160H64c-17.1 0-33.2 6.7-45.3 18.8C6.7 190.9 0 207 0 224.1L.2 320 0 480c0 17.7 14.3 32 31.9 32 17.6 0 32-14.3 32-32l.1-100.7c.9.5 1.6 1.3 2.5 1.7l29.1 43v56c0 17.7 14.3 32 32 32s32-14.3 32-32v-56.5c0-9.9-2.3-19.8-6.7-28.6l-41.2-61.3V253l20.9 20.9c9.1 9.1 21.1 14.1 33.9 14.1H224c17.7 0 32-14.3 32-32s-14.3-32-32-32zM64 128c26.5 0 48-21.5 48-48S90.5 32 64 32 16 53.5 16 80s21.5 48 48 48zm224-96l31.5 223.1-30.9 154.6c-4.3 21.6 13 38.3 31.4 38.3 15.2 0 28-9.1 32.3-30.4.9 16.9 14.6 30.4 31.7 30.4 17.7 0 32-14.3 32-32 0 17.7 14.3 32 32 32s32-14.3 32-32V0H288v32zm-96 0v160h64V0h-32c-17.7 0-32 14.3-32 32zM544 0h-32v496c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V32c0-17.7-14.3-32-32-32z\"]\n};\nvar faPhone = {\n prefix: 'fas',\n iconName: 'phone',\n icon: [512, 512, [], \"f095\", \"M493.4 24.6l-104-24c-11.3-2.6-22.9 3.3-27.5 13.9l-48 112c-4.2 9.8-1.4 21.3 6.9 28l60.6 49.6c-36 76.7-98.9 140.5-177.2 177.2l-49.6-60.6c-6.8-8.3-18.2-11.1-28-6.9l-112 48C3.9 366.5-2 378.1.6 389.4l24 104C27.1 504.2 36.7 512 48 512c256.1 0 464-207.5 464-464 0-11.2-7.7-20.9-18.6-23.4z\"]\n};\nvar faPhoneSlash = {\n prefix: 'fas',\n iconName: 'phone-slash',\n icon: [640, 512, [], \"f3dd\", \"M268.2 381.4l-49.6-60.6c-6.8-8.3-18.2-11.1-28-6.9l-112 48c-10.7 4.6-16.5 16.1-13.9 27.5l24 104c2.5 10.8 12.1 18.6 23.4 18.6 100.7 0 193.7-32.4 269.7-86.9l-80-61.8c-10.9 6.5-22.1 12.7-33.6 18.1zm365.6 76.7L475.1 335.5C537.9 256.4 576 156.9 576 48c0-11.2-7.7-20.9-18.6-23.4l-104-24c-11.3-2.6-22.9 3.3-27.5 13.9l-48 112c-4.2 9.8-1.4 21.3 6.9 28l60.6 49.6c-12.2 26.1-27.9 50.3-46 72.8L45.5 3.4C38.5-2 28.5-.8 23 6.2L3.4 31.4c-5.4 7-4.2 17 2.8 22.4l588.4 454.7c7 5.4 17 4.2 22.5-2.8l19.6-25.3c5.4-6.8 4.1-16.9-2.9-22.3z\"]\n};\nvar faPhoneSquare = {\n prefix: 'fas',\n iconName: 'phone-square',\n icon: [448, 512, [], \"f098\", \"M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM94 416c-7.033 0-13.057-4.873-14.616-11.627l-14.998-65a15 15 0 0 1 8.707-17.16l69.998-29.999a15 15 0 0 1 17.518 4.289l30.997 37.885c48.944-22.963 88.297-62.858 110.781-110.78l-37.886-30.997a15.001 15.001 0 0 1-4.289-17.518l30-69.998a15 15 0 0 1 17.16-8.707l65 14.998A14.997 14.997 0 0 1 384 126c0 160.292-129.945 290-290 290z\"]\n};\nvar faPhoneVolume = {\n prefix: 'fas',\n iconName: 'phone-volume',\n icon: [384, 512, [], \"f2a0\", \"M97.333 506.966c-129.874-129.874-129.681-340.252 0-469.933 5.698-5.698 14.527-6.632 21.263-2.422l64.817 40.513a17.187 17.187 0 0 1 6.849 20.958l-32.408 81.021a17.188 17.188 0 0 1-17.669 10.719l-55.81-5.58c-21.051 58.261-20.612 122.471 0 179.515l55.811-5.581a17.188 17.188 0 0 1 17.669 10.719l32.408 81.022a17.188 17.188 0 0 1-6.849 20.958l-64.817 40.513a17.19 17.19 0 0 1-21.264-2.422zM247.126 95.473c11.832 20.047 11.832 45.008 0 65.055-3.95 6.693-13.108 7.959-18.718 2.581l-5.975-5.726c-3.911-3.748-4.793-9.622-2.261-14.41a32.063 32.063 0 0 0 0-29.945c-2.533-4.788-1.65-10.662 2.261-14.41l5.975-5.726c5.61-5.378 14.768-4.112 18.718 2.581zm91.787-91.187c60.14 71.604 60.092 175.882 0 247.428-4.474 5.327-12.53 5.746-17.552.933l-5.798-5.557c-4.56-4.371-4.977-11.529-.93-16.379 49.687-59.538 49.646-145.933 0-205.422-4.047-4.85-3.631-12.008.93-16.379l5.798-5.557c5.022-4.813 13.078-4.394 17.552.933zm-45.972 44.941c36.05 46.322 36.108 111.149 0 157.546-4.39 5.641-12.697 6.251-17.856 1.304l-5.818-5.579c-4.4-4.219-4.998-11.095-1.285-15.931 26.536-34.564 26.534-82.572 0-117.134-3.713-4.836-3.115-11.711 1.285-15.931l5.818-5.579c5.159-4.947 13.466-4.337 17.856 1.304z\"]\n};\nvar faPiggyBank = {\n prefix: 'fas',\n iconName: 'piggy-bank',\n icon: [576, 512, [], \"f4d3\", \"M560 224h-29.5c-8.8-20-21.6-37.7-37.4-52.5L512 96h-32c-29.4 0-55.4 13.5-73 34.3-7.6-1.1-15.1-2.3-23-2.3H256c-77.4 0-141.9 55-156.8 128H56c-14.8 0-26.5-13.5-23.5-28.8C34.7 215.8 45.4 208 57 208h1c3.3 0 6-2.7 6-6v-20c0-3.3-2.7-6-6-6-28.5 0-53.9 20.4-57.5 48.6C-3.9 258.8 22.7 288 56 288h40c0 52.2 25.4 98.1 64 127.3V496c0 8.8 7.2 16 16 16h64c8.8 0 16-7.2 16-16v-48h128v48c0 8.8 7.2 16 16 16h64c8.8 0 16-7.2 16-16v-80.7c11.8-8.9 22.3-19.4 31.3-31.3H560c8.8 0 16-7.2 16-16V240c0-8.8-7.2-16-16-16zm-128 64c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zM256 96h128c5.4 0 10.7.4 15.9.8 0-.3.1-.5.1-.8 0-53-43-96-96-96s-96 43-96 96c0 2.1.5 4.1.6 6.2 15.2-3.9 31-6.2 47.4-6.2z\"]\n};\nvar faPills = {\n prefix: 'fas',\n iconName: 'pills',\n icon: [576, 512, [], \"f484\", \"M112 32C50.1 32 0 82.1 0 144v224c0 61.9 50.1 112 112 112s112-50.1 112-112V144c0-61.9-50.1-112-112-112zm48 224H64V144c0-26.5 21.5-48 48-48s48 21.5 48 48v112zm139.7-29.7c-3.5-3.5-9.4-3.1-12.3.8-45.3 62.5-40.4 150.1 15.9 206.4 56.3 56.3 143.9 61.2 206.4 15.9 4-2.9 4.3-8.8.8-12.3L299.7 226.3zm229.8-19c-56.3-56.3-143.9-61.2-206.4-15.9-4 2.9-4.3 8.8-.8 12.3l210.8 210.8c3.5 3.5 9.4 3.1 12.3-.8 45.3-62.6 40.5-150.1-15.9-206.4z\"]\n};\nvar faPizzaSlice = {\n prefix: 'fas',\n iconName: 'pizza-slice',\n icon: [512, 512, [], \"f818\", \"M158.87.15c-16.16-1.52-31.2 8.42-35.33 24.12l-14.81 56.27c187.62 5.49 314.54 130.61 322.48 317l56.94-15.78c15.72-4.36 25.49-19.68 23.62-35.9C490.89 165.08 340.78 17.32 158.87.15zm-58.47 112L.55 491.64a16.21 16.21 0 0 0 20 19.75l379-105.1c-4.27-174.89-123.08-292.14-299.15-294.1zM128 416a32 32 0 1 1 32-32 32 32 0 0 1-32 32zm48-152a32 32 0 1 1 32-32 32 32 0 0 1-32 32zm104 104a32 32 0 1 1 32-32 32 32 0 0 1-32 32z\"]\n};\nvar faPlaceOfWorship = {\n prefix: 'fas',\n iconName: 'place-of-worship',\n icon: [640, 512, [], \"f67f\", \"M620.61 366.55L512 320v192h112c8.84 0 16-7.16 16-16V395.96a32 32 0 0 0-19.39-29.41zM0 395.96V496c0 8.84 7.16 16 16 16h112V320L19.39 366.55A32 32 0 0 0 0 395.96zm464.46-149.28L416 217.6V102.63c0-8.49-3.37-16.62-9.38-22.63L331.31 4.69c-6.25-6.25-16.38-6.25-22.62 0L233.38 80c-6 6-9.38 14.14-9.38 22.63V217.6l-48.46 29.08A31.997 31.997 0 0 0 160 274.12V512h96v-96c0-35.35 28.66-64 64-64s64 28.65 64 64v96h96V274.12c0-11.24-5.9-21.66-15.54-27.44z\"]\n};\nvar faPlane = {\n prefix: 'fas',\n iconName: 'plane',\n icon: [576, 512, [], \"f072\", \"M480 192H365.71L260.61 8.06A16.014 16.014 0 0 0 246.71 0h-65.5c-10.63 0-18.3 10.17-15.38 20.39L214.86 192H112l-43.2-57.6c-3.02-4.03-7.77-6.4-12.8-6.4H16.01C5.6 128-2.04 137.78.49 147.88L32 256 .49 364.12C-2.04 374.22 5.6 384 16.01 384H56c5.04 0 9.78-2.37 12.8-6.4L112 320h102.86l-49.03 171.6c-2.92 10.22 4.75 20.4 15.38 20.4h65.5c5.74 0 11.04-3.08 13.89-8.06L365.71 320H480c35.35 0 96-28.65 96-64s-60.65-64-96-64z\"]\n};\nvar faPlaneArrival = {\n prefix: 'fas',\n iconName: 'plane-arrival',\n icon: [640, 512, [], \"f5af\", \"M624 448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h608c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM44.81 205.66l88.74 80a62.607 62.607 0 0 0 25.47 13.93l287.6 78.35c26.48 7.21 54.56 8.72 81 1.36 29.67-8.27 43.44-21.21 47.25-35.71 3.83-14.5-1.73-32.71-23.37-54.96-19.28-19.82-44.35-32.79-70.83-40l-97.51-26.56L282.8 30.22c-1.51-5.81-5.95-10.35-11.66-11.91L206.05.58c-10.56-2.88-20.9 5.32-20.71 16.44l47.92 164.21-102.2-27.84-27.59-67.88c-1.93-4.89-6.01-8.57-11.02-9.93L52.72 64.75c-10.34-2.82-20.53 5-20.72 15.88l.23 101.78c.19 8.91 6.03 17.34 12.58 23.25z\"]\n};\nvar faPlaneDeparture = {\n prefix: 'fas',\n iconName: 'plane-departure',\n icon: [640, 512, [], \"f5b0\", \"M624 448H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h608c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM80.55 341.27c6.28 6.84 15.1 10.72 24.33 10.71l130.54-.18a65.62 65.62 0 0 0 29.64-7.12l290.96-147.65c26.74-13.57 50.71-32.94 67.02-58.31 18.31-28.48 20.3-49.09 13.07-63.65-7.21-14.57-24.74-25.27-58.25-27.45-29.85-1.94-59.54 5.92-86.28 19.48l-98.51 49.99-218.7-82.06a17.799 17.799 0 0 0-18-1.11L90.62 67.29c-10.67 5.41-13.25 19.65-5.17 28.53l156.22 98.1-103.21 52.38-72.35-36.47a17.804 17.804 0 0 0-16.07.02L9.91 230.22c-10.44 5.3-13.19 19.12-5.57 28.08l76.21 82.97z\"]\n};\nvar faPlay = {\n prefix: 'fas',\n iconName: 'play',\n icon: [448, 512, [], \"f04b\", \"M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z\"]\n};\nvar faPlayCircle = {\n prefix: 'fas',\n iconName: 'play-circle',\n icon: [512, 512, [], \"f144\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z\"]\n};\nvar faPlug = {\n prefix: 'fas',\n iconName: 'plug',\n icon: [384, 512, [], \"f1e6\", \"M256 144V32c0-17.673 14.327-32 32-32s32 14.327 32 32v112h-64zm112 16H16c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h16v32c0 77.406 54.969 141.971 128 156.796V512h64v-99.204c73.031-14.825 128-79.39 128-156.796v-32h16c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16zm-240-16V32c0-17.673-14.327-32-32-32S64 14.327 64 32v112h64z\"]\n};\nvar faPlus = {\n prefix: 'fas',\n iconName: 'plus',\n icon: [448, 512, [], \"f067\", \"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"]\n};\nvar faPlusCircle = {\n prefix: 'fas',\n iconName: 'plus-circle',\n icon: [512, 512, [], \"f055\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z\"]\n};\nvar faPlusSquare = {\n prefix: 'fas',\n iconName: 'plus-square',\n icon: [448, 512, [], \"f0fe\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-32 252c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92H92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z\"]\n};\nvar faPodcast = {\n prefix: 'fas',\n iconName: 'podcast',\n icon: [448, 512, [], \"f2ce\", \"M267.429 488.563C262.286 507.573 242.858 512 224 512c-18.857 0-38.286-4.427-43.428-23.437C172.927 460.134 160 388.898 160 355.75c0-35.156 31.142-43.75 64-43.75s64 8.594 64 43.75c0 32.949-12.871 104.179-20.571 132.813zM156.867 288.554c-18.693-18.308-29.958-44.173-28.784-72.599 2.054-49.724 42.395-89.956 92.124-91.881C274.862 121.958 320 165.807 320 220c0 26.827-11.064 51.116-28.866 68.552-2.675 2.62-2.401 6.986.628 9.187 9.312 6.765 16.46 15.343 21.234 25.363 1.741 3.654 6.497 4.66 9.449 1.891 28.826-27.043 46.553-65.783 45.511-108.565-1.855-76.206-63.595-138.208-139.793-140.369C146.869 73.753 80 139.215 80 220c0 41.361 17.532 78.7 45.55 104.989 2.953 2.771 7.711 1.77 9.453-1.887 4.774-10.021 11.923-18.598 21.235-25.363 3.029-2.2 3.304-6.566.629-9.185zM224 0C100.204 0 0 100.185 0 224c0 89.992 52.602 165.647 125.739 201.408 4.333 2.118 9.267-1.544 8.535-6.31-2.382-15.512-4.342-30.946-5.406-44.339-.146-1.836-1.149-3.486-2.678-4.512-47.4-31.806-78.564-86.016-78.187-147.347.592-96.237 79.29-174.648 175.529-174.899C320.793 47.747 400 126.797 400 224c0 61.932-32.158 116.49-80.65 147.867-.999 14.037-3.069 30.588-5.624 47.23-.732 4.767 4.203 8.429 8.535 6.31C395.227 389.727 448 314.187 448 224 448 100.205 347.815 0 224 0zm0 160c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64z\"]\n};\nvar faPoll = {\n prefix: 'fas',\n iconName: 'poll',\n icon: [448, 512, [], \"f681\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM160 368c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16V240c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v128zm96 0c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16V144c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v224zm96 0c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-64c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v64z\"]\n};\nvar faPollH = {\n prefix: 'fas',\n iconName: 'poll-h',\n icon: [448, 512, [], \"f682\", \"M448 432V80c0-26.5-21.5-48-48-48H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48zM112 192c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h128c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16H112zm0 96c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h224c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16H112zm0 96c-8.84 0-16-7.16-16-16v-32c0-8.84 7.16-16 16-16h64c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16h-64z\"]\n};\nvar faPoo = {\n prefix: 'fas',\n iconName: 'poo',\n icon: [512, 512, [], \"f2fe\", \"M451.4 369.1C468.7 356 480 335.4 480 312c0-39.8-32.2-72-72-72h-14.1c13.4-11.7 22.1-28.8 22.1-48 0-35.3-28.7-64-64-64h-5.9c3.6-10.1 5.9-20.7 5.9-32 0-53-43-96-96-96-5.2 0-10.2.7-15.1 1.5C250.3 14.6 256 30.6 256 48c0 44.2-35.8 80-80 80h-16c-35.3 0-64 28.7-64 64 0 19.2 8.7 36.3 22.1 48H104c-39.8 0-72 32.2-72 72 0 23.4 11.3 44 28.6 57.1C26.3 374.6 0 404.1 0 440c0 39.8 32.2 72 72 72h368c39.8 0 72-32.2 72-72 0-35.9-26.3-65.4-60.6-70.9zM192 256c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm159.5 139C341 422.9 293 448 256 448s-85-25.1-95.5-53c-2-5.3 2-11 7.8-11h175.4c5.8 0 9.8 5.7 7.8 11zM320 320c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faPooStorm = {\n prefix: 'fas',\n iconName: 'poo-storm',\n icon: [448, 512, [], \"f75a\", \"M308 336h-57.7l17.3-64.9c2-7.6-3.7-15.1-11.6-15.1h-68c-6 0-11.1 4.5-11.9 10.4l-16 120c-1 7.2 4.6 13.6 11.9 13.6h59.3l-23 97.2c-1.8 7.6 4 14.8 11.7 14.8 4.2 0 8.2-2.2 10.4-6l88-152c4.6-8-1.2-18-10.4-18zm66.4-111.3c5.9-9.6 9.6-20.6 9.6-32.7 0-35.3-28.7-64-64-64h-5.9c3.6-10.1 5.9-20.7 5.9-32 0-53-43-96-96-96-5.2 0-10.2.7-15.1 1.5C218.3 14.6 224 30.6 224 48c0 44.2-35.8 80-80 80h-16c-35.3 0-64 28.7-64 64 0 12.1 3.7 23.1 9.6 32.7C32.6 228 0 262.2 0 304c0 44 36 80 80 80h48.3c.1-.6 0-1.2 0-1.8l16-120c3-21.8 21.7-38.2 43.7-38.2h68c13.8 0 26.5 6.3 34.9 17.2s11.2 24.8 7.6 38.1l-6.6 24.7h16c15.7 0 30.3 8.4 38.1 22 7.8 13.6 7.8 30.5 0 44l-8.1 14h30c44 0 80-36 80-80 .1-41.8-32.5-76-73.5-79.3z\"]\n};\nvar faPoop = {\n prefix: 'fas',\n iconName: 'poop',\n icon: [512, 512, [], \"f619\", \"M451.36 369.14C468.66 355.99 480 335.41 480 312c0-39.77-32.24-72-72-72h-14.07c13.42-11.73 22.07-28.78 22.07-48 0-35.35-28.65-64-64-64h-5.88c3.57-10.05 5.88-20.72 5.88-32 0-53.02-42.98-96-96-96-5.17 0-10.15.74-15.11 1.52C250.31 14.64 256 30.62 256 48c0 44.18-35.82 80-80 80h-16c-35.35 0-64 28.65-64 64 0 19.22 8.65 36.27 22.07 48H104c-39.76 0-72 32.23-72 72 0 23.41 11.34 43.99 28.64 57.14C26.31 374.62 0 404.12 0 440c0 39.76 32.24 72 72 72h368c39.76 0 72-32.24 72-72 0-35.88-26.31-65.38-60.64-70.86z\"]\n};\nvar faPortrait = {\n prefix: 'fas',\n iconName: 'portrait',\n icon: [384, 512, [], \"f3e0\", \"M336 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM192 128c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zm112 236.8c0 10.6-10 19.2-22.4 19.2H102.4C90 384 80 375.4 80 364.8v-19.2c0-31.8 30.1-57.6 67.2-57.6h5c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h5c37.1 0 67.2 25.8 67.2 57.6v19.2z\"]\n};\nvar faPoundSign = {\n prefix: 'fas',\n iconName: 'pound-sign',\n icon: [320, 512, [], \"f154\", \"M308 352h-45.495c-6.627 0-12 5.373-12 12v50.848H128V288h84c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-84v-63.556c0-32.266 24.562-57.086 61.792-57.086 23.658 0 45.878 11.505 57.652 18.849 5.151 3.213 11.888 2.051 15.688-2.685l28.493-35.513c4.233-5.276 3.279-13.005-2.119-17.081C273.124 54.56 236.576 32 187.931 32 106.026 32 48 84.742 48 157.961V224H20c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h28v128H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h296c6.627 0 12-5.373 12-12V364c0-6.627-5.373-12-12-12z\"]\n};\nvar faPowerOff = {\n prefix: 'fas',\n iconName: 'power-off',\n icon: [512, 512, [], \"f011\", \"M400 54.1c63 45 104 118.6 104 201.9 0 136.8-110.8 247.7-247.5 248C120 504.3 8.2 393 8 256.4 7.9 173.1 48.9 99.3 111.8 54.2c11.7-8.3 28-4.8 35 7.7L162.6 90c5.9 10.5 3.1 23.8-6.6 31-41.5 30.8-68 79.6-68 134.9-.1 92.3 74.5 168.1 168 168.1 91.6 0 168.6-74.2 168-169.1-.3-51.8-24.7-101.8-68.1-134-9.7-7.2-12.4-20.5-6.5-30.9l15.8-28.1c7-12.4 23.2-16.1 34.8-7.8zM296 264V24c0-13.3-10.7-24-24-24h-32c-13.3 0-24 10.7-24 24v240c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24z\"]\n};\nvar faPray = {\n prefix: 'fas',\n iconName: 'pray',\n icon: [384, 512, [], \"f683\", \"M256 128c35.35 0 64-28.65 64-64S291.35 0 256 0s-64 28.65-64 64 28.65 64 64 64zm-30.63 169.75c14.06 16.72 39 19.09 55.97 5.22l88-72.02c17.09-13.98 19.59-39.19 5.62-56.28-13.97-17.11-39.19-19.59-56.31-5.62l-57.44 47-38.91-46.31c-15.44-18.39-39.22-27.92-64-25.33-24.19 2.48-45.25 16.27-56.37 36.92l-49.37 92.03c-23.4 43.64-8.69 96.37 34.19 123.75L131.56 432H40c-22.09 0-40 17.91-40 40s17.91 40 40 40h208c34.08 0 53.77-42.79 28.28-68.28L166.42 333.86l34.8-64.87 24.15 28.76z\"]\n};\nvar faPrayingHands = {\n prefix: 'fas',\n iconName: 'praying-hands',\n icon: [640, 512, [], \"f684\", \"M272 191.91c-17.6 0-32 14.4-32 32v80c0 8.84-7.16 16-16 16s-16-7.16-16-16v-76.55c0-17.39 4.72-34.47 13.69-49.39l77.75-129.59c9.09-15.16 4.19-34.81-10.97-43.91-14.45-8.67-32.72-4.3-42.3 9.21-.2.23-.62.21-.79.48l-117.26 175.9C117.56 205.9 112 224.31 112 243.29v80.23l-90.12 30.04A31.974 31.974 0 0 0 0 383.91v96c0 10.82 8.52 32 32 32 2.69 0 5.41-.34 8.06-1.03l179.19-46.62C269.16 449.99 304 403.8 304 351.91v-128c0-17.6-14.4-32-32-32zm346.12 161.73L528 323.6v-80.23c0-18.98-5.56-37.39-16.12-53.23L394.62 14.25c-.18-.27-.59-.24-.79-.48-9.58-13.51-27.85-17.88-42.3-9.21-15.16 9.09-20.06 28.75-10.97 43.91l77.75 129.59c8.97 14.92 13.69 32 13.69 49.39V304c0 8.84-7.16 16-16 16s-16-7.16-16-16v-80c0-17.6-14.4-32-32-32s-32 14.4-32 32v128c0 51.89 34.84 98.08 84.75 112.34l179.19 46.62c2.66.69 5.38 1.03 8.06 1.03 23.48 0 32-21.18 32-32v-96c0-13.77-8.81-25.99-21.88-30.35z\"]\n};\nvar faPrescription = {\n prefix: 'fas',\n iconName: 'prescription',\n icon: [384, 512, [], \"f5b1\", \"M301.26 352l78.06-78.06c6.25-6.25 6.25-16.38 0-22.63l-22.63-22.63c-6.25-6.25-16.38-6.25-22.63 0L256 306.74l-83.96-83.96C219.31 216.8 256 176.89 256 128c0-53.02-42.98-96-96-96H16C7.16 32 0 39.16 0 48v256c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-80h18.75l128 128-78.06 78.06c-6.25 6.25-6.25 16.38 0 22.63l22.63 22.63c6.25 6.25 16.38 6.25 22.63 0L256 397.25l78.06 78.06c6.25 6.25 16.38 6.25 22.63 0l22.63-22.63c6.25-6.25 6.25-16.38 0-22.63L301.26 352zM64 96h96c17.64 0 32 14.36 32 32s-14.36 32-32 32H64V96z\"]\n};\nvar faPrescriptionBottle = {\n prefix: 'fas',\n iconName: 'prescription-bottle',\n icon: [384, 512, [], \"f485\", \"M32 192h120c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H32v64h120c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H32v64h120c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H32v64c0 17.6 14.4 32 32 32h256c17.6 0 32-14.4 32-32V128H32v64zM360 0H24C10.8 0 0 10.8 0 24v48c0 13.2 10.8 24 24 24h336c13.2 0 24-10.8 24-24V24c0-13.2-10.8-24-24-24z\"]\n};\nvar faPrescriptionBottleAlt = {\n prefix: 'fas',\n iconName: 'prescription-bottle-alt',\n icon: [384, 512, [], \"f486\", \"M360 0H24C10.8 0 0 10.8 0 24v48c0 13.2 10.8 24 24 24h336c13.2 0 24-10.8 24-24V24c0-13.2-10.8-24-24-24zM32 480c0 17.6 14.4 32 32 32h256c17.6 0 32-14.4 32-32V128H32v352zm64-184c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8v48c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48z\"]\n};\nvar faPrint = {\n prefix: 'fas',\n iconName: 'print',\n icon: [512, 512, [], \"f02f\", \"M448 192V77.25c0-8.49-3.37-16.62-9.37-22.63L393.37 9.37c-6-6-14.14-9.37-22.63-9.37H96C78.33 0 64 14.33 64 32v160c-35.35 0-64 28.65-64 64v112c0 8.84 7.16 16 16 16h48v96c0 17.67 14.33 32 32 32h320c17.67 0 32-14.33 32-32v-96h48c8.84 0 16-7.16 16-16V256c0-35.35-28.65-64-64-64zm-64 256H128v-96h256v96zm0-224H128V64h192v48c0 8.84 7.16 16 16 16h48v96zm48 72c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24z\"]\n};\nvar faProcedures = {\n prefix: 'fas',\n iconName: 'procedures',\n icon: [640, 512, [], \"f487\", \"M528 224H272c-8.8 0-16 7.2-16 16v144H64V144c0-8.8-7.2-16-16-16H16c-8.8 0-16 7.2-16 16v352c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-48h512v48c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V336c0-61.9-50.1-112-112-112zM136 96h126.1l27.6 55.2c5.9 11.8 22.7 11.8 28.6 0L368 51.8 390.1 96H512c8.8 0 16-7.2 16-16s-7.2-16-16-16H409.9L382.3 8.8C376.4-3 359.6-3 353.7 8.8L304 108.2l-19.9-39.8c-1.4-2.7-4.1-4.4-7.2-4.4H136c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8zm24 256c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64z\"]\n};\nvar faProjectDiagram = {\n prefix: 'fas',\n iconName: 'project-diagram',\n icon: [640, 512, [], \"f542\", \"M384 320H256c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h128c17.67 0 32-14.33 32-32V352c0-17.67-14.33-32-32-32zM192 32c0-17.67-14.33-32-32-32H32C14.33 0 0 14.33 0 32v128c0 17.67 14.33 32 32 32h95.72l73.16 128.04C211.98 300.98 232.4 288 256 288h.28L192 175.51V128h224V64H192V32zM608 0H480c-17.67 0-32 14.33-32 32v128c0 17.67 14.33 32 32 32h128c17.67 0 32-14.33 32-32V32c0-17.67-14.33-32-32-32z\"]\n};\nvar faPuzzlePiece = {\n prefix: 'fas',\n iconName: 'puzzle-piece',\n icon: [576, 512, [], \"f12e\", \"M519.442 288.651c-41.519 0-59.5 31.593-82.058 31.593C377.409 320.244 432 144 432 144s-196.288 80-196.288-3.297c0-35.827 36.288-46.25 36.288-85.985C272 19.216 243.885 0 210.539 0c-34.654 0-66.366 18.891-66.366 56.346 0 41.364 31.711 59.277 31.711 81.75C175.885 207.719 0 166.758 0 166.758v333.237s178.635 41.047 178.635-28.662c0-22.473-40-40.107-40-81.471 0-37.456 29.25-56.346 63.577-56.346 33.673 0 61.788 19.216 61.788 54.717 0 39.735-36.288 50.158-36.288 85.985 0 60.803 129.675 25.73 181.23 25.73 0 0-34.725-120.101 25.827-120.101 35.962 0 46.423 36.152 86.308 36.152C556.712 416 576 387.99 576 354.443c0-34.199-18.962-65.792-56.558-65.792z\"]\n};\nvar faQrcode = {\n prefix: 'fas',\n iconName: 'qrcode',\n icon: [448, 512, [], \"f029\", \"M0 224h192V32H0v192zM64 96h64v64H64V96zm192-64v192h192V32H256zm128 128h-64V96h64v64zM0 480h192V288H0v192zm64-128h64v64H64v-64zm352-64h32v128h-96v-32h-32v96h-64V288h96v32h64v-32zm0 160h32v32h-32v-32zm-64 0h32v32h-32v-32z\"]\n};\nvar faQuestion = {\n prefix: 'fas',\n iconName: 'question',\n icon: [384, 512, [], \"f128\", \"M202.021 0C122.202 0 70.503 32.703 29.914 91.026c-7.363 10.58-5.093 25.086 5.178 32.874l43.138 32.709c10.373 7.865 25.132 6.026 33.253-4.148 25.049-31.381 43.63-49.449 82.757-49.449 30.764 0 68.816 19.799 68.816 49.631 0 22.552-18.617 34.134-48.993 51.164-35.423 19.86-82.299 44.576-82.299 106.405V320c0 13.255 10.745 24 24 24h72.471c13.255 0 24-10.745 24-24v-5.773c0-42.86 125.268-44.645 125.268-160.627C377.504 66.256 286.902 0 202.021 0zM192 373.459c-38.196 0-69.271 31.075-69.271 69.271 0 38.195 31.075 69.27 69.271 69.27s69.271-31.075 69.271-69.271-31.075-69.27-69.271-69.27z\"]\n};\nvar faQuestionCircle = {\n prefix: 'fas',\n iconName: 'question-circle',\n icon: [512, 512, [], \"f059\", \"M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zM262.655 90c-54.497 0-89.255 22.957-116.549 63.758-3.536 5.286-2.353 12.415 2.715 16.258l34.699 26.31c5.205 3.947 12.621 3.008 16.665-2.122 17.864-22.658 30.113-35.797 57.303-35.797 20.429 0 45.698 13.148 45.698 32.958 0 14.976-12.363 22.667-32.534 33.976C247.128 238.528 216 254.941 216 296v4c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12v-1.333c0-28.462 83.186-29.647 83.186-106.667 0-58.002-60.165-102-116.531-102zM256 338c-25.365 0-46 20.635-46 46 0 25.364 20.635 46 46 46s46-20.636 46-46c0-25.365-20.635-46-46-46z\"]\n};\nvar faQuidditch = {\n prefix: 'fas',\n iconName: 'quidditch',\n icon: [640, 512, [], \"f458\", \"M256.5 216.8L343.2 326s-16.6 102.4-76.6 150.1C206.7 523.8 0 510.2 0 510.2s3.8-23.1 11-55.4l94.6-112.2c4-4.7-.9-11.6-6.6-9.5l-60.4 22.1c14.4-41.7 32.7-80 54.6-97.5 59.9-47.8 163.3-40.9 163.3-40.9zm238 135c-44 0-79.8 35.8-79.8 79.9 0 44.1 35.7 79.9 79.8 79.9 44.1 0 79.8-35.8 79.8-79.9 0-44.2-35.8-79.9-79.8-79.9zM636.5 31L616.7 6c-5.5-6.9-15.5-8-22.4-2.6L361.8 181.3l-34.1-43c-5.1-6.4-15.1-5.2-18.6 2.2l-25.3 54.6 86.7 109.2 58.8-12.4c8-1.7 11.4-11.2 6.3-17.6l-34.1-42.9L634 53.5c6.9-5.5 8-15.6 2.5-22.5z\"]\n};\nvar faQuoteLeft = {\n prefix: 'fas',\n iconName: 'quote-left',\n icon: [512, 512, [], \"f10d\", \"M464 256h-80v-64c0-35.3 28.7-64 64-64h8c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24h-8c-88.4 0-160 71.6-160 160v240c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48zm-288 0H96v-64c0-35.3 28.7-64 64-64h8c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24h-8C71.6 32 0 103.6 0 192v240c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z\"]\n};\nvar faQuoteRight = {\n prefix: 'fas',\n iconName: 'quote-right',\n icon: [512, 512, [], \"f10e\", \"M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z\"]\n};\nvar faQuran = {\n prefix: 'fas',\n iconName: 'quran',\n icon: [448, 512, [], \"f687\", \"M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM301.08 145.82c.6-1.21 1.76-1.82 2.92-1.82s2.32.61 2.92 1.82l11.18 22.65 25 3.63c2.67.39 3.74 3.67 1.81 5.56l-18.09 17.63 4.27 24.89c.36 2.11-1.31 3.82-3.21 3.82-.5 0-1.02-.12-1.52-.38L304 211.87l-22.36 11.75c-.5.26-1.02.38-1.52.38-1.9 0-3.57-1.71-3.21-3.82l4.27-24.89-18.09-17.63c-1.94-1.89-.87-5.17 1.81-5.56l24.99-3.63 11.19-22.65zm-57.89-69.01c13.67 0 27.26 2.49 40.38 7.41a6.775 6.775 0 1 1-2.38 13.12c-.67 0-3.09-.21-4.13-.21-52.31 0-94.86 42.55-94.86 94.86 0 52.3 42.55 94.86 94.86 94.86 1.03 0 3.48-.21 4.13-.21 3.93 0 6.8 3.14 6.8 6.78 0 2.98-1.94 5.51-4.62 6.42-13.07 4.87-26.59 7.34-40.19 7.34C179.67 307.19 128 255.51 128 192c0-63.52 51.67-115.19 115.19-115.19zM380.8 448H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8v64z\"]\n};\nvar faRadiation = {\n prefix: 'fas',\n iconName: 'radiation',\n icon: [496, 512, [], \"f7b9\", \"M167.8 256.2H16.2C7.1 256.2-.6 263.9 0 273c5.1 75.8 44.4 142.2 102.5 184.2 7.4 5.3 17.9 2.9 22.7-4.8L205.6 324c-22.6-14.3-37.8-39.2-37.8-67.8zm37.8-67.7c12.3-7.7 26.8-12.4 42.4-12.4s30 4.7 42.4 12.4L370.8 60c4.8-7.7 2.4-18.1-5.6-22.4C330.3 18.8 290.4 8 248 8s-82.3 10.8-117.2 29.6c-8 4.3-10.4 14.8-5.6 22.4l80.4 128.5zm42.4 19.7c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm231.8 48H328.2c0 28.6-15.2 53.5-37.8 67.7l80.4 128.4c4.8 7.7 15.3 10.2 22.7 4.8 58.1-42 97.4-108.4 102.5-184.2.6-9-7.1-16.7-16.2-16.7z\"]\n};\nvar faRadiationAlt = {\n prefix: 'fas',\n iconName: 'radiation-alt',\n icon: [496, 512, [], \"f7ba\", \"M184 256h-79.1c-9.2 0-16.9 7.7-16 16.8 4.6 43.6 27 81.8 59.5 107.8 7.6 6.1 18.8 4.5 24-3.8l41.7-66.8c-18-11.2-30.1-31.2-30.1-54zm97.8-54.1l41.8-66.9c4.9-7.8 2.4-18.4-5.8-22.5C296.7 102.1 273.1 96 248 96s-48.7 6.1-69.9 16.5c-8.2 4.1-10.6 14.7-5.8 22.5l41.8 66.9c9.8-6.2 21.4-9.9 33.8-9.9s24.1 3.7 33.9 9.9zM391.1 256H312c0 22.8-12.1 42.8-30.2 54.1l41.7 66.8c5.2 8.3 16.4 9.9 24 3.8 32.6-26 54.9-64.2 59.5-107.8 1.1-9.2-6.7-16.9-15.9-16.9zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 432c-101.5 0-184-82.5-184-184S146.5 72 248 72s184 82.5 184 184-82.5 184-184 184zm0-216c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z\"]\n};\nvar faRainbow = {\n prefix: 'fas',\n iconName: 'rainbow',\n icon: [576, 512, [], \"f75b\", \"M268.3 32.7C115.4 42.9 0 176.9 0 330.2V464c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320C64 186.8 180.9 80.3 317.5 97.9 430.4 112.4 512 214 512 327.8V464c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320c0-165.3-140-298.6-307.7-287.3zm-5.6 96.9C166 142 96 229.1 96 326.7V464c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320c0-74.8 64.5-134.8 140.8-127.4 66.5 6.5 115.2 66.2 115.2 133.1V464c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320c0-114.2-100.2-205.4-217.3-190.4zm6.2 96.3c-45.6 8.9-76.9 51.5-76.9 97.9V464c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320c0-17.6 14.3-32 32-32s32 14.4 32 32v144c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320c0-59.2-53.8-106-115.1-94.1z\"]\n};\nvar faRandom = {\n prefix: 'fas',\n iconName: 'random',\n icon: [512, 512, [], \"f074\", \"M504.971 359.029c9.373 9.373 9.373 24.569 0 33.941l-80 79.984c-15.01 15.01-40.971 4.49-40.971-16.971V416h-58.785a12.004 12.004 0 0 1-8.773-3.812l-70.556-75.596 53.333-57.143L352 336h32v-39.981c0-21.438 25.943-31.998 40.971-16.971l80 79.981zM12 176h84l52.781 56.551 53.333-57.143-70.556-75.596A11.999 11.999 0 0 0 122.785 96H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12zm372 0v39.984c0 21.46 25.961 31.98 40.971 16.971l80-79.984c9.373-9.373 9.373-24.569 0-33.941l-80-79.981C409.943 24.021 384 34.582 384 56.019V96h-58.785a12.004 12.004 0 0 0-8.773 3.812L96 336H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h110.785c3.326 0 6.503-1.381 8.773-3.812L352 176h32z\"]\n};\nvar faReceipt = {\n prefix: 'fas',\n iconName: 'receipt',\n icon: [384, 512, [], \"f543\", \"M358.4 3.2L320 48 265.6 3.2a15.9 15.9 0 0 0-19.2 0L192 48 137.6 3.2a15.9 15.9 0 0 0-19.2 0L64 48 25.6 3.2C15-4.7 0 2.8 0 16v480c0 13.2 15 20.7 25.6 12.8L64 464l54.4 44.8a15.9 15.9 0 0 0 19.2 0L192 464l54.4 44.8a15.9 15.9 0 0 0 19.2 0L320 464l38.4 44.8c10.5 7.9 25.6.4 25.6-12.8V16c0-13.2-15-20.7-25.6-12.8zM320 360c0 4.4-3.6 8-8 8H72c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h240c4.4 0 8 3.6 8 8v16zm0-96c0 4.4-3.6 8-8 8H72c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h240c4.4 0 8 3.6 8 8v16zm0-96c0 4.4-3.6 8-8 8H72c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h240c4.4 0 8 3.6 8 8v16z\"]\n};\nvar faRecycle = {\n prefix: 'fas',\n iconName: 'recycle',\n icon: [512, 512, [], \"f1b8\", \"M184.561 261.903c3.232 13.997-12.123 24.635-24.068 17.168l-40.736-25.455-50.867 81.402C55.606 356.273 70.96 384 96.012 384H148c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12H96.115c-75.334 0-121.302-83.048-81.408-146.88l50.822-81.388-40.725-25.448c-12.081-7.547-8.966-25.961 4.879-29.158l110.237-25.45c8.611-1.988 17.201 3.381 19.189 11.99l25.452 110.237zm98.561-182.915l41.289 66.076-40.74 25.457c-12.051 7.528-9 25.953 4.879 29.158l110.237 25.45c8.672 1.999 17.215-3.438 19.189-11.99l25.45-110.237c3.197-13.844-11.99-24.719-24.068-17.168l-40.687 25.424-41.263-66.082c-37.521-60.033-125.209-60.171-162.816 0l-17.963 28.766c-3.51 5.62-1.8 13.021 3.82 16.533l33.919 21.195c5.62 3.512 13.024 1.803 16.536-3.817l17.961-28.743c12.712-20.341 41.973-19.676 54.257-.022zM497.288 301.12l-27.515-44.065c-3.511-5.623-10.916-7.334-16.538-3.821l-33.861 21.159c-5.62 3.512-7.33 10.915-3.818 16.536l27.564 44.112c13.257 21.211-2.057 48.96-27.136 48.96H320V336.02c0-14.213-17.242-21.383-27.313-11.313l-80 79.981c-6.249 6.248-6.249 16.379 0 22.627l80 79.989C302.689 517.308 320 510.3 320 495.989V448h95.88c75.274 0 121.335-82.997 81.408-146.88z\"]\n};\nvar faRedo = {\n prefix: 'fas',\n iconName: 'redo',\n icon: [512, 512, [], \"f01e\", \"M500.333 0h-47.411c-6.853 0-12.314 5.729-11.986 12.574l3.966 82.759C399.416 41.899 331.672 8 256.001 8 119.34 8 7.899 119.526 8 256.187 8.101 393.068 119.096 504 256 504c63.926 0 122.202-24.187 166.178-63.908 5.113-4.618 5.354-12.561.482-17.433l-33.971-33.971c-4.466-4.466-11.64-4.717-16.38-.543C341.308 415.448 300.606 432 256 432c-97.267 0-176-78.716-176-176 0-97.267 78.716-176 176-176 60.892 0 114.506 30.858 146.099 77.8l-101.525-4.865c-6.845-.328-12.574 5.133-12.574 11.986v47.411c0 6.627 5.373 12 12 12h200.333c6.627 0 12-5.373 12-12V12c0-6.627-5.373-12-12-12z\"]\n};\nvar faRedoAlt = {\n prefix: 'fas',\n iconName: 'redo-alt',\n icon: [512, 512, [], \"f2f9\", \"M256.455 8c66.269.119 126.437 26.233 170.859 68.685l35.715-35.715C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.75c-30.864-28.899-70.801-44.907-113.23-45.273-92.398-.798-170.283 73.977-169.484 169.442C88.764 348.009 162.184 424 256 424c41.127 0 79.997-14.678 110.629-41.556 4.743-4.161 11.906-3.908 16.368.553l39.662 39.662c4.872 4.872 4.631 12.815-.482 17.433C378.202 479.813 319.926 504 256 504 119.034 504 8.001 392.967 8 256.002 7.999 119.193 119.646 7.755 256.455 8z\"]\n};\nvar faRegistered = {\n prefix: 'fas',\n iconName: 'registered',\n icon: [512, 512, [], \"f25d\", \"M285.363 207.475c0 18.6-9.831 28.431-28.431 28.431h-29.876v-56.14h23.378c28.668 0 34.929 8.773 34.929 27.709zM504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM363.411 360.414c-46.729-84.825-43.299-78.636-44.702-80.98 23.432-15.172 37.945-42.979 37.945-74.486 0-54.244-31.5-89.252-105.498-89.252h-70.667c-13.255 0-24 10.745-24 24V372c0 13.255 10.745 24 24 24h22.567c13.255 0 24-10.745 24-24v-71.663h25.556l44.129 82.937a24.001 24.001 0 0 0 21.188 12.727h24.464c18.261-.001 29.829-19.591 21.018-35.587z\"]\n};\nvar faReply = {\n prefix: 'fas',\n iconName: 'reply',\n icon: [512, 512, [], \"f3e5\", \"M8.309 189.836L184.313 37.851C199.719 24.546 224 35.347 224 56.015v80.053c160.629 1.839 288 34.032 288 186.258 0 61.441-39.581 122.309-83.333 154.132-13.653 9.931-33.111-2.533-28.077-18.631 45.344-145.012-21.507-183.51-176.59-185.742V360c0 20.7-24.3 31.453-39.687 18.164l-176.004-152c-11.071-9.562-11.086-26.753 0-36.328z\"]\n};\nvar faReplyAll = {\n prefix: 'fas',\n iconName: 'reply-all',\n icon: [576, 512, [], \"f122\", \"M136.309 189.836L312.313 37.851C327.72 24.546 352 35.348 352 56.015v82.763c129.182 10.231 224 52.212 224 183.548 0 61.441-39.582 122.309-83.333 154.132-13.653 9.931-33.111-2.533-28.077-18.631 38.512-123.162-3.922-169.482-112.59-182.015v84.175c0 20.701-24.3 31.453-39.687 18.164L136.309 226.164c-11.071-9.561-11.086-26.753 0-36.328zm-128 36.328L184.313 378.15C199.7 391.439 224 380.687 224 359.986v-15.818l-108.606-93.785A55.96 55.96 0 0 1 96 207.998a55.953 55.953 0 0 1 19.393-42.38L224 71.832V56.015c0-20.667-24.28-31.469-39.687-18.164L8.309 189.836c-11.086 9.575-11.071 26.767 0 36.328z\"]\n};\nvar faRepublican = {\n prefix: 'fas',\n iconName: 'republican',\n icon: [640, 512, [], \"f75e\", \"M544 192c0-88.4-71.6-160-160-160H160C71.6 32 0 103.6 0 192v64h544v-64zm-367.7-21.6l-19.8 19.3 4.7 27.3c.8 4.9-4.3 8.6-8.7 6.3L128 210.4l-24.5 12.9c-4.3 2.3-9.5-1.4-8.7-6.3l4.7-27.3-19.8-19.3c-3.6-3.5-1.6-9.5 3.3-10.2l27.4-4 12.2-24.8c2.2-4.5 8.6-4.4 10.7 0l12.2 24.8 27.4 4c5 .7 6.9 6.7 3.4 10.2zm144 0l-19.8 19.3 4.7 27.3c.8 4.9-4.3 8.6-8.7 6.3L272 210.4l-24.5 12.9c-4.3 2.3-9.5-1.4-8.7-6.3l4.7-27.3-19.8-19.3c-3.6-3.5-1.6-9.5 3.3-10.2l27.4-4 12.2-24.8c2.2-4.5 8.6-4.4 10.7 0l12.2 24.8 27.4 4c5 .7 6.9 6.7 3.4 10.2zm144 0l-19.8 19.3 4.7 27.3c.8 4.9-4.3 8.6-8.7 6.3L416 210.4l-24.5 12.9c-4.3 2.3-9.5-1.4-8.7-6.3l4.7-27.3-19.8-19.3c-3.6-3.5-1.6-9.5 3.3-10.2l27.4-4 12.2-24.8c2.2-4.5 8.6-4.4 10.7 0l12.2 24.8 27.4 4c5 .7 6.9 6.7 3.4 10.2zM624 320h-32c-8.8 0-16 7.2-16 16v64c0 8.8-7.2 16-16 16s-16-7.2-16-16V288H0v176c0 8.8 7.2 16 16 16h96c8.8 0 16-7.2 16-16v-80h192v80c0 8.8 7.2 16 16 16h96c8.8 0 16-7.2 16-16V352h32v43.3c0 41.8 30 80.1 71.6 84.3 47.8 4.9 88.4-32.7 88.4-79.6v-64c0-8.8-7.2-16-16-16z\"]\n};\nvar faRestroom = {\n prefix: 'fas',\n iconName: 'restroom',\n icon: [640, 512, [], \"f7bd\", \"M128 128c35.3 0 64-28.7 64-64S163.3 0 128 0 64 28.7 64 64s28.7 64 64 64zm384 0c35.3 0 64-28.7 64-64S547.3 0 512 0s-64 28.7-64 64 28.7 64 64 64zm127.3 226.5l-45.6-185.8c-3.3-13.5-15.5-23-29.8-24.2-15 9.7-32.8 15.5-52 15.5-19.2 0-37-5.8-52-15.5-14.3 1.2-26.5 10.7-29.8 24.2l-45.6 185.8C381 369.6 393 384 409.2 384H464v104c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24V384h54.8c16.2 0 28.2-14.4 24.5-29.5zM336 0h-32c-8.8 0-16 7.2-16 16v480c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V16c0-8.8-7.2-16-16-16zM180.1 144.4c-15 9.8-32.9 15.6-52.1 15.6-19.2 0-37.1-5.8-52.1-15.6C51.3 146.5 32 166.9 32 192v136c0 13.3 10.7 24 24 24h8v136c0 13.3 10.7 24 24 24h80c13.3 0 24-10.7 24-24V352h8c13.3 0 24-10.7 24-24V192c0-25.1-19.3-45.5-43.9-47.6z\"]\n};\nvar faRetweet = {\n prefix: 'fas',\n iconName: 'retweet',\n icon: [640, 512, [], \"f079\", \"M629.657 343.598L528.971 444.284c-9.373 9.372-24.568 9.372-33.941 0L394.343 343.598c-9.373-9.373-9.373-24.569 0-33.941l10.823-10.823c9.562-9.562 25.133-9.34 34.419.492L480 342.118V160H292.451a24.005 24.005 0 0 1-16.971-7.029l-16-16C244.361 121.851 255.069 96 276.451 96H520c13.255 0 24 10.745 24 24v222.118l40.416-42.792c9.285-9.831 24.856-10.054 34.419-.492l10.823 10.823c9.372 9.372 9.372 24.569-.001 33.941zm-265.138 15.431A23.999 23.999 0 0 0 347.548 352H160V169.881l40.416 42.792c9.286 9.831 24.856 10.054 34.419.491l10.822-10.822c9.373-9.373 9.373-24.569 0-33.941L144.971 67.716c-9.373-9.373-24.569-9.373-33.941 0L10.343 168.402c-9.373 9.373-9.373 24.569 0 33.941l10.822 10.822c9.562 9.562 25.133 9.34 34.419-.491L96 169.881V392c0 13.255 10.745 24 24 24h243.549c21.382 0 32.09-25.851 16.971-40.971l-16.001-16z\"]\n};\nvar faRibbon = {\n prefix: 'fas',\n iconName: 'ribbon',\n icon: [448, 512, [], \"f4d6\", \"M6.1 444.3c-9.6 10.8-7.5 27.6 4.5 35.7l68.8 27.9c9.9 6.7 23.3 5 31.3-3.8l91.8-101.9-79.2-87.9-117.2 130zm435.8 0s-292-324.6-295.4-330.1c15.4-8.4 40.2-17.9 77.5-17.9s62.1 9.5 77.5 17.9c-3.3 5.6-56 64.6-56 64.6l79.1 87.7 34.2-38c28.7-31.9 33.3-78.6 11.4-115.5l-43.7-73.5c-4.3-7.2-9.9-13.3-16.8-18-40.7-27.6-127.4-29.7-171.4 0-6.9 4.7-12.5 10.8-16.8 18l-43.6 73.2c-1.5 2.5-37.1 62.2 11.5 116L337.5 504c8 8.9 21.4 10.5 31.3 3.8l68.8-27.9c11.9-8 14-24.8 4.3-35.6z\"]\n};\nvar faRing = {\n prefix: 'fas',\n iconName: 'ring',\n icon: [512, 512, [], \"f70b\", \"M256 64C110.06 64 0 125.91 0 208v98.13C0 384.48 114.62 448 256 448s256-63.52 256-141.87V208c0-82.09-110.06-144-256-144zm0 64c106.04 0 192 35.82 192 80 0 9.26-3.97 18.12-10.91 26.39C392.15 208.21 328.23 192 256 192s-136.15 16.21-181.09 42.39C67.97 226.12 64 217.26 64 208c0-44.18 85.96-80 192-80zM120.43 264.64C155.04 249.93 201.64 240 256 240s100.96 9.93 135.57 24.64C356.84 279.07 308.93 288 256 288s-100.84-8.93-135.57-23.36z\"]\n};\nvar faRoad = {\n prefix: 'fas',\n iconName: 'road',\n icon: [576, 512, [], \"f018\", \"M573.19 402.67l-139.79-320C428.43 71.29 417.6 64 405.68 64h-97.59l2.45 23.16c.5 4.72-3.21 8.84-7.96 8.84h-29.16c-4.75 0-8.46-4.12-7.96-8.84L267.91 64h-97.59c-11.93 0-22.76 7.29-27.73 18.67L2.8 402.67C-6.45 423.86 8.31 448 30.54 448h196.84l10.31-97.68c.86-8.14 7.72-14.32 15.91-14.32h68.8c8.19 0 15.05 6.18 15.91 14.32L348.62 448h196.84c22.23 0 36.99-24.14 27.73-45.33zM260.4 135.16a8 8 0 0 1 7.96-7.16h39.29c4.09 0 7.53 3.09 7.96 7.16l4.6 43.58c.75 7.09-4.81 13.26-11.93 13.26h-40.54c-7.13 0-12.68-6.17-11.93-13.26l4.59-43.58zM315.64 304h-55.29c-9.5 0-16.91-8.23-15.91-17.68l5.07-48c.86-8.14 7.72-14.32 15.91-14.32h45.15c8.19 0 15.05 6.18 15.91 14.32l5.07 48c1 9.45-6.41 17.68-15.91 17.68z\"]\n};\nvar faRobot = {\n prefix: 'fas',\n iconName: 'robot',\n icon: [640, 512, [], \"f544\", \"M0 256v128c0 17.7 14.3 32 32 32h32V224H32c-17.7 0-32 14.3-32 32zM464 96H352V32c0-17.7-14.3-32-32-32s-32 14.3-32 32v64H176c-44.2 0-80 35.8-80 80v272c0 35.3 28.7 64 64 64h320c35.3 0 64-28.7 64-64V176c0-44.2-35.8-80-80-80zM256 416h-64v-32h64v32zm-32-120c-22.1 0-40-17.9-40-40s17.9-40 40-40 40 17.9 40 40-17.9 40-40 40zm128 120h-64v-32h64v32zm96 0h-64v-32h64v32zm-32-120c-22.1 0-40-17.9-40-40s17.9-40 40-40 40 17.9 40 40-17.9 40-40 40zm192-72h-32v192h32c17.7 0 32-14.3 32-32V256c0-17.7-14.3-32-32-32z\"]\n};\nvar faRocket = {\n prefix: 'fas',\n iconName: 'rocket',\n icon: [512, 512, [], \"f135\", \"M505.05 19.1a15.89 15.89 0 0 0-12.2-12.2C460.65 0 435.46 0 410.36 0c-103.2 0-165.1 55.2-211.29 128H94.87A48 48 0 0 0 52 154.49l-49.42 98.8A24 24 0 0 0 24.07 288h103.77l-22.47 22.47a32 32 0 0 0 0 45.25l50.9 50.91a32 32 0 0 0 45.26 0L224 384.16V488a24 24 0 0 0 34.7 21.49l98.7-49.39a47.91 47.91 0 0 0 26.5-42.9V312.79c72.59-46.3 128-108.4 128-211.09.1-25.2.1-50.4-6.85-82.6zM384 168a40 40 0 1 1 40-40 40 40 0 0 1-40 40z\"]\n};\nvar faRoute = {\n prefix: 'fas',\n iconName: 'route',\n icon: [512, 512, [], \"f4d7\", \"M416 320h-96c-17.6 0-32-14.4-32-32s14.4-32 32-32h96s96-107 96-160-43-96-96-96-96 43-96 96c0 25.5 22.2 63.4 45.3 96H320c-52.9 0-96 43.1-96 96s43.1 96 96 96h96c17.6 0 32 14.4 32 32s-14.4 32-32 32H185.5c-16 24.8-33.8 47.7-47.3 64H416c52.9 0 96-43.1 96-96s-43.1-96-96-96zm0-256c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zM96 256c-53 0-96 43-96 96s96 160 96 160 96-107 96-160-43-96-96-96zm0 128c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faRss = {\n prefix: 'fas',\n iconName: 'rss',\n icon: [448, 512, [], \"f09e\", \"M128.081 415.959c0 35.369-28.672 64.041-64.041 64.041S0 451.328 0 415.959s28.672-64.041 64.041-64.041 64.04 28.673 64.04 64.041zm175.66 47.25c-8.354-154.6-132.185-278.587-286.95-286.95C7.656 175.765 0 183.105 0 192.253v48.069c0 8.415 6.49 15.472 14.887 16.018 111.832 7.284 201.473 96.702 208.772 208.772.547 8.397 7.604 14.887 16.018 14.887h48.069c9.149.001 16.489-7.655 15.995-16.79zm144.249.288C439.596 229.677 251.465 40.445 16.503 32.01 7.473 31.686 0 38.981 0 48.016v48.068c0 8.625 6.835 15.645 15.453 15.999 191.179 7.839 344.627 161.316 352.465 352.465.353 8.618 7.373 15.453 15.999 15.453h48.068c9.034-.001 16.329-7.474 16.005-16.504z\"]\n};\nvar faRssSquare = {\n prefix: 'fas',\n iconName: 'rss-square',\n icon: [448, 512, [], \"f143\", \"M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM112 416c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm157.533 0h-34.335c-6.011 0-11.051-4.636-11.442-10.634-5.214-80.05-69.243-143.92-149.123-149.123-5.997-.39-10.633-5.431-10.633-11.441v-34.335c0-6.535 5.468-11.777 11.994-11.425 110.546 5.974 198.997 94.536 204.964 204.964.352 6.526-4.89 11.994-11.425 11.994zm103.027 0h-34.334c-6.161 0-11.175-4.882-11.427-11.038-5.598-136.535-115.204-246.161-251.76-251.76C68.882 152.949 64 147.935 64 141.774V107.44c0-6.454 5.338-11.664 11.787-11.432 167.83 6.025 302.21 141.191 308.205 308.205.232 6.449-4.978 11.787-11.432 11.787z\"]\n};\nvar faRubleSign = {\n prefix: 'fas',\n iconName: 'ruble-sign',\n icon: [384, 512, [], \"f158\", \"M239.36 320C324.48 320 384 260.542 384 175.071S324.48 32 239.36 32H76c-6.627 0-12 5.373-12 12v206.632H12c-6.627 0-12 5.373-12 12V308c0 6.627 5.373 12 12 12h52v32H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h52v52c0 6.627 5.373 12 12 12h58.56c6.627 0 12-5.373 12-12v-52H308c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12H146.56v-32h92.8zm-92.8-219.252h78.72c46.72 0 74.88 29.11 74.88 74.323 0 45.832-28.16 75.561-76.16 75.561h-77.44V100.748z\"]\n};\nvar faRuler = {\n prefix: 'fas',\n iconName: 'ruler',\n icon: [640, 512, [], \"f545\", \"M635.7 167.2L556.1 31.7c-8.8-15-28.3-20.1-43.5-11.5l-69 39.1L503.3 161c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L416 75l-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L333.2 122 278 153.3 337.8 255c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-59.7-101.7-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-27.9-47.5-55.2 31.3 59.7 101.7c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L84.9 262.9l-69 39.1C.7 310.7-4.6 329.8 4.2 344.8l79.6 135.6c8.8 15 28.3 20.1 43.5 11.5L624.1 210c15.2-8.6 20.4-27.8 11.6-42.8z\"]\n};\nvar faRulerCombined = {\n prefix: 'fas',\n iconName: 'ruler-combined',\n icon: [512, 512, [], \"f546\", \"M160 288h-56c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h56v-64h-56c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h56V96h-56c-4.42 0-8-3.58-8-8V72c0-4.42 3.58-8 8-8h56V32c0-17.67-14.33-32-32-32H32C14.33 0 0 14.33 0 32v448c0 2.77.91 5.24 1.57 7.8L160 329.38V288zm320 64h-32v56c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-56h-64v56c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-56h-64v56c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-56h-41.37L24.2 510.43c2.56.66 5.04 1.57 7.8 1.57h448c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32z\"]\n};\nvar faRulerHorizontal = {\n prefix: 'fas',\n iconName: 'ruler-horizontal',\n icon: [576, 512, [], \"f547\", \"M544 128h-48v88c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-88h-64v88c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-88h-64v88c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-88h-64v88c0 4.42-3.58 8-8 8h-16c-4.42 0-8-3.58-8-8v-88h-64v88c0 4.42-3.58 8-8 8H88c-4.42 0-8-3.58-8-8v-88H32c-17.67 0-32 14.33-32 32v192c0 17.67 14.33 32 32 32h512c17.67 0 32-14.33 32-32V160c0-17.67-14.33-32-32-32z\"]\n};\nvar faRulerVertical = {\n prefix: 'fas',\n iconName: 'ruler-vertical',\n icon: [256, 512, [], \"f548\", \"M168 416c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h88v-64h-88c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h88v-64h-88c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h88v-64h-88c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h88V32c0-17.67-14.33-32-32-32H32C14.33 0 0 14.33 0 32v448c0 17.67 14.33 32 32 32h192c17.67 0 32-14.33 32-32v-64h-88z\"]\n};\nvar faRunning = {\n prefix: 'fas',\n iconName: 'running',\n icon: [416, 512, [], \"f70c\", \"M272 96c26.51 0 48-21.49 48-48S298.51 0 272 0s-48 21.49-48 48 21.49 48 48 48zM113.69 317.47l-14.8 34.52H32c-17.67 0-32 14.33-32 32s14.33 32 32 32h77.45c19.25 0 36.58-11.44 44.11-29.09l8.79-20.52-10.67-6.3c-17.32-10.23-30.06-25.37-37.99-42.61zM384 223.99h-44.03l-26.06-53.25c-12.5-25.55-35.45-44.23-61.78-50.94l-71.08-21.14c-28.3-6.8-57.77-.55-80.84 17.14l-39.67 30.41c-14.03 10.75-16.69 30.83-5.92 44.86s30.84 16.66 44.86 5.92l39.69-30.41c7.67-5.89 17.44-8 25.27-6.14l14.7 4.37-37.46 87.39c-12.62 29.48-1.31 64.01 26.3 80.31l84.98 50.17-27.47 87.73c-5.28 16.86 4.11 34.81 20.97 40.09 3.19 1 6.41 1.48 9.58 1.48 13.61 0 26.23-8.77 30.52-22.45l31.64-101.06c5.91-20.77-2.89-43.08-21.64-54.39l-61.24-36.14 31.31-78.28 20.27 41.43c8 16.34 24.92 26.89 43.11 26.89H384c17.67 0 32-14.33 32-32s-14.33-31.99-32-31.99z\"]\n};\nvar faRupeeSign = {\n prefix: 'fas',\n iconName: 'rupee-sign',\n icon: [320, 512, [], \"f156\", \"M308 96c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v44.748c0 6.627 5.373 12 12 12h85.28c27.308 0 48.261 9.958 60.97 27.252H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h158.757c-6.217 36.086-32.961 58.632-74.757 58.632H12c-6.627 0-12 5.373-12 12v53.012c0 3.349 1.4 6.546 3.861 8.818l165.052 152.356a12.001 12.001 0 0 0 8.139 3.182h82.562c10.924 0 16.166-13.408 8.139-20.818L116.871 319.906c76.499-2.34 131.144-53.395 138.318-127.906H308c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-58.69c-3.486-11.541-8.28-22.246-14.252-32H308z\"]\n};\nvar faSadCry = {\n prefix: 'fas',\n iconName: 'sad-cry',\n icon: [496, 512, [], \"f5b3\", \"M248 8C111 8 0 119 0 256c0 90.1 48.2 168.7 120 212.1V288c0-8.8 7.2-16 16-16s16 7.2 16 16v196.7c29.5 12.4 62 19.3 96 19.3s66.5-6.9 96-19.3V288c0-8.8 7.2-16 16-16s16 7.2 16 16v180.1C447.8 424.7 496 346 496 256 496 119 385 8 248 8zm-65.5 216.5c-14.8-13.2-46.2-13.2-61 0L112 233c-3.8 3.3-9.3 4-13.7 1.6-4.4-2.4-6.9-7.4-6.1-12.4 4-25.2 34.2-42.1 59.9-42.1S208 197 212 222.2c.8 5-1.7 10-6.1 12.4-5.8 3.1-11.2.7-13.7-1.6l-9.7-8.5zM248 416c-26.5 0-48-28.7-48-64s21.5-64 48-64 48 28.7 48 64-21.5 64-48 64zm149.8-181.5c-5.8 3.1-11.2.7-13.7-1.6l-9.5-8.5c-14.8-13.2-46.2-13.2-61 0L304 233c-3.8 3.3-9.3 4-13.7 1.6-4.4-2.4-6.9-7.4-6.1-12.4 4-25.2 34.2-42.1 59.9-42.1S400 197 404 222.2c.6 4.9-1.8 9.9-6.2 12.3z\"]\n};\nvar faSadTear = {\n prefix: 'fas',\n iconName: 'sad-tear',\n icon: [496, 512, [], \"f5b4\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zM152 416c-26.5 0-48-21-48-47 0-20 28.5-60.4 41.6-77.8 3.2-4.3 9.6-4.3 12.8 0C171.5 308.6 200 349 200 369c0 26-21.5 47-48 47zm16-176c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm170.2 154.2C315.8 367.4 282.9 352 248 352c-21.2 0-21.2-32 0-32 44.4 0 86.3 19.6 114.7 53.8 13.8 16.4-11.2 36.5-24.5 20.4z\"]\n};\nvar faSatellite = {\n prefix: 'fas',\n iconName: 'satellite',\n icon: [512, 512, [], \"f7bf\", \"M502.7 265l-80.3-80.4 47.8-47.9c13.1-13.1 13.1-34.4 0-47.5l-47.5-47.5c-13.1-13.1-34.4-13.1-47.5 0l-47.8 47.9-80.3-80.3C240.8 3.1 232.7 0 224.5 0S208.2 3.1 202 9.3L105.3 106c-12.4 12.4-12.4 32.6 0 45.1l80.3 80.4-9.8 9.8C122.1 217 59.6 218.6 7.3 246.7c-8.5 4.6-9.6 16.4-2.8 23.2L112 377.4l-17.8 17.8c-2.6-.7-5-1.6-7.8-1.6-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32c0-2.8-.9-5.2-1.6-7.8l17.8-17.8 107.5 107.5c6.8 6.8 18.7 5.7 23.2-2.8 28.1-52.3 29.7-114.8 5.4-168.5l9.9-9.9 80.3 80.4c6.2 6.2 14.4 9.3 22.5 9.3s16.3-3.1 22.5-9.3l96.7-96.7c12.5-12.4 12.5-32.6.1-45zm-352-136.5l73.8-73.8 68.9 68.9-73.8 73.8-68.9-68.9zm232.8 232.8l-68.9-68.9 73.8-73.8 68.9 68.9-73.8 73.8z\"]\n};\nvar faSatelliteDish = {\n prefix: 'fas',\n iconName: 'satellite-dish',\n icon: [512, 512, [], \"f7c0\", \"M188.8 345.9l27.4-27.4c2.6.7 5 1.6 7.8 1.6 17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32c0 2.8.9 5.2 1.6 7.8l-27.4 27.4L49.4 206.5c-7.3-7.3-20.1-6.1-25 3-41.8 77.8-29.9 176.7 35.7 242.3 65.6 65.6 164.6 77.5 242.3 35.7 9.2-4.9 10.4-17.7 3-25L188.8 345.9zM209 0c-9.2-.5-17 6.8-17 16v31.6c0 8.5 6.6 15.5 15 15.9 129.4 7 233.4 112 240.9 241.5.5 8.4 7.5 15 15.9 15h32.1c9.2 0 16.5-7.8 16-17C503.4 139.8 372.2 8.6 209 0zm.3 96c-9.3-.7-17.3 6.7-17.3 16.1v32.1c0 8.4 6.5 15.3 14.8 15.9 76.8 6.3 138 68.2 144.9 145.2.8 8.3 7.6 14.7 15.9 14.7h32.2c9.3 0 16.8-8 16.1-17.3-8.4-110.1-96.5-198.2-206.6-206.7z\"]\n};\nvar faSave = {\n prefix: 'fas',\n iconName: 'save',\n icon: [448, 512, [], \"f0c7\", \"M433.941 129.941l-83.882-83.882A48 48 0 0 0 316.118 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V163.882a48 48 0 0 0-14.059-33.941zM224 416c-35.346 0-64-28.654-64-64 0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64zm96-304.52V212c0 6.627-5.373 12-12 12H76c-6.627 0-12-5.373-12-12V108c0-6.627 5.373-12 12-12h228.52c3.183 0 6.235 1.264 8.485 3.515l3.48 3.48A11.996 11.996 0 0 1 320 111.48z\"]\n};\nvar faSchool = {\n prefix: 'fas',\n iconName: 'school',\n icon: [640, 512, [], \"f549\", \"M0 224v272c0 8.84 7.16 16 16 16h80V192H32c-17.67 0-32 14.33-32 32zm360-48h-24v-40c0-4.42-3.58-8-8-8h-16c-4.42 0-8 3.58-8 8v64c0 4.42 3.58 8 8 8h48c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8zm137.75-63.96l-160-106.67a32.02 32.02 0 0 0-35.5 0l-160 106.67A32.002 32.002 0 0 0 128 138.66V512h128V368c0-8.84 7.16-16 16-16h96c8.84 0 16 7.16 16 16v144h128V138.67c0-10.7-5.35-20.7-14.25-26.63zM320 256c-44.18 0-80-35.82-80-80s35.82-80 80-80 80 35.82 80 80-35.82 80-80 80zm288-64h-64v320h80c8.84 0 16-7.16 16-16V224c0-17.67-14.33-32-32-32z\"]\n};\nvar faScrewdriver = {\n prefix: 'fas',\n iconName: 'screwdriver',\n icon: [512, 512, [], \"f54a\", \"M448 0L320 96v62.06l-83.03 83.03c6.79 4.25 13.27 9.06 19.07 14.87 5.8 5.8 10.62 12.28 14.87 19.07L353.94 192H416l96-128-64-64zM128 278.59L10.92 395.67c-14.55 14.55-14.55 38.15 0 52.71l52.7 52.7c14.56 14.56 38.15 14.56 52.71 0L233.41 384c29.11-29.11 29.11-76.3 0-105.41s-76.3-29.11-105.41 0z\"]\n};\nvar faScroll = {\n prefix: 'fas',\n iconName: 'scroll',\n icon: [640, 512, [], \"f70e\", \"M48 0C21.53 0 0 21.53 0 48v64c0 8.84 7.16 16 16 16h80V48C96 21.53 74.47 0 48 0zm208 412.57V352h288V96c0-52.94-43.06-96-96-96H111.59C121.74 13.41 128 29.92 128 48v368c0 38.87 34.65 69.65 74.75 63.12C234.22 474 256 444.46 256 412.57zM288 384v32c0 52.93-43.06 96-96 96h336c61.86 0 112-50.14 112-112 0-8.84-7.16-16-16-16H288z\"]\n};\nvar faSdCard = {\n prefix: 'fas',\n iconName: 'sd-card',\n icon: [384, 512, [], \"f7c2\", \"M320 0H128L0 128v320c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zM160 160h-48V64h48v96zm80 0h-48V64h48v96zm80 0h-48V64h48v96z\"]\n};\nvar faSearch = {\n prefix: 'fas',\n iconName: 'search',\n icon: [512, 512, [], \"f002\", \"M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z\"]\n};\nvar faSearchDollar = {\n prefix: 'fas',\n iconName: 'search-dollar',\n icon: [512, 512, [], \"f688\", \"M505.04 442.66l-99.71-99.69c-4.5-4.5-10.6-7-17-7h-16.3c27.6-35.3 44-79.69 44-127.99C416.03 93.09 322.92 0 208.02 0S0 93.09 0 207.98s93.11 207.98 208.02 207.98c48.3 0 92.71-16.4 128.01-44v16.3c0 6.4 2.5 12.5 7 17l99.71 99.69c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.59.1-33.99zm-297.02-90.7c-79.54 0-144-64.34-144-143.98 0-79.53 64.35-143.98 144-143.98 79.54 0 144 64.34 144 143.98 0 79.53-64.35 143.98-144 143.98zm27.11-152.54l-45.01-13.5c-5.16-1.55-8.77-6.78-8.77-12.73 0-7.27 5.3-13.19 11.8-13.19h28.11c4.56 0 8.96 1.29 12.82 3.72 3.24 2.03 7.36 1.91 10.13-.73l11.75-11.21c3.53-3.37 3.33-9.21-.57-12.14-9.1-6.83-20.08-10.77-31.37-11.35V112c0-4.42-3.58-8-8-8h-16c-4.42 0-8 3.58-8 8v16.12c-23.63.63-42.68 20.55-42.68 45.07 0 19.97 12.99 37.81 31.58 43.39l45.01 13.5c5.16 1.55 8.77 6.78 8.77 12.73 0 7.27-5.3 13.19-11.8 13.19h-28.1c-4.56 0-8.96-1.29-12.82-3.72-3.24-2.03-7.36-1.91-10.13.73l-11.75 11.21c-3.53 3.37-3.33 9.21.57 12.14 9.1 6.83 20.08 10.77 31.37 11.35V304c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8v-16.12c23.63-.63 42.68-20.54 42.68-45.07 0-19.97-12.99-37.81-31.59-43.39z\"]\n};\nvar faSearchLocation = {\n prefix: 'fas',\n iconName: 'search-location',\n icon: [512, 512, [], \"f689\", \"M505.04 442.66l-99.71-99.69c-4.5-4.5-10.6-7-17-7h-16.3c27.6-35.3 44-79.69 44-127.99C416.03 93.09 322.92 0 208.02 0S0 93.09 0 207.98s93.11 207.98 208.02 207.98c48.3 0 92.71-16.4 128.01-44v16.3c0 6.4 2.5 12.5 7 17l99.71 99.69c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.59.1-33.99zm-297.02-90.7c-79.54 0-144-64.34-144-143.98 0-79.53 64.35-143.98 144-143.98 79.54 0 144 64.34 144 143.98 0 79.53-64.35 143.98-144 143.98zm.02-239.96c-40.78 0-73.84 33.05-73.84 73.83 0 32.96 48.26 93.05 66.75 114.86a9.24 9.24 0 0 0 14.18 0c18.49-21.81 66.75-81.89 66.75-114.86 0-40.78-33.06-73.83-73.84-73.83zm0 96c-13.26 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24z\"]\n};\nvar faSearchMinus = {\n prefix: 'fas',\n iconName: 'search-minus',\n icon: [512, 512, [], \"f010\", \"M304 192v32c0 6.6-5.4 12-12 12H124c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm201 284.7L476.7 505c-9.4 9.4-24.6 9.4-33.9 0L343 405.3c-4.5-4.5-7-10.6-7-17V372c-35.3 27.6-79.7 44-128 44C93.1 416 0 322.9 0 208S93.1 0 208 0s208 93.1 208 208c0 48.3-16.4 92.7-44 128h16.3c6.4 0 12.5 2.5 17 7l99.7 99.7c9.3 9.4 9.3 24.6 0 34zM344 208c0-75.2-60.8-136-136-136S72 132.8 72 208s60.8 136 136 136 136-60.8 136-136z\"]\n};\nvar faSearchPlus = {\n prefix: 'fas',\n iconName: 'search-plus',\n icon: [512, 512, [], \"f00e\", \"M304 192v32c0 6.6-5.4 12-12 12h-56v56c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-56h-56c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h56v-56c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v56h56c6.6 0 12 5.4 12 12zm201 284.7L476.7 505c-9.4 9.4-24.6 9.4-33.9 0L343 405.3c-4.5-4.5-7-10.6-7-17V372c-35.3 27.6-79.7 44-128 44C93.1 416 0 322.9 0 208S93.1 0 208 0s208 93.1 208 208c0 48.3-16.4 92.7-44 128h16.3c6.4 0 12.5 2.5 17 7l99.7 99.7c9.3 9.4 9.3 24.6 0 34zM344 208c0-75.2-60.8-136-136-136S72 132.8 72 208s60.8 136 136 136 136-60.8 136-136z\"]\n};\nvar faSeedling = {\n prefix: 'fas',\n iconName: 'seedling',\n icon: [512, 512, [], \"f4d8\", \"M64 96H0c0 123.7 100.3 224 224 224v144c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V320C288 196.3 187.7 96 64 96zm384-64c-84.2 0-157.4 46.5-195.7 115.2 27.7 30.2 48.2 66.9 59 107.6C424 243.1 512 147.9 512 32h-64z\"]\n};\nvar faServer = {\n prefix: 'fas',\n iconName: 'server',\n icon: [512, 512, [], \"f233\", \"M480 160H32c-17.673 0-32-14.327-32-32V64c0-17.673 14.327-32 32-32h448c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32zm-48-88c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm-64 0c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm112 248H32c-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32h448c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32zm-48-88c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm-64 0c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm112 248H32c-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32h448c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32zm-48-88c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm-64 0c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24z\"]\n};\nvar faShapes = {\n prefix: 'fas',\n iconName: 'shapes',\n icon: [512, 512, [], \"f61f\", \"M512 320v160c0 17.67-14.33 32-32 32H320c-17.67 0-32-14.33-32-32V320c0-17.67 14.33-32 32-32h160c17.67 0 32 14.33 32 32zm-384-64C57.31 256 0 313.31 0 384s57.31 128 128 128 128-57.31 128-128-57.31-128-128-128zm351.03-32c25.34 0 41.18-26.67 28.51-48L412.51 16c-12.67-21.33-44.35-21.33-57.02 0l-95.03 160c-12.67 21.33 3.17 48 28.51 48h190.06z\"]\n};\nvar faShare = {\n prefix: 'fas',\n iconName: 'share',\n icon: [512, 512, [], \"f064\", \"M503.691 189.836L327.687 37.851C312.281 24.546 288 35.347 288 56.015v80.053C127.371 137.907 0 170.1 0 322.326c0 61.441 39.581 122.309 83.333 154.132 13.653 9.931 33.111-2.533 28.077-18.631C66.066 312.814 132.917 274.316 288 272.085V360c0 20.7 24.3 31.453 39.687 18.164l176.004-152c11.071-9.562 11.086-26.753 0-36.328z\"]\n};\nvar faShareAlt = {\n prefix: 'fas',\n iconName: 'share-alt',\n icon: [448, 512, [], \"f1e0\", \"M352 320c-22.608 0-43.387 7.819-59.79 20.895l-102.486-64.054a96.551 96.551 0 0 0 0-41.683l102.486-64.054C308.613 184.181 329.392 192 352 192c53.019 0 96-42.981 96-96S405.019 0 352 0s-96 42.981-96 96c0 7.158.79 14.13 2.276 20.841L155.79 180.895C139.387 167.819 118.608 160 96 160c-53.019 0-96 42.981-96 96s42.981 96 96 96c22.608 0 43.387-7.819 59.79-20.895l102.486 64.054A96.301 96.301 0 0 0 256 416c0 53.019 42.981 96 96 96s96-42.981 96-96-42.981-96-96-96z\"]\n};\nvar faShareAltSquare = {\n prefix: 'fas',\n iconName: 'share-alt-square',\n icon: [448, 512, [], \"f1e1\", \"M448 80v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48zM304 296c-14.562 0-27.823 5.561-37.783 14.671l-67.958-40.775a56.339 56.339 0 0 0 0-27.793l67.958-40.775C276.177 210.439 289.438 216 304 216c30.928 0 56-25.072 56-56s-25.072-56-56-56-56 25.072-56 56c0 4.797.605 9.453 1.74 13.897l-67.958 40.775C171.823 205.561 158.562 200 144 200c-30.928 0-56 25.072-56 56s25.072 56 56 56c14.562 0 27.823-5.561 37.783-14.671l67.958 40.775a56.088 56.088 0 0 0-1.74 13.897c0 30.928 25.072 56 56 56s56-25.072 56-56C360 321.072 334.928 296 304 296z\"]\n};\nvar faShareSquare = {\n prefix: 'fas',\n iconName: 'share-square',\n icon: [576, 512, [], \"f14d\", \"M568.482 177.448L424.479 313.433C409.3 327.768 384 317.14 384 295.985v-71.963c-144.575.97-205.566 35.113-164.775 171.353 4.483 14.973-12.846 26.567-25.006 17.33C155.252 383.105 120 326.488 120 269.339c0-143.937 117.599-172.5 264-173.312V24.012c0-21.174 25.317-31.768 40.479-17.448l144.003 135.988c10.02 9.463 10.028 25.425 0 34.896zM384 379.128V448H64V128h50.916a11.99 11.99 0 0 0 8.648-3.693c14.953-15.568 32.237-27.89 51.014-37.676C185.708 80.83 181.584 64 169.033 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48v-88.806c0-8.288-8.197-14.066-16.011-11.302a71.83 71.83 0 0 1-34.189 3.377c-7.27-1.046-13.8 4.514-13.8 11.859z\"]\n};\nvar faShekelSign = {\n prefix: 'fas',\n iconName: 'shekel-sign',\n icon: [448, 512, [], \"f20b\", \"M248 168v168c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16V168c0-75.11-60.89-136-136-136H24C10.75 32 0 42.74 0 56v408c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16V112h112c30.93 0 56 25.07 56 56zM432 32h-48c-8.84 0-16 7.16-16 16v296c0 30.93-25.07 56-56 56H200V176c0-8.84-7.16-16-16-16h-48c-8.84 0-16 7.16-16 16v280c0 13.25 10.75 24 24 24h168c75.11 0 136-60.89 136-136V48c0-8.84-7.16-16-16-16z\"]\n};\nvar faShieldAlt = {\n prefix: 'fas',\n iconName: 'shield-alt',\n icon: [512, 512, [], \"f3ed\", \"M466.5 83.7l-192-80a48.15 48.15 0 0 0-36.9 0l-192 80C27.7 91.1 16 108.6 16 128c0 198.5 114.5 335.7 221.5 380.3 11.8 4.9 25.1 4.9 36.9 0C360.1 472.6 496 349.3 496 128c0-19.4-11.7-36.9-29.5-44.3zM256.1 446.3l-.1-381 175.9 73.3c-3.3 151.4-82.1 261.1-175.8 307.7z\"]\n};\nvar faShip = {\n prefix: 'fas',\n iconName: 'ship',\n icon: [640, 512, [], \"f21a\", \"M496.616 372.639l70.012-70.012c16.899-16.9 9.942-45.771-12.836-53.092L512 236.102V96c0-17.673-14.327-32-32-32h-64V24c0-13.255-10.745-24-24-24H248c-13.255 0-24 10.745-24 24v40h-64c-17.673 0-32 14.327-32 32v140.102l-41.792 13.433c-22.753 7.313-29.754 36.173-12.836 53.092l70.012 70.012C125.828 416.287 85.587 448 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24 61.023 0 107.499-20.61 143.258-59.396C181.677 487.432 216.021 512 256 512h128c39.979 0 74.323-24.568 88.742-59.396C508.495 491.384 554.968 512 616 512c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24-60.817 0-101.542-31.001-119.384-75.361zM192 128h256v87.531l-118.208-37.995a31.995 31.995 0 0 0-19.584 0L192 215.531V128z\"]\n};\nvar faShippingFast = {\n prefix: 'fas',\n iconName: 'shipping-fast',\n icon: [640, 512, [], \"f48b\", \"M624 352h-16V243.9c0-12.7-5.1-24.9-14.1-33.9L494 110.1c-9-9-21.2-14.1-33.9-14.1H416V48c0-26.5-21.5-48-48-48H112C85.5 0 64 21.5 64 48v48H8c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8h272c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H40c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8h208c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H8c-4.4 0-8 3.6-8 8v16c0 4.4 3.6 8 8 8h208c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H64v128c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM160 464c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm320 0c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-208H416V144h44.1l99.9 99.9V256z\"]\n};\nvar faShoePrints = {\n prefix: 'fas',\n iconName: 'shoe-prints',\n icon: [640, 512, [], \"f54b\", \"M192 160h32V32h-32c-35.35 0-64 28.65-64 64s28.65 64 64 64zM0 416c0 35.35 28.65 64 64 64h32V352H64c-35.35 0-64 28.65-64 64zm337.46-128c-34.91 0-76.16 13.12-104.73 32-24.79 16.38-44.52 32-104.73 32v128l57.53 15.97c26.21 7.28 53.01 13.12 80.31 15.05 32.69 2.31 65.6.67 97.58-6.2C472.9 481.3 512 429.22 512 384c0-64-84.18-96-174.54-96zM491.42 7.19C459.44.32 426.53-1.33 393.84.99c-27.3 1.93-54.1 7.77-80.31 15.04L256 32v128c60.2 0 79.94 15.62 104.73 32 28.57 18.88 69.82 32 104.73 32C555.82 224 640 192 640 128c0-45.22-39.1-97.3-148.58-120.81z\"]\n};\nvar faShoppingBag = {\n prefix: 'fas',\n iconName: 'shopping-bag',\n icon: [448, 512, [], \"f290\", \"M352 160v-32C352 57.42 294.579 0 224 0 153.42 0 96 57.42 96 128v32H0v272c0 44.183 35.817 80 80 80h288c44.183 0 80-35.817 80-80V160h-96zm-192-32c0-35.29 28.71-64 64-64s64 28.71 64 64v32H160v-32zm160 120c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm-192 0c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24z\"]\n};\nvar faShoppingBasket = {\n prefix: 'fas',\n iconName: 'shopping-basket',\n icon: [576, 512, [], \"f291\", \"M576 216v16c0 13.255-10.745 24-24 24h-8l-26.113 182.788C514.509 462.435 494.257 480 470.37 480H105.63c-23.887 0-44.139-17.565-47.518-41.212L32 256h-8c-13.255 0-24-10.745-24-24v-16c0-13.255 10.745-24 24-24h67.341l106.78-146.821c10.395-14.292 30.407-17.453 44.701-7.058 14.293 10.395 17.453 30.408 7.058 44.701L170.477 192h235.046L326.12 82.821c-10.395-14.292-7.234-34.306 7.059-44.701 14.291-10.395 34.306-7.235 44.701 7.058L484.659 192H552c13.255 0 24 10.745 24 24zM312 392V280c0-13.255-10.745-24-24-24s-24 10.745-24 24v112c0 13.255 10.745 24 24 24s24-10.745 24-24zm112 0V280c0-13.255-10.745-24-24-24s-24 10.745-24 24v112c0 13.255 10.745 24 24 24s24-10.745 24-24zm-224 0V280c0-13.255-10.745-24-24-24s-24 10.745-24 24v112c0 13.255 10.745 24 24 24s24-10.745 24-24z\"]\n};\nvar faShoppingCart = {\n prefix: 'fas',\n iconName: 'shopping-cart',\n icon: [576, 512, [], \"f07a\", \"M528.12 301.319l47.273-208C578.806 78.301 567.391 64 551.99 64H159.208l-9.166-44.81C147.758 8.021 137.93 0 126.529 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24h69.883l70.248 343.435C147.325 417.1 136 435.222 136 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-15.674-6.447-29.835-16.824-40h209.647C430.447 426.165 424 440.326 424 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-22.172-12.888-41.332-31.579-50.405l5.517-24.276c3.413-15.018-8.002-29.319-23.403-29.319H218.117l-6.545-32h293.145c11.206 0 20.92-7.754 23.403-18.681z\"]\n};\nvar faShower = {\n prefix: 'fas',\n iconName: 'shower',\n icon: [512, 512, [], \"f2cc\", \"M389.66 135.6L231.6 293.66c-9.37 9.37-24.57 9.37-33.94 0l-11.32-11.32c-9.37-9.37-9.37-24.57 0-33.94l.11-.11c-34.03-40.21-35.16-98.94-3.39-140.38-11.97-7.55-26.14-11.91-41.3-11.91C98.88 96 64 130.88 64 173.76V480H0V173.76C0 95.59 63.59 32 141.76 32c36.93 0 70.61 14.2 95.86 37.42 35.9-11.51 76.5-4.5 106.67 21.03l.11-.11c9.37-9.37 24.57-9.37 33.94 0l11.32 11.32c9.37 9.37 9.37 24.57 0 33.94zM384 208c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm32 0c0-8.837 7.163-16 16-16s16 7.163 16 16-7.163 16-16 16-16-7.163-16-16zm96 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-160 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm48-16c8.837 0 16 7.163 16 16s-7.163 16-16 16-16-7.163-16-16 7.163-16 16-16zm80 16c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-160 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm32 0c0-8.837 7.163-16 16-16s16 7.163 16 16-7.163 16-16 16-16-7.163-16-16zm96 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-128 32c0-8.837 7.163-16 16-16s16 7.163 16 16-7.163 16-16 16-16-7.163-16-16zm96 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-96 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm64 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-32 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-32 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16z\"]\n};\nvar faShuttleVan = {\n prefix: 'fas',\n iconName: 'shuttle-van',\n icon: [640, 512, [], \"f5b6\", \"M628.88 210.65L494.39 49.27A48.01 48.01 0 0 0 457.52 32H32C14.33 32 0 46.33 0 64v288c0 17.67 14.33 32 32 32h32c0 53.02 42.98 96 96 96s96-42.98 96-96h128c0 53.02 42.98 96 96 96s96-42.98 96-96h32c17.67 0 32-14.33 32-32V241.38c0-11.23-3.94-22.1-11.12-30.73zM64 192V96h96v96H64zm96 240c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm160-240h-96V96h96v96zm160 240c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm-96-240V96h66.02l80 96H384z\"]\n};\nvar faSign = {\n prefix: 'fas',\n iconName: 'sign',\n icon: [512, 512, [], \"f4d9\", \"M496 64H128V16c0-8.8-7.2-16-16-16H80c-8.8 0-16 7.2-16 16v48H16C7.2 64 0 71.2 0 80v32c0 8.8 7.2 16 16 16h48v368c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V128h368c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16zM160 384h320V160H160v224z\"]\n};\nvar faSignInAlt = {\n prefix: 'fas',\n iconName: 'sign-in-alt',\n icon: [512, 512, [], \"f2f6\", \"M416 448h-84c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h84c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32h-84c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h84c53 0 96 43 96 96v192c0 53-43 96-96 96zm-47-201L201 79c-15-15-41-4.5-41 17v96H24c-13.3 0-24 10.7-24 24v96c0 13.3 10.7 24 24 24h136v96c0 21.5 26 32 41 17l168-168c9.3-9.4 9.3-24.6 0-34z\"]\n};\nvar faSignLanguage = {\n prefix: 'fas',\n iconName: 'sign-language',\n icon: [448, 512, [], \"f2a7\", \"M91.434 483.987c-.307-16.018 13.109-29.129 29.13-29.129h62.293v-5.714H56.993c-16.021 0-29.437-13.111-29.13-29.129C28.16 404.491 40.835 392 56.428 392h126.429v-5.714H29.136c-16.021 0-29.437-13.111-29.13-29.129.297-15.522 12.973-28.013 28.566-28.013h154.286v-5.714H57.707c-16.021 0-29.437-13.111-29.13-29.129.297-15.522 12.973-28.013 28.566-28.013h168.566l-31.085-22.606c-12.762-9.281-15.583-27.149-6.302-39.912 9.281-12.761 27.15-15.582 39.912-6.302l123.361 89.715a34.287 34.287 0 0 1 14.12 27.728v141.136c0 15.91-10.946 29.73-26.433 33.374l-80.471 18.934a137.16 137.16 0 0 1-31.411 3.646H120c-15.593-.001-28.269-12.492-28.566-28.014zm73.249-225.701h36.423l-11.187-8.136c-18.579-13.511-20.313-40.887-3.17-56.536l-13.004-16.7c-9.843-12.641-28.43-15.171-40.88-5.088-12.065 9.771-14.133 27.447-4.553 39.75l36.371 46.71zm283.298-2.103l-5.003-152.452c-.518-15.771-13.722-28.136-29.493-27.619-15.773.518-28.137 13.722-27.619 29.493l1.262 38.415L283.565 11.019c-9.58-12.303-27.223-14.63-39.653-5.328-12.827 9.599-14.929 28.24-5.086 40.881l76.889 98.745-4.509 3.511-94.79-121.734c-9.58-12.303-27.223-14.63-39.653-5.328-12.827 9.599-14.929 28.24-5.086 40.881l94.443 121.288-4.509 3.511-77.675-99.754c-9.58-12.303-27.223-14.63-39.653-5.328-12.827 9.599-14.929 28.24-5.086 40.881l52.053 66.849c12.497-8.257 29.055-8.285 41.69.904l123.36 89.714c10.904 7.93 17.415 20.715 17.415 34.198v16.999l61.064-47.549a34.285 34.285 0 0 0 13.202-28.177z\"]\n};\nvar faSignOutAlt = {\n prefix: 'fas',\n iconName: 'sign-out-alt',\n icon: [512, 512, [], \"f2f5\", \"M497 273L329 441c-15 15-41 4.5-41-17v-96H152c-13.3 0-24-10.7-24-24v-96c0-13.3 10.7-24 24-24h136V88c0-21.4 25.9-32 41-17l168 168c9.3 9.4 9.3 24.6 0 34zM192 436v-40c0-6.6-5.4-12-12-12H96c-17.7 0-32-14.3-32-32V160c0-17.7 14.3-32 32-32h84c6.6 0 12-5.4 12-12V76c0-6.6-5.4-12-12-12H96c-53 0-96 43-96 96v192c0 53 43 96 96 96h84c6.6 0 12-5.4 12-12z\"]\n};\nvar faSignal = {\n prefix: 'fas',\n iconName: 'signal',\n icon: [640, 512, [], \"f012\", \"M216 288h-48c-8.84 0-16 7.16-16 16v192c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16V304c0-8.84-7.16-16-16-16zM88 384H40c-8.84 0-16 7.16-16 16v96c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16v-96c0-8.84-7.16-16-16-16zm256-192h-48c-8.84 0-16 7.16-16 16v288c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16V208c0-8.84-7.16-16-16-16zm128-96h-48c-8.84 0-16 7.16-16 16v384c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16V112c0-8.84-7.16-16-16-16zM600 0h-48c-8.84 0-16 7.16-16 16v480c0 8.84 7.16 16 16 16h48c8.84 0 16-7.16 16-16V16c0-8.84-7.16-16-16-16z\"]\n};\nvar faSignature = {\n prefix: 'fas',\n iconName: 'signature',\n icon: [640, 512, [], \"f5b7\", \"M623.2 192c-51.8 3.5-125.7 54.7-163.1 71.5-29.1 13.1-54.2 24.4-76.1 24.4-22.6 0-26-16.2-21.3-51.9 1.1-8 11.7-79.2-42.7-76.1-25.1 1.5-64.3 24.8-169.5 126L192 182.2c30.4-75.9-53.2-151.5-129.7-102.8L7.4 116.3C0 121-2.2 130.9 2.5 138.4l17.2 27c4.7 7.5 14.6 9.7 22.1 4.9l58-38.9c18.4-11.7 40.7 7.2 32.7 27.1L34.3 404.1C27.5 421 37 448 64 448c8.3 0 16.5-3.2 22.6-9.4 42.2-42.2 154.7-150.7 211.2-195.8-2.2 28.5-2.1 58.9 20.6 83.8 15.3 16.8 37.3 25.3 65.5 25.3 35.6 0 68-14.6 102.3-30 33-14.8 99-62.6 138.4-65.8 8.5-.7 15.2-7.3 15.2-15.8v-32.1c.2-9.1-7.5-16.8-16.6-16.2z\"]\n};\nvar faSimCard = {\n prefix: 'fas',\n iconName: 'sim-card',\n icon: [384, 512, [], \"f7c4\", \"M320 0H128L0 128v320c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zM160 192h64v64h-64v-64zm-96 32c0-17.7 14.3-32 32-32h32v64H64v-32zm64 224H96c-17.7 0-32-14.3-32-32v-32h64v64zm96 0h-64v-64h64v64zm96-32c0 17.7-14.3 32-32 32h-32v-64h64v32zm0-64H64v-64h256v64zm0-96h-64v-64h32c17.7 0 32 14.3 32 32v32z\"]\n};\nvar faSitemap = {\n prefix: 'fas',\n iconName: 'sitemap',\n icon: [640, 512, [], \"f0e8\", \"M128 352H32c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32zm-24-80h192v48h48v-48h192v48h48v-57.59c0-21.17-17.23-38.41-38.41-38.41H344v-64h40c17.67 0 32-14.33 32-32V32c0-17.67-14.33-32-32-32H256c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h40v64H94.41C73.23 224 56 241.23 56 262.41V320h48v-48zm264 80h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32zm240 0h-96c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32z\"]\n};\nvar faSkating = {\n prefix: 'fas',\n iconName: 'skating',\n icon: [448, 512, [], \"f7c5\", \"M400 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm0 448c-8.8 0-16 7.2-16 16s-7.2 16-16 16h-96c-8.8 0-16 7.2-16 16s7.2 16 16 16h96c26.5 0 48-21.5 48-48 0-8.8-7.2-16-16-16zm-282.2 8.6c-6.2 6.2-16.4 6.3-22.6 0l-67.9-67.9c-6.2-6.2-16.4-6.2-22.6 0s-6.2 16.4 0 22.6l67.9 67.9c9.4 9.4 21.7 14 34 14s24.6-4.7 33.9-14c6.2-6.2 6.2-16.4 0-22.6s-16.4-6.3-22.7 0zm56.1-179.8l-93.7 93.7c-12.5 12.5-12.5 32.8 0 45.2 6.2 6.2 14.4 9.4 22.6 9.4s16.4-3.1 22.6-9.4l91.9-91.9-30.2-30.2c-5-5-9.4-10.7-13.2-16.8zM128 160h105.5l-20.1 17.2c-13.5 11.5-21.6 28.4-22.3 46.1-.7 17.8 6.1 35.2 18.7 47.7l78.2 78.2V432c0 17.7 14.3 32 32 32s32-14.3 32-32v-89.4c0-12.6-5.1-25-14.1-33.9l-61-61c.5-.4 1.2-.6 1.7-1.1l82.3-82.3c11.5-11.5 14.9-28.6 8.7-43.6-6.2-15-20.7-24.7-37-24.7H128c-17.7 0-32 14.3-32 32s14.3 32 32 32z\"]\n};\nvar faSkiing = {\n prefix: 'fas',\n iconName: 'skiing',\n icon: [512, 512, [], \"f7c9\", \"M432 96c26.5 0 48-21.5 48-48S458.5 0 432 0s-48 21.5-48 48 21.5 48 48 48zm73 356.1c-9.4-9.4-24.6-9.4-33.9 0-12.1 12.1-30.5 15.4-45.1 8.7l-135.8-70.2 49.2-73.8c12.7-19 10.2-44.5-6-60.6L293 215.7l-107-53.1c-2.9 19.9 3.4 40 17.7 54.4l75.1 75.2-45.9 68.8L35 258.7c-11.7-6-26.2-1.5-32.3 10.3-6.1 11.8-1.5 26.3 10.3 32.3l391.9 202.5c11.9 5.5 24.5 8.1 37.1 8.1 23.2 0 46-9 63-26 9.3-9.3 9.3-24.5 0-33.8zM120 91.6l-11.5 22.5c14.4 7.3 31.2 4.9 42.8-4.8l47.2 23.4c-.1.1-.1.2-.2.3l114.5 56.8 32.4-13 6.4 19.1c4 12.1 12.6 22 24 27.7l58.1 29c15.9 7.9 35 1.5 42.9-14.3 7.9-15.8 1.5-35-14.3-42.9l-52.1-26.1-17.1-51.2c-8.1-24.2-40.9-56.6-84.5-39.2l-81.2 32.5-62.5-31c.3-14.5-7.2-28.6-20.9-35.6l-11.1 21.7h-.2l-34.4-7c-1.8-.4-3.7.2-5 1.7-1.9 2.2-1.7 5.5.5 7.4l26.2 23z\"]\n};\nvar faSkiingNordic = {\n prefix: 'fas',\n iconName: 'skiing-nordic',\n icon: [576, 512, [], \"f7ca\", \"M336 96c26.5 0 48-21.5 48-48S362.5 0 336 0s-48 21.5-48 48 21.5 48 48 48zm216 320c-13.2 0-24 10.7-24 24 0 13.2-10.8 24-24 24h-69.5L460 285.6c11.7-4.7 20.1-16.2 20.1-29.6 0-17.7-14.3-32-32-32h-44L378 170.8c-12.5-25.5-35.5-44.2-61.8-50.9L245 98.7c-28.3-6.8-57.8-.5-80.8 17.1l-39.7 30.4c-14 10.7-16.7 30.8-5.9 44.9.7.9 1.7 1.3 2.4 2.1L66.9 464H24c-13.2 0-24 10.7-24 24s10.8 24 24 24h480c39.7 0 72-32.3 72-72 0-13.2-10.8-24-24-24zm-260.5 48h-96.9l43.1-91-22-13c-12.1-7.2-21.9-16.9-29.5-27.8L123.7 464H99.5l52.3-261.4c4.1-1 8.1-2.9 11.7-5.6l39.7-30.4c7.7-5.9 17.4-8 25.3-6.1l14.7 4.4-37.5 87.4c-12.6 29.5-1.3 64 26.3 80.3l85 50.2-25.5 81.2zm110.6 0h-43.6l23.6-75.5c5.9-20.8-2.9-43.1-21.6-54.4L299.3 298l31.3-78.3 20.3 41.4c8 16.3 24.9 26.9 43.1 26.9h33.3l-25.2 176z\"]\n};\nvar faSkull = {\n prefix: 'fas',\n iconName: 'skull',\n icon: [512, 512, [], \"f54c\", \"M256 0C114.6 0 0 100.3 0 224c0 70.1 36.9 132.6 94.5 173.7 9.6 6.9 15.2 18.1 13.5 29.9l-9.4 66.2c-1.4 9.6 6 18.2 15.7 18.2H192v-56c0-4.4 3.6-8 8-8h16c4.4 0 8 3.6 8 8v56h64v-56c0-4.4 3.6-8 8-8h16c4.4 0 8 3.6 8 8v56h77.7c9.7 0 17.1-8.6 15.7-18.2l-9.4-66.2c-1.7-11.7 3.8-23 13.5-29.9C475.1 356.6 512 294.1 512 224 512 100.3 397.4 0 256 0zm-96 320c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64zm192 0c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z\"]\n};\nvar faSkullCrossbones = {\n prefix: 'fas',\n iconName: 'skull-crossbones',\n icon: [448, 512, [], \"f714\", \"M439.15 453.06L297.17 384l141.99-69.06c7.9-3.95 11.11-13.56 7.15-21.46L432 264.85c-3.95-7.9-13.56-11.11-21.47-7.16L224 348.41 37.47 257.69c-7.9-3.95-17.51-.75-21.47 7.16L1.69 293.48c-3.95 7.9-.75 17.51 7.15 21.46L150.83 384 8.85 453.06c-7.9 3.95-11.11 13.56-7.15 21.47l14.31 28.63c3.95 7.9 13.56 11.11 21.47 7.15L224 419.59l186.53 90.72c7.9 3.95 17.51.75 21.47-7.15l14.31-28.63c3.95-7.91.74-17.52-7.16-21.47zM150 237.28l-5.48 25.87c-2.67 12.62 5.42 24.85 16.45 24.85h126.08c11.03 0 19.12-12.23 16.45-24.85l-5.5-25.87c41.78-22.41 70-62.75 70-109.28C368 57.31 303.53 0 224 0S80 57.31 80 128c0 46.53 28.22 86.87 70 109.28zM280 112c17.65 0 32 14.35 32 32s-14.35 32-32 32-32-14.35-32-32 14.35-32 32-32zm-112 0c17.65 0 32 14.35 32 32s-14.35 32-32 32-32-14.35-32-32 14.35-32 32-32z\"]\n};\nvar faSlash = {\n prefix: 'fas',\n iconName: 'slash',\n icon: [640, 512, [], \"f715\", \"M594.53 508.63L6.18 53.9c-6.97-5.42-8.23-15.47-2.81-22.45L23.01 6.18C28.43-.8 38.49-2.06 45.47 3.37L633.82 458.1c6.97 5.42 8.23 15.47 2.81 22.45l-19.64 25.27c-5.42 6.98-15.48 8.23-22.46 2.81z\"]\n};\nvar faSleigh = {\n prefix: 'fas',\n iconName: 'sleigh',\n icon: [640, 512, [], \"f7cc\", \"M612.7 350.7l-9.3-7.4c-6.9-5.5-17-4.4-22.5 2.5l-10 12.5c-5.5 6.9-4.4 17 2.5 22.5l9.3 7.4c5.9 4.7 9.2 11.7 9.2 19.2 0 13.6-11 24.6-24.6 24.6H48c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h516c39 0 73.7-29.3 75.9-68.3 1.4-23.8-8.7-46.3-27.2-61zM32 224c0 59.6 40.9 109.2 96 123.5V400h64v-48h192v48h64v-48c53 0 96-43 96-96v-96c17.7 0 32-14.3 32-32s-14.3-32-32-32h-96v64c0 35.3-28.7 64-64 64h-20.7c-65.8 0-125.9-37.2-155.3-96-29.4-58.8-89.6-96-155.3-96H32C14.3 32 0 46.3 0 64s14.3 32 32 32v128z\"]\n};\nvar faSlidersH = {\n prefix: 'fas',\n iconName: 'sliders-h',\n icon: [512, 512, [], \"f1de\", \"M496 384H160v-16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v16H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h80v16c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-16h336c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-160h-80v-16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v16H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h336v16c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-16h80c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-160H288V48c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v16H16C7.2 64 0 71.2 0 80v32c0 8.8 7.2 16 16 16h208v16c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-16h208c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16z\"]\n};\nvar faSmile = {\n prefix: 'fas',\n iconName: 'smile',\n icon: [496, 512, [], \"f118\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm194.8 170.2C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.6-16.3 11-36.7 24.6-20.5 22.4 26.9 55.2 42.2 90.2 42.2s67.8-15.4 90.2-42.2c13.4-16.2 38.1 4.2 24.6 20.5z\"]\n};\nvar faSmileBeam = {\n prefix: 'fas',\n iconName: 'smile-beam',\n icon: [496, 512, [], \"f5b8\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM112 223.4c3.3-42.1 32.2-71.4 56-71.4s52.7 29.3 56 71.4c.7 8.6-10.8 11.9-14.9 4.5l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.3 7.4-15.8 4-15.1-4.5zm250.8 122.8C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.5-16.3 11-36.7 24.6-20.5 22.4 26.9 55.2 42.2 90.2 42.2s67.8-15.4 90.2-42.2c13.6-16.2 38.1 4.3 24.6 20.5zm6.2-118.3l-9.5-17c-7.7-13.7-19.2-21.6-31.5-21.6s-23.8 7.9-31.5 21.6l-9.5 17c-4.1 7.3-15.6 4-14.9-4.5 3.3-42.1 32.2-71.4 56-71.4s52.7 29.3 56 71.4c.6 8.6-11 11.9-15.1 4.5z\"]\n};\nvar faSmileWink = {\n prefix: 'fas',\n iconName: 'smile-wink',\n icon: [496, 512, [], \"f4da\", \"M0 256c0 137 111 248 248 248s248-111 248-248S385 8 248 8 0 119 0 256zm200-48c0 17.7-14.3 32-32 32s-32-14.3-32-32 14.3-32 32-32 32 14.3 32 32zm158.5 16.5c-14.8-13.2-46.2-13.2-61 0L288 233c-8.3 7.4-21.6.4-19.8-10.8 4-25.2 34.2-42.1 59.9-42.1S384 197 388 222.2c1.7 11.1-11.4 18.3-19.8 10.8l-9.7-8.5zM157.8 325.8C180.2 352.7 213 368 248 368s67.8-15.4 90.2-42.2c13.6-16.2 38.1 4.2 24.6 20.5C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.5-16.3 11.2-36.7 24.6-20.4z\"]\n};\nvar faSmog = {\n prefix: 'fas',\n iconName: 'smog',\n icon: [640, 512, [], \"f75f\", \"M624 368H80c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h544c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16zm-480 96H16c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h128c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16zm416 0H224c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h336c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16zM144 288h156.1c22.5 19.7 51.6 32 83.9 32s61.3-12.3 83.9-32H528c61.9 0 112-50.1 112-112S589.9 64 528 64c-18 0-34.7 4.6-49.7 12.1C454 31 406.8 0 352 0c-41 0-77.8 17.3-104 44.8C221.8 17.3 185 0 144 0 64.5 0 0 64.5 0 144s64.5 144 144 144z\"]\n};\nvar faSmoking = {\n prefix: 'fas',\n iconName: 'smoking',\n icon: [640, 512, [], \"f48d\", \"M632 352h-48c-4.4 0-8 3.6-8 8v144c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8zM553.3 87.1c-5.7-3.8-9.3-10-9.3-16.8V8c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v62.3c0 22 10.2 43.4 28.6 55.4 42.2 27.3 67.4 73.8 67.4 124V280c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-30.3c0-65.5-32.4-126.2-86.7-162.6zM432 352H48c-26.5 0-48 21.5-48 48v64c0 26.5 21.5 48 48 48h384c8.8 0 16-7.2 16-16V368c0-8.8-7.2-16-16-16zm-32 112H224v-64h176v64zm87.7-322.4C463.8 125 448 99.3 448 70.3V8c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v66.4c0 43.7 24.6 81.6 60.3 106.7 22.4 15.7 35.7 41.2 35.7 68.6V280c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-30.3c0-43.3-21-83.4-56.3-108.1zM536 352h-48c-4.4 0-8 3.6-8 8v144c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V360c0-4.4-3.6-8-8-8z\"]\n};\nvar faSmokingBan = {\n prefix: 'fas',\n iconName: 'smoking-ban',\n icon: [512, 512, [], \"f54d\", \"M96 304c0 8.8 7.2 16 16 16h117.5l-96-96H112c-8.8 0-16 7.2-16 16v64zM256 0C114.6 0 0 114.6 0 256s114.6 256 256 256 256-114.6 256-256S397.4 0 256 0zm0 448c-105.9 0-192-86.1-192-192 0-41.4 13.3-79.7 35.7-111.1l267.4 267.4C335.7 434.7 297.4 448 256 448zm45.2-192H384v32h-50.8l-32-32zm111.1 111.1L365.2 320H400c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16H269.2L144.9 99.7C176.3 77.3 214.6 64 256 64c105.9 0 192 86.1 192 192 0 41.4-13.3 79.7-35.7 111.1zM320.6 128c-15.6 0-28.6-11.2-31.4-25.9-.7-3.6-4-6.1-7.7-6.1h-16.2c-5 0-8.7 4.5-8 9.4 4.6 30.9 31.2 54.6 63.3 54.6 15.6 0 28.6 11.2 31.4 25.9.7 3.6 4 6.1 7.7 6.1h16.2c5 0 8.7-4.5 8-9.4-4.6-30.9-31.2-54.6-63.3-54.6z\"]\n};\nvar faSms = {\n prefix: 'fas',\n iconName: 'sms',\n icon: [512, 512, [], \"f7cd\", \"M256 32C114.6 32 0 125.1 0 240c0 49.6 21.4 95 57 130.7C44.5 421.1 2.7 466 2.2 466.5c-2.2 2.3-2.8 5.7-1.5 8.7 1.3 3 4.1 4.8 7.3 4.8 66.3 0 116-31.8 140.6-51.4 32.7 12.3 69 19.4 107.4 19.4 141.4 0 256-93.1 256-208S397.4 32 256 32zM128.2 304H116c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h12.3c6 0 10.4-3.5 10.4-6.6 0-1.3-.8-2.7-2.1-3.8l-21.9-18.8c-8.5-7.2-13.3-17.5-13.3-28.1 0-21.3 19-38.6 42.4-38.6H156c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8h-12.3c-6 0-10.4 3.5-10.4 6.6 0 1.3.8 2.7 2.1 3.8l21.9 18.8c8.5 7.2 13.3 17.5 13.3 28.1.1 21.3-19 38.6-42.4 38.6zm191.8-8c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8v-68.2l-24.8 55.8c-2.9 5.9-11.4 5.9-14.3 0L224 227.8V296c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8V192c0-8.8 7.2-16 16-16h16c6.1 0 11.6 3.4 14.3 8.8l17.7 35.4 17.7-35.4c2.7-5.4 8.3-8.8 14.3-8.8h16c8.8 0 16 7.2 16 16v104zm48.3 8H356c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h12.3c6 0 10.4-3.5 10.4-6.6 0-1.3-.8-2.7-2.1-3.8l-21.9-18.8c-8.5-7.2-13.3-17.5-13.3-28.1 0-21.3 19-38.6 42.4-38.6H396c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8h-12.3c-6 0-10.4 3.5-10.4 6.6 0 1.3.8 2.7 2.1 3.8l21.9 18.8c8.5 7.2 13.3 17.5 13.3 28.1.1 21.3-18.9 38.6-42.3 38.6z\"]\n};\nvar faSnowboarding = {\n prefix: 'fas',\n iconName: 'snowboarding',\n icon: [512, 512, [], \"f7ce\", \"M432 96c26.5 0 48-21.5 48-48S458.5 0 432 0s-48 21.5-48 48 21.5 48 48 48zm28.8 153.6c5.8 4.3 12.5 6.4 19.2 6.4 9.7 0 19.3-4.4 25.6-12.8 10.6-14.1 7.8-34.2-6.4-44.8l-111.4-83.5c-13.8-10.3-29.1-18.4-45.4-23.8l-63.7-21.2-26.1-52.1C244.7 2 225.5-4.4 209.7 3.5c-15.8 7.9-22.2 27.1-14.3 42.9l29.1 58.1c5.7 11.4 15.6 19.9 27.7 24l16.4 5.5-41.2 20.6c-21.8 10.9-35.4 32.8-35.4 57.2v53.1l-74.1 24.7c-16.8 5.6-25.8 23.7-20.2 40.5 1.7 5.2 4.9 9.4 8.7 12.9l-38.7-14.1c-9.7-3.5-17.4-10.6-21.8-20-5.6-12-19.9-17.2-31.9-11.6s-17.2 19.9-11.6 31.9c9.8 21 27.1 36.9 48.9 44.8l364.8 132.7c9.7 3.5 19.7 5.3 29.7 5.3 12.5 0 24.9-2.7 36.5-8.2 12-5.6 17.2-19.9 11.6-31.9S474 454.7 462 460.3c-9.3 4.4-19.8 4.8-29.5 1.3l-90.8-33.1c8.7-4.1 15.6-11.8 17.8-21.9l21.9-102c3.9-18.2-3.2-37.2-18.1-48.4l-52-39 66-30.5 83.5 62.9zm-144.4 51.7l-19.7 92c-1.5 7.1-.1 13.9 2.8 20l-169.4-61.6c2.7-.2 5.4-.4 8-1.3l85-28.4c19.6-6.5 32.8-24.8 32.8-45.5V256l60.5 45.3z\"]\n};\nvar faSnowflake = {\n prefix: 'fas',\n iconName: 'snowflake',\n icon: [448, 512, [], \"f2dc\", \"M440.3 345.2l-33.8-19.5 26-7c8.2-2.2 13.1-10.7 10.9-18.9l-4-14.9c-2.2-8.2-10.7-13.1-18.9-10.9l-70.8 19-63.9-37 63.8-36.9 70.8 19c8.2 2.2 16.7-2.7 18.9-10.9l4-14.9c2.2-8.2-2.7-16.7-10.9-18.9l-26-7 33.8-19.5c7.4-4.3 9.9-13.7 5.7-21.1L430.4 119c-4.3-7.4-13.7-9.9-21.1-5.7l-33.8 19.5 7-26c2.2-8.2-2.7-16.7-10.9-18.9l-14.9-4c-8.2-2.2-16.7 2.7-18.9 10.9l-19 70.8-62.8 36.2v-77.5l53.7-53.7c6.2-6.2 6.2-16.4 0-22.6l-11.3-11.3c-6.2-6.2-16.4-6.2-22.6 0L256 56.4V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v40.4l-19.7-19.7c-6.2-6.2-16.4-6.2-22.6 0L138.3 48c-6.3 6.2-6.3 16.4 0 22.6l53.7 53.7v77.5l-62.8-36.2-19-70.8c-2.2-8.2-10.7-13.1-18.9-10.9l-14.9 4c-8.2 2.2-13.1 10.7-10.9 18.9l7 26-33.8-19.5c-7.4-4.3-16.8-1.7-21.1 5.7L2.1 145.7c-4.3 7.4-1.7 16.8 5.7 21.1l33.8 19.5-26 7c-8.3 2.2-13.2 10.7-11 19l4 14.9c2.2 8.2 10.7 13.1 18.9 10.9l70.8-19 63.8 36.9-63.8 36.9-70.8-19c-8.2-2.2-16.7 2.7-18.9 10.9l-4 14.9c-2.2 8.2 2.7 16.7 10.9 18.9l26 7-33.8 19.6c-7.4 4.3-9.9 13.7-5.7 21.1l15.5 26.8c4.3 7.4 13.7 9.9 21.1 5.7l33.8-19.5-7 26c-2.2 8.2 2.7 16.7 10.9 18.9l14.9 4c8.2 2.2 16.7-2.7 18.9-10.9l19-70.8 62.8-36.2v77.5l-53.7 53.7c-6.3 6.2-6.3 16.4 0 22.6l11.3 11.3c6.2 6.2 16.4 6.2 22.6 0l19.7-19.7V496c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-40.4l19.7 19.7c6.2 6.2 16.4 6.2 22.6 0l11.3-11.3c6.2-6.2 6.2-16.4 0-22.6L256 387.7v-77.5l62.8 36.2 19 70.8c2.2 8.2 10.7 13.1 18.9 10.9l14.9-4c8.2-2.2 13.1-10.7 10.9-18.9l-7-26 33.8 19.5c7.4 4.3 16.8 1.7 21.1-5.7l15.5-26.8c4.3-7.3 1.8-16.8-5.6-21z\"]\n};\nvar faSnowman = {\n prefix: 'fas',\n iconName: 'snowman',\n icon: [512, 512, [], \"f7d0\", \"M510.9 152.3l-5.9-14.5c-3.3-8-12.6-11.9-20.8-8.7L456 140.6v-29c0-8.6-7.2-15.6-16-15.6h-16c-8.8 0-16 7-16 15.6v46.9c0 .5.3 1 .3 1.5l-56.4 23c-5.9-10-13.3-18.9-22-26.6 13.6-16.6 22-37.4 22-60.5 0-53-43-96-96-96s-96 43-96 96c0 23.1 8.5 43.9 22 60.5-8.7 7.7-16 16.6-22 26.6l-56.4-23c.1-.5.3-1 .3-1.5v-46.9C104 103 96.8 96 88 96H72c-8.8 0-16 7-16 15.6v29l-28.1-11.5c-8.2-3.2-17.5.7-20.8 8.7l-5.9 14.5c-3.3 8 .7 17.1 8.9 20.3l135.2 55.2c-.4 4-1.2 8-1.2 12.2 0 10.1 1.7 19.6 4.2 28.9C120.9 296.4 104 334.2 104 376c0 54 28.4 100.9 70.8 127.8 9.3 5.9 20.3 8.2 31.3 8.2h99.2c13.3 0 26.3-4.1 37.2-11.7 46.5-32.3 74.4-89.4 62.9-152.6-5.5-30.2-20.5-57.6-41.6-79 2.5-9.2 4.2-18.7 4.2-28.7 0-4.2-.8-8.1-1.2-12.2L502 172.6c8.1-3.1 12.1-12.2 8.9-20.3zM224 96c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm32 272c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm0-64c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm0-64c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm0-88s-16-23.2-16-32 7.2-16 16-16 16 7.2 16 16-16 32-16 32zm32-56c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16z\"]\n};\nvar faSnowplow = {\n prefix: 'fas',\n iconName: 'snowplow',\n icon: [640, 512, [], \"f7d2\", \"M120 376c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm80 0c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm80 0c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm80 0c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm238.6 49.4c-14.5-14.5-22.6-34.1-22.6-54.6V269.2c0-20.5 8.1-40.1 22.6-54.6l36.7-36.7c6.2-6.2 6.2-16.4 0-22.6l-22.6-22.6c-6.2-6.2-16.4-6.2-22.6 0l-36.7 36.7c-26.5 26.5-41.4 62.4-41.4 99.9V288h-64v-50.9c0-8.7-1.8-17.2-5.2-25.2L364.5 29.1C356.9 11.4 339.6 0 320.3 0H176c-26.5 0-48 21.5-48 48v112h-16c-26.5 0-48 21.5-48 48v91.2C26.3 317.2 0 355.4 0 400c0 61.9 50.1 112 112 112h256c61.9 0 112-50.1 112-112 0-17.3-4.2-33.4-11.2-48H512v18.7c0 37.5 14.9 73.4 41.4 99.9l36.7 36.7c6.2 6.2 16.4 6.2 22.6 0l22.6-22.6c6.2-6.2 6.2-16.4 0-22.6l-36.7-36.7zM192 64h117.8l68.6 160H256l-64-64V64zm176 384H112c-26.5 0-48-21.5-48-48s21.5-48 48-48h256c26.5 0 48 21.5 48 48s-21.5 48-48 48z\"]\n};\nvar faSocks = {\n prefix: 'fas',\n iconName: 'socks',\n icon: [512, 512, [], \"f696\", \"M214.66 311.01L288 256V96H128v176l-86.65 64.61c-39.4 29.56-53.86 84.42-29.21 127.06C30.39 495.25 63.27 512 96.08 512c20.03 0 40.25-6.25 57.52-19.2l21.86-16.39c-29.85-55.38-13.54-125.84 39.2-165.4zM288 32c0-11.05 3.07-21.3 8.02-30.38C293.4.92 290.85 0 288 0H160c-17.67 0-32 14.33-32 32v32h160V32zM480 0H352c-17.67 0-32 14.33-32 32v32h192V32c0-17.67-14.33-32-32-32zM320 272l-86.13 64.61c-39.4 29.56-53.86 84.42-29.21 127.06 18.25 31.58 50.61 48.33 83.42 48.33 20.03 0 40.25-6.25 57.52-19.2l115.2-86.4A127.997 127.997 0 0 0 512 304V96H320v176z\"]\n};\nvar faSolarPanel = {\n prefix: 'fas',\n iconName: 'solar-panel',\n icon: [640, 512, [], \"f5ba\", \"M431.98 448.01l-47.97.05V416h-128v32.21l-47.98.05c-8.82.01-15.97 7.16-15.98 15.99l-.05 31.73c-.01 8.85 7.17 16.03 16.02 16.02l223.96-.26c8.82-.01 15.97-7.16 15.98-15.98l.04-31.73c.01-8.85-7.17-16.03-16.02-16.02zM585.2 26.74C582.58 11.31 568.99 0 553.06 0H86.93C71 0 57.41 11.31 54.79 26.74-3.32 369.16.04 348.08.03 352c-.03 17.32 14.29 32 32.6 32h574.74c18.23 0 32.51-14.56 32.59-31.79.02-4.08 3.35 16.95-54.76-325.47zM259.83 64h120.33l9.77 96H250.06l9.77-96zm-75.17 256H71.09L90.1 208h105.97l-11.41 112zm16.29-160H98.24l16.29-96h96.19l-9.77 96zm32.82 160l11.4-112h149.65l11.4 112H233.77zm195.5-256h96.19l16.29 96H439.04l-9.77-96zm26.06 256l-11.4-112H549.9l19.01 112H455.33z\"]\n};\nvar faSort = {\n prefix: 'fas',\n iconName: 'sort',\n icon: [320, 512, [], \"f0dc\", \"M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41zm255-105L177 64c-9.4-9.4-24.6-9.4-33.9 0L24 183c-15.1 15.1-4.4 41 17 41h238c21.4 0 32.1-25.9 17-41z\"]\n};\nvar faSortAlphaDown = {\n prefix: 'fas',\n iconName: 'sort-alpha-down',\n icon: [448, 512, [], \"f15d\", \"M400.7 427.1h-61.1c.7-1 1.5-2 2.3-3.1l67.5-95.7c1.4-2 2.2-4.4 2.2-6.9V300c0-6.6-5.4-12-12-12H274.5c-6.6 0-12 5.4-12 12v28.9c0 6.6 5.4 12 12 12H331c-.7 1-1.5 2-2.3 3.1l-67.2 95.2c-1.4 2-2.2 4.4-2.2 6.9V468c0 6.6 5.4 12 12 12h129.4c6.6 0 12-5.4 12-12v-28.9c0-6.7-5.4-12-12-12zM176 368h-48V48c0-8.8-7.2-16-16-16H80c-8.8 0-16 7.2-16 16v320H16c-14.2 0-21.4 17.2-11.3 27.3l80 80c6.2 6.2 16.4 6.2 22.6 0l80-80c10-10 2.9-27.3-11.3-27.3zm248.2-159.9l-57.1-168c-1.7-4.9-6.2-8.1-11.4-8.1h-39.6c-5.1 0-9.7 3.3-11.4 8.1l-57.1 168c-2.6 7.8 3.1 15.9 11.4 15.9h35.7c5.4 0 10.1-3.5 11.5-8.7l8.1-28.2h42.9l8.3 28.3A12 12 0 0 0 377 224h35.7c8.4 0 14.2-8.1 11.5-15.9zm-95-71.5l6.8-22.9 6.6 22.9z\"]\n};\nvar faSortAlphaUp = {\n prefix: 'fas',\n iconName: 'sort-alpha-up',\n icon: [448, 512, [], \"f15e\", \"M107.3 36.7c-6.2-6.2-16.4-6.2-22.6 0l-80 80c-10 10-2.9 27.3 11.3 27.3h48v320c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V144h48c14.2 0 21.4-17.2 11.3-27.3zm293.4 390.4h-61.1c.7-1 1.5-2 2.3-3.1l67.5-95.7c1.4-2 2.2-4.4 2.2-6.9V300c0-6.6-5.4-12-12-12H274.5c-6.6 0-12 5.4-12 12v28.9c0 6.6 5.4 12 12 12H331c-.7 1-1.5 2-2.3 3.1l-67.2 95.2c-1.4 2-2.2 4.4-2.2 6.9V468c0 6.6 5.4 12 12 12h129.4c6.6 0 12-5.4 12-12v-28.9c0-6.7-5.4-12-12-12zm23.5-219l-57.1-168c-1.7-4.9-6.2-8.1-11.4-8.1h-39.6c-5.1 0-9.7 3.3-11.4 8.1l-57.1 168c-2.6 7.8 3.1 15.9 11.4 15.9h35.7c5.4 0 10.1-3.5 11.5-8.7l8.1-28.2h42.9l8.3 28.3A12 12 0 0 0 377 224h35.7c8.4 0 14.2-8.1 11.5-15.9zm-95-71.5l6.8-22.9 6.6 22.9z\"]\n};\nvar faSortAmountDown = {\n prefix: 'fas',\n iconName: 'sort-amount-down',\n icon: [512, 512, [], \"f160\", \"M187.298 395.314l-79.984 80.002c-6.248 6.247-16.383 6.245-22.627 0L4.705 395.314C-5.365 385.244 1.807 368 16.019 368H64V48c0-8.837 7.163-16 16-16h32c8.837 0 16 7.163 16 16v320h47.984c14.241 0 21.363 17.264 11.314 27.314zM240 96h256c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H240c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16zm-16 112v-32c0-8.837 7.163-16 16-16h192c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16zm0 256v-32c0-8.837 7.163-16 16-16h64c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-64c-8.837 0-16-7.163-16-16zm0-128v-32c0-8.837 7.163-16 16-16h128c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16z\"]\n};\nvar faSortAmountUp = {\n prefix: 'fas',\n iconName: 'sort-amount-up',\n icon: [512, 512, [], \"f161\", \"M4.702 116.686l79.984-80.002c6.248-6.247 16.383-6.245 22.627 0l79.981 80.002c10.07 10.07 2.899 27.314-11.314 27.314H128v320c0 8.837-7.163 16-16 16H80c-8.837 0-16-7.163-16-16V144H16.016c-14.241 0-21.363-17.264-11.314-27.314zM240 96h256c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H240c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16zm-16 112v-32c0-8.837 7.163-16 16-16h192c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16zm0 256v-32c0-8.837 7.163-16 16-16h64c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-64c-8.837 0-16-7.163-16-16zm0-128v-32c0-8.837 7.163-16 16-16h128c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16z\"]\n};\nvar faSortDown = {\n prefix: 'fas',\n iconName: 'sort-down',\n icon: [320, 512, [], \"f0dd\", \"M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z\"]\n};\nvar faSortNumericDown = {\n prefix: 'fas',\n iconName: 'sort-numeric-down',\n icon: [448, 512, [], \"f162\", \"M308.811 113.787l-19.448-20.795c-4.522-4.836-4.274-12.421.556-16.95l43.443-40.741a11.999 11.999 0 0 1 8.209-3.247h31.591c6.627 0 12 5.373 12 12v127.07h25.66c6.627 0 12 5.373 12 12v28.93c0 6.627-5.373 12-12 12H301.649c-6.627 0-12-5.373-12-12v-28.93c0-6.627 5.373-12 12-12h25.414v-57.938c-7.254 6.58-14.211 4.921-18.252.601zm-30.57 238.569c0-32.653 23.865-67.356 68.094-67.356 38.253 0 79.424 28.861 79.424 92.228 0 51.276-32.237 105.772-91.983 105.772-17.836 0-30.546-3.557-38.548-6.781-5.79-2.333-8.789-8.746-6.922-14.703l9.237-29.48c2.035-6.496 9.049-9.983 15.467-7.716 13.029 4.602 27.878 5.275 38.103-4.138-38.742 5.072-72.872-25.36-72.872-67.826zm92.273 19.338c0-22.285-15.302-36.505-25.835-36.505-8.642 0-13.164 7.965-13.164 15.832 0 5.669 1.815 24.168 25.168 24.168 9.973 0 13.377-2.154 13.744-2.731.021-.046.087-.291.087-.764zM175.984 368H128V48c0-8.837-7.163-16-16-16H80c-8.837 0-16 7.163-16 16v320H16.019c-14.212 0-21.384 17.244-11.314 27.314l79.981 80.002c6.245 6.245 16.38 6.247 22.627 0l79.984-80.002c10.05-10.05 2.928-27.314-11.313-27.314z\"]\n};\nvar faSortNumericUp = {\n prefix: 'fas',\n iconName: 'sort-numeric-up',\n icon: [448, 512, [], \"f163\", \"M308.811 113.787l-19.448-20.795c-4.522-4.836-4.274-12.421.556-16.95l43.443-40.741a11.999 11.999 0 0 1 8.209-3.247h31.591c6.627 0 12 5.373 12 12v127.07h25.66c6.627 0 12 5.373 12 12v28.93c0 6.627-5.373 12-12 12H301.649c-6.627 0-12-5.373-12-12v-28.93c0-6.627 5.373-12 12-12h25.414v-57.938c-7.254 6.58-14.211 4.921-18.252.601zm-30.57 238.569c0-32.653 23.865-67.356 68.094-67.356 38.253 0 79.424 28.861 79.424 92.228 0 51.276-32.237 105.772-91.983 105.772-17.836 0-30.546-3.557-38.548-6.781-5.79-2.333-8.789-8.746-6.922-14.703l9.237-29.48c2.035-6.496 9.049-9.983 15.467-7.716 13.029 4.602 27.878 5.275 38.103-4.138-38.742 5.072-72.872-25.36-72.872-67.826zm92.273 19.338c0-22.285-15.302-36.505-25.835-36.505-8.642 0-13.164 7.965-13.164 15.832 0 5.669 1.815 24.168 25.168 24.168 9.973 0 13.377-2.154 13.744-2.731.021-.046.087-.291.087-.764zM16.016 144H64v320c0 8.837 7.163 16 16 16h32c8.837 0 16-7.163 16-16V144h47.981c14.212 0 21.384-17.244 11.314-27.314l-79.981-80.002c-6.245-6.245-16.38-6.247-22.627 0L4.702 116.686C-5.347 126.736 1.775 144 16.016 144z\"]\n};\nvar faSortUp = {\n prefix: 'fas',\n iconName: 'sort-up',\n icon: [320, 512, [], \"f0de\", \"M279 224H41c-21.4 0-32.1-25.9-17-41L143 64c9.4-9.4 24.6-9.4 33.9 0l119 119c15.2 15.1 4.5 41-16.9 41z\"]\n};\nvar faSpa = {\n prefix: 'fas',\n iconName: 'spa',\n icon: [576, 512, [], \"f5bb\", \"M568.25 192c-29.04.13-135.01 6.16-213.84 83-33.12 29.63-53.36 63.3-66.41 94.86-13.05-31.56-33.29-65.23-66.41-94.86-78.83-76.84-184.8-82.87-213.84-83-4.41-.02-7.79 3.4-7.75 7.82.23 27.92 7.14 126.14 88.77 199.3C172.79 480.94 256 480 288 480s115.19.95 199.23-80.88c81.64-73.17 88.54-171.38 88.77-199.3.04-4.42-3.34-7.84-7.75-7.82zM287.98 302.6c12.82-18.85 27.6-35.78 44.09-50.52 19.09-18.61 39.58-33.3 60.26-45.18-16.44-70.5-51.72-133.05-96.73-172.22-4.11-3.58-11.02-3.58-15.14 0-44.99 39.14-80.27 101.63-96.74 172.07 20.37 11.7 40.5 26.14 59.22 44.39a282.768 282.768 0 0 1 45.04 51.46z\"]\n};\nvar faSpaceShuttle = {\n prefix: 'fas',\n iconName: 'space-shuttle',\n icon: [640, 512, [], \"f197\", \"M592.604 208.244C559.735 192.836 515.777 184 472 184H186.327c-4.952-6.555-10.585-11.978-16.72-16H376C229.157 137.747 219.403 32 96.003 32H96v128H80V32c-26.51 0-48 28.654-48 64v64c-23.197 0-32 10.032-32 24v40c0 13.983 8.819 24 32 24v16c-23.197 0-32 10.032-32 24v40c0 13.983 8.819 24 32 24v64c0 35.346 21.49 64 48 64V352h16v128h.003c123.4 0 133.154-105.747 279.997-136H169.606c6.135-4.022 11.768-9.445 16.72-16H472c43.777 0 87.735-8.836 120.604-24.244C622.282 289.845 640 271.992 640 256s-17.718-33.845-47.396-47.756zM488 296a8 8 0 0 1-8-8v-64a8 8 0 0 1 8-8c31.909 0 31.942 80 0 80z\"]\n};\nvar faSpider = {\n prefix: 'fas',\n iconName: 'spider',\n icon: [576, 512, [], \"f717\", \"M151.17 167.35L177.1 176h4.67l5.22-26.12c.72-3.58 1.8-7.58 3.21-11.79l-20.29-40.58 23.8-71.39c2.79-8.38-1.73-17.44-10.12-20.24L168.42.82c-8.38-2.8-17.45 1.73-20.24 10.12l-25.89 77.68a32.04 32.04 0 0 0 1.73 24.43l27.15 54.3zm422.14 182.03l-52.75-79.12a32.002 32.002 0 0 0-26.62-14.25H416l68.99-24.36a32.03 32.03 0 0 0 16.51-12.61l53.6-80.41c4.9-7.35 2.91-17.29-4.44-22.19l-13.31-8.88c-7.35-4.9-17.29-2.91-22.19 4.44l-50.56 75.83L404.1 208H368l-10.37-51.85C355.44 145.18 340.26 96 288 96c-52.26 0-67.44 49.18-69.63 60.15L208 208h-36.1l-60.49-20.17L60.84 112c-4.9-7.35-14.83-9.34-22.19-4.44l-13.31 8.88c-7.35 4.9-9.34 14.83-4.44 22.19l53.6 80.41a32.03 32.03 0 0 0 16.51 12.61L160 256H82.06a32.02 32.02 0 0 0-26.63 14.25L2.69 349.38c-4.9 7.35-2.92 17.29 4.44 22.19l13.31 8.88c7.35 4.9 17.29 2.91 22.19-4.44l48-72h47.06l-60.83 97.33A31.988 31.988 0 0 0 72 418.3V496c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16v-73.11l74.08-118.53c-1.01 14.05-2.08 28.11-2.08 42.21C192 399.64 232.76 448 288 448s96-48.36 96-101.43c0-14.1-1.08-28.16-2.08-42.21L456 422.89V496c0 8.84 7.16 16 16 16h16c8.84 0 16-7.16 16-16v-77.71c0-6-1.69-11.88-4.86-16.96L438.31 304h47.06l48 72c4.9 7.35 14.84 9.34 22.19 4.44l13.31-8.88c7.36-4.9 9.34-14.83 4.44-22.18zM406.09 97.51l-20.29 40.58c1.41 4.21 2.49 8.21 3.21 11.79l5.22 26.12h4.67l25.93-8.65 27.15-54.3a31.995 31.995 0 0 0 1.73-24.43l-25.89-77.68C425.03 2.56 415.96-1.98 407.58.82l-15.17 5.06c-8.38 2.8-12.91 11.86-10.12 20.24l23.8 71.39z\"]\n};\nvar faSpinner = {\n prefix: 'fas',\n iconName: 'spinner',\n icon: [512, 512, [], \"f110\", \"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z\"]\n};\nvar faSplotch = {\n prefix: 'fas',\n iconName: 'splotch',\n icon: [512, 512, [], \"f5bc\", \"M472.29 195.89l-67.06-22.95c-19.28-6.6-33.54-20.92-38.14-38.3L351.1 74.19c-11.58-43.77-76.57-57.13-109.98-22.62l-46.14 47.67c-13.26 13.71-33.54 20.93-54.2 19.31l-71.88-5.62c-52.05-4.07-86.93 44.88-59.03 82.83l38.54 52.42c11.08 15.07 12.82 33.86 4.64 50.24L24.62 355.4c-20.59 41.25 22.84 84.87 73.49 73.81l69.96-15.28c20.11-4.39 41.45 0 57.07 11.73l54.32 40.83c39.32 29.56 101.04 7.57 104.45-37.22l4.7-61.86c1.35-17.79 12.8-33.86 30.63-42.99l62-31.74c44.88-22.96 39.59-80.17-8.95-96.79z\"]\n};\nvar faSprayCan = {\n prefix: 'fas',\n iconName: 'spray-can',\n icon: [512, 512, [], \"f5bd\", \"M224 32c0-17.67-14.33-32-32-32h-64c-17.67 0-32 14.33-32 32v96h128V32zm256 96c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32zm-256 32H96c-53.02 0-96 42.98-96 96v224c0 17.67 14.33 32 32 32h256c17.67 0 32-14.33 32-32V256c0-53.02-42.98-96-96-96zm-64 256c-44.18 0-80-35.82-80-80s35.82-80 80-80 80 35.82 80 80-35.82 80-80 80zM480 96c17.67 0 32-14.33 32-32s-14.33-32-32-32-32 14.33-32 32 14.33 32 32 32zm-96 32c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32zm-96-96c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32zm96 0c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32zm96 192c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32z\"]\n};\nvar faSquare = {\n prefix: 'fas',\n iconName: 'square',\n icon: [448, 512, [], \"f0c8\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z\"]\n};\nvar faSquareFull = {\n prefix: 'fas',\n iconName: 'square-full',\n icon: [512, 512, [], \"f45c\", \"M512 512H0V0h512v512z\"]\n};\nvar faSquareRootAlt = {\n prefix: 'fas',\n iconName: 'square-root-alt',\n icon: [576, 512, [], \"f698\", \"M571.31 251.31l-22.62-22.62c-6.25-6.25-16.38-6.25-22.63 0L480 274.75l-46.06-46.06c-6.25-6.25-16.38-6.25-22.63 0l-22.62 22.62c-6.25 6.25-6.25 16.38 0 22.63L434.75 320l-46.06 46.06c-6.25 6.25-6.25 16.38 0 22.63l22.62 22.62c6.25 6.25 16.38 6.25 22.63 0L480 365.25l46.06 46.06c6.25 6.25 16.38 6.25 22.63 0l22.62-22.62c6.25-6.25 6.25-16.38 0-22.63L525.25 320l46.06-46.06c6.25-6.25 6.25-16.38 0-22.63zM552 0H307.65c-14.54 0-27.26 9.8-30.95 23.87l-84.79 322.8-58.41-106.1A32.008 32.008 0 0 0 105.47 224H24c-13.25 0-24 10.74-24 24v48c0 13.25 10.75 24 24 24h43.62l88.88 163.73C168.99 503.5 186.3 512 204.94 512c17.27 0 44.44-9 54.28-41.48L357.03 96H552c13.25 0 24-10.75 24-24V24c0-13.26-10.75-24-24-24z\"]\n};\nvar faStamp = {\n prefix: 'fas',\n iconName: 'stamp',\n icon: [512, 512, [], \"f5bf\", \"M32 512h448v-64H32v64zm384-256h-66.56c-16.26 0-29.44-13.18-29.44-29.44v-9.46c0-27.37 8.88-53.41 21.46-77.72 9.11-17.61 12.9-38.39 9.05-60.42-6.77-38.78-38.47-70.7-77.26-77.45C212.62-9.04 160 37.33 160 96c0 14.16 3.12 27.54 8.69 39.58C182.02 164.43 192 194.7 192 226.49v.07c0 16.26-13.18 29.44-29.44 29.44H96c-53.02 0-96 42.98-96 96v32c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32v-32c0-53.02-42.98-96-96-96z\"]\n};\nvar faStar = {\n prefix: 'fas',\n iconName: 'star',\n icon: [576, 512, [], \"f005\", \"M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z\"]\n};\nvar faStarAndCrescent = {\n prefix: 'fas',\n iconName: 'star-and-crescent',\n icon: [512, 512, [], \"f699\", \"M340.47 466.36c-1.45 0-6.89.46-9.18.46-116.25 0-210.82-94.57-210.82-210.82S215.04 45.18 331.29 45.18c2.32 0 7.7.46 9.18.46 7.13 0 13.33-5.03 14.75-12.07 1.46-7.25-2.55-14.49-9.47-17.09C316.58 5.54 286.39 0 256 0 114.84 0 0 114.84 0 256s114.84 256 256 256c30.23 0 60.28-5.49 89.32-16.32 5.96-2.02 10.28-7.64 10.28-14.26 0-8.09-6.39-15.06-15.13-15.06zm162.99-252.5l-76.38-11.1-34.16-69.21c-1.83-3.7-5.38-5.55-8.93-5.55s-7.1 1.85-8.93 5.55l-34.16 69.21-76.38 11.1c-8.17 1.18-11.43 11.22-5.52 16.99l55.27 53.87-13.05 76.07c-1.11 6.44 4.01 11.66 9.81 11.66 1.53 0 3.11-.36 4.64-1.17L384 335.37l68.31 35.91c1.53.8 3.11 1.17 4.64 1.17 5.8 0 10.92-5.23 9.81-11.66l-13.05-76.07 55.27-53.87c5.91-5.77 2.65-15.81-5.52-16.99z\"]\n};\nvar faStarHalf = {\n prefix: 'fas',\n iconName: 'star-half',\n icon: [576, 512, [], \"f089\", \"M288 0c-11.4 0-22.8 5.9-28.7 17.8L194 150.2 47.9 171.4c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.1 23 46 46.4 33.7L288 439.6V0z\"]\n};\nvar faStarHalfAlt = {\n prefix: 'fas',\n iconName: 'star-half-alt',\n icon: [536, 512, [], \"f5c0\", \"M508.55 171.51L362.18 150.2 296.77 17.81C290.89 5.98 279.42 0 267.95 0c-11.4 0-22.79 5.9-28.69 17.81l-65.43 132.38-146.38 21.29c-26.25 3.8-36.77 36.09-17.74 54.59l105.89 103-25.06 145.48C86.98 495.33 103.57 512 122.15 512c4.93 0 10-1.17 14.87-3.75l130.95-68.68 130.94 68.7c4.86 2.55 9.92 3.71 14.83 3.71 18.6 0 35.22-16.61 31.66-37.4l-25.03-145.49 105.91-102.98c19.04-18.5 8.52-50.8-17.73-54.6zm-121.74 123.2l-18.12 17.62 4.28 24.88 19.52 113.45-102.13-53.59-22.38-11.74.03-317.19 51.03 103.29 11.18 22.63 25.01 3.64 114.23 16.63-82.65 80.38z\"]\n};\nvar faStarOfDavid = {\n prefix: 'fas',\n iconName: 'star-of-david',\n icon: [464, 512, [], \"f69a\", \"M405.68 256l53.21-89.39C473.3 142.4 455.48 112 426.88 112H319.96l-55.95-93.98C256.86 6.01 244.43 0 232 0s-24.86 6.01-32.01 18.02L144.04 112H37.11c-28.6 0-46.42 30.4-32.01 54.61L58.32 256 5.1 345.39C-9.31 369.6 8.51 400 37.11 400h106.93l55.95 93.98C207.14 505.99 219.57 512 232 512s24.86-6.01 32.01-18.02L319.96 400h106.93c28.6 0 46.42-30.4 32.01-54.61L405.68 256zm-12.78-88l-19.8 33.26L353.3 168h39.6zm-52.39 88l-52.39 88H175.88l-52.39-88 52.38-88h112.25l52.39 88zM232 73.72L254.79 112h-45.57L232 73.72zM71.1 168h39.6l-19.8 33.26L71.1 168zm0 176l19.8-33.26L110.7 344H71.1zM232 438.28L209.21 400h45.57L232 438.28zM353.29 344l19.8-33.26L392.9 344h-39.61z\"]\n};\nvar faStarOfLife = {\n prefix: 'fas',\n iconName: 'star-of-life',\n icon: [480, 512, [], \"f621\", \"M471.99 334.43L336.06 256l135.93-78.43c7.66-4.42 10.28-14.2 5.86-21.86l-32.02-55.43c-4.42-7.65-14.21-10.28-21.87-5.86l-135.93 78.43V16c0-8.84-7.17-16-16.01-16h-64.04c-8.84 0-16.01 7.16-16.01 16v156.86L56.04 94.43c-7.66-4.42-17.45-1.79-21.87 5.86L2.15 155.71c-4.42 7.65-1.8 17.44 5.86 21.86L143.94 256 8.01 334.43c-7.66 4.42-10.28 14.21-5.86 21.86l32.02 55.43c4.42 7.65 14.21 10.27 21.87 5.86l135.93-78.43V496c0 8.84 7.17 16 16.01 16h64.04c8.84 0 16.01-7.16 16.01-16V339.14l135.93 78.43c7.66 4.42 17.45 1.8 21.87-5.86l32.02-55.43c4.42-7.65 1.8-17.43-5.86-21.85z\"]\n};\nvar faStepBackward = {\n prefix: 'fas',\n iconName: 'step-backward',\n icon: [448, 512, [], \"f048\", \"M64 468V44c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12v176.4l195.5-181C352.1 22.3 384 36.6 384 64v384c0 27.4-31.9 41.7-52.5 24.6L136 292.7V468c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12z\"]\n};\nvar faStepForward = {\n prefix: 'fas',\n iconName: 'step-forward',\n icon: [448, 512, [], \"f051\", \"M384 44v424c0 6.6-5.4 12-12 12h-48c-6.6 0-12-5.4-12-12V291.6l-195.5 181C95.9 489.7 64 475.4 64 448V64c0-27.4 31.9-41.7 52.5-24.6L312 219.3V44c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12z\"]\n};\nvar faStethoscope = {\n prefix: 'fas',\n iconName: 'stethoscope',\n icon: [512, 512, [], \"f0f1\", \"M447.1 112c-34.2.5-62.3 28.4-63 62.6-.5 24.3 12.5 45.6 32 56.8V344c0 57.3-50.2 104-112 104-60 0-109.2-44.1-111.9-99.2C265 333.8 320 269.2 320 192V36.6c0-11.4-8.1-21.3-19.3-23.5L237.8.5c-13-2.6-25.6 5.8-28.2 18.8L206.4 35c-2.6 13 5.8 25.6 18.8 28.2l30.7 6.1v121.4c0 52.9-42.2 96.7-95.1 97.2-53.4.5-96.9-42.7-96.9-96V69.4l30.7-6.1c13-2.6 21.4-15.2 18.8-28.2l-3.1-15.7C107.7 6.4 95.1-2 82.1.6L19.3 13C8.1 15.3 0 25.1 0 36.6V192c0 77.3 55.1 142 128.1 156.8C130.7 439.2 208.6 512 304 512c97 0 176-75.4 176-168V231.4c19.1-11.1 32-31.7 32-55.4 0-35.7-29.2-64.5-64.9-64zm.9 80c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16z\"]\n};\nvar faStickyNote = {\n prefix: 'fas',\n iconName: 'sticky-note',\n icon: [448, 512, [], \"f249\", \"M312 320h136V56c0-13.3-10.7-24-24-24H24C10.7 32 0 42.7 0 56v400c0 13.3 10.7 24 24 24h264V344c0-13.2 10.8-24 24-24zm129 55l-98 98c-4.5 4.5-10.6 7-17 7h-6V352h128v6.1c0 6.3-2.5 12.4-7 16.9z\"]\n};\nvar faStop = {\n prefix: 'fas',\n iconName: 'stop',\n icon: [448, 512, [], \"f04d\", \"M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z\"]\n};\nvar faStopCircle = {\n prefix: 'fas',\n iconName: 'stop-circle',\n icon: [512, 512, [], \"f28d\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm96 328c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16v160z\"]\n};\nvar faStopwatch = {\n prefix: 'fas',\n iconName: 'stopwatch',\n icon: [448, 512, [], \"f2f2\", \"M432 304c0 114.9-93.1 208-208 208S16 418.9 16 304c0-104 76.3-190.2 176-205.5V64h-28c-6.6 0-12-5.4-12-12V12c0-6.6 5.4-12 12-12h120c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-28v34.5c37.5 5.8 71.7 21.6 99.7 44.6l27.5-27.5c4.7-4.7 12.3-4.7 17 0l28.3 28.3c4.7 4.7 4.7 12.3 0 17l-29.4 29.4-.6.6C419.7 223.3 432 262.2 432 304zm-176 36V188.5c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12V340c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12z\"]\n};\nvar faStore = {\n prefix: 'fas',\n iconName: 'store',\n icon: [616, 512, [], \"f54e\", \"M602 118.6L537.1 15C531.3 5.7 521 0 510 0H106C95 0 84.7 5.7 78.9 15L14 118.6c-33.5 53.5-3.8 127.9 58.8 136.4 4.5.6 9.1.9 13.7.9 29.6 0 55.8-13 73.8-33.1 18 20.1 44.3 33.1 73.8 33.1 29.6 0 55.8-13 73.8-33.1 18 20.1 44.3 33.1 73.8 33.1 29.6 0 55.8-13 73.8-33.1 18.1 20.1 44.3 33.1 73.8 33.1 4.7 0 9.2-.3 13.7-.9 62.8-8.4 92.6-82.8 59-136.4zM529.5 288c-10 0-19.9-1.5-29.5-3.8V384H116v-99.8c-9.6 2.2-19.5 3.8-29.5 3.8-6 0-12.1-.4-18-1.2-5.6-.8-11.1-2.1-16.4-3.6V480c0 17.7 14.3 32 32 32h448c17.7 0 32-14.3 32-32V283.2c-5.4 1.6-10.8 2.9-16.4 3.6-6.1.8-12.1 1.2-18.2 1.2z\"]\n};\nvar faStoreAlt = {\n prefix: 'fas',\n iconName: 'store-alt',\n icon: [640, 512, [], \"f54f\", \"M320 384H128V224H64v256c0 17.7 14.3 32 32 32h256c17.7 0 32-14.3 32-32V224h-64v160zm314.6-241.8l-85.3-128c-6-8.9-16-14.2-26.7-14.2H117.4c-10.7 0-20.7 5.3-26.6 14.2l-85.3 128c-14.2 21.3 1 49.8 26.6 49.8H608c25.5 0 40.7-28.5 26.6-49.8zM512 496c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V224h-64v272z\"]\n};\nvar faStream = {\n prefix: 'fas',\n iconName: 'stream',\n icon: [512, 512, [], \"f550\", \"M16 128h416c8.84 0 16-7.16 16-16V48c0-8.84-7.16-16-16-16H16C7.16 32 0 39.16 0 48v64c0 8.84 7.16 16 16 16zm480 80H80c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16zm-64 176H16c-8.84 0-16 7.16-16 16v64c0 8.84 7.16 16 16 16h416c8.84 0 16-7.16 16-16v-64c0-8.84-7.16-16-16-16z\"]\n};\nvar faStreetView = {\n prefix: 'fas',\n iconName: 'street-view',\n icon: [512, 512, [], \"f21d\", \"M367.9 329.76c-4.62 5.3-9.78 10.1-15.9 13.65v22.94c66.52 9.34 112 28.05 112 49.65 0 30.93-93.12 56-208 56S48 446.93 48 416c0-21.6 45.48-40.3 112-49.65v-22.94c-6.12-3.55-11.28-8.35-15.9-13.65C58.87 345.34 0 378.05 0 416c0 53.02 114.62 96 256 96s256-42.98 256-96c0-37.95-58.87-70.66-144.1-86.24zM256 128c35.35 0 64-28.65 64-64S291.35 0 256 0s-64 28.65-64 64 28.65 64 64 64zm-64 192v96c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-96c17.67 0 32-14.33 32-32v-96c0-26.51-21.49-48-48-48h-11.8c-11.07 5.03-23.26 8-36.2 8s-25.13-2.97-36.2-8H208c-26.51 0-48 21.49-48 48v96c0 17.67 14.33 32 32 32z\"]\n};\nvar faStrikethrough = {\n prefix: 'fas',\n iconName: 'strikethrough',\n icon: [512, 512, [], \"f0cc\", \"M496 288H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h480c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16zm-214.666 16c27.258 12.937 46.524 28.683 46.524 56.243 0 33.108-28.977 53.676-75.621 53.676-32.325 0-76.874-12.08-76.874-44.271V368c0-8.837-7.164-16-16-16H113.75c-8.836 0-16 7.163-16 16v19.204c0 66.845 77.717 101.82 154.487 101.82 88.578 0 162.013-45.438 162.013-134.424 0-19.815-3.618-36.417-10.143-50.6H281.334zm-30.952-96c-32.422-13.505-56.836-28.946-56.836-59.683 0-33.92 30.901-47.406 64.962-47.406 42.647 0 64.962 16.593 64.962 32.985V136c0 8.837 7.164 16 16 16h45.613c8.836 0 16-7.163 16-16v-30.318c0-52.438-71.725-79.875-142.575-79.875-85.203 0-150.726 40.972-150.726 125.646 0 22.71 4.665 41.176 12.777 56.547h129.823z\"]\n};\nvar faStroopwafel = {\n prefix: 'fas',\n iconName: 'stroopwafel',\n icon: [512, 512, [], \"f551\", \"M188.12 210.74L142.86 256l45.25 45.25L233.37 256l-45.25-45.26zm113.13-22.62L256 142.86l-45.25 45.25L256 233.37l45.25-45.25zm-90.5 135.76L256 369.14l45.26-45.26L256 278.63l-45.25 45.25zM256 0C114.62 0 0 114.62 0 256s114.62 256 256 256 256-114.62 256-256S397.38 0 256 0zm186.68 295.6l-11.31 11.31c-3.12 3.12-8.19 3.12-11.31 0l-28.29-28.29-45.25 45.25 33.94 33.94 16.97-16.97c3.12-3.12 8.19-3.12 11.31 0l11.31 11.31c3.12 3.12 3.12 8.19 0 11.31l-16.97 16.97 16.97 16.97c3.12 3.12 3.12 8.19 0 11.31l-11.31 11.31c-3.12 3.12-8.19 3.12-11.31 0l-16.97-16.97-16.97 16.97c-3.12 3.12-8.19 3.12-11.31 0l-11.31-11.31c-3.12-3.12-3.12-8.19 0-11.31l16.97-16.97-33.94-33.94-45.26 45.26 28.29 28.29c3.12 3.12 3.12 8.19 0 11.31l-11.31 11.31c-3.12 3.12-8.19 3.12-11.31 0L256 414.39l-28.29 28.29c-3.12 3.12-8.19 3.12-11.31 0l-11.31-11.31c-3.12-3.12-3.12-8.19 0-11.31l28.29-28.29-45.25-45.26-33.94 33.94 16.97 16.97c3.12 3.12 3.12 8.19 0 11.31l-11.31 11.31c-3.12 3.12-8.19 3.12-11.31 0l-16.97-16.97-16.97 16.97c-3.12 3.12-8.19 3.12-11.31 0l-11.31-11.31c-3.12-3.12-3.12-8.19 0-11.31l16.97-16.97-16.97-16.97c-3.12-3.12-3.12-8.19 0-11.31l11.31-11.31c3.12-3.12 8.19-3.12 11.31 0l16.97 16.97 33.94-33.94-45.25-45.25-28.29 28.29c-3.12 3.12-8.19 3.12-11.31 0L69.32 295.6c-3.12-3.12-3.12-8.19 0-11.31L97.61 256l-28.29-28.29c-3.12-3.12-3.12-8.19 0-11.31l11.31-11.31c3.12-3.12 8.19-3.12 11.31 0l28.29 28.29 45.25-45.26-33.94-33.94-16.97 16.97c-3.12 3.12-8.19 3.12-11.31 0l-11.31-11.31c-3.12-3.12-3.12-8.19 0-11.31l16.97-16.97-16.97-16.97c-3.12-3.12-3.12-8.19 0-11.31l11.31-11.31c3.12-3.12 8.19-3.12 11.31 0l16.97 16.97 16.97-16.97c3.12-3.12 8.19-3.12 11.31 0l11.31 11.31c3.12 3.12 3.12 8.19 0 11.31l-16.97 16.97 33.94 33.94 45.26-45.25-28.29-28.29c-3.12-3.12-3.12-8.19 0-11.31l11.31-11.31c3.12-3.12 8.19-3.12 11.31 0L256 97.61l28.29-28.29c3.12-3.12 8.19-3.12 11.31 0l11.31 11.31c3.12 3.12 3.12 8.19 0 11.31l-28.29 28.29 45.26 45.25 33.94-33.94-16.97-16.97c-3.12-3.12-3.12-8.19 0-11.31l11.31-11.31c3.12-3.12 8.19-3.12 11.31 0l16.97 16.97 16.97-16.97c3.12-3.12 8.19-3.12 11.31 0l11.31 11.31c3.12 3.12 3.12 8.19 0 11.31l-16.97 16.97 16.97 16.97c3.12 3.12 3.12 8.19 0 11.31l-11.31 11.31c-3.12 3.12-8.19 3.12-11.31 0l-16.97-16.97-33.94 33.94 45.25 45.26 28.29-28.29c3.12-3.12 8.19-3.12 11.31 0l11.31 11.31c3.12 3.12 3.12 8.19 0 11.31L414.39 256l28.29 28.28a8.015 8.015 0 0 1 0 11.32zM278.63 256l45.26 45.25L369.14 256l-45.25-45.26L278.63 256z\"]\n};\nvar faSubscript = {\n prefix: 'fas',\n iconName: 'subscript',\n icon: [512, 512, [], \"f12c\", \"M272 32h-67.8c-5.5 0-10.7 2.9-13.6 7.6l-40.3 65c-2.3 3.6-4.5 7.3-6.2 10.5-1.7-3.2-3.7-6.8-5.7-10.4L98.5 39.6c-2.9-4.7-8.1-7.6-13.6-7.6H16C7.2 32 0 39.2 0 48v32c0 8.8 7.2 16 16 16h30.1l52.8 77.3L42.3 256H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h64c5.5 0 10.7-2.9 13.6-7.6l44.7-72.1c2.2-3.6 4.2-7.3 5.9-10.6 1.8 3.2 3.9 6.9 6.2 10.2l45.7 72.6c2.9 4.7 8 7.5 13.5 7.5H272c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16h-22l-58.6-84.3L244 96h28c8.8 0 16-7.2 16-16V48c0-8.8-7.2-16-16-16zm224 384H395.2c3.5-10.5 18.8-21.3 36.3-32.4 16.6-10.6 35.5-22.6 50.3-38.9 17.5-19.1 25.9-40.2 25.9-64.6 0-60.6-50.7-88.1-97.8-88.1-42.5 0-76.4 22-94.4 50.4-4.7 7.3-2.6 17 4.6 21.9l30.3 20.3c7 4.7 16.5 3.1 21.6-3.6 8-10.4 18.8-18.2 31.7-18.2 19.4 0 26.3 12.9 26.3 23.9 0 36.2-119.4 57-119.4 160 0 6.7.6 13 1.4 19.3 1.1 8 7.8 13.9 15.9 13.9H496c8.8 0 16-7.2 16-16v-32c0-8.7-7.2-15.9-16-15.9z\"]\n};\nvar faSubway = {\n prefix: 'fas',\n iconName: 'subway',\n icon: [448, 512, [], \"f239\", \"M448 96v256c0 51.815-61.624 96-130.022 96l62.98 49.721C386.905 502.417 383.562 512 376 512H72c-7.578 0-10.892-9.594-4.957-14.279L130.022 448C61.82 448 0 403.954 0 352V96C0 42.981 64 0 128 0h192c65 0 128 42.981 128 96zM200 232V120c0-13.255-10.745-24-24-24H72c-13.255 0-24 10.745-24 24v112c0 13.255 10.745 24 24 24h104c13.255 0 24-10.745 24-24zm200 0V120c0-13.255-10.745-24-24-24H272c-13.255 0-24 10.745-24 24v112c0 13.255 10.745 24 24 24h104c13.255 0 24-10.745 24-24zm-48 56c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm-256 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z\"]\n};\nvar faSuitcase = {\n prefix: 'fas',\n iconName: 'suitcase',\n icon: [512, 512, [], \"f0f2\", \"M128 480h256V80c0-26.5-21.5-48-48-48H176c-26.5 0-48 21.5-48 48v400zm64-384h128v32H192V96zm320 80v256c0 26.5-21.5 48-48 48h-48V128h48c26.5 0 48 21.5 48 48zM96 480H48c-26.5 0-48-21.5-48-48V176c0-26.5 21.5-48 48-48h48v352z\"]\n};\nvar faSuitcaseRolling = {\n prefix: 'fas',\n iconName: 'suitcase-rolling',\n icon: [384, 512, [], \"f5c1\", \"M336 160H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h16v16c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-16h128v16c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-16h16c26.51 0 48-21.49 48-48V208c0-26.51-21.49-48-48-48zm-16 216c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h240c4.42 0 8 3.58 8 8v16zm0-96c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16c0-4.42 3.58-8 8-8h240c4.42 0 8 3.58 8 8v16zM144 48h96v80h48V48c0-26.51-21.49-48-48-48h-96c-26.51 0-48 21.49-48 48v80h48V48z\"]\n};\nvar faSun = {\n prefix: 'fas',\n iconName: 'sun',\n icon: [512, 512, [], \"f185\", \"M256 160c-52.9 0-96 43.1-96 96s43.1 96 96 96 96-43.1 96-96-43.1-96-96-96zm246.4 80.5l-94.7-47.3 33.5-100.4c4.5-13.6-8.4-26.5-21.9-21.9l-100.4 33.5-47.4-94.8c-6.4-12.8-24.6-12.8-31 0l-47.3 94.7L92.7 70.8c-13.6-4.5-26.5 8.4-21.9 21.9l33.5 100.4-94.7 47.4c-12.8 6.4-12.8 24.6 0 31l94.7 47.3-33.5 100.5c-4.5 13.6 8.4 26.5 21.9 21.9l100.4-33.5 47.3 94.7c6.4 12.8 24.6 12.8 31 0l47.3-94.7 100.4 33.5c13.6 4.5 26.5-8.4 21.9-21.9l-33.5-100.4 94.7-47.3c13-6.5 13-24.7.2-31.1zm-155.9 106c-49.9 49.9-131.1 49.9-181 0-49.9-49.9-49.9-131.1 0-181 49.9-49.9 131.1-49.9 181 0 49.9 49.9 49.9 131.1 0 181z\"]\n};\nvar faSuperscript = {\n prefix: 'fas',\n iconName: 'superscript',\n icon: [512, 512, [], \"f12b\", \"M272 192h-67.8c-5.5 0-10.7 2.9-13.6 7.6l-40.3 65c-2.3 3.6-4.5 7.3-6.2 10.5-1.7-3.2-3.7-6.8-5.7-10.4l-39.9-65.1c-2.9-4.7-8.1-7.6-13.6-7.6H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h30.1l52.8 77.3L42.3 416H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h64c5.5 0 10.7-2.9 13.6-7.6l44.7-72.1c2.2-3.6 4.2-7.3 5.9-10.6 1.8 3.2 3.9 6.9 6.2 10.2l45.7 72.6c2.9 4.7 8 7.5 13.5 7.5H272c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16h-22l-58.6-84.3L244 256h28c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm224 64H395.2c3.5-10.5 18.8-21.3 36.3-32.4 16.6-10.6 35.5-22.6 50.3-38.9 17.5-19.1 25.9-40.2 25.9-64.6 0-60.6-50.7-88.1-97.8-88.1-42.5 0-76.4 22-94.4 50.4-4.7 7.3-2.6 17 4.6 21.9l30.3 20.3c7 4.7 16.5 3.1 21.6-3.6 8-10.4 18.8-18.2 31.7-18.2 19.4 0 26.3 12.9 26.3 23.9 0 36.2-119.4 57-119.4 160 0 6.7.6 13 1.4 19.3 1.1 8 7.8 13.9 15.9 13.9H496c8.8 0 16-7.2 16-16v-32c0-8.7-7.2-15.9-16-15.9z\"]\n};\nvar faSurprise = {\n prefix: 'fas',\n iconName: 'surprise',\n icon: [496, 512, [], \"f5c2\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zM136 208c0-17.7 14.3-32 32-32s32 14.3 32 32-14.3 32-32 32-32-14.3-32-32zm112 208c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64zm80-176c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faSwatchbook = {\n prefix: 'fas',\n iconName: 'swatchbook',\n icon: [511, 512, [], \"f5c3\", \"M479.06 320H372.29L186.15 506.51c-2.06 2.07-4.49 3.58-6.67 5.49h299.58c17.64 0 31.94-14.33 31.94-32V352c0-17.67-14.3-32-31.94-32zm-44.5-152.9l-90.33-90.51c-12.47-12.5-32.69-12.5-45.17 0l-75.5 75.65V416c0 2.96-.67 5.73-.87 8.64l211.87-212.28c12.47-12.5 12.47-32.77 0-45.26zM191.62 32c0-17.67-14.3-32-31.94-32H31.94C14.3 0 0 14.33 0 32v384c0 53.02 42.9 96 95.81 96s95.81-42.98 95.81-96V32zM95.81 440c-13.23 0-23.95-10.75-23.95-24 0-13.26 10.73-24 23.95-24s23.95 10.74 23.95 24c.01 13.25-10.72 24-23.95 24zm31.94-184H63.88v-64h63.88v64zm0-128H63.88V64h63.88v64z\"]\n};\nvar faSwimmer = {\n prefix: 'fas',\n iconName: 'swimmer',\n icon: [640, 512, [], \"f5c4\", \"M189.61 310.58c3.54 3.26 15.27 9.42 34.39 9.42s30.86-6.16 34.39-9.42c16.02-14.77 34.5-22.58 53.46-22.58h16.3c18.96 0 37.45 7.81 53.46 22.58 3.54 3.26 15.27 9.42 34.39 9.42s30.86-6.16 34.39-9.42c14.86-13.71 31.88-21.12 49.39-22.16l-112.84-80.6 18-12.86c3.64-2.58 8.28-3.52 12.62-2.61l100.35 21.53c25.91 5.53 51.44-10.97 57-36.88 5.55-25.92-10.95-51.44-36.88-57L437.68 98.47c-30.73-6.58-63.02.12-88.56 18.38l-80.02 57.17c-10.38 7.39-19.36 16.44-26.72 26.94L173.75 299c5.47 3.23 10.82 6.93 15.86 11.58zM624 352h-16c-26.04 0-45.8-8.42-56.09-17.9-8.9-8.21-19.66-14.1-31.77-14.1h-16.3c-12.11 0-22.87 5.89-31.77 14.1C461.8 343.58 442.04 352 416 352s-45.8-8.42-56.09-17.9c-8.9-8.21-19.66-14.1-31.77-14.1h-16.3c-12.11 0-22.87 5.89-31.77 14.1C269.8 343.58 250.04 352 224 352s-45.8-8.42-56.09-17.9c-8.9-8.21-19.66-14.1-31.77-14.1h-16.3c-12.11 0-22.87 5.89-31.77 14.1C77.8 343.58 58.04 352 32 352H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h16c38.62 0 72.72-12.19 96-31.84 23.28 19.66 57.38 31.84 96 31.84s72.72-12.19 96-31.84c23.28 19.66 57.38 31.84 96 31.84s72.72-12.19 96-31.84c23.28 19.66 57.38 31.84 96 31.84h16c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm-512-96c44.18 0 80-35.82 80-80s-35.82-80-80-80-80 35.82-80 80 35.82 80 80 80z\"]\n};\nvar faSwimmingPool = {\n prefix: 'fas',\n iconName: 'swimming-pool',\n icon: [640, 512, [], \"f5c5\", \"M624 416h-16c-26.04 0-45.8-8.42-56.09-17.9-8.9-8.21-19.66-14.1-31.77-14.1h-16.3c-12.11 0-22.87 5.89-31.77 14.1C461.8 407.58 442.04 416 416 416s-45.8-8.42-56.09-17.9c-8.9-8.21-19.66-14.1-31.77-14.1h-16.3c-12.11 0-22.87 5.89-31.77 14.1C269.8 407.58 250.04 416 224 416s-45.8-8.42-56.09-17.9c-8.9-8.21-19.66-14.1-31.77-14.1h-16.3c-12.11 0-22.87 5.89-31.77 14.1C77.8 407.58 58.04 416 32 416H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h16c38.62 0 72.72-12.19 96-31.84 23.28 19.66 57.38 31.84 96 31.84s72.72-12.19 96-31.84c23.28 19.66 57.38 31.84 96 31.84s72.72-12.19 96-31.84c23.28 19.66 57.38 31.84 96 31.84h16c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm-400-32v-96h192v96c19.12 0 30.86-6.16 34.39-9.42 9.17-8.46 19.2-14.34 29.61-18.07V128c0-17.64 14.36-32 32-32s32 14.36 32 32v16c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-16c0-52.94-43.06-96-96-96s-96 43.06-96 96v96H224v-96c0-17.64 14.36-32 32-32s32 14.36 32 32v16c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-16c0-52.94-43.06-96-96-96s-96 43.06-96 96v228.5c10.41 3.73 20.44 9.62 29.61 18.07 3.53 3.27 15.27 9.43 34.39 9.43z\"]\n};\nvar faSynagogue = {\n prefix: 'fas',\n iconName: 'synagogue',\n icon: [640, 512, [], \"f69b\", \"M70 196.51L6.67 268.29A26.643 26.643 0 0 0 0 285.93V512h128V239.58l-38-43.07c-5.31-6.01-14.69-6.01-20 0zm563.33 71.78L570 196.51c-5.31-6.02-14.69-6.02-20 0l-38 43.07V512h128V285.93c0-6.5-2.37-12.77-6.67-17.64zM339.99 7.01c-11.69-9.35-28.29-9.35-39.98 0l-128 102.4A32.005 32.005 0 0 0 160 134.4V512h96v-92.57c0-31.88 21.78-61.43 53.25-66.55C349.34 346.35 384 377.13 384 416v96h96V134.4c0-9.72-4.42-18.92-12.01-24.99l-128-102.4zm52.07 215.55c1.98 3.15-.29 7.24-4 7.24h-38.94L324 269.79c-1.85 2.95-6.15 2.95-8 0l-25.12-39.98h-38.94c-3.72 0-5.98-4.09-4-7.24l19.2-30.56-19.2-30.56c-1.98-3.15.29-7.24 4-7.24h38.94l25.12-40c1.85-2.95 6.15-2.95 8 0l25.12 39.98h38.95c3.71 0 5.98 4.09 4 7.24L372.87 192l19.19 30.56z\"]\n};\nvar faSync = {\n prefix: 'fas',\n iconName: 'sync',\n icon: [512, 512, [], \"f021\", \"M440.935 12.574l3.966 82.766C399.416 41.904 331.674 8 256 8 134.813 8 33.933 94.924 12.296 209.824 10.908 217.193 16.604 224 24.103 224h49.084c5.57 0 10.377-3.842 11.676-9.259C103.407 137.408 172.931 80 256 80c60.893 0 114.512 30.856 146.104 77.801l-101.53-4.865c-6.845-.328-12.574 5.133-12.574 11.986v47.411c0 6.627 5.373 12 12 12h200.333c6.627 0 12-5.373 12-12V12c0-6.627-5.373-12-12-12h-47.411c-6.853 0-12.315 5.729-11.987 12.574zM256 432c-60.895 0-114.517-30.858-146.109-77.805l101.868 4.871c6.845.327 12.573-5.134 12.573-11.986v-47.412c0-6.627-5.373-12-12-12H12c-6.627 0-12 5.373-12 12V500c0 6.627 5.373 12 12 12h47.385c6.863 0 12.328-5.745 11.985-12.599l-4.129-82.575C112.725 470.166 180.405 504 256 504c121.187 0 222.067-86.924 243.704-201.824 1.388-7.369-4.308-14.176-11.807-14.176h-49.084c-5.57 0-10.377 3.842-11.676 9.259C408.593 374.592 339.069 432 256 432z\"]\n};\nvar faSyncAlt = {\n prefix: 'fas',\n iconName: 'sync-alt',\n icon: [512, 512, [], \"f2f1\", \"M370.72 133.28C339.458 104.008 298.888 87.962 255.848 88c-77.458.068-144.328 53.178-162.791 126.85-1.344 5.363-6.122 9.15-11.651 9.15H24.103c-7.498 0-13.194-6.807-11.807-14.176C33.933 94.924 134.813 8 256 8c66.448 0 126.791 26.136 171.315 68.685L463.03 40.97C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.749zM32 296h134.059c21.382 0 32.09 25.851 16.971 40.971l-41.75 41.75c31.262 29.273 71.835 45.319 114.876 45.28 77.418-.07 144.315-53.144 162.787-126.849 1.344-5.363 6.122-9.15 11.651-9.15h57.304c7.498 0 13.194 6.807 11.807 14.176C478.067 417.076 377.187 504 256 504c-66.448 0-126.791-26.136-171.315-68.685L48.97 471.03C33.851 486.149 8 475.441 8 454.059V320c0-13.255 10.745-24 24-24z\"]\n};\nvar faSyringe = {\n prefix: 'fas',\n iconName: 'syringe',\n icon: [512, 512, [], \"f48e\", \"M201.5 174.8l55.7 55.8c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0l-55.7-55.8-45.3 45.3 55.8 55.8c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0L111 265.2l-26.4 26.4c-17.3 17.3-25.6 41.1-23 65.4l7.1 63.6L2.3 487c-3.1 3.1-3.1 8.2 0 11.3l11.3 11.3c3.1 3.1 8.2 3.1 11.3 0l66.3-66.3 63.6 7.1c23.9 2.6 47.9-5.4 65.4-23l181.9-181.9-135.7-135.7-64.9 65zm308.2-93.3L430.5 2.3c-3.1-3.1-8.2-3.1-11.3 0l-11.3 11.3c-3.1 3.1-3.1 8.2 0 11.3l28.3 28.3-45.3 45.3-56.6-56.6-17-17c-3.1-3.1-8.2-3.1-11.3 0l-33.9 33.9c-3.1 3.1-3.1 8.2 0 11.3l17 17L424.8 223l17 17c3.1 3.1 8.2 3.1 11.3 0l33.9-34c3.1-3.1 3.1-8.2 0-11.3l-73.5-73.5 45.3-45.3 28.3 28.3c3.1 3.1 8.2 3.1 11.3 0l11.3-11.3c3.1-3.2 3.1-8.2 0-11.4z\"]\n};\nvar faTable = {\n prefix: 'fas',\n iconName: 'table',\n icon: [512, 512, [], \"f0ce\", \"M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM224 416H64v-96h160v96zm0-160H64v-96h160v96zm224 160H288v-96h160v96zm0-160H288v-96h160v96z\"]\n};\nvar faTableTennis = {\n prefix: 'fas',\n iconName: 'table-tennis',\n icon: [512, 512, [], \"f45d\", \"M496.2 296.5C527.7 218.7 512 126.2 449 63.1 365.1-21 229-21 145.1 63.1l-56 56.1 211.5 211.5c46.1-62.1 131.5-77.4 195.6-34.2zm-217.9 79.7L57.9 155.9c-27.3 45.3-21.7 105 17.3 144.1l34.5 34.6L6.7 424c-8.6 7.5-9.1 20.7-1 28.8l53.4 53.5c8 8.1 21.2 7.6 28.7-1L177.1 402l35.7 35.7c19.7 19.7 44.6 30.5 70.3 33.3-7.1-17-11-35.6-11-55.1-.1-13.8 2.5-27 6.2-39.7zM416 320c-53 0-96 43-96 96s43 96 96 96 96-43 96-96-43-96-96-96z\"]\n};\nvar faTablet = {\n prefix: 'fas',\n iconName: 'tablet',\n icon: [448, 512, [], \"f10a\", \"M400 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM224 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z\"]\n};\nvar faTabletAlt = {\n prefix: 'fas',\n iconName: 'tablet-alt',\n icon: [448, 512, [], \"f3fa\", \"M400 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM224 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm176-108c0 6.6-5.4 12-12 12H60c-6.6 0-12-5.4-12-12V60c0-6.6 5.4-12 12-12h328c6.6 0 12 5.4 12 12v312z\"]\n};\nvar faTablets = {\n prefix: 'fas',\n iconName: 'tablets',\n icon: [640, 512, [], \"f490\", \"M160 192C78.9 192 12.5 250.5.1 326.7c-.8 4.8 3.3 9.3 8.3 9.3h303.3c5 0 9.1-4.5 8.3-9.3C307.5 250.5 241.1 192 160 192zm151.6 176H8.4c-5 0-9.1 4.5-8.3 9.3C12.5 453.5 78.9 512 160 512s147.5-58.5 159.9-134.7c.8-4.8-3.3-9.3-8.3-9.3zM593.4 46.6c-56.5-56.5-144.2-61.4-206.9-16-4 2.9-4.3 8.9-.8 12.3L597 254.3c3.5 3.5 9.5 3.2 12.3-.8 45.5-62.7 40.6-150.4-15.9-206.9zM363 65.7c-3.5-3.5-9.5-3.2-12.3.8-45.4 62.7-40.5 150.4 15.9 206.9 56.5 56.5 144.2 61.4 206.9 15.9 4-2.9 4.3-8.9.8-12.3L363 65.7z\"]\n};\nvar faTachometerAlt = {\n prefix: 'fas',\n iconName: 'tachometer-alt',\n icon: [576, 512, [], \"f3fd\", \"M288 32C128.94 32 0 160.94 0 320c0 52.8 14.25 102.26 39.06 144.8 5.61 9.62 16.3 15.2 27.44 15.2h443c11.14 0 21.83-5.58 27.44-15.2C561.75 422.26 576 372.8 576 320c0-159.06-128.94-288-288-288zm0 64c14.71 0 26.58 10.13 30.32 23.65-1.11 2.26-2.64 4.23-3.45 6.67l-9.22 27.67c-5.13 3.49-10.97 6.01-17.64 6.01-17.67 0-32-14.33-32-32S270.33 96 288 96zM96 384c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm48-160c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm246.77-72.41l-61.33 184C343.13 347.33 352 364.54 352 384c0 11.72-3.38 22.55-8.88 32H232.88c-5.5-9.45-8.88-20.28-8.88-32 0-33.94 26.5-61.43 59.9-63.59l61.34-184.01c4.17-12.56 17.73-19.45 30.36-15.17 12.57 4.19 19.35 17.79 15.17 30.36zm14.66 57.2l15.52-46.55c3.47-1.29 7.13-2.23 11.05-2.23 17.67 0 32 14.33 32 32s-14.33 32-32 32c-11.38-.01-20.89-6.28-26.57-15.22zM480 384c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faTag = {\n prefix: 'fas',\n iconName: 'tag',\n icon: [512, 512, [], \"f02b\", \"M0 252.118V48C0 21.49 21.49 0 48 0h204.118a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882L293.823 497.941c-18.745 18.745-49.137 18.745-67.882 0L14.059 286.059A48 48 0 0 1 0 252.118zM112 64c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z\"]\n};\nvar faTags = {\n prefix: 'fas',\n iconName: 'tags',\n icon: [640, 512, [], \"f02c\", \"M497.941 225.941L286.059 14.059A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v204.118a48 48 0 0 0 14.059 33.941l211.882 211.882c18.744 18.745 49.136 18.746 67.882 0l204.118-204.118c18.745-18.745 18.745-49.137 0-67.882zM112 160c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm513.941 133.823L421.823 497.941c-18.745 18.745-49.137 18.745-67.882 0l-.36-.36L527.64 323.522c16.999-16.999 26.36-39.6 26.36-63.64s-9.362-46.641-26.36-63.64L331.397 0h48.721a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882z\"]\n};\nvar faTape = {\n prefix: 'fas',\n iconName: 'tape',\n icon: [640, 512, [], \"f4db\", \"M224 192c-35.3 0-64 28.7-64 64s28.7 64 64 64 64-28.7 64-64-28.7-64-64-64zm400 224H380.6c41.5-40.7 67.4-97.3 67.4-160 0-123.7-100.3-224-224-224S0 132.3 0 256s100.3 224 224 224h400c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm-400-64c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96z\"]\n};\nvar faTasks = {\n prefix: 'fas',\n iconName: 'tasks',\n icon: [512, 512, [], \"f0ae\", \"M208 132h288c8.8 0 16-7.2 16-16V76c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16v40c0 8.8 7.2 16 16 16zm0 160h288c8.8 0 16-7.2 16-16v-40c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16v40c0 8.8 7.2 16 16 16zm0 160h288c8.8 0 16-7.2 16-16v-40c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16v40c0 8.8 7.2 16 16 16zM64 368c-26.5 0-48.6 21.5-48.6 48s22.1 48 48.6 48 48-21.5 48-48-21.5-48-48-48zm92.5-299l-72.2 72.2-15.6 15.6c-4.7 4.7-12.9 4.7-17.6 0L3.5 109.4c-4.7-4.7-4.7-12.3 0-17l15.7-15.7c4.7-4.7 12.3-4.7 17 0l22.7 22.1 63.7-63.3c4.7-4.7 12.3-4.7 17 0l17 16.5c4.6 4.7 4.6 12.3-.1 17zm0 159.6l-72.2 72.2-15.7 15.7c-4.7 4.7-12.9 4.7-17.6 0L3.5 269c-4.7-4.7-4.7-12.3 0-17l15.7-15.7c4.7-4.7 12.3-4.7 17 0l22.7 22.1 63.7-63.7c4.7-4.7 12.3-4.7 17 0l17 17c4.6 4.6 4.6 12.2-.1 16.9z\"]\n};\nvar faTaxi = {\n prefix: 'fas',\n iconName: 'taxi',\n icon: [512, 512, [], \"f1ba\", \"M462 241.64l-22-84.84c-9.6-35.2-41.6-60.8-76.8-60.8H352V64c0-17.67-14.33-32-32-32H192c-17.67 0-32 14.33-32 32v32h-11.2c-35.2 0-67.2 25.6-76.8 60.8l-22 84.84C21.41 248.04 0 273.47 0 304v48c0 23.63 12.95 44.04 32 55.12V448c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h256v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-40.88c19.05-11.09 32-31.5 32-55.12v-48c0-30.53-21.41-55.96-50-62.36zM96 352c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm20.55-112l17.2-66.36c2.23-8.16 9.59-13.64 15.06-13.64h214.4c5.47 0 12.83 5.48 14.85 12.86L395.45 240h-278.9zM416 352c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faTeeth = {\n prefix: 'fas',\n iconName: 'teeth',\n icon: [640, 512, [], \"f62e\", \"M544 0H96C42.98 0 0 42.98 0 96v320c0 53.02 42.98 96 96 96h448c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96zM160 368c0 26.51-21.49 48-48 48s-48-21.49-48-48v-64c0-8.84 7.16-16 16-16h64c8.84 0 16 7.16 16 16v64zm0-128c0 8.84-7.16 16-16 16H80c-8.84 0-16-7.16-16-16v-64c0-26.51 21.49-48 48-48s48 21.49 48 48v64zm144 120c0 30.93-25.07 56-56 56s-56-25.07-56-56v-56c0-8.84 7.16-16 16-16h80c8.84 0 16 7.16 16 16v56zm0-120c0 8.84-7.16 16-16 16h-80c-8.84 0-16-7.16-16-16v-88c0-30.93 25.07-56 56-56s56 25.07 56 56v88zm144 120c0 30.93-25.07 56-56 56s-56-25.07-56-56v-56c0-8.84 7.16-16 16-16h80c8.84 0 16 7.16 16 16v56zm0-120c0 8.84-7.16 16-16 16h-80c-8.84 0-16-7.16-16-16v-88c0-30.93 25.07-56 56-56s56 25.07 56 56v88zm128 128c0 26.51-21.49 48-48 48s-48-21.49-48-48v-64c0-8.84 7.16-16 16-16h64c8.84 0 16 7.16 16 16v64zm0-128c0 8.84-7.16 16-16 16h-64c-8.84 0-16-7.16-16-16v-64c0-26.51 21.49-48 48-48s48 21.49 48 48v64z\"]\n};\nvar faTeethOpen = {\n prefix: 'fas',\n iconName: 'teeth-open',\n icon: [640, 512, [], \"f62f\", \"M544 0H96C42.98 0 0 42.98 0 96v64c0 35.35 28.66 64 64 64h512c35.34 0 64-28.65 64-64V96c0-53.02-42.98-96-96-96zM160 176c0 8.84-7.16 16-16 16H80c-8.84 0-16-7.16-16-16v-32c0-26.51 21.49-48 48-48s48 21.49 48 48v32zm144 0c0 8.84-7.16 16-16 16h-80c-8.84 0-16-7.16-16-16v-56c0-30.93 25.07-56 56-56s56 25.07 56 56v56zm144 0c0 8.84-7.16 16-16 16h-80c-8.84 0-16-7.16-16-16v-56c0-30.93 25.07-56 56-56s56 25.07 56 56v56zm128 0c0 8.84-7.16 16-16 16h-64c-8.84 0-16-7.16-16-16v-32c0-26.51 21.49-48 48-48s48 21.49 48 48v32zm0 144H64c-35.34 0-64 28.65-64 64v32c0 53.02 42.98 96 96 96h448c53.02 0 96-42.98 96-96v-32c0-35.35-28.66-64-64-64zm-416 80c0 26.51-21.49 48-48 48s-48-21.49-48-48v-32c0-8.84 7.16-16 16-16h64c8.84 0 16 7.16 16 16v32zm144-8c0 30.93-25.07 56-56 56s-56-25.07-56-56v-24c0-8.84 7.16-16 16-16h80c8.84 0 16 7.16 16 16v24zm144 0c0 30.93-25.07 56-56 56s-56-25.07-56-56v-24c0-8.84 7.16-16 16-16h80c8.84 0 16 7.16 16 16v24zm128 8c0 26.51-21.49 48-48 48s-48-21.49-48-48v-32c0-8.84 7.16-16 16-16h64c8.84 0 16 7.16 16 16v32z\"]\n};\nvar faTemperatureHigh = {\n prefix: 'fas',\n iconName: 'temperature-high',\n icon: [512, 512, [], \"f769\", \"M416 0c-52.9 0-96 43.1-96 96s43.1 96 96 96 96-43.1 96-96-43.1-96-96-96zm0 128c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm-160-16C256 50.1 205.9 0 144 0S32 50.1 32 112v166.5C12.3 303.2 0 334 0 368c0 79.5 64.5 144 144 144s144-64.5 144-144c0-34-12.3-64.9-32-89.5V112zM144 448c-44.1 0-80-35.9-80-80 0-25.5 12.2-48.9 32-63.8V112c0-26.5 21.5-48 48-48s48 21.5 48 48v192.2c19.8 14.8 32 38.3 32 63.8 0 44.1-35.9 80-80 80zm16-125.1V112c0-8.8-7.2-16-16-16s-16 7.2-16 16v210.9c-18.6 6.6-32 24.2-32 45.1 0 26.5 21.5 48 48 48s48-21.5 48-48c0-20.9-13.4-38.5-32-45.1z\"]\n};\nvar faTemperatureLow = {\n prefix: 'fas',\n iconName: 'temperature-low',\n icon: [512, 512, [], \"f76b\", \"M416 0c-52.9 0-96 43.1-96 96s43.1 96 96 96 96-43.1 96-96-43.1-96-96-96zm0 128c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm-160-16C256 50.1 205.9 0 144 0S32 50.1 32 112v166.5C12.3 303.2 0 334 0 368c0 79.5 64.5 144 144 144s144-64.5 144-144c0-34-12.3-64.9-32-89.5V112zM144 448c-44.1 0-80-35.9-80-80 0-25.5 12.2-48.9 32-63.8V112c0-26.5 21.5-48 48-48s48 21.5 48 48v192.2c19.8 14.8 32 38.3 32 63.8 0 44.1-35.9 80-80 80zm16-125.1V304c0-8.8-7.2-16-16-16s-16 7.2-16 16v18.9c-18.6 6.6-32 24.2-32 45.1 0 26.5 21.5 48 48 48s48-21.5 48-48c0-20.9-13.4-38.5-32-45.1z\"]\n};\nvar faTenge = {\n prefix: 'fas',\n iconName: 'tenge',\n icon: [384, 512, [], \"f7d7\", \"M372 160H12c-6.6 0-12 5.4-12 12v56c0 6.6 5.4 12 12 12h140v228c0 6.6 5.4 12 12 12h56c6.6 0 12-5.4 12-12V240h140c6.6 0 12-5.4 12-12v-56c0-6.6-5.4-12-12-12zm0-128H12C5.4 32 0 37.4 0 44v56c0 6.6 5.4 12 12 12h360c6.6 0 12-5.4 12-12V44c0-6.6-5.4-12-12-12z\"]\n};\nvar faTerminal = {\n prefix: 'fas',\n iconName: 'terminal',\n icon: [640, 512, [], \"f120\", \"M257.981 272.971L63.638 467.314c-9.373 9.373-24.569 9.373-33.941 0L7.029 444.647c-9.357-9.357-9.375-24.522-.04-33.901L161.011 256 6.99 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L257.981 239.03c9.373 9.372 9.373 24.568 0 33.941zM640 456v-32c0-13.255-10.745-24-24-24H312c-13.255 0-24 10.745-24 24v32c0 13.255 10.745 24 24 24h304c13.255 0 24-10.745 24-24z\"]\n};\nvar faTextHeight = {\n prefix: 'fas',\n iconName: 'text-height',\n icon: [576, 512, [], \"f034\", \"M16 32h288c8.837 0 16 7.163 16 16v96c0 8.837-7.163 16-16 16h-35.496c-8.837 0-16-7.163-16-16V96h-54.761v320H232c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H88c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h34.257V96H67.496v48c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16V48c0-8.837 7.163-16 16-16zm475.308 4.685l79.995 80.001C581.309 126.693 574.297 144 559.99 144H512v224h48c15.639 0 20.635 17.991 11.313 27.314l-79.995 80.001c-6.247 6.247-16.381 6.245-22.626 0l-79.995-80.001C378.691 385.307 385.703 368 400.01 368H448V144h-48c-15.639 0-20.635-17.991-11.313-27.314l79.995-80.001c6.247-6.248 16.381-6.245 22.626 0z\"]\n};\nvar faTextWidth = {\n prefix: 'fas',\n iconName: 'text-width',\n icon: [448, 512, [], \"f035\", \"M16 32h416c8.837 0 16 7.163 16 16v96c0 8.837-7.163 16-16 16h-35.496c-8.837 0-16-7.163-16-16V96H261.743v128H296c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H152c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h34.257V96H67.496v48c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16V48c0-8.837 7.163-16 16-16zm427.315 340.682l-80.001-79.995C353.991 283.365 336 288.362 336 304v48H112v-47.99c0-14.307-17.307-21.319-27.314-11.313L4.685 372.692c-6.245 6.245-6.247 16.379 0 22.626l80.001 79.995C94.009 484.635 112 479.638 112 464v-48h224v47.99c0 14.307 17.307 21.319 27.314 11.313l80.001-79.995c6.245-6.245 6.248-16.379 0-22.626z\"]\n};\nvar faTh = {\n prefix: 'fas',\n iconName: 'th',\n icon: [512, 512, [], \"f00a\", \"M149.333 56v80c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24h101.333c13.255 0 24 10.745 24 24zm181.334 240v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h101.333c13.256 0 24.001-10.745 24.001-24zm32-240v80c0 13.255 10.745 24 24 24H488c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H386.667c-13.255 0-24 10.745-24 24zm-32 80V56c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h101.333c13.256 0 24.001-10.745 24.001-24zm-205.334 56H24c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24zM0 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zm386.667-56H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H386.667c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zm0 160H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H386.667c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zM181.333 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24z\"]\n};\nvar faThLarge = {\n prefix: 'fas',\n iconName: 'th-large',\n icon: [512, 512, [], \"f009\", \"M296 32h192c13.255 0 24 10.745 24 24v160c0 13.255-10.745 24-24 24H296c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24zm-80 0H24C10.745 32 0 42.745 0 56v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zM0 296v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zm296 184h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H296c-13.255 0-24 10.745-24 24v160c0 13.255 10.745 24 24 24z\"]\n};\nvar faThList = {\n prefix: 'fas',\n iconName: 'th-list',\n icon: [512, 512, [], \"f00b\", \"M149.333 216v80c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-80c0-13.255 10.745-24 24-24h101.333c13.255 0 24 10.745 24 24zM0 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zM125.333 32H24C10.745 32 0 42.745 0 56v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zm80 448H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zm-24-424v80c0 13.255 10.745 24 24 24H488c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24zm24 264H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24z\"]\n};\nvar faTheaterMasks = {\n prefix: 'fas',\n iconName: 'theater-masks',\n icon: [640, 512, [], \"f630\", \"M206.86 245.15c-35.88 10.45-59.95 41.2-57.53 74.1 11.4-12.72 28.81-23.7 49.9-30.92l7.63-43.18zM95.81 295L64.08 115.49c-.29-1.62.28-2.62.24-2.65 57.76-32.06 123.12-49.01 189.01-49.01 1.61 0 3.23.17 4.85.19 13.95-13.47 31.73-22.83 51.59-26 18.89-3.02 38.05-4.55 57.18-5.32-9.99-13.95-24.48-24.23-41.77-27C301.27 1.89 277.24 0 253.32 0 176.66 0 101.02 19.42 33.2 57.06 9.03 70.48-3.92 98.48 1.05 126.58l31.73 179.51c14.23 80.52 136.33 142.08 204.45 142.08 3.59 0 6.75-.46 10.01-.8-13.52-17.08-28.94-40.48-39.5-67.58-47.61-12.98-106.06-51.62-111.93-84.79zm97.55-137.46c-.73-4.12-2.23-7.87-4.07-11.4-8.25 8.91-20.67 15.75-35.32 18.32-14.65 2.58-28.67.4-39.48-5.17-.52 3.94-.64 7.98.09 12.1 3.84 21.7 24.58 36.19 46.34 32.37 21.75-3.82 36.28-24.52 32.44-46.22zM606.8 120.9c-88.98-49.38-191.43-67.41-291.98-51.35-27.31 4.36-49.08 26.26-54.04 54.36l-31.73 179.51c-15.39 87.05 95.28 196.27 158.31 207.35 63.03 11.09 204.47-53.79 219.86-140.84l31.73-179.51c4.97-28.11-7.98-56.11-32.15-69.52zm-273.24 96.8c3.84-21.7 24.58-36.19 46.34-32.36 21.76 3.83 36.28 24.52 32.45 46.22-.73 4.12-2.23 7.87-4.07 11.4-8.25-8.91-20.67-15.75-35.32-18.32-14.65-2.58-28.67-.4-39.48 5.17-.53-3.95-.65-7.99.08-12.11zm70.47 198.76c-55.68-9.79-93.52-59.27-89.04-112.9 20.6 25.54 56.21 46.17 99.49 53.78 43.28 7.61 83.82.37 111.93-16.6-14.18 51.94-66.71 85.51-122.38 75.72zm130.3-151.34c-8.25-8.91-20.68-15.75-35.33-18.32-14.65-2.58-28.67-.4-39.48 5.17-.52-3.94-.64-7.98.09-12.1 3.84-21.7 24.58-36.19 46.34-32.37 21.75 3.83 36.28 24.52 32.45 46.22-.73 4.13-2.23 7.88-4.07 11.4z\"]\n};\nvar faThermometer = {\n prefix: 'fas',\n iconName: 'thermometer',\n icon: [512, 512, [], \"f491\", \"M476.8 20.4c-37.5-30.7-95.5-26.3-131.9 10.2l-45.7 46 50.5 50.5c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0l-50.4-50.5-45.1 45.4 50.3 50.4c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0L209 167.4l-45.1 45.4L214 263c3.1 3.1 3.1 8.2 0 11.3l-11.3 11.3c-3.1 3.1-8.2 3.1-11.3 0l-50.1-50.2L96 281.1V382L7 471c-9.4 9.4-9.4 24.6 0 33.9 9.4 9.4 24.6 9.4 33.9 0l89-89h99.9L484 162.6c34.9-34.9 42.2-101.5-7.2-142.2z\"]\n};\nvar faThermometerEmpty = {\n prefix: 'fas',\n iconName: 'thermometer-empty',\n icon: [256, 512, [], \"f2cb\", \"M192 384c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-35.346 28.654-64 64-64s64 28.654 64 64zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z\"]\n};\nvar faThermometerFull = {\n prefix: 'fas',\n iconName: 'thermometer-full',\n icon: [256, 512, [], \"f2c7\", \"M224 96c0-53.019-42.981-96-96-96S32 42.981 32 96v203.347C12.225 321.756.166 351.136.002 383.333c-.359 70.303 56.787 128.176 127.089 128.664.299.002.61.003.909.003 70.698 0 128-57.304 128-128 0-32.459-12.088-62.09-32-84.653V96zm-96 368l-.576-.002c-43.86-.304-79.647-36.544-79.423-80.42.173-33.98 19.266-51.652 31.999-66.08V96c0-26.467 21.533-48 48-48s48 21.533 48 48v221.498c12.63 14.312 32 32.164 32 66.502 0 44.112-35.888 80-80 80zm64-80c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-23.685 12.876-44.349 32-55.417V96c0-17.673 14.327-32 32-32s32 14.327 32 32v232.583c19.124 11.068 32 31.732 32 55.417z\"]\n};\nvar faThermometerHalf = {\n prefix: 'fas',\n iconName: 'thermometer-half',\n icon: [256, 512, [], \"f2c9\", \"M192 384c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-23.685 12.876-44.349 32-55.417V224c0-17.673 14.327-32 32-32s32 14.327 32 32v104.583c19.124 11.068 32 31.732 32 55.417zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z\"]\n};\nvar faThermometerQuarter = {\n prefix: 'fas',\n iconName: 'thermometer-quarter',\n icon: [256, 512, [], \"f2ca\", \"M192 384c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-23.685 12.876-44.349 32-55.417V288c0-17.673 14.327-32 32-32s32 14.327 32 32v40.583c19.124 11.068 32 31.732 32 55.417zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z\"]\n};\nvar faThermometerThreeQuarters = {\n prefix: 'fas',\n iconName: 'thermometer-three-quarters',\n icon: [256, 512, [], \"f2c8\", \"M192 384c0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64 0-23.685 12.876-44.349 32-55.417V160c0-17.673 14.327-32 32-32s32 14.327 32 32v168.583c19.124 11.068 32 31.732 32 55.417zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z\"]\n};\nvar faThumbsDown = {\n prefix: 'fas',\n iconName: 'thumbs-down',\n icon: [512, 512, [], \"f165\", \"M0 56v240c0 13.255 10.745 24 24 24h80c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56zm40 200c0-13.255 10.745-24 24-24s24 10.745 24 24-10.745 24-24 24-24-10.745-24-24zm272 256c-20.183 0-29.485-39.293-33.931-57.795-5.206-21.666-10.589-44.07-25.393-58.902-32.469-32.524-49.503-73.967-89.117-113.111a11.98 11.98 0 0 1-3.558-8.521V59.901c0-6.541 5.243-11.878 11.783-11.998 15.831-.29 36.694-9.079 52.651-16.178C256.189 17.598 295.709.017 343.995 0h2.844c42.777 0 93.363.413 113.774 29.737 8.392 12.057 10.446 27.034 6.148 44.632 16.312 17.053 25.063 48.863 16.382 74.757 17.544 23.432 19.143 56.132 9.308 79.469l.11.11c11.893 11.949 19.523 31.259 19.439 49.197-.156 30.352-26.157 58.098-59.553 58.098H350.723C358.03 364.34 384 388.132 384 430.548 384 504 336 512 312 512z\"]\n};\nvar faThumbsUp = {\n prefix: 'fas',\n iconName: 'thumbs-up',\n icon: [512, 512, [], \"f164\", \"M104 224H24c-13.255 0-24 10.745-24 24v240c0 13.255 10.745 24 24 24h80c13.255 0 24-10.745 24-24V248c0-13.255-10.745-24-24-24zM64 472c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zM384 81.452c0 42.416-25.97 66.208-33.277 94.548h101.723c33.397 0 59.397 27.746 59.553 58.098.084 17.938-7.546 37.249-19.439 49.197l-.11.11c9.836 23.337 8.237 56.037-9.308 79.469 8.681 25.895-.069 57.704-16.382 74.757 4.298 17.598 2.244 32.575-6.148 44.632C440.202 511.587 389.616 512 346.839 512l-2.845-.001c-48.287-.017-87.806-17.598-119.56-31.725-15.957-7.099-36.821-15.887-52.651-16.178-6.54-.12-11.783-5.457-11.783-11.998v-213.77c0-3.2 1.282-6.271 3.558-8.521 39.614-39.144 56.648-80.587 89.117-113.111 14.804-14.832 20.188-37.236 25.393-58.902C282.515 39.293 291.817 0 312 0c24 0 72 8 72 81.452z\"]\n};\nvar faThumbtack = {\n prefix: 'fas',\n iconName: 'thumbtack',\n icon: [384, 512, [], \"f08d\", \"M298.028 214.267L285.793 96H328c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H56C42.745 0 32 10.745 32 24v48c0 13.255 10.745 24 24 24h42.207L85.972 214.267C37.465 236.82 0 277.261 0 328c0 13.255 10.745 24 24 24h136v104.007c0 1.242.289 2.467.845 3.578l24 48c2.941 5.882 11.364 5.893 14.311 0l24-48a8.008 8.008 0 0 0 .845-3.578V352h136c13.255 0 24-10.745 24-24-.001-51.183-37.983-91.42-85.973-113.733z\"]\n};\nvar faTicketAlt = {\n prefix: 'fas',\n iconName: 'ticket-alt',\n icon: [576, 512, [], \"f3ff\", \"M128 160h320v192H128V160zm400 96c0 26.51 21.49 48 48 48v96c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48v-96c26.51 0 48-21.49 48-48s-21.49-48-48-48v-96c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v96c-26.51 0-48 21.49-48 48zm-48-104c0-13.255-10.745-24-24-24H120c-13.255 0-24 10.745-24 24v208c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V152z\"]\n};\nvar faTimes = {\n prefix: 'fas',\n iconName: 'times',\n icon: [352, 512, [], \"f00d\", \"M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z\"]\n};\nvar faTimesCircle = {\n prefix: 'fas',\n iconName: 'times-circle',\n icon: [512, 512, [], \"f057\", \"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z\"]\n};\nvar faTint = {\n prefix: 'fas',\n iconName: 'tint',\n icon: [352, 512, [], \"f043\", \"M205.22 22.09c-7.94-28.78-49.44-30.12-58.44 0C100.01 179.85 0 222.72 0 333.91 0 432.35 78.72 512 176 512s176-79.65 176-178.09c0-111.75-99.79-153.34-146.78-311.82zM176 448c-61.75 0-112-50.25-112-112 0-8.84 7.16-16 16-16s16 7.16 16 16c0 44.11 35.89 80 80 80 8.84 0 16 7.16 16 16s-7.16 16-16 16z\"]\n};\nvar faTintSlash = {\n prefix: 'fas',\n iconName: 'tint-slash',\n icon: [640, 512, [], \"f5c7\", \"M633.82 458.1L494.97 350.78c.52-5.57 1.03-11.16 1.03-16.87 0-111.76-99.79-153.34-146.78-311.82-7.94-28.78-49.44-30.12-58.44 0-15.52 52.34-36.87 91.96-58.49 125.68L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.36 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.41-6.97 4.16-17.02-2.82-22.45zM144 333.91C144 432.35 222.72 512 320 512c44.71 0 85.37-16.96 116.4-44.7L162.72 255.78c-11.41 23.5-18.72 48.35-18.72 78.13z\"]\n};\nvar faTired = {\n prefix: 'fas',\n iconName: 'tired',\n icon: [496, 512, [], \"f5c8\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm33.8 189.7l80-48c11.6-6.9 24 7.7 15.4 18L343.6 208l33.6 40.3c8.7 10.4-3.9 24.8-15.4 18l-80-48c-7.7-4.7-7.7-15.9 0-20.6zm-163-30c-8.6-10.3 3.8-24.9 15.4-18l80 48c7.8 4.7 7.8 15.9 0 20.6l-80 48c-11.5 6.8-24-7.6-15.4-18l33.6-40.3-33.6-40.3zM248 288c51.9 0 115.3 43.8 123.2 106.7 1.7 13.6-8 24.6-17.7 20.4-25.9-11.1-64.4-17.4-105.5-17.4s-79.6 6.3-105.5 17.4c-9.8 4.2-19.4-7-17.7-20.4C132.7 331.8 196.1 288 248 288z\"]\n};\nvar faToggleOff = {\n prefix: 'fas',\n iconName: 'toggle-off',\n icon: [576, 512, [], \"f204\", \"M384 64H192C85.961 64 0 149.961 0 256s85.961 192 192 192h192c106.039 0 192-85.961 192-192S490.039 64 384 64zM64 256c0-70.741 57.249-128 128-128 70.741 0 128 57.249 128 128 0 70.741-57.249 128-128 128-70.741 0-128-57.249-128-128zm320 128h-48.905c65.217-72.858 65.236-183.12 0-256H384c70.741 0 128 57.249 128 128 0 70.74-57.249 128-128 128z\"]\n};\nvar faToggleOn = {\n prefix: 'fas',\n iconName: 'toggle-on',\n icon: [576, 512, [], \"f205\", \"M384 64H192C86 64 0 150 0 256s86 192 192 192h192c106 0 192-86 192-192S490 64 384 64zm0 320c-70.8 0-128-57.3-128-128 0-70.8 57.3-128 128-128 70.8 0 128 57.3 128 128 0 70.8-57.3 128-128 128z\"]\n};\nvar faToilet = {\n prefix: 'fas',\n iconName: 'toilet',\n icon: [384, 512, [], \"f7d8\", \"M368 48c8.8 0 16-7.2 16-16V16c0-8.8-7.2-16-16-16H16C7.2 0 0 7.2 0 16v16c0 8.8 7.2 16 16 16h16v156.7C11.8 214.8 0 226.9 0 240c0 67.2 34.6 126.2 86.8 160.5l-21.4 70.2C59.1 491.2 74.5 512 96 512h192c21.5 0 36.9-20.8 30.6-41.3l-21.4-70.2C349.4 366.2 384 307.2 384 240c0-13.1-11.8-25.2-32-35.3V48h16zM80 72c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H88c-4.4 0-8-3.6-8-8V72zm112 200c-77.1 0-139.6-14.3-139.6-32s62.5-32 139.6-32 139.6 14.3 139.6 32-62.5 32-139.6 32z\"]\n};\nvar faToiletPaper = {\n prefix: 'fas',\n iconName: 'toilet-paper',\n icon: [576, 512, [], \"f71e\", \"M128 0C74.98 0 32 85.96 32 192v172.07c0 41.12-9.8 62.77-31.17 126.87C-2.62 501.3 5.09 512 16.01 512h280.92c13.77 0 26-8.81 30.36-21.88 12.83-38.48 24.71-72.4 24.71-126.05V192c0-83.6 23.67-153.52 60.44-192H128zM96 224c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16zm64 0c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16zm64 0c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16zm64 0c-8.84 0-16-7.16-16-16s7.16-16 16-16 16 7.16 16 16-7.16 16-16 16zM480 0c-53.02 0-96 85.96-96 192s42.98 192 96 192 96-85.96 96-192S533.02 0 480 0zm0 256c-17.67 0-32-28.65-32-64s14.33-64 32-64 32 28.65 32 64-14.33 64-32 64z\"]\n};\nvar faToolbox = {\n prefix: 'fas',\n iconName: 'toolbox',\n icon: [512, 512, [], \"f552\", \"M502.63 214.63l-45.25-45.25c-6-6-14.14-9.37-22.63-9.37H384V80c0-26.51-21.49-48-48-48H176c-26.51 0-48 21.49-48 48v80H77.25c-8.49 0-16.62 3.37-22.63 9.37L9.37 214.63c-6 6-9.37 14.14-9.37 22.63V320h128v-16c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v16h128v-16c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v16h128v-82.75c0-8.48-3.37-16.62-9.37-22.62zM320 160H192V96h128v64zm64 208c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-16H192v16c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16v-16H0v96c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32v-96H384v16z\"]\n};\nvar faTools = {\n prefix: 'fas',\n iconName: 'tools',\n icon: [512, 512, [], \"f7d9\", \"M501.1 395.7L384 278.6c-23.1-23.1-57.6-27.6-85.4-13.9L192 158.1V96L64 0 0 64l96 128h62.1l106.6 106.6c-13.6 27.8-9.2 62.3 13.9 85.4l117.1 117.1c14.6 14.6 38.2 14.6 52.7 0l52.7-52.7c14.5-14.6 14.5-38.2 0-52.7zM331.7 225c28.3 0 54.9 11 74.9 31l19.4 19.4c15.8-6.9 30.8-16.5 43.8-29.5 37.1-37.1 49.7-89.3 37.9-136.7-2.2-9-13.5-12.1-20.1-5.5l-74.4 74.4-67.9-11.3L334 98.9l74.4-74.4c6.6-6.6 3.4-17.9-5.7-20.2-47.4-11.7-99.6.9-136.6 37.9-28.5 28.5-41.9 66.1-41.2 103.6l82.1 82.1c8.1-1.9 16.5-2.9 24.7-2.9zm-103.9 82l-56.7-56.7L18.7 402.8c-25 25-25 65.5 0 90.5s65.5 25 90.5 0l123.6-123.6c-7.6-19.9-9.9-41.6-5-62.7zM64 472c-13.2 0-24-10.8-24-24 0-13.3 10.7-24 24-24s24 10.7 24 24c0 13.2-10.7 24-24 24z\"]\n};\nvar faTooth = {\n prefix: 'fas',\n iconName: 'tooth',\n icon: [448, 512, [], \"f5c9\", \"M443.98 96.25c-11.01-45.22-47.11-82.06-92.01-93.72-32.19-8.36-63 5.1-89.14 24.33-3.25 2.39-6.96 3.73-10.5 5.48l28.32 18.21c7.42 4.77 9.58 14.67 4.8 22.11-4.46 6.95-14.27 9.86-22.11 4.8L162.83 12.84c-20.7-10.85-43.38-16.4-66.81-10.31-44.9 11.67-81 48.5-92.01 93.72-10.13 41.62-.42 80.81 21.5 110.43 23.36 31.57 32.68 68.66 36.29 107.35 4.4 47.16 10.33 94.16 20.94 140.32l7.8 33.95c3.19 13.87 15.49 23.7 29.67 23.7 13.97 0 26.15-9.55 29.54-23.16l34.47-138.42c4.56-18.32 20.96-31.16 39.76-31.16s35.2 12.85 39.76 31.16l34.47 138.42c3.39 13.61 15.57 23.16 29.54 23.16 14.18 0 26.48-9.83 29.67-23.7l7.8-33.95c10.61-46.15 16.53-93.16 20.94-140.32 3.61-38.7 12.93-75.78 36.29-107.35 21.95-29.61 31.66-68.8 21.53-110.43z\"]\n};\nvar faTorah = {\n prefix: 'fas',\n iconName: 'torah',\n icon: [640, 512, [], \"f6a0\", \"M48 0A48.05 48.05 0 0 0 0 48v64a16 16 0 0 0 16 16h80V48A48.05 48.05 0 0 0 48 0zm347.14 228.56h34.91l-17.47-29.17zm-59.09 52.07l16.78-28.07h-33.58zM242 228.56h34.9l-17.48-29.19zm188-105.12h-34.9l17.48 29.19zM256 412.57V352h288V96a96.1 96.1 0 0 0-96-96H111.59A79.24 79.24 0 0 1 128 48v368a64 64 0 0 0 74.75 63.12C234.22 474 256 444.46 256 412.57zm-38.59-303a20.11 20.11 0 0 1 17.5-10.15h56.3L318.8 53.3a20 20 0 0 1 17.25-9.82 19.66 19.66 0 0 1 17 9.68l27.7 46.28h56.36a20 20 0 0 1 17.14 30.29L426.57 176l27.79 46.43a19.6 19.6 0 0 1 .23 20 20.11 20.11 0 0 1-17.5 10.15h-56.3L353.2 298.7a20 20 0 0 1-17.2 9.82 19.66 19.66 0 0 1-17-9.68l-27.7-46.28h-56.39a20 20 0 0 1-17.14-30.29L245.43 176l-27.79-46.43a19.6 19.6 0 0 1-.23-19.98zM624 384H288v32a96.11 96.11 0 0 1-96 96h336a112 112 0 0 0 112-112 16 16 0 0 0-16-16zM276.86 123.44H242l17.47 29.17zM336 71.38l-16.83 28.06h33.58zm-31.12 157.18h62.3L398.59 176l-31.47-52.58h-62.3L273.41 176z\"]\n};\nvar faToriiGate = {\n prefix: 'fas',\n iconName: 'torii-gate',\n icon: [512, 512, [], \"f6a1\", \"M376.45 32h-240.9A303.17 303.17 0 0 1 0 0v96c0 17.67 14.33 32 32 32h32v64H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h48v240c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16V256h256v240c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16V256h48c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16h-48v-64h32c17.67 0 32-14.33 32-32V0a303.17 303.17 0 0 1-135.55 32zM128 128h96v64h-96v-64zm256 64h-96v-64h96v64z\"]\n};\nvar faTractor = {\n prefix: 'fas',\n iconName: 'tractor',\n icon: [640, 512, [], \"f722\", \"M528 336c-48.6 0-88 39.4-88 88s39.4 88 88 88 88-39.4 88-88-39.4-88-88-88zm0 112c-13.23 0-24-10.77-24-24s10.77-24 24-24 24 10.77 24 24-10.77 24-24 24zm80-288h-64v-40.2c0-14.12 4.7-27.76 13.15-38.84 4.42-5.8 3.55-14.06-1.32-19.49L534.2 37.3c-6.66-7.45-18.32-6.92-24.7.78C490.58 60.9 480 89.81 480 119.8V160H377.67L321.58 29.14A47.914 47.914 0 0 0 277.45 0H144c-26.47 0-48 21.53-48 48v146.52c-8.63-6.73-20.96-6.46-28.89 1.47L36 227.1c-8.59 8.59-8.59 22.52 0 31.11l5.06 5.06c-4.99 9.26-8.96 18.82-11.91 28.72H22c-12.15 0-22 9.85-22 22v44c0 12.15 9.85 22 22 22h7.14c2.96 9.91 6.92 19.46 11.91 28.73l-5.06 5.06c-8.59 8.59-8.59 22.52 0 31.11L67.1 476c8.59 8.59 22.52 8.59 31.11 0l5.06-5.06c9.26 4.99 18.82 8.96 28.72 11.91V490c0 12.15 9.85 22 22 22h44c12.15 0 22-9.85 22-22v-7.14c9.9-2.95 19.46-6.92 28.72-11.91l5.06 5.06c8.59 8.59 22.52 8.59 31.11 0l31.11-31.11c8.59-8.59 8.59-22.52 0-31.11l-5.06-5.06c4.99-9.26 8.96-18.82 11.91-28.72H330c12.15 0 22-9.85 22-22v-6h80.54c21.91-28.99 56.32-48 95.46-48 18.64 0 36.07 4.61 51.8 12.2l50.82-50.82c6-6 9.37-14.14 9.37-22.63V192c.01-17.67-14.32-32-31.99-32zM176 416c-44.18 0-80-35.82-80-80s35.82-80 80-80 80 35.82 80 80-35.82 80-80 80zm22-256h-38V64h106.89l41.15 96H198z\"]\n};\nvar faTrademark = {\n prefix: 'fas',\n iconName: 'trademark',\n icon: [640, 512, [], \"f25c\", \"M260.6 96H12c-6.6 0-12 5.4-12 12v43.1c0 6.6 5.4 12 12 12h85.1V404c0 6.6 5.4 12 12 12h54.3c6.6 0 12-5.4 12-12V163.1h85.1c6.6 0 12-5.4 12-12V108c.1-6.6-5.3-12-11.9-12zM640 403l-24-296c-.5-6.2-5.7-11-12-11h-65.4c-5.1 0-9.7 3.3-11.3 8.1l-43.8 127.1c-7.2 20.6-16.1 52.8-16.1 52.8h-.9s-8.9-32.2-16.1-52.8l-43.8-127.1c-1.7-4.8-6.2-8.1-11.3-8.1h-65.4c-6.2 0-11.4 4.8-12 11l-24.4 296c-.6 7 4.9 13 12 13H360c6.3 0 11.5-4.9 12-11.2l9.1-132.9c1.8-24.2 0-53.7 0-53.7h.9s10.7 33.6 17.9 53.7l30.7 84.7c1.7 4.7 6.2 7.9 11.3 7.9h50.3c5.1 0 9.6-3.2 11.3-7.9l30.7-84.7c7.2-20.1 17.9-53.7 17.9-53.7h.9s-1.8 29.5 0 53.7l9.1 132.9c.4 6.3 5.7 11.2 12 11.2H628c7 0 12.5-6 12-13z\"]\n};\nvar faTrafficLight = {\n prefix: 'fas',\n iconName: 'traffic-light',\n icon: [384, 512, [], \"f637\", \"M384 192h-64v-37.88c37.2-13.22 64-48.38 64-90.12h-64V32c0-17.67-14.33-32-32-32H96C78.33 0 64 14.33 64 32v32H0c0 41.74 26.8 76.9 64 90.12V192H0c0 41.74 26.8 76.9 64 90.12V320H0c0 42.84 28.25 78.69 66.99 91.05C79.42 468.72 130.6 512 192 512s112.58-43.28 125.01-100.95C355.75 398.69 384 362.84 384 320h-64v-37.88c37.2-13.22 64-48.38 64-90.12zM192 416c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm0-128c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm0-128c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48z\"]\n};\nvar faTrain = {\n prefix: 'fas',\n iconName: 'train',\n icon: [448, 512, [], \"f238\", \"M448 96v256c0 51.815-61.624 96-130.022 96l62.98 49.721C386.905 502.417 383.562 512 376 512H72c-7.578 0-10.892-9.594-4.957-14.279L130.022 448C61.82 448 0 403.954 0 352V96C0 42.981 64 0 128 0h192c65 0 128 42.981 128 96zm-48 136V120c0-13.255-10.745-24-24-24H72c-13.255 0-24 10.745-24 24v112c0 13.255 10.745 24 24 24h304c13.255 0 24-10.745 24-24zm-176 64c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56z\"]\n};\nvar faTram = {\n prefix: 'fas',\n iconName: 'tram',\n icon: [512, 512, [], \"f7da\", \"M288 64c17.7 0 32-14.3 32-32S305.7 0 288 0s-32 14.3-32 32 14.3 32 32 32zm223.5-12.1c-2.3-8.6-11-13.6-19.6-11.3l-480 128c-8.5 2.3-13.6 11-11.3 19.6C2.5 195.3 8.9 200 16 200c1.4 0 2.8-.2 4.1-.5L240 140.8V224H64c-17.7 0-32 14.3-32 32v224c0 17.7 14.3 32 32 32h384c17.7 0 32-14.3 32-32V256c0-17.7-14.3-32-32-32H272v-91.7l228.1-60.8c8.6-2.3 13.6-11.1 11.4-19.6zM176 384H80v-96h96v96zm160-96h96v96h-96v-96zm-32 0v96h-96v-96h96zM192 96c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32z\"]\n};\nvar faTransgender = {\n prefix: 'fas',\n iconName: 'transgender',\n icon: [384, 512, [], \"f224\", \"M372 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-80.7 80.7C198.5 104.1 172.2 96 144 96 64.5 96 0 160.5 0 240c0 68.5 47.9 125.9 112 140.4V408H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v28c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-28h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-27.6c64.1-14.6 112-71.9 112-140.4 0-28.2-8.1-54.5-22.1-76.7l80.7-80.7 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V12c0-6.6-5.4-12-12-12zM144 320c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faTransgenderAlt = {\n prefix: 'fas',\n iconName: 'transgender-alt',\n icon: [480, 512, [], \"f225\", \"M468 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-80.7 80.7C294.5 104.1 268.2 96 240 96c-28.2 0-54.5 8.1-76.7 22.1l-16.5-16.5 19.8-19.8c4.7-4.7 4.7-12.3 0-17l-28.3-28.3c-4.7-4.7-12.3-4.7-17 0l-19.8 19.8-19-19 16.9-16.9C107.1 12.9 101.7 0 91 0H12C5.4 0 0 5.4 0 12v79c0 10.7 12.9 16 20.5 8.5l16.9-16.9 19 19-19.8 19.8c-4.7 4.7-4.7 12.3 0 17l28.3 28.3c4.7 4.7 12.3 4.7 17 0l19.8-19.8 16.5 16.5C104.1 185.5 96 211.8 96 240c0 68.5 47.9 125.9 112 140.4V408h-36c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v28c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-28h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-27.6c64.1-14.6 112-71.9 112-140.4 0-28.2-8.1-54.5-22.1-76.7l80.7-80.7 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V12c0-6.6-5.4-12-12-12zM240 320c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faTrash = {\n prefix: 'fas',\n iconName: 'trash',\n icon: [448, 512, [], \"f1f8\", \"M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z\"]\n};\nvar faTrashAlt = {\n prefix: 'fas',\n iconName: 'trash-alt',\n icon: [448, 512, [], \"f2ed\", \"M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z\"]\n};\nvar faTrashRestore = {\n prefix: 'fas',\n iconName: 'trash-restore',\n icon: [448, 512, [], \"f829\", \"M53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32zm70.11-175.8l89.38-94.26a15.41 15.41 0 0 1 22.62 0l89.38 94.26c10.08 10.62 2.94 28.8-11.32 28.8H256v112a16 16 0 0 1-16 16h-32a16 16 0 0 1-16-16V320h-57.37c-14.26 0-21.4-18.18-11.32-28.8zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z\"]\n};\nvar faTrashRestoreAlt = {\n prefix: 'fas',\n iconName: 'trash-restore-alt',\n icon: [448, 512, [], \"f82a\", \"M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm91.31-172.8l89.38-94.26a15.41 15.41 0 0 1 22.62 0l89.38 94.26c10.08 10.62 2.94 28.8-11.32 28.8H256v112a16 16 0 0 1-16 16h-32a16 16 0 0 1-16-16V320h-57.37c-14.26 0-21.4-18.18-11.32-28.8zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z\"]\n};\nvar faTree = {\n prefix: 'fas',\n iconName: 'tree',\n icon: [384, 512, [], \"f1bb\", \"M378.31 378.49L298.42 288h30.63c9.01 0 16.98-5 20.78-13.06 3.8-8.04 2.55-17.26-3.28-24.05L268.42 160h28.89c9.1 0 17.3-5.35 20.86-13.61 3.52-8.13 1.86-17.59-4.24-24.08L203.66 4.83c-6.03-6.45-17.28-6.45-23.32 0L70.06 122.31c-6.1 6.49-7.75 15.95-4.24 24.08C69.38 154.65 77.59 160 86.69 160h28.89l-78.14 90.91c-5.81 6.78-7.06 15.99-3.27 24.04C37.97 283 45.93 288 54.95 288h30.63L5.69 378.49c-6 6.79-7.36 16.09-3.56 24.26 3.75 8.05 12 13.25 21.01 13.25H160v24.45l-30.29 48.4c-5.32 10.64 2.42 23.16 14.31 23.16h95.96c11.89 0 19.63-12.52 14.31-23.16L224 440.45V416h136.86c9.01 0 17.26-5.2 21.01-13.25 3.8-8.17 2.44-17.47-3.56-24.26z\"]\n};\nvar faTrophy = {\n prefix: 'fas',\n iconName: 'trophy',\n icon: [576, 512, [], \"f091\", \"M552 64H448V24c0-13.3-10.7-24-24-24H152c-13.3 0-24 10.7-24 24v40H24C10.7 64 0 74.7 0 88v56c0 35.7 22.5 72.4 61.9 100.7 31.5 22.7 69.8 37.1 110 41.7C203.3 338.5 240 360 240 360v72h-48c-35.3 0-64 20.7-64 56v12c0 6.6 5.4 12 12 12h296c6.6 0 12-5.4 12-12v-12c0-35.3-28.7-56-64-56h-48v-72s36.7-21.5 68.1-73.6c40.3-4.6 78.6-19 110-41.7 39.3-28.3 61.9-65 61.9-100.7V88c0-13.3-10.7-24-24-24zM99.3 192.8C74.9 175.2 64 155.6 64 144v-16h64.2c1 32.6 5.8 61.2 12.8 86.2-15.1-5.2-29.2-12.4-41.7-21.4zM512 144c0 16.1-17.7 36.1-35.3 48.8-12.5 9-26.7 16.2-41.8 21.4 7-25 11.8-53.6 12.8-86.2H512v16z\"]\n};\nvar faTruck = {\n prefix: 'fas',\n iconName: 'truck',\n icon: [640, 512, [], \"f0d1\", \"M624 352h-16V243.9c0-12.7-5.1-24.9-14.1-33.9L494 110.1c-9-9-21.2-14.1-33.9-14.1H416V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h16c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM160 464c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm320 0c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-208H416V144h44.1l99.9 99.9V256z\"]\n};\nvar faTruckLoading = {\n prefix: 'fas',\n iconName: 'truck-loading',\n icon: [640, 512, [], \"f4de\", \"M50.2 375.6c2.3 8.5 11.1 13.6 19.6 11.3l216.4-58c8.5-2.3 13.6-11.1 11.3-19.6l-49.7-185.5c-2.3-8.5-11.1-13.6-19.6-11.3L151 133.3l24.8 92.7-61.8 16.5-24.8-92.7-77.3 20.7C3.4 172.8-1.7 181.6.6 190.1l49.6 185.5zM384 0c-17.7 0-32 14.3-32 32v323.6L5.9 450c-4.3 1.2-6.8 5.6-5.6 9.8l12.6 46.3c1.2 4.3 5.6 6.8 9.8 5.6l393.7-107.4C418.8 464.1 467.6 512 528 512c61.9 0 112-50.1 112-112V0H384zm144 448c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z\"]\n};\nvar faTruckMonster = {\n prefix: 'fas',\n iconName: 'truck-monster',\n icon: [640, 512, [], \"f63b\", \"M624 224h-16v-64c0-17.67-14.33-32-32-32h-73.6L419.22 24.02A64.025 64.025 0 0 0 369.24 0H256c-17.67 0-32 14.33-32 32v96H48c-8.84 0-16 7.16-16 16v80H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h16.72c29.21-38.65 75.1-64 127.28-64s98.07 25.35 127.28 64h65.45c29.21-38.65 75.1-64 127.28-64s98.07 25.35 127.28 64H624c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zm-336-96V64h81.24l51.2 64H288zm304 224h-5.2c-2.2-7.33-5.07-14.28-8.65-20.89l3.67-3.67c6.25-6.25 6.25-16.38 0-22.63l-22.63-22.63c-6.25-6.25-16.38-6.25-22.63 0l-3.67 3.67A110.85 110.85 0 0 0 512 277.2V272c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v5.2c-7.33 2.2-14.28 5.07-20.89 8.65l-3.67-3.67c-6.25-6.25-16.38-6.25-22.63 0l-22.63 22.63c-6.25 6.25-6.25 16.38 0 22.63l3.67 3.67A110.85 110.85 0 0 0 373.2 352H368c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h5.2c2.2 7.33 5.07 14.28 8.65 20.89l-3.67 3.67c-6.25 6.25-6.25 16.38 0 22.63l22.63 22.63c6.25 6.25 16.38 6.25 22.63 0l3.67-3.67c6.61 3.57 13.57 6.45 20.9 8.65v5.2c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-5.2c7.33-2.2 14.28-5.07 20.9-8.65l3.67 3.67c6.25 6.25 16.38 6.25 22.63 0l22.63-22.63c6.25-6.25 6.25-16.38 0-22.63l-3.67-3.67a110.85 110.85 0 0 0 8.65-20.89h5.2c8.84 0 16-7.16 16-16v-32c-.02-8.84-7.18-16-16.02-16zm-112 80c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm-208-80h-5.2c-2.2-7.33-5.07-14.28-8.65-20.89l3.67-3.67c6.25-6.25 6.25-16.38 0-22.63l-22.63-22.63c-6.25-6.25-16.38-6.25-22.63 0l-3.67 3.67A110.85 110.85 0 0 0 192 277.2V272c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v5.2c-7.33 2.2-14.28 5.07-20.89 8.65l-3.67-3.67c-6.25-6.25-16.38-6.25-22.63 0L58.18 304.8c-6.25 6.25-6.25 16.38 0 22.63l3.67 3.67a110.85 110.85 0 0 0-8.65 20.89H48c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h5.2c2.2 7.33 5.07 14.28 8.65 20.89l-3.67 3.67c-6.25 6.25-6.25 16.38 0 22.63l22.63 22.63c6.25 6.25 16.38 6.25 22.63 0l3.67-3.67c6.61 3.57 13.57 6.45 20.9 8.65v5.2c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-5.2c7.33-2.2 14.28-5.07 20.9-8.65l3.67 3.67c6.25 6.25 16.38 6.25 22.63 0l22.63-22.63c6.25-6.25 6.25-16.38 0-22.63l-3.67-3.67a110.85 110.85 0 0 0 8.65-20.89h5.2c8.84 0 16-7.16 16-16v-32C288 359.16 280.84 352 272 352zm-112 80c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48z\"]\n};\nvar faTruckMoving = {\n prefix: 'fas',\n iconName: 'truck-moving',\n icon: [640, 512, [], \"f4df\", \"M621.3 237.3l-58.5-58.5c-12-12-28.3-18.7-45.3-18.7H480V64c0-17.7-14.3-32-32-32H32C14.3 32 0 46.3 0 64v336c0 44.2 35.8 80 80 80 26.3 0 49.4-12.9 64-32.4 14.6 19.6 37.7 32.4 64 32.4 44.2 0 80-35.8 80-80 0-5.5-.6-10.8-1.6-16h163.2c-1.1 5.2-1.6 10.5-1.6 16 0 44.2 35.8 80 80 80s80-35.8 80-80c0-5.5-.6-10.8-1.6-16H624c8.8 0 16-7.2 16-16v-85.5c0-17-6.7-33.2-18.7-45.2zM80 432c-17.6 0-32-14.4-32-32s14.4-32 32-32 32 14.4 32 32-14.4 32-32 32zm128 0c-17.6 0-32-14.4-32-32s14.4-32 32-32 32 14.4 32 32-14.4 32-32 32zm272-224h37.5c4.3 0 8.3 1.7 11.3 4.7l43.3 43.3H480v-48zm48 224c-17.6 0-32-14.4-32-32s14.4-32 32-32 32 14.4 32 32-14.4 32-32 32z\"]\n};\nvar faTruckPickup = {\n prefix: 'fas',\n iconName: 'truck-pickup',\n icon: [640, 512, [], \"f63c\", \"M624 288h-16v-64c0-17.67-14.33-32-32-32h-48L419.22 56.02A64.025 64.025 0 0 0 369.24 32H256c-17.67 0-32 14.33-32 32v128H64c-17.67 0-32 14.33-32 32v64H16c-8.84 0-16 7.16-16 16v32c0 8.84 7.16 16 16 16h49.61c-.76 5.27-1.61 10.52-1.61 16 0 61.86 50.14 112 112 112s112-50.14 112-112c0-5.48-.85-10.73-1.61-16h67.23c-.76 5.27-1.61 10.52-1.61 16 0 61.86 50.14 112 112 112s112-50.14 112-112c0-5.48-.85-10.73-1.61-16H624c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM288 96h81.24l76.8 96H288V96zM176 416c-26.47 0-48-21.53-48-48s21.53-48 48-48 48 21.53 48 48-21.53 48-48 48zm288 0c-26.47 0-48-21.53-48-48s21.53-48 48-48 48 21.53 48 48-21.53 48-48 48z\"]\n};\nvar faTshirt = {\n prefix: 'fas',\n iconName: 'tshirt',\n icon: [640, 512, [], \"f553\", \"M631.2 96.5L436.5 0C416.4 27.8 371.9 47.2 320 47.2S223.6 27.8 203.5 0L8.8 96.5c-7.9 4-11.1 13.6-7.2 21.5l57.2 114.5c4 7.9 13.6 11.1 21.5 7.2l56.6-27.7c10.6-5.2 23 2.5 23 14.4V480c0 17.7 14.3 32 32 32h256c17.7 0 32-14.3 32-32V226.3c0-11.8 12.4-19.6 23-14.4l56.6 27.7c7.9 4 17.5.8 21.5-7.2L638.3 118c4-7.9.8-17.6-7.1-21.5z\"]\n};\nvar faTty = {\n prefix: 'fas',\n iconName: 'tty',\n icon: [512, 512, [], \"f1e4\", \"M5.37 103.822c138.532-138.532 362.936-138.326 501.262 0 6.078 6.078 7.074 15.496 2.583 22.681l-43.214 69.138a18.332 18.332 0 0 1-22.356 7.305l-86.422-34.569a18.335 18.335 0 0 1-11.434-18.846L351.741 90c-62.145-22.454-130.636-21.986-191.483 0l5.953 59.532a18.331 18.331 0 0 1-11.434 18.846l-86.423 34.568a18.334 18.334 0 0 1-22.356-7.305L2.787 126.502a18.333 18.333 0 0 1 2.583-22.68zM96 308v-40c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H92c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zM96 500v-40c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H140c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z\"]\n};\nvar faTv = {\n prefix: 'fas',\n iconName: 'tv',\n icon: [640, 512, [], \"f26c\", \"M592 0H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h245.1v32h-160c-17.7 0-32 14.3-32 32s14.3 32 32 32h384c17.7 0 32-14.3 32-32s-14.3-32-32-32h-160v-32H592c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-16 352H64V64h512v288z\"]\n};\nvar faUmbrella = {\n prefix: 'fas',\n iconName: 'umbrella',\n icon: [576, 512, [], \"f0e9\", \"M575.7 280.8C547.1 144.5 437.3 62.6 320 49.9V32c0-17.7-14.3-32-32-32s-32 14.3-32 32v17.9C138.3 62.6 29.5 144.5.3 280.8c-2.2 10.1 8.5 21.3 18.7 11.4 52-55 107.7-52.4 158.6 37 5.3 9.5 14.9 8.6 19.7 0 20.2-35.4 44.9-73.2 90.7-73.2 58.5 0 88.2 68.8 90.7 73.2 4.8 8.6 14.4 9.5 19.7 0 51-89.5 107.1-91.4 158.6-37 10.3 10 20.9-1.3 18.7-11.4zM256 301.7V432c0 8.8-7.2 16-16 16-7.8 0-13.2-5.3-15.1-10.7-5.9-16.7-24.1-25.4-40.8-19.5-16.7 5.9-25.4 24.2-19.5 40.8 11.2 31.9 41.6 53.3 75.4 53.3 44.1 0 80-35.9 80-80V301.6c-9.1-7.9-19.8-13.6-32-13.6-12.3.1-22.4 4.8-32 13.7z\"]\n};\nvar faUmbrellaBeach = {\n prefix: 'fas',\n iconName: 'umbrella-beach',\n icon: [640, 512, [], \"f5ca\", \"M115.38 136.9l102.11 37.18c35.19-81.54 86.21-144.29 139-173.7-95.88-4.89-188.78 36.96-248.53 111.8-6.69 8.4-2.66 21.05 7.42 24.72zm132.25 48.16l238.48 86.83c35.76-121.38 18.7-231.66-42.63-253.98-7.4-2.7-15.13-4-23.09-4-58.02.01-128.27 69.17-172.76 171.15zM521.48 60.5c6.22 16.3 10.83 34.6 13.2 55.19 5.74 49.89-1.42 108.23-18.95 166.98l102.62 37.36c10.09 3.67 21.31-3.43 21.57-14.17 2.32-95.69-41.91-187.44-118.44-245.36zM560 447.98H321.06L386 269.5l-60.14-21.9-72.9 200.37H16c-8.84 0-16 7.16-16 16.01v32.01C0 504.83 7.16 512 16 512h544c8.84 0 16-7.17 16-16.01v-32.01c0-8.84-7.16-16-16-16z\"]\n};\nvar faUnderline = {\n prefix: 'fas',\n iconName: 'underline',\n icon: [448, 512, [], \"f0cd\", \"M224.264 388.24c-91.669 0-156.603-51.165-156.603-151.392V64H39.37c-8.837 0-16-7.163-16-16V16c0-8.837 7.163-16 16-16h137.39c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-28.813v172.848c0 53.699 28.314 79.444 76.317 79.444 46.966 0 75.796-25.434 75.796-79.965V64h-28.291c-8.837 0-16-7.163-16-16V16c0-8.837 7.163-16 16-16h136.868c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-28.291v172.848c0 99.405-64.881 151.392-156.082 151.392zM16 448h416c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16z\"]\n};\nvar faUndo = {\n prefix: 'fas',\n iconName: 'undo',\n icon: [512, 512, [], \"f0e2\", \"M212.333 224.333H12c-6.627 0-12-5.373-12-12V12C0 5.373 5.373 0 12 0h48c6.627 0 12 5.373 12 12v78.112C117.773 39.279 184.26 7.47 258.175 8.007c136.906.994 246.448 111.623 246.157 248.532C504.041 393.258 393.12 504 256.333 504c-64.089 0-122.496-24.313-166.51-64.215-5.099-4.622-5.334-12.554-.467-17.42l33.967-33.967c4.474-4.474 11.662-4.717 16.401-.525C170.76 415.336 211.58 432 256.333 432c97.268 0 176-78.716 176-176 0-97.267-78.716-176-176-176-58.496 0-110.28 28.476-142.274 72.333h98.274c6.627 0 12 5.373 12 12v48c0 6.627-5.373 12-12 12z\"]\n};\nvar faUndoAlt = {\n prefix: 'fas',\n iconName: 'undo-alt',\n icon: [512, 512, [], \"f2ea\", \"M255.545 8c-66.269.119-126.438 26.233-170.86 68.685L48.971 40.971C33.851 25.851 8 36.559 8 57.941V192c0 13.255 10.745 24 24 24h134.059c21.382 0 32.09-25.851 16.971-40.971l-41.75-41.75c30.864-28.899 70.801-44.907 113.23-45.273 92.398-.798 170.283 73.977 169.484 169.442C423.236 348.009 349.816 424 256 424c-41.127 0-79.997-14.678-110.63-41.556-4.743-4.161-11.906-3.908-16.368.553L89.34 422.659c-4.872 4.872-4.631 12.815.482 17.433C133.798 479.813 192.074 504 256 504c136.966 0 247.999-111.033 248-247.998C504.001 119.193 392.354 7.755 255.545 8z\"]\n};\nvar faUniversalAccess = {\n prefix: 'fas',\n iconName: 'universal-access',\n icon: [512, 512, [], \"f29a\", \"M256 48c114.953 0 208 93.029 208 208 0 114.953-93.029 208-208 208-114.953 0-208-93.029-208-208 0-114.953 93.029-208 208-208m0-40C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 56C149.961 64 64 149.961 64 256s85.961 192 192 192 192-85.961 192-192S362.039 64 256 64zm0 44c19.882 0 36 16.118 36 36s-16.118 36-36 36-36-16.118-36-36 16.118-36 36-36zm117.741 98.023c-28.712 6.779-55.511 12.748-82.14 15.807.851 101.023 12.306 123.052 25.037 155.621 3.617 9.26-.957 19.698-10.217 23.315-9.261 3.617-19.699-.957-23.316-10.217-8.705-22.308-17.086-40.636-22.261-78.549h-9.686c-5.167 37.851-13.534 56.208-22.262 78.549-3.615 9.255-14.05 13.836-23.315 10.217-9.26-3.617-13.834-14.056-10.217-23.315 12.713-32.541 24.185-54.541 25.037-155.621-26.629-3.058-53.428-9.027-82.141-15.807-8.6-2.031-13.926-10.648-11.895-19.249s10.647-13.926 19.249-11.895c96.686 22.829 124.283 22.783 220.775 0 8.599-2.03 17.218 3.294 19.249 11.895 2.029 8.601-3.297 17.219-11.897 19.249z\"]\n};\nvar faUniversity = {\n prefix: 'fas',\n iconName: 'university',\n icon: [512, 512, [], \"f19c\", \"M496 128v16a8 8 0 0 1-8 8h-24v12c0 6.627-5.373 12-12 12H60c-6.627 0-12-5.373-12-12v-12H24a8 8 0 0 1-8-8v-16a8 8 0 0 1 4.941-7.392l232-88a7.996 7.996 0 0 1 6.118 0l232 88A8 8 0 0 1 496 128zm-24 304H40c-13.255 0-24 10.745-24 24v16a8 8 0 0 0 8 8h464a8 8 0 0 0 8-8v-16c0-13.255-10.745-24-24-24zM96 192v192H60c-6.627 0-12 5.373-12 12v20h416v-20c0-6.627-5.373-12-12-12h-36V192h-64v192h-64V192h-64v192h-64V192H96z\"]\n};\nvar faUnlink = {\n prefix: 'fas',\n iconName: 'unlink',\n icon: [512, 512, [], \"f127\", \"M304.083 405.907c4.686 4.686 4.686 12.284 0 16.971l-44.674 44.674c-59.263 59.262-155.693 59.266-214.961 0-59.264-59.265-59.264-155.696 0-214.96l44.675-44.675c4.686-4.686 12.284-4.686 16.971 0l39.598 39.598c4.686 4.686 4.686 12.284 0 16.971l-44.675 44.674c-28.072 28.073-28.072 73.75 0 101.823 28.072 28.072 73.75 28.073 101.824 0l44.674-44.674c4.686-4.686 12.284-4.686 16.971 0l39.597 39.598zm-56.568-260.216c4.686 4.686 12.284 4.686 16.971 0l44.674-44.674c28.072-28.075 73.75-28.073 101.824 0 28.072 28.073 28.072 73.75 0 101.823l-44.675 44.674c-4.686 4.686-4.686 12.284 0 16.971l39.598 39.598c4.686 4.686 12.284 4.686 16.971 0l44.675-44.675c59.265-59.265 59.265-155.695 0-214.96-59.266-59.264-155.695-59.264-214.961 0l-44.674 44.674c-4.686 4.686-4.686 12.284 0 16.971l39.597 39.598zm234.828 359.28l22.627-22.627c9.373-9.373 9.373-24.569 0-33.941L63.598 7.029c-9.373-9.373-24.569-9.373-33.941 0L7.029 29.657c-9.373 9.373-9.373 24.569 0 33.941l441.373 441.373c9.373 9.372 24.569 9.372 33.941 0z\"]\n};\nvar faUnlock = {\n prefix: 'fas',\n iconName: 'unlock',\n icon: [448, 512, [], \"f09c\", \"M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z\"]\n};\nvar faUnlockAlt = {\n prefix: 'fas',\n iconName: 'unlock-alt',\n icon: [448, 512, [], \"f13e\", \"M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48zM264 408c0 22.1-17.9 40-40 40s-40-17.9-40-40v-48c0-22.1 17.9-40 40-40s40 17.9 40 40v48z\"]\n};\nvar faUpload = {\n prefix: 'fas',\n iconName: 'upload',\n icon: [512, 512, [], \"f093\", \"M296 384h-80c-13.3 0-24-10.7-24-24V192h-87.7c-17.8 0-26.7-21.5-14.1-34.1L242.3 5.7c7.5-7.5 19.8-7.5 27.3 0l152.2 152.2c12.6 12.6 3.7 34.1-14.1 34.1H320v168c0 13.3-10.7 24-24 24zm216-8v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h136v8c0 30.9 25.1 56 56 56h80c30.9 0 56-25.1 56-56v-8h136c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z\"]\n};\nvar faUser = {\n prefix: 'fas',\n iconName: 'user',\n icon: [448, 512, [], \"f007\", \"M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z\"]\n};\nvar faUserAlt = {\n prefix: 'fas',\n iconName: 'user-alt',\n icon: [512, 512, [], \"f406\", \"M256 288c79.5 0 144-64.5 144-144S335.5 0 256 0 112 64.5 112 144s64.5 144 144 144zm128 32h-55.1c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16H128C57.3 320 0 377.3 0 448v16c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48v-16c0-70.7-57.3-128-128-128z\"]\n};\nvar faUserAltSlash = {\n prefix: 'fas',\n iconName: 'user-alt-slash',\n icon: [640, 512, [], \"f4fa\", \"M633.8 458.1L389.6 269.3C433.8 244.7 464 198.1 464 144 464 64.5 399.5 0 320 0c-67.1 0-123 46.1-139 108.2L45.5 3.4C38.5-2 28.5-.8 23 6.2L3.4 31.4c-5.4 7-4.2 17 2.8 22.4l588.4 454.7c7 5.4 17 4.2 22.5-2.8l19.6-25.3c5.4-6.8 4.1-16.9-2.9-22.3zM198.4 320C124.2 320 64 380.2 64 454.4v9.6c0 26.5 21.5 48 48 48h382.2L245.8 320h-47.4z\"]\n};\nvar faUserAstronaut = {\n prefix: 'fas',\n iconName: 'user-astronaut',\n icon: [448, 512, [], \"f4fb\", \"M64 224h13.5c24.7 56.5 80.9 96 146.5 96s121.8-39.5 146.5-96H384c8.8 0 16-7.2 16-16v-96c0-8.8-7.2-16-16-16h-13.5C345.8 39.5 289.6 0 224 0S102.2 39.5 77.5 96H64c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16zm40-88c0-22.1 21.5-40 48-40h144c26.5 0 48 17.9 48 40v24c0 53-43 96-96 96h-48c-53 0-96-43-96-96v-24zm72 72l12-36 36-12-36-12-12-36-12 36-36 12 36 12 12 36zm151.6 113.4C297.7 340.7 262.2 352 224 352s-73.7-11.3-103.6-30.6C52.9 328.5 0 385 0 454.4v9.6c0 26.5 21.5 48 48 48h80v-64c0-17.7 14.3-32 32-32h128c17.7 0 32 14.3 32 32v64h80c26.5 0 48-21.5 48-48v-9.6c0-69.4-52.9-125.9-120.4-133zM272 448c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16zm-96 0c-8.8 0-16 7.2-16 16v48h32v-48c0-8.8-7.2-16-16-16z\"]\n};\nvar faUserCheck = {\n prefix: 'fas',\n iconName: 'user-check',\n icon: [640, 512, [], \"f4fc\", \"M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4zm323-128.4l-27.8-28.1c-4.6-4.7-12.1-4.7-16.8-.1l-104.8 104-45.5-45.8c-4.6-4.7-12.1-4.7-16.8-.1l-28.1 27.9c-4.7 4.6-4.7 12.1-.1 16.8l81.7 82.3c4.6 4.7 12.1 4.7 16.8.1l141.3-140.2c4.6-4.7 4.7-12.2.1-16.8z\"]\n};\nvar faUserCircle = {\n prefix: 'fas',\n iconName: 'user-circle',\n icon: [496, 512, [], \"f2bd\", \"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 96c48.6 0 88 39.4 88 88s-39.4 88-88 88-88-39.4-88-88 39.4-88 88-88zm0 344c-58.7 0-111.3-26.6-146.5-68.2 18.8-35.4 55.6-59.8 98.5-59.8 2.4 0 4.8.4 7.1 1.1 13 4.2 26.6 6.9 40.9 6.9 14.3 0 28-2.7 40.9-6.9 2.3-.7 4.7-1.1 7.1-1.1 42.9 0 79.7 24.4 98.5 59.8C359.3 421.4 306.7 448 248 448z\"]\n};\nvar faUserClock = {\n prefix: 'fas',\n iconName: 'user-clock',\n icon: [640, 512, [], \"f4fd\", \"M496 224c-79.6 0-144 64.4-144 144s64.4 144 144 144 144-64.4 144-144-64.4-144-144-144zm64 150.3c0 5.3-4.4 9.7-9.7 9.7h-60.6c-5.3 0-9.7-4.4-9.7-9.7v-76.6c0-5.3 4.4-9.7 9.7-9.7h12.6c5.3 0 9.7 4.4 9.7 9.7V352h38.3c5.3 0 9.7 4.4 9.7 9.7v12.6zM320 368c0-27.8 6.7-54.1 18.2-77.5-8-1.5-16.2-2.5-24.6-2.5h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h347.1c-45.3-31.9-75.1-84.5-75.1-144zm-96-112c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128z\"]\n};\nvar faUserCog = {\n prefix: 'fas',\n iconName: 'user-cog',\n icon: [640, 512, [], \"f4fe\", \"M610.5 373.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 400.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm201.2 226.5c-2.3-1.2-4.6-2.6-6.8-3.9l-7.9 4.6c-6 3.4-12.8 5.3-19.6 5.3-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-5.5-17.7 1.9-36.4 17.9-45.7l7.9-4.6c-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-16-9.2-23.4-28-17.9-45.7.9-2.9 2.2-5.8 3.2-8.7-3.8-.3-7.5-1.2-11.4-1.2h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c10.1 0 19.5-3.2 27.2-8.5-1.2-3.8-2-7.7-2-11.8v-9.2z\"]\n};\nvar faUserEdit = {\n prefix: 'fas',\n iconName: 'user-edit',\n icon: [640, 512, [], \"f4ff\", \"M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h274.9c-2.4-6.8-3.4-14-2.6-21.3l6.8-60.9 1.2-11.1 7.9-7.9 77.3-77.3c-24.5-27.7-60-45.5-99.9-45.5zm45.3 145.3l-6.8 61c-1.1 10.2 7.5 18.8 17.6 17.6l60.9-6.8 137.9-137.9-71.7-71.7-137.9 137.8zM633 268.9L595.1 231c-9.3-9.3-24.5-9.3-33.8 0l-37.8 37.8-4.1 4.1 71.8 71.7 41.8-41.8c9.3-9.4 9.3-24.5 0-33.9z\"]\n};\nvar faUserFriends = {\n prefix: 'fas',\n iconName: 'user-friends',\n icon: [640, 512, [], \"f500\", \"M192 256c61.9 0 112-50.1 112-112S253.9 32 192 32 80 82.1 80 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C51.6 288 0 339.6 0 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zM480 256c53 0 96-43 96-96s-43-96-96-96-96 43-96 96 43 96 96 96zm48 32h-3.8c-13.9 4.8-28.6 8-44.2 8s-30.3-3.2-44.2-8H432c-20.4 0-39.2 5.9-55.7 15.4 24.4 26.3 39.7 61.2 39.7 99.8v38.4c0 2.2-.5 4.3-.6 6.4H592c26.5 0 48-21.5 48-48 0-61.9-50.1-112-112-112z\"]\n};\nvar faUserGraduate = {\n prefix: 'fas',\n iconName: 'user-graduate',\n icon: [448, 512, [], \"f501\", \"M319.4 320.6L224 416l-95.4-95.4C57.1 323.7 0 382.2 0 454.4v9.6c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-9.6c0-72.2-57.1-130.7-128.6-133.8zM13.6 79.8l6.4 1.5v58.4c-7 4.2-12 11.5-12 20.3 0 8.4 4.6 15.4 11.1 19.7L3.5 242c-1.7 6.9 2.1 14 7.6 14h41.8c5.5 0 9.3-7.1 7.6-14l-15.6-62.3C51.4 175.4 56 168.4 56 160c0-8.8-5-16.1-12-20.3V87.1l66 15.9c-8.6 17.2-14 36.4-14 57 0 70.7 57.3 128 128 128s128-57.3 128-128c0-20.6-5.3-39.8-14-57l96.3-23.2c18.2-4.4 18.2-27.1 0-31.5l-190.4-46c-13-3.1-26.7-3.1-39.7 0L13.6 48.2c-18.1 4.4-18.1 27.2 0 31.6z\"]\n};\nvar faUserInjured = {\n prefix: 'fas',\n iconName: 'user-injured',\n icon: [448, 512, [], \"f728\", \"M277.37 11.98C261.08 4.47 243.11 0 224 0c-53.69 0-99.5 33.13-118.51 80h81.19l90.69-68.02zM342.51 80c-7.9-19.47-20.67-36.2-36.49-49.52L239.99 80h102.52zM224 256c70.69 0 128-57.31 128-128 0-5.48-.95-10.7-1.61-16H97.61c-.67 5.3-1.61 10.52-1.61 16 0 70.69 57.31 128 128 128zM80 299.7V512h128.26l-98.45-221.52A132.835 132.835 0 0 0 80 299.7zM0 464c0 26.51 21.49 48 48 48V320.24C18.88 344.89 0 381.26 0 422.4V464zm256-48h-55.38l42.67 96H256c26.47 0 48-21.53 48-48s-21.53-48-48-48zm57.6-128h-16.71c-22.24 10.18-46.88 16-72.89 16s-50.65-5.82-72.89-16h-7.37l42.67 96H256c44.11 0 80 35.89 80 80 0 18.08-6.26 34.59-16.41 48H400c26.51 0 48-21.49 48-48v-41.6c0-74.23-60.17-134.4-134.4-134.4z\"]\n};\nvar faUserLock = {\n prefix: 'fas',\n iconName: 'user-lock',\n icon: [640, 512, [], \"f502\", \"M320 320c0-11.1 3.1-21.4 8.1-30.5-4.8-.5-9.5-1.5-14.5-1.5h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h280.9c-5.5-9.5-8.9-20.3-8.9-32V320zm-96-64c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm384 32h-32v-48c0-44.2-35.8-80-80-80s-80 35.8-80 80v48h-32c-17.7 0-32 14.3-32 32v160c0 17.7 14.3 32 32 32h224c17.7 0 32-14.3 32-32V320c0-17.7-14.3-32-32-32zm-80 0h-64v-48c0-17.6 14.4-32 32-32s32 14.4 32 32v48z\"]\n};\nvar faUserMd = {\n prefix: 'fas',\n iconName: 'user-md',\n icon: [448, 512, [], \"f0f0\", \"M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zM104 424c0 13.3 10.7 24 24 24s24-10.7 24-24-10.7-24-24-24-24 10.7-24 24zm216-135.4v49c36.5 7.4 64 39.8 64 78.4v41.7c0 7.6-5.4 14.2-12.9 15.7l-32.2 6.4c-4.3.9-8.5-1.9-9.4-6.3l-3.1-15.7c-.9-4.3 1.9-8.6 6.3-9.4l19.3-3.9V416c0-62.8-96-65.1-96 1.9v26.7l19.3 3.9c4.3.9 7.1 5.1 6.3 9.4l-3.1 15.7c-.9 4.3-5.1 7.1-9.4 6.3l-31.2-4.2c-7.9-1.1-13.8-7.8-13.8-15.9V416c0-38.6 27.5-70.9 64-78.4v-45.2c-2.2.7-4.4 1.1-6.6 1.9-18 6.3-37.3 9.8-57.4 9.8s-39.4-3.5-57.4-9.8c-7.4-2.6-14.9-4.2-22.6-5.2v81.6c23.1 6.9 40 28.1 40 53.4 0 30.9-25.1 56-56 56s-56-25.1-56-56c0-25.3 16.9-46.5 40-53.4v-80.4C48.5 301 0 355.8 0 422.4v44.8C0 491.9 20.1 512 44.8 512h358.4c24.7 0 44.8-20.1 44.8-44.8v-44.8c0-72-56.8-130.3-128-133.8z\"]\n};\nvar faUserMinus = {\n prefix: 'fas',\n iconName: 'user-minus',\n icon: [640, 512, [], \"f503\", \"M624 208H432c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h192c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm-400 48c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z\"]\n};\nvar faUserNinja = {\n prefix: 'fas',\n iconName: 'user-ninja',\n icon: [448, 512, [], \"f504\", \"M325.4 289.2L224 390.6 122.6 289.2C54 295.3 0 352.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-70.2-54-127.1-122.6-133.2zM32 192c27.3 0 51.8-11.5 69.2-29.7 15.1 53.9 64 93.7 122.8 93.7 70.7 0 128-57.3 128-128S294.7 0 224 0c-50.4 0-93.6 29.4-114.5 71.8C92.1 47.8 64 32 32 32c0 33.4 17.1 62.8 43.1 80-26 17.2-43.1 46.6-43.1 80zm144-96h96c17.7 0 32 14.3 32 32H144c0-17.7 14.3-32 32-32z\"]\n};\nvar faUserNurse = {\n prefix: 'fas',\n iconName: 'user-nurse',\n icon: [448, 512, [], \"f82f\", \"M57.78 288h82.36c22.51 19.68 51.62 32 83.86 32s61.35-12.32 83.86-32h82.36a16 16 0 0 0 14.28-23.18c-15.23-29.85-31.28-62.23-42.15-95.54C354.78 146.09 352 121.59 352 97.2V48L224 0 96 48v49.2c0 24.39-2.75 48.89-10.33 72.08C74.78 202.59 58.73 235 43.5 264.82A16 16 0 0 0 57.78 288zM184 71.67a5 5 0 0 1 5-5h21.67V45a5 5 0 0 1 5-5h16.66a5 5 0 0 1 5 5v21.67H259a5 5 0 0 1 5 5v16.66a5 5 0 0 1-5 5h-21.67V115a5 5 0 0 1-5 5h-16.66a5 5 0 0 1-5-5V93.33H189a5 5 0 0 1-5-5zM144 160h160v32a80 80 0 0 1-160 0zm175.41 160L224 415.39 128.59 320C57.1 323.1 0 381.6 0 453.79A58.21 58.21 0 0 0 58.21 512h331.58A58.21 58.21 0 0 0 448 453.79C448 381.6 390.9 323.1 319.41 320z\"]\n};\nvar faUserPlus = {\n prefix: 'fas',\n iconName: 'user-plus',\n icon: [640, 512, [], \"f234\", \"M624 208h-64v-64c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v64h-64c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h64v64c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-64h64c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm-400 48c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z\"]\n};\nvar faUserSecret = {\n prefix: 'fas',\n iconName: 'user-secret',\n icon: [448, 512, [], \"f21b\", \"M383.9 308.3l23.9-62.6c4-10.5-3.7-21.7-15-21.7h-58.5c11-18.9 17.8-40.6 17.8-64v-.3c39.2-7.8 64-19.1 64-31.7 0-13.3-27.3-25.1-70.1-33-9.2-32.8-27-65.8-40.6-82.8-9.5-11.9-25.9-15.6-39.5-8.8l-27.6 13.8c-9 4.5-19.6 4.5-28.6 0L182.1 3.4c-13.6-6.8-30-3.1-39.5 8.8-13.5 17-31.4 50-40.6 82.8-42.7 7.9-70 19.7-70 33 0 12.6 24.8 23.9 64 31.7v.3c0 23.4 6.8 45.1 17.8 64H56.3c-11.5 0-19.2 11.7-14.7 22.3l25.8 60.2C27.3 329.8 0 372.7 0 422.4v44.8C0 491.9 20.1 512 44.8 512h358.4c24.7 0 44.8-20.1 44.8-44.8v-44.8c0-48.4-25.8-90.4-64.1-114.1zM176 480l-41.6-192 49.6 32 24 40-32 120zm96 0l-32-120 24-40 49.6-32L272 480zm41.7-298.5c-3.9 11.9-7 24.6-16.5 33.4-10.1 9.3-48 22.4-64-25-2.8-8.4-15.4-8.4-18.3 0-17 50.2-56 32.4-64 25-9.5-8.8-12.7-21.5-16.5-33.4-.8-2.5-6.3-5.7-6.3-5.8v-10.8c28.3 3.6 61 5.8 96 5.8s67.7-2.1 96-5.8v10.8c-.1.1-5.6 3.2-6.4 5.8z\"]\n};\nvar faUserShield = {\n prefix: 'fas',\n iconName: 'user-shield',\n icon: [640, 512, [], \"f505\", \"M622.3 271.1l-115.2-45c-4.1-1.6-12.6-3.7-22.2 0l-115.2 45c-10.7 4.2-17.7 14-17.7 24.9 0 111.6 68.7 188.8 132.9 213.9 9.6 3.7 18 1.6 22.2 0C558.4 489.9 640 420.5 640 296c0-10.9-7-20.7-17.7-24.9zM496 462.4V273.3l95.5 37.3c-5.6 87.1-60.9 135.4-95.5 151.8zM224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm96 40c0-2.5.8-4.8 1.1-7.2-2.5-.1-4.9-.8-7.5-.8h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c6.8 0 13.3-1.5 19.2-4-54-42.9-99.2-116.7-99.2-212z\"]\n};\nvar faUserSlash = {\n prefix: 'fas',\n iconName: 'user-slash',\n icon: [640, 512, [], \"f506\", \"M633.8 458.1L362.3 248.3C412.1 230.7 448 183.8 448 128 448 57.3 390.7 0 320 0c-67.1 0-121.5 51.8-126.9 117.4L45.5 3.4C38.5-2 28.5-.8 23 6.2L3.4 31.4c-5.4 7-4.2 17 2.8 22.4l588.4 454.7c7 5.4 17 4.2 22.5-2.8l19.6-25.3c5.4-6.8 4.1-16.9-2.9-22.3zM96 422.4V464c0 26.5 21.5 48 48 48h350.2L207.4 290.3C144.2 301.3 96 356 96 422.4z\"]\n};\nvar faUserTag = {\n prefix: 'fas',\n iconName: 'user-tag',\n icon: [640, 512, [], \"f507\", \"M630.6 364.9l-90.3-90.2c-12-12-28.3-18.7-45.3-18.7h-79.3c-17.7 0-32 14.3-32 32v79.2c0 17 6.7 33.2 18.7 45.2l90.3 90.2c12.5 12.5 32.8 12.5 45.3 0l92.5-92.5c12.6-12.5 12.6-32.7.1-45.2zm-182.8-21c-13.3 0-24-10.7-24-24s10.7-24 24-24 24 10.7 24 24c0 13.2-10.7 24-24 24zm-223.8-88c70.7 0 128-57.3 128-128C352 57.3 294.7 0 224 0S96 57.3 96 128c0 70.6 57.3 127.9 128 127.9zm127.8 111.2V294c-12.2-3.6-24.9-6.2-38.2-6.2h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 287.9 0 348.1 0 422.3v41.6c0 26.5 21.5 48 48 48h352c15.5 0 29.1-7.5 37.9-18.9l-58-58c-18.1-18.1-28.1-42.2-28.1-67.9z\"]\n};\nvar faUserTie = {\n prefix: 'fas',\n iconName: 'user-tie',\n icon: [448, 512, [], \"f508\", \"M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm95.8 32.6L272 480l-32-136 32-56h-96l32 56-32 136-47.8-191.4C56.9 292 0 350.3 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-72.1-56.9-130.4-128.2-133.8z\"]\n};\nvar faUserTimes = {\n prefix: 'fas',\n iconName: 'user-times',\n icon: [640, 512, [], \"f235\", \"M589.6 240l45.6-45.6c6.3-6.3 6.3-16.5 0-22.8l-22.8-22.8c-6.3-6.3-16.5-6.3-22.8 0L544 194.4l-45.6-45.6c-6.3-6.3-16.5-6.3-22.8 0l-22.8 22.8c-6.3 6.3-6.3 16.5 0 22.8l45.6 45.6-45.6 45.6c-6.3 6.3-6.3 16.5 0 22.8l22.8 22.8c6.3 6.3 16.5 6.3 22.8 0l45.6-45.6 45.6 45.6c6.3 6.3 16.5 6.3 22.8 0l22.8-22.8c6.3-6.3 6.3-16.5 0-22.8L589.6 240zM224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z\"]\n};\nvar faUsers = {\n prefix: 'fas',\n iconName: 'users',\n icon: [640, 512, [], \"f0c0\", \"M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z\"]\n};\nvar faUsersCog = {\n prefix: 'fas',\n iconName: 'users-cog',\n icon: [640, 512, [], \"f509\", \"M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z\"]\n};\nvar faUtensilSpoon = {\n prefix: 'fas',\n iconName: 'utensil-spoon',\n icon: [512, 512, [], \"f2e5\", \"M480.1 31.9c-55-55.1-164.9-34.5-227.8 28.5-49.3 49.3-55.1 110-28.8 160.4L9 413.2c-11.6 10.5-12.1 28.5-1 39.5L59.3 504c11 11 29.1 10.5 39.5-1.1l192.4-214.4c50.4 26.3 111.1 20.5 160.4-28.8 63-62.9 83.6-172.8 28.5-227.8z\"]\n};\nvar faUtensils = {\n prefix: 'fas',\n iconName: 'utensils',\n icon: [416, 512, [], \"f2e7\", \"M207.9 15.2c.8 4.7 16.1 94.5 16.1 128.8 0 52.3-27.8 89.6-68.9 104.6L168 486.7c.7 13.7-10.2 25.3-24 25.3H80c-13.7 0-24.7-11.5-24-25.3l12.9-238.1C27.7 233.6 0 196.2 0 144 0 109.6 15.3 19.9 16.1 15.2 19.3-5.1 61.4-5.4 64 16.3v141.2c1.3 3.4 15.1 3.2 16 0 1.4-25.3 7.9-139.2 8-141.8 3.3-20.8 44.7-20.8 47.9 0 .2 2.7 6.6 116.5 8 141.8.9 3.2 14.8 3.4 16 0V16.3c2.6-21.6 44.8-21.4 48-1.1zm119.2 285.7l-15 185.1c-1.2 14 9.9 26 23.9 26h56c13.3 0 24-10.7 24-24V24c0-13.2-10.7-24-24-24-82.5 0-221.4 178.5-64.9 300.9z\"]\n};\nvar faVectorSquare = {\n prefix: 'fas',\n iconName: 'vector-square',\n icon: [512, 512, [], \"f5cb\", \"M512 128V32c0-17.67-14.33-32-32-32h-96c-17.67 0-32 14.33-32 32H160c0-17.67-14.33-32-32-32H32C14.33 0 0 14.33 0 32v96c0 17.67 14.33 32 32 32v192c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32h192c0 17.67 14.33 32 32 32h96c17.67 0 32-14.33 32-32v-96c0-17.67-14.33-32-32-32V160c17.67 0 32-14.33 32-32zm-96-64h32v32h-32V64zM64 64h32v32H64V64zm32 384H64v-32h32v32zm352 0h-32v-32h32v32zm-32-96h-32c-17.67 0-32 14.33-32 32v32H160v-32c0-17.67-14.33-32-32-32H96V160h32c17.67 0 32-14.33 32-32V96h192v32c0 17.67 14.33 32 32 32h32v192z\"]\n};\nvar faVenus = {\n prefix: 'fas',\n iconName: 'venus',\n icon: [288, 512, [], \"f221\", \"M288 176c0-79.5-64.5-144-144-144S0 96.5 0 176c0 68.5 47.9 125.9 112 140.4V368H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.5 112-71.9 112-140.4zm-224 0c0-44.1 35.9-80 80-80s80 35.9 80 80-35.9 80-80 80-80-35.9-80-80z\"]\n};\nvar faVenusDouble = {\n prefix: 'fas',\n iconName: 'venus-double',\n icon: [512, 512, [], \"f226\", \"M288 176c0-79.5-64.5-144-144-144S0 96.5 0 176c0 68.5 47.9 125.9 112 140.4V368H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.5 112-71.9 112-140.4zm-224 0c0-44.1 35.9-80 80-80s80 35.9 80 80-35.9 80-80 80-80-35.9-80-80zm336 140.4V368h36c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-36v36c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-36h-36c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h36v-51.6c-21.2-4.8-40.6-14.3-57.2-27.3 14-16.7 25-36 32.1-57.1 14.5 14.8 34.7 24 57.1 24 44.1 0 80-35.9 80-80s-35.9-80-80-80c-22.3 0-42.6 9.2-57.1 24-7.1-21.1-18-40.4-32.1-57.1C303.4 43.6 334.3 32 368 32c79.5 0 144 64.5 144 144 0 68.5-47.9 125.9-112 140.4z\"]\n};\nvar faVenusMars = {\n prefix: 'fas',\n iconName: 'venus-mars',\n icon: [576, 512, [], \"f228\", \"M564 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-48.7 48.7C422.5 72.1 396.2 64 368 64c-33.7 0-64.6 11.6-89.2 30.9 14 16.7 25 36 32.1 57.1 14.5-14.8 34.7-24 57.1-24 44.1 0 80 35.9 80 80s-35.9 80-80 80c-22.3 0-42.6-9.2-57.1-24-7.1 21.1-18 40.4-32.1 57.1 24.5 19.4 55.5 30.9 89.2 30.9 79.5 0 144-64.5 144-144 0-28.2-8.1-54.5-22.1-76.7l48.7-48.7 16.9 16.9c2.4 2.4 5.4 3.5 8.4 3.5 6.2 0 12.1-4.8 12.1-12V12c0-6.6-5.4-12-12-12zM144 64C64.5 64 0 128.5 0 208c0 68.5 47.9 125.9 112 140.4V400H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.6 112-71.9 112-140.4 0-79.5-64.5-144-144-144zm0 224c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z\"]\n};\nvar faVial = {\n prefix: 'fas',\n iconName: 'vial',\n icon: [480, 512, [], \"f492\", \"M477.7 186.1L309.5 18.3c-3.1-3.1-8.2-3.1-11.3 0l-34 33.9c-3.1 3.1-3.1 8.2 0 11.3l11.2 11.1L33 316.5c-38.8 38.7-45.1 102-9.4 143.5 20.6 24 49.5 36 78.4 35.9 26.4 0 52.8-10 72.9-30.1l246.3-245.7 11.2 11.1c3.1 3.1 8.2 3.1 11.3 0l34-33.9c3.1-3 3.1-8.1 0-11.2zM318 256H161l148-147.7 78.5 78.3L318 256z\"]\n};\nvar faVials = {\n prefix: 'fas',\n iconName: 'vials',\n icon: [640, 512, [], \"f493\", \"M72 64h24v240c0 44.1 35.9 80 80 80s80-35.9 80-80V64h24c4.4 0 8-3.6 8-8V8c0-4.4-3.6-8-8-8H72c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8zm72 0h64v96h-64V64zm480 384H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM360 64h24v240c0 44.1 35.9 80 80 80s80-35.9 80-80V64h24c4.4 0 8-3.6 8-8V8c0-4.4-3.6-8-8-8H360c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8zm72 0h64v96h-64V64z\"]\n};\nvar faVideo = {\n prefix: 'fas',\n iconName: 'video',\n icon: [576, 512, [], \"f03d\", \"M336.2 64H47.8C21.4 64 0 85.4 0 111.8v288.4C0 426.6 21.4 448 47.8 448h288.4c26.4 0 47.8-21.4 47.8-47.8V111.8c0-26.4-21.4-47.8-47.8-47.8zm189.4 37.7L416 177.3v157.4l109.6 75.5c21.2 14.6 50.4-.3 50.4-25.8V127.5c0-25.4-29.1-40.4-50.4-25.8z\"]\n};\nvar faVideoSlash = {\n prefix: 'fas',\n iconName: 'video-slash',\n icon: [640, 512, [], \"f4e2\", \"M633.8 458.1l-55-42.5c15.4-1.4 29.2-13.7 29.2-31.1v-257c0-25.5-29.1-40.4-50.4-25.8L448 177.3v137.2l-32-24.7v-178c0-26.4-21.4-47.8-47.8-47.8H123.9L45.5 3.4C38.5-2 28.5-.8 23 6.2L3.4 31.4c-5.4 7-4.2 17 2.8 22.4L42.7 82 416 370.6l178.5 138c7 5.4 17 4.2 22.5-2.8l19.6-25.3c5.5-6.9 4.2-17-2.8-22.4zM32 400.2c0 26.4 21.4 47.8 47.8 47.8h288.4c11.2 0 21.4-4 29.6-10.5L32 154.7v245.5z\"]\n};\nvar faVihara = {\n prefix: 'fas',\n iconName: 'vihara',\n icon: [640, 512, [], \"f6a7\", \"M632.88 400.71L544 352v-64l55.16-17.69c11.79-5.9 11.79-22.72 0-28.62L480 192v-64l27.31-16.3c7.72-7.72 5.61-20.74-4.16-25.62L320 0 136.85 86.07c-9.77 4.88-11.88 17.9-4.16 25.62L160 128v64L40.84 241.69c-11.79 5.9-11.79 22.72 0 28.62L96 288v64L7.12 400.71c-5.42 3.62-7.7 9.63-7 15.29.62 5.01 3.57 9.75 8.72 12.33L64 448v48c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-48h160v48c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-48h160v48c0 8.84 7.16 16 16 16h32c8.84 0 16-7.16 16-16v-48l55.15-19.67c5.16-2.58 8.1-7.32 8.72-12.33.71-5.67-1.57-11.68-6.99-15.29zM224 128h192v64H224v-64zm-64 224v-64h320v64H160z\"]\n};\nvar faVolleyballBall = {\n prefix: 'fas',\n iconName: 'volleyball-ball',\n icon: [495, 512, [], \"f45f\", \"M223.3 243.4c-.9-37-8.6-72.8-22.7-105.7-90.8 42.4-157.5 122.4-180.3 216.8 13.4 30.8 32.9 58.3 56.9 81.1 22.7-79.2 74.2-147.8 146.1-192.2zM186.4 109c-15-26.4-34.5-50.1-57.4-70.7C38 88.1-15.8 191.2 4 300.5c33.4-83.1 98.4-152 182.4-191.5zM374 274.1c8.6-99.8-27.3-197.5-97.5-264.4-14.7-1.7-51.6-5.5-98.9 8.5 57.3 59.3 91 138.2 93.5 222.7 32.5 17.7 67.3 29 102.9 33.2zm-124.7 9.5c-31.6 19.3-58.7 43.9-80.2 72.6 82 57.3 184.5 75.1 277.5 47.8 19.7-26.4 34.2-56.8 42.2-89.9-26.6 6.6-53.7 10.4-80.9 10.4-54.6-.1-108.9-14.1-158.6-40.9zM151 383.3c-15.2 26-25.7 54.4-32.1 84.2 37.6 23 81.7 36.5 129.1 36.5 61 0 116.7-22.1 159.9-58.6C295 461.5 204.6 420.6 151 383.3zM331.3 22.7c55.3 70.4 82.5 161.2 74.6 253.6 30.3.2 60.5-4.8 89.7-14.2 0-2 .3-4 .3-6 0-107.8-68.7-199.1-164.6-233.4z\"]\n};\nvar faVolumeDown = {\n prefix: 'fas',\n iconName: 'volume-down',\n icon: [384, 512, [], \"f027\", \"M215.03 72.04L126.06 161H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V89.02c0-21.47-25.96-31.98-40.97-16.98zm123.2 108.08c-11.58-6.33-26.19-2.16-32.61 9.45-6.39 11.61-2.16 26.2 9.45 32.61C327.98 229.28 336 242.62 336 257c0 14.38-8.02 27.72-20.92 34.81-11.61 6.41-15.84 21-9.45 32.61 6.43 11.66 21.05 15.8 32.61 9.45 28.23-15.55 45.77-45 45.77-76.88s-17.54-61.32-45.78-76.87z\"]\n};\nvar faVolumeMute = {\n prefix: 'fas',\n iconName: 'volume-mute',\n icon: [512, 512, [], \"f6a9\", \"M215.03 71.05L126.06 160H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V88.02c0-21.46-25.96-31.98-40.97-16.97zM461.64 256l45.64-45.64c6.3-6.3 6.3-16.52 0-22.82l-22.82-22.82c-6.3-6.3-16.52-6.3-22.82 0L416 210.36l-45.64-45.64c-6.3-6.3-16.52-6.3-22.82 0l-22.82 22.82c-6.3 6.3-6.3 16.52 0 22.82L370.36 256l-45.63 45.63c-6.3 6.3-6.3 16.52 0 22.82l22.82 22.82c6.3 6.3 16.52 6.3 22.82 0L416 301.64l45.64 45.64c6.3 6.3 16.52 6.3 22.82 0l22.82-22.82c6.3-6.3 6.3-16.52 0-22.82L461.64 256z\"]\n};\nvar faVolumeOff = {\n prefix: 'fas',\n iconName: 'volume-off',\n icon: [257, 512, [], \"f026\", \"M216.36 71.04L127.39 160H25.33c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V88.02c0-21.47-25.96-31.98-40.97-16.98z\"]\n};\nvar faVolumeUp = {\n prefix: 'fas',\n iconName: 'volume-up',\n icon: [576, 512, [], \"f028\", \"M215.03 71.05L126.06 160H24c-13.26 0-24 10.74-24 24v144c0 13.25 10.74 24 24 24h102.06l88.97 88.95c15.03 15.03 40.97 4.47 40.97-16.97V88.02c0-21.46-25.96-31.98-40.97-16.97zm233.32-51.08c-11.17-7.33-26.18-4.24-33.51 6.95-7.34 11.17-4.22 26.18 6.95 33.51 66.27 43.49 105.82 116.6 105.82 195.58 0 78.98-39.55 152.09-105.82 195.58-11.17 7.32-14.29 22.34-6.95 33.5 7.04 10.71 21.93 14.56 33.51 6.95C528.27 439.58 576 351.33 576 256S528.27 72.43 448.35 19.97zM480 256c0-63.53-32.06-121.94-85.77-156.24-11.19-7.14-26.03-3.82-33.12 7.46s-3.78 26.21 7.41 33.36C408.27 165.97 432 209.11 432 256s-23.73 90.03-63.48 115.42c-11.19 7.14-14.5 22.07-7.41 33.36 6.51 10.36 21.12 15.14 33.12 7.46C447.94 377.94 480 319.54 480 256zm-141.77-76.87c-11.58-6.33-26.19-2.16-32.61 9.45-6.39 11.61-2.16 26.2 9.45 32.61C327.98 228.28 336 241.63 336 256c0 14.38-8.02 27.72-20.92 34.81-11.61 6.41-15.84 21-9.45 32.61 6.43 11.66 21.05 15.8 32.61 9.45 28.23-15.55 45.77-45 45.77-76.88s-17.54-61.32-45.78-76.86z\"]\n};\nvar faVoteYea = {\n prefix: 'fas',\n iconName: 'vote-yea',\n icon: [640, 512, [], \"f772\", \"M608 320h-64v64h22.4c5.3 0 9.6 3.6 9.6 8v16c0 4.4-4.3 8-9.6 8H73.6c-5.3 0-9.6-3.6-9.6-8v-16c0-4.4 4.3-8 9.6-8H96v-64H32c-17.7 0-32 14.3-32 32v96c0 17.7 14.3 32 32 32h576c17.7 0 32-14.3 32-32v-96c0-17.7-14.3-32-32-32zm-96 64V64.3c0-17.9-14.5-32.3-32.3-32.3H160.4C142.5 32 128 46.5 128 64.3V384h384zM211.2 202l25.5-25.3c4.2-4.2 11-4.2 15.2.1l41.3 41.6 95.2-94.4c4.2-4.2 11-4.2 15.2.1l25.3 25.5c4.2 4.2 4.2 11-.1 15.2L300.5 292c-4.2 4.2-11 4.2-15.2-.1l-74.1-74.7c-4.3-4.2-4.2-11 0-15.2z\"]\n};\nvar faVrCardboard = {\n prefix: 'fas',\n iconName: 'vr-cardboard',\n icon: [640, 512, [], \"f729\", \"M608 64H32C14.33 64 0 78.33 0 96v320c0 17.67 14.33 32 32 32h160.22c25.19 0 48.03-14.77 58.36-37.74l27.74-61.64C286.21 331.08 302.35 320 320 320s33.79 11.08 41.68 28.62l27.74 61.64C399.75 433.23 422.6 448 447.78 448H608c17.67 0 32-14.33 32-32V96c0-17.67-14.33-32-32-32zM160 304c-35.35 0-64-28.65-64-64s28.65-64 64-64 64 28.65 64 64-28.65 64-64 64zm320 0c-35.35 0-64-28.65-64-64s28.65-64 64-64 64 28.65 64 64-28.65 64-64 64z\"]\n};\nvar faWalking = {\n prefix: 'fas',\n iconName: 'walking',\n icon: [320, 512, [], \"f554\", \"M208 96c26.5 0 48-21.5 48-48S234.5 0 208 0s-48 21.5-48 48 21.5 48 48 48zm94.5 149.1l-23.3-11.8-9.7-29.4c-14.7-44.6-55.7-75.8-102.2-75.9-36-.1-55.9 10.1-93.3 25.2-21.6 8.7-39.3 25.2-49.7 46.2L17.6 213c-7.8 15.8-1.5 35 14.2 42.9 15.6 7.9 34.6 1.5 42.5-14.3L81 228c3.5-7 9.3-12.5 16.5-15.4l26.8-10.8-15.2 60.7c-5.2 20.8.4 42.9 14.9 58.8l59.9 65.4c7.2 7.9 12.3 17.4 14.9 27.7l18.3 73.3c4.3 17.1 21.7 27.6 38.8 23.3 17.1-4.3 27.6-21.7 23.3-38.8l-22.2-89c-2.6-10.3-7.7-19.9-14.9-27.7l-45.5-49.7 17.2-68.7 5.5 16.5c5.3 16.1 16.7 29.4 31.7 37l23.3 11.8c15.6 7.9 34.6 1.5 42.5-14.3 7.7-15.7 1.4-35.1-14.3-43zM73.6 385.8c-3.2 8.1-8 15.4-14.2 21.5l-50 50.1c-12.5 12.5-12.5 32.8 0 45.3s32.7 12.5 45.2 0l59.4-59.4c6.1-6.1 10.9-13.4 14.2-21.5l13.5-33.8c-55.3-60.3-38.7-41.8-47.4-53.7l-20.7 51.5z\"]\n};\nvar faWallet = {\n prefix: 'fas',\n iconName: 'wallet',\n icon: [512, 512, [], \"f555\", \"M461.2 128H80c-8.84 0-16-7.16-16-16s7.16-16 16-16h384c8.84 0 16-7.16 16-16 0-26.51-21.49-48-48-48H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h397.2c28.02 0 50.8-21.53 50.8-48V176c0-26.47-22.78-48-50.8-48zM416 336c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32z\"]\n};\nvar faWarehouse = {\n prefix: 'fas',\n iconName: 'warehouse',\n icon: [640, 512, [], \"f494\", \"M504 352H136.4c-4.4 0-8 3.6-8 8l-.1 48c0 4.4 3.6 8 8 8H504c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zm0 96H136.1c-4.4 0-8 3.6-8 8l-.1 48c0 4.4 3.6 8 8 8h368c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zm0-192H136.6c-4.4 0-8 3.6-8 8l-.1 48c0 4.4 3.6 8 8 8H504c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zm106.5-139L338.4 3.7a48.15 48.15 0 0 0-36.9 0L29.5 117C11.7 124.5 0 141.9 0 161.3V504c0 4.4 3.6 8 8 8h80c4.4 0 8-3.6 8-8V256c0-17.6 14.6-32 32.6-32h382.8c18 0 32.6 14.4 32.6 32v248c0 4.4 3.6 8 8 8h80c4.4 0 8-3.6 8-8V161.3c0-19.4-11.7-36.8-29.5-44.3z\"]\n};\nvar faWater = {\n prefix: 'fas',\n iconName: 'water',\n icon: [576, 512, [], \"f773\", \"M562.1 383.9c-21.5-2.4-42.1-10.5-57.9-22.9-14.1-11.1-34.2-11.3-48.2 0-37.9 30.4-107.2 30.4-145.7-1.5-13.5-11.2-33-9.1-46.7 1.8-38 30.1-106.9 30-145.2-1.7-13.5-11.2-33.3-8.9-47.1 2-15.5 12.2-36 20.1-57.7 22.4-7.9.8-13.6 7.8-13.6 15.7v32.2c0 9.1 7.6 16.8 16.7 16 28.8-2.5 56.1-11.4 79.4-25.9 56.5 34.6 137 34.1 192 0 56.5 34.6 137 34.1 192 0 23.3 14.2 50.9 23.3 79.1 25.8 9.1.8 16.7-6.9 16.7-16v-31.6c.1-8-5.7-15.4-13.8-16.3zm0-144c-21.5-2.4-42.1-10.5-57.9-22.9-14.1-11.1-34.2-11.3-48.2 0-37.9 30.4-107.2 30.4-145.7-1.5-13.5-11.2-33-9.1-46.7 1.8-38 30.1-106.9 30-145.2-1.7-13.5-11.2-33.3-8.9-47.1 2-15.5 12.2-36 20.1-57.7 22.4-7.9.8-13.6 7.8-13.6 15.7v32.2c0 9.1 7.6 16.8 16.7 16 28.8-2.5 56.1-11.4 79.4-25.9 56.5 34.6 137 34.1 192 0 56.5 34.6 137 34.1 192 0 23.3 14.2 50.9 23.3 79.1 25.8 9.1.8 16.7-6.9 16.7-16v-31.6c.1-8-5.7-15.4-13.8-16.3zm0-144C540.6 93.4 520 85.4 504.2 73 490.1 61.9 470 61.7 456 73c-37.9 30.4-107.2 30.4-145.7-1.5-13.5-11.2-33-9.1-46.7 1.8-38 30.1-106.9 30-145.2-1.7-13.5-11.2-33.3-8.9-47.1 2-15.5 12.2-36 20.1-57.7 22.4-7.9.8-13.6 7.8-13.6 15.7v32.2c0 9.1 7.6 16.8 16.7 16 28.8-2.5 56.1-11.4 79.4-25.9 56.5 34.6 137 34.1 192 0 56.5 34.6 137 34.1 192 0 23.3 14.2 50.9 23.3 79.1 25.8 9.1.8 16.7-6.9 16.7-16v-31.6c.1-8-5.7-15.4-13.8-16.3z\"]\n};\nvar faWeight = {\n prefix: 'fas',\n iconName: 'weight',\n icon: [512, 512, [], \"f496\", \"M448 64h-25.98C438.44 92.28 448 125.01 448 160c0 105.87-86.13 192-192 192S64 265.87 64 160c0-34.99 9.56-67.72 25.98-96H64C28.71 64 0 92.71 0 128v320c0 35.29 28.71 64 64 64h384c35.29 0 64-28.71 64-64V128c0-35.29-28.71-64-64-64zM256 320c88.37 0 160-71.63 160-160S344.37 0 256 0 96 71.63 96 160s71.63 160 160 160zm-.3-151.94l33.58-78.36c3.5-8.17 12.94-11.92 21.03-8.41 8.12 3.48 11.88 12.89 8.41 21l-33.67 78.55C291.73 188 296 197.45 296 208c0 22.09-17.91 40-40 40s-40-17.91-40-40c0-21.98 17.76-39.77 39.7-39.94z\"]\n};\nvar faWeightHanging = {\n prefix: 'fas',\n iconName: 'weight-hanging',\n icon: [512, 512, [], \"f5cd\", \"M510.28 445.86l-73.03-292.13c-3.8-15.19-16.44-25.72-30.87-25.72h-60.25c3.57-10.05 5.88-20.72 5.88-32 0-53.02-42.98-96-96-96s-96 42.98-96 96c0 11.28 2.3 21.95 5.88 32h-60.25c-14.43 0-27.08 10.54-30.87 25.72L1.72 445.86C-6.61 479.17 16.38 512 48.03 512h415.95c31.64 0 54.63-32.83 46.3-66.14zM256 128c-17.64 0-32-14.36-32-32s14.36-32 32-32 32 14.36 32 32-14.36 32-32 32z\"]\n};\nvar faWheelchair = {\n prefix: 'fas',\n iconName: 'wheelchair',\n icon: [512, 512, [], \"f193\", \"M496.101 385.669l14.227 28.663c3.929 7.915.697 17.516-7.218 21.445l-65.465 32.886c-16.049 7.967-35.556 1.194-43.189-15.055L331.679 320H192c-15.925 0-29.426-11.71-31.679-27.475C126.433 55.308 128.38 70.044 128 64c0-36.358 30.318-65.635 67.052-63.929 33.271 1.545 60.048 28.905 60.925 62.201.868 32.933-23.152 60.423-54.608 65.039l4.67 32.69H336c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H215.182l4.572 32H352a32 32 0 0 1 28.962 18.392L438.477 396.8l36.178-18.349c7.915-3.929 17.517-.697 21.446 7.218zM311.358 352h-24.506c-7.788 54.204-54.528 96-110.852 96-61.757 0-112-50.243-112-112 0-41.505 22.694-77.809 56.324-97.156-3.712-25.965-6.844-47.86-9.488-66.333C45.956 198.464 0 261.963 0 336c0 97.047 78.953 176 176 176 71.87 0 133.806-43.308 161.11-105.192L311.358 352z\"]\n};\nvar faWifi = {\n prefix: 'fas',\n iconName: 'wifi',\n icon: [640, 512, [], \"f1eb\", \"M634.91 154.88C457.74-8.99 182.19-8.93 5.09 154.88c-6.66 6.16-6.79 16.59-.35 22.98l34.24 33.97c6.14 6.1 16.02 6.23 22.4.38 145.92-133.68 371.3-133.71 517.25 0 6.38 5.85 16.26 5.71 22.4-.38l34.24-33.97c6.43-6.39 6.3-16.82-.36-22.98zM320 352c-35.35 0-64 28.65-64 64s28.65 64 64 64 64-28.65 64-64-28.65-64-64-64zm202.67-83.59c-115.26-101.93-290.21-101.82-405.34 0-6.9 6.1-7.12 16.69-.57 23.15l34.44 33.99c6 5.92 15.66 6.32 22.05.8 83.95-72.57 209.74-72.41 293.49 0 6.39 5.52 16.05 5.13 22.05-.8l34.44-33.99c6.56-6.46 6.33-17.06-.56-23.15z\"]\n};\nvar faWind = {\n prefix: 'fas',\n iconName: 'wind',\n icon: [512, 512, [], \"f72e\", \"M156.7 256H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h142.2c15.9 0 30.8 10.9 33.4 26.6 3.3 20-12.1 37.4-31.6 37.4-14.1 0-26.1-9.2-30.4-21.9-2.1-6.3-8.6-10.1-15.2-10.1H81.6c-9.8 0-17.7 8.8-15.9 18.4 8.6 44.1 47.6 77.6 94.2 77.6 57.1 0 102.7-50.1 95.2-108.6C249 291 205.4 256 156.7 256zM16 224h336c59.7 0 106.8-54.8 93.8-116.7-7.6-36.2-36.9-65.5-73.1-73.1-55.4-11.6-105.1 24.9-114.9 75.5-1.9 9.6 6.1 18.3 15.8 18.3h32.8c6.7 0 13.1-3.8 15.2-10.1C325.9 105.2 337.9 96 352 96c19.4 0 34.9 17.4 31.6 37.4-2.6 15.7-17.4 26.6-33.4 26.6H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16zm384 32H243.7c19.3 16.6 33.2 38.8 39.8 64H400c26.5 0 48 21.5 48 48s-21.5 48-48 48c-17.9 0-33.3-9.9-41.6-24.4-2.9-5-8.7-7.6-14.5-7.6h-33.8c-10.9 0-19 10.8-15.3 21.1 17.8 50.6 70.5 84.8 129.4 72.3 41.2-8.7 75.1-41.6 84.7-82.7C526 321.5 470.5 256 400 256z\"]\n};\nvar faWindowClose = {\n prefix: 'fas',\n iconName: 'window-close',\n icon: [512, 512, [], \"f410\", \"M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-83.6 290.5c4.8 4.8 4.8 12.6 0 17.4l-40.5 40.5c-4.8 4.8-12.6 4.8-17.4 0L256 313.3l-66.5 67.1c-4.8 4.8-12.6 4.8-17.4 0l-40.5-40.5c-4.8-4.8-4.8-12.6 0-17.4l67.1-66.5-67.1-66.5c-4.8-4.8-4.8-12.6 0-17.4l40.5-40.5c4.8-4.8 12.6-4.8 17.4 0l66.5 67.1 66.5-67.1c4.8-4.8 12.6-4.8 17.4 0l40.5 40.5c4.8 4.8 4.8 12.6 0 17.4L313.3 256l67.1 66.5z\"]\n};\nvar faWindowMaximize = {\n prefix: 'fas',\n iconName: 'window-maximize',\n icon: [512, 512, [], \"f2d0\", \"M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-16 160H64v-84c0-6.6 5.4-12 12-12h360c6.6 0 12 5.4 12 12v84z\"]\n};\nvar faWindowMinimize = {\n prefix: 'fas',\n iconName: 'window-minimize',\n icon: [512, 512, [], \"f2d1\", \"M464 352H48c-26.5 0-48 21.5-48 48v32c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48v-32c0-26.5-21.5-48-48-48z\"]\n};\nvar faWindowRestore = {\n prefix: 'fas',\n iconName: 'window-restore',\n icon: [512, 512, [], \"f2d2\", \"M512 48v288c0 26.5-21.5 48-48 48h-48V176c0-44.1-35.9-80-80-80H128V48c0-26.5 21.5-48 48-48h288c26.5 0 48 21.5 48 48zM384 176v288c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V176c0-26.5 21.5-48 48-48h288c26.5 0 48 21.5 48 48zm-68 28c0-6.6-5.4-12-12-12H76c-6.6 0-12 5.4-12 12v52h252v-52z\"]\n};\nvar faWineBottle = {\n prefix: 'fas',\n iconName: 'wine-bottle',\n icon: [512, 512, [], \"f72f\", \"M507.31 72.57L439.43 4.69c-6.25-6.25-16.38-6.25-22.63 0l-22.63 22.63c-6.25 6.25-6.25 16.38 0 22.63l-76.67 76.67c-46.58-19.7-102.4-10.73-140.37 27.23L18.75 312.23c-24.99 24.99-24.99 65.52 0 90.51l90.51 90.51c24.99 24.99 65.52 24.99 90.51 0l158.39-158.39c37.96-37.96 46.93-93.79 27.23-140.37l76.67-76.67c6.25 6.25 16.38 6.25 22.63 0l22.63-22.63c6.24-6.24 6.24-16.37-.01-22.62zM179.22 423.29l-90.51-90.51 122.04-122.04 90.51 90.51-122.04 122.04z\"]\n};\nvar faWineGlass = {\n prefix: 'fas',\n iconName: 'wine-glass',\n icon: [288, 512, [], \"f4e3\", \"M216 464h-40V346.81c68.47-15.89 118.05-79.91 111.4-154.16l-15.95-178.1C270.71 6.31 263.9 0 255.74 0H32.26c-8.15 0-14.97 6.31-15.7 14.55L.6 192.66C-6.05 266.91 43.53 330.93 112 346.82V464H72c-22.09 0-40 17.91-40 40 0 4.42 3.58 8 8 8h208c4.42 0 8-3.58 8-8 0-22.09-17.91-40-40-40z\"]\n};\nvar faWineGlassAlt = {\n prefix: 'fas',\n iconName: 'wine-glass-alt',\n icon: [288, 512, [], \"f5ce\", \"M216 464h-40V346.81c68.47-15.89 118.05-79.91 111.4-154.16l-15.95-178.1C270.71 6.31 263.9 0 255.74 0H32.26c-8.15 0-14.97 6.31-15.7 14.55L.6 192.66C-6.05 266.91 43.53 330.93 112 346.82V464H72c-22.09 0-40 17.91-40 40 0 4.42 3.58 8 8 8h208c4.42 0 8-3.58 8-8 0-22.09-17.91-40-40-40zM61.75 48h164.5l7.17 80H54.58l7.17-80z\"]\n};\nvar faWonSign = {\n prefix: 'fas',\n iconName: 'won-sign',\n icon: [576, 512, [], \"f159\", \"M564 192c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-48l18.6-80.6c1.7-7.5-4-14.7-11.7-14.7h-46.1c-5.7 0-10.6 4-11.7 9.5L450.7 128H340.8l-19.7-86c-1.3-5.5-6.1-9.3-11.7-9.3h-44c-5.6 0-10.4 3.8-11.7 9.3l-20 86H125l-17.5-85.7c-1.1-5.6-6.1-9.6-11.8-9.6H53.6c-7.7 0-13.4 7.1-11.7 14.6L60 128H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h62.3l7.2 32H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h83.9l40.9 182.6c1.2 5.5 6.1 9.4 11.7 9.4h56.8c5.6 0 10.4-3.9 11.7-9.3L259.3 288h55.1l42.4 182.7c1.3 5.4 6.1 9.3 11.7 9.3h56.8c5.6 0 10.4-3.9 11.7-9.3L479.1 288H564c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-70.1l7.4-32zM183.8 342c-6.2 25.8-6.8 47.2-7.3 47.2h-1.1s-1.7-22-6.8-47.2l-11-54h38.8zm27.5-118h-66.8l-6.5-32h80.8zm62.9 0l2-8.6c1.9-8 3.5-16 4.8-23.4h11.8c1.3 7.4 2.9 15.4 4.8 23.4l2 8.6zm130.9 118c-5.1 25.2-6.8 47.2-6.8 47.2h-1.1c-.6 0-1.1-21.4-7.3-47.2l-12.4-54h39.1zm25.2-118h-67.4l-7.3-32h81.6z\"]\n};\nvar faWrench = {\n prefix: 'fas',\n iconName: 'wrench',\n icon: [512, 512, [], \"f0ad\", \"M507.73 109.1c-2.24-9.03-13.54-12.09-20.12-5.51l-74.36 74.36-67.88-11.31-11.31-67.88 74.36-74.36c6.62-6.62 3.43-17.9-5.66-20.16-47.38-11.74-99.55.91-136.58 37.93-39.64 39.64-50.55 97.1-34.05 147.2L18.74 402.76c-24.99 24.99-24.99 65.51 0 90.5 24.99 24.99 65.51 24.99 90.5 0l213.21-213.21c50.12 16.71 107.47 5.68 147.37-34.22 37.07-37.07 49.7-89.32 37.91-136.73zM64 472c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24z\"]\n};\nvar faXRay = {\n prefix: 'fas',\n iconName: 'x-ray',\n icon: [640, 512, [], \"f497\", \"M240 384c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16zm160 32c8.8 0 16-7.2 16-16s-7.2-16-16-16-16 7.2-16 16 7.2 16 16 16zM624 0H16C7.2 0 0 7.2 0 16v32c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16V16c0-8.8-7.2-16-16-16zm0 448h-48V96H64v352H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM480 248c0 4.4-3.6 8-8 8H336v32h104c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H336v32h64c26.5 0 48 21.5 48 48s-21.5 48-48 48-48-21.5-48-48v-16h-64v16c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48h64v-32H200c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h104v-32H168c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h136v-32H200c-4.4 0-8-3.6-8-8v-16c0-4.4 3.6-8 8-8h104v-24c0-4.4 3.6-8 8-8h16c4.4 0 8 3.6 8 8v24h104c4.4 0 8 3.6 8 8v16c0 4.4-3.6 8-8 8H336v32h136c4.4 0 8 3.6 8 8v16z\"]\n};\nvar faYenSign = {\n prefix: 'fas',\n iconName: 'yen-sign',\n icon: [384, 512, [], \"f157\", \"M351.2 32h-65.3c-4.6 0-8.8 2.6-10.8 6.7l-55.4 113.2c-14.5 34.7-27.1 71.9-27.1 71.9h-1.3s-12.6-37.2-27.1-71.9L108.8 38.7c-2-4.1-6.2-6.7-10.8-6.7H32.8c-9.1 0-14.8 9.7-10.6 17.6L102.3 200H44c-6.6 0-12 5.4-12 12v32c0 6.6 5.4 12 12 12h88.2l19.8 37.2V320H44c-6.6 0-12 5.4-12 12v32c0 6.6 5.4 12 12 12h108v92c0 6.6 5.4 12 12 12h56c6.6 0 12-5.4 12-12v-92h108c6.6 0 12-5.4 12-12v-32c0-6.6-5.4-12-12-12H232v-26.8l19.8-37.2H340c6.6 0 12-5.4 12-12v-32c0-6.6-5.4-12-12-12h-58.3l80.1-150.4c4.3-7.9-1.5-17.6-10.6-17.6z\"]\n};\nvar faYinYang = {\n prefix: 'fas',\n iconName: 'yin-yang',\n icon: [496, 512, [], \"f6ad\", \"M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm0 376c-17.67 0-32-14.33-32-32s14.33-32 32-32 32 14.33 32 32-14.33 32-32 32zm0-128c-53.02 0-96 42.98-96 96s42.98 96 96 96c-106.04 0-192-85.96-192-192S141.96 64 248 64c53.02 0 96 42.98 96 96s-42.98 96-96 96zm0-128c-17.67 0-32 14.33-32 32s14.33 32 32 32 32-14.33 32-32-14.33-32-32-32z\"]\n};\nvar _iconsCache = {\n faAd: faAd,\n faAddressBook: faAddressBook,\n faAddressCard: faAddressCard,\n faAdjust: faAdjust,\n faAirFreshener: faAirFreshener,\n faAlignCenter: faAlignCenter,\n faAlignJustify: faAlignJustify,\n faAlignLeft: faAlignLeft,\n faAlignRight: faAlignRight,\n faAllergies: faAllergies,\n faAmbulance: faAmbulance,\n faAmericanSignLanguageInterpreting: faAmericanSignLanguageInterpreting,\n faAnchor: faAnchor,\n faAngleDoubleDown: faAngleDoubleDown,\n faAngleDoubleLeft: faAngleDoubleLeft,\n faAngleDoubleRight: faAngleDoubleRight,\n faAngleDoubleUp: faAngleDoubleUp,\n faAngleDown: faAngleDown,\n faAngleLeft: faAngleLeft,\n faAngleRight: faAngleRight,\n faAngleUp: faAngleUp,\n faAngry: faAngry,\n faAnkh: faAnkh,\n faAppleAlt: faAppleAlt,\n faArchive: faArchive,\n faArchway: faArchway,\n faArrowAltCircleDown: faArrowAltCircleDown,\n faArrowAltCircleLeft: faArrowAltCircleLeft,\n faArrowAltCircleRight: faArrowAltCircleRight,\n faArrowAltCircleUp: faArrowAltCircleUp,\n faArrowCircleDown: faArrowCircleDown,\n faArrowCircleLeft: faArrowCircleLeft,\n faArrowCircleRight: faArrowCircleRight,\n faArrowCircleUp: faArrowCircleUp,\n faArrowDown: faArrowDown,\n faArrowLeft: faArrowLeft,\n faArrowRight: faArrowRight,\n faArrowUp: faArrowUp,\n faArrowsAlt: faArrowsAlt,\n faArrowsAltH: faArrowsAltH,\n faArrowsAltV: faArrowsAltV,\n faAssistiveListeningSystems: faAssistiveListeningSystems,\n faAsterisk: faAsterisk,\n faAt: faAt,\n faAtlas: faAtlas,\n faAtom: faAtom,\n faAudioDescription: faAudioDescription,\n faAward: faAward,\n faBaby: faBaby,\n faBabyCarriage: faBabyCarriage,\n faBackspace: faBackspace,\n faBackward: faBackward,\n faBacon: faBacon,\n faBalanceScale: faBalanceScale,\n faBan: faBan,\n faBandAid: faBandAid,\n faBarcode: faBarcode,\n faBars: faBars,\n faBaseballBall: faBaseballBall,\n faBasketballBall: faBasketballBall,\n faBath: faBath,\n faBatteryEmpty: faBatteryEmpty,\n faBatteryFull: faBatteryFull,\n faBatteryHalf: faBatteryHalf,\n faBatteryQuarter: faBatteryQuarter,\n faBatteryThreeQuarters: faBatteryThreeQuarters,\n faBed: faBed,\n faBeer: faBeer,\n faBell: faBell,\n faBellSlash: faBellSlash,\n faBezierCurve: faBezierCurve,\n faBible: faBible,\n faBicycle: faBicycle,\n faBinoculars: faBinoculars,\n faBiohazard: faBiohazard,\n faBirthdayCake: faBirthdayCake,\n faBlender: faBlender,\n faBlenderPhone: faBlenderPhone,\n faBlind: faBlind,\n faBlog: faBlog,\n faBold: faBold,\n faBolt: faBolt,\n faBomb: faBomb,\n faBone: faBone,\n faBong: faBong,\n faBook: faBook,\n faBookDead: faBookDead,\n faBookMedical: faBookMedical,\n faBookOpen: faBookOpen,\n faBookReader: faBookReader,\n faBookmark: faBookmark,\n faBowlingBall: faBowlingBall,\n faBox: faBox,\n faBoxOpen: faBoxOpen,\n faBoxes: faBoxes,\n faBraille: faBraille,\n faBrain: faBrain,\n faBreadSlice: faBreadSlice,\n faBriefcase: faBriefcase,\n faBriefcaseMedical: faBriefcaseMedical,\n faBroadcastTower: faBroadcastTower,\n faBroom: faBroom,\n faBrush: faBrush,\n faBug: faBug,\n faBuilding: faBuilding,\n faBullhorn: faBullhorn,\n faBullseye: faBullseye,\n faBurn: faBurn,\n faBus: faBus,\n faBusAlt: faBusAlt,\n faBusinessTime: faBusinessTime,\n faCalculator: faCalculator,\n faCalendar: faCalendar,\n faCalendarAlt: faCalendarAlt,\n faCalendarCheck: faCalendarCheck,\n faCalendarDay: faCalendarDay,\n faCalendarMinus: faCalendarMinus,\n faCalendarPlus: faCalendarPlus,\n faCalendarTimes: faCalendarTimes,\n faCalendarWeek: faCalendarWeek,\n faCamera: faCamera,\n faCameraRetro: faCameraRetro,\n faCampground: faCampground,\n faCandyCane: faCandyCane,\n faCannabis: faCannabis,\n faCapsules: faCapsules,\n faCar: faCar,\n faCarAlt: faCarAlt,\n faCarBattery: faCarBattery,\n faCarCrash: faCarCrash,\n faCarSide: faCarSide,\n faCaretDown: faCaretDown,\n faCaretLeft: faCaretLeft,\n faCaretRight: faCaretRight,\n faCaretSquareDown: faCaretSquareDown,\n faCaretSquareLeft: faCaretSquareLeft,\n faCaretSquareRight: faCaretSquareRight,\n faCaretSquareUp: faCaretSquareUp,\n faCaretUp: faCaretUp,\n faCarrot: faCarrot,\n faCartArrowDown: faCartArrowDown,\n faCartPlus: faCartPlus,\n faCashRegister: faCashRegister,\n faCat: faCat,\n faCertificate: faCertificate,\n faChair: faChair,\n faChalkboard: faChalkboard,\n faChalkboardTeacher: faChalkboardTeacher,\n faChargingStation: faChargingStation,\n faChartArea: faChartArea,\n faChartBar: faChartBar,\n faChartLine: faChartLine,\n faChartPie: faChartPie,\n faCheck: faCheck,\n faCheckCircle: faCheckCircle,\n faCheckDouble: faCheckDouble,\n faCheckSquare: faCheckSquare,\n faCheese: faCheese,\n faChess: faChess,\n faChessBishop: faChessBishop,\n faChessBoard: faChessBoard,\n faChessKing: faChessKing,\n faChessKnight: faChessKnight,\n faChessPawn: faChessPawn,\n faChessQueen: faChessQueen,\n faChessRook: faChessRook,\n faChevronCircleDown: faChevronCircleDown,\n faChevronCircleLeft: faChevronCircleLeft,\n faChevronCircleRight: faChevronCircleRight,\n faChevronCircleUp: faChevronCircleUp,\n faChevronDown: faChevronDown,\n faChevronLeft: faChevronLeft,\n faChevronRight: faChevronRight,\n faChevronUp: faChevronUp,\n faChild: faChild,\n faChurch: faChurch,\n faCircle: faCircle,\n faCircleNotch: faCircleNotch,\n faCity: faCity,\n faClinicMedical: faClinicMedical,\n faClipboard: faClipboard,\n faClipboardCheck: faClipboardCheck,\n faClipboardList: faClipboardList,\n faClock: faClock,\n faClone: faClone,\n faClosedCaptioning: faClosedCaptioning,\n faCloud: faCloud,\n faCloudDownloadAlt: faCloudDownloadAlt,\n faCloudMeatball: faCloudMeatball,\n faCloudMoon: faCloudMoon,\n faCloudMoonRain: faCloudMoonRain,\n faCloudRain: faCloudRain,\n faCloudShowersHeavy: faCloudShowersHeavy,\n faCloudSun: faCloudSun,\n faCloudSunRain: faCloudSunRain,\n faCloudUploadAlt: faCloudUploadAlt,\n faCocktail: faCocktail,\n faCode: faCode,\n faCodeBranch: faCodeBranch,\n faCoffee: faCoffee,\n faCog: faCog,\n faCogs: faCogs,\n faCoins: faCoins,\n faColumns: faColumns,\n faComment: faComment,\n faCommentAlt: faCommentAlt,\n faCommentDollar: faCommentDollar,\n faCommentDots: faCommentDots,\n faCommentMedical: faCommentMedical,\n faCommentSlash: faCommentSlash,\n faComments: faComments,\n faCommentsDollar: faCommentsDollar,\n faCompactDisc: faCompactDisc,\n faCompass: faCompass,\n faCompress: faCompress,\n faCompressArrowsAlt: faCompressArrowsAlt,\n faConciergeBell: faConciergeBell,\n faCookie: faCookie,\n faCookieBite: faCookieBite,\n faCopy: faCopy,\n faCopyright: faCopyright,\n faCouch: faCouch,\n faCreditCard: faCreditCard,\n faCrop: faCrop,\n faCropAlt: faCropAlt,\n faCross: faCross,\n faCrosshairs: faCrosshairs,\n faCrow: faCrow,\n faCrown: faCrown,\n faCrutch: faCrutch,\n faCube: faCube,\n faCubes: faCubes,\n faCut: faCut,\n faDatabase: faDatabase,\n faDeaf: faDeaf,\n faDemocrat: faDemocrat,\n faDesktop: faDesktop,\n faDharmachakra: faDharmachakra,\n faDiagnoses: faDiagnoses,\n faDice: faDice,\n faDiceD20: faDiceD20,\n faDiceD6: faDiceD6,\n faDiceFive: faDiceFive,\n faDiceFour: faDiceFour,\n faDiceOne: faDiceOne,\n faDiceSix: faDiceSix,\n faDiceThree: faDiceThree,\n faDiceTwo: faDiceTwo,\n faDigitalTachograph: faDigitalTachograph,\n faDirections: faDirections,\n faDivide: faDivide,\n faDizzy: faDizzy,\n faDna: faDna,\n faDog: faDog,\n faDollarSign: faDollarSign,\n faDolly: faDolly,\n faDollyFlatbed: faDollyFlatbed,\n faDonate: faDonate,\n faDoorClosed: faDoorClosed,\n faDoorOpen: faDoorOpen,\n faDotCircle: faDotCircle,\n faDove: faDove,\n faDownload: faDownload,\n faDraftingCompass: faDraftingCompass,\n faDragon: faDragon,\n faDrawPolygon: faDrawPolygon,\n faDrum: faDrum,\n faDrumSteelpan: faDrumSteelpan,\n faDrumstickBite: faDrumstickBite,\n faDumbbell: faDumbbell,\n faDumpster: faDumpster,\n faDumpsterFire: faDumpsterFire,\n faDungeon: faDungeon,\n faEdit: faEdit,\n faEgg: faEgg,\n faEject: faEject,\n faEllipsisH: faEllipsisH,\n faEllipsisV: faEllipsisV,\n faEnvelope: faEnvelope,\n faEnvelopeOpen: faEnvelopeOpen,\n faEnvelopeOpenText: faEnvelopeOpenText,\n faEnvelopeSquare: faEnvelopeSquare,\n faEquals: faEquals,\n faEraser: faEraser,\n faEthernet: faEthernet,\n faEuroSign: faEuroSign,\n faExchangeAlt: faExchangeAlt,\n faExclamation: faExclamation,\n faExclamationCircle: faExclamationCircle,\n faExclamationTriangle: faExclamationTriangle,\n faExpand: faExpand,\n faExpandArrowsAlt: faExpandArrowsAlt,\n faExternalLinkAlt: faExternalLinkAlt,\n faExternalLinkSquareAlt: faExternalLinkSquareAlt,\n faEye: faEye,\n faEyeDropper: faEyeDropper,\n faEyeSlash: faEyeSlash,\n faFastBackward: faFastBackward,\n faFastForward: faFastForward,\n faFax: faFax,\n faFeather: faFeather,\n faFeatherAlt: faFeatherAlt,\n faFemale: faFemale,\n faFighterJet: faFighterJet,\n faFile: faFile,\n faFileAlt: faFileAlt,\n faFileArchive: faFileArchive,\n faFileAudio: faFileAudio,\n faFileCode: faFileCode,\n faFileContract: faFileContract,\n faFileCsv: faFileCsv,\n faFileDownload: faFileDownload,\n faFileExcel: faFileExcel,\n faFileExport: faFileExport,\n faFileImage: faFileImage,\n faFileImport: faFileImport,\n faFileInvoice: faFileInvoice,\n faFileInvoiceDollar: faFileInvoiceDollar,\n faFileMedical: faFileMedical,\n faFileMedicalAlt: faFileMedicalAlt,\n faFilePdf: faFilePdf,\n faFilePowerpoint: faFilePowerpoint,\n faFilePrescription: faFilePrescription,\n faFileSignature: faFileSignature,\n faFileUpload: faFileUpload,\n faFileVideo: faFileVideo,\n faFileWord: faFileWord,\n faFill: faFill,\n faFillDrip: faFillDrip,\n faFilm: faFilm,\n faFilter: faFilter,\n faFingerprint: faFingerprint,\n faFire: faFire,\n faFireAlt: faFireAlt,\n faFireExtinguisher: faFireExtinguisher,\n faFirstAid: faFirstAid,\n faFish: faFish,\n faFistRaised: faFistRaised,\n faFlag: faFlag,\n faFlagCheckered: faFlagCheckered,\n faFlagUsa: faFlagUsa,\n faFlask: faFlask,\n faFlushed: faFlushed,\n faFolder: faFolder,\n faFolderMinus: faFolderMinus,\n faFolderOpen: faFolderOpen,\n faFolderPlus: faFolderPlus,\n faFont: faFont,\n faFontAwesomeLogoFull: faFontAwesomeLogoFull,\n faFootballBall: faFootballBall,\n faForward: faForward,\n faFrog: faFrog,\n faFrown: faFrown,\n faFrownOpen: faFrownOpen,\n faFunnelDollar: faFunnelDollar,\n faFutbol: faFutbol,\n faGamepad: faGamepad,\n faGasPump: faGasPump,\n faGavel: faGavel,\n faGem: faGem,\n faGenderless: faGenderless,\n faGhost: faGhost,\n faGift: faGift,\n faGifts: faGifts,\n faGlassCheers: faGlassCheers,\n faGlassMartini: faGlassMartini,\n faGlassMartiniAlt: faGlassMartiniAlt,\n faGlassWhiskey: faGlassWhiskey,\n faGlasses: faGlasses,\n faGlobe: faGlobe,\n faGlobeAfrica: faGlobeAfrica,\n faGlobeAmericas: faGlobeAmericas,\n faGlobeAsia: faGlobeAsia,\n faGlobeEurope: faGlobeEurope,\n faGolfBall: faGolfBall,\n faGopuram: faGopuram,\n faGraduationCap: faGraduationCap,\n faGreaterThan: faGreaterThan,\n faGreaterThanEqual: faGreaterThanEqual,\n faGrimace: faGrimace,\n faGrin: faGrin,\n faGrinAlt: faGrinAlt,\n faGrinBeam: faGrinBeam,\n faGrinBeamSweat: faGrinBeamSweat,\n faGrinHearts: faGrinHearts,\n faGrinSquint: faGrinSquint,\n faGrinSquintTears: faGrinSquintTears,\n faGrinStars: faGrinStars,\n faGrinTears: faGrinTears,\n faGrinTongue: faGrinTongue,\n faGrinTongueSquint: faGrinTongueSquint,\n faGrinTongueWink: faGrinTongueWink,\n faGrinWink: faGrinWink,\n faGripHorizontal: faGripHorizontal,\n faGripLines: faGripLines,\n faGripLinesVertical: faGripLinesVertical,\n faGripVertical: faGripVertical,\n faGuitar: faGuitar,\n faHSquare: faHSquare,\n faHamburger: faHamburger,\n faHammer: faHammer,\n faHamsa: faHamsa,\n faHandHolding: faHandHolding,\n faHandHoldingHeart: faHandHoldingHeart,\n faHandHoldingUsd: faHandHoldingUsd,\n faHandLizard: faHandLizard,\n faHandMiddleFinger: faHandMiddleFinger,\n faHandPaper: faHandPaper,\n faHandPeace: faHandPeace,\n faHandPointDown: faHandPointDown,\n faHandPointLeft: faHandPointLeft,\n faHandPointRight: faHandPointRight,\n faHandPointUp: faHandPointUp,\n faHandPointer: faHandPointer,\n faHandRock: faHandRock,\n faHandScissors: faHandScissors,\n faHandSpock: faHandSpock,\n faHands: faHands,\n faHandsHelping: faHandsHelping,\n faHandshake: faHandshake,\n faHanukiah: faHanukiah,\n faHardHat: faHardHat,\n faHashtag: faHashtag,\n faHatWizard: faHatWizard,\n faHaykal: faHaykal,\n faHdd: faHdd,\n faHeading: faHeading,\n faHeadphones: faHeadphones,\n faHeadphonesAlt: faHeadphonesAlt,\n faHeadset: faHeadset,\n faHeart: faHeart,\n faHeartBroken: faHeartBroken,\n faHeartbeat: faHeartbeat,\n faHelicopter: faHelicopter,\n faHighlighter: faHighlighter,\n faHiking: faHiking,\n faHippo: faHippo,\n faHistory: faHistory,\n faHockeyPuck: faHockeyPuck,\n faHollyBerry: faHollyBerry,\n faHome: faHome,\n faHorse: faHorse,\n faHorseHead: faHorseHead,\n faHospital: faHospital,\n faHospitalAlt: faHospitalAlt,\n faHospitalSymbol: faHospitalSymbol,\n faHotTub: faHotTub,\n faHotdog: faHotdog,\n faHotel: faHotel,\n faHourglass: faHourglass,\n faHourglassEnd: faHourglassEnd,\n faHourglassHalf: faHourglassHalf,\n faHourglassStart: faHourglassStart,\n faHouseDamage: faHouseDamage,\n faHryvnia: faHryvnia,\n faICursor: faICursor,\n faIceCream: faIceCream,\n faIcicles: faIcicles,\n faIdBadge: faIdBadge,\n faIdCard: faIdCard,\n faIdCardAlt: faIdCardAlt,\n faIgloo: faIgloo,\n faImage: faImage,\n faImages: faImages,\n faInbox: faInbox,\n faIndent: faIndent,\n faIndustry: faIndustry,\n faInfinity: faInfinity,\n faInfo: faInfo,\n faInfoCircle: faInfoCircle,\n faItalic: faItalic,\n faJedi: faJedi,\n faJoint: faJoint,\n faJournalWhills: faJournalWhills,\n faKaaba: faKaaba,\n faKey: faKey,\n faKeyboard: faKeyboard,\n faKhanda: faKhanda,\n faKiss: faKiss,\n faKissBeam: faKissBeam,\n faKissWinkHeart: faKissWinkHeart,\n faKiwiBird: faKiwiBird,\n faLandmark: faLandmark,\n faLanguage: faLanguage,\n faLaptop: faLaptop,\n faLaptopCode: faLaptopCode,\n faLaptopMedical: faLaptopMedical,\n faLaugh: faLaugh,\n faLaughBeam: faLaughBeam,\n faLaughSquint: faLaughSquint,\n faLaughWink: faLaughWink,\n faLayerGroup: faLayerGroup,\n faLeaf: faLeaf,\n faLemon: faLemon,\n faLessThan: faLessThan,\n faLessThanEqual: faLessThanEqual,\n faLevelDownAlt: faLevelDownAlt,\n faLevelUpAlt: faLevelUpAlt,\n faLifeRing: faLifeRing,\n faLightbulb: faLightbulb,\n faLink: faLink,\n faLiraSign: faLiraSign,\n faList: faList,\n faListAlt: faListAlt,\n faListOl: faListOl,\n faListUl: faListUl,\n faLocationArrow: faLocationArrow,\n faLock: faLock,\n faLockOpen: faLockOpen,\n faLongArrowAltDown: faLongArrowAltDown,\n faLongArrowAltLeft: faLongArrowAltLeft,\n faLongArrowAltRight: faLongArrowAltRight,\n faLongArrowAltUp: faLongArrowAltUp,\n faLowVision: faLowVision,\n faLuggageCart: faLuggageCart,\n faMagic: faMagic,\n faMagnet: faMagnet,\n faMailBulk: faMailBulk,\n faMale: faMale,\n faMap: faMap,\n faMapMarked: faMapMarked,\n faMapMarkedAlt: faMapMarkedAlt,\n faMapMarker: faMapMarker,\n faMapMarkerAlt: faMapMarkerAlt,\n faMapPin: faMapPin,\n faMapSigns: faMapSigns,\n faMarker: faMarker,\n faMars: faMars,\n faMarsDouble: faMarsDouble,\n faMarsStroke: faMarsStroke,\n faMarsStrokeH: faMarsStrokeH,\n faMarsStrokeV: faMarsStrokeV,\n faMask: faMask,\n faMedal: faMedal,\n faMedkit: faMedkit,\n faMeh: faMeh,\n faMehBlank: faMehBlank,\n faMehRollingEyes: faMehRollingEyes,\n faMemory: faMemory,\n faMenorah: faMenorah,\n faMercury: faMercury,\n faMeteor: faMeteor,\n faMicrochip: faMicrochip,\n faMicrophone: faMicrophone,\n faMicrophoneAlt: faMicrophoneAlt,\n faMicrophoneAltSlash: faMicrophoneAltSlash,\n faMicrophoneSlash: faMicrophoneSlash,\n faMicroscope: faMicroscope,\n faMinus: faMinus,\n faMinusCircle: faMinusCircle,\n faMinusSquare: faMinusSquare,\n faMitten: faMitten,\n faMobile: faMobile,\n faMobileAlt: faMobileAlt,\n faMoneyBill: faMoneyBill,\n faMoneyBillAlt: faMoneyBillAlt,\n faMoneyBillWave: faMoneyBillWave,\n faMoneyBillWaveAlt: faMoneyBillWaveAlt,\n faMoneyCheck: faMoneyCheck,\n faMoneyCheckAlt: faMoneyCheckAlt,\n faMonument: faMonument,\n faMoon: faMoon,\n faMortarPestle: faMortarPestle,\n faMosque: faMosque,\n faMotorcycle: faMotorcycle,\n faMountain: faMountain,\n faMousePointer: faMousePointer,\n faMugHot: faMugHot,\n faMusic: faMusic,\n faNetworkWired: faNetworkWired,\n faNeuter: faNeuter,\n faNewspaper: faNewspaper,\n faNotEqual: faNotEqual,\n faNotesMedical: faNotesMedical,\n faObjectGroup: faObjectGroup,\n faObjectUngroup: faObjectUngroup,\n faOilCan: faOilCan,\n faOm: faOm,\n faOtter: faOtter,\n faOutdent: faOutdent,\n faPager: faPager,\n faPaintBrush: faPaintBrush,\n faPaintRoller: faPaintRoller,\n faPalette: faPalette,\n faPallet: faPallet,\n faPaperPlane: faPaperPlane,\n faPaperclip: faPaperclip,\n faParachuteBox: faParachuteBox,\n faParagraph: faParagraph,\n faParking: faParking,\n faPassport: faPassport,\n faPastafarianism: faPastafarianism,\n faPaste: faPaste,\n faPause: faPause,\n faPauseCircle: faPauseCircle,\n faPaw: faPaw,\n faPeace: faPeace,\n faPen: faPen,\n faPenAlt: faPenAlt,\n faPenFancy: faPenFancy,\n faPenNib: faPenNib,\n faPenSquare: faPenSquare,\n faPencilAlt: faPencilAlt,\n faPencilRuler: faPencilRuler,\n faPeopleCarry: faPeopleCarry,\n faPepperHot: faPepperHot,\n faPercent: faPercent,\n faPercentage: faPercentage,\n faPersonBooth: faPersonBooth,\n faPhone: faPhone,\n faPhoneSlash: faPhoneSlash,\n faPhoneSquare: faPhoneSquare,\n faPhoneVolume: faPhoneVolume,\n faPiggyBank: faPiggyBank,\n faPills: faPills,\n faPizzaSlice: faPizzaSlice,\n faPlaceOfWorship: faPlaceOfWorship,\n faPlane: faPlane,\n faPlaneArrival: faPlaneArrival,\n faPlaneDeparture: faPlaneDeparture,\n faPlay: faPlay,\n faPlayCircle: faPlayCircle,\n faPlug: faPlug,\n faPlus: faPlus,\n faPlusCircle: faPlusCircle,\n faPlusSquare: faPlusSquare,\n faPodcast: faPodcast,\n faPoll: faPoll,\n faPollH: faPollH,\n faPoo: faPoo,\n faPooStorm: faPooStorm,\n faPoop: faPoop,\n faPortrait: faPortrait,\n faPoundSign: faPoundSign,\n faPowerOff: faPowerOff,\n faPray: faPray,\n faPrayingHands: faPrayingHands,\n faPrescription: faPrescription,\n faPrescriptionBottle: faPrescriptionBottle,\n faPrescriptionBottleAlt: faPrescriptionBottleAlt,\n faPrint: faPrint,\n faProcedures: faProcedures,\n faProjectDiagram: faProjectDiagram,\n faPuzzlePiece: faPuzzlePiece,\n faQrcode: faQrcode,\n faQuestion: faQuestion,\n faQuestionCircle: faQuestionCircle,\n faQuidditch: faQuidditch,\n faQuoteLeft: faQuoteLeft,\n faQuoteRight: faQuoteRight,\n faQuran: faQuran,\n faRadiation: faRadiation,\n faRadiationAlt: faRadiationAlt,\n faRainbow: faRainbow,\n faRandom: faRandom,\n faReceipt: faReceipt,\n faRecycle: faRecycle,\n faRedo: faRedo,\n faRedoAlt: faRedoAlt,\n faRegistered: faRegistered,\n faReply: faReply,\n faReplyAll: faReplyAll,\n faRepublican: faRepublican,\n faRestroom: faRestroom,\n faRetweet: faRetweet,\n faRibbon: faRibbon,\n faRing: faRing,\n faRoad: faRoad,\n faRobot: faRobot,\n faRocket: faRocket,\n faRoute: faRoute,\n faRss: faRss,\n faRssSquare: faRssSquare,\n faRubleSign: faRubleSign,\n faRuler: faRuler,\n faRulerCombined: faRulerCombined,\n faRulerHorizontal: faRulerHorizontal,\n faRulerVertical: faRulerVertical,\n faRunning: faRunning,\n faRupeeSign: faRupeeSign,\n faSadCry: faSadCry,\n faSadTear: faSadTear,\n faSatellite: faSatellite,\n faSatelliteDish: faSatelliteDish,\n faSave: faSave,\n faSchool: faSchool,\n faScrewdriver: faScrewdriver,\n faScroll: faScroll,\n faSdCard: faSdCard,\n faSearch: faSearch,\n faSearchDollar: faSearchDollar,\n faSearchLocation: faSearchLocation,\n faSearchMinus: faSearchMinus,\n faSearchPlus: faSearchPlus,\n faSeedling: faSeedling,\n faServer: faServer,\n faShapes: faShapes,\n faShare: faShare,\n faShareAlt: faShareAlt,\n faShareAltSquare: faShareAltSquare,\n faShareSquare: faShareSquare,\n faShekelSign: faShekelSign,\n faShieldAlt: faShieldAlt,\n faShip: faShip,\n faShippingFast: faShippingFast,\n faShoePrints: faShoePrints,\n faShoppingBag: faShoppingBag,\n faShoppingBasket: faShoppingBasket,\n faShoppingCart: faShoppingCart,\n faShower: faShower,\n faShuttleVan: faShuttleVan,\n faSign: faSign,\n faSignInAlt: faSignInAlt,\n faSignLanguage: faSignLanguage,\n faSignOutAlt: faSignOutAlt,\n faSignal: faSignal,\n faSignature: faSignature,\n faSimCard: faSimCard,\n faSitemap: faSitemap,\n faSkating: faSkating,\n faSkiing: faSkiing,\n faSkiingNordic: faSkiingNordic,\n faSkull: faSkull,\n faSkullCrossbones: faSkullCrossbones,\n faSlash: faSlash,\n faSleigh: faSleigh,\n faSlidersH: faSlidersH,\n faSmile: faSmile,\n faSmileBeam: faSmileBeam,\n faSmileWink: faSmileWink,\n faSmog: faSmog,\n faSmoking: faSmoking,\n faSmokingBan: faSmokingBan,\n faSms: faSms,\n faSnowboarding: faSnowboarding,\n faSnowflake: faSnowflake,\n faSnowman: faSnowman,\n faSnowplow: faSnowplow,\n faSocks: faSocks,\n faSolarPanel: faSolarPanel,\n faSort: faSort,\n faSortAlphaDown: faSortAlphaDown,\n faSortAlphaUp: faSortAlphaUp,\n faSortAmountDown: faSortAmountDown,\n faSortAmountUp: faSortAmountUp,\n faSortDown: faSortDown,\n faSortNumericDown: faSortNumericDown,\n faSortNumericUp: faSortNumericUp,\n faSortUp: faSortUp,\n faSpa: faSpa,\n faSpaceShuttle: faSpaceShuttle,\n faSpider: faSpider,\n faSpinner: faSpinner,\n faSplotch: faSplotch,\n faSprayCan: faSprayCan,\n faSquare: faSquare,\n faSquareFull: faSquareFull,\n faSquareRootAlt: faSquareRootAlt,\n faStamp: faStamp,\n faStar: faStar,\n faStarAndCrescent: faStarAndCrescent,\n faStarHalf: faStarHalf,\n faStarHalfAlt: faStarHalfAlt,\n faStarOfDavid: faStarOfDavid,\n faStarOfLife: faStarOfLife,\n faStepBackward: faStepBackward,\n faStepForward: faStepForward,\n faStethoscope: faStethoscope,\n faStickyNote: faStickyNote,\n faStop: faStop,\n faStopCircle: faStopCircle,\n faStopwatch: faStopwatch,\n faStore: faStore,\n faStoreAlt: faStoreAlt,\n faStream: faStream,\n faStreetView: faStreetView,\n faStrikethrough: faStrikethrough,\n faStroopwafel: faStroopwafel,\n faSubscript: faSubscript,\n faSubway: faSubway,\n faSuitcase: faSuitcase,\n faSuitcaseRolling: faSuitcaseRolling,\n faSun: faSun,\n faSuperscript: faSuperscript,\n faSurprise: faSurprise,\n faSwatchbook: faSwatchbook,\n faSwimmer: faSwimmer,\n faSwimmingPool: faSwimmingPool,\n faSynagogue: faSynagogue,\n faSync: faSync,\n faSyncAlt: faSyncAlt,\n faSyringe: faSyringe,\n faTable: faTable,\n faTableTennis: faTableTennis,\n faTablet: faTablet,\n faTabletAlt: faTabletAlt,\n faTablets: faTablets,\n faTachometerAlt: faTachometerAlt,\n faTag: faTag,\n faTags: faTags,\n faTape: faTape,\n faTasks: faTasks,\n faTaxi: faTaxi,\n faTeeth: faTeeth,\n faTeethOpen: faTeethOpen,\n faTemperatureHigh: faTemperatureHigh,\n faTemperatureLow: faTemperatureLow,\n faTenge: faTenge,\n faTerminal: faTerminal,\n faTextHeight: faTextHeight,\n faTextWidth: faTextWidth,\n faTh: faTh,\n faThLarge: faThLarge,\n faThList: faThList,\n faTheaterMasks: faTheaterMasks,\n faThermometer: faThermometer,\n faThermometerEmpty: faThermometerEmpty,\n faThermometerFull: faThermometerFull,\n faThermometerHalf: faThermometerHalf,\n faThermometerQuarter: faThermometerQuarter,\n faThermometerThreeQuarters: faThermometerThreeQuarters,\n faThumbsDown: faThumbsDown,\n faThumbsUp: faThumbsUp,\n faThumbtack: faThumbtack,\n faTicketAlt: faTicketAlt,\n faTimes: faTimes,\n faTimesCircle: faTimesCircle,\n faTint: faTint,\n faTintSlash: faTintSlash,\n faTired: faTired,\n faToggleOff: faToggleOff,\n faToggleOn: faToggleOn,\n faToilet: faToilet,\n faToiletPaper: faToiletPaper,\n faToolbox: faToolbox,\n faTools: faTools,\n faTooth: faTooth,\n faTorah: faTorah,\n faToriiGate: faToriiGate,\n faTractor: faTractor,\n faTrademark: faTrademark,\n faTrafficLight: faTrafficLight,\n faTrain: faTrain,\n faTram: faTram,\n faTransgender: faTransgender,\n faTransgenderAlt: faTransgenderAlt,\n faTrash: faTrash,\n faTrashAlt: faTrashAlt,\n faTrashRestore: faTrashRestore,\n faTrashRestoreAlt: faTrashRestoreAlt,\n faTree: faTree,\n faTrophy: faTrophy,\n faTruck: faTruck,\n faTruckLoading: faTruckLoading,\n faTruckMonster: faTruckMonster,\n faTruckMoving: faTruckMoving,\n faTruckPickup: faTruckPickup,\n faTshirt: faTshirt,\n faTty: faTty,\n faTv: faTv,\n faUmbrella: faUmbrella,\n faUmbrellaBeach: faUmbrellaBeach,\n faUnderline: faUnderline,\n faUndo: faUndo,\n faUndoAlt: faUndoAlt,\n faUniversalAccess: faUniversalAccess,\n faUniversity: faUniversity,\n faUnlink: faUnlink,\n faUnlock: faUnlock,\n faUnlockAlt: faUnlockAlt,\n faUpload: faUpload,\n faUser: faUser,\n faUserAlt: faUserAlt,\n faUserAltSlash: faUserAltSlash,\n faUserAstronaut: faUserAstronaut,\n faUserCheck: faUserCheck,\n faUserCircle: faUserCircle,\n faUserClock: faUserClock,\n faUserCog: faUserCog,\n faUserEdit: faUserEdit,\n faUserFriends: faUserFriends,\n faUserGraduate: faUserGraduate,\n faUserInjured: faUserInjured,\n faUserLock: faUserLock,\n faUserMd: faUserMd,\n faUserMinus: faUserMinus,\n faUserNinja: faUserNinja,\n faUserNurse: faUserNurse,\n faUserPlus: faUserPlus,\n faUserSecret: faUserSecret,\n faUserShield: faUserShield,\n faUserSlash: faUserSlash,\n faUserTag: faUserTag,\n faUserTie: faUserTie,\n faUserTimes: faUserTimes,\n faUsers: faUsers,\n faUsersCog: faUsersCog,\n faUtensilSpoon: faUtensilSpoon,\n faUtensils: faUtensils,\n faVectorSquare: faVectorSquare,\n faVenus: faVenus,\n faVenusDouble: faVenusDouble,\n faVenusMars: faVenusMars,\n faVial: faVial,\n faVials: faVials,\n faVideo: faVideo,\n faVideoSlash: faVideoSlash,\n faVihara: faVihara,\n faVolleyballBall: faVolleyballBall,\n faVolumeDown: faVolumeDown,\n faVolumeMute: faVolumeMute,\n faVolumeOff: faVolumeOff,\n faVolumeUp: faVolumeUp,\n faVoteYea: faVoteYea,\n faVrCardboard: faVrCardboard,\n faWalking: faWalking,\n faWallet: faWallet,\n faWarehouse: faWarehouse,\n faWater: faWater,\n faWeight: faWeight,\n faWeightHanging: faWeightHanging,\n faWheelchair: faWheelchair,\n faWifi: faWifi,\n faWind: faWind,\n faWindowClose: faWindowClose,\n faWindowMaximize: faWindowMaximize,\n faWindowMinimize: faWindowMinimize,\n faWindowRestore: faWindowRestore,\n faWineBottle: faWineBottle,\n faWineGlass: faWineGlass,\n faWineGlassAlt: faWineGlassAlt,\n faWonSign: faWonSign,\n faWrench: faWrench,\n faXRay: faXRay,\n faYenSign: faYenSign,\n faYinYang: faYinYang\n};\n\nexport { _iconsCache as fas, prefix, faAd, faAddressBook, faAddressCard, faAdjust, faAirFreshener, faAlignCenter, faAlignJustify, faAlignLeft, faAlignRight, faAllergies, faAmbulance, faAmericanSignLanguageInterpreting, faAnchor, faAngleDoubleDown, faAngleDoubleLeft, faAngleDoubleRight, faAngleDoubleUp, faAngleDown, faAngleLeft, faAngleRight, faAngleUp, faAngry, faAnkh, faAppleAlt, faArchive, faArchway, faArrowAltCircleDown, faArrowAltCircleLeft, faArrowAltCircleRight, faArrowAltCircleUp, faArrowCircleDown, faArrowCircleLeft, faArrowCircleRight, faArrowCircleUp, faArrowDown, faArrowLeft, faArrowRight, faArrowUp, faArrowsAlt, faArrowsAltH, faArrowsAltV, faAssistiveListeningSystems, faAsterisk, faAt, faAtlas, faAtom, faAudioDescription, faAward, faBaby, faBabyCarriage, faBackspace, faBackward, faBacon, faBalanceScale, faBan, faBandAid, faBarcode, faBars, faBaseballBall, faBasketballBall, faBath, faBatteryEmpty, faBatteryFull, faBatteryHalf, faBatteryQuarter, faBatteryThreeQuarters, faBed, faBeer, faBell, faBellSlash, faBezierCurve, faBible, faBicycle, faBinoculars, faBiohazard, faBirthdayCake, faBlender, faBlenderPhone, faBlind, faBlog, faBold, faBolt, faBomb, faBone, faBong, faBook, faBookDead, faBookMedical, faBookOpen, faBookReader, faBookmark, faBowlingBall, faBox, faBoxOpen, faBoxes, faBraille, faBrain, faBreadSlice, faBriefcase, faBriefcaseMedical, faBroadcastTower, faBroom, faBrush, faBug, faBuilding, faBullhorn, faBullseye, faBurn, faBus, faBusAlt, faBusinessTime, faCalculator, faCalendar, faCalendarAlt, faCalendarCheck, faCalendarDay, faCalendarMinus, faCalendarPlus, faCalendarTimes, faCalendarWeek, faCamera, faCameraRetro, faCampground, faCandyCane, faCannabis, faCapsules, faCar, faCarAlt, faCarBattery, faCarCrash, faCarSide, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareLeft, faCaretSquareRight, faCaretSquareUp, faCaretUp, faCarrot, faCartArrowDown, faCartPlus, faCashRegister, faCat, faCertificate, faChair, faChalkboard, faChalkboardTeacher, faChargingStation, faChartArea, faChartBar, faChartLine, faChartPie, faCheck, faCheckCircle, faCheckDouble, faCheckSquare, faCheese, faChess, faChessBishop, faChessBoard, faChessKing, faChessKnight, faChessPawn, faChessQueen, faChessRook, faChevronCircleDown, faChevronCircleLeft, faChevronCircleRight, faChevronCircleUp, faChevronDown, faChevronLeft, faChevronRight, faChevronUp, faChild, faChurch, faCircle, faCircleNotch, faCity, faClinicMedical, faClipboard, faClipboardCheck, faClipboardList, faClock, faClone, faClosedCaptioning, faCloud, faCloudDownloadAlt, faCloudMeatball, faCloudMoon, faCloudMoonRain, faCloudRain, faCloudShowersHeavy, faCloudSun, faCloudSunRain, faCloudUploadAlt, faCocktail, faCode, faCodeBranch, faCoffee, faCog, faCogs, faCoins, faColumns, faComment, faCommentAlt, faCommentDollar, faCommentDots, faCommentMedical, faCommentSlash, faComments, faCommentsDollar, faCompactDisc, faCompass, faCompress, faCompressArrowsAlt, faConciergeBell, faCookie, faCookieBite, faCopy, faCopyright, faCouch, faCreditCard, faCrop, faCropAlt, faCross, faCrosshairs, faCrow, faCrown, faCrutch, faCube, faCubes, faCut, faDatabase, faDeaf, faDemocrat, faDesktop, faDharmachakra, faDiagnoses, faDice, faDiceD20, faDiceD6, faDiceFive, faDiceFour, faDiceOne, faDiceSix, faDiceThree, faDiceTwo, faDigitalTachograph, faDirections, faDivide, faDizzy, faDna, faDog, faDollarSign, faDolly, faDollyFlatbed, faDonate, faDoorClosed, faDoorOpen, faDotCircle, faDove, faDownload, faDraftingCompass, faDragon, faDrawPolygon, faDrum, faDrumSteelpan, faDrumstickBite, faDumbbell, faDumpster, faDumpsterFire, faDungeon, faEdit, faEgg, faEject, faEllipsisH, faEllipsisV, faEnvelope, faEnvelopeOpen, faEnvelopeOpenText, faEnvelopeSquare, faEquals, faEraser, faEthernet, faEuroSign, faExchangeAlt, faExclamation, faExclamationCircle, faExclamationTriangle, faExpand, faExpandArrowsAlt, faExternalLinkAlt, faExternalLinkSquareAlt, faEye, faEyeDropper, faEyeSlash, faFastBackward, faFastForward, faFax, faFeather, faFeatherAlt, faFemale, faFighterJet, faFile, faFileAlt, faFileArchive, faFileAudio, faFileCode, faFileContract, faFileCsv, faFileDownload, faFileExcel, faFileExport, faFileImage, faFileImport, faFileInvoice, faFileInvoiceDollar, faFileMedical, faFileMedicalAlt, faFilePdf, faFilePowerpoint, faFilePrescription, faFileSignature, faFileUpload, faFileVideo, faFileWord, faFill, faFillDrip, faFilm, faFilter, faFingerprint, faFire, faFireAlt, faFireExtinguisher, faFirstAid, faFish, faFistRaised, faFlag, faFlagCheckered, faFlagUsa, faFlask, faFlushed, faFolder, faFolderMinus, faFolderOpen, faFolderPlus, faFont, faFontAwesomeLogoFull, faFootballBall, faForward, faFrog, faFrown, faFrownOpen, faFunnelDollar, faFutbol, faGamepad, faGasPump, faGavel, faGem, faGenderless, faGhost, faGift, faGifts, faGlassCheers, faGlassMartini, faGlassMartiniAlt, faGlassWhiskey, faGlasses, faGlobe, faGlobeAfrica, faGlobeAmericas, faGlobeAsia, faGlobeEurope, faGolfBall, faGopuram, faGraduationCap, faGreaterThan, faGreaterThanEqual, faGrimace, faGrin, faGrinAlt, faGrinBeam, faGrinBeamSweat, faGrinHearts, faGrinSquint, faGrinSquintTears, faGrinStars, faGrinTears, faGrinTongue, faGrinTongueSquint, faGrinTongueWink, faGrinWink, faGripHorizontal, faGripLines, faGripLinesVertical, faGripVertical, faGuitar, faHSquare, faHamburger, faHammer, faHamsa, faHandHolding, faHandHoldingHeart, faHandHoldingUsd, faHandLizard, faHandMiddleFinger, faHandPaper, faHandPeace, faHandPointDown, faHandPointLeft, faHandPointRight, faHandPointUp, faHandPointer, faHandRock, faHandScissors, faHandSpock, faHands, faHandsHelping, faHandshake, faHanukiah, faHardHat, faHashtag, faHatWizard, faHaykal, faHdd, faHeading, faHeadphones, faHeadphonesAlt, faHeadset, faHeart, faHeartBroken, faHeartbeat, faHelicopter, faHighlighter, faHiking, faHippo, faHistory, faHockeyPuck, faHollyBerry, faHome, faHorse, faHorseHead, faHospital, faHospitalAlt, faHospitalSymbol, faHotTub, faHotdog, faHotel, faHourglass, faHourglassEnd, faHourglassHalf, faHourglassStart, faHouseDamage, faHryvnia, faICursor, faIceCream, faIcicles, faIdBadge, faIdCard, faIdCardAlt, faIgloo, faImage, faImages, faInbox, faIndent, faIndustry, faInfinity, faInfo, faInfoCircle, faItalic, faJedi, faJoint, faJournalWhills, faKaaba, faKey, faKeyboard, faKhanda, faKiss, faKissBeam, faKissWinkHeart, faKiwiBird, faLandmark, faLanguage, faLaptop, faLaptopCode, faLaptopMedical, faLaugh, faLaughBeam, faLaughSquint, faLaughWink, faLayerGroup, faLeaf, faLemon, faLessThan, faLessThanEqual, faLevelDownAlt, faLevelUpAlt, faLifeRing, faLightbulb, faLink, faLiraSign, faList, faListAlt, faListOl, faListUl, faLocationArrow, faLock, faLockOpen, faLongArrowAltDown, faLongArrowAltLeft, faLongArrowAltRight, faLongArrowAltUp, faLowVision, faLuggageCart, faMagic, faMagnet, faMailBulk, faMale, faMap, faMapMarked, faMapMarkedAlt, faMapMarker, faMapMarkerAlt, faMapPin, faMapSigns, faMarker, faMars, faMarsDouble, faMarsStroke, faMarsStrokeH, faMarsStrokeV, faMask, faMedal, faMedkit, faMeh, faMehBlank, faMehRollingEyes, faMemory, faMenorah, faMercury, faMeteor, faMicrochip, faMicrophone, faMicrophoneAlt, faMicrophoneAltSlash, faMicrophoneSlash, faMicroscope, faMinus, faMinusCircle, faMinusSquare, faMitten, faMobile, faMobileAlt, faMoneyBill, faMoneyBillAlt, faMoneyBillWave, faMoneyBillWaveAlt, faMoneyCheck, faMoneyCheckAlt, faMonument, faMoon, faMortarPestle, faMosque, faMotorcycle, faMountain, faMousePointer, faMugHot, faMusic, faNetworkWired, faNeuter, faNewspaper, faNotEqual, faNotesMedical, faObjectGroup, faObjectUngroup, faOilCan, faOm, faOtter, faOutdent, faPager, faPaintBrush, faPaintRoller, faPalette, faPallet, faPaperPlane, faPaperclip, faParachuteBox, faParagraph, faParking, faPassport, faPastafarianism, faPaste, faPause, faPauseCircle, faPaw, faPeace, faPen, faPenAlt, faPenFancy, faPenNib, faPenSquare, faPencilAlt, faPencilRuler, faPeopleCarry, faPepperHot, faPercent, faPercentage, faPersonBooth, faPhone, faPhoneSlash, faPhoneSquare, faPhoneVolume, faPiggyBank, faPills, faPizzaSlice, faPlaceOfWorship, faPlane, faPlaneArrival, faPlaneDeparture, faPlay, faPlayCircle, faPlug, faPlus, faPlusCircle, faPlusSquare, faPodcast, faPoll, faPollH, faPoo, faPooStorm, faPoop, faPortrait, faPoundSign, faPowerOff, faPray, faPrayingHands, faPrescription, faPrescriptionBottle, faPrescriptionBottleAlt, faPrint, faProcedures, faProjectDiagram, faPuzzlePiece, faQrcode, faQuestion, faQuestionCircle, faQuidditch, faQuoteLeft, faQuoteRight, faQuran, faRadiation, faRadiationAlt, faRainbow, faRandom, faReceipt, faRecycle, faRedo, faRedoAlt, faRegistered, faReply, faReplyAll, faRepublican, faRestroom, faRetweet, faRibbon, faRing, faRoad, faRobot, faRocket, faRoute, faRss, faRssSquare, faRubleSign, faRuler, faRulerCombined, faRulerHorizontal, faRulerVertical, faRunning, faRupeeSign, faSadCry, faSadTear, faSatellite, faSatelliteDish, faSave, faSchool, faScrewdriver, faScroll, faSdCard, faSearch, faSearchDollar, faSearchLocation, faSearchMinus, faSearchPlus, faSeedling, faServer, faShapes, faShare, faShareAlt, faShareAltSquare, faShareSquare, faShekelSign, faShieldAlt, faShip, faShippingFast, faShoePrints, faShoppingBag, faShoppingBasket, faShoppingCart, faShower, faShuttleVan, faSign, faSignInAlt, faSignLanguage, faSignOutAlt, faSignal, faSignature, faSimCard, faSitemap, faSkating, faSkiing, faSkiingNordic, faSkull, faSkullCrossbones, faSlash, faSleigh, faSlidersH, faSmile, faSmileBeam, faSmileWink, faSmog, faSmoking, faSmokingBan, faSms, faSnowboarding, faSnowflake, faSnowman, faSnowplow, faSocks, faSolarPanel, faSort, faSortAlphaDown, faSortAlphaUp, faSortAmountDown, faSortAmountUp, faSortDown, faSortNumericDown, faSortNumericUp, faSortUp, faSpa, faSpaceShuttle, faSpider, faSpinner, faSplotch, faSprayCan, faSquare, faSquareFull, faSquareRootAlt, faStamp, faStar, faStarAndCrescent, faStarHalf, faStarHalfAlt, faStarOfDavid, faStarOfLife, faStepBackward, faStepForward, faStethoscope, faStickyNote, faStop, faStopCircle, faStopwatch, faStore, faStoreAlt, faStream, faStreetView, faStrikethrough, faStroopwafel, faSubscript, faSubway, faSuitcase, faSuitcaseRolling, faSun, faSuperscript, faSurprise, faSwatchbook, faSwimmer, faSwimmingPool, faSynagogue, faSync, faSyncAlt, faSyringe, faTable, faTableTennis, faTablet, faTabletAlt, faTablets, faTachometerAlt, faTag, faTags, faTape, faTasks, faTaxi, faTeeth, faTeethOpen, faTemperatureHigh, faTemperatureLow, faTenge, faTerminal, faTextHeight, faTextWidth, faTh, faThLarge, faThList, faTheaterMasks, faThermometer, faThermometerEmpty, faThermometerFull, faThermometerHalf, faThermometerQuarter, faThermometerThreeQuarters, faThumbsDown, faThumbsUp, faThumbtack, faTicketAlt, faTimes, faTimesCircle, faTint, faTintSlash, faTired, faToggleOff, faToggleOn, faToilet, faToiletPaper, faToolbox, faTools, faTooth, faTorah, faToriiGate, faTractor, faTrademark, faTrafficLight, faTrain, faTram, faTransgender, faTransgenderAlt, faTrash, faTrashAlt, faTrashRestore, faTrashRestoreAlt, faTree, faTrophy, faTruck, faTruckLoading, faTruckMonster, faTruckMoving, faTruckPickup, faTshirt, faTty, faTv, faUmbrella, faUmbrellaBeach, faUnderline, faUndo, faUndoAlt, faUniversalAccess, faUniversity, faUnlink, faUnlock, faUnlockAlt, faUpload, faUser, faUserAlt, faUserAltSlash, faUserAstronaut, faUserCheck, faUserCircle, faUserClock, faUserCog, faUserEdit, faUserFriends, faUserGraduate, faUserInjured, faUserLock, faUserMd, faUserMinus, faUserNinja, faUserNurse, faUserPlus, faUserSecret, faUserShield, faUserSlash, faUserTag, faUserTie, faUserTimes, faUsers, faUsersCog, faUtensilSpoon, faUtensils, faVectorSquare, faVenus, faVenusDouble, faVenusMars, faVial, faVials, faVideo, faVideoSlash, faVihara, faVolleyballBall, faVolumeDown, faVolumeMute, faVolumeOff, faVolumeUp, faVoteYea, faVrCardboard, faWalking, faWallet, faWarehouse, faWater, faWeight, faWeightHanging, faWheelchair, faWifi, faWind, faWindowClose, faWindowMaximize, faWindowMinimize, faWindowRestore, faWineBottle, faWineGlass, faWineGlassAlt, faWonSign, faWrench, faXRay, faYenSign, faYinYang };\n", + "import { parse, icon } from '@fortawesome/fontawesome-svg-core';\nimport PropTypes from 'prop-types';\nimport React from 'react';\n\nfunction _typeof(obj) {\n if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n _typeof = function (obj) {\n return typeof obj;\n };\n } else {\n _typeof = function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n };\n }\n\n return _typeof(obj);\n}\n\nfunction _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}\n\nfunction _objectSpread(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i] != null ? arguments[i] : {};\n var ownKeys = Object.keys(source);\n\n if (typeof Object.getOwnPropertySymbols === 'function') {\n ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {\n return Object.getOwnPropertyDescriptor(source, sym).enumerable;\n }));\n }\n\n ownKeys.forEach(function (key) {\n _defineProperty(target, key, source[key]);\n });\n }\n\n return target;\n}\n\nfunction _objectWithoutPropertiesLoose(source, excluded) {\n if (source == null) return {};\n var target = {};\n var sourceKeys = Object.keys(source);\n var key, i;\n\n for (i = 0; i < sourceKeys.length; i++) {\n key = sourceKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n target[key] = source[key];\n }\n\n return target;\n}\n\nfunction _objectWithoutProperties(source, excluded) {\n if (source == null) return {};\n\n var target = _objectWithoutPropertiesLoose(source, excluded);\n\n var key, i;\n\n if (Object.getOwnPropertySymbols) {\n var sourceSymbolKeys = Object.getOwnPropertySymbols(source);\n\n for (i = 0; i < sourceSymbolKeys.length; i++) {\n key = sourceSymbolKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n target[key] = source[key];\n }\n }\n\n return target;\n}\n\nfunction _toConsumableArray(arr) {\n return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();\n}\n\nfunction _arrayWithoutHoles(arr) {\n if (Array.isArray(arr)) {\n for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];\n\n return arr2;\n }\n}\n\nfunction _iterableToArray(iter) {\n if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter);\n}\n\nfunction _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance\");\n}\n\nvar commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n\nfunction createCommonjsModule(fn, module) {\n\treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n}\n\nvar humps = createCommonjsModule(function (module) {\n(function(global) {\n\n var _processKeys = function(convert, obj, options) {\n if(!_isObject(obj) || _isDate(obj) || _isRegExp(obj) || _isBoolean(obj) || _isFunction(obj)) {\n return obj;\n }\n\n var output,\n i = 0,\n l = 0;\n\n if(_isArray(obj)) {\n output = [];\n for(l=obj.length; i 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n if (typeof element === 'string') {\n return element;\n }\n\n var children = (element.children || []).map(function (child) {\n return convert(createElement, child);\n });\n var mixins = Object.keys(element.attributes || {}).reduce(function (acc, key) {\n var val = element.attributes[key];\n\n switch (key) {\n case 'class':\n acc.attrs['className'] = val;\n delete element.attributes['class'];\n break;\n\n case 'style':\n acc.attrs['style'] = styleToObject(val);\n break;\n\n default:\n if (key.indexOf('aria-') === 0 || key.indexOf('data-') === 0) {\n acc.attrs[key.toLowerCase()] = val;\n } else {\n acc.attrs[humps.camelize(key)] = val;\n }\n\n }\n\n return acc;\n }, {\n attrs: {}\n });\n\n var _extraProps$style = extraProps.style,\n existingStyle = _extraProps$style === void 0 ? {} : _extraProps$style,\n remaining = _objectWithoutProperties(extraProps, [\"style\"]);\n\n mixins.attrs['style'] = _objectSpread({}, mixins.attrs['style'], existingStyle);\n return createElement.apply(void 0, [element.tag, _objectSpread({}, mixins.attrs, remaining)].concat(_toConsumableArray(children)));\n}\n\nvar PRODUCTION = false;\n\ntry {\n PRODUCTION = process.env.NODE_ENV === 'production';\n} catch (e) {}\n\nfunction log () {\n if (!PRODUCTION && console && typeof console.error === 'function') {\n var _console;\n\n (_console = console).error.apply(_console, arguments);\n }\n}\n\nfunction objectWithKey(key, value) {\n return Array.isArray(value) && value.length > 0 || !Array.isArray(value) && value ? _defineProperty({}, key, value) : {};\n}\n\nfunction classList(props) {\n var _classes;\n\n var classes = (_classes = {\n 'fa-spin': props.spin,\n 'fa-pulse': props.pulse,\n 'fa-fw': props.fixedWidth,\n 'fa-inverse': props.inverse,\n 'fa-border': props.border,\n 'fa-li': props.listItem,\n 'fa-flip-horizontal': props.flip === 'horizontal' || props.flip === 'both',\n 'fa-flip-vertical': props.flip === 'vertical' || props.flip === 'both'\n }, _defineProperty(_classes, \"fa-\".concat(props.size), props.size !== null), _defineProperty(_classes, \"fa-rotate-\".concat(props.rotation), props.rotation !== null), _defineProperty(_classes, \"fa-pull-\".concat(props.pull), props.pull !== null), _classes);\n return Object.keys(classes).map(function (key) {\n return classes[key] ? key : null;\n }).filter(function (key) {\n return key;\n });\n}\n\nfunction normalizeIconArgs(icon$$1) {\n if (icon$$1 === null) {\n return null;\n }\n\n if (_typeof(icon$$1) === 'object' && icon$$1.prefix && icon$$1.iconName) {\n return icon$$1;\n }\n\n if (Array.isArray(icon$$1) && icon$$1.length === 2) {\n return {\n prefix: icon$$1[0],\n iconName: icon$$1[1]\n };\n }\n\n if (typeof icon$$1 === 'string') {\n return {\n prefix: 'fas',\n iconName: icon$$1\n };\n }\n}\n\nfunction FontAwesomeIcon(props) {\n var iconArgs = props.icon,\n maskArgs = props.mask,\n symbol = props.symbol,\n className = props.className,\n title = props.title;\n var iconLookup = normalizeIconArgs(iconArgs);\n var classes = objectWithKey('classes', [].concat(_toConsumableArray(classList(props)), _toConsumableArray(className.split(' '))));\n var transform = objectWithKey('transform', typeof props.transform === 'string' ? parse.transform(props.transform) : props.transform);\n var mask = objectWithKey('mask', normalizeIconArgs(maskArgs));\n var renderedIcon = icon(iconLookup, _objectSpread({}, classes, transform, mask, {\n symbol: symbol,\n title: title\n }));\n\n if (!renderedIcon) {\n log('Could not find icon', iconLookup);\n return null;\n }\n\n var abstract = renderedIcon.abstract;\n var extraProps = {};\n Object.keys(props).forEach(function (key) {\n if (!FontAwesomeIcon.defaultProps.hasOwnProperty(key)) {\n extraProps[key] = props[key];\n }\n });\n return convertCurry(abstract[0], extraProps);\n}\nFontAwesomeIcon.displayName = 'FontAwesomeIcon';\nFontAwesomeIcon.propTypes = {\n border: PropTypes.bool,\n className: PropTypes.string,\n mask: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.string]),\n fixedWidth: PropTypes.bool,\n inverse: PropTypes.bool,\n flip: PropTypes.oneOf(['horizontal', 'vertical', 'both']),\n icon: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.string]),\n listItem: PropTypes.bool,\n pull: PropTypes.oneOf(['right', 'left']),\n pulse: PropTypes.bool,\n rotation: PropTypes.oneOf([90, 180, 270]),\n size: PropTypes.oneOf(['lg', 'xs', 'sm', '1x', '2x', '3x', '4x', '5x', '6x', '7x', '8x', '9x', '10x']),\n spin: PropTypes.bool,\n symbol: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),\n title: PropTypes.string,\n transform: PropTypes.oneOfType([PropTypes.string, PropTypes.object])\n};\nFontAwesomeIcon.defaultProps = {\n border: false,\n className: '',\n mask: null,\n fixedWidth: false,\n inverse: false,\n flip: null,\n icon: null,\n listItem: false,\n pull: null,\n pulse: false,\n rotation: null,\n size: null,\n spin: false,\n symbol: false,\n title: '',\n transform: null\n};\nvar convertCurry = convert.bind(null, React.createElement);\n\nexport { FontAwesomeIcon };\n", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _helpers = require(\"../utils/helpers\");\n\nvar _Paper = _interopRequireDefault(require(\"../Paper\"));\n\n// @inheritedComponent Paper\nvar styles = function styles(theme) {\n var backgroundColorDefault = theme.palette.type === 'light' ? theme.palette.grey[100] : theme.palette.grey[900];\n return {\n /* Styles applied to the root element. */\n root: {\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n boxSizing: 'border-box',\n // Prevent padding issue with the Modal and fixed positioned AppBar.\n zIndex: theme.zIndex.appBar,\n flexShrink: 0\n },\n\n /* Styles applied to the root element if `)))) + ((("`" + (`position=\"fixed\"` + "`")) + (`. */\n positionFixed: {\n position: 'fixed',\n top: 0,\n left: 'auto',\n right: 0\n },\n\n /* Styles applied to the root element if ` + ("`" + `position=\"absolute\"`))) + (("`" + (`. */\n positionAbsolute: {\n position: 'absolute',\n top: 0,\n left: 'auto',\n right: 0\n },\n\n /* Styles applied to the root element if ` + "`")) + (`position=\"sticky\"` + ("`" + `. */\n positionSticky: {\n position: 'sticky',\n top: 0,\n left: 'auto',\n right: 0\n },\n\n /* Styles applied to the root element if `)))))))) + ((((((("`" + `position=\"static\"`) + ("`" + (`. */\n positionStatic: {\n position: 'static'\n },\n\n /* Styles applied to the root element if ` + "`"))) + ((`position=\"relative\"` + ("`" + `. */\n positionRelative: {\n position: 'relative'\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`color=\"default\"` + "`")))) + (((`. */\n colorDefault: {\n backgroundColor: backgroundColorDefault,\n color: theme.palette.getContrastText(backgroundColorDefault)\n },\n\n /* Styles applied to the root element if ` + "`") + (`color=\"primary\"` + ("`" + `. */\n colorPrimary: {\n backgroundColor: theme.palette.primary.main,\n color: theme.palette.primary.contrastText\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`color=\"secondary\"` + "`")) + (`. */\n colorSecondary: {\n backgroundColor: theme.palette.secondary.main,\n color: theme.palette.secondary.contrastText\n }\n };\n};\n\nexports.styles = styles;\n\nfunction AppBar(props) {\n var _classNames;\n\n var children = props.children,\n classes = props.classes,\n classNameProp = props.className,\n color = props.color,\n position = props.position,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\", \"color\", \"position\"]);\n var className = (0, _classnames.default)(classes.root, classes[\"position\".concat((0, _helpers.capitalize)(position))], (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes[\"color\".concat((0, _helpers.capitalize)(color))], color !== 'inherit'), (0, _defineProperty2.default)(_classNames, 'mui-fixed', position === 'fixed'), _classNames), classNameProp);\n return _react.default.createElement(_Paper.default, (0, _extends2.default)({\n square: true,\n component: \"header\",\n elevation: 4,\n className: className\n }, other), children);\n}\n\nprocess.env.NODE_ENV !== \"production\" ? AppBar.propTypes = {\n /**\r\n * The content of the component.\r\n */\n children: _propTypes.default.node.isRequired,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The color of the component. It supports those theme colors that make sense for this component.\r\n */\n color: _propTypes.default.oneOf(['inherit', 'primary', 'secondary', 'default']),\n\n /**\r\n * The positioning type. The behavior of the different options is described\r\n * [in the MDN web docs](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Positioning).\r\n * Note: ` + ("`" + `sticky`))))) + (((("`" + ` is not universally supported and will fall back to `) + ("`" + (`static` + "`"))) + ((` when unavailable.\r\n */\n position: _propTypes.default.oneOf(['fixed', 'absolute', 'sticky', 'static', 'relative'])\n} : void 0;\nAppBar.defaultProps = {\n color: 'primary',\n position: 'fixed'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiAppBar'\n})(AppBar);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _AppBar.default;\n }\n});\n\nvar _AppBar = _interopRequireDefault(require(\"./AppBar\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf3 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _assertThisInitialized2 = _interopRequireDefault(require(\"@babel/runtime/helpers/assertThisInitialized\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _reactDom = _interopRequireDefault(require(\"react-dom\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _ownerWindow = _interopRequireDefault(require(\"../utils/ownerWindow\"));\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _NoSsr = _interopRequireDefault(require(\"../NoSsr\"));\n\nvar _focusVisible = require(\"./focusVisible\");\n\nvar _TouchRipple = _interopRequireDefault(require(\"./TouchRipple\"));\n\nvar _createRippleHandler = _interopRequireDefault(require(\"./createRippleHandler\"));\n\nvar styles = {\n /* Styles applied to the root element. */\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n position: 'relative',\n // Remove grey highlight\n WebkitTapHighlightColor: 'transparent',\n backgroundColor: 'transparent',\n // Reset default value\n // We disable the focus ring for mouse, touch and keyboard users.\n outline: 'none',\n border: 0,\n margin: 0,\n // Remove the margin in Safari\n borderRadius: 0,\n padding: 0,\n // Remove the padding in Firefox\n cursor: 'pointer',\n userSelect: 'none',\n verticalAlign: 'middle',\n '-moz-appearance': 'none',\n // Reset\n '-webkit-appearance': 'none',\n // Reset\n textDecoration: 'none',\n // So we take precedent over the style of a native element.\n color: 'inherit',\n '&::-moz-focus-inner': {\n borderStyle: 'none' // Remove Firefox dotted outline.\n\n },\n '&$disabled': {\n pointerEvents: 'none',\n // Disable link interactions\n cursor: 'default'\n }\n },\n\n /* Styles applied to the root element if ` + ("`" + `disabled={true}`)) + ("`" + (`. */\n disabled: {},\n\n /* Styles applied to the root element if keyboard focused. */\n focusVisible: {}\n};\n/* istanbul ignore if */\n\nexports.styles = styles;\n\nif (process.env.NODE_ENV !== 'production' && !_react.default.createContext) {\n throw new Error('Material-UI: react@16.3.0 or greater is required.');\n}\n/**\r\n * ` + "`")))) + (((`ButtonBase` + "`") + (` contains as few styles as possible.\r\n * It aims to be a simple building block for creating a button.\r\n * It contains a load of style reset and some focus/ripple logic.\r\n */\n\n\nvar ButtonBase =\n/*#__PURE__*/\nfunction (_React$Component) {\n (0, _inherits2.default)(ButtonBase, _React$Component);\n\n function ButtonBase() {\n var _getPrototypeOf2;\n\n var _this;\n\n (0, _classCallCheck2.default)(this, ButtonBase);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(ButtonBase)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {};\n _this.keyDown = false;\n _this.focusVisibleCheckTime = 50;\n _this.focusVisibleMaxCheckTimes = 5;\n _this.handleMouseDown = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'MouseDown', 'start', function () {\n clearTimeout(_this.focusVisibleTimeout);\n\n if (_this.state.focusVisible) {\n _this.setState({\n focusVisible: false\n });\n }\n });\n _this.handleMouseUp = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'MouseUp', 'stop');\n _this.handleMouseLeave = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'MouseLeave', 'stop', function (event) {\n if (_this.state.focusVisible) {\n event.preventDefault();\n }\n });\n _this.handleTouchStart = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'TouchStart', 'start');\n _this.handleTouchEnd = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'TouchEnd', 'stop');\n _this.handleTouchMove = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'TouchMove', 'stop');\n _this.handleContextMenu = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'ContextMenu', 'stop');\n _this.handleBlur = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'Blur', 'stop', function () {\n clearTimeout(_this.focusVisibleTimeout);\n\n if (_this.state.focusVisible) {\n _this.setState({\n focusVisible: false\n });\n }\n });\n\n _this.onRippleRef = function (node) {\n _this.ripple = node;\n };\n\n _this.onFocusVisibleHandler = function (event) {\n _this.keyDown = false;\n\n _this.setState({\n focusVisible: true\n });\n\n if (_this.props.onFocusVisible) {\n _this.props.onFocusVisible(event);\n }\n };\n\n _this.handleKeyDown = function (event) {\n var _this$props = _this.props,\n component = _this$props.component,\n focusRipple = _this$props.focusRipple,\n onKeyDown = _this$props.onKeyDown,\n onClick = _this$props.onClick; // Check if key is already down to avoid repeats being counted as multiple activations\n\n if (focusRipple && !_this.keyDown && _this.state.focusVisible && _this.ripple && event.key === ' ') {\n _this.keyDown = true;\n event.persist();\n\n _this.ripple.stop(event, function () {\n _this.ripple.start(event);\n });\n }\n\n if (onKeyDown) {\n onKeyDown(event);\n } // Keyboard accessibility for non interactive elements\n\n\n if (event.target === event.currentTarget && component && component !== 'button' && (event.key === ' ' || event.key === 'Enter') && !(_this.button.tagName === 'A' && _this.button.href)) {\n event.preventDefault();\n\n if (onClick) {\n onClick(event);\n }\n }\n };\n\n _this.handleKeyUp = function (event) {\n if (_this.props.focusRipple && event.key === ' ' && _this.ripple && _this.state.focusVisible) {\n _this.keyDown = false;\n event.persist();\n\n _this.ripple.stop(event, function () {\n _this.ripple.pulsate(event);\n });\n }\n\n if (_this.props.onKeyUp) {\n _this.props.onKeyUp(event);\n }\n };\n\n _this.handleFocus = function (event) {\n if (_this.props.disabled) {\n return;\n } // Fix for https://github.com/facebook/react/issues/7769\n\n\n if (!_this.button) {\n _this.button = event.currentTarget;\n }\n\n event.persist();\n (0, _focusVisible.detectFocusVisible)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), _this.button, function () {\n _this.onFocusVisibleHandler(event);\n });\n\n if (_this.props.onFocus) {\n _this.props.onFocus(event);\n }\n };\n\n return _this;\n }\n\n (0, _createClass2.default)(ButtonBase, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this2 = this;\n\n this.button = _reactDom.default.findDOMNode(this);\n (0, _focusVisible.listenForFocusKeys)((0, _ownerWindow.default)(this.button));\n\n if (this.props.action) {\n this.props.action({\n focusVisible: function focusVisible() {\n _this2.setState({\n focusVisible: true\n });\n\n _this2.button.focus();\n }\n });\n }\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate(prevProps, prevState) {\n if (this.props.focusRipple && !this.props.disableRipple && !prevState.focusVisible && this.state.focusVisible) {\n this.ripple.pulsate();\n }\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n clearTimeout(this.focusVisibleTimeout);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _classNames;\n\n var _this$props2 = this.props,\n action = _this$props2.action,\n buttonRef = _this$props2.buttonRef,\n centerRipple = _this$props2.centerRipple,\n children = _this$props2.children,\n classes = _this$props2.classes,\n classNameProp = _this$props2.className,\n component = _this$props2.component,\n disabled = _this$props2.disabled,\n disableRipple = _this$props2.disableRipple,\n disableTouchRipple = _this$props2.disableTouchRipple,\n focusRipple = _this$props2.focusRipple,\n focusVisibleClassName = _this$props2.focusVisibleClassName,\n onBlur = _this$props2.onBlur,\n onFocus = _this$props2.onFocus,\n onFocusVisible = _this$props2.onFocusVisible,\n onKeyDown = _this$props2.onKeyDown,\n onKeyUp = _this$props2.onKeyUp,\n onMouseDown = _this$props2.onMouseDown,\n onMouseLeave = _this$props2.onMouseLeave,\n onMouseUp = _this$props2.onMouseUp,\n onTouchEnd = _this$props2.onTouchEnd,\n onTouchMove = _this$props2.onTouchMove,\n onTouchStart = _this$props2.onTouchStart,\n tabIndex = _this$props2.tabIndex,\n TouchRippleProps = _this$props2.TouchRippleProps,\n type = _this$props2.type,\n other = (0, _objectWithoutProperties2.default)(_this$props2, [\"action\", \"buttonRef\", \"centerRipple\", \"children\", \"classes\", \"className\", \"component\", \"disabled\", \"disableRipple\", \"disableTouchRipple\", \"focusRipple\", \"focusVisibleClassName\", \"onBlur\", \"onFocus\", \"onFocusVisible\", \"onKeyDown\", \"onKeyUp\", \"onMouseDown\", \"onMouseLeave\", \"onMouseUp\", \"onTouchEnd\", \"onTouchMove\", \"onTouchStart\", \"tabIndex\", \"TouchRippleProps\", \"type\"]);\n var className = (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.disabled, disabled), (0, _defineProperty2.default)(_classNames, classes.focusVisible, this.state.focusVisible), (0, _defineProperty2.default)(_classNames, focusVisibleClassName, this.state.focusVisible), _classNames), classNameProp);\n var ComponentProp = component;\n\n if (ComponentProp === 'button' && other.href) {\n ComponentProp = 'a';\n }\n\n var buttonProps = {};\n\n if (ComponentProp === 'button') {\n buttonProps.type = type || 'button';\n buttonProps.disabled = disabled;\n } else {\n buttonProps.role = 'button';\n }\n\n return _react.default.createElement(ComponentProp, (0, _extends2.default)({\n className: className,\n onBlur: this.handleBlur,\n onFocus: this.handleFocus,\n onKeyDown: this.handleKeyDown,\n onKeyUp: this.handleKeyUp,\n onMouseDown: this.handleMouseDown,\n onMouseLeave: this.handleMouseLeave,\n onMouseUp: this.handleMouseUp,\n onTouchEnd: this.handleTouchEnd,\n onTouchMove: this.handleTouchMove,\n onTouchStart: this.handleTouchStart,\n onContextMenu: this.handleContextMenu,\n ref: buttonRef,\n tabIndex: disabled ? '-1' : tabIndex\n }, buttonProps, other), children, !disableRipple && !disabled ? _react.default.createElement(_NoSsr.default, null, _react.default.createElement(_TouchRipple.default, (0, _extends2.default)({\n innerRef: this.onRippleRef,\n center: centerRipple\n }, TouchRippleProps))) : null);\n }\n }], [{\n key: \"getDerivedStateFromProps\",\n value: function getDerivedStateFromProps(nextProps, prevState) {\n if (typeof prevState.focusVisible === 'undefined') {\n return {\n focusVisible: false,\n lastDisabled: nextProps.disabled\n };\n } // The blur won't fire when the disabled state is set on a focused input.\n // We need to book keep the focused state manually.\n\n\n if (!prevState.prevState && nextProps.disabled && prevState.focusVisible) {\n return {\n focusVisible: false,\n lastDisabled: nextProps.disabled\n };\n }\n\n return {\n lastDisabled: nextProps.disabled\n };\n }\n }]);\n return ButtonBase;\n}(_react.default.Component);\n\nprocess.env.NODE_ENV !== \"production\" ? ButtonBase.propTypes = {\n /**\r\n * Callback fired when the component mounts.\r\n * This is useful when you want to trigger an action programmatically.\r\n * It currently only supports ` + ("`" + `focusVisible()`))) + (("`" + (` action.\r\n *\r\n * @param {object} actions This object contains all possible actions\r\n * that can be triggered programmatically.\r\n */\n action: _propTypes.default.func,\n\n /**\r\n * Use that property to pass a ref callback to the native button component.\r\n */\n buttonRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object]),\n\n /**\r\n * If ` + "`")) + (`true` + ("`" + `, the ripples will be centered.\r\n * They won't start at the cursor interaction position.\r\n */\n centerRipple: _propTypes.default.bool,\n\n /**\r\n * The content of the component.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * If `)))))) + ((((("`" + `true`) + ("`" + (`, the base button will be disabled.\r\n */\n disabled: _propTypes.default.bool,\n\n /**\r\n * If ` + "`"))) + ((`true` + ("`" + `, the ripple effect will be disabled.\r\n */\n disableRipple: _propTypes.default.bool,\n\n /**\r\n * If `)) + ("`" + (`true` + "`")))) + (((`, the touch ripple effect will be disabled.\r\n */\n disableTouchRipple: _propTypes.default.bool,\n\n /**\r\n * If ` + "`") + (`true` + ("`" + `, the base button will have a keyboard focus ripple.\r\n * `))) + (("`" + (`disableRipple` + "`")) + (` must also be ` + ("`" + `false`))))) + (((("`" + `.\r\n */\n focusRipple: _propTypes.default.bool,\n\n /**\r\n * This property can help a person know which element has the keyboard focus.\r\n * The class name will be applied when the element gain the focus through a keyboard interaction.\r\n * It's a polyfill for the [CSS :focus-visible selector](https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo).\r\n * The rationale for using this feature [is explained here](https://github.com/WICG/focus-visible/blob/master/explainer.md).\r\n * A [polyfill can be used](https://github.com/WICG/focus-visible) to apply a `) + ("`" + (`focus-visible` + "`"))) + ((` class to other components\r\n * if needed.\r\n */\n focusVisibleClassName: _propTypes.default.string,\n\n /**\r\n * @ignore\r\n */\n onBlur: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onClick: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onFocus: _propTypes.default.func,\n\n /**\r\n * Callback fired when the component is focused with a keyboard.\r\n * We trigger a ` + ("`" + `onFocus`)) + ("`" + (` callback too.\r\n */\n onFocusVisible: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onKeyDown: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onKeyUp: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onMouseDown: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onMouseLeave: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onMouseUp: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onTouchEnd: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onTouchMove: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n onTouchStart: _propTypes.default.func,\n\n /**\r\n * @ignore\r\n */\n role: _propTypes.default.string,\n\n /**\r\n * @ignore\r\n */\n tabIndex: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),\n\n /**\r\n * Properties applied to the ` + "`")))) + (((`TouchRipple` + "`") + (` element.\r\n */\n TouchRippleProps: _propTypes.default.object,\n\n /**\r\n * Used to control the button's purpose.\r\n * This property passes the value to the ` + ("`" + `type`))) + (("`" + (` attribute of the native button component.\r\n * Valid property values include ` + "`")) + (`button` + ("`" + `, `))))))) + (((((("`" + `submit`) + ("`" + (`, and ` + "`"))) + ((`reset` + ("`" + `.\r\n */\n type: _propTypes.default.string\n} : void 0;\nButtonBase.defaultProps = {\n centerRipple: false,\n component: 'button',\n disableRipple: false,\n disableTouchRipple: false,\n focusRipple: false,\n tabIndex: '0',\n type: 'button'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiButtonBase'\n})(ButtonBase);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf3 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _Transition = _interopRequireDefault(require(\"react-transition-group/Transition\"));\n\n/**\r\n * @ignore - internal component.\r\n */\nvar Ripple =\n/*#__PURE__*/\nfunction (_React$Component) {\n (0, _inherits2.default)(Ripple, _React$Component);\n\n function Ripple() {\n var _getPrototypeOf2;\n\n var _this;\n\n (0, _classCallCheck2.default)(this, Ripple);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(Ripple)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n visible: false,\n leaving: false\n };\n\n _this.handleEnter = function () {\n _this.setState({\n visible: true\n });\n };\n\n _this.handleExit = function () {\n _this.setState({\n leaving: true\n });\n };\n\n return _this;\n }\n\n (0, _createClass2.default)(Ripple, [{\n key: \"render\",\n value: function render() {\n var _classNames, _classNames2;\n\n var _this$props = this.props,\n classes = _this$props.classes,\n classNameProp = _this$props.className,\n pulsate = _this$props.pulsate,\n rippleX = _this$props.rippleX,\n rippleY = _this$props.rippleY,\n rippleSize = _this$props.rippleSize,\n other = (0, _objectWithoutProperties2.default)(_this$props, [\"classes\", \"className\", \"pulsate\", \"rippleX\", \"rippleY\", \"rippleSize\"]);\n var _this$state = this.state,\n visible = _this$state.visible,\n leaving = _this$state.leaving;\n var rippleClassName = (0, _classnames.default)(classes.ripple, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.rippleVisible, visible), (0, _defineProperty2.default)(_classNames, classes.ripplePulsate, pulsate), _classNames), classNameProp);\n var rippleStyles = {\n width: rippleSize,\n height: rippleSize,\n top: -(rippleSize / 2) + rippleY,\n left: -(rippleSize / 2) + rippleX\n };\n var childClassName = (0, _classnames.default)(classes.child, (_classNames2 = {}, (0, _defineProperty2.default)(_classNames2, classes.childLeaving, leaving), (0, _defineProperty2.default)(_classNames2, classes.childPulsate, pulsate), _classNames2));\n return _react.default.createElement(_Transition.default, (0, _extends2.default)({\n onEnter: this.handleEnter,\n onExit: this.handleExit\n }, other), _react.default.createElement(\"span\", {\n className: rippleClassName,\n style: rippleStyles\n }, _react.default.createElement(\"span\", {\n className: childClassName\n })));\n }\n }]);\n return Ripple;\n}(_react.default.Component);\n\nprocess.env.NODE_ENV !== \"production\" ? Ripple.propTypes = {\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * If `)) + ("`" + (`true` + "`")))) + (((`, the ripple pulsates, typically indicating the keyboard focus state of an element.\r\n */\n pulsate: _propTypes.default.bool,\n\n /**\r\n * Diameter of the ripple.\r\n */\n rippleSize: _propTypes.default.number,\n\n /**\r\n * Horizontal position of the ripple center.\r\n */\n rippleX: _propTypes.default.number,\n\n /**\r\n * Vertical position of the ripple center.\r\n */\n rippleY: _propTypes.default.number\n} : void 0;\nRipple.defaultProps = {\n pulsate: false\n};\nvar _default = Ripple;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = exports.DELAY_RIPPLE = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _toConsumableArray2 = _interopRequireDefault(require(\"@babel/runtime/helpers/toConsumableArray\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf3 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _assertThisInitialized2 = _interopRequireDefault(require(\"@babel/runtime/helpers/assertThisInitialized\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _reactDom = _interopRequireDefault(require(\"react-dom\"));\n\nvar _TransitionGroup = _interopRequireDefault(require(\"react-transition-group/TransitionGroup\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _Ripple = _interopRequireDefault(require(\"./Ripple\"));\n\nvar DURATION = 550;\nvar DELAY_RIPPLE = 80;\nexports.DELAY_RIPPLE = DELAY_RIPPLE;\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n display: 'block',\n position: 'absolute',\n overflow: 'hidden',\n borderRadius: 'inherit',\n width: '100%',\n height: '100%',\n left: 0,\n top: 0,\n pointerEvents: 'none',\n zIndex: 0\n },\n\n /* Styles applied to the internal ` + "`") + (`Ripple` + ("`" + ` components `))) + (("`" + (`ripple` + "`")) + (` class. */\n ripple: {\n width: 50,\n height: 50,\n left: 0,\n top: 0,\n opacity: 0,\n position: 'absolute'\n },\n\n /* Styles applied to the internal ` + ("`" + `Ripple`))))) + (((("`" + ` components `) + ("`" + (`rippleVisible` + "`"))) + ((` class. */\n rippleVisible: {\n opacity: 0.3,\n transform: 'scale(1)',\n animation: \"mui-ripple-enter \".concat(DURATION, \"ms \").concat(theme.transitions.easing.easeInOut),\n // Backward compatible logic between JSS v9 and v10.\n // To remove with the release of Material-UI v4\n animationName: '$mui-ripple-enter'\n },\n\n /* Styles applied to the internal ` + ("`" + `Ripple`)) + ("`" + (` components ` + "`")))) + (((`ripplePulsate` + "`") + (` class. */\n ripplePulsate: {\n animationDuration: \"\".concat(theme.transitions.duration.shorter, \"ms\")\n },\n\n /* Styles applied to the internal ` + ("`" + `Ripple`))) + (("`" + (` components ` + "`")) + (`child` + ("`" + ` class. */\n child: {\n opacity: 1,\n display: 'block',\n width: '100%',\n height: '100%',\n borderRadius: '50%',\n backgroundColor: 'currentColor'\n },\n\n /* Styles applied to the internal `)))))) + ((((("`" + `Ripple`) + ("`" + (` components ` + "`"))) + ((`childLeaving` + ("`" + ` class. */\n childLeaving: {\n opacity: 0,\n animation: \"mui-ripple-exit \".concat(DURATION, \"ms \").concat(theme.transitions.easing.easeInOut),\n // Backward compatible logic between JSS v9 and v10.\n // To remove with the release of Material-UI v4\n animationName: '$mui-ripple-exit'\n },\n\n /* Styles applied to the internal `)) + ("`" + (`Ripple` + "`")))) + (((` components ` + "`") + (`childPulsate` + ("`" + ` class. */\n childPulsate: {\n position: 'absolute',\n left: 0,\n top: 0,\n animation: \"mui-ripple-pulsate 2500ms \".concat(theme.transitions.easing.easeInOut, \" 200ms infinite\"),\n // Backward compatible logic between JSS v9 and v10.\n // To remove with the release of Material-UI v4\n animationName: '$mui-ripple-pulsate'\n },\n '@keyframes mui-ripple-enter': {\n '0%': {\n transform: 'scale(0)',\n opacity: 0.1\n },\n '100%': {\n transform: 'scale(1)',\n opacity: 0.3\n }\n },\n '@keyframes mui-ripple-exit': {\n '0%': {\n opacity: 1\n },\n '100%': {\n opacity: 0\n }\n },\n '@keyframes mui-ripple-pulsate': {\n '0%': {\n transform: 'scale(1)'\n },\n '50%': {\n transform: 'scale(0.92)'\n },\n '100%': {\n transform: 'scale(1)'\n }\n }\n };\n};\n\nexports.styles = styles;\n\nvar TouchRipple =\n/*#__PURE__*/\nfunction (_React$PureComponent) {\n (0, _inherits2.default)(TouchRipple, _React$PureComponent);\n\n function TouchRipple() {\n var _getPrototypeOf2;\n\n var _this;\n\n (0, _classCallCheck2.default)(this, TouchRipple);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(TouchRipple)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n nextKey: 0,\n ripples: []\n };\n\n _this.pulsate = function () {\n _this.start({}, {\n pulsate: true\n });\n };\n\n _this.start = function () {\n var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var cb = arguments.length > 2 ? arguments[2] : undefined;\n var _options$pulsate = options.pulsate,\n pulsate = _options$pulsate === void 0 ? false : _options$pulsate,\n _options$center = options.center,\n center = _options$center === void 0 ? _this.props.center || options.pulsate : _options$center,\n _options$fakeElement = options.fakeElement,\n fakeElement = _options$fakeElement === void 0 ? false : _options$fakeElement;\n\n if (event.type === 'mousedown' && _this.ignoringMouseDown) {\n _this.ignoringMouseDown = false;\n return;\n }\n\n if (event.type === 'touchstart') {\n _this.ignoringMouseDown = true;\n }\n\n var element = fakeElement ? null : _reactDom.default.findDOMNode((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));\n var rect = element ? element.getBoundingClientRect() : {\n width: 0,\n height: 0,\n left: 0,\n top: 0\n }; // Get the size of the ripple\n\n var rippleX;\n var rippleY;\n var rippleSize;\n\n if (center || event.clientX === 0 && event.clientY === 0 || !event.clientX && !event.touches) {\n rippleX = Math.round(rect.width / 2);\n rippleY = Math.round(rect.height / 2);\n } else {\n var clientX = event.clientX ? event.clientX : event.touches[0].clientX;\n var clientY = event.clientY ? event.clientY : event.touches[0].clientY;\n rippleX = Math.round(clientX - rect.left);\n rippleY = Math.round(clientY - rect.top);\n }\n\n if (center) {\n rippleSize = Math.sqrt((2 * Math.pow(rect.width, 2) + Math.pow(rect.height, 2)) / 3); // For some reason the animation is broken on Mobile Chrome if the size if even.\n\n if (rippleSize % 2 === 0) {\n rippleSize += 1;\n }\n } else {\n var sizeX = Math.max(Math.abs((element ? element.clientWidth : 0) - rippleX), rippleX) * 2 + 2;\n var sizeY = Math.max(Math.abs((element ? element.clientHeight : 0) - rippleY), rippleY) * 2 + 2;\n rippleSize = Math.sqrt(Math.pow(sizeX, 2) + Math.pow(sizeY, 2));\n } // Touche devices\n\n\n if (event.touches) {\n // Prepare the ripple effect.\n _this.startTimerCommit = function () {\n _this.startCommit({\n pulsate: pulsate,\n rippleX: rippleX,\n rippleY: rippleY,\n rippleSize: rippleSize,\n cb: cb\n });\n }; // Delay the execution of the ripple effect.\n\n\n _this.startTimer = setTimeout(function () {\n if (_this.startTimerCommit) {\n _this.startTimerCommit();\n\n _this.startTimerCommit = null;\n }\n }, DELAY_RIPPLE); // We have to make a tradeoff with this value.\n } else {\n _this.startCommit({\n pulsate: pulsate,\n rippleX: rippleX,\n rippleY: rippleY,\n rippleSize: rippleSize,\n cb: cb\n });\n }\n };\n\n _this.startCommit = function (params) {\n var pulsate = params.pulsate,\n rippleX = params.rippleX,\n rippleY = params.rippleY,\n rippleSize = params.rippleSize,\n cb = params.cb;\n\n _this.setState(function (state) {\n return {\n nextKey: state.nextKey + 1,\n ripples: [].concat((0, _toConsumableArray2.default)(state.ripples), [_react.default.createElement(_Ripple.default, {\n key: state.nextKey,\n classes: _this.props.classes,\n timeout: {\n exit: DURATION,\n enter: DURATION\n },\n pulsate: pulsate,\n rippleX: rippleX,\n rippleY: rippleY,\n rippleSize: rippleSize\n })])\n };\n }, cb);\n };\n\n _this.stop = function (event, cb) {\n clearTimeout(_this.startTimer);\n var ripples = _this.state.ripples; // The touch interaction occurs too quickly.\n // We still want to show ripple effect.\n\n if (event.type === 'touchend' && _this.startTimerCommit) {\n event.persist();\n\n _this.startTimerCommit();\n\n _this.startTimerCommit = null;\n _this.startTimer = setTimeout(function () {\n _this.stop(event, cb);\n });\n return;\n }\n\n _this.startTimerCommit = null;\n\n if (ripples && ripples.length) {\n _this.setState({\n ripples: ripples.slice(1)\n }, cb);\n }\n };\n\n return _this;\n }\n\n (0, _createClass2.default)(TouchRipple, [{\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n clearTimeout(this.startTimer);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n center = _this$props.center,\n classes = _this$props.classes,\n className = _this$props.className,\n other = (0, _objectWithoutProperties2.default)(_this$props, [\"center\", \"classes\", \"className\"]);\n return _react.default.createElement(_TransitionGroup.default, (0, _extends2.default)({\n component: \"span\",\n enter: true,\n exit: true,\n className: (0, _classnames.default)(classes.root, className)\n }, other), this.state.ripples);\n }\n }]);\n return TouchRipple;\n}(_react.default.PureComponent);\n\nprocess.env.NODE_ENV !== \"production\" ? TouchRipple.propTypes = {\n /**\r\n * If `))) + (("`" + (`true` + "`")) + (`, the ripple starts at the center of the component\r\n * rather than at the point of interaction.\r\n */\n center: _propTypes.default.bool,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string\n} : void 0;\nTouchRipple.defaultProps = {\n center: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n flip: false,\n name: 'MuiTouchRipple'\n})(TouchRipple);\n\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\n/* eslint-disable import/no-mutable-exports */\nvar createRippleHandler = function createRippleHandler(instance, eventName, action, cb) {\n return function (event) {\n if (cb) {\n cb.call(instance, event);\n }\n\n var ignore = false; // Ignore events that have been ` + ("`" + `event.preventDefault()`))))) + (((("`" + ` marked.\n\n if (event.defaultPrevented) {\n ignore = true;\n }\n\n if (instance.props.disableTouchRipple && eventName !== 'Blur') {\n ignore = true;\n }\n\n if (!ignore && instance.ripple) {\n instance.ripple[action](event);\n }\n\n if (typeof instance.props[\"on\".concat(eventName)] === 'function') {\n instance.props[\"on\".concat(eventName)](event);\n }\n\n return true;\n };\n};\n/* istanbul ignore if */\n\n\nif (typeof window === 'undefined') {\n createRippleHandler = function createRippleHandler() {\n return function () {};\n };\n}\n\nvar _default = createRippleHandler;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.detectFocusVisible = detectFocusVisible;\nexports.listenForFocusKeys = listenForFocusKeys;\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _ownerDocument = _interopRequireDefault(require(\"../utils/ownerDocument\"));\n\nvar internal = {\n focusKeyPressed: false,\n keyUpEventTimeout: -1\n};\n\nfunction findActiveElement(doc) {\n var activeElement = doc.activeElement;\n\n while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) {\n activeElement = activeElement.shadowRoot.activeElement;\n }\n\n return activeElement;\n}\n\nfunction detectFocusVisible(instance, element, callback) {\n var attempt = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(instance.focusVisibleCheckTime, 'Material-UI: missing instance.focusVisibleCheckTime.') : void 0;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(instance.focusVisibleMaxCheckTimes, 'Material-UI: missing instance.focusVisibleMaxCheckTimes.') : void 0;\n instance.focusVisibleTimeout = setTimeout(function () {\n var doc = (0, _ownerDocument.default)(element);\n var activeElement = findActiveElement(doc);\n\n if (internal.focusKeyPressed && (activeElement === element || element.contains(activeElement))) {\n callback();\n } else if (attempt < instance.focusVisibleMaxCheckTimes) {\n detectFocusVisible(instance, element, callback, attempt + 1);\n }\n }, instance.focusVisibleCheckTime);\n}\n\nvar FOCUS_KEYS = [9, // 'Tab',\n13, // 'Enter',\n27, // 'Escape',\n32, // ' ',\n37, // 'ArrowLeft',\n38, // 'ArrowUp',\n39, // 'ArrowRight',\n40];\n\nfunction isFocusKey(event) {\n // Use event.keyCode to support IE 11\n return FOCUS_KEYS.indexOf(event.keyCode) > -1;\n}\n\nvar handleKeyUpEvent = function handleKeyUpEvent(event) {\n if (isFocusKey(event)) {\n internal.focusKeyPressed = true; // Let's consider that the user is using a keyboard during a window frame of 500ms.\n\n clearTimeout(internal.keyUpEventTimeout);\n internal.keyUpEventTimeout = setTimeout(function () {\n internal.focusKeyPressed = false;\n }, 500);\n }\n};\n\nfunction listenForFocusKeys(win) {\n // The event listener will only be added once per window.\n // Duplicate event listeners will be ignored by addEventListener.\n // Also, this logic is client side only, we don't need a teardown.\n win.addEventListener('keyup', handleKeyUpEvent);\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _ButtonBase.default;\n }\n});\n\nvar _ButtonBase = _interopRequireDefault(require(\"./ButtonBase\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _createBreakpoints = require(\"../styles/createBreakpoints\");\n\nvar _requirePropFactory = _interopRequireDefault(require(\"../utils/requirePropFactory\"));\n\n// A grid component using the following libs as inspiration.\n//\n// For the implementation:\n// - http://v4-alpha.getbootstrap.com/layout/flexbox-grid/\n// - https://github.com/kristoferjoseph/flexboxgrid/blob/master/src/css/flexboxgrid.css\n// - https://github.com/roylee0704/react-flexbox-grid\n// - https://material.angularjs.org/latest/layout/introduction\n//\n// Follow this flexbox Guide to better understand the underlying model:\n// - https://css-tricks.com/snippets/css/a-guide-to-flexbox/\nvar GUTTERS = [0, 8, 16, 24, 32, 40];\nvar GRID_SIZES = ['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];\n\nfunction generateGrid(globalStyles, theme, breakpoint) {\n var styles = {};\n GRID_SIZES.forEach(function (size) {\n var key = \"grid-\".concat(breakpoint, \"-\").concat(size);\n\n if (size === true) {\n // For the auto layouting\n styles[key] = {\n flexBasis: 0,\n flexGrow: 1,\n maxWidth: '100%'\n };\n return;\n }\n\n if (size === 'auto') {\n styles[key] = {\n flexBasis: 'auto',\n flexGrow: 0,\n maxWidth: 'none'\n };\n return;\n } // Keep 7 significant numbers.\n\n\n var width = \"\".concat(Math.round(size / 12 * 10e7) / 10e5, \"%\"); // Close to the bootstrap implementation:\n // https://github.com/twbs/bootstrap/blob/8fccaa2439e97ec72a4b7dc42ccc1f649790adb0/scss/mixins/_grid.scss#L41\n\n styles[key] = {\n flexBasis: width,\n flexGrow: 0,\n maxWidth: width\n };\n }); // No need for a media query for the first size.\n\n if (breakpoint === 'xs') {\n (0, _extends2.default)(globalStyles, styles);\n } else {\n globalStyles[theme.breakpoints.up(breakpoint)] = styles;\n }\n}\n\nfunction generateGutter(theme, breakpoint) {\n var styles = {};\n GUTTERS.forEach(function (spacing, index) {\n if (index === 0) {\n // Skip the default style.\n return;\n }\n\n styles[\"spacing-\".concat(breakpoint, \"-\").concat(spacing)] = {\n margin: -spacing / 2,\n width: \"calc(100% + \".concat(spacing, \"px)\"),\n '& > $item': {\n padding: spacing / 2\n }\n };\n });\n return styles;\n} // Default CSS values\n// flex: '0 1 auto',\n// flexDirection: 'row',\n// alignItems: 'flex-start',\n// flexWrap: 'nowrap',\n// justifyContent: 'flex-start',\n\n\nvar styles = function styles(theme) {\n return (0, _extends2.default)({\n /* Styles applied to the root element if `) + ("`" + (`container={true}` + "`"))) + ((`. */\n container: {\n boxSizing: 'border-box',\n display: 'flex',\n flexWrap: 'wrap',\n width: '100%'\n },\n\n /* Styles applied to the root element if ` + ("`" + `item={true}`)) + ("`" + (`. */\n item: {\n boxSizing: 'border-box',\n margin: '0' // For instance, it's useful when used with a ` + "`")))) + (((`figure` + ("`" + ` element.\n\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`zeroMinWidth={true}` + "`"))) + ((`. */\n zeroMinWidth: {\n minWidth: 0\n },\n\n /* Styles applied to the root element if ` + ("`" + `direction=\"column\"`)) + ("`" + (`. */\n 'direction-xs-column': {\n flexDirection: 'column'\n },\n\n /* Styles applied to the root element if ` + "`"))))))))) + ((((((((`direction=\"column-reverse\"` + "`") + (`. */\n 'direction-xs-column-reverse': {\n flexDirection: 'column-reverse'\n },\n\n /* Styles applied to the root element if ` + ("`" + `direction=\"rwo-reverse\"`))) + (("`" + (`. */\n 'direction-xs-row-reverse': {\n flexDirection: 'row-reverse'\n },\n\n /* Styles applied to the root element if ` + "`")) + (`wrap=\"nowrap\"` + ("`" + `. */\n 'wrap-xs-nowrap': {\n flexWrap: 'nowrap'\n },\n\n /* Styles applied to the root element if `)))) + ((("`" + `wrap=\"reverse\"`) + ("`" + (`. */\n 'wrap-xs-wrap-reverse': {\n flexWrap: 'wrap-reverse'\n },\n\n /* Styles applied to the root element if ` + "`"))) + ((`alignItems=\"center\"` + ("`" + `. */\n 'align-items-xs-center': {\n alignItems: 'center'\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`alignItems=\"flex-start\"` + "`"))))) + ((((`. */\n 'align-items-xs-flex-start': {\n alignItems: 'flex-start'\n },\n\n /* Styles applied to the root element if ` + "`") + (`alignItems=\"flex-end\"` + ("`" + `. */\n 'align-items-xs-flex-end': {\n alignItems: 'flex-end'\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`alignItems=\"baseline\"` + "`")) + (`. */\n 'align-items-xs-baseline': {\n alignItems: 'baseline'\n },\n\n /* Styles applied to the root element if ` + ("`" + `alignContent=\"center\"`)))) + ((("`" + `. */\n 'align-content-xs-center': {\n alignContent: 'center'\n },\n\n /* Styles applied to the root element if `) + ("`" + (`alignContent=\"flex-start\"` + "`"))) + ((`. */\n 'align-content-xs-flex-start': {\n alignContent: 'flex-start'\n },\n\n /* Styles applied to the root element if ` + ("`" + `alignContent=\"flex-end\"`)) + ("`" + (`. */\n 'align-content-xs-flex-end': {\n alignContent: 'flex-end'\n },\n\n /* Styles applied to the root element if ` + "`")))))) + (((((`alignContent=\"space-between\"` + "`") + (`. */\n 'align-content-xs-space-between': {\n alignContent: 'space-between'\n },\n\n /* Styles applied to the root element if ` + ("`" + `alignContent=\"space-around\"`))) + (("`" + (`. */\n 'align-content-xs-space-around': {\n alignContent: 'space-around'\n },\n\n /* Styles applied to the root element if ` + "`")) + (`justify=\"center\"` + ("`" + `. */\n 'justify-xs-center': {\n justifyContent: 'center'\n },\n\n /* Styles applied to the root element if `)))) + ((("`" + `justify=\"flex-end\"`) + ("`" + (`. */\n 'justify-xs-flex-end': {\n justifyContent: 'flex-end'\n },\n\n /* Styles applied to the root element if ` + "`"))) + ((`justify=\"space-between\"` + ("`" + `. */\n 'justify-xs-space-between': {\n justifyContent: 'space-between'\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`justify=\"space-around\"` + "`"))))) + ((((`. */\n 'justify-xs-space-around': {\n justifyContent: 'space-around'\n },\n\n /* Styles applied to the root element if ` + "`") + (`justify=\"space-evenly\"` + ("`" + `. */\n 'justify-xs-space-evenly': {\n justifyContent: 'space-evenly'\n }\n }, generateGutter(theme, 'xs'), _createBreakpoints.keys.reduce(function (accumulator, key) {\n // Use side effect over immutability for better performance.\n generateGrid(accumulator, theme, key);\n return accumulator;\n }, {}));\n};\n\nexports.styles = styles;\n\nfunction Grid(props) {\n var _classNames;\n\n var alignContent = props.alignContent,\n alignItems = props.alignItems,\n classes = props.classes,\n classNameProp = props.className,\n Component = props.component,\n container = props.container,\n direction = props.direction,\n item = props.item,\n justify = props.justify,\n lg = props.lg,\n md = props.md,\n sm = props.sm,\n spacing = props.spacing,\n wrap = props.wrap,\n xl = props.xl,\n xs = props.xs,\n zeroMinWidth = props.zeroMinWidth,\n other = (0, _objectWithoutProperties2.default)(props, [\"alignContent\", \"alignItems\", \"classes\", \"className\", \"component\", \"container\", \"direction\", \"item\", \"justify\", \"lg\", \"md\", \"sm\", \"spacing\", \"wrap\", \"xl\", \"xs\", \"zeroMinWidth\"]);\n var className = (0, _classnames.default)((_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.container, container), (0, _defineProperty2.default)(_classNames, classes.item, item), (0, _defineProperty2.default)(_classNames, classes.zeroMinWidth, zeroMinWidth), (0, _defineProperty2.default)(_classNames, classes[\"spacing-xs-\".concat(String(spacing))], container && spacing !== 0), (0, _defineProperty2.default)(_classNames, classes[\"direction-xs-\".concat(String(direction))], direction !== Grid.defaultProps.direction), (0, _defineProperty2.default)(_classNames, classes[\"wrap-xs-\".concat(String(wrap))], wrap !== Grid.defaultProps.wrap), (0, _defineProperty2.default)(_classNames, classes[\"align-items-xs-\".concat(String(alignItems))], alignItems !== Grid.defaultProps.alignItems), (0, _defineProperty2.default)(_classNames, classes[\"align-content-xs-\".concat(String(alignContent))], alignContent !== Grid.defaultProps.alignContent), (0, _defineProperty2.default)(_classNames, classes[\"justify-xs-\".concat(String(justify))], justify !== Grid.defaultProps.justify), (0, _defineProperty2.default)(_classNames, classes[\"grid-xs-\".concat(String(xs))], xs !== false), (0, _defineProperty2.default)(_classNames, classes[\"grid-sm-\".concat(String(sm))], sm !== false), (0, _defineProperty2.default)(_classNames, classes[\"grid-md-\".concat(String(md))], md !== false), (0, _defineProperty2.default)(_classNames, classes[\"grid-lg-\".concat(String(lg))], lg !== false), (0, _defineProperty2.default)(_classNames, classes[\"grid-xl-\".concat(String(xl))], xl !== false), _classNames), classNameProp);\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: className\n }, other));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? Grid.propTypes = {\n /**\r\n * Defines the `))) + (("`" + (`align-content` + "`")) + (` style property.\r\n * It's applied for all screen sizes.\r\n */\n alignContent: _propTypes.default.oneOf(['stretch', 'center', 'flex-start', 'flex-end', 'space-between', 'space-around']),\n\n /**\r\n * Defines the ` + ("`" + `align-items`)))) + ((("`" + ` style property.\r\n * It's applied for all screen sizes.\r\n */\n alignItems: _propTypes.default.oneOf(['flex-start', 'center', 'flex-end', 'stretch', 'baseline']),\n\n /**\r\n * The content of the component.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * If `) + ("`" + (`true` + "`"))) + ((`, the component will have the flex *container* behavior.\r\n * You should be wrapping *items* with a *container*.\r\n */\n container: _propTypes.default.bool,\n\n /**\r\n * Defines the ` + ("`" + `flex-direction`)) + ("`" + (` style property.\r\n * It is applied for all screen sizes.\r\n */\n direction: _propTypes.default.oneOf(['row', 'row-reverse', 'column', 'column-reverse']),\n\n /**\r\n * If ` + "`"))))))) + ((((((`true` + "`") + (`, the component will have the flex *item* behavior.\r\n * You should be wrapping *items* with a *container*.\r\n */\n item: _propTypes.default.bool,\n\n /**\r\n * Defines the ` + ("`" + `justify-content`))) + (("`" + (` style property.\r\n * It is applied for all screen sizes.\r\n */\n justify: _propTypes.default.oneOf(['flex-start', 'center', 'flex-end', 'space-between', 'space-around', 'space-evenly']),\n\n /**\r\n * Defines the number of grids the component is going to use.\r\n * It's applied for the ` + "`")) + (`lg` + ("`" + ` breakpoint and wider screens if not overridden.\r\n */\n lg: _propTypes.default.oneOf([false, 'auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),\n\n /**\r\n * Defines the number of grids the component is going to use.\r\n * It's applied for the `)))) + ((("`" + `md`) + ("`" + (` breakpoint and wider screens if not overridden.\r\n */\n md: _propTypes.default.oneOf([false, 'auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),\n\n /**\r\n * Defines the number of grids the component is going to use.\r\n * It's applied for the ` + "`"))) + ((`sm` + ("`" + ` breakpoint and wider screens if not overridden.\r\n */\n sm: _propTypes.default.oneOf([false, 'auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),\n\n /**\r\n * Defines the space between the type `)) + ("`" + (`item` + "`"))))) + ((((` component.\r\n * It can only be used on a type ` + "`") + (`container` + ("`" + ` component.\r\n */\n spacing: _propTypes.default.oneOf(GUTTERS),\n\n /**\r\n * Defines the `))) + (("`" + (`flex-wrap` + "`")) + (` style property.\r\n * It's applied for all screen sizes.\r\n */\n wrap: _propTypes.default.oneOf(['nowrap', 'wrap', 'wrap-reverse']),\n\n /**\r\n * Defines the number of grids the component is going to use.\r\n * It's applied for the ` + ("`" + `xl`)))) + ((("`" + ` breakpoint and wider screens.\r\n */\n xl: _propTypes.default.oneOf([false, 'auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),\n\n /**\r\n * Defines the number of grids the component is going to use.\r\n * It's applied for all the screen sizes with the lowest priority.\r\n */\n xs: _propTypes.default.oneOf([false, 'auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),\n\n /**\r\n * If `) + ("`" + (`true` + "`"))) + ((`, it sets ` + ("`" + `min-width: 0`)) + ("`" + (` on the item.\r\n * Refer to the limitations section of the documentation to better understand the use case.\r\n */\n zeroMinWidth: _propTypes.default.bool\n} : void 0;\nGrid.defaultProps = {\n alignContent: 'stretch',\n alignItems: 'stretch',\n component: 'div',\n container: false,\n direction: 'row',\n item: false,\n justify: 'flex-start',\n lg: false,\n md: false,\n sm: false,\n spacing: 0,\n wrap: 'wrap',\n xl: false,\n xs: false,\n zeroMinWidth: false\n};\nvar StyledGrid = (0, _withStyles.default)(styles, {\n name: 'MuiGrid'\n})(Grid);\n\nif (process.env.NODE_ENV !== 'production') {\n var requireProp = (0, _requirePropFactory.default)('Grid');\n StyledGrid.propTypes = (0, _extends2.default)({}, StyledGrid.propTypes, {\n alignContent: requireProp('container'),\n alignItems: requireProp('container'),\n direction: requireProp('container'),\n justify: requireProp('container'),\n lg: requireProp('item'),\n md: requireProp('item'),\n sm: requireProp('item'),\n spacing: requireProp('container'),\n wrap: requireProp('container'),\n xs: requireProp('item'),\n zeroMinWidth: requireProp('zeroMinWidth')\n });\n}\n\nvar _default = StyledGrid;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _Grid.default;\n }\n});\n\nvar _Grid = _interopRequireDefault(require(\"./Grid\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _helpers = require(\"../utils/helpers\");\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n userSelect: 'none',\n fontSize: 24,\n width: '1em',\n height: '1em',\n // Chrome fix for https://bugs.chromium.org/p/chromium/issues/detail?id=820541\n // To remove at some point.\n overflow: 'hidden',\n flexShrink: 0\n },\n\n /* Styles applied to the root element if ` + "`")))))) + (((((`color=\"primary\"` + "`") + (`. */\n colorPrimary: {\n color: theme.palette.primary.main\n },\n\n /* Styles applied to the root element if ` + ("`" + `color=\"secondary\"`))) + (("`" + (`. */\n colorSecondary: {\n color: theme.palette.secondary.main\n },\n\n /* Styles applied to the root element if ` + "`")) + (`color=\"action\"` + ("`" + `. */\n colorAction: {\n color: theme.palette.action.active\n },\n\n /* Styles applied to the root element if `)))) + ((("`" + `color=\"error\"`) + ("`" + (`. */\n colorError: {\n color: theme.palette.error.main\n },\n\n /* Styles applied to the root element if ` + "`"))) + ((`color=\"disabled\"` + ("`" + `. */\n colorDisabled: {\n color: theme.palette.action.disabled\n },\n fontSizeInherit: {\n fontSize: 'inherit'\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`fontSize=\"small\"` + "`"))))) + ((((`. */\n fontSizeSmall: {\n fontSize: 20\n },\n\n /* Styles applied to the root element if ` + "`") + (`fontSize=\"large\"` + ("`" + `. */\n fontSizeLarge: {\n fontSize: 36\n }\n };\n};\n\nexports.styles = styles;\n\nfunction Icon(props) {\n var _classNames;\n\n var children = props.children,\n classes = props.classes,\n className = props.className,\n color = props.color,\n Component = props.component,\n fontSize = props.fontSize,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\", \"color\", \"component\", \"fontSize\"]);\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: (0, _classnames.default)('material-icons', classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes[\"color\".concat((0, _helpers.capitalize)(color))], color !== 'inherit'), (0, _defineProperty2.default)(_classNames, classes[\"fontSize\".concat((0, _helpers.capitalize)(fontSize))], fontSize !== 'default'), _classNames), className),\n \"aria-hidden\": \"true\"\n }, other), children);\n}\n\nprocess.env.NODE_ENV !== \"production\" ? Icon.propTypes = {\n /**\r\n * The name of the icon font ligature.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The color of the component. It supports those theme colors that make sense for this component.\r\n */\n color: _propTypes.default.oneOf(['inherit', 'primary', 'secondary', 'action', 'error', 'disabled']),\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * The fontSize applied to the icon. Defaults to 24px, but can be configure to inherit font size.\r\n */\n fontSize: _propTypes.default.oneOf(['inherit', 'default', 'small', 'large'])\n} : void 0;\nIcon.defaultProps = {\n color: 'inherit',\n component: 'span',\n fontSize: 'default'\n};\nIcon.muiName = 'Icon';\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiIcon'\n})(Icon);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _Icon.default;\n }\n});\n\nvar _Icon = _interopRequireDefault(require(\"./Icon\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _colorManipulator = require(\"../styles/colorManipulator\");\n\nvar _ButtonBase = _interopRequireDefault(require(\"../ButtonBase\"));\n\nvar _helpers = require(\"../utils/helpers\");\n\n// @inheritedComponent ButtonBase\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n textAlign: 'center',\n flex: '0 0 auto',\n fontSize: theme.typography.pxToRem(24),\n padding: 12,\n borderRadius: '50%',\n overflow: 'visible',\n // Explicitly set the default value to solve a bug on IE 11.\n color: theme.palette.action.active,\n transition: theme.transitions.create('background-color', {\n duration: theme.transitions.duration.shortest\n }),\n '&:hover': {\n backgroundColor: (0, _colorManipulator.fade)(theme.palette.action.active, theme.palette.action.hoverOpacity),\n // Reset on touch devices, it doesn't add specificity\n '@media (hover: none)': {\n backgroundColor: 'transparent'\n },\n '&$disabled': {\n backgroundColor: 'transparent'\n }\n },\n '&$disabled': {\n color: theme.palette.action.disabled\n }\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`color=\"inherit\"` + "`")) + (`. */\n colorInherit: {\n color: 'inherit'\n },\n\n /* Styles applied to the root element if ` + ("`" + `color=\"primary\"`)))) + ((("`" + (`. */\n colorPrimary: {\n color: theme.palette.primary.main,\n '&:hover': {\n backgroundColor: (0, _colorManipulator.fade)(theme.palette.primary.main, theme.palette.action.hoverOpacity),\n // Reset on touch devices, it doesn't add specificity\n '@media (hover: none)': {\n backgroundColor: 'transparent'\n }\n }\n },\n\n /* Styles applied to the root element if ` + "`")) + (`color=\"secondary\"` + ("`" + `. */\n colorSecondary: {\n color: theme.palette.secondary.main,\n '&:hover': {\n backgroundColor: (0, _colorManipulator.fade)(theme.palette.secondary.main, theme.palette.action.hoverOpacity),\n // Reset on touch devices, it doesn't add specificity\n '@media (hover: none)': {\n backgroundColor: 'transparent'\n }\n }\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`disabled={true}` + "`")) + (`. */\n disabled: {},\n\n /* Styles applied to the children container element. */\n label: {\n width: '100%',\n display: 'flex',\n alignItems: 'inherit',\n justifyContent: 'inherit'\n }\n };\n};\n/**\r\n * Refer to the [Icons](/style/icons/) section of the documentation\r\n * regarding the available icon options.\r\n */\n\n\nexports.styles = styles;\n\nfunction IconButton(props) {\n var _classNames;\n\n var children = props.children,\n classes = props.classes,\n className = props.className,\n color = props.color,\n disabled = props.disabled,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\", \"color\", \"disabled\"]);\n return _react.default.createElement(_ButtonBase.default, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes[\"color\".concat((0, _helpers.capitalize)(color))], color !== 'default'), (0, _defineProperty2.default)(_classNames, classes.disabled, disabled), _classNames), className),\n centerRipple: true,\n focusRipple: true,\n disabled: disabled\n }, other), _react.default.createElement(\"span\", {\n className: classes.label\n }, children));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? IconButton.propTypes = {\n /**\r\n * The icon element.\r\n */\n children: (0, _utils.chainPropTypes)(_propTypes.default.node, function (props) {\n var found = _react.default.Children.toArray(props.children).some(function (child) {\n return _react.default.isValidElement(child) && child.props.onClick;\n });\n\n if (found) {\n return new Error(['Material-UI: you are providing an onClick event listener ' + 'to a child of a button element.', 'Firefox will never trigger the event.', 'You should move the onClick listener to the parent button element.', 'https://github.com/mui-org/material-ui/issues/13957', // Change error message slightly on every check to prevent caching when testing\n // which would not trigger console errors on subsequent fails\n process.env.NODE_ENV === 'test' ? Date.now() : ''].join('\\n'));\n }\n\n return null;\n }),\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The color of the component. It supports those theme colors that make sense for this component.\r\n */\n color: _propTypes.default.oneOf(['default', 'inherit', 'primary', 'secondary']),\n\n /**\r\n * If ` + ("`" + `true`)))))))) + ((((((("`" + `, the button will be disabled.\r\n */\n disabled: _propTypes.default.bool,\n\n /**\r\n * If `) + ("`" + (`true` + "`"))) + ((`, the ripple will be disabled.\r\n */\n disableRipple: _propTypes.default.bool\n} : void 0;\nIconButton.defaultProps = {\n color: 'default',\n disabled: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiIconButton'\n})(IconButton);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _IconButton.default;\n }\n});\n\nvar _IconButton = _interopRequireDefault(require(\"./IconButton\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _ListContext = _interopRequireDefault(require(\"./ListContext\"));\n\nvar styles = {\n /* Styles applied to the root element. */\n root: {\n listStyle: 'none',\n margin: 0,\n padding: 0,\n position: 'relative'\n },\n\n /* Styles applied to the root element if ` + ("`" + `disablePadding={false}`)) + ("`" + (`. */\n padding: {\n paddingTop: 8,\n paddingBottom: 8\n },\n\n /* Styles applied to the root element if ` + "`")))) + (((`dense={true}` + "`") + (` & ` + ("`" + `disablePadding={false}`))) + (("`" + (`. */\n dense: {\n paddingTop: 4,\n paddingBottom: 4\n },\n\n /* Styles applied to the root element if a ` + "`")) + (`subheader` + ("`" + ` is provided. */\n subheader: {\n paddingTop: 0\n }\n};\nexports.styles = styles;\n\nfunction List(props) {\n var _classNames;\n\n var children = props.children,\n classes = props.classes,\n className = props.className,\n Component = props.component,\n dense = props.dense,\n disablePadding = props.disablePadding,\n subheader = props.subheader,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\", \"component\", \"dense\", \"disablePadding\", \"subheader\"]);\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.dense, dense && !disablePadding), (0, _defineProperty2.default)(_classNames, classes.padding, !disablePadding), (0, _defineProperty2.default)(_classNames, classes.subheader, subheader), _classNames), className)\n }, other), _react.default.createElement(_ListContext.default.Provider, {\n value: {\n dense: dense\n }\n }, subheader, children));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? List.propTypes = {\n /**\r\n * The content of the component.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * If `))))) + (((("`" + `true`) + ("`" + (`, compact vertical padding designed for keyboard and mouse input will be used for\r\n * the list and list items. The property is available to descendant components as the\r\n * ` + "`"))) + ((`dense` + ("`" + ` context.\r\n */\n dense: _propTypes.default.bool,\n\n /**\r\n * If `)) + ("`" + (`true` + "`")))) + (((`, vertical padding will be removed from the list.\r\n */\n disablePadding: _propTypes.default.bool,\n\n /**\r\n * The content of the subheader, normally ` + "`") + (`ListSubheader` + ("`" + `.\r\n */\n subheader: _propTypes.default.node\n} : void 0;\nList.defaultProps = {\n component: 'ul',\n dense: false,\n disablePadding: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiList'\n})(List);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\n/**\r\n * @ignore - internal component.\r\n */\nvar ListContext = _react.default.createContext({});\n\nvar _default = ListContext;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _List.default;\n }\n});\n\nvar _List = _interopRequireDefault(require(\"./List\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _ButtonBase = _interopRequireDefault(require(\"../ButtonBase\"));\n\nvar _reactHelpers = require(\"../utils/reactHelpers\");\n\nvar _MergeListContext = _interopRequireDefault(require(\"./MergeListContext\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the (normally root) `))) + (("`" + (`component` + "`")) + (` element. May be wrapped by a ` + ("`" + `container`)))))) + ((((("`" + `. */\n root: {\n display: 'flex',\n justifyContent: 'flex-start',\n alignItems: 'center',\n position: 'relative',\n textDecoration: 'none',\n width: '100%',\n boxSizing: 'border-box',\n textAlign: 'left',\n paddingTop: 11,\n // To use 10px in v4\n paddingBottom: 11,\n // To use 10px in v4\n '&$selected, &$selected:hover, &$selected:focus': {\n backgroundColor: theme.palette.action.selected\n }\n },\n\n /* Styles applied to the `) + ("`" + (`container` + "`"))) + ((` element if ` + ("`" + `children`)) + ("`" + (` includes ` + "`")))) + (((`ListItemSecondaryAction` + "`") + (`. */\n container: {\n position: 'relative'\n },\n // To remove in v4\n\n /* Styles applied to the ` + ("`" + `component`))) + (("`" + (`'s ` + "`")) + (`focusVisibleClassName` + ("`" + ` property if `))))) + (((("`" + `button={true}`) + ("`" + (`. */\n focusVisible: {},\n\n /* Legacy styles applied to the root element. Use ` + "`"))) + ((`root` + ("`" + ` instead. */\n default: {},\n\n /* Styles applied to the `)) + ("`" + (`component` + "`")))) + (((` element if ` + ("`" + `dense={true}`)) + ("`" + (` or ` + "`"))) + ((`children` + ("`" + ` includes `)) + ("`" + (`Avatar` + "`"))))))) + ((((((`. */\n dense: {\n paddingTop: 8,\n paddingBottom: 8\n },\n\n /* Styles applied to the ` + "`") + (`component` + ("`" + ` element if `))) + (("`" + (`alignItems=\"flex-start\"` + "`")) + (`. */\n alignItemsFlexStart: {\n alignItems: 'flex-start'\n },\n\n /* Styles applied to the inner ` + ("`" + `component`)))) + ((("`" + ` element if `) + ("`" + (`disabled={true}` + "`"))) + ((`. */\n disabled: {\n opacity: 0.5\n },\n\n /* Styles applied to the inner ` + ("`" + `component`)) + ("`" + (` element if ` + "`"))))) + ((((`divider={true}` + "`") + (`. */\n divider: {\n borderBottom: \"1px solid \".concat(theme.palette.divider),\n backgroundClip: 'padding-box'\n },\n\n /* Styles applied to the inner ` + ("`" + `component`))) + (("`" + (` element if ` + "`")) + (`disableGutters={false}` + ("`" + `. */\n gutters: {\n paddingLeft: 16,\n paddingRight: 16\n },\n\n /* Styles applied to the inner `)))) + ((("`" + `component`) + ("`" + (` element if ` + "`"))) + ((`button={true}` + ("`" + `. */\n button: {\n transition: theme.transitions.create('background-color', {\n duration: theme.transitions.duration.shortest\n }),\n '&:hover': {\n textDecoration: 'none',\n backgroundColor: theme.palette.action.hover,\n // Reset on touch devices, it doesn't add specificity\n '@media (hover: none)': {\n backgroundColor: 'transparent'\n }\n },\n '&:focus': {\n backgroundColor: theme.palette.action.hover\n }\n },\n\n /* Styles applied to the `)) + ("`" + (`component` + "`")))))) + (((((` element if ` + "`") + (`children` + ("`" + ` includes `))) + (("`" + (`ListItemSecondaryAction` + "`")) + (`. */\n secondaryAction: {\n // Add some space to avoid collision as ` + ("`" + `ListItemSecondaryAction`)))) + ((("`" + `\n // is absolutely positioned.\n paddingRight: 32\n },\n\n /* Styles applied to the root element if `) + ("`" + (`selected={true}` + "`"))) + ((`. */\n selected: {}\n };\n};\n/**\r\n * Uses an additional container component if ` + ("`" + `ListItemSecondaryAction`)) + ("`" + (` is the last child.\r\n */\n\n\nexports.styles = styles;\n\nfunction ListItem(props) {\n var alignItems = props.alignItems,\n button = props.button,\n childrenProp = props.children,\n classes = props.classes,\n classNameProp = props.className,\n componentProp = props.component,\n ContainerComponent = props.ContainerComponent,\n _props$ContainerProps = props.ContainerProps;\n _props$ContainerProps = _props$ContainerProps === void 0 ? {} : _props$ContainerProps;\n var ContainerClassName = _props$ContainerProps.className,\n ContainerProps = (0, _objectWithoutProperties2.default)(_props$ContainerProps, [\"className\"]),\n denseProp = props.dense,\n disabled = props.disabled,\n disableGutters = props.disableGutters,\n divider = props.divider,\n focusVisibleClassName = props.focusVisibleClassName,\n selected = props.selected,\n other = (0, _objectWithoutProperties2.default)(props, [\"alignItems\", \"button\", \"children\", \"classes\", \"className\", \"component\", \"ContainerComponent\", \"ContainerProps\", \"dense\", \"disabled\", \"disableGutters\", \"divider\", \"focusVisibleClassName\", \"selected\"]);\n return _react.default.createElement(_MergeListContext.default, {\n dense: denseProp,\n alignItems: alignItems\n }, function (_ref) {\n var _classNames;\n\n var dense = _ref.dense;\n\n var children = _react.default.Children.toArray(childrenProp);\n\n var hasAvatar = children.some(function (value) {\n return (0, _reactHelpers.isMuiElement)(value, ['ListItemAvatar']);\n });\n var hasSecondaryAction = children.length && (0, _reactHelpers.isMuiElement)(children[children.length - 1], ['ListItemSecondaryAction']);\n var className = (0, _classnames.default)(classes.root, classes.default, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.dense, dense || hasAvatar), (0, _defineProperty2.default)(_classNames, classes.gutters, !disableGutters), (0, _defineProperty2.default)(_classNames, classes.divider, divider), (0, _defineProperty2.default)(_classNames, classes.disabled, disabled), (0, _defineProperty2.default)(_classNames, classes.button, button), (0, _defineProperty2.default)(_classNames, classes.alignItemsFlexStart, alignItems === 'flex-start'), (0, _defineProperty2.default)(_classNames, classes.secondaryAction, hasSecondaryAction), (0, _defineProperty2.default)(_classNames, classes.selected, selected), _classNames), classNameProp);\n var componentProps = (0, _extends2.default)({\n className: className,\n disabled: disabled\n }, other);\n var Component = componentProp || 'li';\n\n if (button) {\n componentProps.component = componentProp || 'div';\n componentProps.focusVisibleClassName = (0, _classnames.default)(classes.focusVisible, focusVisibleClassName);\n Component = _ButtonBase.default;\n }\n\n if (hasSecondaryAction) {\n // Use div by default.\n Component = !componentProps.component && !componentProp ? 'div' : Component; // Avoid nesting of li > li.\n\n if (ContainerComponent === 'li') {\n if (Component === 'li') {\n Component = 'div';\n } else if (componentProps.component === 'li') {\n componentProps.component = 'div';\n }\n }\n\n return _react.default.createElement(ContainerComponent, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.container, ContainerClassName)\n }, ContainerProps), _react.default.createElement(Component, componentProps, children), children.pop());\n }\n\n return _react.default.createElement(Component, componentProps, children);\n });\n}\n\nprocess.env.NODE_ENV !== \"production\" ? ListItem.propTypes = {\n /**\r\n * Defines the ` + "`"))))) + ((((`align-items` + "`") + (` style property.\r\n */\n alignItems: _propTypes.default.oneOf(['flex-start', 'center']),\n\n /**\r\n * If ` + ("`" + `true`))) + (("`" + (`, the list item will be a button (using ` + "`")) + (`ButtonBase` + ("`" + `).\r\n */\n button: _propTypes.default.bool,\n\n /**\r\n * The content of the component. If a `)))) + ((("`" + (`ListItemSecondaryAction` + "`")) + (` is used it must\r\n * be the last child.\r\n */\n children: (0, _utils.chainPropTypes)(_propTypes.default.node, function (props) {\n var children = _react.default.Children.toArray(props.children); // React.Children.toArray(props.children).findLastIndex(isListItemSecondaryAction)\n\n\n var secondaryActionIndex = -1;\n\n for (var i = children.length - 1; i >= 0; i -= 1) {\n var child = children[i];\n\n if ((0, _reactHelpers.isMuiElement)(child, ['ListItemSecondaryAction'])) {\n secondaryActionIndex = i;\n break;\n }\n } // is ListItemSecondaryAction the last child of ListItem\n\n\n if (secondaryActionIndex !== -1 && secondaryActionIndex !== children.length - 1) {\n return new Error('Material-UI: you used an element after ListItemSecondaryAction. ' + 'For ListItem to detect that it has a secondary action ' + \"you must pass it has the last children to ListItem.\".concat(process.env.NODE_ENV === 'test' ? Date.now() : ''));\n }\n\n return null;\n }),\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n * By default, it's a ` + ("`" + `li`))) + (("`" + (` when ` + "`")) + (`button` + ("`" + ` is `)))))))))) + ((((((((("`" + `false`) + ("`" + (` and a ` + "`"))) + ((`div` + ("`" + ` when `)) + ("`" + (`button` + "`")))) + (((` is ` + "`") + (`true` + ("`" + `.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * The container component used when a `))) + (("`" + (`ListItemSecondaryAction` + "`")) + (` is the last child.\r\n */\n ContainerComponent: _utils.componentPropType,\n\n /**\r\n * Properties applied to the container component if used.\r\n */\n ContainerProps: _propTypes.default.object,\n\n /**\r\n * If ` + ("`" + `true`))))) + (((("`" + `, compact vertical padding designed for keyboard and mouse input will be used.\r\n */\n dense: _propTypes.default.bool,\n\n /**\r\n * If `) + ("`" + (`true` + "`"))) + ((`, the list item will be disabled.\r\n */\n disabled: _propTypes.default.bool,\n\n /**\r\n * If ` + ("`" + `true`)) + ("`" + (`, the left and right padding is removed.\r\n */\n disableGutters: _propTypes.default.bool,\n\n /**\r\n * If ` + "`")))) + (((`true` + "`") + (`, a 1px light border is added to the bottom of the list item.\r\n */\n divider: _propTypes.default.bool,\n\n /**\r\n * @ignore\r\n */\n focusVisibleClassName: _propTypes.default.string,\n\n /**\r\n * Use to apply selected styling.\r\n */\n selected: _propTypes.default.bool\n} : void 0;\nListItem.defaultProps = {\n alignItems: 'center',\n button: false,\n ContainerComponent: 'li',\n dense: false,\n disabled: false,\n disableGutters: false,\n divider: false,\n selected: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiListItem'\n})(ListItem);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _ListContext = _interopRequireDefault(require(\"../List/ListContext\"));\n\n/**\r\n * @ignore - internal component.\r\n *\r\n * Consumes a context and passes that context merged with its props.\r\n */\nfunction MergeListContext(props) {\n var alignItems = props.alignItems,\n children = props.children,\n dense = props.dense;\n return _react.default.createElement(_ListContext.default.Consumer, null, function (context) {\n var childContext = {\n dense: dense || context.dense || false,\n alignItems: alignItems\n };\n return _react.default.createElement(_ListContext.default.Provider, {\n value: childContext\n }, children(childContext));\n });\n}\n\nprocess.env.NODE_ENV !== \"production\" ? MergeListContext.propTypes = {\n alignItems: _propTypes.default.oneOf(['flex-start', 'center']).isRequired,\n children: _propTypes.default.func.isRequired,\n dense: _propTypes.default.bool.isRequired\n} : void 0;\nvar _default = MergeListContext;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _ListItem.default;\n }\n});\n\nvar _ListItem = _interopRequireDefault(require(\"./ListItem\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n marginRight: 16,\n color: theme.palette.action.active,\n flexShrink: 0,\n display: 'inline-flex'\n }\n };\n};\n/**\r\n * A simple wrapper to apply ` + ("`" + `List`))) + (("`" + (` styles to an ` + "`")) + (`Icon` + ("`" + ` or `)))))) + ((((("`" + `SvgIcon`) + ("`" + (`.\r\n */\n\n\nexports.styles = styles;\n\nfunction ListItemIcon(props) {\n var children = props.children,\n classes = props.classes,\n classNameProp = props.className,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\"]);\n return _react.default.createElement(\"div\", (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, classNameProp)\n }, other), children);\n}\n\nprocess.env.NODE_ENV !== \"production\" ? ListItemIcon.propTypes = {\n /**\r\n * The content of the component, normally ` + "`"))) + ((`Icon` + ("`" + `, `)) + ("`" + (`SvgIcon` + "`")))) + (((`,\r\n * or a ` + "`") + (`@material-ui/icons` + ("`" + ` SVG icon element.\r\n */\n children: _propTypes.default.element.isRequired,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string\n} : void 0;\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiListItemIcon'\n})(ListItemIcon);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _ListItemIcon.default;\n }\n});\n\nvar _ListItemIcon = _interopRequireDefault(require(\"./ListItemIcon\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _Typography = _interopRequireDefault(require(\"../Typography\"));\n\nvar _ListContext = _interopRequireDefault(require(\"../List/ListContext\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n flex: '1 1 auto',\n minWidth: 0,\n padding: '0 16px',\n '&:first-child': {\n paddingLeft: 0\n }\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`inset={true}` + "`")) + (`. */\n inset: {\n '&:first-child': {\n paddingLeft: 56\n }\n },\n\n /* Styles applied to the root element if ` + ("`" + `context.dense`))))) + (((("`" + ` is `) + ("`" + (`true` + "`"))) + ((`. */\n dense: {\n fontSize: theme.typography.pxToRem(13)\n },\n\n /* Styles applied to the primary ` + ("`" + `Typography`)) + ("`" + (` component. */\n primary: {\n '&$textDense': {\n fontSize: 'inherit'\n }\n },\n\n /* Styles applied to the secondary ` + "`")))) + (((`Typography` + "`") + (` component. */\n secondary: {\n '&$textDense': {\n fontSize: 'inherit'\n }\n },\n\n /* Styles applied to the ` + ("`" + `Typography`))) + (("`" + (` components if ` + "`")) + (`context.dense` + ("`" + ` is `))))))) + (((((("`" + `true`) + ("`" + (`. */\n textDense: {}\n };\n};\n\nexports.styles = styles;\n\nfunction ListItemText(props) {\n var children = props.children,\n classes = props.classes,\n classNameProp = props.className,\n disableTypography = props.disableTypography,\n inset = props.inset,\n primaryProp = props.primary,\n primaryTypographyProps = props.primaryTypographyProps,\n secondaryProp = props.secondary,\n secondaryTypographyProps = props.secondaryTypographyProps,\n theme = props.theme,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\", \"disableTypography\", \"inset\", \"primary\", \"primaryTypographyProps\", \"secondary\", \"secondaryTypographyProps\", \"theme\"]);\n return _react.default.createElement(_ListContext.default.Consumer, null, function (_ref) {\n var _classNames3;\n\n var dense = _ref.dense;\n var primary = primaryProp != null ? primaryProp : children;\n\n if (primary != null && primary.type !== _Typography.default && !disableTypography) {\n primary = _react.default.createElement(_Typography.default, (0, _extends2.default)({\n variant: theme.typography.useNextVariants ? 'body1' : 'subheading',\n className: (0, _classnames.default)(classes.primary, (0, _defineProperty2.default)({}, classes.textDense, dense)),\n component: \"span\"\n }, primaryTypographyProps), primary);\n }\n\n var secondary = secondaryProp;\n\n if (secondary != null && secondary.type !== _Typography.default && !disableTypography) {\n secondary = _react.default.createElement(_Typography.default, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.secondary, (0, _defineProperty2.default)({}, classes.textDense, dense)),\n color: \"textSecondary\"\n }, secondaryTypographyProps), secondary);\n }\n\n return _react.default.createElement(\"div\", (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, (_classNames3 = {}, (0, _defineProperty2.default)(_classNames3, classes.dense, dense), (0, _defineProperty2.default)(_classNames3, classes.inset, inset), _classNames3), classNameProp)\n }, other), primary, secondary);\n });\n}\n\nprocess.env.NODE_ENV !== \"production\" ? ListItemText.propTypes = {\n /**\r\n * Alias for the ` + "`"))) + ((`primary` + ("`" + ` property.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * If `)) + ("`" + (`true` + "`")))) + (((`, the children won't be wrapped by a Typography component.\r\n * This can be useful to render an alternative Typography variant by wrapping\r\n * the ` + "`") + (`children` + ("`" + ` (or `))) + (("`" + (`primary` + "`")) + (`) text, and optional ` + ("`" + `secondary`))))) + (((("`" + ` text\r\n * with the Typography component.\r\n */\n disableTypography: _propTypes.default.bool,\n\n /**\r\n * If `) + ("`" + (`true` + "`"))) + ((`, the children will be indented.\r\n * This should be used if there is no left avatar or left icon.\r\n */\n inset: _propTypes.default.bool,\n\n /**\r\n * The main content element.\r\n */\n primary: _propTypes.default.node,\n\n /**\r\n * These props will be forwarded to the primary typography component\r\n * (as long as disableTypography is not ` + ("`" + `true`)) + ("`" + (`).\r\n */\n primaryTypographyProps: _propTypes.default.object,\n\n /**\r\n * The secondary content element.\r\n */\n secondary: _propTypes.default.node,\n\n /**\r\n * These props will be forwarded to the secondary typography component\r\n * (as long as disableTypography is not ` + "`")))) + (((`true` + "`") + (`).\r\n */\n secondaryTypographyProps: _propTypes.default.object,\n\n /**\r\n * @ignore\r\n */\n theme: _propTypes.default.object.isRequired\n} : void 0;\nListItemText.defaultProps = {\n disableTypography: false,\n inset: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiListItemText',\n withTheme: true\n})(ListItemText);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _ListItemText.default;\n }\n});\n\nvar _ListItemText = _interopRequireDefault(require(\"./ListItemText\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf3 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\n/**\r\n * NoSsr purposely removes components from the subject of Server Side Rendering (SSR).\r\n *\r\n * This component can be useful in a variety of situations:\r\n * - Escape hatch for broken dependencies not supporting SSR.\r\n * - Improve the time-to-first paint on the client by only rendering above the fold.\r\n * - Reduce the rendering time on the server.\r\n * - Under too heavy server load, you can turn on service degradation.\r\n */\nvar NoSsr =\n/*#__PURE__*/\nfunction (_React$Component) {\n (0, _inherits2.default)(NoSsr, _React$Component);\n\n function NoSsr() {\n var _getPrototypeOf2;\n\n var _this;\n\n (0, _classCallCheck2.default)(this, NoSsr);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(NoSsr)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.mounted = false;\n _this.state = {\n mounted: false\n };\n return _this;\n }\n\n (0, _createClass2.default)(NoSsr, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this2 = this;\n\n this.mounted = true;\n\n if (this.props.defer) {\n // Wondering why we use two RAFs? Check this video out:\n // https://www.youtube.com/watch?v=cCOL7MC4Pl0\n //\n // The componentDidMount() method is called after the DOM nodes are inserted.\n // The UI might not have rendering the changes. We request a frame.\n requestAnimationFrame(function () {\n // The browser should be about to render the DOM nodes\n // that React committed at this point.\n // We don't want to interrupt. Let's wait the next frame.\n requestAnimationFrame(function () {\n // The UI is up-to-date at this point.\n // We can continue rendering the children.\n if (_this2.mounted) {\n _this2.setState({\n mounted: true\n });\n }\n });\n });\n } else {\n this.setState({\n mounted: true\n });\n }\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n this.mounted = false;\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n children = _this$props.children,\n fallback = _this$props.fallback;\n return this.state.mounted ? children : fallback;\n }\n }]);\n return NoSsr;\n}(_react.default.Component);\n\nprocess.env.NODE_ENV !== \"production\" ? NoSsr.propTypes = {\n children: _propTypes.default.node.isRequired,\n\n /**\r\n * If ` + ("`" + `true`))) + (("`" + (`, the component will not only prevent server-side rendering.\r\n * It will also defer the rendering of the children into a different screen frame.\r\n */\n defer: _propTypes.default.bool,\n\n /**\r\n * The fallback content to display.\r\n */\n fallback: _propTypes.default.node\n} : void 0;\n\nif (process.env.NODE_ENV !== 'production') {\n process.env.NODE_ENV !== \"production\" ? NoSsr.propTypes = (0, _utils.exactProp)(NoSsr.propTypes) : void 0;\n}\n\nNoSsr.defaultProps = {\n defer: false,\n fallback: null\n};\nvar _default = NoSsr;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _NoSsr.default;\n }\n});\n\nvar _NoSsr = _interopRequireDefault(require(\"./NoSsr\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar styles = function styles(theme) {\n var elevations = {};\n theme.shadows.forEach(function (shadow, index) {\n elevations[\"elevation\".concat(index)] = {\n boxShadow: shadow\n };\n });\n return (0, _extends2.default)({\n /* Styles applied to the root element. */\n root: {\n backgroundColor: theme.palette.background.paper\n },\n\n /* Styles applied to the root element if ` + "`")) + (`square={false}` + ("`" + `. */\n rounded: {\n borderRadius: theme.shape.borderRadius\n }\n }, elevations);\n};\n\nexports.styles = styles;\n\nfunction Paper(props) {\n var classes = props.classes,\n classNameProp = props.className,\n Component = props.component,\n square = props.square,\n elevation = props.elevation,\n other = (0, _objectWithoutProperties2.default)(props, [\"classes\", \"className\", \"component\", \"square\", \"elevation\"]);\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(elevation >= 0 && elevation < 25, \"Material-UI: this elevation `)))))) + ((((("`" + `\".concat(elevation, \"`) + ("`" + (` is not implemented.\")) : void 0;\n var className = (0, _classnames.default)(classes.root, classes[\"elevation\".concat(elevation)], (0, _defineProperty2.default)({}, classes.rounded, !square), classNameProp);\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: className\n }, other));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? Paper.propTypes = {\n /**\r\n * The content of the component.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * Shadow depth, corresponds to ` + "`"))) + ((`dp` + ("`" + ` in the spec.\r\n * It's accepting values between 0 and 24 inclusive.\r\n */\n elevation: _propTypes.default.number,\n\n /**\r\n * If `)) + ("`" + (`true` + "`")))) + (((`, rounded corners are disabled.\r\n */\n square: _propTypes.default.bool\n} : void 0;\nPaper.defaultProps = {\n component: 'div',\n elevation: 2,\n square: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiPaper'\n})(Paper);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _Paper.default;\n }\n});\n\nvar _Paper = _interopRequireDefault(require(\"./Paper\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf3 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _TableContext = _interopRequireDefault(require(\"./TableContext\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n display: 'table',\n fontFamily: theme.typography.fontFamily,\n width: '100%',\n borderCollapse: 'collapse',\n borderSpacing: 0\n }\n };\n};\n\nexports.styles = styles;\n\nvar Table =\n/*#__PURE__*/\nfunction (_React$Component) {\n (0, _inherits2.default)(Table, _React$Component);\n\n function Table() {\n var _getPrototypeOf2;\n\n var _this;\n\n (0, _classCallCheck2.default)(this, Table);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(Table)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.memoizedContextValue = {};\n return _this;\n }\n\n (0, _createClass2.default)(Table, [{\n key: \"useMemo\",\n // To replace with the corresponding Hook once Material-UI v4 is out:\n // https://reactjs.org/docs/hooks-reference.html#usememo\n value: function useMemo(contextValue) {\n var objectKeys = Object.keys(contextValue);\n\n for (var i = 0; i < objectKeys.length; i += 1) {\n var objectKey = objectKeys[i];\n\n if (contextValue[objectKey] !== this.memoizedContextValue[objectKey]) {\n this.memoizedContextValue = contextValue;\n break;\n }\n }\n\n return this.memoizedContextValue;\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n classes = _this$props.classes,\n className = _this$props.className,\n Component = _this$props.component,\n padding = _this$props.padding,\n other = (0, _objectWithoutProperties2.default)(_this$props, [\"classes\", \"className\", \"component\", \"padding\"]);\n return _react.default.createElement(_TableContext.default.Provider, {\n value: this.useMemo({\n padding: padding\n })\n }, _react.default.createElement(Component, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, className)\n }, other)));\n }\n }]);\n return Table;\n}(_react.default.Component);\n\nprocess.env.NODE_ENV !== \"production\" ? Table.propTypes = {\n /**\r\n * The content of the table, normally ` + "`") + (`TableHead` + ("`" + ` and `))) + (("`" + (`TableBody` + "`")) + (`.\r\n */\n children: _propTypes.default.node.isRequired,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * Allows TableCells to inherit padding of the Table.\r\n */\n padding: _propTypes.default.oneOf(['default', 'checkbox', 'dense', 'none'])\n} : void 0;\nTable.defaultProps = {\n component: 'table',\n padding: 'default'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiTable'\n})(Table);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\n/**\r\n * @ignore - internal component.\r\n */\nvar TableContext = _react.default.createContext();\n\nvar _default = TableContext;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\n/**\r\n * @ignore - internal component.\r\n */\nvar Tablelvl2Context = _react.default.createContext();\n\nvar _default = Tablelvl2Context;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _Table.default;\n }\n});\n\nvar _Table = _interopRequireDefault(require(\"./Table\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _Tablelvl2Context = _interopRequireDefault(require(\"../Table/Tablelvl2Context\"));\n\nvar styles = {\n /* Styles applied to the root element. */\n root: {\n display: 'table-row-group'\n }\n};\nexports.styles = styles;\nvar contextValue = {\n variant: 'body'\n};\n\nfunction TableBody(props) {\n var classes = props.classes,\n className = props.className,\n Component = props.component,\n other = (0, _objectWithoutProperties2.default)(props, [\"classes\", \"className\", \"component\"]);\n return _react.default.createElement(_Tablelvl2Context.default.Provider, {\n value: contextValue\n }, _react.default.createElement(Component, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, className)\n }, other)));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? TableBody.propTypes = {\n /**\r\n * The content of the component, normally ` + ("`" + `TableRow`))))) + (((("`" + `.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType\n} : void 0;\nTableBody.defaultProps = {\n component: 'tbody'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiTableBody'\n})(TableBody);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _TableBody.default;\n }\n});\n\nvar _TableBody = _interopRequireDefault(require(\"./TableBody\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _helpers = require(\"../utils/helpers\");\n\nvar _deprecatedPropType = _interopRequireDefault(require(\"../utils/deprecatedPropType\"));\n\nvar _colorManipulator = require(\"../styles/colorManipulator\");\n\nvar _TableContext = _interopRequireDefault(require(\"../Table/TableContext\"));\n\nvar _Tablelvl2Context = _interopRequireDefault(require(\"../Table/Tablelvl2Context\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n display: 'table-cell',\n verticalAlign: 'inherit',\n // Workaround for a rendering bug with spanned columns in Chrome 62.0.\n // Removes the alpha (sets it to 1), and lightens or darkens the theme color.\n borderBottom: \"1px solid\\n \".concat(theme.palette.type === 'light' ? (0, _colorManipulator.lighten)((0, _colorManipulator.fade)(theme.palette.divider, 1), 0.88) : (0, _colorManipulator.darken)((0, _colorManipulator.fade)(theme.palette.divider, 1), 0.68)),\n textAlign: 'left',\n padding: '4px 56px 4px 24px',\n '&:last-child': {\n paddingRight: 24\n }\n },\n\n /* Styles applied to the root element if `) + ("`" + (`variant=\"head\"` + "`"))) + ((` or ` + ("`" + `context.table.head`)) + ("`" + (`. */\n head: {\n color: theme.palette.text.secondary,\n fontSize: theme.typography.pxToRem(12),\n fontWeight: theme.typography.fontWeightMedium\n },\n\n /* Styles applied to the root element if ` + "`")))) + (((`variant=\"body\"` + ("`" + ` or `)) + ("`" + (`context.table.body` + "`"))) + ((`. */\n body: {\n color: theme.palette.text.primary,\n fontSize: theme.typography.pxToRem(13),\n fontWeight: theme.typography.fontWeightRegular\n },\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"footer\"`)) + ("`" + (` or ` + "`")))))))) + (((((((`context.table.footer` + "`") + (`. */\n footer: {\n borderBottom: 0,\n color: theme.palette.text.secondary,\n fontSize: theme.typography.pxToRem(12)\n },\n\n /* Styles applied to the root element if ` + ("`" + `numeric={true}`))) + (("`" + (`. */\n numeric: {\n textAlign: 'right',\n flexDirection: 'row-reverse' // can be dynamically inherited at runtime by contents\n\n },\n\n /* Styles applied to the root element if ` + "`")) + (`padding=\"dense\"` + ("`" + `. */\n paddingDense: {\n paddingRight: 24\n },\n\n /* Styles applied to the root element if `)))) + ((("`" + `padding=\"checkbox\"`) + ("`" + (`. */\n paddingCheckbox: {\n padding: '0 12px',\n '&:last-child': {\n paddingRight: 12\n }\n },\n\n /* Styles applied to the root element if ` + "`"))) + ((`padding=\"none\"` + ("`" + `. */\n paddingNone: {\n padding: 0,\n '&:last-child': {\n padding: 0\n }\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`align=\"left\"` + "`"))))) + ((((`. */\n alignLeft: {\n textAlign: 'left'\n },\n\n /* Styles applied to the root element if ` + "`") + (`align=\"center\"` + ("`" + `. */\n alignCenter: {\n textAlign: 'center'\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`align=\"right\"` + "`")) + (`. */\n alignRight: {\n textAlign: 'right',\n flexDirection: 'row-reverse'\n },\n\n /* Styles applied to the root element if ` + ("`" + `align=\"justify\"`)))) + ((("`" + `. */\n alignJustify: {\n textAlign: 'justify'\n }\n };\n};\n\nexports.styles = styles;\n\nfunction TableCell(props) {\n var align = props.align,\n children = props.children,\n classes = props.classes,\n classNameProp = props.className,\n component = props.component,\n sortDirection = props.sortDirection,\n _props$numeric = props.numeric,\n numeric = _props$numeric === void 0 ? false : _props$numeric,\n paddingProp = props.padding,\n scopeProp = props.scope,\n variant = props.variant,\n other = (0, _objectWithoutProperties2.default)(props, [\"align\", \"children\", \"classes\", \"className\", \"component\", \"sortDirection\", \"numeric\", \"padding\", \"scope\", \"variant\"]);\n return _react.default.createElement(_TableContext.default.Consumer, null, function (table) {\n return _react.default.createElement(_Tablelvl2Context.default.Consumer, null, function (tablelvl2) {\n var _classNames;\n\n var Component;\n\n if (component) {\n Component = component;\n } else {\n Component = tablelvl2 && tablelvl2.variant === 'head' ? 'th' : 'td';\n }\n\n var scope = scopeProp;\n\n if (!scope && tablelvl2 && tablelvl2.variant === 'head') {\n scope = 'col';\n }\n\n var padding = paddingProp || (table && table.padding ? table.padding : 'default');\n var className = (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.head, variant ? variant === 'head' : tablelvl2 && tablelvl2.variant === 'head'), (0, _defineProperty2.default)(_classNames, classes.body, variant ? variant === 'body' : tablelvl2 && tablelvl2.variant === 'body'), (0, _defineProperty2.default)(_classNames, classes.footer, variant ? variant === 'footer' : tablelvl2 && tablelvl2.variant === 'footer'), (0, _defineProperty2.default)(_classNames, classes[\"align\".concat((0, _helpers.capitalize)(align))], align !== 'inherit'), (0, _defineProperty2.default)(_classNames, classes.numeric, numeric), (0, _defineProperty2.default)(_classNames, classes[\"padding\".concat((0, _helpers.capitalize)(padding))], padding !== 'default'), _classNames), classNameProp);\n var ariaSort = null;\n\n if (sortDirection) {\n ariaSort = sortDirection === 'asc' ? 'ascending' : 'descending';\n }\n\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: className,\n \"aria-sort\": ariaSort,\n scope: scope\n }, other), children);\n });\n });\n}\n\nprocess.env.NODE_ENV !== \"production\" ? TableCell.propTypes = {\n /**\r\n * Set the text-align on the table cell content.\r\n *\r\n * Monetary or generally number fields **should be right aligned** as that allows\r\n * you to add them up quickly in your head without having to worry about decimals.\r\n */\n align: _propTypes.default.oneOf(['inherit', 'left', 'center', 'right', 'justify']),\n\n /**\r\n * The table cell contents.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * If `) + ("`" + (`true` + "`"))) + ((`, content will align to the right.\r\n */\n numeric: (0, _deprecatedPropType.default)(_propTypes.default.bool, 'Instead, use the ` + ("`" + `align`)) + ("`" + (` property.'),\n\n /**\r\n * Sets the padding applied to the cell.\r\n * By default, the Table parent component set the value.\r\n */\n padding: _propTypes.default.oneOf(['default', 'checkbox', 'dense', 'none']),\n\n /**\r\n * Set scope attribute.\r\n */\n scope: _propTypes.default.string,\n\n /**\r\n * Set aria-sort direction.\r\n */\n sortDirection: _propTypes.default.oneOf(['asc', 'desc', false]),\n\n /**\r\n * Specify the cell type.\r\n * By default, the TableHead, TableBody or TableFooter parent component set the value.\r\n */\n variant: _propTypes.default.oneOf(['head', 'body', 'footer'])\n} : void 0;\nTableCell.defaultProps = {\n align: 'inherit'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiTableCell'\n})(TableCell);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _TableCell.default;\n }\n});\n\nvar _TableCell = _interopRequireDefault(require(\"./TableCell\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _Tablelvl2Context = _interopRequireDefault(require(\"../Table/Tablelvl2Context\"));\n\nvar styles = {\n /* Styles applied to the root element. */\n root: {\n display: 'table-header-group'\n }\n};\nexports.styles = styles;\nvar contextValue = {\n variant: 'head'\n};\n\nfunction TableHead(props) {\n var classes = props.classes,\n className = props.className,\n Component = props.component,\n other = (0, _objectWithoutProperties2.default)(props, [\"classes\", \"className\", \"component\"]);\n return _react.default.createElement(_Tablelvl2Context.default.Provider, {\n value: contextValue\n }, _react.default.createElement(Component, (0, _extends2.default)({\n className: (0, _classnames.default)(classes.root, className)\n }, other)));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? TableHead.propTypes = {\n /**\r\n * The content of the component, normally ` + "`")))))) + (((((`TableRow` + "`") + (`.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType\n} : void 0;\nTableHead.defaultProps = {\n component: 'thead'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiTableHead'\n})(TableHead);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _TableHead.default;\n }\n});\n\nvar _TableHead = _interopRequireDefault(require(\"./TableHead\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _Tablelvl2Context = _interopRequireDefault(require(\"../Table/Tablelvl2Context\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n color: 'inherit',\n display: 'table-row',\n height: 48,\n verticalAlign: 'middle',\n // We disable the focus ring for mouse, touch and keyboard users.\n outline: 'none',\n '&$selected': {\n backgroundColor: theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.04)' // grey[100]\n : 'rgba(255, 255, 255, 0.08)'\n },\n '&$hover:hover': {\n backgroundColor: theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.07)' // grey[200]\n : 'rgba(255, 255, 255, 0.14)'\n }\n },\n\n /* Styles applied to the root element if ` + ("`" + `selected={true}`))) + (("`" + (`. */\n selected: {},\n\n /* Styles applied to the root element if ` + "`")) + (`hover={true}` + ("`" + `. */\n hover: {},\n\n /* Styles applied to the root element if table variant = 'head'. */\n head: {\n height: 56\n },\n\n /* Styles applied to the root element if table variant = 'footer'. */\n footer: {\n height: 56\n }\n };\n};\n/**\r\n * Will automatically set dynamic row height\r\n * based on the material table element parent (head, body, etc).\r\n */\n\n\nexports.styles = styles;\n\nfunction TableRow(props) {\n var classes = props.classes,\n classNameProp = props.className,\n Component = props.component,\n hover = props.hover,\n selected = props.selected,\n other = (0, _objectWithoutProperties2.default)(props, [\"classes\", \"className\", \"component\", \"hover\", \"selected\"]);\n return _react.default.createElement(_Tablelvl2Context.default.Consumer, null, function (tablelvl2) {\n var _classNames;\n\n var className = (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.head, tablelvl2 && tablelvl2.variant === 'head'), (0, _defineProperty2.default)(_classNames, classes.footer, tablelvl2 && tablelvl2.variant === 'footer'), (0, _defineProperty2.default)(_classNames, classes.hover, hover), (0, _defineProperty2.default)(_classNames, classes.selected, selected), _classNames), classNameProp);\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: className\n }, other));\n });\n}\n\nprocess.env.NODE_ENV !== \"production\" ? TableRow.propTypes = {\n /**\r\n * Should be valid children such as `)))) + ((("`" + `TableCell`) + ("`" + (`.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * If ` + "`"))) + ((`true` + ("`" + `, the table row will shade on hover.\r\n */\n hover: _propTypes.default.bool,\n\n /**\r\n * If `)) + ("`" + (`true` + "`"))))) + ((((`, the table row will have the selected shading.\r\n */\n selected: _propTypes.default.bool\n} : void 0;\nTableRow.defaultProps = {\n component: 'tr',\n hover: false,\n selected: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiTableRow'\n})(TableRow);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _TableRow.default;\n }\n});\n\nvar _TableRow = _interopRequireDefault(require(\"./TableRow\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n position: 'relative',\n display: 'flex',\n alignItems: 'center'\n },\n\n /* Styles applied to the root element if ` + "`") + (`disableGutters={false}` + ("`" + `. */\n gutters: theme.mixins.gutters(),\n\n /* Styles applied to the root element if `))) + (("`" + (`variant=\"regular\"` + "`")) + (`. */\n regular: theme.mixins.toolbar,\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"dense\"`)))) + ((("`" + `. */\n dense: {\n minHeight: 48\n }\n };\n};\n\nexports.styles = styles;\n\nfunction Toolbar(props) {\n var children = props.children,\n classes = props.classes,\n classNameProp = props.className,\n disableGutters = props.disableGutters,\n variant = props.variant,\n other = (0, _objectWithoutProperties2.default)(props, [\"children\", \"classes\", \"className\", \"disableGutters\", \"variant\"]);\n var className = (0, _classnames.default)(classes.root, classes[variant], (0, _defineProperty2.default)({}, classes.gutters, !disableGutters), classNameProp);\n return _react.default.createElement(\"div\", (0, _extends2.default)({\n className: className\n }, other), children);\n}\n\nprocess.env.NODE_ENV !== \"production\" ? Toolbar.propTypes = {\n /**\r\n * Toolbar children, usually a mixture of `) + ("`" + (`IconButton` + "`"))) + ((`, ` + ("`" + `Button`)) + ("`" + (` and ` + "`"))))))) + ((((((`Typography` + "`") + (`.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * If ` + ("`" + `true`))) + (("`" + (`, disables gutter padding.\r\n */\n disableGutters: _propTypes.default.bool,\n\n /**\r\n * The variant to use.\r\n */\n variant: _propTypes.default.oneOf(['regular', 'dense'])\n} : void 0;\nToolbar.defaultProps = {\n disableGutters: false,\n variant: 'regular'\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiToolbar'\n})(Toolbar);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _Toolbar.default;\n }\n});\n\nvar _Toolbar = _interopRequireDefault(require(\"./Toolbar\"));", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.styles = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _withStyles = _interopRequireDefault(require(\"../styles/withStyles\"));\n\nvar _helpers = require(\"../utils/helpers\");\n\nvar styles = function styles(theme) {\n return {\n /* Styles applied to the root element. */\n root: {\n display: 'block',\n margin: 0\n },\n\n /* Styles applied to the root element if ` + "`")) + (`variant=\"display4\"` + ("`" + `. */\n display4: theme.typography.display4,\n\n /* Styles applied to the root element if `)))) + ((("`" + `variant=\"display3\"`) + ("`" + (`. */\n display3: theme.typography.display3,\n\n /* Styles applied to the root element if ` + "`"))) + ((`variant=\"display2\"` + ("`" + `. */\n display2: theme.typography.display2,\n\n /* Styles applied to the root element if `)) + ("`" + (`variant=\"display1\"` + "`"))))) + ((((`. */\n display1: theme.typography.display1,\n\n /* Styles applied to the root element if ` + "`") + (`variant=\"headline\"` + ("`" + `. */\n headline: theme.typography.headline,\n\n /* Styles applied to the root element if `))) + (("`" + (`variant=\"title\"` + "`")) + (`. */\n title: theme.typography.title,\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"subheading\"`)))) + ((("`" + `. */\n subheading: theme.typography.subheading,\n\n /* Styles applied to the root element if `) + ("`" + (`variant=\"body2\"` + "`"))) + ((`. */\n body2: theme.typography.body2,\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"body1\"`)) + ("`" + (`. */\n body1: theme.typography.body1,\n\n /* Styles applied to the root element if ` + "`")))))) + (((((`variant=\"caption\"` + "`") + (`. */\n caption: theme.typography.caption,\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"button\"`))) + (("`" + (`. */\n button: theme.typography.button,\n\n /* Styles applied to the root element if ` + "`")) + (`variant=\"h1\"` + ("`" + `. */\n h1: theme.typography.h1,\n\n /* Styles applied to the root element if `)))) + ((("`" + `variant=\"h2\"`) + ("`" + (`. */\n h2: theme.typography.h2,\n\n /* Styles applied to the root element if ` + "`"))) + ((`variant=\"h3\"` + ("`" + `. */\n h3: theme.typography.h3,\n\n /* Styles applied to the root element if `)) + ("`" + (`variant=\"h4\"` + "`"))))) + ((((`. */\n h4: theme.typography.h4,\n\n /* Styles applied to the root element if ` + "`") + (`variant=\"h5\"` + ("`" + `. */\n h5: theme.typography.h5,\n\n /* Styles applied to the root element if `))) + (("`" + (`variant=\"h6\"` + "`")) + (`. */\n h6: theme.typography.h6,\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"subtitle1\"`)))) + ((("`" + (`. */\n subtitle1: theme.typography.subtitle1,\n\n /* Styles applied to the root element if ` + "`")) + (`variant=\"subtitle2\"` + ("`" + `. */\n subtitle2: theme.typography.subtitle2,\n\n /* Styles applied to the root element if `))) + (("`" + (`variant=\"overline\"` + "`")) + (`. */\n overline: theme.typography.overline,\n\n /* Styles applied to the root element if ` + ("`" + `variant=\"srOnly\"`))))))))) + (((((((("`" + `. Only accessible to screen readers. */\n srOnly: {\n position: 'absolute',\n height: 1,\n width: 1,\n overflow: 'hidden'\n },\n\n /* Styles applied to the root element if `) + ("`" + (`align=\"left\"` + "`"))) + ((`. */\n alignLeft: {\n textAlign: 'left'\n },\n\n /* Styles applied to the root element if ` + ("`" + `align=\"center\"`)) + ("`" + (`. */\n alignCenter: {\n textAlign: 'center'\n },\n\n /* Styles applied to the root element if ` + "`")))) + (((`align=\"right\"` + "`") + (`. */\n alignRight: {\n textAlign: 'right'\n },\n\n /* Styles applied to the root element if ` + ("`" + `align=\"justify\"`))) + (("`" + (`. */\n alignJustify: {\n textAlign: 'justify'\n },\n\n /* Styles applied to the root element if ` + "`")) + (`align=\"nowrap\"` + ("`" + `. */\n noWrap: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap'\n },\n\n /* Styles applied to the root element if `))))) + (((("`" + `gutterBottom={true}`) + ("`" + (`. */\n gutterBottom: {\n marginBottom: '0.35em'\n },\n\n /* Styles applied to the root element if ` + "`"))) + ((`paragraph={true}` + ("`" + `. */\n paragraph: {\n marginBottom: 16\n },\n\n /* Styles applied to the root element if `)) + ("`" + (`color=\"inherit\"` + "`")))) + (((`. */\n colorInherit: {\n color: 'inherit'\n },\n\n /* Styles applied to the root element if ` + "`") + (`color=\"primary\"` + ("`" + `. */\n colorPrimary: {\n color: theme.palette.primary.main\n },\n\n /* Styles applied to the root element if `))) + (("`" + (`color=\"secondary\"` + "`")) + (`. */\n colorSecondary: {\n color: theme.palette.secondary.main\n },\n\n /* Styles applied to the root element if ` + ("`" + `color=\"textPrimary\"`)))))) + ((((("`" + `. */\n colorTextPrimary: {\n color: theme.palette.text.primary\n },\n\n /* Styles applied to the root element if `) + ("`" + (`color=\"textSecondary\"` + "`"))) + ((`. */\n colorTextSecondary: {\n color: theme.palette.text.secondary\n },\n\n /* Styles applied to the root element if ` + ("`" + `color=\"error\"`)) + ("`" + (`. */\n colorError: {\n color: theme.palette.error.main\n },\n\n /* Styles applied to the root element if ` + "`")))) + (((`inline={true}` + "`") + (`. */\n inline: {\n display: 'inline'\n }\n };\n};\n\nexports.styles = styles;\nvar nextVariants = {\n display4: 'h1',\n display3: 'h2',\n display2: 'h3',\n display1: 'h4',\n headline: 'h5',\n title: 'h6',\n subheading: 'subtitle1'\n};\n\nfunction getVariant(theme, variantProp) {\n var typography = theme.typography;\n var variant = variantProp;\n\n if (!variant) {\n variant = typography.useNextVariants ? 'body2' : 'body1';\n } // complete v2 switch\n\n\n if (typography.useNextVariants) {\n variant = nextVariants[variant] || variant;\n }\n\n return variant;\n}\n\nvar defaultHeadlineMapping = {\n h1: 'h1',\n h2: 'h2',\n h3: 'h3',\n h4: 'h4',\n h5: 'h5',\n h6: 'h6',\n subtitle1: 'h6',\n subtitle2: 'h6',\n body1: 'p',\n body2: 'p',\n // deprecated\n display4: 'h1',\n display3: 'h1',\n display2: 'h1',\n display1: 'h1',\n headline: 'h1',\n title: 'h2',\n subheading: 'h3'\n};\n\nfunction Typography(props) {\n var _classNames;\n\n var align = props.align,\n classes = props.classes,\n classNameProp = props.className,\n color = props.color,\n componentProp = props.component,\n gutterBottom = props.gutterBottom,\n headlineMapping = props.headlineMapping,\n inline = props.inline,\n internalDeprecatedVariant = props.internalDeprecatedVariant,\n noWrap = props.noWrap,\n paragraph = props.paragraph,\n theme = props.theme,\n variantProp = props.variant,\n other = (0, _objectWithoutProperties2.default)(props, [\"align\", \"classes\", \"className\", \"color\", \"component\", \"gutterBottom\", \"headlineMapping\", \"inline\", \"internalDeprecatedVariant\", \"noWrap\", \"paragraph\", \"theme\", \"variant\"]);\n var variant = getVariant(theme, variantProp);\n var className = (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes[variant], variant !== 'inherit'), (0, _defineProperty2.default)(_classNames, classes[\"color\".concat((0, _helpers.capitalize)(color))], color !== 'default'), (0, _defineProperty2.default)(_classNames, classes.noWrap, noWrap), (0, _defineProperty2.default)(_classNames, classes.gutterBottom, gutterBottom), (0, _defineProperty2.default)(_classNames, classes.paragraph, paragraph), (0, _defineProperty2.default)(_classNames, classes[\"align\".concat((0, _helpers.capitalize)(align))], align !== 'inherit'), (0, _defineProperty2.default)(_classNames, classes.inline, inline), _classNames), classNameProp);\n var Component = componentProp || (paragraph ? 'p' : headlineMapping[variant] || defaultHeadlineMapping[variant]) || 'span';\n return _react.default.createElement(Component, (0, _extends2.default)({\n className: className\n }, other));\n}\n\nprocess.env.NODE_ENV !== \"production\" ? Typography.propTypes = {\n /**\r\n * Set the text-align on the component.\r\n */\n align: _propTypes.default.oneOf(['inherit', 'left', 'center', 'right', 'justify']),\n\n /**\r\n * The content of the component.\r\n */\n children: _propTypes.default.node,\n\n /**\r\n * Override or extend the styles applied to the component.\r\n * See [CSS API](#css-api) below for more details.\r\n */\n classes: _propTypes.default.object.isRequired,\n\n /**\r\n * @ignore\r\n */\n className: _propTypes.default.string,\n\n /**\r\n * The color of the component. It supports those theme colors that make sense for this component.\r\n */\n color: _propTypes.default.oneOf(['default', 'error', 'inherit', 'primary', 'secondary', 'textPrimary', 'textSecondary']),\n\n /**\r\n * The component used for the root node.\r\n * Either a string to use a DOM element or a component.\r\n * By default, it maps the variant to a good default headline component.\r\n */\n component: _utils.componentPropType,\n\n /**\r\n * If ` + ("`" + `true`))) + (("`" + (`, the text will have a bottom margin.\r\n */\n gutterBottom: _propTypes.default.bool,\n\n /**\r\n * We are empirically mapping the variant property to a range of different DOM element types.\r\n * For instance, subtitle1 to ` + "`")) + (`
` + ("`" + `.\r\n * If you wish to change that mapping, you can provide your own.\r\n * Alternatively, you can use the `))))) + (((("`" + `component`) + ("`" + (` property.\r\n * The default mapping is the following:\r\n */\n headlineMapping: _propTypes.default.object,\n\n /**\r\n * Controls whether the Typography is inline or not.\r\n */\n inline: _propTypes.default.bool,\n\n /**\r\n * A deprecated variant is used from an internal component. Users don't need\r\n * a deprecation warning here if they switched to the v2 theme. They already\r\n * get the mapping that will be applied in the next major release.\r\n *\r\n * @internal\r\n */\n internalDeprecatedVariant: _propTypes.default.bool,\n\n /**\r\n * If ` + "`"))) + ((`true` + ("`" + `, the text will not wrap, but instead will truncate with an ellipsis.\r\n */\n noWrap: _propTypes.default.bool,\n\n /**\r\n * If `)) + ("`" + (`true` + "`")))) + (((`, the text will have a bottom margin.\r\n */\n paragraph: _propTypes.default.bool,\n\n /**\r\n * @ignore\r\n */\n theme: _propTypes.default.object.isRequired,\n\n /**\r\n * Applies the theme typography styles.\r\n * Use ` + "`") + (`body1` + ("`" + ` as the default value with the legacy implementation and `))) + (("`" + (`body2` + "`")) + (` with the new one.\r\n */\n variant: (0, _utils.chainPropTypes)(_propTypes.default.oneOf(['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'subtitle1', 'subtitle2', 'body1', 'body2', 'caption', 'button', 'overline', 'srOnly', 'inherit', // deprecated\n 'display4', 'display3', 'display2', 'display1', 'headline', 'title', 'subheading']), function (props) {\n var deprecatedVariants = ['display4', 'display3', 'display2', 'display1', 'headline', 'title', 'subheading'];\n\n if (props.theme.typography.useNextVariants && !props.internalDeprecatedVariant && deprecatedVariants.indexOf(props.variant) !== -1) {\n return new Error('Material-UI: you are using a deprecated typography variant: ' + \"` + ("`" + `\".concat(props.variant, \"`))))))) + (((((("`" + ` that will be removed in the next major release.\\n\") + 'Please read the migration guide under https://material-ui.com/style/typography#migration-to-typography-v2.');\n }\n\n return null;\n })\n} : void 0;\nTypography.defaultProps = {\n align: 'inherit',\n color: 'default',\n gutterBottom: false,\n headlineMapping: defaultHeadlineMapping,\n inline: false,\n noWrap: false,\n paragraph: false\n};\n\nvar _default = (0, _withStyles.default)(styles, {\n name: 'MuiTypography',\n withTheme: true\n})(Typography);\n\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"default\", {\n enumerable: true,\n get: function get() {\n return _Typography.default;\n }\n});\n\nvar _Typography = _interopRequireDefault(require(\"./Typography\"));", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar common = {\n black: '#000',\n white: '#fff'\n};\nvar _default = common;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar grey = {\n 50: '#fafafa',\n 100: '#f5f5f5',\n 200: '#eeeeee',\n 300: '#e0e0e0',\n 400: '#bdbdbd',\n 500: '#9e9e9e',\n 600: '#757575',\n 700: '#616161',\n 800: '#424242',\n 900: '#212121',\n A100: '#d5d5d5',\n A200: '#aaaaaa',\n A400: '#303030',\n A700: '#616161'\n};\nvar _default = grey;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar indigo = {\n 50: '#e8eaf6',\n 100: '#c5cae9',\n 200: '#9fa8da',\n 300: '#7986cb',\n 400: '#5c6bc0',\n 500: '#3f51b5',\n 600: '#3949ab',\n 700: '#303f9f',\n 800: '#283593',\n 900: '#1a237e',\n A100: '#8c9eff',\n A200: '#536dfe',\n A400: '#3d5afe',\n A700: '#304ffe'\n};\nvar _default = indigo;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar pink = {\n 50: '#fce4ec',\n 100: '#f8bbd0',\n 200: '#f48fb1',\n 300: '#f06292',\n 400: '#ec407a',\n 500: '#e91e63',\n 600: '#d81b60',\n 700: '#c2185b',\n 800: '#ad1457',\n 900: '#880e4f',\n A100: '#ff80ab',\n A200: '#ff4081',\n A400: '#f50057',\n A700: '#c51162'\n};\nvar _default = pink;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar red = {\n 50: '#ffebee',\n 100: '#ffcdd2',\n 200: '#ef9a9a',\n 300: '#e57373',\n 400: '#ef5350',\n 500: '#f44336',\n 600: '#e53935',\n 700: '#d32f2f',\n 800: '#c62828',\n 900: '#b71c1c',\n A100: '#ff8a80',\n A200: '#ff5252',\n A400: '#ff1744',\n A700: '#d50000'\n};\nvar _default = red;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireWildcard = require(\"@babel/runtime/helpers/interopRequireWildcard\");\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.MuiThemeProviderOld = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf2 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _brcast = _interopRequireDefault(require(\"brcast\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _themeListener = _interopRequireWildcard(require(\"./themeListener\"));\n\n/* eslint-disable no-underscore-dangle */\n\n/**\r\n * This component takes a `) + ("`" + (`theme` + "`"))) + ((` property.\r\n * It makes the ` + ("`" + `theme`)) + ("`" + (` available down the React tree thanks to React context.\r\n * This component should preferably be used at **the root of your component tree**.\r\n */\nvar MuiThemeProviderOld =\n/*#__PURE__*/\nfunction (_React$Component) {\n (0, _inherits2.default)(MuiThemeProviderOld, _React$Component);\n\n // We are not using the React state in order to avoid unnecessary rerender.\n function MuiThemeProviderOld(props, context) {\n var _this;\n\n (0, _classCallCheck2.default)(this, MuiThemeProviderOld);\n _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(MuiThemeProviderOld).call(this)); // Get the outer theme from the context, can be null\n\n _this.broadcast = (0, _brcast.default)();\n _this.outerTheme = _themeListener.default.initial(context); // Propagate the theme so it can be accessed by the children\n\n _this.broadcast.setState(_this.mergeOuterLocalTheme(props.theme));\n\n return _this;\n }\n\n (0, _createClass2.default)(MuiThemeProviderOld, [{\n key: \"getChildContext\",\n value: function getChildContext() {\n var _ref;\n\n var _this$props = this.props,\n disableStylesGeneration = _this$props.disableStylesGeneration,\n sheetsCache = _this$props.sheetsCache,\n sheetsManager = _this$props.sheetsManager;\n var muiThemeProviderOptions = this.context.muiThemeProviderOptions || {};\n\n if (disableStylesGeneration !== undefined) {\n muiThemeProviderOptions.disableStylesGeneration = disableStylesGeneration;\n }\n\n if (sheetsCache !== undefined) {\n muiThemeProviderOptions.sheetsCache = sheetsCache;\n }\n\n if (sheetsManager !== undefined) {\n muiThemeProviderOptions.sheetsManager = sheetsManager;\n }\n\n return _ref = {}, (0, _defineProperty2.default)(_ref, _themeListener.CHANNEL, this.broadcast), (0, _defineProperty2.default)(_ref, \"muiThemeProviderOptions\", muiThemeProviderOptions), _ref;\n }\n }, {\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this2 = this;\n\n // Subscribe on the outer theme, if present\n this.unsubscribeId = _themeListener.default.subscribe(this.context, function (outerTheme) {\n _this2.outerTheme = outerTheme; // Forward the parent theme update to the children\n\n _this2.broadcast.setState(_this2.mergeOuterLocalTheme(_this2.props.theme));\n });\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate(prevProps) {\n // Propagate a local theme update\n if (this.props.theme !== prevProps.theme) {\n this.broadcast.setState(this.mergeOuterLocalTheme(this.props.theme));\n }\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n if (this.unsubscribeId !== null) {\n _themeListener.default.unsubscribe(this.context, this.unsubscribeId);\n }\n } // Simple merge between the outer theme and the local theme\n\n }, {\n key: \"mergeOuterLocalTheme\",\n value: function mergeOuterLocalTheme(localTheme) {\n // To support composition of theme.\n if (typeof localTheme === 'function') {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(this.outerTheme, ['Material-UI: you are providing a theme function property ' + 'to the MuiThemeProvider component:', ' outerTheme} />', 'However, no outer theme is present.', 'Make sure a theme is already injected higher in the React tree ' + 'or provide a theme object.'].join('\\n')) : void 0;\n return localTheme(this.outerTheme);\n }\n\n if (!this.outerTheme) {\n return localTheme;\n }\n\n return (0, _extends2.default)({}, this.outerTheme, localTheme);\n }\n }, {\n key: \"render\",\n value: function render() {\n // TODO move the sheetsManager property to a different component.\n // warning(\n // typeof window !== 'undefined' || this.props.sheetsManager,\n // [\n // 'Material-UI: you need to provide a sheetsManager to the MuiThemeProvider ' +\n // 'when rendering on the server.',\n // 'If you do not, you might experience a memory leak',\n // ].join('\\n'),\n // );\n return this.props.children;\n }\n }]);\n return MuiThemeProviderOld;\n}(_react.default.Component);\n\nexports.MuiThemeProviderOld = MuiThemeProviderOld;\nprocess.env.NODE_ENV !== \"production\" ? MuiThemeProviderOld.propTypes = {\n /**\r\n * You can wrap a node.\r\n */\n children: _propTypes.default.node.isRequired,\n\n /**\r\n * You can disable the generation of the styles with this option.\r\n * It can be useful when traversing the React tree outside of the HTML\r\n * rendering step on the server.\r\n * Let's say you are using react-apollo to extract all\r\n * the queries made by the interface server-side.\r\n * You can significantly speed up the traversal with this property.\r\n */\n disableStylesGeneration: _propTypes.default.bool,\n\n /**\r\n * @ignore\r\n *\r\n * In beta.\r\n */\n sheetsCache: _propTypes.default.object,\n\n /**\r\n * The sheetsManager is used to deduplicate style sheet injection in the page.\r\n * It's deduplicating using the (theme, styles) couple.\r\n * On the server, you should provide a new instance for each request.\r\n */\n sheetsManager: _propTypes.default.object,\n\n /**\r\n * A theme object.\r\n */\n theme: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]).isRequired\n} : void 0;\n\nif (process.env.NODE_ENV !== 'production') {\n process.env.NODE_ENV !== \"production\" ? MuiThemeProviderOld.propTypes = (0, _utils.exactProp)(MuiThemeProviderOld.propTypes) : void 0;\n}\n\nMuiThemeProviderOld.childContextTypes = (0, _extends2.default)({}, _themeListener.default.contextTypes, {\n muiThemeProviderOptions: _propTypes.default.object\n});\nMuiThemeProviderOld.contextTypes = (0, _extends2.default)({}, _themeListener.default.contextTypes, {\n muiThemeProviderOptions: _propTypes.default.object\n});\n/* istanbul ignore if */\n\nif (!_utils.ponyfillGlobal.__MUI_STYLES__) {\n _utils.ponyfillGlobal.__MUI_STYLES__ = {};\n}\n\nif (!_utils.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider) {\n _utils.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider = MuiThemeProviderOld;\n}\n\nvar _default = _utils.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.convertHexToRGB = convertHexToRGB;\nexports.rgbToHex = rgbToHex;\nexports.decomposeColor = decomposeColor;\nexports.recomposeColor = recomposeColor;\nexports.getContrastRatio = getContrastRatio;\nexports.getLuminance = getLuminance;\nexports.emphasize = emphasize;\nexports.fade = fade;\nexports.darken = darken;\nexports.lighten = lighten;\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\n/* eslint-disable no-use-before-define */\n\n/**\r\n * Returns a number whose value is limited to the given range.\r\n *\r\n * @param {number} value The value to be clamped\r\n * @param {number} min The lower boundary of the output range\r\n * @param {number} max The upper boundary of the output range\r\n * @returns {number} A number in the range [min, max]\r\n */\nfunction clamp(value) {\n var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(value >= min && value <= max, \"Material-UI: the value provided \".concat(value, \" is out of range [\").concat(min, \", \").concat(max, \"].\")) : void 0;\n\n if (value < min) {\n return min;\n }\n\n if (value > max) {\n return max;\n }\n\n return value;\n}\n/**\r\n * Converts a color from CSS hex format to CSS rgb format.\r\n *\r\n * @param {string} color - Hex color, i.e. #nnn or #nnnnnn\r\n * @returns {string} A CSS rgb color string\r\n */\n\n\nfunction convertHexToRGB(color) {\n color = color.substr(1);\n var re = new RegExp(\".{1,\".concat(color.length / 3, \"}\"), 'g');\n var colors = color.match(re);\n\n if (colors && colors[0].length === 1) {\n colors = colors.map(function (n) {\n return n + n;\n });\n }\n\n return colors ? \"rgb(\".concat(colors.map(function (n) {\n return parseInt(n, 16);\n }).join(', '), \")\") : '';\n}\n/**\r\n * Converts a color from CSS rgb format to CSS hex format.\r\n *\r\n * @param {string} color - RGB color, i.e. rgb(n, n, n)\r\n * @returns {string} A CSS rgb color string, i.e. #nnnnnn\r\n */\n\n\nfunction rgbToHex(color) {\n // Pass hex straight through\n if (color.indexOf('#') === 0) {\n return color;\n }\n\n function intToHex(c) {\n var hex = c.toString(16);\n return hex.length === 1 ? \"0\".concat(hex) : hex;\n }\n\n var _decomposeColor = decomposeColor(color),\n values = _decomposeColor.values;\n\n values = values.map(function (n) {\n return intToHex(n);\n });\n return \"#\".concat(values.join(''));\n}\n/**\r\n * Returns an object with the type and values of a color.\r\n *\r\n * Note: Does not support rgb % values.\r\n *\r\n * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @returns {object} - A MUI color object: {type: string, values: number[]}\r\n */\n\n\nfunction decomposeColor(color) {\n if (color.charAt(0) === '#') {\n return decomposeColor(convertHexToRGB(color));\n }\n\n var marker = color.indexOf('(');\n var type = color.substring(0, marker);\n var values = color.substring(marker + 1, color.length - 1).split(',');\n values = values.map(function (value) {\n return parseFloat(value);\n });\n\n if (process.env.NODE_ENV !== 'production') {\n if (['rgb', 'rgba', 'hsl', 'hsla'].indexOf(type) === -1) {\n throw new Error([\"Material-UI: unsupported ` + "`")))) + (((`\".concat(color, \"` + "`") + (` color.\"), 'We support the following formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla().'].join('\\n'));\n }\n }\n\n return {\n type: type,\n values: values\n };\n}\n/**\r\n * Converts a color object with type and values to a string.\r\n *\r\n * @param {object} color - Decomposed color\r\n * @param {string} color.type - One of: 'rgb', 'rgba', 'hsl', 'hsla'\r\n * @param {array} color.values - [n,n,n] or [n,n,n,n]\r\n * @returns {string} A CSS color string\r\n */\n\n\nfunction recomposeColor(color) {\n var type = color.type;\n var values = color.values;\n\n if (type.indexOf('rgb') !== -1) {\n // Only convert the first 3 values to int (i.e. not alpha)\n values = values.map(function (n, i) {\n return i < 3 ? parseInt(n, 10) : n;\n });\n }\n\n if (type.indexOf('hsl') !== -1) {\n values[1] = \"\".concat(values[1], \"%\");\n values[2] = \"\".concat(values[2], \"%\");\n }\n\n return \"\".concat(color.type, \"(\").concat(values.join(', '), \")\");\n}\n/**\r\n * Calculates the contrast ratio between two colors.\r\n *\r\n * Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests\r\n *\r\n * @param {string} foreground - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @param {string} background - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @returns {number} A contrast ratio value in the range 0 - 21.\r\n */\n\n\nfunction getContrastRatio(foreground, background) {\n var lumA = getLuminance(foreground);\n var lumB = getLuminance(background);\n return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);\n}\n/**\r\n * The relative brightness of any point in a color space,\r\n * normalized to 0 for darkest black and 1 for lightest white.\r\n *\r\n * Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests\r\n *\r\n * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @returns {number} The relative brightness of the color in the range 0 - 1\r\n */\n\n\nfunction getLuminance(color) {\n var decomposedColor = decomposeColor(color);\n\n if (decomposedColor.type.indexOf('rgb') !== -1) {\n var rgb = decomposedColor.values.map(function (val) {\n val /= 255; // normalized\n\n return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);\n }); // Truncate at 3 digits\n\n return Number((0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2]).toFixed(3));\n } // else if (decomposedColor.type.indexOf('hsl') !== -1)\n\n\n return decomposedColor.values[2] / 100;\n}\n/**\r\n * Darken or lighten a colour, depending on its luminance.\r\n * Light colors are darkened, dark colors are lightened.\r\n *\r\n * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @param {number} coefficient=0.15 - multiplier in the range 0 - 1\r\n * @returns {string} A CSS color string. Hex input values are returned as rgb\r\n */\n\n\nfunction emphasize(color) {\n var coefficient = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.15;\n return getLuminance(color) > 0.5 ? darken(color, coefficient) : lighten(color, coefficient);\n}\n/**\r\n * Set the absolute transparency of a color.\r\n * Any existing alpha values are overwritten.\r\n *\r\n * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @param {number} value - value to set the alpha channel to in the range 0 -1\r\n * @returns {string} A CSS color string. Hex input values are returned as rgb\r\n */\n\n\nfunction fade(color, value) {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(color, \"Material-UI: missing color argument in fade(\".concat(color, \", \").concat(value, \").\")) : void 0;\n if (!color) return color;\n color = decomposeColor(color);\n value = clamp(value);\n\n if (color.type === 'rgb' || color.type === 'hsl') {\n color.type += 'a';\n }\n\n color.values[3] = value;\n return recomposeColor(color);\n}\n/**\r\n * Darkens a color.\r\n *\r\n * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @param {number} coefficient - multiplier in the range 0 - 1\r\n * @returns {string} A CSS color string. Hex input values are returned as rgb\r\n */\n\n\nfunction darken(color, coefficient) {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(color, \"Material-UI: missing color argument in darken(\".concat(color, \", \").concat(coefficient, \").\")) : void 0;\n if (!color) return color;\n color = decomposeColor(color);\n coefficient = clamp(coefficient);\n\n if (color.type.indexOf('hsl') !== -1) {\n color.values[2] *= 1 - coefficient;\n } else if (color.type.indexOf('rgb') !== -1) {\n for (var i = 0; i < 3; i += 1) {\n color.values[i] *= 1 - coefficient;\n }\n }\n\n return recomposeColor(color);\n}\n/**\r\n * Lightens a color.\r\n *\r\n * @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()\r\n * @param {number} coefficient - multiplier in the range 0 - 1\r\n * @returns {string} A CSS color string. Hex input values are returned as rgb\r\n */\n\n\nfunction lighten(color, coefficient) {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(color, \"Material-UI: missing color argument in lighten(\".concat(color, \", \").concat(coefficient, \").\")) : void 0;\n if (!color) return color;\n color = decomposeColor(color);\n coefficient = clamp(coefficient);\n\n if (color.type.indexOf('hsl') !== -1) {\n color.values[2] += (100 - color.values[2]) * coefficient;\n } else if (color.type.indexOf('rgb') !== -1) {\n for (var i = 0; i < 3; i += 1) {\n color.values[i] += (255 - color.values[i]) * coefficient;\n }\n }\n\n return recomposeColor(color);\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = createBreakpoints;\nexports.keys = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\n// Sorted ASC by size. That's important.\n// It can't be configured as it's used statically for propTypes.\nvar keys = ['xs', 'sm', 'md', 'lg', 'xl']; // Keep in mind that @media is inclusive by the CSS specification.\n\nexports.keys = keys;\n\nfunction createBreakpoints(breakpoints) {\n var _breakpoints$values = breakpoints.values,\n values = _breakpoints$values === void 0 ? {\n xs: 0,\n sm: 600,\n md: 960,\n lg: 1280,\n xl: 1920\n } : _breakpoints$values,\n _breakpoints$unit = breakpoints.unit,\n unit = _breakpoints$unit === void 0 ? 'px' : _breakpoints$unit,\n _breakpoints$step = breakpoints.step,\n step = _breakpoints$step === void 0 ? 5 : _breakpoints$step,\n other = (0, _objectWithoutProperties2.default)(breakpoints, [\"values\", \"unit\", \"step\"]);\n\n function up(key) {\n var value = typeof values[key] === 'number' ? values[key] : key;\n return \"@media (min-width:\".concat(value).concat(unit, \")\");\n }\n\n function down(key) {\n var endIndex = keys.indexOf(key) + 1;\n var upperbound = values[keys[endIndex]];\n\n if (endIndex === keys.length) {\n // xl down applies to all sizes\n return up('xs');\n }\n\n var value = typeof upperbound === 'number' && endIndex > 0 ? upperbound : key;\n return \"@media (max-width:\".concat(value - step / 100).concat(unit, \")\");\n }\n\n function between(start, end) {\n var endIndex = keys.indexOf(end) + 1;\n\n if (endIndex === keys.length) {\n return up(start);\n }\n\n return \"@media (min-width:\".concat(values[start]).concat(unit, \") and \") + \"(max-width:\".concat(values[keys[endIndex]] - step / 100).concat(unit, \")\");\n }\n\n function only(key) {\n return between(key, key);\n }\n\n function width(key) {\n return values[key];\n }\n\n return (0, _extends2.default)({\n keys: keys,\n values: values,\n up: up,\n down: down,\n between: between,\n only: only,\n width: width\n }, other);\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = createGenerateClassName;\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar escapeRegex = /([[\\].#*$><+~=|^:(),\"'` + ("`" + `\\s])/g;\n\nfunction safePrefix(classNamePrefix) {\n var prefix = String(classNamePrefix);\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(prefix.length < 256, \"Material-UI: the class name prefix is too long: \".concat(prefix, \".\")) : void 0; // Sanitize the string as will be used to prefix the generated class name.\n\n return prefix.replace(escapeRegex, '-');\n} // Returns a function which generates unique class names based on counters.\n// When new generator function is created, rule counter is reset.\n// We need to reset the rule counter for SSR for each request.\n//\n// It's inspired by\n// https://github.com/cssinjs/jss/blob/4e6a05dd3f7b6572fdd3ab216861d9e446c20331/src/utils/createGenerateClassName.js\n\n\nfunction createGenerateClassName() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var _options$dangerouslyU = options.dangerouslyUseGlobalCSS,\n dangerouslyUseGlobalCSS = _options$dangerouslyU === void 0 ? false : _options$dangerouslyU,\n _options$productionPr = options.productionPrefix,\n productionPrefix = _options$productionPr === void 0 ? 'jss' : _options$productionPr,\n _options$seed = options.seed,\n seed = _options$seed === void 0 ? '' : _options$seed;\n var ruleCounter = 0;\n return function (rule, styleSheet) {\n ruleCounter += 1;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(ruleCounter < 1e10, ['Material-UI: you might have a memory leak.', 'The ruleCounter is not supposed to grow that much.'].join('')) : void 0;\n\n if (dangerouslyUseGlobalCSS && styleSheet && styleSheet.options.name) {\n return \"\".concat(safePrefix(styleSheet.options.name), \"-\").concat(rule.key);\n }\n\n if (process.env.NODE_ENV === 'production') {\n return \"\".concat(productionPrefix).concat(seed).concat(ruleCounter);\n } // Help with debuggability.\n\n\n if (styleSheet && styleSheet.options.classNamePrefix) {\n return \"\".concat(safePrefix(styleSheet.options.classNamePrefix), \"-\").concat(rule.key, \"-\").concat(seed).concat(ruleCounter);\n }\n\n return \"\".concat(rule.key, \"-\").concat(seed).concat(ruleCounter);\n };\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = createMixins;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _extends3 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nfunction createMixins(breakpoints, spacing, mixins) {\n var _toolbar;\n\n return (0, _extends3.default)({\n gutters: function gutters() {\n var styles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return (0, _extends3.default)({\n paddingLeft: spacing.unit * 2,\n paddingRight: spacing.unit * 2\n }, styles, (0, _defineProperty2.default)({}, breakpoints.up('sm'), (0, _extends3.default)({\n paddingLeft: spacing.unit * 3,\n paddingRight: spacing.unit * 3\n }, styles[breakpoints.up('sm')])));\n },\n toolbar: (_toolbar = {\n minHeight: 56\n }, (0, _defineProperty2.default)(_toolbar, \"\".concat(breakpoints.up('xs'), \" and (orientation: landscape)\"), {\n minHeight: 48\n }), (0, _defineProperty2.default)(_toolbar, breakpoints.up('sm'), {\n minHeight: 64\n }), _toolbar)\n }, mixins);\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _deepmerge = _interopRequireDefault(require(\"deepmerge\"));\n\nvar _isPlainObject = _interopRequireDefault(require(\"is-plain-object\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _createBreakpoints = _interopRequireDefault(require(\"./createBreakpoints\"));\n\nvar _createMixins = _interopRequireDefault(require(\"./createMixins\"));\n\nvar _createPalette = _interopRequireDefault(require(\"./createPalette\"));\n\nvar _createTypography = _interopRequireDefault(require(\"./createTypography\"));\n\nvar _shadows = _interopRequireDefault(require(\"./shadows\"));\n\nvar _shape = _interopRequireDefault(require(\"./shape\"));\n\nvar _spacing = _interopRequireDefault(require(\"./spacing\"));\n\nvar _transitions = _interopRequireDefault(require(\"./transitions\"));\n\nvar _zIndex = _interopRequireDefault(require(\"./zIndex\"));\n\n// < 1kb payload overhead when lodash/merge is > 3kb.\nfunction createMuiTheme() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var _options$breakpoints = options.breakpoints,\n breakpointsInput = _options$breakpoints === void 0 ? {} : _options$breakpoints,\n _options$mixins = options.mixins,\n mixinsInput = _options$mixins === void 0 ? {} : _options$mixins,\n _options$palette = options.palette,\n paletteInput = _options$palette === void 0 ? {} : _options$palette,\n shadowsInput = options.shadows,\n _options$spacing = options.spacing,\n spacingInput = _options$spacing === void 0 ? {} : _options$spacing,\n _options$typography = options.typography,\n typographyInput = _options$typography === void 0 ? {} : _options$typography,\n other = (0, _objectWithoutProperties2.default)(options, [\"breakpoints\", \"mixins\", \"palette\", \"shadows\", \"spacing\", \"typography\"]);\n var palette = (0, _createPalette.default)(paletteInput);\n var breakpoints = (0, _createBreakpoints.default)(breakpointsInput);\n var spacing = (0, _extends2.default)({}, _spacing.default, spacingInput);\n var muiTheme = (0, _extends2.default)({\n breakpoints: breakpoints,\n direction: 'ltr',\n mixins: (0, _createMixins.default)(breakpoints, spacing, mixinsInput),\n overrides: {},\n // Inject custom styles\n palette: palette,\n props: {},\n // Inject custom properties\n shadows: shadowsInput || _shadows.default,\n typography: (0, _createTypography.default)(palette, typographyInput)\n }, (0, _deepmerge.default)({\n shape: _shape.default,\n spacing: spacing,\n transitions: _transitions.default,\n zIndex: _zIndex.default\n }, other, {\n isMergeableObject: _isPlainObject.default\n }));\n\n if (process.env.NODE_ENV !== 'production') {\n var statesWarning = ['disabled', 'focused', 'selected', 'checked'];\n\n var traverse = function traverse(node, parentKey) {\n var depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;\n var key; // eslint-disable-next-line guard-for-in, no-restricted-syntax\n\n for (key in node) {\n var child = node[key];\n\n if (depth === 1) {\n if (key.indexOf('Mui') === 0 && child) {\n traverse(child, key, depth + 1);\n }\n } else if (statesWarning.indexOf(key) !== -1 && Object.keys(child).length > 0) {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(false, [\"Material-UI: the `))) + (("`" + (`\".concat(parentKey, \"` + "`")) + (` component increases \") + \"the CSS specificity of the ` + ("`" + `\".concat(key, \"`))))) + (((("`" + ` internal state.\"), 'You can not override it like this: ', JSON.stringify(node, null, 2), '', 'Instead, you need to use the $ruleName syntax:', JSON.stringify((0, _defineProperty2.default)({}, \"&$\".concat(key), child), null, 2), '', 'https://material-ui.com/customization/overrides#internal-states'].join('\\n')) : void 0;\n }\n }\n };\n\n traverse(other.overrides);\n }\n\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(muiTheme.shadows.length === 25, 'Material-UI: the shadows array provided to createMuiTheme should support 25 elevations.') : void 0;\n return muiTheme;\n}\n\nvar _default = createMuiTheme;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = createPalette;\nexports.dark = exports.light = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _deepmerge = _interopRequireDefault(require(\"deepmerge\"));\n\nvar _indigo = _interopRequireDefault(require(\"../colors/indigo\"));\n\nvar _pink = _interopRequireDefault(require(\"../colors/pink\"));\n\nvar _grey = _interopRequireDefault(require(\"../colors/grey\"));\n\nvar _red = _interopRequireDefault(require(\"../colors/red\"));\n\nvar _common = _interopRequireDefault(require(\"../colors/common\"));\n\nvar _colorManipulator = require(\"./colorManipulator\");\n\n// < 1kb payload overhead when lodash/merge is > 3kb.\nvar light = {\n // The colors used to style the text.\n text: {\n // The most important text.\n primary: 'rgba(0, 0, 0, 0.87)',\n // Secondary text.\n secondary: 'rgba(0, 0, 0, 0.54)',\n // Disabled text have even lower visual prominence.\n disabled: 'rgba(0, 0, 0, 0.38)',\n // Text hints.\n hint: 'rgba(0, 0, 0, 0.38)'\n },\n // The color used to divide different elements.\n divider: 'rgba(0, 0, 0, 0.12)',\n // The background colors used to style the surfaces.\n // Consistency between these values is important.\n background: {\n paper: _common.default.white,\n default: _grey.default[50]\n },\n // The colors used to style the action elements.\n action: {\n // The color of an active action like an icon button.\n active: 'rgba(0, 0, 0, 0.54)',\n // The color of an hovered action.\n hover: 'rgba(0, 0, 0, 0.08)',\n hoverOpacity: 0.08,\n // The color of a selected action.\n selected: 'rgba(0, 0, 0, 0.14)',\n // The color of a disabled action.\n disabled: 'rgba(0, 0, 0, 0.26)',\n // The background color of a disabled action.\n disabledBackground: 'rgba(0, 0, 0, 0.12)'\n }\n};\nexports.light = light;\nvar dark = {\n text: {\n primary: _common.default.white,\n secondary: 'rgba(255, 255, 255, 0.7)',\n disabled: 'rgba(255, 255, 255, 0.5)',\n hint: 'rgba(255, 255, 255, 0.5)',\n icon: 'rgba(255, 255, 255, 0.5)'\n },\n divider: 'rgba(255, 255, 255, 0.12)',\n background: {\n paper: _grey.default[800],\n default: '#303030'\n },\n action: {\n active: _common.default.white,\n hover: 'rgba(255, 255, 255, 0.1)',\n hoverOpacity: 0.1,\n selected: 'rgba(255, 255, 255, 0.2)',\n disabled: 'rgba(255, 255, 255, 0.3)',\n disabledBackground: 'rgba(255, 255, 255, 0.12)'\n }\n};\nexports.dark = dark;\n\nfunction addLightOrDark(intent, direction, shade, tonalOffset) {\n if (!intent[direction]) {\n if (intent.hasOwnProperty(shade)) {\n intent[direction] = intent[shade];\n } else if (direction === 'light') {\n intent.light = (0, _colorManipulator.lighten)(intent.main, tonalOffset);\n } else if (direction === 'dark') {\n intent.dark = (0, _colorManipulator.darken)(intent.main, tonalOffset * 1.5);\n }\n }\n}\n\nfunction createPalette(palette) {\n var _palette$primary = palette.primary,\n primary = _palette$primary === void 0 ? {\n light: _indigo.default[300],\n main: _indigo.default[500],\n dark: _indigo.default[700]\n } : _palette$primary,\n _palette$secondary = palette.secondary,\n secondary = _palette$secondary === void 0 ? {\n light: _pink.default.A200,\n main: _pink.default.A400,\n dark: _pink.default.A700\n } : _palette$secondary,\n _palette$error = palette.error,\n error = _palette$error === void 0 ? {\n light: _red.default[300],\n main: _red.default[500],\n dark: _red.default[700]\n } : _palette$error,\n _palette$type = palette.type,\n type = _palette$type === void 0 ? 'light' : _palette$type,\n _palette$contrastThre = palette.contrastThreshold,\n contrastThreshold = _palette$contrastThre === void 0 ? 3 : _palette$contrastThre,\n _palette$tonalOffset = palette.tonalOffset,\n tonalOffset = _palette$tonalOffset === void 0 ? 0.2 : _palette$tonalOffset,\n other = (0, _objectWithoutProperties2.default)(palette, [\"primary\", \"secondary\", \"error\", \"type\", \"contrastThreshold\", \"tonalOffset\"]);\n\n function getContrastText(background) {\n // Use the same logic as\n // Bootstrap: https://github.com/twbs/bootstrap/blob/1d6e3710dd447de1a200f29e8fa521f8a0908f70/scss/_functions.scss#L59\n // and material-components-web https://github.com/material-components/material-components-web/blob/ac46b8863c4dab9fc22c4c662dc6bd1b65dd652f/packages/mdc-theme/_functions.scss#L54\n var contrastText = (0, _colorManipulator.getContrastRatio)(background, dark.text.primary) >= contrastThreshold ? dark.text.primary : light.text.primary;\n\n if (process.env.NODE_ENV !== 'production') {\n var contrast = (0, _colorManipulator.getContrastRatio)(background, contrastText);\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(contrast >= 3, [\"Material-UI: the contrast ratio of \".concat(contrast, \":1 for \").concat(contrastText, \" on \").concat(background), 'falls below the WACG recommended absolute minimum contrast ratio of 3:1.', 'https://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-contrast'].join('\\n')) : void 0;\n }\n\n return contrastText;\n }\n\n function augmentColor(color) {\n var mainShade = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;\n var lightShade = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 300;\n var darkShade = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 700;\n\n if (!color.main && color[mainShade]) {\n color.main = color[mainShade];\n }\n\n if (process.env.NODE_ENV !== 'production' && !color.main) {\n throw new Error(['Material-UI: the color provided to augmentColor(color) is invalid.', \"The color object needs to have a `) + ("`" + (`main` + "`"))) + ((` property or a ` + ("`" + `\".concat(mainShade, \"`)) + ("`" + (` property.\")].join('\\n'));\n }\n\n addLightOrDark(color, 'light', lightShade, tonalOffset);\n addLightOrDark(color, 'dark', darkShade, tonalOffset);\n\n if (!color.contrastText) {\n color.contrastText = getContrastText(color.main);\n }\n\n return color;\n }\n\n augmentColor(primary);\n augmentColor(secondary, 'A400', 'A200', 'A700');\n augmentColor(error);\n var types = {\n dark: dark,\n light: light\n };\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(types[type], \"Material-UI: the palette type ` + "`")))) + (((`\".concat(type, \"` + "`") + (` is not supported.\")) : void 0;\n var paletteOutput = (0, _deepmerge.default)((0, _extends2.default)({\n // A collection of common colors.\n common: _common.default,\n // The palette type, can be light or dark.\n type: type,\n // The colors used to represent primary interface elements for a user.\n primary: primary,\n // The colors used to represent secondary interface elements for a user.\n secondary: secondary,\n // The colors used to represent interface elements that the user should be made aware of.\n error: error,\n // The grey colors.\n grey: _grey.default,\n // Used by ` + ("`" + `getContrastText()`))) + (("`" + (` to maximize the contrast between the background and\n // the text.\n contrastThreshold: contrastThreshold,\n // Take a background color and return the color of the text to maximize the contrast.\n getContrastText: getContrastText,\n // Generate a rich color object.\n augmentColor: augmentColor,\n // Used by the functions below to shift a color's luminance by approximately\n // two indexes within its tonal palette.\n // E.g., shift from Red 500 to Red 300 or Red 700.\n tonalOffset: tonalOffset\n }, types[type]), other, {\n clone: false // No need to clone deep\n\n });\n return paletteOutput;\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = createTypography;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _deepmerge = _interopRequireDefault(require(\"deepmerge\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\n// < 1kb payload overhead when lodash/merge is > 3kb.\nfunction round(value) {\n return Math.round(value * 1e5) / 1e5;\n}\n\nvar caseAllCaps = {\n textTransform: 'uppercase'\n};\nvar defaultFontFamily = '\"Roboto\", \"Helvetica\", \"Arial\", sans-serif';\n/**\r\n * @see @link{https://material.io/design/typography/the-type-system.html}\r\n * @see @link{https://material.io/design/typography/understanding-typography.html}\r\n */\n\nfunction createTypography(palette, typography) {\n var _ref = typeof typography === 'function' ? typography(palette) : typography,\n _ref$fontFamily = _ref.fontFamily,\n fontFamily = _ref$fontFamily === void 0 ? defaultFontFamily : _ref$fontFamily,\n _ref$fontSize = _ref.fontSize,\n fontSize = _ref$fontSize === void 0 ? 14 : _ref$fontSize,\n _ref$fontWeightLight = _ref.fontWeightLight,\n fontWeightLight = _ref$fontWeightLight === void 0 ? 300 : _ref$fontWeightLight,\n _ref$fontWeightRegula = _ref.fontWeightRegular,\n fontWeightRegular = _ref$fontWeightRegula === void 0 ? 400 : _ref$fontWeightRegula,\n _ref$fontWeightMedium = _ref.fontWeightMedium,\n fontWeightMedium = _ref$fontWeightMedium === void 0 ? 500 : _ref$fontWeightMedium,\n _ref$htmlFontSize = _ref.htmlFontSize,\n htmlFontSize = _ref$htmlFontSize === void 0 ? 16 : _ref$htmlFontSize,\n _ref$useNextVariants = _ref.useNextVariants,\n useNextVariants = _ref$useNextVariants === void 0 ? Boolean(_utils.ponyfillGlobal.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__) : _ref$useNextVariants,\n _ref$suppressWarning = _ref.suppressWarning,\n suppressWarning = _ref$suppressWarning === void 0 ? false : _ref$suppressWarning,\n allVariants = _ref.allVariants,\n other = (0, _objectWithoutProperties2.default)(_ref, [\"fontFamily\", \"fontSize\", \"fontWeightLight\", \"fontWeightRegular\", \"fontWeightMedium\", \"htmlFontSize\", \"useNextVariants\", \"suppressWarning\", \"allVariants\"]);\n\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(useNextVariants || suppressWarning, 'Material-UI: you are using the deprecated typography variants ' + 'that will be removed in the next major release.' + '\\nPlease read the migration guide under https://material-ui.com/style/typography#migration-to-typography-v2') : void 0;\n var coef = fontSize / 14;\n\n var pxToRem = function pxToRem(size) {\n return \"\".concat(size / htmlFontSize * coef, \"rem\");\n };\n\n var buildVariant = function buildVariant(fontWeight, size, lineHeight, letterSpacing, casing) {\n return (0, _extends2.default)({\n color: palette.text.primary,\n fontFamily: fontFamily,\n fontWeight: fontWeight,\n fontSize: pxToRem(size),\n // Unitless following http://meyerweb.com/eric/thoughts/2006/02/08/unitless-line-heights/\n lineHeight: lineHeight\n }, fontFamily === defaultFontFamily ? {\n letterSpacing: \"\".concat(round(letterSpacing / size), \"em\")\n } : {}, casing, allVariants);\n };\n\n var nextVariants = {\n h1: buildVariant(fontWeightLight, 96, 1, -1.5),\n h2: buildVariant(fontWeightLight, 60, 1, -0.5),\n h3: buildVariant(fontWeightRegular, 48, 1.04, 0),\n h4: buildVariant(fontWeightRegular, 34, 1.17, 0.25),\n h5: buildVariant(fontWeightRegular, 24, 1.33, 0),\n h6: buildVariant(fontWeightMedium, 20, 1.6, 0.15),\n subtitle1: buildVariant(fontWeightRegular, 16, 1.75, 0.15),\n subtitle2: buildVariant(fontWeightMedium, 14, 1.57, 0.1),\n body1Next: buildVariant(fontWeightRegular, 16, 1.5, 0.15),\n body2Next: buildVariant(fontWeightRegular, 14, 1.5, 0.15),\n buttonNext: buildVariant(fontWeightMedium, 14, 1.75, 0.4, caseAllCaps),\n captionNext: buildVariant(fontWeightRegular, 12, 1.66, 0.4),\n overline: buildVariant(fontWeightRegular, 12, 2.66, 1, caseAllCaps)\n }; // To remove in v4\n\n var oldVariants = {\n display4: (0, _extends2.default)({\n fontSize: pxToRem(112),\n fontWeight: fontWeightLight,\n fontFamily: fontFamily,\n letterSpacing: '-.04em',\n lineHeight: \"\".concat(round(128 / 112), \"em\"),\n marginLeft: '-.04em',\n color: palette.text.secondary\n }, allVariants),\n display3: (0, _extends2.default)({\n fontSize: pxToRem(56),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n letterSpacing: '-.02em',\n lineHeight: \"\".concat(round(73 / 56), \"em\"),\n marginLeft: '-.02em',\n color: palette.text.secondary\n }, allVariants),\n display2: (0, _extends2.default)({\n fontSize: pxToRem(45),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(51 / 45), \"em\"),\n marginLeft: '-.02em',\n color: palette.text.secondary\n }, allVariants),\n display1: (0, _extends2.default)({\n fontSize: pxToRem(34),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(41 / 34), \"em\"),\n color: palette.text.secondary\n }, allVariants),\n headline: (0, _extends2.default)({\n fontSize: pxToRem(24),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(32.5 / 24), \"em\"),\n color: palette.text.primary\n }, allVariants),\n title: (0, _extends2.default)({\n fontSize: pxToRem(21),\n fontWeight: fontWeightMedium,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(24.5 / 21), \"em\"),\n color: palette.text.primary\n }, allVariants),\n subheading: (0, _extends2.default)({\n fontSize: pxToRem(16),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(24 / 16), \"em\"),\n color: palette.text.primary\n }, allVariants),\n body2: (0, _extends2.default)({\n fontSize: pxToRem(14),\n fontWeight: fontWeightMedium,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(24 / 14), \"em\"),\n color: palette.text.primary\n }, allVariants),\n body1: (0, _extends2.default)({\n fontSize: pxToRem(14),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(20.5 / 14), \"em\"),\n color: palette.text.primary\n }, allVariants),\n caption: (0, _extends2.default)({\n fontSize: pxToRem(12),\n fontWeight: fontWeightRegular,\n fontFamily: fontFamily,\n lineHeight: \"\".concat(round(16.5 / 12), \"em\"),\n color: palette.text.secondary\n }, allVariants),\n button: (0, _extends2.default)({\n fontSize: pxToRem(14),\n textTransform: 'uppercase',\n fontWeight: fontWeightMedium,\n fontFamily: fontFamily,\n color: palette.text.primary\n }, allVariants)\n };\n return (0, _deepmerge.default)((0, _extends2.default)({\n pxToRem: pxToRem,\n round: round,\n fontFamily: fontFamily,\n fontSize: fontSize,\n fontWeightLight: fontWeightLight,\n fontWeightRegular: fontWeightRegular,\n fontWeightMedium: fontWeightMedium\n }, oldVariants, nextVariants, useNextVariants ? {\n body1: nextVariants.body1Next,\n body2: nextVariants.body2Next,\n button: nextVariants.buttonNext,\n caption: nextVariants.captionNext\n } : {}, {\n useNextVariants: useNextVariants\n }), other, {\n clone: false // No need to clone deep\n\n });\n}", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _typeof2 = _interopRequireDefault(require(\"@babel/runtime/helpers/typeof\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _deepmerge = _interopRequireDefault(require(\"deepmerge\"));\n\n// < 1kb payload overhead when lodash/merge is > 3kb.\n// Support for the jss-expand plugin.\nfunction arrayMerge(destination, source) {\n return source;\n}\n\nfunction getStylesCreator(stylesOrCreator) {\n var themingEnabled = typeof stylesOrCreator === 'function';\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)((0, _typeof2.default)(stylesOrCreator) === 'object' || themingEnabled, ['Material-UI: the first argument provided to withStyles() is invalid.', 'You need to provide a function generating the styles or a styles object.'].join('\\n')) : void 0;\n\n function create(theme, name) {\n var styles = themingEnabled ? stylesOrCreator(theme) : stylesOrCreator;\n\n if (!name || !theme.overrides || !theme.overrides[name]) {\n return styles;\n }\n\n var overrides = theme.overrides[name];\n var stylesWithOverrides = (0, _extends2.default)({}, styles);\n Object.keys(overrides).forEach(function (key) {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(stylesWithOverrides[key], ['Material-UI: you are trying to override a style that does not exist.', \"Fix the ` + "`")) + (`\".concat(key, \"` + ("`" + ` key of `)))))) + ((((("`" + `theme.overrides.\").concat(name, \"`) + ("`" + (`.\")].join('\\n')) : void 0;\n stylesWithOverrides[key] = (0, _deepmerge.default)(stylesWithOverrides[key], overrides[key], {\n arrayMerge: arrayMerge\n });\n });\n return stylesWithOverrides;\n }\n\n return {\n create: create,\n options: {},\n themingEnabled: themingEnabled\n };\n}\n\nvar _default = getStylesCreator;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\n/* eslint-disable no-restricted-syntax */\nfunction getThemeProps(params) {\n var theme = params.theme,\n name = params.name,\n props = params.props;\n\n if (!theme.props || !name || !theme.props[name]) {\n return props;\n } // Resolve default props, code borrow from React source.\n // https://github.com/facebook/react/blob/15a8f031838a553e41c0b66eb1bcf1da8448104d/packages/react/src/ReactElement.js#L221\n\n\n var defaultProps = theme.props[name];\n var propName;\n\n for (propName in defaultProps) {\n if (props[propName] === undefined) {\n props[propName] = defaultProps[propName];\n }\n }\n\n return props;\n}\n\nvar _default = getThemeProps;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _jssGlobal = _interopRequireDefault(require(\"jss-global\"));\n\nvar _jssNested = _interopRequireDefault(require(\"jss-nested\"));\n\nvar _jssCamelCase = _interopRequireDefault(require(\"jss-camel-case\"));\n\nvar _jssDefaultUnit = _interopRequireDefault(require(\"jss-default-unit\"));\n\nvar _jssVendorPrefixer = _interopRequireDefault(require(\"jss-vendor-prefixer\"));\n\nvar _jssPropsSort = _interopRequireDefault(require(\"jss-props-sort\"));\n\n// Subset of jss-preset-default with only the plugins the Material-UI components are using.\nfunction jssPreset() {\n return {\n plugins: [(0, _jssGlobal.default)(), (0, _jssNested.default)(), (0, _jssCamelCase.default)(), (0, _jssDefaultUnit.default)(), // Disable the vendor prefixer server-side, it does nothing.\n // This way, we can get a performance boost.\n // In the documentation, we are using ` + "`"))) + ((`autoprefixer` + ("`" + ` to solve this problem.\n typeof window === 'undefined' ? null : (0, _jssVendorPrefixer.default)(), (0, _jssPropsSort.default)()]\n };\n}\n\nvar _default = jssPreset;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _extends2 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nfunction mergeClasses() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var baseClasses = options.baseClasses,\n newClasses = options.newClasses,\n Component = options.Component;\n\n if (!newClasses) {\n return baseClasses;\n }\n\n var nextClasses = (0, _extends2.default)({}, baseClasses);\n\n if (process.env.NODE_ENV !== 'production' && typeof newClasses === 'string') {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(false, [\"Material-UI: the value `)) + ("`" + (`\".concat(newClasses, \"` + "`")))) + (((` \") + \"provided to the classes property of \".concat((0, _utils.getDisplayName)(Component), \" is incorrect.\"), 'You might want to use the className property instead.'].join('\\n')) : void 0;\n return baseClasses;\n }\n\n Object.keys(newClasses).forEach(function (key) {\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(baseClasses[key] || !newClasses[key], [\"Material-UI: the key ` + "`") + (`\".concat(key, \"` + ("`" + ` \") + \"provided to the classes property is not implemented in \".concat((0, _utils.getDisplayName)(Component), \".\"), \"You can only override one of the following: \".concat(Object.keys(baseClasses).join(','), \".\")].join('\\n')) : void 0;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(!newClasses[key] || typeof newClasses[key] === 'string', [\"Material-UI: the key `))) + (("`" + (`\".concat(key, \"` + "`")) + (` \") + \"provided to the classes property is not valid for \".concat((0, _utils.getDisplayName)(Component), \".\"), \"You need to provide a non empty string instead of: \".concat(newClasses[key], \".\")].join('\\n')) : void 0;\n\n if (newClasses[key]) {\n nextClasses[key] = \"\".concat(baseClasses[key], \" \").concat(newClasses[key]);\n }\n });\n return nextClasses;\n}\n\nvar _default = mergeClasses;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n// Used https://github.com/thinkloop/multi-key-cache as inspiration\nvar multiKeyStore = {\n set: function set(cache, key1, key2, value) {\n var subCache = cache.get(key1);\n\n if (!subCache) {\n subCache = new Map();\n cache.set(key1, subCache);\n }\n\n subCache.set(key2, value);\n },\n get: function get(cache, key1, key2) {\n var subCache = cache.get(key1);\n return subCache ? subCache.get(key2) : undefined;\n },\n delete: function _delete(cache, key1, key2) {\n var subCache = cache.get(key1);\n subCache.delete(key2);\n }\n};\nvar _default = multiKeyStore;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n// Share the same values than in\n// https://github.com/cssinjs/jss/blob/master/packages/react-jss/src/ns.js\nvar ns = {\n jss: '64a55d578f856d258dc345b094a2a2b3',\n sheetsRegistry: 'd4bd0baacbc52bbd48bbb9eb24344ecd',\n sheetOptions: '6fc570d6bd61383819d0f9e7407c452d'\n};\nvar _default = ns;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar shadowKeyUmbraOpacity = 0.2;\nvar shadowKeyPenumbraOpacity = 0.14;\nvar shadowAmbientShadowOpacity = 0.12;\n\nfunction createShadow() {\n return [\"\".concat(arguments.length <= 0 ? undefined : arguments[0], \"px \").concat(arguments.length <= 1 ? undefined : arguments[1], \"px \").concat(arguments.length <= 2 ? undefined : arguments[2], \"px \").concat(arguments.length <= 3 ? undefined : arguments[3], \"px rgba(0,0,0,\").concat(shadowKeyUmbraOpacity, \")\"), \"\".concat(arguments.length <= 4 ? undefined : arguments[4], \"px \").concat(arguments.length <= 5 ? undefined : arguments[5], \"px \").concat(arguments.length <= 6 ? undefined : arguments[6], \"px \").concat(arguments.length <= 7 ? undefined : arguments[7], \"px rgba(0,0,0,\").concat(shadowKeyPenumbraOpacity, \")\"), \"\".concat(arguments.length <= 8 ? undefined : arguments[8], \"px \").concat(arguments.length <= 9 ? undefined : arguments[9], \"px \").concat(arguments.length <= 10 ? undefined : arguments[10], \"px \").concat(arguments.length <= 11 ? undefined : arguments[11], \"px rgba(0,0,0,\").concat(shadowAmbientShadowOpacity, \")\")].join(',');\n}\n\nvar shadows = ['none', createShadow(0, 1, 3, 0, 0, 1, 1, 0, 0, 2, 1, -1), createShadow(0, 1, 5, 0, 0, 2, 2, 0, 0, 3, 1, -2), createShadow(0, 1, 8, 0, 0, 3, 4, 0, 0, 3, 3, -2), createShadow(0, 2, 4, -1, 0, 4, 5, 0, 0, 1, 10, 0), createShadow(0, 3, 5, -1, 0, 5, 8, 0, 0, 1, 14, 0), createShadow(0, 3, 5, -1, 0, 6, 10, 0, 0, 1, 18, 0), createShadow(0, 4, 5, -2, 0, 7, 10, 1, 0, 2, 16, 1), createShadow(0, 5, 5, -3, 0, 8, 10, 1, 0, 3, 14, 2), createShadow(0, 5, 6, -3, 0, 9, 12, 1, 0, 3, 16, 2), createShadow(0, 6, 6, -3, 0, 10, 14, 1, 0, 4, 18, 3), createShadow(0, 6, 7, -4, 0, 11, 15, 1, 0, 4, 20, 3), createShadow(0, 7, 8, -4, 0, 12, 17, 2, 0, 5, 22, 4), createShadow(0, 7, 8, -4, 0, 13, 19, 2, 0, 5, 24, 4), createShadow(0, 7, 9, -4, 0, 14, 21, 2, 0, 5, 26, 4), createShadow(0, 8, 9, -5, 0, 15, 22, 2, 0, 6, 28, 5), createShadow(0, 8, 10, -5, 0, 16, 24, 2, 0, 6, 30, 5), createShadow(0, 8, 11, -5, 0, 17, 26, 2, 0, 6, 32, 5), createShadow(0, 9, 11, -5, 0, 18, 28, 2, 0, 7, 34, 6), createShadow(0, 9, 12, -6, 0, 19, 29, 2, 0, 7, 36, 6), createShadow(0, 10, 13, -6, 0, 20, 31, 3, 0, 8, 38, 7), createShadow(0, 10, 13, -6, 0, 21, 33, 3, 0, 8, 40, 7), createShadow(0, 10, 14, -6, 0, 22, 35, 3, 0, 8, 42, 7), createShadow(0, 11, 14, -7, 0, 23, 36, 3, 0, 9, 44, 8), createShadow(0, 11, 15, -7, 0, 24, 38, 3, 0, 9, 46, 8)];\nvar _default = shadows;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar shape = {\n borderRadius: 4\n};\nvar _default = shape;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\nvar spacing = {\n // All components align to an 8dp square baseline grid for mobile, tablet, and desktop.\n // https://material.io/design/layout/understanding-layout.html#pixel-density\n unit: 8\n};\nvar _default = spacing;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.CHANNEL = void 0;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\n// Same value used by react-jss\nvar CHANNEL = '__THEMING__';\nexports.CHANNEL = CHANNEL;\nvar themeListener = {\n contextTypes: (0, _defineProperty2.default)({}, CHANNEL, function () {}),\n initial: function initial(context) {\n if (!context[CHANNEL]) {\n return null;\n }\n\n return context[CHANNEL].getState();\n },\n subscribe: function subscribe(context, cb) {\n if (!context[CHANNEL]) {\n return null;\n }\n\n return context[CHANNEL].subscribe(cb);\n },\n unsubscribe: function unsubscribe(context, subscriptionId) {\n if (context[CHANNEL]) {\n context[CHANNEL].unsubscribe(subscriptionId);\n }\n }\n};\nvar _default = themeListener;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.isNumber = exports.isString = exports.formatMs = exports.duration = exports.easing = void 0;\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\n/* eslint-disable no-restricted-globals */\n// Follow https://material.google.com/motion/duration-easing.html#duration-easing-natural-easing-curves\n// to learn the context in which each easing should be used.\nvar easing = {\n // This is the most common easing curve.\n easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',\n // Objects enter the screen at full velocity from off-screen and\n // slowly decelerate to a resting point.\n easeOut: 'cubic-bezier(0.0, 0, 0.2, 1)',\n // Objects leave the screen at full velocity. They do not decelerate when off-screen.\n easeIn: 'cubic-bezier(0.4, 0, 1, 1)',\n // The sharp curve is used by objects that may return to the screen at any time.\n sharp: 'cubic-bezier(0.4, 0, 0.6, 1)'\n}; // Follow https://material.io/guidelines/motion/duration-easing.html#duration-easing-common-durations\n// to learn when use what timing\n\nexports.easing = easing;\nvar duration = {\n shortest: 150,\n shorter: 200,\n short: 250,\n // most basic recommended timing\n standard: 300,\n // this is to be used in complex animations\n complex: 375,\n // recommended when something is entering screen\n enteringScreen: 225,\n // recommended when something is leaving screen\n leavingScreen: 195\n};\nexports.duration = duration;\n\nvar formatMs = function formatMs(milliseconds) {\n return \"\".concat(Math.round(milliseconds), \"ms\");\n};\n\nexports.formatMs = formatMs;\n\nvar isString = function isString(value) {\n return typeof value === 'string';\n};\n\nexports.isString = isString;\n\nvar isNumber = function isNumber(value) {\n return !isNaN(parseFloat(value));\n};\n/**\r\n * @param {string|Array} props\r\n * @param {object} param\r\n * @param {string} param.prop\r\n * @param {number} param.duration\r\n * @param {string} param.easing\r\n * @param {number} param.delay\r\n */\n\n\nexports.isNumber = isNumber;\nvar _default = {\n easing: easing,\n duration: duration,\n create: function create() {\n var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['all'];\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var _options$duration = options.duration,\n durationOption = _options$duration === void 0 ? duration.standard : _options$duration,\n _options$easing = options.easing,\n easingOption = _options$easing === void 0 ? easing.easeInOut : _options$easing,\n _options$delay = options.delay,\n delay = _options$delay === void 0 ? 0 : _options$delay,\n other = (0, _objectWithoutProperties2.default)(options, [\"duration\", \"easing\", \"delay\"]);\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(isString(props) || Array.isArray(props), 'Material-UI: argument \"props\" must be a string or Array.') : void 0;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(isNumber(durationOption) || isString(durationOption), \"Material-UI: argument \\\"duration\\\" must be a number or a string but found \".concat(durationOption, \".\")) : void 0;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(isString(easingOption), 'Material-UI: argument \"easing\" must be a string.') : void 0;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(isNumber(delay) || isString(delay), 'Material-UI: argument \"delay\" must be a number or a string.') : void 0;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(Object.keys(other).length === 0, \"Material-UI: unrecognized argument(s) [\".concat(Object.keys(other).join(','), \"]\")) : void 0;\n return (Array.isArray(props) ? props : [props]).map(function (animatedProp) {\n return \"\".concat(animatedProp, \" \").concat(typeof durationOption === 'string' ? durationOption : formatMs(durationOption), \" \").concat(easingOption, \" \").concat(typeof delay === 'string' ? delay : formatMs(delay));\n }).join(',');\n },\n getAutoHeightDuration: function getAutoHeightDuration(height) {\n if (!height) {\n return 0;\n }\n\n var constant = height / 36; // https://www.wolframalpha.com/input/?i=(4+%2B+15+*+(x+%2F+36+)+**+0.25+%2B+(x+%2F+36)+%2F+5)+*+10\n\n return Math.round((4 + 15 * Math.pow(constant, 0.25) + constant / 5) * 10);\n }\n};\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.sheetsManager = void 0;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _extends3 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _possibleConstructorReturn2 = _interopRequireDefault(require(\"@babel/runtime/helpers/possibleConstructorReturn\"));\n\nvar _getPrototypeOf2 = _interopRequireDefault(require(\"@babel/runtime/helpers/getPrototypeOf\"));\n\nvar _inherits2 = _interopRequireDefault(require(\"@babel/runtime/helpers/inherits\"));\n\nvar _objectWithoutProperties2 = _interopRequireDefault(require(\"@babel/runtime/helpers/objectWithoutProperties\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\nvar _hoistNonReactStatics = _interopRequireDefault(require(\"hoist-non-react-statics\"));\n\nvar _utils = require(\"@material-ui/utils\");\n\nvar _jss = require(\"jss\");\n\nvar _reactJssContext = _interopRequireDefault(require(\"./reactJssContext\"));\n\nvar _jssPreset = _interopRequireDefault(require(\"./jssPreset\"));\n\nvar _mergeClasses = _interopRequireDefault(require(\"./mergeClasses\"));\n\nvar _multiKeyStore = _interopRequireDefault(require(\"./multiKeyStore\"));\n\nvar _createMuiTheme = _interopRequireDefault(require(\"./createMuiTheme\"));\n\nvar _themeListener = _interopRequireDefault(require(\"./themeListener\"));\n\nvar _createGenerateClassName = _interopRequireDefault(require(\"./createGenerateClassName\"));\n\nvar _getStylesCreator = _interopRequireDefault(require(\"./getStylesCreator\"));\n\nvar _getThemeProps = _interopRequireDefault(require(\"./getThemeProps\"));\n\n/* eslint-disable no-underscore-dangle */\n// Default JSS instance.\nvar jss = (0, _jss.create)((0, _jssPreset.default)()); // Use a singleton or the provided one by the context.\n//\n// The counter-based approach doesn't tolerate any mistake.\n// It's much safer to use the same counter everywhere.\n\nvar generateClassName = (0, _createGenerateClassName.default)(); // Global index counter to preserve source order.\n// We create the style sheet during at the creation of the component,\n// children are handled after the parents, so the order of style elements would be parent->child.\n// It is a problem though when a parent passes a className\n// which needs to override any child's styles.\n// StyleSheet of the child has a higher specificity, because of the source order.\n// So our solution is to render sheets them in the reverse order child->sheet, so\n// that parent has a higher specificity.\n\nvar indexCounter = -10e10; // Exported for test purposes\n\nvar sheetsManager = new Map(); // We use the same empty object to ref count the styles that don't need a theme object.\n\nexports.sheetsManager = sheetsManager;\nvar noopTheme = {}; // In order to have self-supporting components, we rely on default theme when not provided.\n\nvar defaultTheme = (0, _createMuiTheme.default)({\n typography: {\n suppressWarning: true\n }\n}); // Link a style sheet with a component.\n// It does not modify the component passed to it;\n// instead, it returns a new component, with a ` + ("`" + `classes`))))) + (((("`" + ` property.\n\nvar withStylesOld = function withStylesOld(stylesOrCreator) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return function (Component) {\n var _extends2;\n\n var _options$withTheme = options.withTheme,\n withTheme = _options$withTheme === void 0 ? false : _options$withTheme,\n _options$flip = options.flip,\n flip = _options$flip === void 0 ? null : _options$flip,\n name = options.name,\n styleSheetOptions = (0, _objectWithoutProperties2.default)(options, [\"withTheme\", \"flip\", \"name\"]);\n var stylesCreator = (0, _getStylesCreator.default)(stylesOrCreator);\n var listenToTheme = stylesCreator.themingEnabled || typeof name === 'string' || withTheme;\n indexCounter += 1;\n stylesCreator.options.index = indexCounter;\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(indexCounter < 0, ['Material-UI: you might have a memory leak.', 'The indexCounter is not supposed to grow that much.'].join('\\n')) : void 0;\n\n var WithStyles =\n /*#__PURE__*/\n function (_React$Component) {\n (0, _inherits2.default)(WithStyles, _React$Component);\n\n function WithStyles(props, context) {\n var _this;\n\n (0, _classCallCheck2.default)(this, WithStyles);\n _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(WithStyles).call(this, props, context));\n _this.jss = context[_reactJssContext.default.jss] || jss;\n _this.sheetsManager = sheetsManager;\n _this.unsubscribeId = null;\n var muiThemeProviderOptions = context.muiThemeProviderOptions;\n\n if (muiThemeProviderOptions) {\n if (muiThemeProviderOptions.sheetsManager) {\n _this.sheetsManager = muiThemeProviderOptions.sheetsManager;\n }\n\n _this.sheetsCache = muiThemeProviderOptions.sheetsCache;\n _this.disableStylesGeneration = muiThemeProviderOptions.disableStylesGeneration;\n } // Attach the stylesCreator to the instance of the component as in the context\n // of react-hot-loader the hooks can be executed in a different closure context:\n // https://github.com/gaearon/react-hot-loader/blob/master/src/patch.dev.js#L107\n\n\n _this.stylesCreatorSaved = stylesCreator;\n _this.sheetOptions = (0, _extends3.default)({\n generateClassName: generateClassName\n }, context[_reactJssContext.default.sheetOptions]); // We use || as the function call is lazy evaluated.\n\n _this.theme = listenToTheme ? _themeListener.default.initial(context) || defaultTheme : noopTheme;\n\n _this.attach(_this.theme);\n\n _this.cacheClasses = {\n // Cache for the finalized classes value.\n value: null,\n // Cache for the last used classes prop pointer.\n lastProp: null,\n // Cache for the last used rendered classes pointer.\n lastJSS: {}\n };\n return _this;\n }\n\n (0, _createClass2.default)(WithStyles, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this2 = this;\n\n if (!listenToTheme) {\n return;\n }\n\n this.unsubscribeId = _themeListener.default.subscribe(this.context, function (theme) {\n var oldTheme = _this2.theme;\n _this2.theme = theme;\n\n _this2.attach(_this2.theme); // Rerender the component so the underlying component gets the theme update.\n // By theme update we mean receiving and applying the new class names.\n\n\n _this2.setState({}, function () {\n _this2.detach(oldTheme);\n });\n });\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate() {\n // react-hot-loader specific logic\n if (this.stylesCreatorSaved === stylesCreator || process.env.NODE_ENV === 'production') {\n return;\n }\n\n this.detach(this.theme);\n this.stylesCreatorSaved = stylesCreator;\n this.attach(this.theme);\n this.forceUpdate();\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n this.detach(this.theme);\n\n if (this.unsubscribeId !== null) {\n _themeListener.default.unsubscribe(this.context, this.unsubscribeId);\n }\n }\n }, {\n key: \"getClasses\",\n value: function getClasses() {\n if (this.disableStylesGeneration) {\n return this.props.classes || {};\n } // Tracks if either the rendered classes or classes prop has changed,\n // requiring the generation of a new finalized classes object.\n\n\n var generate = false;\n\n var sheetManager = _multiKeyStore.default.get(this.sheetsManager, this.stylesCreatorSaved, this.theme);\n\n if (sheetManager.sheet.classes !== this.cacheClasses.lastJSS) {\n this.cacheClasses.lastJSS = sheetManager.sheet.classes;\n generate = true;\n }\n\n if (this.props.classes !== this.cacheClasses.lastProp) {\n this.cacheClasses.lastProp = this.props.classes;\n generate = true;\n }\n\n if (generate) {\n this.cacheClasses.value = (0, _mergeClasses.default)({\n baseClasses: this.cacheClasses.lastJSS,\n newClasses: this.props.classes,\n Component: Component\n });\n }\n\n return this.cacheClasses.value;\n }\n }, {\n key: \"attach\",\n value: function attach(theme) {\n if (this.disableStylesGeneration) {\n return;\n }\n\n var stylesCreatorSaved = this.stylesCreatorSaved;\n\n var sheetManager = _multiKeyStore.default.get(this.sheetsManager, stylesCreatorSaved, theme);\n\n if (!sheetManager) {\n sheetManager = {\n refs: 0,\n sheet: null\n };\n\n _multiKeyStore.default.set(this.sheetsManager, stylesCreatorSaved, theme, sheetManager);\n }\n\n if (sheetManager.refs === 0) {\n var sheet;\n\n if (this.sheetsCache) {\n sheet = _multiKeyStore.default.get(this.sheetsCache, stylesCreatorSaved, theme);\n }\n\n if (!sheet) {\n sheet = this.createSheet(theme);\n sheet.attach();\n\n if (this.sheetsCache) {\n _multiKeyStore.default.set(this.sheetsCache, stylesCreatorSaved, theme, sheet);\n }\n }\n\n sheetManager.sheet = sheet;\n var sheetsRegistry = this.context[_reactJssContext.default.sheetsRegistry];\n\n if (sheetsRegistry) {\n sheetsRegistry.add(sheet);\n }\n }\n\n sheetManager.refs += 1;\n }\n }, {\n key: \"createSheet\",\n value: function createSheet(theme) {\n var styles = this.stylesCreatorSaved.create(theme, name);\n var meta = name;\n\n if (process.env.NODE_ENV !== 'production' && !meta) {\n // Provide a better DX outside production.\n meta = (0, _utils.getDisplayName)(Component);\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(typeof meta === 'string', ['Material-UI: the component displayName is invalid. It needs to be a string.', \"Please fix the following component: \".concat(Component, \".\")].join('\\n')) : void 0;\n }\n\n var sheet = this.jss.createStyleSheet(styles, (0, _extends3.default)({\n meta: meta,\n classNamePrefix: meta,\n flip: typeof flip === 'boolean' ? flip : theme.direction === 'rtl',\n link: false\n }, this.sheetOptions, this.stylesCreatorSaved.options, {\n name: name || Component.displayName\n }, styleSheetOptions));\n return sheet;\n }\n }, {\n key: \"detach\",\n value: function detach(theme) {\n if (this.disableStylesGeneration) {\n return;\n }\n\n var sheetManager = _multiKeyStore.default.get(this.sheetsManager, this.stylesCreatorSaved, theme);\n\n sheetManager.refs -= 1;\n\n if (sheetManager.refs === 0) {\n _multiKeyStore.default.delete(this.sheetsManager, this.stylesCreatorSaved, theme);\n\n this.jss.removeStyleSheet(sheetManager.sheet);\n var sheetsRegistry = this.context[_reactJssContext.default.sheetsRegistry];\n\n if (sheetsRegistry) {\n sheetsRegistry.remove(sheetManager.sheet);\n }\n }\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n classes = _this$props.classes,\n innerRef = _this$props.innerRef,\n other = (0, _objectWithoutProperties2.default)(_this$props, [\"classes\", \"innerRef\"]);\n var more = (0, _getThemeProps.default)({\n theme: this.theme,\n name: name,\n props: other\n }); // Provide the theme to the wrapped component.\n // So we don't have to use the `) + ("`" + (`withTheme()` + "`"))) + ((` Higher-order Component.\n\n if (withTheme && !more.theme) {\n more.theme = this.theme;\n }\n\n return _react.default.createElement(Component, (0, _extends3.default)({}, more, {\n classes: this.getClasses(),\n ref: innerRef\n }));\n }\n }]);\n return WithStyles;\n }(_react.default.Component);\n\n process.env.NODE_ENV !== \"production\" ? WithStyles.propTypes = {\n /**\r\n * Override or extend the styles applied to the component.\r\n */\n classes: _propTypes.default.object,\n\n /**\r\n * Use that property to pass a ref callback to the decorated component.\r\n */\n innerRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object])\n } : void 0;\n WithStyles.contextTypes = (0, _extends3.default)((_extends2 = {\n muiThemeProviderOptions: _propTypes.default.object\n }, (0, _defineProperty2.default)(_extends2, _reactJssContext.default.jss, _propTypes.default.object), (0, _defineProperty2.default)(_extends2, _reactJssContext.default.sheetOptions, _propTypes.default.object), (0, _defineProperty2.default)(_extends2, _reactJssContext.default.sheetsRegistry, _propTypes.default.object), _extends2), listenToTheme ? _themeListener.default.contextTypes : {});\n\n if (process.env.NODE_ENV !== 'production') {\n WithStyles.displayName = \"WithStyles(\".concat((0, _utils.getDisplayName)(Component), \")\");\n }\n\n (0, _hoistNonReactStatics.default)(WithStyles, Component);\n\n if (process.env.NODE_ENV !== 'production') {\n // Exposed for test purposes.\n WithStyles.Naked = Component;\n WithStyles.options = options;\n }\n\n return WithStyles;\n };\n};\n/* istanbul ignore if */\n\n\nif (!_utils.ponyfillGlobal.__MUI_STYLES__) {\n _utils.ponyfillGlobal.__MUI_STYLES__ = {};\n}\n\nif (!_utils.ponyfillGlobal.__MUI_STYLES__.withStyles) {\n _utils.ponyfillGlobal.__MUI_STYLES__.withStyles = withStylesOld;\n}\n\nvar _default = function _default(styles, options) {\n return _utils.ponyfillGlobal.__MUI_STYLES__.withStyles(styles, (0, _extends3.default)({\n defaultTheme: defaultTheme\n }, options));\n};\n\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n// We need to centralize the zIndex definitions as they work\n// like global values in the browser.\nvar zIndex = {\n mobileStepper: 1000,\n appBar: 1100,\n drawer: 1200,\n modal: 1300,\n snackbar: 1400,\n tooltip: 1500\n};\nvar _default = zIndex;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nfunction deprecatedPropType(validator, reason) {\n /* istanbul ignore if */\n if (process.env.NODE_ENV === 'production') {\n return function () {\n return null;\n };\n }\n\n return function (props, propName, componentName, location, propFullName) {\n var componentNameSafe = componentName || '<>';\n var propFullNameSafe = propFullName || propName;\n\n if (typeof props[propName] !== 'undefined') {\n return new Error(\"The \".concat(location, \" ` + ("`" + `\").concat(propFullNameSafe, \"`)) + ("`" + (` of \") + \"` + "`")))) + (((`\".concat(componentNameSafe, \"` + ("`" + ` is deprecated. \").concat(reason));\n }\n\n return null;\n };\n}\n\nvar _default = deprecatedPropType;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.capitalize = capitalize;\nexports.contains = contains;\nexports.findIndex = findIndex;\nexports.find = find;\nexports.createChainedFunction = createChainedFunction;\n\nvar _typeof2 = _interopRequireDefault(require(\"@babel/runtime/helpers/typeof\"));\n\nvar _warning = _interopRequireDefault(require(\"warning\"));\n\n// It should to be noted that this function isn't equivalent to `)) + ("`" + (`text-transform: capitalize` + "`"))) + ((`.\n//\n// A strict capitalization should uppercase the first letter of each word a the sentence.\n// We only handle the first word.\nfunction capitalize(string) {\n if (process.env.NODE_ENV !== 'production' && typeof string !== 'string') {\n throw new Error('Material-UI: capitalize(string) expects a string argument.');\n }\n\n return string.charAt(0).toUpperCase() + string.slice(1);\n}\n\nfunction contains(obj, pred) {\n return Object.keys(pred).every(function (key) {\n return obj.hasOwnProperty(key) && obj[key] === pred[key];\n });\n}\n\nfunction findIndex(arr, pred) {\n var predType = (0, _typeof2.default)(pred);\n\n for (var i = 0; i < arr.length; i += 1) {\n if (predType === 'function' && !!pred(arr[i], i, arr) === true) {\n return i;\n }\n\n if (predType === 'object' && contains(arr[i], pred)) {\n return i;\n }\n\n if (['string', 'number', 'boolean'].indexOf(predType) !== -1) {\n return arr.indexOf(pred);\n }\n }\n\n return -1;\n}\n\nfunction find(arr, pred) {\n var index = findIndex(arr, pred);\n return index > -1 ? arr[index] : undefined;\n}\n/**\r\n * Safe chained function\r\n *\r\n * Will only create a new function if needed,\r\n * otherwise will pass back existing functions or null.\r\n *\r\n * @param {function} functions to chain\r\n * @returns {function|null}\r\n */\n\n\nfunction createChainedFunction() {\n for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) {\n funcs[_key] = arguments[_key];\n }\n\n return funcs.reduce(function (acc, func) {\n if (func == null) {\n return acc;\n }\n\n process.env.NODE_ENV !== \"production\" ? (0, _warning.default)(typeof func === 'function', 'Material-UI: invalid Argument Type, must only provide functions, undefined, or null.') : void 0;\n return function chainedFunction() {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n acc.apply(this, args);\n func.apply(this, args);\n };\n }, function () {});\n}", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nfunction ownerDocument(node) {\n return node && node.ownerDocument || document;\n}\n\nvar _default = ownerDocument;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _ownerDocument = _interopRequireDefault(require(\"./ownerDocument\"));\n\nfunction ownerWindow(node) {\n var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : window;\n var doc = (0, _ownerDocument.default)(node);\n return doc.defaultView || doc.parentView || fallback;\n}\n\nvar _default = ownerWindow;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.cloneElementWithClassName = cloneElementWithClassName;\nexports.cloneChildrenWithClassName = cloneChildrenWithClassName;\nexports.isMuiElement = isMuiElement;\nexports.setRef = setRef;\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _classnames = _interopRequireDefault(require(\"classnames\"));\n\nfunction cloneElementWithClassName(child, className) {\n return _react.default.cloneElement(child, {\n className: (0, _classnames.default)(child.props.className, className)\n });\n}\n\nfunction cloneChildrenWithClassName(children, className) {\n return _react.default.Children.map(children, function (child) {\n return _react.default.isValidElement(child) && cloneElementWithClassName(child, className);\n });\n}\n\nfunction isMuiElement(element, muiNames) {\n return _react.default.isValidElement(element) && muiNames.indexOf(element.type.muiName) !== -1;\n}\n\nfunction setRef(ref, value) {\n if (typeof ref === 'function') {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n}", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nfunction requirePropFactory(componentNameInError) {\n /* istanbul ignore if */\n if (process.env.NODE_ENV === 'production') {\n return function () {\n return null;\n };\n }\n\n var requireProp = function requireProp(requiredProp) {\n return function (props, propName, componentName, location, propFullName) {\n var propFullNameSafe = propFullName || propName;\n\n if (typeof props[propName] !== 'undefined' && !props[requiredProp]) {\n return new Error(\"The property ` + ("`" + `\".concat(propFullNameSafe, \"`)) + ("`" + (` of \") + \"` + "`")))))))) + (((((((`\".concat(componentNameInError, \"` + "`") + (` must be used on ` + ("`" + `\").concat(requiredProp, \"`))) + (("`" + (`.\"));\n }\n\n return null;\n };\n };\n\n return requireProp;\n}\n\nvar _default = requirePropFactory;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nfunction chainPropTypes(propType1, propType2) {\n /* istanbul ignore if */\n if (process.env.NODE_ENV === 'production') {\n return function () {\n return null;\n };\n }\n\n return function validate() {\n return propType1.apply(void 0, arguments) || propType2.apply(void 0, arguments);\n };\n}\n\nvar _default = chainPropTypes;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _typeof2 = _interopRequireDefault(require(\"@babel/runtime/helpers/typeof\"));\n\nvar _reactIs = require(\"react-is\");\n\n/**\n * A factory that returns a propTypes validator that only accepts values that\n * are also accepted by React.createElement\n * e.g. \"div\", functional, class components, forwardRef etc.\n *\n * @param {boolean} isRequired If ` + "`")) + (`true` + ("`" + ` returns a validator\n * that will throw if nullish values are passed\n */\nfunction createComponentProp(isRequired) {\n /* istanbul ignore if */\n if (process.env.NODE_ENV === 'production') {\n return function () {\n return null;\n };\n }\n\n return function componentPropType(props, key, componentName, location, propFullName) {\n var prop = props[key];\n var propName = propFullName || key;\n var message;\n\n if (prop == null) {\n if (isRequired) {\n message = \"The \".concat(location, \" `)))) + ((("`" + `\").concat(propName, \"`) + ("`" + (` is marked as required in ` + "`"))) + ((`\").concat(componentName, \"` + ("`" + `, \") + \"but its value is `)) + ("`" + (`\".concat((0, _typeof2.default)(prop), \"` + "`"))))) + ((((`.\");\n }\n } else if (!(0, _reactIs.isValidElementType)(prop)) {\n var preciseType = (0, _typeof2.default)(prop);\n message = \"Invalid \".concat(location, \" ` + "`") + (`\").concat(propName, \"` + ("`" + ` of type `))) + (("`" + (`\").concat(preciseType, \"` + "`")) + (` \") + \"supplied to ` + ("`" + `\".concat(componentName, \"`)))) + ((("`" + `, expected a component.\");\n }\n\n if (message != null) {\n // change error message slightly on every check to prevent caching when testing\n // which would not trigger console errors on subsequent fails\n return new Error(\"\".concat(message).concat(process.env.NODE_ENV === 'test' ? Date.now() : ''));\n }\n\n return null;\n };\n}\n\nvar componentPropType = createComponentProp(false);\ncomponentPropType.isRequired = createComponentProp(true);\nvar _default = componentPropType;\nexports.default = _default;", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = exports.specialProperty = void 0;\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _extends3 = _interopRequireDefault(require(\"@babel/runtime/helpers/extends\"));\n\n// This module is based on https://github.com/airbnb/prop-types-exact repository.\n// However, in order to reduce the number of dependencies and to remove some extra safe checks\n// the module was forked.\n// Only exported for test purposes.\nvar specialProperty = \"exact-prop: \\u200B\";\nexports.specialProperty = specialProperty;\n\nfunction exactProp(propTypes) {\n /* istanbul ignore if */\n if (process.env.NODE_ENV === 'production') {\n return propTypes;\n }\n\n return (0, _extends3.default)({}, propTypes, (0, _defineProperty2.default)({}, specialProperty, function (props) {\n var unsupportedProps = Object.keys(props).filter(function (prop) {\n return !propTypes.hasOwnProperty(prop);\n });\n\n if (unsupportedProps.length > 0) {\n return new Error(\"The following properties are not supported: \".concat(unsupportedProps.map(function (prop) {\n return \"`) + ("`" + (`\".concat(prop, \"` + "`"))) + ((`\");\n }).join(', '), \". Please remove them.\"));\n }\n\n return null;\n }));\n}\n\nvar _default = exactProp;\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.getFunctionName = getFunctionName;\nexports.default = void 0;\n// Fork of recompose/getDisplayName with added IE 11 support\n// Simplified polyfill for IE 11 support\n// https://github.com/JamesMGreene/Function.name/blob/58b314d4a983110c3682f1228f845d39ccca1817/Function.name.js#L3\nvar fnNameMatchRegex = /^\\s*function(?:\\s|\\s*\\/\\*.*\\*\\/\\s*)+([^(\\s/]*)\\s*/;\n\nfunction getFunctionName(fn) {\n var match = \"\".concat(fn).match(fnNameMatchRegex);\n var name = match && match[1];\n return name || '';\n}\n\nfunction getDisplayName(Component) {\n if (typeof Component === 'string') {\n return Component;\n }\n\n if (!Component) {\n return undefined;\n }\n\n return Component.displayName || Component.name || getFunctionName(Component) || 'Component';\n}\n\nvar _default = getDisplayName;\nexports.default = _default;", + "/** @license Material-UI v3.0.0-alpha.3\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nexport { default as componentPropType } from './componentPropType';\nexport { default as chainPropTypes } from './chainPropTypes';\nexport { default as exactProp } from './exactProp';\nexport { default as getDisplayName } from './getDisplayName';\nexport { default as ponyfillGlobal } from './ponyfillGlobal';\n", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\n/* eslint-disable */\n// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nvar _default = typeof window != 'undefined' && window.Math == Math ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();\n\nexports.default = _default;", + "module.exports = balanced;\nfunction balanced(a, b, str) {\n if (a instanceof RegExp) a = maybeMatch(a, str);\n if (b instanceof RegExp) b = maybeMatch(b, str);\n\n var r = range(a, b, str);\n\n return r && {\n start: r[0],\n end: r[1],\n pre: str.slice(0, r[0]),\n body: str.slice(r[0] + a.length, r[1]),\n post: str.slice(r[1] + b.length)\n };\n}\n\nfunction maybeMatch(reg, str) {\n var m = str.match(reg);\n return m ? m[0] : null;\n}\n\nbalanced.range = range;\nfunction range(a, b, str) {\n var begs, beg, left, right, result;\n var ai = str.indexOf(a);\n var bi = str.indexOf(b, ai + 1);\n var i = ai;\n\n if (ai >= 0 && bi > 0) {\n begs = [];\n left = str.length;\n\n while (i >= 0 && !result) {\n if (i == ai) {\n begs.push(i);\n ai = str.indexOf(a, i + 1);\n } else if (begs.length == 1) {\n result = [ begs.pop(), bi ];\n } else {\n beg = begs.pop();\n if (beg < left) {\n left = beg;\n right = bi;\n }\n\n bi = str.indexOf(b, i + 1);\n }\n\n i = ai < bi && ai >= 0 ? ai : bi;\n }\n\n if (begs.length) {\n result = [ left, right ];\n }\n }\n\n return result;\n}\n", + "function createBroadcast (initialState) {\n var listeners = {};\n var id = 1;\n var _state = initialState;\n\n function getState () {\n return _state\n }\n\n function setState (state) {\n _state = state;\n var keys = Object.keys(listeners);\n var i = 0;\n var len = keys.length;\n for (; i < len; i++) {\n // if a listener gets unsubscribed during setState we just skip it\n if (listeners[keys[i]]) { listeners[keys[i]](state); }\n }\n }\n\n // subscribe to changes and return the subscriptionId\n function subscribe (listener) {\n if (typeof listener !== 'function') {\n throw new Error('listener must be a function.')\n }\n var currentId = id;\n listeners[currentId] = listener;\n id += 1;\n return currentId\n }\n\n // remove subscription by removing the listener function\n function unsubscribe (id) {\n listeners[id] = undefined;\n }\n\n return { getState: getState, setState: setState, subscribe: subscribe, unsubscribe: unsubscribe }\n}\n\nexport default createBroadcast;\n", + "/*!\n Copyright (c) 2017 Jed Watson.\n Licensed under the MIT License (MIT), see\n http://jedwatson.github.io/classnames\n*/\n/* global define */\n\n(function () {\n\t'use strict';\n\n\tvar hasOwn = {}.hasOwnProperty;\n\n\tfunction classNames () {\n\t\tvar classes = [];\n\n\t\tfor (var i = 0; i < arguments.length; i++) {\n\t\t\tvar arg = arguments[i];\n\t\t\tif (!arg) continue;\n\n\t\t\tvar argType = typeof arg;\n\n\t\t\tif (argType === 'string' || argType === 'number') {\n\t\t\t\tclasses.push(arg);\n\t\t\t} else if (Array.isArray(arg) && arg.length) {\n\t\t\t\tvar inner = classNames.apply(null, arg);\n\t\t\t\tif (inner) {\n\t\t\t\t\tclasses.push(inner);\n\t\t\t\t}\n\t\t\t} else if (argType === 'object') {\n\t\t\t\tfor (var key in arg) {\n\t\t\t\t\tif (hasOwn.call(arg, key) && arg[key]) {\n\t\t\t\t\t\tclasses.push(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn classes.join(' ');\n\t}\n\n\tif (typeof module !== 'undefined' && module.exports) {\n\t\tclassNames.default = classNames;\n\t\tmodule.exports = classNames;\n\t} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {\n\t\t// register as 'classnames', consistent with npm package name\n\t\tdefine('classnames', [], function () {\n\t\t\treturn classNames;\n\t\t});\n\t} else {\n\t\twindow.classNames = classNames;\n\t}\n}());\n", + "/* MIT license */\n/* eslint-disable no-mixed-operators */\nconst cssKeywords = require('color-name');\n\n// NOTE: conversions should only return primitive values (i.e. arrays, or\n// values that give correct ` + ("`" + `typeof`)) + ("`" + (` results).\n// do not use box values types (i.e. Number(), String(), etc.)\n\nconst reverseKeywords = {};\nfor (const key of Object.keys(cssKeywords)) {\n\treverseKeywords[cssKeywords[key]] = key;\n}\n\nconst convert = {\n\trgb: {channels: 3, labels: 'rgb'},\n\thsl: {channels: 3, labels: 'hsl'},\n\thsv: {channels: 3, labels: 'hsv'},\n\thwb: {channels: 3, labels: 'hwb'},\n\tcmyk: {channels: 4, labels: 'cmyk'},\n\txyz: {channels: 3, labels: 'xyz'},\n\tlab: {channels: 3, labels: 'lab'},\n\tlch: {channels: 3, labels: 'lch'},\n\thex: {channels: 1, labels: ['hex']},\n\tkeyword: {channels: 1, labels: ['keyword']},\n\tansi16: {channels: 1, labels: ['ansi16']},\n\tansi256: {channels: 1, labels: ['ansi256']},\n\thcg: {channels: 3, labels: ['h', 'c', 'g']},\n\tapple: {channels: 3, labels: ['r16', 'g16', 'b16']},\n\tgray: {channels: 1, labels: ['gray']}\n};\n\nmodule.exports = convert;\n\n// Hide .channels and .labels properties\nfor (const model of Object.keys(convert)) {\n\tif (!('channels' in convert[model])) {\n\t\tthrow new Error('missing channels property: ' + model);\n\t}\n\n\tif (!('labels' in convert[model])) {\n\t\tthrow new Error('missing channel labels property: ' + model);\n\t}\n\n\tif (convert[model].labels.length !== convert[model].channels) {\n\t\tthrow new Error('channel and label counts mismatch: ' + model);\n\t}\n\n\tconst {channels, labels} = convert[model];\n\tdelete convert[model].channels;\n\tdelete convert[model].labels;\n\tObject.defineProperty(convert[model], 'channels', {value: channels});\n\tObject.defineProperty(convert[model], 'labels', {value: labels});\n}\n\nconvert.rgb.hsl = function (rgb) {\n\tconst r = rgb[0] / 255;\n\tconst g = rgb[1] / 255;\n\tconst b = rgb[2] / 255;\n\tconst min = Math.min(r, g, b);\n\tconst max = Math.max(r, g, b);\n\tconst delta = max - min;\n\tlet h;\n\tlet s;\n\n\tif (max === min) {\n\t\th = 0;\n\t} else if (r === max) {\n\t\th = (g - b) / delta;\n\t} else if (g === max) {\n\t\th = 2 + (b - r) / delta;\n\t} else if (b === max) {\n\t\th = 4 + (r - g) / delta;\n\t}\n\n\th = Math.min(h * 60, 360);\n\n\tif (h < 0) {\n\t\th += 360;\n\t}\n\n\tconst l = (min + max) / 2;\n\n\tif (max === min) {\n\t\ts = 0;\n\t} else if (l <= 0.5) {\n\t\ts = delta / (max + min);\n\t} else {\n\t\ts = delta / (2 - max - min);\n\t}\n\n\treturn [h, s * 100, l * 100];\n};\n\nconvert.rgb.hsv = function (rgb) {\n\tlet rdif;\n\tlet gdif;\n\tlet bdif;\n\tlet h;\n\tlet s;\n\n\tconst r = rgb[0] / 255;\n\tconst g = rgb[1] / 255;\n\tconst b = rgb[2] / 255;\n\tconst v = Math.max(r, g, b);\n\tconst diff = v - Math.min(r, g, b);\n\tconst diffc = function (c) {\n\t\treturn (v - c) / 6 / diff + 1 / 2;\n\t};\n\n\tif (diff === 0) {\n\t\th = 0;\n\t\ts = 0;\n\t} else {\n\t\ts = diff / v;\n\t\trdif = diffc(r);\n\t\tgdif = diffc(g);\n\t\tbdif = diffc(b);\n\n\t\tif (r === v) {\n\t\t\th = bdif - gdif;\n\t\t} else if (g === v) {\n\t\t\th = (1 / 3) + rdif - bdif;\n\t\t} else if (b === v) {\n\t\t\th = (2 / 3) + gdif - rdif;\n\t\t}\n\n\t\tif (h < 0) {\n\t\t\th += 1;\n\t\t} else if (h > 1) {\n\t\t\th -= 1;\n\t\t}\n\t}\n\n\treturn [\n\t\th * 360,\n\t\ts * 100,\n\t\tv * 100\n\t];\n};\n\nconvert.rgb.hwb = function (rgb) {\n\tconst r = rgb[0];\n\tconst g = rgb[1];\n\tlet b = rgb[2];\n\tconst h = convert.rgb.hsl(rgb)[0];\n\tconst w = 1 / 255 * Math.min(r, Math.min(g, b));\n\n\tb = 1 - 1 / 255 * Math.max(r, Math.max(g, b));\n\n\treturn [h, w * 100, b * 100];\n};\n\nconvert.rgb.cmyk = function (rgb) {\n\tconst r = rgb[0] / 255;\n\tconst g = rgb[1] / 255;\n\tconst b = rgb[2] / 255;\n\n\tconst k = Math.min(1 - r, 1 - g, 1 - b);\n\tconst c = (1 - r - k) / (1 - k) || 0;\n\tconst m = (1 - g - k) / (1 - k) || 0;\n\tconst y = (1 - b - k) / (1 - k) || 0;\n\n\treturn [c * 100, m * 100, y * 100, k * 100];\n};\n\nfunction comparativeDistance(x, y) {\n\t/*\n\t\tSee https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance\n\t*/\n\treturn (\n\t\t((x[0] - y[0]) ** 2) +\n\t\t((x[1] - y[1]) ** 2) +\n\t\t((x[2] - y[2]) ** 2)\n\t);\n}\n\nconvert.rgb.keyword = function (rgb) {\n\tconst reversed = reverseKeywords[rgb];\n\tif (reversed) {\n\t\treturn reversed;\n\t}\n\n\tlet currentClosestDistance = Infinity;\n\tlet currentClosestKeyword;\n\n\tfor (const keyword of Object.keys(cssKeywords)) {\n\t\tconst value = cssKeywords[keyword];\n\n\t\t// Compute comparative distance\n\t\tconst distance = comparativeDistance(rgb, value);\n\n\t\t// Check if its less, if so set as closest\n\t\tif (distance < currentClosestDistance) {\n\t\t\tcurrentClosestDistance = distance;\n\t\t\tcurrentClosestKeyword = keyword;\n\t\t}\n\t}\n\n\treturn currentClosestKeyword;\n};\n\nconvert.keyword.rgb = function (keyword) {\n\treturn cssKeywords[keyword];\n};\n\nconvert.rgb.xyz = function (rgb) {\n\tlet r = rgb[0] / 255;\n\tlet g = rgb[1] / 255;\n\tlet b = rgb[2] / 255;\n\n\t// Assume sRGB\n\tr = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92);\n\tg = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92);\n\tb = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92);\n\n\tconst x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);\n\tconst y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);\n\tconst z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);\n\n\treturn [x * 100, y * 100, z * 100];\n};\n\nconvert.rgb.lab = function (rgb) {\n\tconst xyz = convert.rgb.xyz(rgb);\n\tlet x = xyz[0];\n\tlet y = xyz[1];\n\tlet z = xyz[2];\n\n\tx /= 95.047;\n\ty /= 100;\n\tz /= 108.883;\n\n\tx = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);\n\ty = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);\n\tz = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);\n\n\tconst l = (116 * y) - 16;\n\tconst a = 500 * (x - y);\n\tconst b = 200 * (y - z);\n\n\treturn [l, a, b];\n};\n\nconvert.hsl.rgb = function (hsl) {\n\tconst h = hsl[0] / 360;\n\tconst s = hsl[1] / 100;\n\tconst l = hsl[2] / 100;\n\tlet t2;\n\tlet t3;\n\tlet val;\n\n\tif (s === 0) {\n\t\tval = l * 255;\n\t\treturn [val, val, val];\n\t}\n\n\tif (l < 0.5) {\n\t\tt2 = l * (1 + s);\n\t} else {\n\t\tt2 = l + s - l * s;\n\t}\n\n\tconst t1 = 2 * l - t2;\n\n\tconst rgb = [0, 0, 0];\n\tfor (let i = 0; i < 3; i++) {\n\t\tt3 = h + 1 / 3 * -(i - 1);\n\t\tif (t3 < 0) {\n\t\t\tt3++;\n\t\t}\n\n\t\tif (t3 > 1) {\n\t\t\tt3--;\n\t\t}\n\n\t\tif (6 * t3 < 1) {\n\t\t\tval = t1 + (t2 - t1) * 6 * t3;\n\t\t} else if (2 * t3 < 1) {\n\t\t\tval = t2;\n\t\t} else if (3 * t3 < 2) {\n\t\t\tval = t1 + (t2 - t1) * (2 / 3 - t3) * 6;\n\t\t} else {\n\t\t\tval = t1;\n\t\t}\n\n\t\trgb[i] = val * 255;\n\t}\n\n\treturn rgb;\n};\n\nconvert.hsl.hsv = function (hsl) {\n\tconst h = hsl[0];\n\tlet s = hsl[1] / 100;\n\tlet l = hsl[2] / 100;\n\tlet smin = s;\n\tconst lmin = Math.max(l, 0.01);\n\n\tl *= 2;\n\ts *= (l <= 1) ? l : 2 - l;\n\tsmin *= lmin <= 1 ? lmin : 2 - lmin;\n\tconst v = (l + s) / 2;\n\tconst sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);\n\n\treturn [h, sv * 100, v * 100];\n};\n\nconvert.hsv.rgb = function (hsv) {\n\tconst h = hsv[0] / 60;\n\tconst s = hsv[1] / 100;\n\tlet v = hsv[2] / 100;\n\tconst hi = Math.floor(h) % 6;\n\n\tconst f = h - Math.floor(h);\n\tconst p = 255 * v * (1 - s);\n\tconst q = 255 * v * (1 - (s * f));\n\tconst t = 255 * v * (1 - (s * (1 - f)));\n\tv *= 255;\n\n\tswitch (hi) {\n\t\tcase 0:\n\t\t\treturn [v, t, p];\n\t\tcase 1:\n\t\t\treturn [q, v, p];\n\t\tcase 2:\n\t\t\treturn [p, v, t];\n\t\tcase 3:\n\t\t\treturn [p, q, v];\n\t\tcase 4:\n\t\t\treturn [t, p, v];\n\t\tcase 5:\n\t\t\treturn [v, p, q];\n\t}\n};\n\nconvert.hsv.hsl = function (hsv) {\n\tconst h = hsv[0];\n\tconst s = hsv[1] / 100;\n\tconst v = hsv[2] / 100;\n\tconst vmin = Math.max(v, 0.01);\n\tlet sl;\n\tlet l;\n\n\tl = (2 - s) * v;\n\tconst lmin = (2 - s) * vmin;\n\tsl = s * vmin;\n\tsl /= (lmin <= 1) ? lmin : 2 - lmin;\n\tsl = sl || 0;\n\tl /= 2;\n\n\treturn [h, sl * 100, l * 100];\n};\n\n// http://dev.w3.org/csswg/css-color/#hwb-to-rgb\nconvert.hwb.rgb = function (hwb) {\n\tconst h = hwb[0] / 360;\n\tlet wh = hwb[1] / 100;\n\tlet bl = hwb[2] / 100;\n\tconst ratio = wh + bl;\n\tlet f;\n\n\t// Wh + bl cant be > 1\n\tif (ratio > 1) {\n\t\twh /= ratio;\n\t\tbl /= ratio;\n\t}\n\n\tconst i = Math.floor(6 * h);\n\tconst v = 1 - bl;\n\tf = 6 * h - i;\n\n\tif ((i & 0x01) !== 0) {\n\t\tf = 1 - f;\n\t}\n\n\tconst n = wh + f * (v - wh); // Linear interpolation\n\n\tlet r;\n\tlet g;\n\tlet b;\n\t/* eslint-disable max-statements-per-line,no-multi-spaces */\n\tswitch (i) {\n\t\tdefault:\n\t\tcase 6:\n\t\tcase 0: r = v; g = n; b = wh; break;\n\t\tcase 1: r = n; g = v; b = wh; break;\n\t\tcase 2: r = wh; g = v; b = n; break;\n\t\tcase 3: r = wh; g = n; b = v; break;\n\t\tcase 4: r = n; g = wh; b = v; break;\n\t\tcase 5: r = v; g = wh; b = n; break;\n\t}\n\t/* eslint-enable max-statements-per-line,no-multi-spaces */\n\n\treturn [r * 255, g * 255, b * 255];\n};\n\nconvert.cmyk.rgb = function (cmyk) {\n\tconst c = cmyk[0] / 100;\n\tconst m = cmyk[1] / 100;\n\tconst y = cmyk[2] / 100;\n\tconst k = cmyk[3] / 100;\n\n\tconst r = 1 - Math.min(1, c * (1 - k) + k);\n\tconst g = 1 - Math.min(1, m * (1 - k) + k);\n\tconst b = 1 - Math.min(1, y * (1 - k) + k);\n\n\treturn [r * 255, g * 255, b * 255];\n};\n\nconvert.xyz.rgb = function (xyz) {\n\tconst x = xyz[0] / 100;\n\tconst y = xyz[1] / 100;\n\tconst z = xyz[2] / 100;\n\tlet r;\n\tlet g;\n\tlet b;\n\n\tr = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);\n\tg = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);\n\tb = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);\n\n\t// Assume sRGB\n\tr = r > 0.0031308\n\t\t? ((1.055 * (r ** (1.0 / 2.4))) - 0.055)\n\t\t: r * 12.92;\n\n\tg = g > 0.0031308\n\t\t? ((1.055 * (g ** (1.0 / 2.4))) - 0.055)\n\t\t: g * 12.92;\n\n\tb = b > 0.0031308\n\t\t? ((1.055 * (b ** (1.0 / 2.4))) - 0.055)\n\t\t: b * 12.92;\n\n\tr = Math.min(Math.max(0, r), 1);\n\tg = Math.min(Math.max(0, g), 1);\n\tb = Math.min(Math.max(0, b), 1);\n\n\treturn [r * 255, g * 255, b * 255];\n};\n\nconvert.xyz.lab = function (xyz) {\n\tlet x = xyz[0];\n\tlet y = xyz[1];\n\tlet z = xyz[2];\n\n\tx /= 95.047;\n\ty /= 100;\n\tz /= 108.883;\n\n\tx = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);\n\ty = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);\n\tz = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);\n\n\tconst l = (116 * y) - 16;\n\tconst a = 500 * (x - y);\n\tconst b = 200 * (y - z);\n\n\treturn [l, a, b];\n};\n\nconvert.lab.xyz = function (lab) {\n\tconst l = lab[0];\n\tconst a = lab[1];\n\tconst b = lab[2];\n\tlet x;\n\tlet y;\n\tlet z;\n\n\ty = (l + 16) / 116;\n\tx = a / 500 + y;\n\tz = y - b / 200;\n\n\tconst y2 = y ** 3;\n\tconst x2 = x ** 3;\n\tconst z2 = z ** 3;\n\ty = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;\n\tx = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;\n\tz = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;\n\n\tx *= 95.047;\n\ty *= 100;\n\tz *= 108.883;\n\n\treturn [x, y, z];\n};\n\nconvert.lab.lch = function (lab) {\n\tconst l = lab[0];\n\tconst a = lab[1];\n\tconst b = lab[2];\n\tlet h;\n\n\tconst hr = Math.atan2(b, a);\n\th = hr * 360 / 2 / Math.PI;\n\n\tif (h < 0) {\n\t\th += 360;\n\t}\n\n\tconst c = Math.sqrt(a * a + b * b);\n\n\treturn [l, c, h];\n};\n\nconvert.lch.lab = function (lch) {\n\tconst l = lch[0];\n\tconst c = lch[1];\n\tconst h = lch[2];\n\n\tconst hr = h / 360 * 2 * Math.PI;\n\tconst a = c * Math.cos(hr);\n\tconst b = c * Math.sin(hr);\n\n\treturn [l, a, b];\n};\n\nconvert.rgb.ansi16 = function (args, saturation = null) {\n\tconst [r, g, b] = args;\n\tlet value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; // Hsv -> ansi16 optimization\n\n\tvalue = Math.round(value / 50);\n\n\tif (value === 0) {\n\t\treturn 30;\n\t}\n\n\tlet ansi = 30\n\t\t+ ((Math.round(b / 255) << 2)\n\t\t| (Math.round(g / 255) << 1)\n\t\t| Math.round(r / 255));\n\n\tif (value === 2) {\n\t\tansi += 60;\n\t}\n\n\treturn ansi;\n};\n\nconvert.hsv.ansi16 = function (args) {\n\t// Optimization here; we already know the value and don't need to get\n\t// it converted for us.\n\treturn convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);\n};\n\nconvert.rgb.ansi256 = function (args) {\n\tconst r = args[0];\n\tconst g = args[1];\n\tconst b = args[2];\n\n\t// We use the extended greyscale palette here, with the exception of\n\t// black and white. normal palette only has 4 greyscale shades.\n\tif (r === g && g === b) {\n\t\tif (r < 8) {\n\t\t\treturn 16;\n\t\t}\n\n\t\tif (r > 248) {\n\t\t\treturn 231;\n\t\t}\n\n\t\treturn Math.round(((r - 8) / 247) * 24) + 232;\n\t}\n\n\tconst ansi = 16\n\t\t+ (36 * Math.round(r / 255 * 5))\n\t\t+ (6 * Math.round(g / 255 * 5))\n\t\t+ Math.round(b / 255 * 5);\n\n\treturn ansi;\n};\n\nconvert.ansi16.rgb = function (args) {\n\tlet color = args % 10;\n\n\t// Handle greyscale\n\tif (color === 0 || color === 7) {\n\t\tif (args > 50) {\n\t\t\tcolor += 3.5;\n\t\t}\n\n\t\tcolor = color / 10.5 * 255;\n\n\t\treturn [color, color, color];\n\t}\n\n\tconst mult = (~~(args > 50) + 1) * 0.5;\n\tconst r = ((color & 1) * mult) * 255;\n\tconst g = (((color >> 1) & 1) * mult) * 255;\n\tconst b = (((color >> 2) & 1) * mult) * 255;\n\n\treturn [r, g, b];\n};\n\nconvert.ansi256.rgb = function (args) {\n\t// Handle greyscale\n\tif (args >= 232) {\n\t\tconst c = (args - 232) * 10 + 8;\n\t\treturn [c, c, c];\n\t}\n\n\targs -= 16;\n\n\tlet rem;\n\tconst r = Math.floor(args / 36) / 5 * 255;\n\tconst g = Math.floor((rem = args % 36) / 6) / 5 * 255;\n\tconst b = (rem % 6) / 5 * 255;\n\n\treturn [r, g, b];\n};\n\nconvert.rgb.hex = function (args) {\n\tconst integer = ((Math.round(args[0]) & 0xFF) << 16)\n\t\t+ ((Math.round(args[1]) & 0xFF) << 8)\n\t\t+ (Math.round(args[2]) & 0xFF);\n\n\tconst string = integer.toString(16).toUpperCase();\n\treturn '000000'.substring(string.length) + string;\n};\n\nconvert.hex.rgb = function (args) {\n\tconst match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);\n\tif (!match) {\n\t\treturn [0, 0, 0];\n\t}\n\n\tlet colorString = match[0];\n\n\tif (match[0].length === 3) {\n\t\tcolorString = colorString.split('').map(char => {\n\t\t\treturn char + char;\n\t\t}).join('');\n\t}\n\n\tconst integer = parseInt(colorString, 16);\n\tconst r = (integer >> 16) & 0xFF;\n\tconst g = (integer >> 8) & 0xFF;\n\tconst b = integer & 0xFF;\n\n\treturn [r, g, b];\n};\n\nconvert.rgb.hcg = function (rgb) {\n\tconst r = rgb[0] / 255;\n\tconst g = rgb[1] / 255;\n\tconst b = rgb[2] / 255;\n\tconst max = Math.max(Math.max(r, g), b);\n\tconst min = Math.min(Math.min(r, g), b);\n\tconst chroma = (max - min);\n\tlet grayscale;\n\tlet hue;\n\n\tif (chroma < 1) {\n\t\tgrayscale = min / (1 - chroma);\n\t} else {\n\t\tgrayscale = 0;\n\t}\n\n\tif (chroma <= 0) {\n\t\thue = 0;\n\t} else\n\tif (max === r) {\n\t\thue = ((g - b) / chroma) % 6;\n\t} else\n\tif (max === g) {\n\t\thue = 2 + (b - r) / chroma;\n\t} else {\n\t\thue = 4 + (r - g) / chroma + 4;\n\t}\n\n\thue /= 6;\n\thue %= 1;\n\n\treturn [hue * 360, chroma * 100, grayscale * 100];\n};\n\nconvert.hsl.hcg = function (hsl) {\n\tconst s = hsl[1] / 100;\n\tconst l = hsl[2] / 100;\n\n\tconst c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l));\n\n\tlet f = 0;\n\tif (c < 1.0) {\n\t\tf = (l - 0.5 * c) / (1.0 - c);\n\t}\n\n\treturn [hsl[0], c * 100, f * 100];\n};\n\nconvert.hsv.hcg = function (hsv) {\n\tconst s = hsv[1] / 100;\n\tconst v = hsv[2] / 100;\n\n\tconst c = s * v;\n\tlet f = 0;\n\n\tif (c < 1.0) {\n\t\tf = (v - c) / (1 - c);\n\t}\n\n\treturn [hsv[0], c * 100, f * 100];\n};\n\nconvert.hcg.rgb = function (hcg) {\n\tconst h = hcg[0] / 360;\n\tconst c = hcg[1] / 100;\n\tconst g = hcg[2] / 100;\n\n\tif (c === 0.0) {\n\t\treturn [g * 255, g * 255, g * 255];\n\t}\n\n\tconst pure = [0, 0, 0];\n\tconst hi = (h % 1) * 6;\n\tconst v = hi % 1;\n\tconst w = 1 - v;\n\tlet mg = 0;\n\n\t/* eslint-disable max-statements-per-line */\n\tswitch (Math.floor(hi)) {\n\t\tcase 0:\n\t\t\tpure[0] = 1; pure[1] = v; pure[2] = 0; break;\n\t\tcase 1:\n\t\t\tpure[0] = w; pure[1] = 1; pure[2] = 0; break;\n\t\tcase 2:\n\t\t\tpure[0] = 0; pure[1] = 1; pure[2] = v; break;\n\t\tcase 3:\n\t\t\tpure[0] = 0; pure[1] = w; pure[2] = 1; break;\n\t\tcase 4:\n\t\t\tpure[0] = v; pure[1] = 0; pure[2] = 1; break;\n\t\tdefault:\n\t\t\tpure[0] = 1; pure[1] = 0; pure[2] = w;\n\t}\n\t/* eslint-enable max-statements-per-line */\n\n\tmg = (1.0 - c) * g;\n\n\treturn [\n\t\t(c * pure[0] + mg) * 255,\n\t\t(c * pure[1] + mg) * 255,\n\t\t(c * pure[2] + mg) * 255\n\t];\n};\n\nconvert.hcg.hsv = function (hcg) {\n\tconst c = hcg[1] / 100;\n\tconst g = hcg[2] / 100;\n\n\tconst v = c + g * (1.0 - c);\n\tlet f = 0;\n\n\tif (v > 0.0) {\n\t\tf = c / v;\n\t}\n\n\treturn [hcg[0], f * 100, v * 100];\n};\n\nconvert.hcg.hsl = function (hcg) {\n\tconst c = hcg[1] / 100;\n\tconst g = hcg[2] / 100;\n\n\tconst l = g * (1.0 - c) + 0.5 * c;\n\tlet s = 0;\n\n\tif (l > 0.0 && l < 0.5) {\n\t\ts = c / (2 * l);\n\t} else\n\tif (l >= 0.5 && l < 1.0) {\n\t\ts = c / (2 * (1 - l));\n\t}\n\n\treturn [hcg[0], s * 100, l * 100];\n};\n\nconvert.hcg.hwb = function (hcg) {\n\tconst c = hcg[1] / 100;\n\tconst g = hcg[2] / 100;\n\tconst v = c + g * (1.0 - c);\n\treturn [hcg[0], (v - c) * 100, (1 - v) * 100];\n};\n\nconvert.hwb.hcg = function (hwb) {\n\tconst w = hwb[1] / 100;\n\tconst b = hwb[2] / 100;\n\tconst v = 1 - b;\n\tconst c = v - w;\n\tlet g = 0;\n\n\tif (c < 1) {\n\t\tg = (v - c) / (1 - c);\n\t}\n\n\treturn [hwb[0], c * 100, g * 100];\n};\n\nconvert.apple.rgb = function (apple) {\n\treturn [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];\n};\n\nconvert.rgb.apple = function (rgb) {\n\treturn [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];\n};\n\nconvert.gray.rgb = function (args) {\n\treturn [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];\n};\n\nconvert.gray.hsl = function (args) {\n\treturn [0, 0, args[0]];\n};\n\nconvert.gray.hsv = convert.gray.hsl;\n\nconvert.gray.hwb = function (gray) {\n\treturn [0, 100, gray[0]];\n};\n\nconvert.gray.cmyk = function (gray) {\n\treturn [0, 0, 0, gray[0]];\n};\n\nconvert.gray.lab = function (gray) {\n\treturn [gray[0], 0, 0];\n};\n\nconvert.gray.hex = function (gray) {\n\tconst val = Math.round(gray[0] / 100 * 255) & 0xFF;\n\tconst integer = (val << 16) + (val << 8) + val;\n\n\tconst string = integer.toString(16).toUpperCase();\n\treturn '000000'.substring(string.length) + string;\n};\n\nconvert.rgb.gray = function (rgb) {\n\tconst val = (rgb[0] + rgb[1] + rgb[2]) / 3;\n\treturn [val / 255 * 100];\n};\n", + "const conversions = require('./conversions');\nconst route = require('./route');\n\nconst convert = {};\n\nconst models = Object.keys(conversions);\n\nfunction wrapRaw(fn) {\n\tconst wrappedFn = function (...args) {\n\t\tconst arg0 = args[0];\n\t\tif (arg0 === undefined || arg0 === null) {\n\t\t\treturn arg0;\n\t\t}\n\n\t\tif (arg0.length > 1) {\n\t\t\targs = arg0;\n\t\t}\n\n\t\treturn fn(args);\n\t};\n\n\t// Preserve .conversion property if there is one\n\tif ('conversion' in fn) {\n\t\twrappedFn.conversion = fn.conversion;\n\t}\n\n\treturn wrappedFn;\n}\n\nfunction wrapRounded(fn) {\n\tconst wrappedFn = function (...args) {\n\t\tconst arg0 = args[0];\n\n\t\tif (arg0 === undefined || arg0 === null) {\n\t\t\treturn arg0;\n\t\t}\n\n\t\tif (arg0.length > 1) {\n\t\t\targs = arg0;\n\t\t}\n\n\t\tconst result = fn(args);\n\n\t\t// We're assuming the result is an array here.\n\t\t// see notice in conversions.js; don't use box types\n\t\t// in conversion functions.\n\t\tif (typeof result === 'object') {\n\t\t\tfor (let len = result.length, i = 0; i < len; i++) {\n\t\t\t\tresult[i] = Math.round(result[i]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t};\n\n\t// Preserve .conversion property if there is one\n\tif ('conversion' in fn) {\n\t\twrappedFn.conversion = fn.conversion;\n\t}\n\n\treturn wrappedFn;\n}\n\nmodels.forEach(fromModel => {\n\tconvert[fromModel] = {};\n\n\tObject.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});\n\tObject.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});\n\n\tconst routes = route(fromModel);\n\tconst routeModels = Object.keys(routes);\n\n\trouteModels.forEach(toModel => {\n\t\tconst fn = routes[toModel];\n\n\t\tconvert[fromModel][toModel] = wrapRounded(fn);\n\t\tconvert[fromModel][toModel].raw = wrapRaw(fn);\n\t});\n});\n\nmodule.exports = convert;\n", + "const conversions = require('./conversions');\n\n/*\n\tThis function routes a model to all other models.\n\n\tall functions that are routed have a property ` + "`")))))) + (((((`.conversion` + "`") + (` attached\n\tto the returned synthetic function. This property is an array\n\tof strings, each with the steps in between the 'from' and 'to'\n\tcolor models (inclusive).\n\n\tconversions that are not possible simply are not included.\n*/\n\nfunction buildGraph() {\n\tconst graph = {};\n\t// https://jsperf.com/object-keys-vs-for-in-with-closure/3\n\tconst models = Object.keys(conversions);\n\n\tfor (let len = models.length, i = 0; i < len; i++) {\n\t\tgraph[models[i]] = {\n\t\t\t// http://jsperf.com/1-vs-infinity\n\t\t\t// micro-opt, but this is simple.\n\t\t\tdistance: -1,\n\t\t\tparent: null\n\t\t};\n\t}\n\n\treturn graph;\n}\n\n// https://en.wikipedia.org/wiki/Breadth-first_search\nfunction deriveBFS(fromModel) {\n\tconst graph = buildGraph();\n\tconst queue = [fromModel]; // Unshift -> queue -> pop\n\n\tgraph[fromModel].distance = 0;\n\n\twhile (queue.length) {\n\t\tconst current = queue.pop();\n\t\tconst adjacents = Object.keys(conversions[current]);\n\n\t\tfor (let len = adjacents.length, i = 0; i < len; i++) {\n\t\t\tconst adjacent = adjacents[i];\n\t\t\tconst node = graph[adjacent];\n\n\t\t\tif (node.distance === -1) {\n\t\t\t\tnode.distance = graph[current].distance + 1;\n\t\t\t\tnode.parent = current;\n\t\t\t\tqueue.unshift(adjacent);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn graph;\n}\n\nfunction link(from, to) {\n\treturn function (args) {\n\t\treturn to(from(args));\n\t};\n}\n\nfunction wrapConversion(toModel, graph) {\n\tconst path = [graph[toModel].parent, toModel];\n\tlet fn = conversions[graph[toModel].parent][toModel];\n\n\tlet cur = graph[toModel].parent;\n\twhile (graph[cur].parent) {\n\t\tpath.unshift(graph[cur].parent);\n\t\tfn = link(conversions[graph[cur].parent][cur], fn);\n\t\tcur = graph[cur].parent;\n\t}\n\n\tfn.conversion = path;\n\treturn fn;\n}\n\nmodule.exports = function (fromModel) {\n\tconst graph = deriveBFS(fromModel);\n\tconst conversion = {};\n\n\tconst models = Object.keys(graph);\n\tfor (let len = models.length, i = 0; i < len; i++) {\n\t\tconst toModel = models[i];\n\t\tconst node = graph[toModel];\n\n\t\tif (node.parent === null) {\n\t\t\t// No possible conversion, or this node is the source model.\n\t\t\tcontinue;\n\t\t}\n\n\t\tconversion[toModel] = wrapConversion(toModel, graph);\n\t}\n\n\treturn conversion;\n};\n\n", + "'use strict'\r\n\r\nmodule.exports = {\r\n\t\"aliceblue\": [240, 248, 255],\r\n\t\"antiquewhite\": [250, 235, 215],\r\n\t\"aqua\": [0, 255, 255],\r\n\t\"aquamarine\": [127, 255, 212],\r\n\t\"azure\": [240, 255, 255],\r\n\t\"beige\": [245, 245, 220],\r\n\t\"bisque\": [255, 228, 196],\r\n\t\"black\": [0, 0, 0],\r\n\t\"blanchedalmond\": [255, 235, 205],\r\n\t\"blue\": [0, 0, 255],\r\n\t\"blueviolet\": [138, 43, 226],\r\n\t\"brown\": [165, 42, 42],\r\n\t\"burlywood\": [222, 184, 135],\r\n\t\"cadetblue\": [95, 158, 160],\r\n\t\"chartreuse\": [127, 255, 0],\r\n\t\"chocolate\": [210, 105, 30],\r\n\t\"coral\": [255, 127, 80],\r\n\t\"cornflowerblue\": [100, 149, 237],\r\n\t\"cornsilk\": [255, 248, 220],\r\n\t\"crimson\": [220, 20, 60],\r\n\t\"cyan\": [0, 255, 255],\r\n\t\"darkblue\": [0, 0, 139],\r\n\t\"darkcyan\": [0, 139, 139],\r\n\t\"darkgoldenrod\": [184, 134, 11],\r\n\t\"darkgray\": [169, 169, 169],\r\n\t\"darkgreen\": [0, 100, 0],\r\n\t\"darkgrey\": [169, 169, 169],\r\n\t\"darkkhaki\": [189, 183, 107],\r\n\t\"darkmagenta\": [139, 0, 139],\r\n\t\"darkolivegreen\": [85, 107, 47],\r\n\t\"darkorange\": [255, 140, 0],\r\n\t\"darkorchid\": [153, 50, 204],\r\n\t\"darkred\": [139, 0, 0],\r\n\t\"darksalmon\": [233, 150, 122],\r\n\t\"darkseagreen\": [143, 188, 143],\r\n\t\"darkslateblue\": [72, 61, 139],\r\n\t\"darkslategray\": [47, 79, 79],\r\n\t\"darkslategrey\": [47, 79, 79],\r\n\t\"darkturquoise\": [0, 206, 209],\r\n\t\"darkviolet\": [148, 0, 211],\r\n\t\"deeppink\": [255, 20, 147],\r\n\t\"deepskyblue\": [0, 191, 255],\r\n\t\"dimgray\": [105, 105, 105],\r\n\t\"dimgrey\": [105, 105, 105],\r\n\t\"dodgerblue\": [30, 144, 255],\r\n\t\"firebrick\": [178, 34, 34],\r\n\t\"floralwhite\": [255, 250, 240],\r\n\t\"forestgreen\": [34, 139, 34],\r\n\t\"fuchsia\": [255, 0, 255],\r\n\t\"gainsboro\": [220, 220, 220],\r\n\t\"ghostwhite\": [248, 248, 255],\r\n\t\"gold\": [255, 215, 0],\r\n\t\"goldenrod\": [218, 165, 32],\r\n\t\"gray\": [128, 128, 128],\r\n\t\"green\": [0, 128, 0],\r\n\t\"greenyellow\": [173, 255, 47],\r\n\t\"grey\": [128, 128, 128],\r\n\t\"honeydew\": [240, 255, 240],\r\n\t\"hotpink\": [255, 105, 180],\r\n\t\"indianred\": [205, 92, 92],\r\n\t\"indigo\": [75, 0, 130],\r\n\t\"ivory\": [255, 255, 240],\r\n\t\"khaki\": [240, 230, 140],\r\n\t\"lavender\": [230, 230, 250],\r\n\t\"lavenderblush\": [255, 240, 245],\r\n\t\"lawngreen\": [124, 252, 0],\r\n\t\"lemonchiffon\": [255, 250, 205],\r\n\t\"lightblue\": [173, 216, 230],\r\n\t\"lightcoral\": [240, 128, 128],\r\n\t\"lightcyan\": [224, 255, 255],\r\n\t\"lightgoldenrodyellow\": [250, 250, 210],\r\n\t\"lightgray\": [211, 211, 211],\r\n\t\"lightgreen\": [144, 238, 144],\r\n\t\"lightgrey\": [211, 211, 211],\r\n\t\"lightpink\": [255, 182, 193],\r\n\t\"lightsalmon\": [255, 160, 122],\r\n\t\"lightseagreen\": [32, 178, 170],\r\n\t\"lightskyblue\": [135, 206, 250],\r\n\t\"lightslategray\": [119, 136, 153],\r\n\t\"lightslategrey\": [119, 136, 153],\r\n\t\"lightsteelblue\": [176, 196, 222],\r\n\t\"lightyellow\": [255, 255, 224],\r\n\t\"lime\": [0, 255, 0],\r\n\t\"limegreen\": [50, 205, 50],\r\n\t\"linen\": [250, 240, 230],\r\n\t\"magenta\": [255, 0, 255],\r\n\t\"maroon\": [128, 0, 0],\r\n\t\"mediumaquamarine\": [102, 205, 170],\r\n\t\"mediumblue\": [0, 0, 205],\r\n\t\"mediumorchid\": [186, 85, 211],\r\n\t\"mediumpurple\": [147, 112, 219],\r\n\t\"mediumseagreen\": [60, 179, 113],\r\n\t\"mediumslateblue\": [123, 104, 238],\r\n\t\"mediumspringgreen\": [0, 250, 154],\r\n\t\"mediumturquoise\": [72, 209, 204],\r\n\t\"mediumvioletred\": [199, 21, 133],\r\n\t\"midnightblue\": [25, 25, 112],\r\n\t\"mintcream\": [245, 255, 250],\r\n\t\"mistyrose\": [255, 228, 225],\r\n\t\"moccasin\": [255, 228, 181],\r\n\t\"navajowhite\": [255, 222, 173],\r\n\t\"navy\": [0, 0, 128],\r\n\t\"oldlace\": [253, 245, 230],\r\n\t\"olive\": [128, 128, 0],\r\n\t\"olivedrab\": [107, 142, 35],\r\n\t\"orange\": [255, 165, 0],\r\n\t\"orangered\": [255, 69, 0],\r\n\t\"orchid\": [218, 112, 214],\r\n\t\"palegoldenrod\": [238, 232, 170],\r\n\t\"palegreen\": [152, 251, 152],\r\n\t\"paleturquoise\": [175, 238, 238],\r\n\t\"palevioletred\": [219, 112, 147],\r\n\t\"papayawhip\": [255, 239, 213],\r\n\t\"peachpuff\": [255, 218, 185],\r\n\t\"peru\": [205, 133, 63],\r\n\t\"pink\": [255, 192, 203],\r\n\t\"plum\": [221, 160, 221],\r\n\t\"powderblue\": [176, 224, 230],\r\n\t\"purple\": [128, 0, 128],\r\n\t\"rebeccapurple\": [102, 51, 153],\r\n\t\"red\": [255, 0, 0],\r\n\t\"rosybrown\": [188, 143, 143],\r\n\t\"royalblue\": [65, 105, 225],\r\n\t\"saddlebrown\": [139, 69, 19],\r\n\t\"salmon\": [250, 128, 114],\r\n\t\"sandybrown\": [244, 164, 96],\r\n\t\"seagreen\": [46, 139, 87],\r\n\t\"seashell\": [255, 245, 238],\r\n\t\"sienna\": [160, 82, 45],\r\n\t\"silver\": [192, 192, 192],\r\n\t\"skyblue\": [135, 206, 235],\r\n\t\"slateblue\": [106, 90, 205],\r\n\t\"slategray\": [112, 128, 144],\r\n\t\"slategrey\": [112, 128, 144],\r\n\t\"snow\": [255, 250, 250],\r\n\t\"springgreen\": [0, 255, 127],\r\n\t\"steelblue\": [70, 130, 180],\r\n\t\"tan\": [210, 180, 140],\r\n\t\"teal\": [0, 128, 128],\r\n\t\"thistle\": [216, 191, 216],\r\n\t\"tomato\": [255, 99, 71],\r\n\t\"turquoise\": [64, 224, 208],\r\n\t\"violet\": [238, 130, 238],\r\n\t\"wheat\": [245, 222, 179],\r\n\t\"white\": [255, 255, 255],\r\n\t\"whitesmoke\": [245, 245, 245],\r\n\t\"yellow\": [255, 255, 0],\r\n\t\"yellowgreen\": [154, 205, 50]\r\n};\r\n", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = camelize;\nvar regExp = /[-\\s]+(.)?/g;\n\n/**\n * Convert dash separated strings to camel cased.\n *\n * @param {String} str\n * @return {String}\n */\nfunction camelize(str) {\n return str.replace(regExp, toUpper);\n}\n\nfunction toUpper(match, c) {\n return c ? c.toUpperCase() : '';\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.supportedValue = exports.supportedProperty = exports.prefix = undefined;\n\nvar _prefix = require('./prefix');\n\nvar _prefix2 = _interopRequireDefault(_prefix);\n\nvar _supportedProperty = require('./supported-property');\n\nvar _supportedProperty2 = _interopRequireDefault(_supportedProperty);\n\nvar _supportedValue = require('./supported-value');\n\nvar _supportedValue2 = _interopRequireDefault(_supportedValue);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nexports['default'] = {\n prefix: _prefix2['default'],\n supportedProperty: _supportedProperty2['default'],\n supportedValue: _supportedValue2['default']\n}; /**\n * CSS Vendor prefix detection and property feature testing.\n *\n * @copyright Oleg Slobodskoi 2015\n * @website https://github.com/jsstyles/css-vendor\n * @license MIT\n */\n\nexports.prefix = _prefix2['default'];\nexports.supportedProperty = _supportedProperty2['default'];\nexports.supportedValue = _supportedValue2['default'];", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _isInBrowser = require('is-in-browser');\n\nvar _isInBrowser2 = _interopRequireDefault(_isInBrowser);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar js = ''; /**\n * Export javascript style and css style vendor prefixes.\n * Based on \"transform\" support test.\n */\n\nvar css = '';\n\n// We should not do anything if required serverside.\nif (_isInBrowser2['default']) {\n // Order matters. We need to check Webkit the last one because\n // other vendors use to add Webkit prefixes to some properties\n var jsCssMap = {\n Moz: '-moz-',\n // IE did it wrong again ...\n ms: '-ms-',\n O: '-o-',\n Webkit: '-webkit-'\n };\n var style = document.createElement('p').style;\n var testProp = 'Transform';\n\n for (var key in jsCssMap) {\n if (key + testProp in style) {\n js = key;\n css = jsCssMap[key];\n break;\n }\n }\n}\n\n/**\n * Vendor prefix string for the current browser.\n *\n * @type {{js: String, css: String}}\n * @api public\n */\nexports['default'] = { js: js, css: css };", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = supportedProperty;\n\nvar _isInBrowser = require('is-in-browser');\n\nvar _isInBrowser2 = _interopRequireDefault(_isInBrowser);\n\nvar _prefix = require('./prefix');\n\nvar _prefix2 = _interopRequireDefault(_prefix);\n\nvar _camelize = require('./camelize');\n\nvar _camelize2 = _interopRequireDefault(_camelize);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar el = void 0;\nvar cache = {};\n\nif (_isInBrowser2['default']) {\n el = document.createElement('p');\n\n /**\n * We test every property on vendor prefix requirement.\n * Once tested, result is cached. It gives us up to 70% perf boost.\n * http://jsperf.com/element-style-object-access-vs-plain-object\n *\n * Prefill cache with known css properties to reduce amount of\n * properties we need to feature test at runtime.\n * http://davidwalsh.name/vendor-prefix\n */\n var computed = window.getComputedStyle(document.documentElement, '');\n for (var key in computed) {\n if (!isNaN(key)) cache[computed[key]] = computed[key];\n }\n}\n\n/**\n * Test if a property is supported, returns supported property with vendor\n * prefix if required. Returns ` + ("`" + `false`))) + (("`" + (` if not supported.\n *\n * @param {String} prop dash separated\n * @return {String|Boolean}\n * @api public\n */\nfunction supportedProperty(prop) {\n // For server-side rendering.\n if (!el) return prop;\n\n // We have not tested this prop yet, lets do the test.\n if (cache[prop] != null) return cache[prop];\n\n // Camelization is required because we can't test using\n // css syntax for e.g. in FF.\n // Test if property is supported as it is.\n if ((0, _camelize2['default'])(prop) in el.style) {\n cache[prop] = prop;\n }\n // Test if property is supported with vendor prefix.\n else if (_prefix2['default'].js + (0, _camelize2['default'])('-' + prop) in el.style) {\n cache[prop] = _prefix2['default'].css + prop;\n } else {\n cache[prop] = false;\n }\n\n return cache[prop];\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = supportedValue;\n\nvar _isInBrowser = require('is-in-browser');\n\nvar _isInBrowser2 = _interopRequireDefault(_isInBrowser);\n\nvar _prefix = require('./prefix');\n\nvar _prefix2 = _interopRequireDefault(_prefix);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar cache = {};\nvar el = void 0;\n\nif (_isInBrowser2['default']) el = document.createElement('p');\n\n/**\n * Returns prefixed value if needed. Returns ` + "`")) + (`false` + ("`" + ` if value is not supported.\n *\n * @param {String} property\n * @param {String} value\n * @return {String|Boolean}\n * @api public\n */\nfunction supportedValue(property, value) {\n // For server-side rendering.\n if (!el) return value;\n\n // It is a string or a number as a string like '1'.\n // We want only prefixable values here.\n if (typeof value !== 'string' || !isNaN(parseInt(value, 10))) return value;\n\n var cacheKey = property + value;\n\n if (cache[cacheKey] != null) return cache[cacheKey];\n\n // IE can even throw an error in some cases, for e.g. style.content = 'bar'\n try {\n // Test value as it is.\n el.style[property] = value;\n } catch (err) {\n cache[cacheKey] = false;\n return false;\n }\n\n // Value is supported as it is.\n if (el.style[property] !== '') {\n cache[cacheKey] = value;\n } else {\n // Test value with vendor prefix.\n value = _prefix2['default'].css + value;\n\n // Hardcode test to convert \"flex\" to \"-ms-flexbox\" for IE10.\n if (value === '-ms-flex') value = '-ms-flexbox';\n\n el.style[property] = value;\n\n // Value is supported with vendor prefix.\n if (el.style[property] !== '') cache[cacheKey] = value;\n }\n\n if (!cache[cacheKey]) cache[cacheKey] = false;\n\n // Reset style value.\n el.style[property] = '';\n\n return cache[cacheKey];\n}", + "export default function(a, b) {\n return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n", + "import ascending from \"./ascending\";\n\nexport default function(compare) {\n if (compare.length === 1) compare = ascendingComparator(compare);\n return {\n left: function(a, x, lo, hi) {\n if (lo == null) lo = 0;\n if (hi == null) hi = a.length;\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (compare(a[mid], x) < 0) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n },\n right: function(a, x, lo, hi) {\n if (lo == null) lo = 0;\n if (hi == null) hi = a.length;\n while (lo < hi) {\n var mid = lo + hi >>> 1;\n if (compare(a[mid], x) > 0) hi = mid;\n else lo = mid + 1;\n }\n return lo;\n }\n };\n}\n\nfunction ascendingComparator(f) {\n return function(d, x) {\n return ascending(f(d), x);\n };\n}\n", + "import ascending from \"./ascending\";\nimport bisector from \"./bisector\";\n\nvar ascendingBisect = bisector(ascending);\nexport var bisectRight = ascendingBisect.right;\nexport var bisectLeft = ascendingBisect.left;\nexport default bisectRight;\n", + "import {pair} from \"./pairs\";\n\nexport default function(values0, values1, reduce) {\n var n0 = values0.length,\n n1 = values1.length,\n values = new Array(n0 * n1),\n i0,\n i1,\n i,\n value0;\n\n if (reduce == null) reduce = pair;\n\n for (i0 = i = 0; i0 < n0; ++i0) {\n for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {\n values[i] = reduce(value0, values1[i1]);\n }\n }\n\n return values;\n}\n", + "export default function(x) {\n return x === null ? NaN : +x;\n}\n", + "var array = Array.prototype;\n\nexport var slice = array.slice;\nexport var map = array.map;\n", + "export default function(start, stop, step) {\n start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;\n\n var i = -1,\n n = Math.max(0, Math.ceil((stop - start) / step)) | 0,\n range = new Array(n);\n\n while (++i < n) {\n range[i] = start + i * step;\n }\n\n return range;\n}\n", + "var e10 = Math.sqrt(50),\n e5 = Math.sqrt(10),\n e2 = Math.sqrt(2);\n\nexport default function(start, stop, count) {\n var reverse,\n i = -1,\n n,\n ticks,\n step;\n\n stop = +stop, start = +start, count = +count;\n if (start === stop && count > 0) return [start];\n if (reverse = stop < start) n = start, start = stop, stop = n;\n if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];\n\n if (step > 0) {\n start = Math.ceil(start / step);\n stop = Math.floor(stop / step);\n ticks = new Array(n = Math.ceil(stop - start + 1));\n while (++i < n) ticks[i] = (start + i) * step;\n } else {\n start = Math.floor(start * step);\n stop = Math.ceil(stop * step);\n ticks = new Array(n = Math.ceil(start - stop + 1));\n while (++i < n) ticks[i] = (start - i) / step;\n }\n\n if (reverse) ticks.reverse();\n\n return ticks;\n}\n\nexport function tickIncrement(start, stop, count) {\n var step = (stop - start) / Math.max(0, count),\n power = Math.floor(Math.log(step) / Math.LN10),\n error = step / Math.pow(10, power);\n return power >= 0\n ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)\n : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);\n}\n\nexport function tickStep(start, stop, count) {\n var step0 = Math.abs(stop - start) / Math.max(0, count),\n step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),\n error = step0 / step1;\n if (error >= e10) step1 *= 10;\n else if (error >= e5) step1 *= 5;\n else if (error >= e2) step1 *= 2;\n return stop < start ? -step1 : step1;\n}\n", + "export default function(values) {\n return Math.ceil(Math.log(values.length) / Math.LN2) + 1;\n}\n", + "import number from \"./number\";\n\nexport default function(values, p, valueof) {\n if (valueof == null) valueof = number;\n if (!(n = values.length)) return;\n if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);\n if (p >= 1) return +valueof(values[n - 1], n - 1, values);\n var n,\n i = (n - 1) * p,\n i0 = Math.floor(i),\n value0 = +valueof(values[i0], i0, values),\n value1 = +valueof(values[i0 + 1], i0 + 1, values);\n return value0 + (value1 - value0) * (i - i0);\n}\n", + "export var prefix = \"$\";\n\nfunction Map() {}\n\nMap.prototype = map.prototype = {\n constructor: Map,\n has: function(key) {\n return (prefix + key) in this;\n },\n get: function(key) {\n return this[prefix + key];\n },\n set: function(key, value) {\n this[prefix + key] = value;\n return this;\n },\n remove: function(key) {\n var property = prefix + key;\n return property in this && delete this[property];\n },\n clear: function() {\n for (var property in this) if (property[0] === prefix) delete this[property];\n },\n keys: function() {\n var keys = [];\n for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));\n return keys;\n },\n values: function() {\n var values = [];\n for (var property in this) if (property[0] === prefix) values.push(this[property]);\n return values;\n },\n entries: function() {\n var entries = [];\n for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});\n return entries;\n },\n size: function() {\n var size = 0;\n for (var property in this) if (property[0] === prefix) ++size;\n return size;\n },\n empty: function() {\n for (var property in this) if (property[0] === prefix) return false;\n return true;\n },\n each: function(f) {\n for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);\n }\n};\n\nfunction map(object, f) {\n var map = new Map;\n\n // Copy constructor.\n if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });\n\n // Index array by numeric index or specified key function.\n else if (Array.isArray(object)) {\n var i = -1,\n n = object.length,\n o;\n\n if (f == null) while (++i < n) map.set(i, object[i]);\n else while (++i < n) map.set(f(o = object[i], i, object), o);\n }\n\n // Convert object to map.\n else if (object) for (var key in object) map.set(key, object[key]);\n\n return map;\n}\n\nexport default map;\n", + "import {default as map, prefix} from \"./map\";\n\nfunction Set() {}\n\nvar proto = map.prototype;\n\nSet.prototype = set.prototype = {\n constructor: Set,\n has: proto.has,\n add: function(value) {\n value += \"\";\n this[prefix + value] = value;\n return this;\n },\n remove: proto.remove,\n clear: proto.clear,\n values: proto.keys,\n size: proto.size,\n empty: proto.empty,\n each: proto.each\n};\n\nfunction set(object, f) {\n var set = new Set;\n\n // Copy constructor.\n if (object instanceof Set) object.each(function(value) { set.add(value); });\n\n // Otherwise, assume it’s an array.\n else if (object) {\n var i = -1, n = object.length;\n if (f == null) while (++i < n) set.add(object[i]);\n else while (++i < n) set.add(f(object[i], i, object));\n }\n\n return set;\n}\n\nexport default set;\n", + "var array = Array.prototype;\n\nexport var map = array.map;\nexport var slice = array.slice;\n", + "import {map} from \"d3-collection\";\nimport {slice} from \"./array\";\n\nexport var implicit = {name: \"implicit\"};\n\nexport default function ordinal(range) {\n var index = map(),\n domain = [],\n unknown = implicit;\n\n range = range == null ? [] : slice.call(range);\n\n function scale(d) {\n var key = d + \"\", i = index.get(key);\n if (!i) {\n if (unknown !== implicit) return unknown;\n index.set(key, i = domain.push(d));\n }\n return range[(i - 1) % range.length];\n }\n\n scale.domain = function(_) {\n if (!arguments.length) return domain.slice();\n domain = [], index = map();\n var i = -1, n = _.length, d, key;\n while (++i < n) if (!index.has(key = (d = _[i]) + \"\")) index.set(key, domain.push(d));\n return scale;\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = slice.call(_), scale) : range.slice();\n };\n\n scale.unknown = function(_) {\n return arguments.length ? (unknown = _, scale) : unknown;\n };\n\n scale.copy = function() {\n return ordinal()\n .domain(domain)\n .range(range)\n .unknown(unknown);\n };\n\n return scale;\n}\n", + "import {range as sequence} from \"d3-array\";\nimport ordinal from \"./ordinal\";\n\nexport default function band() {\n var scale = ordinal().unknown(undefined),\n domain = scale.domain,\n ordinalRange = scale.range,\n range = [0, 1],\n step,\n bandwidth,\n round = false,\n paddingInner = 0,\n paddingOuter = 0,\n align = 0.5;\n\n delete scale.unknown;\n\n function rescale() {\n var n = domain().length,\n reverse = range[1] < range[0],\n start = range[reverse - 0],\n stop = range[1 - reverse];\n step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);\n if (round) step = Math.floor(step);\n start += (stop - start - step * (n - paddingInner)) * align;\n bandwidth = step * (1 - paddingInner);\n if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);\n var values = sequence(n).map(function(i) { return start + step * i; });\n return ordinalRange(reverse ? values.reverse() : values);\n }\n\n scale.domain = function(_) {\n return arguments.length ? (domain(_), rescale()) : domain();\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice();\n };\n\n scale.rangeRound = function(_) {\n return range = [+_[0], +_[1]], round = true, rescale();\n };\n\n scale.bandwidth = function() {\n return bandwidth;\n };\n\n scale.step = function() {\n return step;\n };\n\n scale.round = function(_) {\n return arguments.length ? (round = !!_, rescale()) : round;\n };\n\n scale.padding = function(_) {\n return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;\n };\n\n scale.paddingInner = function(_) {\n return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;\n };\n\n scale.paddingOuter = function(_) {\n return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;\n };\n\n scale.align = function(_) {\n return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;\n };\n\n scale.copy = function() {\n return band()\n .domain(domain())\n .range(range)\n .round(round)\n .paddingInner(paddingInner)\n .paddingOuter(paddingOuter)\n .align(align);\n };\n\n return rescale();\n}\n\nfunction pointish(scale) {\n var copy = scale.copy;\n\n scale.padding = scale.paddingOuter;\n delete scale.paddingInner;\n delete scale.paddingOuter;\n\n scale.copy = function() {\n return pointish(copy());\n };\n\n return scale;\n}\n\nexport function point() {\n return pointish(band().paddingInner(1));\n}\n", + "export default function(constructor, factory, prototype) {\n constructor.prototype = factory.prototype = prototype;\n prototype.constructor = constructor;\n}\n\nexport function extend(parent, definition) {\n var prototype = Object.create(parent.prototype);\n for (var key in definition) prototype[key] = definition[key];\n return prototype;\n}\n", + "import define, {extend} from \"./define\";\n\nexport function Color() {}\n\nexport var darker = 0.7;\nexport var brighter = 1 / darker;\n\nvar reI = \"\\\\s*([+-]?\\\\d+)\\\\s*\",\n reN = \"\\\\s*([+-]?\\\\d*\\\\.?\\\\d+(?:[eE][+-]?\\\\d+)?)\\\\s*\",\n reP = \"\\\\s*([+-]?\\\\d*\\\\.?\\\\d+(?:[eE][+-]?\\\\d+)?)%\\\\s*\",\n reHex3 = /^#([0-9a-f]{3})$/,\n reHex6 = /^#([0-9a-f]{6})$/,\n reRgbInteger = new RegExp(\"^rgb\\\\(\" + [reI, reI, reI] + \"\\\\)$\"),\n reRgbPercent = new RegExp(\"^rgb\\\\(\" + [reP, reP, reP] + \"\\\\)$\"),\n reRgbaInteger = new RegExp(\"^rgba\\\\(\" + [reI, reI, reI, reN] + \"\\\\)$\"),\n reRgbaPercent = new RegExp(\"^rgba\\\\(\" + [reP, reP, reP, reN] + \"\\\\)$\"),\n reHslPercent = new RegExp(\"^hsl\\\\(\" + [reN, reP, reP] + \"\\\\)$\"),\n reHslaPercent = new RegExp(\"^hsla\\\\(\" + [reN, reP, reP, reN] + \"\\\\)$\");\n\nvar named = {\n aliceblue: 0xf0f8ff,\n antiquewhite: 0xfaebd7,\n aqua: 0x00ffff,\n aquamarine: 0x7fffd4,\n azure: 0xf0ffff,\n beige: 0xf5f5dc,\n bisque: 0xffe4c4,\n black: 0x000000,\n blanchedalmond: 0xffebcd,\n blue: 0x0000ff,\n blueviolet: 0x8a2be2,\n brown: 0xa52a2a,\n burlywood: 0xdeb887,\n cadetblue: 0x5f9ea0,\n chartreuse: 0x7fff00,\n chocolate: 0xd2691e,\n coral: 0xff7f50,\n cornflowerblue: 0x6495ed,\n cornsilk: 0xfff8dc,\n crimson: 0xdc143c,\n cyan: 0x00ffff,\n darkblue: 0x00008b,\n darkcyan: 0x008b8b,\n darkgoldenrod: 0xb8860b,\n darkgray: 0xa9a9a9,\n darkgreen: 0x006400,\n darkgrey: 0xa9a9a9,\n darkkhaki: 0xbdb76b,\n darkmagenta: 0x8b008b,\n darkolivegreen: 0x556b2f,\n darkorange: 0xff8c00,\n darkorchid: 0x9932cc,\n darkred: 0x8b0000,\n darksalmon: 0xe9967a,\n darkseagreen: 0x8fbc8f,\n darkslateblue: 0x483d8b,\n darkslategray: 0x2f4f4f,\n darkslategrey: 0x2f4f4f,\n darkturquoise: 0x00ced1,\n darkviolet: 0x9400d3,\n deeppink: 0xff1493,\n deepskyblue: 0x00bfff,\n dimgray: 0x696969,\n dimgrey: 0x696969,\n dodgerblue: 0x1e90ff,\n firebrick: 0xb22222,\n floralwhite: 0xfffaf0,\n forestgreen: 0x228b22,\n fuchsia: 0xff00ff,\n gainsboro: 0xdcdcdc,\n ghostwhite: 0xf8f8ff,\n gold: 0xffd700,\n goldenrod: 0xdaa520,\n gray: 0x808080,\n green: 0x008000,\n greenyellow: 0xadff2f,\n grey: 0x808080,\n honeydew: 0xf0fff0,\n hotpink: 0xff69b4,\n indianred: 0xcd5c5c,\n indigo: 0x4b0082,\n ivory: 0xfffff0,\n khaki: 0xf0e68c,\n lavender: 0xe6e6fa,\n lavenderblush: 0xfff0f5,\n lawngreen: 0x7cfc00,\n lemonchiffon: 0xfffacd,\n lightblue: 0xadd8e6,\n lightcoral: 0xf08080,\n lightcyan: 0xe0ffff,\n lightgoldenrodyellow: 0xfafad2,\n lightgray: 0xd3d3d3,\n lightgreen: 0x90ee90,\n lightgrey: 0xd3d3d3,\n lightpink: 0xffb6c1,\n lightsalmon: 0xffa07a,\n lightseagreen: 0x20b2aa,\n lightskyblue: 0x87cefa,\n lightslategray: 0x778899,\n lightslategrey: 0x778899,\n lightsteelblue: 0xb0c4de,\n lightyellow: 0xffffe0,\n lime: 0x00ff00,\n limegreen: 0x32cd32,\n linen: 0xfaf0e6,\n magenta: 0xff00ff,\n maroon: 0x800000,\n mediumaquamarine: 0x66cdaa,\n mediumblue: 0x0000cd,\n mediumorchid: 0xba55d3,\n mediumpurple: 0x9370db,\n mediumseagreen: 0x3cb371,\n mediumslateblue: 0x7b68ee,\n mediumspringgreen: 0x00fa9a,\n mediumturquoise: 0x48d1cc,\n mediumvioletred: 0xc71585,\n midnightblue: 0x191970,\n mintcream: 0xf5fffa,\n mistyrose: 0xffe4e1,\n moccasin: 0xffe4b5,\n navajowhite: 0xffdead,\n navy: 0x000080,\n oldlace: 0xfdf5e6,\n olive: 0x808000,\n olivedrab: 0x6b8e23,\n orange: 0xffa500,\n orangered: 0xff4500,\n orchid: 0xda70d6,\n palegoldenrod: 0xeee8aa,\n palegreen: 0x98fb98,\n paleturquoise: 0xafeeee,\n palevioletred: 0xdb7093,\n papayawhip: 0xffefd5,\n peachpuff: 0xffdab9,\n peru: 0xcd853f,\n pink: 0xffc0cb,\n plum: 0xdda0dd,\n powderblue: 0xb0e0e6,\n purple: 0x800080,\n rebeccapurple: 0x663399,\n red: 0xff0000,\n rosybrown: 0xbc8f8f,\n royalblue: 0x4169e1,\n saddlebrown: 0x8b4513,\n salmon: 0xfa8072,\n sandybrown: 0xf4a460,\n seagreen: 0x2e8b57,\n seashell: 0xfff5ee,\n sienna: 0xa0522d,\n silver: 0xc0c0c0,\n skyblue: 0x87ceeb,\n slateblue: 0x6a5acd,\n slategray: 0x708090,\n slategrey: 0x708090,\n snow: 0xfffafa,\n springgreen: 0x00ff7f,\n steelblue: 0x4682b4,\n tan: 0xd2b48c,\n teal: 0x008080,\n thistle: 0xd8bfd8,\n tomato: 0xff6347,\n turquoise: 0x40e0d0,\n violet: 0xee82ee,\n wheat: 0xf5deb3,\n white: 0xffffff,\n whitesmoke: 0xf5f5f5,\n yellow: 0xffff00,\n yellowgreen: 0x9acd32\n};\n\ndefine(Color, color, {\n displayable: function() {\n return this.rgb().displayable();\n },\n hex: function() {\n return this.rgb().hex();\n },\n toString: function() {\n return this.rgb() + \"\";\n }\n});\n\nexport default function color(format) {\n var m;\n format = (format + \"\").trim().toLowerCase();\n return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00\n : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000\n : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)\n : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)\n : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)\n : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)\n : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)\n : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)\n : named.hasOwnProperty(format) ? rgbn(named[format])\n : format === \"transparent\" ? new Rgb(NaN, NaN, NaN, 0)\n : null;\n}\n\nfunction rgbn(n) {\n return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);\n}\n\nfunction rgba(r, g, b, a) {\n if (a <= 0) r = g = b = NaN;\n return new Rgb(r, g, b, a);\n}\n\nexport function rgbConvert(o) {\n if (!(o instanceof Color)) o = color(o);\n if (!o) return new Rgb;\n o = o.rgb();\n return new Rgb(o.r, o.g, o.b, o.opacity);\n}\n\nexport function rgb(r, g, b, opacity) {\n return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);\n}\n\nexport function Rgb(r, g, b, opacity) {\n this.r = +r;\n this.g = +g;\n this.b = +b;\n this.opacity = +opacity;\n}\n\ndefine(Rgb, rgb, extend(Color, {\n brighter: function(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);\n },\n darker: function(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);\n },\n rgb: function() {\n return this;\n },\n displayable: function() {\n return (0 <= this.r && this.r <= 255)\n && (0 <= this.g && this.g <= 255)\n && (0 <= this.b && this.b <= 255)\n && (0 <= this.opacity && this.opacity <= 1);\n },\n hex: function() {\n return \"#\" + hex(this.r) + hex(this.g) + hex(this.b);\n },\n toString: function() {\n var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));\n return (a === 1 ? \"rgb(\" : \"rgba(\")\n + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + \", \"\n + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + \", \"\n + Math.max(0, Math.min(255, Math.round(this.b) || 0))\n + (a === 1 ? \")\" : \", \" + a + \")\");\n }\n}));\n\nfunction hex(value) {\n value = Math.max(0, Math.min(255, Math.round(value) || 0));\n return (value < 16 ? \"0\" : \"\") + value.toString(16);\n}\n\nfunction hsla(h, s, l, a) {\n if (a <= 0) h = s = l = NaN;\n else if (l <= 0 || l >= 1) h = s = NaN;\n else if (s <= 0) h = NaN;\n return new Hsl(h, s, l, a);\n}\n\nexport function hslConvert(o) {\n if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);\n if (!(o instanceof Color)) o = color(o);\n if (!o) return new Hsl;\n if (o instanceof Hsl) return o;\n o = o.rgb();\n var r = o.r / 255,\n g = o.g / 255,\n b = o.b / 255,\n min = Math.min(r, g, b),\n max = Math.max(r, g, b),\n h = NaN,\n s = max - min,\n l = (max + min) / 2;\n if (s) {\n if (r === max) h = (g - b) / s + (g < b) * 6;\n else if (g === max) h = (b - r) / s + 2;\n else h = (r - g) / s + 4;\n s /= l < 0.5 ? max + min : 2 - max - min;\n h *= 60;\n } else {\n s = l > 0 && l < 1 ? 0 : h;\n }\n return new Hsl(h, s, l, o.opacity);\n}\n\nexport function hsl(h, s, l, opacity) {\n return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);\n}\n\nfunction Hsl(h, s, l, opacity) {\n this.h = +h;\n this.s = +s;\n this.l = +l;\n this.opacity = +opacity;\n}\n\ndefine(Hsl, hsl, extend(Color, {\n brighter: function(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Hsl(this.h, this.s, this.l * k, this.opacity);\n },\n darker: function(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Hsl(this.h, this.s, this.l * k, this.opacity);\n },\n rgb: function() {\n var h = this.h % 360 + (this.h < 0) * 360,\n s = isNaN(h) || isNaN(this.s) ? 0 : this.s,\n l = this.l,\n m2 = l + (l < 0.5 ? l : 1 - l) * s,\n m1 = 2 * l - m2;\n return new Rgb(\n hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),\n hsl2rgb(h, m1, m2),\n hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),\n this.opacity\n );\n },\n displayable: function() {\n return (0 <= this.s && this.s <= 1 || isNaN(this.s))\n && (0 <= this.l && this.l <= 1)\n && (0 <= this.opacity && this.opacity <= 1);\n }\n}));\n\n/* From FvD 13.37, CSS Color Module Level 3 */\nfunction hsl2rgb(h, m1, m2) {\n return (h < 60 ? m1 + (m2 - m1) * h / 60\n : h < 180 ? m2\n : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60\n : m1) * 255;\n}\n", + "export var deg2rad = Math.PI / 180;\nexport var rad2deg = 180 / Math.PI;\n", + "import define, {extend} from \"./define\";\nimport {Color, rgbConvert, Rgb} from \"./color\";\nimport {deg2rad, rad2deg} from \"./math\";\n\n// https://beta.observablehq.com/@mbostock/lab-and-rgb\nvar K = 18,\n Xn = 0.96422,\n Yn = 1,\n Zn = 0.82521,\n t0 = 4 / 29,\n t1 = 6 / 29,\n t2 = 3 * t1 * t1,\n t3 = t1 * t1 * t1;\n\nfunction labConvert(o) {\n if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);\n if (o instanceof Hcl) {\n if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);\n var h = o.h * deg2rad;\n return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);\n }\n if (!(o instanceof Rgb)) o = rgbConvert(o);\n var r = rgb2lrgb(o.r),\n g = rgb2lrgb(o.g),\n b = rgb2lrgb(o.b),\n y = xyz2lab((0.2225045 * r + 0.7168786 * g + 0.0606169 * b) / Yn), x, z;\n if (r === g && g === b) x = z = y; else {\n x = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn);\n z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn);\n }\n return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);\n}\n\nexport function gray(l, opacity) {\n return new Lab(l, 0, 0, opacity == null ? 1 : opacity);\n}\n\nexport default function lab(l, a, b, opacity) {\n return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);\n}\n\nexport function Lab(l, a, b, opacity) {\n this.l = +l;\n this.a = +a;\n this.b = +b;\n this.opacity = +opacity;\n}\n\ndefine(Lab, lab, extend(Color, {\n brighter: function(k) {\n return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);\n },\n darker: function(k) {\n return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);\n },\n rgb: function() {\n var y = (this.l + 16) / 116,\n x = isNaN(this.a) ? y : y + this.a / 500,\n z = isNaN(this.b) ? y : y - this.b / 200;\n x = Xn * lab2xyz(x);\n y = Yn * lab2xyz(y);\n z = Zn * lab2xyz(z);\n return new Rgb(\n lrgb2rgb( 3.1338561 * x - 1.6168667 * y - 0.4906146 * z),\n lrgb2rgb(-0.9787684 * x + 1.9161415 * y + 0.0334540 * z),\n lrgb2rgb( 0.0719453 * x - 0.2289914 * y + 1.4052427 * z),\n this.opacity\n );\n }\n}));\n\nfunction xyz2lab(t) {\n return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;\n}\n\nfunction lab2xyz(t) {\n return t > t1 ? t * t * t : t2 * (t - t0);\n}\n\nfunction lrgb2rgb(x) {\n return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);\n}\n\nfunction rgb2lrgb(x) {\n return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);\n}\n\nfunction hclConvert(o) {\n if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);\n if (!(o instanceof Lab)) o = labConvert(o);\n if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0, o.l, o.opacity);\n var h = Math.atan2(o.b, o.a) * rad2deg;\n return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);\n}\n\nexport function lch(l, c, h, opacity) {\n return arguments.length === 1 ? hclConvert(l) : new Hcl(h, c, l, opacity == null ? 1 : opacity);\n}\n\nexport function hcl(h, c, l, opacity) {\n return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);\n}\n\nexport function Hcl(h, c, l, opacity) {\n this.h = +h;\n this.c = +c;\n this.l = +l;\n this.opacity = +opacity;\n}\n\ndefine(Hcl, hcl, extend(Color, {\n brighter: function(k) {\n return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);\n },\n darker: function(k) {\n return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);\n },\n rgb: function() {\n return labConvert(this).rgb();\n }\n}));\n", + "import define, {extend} from \"./define\";\nimport {Color, rgbConvert, Rgb, darker, brighter} from \"./color\";\nimport {deg2rad, rad2deg} from \"./math\";\n\nvar A = -0.14861,\n B = +1.78277,\n C = -0.29227,\n D = -0.90649,\n E = +1.97294,\n ED = E * D,\n EB = E * B,\n BC_DA = B * C - D * A;\n\nfunction cubehelixConvert(o) {\n if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);\n if (!(o instanceof Rgb)) o = rgbConvert(o);\n var r = o.r / 255,\n g = o.g / 255,\n b = o.b / 255,\n l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),\n bl = b - l,\n k = (E * (g - l) - C * bl) / D,\n s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1\n h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;\n return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);\n}\n\nexport default function cubehelix(h, s, l, opacity) {\n return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);\n}\n\nexport function Cubehelix(h, s, l, opacity) {\n this.h = +h;\n this.s = +s;\n this.l = +l;\n this.opacity = +opacity;\n}\n\ndefine(Cubehelix, cubehelix, extend(Color, {\n brighter: function(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Cubehelix(this.h, this.s, this.l * k, this.opacity);\n },\n darker: function(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Cubehelix(this.h, this.s, this.l * k, this.opacity);\n },\n rgb: function() {\n var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,\n l = +this.l,\n a = isNaN(this.s) ? 0 : this.s * l * (1 - l),\n cosh = Math.cos(h),\n sinh = Math.sin(h);\n return new Rgb(\n 255 * (l + a * (A * cosh + B * sinh)),\n 255 * (l + a * (C * cosh + D * sinh)),\n 255 * (l + a * (E * cosh)),\n this.opacity\n );\n }\n}));\n", + "export function basis(t1, v0, v1, v2, v3) {\n var t2 = t1 * t1, t3 = t2 * t1;\n return ((1 - 3 * t1 + 3 * t2 - t3) * v0\n + (4 - 6 * t2 + 3 * t3) * v1\n + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2\n + t3 * v3) / 6;\n}\n\nexport default function(values) {\n var n = values.length - 1;\n return function(t) {\n var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),\n v1 = values[i],\n v2 = values[i + 1],\n v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,\n v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;\n return basis((t - i / n) * n, v0, v1, v2, v3);\n };\n}\n", + "export default function(x) {\n return function() {\n return x;\n };\n}\n", + "import constant from \"./constant\";\n\nfunction linear(a, d) {\n return function(t) {\n return a + t * d;\n };\n}\n\nfunction exponential(a, b, y) {\n return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {\n return Math.pow(a + t * b, y);\n };\n}\n\nexport function hue(a, b) {\n var d = b - a;\n return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);\n}\n\nexport function gamma(y) {\n return (y = +y) === 1 ? nogamma : function(a, b) {\n return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);\n };\n}\n\nexport default function nogamma(a, b) {\n var d = b - a;\n return d ? linear(a, d) : constant(isNaN(a) ? b : a);\n}\n", + "import {rgb as colorRgb} from \"d3-color\";\nimport basis from \"./basis\";\nimport basisClosed from \"./basisClosed\";\nimport nogamma, {gamma} from \"./color\";\n\nexport default (function rgbGamma(y) {\n var color = gamma(y);\n\n function rgb(start, end) {\n var r = color((start = colorRgb(start)).r, (end = colorRgb(end)).r),\n g = color(start.g, end.g),\n b = color(start.b, end.b),\n opacity = nogamma(start.opacity, end.opacity);\n return function(t) {\n start.r = r(t);\n start.g = g(t);\n start.b = b(t);\n start.opacity = opacity(t);\n return start + \"\";\n };\n }\n\n rgb.gamma = rgbGamma;\n\n return rgb;\n})(1);\n\nfunction rgbSpline(spline) {\n return function(colors) {\n var n = colors.length,\n r = new Array(n),\n g = new Array(n),\n b = new Array(n),\n i, color;\n for (i = 0; i < n; ++i) {\n color = colorRgb(colors[i]);\n r[i] = color.r || 0;\n g[i] = color.g || 0;\n b[i] = color.b || 0;\n }\n r = spline(r);\n g = spline(g);\n b = spline(b);\n color.opacity = 1;\n return function(t) {\n color.r = r(t);\n color.g = g(t);\n color.b = b(t);\n return color + \"\";\n };\n };\n}\n\nexport var rgbBasis = rgbSpline(basis);\nexport var rgbBasisClosed = rgbSpline(basisClosed);\n", + "import {basis} from \"./basis\";\n\nexport default function(values) {\n var n = values.length;\n return function(t) {\n var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),\n v0 = values[(i + n - 1) % n],\n v1 = values[i % n],\n v2 = values[(i + 1) % n],\n v3 = values[(i + 2) % n];\n return basis((t - i / n) * n, v0, v1, v2, v3);\n };\n}\n", + "export default function(a, b) {\n return a = +a, b -= a, function(t) {\n return a + b * t;\n };\n}\n", + "import number from \"./number\";\n\nvar reA = /[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g,\n reB = new RegExp(reA.source, \"g\");\n\nfunction zero(b) {\n return function() {\n return b;\n };\n}\n\nfunction one(b) {\n return function(t) {\n return b(t) + \"\";\n };\n}\n\nexport default function(a, b) {\n var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b\n am, // current match in a\n bm, // current match in b\n bs, // string preceding current number in b, if any\n i = -1, // index in s\n s = [], // string constants and placeholders\n q = []; // number interpolators\n\n // Coerce inputs to strings.\n a = a + \"\", b = b + \"\";\n\n // Interpolate pairs of numbers in a & b.\n while ((am = reA.exec(a))\n && (bm = reB.exec(b))) {\n if ((bs = bm.index) > bi) { // a string precedes the next number in b\n bs = b.slice(bi, bs);\n if (s[i]) s[i] += bs; // coalesce with previous string\n else s[++i] = bs;\n }\n if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match\n if (s[i]) s[i] += bm; // coalesce with previous string\n else s[++i] = bm;\n } else { // interpolate non-matching numbers\n s[++i] = null;\n q.push({i: i, x: number(am, bm)});\n }\n bi = reB.lastIndex;\n }\n\n // Add remains of b.\n if (bi < b.length) {\n bs = b.slice(bi);\n if (s[i]) s[i] += bs; // coalesce with previous string\n else s[++i] = bs;\n }\n\n // Special optimization for only a single match.\n // Otherwise, interpolate each of the numbers and rejoin the string.\n return s.length < 2 ? (q[0]\n ? one(q[0].x)\n : zero(b))\n : (b = q.length, function(t) {\n for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);\n return s.join(\"\");\n });\n}\n", + "import decompose, {identity} from \"./decompose\";\n\nvar cssNode,\n cssRoot,\n cssView,\n svgNode;\n\nexport function parseCss(value) {\n if (value === \"none\") return identity;\n if (!cssNode) cssNode = document.createElement(\"DIV\"), cssRoot = document.documentElement, cssView = document.defaultView;\n cssNode.style.transform = value;\n value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue(\"transform\");\n cssRoot.removeChild(cssNode);\n value = value.slice(7, -1).split(\",\");\n return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);\n}\n\nexport function parseSvg(value) {\n if (value == null) return identity;\n if (!svgNode) svgNode = document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\");\n svgNode.setAttribute(\"transform\", value);\n if (!(value = svgNode.transform.baseVal.consolidate())) return identity;\n value = value.matrix;\n return decompose(value.a, value.b, value.c, value.d, value.e, value.f);\n}\n", + "import {color} from \"d3-color\";\nimport rgb from \"./rgb\";\nimport array from \"./array\";\nimport date from \"./date\";\nimport number from \"./number\";\nimport object from \"./object\";\nimport string from \"./string\";\nimport constant from \"./constant\";\n\nexport default function(a, b) {\n var t = typeof b, c;\n return b == null || t === \"boolean\" ? constant(b)\n : (t === \"number\" ? number\n : t === \"string\" ? ((c = color(b)) ? (b = c, rgb) : string)\n : b instanceof color ? rgb\n : b instanceof Date ? date\n : Array.isArray(b) ? array\n : typeof b.valueOf !== \"function\" && typeof b.toString !== \"function\" || isNaN(b) ? object\n : number)(a, b);\n}\n", + "export default function(a, b) {\n var d = new Date;\n return a = +a, b -= a, function(t) {\n return d.setTime(a + b * t), d;\n };\n}\n", + "import value from \"./value\";\n\nexport default function(a, b) {\n var nb = b ? b.length : 0,\n na = a ? Math.min(nb, a.length) : 0,\n x = new Array(na),\n c = new Array(nb),\n i;\n\n for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);\n for (; i < nb; ++i) c[i] = b[i];\n\n return function(t) {\n for (i = 0; i < na; ++i) c[i] = x[i](t);\n return c;\n };\n}\n", + "import value from \"./value\";\n\nexport default function(a, b) {\n var i = {},\n c = {},\n k;\n\n if (a === null || typeof a !== \"object\") a = {};\n if (b === null || typeof b !== \"object\") b = {};\n\n for (k in b) {\n if (k in a) {\n i[k] = value(a[k], b[k]);\n } else {\n c[k] = b[k];\n }\n }\n\n return function(t) {\n for (k in i) c[k] = i[k](t);\n return c;\n };\n}\n", + "export default function(a, b) {\n return a = +a, b -= a, function(t) {\n return Math.round(a + b * t);\n };\n}\n", + "var degrees = 180 / Math.PI;\n\nexport var identity = {\n translateX: 0,\n translateY: 0,\n rotate: 0,\n skewX: 0,\n scaleX: 1,\n scaleY: 1\n};\n\nexport default function(a, b, c, d, e, f) {\n var scaleX, scaleY, skewX;\n if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;\n if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;\n if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;\n if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;\n return {\n translateX: e,\n translateY: f,\n rotate: Math.atan2(b, a) * degrees,\n skewX: Math.atan(skewX) * degrees,\n scaleX: scaleX,\n scaleY: scaleY\n };\n}\n", + "import number from \"../number\";\nimport {parseCss, parseSvg} from \"./parse\";\n\nfunction interpolateTransform(parse, pxComma, pxParen, degParen) {\n\n function pop(s) {\n return s.length ? s.pop() + \" \" : \"\";\n }\n\n function translate(xa, ya, xb, yb, s, q) {\n if (xa !== xb || ya !== yb) {\n var i = s.push(\"translate(\", null, pxComma, null, pxParen);\n q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});\n } else if (xb || yb) {\n s.push(\"translate(\" + xb + pxComma + yb + pxParen);\n }\n }\n\n function rotate(a, b, s, q) {\n if (a !== b) {\n if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path\n q.push({i: s.push(pop(s) + \"rotate(\", null, degParen) - 2, x: number(a, b)});\n } else if (b) {\n s.push(pop(s) + \"rotate(\" + b + degParen);\n }\n }\n\n function skewX(a, b, s, q) {\n if (a !== b) {\n q.push({i: s.push(pop(s) + \"skewX(\", null, degParen) - 2, x: number(a, b)});\n } else if (b) {\n s.push(pop(s) + \"skewX(\" + b + degParen);\n }\n }\n\n function scale(xa, ya, xb, yb, s, q) {\n if (xa !== xb || ya !== yb) {\n var i = s.push(pop(s) + \"scale(\", null, \",\", null, \")\");\n q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});\n } else if (xb !== 1 || yb !== 1) {\n s.push(pop(s) + \"scale(\" + xb + \",\" + yb + \")\");\n }\n }\n\n return function(a, b) {\n var s = [], // string constants and placeholders\n q = []; // number interpolators\n a = parse(a), b = parse(b);\n translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);\n rotate(a.rotate, b.rotate, s, q);\n skewX(a.skewX, b.skewX, s, q);\n scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);\n a = b = null; // gc\n return function(t) {\n var i = -1, n = q.length, o;\n while (++i < n) s[(o = q[i]).i] = o.x(t);\n return s.join(\"\");\n };\n };\n}\n\nexport var interpolateTransformCss = interpolateTransform(parseCss, \"px, \", \"px)\", \"deg)\");\nexport var interpolateTransformSvg = interpolateTransform(parseSvg, \", \", \")\", \")\");\n", + "var rho = Math.SQRT2,\n rho2 = 2,\n rho4 = 4,\n epsilon2 = 1e-12;\n\nfunction cosh(x) {\n return ((x = Math.exp(x)) + 1 / x) / 2;\n}\n\nfunction sinh(x) {\n return ((x = Math.exp(x)) - 1 / x) / 2;\n}\n\nfunction tanh(x) {\n return ((x = Math.exp(2 * x)) - 1) / (x + 1);\n}\n\n// p0 = [ux0, uy0, w0]\n// p1 = [ux1, uy1, w1]\nexport default function(p0, p1) {\n var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],\n ux1 = p1[0], uy1 = p1[1], w1 = p1[2],\n dx = ux1 - ux0,\n dy = uy1 - uy0,\n d2 = dx * dx + dy * dy,\n i,\n S;\n\n // Special case for u0 ≅ u1.\n if (d2 < epsilon2) {\n S = Math.log(w1 / w0) / rho;\n i = function(t) {\n return [\n ux0 + t * dx,\n uy0 + t * dy,\n w0 * Math.exp(rho * t * S)\n ];\n }\n }\n\n // General case.\n else {\n var d1 = Math.sqrt(d2),\n b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),\n b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),\n r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),\n r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);\n S = (r1 - r0) / rho;\n i = function(t) {\n var s = t * S,\n coshr0 = cosh(r0),\n u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));\n return [\n ux0 + u * dx,\n uy0 + u * dy,\n w0 * coshr0 / cosh(rho * s + r0)\n ];\n }\n }\n\n i.duration = S * 1000;\n\n return i;\n}\n", + "import {hsl as colorHsl} from \"d3-color\";\nimport color, {hue} from \"./color\";\n\nfunction hsl(hue) {\n return function(start, end) {\n var h = hue((start = colorHsl(start)).h, (end = colorHsl(end)).h),\n s = color(start.s, end.s),\n l = color(start.l, end.l),\n opacity = color(start.opacity, end.opacity);\n return function(t) {\n start.h = h(t);\n start.s = s(t);\n start.l = l(t);\n start.opacity = opacity(t);\n return start + \"\";\n };\n }\n}\n\nexport default hsl(hue);\nexport var hslLong = hsl(color);\n", + "import {hcl as colorHcl} from \"d3-color\";\nimport color, {hue} from \"./color\";\n\nfunction hcl(hue) {\n return function(start, end) {\n var h = hue((start = colorHcl(start)).h, (end = colorHcl(end)).h),\n c = color(start.c, end.c),\n l = color(start.l, end.l),\n opacity = color(start.opacity, end.opacity);\n return function(t) {\n start.h = h(t);\n start.c = c(t);\n start.l = l(t);\n start.opacity = opacity(t);\n return start + \"\";\n };\n }\n}\n\nexport default hcl(hue);\nexport var hclLong = hcl(color);\n", + "import {cubehelix as colorCubehelix} from \"d3-color\";\nimport color, {hue} from \"./color\";\n\nfunction cubehelix(hue) {\n return (function cubehelixGamma(y) {\n y = +y;\n\n function cubehelix(start, end) {\n var h = hue((start = colorCubehelix(start)).h, (end = colorCubehelix(end)).h),\n s = color(start.s, end.s),\n l = color(start.l, end.l),\n opacity = color(start.opacity, end.opacity);\n return function(t) {\n start.h = h(t);\n start.s = s(t);\n start.l = l(Math.pow(t, y));\n start.opacity = opacity(t);\n return start + \"\";\n };\n }\n\n cubehelix.gamma = cubehelixGamma;\n\n return cubehelix;\n })(1);\n}\n\nexport default cubehelix(hue);\nexport var cubehelixLong = cubehelix(color);\n", + "export default function(interpolator, n) {\n var samples = new Array(n);\n for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));\n return samples;\n}\n", + "export default function(x) {\n return function() {\n return x;\n };\n}\n", + "export default function(x) {\n return +x;\n}\n", + "import {bisect} from \"d3-array\";\nimport {interpolate as interpolateValue, interpolateRound} from \"d3-interpolate\";\nimport {map, slice} from \"./array\";\nimport constant from \"./constant\";\nimport number from \"./number\";\n\nvar unit = [0, 1];\n\nexport function deinterpolateLinear(a, b) {\n return (b -= (a = +a))\n ? function(x) { return (x - a) / b; }\n : constant(b);\n}\n\nfunction deinterpolateClamp(deinterpolate) {\n return function(a, b) {\n var d = deinterpolate(a = +a, b = +b);\n return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };\n };\n}\n\nfunction reinterpolateClamp(reinterpolate) {\n return function(a, b) {\n var r = reinterpolate(a = +a, b = +b);\n return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };\n };\n}\n\nfunction bimap(domain, range, deinterpolate, reinterpolate) {\n var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];\n if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);\n else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);\n return function(x) { return r0(d0(x)); };\n}\n\nfunction polymap(domain, range, deinterpolate, reinterpolate) {\n var j = Math.min(domain.length, range.length) - 1,\n d = new Array(j),\n r = new Array(j),\n i = -1;\n\n // Reverse descending domains.\n if (domain[j] < domain[0]) {\n domain = domain.slice().reverse();\n range = range.slice().reverse();\n }\n\n while (++i < j) {\n d[i] = deinterpolate(domain[i], domain[i + 1]);\n r[i] = reinterpolate(range[i], range[i + 1]);\n }\n\n return function(x) {\n var i = bisect(domain, x, 1, j) - 1;\n return r[i](d[i](x));\n };\n}\n\nexport function copy(source, target) {\n return target\n .domain(source.domain())\n .range(source.range())\n .interpolate(source.interpolate())\n .clamp(source.clamp());\n}\n\n// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].\n// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].\nexport default function continuous(deinterpolate, reinterpolate) {\n var domain = unit,\n range = unit,\n interpolate = interpolateValue,\n clamp = false,\n piecewise,\n output,\n input;\n\n function rescale() {\n piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;\n output = input = null;\n return scale;\n }\n\n function scale(x) {\n return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate)))(+x);\n }\n\n scale.invert = function(y) {\n return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);\n };\n\n scale.domain = function(_) {\n return arguments.length ? (domain = map.call(_, number), rescale()) : domain.slice();\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = slice.call(_), rescale()) : range.slice();\n };\n\n scale.rangeRound = function(_) {\n return range = slice.call(_), interpolate = interpolateRound, rescale();\n };\n\n scale.clamp = function(_) {\n return arguments.length ? (clamp = !!_, rescale()) : clamp;\n };\n\n scale.interpolate = function(_) {\n return arguments.length ? (interpolate = _, rescale()) : interpolate;\n };\n\n return rescale();\n}\n", + "// Computes the decimal coefficient and exponent of the specified number x with\n// significant digits p, where x is positive and p is in [1, 21] or undefined.\n// For example, formatDecimal(1.23) returns [\"123\", 0].\nexport default function(x, p) {\n if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf(\"e\")) < 0) return null; // NaN, ±Infinity\n var i, coefficient = x.slice(0, i);\n\n // The string returned by toExponential either has the form \\d\\.\\d+e[-+]\\d+\n // (e.g., 1.2e+3) or the form \\de[-+]\\d+ (e.g., 1e+3).\n return [\n coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,\n +x.slice(i + 1)\n ];\n}\n", + "import formatDecimal from \"./formatDecimal\";\n\nexport default function(x) {\n return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;\n}\n", + "// [[fill]align][sign][symbol][0][width][,][.precision][~][type]\nvar re = /^(?:(.)?([<>=^]))?([+\\-( ])?([$#])?(0)?(\\d+)?(,)?(\\.\\d+)?(~)?([a-z%])?$/i;\n\nexport default function formatSpecifier(specifier) {\n return new FormatSpecifier(specifier);\n}\n\nformatSpecifier.prototype = FormatSpecifier.prototype; // instanceof\n\nfunction FormatSpecifier(specifier) {\n if (!(match = re.exec(specifier))) throw new Error(\"invalid format: \" + specifier);\n var match;\n this.fill = match[1] || \" \";\n this.align = match[2] || \">\";\n this.sign = match[3] || \"-\";\n this.symbol = match[4] || \"\";\n this.zero = !!match[5];\n this.width = match[6] && +match[6];\n this.comma = !!match[7];\n this.precision = match[8] && +match[8].slice(1);\n this.trim = !!match[9];\n this.type = match[10] || \"\";\n}\n\nFormatSpecifier.prototype.toString = function() {\n return this.fill\n + this.align\n + this.sign\n + this.symbol\n + (this.zero ? \"0\" : \"\")\n + (this.width == null ? \"\" : Math.max(1, this.width | 0))\n + (this.comma ? \",\" : \"\")\n + (this.precision == null ? \"\" : \".\" + Math.max(0, this.precision | 0))\n + (this.trim ? \"~\" : \"\")\n + this.type;\n};\n", + "// Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.\nexport default function(s) {\n out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {\n switch (s[i]) {\n case \".\": i0 = i1 = i; break;\n case \"0\": if (i0 === 0) i0 = i; i1 = i; break;\n default: if (i0 > 0) { if (!+s[i]) break out; i0 = 0; } break;\n }\n }\n return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;\n}\n", + "import formatDecimal from \"./formatDecimal\";\n\nexport var prefixExponent;\n\nexport default function(x, p) {\n var d = formatDecimal(x, p);\n if (!d) return x + \"\";\n var coefficient = d[0],\n exponent = d[1],\n i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,\n n = coefficient.length;\n return i === n ? coefficient\n : i > n ? coefficient + new Array(i - n + 1).join(\"0\")\n : i > 0 ? coefficient.slice(0, i) + \".\" + coefficient.slice(i)\n : \"0.\" + new Array(1 - i).join(\"0\") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!\n}\n", + "import formatLocale from \"./locale\";\n\nvar locale;\nexport var format;\nexport var formatPrefix;\n\ndefaultLocale({\n decimal: \".\",\n thousands: \",\",\n grouping: [3],\n currency: [\"$\", \"\"]\n});\n\nexport default function defaultLocale(definition) {\n locale = formatLocale(definition);\n format = locale.format;\n formatPrefix = locale.formatPrefix;\n return locale;\n}\n", + "import formatDecimal from \"./formatDecimal\";\n\nexport default function(x, p) {\n var d = formatDecimal(x, p);\n if (!d) return x + \"\";\n var coefficient = d[0],\n exponent = d[1];\n return exponent < 0 ? \"0.\" + new Array(-exponent).join(\"0\") + coefficient\n : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + \".\" + coefficient.slice(exponent + 1)\n : coefficient + new Array(exponent - coefficient.length + 2).join(\"0\");\n}\n", + "import formatPrefixAuto from \"./formatPrefixAuto\";\nimport formatRounded from \"./formatRounded\";\n\nexport default {\n \"%\": function(x, p) { return (x * 100).toFixed(p); },\n \"b\": function(x) { return Math.round(x).toString(2); },\n \"c\": function(x) { return x + \"\"; },\n \"d\": function(x) { return Math.round(x).toString(10); },\n \"e\": function(x, p) { return x.toExponential(p); },\n \"f\": function(x, p) { return x.toFixed(p); },\n \"g\": function(x, p) { return x.toPrecision(p); },\n \"o\": function(x) { return Math.round(x).toString(8); },\n \"p\": function(x, p) { return formatRounded(x * 100, p); },\n \"r\": formatRounded,\n \"s\": formatPrefixAuto,\n \"X\": function(x) { return Math.round(x).toString(16).toUpperCase(); },\n \"x\": function(x) { return Math.round(x).toString(16); }\n};\n", + "export default function(x) {\n return x;\n}\n", + "import exponent from \"./exponent\";\nimport formatGroup from \"./formatGroup\";\nimport formatNumerals from \"./formatNumerals\";\nimport formatSpecifier from \"./formatSpecifier\";\nimport formatTrim from \"./formatTrim\";\nimport formatTypes from \"./formatTypes\";\nimport {prefixExponent} from \"./formatPrefixAuto\";\nimport identity from \"./identity\";\n\nvar prefixes = [\"y\",\"z\",\"a\",\"f\",\"p\",\"n\",\"µ\",\"m\",\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\",\"Y\"];\n\nexport default function(locale) {\n var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,\n currency = locale.currency,\n decimal = locale.decimal,\n numerals = locale.numerals ? formatNumerals(locale.numerals) : identity,\n percent = locale.percent || \"%\";\n\n function newFormat(specifier) {\n specifier = formatSpecifier(specifier);\n\n var fill = specifier.fill,\n align = specifier.align,\n sign = specifier.sign,\n symbol = specifier.symbol,\n zero = specifier.zero,\n width = specifier.width,\n comma = specifier.comma,\n precision = specifier.precision,\n trim = specifier.trim,\n type = specifier.type;\n\n // The \"n\" type is an alias for \",g\".\n if (type === \"n\") comma = true, type = \"g\";\n\n // The \"\" type, and any invalid type, is an alias for \".12~g\".\n else if (!formatTypes[type]) precision == null && (precision = 12), trim = true, type = \"g\";\n\n // If zero fill is specified, padding goes after sign and before digits.\n if (zero || (fill === \"0\" && align === \"=\")) zero = true, fill = \"0\", align = \"=\";\n\n // Compute the prefix and suffix.\n // For SI-prefix, the suffix is lazily computed.\n var prefix = symbol === \"$\" ? currency[0] : symbol === \"#\" && /[boxX]/.test(type) ? \"0\" + type.toLowerCase() : \"\",\n suffix = symbol === \"$\" ? currency[1] : /[%p]/.test(type) ? percent : \"\";\n\n // What format function should we use?\n // Is this an integer type?\n // Can this type generate exponential notation?\n var formatType = formatTypes[type],\n maybeSuffix = /[defgprs%]/.test(type);\n\n // Set the default precision if not specified,\n // or clamp the specified precision to the supported range.\n // For significant precision, it must be in [1, 21].\n // For fixed precision, it must be in [0, 20].\n precision = precision == null ? 6\n : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))\n : Math.max(0, Math.min(20, precision));\n\n function format(value) {\n var valuePrefix = prefix,\n valueSuffix = suffix,\n i, n, c;\n\n if (type === \"c\") {\n valueSuffix = formatType(value) + valueSuffix;\n value = \"\";\n } else {\n value = +value;\n\n // Perform the initial formatting.\n var valueNegative = value < 0;\n value = formatType(Math.abs(value), precision);\n\n // Trim insignificant zeros.\n if (trim) value = formatTrim(value);\n\n // If a negative value rounds to zero during formatting, treat as positive.\n if (valueNegative && +value === 0) valueNegative = false;\n\n // Compute the prefix and suffix.\n valuePrefix = (valueNegative ? (sign === \"(\" ? sign : \"-\") : sign === \"-\" || sign === \"(\" ? \"\" : sign) + valuePrefix;\n valueSuffix = (type === \"s\" ? prefixes[8 + prefixExponent / 3] : \"\") + valueSuffix + (valueNegative && sign === \"(\" ? \")\" : \"\");\n\n // Break the formatted value into the integer “value” part that can be\n // grouped, and fractional or exponential “suffix” part that is not.\n if (maybeSuffix) {\n i = -1, n = value.length;\n while (++i < n) {\n if (c = value.charCodeAt(i), 48 > c || c > 57) {\n valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;\n value = value.slice(0, i);\n break;\n }\n }\n }\n }\n\n // If the fill character is not \"0\", grouping is applied before padding.\n if (comma && !zero) value = group(value, Infinity);\n\n // Compute the padding.\n var length = valuePrefix.length + value.length + valueSuffix.length,\n padding = length < width ? new Array(width - length + 1).join(fill) : \"\";\n\n // If the fill character is \"0\", grouping is applied after padding.\n if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = \"\";\n\n // Reconstruct the final output based on the desired alignment.\n switch (align) {\n case \"<\": value = valuePrefix + value + valueSuffix + padding; break;\n case \"=\": value = valuePrefix + padding + value + valueSuffix; break;\n case \"^\": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;\n default: value = padding + valuePrefix + value + valueSuffix; break;\n }\n\n return numerals(value);\n }\n\n format.toString = function() {\n return specifier + \"\";\n };\n\n return format;\n }\n\n function formatPrefix(specifier, value) {\n var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = \"f\", specifier)),\n e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,\n k = Math.pow(10, -e),\n prefix = prefixes[8 + e / 3];\n return function(value) {\n return f(k * value) + prefix;\n };\n }\n\n return {\n format: newFormat,\n formatPrefix: formatPrefix\n };\n}\n", + "export default function(grouping, thousands) {\n return function(value, width) {\n var i = value.length,\n t = [],\n j = 0,\n g = grouping[0],\n length = 0;\n\n while (i > 0 && g > 0) {\n if (length + g + 1 > width) g = Math.max(1, width - length);\n t.push(value.substring(i -= g, i + g));\n if ((length += g + 1) > width) break;\n g = grouping[j = (j + 1) % grouping.length];\n }\n\n return t.reverse().join(thousands);\n };\n}\n", + "export default function(numerals) {\n return function(value) {\n return value.replace(/[0-9]/g, function(i) {\n return numerals[+i];\n });\n };\n}\n", + "import exponent from \"./exponent\";\n\nexport default function(step) {\n return Math.max(0, -exponent(Math.abs(step)));\n}\n", + "import {tickStep} from \"d3-array\";\nimport {format, formatPrefix, formatSpecifier, precisionFixed, precisionPrefix, precisionRound} from \"d3-format\";\n\nexport default function(domain, count, specifier) {\n var start = domain[0],\n stop = domain[domain.length - 1],\n step = tickStep(start, stop, count == null ? 10 : count),\n precision;\n specifier = formatSpecifier(specifier == null ? \",f\" : specifier);\n switch (specifier.type) {\n case \"s\": {\n var value = Math.max(Math.abs(start), Math.abs(stop));\n if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;\n return formatPrefix(specifier, value);\n }\n case \"\":\n case \"e\":\n case \"g\":\n case \"p\":\n case \"r\": {\n if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === \"e\");\n break;\n }\n case \"f\":\n case \"%\": {\n if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === \"%\") * 2;\n break;\n }\n }\n return format(specifier);\n}\n", + "import exponent from \"./exponent\";\n\nexport default function(step, value) {\n return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));\n}\n", + "import exponent from \"./exponent\";\n\nexport default function(step, max) {\n step = Math.abs(step), max = Math.abs(max) - step;\n return Math.max(0, exponent(max) - exponent(step)) + 1;\n}\n", + "import {ticks, tickIncrement} from \"d3-array\";\nimport {interpolateNumber as reinterpolate} from \"d3-interpolate\";\nimport {default as continuous, copy, deinterpolateLinear as deinterpolate} from \"./continuous\";\nimport tickFormat from \"./tickFormat\";\n\nexport function linearish(scale) {\n var domain = scale.domain;\n\n scale.ticks = function(count) {\n var d = domain();\n return ticks(d[0], d[d.length - 1], count == null ? 10 : count);\n };\n\n scale.tickFormat = function(count, specifier) {\n return tickFormat(domain(), count, specifier);\n };\n\n scale.nice = function(count) {\n if (count == null) count = 10;\n\n var d = domain(),\n i0 = 0,\n i1 = d.length - 1,\n start = d[i0],\n stop = d[i1],\n step;\n\n if (stop < start) {\n step = start, start = stop, stop = step;\n step = i0, i0 = i1, i1 = step;\n }\n\n step = tickIncrement(start, stop, count);\n\n if (step > 0) {\n start = Math.floor(start / step) * step;\n stop = Math.ceil(stop / step) * step;\n step = tickIncrement(start, stop, count);\n } else if (step < 0) {\n start = Math.ceil(start * step) / step;\n stop = Math.floor(stop * step) / step;\n step = tickIncrement(start, stop, count);\n }\n\n if (step > 0) {\n d[i0] = Math.floor(start / step) * step;\n d[i1] = Math.ceil(stop / step) * step;\n domain(d);\n } else if (step < 0) {\n d[i0] = Math.ceil(start * step) / step;\n d[i1] = Math.floor(stop * step) / step;\n domain(d);\n }\n\n return scale;\n };\n\n return scale;\n}\n\nexport default function linear() {\n var scale = continuous(deinterpolate, reinterpolate);\n\n scale.copy = function() {\n return copy(scale, linear());\n };\n\n return linearish(scale);\n}\n", + "import {map} from \"./array\";\nimport {linearish} from \"./linear\";\nimport number from \"./number\";\n\nexport default function identity() {\n var domain = [0, 1];\n\n function scale(x) {\n return +x;\n }\n\n scale.invert = scale;\n\n scale.domain = scale.range = function(_) {\n return arguments.length ? (domain = map.call(_, number), scale) : domain.slice();\n };\n\n scale.copy = function() {\n return identity().domain(domain);\n };\n\n return linearish(scale);\n}\n", + "export default function(domain, interval) {\n domain = domain.slice();\n\n var i0 = 0,\n i1 = domain.length - 1,\n x0 = domain[i0],\n x1 = domain[i1],\n t;\n\n if (x1 < x0) {\n t = i0, i0 = i1, i1 = t;\n t = x0, x0 = x1, x1 = t;\n }\n\n domain[i0] = interval.floor(x0);\n domain[i1] = interval.ceil(x1);\n return domain;\n}\n", + "import {ticks} from \"d3-array\";\nimport {format} from \"d3-format\";\nimport constant from \"./constant\";\nimport nice from \"./nice\";\nimport {default as continuous, copy} from \"./continuous\";\n\nfunction deinterpolate(a, b) {\n return (b = Math.log(b / a))\n ? function(x) { return Math.log(x / a) / b; }\n : constant(b);\n}\n\nfunction reinterpolate(a, b) {\n return a < 0\n ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }\n : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };\n}\n\nfunction pow10(x) {\n return isFinite(x) ? +(\"1e\" + x) : x < 0 ? 0 : x;\n}\n\nfunction powp(base) {\n return base === 10 ? pow10\n : base === Math.E ? Math.exp\n : function(x) { return Math.pow(base, x); };\n}\n\nfunction logp(base) {\n return base === Math.E ? Math.log\n : base === 10 && Math.log10\n || base === 2 && Math.log2\n || (base = Math.log(base), function(x) { return Math.log(x) / base; });\n}\n\nfunction reflect(f) {\n return function(x) {\n return -f(-x);\n };\n}\n\nexport default function log() {\n var scale = continuous(deinterpolate, reinterpolate).domain([1, 10]),\n domain = scale.domain,\n base = 10,\n logs = logp(10),\n pows = powp(10);\n\n function rescale() {\n logs = logp(base), pows = powp(base);\n if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);\n return scale;\n }\n\n scale.base = function(_) {\n return arguments.length ? (base = +_, rescale()) : base;\n };\n\n scale.domain = function(_) {\n return arguments.length ? (domain(_), rescale()) : domain();\n };\n\n scale.ticks = function(count) {\n var d = domain(),\n u = d[0],\n v = d[d.length - 1],\n r;\n\n if (r = v < u) i = u, u = v, v = i;\n\n var i = logs(u),\n j = logs(v),\n p,\n k,\n t,\n n = count == null ? 10 : +count,\n z = [];\n\n if (!(base % 1) && j - i < n) {\n i = Math.round(i) - 1, j = Math.round(j) + 1;\n if (u > 0) for (; i < j; ++i) {\n for (k = 1, p = pows(i); k < base; ++k) {\n t = p * k;\n if (t < u) continue;\n if (t > v) break;\n z.push(t);\n }\n } else for (; i < j; ++i) {\n for (k = base - 1, p = pows(i); k >= 1; --k) {\n t = p * k;\n if (t < u) continue;\n if (t > v) break;\n z.push(t);\n }\n }\n } else {\n z = ticks(i, j, Math.min(j - i, n)).map(pows);\n }\n\n return r ? z.reverse() : z;\n };\n\n scale.tickFormat = function(count, specifier) {\n if (specifier == null) specifier = base === 10 ? \".0e\" : \",\";\n if (typeof specifier !== \"function\") specifier = format(specifier);\n if (count === Infinity) return specifier;\n if (count == null) count = 10;\n var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?\n return function(d) {\n var i = d / pows(Math.round(logs(d)));\n if (i * base < base - 0.5) i *= base;\n return i <= k ? specifier(d) : \"\";\n };\n };\n\n scale.nice = function() {\n return domain(nice(domain(), {\n floor: function(x) { return pows(Math.floor(logs(x))); },\n ceil: function(x) { return pows(Math.ceil(logs(x))); }\n }));\n };\n\n scale.copy = function() {\n return copy(scale, log().base(base));\n };\n\n return scale;\n}\n", + "import constant from \"./constant\";\nimport {linearish} from \"./linear\";\nimport {default as continuous, copy} from \"./continuous\";\n\nfunction raise(x, exponent) {\n return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);\n}\n\nexport default function pow() {\n var exponent = 1,\n scale = continuous(deinterpolate, reinterpolate),\n domain = scale.domain;\n\n function deinterpolate(a, b) {\n return (b = raise(b, exponent) - (a = raise(a, exponent)))\n ? function(x) { return (raise(x, exponent) - a) / b; }\n : constant(b);\n }\n\n function reinterpolate(a, b) {\n b = raise(b, exponent) - (a = raise(a, exponent));\n return function(t) { return raise(a + b * t, 1 / exponent); };\n }\n\n scale.exponent = function(_) {\n return arguments.length ? (exponent = +_, domain(domain())) : exponent;\n };\n\n scale.copy = function() {\n return copy(scale, pow().exponent(exponent));\n };\n\n return linearish(scale);\n}\n\nexport function sqrt() {\n return pow().exponent(0.5);\n}\n", + "import {ascending, bisect, quantile as threshold} from \"d3-array\";\nimport {slice} from \"./array\";\n\nexport default function quantile() {\n var domain = [],\n range = [],\n thresholds = [];\n\n function rescale() {\n var i = 0, n = Math.max(1, range.length);\n thresholds = new Array(n - 1);\n while (++i < n) thresholds[i - 1] = threshold(domain, i / n);\n return scale;\n }\n\n function scale(x) {\n if (!isNaN(x = +x)) return range[bisect(thresholds, x)];\n }\n\n scale.invertExtent = function(y) {\n var i = range.indexOf(y);\n return i < 0 ? [NaN, NaN] : [\n i > 0 ? thresholds[i - 1] : domain[0],\n i < thresholds.length ? thresholds[i] : domain[domain.length - 1]\n ];\n };\n\n scale.domain = function(_) {\n if (!arguments.length) return domain.slice();\n domain = [];\n for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);\n domain.sort(ascending);\n return rescale();\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = slice.call(_), rescale()) : range.slice();\n };\n\n scale.quantiles = function() {\n return thresholds.slice();\n };\n\n scale.copy = function() {\n return quantile()\n .domain(domain)\n .range(range);\n };\n\n return scale;\n}\n", + "import {bisect} from \"d3-array\";\nimport {slice} from \"./array\";\nimport {linearish} from \"./linear\";\n\nexport default function quantize() {\n var x0 = 0,\n x1 = 1,\n n = 1,\n domain = [0.5],\n range = [0, 1];\n\n function scale(x) {\n if (x <= x) return range[bisect(domain, x, 0, n)];\n }\n\n function rescale() {\n var i = -1;\n domain = new Array(n);\n while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);\n return scale;\n }\n\n scale.domain = function(_) {\n return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];\n };\n\n scale.range = function(_) {\n return arguments.length ? (n = (range = slice.call(_)).length - 1, rescale()) : range.slice();\n };\n\n scale.invertExtent = function(y) {\n var i = range.indexOf(y);\n return i < 0 ? [NaN, NaN]\n : i < 1 ? [x0, domain[0]]\n : i >= n ? [domain[n - 1], x1]\n : [domain[i - 1], domain[i]];\n };\n\n scale.copy = function() {\n return quantize()\n .domain([x0, x1])\n .range(range);\n };\n\n return linearish(scale);\n}\n", + "import {bisect} from \"d3-array\";\nimport {slice} from \"./array\";\n\nexport default function threshold() {\n var domain = [0.5],\n range = [0, 1],\n n = 1;\n\n function scale(x) {\n if (x <= x) return range[bisect(domain, x, 0, n)];\n }\n\n scale.domain = function(_) {\n return arguments.length ? (domain = slice.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = slice.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();\n };\n\n scale.invertExtent = function(y) {\n var i = range.indexOf(y);\n return [domain[i - 1], domain[i]];\n };\n\n scale.copy = function() {\n return threshold()\n .domain(domain)\n .range(range);\n };\n\n return scale;\n}\n", + "var t0 = new Date,\n t1 = new Date;\n\nexport default function newInterval(floori, offseti, count, field) {\n\n function interval(date) {\n return floori(date = new Date(+date)), date;\n }\n\n interval.floor = interval;\n\n interval.ceil = function(date) {\n return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;\n };\n\n interval.round = function(date) {\n var d0 = interval(date),\n d1 = interval.ceil(date);\n return date - d0 < d1 - date ? d0 : d1;\n };\n\n interval.offset = function(date, step) {\n return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;\n };\n\n interval.range = function(start, stop, step) {\n var range = [], previous;\n start = interval.ceil(start);\n step = step == null ? 1 : Math.floor(step);\n if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date\n do range.push(previous = new Date(+start)), offseti(start, step), floori(start);\n while (previous < start && start < stop);\n return range;\n };\n\n interval.filter = function(test) {\n return newInterval(function(date) {\n if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);\n }, function(date, step) {\n if (date >= date) {\n if (step < 0) while (++step <= 0) {\n while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty\n } else while (--step >= 0) {\n while (offseti(date, +1), !test(date)) {} // eslint-disable-line no-empty\n }\n }\n });\n };\n\n if (count) {\n interval.count = function(start, end) {\n t0.setTime(+start), t1.setTime(+end);\n floori(t0), floori(t1);\n return Math.floor(count(t0, t1));\n };\n\n interval.every = function(step) {\n step = Math.floor(step);\n return !isFinite(step) || !(step > 0) ? null\n : !(step > 1) ? interval\n : interval.filter(field\n ? function(d) { return field(d) % step === 0; }\n : function(d) { return interval.count(0, d) % step === 0; });\n };\n }\n\n return interval;\n}\n", + "import interval from \"./interval\";\n\nvar millisecond = interval(function() {\n // noop\n}, function(date, step) {\n date.setTime(+date + step);\n}, function(start, end) {\n return end - start;\n});\n\n// An optimized implementation for this simple case.\nmillisecond.every = function(k) {\n k = Math.floor(k);\n if (!isFinite(k) || !(k > 0)) return null;\n if (!(k > 1)) return millisecond;\n return interval(function(date) {\n date.setTime(Math.floor(date / k) * k);\n }, function(date, step) {\n date.setTime(+date + step * k);\n }, function(start, end) {\n return (end - start) / k;\n });\n};\n\nexport default millisecond;\nexport var milliseconds = millisecond.range;\n", + "export var durationSecond = 1e3;\nexport var durationMinute = 6e4;\nexport var durationHour = 36e5;\nexport var durationDay = 864e5;\nexport var durationWeek = 6048e5;\n", + "import interval from \"./interval\";\nimport {durationSecond} from \"./duration\";\n\nvar second = interval(function(date) {\n date.setTime(date - date.getMilliseconds());\n}, function(date, step) {\n date.setTime(+date + step * durationSecond);\n}, function(start, end) {\n return (end - start) / durationSecond;\n}, function(date) {\n return date.getUTCSeconds();\n});\n\nexport default second;\nexport var seconds = second.range;\n", + "import interval from \"./interval\";\nimport {durationMinute, durationSecond} from \"./duration\";\n\nvar minute = interval(function(date) {\n date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond);\n}, function(date, step) {\n date.setTime(+date + step * durationMinute);\n}, function(start, end) {\n return (end - start) / durationMinute;\n}, function(date) {\n return date.getMinutes();\n});\n\nexport default minute;\nexport var minutes = minute.range;\n", + "import interval from \"./interval\";\nimport {durationHour, durationMinute, durationSecond} from \"./duration\";\n\nvar hour = interval(function(date) {\n date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute);\n}, function(date, step) {\n date.setTime(+date + step * durationHour);\n}, function(start, end) {\n return (end - start) / durationHour;\n}, function(date) {\n return date.getHours();\n});\n\nexport default hour;\nexport var hours = hour.range;\n", + "import interval from \"./interval\";\nimport {durationDay, durationMinute} from \"./duration\";\n\nvar day = interval(function(date) {\n date.setHours(0, 0, 0, 0);\n}, function(date, step) {\n date.setDate(date.getDate() + step);\n}, function(start, end) {\n return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay;\n}, function(date) {\n return date.getDate() - 1;\n});\n\nexport default day;\nexport var days = day.range;\n", + "import interval from \"./interval\";\nimport {durationMinute, durationWeek} from \"./duration\";\n\nfunction weekday(i) {\n return interval(function(date) {\n date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);\n date.setHours(0, 0, 0, 0);\n }, function(date, step) {\n date.setDate(date.getDate() + step * 7);\n }, function(start, end) {\n return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;\n });\n}\n\nexport var sunday = weekday(0);\nexport var monday = weekday(1);\nexport var tuesday = weekday(2);\nexport var wednesday = weekday(3);\nexport var thursday = weekday(4);\nexport var friday = weekday(5);\nexport var saturday = weekday(6);\n\nexport var sundays = sunday.range;\nexport var mondays = monday.range;\nexport var tuesdays = tuesday.range;\nexport var wednesdays = wednesday.range;\nexport var thursdays = thursday.range;\nexport var fridays = friday.range;\nexport var saturdays = saturday.range;\n", + "import interval from \"./interval\";\n\nvar month = interval(function(date) {\n date.setDate(1);\n date.setHours(0, 0, 0, 0);\n}, function(date, step) {\n date.setMonth(date.getMonth() + step);\n}, function(start, end) {\n return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;\n}, function(date) {\n return date.getMonth();\n});\n\nexport default month;\nexport var months = month.range;\n", + "import interval from \"./interval\";\n\nvar year = interval(function(date) {\n date.setMonth(0, 1);\n date.setHours(0, 0, 0, 0);\n}, function(date, step) {\n date.setFullYear(date.getFullYear() + step);\n}, function(start, end) {\n return end.getFullYear() - start.getFullYear();\n}, function(date) {\n return date.getFullYear();\n});\n\n// An optimized implementation for this simple case.\nyear.every = function(k) {\n return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : interval(function(date) {\n date.setFullYear(Math.floor(date.getFullYear() / k) * k);\n date.setMonth(0, 1);\n date.setHours(0, 0, 0, 0);\n }, function(date, step) {\n date.setFullYear(date.getFullYear() + step * k);\n });\n};\n\nexport default year;\nexport var years = year.range;\n", + "import interval from \"./interval\";\nimport {durationMinute} from \"./duration\";\n\nvar utcMinute = interval(function(date) {\n date.setUTCSeconds(0, 0);\n}, function(date, step) {\n date.setTime(+date + step * durationMinute);\n}, function(start, end) {\n return (end - start) / durationMinute;\n}, function(date) {\n return date.getUTCMinutes();\n});\n\nexport default utcMinute;\nexport var utcMinutes = utcMinute.range;\n", + "import interval from \"./interval\";\nimport {durationHour} from \"./duration\";\n\nvar utcHour = interval(function(date) {\n date.setUTCMinutes(0, 0, 0);\n}, function(date, step) {\n date.setTime(+date + step * durationHour);\n}, function(start, end) {\n return (end - start) / durationHour;\n}, function(date) {\n return date.getUTCHours();\n});\n\nexport default utcHour;\nexport var utcHours = utcHour.range;\n", + "import interval from \"./interval\";\nimport {durationDay} from \"./duration\";\n\nvar utcDay = interval(function(date) {\n date.setUTCHours(0, 0, 0, 0);\n}, function(date, step) {\n date.setUTCDate(date.getUTCDate() + step);\n}, function(start, end) {\n return (end - start) / durationDay;\n}, function(date) {\n return date.getUTCDate() - 1;\n});\n\nexport default utcDay;\nexport var utcDays = utcDay.range;\n", + "import interval from \"./interval\";\nimport {durationWeek} from \"./duration\";\n\nfunction utcWeekday(i) {\n return interval(function(date) {\n date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);\n date.setUTCHours(0, 0, 0, 0);\n }, function(date, step) {\n date.setUTCDate(date.getUTCDate() + step * 7);\n }, function(start, end) {\n return (end - start) / durationWeek;\n });\n}\n\nexport var utcSunday = utcWeekday(0);\nexport var utcMonday = utcWeekday(1);\nexport var utcTuesday = utcWeekday(2);\nexport var utcWednesday = utcWeekday(3);\nexport var utcThursday = utcWeekday(4);\nexport var utcFriday = utcWeekday(5);\nexport var utcSaturday = utcWeekday(6);\n\nexport var utcSundays = utcSunday.range;\nexport var utcMondays = utcMonday.range;\nexport var utcTuesdays = utcTuesday.range;\nexport var utcWednesdays = utcWednesday.range;\nexport var utcThursdays = utcThursday.range;\nexport var utcFridays = utcFriday.range;\nexport var utcSaturdays = utcSaturday.range;\n", + "import interval from \"./interval\";\n\nvar utcMonth = interval(function(date) {\n date.setUTCDate(1);\n date.setUTCHours(0, 0, 0, 0);\n}, function(date, step) {\n date.setUTCMonth(date.getUTCMonth() + step);\n}, function(start, end) {\n return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;\n}, function(date) {\n return date.getUTCMonth();\n});\n\nexport default utcMonth;\nexport var utcMonths = utcMonth.range;\n", + "import interval from \"./interval\";\n\nvar utcYear = interval(function(date) {\n date.setUTCMonth(0, 1);\n date.setUTCHours(0, 0, 0, 0);\n}, function(date, step) {\n date.setUTCFullYear(date.getUTCFullYear() + step);\n}, function(start, end) {\n return end.getUTCFullYear() - start.getUTCFullYear();\n}, function(date) {\n return date.getUTCFullYear();\n});\n\n// An optimized implementation for this simple case.\nutcYear.every = function(k) {\n return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : interval(function(date) {\n date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);\n date.setUTCMonth(0, 1);\n date.setUTCHours(0, 0, 0, 0);\n }, function(date, step) {\n date.setUTCFullYear(date.getUTCFullYear() + step * k);\n });\n};\n\nexport default utcYear;\nexport var utcYears = utcYear.range;\n", + "import {\n timeDay,\n timeSunday,\n timeMonday,\n timeThursday,\n timeYear,\n utcDay,\n utcSunday,\n utcMonday,\n utcThursday,\n utcYear\n} from \"d3-time\";\n\nfunction localDate(d) {\n if (0 <= d.y && d.y < 100) {\n var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);\n date.setFullYear(d.y);\n return date;\n }\n return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);\n}\n\nfunction utcDate(d) {\n if (0 <= d.y && d.y < 100) {\n var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));\n date.setUTCFullYear(d.y);\n return date;\n }\n return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));\n}\n\nfunction newYear(y) {\n return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};\n}\n\nexport default function formatLocale(locale) {\n var locale_dateTime = locale.dateTime,\n locale_date = locale.date,\n locale_time = locale.time,\n locale_periods = locale.periods,\n locale_weekdays = locale.days,\n locale_shortWeekdays = locale.shortDays,\n locale_months = locale.months,\n locale_shortMonths = locale.shortMonths;\n\n var periodRe = formatRe(locale_periods),\n periodLookup = formatLookup(locale_periods),\n weekdayRe = formatRe(locale_weekdays),\n weekdayLookup = formatLookup(locale_weekdays),\n shortWeekdayRe = formatRe(locale_shortWeekdays),\n shortWeekdayLookup = formatLookup(locale_shortWeekdays),\n monthRe = formatRe(locale_months),\n monthLookup = formatLookup(locale_months),\n shortMonthRe = formatRe(locale_shortMonths),\n shortMonthLookup = formatLookup(locale_shortMonths);\n\n var formats = {\n \"a\": formatShortWeekday,\n \"A\": formatWeekday,\n \"b\": formatShortMonth,\n \"B\": formatMonth,\n \"c\": null,\n \"d\": formatDayOfMonth,\n \"e\": formatDayOfMonth,\n \"f\": formatMicroseconds,\n \"H\": formatHour24,\n \"I\": formatHour12,\n \"j\": formatDayOfYear,\n \"L\": formatMilliseconds,\n \"m\": formatMonthNumber,\n \"M\": formatMinutes,\n \"p\": formatPeriod,\n \"Q\": formatUnixTimestamp,\n \"s\": formatUnixTimestampSeconds,\n \"S\": formatSeconds,\n \"u\": formatWeekdayNumberMonday,\n \"U\": formatWeekNumberSunday,\n \"V\": formatWeekNumberISO,\n \"w\": formatWeekdayNumberSunday,\n \"W\": formatWeekNumberMonday,\n \"x\": null,\n \"X\": null,\n \"y\": formatYear,\n \"Y\": formatFullYear,\n \"Z\": formatZone,\n \"%\": formatLiteralPercent\n };\n\n var utcFormats = {\n \"a\": formatUTCShortWeekday,\n \"A\": formatUTCWeekday,\n \"b\": formatUTCShortMonth,\n \"B\": formatUTCMonth,\n \"c\": null,\n \"d\": formatUTCDayOfMonth,\n \"e\": formatUTCDayOfMonth,\n \"f\": formatUTCMicroseconds,\n \"H\": formatUTCHour24,\n \"I\": formatUTCHour12,\n \"j\": formatUTCDayOfYear,\n \"L\": formatUTCMilliseconds,\n \"m\": formatUTCMonthNumber,\n \"M\": formatUTCMinutes,\n \"p\": formatUTCPeriod,\n \"Q\": formatUnixTimestamp,\n \"s\": formatUnixTimestampSeconds,\n \"S\": formatUTCSeconds,\n \"u\": formatUTCWeekdayNumberMonday,\n \"U\": formatUTCWeekNumberSunday,\n \"V\": formatUTCWeekNumberISO,\n \"w\": formatUTCWeekdayNumberSunday,\n \"W\": formatUTCWeekNumberMonday,\n \"x\": null,\n \"X\": null,\n \"y\": formatUTCYear,\n \"Y\": formatUTCFullYear,\n \"Z\": formatUTCZone,\n \"%\": formatLiteralPercent\n };\n\n var parses = {\n \"a\": parseShortWeekday,\n \"A\": parseWeekday,\n \"b\": parseShortMonth,\n \"B\": parseMonth,\n \"c\": parseLocaleDateTime,\n \"d\": parseDayOfMonth,\n \"e\": parseDayOfMonth,\n \"f\": parseMicroseconds,\n \"H\": parseHour24,\n \"I\": parseHour24,\n \"j\": parseDayOfYear,\n \"L\": parseMilliseconds,\n \"m\": parseMonthNumber,\n \"M\": parseMinutes,\n \"p\": parsePeriod,\n \"Q\": parseUnixTimestamp,\n \"s\": parseUnixTimestampSeconds,\n \"S\": parseSeconds,\n \"u\": parseWeekdayNumberMonday,\n \"U\": parseWeekNumberSunday,\n \"V\": parseWeekNumberISO,\n \"w\": parseWeekdayNumberSunday,\n \"W\": parseWeekNumberMonday,\n \"x\": parseLocaleDate,\n \"X\": parseLocaleTime,\n \"y\": parseYear,\n \"Y\": parseFullYear,\n \"Z\": parseZone,\n \"%\": parseLiteralPercent\n };\n\n // These recursive directive definitions must be deferred.\n formats.x = newFormat(locale_date, formats);\n formats.X = newFormat(locale_time, formats);\n formats.c = newFormat(locale_dateTime, formats);\n utcFormats.x = newFormat(locale_date, utcFormats);\n utcFormats.X = newFormat(locale_time, utcFormats);\n utcFormats.c = newFormat(locale_dateTime, utcFormats);\n\n function newFormat(specifier, formats) {\n return function(date) {\n var string = [],\n i = -1,\n j = 0,\n n = specifier.length,\n c,\n pad,\n format;\n\n if (!(date instanceof Date)) date = new Date(+date);\n\n while (++i < n) {\n if (specifier.charCodeAt(i) === 37) {\n string.push(specifier.slice(j, i));\n if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);\n else pad = c === \"e\" ? \" \" : \"0\";\n if (format = formats[c]) c = format(date, pad);\n string.push(c);\n j = i + 1;\n }\n }\n\n string.push(specifier.slice(j, i));\n return string.join(\"\");\n };\n }\n\n function newParse(specifier, newDate) {\n return function(string) {\n var d = newYear(1900),\n i = parseSpecifier(d, specifier, string += \"\", 0),\n week, day;\n if (i != string.length) return null;\n\n // If a UNIX timestamp is specified, return it.\n if (\"Q\" in d) return new Date(d.Q);\n\n // The am-pm flag is 0 for AM, and 1 for PM.\n if (\"p\" in d) d.H = d.H % 12 + d.p * 12;\n\n // Convert day-of-week and week-of-year to day-of-year.\n if (\"V\" in d) {\n if (d.V < 1 || d.V > 53) return null;\n if (!(\"w\" in d)) d.w = 1;\n if (\"Z\" in d) {\n week = utcDate(newYear(d.y)), day = week.getUTCDay();\n week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week);\n week = utcDay.offset(week, (d.V - 1) * 7);\n d.y = week.getUTCFullYear();\n d.m = week.getUTCMonth();\n d.d = week.getUTCDate() + (d.w + 6) % 7;\n } else {\n week = newDate(newYear(d.y)), day = week.getDay();\n week = day > 4 || day === 0 ? timeMonday.ceil(week) : timeMonday(week);\n week = timeDay.offset(week, (d.V - 1) * 7);\n d.y = week.getFullYear();\n d.m = week.getMonth();\n d.d = week.getDate() + (d.w + 6) % 7;\n }\n } else if (\"W\" in d || \"U\" in d) {\n if (!(\"w\" in d)) d.w = \"u\" in d ? d.u % 7 : \"W\" in d ? 1 : 0;\n day = \"Z\" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();\n d.m = 0;\n d.d = \"W\" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;\n }\n\n // If a time zone is specified, all fields are interpreted as UTC and then\n // offset according to the specified time zone.\n if (\"Z\" in d) {\n d.H += d.Z / 100 | 0;\n d.M += d.Z % 100;\n return utcDate(d);\n }\n\n // Otherwise, all fields are in local time.\n return newDate(d);\n };\n }\n\n function parseSpecifier(d, specifier, string, j) {\n var i = 0,\n n = specifier.length,\n m = string.length,\n c,\n parse;\n\n while (i < n) {\n if (j >= m) return -1;\n c = specifier.charCodeAt(i++);\n if (c === 37) {\n c = specifier.charAt(i++);\n parse = parses[c in pads ? specifier.charAt(i++) : c];\n if (!parse || ((j = parse(d, string, j)) < 0)) return -1;\n } else if (c != string.charCodeAt(j++)) {\n return -1;\n }\n }\n\n return j;\n }\n\n function parsePeriod(d, string, i) {\n var n = periodRe.exec(string.slice(i));\n return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;\n }\n\n function parseShortWeekday(d, string, i) {\n var n = shortWeekdayRe.exec(string.slice(i));\n return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;\n }\n\n function parseWeekday(d, string, i) {\n var n = weekdayRe.exec(string.slice(i));\n return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;\n }\n\n function parseShortMonth(d, string, i) {\n var n = shortMonthRe.exec(string.slice(i));\n return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;\n }\n\n function parseMonth(d, string, i) {\n var n = monthRe.exec(string.slice(i));\n return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;\n }\n\n function parseLocaleDateTime(d, string, i) {\n return parseSpecifier(d, locale_dateTime, string, i);\n }\n\n function parseLocaleDate(d, string, i) {\n return parseSpecifier(d, locale_date, string, i);\n }\n\n function parseLocaleTime(d, string, i) {\n return parseSpecifier(d, locale_time, string, i);\n }\n\n function formatShortWeekday(d) {\n return locale_shortWeekdays[d.getDay()];\n }\n\n function formatWeekday(d) {\n return locale_weekdays[d.getDay()];\n }\n\n function formatShortMonth(d) {\n return locale_shortMonths[d.getMonth()];\n }\n\n function formatMonth(d) {\n return locale_months[d.getMonth()];\n }\n\n function formatPeriod(d) {\n return locale_periods[+(d.getHours() >= 12)];\n }\n\n function formatUTCShortWeekday(d) {\n return locale_shortWeekdays[d.getUTCDay()];\n }\n\n function formatUTCWeekday(d) {\n return locale_weekdays[d.getUTCDay()];\n }\n\n function formatUTCShortMonth(d) {\n return locale_shortMonths[d.getUTCMonth()];\n }\n\n function formatUTCMonth(d) {\n return locale_months[d.getUTCMonth()];\n }\n\n function formatUTCPeriod(d) {\n return locale_periods[+(d.getUTCHours() >= 12)];\n }\n\n return {\n format: function(specifier) {\n var f = newFormat(specifier += \"\", formats);\n f.toString = function() { return specifier; };\n return f;\n },\n parse: function(specifier) {\n var p = newParse(specifier += \"\", localDate);\n p.toString = function() { return specifier; };\n return p;\n },\n utcFormat: function(specifier) {\n var f = newFormat(specifier += \"\", utcFormats);\n f.toString = function() { return specifier; };\n return f;\n },\n utcParse: function(specifier) {\n var p = newParse(specifier, utcDate);\n p.toString = function() { return specifier; };\n return p;\n }\n };\n}\n\nvar pads = {\"-\": \"\", \"_\": \" \", \"0\": \"0\"},\n numberRe = /^\\s*\\d+/, // note: ignores next directive\n percentRe = /^%/,\n requoteRe = /[\\\\^$*+?|[\\]().{}]/g;\n\nfunction pad(value, fill, width) {\n var sign = value < 0 ? \"-\" : \"\",\n string = (sign ? -value : value) + \"\",\n length = string.length;\n return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);\n}\n\nfunction requote(s) {\n return s.replace(requoteRe, \"\\\\$&\");\n}\n\nfunction formatRe(names) {\n return new RegExp(\"^(?:\" + names.map(requote).join(\"|\") + \")\", \"i\");\n}\n\nfunction formatLookup(names) {\n var map = {}, i = -1, n = names.length;\n while (++i < n) map[names[i].toLowerCase()] = i;\n return map;\n}\n\nfunction parseWeekdayNumberSunday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.w = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekdayNumberMonday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.u = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberSunday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.U = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberISO(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.V = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberMonday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.W = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseFullYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 4));\n return n ? (d.y = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;\n}\n\nfunction parseZone(d, string, i) {\n var n = /^(Z)|([+-]\\d\\d)(?::?(\\d\\d))?/.exec(string.slice(i, i + 6));\n return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || \"00\")), i + n[0].length) : -1;\n}\n\nfunction parseMonthNumber(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.m = n[0] - 1, i + n[0].length) : -1;\n}\n\nfunction parseDayOfMonth(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.d = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseDayOfYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 3));\n return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseHour24(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.H = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMinutes(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.M = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseSeconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.S = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMilliseconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 3));\n return n ? (d.L = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMicroseconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 6));\n return n ? (d.L = Math.floor(n[0] / 1000), i + n[0].length) : -1;\n}\n\nfunction parseLiteralPercent(d, string, i) {\n var n = percentRe.exec(string.slice(i, i + 1));\n return n ? i + n[0].length : -1;\n}\n\nfunction parseUnixTimestamp(d, string, i) {\n var n = numberRe.exec(string.slice(i));\n return n ? (d.Q = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseUnixTimestampSeconds(d, string, i) {\n var n = numberRe.exec(string.slice(i));\n return n ? (d.Q = (+n[0]) * 1000, i + n[0].length) : -1;\n}\n\nfunction formatDayOfMonth(d, p) {\n return pad(d.getDate(), p, 2);\n}\n\nfunction formatHour24(d, p) {\n return pad(d.getHours(), p, 2);\n}\n\nfunction formatHour12(d, p) {\n return pad(d.getHours() % 12 || 12, p, 2);\n}\n\nfunction formatDayOfYear(d, p) {\n return pad(1 + timeDay.count(timeYear(d), d), p, 3);\n}\n\nfunction formatMilliseconds(d, p) {\n return pad(d.getMilliseconds(), p, 3);\n}\n\nfunction formatMicroseconds(d, p) {\n return formatMilliseconds(d, p) + \"000\";\n}\n\nfunction formatMonthNumber(d, p) {\n return pad(d.getMonth() + 1, p, 2);\n}\n\nfunction formatMinutes(d, p) {\n return pad(d.getMinutes(), p, 2);\n}\n\nfunction formatSeconds(d, p) {\n return pad(d.getSeconds(), p, 2);\n}\n\nfunction formatWeekdayNumberMonday(d) {\n var day = d.getDay();\n return day === 0 ? 7 : day;\n}\n\nfunction formatWeekNumberSunday(d, p) {\n return pad(timeSunday.count(timeYear(d), d), p, 2);\n}\n\nfunction formatWeekNumberISO(d, p) {\n var day = d.getDay();\n d = (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);\n return pad(timeThursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2);\n}\n\nfunction formatWeekdayNumberSunday(d) {\n return d.getDay();\n}\n\nfunction formatWeekNumberMonday(d, p) {\n return pad(timeMonday.count(timeYear(d), d), p, 2);\n}\n\nfunction formatYear(d, p) {\n return pad(d.getFullYear() % 100, p, 2);\n}\n\nfunction formatFullYear(d, p) {\n return pad(d.getFullYear() % 10000, p, 4);\n}\n\nfunction formatZone(d) {\n var z = d.getTimezoneOffset();\n return (z > 0 ? \"-\" : (z *= -1, \"+\"))\n + pad(z / 60 | 0, \"0\", 2)\n + pad(z % 60, \"0\", 2);\n}\n\nfunction formatUTCDayOfMonth(d, p) {\n return pad(d.getUTCDate(), p, 2);\n}\n\nfunction formatUTCHour24(d, p) {\n return pad(d.getUTCHours(), p, 2);\n}\n\nfunction formatUTCHour12(d, p) {\n return pad(d.getUTCHours() % 12 || 12, p, 2);\n}\n\nfunction formatUTCDayOfYear(d, p) {\n return pad(1 + utcDay.count(utcYear(d), d), p, 3);\n}\n\nfunction formatUTCMilliseconds(d, p) {\n return pad(d.getUTCMilliseconds(), p, 3);\n}\n\nfunction formatUTCMicroseconds(d, p) {\n return formatUTCMilliseconds(d, p) + \"000\";\n}\n\nfunction formatUTCMonthNumber(d, p) {\n return pad(d.getUTCMonth() + 1, p, 2);\n}\n\nfunction formatUTCMinutes(d, p) {\n return pad(d.getUTCMinutes(), p, 2);\n}\n\nfunction formatUTCSeconds(d, p) {\n return pad(d.getUTCSeconds(), p, 2);\n}\n\nfunction formatUTCWeekdayNumberMonday(d) {\n var dow = d.getUTCDay();\n return dow === 0 ? 7 : dow;\n}\n\nfunction formatUTCWeekNumberSunday(d, p) {\n return pad(utcSunday.count(utcYear(d), d), p, 2);\n}\n\nfunction formatUTCWeekNumberISO(d, p) {\n var day = d.getUTCDay();\n d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);\n return pad(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2);\n}\n\nfunction formatUTCWeekdayNumberSunday(d) {\n return d.getUTCDay();\n}\n\nfunction formatUTCWeekNumberMonday(d, p) {\n return pad(utcMonday.count(utcYear(d), d), p, 2);\n}\n\nfunction formatUTCYear(d, p) {\n return pad(d.getUTCFullYear() % 100, p, 2);\n}\n\nfunction formatUTCFullYear(d, p) {\n return pad(d.getUTCFullYear() % 10000, p, 4);\n}\n\nfunction formatUTCZone() {\n return \"+0000\";\n}\n\nfunction formatLiteralPercent() {\n return \"%\";\n}\n\nfunction formatUnixTimestamp(d) {\n return +d;\n}\n\nfunction formatUnixTimestampSeconds(d) {\n return Math.floor(+d / 1000);\n}\n", + "import formatLocale from \"./locale\";\n\nvar locale;\nexport var timeFormat;\nexport var timeParse;\nexport var utcFormat;\nexport var utcParse;\n\ndefaultLocale({\n dateTime: \"%x, %X\",\n date: \"%-m/%-d/%Y\",\n time: \"%-I:%M:%S %p\",\n periods: [\"AM\", \"PM\"],\n days: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"],\n shortDays: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n months: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"],\n shortMonths: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n});\n\nexport default function defaultLocale(definition) {\n locale = formatLocale(definition);\n timeFormat = locale.format;\n timeParse = locale.parse;\n utcFormat = locale.utcFormat;\n utcParse = locale.utcParse;\n return locale;\n}\n", + "import {utcFormat} from \"./defaultLocale\";\n\nexport var isoSpecifier = \"%Y-%m-%dT%H:%M:%S.%LZ\";\n\nfunction formatIsoNative(date) {\n return date.toISOString();\n}\n\nvar formatIso = Date.prototype.toISOString\n ? formatIsoNative\n : utcFormat(isoSpecifier);\n\nexport default formatIso;\n", + "import {isoSpecifier} from \"./isoFormat\";\nimport {utcParse} from \"./defaultLocale\";\n\nfunction parseIsoNative(string) {\n var date = new Date(string);\n return isNaN(date) ? null : date;\n}\n\nvar parseIso = +new Date(\"2000-01-01T00:00:00.000Z\")\n ? parseIsoNative\n : utcParse(isoSpecifier);\n\nexport default parseIso;\n", + "import {bisector, tickStep} from \"d3-array\";\nimport {interpolateNumber as reinterpolate} from \"d3-interpolate\";\nimport {timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond} from \"d3-time\";\nimport {timeFormat} from \"d3-time-format\";\nimport {map} from \"./array\";\nimport {default as continuous, copy, deinterpolateLinear as deinterpolate} from \"./continuous\";\nimport nice from \"./nice\";\n\nvar durationSecond = 1000,\n durationMinute = durationSecond * 60,\n durationHour = durationMinute * 60,\n durationDay = durationHour * 24,\n durationWeek = durationDay * 7,\n durationMonth = durationDay * 30,\n durationYear = durationDay * 365;\n\nfunction date(t) {\n return new Date(t);\n}\n\nfunction number(t) {\n return t instanceof Date ? +t : +new Date(+t);\n}\n\nexport function calendar(year, month, week, day, hour, minute, second, millisecond, format) {\n var scale = continuous(deinterpolate, reinterpolate),\n invert = scale.invert,\n domain = scale.domain;\n\n var formatMillisecond = format(\".%L\"),\n formatSecond = format(\":%S\"),\n formatMinute = format(\"%I:%M\"),\n formatHour = format(\"%I %p\"),\n formatDay = format(\"%a %d\"),\n formatWeek = format(\"%b %d\"),\n formatMonth = format(\"%B\"),\n formatYear = format(\"%Y\");\n\n var tickIntervals = [\n [second, 1, durationSecond],\n [second, 5, 5 * durationSecond],\n [second, 15, 15 * durationSecond],\n [second, 30, 30 * durationSecond],\n [minute, 1, durationMinute],\n [minute, 5, 5 * durationMinute],\n [minute, 15, 15 * durationMinute],\n [minute, 30, 30 * durationMinute],\n [ hour, 1, durationHour ],\n [ hour, 3, 3 * durationHour ],\n [ hour, 6, 6 * durationHour ],\n [ hour, 12, 12 * durationHour ],\n [ day, 1, durationDay ],\n [ day, 2, 2 * durationDay ],\n [ week, 1, durationWeek ],\n [ month, 1, durationMonth ],\n [ month, 3, 3 * durationMonth ],\n [ year, 1, durationYear ]\n ];\n\n function tickFormat(date) {\n return (second(date) < date ? formatMillisecond\n : minute(date) < date ? formatSecond\n : hour(date) < date ? formatMinute\n : day(date) < date ? formatHour\n : month(date) < date ? (week(date) < date ? formatDay : formatWeek)\n : year(date) < date ? formatMonth\n : formatYear)(date);\n }\n\n function tickInterval(interval, start, stop, step) {\n if (interval == null) interval = 10;\n\n // If a desired tick count is specified, pick a reasonable tick interval\n // based on the extent of the domain and a rough estimate of tick size.\n // Otherwise, assume interval is already a time interval and use it.\n if (typeof interval === \"number\") {\n var target = Math.abs(stop - start) / interval,\n i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);\n if (i === tickIntervals.length) {\n step = tickStep(start / durationYear, stop / durationYear, interval);\n interval = year;\n } else if (i) {\n i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];\n step = i[1];\n interval = i[0];\n } else {\n step = Math.max(tickStep(start, stop, interval), 1);\n interval = millisecond;\n }\n }\n\n return step == null ? interval : interval.every(step);\n }\n\n scale.invert = function(y) {\n return new Date(invert(y));\n };\n\n scale.domain = function(_) {\n return arguments.length ? domain(map.call(_, number)) : domain().map(date);\n };\n\n scale.ticks = function(interval, step) {\n var d = domain(),\n t0 = d[0],\n t1 = d[d.length - 1],\n r = t1 < t0,\n t;\n if (r) t = t0, t0 = t1, t1 = t;\n t = tickInterval(interval, t0, t1, step);\n t = t ? t.range(t0, t1 + 1) : []; // inclusive stop\n return r ? t.reverse() : t;\n };\n\n scale.tickFormat = function(count, specifier) {\n return specifier == null ? tickFormat : format(specifier);\n };\n\n scale.nice = function(interval, step) {\n var d = domain();\n return (interval = tickInterval(interval, d[0], d[d.length - 1], step))\n ? domain(nice(d, interval))\n : scale;\n };\n\n scale.copy = function() {\n return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));\n };\n\n return scale;\n}\n\nexport default function() {\n return calendar(timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);\n}\n", + "import {calendar} from \"./time\";\nimport {utcFormat} from \"d3-time-format\";\nimport {utcYear, utcMonth, utcWeek, utcDay, utcHour, utcMinute, utcSecond, utcMillisecond} from \"d3-time\";\n\nexport default function() {\n return calendar(utcYear, utcMonth, utcWeek, utcDay, utcHour, utcMinute, utcSecond, utcMillisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);\n}\n", + "import {linearish} from \"./linear\";\n\nexport default function sequential(interpolator) {\n var x0 = 0,\n x1 = 1,\n k10 = 1,\n clamp = false;\n\n function scale(x) {\n var t = (x - x0) * k10;\n return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);\n }\n\n scale.domain = function(_) {\n return arguments.length ? (x0 = +_[0], x1 = +_[1], k10 = x0 === x1 ? 0 : 1 / (x1 - x0), scale) : [x0, x1];\n };\n\n scale.clamp = function(_) {\n return arguments.length ? (clamp = !!_, scale) : clamp;\n };\n\n scale.interpolator = function(_) {\n return arguments.length ? (interpolator = _, scale) : interpolator;\n };\n\n scale.copy = function() {\n return sequential(interpolator).domain([x0, x1]).clamp(clamp);\n };\n\n return linearish(scale);\n}\n", + "import {linearish} from \"./linear\";\n\nexport default function diverging(interpolator) {\n var x0 = 0,\n x1 = 0.5,\n x2 = 1,\n k10 = 1,\n k21 = 1,\n clamp = false;\n\n function scale(x) {\n var t = 0.5 + ((x = +x) - x1) * (x < x1 ? k10 : k21);\n return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);\n }\n\n scale.domain = function(_) {\n return arguments.length ? (x0 = +_[0], x1 = +_[1], x2 = +_[2], k10 = x0 === x1 ? 0 : 0.5 / (x1 - x0), k21 = x1 === x2 ? 0 : 0.5 / (x2 - x1), scale) : [x0, x1, x2];\n };\n\n scale.clamp = function(_) {\n return arguments.length ? (clamp = !!_, scale) : clamp;\n };\n\n scale.interpolator = function(_) {\n return arguments.length ? (interpolator = _, scale) : interpolator;\n };\n\n scale.copy = function() {\n return diverging(interpolator).domain([x0, x1, x2]).clamp(clamp);\n };\n\n return linearish(scale);\n}\n", + "export {\n default as scaleBand,\n point as scalePoint\n} from \"./band\";\n\nexport {\n default as scaleIdentity\n} from \"./identity\";\n\nexport {\n default as scaleLinear\n} from \"./linear\";\n\nexport {\n default as scaleLog\n} from \"./log\";\n\nexport {\n default as scaleOrdinal,\n implicit as scaleImplicit\n} from \"./ordinal\";\n\nexport {\n default as scalePow,\n sqrt as scaleSqrt\n} from \"./pow\";\n\nexport {\n default as scaleQuantile\n} from \"./quantile\";\n\nexport {\n default as scaleQuantize\n} from \"./quantize\";\n\nexport {\n default as scaleThreshold\n} from \"./threshold\";\n\nexport {\n default as scaleTime\n} from \"./time\";\n\nexport {\n default as scaleUtc\n} from \"./utcTime\";\n\nexport {\n default as scaleSequential\n} from \"./sequential\";\n\nexport {\n default as scaleDiverging\n} from \"./diverging\";\n", + "var pi = Math.PI,\n tau = 2 * pi,\n epsilon = 1e-6,\n tauEpsilon = tau - epsilon;\n\nfunction Path() {\n this._x0 = this._y0 = // start of current subpath\n this._x1 = this._y1 = null; // end of current subpath\n this._ = \"\";\n}\n\nfunction path() {\n return new Path;\n}\n\nPath.prototype = path.prototype = {\n constructor: Path,\n moveTo: function(x, y) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y);\n },\n closePath: function() {\n if (this._x1 !== null) {\n this._x1 = this._x0, this._y1 = this._y0;\n this._ += \"Z\";\n }\n },\n lineTo: function(x, y) {\n this._ += \"L\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n quadraticCurveTo: function(x1, y1, x, y) {\n this._ += \"Q\" + (+x1) + \",\" + (+y1) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) {\n this._ += \"C\" + (+x1) + \",\" + (+y1) + \",\" + (+x2) + \",\" + (+y2) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n arcTo: function(x1, y1, x2, y2, r) {\n x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;\n var x0 = this._x1,\n y0 = this._y1,\n x21 = x2 - x1,\n y21 = y2 - y1,\n x01 = x0 - x1,\n y01 = y0 - y1,\n l01_2 = x01 * x01 + y01 * y01;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x1,y1).\n if (this._x1 === null) {\n this._ += \"M\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.\n else if (!(l01_2 > epsilon));\n\n // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?\n // Equivalently, is (x1,y1) coincident with (x2,y2)?\n // Or, is the radius zero? Line to (x1,y1).\n else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {\n this._ += \"L\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Otherwise, draw an arc!\n else {\n var x20 = x2 - x0,\n y20 = y2 - y0,\n l21_2 = x21 * x21 + y21 * y21,\n l20_2 = x20 * x20 + y20 * y20,\n l21 = Math.sqrt(l21_2),\n l01 = Math.sqrt(l01_2),\n l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),\n t01 = l / l01,\n t21 = l / l21;\n\n // If the start tangent is not coincident with (x0,y0), line to.\n if (Math.abs(t01 - 1) > epsilon) {\n this._ += \"L\" + (x1 + t01 * x01) + \",\" + (y1 + t01 * y01);\n }\n\n this._ += \"A\" + r + \",\" + r + \",0,0,\" + (+(y01 * x20 > x01 * y20)) + \",\" + (this._x1 = x1 + t21 * x21) + \",\" + (this._y1 = y1 + t21 * y21);\n }\n },\n arc: function(x, y, r, a0, a1, ccw) {\n x = +x, y = +y, r = +r;\n var dx = r * Math.cos(a0),\n dy = r * Math.sin(a0),\n x0 = x + dx,\n y0 = y + dy,\n cw = 1 ^ ccw,\n da = ccw ? a0 - a1 : a1 - a0;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x0,y0).\n if (this._x1 === null) {\n this._ += \"M\" + x0 + \",\" + y0;\n }\n\n // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).\n else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {\n this._ += \"L\" + x0 + \",\" + y0;\n }\n\n // Is this arc empty? We’re done.\n if (!r) return;\n\n // Does the angle go the wrong way? Flip the direction.\n if (da < 0) da = da % tau + tau;\n\n // Is this a complete circle? Draw two arcs to complete the circle.\n if (da > tauEpsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (x - dx) + \",\" + (y - dy) + \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (this._x1 = x0) + \",\" + (this._y1 = y0);\n }\n\n // Is this arc non-empty? Draw an arc!\n else if (da > epsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,\" + (+(da >= pi)) + \",\" + cw + \",\" + (this._x1 = x + r * Math.cos(a1)) + \",\" + (this._y1 = y + r * Math.sin(a1));\n }\n },\n rect: function(x, y, w, h) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y) + \"h\" + (+w) + \"v\" + (+h) + \"h\" + (-w) + \"Z\";\n },\n toString: function() {\n return this._;\n }\n};\n\nexport default path;\n", + "export default function(x) {\n return function constant() {\n return x;\n };\n}\n", + "export var abs = Math.abs;\nexport var atan2 = Math.atan2;\nexport var cos = Math.cos;\nexport var max = Math.max;\nexport var min = Math.min;\nexport var sin = Math.sin;\nexport var sqrt = Math.sqrt;\n\nexport var epsilon = 1e-12;\nexport var pi = Math.PI;\nexport var halfPi = pi / 2;\nexport var tau = 2 * pi;\n\nexport function acos(x) {\n return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);\n}\n\nexport function asin(x) {\n return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);\n}\n", + "function Linear(context) {\n this._context = context;\n}\n\nLinear.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // proceed\n default: this._context.lineTo(x, y); break;\n }\n }\n};\n\nexport default function(context) {\n return new Linear(context);\n}\n", + "export function x(p) {\n return p[0];\n}\n\nexport function y(p) {\n return p[1];\n}\n", + "import {path} from \"d3-path\";\nimport constant from \"./constant\";\nimport curveLinear from \"./curve/linear\";\nimport {x as pointX, y as pointY} from \"./point\";\n\nexport default function() {\n var x = pointX,\n y = pointY,\n defined = constant(true),\n context = null,\n curve = curveLinear,\n output = null;\n\n function line(data) {\n var i,\n n = data.length,\n d,\n defined0 = false,\n buffer;\n\n if (context == null) output = curve(buffer = path());\n\n for (i = 0; i <= n; ++i) {\n if (!(i < n && defined(d = data[i], i, data)) === defined0) {\n if (defined0 = !defined0) output.lineStart();\n else output.lineEnd();\n }\n if (defined0) output.point(+x(d, i, data), +y(d, i, data));\n }\n\n if (buffer) return output = null, buffer + \"\" || null;\n }\n\n line.x = function(_) {\n return arguments.length ? (x = typeof _ === \"function\" ? _ : constant(+_), line) : x;\n };\n\n line.y = function(_) {\n return arguments.length ? (y = typeof _ === \"function\" ? _ : constant(+_), line) : y;\n };\n\n line.defined = function(_) {\n return arguments.length ? (defined = typeof _ === \"function\" ? _ : constant(!!_), line) : defined;\n };\n\n line.curve = function(_) {\n return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;\n };\n\n line.context = function(_) {\n return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;\n };\n\n return line;\n}\n", + "import {path} from \"d3-path\";\nimport constant from \"./constant\";\nimport curveLinear from \"./curve/linear\";\nimport line from \"./line\";\nimport {x as pointX, y as pointY} from \"./point\";\n\nexport default function() {\n var x0 = pointX,\n x1 = null,\n y0 = constant(0),\n y1 = pointY,\n defined = constant(true),\n context = null,\n curve = curveLinear,\n output = null;\n\n function area(data) {\n var i,\n j,\n k,\n n = data.length,\n d,\n defined0 = false,\n buffer,\n x0z = new Array(n),\n y0z = new Array(n);\n\n if (context == null) output = curve(buffer = path());\n\n for (i = 0; i <= n; ++i) {\n if (!(i < n && defined(d = data[i], i, data)) === defined0) {\n if (defined0 = !defined0) {\n j = i;\n output.areaStart();\n output.lineStart();\n } else {\n output.lineEnd();\n output.lineStart();\n for (k = i - 1; k >= j; --k) {\n output.point(x0z[k], y0z[k]);\n }\n output.lineEnd();\n output.areaEnd();\n }\n }\n if (defined0) {\n x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);\n output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);\n }\n }\n\n if (buffer) return output = null, buffer + \"\" || null;\n }\n\n function arealine() {\n return line().defined(defined).curve(curve).context(context);\n }\n\n area.x = function(_) {\n return arguments.length ? (x0 = typeof _ === \"function\" ? _ : constant(+_), x1 = null, area) : x0;\n };\n\n area.x0 = function(_) {\n return arguments.length ? (x0 = typeof _ === \"function\" ? _ : constant(+_), area) : x0;\n };\n\n area.x1 = function(_) {\n return arguments.length ? (x1 = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), area) : x1;\n };\n\n area.y = function(_) {\n return arguments.length ? (y0 = typeof _ === \"function\" ? _ : constant(+_), y1 = null, area) : y0;\n };\n\n area.y0 = function(_) {\n return arguments.length ? (y0 = typeof _ === \"function\" ? _ : constant(+_), area) : y0;\n };\n\n area.y1 = function(_) {\n return arguments.length ? (y1 = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), area) : y1;\n };\n\n area.lineX0 =\n area.lineY0 = function() {\n return arealine().x(x0).y(y0);\n };\n\n area.lineY1 = function() {\n return arealine().x(x0).y(y1);\n };\n\n area.lineX1 = function() {\n return arealine().x(x1).y(y0);\n };\n\n area.defined = function(_) {\n return arguments.length ? (defined = typeof _ === \"function\" ? _ : constant(!!_), area) : defined;\n };\n\n area.curve = function(_) {\n return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;\n };\n\n area.context = function(_) {\n return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;\n };\n\n return area;\n}\n", + "import curveLinear from \"./linear\";\n\nexport var curveRadialLinear = curveRadial(curveLinear);\n\nfunction Radial(curve) {\n this._curve = curve;\n}\n\nRadial.prototype = {\n areaStart: function() {\n this._curve.areaStart();\n },\n areaEnd: function() {\n this._curve.areaEnd();\n },\n lineStart: function() {\n this._curve.lineStart();\n },\n lineEnd: function() {\n this._curve.lineEnd();\n },\n point: function(a, r) {\n this._curve.point(r * Math.sin(a), r * -Math.cos(a));\n }\n};\n\nexport default function curveRadial(curve) {\n\n function radial(context) {\n return new Radial(curve(context));\n }\n\n radial._curve = curve;\n\n return radial;\n}\n", + "import curveRadial, {curveRadialLinear} from \"./curve/radial\";\nimport line from \"./line\";\n\nexport function lineRadial(l) {\n var c = l.curve;\n\n l.angle = l.x, delete l.x;\n l.radius = l.y, delete l.y;\n\n l.curve = function(_) {\n return arguments.length ? c(curveRadial(_)) : c()._curve;\n };\n\n return l;\n}\n\nexport default function() {\n return lineRadial(line().curve(curveRadialLinear));\n}\n", + "export var slice = Array.prototype.slice;\n", + "import {pi, tau} from \"../math\";\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size / pi);\n context.moveTo(r, 0);\n context.arc(0, 0, r, 0, tau);\n }\n};\n", + "export default {\n draw: function(context, size) {\n var r = Math.sqrt(size / 5) / 2;\n context.moveTo(-3 * r, -r);\n context.lineTo(-r, -r);\n context.lineTo(-r, -3 * r);\n context.lineTo(r, -3 * r);\n context.lineTo(r, -r);\n context.lineTo(3 * r, -r);\n context.lineTo(3 * r, r);\n context.lineTo(r, r);\n context.lineTo(r, 3 * r);\n context.lineTo(-r, 3 * r);\n context.lineTo(-r, r);\n context.lineTo(-3 * r, r);\n context.closePath();\n }\n};\n", + "var tan30 = Math.sqrt(1 / 3),\n tan30_2 = tan30 * 2;\n\nexport default {\n draw: function(context, size) {\n var y = Math.sqrt(size / tan30_2),\n x = y * tan30;\n context.moveTo(0, -y);\n context.lineTo(x, 0);\n context.lineTo(0, y);\n context.lineTo(-x, 0);\n context.closePath();\n }\n};\n", + "import {pi, tau} from \"../math\";\n\nvar ka = 0.89081309152928522810,\n kr = Math.sin(pi / 10) / Math.sin(7 * pi / 10),\n kx = Math.sin(tau / 10) * kr,\n ky = -Math.cos(tau / 10) * kr;\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size * ka),\n x = kx * r,\n y = ky * r;\n context.moveTo(0, -r);\n context.lineTo(x, y);\n for (var i = 1; i < 5; ++i) {\n var a = tau * i / 5,\n c = Math.cos(a),\n s = Math.sin(a);\n context.lineTo(s * r, -c * r);\n context.lineTo(c * x - s * y, s * x + c * y);\n }\n context.closePath();\n }\n};\n", + "export default {\n draw: function(context, size) {\n var w = Math.sqrt(size),\n x = -w / 2;\n context.rect(x, x, w, w);\n }\n};\n", + "var sqrt3 = Math.sqrt(3);\n\nexport default {\n draw: function(context, size) {\n var y = -Math.sqrt(size / (sqrt3 * 3));\n context.moveTo(0, y * 2);\n context.lineTo(-sqrt3 * y, -y);\n context.lineTo(sqrt3 * y, -y);\n context.closePath();\n }\n};\n", + "var c = -0.5,\n s = Math.sqrt(3) / 2,\n k = 1 / Math.sqrt(12),\n a = (k / 2 + 1) * 3;\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size / a),\n x0 = r / 2,\n y0 = r * k,\n x1 = x0,\n y1 = r * k + r,\n x2 = -x1,\n y2 = y1;\n context.moveTo(x0, y0);\n context.lineTo(x1, y1);\n context.lineTo(x2, y2);\n context.lineTo(c * x0 - s * y0, s * x0 + c * y0);\n context.lineTo(c * x1 - s * y1, s * x1 + c * y1);\n context.lineTo(c * x2 - s * y2, s * x2 + c * y2);\n context.lineTo(c * x0 + s * y0, c * y0 - s * x0);\n context.lineTo(c * x1 + s * y1, c * y1 - s * x1);\n context.lineTo(c * x2 + s * y2, c * y2 - s * x2);\n context.closePath();\n }\n};\n", + "import {path} from \"d3-path\";\nimport circle from \"./symbol/circle\";\nimport cross from \"./symbol/cross\";\nimport diamond from \"./symbol/diamond\";\nimport star from \"./symbol/star\";\nimport square from \"./symbol/square\";\nimport triangle from \"./symbol/triangle\";\nimport wye from \"./symbol/wye\";\nimport constant from \"./constant\";\n\nexport var symbols = [\n circle,\n cross,\n diamond,\n square,\n star,\n triangle,\n wye\n];\n\nexport default function() {\n var type = constant(circle),\n size = constant(64),\n context = null;\n\n function symbol() {\n var buffer;\n if (!context) context = buffer = path();\n type.apply(this, arguments).draw(context, +size.apply(this, arguments));\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n symbol.type = function(_) {\n return arguments.length ? (type = typeof _ === \"function\" ? _ : constant(_), symbol) : type;\n };\n\n symbol.size = function(_) {\n return arguments.length ? (size = typeof _ === \"function\" ? _ : constant(+_), symbol) : size;\n };\n\n symbol.context = function(_) {\n return arguments.length ? (context = _ == null ? null : _, symbol) : context;\n };\n\n return symbol;\n}\n", + "export default function() {}\n", + "export function point(that, x, y) {\n that._context.bezierCurveTo(\n (2 * that._x0 + that._x1) / 3,\n (2 * that._y0 + that._y1) / 3,\n (that._x0 + 2 * that._x1) / 3,\n (that._y0 + 2 * that._y1) / 3,\n (that._x0 + 4 * that._x1 + x) / 6,\n (that._y0 + 4 * that._y1 + y) / 6\n );\n}\n\nexport function Basis(context) {\n this._context = context;\n}\n\nBasis.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 3: point(this, this._x1, this._y1); // proceed\n case 2: this._context.lineTo(this._x1, this._y1); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new Basis(context);\n}\n", + "import noop from \"../noop\";\nimport {point} from \"./basis\";\n\nfunction BasisClosed(context) {\n this._context = context;\n}\n\nBasisClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x2, this._y2);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);\n this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x2, this._y2);\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._x2 = x, this._y2 = y; break;\n case 1: this._point = 2; this._x3 = x, this._y3 = y; break;\n case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new BasisClosed(context);\n}\n", + "import {point} from \"./basis\";\n\nfunction BasisOpen(context) {\n this._context = context;\n}\n\nBasisOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new BasisOpen(context);\n}\n", + "import {Basis} from \"./basis\";\n\nfunction Bundle(context, beta) {\n this._basis = new Basis(context);\n this._beta = beta;\n}\n\nBundle.prototype = {\n lineStart: function() {\n this._x = [];\n this._y = [];\n this._basis.lineStart();\n },\n lineEnd: function() {\n var x = this._x,\n y = this._y,\n j = x.length - 1;\n\n if (j > 0) {\n var x0 = x[0],\n y0 = y[0],\n dx = x[j] - x0,\n dy = y[j] - y0,\n i = -1,\n t;\n\n while (++i <= j) {\n t = i / j;\n this._basis.point(\n this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),\n this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)\n );\n }\n }\n\n this._x = this._y = null;\n this._basis.lineEnd();\n },\n point: function(x, y) {\n this._x.push(+x);\n this._y.push(+y);\n }\n};\n\nexport default (function custom(beta) {\n\n function bundle(context) {\n return beta === 1 ? new Basis(context) : new Bundle(context, beta);\n }\n\n bundle.beta = function(beta) {\n return custom(+beta);\n };\n\n return bundle;\n})(0.85);\n", + "export function point(that, x, y) {\n that._context.bezierCurveTo(\n that._x1 + that._k * (that._x2 - that._x0),\n that._y1 + that._k * (that._y2 - that._y0),\n that._x2 + that._k * (that._x1 - x),\n that._y2 + that._k * (that._y1 - y),\n that._x2,\n that._y2\n );\n}\n\nexport function Cardinal(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinal.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x2, this._y2); break;\n case 3: point(this, this._x1, this._y1); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; this._x1 = x, this._y1 = y; break;\n case 2: this._point = 3; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new Cardinal(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n", + "import noop from \"../noop\";\nimport {point} from \"./cardinal\";\n\nexport function CardinalClosed(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinalClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.lineTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n this.point(this._x5, this._y5);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._x3 = x, this._y3 = y; break;\n case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;\n case 2: this._point = 3; this._x5 = x, this._y5 = y; break;\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new CardinalClosed(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n", + "import {point} from \"./cardinal\";\n\nexport function CardinalOpen(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinalOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new CardinalOpen(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n", + "import {epsilon} from \"../math\";\nimport {Cardinal} from \"./cardinal\";\n\nexport function point(that, x, y) {\n var x1 = that._x1,\n y1 = that._y1,\n x2 = that._x2,\n y2 = that._y2;\n\n if (that._l01_a > epsilon) {\n var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,\n n = 3 * that._l01_a * (that._l01_a + that._l12_a);\n x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;\n y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;\n }\n\n if (that._l23_a > epsilon) {\n var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,\n m = 3 * that._l23_a * (that._l23_a + that._l12_a);\n x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;\n y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;\n }\n\n that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);\n}\n\nfunction CatmullRom(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRom.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x2, this._y2); break;\n case 3: this.point(this._x2, this._y2); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; // proceed\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n", + "import {CardinalClosed} from \"./cardinalClosed\";\nimport noop from \"../noop\";\nimport {point} from \"./catmullRom\";\n\nfunction CatmullRomClosed(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRomClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.lineTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n this.point(this._x5, this._y5);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; this._x3 = x, this._y3 = y; break;\n case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;\n case 2: this._point = 3; this._x5 = x, this._y5 = y; break;\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n", + "import {CardinalOpen} from \"./cardinalOpen\";\nimport {point} from \"./catmullRom\";\n\nfunction CatmullRomOpen(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRomOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n", + "import noop from \"../noop\";\n\nfunction LinearClosed(context) {\n this._context = context;\n}\n\nLinearClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._point) this._context.closePath();\n },\n point: function(x, y) {\n x = +x, y = +y;\n if (this._point) this._context.lineTo(x, y);\n else this._point = 1, this._context.moveTo(x, y);\n }\n};\n\nexport default function(context) {\n return new LinearClosed(context);\n}\n", + "function sign(x) {\n return x < 0 ? -1 : 1;\n}\n\n// Calculate the slopes of the tangents (Hermite-type interpolation) based on\n// the following paper: Steffen, M. 1990. A Simple Method for Monotonic\n// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.\n// NOV(II), P. 443, 1990.\nfunction slope3(that, x2, y2) {\n var h0 = that._x1 - that._x0,\n h1 = x2 - that._x1,\n s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),\n s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),\n p = (s0 * h1 + s1 * h0) / (h0 + h1);\n return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;\n}\n\n// Calculate a one-sided slope.\nfunction slope2(that, t) {\n var h = that._x1 - that._x0;\n return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;\n}\n\n// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations\n// \"you can express cubic Hermite interpolation in terms of cubic Bézier curves\n// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1\".\nfunction point(that, t0, t1) {\n var x0 = that._x0,\n y0 = that._y0,\n x1 = that._x1,\n y1 = that._y1,\n dx = (x1 - x0) / 3;\n that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);\n}\n\nfunction MonotoneX(context) {\n this._context = context;\n}\n\nMonotoneX.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 =\n this._t0 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x1, this._y1); break;\n case 3: point(this, this._t0, slope2(this, this._t0)); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n var t1 = NaN;\n\n x = +x, y = +y;\n if (x === this._x1 && y === this._y1) return; // Ignore coincident points.\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;\n default: point(this, this._t0, t1 = slope3(this, x, y)); break;\n }\n\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n this._t0 = t1;\n }\n}\n\nfunction MonotoneY(context) {\n this._context = new ReflectContext(context);\n}\n\n(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {\n MonotoneX.prototype.point.call(this, y, x);\n};\n\nfunction ReflectContext(context) {\n this._context = context;\n}\n\nReflectContext.prototype = {\n moveTo: function(x, y) { this._context.moveTo(y, x); },\n closePath: function() { this._context.closePath(); },\n lineTo: function(x, y) { this._context.lineTo(y, x); },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }\n};\n\nexport function monotoneX(context) {\n return new MonotoneX(context);\n}\n\nexport function monotoneY(context) {\n return new MonotoneY(context);\n}\n", + "function Natural(context) {\n this._context = context;\n}\n\nNatural.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x = [];\n this._y = [];\n },\n lineEnd: function() {\n var x = this._x,\n y = this._y,\n n = x.length;\n\n if (n) {\n this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);\n if (n === 2) {\n this._context.lineTo(x[1], y[1]);\n } else {\n var px = controlPoints(x),\n py = controlPoints(y);\n for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {\n this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);\n }\n }\n }\n\n if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();\n this._line = 1 - this._line;\n this._x = this._y = null;\n },\n point: function(x, y) {\n this._x.push(+x);\n this._y.push(+y);\n }\n};\n\n// See https://www.particleincell.com/2012/bezier-splines/ for derivation.\nfunction controlPoints(x) {\n var i,\n n = x.length - 1,\n m,\n a = new Array(n),\n b = new Array(n),\n r = new Array(n);\n a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];\n for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];\n a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];\n for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];\n a[n - 1] = r[n - 1] / b[n - 1];\n for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];\n b[n - 1] = (x[n] + a[n - 1]) / 2;\n for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];\n return [a, b];\n}\n\nexport default function(context) {\n return new Natural(context);\n}\n", + "function Step(context, t) {\n this._context = context;\n this._t = t;\n}\n\nStep.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x = this._y = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // proceed\n default: {\n if (this._t <= 0) {\n this._context.lineTo(this._x, y);\n this._context.lineTo(x, y);\n } else {\n var x1 = this._x * (1 - this._t) + x * this._t;\n this._context.lineTo(x1, this._y);\n this._context.lineTo(x1, y);\n }\n break;\n }\n }\n this._x = x, this._y = y;\n }\n};\n\nexport default function(context) {\n return new Step(context, 0.5);\n}\n\nexport function stepBefore(context) {\n return new Step(context, 0);\n}\n\nexport function stepAfter(context) {\n return new Step(context, 1);\n}\n", + "export default function(series, order) {\n if (!((n = series.length) > 1)) return;\n for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {\n s0 = s1, s1 = series[order[i]];\n for (j = 0; j < m; ++j) {\n s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];\n }\n }\n}\n", + "export default function(series) {\n var n = series.length, o = new Array(n);\n while (--n >= 0) o[n] = n;\n return o;\n}\n", + "import {slice} from \"./array\";\nimport constant from \"./constant\";\nimport offsetNone from \"./offset/none\";\nimport orderNone from \"./order/none\";\n\nfunction stackValue(d, key) {\n return d[key];\n}\n\nexport default function() {\n var keys = constant([]),\n order = orderNone,\n offset = offsetNone,\n value = stackValue;\n\n function stack(data) {\n var kz = keys.apply(this, arguments),\n i,\n m = data.length,\n n = kz.length,\n sz = new Array(n),\n oz;\n\n for (i = 0; i < n; ++i) {\n for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {\n si[j] = sij = [0, +value(data[j], ki, j, data)];\n sij.data = data[j];\n }\n si.key = ki;\n }\n\n for (i = 0, oz = order(sz); i < n; ++i) {\n sz[oz[i]].index = i;\n }\n\n offset(sz, oz);\n return sz;\n }\n\n stack.keys = function(_) {\n return arguments.length ? (keys = typeof _ === \"function\" ? _ : constant(slice.call(_)), stack) : keys;\n };\n\n stack.value = function(_) {\n return arguments.length ? (value = typeof _ === \"function\" ? _ : constant(+_), stack) : value;\n };\n\n stack.order = function(_) {\n return arguments.length ? (order = _ == null ? orderNone : typeof _ === \"function\" ? _ : constant(slice.call(_)), stack) : order;\n };\n\n stack.offset = function(_) {\n return arguments.length ? (offset = _ == null ? offsetNone : _, stack) : offset;\n };\n\n return stack;\n}\n", + "import none from \"./none\";\n\nexport default function(series, order) {\n if (!((n = series.length) > 0)) return;\n for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {\n for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;\n if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;\n }\n none(series, order);\n}\n", + "import none from \"./none\";\n\nexport default function(series, order) {\n if (!((n = series.length) > 0)) return;\n for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {\n for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;\n s0[j][1] += s0[j][0] = -y / 2;\n }\n none(series, order);\n}\n", + "import none from \"./none\";\n\nexport default function(series, order) {\n if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;\n for (var y = 0, j = 1, s0, m, n; j < m; ++j) {\n for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {\n var si = series[order[i]],\n sij0 = si[j][1] || 0,\n sij1 = si[j - 1][1] || 0,\n s3 = (sij0 - sij1) / 2;\n for (var k = 0; k < i; ++k) {\n var sk = series[order[k]],\n skj0 = sk[j][1] || 0,\n skj1 = sk[j - 1][1] || 0;\n s3 += skj0 - skj1;\n }\n s1 += sij0, s2 += s3 * sij0;\n }\n s0[j - 1][1] += s0[j - 1][0] = y;\n if (s1) y -= s2 / s1;\n }\n s0[j - 1][1] += s0[j - 1][0] = y;\n none(series, order);\n}\n", + "export {default as arc} from \"./arc\";\nexport {default as area} from \"./area\";\nexport {default as line} from \"./line\";\nexport {default as pie} from \"./pie\";\nexport {default as areaRadial, default as radialArea} from \"./areaRadial\"; // Note: radialArea is deprecated!\nexport {default as lineRadial, default as radialLine} from \"./lineRadial\"; // Note: radialLine is deprecated!\nexport {default as pointRadial} from \"./pointRadial\";\nexport {linkHorizontal, linkVertical, linkRadial} from \"./link/index\";\n\nexport {default as symbol, symbols} from \"./symbol\";\nexport {default as symbolCircle} from \"./symbol/circle\";\nexport {default as symbolCross} from \"./symbol/cross\";\nexport {default as symbolDiamond} from \"./symbol/diamond\";\nexport {default as symbolSquare} from \"./symbol/square\";\nexport {default as symbolStar} from \"./symbol/star\";\nexport {default as symbolTriangle} from \"./symbol/triangle\";\nexport {default as symbolWye} from \"./symbol/wye\";\n\nexport {default as curveBasisClosed} from \"./curve/basisClosed\";\nexport {default as curveBasisOpen} from \"./curve/basisOpen\";\nexport {default as curveBasis} from \"./curve/basis\";\nexport {default as curveBundle} from \"./curve/bundle\";\nexport {default as curveCardinalClosed} from \"./curve/cardinalClosed\";\nexport {default as curveCardinalOpen} from \"./curve/cardinalOpen\";\nexport {default as curveCardinal} from \"./curve/cardinal\";\nexport {default as curveCatmullRomClosed} from \"./curve/catmullRomClosed\";\nexport {default as curveCatmullRomOpen} from \"./curve/catmullRomOpen\";\nexport {default as curveCatmullRom} from \"./curve/catmullRom\";\nexport {default as curveLinearClosed} from \"./curve/linearClosed\";\nexport {default as curveLinear} from \"./curve/linear\";\nexport {monotoneX as curveMonotoneX, monotoneY as curveMonotoneY} from \"./curve/monotone\";\nexport {default as curveNatural} from \"./curve/natural\";\nexport {default as curveStep, stepAfter as curveStepAfter, stepBefore as curveStepBefore} from \"./curve/step\";\n\nexport {default as stack} from \"./stack\";\nexport {default as stackOffsetExpand} from \"./offset/expand\";\nexport {default as stackOffsetDiverging} from \"./offset/diverging\";\nexport {default as stackOffsetNone} from \"./offset/none\";\nexport {default as stackOffsetSilhouette} from \"./offset/silhouette\";\nexport {default as stackOffsetWiggle} from \"./offset/wiggle\";\nexport {default as stackOrderAscending} from \"./order/ascending\";\nexport {default as stackOrderDescending} from \"./order/descending\";\nexport {default as stackOrderInsideOut} from \"./order/insideOut\";\nexport {default as stackOrderNone} from \"./order/none\";\nexport {default as stackOrderReverse} from \"./order/reverse\";\n", + "/*! decimal.js-light v2.5.0 https://github.com/MikeMcl/decimal.js-light/LICENCE */\r\n;(function (globalScope) {\r\n 'use strict';\r\n\r\n\r\n /*\r\n * decimal.js-light v2.5.0\r\n * An arbitrary-precision Decimal type for JavaScript.\r\n * https://github.com/MikeMcl/decimal.js-light\r\n * Copyright (c) 2018 Michael Mclaughlin \r\n * MIT Expat Licence\r\n */\r\n\r\n\r\n // ----------------------------------- EDITABLE DEFAULTS ------------------------------------ //\r\n\r\n\r\n // The limit on the value of `)))) + ((("`" + `precision`) + ("`" + (`, and on the value of the first argument to\r\n // ` + "`"))) + ((`toDecimalPlaces` + ("`" + `, `)) + ("`" + (`toExponential` + "`"))))) + ((((`, ` + "`") + (`toFixed` + ("`" + `, `))) + (("`" + (`toPrecision` + "`")) + (` and ` + ("`" + `toSignificantDigits`)))) + ((("`" + (`.\r\n var MAX_DIGITS = 1e9, // 0 to 1e9\r\n\r\n\r\n // The initial configuration properties of the Decimal constructor.\r\n Decimal = {\r\n\r\n // These values must be integers within the stated ranges (inclusive).\r\n // Most of these values can be changed during run-time using ` + "`")) + (`Decimal.config` + ("`" + `.\r\n\r\n // The maximum number of significant digits of the result of a calculation or base conversion.\r\n // E.g. `))) + (("`" + (`Decimal.config({ precision: 20 });` + "`")) + (`\r\n precision: 20, // 1 to MAX_DIGITS\r\n\r\n // The rounding mode used by default by ` + ("`" + `toInteger`))))))) + (((((("`" + `, `) + ("`" + (`toDecimalPlaces` + "`"))) + ((`, ` + ("`" + `toExponential`)) + ("`" + (`,\r\n // ` + "`")))) + (((`toFixed` + "`") + (`, ` + ("`" + `toPrecision`))) + (("`" + (` and ` + "`")) + (`toSignificantDigits` + ("`" + `.\r\n //\r\n // ROUND_UP 0 Away from zero.\r\n // ROUND_DOWN 1 Towards zero.\r\n // ROUND_CEIL 2 Towards +Infinity.\r\n // ROUND_FLOOR 3 Towards -Infinity.\r\n // ROUND_HALF_UP 4 Towards nearest neighbour. If equidistant, up.\r\n // ROUND_HALF_DOWN 5 Towards nearest neighbour. If equidistant, down.\r\n // ROUND_HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour.\r\n // ROUND_HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity.\r\n // ROUND_HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity.\r\n //\r\n // E.g.\r\n // `))))) + (((("`" + `Decimal.rounding = 4;`) + ("`" + (`\r\n // ` + "`"))) + ((`Decimal.rounding = Decimal.ROUND_HALF_UP;` + ("`" + `\r\n rounding: 4, // 0 to 8\r\n\r\n // The exponent value at and beneath which `)) + ("`" + (`toString` + "`")))) + (((` returns exponential notation.\r\n // JavaScript numbers: -7\r\n toExpNeg: -7, // 0 to -MAX_E\r\n\r\n // The exponent value at and above which ` + "`") + (`toString` + ("`" + ` returns exponential notation.\r\n // JavaScript numbers: 21\r\n toExpPos: 21, // 0 to MAX_E\r\n\r\n // The natural logarithm of 10.\r\n // 115 digits\r\n LN10: '2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298341967784042286'\r\n },\r\n\r\n\r\n // ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- //\r\n\r\n\r\n external = true,\r\n\r\n decimalError = '[DecimalError] ',\r\n invalidArgument = decimalError + 'Invalid argument: ',\r\n exponentOutOfRange = decimalError + 'Exponent out of range: ',\r\n\r\n mathfloor = Math.floor,\r\n mathpow = Math.pow,\r\n\r\n isDecimal = /^(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i,\r\n\r\n ONE,\r\n BASE = 1e7,\r\n LOG_BASE = 7,\r\n MAX_SAFE_INTEGER = 9007199254740991,\r\n MAX_E = mathfloor(MAX_SAFE_INTEGER / LOG_BASE), // 1286742750677284\r\n\r\n // Decimal.prototype object\r\n P = {};\r\n\r\n\r\n // Decimal prototype methods\r\n\r\n\r\n /*\r\n * absoluteValue abs\r\n * comparedTo cmp\r\n * decimalPlaces dp\r\n * dividedBy div\r\n * dividedToIntegerBy idiv\r\n * equals eq\r\n * exponent\r\n * greaterThan gt\r\n * greaterThanOrEqualTo gte\r\n * isInteger isint\r\n * isNegative isneg\r\n * isPositive ispos\r\n * isZero\r\n * lessThan lt\r\n * lessThanOrEqualTo lte\r\n * logarithm log\r\n * minus sub\r\n * modulo mod\r\n * naturalExponential exp\r\n * naturalLogarithm ln\r\n * negated neg\r\n * plus add\r\n * precision sd\r\n * squareRoot sqrt\r\n * times mul\r\n * toDecimalPlaces todp\r\n * toExponential\r\n * toFixed\r\n * toInteger toint\r\n * toNumber\r\n * toPower pow\r\n * toPrecision\r\n * toSignificantDigits tosd\r\n * toString\r\n * valueOf val\r\n */\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the absolute value of this Decimal.\r\n *\r\n */\r\n P.absoluteValue = P.abs = function () {\r\n var x = new this.constructor(this);\r\n if (x.s) x.s = 1;\r\n return x;\r\n };\r\n\r\n\r\n /*\r\n * Return\r\n * 1 if the value of this Decimal is greater than the value of `))) + (("`" + (`y` + "`")) + (`,\r\n * -1 if the value of this Decimal is less than the value of ` + ("`" + `y`)))))) + ((((("`" + `,\r\n * 0 if they have the same value\r\n *\r\n */\r\n P.comparedTo = P.cmp = function (y) {\r\n var i, j, xdL, ydL,\r\n x = this;\r\n\r\n y = new x.constructor(y);\r\n\r\n // Signs differ?\r\n if (x.s !== y.s) return x.s || -y.s;\r\n\r\n // Compare exponents.\r\n if (x.e !== y.e) return x.e > y.e ^ x.s < 0 ? 1 : -1;\r\n\r\n xdL = x.d.length;\r\n ydL = y.d.length;\r\n\r\n // Compare digit by digit.\r\n for (i = 0, j = xdL < ydL ? xdL : ydL; i < j; ++i) {\r\n if (x.d[i] !== y.d[i]) return x.d[i] > y.d[i] ^ x.s < 0 ? 1 : -1;\r\n }\r\n\r\n // Compare lengths.\r\n return xdL === ydL ? 0 : xdL > ydL ^ x.s < 0 ? 1 : -1;\r\n };\r\n\r\n\r\n /*\r\n * Return the number of decimal places of the value of this Decimal.\r\n *\r\n */\r\n P.decimalPlaces = P.dp = function () {\r\n var x = this,\r\n w = x.d.length - 1,\r\n dp = (w - x.e) * LOG_BASE;\r\n\r\n // Subtract the number of trailing zeros of the last word.\r\n w = x.d[w];\r\n if (w) for (; w % 10 == 0; w /= 10) dp--;\r\n\r\n return dp < 0 ? 0 : dp;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal divided by `) + ("`" + (`y` + "`"))) + ((`, truncated to\r\n * ` + ("`" + `precision`)) + ("`" + (` significant digits.\r\n *\r\n */\r\n P.dividedBy = P.div = function (y) {\r\n return divide(this, new this.constructor(y));\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the integer part of dividing the value of this Decimal\r\n * by the value of ` + "`")))) + (((`y` + "`") + (`, truncated to ` + ("`" + `precision`))) + (("`" + (` significant digits.\r\n *\r\n */\r\n P.dividedToIntegerBy = P.idiv = function (y) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n return round(divide(x, new Ctor(y), 0, 1), Ctor.precision);\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is equal to the value of ` + "`")) + (`y` + ("`" + `, otherwise return false.\r\n *\r\n */\r\n P.equals = P.eq = function (y) {\r\n return !this.cmp(y);\r\n };\r\n\r\n\r\n /*\r\n * Return the (base 10) exponent value of this Decimal (this.e is the base 10000000 exponent).\r\n *\r\n */\r\n P.exponent = function () {\r\n return getBase10Exponent(this);\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is greater than the value of `))))) + (((("`" + `y`) + ("`" + (`, otherwise return\r\n * false.\r\n *\r\n */\r\n P.greaterThan = P.gt = function (y) {\r\n return this.cmp(y) > 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is greater than or equal to the value of ` + "`"))) + ((`y` + ("`" + `,\r\n * otherwise return false.\r\n *\r\n */\r\n P.greaterThanOrEqualTo = P.gte = function (y) {\r\n return this.cmp(y) >= 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is an integer, otherwise return false.\r\n *\r\n */\r\n P.isInteger = P.isint = function () {\r\n return this.e > this.d.length - 2;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is negative, otherwise return false.\r\n *\r\n */\r\n P.isNegative = P.isneg = function () {\r\n return this.s < 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is positive, otherwise return false.\r\n *\r\n */\r\n P.isPositive = P.ispos = function () {\r\n return this.s > 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is 0, otherwise return false.\r\n *\r\n */\r\n P.isZero = function () {\r\n return this.s === 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is less than `)) + ("`" + (`y` + "`")))) + (((`, otherwise return false.\r\n *\r\n */\r\n P.lessThan = P.lt = function (y) {\r\n return this.cmp(y) < 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this Decimal is less than or equal to ` + ("`" + `y`)) + ("`" + (`, otherwise return false.\r\n *\r\n */\r\n P.lessThanOrEqualTo = P.lte = function (y) {\r\n return this.cmp(y) < 1;\r\n };\r\n\r\n\r\n /*\r\n * Return the logarithm of the value of this Decimal to the specified base, truncated to\r\n * ` + "`"))) + ((`precision` + ("`" + ` significant digits.\r\n *\r\n * If no base is specified, return log[10](x).\r\n *\r\n * log[base](x) = ln(x) / ln(base)\r\n *\r\n * The maximum error of the result is 1 ulp (unit in the last place).\r\n *\r\n * [base] {number|string|Decimal} The base of the logarithm.\r\n *\r\n */\r\n P.logarithm = P.log = function (base) {\r\n var r,\r\n x = this,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision,\r\n wpr = pr + 5;\r\n\r\n // Default base is 10.\r\n if (base === void 0) {\r\n base = new Ctor(10);\r\n } else {\r\n base = new Ctor(base);\r\n\r\n // log[-b](x) = NaN\r\n // log[0](x) = NaN\r\n // log[1](x) = NaN\r\n if (base.s < 1 || base.eq(ONE)) throw Error(decimalError + 'NaN');\r\n }\r\n\r\n // log[b](-x) = NaN\r\n // log[b](0) = -Infinity\r\n if (x.s < 1) throw Error(decimalError + (x.s ? 'NaN' : '-Infinity'));\r\n\r\n // log[b](1) = 0\r\n if (x.eq(ONE)) return new Ctor(0);\r\n\r\n external = false;\r\n r = divide(ln(x, wpr), ln(base, wpr), wpr);\r\n external = true;\r\n\r\n return round(r, pr);\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal minus `)) + ("`" + (`y` + "`"))))))))))) + ((((((((((`, truncated to\r\n * ` + "`") + (`precision` + ("`" + ` significant digits.\r\n *\r\n */\r\n P.minus = P.sub = function (y) {\r\n var x = this;\r\n y = new x.constructor(y);\r\n return x.s == y.s ? subtract(x, y) : add(x, (y.s = -y.s, y));\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal modulo `))) + (("`" + (`y` + "`")) + (`, truncated to\r\n * ` + ("`" + `precision`)))) + ((("`" + ` significant digits.\r\n *\r\n */\r\n P.modulo = P.mod = function (y) {\r\n var q,\r\n x = this,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision;\r\n\r\n y = new Ctor(y);\r\n\r\n // x % 0 = NaN\r\n if (!y.s) throw Error(decimalError + 'NaN');\r\n\r\n // Return x if x is 0.\r\n if (!x.s) return round(new Ctor(x), pr);\r\n\r\n // Prevent rounding of intermediate calculations.\r\n external = false;\r\n q = divide(x, y, 0, 1).times(y);\r\n external = true;\r\n\r\n return x.minus(q);\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the natural exponential of the value of this Decimal,\r\n * i.e. the base e raised to the power the value of this Decimal, truncated to `) + ("`" + (`precision` + "`"))) + ((`\r\n * significant digits.\r\n *\r\n */\r\n P.naturalExponential = P.exp = function () {\r\n return exp(this);\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the natural logarithm of the value of this Decimal,\r\n * truncated to ` + ("`" + `precision`)) + ("`" + (` significant digits.\r\n *\r\n */\r\n P.naturalLogarithm = P.ln = function () {\r\n return ln(this);\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal negated, i.e. as if multiplied by\r\n * -1.\r\n *\r\n */\r\n P.negated = P.neg = function () {\r\n var x = new this.constructor(this);\r\n x.s = -x.s || 0;\r\n return x;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal plus ` + "`"))))) + ((((`y` + "`") + (`, truncated to\r\n * ` + ("`" + `precision`))) + (("`" + (` significant digits.\r\n *\r\n */\r\n P.plus = P.add = function (y) {\r\n var x = this;\r\n y = new x.constructor(y);\r\n return x.s == y.s ? add(x, y) : subtract(x, (y.s = -y.s, y));\r\n };\r\n\r\n\r\n /*\r\n * Return the number of significant digits of the value of this Decimal.\r\n *\r\n * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0.\r\n *\r\n */\r\n P.precision = P.sd = function (z) {\r\n var e, sd, w,\r\n x = this;\r\n\r\n if (z !== void 0 && z !== !!z && z !== 1 && z !== 0) throw Error(invalidArgument + z);\r\n\r\n e = getBase10Exponent(x) + 1;\r\n w = x.d.length - 1;\r\n sd = w * LOG_BASE + 1;\r\n w = x.d[w];\r\n\r\n // If non-zero...\r\n if (w) {\r\n\r\n // Subtract the number of trailing zeros of the last word.\r\n for (; w % 10 == 0; w /= 10) sd--;\r\n\r\n // Add the number of digits of the first word.\r\n for (w = x.d[0]; w >= 10; w /= 10) sd++;\r\n }\r\n\r\n return z && e > sd ? e : sd;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the square root of this Decimal, truncated to ` + "`")) + (`precision` + ("`" + `\r\n * significant digits.\r\n *\r\n */\r\n P.squareRoot = P.sqrt = function () {\r\n var e, n, pr, r, s, t, wpr,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n // Negative or zero?\r\n if (x.s < 1) {\r\n if (!x.s) return new Ctor(0);\r\n\r\n // sqrt(-x) = NaN\r\n throw Error(decimalError + 'NaN');\r\n }\r\n\r\n e = getBase10Exponent(x);\r\n external = false;\r\n\r\n // Initial estimate.\r\n s = Math.sqrt(+x);\r\n\r\n // Math.sqrt underflow/overflow?\r\n // Pass x to Math.sqrt as integer, then adjust the exponent of the result.\r\n if (s == 0 || s == 1 / 0) {\r\n n = digitsToString(x.d);\r\n if ((n.length + e) % 2 == 0) n += '0';\r\n s = Math.sqrt(n);\r\n e = mathfloor((e + 1) / 2) - (e < 0 || e % 2);\r\n\r\n if (s == 1 / 0) {\r\n n = '1e' + e;\r\n } else {\r\n n = s.toExponential();\r\n n = n.slice(0, n.indexOf('e') + 1) + e;\r\n }\r\n\r\n r = new Ctor(n);\r\n } else {\r\n r = new Ctor(s.toString());\r\n }\r\n\r\n pr = Ctor.precision;\r\n s = wpr = pr + 3;\r\n\r\n // Newton-Raphson iteration.\r\n for (;;) {\r\n t = r;\r\n r = t.plus(divide(x, t, wpr + 2)).times(0.5);\r\n\r\n if (digitsToString(t.d).slice(0, wpr) === (n = digitsToString(r.d)).slice(0, wpr)) {\r\n n = n.slice(wpr - 3, wpr + 1);\r\n\r\n // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or\r\n // 4999, i.e. approaching a rounding boundary, continue the iteration.\r\n if (s == wpr && n == '4999') {\r\n\r\n // On the first iteration only, check to see if rounding up gives the exact result as the\r\n // nines may infinitely repeat.\r\n round(t, pr + 1, 0);\r\n\r\n if (t.times(t).eq(x)) {\r\n r = t;\r\n break;\r\n }\r\n } else if (n != '9999') {\r\n break;\r\n }\r\n\r\n wpr += 4;\r\n }\r\n }\r\n\r\n external = true;\r\n\r\n return round(r, pr);\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal times `)))) + ((("`" + `y`) + ("`" + (`, truncated to\r\n * ` + "`"))) + ((`precision` + ("`" + ` significant digits.\r\n *\r\n */\r\n P.times = P.mul = function (y) {\r\n var carry, e, i, k, r, rL, t, xdL, ydL,\r\n x = this,\r\n Ctor = x.constructor,\r\n xd = x.d,\r\n yd = (y = new Ctor(y)).d;\r\n\r\n // Return 0 if either is 0.\r\n if (!x.s || !y.s) return new Ctor(0);\r\n\r\n y.s *= x.s;\r\n e = x.e + y.e;\r\n xdL = xd.length;\r\n ydL = yd.length;\r\n\r\n // Ensure xd points to the longer array.\r\n if (xdL < ydL) {\r\n r = xd;\r\n xd = yd;\r\n yd = r;\r\n rL = xdL;\r\n xdL = ydL;\r\n ydL = rL;\r\n }\r\n\r\n // Initialise the result array with zeros.\r\n r = [];\r\n rL = xdL + ydL;\r\n for (i = rL; i--;) r.push(0);\r\n\r\n // Multiply!\r\n for (i = ydL; --i >= 0;) {\r\n carry = 0;\r\n for (k = xdL + i; k > i;) {\r\n t = r[k] + yd[i] * xd[k - i - 1] + carry;\r\n r[k--] = t % BASE | 0;\r\n carry = t / BASE | 0;\r\n }\r\n\r\n r[k] = (r[k] + carry) % BASE | 0;\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (; !r[--rL];) r.pop();\r\n\r\n if (carry) ++e;\r\n else r.shift();\r\n\r\n y.d = r;\r\n y.e = e;\r\n\r\n return external ? round(y, Ctor.precision) : y;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `)) + ("`" + (`dp` + "`")))))) + (((((`\r\n * decimal places using rounding mode ` + "`") + (`rm` + ("`" + ` or `))) + (("`" + (`rounding` + "`")) + (` if ` + ("`" + `rm`)))) + ((("`" + ` is omitted.\r\n *\r\n * If `) + ("`" + (`dp` + "`"))) + ((` is omitted, return a new Decimal whose value is the value of this Decimal.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\n P.toDecimalPlaces = P.todp = function (dp, rm) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n\r\n x = new Ctor(x);\r\n if (dp === void 0) return x;\r\n\r\n checkInt32(dp, 0, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n return round(x, dp + getBase10Exponent(x) + 1, rm);\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this Decimal in exponential notation rounded to\r\n * ` + ("`" + `dp`)) + ("`" + (` fixed decimal places using rounding mode ` + "`"))))) + ((((`rounding` + "`") + (`.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\n P.toExponential = function (dp, rm) {\r\n var str,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (dp === void 0) {\r\n str = toString(x, true);\r\n } else {\r\n checkInt32(dp, 0, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n x = round(new Ctor(x), dp + 1, rm);\r\n str = toString(x, true, dp + 1);\r\n }\r\n\r\n return str;\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this Decimal in normal (fixed-point) notation to\r\n * ` + ("`" + `dp`))) + (("`" + (` fixed decimal places and rounded using rounding mode ` + "`")) + (`rm` + ("`" + ` or `)))) + ((("`" + `rounding`) + ("`" + (` if ` + "`"))) + ((`rm` + ("`" + ` is\r\n * omitted.\r\n *\r\n * As with JavaScript numbers, (-0).toFixed(0) is '0', but e.g. (-0.00001).toFixed(0) is '-0'.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'.\r\n * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'.\r\n * (-0).toFixed(3) is '0.000'.\r\n * (-0.5).toFixed(0) is '-0'.\r\n *\r\n */\r\n P.toFixed = function (dp, rm) {\r\n var str, y,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (dp === void 0) return toString(x);\r\n\r\n checkInt32(dp, 0, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n y = round(new Ctor(x), dp + getBase10Exponent(x) + 1, rm);\r\n str = toString(y.abs(), false, dp + getBase10Exponent(y) + 1);\r\n\r\n // To determine whether to add the minus sign look at the value before it was rounded,\r\n // i.e. look at `)) + ("`" + (`x` + "`"))))))) + ((((((` rather than ` + "`") + (`y` + ("`" + `.\r\n return x.isneg() && !x.isZero() ? '-' + str : str;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a whole number using\r\n * rounding mode `))) + (("`" + (`rounding` + "`")) + (`.\r\n *\r\n */\r\n P.toInteger = P.toint = function () {\r\n var x = this,\r\n Ctor = x.constructor;\r\n return round(new Ctor(x), getBase10Exponent(x) + 1, Ctor.rounding);\r\n };\r\n\r\n\r\n /*\r\n * Return the value of this Decimal converted to a number primitive.\r\n *\r\n */\r\n P.toNumber = function () {\r\n return +this;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal raised to the power ` + ("`" + `y`)))) + ((("`" + `,\r\n * truncated to `) + ("`" + (`precision` + "`"))) + ((` significant digits.\r\n *\r\n * For non-integer or very large exponents pow(x, y) is calculated using\r\n *\r\n * x^y = exp(y*ln(x))\r\n *\r\n * The maximum error is 1 ulp (unit in last place).\r\n *\r\n * y {number|string|Decimal} The power to which to raise this Decimal.\r\n *\r\n */\r\n P.toPower = P.pow = function (y) {\r\n var e, k, pr, r, sign, yIsInt,\r\n x = this,\r\n Ctor = x.constructor,\r\n guard = 12,\r\n yn = +(y = new Ctor(y));\r\n\r\n // pow(x, 0) = 1\r\n if (!y.s) return new Ctor(ONE);\r\n\r\n x = new Ctor(x);\r\n\r\n // pow(0, y > 0) = 0\r\n // pow(0, y < 0) = Infinity\r\n if (!x.s) {\r\n if (y.s < 1) throw Error(decimalError + 'Infinity');\r\n return x;\r\n }\r\n\r\n // pow(1, y) = 1\r\n if (x.eq(ONE)) return x;\r\n\r\n pr = Ctor.precision;\r\n\r\n // pow(x, 1) = x\r\n if (y.eq(ONE)) return round(x, pr);\r\n\r\n e = y.e;\r\n k = y.d.length - 1;\r\n yIsInt = e >= k;\r\n sign = x.s;\r\n\r\n if (!yIsInt) {\r\n\r\n // pow(x < 0, y non-integer) = NaN\r\n if (sign < 0) throw Error(decimalError + 'NaN');\r\n\r\n // If y is a small integer use the 'exponentiation by squaring' algorithm.\r\n } else if ((k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) {\r\n r = new Ctor(ONE);\r\n\r\n // Max k of 9007199254740991 takes 53 loop iterations.\r\n // Maximum digits array length; leaves [28, 34] guard digits.\r\n e = Math.ceil(pr / LOG_BASE + 4);\r\n\r\n external = false;\r\n\r\n for (;;) {\r\n if (k % 2) {\r\n r = r.times(x);\r\n truncate(r.d, e);\r\n }\r\n\r\n k = mathfloor(k / 2);\r\n if (k === 0) break;\r\n\r\n x = x.times(x);\r\n truncate(x.d, e);\r\n }\r\n\r\n external = true;\r\n\r\n return y.s < 0 ? new Ctor(ONE).div(r) : round(r, pr);\r\n }\r\n\r\n // Result is negative if x is negative and the last digit of integer y is odd.\r\n sign = sign < 0 && y.d[Math.max(e, k)] & 1 ? -1 : 1;\r\n\r\n x.s = 1;\r\n external = false;\r\n r = y.times(ln(x, pr + guard));\r\n external = true;\r\n r = exp(r);\r\n r.s = sign;\r\n\r\n return r;\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this Decimal rounded to ` + ("`" + `sd`)) + ("`" + (` significant digits\r\n * using rounding mode ` + "`"))))) + ((((`rounding` + "`") + (`.\r\n *\r\n * Return exponential notation if ` + ("`" + `sd`))) + (("`" + (` is less than the number of digits necessary to represent\r\n * the integer part of the value in normal notation.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\n P.toPrecision = function (sd, rm) {\r\n var e, str,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (sd === void 0) {\r\n e = getBase10Exponent(x);\r\n str = toString(x, e <= Ctor.toExpNeg || e >= Ctor.toExpPos);\r\n } else {\r\n checkInt32(sd, 1, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n x = round(new Ctor(x), sd, rm);\r\n e = getBase10Exponent(x);\r\n str = toString(x, sd <= e || e <= Ctor.toExpNeg, sd);\r\n }\r\n\r\n return str;\r\n };\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of ` + "`")) + (`sd` + ("`" + `\r\n * significant digits using rounding mode `)))) + ((("`" + `rm`) + ("`" + (`, or to ` + "`"))) + ((`precision` + ("`" + ` and `)) + ("`" + (`rounding` + "`")))))) + (((((` respectively if\r\n * omitted.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\n P.toSignificantDigits = P.tosd = function (sd, rm) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n\r\n if (sd === void 0) {\r\n sd = Ctor.precision;\r\n rm = Ctor.rounding;\r\n } else {\r\n checkInt32(sd, 1, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n }\r\n\r\n return round(new Ctor(x), sd, rm);\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this Decimal.\r\n *\r\n * Return exponential notation if this Decimal has a positive exponent equal to or greater than\r\n * ` + "`") + (`toExpPos` + ("`" + `, or a negative exponent equal to or less than `))) + (("`" + (`toExpNeg` + "`")) + (`.\r\n *\r\n */\r\n P.toString = P.valueOf = P.val = P.toJSON = function () {\r\n var x = this,\r\n e = getBase10Exponent(x),\r\n Ctor = x.constructor;\r\n\r\n return toString(x, e <= Ctor.toExpNeg || e >= Ctor.toExpPos);\r\n };\r\n\r\n\r\n // Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers.\r\n\r\n\r\n /*\r\n * add P.minus, P.plus\r\n * checkInt32 P.todp, P.toExponential, P.toFixed, P.toPrecision, P.tosd\r\n * digitsToString P.log, P.sqrt, P.pow, toString, exp, ln\r\n * divide P.div, P.idiv, P.log, P.mod, P.sqrt, exp, ln\r\n * exp P.exp, P.pow\r\n * getBase10Exponent P.exponent, P.sd, P.toint, P.sqrt, P.todp, P.toFixed, P.toPrecision,\r\n * P.toString, divide, round, toString, exp, ln\r\n * getLn10 P.log, ln\r\n * getZeroString digitsToString, toString\r\n * ln P.log, P.ln, P.pow, exp\r\n * parseDecimal Decimal\r\n * round P.abs, P.idiv, P.log, P.minus, P.mod, P.neg, P.plus, P.toint, P.sqrt,\r\n * P.times, P.todp, P.toExponential, P.toFixed, P.pow, P.toPrecision, P.tosd,\r\n * divide, getLn10, exp, ln\r\n * subtract P.minus, P.plus\r\n * toString P.toExponential, P.toFixed, P.toPrecision, P.toString, P.valueOf\r\n * truncate P.pow\r\n *\r\n * Throws: P.log, P.mod, P.sd, P.sqrt, P.pow, checkInt32, divide, round,\r\n * getLn10, exp, ln, parseDecimal, Decimal, config\r\n */\r\n\r\n\r\n function add(x, y) {\r\n var carry, d, e, i, k, len, xd, yd,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision;\r\n\r\n // If either is zero...\r\n if (!x.s || !y.s) {\r\n\r\n // Return x if y is zero.\r\n // Return y if y is non-zero.\r\n if (!y.s) y = new Ctor(x);\r\n return external ? round(y, pr) : y;\r\n }\r\n\r\n xd = x.d;\r\n yd = y.d;\r\n\r\n // x and y are finite, non-zero numbers with the same sign.\r\n\r\n k = x.e;\r\n e = y.e;\r\n xd = xd.slice();\r\n i = k - e;\r\n\r\n // If base 1e7 exponents differ...\r\n if (i) {\r\n if (i < 0) {\r\n d = xd;\r\n i = -i;\r\n len = yd.length;\r\n } else {\r\n d = yd;\r\n e = k;\r\n len = xd.length;\r\n }\r\n\r\n // Limit number of zeros prepended to max(ceil(pr / LOG_BASE), len) + 1.\r\n k = Math.ceil(pr / LOG_BASE);\r\n len = k > len ? k + 1 : len + 1;\r\n\r\n if (i > len) {\r\n i = len;\r\n d.length = 1;\r\n }\r\n\r\n // Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts.\r\n d.reverse();\r\n for (; i--;) d.push(0);\r\n d.reverse();\r\n }\r\n\r\n len = xd.length;\r\n i = yd.length;\r\n\r\n // If yd is longer than xd, swap xd and yd so xd points to the longer array.\r\n if (len - i < 0) {\r\n i = len;\r\n d = yd;\r\n yd = xd;\r\n xd = d;\r\n }\r\n\r\n // Only start adding at yd.length - 1 as the further digits of xd can be left as they are.\r\n for (carry = 0; i;) {\r\n carry = (xd[--i] = xd[i] + yd[i] + carry) / BASE | 0;\r\n xd[i] %= BASE;\r\n }\r\n\r\n if (carry) {\r\n xd.unshift(carry);\r\n ++e;\r\n }\r\n\r\n // Remove trailing zeros.\r\n // No need to check for zero, as +x + +y != 0 && -x + -y != 0\r\n for (len = xd.length; xd[--len] == 0;) xd.pop();\r\n\r\n y.d = xd;\r\n y.e = e;\r\n\r\n return external ? round(y, pr) : y;\r\n }\r\n\r\n\r\n function checkInt32(i, min, max) {\r\n if (i !== ~~i || i < min || i > max) {\r\n throw Error(invalidArgument + i);\r\n }\r\n }\r\n\r\n\r\n function digitsToString(d) {\r\n var i, k, ws,\r\n indexOfLastWord = d.length - 1,\r\n str = '',\r\n w = d[0];\r\n\r\n if (indexOfLastWord > 0) {\r\n str += w;\r\n for (i = 1; i < indexOfLastWord; i++) {\r\n ws = d[i] + '';\r\n k = LOG_BASE - ws.length;\r\n if (k) str += getZeroString(k);\r\n str += ws;\r\n }\r\n\r\n w = d[i];\r\n ws = w + '';\r\n k = LOG_BASE - ws.length;\r\n if (k) str += getZeroString(k);\r\n } else if (w === 0) {\r\n return '0';\r\n }\r\n\r\n // Remove trailing zeros of last w.\r\n for (; w % 10 === 0;) w /= 10;\r\n\r\n return str + w;\r\n }\r\n\r\n\r\n var divide = (function () {\r\n\r\n // Assumes non-zero x and k, and hence non-zero result.\r\n function multiplyInteger(x, k) {\r\n var temp,\r\n carry = 0,\r\n i = x.length;\r\n\r\n for (x = x.slice(); i--;) {\r\n temp = x[i] * k + carry;\r\n x[i] = temp % BASE | 0;\r\n carry = temp / BASE | 0;\r\n }\r\n\r\n if (carry) x.unshift(carry);\r\n\r\n return x;\r\n }\r\n\r\n function compare(a, b, aL, bL) {\r\n var i, r;\r\n\r\n if (aL != bL) {\r\n r = aL > bL ? 1 : -1;\r\n } else {\r\n for (i = r = 0; i < aL; i++) {\r\n if (a[i] != b[i]) {\r\n r = a[i] > b[i] ? 1 : -1;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return r;\r\n }\r\n\r\n function subtract(a, b, aL) {\r\n var i = 0;\r\n\r\n // Subtract b from a.\r\n for (; aL--;) {\r\n a[aL] -= i;\r\n i = a[aL] < b[aL] ? 1 : 0;\r\n a[aL] = i * BASE + a[aL] - b[aL];\r\n }\r\n\r\n // Remove leading zeros.\r\n for (; !a[0] && a.length > 1;) a.shift();\r\n }\r\n\r\n return function (x, y, pr, dp) {\r\n var cmp, e, i, k, prod, prodL, q, qd, rem, remL, rem0, sd, t, xi, xL, yd0, yL, yz,\r\n Ctor = x.constructor,\r\n sign = x.s == y.s ? 1 : -1,\r\n xd = x.d,\r\n yd = y.d;\r\n\r\n // Either 0?\r\n if (!x.s) return new Ctor(x);\r\n if (!y.s) throw Error(decimalError + 'Division by zero');\r\n\r\n e = x.e - y.e;\r\n yL = yd.length;\r\n xL = xd.length;\r\n q = new Ctor(sign);\r\n qd = q.d = [];\r\n\r\n // Result exponent may be one less than e.\r\n for (i = 0; yd[i] == (xd[i] || 0); ) ++i;\r\n if (yd[i] > (xd[i] || 0)) --e;\r\n\r\n if (pr == null) {\r\n sd = pr = Ctor.precision;\r\n } else if (dp) {\r\n sd = pr + (getBase10Exponent(x) - getBase10Exponent(y)) + 1;\r\n } else {\r\n sd = pr;\r\n }\r\n\r\n if (sd < 0) return new Ctor(0);\r\n\r\n // Convert precision in number of base 10 digits to base 1e7 digits.\r\n sd = sd / LOG_BASE + 2 | 0;\r\n i = 0;\r\n\r\n // divisor < 1e7\r\n if (yL == 1) {\r\n k = 0;\r\n yd = yd[0];\r\n sd++;\r\n\r\n // k is the carry.\r\n for (; (i < xL || k) && sd--; i++) {\r\n t = k * BASE + (xd[i] || 0);\r\n qd[i] = t / yd | 0;\r\n k = t % yd | 0;\r\n }\r\n\r\n // divisor >= 1e7\r\n } else {\r\n\r\n // Normalise xd and yd so highest order digit of yd is >= BASE/2\r\n k = BASE / (yd[0] + 1) | 0;\r\n\r\n if (k > 1) {\r\n yd = multiplyInteger(yd, k);\r\n xd = multiplyInteger(xd, k);\r\n yL = yd.length;\r\n xL = xd.length;\r\n }\r\n\r\n xi = yL;\r\n rem = xd.slice(0, yL);\r\n remL = rem.length;\r\n\r\n // Add zeros to make remainder as long as divisor.\r\n for (; remL < yL;) rem[remL++] = 0;\r\n\r\n yz = yd.slice();\r\n yz.unshift(0);\r\n yd0 = yd[0];\r\n\r\n if (yd[1] >= BASE / 2) ++yd0;\r\n\r\n do {\r\n k = 0;\r\n\r\n // Compare divisor and remainder.\r\n cmp = compare(yd, rem, yL, remL);\r\n\r\n // If divisor < remainder.\r\n if (cmp < 0) {\r\n\r\n // Calculate trial digit, k.\r\n rem0 = rem[0];\r\n if (yL != remL) rem0 = rem0 * BASE + (rem[1] || 0);\r\n\r\n // k will be how many times the divisor goes into the current remainder.\r\n k = rem0 / yd0 | 0;\r\n\r\n // Algorithm:\r\n // 1. product = divisor * trial digit (k)\r\n // 2. if product > remainder: product -= divisor, k--\r\n // 3. remainder -= product\r\n // 4. if product was < remainder at 2:\r\n // 5. compare new remainder and divisor\r\n // 6. If remainder > divisor: remainder -= divisor, k++\r\n\r\n if (k > 1) {\r\n if (k >= BASE) k = BASE - 1;\r\n\r\n // product = divisor * trial digit.\r\n prod = multiplyInteger(yd, k);\r\n prodL = prod.length;\r\n remL = rem.length;\r\n\r\n // Compare product and remainder.\r\n cmp = compare(prod, rem, prodL, remL);\r\n\r\n // product > remainder.\r\n if (cmp == 1) {\r\n k--;\r\n\r\n // Subtract divisor from product.\r\n subtract(prod, yL < prodL ? yz : yd, prodL);\r\n }\r\n } else {\r\n\r\n // cmp is -1.\r\n // If k is 0, there is no need to compare yd and rem again below, so change cmp to 1\r\n // to avoid it. If k is 1 there is a need to compare yd and rem again below.\r\n if (k == 0) cmp = k = 1;\r\n prod = yd.slice();\r\n }\r\n\r\n prodL = prod.length;\r\n if (prodL < remL) prod.unshift(0);\r\n\r\n // Subtract product from remainder.\r\n subtract(rem, prod, remL);\r\n\r\n // If product was < previous remainder.\r\n if (cmp == -1) {\r\n remL = rem.length;\r\n\r\n // Compare divisor and new remainder.\r\n cmp = compare(yd, rem, yL, remL);\r\n\r\n // If divisor < new remainder, subtract divisor from remainder.\r\n if (cmp < 1) {\r\n k++;\r\n\r\n // Subtract divisor from remainder.\r\n subtract(rem, yL < remL ? yz : yd, remL);\r\n }\r\n }\r\n\r\n remL = rem.length;\r\n } else if (cmp === 0) {\r\n k++;\r\n rem = [0];\r\n } // if cmp === 1, k will be 0\r\n\r\n // Add the next digit, k, to the result array.\r\n qd[i++] = k;\r\n\r\n // Update the remainder.\r\n if (cmp && rem[0]) {\r\n rem[remL++] = xd[xi] || 0;\r\n } else {\r\n rem = [xd[xi]];\r\n remL = 1;\r\n }\r\n\r\n } while ((xi++ < xL || rem[0] !== void 0) && sd--);\r\n }\r\n\r\n // Leading zero?\r\n if (!qd[0]) qd.shift();\r\n\r\n q.e = e;\r\n\r\n return round(q, dp ? pr + getBase10Exponent(q) + 1 : pr);\r\n };\r\n })();\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the natural exponential of ` + ("`" + `x`)))) + ((("`" + ` truncated to `) + ("`" + (`sd` + "`"))) + ((`\r\n * significant digits.\r\n *\r\n * Taylor/Maclaurin series.\r\n *\r\n * exp(x) = x^0/0! + x^1/1! + x^2/2! + x^3/3! + ...\r\n *\r\n * Argument reduction:\r\n * Repeat x = x / 32, k += 5, until |x| < 0.1\r\n * exp(x) = exp(x / 2^k)^(2^k)\r\n *\r\n * Previously, the argument was initially reduced by\r\n * exp(x) = exp(r) * 10^k where r = x - k * ln10, k = floor(x / ln10)\r\n * to first put r in the range [0, ln10], before dividing by 32 until |x| < 0.1, but this was\r\n * found to be slower than just dividing repeatedly by 32 as above.\r\n *\r\n * (Math object integer min/max: Math.exp(709) = 8.2e+307, Math.exp(-745) = 5e-324)\r\n *\r\n * exp(x) is non-terminating for any finite, non-zero x.\r\n *\r\n */\r\n function exp(x, sd) {\r\n var denominator, guard, pow, sum, t, wpr,\r\n i = 0,\r\n k = 0,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision;\r\n\r\n if (getBase10Exponent(x) > 16) throw Error(exponentOutOfRange + getBase10Exponent(x));\r\n\r\n // exp(0) = 1\r\n if (!x.s) return new Ctor(ONE);\r\n\r\n if (sd == null) {\r\n external = false;\r\n wpr = pr;\r\n } else {\r\n wpr = sd;\r\n }\r\n\r\n t = new Ctor(0.03125);\r\n\r\n while (x.abs().gte(0.1)) {\r\n x = x.times(t); // x = x / 2^5\r\n k += 5;\r\n }\r\n\r\n // Estimate the precision increase necessary to ensure the first 4 rounding digits are correct.\r\n guard = Math.log(mathpow(2, k)) / Math.LN10 * 2 + 5 | 0;\r\n wpr += guard;\r\n denominator = pow = sum = new Ctor(ONE);\r\n Ctor.precision = wpr;\r\n\r\n for (;;) {\r\n pow = round(pow.times(x), wpr);\r\n denominator = denominator.times(++i);\r\n t = sum.plus(divide(pow, denominator, wpr));\r\n\r\n if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) {\r\n while (k--) sum = round(sum.times(sum), wpr);\r\n Ctor.precision = pr;\r\n return sd == null ? (external = true, round(sum, pr)) : sum;\r\n }\r\n\r\n sum = t;\r\n }\r\n }\r\n\r\n\r\n // Calculate the base 10 exponent from the base 1e7 exponent.\r\n function getBase10Exponent(x) {\r\n var e = x.e * LOG_BASE,\r\n w = x.d[0];\r\n\r\n // Add the number of digits of the first word of the digits array.\r\n for (; w >= 10; w /= 10) e++;\r\n return e;\r\n }\r\n\r\n\r\n function getLn10(Ctor, sd, pr) {\r\n\r\n if (sd > Ctor.LN10.sd()) {\r\n\r\n\r\n // Reset global state in case the exception is caught.\r\n external = true;\r\n if (pr) Ctor.precision = pr;\r\n throw Error(decimalError + 'LN10 precision limit exceeded');\r\n }\r\n\r\n return round(new Ctor(Ctor.LN10), sd);\r\n }\r\n\r\n\r\n function getZeroString(k) {\r\n var zs = '';\r\n for (; k--;) zs += '0';\r\n return zs;\r\n }\r\n\r\n\r\n /*\r\n * Return a new Decimal whose value is the natural logarithm of ` + ("`" + `x`)) + ("`" + (` truncated to ` + "`"))))) + ((((`sd` + "`") + (` significant\r\n * digits.\r\n *\r\n * ln(n) is non-terminating (n != 1)\r\n *\r\n */\r\n function ln(y, sd) {\r\n var c, c0, denominator, e, numerator, sum, t, wpr, x2,\r\n n = 1,\r\n guard = 10,\r\n x = y,\r\n xd = x.d,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision;\r\n\r\n // ln(-x) = NaN\r\n // ln(0) = -Infinity\r\n if (x.s < 1) throw Error(decimalError + (x.s ? 'NaN' : '-Infinity'));\r\n\r\n // ln(1) = 0\r\n if (x.eq(ONE)) return new Ctor(0);\r\n\r\n if (sd == null) {\r\n external = false;\r\n wpr = pr;\r\n } else {\r\n wpr = sd;\r\n }\r\n\r\n if (x.eq(10)) {\r\n if (sd == null) external = true;\r\n return getLn10(Ctor, wpr);\r\n }\r\n\r\n wpr += guard;\r\n Ctor.precision = wpr;\r\n c = digitsToString(xd);\r\n c0 = c.charAt(0);\r\n e = getBase10Exponent(x);\r\n\r\n if (Math.abs(e) < 1.5e15) {\r\n\r\n // Argument reduction.\r\n // The series converges faster the closer the argument is to 1, so using\r\n // ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b\r\n // multiply the argument by itself until the leading digits of the significand are 7, 8, 9,\r\n // 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can\r\n // later be divided by this number, then separate out the power of 10 using\r\n // ln(a*10^b) = ln(a) + b*ln(10).\r\n\r\n // max n is 21 (gives 0.9, 1.0 or 1.1) (9e15 / 21 = 4.2e14).\r\n //while (c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1) {\r\n // max n is 6 (gives 0.7 - 1.3)\r\n while (c0 < 7 && c0 != 1 || c0 == 1 && c.charAt(1) > 3) {\r\n x = x.times(y);\r\n c = digitsToString(x.d);\r\n c0 = c.charAt(0);\r\n n++;\r\n }\r\n\r\n e = getBase10Exponent(x);\r\n\r\n if (c0 > 1) {\r\n x = new Ctor('0.' + c);\r\n e++;\r\n } else {\r\n x = new Ctor(c0 + '.' + c.slice(1));\r\n }\r\n } else {\r\n\r\n // The argument reduction method above may result in overflow if the argument y is a massive\r\n // number with exponent >= 1500000000000000 (9e15 / 6 = 1.5e15), so instead recall this\r\n // function using ln(x*10^e) = ln(x) + e*ln(10).\r\n t = getLn10(Ctor, wpr + 2, pr).times(e + '');\r\n x = ln(new Ctor(c0 + '.' + c.slice(1)), wpr - guard).plus(t);\r\n\r\n Ctor.precision = pr;\r\n return sd == null ? (external = true, round(x, pr)) : x;\r\n }\r\n\r\n // x is reduced to a value near 1.\r\n\r\n // Taylor series.\r\n // ln(y) = ln((1 + x)/(1 - x)) = 2(x + x^3/3 + x^5/5 + x^7/7 + ...)\r\n // where x = (y - 1)/(y + 1) (|x| < 1)\r\n sum = numerator = x = divide(x.minus(ONE), x.plus(ONE), wpr);\r\n x2 = round(x.times(x), wpr);\r\n denominator = 3;\r\n\r\n for (;;) {\r\n numerator = round(numerator.times(x2), wpr);\r\n t = sum.plus(divide(numerator, new Ctor(denominator), wpr));\r\n\r\n if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) {\r\n sum = sum.times(2);\r\n\r\n // Reverse the argument reduction.\r\n if (e !== 0) sum = sum.plus(getLn10(Ctor, wpr + 2, pr).times(e + ''));\r\n sum = divide(sum, new Ctor(n), wpr);\r\n\r\n Ctor.precision = pr;\r\n return sd == null ? (external = true, round(sum, pr)) : sum;\r\n }\r\n\r\n sum = t;\r\n denominator += 2;\r\n }\r\n }\r\n\r\n\r\n /*\r\n * Parse the value of a new Decimal ` + ("`" + `x`))) + (("`" + (` from string ` + "`")) + (`str` + ("`" + `.\r\n */\r\n function parseDecimal(x, str) {\r\n var e, i, len;\r\n\r\n // Decimal point?\r\n if ((e = str.indexOf('.')) > -1) str = str.replace('.', '');\r\n\r\n // Exponential form?\r\n if ((i = str.search(/e/i)) > 0) {\r\n\r\n // Determine exponent.\r\n if (e < 0) e = i;\r\n e += +str.slice(i + 1);\r\n str = str.substring(0, i);\r\n } else if (e < 0) {\r\n\r\n // Integer.\r\n e = str.length;\r\n }\r\n\r\n // Determine leading zeros.\r\n for (i = 0; str.charCodeAt(i) === 48;) ++i;\r\n\r\n // Determine trailing zeros.\r\n for (len = str.length; str.charCodeAt(len - 1) === 48;) --len;\r\n str = str.slice(i, len);\r\n\r\n if (str) {\r\n len -= i;\r\n e = e - i - 1;\r\n x.e = mathfloor(e / LOG_BASE);\r\n x.d = [];\r\n\r\n // Transform base\r\n\r\n // e is the base 10 exponent.\r\n // i is where to slice str to get the first word of the digits array.\r\n i = (e + 1) % LOG_BASE;\r\n if (e < 0) i += LOG_BASE;\r\n\r\n if (i < len) {\r\n if (i) x.d.push(+str.slice(0, i));\r\n for (len -= LOG_BASE; i < len;) x.d.push(+str.slice(i, i += LOG_BASE));\r\n str = str.slice(i);\r\n i = LOG_BASE - str.length;\r\n } else {\r\n i -= len;\r\n }\r\n\r\n for (; i--;) str += '0';\r\n x.d.push(+str);\r\n\r\n if (external && (x.e > MAX_E || x.e < -MAX_E)) throw Error(exponentOutOfRange + e);\r\n } else {\r\n\r\n // Zero.\r\n x.s = 0;\r\n x.e = 0;\r\n x.d = [0];\r\n }\r\n\r\n return x;\r\n }\r\n\r\n\r\n /*\r\n * Round `)))) + ((("`" + (`x` + "`")) + (` to ` + ("`" + `sd`))) + (("`" + (` significant digits, using rounding mode ` + "`")) + (`rm` + ("`" + ` if present (truncate otherwise).\r\n */\r\n function round(x, sd, rm) {\r\n var i, j, k, n, rd, doRound, w, xdi,\r\n xd = x.d;\r\n\r\n // rd: the rounding digit, i.e. the digit after the digit that may be rounded up.\r\n // w: the word of xd which contains the rounding digit, a base 1e7 number.\r\n // xdi: the index of w within xd.\r\n // n: the number of digits of w.\r\n // i: what would be the index of rd within w if all the numbers were 7 digits long (i.e. if\r\n // they had leading zeros)\r\n // j: if > 0, the actual index of rd within w (if < 0, rd is a leading zero).\r\n\r\n // Get the length of the first word of the digits array xd.\r\n for (n = 1, k = xd[0]; k >= 10; k /= 10) n++;\r\n i = sd - n;\r\n\r\n // Is the rounding digit in the first word of xd?\r\n if (i < 0) {\r\n i += LOG_BASE;\r\n j = sd;\r\n w = xd[xdi = 0];\r\n } else {\r\n xdi = Math.ceil((i + 1) / LOG_BASE);\r\n k = xd.length;\r\n if (xdi >= k) return x;\r\n w = k = xd[xdi];\r\n\r\n // Get the number of digits of w.\r\n for (n = 1; k >= 10; k /= 10) n++;\r\n\r\n // Get the index of rd within w.\r\n i %= LOG_BASE;\r\n\r\n // Get the index of rd within w, adjusted for leading zeros.\r\n // The number of leading zeros of w is given by LOG_BASE - n.\r\n j = i - LOG_BASE + n;\r\n }\r\n\r\n if (rm !== void 0) {\r\n k = mathpow(10, n - j - 1);\r\n\r\n // Get the rounding digit at index j of w.\r\n rd = w / k % 10 | 0;\r\n\r\n // Are there any non-zero digits after the rounding digit?\r\n doRound = sd < 0 || xd[xdi + 1] !== void 0 || w % k;\r\n\r\n // The expression `)))))))) + ((((((("`" + `w % mathpow(10, n - j - 1)`) + ("`" + (` returns all the digits of w to the right of the\r\n // digit at (left-to-right) index j, e.g. if w is 908714 and j is 2, the expression will give\r\n // 714.\r\n\r\n doRound = rm < 4\r\n ? (rd || doRound) && (rm == 0 || rm == (x.s < 0 ? 3 : 2))\r\n : rd > 5 || rd == 5 && (rm == 4 || doRound || rm == 6 &&\r\n\r\n // Check whether the digit to the left of the rounding digit is odd.\r\n ((i > 0 ? j > 0 ? w / mathpow(10, n - j) : 0 : xd[xdi - 1]) % 10) & 1 ||\r\n rm == (x.s < 0 ? 8 : 7));\r\n }\r\n\r\n if (sd < 1 || !xd[0]) {\r\n if (doRound) {\r\n k = getBase10Exponent(x);\r\n xd.length = 1;\r\n\r\n // Convert sd to decimal places.\r\n sd = sd - k - 1;\r\n\r\n // 1, 0.1, 0.01, 0.001, 0.0001 etc.\r\n xd[0] = mathpow(10, (LOG_BASE - sd % LOG_BASE) % LOG_BASE);\r\n x.e = mathfloor(-sd / LOG_BASE) || 0;\r\n } else {\r\n xd.length = 1;\r\n\r\n // Zero.\r\n xd[0] = x.e = x.s = 0;\r\n }\r\n\r\n return x;\r\n }\r\n\r\n // Remove excess digits.\r\n if (i == 0) {\r\n xd.length = xdi;\r\n k = 1;\r\n xdi--;\r\n } else {\r\n xd.length = xdi + 1;\r\n k = mathpow(10, LOG_BASE - i);\r\n\r\n // E.g. 56700 becomes 56000 if 7 is the rounding digit.\r\n // j > 0 means i > number of leading zeros of w.\r\n xd[xdi] = j > 0 ? (w / mathpow(10, n - j) % mathpow(10, j) | 0) * k : 0;\r\n }\r\n\r\n if (doRound) {\r\n for (;;) {\r\n\r\n // Is the digit to be rounded up in the first word of xd?\r\n if (xdi == 0) {\r\n if ((xd[0] += k) == BASE) {\r\n xd[0] = 1;\r\n ++x.e;\r\n }\r\n\r\n break;\r\n } else {\r\n xd[xdi] += k;\r\n if (xd[xdi] != BASE) break;\r\n xd[xdi--] = 0;\r\n k = 1;\r\n }\r\n }\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (i = xd.length; xd[--i] === 0;) xd.pop();\r\n\r\n if (external && (x.e > MAX_E || x.e < -MAX_E)) {\r\n throw Error(exponentOutOfRange + getBase10Exponent(x));\r\n }\r\n\r\n return x;\r\n }\r\n\r\n\r\n function subtract(x, y) {\r\n var d, e, i, j, k, len, xd, xe, xLTy, yd,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision;\r\n\r\n // Return y negated if x is zero.\r\n // Return x if y is zero and x is non-zero.\r\n if (!x.s || !y.s) {\r\n if (y.s) y.s = -y.s;\r\n else y = new Ctor(x);\r\n return external ? round(y, pr) : y;\r\n }\r\n\r\n xd = x.d;\r\n yd = y.d;\r\n\r\n // x and y are non-zero numbers with the same sign.\r\n\r\n e = y.e;\r\n xe = x.e;\r\n xd = xd.slice();\r\n k = xe - e;\r\n\r\n // If exponents differ...\r\n if (k) {\r\n xLTy = k < 0;\r\n\r\n if (xLTy) {\r\n d = xd;\r\n k = -k;\r\n len = yd.length;\r\n } else {\r\n d = yd;\r\n e = xe;\r\n len = xd.length;\r\n }\r\n\r\n // Numbers with massively different exponents would result in a very high number of zeros\r\n // needing to be prepended, but this can be avoided while still ensuring correct rounding by\r\n // limiting the number of zeros to ` + "`"))) + ((`Math.ceil(pr / LOG_BASE) + 2` + ("`" + `.\r\n i = Math.max(Math.ceil(pr / LOG_BASE), len) + 2;\r\n\r\n if (k > i) {\r\n k = i;\r\n d.length = 1;\r\n }\r\n\r\n // Prepend zeros to equalise exponents.\r\n d.reverse();\r\n for (i = k; i--;) d.push(0);\r\n d.reverse();\r\n\r\n // Base 1e7 exponents equal.\r\n } else {\r\n\r\n // Check digits to determine which is the bigger number.\r\n\r\n i = xd.length;\r\n len = yd.length;\r\n xLTy = i < len;\r\n if (xLTy) len = i;\r\n\r\n for (i = 0; i < len; i++) {\r\n if (xd[i] != yd[i]) {\r\n xLTy = xd[i] < yd[i];\r\n break;\r\n }\r\n }\r\n\r\n k = 0;\r\n }\r\n\r\n if (xLTy) {\r\n d = xd;\r\n xd = yd;\r\n yd = d;\r\n y.s = -y.s;\r\n }\r\n\r\n len = xd.length;\r\n\r\n // Append zeros to xd if shorter.\r\n // Don't add zeros to yd if shorter as subtraction only needs to start at yd length.\r\n for (i = yd.length - len; i > 0; --i) xd[len++] = 0;\r\n\r\n // Subtract yd from xd.\r\n for (i = yd.length; i > k;) {\r\n if (xd[--i] < yd[i]) {\r\n for (j = i; j && xd[--j] === 0;) xd[j] = BASE - 1;\r\n --xd[j];\r\n xd[i] += BASE;\r\n }\r\n\r\n xd[i] -= yd[i];\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (; xd[--len] === 0;) xd.pop();\r\n\r\n // Remove leading zeros and adjust exponent accordingly.\r\n for (; xd[0] === 0; xd.shift()) --e;\r\n\r\n // Zero?\r\n if (!xd[0]) return new Ctor(0);\r\n\r\n y.d = xd;\r\n y.e = e;\r\n\r\n //return external && xd.length >= pr / LOG_BASE ? round(y, pr) : y;\r\n return external ? round(y, pr) : y;\r\n }\r\n\r\n\r\n function toString(x, isExp, sd) {\r\n var k,\r\n e = getBase10Exponent(x),\r\n str = digitsToString(x.d),\r\n len = str.length;\r\n\r\n if (isExp) {\r\n if (sd && (k = sd - len) > 0) {\r\n str = str.charAt(0) + '.' + str.slice(1) + getZeroString(k);\r\n } else if (len > 1) {\r\n str = str.charAt(0) + '.' + str.slice(1);\r\n }\r\n\r\n str = str + (e < 0 ? 'e' : 'e+') + e;\r\n } else if (e < 0) {\r\n str = '0.' + getZeroString(-e - 1) + str;\r\n if (sd && (k = sd - len) > 0) str += getZeroString(k);\r\n } else if (e >= len) {\r\n str += getZeroString(e + 1 - len);\r\n if (sd && (k = sd - e - 1) > 0) str = str + '.' + getZeroString(k);\r\n } else {\r\n if ((k = e + 1) < len) str = str.slice(0, k) + '.' + str.slice(k);\r\n if (sd && (k = sd - len) > 0) {\r\n if (e + 1 === len) str += '.';\r\n str += getZeroString(k);\r\n }\r\n }\r\n\r\n return x.s < 0 ? '-' + str : str;\r\n }\r\n\r\n\r\n // Does not strip trailing zeros.\r\n function truncate(arr, len) {\r\n if (arr.length > len) {\r\n arr.length = len;\r\n return true;\r\n }\r\n }\r\n\r\n\r\n // Decimal methods\r\n\r\n\r\n /*\r\n * clone\r\n * config/set\r\n */\r\n\r\n\r\n /*\r\n * Create and return a Decimal constructor with the same configuration properties as this Decimal\r\n * constructor.\r\n *\r\n */\r\n function clone(obj) {\r\n var i, p, ps;\r\n\r\n /*\r\n * The Decimal constructor and exported function.\r\n * Return a new Decimal instance.\r\n *\r\n * value {number|string|Decimal} A numeric value.\r\n *\r\n */\r\n function Decimal(value) {\r\n var x = this;\r\n\r\n // Decimal called without new.\r\n if (!(x instanceof Decimal)) return new Decimal(value);\r\n\r\n // Retain a reference to this Decimal constructor, and shadow Decimal.prototype.constructor\r\n // which points to Object.\r\n x.constructor = Decimal;\r\n\r\n // Duplicate.\r\n if (value instanceof Decimal) {\r\n x.s = value.s;\r\n x.e = value.e;\r\n x.d = (value = value.d) ? value.slice() : value;\r\n return;\r\n }\r\n\r\n if (typeof value === 'number') {\r\n\r\n // Reject Infinity/NaN.\r\n if (value * 0 !== 0) {\r\n throw Error(invalidArgument + value);\r\n }\r\n\r\n if (value > 0) {\r\n x.s = 1;\r\n } else if (value < 0) {\r\n value = -value;\r\n x.s = -1;\r\n } else {\r\n x.s = 0;\r\n x.e = 0;\r\n x.d = [0];\r\n return;\r\n }\r\n\r\n // Fast path for small integers.\r\n if (value === ~~value && value < 1e7) {\r\n x.e = 0;\r\n x.d = [value];\r\n return;\r\n }\r\n\r\n return parseDecimal(x, value.toString());\r\n } else if (typeof value !== 'string') {\r\n throw Error(invalidArgument + value);\r\n }\r\n\r\n // Minus sign?\r\n if (value.charCodeAt(0) === 45) {\r\n value = value.slice(1);\r\n x.s = -1;\r\n } else {\r\n x.s = 1;\r\n }\r\n\r\n if (isDecimal.test(value)) parseDecimal(x, value);\r\n else throw Error(invalidArgument + value);\r\n }\r\n\r\n Decimal.prototype = P;\r\n\r\n Decimal.ROUND_UP = 0;\r\n Decimal.ROUND_DOWN = 1;\r\n Decimal.ROUND_CEIL = 2;\r\n Decimal.ROUND_FLOOR = 3;\r\n Decimal.ROUND_HALF_UP = 4;\r\n Decimal.ROUND_HALF_DOWN = 5;\r\n Decimal.ROUND_HALF_EVEN = 6;\r\n Decimal.ROUND_HALF_CEIL = 7;\r\n Decimal.ROUND_HALF_FLOOR = 8;\r\n\r\n Decimal.clone = clone;\r\n Decimal.config = Decimal.set = config;\r\n\r\n if (obj === void 0) obj = {};\r\n if (obj) {\r\n ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'LN10'];\r\n for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];\r\n }\r\n\r\n Decimal.config(obj);\r\n\r\n return Decimal;\r\n }\r\n\r\n\r\n /*\r\n * Configure global settings for a Decimal constructor.\r\n *\r\n * `)) + ("`" + (`obj` + "`")))) + (((` is an object with one or more of the following properties,\r\n *\r\n * precision {number}\r\n * rounding {number}\r\n * toExpNeg {number}\r\n * toExpPos {number}\r\n *\r\n * E.g. Decimal.config({ precision: 20, rounding: 4 })\r\n *\r\n */\r\n function config(obj) {\r\n if (!obj || typeof obj !== 'object') {\r\n throw Error(decimalError + 'Object expected');\r\n }\r\n var i, p, v,\r\n ps = [\r\n 'precision', 1, MAX_DIGITS,\r\n 'rounding', 0, 8,\r\n 'toExpNeg', -1 / 0, 0,\r\n 'toExpPos', 0, 1 / 0\r\n ];\r\n\r\n for (i = 0; i < ps.length; i += 3) {\r\n if ((v = obj[p = ps[i]]) !== void 0) {\r\n if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v;\r\n else throw Error(invalidArgument + p + ': ' + v);\r\n }\r\n }\r\n\r\n if ((v = obj[p = 'LN10']) !== void 0) {\r\n if (v == Math.LN10) this[p] = new this(v);\r\n else throw Error(invalidArgument + p + ': ' + v);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n\r\n // Create and configure initial Decimal constructor.\r\n Decimal = clone(Decimal);\r\n\r\n Decimal['default'] = Decimal.Decimal = Decimal;\r\n\r\n // Internal constant.\r\n ONE = new Decimal(1);\r\n\r\n\r\n // Export.\r\n\r\n\r\n // AMD.\r\n if (typeof define == 'function' && define.amd) {\r\n define(function () {\r\n return Decimal;\r\n });\r\n\r\n // Node and other environments that support module.exports.\r\n } else if (typeof module != 'undefined' && module.exports) {\r\n module.exports = Decimal;\r\n\r\n // Browser.\r\n } else {\r\n if (!globalScope) {\r\n globalScope = typeof self != 'undefined' && self && self.self == self\r\n ? self : Function('return this')();\r\n }\r\n\r\n globalScope.Decimal = Decimal;\r\n }\r\n})(this);\r\n", + "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n\ttypeof define === 'function' && define.amd ? define(factory) :\n\t(global.deepmerge = factory());\n}(this, (function () { 'use strict';\n\nvar isMergeableObject = function isMergeableObject(value) {\n\treturn isNonNullObject(value)\n\t\t&& !isSpecial(value)\n};\n\nfunction isNonNullObject(value) {\n\treturn !!value && typeof value === 'object'\n}\n\nfunction isSpecial(value) {\n\tvar stringValue = Object.prototype.toString.call(value);\n\n\treturn stringValue === '[object RegExp]'\n\t\t|| stringValue === '[object Date]'\n\t\t|| isReactElement(value)\n}\n\n// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25\nvar canUseSymbol = typeof Symbol === 'function' && Symbol.for;\nvar REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;\n\nfunction isReactElement(value) {\n\treturn value.$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction emptyTarget(val) {\n\treturn Array.isArray(val) ? [] : {}\n}\n\nfunction cloneUnlessOtherwiseSpecified(value, options) {\n\treturn (options.clone !== false && options.isMergeableObject(value))\n\t\t? deepmerge(emptyTarget(value), value, options)\n\t\t: value\n}\n\nfunction defaultArrayMerge(target, source, options) {\n\treturn target.concat(source).map(function(element) {\n\t\treturn cloneUnlessOtherwiseSpecified(element, options)\n\t})\n}\n\nfunction getMergeFunction(key, options) {\n\tif (!options.customMerge) {\n\t\treturn deepmerge\n\t}\n\tvar customMerge = options.customMerge(key);\n\treturn typeof customMerge === 'function' ? customMerge : deepmerge\n}\n\nfunction mergeObject(target, source, options) {\n\tvar destination = {};\n\tif (options.isMergeableObject(target)) {\n\t\tObject.keys(target).forEach(function(key) {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(target[key], options);\n\t\t});\n\t}\n\tObject.keys(source).forEach(function(key) {\n\t\tif (!options.isMergeableObject(source[key]) || !target[key]) {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(source[key], options);\n\t\t} else {\n\t\t\tdestination[key] = getMergeFunction(key, options)(target[key], source[key], options);\n\t\t}\n\t});\n\treturn destination\n}\n\nfunction deepmerge(target, source, options) {\n\toptions = options || {};\n\toptions.arrayMerge = options.arrayMerge || defaultArrayMerge;\n\toptions.isMergeableObject = options.isMergeableObject || isMergeableObject;\n\n\tvar sourceIsArray = Array.isArray(source);\n\tvar targetIsArray = Array.isArray(target);\n\tvar sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;\n\n\tif (!sourceAndTargetTypesMatch) {\n\t\treturn cloneUnlessOtherwiseSpecified(source, options)\n\t} else if (sourceIsArray) {\n\t\treturn options.arrayMerge(target, source, options)\n\t} else {\n\t\treturn mergeObject(target, source, options)\n\t}\n}\n\ndeepmerge.all = function deepmergeAll(array, options) {\n\tif (!Array.isArray(array)) {\n\t\tthrow new Error('first argument should be an array')\n\t}\n\n\treturn array.reduce(function(prev, next) {\n\t\treturn deepmerge(prev, next, options)\n\t}, {})\n};\n\nvar deepmerge_1 = deepmerge;\n\nreturn deepmerge_1;\n\n})));\n", + "\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nexports.__esModule = true;\nexports.default = addClass;\n\nvar _hasClass = _interopRequireDefault(require(\"./hasClass\"));\n\nfunction addClass(element, className) {\n if (element.classList) element.classList.add(className);else if (!(0, _hasClass.default)(element, className)) if (typeof element.className === 'string') element.className = element.className + ' ' + className;else element.setAttribute('class', (element.className && element.className.baseVal || '') + ' ' + className);\n}\n\nmodule.exports = exports[\"default\"];", + "\"use strict\";\n\nexports.__esModule = true;\nexports.default = hasClass;\n\nfunction hasClass(element, className) {\n if (element.classList) return !!className && element.classList.contains(className);else return (\" \" + (element.className.baseVal || element.className) + \" \").indexOf(\" \" + className + \" \") !== -1;\n}\n\nmodule.exports = exports[\"default\"];", + "'use strict';\n\nfunction replaceClassName(origClass, classToRemove) {\n return origClass.replace(new RegExp('(^|\\\\s)' + classToRemove + '(?:\\\\s|$)', 'g'), '$1').replace(/\\s+/g, ' ').replace(/^\\s*|\\s*$/g, '');\n}\n\nmodule.exports = function removeClass(element, className) {\n if (element.classList) element.classList.remove(className);else if (typeof element.className === 'string') element.className = replaceClassName(element.className, className);else element.setAttribute('class', replaceClassName(element.className && element.className.baseVal || '', className));\n};", + "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", + "// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction $getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return $getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the ` + "`") + (`throw` + ("`" + ` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `))) + (("`" + (`events` + "`")) + (` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = $getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n var args = [];\n for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n ReflectApply(this.listener, this.target, args);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n", + "'use strict';\n\n/**\n * Copyright 2015, Yahoo! Inc.\n * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.\n */\nvar ReactIs = require('react-is');\nvar REACT_STATICS = {\n childContextTypes: true,\n contextType: true,\n contextTypes: true,\n defaultProps: true,\n displayName: true,\n getDefaultProps: true,\n getDerivedStateFromError: true,\n getDerivedStateFromProps: true,\n mixins: true,\n propTypes: true,\n type: true\n};\n\nvar KNOWN_STATICS = {\n name: true,\n length: true,\n prototype: true,\n caller: true,\n callee: true,\n arguments: true,\n arity: true\n};\n\nvar FORWARD_REF_STATICS = {\n '$$typeof': true,\n render: true,\n defaultProps: true,\n displayName: true,\n propTypes: true\n};\n\nvar MEMO_STATICS = {\n '$$typeof': true,\n compare: true,\n defaultProps: true,\n displayName: true,\n propTypes: true,\n type: true\n};\n\nvar TYPE_STATICS = {};\nTYPE_STATICS[ReactIs.ForwardRef] = FORWARD_REF_STATICS;\n\nfunction getStatics(component) {\n if (ReactIs.isMemo(component)) {\n return MEMO_STATICS;\n }\n return TYPE_STATICS[component['$$typeof']] || REACT_STATICS;\n}\n\nvar defineProperty = Object.defineProperty;\nvar getOwnPropertyNames = Object.getOwnPropertyNames;\nvar getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\nvar getPrototypeOf = Object.getPrototypeOf;\nvar objectPrototype = Object.prototype;\n\nfunction hoistNonReactStatics(targetComponent, sourceComponent, blacklist) {\n if (typeof sourceComponent !== 'string') {\n // don't hoist over string (html) components\n\n if (objectPrototype) {\n var inheritedComponent = getPrototypeOf(sourceComponent);\n if (inheritedComponent && inheritedComponent !== objectPrototype) {\n hoistNonReactStatics(targetComponent, inheritedComponent, blacklist);\n }\n }\n\n var keys = getOwnPropertyNames(sourceComponent);\n\n if (getOwnPropertySymbols) {\n keys = keys.concat(getOwnPropertySymbols(sourceComponent));\n }\n\n var targetStatics = getStatics(targetComponent);\n var sourceStatics = getStatics(sourceComponent);\n\n for (var i = 0; i < keys.length; ++i) {\n var key = keys[i];\n if (!KNOWN_STATICS[key] && !(blacklist && blacklist[key]) && !(sourceStatics && sourceStatics[key]) && !(targetStatics && targetStatics[key])) {\n var descriptor = getOwnPropertyDescriptor(sourceComponent, key);\n try {\n // Avoid failures from read-only properties\n defineProperty(targetComponent, key, descriptor);\n } catch (e) {}\n }\n }\n\n return targetComponent;\n }\n\n return targetComponent;\n}\n\nmodule.exports = hoistNonReactStatics;\n", + "/* eslint-disable no-var, prefer-template */\nvar uppercasePattern = /[A-Z]/g\nvar msPattern = /^ms-/\nvar cache = {}\n\nfunction toHyphenLower(match) {\n return '-' + match.toLowerCase()\n}\n\nfunction hyphenateStyleName(name) {\n if (cache.hasOwnProperty(name)) {\n return cache[name]\n }\n\n var hName = name.replace(uppercasePattern, toHyphenLower)\n return (cache[name] = msPattern.test(hName) ? '-' + hName : hName)\n}\n\nexport default hyphenateStyleName\n", + "var _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nexport var isBrowser = (typeof window === \"undefined\" ? \"undefined\" : _typeof(window)) === \"object\" && (typeof document === \"undefined\" ? \"undefined\" : _typeof(document)) === 'object' && document.nodeType === 9;\n\nexport default isBrowser;\n", + "/*!\n * is-plain-object \n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n\n'use strict';\n\nvar isObject = require('isobject');\n\nfunction isObjectObject(o) {\n return isObject(o) === true\n && Object.prototype.toString.call(o) === '[object Object]';\n}\n\nmodule.exports = function isPlainObject(o) {\n var ctor,prot;\n\n if (isObjectObject(o) === false) return false;\n\n // If has modified constructor\n ctor = o.constructor;\n if (typeof ctor !== 'function') return false;\n\n // If has modified prototype\n prot = ctor.prototype;\n if (isObjectObject(prot) === false) return false;\n\n // If constructor does not have an Object-specific method\n if (prot.hasOwnProperty('isPrototypeOf') === false) {\n return false;\n }\n\n // Most likely a plain Object\n return true;\n};\n", + "/*!\n * isobject \n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n\n'use strict';\n\nmodule.exports = function isObject(val) {\n return val != null && typeof val === 'object' && Array.isArray(val) === false;\n};\n", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = camelCase;\n\nvar _hyphenateStyleName = require('hyphenate-style-name');\n\nvar _hyphenateStyleName2 = _interopRequireDefault(_hyphenateStyleName);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n/**\n * Convert camel cased property names to dash separated.\n *\n * @param {Object} style\n * @return {Object}\n */\nfunction convertCase(style) {\n var converted = {};\n\n for (var prop in style) {\n converted[(0, _hyphenateStyleName2['default'])(prop)] = style[prop];\n }\n\n if (style.fallbacks) {\n if (Array.isArray(style.fallbacks)) converted.fallbacks = style.fallbacks.map(convertCase);else converted.fallbacks = convertCase(style.fallbacks);\n }\n\n return converted;\n}\n\n/**\n * Allow camel cased property names by converting them back to dasherized.\n *\n * @param {Rule} rule\n */\nfunction camelCase() {\n function onProcessStyle(style) {\n if (Array.isArray(style)) {\n // Handle rules like @font-face, which can have multiple styles in an array\n for (var index = 0; index < style.length; index++) {\n style[index] = convertCase(style[index]);\n }\n return style;\n }\n\n return convertCase(style);\n }\n\n function onChangeValue(value, prop, rule) {\n var hyphenatedProp = (0, _hyphenateStyleName2['default'])(prop);\n\n // There was no camel case in place\n if (prop === hyphenatedProp) return value;\n\n rule.prop(hyphenatedProp, value);\n\n // Core will ignore that property value we set the proper one above.\n return null;\n }\n\n return { onProcessStyle: onProcessStyle, onChangeValue: onChangeValue };\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n/**\n * Generated jss-default-unit CSS property units\n *\n * @type object\n */\nexports['default'] = {\n 'animation-delay': 'ms',\n 'animation-duration': 'ms',\n 'background-position': 'px',\n 'background-position-x': 'px',\n 'background-position-y': 'px',\n 'background-size': 'px',\n border: 'px',\n 'border-bottom': 'px',\n 'border-bottom-left-radius': 'px',\n 'border-bottom-right-radius': 'px',\n 'border-bottom-width': 'px',\n 'border-left': 'px',\n 'border-left-width': 'px',\n 'border-radius': 'px',\n 'border-right': 'px',\n 'border-right-width': 'px',\n 'border-spacing': 'px',\n 'border-top': 'px',\n 'border-top-left-radius': 'px',\n 'border-top-right-radius': 'px',\n 'border-top-width': 'px',\n 'border-width': 'px',\n 'border-after-width': 'px',\n 'border-before-width': 'px',\n 'border-end-width': 'px',\n 'border-horizontal-spacing': 'px',\n 'border-start-width': 'px',\n 'border-vertical-spacing': 'px',\n bottom: 'px',\n 'box-shadow': 'px',\n 'column-gap': 'px',\n 'column-rule': 'px',\n 'column-rule-width': 'px',\n 'column-width': 'px',\n 'flex-basis': 'px',\n 'font-size': 'px',\n 'font-size-delta': 'px',\n height: 'px',\n left: 'px',\n 'letter-spacing': 'px',\n 'logical-height': 'px',\n 'logical-width': 'px',\n margin: 'px',\n 'margin-after': 'px',\n 'margin-before': 'px',\n 'margin-bottom': 'px',\n 'margin-left': 'px',\n 'margin-right': 'px',\n 'margin-top': 'px',\n 'max-height': 'px',\n 'max-width': 'px',\n 'margin-end': 'px',\n 'margin-start': 'px',\n 'mask-position-x': 'px',\n 'mask-position-y': 'px',\n 'mask-size': 'px',\n 'max-logical-height': 'px',\n 'max-logical-width': 'px',\n 'min-height': 'px',\n 'min-width': 'px',\n 'min-logical-height': 'px',\n 'min-logical-width': 'px',\n motion: 'px',\n 'motion-offset': 'px',\n outline: 'px',\n 'outline-offset': 'px',\n 'outline-width': 'px',\n padding: 'px',\n 'padding-bottom': 'px',\n 'padding-left': 'px',\n 'padding-right': 'px',\n 'padding-top': 'px',\n 'padding-after': 'px',\n 'padding-before': 'px',\n 'padding-end': 'px',\n 'padding-start': 'px',\n 'perspective-origin-x': '%',\n 'perspective-origin-y': '%',\n perspective: 'px',\n right: 'px',\n 'shape-margin': 'px',\n size: 'px',\n 'text-indent': 'px',\n 'text-stroke': 'px',\n 'text-stroke-width': 'px',\n top: 'px',\n 'transform-origin': '%',\n 'transform-origin-x': '%',\n 'transform-origin-y': '%',\n 'transform-origin-z': '%',\n 'transition-delay': 'ms',\n 'transition-duration': 'ms',\n 'vertical-align': 'px',\n width: 'px',\n 'word-spacing': 'px',\n // Not existing properties.\n // Used to avoid issues with jss-expand intergration.\n 'box-shadow-x': 'px',\n 'box-shadow-y': 'px',\n 'box-shadow-blur': 'px',\n 'box-shadow-spread': 'px',\n 'font-line-height': 'px',\n 'text-shadow-x': 'px',\n 'text-shadow-y': 'px',\n 'text-shadow-blur': 'px'\n};", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nexports['default'] = defaultUnit;\n\nvar _defaultUnits = require('./defaultUnits');\n\nvar _defaultUnits2 = _interopRequireDefault(_defaultUnits);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n/**\n * Clones the object and adds a camel cased property version.\n */\nfunction addCamelCasedVersion(obj) {\n var regExp = /(-[a-z])/g;\n var replace = function replace(str) {\n return str[1].toUpperCase();\n };\n var newObj = {};\n for (var key in obj) {\n newObj[key] = obj[key];\n newObj[key.replace(regExp, replace)] = obj[key];\n }\n return newObj;\n}\n\nvar units = addCamelCasedVersion(_defaultUnits2['default']);\n\n/**\n * Recursive deep style passing function\n *\n * @param {String} current property\n * @param {(Object|Array|Number|String)} property value\n * @param {Object} options\n * @return {(Object|Array|Number|String)} resulting value\n */\nfunction iterate(prop, value, options) {\n if (!value) return value;\n\n var convertedValue = value;\n\n var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);\n if (type === 'object' && Array.isArray(value)) type = 'array';\n\n switch (type) {\n case 'object':\n if (prop === 'fallbacks') {\n for (var innerProp in value) {\n value[innerProp] = iterate(innerProp, value[innerProp], options);\n }\n break;\n }\n for (var _innerProp in value) {\n value[_innerProp] = iterate(prop + '-' + _innerProp, value[_innerProp], options);\n }\n break;\n case 'array':\n for (var i = 0; i < value.length; i++) {\n value[i] = iterate(prop, value[i], options);\n }\n break;\n case 'number':\n if (value !== 0) {\n convertedValue = value + (options[prop] || units[prop] || '');\n }\n break;\n default:\n break;\n }\n\n return convertedValue;\n}\n\n/**\n * Add unit to numeric values.\n */\nfunction defaultUnit() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n var camelCasedOptions = addCamelCasedVersion(options);\n\n function onProcessStyle(style, rule) {\n if (rule.type !== 'style') return style;\n\n for (var prop in style) {\n style[prop] = iterate(prop, style[prop], camelCasedOptions);\n }\n\n return style;\n }\n\n function onChangeValue(value, prop) {\n return iterate(prop, value, camelCasedOptions);\n }\n\n return { onProcessStyle: onProcessStyle, onChangeValue: onChangeValue };\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nexports['default'] = jssGlobal;\n\nvar _jss = require('jss');\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar propKey = '@global';\nvar prefixKey = '@global ';\n\nvar GlobalContainerRule = function () {\n function GlobalContainerRule(key, styles, options) {\n _classCallCheck(this, GlobalContainerRule);\n\n this.type = 'global';\n\n this.key = key;\n this.options = options;\n this.rules = new _jss.RuleList(_extends({}, options, {\n parent: this\n }));\n\n for (var selector in styles) {\n this.rules.add(selector, styles[selector], { selector: selector });\n }\n\n this.rules.process();\n }\n\n /**\n * Get a rule.\n */\n\n\n _createClass(GlobalContainerRule, [{\n key: 'getRule',\n value: function getRule(name) {\n return this.rules.get(name);\n }\n\n /**\n * Create and register rule, run plugins.\n */\n\n }, {\n key: 'addRule',\n value: function addRule(name, style, options) {\n var rule = this.rules.add(name, style, options);\n this.options.jss.plugins.onProcessRule(rule);\n return rule;\n }\n\n /**\n * Get index of a rule.\n */\n\n }, {\n key: 'indexOf',\n value: function indexOf(rule) {\n return this.rules.indexOf(rule);\n }\n\n /**\n * Generates a CSS string.\n */\n\n }, {\n key: 'toString',\n value: function toString() {\n return this.rules.toString();\n }\n }]);\n\n return GlobalContainerRule;\n}();\n\nvar GlobalPrefixedRule = function () {\n function GlobalPrefixedRule(name, style, options) {\n _classCallCheck(this, GlobalPrefixedRule);\n\n this.name = name;\n this.options = options;\n var selector = name.substr(prefixKey.length);\n this.rule = options.jss.createRule(selector, style, _extends({}, options, {\n parent: this,\n selector: selector\n }));\n }\n\n _createClass(GlobalPrefixedRule, [{\n key: 'toString',\n value: function toString(options) {\n return this.rule.toString(options);\n }\n }]);\n\n return GlobalPrefixedRule;\n}();\n\nvar separatorRegExp = /\\s*,\\s*/g;\n\nfunction addScope(selector, scope) {\n var parts = selector.split(separatorRegExp);\n var scoped = '';\n for (var i = 0; i < parts.length; i++) {\n scoped += scope + ' ' + parts[i].trim();\n if (parts[i + 1]) scoped += ', ';\n }\n return scoped;\n}\n\nfunction handleNestedGlobalContainerRule(rule) {\n var options = rule.options,\n style = rule.style;\n\n var rules = style[propKey];\n\n if (!rules) return;\n\n for (var name in rules) {\n options.sheet.addRule(name, rules[name], _extends({}, options, {\n selector: addScope(name, rule.selector)\n }));\n }\n\n delete style[propKey];\n}\n\nfunction handlePrefixedGlobalRule(rule) {\n var options = rule.options,\n style = rule.style;\n\n for (var prop in style) {\n if (prop.substr(0, propKey.length) !== propKey) continue;\n\n var selector = addScope(prop.substr(propKey.length), rule.selector);\n options.sheet.addRule(selector, style[prop], _extends({}, options, {\n selector: selector\n }));\n delete style[prop];\n }\n}\n\n/**\n * Convert nested rules to separate, remove them from original styles.\n *\n * @param {Rule} rule\n * @api public\n */\nfunction jssGlobal() {\n function onCreateRule(name, styles, options) {\n if (name === propKey) {\n return new GlobalContainerRule(name, styles, options);\n }\n\n if (name[0] === '@' && name.substr(0, prefixKey.length) === prefixKey) {\n return new GlobalPrefixedRule(name, styles, options);\n }\n\n var parent = options.parent;\n\n\n if (parent) {\n if (parent.type === 'global' || parent.options.parent.type === 'global') {\n options.global = true;\n }\n }\n\n if (options.global) options.selector = name;\n\n return null;\n }\n\n function onProcessRule(rule) {\n if (rule.type !== 'style') return;\n\n handleNestedGlobalContainerRule(rule);\n handlePrefixedGlobalRule(rule);\n }\n\n return { onCreateRule: onCreateRule, onProcessRule: onProcessRule };\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nexports.default = jssNested;\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar separatorRegExp = /\\s*,\\s*/g;\nvar parentRegExp = /&/g;\nvar refRegExp = /\\$([\\w-]+)/g;\n\n/**\n * Convert nested rules to separate, remove them from original styles.\n *\n * @param {Rule} rule\n * @api public\n */\nfunction jssNested() {\n // Get a function to be used for $ref replacement.\n function getReplaceRef(container) {\n return function (match, key) {\n var rule = container.getRule(key);\n if (rule) return rule.selector;\n (0, _warning2.default)(false, '[JSS] Could not find the referenced rule %s in %s.', key, container.options.meta || container);\n return key;\n };\n }\n\n var hasAnd = function hasAnd(str) {\n return str.indexOf('&') !== -1;\n };\n\n function replaceParentRefs(nestedProp, parentProp) {\n var parentSelectors = parentProp.split(separatorRegExp);\n var nestedSelectors = nestedProp.split(separatorRegExp);\n\n var result = '';\n\n for (var i = 0; i < parentSelectors.length; i++) {\n var parent = parentSelectors[i];\n\n for (var j = 0; j < nestedSelectors.length; j++) {\n var nested = nestedSelectors[j];\n if (result) result += ', ';\n // Replace all & by the parent or prefix & with the parent.\n result += hasAnd(nested) ? nested.replace(parentRegExp, parent) : parent + ' ' + nested;\n }\n }\n\n return result;\n }\n\n function getOptions(rule, container, options) {\n // Options has been already created, now we only increase index.\n if (options) return _extends({}, options, { index: options.index + 1 });\n\n var nestingLevel = rule.options.nestingLevel;\n\n nestingLevel = nestingLevel === undefined ? 1 : nestingLevel + 1;\n\n return _extends({}, rule.options, {\n nestingLevel: nestingLevel,\n index: container.indexOf(rule) + 1\n });\n }\n\n function onProcessStyle(style, rule) {\n if (rule.type !== 'style') return style;\n var container = rule.options.parent;\n var options = void 0;\n var replaceRef = void 0;\n for (var prop in style) {\n var isNested = hasAnd(prop);\n var isNestedConditional = prop[0] === '@';\n\n if (!isNested && !isNestedConditional) continue;\n\n options = getOptions(rule, container, options);\n\n if (isNested) {\n var selector = replaceParentRefs(prop, rule.selector\n // Lazily create the ref replacer function just once for\n // all nested rules within the sheet.\n );if (!replaceRef) replaceRef = getReplaceRef(container\n // Replace all $refs.\n );selector = selector.replace(refRegExp, replaceRef);\n\n container.addRule(selector, style[prop], _extends({}, options, { selector: selector }));\n } else if (isNestedConditional) {\n container\n // Place conditional right after the parent rule to ensure right ordering.\n .addRule(prop, null, options).addRule(rule.key, style[prop], { selector: rule.selector });\n }\n\n delete style[prop];\n }\n\n return style;\n }\n\n return { onProcessStyle: onProcessStyle };\n}", + "/**\n * Copyright 2014-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n'use strict';\n\n/**\n * Similar to invariant but only logs a warning if the condition is not met.\n * This can be used to log issues in development environments in critical\n * paths. Removing the logging code for production environments will keep the\n * same logic and follow the same code paths.\n */\n\nvar warning = function() {};\n\nif (process.env.NODE_ENV !== 'production') {\n warning = function(condition, format, args) {\n var len = arguments.length;\n args = new Array(len > 2 ? len - 2 : 0);\n for (var key = 2; key < len; key++) {\n args[key - 2] = arguments[key];\n }\n if (format === undefined) {\n throw new Error(\n '` + ("`" + `warning(condition, format, ...args)`))))) + (((("`" + ` requires a warning ' +\n 'message argument'\n );\n }\n\n if (format.length < 10 || (/^[s\\W]*$/).test(format)) {\n throw new Error(\n 'The warning format should be able to uniquely identify this ' +\n 'warning. Please, use a more descriptive format than: ' + format\n );\n }\n\n if (!condition) {\n var argIndex = 0;\n var message = 'Warning: ' +\n format.replace(/%s/g, function() {\n return args[argIndex++];\n });\n if (typeof console !== 'undefined') {\n console.error(message);\n }\n try {\n // This error was thrown as a convenience so that you can use this stack\n // to find the callsite that caused this warning to fire.\n throw new Error(message);\n } catch(x) {}\n }\n };\n}\n\nmodule.exports = warning;\n", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = jssPropsSort;\n/**\n * Sort props by length.\n */\nfunction jssPropsSort() {\n function sort(prop0, prop1) {\n return prop0.length - prop1.length;\n }\n\n function onProcessStyle(style, rule) {\n if (rule.type !== 'style') return style;\n\n var newStyle = {};\n var props = Object.keys(style).sort(sort);\n for (var prop in props) {\n newStyle[props[prop]] = style[props[prop]];\n }\n return newStyle;\n }\n\n return { onProcessStyle: onProcessStyle };\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = jssVendorPrefixer;\n\nvar _cssVendor = require('css-vendor');\n\nvar vendor = _interopRequireWildcard(_cssVendor);\n\nfunction _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }\n\n/**\n * Add vendor prefix to a property name when needed.\n *\n * @param {Rule} rule\n * @api public\n */\nfunction jssVendorPrefixer() {\n function onProcessRule(rule) {\n if (rule.type === 'keyframes') {\n rule.key = '@' + vendor.prefix.css + rule.key.substr(1);\n }\n }\n\n function onProcessStyle(style, rule) {\n if (rule.type !== 'style') return style;\n\n for (var prop in style) {\n var value = style[prop];\n\n var changeProp = false;\n var supportedProp = vendor.supportedProperty(prop);\n if (supportedProp && supportedProp !== prop) changeProp = true;\n\n var changeValue = false;\n var supportedValue = vendor.supportedValue(supportedProp, value);\n if (supportedValue && supportedValue !== value) changeValue = true;\n\n if (changeProp || changeValue) {\n if (changeProp) delete style[prop];\n style[supportedProp || prop] = supportedValue || value;\n }\n }\n\n return style;\n }\n\n function onChangeValue(value, prop) {\n return vendor.supportedValue(prop, value);\n }\n\n return { onProcessRule: onProcessRule, onProcessStyle: onProcessStyle, onChangeValue: onChangeValue };\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _isInBrowser = require('is-in-browser');\n\nvar _isInBrowser2 = _interopRequireDefault(_isInBrowser);\n\nvar _StyleSheet = require('./StyleSheet');\n\nvar _StyleSheet2 = _interopRequireDefault(_StyleSheet);\n\nvar _PluginsRegistry = require('./PluginsRegistry');\n\nvar _PluginsRegistry2 = _interopRequireDefault(_PluginsRegistry);\n\nvar _rules = require('./plugins/rules');\n\nvar _rules2 = _interopRequireDefault(_rules);\n\nvar _observables = require('./plugins/observables');\n\nvar _observables2 = _interopRequireDefault(_observables);\n\nvar _functions = require('./plugins/functions');\n\nvar _functions2 = _interopRequireDefault(_functions);\n\nvar _sheets = require('./sheets');\n\nvar _sheets2 = _interopRequireDefault(_sheets);\n\nvar _StyleRule = require('./rules/StyleRule');\n\nvar _StyleRule2 = _interopRequireDefault(_StyleRule);\n\nvar _createGenerateClassName = require('./utils/createGenerateClassName');\n\nvar _createGenerateClassName2 = _interopRequireDefault(_createGenerateClassName);\n\nvar _createRule2 = require('./utils/createRule');\n\nvar _createRule3 = _interopRequireDefault(_createRule2);\n\nvar _DomRenderer = require('./renderers/DomRenderer');\n\nvar _DomRenderer2 = _interopRequireDefault(_DomRenderer);\n\nvar _VirtualRenderer = require('./renderers/VirtualRenderer');\n\nvar _VirtualRenderer2 = _interopRequireDefault(_VirtualRenderer);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar defaultPlugins = _rules2['default'].concat([_observables2['default'], _functions2['default']]);\n\nvar instanceCounter = 0;\n\nvar Jss = function () {\n function Jss(options) {\n _classCallCheck(this, Jss);\n\n this.id = instanceCounter++;\n this.version = \"9.8.7\";\n this.plugins = new _PluginsRegistry2['default']();\n this.options = {\n createGenerateClassName: _createGenerateClassName2['default'],\n Renderer: _isInBrowser2['default'] ? _DomRenderer2['default'] : _VirtualRenderer2['default'],\n plugins: []\n };\n this.generateClassName = (0, _createGenerateClassName2['default'])();\n\n // eslint-disable-next-line prefer-spread\n this.use.apply(this, defaultPlugins);\n this.setup(options);\n }\n\n _createClass(Jss, [{\n key: 'setup',\n value: function setup() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n if (options.createGenerateClassName) {\n this.options.createGenerateClassName = options.createGenerateClassName;\n // $FlowFixMe\n this.generateClassName = options.createGenerateClassName();\n }\n\n if (options.insertionPoint != null) this.options.insertionPoint = options.insertionPoint;\n if (options.virtual || options.Renderer) {\n this.options.Renderer = options.Renderer || (options.virtual ? _VirtualRenderer2['default'] : _DomRenderer2['default']);\n }\n\n // eslint-disable-next-line prefer-spread\n if (options.plugins) this.use.apply(this, options.plugins);\n\n return this;\n }\n\n /**\n * Create a Style Sheet.\n */\n\n }, {\n key: 'createStyleSheet',\n value: function createStyleSheet(styles) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n var index = options.index;\n if (typeof index !== 'number') {\n index = _sheets2['default'].index === 0 ? 0 : _sheets2['default'].index + 1;\n }\n var sheet = new _StyleSheet2['default'](styles, _extends({}, options, {\n jss: this,\n generateClassName: options.generateClassName || this.generateClassName,\n insertionPoint: this.options.insertionPoint,\n Renderer: this.options.Renderer,\n index: index\n }));\n this.plugins.onProcessSheet(sheet);\n\n return sheet;\n }\n\n /**\n * Detach the Style Sheet and remove it from the registry.\n */\n\n }, {\n key: 'removeStyleSheet',\n value: function removeStyleSheet(sheet) {\n sheet.detach();\n _sheets2['default'].remove(sheet);\n return this;\n }\n\n /**\n * Create a rule without a Style Sheet.\n */\n\n }, {\n key: 'createRule',\n value: function createRule(name) {\n var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Enable rule without name for inline styles.\n if ((typeof name === 'undefined' ? 'undefined' : _typeof(name)) === 'object') {\n options = style;\n style = name;\n name = undefined;\n }\n\n // Cast from RuleFactoryOptions to RuleOptions\n // https://stackoverflow.com/questions/41328728/force-casting-in-flow\n var ruleOptions = options;\n\n ruleOptions.jss = this;\n ruleOptions.Renderer = this.options.Renderer;\n if (!ruleOptions.generateClassName) ruleOptions.generateClassName = this.generateClassName;\n if (!ruleOptions.classes) ruleOptions.classes = {};\n var rule = (0, _createRule3['default'])(name, style, ruleOptions);\n\n if (!ruleOptions.selector && rule instanceof _StyleRule2['default']) {\n rule.selector = '.' + ruleOptions.generateClassName(rule);\n }\n\n this.plugins.onProcessRule(rule);\n\n return rule;\n }\n\n /**\n * Register plugin. Passed function will be invoked with a rule instance.\n */\n\n }, {\n key: 'use',\n value: function use() {\n var _this = this;\n\n for (var _len = arguments.length, plugins = Array(_len), _key = 0; _key < _len; _key++) {\n plugins[_key] = arguments[_key];\n }\n\n plugins.forEach(function (plugin) {\n // Avoids applying same plugin twice, at least based on ref.\n if (_this.options.plugins.indexOf(plugin) === -1) {\n _this.options.plugins.push(plugin);\n _this.plugins.use(plugin);\n }\n });\n\n return this;\n }\n }]);\n\n return Jss;\n}();\n\nexports['default'] = Jss;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar PluginsRegistry = function () {\n function PluginsRegistry() {\n _classCallCheck(this, PluginsRegistry);\n\n this.hooks = {\n onCreateRule: [],\n onProcessRule: [],\n onProcessStyle: [],\n onProcessSheet: [],\n onChangeValue: [],\n onUpdate: []\n\n /**\n * Call `) + ("`" + (`onCreateRule` + "`"))) + ((` hooks and return an object if returned by a hook.\n */\n };\n }\n\n _createClass(PluginsRegistry, [{\n key: 'onCreateRule',\n value: function onCreateRule(name, decl, options) {\n for (var i = 0; i < this.hooks.onCreateRule.length; i++) {\n var rule = this.hooks.onCreateRule[i](name, decl, options);\n if (rule) return rule;\n }\n return null;\n }\n\n /**\n * Call ` + ("`" + `onProcessRule`)) + ("`" + (` hooks.\n */\n\n }, {\n key: 'onProcessRule',\n value: function onProcessRule(rule) {\n if (rule.isProcessed) return;\n var sheet = rule.options.sheet;\n\n for (var i = 0; i < this.hooks.onProcessRule.length; i++) {\n this.hooks.onProcessRule[i](rule, sheet);\n }\n\n // $FlowFixMe\n if (rule.style) this.onProcessStyle(rule.style, rule, sheet);\n\n rule.isProcessed = true;\n }\n\n /**\n * Call ` + "`")))) + (((`onProcessStyle` + "`") + (` hooks.\n */\n\n }, {\n key: 'onProcessStyle',\n value: function onProcessStyle(style, rule, sheet) {\n var nextStyle = style;\n\n for (var i = 0; i < this.hooks.onProcessStyle.length; i++) {\n nextStyle = this.hooks.onProcessStyle[i](nextStyle, rule, sheet);\n // $FlowFixMe\n rule.style = nextStyle;\n }\n }\n\n /**\n * Call ` + ("`" + `onProcessSheet`))) + (("`" + (` hooks.\n */\n\n }, {\n key: 'onProcessSheet',\n value: function onProcessSheet(sheet) {\n for (var i = 0; i < this.hooks.onProcessSheet.length; i++) {\n this.hooks.onProcessSheet[i](sheet);\n }\n }\n\n /**\n * Call ` + "`")) + (`onUpdate` + ("`" + ` hooks.\n */\n\n }, {\n key: 'onUpdate',\n value: function onUpdate(data, rule, sheet) {\n for (var i = 0; i < this.hooks.onUpdate.length; i++) {\n this.hooks.onUpdate[i](data, rule, sheet);\n }\n }\n\n /**\n * Call `)))))) + ((((("`" + `onChangeValue`) + ("`" + (` hooks.\n */\n\n }, {\n key: 'onChangeValue',\n value: function onChangeValue(value, prop, rule) {\n var processedValue = value;\n for (var i = 0; i < this.hooks.onChangeValue.length; i++) {\n processedValue = this.hooks.onChangeValue[i](processedValue, prop, rule);\n }\n return processedValue;\n }\n\n /**\n * Register a plugin.\n * If function is passed, it is a shortcut for ` + "`"))) + ((`{onProcessRule}` + ("`" + `.\n */\n\n }, {\n key: 'use',\n value: function use(plugin) {\n for (var name in plugin) {\n if (this.hooks[name]) this.hooks[name].push(plugin[name]);else (0, _warning2['default'])(false, '[JSS] Unknown hook \"%s\".', name);\n }\n }\n }]);\n\n return PluginsRegistry;\n}();\n\nexports['default'] = PluginsRegistry;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _createRule = require('./utils/createRule');\n\nvar _createRule2 = _interopRequireDefault(_createRule);\n\nvar _linkRule = require('./utils/linkRule');\n\nvar _linkRule2 = _interopRequireDefault(_linkRule);\n\nvar _StyleRule = require('./rules/StyleRule');\n\nvar _StyleRule2 = _interopRequireDefault(_StyleRule);\n\nvar _escape = require('./utils/escape');\n\nvar _escape2 = _interopRequireDefault(_escape);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Contains rules objects and allows adding/removing etc.\n * Is used for e.g. by `)) + ("`" + (`StyleSheet` + "`")))) + (((` or ` + "`") + (`ConditionalRule` + ("`" + `.\n */\nvar RuleList = function () {\n\n // Original styles object.\n function RuleList(options) {\n var _this = this;\n\n _classCallCheck(this, RuleList);\n\n this.map = {};\n this.raw = {};\n this.index = [];\n\n this.update = function (name, data) {\n var _options = _this.options,\n plugins = _options.jss.plugins,\n sheet = _options.sheet;\n\n if (typeof name === 'string') {\n plugins.onUpdate(data, _this.get(name), sheet);\n } else {\n for (var index = 0; index < _this.index.length; index++) {\n plugins.onUpdate(name, _this.index[index], sheet);\n }\n }\n };\n\n this.options = options;\n this.classes = options.classes;\n }\n\n /**\n * Create and register rule.\n *\n * Will not render after Style Sheet was rendered the first time.\n */\n\n\n // Used to ensure correct rules order.\n\n // Rules registry for access by .get() method.\n // It contains the same rule registered by name and by selector.\n\n\n _createClass(RuleList, [{\n key: 'add',\n value: function add(name, decl, options) {\n var _options2 = this.options,\n parent = _options2.parent,\n sheet = _options2.sheet,\n jss = _options2.jss,\n Renderer = _options2.Renderer,\n generateClassName = _options2.generateClassName;\n\n\n options = _extends({\n classes: this.classes,\n parent: parent,\n sheet: sheet,\n jss: jss,\n Renderer: Renderer,\n generateClassName: generateClassName\n }, options);\n\n if (!options.selector && this.classes[name]) {\n options.selector = '.' + (0, _escape2['default'])(this.classes[name]);\n }\n\n this.raw[name] = decl;\n\n var rule = (0, _createRule2['default'])(name, decl, options);\n\n var className = void 0;\n\n if (!options.selector && rule instanceof _StyleRule2['default']) {\n className = generateClassName(rule, sheet);\n rule.selector = '.' + (0, _escape2['default'])(className);\n }\n\n this.register(rule, className);\n\n var index = options.index === undefined ? this.index.length : options.index;\n this.index.splice(index, 0, rule);\n\n return rule;\n }\n\n /**\n * Get a rule.\n */\n\n }, {\n key: 'get',\n value: function get(name) {\n return this.map[name];\n }\n\n /**\n * Delete a rule.\n */\n\n }, {\n key: 'remove',\n value: function remove(rule) {\n this.unregister(rule);\n this.index.splice(this.indexOf(rule), 1);\n }\n\n /**\n * Get index of a rule.\n */\n\n }, {\n key: 'indexOf',\n value: function indexOf(rule) {\n return this.index.indexOf(rule);\n }\n\n /**\n * Run `))) + (("`" + (`onProcessRule()` + "`")) + (` plugins on every rule.\n */\n\n }, {\n key: 'process',\n value: function process() {\n var plugins = this.options.jss.plugins;\n // We need to clone array because if we modify the index somewhere else during a loop\n // we end up with very hard-to-track-down side effects.\n\n this.index.slice(0).forEach(plugins.onProcessRule, plugins);\n }\n\n /**\n * Register a rule in ` + ("`" + `.map`))))) + (((("`" + ` and `) + ("`" + (`.classes` + "`"))) + ((` maps.\n */\n\n }, {\n key: 'register',\n value: function register(rule, className) {\n this.map[rule.key] = rule;\n if (rule instanceof _StyleRule2['default']) {\n this.map[rule.selector] = rule;\n if (className) this.classes[rule.key] = className;\n }\n }\n\n /**\n * Unregister a rule.\n */\n\n }, {\n key: 'unregister',\n value: function unregister(rule) {\n delete this.map[rule.key];\n if (rule instanceof _StyleRule2['default']) {\n delete this.map[rule.selector];\n delete this.classes[rule.key];\n }\n }\n\n /**\n * Update the function values with a new data.\n */\n\n }, {\n key: 'link',\n\n\n /**\n * Link renderable rules with CSSRuleList.\n */\n value: function link(cssRules) {\n var map = this.options.sheet.renderer.getUnescapedKeysMap(this.index);\n\n for (var i = 0; i < cssRules.length; i++) {\n var cssRule = cssRules[i];\n var _key = this.options.sheet.renderer.getKey(cssRule);\n if (map[_key]) _key = map[_key];\n var rule = this.map[_key];\n if (rule) (0, _linkRule2['default'])(rule, cssRule);\n }\n }\n\n /**\n * Convert rules to a CSS string.\n */\n\n }, {\n key: 'toString',\n value: function toString(options) {\n var str = '';\n var sheet = this.options.sheet;\n\n var link = sheet ? sheet.options.link : false;\n\n for (var index = 0; index < this.index.length; index++) {\n var rule = this.index[index];\n var css = rule.toString(options);\n\n // No need to render an empty rule.\n if (!css && !link) continue;\n\n if (str) str += '\\n';\n str += css;\n }\n\n return str;\n }\n }]);\n\n return RuleList;\n}();\n\nexports['default'] = RuleList;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * SheetsManager is like a WeakMap which is designed to count StyleSheet\n * instances and attach/detach automatically.\n */\nvar SheetsManager = function () {\n function SheetsManager() {\n _classCallCheck(this, SheetsManager);\n\n this.sheets = [];\n this.refs = [];\n this.keys = [];\n }\n\n _createClass(SheetsManager, [{\n key: 'get',\n value: function get(key) {\n var index = this.keys.indexOf(key);\n return this.sheets[index];\n }\n }, {\n key: 'add',\n value: function add(key, sheet) {\n var sheets = this.sheets,\n refs = this.refs,\n keys = this.keys;\n\n var index = sheets.indexOf(sheet);\n\n if (index !== -1) return index;\n\n sheets.push(sheet);\n refs.push(0);\n keys.push(key);\n\n return sheets.length - 1;\n }\n }, {\n key: 'manage',\n value: function manage(key) {\n var index = this.keys.indexOf(key);\n var sheet = this.sheets[index];\n if (this.refs[index] === 0) sheet.attach();\n this.refs[index]++;\n if (!this.keys[index]) this.keys.splice(index, 0, key);\n return sheet;\n }\n }, {\n key: 'unmanage',\n value: function unmanage(key) {\n var index = this.keys.indexOf(key);\n if (index === -1) {\n // eslint-ignore-next-line no-console\n (0, _warning2['default'])(false, \"SheetsManager: can't find sheet to unmanage\");\n return;\n }\n if (this.refs[index] > 0) {\n this.refs[index]--;\n if (this.refs[index] === 0) this.sheets[index].detach();\n }\n }\n }, {\n key: 'size',\n get: function get() {\n return this.keys.length;\n }\n }]);\n\n return SheetsManager;\n}();\n\nexports['default'] = SheetsManager;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Sheets registry to access them all at one place.\n */\nvar SheetsRegistry = function () {\n function SheetsRegistry() {\n _classCallCheck(this, SheetsRegistry);\n\n this.registry = [];\n }\n\n _createClass(SheetsRegistry, [{\n key: 'add',\n\n\n /**\n * Register a Style Sheet.\n */\n value: function add(sheet) {\n var registry = this.registry;\n var index = sheet.options.index;\n\n\n if (registry.indexOf(sheet) !== -1) return;\n\n if (registry.length === 0 || index >= this.index) {\n registry.push(sheet);\n return;\n }\n\n // Find a position.\n for (var i = 0; i < registry.length; i++) {\n if (registry[i].options.index > index) {\n registry.splice(i, 0, sheet);\n return;\n }\n }\n }\n\n /**\n * Reset the registry.\n */\n\n }, {\n key: 'reset',\n value: function reset() {\n this.registry = [];\n }\n\n /**\n * Remove a Style Sheet.\n */\n\n }, {\n key: 'remove',\n value: function remove(sheet) {\n var index = this.registry.indexOf(sheet);\n this.registry.splice(index, 1);\n }\n\n /**\n * Convert all attached sheets to a CSS string.\n */\n\n }, {\n key: 'toString',\n value: function toString(options) {\n return this.registry.filter(function (sheet) {\n return sheet.attached;\n }).map(function (sheet) {\n return sheet.toString(options);\n }).join('\\n');\n }\n }, {\n key: 'index',\n\n\n /**\n * Current highest index number.\n */\n get: function get() {\n return this.registry.length === 0 ? 0 : this.registry[this.registry.length - 1].options.index;\n }\n }]);\n\n return SheetsRegistry;\n}();\n\nexports['default'] = SheetsRegistry;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _linkRule = require('./utils/linkRule');\n\nvar _linkRule2 = _interopRequireDefault(_linkRule);\n\nvar _RuleList = require('./RuleList');\n\nvar _RuleList2 = _interopRequireDefault(_RuleList);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/* eslint-disable-next-line no-use-before-define */\nvar StyleSheet = function () {\n function StyleSheet(styles, options) {\n var _this = this;\n\n _classCallCheck(this, StyleSheet);\n\n this.update = function (name, data) {\n if (typeof name === 'string') {\n _this.rules.update(name, data);\n } else {\n _this.rules.update(name);\n }\n return _this;\n };\n\n this.attached = false;\n this.deployed = false;\n this.linked = false;\n this.classes = {};\n this.options = _extends({}, options, {\n sheet: this,\n parent: this,\n classes: this.classes\n });\n this.renderer = new options.Renderer(this);\n this.rules = new _RuleList2['default'](this.options);\n\n for (var _name in styles) {\n this.rules.add(_name, styles[_name]);\n }\n\n this.rules.process();\n }\n\n /**\n * Attach renderable to the render tree.\n */\n\n\n _createClass(StyleSheet, [{\n key: 'attach',\n value: function attach() {\n if (this.attached) return this;\n if (!this.deployed) this.deploy();\n this.renderer.attach();\n if (!this.linked && this.options.link) this.link();\n this.attached = true;\n return this;\n }\n\n /**\n * Remove renderable from render tree.\n */\n\n }, {\n key: 'detach',\n value: function detach() {\n if (!this.attached) return this;\n this.renderer.detach();\n this.attached = false;\n return this;\n }\n\n /**\n * Add a rule to the current stylesheet.\n * Will insert a rule also after the stylesheet has been rendered first time.\n */\n\n }, {\n key: 'addRule',\n value: function addRule(name, decl, options) {\n var queue = this.queue;\n\n // Plugins can create rules.\n // In order to preserve the right order, we need to queue all ` + ("`" + `.addRule`)) + ("`" + (` calls,\n // which happen after the first ` + "`")))) + (((`rules.add()` + "`") + (` call.\n\n if (this.attached && !queue) this.queue = [];\n\n var rule = this.rules.add(name, decl, options);\n this.options.jss.plugins.onProcessRule(rule);\n\n if (this.attached) {\n if (!this.deployed) return rule;\n // Don't insert rule directly if there is no stringified version yet.\n // It will be inserted all together when .attach is called.\n if (queue) queue.push(rule);else {\n this.insertRule(rule);\n if (this.queue) {\n this.queue.forEach(this.insertRule, this);\n this.queue = undefined;\n }\n }\n return rule;\n }\n\n // We can't add rules to a detached style node.\n // We will redeploy the sheet once user will attach it.\n this.deployed = false;\n\n return rule;\n }\n\n /**\n * Insert rule into the StyleSheet\n */\n\n }, {\n key: 'insertRule',\n value: function insertRule(rule) {\n var renderable = this.renderer.insertRule(rule);\n if (renderable && this.options.link) (0, _linkRule2['default'])(rule, renderable);\n }\n\n /**\n * Create and add rules.\n * Will render also after Style Sheet was rendered the first time.\n */\n\n }, {\n key: 'addRules',\n value: function addRules(styles, options) {\n var added = [];\n for (var _name2 in styles) {\n added.push(this.addRule(_name2, styles[_name2], options));\n }\n return added;\n }\n\n /**\n * Get a rule by name.\n */\n\n }, {\n key: 'getRule',\n value: function getRule(name) {\n return this.rules.get(name);\n }\n\n /**\n * Delete a rule by name.\n * Returns ` + ("`" + `true`))) + (("`" + (`: if rule has been deleted from the DOM.\n */\n\n }, {\n key: 'deleteRule',\n value: function deleteRule(name) {\n var rule = this.rules.get(name);\n\n if (!rule) return false;\n\n this.rules.remove(rule);\n\n if (this.attached && rule.renderable) {\n return this.renderer.deleteRule(rule.renderable);\n }\n\n return true;\n }\n\n /**\n * Get index of a rule.\n */\n\n }, {\n key: 'indexOf',\n value: function indexOf(rule) {\n return this.rules.indexOf(rule);\n }\n\n /**\n * Deploy pure CSS string to a renderable.\n */\n\n }, {\n key: 'deploy',\n value: function deploy() {\n this.renderer.deploy();\n this.deployed = true;\n return this;\n }\n\n /**\n * Link renderable CSS rules from sheet with their corresponding models.\n */\n\n }, {\n key: 'link',\n value: function link() {\n var cssRules = this.renderer.getRules();\n\n // Is undefined when VirtualRenderer is used.\n if (cssRules) this.rules.link(cssRules);\n this.linked = true;\n return this;\n }\n\n /**\n * Update the function values with a new data.\n */\n\n }, {\n key: 'toString',\n\n\n /**\n * Convert rules to a CSS string.\n */\n value: function toString(options) {\n return this.rules.toString(options);\n }\n }]);\n\n return StyleSheet;\n}();\n\nexports['default'] = StyleSheet;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.create = exports.createGenerateClassName = exports.sheets = exports.RuleList = exports.SheetsManager = exports.SheetsRegistry = exports.toCssValue = exports.getDynamicStyles = undefined;\n\nvar _getDynamicStyles = require('./utils/getDynamicStyles');\n\nObject.defineProperty(exports, 'getDynamicStyles', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_getDynamicStyles)['default'];\n }\n});\n\nvar _toCssValue = require('./utils/toCssValue');\n\nObject.defineProperty(exports, 'toCssValue', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_toCssValue)['default'];\n }\n});\n\nvar _SheetsRegistry = require('./SheetsRegistry');\n\nObject.defineProperty(exports, 'SheetsRegistry', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_SheetsRegistry)['default'];\n }\n});\n\nvar _SheetsManager = require('./SheetsManager');\n\nObject.defineProperty(exports, 'SheetsManager', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_SheetsManager)['default'];\n }\n});\n\nvar _RuleList = require('./RuleList');\n\nObject.defineProperty(exports, 'RuleList', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_RuleList)['default'];\n }\n});\n\nvar _sheets = require('./sheets');\n\nObject.defineProperty(exports, 'sheets', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_sheets)['default'];\n }\n});\n\nvar _createGenerateClassName = require('./utils/createGenerateClassName');\n\nObject.defineProperty(exports, 'createGenerateClassName', {\n enumerable: true,\n get: function get() {\n return _interopRequireDefault(_createGenerateClassName)['default'];\n }\n});\n\nvar _Jss = require('./Jss');\n\nvar _Jss2 = _interopRequireDefault(_Jss);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n/**\n * Creates a new instance of Jss.\n */\nvar create = exports.create = function create(options) {\n return new _Jss2['default'](options);\n};\n\n/**\n * A global Jss instance.\n */\nexports['default'] = create();", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _RuleList = require('../RuleList');\n\nvar _RuleList2 = _interopRequireDefault(_RuleList);\n\nvar _StyleRule = require('../rules/StyleRule');\n\nvar _StyleRule2 = _interopRequireDefault(_StyleRule);\n\nvar _createRule = require('../utils/createRule');\n\nvar _createRule2 = _interopRequireDefault(_createRule);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n// A symbol replacement.\nvar now = Date.now();\n\nvar fnValuesNs = 'fnValues' + now;\nvar fnStyleNs = 'fnStyle' + ++now;\n\nexports['default'] = {\n onCreateRule: function onCreateRule(name, decl, options) {\n if (typeof decl !== 'function') return null;\n var rule = (0, _createRule2['default'])(name, {}, options);\n rule[fnStyleNs] = decl;\n return rule;\n },\n onProcessStyle: function onProcessStyle(style, rule) {\n var fn = {};\n for (var prop in style) {\n var value = style[prop];\n if (typeof value !== 'function') continue;\n delete style[prop];\n fn[prop] = value;\n }\n rule = rule;\n rule[fnValuesNs] = fn;\n return style;\n },\n onUpdate: function onUpdate(data, rule) {\n // It is a rules container like for e.g. ConditionalRule.\n if (rule.rules instanceof _RuleList2['default']) {\n rule.rules.update(data);\n return;\n }\n if (!(rule instanceof _StyleRule2['default'])) return;\n\n rule = rule;\n\n // If we have a fn values map, it is a rule with function values.\n if (rule[fnValuesNs]) {\n for (var prop in rule[fnValuesNs]) {\n rule.prop(prop, rule[fnValuesNs][prop](data));\n }\n }\n\n rule = rule;\n\n var fnStyle = rule[fnStyleNs];\n\n // If we have a style function, the entire rule is dynamic and style object\n // will be returned from that function.\n if (fnStyle) {\n var style = fnStyle(data);\n for (var _prop in style) {\n rule.prop(_prop, style[_prop]);\n }\n }\n }\n};", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _StyleRule = require('../rules/StyleRule');\n\nvar _StyleRule2 = _interopRequireDefault(_StyleRule);\n\nvar _createRule = require('../utils/createRule');\n\nvar _createRule2 = _interopRequireDefault(_createRule);\n\nvar _isObservable = require('../utils/isObservable');\n\nvar _isObservable2 = _interopRequireDefault(_isObservable);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nexports['default'] = {\n onCreateRule: function onCreateRule(name, decl, options) {\n if (!(0, _isObservable2['default'])(decl)) return null;\n\n // Cast ` + "`")) + (`decl` + ("`" + ` to `))))))) + (((((("`" + `Observable`) + ("`" + (`, since it passed the type guard.\n var style$ = decl;\n\n var rule = (0, _createRule2['default'])(name, {}, options);\n\n // TODO\n // Call ` + "`"))) + ((`stream.subscribe()` + ("`" + ` returns a subscription, which should be explicitly\n // unsubscribed from when we know this sheet is no longer needed.\n style$.subscribe(function (style) {\n for (var prop in style) {\n rule.prop(prop, style[prop]);\n }\n });\n\n return rule;\n },\n onProcessRule: function onProcessRule(rule) {\n if (!(rule instanceof _StyleRule2['default'])) return;\n var styleRule = rule;\n var style = styleRule.style;\n\n var _loop = function _loop(prop) {\n var value = style[prop];\n if (!(0, _isObservable2['default'])(value)) return 'continue';\n delete style[prop];\n value.subscribe({\n next: function next(nextValue) {\n styleRule.prop(prop, nextValue);\n }\n });\n };\n\n for (var prop in style) {\n var _ret = _loop(prop);\n\n if (_ret === 'continue') continue;\n }\n }\n};", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _SimpleRule = require('../rules/SimpleRule');\n\nvar _SimpleRule2 = _interopRequireDefault(_SimpleRule);\n\nvar _KeyframesRule = require('../rules/KeyframesRule');\n\nvar _KeyframesRule2 = _interopRequireDefault(_KeyframesRule);\n\nvar _ConditionalRule = require('../rules/ConditionalRule');\n\nvar _ConditionalRule2 = _interopRequireDefault(_ConditionalRule);\n\nvar _FontFaceRule = require('../rules/FontFaceRule');\n\nvar _FontFaceRule2 = _interopRequireDefault(_FontFaceRule);\n\nvar _ViewportRule = require('../rules/ViewportRule');\n\nvar _ViewportRule2 = _interopRequireDefault(_ViewportRule);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar classes = {\n '@charset': _SimpleRule2['default'],\n '@import': _SimpleRule2['default'],\n '@namespace': _SimpleRule2['default'],\n '@keyframes': _KeyframesRule2['default'],\n '@media': _ConditionalRule2['default'],\n '@supports': _ConditionalRule2['default'],\n '@font-face': _FontFaceRule2['default'],\n '@viewport': _ViewportRule2['default'],\n '@-ms-viewport': _ViewportRule2['default']\n\n /**\n * Generate plugins which will register all rules.\n */\n};\nvar plugins = Object.keys(classes).map(function (key) {\n // https://jsperf.com/indexof-vs-substr-vs-regex-at-the-beginning-3\n var re = new RegExp('^' + key);\n var RuleClass = classes[key];\n var onCreateRule = function onCreateRule(name, decl, options) {\n return re.test(name) ? new RuleClass(name, decl, options) : null;\n };\n return { onCreateRule: onCreateRule };\n});\n\nexports['default'] = plugins;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _sheets = require('../sheets');\n\nvar _sheets2 = _interopRequireDefault(_sheets);\n\nvar _StyleRule = require('../rules/StyleRule');\n\nvar _StyleRule2 = _interopRequireDefault(_StyleRule);\n\nvar _toCssValue = require('../utils/toCssValue');\n\nvar _toCssValue2 = _interopRequireDefault(_toCssValue);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Cache the value from the first time a function is called.\n */\nvar memoize = function memoize(fn) {\n var value = void 0;\n return function () {\n if (!value) value = fn();\n return value;\n };\n};\n\n/**\n * Get a style property value.\n */\nfunction getPropertyValue(cssRule, prop) {\n try {\n return cssRule.style.getPropertyValue(prop);\n } catch (err) {\n // IE may throw if property is unknown.\n return '';\n }\n}\n\n/**\n * Set a style property.\n */\nfunction setProperty(cssRule, prop, value) {\n try {\n var cssValue = value;\n\n if (Array.isArray(value)) {\n cssValue = (0, _toCssValue2['default'])(value, true);\n\n if (value[value.length - 1] === '!important') {\n cssRule.style.setProperty(prop, cssValue, 'important');\n return true;\n }\n }\n\n cssRule.style.setProperty(prop, cssValue);\n } catch (err) {\n // IE may throw if property is unknown.\n return false;\n }\n return true;\n}\n\n/**\n * Remove a style property.\n */\nfunction removeProperty(cssRule, prop) {\n try {\n cssRule.style.removeProperty(prop);\n } catch (err) {\n (0, _warning2['default'])(false, '[JSS] DOMException \"%s\" was thrown. Tried to remove property \"%s\".', err.message, prop);\n }\n}\n\nvar CSSRuleTypes = {\n STYLE_RULE: 1,\n KEYFRAMES_RULE: 7\n\n /**\n * Get the CSS Rule key.\n */\n\n};var getKey = function () {\n var extractKey = function extractKey(cssText) {\n var from = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n return cssText.substr(from, cssText.indexOf('{') - 1);\n };\n\n return function (cssRule) {\n if (cssRule.type === CSSRuleTypes.STYLE_RULE) return cssRule.selectorText;\n if (cssRule.type === CSSRuleTypes.KEYFRAMES_RULE) {\n var name = cssRule.name;\n\n if (name) return '@keyframes ' + name;\n\n // There is no rule.name in the following browsers:\n // - IE 9\n // - Safari 7.1.8\n // - Mobile Safari 9.0.0\n var cssText = cssRule.cssText;\n\n return '@' + extractKey(cssText, cssText.indexOf('keyframes'));\n }\n\n // Conditionals.\n return extractKey(cssRule.cssText);\n };\n}();\n\n/**\n * Set the selector.\n */\nfunction setSelector(cssRule, selectorText) {\n cssRule.selectorText = selectorText;\n\n // Return false if setter was not successful.\n // Currently works in chrome only.\n return cssRule.selectorText === selectorText;\n}\n\n/**\n * Gets the `)) + ("`" + (`head` + "`")))) + (((` element upon the first call and caches it.\n */\nvar getHead = memoize(function () {\n return document.head || document.getElementsByTagName('head')[0];\n});\n\n/**\n * Gets a map of rule keys, where the property is an unescaped key and value\n * is a potentially escaped one.\n * It is used to identify CSS rules and the corresponding JSS rules. As an identifier\n * for CSSStyleRule we normally use ` + "`") + (`selectorText` + ("`" + `. Though if original selector text\n * contains escaped code points e.g. `))) + (("`" + (`:not(#\\\\20)` + "`")) + (`, CSSOM will compile it to ` + ("`" + `:not(# )`))))) + (((("`" + `\n * and so CSS rule's `) + ("`" + (`selectorText` + "`"))) + ((` won't match JSS rule selector.\n *\n * https://www.w3.org/International/questions/qa-escapes#cssescapes\n */\nvar getUnescapedKeysMap = function () {\n var style = void 0;\n var isAttached = false;\n\n return function (rules) {\n var map = {};\n // https://github.com/facebook/flow/issues/2696\n if (!style) style = document.createElement('style');\n for (var i = 0; i < rules.length; i++) {\n var rule = rules[i];\n if (!(rule instanceof _StyleRule2['default'])) continue;\n var selector = rule.selector;\n // Only unescape selector over CSSOM if it contains a back slash.\n\n if (selector && selector.indexOf('\\\\') !== -1) {\n // Lazilly attach when needed.\n if (!isAttached) {\n getHead().appendChild(style);\n isAttached = true;\n }\n style.textContent = selector + ' {}';\n var _style = style,\n sheet = _style.sheet;\n\n if (sheet) {\n var cssRules = sheet.cssRules;\n\n if (cssRules) map[cssRules[0].selectorText] = rule.key;\n }\n }\n }\n if (isAttached) {\n getHead().removeChild(style);\n isAttached = false;\n }\n return map;\n };\n}();\n\n/**\n * Find attached sheet with an index higher than the passed one.\n */\nfunction findHigherSheet(registry, options) {\n for (var i = 0; i < registry.length; i++) {\n var sheet = registry[i];\n if (sheet.attached && sheet.options.index > options.index && sheet.options.insertionPoint === options.insertionPoint) {\n return sheet;\n }\n }\n return null;\n}\n\n/**\n * Find attached sheet with the highest index.\n */\nfunction findHighestSheet(registry, options) {\n for (var i = registry.length - 1; i >= 0; i--) {\n var sheet = registry[i];\n if (sheet.attached && sheet.options.insertionPoint === options.insertionPoint) {\n return sheet;\n }\n }\n return null;\n}\n\n/**\n * Find a comment with \"jss\" inside.\n */\nfunction findCommentNode(text) {\n var head = getHead();\n for (var i = 0; i < head.childNodes.length; i++) {\n var node = head.childNodes[i];\n if (node.nodeType === 8 && node.nodeValue.trim() === text) {\n return node;\n }\n }\n return null;\n}\n\n/**\n * Find a node before which we can insert the sheet.\n */\nfunction findPrevNode(options) {\n var registry = _sheets2['default'].registry;\n\n\n if (registry.length > 0) {\n // Try to insert before the next higher sheet.\n var sheet = findHigherSheet(registry, options);\n if (sheet) return sheet.renderer.element;\n\n // Otherwise insert after the last attached.\n sheet = findHighestSheet(registry, options);\n if (sheet) return sheet.renderer.element.nextElementSibling;\n }\n\n // Try to find a comment placeholder if registry is empty.\n var insertionPoint = options.insertionPoint;\n\n if (insertionPoint && typeof insertionPoint === 'string') {\n var comment = findCommentNode(insertionPoint);\n if (comment) return comment.nextSibling;\n // If user specifies an insertion point and it can't be found in the document -\n // bad specificity issues may appear.\n (0, _warning2['default'])(insertionPoint === 'jss', '[JSS] Insertion point \"%s\" not found.', insertionPoint);\n }\n\n return null;\n}\n\n/**\n * Insert style element into the DOM.\n */\nfunction insertStyle(style, options) {\n var insertionPoint = options.insertionPoint;\n\n var prevNode = findPrevNode(options);\n\n if (prevNode) {\n var parentNode = prevNode.parentNode;\n\n if (parentNode) parentNode.insertBefore(style, prevNode);\n return;\n }\n\n // Works with iframes and any node types.\n if (insertionPoint && typeof insertionPoint.nodeType === 'number') {\n // https://stackoverflow.com/questions/41328728/force-casting-in-flow\n var insertionPointElement = insertionPoint;\n var _parentNode = insertionPointElement.parentNode;\n\n if (_parentNode) _parentNode.insertBefore(style, insertionPointElement.nextSibling);else (0, _warning2['default'])(false, '[JSS] Insertion point is not in the DOM.');\n return;\n }\n\n getHead().insertBefore(style, prevNode);\n}\n\n/**\n * Read jss nonce setting from the page if the user has set it.\n */\nvar getNonce = memoize(function () {\n var node = document.querySelector('meta[property=\"csp-nonce\"]');\n return node ? node.getAttribute('content') : null;\n});\n\nvar DomRenderer = function () {\n function DomRenderer(sheet) {\n _classCallCheck(this, DomRenderer);\n\n this.getPropertyValue = getPropertyValue;\n this.setProperty = setProperty;\n this.removeProperty = removeProperty;\n this.setSelector = setSelector;\n this.getKey = getKey;\n this.getUnescapedKeysMap = getUnescapedKeysMap;\n this.hasInsertedRules = false;\n\n // There is no sheet when the renderer is used from a standalone StyleRule.\n if (sheet) _sheets2['default'].add(sheet);\n\n this.sheet = sheet;\n\n var _ref = this.sheet ? this.sheet.options : {},\n media = _ref.media,\n meta = _ref.meta,\n element = _ref.element;\n\n this.element = element || document.createElement('style');\n this.element.setAttribute('data-jss', '');\n if (media) this.element.setAttribute('media', media);\n if (meta) this.element.setAttribute('data-meta', meta);\n var nonce = getNonce();\n if (nonce) this.element.setAttribute('nonce', nonce);\n }\n\n /**\n * Insert style element into render tree.\n */\n\n\n // HTMLStyleElement needs fixing https://github.com/facebook/flow/issues/2696\n\n\n _createClass(DomRenderer, [{\n key: 'attach',\n value: function attach() {\n // In the case the element node is external and it is already in the DOM.\n if (this.element.parentNode || !this.sheet) return;\n\n // When rules are inserted using ` + ("`" + `insertRule`)) + ("`" + (` API, after ` + "`")))) + (((`sheet.detach().attach()` + "`") + (`\n // browsers remove those rules.\n // TODO figure out if its a bug and if it is known.\n // Workaround is to redeploy the sheet before attaching as a string.\n if (this.hasInsertedRules) {\n this.deploy();\n this.hasInsertedRules = false;\n }\n\n insertStyle(this.element, this.sheet.options);\n }\n\n /**\n * Remove style element from render tree.\n */\n\n }, {\n key: 'detach',\n value: function detach() {\n this.element.parentNode.removeChild(this.element);\n }\n\n /**\n * Inject CSS string into element.\n */\n\n }, {\n key: 'deploy',\n value: function deploy() {\n if (!this.sheet) return;\n this.element.textContent = '\\n' + this.sheet.toString() + '\\n';\n }\n\n /**\n * Insert a rule into element.\n */\n\n }, {\n key: 'insertRule',\n value: function insertRule(rule, index) {\n var sheet = this.element.sheet;\n var cssRules = sheet.cssRules;\n\n var str = rule.toString();\n if (!index) index = cssRules.length;\n\n if (!str) return false;\n\n try {\n sheet.insertRule(str, index);\n } catch (err) {\n (0, _warning2['default'])(false, '[JSS] Can not insert an unsupported rule \\n\\r%s', rule);\n return false;\n }\n this.hasInsertedRules = true;\n\n return cssRules[index];\n }\n\n /**\n * Delete a rule.\n */\n\n }, {\n key: 'deleteRule',\n value: function deleteRule(cssRule) {\n var sheet = this.element.sheet;\n\n var index = this.indexOf(cssRule);\n if (index === -1) return false;\n sheet.deleteRule(index);\n return true;\n }\n\n /**\n * Get index of a CSS Rule.\n */\n\n }, {\n key: 'indexOf',\n value: function indexOf(cssRule) {\n var cssRules = this.element.sheet.cssRules;\n\n for (var _index = 0; _index < cssRules.length; _index++) {\n if (cssRule === cssRules[_index]) return _index;\n }\n return -1;\n }\n\n /**\n * Generate a new CSS rule and replace the existing one.\n */\n\n }, {\n key: 'replaceRule',\n value: function replaceRule(cssRule, rule) {\n var index = this.indexOf(cssRule);\n var newCssRule = this.insertRule(rule, index);\n this.element.sheet.deleteRule(index);\n return newCssRule;\n }\n\n /**\n * Get all rules elements.\n */\n\n }, {\n key: 'getRules',\n value: function getRules() {\n return this.element.sheet.cssRules;\n }\n }]);\n\n return DomRenderer;\n}();\n\nexports['default'] = DomRenderer;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/* eslint-disable class-methods-use-this */\n\n/**\n * Rendering backend to do nothing in nodejs.\n */\nvar VirtualRenderer = function () {\n function VirtualRenderer() {\n _classCallCheck(this, VirtualRenderer);\n }\n\n _createClass(VirtualRenderer, [{\n key: 'setProperty',\n value: function setProperty() {\n return true;\n }\n }, {\n key: 'getPropertyValue',\n value: function getPropertyValue() {\n return '';\n }\n }, {\n key: 'removeProperty',\n value: function removeProperty() {}\n }, {\n key: 'setSelector',\n value: function setSelector() {\n return true;\n }\n }, {\n key: 'getKey',\n value: function getKey() {\n return '';\n }\n }, {\n key: 'attach',\n value: function attach() {}\n }, {\n key: 'detach',\n value: function detach() {}\n }, {\n key: 'deploy',\n value: function deploy() {}\n }, {\n key: 'insertRule',\n value: function insertRule() {\n return false;\n }\n }, {\n key: 'deleteRule',\n value: function deleteRule() {\n return true;\n }\n }, {\n key: 'replaceRule',\n value: function replaceRule() {\n return false;\n }\n }, {\n key: 'getRules',\n value: function getRules() {}\n }, {\n key: 'indexOf',\n value: function indexOf() {\n return -1;\n }\n }]);\n\n return VirtualRenderer;\n}();\n\nexports['default'] = VirtualRenderer;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _RuleList = require('../RuleList');\n\nvar _RuleList2 = _interopRequireDefault(_RuleList);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Conditional rule for @media, @supports\n */\nvar ConditionalRule = function () {\n function ConditionalRule(key, styles, options) {\n _classCallCheck(this, ConditionalRule);\n\n this.type = 'conditional';\n this.isProcessed = false;\n\n this.key = key;\n this.options = options;\n this.rules = new _RuleList2['default'](_extends({}, options, { parent: this }));\n\n for (var name in styles) {\n this.rules.add(name, styles[name]);\n }\n\n this.rules.process();\n }\n\n /**\n * Get a rule.\n */\n\n\n _createClass(ConditionalRule, [{\n key: 'getRule',\n value: function getRule(name) {\n return this.rules.get(name);\n }\n\n /**\n * Get index of a rule.\n */\n\n }, {\n key: 'indexOf',\n value: function indexOf(rule) {\n return this.rules.indexOf(rule);\n }\n\n /**\n * Create and register rule, run plugins.\n */\n\n }, {\n key: 'addRule',\n value: function addRule(name, style, options) {\n var rule = this.rules.add(name, style, options);\n this.options.jss.plugins.onProcessRule(rule);\n return rule;\n }\n\n /**\n * Generates a CSS string.\n */\n\n }, {\n key: 'toString',\n value: function toString() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { indent: 1 };\n\n var inner = this.rules.toString(options);\n return inner ? this.key + ' {\\n' + inner + '\\n}' : '';\n }\n }]);\n\n return ConditionalRule;\n}();\n\nexports['default'] = ConditionalRule;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _toCss = require('../utils/toCss');\n\nvar _toCss2 = _interopRequireDefault(_toCss);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar FontFaceRule = function () {\n function FontFaceRule(key, style, options) {\n _classCallCheck(this, FontFaceRule);\n\n this.type = 'font-face';\n this.isProcessed = false;\n\n this.key = key;\n this.style = style;\n this.options = options;\n }\n\n /**\n * Generates a CSS string.\n */\n\n\n _createClass(FontFaceRule, [{\n key: 'toString',\n value: function toString(options) {\n if (Array.isArray(this.style)) {\n var str = '';\n for (var index = 0; index < this.style.length; index++) {\n str += (0, _toCss2['default'])(this.key, this.style[index]);\n if (this.style[index + 1]) str += '\\n';\n }\n return str;\n }\n\n return (0, _toCss2['default'])(this.key, this.style, options);\n }\n }]);\n\n return FontFaceRule;\n}();\n\nexports['default'] = FontFaceRule;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _RuleList = require('../RuleList');\n\nvar _RuleList2 = _interopRequireDefault(_RuleList);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Rule for @keyframes\n */\nvar KeyframesRule = function () {\n function KeyframesRule(key, frames, options) {\n _classCallCheck(this, KeyframesRule);\n\n this.type = 'keyframes';\n this.isProcessed = false;\n\n this.key = key;\n this.options = options;\n this.rules = new _RuleList2['default'](_extends({}, options, { parent: this }));\n\n for (var name in frames) {\n this.rules.add(name, frames[name], _extends({}, this.options, {\n parent: this,\n selector: name\n }));\n }\n\n this.rules.process();\n }\n\n /**\n * Generates a CSS string.\n */\n\n\n _createClass(KeyframesRule, [{\n key: 'toString',\n value: function toString() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { indent: 1 };\n\n var inner = this.rules.toString(options);\n if (inner) inner += '\\n';\n return this.key + ' {\\n' + inner + '}';\n }\n }]);\n\n return KeyframesRule;\n}();\n\nexports['default'] = KeyframesRule;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar SimpleRule = function () {\n function SimpleRule(key, value, options) {\n _classCallCheck(this, SimpleRule);\n\n this.type = 'simple';\n this.isProcessed = false;\n\n this.key = key;\n this.value = value;\n this.options = options;\n }\n\n /**\n * Generates a CSS string.\n */\n // eslint-disable-next-line no-unused-vars\n\n\n _createClass(SimpleRule, [{\n key: 'toString',\n value: function toString(options) {\n if (Array.isArray(this.value)) {\n var str = '';\n for (var index = 0; index < this.value.length; index++) {\n str += this.key + ' ' + this.value[index] + ';';\n if (this.value[index + 1]) str += '\\n';\n }\n return str;\n }\n\n return this.key + ' ' + this.value + ';';\n }\n }]);\n\n return SimpleRule;\n}();\n\nexports['default'] = SimpleRule;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _toCss = require('../utils/toCss');\n\nvar _toCss2 = _interopRequireDefault(_toCss);\n\nvar _toCssValue = require('../utils/toCssValue');\n\nvar _toCssValue2 = _interopRequireDefault(_toCssValue);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar StyleRule = function () {\n function StyleRule(key, style, options) {\n _classCallCheck(this, StyleRule);\n\n this.type = 'style';\n this.isProcessed = false;\n var sheet = options.sheet,\n Renderer = options.Renderer,\n selector = options.selector;\n\n this.key = key;\n this.options = options;\n this.style = style;\n if (selector) this.selectorText = selector;\n this.renderer = sheet ? sheet.renderer : new Renderer();\n }\n\n /**\n * Set selector string.\n * Attention: use this with caution. Most browsers didn't implement\n * selectorText setter, so this may result in rerendering of entire Style Sheet.\n */\n\n\n _createClass(StyleRule, [{\n key: 'prop',\n\n\n /**\n * Get or set a style property.\n */\n value: function prop(name, value) {\n // It's a getter.\n if (value === undefined) return this.style[name];\n\n // Don't do anything if the value has not changed.\n if (this.style[name] === value) return this;\n\n value = this.options.jss.plugins.onChangeValue(value, name, this);\n\n var isEmpty = value == null || value === false;\n var isDefined = name in this.style;\n\n // Value is empty and wasn't defined before.\n if (isEmpty && !isDefined) return this;\n\n // We are going to remove this value.\n var remove = isEmpty && isDefined;\n\n if (remove) delete this.style[name];else this.style[name] = value;\n\n // Renderable is defined if StyleSheet option ` + ("`" + `link`))) + (("`" + (` is true.\n if (this.renderable) {\n if (remove) this.renderer.removeProperty(this.renderable, name);else this.renderer.setProperty(this.renderable, name, value);\n return this;\n }\n\n var sheet = this.options.sheet;\n\n if (sheet && sheet.attached) {\n (0, _warning2['default'])(false, 'Rule is not linked. Missing sheet option \"link: true\".');\n }\n return this;\n }\n\n /**\n * Apply rule to an element inline.\n */\n\n }, {\n key: 'applyTo',\n value: function applyTo(renderable) {\n var json = this.toJSON();\n for (var prop in json) {\n this.renderer.setProperty(renderable, prop, json[prop]);\n }return this;\n }\n\n /**\n * Returns JSON representation of the rule.\n * Fallbacks are not supported.\n * Useful for inline styles.\n */\n\n }, {\n key: 'toJSON',\n value: function toJSON() {\n var json = {};\n for (var prop in this.style) {\n var value = this.style[prop];\n if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object') json[prop] = value;else if (Array.isArray(value)) json[prop] = (0, _toCssValue2['default'])(value);\n }\n return json;\n }\n\n /**\n * Generates a CSS string.\n */\n\n }, {\n key: 'toString',\n value: function toString(options) {\n var sheet = this.options.sheet;\n\n var link = sheet ? sheet.options.link : false;\n var opts = link ? _extends({}, options, { allowEmpty: true }) : options;\n return (0, _toCss2['default'])(this.selector, this.style, opts);\n }\n }, {\n key: 'selector',\n set: function set(selector) {\n if (selector === this.selectorText) return;\n\n this.selectorText = selector;\n\n if (!this.renderable) return;\n\n var hasChanged = this.renderer.setSelector(this.renderable, selector);\n\n // If selector setter is not implemented, rerender the rule.\n if (!hasChanged && this.renderable) {\n var renderable = this.renderer.replaceRule(this.renderable, this);\n if (renderable) this.renderable = renderable;\n }\n }\n\n /**\n * Get selector string.\n */\n ,\n get: function get() {\n return this.selectorText;\n }\n }]);\n\n return StyleRule;\n}();\n\nexports['default'] = StyleRule;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _toCss = require('../utils/toCss');\n\nvar _toCss2 = _interopRequireDefault(_toCss);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar ViewportRule = function () {\n function ViewportRule(key, style, options) {\n _classCallCheck(this, ViewportRule);\n\n this.type = 'viewport';\n this.isProcessed = false;\n\n this.key = key;\n this.style = style;\n this.options = options;\n }\n\n /**\n * Generates a CSS string.\n */\n\n\n _createClass(ViewportRule, [{\n key: 'toString',\n value: function toString(options) {\n return (0, _toCss2['default'])(this.key, this.style, options);\n }\n }]);\n\n return ViewportRule;\n}();\n\nexports['default'] = ViewportRule;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _SheetsRegistry = require('./SheetsRegistry');\n\nvar _SheetsRegistry2 = _interopRequireDefault(_SheetsRegistry);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n/**\n * This is a global sheets registry. Only DomRenderer will add sheets to it.\n * On the server one should use an own SheetsRegistry instance and add the\n * sheets to it, because you need to make sure to create a new registry for\n * each request in order to not leak sheets across requests.\n */\nexports['default'] = new _SheetsRegistry2['default']();", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nexports['default'] = cloneStyle;\n\nvar _isObservable = require('./isObservable');\n\nvar _isObservable2 = _interopRequireDefault(_isObservable);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar isArray = Array.isArray;\nfunction cloneStyle(style) {\n // Support empty values in case user ends up with them by accident.\n if (style == null) return style;\n\n // Support string value for SimpleRule.\n var typeOfStyle = typeof style === 'undefined' ? 'undefined' : _typeof(style);\n\n if (typeOfStyle === 'string' || typeOfStyle === 'number' || typeOfStyle === 'function') {\n return style;\n }\n\n // Support array for FontFaceRule.\n if (isArray(style)) return style.map(cloneStyle);\n\n // Support Observable styles. Observables are immutable, so we don't need to\n // copy them.\n if ((0, _isObservable2['default'])(style)) return style;\n\n var newStyle = {};\n for (var name in style) {\n var value = style[name];\n if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') {\n newStyle[name] = cloneStyle(value);\n continue;\n }\n newStyle[name] = value;\n }\n\n return newStyle;\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _StyleSheet = require('../StyleSheet');\n\nvar _StyleSheet2 = _interopRequireDefault(_StyleSheet);\n\nvar _moduleId = require('./moduleId');\n\nvar _moduleId2 = _interopRequireDefault(_moduleId);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar maxRules = 1e10;\n\n\nvar env = process.env.NODE_ENV;\n\n/**\n * Returns a function which generates unique class names based on counters.\n * When new generator function is created, rule counter is reseted.\n * We need to reset the rule counter for SSR for each request.\n */\n\nexports['default'] = function () {\n var ruleCounter = 0;\n var defaultPrefix = env === 'production' ? 'c' : '';\n\n return function (rule, sheet) {\n ruleCounter += 1;\n\n if (ruleCounter > maxRules) {\n (0, _warning2['default'])(false, '[JSS] You might have a memory leak. Rule counter is at %s.', ruleCounter);\n }\n\n var prefix = defaultPrefix;\n var jssId = '';\n\n if (sheet) {\n prefix = sheet.options.classNamePrefix || defaultPrefix;\n if (sheet.options.jss.id != null) jssId += sheet.options.jss.id;\n }\n\n if (env === 'production') {\n return '' + prefix + _moduleId2['default'] + jssId + ruleCounter;\n }\n\n return prefix + rule.key + '-' + _moduleId2['default'] + (jssId && '-' + jssId) + '-' + ruleCounter;\n };\n};", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = createRule;\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _StyleRule = require('../rules/StyleRule');\n\nvar _StyleRule2 = _interopRequireDefault(_StyleRule);\n\nvar _cloneStyle = require('../utils/cloneStyle');\n\nvar _cloneStyle2 = _interopRequireDefault(_cloneStyle);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n/**\n * Create a rule instance.\n */\nfunction createRule() {\n var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'unnamed';\n var decl = arguments[1];\n var options = arguments[2];\n var jss = options.jss;\n\n var declCopy = (0, _cloneStyle2['default'])(decl);\n\n var rule = jss.plugins.onCreateRule(name, declCopy, options);\n if (rule) return rule;\n\n // It is an at-rule and it has no instance.\n if (name[0] === '@') {\n (0, _warning2['default'])(false, '[JSS] Unknown at-rule %s', name);\n }\n\n return new _StyleRule2['default'](name, declCopy, options);\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nvar CSS = global.CSS;\n\nvar env = process.env.NODE_ENV;\n\nvar escapeRegex = /([[\\].#*$><+~=|^:(),\"'` + "`")) + (`])/g;\n\nexports['default'] = function (str) {\n // We don't need to escape it in production, because we are not using user's\n // input for selectors, we are generating a valid selector.\n if (env === 'production') return str;\n\n if (!CSS || !CSS.escape) {\n return str.replace(escapeRegex, '\\\\$1');\n }\n\n return CSS.escape(str);\n};", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nexports['default'] = getDynamicStyles;\n/**\n * Extracts a styles object with only props that contain function values.\n */\nfunction getDynamicStyles(styles) {\n var to = null;\n\n for (var key in styles) {\n var value = styles[key];\n var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);\n\n if (type === 'function') {\n if (!to) to = {};\n to[key] = value;\n } else if (type === 'object' && value !== null && !Array.isArray(value)) {\n var extracted = getDynamicStyles(value);\n if (extracted) {\n if (!to) to = {};\n to[key] = extracted;\n }\n }\n }\n\n return to;\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _symbolObservable = require('symbol-observable');\n\nvar _symbolObservable2 = _interopRequireDefault(_symbolObservable);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nexports['default'] = function (value) {\n return value && value[_symbolObservable2['default']] && value === value[_symbolObservable2['default']]();\n};", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports[\"default\"] = linkRule;\n/**\n * Link rule with CSSStyleRule and nested rules with corresponding nested cssRules if both exists.\n */\nfunction linkRule(rule, cssRule) {\n rule.renderable = cssRule;\n if (rule.rules && cssRule.cssRules) rule.rules.link(cssRule.cssRules);\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nvar ns = '2f1acc6c3a606b082e5eef5e54414ffb';\nif (global[ns] == null) global[ns] = 0;\n\n// Bundle may contain multiple JSS versions at the same time. In order to identify\n// the current version with just one short number and use it for classes generation\n// we use a counter. Also it is more accurate, because user can manually reevaluate\n// the module.\nexports['default'] = global[ns]++;", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = toCss;\n\nvar _toCssValue = require('./toCssValue');\n\nvar _toCssValue2 = _interopRequireDefault(_toCssValue);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n/**\n * Indent a string.\n * http://jsperf.com/array-join-vs-for\n */\nfunction indentStr(str, indent) {\n var result = '';\n for (var index = 0; index < indent; index++) {\n result += ' ';\n }return result + str;\n}\n\n/**\n * Converts a Rule to CSS string.\n */\n\nfunction toCss(selector, style) {\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n var result = '';\n\n if (!style) return result;\n\n var _options$indent = options.indent,\n indent = _options$indent === undefined ? 0 : _options$indent;\n var fallbacks = style.fallbacks;\n\n\n indent++;\n\n // Apply fallbacks first.\n if (fallbacks) {\n // Array syntax {fallbacks: [{prop: value}]}\n if (Array.isArray(fallbacks)) {\n for (var index = 0; index < fallbacks.length; index++) {\n var fallback = fallbacks[index];\n for (var prop in fallback) {\n var value = fallback[prop];\n if (value != null) {\n result += '\\n' + indentStr(prop + ': ' + (0, _toCssValue2['default'])(value) + ';', indent);\n }\n }\n }\n } else {\n // Object syntax {fallbacks: {prop: value}}\n for (var _prop in fallbacks) {\n var _value = fallbacks[_prop];\n if (_value != null) {\n result += '\\n' + indentStr(_prop + ': ' + (0, _toCssValue2['default'])(_value) + ';', indent);\n }\n }\n }\n }\n\n for (var _prop2 in style) {\n var _value2 = style[_prop2];\n if (_value2 != null && _prop2 !== 'fallbacks') {\n result += '\\n' + indentStr(_prop2 + ': ' + (0, _toCssValue2['default'])(_value2) + ';', indent);\n }\n }\n\n // Allow empty style in this case, because properties will be added dynamically.\n if (!result && !options.allowEmpty) return result;\n\n indent--;\n result = indentStr(selector + ' {' + result + '\\n', indent) + indentStr('}', indent);\n\n return result;\n}", + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports['default'] = toCssValue;\nvar join = function join(value, by) {\n var result = '';\n for (var i = 0; i < value.length; i++) {\n // Remove !important from the value, it will be readded later.\n if (value[i] === '!important') break;\n if (result) result += by;\n result += value[i];\n }\n return result;\n};\n\n/**\n * Converts array values to string.\n *\n * ` + ("`" + `margin: [['5px', '10px']]`)))))) + ((((("`" + ` > `) + ("`" + (`margin: 5px 10px;` + "`"))) + ((`\n * ` + ("`" + `border: ['1px', '2px']`)) + ("`" + (` > ` + "`")))) + (((`border: 1px, 2px;` + "`") + (`\n * ` + ("`" + `margin: [['5px', '10px'], '!important']`))) + (("`" + (` > ` + "`")) + (`margin: 5px 10px !important;` + ("`" + `\n * `))))) + (((("`" + `color: ['red', !important]`) + ("`" + (` > ` + "`"))) + ((`color: red !important;` + ("`" + `\n */\nfunction toCssValue(value) {\n var ignoreImportant = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n if (!Array.isArray(value)) return value;\n\n var cssValue = '';\n\n // Support space separated values via `)) + ("`" + (`[['5px', '10px']]` + "`")))) + (((`.\n if (Array.isArray(value[0])) {\n for (var i = 0; i < value.length; i++) {\n if (value[i] === '!important') break;\n if (cssValue) cssValue += ', ';\n cssValue += join(value[i], ' ');\n }\n } else cssValue = join(value, ', ');\n\n // Add !important, because it was ignored.\n if (!ignoreImportant && value[value.length - 1] === '!important') {\n cssValue += ' !important';\n }\n\n return cssValue;\n}", + "/**\n * Copyright 2014-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n'use strict';\n\n/**\n * Similar to invariant but only logs a warning if the condition is not met.\n * This can be used to log issues in development environments in critical\n * paths. Removing the logging code for production environments will keep the\n * same logic and follow the same code paths.\n */\n\nvar warning = function() {};\n\nif (process.env.NODE_ENV !== 'production') {\n warning = function(condition, format, args) {\n var len = arguments.length;\n args = new Array(len > 2 ? len - 2 : 0);\n for (var key = 2; key < len; key++) {\n args[key - 2] = arguments[key];\n }\n if (format === undefined) {\n throw new Error(\n '` + ("`" + `warning(condition, format, ...args)`)) + ("`" + (` requires a warning ' +\n 'message argument'\n );\n }\n\n if (format.length < 10 || (/^[s\\W]*$/).test(format)) {\n throw new Error(\n 'The warning format should be able to uniquely identify this ' +\n 'warning. Please, use a more descriptive format than: ' + format\n );\n }\n\n if (!condition) {\n var argIndex = 0;\n var message = 'Warning: ' +\n format.replace(/%s/g, function() {\n return args[argIndex++];\n });\n if (typeof console !== 'undefined') {\n console.error(message);\n }\n try {\n // This error was thrown as a convenience so that you can use this stack\n // to find the callsite that caused this warning to fire.\n throw new Error(message);\n } catch(x) {}\n }\n };\n}\n\nmodule.exports = warning;\n", + "/**\n * lodash (Custom Build) \n * Build: ` + "`"))) + ((`lodash modularize exports=\"npm\" -o ./` + ("`" + `\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the `)) + ("`" + (`TypeError` + "`"))))))))) + ((((((((` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various ` + "`") + (`Number` + ("`" + ` constants. */\nvar NAN = 0 / 0;\n\n/** `))) + (("`" + (`Object#toString` + "`")) + (` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on ` + ("`" + `root`)))) + ((("`" + `. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable `) + ("`" + (`global` + "`"))) + ((` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable ` + ("`" + `self`)) + ("`" + (`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [` + "`"))))) + ((((`toStringTag` + "`") + (`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other ` + ("`" + `lodash`))) + (("`" + (` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\n/**\n * Creates a debounced function that delays invoking ` + "`")) + (`func` + ("`" + ` until after `)))) + ((("`" + `wait`) + ("`" + (`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a ` + "`"))) + ((`cancel` + ("`" + ` method to cancel\n * delayed `)) + ("`" + (`func` + "`")))))) + (((((` invocations and a ` + "`") + (`flush` + ("`" + ` method to immediately invoke them.\n * Provide `))) + (("`" + (`options` + "`")) + (` to indicate whether ` + ("`" + `func`)))) + ((("`" + ` should be invoked on the\n * leading and/or trailing edge of the `) + ("`" + (`wait` + "`"))) + ((` timeout. The ` + ("`" + `func`)) + ("`" + (` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last ` + "`"))))) + ((((`func` + "`") + (`\n * invocation.\n *\n * **Note:** If ` + ("`" + `leading`))) + (("`" + (` and ` + "`")) + (`trailing` + ("`" + ` options are `)))) + ((("`" + `true`) + ("`" + (`, ` + "`"))) + ((`func` + ("`" + ` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `)) + ("`" + (`wait` + "`"))))))) + ((((((` timeout.\n *\n * If ` + "`") + (`wait` + ("`" + ` is `))) + (("`" + (`0` + "`")) + (` and ` + ("`" + `leading`)))) + ((("`" + ` is `) + ("`" + (`false` + "`"))) + ((`, ` + ("`" + `func`)) + ("`" + (` invocation is deferred\n * until to the next tick, similar to ` + "`"))))) + ((((`setTimeout` + "`") + (` with a timeout of ` + ("`" + `0`))) + (("`" + (`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between ` + "`")) + (`_.debounce` + ("`" + ` and `)))) + ((("`" + `_.throttle`) + ("`" + (`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time ` + "`"))) + ((`func` + ("`" + ` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `)) + ("`" + (`sendMail` + "`")))))) + (((((` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure ` + "`") + (`batchLog` + ("`" + ` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `))) + (("`" + (`maxWait` + "`")) + (` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n result = wait - timeSinceLastCall;\n\n return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the ` + ("`" + `maxWait`)))) + ((("`" + ` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `) + ("`" + (`lastArgs` + "`"))) + ((` which means ` + ("`" + `func`)) + ("`" + (` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\n/**\n * Checks if ` + "`"))))) + ((((`value` + "`") + (` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of ` + ("`" + `Object`))) + (("`" + (`. (e.g. arrays, functions, objects, regexes, ` + "`")) + (`new Number(0)` + ("`" + `, and `)))) + ((("`" + (`new String('')` + "`")) + (`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if ` + "`")) + (`value` + ("`" + ` is an object, else `)))))))) + ((((((("`" + `false`) + ("`" + (`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if ` + "`"))) + ((`value` + ("`" + ` is object-like. A value is object-like if it's not `)) + ("`" + (`null` + "`")))) + (((`\n * and has a ` + "`") + (`typeof` + ("`" + ` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `))) + (("`" + (`true` + "`")) + (` if ` + ("`" + `value`))))) + (((("`" + ` is object-like, else `) + ("`" + (`false` + "`"))) + ((`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if ` + ("`" + `value`)) + ("`" + (` is classified as a ` + "`")))) + (((`Symbol` + "`") + (` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if ` + "`")) + (`value` + ("`" + ` is a symbol, else `)))))) + ((((("`" + `false`) + ("`" + (`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts ` + "`"))) + ((`value` + ("`" + ` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = debounce;\n", + "/**\n * lodash (Custom Build) \n * Build: `)) + ("`" + (`lodash modularize exports=\"npm\" -o ./` + "`")))) + (((`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the ` + "`") + (`TypeError` + ("`" + ` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various `))) + (("`" + (`Number` + "`")) + (` constants. */\nvar NAN = 0 / 0;\n\n/** ` + ("`" + `Object#toString`))))) + (((("`" + ` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `) + ("`" + (`root` + "`"))) + ((`. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable ` + ("`" + `global`)) + ("`" + (` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable ` + "`")))) + (((`self` + ("`" + `. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`)) + ("`" + (`toStringTag` + "`"))) + ((`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other ` + ("`" + `lodash`)) + ("`" + (` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\n/**\n * Creates a debounced function that delays invoking ` + "`"))))))) + ((((((`func` + "`") + (` until after ` + ("`" + `wait`))) + (("`" + (`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a ` + "`")) + (`cancel` + ("`" + ` method to cancel\n * delayed `)))) + ((("`" + `func`) + ("`" + (` invocations and a ` + "`"))) + ((`flush` + ("`" + ` method to immediately invoke them.\n * Provide `)) + ("`" + (`options` + "`"))))) + ((((` to indicate whether ` + "`") + (`func` + ("`" + ` should be invoked on the\n * leading and/or trailing edge of the `))) + (("`" + (`wait` + "`")) + (` timeout. The ` + ("`" + `func`)))) + ((("`" + ` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `) + ("`" + (`func` + "`"))) + ((`\n * invocation.\n *\n * **Note:** If ` + ("`" + `leading`)) + ("`" + (` and ` + "`")))))) + (((((`trailing` + "`") + (` options are ` + ("`" + `true`))) + (("`" + (`, ` + "`")) + (`func` + ("`" + ` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `)))) + ((("`" + `wait`) + ("`" + (` timeout.\n *\n * If ` + "`"))) + ((`wait` + ("`" + ` is `)) + ("`" + (`0` + "`"))))) + ((((` and ` + "`") + (`leading` + ("`" + ` is `))) + (("`" + (`false` + "`")) + (`, ` + ("`" + `func`)))) + ((("`" + (` invocation is deferred\n * until to the next tick, similar to ` + "`")) + (`setTimeout` + ("`" + ` with a timeout of `))) + (("`" + (`0` + "`")) + (`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between ` + ("`" + `_.debounce`)))))))))) + ((((((((("`" + ` and `) + ("`" + (`_.throttle` + "`"))) + ((`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time ` + ("`" + `func`)) + ("`" + (` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke ` + "`")))) + (((`sendMail` + "`") + (` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure ` + ("`" + `batchLog`))) + (("`" + (` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any ` + "`")) + (`maxWait` + ("`" + ` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n result = wait - timeSinceLastCall;\n\n return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `))))) + (((("`" + `maxWait`) + ("`" + (` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have ` + "`"))) + ((`lastArgs` + ("`" + ` which means `)) + ("`" + (`func` + "`")))) + (((` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\n/**\n * Creates a throttled function that only invokes ` + "`") + (`func` + ("`" + ` at most once per\n * every `))) + (("`" + (`wait` + "`")) + (` milliseconds. The throttled function comes with a ` + ("`" + `cancel`)))))) + ((((("`" + `\n * method to cancel delayed `) + ("`" + (`func` + "`"))) + ((` invocations and a ` + ("`" + `flush`)) + ("`" + (` method to\n * immediately invoke them. Provide ` + "`")))) + (((`options` + "`") + (` to indicate whether ` + ("`" + `func`))) + (("`" + (`\n * should be invoked on the leading and/or trailing edge of the ` + "`")) + (`wait` + ("`" + `\n * timeout. The `))))) + (((("`" + `func`) + ("`" + (` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last ` + "`"))) + ((`func` + ("`" + ` invocation.\n *\n * **Note:** If `)) + ("`" + (`leading` + "`")))) + (((` and ` + "`") + (`trailing` + ("`" + ` options are `))) + (("`" + (`true` + "`")) + (`, ` + ("`" + `func`))))))) + (((((("`" + ` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `) + ("`" + (`wait` + "`"))) + ((` timeout.\n *\n * If ` + ("`" + `wait`)) + ("`" + (` is ` + "`")))) + (((`0` + "`") + (` and ` + ("`" + `leading`))) + (("`" + (` is ` + "`")) + (`false` + ("`" + `, `))))) + (((("`" + `func`) + ("`" + (` invocation is deferred\n * until to the next tick, similar to ` + "`"))) + ((`setTimeout` + ("`" + ` with a timeout of `)) + ("`" + (`0` + "`")))) + (((`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between ` + "`") + (`_.throttle` + ("`" + ` and `))) + (("`" + (`_.debounce` + "`")) + (`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke ` + ("`" + `renewToken`)))))) + ((((("`" + ` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\n/**\n * Checks if `) + ("`" + (`value` + "`"))) + ((` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of ` + ("`" + `Object`)) + ("`" + (`. (e.g. arrays, functions, objects, regexes, ` + "`")))) + (((`new Number(0)` + "`") + (`, and ` + ("`" + `new String('')`))) + (("`" + (`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`")) + (`true` + ("`" + ` if `))))) + (((("`" + `value`) + ("`" + (` is an object, else ` + "`"))) + ((`false` + ("`" + `.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `)) + ("`" + (`value` + "`")))) + (((` is object-like. A value is object-like if it's not ` + ("`" + `null`)) + ("`" + (`\n * and has a ` + "`"))) + ((`typeof` + ("`" + ` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`")))))))) + (((((((` if ` + "`") + (`value` + ("`" + ` is object-like, else `))) + (("`" + (`false` + "`")) + (`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if ` + ("`" + `value`)))) + ((("`" + ` is classified as a `) + ("`" + (`Symbol` + "`"))) + ((` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`)) + ("`" + (` if ` + "`"))))) + ((((`value` + "`") + (` is a symbol, else ` + ("`" + `false`))) + (("`" + (`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts ` + "`")) + (`value` + ("`" + ` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = throttle;\n", + "var getNative = require('./_getNative'),\n root = require('./_root');\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nmodule.exports = DataView;\n", + "var hashClear = require('./_hashClear'),\n hashDelete = require('./_hashDelete'),\n hashGet = require('./_hashGet'),\n hashHas = require('./_hashHas'),\n hashSet = require('./_hashSet');\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `)))) + ((("`" + `Hash`) + ("`" + (`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nmodule.exports = Hash;\n", + "var listCacheClear = require('./_listCacheClear'),\n listCacheDelete = require('./_listCacheDelete'),\n listCacheGet = require('./_listCacheGet'),\n listCacheHas = require('./_listCacheHas'),\n listCacheSet = require('./_listCacheSet');\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to ` + "`"))) + ((`ListCache` + ("`" + `.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nmodule.exports = ListCache;\n", + "var getNative = require('./_getNative'),\n root = require('./_root');\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nmodule.exports = Map;\n", + "var mapCacheClear = require('./_mapCacheClear'),\n mapCacheDelete = require('./_mapCacheDelete'),\n mapCacheGet = require('./_mapCacheGet'),\n mapCacheHas = require('./_mapCacheHas'),\n mapCacheSet = require('./_mapCacheSet');\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `)) + ("`" + (`MapCache` + "`")))))) + (((((`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nmodule.exports = MapCache;\n", + "var getNative = require('./_getNative'),\n root = require('./_root');\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nmodule.exports = Promise;\n", + "var getNative = require('./_getNative'),\n root = require('./_root');\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nmodule.exports = Set;\n", + "var MapCache = require('./_MapCache'),\n setCacheAdd = require('./_setCacheAdd'),\n setCacheHas = require('./_setCacheHas');\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n var index = -1,\n length = values == null ? 0 : values.length;\n\n this.__data__ = new MapCache;\n while (++index < length) {\n this.add(values[index]);\n }\n}\n\n// Add methods to ` + "`") + (`SetCache` + ("`" + `.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\nmodule.exports = SetCache;\n", + "var ListCache = require('./_ListCache'),\n stackClear = require('./_stackClear'),\n stackDelete = require('./_stackDelete'),\n stackGet = require('./_stackGet'),\n stackHas = require('./_stackHas'),\n stackSet = require('./_stackSet');\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n// Add methods to `))) + (("`" + (`Stack` + "`")) + (`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nmodule.exports = Stack;\n", + "var root = require('./_root');\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nmodule.exports = Symbol;\n", + "var root = require('./_root');\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nmodule.exports = Uint8Array;\n", + "var getNative = require('./_getNative'),\n root = require('./_root');\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nmodule.exports = WeakMap;\n", + "/**\n * A faster alternative to ` + ("`" + `Function#apply`)))) + ((("`" + `, this function invokes `) + ("`" + (`func` + "`"))) + ((`\n * with the ` + ("`" + `this`)) + ("`" + (` binding of ` + "`"))))) + ((((`thisArg` + "`") + (` and the arguments of ` + ("`" + `args`))) + (("`" + (`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The ` + "`")) + (`this` + ("`" + ` binding of `)))) + ((("`" + `func`) + ("`" + (`.\n * @param {Array} args The arguments to invoke ` + "`"))) + ((`func` + ("`" + ` with.\n * @returns {*} Returns the result of `)) + ("`" + (`func` + "`"))))))) + ((((((`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nmodule.exports = apply;\n", + "/**\n * A specialized version of ` + "`") + (`_.every` + ("`" + ` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `))) + (("`" + (`true` + "`")) + (` if all elements pass the predicate check,\n * else ` + ("`" + `false`)))) + ((("`" + `.\n */\nfunction arrayEvery(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (!predicate(array[index], index, array)) {\n return false;\n }\n }\n return true;\n}\n\nmodule.exports = arrayEvery;\n", + "/**\n * A specialized version of `) + ("`" + (`_.filter` + "`"))) + ((` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nmodule.exports = arrayFilter;\n", + "var baseIndexOf = require('./_baseIndexOf');\n\n/**\n * A specialized version of ` + ("`" + `_.includes`)) + ("`" + (` for arrays without support for\n * specifying an index to search from.\n *\n * @private\n * @param {Array} [array] The array to inspect.\n * @param {*} target The value to search for.\n * @returns {boolean} Returns ` + "`"))))) + ((((`true` + "`") + (` if ` + ("`" + `target`))) + (("`" + (` is found, else ` + "`")) + (`false` + ("`" + `.\n */\nfunction arrayIncludes(array, value) {\n var length = array == null ? 0 : array.length;\n return !!length && baseIndexOf(array, value, 0) > -1;\n}\n\nmodule.exports = arrayIncludes;\n", + "/**\n * This function is like `)))) + ((("`" + `arrayIncludes`) + ("`" + (` except that it accepts a comparator.\n *\n * @private\n * @param {Array} [array] The array to inspect.\n * @param {*} target The value to search for.\n * @param {Function} comparator The comparator invoked per element.\n * @returns {boolean} Returns ` + "`"))) + ((`true` + ("`" + ` if `)) + ("`" + (`target` + "`")))))) + (((((` is found, else ` + "`") + (`false` + ("`" + `.\n */\nfunction arrayIncludesWith(array, value, comparator) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (comparator(value, array[index])) {\n return true;\n }\n }\n return false;\n}\n\nmodule.exports = arrayIncludesWith;\n", + "var baseTimes = require('./_baseTimes'),\n isArguments = require('./isArguments'),\n isArray = require('./isArray'),\n isBuffer = require('./isBuffer'),\n isIndex = require('./_isIndex'),\n isTypedArray = require('./isTypedArray');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `))) + (("`" + (`value` + "`")) + (`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable ` + ("`" + `arguments.length`)))) + ((("`" + ` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\nmodule.exports = arrayLikeKeys;\n", + "/**\n * A specialized version of `) + ("`" + (`_.map` + "`"))) + ((` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nmodule.exports = arrayMap;\n", + "/**\n * Appends the elements of ` + ("`" + `values`)) + ("`" + (` to ` + "`"))))) + ((((`array` + "`") + (`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns ` + ("`" + `array`))) + (("`" + (`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nmodule.exports = arrayPush;\n", + "/**\n * A specialized version of ` + "`")) + (`_.some` + ("`" + ` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `)))) + ((("`" + (`true` + "`")) + (` if any element passes the predicate check,\n * else ` + ("`" + `false`))) + (("`" + (`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nmodule.exports = arraySome;\n", + "var eq = require('./eq');\n\n/**\n * Gets the index at which the ` + "`")) + (`key` + ("`" + ` is found in `))))))))) + (((((((("`" + `array`) + ("`" + (` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else ` + "`"))) + ((`-1` + ("`" + `.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nmodule.exports = assocIndexOf;\n", + "var defineProperty = require('./_defineProperty');\n\n/**\n * The base implementation of `)) + ("`" + (`assignValue` + "`")))) + (((` and ` + "`") + (`assignMergeValue` + ("`" + ` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction baseAssignValue(object, key, value) {\n if (key == '__proto__' && defineProperty) {\n defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n}\n\nmodule.exports = baseAssignValue;\n", + "var baseForOwn = require('./_baseForOwn'),\n createBaseEach = require('./_createBaseEach');\n\n/**\n * The base implementation of `))) + (("`" + (`_.forEach` + "`")) + (` without support for iteratee shorthands.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array|Object} Returns ` + ("`" + `collection`))))) + (((("`" + `.\n */\nvar baseEach = createBaseEach(baseForOwn);\n\nmodule.exports = baseEach;\n", + "var baseEach = require('./_baseEach');\n\n/**\n * The base implementation of `) + ("`" + (`_.every` + "`"))) + ((` without support for iteratee shorthands.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns ` + ("`" + `true`)) + ("`" + (` if all elements pass the predicate check,\n * else ` + "`")))) + (((`false` + "`") + (`\n */\nfunction baseEvery(collection, predicate) {\n var result = true;\n baseEach(collection, function(value, index, collection) {\n result = !!predicate(value, index, collection);\n return result;\n });\n return result;\n}\n\nmodule.exports = baseEvery;\n", + "var isSymbol = require('./isSymbol');\n\n/**\n * The base implementation of methods like ` + ("`" + `_.max`))) + (("`" + (` and ` + "`")) + (`_.min` + ("`" + ` which accepts a\n * `)))))) + ((((("`" + `comparator`) + ("`" + (` to determine the extremum value.\n *\n * @private\n * @param {Array} array The array to iterate over.\n * @param {Function} iteratee The iteratee invoked per iteration.\n * @param {Function} comparator The comparator used to compare values.\n * @returns {*} Returns the extremum value.\n */\nfunction baseExtremum(array, iteratee, comparator) {\n var index = -1,\n length = array.length;\n\n while (++index < length) {\n var value = array[index],\n current = iteratee(value);\n\n if (current != null && (computed === undefined\n ? (current === current && !isSymbol(current))\n : comparator(current, computed)\n )) {\n var computed = current,\n result = value;\n }\n }\n return result;\n}\n\nmodule.exports = baseExtremum;\n", + "var baseEach = require('./_baseEach');\n\n/**\n * The base implementation of ` + "`"))) + ((`_.filter` + ("`" + ` without support for iteratee shorthands.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction baseFilter(collection, predicate) {\n var result = [];\n baseEach(collection, function(value, index, collection) {\n if (predicate(value, index, collection)) {\n result.push(value);\n }\n });\n return result;\n}\n\nmodule.exports = baseFilter;\n", + "/**\n * The base implementation of `)) + ("`" + (`_.findIndex` + "`")))) + (((` and ` + "`") + (`_.findLastIndex` + ("`" + ` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `))) + (("`" + (`-1` + "`")) + (`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nmodule.exports = baseFindIndex;\n", + "var arrayPush = require('./_arrayPush'),\n isFlattenable = require('./_isFlattenable');\n\n/**\n * The base implementation of ` + ("`" + `_.flatten`))))) + (((("`" + ` with support for restricting flattening.\n *\n * @private\n * @param {Array} array The array to flatten.\n * @param {number} depth The maximum recursion depth.\n * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.\n * @param {boolean} [isStrict] Restrict to values that pass `) + ("`" + (`predicate` + "`"))) + ((` checks.\n * @param {Array} [result=[]] The initial result value.\n * @returns {Array} Returns the new flattened array.\n */\nfunction baseFlatten(array, depth, predicate, isStrict, result) {\n var index = -1,\n length = array.length;\n\n predicate || (predicate = isFlattenable);\n result || (result = []);\n\n while (++index < length) {\n var value = array[index];\n if (depth > 0 && predicate(value)) {\n if (depth > 1) {\n // Recursively flatten arrays (susceptible to call stack limits).\n baseFlatten(value, depth - 1, predicate, isStrict, result);\n } else {\n arrayPush(result, value);\n }\n } else if (!isStrict) {\n result[result.length] = value;\n }\n }\n return result;\n}\n\nmodule.exports = baseFlatten;\n", + "var createBaseFor = require('./_createBaseFor');\n\n/**\n * The base implementation of ` + ("`" + `baseForOwn`)) + ("`" + (` which iterates over ` + "`")))) + (((`object` + "`") + (`\n * properties returned by ` + ("`" + `keysFunc`))) + (("`" + (` and invokes ` + "`")) + (`iteratee` + ("`" + ` for each property.\n * Iteratee functions may exit iteration early by explicitly returning `))))))) + (((((("`" + `false`) + ("`" + (`.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {Function} keysFunc The function to get the keys of ` + "`"))) + ((`object` + ("`" + `.\n * @returns {Object} Returns `)) + ("`" + (`object` + "`")))) + (((`.\n */\nvar baseFor = createBaseFor();\n\nmodule.exports = baseFor;\n", + "var baseFor = require('./_baseFor'),\n keys = require('./keys');\n\n/**\n * The base implementation of ` + "`") + (`_.forOwn` + ("`" + ` without support for iteratee shorthands.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Object} Returns `))) + (("`" + (`object` + "`")) + (`.\n */\nfunction baseForOwn(object, iteratee) {\n return object && baseFor(object, iteratee, keys);\n}\n\nmodule.exports = baseForOwn;\n", + "var castPath = require('./_castPath'),\n toKey = require('./_toKey');\n\n/**\n * The base implementation of ` + ("`" + `_.get`))))) + (((("`" + ` without support for default values.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @returns {*} Returns the resolved value.\n */\nfunction baseGet(object, path) {\n path = castPath(path, object);\n\n var index = 0,\n length = path.length;\n\n while (object != null && index < length) {\n object = object[toKey(path[index++])];\n }\n return (index && index == length) ? object : undefined;\n}\n\nmodule.exports = baseGet;\n", + "var arrayPush = require('./_arrayPush'),\n isArray = require('./isArray');\n\n/**\n * The base implementation of `) + ("`" + (`getAllKeys` + "`"))) + ((` and ` + ("`" + `getAllKeysIn`)) + ("`" + (` which uses\n * ` + "`")))) + (((`keysFunc` + "`") + (` and ` + ("`" + `symbolsFunc`))) + (("`" + (` to get the enumerable property names and\n * symbols of ` + "`")) + (`object` + ("`" + `.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `)))))) + ((((("`" + `object`) + ("`" + (`.\n * @param {Function} symbolsFunc The function to get the symbols of ` + "`"))) + ((`object` + ("`" + `.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nmodule.exports = baseGetAllKeys;\n", + "var Symbol = require('./_Symbol'),\n getRawTag = require('./_getRawTag'),\n objectToString = require('./_objectToString');\n\n/** `)) + ("`" + (`Object#toString` + "`")))) + (((` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of ` + "`") + (`getTag` + ("`" + ` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `))) + (("`" + (`toStringTag` + "`")) + (`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nmodule.exports = baseGetTag;\n", + "/**\n * The base implementation of ` + ("`" + `_.gt`))))) + (((("`" + ` which doesn't coerce arguments.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `) + ("`" + (`true` + "`"))) + ((` if ` + ("`" + `value`)) + ("`" + (` is greater than ` + "`")))) + (((`other` + ("`" + `,\n * else `)) + ("`" + (`false` + "`"))) + ((`.\n */\nfunction baseGt(value, other) {\n return value > other;\n}\n\nmodule.exports = baseGt;\n", + "/**\n * The base implementation of ` + ("`" + `_.hasIn`)) + ("`" + (` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns ` + "`")))))))) + (((((((`true` + "`") + (` if ` + ("`" + `key`))) + (("`" + (` exists, else ` + "`")) + (`false` + ("`" + `.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nmodule.exports = baseHasIn;\n", + "var baseFindIndex = require('./_baseFindIndex'),\n baseIsNaN = require('./_baseIsNaN'),\n strictIndexOf = require('./_strictIndexOf');\n\n/**\n * The base implementation of `)))) + ((("`" + `_.indexOf`) + ("`" + (` without ` + "`"))) + ((`fromIndex` + ("`" + ` bounds checks.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `)) + ("`" + (`-1` + "`"))))) + ((((`.\n */\nfunction baseIndexOf(array, value, fromIndex) {\n return value === value\n ? strictIndexOf(array, value, fromIndex)\n : baseFindIndex(array, baseIsNaN, fromIndex);\n}\n\nmodule.exports = baseIndexOf;\n", + "var SetCache = require('./_SetCache'),\n arrayIncludes = require('./_arrayIncludes'),\n arrayIncludesWith = require('./_arrayIncludesWith'),\n arrayMap = require('./_arrayMap'),\n baseUnary = require('./_baseUnary'),\n cacheHas = require('./_cacheHas');\n\n/* Built-in method references for those with the same name as other ` + "`") + (`lodash` + ("`" + ` methods. */\nvar nativeMin = Math.min;\n\n/**\n * The base implementation of methods like `))) + (("`" + (`_.intersection` + "`")) + (`, without support\n * for iteratee shorthands, that accepts an array of arrays to inspect.\n *\n * @private\n * @param {Array} arrays The arrays to inspect.\n * @param {Function} [iteratee] The iteratee invoked per element.\n * @param {Function} [comparator] The comparator invoked per element.\n * @returns {Array} Returns the new array of shared values.\n */\nfunction baseIntersection(arrays, iteratee, comparator) {\n var includes = comparator ? arrayIncludesWith : arrayIncludes,\n length = arrays[0].length,\n othLength = arrays.length,\n othIndex = othLength,\n caches = Array(othLength),\n maxLength = Infinity,\n result = [];\n\n while (othIndex--) {\n var array = arrays[othIndex];\n if (othIndex && iteratee) {\n array = arrayMap(array, baseUnary(iteratee));\n }\n maxLength = nativeMin(array.length, maxLength);\n caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))\n ? new SetCache(othIndex && array)\n : undefined;\n }\n array = arrays[0];\n\n var index = -1,\n seen = caches[0];\n\n outer:\n while (++index < length && result.length < maxLength) {\n var value = array[index],\n computed = iteratee ? iteratee(value) : value;\n\n value = (comparator || value !== 0) ? value : 0;\n if (!(seen\n ? cacheHas(seen, computed)\n : includes(result, computed, comparator)\n )) {\n othIndex = othLength;\n while (--othIndex) {\n var cache = caches[othIndex];\n if (!(cache\n ? cacheHas(cache, computed)\n : includes(arrays[othIndex], computed, comparator))\n ) {\n continue outer;\n }\n }\n if (seen) {\n seen.push(computed);\n }\n result.push(value);\n }\n }\n return result;\n}\n\nmodule.exports = baseIntersection;\n", + "var baseGetTag = require('./_baseGetTag'),\n isObjectLike = require('./isObjectLike');\n\n/** ` + ("`" + `Object#toString`)))) + ((("`" + ` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `) + ("`" + (`_.isArguments` + "`"))) + ((`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`)) + ("`" + (` if ` + "`")))))) + (((((`value` + "`") + (` is an ` + ("`" + `arguments`))) + (("`" + (` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nmodule.exports = baseIsArguments;\n", + "var baseIsEqualDeep = require('./_baseIsEqualDeep'),\n isObjectLike = require('./isObjectLike');\n\n/**\n * The base implementation of ` + "`")) + (`_.isEqual` + ("`" + ` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Unordered comparison\n * 2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `)))) + ((("`" + `value`) + ("`" + (` and ` + "`"))) + ((`other` + ("`" + ` objects.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`"))))) + ((((` if the values are equivalent, else ` + "`") + (`false` + ("`" + `.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n if (value === other) {\n return true;\n }\n if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n return value !== value && other !== other;\n }\n return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\nmodule.exports = baseIsEqual;\n", + "var Stack = require('./_Stack'),\n equalArrays = require('./_equalArrays'),\n equalByTag = require('./_equalByTag'),\n equalObjects = require('./_equalObjects'),\n getTag = require('./_getTag'),\n isArray = require('./isArray'),\n isBuffer = require('./isBuffer'),\n isTypedArray = require('./isTypedArray');\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** `))) + (("`" + (`Object#toString` + "`")) + (` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of ` + ("`" + `baseIsEqual`)))) + ((("`" + (` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See ` + "`")) + (`baseIsEqual` + ("`" + ` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `))) + (("`" + (`object` + "`")) + (` and ` + ("`" + `other`))))))) + (((((("`" + ` objects.\n * @returns {boolean} Returns `) + ("`" + (`true` + "`"))) + ((` if the objects are equivalent, else ` + ("`" + `false`)) + ("`" + (`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n var objIsArr = isArray(object),\n othIsArr = isArray(other),\n objTag = objIsArr ? arrayTag : getTag(object),\n othTag = othIsArr ? arrayTag : getTag(other);\n\n objTag = objTag == argsTag ? objectTag : objTag;\n othTag = othTag == argsTag ? objectTag : othTag;\n\n var objIsObj = objTag == objectTag,\n othIsObj = othTag == objectTag,\n isSameTag = objTag == othTag;\n\n if (isSameTag && isBuffer(object)) {\n if (!isBuffer(other)) {\n return false;\n }\n objIsArr = true;\n objIsObj = false;\n }\n if (isSameTag && !objIsObj) {\n stack || (stack = new Stack);\n return (objIsArr || isTypedArray(object))\n ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n }\n if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n if (objIsWrapped || othIsWrapped) {\n var objUnwrapped = objIsWrapped ? object.value() : object,\n othUnwrapped = othIsWrapped ? other.value() : other;\n\n stack || (stack = new Stack);\n return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n }\n }\n if (!isSameTag) {\n return false;\n }\n stack || (stack = new Stack);\n return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\nmodule.exports = baseIsEqualDeep;\n", + "var Stack = require('./_Stack'),\n baseIsEqual = require('./_baseIsEqual');\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/**\n * The base implementation of ` + "`")))) + (((`_.isMatch` + "`") + (` without support for iteratee shorthands.\n *\n * @private\n * @param {Object} object The object to inspect.\n * @param {Object} source The object of property values to match.\n * @param {Array} matchData The property names, values, and compare flags to match.\n * @param {Function} [customizer] The function to customize comparisons.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if ` + "`")) + (`object` + ("`" + ` is a match, else `))))) + (((("`" + `false`) + ("`" + (`.\n */\nfunction baseIsMatch(object, source, matchData, customizer) {\n var index = matchData.length,\n length = index,\n noCustomizer = !customizer;\n\n if (object == null) {\n return !length;\n }\n object = Object(object);\n while (index--) {\n var data = matchData[index];\n if ((noCustomizer && data[2])\n ? data[1] !== object[data[0]]\n : !(data[0] in object)\n ) {\n return false;\n }\n }\n while (++index < length) {\n data = matchData[index];\n var key = data[0],\n objValue = object[key],\n srcValue = data[1];\n\n if (noCustomizer && data[2]) {\n if (objValue === undefined && !(key in object)) {\n return false;\n }\n } else {\n var stack = new Stack;\n if (customizer) {\n var result = customizer(objValue, srcValue, key, object, source, stack);\n }\n if (!(result === undefined\n ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)\n : result\n )) {\n return false;\n }\n }\n }\n return true;\n}\n\nmodule.exports = baseIsMatch;\n", + "/**\n * The base implementation of ` + "`"))) + ((`_.isNaN` + ("`" + ` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`")))) + (((` if ` + "`") + (`value` + ("`" + ` is `))) + (("`" + (`NaN` + "`")) + (`, else ` + ("`" + `false`)))))) + ((((("`" + `.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nmodule.exports = baseIsNaN;\n", + "var isFunction = require('./isFunction'),\n isMasked = require('./_isMasked'),\n isObject = require('./isObject'),\n toSource = require('./_toSource');\n\n/**\n * Used to match `) + ("`" + (`RegExp` + "`"))) + ((`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of ` + ("`" + `_.isNative`)) + ("`" + (` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`")))) + (((`true` + "`") + (` if ` + ("`" + `value`))) + (("`" + (` is a native function,\n * else ` + "`")) + (`false` + ("`" + `.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nmodule.exports = baseIsNative;\n", + "var baseGetTag = require('./_baseGetTag'),\n isLength = require('./isLength'),\n isObjectLike = require('./isObjectLike');\n\n/** `))))) + (((("`" + `Object#toString`) + ("`" + (` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify ` + "`"))) + ((`toStringTag` + ("`" + ` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `)) + ("`" + (`_.isTypedArray` + "`")))) + (((` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`)) + ("`" + (` if ` + "`"))) + ((`value` + ("`" + ` is a typed array, else `)) + ("`" + (`false` + "`")))))))))))) + (((((((((((`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nmodule.exports = baseIsTypedArray;\n", + "var baseMatches = require('./_baseMatches'),\n baseMatchesProperty = require('./_baseMatchesProperty'),\n identity = require('./identity'),\n isArray = require('./isArray'),\n property = require('./property');\n\n/**\n * The base implementation of ` + "`") + (`_.iteratee` + ("`" + `.\n *\n * @private\n * @param {*} [value=_.identity] The value to convert to an iteratee.\n * @returns {Function} Returns the iteratee.\n */\nfunction baseIteratee(value) {\n // Don't store the `))) + (("`" + (`typeof` + "`")) + (` result in a variable to avoid a JIT bug in Safari 9.\n // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.\n if (typeof value == 'function') {\n return value;\n }\n if (value == null) {\n return identity;\n }\n if (typeof value == 'object') {\n return isArray(value)\n ? baseMatchesProperty(value[0], value[1])\n : baseMatches(value);\n }\n return property(value);\n}\n\nmodule.exports = baseIteratee;\n", + "var isPrototype = require('./_isPrototype'),\n nativeKeys = require('./_nativeKeys');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of ` + ("`" + `_.keys`)))) + ((("`" + ` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\nmodule.exports = baseKeys;\n", + "/**\n * The base implementation of `) + ("`" + (`_.lt` + "`"))) + ((` which doesn't coerce arguments.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns ` + ("`" + `true`)) + ("`" + (` if ` + "`"))))) + ((((`value` + "`") + (` is less than ` + ("`" + `other`))) + (("`" + (`,\n * else ` + "`")) + (`false` + ("`" + `.\n */\nfunction baseLt(value, other) {\n return value < other;\n}\n\nmodule.exports = baseLt;\n", + "var baseEach = require('./_baseEach'),\n isArrayLike = require('./isArrayLike');\n\n/**\n * The base implementation of `)))) + ((("`" + `_.map`) + ("`" + (` without support for iteratee shorthands.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction baseMap(collection, iteratee) {\n var index = -1,\n result = isArrayLike(collection) ? Array(collection.length) : [];\n\n baseEach(collection, function(value, key, collection) {\n result[++index] = iteratee(value, key, collection);\n });\n return result;\n}\n\nmodule.exports = baseMap;\n", + "var baseIsMatch = require('./_baseIsMatch'),\n getMatchData = require('./_getMatchData'),\n matchesStrictComparable = require('./_matchesStrictComparable');\n\n/**\n * The base implementation of ` + "`"))) + ((`_.matches` + ("`" + ` which doesn't clone `)) + ("`" + (`source` + "`")))))) + (((((`.\n *\n * @private\n * @param {Object} source The object of property values to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction baseMatches(source) {\n var matchData = getMatchData(source);\n if (matchData.length == 1 && matchData[0][2]) {\n return matchesStrictComparable(matchData[0][0], matchData[0][1]);\n }\n return function(object) {\n return object === source || baseIsMatch(object, source, matchData);\n };\n}\n\nmodule.exports = baseMatches;\n", + "var baseIsEqual = require('./_baseIsEqual'),\n get = require('./get'),\n hasIn = require('./hasIn'),\n isKey = require('./_isKey'),\n isStrictComparable = require('./_isStrictComparable'),\n matchesStrictComparable = require('./_matchesStrictComparable'),\n toKey = require('./_toKey');\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/**\n * The base implementation of ` + "`") + (`_.matchesProperty` + ("`" + ` which doesn't clone `))) + (("`" + (`srcValue` + "`")) + (`.\n *\n * @private\n * @param {string} path The path of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction baseMatchesProperty(path, srcValue) {\n if (isKey(path) && isStrictComparable(srcValue)) {\n return matchesStrictComparable(toKey(path), srcValue);\n }\n return function(object) {\n var objValue = get(object, path);\n return (objValue === undefined && objValue === srcValue)\n ? hasIn(object, path)\n : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);\n };\n}\n\nmodule.exports = baseMatchesProperty;\n", + "var arrayMap = require('./_arrayMap'),\n baseIteratee = require('./_baseIteratee'),\n baseMap = require('./_baseMap'),\n baseSortBy = require('./_baseSortBy'),\n baseUnary = require('./_baseUnary'),\n compareMultiple = require('./_compareMultiple'),\n identity = require('./identity');\n\n/**\n * The base implementation of ` + ("`" + `_.orderBy`)))) + ((("`" + ` without param guards.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.\n * @param {string[]} orders The sort orders of `) + ("`" + (`iteratees` + "`"))) + ((`.\n * @returns {Array} Returns the new sorted array.\n */\nfunction baseOrderBy(collection, iteratees, orders) {\n var index = -1;\n iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(baseIteratee));\n\n var result = baseMap(collection, function(value, key, collection) {\n var criteria = arrayMap(iteratees, function(iteratee) {\n return iteratee(value);\n });\n return { 'criteria': criteria, 'index': ++index, 'value': value };\n });\n\n return baseSortBy(result, function(object, other) {\n return compareMultiple(object, other, orders);\n });\n}\n\nmodule.exports = baseOrderBy;\n", + "/**\n * The base implementation of ` + ("`" + `_.property`)) + ("`" + (` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nmodule.exports = baseProperty;\n", + "var baseGet = require('./_baseGet');\n\n/**\n * A specialized version of ` + "`"))))) + ((((`baseProperty` + "`") + (` which supports deep paths.\n *\n * @private\n * @param {Array|string} path The path of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction basePropertyDeep(path) {\n return function(object) {\n return baseGet(object, path);\n };\n}\n\nmodule.exports = basePropertyDeep;\n", + "/* Built-in method references for those with the same name as other ` + ("`" + `lodash`))) + (("`" + (` methods. */\nvar nativeCeil = Math.ceil,\n nativeMax = Math.max;\n\n/**\n * The base implementation of ` + "`")) + (`_.range` + ("`" + ` and `)))) + ((("`" + `_.rangeRight`) + ("`" + (` which doesn't\n * coerce arguments.\n *\n * @private\n * @param {number} start The start of the range.\n * @param {number} end The end of the range.\n * @param {number} step The value to increment or decrement by.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Array} Returns the range of numbers.\n */\nfunction baseRange(start, end, step, fromRight) {\n var index = -1,\n length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),\n result = Array(length);\n\n while (length--) {\n result[fromRight ? length : ++index] = start;\n start += step;\n }\n return result;\n}\n\nmodule.exports = baseRange;\n", + "var identity = require('./identity'),\n overRest = require('./_overRest'),\n setToString = require('./_setToString');\n\n/**\n * The base implementation of ` + "`"))) + ((`_.rest` + ("`" + ` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n return setToString(overRest(func, start, identity), func + '');\n}\n\nmodule.exports = baseRest;\n", + "var constant = require('./constant'),\n defineProperty = require('./_defineProperty'),\n identity = require('./identity');\n\n/**\n * The base implementation of `)) + ("`" + (`setToString` + "`"))))))) + ((((((` without support for hot loop shorting.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The ` + "`") + (`toString` + ("`" + ` result.\n * @returns {Function} Returns `))) + (("`" + (`func` + "`")) + (`.\n */\nvar baseSetToString = !defineProperty ? identity : function(func, string) {\n return defineProperty(func, 'toString', {\n 'configurable': true,\n 'enumerable': false,\n 'value': constant(string),\n 'writable': true\n });\n};\n\nmodule.exports = baseSetToString;\n", + "var baseEach = require('./_baseEach');\n\n/**\n * The base implementation of ` + ("`" + `_.some`)))) + ((("`" + ` without support for iteratee shorthands.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `) + ("`" + (`true` + "`"))) + ((` if any element passes the predicate check,\n * else ` + ("`" + `false`)) + ("`" + (`.\n */\nfunction baseSome(collection, predicate) {\n var result;\n\n baseEach(collection, function(value, index, collection) {\n result = predicate(value, index, collection);\n return !result;\n });\n return !!result;\n}\n\nmodule.exports = baseSome;\n", + "/**\n * The base implementation of ` + "`"))))) + ((((`_.sortBy` + "`") + (` which uses ` + ("`" + `comparer`))) + (("`" + (` to define the\n * sort order of ` + "`")) + (`array` + ("`" + ` and replaces criteria objects with their corresponding\n * values.\n *\n * @private\n * @param {Array} array The array to sort.\n * @param {Function} comparer The function to define sort order.\n * @returns {Array} Returns `)))) + ((("`" + `array`) + ("`" + (`.\n */\nfunction baseSortBy(array, comparer) {\n var length = array.length;\n\n array.sort(comparer);\n while (length--) {\n array[length] = array[length].value;\n }\n return array;\n}\n\nmodule.exports = baseSortBy;\n", + "/**\n * The base implementation of ` + "`"))) + ((`_.times` + ("`" + ` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `)) + ("`" + (`iteratee` + "`")))))) + (((((`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nmodule.exports = baseTimes;\n", + "var Symbol = require('./_Symbol'),\n arrayMap = require('./_arrayMap'),\n isArray = require('./isArray'),\n isSymbol = require('./isSymbol');\n\n/** Used as references for various ` + "`") + (`Number` + ("`" + ` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `))) + (("`" + (`_.toString` + "`")) + (` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return arrayMap(value, baseToString) + '';\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nmodule.exports = baseToString;\n", + "/**\n * The base implementation of ` + ("`" + `_.unary`)))) + ((("`" + ` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nmodule.exports = baseUnary;\n", + "var SetCache = require('./_SetCache'),\n arrayIncludes = require('./_arrayIncludes'),\n arrayIncludesWith = require('./_arrayIncludesWith'),\n cacheHas = require('./_cacheHas'),\n createSet = require('./_createSet'),\n setToArray = require('./_setToArray');\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * The base implementation of `) + ("`" + (`_.uniqBy` + "`"))) + ((` without support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} [iteratee] The iteratee invoked per element.\n * @param {Function} [comparator] The comparator invoked per element.\n * @returns {Array} Returns the new duplicate free array.\n */\nfunction baseUniq(array, iteratee, comparator) {\n var index = -1,\n includes = arrayIncludes,\n length = array.length,\n isCommon = true,\n result = [],\n seen = result;\n\n if (comparator) {\n isCommon = false;\n includes = arrayIncludesWith;\n }\n else if (length >= LARGE_ARRAY_SIZE) {\n var set = iteratee ? null : createSet(array);\n if (set) {\n return setToArray(set);\n }\n isCommon = false;\n includes = cacheHas;\n seen = new SetCache;\n }\n else {\n seen = iteratee ? [] : result;\n }\n outer:\n while (++index < length) {\n var value = array[index],\n computed = iteratee ? iteratee(value) : value;\n\n value = (comparator || value !== 0) ? value : 0;\n if (isCommon && computed === computed) {\n var seenIndex = seen.length;\n while (seenIndex--) {\n if (seen[seenIndex] === computed) {\n continue outer;\n }\n }\n if (iteratee) {\n seen.push(computed);\n }\n result.push(value);\n }\n else if (!includes(seen, computed, comparator)) {\n if (seen !== result) {\n seen.push(computed);\n }\n result.push(value);\n }\n }\n return result;\n}\n\nmodule.exports = baseUniq;\n", + "/**\n * Checks if a ` + ("`" + `cache`)) + ("`" + (` value for ` + "`"))))) + ((((`key` + "`") + (` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if an entry for ` + "`")) + (`key` + ("`" + ` exists, else `)))) + ((("`" + (`false` + "`")) + (`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nmodule.exports = cacheHas;\n", + "var isArrayLikeObject = require('./isArrayLikeObject');\n\n/**\n * Casts ` + ("`" + `value`))) + (("`" + (` to an empty array if it's not an array like object.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {Array|Object} Returns the cast array-like object.\n */\nfunction castArrayLikeObject(value) {\n return isArrayLikeObject(value) ? value : [];\n}\n\nmodule.exports = castArrayLikeObject;\n", + "var isArray = require('./isArray'),\n isKey = require('./_isKey'),\n stringToPath = require('./_stringToPath'),\n toString = require('./toString');\n\n/**\n * Casts ` + "`")) + (`value` + ("`" + ` to a path array if it's not one.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {Object} [object] The object to query keys on.\n * @returns {Array} Returns the cast property path array.\n */\nfunction castPath(value, object) {\n if (isArray(value)) {\n return value;\n }\n return isKey(value, object) ? [value] : stringToPath(toString(value));\n}\n\nmodule.exports = castPath;\n", + "var isSymbol = require('./isSymbol');\n\n/**\n * Compares values to sort them in ascending order.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {number} Returns the sort order indicator for `)))))))) + ((((((("`" + `value`) + ("`" + (`.\n */\nfunction compareAscending(value, other) {\n if (value !== other) {\n var valIsDefined = value !== undefined,\n valIsNull = value === null,\n valIsReflexive = value === value,\n valIsSymbol = isSymbol(value);\n\n var othIsDefined = other !== undefined,\n othIsNull = other === null,\n othIsReflexive = other === other,\n othIsSymbol = isSymbol(other);\n\n if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||\n (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||\n (valIsNull && othIsDefined && othIsReflexive) ||\n (!valIsDefined && othIsReflexive) ||\n !valIsReflexive) {\n return 1;\n }\n if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||\n (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||\n (othIsNull && valIsDefined && valIsReflexive) ||\n (!othIsDefined && valIsReflexive) ||\n !othIsReflexive) {\n return -1;\n }\n }\n return 0;\n}\n\nmodule.exports = compareAscending;\n", + "var compareAscending = require('./_compareAscending');\n\n/**\n * Used by ` + "`"))) + ((`_.orderBy` + ("`" + ` to compare multiple properties of a value to another\n * and stable sort them.\n *\n * If `)) + ("`" + (`orders` + "`")))) + (((` is unspecified, all values are sorted in ascending order. Otherwise,\n * specify an order of \"desc\" for descending or \"asc\" for ascending sort order\n * of corresponding values.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {boolean[]|string[]} orders The order to sort by for each property.\n * @returns {number} Returns the sort order indicator for ` + "`") + (`object` + ("`" + `.\n */\nfunction compareMultiple(object, other, orders) {\n var index = -1,\n objCriteria = object.criteria,\n othCriteria = other.criteria,\n length = objCriteria.length,\n ordersLength = orders.length;\n\n while (++index < length) {\n var result = compareAscending(objCriteria[index], othCriteria[index]);\n if (result) {\n if (index >= ordersLength) {\n return result;\n }\n var order = orders[index];\n return result * (order == 'desc' ? -1 : 1);\n }\n }\n // Fixes an `))) + (("`" + (`Array#sort` + "`")) + (` bug in the JS engine embedded in Adobe applications\n // that causes it, under certain circumstances, to provide the same value for\n // ` + ("`" + `object`))))) + (((("`" + ` and `) + ("`" + (`other` + "`"))) + ((`. See https://github.com/jashkenas/underscore/pull/1247\n // for more details.\n //\n // This also ensures a stable sort in V8 and other engines.\n // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.\n return object.index - other.index;\n}\n\nmodule.exports = compareMultiple;\n", + "var root = require('./_root');\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nmodule.exports = coreJsData;\n", + "var isArrayLike = require('./isArrayLike');\n\n/**\n * Creates a ` + ("`" + `baseEach`)) + ("`" + (` or ` + "`")))) + (((`baseEachRight` + "`") + (` function.\n *\n * @private\n * @param {Function} eachFunc The function to iterate over a collection.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseEach(eachFunc, fromRight) {\n return function(collection, iteratee) {\n if (collection == null) {\n return collection;\n }\n if (!isArrayLike(collection)) {\n return eachFunc(collection, iteratee);\n }\n var length = collection.length,\n index = fromRight ? length : -1,\n iterable = Object(collection);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (iteratee(iterable[index], index, iterable) === false) {\n break;\n }\n }\n return collection;\n };\n}\n\nmodule.exports = createBaseEach;\n", + "/**\n * Creates a base function for methods like ` + ("`" + `_.forIn`))) + (("`" + (` and ` + "`")) + (`_.forOwn` + ("`" + `.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nmodule.exports = createBaseFor;\n", + "var baseIteratee = require('./_baseIteratee'),\n isArrayLike = require('./isArrayLike'),\n keys = require('./keys');\n\n/**\n * Creates a `)))))) + ((((("`" + `_.find`) + ("`" + (` or ` + "`"))) + ((`_.findLast` + ("`" + ` function.\n *\n * @private\n * @param {Function} findIndexFunc The function to find the collection index.\n * @returns {Function} Returns the new find function.\n */\nfunction createFind(findIndexFunc) {\n return function(collection, predicate, fromIndex) {\n var iterable = Object(collection);\n if (!isArrayLike(collection)) {\n var iteratee = baseIteratee(predicate, 3);\n collection = keys(collection);\n predicate = function(key) { return iteratee(iterable[key], key, iterable); };\n }\n var index = findIndexFunc(collection, predicate, fromIndex);\n return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;\n };\n}\n\nmodule.exports = createFind;\n", + "var baseRange = require('./_baseRange'),\n isIterateeCall = require('./_isIterateeCall'),\n toFinite = require('./toFinite');\n\n/**\n * Creates a `)) + ("`" + (`_.range` + "`")))) + (((` or ` + "`") + (`_.rangeRight` + ("`" + ` function.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new range function.\n */\nfunction createRange(fromRight) {\n return function(start, end, step) {\n if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {\n end = step = undefined;\n }\n // Ensure the sign of `))) + (("`" + (`-0` + "`")) + (` is preserved.\n start = toFinite(start);\n if (end === undefined) {\n end = start;\n start = 0;\n } else {\n end = toFinite(end);\n }\n step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);\n return baseRange(start, end, step, fromRight);\n };\n}\n\nmodule.exports = createRange;\n", + "var Set = require('./_Set'),\n noop = require('./noop'),\n setToArray = require('./_setToArray');\n\n/** Used as references for various ` + ("`" + `Number`))))) + (((("`" + ` constants. */\nvar INFINITY = 1 / 0;\n\n/**\n * Creates a set object of `) + ("`" + (`values` + "`"))) + ((`.\n *\n * @private\n * @param {Array} values The values to add to the set.\n * @returns {Object} Returns the new set.\n */\nvar createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {\n return new Set(values);\n};\n\nmodule.exports = createSet;\n", + "var getNative = require('./_getNative');\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nmodule.exports = defineProperty;\n", + "var SetCache = require('./_SetCache'),\n arraySome = require('./_arraySome'),\n cacheHas = require('./_cacheHas');\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/**\n * A specialized version of ` + ("`" + `baseIsEqualDeep`)) + ("`" + (` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See ` + "`")))) + (((`baseIsEqual` + "`") + (` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed ` + ("`" + `array`))) + (("`" + (` and ` + "`")) + (`other` + ("`" + ` objects.\n * @returns {boolean} Returns `))))))) + (((((("`" + `true`) + ("`" + (` if the arrays are equivalent, else ` + "`"))) + ((`false` + ("`" + `.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n arrLength = array.length,\n othLength = other.length;\n\n if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(array);\n if (stacked && stack.get(other)) {\n return stacked == other;\n }\n var index = -1,\n result = true,\n seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n stack.set(array, other);\n stack.set(other, array);\n\n // Ignore non-index properties.\n while (++index < arrLength) {\n var arrValue = array[index],\n othValue = other[index];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, arrValue, index, other, array, stack)\n : customizer(arrValue, othValue, index, array, other, stack);\n }\n if (compared !== undefined) {\n if (compared) {\n continue;\n }\n result = false;\n break;\n }\n // Recursively compare arrays (susceptible to call stack limits).\n if (seen) {\n if (!arraySome(other, function(othValue, othIndex) {\n if (!cacheHas(seen, othIndex) &&\n (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n return seen.push(othIndex);\n }\n })) {\n result = false;\n break;\n }\n } else if (!(\n arrValue === othValue ||\n equalFunc(arrValue, othValue, bitmask, customizer, stack)\n )) {\n result = false;\n break;\n }\n }\n stack['delete'](array);\n stack['delete'](other);\n return result;\n}\n\nmodule.exports = equalArrays;\n", + "var Symbol = require('./_Symbol'),\n Uint8Array = require('./_Uint8Array'),\n eq = require('./eq'),\n equalArrays = require('./_equalArrays'),\n mapToArray = require('./_mapToArray'),\n setToArray = require('./_setToArray');\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/** `)) + ("`" + (`Object#toString` + "`")))) + (((` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * A specialized version of ` + "`") + (`baseIsEqualDeep` + ("`" + ` for comparing objects of\n * the same `))) + (("`" + (`toStringTag` + "`")) + (`.\n *\n * **Note:** This function only supports comparing values with tags of\n * ` + ("`" + `Boolean`))))) + (((("`" + `, `) + ("`" + (`Date` + "`"))) + ((`, ` + ("`" + `Error`)) + ("`" + (`, ` + "`")))) + (((`Number` + "`") + (`, ` + ("`" + `RegExp`))) + (("`" + (`, or ` + "`")) + (`String` + ("`" + `.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `)))))) + ((((("`" + `toStringTag`) + ("`" + (` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See ` + "`"))) + ((`baseIsEqual` + ("`" + ` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `)) + ("`" + (`object` + "`")))) + (((` and ` + "`") + (`other` + ("`" + ` objects.\n * @returns {boolean} Returns `))) + (("`" + (`true` + "`")) + (` if the objects are equivalent, else ` + ("`" + `false`))))) + (((("`" + `.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n switch (tag) {\n case dataViewTag:\n if ((object.byteLength != other.byteLength) ||\n (object.byteOffset != other.byteOffset)) {\n return false;\n }\n object = object.buffer;\n other = other.buffer;\n\n case arrayBufferTag:\n if ((object.byteLength != other.byteLength) ||\n !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n return false;\n }\n return true;\n\n case boolTag:\n case dateTag:\n case numberTag:\n // Coerce booleans to `) + ("`" + (`1` + "`"))) + ((` or ` + ("`" + `0`)) + ("`" + (` and dates to milliseconds.\n // Invalid dates are coerced to ` + "`")))) + (((`NaN` + ("`" + `.\n return eq(+object, +other);\n\n case errorTag:\n return object.name == other.name && object.message == other.message;\n\n case regexpTag:\n case stringTag:\n // Coerce regexes to strings and treat strings, primitives and objects,\n // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n // for more details.\n return object == (other + '');\n\n case mapTag:\n var convert = mapToArray;\n\n case setTag:\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n convert || (convert = setToArray);\n\n if (object.size != other.size && !isPartial) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked) {\n return stacked == other;\n }\n bitmask |= COMPARE_UNORDERED_FLAG;\n\n // Recursively compare objects (susceptible to call stack limits).\n stack.set(object, other);\n var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n stack['delete'](object);\n return result;\n\n case symbolTag:\n if (symbolValueOf) {\n return symbolValueOf.call(object) == symbolValueOf.call(other);\n }\n }\n return false;\n}\n\nmodule.exports = equalByTag;\n", + "var getAllKeys = require('./_getAllKeys');\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `)) + ("`" + (`baseIsEqualDeep` + "`"))) + ((` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See ` + ("`" + `baseIsEqual`)) + ("`" + (` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed ` + "`"))))))))) + ((((((((`object` + "`") + (` and ` + ("`" + `other`))) + (("`" + (` objects.\n * @returns {boolean} Returns ` + "`")) + (`true` + ("`" + ` if the objects are equivalent, else `)))) + ((("`" + `false`) + ("`" + (`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n objProps = getAllKeys(object),\n objLength = objProps.length,\n othProps = getAllKeys(other),\n othLength = othProps.length;\n\n if (objLength != othLength && !isPartial) {\n return false;\n }\n var index = objLength;\n while (index--) {\n var key = objProps[index];\n if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n return false;\n }\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked && stack.get(other)) {\n return stacked == other;\n }\n var result = true;\n stack.set(object, other);\n stack.set(other, object);\n\n var skipCtor = isPartial;\n while (++index < objLength) {\n key = objProps[index];\n var objValue = object[key],\n othValue = other[key];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, objValue, key, other, object, stack)\n : customizer(objValue, othValue, key, object, other, stack);\n }\n // Recursively compare objects (susceptible to call stack limits).\n if (!(compared === undefined\n ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n : compared\n )) {\n result = false;\n break;\n }\n skipCtor || (skipCtor = key == 'constructor');\n }\n if (result && !skipCtor) {\n var objCtor = object.constructor,\n othCtor = other.constructor;\n\n // Non ` + "`"))) + ((`Object` + ("`" + ` object instances with different constructors are not equal.\n if (objCtor != othCtor &&\n ('constructor' in object && 'constructor' in other) &&\n !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n result = false;\n }\n }\n stack['delete'](object);\n stack['delete'](other);\n return result;\n}\n\nmodule.exports = equalObjects;\n", + "/** Detect free variable `)) + ("`" + (`global` + "`"))))) + ((((` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nmodule.exports = freeGlobal;\n", + "var baseGetAllKeys = require('./_baseGetAllKeys'),\n getSymbols = require('./_getSymbols'),\n keys = require('./keys');\n\n/**\n * Creates an array of own enumerable property names and symbols of ` + "`") + (`object` + ("`" + `.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\nmodule.exports = getAllKeys;\n", + "var isKeyable = require('./_isKeyable');\n\n/**\n * Gets the data for `))) + (("`" + (`map` + "`")) + (`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nmodule.exports = getMapData;\n", + "var isStrictComparable = require('./_isStrictComparable'),\n keys = require('./keys');\n\n/**\n * Gets the property names, values, and compare flags of ` + ("`" + `object`)))) + ((("`" + `.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the match data of `) + ("`" + (`object` + "`"))) + ((`.\n */\nfunction getMatchData(object) {\n var result = keys(object),\n length = result.length;\n\n while (length--) {\n var key = result[length],\n value = object[key];\n\n result[length] = [key, value, isStrictComparable(value)];\n }\n return result;\n}\n\nmodule.exports = getMatchData;\n", + "var baseIsNative = require('./_baseIsNative'),\n getValue = require('./_getValue');\n\n/**\n * Gets the native function at ` + ("`" + `key`)) + ("`" + (` of ` + "`")))))) + (((((`object` + "`") + (`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else ` + ("`" + `undefined`))) + (("`" + (`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nmodule.exports = getNative;\n", + "var overArg = require('./_overArg');\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nmodule.exports = getPrototype;\n", + "var Symbol = require('./_Symbol');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [` + "`")) + (`toStringTag` + ("`" + `](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `)))) + ((("`" + `baseGetTag`) + ("`" + (` which ignores ` + "`"))) + ((`Symbol.toStringTag` + ("`" + ` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `)) + ("`" + (`toStringTag` + "`"))))) + ((((`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nmodule.exports = getRawTag;\n", + "var arrayFilter = require('./_arrayFilter'),\n stubArray = require('./stubArray');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other ` + "`") + (`lodash` + ("`" + ` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `))) + (("`" + (`object` + "`")) + (`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\nmodule.exports = getSymbols;\n", + "var DataView = require('./_DataView'),\n Map = require('./_Map'),\n Promise = require('./_Promise'),\n Set = require('./_Set'),\n WeakMap = require('./_WeakMap'),\n baseGetTag = require('./_baseGetTag'),\n toSource = require('./_toSource');\n\n/** ` + ("`" + `Object#toString`)))) + ((("`" + ` result references. */\nvar mapTag = '[object Map]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n setTag = '[object Set]',\n weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `) + ("`" + (`toStringTag` + "`"))) + ((` of ` + ("`" + `value`)) + ("`" + (`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the ` + "`"))))))) + ((((((`toStringTag` + "`") + (`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\nmodule.exports = getTag;\n", + "/**\n * Gets the value at ` + ("`" + `key`))) + (("`" + (` of ` + "`")) + (`object` + ("`" + `.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nmodule.exports = getValue;\n", + "var castPath = require('./_castPath'),\n isArguments = require('./isArguments'),\n isArray = require('./isArray'),\n isIndex = require('./_isIndex'),\n isLength = require('./isLength'),\n toKey = require('./_toKey');\n\n/**\n * Checks if `)))) + ((("`" + `path`) + ("`" + (` exists on ` + "`"))) + ((`object` + ("`" + `.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @param {Function} hasFunc The function to check properties.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`"))))) + ((((` if ` + "`") + (`path` + ("`" + ` exists, else `))) + (("`" + (`false` + "`")) + (`.\n */\nfunction hasPath(object, path, hasFunc) {\n path = castPath(path, object);\n\n var index = -1,\n length = path.length,\n result = false;\n\n while (++index < length) {\n var key = toKey(path[index]);\n if (!(result = object != null && hasFunc(object, key))) {\n break;\n }\n object = object[key];\n }\n if (result || ++index != length) {\n return result;\n }\n length = object == null ? 0 : object.length;\n return !!length && isLength(length) && isIndex(key, length) &&\n (isArray(object) || isArguments(object));\n}\n\nmodule.exports = hasPath;\n", + "var nativeCreate = require('./_nativeCreate');\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nmodule.exports = hashClear;\n", + "/**\n * Removes ` + ("`" + `key`)))) + ((("`" + ` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `) + ("`" + (`true` + "`"))) + ((` if the entry was removed, else ` + ("`" + `false`)) + ("`" + (`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nmodule.exports = hashDelete;\n", + "var nativeCreate = require('./_nativeCreate');\n\n/** Used to stand-in for ` + "`")))))) + (((((`undefined` + "`") + (` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for ` + ("`" + `key`))) + (("`" + (`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nmodule.exports = hashGet;\n", + "var nativeCreate = require('./_nativeCreate');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for ` + "`")) + (`key` + ("`" + ` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `)))) + ((("`" + `true`) + ("`" + (` if an entry for ` + "`"))) + ((`key` + ("`" + ` exists, else `)) + ("`" + (`false` + "`"))))) + ((((`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nmodule.exports = hashHas;\n", + "var nativeCreate = require('./_nativeCreate');\n\n/** Used to stand-in for ` + "`") + (`undefined` + ("`" + ` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `))) + (("`" + (`key` + "`")) + (` to ` + ("`" + `value`)))) + ((("`" + (`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nmodule.exports = hashSet;\n", + "var Symbol = require('./_Symbol'),\n isArguments = require('./isArguments'),\n isArray = require('./isArray');\n\n/** Built-in value references. */\nvar spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined;\n\n/**\n * Checks if ` + "`")) + (`value` + ("`" + ` is a flattenable `))) + (("`" + (`arguments` + "`")) + (` object or array.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`)))))))) + ((((((("`" + ` if `) + ("`" + (`value` + "`"))) + ((` is flattenable, else ` + ("`" + `false`)) + ("`" + (`.\n */\nfunction isFlattenable(value) {\n return isArray(value) || isArguments(value) ||\n !!(spreadableSymbol && value && value[spreadableSymbol]);\n}\n\nmodule.exports = isFlattenable;\n", + "/** Used as references for various ` + "`")))) + (((`Number` + "`") + (` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if ` + ("`" + `value`))) + (("`" + (` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns ` + "`")) + (`true` + ("`" + ` if `))))) + (((("`" + `value`) + ("`" + (` is a valid index, else ` + "`"))) + ((`false` + ("`" + `.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nmodule.exports = isIndex;\n", + "var eq = require('./eq'),\n isArrayLike = require('./isArrayLike'),\n isIndex = require('./_isIndex'),\n isObject = require('./isObject');\n\n/**\n * Checks if the given arguments are from an iteratee call.\n *\n * @private\n * @param {*} value The potential iteratee value argument.\n * @param {*} index The potential iteratee index or key argument.\n * @param {*} object The potential iteratee object argument.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`")))) + (((` if the arguments are from an iteratee call,\n * else ` + "`") + (`false` + ("`" + `.\n */\nfunction isIterateeCall(value, index, object) {\n if (!isObject(object)) {\n return false;\n }\n var type = typeof index;\n if (type == 'number'\n ? (isArrayLike(object) && isIndex(index, object.length))\n : (type == 'string' && index in object)\n ) {\n return eq(object[index], value);\n }\n return false;\n}\n\nmodule.exports = isIterateeCall;\n", + "var isArray = require('./isArray'),\n isSymbol = require('./isSymbol');\n\n/** Used to match property names within property paths. */\nvar reIsDeepProp = /\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,\n reIsPlainProp = /^\\w*$/;\n\n/**\n * Checks if `))) + (("`" + (`value` + "`")) + (` is a property name and not a property path.\n *\n * @private\n * @param {*} value The value to check.\n * @param {Object} [object] The object to query keys on.\n * @returns {boolean} Returns ` + ("`" + `true`)))))) + ((((("`" + ` if `) + ("`" + (`value` + "`"))) + ((` is a property name, else ` + ("`" + `false`)) + ("`" + (`.\n */\nfunction isKey(value, object) {\n if (isArray(value)) {\n return false;\n }\n var type = typeof value;\n if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n value == null || isSymbol(value)) {\n return true;\n }\n return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n (object != null && value in Object(object));\n}\n\nmodule.exports = isKey;\n", + "/**\n * Checks if ` + "`")))) + (((`value` + "`") + (` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if ` + "`")) + (`value` + ("`" + ` is suitable, else `))))) + (((("`" + `false`) + ("`" + (`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nmodule.exports = isKeyable;\n", + "var coreJsData = require('./_coreJsData');\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if ` + "`"))) + ((`func` + ("`" + ` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`")))) + (((` if ` + ("`" + `func`)) + ("`" + (` is masked, else ` + "`"))) + ((`false` + ("`" + `.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nmodule.exports = isMasked;\n", + "/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `)) + ("`" + (`value` + "`"))))))) + ((((((` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`") + (`true` + ("`" + ` if `))) + (("`" + (`value` + "`")) + (` is a prototype, else ` + ("`" + `false`)))) + ((("`" + `.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nmodule.exports = isPrototype;\n", + "var isObject = require('./isObject');\n\n/**\n * Checks if `) + ("`" + (`value` + "`"))) + ((` is suitable for strict equality comparisons, i.e. ` + ("`" + `===`)) + ("`" + (`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`"))))) + ((((`true` + "`") + (` if ` + ("`" + `value`))) + (("`" + (` if suitable for strict\n * equality comparisons, else ` + "`")) + (`false` + ("`" + `.\n */\nfunction isStrictComparable(value) {\n return value === value && !isObject(value);\n}\n\nmodule.exports = isStrictComparable;\n", + "/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nmodule.exports = listCacheClear;\n", + "var assocIndexOf = require('./_assocIndexOf');\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `)))) + ((("`" + `key`) + ("`" + (` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns ` + "`"))) + ((`true` + ("`" + ` if the entry was removed, else `)) + ("`" + (`false` + "`")))))) + (((((`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nmodule.exports = listCacheDelete;\n", + "var assocIndexOf = require('./_assocIndexOf');\n\n/**\n * Gets the list cache value for ` + "`") + (`key` + ("`" + `.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nmodule.exports = listCacheGet;\n", + "var assocIndexOf = require('./_assocIndexOf');\n\n/**\n * Checks if a list cache value for `))) + (("`" + (`key` + "`")) + (` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns ` + ("`" + `true`)))) + ((("`" + ` if an entry for `) + ("`" + (`key` + "`"))) + ((` exists, else ` + ("`" + `false`)) + ("`" + (`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nmodule.exports = listCacheHas;\n", + "var assocIndexOf = require('./_assocIndexOf');\n\n/**\n * Sets the list cache ` + "`"))))) + ((((`key` + "`") + (` to ` + ("`" + `value`))) + (("`" + (`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nmodule.exports = listCacheSet;\n", + "var Hash = require('./_Hash'),\n ListCache = require('./_ListCache'),\n Map = require('./_Map');\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nmodule.exports = mapCacheClear;\n", + "var getMapData = require('./_getMapData');\n\n/**\n * Removes ` + "`")) + (`key` + ("`" + ` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `)))) + ((("`" + (`true` + "`")) + (` if the entry was removed, else ` + ("`" + `false`))) + (("`" + (`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nmodule.exports = mapCacheDelete;\n", + "var getMapData = require('./_getMapData');\n\n/**\n * Gets the map value for ` + "`")) + (`key` + ("`" + `.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nmodule.exports = mapCacheGet;\n", + "var getMapData = require('./_getMapData');\n\n/**\n * Checks if a map value for `)))))))))) + ((((((((("`" + `key`) + ("`" + (` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns ` + "`"))) + ((`true` + ("`" + ` if an entry for `)) + ("`" + (`key` + "`")))) + (((` exists, else ` + "`") + (`false` + ("`" + `.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nmodule.exports = mapCacheHas;\n", + "var getMapData = require('./_getMapData');\n\n/**\n * Sets the map `))) + (("`" + (`key` + "`")) + (` to ` + ("`" + `value`))))) + (((("`" + `.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nmodule.exports = mapCacheSet;\n", + "/**\n * Converts `) + ("`" + (`map` + "`"))) + ((` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nmodule.exports = mapToArray;\n", + "/**\n * A specialized version of ` + ("`" + `matchesProperty`)) + ("`" + (` for source values suitable\n * for strict equality comparisons, i.e. ` + "`")))) + (((`===` + "`") + (`.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @param {*} srcValue The value to match.\n * @returns {Function} Returns the new spec function.\n */\nfunction matchesStrictComparable(key, srcValue) {\n return function(object) {\n if (object == null) {\n return false;\n }\n return object[key] === srcValue &&\n (srcValue !== undefined || (key in Object(object)));\n };\n}\n\nmodule.exports = matchesStrictComparable;\n", + "var memoize = require('./memoize');\n\n/** Used as the maximum memoize cache size. */\nvar MAX_MEMOIZE_SIZE = 500;\n\n/**\n * A specialized version of ` + ("`" + `_.memoize`))) + (("`" + (` which clears the memoized function's\n * cache when it exceeds ` + "`")) + (`MAX_MEMOIZE_SIZE` + ("`" + `.\n *\n * @private\n * @param {Function} func The function to have its output memoized.\n * @returns {Function} Returns the new memoized function.\n */\nfunction memoizeCapped(func) {\n var result = memoize(func, function(key) {\n if (cache.size === MAX_MEMOIZE_SIZE) {\n cache.clear();\n }\n return key;\n });\n\n var cache = result.cache;\n return result;\n}\n\nmodule.exports = memoizeCapped;\n", + "var getNative = require('./_getNative');\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nmodule.exports = nativeCreate;\n", + "var overArg = require('./_overArg');\n\n/* Built-in method references for those with the same name as other `)))))) + ((((("`" + `lodash`) + ("`" + (` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nmodule.exports = nativeKeys;\n", + "var freeGlobal = require('./_freeGlobal');\n\n/** Detect free variable ` + "`"))) + ((`exports` + ("`" + `. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `)) + ("`" + (`module` + "`")))) + (((`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension ` + "`") + (`module.exports` + ("`" + `. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `))) + (("`" + (`process` + "`")) + (` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use ` + ("`" + `util.types`))))) + (((("`" + ` for Node.js 10+.\n var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `) + ("`" + (`process.binding('util')` + "`"))) + ((` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\nmodule.exports = nodeUtil;\n", + "/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [` + ("`" + `toStringTag`)) + ("`" + (`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts ` + "`")))) + (((`value` + "`") + (` to a string using ` + ("`" + `Object.prototype.toString`))) + (("`" + (`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nmodule.exports = objectToString;\n", + "/**\n * Creates a unary function that invokes ` + "`")) + (`func` + ("`" + ` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nmodule.exports = overArg;\n", + "var apply = require('./_apply');\n\n/* Built-in method references for those with the same name as other `))))))) + (((((("`" + `lodash`) + ("`" + (` methods. */\nvar nativeMax = Math.max;\n\n/**\n * A specialized version of ` + "`"))) + ((`baseRest` + ("`" + ` which transforms the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @param {Function} transform The rest array transform.\n * @returns {Function} Returns the new function.\n */\nfunction overRest(func, start, transform) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = transform(array);\n return apply(func, this, otherArgs);\n };\n}\n\nmodule.exports = overRest;\n", + "var freeGlobal = require('./_freeGlobal');\n\n/** Detect free variable `)) + ("`" + (`self` + "`")))) + (((`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nmodule.exports = root;\n", + "/** Used to stand-in for ` + "`") + (`undefined` + ("`" + ` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `))) + (("`" + (`value` + "`")) + (` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nmodule.exports = setCacheAdd;\n", + "/**\n * Checks if ` + ("`" + `value`))))) + (((("`" + ` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `) + ("`" + (`true` + "`"))) + ((` if ` + ("`" + `value`)) + ("`" + (` is found, else ` + "`")))) + (((`false` + "`") + (`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nmodule.exports = setCacheHas;\n", + "/**\n * Converts ` + ("`" + `set`))) + (("`" + (` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nmodule.exports = setToArray;\n", + "var baseSetToString = require('./_baseSetToString'),\n shortOut = require('./_shortOut');\n\n/**\n * Sets the ` + "`")) + (`toString` + ("`" + ` method of `)))))) + ((((("`" + `func`) + ("`" + (` to return ` + "`"))) + ((`string` + ("`" + `.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `)) + ("`" + (`toString` + "`")))) + (((` result.\n * @returns {Function} Returns ` + "`") + (`func` + ("`" + `.\n */\nvar setToString = shortOut(baseSetToString);\n\nmodule.exports = setToString;\n", + "/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `))) + (("`" + (`lodash` + "`")) + (` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke ` + ("`" + `identity`))))) + (((("`" + ` instead\n * of `) + ("`" + (`func` + "`"))) + ((` when it's called ` + ("`" + `HOT_COUNT`)) + ("`" + (` or more times in ` + "`")))) + (((`HOT_SPAN` + ("`" + `\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nmodule.exports = shortOut;\n", + "var ListCache = require('./_ListCache');\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\nmodule.exports = stackClear;\n", + "/**\n * Removes `)) + ("`" + (`key` + "`"))) + ((` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns ` + ("`" + `true`)) + ("`" + (` if the entry was removed, else ` + "`")))))))) + (((((((`false` + "`") + (`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nmodule.exports = stackDelete;\n", + "/**\n * Gets the stack value for ` + ("`" + `key`))) + (("`" + (`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nmodule.exports = stackGet;\n", + "/**\n * Checks if a stack value for ` + "`")) + (`key` + ("`" + ` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `)))) + ((("`" + `true`) + ("`" + (` if an entry for ` + "`"))) + ((`key` + ("`" + ` exists, else `)) + ("`" + (`false` + "`"))))) + ((((`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nmodule.exports = stackHas;\n", + "var ListCache = require('./_ListCache'),\n Map = require('./_Map'),\n MapCache = require('./_MapCache');\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack ` + "`") + (`key` + ("`" + ` to `))) + (("`" + (`value` + "`")) + (`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\nmodule.exports = stackSet;\n", + "/**\n * A specialized version of ` + ("`" + `_.indexOf`)))) + ((("`" + ` which performs strict equality\n * comparisons of values, i.e. `) + ("`" + (`===` + "`"))) + ((`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else ` + ("`" + `-1`)) + ("`" + (`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nmodule.exports = strictIndexOf;\n", + "var memoizeCapped = require('./_memoizeCapped');\n\n/** Used to match property names within property paths. */\nvar rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n/** Used to match backslashes in property paths. */\nvar reEscapeChar = /\\\\(\\\\)?/g;\n\n/**\n * Converts ` + "`")))))) + (((((`string` + "`") + (` to a property path array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the property path array.\n */\nvar stringToPath = memoizeCapped(function(string) {\n var result = [];\n if (string.charCodeAt(0) === 46 /* . */) {\n result.push('');\n }\n string.replace(rePropName, function(match, number, quote, subString) {\n result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));\n });\n return result;\n});\n\nmodule.exports = stringToPath;\n", + "var isSymbol = require('./isSymbol');\n\n/** Used as references for various ` + ("`" + `Number`))) + (("`" + (` constants. */\nvar INFINITY = 1 / 0;\n\n/**\n * Converts ` + "`")) + (`value` + ("`" + ` to a string key if it's not a string or symbol.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {string|symbol} Returns the key.\n */\nfunction toKey(value) {\n if (typeof value == 'string' || isSymbol(value)) {\n return value;\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nmodule.exports = toKey;\n", + "/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `)))) + ((("`" + `func`) + ("`" + (` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nmodule.exports = toSource;\n", + "/**\n * Creates a function that returns ` + "`"))) + ((`value` + ("`" + `.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nmodule.exports = constant;\n", + "var isObject = require('./isObject'),\n now = require('./now'),\n toNumber = require('./toNumber');\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `)) + ("`" + (`lodash` + "`"))))) + ((((` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking ` + "`") + (`func` + ("`" + ` until after `))) + (("`" + (`wait` + "`")) + (`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a ` + ("`" + `cancel`)))) + ((("`" + ` method to cancel\n * delayed `) + ("`" + (`func` + "`"))) + ((` invocations and a ` + ("`" + `flush`)) + ("`" + (` method to immediately invoke them.\n * Provide ` + "`"))))))) + ((((((`options` + "`") + (` to indicate whether ` + ("`" + `func`))) + (("`" + (` should be invoked on the\n * leading and/or trailing edge of the ` + "`")) + (`wait` + ("`" + ` timeout. The `)))) + ((("`" + `func`) + ("`" + (` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last ` + "`"))) + ((`func` + ("`" + `\n * invocation.\n *\n * **Note:** If `)) + ("`" + (`leading` + "`"))))) + ((((` and ` + "`") + (`trailing` + ("`" + ` options are `))) + (("`" + (`true` + "`")) + (`, ` + ("`" + `func`)))) + ((("`" + ` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `) + ("`" + (`wait` + "`"))) + ((` timeout.\n *\n * If ` + ("`" + `wait`)) + ("`" + (` is ` + "`")))))) + (((((`0` + "`") + (` and ` + ("`" + `leading`))) + (("`" + (` is ` + "`")) + (`false` + ("`" + `, `)))) + ((("`" + `func`) + ("`" + (` invocation is deferred\n * until to the next tick, similar to ` + "`"))) + ((`setTimeout` + ("`" + ` with a timeout of `)) + ("`" + (`0` + "`"))))) + ((((`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between ` + "`") + (`_.debounce` + ("`" + ` and `))) + (("`" + (`_.throttle` + "`")) + (`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time ` + ("`" + `func`)))) + ((("`" + (` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke ` + "`")) + (`sendMail` + ("`" + ` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `))) + (("`" + (`batchLog` + "`")) + (` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any ` + ("`" + `maxWait`))))))))) + (((((((("`" + ` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `) + ("`" + (`maxWait` + "`"))) + ((` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have ` + ("`" + `lastArgs`)) + ("`" + (` which means ` + "`")))) + (((`func` + "`") + (` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\nmodule.exports = debounce;\n", + "/**\n * Performs a\n * [` + ("`" + `SameValueZero`))) + (("`" + (`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns ` + "`")) + (`true` + ("`" + ` if the values are equivalent, else `))))) + (((("`" + `false`) + ("`" + (`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nmodule.exports = eq;\n", + "var arrayEvery = require('./_arrayEvery'),\n baseEvery = require('./_baseEvery'),\n baseIteratee = require('./_baseIteratee'),\n isArray = require('./isArray'),\n isIterateeCall = require('./_isIterateeCall');\n\n/**\n * Checks if ` + "`"))) + ((`predicate` + ("`" + ` returns truthy for **all** elements of `)) + ("`" + (`collection` + "`")))) + (((`.\n * Iteration is stopped once ` + "`") + (`predicate` + ("`" + ` returns falsey. The predicate is\n * invoked with three arguments: (value, index|key, collection).\n *\n * **Note:** This method returns `))) + (("`" + (`true` + "`")) + (` for\n * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because\n * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of\n * elements of empty collections.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @param- {Object} [guard] Enables use as an iteratee for methods like ` + ("`" + `_.map`)))))) + ((((("`" + `.\n * @returns {boolean} Returns `) + ("`" + (`true` + "`"))) + ((` if all elements pass the predicate check,\n * else ` + ("`" + `false`)) + ("`" + (`.\n * @example\n *\n * _.every([true, 1, null, 'yes'], Boolean);\n * // => false\n *\n * var users = [\n * { 'user': 'barney', 'age': 36, 'active': false },\n * { 'user': 'fred', 'age': 40, 'active': false }\n * ];\n *\n * // The ` + "`")))) + (((`_.matches` + "`") + (` iteratee shorthand.\n * _.every(users, { 'user': 'barney', 'active': false });\n * // => false\n *\n * // The ` + ("`" + `_.matchesProperty`))) + (("`" + (` iteratee shorthand.\n * _.every(users, ['active', false]);\n * // => true\n *\n * // The ` + "`")) + (`_.property` + ("`" + ` iteratee shorthand.\n * _.every(users, 'active');\n * // => false\n */\nfunction every(collection, predicate, guard) {\n var func = isArray(collection) ? arrayEvery : baseEvery;\n if (guard && isIterateeCall(collection, predicate, guard)) {\n predicate = undefined;\n }\n return func(collection, baseIteratee(predicate, 3));\n}\n\nmodule.exports = every;\n", + "var arrayFilter = require('./_arrayFilter'),\n baseFilter = require('./_baseFilter'),\n baseIteratee = require('./_baseIteratee'),\n isArray = require('./isArray');\n\n/**\n * Iterates over elements of `))))) + (((("`" + `collection`) + ("`" + (`, returning an array of all elements\n * ` + "`"))) + ((`predicate` + ("`" + ` returns truthy for. The predicate is invoked with three\n * arguments: (value, index|key, collection).\n *\n * **Note:** Unlike `)) + ("`" + (`_.remove` + "`")))) + (((`, this method returns a new array.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n * @see _.reject\n * @example\n *\n * var users = [\n * { 'user': 'barney', 'age': 36, 'active': true },\n * { 'user': 'fred', 'age': 40, 'active': false }\n * ];\n *\n * _.filter(users, function(o) { return !o.active; });\n * // => objects for ['fred']\n *\n * // The ` + "`") + (`_.matches` + ("`" + ` iteratee shorthand.\n * _.filter(users, { 'age': 36, 'active': true });\n * // => objects for ['barney']\n *\n * // The `))) + (("`" + (`_.matchesProperty` + "`")) + (` iteratee shorthand.\n * _.filter(users, ['active', false]);\n * // => objects for ['fred']\n *\n * // The ` + ("`" + `_.property`))))))) + (((((("`" + ` iteratee shorthand.\n * _.filter(users, 'active');\n * // => objects for ['barney']\n */\nfunction filter(collection, predicate) {\n var func = isArray(collection) ? arrayFilter : baseFilter;\n return func(collection, baseIteratee(predicate, 3));\n}\n\nmodule.exports = filter;\n", + "var createFind = require('./_createFind'),\n findIndex = require('./findIndex');\n\n/**\n * Iterates over elements of `) + ("`" + (`collection` + "`"))) + ((`, returning the first element\n * ` + ("`" + `predicate`)) + ("`" + (` returns truthy for. The predicate is invoked with three\n * arguments: (value, index|key, collection).\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to inspect.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @param {number} [fromIndex=0] The index to search from.\n * @returns {*} Returns the matched element, else ` + "`")))) + (((`undefined` + "`") + (`.\n * @example\n *\n * var users = [\n * { 'user': 'barney', 'age': 36, 'active': true },\n * { 'user': 'fred', 'age': 40, 'active': false },\n * { 'user': 'pebbles', 'age': 1, 'active': true }\n * ];\n *\n * _.find(users, function(o) { return o.age < 40; });\n * // => object for 'barney'\n *\n * // The ` + ("`" + `_.matches`))) + (("`" + (` iteratee shorthand.\n * _.find(users, { 'age': 1, 'active': true });\n * // => object for 'pebbles'\n *\n * // The ` + "`")) + (`_.matchesProperty` + ("`" + ` iteratee shorthand.\n * _.find(users, ['active', false]);\n * // => object for 'fred'\n *\n * // The `))))) + (((("`" + `_.property`) + ("`" + (` iteratee shorthand.\n * _.find(users, 'active');\n * // => object for 'barney'\n */\nvar find = createFind(findIndex);\n\nmodule.exports = find;\n", + "var baseFindIndex = require('./_baseFindIndex'),\n baseIteratee = require('./_baseIteratee'),\n toInteger = require('./toInteger');\n\n/* Built-in method references for those with the same name as other ` + "`"))) + ((`lodash` + ("`" + ` methods. */\nvar nativeMax = Math.max;\n\n/**\n * This method is like `)) + ("`" + (`_.find` + "`")))) + (((` except that it returns the index of the first\n * element ` + "`") + (`predicate` + ("`" + ` returns truthy for instead of the element itself.\n *\n * @static\n * @memberOf _\n * @since 1.1.0\n * @category Array\n * @param {Array} array The array to inspect.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @param {number} [fromIndex=0] The index to search from.\n * @returns {number} Returns the index of the found element, else `))) + (("`" + (`-1` + "`")) + (`.\n * @example\n *\n * var users = [\n * { 'user': 'barney', 'active': false },\n * { 'user': 'fred', 'active': false },\n * { 'user': 'pebbles', 'active': true }\n * ];\n *\n * _.findIndex(users, function(o) { return o.user == 'barney'; });\n * // => 0\n *\n * // The ` + ("`" + `_.matches`)))))) + ((((("`" + ` iteratee shorthand.\n * _.findIndex(users, { 'user': 'fred', 'active': false });\n * // => 1\n *\n * // The `) + ("`" + (`_.matchesProperty` + "`"))) + ((` iteratee shorthand.\n * _.findIndex(users, ['active', false]);\n * // => 0\n *\n * // The ` + ("`" + `_.property`)) + ("`" + (` iteratee shorthand.\n * _.findIndex(users, 'active');\n * // => 2\n */\nfunction findIndex(array, predicate, fromIndex) {\n var length = array == null ? 0 : array.length;\n if (!length) {\n return -1;\n }\n var index = fromIndex == null ? 0 : toInteger(fromIndex);\n if (index < 0) {\n index = nativeMax(length + index, 0);\n }\n return baseFindIndex(array, baseIteratee(predicate, 3), index);\n}\n\nmodule.exports = findIndex;\n", + "var baseFlatten = require('./_baseFlatten'),\n map = require('./map');\n\n/**\n * Creates a flattened array of values by running each element in ` + "`")))) + (((`collection` + "`") + (`\n * thru ` + ("`" + `iteratee`))) + (("`" + (` and flattening the mapped results. The iteratee is invoked\n * with three arguments: (value, index|key, collection).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Array} Returns the new flattened array.\n * @example\n *\n * function duplicate(n) {\n * return [n, n];\n * }\n *\n * _.flatMap([1, 2], duplicate);\n * // => [1, 1, 2, 2]\n */\nfunction flatMap(collection, iteratee) {\n return baseFlatten(map(collection, iteratee), 1);\n}\n\nmodule.exports = flatMap;\n", + "var baseGet = require('./_baseGet');\n\n/**\n * Gets the value at ` + "`")) + (`path` + ("`" + ` of `))))) + (((("`" + `object`) + ("`" + (`. If the resolved value is\n * ` + "`"))) + ((`undefined` + ("`" + `, the `)) + ("`" + (`defaultValue` + "`")))) + (((` is returned in its place.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @param {*} [defaultValue] The value returned for ` + ("`" + `undefined`)) + ("`" + (` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.get(object, 'a[0].b.c');\n * // => 3\n *\n * _.get(object, ['a', '0', 'b', 'c']);\n * // => 3\n *\n * _.get(object, 'a.b.c', 'default');\n * // => 'default'\n */\nfunction get(object, path, defaultValue) {\n var result = object == null ? undefined : baseGet(object, path);\n return result === undefined ? defaultValue : result;\n}\n\nmodule.exports = get;\n", + "var baseHasIn = require('./_baseHasIn'),\n hasPath = require('./_hasPath');\n\n/**\n * Checks if ` + "`"))) + ((`path` + ("`" + ` is a direct or inherited property of `)) + ("`" + (`object` + "`")))))))) + (((((((`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @returns {boolean} Returns ` + "`") + (`true` + ("`" + ` if `))) + (("`" + (`path` + "`")) + (` exists, else ` + ("`" + `false`)))) + ((("`" + `.\n * @example\n *\n * var object = _.create({ 'a': _.create({ 'b': 2 }) });\n *\n * _.hasIn(object, 'a');\n * // => true\n *\n * _.hasIn(object, 'a.b');\n * // => true\n *\n * _.hasIn(object, ['a', 'b']);\n * // => true\n *\n * _.hasIn(object, 'b');\n * // => false\n */\nfunction hasIn(object, path) {\n return object != null && hasPath(object, path, baseHasIn);\n}\n\nmodule.exports = hasIn;\n", + "/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `) + ("`" + (`value` + "`"))) + ((`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nmodule.exports = identity;\n", + "var arrayMap = require('./_arrayMap'),\n baseIntersection = require('./_baseIntersection'),\n baseRest = require('./_baseRest'),\n castArrayLikeObject = require('./_castArrayLikeObject');\n\n/**\n * Creates an array of unique values that are included in all given arrays\n * using [` + ("`" + `SameValueZero`)) + ("`" + (`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons. The order and references of result values are\n * determined by the first array.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {...Array} [arrays] The arrays to inspect.\n * @returns {Array} Returns the new array of intersecting values.\n * @example\n *\n * _.intersection([2, 1], [2, 3]);\n * // => [2]\n */\nvar intersection = baseRest(function(arrays) {\n var mapped = arrayMap(arrays, castArrayLikeObject);\n return (mapped.length && mapped[0] === arrays[0])\n ? baseIntersection(mapped)\n : [];\n});\n\nmodule.exports = intersection;\n", + "var baseIsArguments = require('./_baseIsArguments'),\n isObjectLike = require('./isObjectLike');\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if ` + "`"))))) + ((((`value` + "`") + (` is likely an ` + ("`" + `arguments`))) + (("`" + (` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`")) + (`true` + ("`" + ` if `)))) + ((("`" + `value`) + ("`" + (` is an ` + "`"))) + ((`arguments` + ("`" + ` object,\n * else `)) + ("`" + (`false` + "`")))))) + (((((`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nmodule.exports = isArguments;\n", + "/**\n * Checks if ` + "`") + (`value` + ("`" + ` is classified as an `))) + (("`" + (`Array` + "`")) + (` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`)))) + ((("`" + ` if `) + ("`" + (`value` + "`"))) + ((` is an array, else ` + ("`" + `false`)) + ("`" + (`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nmodule.exports = isArray;\n", + "var isFunction = require('./isFunction'),\n isLength = require('./isLength');\n\n/**\n * Checks if ` + "`"))))) + ((((`value` + "`") + (` is array-like. A value is considered array-like if it's\n * not a function and has a ` + ("`" + `value.length`))) + (("`" + (` that's an integer greater than or\n * equal to ` + "`")) + (`0` + ("`" + ` and less than or equal to `)))) + ((("`" + (`Number.MAX_SAFE_INTEGER` + "`")) + (`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if ` + "`")) + (`value` + ("`" + ` is array-like, else `))))))) + (((((("`" + `false`) + ("`" + (`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\nmodule.exports = isArrayLike;\n", + "var isArrayLike = require('./isArrayLike'),\n isObjectLike = require('./isObjectLike');\n\n/**\n * This method is like ` + "`"))) + ((`_.isArrayLike` + ("`" + ` except that it also checks if `)) + ("`" + (`value` + "`")))) + (((`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`") + (`true` + ("`" + ` if `))) + (("`" + (`value` + "`")) + (` is an array-like object,\n * else ` + ("`" + `false`))))) + (((("`" + `.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n}\n\nmodule.exports = isArrayLikeObject;\n", + "var root = require('./_root'),\n stubFalse = require('./stubFalse');\n\n/** Detect free variable `) + ("`" + (`exports` + "`"))) + ((`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable ` + ("`" + `module`)) + ("`" + (`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension ` + "`")))) + (((`module.exports` + "`") + (`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other ` + ("`" + `lodash`))) + (("`" + (` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if ` + "`")) + (`value` + ("`" + ` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `)))))) + ((((("`" + `true`) + ("`" + (` if ` + "`"))) + ((`value` + ("`" + ` is a buffer, else `)) + ("`" + (`false` + "`")))) + (((`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nmodule.exports = isBuffer;\n", + "var baseIsEqual = require('./_baseIsEqual');\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, ` + "`") + (`Object` + ("`" + ` objects, regexes,\n * sets, strings, symbols, and typed arrays. `))) + (("`" + (`Object` + "`")) + (` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. ` + ("`" + `===`))))) + (((("`" + `.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `) + ("`" + (`true` + "`"))) + ((` if the values are equivalent, else ` + ("`" + `false`)) + ("`" + (`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n return baseIsEqual(value, other);\n}\n\nmodule.exports = isEqual;\n", + "var baseGetTag = require('./_baseGetTag'),\n isObject = require('./isObject');\n\n/** ` + "`")))) + (((`Object#toString` + ("`" + ` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `)) + ("`" + (`value` + "`"))) + ((` is classified as a ` + ("`" + `Function`)) + ("`" + (` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`"))))))))))) + ((((((((((`true` + "`") + (` if ` + ("`" + `value`))) + (("`" + (` is a function, else ` + "`")) + (`false` + ("`" + `.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `)))) + ((("`" + `Object#toString`) + ("`" + (` avoids issues with the ` + "`"))) + ((`typeof` + ("`" + ` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nmodule.exports = isFunction;\n", + "/** Used as references for various `)) + ("`" + (`Number` + "`"))))) + ((((` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if ` + "`") + (`value` + ("`" + ` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`))) + (("`" + (`ToLength` + "`")) + (`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`)))) + ((("`" + ` if `) + ("`" + (`value` + "`"))) + ((` is a valid length, else ` + ("`" + `false`)) + ("`" + (`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nmodule.exports = isLength;\n", + "var isNumber = require('./isNumber');\n\n/**\n * Checks if ` + "`")))))) + (((((`value` + "`") + (` is ` + ("`" + `NaN`))) + (("`" + (`.\n *\n * **Note:** This method is based on\n * [` + "`")) + (`Number.isNaN` + ("`" + `](https://mdn.io/Number/isNaN) and is not the same as\n * global [`)))) + ((("`" + `isNaN`) + ("`" + (`](https://mdn.io/isNaN) which returns ` + "`"))) + ((`true` + ("`" + ` for\n * `)) + ("`" + (`undefined` + "`"))))) + ((((` and other non-number values.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`") + (`true` + ("`" + ` if `))) + (("`" + (`value` + "`")) + (` is ` + ("`" + `NaN`)))) + ((("`" + `, else `) + ("`" + (`false` + "`"))) + ((`.\n * @example\n *\n * _.isNaN(NaN);\n * // => true\n *\n * _.isNaN(new Number(NaN));\n * // => true\n *\n * isNaN(undefined);\n * // => true\n *\n * _.isNaN(undefined);\n * // => false\n */\nfunction isNaN(value) {\n // An ` + ("`" + `NaN`)) + ("`" + (` primitive is the only value that is not equal to itself.\n // Perform the ` + "`"))))))) + ((((((`toStringTag` + "`") + (` check first to avoid errors with some\n // ActiveX objects in IE.\n return isNumber(value) && value != +value;\n}\n\nmodule.exports = isNaN;\n", + "/**\n * Checks if ` + ("`" + `value`))) + (("`" + (` is ` + "`")) + (`null` + ("`" + ` or `)))) + ((("`" + `undefined`) + ("`" + (`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`"))) + ((`true` + ("`" + ` if `)) + ("`" + (`value` + "`"))))) + ((((` is nullish, else ` + "`") + (`false` + ("`" + `.\n * @example\n *\n * _.isNil(null);\n * // => true\n *\n * _.isNil(void 0);\n * // => true\n *\n * _.isNil(NaN);\n * // => false\n */\nfunction isNil(value) {\n return value == null;\n}\n\nmodule.exports = isNil;\n", + "var baseGetTag = require('./_baseGetTag'),\n isObjectLike = require('./isObjectLike');\n\n/** `))) + (("`" + (`Object#toString` + "`")) + (` result references. */\nvar numberTag = '[object Number]';\n\n/**\n * Checks if ` + ("`" + `value`)))) + ((("`" + ` is classified as a `) + ("`" + (`Number` + "`"))) + ((` primitive or object.\n *\n * **Note:** To exclude ` + ("`" + `Infinity`)) + ("`" + (`, ` + "`")))))) + (((((`-Infinity` + "`") + (`, and ` + ("`" + `NaN`))) + (("`" + (`, which are\n * classified as numbers, use the ` + "`")) + (`_.isFinite` + ("`" + ` method.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `)))) + ((("`" + `true`) + ("`" + (` if ` + "`"))) + ((`value` + ("`" + ` is a number, else `)) + ("`" + (`false` + "`"))))) + ((((`.\n * @example\n *\n * _.isNumber(3);\n * // => true\n *\n * _.isNumber(Number.MIN_VALUE);\n * // => true\n *\n * _.isNumber(Infinity);\n * // => true\n *\n * _.isNumber('3');\n * // => false\n */\nfunction isNumber(value) {\n return typeof value == 'number' ||\n (isObjectLike(value) && baseGetTag(value) == numberTag);\n}\n\nmodule.exports = isNumber;\n", + "/**\n * Checks if ` + "`") + (`value` + ("`" + ` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `))) + (("`" + (`Object` + "`")) + (`. (e.g. arrays, functions, objects, regexes, ` + ("`" + `new Number(0)`)))) + ((("`" + (`, and ` + "`")) + (`new String('')` + ("`" + `)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `))) + (("`" + (`true` + "`")) + (` if ` + ("`" + `value`)))))))) + ((((((("`" + ` is an object, else `) + ("`" + (`false` + "`"))) + ((`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nmodule.exports = isObject;\n", + "/**\n * Checks if ` + ("`" + `value`)) + ("`" + (` is object-like. A value is object-like if it's not ` + "`")))) + (((`null` + "`") + (`\n * and has a ` + ("`" + `typeof`))) + (("`" + (` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`")) + (`true` + ("`" + ` if `))))) + (((("`" + `value`) + ("`" + (` is object-like, else ` + "`"))) + ((`false` + ("`" + `.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nmodule.exports = isObjectLike;\n", + "var baseGetTag = require('./_baseGetTag'),\n getPrototype = require('./_getPrototype'),\n isObjectLike = require('./isObjectLike');\n\n/** `)) + ("`" + (`Object#toString` + "`")))) + (((` result references. */\nvar objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the ` + "`") + (`Object` + ("`" + ` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Checks if `))) + (("`" + (`value` + "`")) + (` is a plain object, that is, an object created by the\n * ` + ("`" + `Object`)))))) + ((((("`" + ` constructor or one with a `) + ("`" + (`[[Prototype]]` + "`"))) + ((` of ` + ("`" + `null`)) + ("`" + (`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`")))) + (((`true` + "`") + (` if ` + ("`" + `value`))) + (("`" + (` is a plain object, else ` + "`")) + (`false` + ("`" + `.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n funcToString.call(Ctor) == objectCtorString;\n}\n\nmodule.exports = isPlainObject;\n", + "var baseGetTag = require('./_baseGetTag'),\n isArray = require('./isArray'),\n isObjectLike = require('./isObjectLike');\n\n/** `))))) + (((("`" + `Object#toString`) + ("`" + (` result references. */\nvar stringTag = '[object String]';\n\n/**\n * Checks if ` + "`"))) + ((`value` + ("`" + ` is classified as a `)) + ("`" + (`String` + "`")))) + (((` primitive or object.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + "`") + (`true` + ("`" + ` if `))) + (("`" + (`value` + "`")) + (` is a string, else ` + ("`" + `false`))))))) + (((((("`" + `.\n * @example\n *\n * _.isString('abc');\n * // => true\n *\n * _.isString(1);\n * // => false\n */\nfunction isString(value) {\n return typeof value == 'string' ||\n (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);\n}\n\nmodule.exports = isString;\n", + "var baseGetTag = require('./_baseGetTag'),\n isObjectLike = require('./isObjectLike');\n\n/** `) + ("`" + (`Object#toString` + "`"))) + ((` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if ` + ("`" + `value`)) + ("`" + (` is classified as a ` + "`")))) + (((`Symbol` + "`") + (` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns ` + ("`" + `true`))) + (("`" + (` if ` + "`")) + (`value` + ("`" + ` is a symbol, else `))))) + (((("`" + `false`) + ("`" + (`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nmodule.exports = isSymbol;\n", + "var baseIsTypedArray = require('./_baseIsTypedArray'),\n baseUnary = require('./_baseUnary'),\n nodeUtil = require('./_nodeUtil');\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if ` + "`"))) + ((`value` + ("`" + ` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `)) + ("`" + (`true` + "`")))) + (((` if ` + "`") + (`value` + ("`" + ` is a typed array, else `))) + (("`" + (`false` + "`")) + (`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nmodule.exports = isTypedArray;\n", + "var arrayLikeKeys = require('./_arrayLikeKeys'),\n baseKeys = require('./_baseKeys'),\n isArrayLike = require('./isArrayLike');\n\n/**\n * Creates an array of the own enumerable property names of ` + ("`" + `object`)))))) + ((((("`" + `.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nmodule.exports = keys;\n", + "/**\n * Gets the last element of `) + ("`" + (`array` + "`"))) + ((`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to query.\n * @returns {*} Returns the last element of ` + ("`" + `array`)) + ("`" + (`.\n * @example\n *\n * _.last([1, 2, 3]);\n * // => 3\n */\nfunction last(array) {\n var length = array == null ? 0 : array.length;\n return length ? array[length - 1] : undefined;\n}\n\nmodule.exports = last;\n", + "var arrayMap = require('./_arrayMap'),\n baseIteratee = require('./_baseIteratee'),\n baseMap = require('./_baseMap'),\n isArray = require('./isArray');\n\n/**\n * Creates an array of values by running each element in ` + "`")))) + (((`collection` + "`") + (` thru\n * ` + ("`" + `iteratee`))) + (("`" + (`. The iteratee is invoked with three arguments:\n * (value, index|key, collection).\n *\n * Many lodash methods are guarded to work as iteratees for methods like\n * ` + "`")) + (`_.every` + ("`" + `, `))))) + (((("`" + `_.filter`) + ("`" + (`, ` + "`"))) + ((`_.map` + ("`" + `, `)) + ("`" + (`_.mapValues` + "`")))) + (((`, ` + ("`" + `_.reject`)) + ("`" + (`, and ` + "`"))) + ((`_.some` + ("`" + `.\n *\n * The guarded methods are:\n * `)) + ("`" + (`ary` + "`"))))))))) + ((((((((`, ` + "`") + (`chunk` + ("`" + `, `))) + (("`" + (`curry` + "`")) + (`, ` + ("`" + `curryRight`)))) + ((("`" + `, `) + ("`" + (`drop` + "`"))) + ((`, ` + ("`" + `dropRight`)) + ("`" + (`, ` + "`"))))) + ((((`every` + "`") + (`,\n * ` + ("`" + `fill`))) + (("`" + (`, ` + "`")) + (`invert` + ("`" + `, `)))) + ((("`" + `parseInt`) + ("`" + (`, ` + "`"))) + ((`random` + ("`" + `, `)) + ("`" + (`range` + "`")))))) + (((((`, ` + "`") + (`rangeRight` + ("`" + `, `))) + (("`" + (`repeat` + "`")) + (`,\n * ` + ("`" + `sampleSize`)))) + ((("`" + `, `) + ("`" + (`slice` + "`"))) + ((`, ` + ("`" + `some`)) + ("`" + (`, ` + "`"))))) + ((((`sortBy` + "`") + (`, ` + ("`" + `split`))) + (("`" + (`, ` + "`")) + (`take` + ("`" + `, `)))) + ((("`" + `takeRight`) + ("`" + (`,\n * ` + "`"))) + ((`template` + ("`" + `, `)) + ("`" + (`trim` + "`"))))))) + ((((((`, ` + "`") + (`trimEnd` + ("`" + `, `))) + (("`" + (`trimStart` + "`")) + (`, and ` + ("`" + `words`)))) + ((("`" + `\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n * @example\n *\n * function square(n) {\n * return n * n;\n * }\n *\n * _.map([4, 8], square);\n * // => [16, 64]\n *\n * _.map({ 'a': 4, 'b': 8 }, square);\n * // => [16, 64] (iteration order is not guaranteed)\n *\n * var users = [\n * { 'user': 'barney' },\n * { 'user': 'fred' }\n * ];\n *\n * // The `) + ("`" + (`_.property` + "`"))) + ((` iteratee shorthand.\n * _.map(users, 'user');\n * // => ['barney', 'fred']\n */\nfunction map(collection, iteratee) {\n var func = isArray(collection) ? arrayMap : baseMap;\n return func(collection, baseIteratee(iteratee, 3));\n}\n\nmodule.exports = map;\n", + "var baseAssignValue = require('./_baseAssignValue'),\n baseForOwn = require('./_baseForOwn'),\n baseIteratee = require('./_baseIteratee');\n\n/**\n * Creates an object with the same keys as ` + ("`" + `object`)) + ("`" + (` and values generated\n * by running each own enumerable string keyed property of ` + "`"))))) + ((((`object` + "`") + (` thru\n * ` + ("`" + `iteratee`))) + (("`" + (`. The iteratee is invoked with three arguments:\n * (value, key, object).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns the new mapped object.\n * @see _.mapKeys\n * @example\n *\n * var users = {\n * 'fred': { 'user': 'fred', 'age': 40 },\n * 'pebbles': { 'user': 'pebbles', 'age': 1 }\n * };\n *\n * _.mapValues(users, function(o) { return o.age; });\n * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)\n *\n * // The ` + "`")) + (`_.property` + ("`" + ` iteratee shorthand.\n * _.mapValues(users, 'age');\n * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)\n */\nfunction mapValues(object, iteratee) {\n var result = {};\n iteratee = baseIteratee(iteratee, 3);\n\n baseForOwn(object, function(value, key, object) {\n baseAssignValue(result, key, iteratee(value, key, object));\n });\n return result;\n}\n\nmodule.exports = mapValues;\n", + "var baseExtremum = require('./_baseExtremum'),\n baseGt = require('./_baseGt'),\n identity = require('./identity');\n\n/**\n * Computes the maximum value of `)))) + ((("`" + `array`) + ("`" + (`. If ` + "`"))) + ((`array` + ("`" + ` is empty or falsey,\n * `)) + ("`" + (`undefined` + "`")))))) + (((((` is returned.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Math\n * @param {Array} array The array to iterate over.\n * @returns {*} Returns the maximum value.\n * @example\n *\n * _.max([4, 2, 8, 6]);\n * // => 8\n *\n * _.max([]);\n * // => undefined\n */\nfunction max(array) {\n return (array && array.length)\n ? baseExtremum(array, identity, baseGt)\n : undefined;\n}\n\nmodule.exports = max;\n", + "var MapCache = require('./_MapCache');\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that memoizes the result of ` + "`") + (`func` + ("`" + `. If `))) + (("`" + (`resolver` + "`")) + (` is\n * provided, it determines the cache key for storing the result based on the\n * arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is used as the map cache key. The ` + ("`" + `func`)))) + ((("`" + `\n * is invoked with the `) + ("`" + (`this` + "`"))) + ((` binding of the memoized function.\n *\n * **Note:** The cache is exposed as the ` + ("`" + `cache`)) + ("`" + (` property on the memoized\n * function. Its creation may be customized by replacing the ` + "`"))))) + ((((`_.memoize.Cache` + "`") + (`\n * constructor with one whose instances implement the\n * [` + ("`" + `Map`))) + (("`" + (`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)\n * method interface of ` + "`")) + (`clear` + ("`" + `, `)))) + ((("`" + (`delete` + "`")) + (`, ` + ("`" + `get`))) + (("`" + (`, ` + "`")) + (`has` + ("`" + `, and `)))))))) + ((((((("`" + `set`) + ("`" + (`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to have its output memoized.\n * @param {Function} [resolver] The function to resolve the cache key.\n * @returns {Function} Returns the new memoized function.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n * var other = { 'c': 3, 'd': 4 };\n *\n * var values = _.memoize(_.values);\n * values(object);\n * // => [1, 2]\n *\n * values(other);\n * // => [3, 4]\n *\n * object.a = 2;\n * values(object);\n * // => [1, 2]\n *\n * // Modify the result cache.\n * values.cache.set(object, ['a', 'b']);\n * values(object);\n * // => ['a', 'b']\n *\n * // Replace ` + "`"))) + ((`_.memoize.Cache` + ("`" + `.\n * _.memoize.Cache = WeakMap;\n */\nfunction memoize(func, resolver) {\n if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n var memoized = function() {\n var args = arguments,\n key = resolver ? resolver.apply(this, args) : args[0],\n cache = memoized.cache;\n\n if (cache.has(key)) {\n return cache.get(key);\n }\n var result = func.apply(this, args);\n memoized.cache = cache.set(key, result) || cache;\n return result;\n };\n memoized.cache = new (memoize.Cache || MapCache);\n return memoized;\n}\n\n// Expose `)) + ("`" + (`MapCache` + "`")))) + (((`.\nmemoize.Cache = MapCache;\n\nmodule.exports = memoize;\n", + "var baseExtremum = require('./_baseExtremum'),\n baseLt = require('./_baseLt'),\n identity = require('./identity');\n\n/**\n * Computes the minimum value of ` + "`") + (`array` + ("`" + `. If `))) + (("`" + (`array` + "`")) + (` is empty or falsey,\n * ` + ("`" + `undefined`))))) + (((("`" + ` is returned.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Math\n * @param {Array} array The array to iterate over.\n * @returns {*} Returns the minimum value.\n * @example\n *\n * _.min([4, 2, 8, 6]);\n * // => 2\n *\n * _.min([]);\n * // => undefined\n */\nfunction min(array) {\n return (array && array.length)\n ? baseExtremum(array, identity, baseLt)\n : undefined;\n}\n\nmodule.exports = min;\n", + "/**\n * This method returns `) + ("`" + (`undefined` + "`"))) + ((`.\n *\n * @static\n * @memberOf _\n * @since 2.3.0\n * @category Util\n * @example\n *\n * _.times(2, _.noop);\n * // => [undefined, undefined]\n */\nfunction noop() {\n // No operation performed.\n}\n\nmodule.exports = noop;\n", + "var root = require('./_root');\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\nmodule.exports = now;\n", + "var baseProperty = require('./_baseProperty'),\n basePropertyDeep = require('./_basePropertyDeep'),\n isKey = require('./_isKey'),\n toKey = require('./_toKey');\n\n/**\n * Creates a function that returns the value at ` + ("`" + `path`)) + ("`" + (` of a given object.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {Array|string} path The path of the property to get.\n * @returns {Function} Returns the new accessor function.\n * @example\n *\n * var objects = [\n * { 'a': { 'b': 2 } },\n * { 'a': { 'b': 1 } }\n * ];\n *\n * _.map(objects, _.property('a.b'));\n * // => [2, 1]\n *\n * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');\n * // => [1, 2]\n */\nfunction property(path) {\n return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);\n}\n\nmodule.exports = property;\n", + "var createRange = require('./_createRange');\n\n/**\n * Creates an array of numbers (positive and/or negative) progressing from\n * ` + "`")))) + (((`start` + "`") + (` up to, but not including, ` + ("`" + `end`))) + (("`" + (`. A step of ` + "`")) + (`-1` + ("`" + ` is used if a negative\n * `)))))) + ((((("`" + `start`) + ("`" + (` is specified without an ` + "`"))) + ((`end` + ("`" + ` or `)) + ("`" + (`step` + "`")))) + (((`. If ` + "`") + (`end` + ("`" + ` is not specified,\n * it's set to `))) + (("`" + (`start` + "`")) + (` with ` + ("`" + `start`))))) + (((("`" + ` then set to `) + ("`" + (`0` + "`"))) + ((`.\n *\n * **Note:** JavaScript follows the IEEE-754 standard for resolving\n * floating-point values which can produce unexpected results.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {number} [start=0] The start of the range.\n * @param {number} end The end of the range.\n * @param {number} [step=1] The value to increment or decrement by.\n * @returns {Array} Returns the range of numbers.\n * @see _.inRange, _.rangeRight\n * @example\n *\n * _.range(4);\n * // => [0, 1, 2, 3]\n *\n * _.range(-4);\n * // => [0, -1, -2, -3]\n *\n * _.range(1, 5);\n * // => [1, 2, 3, 4]\n *\n * _.range(0, 20, 5);\n * // => [0, 5, 10, 15]\n *\n * _.range(0, -4, -1);\n * // => [0, -1, -2, -3]\n *\n * _.range(1, 4, 0);\n * // => [1, 1, 1]\n *\n * _.range(0);\n * // => []\n */\nvar range = createRange();\n\nmodule.exports = range;\n", + "var arraySome = require('./_arraySome'),\n baseIteratee = require('./_baseIteratee'),\n baseSome = require('./_baseSome'),\n isArray = require('./isArray'),\n isIterateeCall = require('./_isIterateeCall');\n\n/**\n * Checks if ` + ("`" + `predicate`)) + ("`" + (` returns truthy for **any** element of ` + "`")))) + (((`collection` + ("`" + `.\n * Iteration is stopped once `)) + ("`" + (`predicate` + "`"))) + ((` returns truthy. The predicate is\n * invoked with three arguments: (value, index|key, collection).\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @param- {Object} [guard] Enables use as an iteratee for methods like ` + ("`" + `_.map`)) + ("`" + (`.\n * @returns {boolean} Returns ` + "`"))))))) + ((((((`true` + "`") + (` if any element passes the predicate check,\n * else ` + ("`" + `false`))) + (("`" + (`.\n * @example\n *\n * _.some([null, 0, 'yes', false], Boolean);\n * // => true\n *\n * var users = [\n * { 'user': 'barney', 'active': true },\n * { 'user': 'fred', 'active': false }\n * ];\n *\n * // The ` + "`")) + (`_.matches` + ("`" + ` iteratee shorthand.\n * _.some(users, { 'user': 'barney', 'active': false });\n * // => false\n *\n * // The `)))) + ((("`" + `_.matchesProperty`) + ("`" + (` iteratee shorthand.\n * _.some(users, ['active', false]);\n * // => true\n *\n * // The ` + "`"))) + ((`_.property` + ("`" + ` iteratee shorthand.\n * _.some(users, 'active');\n * // => true\n */\nfunction some(collection, predicate, guard) {\n var func = isArray(collection) ? arraySome : baseSome;\n if (guard && isIterateeCall(collection, predicate, guard)) {\n predicate = undefined;\n }\n return func(collection, baseIteratee(predicate, 3));\n}\n\nmodule.exports = some;\n", + "var baseFlatten = require('./_baseFlatten'),\n baseOrderBy = require('./_baseOrderBy'),\n baseRest = require('./_baseRest'),\n isIterateeCall = require('./_isIterateeCall');\n\n/**\n * Creates an array of elements, sorted in ascending order by the results of\n * running each element in a collection thru each iteratee. This method\n * performs a stable sort, that is, it preserves the original sort order of\n * equal elements. The iteratees are invoked with one argument: (value).\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {...(Function|Function[])} [iteratees=[_.identity]]\n * The iteratees to sort by.\n * @returns {Array} Returns the new sorted array.\n * @example\n *\n * var users = [\n * { 'user': 'fred', 'age': 48 },\n * { 'user': 'barney', 'age': 36 },\n * { 'user': 'fred', 'age': 40 },\n * { 'user': 'barney', 'age': 34 }\n * ];\n *\n * _.sortBy(users, [function(o) { return o.user; }]);\n * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]\n *\n * _.sortBy(users, ['user', 'age']);\n * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]\n */\nvar sortBy = baseRest(function(collection, iteratees) {\n if (collection == null) {\n return [];\n }\n var length = iteratees.length;\n if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {\n iteratees = [];\n } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {\n iteratees = [iteratees[0]];\n }\n return baseOrderBy(collection, baseFlatten(iteratees, 1), []);\n});\n\nmodule.exports = sortBy;\n", + "/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nmodule.exports = stubArray;\n", + "/**\n * This method returns `)) + ("`" + (`false` + "`"))))) + ((((`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns ` + "`") + (`false` + ("`" + `.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nmodule.exports = stubFalse;\n", + "var debounce = require('./debounce'),\n isObject = require('./isObject');\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `))) + (("`" + (`func` + "`")) + (` at most once per\n * every ` + ("`" + `wait`)))) + ((("`" + ` milliseconds. The throttled function comes with a `) + ("`" + (`cancel` + "`"))) + ((`\n * method to cancel delayed ` + ("`" + `func`)) + ("`" + (` invocations and a ` + "`")))))) + (((((`flush` + "`") + (` method to\n * immediately invoke them. Provide ` + ("`" + `options`))) + (("`" + (` to indicate whether ` + "`")) + (`func` + ("`" + `\n * should be invoked on the leading and/or trailing edge of the `)))) + ((("`" + `wait`) + ("`" + (`\n * timeout. The ` + "`"))) + ((`func` + ("`" + ` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `)) + ("`" + (`func` + "`"))))) + ((((` invocation.\n *\n * **Note:** If ` + "`") + (`leading` + ("`" + ` and `))) + (("`" + (`trailing` + "`")) + (` options are ` + ("`" + `true`)))) + ((("`" + (`, ` + "`")) + (`func` + ("`" + ` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `))) + (("`" + (`wait` + "`")) + (` timeout.\n *\n * If ` + ("`" + `wait`)))))))))) + ((((((((("`" + ` is `) + ("`" + (`0` + "`"))) + ((` and ` + ("`" + `leading`)) + ("`" + (` is ` + "`")))) + (((`false` + "`") + (`, ` + ("`" + `func`))) + (("`" + (` invocation is deferred\n * until to the next tick, similar to ` + "`")) + (`setTimeout` + ("`" + ` with a timeout of `))))) + (((("`" + `0`) + ("`" + (`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between ` + "`"))) + ((`_.throttle` + ("`" + ` and `)) + ("`" + (`_.debounce` + "`")))) + (((`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke ` + "`") + (`renewToken` + ("`" + ` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\nmodule.exports = throttle;\n", + "var toNumber = require('./toNumber');\n\n/** Used as references for various `))) + (("`" + (`Number` + "`")) + (` constants. */\nvar INFINITY = 1 / 0,\n MAX_INTEGER = 1.7976931348623157e+308;\n\n/**\n * Converts ` + ("`" + `value`)))))) + ((((("`" + ` to a finite number.\n *\n * @static\n * @memberOf _\n * @since 4.12.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {number} Returns the converted number.\n * @example\n *\n * _.toFinite(3.2);\n * // => 3.2\n *\n * _.toFinite(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toFinite(Infinity);\n * // => 1.7976931348623157e+308\n *\n * _.toFinite('3.2');\n * // => 3.2\n */\nfunction toFinite(value) {\n if (!value) {\n return value === 0 ? value : 0;\n }\n value = toNumber(value);\n if (value === INFINITY || value === -INFINITY) {\n var sign = (value < 0 ? -1 : 1);\n return sign * MAX_INTEGER;\n }\n return value === value ? value : 0;\n}\n\nmodule.exports = toFinite;\n", + "var toFinite = require('./toFinite');\n\n/**\n * Converts `) + ("`" + (`value` + "`"))) + ((` to an integer.\n *\n * **Note:** This method is loosely based on\n * [` + ("`" + `ToInteger`)) + ("`" + (`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {number} Returns the converted integer.\n * @example\n *\n * _.toInteger(3.2);\n * // => 3\n *\n * _.toInteger(Number.MIN_VALUE);\n * // => 0\n *\n * _.toInteger(Infinity);\n * // => 1.7976931348623157e+308\n *\n * _.toInteger('3.2');\n * // => 3\n */\nfunction toInteger(value) {\n var result = toFinite(value),\n remainder = result % 1;\n\n return result === result ? (remainder ? result - remainder : result) : 0;\n}\n\nmodule.exports = toInteger;\n", + "var isObject = require('./isObject'),\n isSymbol = require('./isSymbol');\n\n/** Used as references for various ` + "`")))) + (((`Number` + "`") + (` constants. */\nvar NAN = 0 / 0;\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on ` + ("`" + `root`))) + (("`" + (`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts ` + "`")) + (`value` + ("`" + ` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = toNumber;\n", + "var baseToString = require('./_baseToString');\n\n/**\n * Converts `))))) + (((("`" + `value`) + ("`" + (` to a string. An empty string is returned for ` + "`"))) + ((`null` + ("`" + `\n * and `)) + ("`" + (`undefined` + "`")))) + (((` values. The sign of ` + "`") + (`-0` + ("`" + ` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\nmodule.exports = toString;\n", + "var baseIteratee = require('./_baseIteratee'),\n baseUniq = require('./_baseUniq');\n\n/**\n * This method is like `))) + (("`" + (`_.uniq` + "`")) + (` except that it accepts ` + ("`" + `iteratee`))))))) + (((((("`" + ` which is\n * invoked for each element in `) + ("`" + (`array` + "`"))) + ((` to generate the criterion by which\n * uniqueness is computed. The order of result values is determined by the\n * order they occur in the array. The iteratee is invoked with one argument:\n * (value).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Array\n * @param {Array} array The array to inspect.\n * @param {Function} [iteratee=_.identity] The iteratee invoked per element.\n * @returns {Array} Returns the new duplicate free array.\n * @example\n *\n * _.uniqBy([2.1, 1.2, 2.3], Math.floor);\n * // => [2.1, 1.2]\n *\n * // The ` + ("`" + `_.property`)) + ("`" + (` iteratee shorthand.\n * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');\n * // => [{ 'x': 1 }, { 'x': 2 }]\n */\nfunction uniqBy(array, iteratee) {\n return (array && array.length) ? baseUniq(array, baseIteratee(iteratee, 2)) : [];\n}\n\nmodule.exports = uniqBy;\n", + "var Mexp=require('./postfix_evaluator.js');\r\nMexp.prototype.formulaEval = function () {\r\n\t\"use strict\";\r\n\tvar stack=[],pop1,pop2,pop3;\r\n\tvar disp=[];\r\n\tvar temp='';\r\n\tvar arr=this.value;\r\n\tfor(var i=0;i\"+pop2.value+\"\"+arr[i].show+\"\"+pop1.value+\"\",type:10});\r\n\t\t\telse disp.push({value:(pop2.type!=1?\"(\":\"\")+pop2.value+(pop2.type!=1?\")\":\"\")+\"\"+pop1.value+\"\",type:1});\r\n\t\t}\r\n\t\telse if(arr[i].type===2||arr[i].type===9){\r\n\t\t\tpop1=disp.pop();\r\n\t\t\tpop2=disp.pop();\r\n\t\t\tdisp.push({value:(pop2.type!=1?\"(\":\"\")+pop2.value+(pop2.type!=1?\")\":\"\")+arr[i].show+(pop1.type!=1?\"(\":\"\")+pop1.value+(pop1.type!=1?\")\":\"\"),type:arr[i].type});\r\n\t\t}\r\n\t\telse if(arr[i].type===12){\r\n\t\t\tpop1=disp.pop();\r\n\t\t\tpop2=disp.pop();\r\n\t\t\tpop3=disp.pop();\r\n\t\t\tdisp.push({value:arr[i].show+\"(\"+pop3.value+\",\"+pop2.value+\",\"+pop1.value+\")\",type:12});\r\n\t\t}\r\n\t}\r\n\treturn disp[0].value;\r\n};\r\nmodule.exports=Mexp;", + "var Mexp=require('./math_function.js');\r\n\tfunction inc(arr,val){\r\n\t\tfor(var i=0;i(newAr.length-2)?newAr.length-1:inpStr.length-i);x>0;x--){\r\n\t\t\t\tfor(y=0;yprep)stack.push(elem);\r\n\t\t\t\telse {\r\n\t\t\t\t\twhile(prep>=pre&&!flag||flag&&pre1) {\r\n\t\tthrow(new Mexp.exception(\"Uncaught Syntax error\"));\r\n\t}\r\n\treturn stack[0].value>1000000000000000?\"Infinity\":parseFloat(stack[0].value.toFixed(15));\r\n};\r\nMexp.eval=function(str,tokens,obj){\r\n\tif (typeof tokens===\"undefined\") {\r\n\t\treturn this.lex(str).toPostfix().postfixEval();\r\n\t}\r\n\telse if (typeof obj===\"undefined\") {\r\n\t\tif (typeof tokens.length!==\"undefined\") \r\n\t\t\treturn this.lex(str,tokens).toPostfix().postfixEval();\r\n\t\telse\r\n\t\t\treturn this.lex(str).toPostfix().postfixEval(tokens);\r\n\t}\r\n\telse\r\n\t\treturn this.lex(str,tokens).toPostfix().postfixEval(obj);\r\n};\r\nmodule.exports=Mexp;", + "/*\nobject-assign\n(c) Sindre Sorhus\n@license MIT\n*/\n\n'use strict';\n/* eslint-disable no-unused-vars */\nvar getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line no-new-wrappers\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (err) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (getOwnPropertySymbols) {\n\t\t\tsymbols = getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n", + "// Generated by CoffeeScript 1.12.2\n(function() {\n var getNanoSeconds, hrtime, loadTime, moduleLoadTime, nodeLoadTime, upTime;\n\n if ((typeof performance !== \"undefined\" && performance !== null) && performance.now) {\n module.exports = function() {\n return performance.now();\n };\n } else if ((typeof process !== \"undefined\" && process !== null) && process.hrtime) {\n module.exports = function() {\n return (getNanoSeconds() - nodeLoadTime) / 1e6;\n };\n hrtime = process.hrtime;\n getNanoSeconds = function() {\n var hr;\n hr = hrtime();\n return hr[0] * 1e9 + hr[1];\n };\n moduleLoadTime = getNanoSeconds();\n upTime = process.uptime() * 1e9;\n nodeLoadTime = moduleLoadTime - upTime;\n } else if (Date.now) {\n module.exports = function() {\n return Date.now() - loadTime;\n };\n loadTime = Date.now();\n } else {\n module.exports = function() {\n return new Date().getTime() - loadTime;\n };\n loadTime = new Date().getTime();\n }\n\n}).call(this);\n\n//# sourceMappingURL=performance-now.js.map\n", + "// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n", + "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');\n\nfunction emptyFunction() {}\nfunction emptyFunctionWithReset() {}\nemptyFunctionWithReset.resetWarningCache = emptyFunction;\n\nmodule.exports = function() {\n function shim(props, propName, componentName, location, propFullName, secret) {\n if (secret === ReactPropTypesSecret) {\n // It is still safe when called from React.\n return;\n }\n var err = new Error(\n 'Calling PropTypes validators directly is not supported by the ` + "`")))) + (((`prop-types` + "`") + (` package. ' +\n 'Use PropTypes.checkPropTypes() to call them. ' +\n 'Read more at http://fb.me/use-check-prop-types'\n );\n err.name = 'Invariant Violation';\n throw err;\n };\n shim.isRequired = shim;\n function getShim() {\n return shim;\n };\n // Important!\n // Keep this list in sync with production version in ` + ("`" + `./factoryWithTypeCheckers.js`))) + (("`" + (`.\n var ReactPropTypes = {\n array: shim,\n bool: shim,\n func: shim,\n number: shim,\n object: shim,\n string: shim,\n symbol: shim,\n\n any: shim,\n arrayOf: getShim,\n element: shim,\n elementType: shim,\n instanceOf: getShim,\n node: shim,\n objectOf: getShim,\n oneOf: getShim,\n oneOfType: getShim,\n shape: getShim,\n exact: getShim,\n\n checkPropTypes: emptyFunctionWithReset,\n resetWarningCache: emptyFunction\n };\n\n ReactPropTypes.PropTypes = ReactPropTypes;\n\n return ReactPropTypes;\n};\n", + "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nif (process.env.NODE_ENV !== 'production') {\n var ReactIs = require('react-is');\n\n // By explicitly using ` + "`")) + (`prop-types` + ("`" + ` you are opting into new development behavior.\n // http://fb.me/prop-types-in-prod\n var throwOnDirectAccess = true;\n module.exports = require('./factoryWithTypeCheckers')(ReactIs.isElement, throwOnDirectAccess);\n} else {\n // By explicitly using `))))) + (((("`" + `prop-types`) + ("`" + (` you are opting into new production behavior.\n // http://fb.me/prop-types-in-prod\n module.exports = require('./factoryWithThrowingShims')();\n}\n", + "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';\n\nmodule.exports = ReactPropTypesSecret;\n", + "var now = require('performance-now')\n , root = typeof window === 'undefined' ? global : window\n , vendors = ['moz', 'webkit']\n , suffix = 'AnimationFrame'\n , raf = root['request' + suffix]\n , caf = root['cancel' + suffix] || root['cancelRequest' + suffix]\n\nfor(var i = 0; !raf && i < vendors.length; i++) {\n raf = root[vendors[i] + 'Request' + suffix]\n caf = root[vendors[i] + 'Cancel' + suffix]\n || root[vendors[i] + 'CancelRequest' + suffix]\n}\n\n// Some versions of FF have rAF but not cAF\nif(!raf || !caf) {\n var last = 0\n , id = 0\n , queue = []\n , frameDuration = 1000 / 60\n\n raf = function(callback) {\n if(queue.length === 0) {\n var _now = now()\n , next = Math.max(0, frameDuration - (_now - last))\n last = next + _now\n setTimeout(function() {\n var cp = queue.slice(0)\n // Clear queue here to prevent\n // callbacks from appending listeners\n // to the current frame's queue\n queue.length = 0\n for(var i = 0; i < cp.length; i++) {\n if(!cp[i].cancelled) {\n try{\n cp[i].callback(last)\n } catch(e) {\n setTimeout(function() { throw e }, 0)\n }\n }\n }\n }, Math.round(next))\n }\n queue.push({\n handle: ++id,\n callback: callback,\n cancelled: false\n })\n return id\n }\n\n caf = function(handle) {\n for(var i = 0; i < queue.length; i++) {\n if(queue[i].handle === handle) {\n queue[i].cancelled = true\n }\n }\n }\n}\n\nmodule.exports = function(fn) {\n // Wrap in a new function to prevent\n // ` + "`"))) + ((`cancel` + ("`" + ` potentially being assigned\n // to the native rAF function\n return raf.call(root, fn)\n}\nmodule.exports.cancel = function() {\n caf.apply(root, arguments)\n}\nmodule.exports.polyfill = function(object) {\n if (!object) {\n object = root;\n }\n object.requestAnimationFrame = raf\n object.cancelAnimationFrame = caf\n}\n", + "/** @license React v16.8.4\n * react-dom.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n/*\n Modernizr 3.0.0pre (Custom Build) | MIT\n*/\n'use strict';var aa=require(\"react\"),n=require(\"object-assign\"),r=require(\"scheduler\");function ba(a,b,c,d,e,f,g,h){if(!a){a=void 0;if(void 0===b)a=Error(\"Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.\");else{var l=[c,d,e,f,g,h],k=0;a=Error(b.replace(/%s/g,function(){return l[k++]}));a.name=\"Invariant Violation\"}a.framesToPop=1;throw a;}}\nfunction x(a){for(var b=arguments.length-1,c=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+a,d=0;dthis.eventPool.length&&this.eventPool.push(a)}\nfunction hb(a){a.eventPool=[];a.getPooled=ib;a.release=jb}var kb=y.extend({data:null}),lb=y.extend({data:null}),mb=[9,13,27,32],nb=Ra&&\"CompositionEvent\"in window,ob=null;Ra&&\"documentMode\"in document&&(ob=document.documentMode);\nvar pb=Ra&&\"TextEvent\"in window&&!ob,qb=Ra&&(!nb||ob&&8=ob),rb=String.fromCharCode(32),sb={beforeInput:{phasedRegistrationNames:{bubbled:\"onBeforeInput\",captured:\"onBeforeInputCapture\"},dependencies:[\"compositionend\",\"keypress\",\"textInput\",\"paste\"]},compositionEnd:{phasedRegistrationNames:{bubbled:\"onCompositionEnd\",captured:\"onCompositionEndCapture\"},dependencies:\"blur compositionend keydown keypress keyup mousedown\".split(\" \")},compositionStart:{phasedRegistrationNames:{bubbled:\"onCompositionStart\",\ncaptured:\"onCompositionStartCapture\"},dependencies:\"blur compositionstart keydown keypress keyup mousedown\".split(\" \")},compositionUpdate:{phasedRegistrationNames:{bubbled:\"onCompositionUpdate\",captured:\"onCompositionUpdateCapture\"},dependencies:\"blur compositionupdate keydown keypress keyup mousedown\".split(\" \")}},tb=!1;\nfunction ub(a,b){switch(a){case \"keyup\":return-1!==mb.indexOf(b.keyCode);case \"keydown\":return 229!==b.keyCode;case \"keypress\":case \"mousedown\":case \"blur\":return!0;default:return!1}}function vb(a){a=a.detail;return\"object\"===typeof a&&\"data\"in a?a.data:null}var wb=!1;function xb(a,b){switch(a){case \"compositionend\":return vb(b);case \"keypress\":if(32!==b.which)return null;tb=!0;return rb;case \"textInput\":return a=b.data,a===rb&&tb?null:a;default:return null}}\nfunction yb(a,b){if(wb)return\"compositionend\"===a||!nb&&ub(a,b)?(a=eb(),db=cb=bb=null,wb=!1,a):null;switch(a){case \"paste\":return null;case \"keypress\":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1b}return!1}function C(a,b,c,d,e){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b}var D={};\n\"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style\".split(\" \").forEach(function(a){D[a]=new C(a,0,!1,a,null)});[[\"acceptCharset\",\"accept-charset\"],[\"className\",\"class\"],[\"htmlFor\",\"for\"],[\"httpEquiv\",\"http-equiv\"]].forEach(function(a){var b=a[0];D[b]=new C(b,1,!1,a[1],null)});[\"contentEditable\",\"draggable\",\"spellCheck\",\"value\"].forEach(function(a){D[a]=new C(a,2,!1,a.toLowerCase(),null)});\n[\"autoReverse\",\"externalResourcesRequired\",\"focusable\",\"preserveAlpha\"].forEach(function(a){D[a]=new C(a,2,!1,a,null)});\"allowFullScreen async autoFocus autoPlay controls default defer disabled formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope\".split(\" \").forEach(function(a){D[a]=new C(a,3,!1,a.toLowerCase(),null)});[\"checked\",\"multiple\",\"muted\",\"selected\"].forEach(function(a){D[a]=new C(a,3,!0,a,null)});\n[\"capture\",\"download\"].forEach(function(a){D[a]=new C(a,4,!1,a,null)});[\"cols\",\"rows\",\"size\",\"span\"].forEach(function(a){D[a]=new C(a,6,!1,a,null)});[\"rowSpan\",\"start\"].forEach(function(a){D[a]=new C(a,5,!1,a.toLowerCase(),null)});var rc=/[\\-:]([a-z])/g;function sc(a){return a[1].toUpperCase()}\n\"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height\".split(\" \").forEach(function(a){var b=a.replace(rc,\nsc);D[b]=new C(b,1,!1,a,null)});\"xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type\".split(\" \").forEach(function(a){var b=a.replace(rc,sc);D[b]=new C(b,1,!1,a,\"http://www.w3.org/1999/xlink\")});[\"xml:base\",\"xml:lang\",\"xml:space\"].forEach(function(a){var b=a.replace(rc,sc);D[b]=new C(b,1,!1,a,\"http://www.w3.org/XML/1998/namespace\")});[\"tabIndex\",\"crossOrigin\"].forEach(function(a){D[a]=new C(a,1,!1,a.toLowerCase(),null)});\nfunction tc(a,b,c,d){var e=D.hasOwnProperty(b)?D[b]:null;var f=null!==e?0===e.type:d?!1:!(2zd.length&&zd.push(a)}}}var Fd={},Gd=0,Hd=\"_reactListenersID\"+(\"\"+Math.random()).slice(2);\nfunction Id(a){Object.prototype.hasOwnProperty.call(a,Hd)||(a[Hd]=Gd++,Fd[a[Hd]]={});return Fd[a[Hd]]}function Jd(a){a=a||(\"undefined\"!==typeof document?document:void 0);if(\"undefined\"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}}function Kd(a){for(;a&&a.firstChild;)a=a.firstChild;return a}\nfunction Ld(a,b){var c=Kd(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;if(a<=b&&d>=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=Kd(c)}}function Md(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?Md(a,b.parentNode):\"contains\"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}\nfunction Nd(){for(var a=window,b=Jd();b instanceof a.HTMLIFrameElement;){try{a=b.contentDocument.defaultView}catch(c){break}b=Jd(a.document)}return b}function Od(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&(\"input\"===b&&(\"text\"===a.type||\"search\"===a.type||\"tel\"===a.type||\"url\"===a.type||\"password\"===a.type)||\"textarea\"===b||\"true\"===a.contentEditable)}\nfunction Pd(){var a=Nd();if(Od(a)){if(\"selectionStart\"in a)var b={start:a.selectionStart,end:a.selectionEnd};else a:{b=(b=a.ownerDocument)&&b.defaultView||window;var c=b.getSelection&&b.getSelection();if(c&&0!==c.rangeCount){b=c.anchorNode;var d=c.anchorOffset,e=c.focusNode;c=c.focusOffset;try{b.nodeType,e.nodeType}catch(A){b=null;break a}var f=0,g=-1,h=-1,l=0,k=0,m=a,p=null;b:for(;;){for(var t;;){m!==b||0!==d&&3!==m.nodeType||(g=f+d);m!==e||0!==c&&3!==m.nodeType||(h=f+c);3===m.nodeType&&(f+=m.nodeValue.length);\nif(null===(t=m.firstChild))break;p=m;m=t}for(;;){if(m===a)break b;p===b&&++l===d&&(g=f);p===e&&++k===c&&(h=f);if(null!==(t=m.nextSibling))break;m=p;p=m.parentNode}m=t}b=-1===g||-1===h?null:{start:g,end:h}}else b=null}b=b||{start:0,end:0}}else b=null;return{focusedElem:a,selectionRange:b}}\nfunction Qd(a){var b=Nd(),c=a.focusedElem,d=a.selectionRange;if(b!==c&&c&&c.ownerDocument&&Md(c.ownerDocument.documentElement,c)){if(null!==d&&Od(c))if(b=d.start,a=d.end,void 0===a&&(a=b),\"selectionStart\"in c)c.selectionStart=b,c.selectionEnd=Math.min(a,c.value.length);else if(a=(b=c.ownerDocument||document)&&b.defaultView||window,a.getSelection){a=a.getSelection();var e=c.textContent.length,f=Math.min(d.start,e);d=void 0===d.end?f:Math.min(d.end,e);!a.extend&&f>d&&(e=d,d=f,f=e);e=Ld(c,f);var g=Ld(c,\nd);e&&g&&(1!==a.rangeCount||a.anchorNode!==e.node||a.anchorOffset!==e.offset||a.focusNode!==g.node||a.focusOffset!==g.offset)&&(b=b.createRange(),b.setStart(e.node,e.offset),a.removeAllRanges(),f>d?(a.addRange(b),a.extend(g.node,g.offset)):(b.setEnd(g.node,g.offset),a.addRange(b)))}b=[];for(a=c;a=a.parentNode;)1===a.nodeType&&b.push({element:a,left:a.scrollLeft,top:a.scrollTop});\"function\"===typeof c.focus&&c.focus();for(c=0;c=document.documentMode,Sd={select:{phasedRegistrationNames:{bubbled:\"onSelect\",captured:\"onSelectCapture\"},dependencies:\"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange\".split(\" \")}},Td=null,Ud=null,Vd=null,Wd=!1;\nfunction Xd(a,b){var c=b.window===b?b.document:9===b.nodeType?b:b.ownerDocument;if(Wd||null==Td||Td!==Jd(c))return null;c=Td;\"selectionStart\"in c&&Od(c)?c={start:c.selectionStart,end:c.selectionEnd}:(c=(c.ownerDocument&&c.ownerDocument.defaultView||window).getSelection(),c={anchorNode:c.anchorNode,anchorOffset:c.anchorOffset,focusNode:c.focusNode,focusOffset:c.focusOffset});return Vd&&dd(Vd,c)?null:(Vd=c,a=y.getPooled(Sd.select,Ud,a,b),a.type=\"select\",a.target=Td,Qa(a),a)}\nvar Yd={eventTypes:Sd,extractEvents:function(a,b,c,d){var e=d.window===d?d.document:9===d.nodeType?d:d.ownerDocument,f;if(!(f=!e)){a:{e=Id(e);f=sa.onSelect;for(var g=0;g=b.length?void 0:x(\"93\"),b=b[0]),c=b),null==c&&(c=\"\"));a._wrapperState={initialValue:uc(c)}}\nfunction de(a,b){var c=uc(b.value),d=uc(b.defaultValue);null!=c&&(c=\"\"+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!==c&&(a.defaultValue=c));null!=d&&(a.defaultValue=\"\"+d)}function ee(a){var b=a.textContent;b===a._wrapperState.initialValue&&(a.value=b)}var fe={html:\"http://www.w3.org/1999/xhtml\",mathml:\"http://www.w3.org/1998/Math/MathML\",svg:\"http://www.w3.org/2000/svg\"};\nfunction ge(a){switch(a){case \"svg\":return\"http://www.w3.org/2000/svg\";case \"math\":return\"http://www.w3.org/1998/Math/MathML\";default:return\"http://www.w3.org/1999/xhtml\"}}function he(a,b){return null==a||\"http://www.w3.org/1999/xhtml\"===a?ge(b):\"http://www.w3.org/2000/svg\"===a&&\"foreignObject\"===b?\"http://www.w3.org/1999/xhtml\":a}\nvar ie=void 0,je=function(a){return\"undefined\"!==typeof MSApp&&MSApp.execUnsafeLocalFunction?function(b,c,d,e){MSApp.execUnsafeLocalFunction(function(){return a(b,c,d,e)})}:a}(function(a,b){if(a.namespaceURI!==fe.svg||\"innerHTML\"in a)a.innerHTML=b;else{ie=ie||document.createElement(\"div\");ie.innerHTML=\"\"+b+\"\";for(b=ie.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;b.firstChild;)a.appendChild(b.firstChild)}});\nfunction ke(a,b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b}\nvar le={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,\nfloodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},me=[\"Webkit\",\"ms\",\"Moz\",\"O\"];Object.keys(le).forEach(function(a){me.forEach(function(b){b=b+a.charAt(0).toUpperCase()+a.substring(1);le[b]=le[a]})});function ne(a,b,c){return null==b||\"boolean\"===typeof b||\"\"===b?\"\":c||\"number\"!==typeof b||0===b||le.hasOwnProperty(a)&&le[a]?(\"\"+b).trim():b+\"px\"}\nfunction oe(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf(\"--\"),e=ne(c,b[c],d);\"float\"===c&&(c=\"cssFloat\");d?a.setProperty(c,e):a[c]=e}}var pe=n({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});\nfunction qe(a,b){b&&(pe[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML?x(\"137\",a,\"\"):void 0),null!=b.dangerouslySetInnerHTML&&(null!=b.children?x(\"60\"):void 0,\"object\"===typeof b.dangerouslySetInnerHTML&&\"__html\"in b.dangerouslySetInnerHTML?void 0:x(\"61\")),null!=b.style&&\"object\"!==typeof b.style?x(\"62\",\"\"):void 0)}\nfunction re(a,b){if(-1===a.indexOf(\"-\"))return\"string\"===typeof b.is;switch(a){case \"annotation-xml\":case \"color-profile\":case \"font-face\":case \"font-face-src\":case \"font-face-uri\":case \"font-face-format\":case \"font-face-name\":case \"missing-glyph\":return!1;default:return!0}}\nfunction se(a,b){a=9===a.nodeType||11===a.nodeType?a:a.ownerDocument;var c=Id(a);b=sa[b];for(var d=0;dGe||(a.current=Fe[Ge],Fe[Ge]=null,Ge--)}function G(a,b){Ge++;Fe[Ge]=a.current;a.current=b}var He={},H={current:He},I={current:!1},Ie=He;\nfunction Je(a,b){var c=a.type.contextTypes;if(!c)return He;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function J(a){a=a.childContextTypes;return null!==a&&void 0!==a}function Ke(a){F(I,a);F(H,a)}function Le(a){F(I,a);F(H,a)}\nfunction Me(a,b,c){H.current!==He?x(\"168\"):void 0;G(H,b,a);G(I,c,a)}function Ne(a,b,c){var d=a.stateNode;a=b.childContextTypes;if(\"function\"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)e in a?void 0:x(\"108\",ic(b)||\"Unknown\",e);return n({},c,d)}function Oe(a){var b=a.stateNode;b=b&&b.__reactInternalMemoizedMergedChildContext||He;Ie=H.current;G(H,b,a);G(I,I.current,a);return!0}\nfunction Pe(a,b,c){var d=a.stateNode;d?void 0:x(\"169\");c?(b=Ne(a,b,Ie),d.__reactInternalMemoizedMergedChildContext=b,F(I,a),F(H,a),G(H,b,a)):F(I,a);G(I,c,a)}var Qe=null,Re=null;function Se(a){return function(b){try{return a(b)}catch(c){}}}\nfunction Te(a){if(\"undefined\"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)return!0;try{var c=b.inject(a);Qe=Se(function(a){return b.onCommitFiberRoot(c,a)});Re=Se(function(a){return b.onCommitFiberUnmount(c,a)})}catch(d){}return!0}\nfunction Ue(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.contextDependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.effectTag=0;this.lastEffect=this.firstEffect=this.nextEffect=null;this.childExpirationTime=this.expirationTime=0;this.alternate=null}function K(a,b,c,d){return new Ue(a,b,c,d)}\nfunction Ve(a){a=a.prototype;return!(!a||!a.isReactComponent)}function We(a){if(\"function\"===typeof a)return Ve(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===cc)return 11;if(a===ec)return 14}return 2}\nfunction Xe(a,b){var c=a.alternate;null===c?(c=K(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.effectTag=0,c.nextEffect=null,c.firstEffect=null,c.lastEffect=null);c.childExpirationTime=a.childExpirationTime;c.expirationTime=a.expirationTime;c.child=a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;c.contextDependencies=a.contextDependencies;c.sibling=a.sibling;\nc.index=a.index;c.ref=a.ref;return c}\nfunction Ye(a,b,c,d,e,f){var g=2;d=a;if(\"function\"===typeof a)Ve(a)&&(g=1);else if(\"string\"===typeof a)g=5;else a:switch(a){case Xb:return Ze(c.children,e,f,b);case bc:return $e(c,e|3,f,b);case Yb:return $e(c,e|2,f,b);case Zb:return a=K(12,c,b,e|4),a.elementType=Zb,a.type=Zb,a.expirationTime=f,a;case dc:return a=K(13,c,b,e),a.elementType=dc,a.type=dc,a.expirationTime=f,a;default:if(\"object\"===typeof a&&null!==a)switch(a.$$typeof){case $b:g=10;break a;case ac:g=9;break a;case cc:g=11;break a;case ec:g=\n14;break a;case fc:g=16;d=null;break a}x(\"130\",null==a?a:typeof a,\"\")}b=K(g,c,b,e);b.elementType=a;b.type=d;b.expirationTime=f;return b}function Ze(a,b,c,d){a=K(7,a,d,b);a.expirationTime=c;return a}function $e(a,b,c,d){a=K(8,a,d,b);b=0===(b&1)?Yb:bc;a.elementType=b;a.type=b;a.expirationTime=c;return a}function af(a,b,c){a=K(6,a,null,b);a.expirationTime=c;return a}\nfunction bf(a,b,c){b=K(4,null!==a.children?a.children:[],a.key,b);b.expirationTime=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function cf(a,b){a.didError=!1;var c=a.earliestPendingTime;0===c?a.earliestPendingTime=a.latestPendingTime=b:cb&&(a.latestPendingTime=b);df(b,a)}\nfunction ef(a,b){a.didError=!1;if(0===b)a.earliestPendingTime=0,a.latestPendingTime=0,a.earliestSuspendedTime=0,a.latestSuspendedTime=0,a.latestPingedTime=0;else{bb?a.earliestPendingTime=a.latestPendingTime=0:a.earliestPendingTime>b&&(a.earliestPendingTime=a.latestPendingTime));c=a.earliestSuspendedTime;0===c?cf(a,b):bc&&cf(a,b)}df(0,a)}function ff(a,b){a.didError=!1;a.latestPingedTime>=b&&(a.latestPingedTime=0);var c=a.earliestPendingTime,d=a.latestPendingTime;c===b?a.earliestPendingTime=d===b?a.latestPendingTime=0:d:d===b&&(a.latestPendingTime=c);c=a.earliestSuspendedTime;d=a.latestSuspendedTime;0===c?a.earliestSuspendedTime=a.latestSuspendedTime=b:cb&&(a.latestSuspendedTime=b);df(b,a)}\nfunction gf(a,b){var c=a.earliestPendingTime;a=a.earliestSuspendedTime;c>b&&(b=c);a>b&&(b=a);return b}function df(a,b){var c=b.earliestSuspendedTime,d=b.latestSuspendedTime,e=b.earliestPendingTime,f=b.latestPingedTime;e=0!==e?e:f;0===e&&(0===a||da&&(a=c);b.nextExpirationTimeToWorkOn=e;b.expirationTime=a}function L(a,b){if(a&&a.defaultProps){b=n({},b);a=a.defaultProps;for(var c in a)void 0===b[c]&&(b[c]=a[c])}return b}\nfunction hf(a){var b=a._result;switch(a._status){case 1:return b;case 2:throw b;case 0:throw b;default:a._status=0;b=a._ctor;b=b();b.then(function(b){0===a._status&&(b=b.default,a._status=1,a._result=b)},function(b){0===a._status&&(a._status=2,a._result=b)});switch(a._status){case 1:return a._result;case 2:throw a._result;}a._result=b;throw b;}}var jf=(new aa.Component).refs;\nfunction kf(a,b,c,d){b=a.memoizedState;c=c(d,b);c=null===c||void 0===c?b:n({},b,c);a.memoizedState=c;d=a.updateQueue;null!==d&&0===a.expirationTime&&(d.baseState=c)}\nvar tf={isMounted:function(a){return(a=a._reactInternalFiber)?2===ed(a):!1},enqueueSetState:function(a,b,c){a=a._reactInternalFiber;var d=lf();d=mf(d,a);var e=nf(d);e.payload=b;void 0!==c&&null!==c&&(e.callback=c);of();pf(a,e);qf(a,d)},enqueueReplaceState:function(a,b,c){a=a._reactInternalFiber;var d=lf();d=mf(d,a);var e=nf(d);e.tag=rf;e.payload=b;void 0!==c&&null!==c&&(e.callback=c);of();pf(a,e);qf(a,d)},enqueueForceUpdate:function(a,b){a=a._reactInternalFiber;var c=lf();c=mf(c,a);var d=nf(c);d.tag=\nsf;void 0!==b&&null!==b&&(d.callback=b);of();pf(a,d);qf(a,c)}};function uf(a,b,c,d,e,f,g){a=a.stateNode;return\"function\"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(d,f,g):b.prototype&&b.prototype.isPureReactComponent?!dd(c,d)||!dd(e,f):!0}\nfunction vf(a,b,c){var d=!1,e=He;var f=b.contextType;\"object\"===typeof f&&null!==f?f=M(f):(e=J(b)?Ie:H.current,d=b.contextTypes,f=(d=null!==d&&void 0!==d)?Je(a,e):He);b=new b(c,f);a.memoizedState=null!==b.state&&void 0!==b.state?b.state:null;b.updater=tf;a.stateNode=b;b._reactInternalFiber=a;d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=e,a.__reactInternalMemoizedMaskedChildContext=f);return b}\nfunction wf(a,b,c,d){a=b.state;\"function\"===typeof b.componentWillReceiveProps&&b.componentWillReceiveProps(c,d);\"function\"===typeof b.UNSAFE_componentWillReceiveProps&&b.UNSAFE_componentWillReceiveProps(c,d);b.state!==a&&tf.enqueueReplaceState(b,b.state,null)}\nfunction xf(a,b,c,d){var e=a.stateNode;e.props=c;e.state=a.memoizedState;e.refs=jf;var f=b.contextType;\"object\"===typeof f&&null!==f?e.context=M(f):(f=J(b)?Ie:H.current,e.context=Je(a,f));f=a.updateQueue;null!==f&&(yf(a,f,c,e,d),e.state=a.memoizedState);f=b.getDerivedStateFromProps;\"function\"===typeof f&&(kf(a,b,f,c),e.state=a.memoizedState);\"function\"===typeof b.getDerivedStateFromProps||\"function\"===typeof e.getSnapshotBeforeUpdate||\"function\"!==typeof e.UNSAFE_componentWillMount&&\"function\"!==\ntypeof e.componentWillMount||(b=e.state,\"function\"===typeof e.componentWillMount&&e.componentWillMount(),\"function\"===typeof e.UNSAFE_componentWillMount&&e.UNSAFE_componentWillMount(),b!==e.state&&tf.enqueueReplaceState(e,e.state,null),f=a.updateQueue,null!==f&&(yf(a,f,c,e,d),e.state=a.memoizedState));\"function\"===typeof e.componentDidMount&&(a.effectTag|=4)}var zf=Array.isArray;\nfunction Af(a,b,c){a=c.ref;if(null!==a&&\"function\"!==typeof a&&\"object\"!==typeof a){if(c._owner){c=c._owner;var d=void 0;c&&(1!==c.tag?x(\"309\"):void 0,d=c.stateNode);d?void 0:x(\"147\",a);var e=\"\"+a;if(null!==b&&null!==b.ref&&\"function\"===typeof b.ref&&b.ref._stringRef===e)return b.ref;b=function(a){var b=d.refs;b===jf&&(b=d.refs={});null===a?delete b[e]:b[e]=a};b._stringRef=e;return b}\"string\"!==typeof a?x(\"284\"):void 0;c._owner?void 0:x(\"290\",a)}return a}\nfunction Bf(a,b){\"textarea\"!==a.type&&x(\"31\",\"[object Object]\"===Object.prototype.toString.call(b)?\"object with keys {\"+Object.keys(b).join(\", \")+\"}\":b,\"\")}\nfunction Cf(a){function b(b,c){if(a){var d=b.lastEffect;null!==d?(d.nextEffect=c,b.lastEffect=c):b.firstEffect=b.lastEffect=c;c.nextEffect=null;c.effectTag=8}}function c(c,d){if(!a)return null;for(;null!==d;)b(c,d),d=d.sibling;return null}function d(a,b){for(a=new Map;null!==b;)null!==b.key?a.set(b.key,b):a.set(b.index,b),b=b.sibling;return a}function e(a,b,c){a=Xe(a,b,c);a.index=0;a.sibling=null;return a}function f(b,c,d){b.index=d;if(!a)return c;d=b.alternate;if(null!==d)return d=d.index,du?(B=q,q=null):B=q.sibling;var w=t(e,q,h[u],k);if(null===w){null===q&&(q=B);break}a&&\nq&&null===w.alternate&&b(e,q);g=f(w,g,u);null===m?l=w:m.sibling=w;m=w;q=B}if(u===h.length)return c(e,q),l;if(null===q){for(;uu?(B=q,q=null):B=q.sibling;var v=t(e,q,w.value,k);if(null===v){q||(q=B);break}a&&q&&null===v.alternate&&b(e,q);g=f(v,g,u);null===m?l=v:m.sibling=v;m=v;q=B}if(w.done)return c(e,q),l;if(null===q){for(;!w.done;u++,w=h.next())w=p(e,w.value,k),null!==w&&(g=f(w,g,u),null===m?l=w:m.sibling=w,m=w);return l}for(q=d(e,q);!w.done;u++,w=h.next())w=A(q,e,u,w.value,k),null!==w&&(a&&null!==w.alternate&&q.delete(null===w.key?u:\nw.key),g=f(w,g,u),null===m?l=w:m.sibling=w,m=w);a&&q.forEach(function(a){return b(e,a)});return l}return function(a,d,f,h){var k=\"object\"===typeof f&&null!==f&&f.type===Xb&&null===f.key;k&&(f=f.props.children);var l=\"object\"===typeof f&&null!==f;if(l)switch(f.$$typeof){case Vb:a:{l=f.key;for(k=d;null!==k;){if(k.key===l)if(7===k.tag?f.type===Xb:k.elementType===f.type){c(a,k.sibling);d=e(k,f.type===Xb?f.props.children:f.props,h);d.ref=Af(a,k,f);d.return=a;a=d;break a}else{c(a,k);break}else b(a,k);k=\nk.sibling}f.type===Xb?(d=Ze(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=Ye(f.type,f.key,f.props,null,a.mode,h),h.ref=Af(a,d,f),h.return=a,a=h)}return g(a);case Wb:a:{for(k=f.key;null!==d;){if(d.key===k)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[],h);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=bf(f,a.mode,h);d.return=a;a=d}return g(a)}if(\"string\"===typeof f||\"number\"===typeof f)return f=\n\"\"+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f,h),d.return=a,a=d):(c(a,d),d=af(f,a.mode,h),d.return=a,a=d),g(a);if(zf(f))return v(a,d,f,h);if(hc(f))return R(a,d,f,h);l&&Bf(a,f);if(\"undefined\"===typeof f&&!k)switch(a.tag){case 1:case 0:h=a.type,x(\"152\",h.displayName||h.name||\"Component\")}return c(a,d)}}var Df=Cf(!0),Ef=Cf(!1),Ff={},N={current:Ff},Gf={current:Ff},Hf={current:Ff};function If(a){a===Ff?x(\"174\"):void 0;return a}\nfunction Jf(a,b){G(Hf,b,a);G(Gf,a,a);G(N,Ff,a);var c=b.nodeType;switch(c){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:he(null,\"\");break;default:c=8===c?b.parentNode:b,b=c.namespaceURI||null,c=c.tagName,b=he(b,c)}F(N,a);G(N,b,a)}function Kf(a){F(N,a);F(Gf,a);F(Hf,a)}function Lf(a){If(Hf.current);var b=If(N.current);var c=he(b,a.type);b!==c&&(G(Gf,a,a),G(N,c,a))}function Mf(a){Gf.current===a&&(F(N,a),F(Gf,a))}\nvar Nf=0,Of=2,Pf=4,Qf=8,Rf=16,Sf=32,Tf=64,Uf=128,Vf=Tb.ReactCurrentDispatcher,Wf=0,Xf=null,O=null,P=null,Yf=null,Q=null,Zf=null,$f=0,ag=null,bg=0,cg=!1,dg=null,eg=0;function fg(){x(\"307\")}function gg(a,b){if(null===b)return!1;for(var c=0;c$f&&($f=m)):f=l.eagerReducer===a?l.eagerState:a(f,l.action);g=l;l=l.next}while(null!==l&&l!==d);k||(h=g,e=f);bd(f,b.memoizedState)||(qg=!0);b.memoizedState=f;b.baseUpdate=h;b.baseState=e;c.eagerReducer=a;c.eagerState=f}return[b.memoizedState,c.dispatch]}\nfunction rg(a,b,c,d){a={tag:a,create:b,destroy:c,deps:d,next:null};null===ag?(ag={lastEffect:null},ag.lastEffect=a.next=a):(b=ag.lastEffect,null===b?ag.lastEffect=a.next=a:(c=b.next,b.next=a,a.next=c,ag.lastEffect=a));return a}function sg(a,b,c,d){var e=mg();bg|=a;e.memoizedState=rg(b,c,void 0,void 0===d?null:d)}\nfunction tg(a,b,c,d){var e=ng();d=void 0===d?null:d;var f=void 0;if(null!==O){var g=O.memoizedState;f=g.destroy;if(null!==d&&gg(d,g.deps)){rg(Nf,c,f,d);return}}bg|=a;e.memoizedState=rg(b,c,f,d)}function ug(a,b){if(\"function\"===typeof b)return a=a(),b(a),function(){b(null)};if(null!==b&&void 0!==b)return a=a(),b.current=a,function(){b.current=null}}function vg(){}\nfunction wg(a,b,c){25>eg?void 0:x(\"301\");var d=a.alternate;if(a===Xf||null!==d&&d===Xf)if(cg=!0,a={expirationTime:Wf,action:c,eagerReducer:null,eagerState:null,next:null},null===dg&&(dg=new Map),c=dg.get(b),void 0===c)dg.set(b,a);else{for(b=c;null!==b.next;)b=b.next;b.next=a}else{of();var e=lf();e=mf(e,a);var f={expirationTime:e,action:c,eagerReducer:null,eagerState:null,next:null},g=b.last;if(null===g)f.next=f;else{var h=g.next;null!==h&&(f.next=h);g.next=f}b.last=f;if(0===a.expirationTime&&(null===\nd||0===d.expirationTime)&&(d=b.eagerReducer,null!==d))try{var l=b.eagerState,k=d(l,c);f.eagerReducer=d;f.eagerState=k;if(bd(k,l))return}catch(m){}finally{}qf(a,e)}}\nvar kg={readContext:M,useCallback:fg,useContext:fg,useEffect:fg,useImperativeHandle:fg,useLayoutEffect:fg,useMemo:fg,useReducer:fg,useRef:fg,useState:fg,useDebugValue:fg},ig={readContext:M,useCallback:function(a,b){mg().memoizedState=[a,void 0===b?null:b];return a},useContext:M,useEffect:function(a,b){return sg(516,Uf|Tf,a,b)},useImperativeHandle:function(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return sg(4,Pf|Sf,ug.bind(null,b,a),c)},useLayoutEffect:function(a,b){return sg(4,Pf|Sf,a,b)},\nuseMemo:function(a,b){var c=mg();b=void 0===b?null:b;a=a();c.memoizedState=[a,b];return a},useReducer:function(a,b,c){var d=mg();b=void 0!==c?c(b):b;d.memoizedState=d.baseState=b;a=d.queue={last:null,dispatch:null,eagerReducer:a,eagerState:b};a=a.dispatch=wg.bind(null,Xf,a);return[d.memoizedState,a]},useRef:function(a){var b=mg();a={current:a};return b.memoizedState=a},useState:function(a){var b=mg();\"function\"===typeof a&&(a=a());b.memoizedState=b.baseState=a;a=b.queue={last:null,dispatch:null,eagerReducer:og,\neagerState:a};a=a.dispatch=wg.bind(null,Xf,a);return[b.memoizedState,a]},useDebugValue:vg},jg={readContext:M,useCallback:function(a,b){var c=ng();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&gg(b,d[1]))return d[0];c.memoizedState=[a,b];return a},useContext:M,useEffect:function(a,b){return tg(516,Uf|Tf,a,b)},useImperativeHandle:function(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return tg(4,Pf|Sf,ug.bind(null,b,a),c)},useLayoutEffect:function(a,b){return tg(4,Pf|Sf,a,b)},\nuseMemo:function(a,b){var c=ng();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&gg(b,d[1]))return d[0];a=a();c.memoizedState=[a,b];return a},useReducer:pg,useRef:function(){return ng().memoizedState},useState:function(a){return pg(og,a)},useDebugValue:vg},xg=null,yg=null,zg=!1;\nfunction Ag(a,b){var c=K(5,null,null,0);c.elementType=\"DELETED\";c.type=\"DELETED\";c.stateNode=b;c.return=a;c.effectTag=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect=a.lastEffect=c}function Bg(a,b){switch(a.tag){case 5:var c=a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,!0):!1;case 6:return b=\"\"===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,!0):!1;case 13:return!1;default:return!1}}\nfunction Cg(a){if(zg){var b=yg;if(b){var c=b;if(!Bg(a,b)){b=De(c);if(!b||!Bg(a,b)){a.effectTag|=2;zg=!1;xg=a;return}Ag(xg,c)}xg=a;yg=Ee(b)}else a.effectTag|=2,zg=!1,xg=a}}function Dg(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag&&18!==a.tag;)a=a.return;xg=a}function Eg(a){if(a!==xg)return!1;if(!zg)return Dg(a),zg=!0,!1;var b=a.type;if(5!==a.tag||\"head\"!==b&&\"body\"!==b&&!xe(b,a.memoizedProps))for(b=yg;b;)Ag(a,b),b=De(b);Dg(a);yg=xg?De(a.stateNode):null;return!0}function Fg(){yg=xg=null;zg=!1}\nvar Gg=Tb.ReactCurrentOwner,qg=!1;function S(a,b,c,d){b.child=null===a?Ef(b,null,c,d):Df(b,a.child,c,d)}function Hg(a,b,c,d,e){c=c.render;var f=b.ref;Ig(b,e);d=hg(a,b,c,d,f,e);if(null!==a&&!qg)return b.updateQueue=a.updateQueue,b.effectTag&=-517,a.expirationTime<=e&&(a.expirationTime=0),Jg(a,b,e);b.effectTag|=1;S(a,b,d,e);return b.child}\nfunction Kg(a,b,c,d,e,f){if(null===a){var g=c.type;if(\"function\"===typeof g&&!Ve(g)&&void 0===g.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=g,Lg(a,b,g,d,e,f);a=Ye(c.type,null,d,null,b.mode,f);a.ref=b.ref;a.return=b;return b.child=a}g=a.child;if(e=c)return Sg(a,b,c);b=Jg(a,b,c);return null!==b?b.sibling:null}}return Jg(a,b,c)}}else qg=!1;b.expirationTime=0;switch(b.tag){case 2:d=\nb.elementType;null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);a=b.pendingProps;var e=Je(b,H.current);Ig(b,c);e=hg(null,b,d,a,e,c);b.effectTag|=1;if(\"object\"===typeof e&&null!==e&&\"function\"===typeof e.render&&void 0===e.$$typeof){b.tag=1;lg();if(J(d)){var f=!0;Oe(b)}else f=!1;b.memoizedState=null!==e.state&&void 0!==e.state?e.state:null;var g=d.getDerivedStateFromProps;\"function\"===typeof g&&kf(b,d,g,a);e.updater=tf;b.stateNode=e;e._reactInternalFiber=b;xf(b,d,a,c);b=Qg(null,b,d,!0,f,\nc)}else b.tag=0,S(null,b,e,c),b=b.child;return b;case 16:e=b.elementType;null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);f=b.pendingProps;a=hf(e);b.type=a;e=b.tag=We(a);f=L(a,f);g=void 0;switch(e){case 0:g=Mg(null,b,a,f,c);break;case 1:g=Og(null,b,a,f,c);break;case 11:g=Hg(null,b,a,f,c);break;case 14:g=Kg(null,b,a,L(a.type,f),d,c);break;default:x(\"306\",a,\"\")}return g;case 0:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:L(d,e),Mg(a,b,d,e,c);case 1:return d=b.type,e=b.pendingProps,\ne=b.elementType===d?e:L(d,e),Og(a,b,d,e,c);case 3:Rg(b);d=b.updateQueue;null===d?x(\"282\"):void 0;e=b.memoizedState;e=null!==e?e.element:null;yf(b,d,b.pendingProps,null,c);d=b.memoizedState.element;if(d===e)Fg(),b=Jg(a,b,c);else{e=b.stateNode;if(e=(null===a||null===a.child)&&e.hydrate)yg=Ee(b.stateNode.containerInfo),xg=b,e=zg=!0;e?(b.effectTag|=2,b.child=Ef(b,null,d,c)):(S(a,b,d,c),Fg());b=b.child}return b;case 5:return Lf(b),null===a&&Cg(b),d=b.type,e=b.pendingProps,f=null!==a?a.memoizedProps:null,\ng=e.children,xe(d,e)?g=null:null!==f&&xe(d,f)&&(b.effectTag|=16),Ng(a,b),1!==c&&b.mode&1&&e.hidden?(b.expirationTime=b.childExpirationTime=1,b=null):(S(a,b,g,c),b=b.child),b;case 6:return null===a&&Cg(b),null;case 13:return Sg(a,b,c);case 4:return Jf(b,b.stateNode.containerInfo),d=b.pendingProps,null===a?b.child=Df(b,null,d,c):S(a,b,d,c),b.child;case 11:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:L(d,e),Hg(a,b,d,e,c);case 7:return S(a,b,b.pendingProps,c),b.child;case 8:return S(a,b,b.pendingProps.children,\nc),b.child;case 12:return S(a,b,b.pendingProps.children,c),b.child;case 10:a:{d=b.type._context;e=b.pendingProps;g=b.memoizedProps;f=e.value;Ug(b,f);if(null!==g){var h=g.value;f=bd(h,f)?0:(\"function\"===typeof d._calculateChangedBits?d._calculateChangedBits(h,f):1073741823)|0;if(0===f){if(g.children===e.children&&!I.current){b=Jg(a,b,c);break a}}else for(h=b.child,null!==h&&(h.return=b);null!==h;){var l=h.contextDependencies;if(null!==l){g=h.child;for(var k=l.first;null!==k;){if(k.context===d&&0!==\n(k.observedBits&f)){1===h.tag&&(k=nf(c),k.tag=sf,pf(h,k));h.expirationTime=b&&(qg=!0);a.contextDependencies=null}\nfunction M(a,b){if(Yg!==a&&!1!==b&&0!==b){if(\"number\"!==typeof b||1073741823===b)Yg=a,b=1073741823;b={context:a,observedBits:b,next:null};null===Xg?(null===Wg?x(\"308\"):void 0,Xg=b,Wg.contextDependencies={first:b,expirationTime:0}):Xg=Xg.next=b}return a._currentValue}var $g=0,rf=1,sf=2,ah=3,Pg=!1;function bh(a){return{baseState:a,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}\nfunction ch(a){return{baseState:a.baseState,firstUpdate:a.firstUpdate,lastUpdate:a.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function nf(a){return{expirationTime:a,tag:$g,payload:null,callback:null,next:null,nextEffect:null}}function dh(a,b){null===a.lastUpdate?a.firstUpdate=a.lastUpdate=b:(a.lastUpdate.next=b,a.lastUpdate=b)}\nfunction pf(a,b){var c=a.alternate;if(null===c){var d=a.updateQueue;var e=null;null===d&&(d=a.updateQueue=bh(a.memoizedState))}else d=a.updateQueue,e=c.updateQueue,null===d?null===e?(d=a.updateQueue=bh(a.memoizedState),e=c.updateQueue=bh(c.memoizedState)):d=a.updateQueue=ch(e):null===e&&(e=c.updateQueue=ch(d));null===e||d===e?dh(d,b):null===d.lastUpdate||null===e.lastUpdate?(dh(d,b),dh(e,b)):(dh(d,b),e.lastUpdate=b)}\nfunction eh(a,b){var c=a.updateQueue;c=null===c?a.updateQueue=bh(a.memoizedState):fh(a,c);null===c.lastCapturedUpdate?c.firstCapturedUpdate=c.lastCapturedUpdate=b:(c.lastCapturedUpdate.next=b,c.lastCapturedUpdate=b)}function fh(a,b){var c=a.alternate;null!==c&&b===c.updateQueue&&(b=a.updateQueue=ch(b));return b}\nfunction gh(a,b,c,d,e,f){switch(c.tag){case rf:return a=c.payload,\"function\"===typeof a?a.call(f,d,e):a;case ah:a.effectTag=a.effectTag&-2049|64;case $g:a=c.payload;e=\"function\"===typeof a?a.call(f,d,e):a;if(null===e||void 0===e)break;return n({},d,e);case sf:Pg=!0}return d}\nfunction yf(a,b,c,d,e){Pg=!1;b=fh(a,b);for(var f=b.baseState,g=null,h=0,l=b.firstUpdate,k=f;null!==l;){var m=l.expirationTime;md?e:d);Ih.current=null;d=void 0;1c?b:c;0===b&&(Fh=null);$h(a,b)}\nfunction ai(a){for(;;){var b=a.alternate,c=a.return,d=a.sibling;if(0===(a.effectTag&1024)){T=a;a:{var e=b;b=a;var f=U;var g=b.pendingProps;switch(b.tag){case 2:break;case 16:break;case 15:case 0:break;case 1:J(b.type)&&Ke(b);break;case 3:Kf(b);Le(b);g=b.stateNode;g.pendingContext&&(g.context=g.pendingContext,g.pendingContext=null);if(null===e||null===e.child)Eg(b),b.effectTag&=-3;mh(b);break;case 5:Mf(b);var h=If(Hf.current);f=b.type;if(null!==e&&null!=b.stateNode)nh(e,b,f,g,h),e.ref!==b.ref&&(b.effectTag|=\n128);else if(g){var l=If(N.current);if(Eg(b)){g=b;e=g.stateNode;var k=g.type,m=g.memoizedProps,p=h;e[Fa]=g;e[Ga]=m;f=void 0;h=k;switch(h){case \"iframe\":case \"object\":E(\"load\",e);break;case \"video\":case \"audio\":for(k=0;k\\x3c/script>\",k=e.removeChild(e.firstChild)):\"string\"===typeof p.is?k=k.createElement(e,{is:p.is}):(k=k.createElement(e),\"select\"===e&&p.multiple&&(k.multiple=!0)):k=k.createElementNS(l,e);e=k;e[Fa]=m;e[Ga]=g;lh(e,b,!1,!1);p=e;k=f;m=g;var t=h,A=re(k,m);switch(k){case \"iframe\":case \"object\":E(\"load\",\np);h=m;break;case \"video\":case \"audio\":for(h=0;hg&&(g=e),h>g&&(g=h),f=f.sibling;b.childExpirationTime=g}if(null!==T)return T;null!==c&&0===(c.effectTag&1024)&&(null===c.firstEffect&&\n(c.firstEffect=a.firstEffect),null!==a.lastEffect&&(null!==c.lastEffect&&(c.lastEffect.nextEffect=a.firstEffect),c.lastEffect=a.lastEffect),1=v)t=0;else if(-1===t||v component higher in the tree to provide a loading indicator or placeholder to display.\"+jc(k))}Nh=!0;m=jh(m,k);h=l;do{switch(h.tag){case 3:h.effectTag|=2048;h.expirationTime=g;g=Ch(h,m,g);eh(h,g);break a;case 1:if(t=m,A=h.type,k=h.stateNode,0===(h.effectTag&64)&&(\"function\"===typeof A.getDerivedStateFromError||null!==k&&\"function\"===typeof k.componentDidCatch&&(null===Fh||!Fh.has(k)))){h.effectTag|=2048;\nh.expirationTime=g;g=Eh(h,t,g);eh(h,g);break a}}h=h.return}while(null!==h)}T=ai(f);continue}}}break}while(1);Kh=!1;Hh.current=c;Yg=Xg=Wg=null;lg();if(e)Lh=null,a.finishedWork=null;else if(null!==T)a.finishedWork=null;else{c=a.current.alternate;null===c?x(\"281\"):void 0;Lh=null;if(Nh){e=a.latestPendingTime;f=a.latestSuspendedTime;g=a.latestPingedTime;if(0!==e&&eb?0:b)):(a.pendingCommitExpirationTime=d,a.finishedWork=c)}}\nfunction sh(a,b){for(var c=a.return;null!==c;){switch(c.tag){case 1:var d=c.stateNode;if(\"function\"===typeof c.type.getDerivedStateFromError||\"function\"===typeof d.componentDidCatch&&(null===Fh||!Fh.has(d))){a=jh(b,a);a=Eh(c,a,1073741823);pf(c,a);qf(c,1073741823);return}break;case 3:a=jh(b,a);a=Ch(c,a,1073741823);pf(c,a);qf(c,1073741823);return}c=c.return}3===a.tag&&(c=jh(b,a),c=Ch(a,c,1073741823),pf(a,c),qf(a,1073741823))}\nfunction mf(a,b){var c=r.unstable_getCurrentPriorityLevel(),d=void 0;if(0===(b.mode&1))d=1073741823;else if(Kh&&!Oh)d=U;else{switch(c){case r.unstable_ImmediatePriority:d=1073741823;break;case r.unstable_UserBlockingPriority:d=1073741822-10*(((1073741822-a+15)/10|0)+1);break;case r.unstable_NormalPriority:d=1073741822-25*(((1073741822-a+500)/25|0)+1);break;case r.unstable_LowPriority:case r.unstable_IdlePriority:d=1;break;default:x(\"313\")}null!==Lh&&d===U&&--d}c===r.unstable_UserBlockingPriority&&\n(0===gi||d=d){a.didError=!1;b=a.latestPingedTime;if(0===b||b>c)a.latestPingedTime=c;df(c,a);c=a.expirationTime;0!==c&&Xh(a,c)}}function Ah(a,b){var c=a.stateNode;null!==c&&c.delete(b);b=lf();b=mf(b,a);a=hi(a,b);null!==a&&(cf(a,b),b=a.expirationTime,0!==b&&Xh(a,b))}\nfunction hi(a,b){a.expirationTimeU&&Sh(),cf(a,b),Kh&&!Oh&&Lh===a||Xh(a,a.expirationTime),ii>ji&&(ii=0,x(\"185\")))}function ki(a,b,c,d,e){return r.unstable_runWithPriority(r.unstable_ImmediatePriority,function(){return a(b,c,d,e)})}var li=null,Y=null,mi=0,ni=void 0,W=!1,oi=null,Z=0,gi=0,pi=!1,qi=null,X=!1,ri=!1,si=null,ti=r.unstable_now(),ui=1073741822-(ti/10|0),vi=ui,ji=50,ii=0,wi=null;function xi(){ui=1073741822-((r.unstable_now()-ti)/10|0)}\nfunction yi(a,b){if(0!==mi){if(ba.expirationTime&&(a.expirationTime=b);W||(X?ri&&(oi=a,Z=1073741823,Di(a,1073741823,!1)):1073741823===b?Yh(1073741823,!1):yi(a,b))}\nfunction Ci(){var a=0,b=null;if(null!==Y)for(var c=Y,d=li;null!==d;){var e=d.expirationTime;if(0===e){null===c||null===Y?x(\"244\"):void 0;if(d===d.nextScheduledRoot){li=Y=d.nextScheduledRoot=null;break}else if(d===li)li=e=d.nextScheduledRoot,Y.nextScheduledRoot=e,d.nextScheduledRoot=null;else if(d===Y){Y=c;Y.nextScheduledRoot=li;d.nextScheduledRoot=null;break}else c.nextScheduledRoot=d.nextScheduledRoot,d.nextScheduledRoot=null;d=c.nextScheduledRoot}else{e>a&&(a=e,b=d);if(d===Y)break;if(1073741823===\na)break;c=d;d=d.nextScheduledRoot}}oi=b;Z=a}var Ei=!1;function di(){return Ei?!0:r.unstable_shouldYield()?Ei=!0:!1}function zi(){try{if(!di()&&null!==li){xi();var a=li;do{var b=a.expirationTime;0!==b&&ui<=b&&(a.nextExpirationTimeToWorkOn=ui);a=a.nextScheduledRoot}while(a!==li)}Yh(0,!0)}finally{Ei=!1}}\nfunction Yh(a,b){Ci();if(b)for(xi(),vi=ui;null!==oi&&0!==Z&&a<=Z&&!(Ei&&ui>Z);)Di(oi,Z,ui>Z),Ci(),xi(),vi=ui;else for(;null!==oi&&0!==Z&&a<=Z;)Di(oi,Z,!1),Ci();b&&(mi=0,ni=null);0!==Z&&yi(oi,Z);ii=0;wi=null;if(null!==si)for(a=si,si=null,b=0;b=c&&(null===si?si=[d]:si.push(d),d._defer)){a.finishedWork=b;a.expirationTime=0;return}a.finishedWork=null;a===wi?ii++:(wi=a,ii=0);r.unstable_runWithPriority(r.unstable_ImmediatePriority,function(){Zh(a,b)})}function Dh(a){null===oi?x(\"246\"):void 0;oi.expirationTime=0;pi||(pi=!0,qi=a)}function Gi(a,b){var c=X;X=!0;try{return a(b)}finally{(X=c)||W||Yh(1073741823,!1)}}\nfunction Hi(a,b){if(X&&!ri){ri=!0;try{return a(b)}finally{ri=!1}}return a(b)}function Ii(a,b,c){X||W||0===gi||(Yh(gi,!1),gi=0);var d=X;X=!0;try{return r.unstable_runWithPriority(r.unstable_UserBlockingPriority,function(){return a(b,c)})}finally{(X=d)||W||Yh(1073741823,!1)}}\nfunction Ji(a,b,c,d,e){var f=b.current;a:if(c){c=c._reactInternalFiber;b:{2===ed(c)&&1===c.tag?void 0:x(\"170\");var g=c;do{switch(g.tag){case 3:g=g.stateNode.context;break b;case 1:if(J(g.type)){g=g.stateNode.__reactInternalMemoizedMergedChildContext;break b}}g=g.return}while(null!==g);x(\"171\");g=void 0}if(1===c.tag){var h=c.type;if(J(h)){c=Ne(c,h,g);break a}}c=g}else c=He;null===b.context?b.context=c:b.pendingContext=c;b=e;e=nf(d);e.payload={element:a};b=void 0===b?null:b;null!==b&&(e.callback=b);\nof();pf(f,e);qf(f,d);return d}function Ki(a,b,c,d){var e=b.current,f=lf();e=mf(f,e);return Ji(a,b,c,e,d)}function Li(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return a.child.stateNode;default:return a.child.stateNode}}function Mi(a,b,c){var d=3=Jh&&(b=Jh-1);this._expirationTime=Jh=b;this._root=a;this._callbacks=this._next=null;this._hasChildren=this._didComplete=!1;this._children=null;this._defer=!0}Ni.prototype.render=function(a){this._defer?void 0:x(\"250\");this._hasChildren=!0;this._children=a;var b=this._root._internalRoot,c=this._expirationTime,d=new Oi;Ji(a,b,null,c,d._onCommit);return d};\nNi.prototype.then=function(a){if(this._didComplete)a();else{var b=this._callbacks;null===b&&(b=this._callbacks=[]);b.push(a)}};\nNi.prototype.commit=function(){var a=this._root._internalRoot,b=a.firstBatch;this._defer&&null!==b?void 0:x(\"251\");if(this._hasChildren){var c=this._expirationTime;if(b!==this){this._hasChildren&&(c=this._expirationTime=b._expirationTime,this.render(this._children));for(var d=null,e=b;e!==this;)d=e,e=e._next;null===d?x(\"251\"):void 0;d._next=e._next;this._next=b;a.firstBatch=this}this._defer=!1;Bi(a,c);b=this._next;this._next=null;b=a.firstBatch=b;null!==b&&b._hasChildren&&b.render(b._children)}else this._next=\nnull,this._defer=!1};Ni.prototype._onComplete=function(){if(!this._didComplete){this._didComplete=!0;var a=this._callbacks;if(null!==a)for(var b=0;b=b;)c=d,d=d._next;a._next=d;null!==c&&(c._next=a)}return a};function Qi(a){return!(!a||1!==a.nodeType&&9!==a.nodeType&&11!==a.nodeType&&(8!==a.nodeType||\" react-mount-point-unstable \"!==a.nodeValue))}Gb=Gi;Hb=Ii;Ib=function(){W||0===gi||(Yh(gi,!1),gi=0)};\nfunction Ri(a,b){b||(b=a?9===a.nodeType?a.documentElement:a.firstChild:null,b=!(!b||1!==b.nodeType||!b.hasAttribute(\"data-reactroot\")));if(!b)for(var c;c=a.lastChild;)a.removeChild(c);return new Pi(a,!1,b)}\nfunction Si(a,b,c,d,e){var f=c._reactRootContainer;if(f){if(\"function\"===typeof e){var g=e;e=function(){var a=Li(f._internalRoot);g.call(a)}}null!=a?f.legacy_renderSubtreeIntoContainer(a,b,e):f.render(b,e)}else{f=c._reactRootContainer=Ri(c,d);if(\"function\"===typeof e){var h=e;e=function(){var a=Li(f._internalRoot);h.call(a)}}Hi(function(){null!=a?f.legacy_renderSubtreeIntoContainer(a,b,e):f.render(b,e)})}return Li(f._internalRoot)}\nfunction Ti(a,b){var c=2 1 && arguments[1] !== undefined ? arguments[1] : 0;\n var currTime = -1;\n\n var shouldUpdate = function shouldUpdate(now) {\n if (currTime < 0) {\n currTime = now;\n }\n\n if (now - currTime > timeout) {\n callback(now);\n currTime = -1;\n } else {\n raf(shouldUpdate);\n }\n };\n\n raf(shouldUpdate);\n}", + "function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nimport setRafTimeout from './setRafTimeout';\nexport default function createAnimateManager() {\n var currStyle = {};\n\n var handleChange = function handleChange() {\n return null;\n };\n\n var shouldStop = false;\n\n var setStyle = function setStyle(_style) {\n if (shouldStop) {\n return;\n }\n\n if (Array.isArray(_style)) {\n if (!_style.length) {\n return;\n }\n\n var styles = _style;\n\n var _styles = _toArray(styles),\n curr = _styles[0],\n restStyles = _styles.slice(1);\n\n if (typeof curr === 'number') {\n setRafTimeout(setStyle.bind(null, restStyles), curr);\n return;\n }\n\n setStyle(curr);\n setRafTimeout(setStyle.bind(null, restStyles));\n return;\n }\n\n if (_typeof(_style) === 'object') {\n currStyle = _style;\n handleChange(currStyle);\n }\n\n if (typeof _style === 'function') {\n _style();\n }\n };\n\n return {\n stop: function stop() {\n shouldStop = true;\n },\n start: function start(style) {\n shouldStop = false;\n setStyle(style);\n },\n subscribe: function subscribe(_handleChange) {\n handleChange = _handleChange;\n return function () {\n handleChange = function handleChange() {\n return null;\n };\n };\n }\n };\n}", + "import _isPlainObject from \"lodash/isPlainObject\";\nimport _isEqual from \"lodash/isEqual\";\nimport _isArray from \"lodash/isArray\";\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction shallowEqual(objA, objB) {\n if (objA === objB) {\n return true;\n }\n\n if (_typeof(objA) !== 'object' || objA === null || _typeof(objB) !== 'object' || objB === null) {\n return false;\n }\n\n var keysA = Object.keys(objA);\n var keysB = Object.keys(objB);\n\n if (keysA.length !== keysB.length) {\n return false;\n }\n\n var bHasOwnProperty = hasOwnProperty.bind(objB);\n\n for (var i = 0; i < keysA.length; i++) {\n var keyA = keysA[i];\n\n if (objA[keyA] === objB[keyA]) {\n continue;\n } // special diff with Array or Object\n\n\n if (_isArray(objA[keyA])) {\n if (!_isArray(objB[keyA]) || objA[keyA].length !== objB[keyA].length) {\n return false;\n } else if (!_isEqual(objA[keyA], objB[keyA])) {\n return false;\n }\n } else if (_isPlainObject(objA[keyA])) {\n if (!_isPlainObject(objB[keyA]) || !_isEqual(objA[keyA], objB[keyA])) {\n return false;\n }\n } else if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction shallowCompare(instance, nextProps, nextState) {\n return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);\n}\n\nfunction shouldComponentUpdate(nextProps, nextState) {\n return shallowCompare(this, nextProps, nextState);\n}\n/* eslint-disable no-param-reassign */\n\n\nfunction pureRenderDecorator(component) {\n component.prototype.shouldComponentUpdate = shouldComponentUpdate;\n}\n\nexport { shallowEqual };\nexport default pureRenderDecorator;", + "import _intersection from \"lodash/intersection\";\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n/* eslint no-console: 0 */\nvar PREFIX_LIST = ['Webkit', 'Moz', 'O', 'ms'];\nvar IN_LINE_PREFIX_LIST = ['-webkit-', '-moz-', '-o-', '-ms-'];\nvar IN_COMPATIBLE_PROPERTY = ['transform', 'transformOrigin', 'transition'];\nexport var getIntersectionKeys = function getIntersectionKeys(preObj, nextObj) {\n return _intersection(Object.keys(preObj), Object.keys(nextObj));\n};\nexport var identity = function identity(param) {\n return param;\n};\n/*\n * @description: convert camel case to dash case\n * string => string\n */\n\nexport var getDashCase = function getDashCase(name) {\n return name.replace(/([A-Z])/g, function (v) {\n return \"-\".concat(v.toLowerCase());\n });\n};\n/*\n * @description: add compatible style prefix\n * (string, string) => object\n */\n\nexport var generatePrefixStyle = function generatePrefixStyle(name, value) {\n if (IN_COMPATIBLE_PROPERTY.indexOf(name) === -1) {\n return _defineProperty({}, name, value);\n }\n\n var isTransition = name === 'transition';\n var camelName = name.replace(/(\\w)/, function (v) {\n return v.toUpperCase();\n });\n var styleVal = value;\n return PREFIX_LIST.reduce(function (result, property, i) {\n if (isTransition) {\n styleVal = value.replace(/(transform|transform-origin)/gim, \"\".concat(IN_LINE_PREFIX_LIST[i], \"$1\"));\n }\n\n return _objectSpread({}, result, _defineProperty({}, property + camelName, styleVal));\n }, {});\n};\nexport var log = function log() {\n var _console;\n\n (_console = console).log.apply(_console, arguments);\n};\n/*\n * @description: log the value of a varible\n * string => any => any\n */\n\nexport var debug = function debug(name) {\n return function (item) {\n log(name, item);\n return item;\n };\n};\n/*\n * @description: log name, args, return value of a function\n * function => function\n */\n\nexport var debugf = function debugf(tag, f) {\n return function () {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var res = f.apply(void 0, args);\n var name = tag || f.name || 'anonymous function';\n var argNames = \"(\".concat(args.map(JSON.stringify).join(', '), \")\");\n log(\"\".concat(name, \": \").concat(argNames, \" => \").concat(JSON.stringify(res)));\n return res;\n };\n};\n/*\n * @description: map object on every element in this object.\n * (function, object) => object\n */\n\nexport var mapObject = function mapObject(fn, obj) {\n return Object.keys(obj).reduce(function (res, key) {\n return _objectSpread({}, res, _defineProperty({}, key, fn(key, obj[key])));\n }, {});\n};\n/*\n * @description: add compatible prefix to style\n * object => object\n */\n\nexport var translateStyle = function translateStyle(style) {\n return Object.keys(style).reduce(function (res, key) {\n return _objectSpread({}, res, generatePrefixStyle(key, res[key]));\n }, style);\n};\nexport var compose = function compose() {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n if (!args.length) {\n return identity;\n }\n\n var fns = args.reverse(); // first function can receive multiply arguments\n\n var firstFn = fns[0];\n var tailsFn = fns.slice(1);\n return function () {\n return tailsFn.reduce(function (res, fn) {\n return fn(res);\n }, firstFn.apply(void 0, arguments));\n };\n};\nexport var getTransitionVal = function getTransitionVal(props, duration, easing) {\n return props.map(function (prop) {\n return \"\".concat(getDashCase(prop), \" \").concat(duration, \"ms \").concat(easing);\n }).join(',');\n};\nvar isDev = process.env.NODE_ENV !== 'production';\nexport var warn = function warn(condition, format, a, b, c, d, e, f) {\n if (isDev && typeof console !== 'undefined' && console.warn) {\n if (format === undefined) {\n console.warn('LogUtils requires an error message argument');\n }\n\n if (!condition) {\n if (format === undefined) {\n console.warn('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');\n } else {\n var args = [a, b, c, d, e, f];\n var argIndex = 0;\n console.warn(format.replace(/%s/g, function () {\n return args[argIndex++];\n }));\n }\n }\n }\n};", + "function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nimport { warn } from './util';\nvar ACCURACY = 1e-4;\n\nvar cubicBezierFactor = function cubicBezierFactor(c1, c2) {\n return [0, 3 * c1, 3 * c2 - 6 * c1, 3 * c1 - 3 * c2 + 1];\n};\n\nvar multyTime = function multyTime(params, t) {\n return params.map(function (param, i) {\n return param * Math.pow(t, i);\n }).reduce(function (pre, curr) {\n return pre + curr;\n });\n};\n\nvar cubicBezier = function cubicBezier(c1, c2) {\n return function (t) {\n var params = cubicBezierFactor(c1, c2);\n return multyTime(params, t);\n };\n};\n\nvar derivativeCubicBezier = function derivativeCubicBezier(c1, c2) {\n return function (t) {\n var params = cubicBezierFactor(c1, c2);\n\n var newParams = _toConsumableArray(params.map(function (param, i) {\n return param * i;\n }).slice(1)).concat([0]);\n\n return multyTime(newParams, t);\n };\n}; // calculate cubic-bezier using Newton's method\n\n\nexport var configBezier = function configBezier() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var x1 = args[0],\n y1 = args[1],\n x2 = args[2],\n y2 = args[3];\n\n if (args.length === 1) {\n switch (args[0]) {\n case 'linear':\n x1 = 0.0;\n y1 = 0.0;\n x2 = 1.0;\n y2 = 1.0;\n break;\n\n case 'ease':\n x1 = 0.25;\n y1 = 0.1;\n x2 = 0.25;\n y2 = 1.0;\n break;\n\n case 'ease-in':\n x1 = 0.42;\n y1 = 0.0;\n x2 = 1.0;\n y2 = 1.0;\n break;\n\n case 'ease-out':\n x1 = 0.42;\n y1 = 0.0;\n x2 = 0.58;\n y2 = 1.0;\n break;\n\n case 'ease-in-out':\n x1 = 0.0;\n y1 = 0.0;\n x2 = 0.58;\n y2 = 1.0;\n break;\n\n default:\n warn(false, '[configBezier]: arguments should be one of ' + 'oneOf \\'linear\\', \\'ease\\', \\'ease-in\\', \\'ease-out\\', ' + '\\'ease-in-out\\', instead received %s', args);\n }\n }\n\n warn([x1, x2, y1, y2].every(function (num) {\n return typeof num === 'number' && num >= 0 && num <= 1;\n }), '[configBezier]: arguments should be x1, y1, x2, y2 of [0, 1] instead received %s', args);\n var curveX = cubicBezier(x1, x2);\n var curveY = cubicBezier(y1, y2);\n var derCurveX = derivativeCubicBezier(x1, x2);\n\n var rangeValue = function rangeValue(value) {\n if (value > 1) {\n return 1;\n } else if (value < 0) {\n return 0;\n }\n\n return value;\n };\n\n var bezier = function bezier(_t) {\n var t = _t > 1 ? 1 : _t;\n var x = t;\n\n for (var i = 0; i < 8; ++i) {\n var evalT = curveX(x) - t;\n var derVal = derCurveX(x);\n\n if (Math.abs(evalT - t) < ACCURACY || derVal < ACCURACY) {\n return curveY(x);\n }\n\n x = rangeValue(x - evalT / derVal);\n }\n\n return curveY(x);\n };\n\n bezier.isStepper = false;\n return bezier;\n};\nexport var configSpring = function configSpring() {\n var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var _config$stiff = config.stiff,\n stiff = _config$stiff === void 0 ? 100 : _config$stiff,\n _config$damping = config.damping,\n damping = _config$damping === void 0 ? 8 : _config$damping,\n _config$dt = config.dt,\n dt = _config$dt === void 0 ? 17 : _config$dt;\n\n var stepper = function stepper(currX, destX, currV) {\n var FSpring = -(currX - destX) * stiff;\n var FDamping = currV * damping;\n var newV = currV + (FSpring - FDamping) * dt / 1000;\n var newX = currV * dt / 1000 + currX;\n\n if (Math.abs(newX - destX) < ACCURACY && Math.abs(newV) < ACCURACY) {\n return [destX, 0];\n }\n\n return [newX, newV];\n };\n\n stepper.isStepper = true;\n stepper.dt = dt;\n return stepper;\n};\nexport var configEasing = function configEasing() {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n var easing = args[0];\n\n if (typeof easing === 'string') {\n switch (easing) {\n case 'ease':\n case 'ease-in-out':\n case 'ease-out':\n case 'ease-in':\n case 'linear':\n return configBezier(easing);\n\n case 'spring':\n return configSpring();\n\n default:\n warn(false, '[configEasing]: first argument should be one of \\'ease\\', \\'ease-in\\', ' + '\\'ease-out\\', \\'ease-in-out\\', \\'linear\\' and \\'spring\\', instead received %s', args);\n }\n }\n\n if (typeof easing === 'function') {\n return easing;\n }\n\n warn(false, '[configEasing]: first argument type should be function or ' + 'string, instead received %s', args);\n return null;\n};", + "import _filter from \"lodash/filter\";\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nimport raf, { cancel as caf } from 'raf';\nimport { getIntersectionKeys, mapObject } from './util';\n\nvar alpha = function alpha(begin, end, k) {\n return begin + (end - begin) * k;\n};\n\nvar needContinue = function needContinue(_ref) {\n var from = _ref.from,\n to = _ref.to;\n return from !== to;\n};\n/*\n * @description: cal new from value and velocity in each stepper\n * @return: { [styleProperty]: { from, to, velocity } }\n */\n\n\nvar calStepperVals = function calStepperVals(easing, preVals, steps) {\n var nextStepVals = mapObject(function (key, val) {\n if (needContinue(val)) {\n var _easing = easing(val.from, val.to, val.velocity),\n _easing2 = _slicedToArray(_easing, 2),\n newX = _easing2[0],\n newV = _easing2[1];\n\n return _objectSpread({}, val, {\n from: newX,\n velocity: newV\n });\n }\n\n return val;\n }, preVals);\n\n if (steps < 1) {\n return mapObject(function (key, val) {\n if (needContinue(val)) {\n return _objectSpread({}, val, {\n velocity: alpha(val.velocity, nextStepVals[key].velocity, steps),\n from: alpha(val.from, nextStepVals[key].from, steps)\n });\n }\n\n return val;\n }, preVals);\n }\n\n return calStepperVals(easing, nextStepVals, steps - 1);\n}; // configure update function\n\n\nexport default (function (from, to, easing, duration, render) {\n var interKeys = getIntersectionKeys(from, to);\n var timingStyle = interKeys.reduce(function (res, key) {\n return _objectSpread({}, res, _defineProperty({}, key, [from[key], to[key]]));\n }, {});\n var stepperStyle = interKeys.reduce(function (res, key) {\n return _objectSpread({}, res, _defineProperty({}, key, {\n from: from[key],\n velocity: 0,\n to: to[key]\n }));\n }, {});\n var cafId = -1;\n var preTime;\n var beginTime;\n\n var update = function update() {\n return null;\n };\n\n var getCurrStyle = function getCurrStyle() {\n return mapObject(function (key, val) {\n return val.from;\n }, stepperStyle);\n };\n\n var shouldStopAnimation = function shouldStopAnimation() {\n return !_filter(stepperStyle, needContinue).length;\n }; // stepper timing function like spring\n\n\n var stepperUpdate = function stepperUpdate(now) {\n if (!preTime) {\n preTime = now;\n }\n\n var deltaTime = now - preTime;\n var steps = deltaTime / easing.dt;\n stepperStyle = calStepperVals(easing, stepperStyle, steps); // get union set and add compatible prefix\n\n render(_objectSpread({}, from, to, getCurrStyle(stepperStyle)));\n preTime = now;\n\n if (!shouldStopAnimation()) {\n cafId = raf(update);\n }\n }; // t => val timing function like cubic-bezier\n\n\n var timingUpdate = function timingUpdate(now) {\n if (!beginTime) {\n beginTime = now;\n }\n\n var t = (now - beginTime) / duration;\n var currStyle = mapObject(function (key, val) {\n return alpha.apply(void 0, _toConsumableArray(val).concat([easing(t)]));\n }, timingStyle); // get union set and add compatible prefix\n\n render(_objectSpread({}, from, to, currStyle));\n\n if (t < 1) {\n cafId = raf(update);\n } else {\n var finalStyle = mapObject(function (key, val) {\n return alpha.apply(void 0, _toConsumableArray(val).concat([easing(1)]));\n }, timingStyle);\n render(_objectSpread({}, from, to, finalStyle));\n }\n };\n\n update = easing.isStepper ? stepperUpdate : timingUpdate; // return start animation method\n\n return function () {\n raf(update); // return stop animation method\n\n return function () {\n caf(cafId);\n };\n };\n});", + "import _isEqual from \"lodash/isEqual\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nimport React, { Component, cloneElement, Children } from 'react';\nimport PropTypes from 'prop-types';\nimport createAnimateManager from './AnimateManager';\nimport pureRender from './PureRender';\nimport { configEasing } from './easing';\nimport configUpdate from './configUpdate';\nimport { getTransitionVal, identity, translateStyle } from './util';\n\nvar Animate = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Animate, _Component);\n\n function Animate(props, context) {\n var _this;\n\n _classCallCheck(this, Animate);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(Animate).call(this, props, context));\n var _this$props = _this.props,\n isActive = _this$props.isActive,\n attributeName = _this$props.attributeName,\n from = _this$props.from,\n to = _this$props.to,\n steps = _this$props.steps,\n children = _this$props.children;\n _this.handleStyleChange = _this.handleStyleChange.bind(_assertThisInitialized(_assertThisInitialized(_this)));\n _this.changeStyle = _this.changeStyle.bind(_assertThisInitialized(_assertThisInitialized(_this)));\n\n if (!isActive) {\n _this.state = {\n style: {}\n }; // if children is a function and animation is not active, set style to 'to'\n\n if (typeof children === 'function') {\n _this.state = {\n style: to\n };\n }\n\n return _possibleConstructorReturn(_this);\n }\n\n if (steps && steps.length) {\n _this.state = {\n style: steps[0].style\n };\n } else if (from) {\n if (typeof children === 'function') {\n _this.state = {\n style: from\n };\n return _possibleConstructorReturn(_this);\n }\n\n _this.state = {\n style: attributeName ? _defineProperty({}, attributeName, from) : from\n };\n } else {\n _this.state = {\n style: {}\n };\n }\n\n return _this;\n }\n\n _createClass(Animate, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this$props2 = this.props,\n isActive = _this$props2.isActive,\n canBegin = _this$props2.canBegin;\n this.mounted = true;\n\n if (!isActive || !canBegin) {\n return;\n }\n\n this.runAnimation(this.props);\n }\n }, {\n key: \"componentWillReceiveProps\",\n value: function componentWillReceiveProps(nextProps) {\n var isActive = nextProps.isActive,\n canBegin = nextProps.canBegin,\n attributeName = nextProps.attributeName,\n shouldReAnimate = nextProps.shouldReAnimate;\n\n if (!canBegin) {\n return;\n }\n\n if (!isActive) {\n this.setState({\n style: attributeName ? _defineProperty({}, attributeName, nextProps.to) : nextProps.to\n });\n return;\n }\n\n if (_isEqual(this.props.to, nextProps.to) && this.props.canBegin && this.props.isActive) {\n return;\n }\n\n var isTriggered = !this.props.canBegin || !this.props.isActive;\n\n if (this.manager) {\n this.manager.stop();\n }\n\n if (this.stopJSAnimation) {\n this.stopJSAnimation();\n }\n\n var from = isTriggered || shouldReAnimate ? nextProps.from : this.props.to;\n this.setState({\n style: attributeName ? _defineProperty({}, attributeName, from) : from\n });\n this.runAnimation(_objectSpread({}, nextProps, {\n from: from,\n begin: 0\n }));\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n this.mounted = false;\n\n if (this.unSubscribe) {\n this.unSubscribe();\n }\n\n if (this.manager) {\n this.manager.stop();\n this.manager = null;\n }\n\n if (this.stopJSAnimation) {\n this.stopJSAnimation();\n }\n }\n }, {\n key: \"runJSAnimation\",\n value: function runJSAnimation(props) {\n var _this2 = this;\n\n var from = props.from,\n to = props.to,\n duration = props.duration,\n easing = props.easing,\n begin = props.begin,\n onAnimationEnd = props.onAnimationEnd,\n onAnimationStart = props.onAnimationStart;\n var startAnimation = configUpdate(from, to, configEasing(easing), duration, this.changeStyle);\n\n var finalStartAnimation = function finalStartAnimation() {\n _this2.stopJSAnimation = startAnimation();\n };\n\n this.manager.start([onAnimationStart, begin, finalStartAnimation, duration, onAnimationEnd]);\n }\n }, {\n key: \"runStepAnimation\",\n value: function runStepAnimation(props) {\n var _this3 = this;\n\n var steps = props.steps,\n begin = props.begin,\n onAnimationStart = props.onAnimationStart;\n var _steps$ = steps[0],\n initialStyle = _steps$.style,\n _steps$$duration = _steps$.duration,\n initialTime = _steps$$duration === void 0 ? 0 : _steps$$duration;\n\n var addStyle = function addStyle(sequence, nextItem, index) {\n if (index === 0) {\n return sequence;\n }\n\n var duration = nextItem.duration,\n _nextItem$easing = nextItem.easing,\n easing = _nextItem$easing === void 0 ? 'ease' : _nextItem$easing,\n style = nextItem.style,\n nextProperties = nextItem.properties,\n onAnimationEnd = nextItem.onAnimationEnd;\n var preItem = index > 0 ? steps[index - 1] : nextItem;\n var properties = nextProperties || Object.keys(style);\n\n if (typeof easing === 'function' || easing === 'spring') {\n return _toConsumableArray(sequence).concat([_this3.runJSAnimation.bind(_this3, {\n from: preItem.style,\n to: style,\n duration: duration,\n easing: easing\n }), duration]);\n }\n\n var transition = getTransitionVal(properties, duration, easing);\n\n var newStyle = _objectSpread({}, preItem.style, style, {\n transition: transition\n });\n\n return _toConsumableArray(sequence).concat([newStyle, duration, onAnimationEnd]).filter(identity);\n };\n\n return this.manager.start([onAnimationStart].concat(_toConsumableArray(steps.reduce(addStyle, [initialStyle, Math.max(initialTime, begin)])), [props.onAnimationEnd]));\n }\n }, {\n key: \"runAnimation\",\n value: function runAnimation(props) {\n if (!this.manager) {\n this.manager = createAnimateManager();\n }\n\n var begin = props.begin,\n duration = props.duration,\n attributeName = props.attributeName,\n propsTo = props.to,\n easing = props.easing,\n onAnimationStart = props.onAnimationStart,\n onAnimationEnd = props.onAnimationEnd,\n steps = props.steps,\n children = props.children;\n var manager = this.manager;\n this.unSubscribe = manager.subscribe(this.handleStyleChange);\n\n if (typeof easing === 'function' || typeof children === 'function' || easing === 'spring') {\n this.runJSAnimation(props);\n return;\n }\n\n if (steps.length > 1) {\n this.runStepAnimation(props);\n return;\n }\n\n var to = attributeName ? _defineProperty({}, attributeName, propsTo) : propsTo;\n var transition = getTransitionVal(Object.keys(to), duration, easing);\n manager.start([onAnimationStart, begin, _objectSpread({}, to, {\n transition: transition\n }), duration, onAnimationEnd]);\n }\n }, {\n key: \"handleStyleChange\",\n value: function handleStyleChange(style) {\n this.changeStyle(style);\n }\n }, {\n key: \"changeStyle\",\n value: function changeStyle(style) {\n if (this.mounted) {\n this.setState({\n style: style\n });\n }\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props3 = this.props,\n children = _this$props3.children,\n begin = _this$props3.begin,\n duration = _this$props3.duration,\n attributeName = _this$props3.attributeName,\n easing = _this$props3.easing,\n isActive = _this$props3.isActive,\n steps = _this$props3.steps,\n from = _this$props3.from,\n to = _this$props3.to,\n canBegin = _this$props3.canBegin,\n onAnimationEnd = _this$props3.onAnimationEnd,\n shouldReAnimate = _this$props3.shouldReAnimate,\n onAnimationReStart = _this$props3.onAnimationReStart,\n others = _objectWithoutProperties(_this$props3, [\"children\", \"begin\", \"duration\", \"attributeName\", \"easing\", \"isActive\", \"steps\", \"from\", \"to\", \"canBegin\", \"onAnimationEnd\", \"shouldReAnimate\", \"onAnimationReStart\"]);\n\n var count = Children.count(children);\n var stateStyle = translateStyle(this.state.style);\n\n if (typeof children === 'function') {\n return children(stateStyle);\n }\n\n if (!isActive || count === 0) {\n return children;\n }\n\n var cloneContainer = function cloneContainer(container) {\n var _container$props = container.props,\n _container$props$styl = _container$props.style,\n style = _container$props$styl === void 0 ? {} : _container$props$styl,\n className = _container$props.className;\n var res = cloneElement(container, _objectSpread({}, others, {\n style: _objectSpread({}, style, stateStyle),\n className: className\n }));\n return res;\n };\n\n if (count === 1) {\n return cloneContainer(Children.only(children));\n }\n\n return React.createElement(\"div\", null, Children.map(children, function (child) {\n return cloneContainer(child);\n }));\n }\n }]);\n\n return Animate;\n}(Component), _class2.displayName = 'Animate', _class2.propTypes = {\n from: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),\n to: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),\n attributeName: PropTypes.string,\n // animation duration\n duration: PropTypes.number,\n begin: PropTypes.number,\n easing: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),\n steps: PropTypes.arrayOf(PropTypes.shape({\n duration: PropTypes.number.isRequired,\n style: PropTypes.object.isRequired,\n easing: PropTypes.oneOfType([PropTypes.oneOf(['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear']), PropTypes.func]),\n // transition css properties(dash case), optional\n properties: PropTypes.arrayOf('string'),\n onAnimationEnd: PropTypes.func\n })),\n children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),\n isActive: PropTypes.bool,\n canBegin: PropTypes.bool,\n onAnimationEnd: PropTypes.func,\n // decide if it should reanimate with initial from style when props change\n shouldReAnimate: PropTypes.bool,\n onAnimationStart: PropTypes.func,\n onAnimationReStart: PropTypes.func\n}, _class2.defaultProps = {\n begin: 0,\n duration: 1000,\n from: '',\n to: '',\n attributeName: '',\n easing: 'ease',\n isActive: true,\n canBegin: true,\n steps: [],\n onAnimationEnd: function onAnimationEnd() {},\n onAnimationStart: function onAnimationStart() {}\n}, _temp)) || _class;\n\nexport default Animate;", + "import _isNumber from \"lodash/isNumber\";\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nimport React, { Component, Children } from 'react';\nimport { Transition } from 'react-transition-group';\nimport PropTypes from 'prop-types';\nimport Animate from './Animate';\n\nvar parseDurationOfSingleTransition = function parseDurationOfSingleTransition() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var steps = options.steps,\n duration = options.duration;\n\n if (steps && steps.length) {\n return steps.reduce(function (result, entry) {\n return result + (_isNumber(entry.duration) && entry.duration > 0 ? entry.duration : 0);\n }, 0);\n }\n\n if (_isNumber(duration)) {\n return duration;\n }\n\n return 0;\n};\n\nvar AnimateGroupChild =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(AnimateGroupChild, _Component);\n\n function AnimateGroupChild() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, AnimateGroupChild);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AnimateGroupChild)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n isActive: false\n };\n\n _this.handleEnter = function (node, isAppearing) {\n var _this$props = _this.props,\n appearOptions = _this$props.appearOptions,\n enterOptions = _this$props.enterOptions;\n\n _this.handleStyleActive(isAppearing ? appearOptions : enterOptions);\n };\n\n _this.handleExit = function () {\n _this.handleStyleActive(_this.props.leaveOptions);\n };\n\n return _this;\n }\n\n _createClass(AnimateGroupChild, [{\n key: \"handleStyleActive\",\n value: function handleStyleActive(style) {\n if (style) {\n var onAnimationEnd = style.onAnimationEnd ? function () {\n style.onAnimationEnd();\n } : null;\n this.setState(_objectSpread({}, style, {\n onAnimationEnd: onAnimationEnd,\n isActive: true\n }));\n }\n }\n }, {\n key: \"parseTimeout\",\n value: function parseTimeout() {\n var _this$props2 = this.props,\n appearOptions = _this$props2.appearOptions,\n enterOptions = _this$props2.enterOptions,\n leaveOptions = _this$props2.leaveOptions;\n return parseDurationOfSingleTransition(appearOptions) + parseDurationOfSingleTransition(enterOptions) + parseDurationOfSingleTransition(leaveOptions);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this2 = this;\n\n var _this$props3 = this.props,\n children = _this$props3.children,\n appearOptions = _this$props3.appearOptions,\n enterOptions = _this$props3.enterOptions,\n leaveOptions = _this$props3.leaveOptions,\n props = _objectWithoutProperties(_this$props3, [\"children\", \"appearOptions\", \"enterOptions\", \"leaveOptions\"]);\n\n return React.createElement(Transition, _extends({}, props, {\n onEnter: this.handleEnter,\n onExit: this.handleExit,\n timeout: this.parseTimeout()\n }), function () {\n return React.createElement(Animate, _this2.state, Children.only(children));\n });\n }\n }]);\n\n return AnimateGroupChild;\n}(Component);\n\nAnimateGroupChild.propTypes = {\n appearOptions: PropTypes.object,\n enterOptions: PropTypes.object,\n leaveOptions: PropTypes.object,\n children: PropTypes.element\n};\nexport default AnimateGroupChild;", + "import React, { Children } from 'react';\nimport { TransitionGroup } from 'react-transition-group';\nimport PropTypes from 'prop-types';\nimport AnimateGroupChild from './AnimateGroupChild';\n\nfunction AnimateGroup(props) {\n var component = props.component,\n children = props.children,\n appear = props.appear,\n enter = props.enter,\n leave = props.leave;\n return React.createElement(TransitionGroup, {\n component: component\n }, Children.map(children, function (child, index) {\n return React.createElement(AnimateGroupChild, {\n appearOptions: appear,\n enterOptions: enter,\n leaveOptions: leave,\n key: \"child-\".concat(index)\n }, child);\n }));\n}\n\nAnimateGroup.propTypes = {\n appear: PropTypes.object,\n enter: PropTypes.object,\n leave: PropTypes.object,\n children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]),\n component: PropTypes.any\n};\nAnimateGroup.defaultProps = {\n component: 'span'\n};\nexport default AnimateGroup;", + "import Animate from './Animate';\nimport { configBezier, configSpring } from './easing';\nimport { translateStyle } from './util';\nimport AnimateGroup from './AnimateGroup';\nexport { configSpring, configBezier, AnimateGroup, translateStyle };\nexport default Animate;", + "\"use strict\";\n\nexports.__esModule = true;\nexports.default = void 0;\n\nvar PropTypes = _interopRequireWildcard(require(\"prop-types\"));\n\nvar _addClass = _interopRequireDefault(require(\"dom-helpers/class/addClass\"));\n\nvar _removeClass = _interopRequireDefault(require(\"dom-helpers/class/removeClass\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _Transition = _interopRequireDefault(require(\"./Transition\"));\n\nvar _PropTypes = require(\"./utils/PropTypes\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\nvar addClass = function addClass(node, classes) {\n return node && classes && classes.split(' ').forEach(function (c) {\n return (0, _addClass.default)(node, c);\n });\n};\n\nvar removeClass = function removeClass(node, classes) {\n return node && classes && classes.split(' ').forEach(function (c) {\n return (0, _removeClass.default)(node, c);\n });\n};\n/**\n * A `)) + ("`" + (`Transition` + "`")))) + (((` component using CSS transitions and animations.\n * It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library.\n *\n * ` + "`") + (`CSSTransition` + ("`" + ` applies a pair of class names during the `))) + (("`" + (`appear` + "`")) + (`, ` + ("`" + `enter`)))))) + ((((("`" + `,\n * and `) + ("`" + (`exit` + "`"))) + ((` stages of the transition. The first class is applied and then a\n * second \"active\" class in order to activate the css animation. After the animation,\n * matching ` + ("`" + `done`)) + ("`" + (` class names are applied to persist the animation state.\n *\n * When the ` + "`")))) + (((`in` + "`") + (` prop is toggled to ` + ("`" + `true`))) + (("`" + (` the Component will get\n * the ` + "`")) + (`example-enter` + ("`" + ` CSS class and the `))))) + (((("`" + `example-enter-active`) + ("`" + (` CSS class\n * added in the next tick. This is a convention based on the ` + "`"))) + ((`classNames` + ("`" + ` prop.\n */\n\n\nvar CSSTransition =\n/*#__PURE__*/\nfunction (_React$Component) {\n _inheritsLoose(CSSTransition, _React$Component);\n\n function CSSTransition() {\n var _this;\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;\n\n _this.onEnter = function (node, appearing) {\n var _this$getClassNames = _this.getClassNames(appearing ? 'appear' : 'enter'),\n className = _this$getClassNames.className;\n\n _this.removeClasses(node, 'exit');\n\n addClass(node, className);\n\n if (_this.props.onEnter) {\n _this.props.onEnter(node, appearing);\n }\n };\n\n _this.onEntering = function (node, appearing) {\n var _this$getClassNames2 = _this.getClassNames(appearing ? 'appear' : 'enter'),\n activeClassName = _this$getClassNames2.activeClassName;\n\n _this.reflowAndAddClass(node, activeClassName);\n\n if (_this.props.onEntering) {\n _this.props.onEntering(node, appearing);\n }\n };\n\n _this.onEntered = function (node, appearing) {\n var _this$getClassNames3 = _this.getClassNames('enter'),\n doneClassName = _this$getClassNames3.doneClassName;\n\n _this.removeClasses(node, appearing ? 'appear' : 'enter');\n\n addClass(node, doneClassName);\n\n if (_this.props.onEntered) {\n _this.props.onEntered(node, appearing);\n }\n };\n\n _this.onExit = function (node) {\n var _this$getClassNames4 = _this.getClassNames('exit'),\n className = _this$getClassNames4.className;\n\n _this.removeClasses(node, 'appear');\n\n _this.removeClasses(node, 'enter');\n\n addClass(node, className);\n\n if (_this.props.onExit) {\n _this.props.onExit(node);\n }\n };\n\n _this.onExiting = function (node) {\n var _this$getClassNames5 = _this.getClassNames('exit'),\n activeClassName = _this$getClassNames5.activeClassName;\n\n _this.reflowAndAddClass(node, activeClassName);\n\n if (_this.props.onExiting) {\n _this.props.onExiting(node);\n }\n };\n\n _this.onExited = function (node) {\n var _this$getClassNames6 = _this.getClassNames('exit'),\n doneClassName = _this$getClassNames6.doneClassName;\n\n _this.removeClasses(node, 'exit');\n\n addClass(node, doneClassName);\n\n if (_this.props.onExited) {\n _this.props.onExited(node);\n }\n };\n\n _this.getClassNames = function (type) {\n var classNames = _this.props.classNames;\n var className = typeof classNames !== 'string' ? classNames[type] : classNames + '-' + type;\n var activeClassName = typeof classNames !== 'string' ? classNames[type + 'Active'] : className + '-active';\n var doneClassName = typeof classNames !== 'string' ? classNames[type + 'Done'] : className + '-done';\n return {\n className: className,\n activeClassName: activeClassName,\n doneClassName: doneClassName\n };\n };\n\n return _this;\n }\n\n var _proto = CSSTransition.prototype;\n\n _proto.removeClasses = function removeClasses(node, type) {\n var _this$getClassNames7 = this.getClassNames(type),\n className = _this$getClassNames7.className,\n activeClassName = _this$getClassNames7.activeClassName,\n doneClassName = _this$getClassNames7.doneClassName;\n\n className && removeClass(node, className);\n activeClassName && removeClass(node, activeClassName);\n doneClassName && removeClass(node, doneClassName);\n };\n\n _proto.reflowAndAddClass = function reflowAndAddClass(node, className) {\n // This is for to force a repaint,\n // which is necessary in order to transition styles when adding a class name.\n if (className) {\n /* eslint-disable no-unused-expressions */\n node && node.scrollTop;\n /* eslint-enable no-unused-expressions */\n\n addClass(node, className);\n }\n };\n\n _proto.render = function render() {\n var props = _extends({}, this.props);\n\n delete props.classNames;\n return _react.default.createElement(_Transition.default, _extends({}, props, {\n onEnter: this.onEnter,\n onEntered: this.onEntered,\n onEntering: this.onEntering,\n onExit: this.onExit,\n onExiting: this.onExiting,\n onExited: this.onExited\n }));\n };\n\n return CSSTransition;\n}(_react.default.Component);\n\nCSSTransition.propTypes = process.env.NODE_ENV !== \"production\" ? _extends({}, _Transition.default.propTypes, {\n /**\n * The animation classNames applied to the component as it enters, exits or has finished the transition.\n * A single name can be provided and it will be suffixed for each stage: e.g.\n *\n * `)) + ("`" + (`classNames=\"fade\"` + "`")))) + (((` applies ` + ("`" + `fade-enter`)) + ("`" + (`, ` + "`"))) + ((`fade-enter-active` + ("`" + `, `)) + ("`" + (`fade-enter-done` + "`")))))))) + (((((((`,\n * ` + "`") + (`fade-exit` + ("`" + `, `))) + (("`" + (`fade-exit-active` + "`")) + (`, ` + ("`" + `fade-exit-done`)))) + ((("`" + `, `) + ("`" + (`fade-appear` + "`"))) + ((`, and ` + ("`" + `fade-appear-active`)) + ("`" + (`.\n * Each individual classNames can also be specified independently like:\n *\n * ` + "`"))))) + (((("`" + "`") + (`js\n * classNames={{\n * appear: 'my-appear',\n * appearActive: 'my-active-appear',\n * enter: 'my-enter',\n * enterActive: 'my-active-enter',\n * enterDone: 'my-done-enter',\n * exit: 'my-exit',\n * exitActive: 'my-active-exit',\n * exitDone: 'my-done-exit',\n * }}\n * ` + ("`" + "`"))) + (("`" + (`\n *\n * If you want to set these classes using CSS Modules:\n *\n * ` + "`")) + ("`" + ("`" + `js\n * import styles from './styles.css';\n * `)))) + ((("`" + "`") + ("`" + (`\n *\n * you might want to use camelCase in your CSS file, that way could simply spread\n * them instead of listing them one by one:\n *\n * ` + "`"))) + (("`" + ("`" + `js\n * classNames={{ ...styles }}\n * `)) + ("`" + ("`" + "`")))))) + (((((`\n *\n * @type {string | {\n * appear?: string,\n * appearActive?: string,\n * enter?: string,\n * enterActive?: string,\n * enterDone?: string,\n * exit?: string,\n * exitActive?: string,\n * exitDone?: string,\n * }}\n */\n classNames: _PropTypes.classNamesShape,\n\n /**\n * A ` + "`") + (`` + ("`" + ` callback fired immediately after the 'enter' or 'appear' class is\n * applied.\n *\n * @type Function(node: HtmlElement, isAppearing: bool)\n */\n onEnter: PropTypes.func,\n\n /**\n * A `))) + (("`" + (`` + "`")) + (` callback fired immediately after the 'enter-active' or\n * 'appear-active' class is applied.\n *\n * @type Function(node: HtmlElement, isAppearing: bool)\n */\n onEntering: PropTypes.func,\n\n /**\n * A ` + ("`" + ``)))) + ((("`" + ` callback fired immediately after the 'enter' or\n * 'appear' classes are **removed** and the `) + ("`" + (`done` + "`"))) + ((` class is added to the DOM node.\n *\n * @type Function(node: HtmlElement, isAppearing: bool)\n */\n onEntered: PropTypes.func,\n\n /**\n * A ` + ("`" + ``)) + ("`" + (` callback fired immediately after the 'exit' class is\n * applied.\n *\n * @type Function(node: HtmlElement)\n */\n onExit: PropTypes.func,\n\n /**\n * A ` + "`"))))) + ((((`` + "`") + (` callback fired immediately after the 'exit-active' is applied.\n *\n * @type Function(node: HtmlElement)\n */\n onExiting: PropTypes.func,\n\n /**\n * A ` + ("`" + ``))) + (("`" + (` callback fired immediately after the 'exit' classes\n * are **removed** and the ` + "`")) + (`exit-done` + ("`" + ` class is added to the DOM node.\n *\n * @type Function(node: HtmlElement)\n */\n onExited: PropTypes.func\n}) : {};\nvar _default = CSSTransition;\nexports.default = _default;\nmodule.exports = exports[\"default\"];", + "\"use strict\";\n\nexports.__esModule = true;\nexports.default = void 0;\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _reactDom = require(\"react-dom\");\n\nvar _TransitionGroup = _interopRequireDefault(require(\"./TransitionGroup\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\n/**\n * The `)))) + ((("`" + (`` + "`")) + (` component is a specialized ` + ("`" + `Transition`))) + (("`" + (` component\n * that animates between two children.\n *\n * ` + "`")) + ("`" + ("`" + `jsx\n * \n *
I appear first
\n *
I replace the above
\n *
\n * `))))))) + (((((("`" + "`") + ("`" + (`\n */\nvar ReplaceTransition =\n/*#__PURE__*/\nfunction (_React$Component) {\n _inheritsLoose(ReplaceTransition, _React$Component);\n\n function ReplaceTransition() {\n var _this;\n\n for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {\n _args[_key] = arguments[_key];\n }\n\n _this = _React$Component.call.apply(_React$Component, [this].concat(_args)) || this;\n\n _this.handleEnter = function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n return _this.handleLifecycle('onEnter', 0, args);\n };\n\n _this.handleEntering = function () {\n for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n args[_key3] = arguments[_key3];\n }\n\n return _this.handleLifecycle('onEntering', 0, args);\n };\n\n _this.handleEntered = function () {\n for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {\n args[_key4] = arguments[_key4];\n }\n\n return _this.handleLifecycle('onEntered', 0, args);\n };\n\n _this.handleExit = function () {\n for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {\n args[_key5] = arguments[_key5];\n }\n\n return _this.handleLifecycle('onExit', 1, args);\n };\n\n _this.handleExiting = function () {\n for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {\n args[_key6] = arguments[_key6];\n }\n\n return _this.handleLifecycle('onExiting', 1, args);\n };\n\n _this.handleExited = function () {\n for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) {\n args[_key7] = arguments[_key7];\n }\n\n return _this.handleLifecycle('onExited', 1, args);\n };\n\n return _this;\n }\n\n var _proto = ReplaceTransition.prototype;\n\n _proto.handleLifecycle = function handleLifecycle(handler, idx, originalArgs) {\n var _child$props;\n\n var children = this.props.children;\n\n var child = _react.default.Children.toArray(children)[idx];\n\n if (child.props[handler]) (_child$props = child.props)[handler].apply(_child$props, originalArgs);\n if (this.props[handler]) this.props[handler]((0, _reactDom.findDOMNode)(this));\n };\n\n _proto.render = function render() {\n var _this$props = this.props,\n children = _this$props.children,\n inProp = _this$props.in,\n props = _objectWithoutPropertiesLoose(_this$props, [\"children\", \"in\"]);\n\n var _React$Children$toArr = _react.default.Children.toArray(children),\n first = _React$Children$toArr[0],\n second = _React$Children$toArr[1];\n\n delete props.onEnter;\n delete props.onEntering;\n delete props.onEntered;\n delete props.onExit;\n delete props.onExiting;\n delete props.onExited;\n return _react.default.createElement(_TransitionGroup.default, props, inProp ? _react.default.cloneElement(first, {\n key: 'first',\n onEnter: this.handleEnter,\n onEntering: this.handleEntering,\n onEntered: this.handleEntered\n }) : _react.default.cloneElement(second, {\n key: 'second',\n onEnter: this.handleExit,\n onEntering: this.handleExiting,\n onEntered: this.handleExited\n }));\n };\n\n return ReplaceTransition;\n}(_react.default.Component);\n\nReplaceTransition.propTypes = process.env.NODE_ENV !== \"production\" ? {\n in: _propTypes.default.bool.isRequired,\n children: function children(props, propName) {\n if (_react.default.Children.count(props[propName]) !== 2) return new Error(\"\\\"\" + propName + \"\\\" must be exactly two transition components.\");\n return null;\n }\n} : {};\nvar _default = ReplaceTransition;\nexports.default = _default;\nmodule.exports = exports[\"default\"];", + "\"use strict\";\n\nexports.__esModule = true;\nexports.default = exports.EXITING = exports.ENTERED = exports.ENTERING = exports.EXITED = exports.UNMOUNTED = void 0;\n\nvar PropTypes = _interopRequireWildcard(require(\"prop-types\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _reactDom = _interopRequireDefault(require(\"react-dom\"));\n\nvar _reactLifecyclesCompat = require(\"react-lifecycles-compat\");\n\nvar _PropTypes = require(\"./utils/PropTypes\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\nvar UNMOUNTED = 'unmounted';\nexports.UNMOUNTED = UNMOUNTED;\nvar EXITED = 'exited';\nexports.EXITED = EXITED;\nvar ENTERING = 'entering';\nexports.ENTERING = ENTERING;\nvar ENTERED = 'entered';\nexports.ENTERED = ENTERED;\nvar EXITING = 'exiting';\n/**\n * The Transition component lets you describe a transition from one component\n * state to another _over time_ with a simple declarative API. Most commonly\n * it's used to animate the mounting and unmounting of a component, but can also\n * be used to describe in-place transition states as well.\n *\n * By default the ` + "`"))) + ((`Transition` + ("`" + ` component does not alter the behavior of the\n * component it renders, it only tracks \"enter\" and \"exit\" states for the components.\n * It's up to you to give meaning and effect to those states. For example we can\n * add styles to a component when it enters or exits:\n *\n * `)) + ("`" + ("`" + "`")))) + (((`jsx\n * import Transition from 'react-transition-group/Transition';\n *\n * const duration = 300;\n *\n * const defaultStyle = {\n * transition: ` + "`") + (`opacity ${duration}ms ease-in-out` + ("`" + `,\n * opacity: 0,\n * }\n *\n * const transitionStyles = {\n * entering: { opacity: 0 },\n * entered: { opacity: 1 },\n * };\n *\n * const Fade = ({ in: inProp }) => (\n * \n * {(state) => (\n *
\n * I'm a fade Transition!\n *
\n * )}\n *
\n * );\n * `))) + (("`" + ("`" + "`")) + (`\n *\n * As noted the ` + ("`" + `Transition`))))) + (((("`" + ` component doesn't _do_ anything by itself to its child component.\n * What it does do is track transition states over time so you can update the\n * component (such as by adding styles or classes) when it changes states.\n *\n * There are 4 main states a Transition can be in:\n * - `) + ("`" + (`'entering'` + "`"))) + ((`\n * - ` + ("`" + `'entered'`)) + ("`" + (`\n * - ` + "`")))) + (((`'exiting'` + "`") + (`\n * - ` + ("`" + `'exited'`))) + (("`" + (`\n *\n * Transition state is toggled via the ` + "`")) + (`in` + ("`" + ` prop. When `)))))) + ((((("`" + `true`) + ("`" + (` the component begins the\n * \"Enter\" stage. During this stage, the component will shift from its current transition state,\n * to ` + "`"))) + ((`'entering'` + ("`" + ` for the duration of the transition and then to the `)) + ("`" + (`'entered'` + "`")))) + (((` stage once\n * it's complete. Let's take the following example:\n *\n * ` + "`") + ("`" + ("`" + `jsx\n * state = { in: false };\n *\n * toggleEnterState = () => {\n * this.setState({ in: true });\n * }\n *\n * render() {\n * return (\n *
\n * \n * \n *
\n * );\n * }\n * `))) + (("`" + ("`" + "`")) + (`\n *\n * When the button is clicked the component will shift to the ` + ("`" + `'entering'`))))) + (((("`" + ` state and\n * stay there for 500ms (the value of `) + ("`" + (`timeout` + "`"))) + ((`) before it finally switches to ` + ("`" + `'entered'`)) + ("`" + (`.\n *\n * When ` + "`")))) + (((`in` + ("`" + ` is `)) + ("`" + (`false` + "`"))) + ((` the same thing happens except the state moves from ` + ("`" + `'exiting'`)) + ("`" + (` to ` + "`"))))))))) + ((((((((`'exited'` + "`") + (`.\n *\n * ## Timing\n *\n * Timing is often the trickiest part of animation, mistakes can result in slight delays\n * that are hard to pin down. A common example is when you want to add an exit transition,\n * you should set the desired final styles when the state is ` + ("`" + `'exiting'`))) + (("`" + (`. That's when the\n * transition to those styles will start and, if you matched the ` + "`")) + (`timeout` + ("`" + ` prop with the\n * CSS Transition duration, it will end exactly when the state changes to `)))) + ((("`" + `'exited'`) + ("`" + (`.\n *\n * > **Note**: For simpler transitions the ` + "`"))) + ((`Transition` + ("`" + ` component might be enough, but\n * > take into account that it's platform-agnostic, while the `)) + ("`" + (`CSSTransition` + "`"))))) + ((((` component\n * > [forces reflows](https://github.com/reactjs/react-transition-group/blob/5007303e729a74be66a21c3e2205e4916821524b/src/CSSTransition.js#L208-L215)\n * > in order to make more complex transitions more predictable. For example, even though\n * > classes ` + "`") + (`example-enter` + ("`" + ` and `))) + (("`" + (`example-enter-active` + "`")) + (` are applied immediately one after\n * > another, you can still transition from one to the other because of the forced reflow\n * > (read [this issue](https://github.com/reactjs/react-transition-group/issues/159#issuecomment-322761171)\n * > for more info). Take this into account when choosing between ` + ("`" + `Transition`)))) + ((("`" + ` and\n * > `) + ("`" + (`CSSTransition` + "`"))) + ((`.\n */\n\nexports.EXITING = EXITING;\n\nvar Transition =\n/*#__PURE__*/\nfunction (_React$Component) {\n _inheritsLoose(Transition, _React$Component);\n\n function Transition(props, context) {\n var _this;\n\n _this = _React$Component.call(this, props, context) || this;\n var parentGroup = context.transitionGroup; // In the context of a TransitionGroup all enters are really appears\n\n var appear = parentGroup && !parentGroup.isMounting ? props.enter : props.appear;\n var initialStatus;\n _this.appearStatus = null;\n\n if (props.in) {\n if (appear) {\n initialStatus = EXITED;\n _this.appearStatus = ENTERING;\n } else {\n initialStatus = ENTERED;\n }\n } else {\n if (props.unmountOnExit || props.mountOnEnter) {\n initialStatus = UNMOUNTED;\n } else {\n initialStatus = EXITED;\n }\n }\n\n _this.state = {\n status: initialStatus\n };\n _this.nextCallback = null;\n return _this;\n }\n\n var _proto = Transition.prototype;\n\n _proto.getChildContext = function getChildContext() {\n return {\n transitionGroup: null // allows for nested Transitions\n\n };\n };\n\n Transition.getDerivedStateFromProps = function getDerivedStateFromProps(_ref, prevState) {\n var nextIn = _ref.in;\n\n if (nextIn && prevState.status === UNMOUNTED) {\n return {\n status: EXITED\n };\n }\n\n return null;\n }; // getSnapshotBeforeUpdate(prevProps) {\n // let nextStatus = null\n // if (prevProps !== this.props) {\n // const { status } = this.state\n // if (this.props.in) {\n // if (status !== ENTERING && status !== ENTERED) {\n // nextStatus = ENTERING\n // }\n // } else {\n // if (status === ENTERING || status === ENTERED) {\n // nextStatus = EXITING\n // }\n // }\n // }\n // return { nextStatus }\n // }\n\n\n _proto.componentDidMount = function componentDidMount() {\n this.updateStatus(true, this.appearStatus);\n };\n\n _proto.componentDidUpdate = function componentDidUpdate(prevProps) {\n var nextStatus = null;\n\n if (prevProps !== this.props) {\n var status = this.state.status;\n\n if (this.props.in) {\n if (status !== ENTERING && status !== ENTERED) {\n nextStatus = ENTERING;\n }\n } else {\n if (status === ENTERING || status === ENTERED) {\n nextStatus = EXITING;\n }\n }\n }\n\n this.updateStatus(false, nextStatus);\n };\n\n _proto.componentWillUnmount = function componentWillUnmount() {\n this.cancelNextCallback();\n };\n\n _proto.getTimeouts = function getTimeouts() {\n var timeout = this.props.timeout;\n var exit, enter, appear;\n exit = enter = appear = timeout;\n\n if (timeout != null && typeof timeout !== 'number') {\n exit = timeout.exit;\n enter = timeout.enter; // TODO: remove fallback for next major\n\n appear = timeout.appear !== undefined ? timeout.appear : enter;\n }\n\n return {\n exit: exit,\n enter: enter,\n appear: appear\n };\n };\n\n _proto.updateStatus = function updateStatus(mounting, nextStatus) {\n if (mounting === void 0) {\n mounting = false;\n }\n\n if (nextStatus !== null) {\n // nextStatus will always be ENTERING or EXITING.\n this.cancelNextCallback();\n\n var node = _reactDom.default.findDOMNode(this);\n\n if (nextStatus === ENTERING) {\n this.performEnter(node, mounting);\n } else {\n this.performExit(node);\n }\n } else if (this.props.unmountOnExit && this.state.status === EXITED) {\n this.setState({\n status: UNMOUNTED\n });\n }\n };\n\n _proto.performEnter = function performEnter(node, mounting) {\n var _this2 = this;\n\n var enter = this.props.enter;\n var appearing = this.context.transitionGroup ? this.context.transitionGroup.isMounting : mounting;\n var timeouts = this.getTimeouts();\n var enterTimeout = appearing ? timeouts.appear : timeouts.enter; // no enter animation skip right to ENTERED\n // if we are mounting and running this it means appear _must_ be set\n\n if (!mounting && !enter) {\n this.safeSetState({\n status: ENTERED\n }, function () {\n _this2.props.onEntered(node);\n });\n return;\n }\n\n this.props.onEnter(node, appearing);\n this.safeSetState({\n status: ENTERING\n }, function () {\n _this2.props.onEntering(node, appearing);\n\n _this2.onTransitionEnd(node, enterTimeout, function () {\n _this2.safeSetState({\n status: ENTERED\n }, function () {\n _this2.props.onEntered(node, appearing);\n });\n });\n });\n };\n\n _proto.performExit = function performExit(node) {\n var _this3 = this;\n\n var exit = this.props.exit;\n var timeouts = this.getTimeouts(); // no exit animation skip right to EXITED\n\n if (!exit) {\n this.safeSetState({\n status: EXITED\n }, function () {\n _this3.props.onExited(node);\n });\n return;\n }\n\n this.props.onExit(node);\n this.safeSetState({\n status: EXITING\n }, function () {\n _this3.props.onExiting(node);\n\n _this3.onTransitionEnd(node, timeouts.exit, function () {\n _this3.safeSetState({\n status: EXITED\n }, function () {\n _this3.props.onExited(node);\n });\n });\n });\n };\n\n _proto.cancelNextCallback = function cancelNextCallback() {\n if (this.nextCallback !== null) {\n this.nextCallback.cancel();\n this.nextCallback = null;\n }\n };\n\n _proto.safeSetState = function safeSetState(nextState, callback) {\n // This shouldn't be necessary, but there are weird race conditions with\n // setState callbacks and unmounting in testing, so always make sure that\n // we can cancel any pending setState callbacks after we unmount.\n callback = this.setNextCallback(callback);\n this.setState(nextState, callback);\n };\n\n _proto.setNextCallback = function setNextCallback(callback) {\n var _this4 = this;\n\n var active = true;\n\n this.nextCallback = function (event) {\n if (active) {\n active = false;\n _this4.nextCallback = null;\n callback(event);\n }\n };\n\n this.nextCallback.cancel = function () {\n active = false;\n };\n\n return this.nextCallback;\n };\n\n _proto.onTransitionEnd = function onTransitionEnd(node, timeout, handler) {\n this.setNextCallback(handler);\n var doesNotHaveTimeoutOrListener = timeout == null && !this.props.addEndListener;\n\n if (!node || doesNotHaveTimeoutOrListener) {\n setTimeout(this.nextCallback, 0);\n return;\n }\n\n if (this.props.addEndListener) {\n this.props.addEndListener(node, this.nextCallback);\n }\n\n if (timeout != null) {\n setTimeout(this.nextCallback, timeout);\n }\n };\n\n _proto.render = function render() {\n var status = this.state.status;\n\n if (status === UNMOUNTED) {\n return null;\n }\n\n var _this$props = this.props,\n children = _this$props.children,\n childProps = _objectWithoutPropertiesLoose(_this$props, [\"children\"]); // filter props for Transtition\n\n\n delete childProps.in;\n delete childProps.mountOnEnter;\n delete childProps.unmountOnExit;\n delete childProps.appear;\n delete childProps.enter;\n delete childProps.exit;\n delete childProps.timeout;\n delete childProps.addEndListener;\n delete childProps.onEnter;\n delete childProps.onEntering;\n delete childProps.onEntered;\n delete childProps.onExit;\n delete childProps.onExiting;\n delete childProps.onExited;\n\n if (typeof children === 'function') {\n return children(status, childProps);\n }\n\n var child = _react.default.Children.only(children);\n\n return _react.default.cloneElement(child, childProps);\n };\n\n return Transition;\n}(_react.default.Component);\n\nTransition.contextTypes = {\n transitionGroup: PropTypes.object\n};\nTransition.childContextTypes = {\n transitionGroup: function transitionGroup() {}\n};\nTransition.propTypes = process.env.NODE_ENV !== \"production\" ? {\n /**\n * A ` + ("`" + `function`)) + ("`" + (` child can be used instead of a React element.\n * This function is called with the current transition status\n * ('entering', 'entered', 'exiting', 'exited', 'unmounted'), which can be used\n * to apply context specific props to a component.\n *\n * ` + "`")))))) + ((((("`" + "`") + (`jsx\n * \n * {(status) => (\n * \n * )}\n * \n * ` + "`")) + ("`" + ("`" + `\n */\n children: PropTypes.oneOfType([PropTypes.func.isRequired, PropTypes.element.isRequired]).isRequired,\n\n /**\n * Show the component; triggers the enter or exit states\n */\n in: PropTypes.bool,\n\n /**\n * By default the child component is mounted immediately along with\n * the parent `)))) + ((("`" + `Transition`) + ("`" + (` component. If you want to \"lazy mount\" the component on the\n * first ` + "`"))) + ((`in={true}` + ("`" + ` you can set `)) + ("`" + (`mountOnEnter` + "`"))))) + ((((`. After the first enter transition the component will stay\n * mounted, even on \"exited\", unless you also specify ` + "`") + (`unmountOnExit` + ("`" + `.\n */\n mountOnEnter: PropTypes.bool,\n\n /**\n * By default the child component stays mounted after it reaches the `))) + (("`" + (`'exited'` + "`")) + (` state.\n * Set ` + ("`" + `unmountOnExit`)))) + ((("`" + ` if you'd prefer to unmount the component after it finishes exiting.\n */\n unmountOnExit: PropTypes.bool,\n\n /**\n * Normally a component is not transitioned if it is shown when the `) + ("`" + (`` + "`"))) + ((` component mounts.\n * If you want to transition on the first mount set ` + ("`" + `appear`)) + ("`" + (` to ` + "`"))))))) + ((((((`true` + "`") + (`, and the\n * component will transition in as soon as the ` + ("`" + ``))) + (("`" + (` mounts.\n *\n * > Note: there are no specific \"appear\" states. ` + "`")) + (`appear` + ("`" + ` only adds an additional `)))) + ((("`" + `enter`) + ("`" + (` transition.\n */\n appear: PropTypes.bool,\n\n /**\n * Enable or disable enter transitions.\n */\n enter: PropTypes.bool,\n\n /**\n * Enable or disable exit transitions.\n */\n exit: PropTypes.bool,\n\n /**\n * The duration of the transition, in milliseconds.\n * Required unless ` + "`"))) + ((`addEndListener` + ("`" + ` is provided\n *\n * You may specify a single timeout for all transitions like: `)) + ("`" + (`timeout={500}` + "`"))))) + ((((`,\n * or individually like:\n *\n * ` + "`") + ("`" + ("`" + `jsx\n * timeout={{\n * enter: 300,\n * exit: 500,\n * appear: 500,\n * }}\n * `))) + (("`" + ("`" + "`")) + (`\n *\n * If the value of ` + ("`" + `appear`)))) + ((("`" + ` is not set, then the value from enter is taken.\n *\n * If the `) + ("`" + (`enter` + "`"))) + ((` or ` + ("`" + `exit`)) + ("`" + (` value is ` + "`")))))) + (((((`null` + "`") + (` or ` + ("`" + `undefined`))) + (("`" + (`, then the timer is set to ` + "`")) + (`0` + ("`" + `\n *\n * @type {number | { enter?: number, exit?: number, appear?: number }}\n */\n timeout: function timeout(props) {\n var pt = process.env.NODE_ENV !== \"production\" ? _PropTypes.timeoutsShape : {};;\n if (!props.addEndListener) pt = pt.isRequired;\n\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n return pt.apply(void 0, [props].concat(args));\n },\n\n /**\n * Add a custom transition end trigger. Called with the transitioning\n * DOM node and a `)))) + ((("`" + `done`) + ("`" + (` callback. Allows for more fine grained transition end\n * logic. **Note:** Timeouts are still used as a fallback if provided.\n *\n * ` + "`"))) + (("`" + ("`" + `jsx\n * addEndListener={(node, done) => {\n * // use the css transitionend event to mark the finish of a transition\n * node.addEventListener('transitionend', done, false);\n * }}\n * `)) + ("`" + ("`" + "`"))))) + ((((`\n */\n addEndListener: PropTypes.func,\n\n /**\n * Callback fired before the \"entering\" status is applied. An extra parameter\n * ` + "`") + (`isAppearing` + ("`" + ` is supplied to indicate if the enter stage is occurring on the initial mount\n *\n * @type Function(node: HtmlElement, isAppearing: bool) -> void\n */\n onEnter: PropTypes.func,\n\n /**\n * Callback fired after the \"entering\" status is applied. An extra parameter\n * `))) + (("`" + (`isAppearing` + "`")) + (` is supplied to indicate if the enter stage is occurring on the initial mount\n *\n * @type Function(node: HtmlElement, isAppearing: bool)\n */\n onEntering: PropTypes.func,\n\n /**\n * Callback fired after the \"entered\" status is applied. An extra parameter\n * ` + ("`" + `isAppearing`)))) + ((("`" + (` is supplied to indicate if the enter stage is occurring on the initial mount\n *\n * @type Function(node: HtmlElement, isAppearing: bool) -> void\n */\n onEntered: PropTypes.func,\n\n /**\n * Callback fired before the \"exiting\" status is applied.\n *\n * @type Function(node: HtmlElement) -> void\n */\n onExit: PropTypes.func,\n\n /**\n * Callback fired after the \"exiting\" status is applied.\n *\n * @type Function(node: HtmlElement) -> void\n */\n onExiting: PropTypes.func,\n\n /**\n * Callback fired after the \"exited\" status is applied.\n *\n * @type Function(node: HtmlElement) -> void\n */\n onExited: PropTypes.func // Name the function so it is clearer in the documentation\n\n} : {};\n\nfunction noop() {}\n\nTransition.defaultProps = {\n in: false,\n mountOnEnter: false,\n unmountOnExit: false,\n appear: false,\n enter: true,\n exit: true,\n onEnter: noop,\n onEntering: noop,\n onEntered: noop,\n onExit: noop,\n onExiting: noop,\n onExited: noop\n};\nTransition.UNMOUNTED = 0;\nTransition.EXITED = 1;\nTransition.ENTERING = 2;\nTransition.ENTERED = 3;\nTransition.EXITING = 4;\n\nvar _default = (0, _reactLifecyclesCompat.polyfill)(Transition);\n\nexports.default = _default;", + "\"use strict\";\n\nexports.__esModule = true;\nexports.default = void 0;\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _reactLifecyclesCompat = require(\"react-lifecycles-compat\");\n\nvar _ChildMapping = require(\"./utils/ChildMapping\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nvar values = Object.values || function (obj) {\n return Object.keys(obj).map(function (k) {\n return obj[k];\n });\n};\n\nvar defaultProps = {\n component: 'div',\n childFactory: function childFactory(child) {\n return child;\n }\n /**\n * The ` + "`")) + (`` + ("`" + ` component manages a set of transition components\n * (`))) + (("`" + (`` + "`")) + (` and ` + ("`" + ``)))))))) + ((((((("`" + `) in a list. Like with the transition\n * components, `) + ("`" + (`` + "`"))) + ((` is a state machine for managing the mounting\n * and unmounting of components over time.\n *\n * Consider the example below. As items are removed or added to the TodoList the\n * ` + ("`" + `in`)) + ("`" + (` prop is toggled automatically by the ` + "`")))) + (((`` + "`") + (`.\n *\n * Note that ` + ("`" + ``))) + (("`" + (` does not define any animation behavior!\n * Exactly _how_ a list item animates is up to the individual transition\n * component. This means you can mix and match animations across different list\n * items.\n */\n\n};\n\nvar TransitionGroup =\n/*#__PURE__*/\nfunction (_React$Component) {\n _inheritsLoose(TransitionGroup, _React$Component);\n\n function TransitionGroup(props, context) {\n var _this;\n\n _this = _React$Component.call(this, props, context) || this;\n\n var handleExited = _this.handleExited.bind(_assertThisInitialized(_assertThisInitialized(_this))); // Initial children should all be entering, dependent on appear\n\n\n _this.state = {\n handleExited: handleExited,\n firstRender: true\n };\n return _this;\n }\n\n var _proto = TransitionGroup.prototype;\n\n _proto.getChildContext = function getChildContext() {\n return {\n transitionGroup: {\n isMounting: !this.appeared\n }\n };\n };\n\n _proto.componentDidMount = function componentDidMount() {\n this.appeared = true;\n this.mounted = true;\n };\n\n _proto.componentWillUnmount = function componentWillUnmount() {\n this.mounted = false;\n };\n\n TransitionGroup.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, _ref) {\n var prevChildMapping = _ref.children,\n handleExited = _ref.handleExited,\n firstRender = _ref.firstRender;\n return {\n children: firstRender ? (0, _ChildMapping.getInitialChildMapping)(nextProps, handleExited) : (0, _ChildMapping.getNextChildMapping)(nextProps, prevChildMapping, handleExited),\n firstRender: false\n };\n };\n\n _proto.handleExited = function handleExited(child, node) {\n var currentChildMapping = (0, _ChildMapping.getChildMapping)(this.props.children);\n if (child.key in currentChildMapping) return;\n\n if (child.props.onExited) {\n child.props.onExited(node);\n }\n\n if (this.mounted) {\n this.setState(function (state) {\n var children = _extends({}, state.children);\n\n delete children[child.key];\n return {\n children: children\n };\n });\n }\n };\n\n _proto.render = function render() {\n var _this$props = this.props,\n Component = _this$props.component,\n childFactory = _this$props.childFactory,\n props = _objectWithoutPropertiesLoose(_this$props, [\"component\", \"childFactory\"]);\n\n var children = values(this.state.children).map(childFactory);\n delete props.appear;\n delete props.enter;\n delete props.exit;\n\n if (Component === null) {\n return children;\n }\n\n return _react.default.createElement(Component, props, children);\n };\n\n return TransitionGroup;\n}(_react.default.Component);\n\nTransitionGroup.childContextTypes = {\n transitionGroup: _propTypes.default.object.isRequired\n};\nTransitionGroup.propTypes = process.env.NODE_ENV !== \"production\" ? {\n /**\n * ` + "`")) + (`` + ("`" + ` renders a `))))) + (((("`" + `
`) + ("`" + (` by default. You can change this\n * behavior by providing a ` + "`"))) + ((`component` + ("`" + ` prop.\n * If you use React v16+ and would like to avoid a wrapping `)) + ("`" + (`
` + "`")))) + (((` element\n * you can pass in ` + "`") + (`component={null}` + ("`" + `. This is useful if the wrapping div\n * borks your css styles.\n */\n component: _propTypes.default.any,\n\n /**\n * A set of `))) + (("`" + (`` + "`")) + (` components, that are toggled ` + ("`" + `in`)))))) + ((((("`" + ` and out as they\n * leave. the `) + ("`" + (`` + "`"))) + ((` will inject specific transition props, so\n * remember to spread them through if you are wrapping the ` + ("`" + ``)) + ("`" + (` as\n * with our ` + "`")))) + (((`` + "`") + (` example.\n *\n * While this component is meant to make it easier to animate multiple\n * ` + ("`" + `Transition`))) + (("`" + (` or ` + "`")) + (`CSSTransition` + ("`" + ` children, sometimes you want to transition a\n * single child by changing its content, e.g. routes, slides, images in a\n * carousel etc. In that case you can change the `))))) + (((("`" + `key`) + ("`" + (` prop of the child\n * component along with its content, that way ` + "`"))) + ((`TransitionGroup` + ("`" + ` will know that\n * it should transition the child.\n */\n children: _propTypes.default.node,\n\n /**\n * A convenience prop that enables or disables appear animations\n * for all children. Note that specifying this will override any defaults set\n * on individual children Transitions.\n */\n appear: _propTypes.default.bool,\n\n /**\n * A convenience prop that enables or disables enter animations\n * for all children. Note that specifying this will override any defaults set\n * on individual children Transitions.\n */\n enter: _propTypes.default.bool,\n\n /**\n * A convenience prop that enables or disables exit animations\n * for all children. Note that specifying this will override any defaults set\n * on individual children Transitions.\n */\n exit: _propTypes.default.bool,\n\n /**\n * You may need to apply reactive updates to a child as it is exiting.\n * This is generally done by using `)) + ("`" + (`cloneElement` + "`")))) + (((` however in the case of an exiting\n * child the element has already been removed and not accessible to the consumer.\n *\n * If you do need to update a child as it leaves you can provide a ` + ("`" + `childFactory`)) + ("`" + (`\n * to wrap every child, even the ones that are leaving.\n *\n * @type Function(child: ReactElement) -> ReactElement\n */\n childFactory: _propTypes.default.func\n} : {};\nTransitionGroup.defaultProps = defaultProps;\n\nvar _default = (0, _reactLifecyclesCompat.polyfill)(TransitionGroup);\n\nexports.default = _default;\nmodule.exports = exports[\"default\"];", + "\"use strict\";\n\nvar _CSSTransition = _interopRequireDefault(require(\"./CSSTransition\"));\n\nvar _ReplaceTransition = _interopRequireDefault(require(\"./ReplaceTransition\"));\n\nvar _TransitionGroup = _interopRequireDefault(require(\"./TransitionGroup\"));\n\nvar _Transition = _interopRequireDefault(require(\"./Transition\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nmodule.exports = {\n Transition: _Transition.default,\n TransitionGroup: _TransitionGroup.default,\n ReplaceTransition: _ReplaceTransition.default,\n CSSTransition: _CSSTransition.default\n};", + "\"use strict\";\n\nexports.__esModule = true;\nexports.getChildMapping = getChildMapping;\nexports.mergeChildMappings = mergeChildMappings;\nexports.getInitialChildMapping = getInitialChildMapping;\nexports.getNextChildMapping = getNextChildMapping;\n\nvar _react = require(\"react\");\n\n/**\n * Given ` + "`"))) + ((`this.props.children` + ("`" + `, return an object mapping key to child.\n *\n * @param {*} children `)) + ("`" + (`this.props.children` + "`"))))))) + ((((((`\n * @return {object} Mapping of key to child\n */\nfunction getChildMapping(children, mapFn) {\n var mapper = function mapper(child) {\n return mapFn && (0, _react.isValidElement)(child) ? mapFn(child) : child;\n };\n\n var result = Object.create(null);\n if (children) _react.Children.map(children, function (c) {\n return c;\n }).forEach(function (child) {\n // run the map function here instead so that the key is the computed one\n result[child.key] = mapper(child);\n });\n return result;\n}\n/**\n * When you're adding or removing children some may be added or removed in the\n * same render pass. We want to show *both* since we want to simultaneously\n * animate elements in and out. This function takes a previous set of keys\n * and a new set of keys and merges them with its best guess of the correct\n * ordering. In the future we may expose some of the utilities in\n * ReactMultiChild to make this easy, but for now React itself does not\n * directly have this concept of the union of prevChildren and nextChildren\n * so we implement it here.\n *\n * @param {object} prev prev children as returned from\n * ` + "`") + (`ReactTransitionChildMapping.getChildMapping()` + ("`" + `.\n * @param {object} next next children as returned from\n * `))) + (("`" + (`ReactTransitionChildMapping.getChildMapping()` + "`")) + (`.\n * @return {object} a key set that contains all keys in ` + ("`" + `prev`)))) + ((("`" + ` and all keys\n * in `) + ("`" + (`next` + "`"))) + ((` in a reasonable order.\n */\n\n\nfunction mergeChildMappings(prev, next) {\n prev = prev || {};\n next = next || {};\n\n function getValueForKey(key) {\n return key in next ? next[key] : prev[key];\n } // For each key of ` + ("`" + `next`)) + ("`" + (`, the list of keys to insert before that key in\n // the combined list\n\n\n var nextKeysPending = Object.create(null);\n var pendingKeys = [];\n\n for (var prevKey in prev) {\n if (prevKey in next) {\n if (pendingKeys.length) {\n nextKeysPending[prevKey] = pendingKeys;\n pendingKeys = [];\n }\n } else {\n pendingKeys.push(prevKey);\n }\n }\n\n var i;\n var childMapping = {};\n\n for (var nextKey in next) {\n if (nextKeysPending[nextKey]) {\n for (i = 0; i < nextKeysPending[nextKey].length; i++) {\n var pendingNextKey = nextKeysPending[nextKey][i];\n childMapping[nextKeysPending[nextKey][i]] = getValueForKey(pendingNextKey);\n }\n }\n\n childMapping[nextKey] = getValueForKey(nextKey);\n } // Finally, add the keys which didn't appear before any key in ` + "`"))))) + ((((`next` + "`") + (`\n\n\n for (i = 0; i < pendingKeys.length; i++) {\n childMapping[pendingKeys[i]] = getValueForKey(pendingKeys[i]);\n }\n\n return childMapping;\n}\n\nfunction getProp(child, prop, props) {\n return props[prop] != null ? props[prop] : child.props[prop];\n}\n\nfunction getInitialChildMapping(props, onExited) {\n return getChildMapping(props.children, function (child) {\n return (0, _react.cloneElement)(child, {\n onExited: onExited.bind(null, child),\n in: true,\n appear: getProp(child, 'appear', props),\n enter: getProp(child, 'enter', props),\n exit: getProp(child, 'exit', props)\n });\n });\n}\n\nfunction getNextChildMapping(nextProps, prevChildMapping, onExited) {\n var nextChildMapping = getChildMapping(nextProps.children);\n var children = mergeChildMappings(prevChildMapping, nextChildMapping);\n Object.keys(children).forEach(function (key) {\n var child = children[key];\n if (!(0, _react.isValidElement)(child)) return;\n var hasPrev = key in prevChildMapping;\n var hasNext = key in nextChildMapping;\n var prevChild = prevChildMapping[key];\n var isLeaving = (0, _react.isValidElement)(prevChild) && !prevChild.props.in; // item is new (entering)\n\n if (hasNext && (!hasPrev || isLeaving)) {\n // console.log('entering', key)\n children[key] = (0, _react.cloneElement)(child, {\n onExited: onExited.bind(null, child),\n in: true,\n exit: getProp(child, 'exit', nextProps),\n enter: getProp(child, 'enter', nextProps)\n });\n } else if (!hasNext && hasPrev && !isLeaving) {\n // item is old (exiting)\n // console.log('leaving', key)\n children[key] = (0, _react.cloneElement)(child, {\n in: false\n });\n } else if (hasNext && hasPrev && (0, _react.isValidElement)(prevChild)) {\n // item hasn't changed transition states\n // copy over the last transition props;\n // console.log('unchanged', key)\n children[key] = (0, _react.cloneElement)(child, {\n onExited: onExited.bind(null, child),\n in: prevChild.props.in,\n exit: getProp(child, 'exit', nextProps),\n enter: getProp(child, 'enter', nextProps)\n });\n }\n });\n return children;\n}", + "\"use strict\";\n\nexports.__esModule = true;\nexports.classNamesShape = exports.timeoutsShape = void 0;\n\nvar _propTypes = _interopRequireDefault(require(\"prop-types\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar timeoutsShape = process.env.NODE_ENV !== 'production' ? _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.shape({\n enter: _propTypes.default.number,\n exit: _propTypes.default.number,\n appear: _propTypes.default.number\n}).isRequired]) : null;\nexports.timeoutsShape = timeoutsShape;\nvar classNamesShape = process.env.NODE_ENV !== 'production' ? _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.shape({\n enter: _propTypes.default.string,\n exit: _propTypes.default.string,\n active: _propTypes.default.string\n}), _propTypes.default.shape({\n enter: _propTypes.default.string,\n enterDone: _propTypes.default.string,\n enterActive: _propTypes.default.string,\n exit: _propTypes.default.string,\n exitDone: _propTypes.default.string,\n exitActive: _propTypes.default.string\n})]) : null;\nexports.classNamesShape = classNamesShape;", + "/** @license React v16.8.4\n * react.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';var k=require(\"object-assign\"),n=\"function\"===typeof Symbol&&Symbol.for,p=n?Symbol.for(\"react.element\"):60103,q=n?Symbol.for(\"react.portal\"):60106,r=n?Symbol.for(\"react.fragment\"):60107,t=n?Symbol.for(\"react.strict_mode\"):60108,u=n?Symbol.for(\"react.profiler\"):60114,v=n?Symbol.for(\"react.provider\"):60109,w=n?Symbol.for(\"react.context\"):60110,x=n?Symbol.for(\"react.concurrent_mode\"):60111,y=n?Symbol.for(\"react.forward_ref\"):60112,z=n?Symbol.for(\"react.suspense\"):60113,aa=n?Symbol.for(\"react.memo\"):\n60115,ba=n?Symbol.for(\"react.lazy\"):60116,A=\"function\"===typeof Symbol&&Symbol.iterator;function ca(a,b,d,c,e,g,h,f){if(!a){a=void 0;if(void 0===b)a=Error(\"Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.\");else{var l=[d,c,e,g,h,f],m=0;a=Error(b.replace(/%s/g,function(){return l[m++]}));a.name=\"Invariant Violation\"}a.framesToPop=1;throw a;}}\nfunction B(a){for(var b=arguments.length-1,d=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+a,c=0;cP.length&&P.push(a)}\nfunction S(a,b,d,c){var e=typeof a;if(\"undefined\"===e||\"boolean\"===e)a=null;var g=!1;if(null===a)g=!0;else switch(e){case \"string\":case \"number\":g=!0;break;case \"object\":switch(a.$$typeof){case p:case q:g=!0}}if(g)return d(c,a,\"\"===b?\".\"+T(a,0):b),1;g=0;b=\"\"===b?\".\":b+\":\";if(Array.isArray(a))for(var h=0;h max) {\n validMin = max;\n validMax = min;\n }\n\n return [validMin, validMax];\n}\n/**\n * Calculate the step which is easy to understand between ticks, like 10, 20, 25\n *\n * @param {Decimal} roughStep The rough step calculated by deviding the\n * difference by the tickCount\n * @param {Boolean} allowDecimals Allow the ticks to be decimals or not\n * @param {Integer} correctionFactor A correction factor\n * @return {Decimal} The step which is easy to understand between two ticks\n */\n\n\nfunction getFormatStep(roughStep, allowDecimals, correctionFactor) {\n if (roughStep.lte(0)) {\n return new _decimal.default(0);\n }\n\n var digitCount = _arithmetic.default.getDigitCount(roughStep.toNumber()); // The ratio between the rough step and the smallest number which has a bigger\n // order of magnitudes than the rough step\n\n\n var digitCountValue = new _decimal.default(10).pow(digitCount);\n var stepRatio = roughStep.div(digitCountValue); // When an integer and a float multiplied, the accuracy of result may be wrong\n\n var stepRatioScale = digitCount !== 1 ? 0.05 : 0.1;\n var amendStepRatio = new _decimal.default(Math.ceil(stepRatio.div(stepRatioScale).toNumber())).add(correctionFactor).mul(stepRatioScale);\n var formatStep = amendStepRatio.mul(digitCountValue);\n return allowDecimals ? formatStep : new _decimal.default(Math.ceil(formatStep));\n}\n/**\n * calculate the ticks when the minimum value equals to the maximum value\n *\n * @param {Number} value The minimum valuue which is also the maximum value\n * @param {Integer} tickCount The count of ticks\n * @param {Boolean} allowDecimals Allow the ticks to be decimals or not\n * @return {Array} ticks\n */\n\n\nfunction getTickOfSingleValue(value, tickCount, allowDecimals) {\n var step = 1; // calculate the middle value of ticks\n\n var middle = new _decimal.default(value);\n\n if (!middle.isint() && allowDecimals) {\n var absVal = Math.abs(value);\n\n if (absVal < 1) {\n // The step should be a float number when the difference is smaller than 1\n step = new _decimal.default(10).pow(_arithmetic.default.getDigitCount(value) - 1);\n middle = new _decimal.default(Math.floor(middle.div(step).toNumber())).mul(step);\n } else if (absVal > 1) {\n // Return the maximum integer which is smaller than 'value' when 'value' is greater than 1\n middle = new _decimal.default(Math.floor(value));\n }\n } else if (value === 0) {\n middle = new _decimal.default(Math.floor((tickCount - 1) / 2));\n } else if (!allowDecimals) {\n middle = new _decimal.default(Math.floor(value));\n }\n\n var middleIndex = Math.floor((tickCount - 1) / 2);\n var fn = (0, _utils.compose)((0, _utils.map)(function (n) {\n return middle.add(new _decimal.default(n - middleIndex).mul(step)).toNumber();\n }), _utils.range);\n return fn(0, tickCount);\n}\n/**\n * Calculate the step\n *\n * @param {Number} min The minimum value of an interval\n * @param {Number} max The maximum value of an interval\n * @param {Integer} tickCount The count of ticks\n * @param {Boolean} allowDecimals Allow the ticks to be decimals or not\n * @param {Number} correctionFactor A correction factor\n * @return {Object} The step, minimum value of ticks, maximum value of ticks\n */\n\n\nfunction calculateStep(min, max, tickCount, allowDecimals) {\n var correctionFactor = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;\n\n // dirty hack (for recharts' test)\n if (!Number.isFinite((max - min) / (tickCount - 1))) {\n return {\n step: new _decimal.default(0),\n tickMin: new _decimal.default(0),\n tickMax: new _decimal.default(0)\n };\n } // The step which is easy to understand between two ticks\n\n\n var step = getFormatStep(new _decimal.default(max).sub(min).div(tickCount - 1), allowDecimals, correctionFactor); // A medial value of ticks\n\n var middle; // When 0 is inside the interval, 0 should be a tick\n\n if (min <= 0 && max >= 0) {\n middle = new _decimal.default(0);\n } else {\n // calculate the middle value\n middle = new _decimal.default(min).add(max).div(2); // minus modulo value\n\n middle = middle.sub(new _decimal.default(middle).mod(step));\n }\n\n var belowCount = Math.ceil(middle.sub(min).div(step).toNumber());\n var upCount = Math.ceil(new _decimal.default(max).sub(middle).div(step).toNumber());\n var scaleCount = belowCount + upCount + 1;\n\n if (scaleCount > tickCount) {\n // When more ticks need to cover the interval, step should be bigger.\n return calculateStep(min, max, tickCount, allowDecimals, correctionFactor + 1);\n }\n\n if (scaleCount < tickCount) {\n // When less ticks can cover the interval, we should add some additional ticks\n upCount = max > 0 ? upCount + (tickCount - scaleCount) : upCount;\n belowCount = max > 0 ? belowCount : belowCount + (tickCount - scaleCount);\n }\n\n return {\n step: step,\n tickMin: middle.sub(new _decimal.default(belowCount).mul(step)),\n tickMax: middle.add(new _decimal.default(upCount).mul(step))\n };\n}\n/**\n * Calculate the ticks of an interval, the count of ticks will be guraranteed\n *\n * @param {Number} min, max min: The minimum value, max: The maximum value\n * @param {Integer} tickCount The count of ticks\n * @param {Boolean} allowDecimals Allow the ticks to be decimals or not\n * @return {Array} ticks\n */\n\n\nfunction getNiceTickValuesFn(_ref3) {\n var _ref4 = _slicedToArray(_ref3, 2),\n min = _ref4[0],\n max = _ref4[1];\n\n var tickCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 6;\n var allowDecimals = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n // More than two ticks should be return\n var count = Math.max(tickCount, 2);\n\n var _getValidInterval = getValidInterval([min, max]),\n _getValidInterval2 = _slicedToArray(_getValidInterval, 2),\n cormin = _getValidInterval2[0],\n cormax = _getValidInterval2[1];\n\n if (cormin === -Infinity || cormax === Infinity) {\n var _values = cormax === Infinity ? [cormin].concat(_toConsumableArray((0, _utils.range)(0, tickCount - 1).map(function () {\n return Infinity;\n }))) : _toConsumableArray((0, _utils.range)(0, tickCount - 1).map(function () {\n return -Infinity;\n })).concat([cormax]);\n\n return min > max ? (0, _utils.reverse)(_values) : _values;\n }\n\n if (cormin === cormax) {\n return getTickOfSingleValue(cormin, tickCount, allowDecimals);\n } // Get the step between two ticks\n\n\n var _calculateStep = calculateStep(cormin, cormax, count, allowDecimals),\n step = _calculateStep.step,\n tickMin = _calculateStep.tickMin,\n tickMax = _calculateStep.tickMax;\n\n var values = _arithmetic.default.rangeStep(tickMin, tickMax.add(new _decimal.default(0.1).mul(step)), step);\n\n return min > max ? (0, _utils.reverse)(values) : values;\n}\n/**\n * Calculate the ticks of an interval, the count of ticks won't be guraranteed\n *\n * @param {Number} min, max min: The minimum value, max: The maximum value\n * @param {Integer} tickCount The count of ticks\n * @param {Boolean} allowDecimals Allow the ticks to be decimals or not\n * @return {Array} ticks\n */\n\n\nfunction getTickValuesFn(_ref5) {\n var _ref6 = _slicedToArray(_ref5, 2),\n min = _ref6[0],\n max = _ref6[1];\n\n var tickCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 6;\n var allowDecimals = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n // More than two ticks should be return\n var count = Math.max(tickCount, 2);\n\n var _getValidInterval3 = getValidInterval([min, max]),\n _getValidInterval4 = _slicedToArray(_getValidInterval3, 2),\n cormin = _getValidInterval4[0],\n cormax = _getValidInterval4[1];\n\n if (cormin === -Infinity || cormax === Infinity) {\n return [min, max];\n }\n\n if (cormin === cormax) {\n return getTickOfSingleValue(cormin, tickCount, allowDecimals);\n }\n\n var step = getFormatStep(new _decimal.default(cormax).sub(cormin).div(count - 1), allowDecimals, 0);\n var fn = (0, _utils.compose)((0, _utils.map)(function (n) {\n return new _decimal.default(cormin).add(new _decimal.default(n).mul(step)).toNumber();\n }), _utils.range);\n var values = fn(0, count).filter(function (entry) {\n return entry >= cormin && entry <= cormax;\n });\n return min > max ? (0, _utils.reverse)(values) : values;\n}\n/**\n * Calculate the ticks of an interval, the count of ticks won't be guraranteed,\n * but the domain will be guaranteed\n *\n * @param {Number} min, max min: The minimum value, max: The maximum value\n * @param {Integer} tickCount The count of ticks\n * @param {Boolean} allowDecimals Allow the ticks to be decimals or not\n * @return {Array} ticks\n */\n\n\nfunction getTickValuesFixedDomainFn(_ref7, tickCount) {\n var _ref8 = _slicedToArray(_ref7, 2),\n min = _ref8[0],\n max = _ref8[1];\n\n var allowDecimals = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n // More than two ticks should be return\n var _getValidInterval5 = getValidInterval([min, max]),\n _getValidInterval6 = _slicedToArray(_getValidInterval5, 2),\n cormin = _getValidInterval6[0],\n cormax = _getValidInterval6[1];\n\n if (cormin === -Infinity || cormax === Infinity) {\n return [min, max];\n }\n\n if (cormin === cormax) {\n return [cormin];\n }\n\n var count = Math.max(tickCount, 2);\n var step = getFormatStep(new _decimal.default(cormax).sub(cormin).div(count - 1), allowDecimals, 0);\n\n var values = _toConsumableArray(_arithmetic.default.rangeStep(new _decimal.default(cormin), new _decimal.default(cormax).sub(new _decimal.default(0.99).mul(step)), step)).concat([cormax]);\n\n return min > max ? (0, _utils.reverse)(values) : values;\n}\n\nvar getNiceTickValues = (0, _utils.memoize)(getNiceTickValuesFn);\nexports.getNiceTickValues = getNiceTickValues;\nvar getTickValues = (0, _utils.memoize)(getTickValuesFn);\nexports.getTickValues = getTickValues;\nvar getTickValuesFixedDomain = (0, _utils.memoize)(getTickValuesFixedDomainFn);\nexports.getTickValuesFixedDomain = getTickValuesFixedDomain;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nObject.defineProperty(exports, \"getTickValues\", {\n enumerable: true,\n get: function get() {\n return _getNiceTickValues.getTickValues;\n }\n});\nObject.defineProperty(exports, \"getNiceTickValues\", {\n enumerable: true,\n get: function get() {\n return _getNiceTickValues.getNiceTickValues;\n }\n});\nObject.defineProperty(exports, \"getTickValuesFixedDomain\", {\n enumerable: true,\n get: function get() {\n return _getNiceTickValues.getTickValuesFixedDomain;\n }\n});\n\nvar _getNiceTickValues = require(\"./getNiceTickValues\");", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _decimal = _interopRequireDefault(require(\"decimal.js-light\"));\n\nvar _utils = require(\"./utils\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n/**\n * @fileOverview 一些公用的运算方法\n * @author xile611\n * @date 2015-09-17\n */\n\n/**\n * 获取数值的位数\n * 其中绝对值属于区间[0.1, 1), 得到的值为0\n * 绝对值属于区间[0.01, 0.1),得到的位数为 -1\n * 绝对值属于区间[0.001, 0.01),得到的位数为 -2\n *\n * @param {Number} value 数值\n * @return {Integer} 位数\n */\nfunction getDigitCount(value) {\n var result;\n\n if (value === 0) {\n result = 1;\n } else {\n result = Math.floor(new _decimal.default(value).abs().log(10).toNumber()) + 1;\n }\n\n return result;\n}\n/**\n * 按照固定的步长获取[start, end)这个区间的数据\n * 并且需要处理js计算精度的问题\n *\n * @param {Decimal} start 起点\n * @param {Decimal} end 终点,不包含该值\n * @param {Decimal} step 步长\n * @return {Array} 若干数值\n */\n\n\nfunction rangeStep(start, end, step) {\n var num = new _decimal.default(start);\n var result = [];\n\n while (num.lt(end)) {\n result.push(num.toNumber());\n num = num.add(step);\n }\n\n return result;\n}\n/**\n * 对数值进行线性插值\n *\n * @param {Number} a 定义域的极点\n * @param {Number} b 定义域的极点\n * @param {Number} t [0, 1]内的某个值\n * @return {Number} 定义域内的某个值\n */\n\n\nvar interpolateNumber = (0, _utils.curry)(function (a, b, t) {\n var newA = +a;\n var newB = +b;\n return newA + t * (newB - newA);\n});\n/**\n * 线性插值的逆运算\n *\n * @param {Number} a 定义域的极点\n * @param {Number} b 定义域的极点\n * @param {Number} x 可以认为是插值后的一个输出值\n * @return {Number} 当x在 a ~ b这个范围内时,返回值属于[0, 1]\n */\n\nvar uninterpolateNumber = (0, _utils.curry)(function (a, b, x) {\n var diff = b - +a;\n diff = diff || Infinity;\n return (x - a) / diff;\n});\n/**\n * 线性插值的逆运算,并且有截断的操作\n *\n * @param {Number} a 定义域的极点\n * @param {Number} b 定义域的极点\n * @param {Number} x 可以认为是插值后的一个输出值\n * @return {Number} 当x在 a ~ b这个区间内时,返回值属于[0, 1],\n * 当x不在 a ~ b这个区间时,会截断到 a ~ b 这个区间\n */\n\nvar uninterpolateTruncation = (0, _utils.curry)(function (a, b, x) {\n var diff = b - +a;\n diff = diff || Infinity;\n return Math.max(0, Math.min(1, (x - a) / diff));\n});\nvar _default = {\n rangeStep: rangeStep,\n getDigitCount: getDigitCount,\n interpolateNumber: interpolateNumber,\n uninterpolateNumber: uninterpolateNumber,\n uninterpolateTruncation: uninterpolateTruncation\n};\nexports.default = _default;", + "\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.memoize = exports.reverse = exports.compose = exports.map = exports.range = exports.curry = exports.PLACE_HOLDER = void 0;\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nvar identity = function identity(i) {\n return i;\n};\n\nvar PLACE_HOLDER = {\n '@@functional/placeholder': true\n};\nexports.PLACE_HOLDER = PLACE_HOLDER;\n\nvar isPlaceHolder = function isPlaceHolder(val) {\n return val === PLACE_HOLDER;\n};\n\nvar curry0 = function curry0(fn) {\n return function _curried() {\n if (arguments.length === 0 || arguments.length === 1 && isPlaceHolder(arguments.length <= 0 ? undefined : arguments[0])) {\n return _curried;\n }\n\n return fn.apply(void 0, arguments);\n };\n};\n\nvar curryN = function curryN(n, fn) {\n if (n === 1) {\n return fn;\n }\n\n return curry0(function () {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var argsLength = args.filter(function (arg) {\n return arg !== PLACE_HOLDER;\n }).length;\n\n if (argsLength >= n) {\n return fn.apply(void 0, args);\n }\n\n return curryN(n - argsLength, curry0(function () {\n for (var _len2 = arguments.length, restArgs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n restArgs[_key2] = arguments[_key2];\n }\n\n var newArgs = args.map(function (arg) {\n return isPlaceHolder(arg) ? restArgs.shift() : arg;\n });\n return fn.apply(void 0, _toConsumableArray(newArgs).concat(restArgs));\n }));\n });\n};\n\nvar curry = function curry(fn) {\n return curryN(fn.length, fn);\n};\n\nexports.curry = curry;\n\nvar range = function range(begin, end) {\n var arr = [];\n\n for (var i = begin; i < end; ++i) {\n arr[i - begin] = i;\n }\n\n return arr;\n};\n\nexports.range = range;\nvar map = curry(function (fn, arr) {\n if (Array.isArray(arr)) {\n return arr.map(fn);\n }\n\n return Object.keys(arr).map(function (key) {\n return arr[key];\n }).map(fn);\n});\nexports.map = map;\n\nvar compose = function compose() {\n for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n args[_key3] = arguments[_key3];\n }\n\n if (!args.length) {\n return identity;\n }\n\n var fns = args.reverse(); // first function can receive multiply arguments\n\n var firstFn = fns[0];\n var tailsFn = fns.slice(1);\n return function () {\n return tailsFn.reduce(function (res, fn) {\n return fn(res);\n }, firstFn.apply(void 0, arguments));\n };\n};\n\nexports.compose = compose;\n\nvar reverse = function reverse(arr) {\n if (Array.isArray(arr)) {\n return arr.reverse();\n } // can be string\n\n\n return arr.split('').reverse.join('');\n};\n\nexports.reverse = reverse;\n\nvar memoize = function memoize(fn) {\n var lastArgs = null;\n var lastResult = null;\n return function () {\n for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {\n args[_key4] = arguments[_key4];\n }\n\n if (lastArgs && args.every(function (val, i) {\n return val === lastArgs[i];\n })) {\n return lastResult;\n }\n\n lastArgs = args;\n lastResult = fn.apply(void 0, args);\n return lastResult;\n };\n};\n\nexports.memoize = memoize;", + "import _isEqual from \"lodash/isEqual\";\nimport _isNaN from \"lodash/isNaN\";\nimport _isFunction from \"lodash/isFunction\";\nimport _get from \"lodash/get\";\nimport _isNil from \"lodash/isNil\";\nimport _isArray from \"lodash/isArray\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Area\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Animate from 'react-smooth';\nimport Curve from '../shape/Curve';\nimport Dot from '../shape/Dot';\nimport Layer from '../container/Layer';\nimport LabelList from '../component/LabelList';\nimport pureRender from '../util/PureRender';\nimport { PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, LEGEND_TYPES, getPresentationAttributes, isSsr, filterEventAttributes } from '../util/ReactUtils';\nimport { isNumber, uniqueId, interpolateNumber } from '../util/DataUtils';\nimport { getCateCoordinateOfLine, getValueByDataKey } from '../util/ChartUtils';\n\nvar Area = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Area, _Component);\n\n function Area() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, Area);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Area)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n isAnimationFinished: true\n };\n _this.id = uniqueId('recharts-area-');\n\n _this.cachePrevData = function (points, baseLine) {\n _this.setState({\n prevPoints: points,\n prevBaseLine: baseLine\n });\n };\n\n _this.handleAnimationEnd = function () {\n var onAnimationEnd = _this.props.onAnimationEnd;\n\n _this.setState({\n isAnimationFinished: true\n });\n\n if (_isFunction(onAnimationEnd)) {\n onAnimationEnd();\n }\n };\n\n _this.handleAnimationStart = function () {\n var onAnimationStart = _this.props.onAnimationStart;\n\n _this.setState({\n isAnimationFinished: false\n });\n\n if (_isFunction(onAnimationStart)) {\n onAnimationStart();\n }\n };\n\n return _this;\n }\n\n _createClass(Area, [{\n key: \"componentWillReceiveProps\",\n value: function componentWillReceiveProps(nextProps) {\n var _this$props = this.props,\n animationId = _this$props.animationId,\n points = _this$props.points,\n baseLine = _this$props.baseLine;\n\n if (nextProps.animationId !== animationId) {\n this.cachePrevData(points, baseLine);\n }\n }\n }, {\n key: \"renderDots\",\n value: function renderDots(needClip, clipPathId) {\n var _this2 = this;\n\n var isAnimationActive = this.props.isAnimationActive;\n var isAnimationFinished = this.state.isAnimationFinished;\n\n if (isAnimationActive && !isAnimationFinished) {\n return null;\n }\n\n var _this$props2 = this.props,\n dot = _this$props2.dot,\n points = _this$props2.points,\n dataKey = _this$props2.dataKey;\n var areaProps = getPresentationAttributes(this.props);\n var customDotProps = getPresentationAttributes(dot);\n var dotEvents = filterEventAttributes(dot);\n var dots = points.map(function (entry, i) {\n var dotProps = _objectSpread({\n key: \"dot-\".concat(i),\n r: 3\n }, areaProps, customDotProps, dotEvents, {\n dataKey: dataKey,\n cx: entry.x,\n cy: entry.y,\n index: i,\n value: entry.value,\n payload: entry.payload\n });\n\n return _this2.constructor.renderDotItem(dot, dotProps);\n });\n var dotsProps = {\n clipPath: needClip ? \"url(#clipPath-\".concat(clipPathId, \")\") : null\n };\n return React.createElement(Layer, _extends({\n className: \"recharts-area-dots\"\n }, dotsProps), dots);\n }\n }, {\n key: \"renderHorizontalRect\",\n value: function renderHorizontalRect(alpha) {\n var _this$props3 = this.props,\n baseLine = _this$props3.baseLine,\n points = _this$props3.points,\n strokeWidth = _this$props3.strokeWidth;\n var startX = points[0].x;\n var endX = points[points.length - 1].x;\n var width = alpha * Math.abs(startX - endX);\n var maxY = Math.max.apply(null, points.map(function (entry) {\n return entry.y || 0;\n }));\n\n if (isNumber(baseLine)) {\n maxY = Math.max(baseLine, maxY);\n } else if (baseLine && _isArray(baseLine) && baseLine.length) {\n maxY = Math.max(Math.max.apply(null, baseLine.map(function (entry) {\n return entry.y || 0;\n })), maxY);\n }\n\n if (isNumber(maxY)) {\n return React.createElement(\"rect\", {\n x: startX < endX ? startX : startX - width,\n y: 0,\n width: width,\n height: parseInt(maxY + (strokeWidth || 1), 10)\n });\n }\n\n return null;\n }\n }, {\n key: \"renderVerticalRect\",\n value: function renderVerticalRect(alpha) {\n var _this$props4 = this.props,\n baseLine = _this$props4.baseLine,\n points = _this$props4.points,\n strokeWidth = _this$props4.strokeWidth;\n var startY = points[0].y;\n var endY = points[points.length - 1].y;\n var height = alpha * Math.abs(startY - endY);\n var maxX = Math.max.apply(null, points.map(function (entry) {\n return entry.x || 0;\n }));\n\n if (isNumber(baseLine)) {\n maxX = Math.max(baseLine, maxX);\n } else if (baseLine && _isArray(baseLine) && baseLine.length) {\n maxX = Math.max(Math.max.apply(null, baseLine.map(function (entry) {\n return entry.x || 0;\n })), maxX);\n }\n\n if (isNumber(maxX)) {\n return React.createElement(\"rect\", {\n x: 0,\n y: startY < endY ? startY : startY - height,\n width: maxX + (strokeWidth || 1),\n height: parseInt(height, 10)\n });\n }\n\n return null;\n }\n }, {\n key: \"renderClipRect\",\n value: function renderClipRect(alpha) {\n var layout = this.props.layout;\n\n if (layout === 'vertical') {\n return this.renderVerticalRect(alpha);\n }\n\n return this.renderHorizontalRect(alpha);\n }\n }, {\n key: \"renderAreaStatically\",\n value: function renderAreaStatically(points, baseLine, needClip, clipPathId) {\n var _this$props5 = this.props,\n layout = _this$props5.layout,\n type = _this$props5.type,\n stroke = _this$props5.stroke,\n connectNulls = _this$props5.connectNulls,\n isRange = _this$props5.isRange;\n return React.createElement(Layer, {\n clipPath: needClip ? \"url(#clipPath-\".concat(clipPathId, \")\") : null\n }, React.createElement(Curve, _extends({}, this.props, {\n points: points,\n baseLine: baseLine,\n stroke: \"none\",\n className: \"recharts-area-area\"\n })), stroke !== 'none' && React.createElement(Curve, _extends({}, getPresentationAttributes(this.props), {\n className: \"recharts-area-curve\",\n layout: layout,\n type: type,\n connectNulls: connectNulls,\n fill: \"none\",\n points: points\n })), stroke !== 'none' && isRange && React.createElement(Curve, _extends({}, getPresentationAttributes(this.props), {\n className: \"recharts-area-curve\",\n layout: layout,\n type: type,\n connectNulls: connectNulls,\n fill: \"none\",\n points: baseLine\n })));\n }\n }, {\n key: \"renderAreaWithAnimation\",\n value: function renderAreaWithAnimation(needClip, clipPathId) {\n var _this3 = this;\n\n var _this$props6 = this.props,\n points = _this$props6.points,\n baseLine = _this$props6.baseLine,\n isAnimationActive = _this$props6.isAnimationActive,\n animationBegin = _this$props6.animationBegin,\n animationDuration = _this$props6.animationDuration,\n animationEasing = _this$props6.animationEasing,\n animationId = _this$props6.animationId;\n var _this$state = this.state,\n prevPoints = _this$state.prevPoints,\n prevBaseLine = _this$state.prevBaseLine; // const clipPathId = _.isNil(id) ? this.id : id;\n\n return React.createElement(Animate, {\n begin: animationBegin,\n duration: animationDuration,\n isActive: isAnimationActive,\n easing: animationEasing,\n from: {\n t: 0\n },\n to: {\n t: 1\n },\n key: \"area-\".concat(animationId),\n onAnimationEnd: this.handleAnimationEnd,\n onAnimationStart: this.handleAnimationStart\n }, function (_ref) {\n var t = _ref.t;\n\n if (prevPoints) {\n var prevPointsDiffFactor = prevPoints.length / points.length; // update animtaion\n\n var stepPoints = points.map(function (entry, index) {\n var prevPointIndex = Math.floor(index * prevPointsDiffFactor);\n\n if (prevPoints[prevPointIndex]) {\n var prev = prevPoints[prevPointIndex];\n var interpolatorX = interpolateNumber(prev.x, entry.x);\n var interpolatorY = interpolateNumber(prev.y, entry.y);\n return _objectSpread({}, entry, {\n x: interpolatorX(t),\n y: interpolatorY(t)\n });\n }\n\n return entry;\n });\n var stepBaseLine;\n\n if (isNumber(baseLine)) {\n var interpolator = interpolateNumber(prevBaseLine, baseLine);\n stepBaseLine = interpolator(t);\n } else if (_isNil(baseLine) || _isNaN(baseLine)) {\n var _interpolator = interpolateNumber(prevBaseLine, 0);\n\n stepBaseLine = _interpolator(t);\n } else {\n stepBaseLine = baseLine.map(function (entry, index) {\n var prevPointIndex = Math.floor(index * prevPointsDiffFactor);\n\n if (prevBaseLine[prevPointIndex]) {\n var prev = prevBaseLine[prevPointIndex];\n var interpolatorX = interpolateNumber(prev.x, entry.x);\n var interpolatorY = interpolateNumber(prev.y, entry.y);\n return _objectSpread({}, entry, {\n x: interpolatorX(t),\n y: interpolatorY(t)\n });\n }\n\n return entry;\n });\n }\n\n return _this3.renderAreaStatically(stepPoints, stepBaseLine, needClip, clipPathId);\n }\n\n return React.createElement(Layer, null, React.createElement(\"defs\", null, React.createElement(\"clipPath\", {\n id: \"animationClipPath-\".concat(clipPathId)\n }, _this3.renderClipRect(t))), React.createElement(Layer, {\n clipPath: \"url(#animationClipPath-\".concat(clipPathId, \")\")\n }, _this3.renderAreaStatically(points, baseLine, needClip, clipPathId)));\n });\n }\n }, {\n key: \"renderArea\",\n value: function renderArea(needClip, clipPathId) {\n var _this$props7 = this.props,\n points = _this$props7.points,\n baseLine = _this$props7.baseLine,\n isAnimationActive = _this$props7.isAnimationActive;\n var _this$state2 = this.state,\n prevPoints = _this$state2.prevPoints,\n prevBaseLine = _this$state2.prevBaseLine,\n totalLength = _this$state2.totalLength;\n\n if (isAnimationActive && points && points.length && (!prevPoints && totalLength > 0 || !_isEqual(prevPoints, points) || !_isEqual(prevBaseLine, baseLine))) {\n return this.renderAreaWithAnimation(needClip, clipPathId);\n }\n\n return this.renderAreaStatically(points, baseLine, needClip, clipPathId);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props8 = this.props,\n hide = _this$props8.hide,\n dot = _this$props8.dot,\n points = _this$props8.points,\n className = _this$props8.className,\n top = _this$props8.top,\n left = _this$props8.left,\n xAxis = _this$props8.xAxis,\n yAxis = _this$props8.yAxis,\n width = _this$props8.width,\n height = _this$props8.height,\n isAnimationActive = _this$props8.isAnimationActive,\n id = _this$props8.id;\n\n if (hide || !points || !points.length) {\n return null;\n }\n\n var isAnimationFinished = this.state.isAnimationFinished;\n var hasSinglePoint = points.length === 1;\n var layerClass = classNames('recharts-area', className);\n var needClip = xAxis && xAxis.allowDataOverflow || yAxis && yAxis.allowDataOverflow;\n var clipPathId = _isNil(id) ? this.id : id;\n return React.createElement(Layer, {\n className: layerClass\n }, needClip ? React.createElement(\"defs\", null, React.createElement(\"clipPath\", {\n id: \"clipPath-\".concat(clipPathId)\n }, React.createElement(\"rect\", {\n x: left,\n y: top,\n width: width,\n height: parseInt(height, 10)\n }))) : null, !hasSinglePoint ? this.renderArea(needClip, clipPathId) : null, (dot || hasSinglePoint) && this.renderDots(needClip, clipPathId), (!isAnimationActive || isAnimationFinished) && LabelList.renderCallByParent(this.props, points));\n }\n }]);\n\n return Area;\n}(Component), _class2.displayName = 'Area', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, {\n className: PropTypes.string,\n dataKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]).isRequired,\n type: PropTypes.oneOfType([PropTypes.oneOf(['basis', 'basisClosed', 'basisOpen', 'linear', 'linearClosed', 'natural', 'monotoneX', 'monotoneY', 'monotone', 'step', 'stepBefore', 'stepAfter']), PropTypes.func]),\n unit: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n yAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n xAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n yAxis: PropTypes.object,\n xAxis: PropTypes.object,\n stackId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n legendType: PropTypes.oneOf(LEGEND_TYPES),\n connectNulls: PropTypes.bool,\n activeDot: PropTypes.oneOfType([PropTypes.object, PropTypes.element, PropTypes.func, PropTypes.bool]),\n // dot configuration\n dot: PropTypes.oneOfType([PropTypes.func, PropTypes.element, PropTypes.object, PropTypes.bool]),\n label: PropTypes.oneOfType([PropTypes.func, PropTypes.element, PropTypes.object, PropTypes.bool]),\n hide: PropTypes.bool,\n // have curve configuration\n layout: PropTypes.oneOf(['horizontal', 'vertical']),\n baseLine: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),\n isRange: PropTypes.bool,\n points: PropTypes.arrayOf(PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n value: PropTypes.oneOfType([PropTypes.number, PropTypes.array])\n })),\n onAnimationStart: PropTypes.func,\n onAnimationEnd: PropTypes.func,\n animationId: PropTypes.number,\n isAnimationActive: PropTypes.bool,\n animationBegin: PropTypes.number,\n animationDuration: PropTypes.number,\n animationEasing: PropTypes.oneOf(['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear']),\n id: PropTypes.string\n}), _class2.defaultProps = {\n stroke: '#3182bd',\n fill: '#3182bd',\n fillOpacity: 0.6,\n xAxisId: 0,\n yAxisId: 0,\n legendType: 'line',\n connectNulls: false,\n // points of area\n points: [],\n dot: false,\n activeDot: true,\n hide: false,\n isAnimationActive: !isSsr(),\n animationBegin: 0,\n animationDuration: 1500,\n animationEasing: 'ease'\n}, _class2.getBaseValue = function (props, xAxis, yAxis) {\n var layout = props.layout,\n baseValue = props.baseValue;\n\n if (isNumber(baseValue)) {\n return baseValue;\n }\n\n var numericAxis = layout === 'horizontal' ? yAxis : xAxis;\n var domain = numericAxis.scale.domain();\n\n if (numericAxis.type === 'number') {\n var max = Math.max(domain[0], domain[1]);\n var min = Math.min(domain[0], domain[1]);\n\n if (baseValue === 'dataMin') {\n return min;\n }\n\n if (baseValue === 'dataMax') {\n return max;\n }\n\n return max < 0 ? max : Math.max(Math.min(domain[0], domain[1]), 0);\n }\n\n if (baseValue === 'dataMin') {\n return domain[0];\n }\n\n if (baseValue === 'dataMax') {\n return domain[1];\n }\n\n return domain[0];\n}, _class2.getComposedData = function (_ref2) {\n var props = _ref2.props,\n xAxis = _ref2.xAxis,\n yAxis = _ref2.yAxis,\n xAxisTicks = _ref2.xAxisTicks,\n yAxisTicks = _ref2.yAxisTicks,\n bandSize = _ref2.bandSize,\n dataKey = _ref2.dataKey,\n stackedData = _ref2.stackedData,\n dataStartIndex = _ref2.dataStartIndex,\n displayedData = _ref2.displayedData,\n offset = _ref2.offset;\n var layout = props.layout;\n var hasStack = stackedData && stackedData.length;\n var baseValue = Area.getBaseValue(props, xAxis, yAxis);\n var isRange = false;\n var points = displayedData.map(function (entry, index) {\n var value;\n\n if (hasStack) {\n value = stackedData[dataStartIndex + index];\n } else {\n value = getValueByDataKey(entry, dataKey);\n\n if (!_isArray(value)) {\n value = [baseValue, value];\n } else {\n isRange = true;\n }\n }\n\n if (layout === 'horizontal') {\n return {\n x: getCateCoordinateOfLine({\n axis: xAxis,\n ticks: xAxisTicks,\n bandSize: bandSize,\n entry: entry,\n index: index\n }),\n y: _isNil(value[1]) ? null : yAxis.scale(value[1]),\n value: value,\n payload: entry\n };\n }\n\n return {\n x: _isNil(value[1]) ? null : xAxis.scale(value[1]),\n y: getCateCoordinateOfLine({\n axis: yAxis,\n ticks: yAxisTicks,\n bandSize: bandSize,\n entry: entry,\n index: index\n }),\n value: value,\n payload: entry\n };\n });\n var baseLine;\n\n if (hasStack || isRange) {\n baseLine = points.map(function (entry) {\n if (layout === 'horizontal') {\n return {\n x: entry.x,\n y: !_isNil(_get(entry, 'value[0]')) ? yAxis.scale(_get(entry, 'value[0]')) : null\n };\n }\n\n return {\n x: !_isNil(_get(entry, 'value[0]')) ? xAxis.scale(_get(entry, 'value[0]')) : null,\n y: entry.y\n };\n });\n } else if (layout === 'horizontal') {\n baseLine = yAxis.scale(baseValue);\n } else {\n baseLine = xAxis.scale(baseValue);\n }\n\n return _objectSpread({\n points: points,\n baseLine: baseLine,\n layout: layout,\n isRange: isRange\n }, offset);\n}, _class2.renderDotItem = function (option, props) {\n var dotItem;\n\n if (React.isValidElement(option)) {\n dotItem = React.cloneElement(option, props);\n } else if (_isFunction(option)) {\n dotItem = option(props);\n } else {\n dotItem = React.createElement(Dot, _extends({}, props, {\n className: \"recharts-area-dot\"\n }));\n }\n\n return dotItem;\n}, _temp)) || _class;\n\nexport default Area;", + "function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nvar PREFIX_LIST = ['Webkit', 'Moz', 'O', 'ms'];\nexport var generatePrefixStyle = function generatePrefixStyle(name, value) {\n if (!name) {\n return null;\n }\n\n var camelName = name.replace(/(\\w)/, function (v) {\n return v.toUpperCase();\n });\n var result = PREFIX_LIST.reduce(function (res, entry) {\n return _objectSpread({}, res, _defineProperty({}, entry + camelName, value));\n }, {});\n result[name] = value;\n return result;\n};", + "import _range from \"lodash/range\";\nimport _isFunction from \"lodash/isFunction\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\n/**\n * @fileOverview Brush\n */\nimport React, { Component, Children } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { scalePoint } from 'd3-scale';\nimport { getValueByDataKey } from '../util/ChartUtils';\nimport pureRender from '../util/PureRender';\nimport Layer from '../container/Layer';\nimport Text from '../component/Text';\nimport { isNumber } from '../util/DataUtils';\nimport { generatePrefixStyle } from '../util/CssPrefixUtils';\n\nvar Brush = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Brush, _Component);\n\n function Brush(props) {\n var _this;\n\n _classCallCheck(this, Brush);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(Brush).call(this, props));\n\n _this.handleDrag = function (e) {\n if (_this.leaveTimer) {\n clearTimeout(_this.leaveTimer);\n _this.leaveTimer = null;\n }\n\n if (_this.state.isTravellerMoving) {\n _this.handleTravellerMove(e);\n } else if (_this.state.isSlideMoving) {\n _this.handleSlideDrag(e);\n }\n };\n\n _this.handleTouchMove = function (e) {\n if (e.changedTouches != null && e.changedTouches.length > 0) {\n _this.handleDrag(e.changedTouches[0]);\n }\n };\n\n _this.handleDragEnd = function () {\n _this.setState({\n isTravellerMoving: false,\n isSlideMoving: false\n });\n };\n\n _this.handleLeaveWrapper = function () {\n if (_this.state.isTravellerMoving || _this.state.isSlideMoving) {\n _this.leaveTimer = setTimeout(_this.handleDragEnd, _this.props.leaveTimeOut);\n }\n };\n\n _this.handleEnterSlideOrTraveller = function () {\n _this.setState({\n isTextActive: true\n });\n };\n\n _this.handleLeaveSlideOrTraveller = function () {\n _this.setState({\n isTextActive: false\n });\n };\n\n _this.handleSlideDragStart = function (e) {\n var event = e.changedTouches && e.changedTouches.length ? e.changedTouches[0] : e;\n\n _this.setState({\n isTravellerMoving: false,\n isSlideMoving: true,\n slideMoveStartX: event.pageX\n });\n };\n\n _this.travellerDragStartHandlers = {\n startX: _this.handleTravellerDragStart.bind(_assertThisInitialized(_assertThisInitialized(_this)), 'startX'),\n endX: _this.handleTravellerDragStart.bind(_assertThisInitialized(_assertThisInitialized(_this)), 'endX')\n };\n _this.state = props.data && props.data.length ? _this.updateScale(props) : {};\n return _this;\n }\n\n _createClass(Brush, [{\n key: \"componentWillReceiveProps\",\n value: function componentWillReceiveProps(nextProps) {\n var _this2 = this;\n\n var _this$props = this.props,\n data = _this$props.data,\n width = _this$props.width,\n x = _this$props.x,\n travellerWidth = _this$props.travellerWidth,\n updateId = _this$props.updateId;\n\n if ((nextProps.data !== data || nextProps.updateId !== updateId) && nextProps.data && nextProps.data.length) {\n this.setState(this.updateScale(nextProps));\n } else if (nextProps.width !== width || nextProps.x !== x || nextProps.travellerWidth !== travellerWidth) {\n this.scale.range([nextProps.x, nextProps.x + nextProps.width - nextProps.travellerWidth]);\n this.scaleValues = this.scale.domain().map(function (entry) {\n return _this2.scale(entry);\n });\n this.setState({\n startX: this.scale(nextProps.startIndex),\n endX: this.scale(nextProps.endIndex)\n });\n }\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n this.scale = null;\n this.scaleValues = null;\n\n if (this.leaveTimer) {\n clearTimeout(this.leaveTimer);\n this.leaveTimer = null;\n }\n }\n }, {\n key: \"getIndex\",\n value: function getIndex(_ref) {\n var startX = _ref.startX,\n endX = _ref.endX;\n var _this$props2 = this.props,\n gap = _this$props2.gap,\n data = _this$props2.data;\n var lastIndex = data.length - 1;\n var min = Math.min(startX, endX);\n var max = Math.max(startX, endX);\n var minIndex = this.constructor.getIndexInRange(this.scaleValues, min);\n var maxIndex = this.constructor.getIndexInRange(this.scaleValues, max);\n return {\n startIndex: minIndex - minIndex % gap,\n endIndex: maxIndex === lastIndex ? lastIndex : maxIndex - maxIndex % gap\n };\n }\n }, {\n key: \"getTextOfTick\",\n value: function getTextOfTick(index) {\n var _this$props3 = this.props,\n data = _this$props3.data,\n tickFormatter = _this$props3.tickFormatter,\n dataKey = _this$props3.dataKey;\n var text = getValueByDataKey(data[index], dataKey, index);\n return _isFunction(tickFormatter) ? tickFormatter(text) : text;\n }\n }, {\n key: \"handleSlideDrag\",\n value: function handleSlideDrag(e) {\n var _this$state = this.state,\n slideMoveStartX = _this$state.slideMoveStartX,\n startX = _this$state.startX,\n endX = _this$state.endX;\n var _this$props4 = this.props,\n x = _this$props4.x,\n width = _this$props4.width,\n travellerWidth = _this$props4.travellerWidth,\n startIndex = _this$props4.startIndex,\n endIndex = _this$props4.endIndex,\n onChange = _this$props4.onChange;\n var delta = e.pageX - slideMoveStartX;\n\n if (delta > 0) {\n delta = Math.min(delta, x + width - travellerWidth - endX, x + width - travellerWidth - startX);\n } else if (delta < 0) {\n delta = Math.max(delta, x - startX, x - endX);\n }\n\n var newIndex = this.getIndex({\n startX: startX + delta,\n endX: endX + delta\n });\n\n if ((newIndex.startIndex !== startIndex || newIndex.endIndex !== endIndex) && onChange) {\n onChange(newIndex);\n }\n\n this.setState({\n startX: startX + delta,\n endX: endX + delta,\n slideMoveStartX: e.pageX\n });\n }\n }, {\n key: \"handleTravellerDragStart\",\n value: function handleTravellerDragStart(id, e) {\n var event = e.changedTouches && e.changedTouches.length ? e.changedTouches[0] : e;\n this.setState({\n isSlideMoving: false,\n isTravellerMoving: true,\n movingTravellerId: id,\n brushMoveStartX: event.pageX\n });\n }\n }, {\n key: \"handleTravellerMove\",\n value: function handleTravellerMove(e) {\n var _this$setState;\n\n var _this$state2 = this.state,\n brushMoveStartX = _this$state2.brushMoveStartX,\n movingTravellerId = _this$state2.movingTravellerId,\n endX = _this$state2.endX,\n startX = _this$state2.startX;\n var prevValue = this.state[movingTravellerId];\n var _this$props5 = this.props,\n x = _this$props5.x,\n width = _this$props5.width,\n travellerWidth = _this$props5.travellerWidth,\n onChange = _this$props5.onChange,\n gap = _this$props5.gap,\n data = _this$props5.data;\n var params = {\n startX: this.state.startX,\n endX: this.state.endX\n };\n var delta = e.pageX - brushMoveStartX;\n\n if (delta > 0) {\n delta = Math.min(delta, x + width - travellerWidth - prevValue);\n } else if (delta < 0) {\n delta = Math.max(delta, x - prevValue);\n }\n\n params[movingTravellerId] = prevValue + delta;\n var newIndex = this.getIndex(params);\n var startIndex = newIndex.startIndex,\n endIndex = newIndex.endIndex;\n\n var isFullGap = function isFullGap() {\n var lastIndex = data.length - 1;\n\n if (movingTravellerId === 'startX' && (endX > startX ? startIndex % gap === 0 : endIndex % gap === 0) || endX < startX && endIndex === lastIndex || movingTravellerId === 'endX' && (endX > startX ? endIndex % gap === 0 : startIndex % gap === 0) || endX > startX && endIndex === lastIndex) {\n return true;\n }\n\n return false;\n };\n\n this.setState((_this$setState = {}, _defineProperty(_this$setState, movingTravellerId, prevValue + delta), _defineProperty(_this$setState, \"brushMoveStartX\", e.pageX), _this$setState), function () {\n if (onChange) {\n if (isFullGap()) {\n onChange(newIndex);\n }\n }\n });\n }\n }, {\n key: \"updateScale\",\n value: function updateScale(props) {\n var _this3 = this;\n\n var data = props.data,\n startIndex = props.startIndex,\n endIndex = props.endIndex,\n x = props.x,\n width = props.width,\n travellerWidth = props.travellerWidth;\n var len = data.length;\n this.scale = scalePoint().domain(_range(0, len)).range([x, x + width - travellerWidth]);\n this.scaleValues = this.scale.domain().map(function (entry) {\n return _this3.scale(entry);\n });\n return {\n isTextActive: false,\n isSlideMoving: false,\n isTravellerMoving: false,\n startX: this.scale(startIndex),\n endX: this.scale(endIndex)\n };\n }\n }, {\n key: \"renderBackground\",\n value: function renderBackground() {\n var _this$props6 = this.props,\n x = _this$props6.x,\n y = _this$props6.y,\n width = _this$props6.width,\n height = _this$props6.height,\n fill = _this$props6.fill,\n stroke = _this$props6.stroke;\n return React.createElement(\"rect\", {\n stroke: stroke,\n fill: fill,\n x: x,\n y: y,\n width: width,\n height: height\n });\n }\n }, {\n key: \"renderPanorama\",\n value: function renderPanorama() {\n var _this$props7 = this.props,\n x = _this$props7.x,\n y = _this$props7.y,\n width = _this$props7.width,\n height = _this$props7.height,\n data = _this$props7.data,\n children = _this$props7.children,\n padding = _this$props7.padding;\n var chartElement = Children.only(children);\n\n if (!chartElement) {\n return null;\n }\n\n return React.cloneElement(chartElement, {\n x: x,\n y: y,\n width: width,\n height: height,\n margin: padding,\n compact: true,\n data: data\n });\n }\n }, {\n key: \"renderTraveller\",\n value: function renderTraveller(travellerX, id) {\n var _this$props8 = this.props,\n y = _this$props8.y,\n travellerWidth = _this$props8.travellerWidth,\n height = _this$props8.height,\n stroke = _this$props8.stroke;\n var lineY = Math.floor(y + height / 2) - 1;\n var x = Math.max(travellerX, this.props.x);\n return React.createElement(Layer, {\n className: \"recharts-brush-traveller\",\n onMouseEnter: this.handleEnterSlideOrTraveller,\n onMouseLeave: this.handleLeaveSlideOrTraveller,\n onMouseDown: this.travellerDragStartHandlers[id],\n onTouchStart: this.travellerDragStartHandlers[id],\n style: {\n cursor: 'col-resize'\n }\n }, React.createElement(\"rect\", {\n x: x,\n y: y,\n width: travellerWidth,\n height: height,\n fill: stroke,\n stroke: \"none\"\n }), React.createElement(\"line\", {\n x1: x + 1,\n y1: lineY,\n x2: x + travellerWidth - 1,\n y2: lineY,\n fill: \"none\",\n stroke: \"#fff\"\n }), React.createElement(\"line\", {\n x1: x + 1,\n y1: lineY + 2,\n x2: x + travellerWidth - 1,\n y2: lineY + 2,\n fill: \"none\",\n stroke: \"#fff\"\n }));\n }\n }, {\n key: \"renderSlide\",\n value: function renderSlide(startX, endX) {\n var _this$props9 = this.props,\n y = _this$props9.y,\n height = _this$props9.height,\n stroke = _this$props9.stroke;\n return React.createElement(\"rect\", {\n className: \"recharts-brush-slide\",\n onMouseEnter: this.handleEnterSlideOrTraveller,\n onMouseLeave: this.handleLeaveSlideOrTraveller,\n onMouseDown: this.handleSlideDragStart,\n onTouchStart: this.handleSlideDragStart,\n style: {\n cursor: 'move'\n },\n stroke: \"none\",\n fill: stroke,\n fillOpacity: 0.2,\n x: Math.min(startX, endX),\n y: y,\n width: Math.abs(endX - startX),\n height: height\n });\n }\n }, {\n key: \"renderText\",\n value: function renderText() {\n var _this$props10 = this.props,\n startIndex = _this$props10.startIndex,\n endIndex = _this$props10.endIndex,\n y = _this$props10.y,\n height = _this$props10.height,\n travellerWidth = _this$props10.travellerWidth,\n stroke = _this$props10.stroke;\n var _this$state3 = this.state,\n startX = _this$state3.startX,\n endX = _this$state3.endX;\n var offset = 5;\n var attrs = {\n pointerEvents: 'none',\n fill: stroke\n };\n return React.createElement(Layer, {\n className: \"recharts-brush-texts\"\n }, React.createElement(Text, _extends({\n textAnchor: \"end\",\n verticalAnchor: \"middle\",\n x: Math.min(startX, endX) - offset,\n y: y + height / 2\n }, attrs), this.getTextOfTick(startIndex)), React.createElement(Text, _extends({\n textAnchor: \"start\",\n verticalAnchor: \"middle\",\n x: Math.max(startX, endX) + travellerWidth + offset,\n y: y + height / 2\n }, attrs), this.getTextOfTick(endIndex)));\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props11 = this.props,\n data = _this$props11.data,\n className = _this$props11.className,\n children = _this$props11.children,\n x = _this$props11.x,\n y = _this$props11.y,\n width = _this$props11.width,\n height = _this$props11.height;\n var _this$state4 = this.state,\n startX = _this$state4.startX,\n endX = _this$state4.endX,\n isTextActive = _this$state4.isTextActive,\n isSlideMoving = _this$state4.isSlideMoving,\n isTravellerMoving = _this$state4.isTravellerMoving;\n\n if (!data || !data.length || !isNumber(x) || !isNumber(y) || !isNumber(width) || !isNumber(height) || width <= 0 || height <= 0) {\n return null;\n }\n\n var layerClass = classNames('recharts-brush', className);\n var isPanoramic = React.Children.count(children) === 1;\n var style = generatePrefixStyle('userSelect', 'none');\n return React.createElement(Layer, {\n className: layerClass,\n onMouseMove: this.handleDrag,\n onMouseLeave: this.handleLeaveWrapper,\n onMouseUp: this.handleDragEnd,\n onTouchEnd: this.handleDragEnd,\n onTouchMove: this.handleTouchMove,\n style: style\n }, this.renderBackground(), isPanoramic && this.renderPanorama(), this.renderSlide(startX, endX), this.renderTraveller(startX, 'startX'), this.renderTraveller(endX, 'endX'), (isTextActive || isSlideMoving || isTravellerMoving) && this.renderText());\n }\n }], [{\n key: \"getIndexInRange\",\n value: function getIndexInRange(range, x) {\n var len = range.length;\n var start = 0;\n var end = len - 1;\n\n while (end - start > 1) {\n var middle = Math.floor((start + end) / 2);\n\n if (range[middle] > x) {\n end = middle;\n } else {\n start = middle;\n }\n }\n\n return x >= range[end] ? end : start;\n }\n }]);\n\n return Brush;\n}(Component), _class2.displayName = 'Brush', _class2.propTypes = {\n className: PropTypes.string,\n fill: PropTypes.string,\n stroke: PropTypes.string,\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number.isRequired,\n travellerWidth: PropTypes.number,\n gap: PropTypes.number,\n padding: PropTypes.shape({\n top: PropTypes.number,\n right: PropTypes.number,\n bottom: PropTypes.number,\n left: PropTypes.number\n }),\n dataKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]),\n data: PropTypes.array,\n startIndex: PropTypes.number,\n endIndex: PropTypes.number,\n tickFormatter: PropTypes.func,\n children: PropTypes.node,\n onChange: PropTypes.func,\n updateId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n leaveTimeOut: PropTypes.number\n}, _class2.defaultProps = {\n height: 40,\n travellerWidth: 5,\n gap: 1,\n fill: '#fff',\n stroke: '#666',\n padding: {\n top: 1,\n right: 1,\n bottom: 1,\n left: 1\n },\n leaveTimeOut: 1000\n}, _temp)) || _class;\n\nexport default Brush;", + "import _isFunction from \"lodash/isFunction\";\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Cartesian Axis\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { shallowEqual } from '../util/PureRender';\nimport { getStringSize } from '../util/DOMUtils';\nimport Layer from '../container/Layer';\nimport Text from '../component/Text';\nimport Label from '../component/Label';\nimport { isSsr, PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, getPresentationAttributes, filterEventsOfChild } from '../util/ReactUtils';\nimport { isNumber, mathSign } from '../util/DataUtils';\n\nvar CartesianAxis =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(CartesianAxis, _Component);\n\n function CartesianAxis() {\n _classCallCheck(this, CartesianAxis);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(CartesianAxis).apply(this, arguments));\n }\n\n _createClass(CartesianAxis, [{\n key: \"shouldComponentUpdate\",\n value: function shouldComponentUpdate(_ref, state) {\n var viewBox = _ref.viewBox,\n restProps = _objectWithoutProperties(_ref, [\"viewBox\"]);\n\n // props.viewBox is sometimes generated every time -\n // check that specially as object equality is likely to fail\n var _this$props = this.props,\n viewBoxOld = _this$props.viewBox,\n restPropsOld = _objectWithoutProperties(_this$props, [\"viewBox\"]);\n\n return !shallowEqual(viewBox, viewBoxOld) || !shallowEqual(restProps, restPropsOld) || !shallowEqual(state, this.state);\n }\n /**\n * Calculate the coordinates of endpoints in ticks\n * @param {Object} data The data of a simple tick\n * @return {Object} (x1, y1): The coordinate of endpoint close to tick text\n * (x2, y2): The coordinate of endpoint close to axis\n */\n\n }, {\n key: \"getTickLineCoord\",\n value: function getTickLineCoord(data) {\n var _this$props2 = this.props,\n x = _this$props2.x,\n y = _this$props2.y,\n width = _this$props2.width,\n height = _this$props2.height,\n orientation = _this$props2.orientation,\n tickSize = _this$props2.tickSize,\n mirror = _this$props2.mirror,\n tickMargin = _this$props2.tickMargin;\n var x1, x2, y1, y2, tx, ty;\n var sign = mirror ? -1 : 1;\n var finalTickSize = data.tickSize || tickSize;\n var tickCoord = isNumber(data.tickCoord) ? data.tickCoord : data.coordinate;\n\n switch (orientation) {\n case 'top':\n x1 = x2 = data.coordinate;\n y2 = y + !mirror * height;\n y1 = y2 - sign * finalTickSize;\n ty = y1 - sign * tickMargin;\n tx = tickCoord;\n break;\n\n case 'left':\n y1 = y2 = data.coordinate;\n x2 = x + !mirror * width;\n x1 = x2 - sign * finalTickSize;\n tx = x1 - sign * tickMargin;\n ty = tickCoord;\n break;\n\n case 'right':\n y1 = y2 = data.coordinate;\n x2 = x + mirror * width;\n x1 = x2 + sign * finalTickSize;\n tx = x1 + sign * tickMargin;\n ty = tickCoord;\n break;\n\n default:\n x1 = x2 = data.coordinate;\n y2 = y + mirror * height;\n y1 = y2 + sign * finalTickSize;\n ty = y1 + sign * tickMargin;\n tx = tickCoord;\n break;\n }\n\n return {\n line: {\n x1: x1,\n y1: y1,\n x2: x2,\n y2: y2\n },\n tick: {\n x: tx,\n y: ty\n }\n };\n }\n }, {\n key: \"getTickTextAnchor\",\n value: function getTickTextAnchor() {\n var _this$props3 = this.props,\n orientation = _this$props3.orientation,\n mirror = _this$props3.mirror;\n var textAnchor;\n\n switch (orientation) {\n case 'left':\n textAnchor = mirror ? 'start' : 'end';\n break;\n\n case 'right':\n textAnchor = mirror ? 'end' : 'start';\n break;\n\n default:\n textAnchor = 'middle';\n break;\n }\n\n return textAnchor;\n }\n }, {\n key: \"getTickVerticalAnchor\",\n value: function getTickVerticalAnchor() {\n var _this$props4 = this.props,\n orientation = _this$props4.orientation,\n mirror = _this$props4.mirror;\n var verticalAnchor = 'end';\n\n switch (orientation) {\n case 'left':\n case 'right':\n verticalAnchor = 'middle';\n break;\n\n case 'top':\n verticalAnchor = mirror ? 'start' : 'end';\n break;\n\n default:\n verticalAnchor = mirror ? 'end' : 'start';\n break;\n }\n\n return verticalAnchor;\n }\n }, {\n key: \"renderAxisLine\",\n value: function renderAxisLine() {\n var _this$props5 = this.props,\n x = _this$props5.x,\n y = _this$props5.y,\n width = _this$props5.width,\n height = _this$props5.height,\n orientation = _this$props5.orientation,\n axisLine = _this$props5.axisLine,\n mirror = _this$props5.mirror;\n\n var props = _objectSpread({}, getPresentationAttributes(this.props), {\n fill: 'none'\n }, getPresentationAttributes(axisLine));\n\n if (orientation === 'top' || orientation === 'bottom') {\n var needHeight = orientation === 'top' && !mirror || orientation === 'bottom' && mirror;\n props = _objectSpread({}, props, {\n x1: x,\n y1: y + needHeight * height,\n x2: x + width,\n y2: y + needHeight * height\n });\n } else {\n var needWidth = orientation === 'left' && !mirror || orientation === 'right' && mirror;\n props = _objectSpread({}, props, {\n x1: x + needWidth * width,\n y1: y,\n x2: x + needWidth * width,\n y2: y + height\n });\n }\n\n return React.createElement(\"line\", _extends({\n className: \"recharts-cartesian-axis-line\"\n }, props));\n }\n }, {\n key: \"renderTicks\",\n\n /**\n * render the ticks\n * @param {Array} ticks The ticks to actually render (overrides what was passed in props)\n * @return {ReactComponent} renderedTicks\n */\n value: function renderTicks(ticks) {\n var _this = this;\n\n var _this$props6 = this.props,\n tickLine = _this$props6.tickLine,\n stroke = _this$props6.stroke,\n tick = _this$props6.tick,\n tickFormatter = _this$props6.tickFormatter,\n unit = _this$props6.unit;\n var finalTicks = CartesianAxis.getTicks(_objectSpread({}, this.props, {\n ticks: ticks\n }));\n var textAnchor = this.getTickTextAnchor();\n var verticalAnchor = this.getTickVerticalAnchor();\n var axisProps = getPresentationAttributes(this.props);\n var customTickProps = getPresentationAttributes(tick);\n\n var tickLineProps = _objectSpread({}, axisProps, {\n fill: 'none'\n }, getPresentationAttributes(tickLine));\n\n var items = finalTicks.map(function (entry, i) {\n var _this$getTickLineCoor = _this.getTickLineCoord(entry),\n lineCoord = _this$getTickLineCoor.line,\n tickCoord = _this$getTickLineCoor.tick;\n\n var tickProps = _objectSpread({\n textAnchor: textAnchor,\n verticalAnchor: verticalAnchor\n }, axisProps, {\n stroke: 'none',\n fill: stroke\n }, customTickProps, tickCoord, {\n index: i,\n payload: entry,\n visibleTicksCount: finalTicks.length\n });\n\n return React.createElement(Layer, _extends({\n className: \"recharts-cartesian-axis-tick\",\n key: \"tick-\".concat(i)\n }, filterEventsOfChild(_this.props, entry, i)), tickLine && React.createElement(\"line\", _extends({\n className: \"recharts-cartesian-axis-tick-line\"\n }, tickLineProps, lineCoord)), tick && _this.constructor.renderTickItem(tick, tickProps, \"\".concat(_isFunction(tickFormatter) ? tickFormatter(entry.value) : entry.value).concat(unit || '')));\n });\n return React.createElement(\"g\", {\n className: \"recharts-cartesian-axis-ticks\"\n }, items);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props7 = this.props,\n axisLine = _this$props7.axisLine,\n width = _this$props7.width,\n height = _this$props7.height,\n ticksGenerator = _this$props7.ticksGenerator,\n className = _this$props7.className,\n hide = _this$props7.hide;\n\n if (hide) {\n return null;\n }\n\n var _this$props8 = this.props,\n ticks = _this$props8.ticks,\n noTicksProps = _objectWithoutProperties(_this$props8, [\"ticks\"]);\n\n var finalTicks = ticks;\n\n if (_isFunction(ticksGenerator)) {\n finalTicks = ticks && ticks.length > 0 ? ticksGenerator(this.props) : ticksGenerator(noTicksProps);\n }\n\n if (width <= 0 || height <= 0 || !finalTicks || !finalTicks.length) {\n return null;\n }\n\n return React.createElement(Layer, {\n className: classNames('recharts-cartesian-axis', className)\n }, axisLine && this.renderAxisLine(), this.renderTicks(finalTicks), Label.renderCallByParent(this.props));\n }\n }], [{\n key: \"getTicks\",\n value: function getTicks(props) {\n var tick = props.tick,\n ticks = props.ticks,\n viewBox = props.viewBox,\n minTickGap = props.minTickGap,\n orientation = props.orientation,\n interval = props.interval,\n tickFormatter = props.tickFormatter,\n unit = props.unit;\n\n if (!ticks || !ticks.length || !tick) {\n return [];\n }\n\n if (isNumber(interval) || isSsr()) {\n return CartesianAxis.getNumberIntervalTicks(ticks, isNumber(interval) ? interval : 0);\n }\n\n if (interval === 'preserveStartEnd') {\n return CartesianAxis.getTicksStart({\n ticks: ticks,\n tickFormatter: tickFormatter,\n viewBox: viewBox,\n orientation: orientation,\n minTickGap: minTickGap,\n unit: unit\n }, true);\n }\n\n if (interval === 'preserveStart') {\n return CartesianAxis.getTicksStart({\n ticks: ticks,\n tickFormatter: tickFormatter,\n viewBox: viewBox,\n orientation: orientation,\n minTickGap: minTickGap,\n unit: unit\n });\n }\n\n return CartesianAxis.getTicksEnd({\n ticks: ticks,\n tickFormatter: tickFormatter,\n viewBox: viewBox,\n orientation: orientation,\n minTickGap: minTickGap,\n unit: unit\n });\n }\n }, {\n key: \"getNumberIntervalTicks\",\n value: function getNumberIntervalTicks(ticks, interval) {\n return ticks.filter(function (entry, i) {\n return i % (interval + 1) === 0;\n });\n }\n }, {\n key: \"getTicksStart\",\n value: function getTicksStart(_ref2, preserveEnd) {\n var ticks = _ref2.ticks,\n tickFormatter = _ref2.tickFormatter,\n viewBox = _ref2.viewBox,\n orientation = _ref2.orientation,\n minTickGap = _ref2.minTickGap,\n unit = _ref2.unit;\n var x = viewBox.x,\n y = viewBox.y,\n width = viewBox.width,\n height = viewBox.height;\n var sizeKey = orientation === 'top' || orientation === 'bottom' ? 'width' : 'height';\n var result = (ticks || []).slice(); // we need add the width of 'unit' only when sizeKey === 'width'\n\n var unitSize = unit && sizeKey === 'width' ? getStringSize(unit)[sizeKey] : 0;\n var len = result.length;\n var sign = len >= 2 ? mathSign(result[1].coordinate - result[0].coordinate) : 1;\n var start, end;\n\n if (sign === 1) {\n start = sizeKey === 'width' ? x : y;\n end = sizeKey === 'width' ? x + width : y + height;\n } else {\n start = sizeKey === 'width' ? x + width : y + height;\n end = sizeKey === 'width' ? x : y;\n }\n\n if (preserveEnd) {\n // Try to guarantee the tail to be displayed\n var tail = ticks[len - 1];\n var tailContent = _isFunction(tickFormatter) ? tickFormatter(tail.value) : tail.value;\n var tailSize = getStringSize(tailContent)[sizeKey] + unitSize;\n var tailGap = sign * (tail.coordinate + sign * tailSize / 2 - end);\n result[len - 1] = tail = _objectSpread({}, tail, {\n tickCoord: tailGap > 0 ? tail.coordinate - tailGap * sign : tail.coordinate\n });\n var isTailShow = sign * (tail.tickCoord - sign * tailSize / 2 - start) >= 0 && sign * (tail.tickCoord + sign * tailSize / 2 - end) <= 0;\n\n if (isTailShow) {\n end = tail.tickCoord - sign * (tailSize / 2 + minTickGap);\n result[len - 1] = _objectSpread({}, tail, {\n isShow: true\n });\n }\n }\n\n var count = preserveEnd ? len - 1 : len;\n\n for (var i = 0; i < count; i++) {\n var entry = result[i];\n var content = _isFunction(tickFormatter) ? tickFormatter(entry.value) : entry.value;\n var size = getStringSize(content)[sizeKey] + unitSize;\n\n if (i === 0) {\n var gap = sign * (entry.coordinate - sign * size / 2 - start);\n result[i] = entry = _objectSpread({}, entry, {\n tickCoord: gap < 0 ? entry.coordinate - gap * sign : entry.coordinate\n });\n } else {\n result[i] = entry = _objectSpread({}, entry, {\n tickCoord: entry.coordinate\n });\n }\n\n var isShow = sign * (entry.tickCoord - sign * size / 2 - start) >= 0 && sign * (entry.tickCoord + sign * size / 2 - end) <= 0;\n\n if (isShow) {\n start = entry.tickCoord + sign * (size / 2 + minTickGap);\n result[i] = _objectSpread({}, entry, {\n isShow: true\n });\n }\n }\n\n return result.filter(function (entry) {\n return entry.isShow;\n });\n }\n }, {\n key: \"getTicksEnd\",\n value: function getTicksEnd(_ref3) {\n var ticks = _ref3.ticks,\n tickFormatter = _ref3.tickFormatter,\n viewBox = _ref3.viewBox,\n orientation = _ref3.orientation,\n minTickGap = _ref3.minTickGap,\n unit = _ref3.unit;\n var x = viewBox.x,\n y = viewBox.y,\n width = viewBox.width,\n height = viewBox.height;\n var sizeKey = orientation === 'top' || orientation === 'bottom' ? 'width' : 'height'; // we need add the width of 'unit' only when sizeKey === 'width'\n\n var unitSize = unit && sizeKey === 'width' ? getStringSize(unit)[sizeKey] : 0;\n var result = (ticks || []).slice();\n var len = result.length;\n var sign = len >= 2 ? mathSign(result[1].coordinate - result[0].coordinate) : 1;\n var start, end;\n\n if (sign === 1) {\n start = sizeKey === 'width' ? x : y;\n end = sizeKey === 'width' ? x + width : y + height;\n } else {\n start = sizeKey === 'width' ? x + width : y + height;\n end = sizeKey === 'width' ? x : y;\n }\n\n for (var i = len - 1; i >= 0; i--) {\n var entry = result[i];\n var content = _isFunction(tickFormatter) ? tickFormatter(entry.value) : entry.value;\n var size = getStringSize(content)[sizeKey] + unitSize;\n\n if (i === len - 1) {\n var gap = sign * (entry.coordinate + sign * size / 2 - end);\n result[i] = entry = _objectSpread({}, entry, {\n tickCoord: gap > 0 ? entry.coordinate - gap * sign : entry.coordinate\n });\n } else {\n result[i] = entry = _objectSpread({}, entry, {\n tickCoord: entry.coordinate\n });\n }\n\n var isShow = sign * (entry.tickCoord - sign * size / 2 - start) >= 0 && sign * (entry.tickCoord + sign * size / 2 - end) <= 0;\n\n if (isShow) {\n end = entry.tickCoord - sign * (size / 2 + minTickGap);\n result[i] = _objectSpread({}, entry, {\n isShow: true\n });\n }\n }\n\n return result.filter(function (entry) {\n return entry.isShow;\n });\n }\n }, {\n key: \"renderTickItem\",\n value: function renderTickItem(option, props, value) {\n var tickItem;\n\n if (React.isValidElement(option)) {\n tickItem = React.cloneElement(option, props);\n } else if (_isFunction(option)) {\n tickItem = option(props);\n } else {\n tickItem = React.createElement(Text, _extends({}, props, {\n className: \"recharts-cartesian-axis-tick-value\"\n }), value);\n }\n\n return tickItem;\n }\n }]);\n\n return CartesianAxis;\n}(Component);\n\nCartesianAxis.displayName = 'CartesianAxis';\nCartesianAxis.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, {\n className: PropTypes.string,\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number,\n orientation: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),\n // The viewBox of svg\n viewBox: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number\n }),\n tick: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object, PropTypes.element]),\n axisLine: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n tickLine: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n mirror: PropTypes.bool,\n tickMargin: PropTypes.number.isRequired,\n minTickGap: PropTypes.number,\n ticks: PropTypes.array,\n tickSize: PropTypes.number,\n stroke: PropTypes.string,\n tickFormatter: PropTypes.func,\n ticksGenerator: PropTypes.func,\n interval: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['preserveStart', 'preserveEnd', 'preserveStartEnd'])])\n});\nCartesianAxis.defaultProps = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n viewBox: {\n x: 0,\n y: 0,\n width: 0,\n height: 0\n },\n // The orientation of axis\n orientation: 'bottom',\n // The ticks\n ticks: [],\n stroke: '#666',\n tickLine: true,\n axisLine: true,\n tick: true,\n mirror: false,\n minTickGap: 5,\n // The width or height of tick\n tickSize: 6,\n tickMargin: 2,\n interval: 'preserveEnd'\n};\nexport default CartesianAxis;", + "function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Render a group of error bar\n*/\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport Layer from '../container/Layer';\nimport { getPresentationAttributes } from '../util/ReactUtils';\n\nvar ErrorBar =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(ErrorBar, _Component);\n\n function ErrorBar() {\n _classCallCheck(this, ErrorBar);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(ErrorBar).apply(this, arguments));\n }\n\n _createClass(ErrorBar, [{\n key: \"renderErrorBars\",\n value: function renderErrorBars() {\n var _this$props = this.props,\n offset = _this$props.offset,\n layout = _this$props.layout,\n width = _this$props.width,\n dataKey = _this$props.dataKey,\n data = _this$props.data,\n dataPointFormatter = _this$props.dataPointFormatter,\n xAxis = _this$props.xAxis,\n yAxis = _this$props.yAxis,\n others = _objectWithoutProperties(_this$props, [\"offset\", \"layout\", \"width\", \"dataKey\", \"data\", \"dataPointFormatter\", \"xAxis\", \"yAxis\"]);\n\n var props = getPresentationAttributes(others);\n return data.map(function (entry, i) {\n var _dataPointFormatter = dataPointFormatter(entry, dataKey),\n x = _dataPointFormatter.x,\n y = _dataPointFormatter.y,\n value = _dataPointFormatter.value,\n errorVal = _dataPointFormatter.errorVal;\n\n if (!errorVal) {\n return null;\n }\n\n var xMid, yMid, xMin, yMin, xMax, yMax, scale, coordsTop, coordsMid, coordsBot, lowBound, highBound;\n\n if (Array.isArray(errorVal)) {\n var _errorVal = _slicedToArray(errorVal, 2);\n\n lowBound = _errorVal[0];\n highBound = _errorVal[1];\n } else {\n lowBound = highBound = errorVal;\n }\n\n if (layout === 'vertical') {\n scale = xAxis.scale;\n xMid = value;\n yMid = y + offset;\n xMin = scale(xMid - lowBound);\n yMin = yMid + width;\n xMax = scale(xMid + highBound);\n yMax = yMid - width;\n coordsTop = {\n x1: xMax,\n y1: yMin,\n x2: xMax,\n y2: yMax\n };\n coordsMid = {\n x1: xMin,\n y1: yMid,\n x2: xMax,\n y2: yMid\n };\n coordsBot = {\n x1: xMin,\n y1: yMin,\n x2: xMin,\n y2: yMax\n };\n } else if (layout === 'horizontal') {\n scale = yAxis.scale;\n xMid = x + offset;\n yMid = value;\n xMin = xMid - width;\n xMax = xMid + width;\n yMin = scale(yMid - lowBound);\n yMax = scale(yMid + highBound);\n coordsTop = {\n x1: xMin,\n y1: yMax,\n x2: xMax,\n y2: yMax\n };\n coordsMid = {\n x1: xMid,\n y1: yMin,\n x2: xMid,\n y2: yMax\n };\n coordsBot = {\n x1: xMin,\n y1: yMin,\n x2: xMax,\n y2: yMin\n };\n }\n\n return React.createElement(Layer, _extends({\n className: \"recharts-errorBar\",\n key: \"bar-\".concat(i)\n }, props), React.createElement(\"line\", coordsTop), React.createElement(\"line\", coordsMid), React.createElement(\"line\", coordsBot));\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n return React.createElement(Layer, {\n className: \"recharts-errorBars\"\n }, this.renderErrorBars());\n }\n }]);\n\n return ErrorBar;\n}(Component);\n\nErrorBar.propTypes = {\n dataKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]).isRequired,\n data: PropTypes.array,\n xAxis: PropTypes.object,\n yAxis: PropTypes.object,\n layout: PropTypes.string,\n dataPointFormatter: PropTypes.func,\n stroke: PropTypes.string,\n strokeWidth: PropTypes.number,\n width: PropTypes.number,\n offset: PropTypes.number\n};\nErrorBar.defaultProps = {\n stroke: 'black',\n strokeWidth: 1.5,\n width: 5,\n offset: 0,\n layout: 'horizontal'\n};\nexport default ErrorBar;", + "import _isFunction from \"lodash/isFunction\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Reference Line\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport Layer from '../container/Layer';\nimport Label from '../component/Label';\nimport { LabeledScaleHelper, rectWithPoints } from '../util/CartesianUtils';\nimport { ifOverflowMatches } from '../util/ChartUtils';\nimport { isNumOrStr } from '../util/DataUtils';\nimport { warn } from '../util/LogUtils';\nimport { PRESENTATION_ATTRIBUTES } from '../util/ReactUtils';\nimport Rectangle from '../shape/Rectangle';\n\nvar ReferenceArea = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(ReferenceArea, _Component);\n\n function ReferenceArea() {\n _classCallCheck(this, ReferenceArea);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(ReferenceArea).apply(this, arguments));\n }\n\n _createClass(ReferenceArea, [{\n key: \"getRect\",\n value: function getRect(hasX1, hasX2, hasY1, hasY2) {\n var _this$props = this.props,\n xValue1 = _this$props.x1,\n xValue2 = _this$props.x2,\n yValue1 = _this$props.y1,\n yValue2 = _this$props.y2,\n xAxis = _this$props.xAxis,\n yAxis = _this$props.yAxis;\n var scale = LabeledScaleHelper.create({\n x: xAxis.scale,\n y: yAxis.scale\n });\n var p1 = {\n x: hasX1 ? scale.x.apply(xValue1) : scale.x.rangeMin,\n y: hasY1 ? scale.y.apply(yValue1) : scale.y.rangeMin\n };\n var p2 = {\n x: hasX2 ? scale.x.apply(xValue2) : scale.x.rangeMax,\n y: hasY2 ? scale.y.apply(yValue2) : scale.y.rangeMax\n };\n\n if (ifOverflowMatches(this.props, 'discard') && (!scale.isInRange(p1) || !scale.isInRange(p2))) {\n return null;\n }\n\n return rectWithPoints(p1, p2);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n x1 = _this$props2.x1,\n x2 = _this$props2.x2,\n y1 = _this$props2.y1,\n y2 = _this$props2.y2,\n className = _this$props2.className,\n alwaysShow = _this$props2.alwaysShow,\n clipPathId = _this$props2.clipPathId;\n warn(alwaysShow === undefined, 'The alwaysShow prop is deprecated. Please use ifOverflow=\"extendDomain\" instead.');\n var hasX1 = isNumOrStr(x1);\n var hasX2 = isNumOrStr(x2);\n var hasY1 = isNumOrStr(y1);\n var hasY2 = isNumOrStr(y2);\n\n if (!hasX1 && !hasX2 && !hasY1 && !hasY2) {\n return null;\n }\n\n var rect = this.getRect(hasX1, hasX2, hasY1, hasY2);\n\n if (!rect) {\n return null;\n }\n\n var shape = this.props.shape;\n var clipPath = ifOverflowMatches(this.props, 'hidden') ? \"url(#\".concat(clipPathId, \")\") : undefined;\n return React.createElement(Layer, {\n className: classNames('recharts-reference-area', className)\n }, this.constructor.renderRect(shape, _objectSpread({\n clipPath: clipPath\n }, this.props, rect)), Label.renderCallByParent(this.props, rect));\n }\n }], [{\n key: \"renderRect\",\n value: function renderRect(option, props) {\n var rect;\n\n if (React.isValidElement(option)) {\n rect = React.cloneElement(option, props);\n } else if (_isFunction(option)) {\n rect = option(props);\n } else {\n rect = React.createElement(Rectangle, _extends({}, props, {\n className: \"recharts-reference-area-rect\"\n }));\n }\n\n return rect;\n }\n }]);\n\n return ReferenceArea;\n}(Component), _class2.displayName = 'ReferenceArea', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n viewBox: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number\n }),\n xAxis: PropTypes.object,\n yAxis: PropTypes.object,\n isFront: PropTypes.bool,\n alwaysShow: PropTypes.bool,\n ifOverflow: PropTypes.oneOf(['hidden', 'visible', 'discard', 'extendDomain']),\n x1: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n x2: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n y1: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n y2: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n className: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n yAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n xAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n shape: PropTypes.oneOfType([PropTypes.func, PropTypes.element])\n}), _class2.defaultProps = {\n isFront: false,\n ifOverflow: 'discard',\n xAxisId: 0,\n yAxisId: 0,\n r: 10,\n fill: '#ccc',\n fillOpacity: 0.5,\n stroke: 'none',\n strokeWidth: 1\n}, _temp)) || _class;\n\nexport default ReferenceArea;", + "import _isFunction from \"lodash/isFunction\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Reference Dot\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport Layer from '../container/Layer';\nimport Dot from '../shape/Dot';\nimport { PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\nimport Label from '../component/Label';\nimport { isNumOrStr } from '../util/DataUtils';\nimport { ifOverflowMatches } from '../util/ChartUtils';\nimport { LabeledScaleHelper } from '../util/CartesianUtils';\nimport { warn } from '../util/LogUtils';\n\nvar ReferenceDot = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(ReferenceDot, _Component);\n\n function ReferenceDot() {\n _classCallCheck(this, ReferenceDot);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(ReferenceDot).apply(this, arguments));\n }\n\n _createClass(ReferenceDot, [{\n key: \"getCoordinate\",\n value: function getCoordinate() {\n var _this$props = this.props,\n x = _this$props.x,\n y = _this$props.y,\n xAxis = _this$props.xAxis,\n yAxis = _this$props.yAxis;\n var scales = LabeledScaleHelper.create({\n x: xAxis.scale,\n y: yAxis.scale\n });\n var result = scales.apply({\n x: x,\n y: y\n }, {\n bandAware: true\n });\n\n if (ifOverflowMatches(this.props, 'discard') && !scales.isInRange(result)) {\n return null;\n }\n\n return result;\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n x = _this$props2.x,\n y = _this$props2.y,\n r = _this$props2.r,\n alwaysShow = _this$props2.alwaysShow,\n clipPathId = _this$props2.clipPathId;\n var isX = isNumOrStr(x);\n var isY = isNumOrStr(y);\n warn(alwaysShow === undefined, 'The alwaysShow prop is deprecated. Please use ifOverflow=\"extendDomain\" instead.');\n\n if (!isX || !isY) {\n return null;\n }\n\n var coordinate = this.getCoordinate();\n\n if (!coordinate) {\n return null;\n }\n\n var cx = coordinate.x,\n cy = coordinate.y;\n var _this$props3 = this.props,\n shape = _this$props3.shape,\n className = _this$props3.className;\n var clipPath = ifOverflowMatches(this.props, 'hidden') ? \"url(#\".concat(clipPathId, \")\") : undefined;\n\n var dotProps = _objectSpread({\n clipPath: clipPath\n }, getPresentationAttributes(this.props), filterEventAttributes(this.props), {\n cx: cx,\n cy: cy\n });\n\n return React.createElement(Layer, {\n className: classNames('recharts-reference-dot', className)\n }, this.constructor.renderDot(shape, dotProps), Label.renderCallByParent(this.props, {\n x: cx - r,\n y: cy - r,\n width: 2 * r,\n height: 2 * r\n }));\n }\n }], [{\n key: \"renderDot\",\n value: function renderDot(option, props) {\n var dot;\n\n if (React.isValidElement(option)) {\n dot = React.cloneElement(option, props);\n } else if (_isFunction(option)) {\n dot = option(props);\n } else {\n dot = React.createElement(Dot, _extends({}, props, {\n cx: props.cx,\n cy: props.cy,\n className: \"recharts-reference-dot-dot\"\n }));\n }\n\n return dot;\n }\n }]);\n\n return ReferenceDot;\n}(Component), _class2.displayName = 'ReferenceDot', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, {\n r: PropTypes.number,\n xAxis: PropTypes.shape({\n scale: PropTypes.func\n }),\n yAxis: PropTypes.shape({\n scale: PropTypes.func\n }),\n isFront: PropTypes.bool,\n alwaysShow: PropTypes.bool,\n ifOverflow: PropTypes.oneOf(['hidden', 'visible', 'discard', 'extendDomain']),\n x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n y: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n className: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n yAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n xAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n shape: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),\n clipPathId: PropTypes.string\n}), _class2.defaultProps = {\n isFront: false,\n ifOverflow: 'discard',\n xAxisId: 0,\n yAxisId: 0,\n r: 10,\n fill: '#fff',\n stroke: '#ccc',\n fillOpacity: 1,\n strokeWidth: 1\n}, _temp)) || _class;\n\nexport default ReferenceDot;", + "import _some from \"lodash/some\";\nimport _isFunction from \"lodash/isFunction\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\n/**\n * @fileOverview Reference Line\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport Layer from '../container/Layer';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\nimport Label from '../component/Label';\nimport { ifOverflowMatches } from '../util/ChartUtils';\nimport { isNumOrStr } from '../util/DataUtils';\nimport { LabeledScaleHelper, rectWithCoords } from '../util/CartesianUtils';\nimport { warn } from '../util/LogUtils';\n\nvar renderLine = function renderLine(option, props) {\n var line;\n\n if (React.isValidElement(option)) {\n line = React.cloneElement(option, props);\n } else if (_isFunction(option)) {\n line = option(props);\n } else {\n line = React.createElement(\"line\", _extends({}, props, {\n className: \"recharts-reference-line-line\"\n }));\n }\n\n return line;\n};\n\nvar ReferenceLine = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(ReferenceLine, _Component);\n\n function ReferenceLine() {\n _classCallCheck(this, ReferenceLine);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(ReferenceLine).apply(this, arguments));\n }\n\n _createClass(ReferenceLine, [{\n key: \"getEndPoints\",\n value: function getEndPoints(scales, isFixedX, isFixedY, isSegment) {\n var _this$props$viewBox = this.props.viewBox,\n x = _this$props$viewBox.x,\n y = _this$props$viewBox.y,\n width = _this$props$viewBox.width,\n height = _this$props$viewBox.height;\n\n if (isFixedY) {\n var _this$props = this.props,\n yCoord = _this$props.y,\n orientation = _this$props.yAxis.orientation;\n var coord = scales.y.apply(yCoord, {\n bandAware: true\n });\n\n if (ifOverflowMatches(this.props, 'discard') && !scales.y.isInRange(coord)) {\n return null;\n }\n\n var points = [{\n x: x + width,\n y: coord\n }, {\n x: x,\n y: coord\n }];\n return orientation === 'left' ? points.reverse() : points;\n }\n\n if (isFixedX) {\n var _this$props2 = this.props,\n xCoord = _this$props2.x,\n _orientation = _this$props2.xAxis.orientation;\n\n var _coord = scales.x.apply(xCoord, {\n bandAware: true\n });\n\n if (ifOverflowMatches(this.props, 'discard') && !scales.x.isInRange(_coord)) {\n return null;\n }\n\n var _points = [{\n x: _coord,\n y: y + height\n }, {\n x: _coord,\n y: y\n }];\n return _orientation === 'top' ? _points.reverse() : _points;\n }\n\n if (isSegment) {\n var segment = this.props.segment;\n\n var _points2 = segment.map(function (p) {\n return scales.apply(p, {\n bandAware: true\n });\n });\n\n if (ifOverflowMatches(this.props, 'discard') && _some(_points2, function (p) {\n return !scales.isInRange(p);\n })) {\n return null;\n }\n\n return _points2;\n }\n\n return null;\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props3 = this.props,\n fixedX = _this$props3.x,\n fixedY = _this$props3.y,\n segment = _this$props3.segment,\n xAxis = _this$props3.xAxis,\n yAxis = _this$props3.yAxis,\n shape = _this$props3.shape,\n className = _this$props3.className,\n alwaysShow = _this$props3.alwaysShow,\n clipPathId = _this$props3.clipPathId;\n warn(alwaysShow === undefined, 'The alwaysShow prop is deprecated. Please use ifOverflow=\"extendDomain\" instead.');\n var scales = LabeledScaleHelper.create({\n x: xAxis.scale,\n y: yAxis.scale\n });\n var isX = isNumOrStr(fixedX);\n var isY = isNumOrStr(fixedY);\n var isSegment = segment && segment.length === 2;\n var endPoints = this.getEndPoints(scales, isX, isY, isSegment);\n\n if (!endPoints) {\n return null;\n }\n\n var _endPoints = _slicedToArray(endPoints, 2),\n _endPoints$ = _endPoints[0],\n x1 = _endPoints$.x,\n y1 = _endPoints$.y,\n _endPoints$2 = _endPoints[1],\n x2 = _endPoints$2.x,\n y2 = _endPoints$2.y;\n\n var clipPath = ifOverflowMatches(this.props, 'hidden') ? \"url(#\".concat(clipPathId, \")\") : undefined;\n\n var props = _objectSpread({\n clipPath: clipPath\n }, getPresentationAttributes(this.props), filterEventAttributes(this.props), {\n x1: x1,\n y1: y1,\n x2: x2,\n y2: y2\n });\n\n return React.createElement(Layer, {\n className: classNames('recharts-reference-line', className)\n }, renderLine(shape, props), Label.renderCallByParent(this.props, rectWithCoords({\n x1: x1,\n y1: y1,\n x2: x2,\n y2: y2\n })));\n }\n }]);\n\n return ReferenceLine;\n}(Component), _class2.displayName = 'ReferenceLine', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n viewBox: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number\n }),\n xAxis: PropTypes.object,\n yAxis: PropTypes.object,\n isFront: PropTypes.bool,\n alwaysShow: PropTypes.bool,\n ifOverflow: PropTypes.oneOf(['hidden', 'visible', 'discard', 'extendDomain']),\n x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n y: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n segment: PropTypes.arrayOf(PropTypes.shape({\n x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n y: PropTypes.oneOfType([PropTypes.number, PropTypes.string])\n })),\n className: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n yAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n xAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n shape: PropTypes.func\n}), _class2.defaultProps = {\n isFront: false,\n ifOverflow: 'discard',\n xAxisId: 0,\n yAxisId: 0,\n fill: 'none',\n stroke: '#ccc',\n fillOpacity: 1,\n strokeWidth: 1\n}, _temp)) || _class;\n\nexport default ReferenceLine;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview X Axis\n */\nimport { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport pureRender from '../util/PureRender';\nimport { SCALE_TYPES } from '../util/ReactUtils';\n\nvar XAxis = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(XAxis, _Component);\n\n function XAxis() {\n _classCallCheck(this, XAxis);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(XAxis).apply(this, arguments));\n }\n\n _createClass(XAxis, [{\n key: \"render\",\n value: function render() {\n return null;\n }\n }]);\n\n return XAxis;\n}(Component), _class2.displayName = 'XAxis', _class2.propTypes = {\n allowDecimals: PropTypes.bool,\n allowDuplicatedCategory: PropTypes.bool,\n hide: PropTypes.bool,\n // The name of data displayed in the axis\n name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n // The unit of data displayed in the axis\n unit: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n // The unique id of x-axis\n xAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n domain: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func, PropTypes.oneOf(['auto', 'dataMin', 'dataMax'])])),\n // The key of data displayed in the axis\n dataKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]),\n // The width of axis which is usually calculated internally\n width: PropTypes.number,\n // The height of axis, which need to be setted by user\n height: PropTypes.number,\n mirror: PropTypes.bool,\n // The orientation of axis\n orientation: PropTypes.oneOf(['top', 'bottom']),\n type: PropTypes.oneOf(['number', 'category']),\n // Ticks can be any type when the axis is the type of category\n // Ticks must be numbers when the axis is the type of number\n ticks: PropTypes.array,\n // The count of ticks\n tickCount: PropTypes.number,\n // The formatter function of tick\n tickFormatter: PropTypes.func,\n padding: PropTypes.shape({\n left: PropTypes.number,\n right: PropTypes.number\n }),\n allowDataOverflow: PropTypes.bool,\n scale: PropTypes.oneOfType([PropTypes.oneOf(SCALE_TYPES), PropTypes.func]),\n tick: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object, PropTypes.element]),\n axisLine: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n tickLine: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n minTickGap: PropTypes.number,\n tickSize: PropTypes.number,\n interval: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['preserveStart', 'preserveEnd', 'preserveStartEnd'])]),\n reversed: PropTypes.bool\n}, _class2.defaultProps = {\n allowDecimals: true,\n hide: false,\n orientation: 'bottom',\n width: 0,\n height: 30,\n mirror: false,\n xAxisId: 0,\n tickCount: 5,\n type: 'category',\n domain: [0, 'auto'],\n padding: {\n left: 0,\n right: 0\n },\n allowDataOverflow: false,\n scale: 'auto',\n reversed: false,\n allowDuplicatedCategory: true\n}, _temp)) || _class;\n\nexport default XAxis;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Y Axis\n */\nimport { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport pureRender from '../util/PureRender';\n\nvar YAxis = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(YAxis, _Component);\n\n function YAxis() {\n _classCallCheck(this, YAxis);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(YAxis).apply(this, arguments));\n }\n\n _createClass(YAxis, [{\n key: \"render\",\n value: function render() {\n return null;\n }\n }]);\n\n return YAxis;\n}(Component), _class2.displayName = 'YAxis', _class2.propTypes = {\n allowDecimals: PropTypes.bool,\n allowDuplicatedCategory: PropTypes.bool,\n hide: PropTypes.bool,\n // The name of data displayed in the axis\n name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n // The unit of data displayed in the axis\n unit: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n // The unique id of y-axis\n yAxisId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n domain: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func, PropTypes.oneOf(['auto', 'dataMin', 'dataMax'])])),\n // The key of data displayed in the axis\n dataKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]),\n // Ticks can be any type when the axis is the type of category\n // Ticks must be numbers when the axis is the type of number\n ticks: PropTypes.array,\n // The count of ticks\n tickCount: PropTypes.number,\n // The formatter function of tick\n tickFormatter: PropTypes.func,\n // The width of axis, which need to be setted by user\n width: PropTypes.number,\n // The height of axis which is usually calculated in Chart\n height: PropTypes.number,\n mirror: PropTypes.bool,\n // The orientation of axis\n orientation: PropTypes.oneOf(['left', 'right']),\n type: PropTypes.oneOf(['number', 'category']),\n padding: PropTypes.shape({\n top: PropTypes.number,\n bottom: PropTypes.number\n }),\n allowDataOverflow: PropTypes.bool,\n scale: PropTypes.oneOfType([PropTypes.oneOf(['auto', 'linear', 'pow', 'sqrt', 'log', 'identity', 'time', 'band', 'point', 'ordinal', 'quantile', 'quantize', 'utc', 'sequential', 'threshold']), PropTypes.func]),\n tick: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object, PropTypes.element]),\n axisLine: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n tickLine: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n minTickGap: PropTypes.number,\n tickSize: PropTypes.number,\n interval: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['preserveStart', 'preserveEnd', 'preserveStartEnd'])]),\n reversed: PropTypes.bool\n}, _class2.defaultProps = {\n allowDuplicatedCategory: true,\n allowDecimals: true,\n hide: false,\n orientation: 'left',\n width: 60,\n height: 0,\n mirror: false,\n yAxisId: 0,\n tickCount: 5,\n type: 'number',\n domain: [0, 'auto'],\n padding: {\n top: 0,\n bottom: 0\n },\n allowDataOverflow: false,\n scale: 'auto',\n reversed: false\n}, _temp)) || _class;\n\nexport default YAxis;", + "import EventEmitter from 'events';\nvar eventCenter = new EventEmitter();\n\nif (eventCenter.setMaxListeners) {\n eventCenter.setMaxListeners(10);\n}\n\nexport { eventCenter };\nexport var SYNC_EVENT = 'recharts.syncMouseEvents';", + "import _every from \"lodash/every\";\nimport _find from \"lodash/find\";\nimport _sortBy from \"lodash/sortBy\";\nimport _isFunction from \"lodash/isFunction\";\nimport _range from \"lodash/range\";\nimport _throttle from \"lodash/throttle\";\nimport _isNil from \"lodash/isNil\";\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nimport React, { Component, cloneElement, isValidElement, createElement } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Surface from '../container/Surface';\nimport Layer from '../container/Layer';\nimport Tooltip from '../component/Tooltip';\nimport Legend from '../component/Legend';\nimport Curve from '../shape/Curve';\nimport Cross from '../shape/Cross';\nimport Sector from '../shape/Sector';\nimport Dot from '../shape/Dot';\nimport Rectangle from '../shape/Rectangle';\nimport { findAllByType, findChildByType, getDisplayName, parseChildIndex, getPresentationAttributes, validateWidthHeight, isChildrenEqual, renderByOrder, getReactEventByType, filterEventAttributes } from '../util/ReactUtils';\nimport CartesianAxis from '../cartesian/CartesianAxis';\nimport Brush from '../cartesian/Brush';\nimport { getOffset, calculateChartCoordinate } from '../util/DOMUtils';\nimport { getAnyElementOfObject, hasDuplicate, uniqueId, isNumber, findEntryInArray } from '../util/DataUtils';\nimport { calculateActiveTickIndex, getMainColorOfGraphicItem, getBarSizeList, getBarPosition, appendOffsetOfLegend, getLegendProps, combineEventHandlers, getTicksOfAxis, getCoordinatesOfGrid, getStackedDataOfItem, parseErrorBarsOfAxis, getBandSizeOfAxis, getStackGroupsByAxisId, getValueByDataKey, isCategorialAxis, getDomainOfItemsWithSameAxis, getDomainOfStackGroups, getDomainOfDataByKey, detectReferenceElementsDomain, parseSpecifiedDomain, parseDomainOfCategoryAxis } from '../util/ChartUtils';\nimport { inRangeOfSector, polarToCartesian } from '../util/PolarUtils';\nimport { shallowEqual } from '../util/PureRender';\nimport { eventCenter, SYNC_EVENT } from '../util/Events';\nvar ORIENT_MAP = {\n xAxis: ['bottom', 'top'],\n yAxis: ['left', 'right']\n};\nvar originCoordinate = {\n x: 0,\n y: 0\n};\n\nvar generateCategoricalChart = function generateCategoricalChart(_ref) {\n var chartName = _ref.chartName,\n GraphicalChild = _ref.GraphicalChild,\n _ref$eventType = _ref.eventType,\n eventType = _ref$eventType === void 0 ? 'axis' : _ref$eventType,\n axisComponents = _ref.axisComponents,\n legendContent = _ref.legendContent,\n formatAxisMap = _ref.formatAxisMap,\n defaultProps = _ref.defaultProps,\n propTypes = _ref.propTypes;\n\n var CategoricalChartWrapper =\n /*#__PURE__*/\n function (_Component) {\n _inherits(CategoricalChartWrapper, _Component);\n\n /**\n * Returns default, reset state for the categorical chart.\n * @param {Object} props Props object to use when creating the default state\n * @return {Object} Whole new state\n */\n function CategoricalChartWrapper(_props) {\n var _this;\n\n _classCallCheck(this, CategoricalChartWrapper);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(CategoricalChartWrapper).call(this, _props));\n\n _this.handleLegendBBoxUpdate = function (box) {\n if (box && _this.legendInstance) {\n var _this$state = _this.state,\n dataStartIndex = _this$state.dataStartIndex,\n dataEndIndex = _this$state.dataEndIndex,\n updateId = _this$state.updateId;\n\n _this.setState(_this.updateStateOfAxisMapsOffsetAndStackGroups({\n props: _this.props,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex,\n updateId: updateId\n }));\n }\n };\n\n _this.handleReceiveSyncEvent = function (cId, chartId, data) {\n var _this$props = _this.props,\n syncId = _this$props.syncId,\n layout = _this$props.layout;\n var updateId = _this.state.updateId;\n\n if (syncId === cId && chartId !== _this.uniqueChartId) {\n var dataStartIndex = data.dataStartIndex,\n dataEndIndex = data.dataEndIndex;\n\n if (!_isNil(data.dataStartIndex) || !_isNil(data.dataEndIndex)) {\n _this.setState(_objectSpread({\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n }, _this.updateStateOfAxisMapsOffsetAndStackGroups({\n props: _this.props,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex,\n updateId: updateId\n })));\n } else if (!_isNil(data.activeTooltipIndex)) {\n var chartX = data.chartX,\n chartY = data.chartY,\n activeTooltipIndex = data.activeTooltipIndex;\n var _this$state2 = _this.state,\n offset = _this$state2.offset,\n tooltipTicks = _this$state2.tooltipTicks;\n\n if (!offset) {\n return;\n }\n\n var viewBox = _objectSpread({}, offset, {\n x: offset.left,\n y: offset.top\n }); // When a categotical chart is combined with another chart, the value of chartX\n // and chartY may beyond the boundaries.\n\n\n var validateChartX = Math.min(chartX, viewBox.x + viewBox.width);\n var validateChartY = Math.min(chartY, viewBox.y + viewBox.height);\n var activeLabel = tooltipTicks[activeTooltipIndex] && tooltipTicks[activeTooltipIndex].value;\n\n var activePayload = _this.getTooltipContent(activeTooltipIndex);\n\n var activeCoordinate = tooltipTicks[activeTooltipIndex] ? {\n x: layout === 'horizontal' ? tooltipTicks[activeTooltipIndex].coordinate : validateChartX,\n y: layout === 'horizontal' ? validateChartY : tooltipTicks[activeTooltipIndex].coordinate\n } : originCoordinate;\n\n _this.setState(_objectSpread({}, data, {\n activeLabel: activeLabel,\n activeCoordinate: activeCoordinate,\n activePayload: activePayload\n }));\n } else {\n _this.setState(data);\n }\n }\n };\n\n _this.handleBrushChange = function (_ref2) {\n var startIndex = _ref2.startIndex,\n endIndex = _ref2.endIndex;\n\n // Only trigger changes if the extents of the brush have actually changed\n if (startIndex !== _this.state.dataStartIndex || endIndex !== _this.state.dataEndIndex) {\n var updateId = _this.state.updateId;\n\n _this.setState(function () {\n return _objectSpread({\n dataStartIndex: startIndex,\n dataEndIndex: endIndex\n }, _this.updateStateOfAxisMapsOffsetAndStackGroups({\n props: _this.props,\n dataStartIndex: startIndex,\n dataEndIndex: endIndex,\n updateId: updateId\n }));\n });\n\n _this.triggerSyncEvent({\n dataStartIndex: startIndex,\n dataEndIndex: endIndex\n });\n }\n };\n\n _this.handleMouseEnter = function (e) {\n var onMouseEnter = _this.props.onMouseEnter;\n\n var mouse = _this.getMouseInfo(e);\n\n if (mouse) {\n var nextState = _objectSpread({}, mouse, {\n isTooltipActive: true\n });\n\n _this.setState(nextState);\n\n _this.triggerSyncEvent(nextState);\n\n if (_isFunction(onMouseEnter)) {\n onMouseEnter(nextState, e);\n }\n }\n };\n\n _this.triggeredAfterMouseMove = function (e) {\n var onMouseMove = _this.props.onMouseMove;\n\n var mouse = _this.getMouseInfo(e);\n\n var nextState = mouse ? _objectSpread({}, mouse, {\n isTooltipActive: true\n }) : {\n isTooltipActive: false\n };\n\n _this.setState(nextState);\n\n _this.triggerSyncEvent(nextState);\n\n if (_isFunction(onMouseMove)) {\n onMouseMove(nextState, e);\n }\n };\n\n _this.handleItemMouseEnter = function (el) {\n _this.setState(function () {\n return {\n isTooltipActive: true,\n activeItem: el,\n activePayload: el.tooltipPayload,\n activeCoordinate: el.tooltipPosition || {\n x: el.cx,\n y: el.cy\n }\n };\n });\n };\n\n _this.handleItemMouseLeave = function () {\n _this.setState(function () {\n return {\n isTooltipActive: false\n };\n });\n };\n\n _this.handleMouseMove = function (e) {\n if (e && _isFunction(e.persist)) {\n e.persist();\n }\n\n _this.triggeredAfterMouseMove(e);\n };\n\n _this.handleMouseLeave = function (e) {\n var onMouseLeave = _this.props.onMouseLeave;\n var nextState = {\n isTooltipActive: false\n };\n\n _this.setState(nextState);\n\n _this.triggerSyncEvent(nextState);\n\n if (_isFunction(onMouseLeave)) {\n onMouseLeave(nextState, e);\n }\n };\n\n _this.handleOuterEvent = function (e) {\n var eventName = getReactEventByType(e);\n\n if (eventName && _isFunction(_this.props[eventName])) {\n var mouse = _this.getMouseInfo(e);\n\n var handler = _this.props[eventName];\n handler(mouse, e);\n }\n };\n\n _this.handleClick = function (e) {\n var onClick = _this.props.onClick;\n\n if (_isFunction(onClick)) {\n var mouse = _this.getMouseInfo(e);\n\n onClick(mouse, e);\n }\n };\n\n _this.handleMouseDown = function (e) {\n var onMouseDown = _this.props.onMouseDown;\n\n if (_isFunction(onMouseDown)) {\n var mouse = _this.getMouseInfo(e);\n\n onMouseDown(mouse, e);\n }\n };\n\n _this.handleMouseUp = function (e) {\n var onMouseUp = _this.props.onMouseUp;\n\n if (_isFunction(onMouseUp)) {\n var mouse = _this.getMouseInfo(e);\n\n onMouseUp(mouse, e);\n }\n };\n\n _this.handleTouchMove = function (e) {\n if (e.changedTouches != null && e.changedTouches.length > 0) {\n _this.handleMouseMove(e.changedTouches[0]);\n }\n };\n\n _this.handleTouchStart = function (e) {\n if (e.changedTouches != null && e.changedTouches.length > 0) {\n _this.handleMouseDown(e.changedTouches[0]);\n }\n };\n\n _this.handleTouchEnd = function (e) {\n if (e.changedTouches != null && e.changedTouches.length > 0) {\n _this.handleMouseUp(e.changedTouches[0]);\n }\n };\n\n _this.verticalCoordinatesGenerator = function (_ref3) {\n var xAxis = _ref3.xAxis,\n width = _ref3.width,\n height = _ref3.height,\n offset = _ref3.offset;\n return getCoordinatesOfGrid(CartesianAxis.getTicks(_objectSpread({}, CartesianAxis.defaultProps, xAxis, {\n ticks: getTicksOfAxis(xAxis, true),\n viewBox: {\n x: 0,\n y: 0,\n width: width,\n height: height\n }\n })), offset.left, offset.left + offset.width);\n };\n\n _this.horizontalCoordinatesGenerator = function (_ref4) {\n var yAxis = _ref4.yAxis,\n width = _ref4.width,\n height = _ref4.height,\n offset = _ref4.offset;\n return getCoordinatesOfGrid(CartesianAxis.getTicks(_objectSpread({}, CartesianAxis.defaultProps, yAxis, {\n ticks: getTicksOfAxis(yAxis, true),\n viewBox: {\n x: 0,\n y: 0,\n width: width,\n height: height\n }\n })), offset.top, offset.top + offset.height);\n };\n\n _this.axesTicksGenerator = function (axis) {\n return getTicksOfAxis(axis, true);\n };\n\n _this.tooltipTicksGenerator = function (axisMap) {\n var axis = getAnyElementOfObject(axisMap);\n var tooltipTicks = getTicksOfAxis(axis, false, true);\n return {\n tooltipTicks: tooltipTicks,\n orderedTooltipTicks: _sortBy(tooltipTicks, function (o) {\n return o.coordinate;\n }),\n tooltipAxis: axis,\n tooltipAxisBandSize: getBandSizeOfAxis(axis)\n };\n };\n\n _this.renderCursor = function (element) {\n var _this$state3 = _this.state,\n isTooltipActive = _this$state3.isTooltipActive,\n activeCoordinate = _this$state3.activeCoordinate,\n activePayload = _this$state3.activePayload,\n offset = _this$state3.offset;\n\n if (!element || !element.props.cursor || !isTooltipActive || !activeCoordinate) {\n return null;\n }\n\n var layout = _this.props.layout;\n var restProps;\n var cursorComp = Curve;\n\n if (chartName === 'ScatterChart') {\n restProps = activeCoordinate;\n cursorComp = Cross;\n } else if (chartName === 'BarChart') {\n restProps = _this.getCursorRectangle();\n cursorComp = Rectangle;\n } else if (layout === 'radial') {\n var _this$getCursorPoints = _this.getCursorPoints(),\n cx = _this$getCursorPoints.cx,\n cy = _this$getCursorPoints.cy,\n radius = _this$getCursorPoints.radius,\n startAngle = _this$getCursorPoints.startAngle,\n endAngle = _this$getCursorPoints.endAngle;\n\n restProps = {\n cx: cx,\n cy: cy,\n startAngle: startAngle,\n endAngle: endAngle,\n innerRadius: radius,\n outerRadius: radius\n };\n cursorComp = Sector;\n } else {\n restProps = {\n points: _this.getCursorPoints()\n };\n cursorComp = Curve;\n }\n\n var key = element.key || '_recharts-cursor';\n\n var cursorProps = _objectSpread({\n stroke: '#ccc',\n pointerEvents: 'none'\n }, offset, restProps, getPresentationAttributes(element.props.cursor), {\n payload: activePayload,\n key: key,\n className: 'recharts-tooltip-cursor'\n });\n\n return isValidElement(element.props.cursor) ? cloneElement(element.props.cursor, cursorProps) : createElement(cursorComp, cursorProps);\n };\n\n _this.renderPolarAxis = function (element, displayName, index) {\n var axisType = element.type.axisType;\n\n var axisMap = _this.state[\"\".concat(axisType, \"Map\")];\n\n var axisOption = axisMap[element.props[\"\".concat(axisType, \"Id\")]];\n return cloneElement(element, _objectSpread({}, axisOption, {\n className: axisType,\n key: element.key || \"\".concat(displayName, \"-\").concat(index),\n ticks: getTicksOfAxis(axisOption, true)\n }));\n };\n\n _this.renderXAxis = function (element, displayName, index) {\n var xAxisMap = _this.state.xAxisMap;\n var axisObj = xAxisMap[element.props.xAxisId];\n return _this.renderAxis(axisObj, element, displayName, index);\n };\n\n _this.renderYAxis = function (element, displayName, index) {\n var yAxisMap = _this.state.yAxisMap;\n var axisObj = yAxisMap[element.props.yAxisId];\n return _this.renderAxis(axisObj, element, displayName, index);\n };\n\n _this.renderGrid = function (element) {\n var _this$state4 = _this.state,\n xAxisMap = _this$state4.xAxisMap,\n yAxisMap = _this$state4.yAxisMap,\n offset = _this$state4.offset;\n var _this$props2 = _this.props,\n width = _this$props2.width,\n height = _this$props2.height;\n var xAxis = getAnyElementOfObject(xAxisMap);\n\n var yAxisWithFiniteDomain = _find(yAxisMap, function (axis) {\n return _every(axis.domain, Number.isFinite);\n });\n\n var yAxis = yAxisWithFiniteDomain || getAnyElementOfObject(yAxisMap);\n var props = element.props || {};\n return cloneElement(element, {\n key: element.key || 'grid',\n x: isNumber(props.x) ? props.x : offset.left,\n y: isNumber(props.y) ? props.y : offset.top,\n width: isNumber(props.width) ? props.width : offset.width,\n height: isNumber(props.height) ? props.height : offset.height,\n xAxis: xAxis,\n yAxis: yAxis,\n offset: offset,\n chartWidth: width,\n chartHeight: height,\n verticalCoordinatesGenerator: props.verticalCoordinatesGenerator || _this.verticalCoordinatesGenerator,\n horizontalCoordinatesGenerator: props.horizontalCoordinatesGenerator || _this.horizontalCoordinatesGenerator\n });\n };\n\n _this.renderPolarGrid = function (element) {\n var _this$state5 = _this.state,\n radiusAxisMap = _this$state5.radiusAxisMap,\n angleAxisMap = _this$state5.angleAxisMap;\n var radiusAxis = getAnyElementOfObject(radiusAxisMap);\n var angleAxis = getAnyElementOfObject(angleAxisMap);\n var cx = angleAxis.cx,\n cy = angleAxis.cy,\n innerRadius = angleAxis.innerRadius,\n outerRadius = angleAxis.outerRadius;\n return cloneElement(element, {\n polarAngles: getTicksOfAxis(angleAxis, true).map(function (entry) {\n return entry.coordinate;\n }),\n polarRadius: getTicksOfAxis(radiusAxis, true).map(function (entry) {\n return entry.coordinate;\n }),\n cx: cx,\n cy: cy,\n innerRadius: innerRadius,\n outerRadius: outerRadius,\n key: element.key || 'polar-grid'\n });\n };\n\n _this.renderBrush = function (element) {\n var _this$props3 = _this.props,\n margin = _this$props3.margin,\n data = _this$props3.data;\n var _this$state6 = _this.state,\n offset = _this$state6.offset,\n dataStartIndex = _this$state6.dataStartIndex,\n dataEndIndex = _this$state6.dataEndIndex,\n updateId = _this$state6.updateId; // TODO: update brush when children update\n\n return cloneElement(element, {\n key: element.key || '_recharts-brush',\n onChange: combineEventHandlers(_this.handleBrushChange, null, element.props.onChange),\n data: data,\n x: isNumber(element.props.x) ? element.props.x : offset.left,\n y: isNumber(element.props.y) ? element.props.y : offset.top + offset.height + offset.brushBottom - (margin.bottom || 0),\n width: isNumber(element.props.width) ? element.props.width : offset.width,\n startIndex: dataStartIndex,\n endIndex: dataEndIndex,\n updateId: \"brush-\".concat(updateId)\n });\n };\n\n _this.renderReferenceElement = function (element, displayName, index) {\n if (!element) {\n return null;\n }\n\n var _assertThisInitialize = _assertThisInitialized(_assertThisInitialized(_this)),\n clipPathId = _assertThisInitialize.clipPathId;\n\n var _this$state7 = _this.state,\n xAxisMap = _this$state7.xAxisMap,\n yAxisMap = _this$state7.yAxisMap,\n offset = _this$state7.offset;\n var _element$props = element.props,\n xAxisId = _element$props.xAxisId,\n yAxisId = _element$props.yAxisId;\n return cloneElement(element, {\n key: element.key || \"\".concat(displayName, \"-\").concat(index),\n xAxis: xAxisMap[xAxisId],\n yAxis: yAxisMap[yAxisId],\n viewBox: {\n x: offset.left,\n y: offset.top,\n width: offset.width,\n height: offset.height\n },\n clipPathId: clipPathId\n });\n };\n\n _this.renderGraphicChild = function (element, displayName, index) {\n var item = _this.filterFormatItem(element, displayName, index);\n\n if (!item) {\n return null;\n }\n\n var graphicalItem = cloneElement(element, item.props);\n var _this$state8 = _this.state,\n isTooltipActive = _this$state8.isTooltipActive,\n tooltipAxis = _this$state8.tooltipAxis,\n activeTooltipIndex = _this$state8.activeTooltipIndex,\n activeLabel = _this$state8.activeLabel;\n var children = _this.props.children;\n var tooltipItem = findChildByType(children, Tooltip);\n var _item$props = item.props,\n points = _item$props.points,\n isRange = _item$props.isRange,\n baseLine = _item$props.baseLine;\n var _item$item$props = item.item.props,\n activeDot = _item$item$props.activeDot,\n hide = _item$item$props.hide;\n var hasActive = !hide && isTooltipActive && tooltipItem && activeDot && activeTooltipIndex >= 0;\n\n if (hasActive) {\n var activePoint, basePoint;\n\n if (tooltipAxis.dataKey && !tooltipAxis.allowDuplicatedCategory) {\n activePoint = findEntryInArray(points, \"payload.\".concat(tooltipAxis.dataKey), activeLabel);\n basePoint = isRange && baseLine && findEntryInArray(baseLine, \"payload.\".concat(tooltipAxis.dataKey), activeLabel);\n } else {\n activePoint = points[activeTooltipIndex];\n basePoint = isRange && baseLine && baseLine[activeTooltipIndex];\n }\n\n if (!_isNil(activePoint)) {\n return [graphicalItem].concat(_toConsumableArray(_this.renderActivePoints({\n item: item,\n activePoint: activePoint,\n basePoint: basePoint,\n childIndex: activeTooltipIndex,\n isRange: isRange\n })));\n }\n }\n\n if (isRange) {\n return [graphicalItem, null, null];\n }\n\n return [graphicalItem, null];\n };\n\n var defaultState = _this.constructor.createDefaultState(_props);\n\n var _updateId = 0;\n _this.state = _objectSpread({}, defaultState, {\n updateId: 0\n }, _this.updateStateOfAxisMapsOffsetAndStackGroups(_objectSpread({\n props: _props\n }, defaultState, {\n updateId: _updateId\n })));\n _this.uniqueChartId = _isNil(_props.id) ? uniqueId('recharts') : _props.id;\n _this.clipPathId = \"\".concat(_this.uniqueChartId, \"-clip\");\n\n if (_props.throttleDelay) {\n _this.triggeredAfterMouseMove = _throttle(_this.triggeredAfterMouseMove, _props.throttleDelay);\n }\n\n return _this;\n }\n /* eslint-disable react/no-did-mount-set-state */\n\n\n _createClass(CategoricalChartWrapper, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n if (!_isNil(this.props.syncId)) {\n this.addListener();\n }\n }\n }, {\n key: \"componentWillReceiveProps\",\n value: function componentWillReceiveProps(nextProps) {\n var _this2 = this;\n\n var _this$props4 = this.props,\n data = _this$props4.data,\n children = _this$props4.children,\n width = _this$props4.width,\n height = _this$props4.height,\n layout = _this$props4.layout,\n stackOffset = _this$props4.stackOffset,\n margin = _this$props4.margin;\n var updateId = this.state.updateId;\n\n if (nextProps.data !== data || nextProps.width !== width || nextProps.height !== height || nextProps.layout !== layout || nextProps.stackOffset !== stackOffset || !shallowEqual(nextProps.margin, margin)) {\n var defaultState = this.constructor.createDefaultState(nextProps);\n this.setState(_objectSpread({}, defaultState, {\n updateId: updateId + 1\n }, this.updateStateOfAxisMapsOffsetAndStackGroups(_objectSpread({\n props: nextProps\n }, defaultState, {\n updateId: updateId + 1\n }))));\n } else if (!isChildrenEqual(nextProps.children, children)) {\n // update configuration in chilren\n var hasGlobalData = !_isNil(nextProps.data);\n var newUpdateId = hasGlobalData ? updateId : updateId + 1;\n this.setState(function (prevState) {\n return _objectSpread({\n updateId: newUpdateId\n }, _this2.updateStateOfAxisMapsOffsetAndStackGroups(_objectSpread({\n props: nextProps\n }, prevState, {\n updateId: newUpdateId\n })));\n });\n } // add syncId\n\n\n if (_isNil(this.props.syncId) && !_isNil(nextProps.syncId)) {\n this.addListener();\n } // remove syncId\n\n\n if (!_isNil(this.props.syncId) && _isNil(nextProps.syncId)) {\n this.removeListener();\n }\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n if (!_isNil(this.props.syncId)) {\n this.removeListener();\n }\n\n if (typeof this.triggeredAfterMouseMove.cancel === 'function') {\n this.triggeredAfterMouseMove.cancel();\n }\n }\n /**\n * Get the configuration of all x-axis or y-axis\n * @param {Object} props Latest props\n * @param {String} axisType The type of axis\n * @param {Array} graphicalItems The instances of item\n * @param {Object} stackGroups The items grouped by axisId and stackId\n * @param {Number} dataStartIndex The start index of the data series when a brush is applied\n * @param {Number} dataEndIndex The end index of the data series when a brush is applied\n * @return {Object} Configuration\n */\n\n }, {\n key: \"getAxisMap\",\n value: function getAxisMap(props, _ref5) {\n var _ref5$axisType = _ref5.axisType,\n axisType = _ref5$axisType === void 0 ? 'xAxis' : _ref5$axisType,\n AxisComp = _ref5.AxisComp,\n graphicalItems = _ref5.graphicalItems,\n stackGroups = _ref5.stackGroups,\n dataStartIndex = _ref5.dataStartIndex,\n dataEndIndex = _ref5.dataEndIndex;\n var children = props.children;\n var axisIdKey = \"\".concat(axisType, \"Id\"); // Get all the instance of Axis\n\n var axes = findAllByType(children, AxisComp);\n var axisMap = {};\n\n if (axes && axes.length) {\n axisMap = this.getAxisMapByAxes(props, {\n axes: axes,\n graphicalItems: graphicalItems,\n axisType: axisType,\n axisIdKey: axisIdKey,\n stackGroups: stackGroups,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n });\n } else if (graphicalItems && graphicalItems.length) {\n axisMap = this.getAxisMapByItems(props, {\n Axis: AxisComp,\n graphicalItems: graphicalItems,\n axisType: axisType,\n axisIdKey: axisIdKey,\n stackGroups: stackGroups,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n });\n }\n\n return axisMap;\n }\n /**\n * Get the configuration of axis by the options of axis instance\n * @param {Object} props Latest props\n * @param {Array} axes The instance of axes\n * @param {Array} graphicalItems The instances of item\n * @param {String} axisType The type of axis, xAxis - x-axis, yAxis - y-axis\n * @param {String} axisIdKey The unique id of an axis\n * @param {Object} stackGroups The items grouped by axisId and stackId\n * @param {Number} dataStartIndex The start index of the data series when a brush is applied\n * @param {Number} dataEndIndex The end index of the data series when a brush is applied\n * @return {Object} Configuration\n */\n\n }, {\n key: \"getAxisMapByAxes\",\n value: function getAxisMapByAxes(props, _ref6) {\n var _this3 = this;\n\n var axes = _ref6.axes,\n graphicalItems = _ref6.graphicalItems,\n axisType = _ref6.axisType,\n axisIdKey = _ref6.axisIdKey,\n stackGroups = _ref6.stackGroups,\n dataStartIndex = _ref6.dataStartIndex,\n dataEndIndex = _ref6.dataEndIndex;\n var layout = props.layout,\n children = props.children,\n stackOffset = props.stackOffset;\n var isCategorial = isCategorialAxis(layout, axisType); // Eliminate duplicated axes\n\n var axisMap = axes.reduce(function (result, child) {\n var _child$props = child.props,\n type = _child$props.type,\n dataKey = _child$props.dataKey,\n allowDataOverflow = _child$props.allowDataOverflow,\n allowDuplicatedCategory = _child$props.allowDuplicatedCategory,\n scale = _child$props.scale,\n ticks = _child$props.ticks;\n var axisId = child.props[axisIdKey];\n\n var displayedData = _this3.constructor.getDisplayedData(props, {\n graphicalItems: graphicalItems.filter(function (item) {\n return item.props[axisIdKey] === axisId;\n }),\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n });\n\n var len = displayedData.length;\n\n if (!result[axisId]) {\n var domain, duplicateDomain, categoricalDomain;\n\n if (dataKey) {\n domain = getDomainOfDataByKey(displayedData, dataKey, type);\n\n if (type === 'category' && isCategorial) {\n var duplicate = hasDuplicate(domain);\n\n if (allowDuplicatedCategory && duplicate) {\n duplicateDomain = domain; // When category axis has duplicated text, serial numbers are used to generate scale\n\n domain = _range(0, len);\n } else if (!allowDuplicatedCategory) {\n // remove duplicated category\n domain = parseDomainOfCategoryAxis(child.props.domain, domain, child).reduce(function (finalDomain, entry) {\n return finalDomain.indexOf(entry) >= 0 ? finalDomain : _toConsumableArray(finalDomain).concat([entry]);\n }, []);\n }\n } else if (type === 'category') {\n if (!allowDuplicatedCategory) {\n domain = parseDomainOfCategoryAxis(child.props.domain, domain, child).reduce(function (finalDomain, entry) {\n return finalDomain.indexOf(entry) >= 0 || entry === '' || _isNil(entry) ? finalDomain : _toConsumableArray(finalDomain).concat([entry]);\n }, []);\n } else {\n // eliminate undefined or null or empty string\n domain = domain.filter(function (entry) {\n return entry !== '' && !_isNil(entry);\n });\n }\n } else if (type === 'number') {\n var errorBarsDomain = parseErrorBarsOfAxis(displayedData, graphicalItems.filter(function (item) {\n return item.props[axisIdKey] === axisId && !item.props.hide;\n }), dataKey, axisType);\n\n if (errorBarsDomain) {\n domain = errorBarsDomain;\n }\n }\n\n if (isCategorial && (type === 'number' || scale !== 'auto')) {\n categoricalDomain = getDomainOfDataByKey(displayedData, dataKey, 'category');\n }\n } else if (isCategorial) {\n domain = _range(0, len);\n } else if (stackGroups && stackGroups[axisId] && stackGroups[axisId].hasStack && type === 'number') {\n // when stackOffset is 'expand', the domain may be calculated as [0, 1.000000000002]\n domain = stackOffset === 'expand' ? [0, 1] : getDomainOfStackGroups(stackGroups[axisId].stackGroups, dataStartIndex, dataEndIndex);\n } else {\n domain = getDomainOfItemsWithSameAxis(displayedData, graphicalItems.filter(function (item) {\n return item.props[axisIdKey] === axisId && !item.props.hide;\n }), type, true);\n }\n\n if (type === 'number') {\n // To detect wether there is any reference lines whose props alwaysShow is true\n domain = detectReferenceElementsDomain(children, domain, axisId, axisType, ticks);\n\n if (child.props.domain) {\n domain = parseSpecifiedDomain(child.props.domain, domain, allowDataOverflow);\n }\n }\n\n return _objectSpread({}, result, _defineProperty({}, axisId, _objectSpread({}, child.props, {\n axisType: axisType,\n domain: domain,\n categoricalDomain: categoricalDomain,\n duplicateDomain: duplicateDomain,\n originalDomain: child.props.domain,\n isCategorial: isCategorial,\n layout: layout\n })));\n }\n\n return result;\n }, {});\n return axisMap;\n }\n /**\n * Get the configuration of axis by the options of item,\n * this kind of axis does not display in chart\n * @param {Object} props Latest props\n * @param {Array} graphicalItems The instances of item\n * @param {ReactElement} Axis Axis Component\n * @param {String} axisType The type of axis, xAxis - x-axis, yAxis - y-axis\n * @param {String} axisIdKey The unique id of an axis\n * @param {Object} stackGroups The items grouped by axisId and stackId\n * @param {Number} dataStartIndex The start index of the data series when a brush is applied\n * @param {Number} dataEndIndex The end index of the data series when a brush is applied\n * @return {Object} Configuration\n */\n\n }, {\n key: \"getAxisMapByItems\",\n value: function getAxisMapByItems(props, _ref7) {\n var graphicalItems = _ref7.graphicalItems,\n Axis = _ref7.Axis,\n axisType = _ref7.axisType,\n axisIdKey = _ref7.axisIdKey,\n stackGroups = _ref7.stackGroups,\n dataStartIndex = _ref7.dataStartIndex,\n dataEndIndex = _ref7.dataEndIndex;\n var layout = props.layout,\n children = props.children;\n var displayedData = this.constructor.getDisplayedData(props, {\n graphicalItems: graphicalItems,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n });\n var len = displayedData.length;\n var isCategorial = isCategorialAxis(layout, axisType);\n var index = -1; // The default type of x-axis is category axis,\n // The default contents of x-axis is the serial numbers of data\n // The default type of y-axis is number axis\n // The default contents of y-axis is the domain of data\n\n var axisMap = graphicalItems.reduce(function (result, child) {\n var axisId = child.props[axisIdKey];\n\n if (!result[axisId]) {\n index++;\n var domain;\n\n if (isCategorial) {\n domain = _range(0, len);\n } else if (stackGroups && stackGroups[axisId] && stackGroups[axisId].hasStack) {\n domain = getDomainOfStackGroups(stackGroups[axisId].stackGroups, dataStartIndex, dataEndIndex);\n domain = detectReferenceElementsDomain(children, domain, axisId, axisType);\n } else {\n domain = parseSpecifiedDomain(Axis.defaultProps.domain, getDomainOfItemsWithSameAxis(displayedData, graphicalItems.filter(function (item) {\n return item.props[axisIdKey] === axisId && !item.props.hide;\n }), 'number'), Axis.defaultProps.allowDataOverflow);\n domain = detectReferenceElementsDomain(children, domain, axisId, axisType);\n }\n\n return _objectSpread({}, result, _defineProperty({}, axisId, _objectSpread({\n axisType: axisType\n }, Axis.defaultProps, {\n hide: true,\n orientation: ORIENT_MAP[axisType] && ORIENT_MAP[axisType][index % 2],\n domain: domain,\n originalDomain: Axis.defaultProps.domain,\n isCategorial: isCategorial,\n layout: layout // specify scale when no Axis\n // scale: isCategorial ? 'band' : 'linear',\n\n })));\n }\n\n return result;\n }, {});\n return axisMap;\n }\n }, {\n key: \"getActiveCoordinate\",\n value: function getActiveCoordinate(tooltipTicks, activeIndex, rangeObj) {\n var layout = this.props.layout;\n var entry = tooltipTicks.find(function (tick) {\n return tick && tick.index === activeIndex;\n });\n\n if (entry) {\n if (layout === 'horizontal') {\n return {\n x: entry.coordinate,\n y: rangeObj.y\n };\n }\n\n if (layout === 'vertical') {\n return {\n x: rangeObj.x,\n y: entry.coordinate\n };\n }\n\n if (layout === 'centric') {\n var _angle = entry.coordinate;\n var _radius = rangeObj.radius;\n return _objectSpread({}, rangeObj, polarToCartesian(rangeObj.cx, rangeObj.cy, _radius, _angle), {\n angle: _angle,\n radius: _radius\n });\n }\n\n var radius = entry.coordinate;\n var angle = rangeObj.angle;\n return _objectSpread({}, rangeObj, polarToCartesian(rangeObj.cx, rangeObj.cy, radius, angle), {\n angle: angle,\n radius: radius\n });\n }\n\n return originCoordinate;\n }\n /**\n * Get the information of mouse in chart, return null when the mouse is not in the chart\n * @param {Object} event The event object\n * @return {Object} Mouse data\n */\n\n }, {\n key: \"getMouseInfo\",\n value: function getMouseInfo(event) {\n if (!this.container) {\n return null;\n }\n\n var containerOffset = getOffset(this.container);\n var e = calculateChartCoordinate(event, containerOffset);\n var rangeObj = this.inRange(e.chartX, e.chartY);\n\n if (!rangeObj) {\n return null;\n }\n\n var _this$state9 = this.state,\n xAxisMap = _this$state9.xAxisMap,\n yAxisMap = _this$state9.yAxisMap;\n\n if (eventType !== 'axis' && xAxisMap && yAxisMap) {\n var xScale = getAnyElementOfObject(xAxisMap).scale;\n var yScale = getAnyElementOfObject(yAxisMap).scale;\n var xValue = xScale && xScale.invert ? xScale.invert(e.chartX) : null;\n var yValue = yScale && yScale.invert ? yScale.invert(e.chartY) : null;\n return _objectSpread({}, e, {\n xValue: xValue,\n yValue: yValue\n });\n }\n\n var _this$state10 = this.state,\n ticks = _this$state10.orderedTooltipTicks,\n axis = _this$state10.tooltipAxis,\n tooltipTicks = _this$state10.tooltipTicks;\n var pos = this.calculateTooltipPos(rangeObj);\n var activeIndex = calculateActiveTickIndex(pos, ticks, tooltipTicks, axis);\n\n if (activeIndex >= 0 && tooltipTicks) {\n var activeLabel = tooltipTicks[activeIndex] && tooltipTicks[activeIndex].value;\n var activePayload = this.getTooltipContent(activeIndex, activeLabel);\n var activeCoordinate = this.getActiveCoordinate(ticks, activeIndex, rangeObj);\n return _objectSpread({}, e, {\n activeTooltipIndex: activeIndex,\n activeLabel: activeLabel,\n activePayload: activePayload,\n activeCoordinate: activeCoordinate\n });\n }\n\n return null;\n }\n /**\n * Get the content to be displayed in the tooltip\n * @param {Number} activeIndex Active index of data\n * @param {String} activeLabel Active label of data\n * @return {Array} The content of tooltip\n */\n\n }, {\n key: \"getTooltipContent\",\n value: function getTooltipContent(activeIndex, activeLabel) {\n var _this$state11 = this.state,\n graphicalItems = _this$state11.graphicalItems,\n tooltipAxis = _this$state11.tooltipAxis;\n var displayedData = this.constructor.getDisplayedData(this.props, this.state);\n\n if (activeIndex < 0 || !graphicalItems || !graphicalItems.length || activeIndex >= displayedData.length) {\n return null;\n } // get data by activeIndex when the axis don't allow duplicated category\n\n\n return graphicalItems.reduce(function (result, child) {\n var hide = child.props.hide;\n\n if (hide) {\n return result;\n }\n\n var _child$props2 = child.props,\n dataKey = _child$props2.dataKey,\n name = _child$props2.name,\n unit = _child$props2.unit,\n formatter = _child$props2.formatter,\n data = _child$props2.data;\n var payload;\n\n if (tooltipAxis.dataKey && !tooltipAxis.allowDuplicatedCategory) {\n // graphic child has data props\n payload = findEntryInArray(data || displayedData, tooltipAxis.dataKey, activeLabel);\n } else {\n payload = displayedData[activeIndex];\n }\n\n if (!payload) {\n return result;\n }\n\n return _toConsumableArray(result).concat([_objectSpread({}, getPresentationAttributes(child), {\n dataKey: dataKey,\n unit: unit,\n formatter: formatter,\n name: name || dataKey,\n color: getMainColorOfGraphicItem(child),\n value: getValueByDataKey(payload, dataKey),\n payload: payload\n })]);\n }, []);\n }\n }, {\n key: \"getFormatItems\",\n value: function getFormatItems(props, currentState) {\n var _this4 = this;\n\n var graphicalItems = currentState.graphicalItems,\n stackGroups = currentState.stackGroups,\n offset = currentState.offset,\n updateId = currentState.updateId,\n dataStartIndex = currentState.dataStartIndex,\n dataEndIndex = currentState.dataEndIndex;\n var barSize = props.barSize,\n layout = props.layout,\n barGap = props.barGap,\n barCategoryGap = props.barCategoryGap,\n globalMaxBarSize = props.maxBarSize;\n\n var _this$constructor$get = this.constructor.getAxisNameByLayout(layout),\n numericAxisName = _this$constructor$get.numericAxisName,\n cateAxisName = _this$constructor$get.cateAxisName;\n\n var hasBar = this.constructor.hasBar(graphicalItems);\n var sizeList = hasBar && getBarSizeList({\n barSize: barSize,\n stackGroups: stackGroups\n });\n var formatedItems = [];\n graphicalItems.forEach(function (item, index) {\n var displayedData = _this4.constructor.getDisplayedData(props, {\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n }, item);\n\n var _item$props2 = item.props,\n dataKey = _item$props2.dataKey,\n childMaxBarSize = _item$props2.maxBarSize;\n var numericAxisId = item.props[\"\".concat(numericAxisName, \"Id\")];\n var cateAxisId = item.props[\"\".concat(cateAxisName, \"Id\")];\n var axisObj = axisComponents.reduce(function (result, entry) {\n var _objectSpread4;\n\n var axisMap = currentState[\"\".concat(entry.axisType, \"Map\")];\n var id = item.props[\"\".concat(entry.axisType, \"Id\")];\n var axis = axisMap && axisMap[id];\n return _objectSpread({}, result, (_objectSpread4 = {}, _defineProperty(_objectSpread4, entry.axisType, axis), _defineProperty(_objectSpread4, \"\".concat(entry.axisType, \"Ticks\"), getTicksOfAxis(axis)), _objectSpread4));\n }, {});\n var cateAxis = axisObj[cateAxisName];\n var cateTicks = axisObj[\"\".concat(cateAxisName, \"Ticks\")];\n var stackedData = stackGroups && stackGroups[numericAxisId] && stackGroups[numericAxisId].hasStack && getStackedDataOfItem(item, stackGroups[numericAxisId].stackGroups);\n var bandSize = getBandSizeOfAxis(cateAxis, cateTicks);\n var maxBarSize = _isNil(childMaxBarSize) ? globalMaxBarSize : childMaxBarSize;\n var barPosition = hasBar && getBarPosition({\n barGap: barGap,\n barCategoryGap: barCategoryGap,\n bandSize: bandSize,\n sizeList: sizeList[cateAxisId],\n maxBarSize: maxBarSize\n });\n var componsedFn = item && item.type && item.type.getComposedData;\n\n if (componsedFn) {\n var _objectSpread5;\n\n formatedItems.push({\n props: _objectSpread({}, componsedFn(_objectSpread({}, axisObj, {\n displayedData: displayedData,\n props: props,\n dataKey: dataKey,\n item: item,\n bandSize: bandSize,\n barPosition: barPosition,\n offset: offset,\n stackedData: stackedData,\n layout: layout,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex,\n onItemMouseLeave: combineEventHandlers(_this4.handleItemMouseLeave, null, item.props.onMouseLeave),\n onItemMouseEnter: combineEventHandlers(_this4.handleItemMouseEnter, null, item.props.onMouseEnter)\n })), (_objectSpread5 = {\n key: item.key || \"item-\".concat(index)\n }, _defineProperty(_objectSpread5, numericAxisName, axisObj[numericAxisName]), _defineProperty(_objectSpread5, cateAxisName, axisObj[cateAxisName]), _defineProperty(_objectSpread5, \"animationId\", updateId), _objectSpread5)),\n childIndex: parseChildIndex(item, props.children),\n item: item\n });\n }\n });\n return formatedItems;\n }\n }, {\n key: \"getCursorRectangle\",\n value: function getCursorRectangle() {\n var layout = this.props.layout;\n var _this$state12 = this.state,\n activeCoordinate = _this$state12.activeCoordinate,\n offset = _this$state12.offset,\n tooltipAxisBandSize = _this$state12.tooltipAxisBandSize;\n var halfSize = tooltipAxisBandSize / 2;\n return {\n stroke: 'none',\n fill: '#ccc',\n x: layout === 'horizontal' ? activeCoordinate.x - halfSize : offset.left + 0.5,\n y: layout === 'horizontal' ? offset.top + 0.5 : activeCoordinate.y - halfSize,\n width: layout === 'horizontal' ? tooltipAxisBandSize : offset.width - 1,\n height: layout === 'horizontal' ? offset.height - 1 : tooltipAxisBandSize\n };\n }\n }, {\n key: \"getCursorPoints\",\n value: function getCursorPoints() {\n var layout = this.props.layout;\n var _this$state13 = this.state,\n activeCoordinate = _this$state13.activeCoordinate,\n offset = _this$state13.offset;\n var x1, y1, x2, y2;\n\n if (layout === 'horizontal') {\n x1 = activeCoordinate.x;\n x2 = x1;\n y1 = offset.top;\n y2 = offset.top + offset.height;\n } else if (layout === 'vertical') {\n y1 = activeCoordinate.y;\n y2 = y1;\n x1 = offset.left;\n x2 = offset.left + offset.width;\n } else if (!_isNil(activeCoordinate.cx) || !_isNil(activeCoordinate.cy)) {\n if (layout === 'centric') {\n var cx = activeCoordinate.cx,\n cy = activeCoordinate.cy,\n innerRadius = activeCoordinate.innerRadius,\n outerRadius = activeCoordinate.outerRadius,\n angle = activeCoordinate.angle;\n var innerPoint = polarToCartesian(cx, cy, innerRadius, angle);\n var outerPoint = polarToCartesian(cx, cy, outerRadius, angle);\n x1 = innerPoint.x;\n y1 = innerPoint.y;\n x2 = outerPoint.x;\n y2 = outerPoint.y;\n } else {\n var _cx = activeCoordinate.cx,\n _cy = activeCoordinate.cy,\n radius = activeCoordinate.radius,\n startAngle = activeCoordinate.startAngle,\n endAngle = activeCoordinate.endAngle;\n var startPoint = polarToCartesian(_cx, _cy, radius, startAngle);\n var endPoint = polarToCartesian(_cx, _cy, radius, endAngle);\n return {\n points: [startPoint, endPoint],\n cx: _cx,\n cy: _cy,\n radius: radius,\n startAngle: startAngle,\n endAngle: endAngle\n };\n }\n }\n\n return [{\n x: x1,\n y: y1\n }, {\n x: x2,\n y: y2\n }];\n }\n }, {\n key: \"calculateTooltipPos\",\n value: function calculateTooltipPos(rangeObj) {\n var layout = this.props.layout;\n\n if (layout === 'horizontal') {\n return rangeObj.x;\n }\n\n if (layout === 'vertical') {\n return rangeObj.y;\n }\n\n if (layout === 'centric') {\n return rangeObj.angle;\n }\n\n return rangeObj.radius;\n }\n }, {\n key: \"inRange\",\n value: function inRange(x, y) {\n var layout = this.props.layout;\n\n if (layout === 'horizontal' || layout === 'vertical') {\n var offset = this.state.offset;\n var isInRange = x >= offset.left && x <= offset.left + offset.width && y >= offset.top && y <= offset.top + offset.height;\n return isInRange ? {\n x: x,\n y: y\n } : null;\n }\n\n var _this$state14 = this.state,\n angleAxisMap = _this$state14.angleAxisMap,\n radiusAxisMap = _this$state14.radiusAxisMap;\n\n if (angleAxisMap && radiusAxisMap) {\n var angleAxis = getAnyElementOfObject(angleAxisMap);\n return inRangeOfSector({\n x: x,\n y: y\n }, angleAxis);\n }\n\n return null;\n }\n }, {\n key: \"parseEventsOfWrapper\",\n value: function parseEventsOfWrapper() {\n var children = this.props.children;\n var tooltipItem = findChildByType(children, Tooltip);\n var tooltipEvents = tooltipItem && eventType === 'axis' ? {\n onMouseEnter: this.handleMouseEnter,\n onMouseMove: this.handleMouseMove,\n onMouseLeave: this.handleMouseLeave,\n onTouchMove: this.handleTouchMove,\n onTouchStart: this.handleTouchStart,\n onTouchEnd: this.handleTouchEnd\n } : {};\n var outerEvents = filterEventAttributes(this.props, this.handleOuterEvent);\n return _objectSpread({}, outerEvents, tooltipEvents);\n }\n /**\n * The AxisMaps are expensive to render on large data sets\n * so provide the ability to store them in state and only update them when necessary\n * they are dependent upon the start and end index of\n * the brush so it's important that this method is called _after_\n * the state is updated with any new start/end indices\n *\n * @param {Object} props The props object to be used for updating the axismaps\n * @param {Number} dataStartIndex The start index of the data series when a brush is applied\n * @param {Number} dataEndIndex The end index of the data series when a brush is applied\n * @param {Number} updateId The update id\n * @return {Object} state New state to set\n */\n\n }, {\n key: \"updateStateOfAxisMapsOffsetAndStackGroups\",\n value: function updateStateOfAxisMapsOffsetAndStackGroups(_ref8) {\n var _this5 = this;\n\n var props = _ref8.props,\n dataStartIndex = _ref8.dataStartIndex,\n dataEndIndex = _ref8.dataEndIndex,\n updateId = _ref8.updateId;\n\n if (!validateWidthHeight({\n props: props\n })) {\n return null;\n }\n\n var children = props.children,\n layout = props.layout,\n stackOffset = props.stackOffset,\n data = props.data,\n reverseStackOrder = props.reverseStackOrder;\n\n var _this$constructor$get2 = this.constructor.getAxisNameByLayout(layout),\n numericAxisName = _this$constructor$get2.numericAxisName,\n cateAxisName = _this$constructor$get2.cateAxisName;\n\n var graphicalItems = findAllByType(children, GraphicalChild);\n var stackGroups = getStackGroupsByAxisId(data, graphicalItems, \"\".concat(numericAxisName, \"Id\"), \"\".concat(cateAxisName, \"Id\"), stackOffset, reverseStackOrder);\n var axisObj = axisComponents.reduce(function (result, entry) {\n var name = \"\".concat(entry.axisType, \"Map\");\n return _objectSpread({}, result, _defineProperty({}, name, _this5.getAxisMap(props, _objectSpread({}, entry, {\n graphicalItems: graphicalItems,\n stackGroups: entry.axisType === numericAxisName && stackGroups,\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex\n }))));\n }, {});\n var offset = this.calculateOffset(_objectSpread({}, axisObj, {\n props: props,\n graphicalItems: graphicalItems\n }));\n Object.keys(axisObj).forEach(function (key) {\n axisObj[key] = formatAxisMap(props, axisObj[key], offset, key.replace('Map', ''), chartName);\n });\n var cateAxisMap = axisObj[\"\".concat(cateAxisName, \"Map\")];\n var ticksObj = this.tooltipTicksGenerator(cateAxisMap);\n var formatedGraphicalItems = this.getFormatItems(props, _objectSpread({}, axisObj, {\n dataStartIndex: dataStartIndex,\n dataEndIndex: dataEndIndex,\n updateId: updateId,\n graphicalItems: graphicalItems,\n stackGroups: stackGroups,\n offset: offset\n }));\n return _objectSpread({\n formatedGraphicalItems: formatedGraphicalItems,\n graphicalItems: graphicalItems,\n offset: offset,\n stackGroups: stackGroups\n }, ticksObj, axisObj);\n }\n /* eslint-disable no-underscore-dangle */\n\n }, {\n key: \"addListener\",\n value: function addListener() {\n eventCenter.on(SYNC_EVENT, this.handleReceiveSyncEvent);\n\n if (eventCenter.setMaxListeners && eventCenter._maxListeners) {\n eventCenter.setMaxListeners(eventCenter._maxListeners + 1);\n }\n }\n }, {\n key: \"removeListener\",\n value: function removeListener() {\n eventCenter.removeListener(SYNC_EVENT, this.handleReceiveSyncEvent);\n\n if (eventCenter.setMaxListeners && eventCenter._maxListeners) {\n eventCenter.setMaxListeners(eventCenter._maxListeners - 1);\n }\n }\n /**\n * Calculate the offset of main part in the svg element\n * @param {Object} props Latest props\n * @param {Array} graphicalItems The instances of item\n * @param {Object} xAxisMap The configuration of x-axis\n * @param {Object} yAxisMap The configuration of y-axis\n * @return {Object} The offset of main part in the svg element\n */\n\n }, {\n key: \"calculateOffset\",\n value: function calculateOffset(_ref9) {\n var props = _ref9.props,\n graphicalItems = _ref9.graphicalItems,\n _ref9$xAxisMap = _ref9.xAxisMap,\n xAxisMap = _ref9$xAxisMap === void 0 ? {} : _ref9$xAxisMap,\n _ref9$yAxisMap = _ref9.yAxisMap,\n yAxisMap = _ref9$yAxisMap === void 0 ? {} : _ref9$yAxisMap;\n var width = props.width,\n height = props.height,\n children = props.children;\n var margin = props.margin || {};\n var brushItem = findChildByType(children, Brush);\n var legendItem = findChildByType(children, Legend);\n var offsetH = Object.keys(yAxisMap).reduce(function (result, id) {\n var entry = yAxisMap[id];\n var orientation = entry.orientation;\n\n if (!entry.mirror && !entry.hide) {\n return _objectSpread({}, result, _defineProperty({}, orientation, result[orientation] + entry.width));\n }\n\n return result;\n }, {\n left: margin.left || 0,\n right: margin.right || 0\n });\n var offsetV = Object.keys(xAxisMap).reduce(function (result, id) {\n var entry = xAxisMap[id];\n var orientation = entry.orientation;\n\n if (!entry.mirror && !entry.hide) {\n return _objectSpread({}, result, _defineProperty({}, orientation, result[orientation] + entry.height));\n }\n\n return result;\n }, {\n top: margin.top || 0,\n bottom: margin.bottom || 0\n });\n\n var offset = _objectSpread({}, offsetV, offsetH);\n\n var brushBottom = offset.bottom;\n\n if (brushItem) {\n offset.bottom += brushItem.props.height || Brush.defaultProps.height;\n }\n\n if (legendItem && this.legendInstance) {\n var legendBox = this.legendInstance.getBBox();\n offset = appendOffsetOfLegend(offset, graphicalItems, props, legendBox);\n }\n\n return _objectSpread({\n brushBottom: brushBottom\n }, offset, {\n width: width - offset.left - offset.right,\n height: height - offset.top - offset.bottom\n });\n }\n }, {\n key: \"triggerSyncEvent\",\n value: function triggerSyncEvent(data) {\n var syncId = this.props.syncId;\n\n if (!_isNil(syncId)) {\n eventCenter.emit(SYNC_EVENT, syncId, this.uniqueChartId, data);\n }\n }\n }, {\n key: \"filterFormatItem\",\n value: function filterFormatItem(item, displayName, childIndex) {\n var formatedGraphicalItems = this.state.formatedGraphicalItems;\n\n for (var i = 0, len = formatedGraphicalItems.length; i < len; i++) {\n var entry = formatedGraphicalItems[i];\n\n if (entry.item === item || entry.props.key === item.key || displayName === getDisplayName(entry.item.type) && childIndex === entry.childIndex) {\n return entry;\n }\n }\n\n return null;\n }\n }, {\n key: \"renderAxis\",\n\n /**\n * Draw axis\n * @param {Object} axisOptions The options of axis\n * @param {Object} element The axis element\n * @param {String} displayName The display name of axis\n * @param {Number} index The index of element\n * @return {ReactElement} The instance of x-axes\n */\n value: function renderAxis(axisOptions, element, displayName, index) {\n var _this$props5 = this.props,\n width = _this$props5.width,\n height = _this$props5.height;\n return React.createElement(CartesianAxis, _extends({}, axisOptions, {\n className: \"recharts-\".concat(axisOptions.axisType, \" \").concat(axisOptions.axisType),\n key: element.key || \"\".concat(displayName, \"-\").concat(index),\n viewBox: {\n x: 0,\n y: 0,\n width: width,\n height: height\n },\n ticksGenerator: this.axesTicksGenerator\n }));\n }\n /**\n * Draw grid\n * @param {ReactElement} element the grid item\n * @return {ReactElement} The instance of grid\n */\n\n }, {\n key: \"renderLegend\",\n\n /**\n * Draw legend\n * @return {ReactElement} The instance of Legend\n */\n value: function renderLegend() {\n var _this6 = this;\n\n var formatedGraphicalItems = this.state.formatedGraphicalItems;\n var _this$props6 = this.props,\n children = _this$props6.children,\n width = _this$props6.width,\n height = _this$props6.height;\n var margin = this.props.margin || {};\n var legendWidth = width - (margin.left || 0) - (margin.right || 0);\n var legendHeight = height - (margin.top || 0) - (margin.bottom || 0);\n var props = getLegendProps({\n children: children,\n formatedGraphicalItems: formatedGraphicalItems,\n legendWidth: legendWidth,\n legendHeight: legendHeight,\n legendContent: legendContent\n });\n\n if (!props) {\n return null;\n }\n\n var item = props.item,\n otherProps = _objectWithoutProperties(props, [\"item\"]);\n\n return cloneElement(item, _objectSpread({}, otherProps, {\n chartWidth: width,\n chartHeight: height,\n margin: margin,\n ref: function ref(legend) {\n _this6.legendInstance = legend;\n },\n onBBoxUpdate: this.handleLegendBBoxUpdate\n }));\n }\n /**\n * Draw Tooltip\n * @return {ReactElement} The instance of Tooltip\n */\n\n }, {\n key: \"renderTooltip\",\n value: function renderTooltip() {\n var children = this.props.children;\n var tooltipItem = findChildByType(children, Tooltip);\n\n if (!tooltipItem) {\n return null;\n }\n\n var _this$state15 = this.state,\n isTooltipActive = _this$state15.isTooltipActive,\n activeCoordinate = _this$state15.activeCoordinate,\n activePayload = _this$state15.activePayload,\n activeLabel = _this$state15.activeLabel,\n offset = _this$state15.offset;\n return cloneElement(tooltipItem, {\n viewBox: _objectSpread({}, offset, {\n x: offset.left,\n y: offset.top\n }),\n active: isTooltipActive,\n label: activeLabel,\n payload: isTooltipActive ? activePayload : [],\n coordinate: activeCoordinate\n });\n }\n }, {\n key: \"renderActivePoints\",\n value: function renderActivePoints(_ref10) {\n var item = _ref10.item,\n activePoint = _ref10.activePoint,\n basePoint = _ref10.basePoint,\n childIndex = _ref10.childIndex,\n isRange = _ref10.isRange;\n var result = [];\n var key = item.props.key;\n var _item$item$props2 = item.item.props,\n activeDot = _item$item$props2.activeDot,\n dataKey = _item$item$props2.dataKey;\n\n var dotProps = _objectSpread({\n index: childIndex,\n dataKey: dataKey,\n cx: activePoint.x,\n cy: activePoint.y,\n r: 4,\n fill: getMainColorOfGraphicItem(item.item),\n strokeWidth: 2,\n stroke: '#fff',\n payload: activePoint.payload,\n value: activePoint.value,\n key: \"\".concat(key, \"-activePoint-\").concat(childIndex)\n }, getPresentationAttributes(activeDot), filterEventAttributes(activeDot));\n\n result.push(this.constructor.renderActiveDot(activeDot, dotProps, childIndex));\n\n if (basePoint) {\n result.push(this.constructor.renderActiveDot(activeDot, _objectSpread({}, dotProps, {\n cx: basePoint.x,\n cy: basePoint.y,\n key: \"\".concat(key, \"-basePoint-\").concat(childIndex)\n }), childIndex));\n } else if (isRange) {\n result.push(null);\n }\n\n return result;\n }\n }, {\n key: \"renderClipPath\",\n value: function renderClipPath() {\n var clipPathId = this.clipPathId;\n var _this$state$offset = this.state.offset,\n left = _this$state$offset.left,\n top = _this$state$offset.top,\n height = _this$state$offset.height,\n width = _this$state$offset.width;\n return React.createElement(\"defs\", null, React.createElement(\"clipPath\", {\n id: clipPathId\n }, React.createElement(\"rect\", {\n x: left,\n y: top,\n height: height,\n width: width\n })));\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this7 = this;\n\n if (!validateWidthHeight(this)) {\n return null;\n }\n\n var _this$props7 = this.props,\n children = _this$props7.children,\n className = _this$props7.className,\n width = _this$props7.width,\n height = _this$props7.height,\n style = _this$props7.style,\n compact = _this$props7.compact,\n others = _objectWithoutProperties(_this$props7, [\"children\", \"className\", \"width\", \"height\", \"style\", \"compact\"]);\n\n var attrs = getPresentationAttributes(others);\n var map = {\n CartesianGrid: {\n handler: this.renderGrid,\n once: true\n },\n ReferenceArea: {\n handler: this.renderReferenceElement\n },\n ReferenceLine: {\n handler: this.renderReferenceElement\n },\n ReferenceDot: {\n handler: this.renderReferenceElement\n },\n XAxis: {\n handler: this.renderXAxis\n },\n YAxis: {\n handler: this.renderYAxis\n },\n Brush: {\n handler: this.renderBrush,\n once: true\n },\n Bar: {\n handler: this.renderGraphicChild\n },\n Line: {\n handler: this.renderGraphicChild\n },\n Area: {\n handler: this.renderGraphicChild\n },\n Radar: {\n handler: this.renderGraphicChild\n },\n RadialBar: {\n handler: this.renderGraphicChild\n },\n Scatter: {\n handler: this.renderGraphicChild\n },\n Pie: {\n handler: this.renderGraphicChild\n },\n Funnel: {\n handler: this.renderGraphicChild\n },\n Tooltip: {\n handler: this.renderCursor,\n once: true\n },\n PolarGrid: {\n handler: this.renderPolarGrid,\n once: true\n },\n PolarAngleAxis: {\n handler: this.renderPolarAxis\n },\n PolarRadiusAxis: {\n handler: this.renderPolarAxis\n }\n }; // The \"compact\" mode is mainly used as the panorama within Brush\n\n if (compact) {\n return React.createElement(Surface, _extends({}, attrs, {\n width: width,\n height: height\n }), this.renderClipPath(), renderByOrder(children, map));\n }\n\n var events = this.parseEventsOfWrapper();\n return React.createElement(\"div\", _extends({\n className: classNames('recharts-wrapper', className),\n style: _objectSpread({\n position: 'relative',\n cursor: 'default',\n width: width,\n height: height\n }, style)\n }, events, {\n ref: function ref(node) {\n _this7.container = node;\n }\n }), React.createElement(Surface, _extends({}, attrs, {\n width: width,\n height: height\n }), this.renderClipPath(), renderByOrder(children, map)), this.renderLegend(), this.renderTooltip());\n }\n }], [{\n key: \"getAxisNameByLayout\",\n value: function getAxisNameByLayout(layout) {\n if (layout === 'horizontal') {\n return {\n numericAxisName: 'yAxis',\n cateAxisName: 'xAxis'\n };\n }\n\n if (layout === 'vertical') {\n return {\n numericAxisName: 'xAxis',\n cateAxisName: 'yAxis'\n };\n }\n\n if (layout === 'centric') {\n return {\n numericAxisName: 'radiusAxis',\n cateAxisName: 'angleAxis'\n };\n }\n\n return {\n numericAxisName: 'angleAxis',\n cateAxisName: 'radiusAxis'\n };\n }\n }, {\n key: \"renderActiveDot\",\n value: function renderActiveDot(option, props) {\n var dot;\n\n if (isValidElement(option)) {\n dot = cloneElement(option, props);\n } else if (_isFunction(option)) {\n dot = option(props);\n } else {\n dot = React.createElement(Dot, props);\n }\n\n return React.createElement(Layer, {\n className: \"recharts-active-dot\",\n key: props.key\n }, dot);\n }\n }]);\n\n return CategoricalChartWrapper;\n }(Component);\n\n CategoricalChartWrapper.displayName = chartName;\n CategoricalChartWrapper.propTypes = _objectSpread({\n syncId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n compact: PropTypes.bool,\n width: PropTypes.number,\n height: PropTypes.number,\n data: PropTypes.arrayOf(PropTypes.object),\n layout: PropTypes.oneOf(['horizontal', 'vertical']),\n stackOffset: PropTypes.oneOf(['sign', 'expand', 'none', 'wiggle', 'silhouette']),\n throttleDelay: PropTypes.number,\n margin: PropTypes.shape({\n top: PropTypes.number,\n right: PropTypes.number,\n bottom: PropTypes.number,\n left: PropTypes.number\n }),\n barCategoryGap: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n barGap: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n barSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n maxBarSize: PropTypes.number,\n style: PropTypes.object,\n className: PropTypes.string,\n children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),\n defaultShowTooltip: PropTypes.bool,\n onClick: PropTypes.func,\n onMouseLeave: PropTypes.func,\n onMouseEnter: PropTypes.func,\n onMouseMove: PropTypes.func,\n onMouseDown: PropTypes.func,\n onMouseUp: PropTypes.func,\n reverseStackOrder: PropTypes.bool,\n id: PropTypes.string\n }, propTypes);\n CategoricalChartWrapper.defaultProps = _objectSpread({\n layout: 'horizontal',\n stackOffset: 'none',\n barCategoryGap: '10%',\n barGap: 4,\n margin: {\n top: 5,\n right: 5,\n bottom: 5,\n left: 5\n },\n reverseStackOrder: false\n }, defaultProps);\n\n CategoricalChartWrapper.createDefaultState = function (props) {\n var children = props.children,\n defaultShowTooltip = props.defaultShowTooltip;\n var brushItem = findChildByType(children, Brush);\n var startIndex = brushItem && brushItem.props && brushItem.props.startIndex || 0;\n var endIndex = brushItem && brushItem.props && brushItem.props.endIndex || props.data && props.data.length - 1 || 0;\n return {\n chartX: 0,\n chartY: 0,\n dataStartIndex: startIndex,\n dataEndIndex: endIndex,\n activeTooltipIndex: -1,\n isTooltipActive: !_isNil(defaultShowTooltip) ? defaultShowTooltip : false\n };\n };\n\n CategoricalChartWrapper.hasBar = function (graphicalItems) {\n if (!graphicalItems || !graphicalItems.length) {\n return false;\n }\n\n return graphicalItems.some(function (item) {\n var name = getDisplayName(item && item.type);\n return name && name.indexOf('Bar') >= 0;\n });\n };\n\n CategoricalChartWrapper.getDisplayedData = function (props, _ref11, item) {\n var graphicalItems = _ref11.graphicalItems,\n dataStartIndex = _ref11.dataStartIndex,\n dataEndIndex = _ref11.dataEndIndex;\n var itemsData = (graphicalItems || []).reduce(function (result, child) {\n var itemData = child.props.data;\n\n if (itemData && itemData.length) {\n return _toConsumableArray(result).concat(_toConsumableArray(itemData));\n }\n\n return result;\n }, []);\n\n if (itemsData && itemsData.length > 0) {\n return itemsData;\n }\n\n if (item && item.props && item.props.data && item.props.data.length > 0) {\n return item.props.data;\n }\n\n var data = props.data;\n\n if (data && data.length && isNumber(dataStartIndex) && isNumber(dataEndIndex)) {\n return data.slice(dataStartIndex, dataEndIndex + 1);\n }\n\n return [];\n };\n\n return CategoricalChartWrapper;\n};\n\nexport default generateCategoricalChart;", + "/**\n * @fileOverview Area Chart\n */\nimport generateCategoricalChart from './generateCategoricalChart';\nimport Area from '../cartesian/Area';\nimport XAxis from '../cartesian/XAxis';\nimport YAxis from '../cartesian/YAxis';\nimport { formatAxisMap } from '../util/CartesianUtils';\nexport default generateCategoricalChart({\n chartName: 'AreaChart',\n GraphicalChild: Area,\n axisComponents: [{\n axisType: 'xAxis',\n AxisComp: XAxis\n }, {\n axisType: 'yAxis',\n AxisComp: YAxis\n }],\n formatAxisMap: formatAxisMap\n});", + "import _isObject from \"lodash/isObject\";\nimport _isFunction from \"lodash/isFunction\";\nimport _isNil from \"lodash/isNil\";\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nimport React, { cloneElement, isValidElement } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Text from './Text';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes, findAllByType } from '../util/ReactUtils';\nimport { isNumOrStr, isNumber, isPercent, getPercentValue, uniqueId, mathSign } from '../util/DataUtils';\nimport { polarToCartesian } from '../util/PolarUtils';\nvar cartesianViewBoxShape = PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number\n});\nvar polarViewBoxShape = PropTypes.shape({\n cx: PropTypes.number,\n cy: PropTypes.number,\n innerRadius: PropTypes.number,\n outerRadius: PropTypes.number,\n startAngle: PropTypes.number,\n endAngle: PropTypes.number\n});\n\nvar propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n viewBox: PropTypes.oneOfType([cartesianViewBoxShape, polarViewBoxShape]),\n formatter: PropTypes.func,\n value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n offset: PropTypes.number,\n position: PropTypes.oneOf(['top', 'left', 'right', 'bottom', 'inside', 'outside', 'insideLeft', 'insideRight', 'insideTop', 'insideBottom', 'insideTopLeft', 'insideBottomLeft', 'insideTopRight', 'insideBottomRight', 'insideStart', 'insideEnd', 'end', 'center', 'centerTop', 'centerBottom']),\n children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),\n className: PropTypes.string,\n content: PropTypes.oneOfType([PropTypes.element, PropTypes.func])\n});\n\nvar defaultProps = {\n offset: 5\n};\n\nvar getLabel = function getLabel(props) {\n var value = props.value,\n formatter = props.formatter;\n var label = _isNil(props.children) ? value : props.children;\n\n if (_isFunction(formatter)) {\n return formatter(label);\n }\n\n return label;\n};\n\nvar getDeltaAngle = function getDeltaAngle(startAngle, endAngle) {\n var sign = mathSign(endAngle - startAngle);\n var deltaAngle = Math.min(Math.abs(endAngle - startAngle), 360);\n return sign * deltaAngle;\n};\n\nvar renderRadialLabel = function renderRadialLabel(labelProps, label, attrs) {\n var position = labelProps.position,\n viewBox = labelProps.viewBox,\n offset = labelProps.offset,\n className = labelProps.className;\n var cx = viewBox.cx,\n cy = viewBox.cy,\n innerRadius = viewBox.innerRadius,\n outerRadius = viewBox.outerRadius,\n startAngle = viewBox.startAngle,\n endAngle = viewBox.endAngle,\n clockWise = viewBox.clockWise;\n var radius = (innerRadius + outerRadius) / 2;\n var deltaAngle = getDeltaAngle(startAngle, endAngle);\n var sign = deltaAngle >= 0 ? 1 : -1;\n var labelAngle, direction;\n\n if (position === 'insideStart') {\n labelAngle = startAngle + sign * offset;\n direction = clockWise;\n } else if (position === 'insideEnd') {\n labelAngle = endAngle - sign * offset;\n direction = !clockWise;\n } else if (position === 'end') {\n labelAngle = endAngle + sign * offset;\n direction = clockWise;\n }\n\n direction = deltaAngle <= 0 ? direction : !direction;\n var startPoint = polarToCartesian(cx, cy, radius, labelAngle);\n var endPoint = polarToCartesian(cx, cy, radius, labelAngle + (direction ? 1 : -1) * 359);\n var path = \"M\".concat(startPoint.x, \",\").concat(startPoint.y, \"\\n A\").concat(radius, \",\").concat(radius, \",0,1,\").concat(direction ? 0 : 1, \",\\n \").concat(endPoint.x, \",\").concat(endPoint.y);\n var id = _isNil(labelProps.id) ? uniqueId('recharts-radial-line-') : labelProps.id;\n return React.createElement(\"text\", _extends({}, attrs, {\n dominantBaseline: \"central\",\n className: classNames('recharts-radial-bar-label', className)\n }), React.createElement(\"defs\", null, React.createElement(\"path\", {\n id: id,\n d: path\n })), React.createElement(\"textPath\", {\n xlinkHref: \"#\".concat(id)\n }, label));\n};\n\nvar getAttrsOfPolarLabel = function getAttrsOfPolarLabel(props) {\n var viewBox = props.viewBox,\n offset = props.offset,\n position = props.position;\n var cx = viewBox.cx,\n cy = viewBox.cy,\n innerRadius = viewBox.innerRadius,\n outerRadius = viewBox.outerRadius,\n startAngle = viewBox.startAngle,\n endAngle = viewBox.endAngle;\n var midAngle = (startAngle + endAngle) / 2;\n\n if (position === 'outside') {\n var _polarToCartesian = polarToCartesian(cx, cy, outerRadius + offset, midAngle),\n _x = _polarToCartesian.x,\n _y = _polarToCartesian.y;\n\n return {\n x: _x,\n y: _y,\n textAnchor: _x >= cx ? 'start' : 'end',\n verticalAnchor: 'middle'\n };\n }\n\n if (position === 'center') {\n return {\n x: cx,\n y: cy,\n textAnchor: 'middle',\n verticalAnchor: 'middle'\n };\n }\n\n if (position === 'centerTop') {\n return {\n x: cx,\n y: cy,\n textAnchor: 'middle',\n verticalAnchor: 'start'\n };\n }\n\n if (position === 'centerBottom') {\n return {\n x: cx,\n y: cy,\n textAnchor: 'middle',\n verticalAnchor: 'end'\n };\n }\n\n var r = (innerRadius + outerRadius) / 2;\n\n var _polarToCartesian2 = polarToCartesian(cx, cy, r, midAngle),\n x = _polarToCartesian2.x,\n y = _polarToCartesian2.y;\n\n return {\n x: x,\n y: y,\n textAnchor: 'middle',\n verticalAnchor: 'middle'\n };\n};\n\nvar getAttrsOfCartesianLabel = function getAttrsOfCartesianLabel(props) {\n var viewBox = props.viewBox,\n offset = props.offset,\n position = props.position;\n var x = viewBox.x,\n y = viewBox.y,\n width = viewBox.width,\n height = viewBox.height;\n var sign = height >= 0 ? 1 : -1;\n\n if (position === 'top') {\n return {\n x: x + width / 2,\n y: y - sign * offset,\n textAnchor: 'middle',\n verticalAnchor: sign > 0 ? 'end' : 'start'\n };\n }\n\n if (position === 'bottom') {\n return {\n x: x + width / 2,\n y: y + height + sign * offset,\n textAnchor: 'middle',\n verticalAnchor: 'start'\n };\n }\n\n if (position === 'left') {\n return {\n x: x - offset,\n y: y + height / 2,\n textAnchor: 'end',\n verticalAnchor: 'middle'\n };\n }\n\n if (position === 'right') {\n return {\n x: x + width + offset,\n y: y + height / 2,\n textAnchor: 'start',\n verticalAnchor: 'middle'\n };\n }\n\n if (position === 'insideLeft') {\n return {\n x: x + offset,\n y: y + height / 2,\n textAnchor: 'start',\n verticalAnchor: 'middle'\n };\n }\n\n if (position === 'insideRight') {\n return {\n x: x + width - offset,\n y: y + height / 2,\n textAnchor: 'end',\n verticalAnchor: 'middle'\n };\n }\n\n if (position === 'insideTop') {\n return {\n x: x + width / 2,\n y: y + sign * offset,\n textAnchor: 'middle',\n verticalAnchor: 'start'\n };\n }\n\n if (position === 'insideBottom') {\n return {\n x: x + width / 2,\n y: y + height - sign * offset,\n textAnchor: 'middle',\n verticalAnchor: 'end'\n };\n }\n\n if (position === 'insideTopLeft') {\n return {\n x: x + offset,\n y: y + sign * offset,\n textAnchor: 'start',\n verticalAnchor: 'start'\n };\n }\n\n if (position === 'insideTopRight') {\n return {\n x: x + width - offset,\n y: y + sign * offset,\n textAnchor: 'end',\n verticalAnchor: 'start'\n };\n }\n\n if (position === 'insideBottomLeft') {\n return {\n x: x + offset,\n y: y + height - sign * offset,\n textAnchor: 'start',\n verticalAnchor: 'end'\n };\n }\n\n if (position === 'insideBottomRight') {\n return {\n x: x + width - offset,\n y: y + height - sign * offset,\n textAnchor: 'end',\n verticalAnchor: 'end'\n };\n }\n\n if (_isObject(position) && (isNumber(position.x) || isPercent(position.x)) && (isNumber(position.y) || isPercent(position.y))) {\n return {\n x: x + getPercentValue(position.x, width),\n y: y + getPercentValue(position.y, height),\n textAnchor: 'end',\n verticalAnchor: 'end'\n };\n }\n\n return {\n x: x + width / 2,\n y: y + height / 2,\n textAnchor: 'middle',\n verticalAnchor: 'middle'\n };\n};\n\nvar isPolar = function isPolar(viewBox) {\n return isNumber(viewBox.cx);\n};\n\nfunction Label(props) {\n var viewBox = props.viewBox,\n position = props.position,\n value = props.value,\n children = props.children,\n content = props.content,\n _props$className = props.className,\n className = _props$className === void 0 ? '' : _props$className;\n\n if (!viewBox || _isNil(value) && _isNil(children) && !isValidElement(content) && !_isFunction(content)) {\n return null;\n }\n\n if (isValidElement(content)) {\n return cloneElement(content, props);\n }\n\n var label;\n\n if (_isFunction(content)) {\n label = content(props);\n\n if (isValidElement(label)) {\n return label;\n }\n } else {\n label = getLabel(props);\n }\n\n var isPolarLabel = isPolar(viewBox);\n var attrs = getPresentationAttributes(props);\n\n if (isPolarLabel && (position === 'insideStart' || position === 'insideEnd' || position === 'end')) {\n return renderRadialLabel(props, label, attrs);\n }\n\n var positionAttrs = isPolarLabel ? getAttrsOfPolarLabel(props) : getAttrsOfCartesianLabel(props);\n return React.createElement(Text, _extends({\n className: classNames('recharts-label', className)\n }, attrs, positionAttrs), label);\n}\n\nLabel.displayName = 'Label';\nLabel.defaultProps = defaultProps;\nLabel.propTypes = propTypes;\n\nvar parseViewBox = function parseViewBox(props) {\n var cx = props.cx,\n cy = props.cy,\n angle = props.angle,\n startAngle = props.startAngle,\n endAngle = props.endAngle,\n r = props.r,\n radius = props.radius,\n innerRadius = props.innerRadius,\n outerRadius = props.outerRadius,\n x = props.x,\n y = props.y,\n top = props.top,\n left = props.left,\n width = props.width,\n height = props.height,\n clockWise = props.clockWise;\n\n if (isNumber(width) && isNumber(height)) {\n if (isNumber(x) && isNumber(y)) {\n return {\n x: x,\n y: y,\n width: width,\n height: height\n };\n }\n\n if (isNumber(top) && isNumber(left)) {\n return {\n x: top,\n y: left,\n width: width,\n height: height\n };\n }\n }\n\n if (isNumber(x) && isNumber(y)) {\n return {\n x: x,\n y: y,\n width: 0,\n height: 0\n };\n }\n\n if (isNumber(cx) && isNumber(cy)) {\n return {\n cx: cx,\n cy: cy,\n startAngle: startAngle || angle || 0,\n endAngle: endAngle || angle || 0,\n innerRadius: innerRadius || 0,\n outerRadius: outerRadius || radius || r || 0,\n clockWise: clockWise\n };\n }\n\n if (props.viewBox) {\n return props.viewBox;\n }\n\n return {};\n};\n\nvar parseLabel = function parseLabel(label, viewBox) {\n if (!label) {\n return null;\n }\n\n if (label === true) {\n return React.createElement(Label, {\n key: \"label-implicit\",\n viewBox: viewBox\n });\n }\n\n if (isNumOrStr(label)) {\n return React.createElement(Label, {\n key: \"label-implicit\",\n viewBox: viewBox,\n value: label\n });\n }\n\n if (isValidElement(label) || _isFunction(label)) {\n return React.createElement(Label, {\n key: \"label-implicit\",\n content: label,\n viewBox: viewBox\n });\n }\n\n if (_isObject(label)) {\n return React.createElement(Label, _extends({\n viewBox: viewBox\n }, label, {\n key: \"label-implicit\"\n }));\n }\n\n return null;\n};\n\nvar renderCallByParent = function renderCallByParent(parentProps, viewBox) {\n var ckeckPropsLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n if (!parentProps || !parentProps.children && ckeckPropsLabel && !parentProps.label) {\n return null;\n }\n\n var children = parentProps.children;\n var parentViewBox = parseViewBox(parentProps);\n var explicitChilren = findAllByType(children, Label).map(function (child, index) {\n return cloneElement(child, {\n viewBox: viewBox || parentViewBox,\n key: \"label-\".concat(index)\n });\n });\n\n if (!ckeckPropsLabel) {\n return explicitChilren;\n }\n\n var implicitLabel = parseLabel(parentProps.label, viewBox || parentViewBox);\n return [implicitLabel].concat(_toConsumableArray(explicitChilren));\n};\n\nLabel.parseViewBox = parseViewBox;\nLabel.renderCallByParent = renderCallByParent;\nexport default Label;", + "import _isObject from \"lodash/isObject\";\nimport _isFunction from \"lodash/isFunction\";\nimport _isNil from \"lodash/isNil\";\nimport _last from \"lodash/last\";\nimport _isArray from \"lodash/isArray\";\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nimport React, { cloneElement } from 'react';\nimport PropTypes from 'prop-types';\nimport Label from './Label';\nimport Layer from '../container/Layer';\nimport { getPresentationAttributes, findAllByType } from '../util/ReactUtils';\nimport { getValueByDataKey } from '../util/ChartUtils';\nvar propTypes = {\n id: PropTypes.string,\n data: PropTypes.arrayOf(PropTypes.object),\n valueAccessor: PropTypes.func,\n clockWise: PropTypes.bool,\n dataKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func])\n};\nvar defaultProps = {\n valueAccessor: function valueAccessor(entry) {\n return _isArray(entry.value) ? _last(entry.value) : entry.value;\n }\n};\n\nfunction LabelList(props) {\n var data = props.data,\n valueAccessor = props.valueAccessor,\n dataKey = props.dataKey,\n clockWise = props.clockWise,\n id = props.id,\n others = _objectWithoutProperties(props, [\"data\", \"valueAccessor\", \"dataKey\", \"clockWise\", \"id\"]);\n\n if (!data || !data.length) {\n return null;\n }\n\n return React.createElement(Layer, {\n className: \"recharts-label-list\"\n }, data.map(function (entry, index) {\n var value = _isNil(dataKey) ? valueAccessor(entry, index) : getValueByDataKey(entry && entry.payload, dataKey);\n var idProps = _isNil(id) ? {} : {\n id: \"\".concat(id, \"-\").concat(index)\n };\n return React.createElement(Label, _extends({}, getPresentationAttributes(entry), others, idProps, {\n index: index,\n value: value,\n viewBox: Label.parseViewBox(_isNil(clockWise) ? entry : _objectSpread({}, entry, {\n clockWise: clockWise\n })),\n key: \"label-\".concat(index)\n }));\n }));\n}\n\nLabelList.propTypes = propTypes;\nLabelList.displayName = 'LabelList';\n\nvar parseLabelList = function parseLabelList(label, data) {\n if (!label) {\n return null;\n }\n\n if (label === true) {\n return React.createElement(LabelList, {\n key: \"labelList-implicit\",\n data: data\n });\n }\n\n if (React.isValidElement(label) || _isFunction(label)) {\n return React.createElement(LabelList, {\n key: \"labelList-implicit\",\n data: data,\n content: label\n });\n }\n\n if (_isObject(label)) {\n return React.createElement(LabelList, _extends({\n data: data\n }, label, {\n key: \"labelList-implicit\"\n }));\n }\n\n return null;\n};\n\nvar renderCallByParent = function renderCallByParent(parentProps, data) {\n var ckeckPropsLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n if (!parentProps || !parentProps.children && ckeckPropsLabel && !parentProps.label) {\n return null;\n }\n\n var children = parentProps.children;\n var explicitChilren = findAllByType(children, LabelList).map(function (child, index) {\n return cloneElement(child, {\n data: data,\n key: \"labelList-\".concat(index)\n });\n });\n\n if (!ckeckPropsLabel) {\n return explicitChilren;\n }\n\n var implicitLabelList = parseLabelList(parentProps.label, data);\n return [implicitLabelList].concat(_toConsumableArray(explicitChilren));\n};\n\nLabelList.renderCallByParent = renderCallByParent;\nLabelList.defaultProps = defaultProps;\nexport default LabelList;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Default Legend Content\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport Surface from '../container/Surface';\nimport Symbols from '../shape/Symbols';\nimport { filterEventsOfChild, LEGEND_TYPES } from '../util/ReactUtils';\nvar SIZE = 32;\nvar ICON_TYPES = LEGEND_TYPES.filter(function (type) {\n return type !== 'none';\n});\n\nvar DefaultLegendContent = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(DefaultLegendContent, _Component);\n\n function DefaultLegendContent() {\n _classCallCheck(this, DefaultLegendContent);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(DefaultLegendContent).apply(this, arguments));\n }\n\n _createClass(DefaultLegendContent, [{\n key: \"renderIcon\",\n\n /**\n * Render the path of icon\n * @param {Object} data Data of each legend item\n * @return {String} Path element\n */\n value: function renderIcon(data) {\n var inactiveColor = this.props.inactiveColor;\n var halfSize = SIZE / 2;\n var sixthSize = SIZE / 6;\n var thirdSize = SIZE / 3;\n var color = data.inactive ? inactiveColor : data.color;\n\n if (data.type === 'plainline') {\n return React.createElement(\"line\", {\n strokeWidth: 4,\n fill: \"none\",\n stroke: color,\n strokeDasharray: data.payload.strokeDasharray,\n x1: 0,\n y1: halfSize,\n x2: SIZE,\n y2: halfSize,\n className: \"recharts-legend-icon\"\n });\n }\n\n if (data.type === 'line') {\n return React.createElement(\"path\", {\n strokeWidth: 4,\n fill: \"none\",\n stroke: color,\n d: \"M0,\".concat(halfSize, \"h\").concat(thirdSize, \"\\n A\").concat(sixthSize, \",\").concat(sixthSize, \",0,1,1,\").concat(2 * thirdSize, \",\").concat(halfSize, \"\\n H\").concat(SIZE, \"M\").concat(2 * thirdSize, \",\").concat(halfSize, \"\\n A\").concat(sixthSize, \",\").concat(sixthSize, \",0,1,1,\").concat(thirdSize, \",\").concat(halfSize),\n className: \"recharts-legend-icon\"\n });\n }\n\n if (data.type === 'rect') {\n return React.createElement(\"path\", {\n stroke: \"none\",\n fill: color,\n d: \"M0,\".concat(SIZE / 8, \"h\").concat(SIZE, \"v\").concat(SIZE * 3 / 4, \"h\").concat(-SIZE, \"z\"),\n className: \"recharts-legend-icon\"\n });\n }\n\n return React.createElement(Symbols, {\n fill: color,\n cx: halfSize,\n cy: halfSize,\n size: SIZE,\n sizeType: \"diameter\",\n type: data.type\n });\n }\n /**\n * Draw items of legend\n * @return {ReactElement} Items\n */\n\n }, {\n key: \"renderItems\",\n value: function renderItems() {\n var _this = this;\n\n var _this$props = this.props,\n payload = _this$props.payload,\n iconSize = _this$props.iconSize,\n layout = _this$props.layout,\n formatter = _this$props.formatter;\n var viewBox = {\n x: 0,\n y: 0,\n width: SIZE,\n height: SIZE\n };\n var itemStyle = {\n display: layout === 'horizontal' ? 'inline-block' : 'block',\n marginRight: 10\n };\n var svgStyle = {\n display: 'inline-block',\n verticalAlign: 'middle',\n marginRight: 4\n };\n return payload.map(function (entry, i) {\n var _classNames;\n\n var finalFormatter = entry.formatter || formatter;\n var className = classNames((_classNames = {\n 'recharts-legend-item': true\n }, _defineProperty(_classNames, \"legend-item-\".concat(i), true), _defineProperty(_classNames, \"inactive\", entry.inactive), _classNames));\n\n if (entry.type === 'none') {\n return null;\n }\n\n return React.createElement(\"li\", _extends({\n className: className,\n style: itemStyle,\n key: \"legend-item-\".concat(i)\n }, filterEventsOfChild(_this.props, entry, i)), React.createElement(Surface, {\n width: iconSize,\n height: iconSize,\n viewBox: viewBox,\n style: svgStyle\n }, _this.renderIcon(entry)), React.createElement(\"span\", {\n className: \"recharts-legend-item-text\"\n }, finalFormatter ? finalFormatter(entry.value, entry, i) : entry.value));\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n payload = _this$props2.payload,\n layout = _this$props2.layout,\n align = _this$props2.align;\n\n if (!payload || !payload.length) {\n return null;\n }\n\n var finalStyle = {\n padding: 0,\n margin: 0,\n textAlign: layout === 'horizontal' ? align : 'left'\n };\n return React.createElement(\"ul\", {\n className: \"recharts-default-legend\",\n style: finalStyle\n }, this.renderItems());\n }\n }]);\n\n return DefaultLegendContent;\n}(Component), _class2.displayName = 'Legend', _class2.propTypes = {\n content: PropTypes.element,\n iconSize: PropTypes.number,\n iconType: PropTypes.oneOf(ICON_TYPES),\n layout: PropTypes.oneOf(['horizontal', 'vertical']),\n align: PropTypes.oneOf(['center', 'left', 'right']),\n verticalAlign: PropTypes.oneOf(['top', 'bottom', 'middle']),\n payload: PropTypes.arrayOf(PropTypes.shape({\n value: PropTypes.any,\n id: PropTypes.any,\n type: PropTypes.oneOf(LEGEND_TYPES)\n })),\n inactiveColor: PropTypes.string,\n formatter: PropTypes.func,\n onMouseEnter: PropTypes.func,\n onMouseLeave: PropTypes.func,\n onClick: PropTypes.func\n}, _class2.defaultProps = {\n iconSize: 14,\n layout: 'horizontal',\n align: 'center',\n verticalAlign: 'middle',\n inactiveColor: '#ccc'\n}, _temp)) || _class;\n\nexport default DefaultLegendContent;", + "import _isFunction from \"lodash/isFunction\";\nimport _uniqBy from \"lodash/uniqBy\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Legend\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport pureRender from '../util/PureRender';\nimport DefaultLegendContent from './DefaultLegendContent';\nimport { isNumber } from '../util/DataUtils';\nimport { LEGEND_TYPES } from '../util/ReactUtils';\n\nvar defaultUniqBy = function defaultUniqBy(entry) {\n return entry.value;\n};\n\nvar getUniqPaylod = function getUniqPaylod(option, payload) {\n if (option === true) {\n return _uniqBy(payload, defaultUniqBy);\n }\n\n if (_isFunction(option)) {\n return _uniqBy(payload, option);\n }\n\n return payload;\n};\n\nvar renderContent = function renderContent(content, props) {\n if (React.isValidElement(content)) {\n return React.cloneElement(content, props);\n }\n\n if (_isFunction(content)) {\n return content(props);\n }\n\n return React.createElement(DefaultLegendContent, props);\n};\n\nvar EPS = 1;\nvar ICON_TYPES = LEGEND_TYPES.filter(function (type) {\n return type !== 'none';\n});\n\nvar Legend = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Legend, _Component);\n\n function Legend() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, Legend);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Legend)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n boxWidth: -1,\n boxHeight: -1\n };\n return _this;\n }\n\n _createClass(Legend, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n this.updateBBox();\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate() {\n this.updateBBox();\n }\n }, {\n key: \"getBBox\",\n value: function getBBox() {\n var _this$state = this.state,\n boxWidth = _this$state.boxWidth,\n boxHeight = _this$state.boxHeight;\n\n if (boxWidth >= 0 && boxHeight >= 0) {\n return {\n width: boxWidth,\n height: boxHeight\n };\n }\n\n return null;\n }\n }, {\n key: \"getDefaultPosition\",\n value: function getDefaultPosition(style) {\n var _this$props = this.props,\n layout = _this$props.layout,\n align = _this$props.align,\n verticalAlign = _this$props.verticalAlign,\n margin = _this$props.margin,\n chartWidth = _this$props.chartWidth,\n chartHeight = _this$props.chartHeight;\n var hPos, vPos;\n\n if (!style || (style.left === undefined || style.left === null) && (style.right === undefined || style.right === null)) {\n if (align === 'center' && layout === 'vertical') {\n var box = this.getBBox() || {\n width: 0\n };\n hPos = {\n left: ((chartWidth || 0) - box.width) / 2\n };\n } else {\n hPos = align === 'right' ? {\n right: margin && margin.right || 0\n } : {\n left: margin && margin.left || 0\n };\n }\n }\n\n if (!style || (style.top === undefined || style.top === null) && (style.bottom === undefined || style.bottom === null)) {\n if (verticalAlign === 'middle') {\n var _box = this.getBBox() || {\n height: 0\n };\n\n vPos = {\n top: ((chartHeight || 0) - _box.height) / 2\n };\n } else {\n vPos = verticalAlign === 'bottom' ? {\n bottom: margin && margin.bottom || 0\n } : {\n top: margin && margin.top || 0\n };\n }\n }\n\n return _objectSpread({}, hPos, vPos);\n }\n }, {\n key: \"updateBBox\",\n value: function updateBBox() {\n var _this$state2 = this.state,\n boxWidth = _this$state2.boxWidth,\n boxHeight = _this$state2.boxHeight;\n var onBBoxUpdate = this.props.onBBoxUpdate;\n\n if (this.wrapperNode && this.wrapperNode.getBoundingClientRect) {\n var box = this.wrapperNode.getBoundingClientRect();\n\n if (Math.abs(box.width - boxWidth) > EPS || Math.abs(box.height - boxHeight) > EPS) {\n this.setState({\n boxWidth: box.width,\n boxHeight: box.height\n }, function () {\n if (onBBoxUpdate) {\n onBBoxUpdate(box);\n }\n });\n }\n } else if (boxWidth !== -1 || boxHeight !== -1) {\n this.setState({\n boxWidth: -1,\n boxHeight: -1\n }, function () {\n if (onBBoxUpdate) {\n onBBoxUpdate(null);\n }\n });\n }\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this2 = this;\n\n var _this$props2 = this.props,\n content = _this$props2.content,\n width = _this$props2.width,\n height = _this$props2.height,\n wrapperStyle = _this$props2.wrapperStyle,\n paylodUniqBy = _this$props2.paylodUniqBy,\n payload = _this$props2.payload;\n\n var outerStyle = _objectSpread({\n position: 'absolute',\n width: width || 'auto',\n height: height || 'auto'\n }, this.getDefaultPosition(wrapperStyle), wrapperStyle);\n\n return React.createElement(\"div\", {\n className: \"recharts-legend-wrapper\",\n style: outerStyle,\n ref: function ref(node) {\n _this2.wrapperNode = node;\n }\n }, renderContent(content, _objectSpread({}, this.props, {\n payload: getUniqPaylod(paylodUniqBy, payload)\n })));\n }\n }], [{\n key: \"getWithHeight\",\n value: function getWithHeight(item, chartWidth) {\n var layout = item.props.layout;\n\n if (layout === 'vertical' && isNumber(item.props.height)) {\n return {\n height: item.props.height\n };\n }\n\n if (layout === 'horizontal') {\n return {\n width: item.props.width || chartWidth\n };\n }\n\n return null;\n }\n }]);\n\n return Legend;\n}(Component), _class2.displayName = 'Legend', _class2.propTypes = {\n content: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),\n wrapperStyle: PropTypes.object,\n chartWidth: PropTypes.number,\n chartHeight: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number,\n iconSize: PropTypes.number,\n iconType: PropTypes.oneOf(ICON_TYPES),\n layout: PropTypes.oneOf(['horizontal', 'vertical']),\n align: PropTypes.oneOf(['center', 'left', 'right']),\n verticalAlign: PropTypes.oneOf(['top', 'bottom', 'middle']),\n margin: PropTypes.shape({\n top: PropTypes.number,\n left: PropTypes.number,\n bottom: PropTypes.number,\n right: PropTypes.number\n }),\n payload: PropTypes.arrayOf(PropTypes.shape({\n value: PropTypes.any,\n id: PropTypes.any,\n type: PropTypes.oneOf(LEGEND_TYPES)\n })),\n paylodUniqBy: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),\n formatter: PropTypes.func,\n onMouseEnter: PropTypes.func,\n onMouseLeave: PropTypes.func,\n onClick: PropTypes.func,\n onBBoxUpdate: PropTypes.func\n}, _class2.defaultProps = {\n iconSize: 14,\n layout: 'horizontal',\n align: 'center',\n verticalAlign: 'bottom'\n}, _temp)) || _class;\n\nexport default Legend;", + "import _debounce from \"lodash/debounce\";\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Wrapper component to make charts adapt to the size of parent * DOM\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport ReactResizeDetector from 'react-resize-detector';\nimport { isPercent } from '../util/DataUtils';\nimport { warn } from '../util/LogUtils';\n\nvar ResponsiveContainer =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(ResponsiveContainer, _Component);\n\n function ResponsiveContainer(props) {\n var _this;\n\n _classCallCheck(this, ResponsiveContainer);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(ResponsiveContainer).call(this, props));\n\n _this.updateDimensionsImmediate = function () {\n if (!_this.mounted) {\n return;\n }\n\n var newSize = _this.getContainerSize();\n\n if (newSize) {\n var _this$state = _this.state,\n oldWidth = _this$state.containerWidth,\n oldHeight = _this$state.containerHeight;\n var containerWidth = newSize.containerWidth,\n containerHeight = newSize.containerHeight;\n\n if (containerWidth !== oldWidth || containerHeight !== oldHeight) {\n _this.setState({\n containerWidth: containerWidth,\n containerHeight: containerHeight\n });\n }\n }\n };\n\n _this.state = {\n containerWidth: -1,\n containerHeight: -1\n };\n _this.handleResize = props.debounce > 0 ? _debounce(_this.updateDimensionsImmediate, props.debounce) : _this.updateDimensionsImmediate;\n return _this;\n }\n /* eslint-disable react/no-did-mount-set-state */\n\n\n _createClass(ResponsiveContainer, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n this.mounted = true;\n var size = this.getContainerSize();\n\n if (size) {\n this.setState(size);\n }\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n this.mounted = false;\n }\n }, {\n key: \"getContainerSize\",\n value: function getContainerSize() {\n if (!this.container) {\n return null;\n }\n\n return {\n containerWidth: this.container.clientWidth,\n containerHeight: this.container.clientHeight\n };\n }\n }, {\n key: \"renderChart\",\n value: function renderChart() {\n var _this$state2 = this.state,\n containerWidth = _this$state2.containerWidth,\n containerHeight = _this$state2.containerHeight;\n\n if (containerWidth < 0 || containerHeight < 0) {\n return null;\n }\n\n var _this$props = this.props,\n aspect = _this$props.aspect,\n width = _this$props.width,\n height = _this$props.height,\n minWidth = _this$props.minWidth,\n minHeight = _this$props.minHeight,\n maxHeight = _this$props.maxHeight,\n children = _this$props.children;\n warn(isPercent(width) || isPercent(height), \"The width(%s) and height(%s) are both fixed numbers,\\n maybe you don't need to use a ResponsiveContainer.\", width, height);\n warn(!aspect || aspect > 0, 'The aspect(%s) must be greater than zero.', aspect);\n var calculatedWidth = isPercent(width) ? containerWidth : width;\n var calculatedHeight = isPercent(height) ? containerHeight : height;\n\n if (aspect && aspect > 0) {\n // Preserve the desired aspect ratio\n calculatedHeight = calculatedWidth / aspect; // if maxHeight is set, overwrite if calculatedHeight is greater than maxHeight\n\n if (maxHeight && calculatedHeight > maxHeight) {\n calculatedHeight = maxHeight;\n }\n }\n\n warn(calculatedWidth > 0 || calculatedHeight > 0, \"The width(%s) and height(%s) of chart should be greater than 0,\\n please check the style of container, or the props width(%s) and height(%s),\\n or add a minWidth(%s) or minHeight(%s) or use aspect(%s) to control the\\n height and width.\", calculatedWidth, calculatedHeight, width, height, minWidth, minHeight, aspect);\n return React.cloneElement(children, {\n width: calculatedWidth,\n height: calculatedHeight\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this2 = this;\n\n var _this$props2 = this.props,\n minWidth = _this$props2.minWidth,\n minHeight = _this$props2.minHeight,\n width = _this$props2.width,\n height = _this$props2.height,\n maxHeight = _this$props2.maxHeight,\n id = _this$props2.id,\n className = _this$props2.className;\n var style = {\n width: width,\n height: height,\n minWidth: minWidth,\n minHeight: minHeight,\n maxHeight: maxHeight\n };\n return React.createElement(\"div\", {\n id: id,\n className: classNames('recharts-responsive-container', className),\n style: style,\n ref: function ref(node) {\n _this2.container = node;\n }\n }, this.renderChart(), React.createElement(ReactResizeDetector, {\n handleWidth: true,\n handleHeight: true,\n onResize: this.handleResize\n }));\n }\n }]);\n\n return ResponsiveContainer;\n}(Component);\n\nResponsiveContainer.displayName = 'ResponsiveContainer';\nResponsiveContainer.propTypes = {\n aspect: PropTypes.number,\n width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n minHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n minWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n maxHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n children: PropTypes.node.isRequired,\n debounce: PropTypes.number,\n id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n className: PropTypes.oneOfType([PropTypes.string, PropTypes.number])\n};\nResponsiveContainer.defaultProps = {\n width: '100%',\n height: '100%',\n debounce: 0\n};\nexport default ResponsiveContainer;", + "import _isNil from \"lodash/isNil\";\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport reduceCSSCalc from 'reduce-css-calc';\nimport classNames from 'classnames';\nimport { isNumber, isNumOrStr } from '../util/DataUtils';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes, isSsr } from '../util/ReactUtils';\nimport { getStringSize } from '../util/DOMUtils';\nvar BREAKING_SPACES = /[ \\f\\n\\r\\t\\v\\u2028\\u2029]+/;\n\nvar calculateWordWidths = function calculateWordWidths(props) {\n try {\n var words = !_isNil(props.children) ? props.children.toString().split(BREAKING_SPACES) : [];\n var wordsWithComputedWidth = words.map(function (word) {\n return {\n word: word,\n width: getStringSize(word, props.style).width\n };\n });\n var spaceWidth = getStringSize(\"\\xA0\", props.style).width;\n return {\n wordsWithComputedWidth: wordsWithComputedWidth,\n spaceWidth: spaceWidth\n };\n } catch (e) {\n return null;\n }\n};\n\nvar Text =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Text, _Component);\n\n function Text() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, Text);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Text)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n wordsByLines: []\n };\n return _this;\n }\n\n _createClass(Text, [{\n key: \"componentWillMount\",\n value: function componentWillMount() {\n this.updateWordsByLines(this.props, true);\n }\n }, {\n key: \"componentWillReceiveProps\",\n value: function componentWillReceiveProps(nextProps) {\n var needCalculate = this.props.children !== nextProps.children || this.props.style !== nextProps.style;\n this.updateWordsByLines(nextProps, needCalculate);\n }\n }, {\n key: \"updateWordsByLines\",\n value: function updateWordsByLines(props, needCalculate) {\n // Only perform calculations if using features that require them (multiline, scaleToFit)\n if ((props.width || props.scaleToFit) && !isSsr()) {\n if (needCalculate) {\n var wordWidths = calculateWordWidths(props);\n\n if (wordWidths) {\n var wordsWithComputedWidth = wordWidths.wordsWithComputedWidth,\n spaceWidth = wordWidths.spaceWidth;\n this.wordsWithComputedWidth = wordsWithComputedWidth;\n this.spaceWidth = spaceWidth;\n } else {\n this.updateWordsWithoutCalculate(props);\n return;\n }\n }\n\n var wordsByLines = this.calculateWordsByLines(this.wordsWithComputedWidth, this.spaceWidth, props.width);\n this.setState({\n wordsByLines: wordsByLines\n });\n } else {\n this.updateWordsWithoutCalculate(props);\n }\n }\n }, {\n key: \"updateWordsWithoutCalculate\",\n value: function updateWordsWithoutCalculate(props) {\n var words = !_isNil(props.children) ? props.children.toString().split(BREAKING_SPACES) : [];\n this.setState({\n wordsByLines: [{\n words: words\n }]\n });\n }\n }, {\n key: \"calculateWordsByLines\",\n value: function calculateWordsByLines(wordsWithComputedWidth, spaceWidth, lineWidth) {\n var scaleToFit = this.props.scaleToFit;\n return wordsWithComputedWidth.reduce(function (result, _ref) {\n var word = _ref.word,\n width = _ref.width;\n var currentLine = result[result.length - 1];\n\n if (currentLine && (lineWidth == null || scaleToFit || currentLine.width + width + spaceWidth < lineWidth)) {\n // Word can be added to an existing line\n currentLine.words.push(word);\n currentLine.width += width + spaceWidth;\n } else {\n // Add first word to line or word is too long to scaleToFit on existing line\n var newLine = {\n words: [word],\n width: width\n };\n result.push(newLine);\n }\n\n return result;\n }, []);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n dx = _this$props.dx,\n dy = _this$props.dy,\n textAnchor = _this$props.textAnchor,\n verticalAnchor = _this$props.verticalAnchor,\n scaleToFit = _this$props.scaleToFit,\n angle = _this$props.angle,\n lineHeight = _this$props.lineHeight,\n capHeight = _this$props.capHeight,\n className = _this$props.className,\n textProps = _objectWithoutProperties(_this$props, [\"dx\", \"dy\", \"textAnchor\", \"verticalAnchor\", \"scaleToFit\", \"angle\", \"lineHeight\", \"capHeight\", \"className\"]);\n\n var wordsByLines = this.state.wordsByLines;\n\n if (!isNumOrStr(textProps.x) || !isNumOrStr(textProps.y)) {\n return null;\n }\n\n var x = textProps.x + (isNumber(dx) ? dx : 0);\n var y = textProps.y + (isNumber(dy) ? dy : 0);\n var startDy;\n\n switch (verticalAnchor) {\n case 'start':\n startDy = reduceCSSCalc(\"calc(\".concat(capHeight, \")\"));\n break;\n\n case 'middle':\n startDy = reduceCSSCalc(\"calc(\".concat((wordsByLines.length - 1) / 2, \" * -\").concat(lineHeight, \" + (\").concat(capHeight, \" / 2))\"));\n break;\n\n default:\n startDy = reduceCSSCalc(\"calc(\".concat(wordsByLines.length - 1, \" * -\").concat(lineHeight, \")\"));\n break;\n }\n\n var transforms = [];\n\n if (scaleToFit) {\n var lineWidth = wordsByLines[0].width;\n transforms.push(\"scale(\".concat(this.props.width / lineWidth, \")\"));\n }\n\n if (angle) {\n transforms.push(\"rotate(\".concat(angle, \", \").concat(x, \", \").concat(y, \")\"));\n }\n\n if (transforms.length) {\n textProps.transform = transforms.join(' ');\n }\n\n return React.createElement(\"text\", _extends({}, getPresentationAttributes(textProps), {\n x: x,\n y: y,\n className: classNames('recharts-text', className),\n textAnchor: textAnchor\n }), wordsByLines.map(function (line, index) {\n return React.createElement(\"tspan\", {\n x: x,\n dy: index === 0 ? startDy : lineHeight,\n key: index\n }, line.words.join(' '));\n }));\n }\n }]);\n\n return Text;\n}(Component);\n\nText.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n scaleToFit: PropTypes.bool,\n angle: PropTypes.number,\n textAnchor: PropTypes.oneOf(['start', 'middle', 'end', 'inherit']),\n verticalAnchor: PropTypes.oneOf(['start', 'middle', 'end']),\n style: PropTypes.object\n});\nText.defaultProps = {\n x: 0,\n y: 0,\n lineHeight: '1em',\n capHeight: '0.71em',\n // Magic number from d3\n scaleToFit: false,\n textAnchor: 'start',\n verticalAnchor: 'end' // Maintain compat with existing charts / default SVG behavior\n\n};\nexport default Text;", + "import _isArray from \"lodash/isArray\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport { isNumOrStr } from '../util/DataUtils';\n\nvar defaultFormatter = function defaultFormatter(value) {\n return _isArray(value) && isNumOrStr(value[0]) && isNumOrStr(value[1]) ? value.join(' ~ ') : value;\n};\n\nvar DefaultTooltipContent = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(DefaultTooltipContent, _Component);\n\n function DefaultTooltipContent() {\n _classCallCheck(this, DefaultTooltipContent);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(DefaultTooltipContent).apply(this, arguments));\n }\n\n _createClass(DefaultTooltipContent, [{\n key: \"renderContent\",\n value: function renderContent() {\n var _this$props = this.props,\n payload = _this$props.payload,\n separator = _this$props.separator,\n formatter = _this$props.formatter,\n itemStyle = _this$props.itemStyle,\n itemSorter = _this$props.itemSorter;\n\n if (payload && payload.length) {\n var listStyle = {\n padding: 0,\n margin: 0\n };\n var items = payload.sort(itemSorter).map(function (entry, i) {\n var finalItemStyle = _objectSpread({\n display: 'block',\n paddingTop: 4,\n paddingBottom: 4,\n color: entry.color || '#000'\n }, itemStyle);\n\n var finalFormatter = entry.formatter || formatter || defaultFormatter;\n var name = entry.name,\n value = entry.value;\n\n if (finalFormatter) {\n var formatted = finalFormatter(value, name, entry, i);\n\n if (Array.isArray(formatted)) {\n var _formatted = _slicedToArray(formatted, 2);\n\n value = _formatted[0];\n name = _formatted[1];\n } else {\n value = formatted;\n }\n }\n\n return React.createElement(\"li\", {\n className: \"recharts-tooltip-item\",\n key: \"tooltip-item-\".concat(i),\n style: finalItemStyle\n }, isNumOrStr(name) ? React.createElement(\"span\", {\n className: \"recharts-tooltip-item-name\"\n }, name) : null, isNumOrStr(name) ? React.createElement(\"span\", {\n className: \"recharts-tooltip-item-separator\"\n }, separator) : null, React.createElement(\"span\", {\n className: \"recharts-tooltip-item-value\"\n }, value), React.createElement(\"span\", {\n className: \"recharts-tooltip-item-unit\"\n }, entry.unit || ''));\n });\n return React.createElement(\"ul\", {\n className: \"recharts-tooltip-item-list\",\n style: listStyle\n }, items);\n }\n\n return null;\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n wrapperClassName = _this$props2.wrapperClassName,\n contentStyle = _this$props2.contentStyle,\n labelClassName = _this$props2.labelClassName,\n labelStyle = _this$props2.labelStyle,\n label = _this$props2.label,\n labelFormatter = _this$props2.labelFormatter;\n\n var finalStyle = _objectSpread({\n margin: 0,\n padding: 10,\n backgroundColor: '#fff',\n border: '1px solid #ccc',\n whiteSpace: 'nowrap'\n }, contentStyle);\n\n var finalLabelStyle = _objectSpread({\n margin: 0\n }, labelStyle);\n\n var hasLabel = isNumOrStr(label);\n var finalLabel = hasLabel ? label : '';\n var wrapperCN = classNames('recharts-default-tooltip', wrapperClassName);\n var labelCN = classNames('recharts-tooltip-label', labelClassName);\n\n if (hasLabel && labelFormatter) {\n finalLabel = labelFormatter(label);\n }\n\n return React.createElement(\"div\", {\n className: wrapperCN,\n style: finalStyle\n }, React.createElement(\"p\", {\n className: labelCN,\n style: finalLabelStyle\n }, finalLabel), this.renderContent());\n }\n }]);\n\n return DefaultTooltipContent;\n}(Component), _class2.displayName = 'DefaultTooltipContent', _class2.propTypes = {\n separator: PropTypes.string,\n wrapperClassName: PropTypes.string,\n labelClassName: PropTypes.string,\n formatter: PropTypes.func,\n contentStyle: PropTypes.object,\n itemStyle: PropTypes.object,\n labelStyle: PropTypes.object,\n labelFormatter: PropTypes.func,\n label: PropTypes.any,\n payload: PropTypes.arrayOf(PropTypes.shape({\n name: PropTypes.any,\n value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.array]),\n unit: PropTypes.any\n })),\n itemSorter: PropTypes.func\n}, _class2.defaultProps = {\n separator: ' : ',\n contentStyle: {},\n itemStyle: {},\n labelStyle: {}\n}, _temp)) || _class;\n\nexport default DefaultTooltipContent;", + "import _isNil from \"lodash/isNil\";\nimport _isFunction from \"lodash/isFunction\";\nimport _uniqBy from \"lodash/uniqBy\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Tooltip\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { translateStyle } from 'react-smooth';\nimport classNames from 'classnames';\nimport DefaultTooltipContent from './DefaultTooltipContent';\nimport { isSsr } from '../util/ReactUtils';\nimport { isNumber } from '../util/DataUtils';\nimport pureRender from '../util/PureRender';\nvar CLS_PREFIX = 'recharts-tooltip-wrapper';\nvar EPS = 1;\n\nvar defaultUniqBy = function defaultUniqBy(entry) {\n return entry.dataKey;\n};\n\nvar getUniqPaylod = function getUniqPaylod(option, payload) {\n if (option === true) {\n return _uniqBy(payload, defaultUniqBy);\n }\n\n if (_isFunction(option)) {\n return _uniqBy(payload, option);\n }\n\n return payload;\n};\n\nvar propTypes = {\n content: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),\n viewBox: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number\n }),\n active: PropTypes.bool,\n separator: PropTypes.string,\n formatter: PropTypes.func,\n offset: PropTypes.number,\n itemStyle: PropTypes.object,\n labelStyle: PropTypes.object,\n wrapperStyle: PropTypes.object,\n contentStyle: PropTypes.object,\n cursor: PropTypes.oneOfType([PropTypes.bool, PropTypes.element, PropTypes.object]),\n coordinate: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number\n }),\n position: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number\n }),\n label: PropTypes.any,\n payload: PropTypes.arrayOf(PropTypes.shape({\n name: PropTypes.any,\n value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.array]),\n unit: PropTypes.any\n })),\n paylodUniqBy: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),\n isAnimationActive: PropTypes.bool,\n animationDuration: PropTypes.number,\n animationEasing: PropTypes.oneOf(['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear']),\n itemSorter: PropTypes.func,\n filterNull: PropTypes.bool,\n useTranslate3d: PropTypes.bool\n};\nvar defaultProps = {\n active: false,\n offset: 10,\n viewBox: {\n x1: 0,\n x2: 0,\n y1: 0,\n y2: 0\n },\n coordinate: {\n x: 0,\n y: 0\n },\n cursorStyle: {},\n separator: ' : ',\n wrapperStyle: {},\n contentStyle: {},\n itemStyle: {},\n labelStyle: {},\n cursor: true,\n isAnimationActive: !isSsr(),\n animationEasing: 'ease',\n animationDuration: 400,\n itemSorter: function itemSorter() {\n return -1;\n },\n filterNull: true,\n useTranslate3d: false\n};\n\nvar renderContent = function renderContent(content, props) {\n if (React.isValidElement(content)) {\n return React.cloneElement(content, props);\n }\n\n if (_isFunction(content)) {\n return content(props);\n }\n\n return React.createElement(DefaultTooltipContent, props);\n};\n\nvar Tooltip = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Tooltip, _Component);\n\n function Tooltip() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, Tooltip);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Tooltip)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n boxWidth: -1,\n boxHeight: -1\n };\n return _this;\n }\n\n _createClass(Tooltip, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n this.updateBBox();\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate() {\n this.updateBBox();\n }\n }, {\n key: \"updateBBox\",\n value: function updateBBox() {\n var _this$state = this.state,\n boxWidth = _this$state.boxWidth,\n boxHeight = _this$state.boxHeight;\n\n if (this.wrapperNode && this.wrapperNode.getBoundingClientRect) {\n var box = this.wrapperNode.getBoundingClientRect();\n\n if (Math.abs(box.width - boxWidth) > EPS || Math.abs(box.height - boxHeight) > EPS) {\n this.setState({\n boxWidth: box.width,\n boxHeight: box.height\n });\n }\n } else if (boxWidth !== -1 || boxHeight !== -1) {\n this.setState({\n boxWidth: -1,\n boxHeight: -1\n });\n }\n }\n }, {\n key: \"render\",\n value: function render() {\n var _classNames,\n _this2 = this;\n\n var _this$props = this.props,\n payload = _this$props.payload,\n isAnimationActive = _this$props.isAnimationActive,\n animationDuration = _this$props.animationDuration,\n animationEasing = _this$props.animationEasing,\n filterNull = _this$props.filterNull,\n paylodUniqBy = _this$props.paylodUniqBy;\n var finalPayload = getUniqPaylod(paylodUniqBy, filterNull && payload && payload.length ? payload.filter(function (entry) {\n return !_isNil(entry.value);\n }) : payload);\n var hasPayload = finalPayload && finalPayload.length;\n var _this$props2 = this.props,\n content = _this$props2.content,\n viewBox = _this$props2.viewBox,\n coordinate = _this$props2.coordinate,\n position = _this$props2.position,\n active = _this$props2.active,\n offset = _this$props2.offset,\n wrapperStyle = _this$props2.wrapperStyle;\n\n var outerStyle = _objectSpread({\n pointerEvents: 'none',\n visibility: active && hasPayload ? 'visible' : 'hidden',\n position: 'absolute',\n top: 0\n }, wrapperStyle);\n\n var translateX, translateY;\n\n if (position && isNumber(position.x) && isNumber(position.y)) {\n translateX = position.x;\n translateY = position.y;\n } else {\n var _this$state2 = this.state,\n boxWidth = _this$state2.boxWidth,\n boxHeight = _this$state2.boxHeight;\n\n if (boxWidth > 0 && boxHeight > 0 && coordinate) {\n translateX = position && isNumber(position.x) ? position.x : Math.max(coordinate.x + boxWidth + offset > viewBox.x + viewBox.width ? coordinate.x - boxWidth - offset : coordinate.x + offset, viewBox.x);\n translateY = position && isNumber(position.y) ? position.y : Math.max(coordinate.y + boxHeight + offset > viewBox.y + viewBox.height ? coordinate.y - boxHeight - offset : coordinate.y + offset, viewBox.y);\n } else {\n outerStyle.visibility = 'hidden';\n }\n }\n\n outerStyle = _objectSpread({}, outerStyle, translateStyle({\n transform: this.props.useTranslate3d ? \"translate3d(\".concat(translateX, \"px, \").concat(translateY, \"px, 0)\") : \"translate(\".concat(translateX, \"px, \").concat(translateY, \"px)\")\n }));\n\n if (isAnimationActive && active) {\n outerStyle = _objectSpread({}, outerStyle, translateStyle({\n transition: \"transform \".concat(animationDuration, \"ms \").concat(animationEasing)\n }));\n }\n\n var cls = classNames(CLS_PREFIX, (_classNames = {}, _defineProperty(_classNames, \"\".concat(CLS_PREFIX, \"-right\"), isNumber(translateX) && coordinate && isNumber(coordinate.x) && translateX >= coordinate.x), _defineProperty(_classNames, \"\".concat(CLS_PREFIX, \"-left\"), isNumber(translateX) && coordinate && isNumber(coordinate.x) && translateX < coordinate.x), _defineProperty(_classNames, \"\".concat(CLS_PREFIX, \"-bottom\"), isNumber(translateY) && coordinate && isNumber(coordinate.y) && translateY >= coordinate.y), _defineProperty(_classNames, \"\".concat(CLS_PREFIX, \"-top\"), isNumber(translateY) && coordinate && isNumber(coordinate.y) && translateY < coordinate.y), _classNames));\n return React.createElement(\"div\", {\n className: cls,\n style: outerStyle,\n ref: function ref(node) {\n _this2.wrapperNode = node;\n }\n }, renderContent(content, _objectSpread({}, this.props, {\n payload: finalPayload\n })));\n }\n }]);\n\n return Tooltip;\n}(Component), _class2.displayName = 'Tooltip', _class2.propTypes = propTypes, _class2.defaultProps = defaultProps, _temp)) || _class;\n\nexport default Tooltip;", + "function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/**\n * @fileOverview Layer\n */\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nvar propTypes = {\n className: PropTypes.string,\n children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])\n};\n\nfunction Layer(props) {\n var children = props.children,\n className = props.className,\n others = _objectWithoutProperties(props, [\"children\", \"className\"]);\n\n var layerClass = classNames('recharts-layer', className);\n return React.createElement(\"g\", _extends({\n className: layerClass\n }, others), children);\n}\n\nLayer.propTypes = propTypes;\nexport default Layer;", + "function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/**\n * @fileOverview Surface\n */\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { getPresentationAttributes } from '../util/ReactUtils';\nvar propTypes = {\n width: PropTypes.number.isRequired,\n height: PropTypes.number.isRequired,\n viewBox: PropTypes.shape({\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number\n }),\n className: PropTypes.string,\n style: PropTypes.object,\n children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])\n};\n\nfunction Surface(props) {\n var children = props.children,\n width = props.width,\n height = props.height,\n viewBox = props.viewBox,\n className = props.className,\n style = props.style,\n others = _objectWithoutProperties(props, [\"children\", \"width\", \"height\", \"viewBox\", \"className\", \"style\"]);\n\n var svgView = viewBox || {\n width: width,\n height: height,\n x: 0,\n y: 0\n };\n var layerClass = classNames('recharts-surface', className);\n var attrs = getPresentationAttributes(others);\n return React.createElement(\"svg\", _extends({}, attrs, {\n className: layerClass,\n width: width,\n height: height,\n style: style,\n viewBox: \"\".concat(svgView.x, \" \").concat(svgView.y, \" \").concat(svgView.width, \" \").concat(svgView.height),\n version: \"1.1\"\n }), children);\n}\n\nSurface.propTypes = propTypes;\nexport default Surface;", + "import 'core-js/es6/math';\nimport 'core-js/es6/number';\n/* eslint no-proto: 0 */\n\nvar testObject = {};\n\nif (!(Object.setPrototypeOf || testObject.__proto__)) {\n var nativeGetPrototypeOf = Object.getPrototypeOf;\n\n Object.getPrototypeOf = function (object) {\n if (object.__proto__) {\n return object.__proto__;\n }\n\n return nativeGetPrototypeOf.call(Object, object);\n };\n}", + "import './polyfill';\nimport _Surface from './container/Surface';\nexport { _Surface as Surface };\nimport _Layer from './container/Layer';\nexport { _Layer as Layer };\nimport _Legend from './component/Legend';\nexport { _Legend as Legend };\nimport _Tooltip from './component/Tooltip';\nexport { _Tooltip as Tooltip };\nimport _ResponsiveContainer from './component/ResponsiveContainer';\nexport { _ResponsiveContainer as ResponsiveContainer };\nimport _Cell from './component/Cell';\nexport { _Cell as Cell };\nimport _Text from './component/Text';\nexport { _Text as Text };\nimport _Label from './component/Label';\nexport { _Label as Label };\nimport _LabelList from './component/LabelList';\nexport { _LabelList as LabelList };\nimport _Sector from './shape/Sector';\nexport { _Sector as Sector };\nimport _Curve from './shape/Curve';\nexport { _Curve as Curve };\nimport _Rectangle from './shape/Rectangle';\nexport { _Rectangle as Rectangle };\nimport _Polygon from './shape/Polygon';\nexport { _Polygon as Polygon };\nimport _Dot from './shape/Dot';\nexport { _Dot as Dot };\nimport _Cross from './shape/Cross';\nexport { _Cross as Cross };\nimport _Symbols from './shape/Symbols';\nexport { _Symbols as Symbols };\nimport _PolarGrid from './polar/PolarGrid';\nexport { _PolarGrid as PolarGrid };\nimport _PolarRadiusAxis from './polar/PolarRadiusAxis';\nexport { _PolarRadiusAxis as PolarRadiusAxis };\nimport _PolarAngleAxis from './polar/PolarAngleAxis';\nexport { _PolarAngleAxis as PolarAngleAxis };\nimport _Pie from './polar/Pie';\nexport { _Pie as Pie };\nimport _Radar from './polar/Radar';\nexport { _Radar as Radar };\nimport _RadialBar from './polar/RadialBar';\nexport { _RadialBar as RadialBar };\nimport _Brush from './cartesian/Brush';\nexport { _Brush as Brush };\nimport _ReferenceLine from './cartesian/ReferenceLine';\nexport { _ReferenceLine as ReferenceLine };\nimport _ReferenceDot from './cartesian/ReferenceDot';\nexport { _ReferenceDot as ReferenceDot };\nimport _ReferenceArea from './cartesian/ReferenceArea';\nexport { _ReferenceArea as ReferenceArea };\nimport _CartesianAxis from './cartesian/CartesianAxis';\nexport { _CartesianAxis as CartesianAxis };\nimport _CartesianGrid from './cartesian/CartesianGrid';\nexport { _CartesianGrid as CartesianGrid };\nimport _Line from './cartesian/Line';\nexport { _Line as Line };\nimport _Area from './cartesian/Area';\nexport { _Area as Area };\nimport _Bar from './cartesian/Bar';\nexport { _Bar as Bar };\nimport _Scatter from './cartesian/Scatter';\nexport { _Scatter as Scatter };\nimport _XAxis from './cartesian/XAxis';\nexport { _XAxis as XAxis };\nimport _YAxis from './cartesian/YAxis';\nexport { _YAxis as YAxis };\nimport _ZAxis from './cartesian/ZAxis';\nexport { _ZAxis as ZAxis };\nimport _ErrorBar from './cartesian/ErrorBar';\nexport { _ErrorBar as ErrorBar };\nimport _LineChart from './chart/LineChart';\nexport { _LineChart as LineChart };\nimport _BarChart from './chart/BarChart';\nexport { _BarChart as BarChart };\nimport _PieChart from './chart/PieChart';\nexport { _PieChart as PieChart };\nimport _Treemap from './chart/Treemap';\nexport { _Treemap as Treemap };\nimport _Sankey from './chart/Sankey';\nexport { _Sankey as Sankey };\nimport _RadarChart from './chart/RadarChart';\nexport { _RadarChart as RadarChart };\nimport _ScatterChart from './chart/ScatterChart';\nexport { _ScatterChart as ScatterChart };\nimport _AreaChart from './chart/AreaChart';\nexport { _AreaChart as AreaChart };\nimport _RadialBarChart from './chart/RadialBarChart';\nexport { _RadialBarChart as RadialBarChart };\nimport _ComposedChart from './chart/ComposedChart';\nexport { _ComposedChart as ComposedChart };\nimport _Funnel from './numberAxis/Funnel';\nexport { _Funnel as Funnel };\nimport _FunnelChart from './chart/FunnelChart';\nexport { _FunnelChart as FunnelChart };\nimport _Trapezoid from './shape/Trapezoid';\nexport { _Trapezoid as Trapezoid };", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Cross\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport { isNumber } from '../util/DataUtils';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes } from '../util/ReactUtils';\n\nvar Cross = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Cross, _Component);\n\n function Cross() {\n _classCallCheck(this, Cross);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(Cross).apply(this, arguments));\n }\n\n _createClass(Cross, [{\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n x = _this$props.x,\n y = _this$props.y,\n width = _this$props.width,\n height = _this$props.height,\n top = _this$props.top,\n left = _this$props.left,\n className = _this$props.className;\n\n if (!isNumber(x) || !isNumber(y) || !isNumber(width) || !isNumber(height) || !isNumber(top) || !isNumber(left)) {\n return null;\n }\n\n return React.createElement(\"path\", _extends({}, getPresentationAttributes(this.props), {\n className: classNames('recharts-cross', className),\n d: this.constructor.getPath(x, y, width, height, top, left)\n }));\n }\n }], [{\n key: \"getPath\",\n value: function getPath(x, y, width, height, top, left) {\n return \"M\".concat(x, \",\").concat(top, \"v\").concat(height, \"M\").concat(left, \",\").concat(y, \"h\").concat(width);\n }\n }]);\n\n return Cross;\n}(Component), _class2.displayName = 'Cross', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number,\n top: PropTypes.number,\n left: PropTypes.number,\n className: PropTypes.string\n}), _class2.defaultProps = {\n x: 0,\n y: 0,\n top: 0,\n left: 0,\n width: 0,\n height: 0\n}, _temp)) || _class;\n\nexport default Cross;", + "import _isArray from \"lodash/isArray\";\nimport _isFunction from \"lodash/isFunction\";\n\nvar _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Curve\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { line as shapeLine, area as shapeArea, curveBasisClosed, curveBasisOpen, curveBasis, curveLinearClosed, curveLinear, curveMonotoneX, curveMonotoneY, curveNatural, curveStep, curveStepAfter, curveStepBefore } from 'd3-shape';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\nimport { isNumber } from '../util/DataUtils';\nvar CURVE_FACTORIES = {\n curveBasisClosed: curveBasisClosed,\n curveBasisOpen: curveBasisOpen,\n curveBasis: curveBasis,\n curveLinearClosed: curveLinearClosed,\n curveLinear: curveLinear,\n curveMonotoneX: curveMonotoneX,\n curveMonotoneY: curveMonotoneY,\n curveNatural: curveNatural,\n curveStep: curveStep,\n curveStepAfter: curveStepAfter,\n curveStepBefore: curveStepBefore\n};\n\nvar defined = function defined(p) {\n return p.x === +p.x && p.y === +p.y;\n};\n\nvar getX = function getX(p) {\n return p.x;\n};\n\nvar getY = function getY(p) {\n return p.y;\n};\n\nvar getCurveFactory = function getCurveFactory(type, layout) {\n if (_isFunction(type)) {\n return type;\n }\n\n var name = \"curve\".concat(type.slice(0, 1).toUpperCase()).concat(type.slice(1));\n\n if (name === 'curveMonotone' && layout) {\n return CURVE_FACTORIES[\"\".concat(name).concat(layout === 'vertical' ? 'Y' : 'X')];\n }\n\n return CURVE_FACTORIES[name] || curveLinear;\n};\n\nvar Curve = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Curve, _Component);\n\n function Curve() {\n _classCallCheck(this, Curve);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(Curve).apply(this, arguments));\n }\n\n _createClass(Curve, [{\n key: \"getPath\",\n\n /**\n * Calculate the path of curve\n * @return {String} path\n */\n value: function getPath() {\n var _this$props = this.props,\n type = _this$props.type,\n points = _this$props.points,\n baseLine = _this$props.baseLine,\n layout = _this$props.layout,\n connectNulls = _this$props.connectNulls;\n var curveFactory = getCurveFactory(type, layout);\n var formatPoints = connectNulls ? points.filter(function (entry) {\n return defined(entry);\n }) : points;\n var lineFunction;\n\n if (_isArray(baseLine)) {\n var formatBaseLine = connectNulls ? baseLine.filter(function (base) {\n return defined(base);\n }) : baseLine;\n var areaPoints = formatPoints.map(function (entry, index) {\n return _objectSpread({}, entry, {\n base: formatBaseLine[index]\n });\n });\n\n if (layout === 'vertical') {\n lineFunction = shapeArea().y(getY).x1(getX).x0(function (d) {\n return d.base.x;\n });\n } else {\n lineFunction = shapeArea().x(getX).y1(getY).y0(function (d) {\n return d.base.y;\n });\n }\n\n lineFunction.defined(defined).curve(curveFactory);\n return lineFunction(areaPoints);\n }\n\n if (layout === 'vertical' && isNumber(baseLine)) {\n lineFunction = shapeArea().y(getY).x1(getX).x0(baseLine);\n } else if (isNumber(baseLine)) {\n lineFunction = shapeArea().x(getX).y1(getY).y0(baseLine);\n } else {\n lineFunction = shapeLine().x(getX).y(getY);\n }\n\n lineFunction.defined(defined).curve(curveFactory);\n return lineFunction(formatPoints);\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n className = _this$props2.className,\n points = _this$props2.points,\n path = _this$props2.path,\n pathRef = _this$props2.pathRef;\n\n if ((!points || !points.length) && !path) {\n return null;\n }\n\n var realPath = points && points.length ? this.getPath() : path;\n return React.createElement(\"path\", _extends({}, getPresentationAttributes(this.props), filterEventAttributes(this.props, null, true), {\n className: classNames('recharts-curve', className),\n d: realPath,\n ref: pathRef\n }));\n }\n }]);\n\n return Curve;\n}(Component), _class2.displayName = 'Curve', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n className: PropTypes.string,\n type: PropTypes.oneOfType([PropTypes.oneOf(['basis', 'basisClosed', 'basisOpen', 'linear', 'linearClosed', 'natural', 'monotoneX', 'monotoneY', 'monotone', 'step', 'stepBefore', 'stepAfter']), PropTypes.func]),\n layout: PropTypes.oneOf(['horizontal', 'vertical']),\n baseLine: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),\n points: PropTypes.arrayOf(PropTypes.object),\n connectNulls: PropTypes.bool,\n path: PropTypes.string,\n pathRef: PropTypes.func\n}), _class2.defaultProps = {\n type: 'linear',\n points: [],\n connectNulls: false\n}, _temp)) || _class;\n\nexport default Curve;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Dot\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport { getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\n\nvar Dot = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Dot, _Component);\n\n function Dot() {\n _classCallCheck(this, Dot);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(Dot).apply(this, arguments));\n }\n\n _createClass(Dot, [{\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n cx = _this$props.cx,\n cy = _this$props.cy,\n r = _this$props.r,\n className = _this$props.className;\n var layerClass = classNames('recharts-dot', className);\n\n if (cx === +cx && cy === +cy && r === +r) {\n return React.createElement(\"circle\", _extends({}, getPresentationAttributes(this.props), filterEventAttributes(this.props, null, true), {\n className: layerClass,\n cx: cx,\n cy: cy,\n r: r\n }));\n }\n\n return null;\n }\n }]);\n\n return Dot;\n}(Component), _class2.displayName = 'Dot', _class2.propTypes = {\n className: PropTypes.string,\n cx: PropTypes.number,\n cy: PropTypes.number,\n r: PropTypes.number\n}, _temp)) || _class;\n\nexport default Dot;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Rectangle\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Animate from 'react-smooth';\nimport pureRender from '../util/PureRender';\nimport { PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\n\nvar getRectangePath = function getRectangePath(x, y, width, height, radius) {\n var maxRadius = Math.min(Math.abs(width) / 2, Math.abs(height) / 2);\n var ySign = height >= 0 ? 1 : -1;\n var xSign = width >= 0 ? 1 : -1;\n var clockWise = height >= 0 && width >= 0 || height < 0 && width < 0 ? 1 : 0;\n var path;\n\n if (maxRadius > 0 && radius instanceof Array) {\n var newRadius = [];\n\n for (var i = 0, len = 4; i < len; i++) {\n newRadius[i] = radius[i] > maxRadius ? maxRadius : radius[i];\n }\n\n path = \"M\".concat(x, \",\").concat(y + ySign * newRadius[0]);\n\n if (newRadius[0] > 0) {\n path += \"A \".concat(newRadius[0], \",\").concat(newRadius[0], \",0,0,\").concat(clockWise, \",\").concat(x + xSign * newRadius[0], \",\").concat(y);\n }\n\n path += \"L \".concat(x + width - xSign * newRadius[1], \",\").concat(y);\n\n if (newRadius[1] > 0) {\n path += \"A \".concat(newRadius[1], \",\").concat(newRadius[1], \",0,0,\").concat(clockWise, \",\\n \").concat(x + width, \",\").concat(y + ySign * newRadius[1]);\n }\n\n path += \"L \".concat(x + width, \",\").concat(y + height - ySign * newRadius[2]);\n\n if (newRadius[2] > 0) {\n path += \"A \".concat(newRadius[2], \",\").concat(newRadius[2], \",0,0,\").concat(clockWise, \",\\n \").concat(x + width - xSign * newRadius[2], \",\").concat(y + height);\n }\n\n path += \"L \".concat(x + xSign * newRadius[3], \",\").concat(y + height);\n\n if (newRadius[3] > 0) {\n path += \"A \".concat(newRadius[3], \",\").concat(newRadius[3], \",0,0,\").concat(clockWise, \",\\n \").concat(x, \",\").concat(y + height - ySign * newRadius[3]);\n }\n\n path += 'Z';\n } else if (maxRadius > 0 && radius === +radius && radius > 0) {\n var _newRadius = Math.min(maxRadius, radius);\n\n path = \"M \".concat(x, \",\").concat(y + ySign * _newRadius, \"\\n A \").concat(_newRadius, \",\").concat(_newRadius, \",0,0,\").concat(clockWise, \",\").concat(x + xSign * _newRadius, \",\").concat(y, \"\\n L \").concat(x + width - xSign * _newRadius, \",\").concat(y, \"\\n A \").concat(_newRadius, \",\").concat(_newRadius, \",0,0,\").concat(clockWise, \",\").concat(x + width, \",\").concat(y + ySign * _newRadius, \"\\n L \").concat(x + width, \",\").concat(y + height - ySign * _newRadius, \"\\n A \").concat(_newRadius, \",\").concat(_newRadius, \",0,0,\").concat(clockWise, \",\").concat(x + width - xSign * _newRadius, \",\").concat(y + height, \"\\n L \").concat(x + xSign * _newRadius, \",\").concat(y + height, \"\\n A \").concat(_newRadius, \",\").concat(_newRadius, \",0,0,\").concat(clockWise, \",\").concat(x, \",\").concat(y + height - ySign * _newRadius, \" Z\");\n } else {\n path = \"M \".concat(x, \",\").concat(y, \" h \").concat(width, \" v \").concat(height, \" h \").concat(-width, \" Z\");\n }\n\n return path;\n};\n\nvar Rectangle = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Rectangle, _Component);\n\n function Rectangle() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, Rectangle);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Rectangle)).call.apply(_getPrototypeOf2, [this].concat(args)));\n _this.state = {\n totalLength: -1\n };\n return _this;\n }\n\n _createClass(Rectangle, [{\n key: \"componentDidMount\",\n\n /* eslint-disable react/no-did-mount-set-state */\n value: function componentDidMount() {\n if (this.node && this.node.getTotalLength) {\n try {\n var totalLength = this.node.getTotalLength();\n\n if (totalLength) {\n this.setState({\n totalLength: totalLength\n });\n }\n } catch (err) {// calculate total length error\n }\n }\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this2 = this;\n\n var _this$props = this.props,\n x = _this$props.x,\n y = _this$props.y,\n width = _this$props.width,\n height = _this$props.height,\n radius = _this$props.radius,\n className = _this$props.className;\n var totalLength = this.state.totalLength;\n var _this$props2 = this.props,\n animationEasing = _this$props2.animationEasing,\n animationDuration = _this$props2.animationDuration,\n animationBegin = _this$props2.animationBegin,\n isAnimationActive = _this$props2.isAnimationActive,\n isUpdateAnimationActive = _this$props2.isUpdateAnimationActive;\n\n if (x !== +x || y !== +y || width !== +width || height !== +height || width === 0 || height === 0) {\n return null;\n }\n\n var layerClass = classNames('recharts-rectangle', className);\n\n if (!isUpdateAnimationActive) {\n return React.createElement(\"path\", _extends({}, getPresentationAttributes(this.props), filterEventAttributes(this.props), {\n className: layerClass,\n d: getRectangePath(x, y, width, height, radius)\n }));\n }\n\n return React.createElement(Animate, {\n canBegin: totalLength > 0,\n from: {\n width: width,\n height: height,\n x: x,\n y: y\n },\n to: {\n width: width,\n height: height,\n x: x,\n y: y\n },\n duration: animationDuration,\n animationEasing: animationEasing,\n isActive: isUpdateAnimationActive\n }, function (_ref) {\n var currWidth = _ref.width,\n currHeight = _ref.height,\n currX = _ref.x,\n currY = _ref.y;\n return React.createElement(Animate, {\n canBegin: totalLength > 0,\n from: \"0px \".concat(totalLength === -1 ? 1 : totalLength, \"px\"),\n to: \"\".concat(totalLength, \"px 0px\"),\n attributeName: \"strokeDasharray\",\n begin: animationBegin,\n duration: animationDuration,\n isActive: isAnimationActive,\n easing: animationEasing\n }, React.createElement(\"path\", _extends({}, getPresentationAttributes(_this2.props), filterEventAttributes(_this2.props), {\n className: layerClass,\n d: getRectangePath(currX, currY, currWidth, currHeight, radius),\n ref: function ref(node) {\n _this2.node = node;\n }\n })));\n });\n }\n }]);\n\n return Rectangle;\n}(Component), _class2.displayName = 'Rectangle', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, EVENT_ATTRIBUTES, {\n className: PropTypes.string,\n x: PropTypes.number,\n y: PropTypes.number,\n width: PropTypes.number,\n height: PropTypes.number,\n radius: PropTypes.oneOfType([PropTypes.number, PropTypes.array]),\n isAnimationActive: PropTypes.bool,\n isUpdateAnimationActive: PropTypes.bool,\n animationBegin: PropTypes.number,\n animationDuration: PropTypes.number,\n animationEasing: PropTypes.oneOf(['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear'])\n}), _class2.defaultProps = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n // The radius of border\n // The radius of four corners when radius is a number\n // The radius of left-top, right-top, right-bottom, left-bottom when radius is an array\n radius: 0,\n isAnimationActive: false,\n isUpdateAnimationActive: false,\n animationBegin: 0,\n animationDuration: 1500,\n animationEasing: 'ease'\n}, _temp)) || _class;\n\nexport default Rectangle;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Sector\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\nimport { polarToCartesian, RADIAN } from '../util/PolarUtils';\nimport { getPercentValue, mathSign } from '../util/DataUtils';\n\nvar getDeltaAngle = function getDeltaAngle(startAngle, endAngle) {\n var sign = mathSign(endAngle - startAngle);\n var deltaAngle = Math.min(Math.abs(endAngle - startAngle), 359.999);\n return sign * deltaAngle;\n};\n\nvar getTangentCircle = function getTangentCircle(_ref) {\n var cx = _ref.cx,\n cy = _ref.cy,\n radius = _ref.radius,\n angle = _ref.angle,\n sign = _ref.sign,\n isExternal = _ref.isExternal,\n cornerRadius = _ref.cornerRadius;\n var centerRadius = cornerRadius * (isExternal ? 1 : -1) + radius;\n var theta = Math.asin(cornerRadius / centerRadius) / RADIAN;\n var centerAngle = angle + sign * theta;\n var center = polarToCartesian(cx, cy, centerRadius, centerAngle); // The coordinate of point which is tangent to the circle\n\n var circleTangency = polarToCartesian(cx, cy, radius, centerAngle); // The coordinate of point which is tangent to the radius line\n\n var lineTangency = polarToCartesian(cx, cy, centerRadius * Math.cos(theta * RADIAN), angle);\n return {\n center: center,\n circleTangency: circleTangency,\n lineTangency: lineTangency,\n theta: theta\n };\n};\n\nvar getSectorPath = function getSectorPath(_ref2) {\n var cx = _ref2.cx,\n cy = _ref2.cy,\n innerRadius = _ref2.innerRadius,\n outerRadius = _ref2.outerRadius,\n startAngle = _ref2.startAngle,\n endAngle = _ref2.endAngle;\n var angle = getDeltaAngle(startAngle, endAngle); // When the angle of sector equals to 360, star point and end point coincide\n\n var tempEndAngle = startAngle + angle;\n var outerStartPoint = polarToCartesian(cx, cy, outerRadius, startAngle);\n var outerEndPoint = polarToCartesian(cx, cy, outerRadius, tempEndAngle);\n var path = \"M \".concat(outerStartPoint.x, \",\").concat(outerStartPoint.y, \"\\n A \").concat(outerRadius, \",\").concat(outerRadius, \",0,\\n \").concat(+(Math.abs(angle) > 180), \",\").concat(+(startAngle > tempEndAngle), \",\\n \").concat(outerEndPoint.x, \",\").concat(outerEndPoint.y, \"\\n \");\n\n if (innerRadius > 0) {\n var innerStartPoint = polarToCartesian(cx, cy, innerRadius, startAngle);\n var innerEndPoint = polarToCartesian(cx, cy, innerRadius, tempEndAngle);\n path += \"L \".concat(innerEndPoint.x, \",\").concat(innerEndPoint.y, \"\\n A \").concat(innerRadius, \",\").concat(innerRadius, \",0,\\n \").concat(+(Math.abs(angle) > 180), \",\").concat(+(startAngle <= tempEndAngle), \",\\n \").concat(innerStartPoint.x, \",\").concat(innerStartPoint.y, \" Z\");\n } else {\n path += \"L \".concat(cx, \",\").concat(cy, \" Z\");\n }\n\n return path;\n};\n\nvar getSectorWithCorner = function getSectorWithCorner(_ref3) {\n var cx = _ref3.cx,\n cy = _ref3.cy,\n innerRadius = _ref3.innerRadius,\n outerRadius = _ref3.outerRadius,\n cornerRadius = _ref3.cornerRadius,\n startAngle = _ref3.startAngle,\n endAngle = _ref3.endAngle;\n var sign = mathSign(endAngle - startAngle);\n\n var _getTangentCircle = getTangentCircle({\n cx: cx,\n cy: cy,\n radius: outerRadius,\n angle: startAngle,\n sign: sign,\n cornerRadius: cornerRadius\n }),\n soct = _getTangentCircle.circleTangency,\n solt = _getTangentCircle.lineTangency,\n sot = _getTangentCircle.theta;\n\n var _getTangentCircle2 = getTangentCircle({\n cx: cx,\n cy: cy,\n radius: outerRadius,\n angle: endAngle,\n sign: -sign,\n cornerRadius: cornerRadius\n }),\n eoct = _getTangentCircle2.circleTangency,\n eolt = _getTangentCircle2.lineTangency,\n eot = _getTangentCircle2.theta;\n\n var outerArcAngle = Math.abs(startAngle - endAngle) - sot - eot;\n\n if (outerArcAngle < 0) {\n return getSectorPath({\n cx: cx,\n cy: cy,\n innerRadius: innerRadius,\n outerRadius: outerRadius,\n startAngle: startAngle,\n endAngle: endAngle\n });\n }\n\n var path = \"M \".concat(solt.x, \",\").concat(solt.y, \"\\n A\").concat(cornerRadius, \",\").concat(cornerRadius, \",0,0,\").concat(+(sign < 0), \",\").concat(soct.x, \",\").concat(soct.y, \"\\n A\").concat(outerRadius, \",\").concat(outerRadius, \",0,\").concat(+(outerArcAngle > 180), \",\").concat(+(sign < 0), \",\").concat(eoct.x, \",\").concat(eoct.y, \"\\n A\").concat(cornerRadius, \",\").concat(cornerRadius, \",0,0,\").concat(+(sign < 0), \",\").concat(eolt.x, \",\").concat(eolt.y, \"\\n \");\n\n if (innerRadius > 0) {\n var _getTangentCircle3 = getTangentCircle({\n cx: cx,\n cy: cy,\n radius: innerRadius,\n angle: startAngle,\n sign: sign,\n isExternal: true,\n cornerRadius: cornerRadius\n }),\n sict = _getTangentCircle3.circleTangency,\n silt = _getTangentCircle3.lineTangency,\n sit = _getTangentCircle3.theta;\n\n var _getTangentCircle4 = getTangentCircle({\n cx: cx,\n cy: cy,\n radius: innerRadius,\n angle: endAngle,\n sign: -sign,\n isExternal: true,\n cornerRadius: cornerRadius\n }),\n eict = _getTangentCircle4.circleTangency,\n eilt = _getTangentCircle4.lineTangency,\n eit = _getTangentCircle4.theta;\n\n var innerArcAngle = Math.abs(startAngle - endAngle) - sit - eit;\n\n if (innerArcAngle < 0) {\n return \"\".concat(path, \"L\").concat(cx, \",\").concat(cy, \"Z\");\n }\n\n path += \"L\".concat(eilt.x, \",\").concat(eilt.y, \"\\n A\").concat(cornerRadius, \",\").concat(cornerRadius, \",0,0,\").concat(+(sign < 0), \",\").concat(eict.x, \",\").concat(eict.y, \"\\n A\").concat(innerRadius, \",\").concat(innerRadius, \",0,\").concat(+(innerArcAngle > 180), \",\").concat(+(sign > 0), \",\").concat(sict.x, \",\").concat(sict.y, \"\\n A\").concat(cornerRadius, \",\").concat(cornerRadius, \",0,0,\").concat(+(sign < 0), \",\").concat(silt.x, \",\").concat(silt.y, \"Z\");\n } else {\n path += \"L\".concat(cx, \",\").concat(cy, \"Z\");\n }\n\n return path;\n};\n\nvar Sector = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Sector, _Component);\n\n function Sector() {\n _classCallCheck(this, Sector);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(Sector).apply(this, arguments));\n }\n\n _createClass(Sector, [{\n key: \"render\",\n value: function render() {\n var _this$props = this.props,\n cx = _this$props.cx,\n cy = _this$props.cy,\n innerRadius = _this$props.innerRadius,\n outerRadius = _this$props.outerRadius,\n cornerRadius = _this$props.cornerRadius,\n startAngle = _this$props.startAngle,\n endAngle = _this$props.endAngle,\n className = _this$props.className;\n\n if (outerRadius < innerRadius || startAngle === endAngle) {\n return null;\n }\n\n var layerClass = classNames('recharts-sector', className);\n var deltaRadius = outerRadius - innerRadius;\n var cr = getPercentValue(cornerRadius, deltaRadius, 0, true);\n var path;\n\n if (cr > 0 && Math.abs(startAngle - endAngle) < 360) {\n path = getSectorWithCorner({\n cx: cx,\n cy: cy,\n innerRadius: innerRadius,\n outerRadius: outerRadius,\n cornerRadius: Math.min(cr, deltaRadius / 2),\n startAngle: startAngle,\n endAngle: endAngle\n });\n } else {\n path = getSectorPath({\n cx: cx,\n cy: cy,\n innerRadius: innerRadius,\n outerRadius: outerRadius,\n startAngle: startAngle,\n endAngle: endAngle\n });\n }\n\n return React.createElement(\"path\", _extends({}, getPresentationAttributes(this.props), filterEventAttributes(this.props), {\n className: layerClass,\n d: path\n }));\n }\n }]);\n\n return Sector;\n}(Component), _class2.displayName = 'Sector', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n className: PropTypes.string,\n cx: PropTypes.number,\n cy: PropTypes.number,\n innerRadius: PropTypes.number,\n outerRadius: PropTypes.number,\n startAngle: PropTypes.number,\n endAngle: PropTypes.number,\n cornerRadius: PropTypes.oneOfType([PropTypes.number, PropTypes.string])\n}), _class2.defaultProps = {\n cx: 0,\n cy: 0,\n innerRadius: 0,\n outerRadius: 0,\n startAngle: 0,\n endAngle: 0,\n cornerRadius: 0\n}, _temp)) || _class;\n\nexport default Sector;", + "var _class, _class2, _temp;\n\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n/**\n * @fileOverview Curve\n */\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { symbol as shapeSymbol, symbolCircle, symbolCross, symbolDiamond, symbolSquare, symbolStar, symbolTriangle, symbolWye } from 'd3-shape';\nimport classNames from 'classnames';\nimport pureRender from '../util/PureRender';\nimport { PRESENTATION_ATTRIBUTES, getPresentationAttributes, filterEventAttributes } from '../util/ReactUtils';\nvar SYMBOL_FACTORIES = {\n symbolCircle: symbolCircle,\n symbolCross: symbolCross,\n symbolDiamond: symbolDiamond,\n symbolSquare: symbolSquare,\n symbolStar: symbolStar,\n symbolTriangle: symbolTriangle,\n symbolWye: symbolWye\n};\nvar RADIAN = Math.PI / 180;\n\nvar getSymbolFactory = function getSymbolFactory(type) {\n var name = \"symbol\".concat(type.slice(0, 1).toUpperCase()).concat(type.slice(1));\n return SYMBOL_FACTORIES[name] || symbolCircle;\n};\n\nvar calculateAreaSize = function calculateAreaSize(size, sizeType, type) {\n if (sizeType === 'area') {\n return size;\n }\n\n switch (type) {\n case 'cross':\n return 5 * size * size / 9;\n\n case 'diamond':\n return 0.5 * size * size / Math.sqrt(3);\n\n case 'square':\n return size * size;\n\n case 'star':\n {\n var angle = 18 * RADIAN;\n return 1.25 * size * size * (Math.tan(angle) - Math.tan(angle * 2) * Math.pow(Math.tan(angle), 2));\n }\n\n case 'triangle':\n return Math.sqrt(3) * size * size / 4;\n\n case 'wye':\n return (21 - 10 * Math.sqrt(3)) * size * size / 8;\n\n default:\n return Math.PI * size * size / 4;\n }\n};\n\nvar Symbols = pureRender(_class = (_temp = _class2 =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(Symbols, _Component);\n\n function Symbols() {\n _classCallCheck(this, Symbols);\n\n return _possibleConstructorReturn(this, _getPrototypeOf(Symbols).apply(this, arguments));\n }\n\n _createClass(Symbols, [{\n key: \"getPath\",\n\n /**\n * Calculate the path of curve\n * @return {String} path\n */\n value: function getPath() {\n var _this$props = this.props,\n size = _this$props.size,\n sizeType = _this$props.sizeType,\n type = _this$props.type;\n var symbolFactory = getSymbolFactory(type);\n var symbol = shapeSymbol().type(symbolFactory).size(calculateAreaSize(size, sizeType, type));\n return symbol();\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n className = _this$props2.className,\n cx = _this$props2.cx,\n cy = _this$props2.cy,\n size = _this$props2.size;\n\n if (cx === +cx && cy === +cy && size === +size) {\n return React.createElement(\"path\", _extends({}, getPresentationAttributes(this.props), filterEventAttributes(this.props), {\n className: classNames('recharts-symbols', className),\n transform: \"translate(\".concat(cx, \", \").concat(cy, \")\"),\n d: this.getPath()\n }));\n }\n\n return null;\n }\n }]);\n\n return Symbols;\n}(Component), _class2.displayName = 'Symbols', _class2.propTypes = _objectSpread({}, PRESENTATION_ATTRIBUTES, {\n className: PropTypes.string,\n type: PropTypes.oneOf(['circle', 'cross', 'diamond', 'square', 'star', 'triangle', 'wye']),\n cx: PropTypes.number,\n cy: PropTypes.number,\n size: PropTypes.number,\n sizeType: PropTypes.oneOf(['area', 'diameter'])\n}), _class2.defaultProps = {\n type: 'circle',\n size: 64,\n sizeType: 'area'\n}, _temp)) || _class;\n\nexport default Symbols;", + "import _every from \"lodash/every\";\nimport _mapValues from \"lodash/mapValues\";\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nimport { getTicksOfScale, parseScale, checkDomainOfScale, getBandSizeOfAxis } from './ChartUtils';\n/**\n * Calculate the scale function, position, width, height of axes\n * @param {Object} props Latest props\n * @param {Object} axisMap The configuration of axes\n * @param {Object} offset The offset of main part in the svg element\n * @param {String} axisType The type of axes, x-axis or y-axis\n * @param {String} chartName The name of chart\n * @return {Object} Configuration\n */\n\nexport var formatAxisMap = function formatAxisMap(props, axisMap, offset, axisType, chartName) {\n var width = props.width,\n height = props.height,\n layout = props.layout;\n var ids = Object.keys(axisMap);\n var steps = {\n left: offset.left,\n leftMirror: offset.left,\n right: width - offset.right,\n rightMirror: width - offset.right,\n top: offset.top,\n topMirror: offset.top,\n bottom: height - offset.bottom,\n bottomMirror: height - offset.bottom\n };\n return ids.reduce(function (result, id) {\n var axis = axisMap[id];\n var orientation = axis.orientation,\n domain = axis.domain,\n _axis$padding = axis.padding,\n padding = _axis$padding === void 0 ? {} : _axis$padding,\n mirror = axis.mirror,\n reversed = axis.reversed;\n var offsetKey = \"\".concat(orientation).concat(mirror ? 'Mirror' : '');\n var range, x, y, needSpace;\n\n if (axisType === 'xAxis') {\n range = [offset.left + (padding.left || 0), offset.left + offset.width - (padding.right || 0)];\n } else if (axisType === 'yAxis') {\n range = layout === 'horizontal' ? [offset.top + offset.height - (padding.bottom || 0), offset.top + (padding.top || 0)] : [offset.top + (padding.top || 0), offset.top + offset.height - (padding.bottom || 0)];\n } else {\n range = axis.range;\n }\n\n if (reversed) {\n range = [range[1], range[0]];\n }\n\n var _parseScale = parseScale(axis, chartName),\n scale = _parseScale.scale,\n realScaleType = _parseScale.realScaleType;\n\n scale.domain(domain).range(range);\n checkDomainOfScale(scale);\n var ticks = getTicksOfScale(scale, _objectSpread({}, axis, {\n realScaleType: realScaleType\n }));\n\n if (axisType === 'xAxis') {\n needSpace = orientation === 'top' && !mirror || orientation === 'bottom' && mirror;\n x = offset.left;\n y = steps[offsetKey] - needSpace * axis.height;\n } else if (axisType === 'yAxis') {\n needSpace = orientation === 'left' && !mirror || orientation === 'right' && mirror;\n x = steps[offsetKey] - needSpace * axis.width;\n y = offset.top;\n }\n\n var finalAxis = _objectSpread({}, axis, ticks, {\n realScaleType: realScaleType,\n x: x,\n y: y,\n scale: scale,\n width: axisType === 'xAxis' ? offset.width : axis.width,\n height: axisType === 'yAxis' ? offset.height : axis.height\n });\n\n finalAxis.bandSize = getBandSizeOfAxis(finalAxis, ticks);\n\n if (!axis.hide && axisType === 'xAxis') {\n steps[offsetKey] += (needSpace ? -1 : 1) * finalAxis.height;\n } else if (!axis.hide) {\n steps[offsetKey] += (needSpace ? -1 : 1) * finalAxis.width;\n }\n\n return _objectSpread({}, result, _defineProperty({}, id, finalAxis));\n }, {});\n};\nexport var rectWithPoints = function rectWithPoints(_ref, _ref2) {\n var x1 = _ref.x,\n y1 = _ref.y;\n var x2 = _ref2.x,\n y2 = _ref2.y;\n return {\n x: Math.min(x1, x2),\n y: Math.min(y1, y2),\n width: Math.abs(x2 - x1),\n height: Math.abs(y2 - y1)\n };\n};\n/**\n * Compute the x, y, width, and height of a box from two reference points.\n * @param {Object} coords x1, x2, y1, and y2\n * @return {Object} object\n */\n\nexport var rectWithCoords = function rectWithCoords(_ref3) {\n var x1 = _ref3.x1,\n y1 = _ref3.y1,\n x2 = _ref3.x2,\n y2 = _ref3.y2;\n return rectWithPoints({\n x: x1,\n y: y1\n }, {\n x: x2,\n y: y2\n });\n};\nexport var ScaleHelper =\n/*#__PURE__*/\nfunction () {\n _createClass(ScaleHelper, null, [{\n key: \"create\",\n value: function create(obj) {\n return new ScaleHelper(obj);\n }\n }]);\n\n function ScaleHelper(scale) {\n _classCallCheck(this, ScaleHelper);\n\n this.scale = scale;\n }\n\n _createClass(ScaleHelper, [{\n key: \"apply\",\n value: function apply(value) {\n var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n bandAware = _ref4.bandAware;\n\n if (value === undefined) {\n return undefined;\n }\n\n if (bandAware) {\n var offset = this.bandwidth ? this.bandwidth() / 2 : 0;\n return this.scale(value) + offset;\n }\n\n return this.scale(value);\n }\n }, {\n key: \"isInRange\",\n value: function isInRange(value) {\n var range = this.range();\n var first = range[0];\n var last = range[range.length - 1];\n return first <= last ? value >= first && value <= last : value >= last && value <= first;\n }\n }, {\n key: \"domain\",\n get: function get() {\n return this.scale.domain;\n }\n }, {\n key: \"range\",\n get: function get() {\n return this.scale.range;\n }\n }, {\n key: \"rangeMin\",\n get: function get() {\n return this.range()[0];\n }\n }, {\n key: \"rangeMax\",\n get: function get() {\n return this.range()[1];\n }\n }, {\n key: \"bandwidth\",\n get: function get() {\n return this.scale.bandwidth;\n }\n }]);\n\n return ScaleHelper;\n}();\nScaleHelper.EPS = 1e-4;\nexport var LabeledScaleHelper =\n/*#__PURE__*/\nfunction () {\n _createClass(LabeledScaleHelper, null, [{\n key: \"create\",\n value: function create(obj) {\n return new this(obj);\n }\n }]);\n\n function LabeledScaleHelper(scales) {\n _classCallCheck(this, LabeledScaleHelper);\n\n this.scales = _mapValues(scales, ScaleHelper.create);\n Object.assign(this, this.scales);\n }\n\n _createClass(LabeledScaleHelper, [{\n key: \"apply\",\n value: function apply(coords) {\n var _ref5 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n bandAware = _ref5.bandAware;\n\n var scales = this.scales;\n return _mapValues(coords, function (value, label) {\n return scales[label].apply(value, {\n bandAware: bandAware\n });\n });\n }\n }, {\n key: \"isInRange\",\n value: function isInRange(coords) {\n var scales = this.scales;\n return _every(coords, function (value, label) {\n return scales[label].isInRange(value);\n });\n }\n }]);\n\n return LabeledScaleHelper;\n}();", + "import _isEqual from \"lodash/isEqual\";\nimport _sortBy from \"lodash/sortBy\";\nimport _isNaN from \"lodash/isNaN\";\nimport _isString from \"lodash/isString\";\nimport _max from \"lodash/max\";\nimport _min from \"lodash/min\";\nimport _isArray from \"lodash/isArray\";\nimport _flatMap from \"lodash/flatMap\";\nimport _isFunction from \"lodash/isFunction\";\nimport _get from \"lodash/get\";\nimport _isNil from \"lodash/isNil\";\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nimport { getNiceTickValues, getTickValuesFixedDomain } from 'recharts-scale';\nimport * as d3Scales from 'd3-scale';\nimport { stack as shapeStack, stackOrderNone, stackOffsetExpand, stackOffsetNone, stackOffsetSilhouette, stackOffsetWiggle } from 'd3-shape';\nimport { isNumOrStr, uniqueId, isNumber, getPercentValue, mathSign, findEntryInArray } from './DataUtils';\nimport ReferenceDot from '../cartesian/ReferenceDot';\nimport ReferenceLine from '../cartesian/ReferenceLine';\nimport ReferenceArea from '../cartesian/ReferenceArea';\nimport ErrorBar from '../cartesian/ErrorBar';\nimport Legend from '../component/Legend';\nimport { findAllByType, findChildByType, getDisplayName } from './ReactUtils';\nexport var getValueByDataKey = function getValueByDataKey(obj, dataKey, defaultValue) {\n if (_isNil(obj) || _isNil(dataKey)) {\n return defaultValue;\n }\n\n if (isNumOrStr(dataKey)) {\n return _get(obj, dataKey, defaultValue);\n }\n\n if (_isFunction(dataKey)) {\n return dataKey(obj);\n }\n\n return defaultValue;\n};\n/**\n * Get domain of data by key\n * @param {Array} data The data displayed in the chart\n * @param {String} key The unique key of a group of data\n * @param {String} type The type of axis\n * @param {Boolean} filterNil Whether or not filter nil values\n * @return {Array} Domain of data\n */\n\nexport var getDomainOfDataByKey = function getDomainOfDataByKey(data, key, type, filterNil) {\n var flattenData = _flatMap(data, function (entry) {\n return getValueByDataKey(entry, key);\n });\n\n if (type === 'number') {\n var domain = flattenData.filter(function (entry) {\n return isNumber(entry) || parseFloat(entry, 10);\n });\n return [Math.min.apply(null, domain), Math.max.apply(null, domain)];\n }\n\n var validateData = filterNil ? flattenData.filter(function (entry) {\n return !_isNil(entry);\n }) : flattenData;\n return validateData.map(function (entry) {\n return isNumOrStr(entry) ? entry : '';\n });\n};\nexport var calculateActiveTickIndex = function calculateActiveTickIndex(coordinate, ticks, unsortedTicks, axis) {\n var index = -1;\n var len = ticks.length;\n\n if (len > 1) {\n if (axis && axis.axisType === 'angleAxis' && Math.abs(Math.abs(axis.range[1] - axis.range[0]) - 360) <= 1e-6) {\n var range = axis.range; // ticks are distributed in a circle\n\n for (var i = 0; i < len; i++) {\n var before = i > 0 ? unsortedTicks[i - 1].coordinate : unsortedTicks[len - 1].coordinate;\n var cur = unsortedTicks[i].coordinate;\n var after = i >= len - 1 ? unsortedTicks[0].coordinate : unsortedTicks[i + 1].coordinate;\n var sameDirectionCoord = void 0;\n\n if (mathSign(cur - before) !== mathSign(after - cur)) {\n var diffInterval = [];\n\n if (mathSign(after - cur) === mathSign(range[1] - range[0])) {\n sameDirectionCoord = after;\n var curInRange = cur + range[1] - range[0];\n diffInterval[0] = Math.min(curInRange, (curInRange + before) / 2);\n diffInterval[1] = Math.max(curInRange, (curInRange + before) / 2);\n } else {\n sameDirectionCoord = before;\n var afterInRange = after + range[1] - range[0];\n diffInterval[0] = Math.min(cur, (afterInRange + cur) / 2);\n diffInterval[1] = Math.max(cur, (afterInRange + cur) / 2);\n }\n\n var sameInterval = [Math.min(cur, (sameDirectionCoord + cur) / 2), Math.max(cur, (sameDirectionCoord + cur) / 2)];\n\n if (coordinate > sameInterval[0] && coordinate <= sameInterval[1] || coordinate >= diffInterval[0] && coordinate <= diffInterval[1]) {\n index = unsortedTicks[i].index;\n break;\n }\n } else {\n var min = Math.min(before, after);\n var max = Math.max(before, after);\n\n if (coordinate > (min + cur) / 2 && coordinate <= (max + cur) / 2) {\n index = unsortedTicks[i].index;\n break;\n }\n }\n }\n } else {\n // ticks are distributed in a single direction\n for (var _i = 0; _i < len; _i++) {\n if (_i === 0 && coordinate <= (ticks[_i].coordinate + ticks[_i + 1].coordinate) / 2 || _i > 0 && _i < len - 1 && coordinate > (ticks[_i].coordinate + ticks[_i - 1].coordinate) / 2 && coordinate <= (ticks[_i].coordinate + ticks[_i + 1].coordinate) / 2 || _i === len - 1 && coordinate > (ticks[_i].coordinate + ticks[_i - 1].coordinate) / 2) {\n index = ticks[_i].index;\n break;\n }\n }\n }\n } else {\n index = 0;\n }\n\n return index;\n};\n/**\n * Get the main color of each graphic item\n * @param {ReactElement} item A graphic item\n * @return {String} Color\n */\n\nexport var getMainColorOfGraphicItem = function getMainColorOfGraphicItem(item) {\n var displayName = item.type.displayName;\n var result;\n\n switch (displayName) {\n case 'Line':\n case 'Area':\n case 'Radar':\n result = item.props.stroke;\n break;\n\n default:\n result = item.props.fill;\n break;\n }\n\n return result;\n};\nexport var getLegendProps = function getLegendProps(_ref) {\n var children = _ref.children,\n formatedGraphicalItems = _ref.formatedGraphicalItems,\n legendWidth = _ref.legendWidth,\n legendContent = _ref.legendContent;\n var legendItem = findChildByType(children, Legend);\n\n if (!legendItem) {\n return null;\n }\n\n var legendData;\n\n if (legendItem.props && legendItem.props.payload) {\n legendData = legendItem.props && legendItem.props.payload;\n } else if (legendContent === 'children') {\n legendData = (formatedGraphicalItems || []).reduce(function (result, _ref2) {\n var item = _ref2.item,\n props = _ref2.props;\n var data = props.sectors || props.data || [];\n return result.concat(data.map(function (entry) {\n return {\n type: legendItem.props.iconType || item.props.legendType,\n value: entry.name,\n color: entry.fill,\n payload: entry\n };\n }));\n }, []);\n } else {\n legendData = (formatedGraphicalItems || []).map(function (_ref3) {\n var item = _ref3.item;\n var _item$props = item.props,\n dataKey = _item$props.dataKey,\n name = _item$props.name,\n legendType = _item$props.legendType,\n hide = _item$props.hide;\n return {\n inactive: hide,\n dataKey: dataKey,\n type: legendItem.props.iconType || legendType || 'square',\n color: getMainColorOfGraphicItem(item),\n value: name || dataKey,\n payload: item.props\n };\n });\n }\n\n return _objectSpread({}, legendItem.props, Legend.getWithHeight(legendItem, legendWidth), {\n payload: legendData,\n item: legendItem\n });\n};\n/**\n * Calculate the size of all groups for stacked bar graph\n * @param {Object} stackGroups The items grouped by axisId and stackId\n * @return {Object} The size of all groups\n */\n\nexport var getBarSizeList = function getBarSizeList(_ref4) {\n var globalSize = _ref4.barSize,\n _ref4$stackGroups = _ref4.stackGroups,\n stackGroups = _ref4$stackGroups === void 0 ? {} : _ref4$stackGroups;\n\n if (!stackGroups) {\n return {};\n }\n\n var result = {};\n var numericAxisIds = Object.keys(stackGroups);\n\n for (var i = 0, len = numericAxisIds.length; i < len; i++) {\n var sgs = stackGroups[numericAxisIds[i]].stackGroups;\n var stackIds = Object.keys(sgs);\n\n for (var j = 0, sLen = stackIds.length; j < sLen; j++) {\n var _sgs$stackIds$j = sgs[stackIds[j]],\n items = _sgs$stackIds$j.items,\n cateAxisId = _sgs$stackIds$j.cateAxisId;\n var barItems = items.filter(function (item) {\n return getDisplayName(item.type).indexOf('Bar') >= 0;\n });\n\n if (barItems && barItems.length) {\n var selfSize = barItems[0].props.barSize;\n var cateId = barItems[0].props[cateAxisId];\n\n if (!result[cateId]) {\n result[cateId] = [];\n }\n\n result[cateId].push({\n item: barItems[0],\n stackList: barItems.slice(1),\n barSize: _isNil(selfSize) ? globalSize : selfSize\n });\n }\n }\n }\n\n return result;\n};\n/**\n * Calculate the size of each bar and the gap between two bars\n * @param {Number} bandSize The size of each category\n * @param {sizeList} sizeList The size of all groups\n * @param {maxBarSize} maxBarSize The maximum size of bar\n * @return {Number} The size of each bar and the gap between two bars\n */\n\nexport var getBarPosition = function getBarPosition(_ref5) {\n var barGap = _ref5.barGap,\n barCategoryGap = _ref5.barCategoryGap,\n bandSize = _ref5.bandSize,\n _ref5$sizeList = _ref5.sizeList,\n sizeList = _ref5$sizeList === void 0 ? [] : _ref5$sizeList,\n maxBarSize = _ref5.maxBarSize;\n var len = sizeList.length;\n if (len < 1) return null;\n var realBarGap = getPercentValue(barGap, bandSize, 0, true);\n var result; // whether or not is barSize setted by user\n\n if (sizeList[0].barSize === +sizeList[0].barSize) {\n var useFull = false;\n var fullBarSize = bandSize / len;\n var sum = sizeList.reduce(function (res, entry) {\n return res + entry.barSize || 0;\n }, 0);\n sum += (len - 1) * realBarGap;\n\n if (sum >= bandSize) {\n sum -= (len - 1) * realBarGap;\n realBarGap = 0;\n }\n\n if (sum >= bandSize && fullBarSize > 0) {\n useFull = true;\n fullBarSize *= 0.9;\n sum = len * fullBarSize;\n }\n\n var offset = (bandSize - sum) / 2 >> 0;\n var prev = {\n offset: offset - realBarGap,\n size: 0\n };\n result = sizeList.reduce(function (res, entry) {\n var newRes = _toConsumableArray(res).concat([{\n item: entry.item,\n position: {\n offset: prev.offset + prev.size + realBarGap,\n size: useFull ? fullBarSize : entry.barSize\n }\n }]);\n\n prev = newRes[newRes.length - 1].position;\n\n if (entry.stackList && entry.stackList.length) {\n entry.stackList.forEach(function (item) {\n newRes.push({\n item: item,\n position: prev\n });\n });\n }\n\n return newRes;\n }, []);\n } else {\n var _offset = getPercentValue(barCategoryGap, bandSize, 0, true);\n\n if (bandSize - 2 * _offset - (len - 1) * realBarGap <= 0) {\n realBarGap = 0;\n }\n\n var originalSize = (bandSize - 2 * _offset - (len - 1) * realBarGap) / len;\n\n if (originalSize > 1) {\n originalSize >>= 0;\n }\n\n var size = maxBarSize === +maxBarSize ? Math.min(originalSize, maxBarSize) : originalSize;\n result = sizeList.reduce(function (res, entry, i) {\n var newRes = _toConsumableArray(res).concat([{\n item: entry.item,\n position: {\n offset: _offset + (originalSize + realBarGap) * i + (originalSize - size) / 2,\n size: size\n }\n }]);\n\n if (entry.stackList && entry.stackList.length) {\n entry.stackList.forEach(function (item) {\n newRes.push({\n item: item,\n position: newRes[newRes.length - 1].position\n });\n });\n }\n\n return newRes;\n }, []);\n }\n\n return result;\n};\nexport var appendOffsetOfLegend = function appendOffsetOfLegend(offset, items, props, legendBox) {\n var children = props.children,\n width = props.width,\n height = props.height,\n margin = props.margin;\n var legendWidth = width - (margin.left || 0) - (margin.right || 0);\n var legendHeight = height - (margin.top || 0) - (margin.bottom || 0);\n var legendProps = getLegendProps({\n children: children,\n items: items,\n legendWidth: legendWidth,\n legendHeight: legendHeight\n });\n var newOffset = offset;\n\n if (legendProps) {\n var box = legendBox || {};\n var align = legendProps.align,\n verticalAlign = legendProps.verticalAlign,\n layout = legendProps.layout;\n\n if ((layout === 'vertical' || layout === 'horizontal' && verticalAlign === 'center') && isNumber(offset[align])) {\n newOffset = _objectSpread({}, offset, _defineProperty({}, align, newOffset[align] + (box.width || 0)));\n }\n\n if ((layout === 'horizontal' || layout === 'vertical' && align === 'center') && isNumber(offset[verticalAlign])) {\n newOffset = _objectSpread({}, offset, _defineProperty({}, verticalAlign, newOffset[verticalAlign] + (box.height || 0)));\n }\n }\n\n return newOffset;\n};\nexport var getDomainOfErrorBars = function getDomainOfErrorBars(data, item, dataKey, axisType) {\n var children = item.props.children;\n var errorBars = findAllByType(children, ErrorBar).filter(function (errorBarChild) {\n var direction = errorBarChild.props.direction;\n return _isNil(direction) || _isNil(axisType) ? true : axisType.indexOf(direction) >= 0;\n });\n\n if (errorBars && errorBars.length) {\n var keys = errorBars.map(function (errorBarChild) {\n return errorBarChild.props.dataKey;\n });\n return data.reduce(function (result, entry) {\n var entryValue = getValueByDataKey(entry, dataKey, 0);\n var mainValue = _isArray(entryValue) ? [_min(entryValue), _max(entryValue)] : [entryValue, entryValue];\n var errorDomain = keys.reduce(function (prevErrorArr, k) {\n var errorValue = getValueByDataKey(entry, k, 0);\n var lowerValue = mainValue[0] - Math.abs(_isArray(errorValue) ? errorValue[0] : errorValue);\n var upperValue = mainValue[1] + Math.abs(_isArray(errorValue) ? errorValue[1] : errorValue);\n return [Math.min(lowerValue, prevErrorArr[0]), Math.max(upperValue, prevErrorArr[1])];\n }, [Infinity, -Infinity]);\n return [Math.min(errorDomain[0], result[0]), Math.max(errorDomain[1], result[1])];\n }, [Infinity, -Infinity]);\n }\n\n return null;\n};\nexport var parseErrorBarsOfAxis = function parseErrorBarsOfAxis(data, items, dataKey, axisType) {\n var domains = items.map(function (item) {\n return getDomainOfErrorBars(data, item, dataKey, axisType);\n }).filter(function (entry) {\n return !_isNil(entry);\n });\n\n if (domains && domains.length) {\n return domains.reduce(function (result, entry) {\n return [Math.min(result[0], entry[0]), Math.max(result[1], entry[1])];\n }, [Infinity, -Infinity]);\n }\n\n return null;\n};\n/**\n * Get domain of data by the configuration of item element\n * @param {Array} data The data displayed in the chart\n * @param {Array} items The instances of item\n * @param {String} type The type of axis, number - Number Axis, category - Category Axis\n * @param {Boolean} filterNil Whether or not filter nil values\n * @return {Array} Domain\n */\n\nexport var getDomainOfItemsWithSameAxis = function getDomainOfItemsWithSameAxis(data, items, type, filterNil) {\n var domains = items.map(function (item) {\n var dataKey = item.props.dataKey;\n\n if (type === 'number' && dataKey) {\n return getDomainOfErrorBars(data, item, dataKey) || getDomainOfDataByKey(data, dataKey, type, filterNil);\n }\n\n return getDomainOfDataByKey(data, dataKey, type, filterNil);\n });\n\n if (type === 'number') {\n // Calculate the domain of number axis\n return domains.reduce(function (result, entry) {\n return [Math.min(result[0], entry[0]), Math.max(result[1], entry[1])];\n }, [Infinity, -Infinity]);\n }\n\n var tag = {}; // Get the union set of category axis\n\n return domains.reduce(function (result, entry) {\n for (var i = 0, len = entry.length; i < len; i++) {\n if (!tag[entry[i]]) {\n tag[entry[i]] = true;\n result.push(entry[i]);\n }\n }\n\n return result;\n }, []);\n};\nexport var isCategorialAxis = function isCategorialAxis(layout, axisType) {\n return layout === 'horizontal' && axisType === 'xAxis' || layout === 'vertical' && axisType === 'yAxis' || layout === 'centric' && axisType === 'angleAxis' || layout === 'radial' && axisType === 'radiusAxis';\n};\n/**\n * Calculate the Coordinates of grid\n * @param {Array} ticks The ticks in axis\n * @param {Number} min The minimun value of axis\n * @param {Number} max The maximun value of axis\n * @return {Array} Coordinates\n */\n\nexport var getCoordinatesOfGrid = function getCoordinatesOfGrid(ticks, min, max) {\n var hasMin, hasMax;\n var values = ticks.map(function (entry) {\n if (entry.coordinate === min) {\n hasMin = true;\n }\n\n if (entry.coordinate === max) {\n hasMax = true;\n }\n\n return entry.coordinate;\n });\n\n if (!hasMin) {\n values.push(min);\n }\n\n if (!hasMax) {\n values.push(max);\n }\n\n return values;\n};\n/**\n * Get the ticks of an axis\n * @param {Object} axis The configuration of an axis\n * @param {Boolean} isGrid Whether or not are the ticks in grid\n * @param {Boolean} isAll Return the ticks of all the points or not\n * @return {Array} Ticks\n */\n\nexport var getTicksOfAxis = function getTicksOfAxis(axis, isGrid, isAll) {\n if (!axis) return null;\n var scale = axis.scale;\n var duplicateDomain = axis.duplicateDomain,\n type = axis.type,\n range = axis.range;\n var offset = (isGrid || isAll) && type === 'category' && scale.bandwidth ? scale.bandwidth() / 2 : 0;\n offset = axis.axisType === 'angleAxis' ? mathSign(range[0] - range[1]) * 2 * offset : offset; // The ticks setted by user should only affect the ticks adjacent to axis line\n\n if (isGrid && (axis.ticks || axis.niceTicks)) {\n return (axis.ticks || axis.niceTicks).map(function (entry) {\n var scaleContent = duplicateDomain ? duplicateDomain.indexOf(entry) : entry;\n return {\n coordinate: scale(scaleContent) + offset,\n value: entry,\n offset: offset\n };\n });\n }\n\n if (axis.isCategorial && axis.categoricalDomain) {\n return axis.categoricalDomain.map(function (entry, index) {\n return {\n coordinate: scale(entry),\n value: entry,\n index: index,\n offset: offset\n };\n });\n }\n\n if (scale.ticks && !isAll) {\n return scale.ticks(axis.tickCount).map(function (entry) {\n return {\n coordinate: scale(entry) + offset,\n value: entry,\n offset: offset\n };\n });\n } // When axis has duplicated text, serial numbers are used to generate scale\n\n\n return scale.domain().map(function (entry, index) {\n return {\n coordinate: scale(entry) + offset,\n value: duplicateDomain ? duplicateDomain[entry] : entry,\n index: index,\n offset: offset\n };\n });\n};\n/**\n * combine the handlers\n * @param {Function} defaultHandler Internal private handler\n * @param {Function} parentHandler Handler function specified in parent component\n * @param {Function} childHandler Handler function specified in child component\n * @return {Function} The combined handler\n */\n\nexport var combineEventHandlers = function combineEventHandlers(defaultHandler, parentHandler, childHandler) {\n var customizedHandler;\n\n if (_isFunction(childHandler)) {\n customizedHandler = childHandler;\n } else if (_isFunction(parentHandler)) {\n customizedHandler = parentHandler;\n }\n\n if (_isFunction(defaultHandler) || customizedHandler) {\n return function (arg1, arg2, arg3, arg4) {\n if (_isFunction(defaultHandler)) {\n defaultHandler(arg1, arg2, arg3, arg4);\n }\n\n if (_isFunction(customizedHandler)) {\n customizedHandler(arg1, arg2, arg3, arg4);\n }\n };\n }\n\n return null;\n};\n/**\n * Parse the scale function of axis\n * @param {Object} axis The option of axis\n * @param {String} chartType The displayName of chart\n * @return {Function} The scale funcion\n */\n\nexport var parseScale = function parseScale(axis, chartType) {\n var scale = axis.scale,\n type = axis.type,\n layout = axis.layout,\n axisType = axis.axisType;\n\n if (scale === 'auto') {\n if (layout === 'radial' && axisType === 'radiusAxis') {\n return {\n scale: d3Scales.scaleBand(),\n realScaleType: 'band'\n };\n }\n\n if (layout === 'radial' && axisType === 'angleAxis') {\n return {\n scale: d3Scales.scaleLinear(),\n realScaleType: 'linear'\n };\n }\n\n if (type === 'category' && chartType && (chartType.indexOf('LineChart') >= 0 || chartType.indexOf('AreaChart') >= 0)) {\n return {\n scale: d3Scales.scalePoint(),\n realScaleType: 'point'\n };\n }\n\n if (type === 'category') {\n return {\n scale: d3Scales.scaleBand(),\n realScaleType: 'band'\n };\n }\n\n return {\n scale: d3Scales.scaleLinear(),\n realScaleType: 'linear'\n };\n }\n\n if (_isString(scale)) {\n var name = \"scale\".concat(scale.slice(0, 1).toUpperCase()).concat(scale.slice(1));\n return {\n scale: (d3Scales[name] || d3Scales.scalePoint)(),\n realScaleType: d3Scales[name] ? name : 'point'\n };\n }\n\n return _isFunction(scale) ? {\n scale: scale\n } : {\n scale: d3Scales.scalePoint(),\n realScaleType: 'point'\n };\n};\nvar EPS = 1e-4;\nexport var checkDomainOfScale = function checkDomainOfScale(scale) {\n var domain = scale.domain();\n\n if (!domain || domain.length <= 2) {\n return;\n }\n\n var len = domain.length;\n var range = scale.range();\n var min = Math.min(range[0], range[1]) - EPS;\n var max = Math.max(range[0], range[1]) + EPS;\n var first = scale(domain[0]);\n var last = scale(domain[len - 1]);\n\n if (first < min || first > max || last < min || last > max) {\n scale.domain([domain[0], domain[len - 1]]);\n }\n};\nexport var findPositionOfBar = function findPositionOfBar(barPosition, child) {\n if (!barPosition) {\n return null;\n }\n\n for (var i = 0, len = barPosition.length; i < len; i++) {\n if (barPosition[i].item === child) {\n return barPosition[i].position;\n }\n }\n\n return null;\n};\nexport var truncateByDomain = function truncateByDomain(value, domain) {\n if (!domain || domain.length !== 2 || !isNumber(domain[0]) || !isNumber(domain[1])) {\n return value;\n }\n\n var min = Math.min(domain[0], domain[1]);\n var max = Math.max(domain[0], domain[1]);\n var result = [value[0], value[1]];\n\n if (!isNumber(value[0]) || value[0] < min) {\n result[0] = min;\n }\n\n if (!isNumber(value[1]) || value[1] > max) {\n result[1] = max;\n }\n\n if (result[0] > max) {\n result[0] = max;\n }\n\n if (result[1] < min) {\n result[1] = min;\n }\n\n return result;\n};\n/* eslint no-param-reassign: 0 */\n\nexport var offsetSign = function offsetSign(series) {\n var n = series.length;\n\n if (n <= 0) {\n return;\n }\n\n for (var j = 0, m = series[0].length; j < m; ++j) {\n var positive = 0;\n var negative = 0;\n\n for (var i = 0; i < n; ++i) {\n var value = _isNaN(series[i][j][1]) ? series[i][j][0] : series[i][j][1];\n /* eslint-disable prefer-destructuring */\n\n if (value >= 0) {\n series[i][j][0] = positive;\n series[i][j][1] = positive + value;\n positive = series[i][j][1];\n } else {\n series[i][j][0] = negative;\n series[i][j][1] = negative + value;\n negative = series[i][j][1];\n }\n /* eslint-enable prefer-destructuring */\n\n }\n }\n};\nvar STACK_OFFSET_MAP = {\n sign: offsetSign,\n expand: stackOffsetExpand,\n none: stackOffsetNone,\n silhouette: stackOffsetSilhouette,\n wiggle: stackOffsetWiggle\n};\nexport var getStackedData = function getStackedData(data, stackItems, offsetType) {\n var dataKeys = stackItems.map(function (item) {\n return item.props.dataKey;\n });\n var stack = shapeStack().keys(dataKeys).value(function (d, key) {\n return +getValueByDataKey(d, key, 0);\n }).order(stackOrderNone).offset(STACK_OFFSET_MAP[offsetType]);\n return stack(data);\n};\nexport var getStackGroupsByAxisId = function getStackGroupsByAxisId(data, _items, numericAxisId, cateAxisId, offsetType, reverseStackOrder) {\n if (!data) {\n return null;\n } // reversing items to affect render order (for layering)\n\n\n var items = reverseStackOrder ? _items.reverse() : _items;\n var stackGroups = items.reduce(function (result, item) {\n var _item$props2 = item.props,\n stackId = _item$props2.stackId,\n hide = _item$props2.hide;\n\n if (hide) {\n return result;\n }\n\n var axisId = item.props[numericAxisId];\n var parentGroup = result[axisId] || {\n hasStack: false,\n stackGroups: {}\n };\n\n if (isNumOrStr(stackId)) {\n var childGroup = parentGroup.stackGroups[stackId] || {\n numericAxisId: numericAxisId,\n cateAxisId: cateAxisId,\n items: []\n };\n childGroup.items.push(item);\n parentGroup.hasStack = true;\n parentGroup.stackGroups[stackId] = childGroup;\n } else {\n parentGroup.stackGroups[uniqueId('_stackId_')] = {\n numericAxisId: numericAxisId,\n cateAxisId: cateAxisId,\n items: [item]\n };\n }\n\n return _objectSpread({}, result, _defineProperty({}, axisId, parentGroup));\n }, {});\n return Object.keys(stackGroups).reduce(function (result, axisId) {\n var group = stackGroups[axisId];\n\n if (group.hasStack) {\n group.stackGroups = Object.keys(group.stackGroups).reduce(function (res, stackId) {\n var g = group.stackGroups[stackId];\n return _objectSpread({}, res, _defineProperty({}, stackId, {\n numericAxisId: numericAxisId,\n cateAxisId: cateAxisId,\n items: g.items,\n stackedData: getStackedData(data, g.items, offsetType)\n }));\n }, {});\n }\n\n return _objectSpread({}, result, _defineProperty({}, axisId, group));\n }, {});\n};\n/**\n * get domain of ticks\n * @param {Array} ticks Ticks of axis\n * @param {String} type The type of axis\n * @return {Array} domain\n */\n\nexport var calculateDomainOfTicks = function calculateDomainOfTicks(ticks, type) {\n if (type === 'number') {\n return [Math.min.apply(null, ticks), Math.max.apply(null, ticks)];\n }\n\n return ticks;\n};\n/**\n * Configure the scale function of axis\n * @param {Object} scale The scale function\n * @param {Object} opts The configuration of axis\n * @return {Object} null\n */\n\nexport var getTicksOfScale = function getTicksOfScale(scale, opts) {\n var realScaleType = opts.realScaleType,\n type = opts.type,\n tickCount = opts.tickCount,\n originalDomain = opts.originalDomain,\n allowDecimals = opts.allowDecimals;\n var scaleType = realScaleType || opts.scale;\n\n if (scaleType !== 'auto' && scaleType !== 'linear') {\n return null;\n }\n\n if (tickCount && type === 'number' && originalDomain && (originalDomain[0] === 'auto' || originalDomain[1] === 'auto')) {\n // Calculate the ticks by the number of grid when the axis is a number axis\n var domain = scale.domain();\n var tickValues = getNiceTickValues(domain, tickCount, allowDecimals);\n scale.domain(calculateDomainOfTicks(tickValues, type));\n return {\n niceTicks: tickValues\n };\n }\n\n if (tickCount && type === 'number') {\n var _domain = scale.domain();\n\n var _tickValues = getTickValuesFixedDomain(_domain, tickCount, allowDecimals);\n\n return {\n niceTicks: _tickValues\n };\n }\n\n return null;\n};\nexport var getCateCoordinateOfLine = function getCateCoordinateOfLine(_ref6) {\n var axis = _ref6.axis,\n ticks = _ref6.ticks,\n bandSize = _ref6.bandSize,\n entry = _ref6.entry,\n index = _ref6.index,\n dataKey = _ref6.dataKey;\n\n if (axis.type === 'category') {\n // find coordinate of category axis by the value of category\n if (!axis.allowDuplicatedCategory && axis.dataKey && !_isNil(entry[axis.dataKey])) {\n var matchedTick = findEntryInArray(ticks, 'value', entry[axis.dataKey]);\n\n if (matchedTick) {\n return matchedTick.coordinate + bandSize / 2;\n }\n }\n\n return ticks[index] ? ticks[index].coordinate + bandSize / 2 : null;\n }\n\n var value = getValueByDataKey(entry, !_isNil(dataKey) ? dataKey : axis.dataKey);\n return !_isNil(value) ? axis.scale(value) : null;\n};\nexport var getCateCoordinateOfBar = function getCateCoordinateOfBar(_ref7) {\n var axis = _ref7.axis,\n ticks = _ref7.ticks,\n offset = _ref7.offset,\n bandSize = _ref7.bandSize,\n entry = _ref7.entry,\n index = _ref7.index;\n\n if (axis.type === 'category') {\n return ticks[index] ? ticks[index].coordinate + offset : null;\n }\n\n var value = getValueByDataKey(entry, axis.dataKey, axis.domain[index]);\n return !_isNil(value) ? axis.scale(value) - bandSize / 2 + offset : null;\n};\nexport var getBaseValueOfBar = function getBaseValueOfBar(_ref8) {\n var numericAxis = _ref8.numericAxis;\n var domain = numericAxis.scale.domain();\n\n if (numericAxis.type === 'number') {\n var min = Math.min(domain[0], domain[1]);\n var max = Math.max(domain[0], domain[1]);\n\n if (min <= 0 && max >= 0) {\n return 0;\n }\n\n if (max < 0) {\n return max;\n }\n\n return min;\n }\n\n return domain[0];\n};\nexport var ifOverflowMatches = function ifOverflowMatches(props, value) {\n var alwaysShow = props.alwaysShow;\n var ifOverflow = props.ifOverflow;\n\n if (alwaysShow) {\n ifOverflow = 'extendDomain';\n }\n\n return ifOverflow === value;\n};\nexport var detectReferenceElementsDomain = function detectReferenceElementsDomain(children, domain, axisId, axisType, specifiedTicks) {\n var lines = findAllByType(children, ReferenceLine);\n var dots = findAllByType(children, ReferenceDot);\n var elements = lines.concat(dots);\n var areas = findAllByType(children, ReferenceArea);\n var idKey = \"\".concat(axisType, \"Id\");\n var valueKey = axisType[0];\n var finalDomain = domain;\n\n if (elements.length) {\n finalDomain = elements.reduce(function (result, el) {\n if (el.props[idKey] === axisId && ifOverflowMatches(el.props, 'extendDomain') && isNumber(el.props[valueKey])) {\n var value = el.props[valueKey];\n return [Math.min(result[0], value), Math.max(result[1], value)];\n }\n\n return result;\n }, finalDomain);\n }\n\n if (areas.length) {\n var key1 = \"\".concat(valueKey, \"1\");\n var key2 = \"\".concat(valueKey, \"2\");\n finalDomain = areas.reduce(function (result, el) {\n if (el.props[idKey] === axisId && ifOverflowMatches(el.props, 'extendDomain') && isNumber(el.props[key1]) && isNumber(el.props[key2])) {\n var value1 = el.props[key1];\n var value2 = el.props[key2];\n return [Math.min(result[0], value1, value2), Math.max(result[1], value1, value2)];\n }\n\n return result;\n }, finalDomain);\n }\n\n if (specifiedTicks && specifiedTicks.length) {\n finalDomain = specifiedTicks.reduce(function (result, tick) {\n if (isNumber(tick)) {\n return [Math.min(result[0], tick), Math.max(result[1], tick)];\n }\n\n return result;\n }, finalDomain);\n }\n\n return finalDomain;\n};\nexport var getStackedDataOfItem = function getStackedDataOfItem(item, stackGroups) {\n var stackId = item.props.stackId;\n\n if (isNumOrStr(stackId)) {\n var group = stackGroups[stackId];\n\n if (group && group.items.length) {\n var itemIndex = -1;\n\n for (var i = 0, len = group.items.length; i < len; i++) {\n if (group.items[i] === item) {\n itemIndex = i;\n break;\n }\n }\n\n return itemIndex >= 0 ? group.stackedData[itemIndex] : null;\n }\n }\n\n return null;\n};\n\nvar getDomainOfSingle = function getDomainOfSingle(data) {\n return data.reduce(function (result, entry) {\n return [Math.min.apply(null, entry.concat([result[0]]).filter(isNumber)), Math.max.apply(null, entry.concat([result[1]]).filter(isNumber))];\n }, [Infinity, -Infinity]);\n};\n\nexport var getDomainOfStackGroups = function getDomainOfStackGroups(stackGroups, startIndex, endIndex) {\n return Object.keys(stackGroups).reduce(function (result, stackId) {\n var group = stackGroups[stackId];\n var stackedData = group.stackedData;\n var domain = stackedData.reduce(function (res, entry) {\n var s = getDomainOfSingle(entry.slice(startIndex, endIndex + 1));\n return [Math.min(res[0], s[0]), Math.max(res[1], s[1])];\n }, [Infinity, -Infinity]);\n return [Math.min(domain[0], result[0]), Math.max(domain[1], result[1])];\n }, [Infinity, -Infinity]).map(function (result) {\n return result === Infinity || result === -Infinity ? 0 : result;\n });\n};\nexport var MIN_VALUE_REG = /^dataMin[\\s]*-[\\s]*([0-9]+([.]{1}[0-9]+){0,1})$/;\nexport var MAX_VALUE_REG = /^dataMax[\\s]*\\+[\\s]*([0-9]+([.]{1}[0-9]+){0,1})$/;\nexport var parseSpecifiedDomain = function parseSpecifiedDomain(specifiedDomain, dataDomain, allowDataOverflow) {\n if (!_isArray(specifiedDomain)) {\n return dataDomain;\n }\n\n var domain = [];\n /* eslint-disable prefer-destructuring */\n\n if (isNumber(specifiedDomain[0])) {\n domain[0] = allowDataOverflow ? specifiedDomain[0] : Math.min(specifiedDomain[0], dataDomain[0]);\n } else if (MIN_VALUE_REG.test(specifiedDomain[0])) {\n var value = +MIN_VALUE_REG.exec(specifiedDomain[0])[1];\n domain[0] = dataDomain[0] - value;\n } else if (_isFunction(specifiedDomain[0])) {\n domain[0] = specifiedDomain[0](dataDomain[0]);\n } else {\n domain[0] = dataDomain[0];\n }\n\n if (isNumber(specifiedDomain[1])) {\n domain[1] = allowDataOverflow ? specifiedDomain[1] : Math.max(specifiedDomain[1], dataDomain[1]);\n } else if (MAX_VALUE_REG.test(specifiedDomain[1])) {\n var _value = +MAX_VALUE_REG.exec(specifiedDomain[1])[1];\n\n domain[1] = dataDomain[1] + _value;\n } else if (_isFunction(specifiedDomain[1])) {\n domain[1] = specifiedDomain[1](dataDomain[1]);\n } else {\n domain[1] = dataDomain[1];\n }\n /* eslint-enable prefer-destructuring */\n\n\n return domain;\n};\n/**\n * Calculate the size between two category\n * @param {Object} axis The options of axis\n * @param {Array} ticks The ticks of axis\n * @return {Number} Size\n */\n\nexport var getBandSizeOfAxis = function getBandSizeOfAxis(axis, ticks) {\n if (axis && axis.scale && axis.scale.bandwidth) {\n return axis.scale.bandwidth();\n }\n\n if (axis && ticks && ticks.length >= 2) {\n var orderedTicks = _sortBy(ticks, function (o) {\n return o.coordinate;\n });\n\n var bandSize = Infinity;\n\n for (var i = 1, len = orderedTicks.length; i < len; i++) {\n var cur = orderedTicks[i];\n var prev = orderedTicks[i - 1];\n bandSize = Math.min((cur.coordinate || 0) - (prev.coordinate || 0), bandSize);\n }\n\n return bandSize === Infinity ? 0 : bandSize;\n }\n\n return 0;\n};\n/**\n * parse the domain of a category axis when a domain is specified\n * @param {Array} specifiedDomain The domain specified by users\n * @param {Array} calculatedDomain The domain calculated by dateKey\n * @param {ReactElement} axisChild The axis element\n * @returns {Array} domains\n */\n\nexport var parseDomainOfCategoryAxis = function parseDomainOfCategoryAxis(specifiedDomain, calculatedDomain, axisChild) {\n if (!specifiedDomain || !specifiedDomain.length) {\n return calculatedDomain;\n }\n\n if (_isEqual(specifiedDomain, _get(axisChild, 'type.defaultProps.domain'))) {\n return calculatedDomain;\n }\n\n return specifiedDomain;\n};", + "function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nimport { isSsr } from './ReactUtils';\nvar stringCache = {\n widthCache: {},\n cacheCount: 0\n};\nvar MAX_CACHE_NUM = 2000;\nvar SPAN_STYLE = {\n position: 'absolute',\n top: '-20000px',\n left: 0,\n padding: 0,\n margin: 0,\n border: 'none',\n whiteSpace: 'pre'\n};\nvar STYLE_LIST = ['minWidth', 'maxWidth', 'width', 'minHeight', 'maxHeight', 'height', 'top', 'left', 'fontSize', 'lineHeight', 'padding', 'margin', 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom'];\nvar MEASUREMENT_SPAN_ID = 'recharts_measurement_span';\n\nfunction autoCompleteStyle(name, value) {\n if (STYLE_LIST.indexOf(name) >= 0 && value === +value) {\n return \"\".concat(value, \"px\");\n }\n\n return value;\n}\n\nfunction camelToMiddleLine(text) {\n var strs = text.split('');\n var formatStrs = strs.reduce(function (result, entry) {\n if (entry === entry.toUpperCase()) {\n return _toConsumableArray(result).concat(['-', entry.toLowerCase()]);\n }\n\n return _toConsumableArray(result).concat([entry]);\n }, []);\n return formatStrs.join('');\n}\n\nexport var getStyleString = function getStyleString(style) {\n return Object.keys(style).reduce(function (result, s) {\n return \"\".concat(result).concat(camelToMiddleLine(s), \":\").concat(autoCompleteStyle(s, style[s]), \";\");\n }, '');\n};\nexport var getStringSize = function getStringSize(text) {\n var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (text === undefined || text === null || isSsr()) {\n return {\n width: 0,\n height: 0\n };\n }\n\n var str = \"\".concat(text);\n var styleString = getStyleString(style);\n var cacheKey = \"\".concat(str, \"-\").concat(styleString);\n\n if (stringCache.widthCache[cacheKey]) {\n return stringCache.widthCache[cacheKey];\n }\n\n try {\n var measurementSpan = document.getElementById(MEASUREMENT_SPAN_ID);\n\n if (!measurementSpan) {\n measurementSpan = document.createElement('span');\n measurementSpan.setAttribute('id', MEASUREMENT_SPAN_ID);\n document.body.appendChild(measurementSpan);\n } // Need to use CSS Object Model (CSSOM) to be able to comply with Content Security Policy (CSP)\n // https://en.wikipedia.org/wiki/Content_Security_Policy\n\n\n var measurementSpanStyle = _objectSpread({}, SPAN_STYLE, style);\n\n Object.keys(measurementSpanStyle).map(function (styleKey) {\n measurementSpan.style[styleKey] = measurementSpanStyle[styleKey];\n return styleKey;\n });\n measurementSpan.textContent = str;\n var rect = measurementSpan.getBoundingClientRect();\n var result = {\n width: rect.width,\n height: rect.height\n };\n stringCache.widthCache[cacheKey] = result;\n\n if (++stringCache.cacheCount > MAX_CACHE_NUM) {\n stringCache.cacheCount = 0;\n stringCache.widthCache = {};\n }\n\n return result;\n } catch (e) {\n return {\n width: 0,\n height: 0\n };\n }\n};\nexport var getOffset = function getOffset(el) {\n var html = el.ownerDocument.documentElement;\n var box = {\n top: 0,\n left: 0\n }; // If we don't have gBCR, just use 0,0 rather than error\n // BlackBerry 5, iOS 3 (original iPhone)\n\n if (typeof el.getBoundingClientRect !== 'undefined') {\n box = el.getBoundingClientRect();\n }\n\n return {\n top: box.top + window.pageYOffset - html.clientTop,\n left: box.left + window.pageXOffset - html.clientLeft\n };\n};\n/**\n * Calculate coordinate of cursor in chart\n * @param {Object} event Event object\n * @param {Object} offset The offset of main part in the svg element\n * @return {Object} {chartX, chartY}\n */\n\nexport var calculateChartCoordinate = function calculateChartCoordinate(event, offset) {\n return {\n chartX: Math.round(event.pageX - offset.left),\n chartY: Math.round(event.pageY - offset.top)\n };\n};", + "import _get from \"lodash/get\";\nimport _isArray from \"lodash/isArray\";\nimport _isNaN from \"lodash/isNaN\";\nimport _isNumber from \"lodash/isNumber\";\nimport _isString from \"lodash/isString\";\nexport var mathSign = function mathSign(value) {\n if (value === 0) {\n return 0;\n }\n\n if (value > 0) {\n return 1;\n }\n\n return -1;\n};\nexport var isPercent = function isPercent(value) {\n return _isString(value) && value.indexOf('%') === value.length - 1;\n};\nexport var isNumber = function isNumber(value) {\n return _isNumber(value) && !_isNaN(value);\n};\nexport var isNumOrStr = function isNumOrStr(value) {\n return isNumber(value) || _isString(value);\n};\nvar idCounter = 0;\nexport var uniqueId = function uniqueId(prefix) {\n var id = ++idCounter;\n return \"\".concat(prefix || '').concat(id);\n};\n/**\n * Get percent value of a total value\n * @param {Number|String} percent A percent\n * @param {Number} totalValue Total value\n * @param {NUmber} defaultValue The value returned when percent is undefined or invalid\n * @param {Boolean} validate If set to be true, the result will be validated\n * @return {Number} value\n */\n\nexport var getPercentValue = function getPercentValue(percent, totalValue) {\n var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n var validate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n\n if (!isNumber(percent) && !_isString(percent)) {\n return defaultValue;\n }\n\n var value;\n\n if (isPercent(percent)) {\n var index = percent.indexOf('%');\n value = totalValue * parseFloat(percent.slice(0, index)) / 100;\n } else {\n value = +percent;\n }\n\n if (_isNaN(value)) {\n value = defaultValue;\n }\n\n if (validate && value > totalValue) {\n value = totalValue;\n }\n\n return value;\n};\nexport var getAnyElementOfObject = function getAnyElementOfObject(obj) {\n if (!obj) {\n return null;\n }\n\n var keys = Object.keys(obj);\n\n if (keys && keys.length) {\n return obj[keys[0]];\n }\n\n return null;\n};\nexport var hasDuplicate = function hasDuplicate(ary) {\n if (!_isArray(ary)) {\n return false;\n }\n\n var len = ary.length;\n var cache = {};\n\n for (var i = 0; i < len; i++) {\n if (!cache[ary[i]]) {\n cache[ary[i]] = true;\n } else {\n return true;\n }\n }\n\n return false;\n};\nexport var interpolateNumber = function interpolateNumber(numberA, numberB) {\n if (isNumber(numberA) && isNumber(numberB)) {\n return function (t) {\n return numberA + t * (numberB - numberA);\n };\n }\n\n return function () {\n return numberB;\n };\n};\nexport var findEntryInArray = function findEntryInArray(ary, specifiedKey, specifiedValue) {\n if (!ary || !ary.length) {\n return null;\n }\n\n return ary.find(function (entry) {\n return entry && _get(entry, specifiedKey) === specifiedValue;\n });\n};\n/**\n * The least square linear regression\n * @param {Array} data The array of points\n * @returns {Object} The domain of x, and the parameter of linear function\n */\n\nexport var getLinearRegression = function getLinearRegression(data) {\n if (!data || !data.length) {\n return null;\n }\n\n var len = data.length;\n var xsum = 0;\n var ysum = 0;\n var xysum = 0;\n var xxsum = 0;\n var xmin = Infinity;\n var xmax = -Infinity;\n\n for (var i = 0; i < len; i++) {\n xsum += data[i].cx;\n ysum += data[i].cy;\n xysum += data[i].cx * data[i].cy;\n xxsum += data[i].cx * data[i].cx;\n xmin = Math.min(xmin, data[i].cx);\n xmax = Math.max(xmax, data[i].cx);\n }\n\n var a = len * xxsum !== xsum * xsum ? (len * xysum - xsum * ysum) / (len * xxsum - xsum * xsum) : 0;\n return {\n xmin: xmin,\n xmax: xmax,\n a: a,\n b: (ysum - a * xsum) / len\n };\n};", + "/* eslint no-console: 0 */\nvar isDev = process.env.NODE_ENV !== 'production';\nexport var warn = function warn(condition, format, a, b, c, d, e, f) {\n if (isDev && typeof console !== 'undefined' && console.warn) {\n if (format === undefined) {\n console.warn('LogUtils requires an error message argument');\n }\n\n if (!condition) {\n if (format === undefined) {\n console.warn('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');\n } else {\n var args = [a, b, c, d, e, f];\n var argIndex = 0;\n console.warn(format.replace(/%s/g, function () {\n return args[argIndex++];\n }));\n }\n }\n }\n};", + "import _isNil from \"lodash/isNil\";\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); }\n\nfunction _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\nimport { getPercentValue } from './DataUtils';\nimport { parseScale, checkDomainOfScale, getTicksOfScale } from './ChartUtils';\nexport var RADIAN = Math.PI / 180;\nexport var degreeToRadian = function degreeToRadian(angle) {\n return angle * Math.PI / 180;\n};\nexport var radianToDegree = function radianToDegree(angleInRadian) {\n return angleInRadian * 180 / Math.PI;\n};\nexport var polarToCartesian = function polarToCartesian(cx, cy, radius, angle) {\n return {\n x: cx + Math.cos(-RADIAN * angle) * radius,\n y: cy + Math.sin(-RADIAN * angle) * radius\n };\n};\nexport var getMaxRadius = function getMaxRadius(width, height) {\n var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n return Math.min(Math.abs(width - (offset.left || 0) - (offset.right || 0)), Math.abs(height - (offset.top || 0) - (offset.bottom || 0))) / 2;\n};\n/**\n * Calculate the scale function, position, width, height of axes\n * @param {Object} props Latest props\n * @param {Object} axisMap The configuration of axes\n * @param {Object} offset The offset of main part in the svg element\n * @param {Object} axisType The type of axes, radius-axis or angle-axis\n * @param {String} chartName The name of chart\n * @return {Object} Configuration\n */\n\nexport var formatAxisMap = function formatAxisMap(props, axisMap, offset, axisType, chartName) {\n var width = props.width,\n height = props.height;\n var startAngle = props.startAngle,\n endAngle = props.endAngle;\n var cx = getPercentValue(props.cx, width, width / 2);\n var cy = getPercentValue(props.cy, height, height / 2);\n var maxRadius = getMaxRadius(width, height, offset);\n var innerRadius = getPercentValue(props.innerRadius, maxRadius, 0);\n var outerRadius = getPercentValue(props.outerRadius, maxRadius, maxRadius * 0.8);\n var ids = Object.keys(axisMap);\n return ids.reduce(function (result, id) {\n var axis = axisMap[id];\n var domain = axis.domain,\n reversed = axis.reversed;\n var range;\n\n if (_isNil(axis.range)) {\n if (axisType === 'angleAxis') {\n range = [startAngle, endAngle];\n } else if (axisType === 'radiusAxis') {\n range = [innerRadius, outerRadius];\n }\n\n if (reversed) {\n range = [range[1], range[0]];\n }\n } else {\n range = axis.range;\n var _range = range;\n\n var _range2 = _slicedToArray(_range, 2);\n\n startAngle = _range2[0];\n endAngle = _range2[1];\n }\n\n var _parseScale = parseScale(axis, chartName),\n realScaleType = _parseScale.realScaleType,\n scale = _parseScale.scale;\n\n scale.domain(domain).range(range);\n checkDomainOfScale(scale);\n var ticks = getTicksOfScale(scale, _objectSpread({}, axis, {\n realScaleType: realScaleType\n }));\n\n var finalAxis = _objectSpread({}, axis, ticks, {\n range: range,\n radius: outerRadius,\n realScaleType: realScaleType,\n scale: scale,\n cx: cx,\n cy: cy,\n innerRadius: innerRadius,\n outerRadius: outerRadius,\n startAngle: startAngle,\n endAngle: endAngle\n });\n\n return _objectSpread({}, result, _defineProperty({}, id, finalAxis));\n }, {});\n};\nexport var distanceBetweenPoints = function distanceBetweenPoints(point, anotherPoint) {\n var x1 = point.x,\n y1 = point.y;\n var x2 = anotherPoint.x,\n y2 = anotherPoint.y;\n return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));\n};\nexport var getAngleOfPoint = function getAngleOfPoint(_ref, _ref2) {\n var x = _ref.x,\n y = _ref.y;\n var cx = _ref2.cx,\n cy = _ref2.cy;\n var radius = distanceBetweenPoints({\n x: x,\n y: y\n }, {\n x: cx,\n y: cy\n });\n\n if (radius <= 0) {\n return {\n radius: radius\n };\n }\n\n var cos = (x - cx) / radius;\n var angleInRadian = Math.acos(cos);\n\n if (y > cy) {\n angleInRadian = 2 * Math.PI - angleInRadian;\n }\n\n return {\n radius: radius,\n angle: radianToDegree(angleInRadian),\n angleInRadian: angleInRadian\n };\n};\nexport var formatAngleOfSector = function formatAngleOfSector(_ref3) {\n var startAngle = _ref3.startAngle,\n endAngle = _ref3.endAngle;\n var startCnt = Math.floor(startAngle / 360);\n var endCnt = Math.floor(endAngle / 360);\n var min = Math.min(startCnt, endCnt);\n return {\n startAngle: startAngle - min * 360,\n endAngle: endAngle - min * 360\n };\n};\n\nvar reverseFormatAngleOfSetor = function reverseFormatAngleOfSetor(angle, _ref4) {\n var startAngle = _ref4.startAngle,\n endAngle = _ref4.endAngle;\n var startCnt = Math.floor(startAngle / 360);\n var endCnt = Math.floor(endAngle / 360);\n var min = Math.min(startCnt, endCnt);\n return angle + min * 360;\n};\n\nexport var inRangeOfSector = function inRangeOfSector(_ref5, sector) {\n var x = _ref5.x,\n y = _ref5.y;\n\n var _getAngleOfPoint = getAngleOfPoint({\n x: x,\n y: y\n }, sector),\n radius = _getAngleOfPoint.radius,\n angle = _getAngleOfPoint.angle;\n\n var innerRadius = sector.innerRadius,\n outerRadius = sector.outerRadius;\n\n if (radius < innerRadius || radius > outerRadius) {\n return false;\n }\n\n if (radius === 0) {\n return true;\n }\n\n var _formatAngleOfSector = formatAngleOfSector(sector),\n startAngle = _formatAngleOfSector.startAngle,\n endAngle = _formatAngleOfSector.endAngle;\n\n var formatAngle = angle;\n var inRange;\n\n if (startAngle <= endAngle) {\n while (formatAngle > endAngle) {\n formatAngle -= 360;\n }\n\n while (formatAngle < startAngle) {\n formatAngle += 360;\n }\n\n inRange = formatAngle >= startAngle && formatAngle <= endAngle;\n } else {\n while (formatAngle > startAngle) {\n formatAngle -= 360;\n }\n\n while (formatAngle < endAngle) {\n formatAngle += 360;\n }\n\n inRange = formatAngle >= endAngle && formatAngle <= startAngle;\n }\n\n if (inRange) {\n return _objectSpread({}, sector, {\n radius: radius,\n angle: reverseFormatAngleOfSetor(formatAngle, sector)\n });\n }\n\n return null;\n};", + "export function shallowEqual(a, b) {\n /* eslint-disable no-restricted-syntax */\n for (var key in a) {\n if ({}.hasOwnProperty.call(a, key) && (!{}.hasOwnProperty.call(b, key) || a[key] !== b[key])) {\n return false;\n }\n }\n\n for (var _key in b) {\n if ({}.hasOwnProperty.call(b, _key) && !{}.hasOwnProperty.call(a, _key)) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction shouldComponentUpdate(props, state) {\n return !shallowEqual(props, this.props) || !shallowEqual(state, this.state);\n}\n\nexport default function pureRenderDecorator(component) {\n // eslint-disable-next-line no-param-reassign\n component.prototype.shouldComponentUpdate = shouldComponentUpdate;\n}", + "import _isNil from \"lodash/isNil\";\nimport _isString from \"lodash/isString\";\nimport _isObject from \"lodash/isObject\";\nimport _isFunction from \"lodash/isFunction\";\nimport _isArray from \"lodash/isArray\";\n\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nimport React, { Children } from 'react';\nimport PropTypes from 'prop-types';\nimport { isNumber } from './DataUtils';\nimport { shallowEqual } from './PureRender';\nexport var PRESENTATION_ATTRIBUTES = {\n 'aria-current': PropTypes.string,\n // state\n 'aria-details': PropTypes.any,\n 'aria-disabled': PropTypes.any,\n // state\n 'aria-hidden': PropTypes.any,\n // state\n 'aria-invalid': PropTypes.any,\n // state\n 'aria-keyshortcuts': PropTypes.any,\n 'aria-label': PropTypes.any,\n 'aria-roledescription': PropTypes.any,\n // Widget Attributes\n 'aria-autocomplete': PropTypes.any,\n 'aria-checked': PropTypes.any,\n 'aria-expanded': PropTypes.any,\n 'aria-haspopup': PropTypes.any,\n 'aria-level': PropTypes.any,\n 'aria-modal': PropTypes.any,\n 'aria-multiline': PropTypes.any,\n 'aria-multiselectable': PropTypes.any,\n 'aria-orientation': PropTypes.any,\n 'aria-placeholder': PropTypes.any,\n 'aria-pressed': PropTypes.any,\n 'aria-readonly': PropTypes.any,\n 'aria-required': PropTypes.any,\n 'aria-selected': PropTypes.any,\n 'aria-sort': PropTypes.any,\n 'aria-valuemax': PropTypes.any,\n 'aria-valuemin': PropTypes.any,\n 'aria-valuenow': PropTypes.any,\n 'aria-valuetext': PropTypes.any,\n // Live Region Attributes\n 'aria-atomic': PropTypes.any,\n 'aria-busy': PropTypes.any,\n 'aria-live': PropTypes.any,\n 'aria-relevant': PropTypes.any,\n // Drag-and-Drop Attributes\n 'aria-dropeffect': PropTypes.any,\n 'aria-grabbed': PropTypes.any,\n // Relationship Attributes\n 'aria-activedescendant': PropTypes.any,\n 'aria-colcount': PropTypes.any,\n 'aria-colindex': PropTypes.any,\n 'aria-colspan': PropTypes.any,\n 'aria-controls': PropTypes.any,\n 'aria-describedby': PropTypes.any,\n 'aria-errormessage': PropTypes.any,\n 'aria-flowto': PropTypes.any,\n 'aria-labelledby': PropTypes.any,\n 'aria-owns': PropTypes.any,\n 'aria-posinset': PropTypes.any,\n 'aria-rowcount': PropTypes.any,\n 'aria-rowindex': PropTypes.any,\n 'aria-rowspan': PropTypes.any,\n 'aria-setsize': PropTypes.any,\n alignmentBaseline: PropTypes.string,\n angle: PropTypes.number,\n baselineShift: PropTypes.string,\n clip: PropTypes.string,\n clipPath: PropTypes.string,\n clipRule: PropTypes.string,\n color: PropTypes.string,\n colorInterpolation: PropTypes.string,\n colorInterpolationFilters: PropTypes.string,\n colorProfile: PropTypes.string,\n colorRendering: PropTypes.string,\n cursor: PropTypes.string,\n direction: PropTypes.oneOf(['ltr', 'rtl', 'inherit']),\n display: PropTypes.string,\n dominantBaseline: PropTypes.string,\n enableBackground: PropTypes.string,\n fill: PropTypes.string,\n fillOpacity: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n fillRule: PropTypes.oneOf(['nonzero', 'evenodd', 'inherit']),\n filter: PropTypes.string,\n floodColor: PropTypes.string,\n floodOpacity: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n font: PropTypes.string,\n fontFamily: PropTypes.string,\n fontSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n fontSizeAdjust: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n fontStretch: PropTypes.oneOf(['normal', 'wider', 'narrower', 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded', 'inherit']),\n fontStyle: PropTypes.oneOf(['normal', 'italic', 'oblique', 'inherit']),\n fontVariant: PropTypes.oneOf(['normal', 'small-caps', 'inherit']),\n fontWeight: PropTypes.oneOf(['normal', 'bold', 'bolder', 'lighter', 100, 200, 300, 400, 500, 600, 700, 800, 900, 'inherit']),\n glyphOrientationHorizontal: PropTypes.string,\n glyphOrientationVertical: PropTypes.string,\n imageRendering: PropTypes.oneOf(['auto', 'optimizeSpeed', 'optimizeQuality', 'inherit']),\n kerning: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n letterSpacing: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n lightingColor: PropTypes.string,\n lineHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n markerEnd: PropTypes.string,\n markerMid: PropTypes.string,\n markerStart: PropTypes.string,\n mask: PropTypes.string,\n opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n overflow: PropTypes.oneOf(['visible', 'hidden', 'scroll', 'auto', 'inherit']),\n pointerEvents: PropTypes.oneOf(['visiblePainted', 'visibleFill', 'visibleStroke', 'visible', 'painted', 'fill', 'stroke', 'all', 'none', 'inherit']),\n shapeRendering: PropTypes.oneOf(['auto', 'optimizeSpeed', 'crispEdges', 'geometricPrecision', 'inherit']),\n stopColor: PropTypes.string,\n stopOpacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n stroke: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n strokeDasharray: PropTypes.string,\n strokeDashoffset: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n strokeLinecap: PropTypes.oneOf(['butt', 'round', 'square', 'inherit']),\n strokeLinejoin: PropTypes.oneOf(['miter', 'round', 'bevel', 'inherit']),\n strokeMiterlimit: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n strokeOpacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n strokeWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n textAnchor: PropTypes.oneOf(['start', 'middle', 'end', 'inherit']),\n textDecoration: PropTypes.oneOf(['none', 'underline', 'overline', 'line-through', 'blink', 'inherit']),\n textRendering: PropTypes.oneOf(['auto', 'optimizeSpeed', 'optimizeLegibility', 'geometricPrecision', 'inherit']),\n unicodeBidi: PropTypes.oneOf(['normal', 'embed', 'bidi-override', 'inherit']),\n visibility: PropTypes.oneOf(['visible', 'hidden', 'collapse', 'inherit']),\n wordSpacing: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n writingMode: PropTypes.oneOf(['lr-tb', 'rl-tb', 'tb-rl', 'lr', 'rl', 'tb', 'inherit']),\n transform: PropTypes.string,\n role: PropTypes.string,\n focusable: PropTypes.string,\n tabIndex: PropTypes.string,\n style: PropTypes.object,\n width: PropTypes.number,\n height: PropTypes.number,\n dx: PropTypes.number,\n dy: PropTypes.number,\n x: PropTypes.number,\n y: PropTypes.number,\n r: PropTypes.number,\n // The radius of Rectangle\n radius: PropTypes.oneOfType([PropTypes.number, PropTypes.array])\n};\nexport var EVENT_ATTRIBUTES = {\n onClick: PropTypes.func,\n onMouseDown: PropTypes.func,\n onMouseUp: PropTypes.func,\n onMouseOver: PropTypes.func,\n onMouseMove: PropTypes.func,\n onMouseOut: PropTypes.func,\n onMouseEnter: PropTypes.func,\n onMouseLeave: PropTypes.func,\n onTouchEnd: PropTypes.func,\n onTouchMove: PropTypes.func,\n onTouchStart: PropTypes.func,\n onTouchCancel: PropTypes.func\n};\nvar REACT_BROWSER_EVENT_MAP = {\n click: 'onClick',\n mousedown: 'onMouseDown',\n mouseup: 'onMouseUp',\n mouseover: 'onMouseOver',\n mousemove: 'onMouseMove',\n mouseout: 'onMouseOut',\n mouseenter: 'onMouseEnter',\n mouseleave: 'onMouseLeave',\n touchcancel: 'onTouchCancel',\n touchend: 'onTouchEnd',\n touchmove: 'onTouchMove',\n touchstart: 'onTouchStart'\n};\nexport var SCALE_TYPES = ['auto', 'linear', 'pow', 'sqrt', 'log', 'identity', 'time', 'band', 'point', 'ordinal', 'quantile', 'quantize', 'utc', 'sequential', 'threshold'];\nexport var LEGEND_TYPES = ['plainline', 'line', 'square', 'rect', 'circle', 'cross', 'diamond', 'star', 'triangle', 'wye', 'none'];\n/**\n * Get the display name of a component\n * @param {Object} Comp Specified Component\n * @return {String} Display name of Component\n */\n\nexport var getDisplayName = function getDisplayName(Comp) {\n if (typeof Comp === 'string') {\n return Comp;\n }\n\n if (!Comp) {\n return '';\n }\n\n return Comp.displayName || Comp.name || 'Component';\n};\n/*\n * Find and return all matched children by type. ` + ("`" + `type`))) + (("`" + (` can be a React element class or\n * string\n */\n\nexport var findAllByType = function findAllByType(children, type) {\n var result = [];\n var types = [];\n\n if (_isArray(type)) {\n types = type.map(function (t) {\n return getDisplayName(t);\n });\n } else {\n types = [getDisplayName(type)];\n }\n\n React.Children.forEach(children, function (child) {\n var childType = child && child.type && (child.type.displayName || child.type.name);\n\n if (types.indexOf(childType) !== -1) {\n result.push(child);\n }\n });\n return result;\n};\n/*\n * Return the first matched child by type, return null otherwise.\n * ` + "`")) + (`type` + ("`" + ` can be a React element class or string.\n */\n\nexport var findChildByType = function findChildByType(children, type) {\n var result = findAllByType(children, type);\n return result && result[0];\n};\n/*\n * Create a new array of children excluding the ones matched the type\n */\n\nexport var withoutType = function withoutType(children, type) {\n var newChildren = [];\n var types;\n\n if (_isArray(type)) {\n types = type.map(function (t) {\n return getDisplayName(t);\n });\n } else {\n types = [getDisplayName(type)];\n }\n\n React.Children.forEach(children, function (child) {\n if (child && child.type && child.type.displayName && types.indexOf(child.type.displayName) !== -1) {\n return;\n }\n\n newChildren.push(child);\n });\n return newChildren;\n};\n/**\n * get all the presentation attribute of svg element\n * @param {Object} el A react element or the props of a react element\n * @return {Object} attributes or null\n */\n\nexport var getPresentationAttributes = function getPresentationAttributes(el) {\n if (!el || _isFunction(el)) {\n return null;\n }\n\n var props = React.isValidElement(el) ? el.props : el;\n\n if (!_isObject(props)) {\n return null;\n }\n\n var out = null; // eslint-disable-next-line no-restricted-syntax\n\n for (var i in props) {\n if ({}.hasOwnProperty.call(props, i) && PRESENTATION_ATTRIBUTES[i]) {\n if (!out) out = {};\n out[i] = props[i];\n }\n }\n\n return out;\n};\n\nvar getEventHandlerOfElement = function getEventHandlerOfElement(originalHandler, props) {\n return function (e) {\n originalHandler(props, e);\n return null;\n };\n};\n/**\n * get all the event attribute of svg element\n * @param {Object} el A react element or the props of a react element\n * @param {Function} newHandler New handler of event\n * @param {Boolean} wrapCallback Wrap callback and return more parameters or not\n * @return {Object} attributes or null\n */\n\n\nexport var filterEventAttributes = function filterEventAttributes(el, newHandler) {\n var wrapCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n if (!el || _isFunction(el)) {\n return null;\n }\n\n var props = React.isValidElement(el) ? el.props : el;\n\n if (!_isObject(props)) {\n return null;\n }\n\n var out = null; // eslint-disable-next-line no-restricted-syntax\n\n for (var i in props) {\n if ({}.hasOwnProperty.call(props, i) && EVENT_ATTRIBUTES[i]) {\n if (!out) out = {};\n out[i] = newHandler || (wrapCallback ? getEventHandlerOfElement(props[i], props) : props[i]);\n }\n }\n\n return out;\n};\n\nvar getEventHandlerOfChild = function getEventHandlerOfChild(originalHandler, data, index) {\n return function (e) {\n originalHandler(data, index, e);\n return null;\n };\n};\n\nexport var filterEventsOfChild = function filterEventsOfChild(props, data, index) {\n if (!_isObject(props)) {\n return null;\n }\n\n var out = null; // eslint-disable-next-line no-restricted-syntax\n\n for (var i in props) {\n if ({}.hasOwnProperty.call(props, i) && EVENT_ATTRIBUTES[i] && _isFunction(props[i])) {\n if (!out) out = {};\n out[i] = getEventHandlerOfChild(props[i], data, index);\n }\n }\n\n return out;\n};\n/**\n * validate the width and height props of a chart element\n * @param {Object} el A chart element\n * @return {Boolean} true If the props width and height are number, and greater than 0\n */\n\nexport var validateWidthHeight = function validateWidthHeight(el) {\n if (!el || !el.props) {\n return false;\n }\n\n var _el$props = el.props,\n width = _el$props.width,\n height = _el$props.height;\n\n if (!isNumber(width) || width <= 0 || !isNumber(height) || height <= 0) {\n return false;\n }\n\n return true;\n};\nexport var isSsr = function isSsr() {\n return !(typeof window !== 'undefined' && window.document && window.document.createElement && window.setTimeout);\n};\nvar SVG_TAGS = ['a', 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColormatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-url', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'lineGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'stop', 'style', 'svg', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', 'tspan', 'use', 'view', 'vkern'];\n\nvar isSvgElement = function isSvgElement(child) {\n return child && child.type && _isString(child.type) && SVG_TAGS.indexOf(child.type) >= 0;\n};\n/**\n * Filter all the svg elements of children\n * @param {Array} children The children of a react element\n * @return {Array} All the svg elements\n */\n\n\nexport var filterSvgElements = function filterSvgElements(children) {\n var svgElements = [];\n React.Children.forEach(children, function (entry) {\n if (entry && entry.type && _isString(entry.type) && SVG_TAGS.indexOf(entry.type) >= 0) {\n svgElements.push(entry);\n }\n });\n return svgElements;\n};\nexport var isSingleChildEqual = function isSingleChildEqual(nextChild, prevChild) {\n if (_isNil(nextChild) && _isNil(prevChild)) {\n return true;\n }\n\n if (!_isNil(nextChild) && !_isNil(prevChild)) {\n var _ref = nextChild.props || {},\n nextChildren = _ref.children,\n nextProps = _objectWithoutProperties(_ref, [\"children\"]);\n\n var _ref2 = prevChild.props || {},\n prevChildren = _ref2.children,\n prevProps = _objectWithoutProperties(_ref2, [\"children\"]);\n\n if (nextChildren && prevChildren) {\n // eslint-disable-next-line no-use-before-define\n return shallowEqual(nextProps, prevProps) && isChildrenEqual(nextChildren, prevChildren);\n }\n\n if (!nextChildren && !prevChildren) {\n return shallowEqual(nextProps, prevProps);\n }\n\n return false;\n }\n\n return false;\n};\n/**\n * Wether props of children changed\n * @param {Object} nextChildren The latest children\n * @param {Object} prevChildren The prev children\n * @return {Boolean} equal or not\n */\n\nexport var isChildrenEqual = function isChildrenEqual(nextChildren, prevChildren) {\n if (nextChildren === prevChildren) {\n return true;\n }\n\n if (Children.count(nextChildren) !== Children.count(prevChildren)) {\n return false;\n }\n\n var count = Children.count(nextChildren);\n\n if (count === 0) {\n return true;\n }\n\n if (count === 1) {\n return isSingleChildEqual(_isArray(nextChildren) ? nextChildren[0] : nextChildren, _isArray(prevChildren) ? prevChildren[0] : prevChildren);\n }\n\n for (var i = 0; i < count; i++) {\n var nextChild = nextChildren[i];\n var prevChild = prevChildren[i];\n\n if (_isArray(nextChild) || _isArray(prevChild)) {\n if (!isChildrenEqual(nextChild, prevChild)) {\n return false;\n }\n } else if (!isSingleChildEqual(nextChild, prevChild)) {\n return false;\n }\n }\n\n return true;\n};\nexport var renderByOrder = function renderByOrder(children, renderMap) {\n var elements = [];\n var record = {};\n Children.forEach(children, function (child, index) {\n if (child && isSvgElement(child)) {\n elements.push(child);\n } else if (child && renderMap[getDisplayName(child.type)]) {\n var displayName = getDisplayName(child.type);\n var _renderMap$displayNam = renderMap[displayName],\n handler = _renderMap$displayNam.handler,\n once = _renderMap$displayNam.once;\n\n if (once && !record[displayName] || !once) {\n var results = handler(child, displayName, index);\n\n if (_isArray(results)) {\n elements = [elements].concat(_toConsumableArray(results));\n } else {\n elements.push(results);\n }\n\n record[displayName] = true;\n }\n }\n });\n return elements;\n};\nexport var getReactEventByType = function getReactEventByType(e) {\n var type = e && e.type;\n\n if (type && REACT_BROWSER_EVENT_MAP[type]) {\n return REACT_BROWSER_EVENT_MAP[type];\n }\n\n return null;\n};\nexport var parseChildIndex = function parseChildIndex(child, children) {\n var result = -1;\n Children.forEach(children, function (entry, index) {\n if (entry === child) {\n result = index;\n }\n });\n return result;\n};", + "require('../modules/es6.math.acosh');\nrequire('../modules/es6.math.asinh');\nrequire('../modules/es6.math.atanh');\nrequire('../modules/es6.math.cbrt');\nrequire('../modules/es6.math.clz32');\nrequire('../modules/es6.math.cosh');\nrequire('../modules/es6.math.expm1');\nrequire('../modules/es6.math.fround');\nrequire('../modules/es6.math.hypot');\nrequire('../modules/es6.math.imul');\nrequire('../modules/es6.math.log10');\nrequire('../modules/es6.math.log1p');\nrequire('../modules/es6.math.log2');\nrequire('../modules/es6.math.sign');\nrequire('../modules/es6.math.sinh');\nrequire('../modules/es6.math.tanh');\nrequire('../modules/es6.math.trunc');\nmodule.exports = require('../modules/_core').Math;\n", + "require('../modules/es6.number.constructor');\nrequire('../modules/es6.number.to-fixed');\nrequire('../modules/es6.number.to-precision');\nrequire('../modules/es6.number.epsilon');\nrequire('../modules/es6.number.is-finite');\nrequire('../modules/es6.number.is-integer');\nrequire('../modules/es6.number.is-nan');\nrequire('../modules/es6.number.is-safe-integer');\nrequire('../modules/es6.number.max-safe-integer');\nrequire('../modules/es6.number.min-safe-integer');\nrequire('../modules/es6.number.parse-float');\nrequire('../modules/es6.number.parse-int');\nmodule.exports = require('../modules/_core').Number;\n", + "module.exports = function (it) {\n if (typeof it != 'function') throw TypeError(it + ' is not a function!');\n return it;\n};\n", + "var cof = require('./_cof');\nmodule.exports = function (it, msg) {\n if (typeof it != 'number' && cof(it) != 'Number') throw TypeError(msg);\n return +it;\n};\n", + "var isObject = require('./_is-object');\nmodule.exports = function (it) {\n if (!isObject(it)) throw TypeError(it + ' is not an object!');\n return it;\n};\n", + "// false -> Array#indexOf\n// true -> Array#includes\nvar toIObject = require('./_to-iobject');\nvar toLength = require('./_to-length');\nvar toAbsoluteIndex = require('./_to-absolute-index');\nmodule.exports = function (IS_INCLUDES) {\n return function ($this, el, fromIndex) {\n var O = toIObject($this);\n var length = toLength(O.length);\n var index = toAbsoluteIndex(fromIndex, length);\n var value;\n // Array#includes uses SameValueZero equality algorithm\n // eslint-disable-next-line no-self-compare\n if (IS_INCLUDES && el != el) while (length > index) {\n value = O[index++];\n // eslint-disable-next-line no-self-compare\n if (value != value) return true;\n // Array#indexOf ignores holes, Array#includes - not\n } else for (;length > index; index++) if (IS_INCLUDES || index in O) {\n if (O[index] === el) return IS_INCLUDES || index || 0;\n } return !IS_INCLUDES && -1;\n };\n};\n", + "var toString = {}.toString;\n\nmodule.exports = function (it) {\n return toString.call(it).slice(8, -1);\n};\n", + "var core = module.exports = { version: '2.5.7' };\nif (typeof __e == 'number') __e = core; // eslint-disable-line no-undef\n", + "// optional / simple context binding\nvar aFunction = require('./_a-function');\nmodule.exports = function (fn, that, length) {\n aFunction(fn);\n if (that === undefined) return fn;\n switch (length) {\n case 1: return function (a) {\n return fn.call(that, a);\n };\n case 2: return function (a, b) {\n return fn.call(that, a, b);\n };\n case 3: return function (a, b, c) {\n return fn.call(that, a, b, c);\n };\n }\n return function (/* ...args */) {\n return fn.apply(that, arguments);\n };\n};\n", + "// 7.2.1 RequireObjectCoercible(argument)\nmodule.exports = function (it) {\n if (it == undefined) throw TypeError(\"Can't call method on \" + it);\n return it;\n};\n", + "// Thank's IE8 for his funny defineProperty\nmodule.exports = !require('./_fails')(function () {\n return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;\n});\n", + "var isObject = require('./_is-object');\nvar document = require('./_global').document;\n// typeof document.createElement is 'object' in old IE\nvar is = isObject(document) && isObject(document.createElement);\nmodule.exports = function (it) {\n return is ? document.createElement(it) : {};\n};\n", + "// IE 8- don't enum bug keys\nmodule.exports = (\n 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'\n).split(',');\n", + "var global = require('./_global');\nvar core = require('./_core');\nvar hide = require('./_hide');\nvar redefine = require('./_redefine');\nvar ctx = require('./_ctx');\nvar PROTOTYPE = 'prototype';\n\nvar $export = function (type, name, source) {\n var IS_FORCED = type & $export.F;\n var IS_GLOBAL = type & $export.G;\n var IS_STATIC = type & $export.S;\n var IS_PROTO = type & $export.P;\n var IS_BIND = type & $export.B;\n var target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE];\n var exports = IS_GLOBAL ? core : core[name] || (core[name] = {});\n var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {});\n var key, own, out, exp;\n if (IS_GLOBAL) source = name;\n for (key in source) {\n // contains in native\n own = !IS_FORCED && target && target[key] !== undefined;\n // export native or passed\n out = (own ? target : source)[key];\n // bind timers to global for call from export context\n exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;\n // extend global\n if (target) redefine(target, key, out, type & $export.U);\n // export\n if (exports[key] != out) hide(exports, key, exp);\n if (IS_PROTO && expProto[key] != out) expProto[key] = out;\n }\n};\nglobal.core = core;\n// type bitmap\n$export.F = 1; // forced\n$export.G = 2; // global\n$export.S = 4; // static\n$export.P = 8; // proto\n$export.B = 16; // bind\n$export.W = 32; // wrap\n$export.U = 64; // safe\n$export.R = 128; // real proto method for `)))) + ((("`" + `library`) + ("`" + (`\nmodule.exports = $export;\n", + "module.exports = function (exec) {\n try {\n return !!exec();\n } catch (e) {\n return true;\n }\n};\n", + "// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nvar global = module.exports = typeof window != 'undefined' && window.Math == Math\n ? window : typeof self != 'undefined' && self.Math == Math ? self\n // eslint-disable-next-line no-new-func\n : Function('return this')();\nif (typeof __g == 'number') __g = global; // eslint-disable-line no-undef\n", + "var hasOwnProperty = {}.hasOwnProperty;\nmodule.exports = function (it, key) {\n return hasOwnProperty.call(it, key);\n};\n", + "var dP = require('./_object-dp');\nvar createDesc = require('./_property-desc');\nmodule.exports = require('./_descriptors') ? function (object, key, value) {\n return dP.f(object, key, createDesc(1, value));\n} : function (object, key, value) {\n object[key] = value;\n return object;\n};\n", + "var document = require('./_global').document;\nmodule.exports = document && document.documentElement;\n", + "module.exports = !require('./_descriptors') && !require('./_fails')(function () {\n return Object.defineProperty(require('./_dom-create')('div'), 'a', { get: function () { return 7; } }).a != 7;\n});\n", + "var isObject = require('./_is-object');\nvar setPrototypeOf = require('./_set-proto').set;\nmodule.exports = function (that, target, C) {\n var S = target.constructor;\n var P;\n if (S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf) {\n setPrototypeOf(that, P);\n } return that;\n};\n", + "// fallback for non-array-like ES3 and non-enumerable old V8 strings\nvar cof = require('./_cof');\n// eslint-disable-next-line no-prototype-builtins\nmodule.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) {\n return cof(it) == 'String' ? it.split('') : Object(it);\n};\n", + "// 20.1.2.3 Number.isInteger(number)\nvar isObject = require('./_is-object');\nvar floor = Math.floor;\nmodule.exports = function isInteger(it) {\n return !isObject(it) && isFinite(it) && floor(it) === it;\n};\n", + "module.exports = function (it) {\n return typeof it === 'object' ? it !== null : typeof it === 'function';\n};\n", + "module.exports = false;\n", + "// 20.2.2.14 Math.expm1(x)\nvar $expm1 = Math.expm1;\nmodule.exports = (!$expm1\n // Old FF bug\n || $expm1(10) > 22025.465794806719 || $expm1(10) < 22025.4657948067165168\n // Tor Browser bug\n || $expm1(-2e-17) != -2e-17\n) ? function expm1(x) {\n return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : Math.exp(x) - 1;\n} : $expm1;\n", + "// 20.2.2.16 Math.fround(x)\nvar sign = require('./_math-sign');\nvar pow = Math.pow;\nvar EPSILON = pow(2, -52);\nvar EPSILON32 = pow(2, -23);\nvar MAX32 = pow(2, 127) * (2 - EPSILON32);\nvar MIN32 = pow(2, -126);\n\nvar roundTiesToEven = function (n) {\n return n + 1 / EPSILON - 1 / EPSILON;\n};\n\nmodule.exports = Math.fround || function fround(x) {\n var $abs = Math.abs(x);\n var $sign = sign(x);\n var a, result;\n if ($abs < MIN32) return $sign * roundTiesToEven($abs / MIN32 / EPSILON32) * MIN32 * EPSILON32;\n a = (1 + EPSILON32 / EPSILON) * $abs;\n result = a - (a - $abs);\n // eslint-disable-next-line no-self-compare\n if (result > MAX32 || result != result) return $sign * Infinity;\n return $sign * result;\n};\n", + "// 20.2.2.20 Math.log1p(x)\nmodule.exports = Math.log1p || function log1p(x) {\n return (x = +x) > -1e-8 && x < 1e-8 ? x - x * x / 2 : Math.log(1 + x);\n};\n", + "// 20.2.2.28 Math.sign(x)\nmodule.exports = Math.sign || function sign(x) {\n // eslint-disable-next-line no-self-compare\n return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;\n};\n", + "// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])\nvar anObject = require('./_an-object');\nvar dPs = require('./_object-dps');\nvar enumBugKeys = require('./_enum-bug-keys');\nvar IE_PROTO = require('./_shared-key')('IE_PROTO');\nvar Empty = function () { /* empty */ };\nvar PROTOTYPE = 'prototype';\n\n// Create object with fake ` + "`"))) + ((`null` + ("`" + ` prototype: use iframe Object with cleared prototype\nvar createDict = function () {\n // Thrash, waste and sodomy: IE GC bug\n var iframe = require('./_dom-create')('iframe');\n var i = enumBugKeys.length;\n var lt = '<';\n var gt = '>';\n var iframeDocument;\n iframe.style.display = 'none';\n require('./_html').appendChild(iframe);\n iframe.src = 'javascript:'; // eslint-disable-line no-script-url\n // createDict = iframe.contentWindow.Object;\n // html.removeChild(iframe);\n iframeDocument = iframe.contentWindow.document;\n iframeDocument.open();\n iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);\n iframeDocument.close();\n createDict = iframeDocument.F;\n while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]];\n return createDict();\n};\n\nmodule.exports = Object.create || function create(O, Properties) {\n var result;\n if (O !== null) {\n Empty[PROTOTYPE] = anObject(O);\n result = new Empty();\n Empty[PROTOTYPE] = null;\n // add \"__proto__\" for Object.getPrototypeOf polyfill\n result[IE_PROTO] = O;\n } else result = createDict();\n return Properties === undefined ? result : dPs(result, Properties);\n};\n", + "var anObject = require('./_an-object');\nvar IE8_DOM_DEFINE = require('./_ie8-dom-define');\nvar toPrimitive = require('./_to-primitive');\nvar dP = Object.defineProperty;\n\nexports.f = require('./_descriptors') ? Object.defineProperty : function defineProperty(O, P, Attributes) {\n anObject(O);\n P = toPrimitive(P, true);\n anObject(Attributes);\n if (IE8_DOM_DEFINE) try {\n return dP(O, P, Attributes);\n } catch (e) { /* empty */ }\n if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');\n if ('value' in Attributes) O[P] = Attributes.value;\n return O;\n};\n", + "var dP = require('./_object-dp');\nvar anObject = require('./_an-object');\nvar getKeys = require('./_object-keys');\n\nmodule.exports = require('./_descriptors') ? Object.defineProperties : function defineProperties(O, Properties) {\n anObject(O);\n var keys = getKeys(Properties);\n var length = keys.length;\n var i = 0;\n var P;\n while (length > i) dP.f(O, P = keys[i++], Properties[P]);\n return O;\n};\n", + "var pIE = require('./_object-pie');\nvar createDesc = require('./_property-desc');\nvar toIObject = require('./_to-iobject');\nvar toPrimitive = require('./_to-primitive');\nvar has = require('./_has');\nvar IE8_DOM_DEFINE = require('./_ie8-dom-define');\nvar gOPD = Object.getOwnPropertyDescriptor;\n\nexports.f = require('./_descriptors') ? gOPD : function getOwnPropertyDescriptor(O, P) {\n O = toIObject(O);\n P = toPrimitive(P, true);\n if (IE8_DOM_DEFINE) try {\n return gOPD(O, P);\n } catch (e) { /* empty */ }\n if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]);\n};\n", + "// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)\nvar $keys = require('./_object-keys-internal');\nvar hiddenKeys = require('./_enum-bug-keys').concat('length', 'prototype');\n\nexports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {\n return $keys(O, hiddenKeys);\n};\n", + "var has = require('./_has');\nvar toIObject = require('./_to-iobject');\nvar arrayIndexOf = require('./_array-includes')(false);\nvar IE_PROTO = require('./_shared-key')('IE_PROTO');\n\nmodule.exports = function (object, names) {\n var O = toIObject(object);\n var i = 0;\n var result = [];\n var key;\n for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key);\n // Don't enum bug & hidden keys\n while (names.length > i) if (has(O, key = names[i++])) {\n ~arrayIndexOf(result, key) || result.push(key);\n }\n return result;\n};\n", + "// 19.1.2.14 / 15.2.3.14 Object.keys(O)\nvar $keys = require('./_object-keys-internal');\nvar enumBugKeys = require('./_enum-bug-keys');\n\nmodule.exports = Object.keys || function keys(O) {\n return $keys(O, enumBugKeys);\n};\n", + "exports.f = {}.propertyIsEnumerable;\n", + "var $parseFloat = require('./_global').parseFloat;\nvar $trim = require('./_string-trim').trim;\n\nmodule.exports = 1 / $parseFloat(require('./_string-ws') + '-0') !== -Infinity ? function parseFloat(str) {\n var string = $trim(String(str), 3);\n var result = $parseFloat(string);\n return result === 0 && string.charAt(0) == '-' ? -0 : result;\n} : $parseFloat;\n", + "var $parseInt = require('./_global').parseInt;\nvar $trim = require('./_string-trim').trim;\nvar ws = require('./_string-ws');\nvar hex = /^[-+]?0[xX]/;\n\nmodule.exports = $parseInt(ws + '08') !== 8 || $parseInt(ws + '0x16') !== 22 ? function parseInt(str, radix) {\n var string = $trim(String(str), 3);\n return $parseInt(string, (radix >>> 0) || (hex.test(string) ? 16 : 10));\n} : $parseInt;\n", + "module.exports = function (bitmap, value) {\n return {\n enumerable: !(bitmap & 1),\n configurable: !(bitmap & 2),\n writable: !(bitmap & 4),\n value: value\n };\n};\n", + "var global = require('./_global');\nvar hide = require('./_hide');\nvar has = require('./_has');\nvar SRC = require('./_uid')('src');\nvar TO_STRING = 'toString';\nvar $toString = Function[TO_STRING];\nvar TPL = ('' + $toString).split(TO_STRING);\n\nrequire('./_core').inspectSource = function (it) {\n return $toString.call(it);\n};\n\n(module.exports = function (O, key, val, safe) {\n var isFunction = typeof val == 'function';\n if (isFunction) has(val, 'name') || hide(val, 'name', key);\n if (O[key] === val) return;\n if (isFunction) has(val, SRC) || hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key)));\n if (O === global) {\n O[key] = val;\n } else if (!safe) {\n delete O[key];\n hide(O, key, val);\n } else if (O[key]) {\n O[key] = val;\n } else {\n hide(O, key, val);\n }\n// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative\n})(Function.prototype, TO_STRING, function toString() {\n return typeof this == 'function' && this[SRC] || $toString.call(this);\n});\n", + "// Works with __proto__ only. Old v8 can't work with null proto objects.\n/* eslint-disable no-proto */\nvar isObject = require('./_is-object');\nvar anObject = require('./_an-object');\nvar check = function (O, proto) {\n anObject(O);\n if (!isObject(proto) && proto !== null) throw TypeError(proto + \": can't set as prototype!\");\n};\nmodule.exports = {\n set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line\n function (test, buggy, set) {\n try {\n set = require('./_ctx')(Function.call, require('./_object-gopd').f(Object.prototype, '__proto__').set, 2);\n set(test, []);\n buggy = !(test instanceof Array);\n } catch (e) { buggy = true; }\n return function setPrototypeOf(O, proto) {\n check(O, proto);\n if (buggy) O.__proto__ = proto;\n else set(O, proto);\n return O;\n };\n }({}, false) : undefined),\n check: check\n};\n", + "var shared = require('./_shared')('keys');\nvar uid = require('./_uid');\nmodule.exports = function (key) {\n return shared[key] || (shared[key] = uid(key));\n};\n", + "var core = require('./_core');\nvar global = require('./_global');\nvar SHARED = '__core-js_shared__';\nvar store = global[SHARED] || (global[SHARED] = {});\n\n(module.exports = function (key, value) {\n return store[key] || (store[key] = value !== undefined ? value : {});\n})('versions', []).push({\n version: core.version,\n mode: require('./_library') ? 'pure' : 'global',\n copyright: '© 2018 Denis Pushkarev (zloirock.ru)'\n});\n", + "'use strict';\nvar toInteger = require('./_to-integer');\nvar defined = require('./_defined');\n\nmodule.exports = function repeat(count) {\n var str = String(defined(this));\n var res = '';\n var n = toInteger(count);\n if (n < 0 || n == Infinity) throw RangeError(\"Count can't be negative\");\n for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) res += str;\n return res;\n};\n", + "var $export = require('./_export');\nvar defined = require('./_defined');\nvar fails = require('./_fails');\nvar spaces = require('./_string-ws');\nvar space = '[' + spaces + ']';\nvar non = '\\u200b\\u0085';\nvar ltrim = RegExp('^' + space + space + '*');\nvar rtrim = RegExp(space + space + '*$');\n\nvar exporter = function (KEY, exec, ALIAS) {\n var exp = {};\n var FORCE = fails(function () {\n return !!spaces[KEY]() || non[KEY]() != non;\n });\n var fn = exp[KEY] = FORCE ? exec(trim) : spaces[KEY];\n if (ALIAS) exp[ALIAS] = fn;\n $export($export.P + $export.F * FORCE, 'String', exp);\n};\n\n// 1 -> String#trimLeft\n// 2 -> String#trimRight\n// 3 -> String#trim\nvar trim = exporter.trim = function (string, TYPE) {\n string = String(defined(string));\n if (TYPE & 1) string = string.replace(ltrim, '');\n if (TYPE & 2) string = string.replace(rtrim, '');\n return string;\n};\n\nmodule.exports = exporter;\n", + "module.exports = '\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003' +\n '\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF';\n", + "var toInteger = require('./_to-integer');\nvar max = Math.max;\nvar min = Math.min;\nmodule.exports = function (index, length) {\n index = toInteger(index);\n return index < 0 ? max(index + length, 0) : min(index, length);\n};\n", + "// 7.1.4 ToInteger\nvar ceil = Math.ceil;\nvar floor = Math.floor;\nmodule.exports = function (it) {\n return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);\n};\n", + "// to indexed object, toObject with fallback for non-array-like ES3 strings\nvar IObject = require('./_iobject');\nvar defined = require('./_defined');\nmodule.exports = function (it) {\n return IObject(defined(it));\n};\n", + "// 7.1.15 ToLength\nvar toInteger = require('./_to-integer');\nvar min = Math.min;\nmodule.exports = function (it) {\n return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991\n};\n", + "// 7.1.1 ToPrimitive(input [, PreferredType])\nvar isObject = require('./_is-object');\n// instead of the ES6 spec version, we didn't implement @@toPrimitive case\n// and the second argument - flag - preferred type is a string\nmodule.exports = function (it, S) {\n if (!isObject(it)) return it;\n var fn, val;\n if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val;\n if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n throw TypeError(\"Can't convert object to primitive value\");\n};\n", + "var id = 0;\nvar px = Math.random();\nmodule.exports = function (key) {\n return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));\n};\n", + "// 20.2.2.3 Math.acosh(x)\nvar $export = require('./_export');\nvar log1p = require('./_math-log1p');\nvar sqrt = Math.sqrt;\nvar $acosh = Math.acosh;\n\n$export($export.S + $export.F * !($acosh\n // V8 bug: https://code.google.com/p/v8/issues/detail?id=3509\n && Math.floor($acosh(Number.MAX_VALUE)) == 710\n // Tor Browser bug: Math.acosh(Infinity) -> NaN\n && $acosh(Infinity) == Infinity\n), 'Math', {\n acosh: function acosh(x) {\n return (x = +x) < 1 ? NaN : x > 94906265.62425156\n ? Math.log(x) + Math.LN2\n : log1p(x - 1 + sqrt(x - 1) * sqrt(x + 1));\n }\n});\n", + "// 20.2.2.5 Math.asinh(x)\nvar $export = require('./_export');\nvar $asinh = Math.asinh;\n\nfunction asinh(x) {\n return !isFinite(x = +x) || x == 0 ? x : x < 0 ? -asinh(-x) : Math.log(x + Math.sqrt(x * x + 1));\n}\n\n// Tor Browser bug: Math.asinh(0) -> -0\n$export($export.S + $export.F * !($asinh && 1 / $asinh(0) > 0), 'Math', { asinh: asinh });\n", + "// 20.2.2.7 Math.atanh(x)\nvar $export = require('./_export');\nvar $atanh = Math.atanh;\n\n// Tor Browser bug: Math.atanh(-0) -> 0\n$export($export.S + $export.F * !($atanh && 1 / $atanh(-0) < 0), 'Math', {\n atanh: function atanh(x) {\n return (x = +x) == 0 ? x : Math.log((1 + x) / (1 - x)) / 2;\n }\n});\n", + "// 20.2.2.9 Math.cbrt(x)\nvar $export = require('./_export');\nvar sign = require('./_math-sign');\n\n$export($export.S, 'Math', {\n cbrt: function cbrt(x) {\n return sign(x = +x) * Math.pow(Math.abs(x), 1 / 3);\n }\n});\n", + "// 20.2.2.11 Math.clz32(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', {\n clz32: function clz32(x) {\n return (x >>>= 0) ? 31 - Math.floor(Math.log(x + 0.5) * Math.LOG2E) : 32;\n }\n});\n", + "// 20.2.2.12 Math.cosh(x)\nvar $export = require('./_export');\nvar exp = Math.exp;\n\n$export($export.S, 'Math', {\n cosh: function cosh(x) {\n return (exp(x = +x) + exp(-x)) / 2;\n }\n});\n", + "// 20.2.2.14 Math.expm1(x)\nvar $export = require('./_export');\nvar $expm1 = require('./_math-expm1');\n\n$export($export.S + $export.F * ($expm1 != Math.expm1), 'Math', { expm1: $expm1 });\n", + "// 20.2.2.16 Math.fround(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', { fround: require('./_math-fround') });\n", + "// 20.2.2.17 Math.hypot([value1[, value2[, … ]]])\nvar $export = require('./_export');\nvar abs = Math.abs;\n\n$export($export.S, 'Math', {\n hypot: function hypot(value1, value2) { // eslint-disable-line no-unused-vars\n var sum = 0;\n var i = 0;\n var aLen = arguments.length;\n var larg = 0;\n var arg, div;\n while (i < aLen) {\n arg = abs(arguments[i++]);\n if (larg < arg) {\n div = larg / arg;\n sum = sum * div * div + 1;\n larg = arg;\n } else if (arg > 0) {\n div = arg / larg;\n sum += div * div;\n } else sum += arg;\n }\n return larg === Infinity ? Infinity : larg * Math.sqrt(sum);\n }\n});\n", + "// 20.2.2.18 Math.imul(x, y)\nvar $export = require('./_export');\nvar $imul = Math.imul;\n\n// some WebKit versions fails with big numbers, some has wrong arity\n$export($export.S + $export.F * require('./_fails')(function () {\n return $imul(0xffffffff, 5) != -5 || $imul.length != 2;\n}), 'Math', {\n imul: function imul(x, y) {\n var UINT16 = 0xffff;\n var xn = +x;\n var yn = +y;\n var xl = UINT16 & xn;\n var yl = UINT16 & yn;\n return 0 | xl * yl + ((UINT16 & xn >>> 16) * yl + xl * (UINT16 & yn >>> 16) << 16 >>> 0);\n }\n});\n", + "// 20.2.2.21 Math.log10(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', {\n log10: function log10(x) {\n return Math.log(x) * Math.LOG10E;\n }\n});\n", + "// 20.2.2.20 Math.log1p(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', { log1p: require('./_math-log1p') });\n", + "// 20.2.2.22 Math.log2(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', {\n log2: function log2(x) {\n return Math.log(x) / Math.LN2;\n }\n});\n", + "// 20.2.2.28 Math.sign(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', { sign: require('./_math-sign') });\n", + "// 20.2.2.30 Math.sinh(x)\nvar $export = require('./_export');\nvar expm1 = require('./_math-expm1');\nvar exp = Math.exp;\n\n// V8 near Chromium 38 has a problem with very small numbers\n$export($export.S + $export.F * require('./_fails')(function () {\n return !Math.sinh(-2e-17) != -2e-17;\n}), 'Math', {\n sinh: function sinh(x) {\n return Math.abs(x = +x) < 1\n ? (expm1(x) - expm1(-x)) / 2\n : (exp(x - 1) - exp(-x - 1)) * (Math.E / 2);\n }\n});\n", + "// 20.2.2.33 Math.tanh(x)\nvar $export = require('./_export');\nvar expm1 = require('./_math-expm1');\nvar exp = Math.exp;\n\n$export($export.S, 'Math', {\n tanh: function tanh(x) {\n var a = expm1(x = +x);\n var b = expm1(-x);\n return a == Infinity ? 1 : b == Infinity ? -1 : (a - b) / (exp(x) + exp(-x));\n }\n});\n", + "// 20.2.2.34 Math.trunc(x)\nvar $export = require('./_export');\n\n$export($export.S, 'Math', {\n trunc: function trunc(it) {\n return (it > 0 ? Math.floor : Math.ceil)(it);\n }\n});\n", + "'use strict';\nvar global = require('./_global');\nvar has = require('./_has');\nvar cof = require('./_cof');\nvar inheritIfRequired = require('./_inherit-if-required');\nvar toPrimitive = require('./_to-primitive');\nvar fails = require('./_fails');\nvar gOPN = require('./_object-gopn').f;\nvar gOPD = require('./_object-gopd').f;\nvar dP = require('./_object-dp').f;\nvar $trim = require('./_string-trim').trim;\nvar NUMBER = 'Number';\nvar $Number = global[NUMBER];\nvar Base = $Number;\nvar proto = $Number.prototype;\n// Opera ~12 has broken Object#toString\nvar BROKEN_COF = cof(require('./_object-create')(proto)) == NUMBER;\nvar TRIM = 'trim' in String.prototype;\n\n// 7.1.3 ToNumber(argument)\nvar toNumber = function (argument) {\n var it = toPrimitive(argument, false);\n if (typeof it == 'string' && it.length > 2) {\n it = TRIM ? it.trim() : $trim(it, 3);\n var first = it.charCodeAt(0);\n var third, radix, maxCode;\n if (first === 43 || first === 45) {\n third = it.charCodeAt(2);\n if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix\n } else if (first === 48) {\n switch (it.charCodeAt(1)) {\n case 66: case 98: radix = 2; maxCode = 49; break; // fast equal /^0b[01]+$/i\n case 79: case 111: radix = 8; maxCode = 55; break; // fast equal /^0o[0-7]+$/i\n default: return +it;\n }\n for (var digits = it.slice(2), i = 0, l = digits.length, code; i < l; i++) {\n code = digits.charCodeAt(i);\n // parseInt parses a string to a first unavailable symbol\n // but ToNumber should return NaN if a string contains unavailable symbols\n if (code < 48 || code > maxCode) return NaN;\n } return parseInt(digits, radix);\n }\n } return +it;\n};\n\nif (!$Number(' 0o1') || !$Number('0b1') || $Number('+0x1')) {\n $Number = function Number(value) {\n var it = arguments.length < 1 ? 0 : value;\n var that = this;\n return that instanceof $Number\n // check on 1..constructor(foo) case\n && (BROKEN_COF ? fails(function () { proto.valueOf.call(that); }) : cof(that) != NUMBER)\n ? inheritIfRequired(new Base(toNumber(it)), that, $Number) : toNumber(it);\n };\n for (var keys = require('./_descriptors') ? gOPN(Base) : (\n // ES3:\n 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +\n // ES6 (in case, if modules with ES6 Number statics required before):\n 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +\n 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger'\n ).split(','), j = 0, key; keys.length > j; j++) {\n if (has(Base, key = keys[j]) && !has($Number, key)) {\n dP($Number, key, gOPD(Base, key));\n }\n }\n $Number.prototype = proto;\n proto.constructor = $Number;\n require('./_redefine')(global, NUMBER, $Number);\n}\n", + "// 20.1.2.1 Number.EPSILON\nvar $export = require('./_export');\n\n$export($export.S, 'Number', { EPSILON: Math.pow(2, -52) });\n", + "// 20.1.2.2 Number.isFinite(number)\nvar $export = require('./_export');\nvar _isFinite = require('./_global').isFinite;\n\n$export($export.S, 'Number', {\n isFinite: function isFinite(it) {\n return typeof it == 'number' && _isFinite(it);\n }\n});\n", + "// 20.1.2.3 Number.isInteger(number)\nvar $export = require('./_export');\n\n$export($export.S, 'Number', { isInteger: require('./_is-integer') });\n", + "// 20.1.2.4 Number.isNaN(number)\nvar $export = require('./_export');\n\n$export($export.S, 'Number', {\n isNaN: function isNaN(number) {\n // eslint-disable-next-line no-self-compare\n return number != number;\n }\n});\n", + "// 20.1.2.5 Number.isSafeInteger(number)\nvar $export = require('./_export');\nvar isInteger = require('./_is-integer');\nvar abs = Math.abs;\n\n$export($export.S, 'Number', {\n isSafeInteger: function isSafeInteger(number) {\n return isInteger(number) && abs(number) <= 0x1fffffffffffff;\n }\n});\n", + "// 20.1.2.6 Number.MAX_SAFE_INTEGER\nvar $export = require('./_export');\n\n$export($export.S, 'Number', { MAX_SAFE_INTEGER: 0x1fffffffffffff });\n", + "// 20.1.2.10 Number.MIN_SAFE_INTEGER\nvar $export = require('./_export');\n\n$export($export.S, 'Number', { MIN_SAFE_INTEGER: -0x1fffffffffffff });\n", + "var $export = require('./_export');\nvar $parseFloat = require('./_parse-float');\n// 20.1.2.12 Number.parseFloat(string)\n$export($export.S + $export.F * (Number.parseFloat != $parseFloat), 'Number', { parseFloat: $parseFloat });\n", + "var $export = require('./_export');\nvar $parseInt = require('./_parse-int');\n// 20.1.2.13 Number.parseInt(string, radix)\n$export($export.S + $export.F * (Number.parseInt != $parseInt), 'Number', { parseInt: $parseInt });\n", + "'use strict';\nvar $export = require('./_export');\nvar toInteger = require('./_to-integer');\nvar aNumberValue = require('./_a-number-value');\nvar repeat = require('./_string-repeat');\nvar $toFixed = 1.0.toFixed;\nvar floor = Math.floor;\nvar data = [0, 0, 0, 0, 0, 0];\nvar ERROR = 'Number.toFixed: incorrect invocation!';\nvar ZERO = '0';\n\nvar multiply = function (n, c) {\n var i = -1;\n var c2 = c;\n while (++i < 6) {\n c2 += n * data[i];\n data[i] = c2 % 1e7;\n c2 = floor(c2 / 1e7);\n }\n};\nvar divide = function (n) {\n var i = 6;\n var c = 0;\n while (--i >= 0) {\n c += data[i];\n data[i] = floor(c / n);\n c = (c % n) * 1e7;\n }\n};\nvar numToString = function () {\n var i = 6;\n var s = '';\n while (--i >= 0) {\n if (s !== '' || i === 0 || data[i] !== 0) {\n var t = String(data[i]);\n s = s === '' ? t : s + repeat.call(ZERO, 7 - t.length) + t;\n }\n } return s;\n};\nvar pow = function (x, n, acc) {\n return n === 0 ? acc : n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc);\n};\nvar log = function (x) {\n var n = 0;\n var x2 = x;\n while (x2 >= 4096) {\n n += 12;\n x2 /= 4096;\n }\n while (x2 >= 2) {\n n += 1;\n x2 /= 2;\n } return n;\n};\n\n$export($export.P + $export.F * (!!$toFixed && (\n 0.00008.toFixed(3) !== '0.000' ||\n 0.9.toFixed(0) !== '1' ||\n 1.255.toFixed(2) !== '1.25' ||\n 1000000000000000128.0.toFixed(0) !== '1000000000000000128'\n) || !require('./_fails')(function () {\n // V8 ~ Android 4.3-\n $toFixed.call({});\n})), 'Number', {\n toFixed: function toFixed(fractionDigits) {\n var x = aNumberValue(this, ERROR);\n var f = toInteger(fractionDigits);\n var s = '';\n var m = ZERO;\n var e, z, j, k;\n if (f < 0 || f > 20) throw RangeError(ERROR);\n // eslint-disable-next-line no-self-compare\n if (x != x) return 'NaN';\n if (x <= -1e21 || x >= 1e21) return String(x);\n if (x < 0) {\n s = '-';\n x = -x;\n }\n if (x > 1e-21) {\n e = log(x * pow(2, 69, 1)) - 69;\n z = e < 0 ? x * pow(2, -e, 1) : x / pow(2, e, 1);\n z *= 0x10000000000000;\n e = 52 - e;\n if (e > 0) {\n multiply(0, z);\n j = f;\n while (j >= 7) {\n multiply(1e7, 0);\n j -= 7;\n }\n multiply(pow(10, j, 1), 0);\n j = e - 1;\n while (j >= 23) {\n divide(1 << 23);\n j -= 23;\n }\n divide(1 << j);\n multiply(1, 1);\n divide(2);\n m = numToString();\n } else {\n multiply(0, z);\n multiply(1 << -e, 0);\n m = numToString() + repeat.call(ZERO, f);\n }\n }\n if (f > 0) {\n k = m.length;\n m = s + (k <= f ? '0.' + repeat.call(ZERO, f - k) + m : m.slice(0, k - f) + '.' + m.slice(k - f));\n } else {\n m = s + m;\n } return m;\n }\n});\n", + "'use strict';\nvar $export = require('./_export');\nvar $fails = require('./_fails');\nvar aNumberValue = require('./_a-number-value');\nvar $toPrecision = 1.0.toPrecision;\n\n$export($export.P + $export.F * ($fails(function () {\n // IE7-\n return $toPrecision.call(1, undefined) !== '1';\n}) || !$fails(function () {\n // V8 ~ Android 4.3-\n $toPrecision.call({});\n})), 'Number', {\n toPrecision: function toPrecision(precision) {\n var that = aNumberValue(this, 'Number#toPrecision: incorrect invocation!');\n return precision === undefined ? $toPrecision.call(that) : $toPrecision.call(that, precision);\n }\n});\n", + "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');\n\nfunction emptyFunction() {}\n\nmodule.exports = function() {\n function shim(props, propName, componentName, location, propFullName, secret) {\n if (secret === ReactPropTypesSecret) {\n // It is still safe when called from React.\n return;\n }\n var err = new Error(\n 'Calling PropTypes validators directly is not supported by the `)) + ("`" + (`prop-types` + "`")))))) + (((((` package. ' +\n 'Use PropTypes.checkPropTypes() to call them. ' +\n 'Read more at http://fb.me/use-check-prop-types'\n );\n err.name = 'Invariant Violation';\n throw err;\n };\n shim.isRequired = shim;\n function getShim() {\n return shim;\n };\n // Important!\n // Keep this list in sync with production version in ` + "`") + (`./factoryWithTypeCheckers.js` + ("`" + `.\n var ReactPropTypes = {\n array: shim,\n bool: shim,\n func: shim,\n number: shim,\n object: shim,\n string: shim,\n symbol: shim,\n\n any: shim,\n arrayOf: getShim,\n element: shim,\n instanceOf: getShim,\n node: shim,\n objectOf: getShim,\n oneOf: getShim,\n oneOfType: getShim,\n shape: getShim,\n exact: getShim\n };\n\n ReactPropTypes.checkPropTypes = emptyFunction;\n ReactPropTypes.PropTypes = ReactPropTypes;\n\n return ReactPropTypes;\n};\n", + "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nif (process.env.NODE_ENV !== 'production') {\n var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&\n Symbol.for &&\n Symbol.for('react.element')) ||\n 0xeac7;\n\n var isValidElement = function(object) {\n return typeof object === 'object' &&\n object !== null &&\n object.$$typeof === REACT_ELEMENT_TYPE;\n };\n\n // By explicitly using `))) + (("`" + (`prop-types` + "`")) + (` you are opting into new development behavior.\n // http://fb.me/prop-types-in-prod\n var throwOnDirectAccess = true;\n module.exports = require('./factoryWithTypeCheckers')(isValidElement, throwOnDirectAccess);\n} else {\n // By explicitly using ` + ("`" + `prop-types`)))) + ((("`" + ` you are opting into new production behavior.\n // http://fb.me/prop-types-in-prod\n module.exports = require('./factoryWithThrowingShims')();\n}\n", + "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';\n\nmodule.exports = ReactPropTypesSecret;\n", + "/**\n * Module dependencies\n */\nvar balanced = require(\"balanced-match\")\nvar reduceFunctionCall = require(\"reduce-function-call\")\nvar mexp = require(\"math-expression-evaluator\")\n\n/**\n * Constantes\n */\nvar MAX_STACK = 100 // should be enough for a single calc()...\nvar NESTED_CALC_RE = /(\\+|\\-|\\*|\\\\|[^a-z]|)(\\s*)(\\()/g\n\n/**\n * Global variables\n */\nvar stack\n\n/**\n * Expose reduceCSSCalc plugin\n *\n * @type {Function}\n */\nmodule.exports = reduceCSSCalc\n\n/**\n * Reduce CSS calc() in a string, whenever it's possible\n *\n * @param {String} value css input\n */\nfunction reduceCSSCalc(value, decimalPrecision) {\n stack = 0\n decimalPrecision = Math.pow(10, decimalPrecision === undefined ? 5 : decimalPrecision)\n\n // Allow calc() on multiple lines\n value = value.replace(/\\n+/g, \" \")\n\n /**\n * Evaluates an expression\n *\n * @param {String} expression\n * @returns {String}\n */\n function evaluateExpression (expression, functionIdentifier, call) {\n if (stack++ > MAX_STACK) {\n stack = 0\n throw new Error(\"Call stack overflow for \" + call)\n }\n\n if (expression === \"\") {\n throw new Error(functionIdentifier + \"(): '\" + call + \"' must contain a non-whitespace string\")\n }\n\n expression = evaluateNestedExpression(expression, call)\n\n var units = getUnitsInExpression(expression)\n\n // If the expression contains multiple units or CSS variables,\n // then let the expression be (i.e. browser calc())\n if (units.length > 1 || expression.indexOf(\"var(\") > -1) {\n return functionIdentifier + \"(\" + expression + \")\"\n }\n\n var unit = units[0] || \"\"\n\n if (unit === \"%\") {\n // Convert percentages to numbers, to handle expressions like: 50% * 50% (will become: 25%):\n // console.log(expression)\n expression = expression.replace(/\\b[0-9\\.]+%/g, function(percent) {\n return parseFloat(percent.slice(0, -1)) * 0.01\n })\n }\n\n // Remove units in expression:\n var toEvaluate = expression.replace(new RegExp(unit, \"gi\"), \"\")\n var result\n\n try {\n result = mexp.eval(toEvaluate)\n }\n catch (e) {\n return functionIdentifier + \"(\" + expression + \")\"\n }\n\n // Transform back to a percentage result:\n if (unit === \"%\") {\n result *= 100\n }\n\n // adjust rounding shit\n // (0.1 * 0.2 === 0.020000000000000004)\n if (functionIdentifier.length || unit === \"%\") {\n result = Math.round(result * decimalPrecision) / decimalPrecision\n }\n\n // Add unit\n result += unit\n\n return result\n }\n\n /**\n * Evaluates nested expressions\n *\n * @param {String} expression\n * @returns {String}\n */\n function evaluateNestedExpression(expression, call) {\n // Remove the calc part from nested expressions to ensure\n // better browser compatibility\n expression = expression.replace(/((?:\\-[a-z]+\\-)?calc)/g, \"\")\n var evaluatedPart = \"\"\n var nonEvaluatedPart = expression\n var matches\n while ((matches = NESTED_CALC_RE.exec(nonEvaluatedPart))) {\n if (matches[0].index > 0) {\n evaluatedPart += nonEvaluatedPart.substring(0, matches[0].index)\n }\n\n var balancedExpr = balanced(\"(\", \")\", nonEvaluatedPart.substring([0].index))\n if (balancedExpr.body === \"\") {\n throw new Error(\"'\" + expression + \"' must contain a non-whitespace string\")\n }\n\n var evaluated = evaluateExpression(balancedExpr.body, \"\", call)\n\n evaluatedPart += balancedExpr.pre + evaluated\n nonEvaluatedPart = balancedExpr.post\n }\n\n return evaluatedPart + nonEvaluatedPart\n }\n\n return reduceFunctionCall(value, /((?:\\-[a-z]+\\-)?calc)\\(/, evaluateExpression)\n}\n\n/**\n * Checks what units are used in an expression\n *\n * @param {String} expression\n * @returns {Array}\n */\n\nfunction getUnitsInExpression(expression) {\n var uniqueUnits = []\n var uniqueLowerCaseUnits = []\n var unitRegEx = /[\\.0-9]([%a-z]+)/gi\n var matches = unitRegEx.exec(expression)\n\n while (matches) {\n if (!matches || !matches[1]) {\n continue\n }\n\n if (uniqueLowerCaseUnits.indexOf(matches[1].toLowerCase()) === -1) {\n uniqueUnits.push(matches[1])\n uniqueLowerCaseUnits.push(matches[1].toLowerCase())\n }\n\n matches = unitRegEx.exec(expression)\n }\n\n return uniqueUnits\n}\n", + "/*\n * Module dependencies\n */\nvar balanced = require(\"balanced-match\")\n\n/**\n * Expose `) + ("`" + (`reduceFunctionCall` + "`"))) + ((`\n *\n * @type {Function}\n */\nmodule.exports = reduceFunctionCall\n\n/**\n * Walkthrough all expressions, evaluate them and insert them into the declaration\n *\n * @param {Array} expressions\n * @param {Object} declaration\n */\n\nfunction reduceFunctionCall(string, functionRE, callback) {\n var call = string\n return getFunctionCalls(string, functionRE).reduce(function(string, obj) {\n return string.replace(obj.functionIdentifier + \"(\" + obj.matches.body + \")\", evalFunctionCall(obj.matches.body, obj.functionIdentifier, callback, call, functionRE))\n }, string)\n}\n\n/**\n * Parses expressions in a value\n *\n * @param {String} value\n * @returns {Array}\n * @api private\n */\n\nfunction getFunctionCalls(call, functionRE) {\n var expressions = []\n\n var fnRE = typeof functionRE === \"string\" ? new RegExp(\"\\\\b(\" + functionRE + \")\\\\(\") : functionRE\n do {\n var searchMatch = fnRE.exec(call)\n if (!searchMatch) {\n return expressions\n }\n if (searchMatch[1] === undefined) {\n throw new Error(\"Missing the first couple of parenthesis to get the function identifier in \" + functionRE)\n }\n var fn = searchMatch[1]\n var startIndex = searchMatch.index\n var matches = balanced(\"(\", \")\", call.substring(startIndex))\n\n if (!matches || matches.start !== searchMatch[0].length - 1) {\n throw new SyntaxError(fn + \"(): missing closing ')' in the value '\" + call + \"'\")\n }\n\n expressions.push({matches: matches, functionIdentifier: fn})\n call = matches.post\n }\n while (fnRE.test(call))\n\n return expressions\n}\n\n/**\n * Evaluates an expression\n *\n * @param {String} expression\n * @returns {String}\n * @api private\n */\n\nfunction evalFunctionCall (string, functionIdentifier, callback, call, functionRE) {\n // allow recursivity\n return callback(reduceFunctionCall(string, functionRE, callback), functionIdentifier, call)\n}\n", + "/**\r\n * A collection of shims that provide minimal functionality of the ES6 collections.\r\n *\r\n * These implementations are not meant to be used outside of the ResizeObserver\r\n * modules as they cover only a limited range of use cases.\r\n */\r\n/* eslint-disable require-jsdoc, valid-jsdoc */\r\nvar MapShim = (function () {\r\n if (typeof Map !== 'undefined') {\r\n return Map;\r\n }\r\n /**\r\n * Returns index in provided array that matches the specified key.\r\n *\r\n * @param {Array} arr\r\n * @param {*} key\r\n * @returns {number}\r\n */\r\n function getIndex(arr, key) {\r\n var result = -1;\r\n arr.some(function (entry, index) {\r\n if (entry[0] === key) {\r\n result = index;\r\n return true;\r\n }\r\n return false;\r\n });\r\n return result;\r\n }\r\n return /** @class */ (function () {\r\n function class_1() {\r\n this.__entries__ = [];\r\n }\r\n Object.defineProperty(class_1.prototype, \"size\", {\r\n /**\r\n * @returns {boolean}\r\n */\r\n get: function () {\r\n return this.__entries__.length;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n /**\r\n * @param {*} key\r\n * @returns {*}\r\n */\r\n class_1.prototype.get = function (key) {\r\n var index = getIndex(this.__entries__, key);\r\n var entry = this.__entries__[index];\r\n return entry && entry[1];\r\n };\r\n /**\r\n * @param {*} key\r\n * @param {*} value\r\n * @returns {void}\r\n */\r\n class_1.prototype.set = function (key, value) {\r\n var index = getIndex(this.__entries__, key);\r\n if (~index) {\r\n this.__entries__[index][1] = value;\r\n }\r\n else {\r\n this.__entries__.push([key, value]);\r\n }\r\n };\r\n /**\r\n * @param {*} key\r\n * @returns {void}\r\n */\r\n class_1.prototype.delete = function (key) {\r\n var entries = this.__entries__;\r\n var index = getIndex(entries, key);\r\n if (~index) {\r\n entries.splice(index, 1);\r\n }\r\n };\r\n /**\r\n * @param {*} key\r\n * @returns {void}\r\n */\r\n class_1.prototype.has = function (key) {\r\n return !!~getIndex(this.__entries__, key);\r\n };\r\n /**\r\n * @returns {void}\r\n */\r\n class_1.prototype.clear = function () {\r\n this.__entries__.splice(0);\r\n };\r\n /**\r\n * @param {Function} callback\r\n * @param {*} [ctx=null]\r\n * @returns {void}\r\n */\r\n class_1.prototype.forEach = function (callback, ctx) {\r\n if (ctx === void 0) { ctx = null; }\r\n for (var _i = 0, _a = this.__entries__; _i < _a.length; _i++) {\r\n var entry = _a[_i];\r\n callback.call(ctx, entry[1], entry[0]);\r\n }\r\n };\r\n return class_1;\r\n }());\r\n})();\n\n/**\r\n * Detects whether window and document objects are available in current environment.\r\n */\r\nvar isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && window.document === document;\n\n// Returns global object of a current environment.\r\nvar global$1 = (function () {\r\n if (typeof global !== 'undefined' && global.Math === Math) {\r\n return global;\r\n }\r\n if (typeof self !== 'undefined' && self.Math === Math) {\r\n return self;\r\n }\r\n if (typeof window !== 'undefined' && window.Math === Math) {\r\n return window;\r\n }\r\n // eslint-disable-next-line no-new-func\r\n return Function('return this')();\r\n})();\n\n/**\r\n * A shim for the requestAnimationFrame which falls back to the setTimeout if\r\n * first one is not supported.\r\n *\r\n * @returns {number} Requests' identifier.\r\n */\r\nvar requestAnimationFrame$1 = (function () {\r\n if (typeof requestAnimationFrame === 'function') {\r\n // It's required to use a bounded function because IE sometimes throws\r\n // an \"Invalid calling object\" error if rAF is invoked without the global\r\n // object on the left hand side.\r\n return requestAnimationFrame.bind(global$1);\r\n }\r\n return function (callback) { return setTimeout(function () { return callback(Date.now()); }, 1000 / 60); };\r\n})();\n\n// Defines minimum timeout before adding a trailing call.\r\nvar trailingTimeout = 2;\r\n/**\r\n * Creates a wrapper function which ensures that provided callback will be\r\n * invoked only once during the specified delay period.\r\n *\r\n * @param {Function} callback - Function to be invoked after the delay period.\r\n * @param {number} delay - Delay after which to invoke callback.\r\n * @returns {Function}\r\n */\r\nfunction throttle (callback, delay) {\r\n var leadingCall = false, trailingCall = false, lastCallTime = 0;\r\n /**\r\n * Invokes the original callback function and schedules new invocation if\r\n * the \"proxy\" was called during current request.\r\n *\r\n * @returns {void}\r\n */\r\n function resolvePending() {\r\n if (leadingCall) {\r\n leadingCall = false;\r\n callback();\r\n }\r\n if (trailingCall) {\r\n proxy();\r\n }\r\n }\r\n /**\r\n * Callback invoked after the specified delay. It will further postpone\r\n * invocation of the original function delegating it to the\r\n * requestAnimationFrame.\r\n *\r\n * @returns {void}\r\n */\r\n function timeoutCallback() {\r\n requestAnimationFrame$1(resolvePending);\r\n }\r\n /**\r\n * Schedules invocation of the original function.\r\n *\r\n * @returns {void}\r\n */\r\n function proxy() {\r\n var timeStamp = Date.now();\r\n if (leadingCall) {\r\n // Reject immediately following calls.\r\n if (timeStamp - lastCallTime < trailingTimeout) {\r\n return;\r\n }\r\n // Schedule new call to be in invoked when the pending one is resolved.\r\n // This is important for \"transitions\" which never actually start\r\n // immediately so there is a chance that we might miss one if change\r\n // happens amids the pending invocation.\r\n trailingCall = true;\r\n }\r\n else {\r\n leadingCall = true;\r\n trailingCall = false;\r\n setTimeout(timeoutCallback, delay);\r\n }\r\n lastCallTime = timeStamp;\r\n }\r\n return proxy;\r\n}\n\n// Minimum delay before invoking the update of observers.\r\nvar REFRESH_DELAY = 20;\r\n// A list of substrings of CSS properties used to find transition events that\r\n// might affect dimensions of observed elements.\r\nvar transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight'];\r\n// Check if MutationObserver is available.\r\nvar mutationObserverSupported = typeof MutationObserver !== 'undefined';\r\n/**\r\n * Singleton controller class which handles updates of ResizeObserver instances.\r\n */\r\nvar ResizeObserverController = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserverController.\r\n *\r\n * @private\r\n */\r\n function ResizeObserverController() {\r\n /**\r\n * Indicates whether DOM listeners have been added.\r\n *\r\n * @private {boolean}\r\n */\r\n this.connected_ = false;\r\n /**\r\n * Tells that controller has subscribed for Mutation Events.\r\n *\r\n * @private {boolean}\r\n */\r\n this.mutationEventsAdded_ = false;\r\n /**\r\n * Keeps reference to the instance of MutationObserver.\r\n *\r\n * @private {MutationObserver}\r\n */\r\n this.mutationsObserver_ = null;\r\n /**\r\n * A list of connected observers.\r\n *\r\n * @private {Array}\r\n */\r\n this.observers_ = [];\r\n this.onTransitionEnd_ = this.onTransitionEnd_.bind(this);\r\n this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY);\r\n }\r\n /**\r\n * Adds observer to observers list.\r\n *\r\n * @param {ResizeObserverSPI} observer - Observer to be added.\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.addObserver = function (observer) {\r\n if (!~this.observers_.indexOf(observer)) {\r\n this.observers_.push(observer);\r\n }\r\n // Add listeners if they haven't been added yet.\r\n if (!this.connected_) {\r\n this.connect_();\r\n }\r\n };\r\n /**\r\n * Removes observer from observers list.\r\n *\r\n * @param {ResizeObserverSPI} observer - Observer to be removed.\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.removeObserver = function (observer) {\r\n var observers = this.observers_;\r\n var index = observers.indexOf(observer);\r\n // Remove observer if it's present in registry.\r\n if (~index) {\r\n observers.splice(index, 1);\r\n }\r\n // Remove listeners if controller has no connected observers.\r\n if (!observers.length && this.connected_) {\r\n this.disconnect_();\r\n }\r\n };\r\n /**\r\n * Invokes the update of observers. It will continue running updates insofar\r\n * it detects changes.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.refresh = function () {\r\n var changesDetected = this.updateObservers_();\r\n // Continue running updates if changes have been detected as there might\r\n // be future ones caused by CSS transitions.\r\n if (changesDetected) {\r\n this.refresh();\r\n }\r\n };\r\n /**\r\n * Updates every observer from observers list and notifies them of queued\r\n * entries.\r\n *\r\n * @private\r\n * @returns {boolean} Returns \"true\" if any observer has detected changes in\r\n * dimensions of it's elements.\r\n */\r\n ResizeObserverController.prototype.updateObservers_ = function () {\r\n // Collect observers that have active observations.\r\n var activeObservers = this.observers_.filter(function (observer) {\r\n return observer.gatherActive(), observer.hasActive();\r\n });\r\n // Deliver notifications in a separate cycle in order to avoid any\r\n // collisions between observers, e.g. when multiple instances of\r\n // ResizeObserver are tracking the same element and the callback of one\r\n // of them changes content dimensions of the observed target. Sometimes\r\n // this may result in notifications being blocked for the rest of observers.\r\n activeObservers.forEach(function (observer) { return observer.broadcastActive(); });\r\n return activeObservers.length > 0;\r\n };\r\n /**\r\n * Initializes DOM listeners.\r\n *\r\n * @private\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.connect_ = function () {\r\n // Do nothing if running in a non-browser environment or if listeners\r\n // have been already added.\r\n if (!isBrowser || this.connected_) {\r\n return;\r\n }\r\n // Subscription to the \"Transitionend\" event is used as a workaround for\r\n // delayed transitions. This way it's possible to capture at least the\r\n // final state of an element.\r\n document.addEventListener('transitionend', this.onTransitionEnd_);\r\n window.addEventListener('resize', this.refresh);\r\n if (mutationObserverSupported) {\r\n this.mutationsObserver_ = new MutationObserver(this.refresh);\r\n this.mutationsObserver_.observe(document, {\r\n attributes: true,\r\n childList: true,\r\n characterData: true,\r\n subtree: true\r\n });\r\n }\r\n else {\r\n document.addEventListener('DOMSubtreeModified', this.refresh);\r\n this.mutationEventsAdded_ = true;\r\n }\r\n this.connected_ = true;\r\n };\r\n /**\r\n * Removes DOM listeners.\r\n *\r\n * @private\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.disconnect_ = function () {\r\n // Do nothing if running in a non-browser environment or if listeners\r\n // have been already removed.\r\n if (!isBrowser || !this.connected_) {\r\n return;\r\n }\r\n document.removeEventListener('transitionend', this.onTransitionEnd_);\r\n window.removeEventListener('resize', this.refresh);\r\n if (this.mutationsObserver_) {\r\n this.mutationsObserver_.disconnect();\r\n }\r\n if (this.mutationEventsAdded_) {\r\n document.removeEventListener('DOMSubtreeModified', this.refresh);\r\n }\r\n this.mutationsObserver_ = null;\r\n this.mutationEventsAdded_ = false;\r\n this.connected_ = false;\r\n };\r\n /**\r\n * \"Transitionend\" event handler.\r\n *\r\n * @private\r\n * @param {TransitionEvent} event\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.onTransitionEnd_ = function (_a) {\r\n var _b = _a.propertyName, propertyName = _b === void 0 ? '' : _b;\r\n // Detect whether transition may affect dimensions of an element.\r\n var isReflowProperty = transitionKeys.some(function (key) {\r\n return !!~propertyName.indexOf(key);\r\n });\r\n if (isReflowProperty) {\r\n this.refresh();\r\n }\r\n };\r\n /**\r\n * Returns instance of the ResizeObserverController.\r\n *\r\n * @returns {ResizeObserverController}\r\n */\r\n ResizeObserverController.getInstance = function () {\r\n if (!this.instance_) {\r\n this.instance_ = new ResizeObserverController();\r\n }\r\n return this.instance_;\r\n };\r\n /**\r\n * Holds reference to the controller's instance.\r\n *\r\n * @private {ResizeObserverController}\r\n */\r\n ResizeObserverController.instance_ = null;\r\n return ResizeObserverController;\r\n}());\n\n/**\r\n * Defines non-writable/enumerable properties of the provided target object.\r\n *\r\n * @param {Object} target - Object for which to define properties.\r\n * @param {Object} props - Properties to be defined.\r\n * @returns {Object} Target object.\r\n */\r\nvar defineConfigurable = (function (target, props) {\r\n for (var _i = 0, _a = Object.keys(props); _i < _a.length; _i++) {\r\n var key = _a[_i];\r\n Object.defineProperty(target, key, {\r\n value: props[key],\r\n enumerable: false,\r\n writable: false,\r\n configurable: true\r\n });\r\n }\r\n return target;\r\n});\n\n/**\r\n * Returns the global object associated with provided element.\r\n *\r\n * @param {Object} target\r\n * @returns {Object}\r\n */\r\nvar getWindowOf = (function (target) {\r\n // Assume that the element is an instance of Node, which means that it\r\n // has the \"ownerDocument\" property from which we can retrieve a\r\n // corresponding global object.\r\n var ownerGlobal = target && target.ownerDocument && target.ownerDocument.defaultView;\r\n // Return the local global object if it's not possible extract one from\r\n // provided element.\r\n return ownerGlobal || global$1;\r\n});\n\n// Placeholder of an empty content rectangle.\r\nvar emptyRect = createRectInit(0, 0, 0, 0);\r\n/**\r\n * Converts provided string to a number.\r\n *\r\n * @param {number|string} value\r\n * @returns {number}\r\n */\r\nfunction toFloat(value) {\r\n return parseFloat(value) || 0;\r\n}\r\n/**\r\n * Extracts borders size from provided styles.\r\n *\r\n * @param {CSSStyleDeclaration} styles\r\n * @param {...string} positions - Borders positions (top, right, ...)\r\n * @returns {number}\r\n */\r\nfunction getBordersSize(styles) {\r\n var positions = [];\r\n for (var _i = 1; _i < arguments.length; _i++) {\r\n positions[_i - 1] = arguments[_i];\r\n }\r\n return positions.reduce(function (size, position) {\r\n var value = styles['border-' + position + '-width'];\r\n return size + toFloat(value);\r\n }, 0);\r\n}\r\n/**\r\n * Extracts paddings sizes from provided styles.\r\n *\r\n * @param {CSSStyleDeclaration} styles\r\n * @returns {Object} Paddings box.\r\n */\r\nfunction getPaddings(styles) {\r\n var positions = ['top', 'right', 'bottom', 'left'];\r\n var paddings = {};\r\n for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) {\r\n var position = positions_1[_i];\r\n var value = styles['padding-' + position];\r\n paddings[position] = toFloat(value);\r\n }\r\n return paddings;\r\n}\r\n/**\r\n * Calculates content rectangle of provided SVG element.\r\n *\r\n * @param {SVGGraphicsElement} target - Element content rectangle of which needs\r\n * to be calculated.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getSVGContentRect(target) {\r\n var bbox = target.getBBox();\r\n return createRectInit(0, 0, bbox.width, bbox.height);\r\n}\r\n/**\r\n * Calculates content rectangle of provided HTMLElement.\r\n *\r\n * @param {HTMLElement} target - Element for which to calculate the content rectangle.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getHTMLElementContentRect(target) {\r\n // Client width & height properties can't be\r\n // used exclusively as they provide rounded values.\r\n var clientWidth = target.clientWidth, clientHeight = target.clientHeight;\r\n // By this condition we can catch all non-replaced inline, hidden and\r\n // detached elements. Though elements with width & height properties less\r\n // than 0.5 will be discarded as well.\r\n //\r\n // Without it we would need to implement separate methods for each of\r\n // those cases and it's not possible to perform a precise and performance\r\n // effective test for hidden elements. E.g. even jQuery's ':visible' filter\r\n // gives wrong results for elements with width & height less than 0.5.\r\n if (!clientWidth && !clientHeight) {\r\n return emptyRect;\r\n }\r\n var styles = getWindowOf(target).getComputedStyle(target);\r\n var paddings = getPaddings(styles);\r\n var horizPad = paddings.left + paddings.right;\r\n var vertPad = paddings.top + paddings.bottom;\r\n // Computed styles of width & height are being used because they are the\r\n // only dimensions available to JS that contain non-rounded values. It could\r\n // be possible to utilize the getBoundingClientRect if only it's data wasn't\r\n // affected by CSS transformations let alone paddings, borders and scroll bars.\r\n var width = toFloat(styles.width), height = toFloat(styles.height);\r\n // Width & height include paddings and borders when the 'border-box' box\r\n // model is applied (except for IE).\r\n if (styles.boxSizing === 'border-box') {\r\n // Following conditions are required to handle Internet Explorer which\r\n // doesn't include paddings and borders to computed CSS dimensions.\r\n //\r\n // We can say that if CSS dimensions + paddings are equal to the \"client\"\r\n // properties then it's either IE, and thus we don't need to subtract\r\n // anything, or an element merely doesn't have paddings/borders styles.\r\n if (Math.round(width + horizPad) !== clientWidth) {\r\n width -= getBordersSize(styles, 'left', 'right') + horizPad;\r\n }\r\n if (Math.round(height + vertPad) !== clientHeight) {\r\n height -= getBordersSize(styles, 'top', 'bottom') + vertPad;\r\n }\r\n }\r\n // Following steps can't be applied to the document's root element as its\r\n // client[Width/Height] properties represent viewport area of the window.\r\n // Besides, it's as well not necessary as the itself neither has\r\n // rendered scroll bars nor it can be clipped.\r\n if (!isDocumentElement(target)) {\r\n // In some browsers (only in Firefox, actually) CSS width & height\r\n // include scroll bars size which can be removed at this step as scroll\r\n // bars are the only difference between rounded dimensions + paddings\r\n // and \"client\" properties, though that is not always true in Chrome.\r\n var vertScrollbar = Math.round(width + horizPad) - clientWidth;\r\n var horizScrollbar = Math.round(height + vertPad) - clientHeight;\r\n // Chrome has a rather weird rounding of \"client\" properties.\r\n // E.g. for an element with content width of 314.2px it sometimes gives\r\n // the client width of 315px and for the width of 314.7px it may give\r\n // 314px. And it doesn't happen all the time. So just ignore this delta\r\n // as a non-relevant.\r\n if (Math.abs(vertScrollbar) !== 1) {\r\n width -= vertScrollbar;\r\n }\r\n if (Math.abs(horizScrollbar) !== 1) {\r\n height -= horizScrollbar;\r\n }\r\n }\r\n return createRectInit(paddings.left, paddings.top, width, height);\r\n}\r\n/**\r\n * Checks whether provided element is an instance of the SVGGraphicsElement.\r\n *\r\n * @param {Element} target - Element to be checked.\r\n * @returns {boolean}\r\n */\r\nvar isSVGGraphicsElement = (function () {\r\n // Some browsers, namely IE and Edge, don't have the SVGGraphicsElement\r\n // interface.\r\n if (typeof SVGGraphicsElement !== 'undefined') {\r\n return function (target) { return target instanceof getWindowOf(target).SVGGraphicsElement; };\r\n }\r\n // If it's so, then check that element is at least an instance of the\r\n // SVGElement and that it has the \"getBBox\" method.\r\n // eslint-disable-next-line no-extra-parens\r\n return function (target) { return (target instanceof getWindowOf(target).SVGElement &&\r\n typeof target.getBBox === 'function'); };\r\n})();\r\n/**\r\n * Checks whether provided element is a document element ().\r\n *\r\n * @param {Element} target - Element to be checked.\r\n * @returns {boolean}\r\n */\r\nfunction isDocumentElement(target) {\r\n return target === getWindowOf(target).document.documentElement;\r\n}\r\n/**\r\n * Calculates an appropriate content rectangle for provided html or svg element.\r\n *\r\n * @param {Element} target - Element content rectangle of which needs to be calculated.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getContentRect(target) {\r\n if (!isBrowser) {\r\n return emptyRect;\r\n }\r\n if (isSVGGraphicsElement(target)) {\r\n return getSVGContentRect(target);\r\n }\r\n return getHTMLElementContentRect(target);\r\n}\r\n/**\r\n * Creates rectangle with an interface of the DOMRectReadOnly.\r\n * Spec: https://drafts.fxtf.org/geometry/#domrectreadonly\r\n *\r\n * @param {DOMRectInit} rectInit - Object with rectangle's x/y coordinates and dimensions.\r\n * @returns {DOMRectReadOnly}\r\n */\r\nfunction createReadOnlyRect(_a) {\r\n var x = _a.x, y = _a.y, width = _a.width, height = _a.height;\r\n // If DOMRectReadOnly is available use it as a prototype for the rectangle.\r\n var Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object;\r\n var rect = Object.create(Constr.prototype);\r\n // Rectangle's properties are not writable and non-enumerable.\r\n defineConfigurable(rect, {\r\n x: x, y: y, width: width, height: height,\r\n top: y,\r\n right: x + width,\r\n bottom: height + y,\r\n left: x\r\n });\r\n return rect;\r\n}\r\n/**\r\n * Creates DOMRectInit object based on the provided dimensions and the x/y coordinates.\r\n * Spec: https://drafts.fxtf.org/geometry/#dictdef-domrectinit\r\n *\r\n * @param {number} x - X coordinate.\r\n * @param {number} y - Y coordinate.\r\n * @param {number} width - Rectangle's width.\r\n * @param {number} height - Rectangle's height.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction createRectInit(x, y, width, height) {\r\n return { x: x, y: y, width: width, height: height };\r\n}\n\n/**\r\n * Class that is responsible for computations of the content rectangle of\r\n * provided DOM element and for keeping track of it's changes.\r\n */\r\nvar ResizeObservation = /** @class */ (function () {\r\n /**\r\n * Creates an instance of ResizeObservation.\r\n *\r\n * @param {Element} target - Element to be observed.\r\n */\r\n function ResizeObservation(target) {\r\n /**\r\n * Broadcasted width of content rectangle.\r\n *\r\n * @type {number}\r\n */\r\n this.broadcastWidth = 0;\r\n /**\r\n * Broadcasted height of content rectangle.\r\n *\r\n * @type {number}\r\n */\r\n this.broadcastHeight = 0;\r\n /**\r\n * Reference to the last observed content rectangle.\r\n *\r\n * @private {DOMRectInit}\r\n */\r\n this.contentRect_ = createRectInit(0, 0, 0, 0);\r\n this.target = target;\r\n }\r\n /**\r\n * Updates content rectangle and tells whether it's width or height properties\r\n * have changed since the last broadcast.\r\n *\r\n * @returns {boolean}\r\n */\r\n ResizeObservation.prototype.isActive = function () {\r\n var rect = getContentRect(this.target);\r\n this.contentRect_ = rect;\r\n return (rect.width !== this.broadcastWidth ||\r\n rect.height !== this.broadcastHeight);\r\n };\r\n /**\r\n * Updates 'broadcastWidth' and 'broadcastHeight' properties with a data\r\n * from the corresponding properties of the last observed content rectangle.\r\n *\r\n * @returns {DOMRectInit} Last observed content rectangle.\r\n */\r\n ResizeObservation.prototype.broadcastRect = function () {\r\n var rect = this.contentRect_;\r\n this.broadcastWidth = rect.width;\r\n this.broadcastHeight = rect.height;\r\n return rect;\r\n };\r\n return ResizeObservation;\r\n}());\n\nvar ResizeObserverEntry = /** @class */ (function () {\r\n /**\r\n * Creates an instance of ResizeObserverEntry.\r\n *\r\n * @param {Element} target - Element that is being observed.\r\n * @param {DOMRectInit} rectInit - Data of the element's content rectangle.\r\n */\r\n function ResizeObserverEntry(target, rectInit) {\r\n var contentRect = createReadOnlyRect(rectInit);\r\n // According to the specification following properties are not writable\r\n // and are also not enumerable in the native implementation.\r\n //\r\n // Property accessors are not being used as they'd require to define a\r\n // private WeakMap storage which may cause memory leaks in browsers that\r\n // don't support this type of collections.\r\n defineConfigurable(this, { target: target, contentRect: contentRect });\r\n }\r\n return ResizeObserverEntry;\r\n}());\n\nvar ResizeObserverSPI = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserver.\r\n *\r\n * @param {ResizeObserverCallback} callback - Callback function that is invoked\r\n * when one of the observed elements changes it's content dimensions.\r\n * @param {ResizeObserverController} controller - Controller instance which\r\n * is responsible for the updates of observer.\r\n * @param {ResizeObserver} callbackCtx - Reference to the public\r\n * ResizeObserver instance which will be passed to callback function.\r\n */\r\n function ResizeObserverSPI(callback, controller, callbackCtx) {\r\n /**\r\n * Collection of resize observations that have detected changes in dimensions\r\n * of elements.\r\n *\r\n * @private {Array}\r\n */\r\n this.activeObservations_ = [];\r\n /**\r\n * Registry of the ResizeObservation instances.\r\n *\r\n * @private {Map}\r\n */\r\n this.observations_ = new MapShim();\r\n if (typeof callback !== 'function') {\r\n throw new TypeError('The callback provided as parameter 1 is not a function.');\r\n }\r\n this.callback_ = callback;\r\n this.controller_ = controller;\r\n this.callbackCtx_ = callbackCtx;\r\n }\r\n /**\r\n * Starts observing provided element.\r\n *\r\n * @param {Element} target - Element to be observed.\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.observe = function (target) {\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n // Do nothing if current environment doesn't have the Element interface.\r\n if (typeof Element === 'undefined' || !(Element instanceof Object)) {\r\n return;\r\n }\r\n if (!(target instanceof getWindowOf(target).Element)) {\r\n throw new TypeError('parameter 1 is not of type \"Element\".');\r\n }\r\n var observations = this.observations_;\r\n // Do nothing if element is already being observed.\r\n if (observations.has(target)) {\r\n return;\r\n }\r\n observations.set(target, new ResizeObservation(target));\r\n this.controller_.addObserver(this);\r\n // Force the update of observations.\r\n this.controller_.refresh();\r\n };\r\n /**\r\n * Stops observing provided element.\r\n *\r\n * @param {Element} target - Element to stop observing.\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.unobserve = function (target) {\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n // Do nothing if current environment doesn't have the Element interface.\r\n if (typeof Element === 'undefined' || !(Element instanceof Object)) {\r\n return;\r\n }\r\n if (!(target instanceof getWindowOf(target).Element)) {\r\n throw new TypeError('parameter 1 is not of type \"Element\".');\r\n }\r\n var observations = this.observations_;\r\n // Do nothing if element is not being observed.\r\n if (!observations.has(target)) {\r\n return;\r\n }\r\n observations.delete(target);\r\n if (!observations.size) {\r\n this.controller_.removeObserver(this);\r\n }\r\n };\r\n /**\r\n * Stops observing all elements.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.disconnect = function () {\r\n this.clearActive();\r\n this.observations_.clear();\r\n this.controller_.removeObserver(this);\r\n };\r\n /**\r\n * Collects observation instances the associated element of which has changed\r\n * it's content rectangle.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.gatherActive = function () {\r\n var _this = this;\r\n this.clearActive();\r\n this.observations_.forEach(function (observation) {\r\n if (observation.isActive()) {\r\n _this.activeObservations_.push(observation);\r\n }\r\n });\r\n };\r\n /**\r\n * Invokes initial callback function with a list of ResizeObserverEntry\r\n * instances collected from active resize observations.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.broadcastActive = function () {\r\n // Do nothing if observer doesn't have active observations.\r\n if (!this.hasActive()) {\r\n return;\r\n }\r\n var ctx = this.callbackCtx_;\r\n // Create ResizeObserverEntry instance for every active observation.\r\n var entries = this.activeObservations_.map(function (observation) {\r\n return new ResizeObserverEntry(observation.target, observation.broadcastRect());\r\n });\r\n this.callback_.call(ctx, entries, ctx);\r\n this.clearActive();\r\n };\r\n /**\r\n * Clears the collection of active observations.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.clearActive = function () {\r\n this.activeObservations_.splice(0);\r\n };\r\n /**\r\n * Tells whether observer has active observations.\r\n *\r\n * @returns {boolean}\r\n */\r\n ResizeObserverSPI.prototype.hasActive = function () {\r\n return this.activeObservations_.length > 0;\r\n };\r\n return ResizeObserverSPI;\r\n}());\n\n// Registry of internal observers. If WeakMap is not available use current shim\r\n// for the Map collection as it has all required methods and because WeakMap\r\n// can't be fully polyfilled anyway.\r\nvar observers = typeof WeakMap !== 'undefined' ? new WeakMap() : new MapShim();\r\n/**\r\n * ResizeObserver API. Encapsulates the ResizeObserver SPI implementation\r\n * exposing only those methods and properties that are defined in the spec.\r\n */\r\nvar ResizeObserver = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserver.\r\n *\r\n * @param {ResizeObserverCallback} callback - Callback that is invoked when\r\n * dimensions of the observed elements change.\r\n */\r\n function ResizeObserver(callback) {\r\n if (!(this instanceof ResizeObserver)) {\r\n throw new TypeError('Cannot call a class as a function.');\r\n }\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n var controller = ResizeObserverController.getInstance();\r\n var observer = new ResizeObserverSPI(callback, controller, this);\r\n observers.set(this, observer);\r\n }\r\n return ResizeObserver;\r\n}());\r\n// Expose public methods of ResizeObserver.\r\n[\r\n 'observe',\r\n 'unobserve',\r\n 'disconnect'\r\n].forEach(function (method) {\r\n ResizeObserver.prototype[method] = function () {\r\n var _a;\r\n return (_a = observers.get(this))[method].apply(_a, arguments);\r\n };\r\n});\n\nvar index = (function () {\r\n // Export existing implementation if available.\r\n if (typeof global$1.ResizeObserver !== 'undefined') {\r\n return global$1.ResizeObserver;\r\n }\r\n return ResizeObserver;\r\n})();\n\nexport default index;\n", + "/** @license React v0.13.4\n * scheduler.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';Object.defineProperty(exports,\"__esModule\",{value:!0});var d=null,e=!1,g=3,k=-1,l=-1,m=!1,n=!1;function p(){if(!m){var a=d.expirationTime;n?q():n=!0;r(t,a)}}\nfunction u(){var a=d,b=d.next;if(d===b)d=null;else{var c=d.previous;d=c.next=b;b.previous=c}a.next=a.previous=null;c=a.callback;b=a.expirationTime;a=a.priorityLevel;var f=g,Q=l;g=a;l=b;try{var h=c()}finally{g=f,l=Q}if(\"function\"===typeof h)if(h={callback:h,priorityLevel:a,expirationTime:b,next:null,previous:null},null===d)d=h.next=h.previous=h;else{c=null;a=d;do{if(a.expirationTime>=b){c=a;break}a=a.next}while(a!==d);null===c?c=d:c===d&&(d=h,p());b=c.previous;b.next=c.previous=h;h.next=c;h.previous=\nb}}function v(){if(-1===k&&null!==d&&1===d.priorityLevel){m=!0;try{do u();while(null!==d&&1===d.priorityLevel)}finally{m=!1,null!==d?p():n=!1}}}function t(a){m=!0;var b=e;e=a;try{if(a)for(;null!==d;){var c=exports.unstable_now();if(d.expirationTime<=c){do u();while(null!==d&&d.expirationTime<=c)}else break}else if(null!==d){do u();while(null!==d&&!w())}}finally{m=!1,e=b,null!==d?p():n=!1,v()}}\nvar x=Date,y=\"function\"===typeof setTimeout?setTimeout:void 0,z=\"function\"===typeof clearTimeout?clearTimeout:void 0,A=\"function\"===typeof requestAnimationFrame?requestAnimationFrame:void 0,B=\"function\"===typeof cancelAnimationFrame?cancelAnimationFrame:void 0,C,D;function E(a){C=A(function(b){z(D);a(b)});D=y(function(){B(C);a(exports.unstable_now())},100)}\nif(\"object\"===typeof performance&&\"function\"===typeof performance.now){var F=performance;exports.unstable_now=function(){return F.now()}}else exports.unstable_now=function(){return x.now()};var r,q,w,G=null;\"undefined\"!==typeof window?G=window:\"undefined\"!==typeof global&&(G=global);\nif(G&&G._schedMock){var H=G._schedMock;r=H[0];q=H[1];w=H[2];exports.unstable_now=H[3]}else if(\"undefined\"===typeof window||\"function\"!==typeof MessageChannel){var I=null,J=function(a){if(null!==I)try{I(a)}finally{I=null}};r=function(a){null!==I?setTimeout(r,0,a):(I=a,setTimeout(J,0,!1))};q=function(){I=null};w=function(){return!1}}else{\"undefined\"!==typeof console&&(\"function\"!==typeof A&&console.error(\"This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\"),\n\"function\"!==typeof B&&console.error(\"This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\"));var K=null,L=!1,M=-1,N=!1,O=!1,P=0,R=33,S=33;w=function(){return P<=exports.unstable_now()};var T=new MessageChannel,U=T.port2;T.port1.onmessage=function(){L=!1;var a=K,b=M;K=null;M=-1;var c=exports.unstable_now(),f=!1;if(0>=P-c)if(-1!==b&&b<=c)f=!0;else{N||(N=!0,E(V));K=a;M=b;return}if(null!==a){O=!0;try{a(f)}finally{O=!1}}};\nvar V=function(a){if(null!==K){E(V);var b=a-P+S;bb&&(b=8),S=bb?U.postMessage(void 0):N||(N=!0,E(V))};q=function(){K=null;L=!1;M=-1}}exports.unstable_ImmediatePriority=1;exports.unstable_UserBlockingPriority=2;exports.unstable_NormalPriority=3;exports.unstable_IdlePriority=5;exports.unstable_LowPriority=4;\nexports.unstable_runWithPriority=function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3}var c=g,f=k;g=a;k=exports.unstable_now();try{return b()}finally{g=c,k=f,v()}};exports.unstable_next=function(a){switch(g){case 1:case 2:case 3:var b=3;break;default:b=g}var c=g,f=k;g=b;k=exports.unstable_now();try{return a()}finally{g=c,k=f,v()}};\nexports.unstable_scheduleCallback=function(a,b){var c=-1!==k?k:exports.unstable_now();if(\"object\"===typeof b&&null!==b&&\"number\"===typeof b.timeout)b=c+b.timeout;else switch(g){case 1:b=c+-1;break;case 2:b=c+250;break;case 5:b=c+1073741823;break;case 4:b=c+1E4;break;default:b=c+5E3}a={callback:a,priorityLevel:g,expirationTime:b,next:null,previous:null};if(null===d)d=a.next=a.previous=a,p();else{c=null;var f=d;do{if(f.expirationTime>b){c=f;break}f=f.next}while(f!==d);null===c?c=d:c===d&&(d=a,p());\nb=c.previous;b.next=c.previous=a;a.next=c;a.previous=b}return a};exports.unstable_cancelCallback=function(a){var b=a.next;if(null!==b){if(b===a)d=null;else{a===d&&(d=b);var c=a.previous;c.next=b;b.previous=c}a.next=a.previous=null}};exports.unstable_wrapCallback=function(a){var b=g;return function(){var c=g,f=k;g=b;k=exports.unstable_now();try{return a.apply(this,arguments)}finally{g=c,k=f,v()}}};exports.unstable_getCurrentPriorityLevel=function(){return g};\nexports.unstable_shouldYield=function(){return!e&&(null!==d&&d.expirationTime element; its readystatechange event will be fired asynchronously once it is inserted\n // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.\n var script = doc.createElement(\"script\");\n script.onreadystatechange = function () {\n runIfPresent(handle);\n script.onreadystatechange = null;\n html.removeChild(script);\n script = null;\n };\n html.appendChild(script);\n };\n }\n\n function installSetTimeoutImplementation() {\n registerImmediate = function(handle) {\n setTimeout(runIfPresent, 0, handle);\n };\n }\n\n // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.\n var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);\n attachTo = attachTo && attachTo.setTimeout ? attachTo : global;\n\n // Don't get fooled by e.g. browserify environments.\n if ({}.toString.call(global.process) === \"[object process]\") {\n // For Node.js before 0.9\n installNextTickImplementation();\n\n } else if (canUsePostMessage()) {\n // For non-IE10 modern browsers\n installPostMessageImplementation();\n\n } else if (global.MessageChannel) {\n // For web workers, where supported\n installMessageChannelImplementation();\n\n } else if (doc && \"onreadystatechange\" in doc.createElement(\"script\")) {\n // For IE 6–8\n installReadyStateChangeImplementation();\n\n } else {\n // For older browsers\n installSetTimeoutImplementation();\n }\n\n attachTo.setImmediate = setImmediate;\n attachTo.clearImmediate = clearImmediate;\n}(typeof self === \"undefined\" ? typeof global === \"undefined\" ? this : global : self));\n", + "/* global window */\nimport ponyfill from './ponyfill.js';\n\nvar root;\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = ponyfill(root);\nexport default result;\n", + "export default function symbolObservablePonyfill(root) {\n\tvar result;\n\tvar Symbol = root.Symbol;\n\n\tif (typeof Symbol === 'function') {\n\t\tif (Symbol.observable) {\n\t\t\tresult = Symbol.observable;\n\t\t} else {\n\t\t\tresult = Symbol('observable');\n\t\t\tSymbol.observable = result;\n\t\t}\n\t} else {\n\t\tresult = '@@observable';\n\t}\n\n\treturn result;\n};\n", + "var scope = (typeof global !== \"undefined\" && global) ||\n (typeof self !== \"undefined\" && self) ||\n window;\nvar apply = Function.prototype.apply;\n\n// DOM APIs, for completeness\n\nexports.setTimeout = function() {\n return new Timeout(apply.call(setTimeout, scope, arguments), clearTimeout);\n};\nexports.setInterval = function() {\n return new Timeout(apply.call(setInterval, scope, arguments), clearInterval);\n};\nexports.clearTimeout =\nexports.clearInterval = function(timeout) {\n if (timeout) {\n timeout.close();\n }\n};\n\nfunction Timeout(id, clearFn) {\n this._id = id;\n this._clearFn = clearFn;\n}\nTimeout.prototype.unref = Timeout.prototype.ref = function() {};\nTimeout.prototype.close = function() {\n this._clearFn.call(scope, this._id);\n};\n\n// Does not start the time, just sets up the members needed.\nexports.enroll = function(item, msecs) {\n clearTimeout(item._idleTimeoutId);\n item._idleTimeout = msecs;\n};\n\nexports.unenroll = function(item) {\n clearTimeout(item._idleTimeoutId);\n item._idleTimeout = -1;\n};\n\nexports._unrefActive = exports.active = function(item) {\n clearTimeout(item._idleTimeoutId);\n\n var msecs = item._idleTimeout;\n if (msecs >= 0) {\n item._idleTimeoutId = setTimeout(function onTimeout() {\n if (item._onTimeout)\n item._onTimeout();\n }, msecs);\n }\n};\n\n// setimmediate attaches itself to the global object\nrequire(\"setimmediate\");\n// On some exotic environments, it's not clear which object `)))) + ((("`" + (`setimmediate` + "`")) + (` was\n// able to install onto. Search each possibility in the same order as the\n// ` + ("`" + `setimmediate`))) + (("`" + (` library.\nexports.setImmediate = (typeof self !== \"undefined\" && self.setImmediate) ||\n (typeof global !== \"undefined\" && global.setImmediate) ||\n (this && this.setImmediate);\nexports.clearImmediate = (typeof self !== \"undefined\" && self.clearImmediate) ||\n (typeof global !== \"undefined\" && global.clearImmediate) ||\n (this && this.clearImmediate);\n", + "/**\n * Copyright (c) 2014-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\n/**\n * Similar to invariant but only logs a warning if the condition is not met.\n * This can be used to log issues in development environments in critical\n * paths. Removing the logging code for production environments will keep the\n * same logic and follow the same code paths.\n */\n\nvar __DEV__ = process.env.NODE_ENV !== 'production';\n\nvar warning = function() {};\n\nif (__DEV__) {\n var printWarning = function printWarning(format, args) {\n var len = arguments.length;\n args = new Array(len > 1 ? len - 1 : 0);\n for (var key = 1; key < len; key++) {\n args[key - 1] = arguments[key];\n }\n var argIndex = 0;\n var message = 'Warning: ' +\n format.replace(/%s/g, function() {\n return args[argIndex++];\n });\n if (typeof console !== 'undefined') {\n console.error(message);\n }\n try {\n // --- Welcome to debugging React ---\n // This error was thrown as a convenience so that you can use this stack\n // to find the callsite that caused this warning to fire.\n throw new Error(message);\n } catch (x) {}\n }\n\n warning = function(condition, format, args) {\n var len = arguments.length;\n args = new Array(len > 2 ? len - 2 : 0);\n for (var key = 2; key < len; key++) {\n args[key - 2] = arguments[key];\n }\n if (format === undefined) {\n throw new Error(\n '` + "`")) + (`warning(condition, format, ...args)` + ("`" + ` requires a warning ' +\n 'message argument'\n );\n }\n if (!condition) {\n printWarning.apply(null, [format].concat(args));\n }\n };\n}\n\nmodule.exports = warning;\n", + "var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n", + "module.exports = function(originalModule) {\n\tif (!originalModule.webpackPolyfill) {\n\t\tvar module = Object.create(originalModule);\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"exports\", {\n\t\t\tenumerable: true\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n", + "module.exports = function(module) {\n\tif (!module.webpackPolyfill) {\n\t\tmodule.deprecate = function() {};\n\t\tmodule.paths = [];\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n" + ], + "sourceRoot": "" +}`)))))))))))))) + +func bundleJsMapBytes() ([]byte, error) { + return _bundleJsMap, nil +} + +func bundleJsMap() (*asset, error) { + bytes, err := bundleJsMapBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "bundle.js.map", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb6, 0x68, 0x46, 0x48, 0x3, 0x7c, 0x38, 0x69, 0xe7, 0xca, 0x1d, 0x61, 0xd8, 0x6c, 0x20, 0x6a, 0xf5, 0xe3, 0x9c, 0xa5, 0x35, 0xd7, 0xd9, 0x4d, 0x63, 0xd3, 0xe3, 0xdc, 0x80, 0x20, 0x6a, 0xe1}} return a, nil } @@ -40727,6 +38047,8 @@ var _bindata = map[string]func() (*asset, error){ "index.html": indexHtml, "bundle.js": bundleJs, + + "bundle.js.map": bundleJsMap, } // AssetDir returns the file names below a certain @@ -40770,8 +38092,9 @@ type bintree struct { } var _bintree = &bintree{nil, map[string]*bintree{ - "bundle.js": {bundleJs, map[string]*bintree{}}, - "index.html": {indexHtml, map[string]*bintree{}}, + "bundle.js": {bundleJs, map[string]*bintree{}}, + "bundle.js.map": {bundleJsMap, map[string]*bintree{}}, + "index.html": {indexHtml, map[string]*bintree{}}, }} // RestoreAsset restores an asset under the given directory. diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintignore b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintignore new file mode 100644 index 00000000..565bf83e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintignore @@ -0,0 +1,3 @@ +node_modules/* #ignored by default +flow-typed/* +bundle.js diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintrc b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintrc index ab7a3a03..923d6f5d 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintrc +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.eslintrc @@ -16,71 +16,66 @@ // React syntax style mostly according to https://github.com/airbnb/javascript/tree/master/react { - 'env': { - 'browser': true, - 'node': true, - 'es6': true, + "env": { + "browser": true, + "node": true, + "es6": true }, - 'parser': 'babel-eslint', - 'parserOptions': { - 'sourceType': 'module', - 'ecmaVersion': 6, - 'ecmaFeatures': { - 'jsx': true, + "parser": "babel-eslint", + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 6, + "ecmaFeatures": { + "jsx": true } }, - 'extends': 'airbnb', - 'plugins': [ - 'flowtype', - 'react', + "extends": [ + "eslint:recommended", + "airbnb", + "plugin:flowtype/recommended", + "plugin:react/recommended" ], - 'rules': { - 'no-tabs': 'off', - 'indent': ['error', 'tab'], - 'react/jsx-indent': ['error', 'tab'], - 'react/jsx-indent-props': ['error', 'tab'], - 'react/prefer-stateless-function': 'off', - 'jsx-quotes': ['error', 'prefer-single'], - 'no-plusplus': 'off', - 'no-console': ['error', { allow: ['error'] }], - + "plugins": [ + "flowtype", + "react" + ], + "rules": { + "no-tabs": "off", + "indent": ["error", "tab"], + "react/jsx-indent": ["error", "tab"], + "react/jsx-indent-props": ["error", "tab"], + "react/prefer-stateless-function": "off", + "react/destructuring-assignment": ["error", "always", {"ignoreClassFields": true}], + "jsx-quotes": ["error", "prefer-single"], + "no-plusplus": "off", + "no-console": ["error", { "allow": ["error"] }], // Specifies the maximum length of a line. - 'max-len': ['warn', 120, 2, { - 'ignoreUrls': true, - 'ignoreComments': false, - 'ignoreRegExpLiterals': true, - 'ignoreStrings': true, - 'ignoreTemplateLiterals': true, + "max-len": ["warn", 120, 2, { + "ignoreUrls": true, + "ignoreComments": false, + "ignoreRegExpLiterals": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true }], // Enforces consistent spacing between keys and values in object literal properties. - 'key-spacing': ['error', {'align': { - 'beforeColon': false, - 'afterColon': true, - 'on': 'value' + "key-spacing": ["error", {"align": { + "beforeColon": false, + "afterColon": true, + "on": "value" }}], // Prohibits padding inside curly braces. - 'object-curly-spacing': ['error', 'never'], - 'no-use-before-define': 'off', // messageAPI - 'default-case': 'off', - - 'flowtype/boolean-style': ['error', 'boolean'], - 'flowtype/define-flow-type': 'warn', - 'flowtype/generic-spacing': ['error', 'never'], - 'flowtype/no-primitive-constructor-types': 'error', - 'flowtype/no-weak-types': 'error', - 'flowtype/object-type-delimiter': ['error', 'comma'], - 'flowtype/require-valid-file-annotation': 'error', - 'flowtype/semi': ['error', 'always'], - 'flowtype/space-after-type-colon': ['error', 'always'], - 'flowtype/space-before-generic-bracket': ['error', 'never'], - 'flowtype/space-before-type-colon': ['error', 'never'], - 'flowtype/union-intersection-spacing': ['error', 'always'], - 'flowtype/use-flow-type': 'warn', - 'flowtype/valid-syntax': 'warn', + "object-curly-spacing": ["error", "never"], + "no-use-before-define": "off", // message types + "default-case": "off" }, - 'settings': { - 'flowtype': { - 'onlyFilesWithFlowAnnotation': true, + "settings": { + "import/resolver": { + "node": { + "paths": ["components"] // import './components/Component' -> import 'Component' + } + }, + "flowtype": { + "onlyFilesWithFlowAnnotation": true } - }, + } } diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.flowconfig b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.flowconfig index 8051ae5d..9104d62a 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.flowconfig +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/.flowconfig @@ -7,3 +7,5 @@ node_modules/jss/flow-typed [options] include_warnings=true +module.system.node.resolve_dirname=node_modules +module.system.node.resolve_dirname=components diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx index ed2f411f..f2750ee3 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/common.jsx @@ -16,43 +16,46 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +import {faHome, faLink, faGlobeEurope, faTachometerAlt, faList} from '@fortawesome/free-solid-svg-icons'; +import {faCreditCard} from '@fortawesome/free-regular-svg-icons'; + type ProvidedMenuProp = {|title: string, icon: string|}; const menuSkeletons: Array<{|id: string, menu: ProvidedMenuProp|}> = [ { id: 'home', menu: { title: 'Home', - icon: 'home', + icon: faHome, }, }, { id: 'chain', menu: { title: 'Chain', - icon: 'link', + icon: faLink, }, }, { id: 'txpool', menu: { title: 'TxPool', - icon: 'credit-card', + icon: faCreditCard, }, }, { id: 'network', menu: { title: 'Network', - icon: 'globe', + icon: faGlobeEurope, }, }, { id: 'system', menu: { title: 'System', - icon: 'tachometer', + icon: faTachometerAlt, }, }, { id: 'logs', menu: { title: 'Logs', - icon: 'list', + icon: faList, }, }, ]; @@ -64,8 +67,26 @@ export const MENU: Map = new Map(menuSkeletons.map(({id, export const DURATION = 200; +export const chartStrokeWidth = 0.2; + export const styles = { light: { color: 'rgba(255, 255, 255, 0.54)', }, }; + +// unit contains the units for the bytePlotter. +export const unit = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi']; + +// simplifyBytes returns the simplified version of the given value followed by the unit. +export const simplifyBytes = (x: number) => { + let i = 0; + for (; x > 1024 && i < 8; i++) { + x /= 1024; + } + return x.toFixed(2).toString().concat(' ', unit[i], 'B'); +}; + +// hues contains predefined colors for gradient stop colors. +export const hues = ['#00FF00', '#FFFF00', '#FF7F00', '#FF0000']; +export const hueScale = [0, 2048, 102400, 2097152]; diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx index 1075346f..08da823c 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/ChartRow.jsx @@ -19,7 +19,7 @@ import React, {Component} from 'react'; import type {ChildrenArray} from 'react'; -import Grid from 'material-ui/Grid'; +import Grid from '@material-ui/core/Grid'; // styles contains the constant styles of the component. const styles = { @@ -33,7 +33,7 @@ const styles = { flex: 1, padding: 0, }, -} +}; export type Props = { children: ChildrenArray>, diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx index f597c1ca..52d005e5 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/CustomTooltip.jsx @@ -18,8 +18,8 @@ import React, {Component} from 'react'; -import Typography from 'material-ui/Typography'; -import {styles} from '../common'; +import Typography from '@material-ui/core/Typography'; +import {styles, simplifyBytes} from '../common'; // multiplier multiplies a number by another. export const multiplier = (by: number = 1) => (x: number) => x * by; @@ -37,18 +37,6 @@ export const percentPlotter = (text: string, mapper: (T => T) = multiplier(1) ); }; -// unit contains the units for the bytePlotter. -const unit = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi']; - -// simplifyBytes returns the simplified version of the given value followed by the unit. -const simplifyBytes = (x: number) => { - let i = 0; - for (; x > 1024 && i < 8; i++) { - x /= 1024; - } - return x.toFixed(2).toString().concat(' ', unit[i], 'B'); -}; - // bytePlotter renders a tooltip, which displays the payload as a byte value. export const bytePlotter = (text: string, mapper: (T => T) = multiplier(1)) => (payload: T) => { const p = mapper(payload); @@ -70,7 +58,8 @@ export const bytePerSecPlotter = (text: string, mapper: (T => T) = multiplier } return ( - {text} {simplifyBytes(p)}/s + {text} + {simplifyBytes(p)}/s ); }; diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Dashboard.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Dashboard.jsx index 63c2186a..944d5009 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Dashboard.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Dashboard.jsx @@ -17,14 +17,16 @@ // along with the go-ethereum library. If not, see . import React, {Component} from 'react'; +import {hot} from 'react-hot-loader'; -import withStyles from 'material-ui/styles/withStyles'; +import withStyles from '@material-ui/core/styles/withStyles'; -import Header from './Header'; -import Body from './Body'; +import Header from 'Header'; +import Body from 'Body'; +import {inserter as logInserter, SAME} from 'Logs'; +import {inserter as peerInserter} from 'Network'; import {MENU} from '../common'; import type {Content} from '../types/content'; -import {inserter as logInserter} from './Logs'; // deepUpdate updates an object corresponding to the given update data, which has // the shape of the same structure as the original object. updater also has the same @@ -37,7 +39,6 @@ import {inserter as logInserter} from './Logs'; // of the update. const deepUpdate = (updater: Object, update: Object, prev: Object): $Shape => { if (typeof update === 'undefined') { - // TODO (kurkomisi): originally this was deep copy, investigate it. return prev; } if (typeof updater === 'function') { @@ -88,8 +89,13 @@ const defaultContent: () => Content = () => ({ home: {}, chain: {}, txpool: {}, - network: {}, - system: { + network: { + peers: { + bundles: {}, + }, + diff: [], + }, + system: { activeMemory: [], virtualMemory: [], networkIngress: [], @@ -103,8 +109,8 @@ const defaultContent: () => Content = () => ({ chunks: [], endTop: false, endBottom: true, - topChanged: 0, - bottomChanged: 0, + topChanged: SAME, + bottomChanged: SAME, }, }); @@ -119,7 +125,7 @@ const updaters = { home: null, chain: null, txpool: null, - network: null, + network: peerInserter(200), system: { activeMemory: appender(200), virtualMemory: appender(200), @@ -186,8 +192,8 @@ class Dashboard extends Component { // reconnect establishes a websocket connection with the server, listens for incoming messages // and tries to reconnect on connection loss. reconnect = () => { - // PROD is defined by webpack. - const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${PROD ? window.location.host : 'localhost:8080'}/api`); + const host = process.env.NODE_ENV === 'production' ? window.location.host : 'localhost:8080'; + const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${host}/api`); server.onopen = () => { this.setState({content: defaultContent(), shouldUpdate: {}, server}); }; @@ -249,4 +255,4 @@ class Dashboard extends Component { } } -export default withStyles(themeStyles)(Dashboard); +export default hot(module)(withStyles(themeStyles)(Dashboard)); diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Footer.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Footer.jsx index 20830cbb..a5cab08a 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Footer.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Footer.jsx @@ -18,14 +18,19 @@ import React, {Component} from 'react'; -import withStyles from 'material-ui/styles/withStyles'; -import Typography from 'material-ui/Typography'; -import Grid from 'material-ui/Grid'; -import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts'; +import withStyles from '@material-ui/core/styles/withStyles'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import ResponsiveContainer from 'recharts/es6/component/ResponsiveContainer'; +import AreaChart from 'recharts/es6/chart/AreaChart'; +import Area from 'recharts/es6/cartesian/Area'; +import ReferenceLine from 'recharts/es6/cartesian/ReferenceLine'; +import Label from 'recharts/es6/component/Label'; +import Tooltip from 'recharts/es6/component/Tooltip'; -import ChartRow from './ChartRow'; -import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip'; -import {styles as commonStyles} from '../common'; +import ChartRow from 'ChartRow'; +import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from 'CustomTooltip'; +import {chartStrokeWidth, styles as commonStyles} from '../common'; import type {General, System} from '../types/content'; const FOOTER_SYNC_ID = 'footerSyncId'; @@ -38,6 +43,15 @@ const TRAFFIC = 'traffic'; const TOP = 'Top'; const BOTTOM = 'Bottom'; +const cpuLabelTop = 'Process load'; +const cpuLabelBottom = 'System load'; +const memoryLabelTop = 'Active memory'; +const memoryLabelBottom = 'Virtual memory'; +const diskLabelTop = 'Disk read'; +const diskLabelBottom = 'Disk write'; +const trafficLabelTop = 'Download'; +const trafficLabelBottom = 'Upload'; + // styles contains the constant styles of the component. const styles = { footer: { @@ -53,6 +67,10 @@ const styles = { height: '100%', width: '99%', }, + link: { + color: 'inherit', + textDecoration: 'none', + }, }; // themeStyles returns the styles generated from the theme for the component. @@ -73,18 +91,23 @@ export type Props = { shouldUpdate: Object, }; +type State = {}; + // Footer renders the footer of the dashboard. -class Footer extends Component { - shouldComponentUpdate(nextProps) { +class Footer extends Component { + shouldComponentUpdate(nextProps: Readonly, nextState: Readonly, nextContext: any) { return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined'; } // halfHeightChart renders an area chart with half of the height of its parent. - halfHeightChart = (chartProps, tooltip, areaProps) => ( + halfHeightChart = (chartProps, tooltip, areaProps, label, position) => ( - + {!tooltip || (} />)} - + + + ); @@ -111,6 +134,8 @@ class Footer extends Component { }, topChart.tooltip, {dataKey: topKey, stroke: topColor, fill: topColor}, + topChart.label, + 'insideBottomLeft', )} {this.halfHeightChart( { @@ -120,6 +145,8 @@ class Footer extends Component { }, bottomChart.tooltip, {dataKey: bottomKey, stroke: bottomColor, fill: bottomColor}, + bottomChart.label, + 'insideTopLeft', )}
); @@ -135,37 +162,42 @@ class Footer extends Component { {this.doubleChart( FOOTER_SYNC_ID, CPU, - {data: system.processCPU, tooltip: percentPlotter('Process load')}, - {data: system.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))}, + {data: system.processCPU, tooltip: percentPlotter(cpuLabelTop), label: cpuLabelTop}, + {data: system.systemCPU, tooltip: percentPlotter(cpuLabelBottom, multiplier(-1)), label: cpuLabelBottom}, )} {this.doubleChart( FOOTER_SYNC_ID, MEMORY, - {data: system.activeMemory, tooltip: bytePlotter('Active memory')}, - {data: system.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))}, + {data: system.activeMemory, tooltip: bytePlotter(memoryLabelTop), label: memoryLabelTop}, + {data: system.virtualMemory, tooltip: bytePlotter(memoryLabelBottom, multiplier(-1)), label: memoryLabelBottom}, )} {this.doubleChart( FOOTER_SYNC_ID, DISK, - {data: system.diskRead, tooltip: bytePerSecPlotter('Disk read')}, - {data: system.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))}, + {data: system.diskRead, tooltip: bytePerSecPlotter(diskLabelTop), label: diskLabelTop}, + {data: system.diskWrite, tooltip: bytePerSecPlotter(diskLabelBottom, multiplier(-1)), label: diskLabelBottom}, )} {this.doubleChart( FOOTER_SYNC_ID, TRAFFIC, - {data: system.networkIngress, tooltip: bytePerSecPlotter('Download')}, - {data: system.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))}, + {data: system.networkIngress, tooltip: bytePerSecPlotter(trafficLabelTop), label: trafficLabelTop}, + {data: system.networkEgress, tooltip: bytePerSecPlotter(trafficLabelBottom, multiplier(-1)), label: trafficLabelBottom}, )} - + Geth {general.version} {general.commit && ( {'Commit '} -
+ {general.commit.substring(0, 8)} diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Header.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Header.jsx index 43bd2bed..063e82d0 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Header.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Header.jsx @@ -18,13 +18,13 @@ import React, {Component} from 'react'; -import withStyles from 'material-ui/styles/withStyles'; -import AppBar from 'material-ui/AppBar'; -import Toolbar from 'material-ui/Toolbar'; -import IconButton from 'material-ui/IconButton'; -import Icon from 'material-ui/Icon'; -import MenuIcon from 'material-ui-icons/Menu'; -import Typography from 'material-ui/Typography'; +import withStyles from '@material-ui/core/styles/withStyles'; +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import IconButton from '@material-ui/core/IconButton'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faBars} from '@fortawesome/free-solid-svg-icons'; +import Typography from '@material-ui/core/Typography'; // styles contains the constant styles of the component. const styles = { @@ -67,9 +67,7 @@ class Header extends Component { - - - + Go Ethereum Dashboard diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Logs.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Logs.jsx index 57d6328d..3359287d 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Logs.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Logs.jsx @@ -18,7 +18,8 @@ import React, {Component} from 'react'; -import List, {ListItem} from 'material-ui/List'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; import escapeHtml from 'escape-html'; import type {Record, Content, LogsMessage, Logs as LogsType} from '../types/content'; @@ -104,9 +105,9 @@ const createChunk = (records: Array) => { // ADDED, SAME and REMOVED are used to track the change of the log chunk array. // The scroll position is set using these values. -const ADDED = 1; -const SAME = 0; -const REMOVED = -1; +export const ADDED = 1; +export const SAME = 0; +export const REMOVED = -1; // inserter is a state updater function for the main component, which inserts the new log chunk into the chunk array. // limit is the maximum length of the chunk array, used in order to prevent the browser from OOM. @@ -166,7 +167,7 @@ export const inserter = (limit: number) => (update: LogsMessage, prev: LogsType) // styles contains the constant styles of the component. const styles = { logListItem: { - padding: 0, + padding: 0, lineHeight: 1.231, }, logChunk: { @@ -251,15 +252,15 @@ class Logs extends Component { // atBottom checks if the scroll position it at the bottom of the container. atBottom = () => { const {container} = this.props; - return container.scrollHeight - container.scrollTop <= - container.clientHeight + container.scrollHeight * requestBand; + return container.scrollHeight - container.scrollTop + <= container.clientHeight + container.scrollHeight * requestBand; }; // beforeUpdate is called by the parent component, saves the previous scroll position // and the height of the first log chunk, which can be deleted during the insertion. beforeUpdate = () => { let firstHeight = 0; - let chunkList = this.content.children[1]; + const chunkList = this.content.children[1]; if (chunkList && chunkList.children[0]) { firstHeight = chunkList.children[0].clientHeight; } diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Main.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Main.jsx index 0018aaf7..5bb13abd 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Main.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Main.jsx @@ -18,11 +18,12 @@ import React, {Component} from 'react'; -import withStyles from 'material-ui/styles/withStyles'; +import withStyles from '@material-ui/core/styles/withStyles'; +import Network from 'Network'; +import Logs from 'Logs'; +import Footer from 'Footer'; import {MENU} from '../common'; -import Logs from './Logs'; -import Footer from './Footer'; import type {Content} from '../types/content'; // styles contains the constant styles of the component. @@ -33,7 +34,7 @@ const styles = { width: '100%', }, content: { - flex: 1, + flex: 1, overflow: 'auto', }, }; @@ -54,21 +55,16 @@ export type Props = { send: string => void, }; +type State = {}; + // Main renders the chosen content. -class Main extends Component { +class Main extends Component { constructor(props) { super(props); this.container = React.createRef(); this.content = React.createRef(); } - getSnapshotBeforeUpdate() { - if (this.content && typeof this.content.beforeUpdate === 'function') { - return this.content.beforeUpdate(); - } - return null; - } - componentDidUpdate(prevProps, prevState, snapshot) { if (this.content && typeof this.content.didUpdate === 'function') { this.content.didUpdate(prevProps, prevState, snapshot); @@ -81,6 +77,13 @@ class Main extends Component { } }; + getSnapshotBeforeUpdate(prevProps: Readonly

, prevState: Readonly) { + if (this.content && typeof this.content.beforeUpdate === 'function') { + return this.content.beforeUpdate(); + } + return null; + } + render() { const { classes, active, content, shouldUpdate, @@ -89,9 +92,20 @@ class Main extends Component { let children = null; switch (active) { case MENU.get('home').id: + children =

Work in progress.
; + break; case MENU.get('chain').id: + children =
Work in progress.
; + break; case MENU.get('txpool').id: + children =
Work in progress.
; + break; case MENU.get('network').id: + children = ; + break; case MENU.get('system').id: children =
Work in progress.
; break; diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Network.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Network.jsx new file mode 100644 index 00000000..3a52892e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/Network.jsx @@ -0,0 +1,529 @@ +// @flow + +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +import React, {Component} from 'react'; + +import Table from '@material-ui/core/Table'; +import TableHead from '@material-ui/core/TableHead'; +import TableBody from '@material-ui/core/TableBody'; +import TableRow from '@material-ui/core/TableRow'; +import TableCell from '@material-ui/core/TableCell'; +import Grid from '@material-ui/core/Grid/Grid'; +import Typography from '@material-ui/core/Typography'; +import {AreaChart, Area, Tooltip, YAxis} from 'recharts'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCircle as fasCircle} from '@fortawesome/free-solid-svg-icons'; +import {faCircle as farCircle} from '@fortawesome/free-regular-svg-icons'; +import convert from 'color-convert'; + +import CustomTooltip, {bytePlotter, multiplier} from 'CustomTooltip'; +import type {Network as NetworkType, PeerEvent} from '../types/content'; +import {styles as commonStyles, chartStrokeWidth, hues, hueScale} from '../common'; + +// Peer chart dimensions. +const trafficChartHeight = 18; +const trafficChartWidth = 400; + +// setMaxIngress adjusts the peer chart's gradient values based on the given value. +const setMaxIngress = (peer, value) => { + peer.maxIngress = value; + peer.ingressGradient = []; + peer.ingressGradient.push({offset: hueScale[0], color: hues[0]}); + let i = 1; + for (; i < hues.length && value > hueScale[i]; i++) { + peer.ingressGradient.push({offset: Math.floor(hueScale[i] * 100 / value), color: hues[i]}); + } + i--; + if (i < hues.length - 1) { + // Usually the maximum value gets between two points on the predefined + // color scale (e.g. 123KB is somewhere between 100KB (#FFFF00) and + // 1MB (#FF0000)), and the charts need to be comparable by the colors, + // so we have to calculate the last hue using the maximum value and the + // surrounding hues in order to avoid the uniformity of the top colors + // on the charts. For this reason the two hues are translated into the + // CIELAB color space, and the top color will be their weighted average + // (CIELAB is perceptually uniform, meaning that any point on the line + // between two pure color points is also a pure color, so the weighted + // average will not lose from the saturation). + // + // In case the maximum value is greater than the biggest predefined + // scale value, the top of the chart will have uniform color. + const lastHue = convert.hex.lab(hues[i]); + const proportion = (value - hueScale[i]) * 100 / (hueScale[i + 1] - hueScale[i]); + convert.hex.lab(hues[i + 1]).forEach((val, j) => { + lastHue[j] = (lastHue[j] * proportion + val * (100 - proportion)) / 100; + }); + peer.ingressGradient.push({offset: 100, color: `#${convert.lab.hex(lastHue)}`}); + } +}; + +// setMaxEgress adjusts the peer chart's gradient values based on the given value. +// In case of the egress the chart is upside down, so the gradients need to be +// calculated inversely compared to the ingress. +const setMaxEgress = (peer, value) => { + peer.maxEgress = value; + peer.egressGradient = []; + peer.egressGradient.push({offset: 100 - hueScale[0], color: hues[0]}); + let i = 1; + for (; i < hues.length && value > hueScale[i]; i++) { + peer.egressGradient.unshift({offset: 100 - Math.floor(hueScale[i] * 100 / value), color: hues[i]}); + } + i--; + if (i < hues.length - 1) { + // Calculate the last hue. + const lastHue = convert.hex.lab(hues[i]); + const proportion = (value - hueScale[i]) * 100 / (hueScale[i + 1] - hueScale[i]); + convert.hex.lab(hues[i + 1]).forEach((val, j) => { + lastHue[j] = (lastHue[j] * proportion + val * (100 - proportion)) / 100; + }); + peer.egressGradient.unshift({offset: 0, color: `#${convert.lab.hex(lastHue)}`}); + } +}; + + +// setIngressChartAttributes searches for the maximum value of the ingress +// samples, and adjusts the peer chart's gradient values accordingly. +const setIngressChartAttributes = (peer) => { + let max = 0; + peer.ingress.forEach(({value}) => { + if (value > max) { + max = value; + } + }); + setMaxIngress(peer, max); +}; + +// setEgressChartAttributes searches for the maximum value of the egress +// samples, and adjusts the peer chart's gradient values accordingly. +const setEgressChartAttributes = (peer) => { + let max = 0; + peer.egress.forEach(({value}) => { + if (value > max) { + max = value; + } + }); + setMaxEgress(peer, max); +}; + +// inserter is a state updater function for the main component, which handles the peers. +export const inserter = (sampleLimit: number) => (update: NetworkType, prev: NetworkType) => { + // The first message contains the metered peer history. + if (update.peers && update.peers.bundles) { + prev.peers = update.peers; + Object.values(prev.peers.bundles).forEach((bundle) => { + if (bundle.knownPeers) { + Object.values(bundle.knownPeers).forEach((peer) => { + if (!peer.maxIngress) { + setIngressChartAttributes(peer); + } + if (!peer.maxEgress) { + setEgressChartAttributes(peer); + } + }); + } + }); + } + if (Array.isArray(update.diff)) { + update.diff.forEach((event: PeerEvent) => { + if (!event.ip) { + console.error('Peer event without IP', event); + return; + } + switch (event.remove) { + case 'bundle': { + delete prev.peers.bundles[event.ip]; + return; + } + case 'known': { + if (!event.id) { + console.error('Remove known peer event without ID', event.ip); + return; + } + const bundle = prev.peers.bundles[event.ip]; + if (!bundle || !bundle.knownPeers || !bundle.knownPeers[event.id]) { + console.error('No known peer to remove', event.ip, event.id); + return; + } + delete bundle.knownPeers[event.id]; + return; + } + case 'attempt': { + const bundle = prev.peers.bundles[event.ip]; + if (!bundle || !Array.isArray(bundle.attempts) || bundle.attempts.length < 1) { + console.error('No unknown peer to remove', event.ip); + return; + } + bundle.attempts.splice(0, 1); + return; + } + } + if (!prev.peers.bundles[event.ip]) { + prev.peers.bundles[event.ip] = { + location: { + country: '', + city: '', + latitude: 0, + longitude: 0, + }, + knownPeers: {}, + attempts: [], + }; + } + const bundle = prev.peers.bundles[event.ip]; + if (event.location) { + bundle.location = event.location; + return; + } + if (!event.id) { + if (!bundle.attempts) { + bundle.attempts = []; + } + bundle.attempts.push({ + connected: event.connected, + disconnected: event.disconnected, + }); + return; + } + if (!bundle.knownPeers) { + bundle.knownPeers = {}; + } + if (!bundle.knownPeers[event.id]) { + bundle.knownPeers[event.id] = { + connected: [], + disconnected: [], + ingress: [], + egress: [], + active: false, + }; + } + const peer = bundle.knownPeers[event.id]; + if (!peer.maxIngress) { + setIngressChartAttributes(peer); + } + if (!peer.maxEgress) { + setEgressChartAttributes(peer); + } + if (event.connected) { + if (!peer.connected) { + console.warn('peer.connected should exist'); + peer.connected = []; + } + peer.connected.push(event.connected); + } + if (event.disconnected) { + if (!peer.disconnected) { + console.warn('peer.disconnected should exist'); + peer.disconnected = []; + } + peer.disconnected.push(event.disconnected); + } + switch (event.activity) { + case 'active': + peer.active = true; + break; + case 'inactive': + peer.active = false; + break; + } + if (Array.isArray(event.ingress) && Array.isArray(event.egress)) { + if (event.ingress.length !== event.egress.length) { + console.error('Different traffic sample length', event); + return; + } + // Check if there is a new maximum value, and reset the colors in case. + let maxIngress = peer.maxIngress; + event.ingress.forEach(({value}) => { + if (value > maxIngress) { + maxIngress = value; + } + }); + if (maxIngress > peer.maxIngress) { + setMaxIngress(peer, maxIngress); + } + // Push the new values. + peer.ingress.splice(peer.ingress.length, 0, ...event.ingress); + const ingressDiff = peer.ingress.length - sampleLimit; + if (ingressDiff > 0) { + // Check if the maximum value is in the beginning. + let i = 0; + while (i < ingressDiff && peer.ingress[i].value < peer.maxIngress) { + i++; + } + // Remove the old values from the beginning. + peer.ingress.splice(0, ingressDiff); + if (i < ingressDiff) { + // Reset the colors if the maximum value leaves the chart. + setIngressChartAttributes(peer); + } + } + // Check if there is a new maximum value, and reset the colors in case. + let maxEgress = peer.maxEgress; + event.egress.forEach(({value}) => { + if (value > maxEgress) { + maxEgress = value; + } + }); + if (maxEgress > peer.maxEgress) { + setMaxEgress(peer, maxEgress); + } + // Push the new values. + peer.egress.splice(peer.egress.length, 0, ...event.egress); + const egressDiff = peer.egress.length - sampleLimit; + if (egressDiff > 0) { + // Check if the maximum value is in the beginning. + let i = 0; + while (i < egressDiff && peer.egress[i].value < peer.maxEgress) { + i++; + } + // Remove the old values from the beginning. + peer.egress.splice(0, egressDiff); + if (i < egressDiff) { + // Reset the colors if the maximum value leaves the chart. + setEgressChartAttributes(peer); + } + } + } + }); + } + return prev; +}; + +// styles contains the constant styles of the component. +const styles = { + tableHead: { + height: 'auto', + }, + tableRow: { + height: 'auto', + }, + tableCell: { + paddingTop: 0, + paddingRight: 5, + paddingBottom: 0, + paddingLeft: 5, + border: 'none', + }, +}; + +export type Props = { + container: Object, + content: NetworkType, + shouldUpdate: Object, +}; + +type State = {}; + +// Network renders the network page. +class Network extends Component { + componentDidMount() { + const {container} = this.props; + if (typeof container === 'undefined') { + return; + } + container.scrollTop = 0; + } + + formatTime = (t: string) => { + const time = new Date(t); + if (isNaN(time)) { + return ''; + } + const month = `0${time.getMonth() + 1}`.slice(-2); + const date = `0${time.getDate()}`.slice(-2); + const hours = `0${time.getHours()}`.slice(-2); + const minutes = `0${time.getMinutes()}`.slice(-2); + const seconds = `0${time.getSeconds()}`.slice(-2); + return `${month}/${date}/${hours}:${minutes}:${seconds}`; + }; + + copyToClipboard = (id) => (event) => { + event.preventDefault(); + navigator.clipboard.writeText(id).then(() => {}, () => { + console.error("Failed to copy node id", id); + }); + }; + + peerTableRow = (ip, id, bundle, peer) => { + const ingressValues = peer.ingress.map(({value}) => ({ingress: value || 0.001})); + const egressValues = peer.egress.map(({value}) => ({egress: -value || -0.001})); + + return ( + + + {peer.active + ? + : + } + + + {id.substring(0, 10)} + + + {bundle.location ? (() => { + const l = bundle.location; + return `${l.country ? l.country : ''}${l.city ? `/${l.city}` : ''}`; + })() : ''} + + + + + + {peer.ingressGradient + && peer.ingressGradient.map(({offset, color}, i) => ( + + ))} + + + } /> + Math.max(dataMax, 0)]} /> + + + + + + {peer.egressGradient + && peer.egressGradient.map(({offset, color}, i) => ( + + ))} + + + } /> + Math.min(dataMin, 0), -0.001]} /> + + + + + ); + }; + + render() { + return ( + + + + + + + Node ID + Location + Traffic + + + + {Object.entries(this.props.content.peers.bundles).map(([ip, bundle]) => { + if (!bundle.knownPeers || Object.keys(bundle.knownPeers).length < 1) { + return null; + } + return Object.entries(bundle.knownPeers).map(([id, peer]) => { + if (peer.active === false) { + return null; + } + return this.peerTableRow(ip, id, bundle, peer); + }); + })} + + + {Object.entries(this.props.content.peers.bundles).map(([ip, bundle]) => { + if (!bundle.knownPeers || Object.keys(bundle.knownPeers).length < 1) { + return null; + } + return Object.entries(bundle.knownPeers).map(([id, peer]) => { + if (peer.active === true) { + return null; + } + return this.peerTableRow(ip, id, bundle, peer); + }); + })} + +
+
+ + + Connection attempts + + + + + IP + Location + Nr + + + + {Object.entries(this.props.content.peers.bundles).map(([ip, bundle]) => { + if (!bundle.attempts || bundle.attempts.length < 1) { + return null; + } + return ( + + {ip} + + {bundle.location ? (() => { + const l = bundle.location; + return `${l.country ? l.country : ''}${l.city ? `/${l.city}` : ''}`; + })() : ''} + + + {Object.values(bundle.attempts).length} + + + ); + })} + +
+
+
+ ); + } +} + +export default Network; diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/SideBar.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/SideBar.jsx index 463d6cb4..301e458d 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/SideBar.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/components/SideBar.jsx @@ -18,11 +18,14 @@ import React, {Component} from 'react'; -import withStyles from 'material-ui/styles/withStyles'; -import List, {ListItem, ListItemIcon, ListItemText} from 'material-ui/List'; -import Icon from 'material-ui/Icon'; +import withStyles from '@material-ui/core/styles/withStyles'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import Icon from '@material-ui/core/Icon'; import Transition from 'react-transition-group/Transition'; -import {Icon as FontAwesome} from 'react-fa'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {MENU, DURATION} from '../common'; @@ -48,6 +51,7 @@ const themeStyles = theme => ({ }, icon: { fontSize: theme.spacing.unit * 3, + overflow: 'unset', }, }); @@ -57,9 +61,11 @@ export type Props = { changeContent: string => void, }; +type State = {} + // SideBar renders the sidebar of the dashboard. -class SideBar extends Component { - shouldComponentUpdate(nextProps) { +class SideBar extends Component { + shouldComponentUpdate(nextProps: Readonly, nextState: Readonly, nextContext: any) { return nextProps.opened !== this.props.opened; } @@ -78,7 +84,7 @@ class SideBar extends Component { - + content + .replace(/src.*url(?!.*url.*(\.eot)).*(\.eot)[^;]*;/, '') + .replace(/url(?!.*url.*(\.eot)).*(\.eot)[^,]*,/, '') + .replace(/url(?!.*url.*(\.ttf)).*(\.ttf)[^,]*,/, '') + .replace(/,[^,]*url(?!.*url.*(\.svg)).*(\.svg)[^;]*;/, ';'); diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.html b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.html index 1211d152..fbfb7f00 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.html +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.html @@ -21,6 +21,6 @@
- + diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.jsx index 4ee567b0..a08911aa 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/index.jsx @@ -19,12 +19,15 @@ import React from 'react'; import {render} from 'react-dom'; -import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; -import createMuiTheme from 'material-ui/styles/createMuiTheme'; +import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider'; +import createMuiTheme from '@material-ui/core/styles/createMuiTheme'; import Dashboard from './components/Dashboard'; const theme: Object = createMuiTheme({ + // typography: { + // useNextVariants: true, + // }, palette: { type: 'dark', }, diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/package.json b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/package.json index fb1a68e5..626ed288 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/package.json +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/package.json @@ -1,48 +1,65 @@ { + "private": true, "dependencies": { - "babel-core": "^6.26.0", - "babel-eslint": "^8.2.1", - "babel-loader": "^7.1.2", - "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-flow-strip-types": "^6.22.0", - "babel-plugin-transform-runtime": "^6.23.0", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.24.1", - "babel-preset-stage-0": "^6.24.1", - "babel-runtime": "^6.26.0", - "classnames": "^2.2.5", - "css-loader": "^0.28.9", + "@babel/core": "7.3.4", + "@babel/plugin-proposal-class-properties": "7.3.4", + "@babel/plugin-proposal-function-bind": "7.2.0", + "@babel/plugin-transform-flow-strip-types": "7.3.4", + "@babel/preset-env": "7.3.4", + "@babel/preset-react": "^7.0.0", + "@babel/preset-stage-0": "^7.0.0", + "@fortawesome/fontawesome-free-regular": "^5.0.13", + "@fortawesome/fontawesome-svg-core": "^1.2.15", + "@fortawesome/free-regular-svg-icons": "^5.7.2", + "@fortawesome/free-solid-svg-icons": "^5.7.2", + "@fortawesome/react-fontawesome": "^0.1.4", + "@material-ui/core": "3.9.2", + "@material-ui/icons": "3.0.2", + "babel-eslint": "10.0.1", + "babel-loader": "8.0.5", + "classnames": "^2.2.6", + "color-convert": "^2.0.0", + "css-loader": "2.1.1", "escape-html": "^1.0.3", - "eslint": "^4.16.0", - "eslint-config-airbnb": "^16.1.0", - "eslint-loader": "^2.0.0", - "eslint-plugin-flowtype": "^2.41.0", - "eslint-plugin-import": "^2.8.0", - "eslint-plugin-jsx-a11y": "^6.0.3", - "eslint-plugin-react": "^7.5.1", - "file-loader": "^1.1.6", - "flow-bin": "^0.63.1", - "flow-bin-loader": "^1.0.2", - "flow-typed": "^2.2.3", - "material-ui": "^1.0.0-beta.30", - "material-ui-icons": "^1.0.0-beta.17", + "eslint": "5.15.1", + "eslint-config-airbnb": "^17.0.0", + "eslint-loader": "2.1.2", + "eslint-plugin-flowtype": "3.4.2", + "eslint-plugin-import": "2.16.0", + "eslint-plugin-jsx-a11y": "6.2.1", + "eslint-plugin-node": "8.0.1", + "eslint-plugin-promise": "4.0.1", + "eslint-plugin-react": "7.12.4", + "file-loader": "3.0.1", + "flow-bin": "0.94.0", + "flow-bin-loader": "^1.0.3", + "flow-typed": "^2.5.1", + "js-beautify": "1.9.0", "path": "^0.12.7", - "react": "^16.2.0", - "react-dom": "^16.2.0", - "react-fa": "^5.0.0", - "react-transition-group": "^2.2.1", - "recharts": "^1.0.0-beta.9", - "style-loader": "^0.19.1", + "react": "16.8.4", + "react-dom": "16.8.4", + "react-hot-loader": "4.8.0", + "react-transition-group": "2.6.1", + "recharts": "1.5.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "^1.2.3", "url": "^0.11.0", - "url-loader": "^0.6.2", - "webpack": "^3.10.0", - "webpack-dev-server": "^2.11.1" + "url-loader": "1.1.2", + "webpack": "4.29.6", + "webpack-cli": "3.2.3", + "webpack-dashboard": "3.0.0", + "webpack-dev-server": "3.2.1", + "webpack-merge": "4.2.1" }, "scripts": { - "build": "NODE_ENV=production webpack", - "stats": "webpack --profile --json > stats.json", - "dev": "webpack-dev-server --port 8081", - "flow": "flow-typed install" - } + "build": "webpack --config webpack.config.prod.js", + "stats": "webpack --config webpack.config.prod.js --profile --json > stats.json", + "dev": "webpack-dev-server --open --config webpack.config.dev.js", + "dash": "webpack-dashboard -- yarn dev", + "install-flow": "flow-typed install", + "flow": "flow status --show-all-errors", + "eslint": "eslint **/*" + }, + "sideEffects": false, + "license": "LGPL-3.0-or-later" } diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/types/content.jsx b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/types/content.jsx index ff82c357..3086d442 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/types/content.jsx +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/types/content.jsx @@ -29,7 +29,6 @@ export type Content = { export type ChartEntries = Array; export type ChartEntry = { - time: Date, value: number, }; @@ -51,7 +50,50 @@ export type TxPool = { }; export type Network = { - /* TODO (kurkomisi) */ + peers: Peers, + diff: Array +}; + +export type PeerEvent = { + ip: string, + id: string, + remove: string, + location: GeoLocation, + connected: Date, + disconnected: Date, + ingress: ChartEntries, + egress: ChartEntries, + activity: string, +}; + +export type Peers = { + bundles: {[string]: PeerBundle}, +}; + +export type PeerBundle = { + location: GeoLocation, + knownPeers: {[string]: KnownPeer}, + attempts: Array, +}; + +export type KnownPeer = { + connected: Array, + disconnected: Array, + ingress: Array, + egress: Array, + active: boolean, +}; + +export type UnknownPeer = { + connected: Date, + disconnected: Date, +}; + +export type GeoLocation = { + country: string, + city: string, + latitude: number, + longitude: number, }; export type System = { diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.js b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.common.js similarity index 58% rename from vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.js rename to vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.common.js index f58d35ad..73ca9049 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.js +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.common.js @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,28 +14,25 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -const webpack = require('webpack'); const path = require('path'); module.exports = { + target: 'web', + entry: { + bundle: './index', + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, ''), + sourceMapFilename: '[file].map', + }, resolve: { + modules: [ + 'node_modules', + path.resolve(__dirname, 'components'), // import './components/Component' -> import 'Component' + ], extensions: ['.js', '.jsx'], }, - entry: './index', - output: { - path: path.resolve(__dirname, ''), - filename: 'bundle.js', - }, - plugins: [ - new webpack.optimize.UglifyJsPlugin({ - comments: false, - mangle: false, - beautify: true, - }), - new webpack.DefinePlugin({ - PROD: process.env.NODE_ENV === 'production', - }), - ], module: { rules: [ { @@ -45,27 +42,38 @@ module.exports = { { loader: 'babel-loader', options: { - plugins: [ // order: from top to bottom - // 'transform-decorators-legacy', // @withStyles, @withTheme - 'transform-class-properties', // static defaultProps - 'transform-flow-strip-types', - ], presets: [ // order: from bottom to top - 'env', - 'react', - 'stage-0', + '@babel/env', + '@babel/react', + ], + plugins: [ // order: from top to bottom + '@babel/proposal-function-bind', // instead of stage 0 + '@babel/proposal-class-properties', // static defaultProps + '@babel/transform-flow-strip-types', + 'react-hot-loader/babel', ], }, }, - // 'eslint-loader', // show errors not only in the editor, but also in the console + // 'eslint-loader', // show errors in the console ], }, { - test: /font-awesome\.css$/, - use: [ - 'style-loader', - 'css-loader', - path.resolve(__dirname, './fa-only-woff-loader.js'), + test: /\.css$/, + oneOf: [ + { + test: /font-awesome/, + use: [ + 'style-loader', + 'css-loader', + path.resolve(__dirname, './fa-only-woff-loader.js'), + ], + }, + { + use: [ + 'style-loader', + 'css-loader', + ], + }, ], }, { diff --git a/vendor/github.com/ethereum/go-ethereum/core/rawdb/interfaces.go b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.dev.js similarity index 63% rename from vendor/github.com/ethereum/go-ethereum/core/rawdb/interfaces.go rename to vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.dev.js index 3bdf5512..2f00e0da 100644 --- a/vendor/github.com/ethereum/go-ethereum/core/rawdb/interfaces.go +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.dev.js @@ -14,20 +14,22 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package rawdb +const webpack = require('webpack'); +const merge = require('webpack-merge'); +const WebpackDashboard = require('webpack-dashboard/plugin'); +const common = require('./webpack.config.common.js'); -// DatabaseReader wraps the Has and Get method of a backing data store. -type DatabaseReader interface { - Has(key []byte) (bool, error) - Get(key []byte) ([]byte, error) -} - -// DatabaseWriter wraps the Put method of a backing data store. -type DatabaseWriter interface { - Put(key []byte, value []byte) error -} - -// DatabaseDeleter wraps the Delete method of a backing data store. -type DatabaseDeleter interface { - Delete(key []byte) error -} +module.exports = merge(common, { + mode: 'development', + plugins: [ + new WebpackDashboard(), + new webpack.HotModuleReplacementPlugin(), + ], + // devtool: 'eval', + devtool: 'source-map', + devServer: { + port: 8081, + hot: true, + compress: true, + }, +}); diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/utils_test.go b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.prod.js similarity index 53% rename from vendor/github.com/ethereum/go-ethereum/rpc/utils_test.go rename to vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.prod.js index e0e063f6..f6d29c36 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/utils_test.go +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/webpack.config.prod.js @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,30 +14,28 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package rpc +const TerserPlugin = require('terser-webpack-plugin'); +const merge = require('webpack-merge'); +const common = require('./webpack.config.common.js'); -import ( - "strings" - "testing" -) - -func TestNewID(t *testing.T) { - hexchars := "0123456789ABCDEFabcdef" - for i := 0; i < 100; i++ { - id := string(NewID()) - if !strings.HasPrefix(id, "0x") { - t.Fatalf("invalid ID prefix, want '0x...', got %s", id) - } - - id = id[2:] - if len(id) == 0 || len(id) > 32 { - t.Fatalf("invalid ID length, want len(id) > 0 && len(id) <= 32), got %d", len(id)) - } - - for i := 0; i < len(id); i++ { - if strings.IndexByte(hexchars, id[i]) == -1 { - t.Fatalf("unexpected byte, want any valid hex char, got %c", id[i]) - } - } - } -} +module.exports = merge(common, { + mode: 'production', + devtool: 'source-map', + optimization: { + minimize: true, + namedModules: true, // Module names instead of numbers - resolves the large diff problem. + minimizer: [ + new TerserPlugin({ + cache: true, + parallel: true, + sourceMap: true, + terserOptions: { + output: { + comments: false, + beautify: true, + }, + }, + }), + ], + }, +}); diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/yarn.lock b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/yarn.lock index 10277c98..70743e14 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/assets/yarn.lock +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/assets/yarn.lock @@ -2,217 +2,1147 @@ # yarn lockfile v1 -"@babel/code-frame@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== dependencies: - "@babel/highlight" "7.0.0-beta.44" + "@babel/highlight" "^7.0.0" -"@babel/generator@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" +"@babel/core@7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b" + integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA== dependencies: - "@babel/types" "7.0.0-beta.44" + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.3.4" + "@babel/helpers" "^7.2.0" + "@babel/parser" "^7.3.4" + "@babel/template" "^7.2.2" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e" + integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg== + dependencies: + "@babel/types" "^7.3.4" jsesc "^2.5.1" - lodash "^4.2.0" + lodash "^4.17.11" source-map "^0.5.0" trim-right "^1.0.1" -"@babel/helper-function-name@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.44" - "@babel/template" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" + "@babel/types" "^7.0.0" -"@babel/helper-get-function-arity@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" +"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" + integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== dependencies: - "@babel/types" "7.0.0-beta.44" + "@babel/helper-explode-assignable-expression" "^7.1.0" + "@babel/types" "^7.0.0" -"@babel/helper-split-export-declaration@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" +"@babel/helper-builder-react-jsx@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz#a1ac95a5d2b3e88ae5e54846bf462eeb81b318a4" + integrity sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw== dependencies: - "@babel/types" "7.0.0-beta.44" + "@babel/types" "^7.3.0" + esutils "^2.0.0" -"@babel/highlight@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" +"@babel/helper-call-delegate@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" + integrity sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ== + dependencies: + "@babel/helper-hoist-variables" "^7.0.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-create-class-features-plugin@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.4.tgz#092711a7a3ad8ea34de3e541644c2ce6af1f6f0c" + integrity sha512-uFpzw6L2omjibjxa8VGZsJUPL5wJH0zzGKpoz0ccBkzIa6C8kWNUbiBmQ0rgOKWlHJ6qzmfa6lTiGchiV8SC+g== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.3.4" + "@babel/helper-split-export-declaration" "^7.0.0" + +"@babel/helper-define-map@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" + integrity sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/types" "^7.0.0" + lodash "^4.17.10" + +"@babel/helper-explode-assignable-expression@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" + integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== + dependencies: + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-hoist-variables@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88" + integrity sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-member-expression-to-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" + integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-imports@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-transforms@^7.1.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963" + integrity sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/template" "^7.2.2" + "@babel/types" "^7.2.2" + lodash "^4.17.10" + +"@babel/helper-optimise-call-expression@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" + integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/helper-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" + integrity sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg== + dependencies: + lodash "^4.17.10" + +"@babel/helper-remap-async-to-generator@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" + integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-wrap-function" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz#a795208e9b911a6eeb08e5891faacf06e7013e13" + integrity sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" + +"@babel/helper-simple-access@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== + dependencies: + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-wrap-function@^7.1.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" + integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.2.0" + +"@babel/helpers@^7.2.0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.3.1.tgz#949eec9ea4b45d3210feb7dc1c22db664c9e44b9" + integrity sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA== + dependencies: + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.5" + "@babel/types" "^7.3.0" + +"@babel/highlight@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== dependencies: chalk "^2.0.0" esutils "^2.0.2" - js-tokens "^3.0.0" + js-tokens "^4.0.0" -"@babel/template@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" - dependencies: - "@babel/code-frame" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" - babylon "7.0.0-beta.44" - lodash "^4.2.0" +"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" + integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ== -"@babel/traverse@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" +"@babel/plugin-proposal-async-generator-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" + integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== dependencies: - "@babel/code-frame" "7.0.0-beta.44" - "@babel/generator" "7.0.0-beta.44" - "@babel/helper-function-name" "7.0.0-beta.44" - "@babel/helper-split-export-declaration" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" - babylon "7.0.0-beta.44" - debug "^3.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + +"@babel/plugin-proposal-class-properties@7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.4.tgz#410f5173b3dc45939f9ab30ca26684d72901405e" + integrity sha512-lUf8D3HLs4yYlAo8zjuneLvfxN7qfKv1Yzbj5vjqaqMJxgJA3Ipwp4VUJ+OrOdz53Wbww6ahwB8UhB2HQyLotA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.3.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-proposal-function-bind@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-bind/-/plugin-proposal-function-bind-7.2.0.tgz#94dc2cdc505cafc4e225c0014335a01648056bf7" + integrity sha512-qOFJ/eX1Is78sywwTxDcsntLOdb5ZlHVVqUz5xznq8ldAfOVIyZzp1JE2rzHnaksZIhrqMrwIpQL/qcEprnVbw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-function-bind" "^7.2.0" + +"@babel/plugin-proposal-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" + integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + +"@babel/plugin-proposal-object-rest-spread@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz#47f73cf7f2a721aad5c0261205405c642e424654" + integrity sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" + integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz#abe7281fe46c95ddc143a65e5358647792039520" + integrity sha512-LvRVYb7kikuOtIoUeWTkOxQEV1kYvL5B6U3iWEGCzPNRus1MzJweFqORTj+0jkxozkTSYNJozPOddxmqdqsRpw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.2.0" + +"@babel/plugin-syntax-async-generators@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" + integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-flow@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c" + integrity sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-function-bind@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-bind/-/plugin-syntax-function-bind-7.2.0.tgz#68fe85b0c0da67125f87bf239c68051b06c66309" + integrity sha512-/WzU1lLU2l0wDfB42Wkg6tahrmtBbiD8C4H6EGSX0M4GAjzN6JiOpq/Uh8G6GSoR6lPMvhjM0MNiV6znj6y/zg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" + integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-jsx@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7" + integrity sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" + integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" + integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" + integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz#4e45408d3c3da231c0e7b823f407a53a7eb3048c" + integrity sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + +"@babel/plugin-transform-block-scoped-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" + integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz#5c22c339de234076eee96c8783b2fed61202c5c4" + integrity sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.11" + +"@babel/plugin-transform-classes@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz#dc173cb999c6c5297e0b5f2277fdaaec3739d0cc" + integrity sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-define-map" "^7.1.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.3.4" + "@babel/helper-split-export-declaration" "^7.0.0" globals "^11.1.0" - invariant "^2.2.0" - lodash "^4.2.0" -"@babel/types@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" +"@babel/plugin-transform-computed-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" + integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.2.0": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz#f2f5520be055ba1c38c41c0e094d8a461dd78f2d" + integrity sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz#f0aabb93d120a8ac61e925ea0ba440812dbe0e49" + integrity sha512-sKxnyHfizweTgKZf7XsXu/CNupKhzijptfTM+bozonIuyVrLWVUvYjE2bhuSBML8VQeMxq4Mm63Q9qvcvUcciQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.1.3" + +"@babel/plugin-transform-duplicate-keys@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3" + integrity sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" + integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-flow-strip-types@7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.3.4.tgz#00156236defb7dedddc2d3c9477dcc01a4494327" + integrity sha512-PmQC9R7DwpBFA+7ATKMyzViz3zCaMNouzZMPZN2K5PnbBbtL3AXFYTkDk+Hey5crQq2A90UG5Uthz0mel+XZrA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" + +"@babel/plugin-transform-for-of@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz#ab7468befa80f764bb03d3cb5eef8cc998e1cad9" + integrity sha512-Kz7Mt0SsV2tQk6jG5bBv5phVbkd0gd27SgYD4hH1aLMJRchM0dzHaXvrWhVZ+WxAlDoAKZ7Uy3jVTW2mKXQ1WQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz#f7930362829ff99a3174c39f0afcc024ef59731a" + integrity sha512-kWgksow9lHdvBC2Z4mxTsvc7YdY7w/V6B2vy9cTIPtLEE9NhwoWivaxdNM/S37elu5bqlLP/qOY906LukO9lkQ== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" + integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-amd@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6" + integrity sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-commonjs@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz#c4f1933f5991d5145e9cfad1dfd848ea1727f404" + integrity sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + +"@babel/plugin-transform-modules-systemjs@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz#813b34cd9acb6ba70a84939f3680be0eb2e58861" + integrity sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw== + dependencies: + "@babel/helper-hoist-variables" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-umd@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" + integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz#140b52985b2d6ef0cb092ef3b29502b990f9cd50" + integrity sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw== + dependencies: + regexp-tree "^0.1.0" + +"@babel/plugin-transform-new-target@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" + integrity sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-object-super@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" + integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + +"@babel/plugin-transform-parameters@^7.2.0": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz#3a873e07114e1a5bee17d04815662c8317f10e30" + integrity sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw== + dependencies: + "@babel/helper-call-delegate" "^7.1.0" + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-react-display-name@^7.0.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz#ebfaed87834ce8dc4279609a4f0c324c156e3eb0" + integrity sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-react-jsx-self@^7.0.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz#461e21ad9478f1031dd5e276108d027f1b5240ba" + integrity sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@babel/plugin-transform-react-jsx-source@^7.0.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz#20c8c60f0140f5dd3cd63418d452801cf3f7180f" + integrity sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@babel/plugin-transform-react-jsx@^7.0.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz#f2cab99026631c767e2745a5368b331cfe8f5290" + integrity sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg== + dependencies: + "@babel/helper-builder-react-jsx" "^7.3.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@babel/plugin-transform-regenerator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz#1601655c362f5b38eead6a52631f5106b29fa46a" + integrity sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA== + dependencies: + regenerator-transform "^0.13.4" + +"@babel/plugin-transform-shorthand-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" + integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.2.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" + integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" + integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b" + integrity sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" + integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-unicode-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz#4eb8db16f972f8abb5062c161b8b115546ade08b" + integrity sha512-m48Y0lMhrbXEJnVUaYly29jRXbQ3ksxPrS1Tg8t+MHqzXhtBYAvI51euOBaoAlZLPHsieY9XPVMf80a5x0cPcA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.1.3" + +"@babel/preset-env@7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.4.tgz#887cf38b6d23c82f19b5135298bdb160062e33e1" + integrity sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.2.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.3.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.2.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.3.4" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.3.4" + "@babel/plugin-transform-classes" "^7.3.4" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.2.0" + "@babel/plugin-transform-dotall-regex" "^7.2.0" + "@babel/plugin-transform-duplicate-keys" "^7.2.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.2.0" + "@babel/plugin-transform-function-name" "^7.2.0" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.2.0" + "@babel/plugin-transform-modules-commonjs" "^7.2.0" + "@babel/plugin-transform-modules-systemjs" "^7.3.4" + "@babel/plugin-transform-modules-umd" "^7.2.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0" + "@babel/plugin-transform-new-target" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.2.0" + "@babel/plugin-transform-parameters" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.3.4" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.2.0" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.2.0" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.2.0" + browserslist "^4.3.4" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.3.0" + +"@babel/preset-react@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0" + integrity sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + +"@babel/preset-stage-0@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/preset-stage-0/-/preset-stage-0-7.0.0.tgz#999aaec79ee8f0a763042c68c06539c97c6e0646" + integrity sha512-FBMd0IiARPtH5aaOFUVki6evHiJQiY0pFy7fizyRF7dtwc+el3nwpzvhb9qBNzceG1OIJModG1xpE0DDFjPXwA== + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.4.tgz#73d12ba819e365fcf7fd152aed56d6df97d21c83" + integrity sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g== + dependencies: + regenerator-runtime "^0.12.0" + +"@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" + integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06" + integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.3.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.3.4" + "@babel/types" "^7.3.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed" + integrity sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ== dependencies: esutils "^2.0.2" - lodash "^4.2.0" + lodash "^4.17.11" to-fast-properties "^2.0.0" -"@types/jss@^9.3.0": - version "9.5.0" - resolved "https://registry.yarnpkg.com/@types/jss/-/jss-9.5.0.tgz#65d9b5c61f1e95ad3acd53e9a8b2d2342aa917e8" - dependencies: - csstype "^1.6.0" +"@fortawesome/fontawesome-common-types@^0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.1.7.tgz#4336c4b06d0b5608ff1215464b66fcf9f4795284" + integrity sha512-ego8jRVSHfq/iq4KRZJKQeUAdi3ZjGNrqw4oPN3fNdvTBnLCSntwVCnc37bsAJP9UB8MhrTfPnZYxkv2vpS4pg== -"@types/react-transition-group@^2.0.6": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-2.0.7.tgz#2847292d54c5685d982ae5a3ecb6960946689d87" +"@fortawesome/fontawesome-common-types@^0.2.15": + version "0.2.15" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.15.tgz#16af950653083d1e3064061de9f8e5e3b579f688" + integrity sha512-ATBRyKJw1d2ko+0DWN9+BXau0EK3I/Q6pPzPv3LhJD7r052YFAkAdfb1Bd7ZqhBsJrdse/S7jKxWUOZ61qBD4g== + +"@fortawesome/fontawesome-free-regular@^5.0.13": + version "5.0.13" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-regular/-/fontawesome-free-regular-5.0.13.tgz#eb78c30184e3f456a423a1dcfa0f682f7b50de4a" + integrity sha512-36lz9Idww1L4QaaTcv7GZiOeIP9emJFDUsedvRovI10kmwyd6rN0PKkIjnq0FB4foLhX4Rou8vnbCCmjtqiLug== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.1.7" + +"@fortawesome/fontawesome-svg-core@^1.2.15": + version "1.2.15" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.15.tgz#368f9fc7e8e8d8636495dc7483f97510f920ba97" + integrity sha512-M/sHyl4g2VBtKYkay1Z+XImMyTVcaBPmehYtPw4HKD9zg2E7eovB7Yx98aUfZjPbroGqa+IL4/+KhWBMOGlHIQ== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.15" + +"@fortawesome/free-regular-svg-icons@^5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.7.2.tgz#7113bf9df5a970918b8cac8eb45e5ad120818741" + integrity sha512-ZO+zQcncfT7omTsTIjBkugj/dFXiSnoK44I5p0/WAoNX8aX2Au7j+uxq1qFX4bevkfGFGsPeJUYU1+Q1PB/5pQ== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.15" + +"@fortawesome/free-solid-svg-icons@^5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.7.2.tgz#9ec2ed353d630092a8e19cc8aae2f716572963e5" + integrity sha512-iujcXMyAvIbWM8W3jkOLpvJbR+rPpdN1QyqhZeJaLRdHPH4JmuovIAYP4vx5Sa1csZVXfRD1eDWqVZ/jGM620A== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.15" + +"@fortawesome/react-fontawesome@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.4.tgz#18d61d9b583ca289a61aa7dccc05bd164d6bc9ad" + integrity sha512-GwmxQ+TK7PEdfSwvxtGnMCqrfEm0/HbRHArbUudsYiy9KzVCwndxa2KMcfyTQ8El0vROrq8gOOff09RF1oQe8g== + dependencies: + humps "^2.0.1" + prop-types "^15.5.10" + +"@material-ui/core@3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-3.9.2.tgz#41ed1a470e981d199829eb5d9317a671c66a6f7d" + integrity sha512-aukR3mSH3g115St2OnqoeMRtmxzxxx+Mch7pFKRV3Tz3URExBlZwOolimjxKZpG4LGec8HlhREawafLsDzjVWQ== + dependencies: + "@babel/runtime" "^7.2.0" + "@material-ui/system" "^3.0.0-alpha.0" + "@material-ui/utils" "^3.0.0-alpha.2" + "@types/jss" "^9.5.6" + "@types/react-transition-group" "^2.0.8" + brcast "^3.0.1" + classnames "^2.2.5" + csstype "^2.5.2" + debounce "^1.1.0" + deepmerge "^3.0.0" + dom-helpers "^3.2.1" + hoist-non-react-statics "^3.2.1" + is-plain-object "^2.0.4" + jss "^9.8.7" + jss-camel-case "^6.0.0" + jss-default-unit "^8.0.2" + jss-global "^3.0.0" + jss-nested "^6.0.1" + jss-props-sort "^6.0.0" + jss-vendor-prefixer "^7.0.0" + normalize-scroll-left "^0.1.2" + popper.js "^1.14.1" + prop-types "^15.6.0" + react-event-listener "^0.6.2" + react-transition-group "^2.2.1" + recompose "0.28.0 - 0.30.0" + warning "^4.0.1" + +"@material-ui/icons@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-3.0.2.tgz#d67a6dd1ec8312d3a88ec97944a63daeef24fe10" + integrity sha512-QY/3gJnObZQ3O/e6WjH+0ah2M3MOgLOzCy8HTUoUx9B6dDrS18vP7Ycw3qrDEKlB6q1KNxy6CZHm5FCauWGy2g== + dependencies: + "@babel/runtime" "^7.2.0" + recompose "0.28.0 - 0.30.0" + +"@material-ui/system@^3.0.0-alpha.0": + version "3.0.0-alpha.2" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-3.0.0-alpha.2.tgz#096e80c8bb0f70aea435b9e38ea7749ee77b4e46" + integrity sha512-odmxQ0peKpP7RQBQ8koly06YhsPzcoVib1vByVPBH4QhwqBXuYoqlCjt02846fYspAqkrWzjxnWUD311EBbxOA== + dependencies: + "@babel/runtime" "^7.2.0" + deepmerge "^3.0.0" + prop-types "^15.6.0" + warning "^4.0.1" + +"@material-ui/utils@^3.0.0-alpha.2": + version "3.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-3.0.0-alpha.3.tgz#836c62ea46f5ffc6f0b5ea05ab814704a86908b1" + integrity sha512-rwMdMZptX0DivkqBuC+Jdq7BYTXwqKai5G5ejPpuEDKpWzi1Oxp+LygGw329FrKpuKeiqpcymlqJTjmy+quWng== + dependencies: + "@babel/runtime" "^7.2.0" + prop-types "^15.6.0" + react-is "^16.6.3" + +"@most/multicast@^1.2.5": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@most/multicast/-/multicast-1.3.0.tgz#e01574840df634478ac3fabd164c6e830fb3b966" + integrity sha512-DWH8AShgp5bXn+auGzf5tzPxvpmEvQJd0CNsApOci1LDF4eAEcnw4HQOr2Jaa+L92NbDYFKBSXxll+i7r1ikvw== + dependencies: + "@most/prelude" "^1.4.0" + +"@most/prelude@^1.4.0": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@most/prelude/-/prelude-1.7.2.tgz#be4ed406518d4c8c220e45c39fa7251365425b73" + integrity sha512-GM5ec7+xpkuXiCMyzhyENgH/xZ8t0nAMDBY0QOsVVD6TrZYjJKUnW1eaI18HHX8W+COWMwWR9c0zoPiBp9+tUg== + +"@octokit/rest@^15.2.6": + version "15.18.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.18.1.tgz#ec7fb0f8775ef64dc095fae6635411d3fbff9b62" + integrity sha512-g2tecjp2TEtYV8bKAFvfQtu+W29HM7ektmWmw8zrMy9/XCKDEYRErR2YvvhN9+IxkLC4O3lDqYP4b6WgsL6Utw== + dependencies: + before-after-hook "^1.1.0" + btoa-lite "^1.0.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.0" + lodash "^4.17.4" + node-fetch "^2.1.1" + universal-user-agent "^2.0.0" + url-template "^2.0.8" + +"@types/jss@^9.5.6": + version "9.5.8" + resolved "https://registry.yarnpkg.com/@types/jss/-/jss-9.5.8.tgz#258391f42211c042fc965508d505cbdc579baa5b" + integrity sha512-bBbHvjhm42UKki+wZpR89j73ykSXg99/bhuKuYYePtpma3ZAnmeGnl0WxXiZhPGsIfzKwCUkpPC0jlrVMBfRxA== + dependencies: + csstype "^2.0.0" + indefinite-observable "^1.0.1" + +"@types/prop-types@*": + version "15.7.0" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.0.tgz#4c48fed958d6dcf9487195a0ef6456d5f6e0163a" + integrity sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg== + +"@types/react-transition-group@^2.0.8": + version "2.0.16" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-2.0.16.tgz#2dcb9e396ab385ee19c4af1c9caa469a14cd042f" + integrity sha512-FUJEx2BGJPU1qVQoWd9v7wpOwnCPTWhcE4iTaU5prry9SvwiI11lCXOci8Nz9cM/Fuf650l7Skg6nlVeCYjPFA== dependencies: "@types/react" "*" "@types/react@*": - version "16.0.40" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.40.tgz#caabc2296886f40b67f6fc80f0f3464476461df9" + version "16.8.8" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.8.tgz#4b60a469fd2469f7aa6eaa0f8cfbc51f6d76e662" + integrity sha512-xwEvyet96u7WnB96kqY0yY7qxx/pEpU51QeACkKFtrgjjXITQn0oO1iwPEraXVgh10ZFPix7gs1R4OJXF7P5sg== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + +"@webassemblyjs/floating-point-hex-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@~1.3.4: +accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= dependencies: mime-types "~2.1.18" negotiator "0.6.1" -acorn-dynamic-import@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== + +acorn-jsx@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" + integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== + +acorn@^6.0.5, acorn@^6.0.7: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" + integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +agent-base@4, agent-base@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: - acorn "^4.0.3" + es6-promisify "^5.0.0" -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - -acorn@^5.0.0, acorn@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.0.tgz#1abb587fbf051f94e3de20e6b26ef910b1828298" - -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== ajv-keywords@^3.0.0, ajv-keywords@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" + version "3.4.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d" + integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" +ajv@^6.0.1, ajv@^6.1.0, ajv@^6.9.1: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" + integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ajv@^5.0.0, ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" + fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" -ajv@^6.0.1, ajv@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.2.0.tgz#afac295bbaa0152449e522742e4547c1ae9328d2" - dependencies: - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - -alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - -ansi-escapes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" -aproba@^1.0.3: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -220,49 +1150,47 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" -aria-query@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.7.1.tgz#26cbb5aff64144b0a825be1846e0b16cfa00b11e" +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= dependencies: ast-types-flow "0.0.7" commander "^2.11.0" -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= -arr-flatten@^1.0.1, arr-flatten@^1.1.0: +arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= array-flatten@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== array-includes@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= dependencies: define-properties "^1.1.2" es-abstract "^1.7.0" @@ -270,847 +1198,168 @@ array-includes@^3.0.3: array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== dependencies: bn.js "^4.0.0" inherits "^2.0.1" minimalistic-assert "^1.0.0" -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= dependencies: util "0.10.3" assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types-flow@0.0.7: +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-each@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735" + integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg== + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -async@^2.1.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" +async@^2.5.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== dependencies: - lodash "^4.14.0" + lodash "^4.17.11" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -atob@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" - -autoprefixer@^6.3.1: - version "6.7.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" - dependencies: - browserslist "^1.7.6" - caniuse-db "^1.0.30000634" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^5.2.16" - postcss-value-parser "^3.2.3" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -axobject-query@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-0.1.0.tgz#62f59dbc59c9f9242759ca349960e7a2fe3c36c0" +axobject-query@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" + integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww== dependencies: ast-types-flow "0.0.7" -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" +babel-eslint@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" + integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ== dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - -babel-eslint@^8.2.1: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" - dependencies: - "@babel/code-frame" "7.0.0-beta.44" - "@babel/traverse" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" - babylon "7.0.0-beta.44" - eslint-scope "~3.7.1" + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" +babel-loader@8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.5.tgz#225322d7509c2157655840bba52e46b6c2f2fe33" + integrity sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw== dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-bindify-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-builder-react-jsx@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - esutils "^2.0.2" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-loader@^7.1.2: - version "7.1.4" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015" - dependencies: - find-cache-dir "^1.0.0" + find-cache-dir "^2.0.0" loader-utils "^1.0.2" mkdirp "^0.5.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - -babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - -babel-plugin-syntax-do-expressions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" - -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - -babel-plugin-syntax-flow@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - -babel-plugin-syntax-function-bind@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" - -babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-decorators-legacy@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz#741b58f6c5bce9e6027e0882d9c994f04f366925" - dependencies: - babel-plugin-syntax-decorators "^6.1.18" - babel-runtime "^6.2.0" - babel-template "^6.3.0" - -babel-plugin-transform-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - dependencies: - babel-helper-explode-class "^6.24.1" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-do-expressions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb" - dependencies: - babel-plugin-syntax-do-expressions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.23.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-flow-strip-types@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" - dependencies: - babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-function-bind@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz#c6fb8e96ac296a310b8cf8ea401462407ddf6a97" - dependencies: - babel-plugin-syntax-function-bind "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-react-display-name@^6.23.0: - version "6.25.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx-self@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx-source@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" - dependencies: - babel-helper-builder-react-jsx "^6.24.1" - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-regenerator@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-runtime@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" + util.promisify "^1.0.0" babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" regenerator-runtime "^0.10.5" -babel-preset-env@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^2.1.2" - invariant "^2.2.2" - semver "^5.3.0" - -babel-preset-flow@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" - dependencies: - babel-plugin-transform-flow-strip-types "^6.22.0" - -babel-preset-react@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" - dependencies: - babel-plugin-syntax-jsx "^6.3.13" - babel-plugin-transform-react-display-name "^6.23.0" - babel-plugin-transform-react-jsx "^6.24.1" - babel-plugin-transform-react-jsx-self "^6.22.0" - babel-plugin-transform-react-jsx-source "^6.22.0" - babel-preset-flow "^6.23.0" - -babel-preset-stage-0@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz#5642d15042f91384d7e5af8bc88b1db95b039e6a" - dependencies: - babel-plugin-transform-do-expressions "^6.22.0" - babel-plugin-transform-function-bind "^6.22.0" - babel-preset-stage-1 "^6.24.1" - -babel-preset-stage-1@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" - dependencies: - babel-plugin-transform-class-constructor-call "^6.24.1" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.24.1" - -babel-preset-stage-2@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators "^6.24.1" - babel-preset-stage-3 "^6.24.1" - -babel-preset-stage-3@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.24.1" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-plugin-transform-exponentiation-operator "^6.24.1" - babel-plugin-transform-object-rest-spread "^6.22.0" - -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@7.0.0-beta.44: - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= balanced-match@^0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg= balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= base64-js@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -1123,56 +1372,83 @@ base@^0.11.1: batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" +before-after-hook@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.4.0.tgz#2b6bf23dca4f32e628fd2747c10a37c74a4b484d" + integrity sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg== + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= dependencies: - tweetnacl "^0.14.3" + callsite "1.0.0" -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" +big-integer@^1.6.17: + version "1.6.42" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.42.tgz#91623ae5ceeff9a47416c56c9440a66f12f534f1" + integrity sha512-3UQFKcRMx+5Z+IK5vYTMYK2jzLRJkt+XqyDdacgWgtMjjuifKpKTFneJLEgeBElOE2/lXZ1LcMcb5s8pwG2U8Q== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + version "1.13.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.0.tgz#9523e001306a32444b907423f1de2164222f6ab1" + integrity sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw== -"binary@>= 0.3.0 < 1": +binary@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= dependencies: buffers "~0.1.1" chainsaw "~0.1.0" -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +bluebird@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -body-parser@1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" +body-parser@1.18.3: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= dependencies: bytes "3.0.0" content-type "~1.0.4" debug "2.6.9" - depd "~1.1.1" - http-errors "~1.6.2" - iconv-lite "0.4.19" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" on-finished "~2.3.0" - qs "6.5.1" - raw-body "2.3.2" - type-is "~1.6.15" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= dependencies: array-flatten "^2.1.0" deep-equal "^1.0.1" @@ -1181,38 +1457,24 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -braces@^2.3.0, braces@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" - define-property "^1.0.0" extend-shallow "^2.0.1" fill-range "^4.0.0" isobject "^3.0.1" - kind-of "^6.0.2" repeat-element "^1.1.2" snapdragon "^0.8.1" snapdragon-node "^2.0.1" @@ -1222,14 +1484,17 @@ braces@^2.3.0, braces@^2.3.1: brcast@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd" + integrity sha512-eI3yqf9YEqyGl9PCNTR46MGvDylGtaHjalcz6Q3fAPnP/PhpKkkve52vFdfGpwp4VUvK6LUr4TQN+2stCrEwTg== brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== dependencies: buffer-xor "^1.0.3" cipher-base "^1.0.0" @@ -1239,24 +1504,28 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4: safe-buffer "^5.0.1" browserify-cipher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== dependencies: browserify-aes "^1.0.4" browserify-des "^1.0.0" evp_bytestokey "^1.0.0" browserify-des@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== dependencies: cipher-base "^1.0.1" des.js "^1.0.0" inherits "^2.0.1" + safe-buffer "^5.1.2" browserify-rsa@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= dependencies: bn.js "^4.1.0" randombytes "^2.0.1" @@ -1264,6 +1533,7 @@ browserify-rsa@^4.0.0: browserify-sign@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= dependencies: bn.js "^4.1.1" browserify-rsa "^4.0.0" @@ -1276,34 +1546,53 @@ browserify-sign@^4.0.0: browserify-zlib@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== dependencies: pako "~1.0.5" -browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: - version "1.7.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" +browserslist@^4.3.4: + version "4.4.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2" + integrity sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg== dependencies: - caniuse-db "^1.0.30000639" - electron-to-chromium "^1.2.7" + caniuse-lite "^1.0.30000939" + electron-to-chromium "^1.3.113" + node-releases "^1.1.8" -browserslist@^2.1.2: - version "2.11.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" - dependencies: - caniuse-lite "^1.0.30000792" - electron-to-chromium "^1.3.30" +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof-polyfill@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz#a9fb806ce8145d5428510ce72f278bb363a638bf" + integrity sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8= buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + integrity sha1-mXjOMXOIxkmth5MCjDR37wRKi1E= buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^4.3.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1312,22 +1601,42 @@ buffer@^4.3.0: buffers@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" - -builtin-modules@^1.0.0, builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cacache@^11.0.2: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== + dependencies: + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -1339,98 +1648,47 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" +callsites@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" + integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -caniuse-api@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" - dependencies: - browserslist "^1.3.6" - caniuse-db "^1.0.30000529" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" +camelcase@^5.0.0, camelcase@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.2.0.tgz#e7522abda5ed94cc0489e1b8466610e88404cf45" + integrity sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ== -caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000811" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000811.tgz#19efb9238393d40078332c34485c818d641c4305" - -caniuse-lite@^1.0.30000792: - version "1.0.30000811" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000811.tgz#0b6e40f2efccc27bd3cb52f91ee7ca4673d77d10" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - -chain-function@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" +caniuse-lite@^1.0.30000939: + version "1.0.30000947" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000947.tgz#c30305e9701449c22e97f4e9837cea3d76aa3273" + integrity sha512-ubgBUfufe5Oi3W1+EHyh2C3lfBIEcZ6bTuvl5wNOpIuRB978GF/Z+pQ7pGGUpeYRB0P+8C7i/3lt6xkeu2hwnA== chainsaw@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= dependencies: traverse ">=0.3.0 <0.4" -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.1.0, chalk@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" +chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -1439,279 +1697,331 @@ chalk@^2.1.0, chalk@^2.3.1: change-emitter@^0.1.2: version "0.1.6" resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" + integrity sha1-6LL+PX8at9aaMhma/5HqaTFAlRU= -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= chokidar@^2.0.0, chokidar@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7" + version "2.1.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.2.tgz#9c23ea40b01638439e0513864d362aeacc5ad058" + integrity sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg== dependencies: anymatch "^2.0.0" - async-each "^1.0.0" - braces "^2.3.0" + async-each "^1.0.1" + braces "^2.3.2" glob-parent "^3.1.0" - inherits "^2.0.1" + inherits "^2.0.3" is-binary-path "^1.0.0" is-glob "^4.0.0" - normalize-path "^2.1.1" + normalize-path "^3.0.0" path-is-absolute "^1.0.0" - readdirp "^2.0.0" - upath "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.0" optionalDependencies: - fsevents "^1.0.0" + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== + dependencies: + tslib "^1.9.0" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - -clap@^1.0.9: - version "1.2.3" - resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" - dependencies: - chalk "^1.1.3" - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.2.5, classnames@^2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" +classnames@^2.2.5, classnames@^2.2.6, classnames@~2.2.5: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= dependencies: restore-cursor "^2.0.0" cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" wrap-ansi "^2.0.0" -clone@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -coa@~1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: - q "^1.1.2" + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.3.0, color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: - color-name "^1.1.1" + color-name "1.1.3" -color-name@^1.0.0, color-name@^1.1.1: +color-convert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.0.tgz#9851ac61cc0d3898a8a3088650d5bf447bf69d97" + integrity sha512-hzTicsCJIHdxih9+2aLR1tNGZX5qSJGRHDPVwSY26tVrEf55XNajLOBWz2UuWSIergszA09/bqnOiHyqx9fxQg== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-string@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" - dependencies: - color-name "^1.0.0" +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color@^0.11.0: - version "0.11.4" - resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" - dependencies: - clone "^1.0.2" - color-convert "^1.3.0" - color-string "^0.3.0" +colors@^1.1.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== -colormin@^1.0.5: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" - dependencies: - color "^0.11.0" - css-color-names "0.0.4" - has "^1.0.1" +commander@^2.11.0, commander@^2.15.1, commander@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== -colors@^1.1.2, colors@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" - -commander@^2.11.0: - version "2.14.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" +commander@~2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -component-emitter@^1.2.1: +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -compressible@~2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +compressible@~2.0.14: + version "2.0.16" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.16.tgz#a49bf9858f3821b64ce1be0296afc7380466a77f" + integrity sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA== dependencies: - mime-db ">= 1.33.0 < 2" + mime-db ">= 1.38.0 < 2" compression@^1.5.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== dependencies: - accepts "~1.3.4" + accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.13" + compressible "~2.0.14" debug "2.6.9" on-headers "~1.0.1" - safe-buffer "5.1.1" + safe-buffer "5.1.2" vary "~1.1.2" concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.6.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26" +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: + buffer-from "^1.0.0" inherits "^2.0.3" readable-stream "^2.2.2" typedarray "^0.0.6" +config-chain@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + connect-history-api-fallback@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= dependencies: date-now "^0.1.4" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" +convert-source-map@^1.1.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - -core-js@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= core-js@^2.4.0, core-js@^2.5.0: + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== + +core-js@~2.5.1: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= create-ecdh@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== dependencies: bn.js "^4.1.0" elliptic "^6.0.0" create-hash@^1.1.0, create-hash@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== dependencies: cipher-base "^1.0.1" inherits "^2.0.1" - ripemd160 "^2.0.0" + md5.js "^1.3.4" + ripemd160 "^2.0.1" sha.js "^2.4.0" create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== dependencies: cipher-base "^1.0.3" create-hash "^1.1.0" @@ -1720,27 +2030,35 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== dependencies: browserify-cipher "^1.0.0" browserify-sign "^4.0.0" @@ -1754,262 +2072,241 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -css-color-names@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - -css-loader@^0.28.9: - version "0.28.10" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.10.tgz#40282e79230f7bcb4e483efa631d670b735ebf42" +css-loader@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" + integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== dependencies: - babel-code-frame "^6.26.0" - css-selector-tokenizer "^0.7.0" - cssnano "^3.10.0" - icss-utils "^2.1.0" - loader-utils "^1.0.2" - lodash.camelcase "^4.3.0" - object-assign "^4.1.1" - postcss "^5.0.6" - postcss-modules-extract-imports "^1.2.0" - postcss-modules-local-by-default "^1.2.0" - postcss-modules-scope "^1.1.0" - postcss-modules-values "^1.3.0" + camelcase "^5.2.0" + icss-utils "^4.1.0" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.14" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^2.0.6" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^2.0.0" postcss-value-parser "^3.3.0" - source-list-map "^2.0.0" - -css-selector-tokenizer@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" + schema-utils "^1.0.0" css-vendor@^0.3.8: version "0.3.8" resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa" + integrity sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo= dependencies: is-in-browser "^1.0.2" -cssesc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" - dependencies: - autoprefixer "^6.3.1" - decamelize "^1.1.2" - defined "^1.0.0" - has "^1.0.1" - object-assign "^4.0.1" - postcss "^5.0.14" - postcss-calc "^5.2.0" - postcss-colormin "^2.1.8" - postcss-convert-values "^2.3.4" - postcss-discard-comments "^2.0.4" - postcss-discard-duplicates "^2.0.1" - postcss-discard-empty "^2.0.1" - postcss-discard-overridden "^0.1.1" - postcss-discard-unused "^2.2.1" - postcss-filter-plugins "^2.0.0" - postcss-merge-idents "^2.1.5" - postcss-merge-longhand "^2.0.1" - postcss-merge-rules "^2.0.3" - postcss-minify-font-values "^1.0.2" - postcss-minify-gradients "^1.0.1" - postcss-minify-params "^1.0.4" - postcss-minify-selectors "^2.0.4" - postcss-normalize-charset "^1.1.0" - postcss-normalize-url "^3.0.7" - postcss-ordered-values "^2.1.0" - postcss-reduce-idents "^2.2.2" - postcss-reduce-initial "^1.0.0" - postcss-reduce-transforms "^1.0.3" - postcss-svgo "^2.1.1" - postcss-unique-selectors "^2.0.2" - postcss-value-parser "^3.2.3" - postcss-zindex "^2.0.1" +csstype@^2.0.0, csstype@^2.2.0, csstype@^2.5.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.3.tgz#b701e5968245bf9b08d54ac83d00b624e622a9fa" + integrity sha512-rINUZXOkcBmoHWEyu7JdHu5JMzkGRoMX4ov9830WNgxf5UYxcBUO0QTKAqeJ5EZfSdlrcJYkC8WwfVW7JYi4yg== -csso@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" - dependencies: - clap "^1.0.9" - source-map "^0.5.3" - -csstype@^1.6.0: - version "1.8.2" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-1.8.2.tgz#2c0f16da08b99f13fe7fbb242e87d1a19dbe77a7" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= d3-array@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.1.tgz#d1ca33de2f6ac31efadb8e050a021d7e2396d5dc" + version "1.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" + integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== d3-collection@1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2" + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" + integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== d3-color@1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b" + version "1.2.3" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.2.3.tgz#6c67bb2af6df3cc8d79efcc4d3a3e83e28c8048f" + integrity sha512-x37qq3ChOTLd26hnps36lexMRhNXEtVxZ4B25rL0DVdDsGQIJGB18S7y9XDwlDD6MD/ZBzITCf4JjGMM10TZkw== d3-format@1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.2.2.tgz#1a39c479c8a57fe5051b2e67a3bee27061a74e7a" + version "1.3.2" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.3.2.tgz#6a96b5e31bcb98122a30863f7d92365c00603562" + integrity sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ== -d3-interpolate@1, d3-interpolate@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6" +d3-interpolate@1, d3-interpolate@~1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.3.2.tgz#417d3ebdeb4bc4efcc8fd4361c55e4040211fd68" + integrity sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w== dependencies: d3-color "1" d3-path@1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764" + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.7.tgz#8de7cd693a75ac0b5480d3abaccd94793e58aae8" + integrity sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA== -d3-scale@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.6.tgz#bce19da80d3a0cf422c9543ae3322086220b34ed" +d3-scale@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.1.2.tgz#4e932b7b60182aee9073ede8764c98423e5f9a94" + integrity sha512-bESpd64ylaKzCDzvULcmHKZTlzA/6DGSVwx7QSDj/EnX9cpSevsdiwdHFYI9ouo9tNBbV3v5xztHS2uFeOzh8Q== dependencies: d3-array "^1.2.0" d3-collection "1" - d3-color "1" d3-format "1" d3-interpolate "1" d3-time "1" d3-time-format "2" -d3-shape@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.2.0.tgz#45d01538f064bafd05ea3d6d2cb748fd8c41f777" +d3-shape@~1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.2.3.tgz#3dad9b593e7297adac19b1f34a6821940968d7d6" + integrity sha512-mdrQ+V3jdEAa5k9clSEhCNFtq+pdky25PBGjocUgAI0AUbu/Esq4x6bdFcjkNura87Wqp1pd3dfZh6uJ+XojlA== dependencies: d3-path "1" d3-time-format@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.1.tgz#85b7cdfbc9ffca187f14d3c456ffda268081bb31" + version "2.1.3" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.3.tgz#ae06f8e0126a9d60d6364eac5b1533ae1bac826b" + integrity sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA== dependencies: d3-time "1" d3-time@1: - version "1.0.8" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.8.tgz#dbd2d6007bf416fe67a76d17947b784bffea1e84" + version "1.0.11" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.11.tgz#1d831a3e25cd189eb256c17770a666368762bbce" + integrity sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw== -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - -damerau-levenshtein@^1.0.0: +damerau-levenshtein@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" + integrity sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ= date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: +debounce@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131" + integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg== + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.1.0: +debug@3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: +debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decamelize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== + dependencies: + xregexp "4.0.0" + +decimal.js-light@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.0.tgz#ca7faf504c799326df94b0ab920424fdfc125348" + integrity sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg== decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= decompress-response@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= dependencies: mimic-response "^1.0.0" deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -deepmerge@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312" +deepmerge@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e" + integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow== -define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" +default-gateway@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" + execa "^1.0.0" + ip-regex "^2.1.0" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - del@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU= dependencies: globby "^6.1.0" is-path-cwd "^1.0.0" @@ -2018,25 +2315,20 @@ del@^3.0.0: pify "^3.0.0" rimraf "^2.2.8" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - -depd@~1.1.1: +depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" @@ -2044,24 +2336,27 @@ des.js@^1.0.0: destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-node@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== diffie-hellman@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== dependencies: bn.js "^4.1.0" miller-rabin "^4.0.0" @@ -2070,10 +2365,12 @@ diffie-hellman@^5.0.0: dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= dns-packet@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== dependencies: ip "^1.1.0" safe-buffer "^5.0.1" @@ -2081,55 +2378,95 @@ dns-packet@^1.3.1: dns-txt@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= dependencies: buffer-indexof "^1.0.0" doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= dependencies: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.2, doctrine@^2.1.0: +doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" -dom-helpers@^3.2.0, dom-helpers@^3.2.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-helpers@^3.2.1, dom-helpers@^3.3.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" dom-walk@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== dependencies: - jsbn "~0.1.0" + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +editorconfig@^0.15.2: + version "0.15.3" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" + integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g== + dependencies: + commander "^2.19.0" + lru-cache "^4.1.5" + semver "^5.6.0" + sigmund "^1.0.1" ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: - version "1.3.34" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.34.tgz#d93498f40391bb0c16a603d8241b9951404157ed" +electron-to-chromium@^1.3.113: + version "1.3.116" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.116.tgz#1dbfee6a592a0c14ade77dbdfe54fef86387d702" + integrity sha512-NKwKAXzur5vFCZYBHpdWjTMO8QptNLNP80nItkSIgUOapPAo9Uia+RvkCaZJtO7fhQaVElSvBPWEc2ku6cKsPA== elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2139,154 +2476,171 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" -emoji-regex@^6.1.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" +emoji-regex@^7.0.1, emoji-regex@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= -encodeurl@~1.0.1: +encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= dependencies: iconv-lite "~0.4.13" -enhanced-resolve@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + integrity sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59" + integrity sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~6.1.0" + +enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== dependencies: graceful-fs "^4.1.2" memory-fs "^0.4.0" - object-assign "^4.0.1" - tapable "^0.2.7" + tapable "^1.0.0" -errno@^0.1.3: +errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== dependencies: prr "~1.0.1" error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.7.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" +es-abstract@^1.11.0, es-abstract@^1.12.0, es-abstract@^1.5.1, es-abstract@^1.7.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== dependencies: - es-to-primitive "^1.1.1" + es-to-primitive "^1.2.0" function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" + has "^1.0.3" + is-callable "^1.1.4" is-regex "^1.0.4" + object-keys "^1.0.12" -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== dependencies: - is-callable "^1.1.1" + is-callable "^1.1.4" is-date-object "^1.0.1" - is-symbol "^1.0.1" + is-symbol "^1.0.2" -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.39" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.39.tgz#fca21b67559277ca4ac1a1ed7048b107b6f76d87" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" +es6-promise@^4.0.3: + version "4.2.6" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" + integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" + es6-promise "^4.0.3" escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-config-airbnb-base@^12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944" +eslint-config-airbnb-base@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" + integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw== dependencies: eslint-restricted-globals "^0.1.1" + object.assign "^4.1.0" + object.entries "^1.0.4" -eslint-config-airbnb@^16.1.0: - version "16.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz#2546bfb02cc9fe92284bf1723ccf2e87bc45ca46" +eslint-config-airbnb@^17.0.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" + integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw== dependencies: - eslint-config-airbnb-base "^12.1.0" + eslint-config-airbnb-base "^13.1.0" + object.assign "^4.1.0" + object.entries "^1.0.4" -eslint-import-resolver-node@^0.3.1: +eslint-import-resolver-node@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== dependencies: debug "^2.6.9" resolve "^1.5.0" -eslint-loader@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.0.0.tgz#d136619b5c684e36531ffc28c60a56e404608f5d" +eslint-loader@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.1.2.tgz#453542a1230d6ffac90e4e7cb9cadba9d851be68" + integrity sha512-rA9XiXEOilLYPOIInvVH5S/hYfyTPyxag6DZhoQOduM+3TkghAEQ3VcFO8VnX4J4qg/UIBzp72aOf/xvYmpmsg== dependencies: loader-fs-cache "^1.0.0" loader-utils "^1.0.2" @@ -2294,182 +2648,247 @@ eslint-loader@^2.0.0: object-hash "^1.1.4" rimraf "^2.6.1" -eslint-module-utils@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" +eslint-module-utils@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz#546178dab5e046c8b562bbb50705e2456d7bda49" + integrity sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w== dependencies: debug "^2.6.8" - pkg-dir "^1.0.0" + pkg-dir "^2.0.0" -eslint-plugin-flowtype@^2.41.0: - version "2.46.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.1.tgz#c4f81d580cd89c82bc3a85a1ccf4ae3a915143a4" +eslint-plugin-es@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz#475f65bb20c993fc10e8c8fe77d1d60068072da6" + integrity sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw== dependencies: - lodash "^4.15.0" + eslint-utils "^1.3.0" + regexpp "^2.0.1" -eslint-plugin-import@^2.8.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" +eslint-plugin-flowtype@3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-3.4.2.tgz#55475e10b05fd714d60bceebbbed596cb8706b16" + integrity sha512-sv6O6fiN3dIwhU4qRxfcyIpbKGVvsxwIQ6vgBLudpQKjH1rEyEFEOjGzGEUBTQP9J8LdTZm37OjiqZ0ZeFOa6g== + dependencies: + lodash "^4.17.11" + +eslint-plugin-import@2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz#97ac3e75d0791c4fac0e15ef388510217be7f66f" + integrity sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A== dependencies: - builtin-modules "^1.1.1" contains-path "^0.1.0" - debug "^2.6.8" + debug "^2.6.9" doctrine "1.5.0" - eslint-import-resolver-node "^0.3.1" - eslint-module-utils "^2.1.1" - has "^1.0.1" - lodash "^4.17.4" - minimatch "^3.0.3" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.3.0" + has "^1.0.3" + lodash "^4.17.11" + minimatch "^3.0.4" read-pkg-up "^2.0.0" + resolve "^1.9.0" -eslint-plugin-jsx-a11y@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz#54583d1ae442483162e040e13cc31865465100e5" +eslint-plugin-jsx-a11y@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c" + integrity sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w== dependencies: - aria-query "^0.7.0" + aria-query "^3.0.0" array-includes "^3.0.3" - ast-types-flow "0.0.7" - axobject-query "^0.1.0" - damerau-levenshtein "^1.0.0" - emoji-regex "^6.1.0" - jsx-ast-utils "^2.0.0" - -eslint-plugin-react@^7.5.1: - version "7.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160" - dependencies: - doctrine "^2.0.2" - has "^1.0.1" + ast-types-flow "^0.0.7" + axobject-query "^2.0.2" + damerau-levenshtein "^1.0.4" + emoji-regex "^7.0.2" + has "^1.0.3" jsx-ast-utils "^2.0.1" - prop-types "^15.6.0" + +eslint-plugin-node@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-8.0.1.tgz#55ae3560022863d141fa7a11799532340a685964" + integrity sha512-ZjOjbjEi6jd82rIpFSgagv4CHWzG9xsQAVp1ZPlhRnnYxcTgENUVBvhYmkQ7GvT1QFijUSo69RaiOJKhMu6i8w== + dependencies: + eslint-plugin-es "^1.3.1" + eslint-utils "^1.3.1" + ignore "^5.0.2" + minimatch "^3.0.4" + resolve "^1.8.1" + semver "^5.5.0" + +eslint-plugin-promise@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz#2d074b653f35a23d1ba89d8e976a985117d1c6a2" + integrity sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg== + +eslint-plugin-react@7.12.4: + version "7.12.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz#b1ecf26479d61aee650da612e425c53a99f48c8c" + integrity sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ== + dependencies: + array-includes "^3.0.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + object.fromentries "^2.0.0" + prop-types "^15.6.2" + resolve "^1.9.0" eslint-restricted-globals@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" + integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc= -eslint-scope@^3.7.1, eslint-scope@~3.7.1: +eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^4.0.0, eslint-scope@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.2.tgz#5f10cd6cabb1965bf479fa65745673439e21cb0e" + integrity sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.0, eslint-utils@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== -eslint@^4.16.0: - version "4.18.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" +eslint@5.15.1: + version "5.15.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.15.1.tgz#8266b089fd5391e0009a047050795b1d73664524" + integrity sha512-NTcm6vQ+PTgN3UBsALw5BMhgO6i5EpIjQF/Xb5tIh3sk9QhrFafujUOczGz4J24JBlzWclSB9Vmx8d+9Z6bFCg== dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.2" + eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" - espree "^3.5.2" - esquery "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" esutils "^2.0.2" - file-entry-cache "^2.0.0" + file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" + inquirer "^6.2.2" + js-yaml "^3.12.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" + lodash "^4.17.11" + minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" path-is-inside "^1.0.2" - pluralize "^7.0.0" progress "^2.0.0" - require-uncached "^1.0.3" - semver "^5.3.0" + regexpp "^2.0.1" + semver "^5.5.1" strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" -espree@^3.5.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.3.tgz#931e0af64e7fbbed26b050a29daad1fc64799fa6" +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== dependencies: - acorn "^5.4.0" - acorn-jsx "^3.0.0" - -esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" +esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= -esutils@^2.0.2: +esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" +eventemitter3@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== + +events@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== dependencies: - d "1" - es5-ext "~0.10.14" - -eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" - -events@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - -eventsource@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" - dependencies: - original ">=0.0.5" + original "^1.0.0" evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== dependencies: md5.js "^1.3.4" safe-buffer "^5.1.1" +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -2479,15 +2898,23 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: - is-posix-bracket "^0.1.0" + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -2497,81 +2924,77 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= dependencies: - fill-range "^2.1.0" + homedir-polyfill "^1.0.1" express@^4.16.2: - version "4.16.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== dependencies: - accepts "~1.3.4" + accepts "~1.3.5" array-flatten "1.1.1" - body-parser "1.18.2" + body-parser "1.18.3" content-disposition "0.5.2" content-type "~1.0.4" cookie "0.3.1" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.1" - encodeurl "~1.0.1" + depd "~1.1.2" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.0" + finalhandler "1.1.1" fresh "0.5.2" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.2" path-to-regexp "0.1.7" - proxy-addr "~2.0.2" - qs "6.5.1" + proxy-addr "~2.0.4" + qs "6.5.2" range-parser "~1.2.0" - safe-buffer "5.1.1" - send "0.16.1" - serve-static "1.13.1" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" setprototypeof "1.1.0" - statuses "~1.3.1" - type-is "~1.6.15" + statuses "~1.4.0" + type-is "~1.6.16" utils-merge "1.0.1" vary "~1.1.2" extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -external-editor@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" +external-editor@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" + chardet "^0.7.0" + iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -2582,45 +3005,39 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-levenshtein@~2.0.4: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -fastparse@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.0: +faye-websocket@~0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= dependencies: websocket-driver ">=0.5.1" -fbjs@^0.8.1, fbjs@^0.8.16: - version "0.8.16" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" +fbjs@^0.8.1: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= dependencies: core-js "^1.0.0" isomorphic-fetch "^2.1.1" @@ -2628,82 +3045,85 @@ fbjs@^0.8.1, fbjs@^0.8.16: object-assign "^4.1.0" promise "^7.1.1" setimmediate "^1.0.5" - ua-parser-js "^0.7.9" + ua-parser-js "^0.7.18" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" + flat-cache "^2.0.1" -file-loader@^1.1.6: - version "1.1.11" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.11.tgz#6fe886449b0f2a936e43cabaac0cdbfb369506f8" +file-loader@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" + integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== dependencies: loader-utils "^1.0.2" - schema-utils "^0.4.5" + schema-utils "^1.0.0" -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" +filesize@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" repeat-string "^1.6.1" to-regex-range "^2.1.0" -finalhandler@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== dependencies: debug "2.6.9" - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" on-finished "~2.3.0" parseurl "~1.3.2" - statuses "~1.3.1" + statuses "~1.4.0" unpipe "~1.0.0" find-cache-dir@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= dependencies: commondir "^1.0.1" mkdirp "^0.5.1" pkg-dir "^1.0.0" -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== dependencies: commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" + make-dir "^2.0.0" + pkg-dir "^3.0.0" find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -2711,38 +3131,60 @@ find-up@^1.0.0: find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" + locate-path "^3.0.0" -flatten@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" +findup-sync@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= + dependencies: + detect-file "^1.0.0" + is-glob "^3.1.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" -flow-bin-loader@^1.0.2: +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" + integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== + +flow-bin-loader@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/flow-bin-loader/-/flow-bin-loader-1.0.3.tgz#1b95260437bea24786a5abc022ef3efa02df77c5" + integrity sha512-JgbydYGf7/Di8Jq4Az3+58g8lreabVdzI3IZQFICpQSH+yK8Uhgc1+Os5rnFBUfAQuhx3imUjpfOjaTLlz8M5A== -flow-bin@^0.63.1: - version "0.63.1" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.63.1.tgz#ab00067c197169a5fb5b4996c8f6927b06694828" +flow-bin@0.94.0: + version "0.94.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.94.0.tgz#b5d58fe7559705b73a18229f97edfc3ab6ffffcb" + integrity sha512-DYF7r9CJ/AksfmmB4+q+TyLMoeQPRnqtF1Pk7KY3zgfkB/nVuA3nXyzqgsIPIvnMSiFEXQcFK4z+iPxSLckZhQ== -flow-typed@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/flow-typed/-/flow-typed-2.3.0.tgz#0f8604faab60691b885024e16ec0e3256e3b680e" +flow-typed@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/flow-typed/-/flow-typed-2.5.1.tgz#0ff565cc94d2af8c557744ba364b6f14726a6b9f" + integrity sha1-D/VlzJTSr4xVd0S6NktvFHJqa58= dependencies: + "@octokit/rest" "^15.2.6" babel-polyfill "^6.26.0" colors "^1.1.2" fs-extra "^5.0.0" - github "0.2.4" glob "^7.1.2" got "^7.1.0" md5 "^2.1.0" @@ -2751,110 +3193,123 @@ flow-typed@^2.2.3: semver "^5.5.0" table "^4.0.2" through "^2.3.8" - unzip "^0.1.11" + unzipper "^0.8.11" which "^1.3.0" yargs "^4.2.0" -font-awesome@^4.3.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" -for-in@^1.0.1, for-in@^1.0.2: +follow-redirects@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== + dependencies: + debug "^3.2.6" + +for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fp-ts@^1.0.0, fp-ts@^1.0.1: + version "1.14.4" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.14.4.tgz#df431e1bfe590f23ad418ca8c889880106a5008f" + integrity sha512-A20kqVBpV/VOpDmEDudb+FP/qOV+V/yEqHQQfHPHLHeX3alFM0JjX1cXNcU8+p8z5yeCkHFolKo7uJMRwUSMFA== fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" +fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" + nan "^2.9.2" + node-pre-gyp "^0.10.0" -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -"fstream@>= 0.1.30 < 1": - version "0.1.31" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-0.1.31.tgz#7337f058fbbbbefa8c9f561a28cab0849202c988" - dependencies: - graceful-fs "~3.0.2" - inherits "~2.0.0" - mkdirp "0.5" - rimraf "2" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: +fstream@~1.0.10: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2, function-bind@^1.1.1: +function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2866,56 +3321,39 @@ gauge@~2.7.3: wide-align "^1.1.0" get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -github@0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" - dependencies: - mime "^1.2.11" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= dependencies: is-glob "^3.1.0" path-dirname "^1.0.0" -glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" +glob@^7.0.3, glob@^7.1.2, glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2924,39 +3362,43 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -global@~4.3.0: +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= dependencies: min-document "^2.19.0" process "~0.5.1" -globals@^11.0.1: - version "11.3.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0" - -globals@^11.1.0: - version "11.5.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" - -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" +globals@^11.1.0, globals@^11.7.0: + version "11.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" + integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= dependencies: array-union "^1.0.1" glob "^7.0.3" @@ -2967,6 +3409,7 @@ globby@^6.1.0: got@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== dependencies: decompress-response "^3.2.0" duplexer3 "^0.1.4" @@ -2983,66 +3426,70 @@ got@^7.1.0: url-parse-lax "^1.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -graceful-fs@~3.0.2: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - dependencies: - natives "^1.1.0" - -handle-thing@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -has-ansi@^2.0.0: +handle-thing@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +handlebars@^4.0.11: + version "4.1.0" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" + integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== dependencies: - ansi-regex "^2.0.0" + async "^2.5.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -3051,6 +3498,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -3059,198 +3507,252 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: - function-bind "^1.0.2" - -hash-base@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" - dependencies: - inherits "^2.0.1" + function-bind "^1.1.1" hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== dependencies: inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" + minimalistic-assert "^1.0.1" hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= dependencies: hash.js "^1.0.3" minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - hoist-non-react-statics@^2.3.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40" + version "2.5.5" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" +hoist-non-react-statics@^3.2.1, hoist-non-react-statics@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" + react-is "^16.7.0" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" hosted-git-info@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= dependencies: inherits "^2.0.1" obuf "^1.0.0" readable-stream "^2.0.1" wbuf "^1.1.0" -html-comment-regex@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" - html-entities@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= -http-errors@1.6.2, http-errors@~1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= dependencies: - depd "1.1.1" + depd "~1.1.2" inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" http-parser-js@>=0.4.0: - version "0.4.10" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + version "0.5.0" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" + integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w== -http-proxy-middleware@~0.17.4: - version "0.17.4" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833" +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== dependencies: - http-proxy "^1.16.2" - is-glob "^3.1.0" - lodash "^4.17.2" - micromatch "^2.3.11" + agent-base "4" + debug "3.1.0" -http-proxy@^1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" +http-proxy-middleware@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" +http-proxy@^1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +humps@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa" + integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao= hyphenate-style-name@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" + version "1.0.3" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48" + integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ== -iconv-lite@0.4.19, iconv-lite@^0.4.17: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - -iconv-lite@~0.4.13: +iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= -icss-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" +icss-utils@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.0.tgz#339dbbffb9f8729a243b701e1c29d4cc58c52f0e" + integrity sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ== dependencies: - postcss "^6.0.1" + postcss "^7.0.14" ieee754@^1.1.4: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== -ignore@^3.3.3: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -import-local@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== dependencies: - pkg-dir "^2.0.0" + minimatch "^3.0.4" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.0.2: + version "5.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.0.5.tgz#c663c548d6ce186fb33616a8ccb5d46e56bdbbf9" + integrity sha512-kOC8IUb8HSDMVcYrDVezCxpJkzSQWTAzf3olpKM6o9rM5zpojx23O0Fl8Wr4+qJ6ZbPEHqf1fdwev/DS7v7pmA== + +import-fresh@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" + integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" resolve-cwd "^2.0.0" imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" +indefinite-observable@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/indefinite-observable/-/indefinite-observable-1.0.2.tgz#0a328793ab2385d4b9dca23eaab4afe6936a73f8" + integrity sha512-Mps0898zEduHyPhb7UCgNmfzlqNZknVmaFz5qzr0mm04YQ5FGLhAyK/dJ+NaRxGyR6juQXIxh5Ev0xx+qq0nYA== dependencies: - repeating "^2.0.0" + symbol-observable "1.2.0" indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -3258,121 +3760,173 @@ inflight@^1.0.4: inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -ini@~1.3.0: +ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" +inquirer@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" + integrity sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA== dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" + ansi-escapes "^3.2.0" + chalk "^2.4.2" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.0.4" + external-editor "^3.0.3" figures "^2.0.0" - lodash "^4.3.0" + lodash "^4.17.11" mute-stream "0.0.7" run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" + rxjs "^6.4.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" -internal-ip@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" +inspectpack@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/inspectpack/-/inspectpack-4.1.2.tgz#b07dd10f1131c290d2076270470787d61b47097e" + integrity sha512-bd0iIr5P2xRMtjQQkPnUYJSNa3mUFYER/2eQOPAoXrWBnZXMeFVAgRt/Dny8XVdSkkFoNKhumPjjV9QgTDcVxQ== dependencies: - meow "^3.3.0" + chalk "^2.4.0" + io-ts "^1.0.5" + io-ts-reporters "^0.0.20" + pify "^3.0.0" + semver-compare "^1.0.0" + yargs "^11.0.0" -interpret@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" +internal-ip@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.2.0.tgz#46e81b638d84c338e5c67e42b1a17db67d0814fa" + integrity sha512-ZY8Rk+hlvFeuMmG5uH1MXhhdeMntmIaxaInvAmzMq/SHV8rv4Kh+6GiQNNDQd0wZFrcO+FiTBo8lui/osKOyJw== + dependencies: + default-gateway "^4.0.1" + ipaddr.js "^1.9.0" -invariant@^2.2.0, invariant@^2.2.2: +interpret@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +io-ts-reporters@^0.0.20: + version "0.0.20" + resolved "https://registry.yarnpkg.com/io-ts-reporters/-/io-ts-reporters-0.0.20.tgz#2b8cbb6a2bc4562dae6917a3a413fa2c9851a644" + integrity sha512-ZGyPkto96U8exipqA915ZqxIJsaFLavgZIQOEgg4Pa8qgq1Hl9ZKBtN708ZXPzlAGR/jxofrD4QNT8SHowIDVA== + dependencies: + fp-ts "^1.0.1" + io-ts "^1.0.2" + +io-ts@^1.0.2, io-ts@^1.0.5: + version "1.8.2" + resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.8.2.tgz#4fe3878c147c9851604d36982ee6f64d3e6a4a1e" + integrity sha512-BvP7iC4bgum5e3Fh82xCUrKWt739osKjmQBMORGij2AOMfTmevj8SEqBhN8EeI0GEwIMHb2bXe4fuikN0lsTWg== + dependencies: + fp-ts "^1.0.0" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -ipaddr.js@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" +ipaddr.js@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= dependencies: binary-extensions "^1.0.0" is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - -is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -3381,455 +3935,382 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-function@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-glob@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= dependencies: is-extglob "^2.1.1" is-in-browser@^1.0.2, is-in-browser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" + integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - is-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - -is-odd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" - dependencies: - is-number "^4.0.0" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= dependencies: path-is-inside "^1.0.1" -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: +is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= dependencies: has "^1.0.1" -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= -is-svg@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== dependencies: - html-comment-regex "^1.1.0" - -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + has-symbols "^1.0.0" is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-windows@^1.0.2: +is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= dependencies: node-fetch "^1.0.1" whatwg-fetch ">=0.10.0" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - isurl@^1.0.0-alpha5: version "1.0.0" resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" -js-base64@^2.1.9: - version "2.4.3" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582" +js-beautify@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.9.0.tgz#2562fcdee340f9f962ae2ec4a8a40e7aaa6d964f" + integrity sha512-P0skmY4IDjfLiVrx+GLDeme8w5G0R1IGXgccVU5HP2VM3lRblH7qN2LTea5vZAxrDjpZBD0Jv+ahpjwVcbz/rw== + dependencies: + config-chain "^1.1.12" + editorconfig "^0.15.2" + glob "^7.1.3" + mkdirp "~0.5.0" + nopt "~4.0.1" -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +js-levenshtein@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" + integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== -js-yaml@^3.9.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.12.0: + version "3.12.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.2.tgz#ef1d067c5a9d9cb65bd72f285b5d8105c77f14fc" + integrity sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q== dependencies: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" - dependencies: - argparse "^1.0.7" - esprima "^2.6.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - jsesc@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -json-loader@^0.5.4: - version "0.5.7" - resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= -json5@^0.5.0, json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -jss-camel-case@^6.0.0, jss-camel-case@^6.1.0: +jss-camel-case@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/jss-camel-case/-/jss-camel-case-6.1.0.tgz#ccb1ff8d6c701c02a1fed6fb6fb6b7896e11ce44" + integrity sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ== dependencies: hyphenate-style-name "^1.0.2" -jss-compose@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/jss-compose/-/jss-compose-5.0.0.tgz#ce01b2e4521d65c37ea42cf49116e5f7ab596484" - dependencies: - warning "^3.0.0" - jss-default-unit@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/jss-default-unit/-/jss-default-unit-8.0.2.tgz#cc1e889bae4c0b9419327b314ab1c8e2826890e6" - -jss-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/jss-expand/-/jss-expand-5.1.0.tgz#b1ad74ec18631f34f65a2124fcfceb6400610e3d" - -jss-extend@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/jss-extend/-/jss-extend-6.2.0.tgz#4af09d0b72fb98ee229970f8ca852fec1ca2a8dc" - dependencies: - warning "^3.0.0" + integrity sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg== jss-global@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/jss-global/-/jss-global-3.0.0.tgz#e19e5c91ab2b96353c227e30aa2cbd938cdaafa2" + integrity sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q== jss-nested@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/jss-nested/-/jss-nested-6.0.1.tgz#ef992b79d6e8f63d939c4397b9d99b5cbbe824ca" + integrity sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA== dependencies: warning "^3.0.0" -jss-preset-default@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/jss-preset-default/-/jss-preset-default-4.3.0.tgz#7bc91b0b282492557d36ed4e5c6d7c8cb3154bb8" - dependencies: - jss-camel-case "^6.1.0" - jss-compose "^5.0.0" - jss-default-unit "^8.0.2" - jss-expand "^5.1.0" - jss-extend "^6.2.0" - jss-global "^3.0.0" - jss-nested "^6.0.1" - jss-props-sort "^6.0.0" - jss-template "^1.0.1" - jss-vendor-prefixer "^7.0.0" - jss-props-sort@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/jss-props-sort/-/jss-props-sort-6.0.0.tgz#9105101a3b5071fab61e2d85ea74cc22e9b16323" - -jss-template@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/jss-template/-/jss-template-1.0.1.tgz#09aed9d86cc547b07f53ef355d7e1777f7da430a" - dependencies: - warning "^3.0.0" + integrity sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g== jss-vendor-prefixer@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz#0166729650015ef19d9f02437c73667231605c71" + integrity sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA== dependencies: css-vendor "^0.3.8" -jss@^9.3.2, jss@^9.3.3: - version "9.8.0" - resolved "https://registry.yarnpkg.com/jss/-/jss-9.8.0.tgz#77830def563870103f8671ed31ce3a3d2f32aa2b" +jss@^9.8.7: + version "9.8.7" + resolved "https://registry.yarnpkg.com/jss/-/jss-9.8.7.tgz#ed9763fc0f2f0260fc8260dac657af61e622ce05" + integrity sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ== dependencies: is-in-browser "^1.1.3" symbol-observable "^1.1.0" warning "^3.0.0" -jsx-ast-utils@^2.0.0, jsx-ast-utils@^2.0.1: +jsx-ast-utils@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + integrity sha1-6AGxs5mF4g//yHtA43SAgOLcrH8= dependencies: array-includes "^3.0.3" -keycode@^2.1.9: - version "2.1.9" - resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" - killable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - -lazy-cache@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" - dependencies: - set-getter "^0.1.0" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= dependencies: invert-kv "^1.0.0" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" +listenercount@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -3840,6 +4321,7 @@ load-json-file@^1.0.0: load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -3849,168 +4331,148 @@ load-json-file@^2.0.0: loader-fs-cache@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc" + integrity sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw= dependencies: find-cache-dir "^0.1.1" mkdirp "0.5.1" loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== dependencies: - big.js "^3.1.3" + big.js "^5.2.2" emojis-list "^2.0.0" - json5 "^0.5.0" + json5 "^1.0.1" locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + lodash.assign@^4.0.3, lodash.assign@^4.0.6: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - -lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.3.0, lodash@~4.17.4: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - -lodash@^4.17.4, lodash@^4.2.0: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.4, lodash@~4.17.5: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== loglevel@^1.4.1: version "1.6.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" + integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: - js-tokens "^3.0.0" - -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" + js-tokens "^3.0.0 || ^4.0.0" lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== -lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" +lru-cache@^4.0.1, lru-cache@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" -macaddress@^0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: - pify "^3.0.0" + yallist "^3.0.2" + +macos-release@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.0.0.tgz#7dddf4caf79001a851eb4fba7fb6034f251276ab" + integrity sha512-iCM3ZGeqIzlrH7KxYK+fphlJpCCczyHXc+HhRVbEu9uNTCrzYJjvvtefzeKTCVHd5AP/aD/fzC80JZ4ZP+dQ/A== + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" -"match-stream@>= 0.0.2 < 1": - version "0.0.2" - resolved "https://registry.yarnpkg.com/match-stream/-/match-stream-0.0.2.tgz#99eb050093b34dffade421b9ac0b410a9cfa17cf" - dependencies: - buffers "~0.1.1" - readable-stream "~1.0.0" - -material-ui-icons@^1.0.0-beta.17: - version "1.0.0-beta.35" - resolved "https://registry.yarnpkg.com/material-ui-icons/-/material-ui-icons-1.0.0-beta.35.tgz#f795fafa385918ef7c88ee382e5e5bf4401f008c" - dependencies: - recompose "^0.26.0" - -material-ui@^1.0.0-beta.30: - version "1.0.0-beta.35" - resolved "https://registry.yarnpkg.com/material-ui/-/material-ui-1.0.0-beta.35.tgz#eeac6be307c0469943c7686e5c6bd4eaa6b1b563" - dependencies: - "@types/jss" "^9.3.0" - "@types/react-transition-group" "^2.0.6" - babel-runtime "^6.26.0" - brcast "^3.0.1" - classnames "^2.2.5" - deepmerge "^2.0.1" - dom-helpers "^3.2.1" - hoist-non-react-statics "^2.3.1" - jss "^9.3.3" - jss-camel-case "^6.0.0" - jss-default-unit "^8.0.2" - jss-global "^3.0.0" - jss-nested "^6.0.1" - jss-props-sort "^6.0.0" - jss-vendor-prefixer "^7.0.0" - keycode "^2.1.9" - lodash "^4.2.0" - normalize-scroll-left "^0.1.2" - prop-types "^15.6.0" - react-event-listener "^0.5.1" - react-jss "^8.1.0" - react-popper "^0.8.0" - react-scrollbar-size "^2.0.2" - react-transition-group "^2.2.1" - recompose "^0.26.0" - scroll "^2.0.3" - warning "^3.0.0" - math-expression-evaluator@^1.2.14: version "1.2.17" resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + integrity sha1-3oGf282E3M2PrlnGrreWFbnSZqw= md5.js@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== dependencies: hash-base "^3.0.0" inherits "^2.0.1" + safe-buffer "^5.1.2" md5@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= dependencies: charenc "~0.0.1" crypt "~0.0.1" @@ -4019,64 +4481,46 @@ md5@^2.1.0: media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= dependencies: mimic-fn "^1.0.0" -memory-fs@^0.4.0, memory-fs@~0.4.1: +mem@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.2.0.tgz#5ee057680ed9cb8dad8a78d820f9a8897a102025" + integrity sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= dependencies: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.3.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.1.4: - version "3.1.9" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -4090,93 +4534,178 @@ micromatch@^3.1.4: object.pick "^1.3.0" regex-not "^1.0.0" snapdragon "^0.8.1" - to-regex "^3.0.1" + to-regex "^3.0.2" miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== dependencies: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" +"mime-db@>= 1.38.0 < 2", mime-db@~1.38.0: + version "1.38.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" + integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" +mime-types@~2.1.17, mime-types@~2.1.18: + version "2.1.22" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" + integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== dependencies: - mime-db "~1.33.0" + mime-db "~1.38.0" mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^1.2.11, mime@^1.4.1, mime@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" +mime@^2.0.3, mime@^2.3.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" + integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.0.0.tgz#0913ff0b121db44ef5848242c38bbb35d44cabde" + integrity sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA== mimic-response@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== min-document@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= dependencies: dom-walk "^0.1.0" -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" +most@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/most/-/most-1.7.3.tgz#406c31a66d73aa16957816fdf96965e27df84f1a" + integrity sha512-mk68SM/ptK8WSo3l03raXcWy02Hl7jbzxVozMuvyYxohn4yteh2THhl3+XABF5cunWE8eXHAsLbv+RCJI5y+jg== + dependencies: + "@most/multicast" "^1.2.5" + "@most/prelude" "^1.4.0" + symbol-observable "^1.0.2" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= multicast-dns@^6.0.1: version "6.2.3" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== dependencies: dns-packet "^1.3.1" thunky "^1.0.2" @@ -4184,21 +4713,23 @@ multicast-dns@^6.0.1: mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@^2.3.0: - version "2.9.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866" +nan@^2.9.2: + version "2.13.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.0.tgz#7bdfc27dd3c060c46e60b62c72b74012d1a4cd68" + integrity sha512-5DDQvN0luhXdut8SCwzm/ZuAX2W+fwhqNzfq7CZ+OJzQ6NwpcqmIGyLD1R8MEt7BeErzcsI0JLr4pND2pNp2Cw== nanomatch@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" define-property "^2.0.2" extend-shallow "^3.0.2" fragment-cache "^0.2.1" - is-odd "^2.0.0" is-windows "^1.0.2" kind-of "^6.0.2" object.pick "^1.3.0" @@ -4206,36 +4737,62 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -natives@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.1.tgz#011acce1f7cbd87f7ba6b3093d6cd9392be1c574" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= neo-async@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +neo-blessed@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/neo-blessed/-/neo-blessed-0.2.0.tgz#30f9495fdd104494402b62c6273a9c9b82de4f2b" + integrity sha512-C2kC4K+G2QnNQFXUIxTQvqmrdSIzGTX1ZRKeDW6ChmvPRw8rTkTEJzbEQHiHy06d36PCl/yMOCjquCRV8SpSQw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== dependencies: encoding "^0.1.11" is-stream "^1.0.1" -node-forge@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300" +node-fetch@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" + integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + version "2.2.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.0.tgz#c72f60d9d46de08a940dedbb25f3ffa2f9bbaa77" + integrity sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA== dependencies: assert "^1.1.1" browserify-zlib "^0.2.0" @@ -4244,7 +4801,7 @@ node-libs-browser@^2.0.0: constants-browserify "^1.0.0" crypto-browserify "^3.11.0" domain-browser "^1.1.1" - events "^1.0.0" + events "^3.0.0" https-browserify "^1.0.0" os-browserify "^0.3.0" path-browserify "0.0.0" @@ -4258,165 +4815,233 @@ node-libs-browser@^2.0.0: timers-browserify "^2.0.4" tty-browserify "0.0.0" url "^0.11.0" - util "^0.10.3" + util "^0.11.0" vm-browserify "0.0.4" -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== dependencies: detect-libc "^1.0.2" - hawk "3.1.3" mkdirp "^0.5.1" + needle "^2.2.1" nopt "^4.0.1" + npm-packlist "^1.1.6" npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" + rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" + tar "^4" -nopt@^4.0.1: +node-releases@^1.1.8: + version "1.1.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.10.tgz#5dbeb6bc7f4e9c85b899e2e7adcc0635c9b2adf7" + integrity sha512-KbUPCpfoBvb3oBkej9+nrU0/7xPlVhmhhUJ1PZqwIP5/1dJkRWKWD3OONjo6M2J7tSCBtDCumLwwqeI+DWWaLQ== + dependencies: + semver "^5.3.0" + +nopt@^4.0.1, nopt@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= dependencies: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" + resolve "^1.10.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-scroll-left@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-scroll-left/-/normalize-scroll-left-0.1.2.tgz#6b79691ba79eb5fb107fa5edfbdc06b55caee2aa" + integrity sha512-F9YMRls0zCF6BFIE2YnXDRpHPpfd91nOIaNdDgrx5YMoPLo8Wqj+6jNXHQsYBavJeXP4ww8HCt0xQAKc5qk2Fg== -normalize-url@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.1" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" + integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== dependencies: - object-assign "^4.0.1" - prepend-http "^1.0.0" - query-string "^4.1.0" - sort-keys "^1.0.0" + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" gauge "~2.7.3" set-blocking "~2.0.0" -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" object-hash@^1.1.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.2.0.tgz#e96af0e96981996a1d47f88ead8f74f1ebc4422b" + version "1.3.1" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" + integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== -object-keys@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" + integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg== object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.entries@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" + integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + +object.fromentries@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab" + integrity sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA== + dependencies: + define-properties "^1.1.2" + es-abstract "^1.11.0" + function-bind "^1.1.1" + has "^1.0.1" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" -obuf@^1.0.0, obuf@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= dependencies: ee-first "1.1.1" on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0, once@^1.3.3: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= dependencies: mimic-fn "^1.0.0" opn@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" + version "5.4.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" + integrity sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw== dependencies: is-wsl "^1.1.0" +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -4425,161 +5050,259 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -original@>=0.0.5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== dependencies: - url-parse "1.0.x" + url-parse "^1.4.3" os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= dependencies: lcid "^1.0.0" os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== dependencies: execa "^0.7.0" lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.0.0.tgz#e1434dbfddb8e74b44c98b56797d951b7648a5d9" + integrity sha512-7c74tib2FsdFbQ3W+qj8Tyd1R3Z6tuVRNNxXjJcZ4NgjIEQU9N/prVMqcW29XZPXGACqaXN3jq58/6hoaoXH6g== + dependencies: + macos-release "^2.0.0" + windows-release "^3.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -"over@>= 0.0.5 < 1": - version "0.0.5" - resolved "https://registry.yarnpkg.com/over/-/over-0.0.5.tgz#f29852e70fd7e25f360e013a8ec44c82aedb5708" - p-cancelable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" + integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg== p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + p-map@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== p-timeout@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== pako@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + version "1.0.10" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" + integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5" + integrity sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA== + dependencies: + callsites "^3.0.0" parse-asn1@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + version "5.1.4" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" + integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" create-hash "^1.1.0" evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" + safe-buffer "^5.1.1" parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: +path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= -path-key@^2.0.0: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -4588,19 +5311,22 @@ path-type@^1.0.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^2.0.0" path@^0.12.7: version "0.12.7" resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= dependencies: process "^0.11.1" util "^0.10.3" pbkdf2@^3.0.3: - version "3.0.14" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== dependencies: create-hash "^1.1.2" create-hmac "^1.1.4" @@ -4608,55 +5334,68 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= dependencies: find-up "^1.0.0" pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= dependencies: find-up "^2.1.0" -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" -popper.js@^1.12.9: - version "1.12.9" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.12.9.tgz#0dfbc2dff96c451bb332edcfcfaaf566d331d5b3" +popper.js@^1.14.1: + version "1.14.7" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" + integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ== portfinder@^1.0.9: - version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== dependencies: async "^1.5.2" debug "^2.2.0" @@ -4665,404 +5404,245 @@ portfinder@^1.0.9: posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -postcss-calc@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" - dependencies: - postcss "^5.0.2" - postcss-message-helpers "^2.0.0" - reduce-css-calc "^1.2.6" - -postcss-colormin@^2.1.8: - version "2.2.2" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" - dependencies: - colormin "^1.0.5" - postcss "^5.0.13" - postcss-value-parser "^3.2.3" - -postcss-convert-values@^2.3.4: - version "2.6.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" - dependencies: - postcss "^5.0.11" - postcss-value-parser "^3.1.2" - -postcss-discard-comments@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" - dependencies: - postcss "^5.0.14" - -postcss-discard-duplicates@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" - dependencies: - postcss "^5.0.4" - -postcss-discard-empty@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" - dependencies: - postcss "^5.0.14" - -postcss-discard-overridden@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" - dependencies: - postcss "^5.0.16" - -postcss-discard-unused@^2.2.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" - dependencies: - postcss "^5.0.14" - uniqs "^2.0.0" - -postcss-filter-plugins@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" - dependencies: - postcss "^5.0.4" - uniqid "^4.0.0" - -postcss-merge-idents@^2.1.5: - version "2.1.7" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" - dependencies: - has "^1.0.1" - postcss "^5.0.10" - postcss-value-parser "^3.1.1" - -postcss-merge-longhand@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" - dependencies: - postcss "^5.0.4" - -postcss-merge-rules@^2.0.3: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" - dependencies: - browserslist "^1.5.2" - caniuse-api "^1.5.2" - postcss "^5.0.4" - postcss-selector-parser "^2.2.2" - vendors "^1.0.0" - -postcss-message-helpers@^2.0.0: +postcss-modules-extract-imports@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" - -postcss-minify-font-values@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== dependencies: - object-assign "^4.0.1" - postcss "^5.0.4" - postcss-value-parser "^3.0.2" + postcss "^7.0.5" -postcss-minify-gradients@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" +postcss-modules-local-by-default@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" + integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== dependencies: - postcss "^5.0.12" - postcss-value-parser "^3.3.0" + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + postcss-value-parser "^3.3.1" -postcss-minify-params@^1.0.4: - version "1.2.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" +postcss-modules-scope@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" + integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== dependencies: - alphanum-sort "^1.0.1" - postcss "^5.0.2" - postcss-value-parser "^3.0.2" - uniqs "^2.0.0" + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" -postcss-minify-selectors@^2.0.4: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" - dependencies: - alphanum-sort "^1.0.2" - has "^1.0.1" - postcss "^5.0.14" - postcss-selector-parser "^2.0.0" - -postcss-modules-extract-imports@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" - dependencies: - postcss "^6.0.1" - -postcss-modules-local-by-default@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-scope@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-values@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" +postcss-modules-values@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" + integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== dependencies: icss-replace-symbols "^1.1.0" - postcss "^6.0.1" + postcss "^7.0.6" -postcss-normalize-charset@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" +postcss-selector-parser@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== dependencies: - postcss "^5.0.5" - -postcss-normalize-url@^3.0.7: - version "3.0.8" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^1.4.0" - postcss "^5.0.14" - postcss-value-parser "^3.2.3" - -postcss-ordered-values@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" - dependencies: - postcss "^5.0.4" - postcss-value-parser "^3.0.1" - -postcss-reduce-idents@^2.2.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" - dependencies: - postcss "^5.0.4" - postcss-value-parser "^3.0.2" - -postcss-reduce-initial@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" - dependencies: - postcss "^5.0.4" - -postcss-reduce-transforms@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" - dependencies: - has "^1.0.1" - postcss "^5.0.8" - postcss-value-parser "^3.0.1" - -postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" - dependencies: - flatten "^1.0.2" + cssesc "^3.0.0" indexes-of "^1.0.1" uniq "^1.0.1" -postcss-svgo@^2.1.1: - version "2.1.6" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" - dependencies: - is-svg "^2.0.0" - postcss "^5.0.14" - postcss-value-parser "^3.2.3" - svgo "^0.7.0" +postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss-unique-selectors@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" +postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== dependencies: - alphanum-sort "^1.0.1" - postcss "^5.0.4" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" - -postcss-zindex@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" - dependencies: - has "^1.0.1" - postcss "^5.0.4" - uniqs "^2.0.0" - -postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16: - version "5.2.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" - dependencies: - chalk "^1.1.3" - js-base64 "^2.1.9" - source-map "^0.5.6" - supports-color "^3.2.3" - -postcss@^6.0.1: - version "6.0.19" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.19.tgz#76a78386f670b9d9494a655bf23ac012effd1555" - dependencies: - chalk "^2.3.1" + chalk "^2.4.2" source-map "^0.6.1" - supports-color "^5.2.0" + supports-color "^6.1.0" prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.0, prepend-http@^1.0.1: +prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -private@^0.1.6, private@^0.1.8: +private@^0.1.6: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== process@^0.11.1, process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== dependencies: asap "~2.0.3" -prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0: - version "15.6.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" +prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +prop-types@~15.6.0: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== dependencies: - fbjs "^0.8.16" loose-envify "^1.3.1" object-assign "^4.1.1" -proxy-addr@~2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== dependencies: forwarded "~0.1.2" - ipaddr.js "1.6.0" + ipaddr.js "1.8.0" prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= public-encrypt@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== dependencies: bn.js "^4.1.0" browserify-rsa "^4.0.0" create-hash "^1.1.0" parse-asn1 "^5.0.0" randombytes "^2.0.1" + safe-buffer "^5.1.2" -"pullstream@>= 0.4.1 < 1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== dependencies: - over ">= 0.0.5 < 1" - readable-stream "~1.0.31" - setimmediate ">= 1.0.2 < 2" - slice-stream ">= 1.0.0 < 2" + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^1.2.4, punycode@^1.4.1: +punycode@^1.2.4: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -query-string@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" - dependencies: - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" +qs@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -querystringify@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" +querystringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== -querystringify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" - -raf@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" +raf@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== dependencies: performance-now "^2.1.0" -rafl@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rafl/-/rafl-1.2.2.tgz#fe930f758211020d47e38815f5196a8be4150740" - dependencies: - global "~4.3.0" - -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" randomfill@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== dependencies: randombytes "^2.0.5" safe-buffer "^5.1.0" @@ -5070,114 +5650,116 @@ randomfill@^1.0.3: range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= -raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== dependencies: bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" + http-errors "1.6.3" + iconv-lite "0.4.23" unpipe "1.0.0" -rc@^1.1.7: - version "1.2.5" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: - deep-extend "~0.4.0" + deep-extend "^0.6.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" -react-dom@^16.2.0: - version "16.4.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" +react-dom@16.8.4: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.4.tgz#1061a8e01a2b3b0c8160037441c3bf00a0e3bc48" + integrity sha512-Ob2wK7XG2tUDt7ps7LtLzGYYB6DXMCLj0G5fO6WeEICtT4/HdpOi7W/xLzZnR6RCG1tYza60nMdqtxzA8FaPJQ== dependencies: - fbjs "^0.8.16" loose-envify "^1.1.0" object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.13.4" + +react-event-listener@^0.6.2: + version "0.6.6" + resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.6.tgz#758f7b991cad9086dd39fd29fad72127e1d8962a" + integrity sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw== + dependencies: + "@babel/runtime" "^7.2.0" prop-types "^15.6.0" + warning "^4.0.1" -react-event-listener@^0.5.1: - version "0.5.3" - resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.5.3.tgz#a8b492596ad601865314fcc2c18cb87b6ce3876e" +react-hot-loader@4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.8.0.tgz#0b7c7dd9407415e23eb8246fdd28b0b839f54cb6" + integrity sha512-HY9F0vITYSVmXhAR6tPkMk240nxmoH8+0rca9iO2B82KVguiCiBJkieS0Wb4CeSIzLWecYx3iOcq8dcbnp0bxA== dependencies: - babel-runtime "^6.26.0" - fbjs "^0.8.16" + fast-levenshtein "^2.0.6" + global "^4.3.0" + hoist-non-react-statics "^3.3.0" + loader-utils "^1.1.0" + lodash "^4.17.11" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + shallowequal "^1.0.2" + source-map "^0.7.3" + +react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" + integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== + +react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-resize-detector@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-2.3.0.tgz#57bad1ae26a28a62a2ddb678ba6ffdf8fa2b599c" + integrity sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ== + dependencies: + lodash.debounce "^4.0.8" + lodash.throttle "^4.1.1" prop-types "^15.6.0" - warning "^3.0.0" + resize-observer-polyfill "^1.5.0" -react-fa@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/react-fa/-/react-fa-5.0.0.tgz#d571732856c6cb2c155c46daef018ba67a75b973" - dependencies: - font-awesome "^4.3.0" - prop-types "^15.5.8" - -react-jss@^8.1.0: - version "8.3.3" - resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-8.3.3.tgz#677a57569d3e4f5099fcdeafeddd8d2c62ab5977" - dependencies: - hoist-non-react-statics "^2.3.1" - jss "^9.3.2" - jss-preset-default "^4.3.0" - prop-types "^15.6.0" - theming "^1.3.0" - -react-popper@^0.8.0: - version "0.8.2" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-0.8.2.tgz#092095ff13933211d3856d9f325511ec3a42f12c" - dependencies: - popper.js "^1.12.9" - prop-types "^15.6.0" - -react-resize-detector@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-1.1.0.tgz#4a9831fa3caad32230478dd0185cbd2aa91a5ebf" - dependencies: - prop-types "^15.5.10" - -react-scrollbar-size@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/react-scrollbar-size/-/react-scrollbar-size-2.1.0.tgz#105e797135cab92b1f9e16f00071db7f29f80754" - dependencies: - babel-runtime "^6.26.0" - prop-types "^15.6.0" - react-event-listener "^0.5.1" - stifle "^1.0.2" - -react-smooth@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.0.tgz#b29dbebddddb06d21b5b08962167fb9eac1897d8" +react-smooth@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.2.tgz#f7a2d932ece8db898646078c3c97f3e9533e0486" + integrity sha512-pIGzL1g9VGAsRsdZQokIK0vrCkcdKtnOnS1gyB2rrowdLy69lNSWoIjCTWAfgbiYvria8tm5hEZqj+jwXMkV4A== dependencies: lodash "~4.17.4" prop-types "^15.6.0" - raf "^3.2.0" - react-transition-group "^2.2.1" + raf "^3.4.0" + react-transition-group "^2.5.0" -react-transition-group@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10" +react-transition-group@2.6.1, react-transition-group@^2.2.1, react-transition-group@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.6.1.tgz#abf4a95e2f13fb9ba83a970a896fedbc5c4856a2" + integrity sha512-9DHwCy0aOYEe35frlEN68N9ut/THDQBLnVoQuKTvzF4/s3tk7lqkefCqxK2Nv96fOh6JXk6tQtliygk6tl3bQA== dependencies: - chain-function "^1.0.0" - classnames "^2.2.5" - dom-helpers "^3.2.0" - loose-envify "^1.3.1" - prop-types "^15.5.8" - warning "^3.0.0" + dom-helpers "^3.3.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-lifecycles-compat "^3.0.4" -react@^16.2.0: - version "16.4.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585" +react@16.8.4: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react/-/react-16.8.4.tgz#fdf7bd9ae53f03a9c4cd1a371432c206be1c4768" + integrity sha512-0GQ6gFXfUH7aZcjGVymlPOASTuSjlQL4ZtVC5YKH+3JL6bBLCVO21DknzmaPlI90LN253ojj02nsapy+j7wIjg== dependencies: - fbjs "^0.8.16" loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.0" + prop-types "^15.6.2" + scheduler "^0.13.4" read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -5185,6 +5767,7 @@ read-pkg-up@^1.0.1: read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= dependencies: find-up "^2.0.0" read-pkg "^2.0.0" @@ -5192,6 +5775,7 @@ read-pkg-up@^2.0.0: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -5200,92 +5784,96 @@ read-pkg@^1.0.0: read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071" +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~2.0.0" safe-buffer "~5.1.1" - string_decoder "~1.0.3" + string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^2.2.9: - version "2.3.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" +readable-stream@^3.0.6: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.2.0.tgz#de17f229864c120a9f56945756e4f32c4045245d" + integrity sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw== dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" -readable-stream@~1.0.0, readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" +readable-stream@~2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + integrity sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA= dependencies: + buffer-shims "^1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" - isarray "0.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" string_decoder "~0.10.x" + util-deprecate "~1.0.1" -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" + graceful-fs "^4.1.11" + micromatch "^3.1.10" readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" -recharts-scale@0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.3.2.tgz#dac7621714a4765d152cb2adbc30c73b831208c9" - -recharts@^1.0.0-beta.9: - version "1.0.0-beta.10" - resolved "https://registry.yarnpkg.com/recharts/-/recharts-1.0.0-beta.10.tgz#d3cd15df6b7879d5968da3c942b5fcdaf2504fe1" +recharts-scale@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.2.tgz#b66315d985cd9b80d5f7d977a5aab9a305abc354" + integrity sha512-p/cKt7j17D1CImLgX2f5+6IXLbRHGUQkogIp06VUoci/XkhOQiGSzUrsD1uRmiI7jha4u8XNFOjkHkzzBPivMg== dependencies: - classnames "2.2.5" - core-js "2.5.1" - d3-interpolate "^1.1.5" - d3-scale "1.0.6" - d3-shape "1.2.0" - lodash "~4.17.4" - prop-types "^15.6.0" - react-resize-detector "1.1.0" - react-smooth "1.0.0" - recharts-scale "0.3.2" - reduce-css-calc "1.3.0" + decimal.js-light "^2.4.1" -recompose@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.26.0.tgz#9babff039cb72ba5bd17366d55d7232fbdfb2d30" +recharts@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-1.5.0.tgz#ecb4f015cec5b1284294954b7906c7c2ec6e25be" + integrity sha512-bsKJRvh4NepPJlXoI4L9oRKhrv59W7fjs6qTqk6le9MFAywe8EYiW/t07RDQHBVIj6icb+UdSFsHxEo8c5AcTg== dependencies: + classnames "~2.2.5" + core-js "~2.5.1" + d3-interpolate "~1.3.0" + d3-scale "~2.1.0" + d3-shape "~1.2.0" + lodash "~4.17.5" + prop-types "~15.6.0" + react-resize-detector "~2.3.0" + react-smooth "~1.0.0" + recharts-scale "^0.4.2" + reduce-css-calc "~1.3.0" + +"recompose@0.28.0 - 0.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" + integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== + dependencies: + "@babel/runtime" "^7.0.0" change-emitter "^0.1.2" fbjs "^0.8.1" hoist-non-react-statics "^2.3.1" + react-lifecycles-compat "^3.0.2" symbol-observable "^1.0.4" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - -reduce-css-calc@1.3.0, reduce-css-calc@^1.2.6: +reduce-css-calc@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY= dependencies: balanced-match "^0.4.2" math-expression-evaluator "^1.2.14" @@ -5294,159 +5882,162 @@ reduce-css-calc@1.3.0, reduce-css-calc@^1.2.6: reduce-function-call@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + integrity sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk= dependencies: balanced-match "^0.4.2" -regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" +regenerate-unicode-properties@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.2.tgz#7b38faa296252376d363558cfbda90c9ce709662" + integrity sha512-SbA/iNrBUf6Pv2zU8Ekv1Qbhv92yxL4hiDa2siuxs4KKn4oOoMDHXjAf7+Nz9qinUQ46B1LcWEi/PhJfPWpZWQ== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + +regenerator-transform@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" + integrity sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A== dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" private "^0.1.6" -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpu-core@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: +regexp-tree@^0.1.0: version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.5.tgz#7cd71fca17198d04b4176efd79713f2998009397" + integrity sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpu-core@^4.1.3, regexpu-core@^4.2.0: + version "4.5.4" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" + integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.0.2" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + +regjsgen@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" + integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== + +regjsparser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" + integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== dependencies: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.5.2, repeat-string@^1.6.1: +repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: +requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= dependencies: resolve-from "^3.0.0" -resolve-from@^1.0.0: +resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" +resolve@^1.10.0, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1, resolve@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== dependencies: - path-parse "^1.0.5" + path-parse "^1.0.6" restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -5454,101 +6045,114 @@ restore-cursor@^2.0.0: ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" +rimraf@2, rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: - align-text "^0.1.1" - -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" + glob "^7.1.3" ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== dependencies: - hash-base "^2.0.0" + hash-base "^3.0.0" inherits "^2.0.1" run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= dependencies: is-promise "^2.1.0" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= dependencies: - rx-lite "*" + aproba "^1.1.1" -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" +rxjs@^6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" + integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== + dependencies: + tslib "^1.9.0" -safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@~1.2.1: +sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -schema-utils@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" +scheduler@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.4.tgz#8fef05e7a3580c76c0364d2df5e550e4c9140298" + integrity sha512-cvSOlRPxOHs5dAhP9yiS/6IDmVAVxmk33f0CtTJRkmUWcb1Us+t7b1wqdzoC0REw2muC9V5f1L/w5R5uKGaepA== dependencies: - ajv "^5.0.0" + loose-envify "^1.1.0" + object-assign "^4.1.1" -schema-utils@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== dependencies: ajv "^6.1.0" + ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -scroll@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/scroll/-/scroll-2.0.3.tgz#0951b785544205fd17753bc3d294738ba16fc2ab" - dependencies: - rafl "~1.2.1" - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= selfsigned@^1.9.1: - version "1.10.2" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.2.tgz#b4449580d99929b65b10a48389301a6592088758" + version "1.10.4" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" + integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== dependencies: - node-forge "0.7.1" + node-forge "0.7.5" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -send@0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== dependencies: debug "2.6.9" - depd "~1.1.1" + depd "~1.1.2" destroy "~1.0.4" - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" @@ -5557,11 +6161,17 @@ send@0.16.1: ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" - statuses "~1.3.1" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879" + integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw== serve-index@^1.7.2: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= dependencies: accepts "~1.3.4" batch "0.6.1" @@ -5571,32 +6181,25 @@ serve-index@^1.7.2: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== dependencies: - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.2" - send "0.16.1" + send "0.16.2" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-getter@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" - dependencies: - to-object-path "^0.3.0" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -5606,64 +6209,78 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" is-plain-object "^2.0.3" split-string "^3.0.1" -"setimmediate@>= 1.0.1 < 2", "setimmediate@>= 1.0.2 < 2", setimmediate@^1.0.4, setimmediate@^1.0.5: +setimmediate@^1.0.4, setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.10" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" +shallowequal@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= slice-ansi@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== dependencies: is-fullwidth-code-point "^2.0.0" -"slice-stream@>= 1.0.0 < 2": - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== dependencies: - readable-stream "~1.0.31" + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -5672,12 +6289,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370" + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" @@ -5686,309 +6305,355 @@ snapdragon@^0.8.1: map-cache "^0.2.2" source-map "^0.5.6" source-map-resolve "^0.5.0" - use "^2.0.0" + use "^3.1.0" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= -sockjs-client@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" +socket.io-client@2.2.0, socket.io-client@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + integrity sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA== dependencies: - debug "^2.6.6" - eventsource "0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b" + integrity sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w== + dependencies: + debug "~4.1.0" + engine.io "~3.3.1" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.2.0" + socket.io-parser "~3.3.0" + +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" json3 "^3.3.2" - url-parse "^1.1.8" + url-parse "^1.4.3" sockjs@0.3.19: version "0.3.19" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== dependencies: faye-websocket "^0.10.0" uuid "^3.0.1" -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - dependencies: - is-plain-obj "^1.0.0" - source-list-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-map-resolve@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== dependencies: - atob "^2.0.0" + atob "^2.1.1" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" +source-map-support@~0.5.10: + version "0.5.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2" + integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ== dependencies: - source-map "^0.5.6" + buffer-from "^1.0.0" + source-map "^0.6.0" source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" + integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== + +spdy-transport@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - -spdy-transport@^2.0.18: - version "2.0.20" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.20.tgz#735e72054c486b2354fe89e702256004a39ace4d" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== dependencies: - debug "^2.6.8" - detect-node "^2.0.3" + debug "^4.1.0" + detect-node "^2.0.4" hpack.js "^2.1.6" - obuf "^1.1.1" - readable-stream "^2.2.9" - safe-buffer "^5.0.1" - wbuf "^1.7.2" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" -spdy@^3.4.1: - version "3.4.7" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== dependencies: - debug "^2.6.8" - handle-thing "^1.2.5" + debug "^4.1.0" + handle-thing "^2.0.0" http-deceiver "^1.2.7" - safe-buffer "^5.0.1" select-hose "^2.0.0" - spdy-transport "^2.0.18" + spdy-transport "^3.0.0" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" + figgy-pudding "^3.5.1" static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.3.1 < 2": +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - -statuses@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - -stifle@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/stifle/-/stifle-1.0.4.tgz#8b3bcdf52419b0a9c79e35adadce50123c1d8e99" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== stream-browserify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== dependencies: inherits "~2.0.1" readable-stream "^2.0.2" +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + stream-http@^2.7.2: - version "2.8.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.3.3" + readable-stream "^2.3.6" to-arraybuffer "^1.0.0" xtend "^4.0.0" -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= -string-width@^1.0.1, string-width@^1.0.2: +string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^1.0.0, string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== dependencies: safe-buffer "~5.1.0" string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= -stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0, strip-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.1.0.tgz#55aaa54e33b4c0649a7338a43437b1887d153ec4" + integrity sha512-TjxrkPONqO2Z8QDCpeE2j6n0M6EwxzyDgzEeGp+FbdvaJAt//ClYi6W5my+3ROlC/hZX2KACUwDfK49Ka5eDvg== + dependencies: + ansi-regex "^4.1.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - -strip-json-comments@~2.0.1: +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -style-loader@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.19.1.tgz#591ffc80bcefe268b77c5d9ebc0505d772619f85" +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== dependencies: - loader-utils "^1.0.2" - schema-utils "^0.3.0" + loader-utils "^1.1.0" + schema-utils "^1.0.0" -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -supports-color@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - dependencies: - has-flag "^1.0.0" - -supports-color@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - dependencies: - has-flag "^2.0.0" - -supports-color@^5.1.0, supports-color@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" +supports-color@^5.3.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== dependencies: has-flag "^3.0.0" -svgo@^0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" - dependencies: - coa "~1.0.1" - colors "~1.1.2" - csso "~2.3.1" - js-yaml "~3.7.0" - mkdirp "~0.5.1" - sax "~1.2.1" - whet.extend "~0.9.9" - -symbol-observable@^1.0.4, symbol-observable@^1.1.0: +symbol-observable@1.2.0, symbol-observable@^1.0.2, symbol-observable@^1.0.4, symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - -table@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== table@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" + integrity sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg== dependencies: ajv "^6.0.1" ajv-keywords "^3.0.0" @@ -5997,147 +6662,170 @@ table@^4.0.2: slice-ansi "1.0.0" string-width "^2.1.1" -tapable@^0.2.7: - version "0.2.8" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" +table@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2" + integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ== dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" + ajv "^6.9.1" + lodash "^4.17.11" + slice-ansi "^2.1.0" + string-width "^3.0.0" -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e" + integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA== + +tar@^4: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" -text-table@~0.2.0: +terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8" + integrity sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA== + dependencies: + cacache "^11.0.2" + find-cache-dir "^2.0.0" + schema-utils "^1.0.0" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + terser "^3.16.1" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +terser@^3.16.1: + version "3.17.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" + integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ== + dependencies: + commander "^2.19.0" + source-map "~0.6.1" + source-map-support "~0.5.10" + +text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -theming@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/theming/-/theming-1.3.0.tgz#286d5bae80be890d0adc645e5ca0498723725bdc" +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== dependencies: - brcast "^3.0.1" - is-function "^1.0.1" - is-plain-object "^2.0.1" - prop-types "^15.5.8" + readable-stream "~2.3.6" + xtend "~4.0.1" through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= thunky@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371" - -time-stamp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" + version "1.0.3" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" + integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== timed-out@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= timers-browserify@^2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== dependencies: setimmediate "^1.0.4" tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" -to-regex@^3.0.1: +to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@~2.3.0: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - dependencies: - punycode "^1.4.1" - "traverse@>=0.3.0 <0.4": version "0.3.9" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" -type-is@~1.6.15: +type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== dependencies: media-typer "0.3.0" mime-types "~2.1.18" @@ -6145,39 +6833,48 @@ type-is@~1.6.15: typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -ua-parser-js@^0.7.9: - version "0.7.18" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" +ua-parser-js@^0.7.18: + version "0.7.19" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b" + integrity sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ== -uglify-js@^2.8.29: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" +uglify-js@^3.1.4: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" + commander "~2.17.1" + source-map "~0.6.1" -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== -uglifyjs-webpack-plugin@^0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== dependencies: - source-map "^0.5.6" - uglify-js "^2.8.29" - webpack-sources "^1.0.1" + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +unicode-match-property-value-ecmascript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" + integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" + integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -6187,119 +6884,179 @@ union-value@^1.0.0: uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= -uniqid@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: - macaddress "^0.2.8" + unique-slug "^2.0.0" -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" +unique-slug@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== + dependencies: + imurmurhash "^0.1.4" + +universal-user-agent@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.3.tgz#9f6f09f9cc33de867bb720d84c08069b14937c6c" + integrity sha512-eRHEHhChCBHrZsA4WEhdgiOKgdvgrMIHwnwnqD0r5C6AO8kwKcG7qSku3iXdhvHL3YvsS9ZkSGN8h/hIpoFC8g== + dependencies: + os-name "^3.0.0" universalify@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" -unzip@^0.1.11: - version "0.1.11" - resolved "https://registry.yarnpkg.com/unzip/-/unzip-0.1.11.tgz#89749c63b058d7d90d619f86b98aa1535d3b97f0" +unzipper@^0.8.11: + version "0.8.14" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.8.14.tgz#ade0524cd2fc14d11b8de258be22f9d247d3f79b" + integrity sha512-8rFtE7EP5ssOwGpN2dt1Q4njl0N1hUXJ7sSPz0leU2hRdq6+pra57z4YPBlVqm40vcgv6ooKZEAx48fMTv9x4w== dependencies: - binary ">= 0.3.0 < 1" - fstream ">= 0.1.30 < 1" - match-stream ">= 0.0.2 < 1" - pullstream ">= 0.4.1 < 1" - readable-stream "~1.0.31" - setimmediate ">= 1.0.1 < 2" + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "~1.0.10" + listenercount "~1.0.1" + readable-stream "~2.1.5" + setimmediate "~1.0.4" -upath@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" +upath@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-loader@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.6.2.tgz#a007a7109620e9d988d14bce677a1decb9a993f7" +url-loader@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8" + integrity sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg== dependencies: - loader-utils "^1.0.2" - mime "^1.4.1" - schema-utils "^0.3.0" + loader-utils "^1.1.0" + mime "^2.0.3" + schema-utils "^1.0.0" url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= dependencies: prepend-http "^1.0.1" -url-parse@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" +url-parse@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== dependencies: - querystringify "0.0.x" - requires-port "1.0.x" + querystringify "^2.0.0" + requires-port "^1.0.0" -url-parse@^1.1.8: - version "1.2.0" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" - dependencies: - querystringify "~1.0.0" - requires-port "~1.0.0" +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= dependencies: punycode "1.3.2" querystring "0.2.0" -use@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" - dependencies: - define-property "^0.2.5" - isobject "^3.0.0" - lazy-cache "^2.0.2" +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util@0.10.3, util@^0.10.3: +util.promisify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= dependencies: inherits "2.0.1" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.0.0, uuid@^3.0.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" +uuid@^3.0.1, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +v8-compile-cache@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" + integrity sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw== validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" @@ -6307,124 +7064,180 @@ validate-npm-package-license@^3.0.1: vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - -vendors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= vm-browserify@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= dependencies: indexof "0.0.1" warning@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w= dependencies: loose-envify "^1.0.0" -watchpack@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" +warning@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== dependencies: chokidar "^2.0.2" graceful-fs "^4.1.2" neo-async "^2.5.0" -wbuf@^1.1.0, wbuf@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe" +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== dependencies: minimalistic-assert "^1.0.0" -webpack-dev-middleware@1.12.2: - version "1.12.2" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" +webpack-cli@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.2.3.tgz#13653549adfd8ccd920ad7be1ef868bacc22e346" + integrity sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q== dependencies: - memory-fs "~0.4.1" - mime "^1.5.0" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - time-stamp "^2.0.0" + chalk "^2.4.1" + cross-spawn "^6.0.5" + enhanced-resolve "^4.1.0" + findup-sync "^2.0.0" + global-modules "^1.0.0" + import-local "^2.0.0" + interpret "^1.1.0" + loader-utils "^1.1.0" + supports-color "^5.5.0" + v8-compile-cache "^2.0.2" + yargs "^12.0.4" -webpack-dev-server@^2.11.1: - version "2.11.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.11.2.tgz#1f4f4c78bf1895378f376815910812daf79a216f" +webpack-dashboard@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/webpack-dashboard/-/webpack-dashboard-3.0.0.tgz#14b2374841efd9b28d0368f07a38bc1af43970e1" + integrity sha512-OtqccZJLR9CPbn86p6iwXWrseh944AkNj0AzrNvC7j4x+yHjmX1dlDpyo1f35GwY6F9eBWpMffUoGeWrFjLNUA== + dependencies: + commander "^2.15.1" + cross-spawn "^6.0.5" + filesize "^3.6.1" + handlebars "^4.0.11" + inspectpack "^4.0.0" + most "^1.7.3" + neo-blessed "^0.2.0" + socket.io "^2.1.1" + socket.io-client "^2.1.1" + +webpack-dev-middleware@^3.5.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.1.tgz#91f2531218a633a99189f7de36045a331a4b9cd4" + integrity sha512-XQmemun8QJexMEvNFbD2BIg4eSKrmSIMrTfnl2nql2Sc6OGAYFyb8rwuYrCjl/IiEYYuyTEiimMscu7EXji/Dw== + dependencies: + memory-fs "^0.4.1" + mime "^2.3.1" + range-parser "^1.0.3" + webpack-log "^2.0.0" + +webpack-dev-server@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.2.1.tgz#1b45ce3ecfc55b6ebe5e36dab2777c02bc508c4e" + integrity sha512-sjuE4mnmx6JOh9kvSbPYw3u/6uxCLHNWfhWaIPwcXWsvWOPN+nc5baq4i9jui3oOBRXGonK9+OI0jVkaz6/rCw== dependencies: ansi-html "0.0.7" - array-includes "^3.0.3" bonjour "^3.5.0" chokidar "^2.0.0" compression "^1.5.2" connect-history-api-fallback "^1.3.0" - debug "^3.1.0" + debug "^4.1.1" del "^3.0.0" express "^4.16.2" html-entities "^1.2.0" - http-proxy-middleware "~0.17.4" - import-local "^1.0.0" - internal-ip "1.2.0" + http-proxy-middleware "^0.19.1" + import-local "^2.0.0" + internal-ip "^4.2.0" ip "^1.1.5" killable "^1.0.0" loglevel "^1.4.1" opn "^5.1.0" portfinder "^1.0.9" + schema-utils "^1.0.0" selfsigned "^1.9.1" + semver "^5.6.0" serve-index "^1.7.2" sockjs "0.3.19" - sockjs-client "1.1.4" - spdy "^3.4.1" + sockjs-client "1.3.0" + spdy "^4.0.0" strip-ansi "^3.0.0" - supports-color "^5.1.0" - webpack-dev-middleware "1.12.2" - yargs "6.6.0" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.5.1" + webpack-log "^2.0.0" + yargs "12.0.2" -webpack-sources@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.1.tgz#5e923cf802ea2ace4fd5af1d3247368a633489b4" + integrity sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw== + dependencies: + lodash "^4.17.5" + +webpack-sources@^1.1.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^3.10.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.11.0.tgz#77da451b1d7b4b117adaf41a1a93b5742f24d894" +webpack@4.29.6: + version "4.29.6" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.6.tgz#66bf0ec8beee4d469f8b598d3988ff9d8d90e955" + integrity sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw== dependencies: - acorn "^5.0.0" - acorn-dynamic-import "^2.0.0" + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.0.5" + acorn-dynamic-import "^4.0.0" ajv "^6.1.0" ajv-keywords "^3.1.0" - async "^2.1.2" - enhanced-resolve "^3.4.0" - escope "^3.6.0" - interpret "^1.0.0" - json-loader "^0.5.4" - json5 "^0.5.1" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" loader-runner "^2.3.0" loader-utils "^1.1.0" memory-fs "~0.4.1" + micromatch "^3.1.8" mkdirp "~0.5.0" + neo-async "^2.5.0" node-libs-browser "^2.0.0" - source-map "^0.5.3" - supports-color "^4.2.1" - tapable "^0.2.7" - uglifyjs-webpack-plugin "^0.4.6" - watchpack "^1.4.0" - webpack-sources "^1.0.1" - yargs "^8.0.2" + schema-utils "^1.0.0" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" @@ -6432,54 +7245,70 @@ websocket-driver@>=0.5.1: websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== whatwg-fetch@>=0.10.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - -whet.extend@~0.9.9: - version "0.9.9" - resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" + integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.2.9, which@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" +which@^1.2.14, which@^1.2.9, which@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: - string-width "^1.0.2" - -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + string-width "^1.0.2 || 2" window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +windows-release@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.1.0.tgz#8d4a7e266cbf5a233f6c717dac19ce00af36e12e" + integrity sha512-hBb7m7acFgQPQc222uEQTmdcGLeBmQLNLFIh0rDk3CwFOBrfjefLzEfEfmpMq8Af/n/GnFf3eYf203FY1PmudA== + dependencies: + execa "^0.10.0" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== + dependencies: + errno "~0.1.7" wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -6487,65 +7316,145 @@ wrap-ansi@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== dependencies: mkdirp "^0.5.1" -xtend@^4.0.0: +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xregexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== + +xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== + dependencies: + camelcase "^4.1.0" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" yargs-parser@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + integrity sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ= dependencies: camelcase "^3.0.0" lodash.assign "^4.0.6" -yargs-parser@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" - dependencies: - camelcase "^3.0.0" - -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= dependencies: camelcase "^4.1.0" -yargs@6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" +yargs@12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" + integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ== dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" - decamelize "^1.1.1" + cliui "^4.0.0" + decamelize "^2.0.0" + find-up "^3.0.0" get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" + os-locale "^3.0.0" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^10.1.0" + +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" y18n "^3.2.1" - yargs-parser "^4.2.0" + yargs-parser "^9.0.2" + +yargs@^12.0.4: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" yargs@^4.2.0: version "4.8.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + integrity sha1-wMQpJMpKqmsObaFznfshZDn53cA= dependencies: cliui "^3.2.0" decamelize "^1.1.1" @@ -6562,29 +7471,7 @@ yargs@^4.2.0: y18n "^3.2.1" yargs-parser "^2.4.1" -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go b/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go index 3ba92ac7..d69a750f 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go @@ -18,8 +18,10 @@ package dashboard //go:generate yarn --cwd ./assets install //go:generate yarn --cwd ./assets build -//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/index.html assets/bundle.js +//go:generate yarn --cwd ./assets js-beautify -f bundle.js.map -r -w 1 +//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/index.html assets/bundle.js assets/bundle.js.map //go:generate sh -c "sed 's#var _bundleJs#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go" +//go:generate sh -c "sed 's#var _bundleJsMap#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go" //go:generate sh -c "sed 's#var _indexHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go" //go:generate gofmt -w -s assets.go @@ -27,16 +29,13 @@ import ( "fmt" "net" "net/http" - "runtime" "sync" "sync/atomic" "time" "io" - "github.com/elastic/gosigar" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -45,31 +44,29 @@ import ( ) const ( - activeMemorySampleLimit = 200 // Maximum number of active memory data samples - virtualMemorySampleLimit = 200 // Maximum number of virtual memory data samples - networkIngressSampleLimit = 200 // Maximum number of network ingress data samples - networkEgressSampleLimit = 200 // Maximum number of network egress data samples - processCPUSampleLimit = 200 // Maximum number of process cpu data samples - systemCPUSampleLimit = 200 // Maximum number of system cpu data samples - diskReadSampleLimit = 200 // Maximum number of disk read data samples - diskWriteSampleLimit = 200 // Maximum number of disk write data samples + sampleLimit = 200 // Maximum number of data samples ) -var nextID uint32 // Next connection id - // Dashboard contains the dashboard internals. type Dashboard struct { - config *Config + config *Config // Configuration values for the dashboard - listener net.Listener - conns map[uint32]*client // Currently live websocket connections - history *Message - lock sync.RWMutex // Lock protecting the dashboard's internals + listener net.Listener // Network listener listening for dashboard clients + conns map[uint32]*client // Currently live websocket connections + nextConnID uint32 // Next connection id - logdir string + history *Message // Stored historical data + + lock sync.Mutex // Lock protecting the dashboard's internals + sysLock sync.RWMutex // Lock protecting the stored system data + peerLock sync.RWMutex // Lock protecting the stored peer data + logLock sync.RWMutex // Lock protecting the stored log data + + geodb *geoDB // geoip database instance for IP to geographical information conversions + logdir string // Directory containing the log files quit chan chan error // Channel used for graceful exit - wg sync.WaitGroup + wg sync.WaitGroup // Wait group used to close the data collector threads } // client represents active websocket connection with a remote browser. @@ -96,14 +93,14 @@ func New(config *Config, commit string, logdir string) *Dashboard { Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta), }, System: &SystemMessage{ - ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh), - VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh), - NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh), - NetworkEgress: emptyChartEntries(now, networkEgressSampleLimit, config.Refresh), - ProcessCPU: emptyChartEntries(now, processCPUSampleLimit, config.Refresh), - SystemCPU: emptyChartEntries(now, systemCPUSampleLimit, config.Refresh), - DiskRead: emptyChartEntries(now, diskReadSampleLimit, config.Refresh), - DiskWrite: emptyChartEntries(now, diskWriteSampleLimit, config.Refresh), + ActiveMemory: emptyChartEntries(now, sampleLimit), + VirtualMemory: emptyChartEntries(now, sampleLimit), + NetworkIngress: emptyChartEntries(now, sampleLimit), + NetworkEgress: emptyChartEntries(now, sampleLimit), + ProcessCPU: emptyChartEntries(now, sampleLimit), + SystemCPU: emptyChartEntries(now, sampleLimit), + DiskRead: emptyChartEntries(now, sampleLimit), + DiskWrite: emptyChartEntries(now, sampleLimit), }, }, logdir: logdir, @@ -111,12 +108,10 @@ func New(config *Config, commit string, logdir string) *Dashboard { } // emptyChartEntries returns a ChartEntry array containing limit number of empty samples. -func emptyChartEntries(t time.Time, limit int, refresh time.Duration) ChartEntries { +func emptyChartEntries(t time.Time, limit int) ChartEntries { ce := make(ChartEntries, limit) for i := 0; i < limit; i++ { - ce[i] = &ChartEntry{ - Time: t.Add(-time.Duration(i) * refresh), - } + ce[i] = new(ChartEntry) } return ce } @@ -132,9 +127,10 @@ func (db *Dashboard) APIs() []rpc.API { return nil } func (db *Dashboard) Start(server *p2p.Server) error { log.Info("Starting dashboard") - db.wg.Add(2) - go db.collectData() + db.wg.Add(3) + go db.collectSystemData() go db.streamLogs() + go db.collectPeerData() http.HandleFunc("/", db.webHandler) http.Handle("/api", websocket.Handler(db.apiHandler)) @@ -160,7 +156,7 @@ func (db *Dashboard) Stop() error { } // Close the collectors. errc := make(chan error, 1) - for i := 0; i < 2; i++ { + for i := 0; i < 3; i++ { db.quit <- errc if err := <-errc; err != nil { errs = append(errs, err) @@ -206,7 +202,7 @@ func (db *Dashboard) webHandler(w http.ResponseWriter, r *http.Request) { // apiHandler handles requests for the dashboard. func (db *Dashboard) apiHandler(conn *websocket.Conn) { - id := atomic.AddUint32(&nextID, 1) + id := atomic.AddUint32(&db.nextConnID, 1) client := &client{ conn: conn, msg: make(chan *Message, 128), @@ -233,10 +229,21 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) { } }() - db.lock.Lock() // Send the past data. - client.msg <- deepcopy.Copy(db.history).(*Message) + db.sysLock.RLock() + db.peerLock.RLock() + db.logLock.RLock() + + h := deepcopy.Copy(db.history).(*Message) + + db.sysLock.RUnlock() + db.peerLock.RUnlock() + db.logLock.RUnlock() + + client.msg <- h + // Start tracking the connection and drop at connection loss. + db.lock.Lock() db.conns[id] = client db.lock.Unlock() defer func() { @@ -259,136 +266,6 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) { } } -// meterCollector returns a function, which retrieves a specific meter. -func meterCollector(name string) func() int64 { - if metric := metrics.DefaultRegistry.Get(name); metric != nil { - m := metric.(metrics.Meter) - return func() int64 { - return m.Count() - } - } - return func() int64 { - return 0 - } -} - -// collectData collects the required data to plot on the dashboard. -func (db *Dashboard) collectData() { - defer db.wg.Done() - - systemCPUUsage := gosigar.Cpu{} - systemCPUUsage.Get() - var ( - mem runtime.MemStats - - collectNetworkIngress = meterCollector("p2p/InboundTraffic") - collectNetworkEgress = meterCollector("p2p/OutboundTraffic") - collectDiskRead = meterCollector("eth/db/chaindata/disk/read") - collectDiskWrite = meterCollector("eth/db/chaindata/disk/write") - - prevNetworkIngress = collectNetworkIngress() - prevNetworkEgress = collectNetworkEgress() - prevProcessCPUTime = getProcessCPUTime() - prevSystemCPUUsage = systemCPUUsage - prevDiskRead = collectDiskRead() - prevDiskWrite = collectDiskWrite() - - frequency = float64(db.config.Refresh / time.Second) - numCPU = float64(runtime.NumCPU()) - ) - - for { - select { - case errc := <-db.quit: - errc <- nil - return - case <-time.After(db.config.Refresh): - systemCPUUsage.Get() - var ( - curNetworkIngress = collectNetworkIngress() - curNetworkEgress = collectNetworkEgress() - curProcessCPUTime = getProcessCPUTime() - curSystemCPUUsage = systemCPUUsage - curDiskRead = collectDiskRead() - curDiskWrite = collectDiskWrite() - - deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress) - deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress) - deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime - deltaSystemCPUUsage = curSystemCPUUsage.Delta(prevSystemCPUUsage) - deltaDiskRead = curDiskRead - prevDiskRead - deltaDiskWrite = curDiskWrite - prevDiskWrite - ) - prevNetworkIngress = curNetworkIngress - prevNetworkEgress = curNetworkEgress - prevProcessCPUTime = curProcessCPUTime - prevSystemCPUUsage = curSystemCPUUsage - prevDiskRead = curDiskRead - prevDiskWrite = curDiskWrite - - now := time.Now() - - runtime.ReadMemStats(&mem) - activeMemory := &ChartEntry{ - Time: now, - Value: float64(mem.Alloc) / frequency, - } - virtualMemory := &ChartEntry{ - Time: now, - Value: float64(mem.Sys) / frequency, - } - networkIngress := &ChartEntry{ - Time: now, - Value: deltaNetworkIngress / frequency, - } - networkEgress := &ChartEntry{ - Time: now, - Value: deltaNetworkEgress / frequency, - } - processCPU := &ChartEntry{ - Time: now, - Value: deltaProcessCPUTime / frequency / numCPU * 100, - } - systemCPU := &ChartEntry{ - Time: now, - Value: float64(deltaSystemCPUUsage.Sys+deltaSystemCPUUsage.User) / frequency / numCPU, - } - diskRead := &ChartEntry{ - Time: now, - Value: float64(deltaDiskRead) / frequency, - } - diskWrite := &ChartEntry{ - Time: now, - Value: float64(deltaDiskWrite) / frequency, - } - sys := db.history.System - db.lock.Lock() - sys.ActiveMemory = append(sys.ActiveMemory[1:], activeMemory) - sys.VirtualMemory = append(sys.VirtualMemory[1:], virtualMemory) - sys.NetworkIngress = append(sys.NetworkIngress[1:], networkIngress) - sys.NetworkEgress = append(sys.NetworkEgress[1:], networkEgress) - sys.ProcessCPU = append(sys.ProcessCPU[1:], processCPU) - sys.SystemCPU = append(sys.SystemCPU[1:], systemCPU) - sys.DiskRead = append(sys.DiskRead[1:], diskRead) - sys.DiskWrite = append(sys.DiskWrite[1:], diskWrite) - db.lock.Unlock() - - db.sendToAll(&Message{ - System: &SystemMessage{ - ActiveMemory: ChartEntries{activeMemory}, - VirtualMemory: ChartEntries{virtualMemory}, - NetworkIngress: ChartEntries{networkIngress}, - NetworkEgress: ChartEntries{networkEgress}, - ProcessCPU: ChartEntries{processCPU}, - SystemCPU: ChartEntries{systemCPU}, - DiskRead: ChartEntries{diskRead}, - DiskWrite: ChartEntries{diskWrite}, - }, - }) - } - } -} - // sendToAll sends the given message to the active dashboards. func (db *Dashboard) sendToAll(msg *Message) { db.lock.Lock() diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/geoip.go b/vendor/github.com/ethereum/go-ethereum/dashboard/geoip.go new file mode 100644 index 00000000..ae10bbe8 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/geoip.go @@ -0,0 +1,98 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package dashboard + +import ( + "net" + "time" + + "github.com/apilayer/freegeoip" +) + +// geoDBInfo contains all the geographical information we could extract based on an IP +// address. +type geoDBInfo struct { + Country struct { + Names struct { + English string `maxminddb:"en" json:"en,omitempty"` + } `maxminddb:"names" json:"names,omitempty"` + } `maxminddb:"country" json:"country,omitempty"` + City struct { + Names struct { + English string `maxminddb:"en" json:"en,omitempty"` + } `maxminddb:"names" json:"names,omitempty"` + } `maxminddb:"city" json:"city,omitempty"` + Location struct { + Latitude float64 `maxminddb:"latitude" json:"latitude,omitempty"` + Longitude float64 `maxminddb:"longitude" json:"longitude,omitempty"` + } `maxminddb:"location" json:"location,omitempty"` +} + +// geoLocation contains geographical information. +type geoLocation struct { + Country string `json:"country,omitempty"` + City string `json:"city,omitempty"` + Latitude float64 `json:"latitude,omitempty"` + Longitude float64 `json:"longitude,omitempty"` +} + +// geoDB represents a geoip database that can be queried for IP to geographical +// information conversions. +type geoDB struct { + geodb *freegeoip.DB +} + +// Open creates a new geoip database with an up-to-date database from the internet. +func openGeoDB() (*geoDB, error) { + // Initiate a geoip database to cross reference locations + db, err := freegeoip.OpenURL(freegeoip.MaxMindDB, 24*time.Hour, time.Hour) + if err != nil { + return nil, err + } + // Wait until the database is updated to the latest data + select { + case <-db.NotifyOpen(): + case err := <-db.NotifyError(): + return nil, err + } + // Assemble and return our custom wrapper + return &geoDB{geodb: db}, nil +} + +// Close terminates the database background updater. +func (db *geoDB) close() error { + db.geodb.Close() + return nil +} + +// Lookup converts an IP address to a geographical location. +func (db *geoDB) lookup(ip net.IP) *geoDBInfo { + result := new(geoDBInfo) + db.geodb.Lookup(ip, result) + return result +} + +// Location retrieves the geographical location of the given IP address. +func (db *geoDB) location(ip string) *geoLocation { + location := db.lookup(net.ParseIP(ip)) + return &geoLocation{ + Country: location.Country.Names.English, + City: location.City.Names.English, + Latitude: location.Location.Latitude, + Longitude: location.Location.Longitude, + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/log.go b/vendor/github.com/ethereum/go-ethereum/dashboard/log.go index 5d852d60..be773269 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/log.go +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/log.go @@ -94,13 +94,13 @@ func (db *Dashboard) handleLogRequest(r *LogsRequest, c *client) { // The last file is continuously updated, and its chunks are streamed, // so in order to avoid log record duplication on the client side, it is // handled differently. Its actual content is always saved in the history. - db.lock.Lock() + db.logLock.RLock() if db.history.Logs != nil { c.msg <- &Message{ - Logs: db.history.Logs, + Logs: deepcopy.Copy(db.history.Logs).(*LogsMessage), } } - db.lock.Unlock() + db.logLock.RUnlock() return case fileNames[idx] == r.Name: idx++ @@ -174,7 +174,7 @@ func (db *Dashboard) streamLogs() { log.Warn("Problem with file", "name", opened.Name(), "err", err) return } - db.lock.Lock() + db.logLock.Lock() db.history.Logs = &LogsMessage{ Source: &LogFile{ Name: fi.Name(), @@ -182,7 +182,7 @@ func (db *Dashboard) streamLogs() { }, Chunk: emptyChunk, } - db.lock.Unlock() + db.logLock.Unlock() watcher := make(chan notify.EventInfo, 10) if err := notify.Watch(db.logdir, watcher, notify.Create); err != nil { @@ -240,10 +240,10 @@ loop: log.Warn("Problem with file", "name", opened.Name(), "err", err) break loop } - db.lock.Lock() + db.logLock.Lock() db.history.Logs.Source.Name = fi.Name() db.history.Logs.Chunk = emptyChunk - db.lock.Unlock() + db.logLock.Unlock() case <-ticker.C: // Send log updates to the client. if opened == nil { log.Warn("The last log file is not opened") @@ -266,7 +266,7 @@ loop: var l *LogsMessage // Update the history. - db.lock.Lock() + db.logLock.Lock() if bytes.Equal(db.history.Logs.Chunk, emptyChunk) { db.history.Logs.Chunk = chunk l = deepcopy.Copy(db.history.Logs).(*LogsMessage) @@ -278,7 +278,7 @@ loop: db.history.Logs.Chunk = b l = &LogsMessage{Chunk: chunk} } - db.lock.Unlock() + db.logLock.Unlock() db.sendToAll(&Message{Logs: l}) case errc = <-db.quit: diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/message.go b/vendor/github.com/ethereum/go-ethereum/dashboard/message.go index 46856b9e..797b210f 100644 --- a/vendor/github.com/ethereum/go-ethereum/dashboard/message.go +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/message.go @@ -18,7 +18,6 @@ package dashboard import ( "encoding/json" - "time" ) type Message struct { @@ -34,8 +33,7 @@ type Message struct { type ChartEntries []*ChartEntry type ChartEntry struct { - Time time.Time `json:"time,omitempty"` - Value float64 `json:"value,omitempty"` + Value float64 `json:"value"` } type GeneralMessage struct { @@ -55,10 +53,14 @@ type TxPoolMessage struct { /* TODO (kurkomisi) */ } +// NetworkMessage contains information about the peers +// organized based on their IP address and node ID. type NetworkMessage struct { - /* TODO (kurkomisi) */ + Peers *peerContainer `json:"peers,omitempty"` // Peer tree. + Diff []*peerEvent `json:"diff,omitempty"` // Events that change the peer tree. } +// SystemMessage contains the metered system data samples. type SystemMessage struct { ActiveMemory ChartEntries `json:"activeMemory,omitempty"` VirtualMemory ChartEntries `json:"virtualMemory,omitempty"` @@ -70,7 +72,7 @@ type SystemMessage struct { DiskWrite ChartEntries `json:"diskWrite,omitempty"` } -// LogsMessage wraps up a log chunk. If Source isn't present, the chunk is a stream chunk. +// LogsMessage wraps up a log chunk. If 'Source' isn't present, the chunk is a stream chunk. type LogsMessage struct { Source *LogFile `json:"source,omitempty"` // Attributes of the log file. Chunk json.RawMessage `json:"chunk"` // Contains log records. @@ -87,6 +89,7 @@ type Request struct { Logs *LogsRequest `json:"logs,omitempty"` } +// LogsRequest contains the attributes of the log file the client wants to receive. type LogsRequest struct { Name string `json:"name"` // The request handler searches for log file based on this file name. Past bool `json:"past"` // Denotes whether the client wants the previous or the next file. diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/peers.go b/vendor/github.com/ethereum/go-ethereum/dashboard/peers.go new file mode 100644 index 00000000..e591bda7 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/peers.go @@ -0,0 +1,552 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package dashboard + +import ( + "container/list" + "strings" + "time" + + "github.com/ethereum/go-ethereum/metrics" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" +) + +const ( + eventBufferLimit = 128 // Maximum number of buffered peer events. + knownPeerLimit = 100 // Maximum number of stored peers, which successfully made the handshake. + attemptLimit = 200 // Maximum number of stored peers, which failed to make the handshake. + + // eventLimit is the maximum number of the dashboard's custom peer events, + // that are collected between two metering period and sent to the clients + // as one message. + // TODO (kurkomisi): Limit the number of events. + eventLimit = knownPeerLimit << 2 +) + +// peerContainer contains information about the node's peers. This data structure +// maintains the metered peer data based on the different behaviours of the peers. +// +// Every peer has an IP address, and the peers that manage to make the handshake +// (known peers) have node IDs too. There can appear more peers with the same IP, +// therefore the peer container data structure is a tree consisting of a map of +// maps, where the first key groups the peers by IP, while the second one groups +// them by the node ID. The known peers can be active if their connection is still +// open, or inactive otherwise. The peers failing before the handshake (unknown +// peers) only have IP addresses, so their connection attempts are stored as part +// of the value of the outer map. +// +// Another criteria is to limit the number of metered peers so that +// they don't fill the memory. The selection order is based on the +// peers activity: the peers that are inactive for the longest time +// are thrown first. For the selection a fifo list is used which is +// linked to the bottom of the peer tree in a way that every activity +// of the peer pushes the peer to the end of the list, so the inactive +// ones come to the front. When a peer has some activity, it is removed +// from and reinserted into the list. When the length of the list reaches +// the limit, the first element is removed from the list, as well as from +// the tree. +// +// The active peers have priority over the inactive ones, therefore +// they have their own list. The separation makes it sure that the +// inactive peers are always removed before the active ones. +// +// The peers that don't manage to make handshake are not inserted into the list, +// only their connection attempts are appended to the array belonging to their IP. +// In order to keep the fifo principle, a super array contains the order of the +// attempts, and when the overall count reaches the limit, the earliest attempt is +// removed from the beginning of its array. +// +// This data structure makes it possible to marshal the peer +// history simply by passing it to the JSON marshaler. +type peerContainer struct { + // Bundles is the outer map using the peer's IP address as key. + Bundles map[string]*peerBundle `json:"bundles,omitempty"` + + activeCount int // Number of the still connected peers + + // inactivePeers contains the peers with closed connection in chronological order. + inactivePeers *list.List + + // attemptOrder is the super array containing the IP addresses, from which + // the peers attempted to connect then failed before/during the handshake. + // Its values are appended in chronological order, which means that the + // oldest attempt is at the beginning of the array. When the first element + // is removed, the first element of the related bundle's attempt array is + // removed too, ensuring that always the latest attempts are stored. + attemptOrder []string + + // geodb is the geoip database used to retrieve the peers' geographical location. + geodb *geoDB +} + +// newPeerContainer returns a new instance of the peer container. +func newPeerContainer(geodb *geoDB) *peerContainer { + return &peerContainer{ + Bundles: make(map[string]*peerBundle), + inactivePeers: list.New(), + attemptOrder: make([]string, 0, attemptLimit), + geodb: geodb, + } +} + +// bundle inserts a new peer bundle into the map, if the peer belonging +// to the given IP wasn't metered so far. In this case retrieves the location of +// the IP address from the database and creates a corresponding peer event. +// Returns the bundle belonging to the given IP and the events occurring during +// the initialization. +func (pc *peerContainer) bundle(ip string) (*peerBundle, []*peerEvent) { + var events []*peerEvent + if _, ok := pc.Bundles[ip]; !ok { + location := pc.geodb.location(ip) + events = append(events, &peerEvent{ + IP: ip, + Location: location, + }) + pc.Bundles[ip] = &peerBundle{ + Location: location, + KnownPeers: make(map[string]*knownPeer), + } + } + return pc.Bundles[ip], events +} + +// extendKnown handles the events of the successfully connected peers. +// Returns the events occurring during the extension. +func (pc *peerContainer) extendKnown(event *peerEvent) []*peerEvent { + bundle, events := pc.bundle(event.IP) + peer, peerEvents := bundle.knownPeer(event.IP, event.ID) + events = append(events, peerEvents...) + // Append the connect and the disconnect events to + // the corresponding arrays keeping the limit. + switch { + case event.Connected != nil: + peer.Connected = append(peer.Connected, event.Connected) + if first := len(peer.Connected) - sampleLimit; first > 0 { + peer.Connected = peer.Connected[first:] + } + peer.Active = true + events = append(events, &peerEvent{ + Activity: Active, + IP: peer.ip, + ID: peer.id, + }) + pc.activeCount++ + if peer.listElement != nil { + _ = pc.inactivePeers.Remove(peer.listElement) + peer.listElement = nil + } + case event.Disconnected != nil: + peer.Disconnected = append(peer.Disconnected, event.Disconnected) + if first := len(peer.Disconnected) - sampleLimit; first > 0 { + peer.Disconnected = peer.Disconnected[first:] + } + peer.Active = false + events = append(events, &peerEvent{ + Activity: Inactive, + IP: peer.ip, + ID: peer.id, + }) + pc.activeCount-- + if peer.listElement != nil { + // If the peer is already in the list, remove and reinsert it. + _ = pc.inactivePeers.Remove(peer.listElement) + } + // Insert the peer into the list. + peer.listElement = pc.inactivePeers.PushBack(peer) + } + for pc.inactivePeers.Len() > 0 && pc.activeCount+pc.inactivePeers.Len() > knownPeerLimit { + // While the count of the known peers is greater than the limit, + // remove the first element from the inactive peer list and from the map. + if removedPeer, ok := pc.inactivePeers.Remove(pc.inactivePeers.Front()).(*knownPeer); ok { + events = append(events, pc.removeKnown(removedPeer.ip, removedPeer.id)...) + } else { + log.Warn("Failed to parse the removed peer") + } + } + if pc.activeCount > knownPeerLimit { + log.Warn("Number of active peers is greater than the limit") + } + return events +} + +// handleAttempt handles the events of the peers failing before/during the handshake. +// Returns the events occurring during the extension. +func (pc *peerContainer) handleAttempt(event *peerEvent) []*peerEvent { + bundle, events := pc.bundle(event.IP) + bundle.Attempts = append(bundle.Attempts, &peerAttempt{ + Connected: *event.Connected, + Disconnected: *event.Disconnected, + }) + pc.attemptOrder = append(pc.attemptOrder, event.IP) + for len(pc.attemptOrder) > attemptLimit { + // While the length of the connection attempt order array is greater + // than the limit, remove the first element from the involved peer's + // array and also from the super array. + events = append(events, pc.removeAttempt(pc.attemptOrder[0])...) + pc.attemptOrder = pc.attemptOrder[1:] + } + return events +} + +// peerBundle contains the peers belonging to a given IP address. +type peerBundle struct { + // Location contains the geographical location based on the bundle's IP address. + Location *geoLocation `json:"location,omitempty"` + + // KnownPeers is the inner map of the metered peer + // maintainer data structure using the node ID as key. + KnownPeers map[string]*knownPeer `json:"knownPeers,omitempty"` + + // Attempts contains the failed connection attempts of the + // peers belonging to a given IP address in chronological order. + Attempts []*peerAttempt `json:"attempts,omitempty"` +} + +// removeKnown removes the known peer belonging to the +// given IP address and node ID from the peer tree. +func (pc *peerContainer) removeKnown(ip, id string) (events []*peerEvent) { + // TODO (kurkomisi): Remove peers that don't have traffic samples anymore. + if bundle, ok := pc.Bundles[ip]; ok { + if _, ok := bundle.KnownPeers[id]; ok { + events = append(events, &peerEvent{ + Remove: RemoveKnown, + IP: ip, + ID: id, + }) + delete(bundle.KnownPeers, id) + } else { + log.Warn("No peer to remove", "ip", ip, "id", id) + } + if len(bundle.KnownPeers) < 1 && len(bundle.Attempts) < 1 { + events = append(events, &peerEvent{ + Remove: RemoveBundle, + IP: ip, + }) + delete(pc.Bundles, ip) + } + } else { + log.Warn("No bundle to remove", "ip", ip) + } + return events +} + +// removeAttempt removes the peer attempt belonging to the +// given IP address and node ID from the peer tree. +func (pc *peerContainer) removeAttempt(ip string) (events []*peerEvent) { + if bundle, ok := pc.Bundles[ip]; ok { + if len(bundle.Attempts) > 0 { + events = append(events, &peerEvent{ + Remove: RemoveAttempt, + IP: ip, + }) + bundle.Attempts = bundle.Attempts[1:] + } + if len(bundle.Attempts) < 1 && len(bundle.KnownPeers) < 1 { + events = append(events, &peerEvent{ + Remove: RemoveBundle, + IP: ip, + }) + delete(pc.Bundles, ip) + } + } + return events +} + +// knownPeer inserts a new peer into the map, if the peer belonging +// to the given IP address and node ID wasn't metered so far. Returns the peer +// belonging to the given IP and ID as well as the events occurring during the +// initialization. +func (bundle *peerBundle) knownPeer(ip, id string) (*knownPeer, []*peerEvent) { + var events []*peerEvent + if _, ok := bundle.KnownPeers[id]; !ok { + now := time.Now() + ingress := emptyChartEntries(now, sampleLimit) + egress := emptyChartEntries(now, sampleLimit) + events = append(events, &peerEvent{ + IP: ip, + ID: id, + Ingress: append([]*ChartEntry{}, ingress...), + Egress: append([]*ChartEntry{}, egress...), + }) + bundle.KnownPeers[id] = &knownPeer{ + ip: ip, + id: id, + Ingress: ingress, + Egress: egress, + } + } + return bundle.KnownPeers[id], events +} + +// knownPeer contains the metered data of a particular peer. +type knownPeer struct { + // Connected contains the timestamps of the peer's connection events. + Connected []*time.Time `json:"connected,omitempty"` + + // Disconnected contains the timestamps of the peer's disconnection events. + Disconnected []*time.Time `json:"disconnected,omitempty"` + + // Ingress and Egress contain the peer's traffic samples, which are collected + // periodically from the metrics registry. + // + // A peer can connect multiple times, and we want to visualize the time + // passed between two connections, so after the first connection a 0 value + // is appended to the traffic arrays even if the peer is inactive until the + // peer is removed. + Ingress ChartEntries `json:"ingress,omitempty"` + Egress ChartEntries `json:"egress,omitempty"` + + Active bool `json:"active"` // Denotes if the peer is still connected. + + listElement *list.Element // Pointer to the peer element in the list. + ip, id string // The IP and the ID by which the peer can be accessed in the tree. + prevIngress float64 + prevEgress float64 +} + +// peerAttempt contains a failed peer connection attempt's attributes. +type peerAttempt struct { + // Connected contains the timestamp of the connection attempt's moment. + Connected time.Time `json:"connected"` + + // Disconnected contains the timestamp of the + // moment when the connection attempt failed. + Disconnected time.Time `json:"disconnected"` +} + +type RemovedPeerType string +type ActivityType string + +const ( + RemoveKnown RemovedPeerType = "known" + RemoveAttempt RemovedPeerType = "attempt" + RemoveBundle RemovedPeerType = "bundle" + + Active ActivityType = "active" + Inactive ActivityType = "inactive" +) + +// peerEvent contains the attributes of a peer event. +type peerEvent struct { + IP string `json:"ip,omitempty"` // IP address of the peer. + ID string `json:"id,omitempty"` // Node ID of the peer. + Remove RemovedPeerType `json:"remove,omitempty"` // Type of the peer that is to be removed. + Location *geoLocation `json:"location,omitempty"` // Geographical location of the peer. + Connected *time.Time `json:"connected,omitempty"` // Timestamp of the connection moment. + Disconnected *time.Time `json:"disconnected,omitempty"` // Timestamp of the disonnection moment. + Ingress ChartEntries `json:"ingress,omitempty"` // Ingress samples. + Egress ChartEntries `json:"egress,omitempty"` // Egress samples. + Activity ActivityType `json:"activity,omitempty"` // Connection status change. +} + +// trafficMap is a container for the periodically collected peer traffic. +type trafficMap map[string]map[string]float64 + +// insert inserts a new value to the traffic map. Overwrites +// the value at the given ip and id if that already exists. +func (m *trafficMap) insert(ip, id string, val float64) { + if _, ok := (*m)[ip]; !ok { + (*m)[ip] = make(map[string]float64) + } + (*m)[ip][id] = val +} + +// collectPeerData gathers data about the peers and sends it to the clients. +func (db *Dashboard) collectPeerData() { + defer db.wg.Done() + + // Open the geodb database for IP to geographical information conversions. + var err error + db.geodb, err = openGeoDB() + if err != nil { + log.Warn("Failed to open geodb", "err", err) + return + } + defer db.geodb.close() + + peerCh := make(chan p2p.MeteredPeerEvent, eventBufferLimit) // Peer event channel. + subPeer := p2p.SubscribeMeteredPeerEvent(peerCh) // Subscribe to peer events. + defer subPeer.Unsubscribe() // Unsubscribe at the end. + + ticker := time.NewTicker(db.config.Refresh) + defer ticker.Stop() + + type registryFunc func(name string, i interface{}) + type collectorFunc func(traffic *trafficMap) registryFunc + + // trafficCollector generates a function that can be passed to + // the prefixed peer registry in order to collect the metered + // traffic data from each peer meter. + trafficCollector := func(prefix string) collectorFunc { + // This part makes is possible to collect the + // traffic data into a map from outside. + return func(traffic *trafficMap) registryFunc { + // The function which can be passed to the registry. + return func(name string, i interface{}) { + if m, ok := i.(metrics.Meter); ok { + // The name of the meter has the format: / + if k := strings.Split(strings.TrimPrefix(name, prefix), "/"); len(k) == 2 { + traffic.insert(k[0], k[1], float64(m.Count())) + } else { + log.Warn("Invalid meter name", "name", name, "prefix", prefix) + } + } else { + log.Warn("Invalid meter type", "name", name) + } + } + } + } + collectIngress := trafficCollector(p2p.MetricsInboundTraffic + "/") + collectEgress := trafficCollector(p2p.MetricsOutboundTraffic + "/") + + peers := newPeerContainer(db.geodb) + db.peerLock.Lock() + db.history.Network = &NetworkMessage{ + Peers: peers, + } + db.peerLock.Unlock() + + // newPeerEvents contains peer events, which trigger operations that + // will be executed on the peer tree after a metering period. + newPeerEvents := make([]*peerEvent, 0, eventLimit) + ingress, egress := new(trafficMap), new(trafficMap) + *ingress, *egress = make(trafficMap), make(trafficMap) + + for { + select { + case event := <-peerCh: + now := time.Now() + switch event.Type { + case p2p.PeerConnected: + connected := now.Add(-event.Elapsed) + newPeerEvents = append(newPeerEvents, &peerEvent{ + IP: event.IP.String(), + ID: event.ID.String(), + Connected: &connected, + }) + case p2p.PeerDisconnected: + ip, id := event.IP.String(), event.ID.String() + newPeerEvents = append(newPeerEvents, &peerEvent{ + IP: ip, + ID: id, + Disconnected: &now, + }) + // The disconnect event comes with the last metered traffic count, + // because after the disconnection the peer's meter is removed + // from the registry. It can happen, that between two metering + // period the same peer disconnects multiple times, and appending + // all the samples to the traffic arrays would shift the metering, + // so only the last metering is stored, overwriting the previous one. + ingress.insert(ip, id, float64(event.Ingress)) + egress.insert(ip, id, float64(event.Egress)) + case p2p.PeerHandshakeFailed: + connected := now.Add(-event.Elapsed) + newPeerEvents = append(newPeerEvents, &peerEvent{ + IP: event.IP.String(), + Connected: &connected, + Disconnected: &now, + }) + default: + log.Error("Unknown metered peer event type", "type", event.Type) + } + case <-ticker.C: + // Collect the traffic samples from the registry. + p2p.PeerIngressRegistry.Each(collectIngress(ingress)) + p2p.PeerEgressRegistry.Each(collectEgress(egress)) + + // Protect 'peers', because it is part of the history. + db.peerLock.Lock() + + var diff []*peerEvent + for i := 0; i < len(newPeerEvents); i++ { + if newPeerEvents[i].IP == "" { + log.Warn("Peer event without IP", "event", *newPeerEvents[i]) + continue + } + diff = append(diff, newPeerEvents[i]) + // There are two main branches of peer events coming from the event + // feed, one belongs to the known peers, one to the unknown peers. + // If the event has node ID, it belongs to a known peer, otherwise + // to an unknown one, which is considered as connection attempt. + // + // The extension can produce additional peer events, such + // as remove, location and initial samples events. + if newPeerEvents[i].ID == "" { + diff = append(diff, peers.handleAttempt(newPeerEvents[i])...) + continue + } + diff = append(diff, peers.extendKnown(newPeerEvents[i])...) + } + // Update the peer tree using the traffic maps. + for ip, bundle := range peers.Bundles { + for id, peer := range bundle.KnownPeers { + // Value is 0 if the traffic map doesn't have the + // entry corresponding to the given IP and ID. + curIngress, curEgress := (*ingress)[ip][id], (*egress)[ip][id] + deltaIngress, deltaEgress := curIngress, curEgress + if deltaIngress >= peer.prevIngress { + deltaIngress -= peer.prevIngress + } + if deltaEgress >= peer.prevEgress { + deltaEgress -= peer.prevEgress + } + peer.prevIngress, peer.prevEgress = curIngress, curEgress + i := &ChartEntry{ + Value: deltaIngress, + } + e := &ChartEntry{ + Value: deltaEgress, + } + peer.Ingress = append(peer.Ingress, i) + peer.Egress = append(peer.Egress, e) + if first := len(peer.Ingress) - sampleLimit; first > 0 { + peer.Ingress = peer.Ingress[first:] + } + if first := len(peer.Egress) - sampleLimit; first > 0 { + peer.Egress = peer.Egress[first:] + } + // Creating the traffic sample events. + diff = append(diff, &peerEvent{ + IP: ip, + ID: id, + Ingress: ChartEntries{i}, + Egress: ChartEntries{e}, + }) + } + } + db.peerLock.Unlock() + + if len(diff) > 0 { + db.sendToAll(&Message{Network: &NetworkMessage{ + Diff: diff, + }}) + } + // Clear the traffic maps, and the event array, + // prepare them for the next metering. + *ingress, *egress = make(trafficMap), make(trafficMap) + newPeerEvents = newPeerEvents[:0] + case err := <-subPeer.Err(): + log.Warn("Peer subscription error", "err", err) + return + case errc := <-db.quit: + errc <- nil + return + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/system.go b/vendor/github.com/ethereum/go-ethereum/dashboard/system.go new file mode 100644 index 00000000..a880c5a7 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/dashboard/system.go @@ -0,0 +1,146 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package dashboard + +import ( + "runtime" + "time" + + "github.com/elastic/gosigar" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/p2p" +) + +// meterCollector returns a function, which retrieves the count of a specific meter. +func meterCollector(name string) func() int64 { + if meter := metrics.Get(name); meter != nil { + m := meter.(metrics.Meter) + return func() int64 { + return m.Count() + } + } + return func() int64 { + return 0 + } +} + +// collectSystemData gathers data about the system and sends it to the clients. +func (db *Dashboard) collectSystemData() { + defer db.wg.Done() + + systemCPUUsage := gosigar.Cpu{} + systemCPUUsage.Get() + var ( + mem runtime.MemStats + + collectNetworkIngress = meterCollector(p2p.MetricsInboundTraffic) + collectNetworkEgress = meterCollector(p2p.MetricsOutboundTraffic) + collectDiskRead = meterCollector("eth/db/chaindata/disk/read") + collectDiskWrite = meterCollector("eth/db/chaindata/disk/write") + + prevNetworkIngress = collectNetworkIngress() + prevNetworkEgress = collectNetworkEgress() + prevProcessCPUTime = getProcessCPUTime() + prevSystemCPUUsage = systemCPUUsage + prevDiskRead = collectDiskRead() + prevDiskWrite = collectDiskWrite() + + frequency = float64(db.config.Refresh / time.Second) + numCPU = float64(runtime.NumCPU()) + ) + + for { + select { + case errc := <-db.quit: + errc <- nil + return + case <-time.After(db.config.Refresh): + systemCPUUsage.Get() + var ( + curNetworkIngress = collectNetworkIngress() + curNetworkEgress = collectNetworkEgress() + curProcessCPUTime = getProcessCPUTime() + curSystemCPUUsage = systemCPUUsage + curDiskRead = collectDiskRead() + curDiskWrite = collectDiskWrite() + + deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress) + deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress) + deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime + deltaSystemCPUUsage = curSystemCPUUsage.Delta(prevSystemCPUUsage) + deltaDiskRead = curDiskRead - prevDiskRead + deltaDiskWrite = curDiskWrite - prevDiskWrite + ) + prevNetworkIngress = curNetworkIngress + prevNetworkEgress = curNetworkEgress + prevProcessCPUTime = curProcessCPUTime + prevSystemCPUUsage = curSystemCPUUsage + prevDiskRead = curDiskRead + prevDiskWrite = curDiskWrite + + runtime.ReadMemStats(&mem) + activeMemory := &ChartEntry{ + Value: float64(mem.Alloc) / frequency, + } + virtualMemory := &ChartEntry{ + Value: float64(mem.Sys) / frequency, + } + networkIngress := &ChartEntry{ + Value: deltaNetworkIngress / frequency, + } + networkEgress := &ChartEntry{ + Value: deltaNetworkEgress / frequency, + } + processCPU := &ChartEntry{ + Value: deltaProcessCPUTime / frequency / numCPU * 100, + } + systemCPU := &ChartEntry{ + Value: float64(deltaSystemCPUUsage.Sys+deltaSystemCPUUsage.User) / frequency / numCPU, + } + diskRead := &ChartEntry{ + Value: float64(deltaDiskRead) / frequency, + } + diskWrite := &ChartEntry{ + Value: float64(deltaDiskWrite) / frequency, + } + db.sysLock.Lock() + sys := db.history.System + sys.ActiveMemory = append(sys.ActiveMemory[1:], activeMemory) + sys.VirtualMemory = append(sys.VirtualMemory[1:], virtualMemory) + sys.NetworkIngress = append(sys.NetworkIngress[1:], networkIngress) + sys.NetworkEgress = append(sys.NetworkEgress[1:], networkEgress) + sys.ProcessCPU = append(sys.ProcessCPU[1:], processCPU) + sys.SystemCPU = append(sys.SystemCPU[1:], systemCPU) + sys.DiskRead = append(sys.DiskRead[1:], diskRead) + sys.DiskWrite = append(sys.DiskWrite[1:], diskWrite) + db.sysLock.Unlock() + + db.sendToAll(&Message{ + System: &SystemMessage{ + ActiveMemory: ChartEntries{activeMemory}, + VirtualMemory: ChartEntries{virtualMemory}, + NetworkIngress: ChartEntries{networkIngress}, + NetworkEgress: ChartEntries{networkEgress}, + ProcessCPU: ChartEntries{processCPU}, + SystemCPU: ChartEntries{systemCPU}, + DiskRead: ChartEntries{diskRead}, + DiskWrite: ChartEntries{diskWrite}, + }, + }) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/docs/audits/2017-04-25_Geth-audit_Truesec.pdf b/vendor/github.com/ethereum/go-ethereum/docs/audits/2017-04-25_Geth-audit_Truesec.pdf new file mode 100644 index 00000000..702dc995 Binary files /dev/null and b/vendor/github.com/ethereum/go-ethereum/docs/audits/2017-04-25_Geth-audit_Truesec.pdf differ diff --git a/vendor/github.com/ethereum/go-ethereum/docs/audits/2018-09-14_Clef-audit_NCC.pdf b/vendor/github.com/ethereum/go-ethereum/docs/audits/2018-09-14_Clef-audit_NCC.pdf new file mode 100644 index 00000000..1a5c66f1 Binary files /dev/null and b/vendor/github.com/ethereum/go-ethereum/docs/audits/2018-09-14_Clef-audit_NCC.pdf differ diff --git a/vendor/github.com/ethereum/go-ethereum/eth/api.go b/vendor/github.com/ethereum/go-ethereum/eth/api.go index 3ec3afb8..bdbbd1ba 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/api.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/api.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -70,7 +69,7 @@ func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 { // ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config. func (api *PublicEthereumAPI) ChainId() hexutil.Uint64 { chainID := new(big.Int) - if config := api.e.chainConfig; config.IsEIP155(api.e.blockchain.CurrentBlock().Number()) { + if config := api.e.blockchain.Config(); config.IsEIP155(api.e.blockchain.CurrentBlock().Number()) { chainID = config.ChainID } return (hexutil.Uint64)(chainID.Uint64()) @@ -288,14 +287,13 @@ func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error // PrivateDebugAPI is the collection of Ethereum full node APIs exposed over // the private debugging endpoint. type PrivateDebugAPI struct { - config *params.ChainConfig - eth *Ethereum + eth *Ethereum } // NewPrivateDebugAPI creates a new API definition for the full node-related // private debug methods of the Ethereum service. -func NewPrivateDebugAPI(config *params.ChainConfig, eth *Ethereum) *PrivateDebugAPI { - return &PrivateDebugAPI{config: config, eth: eth} +func NewPrivateDebugAPI(eth *Ethereum) *PrivateDebugAPI { + return &PrivateDebugAPI{eth: eth} } // Preimage is a debug API function that returns the preimage for a sha3 hash, if known. @@ -444,16 +442,16 @@ func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Bloc if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) } + triedb := api.eth.BlockChain().StateCache().TrieDB() - oldTrie, err := trie.NewSecure(startBlock.Root(), trie.NewDatabase(api.eth.chainDb), 0) + oldTrie, err := trie.NewSecure(startBlock.Root(), triedb) if err != nil { return nil, err } - newTrie, err := trie.NewSecure(endBlock.Root(), trie.NewDatabase(api.eth.chainDb), 0) + newTrie, err := trie.NewSecure(endBlock.Root(), triedb) if err != nil { return nil, err } - diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{})) iter := trie.NewIterator(diff) diff --git a/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go b/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go index 8748d444..7e90f801 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/api_backend.go @@ -44,7 +44,7 @@ type EthAPIBackend struct { // ChainConfig returns the active chain configuration. func (b *EthAPIBackend) ChainConfig() *params.ChainConfig { - return b.eth.chainConfig + return b.eth.blockchain.Config() } func (b *EthAPIBackend) CurrentBlock() *types.Block { @@ -125,12 +125,12 @@ func (b *EthAPIBackend) GetTd(blockHash common.Hash) *big.Int { return b.eth.blockchain.GetTdByHash(blockHash) } -func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { +func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) { state.SetBalance(msg.From(), math.MaxBig256) vmError := func() error { return nil } context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil) - return vm.NewEVM(context, state, b.eth.chainConfig, vmCfg), vmError, nil + return vm.NewEVM(context, state, b.eth.blockchain.Config(), *b.eth.blockchain.GetVMConfig()), vmError, nil } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { diff --git a/vendor/github.com/ethereum/go-ethereum/eth/api_test.go b/vendor/github.com/ethereum/go-ethereum/eth/api_test.go index 47b062a4..cdd5bb8e 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/api_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/api_test.go @@ -22,8 +22,8 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/ethdb" ) var dumper = spew.ConfigState{Indent: " "} @@ -31,7 +31,7 @@ var dumper = spew.ConfigState{Indent: " "} func TestStorageRangeAt(t *testing.T) { // Create a state where account 0x010000... has a few storage entries. var ( - state, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) addr = common.Address{0x01} keys = []common.Hash{ // hashes of Keys of storage common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"), diff --git a/vendor/github.com/ethereum/go-ethereum/eth/api_tracer.go b/vendor/github.com/ethereum/go-ethereum/eth/api_tracer.go index 80552ada..2800ff65 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/api_tracer.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/api_tracer.go @@ -17,11 +17,13 @@ package eth import ( + "bufio" "bytes" "context" "errors" "fmt" "io/ioutil" + "os" "runtime" "sync" "time" @@ -60,6 +62,13 @@ type TraceConfig struct { Reexec *uint64 } +// StdTraceConfig holds extra parameters to standard-json trace functions. +type StdTraceConfig struct { + *vm.LogConfig + Reexec *uint64 + TxHash common.Hash +} + // txTraceResult is the result of a single transaction trace. type txTraceResult struct { Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer @@ -138,7 +147,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl // Ensure we have a valid starting state before doing any work origin := start.NumberU64() - database := state.NewDatabase(api.eth.ChainDb()) + database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16) // Chain tracing will probably start at genesis if number := start.NumberU64(); number > 0 { start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1) @@ -192,7 +201,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl // Fetch and execute the next block trace tasks for task := range tasks { - signer := types.MakeSigner(api.config, task.block.Number()) + signer := types.MakeSigner(api.eth.blockchain.Config(), task.block.Number()) // Trace all the transactions contained within for i, tx := range task.block.Transactions() { @@ -205,7 +214,8 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } - task.statedb.Finalise(true) + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + task.statedb.Finalise(api.eth.blockchain.Config().IsEIP158(task.block.Number())) task.results[i] = &txTraceResult{Result: res} } // Stream the result back to the user or abort on teardown @@ -285,7 +295,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl break } // Finalize the state so any modifications are written to the trie - root, err := statedb.Commit(true) + root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number())) if err != nil { failed = err break @@ -366,7 +376,7 @@ func (api *PrivateDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.B func (api *PrivateDebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) { block := api.eth.blockchain.GetBlockByHash(hash) if block == nil { - return nil, fmt.Errorf("block #%x not found", hash) + return nil, fmt.Errorf("block %#x not found", hash) } return api.traceBlock(ctx, block, config) } @@ -391,13 +401,41 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string, return api.TraceBlock(ctx, blob, config) } -// TraceBadBlock returns the structured logs created during the execution of a block -// within the blockchain 'badblocks' cache -func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, index int, config *TraceConfig) ([]*txTraceResult, error) { - if blocks := api.eth.blockchain.BadBlocks(); index < len(blocks) { - return api.traceBlock(ctx, blocks[index], config) +// TraceBadBlockByHash returns the structured logs created during the execution of +// EVM against a block pulled from the pool of bad ones and returns them as a JSON +// object. +func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) { + blocks := api.eth.blockchain.BadBlocks() + for _, block := range blocks { + if block.Hash() == hash { + return api.traceBlock(ctx, block, config) + } } - return nil, fmt.Errorf("index out of range") + return nil, fmt.Errorf("bad block %#x not found", hash) +} + +// StandardTraceBlockToFile dumps the structured logs created during the +// execution of EVM to the local file system and returns a list of files +// to the caller. +func (api *PrivateDebugAPI) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) { + block := api.eth.blockchain.GetBlockByHash(hash) + if block == nil { + return nil, fmt.Errorf("block %#x not found", hash) + } + return api.standardTraceBlockToFile(ctx, block, config) +} + +// StandardTraceBadBlockToFile dumps the structured logs created during the +// execution of EVM against a block pulled from the pool of bad ones to the +// local file system and returns a list of files to the caller. +func (api *PrivateDebugAPI) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) { + blocks := api.eth.blockchain.BadBlocks() + for _, block := range blocks { + if block.Hash() == hash { + return api.standardTraceBlockToFile(ctx, block, config) + } + } + return nil, fmt.Errorf("bad block %#x not found", hash) } // traceBlock configures a new tracer according to the provided configuration, and @@ -410,7 +448,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, } parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { - return nil, fmt.Errorf("parent %x not found", block.ParentHash()) + return nil, fmt.Errorf("parent %#x not found", block.ParentHash()) } reexec := defaultTraceReexec if config != nil && config.Reexec != nil { @@ -422,7 +460,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, } // Execute all the transaction contained within the block concurrently var ( - signer = types.MakeSigner(api.config, block.Number()) + signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number()) txs = block.Transactions() results = make([]*txTraceResult, len(txs)) @@ -463,13 +501,14 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, msg, _ := tx.AsMessage(signer) vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{}) + vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err break } // Finalize the state so any modifications are written to the trie - statedb.Finalise(true) + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) } close(jobs) pend.Wait() @@ -481,6 +520,116 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, return results, nil } +// standardTraceBlockToFile configures a new tracer which uses standard JSON output, +// and traces either a full block or an individual transaction. The return value will +// be one filename per transaction traced. +func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) { + // If we're tracing a single transaction, make sure it's present + if config != nil && config.TxHash != (common.Hash{}) { + if !containsTx(block, config.TxHash) { + return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash) + } + } + // Create the parent state database + if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil { + return nil, err + } + parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) + if parent == nil { + return nil, fmt.Errorf("parent %#x not found", block.ParentHash()) + } + reexec := defaultTraceReexec + if config != nil && config.Reexec != nil { + reexec = *config.Reexec + } + statedb, err := api.computeStateDB(parent, reexec) + if err != nil { + return nil, err + } + // Retrieve the tracing configurations, or use default values + var ( + logConfig vm.LogConfig + txHash common.Hash + ) + if config != nil { + if config.LogConfig != nil { + logConfig = *config.LogConfig + } + txHash = config.TxHash + } + logConfig.Debug = true + + // Execute transaction, either tracing all or just the requested one + var ( + signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number()) + dumps []string + ) + for i, tx := range block.Transactions() { + // Prepare the trasaction for un-traced execution + var ( + msg, _ = tx.AsMessage(signer) + vmctx = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) + + vmConf vm.Config + dump *os.File + writer *bufio.Writer + err error + ) + // If the transaction needs tracing, swap out the configs + if tx.Hash() == txHash || txHash == (common.Hash{}) { + // Generate a unique temporary file to dump it into + prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4]) + + dump, err = ioutil.TempFile(os.TempDir(), prefix) + if err != nil { + return nil, err + } + dumps = append(dumps, dump.Name()) + + // Swap out the noop logger to the standard tracer + writer = bufio.NewWriter(dump) + vmConf = vm.Config{ + Debug: true, + Tracer: vm.NewJSONLogger(&logConfig, writer), + EnablePreimageRecording: true, + } + } + // Execute the transaction and flush any traces to disk + vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vmConf) + _, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) + if writer != nil { + writer.Flush() + } + if dump != nil { + dump.Close() + log.Info("Wrote standard trace", "file", dump.Name()) + } + if err != nil { + return dumps, err + } + // Finalize the state so any modifications are written to the trie + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + + // If we've traced the transaction we were looking for, abort + if tx.Hash() == txHash { + break + } + } + return dumps, nil +} + +// containsTx reports whether the transaction with a certain hash +// is contained within the specified block. +func containsTx(block *types.Block, hash common.Hash) bool { + for _, tx := range block.Transactions() { + if tx.Hash() == hash { + return true + } + } + return false +} + // computeStateDB retrieves the state database associated with a certain block. // If no state is locally available for the given block, a number of blocks are // attempted to be reexecuted to generate the desired state. @@ -492,7 +641,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* } // Otherwise try to reexec blocks until we find a state or reach our limit origin := block.NumberU64() - database := state.NewDatabase(api.eth.ChainDb()) + database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16) for i := uint64(0); i < reexec; i++ { block = api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) @@ -506,7 +655,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* if err != nil { switch err.(type) { case *trie.MissingNodeError: - return nil, errors.New("required historical state unavailable") + return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec) default: return nil, err } @@ -520,7 +669,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* for block.NumberU64() < origin { // Print progress logs if long enough time elapsed if time.Since(logged) > 8*time.Second { - log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "elapsed", time.Since(start)) + log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "remaining", origin-block.NumberU64()-1, "elapsed", time.Since(start)) logged = time.Now() } // Retrieve the next block to regenerate and process it @@ -529,15 +678,15 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* } _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{}) if err != nil { - return nil, err + return nil, fmt.Errorf("processing block %d failed: %v", block.NumberU64(), err) } // Finalize the state so any modifications are written to the trie - root, err := statedb.Commit(true) + root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number())) if err != nil { return nil, err } if err := statedb.Reset(root); err != nil { - return nil, err + return nil, fmt.Errorf("state reset after block %d failed: %v", block.NumberU64(), err) } database.TrieDB().Reference(root, common.Hash{}) if proot != (common.Hash{}) { @@ -556,7 +705,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha // Retrieve the transaction and assemble its EVM context tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash) if tx == nil { - return nil, fmt.Errorf("transaction %x not found", hash) + return nil, fmt.Errorf("transaction %#x not found", hash) } reexec := defaultTraceReexec if config != nil && config.Reexec != nil { @@ -607,7 +756,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v tracer = vm.NewStructLogger(config.LogConfig) } // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) + vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer}) ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { @@ -636,18 +785,18 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree // Create the parent state database block := api.eth.blockchain.GetBlockByHash(blockHash) if block == nil { - return nil, vm.Context{}, nil, fmt.Errorf("block %x not found", blockHash) + return nil, vm.Context{}, nil, fmt.Errorf("block %#x not found", blockHash) } parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { - return nil, vm.Context{}, nil, fmt.Errorf("parent %x not found", block.ParentHash()) + return nil, vm.Context{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash()) } statedb, err := api.computeStateDB(parent, reexec) if err != nil { return nil, vm.Context{}, nil, err } // Recompute transactions up to the target index. - signer := types.MakeSigner(api.config, block.Number()) + signer := types.MakeSigner(api.eth.blockchain.Config(), block.Number()) for idx, tx := range block.Transactions() { // Assemble the transaction call message and return if the requested offset @@ -657,12 +806,13 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree return msg, context, statedb, nil } // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{}) + vmenv := vm.NewEVM(context, statedb, api.eth.blockchain.Config(), vm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { - return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) + return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state - statedb.Finalise(true) + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) } - return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash) + return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, blockHash) } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/backend.go b/vendor/github.com/ethereum/go-ethereum/eth/backend.go index b555b064..ac2f903e 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/backend.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/backend.go @@ -54,14 +54,14 @@ import ( type LesServer interface { Start(srvr *p2p.Server) Stop() + APIs() []rpc.API Protocols() []p2p.Protocol SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) } // Ethereum implements the Ethereum full node service. type Ethereum struct { - config *Config - chainConfig *params.ChainConfig + config *Config // Channel for shutting down the service shutdownChan chan bool // Channel for shutting down the Ethereum @@ -113,12 +113,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { log.Warn("Sanitizing invalid miner gas price", "provided", config.MinerGasPrice, "updated", DefaultConfig.MinerGasPrice) config.MinerGasPrice = new(big.Int).Set(DefaultConfig.MinerGasPrice) } + if config.NoPruning && config.TrieDirtyCache > 0 { + config.TrieCleanCache += config.TrieDirtyCache + config.TrieDirtyCache = 0 + } + log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) + // Assemble the Ethereum object - chainDb, err := CreateDB(ctx, config, "chaindata") + chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } @@ -127,7 +133,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { eth := &Ethereum{ config: config, chainDb: chainDb, - chainConfig: chainConfig, eventMux: ctx.EventMux, accountManager: ctx.AccountManager, engine: CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.MinerNotify, config.MinerNoverify, chainDb), @@ -139,14 +144,20 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), } - log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId) + bcVersion := rawdb.ReadDatabaseVersion(chainDb) + var dbVer = "" + if bcVersion != nil { + dbVer = fmt.Sprintf("%d", *bcVersion) + } + log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId, "dbversion", dbVer) if !config.SkipBcVersionCheck { - bcVersion := rawdb.ReadDatabaseVersion(chainDb) - if bcVersion != core.BlockChainVersion && bcVersion != 0 { - return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d).\n", bcVersion, core.BlockChainVersion) + if bcVersion != nil && *bcVersion > core.BlockChainVersion { + return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) + } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { + log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) + rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) } - rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) } var ( vmConfig = vm.Config{ @@ -154,9 +165,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { EWASMInterpreter: config.EWASMInterpreter, EVMInterpreter: config.EVMInterpreter, } - cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout} + cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieCleanLimit: config.TrieCleanCache, TrieDirtyLimit: config.TrieDirtyCache, TrieTimeLimit: config.TrieTimeout} ) - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve) + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve) if err != nil { return nil, err } @@ -171,13 +182,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if config.TxPool.Journal != "" { config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) } - eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) + eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain) - if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { + if eth.protocolManager, err = NewProtocolManager(chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, config.Whitelist); err != nil { return nil, err } - eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil, eth.isLocalBlock) + eth.miner = miner.New(eth, chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil, eth.isLocalBlock) eth.miner.SetExtra(makeExtraData(config.MinerExtraData)) eth.APIBackend = &EthAPIBackend{eth, nil} @@ -207,18 +218,6 @@ func makeExtraData(extra []byte) []byte { return extra } -// CreateDB creates the chain database. -func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) { - db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) - if err != nil { - return nil, err - } - if db, ok := db.(*ethdb.LDBDatabase); ok { - db.Meter("eth/db/chaindata/") - } - return db, nil -} - // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up @@ -255,6 +254,10 @@ func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainCo func (s *Ethereum) APIs() []rpc.API { apis := ethapi.GetAPIs(s.APIBackend) + // Append any APIs exposed explicitly by the les server + if s.lesServer != nil { + apis = append(apis, s.lesServer.APIs()...) + } // Append any APIs exposed explicitly by the consensus engine apis = append(apis, s.engine.APIs(s.BlockChain())...) @@ -297,7 +300,7 @@ func (s *Ethereum) APIs() []rpc.API { }, { Namespace: "debug", Version: "1.0", - Service: NewPrivateDebugAPI(s.chainConfig, s), + Service: NewPrivateDebugAPI(s), }, { Namespace: "net", Version: "1.0", @@ -432,7 +435,7 @@ func (s *Ethereum) StartMining(threads int) error { log.Error("Etherbase account unavailable locally", "err", err) return fmt.Errorf("signer missing: %v", err) } - clique.Authorize(eb, wallet.SignHash) + clique.Authorize(eb, wallet.SignData) } // If mining is started, we can disable the transaction rejection mechanism // introduced to speed sync times. diff --git a/vendor/github.com/ethereum/go-ethereum/eth/bloombits.go b/vendor/github.com/ethereum/go-ethereum/eth/bloombits.go index c7bb5614..9a31997d 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/bloombits.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/bloombits.go @@ -102,7 +102,7 @@ func NewBloomIndexer(db ethdb.Database, size, confirms uint64) *core.ChainIndexe db: db, size: size, } - table := ethdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix)) + table := rawdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix)) return core.NewChainIndexer(db, table, backend, size, confirms, bloomThrottling, "bloombits") } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/config.go b/vendor/github.com/ethereum/go-ethereum/eth/config.go index e32c01a7..1bbe326d 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/config.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/config.go @@ -43,15 +43,16 @@ var DefaultConfig = Config{ DatasetsInMem: 1, DatasetsOnDisk: 2, }, - NetworkId: 1, - LightPeers: 100, - DatabaseCache: 768, - TrieCache: 256, - TrieTimeout: 60 * time.Minute, - MinerGasFloor: 8000000, - MinerGasCeil: 8000000, - MinerGasPrice: big.NewInt(params.GWei), - MinerRecommit: 3 * time.Second, + NetworkId: 1, + LightPeers: 100, + DatabaseCache: 512, + TrieCleanCache: 256, + TrieDirtyCache: 256, + TrieTimeout: 60 * time.Minute, + MinerGasFloor: 8000000, + MinerGasCeil: 8000000, + MinerGasPrice: big.NewInt(params.GWei), + MinerRecommit: 3 * time.Second, TxPool: core.DefaultTxPoolConfig, GPO: gasprice.Config{ @@ -67,8 +68,15 @@ func init() { home = user.HomeDir } } - if runtime.GOOS == "windows" { - DefaultConfig.Ethash.DatasetDir = filepath.Join(home, "AppData", "Ethash") + if runtime.GOOS == "darwin" { + DefaultConfig.Ethash.DatasetDir = filepath.Join(home, "Library", "Ethash") + } else if runtime.GOOS == "windows" { + localappdata := os.Getenv("LOCALAPPDATA") + if localappdata != "" { + DefaultConfig.Ethash.DatasetDir = filepath.Join(localappdata, "Ethash") + } else { + DefaultConfig.Ethash.DatasetDir = filepath.Join(home, "AppData", "Local", "Ethash") + } } else { DefaultConfig.Ethash.DatasetDir = filepath.Join(home, ".ethash") } @@ -86,16 +94,27 @@ type Config struct { SyncMode downloader.SyncMode NoPruning bool + // Whitelist of required block number -> hash values to accept + Whitelist map[uint64]common.Hash `toml:"-"` + // Light client options - LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests - LightPeers int `toml:",omitempty"` // Maximum number of LES client peers + LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests + LightBandwidthIn int `toml:",omitempty"` // Incoming bandwidth limit for light servers + LightBandwidthOut int `toml:",omitempty"` // Outgoing bandwidth limit for light servers + LightPeers int `toml:",omitempty"` // Maximum number of LES client peers + OnlyAnnounce bool // Maximum number of LES client peers + + // Ultra Light client options + ULC *ULCConfig `toml:",omitempty"` // Database options SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` DatabaseCache int - TrieCache int - TrieTimeout time.Duration + + TrieCleanCache int + TrieDirtyCache int + TrieTimeout time.Duration // Mining-related options Etherbase common.Address `toml:",omitempty"` @@ -124,8 +143,12 @@ type Config struct { // Type of the EWASM interpreter ("" for default) EWASMInterpreter string + // Type of the EVM interpreter ("" for default) EVMInterpreter string + + // Constantinople block override (TODO: remove after the fork) + ConstantinopleOverride *big.Int } type configMarshaling struct { diff --git a/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader.go b/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader.go index 56c54c8e..d926d7aa 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader.go @@ -99,6 +99,7 @@ type Downloader struct { mode SyncMode // Synchronisation mode defining the strategy used (per sync cycle) mux *event.TypeMux // Event multiplexer to announce sync operation events + genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT) queue *queue // Scheduler for selecting the hashes to download peers *peerSet // Set of active peers from which download can proceed stateDB ethdb.Database @@ -181,6 +182,9 @@ type BlockChain interface { // HasBlock verifies a block's presence in the local chain. HasBlock(common.Hash, uint64) bool + // HasFastBlock verifies a fast block's presence in the local chain. + HasFastBlock(common.Hash, uint64) bool + // GetBlockByHash retrieves a block from the local chain. GetBlockByHash(common.Hash) *types.Block @@ -411,7 +415,8 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I if err != nil { d.mux.Post(FailedEvent{err}) } else { - d.mux.Post(DoneEvent{}) + latest := d.lightchain.CurrentHeader() + d.mux.Post(DoneEvent{latest}) } }() if p.version < 62 { @@ -430,7 +435,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I } height := latest.Number.Uint64() - origin, err := d.findAncestor(p, height) + origin, err := d.findAncestor(p, latest) if err != nil { return err } @@ -587,41 +592,109 @@ func (d *Downloader) fetchHeight(p *peerConnection) (*types.Header, error) { } } +// calculateRequestSpan calculates what headers to request from a peer when trying to determine the +// common ancestor. +// It returns parameters to be used for peer.RequestHeadersByNumber: +// from - starting block number +// count - number of headers to request +// skip - number of headers to skip +// and also returns 'max', the last block which is expected to be returned by the remote peers, +// given the (from,count,skip) +func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) { + var ( + from int + count int + MaxCount = MaxHeaderFetch / 16 + ) + // requestHead is the highest block that we will ask for. If requestHead is not offset, + // the highest block that we will get is 16 blocks back from head, which means we + // will fetch 14 or 15 blocks unnecessarily in the case the height difference + // between us and the peer is 1-2 blocks, which is most common + requestHead := int(remoteHeight) - 1 + if requestHead < 0 { + requestHead = 0 + } + // requestBottom is the lowest block we want included in the query + // Ideally, we want to include just below own head + requestBottom := int(localHeight - 1) + if requestBottom < 0 { + requestBottom = 0 + } + totalSpan := requestHead - requestBottom + span := 1 + totalSpan/MaxCount + if span < 2 { + span = 2 + } + if span > 16 { + span = 16 + } + + count = 1 + totalSpan/span + if count > MaxCount { + count = MaxCount + } + if count < 2 { + count = 2 + } + from = requestHead - (count-1)*span + if from < 0 { + from = 0 + } + max := from + (count-1)*span + return int64(from), count, span - 1, uint64(max) +} + // findAncestor tries to locate the common ancestor link of the local chain and // a remote peers blockchain. In the general case when our node was in sync and // on the correct chain, checking the top N links should already get us a match. // In the rare scenario when we ended up on a long reorganisation (i.e. none of // the head links match), we do a binary search to find the common ancestor. -func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, error) { +func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) { // Figure out the valid ancestor range to prevent rewrite attacks - floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64() + var ( + floor = int64(-1) + localHeight uint64 + remoteHeight = remoteHeader.Number.Uint64() + ) + switch d.mode { + case FullSync: + localHeight = d.blockchain.CurrentBlock().NumberU64() + case FastSync: + localHeight = d.blockchain.CurrentFastBlock().NumberU64() + default: + localHeight = d.lightchain.CurrentHeader().Number.Uint64() + } + p.log.Debug("Looking for common ancestor", "local", localHeight, "remote", remoteHeight) - if d.mode == FullSync { - ceil = d.blockchain.CurrentBlock().NumberU64() - } else if d.mode == FastSync { - ceil = d.blockchain.CurrentFastBlock().NumberU64() + // Recap floor value for binary search + if localHeight >= MaxForkAncestry { + // We're above the max reorg threshold, find the earliest fork point + floor = int64(localHeight - MaxForkAncestry) } - if ceil >= MaxForkAncestry { - floor = int64(ceil - MaxForkAncestry) + // If we're doing a light sync, ensure the floor doesn't go below the CHT, as + // all headers before that point will be missing. + if d.mode == LightSync { + // If we dont know the current CHT position, find it + if d.genesis == 0 { + header := d.lightchain.CurrentHeader() + for header != nil { + d.genesis = header.Number.Uint64() + if floor >= int64(d.genesis)-1 { + break + } + header = d.lightchain.GetHeaderByHash(header.ParentHash) + } + } + // We already know the "genesis" block number, cap floor to that + if floor < int64(d.genesis)-1 { + floor = int64(d.genesis) - 1 + } } - p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height) - // Request the topmost blocks to short circuit binary ancestor lookup - head := ceil - if head > height { - head = height - } - from := int64(head) - int64(MaxHeaderFetch) - if from < 0 { - from = 0 - } - // Span out with 15 block gaps into the future to catch bad head reports - limit := 2 * MaxHeaderFetch / 16 - count := 1 + int((int64(ceil)-from)/16) - if count > limit { - count = limit - } - go p.peer.RequestHeadersByNumber(uint64(from), count, 15, false) + from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight) + + p.log.Trace("Span searching for common ancestor", "count", count, "from", from, "skip", skip) + go p.peer.RequestHeadersByNumber(uint64(from), count, skip, false) // Wait for the remote response to the head fetch number, hash := uint64(0), common.Hash{} @@ -647,9 +720,10 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err return 0, errEmptyHeaderSet } // Make sure the peer's reply conforms to the request - for i := 0; i < len(headers); i++ { - if number := headers[i].Number.Int64(); number != from+int64(i)*16 { - p.log.Warn("Head headers broke chain ordering", "index", i, "requested", from+int64(i)*16, "received", number) + for i, header := range headers { + expectNumber := from + int64(i)*int64(skip+1) + if number := header.Number.Int64(); number != expectNumber { + p.log.Warn("Head headers broke chain ordering", "index", i, "requested", expectNumber, "received", number) return 0, errInvalidChain } } @@ -657,20 +731,24 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err finished = true for i := len(headers) - 1; i >= 0; i-- { // Skip any headers that underflow/overflow our requested set - if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > ceil { + if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > max { continue } // Otherwise check if we already know the header or not h := headers[i].Hash() n := headers[i].Number.Uint64() - if (d.mode == FullSync && d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && d.lightchain.HasHeader(h, n)) { - number, hash = n, h - // If every header is known, even future ones, the peer straight out lied about its head - if number > height && i == limit-1 { - p.log.Warn("Lied about chain head", "reported", height, "found", number) - return 0, errStallingPeer - } + var known bool + switch d.mode { + case FullSync: + known = d.blockchain.HasBlock(h, n) + case FastSync: + known = d.blockchain.HasFastBlock(h, n) + default: + known = d.lightchain.HasHeader(h, n) + } + if known { + number, hash = n, h break } } @@ -694,10 +772,12 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err return number, nil } // Ancestor not found, we need to binary search over our chain - start, end := uint64(0), head + start, end := uint64(0), remoteHeight if floor > 0 { start = uint64(floor) } + p.log.Trace("Binary searching for common ancestor", "start", start, "end", end) + for start+1 < end { // Split our chain interval in two, and request the hash to cross check check := (start + end) / 2 @@ -730,7 +810,17 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err // Modify the search interval based on the response h := headers[0].Hash() n := headers[0].Number.Uint64() - if (d.mode == FullSync && !d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && !d.lightchain.HasHeader(h, n)) { + + var known bool + switch d.mode { + case FullSync: + known = d.blockchain.HasBlock(h, n) + case FastSync: + known = d.blockchain.HasFastBlock(h, n) + default: + known = d.lightchain.HasHeader(h, n) + } + if !known { end = check break } @@ -1282,7 +1372,6 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er } // Otherwise split the chunk of headers into batches and process them gotHeaders = true - for len(headers) > 0 { // Terminate if something failed in between processing chunks select { @@ -1345,7 +1434,6 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er headers = headers[limit:] origin += uint64(limit) } - // Update the highest block number we know if a higher one is found. d.syncStatsLock.Lock() if d.syncStatsChainHeight < origin { @@ -1401,7 +1489,15 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) } if index, err := d.blockchain.InsertChain(blocks); err != nil { - log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) + if index < len(results) { + log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) + } else { + // The InsertChain method in blockchain.go will sometimes return an out-of-bounds index, + // when it needs to preprocess blocks to import a sidechain. + // The importer will put together a new list of blocks to import, which is a superset + // of the blocks delivered from the downloader, and the indexing will be off. + log.Debug("Downloaded item processing failed on sidechain import", "index", index, "err", err) + } return errInvalidChain } return nil diff --git a/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader_test.go b/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader_test.go index 1fe02d88..bee6438b 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/downloader/downloader_test.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "math/big" + "strings" "sync" "sync/atomic" "testing" @@ -27,6 +28,7 @@ import ( ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -70,8 +72,9 @@ func newTester() *downloadTester { ownReceipts: map[common.Hash]types.Receipts{testGenesis.Hash(): nil}, ownChainTd: map[common.Hash]*big.Int{testGenesis.Hash(): testGenesis.Difficulty()}, } - tester.stateDb = ethdb.NewMemDatabase() + tester.stateDb = rawdb.NewMemoryDatabase() tester.stateDb.Put(testGenesis.Root().Bytes(), []byte{0x00}) + tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer) return tester } @@ -114,6 +117,15 @@ func (dl *downloadTester) HasBlock(hash common.Hash, number uint64) bool { return dl.GetBlockByHash(hash) != nil } +// HasFastBlock checks if a block is present in the testers canonical chain. +func (dl *downloadTester) HasFastBlock(hash common.Hash, number uint64) bool { + dl.lock.RLock() + defer dl.lock.RUnlock() + + _, ok := dl.ownReceipts[hash] + return ok +} + // GetHeader retrieves a header from the testers canonical chain. func (dl *downloadTester) GetHeaderByHash(hash common.Hash) *types.Header { dl.lock.RLock() @@ -175,7 +187,7 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block { func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error { // For now only check that the state trie is correct if block := dl.GetBlockByHash(hash); block != nil { - _, err := trie.NewSecure(block.Root(), trie.NewDatabase(dl.stateDb), 0) + _, err := trie.NewSecure(block.Root(), trie.NewDatabase(dl.stateDb)) return err } return fmt.Errorf("non existent block: %x", hash[:4]) @@ -234,6 +246,7 @@ func (dl *downloadTester) InsertChain(blocks types.Blocks) (i int, err error) { dl.ownHeaders[block.Hash()] = block.Header() } dl.ownBlocks[block.Hash()] = block + dl.ownReceipts[block.Hash()] = make(types.Receipts, 0) dl.stateDb.Put(block.Root().Bytes(), []byte{0x00}) dl.ownChainTd[block.Hash()] = new(big.Int).Add(dl.ownChainTd[block.ParentHash()], block.Difficulty()) } @@ -374,28 +387,28 @@ func (dlp *downloadTesterPeer) RequestNodeData(hashes []common.Hash) error { // assertOwnChain checks if the local chain contains the correct number of items // of the various chain components. func assertOwnChain(t *testing.T, tester *downloadTester, length int) { + // Mark this method as a helper to report errors at callsite, not in here + t.Helper() + assertOwnForkedChain(t, tester, 1, []int{length}) } // assertOwnForkedChain checks if the local forked chain contains the correct // number of items of the various chain components. func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, lengths []int) { - // Initialize the counters for the first fork - headers, blocks, receipts := lengths[0], lengths[0], lengths[0]-fsMinFullBlocks + // Mark this method as a helper to report errors at callsite, not in here + t.Helper() + + // Initialize the counters for the first fork + headers, blocks, receipts := lengths[0], lengths[0], lengths[0] - if receipts < 0 { - receipts = 1 - } // Update the counters for each subsequent fork for _, length := range lengths[1:] { headers += length - common blocks += length - common - receipts += length - common - fsMinFullBlocks + receipts += length - common } - switch tester.downloader.mode { - case FullSync: - receipts = 1 - case LightSync: + if tester.downloader.mode == LightSync { blocks, receipts = 1, 1 } if hs := len(tester.ownHeaders); hs != headers { @@ -1149,7 +1162,9 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { } func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.SyncProgress) { + // Mark this method as a helper to report errors at callsite, not in here t.Helper() + p := d.Progress() p.KnownStates, p.PulledStates = 0, 0 want.KnownStates, want.PulledStates = 0, 0 @@ -1479,3 +1494,78 @@ func (ftp *floodingTestPeer) RequestHeadersByNumber(from uint64, count, skip int } return nil } + +func TestRemoteHeaderRequestSpan(t *testing.T) { + testCases := []struct { + remoteHeight uint64 + localHeight uint64 + expected []int + }{ + // Remote is way higher. We should ask for the remote head and go backwards + {1500, 1000, + []int{1323, 1339, 1355, 1371, 1387, 1403, 1419, 1435, 1451, 1467, 1483, 1499}, + }, + {15000, 13006, + []int{14823, 14839, 14855, 14871, 14887, 14903, 14919, 14935, 14951, 14967, 14983, 14999}, + }, + //Remote is pretty close to us. We don't have to fetch as many + {1200, 1150, + []int{1149, 1154, 1159, 1164, 1169, 1174, 1179, 1184, 1189, 1194, 1199}, + }, + // Remote is equal to us (so on a fork with higher td) + // We should get the closest couple of ancestors + {1500, 1500, + []int{1497, 1499}, + }, + // We're higher than the remote! Odd + {1000, 1500, + []int{997, 999}, + }, + // Check some weird edgecases that it behaves somewhat rationally + {0, 1500, + []int{0, 2}, + }, + {6000000, 0, + []int{5999823, 5999839, 5999855, 5999871, 5999887, 5999903, 5999919, 5999935, 5999951, 5999967, 5999983, 5999999}, + }, + {0, 0, + []int{0, 2}, + }, + } + reqs := func(from, count, span int) []int { + var r []int + num := from + for len(r) < count { + r = append(r, num) + num += span + 1 + } + return r + } + for i, tt := range testCases { + from, count, span, max := calculateRequestSpan(tt.remoteHeight, tt.localHeight) + data := reqs(int(from), count, span) + + if max != uint64(data[len(data)-1]) { + t.Errorf("test %d: wrong last value %d != %d", i, data[len(data)-1], max) + } + failed := false + if len(data) != len(tt.expected) { + failed = true + t.Errorf("test %d: length wrong, expected %d got %d", i, len(tt.expected), len(data)) + } else { + for j, n := range data { + if n != tt.expected[j] { + failed = true + break + } + } + } + if failed { + res := strings.Replace(fmt.Sprint(data), " ", ",", -1) + exp := strings.Replace(fmt.Sprint(tt.expected), " ", ",", -1) + fmt.Printf("got: %v\n", res) + fmt.Printf("exp: %v\n", exp) + t.Errorf("test %d: wrong values", i) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/eth/downloader/events.go b/vendor/github.com/ethereum/go-ethereum/eth/downloader/events.go index 64905b8f..25255a3a 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/downloader/events.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/downloader/events.go @@ -16,6 +16,10 @@ package downloader -type DoneEvent struct{} +import "github.com/ethereum/go-ethereum/core/types" + +type DoneEvent struct { + Latest *types.Header +} type StartEvent struct{} type FailedEvent struct{ Err error } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/downloader/queue.go b/vendor/github.com/ethereum/go-ethereum/eth/downloader/queue.go index 863cc8de..7c339538 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/downloader/queue.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/downloader/queue.go @@ -325,7 +325,7 @@ func (q *queue) Schedule(headers []*types.Header, from uint64) []*types.Header { } // Make sure no duplicate requests are executed if _, ok := q.blockTaskPool[hash]; ok { - log.Warn("Header already scheduled for block fetch", "number", header.Number, "hash", hash) + log.Warn("Header already scheduled for block fetch", "number", header.Number, "hash", hash) continue } if _, ok := q.receiptTaskPool[hash]; ok { diff --git a/vendor/github.com/ethereum/go-ethereum/eth/downloader/statesync.go b/vendor/github.com/ethereum/go-ethereum/eth/downloader/statesync.go index 29d5ee4d..f294600b 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/downloader/statesync.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/downloader/statesync.go @@ -25,10 +25,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" + "golang.org/x/crypto/sha3" ) // stateReq represents a batch of state fetch requests grouped together into @@ -152,7 +152,7 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync { finished = append(finished, req) delete(active, pack.PeerId()) - // Handle dropped peer connections: + // Handle dropped peer connections: case p := <-peerDrop: // Skip if no request is currently pending req := active[p.id] @@ -240,7 +240,7 @@ func newStateSync(d *Downloader, root common.Hash) *stateSync { return &stateSync{ d: d, sched: state.NewStateSync(root, d.stateDB), - keccak: sha3.NewKeccak256(), + keccak: sha3.NewLegacyKeccak256(), tasks: make(map[common.Hash]*stateTask), deliver: make(chan *stateReq), cancel: make(chan struct{}), @@ -310,7 +310,13 @@ func (s *stateSync) loop() (err error) { // 2 items are the minimum requested, if even that times out, we've no use of // this peer at the moment. log.Warn("Stalling state sync, dropping peer", "peer", req.peer.id) - s.d.dropPeer(req.peer.id) + if s.d.dropPeer == nil { + // The dropPeer method is nil when `--copydb` is used for a local copy. + // Timeouts can occur if e.g. compaction hits at the wrong time, and can be ignored + req.peer.log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", req.peer.id) + } else { + s.d.dropPeer(req.peer.id) + } } // Process all the received blobs and check for stale delivery delivered, err := s.process(req) @@ -398,9 +404,8 @@ func (s *stateSync) fillTasks(n int, req *stateReq) { // process iterates over a batch of delivered state data, injecting each item // into a running state sync, re-queuing any items that were requested but not -// delivered. -// Returns whether the peer actually managed to deliver anything of value, -// and any error that occurred +// delivered. Returns whether the peer actually managed to deliver anything of +// value, and any error that occurred. func (s *stateSync) process(req *stateReq) (int, error) { // Collect processing stats and update progress if valid data was received duplicate, unexpected, successful := 0, 0, 0 @@ -412,14 +417,12 @@ func (s *stateSync) process(req *stateReq) (int, error) { }(time.Now()) // Iterate over all the delivered data and inject one-by-one into the trie - progress := false for _, blob := range req.response { - prog, hash, err := s.processNodeData(blob) + _, hash, err := s.processNodeData(blob) switch err { case nil: s.numUncommitted++ s.bytesUncommitted += len(blob) - progress = progress || prog successful++ case trie.ErrNotRequested: unexpected++ diff --git a/vendor/github.com/ethereum/go-ethereum/eth/downloader/testchain_test.go b/vendor/github.com/ethereum/go-ethereum/eth/downloader/testchain_test.go index 0b5a2142..4ae342dc 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/downloader/testchain_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/downloader/testchain_test.go @@ -24,9 +24,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -34,7 +34,7 @@ import ( var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) - testDB = ethdb.NewMemDatabase() + testDB = rawdb.NewMemoryDatabase() testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000)) ) diff --git a/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher.go b/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher.go index f0b5e806..94f05f96 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher.go @@ -110,7 +110,6 @@ type Fetcher struct { notify chan *announce inject chan *inject - blockFilter chan chan []*types.Block headerFilter chan chan *headerFilterTask bodyFilter chan chan *bodyFilterTask @@ -150,7 +149,6 @@ func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBloc return &Fetcher{ notify: make(chan *announce), inject: make(chan *inject), - blockFilter: make(chan chan []*types.Block), headerFilter: make(chan chan *headerFilterTask), bodyFilter: make(chan chan *bodyFilterTask), done: make(chan common.Hash), diff --git a/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher_test.go b/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher_test.go index 3d4f0d1e..83172c53 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/fetcher/fetcher_test.go @@ -27,14 +27,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) var ( - testdb = ethdb.NewMemDatabase() + testdb = rawdb.NewMemoryDatabase() testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) @@ -244,7 +244,7 @@ func verifyImportEvent(t *testing.T, imported chan *types.Block, arrive bool) { select { case <-imported: t.Fatalf("import invoked") - case <-time.After(10 * time.Millisecond): + case <-time.After(20 * time.Millisecond): } } } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/filters/bench_test.go b/vendor/github.com/ethereum/go-ethereum/eth/filters/bench_test.go index c5f681e0..434e6a44 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/filters/bench_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/filters/bench_test.go @@ -17,7 +17,6 @@ package filters import ( - "bytes" "context" "fmt" "testing" @@ -67,7 +66,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { benchDataDir := node.DefaultDataDir() + "/geth/chaindata" fmt.Println("Running bloombits benchmark section size:", sectionSize) - db, err := ethdb.NewLDBDatabase(benchDataDir, 128, 1024) + db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "") if err != nil { b.Fatalf("error opening database at %v: %v", benchDataDir, err) } @@ -129,7 +128,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { for i := 0; i < benchFilterCnt; i++ { if i%20 == 0 { db.Close() - db, _ = ethdb.NewLDBDatabase(benchDataDir, 128, 1024) + db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "") backend = &testBackend{mux, db, cnt, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)} } var addr common.Address @@ -146,37 +145,21 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { db.Close() } -func forEachKey(db ethdb.Database, startPrefix, endPrefix []byte, fn func(key []byte)) { - it := db.(*ethdb.LDBDatabase).NewIterator() - it.Seek(startPrefix) - for it.Valid() { - key := it.Key() - cmpLen := len(key) - if len(endPrefix) < cmpLen { - cmpLen = len(endPrefix) - } - if bytes.Compare(key[:cmpLen], endPrefix) == 1 { - break - } - fn(common.CopyBytes(key)) - it.Next() - } - it.Release() -} - var bloomBitsPrefix = []byte("bloomBits-") func clearBloomBits(db ethdb.Database) { fmt.Println("Clearing bloombits data...") - forEachKey(db, bloomBitsPrefix, bloomBitsPrefix, func(key []byte) { - db.Delete(key) - }) + it := db.NewIteratorWithPrefix(bloomBitsPrefix) + for it.Next() { + db.Delete(it.Key()) + } + it.Release() } func BenchmarkNoBloomBits(b *testing.B) { benchDataDir := node.DefaultDataDir() + "/geth/chaindata" fmt.Println("Running benchmark without bloombits") - db, err := ethdb.NewLDBDatabase(benchDataDir, 128, 1024) + db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "") if err != nil { b.Fatalf("error opening database at %v: %v", benchDataDir, err) } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_system_test.go b/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_system_test.go index e71080b1..e0c2a6a9 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_system_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_system_test.go @@ -161,7 +161,7 @@ func TestBlockSubscription(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) @@ -218,7 +218,7 @@ func TestPendingTxFilter(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) @@ -278,7 +278,7 @@ func TestPendingTxFilter(t *testing.T) { func TestLogFilterCreation(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) @@ -327,7 +327,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) @@ -354,7 +354,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { func TestInvalidGetLogsRequest(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) @@ -384,7 +384,7 @@ func TestLogFilter(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) @@ -503,7 +503,7 @@ func TestPendingLogsSubscription(t *testing.T) { var ( mux = new(event.TypeMux) - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) logsFeed = new(event.Feed) diff --git a/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_test.go b/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_test.go index 396a03d6..96d27bcf 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/filters/filter_test.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" ) @@ -51,7 +50,7 @@ func BenchmarkFilters(b *testing.B) { defer os.RemoveAll(dir) var ( - db, _ = ethdb.NewLDBDatabase(dir, 0, 0) + db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "") mux = new(event.TypeMux) txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) @@ -110,7 +109,7 @@ func TestFilters(t *testing.T) { defer os.RemoveAll(dir) var ( - db, _ = ethdb.NewLDBDatabase(dir, 0, 0) + db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "") mux = new(event.TypeMux) txFeed = new(event.Feed) rmLogsFeed = new(event.Feed) diff --git a/vendor/github.com/ethereum/go-ethereum/eth/gen_config.go b/vendor/github.com/ethereum/go-ethereum/eth/gen_config.go index d401a917..30ff8b6e 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/gen_config.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/gen_config.go @@ -23,12 +23,17 @@ func (c Config) MarshalTOML() (interface{}, error) { NetworkId uint64 SyncMode downloader.SyncMode NoPruning bool - LightServ int `toml:",omitempty"` - LightPeers int `toml:",omitempty"` - SkipBcVersionCheck bool `toml:"-"` - DatabaseHandles int `toml:"-"` + LightServ int `toml:",omitempty"` + LightBandwidthIn int `toml:",omitempty"` + LightBandwidthOut int `toml:",omitempty"` + LightPeers int `toml:",omitempty"` + OnlyAnnounce bool + ULC *ULCConfig `toml:",omitempty"` + SkipBcVersionCheck bool `toml:"-"` + DatabaseHandles int `toml:"-"` DatabaseCache int - TrieCache int + TrieCleanCache int + TrieDirtyCache int TrieTimeout time.Duration Etherbase common.Address `toml:",omitempty"` MinerNotify []string `toml:",omitempty"` @@ -43,6 +48,8 @@ func (c Config) MarshalTOML() (interface{}, error) { GPO gasprice.Config EnablePreimageRecording bool DocRoot string `toml:"-"` + EWASMInterpreter string + EVMInterpreter string } var enc Config enc.Genesis = c.Genesis @@ -50,11 +57,16 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.SyncMode = c.SyncMode enc.NoPruning = c.NoPruning enc.LightServ = c.LightServ + enc.LightBandwidthIn = c.LightBandwidthIn + enc.LightBandwidthOut = c.LightBandwidthOut enc.LightPeers = c.LightPeers + enc.OnlyAnnounce = c.OnlyAnnounce + enc.ULC = c.ULC enc.SkipBcVersionCheck = c.SkipBcVersionCheck enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache - enc.TrieCache = c.TrieCache + enc.TrieCleanCache = c.TrieCleanCache + enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout enc.Etherbase = c.Etherbase enc.MinerNotify = c.MinerNotify @@ -67,8 +79,11 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.Ethash = c.Ethash enc.TxPool = c.TxPool enc.GPO = c.GPO + enc.EnablePreimageRecording = c.EnablePreimageRecording enc.DocRoot = c.DocRoot + enc.EWASMInterpreter = c.EWASMInterpreter + enc.EVMInterpreter = c.EVMInterpreter return &enc, nil } @@ -79,12 +94,17 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { NetworkId *uint64 SyncMode *downloader.SyncMode NoPruning *bool - LightServ *int `toml:",omitempty"` - LightPeers *int `toml:",omitempty"` - SkipBcVersionCheck *bool `toml:"-"` - DatabaseHandles *int `toml:"-"` + LightServ *int `toml:",omitempty"` + LightBandwidthIn *int `toml:",omitempty"` + LightBandwidthOut *int `toml:",omitempty"` + LightPeers *int `toml:",omitempty"` + OnlyAnnounce *bool + ULC *ULCConfig `toml:",omitempty"` + SkipBcVersionCheck *bool `toml:"-"` + DatabaseHandles *int `toml:"-"` DatabaseCache *int - TrieCache *int + TrieCleanCache *int + TrieDirtyCache *int TrieTimeout *time.Duration Etherbase *common.Address `toml:",omitempty"` MinerNotify []string `toml:",omitempty"` @@ -99,6 +119,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { GPO *gasprice.Config EnablePreimageRecording *bool DocRoot *string `toml:"-"` + EWASMInterpreter *string + EVMInterpreter *string } var dec Config if err := unmarshal(&dec); err != nil { @@ -119,9 +141,21 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.LightServ != nil { c.LightServ = *dec.LightServ } + if dec.LightBandwidthIn != nil { + c.LightBandwidthIn = *dec.LightBandwidthIn + } + if dec.LightBandwidthOut != nil { + c.LightBandwidthOut = *dec.LightBandwidthOut + } if dec.LightPeers != nil { c.LightPeers = *dec.LightPeers } + if dec.OnlyAnnounce != nil { + c.OnlyAnnounce = *dec.OnlyAnnounce + } + if dec.ULC != nil { + c.ULC = dec.ULC + } if dec.SkipBcVersionCheck != nil { c.SkipBcVersionCheck = *dec.SkipBcVersionCheck } @@ -131,8 +165,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DatabaseCache != nil { c.DatabaseCache = *dec.DatabaseCache } - if dec.TrieCache != nil { - c.TrieCache = *dec.TrieCache + if dec.TrieCleanCache != nil { + c.TrieCleanCache = *dec.TrieCleanCache + } + if dec.TrieDirtyCache != nil { + c.TrieDirtyCache = *dec.TrieDirtyCache } if dec.TrieTimeout != nil { c.TrieTimeout = *dec.TrieTimeout @@ -176,5 +213,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DocRoot != nil { c.DocRoot = *dec.DocRoot } + if dec.EWASMInterpreter != nil { + c.EWASMInterpreter = *dec.EWASMInterpreter + } + if dec.EVMInterpreter != nil { + c.EVMInterpreter = *dec.EVMInterpreter + } return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/handler.go b/vendor/github.com/ethereum/go-ethereum/eth/handler.go index bd227a84..b42612a5 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/handler.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/handler.go @@ -88,6 +88,8 @@ type ProtocolManager struct { txsSub event.Subscription minedBlockSub *event.TypeMuxSubscription + whitelist map[uint64]common.Hash + // channels for fetcher, syncer, txsyncLoop newPeerCh chan *peer txsyncCh chan *txsync @@ -101,7 +103,7 @@ type ProtocolManager struct { // NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // with the Ethereum network. -func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) { +func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, whitelist map[uint64]common.Hash) (*ProtocolManager, error) { // Create the protocol manager with the base fields manager := &ProtocolManager{ networkID: networkID, @@ -110,6 +112,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne blockchain: blockchain, chainconfig: config, peers: newPeerSet(), + whitelist: whitelist, newPeerCh: make(chan *peer), noMorePeers: make(chan struct{}), txsyncCh: make(chan *txsync), @@ -307,7 +310,13 @@ func (pm *ProtocolManager) handle(p *peer) error { } }() } - // main loop. handle incoming messages. + // If we have any explicit whitelist block hashes, request them + for number := range pm.whitelist { + if err := p.RequestHeadersByNumber(number, 1, 0, false); err != nil { + return err + } + } + // Handle incoming messages until the connection is torn down for { if err := pm.handleMsg(p); err != nil { p.Log().Debug("Ethereum message handling failed", "err", err) @@ -466,6 +475,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { p.Log().Debug("Verified to be on the same side of the DAO fork") return nil } + // Otherwise if it's a whitelisted block, validate against the set + if want, ok := pm.whitelist[headers[0].Number.Uint64()]; ok { + if hash := headers[0].Hash(); want != hash { + p.Log().Info("Whitelist mismatch, dropping peer", "number", headers[0].Number.Uint64(), "hash", hash, "want", want) + return errors.New("whitelist block mismatch") + } + p.Log().Debug("Whitelist block verified", "number", headers[0].Number.Uint64(), "hash", want) + } // Irrelevant of the fork checks, send the header to the fetcher just in case headers = pm.fetcher.FilterHeaders(p.id, headers, time.Now()) } @@ -658,7 +675,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { p.SetHead(trueHead, trueTD) // Schedule a sync if above ours. Note, this will not fire a sync for a gap of - // a singe block (as the true TD is below the propagated block), however this + // a single block (as the true TD is below the propagated block), however this // scenario should easily be covered by the fetcher. currentBlock := pm.blockchain.CurrentBlock() if trueTD.Cmp(pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())) > 0 { diff --git a/vendor/github.com/ethereum/go-ethereum/eth/handler_test.go b/vendor/github.com/ethereum/go-ethereum/eth/handler_test.go index 7811cd48..7028d8d0 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/handler_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/handler_test.go @@ -27,12 +27,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -344,11 +344,15 @@ func testGetNodeData(t *testing.T, protocol int) { // Fetch for now the entire chain db hashes := []common.Hash{} - for _, key := range db.Keys() { - if len(key) == len(common.Hash{}) { + + it := db.NewIterator() + for it.Next() { + if key := it.Key(); len(key) == common.HashLength { hashes = append(hashes, common.BytesToHash(key)) } } + it.Release() + p2p.Send(peer.app, 0x0d, hashes) msg, err := peer.app.ReadMsg() if err != nil { @@ -367,7 +371,7 @@ func testGetNodeData(t *testing.T, protocol int) { t.Errorf("data hash mismatch: have %x, want %x", hash, want) } } - statedb := ethdb.NewMemDatabase() + statedb := rawdb.NewMemoryDatabase() for i := 0; i < len(data); i++ { statedb.Put(hashes[i].Bytes(), data[i]) } @@ -469,7 +473,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool var ( evmux = new(event.TypeMux) pow = ethash.NewFaker() - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} gspec = &core.Genesis{Config: config} genesis = gspec.MustCommit(db) @@ -478,7 +482,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } - pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db) + pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil) if err != nil { t.Fatalf("failed to start test protocol manager: %v", err) } @@ -550,7 +554,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) { var ( evmux = new(event.TypeMux) pow = ethash.NewFaker() - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() config = ¶ms.ChainConfig{} gspec = &core.Genesis{Config: config} genesis = gspec.MustCommit(db) @@ -559,7 +563,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) { if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } - pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db) + pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil) if err != nil { t.Fatalf("failed to start test protocol manager: %v", err) } @@ -585,7 +589,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) { } }(peer) } - timeoutCh := time.NewTimer(time.Millisecond * 100).C + timeout := time.After(300 * time.Millisecond) var receivedCount int outer: for { @@ -597,7 +601,7 @@ outer: if receivedCount == totalPeers { break outer } - case <-timeoutCh: + case <-timeout: break outer } } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/helper_test.go b/vendor/github.com/ethereum/go-ethereum/eth/helper_test.go index 4e38a129..e91429b8 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/helper_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/helper_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -49,11 +50,11 @@ var ( // newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, and potential notification // channels for different events. -func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase, error) { +func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, ethdb.Database, error) { var ( evmux = new(event.TypeMux) engine = ethash.NewFaker() - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec = &core.Genesis{ Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}}, @@ -66,7 +67,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func panic(err) } - pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db) + pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, nil) if err != nil { return nil, nil, err } @@ -78,7 +79,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func // with the given number of blocks already known, and potential notification // channels for different events. In case of an error, the constructor force- // fails the test. -func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase) { +func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, ethdb.Database) { pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx) if err != nil { t.Fatalf("Failed to create protocol manager: %v", err) diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/assets.go b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/assets.go index 04dd6fe8..d0a0bf7c 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/assets.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/assets.go @@ -1,14 +1,14 @@ // Code generated by go-bindata. DO NOT EDIT. // sources: -// 4byte_tracer.js -// bigram_tracer.js -// call_tracer.js -// evmdis_tracer.js -// noop_tracer.js -// opcount_tracer.js -// prestate_tracer.js -// trigram_tracer.js -// unigram_tracer.js +// 4byte_tracer.js (2.933kB) +// bigram_tracer.js (1.712kB) +// call_tracer.js (8.643kB) +// evmdis_tracer.js (4.194kB) +// noop_tracer.js (1.271kB) +// opcount_tracer.js (1.372kB) +// prestate_tracer.js (4.234kB) +// trigram_tracer.js (1.788kB) +// unigram_tracer.js (1.51kB) package tracers @@ -28,7 +28,7 @@ import ( func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) + return nil, fmt.Errorf("read %q: %v", name, err) } var buf bytes.Buffer @@ -36,7 +36,7 @@ func bindataRead(data []byte, name string) ([]byte, error) { clErr := gz.Close() if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) + return nil, fmt.Errorf("read %q: %v", name, err) } if clErr != nil { return nil, err @@ -117,7 +117,7 @@ func bigram_tracerJs() (*asset, error) { return a, nil } -var _call_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x59\xdf\x6f\x1b\x37\xf2\x7f\x96\xfe\x8a\x49\x1e\x6a\x09\x51\x24\x27\xe9\xb7\x5f\xc0\xae\x7a\xd0\x39\x4a\x6a\xc0\x8d\x03\x5b\x69\x10\x04\x79\xa0\x76\x67\x25\xd6\x5c\x72\x4b\x72\x2d\xef\xa5\xfe\xdf\x0f\x33\xe4\xae\x56\x3f\xec\xe8\x7a\xb8\x43\xef\x45\xd0\x2e\x67\x86\xc3\x99\xcf\xfc\xe2\x8e\x46\x70\x66\x8a\xca\xca\xc5\xd2\xc3\xcb\xe3\x17\xff\x0f\xb3\x25\xc2\xc2\x3c\x47\xbf\x44\x8b\x65\x0e\x93\xd2\x2f\x8d\x75\xdd\xd1\x08\x66\x4b\xe9\x20\x93\x0a\x41\x3a\x28\x84\xf5\x60\x32\xf0\x5b\xf4\x4a\xce\xad\xb0\xd5\xb0\x3b\x1a\x05\x9e\xbd\xcb\x24\x21\xb3\x88\xe0\x4c\xe6\x57\xc2\xe2\x09\x54\xa6\x84\x44\x68\xb0\x98\x4a\xe7\xad\x9c\x97\x1e\x41\x7a\x10\x3a\x1d\x19\x0b\xb9\x49\x65\x56\x91\x48\xe9\xa1\xd4\x29\x5a\xde\xda\xa3\xcd\x5d\xad\xc7\xdb\x77\x1f\xe0\x02\x9d\x43\x0b\x6f\x51\xa3\x15\x0a\xde\x97\x73\x25\x13\xb8\x90\x09\x6a\x87\x20\x1c\x14\xf4\xc6\x2d\x31\x85\x39\x8b\x23\xc6\x37\xa4\xca\x75\x54\x05\xde\x98\x52\xa7\xc2\x4b\xa3\x07\x80\x92\x34\x87\x5b\xb4\x4e\x1a\x0d\xaf\xea\xad\xa2\xc0\x01\x18\x4b\x42\x7a\xc2\xd3\x01\x2c\x98\x82\xf8\xfa\x20\x74\x05\x4a\xf8\x35\xeb\x01\x06\x59\x9f\x3b\x05\xa9\x79\x9b\xa5\x29\x10\xfc\x52\x78\x3a\xf5\x4a\x2a\x05\x73\x84\xd2\x61\x56\xaa\x01\x49\x9b\x97\x1e\x3e\x9e\xcf\x7e\xbe\xfc\x30\x83\xc9\xbb\x4f\xf0\x71\x72\x75\x35\x79\x37\xfb\x74\x0a\x2b\xe9\x97\xa6\xf4\x80\xb7\x18\x44\xc9\xbc\x50\x12\x53\x58\x09\x6b\x85\xf6\x15\x98\x8c\x24\xfc\x32\xbd\x3a\xfb\x79\xf2\x6e\x36\xf9\xfb\xf9\xc5\xf9\xec\x13\x18\x0b\x6f\xce\x67\xef\xa6\xd7\xd7\xf0\xe6\xf2\x0a\x26\xf0\x7e\x72\x35\x3b\x3f\xfb\x70\x31\xb9\x82\xf7\x1f\xae\xde\x5f\x5e\x4f\x87\x70\x8d\xa4\x15\x12\xff\xb7\x6d\x9e\xb1\xf7\x2c\x42\x8a\x5e\x48\xe5\x6a\x4b\x7c\x32\x25\xb8\xa5\x29\x55\x0a\x4b\x71\x8b\x60\x31\x41\x79\x8b\x29\x08\x48\x4c\x51\x1d\xec\x54\x92\x25\x94\xd1\x0b\x3e\xf3\x83\x80\x84\xf3\x0c\xb4\xf1\x03\x70\x88\xf0\xe3\xd2\xfb\xe2\x64\x34\x5a\xad\x56\xc3\x85\x2e\x87\xc6\x2e\x46\x2a\x88\x73\xa3\x9f\x86\x5d\x92\x99\x08\xa5\x66\x56\x24\x68\xc9\x39\x02\xb2\x92\xcc\xaf\xcc\x4a\x83\xb7\x42\x3b\x91\x90\xab\xe9\x7f\xc2\x60\x14\x1e\xf0\x8e\x9e\xbc\x23\xd0\x82\xc5\xc2\x58\xfa\xaf\x54\x8d\x33\xa9\x3d\x5a\x2d\x14\xcb\x76\x90\x8b\x14\x61\x5e\x81\x68\x0b\x1c\xb4\x0f\x43\x30\x0a\xee\x06\xa9\x33\x63\x73\x86\xe5\xb0\xfb\xb5\xdb\x89\x1a\x3a\x2f\x92\x1b\x52\x90\xe4\x27\xa5\xb5\xa8\x3d\x99\xb2\xb4\x4e\xde\x22\x93\x40\xa0\x89\xf6\x9c\xfe\xfa\x0b\xe0\x1d\x26\x65\x90\xd4\x69\x84\x9c\xc0\xe7\xaf\xf7\x5f\x06\x5d\x16\x9d\xa2\x4b\x50\xa7\x98\xf2\xf9\x6e\x1c\xac\x96\x6c\x51\x58\xe1\xd1\x2d\xc2\x6f\xa5\xf3\x2d\x9a\xcc\x9a\x1c\x84\x06\x53\x12\xe2\xdb\xd6\x91\xda\x1b\x16\x28\xe8\xbf\x46\xcb\x1a\x0d\xbb\x9d\x86\xf9\x04\x32\xa1\x1c\xc6\x7d\x9d\xc7\x82\x4e\x23\xf5\xad\xb9\x21\xc9\xc6\x12\x84\x6d\x05\xa6\x48\x4c\x1a\x83\x81\xce\xd1\x1c\x03\xdd\xb0\xdb\x21\xbe\x13\xc8\x4a\xcd\xdb\xf6\x94\x59\x0c\x20\x9d\xf7\xe1\x6b\xb7\x43\x62\xcf\x44\xe1\x4b\x8b\x6c\x4f\xb4\xd6\x58\x07\x32\xcf\x31\x95\xc2\xa3\xaa\xba\x9d\xce\xad\xb0\x61\x01\xc6\xa0\xcc\x62\xb8\x40\x3f\xa5\xc7\x5e\xff\xb4\xdb\xe9\xc8\x0c\x7a\x61\xf5\xc9\x78\xcc\xd9\x27\x93\x1a\xd3\x20\xbe\xe3\x97\xd2\x0d\x33\x51\x2a\xdf\xec\x4b\x4c\x1d\x8b\xbe\xb4\x9a\xfe\xde\x07\x2d\x3e\x22\x18\xad\x2a\x48\x28\xcb\x88\x39\x85\xa7\xab\x9c\xc7\x3c\x1e\xce\x0d\x20\x13\x8e\x4c\x28\x33\x58\x21\x14\x16\x9f\x27\x4b\x24\xdf\xe9\x04\xa3\x96\xae\x72\xec\xd4\x31\xd0\x6e\x43\x53\x0c\xbd\x79\x57\xe6\x73\xb4\xbd\x3e\x7c\x07\xc7\x77\xd9\x71\x1f\xc6\x63\xfe\x53\xeb\x1e\x79\xa2\xbe\x24\xc5\x14\xf1\xa0\xcc\x7f\xed\xad\xd4\x8b\x70\xd6\xa8\xeb\x79\x06\x02\x34\xae\x20\x31\x9a\x41\x4d\x5e\x99\xa3\xd4\x0b\x48\x2c\x0a\x8f\xe9\x00\x44\x9a\x82\x37\x01\x79\x0d\xce\x36\xb7\x84\xef\xbe\xe3\xbd\xc6\x70\x74\x76\x35\x9d\xcc\xa6\x47\x2d\x25\xa4\xbe\xcc\xb2\xa8\x07\xf3\x0e\x0b\xc4\x9b\xde\x8b\xfe\xf0\x56\xa8\x12\x2f\xb3\xa0\x51\xa4\x9d\xea\x14\xc6\x91\xe7\xd9\x36\xcf\xcb\x0d\x1e\x62\x1a\x8d\x60\xe2\x1c\xe6\x73\x85\xbb\xb1\x17\x83\x93\xe3\xd4\x79\x4a\x4e\x04\xb4\xc4\xe4\x85\x42\x02\x50\xbd\x6b\xb4\x34\x6b\xdc\xf1\x55\x81\x27\x00\x00\xa6\x18\xf0\x0b\x82\x3d\xbf\xf0\xe6\x67\xbc\x63\x77\xd4\xd6\x22\x00\x4d\xd2\xd4\xa2\x73\xbd\x7e\x3f\x90\x4b\x5d\x94\xfe\x64\x83\x3c\xc7\xdc\xd8\x6a\xe8\x28\xf7\xf4\xf8\x68\x83\x70\xd2\x9a\x67\x21\xdc\xb9\x26\x9e\x08\xca\xb7\xc2\xf5\xd6\x4b\x67\xc6\xf9\x93\x7a\x89\x1e\xea\x35\xb6\x05\xb1\x1d\x1d\xdf\x1d\xed\x5a\xeb\xb8\xbf\x76\xfa\x8b\x1f\xfa\xc4\x72\x7f\xda\x40\xb9\xc9\x08\xc3\xa2\x74\xcb\x1e\x23\x67\xbd\xba\x8e\xfa\x31\x78\x5b\xe2\x5e\xa4\x33\x7a\x76\x91\xe3\x50\x65\x94\x36\xbc\x2d\x13\x46\xd0\x42\x70\x52\xe1\xa0\x16\x94\x64\x5d\x39\x67\x9b\x7b\x63\x1e\x04\xd2\xf5\xf4\xe2\xcd\xeb\xe9\xf5\xec\xea\xc3\xd9\xac\x0d\x27\x85\x99\x27\xa5\x36\xcf\xa0\x50\x2f\xfc\x92\xf5\x27\x71\x9b\xab\x9f\x89\xe7\xf9\x8b\x2f\xe1\x0d\x8c\xf7\x44\x77\xe7\x71\x0e\xf8\xfc\x85\x65\xdf\xef\x9a\x6f\x93\x34\x18\xf3\x6b\x00\x91\x29\xee\xdb\x39\x62\x4f\xd8\xe5\xe8\x97\x26\xe5\x3c\x98\x88\x90\x4a\x6b\x2b\xa6\x46\xe3\xc1\xc1\xd7\xab\xa3\x6f\x72\x71\x71\x04\x7f\xfc\x01\xad\xe7\xb3\xcb\xd7\xd3\xf6\xbb\xd7\xd3\x8b\xe9\xdb\xc9\x6c\xba\x4d\x7b\x3d\x9b\xcc\xce\xcf\xf8\x6d\x3f\x5a\x65\x34\x82\xeb\x1b\x59\x70\x42\xe5\x34\x65\xf2\x82\x3b\xc3\x46\x5f\x37\x00\xbf\x34\xd4\x73\xd9\x58\x2f\x32\xa1\x93\x3a\x8f\xbb\xda\x69\xde\x90\xcb\x4c\x1d\x2b\xbb\xa9\xa0\x0d\xd4\x7e\xe3\x46\xe9\xde\x5b\x8c\x9b\xa6\x3d\x6f\x6a\xbd\xd6\x06\x0d\x1e\xe1\x5c\xc7\x49\xa6\x77\xf8\x21\xe1\x6f\x70\x0c\x27\xf0\x22\x66\x92\x47\x52\xd5\x4b\x78\x46\xe2\xff\x44\xc2\x7a\xb5\x87\xf3\xaf\x99\xb6\xbc\x61\xe2\x9a\xdc\x9b\xff\x7e\x3a\x33\xa5\xbf\xcc\xb2\x13\xd8\x36\xe2\xf7\x3b\x46\x6c\xe8\x2f\x50\xef\xd2\xff\xdf\x0e\xfd\x3a\xf5\x11\xaa\x4c\x01\x4f\x76\x20\x12\x12\xcf\x93\xad\x38\x88\xc6\xe5\x6e\x86\xa5\xc1\xf8\x81\x64\xfb\x72\x13\xc3\x0f\x65\x8b\x7f\x2b\xd9\xee\xed\xca\xa8\xf7\xda\xec\xbb\x06\x60\xd1\x5b\x89\xb7\x34\x59\x1d\x39\x16\x49\xfd\xa9\x59\x09\x9d\xe0\x10\x3e\x62\x90\xa8\x11\x39\xb9\xc4\x7e\x96\xda\x11\x6e\xf1\xa8\x27\x8d\x93\x09\x43\x4c\x70\xdb\x69\x11\x72\x51\xd1\x64\x92\x95\xfa\xa6\x82\x85\x70\x90\x56\x5a\xe4\x32\x71\x41\x1e\xf7\xb2\x16\x17\xc2\xb2\x58\x8b\xbf\x97\xe8\x68\xcc\x21\x20\x8b\xc4\x97\x42\xa9\x0a\x16\x92\x66\x15\xe2\xee\xbd\x7c\x75\x7c\x0c\xce\xcb\x02\x75\x3a\x80\x1f\x5e\x8d\x7e\xf8\x1e\x6c\xa9\xb0\x3f\xec\xb6\xd2\x78\x73\xd4\xe8\x0d\x5a\x88\xe8\x79\x8d\x85\x5f\xf6\xfa\xf0\xd3\x03\xf5\xe0\x81\xe4\xbe\x97\x16\x9e\xc3\x8b\x2f\x43\xd2\x6b\xbc\x81\xdb\xe0\x49\x40\xe5\x30\x4a\xa3\xf9\xee\xf2\xf5\x65\xef\x46\x58\xa1\xc4\x1c\xfb\x27\x3c\xef\xb1\xad\x56\x22\x36\xfc\xe4\x14\x28\x94\x90\x1a\x44\x92\x98\x52\x7b\x32\x7c\xdd\xbb\xab\x8a\xf2\xfb\x91\xaf\xe5\xf1\x68\x24\x92\x04\x9d\xab\xd3\x3d\x7b\x8d\xd4\x11\x39\x71\x83\xd4\x4e\xa6\xd8\xf2\x0a\x65\x07\xc3\xa9\x39\x52\xd0\xe4\x58\x0b\xcc\x8d\xa3\x4d\xe6\x08\x2b\x4b\x73\x86\x93\x3a\xe1\x41\x3b\x45\xb2\xb6\x03\xa3\x41\x80\x32\x3c\xdd\x73\x8c\x83\xb0\x0b\x37\x0c\xf9\x9e\xb6\xa5\x9c\xa3\xcd\x6a\xb8\x09\xe4\x36\x54\xb9\xa3\xdf\x6a\x07\x34\xe0\x9d\x74\x9e\x1b\x48\xd2\x52\x3a\x08\x48\x96\x7a\x31\x80\xc2\x14\x9c\xa7\x0f\xec\x25\xaf\xa6\xbf\x4e\xaf\x9a\xe2\x7f\xb8\x13\xeb\x16\xff\x69\x33\x01\x81\xa5\xf1\xc2\x63\xfa\x74\x4f\xcf\xbe\x07\x50\xe3\x07\x00\x45\xf2\xd7\xb5\xf1\x7d\xeb\x38\x4a\x38\xbf\x76\xcc\x02\xc3\xf8\xd2\x56\xc0\x95\xca\xbb\xad\xdc\xbd\x9d\x1c\x4c\x51\x57\x08\x52\x8a\xd3\x0e\x25\xf6\x3d\x9d\x75\x34\xb8\x6f\x03\x4f\x40\xa0\x69\x25\x00\x5e\xaf\x3b\x34\x11\x72\x3e\x6b\x68\x4a\x4f\x4e\xa7\x2a\xbd\x4e\x71\x0b\xe1\x3e\x38\xf6\x6d\x4c\x72\x73\xb9\x38\xd7\xbe\x57\x2f\x9e\x6b\x78\x0e\xf5\x03\xa5\x6e\x78\xbe\x11\x2b\x7b\x72\x60\x27\x45\x85\x1e\x61\x2d\xe2\x14\xb6\x5e\x91\xa0\x70\x68\x36\x8d\x45\xbf\x5b\x82\x8f\xa3\x34\x32\xcb\x13\x8b\x7e\x88\xbf\x97\x42\xb9\xde\x71\xd3\x12\x84\x13\x78\xc3\x45\x6c\xdc\x94\xb1\xba\xce\x11\xcf\x46\x93\x11\x05\x06\xb6\x68\x8d\x9a\x2d\x9d\x87\xda\x94\xe2\xa3\x12\xa2\x88\x98\x1c\x1a\x8f\x45\xf8\xed\xeb\x32\x3b\x6d\x02\x78\xda\x94\xfd\x4c\x48\x55\x5a\x7c\x7a\x0a\x7b\x92\x8b\x2b\x6d\x26\x12\xf6\xa5\x43\xe0\x11\xd4\x81\x33\x39\x2e\xcd\x2a\x28\xb0\x2f\x45\xed\x82\xa3\xc1\xc1\x56\x91\xe0\xbb\x14\xe1\xa0\x74\x62\x81\x2d\x70\x34\x06\xaf\x1d\xb5\x77\x2e\xfe\xd3\xd0\x79\xd6\x3c\x7e\x03\x45\x61\x97\x6f\x42\xe3\x31\x6c\xec\xf5\xf2\x4e\x2f\x53\x13\x71\x47\xd3\x7a\xa8\x55\x0d\x0d\x47\x83\x9c\x7f\xc5\xef\xff\x19\xc7\x07\xcf\xc7\xdf\x43\x03\x6d\x9b\x36\x9c\x71\x93\x38\x9c\x74\xdd\xc4\x7c\x1b\x05\xcd\xea\x43\x00\x78\xa8\x3f\x22\xa8\xea\xdf\x30\xf1\x6b\xb8\x72\x4b\x43\x4f\x85\xc5\x5b\x69\x4a\xaa\x56\xf8\xbf\x34\xff\x35\xfd\xdd\x7d\xb7\x73\x1f\xef\xbc\xd8\x7d\xed\x4b\xaf\xd5\x32\xde\xd9\x86\xd6\xa8\x55\x2b\x0c\x17\xd2\x78\x15\x96\x85\xdb\xd4\x0e\xf3\x3f\x72\xf9\x15\xe3\xdd\x9b\x82\x6a\x7f\x2c\x45\xca\xa2\x48\xab\xa6\xfa\x0d\x42\xd7\x01\x4b\xa1\xd3\x38\x79\x88\x34\x95\x24\x8f\xb1\x48\x1a\x8a\x85\x90\xba\xbb\xd7\x8c\xdf\x2c\xb9\xfb\x90\xb1\xd3\xc8\xb6\xab\x66\x9c\x18\x69\xbc\x63\x8d\xbb\x07\x54\xc7\xad\x58\xda\xbe\xc7\x8b\x57\x81\x46\xbb\x32\xe7\xb6\x17\xc4\xad\x90\x4a\xd0\xa8\xc5\xed\x94\x4e\x21\x51\x28\x74\xb8\xbd\xc7\xcc\x9b\x5b\xb4\xae\x7b\x00\xc8\xff\x0c\xc6\xb7\x92\x63\xfd\x18\xcd\x71\x78\xcc\x1e\x1a\xb1\xe1\xf8\x6f\x94\xf0\x3e\xc2\xab\x65\xde\x10\x59\xd2\xf3\x87\x1d\xd4\xbe\x7b\x58\x48\x71\x83\x44\x34\x3f\xc1\x71\xab\x09\xff\xab\x04\xd9\x2e\xc4\x2e\x9a\x66\x2c\x1e\xde\x1b\x33\x00\x85\x82\x47\xa2\xfa\xb3\x4b\xdd\x7c\x3e\x36\xa1\xd5\xd1\x1b\xda\xb7\x9d\xf0\xe5\x4b\xac\x25\xd6\xd7\x1d\xa1\x8f\x9f\x23\x6a\x90\x1e\xad\xa0\xe1\x87\xd0\x15\xbf\x14\x90\x96\x8e\xc5\xb1\x5f\x24\x05\x5d\x14\x1c\xaf\xed\xa9\x3e\x4b\xbd\x18\x76\x3b\xe1\x7d\x2b\xde\x13\x7f\xb7\x8e\xf7\x50\x0c\x99\x33\x5e\x00\x34\xf3\x7f\xe2\xef\xb8\x67\xe4\x19\x79\xeb\x12\x80\xd6\xe8\x55\x18\xa0\xb7\x46\x7e\x66\x8c\x63\xff\xf6\xcd\x22\xad\xf1\xbb\x0d\x80\x33\xe9\x42\xb8\x20\x66\x2b\x24\xfc\xdd\x6e\x44\xd4\x0c\x14\x0c\x27\xfb\x19\x68\x69\x0f\xd3\xd6\x35\x04\x11\xf3\xab\xb0\x1a\x0a\xfb\x49\x7b\x35\xbc\x8a\x07\x95\x79\xcb\x36\x32\x67\xdb\xdc\x9f\xee\x4f\x72\xc7\x35\x1e\xf7\x27\x33\xb2\x79\x03\xd8\x07\x58\xdb\x83\xc5\x2e\xc9\x63\xa9\x92\xa5\xd7\x99\xed\x01\x56\x96\xde\x6a\x3d\xfc\xdd\xe1\x22\x1b\xe2\xb6\x8a\x1b\x34\xfb\x84\xc4\x3c\x13\xe9\x82\x65\x6b\x01\x01\xd5\x41\x57\x46\xb4\xfc\x07\x46\x89\xed\xf8\xa9\x97\xc0\x62\xf8\xb0\xc0\x0d\x29\x85\x8f\x99\x73\xf1\x2f\x1d\xcd\x8c\xeb\xb8\x48\xd1\x49\x8b\x29\x64\x12\x55\x0a\x26\x45\xcb\x13\xe9\x6f\xce\xe8\xf0\x09\x09\xad\x24\x89\xe1\x53\x59\xf8\x6a\xcd\x1f\xf0\xb4\x4c\xd0\x57\x90\xa1\xe0\x6f\x41\xde\x40\x21\x9c\x83\x1c\x05\xcd\xa0\x59\xa9\x54\x05\xc6\xa6\x48\xc2\x9b\xa1\x8c\x42\xd2\x40\xe9\xd0\x3a\x58\x2d\x4d\x2c\x93\xdc\xa5\x15\xd4\x74\x4a\x3f\x88\xf7\x2e\xd2\x15\x4a\x54\x20\x3d\x95\xe4\x78\xa8\x76\x94\x36\x1f\x60\xf8\x2b\x8e\xa1\xaa\xbb\x1b\xa2\xf5\x5c\xb7\x19\xa3\xfc\x9a\x9e\x36\xa3\x33\xce\x35\x9b\x71\xb9\xbe\x91\xda\x0c\xc2\xba\x6c\x6c\x46\x5a\xbb\x08\x6d\x86\x13\xaf\xf0\xd3\x66\x20\xb5\xfa\x65\x5e\x60\x70\x34\x0c\xfc\xb4\x15\x5a\xac\x65\x8c\xad\xf0\xb9\xb1\x21\xe7\xa7\x41\x04\x0c\x79\xb1\x47\xc6\xb9\xc1\x8a\x32\x71\xb0\x51\xab\xac\x84\x17\x9f\x6f\xb0\xfa\xb2\xbf\x8a\x44\x38\xb6\xe8\x9a\xb2\x51\x43\x3a\xac\x3d\x12\xc8\x8d\x16\x72\x7c\x7c\x0a\xf2\xc7\x36\x43\x5d\xf9\x40\x3e\x7b\x56\xef\xd9\x5e\xff\x2c\xbf\xd4\xd1\xd9\x20\x7e\x6b\xbd\xbf\xa1\x51\x8c\x91\x40\x43\x41\xd1\xbd\xef\xfe\x33\x00\x00\xff\xff\xb5\x25\x8b\x4d\x94\x21\x00\x00") +var _call_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x59\x5f\x6f\x1b\xb7\xb2\x7f\x96\x3e\xc5\x24\x0f\xb5\x84\x28\x92\x93\xf4\xf6\x02\x76\xd5\x0b\x5d\x47\x49\x0d\xb8\x71\x60\x2b\x0d\x82\x20\x0f\xd4\xee\xac\xc4\x9a\x4b\x6e\x49\xae\xe4\x3d\xa9\xbf\xfb\xc1\x0c\xb9\xab\xd5\x1f\x3b\x6e\x0f\xce\x41\xcf\x8b\xa0\x5d\xce\x0c\x87\x33\xbf\xf9\xc7\x1d\x8d\xe0\xcc\x14\x95\x95\x8b\xa5\x87\x97\xc7\x2f\xfe\x17\x66\x4b\x84\x85\x79\x8e\x7e\x89\x16\xcb\x1c\x26\xa5\x5f\x1a\xeb\xba\xa3\x11\xcc\x96\xd2\x41\x26\x15\x82\x74\x50\x08\xeb\xc1\x64\xe0\x77\xe8\x95\x9c\x5b\x61\xab\x61\x77\x34\x0a\x3c\x07\x97\x49\x42\x66\x11\xc1\x99\xcc\xaf\x85\xc5\x13\xa8\x4c\x09\x89\xd0\x60\x31\x95\xce\x5b\x39\x2f\x3d\x82\xf4\x20\x74\x3a\x32\x16\x72\x93\xca\xac\x22\x91\xd2\x43\xa9\x53\xb4\xbc\xb5\x47\x9b\xbb\x5a\x8f\xb7\xef\x3e\xc0\x05\x3a\x87\x16\xde\xa2\x46\x2b\x14\xbc\x2f\xe7\x4a\x26\x70\x21\x13\xd4\x0e\x41\x38\x28\xe8\x8d\x5b\x62\x0a\x73\x16\x47\x8c\x6f\x48\x95\xeb\xa8\x0a\xbc\x31\xa5\x4e\x85\x97\x46\x0f\x00\x25\x69\x0e\x2b\xb4\x4e\x1a\x0d\xaf\xea\xad\xa2\xc0\x01\x18\x4b\x42\x7a\xc2\xd3\x01\x2c\x98\x82\xf8\xfa\x20\x74\x05\x4a\xf8\x0d\xeb\x23\x0c\xb2\x39\x77\x0a\x52\xf3\x36\x4b\x53\x20\xf8\xa5\xf0\x74\xea\xb5\x54\x0a\xe6\x08\xa5\xc3\xac\x54\x03\x92\x36\x2f\x3d\x7c\x3c\x9f\xfd\x7c\xf9\x61\x06\x93\x77\x9f\xe0\xe3\xe4\xea\x6a\xf2\x6e\xf6\xe9\x14\xd6\xd2\x2f\x4d\xe9\x01\x57\x18\x44\xc9\xbc\x50\x12\x53\x58\x0b\x6b\x85\xf6\x15\x98\x8c\x24\xfc\x32\xbd\x3a\xfb\x79\xf2\x6e\x36\xf9\xff\xf3\x8b\xf3\xd9\x27\x30\x16\xde\x9c\xcf\xde\x4d\xaf\xaf\xe1\xcd\xe5\x15\x4c\xe0\xfd\xe4\x6a\x76\x7e\xf6\xe1\x62\x72\x05\xef\x3f\x5c\xbd\xbf\xbc\x9e\x0e\xe1\x1a\x49\x2b\x24\xfe\x6f\xdb\x3c\x63\xef\x59\x84\x14\xbd\x90\xca\xd5\x96\xf8\x64\x4a\x70\x4b\x53\xaa\x14\x96\x62\x85\x60\x31\x41\xb9\xc2\x14\x04\x24\xa6\xa8\x1e\xed\x54\x92\x25\x94\xd1\x0b\x3e\xf3\xbd\x80\x84\xf3\x0c\xb4\xf1\x03\x70\x88\xf0\xe3\xd2\xfb\xe2\x64\x34\x5a\xaf\xd7\xc3\x85\x2e\x87\xc6\x2e\x46\x2a\x88\x73\xa3\x9f\x86\x5d\x92\x99\x08\xa5\x66\x56\x24\x68\xc9\x39\x02\xb2\x92\xcc\xaf\xcc\x5a\x83\xb7\x42\x3b\x91\x90\xab\xe9\x7f\xc2\x60\x14\x1e\xf0\x96\x9e\xbc\x23\xd0\x82\xc5\xc2\x58\xfa\xaf\x54\x8d\x33\xa9\x3d\x5a\x2d\x14\xcb\x76\x90\x8b\x14\x61\x5e\x81\x68\x0b\x1c\xb4\x0f\x43\x30\x0a\xee\x06\xa9\x33\x63\x73\x86\xe5\xb0\xfb\xb5\xdb\x89\x1a\x3a\x2f\x92\x1b\x52\x90\xe4\x27\xa5\xb5\xa8\x3d\x99\xb2\xb4\x4e\xae\x90\x49\x20\xd0\x44\x7b\x4e\x7f\xfd\x05\xf0\x16\x93\x32\x48\xea\x34\x42\x4e\xe0\xf3\xd7\xbb\x2f\x83\x2e\x8b\x4e\xd1\x25\xa8\x53\x4c\xf9\x7c\x37\x0e\xd6\x4b\xb6\x28\xac\xf1\x68\x85\xf0\x5b\xe9\x7c\x8b\x26\xb3\x26\x07\xa1\xc1\x94\x84\xf8\xb6\x75\xa4\xf6\x86\x05\x0a\xfa\xaf\xd1\xb2\x46\xc3\x6e\xa7\x61\x3e\x81\x4c\x28\x87\x71\x5f\xe7\xb1\xa0\xd3\x48\xbd\x32\x37\x24\xd9\x58\x82\xb0\xad\xc0\x14\x89\x49\x63\x30\xd0\x39\x9a\x63\xa0\x1b\x76\x3b\xc4\x77\x02\x59\xa9\x79\xdb\x9e\x32\x8b\x01\xa4\xf3\x3e\x7c\xed\x76\x48\xec\x99\x28\x7c\x69\x91\xed\x89\xd6\x1a\xeb\x40\xe6\x39\xa6\x52\x78\x54\x55\xb7\xd3\x59\x09\x1b\x16\x60\x0c\xca\x2c\x86\x0b\xf4\x53\x7a\xec\xf5\x4f\xbb\x9d\x8e\xcc\xa0\x17\x56\x9f\x8c\xc7\x9c\x7d\x32\xa9\x31\x0d\xe2\x3b\x7e\x29\xdd\x30\x13\xa5\xf2\xcd\xbe\xc4\xd4\xb1\xe8\x4b\xab\xe9\xef\x5d\xd0\xe2\x23\x82\xd1\xaa\x82\x84\xb2\x8c\x98\x53\x78\xba\xca\x79\xcc\xe3\xe1\xdc\x00\x32\xe1\xc8\x84\x32\x83\x35\x42\x61\xf1\x79\xb2\x44\xf2\x9d\x4e\x30\x6a\xe9\x2a\xc7\x4e\x1d\x03\xed\x36\x34\xc5\xd0\x9b\x77\x65\x3e\x47\xdb\xeb\xc3\x77\x70\x7c\x9b\x1d\xf7\x61\x3c\xe6\x3f\xb5\xee\x91\x27\xea\x4b\x52\x4c\x11\x0f\xca\xfc\xd7\xde\x4a\xbd\x08\x67\x8d\xba\x9e\x67\x20\x40\xe3\x1a\x12\xa3\x19\xd4\xe4\x95\x39\x4a\xbd\x80\xc4\xa2\xf0\x98\x0e\x40\xa4\x29\x78\x13\x90\xd7\xe0\x6c\x7b\x4b\xf8\xee\x3b\xe8\xd1\x66\x63\x38\x3a\xbb\x9a\x4e\x66\xd3\x23\xf8\xe3\x0f\x08\x6f\x9e\x86\x37\x2f\x9f\xf6\x5b\x9a\x49\x7d\x99\x65\x51\x39\x16\x38\x2c\x10\x6f\x7a\x2f\xfa\xc3\x95\x50\x25\x5e\x66\x41\xcd\x48\x3b\xd5\x29\x8c\x23\xcf\xb3\x5d\x9e\x97\x5b\x3c\xc4\x34\x1a\xc1\xc4\x39\xcc\xe7\x0a\xf7\x03\x32\x46\x2c\x07\xaf\xf3\x94\xb1\x08\x7d\x89\xc9\x0b\x85\x84\xaa\x7a\xd7\x68\x7e\xd6\xb8\xe3\xab\x02\x4f\x00\x00\x4c\x31\xe0\x17\x14\x0b\xfc\xc2\x9b\x9f\xf1\x96\x7d\x54\x9b\x90\x50\x35\x49\x53\x8b\xce\xf5\xfa\xfd\x40\x2e\x75\x51\xfa\x93\x2d\xf2\x1c\x73\x63\xab\xa1\xa3\x84\xd4\xe3\xa3\x0d\xc2\x49\x6b\x9e\x85\x70\xe7\x9a\x78\x22\x52\xdf\x0a\xd7\xdb\x2c\x9d\x19\xe7\x4f\xea\x25\x7a\xa8\xd7\xd8\x16\xc4\x76\x74\x7c\x7b\xb4\x6f\xad\xe3\xfe\x06\x09\x2f\x7e\xe8\x13\xcb\xdd\x69\x83\xef\x26\x4d\x0c\x8b\xd2\x2d\x7b\x0c\xa7\xcd\xea\x26\x15\x8c\xc1\xdb\x12\x0f\xc2\x9f\x21\xb5\x0f\x27\x87\x2a\xa3\x5c\xe2\x6d\x99\x30\xac\x16\x82\x33\x0d\x47\xba\xa0\xcc\xeb\xca\x39\xdb\xdc\x1b\xb3\x8f\xae\x08\xae\xeb\xe9\xc5\x9b\xd7\xd3\xeb\xd9\xd5\x87\xb3\xd9\x51\x0b\x4e\x0a\x33\x4f\x4a\x6d\x9f\x41\xa1\x5e\xf8\x25\xeb\x4f\xe2\xb6\x57\x3f\x13\xcf\xf3\x17\x5f\xc2\x1b\x18\x1f\x08\xf9\xce\xc3\x1c\xf0\xf9\x0b\xcb\xbe\xdb\x37\xdf\x36\x69\x30\xe6\xd7\x00\x22\x53\xdc\xb5\x13\xc7\x81\x58\xcc\xd1\x2f\x4d\xca\xc9\x31\x11\x21\xbf\xd6\x56\x4c\x8d\xc6\x3f\x1f\x91\x93\x8b\x8b\x56\x3c\xf2\xf3\xd9\xe5\xeb\x76\x8c\x1e\xbd\x9e\x5e\x4c\xdf\x4e\x66\xd3\x5d\xda\xeb\xd9\x64\x76\x7e\xc6\x6f\xeb\xf0\x1d\x8d\xe0\xfa\x46\x16\x9c\x65\x39\x77\x99\xbc\xe0\x76\xb1\xd1\xd7\x0d\xc0\x2f\x0d\x35\x62\x36\x16\x91\x4c\xe8\xa4\x4e\xee\xae\x76\x9a\x37\xe4\x32\x53\xc7\xca\x7e\x2a\x68\x03\xb5\xdf\xb8\x51\xba\xf7\x16\xe3\xa6\x69\xcf\x9b\x5a\xaf\x8d\x41\x83\x47\x38\x01\x72\x92\xe9\x3d\xfe\x90\xf0\x7f\x70\x0c\x27\xf0\x22\x66\x92\x07\x52\xd5\x4b\x78\x46\xe2\xff\x42\xc2\x7a\x75\x80\xf3\xef\x99\xb6\xbc\x61\xe2\x9a\xdc\x9b\xff\x7c\x3a\x33\xa5\xbf\xcc\xb2\x13\xd8\x35\xe2\xf7\x7b\x46\x6c\xe8\x2f\x50\xef\xd3\xff\xcf\x1e\xfd\x26\xf5\x11\xaa\x4c\x01\x4f\xf6\x20\x12\x12\xcf\x93\x9d\x38\x88\xc6\xe5\x16\x87\xa5\xc1\xf8\x9e\x64\xfb\x72\x1b\xc3\xf7\x65\x8b\x7f\x29\xd9\x1e\x6c\xd5\xa8\x21\xdb\x6e\xc6\x06\x60\xd1\x5b\x89\x2b\x1a\xb7\x8e\x1c\x8b\xa4\xa6\xd5\xac\x85\x4e\x70\x08\x1f\x31\x48\xd4\x88\x9c\x5c\x62\x93\x4b\x3d\x0a\xf7\x7d\xd4\xa8\xc6\x71\x85\x21\x26\xb8\x17\xb5\x08\xb9\xa8\x68\x5c\xc9\x4a\x7d\x53\xc1\x42\x38\x48\x2b\x2d\x72\x99\xb8\x20\x8f\x1b\x5c\x8b\x0b\x61\x59\xac\xc5\xdf\x4b\x74\x34\xfb\x10\x90\x45\xe2\x4b\xa1\x54\x05\x0b\x49\x03\x0c\x71\xf7\x5e\xbe\x3a\x3e\x06\xe7\x65\x81\x3a\x1d\xc0\x0f\xaf\x46\x3f\x7c\x0f\xb6\x54\xd8\x1f\x76\x5b\x69\xbc\x39\x6a\xf4\x06\x2d\x44\xf4\xbc\xc6\xc2\x2f\x7b\x7d\xf8\xe9\x9e\x7a\x70\x4f\x72\x3f\x48\x0b\xcf\xe1\xc5\x97\x21\xe9\x35\xde\xc2\x6d\xf0\x24\xa0\x72\x18\xa5\xd1\xd0\x77\xf9\xfa\xb2\x77\x23\xac\x50\x62\x8e\xfd\x13\x1e\x02\xd9\x56\x6b\x11\xa7\x00\x72\x0a\x14\x4a\x48\x0d\x22\x49\x4c\xa9\x3d\x19\xbe\x6e\xe8\x55\x45\xf9\xfd\xc8\xd7\xf2\x78\x5e\x12\x49\x82\xce\xd5\xe9\x9e\xbd\x46\xea\x88\x9c\xb8\x41\x6a\x27\x53\x6c\x79\x85\xb2\x83\xe1\xd4\x1c\x29\x68\x9c\xac\x05\xe6\xc6\xd1\x26\x73\x84\xb5\xa5\xe1\xc3\x49\x9d\xf0\xf4\x9d\x22\x59\xdb\x81\xd1\x20\x40\x19\x1e\xf9\x39\xc6\x41\xd8\x85\x1b\x86\x7c\x4f\xdb\x52\xce\xd1\x66\x3d\xdc\x06\x72\x1b\xaa\xdc\xe6\xef\xb4\x03\x1a\xf0\x56\x3a\xcf\x5d\x25\x69\x29\x1d\x04\x24\x4b\xbd\x18\x40\x61\x0a\xce\xd3\xdf\x2a\x67\x31\x59\x5f\x4d\x7f\x9d\x5e\x35\xc5\xff\xf1\x4e\xac\xfb\xfe\xa7\xcd\x58\x04\x96\x66\x0e\x8f\xe9\xd3\x03\x8d\xfc\x01\x40\x8d\xef\x01\x14\xc9\xdf\xd4\xc6\xf7\xad\xe3\x28\xe1\xfc\xc6\x31\x0b\x0c\x33\x4d\x5b\x01\x57\x2a\xef\x76\x72\xf7\x6e\x72\x30\x45\x5d\x21\x48\x29\x4e\x3b\x94\xd8\x77\xbb\xed\xad\x85\x4d\xd3\xbd\xc1\xe7\x79\xcb\xc6\x6b\x6e\xb9\x02\x51\x2b\x35\xf0\x7a\xdd\xbb\x89\x50\x0d\x58\x77\x53\x7a\x82\x03\xd5\xef\x4d\xf2\x5b\x08\xf7\xc1\xb1\xd7\x63\xfa\x9b\xcb\xc5\xb9\xf6\xbd\x7a\xf1\x5c\xc3\x73\xa8\x1f\x28\xa9\xc3\xf3\xad\x28\x3a\x90\x1d\x3b\x29\x2a\xf4\x08\x1b\x11\xa7\xb0\xf3\x8a\x04\x05\x73\xb0\xd1\x2c\xfa\xfd\xe2\x7c\x1c\xa5\x91\xc1\x9e\x58\xf4\x43\xfc\xbd\x14\xca\xf5\x8e\x9b\x66\x21\x9c\xc0\x1b\x2e\x6f\xe3\xa6\xc0\xd5\x15\x90\x78\xb6\xda\x8f\x28\x30\xb0\x45\x6b\xd4\x6c\xe9\x3c\x54\xad\x14\x1f\x94\x10\x45\xc4\xb4\xd1\xf8\x32\x02\xf3\x50\xff\xd9\x69\x13\xc0\xd3\xa6\x21\xc8\x84\x54\xa5\xc5\xa7\xa7\x70\x20\xed\xb8\xd2\x66\x22\x61\x5f\x3a\x04\x9e\x58\x1d\x38\x93\xe3\xd2\xac\x83\x02\x87\x92\xd7\x3e\x38\x1a\x1c\xec\x94\x0f\xbe\x7a\x11\x0e\x4a\x27\x16\xd8\x02\x47\x63\xf0\xda\x51\x07\xc7\xe8\xbf\x0c\x9d\x67\xcd\xe3\x37\x50\x14\x76\xf9\x26\x34\x1e\xc2\xc6\x41\x2f\xef\x75\x39\x35\x11\xf7\x3a\xad\x87\x5a\xd5\xd0\x8a\x34\xc8\xf9\x33\x7e\xff\xf7\x38\x3e\x78\x3e\xfe\x3e\x36\xd0\x76\x69\xc3\x19\xb7\x89\xc3\x49\x37\xed\xcd\xb7\x51\xd0\xac\xde\x07\x80\xfb\x3a\x27\x82\xaa\xfe\x0d\x13\xbf\x81\x2b\x37\x3b\xf4\x54\x58\x5c\x49\x53\x52\x1d\xc3\xff\xa6\xc9\xb0\xe9\xfc\xee\xba\x9d\xbb\x78\x45\xc6\xee\x6b\xdf\x91\xad\x97\xf1\x8a\x37\x34\x4d\xad\x2a\x62\xb8\xc4\xc6\x9b\xb3\x2c\x5c\xbe\x76\x98\xff\x81\xbb\xb2\x18\xef\xde\x14\xd4\x15\xc4\x22\xa5\x2c\x8a\xb4\x6a\xea\xe2\x20\xf4\x23\xb0\x14\x3a\x8d\x33\x89\x48\x53\x49\xf2\x18\x8b\xa4\xa1\x58\x08\xa9\xbb\x07\xcd\xf8\xcd\x62\x7c\x08\x19\x7b\x2d\x6e\xbb\x9e\xc6\x59\x92\x06\x3f\xd6\xb8\xfb\x88\xba\xb9\x13\x4b\xbb\xd7\x7e\xf1\xe6\xd0\x68\x57\xe6\xdc\x10\x83\x58\x09\xa9\x04\x0d\x61\xdc\x68\xe9\x14\x12\x85\x42\x87\xcb\x7e\xcc\xbc\x59\xa1\x75\xdd\x47\x80\xfc\xaf\x60\x7c\x27\x39\xd6\x8f\xd1\x1c\x8f\x8f\xd9\xc7\x46\x6c\x38\xfe\x1b\x25\xbc\x8f\xf0\x6a\x99\x37\x44\x96\xf4\xfc\x1d\x08\xb5\xef\x3e\x2e\xa4\xb8\x75\x22\x9a\x9f\xe0\xb8\xd5\x9e\xff\x5d\x82\x6c\x1f\x62\x17\x4d\x9b\x16\x0f\xef\x8d\x19\x80\x42\xc1\xc3\x52\xfd\x95\xa6\x6e\x4b\x1f\x9a\xdd\xea\xe8\x0d\x8d\xdd\x5e\xf8\xf2\xf5\xd6\x12\xeb\x8b\x90\xd0\xe1\xcf\x11\x35\x48\x8f\x56\xd0\x58\x44\xe8\x8a\x1f\x16\x48\x4b\xc7\xe2\xd8\x2f\x92\x82\x2e\x0a\x8e\xb7\xfc\x54\x9f\xa5\x5e\x0c\xbb\x9d\xf0\xbe\x15\xef\x89\xbf\xdd\xc4\x7b\x28\x86\xcc\x19\xaf\x06\x9a\x9b\x81\xc4\xdf\x72\xd3\xc8\xd3\xf3\xce\xf5\x00\xad\xd1\xab\x30\x5a\xef\x5c\x06\x30\x63\xbc\x10\xd8\xbd\x73\xa4\x35\x7e\xb7\x05\x70\x26\x5d\x08\x17\xc4\xec\x84\x84\xbf\xdd\x8f\x88\x9a\x81\x82\xe1\xe4\x30\x03\x2d\x1d\x60\xda\xb9\xa0\x20\x62\x7e\x15\x56\x43\x61\x3f\x69\xaf\x86\x57\xf1\xa0\x32\x6f\xd9\x46\xe6\x6c\x9b\xbb\xd3\xc3\x49\xee\xb8\xc6\xe3\xe1\x64\x46\x36\x6f\x00\x7b\x0f\x6b\x7b\xe4\xd8\x27\x79\x28\x55\xb2\xf4\x3a\xb3\xdd\xc3\xca\xd2\x5b\xad\x87\xbf\x7d\xbc\xc8\x86\xb8\xad\xe2\x16\xcd\x21\x21\x31\xcf\x44\xba\x60\xd9\x5a\x40\x40\x75\xd0\x95\x11\x2d\xff\x81\x51\x62\x3b\x7e\xea\x25\xb0\x18\xbe\x43\x70\x43\x4a\xe1\x63\xe6\x5c\xfc\x4b\x47\xd3\xe4\x26\x2e\x52\x74\xd2\x62\x0a\x99\x44\x95\x82\x49\xd1\xf2\xac\xfa\x9b\x33\x3a\x7c\x71\x42\x2b\x49\x62\xf8\xb2\x16\x3e\x72\xf3\xf7\x3e\x2d\x13\xf4\x15\x64\x28\xf8\xd3\x91\x37\x50\x08\xe7\x20\x47\x41\xd3\x69\x56\x2a\x55\x81\xb1\x29\x92\xf0\x66\x5c\xa3\x90\x34\x50\x3a\xb4\x0e\xd6\x4b\x13\xcb\x24\x77\x69\x05\x35\x9d\xd2\x0f\xe2\x8d\x8c\x74\x85\x12\x15\x48\x4f\x25\x39\x1e\xaa\x1d\xa5\xcd\xf7\x1a\xfe\xe8\x63\xa8\xea\xee\x87\x68\x3d\xd8\x6d\xc7\x28\xbf\xa6\xa7\xed\xe8\x8c\x73\xcd\x76\x5c\x6e\xee\xaa\xb6\x83\xb0\x2e\x1b\xdb\x91\xd6\x2e\x42\xdb\xe1\xc4\x2b\xfc\xb4\x1d\x48\xad\x7e\x99\x17\x18\x1c\x0d\x03\x3f\xed\x84\x16\x6b\x19\x63\x2b\x7c\x9d\x6c\xc8\xf9\x69\x10\x01\x43\x5e\xec\x91\x71\x6e\xb0\xa2\x4c\x1c\x6c\xd4\x2a\x2b\xe1\xc5\xe7\x1b\xac\xbe\x1c\xae\x22\x11\x8e\x2d\xba\xa6\x6c\xd4\x90\x0e\x6b\x0f\x04\x72\xa3\x85\x1c\x1f\x9f\x82\xfc\xb1\xcd\x50\x57\x3e\x90\xcf\x9e\xd5\x7b\xb6\xd7\x3f\xcb\x2f\x75\x74\x36\x88\xdf\x59\xef\x6f\x69\x14\x63\x24\xd0\x50\x50\x74\xef\xba\xff\x0c\x00\x00\xff\xff\x00\x24\x55\x1f\xc3\x21\x00\x00") func call_tracerJsBytes() ([]byte, error) { return bindataRead( @@ -133,7 +133,7 @@ func call_tracerJs() (*asset, error) { } info := bindataFileInfo{name: "call_tracer.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xb3, 0xb6, 0xe8, 0x19, 0xc3, 0xa, 0xce, 0xfd, 0x50, 0x84, 0xf7, 0x8a, 0xc5, 0x99, 0x10, 0x58, 0xc4, 0x69, 0xfb, 0x8, 0xad, 0x67, 0xea, 0x12, 0x38, 0xcb, 0xd, 0x2a, 0x94, 0xa1, 0x70}} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0xef, 0x68, 0xda, 0xd8, 0x9, 0xf5, 0xd5, 0x71, 0xa8, 0x8a, 0xfb, 0x30, 0xe8, 0xf0, 0x72, 0x14, 0x36, 0x6b, 0x62, 0x5a, 0x4e, 0xff, 0x16, 0xdc, 0xd3, 0x2c, 0x68, 0x7b, 0x79, 0x9f, 0xd3}} return a, nil } @@ -197,7 +197,7 @@ func opcount_tracerJs() (*asset, error) { return a, nil } -var _prestate_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x57\xdd\x6f\x1b\xb9\x11\x7f\xde\xfd\x2b\xa6\x7e\x91\x84\x53\x56\xce\x15\xb8\x02\x72\x5d\x60\xa3\x28\x89\x00\x9d\x6d\x48\x4a\x5d\xf7\x70\x0f\x5c\x72\x76\xc5\x13\x45\x2e\x48\xae\x3e\x10\xf8\x7f\x2f\x86\xfb\x21\xcb\x67\x27\x6e\xeb\x27\x2f\x39\xfc\xcd\xf7\x6f\x46\xa3\x11\x4c\x4c\x79\xb4\xb2\x58\x7b\xf8\xf9\xf2\xfd\xdf\x60\xb5\x46\x28\xcc\x3b\xf4\x6b\xb4\x58\x6d\x21\xad\xfc\xda\x58\x17\x8f\x46\xb0\x5a\x4b\x07\xb9\x54\x08\xd2\x41\xc9\xac\x07\x93\x83\x7f\x26\xaf\x64\x66\x99\x3d\x26\xf1\x68\x54\xbf\x79\xf1\x9a\x10\x72\x8b\x08\xce\xe4\x7e\xcf\x2c\x8e\xe1\x68\x2a\xe0\x4c\x83\x45\x21\x9d\xb7\x32\xab\x3c\x82\xf4\xc0\xb4\x18\x19\x0b\x5b\x23\x64\x7e\x24\x48\xe9\xa1\xd2\x02\x6d\x50\xed\xd1\x6e\x5d\x6b\xc7\xe7\x9b\xaf\x30\x47\xe7\xd0\xc2\x67\xd4\x68\x99\x82\xbb\x2a\x53\x92\xc3\x5c\x72\xd4\x0e\x81\x39\x28\xe9\xc4\xad\x51\x40\x16\xe0\xe8\xe1\x27\x32\x65\xd9\x98\x02\x9f\x4c\xa5\x05\xf3\xd2\xe8\x21\xa0\x24\xcb\x61\x87\xd6\x49\xa3\xe1\xaf\xad\xaa\x06\x70\x08\xc6\x12\x48\x9f\x79\x72\xc0\x82\x29\xe9\xdd\x00\x98\x3e\x82\x62\xfe\xf4\xf4\x0d\x01\x39\xf9\x2d\x40\xea\xa0\x66\x6d\x4a\x04\xbf\x66\x9e\xbc\xde\x4b\xa5\x20\x43\xa8\x1c\xe6\x95\x1a\x12\x5a\x56\x79\xb8\x9f\xad\xbe\xdc\x7e\x5d\x41\x7a\xf3\x00\xf7\xe9\x62\x91\xde\xac\x1e\xae\x60\x2f\xfd\xda\x54\x1e\x70\x87\x35\x94\xdc\x96\x4a\xa2\x80\x3d\xb3\x96\x69\x7f\x04\x93\x13\xc2\xaf\xd3\xc5\xe4\x4b\x7a\xb3\x4a\x3f\xcc\xe6\xb3\xd5\x03\x18\x0b\x9f\x66\xab\x9b\xe9\x72\x09\x9f\x6e\x17\x90\xc2\x5d\xba\x58\xcd\x26\x5f\xe7\xe9\x02\xee\xbe\x2e\xee\x6e\x97\xd3\x04\x96\x48\x56\x21\xbd\xff\x71\xcc\xf3\x90\x3d\x8b\x20\xd0\x33\xa9\x5c\x1b\x89\x07\x53\x81\x5b\x9b\x4a\x09\x58\xb3\x1d\x82\x45\x8e\x72\x87\x02\x18\x70\x53\x1e\xdf\x9c\x54\xc2\x62\xca\xe8\x22\xf8\xfc\x6a\x41\xc2\x2c\x07\x6d\xfc\x10\x1c\x22\xfc\x7d\xed\x7d\x39\x1e\x8d\xf6\xfb\x7d\x52\xe8\x2a\x31\xb6\x18\xa9\x1a\xce\x8d\xfe\x91\xc4\x84\x59\x5a\x74\x9e\x79\x5c\x59\xc6\xd1\x82\xa9\x7c\x59\x79\x07\xae\xca\x73\xc9\x25\x6a\x0f\x52\xe7\xc6\x6e\x43\xa5\x80\x37\xc0\x2d\x32\x8f\xc0\x40\x19\xce\x14\xe0\x01\x79\x15\xee\xea\x48\x87\x72\xb5\x4c\x3b\xc6\xc3\x69\x6e\xcd\x96\x7c\xad\x9c\xa7\x7f\x9c\xc3\x6d\xa6\x50\x40\x81\x1a\x9d\x74\x90\x29\xc3\x37\x49\xfc\x2d\x8e\x9e\x18\x43\x75\x12\x3c\x6c\x84\x42\x6d\xec\xb1\x67\x11\xb2\x4a\x2a\x21\x75\x91\xc4\x51\x2b\x3d\x06\x5d\x29\x35\x8c\x03\x84\x32\x66\x53\x95\x29\xe7\xa6\x0a\xb6\xff\x81\xdc\xd7\x60\xae\x44\x2e\x73\x2a\x0e\xd6\xdd\x7a\x13\xae\x3a\xbd\x26\x23\xf9\x24\x8e\xce\x60\xc6\x90\x57\x3a\xb8\xd3\x67\x42\xd8\x21\x88\x6c\xf0\x2d\x8e\xa2\x1d\xb3\x84\x05\xd7\xe0\xcd\x17\x3c\x84\xcb\xc1\x55\x1c\x45\x32\x87\xbe\x5f\x4b\x97\xb4\xc0\xbf\x31\xce\x7f\x87\xeb\xeb\xeb\xd0\xd4\xb9\xd4\x28\x06\x40\x10\xd1\x4b\x62\xf5\x4d\x94\x31\xc5\x34\xc7\x31\xf4\x2e\x0f\x3d\xf8\x09\x44\x96\x14\xe8\x3f\xd4\xa7\xb5\xb2\xc4\x9b\xa5\xb7\x52\x17\xfd\xf7\xbf\x0c\x86\xe1\x95\x36\xe1\x0d\x34\xe2\x37\xa6\x13\xae\xef\xb9\x11\xe1\xba\xb1\xb9\x96\x9a\x18\xd1\x08\x35\x52\xce\x1b\xcb\x0a\x1c\xc3\xb7\x47\xfa\x7e\x24\xaf\x1e\xe3\xe8\xf1\x2c\xca\xcb\x5a\xe8\x95\x28\x37\x10\x80\xda\xdb\xae\xce\x0b\x49\x9d\xfa\x34\x01\x01\xef\x7b\x49\x58\xb6\xa6\x3c\x4b\xc2\x06\x8f\x3f\xce\x04\x5d\x48\x71\xe8\x2e\x36\x78\x1c\x5c\xc5\xaf\xa6\x28\x69\x8c\xfe\x4d\x8a\xc3\xcb\xf9\x22\xc0\x1d\x53\x1d\x60\x1d\xbf\x25\x21\x9c\xec\x1a\x04\xdd\x41\x07\xc9\xfe\xe5\x1a\x2e\x2e\x0f\x97\xff\xe7\xdf\x45\x63\xc1\x0b\x25\xf3\xcc\xec\x37\x98\xf6\x78\x9e\x4f\x8b\xae\x52\x9e\xda\x4e\xea\x9d\xd9\x10\x81\xae\x29\x4f\x4a\x85\xd4\x98\x92\xaa\xc6\xd5\x0c\x96\x21\x6a\x90\x1e\x2d\x23\x0a\x37\x3b\xb4\x34\xbd\xc0\xa2\xaf\xac\x76\x5d\x3a\x73\xa9\x99\x6a\x81\x9b\xec\x7b\xcb\x78\xdd\xbb\xf5\xf9\x93\x9c\x72\x7f\x08\xd9\x0c\x3e\x8e\x46\x90\x7a\x20\x3f\xa1\x34\x52\xfb\x21\xec\x11\x34\xa2\x20\x02\x12\x28\x2a\xee\x03\x5e\x6f\xc7\x54\x85\xbd\x9a\x64\x88\xaa\xc3\x53\x53\xd1\x44\x7a\x42\x42\xc3\x60\xe0\xd6\xec\xc2\xa8\xcd\x18\xdf\x40\xd3\xf8\xc6\xca\x42\xea\xb8\x89\xe9\x59\xd3\x93\x45\x09\x01\x07\xb3\x42\xcd\x50\xee\xe9\xe4\x43\xc8\x7f\x26\x8b\x99\xf6\xcf\x8a\xa8\x8e\x7c\xfb\x74\xf0\x7b\xd2\x34\x71\xe2\x88\x78\xfb\x3f\x0f\x86\xf0\xfe\x97\xae\x32\xbd\x21\x28\xf8\x31\x98\x37\xaf\x43\xc5\xcf\x2b\xe2\xe5\x67\x41\x0d\x31\xc9\x4f\x41\x6b\xe2\xaa\x8c\xd2\x51\xfb\x19\xe2\x78\xce\x26\x57\xdf\xc1\x3d\xf7\xad\xc5\x6d\x42\x93\x30\x21\x5e\x07\xad\x53\xf4\x11\xb9\xc5\x2d\x4d\x17\xca\x02\x67\x4a\xa1\xed\x39\x08\xdc\x35\x6c\xca\x29\xe4\x0b\xb7\xa5\x3f\xb6\x33\xc7\x33\x5b\xa0\x77\x3f\x36\x2c\xe0\xbc\x7b\xd7\x52\x71\x08\xc5\xb1\x44\xb8\xbe\x86\xde\x64\x31\x4d\x57\xd3\x5e\xd3\x4c\xa3\x11\xdc\x63\xd8\xc8\x32\x25\x33\xa1\x8e\x20\x50\xa1\xc7\xda\x2e\xa3\x43\x88\x3a\x6a\x1a\xd2\x6a\x45\x4b\x0f\x1e\xa4\xf3\x52\x17\x50\x33\xd6\x9e\xe6\x7b\x03\x17\x7a\x84\xb3\xca\x51\xb5\x3e\x1b\x86\xde\xd0\x66\x63\x91\xf8\x8d\xe6\x50\x68\x37\xa6\x64\xb7\x09\xe5\xd2\x3a\x0f\xa5\x62\x1c\x13\xc2\xeb\x8c\x79\x3d\xbf\x0d\x33\x93\xea\x45\x68\xc1\x00\x74\x1a\xb4\x4c\xd1\xa0\x26\xf5\x0e\xfa\x2d\xc6\x20\x8e\x22\xdb\x4a\x3f\xc1\xbe\x3a\x51\x82\xf3\x58\x3e\x25\x04\x5a\x70\x70\x87\x44\xe5\x81\x0d\xea\xa1\x4c\xba\xfe\xf9\x6b\xb3\x05\xa0\x4b\xe2\x88\xde\x3d\xe9\x6b\x65\x8a\xf3\xbe\x16\x75\x58\x78\x65\x2d\xe5\xbf\x1b\x05\x39\xf5\xf8\x1f\x95\xf3\x14\x53\x4b\xe1\x69\xd8\xe2\x25\xb2\x0e\xd4\x4c\x53\x7f\xf0\xe7\x21\x4a\xf3\x33\xcc\x2b\x52\xd7\x4c\xcb\x7a\xab\x2c\x8d\x47\xed\x25\x53\xea\x48\x79\xd8\x5b\x5a\xa7\x68\x81\x1a\x82\x93\x24\x15\x18\x27\x88\x4a\xcd\x55\x25\xea\x32\x08\x75\xdc\xe0\xb9\x60\xf3\xf9\x1e\xb6\x45\xe7\x58\x81\x09\x55\x52\x2e\x0f\xcd\x26\xab\xa1\x57\x93\x5c\x7f\xd0\x4b\x3a\x23\xcf\x29\x46\x99\x22\x69\x8b\x8c\xb8\x3a\x15\xc2\xa2\x73\xfd\x41\xc3\x39\x5d\x66\xef\xd7\xa8\x29\xf8\xa0\x71\x0f\xdd\x8a\xc4\x38\xa7\x95\x51\x0c\x81\x09\x41\xd4\xf6\x6c\x9d\x89\xa3\xc8\xed\xa5\xe7\x6b\x08\x9a\x4c\x79\xea\xc5\x41\x53\xff\x9c\x39\x84\x8b\xe9\xbf\x56\x93\xdb\x8f\xd3\xc9\xed\xdd\xc3\xc5\x18\xce\xce\x96\xb3\x7f\x4f\xbb\xb3\x0f\xe9\x3c\xbd\x99\x4c\x2f\xc6\xa7\x39\x74\xee\x90\x37\xad\x0b\xa4\xd0\x79\xc6\x37\x49\x89\xb8\xe9\x5f\x9e\xf3\xc0\xc9\xc1\x28\xca\x2c\xb2\xcd\xd5\xc9\x98\xba\x41\x1b\x1d\x2d\xe5\xc2\x35\xbc\x1a\xac\xab\xd7\xad\x99\x34\xf2\xfd\x96\xc8\x4f\x2b\x51\xa0\x8a\xef\xda\x91\xce\xe7\x9d\xe7\xf4\x41\xe1\xe8\x0e\x3e\x4e\xe7\xd3\xcf\xe9\x6a\x7a\x26\xb5\x5c\xa5\xab\xd9\xa4\x3e\xfa\xaf\x43\xf4\xfe\xcd\x21\xea\x2d\x97\xab\xdb\xc5\xb4\x37\x6e\xbe\xe6\xb7\xe9\xc7\xde\x9f\x14\x36\x7b\xd3\xf7\x8a\xcc\x9b\x7b\x63\xc5\xff\x92\xab\x27\xbb\x43\xce\x5e\x5a\x1d\x02\x09\x71\x5f\x3d\xfb\x89\x00\x4c\xb7\xfc\x91\xd7\x3f\x93\xa2\xf0\xfe\x45\xc6\x78\x8c\x1f\xe3\xff\x04\x00\x00\xff\xff\xb5\x44\x89\xaf\xbc\x0f\x00\x00") +var _prestate_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x57\xdd\x6f\xdb\x38\x12\x7f\x96\xfe\x8a\x41\x5f\x6c\xa3\xae\xdc\x64\x81\x3d\xc0\xb9\x1c\xa0\xba\x6e\x1b\x20\x9b\x04\xb6\x7b\xb9\xdc\x62\x1f\x28\x72\x24\x73\x4d\x93\x02\x49\xd9\xf1\x15\xf9\xdf\x0f\x43\x7d\xf8\xa3\x49\xd3\xdd\x37\x9b\x1c\xfe\xe6\xfb\x37\xa3\xd1\x08\x26\xa6\xdc\x59\x59\x2c\x3d\x9c\xbf\x3f\xfb\x07\x2c\x96\x08\x85\x79\x87\x7e\x89\x16\xab\x35\xa4\x95\x5f\x1a\xeb\xe2\xd1\x08\x16\x4b\xe9\x20\x97\x0a\x41\x3a\x28\x99\xf5\x60\x72\xf0\x27\xf2\x4a\x66\x96\xd9\x5d\x12\x8f\x46\xf5\x9b\x67\xaf\x09\x21\xb7\x88\xe0\x4c\xee\xb7\xcc\xe2\x18\x76\xa6\x02\xce\x34\x58\x14\xd2\x79\x2b\xb3\xca\x23\x48\x0f\x4c\x8b\x91\xb1\xb0\x36\x42\xe6\x3b\x82\x94\x1e\x2a\x2d\xd0\x06\xd5\x1e\xed\xda\xb5\x76\x7c\xbe\xf9\x0a\xd7\xe8\x1c\x5a\xf8\x8c\x1a\x2d\x53\x70\x57\x65\x4a\x72\xb8\x96\x1c\xb5\x43\x60\x0e\x4a\x3a\x71\x4b\x14\x90\x05\x38\x7a\xf8\x89\x4c\x99\x37\xa6\xc0\x27\x53\x69\xc1\xbc\x34\x7a\x08\x28\xc9\x72\xd8\xa0\x75\xd2\x68\xf8\xa5\x55\xd5\x00\x0e\xc1\x58\x02\xe9\x33\x4f\x0e\x58\x30\x25\xbd\x1b\x00\xd3\x3b\x50\xcc\xef\x9f\xfe\x44\x40\xf6\x7e\x0b\x90\x3a\xa8\x59\x9a\x12\xc1\x2f\x99\x27\xaf\xb7\x52\x29\xc8\x10\x2a\x87\x79\xa5\x86\x84\x96\x55\x1e\xee\xaf\x16\x5f\x6e\xbf\x2e\x20\xbd\x79\x80\xfb\x74\x36\x4b\x6f\x16\x0f\x17\xb0\x95\x7e\x69\x2a\x0f\xb8\xc1\x1a\x4a\xae\x4b\x25\x51\xc0\x96\x59\xcb\xb4\xdf\x81\xc9\x09\xe1\xb7\xe9\x6c\xf2\x25\xbd\x59\xa4\x1f\xae\xae\xaf\x16\x0f\x60\x2c\x7c\xba\x5a\xdc\x4c\xe7\x73\xf8\x74\x3b\x83\x14\xee\xd2\xd9\xe2\x6a\xf2\xf5\x3a\x9d\xc1\xdd\xd7\xd9\xdd\xed\x7c\x9a\xc0\x1c\xc9\x2a\xa4\xf7\xaf\xc7\x3c\x0f\xd9\xb3\x08\x02\x3d\x93\xca\xb5\x91\x78\x30\x15\xb8\xa5\xa9\x94\x80\x25\xdb\x20\x58\xe4\x28\x37\x28\x80\x01\x37\xe5\xee\xa7\x93\x4a\x58\x4c\x19\x5d\x04\x9f\x5f\x2c\x48\xb8\xca\x41\x1b\x3f\x04\x87\x08\xff\x5c\x7a\x5f\x8e\x47\xa3\xed\x76\x9b\x14\xba\x4a\x8c\x2d\x46\xaa\x86\x73\xa3\x7f\x25\x31\x61\x96\x16\x9d\x67\x1e\x17\x96\x71\xb4\x60\x2a\x5f\x56\xde\x81\xab\xf2\x5c\x72\x89\xda\x83\xd4\xb9\xb1\xeb\x50\x29\xe0\x0d\x70\x8b\xcc\x23\x30\x50\x86\x33\x05\xf8\x88\xbc\x0a\x77\x75\xa4\x43\xb9\x5a\xa6\x1d\xe3\xe1\x34\xb7\x66\x4d\xbe\x56\xce\xd3\x0f\xe7\x70\x9d\x29\x14\x50\xa0\x46\x27\x1d\x64\xca\xf0\x55\x12\x7f\x8b\xa3\x03\x63\xa8\x4e\x82\x87\x8d\x50\xa8\x8d\x2d\xf6\x2c\x42\x56\x49\x25\xa4\x2e\x92\x38\x6a\xa5\xc7\xa0\x2b\xa5\x86\x71\x80\x50\xc6\xac\xaa\x32\xe5\xdc\x54\xc1\xf6\x3f\x91\xfb\x1a\xcc\x95\xc8\x65\x4e\xc5\xc1\xba\x5b\x6f\xc2\x55\xa7\xd7\x64\x24\x9f\xc4\xd1\x11\xcc\x18\xf2\x4a\x07\x77\xfa\x4c\x08\x3b\x04\x91\x0d\xbe\xc5\x51\xb4\x61\x96\xb0\xe0\x12\xbc\xf9\x82\x8f\xe1\x72\x70\x11\x47\x91\xcc\xa1\xef\x97\xd2\x25\x2d\xf0\xef\x8c\xf3\x3f\xe0\xf2\xf2\x32\x34\x75\x2e\x35\x8a\x01\x10\x44\xf4\x9c\x58\x7d\x13\x65\x4c\x31\xcd\x71\x0c\xbd\xf7\x8f\x3d\x78\x0b\x22\x4b\x0a\xf4\x1f\xea\xd3\x5a\x59\xe2\xcd\xdc\x5b\xa9\x8b\xfe\xd9\xaf\x83\x61\x78\xa5\x4d\x78\x03\x8d\xf8\x8d\xe9\x84\xeb\x7b\x6e\x44\xb8\x6e\x6c\xae\xa5\x26\x46\x34\x42\x8d\x94\xf3\xc6\xb2\x02\xc7\xf0\xed\x89\xfe\x3f\x91\x57\x4f\x71\xf4\x74\x14\xe5\x79\x2d\xf4\x42\x94\x1b\x08\x40\xed\x6d\x57\xe7\x85\xa4\x4e\x3d\x4c\x40\xc0\xfb\x51\x12\xe6\xad\x29\x27\x49\x58\xe1\xee\xf5\x4c\xd0\x85\x14\x8f\xdd\xc5\x0a\x77\x83\x8b\xf8\xc5\x14\x25\x8d\xd1\xbf\x4b\xf1\xf8\xb3\xf9\x3a\x79\x73\x14\xd7\x39\x49\xed\xed\x1d\x0c\x4e\xe2\x68\xd1\x55\xca\x53\xb9\x4b\xbd\x31\x2b\x22\xae\x25\xc5\x47\xa9\x10\x12\x53\x52\xb6\x5c\xcd\x1c\x19\xa2\x06\xe9\xd1\x32\xa2\x4e\xb3\x41\x4b\x53\x03\x2c\xfa\xca\x6a\xd7\x85\x31\x97\x9a\xa9\x16\xb8\x89\xba\xb7\x8c\xd7\x3d\x53\x9f\x1f\xc4\x92\xfb\xc7\x10\xc5\xe0\xdd\x68\x04\xa9\x07\x72\x11\x4a\x23\xb5\x1f\xc2\x16\x41\x23\x0a\x6a\x7c\x81\xa2\xe2\x3e\xe0\xf5\x36\x4c\x55\xd8\xab\x9b\x9b\x28\x32\x3c\x35\x15\x4d\x82\x83\xe6\x1f\x06\x03\xd7\x66\x13\x46\x5c\xc6\xf8\x0a\x9a\x86\x33\x56\x16\x52\xc7\x4d\x38\x8f\x9a\x8d\x2c\x4a\x08\x38\x98\x15\x72\x45\x49\xa4\x93\x0f\x4c\xc1\x25\x64\xb2\xb8\xd2\xfe\x24\x79\x75\xd0\xdb\xa7\x83\x3f\x92\xa6\x79\x12\x47\x84\xd7\x3f\x1f\x0c\xe1\xec\xd7\xae\x22\xbc\x21\x28\x78\x1d\xcc\x9b\x97\xa1\xe2\xd3\x62\x78\xfe\x59\x50\x43\x1d\xfc\x36\x68\x4d\x5c\x95\x51\x3a\x6a\x3f\x43\x1c\x8f\xbb\xf8\xe2\x07\xb8\xc7\xbe\xb5\xb8\x4d\x68\x12\x26\xc4\xcb\xa0\x75\x8a\x3e\x22\xb7\xb8\x26\x56\xa7\x2c\x70\xa6\x14\xda\x9e\x83\xc0\x19\xc3\xa6\x9c\x42\xbe\x70\x5d\xfa\x5d\xcb\xf5\x9e\xd9\x02\xbd\x7b\xdd\xb0\x80\xf3\xee\x5d\x4b\x81\x21\x14\xbb\x12\xe1\xf2\x12\x7a\x93\xd9\x34\x5d\x4c\x7b\x4d\x1b\x8d\x46\x70\x8f\x61\x13\xca\x94\xcc\x84\xda\x81\x40\x85\x1e\x6b\xbb\x8c\x0e\x21\xea\x28\x61\x48\x2b\x0d\x2d\x1b\xf8\x28\x9d\x97\xba\x80\x9a\x29\xb6\x34\x57\x1b\xb8\xd0\x23\x9c\x55\x8e\xaa\xf5\x64\x08\x79\x43\x1b\x85\x45\xe2\x15\xe2\xff\xd0\x6e\x4c\xc9\x6e\x03\xc9\xa5\x75\x1e\x4a\xc5\x38\x26\x84\xd7\x19\xf3\x72\x7e\x9b\x4e\x26\xd5\xb3\xd0\x82\x01\x68\x3f\xe0\x98\xa2\x01\x49\xea\x1d\xf4\x5b\x8c\x41\x1c\x45\xb6\x95\x3e\xc0\xbe\xd8\x53\x82\xf3\x58\x1e\x12\x02\x2d\x16\xb8\x41\xa2\xd0\xc0\x06\xf5\x30\x24\x5d\xff\xfe\xad\x99\xbe\xe8\x92\x38\xa2\x77\x07\x7d\xad\x4c\x71\xdc\xd7\xa2\x0e\x0b\xaf\xac\xa5\xfc\x77\x14\x9c\x53\x8f\xff\x59\x39\x4f\x31\xb5\x14\x9e\x86\x2d\x9e\x23\xc9\x40\x89\x34\x6d\x07\xdf\x93\x21\xcd\xad\x30\x27\x48\x5d\x33\xa5\xea\x6d\xae\x34\x1e\xb5\x97\x4c\xa9\x1d\xe5\x61\x6b\x69\x8d\xa1\xc5\x65\x08\x4e\x92\x54\x60\x9c\x20\x2a\x35\x57\x95\xa8\xcb\x20\xd4\x71\x83\xe7\x82\xcd\xc7\xfb\xcf\x1a\x9d\x63\x05\x26\x54\x49\xb9\x7c\x6c\x36\x48\x0d\xbd\x9a\xe4\xfa\x83\x5e\xd2\x19\x79\x4c\x31\xca\x14\x49\x5b\x64\x44\xd3\xa9\x10\x16\x9d\xeb\x0f\x1a\xce\xe9\x32\x7b\xbf\x44\x4d\xc1\x07\x8d\x5b\xe8\x56\x13\xc6\x39\xad\x6a\x62\x08\x4c\x08\xa2\xb6\x93\x35\x22\x8e\x22\xb7\x95\x9e\x2f\x21\x68\x32\xe5\xbe\x17\x07\x4d\xfd\x73\xe6\x10\xde\x4c\xff\xb3\x98\xdc\x7e\x9c\x4e\x6e\xef\x1e\xde\x8c\xe1\xe8\x6c\x7e\xf5\xdf\x69\x77\xf6\x21\xbd\x4e\x6f\x26\xd3\x37\xe3\x30\x9b\x9f\x71\xc8\x9b\xd6\x05\x52\xe8\x3c\xe3\xab\xa4\x44\x5c\xf5\xdf\x1f\xf3\xc0\xde\xc1\x28\xca\x2c\xb2\xd5\xc5\xde\x98\xba\x41\x1b\x1d\x2d\xe5\xc2\x25\xbc\x18\xac\x8b\x97\xad\x99\x34\xf2\xfd\x96\xc8\xf7\xab\x48\xa0\x8a\xd7\xed\x38\xff\xcb\x86\x84\xde\x61\x7c\x35\x06\xc7\x14\x6d\xc0\xf2\x7f\xf4\xe5\x92\xe7\x0e\xfd\x10\x50\x0b\xb3\x25\xe6\xeb\x50\xeb\x9b\x06\xf7\x20\x64\x67\x83\x9a\x41\x6f\xf3\xfe\xa0\x13\x26\xb0\xef\x45\xcf\x9f\x13\x45\x2d\xe0\xb2\x45\x7f\x1b\x5e\xbe\x1e\xa8\xf3\x26\x52\x27\x0a\x7e\x39\xd9\xf0\xc2\xfd\x1a\xd7\xc6\xee\x9a\x71\x74\xe0\xdf\x8f\xa3\x9a\x5e\x5f\x77\xf5\x44\x7f\xa8\xc8\xba\x83\x8f\xd3\xeb\xe9\xe7\x74\x31\x3d\x92\x9a\x2f\xd2\xc5\xd5\xa4\x3e\xfa\xcb\x85\x77\xf6\xd3\x85\xd7\x9b\xcf\x17\xb7\xb3\x69\x6f\xdc\xfc\xbb\xbe\x4d\x3f\xf6\xbe\x53\xd8\x6c\x81\x3f\x6a\x5d\x6f\xee\x8d\x15\x7f\xa7\x03\x0e\x36\xb2\x9c\x3d\xb7\x90\x05\x6a\xe7\xbe\x3a\xf9\xe0\x01\xa6\x5b\x56\xce\xeb\x8f\xbe\x28\xbc\x7f\x96\x87\x9f\xe2\xa7\xf8\xff\x01\x00\x00\xff\xff\xb1\x28\x85\x2a\x8a\x10\x00\x00") func prestate_tracerJsBytes() ([]byte, error) { return bindataRead( @@ -213,7 +213,7 @@ func prestate_tracerJs() (*asset, error) { } info := bindataFileInfo{name: "prestate_tracer.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd0, 0xd5, 0x5, 0x92, 0xed, 0xf4, 0x69, 0x2e, 0x14, 0x48, 0x35, 0x67, 0xcc, 0xf2, 0x3e, 0xc7, 0xf, 0x18, 0x22, 0x7a, 0x4d, 0x6f, 0x31, 0xad, 0x3c, 0x92, 0x77, 0xb4, 0x1, 0x2a, 0xd3, 0x7c}} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0x79, 0x70, 0x4f, 0xc5, 0x78, 0x57, 0x63, 0x6f, 0x5, 0x31, 0xce, 0x3e, 0x5d, 0xbd, 0x71, 0x4, 0x46, 0x78, 0xcd, 0x1d, 0xcd, 0xb9, 0xd8, 0x10, 0xff, 0xe6, 0xc5, 0x59, 0xb9, 0x25, 0x6e}} return a, nil } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/call_tracer.js b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/call_tracer.js index 83495b15..f8b383cd 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/call_tracer.js +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/call_tracer.js @@ -38,7 +38,7 @@ var op = log.op.toString(); } // If a new contract is being created, add to the call stack - if (syscall && op == 'CREATE') { + if (syscall && (op == 'CREATE' || op == "CREATE2")) { var inOff = log.stack.peek(1).valueOf(); var inEnd = inOff + log.stack.peek(2).valueOf(); @@ -116,7 +116,7 @@ // Pop off the last call and get the execution results var call = this.callstack.pop(); - if (call.type == 'CREATE') { + if (call.type == 'CREATE' || call.type == "CREATE2") { // If the call was a CREATE, retrieve the contract address and output code call.gasUsed = '0x' + bigInt(call.gasIn - call.gasCost - log.getGas()).toString(16); delete call.gasIn; delete call.gasCost; diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/prestate_tracer.js b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/prestate_tracer.js index 99f71d2c..e0a22bf1 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/prestate_tracer.js +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/prestate_tracer.js @@ -40,10 +40,7 @@ var idx = toHex(key); if (this.prestate[acc].storage[idx] === undefined) { - var val = toHex(db.getState(addr, key)); - if (val != "0x0000000000000000000000000000000000000000000000000000000000000000") { - this.prestate[acc].storage[idx] = toHex(db.getState(addr, key)); - } + this.prestate[acc].storage[idx] = toHex(db.getState(addr, key)); } }, @@ -89,6 +86,14 @@ var from = log.contract.getAddress(); this.lookupAccount(toContract(from, db.getNonce(from)), db); break; + case "CREATE2": + var from = log.contract.getAddress(); + // stack: salt, size, offset, endowment + var offset = log.stack.peek(1).valueOf() + var size = log.stack.peek(2).valueOf() + var end = offset + size + this.lookupAccount(toContract2(from, log.stack.peek(3).toString(16), log.memory.slice(offset, end)), db); + break; case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL": this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db); break; diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/tracers.go b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/tracers.go index dcf0d49d..2e40975b 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/tracers.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/internal/tracers/tracers.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:generate go-bindata -nometadata -o assets.go -pkg tracers -ignore ((tracers)|(assets)).go ./... +//go:generate go-bindata -nometadata -o assets.go -pkg tracers -ignore tracers.go -ignore assets.go ./... //go:generate gofmt -s -w assets.go // Package tracers contains the actual JavaScript tracer assets. diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json b/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json index b8a4cdd2..d1c8ac91 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json @@ -65,7 +65,7 @@ "value": "0x0" } ], - "error": "invalid jump destination (PUSH1) 0", + "error": "evm: invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", "gas": "0x435c8", "gasUsed": "0x435c8", diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_throw.json b/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_throw.json index 60d4d107..d66f1ffa 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_throw.json +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/testdata/call_tracer_throw.json @@ -50,7 +50,7 @@ }, "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750", "result": { - "error": "invalid jump destination (PUSH1) 2", + "error": "evm: invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", "gas": "0x37b38", "gasUsed": "0x37b38", diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracer.go b/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracer.go index 3533a831..9d670186 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracer.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracer.go @@ -367,6 +367,28 @@ func New(code string) (*Tracer, error) { copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) return 1 }) + tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int { + var from common.Address + if ptr, size := ctx.GetBuffer(-3); ptr != nil { + from = common.BytesToAddress(makeSlice(ptr, size)) + } else { + from = common.HexToAddress(ctx.GetString(-3)) + } + // Retrieve salt hex string from js stack + salt := common.HexToHash(ctx.GetString(-2)) + // Retrieve code slice from js stack + var code []byte + if ptr, size := ctx.GetBuffer(-1); ptr != nil { + code = common.CopyBytes(makeSlice(ptr, size)) + } else { + code = common.FromHex(ctx.GetString(-1)) + } + codeHash := crypto.Keccak256(code) + ctx.Pop3() + contract := crypto.CreateAddress2(from, salt, codeHash) + copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) + return 1 + }) tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { _, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))] ctx.PushBoolean(ok) diff --git a/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracers_test.go b/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracers_test.go index d25fc459..69eb80a5 100644 --- a/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracers_test.go +++ b/vendor/github.com/ethereum/go-ethereum/eth/tracers/tracers_test.go @@ -17,6 +17,8 @@ package tracers import ( + "crypto/ecdsa" + "crypto/rand" "encoding/json" "io/ioutil" "math/big" @@ -29,9 +31,11 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" ) @@ -116,6 +120,85 @@ type callTracerTest struct { Result *callTrace `json:"result"` } +func TestPrestateTracerCreate2(t *testing.T) { + unsignedTx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), + new(big.Int), 5000000, big.NewInt(1), []byte{}) + + privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) + if err != nil { + t.Fatalf("err %v", err) + } + signer := types.NewEIP155Signer(big.NewInt(1)) + tx, err := types.SignTx(unsignedTx, signer, privateKeyECDSA) + if err != nil { + t.Fatalf("err %v", err) + } + /** + This comes from one of the test-vectors on the Skinny Create2 - EIP + + address 0x00000000000000000000000000000000deadbeef + salt 0x00000000000000000000000000000000000000000000000000000000cafebabe + init_code 0xdeadbeef + gas (assuming no mem expansion): 32006 + result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7 + */ + origin, _ := signer.Sender(tx) + context := vm.Context{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Origin: origin, + Coinbase: common.Address{}, + BlockNumber: new(big.Int).SetUint64(8000000), + Time: new(big.Int).SetUint64(5), + Difficulty: big.NewInt(0x30000), + GasLimit: uint64(6000000), + GasPrice: big.NewInt(1), + } + alloc := core.GenesisAlloc{} + + // The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns + // the address + alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{ + Nonce: 1, + Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"), + Balance: big.NewInt(1), + } + alloc[origin] = core.GenesisAccount{ + Nonce: 1, + Code: []byte{}, + Balance: big.NewInt(500000000000000), + } + statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc) + + // Create the tracer, the EVM environment and run it + tracer, err := New("prestateTracer") + if err != nil { + t.Fatalf("failed to create call tracer: %v", err) + } + evm := vm.NewEVM(context, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) + + msg, err := tx.AsMessage(signer) + if err != nil { + t.Fatalf("failed to prepare transaction for tracing: %v", err) + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if _, _, _, err = st.TransitionDb(); err != nil { + t.Fatalf("failed to execute transaction: %v", err) + } + // Retrieve the trace result and compare against the etalon + res, err := tracer.GetResult() + if err != nil { + t.Fatalf("failed to retrieve trace result: %v", err) + } + ret := make(map[string]interface{}) + if err := json.Unmarshal(res, &ret); err != nil { + t.Fatalf("failed to unmarshal trace result: %v", err) + } + if _, has := ret["0x60f3f640a8508fc6a86d45df051962668e1e8ac7"]; !has { + t.Fatalf("Expected 0x60f3f640a8508fc6a86d45df051962668e1e8ac7 in result") + } +} + // Iterates over all the input-output datasets in the tracer test harness and // runs the JavaScript tracers against them. func TestCallTracer(t *testing.T) { @@ -159,7 +242,7 @@ func TestCallTracer(t *testing.T) { GasLimit: uint64(test.Context.GasLimit), GasPrice: tx.GasPrice(), } - statedb := tests.MakePreState(ethdb.NewMemDatabase(), test.Genesis.Alloc) + statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc) // Create the tracer, the EVM environment and run it tracer, err := New("callTracer") @@ -185,8 +268,9 @@ func TestCallTracer(t *testing.T) { if err := json.Unmarshal(res, ret); err != nil { t.Fatalf("failed to unmarshal trace result: %v", err) } + if !reflect.DeepEqual(ret, test.Result) { - t.Fatalf("trace mismatch: have %+v, want %+v", ret, test.Result) + t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) } }) } diff --git a/vendor/github.com/ethereum/go-ethereum/eth/ulc_config.go b/vendor/github.com/ethereum/go-ethereum/eth/ulc_config.go new file mode 100644 index 00000000..effa6da2 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/eth/ulc_config.go @@ -0,0 +1,9 @@ +package eth + +const DefaultULCMinTrustedFraction = 75 + +// ULCConfig is a Ultra Light client options. +type ULCConfig struct { + TrustedServers []string `toml:",omitempty"` // A list of trusted servers + MinTrustedFraction int `toml:",omitempty"` // Minimum percentage of connected trusted servers to validate trusted (1-100) +} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/.gitignore b/vendor/github.com/ethereum/go-ethereum/ethdb/.gitignore deleted file mode 100644 index f725d58d..00000000 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. -# -# If you find yourself ignoring temporary files generated by your text editor -# or operating system, you probably want to add a global ignore instead: -# git config --global core.excludesfile ~/.gitignore_global - -/tmp -*/**/*un~ -*un~ -.DS_Store -*/**/.DS_Store - diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/interface.go b/vendor/github.com/ethereum/go-ethereum/ethdb/batch.go similarity index 53% rename from vendor/github.com/ethereum/go-ethereum/ethdb/interface.go rename to vendor/github.com/ethereum/go-ethereum/ethdb/batch.go index af135577..a9c40635 100644 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/interface.go +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/batch.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -16,37 +16,31 @@ package ethdb -// Code using batches should try to add this much data to the batch. -// The value was determined empirically. +// IdealBatchSize defines the size of the data batches should ideally add in one +// write. const IdealBatchSize = 100 * 1024 -// Putter wraps the database write operation supported by both batches and regular databases. -type Putter interface { - Put(key []byte, value []byte) error +// Batch is a write-only database that commits changes to its host database +// when Write is called. A batch cannot be used concurrently. +type Batch interface { + Writer + + // ValueSize retrieves the amount of data queued up for writing. + ValueSize() int + + // Write flushes any accumulated data to disk. + Write() error + + // Reset resets the batch for reuse. + Reset() + + // Replay replays the batch contents. + Replay(w Writer) error } -// Deleter wraps the database delete operation supported by both batches and regular databases. -type Deleter interface { - Delete(key []byte) error -} - -// Database wraps all database operations. All methods are safe for concurrent use. -type Database interface { - Putter - Deleter - Get(key []byte) ([]byte, error) - Has(key []byte) (bool, error) - Close() +// Batcher wraps the NewBatch method of a backing data store. +type Batcher interface { + // NewBatch creates a write-only database that buffers changes to its host db + // until a final write is called. NewBatch() Batch } - -// Batch is a write-only database that commits changes to its host database -// when Write is called. Batch cannot be used concurrently. -type Batch interface { - Putter - Deleter - ValueSize() int // amount of data in the batch - Write() error - // Reset resets the batch for reuse - Reset() -} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/database.go b/vendor/github.com/ethereum/go-ethereum/ethdb/database.go index 6c62d6a3..bab99aed 100644 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/database.go +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/database.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,371 +14,67 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build !js - +// Package ethdb defines the interfaces for an Ethereum data store. package ethdb -import ( - "fmt" - "strconv" - "strings" - "sync" - "time" +import "io" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/errors" - "github.com/syndtr/goleveldb/leveldb/filter" - "github.com/syndtr/goleveldb/leveldb/iterator" - "github.com/syndtr/goleveldb/leveldb/opt" - "github.com/syndtr/goleveldb/leveldb/util" -) +// Reader wraps the Has and Get method of a backing data store. +type Reader interface { + // Has retrieves if a key is present in the key-value data store. + Has(key []byte) (bool, error) -const ( - writePauseWarningThrottler = 1 * time.Minute -) - -var OpenFileLimit = 64 - -type LDBDatabase struct { - fn string // filename for reporting - db *leveldb.DB // LevelDB instance - - compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction - compReadMeter metrics.Meter // Meter for measuring the data read during compaction - compWriteMeter metrics.Meter // Meter for measuring the data written during compaction - writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction - writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction - diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read - diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written - - quitLock sync.Mutex // Mutex protecting the quit channel access - quitChan chan chan error // Quit channel to stop the metrics collection before closing the database - - log log.Logger // Contextual logger tracking the database path + // Get retrieves the given key if it's present in the key-value data store. + Get(key []byte) ([]byte, error) } -// NewLDBDatabase returns a LevelDB wrapped object. -func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) { - logger := log.New("database", file) +// Writer wraps the Put method of a backing data store. +type Writer interface { + // Put inserts the given value into the key-value data store. + Put(key []byte, value []byte) error - // Ensure we have some minimal caching and file guarantees - if cache < 16 { - cache = 16 - } - if handles < 16 { - handles = 16 - } - logger.Info("Allocated cache and file handles", "cache", cache, "handles", handles) - - // Open the db and recover any potential corruptions - db, err := leveldb.OpenFile(file, &opt.Options{ - OpenFilesCacheCapacity: handles, - BlockCacheCapacity: cache / 2 * opt.MiB, - WriteBuffer: cache / 4 * opt.MiB, // Two of these are used internally - Filter: filter.NewBloomFilter(10), - }) - if _, corrupted := err.(*errors.ErrCorrupted); corrupted { - db, err = leveldb.RecoverFile(file, nil) - } - // (Re)check for errors and abort if opening of the db failed - if err != nil { - return nil, err - } - return &LDBDatabase{ - fn: file, - db: db, - log: logger, - }, nil + // Delete removes the key from the key-value data store. + Delete(key []byte) error } -// Path returns the path to the database directory. -func (db *LDBDatabase) Path() string { - return db.fn +// Stater wraps the Stat method of a backing data store. +type Stater interface { + // Stat returns a particular internal stat of the database. + Stat(property string) (string, error) } -// Put puts the given key / value to the queue -func (db *LDBDatabase) Put(key []byte, value []byte) error { - return db.db.Put(key, value, nil) +// Compacter wraps the Compact method of a backing data store. +type Compacter interface { + // Compact flattens the underlying data store for the given key range. In essence, + // deleted and overwritten versions are discarded, and the data is rearranged to + // reduce the cost of operations needed to access them. + // + // A nil start is treated as a key before all keys in the data store; a nil limit + // is treated as a key after all keys in the data store. If both is nil then it + // will compact entire data store. + Compact(start []byte, limit []byte) error } -func (db *LDBDatabase) Has(key []byte) (bool, error) { - return db.db.Has(key, nil) +// KeyValueStore contains all the methods required to allow handling different +// key-value data stores backing the high level database. +type KeyValueStore interface { + Reader + Writer + Batcher + Iteratee + Stater + Compacter + io.Closer } -// Get returns the given key if it's present. -func (db *LDBDatabase) Get(key []byte) ([]byte, error) { - dat, err := db.db.Get(key, nil) - if err != nil { - return nil, err - } - return dat, nil -} - -// Delete deletes the key from the queue and database -func (db *LDBDatabase) Delete(key []byte) error { - return db.db.Delete(key, nil) -} - -func (db *LDBDatabase) NewIterator() iterator.Iterator { - return db.db.NewIterator(nil, nil) -} - -// NewIteratorWithPrefix returns a iterator to iterate over subset of database content with a particular prefix. -func (db *LDBDatabase) NewIteratorWithPrefix(prefix []byte) iterator.Iterator { - return db.db.NewIterator(util.BytesPrefix(prefix), nil) -} - -func (db *LDBDatabase) Close() { - // Stop the metrics collection to avoid internal database races - db.quitLock.Lock() - defer db.quitLock.Unlock() - - if db.quitChan != nil { - errc := make(chan error) - db.quitChan <- errc - if err := <-errc; err != nil { - db.log.Error("Metrics collection failed", "err", err) - } - db.quitChan = nil - } - err := db.db.Close() - if err == nil { - db.log.Info("Database closed") - } else { - db.log.Error("Failed to close database", "err", err) - } -} - -func (db *LDBDatabase) LDB() *leveldb.DB { - return db.db -} - -// Meter configures the database metrics collectors and -func (db *LDBDatabase) Meter(prefix string) { - // Initialize all the metrics collector at the requested prefix - db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil) - db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil) - db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil) - db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil) - db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil) - db.writeDelayMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil) - db.writeDelayNMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", nil) - - // Create a quit channel for the periodic collector and run it - db.quitLock.Lock() - db.quitChan = make(chan chan error) - db.quitLock.Unlock() - - go db.meter(3 * time.Second) -} - -// meter periodically retrieves internal leveldb counters and reports them to -// the metrics subsystem. -// -// This is how a stats table look like (currently): -// Compactions -// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB) -// -------+------------+---------------+---------------+---------------+--------------- -// 0 | 0 | 0.00000 | 1.27969 | 0.00000 | 12.31098 -// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294 -// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884 -// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000 -// -// This is how the write delay look like (currently): -// DelayN:5 Delay:406.604657ms Paused: false -// -// This is how the iostats look like (currently): -// Read(MB):3895.04860 Write(MB):3654.64712 -func (db *LDBDatabase) meter(refresh time.Duration) { - // Create the counters to store current and previous compaction values - compactions := make([][]float64, 2) - for i := 0; i < 2; i++ { - compactions[i] = make([]float64, 3) - } - // Create storage for iostats. - var iostats [2]float64 - - // Create storage and warning log tracer for write delay. - var ( - delaystats [2]int64 - lastWritePaused time.Time - ) - - var ( - errc chan error - merr error - ) - - // Iterate ad infinitum and collect the stats - for i := 1; errc == nil && merr == nil; i++ { - // Retrieve the database stats - stats, err := db.db.GetProperty("leveldb.stats") - if err != nil { - db.log.Error("Failed to read database stats", "err", err) - merr = err - continue - } - // Find the compaction table, skip the header - lines := strings.Split(stats, "\n") - for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" { - lines = lines[1:] - } - if len(lines) <= 3 { - db.log.Error("Compaction table not found") - merr = errors.New("compaction table not found") - continue - } - lines = lines[3:] - - // Iterate over all the table rows, and accumulate the entries - for j := 0; j < len(compactions[i%2]); j++ { - compactions[i%2][j] = 0 - } - for _, line := range lines { - parts := strings.Split(line, "|") - if len(parts) != 6 { - break - } - for idx, counter := range parts[3:] { - value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64) - if err != nil { - db.log.Error("Compaction entry parsing failed", "err", err) - merr = err - continue - } - compactions[i%2][idx] += value - } - } - // Update all the requested meters - if db.compTimeMeter != nil { - db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000)) - } - if db.compReadMeter != nil { - db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024)) - } - if db.compWriteMeter != nil { - db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024)) - } - - // Retrieve the write delay statistic - writedelay, err := db.db.GetProperty("leveldb.writedelay") - if err != nil { - db.log.Error("Failed to read database write delay statistic", "err", err) - merr = err - continue - } - var ( - delayN int64 - delayDuration string - duration time.Duration - paused bool - ) - if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil { - db.log.Error("Write delay statistic not found") - merr = err - continue - } - duration, err = time.ParseDuration(delayDuration) - if err != nil { - db.log.Error("Failed to parse delay duration", "err", err) - merr = err - continue - } - if db.writeDelayNMeter != nil { - db.writeDelayNMeter.Mark(delayN - delaystats[0]) - } - if db.writeDelayMeter != nil { - db.writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1]) - } - // If a warning that db is performing compaction has been displayed, any subsequent - // warnings will be withheld for one minute not to overwhelm the user. - if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 && - time.Now().After(lastWritePaused.Add(writePauseWarningThrottler)) { - db.log.Warn("Database compacting, degraded performance") - lastWritePaused = time.Now() - } - delaystats[0], delaystats[1] = delayN, duration.Nanoseconds() - - // Retrieve the database iostats. - ioStats, err := db.db.GetProperty("leveldb.iostats") - if err != nil { - db.log.Error("Failed to read database iostats", "err", err) - merr = err - continue - } - var nRead, nWrite float64 - parts := strings.Split(ioStats, " ") - if len(parts) < 2 { - db.log.Error("Bad syntax of ioStats", "ioStats", ioStats) - merr = fmt.Errorf("bad syntax of ioStats %s", ioStats) - continue - } - if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil { - db.log.Error("Bad syntax of read entry", "entry", parts[0]) - merr = err - continue - } - if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil { - db.log.Error("Bad syntax of write entry", "entry", parts[1]) - merr = err - continue - } - if db.diskReadMeter != nil { - db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024)) - } - if db.diskWriteMeter != nil { - db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024)) - } - iostats[0], iostats[1] = nRead, nWrite - - // Sleep a bit, then repeat the stats collection - select { - case errc = <-db.quitChan: - // Quit requesting, stop hammering the database - case <-time.After(refresh): - // Timeout, gather a new set of stats - } - } - - if errc == nil { - errc = <-db.quitChan - } - errc <- merr -} - -func (db *LDBDatabase) NewBatch() Batch { - return &ldbBatch{db: db.db, b: new(leveldb.Batch)} -} - -type ldbBatch struct { - db *leveldb.DB - b *leveldb.Batch - size int -} - -func (b *ldbBatch) Put(key, value []byte) error { - b.b.Put(key, value) - b.size += len(value) - return nil -} - -func (b *ldbBatch) Delete(key []byte) error { - b.b.Delete(key) - b.size += 1 - return nil -} - -func (b *ldbBatch) Write() error { - return b.db.Write(b.b, nil) -} - -func (b *ldbBatch) ValueSize() int { - return b.size -} - -func (b *ldbBatch) Reset() { - b.b.Reset() - b.size = 0 +// Database contains all the methods required by the high level database to not +// only access the key-value data store but also the chain freezer. +type Database interface { + Reader + Writer + Batcher + Iteratee + Stater + Compacter + io.Closer } diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/database_js.go b/vendor/github.com/ethereum/go-ethereum/ethdb/database_js.go deleted file mode 100644 index ba6eeb5a..00000000 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/database_js.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build js - -package ethdb - -import ( - "errors" -) - -var errNotSupported = errors.New("ethdb: not supported") - -type LDBDatabase struct { -} - -// NewLDBDatabase returns a LevelDB wrapped object. -func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) { - return nil, errNotSupported -} - -// Path returns the path to the database directory. -func (db *LDBDatabase) Path() string { - return "" -} - -// Put puts the given key / value to the queue -func (db *LDBDatabase) Put(key []byte, value []byte) error { - return errNotSupported -} - -func (db *LDBDatabase) Has(key []byte) (bool, error) { - return false, errNotSupported -} - -// Get returns the given key if it's present. -func (db *LDBDatabase) Get(key []byte) ([]byte, error) { - return nil, errNotSupported -} - -// Delete deletes the key from the queue and database -func (db *LDBDatabase) Delete(key []byte) error { - return errNotSupported -} - -func (db *LDBDatabase) Close() { -} - -// Meter configures the database metrics collectors and -func (db *LDBDatabase) Meter(prefix string) { -} - -func (db *LDBDatabase) NewBatch() Batch { - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/database_test.go b/vendor/github.com/ethereum/go-ethereum/ethdb/database_test.go deleted file mode 100644 index 382fedbf..00000000 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/database_test.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !js - -package ethdb_test - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "strconv" - "sync" - "testing" - - "github.com/ethereum/go-ethereum/ethdb" -) - -func newTestLDB() (*ethdb.LDBDatabase, func()) { - dirname, err := ioutil.TempDir(os.TempDir(), "ethdb_test_") - if err != nil { - panic("failed to create test file: " + err.Error()) - } - db, err := ethdb.NewLDBDatabase(dirname, 0, 0) - if err != nil { - panic("failed to create test database: " + err.Error()) - } - - return db, func() { - db.Close() - os.RemoveAll(dirname) - } -} - -var test_values = []string{"", "a", "1251", "\x00123\x00"} - -func TestLDB_PutGet(t *testing.T) { - db, remove := newTestLDB() - defer remove() - testPutGet(db, t) -} - -func TestMemoryDB_PutGet(t *testing.T) { - testPutGet(ethdb.NewMemDatabase(), t) -} - -func testPutGet(db ethdb.Database, t *testing.T) { - t.Parallel() - - for _, k := range test_values { - err := db.Put([]byte(k), nil) - if err != nil { - t.Fatalf("put failed: %v", err) - } - } - - for _, k := range test_values { - data, err := db.Get([]byte(k)) - if err != nil { - t.Fatalf("get failed: %v", err) - } - if len(data) != 0 { - t.Fatalf("get returned wrong result, got %q expected nil", string(data)) - } - } - - _, err := db.Get([]byte("non-exist-key")) - if err == nil { - t.Fatalf("expect to return a not found error") - } - - for _, v := range test_values { - err := db.Put([]byte(v), []byte(v)) - if err != nil { - t.Fatalf("put failed: %v", err) - } - } - - for _, v := range test_values { - data, err := db.Get([]byte(v)) - if err != nil { - t.Fatalf("get failed: %v", err) - } - if !bytes.Equal(data, []byte(v)) { - t.Fatalf("get returned wrong result, got %q expected %q", string(data), v) - } - } - - for _, v := range test_values { - err := db.Put([]byte(v), []byte("?")) - if err != nil { - t.Fatalf("put override failed: %v", err) - } - } - - for _, v := range test_values { - data, err := db.Get([]byte(v)) - if err != nil { - t.Fatalf("get failed: %v", err) - } - if !bytes.Equal(data, []byte("?")) { - t.Fatalf("get returned wrong result, got %q expected ?", string(data)) - } - } - - for _, v := range test_values { - orig, err := db.Get([]byte(v)) - if err != nil { - t.Fatalf("get failed: %v", err) - } - orig[0] = byte(0xff) - data, err := db.Get([]byte(v)) - if err != nil { - t.Fatalf("get failed: %v", err) - } - if !bytes.Equal(data, []byte("?")) { - t.Fatalf("get returned wrong result, got %q expected ?", string(data)) - } - } - - for _, v := range test_values { - err := db.Delete([]byte(v)) - if err != nil { - t.Fatalf("delete %q failed: %v", v, err) - } - } - - for _, v := range test_values { - _, err := db.Get([]byte(v)) - if err == nil { - t.Fatalf("got deleted value %q", v) - } - } -} - -func TestLDB_ParallelPutGet(t *testing.T) { - db, remove := newTestLDB() - defer remove() - testParallelPutGet(db, t) -} - -func TestMemoryDB_ParallelPutGet(t *testing.T) { - testParallelPutGet(ethdb.NewMemDatabase(), t) -} - -func testParallelPutGet(db ethdb.Database, t *testing.T) { - const n = 8 - var pending sync.WaitGroup - - pending.Add(n) - for i := 0; i < n; i++ { - go func(key string) { - defer pending.Done() - err := db.Put([]byte(key), []byte("v"+key)) - if err != nil { - panic("put failed: " + err.Error()) - } - }(strconv.Itoa(i)) - } - pending.Wait() - - pending.Add(n) - for i := 0; i < n; i++ { - go func(key string) { - defer pending.Done() - data, err := db.Get([]byte(key)) - if err != nil { - panic("get failed: " + err.Error()) - } - if !bytes.Equal(data, []byte("v"+key)) { - panic(fmt.Sprintf("get failed, got %q expected %q", []byte(data), []byte("v"+key))) - } - }(strconv.Itoa(i)) - } - pending.Wait() - - pending.Add(n) - for i := 0; i < n; i++ { - go func(key string) { - defer pending.Done() - err := db.Delete([]byte(key)) - if err != nil { - panic("delete failed: " + err.Error()) - } - }(strconv.Itoa(i)) - } - pending.Wait() - - pending.Add(n) - for i := 0; i < n; i++ { - go func(key string) { - defer pending.Done() - _, err := db.Get([]byte(key)) - if err == nil { - panic("get succeeded") - } - }(strconv.Itoa(i)) - } - pending.Wait() -} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/iterator.go b/vendor/github.com/ethereum/go-ethereum/ethdb/iterator.go new file mode 100644 index 00000000..f3cee7ec --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/iterator.go @@ -0,0 +1,61 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package ethdb + +// Iterator iterates over a database's key/value pairs in ascending key order. +// +// When it encounters an error any seek will return false and will yield no key/ +// value pairs. The error can be queried by calling the Error method. Calling +// Release is still necessary. +// +// An iterator must be released after use, but it is not necessary to read an +// iterator until exhaustion. An iterator is not safe for concurrent use, but it +// is safe to use multiple iterators concurrently. +type Iterator interface { + // Next moves the iterator to the next key/value pair. It returns whether the + // iterator is exhausted. + Next() bool + + // Error returns any accumulated error. Exhausting all the key/value pairs + // is not considered to be an error. + Error() error + + // Key returns the key of the current key/value pair, or nil if done. The caller + // should not modify the contents of the returned slice, and its contents may + // change on the next call to Next. + Key() []byte + + // Value returns the value of the current key/value pair, or nil if done. The + // caller should not modify the contents of the returned slice, and its contents + // may change on the next call to Next. + Value() []byte + + // Release releases associated resources. Release should always succeed and can + // be called multiple times without causing error. + Release() +} + +// Iteratee wraps the NewIterator methods of a backing data store. +type Iteratee interface { + // NewIterator creates a binary-alphabetical iterator over the entire keyspace + // contained within the key-value database. + NewIterator() Iterator + + // NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset + // of database content with a particular key prefix. + NewIteratorWithPrefix(prefix []byte) Iterator +} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/leveldb/leveldb.go b/vendor/github.com/ethereum/go-ethereum/ethdb/leveldb/leveldb.go new file mode 100644 index 00000000..f437cb97 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/leveldb/leveldb.go @@ -0,0 +1,447 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// +build !js + +// Package leveldb implements the key-value database layer based on LevelDB. +package leveldb + +import ( + "fmt" + "strconv" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/errors" + "github.com/syndtr/goleveldb/leveldb/filter" + "github.com/syndtr/goleveldb/leveldb/opt" + "github.com/syndtr/goleveldb/leveldb/util" +) + +const ( + // degradationWarnInterval specifies how often warning should be printed if the + // leveldb database cannot keep up with requested writes. + degradationWarnInterval = time.Minute + + // minCache is the minimum amount of memory in megabytes to allocate to leveldb + // read and write caching, split half and half. + minCache = 16 + + // minHandles is the minimum number of files handles to allocate to the open + // database files. + minHandles = 16 + + // metricsGatheringInterval specifies the interval to retrieve leveldb database + // compaction, io and pause stats to report to the user. + metricsGatheringInterval = 3 * time.Second +) + +// Database is a persistent key-value store. Apart from basic data storage +// functionality it also supports batch writes and iterating over the keyspace in +// binary-alphabetical order. +type Database struct { + fn string // filename for reporting + db *leveldb.DB // LevelDB instance + + compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction + compReadMeter metrics.Meter // Meter for measuring the data read during compaction + compWriteMeter metrics.Meter // Meter for measuring the data written during compaction + writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction + writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction + diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read + diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written + + quitLock sync.Mutex // Mutex protecting the quit channel access + quitChan chan chan error // Quit channel to stop the metrics collection before closing the database + + log log.Logger // Contextual logger tracking the database path +} + +// New returns a wrapped LevelDB object. The namespace is the prefix that the +// metrics reporting should use for surfacing internal stats. +func New(file string, cache int, handles int, namespace string) (*Database, error) { + // Ensure we have some minimal caching and file guarantees + if cache < minCache { + cache = minCache + } + if handles < minHandles { + handles = minHandles + } + logger := log.New("database", file) + logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles) + + // Open the db and recover any potential corruptions + db, err := leveldb.OpenFile(file, &opt.Options{ + OpenFilesCacheCapacity: handles, + BlockCacheCapacity: cache / 2 * opt.MiB, + WriteBuffer: cache / 4 * opt.MiB, // Two of these are used internally + Filter: filter.NewBloomFilter(10), + }) + if _, corrupted := err.(*errors.ErrCorrupted); corrupted { + db, err = leveldb.RecoverFile(file, nil) + } + if err != nil { + return nil, err + } + // Assemble the wrapper with all the registered metrics + ldb := &Database{ + fn: file, + db: db, + log: logger, + quitChan: make(chan chan error), + } + ldb.compTimeMeter = metrics.NewRegisteredMeter(namespace+"compact/time", nil) + ldb.compReadMeter = metrics.NewRegisteredMeter(namespace+"compact/input", nil) + ldb.compWriteMeter = metrics.NewRegisteredMeter(namespace+"compact/output", nil) + ldb.diskReadMeter = metrics.NewRegisteredMeter(namespace+"disk/read", nil) + ldb.diskWriteMeter = metrics.NewRegisteredMeter(namespace+"disk/write", nil) + ldb.writeDelayMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/duration", nil) + ldb.writeDelayNMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/counter", nil) + + // Start up the metrics gathering and return + go ldb.meter(metricsGatheringInterval) + return ldb, nil +} + +// Close stops the metrics collection, flushes any pending data to disk and closes +// all io accesses to the underlying key-value store. +func (db *Database) Close() error { + db.quitLock.Lock() + defer db.quitLock.Unlock() + + if db.quitChan != nil { + errc := make(chan error) + db.quitChan <- errc + if err := <-errc; err != nil { + db.log.Error("Metrics collection failed", "err", err) + } + db.quitChan = nil + } + return db.db.Close() +} + +// Has retrieves if a key is present in the key-value store. +func (db *Database) Has(key []byte) (bool, error) { + return db.db.Has(key, nil) +} + +// Get retrieves the given key if it's present in the key-value store. +func (db *Database) Get(key []byte) ([]byte, error) { + dat, err := db.db.Get(key, nil) + if err != nil { + return nil, err + } + return dat, nil +} + +// Put inserts the given value into the key-value store. +func (db *Database) Put(key []byte, value []byte) error { + return db.db.Put(key, value, nil) +} + +// Delete removes the key from the key-value store. +func (db *Database) Delete(key []byte) error { + return db.db.Delete(key, nil) +} + +// NewBatch creates a write-only key-value store that buffers changes to its host +// database until a final write is called. +func (db *Database) NewBatch() ethdb.Batch { + return &batch{ + db: db.db, + b: new(leveldb.Batch), + } +} + +// NewIterator creates a binary-alphabetical iterator over the entire keyspace +// contained within the leveldb database. +func (db *Database) NewIterator() ethdb.Iterator { + return db.NewIteratorWithPrefix(nil) +} + +// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset +// of database content with a particular key prefix. +func (db *Database) NewIteratorWithPrefix(prefix []byte) ethdb.Iterator { + return db.db.NewIterator(util.BytesPrefix(prefix), nil) +} + +// Stat returns a particular internal stat of the database. +func (db *Database) Stat(property string) (string, error) { + return db.db.GetProperty(property) +} + +// Compact flattens the underlying data store for the given key range. In essence, +// deleted and overwritten versions are discarded, and the data is rearranged to +// reduce the cost of operations needed to access them. +// +// A nil start is treated as a key before all keys in the data store; a nil limit +// is treated as a key after all keys in the data store. If both is nil then it +// will compact entire data store. +func (db *Database) Compact(start []byte, limit []byte) error { + return db.db.CompactRange(util.Range{Start: start, Limit: limit}) +} + +// Path returns the path to the database directory. +func (db *Database) Path() string { + return db.fn +} + +// meter periodically retrieves internal leveldb counters and reports them to +// the metrics subsystem. +// +// This is how a LevelDB stats table looks like (currently): +// Compactions +// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB) +// -------+------------+---------------+---------------+---------------+--------------- +// 0 | 0 | 0.00000 | 1.27969 | 0.00000 | 12.31098 +// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294 +// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884 +// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000 +// +// This is how the write delay look like (currently): +// DelayN:5 Delay:406.604657ms Paused: false +// +// This is how the iostats look like (currently): +// Read(MB):3895.04860 Write(MB):3654.64712 +func (db *Database) meter(refresh time.Duration) { + // Create the counters to store current and previous compaction values + compactions := make([][]float64, 2) + for i := 0; i < 2; i++ { + compactions[i] = make([]float64, 3) + } + // Create storage for iostats. + var iostats [2]float64 + + // Create storage and warning log tracer for write delay. + var ( + delaystats [2]int64 + lastWritePaused time.Time + ) + + var ( + errc chan error + merr error + ) + + // Iterate ad infinitum and collect the stats + for i := 1; errc == nil && merr == nil; i++ { + // Retrieve the database stats + stats, err := db.db.GetProperty("leveldb.stats") + if err != nil { + db.log.Error("Failed to read database stats", "err", err) + merr = err + continue + } + // Find the compaction table, skip the header + lines := strings.Split(stats, "\n") + for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" { + lines = lines[1:] + } + if len(lines) <= 3 { + db.log.Error("Compaction leveldbTable not found") + merr = errors.New("compaction leveldbTable not found") + continue + } + lines = lines[3:] + + // Iterate over all the leveldbTable rows, and accumulate the entries + for j := 0; j < len(compactions[i%2]); j++ { + compactions[i%2][j] = 0 + } + for _, line := range lines { + parts := strings.Split(line, "|") + if len(parts) != 6 { + break + } + for idx, counter := range parts[3:] { + value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64) + if err != nil { + db.log.Error("Compaction entry parsing failed", "err", err) + merr = err + continue + } + compactions[i%2][idx] += value + } + } + // Update all the requested meters + if db.compTimeMeter != nil { + db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000)) + } + if db.compReadMeter != nil { + db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024)) + } + if db.compWriteMeter != nil { + db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024)) + } + + // Retrieve the write delay statistic + writedelay, err := db.db.GetProperty("leveldb.writedelay") + if err != nil { + db.log.Error("Failed to read database write delay statistic", "err", err) + merr = err + continue + } + var ( + delayN int64 + delayDuration string + duration time.Duration + paused bool + ) + if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil { + db.log.Error("Write delay statistic not found") + merr = err + continue + } + duration, err = time.ParseDuration(delayDuration) + if err != nil { + db.log.Error("Failed to parse delay duration", "err", err) + merr = err + continue + } + if db.writeDelayNMeter != nil { + db.writeDelayNMeter.Mark(delayN - delaystats[0]) + } + if db.writeDelayMeter != nil { + db.writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1]) + } + // If a warning that db is performing compaction has been displayed, any subsequent + // warnings will be withheld for one minute not to overwhelm the user. + if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 && + time.Now().After(lastWritePaused.Add(degradationWarnInterval)) { + db.log.Warn("Database compacting, degraded performance") + lastWritePaused = time.Now() + } + delaystats[0], delaystats[1] = delayN, duration.Nanoseconds() + + // Retrieve the database iostats. + ioStats, err := db.db.GetProperty("leveldb.iostats") + if err != nil { + db.log.Error("Failed to read database iostats", "err", err) + merr = err + continue + } + var nRead, nWrite float64 + parts := strings.Split(ioStats, " ") + if len(parts) < 2 { + db.log.Error("Bad syntax of ioStats", "ioStats", ioStats) + merr = fmt.Errorf("bad syntax of ioStats %s", ioStats) + continue + } + if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil { + db.log.Error("Bad syntax of read entry", "entry", parts[0]) + merr = err + continue + } + if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil { + db.log.Error("Bad syntax of write entry", "entry", parts[1]) + merr = err + continue + } + if db.diskReadMeter != nil { + db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024)) + } + if db.diskWriteMeter != nil { + db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024)) + } + iostats[0], iostats[1] = nRead, nWrite + + // Sleep a bit, then repeat the stats collection + select { + case errc = <-db.quitChan: + // Quit requesting, stop hammering the database + case <-time.After(refresh): + // Timeout, gather a new set of stats + } + } + + if errc == nil { + errc = <-db.quitChan + } + errc <- merr +} + +// batch is a write-only leveldb batch that commits changes to its host database +// when Write is called. A batch cannot be used concurrently. +type batch struct { + db *leveldb.DB + b *leveldb.Batch + size int +} + +// Put inserts the given value into the batch for later committing. +func (b *batch) Put(key, value []byte) error { + b.b.Put(key, value) + b.size += len(value) + return nil +} + +// Delete inserts the a key removal into the batch for later committing. +func (b *batch) Delete(key []byte) error { + b.b.Delete(key) + b.size++ + return nil +} + +// ValueSize retrieves the amount of data queued up for writing. +func (b *batch) ValueSize() int { + return b.size +} + +// Write flushes any accumulated data to disk. +func (b *batch) Write() error { + return b.db.Write(b.b, nil) +} + +// Reset resets the batch for reuse. +func (b *batch) Reset() { + b.b.Reset() + b.size = 0 +} + +// Replay replays the batch contents. +func (b *batch) Replay(w ethdb.Writer) error { + return b.b.Replay(&replayer{writer: w}) +} + +// replayer is a small wrapper to implement the correct replay methods. +type replayer struct { + writer ethdb.Writer + failure error +} + +// Put inserts the given value into the key-value data store. +func (r *replayer) Put(key, value []byte) { + // If the replay already failed, stop executing ops + if r.failure != nil { + return + } + r.failure = r.writer.Put(key, value) +} + +// Delete removes the key from the key-value data store. +func (r *replayer) Delete(key []byte) { + // If the replay already failed, stop executing ops + if r.failure != nil { + return + } + r.failure = r.writer.Delete(key) +} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/memory_database.go b/vendor/github.com/ethereum/go-ethereum/ethdb/memory_database.go deleted file mode 100644 index 727f2f7c..00000000 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/memory_database.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethdb - -import ( - "errors" - "sync" - - "github.com/ethereum/go-ethereum/common" -) - -/* - * This is a test memory database. Do not use for any production it does not get persisted - */ -type MemDatabase struct { - db map[string][]byte - lock sync.RWMutex -} - -func NewMemDatabase() *MemDatabase { - return &MemDatabase{ - db: make(map[string][]byte), - } -} - -func NewMemDatabaseWithCap(size int) *MemDatabase { - return &MemDatabase{ - db: make(map[string][]byte, size), - } -} - -func (db *MemDatabase) Put(key []byte, value []byte) error { - db.lock.Lock() - defer db.lock.Unlock() - - db.db[string(key)] = common.CopyBytes(value) - return nil -} - -func (db *MemDatabase) Has(key []byte) (bool, error) { - db.lock.RLock() - defer db.lock.RUnlock() - - _, ok := db.db[string(key)] - return ok, nil -} - -func (db *MemDatabase) Get(key []byte) ([]byte, error) { - db.lock.RLock() - defer db.lock.RUnlock() - - if entry, ok := db.db[string(key)]; ok { - return common.CopyBytes(entry), nil - } - return nil, errors.New("not found") -} - -func (db *MemDatabase) Keys() [][]byte { - db.lock.RLock() - defer db.lock.RUnlock() - - keys := [][]byte{} - for key := range db.db { - keys = append(keys, []byte(key)) - } - return keys -} - -func (db *MemDatabase) Delete(key []byte) error { - db.lock.Lock() - defer db.lock.Unlock() - - delete(db.db, string(key)) - return nil -} - -func (db *MemDatabase) Close() {} - -func (db *MemDatabase) NewBatch() Batch { - return &memBatch{db: db} -} - -func (db *MemDatabase) Len() int { return len(db.db) } - -type kv struct { - k, v []byte - del bool -} - -type memBatch struct { - db *MemDatabase - writes []kv - size int -} - -func (b *memBatch) Put(key, value []byte) error { - b.writes = append(b.writes, kv{common.CopyBytes(key), common.CopyBytes(value), false}) - b.size += len(value) - return nil -} - -func (b *memBatch) Delete(key []byte) error { - b.writes = append(b.writes, kv{common.CopyBytes(key), nil, true}) - b.size += 1 - return nil -} - -func (b *memBatch) Write() error { - b.db.lock.Lock() - defer b.db.lock.Unlock() - - for _, kv := range b.writes { - if kv.del { - delete(b.db.db, string(kv.k)) - continue - } - b.db.db[string(kv.k)] = kv.v - } - return nil -} - -func (b *memBatch) ValueSize() int { - return b.size -} - -func (b *memBatch) Reset() { - b.writes = b.writes[:0] - b.size = 0 -} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/memorydb/memorydb.go b/vendor/github.com/ethereum/go-ethereum/ethdb/memorydb/memorydb.go new file mode 100644 index 00000000..5c3f7e22 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/memorydb/memorydb.go @@ -0,0 +1,314 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package memorydb implements the key-value database layer based on memory maps. +package memorydb + +import ( + "errors" + "sort" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" +) + +var ( + // errMemorydbClosed is returned if a memory database was already closed at the + // invocation of a data access operation. + errMemorydbClosed = errors.New("database closed") + + // errMemorydbNotFound is returned if a key is requested that is not found in + // the provided memory database. + errMemorydbNotFound = errors.New("not found") +) + +// Database is an ephemeral key-value store. Apart from basic data storage +// functionality it also supports batch writes and iterating over the keyspace in +// binary-alphabetical order. +type Database struct { + db map[string][]byte + lock sync.RWMutex +} + +// New returns a wrapped map with all the required database interface methods +// implemented. +func New() *Database { + return &Database{ + db: make(map[string][]byte), + } +} + +// NewWithCap returns a wrapped map pre-allocated to the provided capcity with +// all the required database interface methods implemented. +func NewWithCap(size int) *Database { + return &Database{ + db: make(map[string][]byte, size), + } +} + +// Close deallocates the internal map and ensures any consecutive data access op +// failes with an error. +func (db *Database) Close() error { + db.lock.Lock() + defer db.lock.Unlock() + + db.db = nil + return nil +} + +// Has retrieves if a key is present in the key-value store. +func (db *Database) Has(key []byte) (bool, error) { + db.lock.RLock() + defer db.lock.RUnlock() + + if db.db == nil { + return false, errMemorydbClosed + } + _, ok := db.db[string(key)] + return ok, nil +} + +// Get retrieves the given key if it's present in the key-value store. +func (db *Database) Get(key []byte) ([]byte, error) { + db.lock.RLock() + defer db.lock.RUnlock() + + if db.db == nil { + return nil, errMemorydbClosed + } + if entry, ok := db.db[string(key)]; ok { + return common.CopyBytes(entry), nil + } + return nil, errMemorydbNotFound +} + +// Put inserts the given value into the key-value store. +func (db *Database) Put(key []byte, value []byte) error { + db.lock.Lock() + defer db.lock.Unlock() + + if db.db == nil { + return errMemorydbClosed + } + db.db[string(key)] = common.CopyBytes(value) + return nil +} + +// Delete removes the key from the key-value store. +func (db *Database) Delete(key []byte) error { + db.lock.Lock() + defer db.lock.Unlock() + + if db.db == nil { + return errMemorydbClosed + } + delete(db.db, string(key)) + return nil +} + +// NewBatch creates a write-only key-value store that buffers changes to its host +// database until a final write is called. +func (db *Database) NewBatch() ethdb.Batch { + return &batch{ + db: db, + } +} + +// NewIterator creates a binary-alphabetical iterator over the entire keyspace +// contained within the memory database. +func (db *Database) NewIterator() ethdb.Iterator { + return db.NewIteratorWithPrefix(nil) +} + +// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset +// of database content with a particular key prefix. +func (db *Database) NewIteratorWithPrefix(prefix []byte) ethdb.Iterator { + db.lock.RLock() + defer db.lock.RUnlock() + + var ( + pr = string(prefix) + keys = make([]string, 0, len(db.db)) + values = make([][]byte, 0, len(db.db)) + ) + // Collect the keys from the memory database corresponding to the given prefix + for key := range db.db { + if strings.HasPrefix(key, pr) { + keys = append(keys, key) + } + } + // Sort the items and retrieve the associated values + sort.Strings(keys) + for _, key := range keys { + values = append(values, db.db[key]) + } + return &iterator{ + keys: keys, + values: values, + } +} + +// Stat returns a particular internal stat of the database. +func (db *Database) Stat(property string) (string, error) { + return "", errors.New("unknown property") +} + +// Compact is not supported on a memory database. +func (db *Database) Compact(start []byte, limit []byte) error { + return errors.New("unsupported operation") +} + +// Len returns the number of entries currently present in the memory database. +// +// Note, this method is only used for testing (i.e. not public in general) and +// does not have explicit checks for closed-ness to allow simpler testing code. +func (db *Database) Len() int { + db.lock.RLock() + defer db.lock.RUnlock() + + return len(db.db) +} + +// keyvalue is a key-value tuple tagged with a deletion field to allow creating +// memory-database write batches. +type keyvalue struct { + key []byte + value []byte + delete bool +} + +// batch is a write-only memory batch that commits changes to its host +// database when Write is called. A batch cannot be used concurrently. +type batch struct { + db *Database + writes []keyvalue + size int +} + +// Put inserts the given value into the batch for later committing. +func (b *batch) Put(key, value []byte) error { + b.writes = append(b.writes, keyvalue{common.CopyBytes(key), common.CopyBytes(value), false}) + b.size += len(value) + return nil +} + +// Delete inserts the a key removal into the batch for later committing. +func (b *batch) Delete(key []byte) error { + b.writes = append(b.writes, keyvalue{common.CopyBytes(key), nil, true}) + b.size += 1 + return nil +} + +// ValueSize retrieves the amount of data queued up for writing. +func (b *batch) ValueSize() int { + return b.size +} + +// Write flushes any accumulated data to the memory database. +func (b *batch) Write() error { + b.db.lock.Lock() + defer b.db.lock.Unlock() + + for _, keyvalue := range b.writes { + if keyvalue.delete { + delete(b.db.db, string(keyvalue.key)) + continue + } + b.db.db[string(keyvalue.key)] = keyvalue.value + } + return nil +} + +// Reset resets the batch for reuse. +func (b *batch) Reset() { + b.writes = b.writes[:0] + b.size = 0 +} + +// Replay replays the batch contents. +func (b *batch) Replay(w ethdb.Writer) error { + for _, keyvalue := range b.writes { + if keyvalue.delete { + if err := w.Delete(keyvalue.key); err != nil { + return err + } + continue + } + if err := w.Put(keyvalue.key, keyvalue.value); err != nil { + return err + } + } + return nil +} + +// iterator can walk over the (potentially partial) keyspace of a memory key +// value store. Internally it is a deep copy of the entire iterated state, +// sorted by keys. +type iterator struct { + inited bool + keys []string + values [][]byte +} + +// Next moves the iterator to the next key/value pair. It returns whether the +// iterator is exhausted. +func (it *iterator) Next() bool { + // If the iterator was not yet initialized, do it now + if !it.inited { + it.inited = true + return len(it.keys) > 0 + } + // Iterator already initialize, advance it + if len(it.keys) > 0 { + it.keys = it.keys[1:] + it.values = it.values[1:] + } + return len(it.keys) > 0 +} + +// Error returns any accumulated error. Exhausting all the key/value pairs +// is not considered to be an error. A memory iterator cannot encounter errors. +func (it *iterator) Error() error { + return nil +} + +// Key returns the key of the current key/value pair, or nil if done. The caller +// should not modify the contents of the returned slice, and its contents may +// change on the next call to Next. +func (it *iterator) Key() []byte { + if len(it.keys) > 0 { + return []byte(it.keys[0]) + } + return nil +} + +// Value returns the value of the current key/value pair, or nil if done. The +// caller should not modify the contents of the returned slice, and its contents +// may change on the next call to Next. +func (it *iterator) Value() []byte { + if len(it.values) > 0 { + return it.values[0] + } + return nil +} + +// Release releases associated resources. Release should always succeed and can +// be called multiple times without causing error. +func (it *iterator) Release() { + it.keys, it.values = nil, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/memorydb/memorydb_test.go b/vendor/github.com/ethereum/go-ethereum/ethdb/memorydb/memorydb_test.go new file mode 100644 index 00000000..4210a0f7 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/ethdb/memorydb/memorydb_test.go @@ -0,0 +1,100 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package memorydb + +import ( + "bytes" + "testing" +) + +// Tests that key-value iteration on top of a memory database works. +func TestMemoryDBIterator(t *testing.T) { + tests := []struct { + content map[string]string + prefix string + order []string + }{ + // Empty databases should be iterable + {map[string]string{}, "", nil}, + {map[string]string{}, "non-existent-prefix", nil}, + + // Single-item databases should be iterable + {map[string]string{"key": "val"}, "", []string{"key"}}, + {map[string]string{"key": "val"}, "k", []string{"key"}}, + {map[string]string{"key": "val"}, "l", nil}, + + // Multi-item databases should be fully iterable + { + map[string]string{"k1": "v1", "k5": "v5", "k2": "v2", "k4": "v4", "k3": "v3"}, + "", + []string{"k1", "k2", "k3", "k4", "k5"}, + }, + { + map[string]string{"k1": "v1", "k5": "v5", "k2": "v2", "k4": "v4", "k3": "v3"}, + "k", + []string{"k1", "k2", "k3", "k4", "k5"}, + }, + { + map[string]string{"k1": "v1", "k5": "v5", "k2": "v2", "k4": "v4", "k3": "v3"}, + "l", + nil, + }, + // Multi-item databases should be prefix-iterable + { + map[string]string{ + "ka1": "va1", "ka5": "va5", "ka2": "va2", "ka4": "va4", "ka3": "va3", + "kb1": "vb1", "kb5": "vb5", "kb2": "vb2", "kb4": "vb4", "kb3": "vb3", + }, + "ka", + []string{"ka1", "ka2", "ka3", "ka4", "ka5"}, + }, + { + map[string]string{ + "ka1": "va1", "ka5": "va5", "ka2": "va2", "ka4": "va4", "ka3": "va3", + "kb1": "vb1", "kb5": "vb5", "kb2": "vb2", "kb4": "vb4", "kb3": "vb3", + }, + "kc", + nil, + }, + } + for i, tt := range tests { + // Create the key-value data store + db := New() + for key, val := range tt.content { + if err := db.Put([]byte(key), []byte(val)); err != nil { + t.Fatalf("test %d: failed to insert item %s:%s into database: %v", i, key, val, err) + } + } + // Iterate over the database with the given configs and verify the results + it, idx := db.NewIteratorWithPrefix([]byte(tt.prefix)), 0 + for it.Next() { + if !bytes.Equal(it.Key(), []byte(tt.order[idx])) { + t.Errorf("test %d: item %d: key mismatch: have %s, want %s", i, idx, string(it.Key()), tt.order[idx]) + } + if !bytes.Equal(it.Value(), []byte(tt.content[tt.order[idx]])) { + t.Errorf("test %d: item %d: value mismatch: have %s, want %s", i, idx, string(it.Value()), tt.content[tt.order[idx]]) + } + idx++ + } + if err := it.Error(); err != nil { + t.Errorf("test %d: iteration failed: %v", i, err) + } + if idx != len(tt.order) { + t.Errorf("test %d: iteration terminated prematurely: have %d, want %d", i, idx, len(tt.order)) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/table.go b/vendor/github.com/ethereum/go-ethereum/ethdb/table.go deleted file mode 100644 index 28069c07..00000000 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/table.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethdb - -type table struct { - db Database - prefix string -} - -// NewTable returns a Database object that prefixes all keys with a given -// string. -func NewTable(db Database, prefix string) Database { - return &table{ - db: db, - prefix: prefix, - } -} - -func (dt *table) Put(key []byte, value []byte) error { - return dt.db.Put(append([]byte(dt.prefix), key...), value) -} - -func (dt *table) Has(key []byte) (bool, error) { - return dt.db.Has(append([]byte(dt.prefix), key...)) -} - -func (dt *table) Get(key []byte) ([]byte, error) { - return dt.db.Get(append([]byte(dt.prefix), key...)) -} - -func (dt *table) Delete(key []byte) error { - return dt.db.Delete(append([]byte(dt.prefix), key...)) -} - -func (dt *table) Close() { - // Do nothing; don't close the underlying DB. -} diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/table_batch.go b/vendor/github.com/ethereum/go-ethereum/ethdb/table_batch.go deleted file mode 100644 index ae83e79c..00000000 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/table_batch.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethdb - -type tableBatch struct { - batch Batch - prefix string -} - -// NewTableBatch returns a Batch object which prefixes all keys with a given string. -func NewTableBatch(db Database, prefix string) Batch { - return &tableBatch{db.NewBatch(), prefix} -} - -func (dt *table) NewBatch() Batch { - return &tableBatch{dt.db.NewBatch(), dt.prefix} -} - -func (tb *tableBatch) Put(key, value []byte) error { - return tb.batch.Put(append([]byte(tb.prefix), key...), value) -} - -func (tb *tableBatch) Delete(key []byte) error { - return tb.batch.Delete(append([]byte(tb.prefix), key...)) -} - -func (tb *tableBatch) Write() error { - return tb.batch.Write() -} - -func (tb *tableBatch) ValueSize() int { - return tb.batch.ValueSize() -} - -func (tb *tableBatch) Reset() { - tb.batch.Reset() -} diff --git a/vendor/github.com/ethereum/go-ethereum/graphql/graphiql.go b/vendor/github.com/ethereum/go-ethereum/graphql/graphiql.go new file mode 100644 index 00000000..6d9dda3e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/graphql/graphiql.go @@ -0,0 +1,95 @@ +// The MIT License (MIT) +// +// Copyright (c) 2016 Muhammed Thanish +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package graphql + +import ( + "bytes" + "fmt" + "net/http" +) + +// GraphiQL is an in-browser IDE for exploring GraphiQL APIs. +// This handler returns GraphiQL when requested. +// +// For more information, see https://github.com/graphql/graphiql. +type GraphiQL struct{} + +func respond(w http.ResponseWriter, body []byte, code int) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(code) + _, _ = w.Write(body) +} + +func errorJSON(msg string) []byte { + buf := bytes.Buffer{} + fmt.Fprintf(&buf, `{"error": "%s"}`, msg) + return buf.Bytes() +} + +func (h GraphiQL) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + respond(w, errorJSON("only GET requests are supported"), http.StatusMethodNotAllowed) + return + } + + w.Write(graphiql) +} + +var graphiql = []byte(` + + + + + + + + + + +
Loading...
+ + + +`) diff --git a/vendor/github.com/ethereum/go-ethereum/graphql/graphql.go b/vendor/github.com/ethereum/go-ethereum/graphql/graphql.go new file mode 100644 index 00000000..b16f93e4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/graphql/graphql.go @@ -0,0 +1,1233 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package graphql provides a GraphQL interface to Ethereum node data. +package graphql + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" + graphqlgo "github.com/graph-gophers/graphql-go" + "github.com/graph-gophers/graphql-go/relay" +) + +var OnlyOnMainChainError = errors.New("This operation is only available for blocks on the canonical chain.") +var BlockInvariantError = errors.New("Block objects must be instantiated with at least one of num or hash.") + +// Account represents an Ethereum account at a particular block. +type Account struct { + backend *eth.EthAPIBackend + address common.Address + blockNumber rpc.BlockNumber +} + +// getState fetches the StateDB object for an account. +func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { + state, _, err := a.backend.StateAndHeaderByNumber(ctx, a.blockNumber) + return state, err +} + +func (a *Account) Address(ctx context.Context) (common.Address, error) { + return a.address, nil +} + +func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) { + state, err := a.getState(ctx) + if err != nil { + return hexutil.Big{}, err + } + + return hexutil.Big(*state.GetBalance(a.address)), nil +} + +func (a *Account) TransactionCount(ctx context.Context) (hexutil.Uint64, error) { + state, err := a.getState(ctx) + if err != nil { + return 0, err + } + + return hexutil.Uint64(state.GetNonce(a.address)), nil +} + +func (a *Account) Code(ctx context.Context) (hexutil.Bytes, error) { + state, err := a.getState(ctx) + if err != nil { + return hexutil.Bytes{}, err + } + + return hexutil.Bytes(state.GetCode(a.address)), nil +} + +func (a *Account) Storage(ctx context.Context, args struct{ Slot common.Hash }) (common.Hash, error) { + state, err := a.getState(ctx) + if err != nil { + return common.Hash{}, err + } + + return state.GetState(a.address, args.Slot), nil +} + +// Log represents an individual log message. All arguments are mandatory. +type Log struct { + backend *eth.EthAPIBackend + transaction *Transaction + log *types.Log +} + +func (l *Log) Transaction(ctx context.Context) *Transaction { + return l.transaction +} + +func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account { + return &Account{ + backend: l.backend, + address: l.log.Address, + blockNumber: args.Number(), + } +} + +func (l *Log) Index(ctx context.Context) int32 { + return int32(l.log.Index) +} + +func (l *Log) Topics(ctx context.Context) []common.Hash { + return l.log.Topics +} + +func (l *Log) Data(ctx context.Context) hexutil.Bytes { + return hexutil.Bytes(l.log.Data) +} + +// Transaction represents an Ethereum transaction. +// backend and hash are mandatory; all others will be fetched when required. +type Transaction struct { + backend *eth.EthAPIBackend + hash common.Hash + tx *types.Transaction + block *Block + index uint64 +} + +// resolve returns the internal transaction object, fetching it if needed. +func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) { + if t.tx == nil { + tx, blockHash, _, index := rawdb.ReadTransaction(t.backend.ChainDb(), t.hash) + if tx != nil { + t.tx = tx + t.block = &Block{ + backend: t.backend, + hash: blockHash, + canonical: unknown, + } + t.index = index + } else { + t.tx = t.backend.GetPoolTransaction(t.hash) + } + } + return t.tx, nil +} + +func (tx *Transaction) Hash(ctx context.Context) common.Hash { + return tx.hash +} + +func (t *Transaction) InputData(ctx context.Context) (hexutil.Bytes, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return hexutil.Bytes{}, err + } + return hexutil.Bytes(tx.Data()), nil +} + +func (t *Transaction) Gas(ctx context.Context) (hexutil.Uint64, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return 0, err + } + return hexutil.Uint64(tx.Gas()), nil +} + +func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return hexutil.Big{}, err + } + return hexutil.Big(*tx.GasPrice()), nil +} + +func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return hexutil.Big{}, err + } + return hexutil.Big(*tx.Value()), nil +} + +func (t *Transaction) Nonce(ctx context.Context) (hexutil.Uint64, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return 0, err + } + return hexutil.Uint64(tx.Nonce()), nil +} + +func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return nil, err + } + + to := tx.To() + if to == nil { + return nil, nil + } + + return &Account{ + backend: t.backend, + address: *to, + blockNumber: args.Number(), + }, nil +} + +func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, error) { + tx, err := t.resolve(ctx) + if err != nil || tx == nil { + return nil, err + } + + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + from, _ := types.Sender(signer, tx) + + return &Account{ + backend: t.backend, + address: from, + blockNumber: args.Number(), + }, nil +} + +func (t *Transaction) Block(ctx context.Context) (*Block, error) { + if _, err := t.resolve(ctx); err != nil { + return nil, err + } + return t.block, nil +} + +func (t *Transaction) Index(ctx context.Context) (*int32, error) { + if _, err := t.resolve(ctx); err != nil { + return nil, err + } + if t.block == nil { + return nil, nil + } + index := int32(t.index) + return &index, nil +} + +// getReceipt returns the receipt associated with this transaction, if any. +func (t *Transaction) getReceipt(ctx context.Context) (*types.Receipt, error) { + if _, err := t.resolve(ctx); err != nil { + return nil, err + } + + if t.block == nil { + return nil, nil + } + + receipts, err := t.block.resolveReceipts(ctx) + if err != nil { + return nil, err + } + + return receipts[t.index], nil +} + +func (t *Transaction) Status(ctx context.Context) (*hexutil.Uint64, error) { + receipt, err := t.getReceipt(ctx) + if err != nil || receipt == nil { + return nil, err + } + + ret := hexutil.Uint64(receipt.Status) + return &ret, nil +} + +func (t *Transaction) GasUsed(ctx context.Context) (*hexutil.Uint64, error) { + receipt, err := t.getReceipt(ctx) + if err != nil || receipt == nil { + return nil, err + } + + ret := hexutil.Uint64(receipt.GasUsed) + return &ret, nil +} + +func (t *Transaction) CumulativeGasUsed(ctx context.Context) (*hexutil.Uint64, error) { + receipt, err := t.getReceipt(ctx) + if err != nil || receipt == nil { + return nil, err + } + + ret := hexutil.Uint64(receipt.CumulativeGasUsed) + return &ret, nil +} + +func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) (*Account, error) { + receipt, err := t.getReceipt(ctx) + if err != nil || receipt == nil || receipt.ContractAddress == (common.Address{}) { + return nil, err + } + + return &Account{ + backend: t.backend, + address: receipt.ContractAddress, + blockNumber: args.Number(), + }, nil +} + +func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) { + receipt, err := t.getReceipt(ctx) + if err != nil || receipt == nil { + return nil, err + } + + ret := make([]*Log, 0, len(receipt.Logs)) + for _, log := range receipt.Logs { + ret = append(ret, &Log{ + backend: t.backend, + transaction: t, + log: log, + }) + } + return &ret, nil +} + +type BlockType int + +const ( + unknown BlockType = iota + isCanonical + notCanonical +) + +// Block represents an Ethereum block. +// backend, and either num or hash are mandatory. All other fields are lazily fetched +// when required. +type Block struct { + backend *eth.EthAPIBackend + num *rpc.BlockNumber + hash common.Hash + header *types.Header + block *types.Block + receipts []*types.Receipt + canonical BlockType // Indicates if this block is on the main chain or not. +} + +func (b *Block) onMainChain(ctx context.Context) error { + if b.canonical == unknown { + header, err := b.resolveHeader(ctx) + if err != nil { + return err + } + canonHeader, err := b.backend.HeaderByNumber(ctx, rpc.BlockNumber(header.Number.Uint64())) + if err != nil { + return err + } + if header.Hash() == canonHeader.Hash() { + b.canonical = isCanonical + } else { + b.canonical = notCanonical + } + } + if b.canonical != isCanonical { + return OnlyOnMainChainError + } + return nil +} + +// resolve returns the internal Block object representing this block, fetching +// it if necessary. +func (b *Block) resolve(ctx context.Context) (*types.Block, error) { + if b.block != nil { + return b.block, nil + } + + var err error + if b.hash != (common.Hash{}) { + b.block, err = b.backend.GetBlock(ctx, b.hash) + } else { + b.block, err = b.backend.BlockByNumber(ctx, *b.num) + } + if b.block != nil { + b.header = b.block.Header() + } + return b.block, err +} + +// resolveHeader returns the internal Header object for this block, fetching it +// if necessary. Call this function instead of `resolve` unless you need the +// additional data (transactions and uncles). +func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) { + if b.num == nil && b.hash == (common.Hash{}) { + return nil, BlockInvariantError + } + + if b.header == nil { + if _, err := b.resolve(ctx); err != nil { + return nil, err + } + } + return b.header, nil +} + +// resolveReceipts returns the list of receipts for this block, fetching them +// if necessary. +func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) { + if b.receipts == nil { + hash := b.hash + if hash == (common.Hash{}) { + header, err := b.resolveHeader(ctx) + if err != nil { + return nil, err + } + hash = header.Hash() + } + + receipts, err := b.backend.GetReceipts(ctx, hash) + if err != nil { + return nil, err + } + b.receipts = []*types.Receipt(receipts) + } + return b.receipts, nil +} + +func (b *Block) Number(ctx context.Context) (hexutil.Uint64, error) { + if b.num == nil || *b.num == rpc.LatestBlockNumber { + header, err := b.resolveHeader(ctx) + if err != nil { + return 0, err + } + num := rpc.BlockNumber(header.Number.Uint64()) + b.num = &num + } + return hexutil.Uint64(*b.num), nil +} + +func (b *Block) Hash(ctx context.Context) (common.Hash, error) { + if b.hash == (common.Hash{}) { + header, err := b.resolveHeader(ctx) + if err != nil { + return common.Hash{}, err + } + b.hash = header.Hash() + } + return b.hash, nil +} + +func (b *Block) GasLimit(ctx context.Context) (hexutil.Uint64, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return 0, err + } + return hexutil.Uint64(header.GasLimit), nil +} + +func (b *Block) GasUsed(ctx context.Context) (hexutil.Uint64, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return 0, err + } + return hexutil.Uint64(header.GasUsed), nil +} + +func (b *Block) Parent(ctx context.Context) (*Block, error) { + // If the block hasn't been fetched, and we'll need it, fetch it. + if b.num == nil && b.hash != (common.Hash{}) && b.header == nil { + if _, err := b.resolve(ctx); err != nil { + return nil, err + } + } + + if b.header != nil && b.block.NumberU64() > 0 { + num := rpc.BlockNumber(b.header.Number.Uint64() - 1) + return &Block{ + backend: b.backend, + num: &num, + hash: b.header.ParentHash, + canonical: unknown, + }, nil + } + if b.num != nil && *b.num != 0 { + num := *b.num - 1 + return &Block{ + backend: b.backend, + num: &num, + canonical: isCanonical, + }, nil + } + return nil, nil +} + +func (b *Block) Difficulty(ctx context.Context) (hexutil.Big, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Big{}, err + } + return hexutil.Big(*header.Difficulty), nil +} + +func (b *Block) Timestamp(ctx context.Context) (hexutil.Big, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Big{}, err + } + return hexutil.Big(*header.Time), nil +} + +func (b *Block) Nonce(ctx context.Context) (hexutil.Bytes, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Bytes{}, err + } + return hexutil.Bytes(header.Nonce[:]), nil +} + +func (b *Block) MixHash(ctx context.Context) (common.Hash, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return common.Hash{}, err + } + return header.MixDigest, nil +} + +func (b *Block) TransactionsRoot(ctx context.Context) (common.Hash, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return common.Hash{}, err + } + return header.TxHash, nil +} + +func (b *Block) StateRoot(ctx context.Context) (common.Hash, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return common.Hash{}, err + } + return header.Root, nil +} + +func (b *Block) ReceiptsRoot(ctx context.Context) (common.Hash, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return common.Hash{}, err + } + return header.ReceiptHash, nil +} + +func (b *Block) OmmerHash(ctx context.Context) (common.Hash, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return common.Hash{}, err + } + return header.UncleHash, nil +} + +func (b *Block) OmmerCount(ctx context.Context) (*int32, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + count := int32(len(block.Uncles())) + return &count, err +} + +func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + + ret := make([]*Block, 0, len(block.Uncles())) + for _, uncle := range block.Uncles() { + blockNumber := rpc.BlockNumber(uncle.Number.Uint64()) + ret = append(ret, &Block{ + backend: b.backend, + num: &blockNumber, + hash: uncle.Hash(), + header: uncle, + canonical: notCanonical, + }) + } + return &ret, nil +} + +func (b *Block) ExtraData(ctx context.Context) (hexutil.Bytes, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Bytes{}, err + } + return hexutil.Bytes(header.Extra), nil +} + +func (b *Block) LogsBloom(ctx context.Context) (hexutil.Bytes, error) { + header, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Bytes{}, err + } + return hexutil.Bytes(header.Bloom.Bytes()), nil +} + +func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) { + h := b.hash + if h == (common.Hash{}) { + header, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Big{}, err + } + h = header.Hash() + } + + return hexutil.Big(*b.backend.GetTd(h)), nil +} + +// BlockNumberArgs encapsulates arguments to accessors that specify a block number. +type BlockNumberArgs struct { + Block *hexutil.Uint64 +} + +// Number returns the provided block number, or rpc.LatestBlockNumber if none +// was provided. +func (a BlockNumberArgs) Number() rpc.BlockNumber { + if a.Block != nil { + return rpc.BlockNumber(*a.Block) + } + return rpc.LatestBlockNumber +} + +func (b *Block) Miner(ctx context.Context, args BlockNumberArgs) (*Account, error) { + block, err := b.resolve(ctx) + if err != nil { + return nil, err + } + + return &Account{ + backend: b.backend, + address: block.Coinbase(), + blockNumber: args.Number(), + }, nil +} + +func (b *Block) TransactionCount(ctx context.Context) (*int32, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + count := int32(len(block.Transactions())) + return &count, err +} + +func (b *Block) Transactions(ctx context.Context) (*[]*Transaction, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + + ret := make([]*Transaction, 0, len(block.Transactions())) + for i, tx := range block.Transactions() { + ret = append(ret, &Transaction{ + backend: b.backend, + hash: tx.Hash(), + tx: tx, + block: b, + index: uint64(i), + }) + } + return &ret, nil +} + +func (b *Block) TransactionAt(ctx context.Context, args struct{ Index int32 }) (*Transaction, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + + txes := block.Transactions() + if args.Index < 0 || int(args.Index) >= len(txes) { + return nil, nil + } + + tx := txes[args.Index] + return &Transaction{ + backend: b.backend, + hash: tx.Hash(), + tx: tx, + block: b, + index: uint64(args.Index), + }, nil +} + +func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block, error) { + block, err := b.resolve(ctx) + if err != nil || block == nil { + return nil, err + } + + uncles := block.Uncles() + if args.Index < 0 || int(args.Index) >= len(uncles) { + return nil, nil + } + + uncle := uncles[args.Index] + blockNumber := rpc.BlockNumber(uncle.Number.Uint64()) + return &Block{ + backend: b.backend, + num: &blockNumber, + hash: uncle.Hash(), + header: uncle, + canonical: notCanonical, + }, nil +} + +// BlockFilterCriteria encapsulates criteria passed to a `logs` accessor inside +// a block. +type BlockFilterCriteria struct { + Addresses *[]common.Address // restricts matches to events created by specific contracts + + // The Topic list restricts matches to particular event topics. Each event has a list + // of topics. Topics matches a prefix of that list. An empty element slice matches any + // topic. Non-empty elements represent an alternative that matches any of the + // contained topics. + // + // Examples: + // {} or nil matches any topic list + // {{A}} matches topic A in first position + // {{}, {B}} matches any topic in first position, B in second position + // {{A}, {B}} matches topic A in first position, B in second position + // {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position + Topics *[][]common.Hash +} + +// runFilter accepts a filter and executes it, returning all its results as +// `Log` objects. +func runFilter(ctx context.Context, be *eth.EthAPIBackend, filter *filters.Filter) ([]*Log, error) { + logs, err := filter.Logs(ctx) + if err != nil || logs == nil { + return nil, err + } + + ret := make([]*Log, 0, len(logs)) + for _, log := range logs { + ret = append(ret, &Log{ + backend: be, + transaction: &Transaction{backend: be, hash: log.TxHash}, + log: log, + }) + } + return ret, nil +} + +func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteria }) ([]*Log, error) { + var addresses []common.Address + if args.Filter.Addresses != nil { + addresses = *args.Filter.Addresses + } + + var topics [][]common.Hash + if args.Filter.Topics != nil { + topics = *args.Filter.Topics + } + + hash := b.hash + if hash == (common.Hash{}) { + block, err := b.resolve(ctx) + if err != nil { + return nil, err + } + hash = block.Hash() + } + + // Construct the range filter + filter := filters.NewBlockFilter(b.backend, hash, addresses, topics) + + // Run the filter and return all the logs + return runFilter(ctx, b.backend, filter) +} + +func (b *Block) Account(ctx context.Context, args struct { + Address common.Address +}) (*Account, error) { + err := b.onMainChain(ctx) + if err != nil { + return nil, err + } + + if b.num == nil { + _, err := b.resolveHeader(ctx) + if err != nil { + return nil, err + } + } + + return &Account{ + backend: b.backend, + address: args.Address, + blockNumber: *b.num, + }, nil +} + +// CallData encapsulates arguments to `call` or `estimateGas`. +// All arguments are optional. +type CallData struct { + From *common.Address // The Ethereum address the call is from. + To *common.Address // The Ethereum address the call is to. + Gas *hexutil.Uint64 // The amount of gas provided for the call. + GasPrice *hexutil.Big // The price of each unit of gas, in wei. + Value *hexutil.Big // The value sent along with the call. + Data *hexutil.Bytes // Any data sent with the call. +} + +// CallResult encapsulates the result of an invocation of the `call` accessor. +type CallResult struct { + data hexutil.Bytes // The return data from the call + gasUsed hexutil.Uint64 // The amount of gas used + status hexutil.Uint64 // The return status of the call - 0 for failure or 1 for success. +} + +func (c *CallResult) Data() hexutil.Bytes { + return c.data +} + +func (c *CallResult) GasUsed() hexutil.Uint64 { + return c.gasUsed +} + +func (c *CallResult) Status() hexutil.Uint64 { + return c.status +} + +func (b *Block) Call(ctx context.Context, args struct { + Data ethapi.CallArgs +}) (*CallResult, error) { + err := b.onMainChain(ctx) + if err != nil { + return nil, err + } + + if b.num == nil { + _, err := b.resolveHeader(ctx) + if err != nil { + return nil, err + } + } + + result, gas, failed, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.num, vm.Config{}, 5*time.Second) + status := hexutil.Uint64(1) + if failed { + status = 0 + } + return &CallResult{ + data: hexutil.Bytes(result), + gasUsed: hexutil.Uint64(gas), + status: status, + }, err +} + +func (b *Block) EstimateGas(ctx context.Context, args struct { + Data ethapi.CallArgs +}) (hexutil.Uint64, error) { + err := b.onMainChain(ctx) + if err != nil { + return hexutil.Uint64(0), err + } + + if b.num == nil { + _, err := b.resolveHeader(ctx) + if err != nil { + return hexutil.Uint64(0), err + } + } + + gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.num) + return gas, err +} + +type Pending struct { + backend *eth.EthAPIBackend +} + +func (p *Pending) TransactionCount(ctx context.Context) (int32, error) { + txs, err := p.backend.GetPoolTransactions() + return int32(len(txs)), err +} + +func (p *Pending) Transactions(ctx context.Context) (*[]*Transaction, error) { + txs, err := p.backend.GetPoolTransactions() + if err != nil { + return nil, err + } + + ret := make([]*Transaction, 0, len(txs)) + for i, tx := range txs { + ret = append(ret, &Transaction{ + backend: p.backend, + hash: tx.Hash(), + tx: tx, + index: uint64(i), + }) + } + return &ret, nil +} + +func (p *Pending) Account(ctx context.Context, args struct { + Address common.Address +}) *Account { + return &Account{ + backend: p.backend, + address: args.Address, + blockNumber: rpc.PendingBlockNumber, + } +} + +func (p *Pending) Call(ctx context.Context, args struct { + Data ethapi.CallArgs +}) (*CallResult, error) { + result, gas, failed, err := ethapi.DoCall(ctx, p.backend, args.Data, rpc.PendingBlockNumber, vm.Config{}, 5*time.Second) + status := hexutil.Uint64(1) + if failed { + status = 0 + } + return &CallResult{ + data: hexutil.Bytes(result), + gasUsed: hexutil.Uint64(gas), + status: status, + }, err +} + +func (p *Pending) EstimateGas(ctx context.Context, args struct { + Data ethapi.CallArgs +}) (hexutil.Uint64, error) { + return ethapi.DoEstimateGas(ctx, p.backend, args.Data, rpc.PendingBlockNumber) +} + +// Resolver is the top-level object in the GraphQL hierarchy. +type Resolver struct { + backend *eth.EthAPIBackend +} + +func (r *Resolver) Block(ctx context.Context, args struct { + Number *hexutil.Uint64 + Hash *common.Hash +}) (*Block, error) { + var block *Block + if args.Number != nil { + num := rpc.BlockNumber(uint64(*args.Number)) + block = &Block{ + backend: r.backend, + num: &num, + canonical: isCanonical, + } + } else if args.Hash != nil { + block = &Block{ + backend: r.backend, + hash: *args.Hash, + canonical: unknown, + } + } else { + num := rpc.LatestBlockNumber + block = &Block{ + backend: r.backend, + num: &num, + canonical: isCanonical, + } + } + + // Resolve the block; if it doesn't exist, return nil. + b, err := block.resolve(ctx) + if err != nil { + return nil, err + } else if b == nil { + return nil, nil + } + return block, nil +} + +func (r *Resolver) Blocks(ctx context.Context, args struct { + From hexutil.Uint64 + To *hexutil.Uint64 +}) ([]*Block, error) { + from := rpc.BlockNumber(args.From) + + var to rpc.BlockNumber + if args.To != nil { + to = rpc.BlockNumber(*args.To) + } else { + to = rpc.BlockNumber(r.backend.CurrentBlock().Number().Int64()) + } + + if to < from { + return []*Block{}, nil + } + + ret := make([]*Block, 0, to-from+1) + for i := from; i <= to; i++ { + num := i + ret = append(ret, &Block{ + backend: r.backend, + num: &num, + canonical: isCanonical, + }) + } + return ret, nil +} + +func (r *Resolver) Pending(ctx context.Context) *Pending { + return &Pending{r.backend} +} + +func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) (*Transaction, error) { + tx := &Transaction{ + backend: r.backend, + hash: args.Hash, + } + + // Resolve the transaction; if it doesn't exist, return nil. + t, err := tx.resolve(ctx) + if err != nil { + return nil, err + } else if t == nil { + return nil, nil + } + return tx, nil +} + +func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hexutil.Bytes }) (common.Hash, error) { + tx := new(types.Transaction) + if err := rlp.DecodeBytes(args.Data, tx); err != nil { + return common.Hash{}, err + } + hash, err := ethapi.SubmitTransaction(ctx, r.backend, tx) + return hash, err +} + +// FilterCriteria encapsulates the arguments to `logs` on the root resolver object. +type FilterCriteria struct { + FromBlock *hexutil.Uint64 // beginning of the queried range, nil means genesis block + ToBlock *hexutil.Uint64 // end of the range, nil means latest block + Addresses *[]common.Address // restricts matches to events created by specific contracts + + // The Topic list restricts matches to particular event topics. Each event has a list + // of topics. Topics matches a prefix of that list. An empty element slice matches any + // topic. Non-empty elements represent an alternative that matches any of the + // contained topics. + // + // Examples: + // {} or nil matches any topic list + // {{A}} matches topic A in first position + // {{}, {B}} matches any topic in first position, B in second position + // {{A}, {B}} matches topic A in first position, B in second position + // {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position + Topics *[][]common.Hash +} + +func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria }) ([]*Log, error) { + // Convert the RPC block numbers into internal representations + begin := rpc.LatestBlockNumber.Int64() + if args.Filter.FromBlock != nil { + begin = int64(*args.Filter.FromBlock) + } + end := rpc.LatestBlockNumber.Int64() + if args.Filter.ToBlock != nil { + end = int64(*args.Filter.ToBlock) + } + + var addresses []common.Address + if args.Filter.Addresses != nil { + addresses = *args.Filter.Addresses + } + + var topics [][]common.Hash + if args.Filter.Topics != nil { + topics = *args.Filter.Topics + } + + // Construct the range filter + filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics) + + return runFilter(ctx, r.backend, filter) +} + +func (r *Resolver) GasPrice(ctx context.Context) (hexutil.Big, error) { + price, err := r.backend.SuggestPrice(ctx) + return hexutil.Big(*price), err +} + +func (r *Resolver) ProtocolVersion(ctx context.Context) (int32, error) { + return int32(r.backend.ProtocolVersion()), nil +} + +// SyncState represents the synchronisation status returned from the `syncing` accessor. +type SyncState struct { + progress ethereum.SyncProgress +} + +func (s *SyncState) StartingBlock() hexutil.Uint64 { + return hexutil.Uint64(s.progress.StartingBlock) +} + +func (s *SyncState) CurrentBlock() hexutil.Uint64 { + return hexutil.Uint64(s.progress.CurrentBlock) +} + +func (s *SyncState) HighestBlock() hexutil.Uint64 { + return hexutil.Uint64(s.progress.HighestBlock) +} + +func (s *SyncState) PulledStates() *hexutil.Uint64 { + ret := hexutil.Uint64(s.progress.PulledStates) + return &ret +} + +func (s *SyncState) KnownStates() *hexutil.Uint64 { + ret := hexutil.Uint64(s.progress.KnownStates) + return &ret +} + +// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not +// yet received the latest block headers from its pears. In case it is synchronizing: +// - startingBlock: block number this node started to synchronise from +// - currentBlock: block number this node is currently importing +// - highestBlock: block number of the highest block header this node has received from peers +// - pulledStates: number of state entries processed until now +// - knownStates: number of known state entries that still need to be pulled +func (r *Resolver) Syncing() (*SyncState, error) { + progress := r.backend.Downloader().Progress() + + // Return not syncing if the synchronisation already completed + if progress.CurrentBlock >= progress.HighestBlock { + return nil, nil + } + // Otherwise gather the block sync stats + return &SyncState{progress}, nil +} + +// NewHandler returns a new `http.Handler` that will answer GraphQL queries. +// It additionally exports an interactive query browser on the / endpoint. +func NewHandler(be *eth.EthAPIBackend) (http.Handler, error) { + q := Resolver{be} + + s, err := graphqlgo.ParseSchema(schema, &q) + if err != nil { + return nil, err + } + h := &relay.Handler{Schema: s} + + mux := http.NewServeMux() + mux.Handle("/", GraphiQL{}) + mux.Handle("/graphql", h) + mux.Handle("/graphql/", h) + return mux, nil +} + +// Service encapsulates a GraphQL service. +type Service struct { + endpoint string // The host:port endpoint for this service. + cors []string // Allowed CORS domains + vhosts []string // Recognised vhosts + timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests. + backend *eth.EthAPIBackend // The backend that queries will operate onn. + handler http.Handler // The `http.Handler` used to answer queries. + listener net.Listener // The listening socket. +} + +// Protocols returns the list of protocols exported by this service. +func (s *Service) Protocols() []p2p.Protocol { return nil } + +// APIs returns the list of APIs exported by this service. +func (s *Service) APIs() []rpc.API { return nil } + +// Start is called after all services have been constructed and the networking +// layer was also initialized to spawn any goroutines required by the service. +func (s *Service) Start(server *p2p.Server) error { + var err error + s.handler, err = NewHandler(s.backend) + if err != nil { + return err + } + + if s.listener, err = net.Listen("tcp", s.endpoint); err != nil { + return err + } + + go rpc.NewHTTPServer(s.cors, s.vhosts, s.timeouts, s.handler).Serve(s.listener) + log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.endpoint)) + return nil +} + +// Stop terminates all goroutines belonging to the service, blocking until they +// are all terminated. +func (s *Service) Stop() error { + if s.listener != nil { + s.listener.Close() + s.listener = nil + log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.endpoint)) + } + return nil +} + +// NewService constructs a new service instance. +func NewService(backend *eth.EthAPIBackend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) { + return &Service{ + endpoint: endpoint, + cors: cors, + vhosts: vhosts, + timeouts: timeouts, + backend: backend, + }, nil +} + +// RegisterGraphQLService is a utility function to construct a new service and register it against a node. +func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error { + return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + var ethereum *eth.Ethereum + if err := ctx.Service(ðereum); err != nil { + return nil, err + } + return NewService(ethereum.APIBackend, endpoint, cors, vhosts, timeouts) + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/state.go b/vendor/github.com/ethereum/go-ethereum/graphql/graphql_test.go similarity index 75% rename from vendor/github.com/ethereum/go-ethereum/swarm/state.go rename to vendor/github.com/ethereum/go-ethereum/graphql/graphql_test.go index 1984ab03..d6341839 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/state.go +++ b/vendor/github.com/ethereum/go-ethereum/graphql/graphql_test.go @@ -14,15 +14,16 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package swarm +package graphql -type Voidstore struct { -} +import ( + "testing" +) -func (self Voidstore) Load(string) ([]byte, error) { - return nil, nil -} - -func (self Voidstore) Save(string, []byte) error { - return nil +func TestBuildSchema(t *testing.T) { + // Make sure the schema can be parsed and matched up to the object model. + _, err := NewHandler(nil) + if err != nil { + t.Errorf("Could not construct GraphQL handler: %v", err) + } } diff --git a/vendor/github.com/ethereum/go-ethereum/graphql/schema.go b/vendor/github.com/ethereum/go-ethereum/graphql/schema.go new file mode 100644 index 00000000..e266e429 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/graphql/schema.go @@ -0,0 +1,320 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package graphql + +const schema string = ` + # Bytes32 is a 32 byte binary string, represented as 0x-prefixed hexadecimal. + scalar Bytes32 + # Address is a 20 byte Ethereum address, represented as 0x-prefixed hexadecimal. + scalar Address + # Bytes is an arbitrary length binary string, represented as 0x-prefixed hexadecimal. + # An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nybbles. + scalar Bytes + # BigInt is a large integer. Input is accepted as either a JSON number or as a string. + # Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all + # 0x-prefixed hexadecimal. + scalar BigInt + # Long is a 64 bit unsigned integer. + scalar Long + + schema { + query: Query + mutation: Mutation + } + + # Account is an Ethereum account at a particular block. + type Account { + # Address is the address owning the account. + address: Address! + # Balance is the balance of the account, in wei. + balance: BigInt! + # TransactionCount is the number of transactions sent from this account, + # or in the case of a contract, the number of contracts created. Otherwise + # known as the nonce. + transactionCount: Long! + # Code contains the smart contract code for this account, if the account + # is a (non-self-destructed) contract. + code: Bytes! + # Storage provides access to the storage of a contract account, indexed + # by its 32 byte slot identifier. + storage(slot: Bytes32!): Bytes32! + } + + # Log is an Ethereum event log. + type Log { + # Index is the index of this log in the block. + index: Int! + # Account is the account which generated this log - this will always + # be a contract account. + account(block: Long): Account! + # Topics is a list of 0-4 indexed topics for the log. + topics: [Bytes32!]! + # Data is unindexed data for this log. + data: Bytes! + # Transaction is the transaction that generated this log entry. + transaction: Transaction! + } + + # Transaction is an Ethereum transaction. + type Transaction { + # Hash is the hash of this transaction. + hash: Bytes32! + # Nonce is the nonce of the account this transaction was generated with. + nonce: Long! + # Index is the index of this transaction in the parent block. This will + # be null if the transaction has not yet been mined. + index: Int + # From is the account that sent this transaction - this will always be + # an externally owned account. + from(block: Long): Account! + # To is the account the transaction was sent to. This is null for + # contract-creating transactions. + to(block: Long): Account + # Value is the value, in wei, sent along with this transaction. + value: BigInt! + # GasPrice is the price offered to miners for gas, in wei per unit. + gasPrice: BigInt! + # Gas is the maximum amount of gas this transaction can consume. + gas: Long! + # InputData is the data supplied to the target of the transaction. + inputData: Bytes! + # Block is the block this transaction was mined in. This will be null if + # the transaction has not yet been mined. + block: Block + + # Status is the return status of the transaction. This will be 1 if the + # transaction succeeded, or 0 if it failed (due to a revert, or due to + # running out of gas). If the transaction has not yet been mined, this + # field will be null. + status: Long + # GasUsed is the amount of gas that was used processing this transaction. + # If the transaction has not yet been mined, this field will be null. + gasUsed: Long + # CumulativeGasUsed is the total gas used in the block up to and including + # this transaction. If the transaction has not yet been mined, this field + # will be null. + cumulativeGasUsed: Long + # CreatedContract is the account that was created by a contract creation + # transaction. If the transaction was not a contract creation transaction, + # or it has not yet been mined, this field will be null. + createdContract(block: Long): Account + # Logs is a list of log entries emitted by this transaction. If the + # transaction has not yet been mined, this field will be null. + logs: [Log!] + } + + # BlockFilterCriteria encapsulates log filter criteria for a filter applied + # to a single block. + input BlockFilterCriteria { + # Addresses is list of addresses that are of interest. If this list is + # empty, results will not be filtered by address. + addresses: [Address!] + # Topics list restricts matches to particular event topics. Each event has a list + # of topics. Topics matches a prefix of that list. An empty element array matches any + # topic. Non-empty elements represent an alternative that matches any of the + # contained topics. + # + # Examples: + # - [] or nil matches any topic list + # - [[A]] matches topic A in first position + # - [[], [B]] matches any topic in first position, B in second position + # - [[A], [B]] matches topic A in first position, B in second position + # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position + topics: [[Bytes32!]!] + } + + # Block is an Ethereum block. + type Block { + # Number is the number of this block, starting at 0 for the genesis block. + number: Long! + # Hash is the block hash of this block. + hash: Bytes32! + # Parent is the parent block of this block. + parent: Block + # Nonce is the block nonce, an 8 byte sequence determined by the miner. + nonce: Bytes! + # TransactionsRoot is the keccak256 hash of the root of the trie of transactions in this block. + transactionsRoot: Bytes32! + # TransactionCount is the number of transactions in this block. if + # transactions are not available for this block, this field will be null. + transactionCount: Int + # StateRoot is the keccak256 hash of the state trie after this block was processed. + stateRoot: Bytes32! + # ReceiptsRoot is the keccak256 hash of the trie of transaction receipts in this block. + receiptsRoot: Bytes32! + # Miner is the account that mined this block. + miner(block: Long): Account! + # ExtraData is an arbitrary data field supplied by the miner. + extraData: Bytes! + # GasLimit is the maximum amount of gas that was available to transactions in this block. + gasLimit: Long! + # GasUsed is the amount of gas that was used executing transactions in this block. + gasUsed: Long! + # Timestamp is the unix timestamp at which this block was mined. + timestamp: BigInt! + # LogsBloom is a bloom filter that can be used to check if a block may + # contain log entries matching a filter. + logsBloom: Bytes! + # MixHash is the hash that was used as an input to the PoW process. + mixHash: Bytes32! + # Difficulty is a measure of the difficulty of mining this block. + difficulty: BigInt! + # TotalDifficulty is the sum of all difficulty values up to and including + # this block. + totalDifficulty: BigInt! + # OmmerCount is the number of ommers (AKA uncles) associated with this + # block. If ommers are unavailable, this field will be null. + ommerCount: Int + # Ommers is a list of ommer (AKA uncle) blocks associated with this block. + # If ommers are unavailable, this field will be null. Depending on your + # node, the transactions, transactionAt, transactionCount, ommers, + # ommerCount and ommerAt fields may not be available on any ommer blocks. + ommers: [Block] + # OmmerAt returns the ommer (AKA uncle) at the specified index. If ommers + # are unavailable, or the index is out of bounds, this field will be null. + ommerAt(index: Int!): Block + # OmmerHash is the keccak256 hash of all the ommers (AKA uncles) + # associated with this block. + ommerHash: Bytes32! + # Transactions is a list of transactions associated with this block. If + # transactions are unavailable for this block, this field will be null. + transactions: [Transaction!] + # TransactionAt returns the transaction at the specified index. If + # transactions are unavailable for this block, or if the index is out of + # bounds, this field will be null. + transactionAt(index: Int!): Transaction + # Logs returns a filtered set of logs from this block. + logs(filter: BlockFilterCriteria!): [Log!]! + # Account fetches an Ethereum account at the current block's state. + account(address: Address!): Account! + # Call executes a local call operation at the current block's state. + call(data: CallData!): CallResult + # EstimateGas estimates the amount of gas that will be required for + # successful execution of a transaction at the current block's state. + estimateGas(data: CallData!): Long! + } + + # CallData represents the data associated with a local contract call. + # All fields are optional. + input CallData { + # From is the address making the call. + from: Address + # To is the address the call is sent to. + to: Address + # Gas is the amount of gas sent with the call. + gas: Long + # GasPrice is the price, in wei, offered for each unit of gas. + gasPrice: BigInt + # Value is the value, in wei, sent along with the call. + value: BigInt + # Data is the data sent to the callee. + data: Bytes + } + + # CallResult is the result of a local call operation. + type CallResult { + # Data is the return data of the called contract. + data: Bytes! + # GasUsed is the amount of gas used by the call, after any refunds. + gasUsed: Long! + # Status is the result of the call - 1 for success or 0 for failure. + status: Long! + } + + # FilterCriteria encapsulates log filter criteria for searching log entries. + input FilterCriteria { + # FromBlock is the block at which to start searching, inclusive. Defaults + # to the latest block if not supplied. + fromBlock: Long + # ToBlock is the block at which to stop searching, inclusive. Defaults + # to the latest block if not supplied. + toBlock: Long + # Addresses is a list of addresses that are of interest. If this list is + # empty, results will not be filtered by address. + addresses: [Address!] + # Topics list restricts matches to particular event topics. Each event has a list + # of topics. Topics matches a prefix of that list. An empty element array matches any + # topic. Non-empty elements represent an alternative that matches any of the + # contained topics. + # + # Examples: + # - [] or nil matches any topic list + # - [[A]] matches topic A in first position + # - [[], [B]] matches any topic in first position, B in second position + # - [[A], [B]] matches topic A in first position, B in second position + # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position + topics: [[Bytes32!]!] + } + + # SyncState contains the current synchronisation state of the client. + type SyncState{ + # StartingBlock is the block number at which synchronisation started. + startingBlock: Long! + # CurrentBlock is the point at which synchronisation has presently reached. + currentBlock: Long! + # HighestBlock is the latest known block number. + highestBlock: Long! + # PulledStates is the number of state entries fetched so far, or null + # if this is not known or not relevant. + pulledStates: Long + # KnownStates is the number of states the node knows of so far, or null + # if this is not known or not relevant. + knownStates: Long + } + + # Pending represents the current pending state. + type Pending { + # TransactionCount is the number of transactions in the pending state. + transactionCount: Int! + # Transactions is a list of transactions in the current pending state. + transactions: [Transaction!] + # Account fetches an Ethereum account for the pending state. + account(address: Address!): Account! + # Call executes a local call operation for the pending state. + call(data: CallData!): CallResult + # EstimateGas estimates the amount of gas that will be required for + # successful execution of a transaction for the pending state. + estimateGas(data: CallData!): Long! + } + + type Query { + # Block fetches an Ethereum block by number or by hash. If neither is + # supplied, the most recent known block is returned. + block(number: Long, hash: Bytes32): Block + # Blocks returns all the blocks between two numbers, inclusive. If + # to is not supplied, it defaults to the most recent known block. + blocks(from: Long!, to: Long): [Block!]! + # Pending returns the current pending state. + pending: Pending! + # Transaction returns a transaction specified by its hash. + transaction(hash: Bytes32!): Transaction + # Logs returns log entries matching the provided filter. + logs(filter: FilterCriteria!): [Log!]! + # GasPrice returns the node's estimate of a gas price sufficient to + # ensure a transaction is mined in a timely fashion. + gasPrice: BigInt! + # ProtocolVersion returns the current wire protocol version number. + protocolVersion: Int! + # Syncing returns information on the current synchronisation state. + syncing: SyncState + } + + type Mutation { + # SendRawTransaction sends an RLP-encoded transaction to the network. + sendRawTransaction(data: Bytes!): Bytes32! + } +` diff --git a/vendor/github.com/ethereum/go-ethereum/interfaces.go b/vendor/github.com/ethereum/go-ethereum/interfaces.go index 26b0fcbc..1ff31f96 100644 --- a/vendor/github.com/ethereum/go-ethereum/interfaces.go +++ b/vendor/github.com/ethereum/go-ethereum/interfaces.go @@ -144,9 +144,9 @@ type FilterQuery struct { // Examples: // {} or nil matches any topic list // {{A}} matches topic A in first position - // {{}, {B}} matches any topic in first position, B in second position - // {{A}, {B}} matches topic A in first position, B in second position - // {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position + // {{}, {B}} matches any topic in first position AND B in second position + // {{A}, {B}} matches topic A in first position AND B in second position + // {{A, B}, {C, D}} matches topic (A OR B) in first position AND (C OR D) in second position Topics [][]common.Hash } diff --git a/vendor/github.com/ethereum/go-ethereum/internal/build/util.go b/vendor/github.com/ethereum/go-ethereum/internal/build/util.go index 195bdb40..319c0f2d 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/build/util.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/build/util.go @@ -143,9 +143,9 @@ func CopyFile(dst, src string, mode os.FileMode) { // so that go commands executed by build use the same version of Go as the 'host' that runs // build code. e.g. // -// /usr/lib/go-1.11/bin/go run build/ci.go ... +// /usr/lib/go-1.12.1/bin/go run build/ci.go ... // -// runs using go 1.11 and invokes go 1.11 tools from the same GOROOT. This is also important +// runs using go 1.12.1 and invokes go 1.12.1 tools from the same GOROOT. This is also important // because runtime.Version checks on the host should match the tools that are run. func GoTool(tool string, args ...string) *exec.Cmd { args = append([]string{tool}, args...) @@ -177,3 +177,34 @@ func ExpandPackagesNoVendor(patterns []string) []string { } return patterns } + +// UploadSFTP uploads files to a remote host using the sftp command line tool. +// The destination host may be specified either as [user@]host[: or as a URI in +// the form sftp://[user@]host[:port]. +func UploadSFTP(identityFile, host, dir string, files []string) error { + sftp := exec.Command("sftp") + sftp.Stdout = nil + sftp.Stderr = os.Stderr + if identityFile != "" { + sftp.Args = append(sftp.Args, "-i", identityFile) + } + sftp.Args = append(sftp.Args, host) + fmt.Println(">>>", strings.Join(sftp.Args, " ")) + if *DryRunFlag { + return nil + } + + stdin, err := sftp.StdinPipe() + if err != nil { + return fmt.Errorf("can't create stdin pipe for sftp: %v", err) + } + if err := sftp.Start(); err != nil { + return err + } + in := io.MultiWriter(stdin, os.Stdout) + for _, f := range files { + fmt.Fprintln(in, "put", f, path.Join(dir, filepath.Base(f))) + } + stdin.Close() + return sftp.Wait() +} diff --git a/vendor/github.com/ethereum/go-ethereum/internal/cmdtest/test_cmd.go b/vendor/github.com/ethereum/go-ethereum/internal/cmdtest/test_cmd.go index 20e82ec2..f8b1b43c 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/cmdtest/test_cmd.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/cmdtest/test_cmd.go @@ -27,6 +27,7 @@ import ( "regexp" "strings" "sync" + "syscall" "testing" "text/template" "time" @@ -50,6 +51,8 @@ type TestCmd struct { stdout *bufio.Reader stdin io.WriteCloser stderr *testlogger + // Err will contain the process exit error or interrupt signal error + Err error } // Run exec's the current binary using name as argv[0] which will trigger the @@ -182,11 +185,25 @@ func (tt *TestCmd) ExpectExit() { } func (tt *TestCmd) WaitExit() { - tt.cmd.Wait() + tt.Err = tt.cmd.Wait() } func (tt *TestCmd) Interrupt() { - tt.cmd.Process.Signal(os.Interrupt) + tt.Err = tt.cmd.Process.Signal(os.Interrupt) +} + +// ExitStatus exposes the process' OS exit code +// It will only return a valid value after the process has finished. +func (tt *TestCmd) ExitStatus() int { + if tt.Err != nil { + exitErr := tt.Err.(*exec.ExitError) + if exitErr != nil { + if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { + return status.ExitStatus() + } + } + } + return 0 } // StderrText returns any stderr output written so far. diff --git a/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go b/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go index 0c751c32..e85e6d20 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -43,7 +44,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/util" ) const ( @@ -217,7 +217,7 @@ func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI { } } -// ListAccounts will return a list of addresses for accounts this node manages. +// listAccounts will return a list of addresses for accounts this node manages. func (s *PrivateAccountAPI) ListAccounts() []common.Address { addresses := make([]common.Address, 0) // return [] instead of nil if empty for _, wallet := range s.am.Wallets() { @@ -339,7 +339,7 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool { return fetchKeystore(s.am).Lock(addr) == nil } -// signTransactions sets defaults and signs the given transaction +// signTransaction sets defaults and signs the given transaction // NOTE: the caller needs to ensure that the nonceLock is held, if applicable, // and release it after the transaction has been submitted to the tx pool func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *SendTxArgs, passwd string) (*types.Transaction, error) { @@ -356,11 +356,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *SendTxArg // Assemble the transaction and sign with the wallet tx := args.toTransaction() - var chainID *big.Int - if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { - chainID = config.ChainID - } - return wallet.SignTxWithPassphrase(account, passwd, tx, chainID) + return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) } // SendTransaction will create a transaction from the given arguments and @@ -378,7 +374,7 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs log.Warn("Failed transaction send attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err) return common.Hash{}, err } - return submitTransaction(ctx, s.b, signed) + return SubmitTransaction(ctx, s.b, signed) } // SignTransaction will create a transaction from the given arguments and @@ -409,18 +405,6 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs return &SignTransactionResult{data, signed}, nil } -// signHash is a helper function that calculates a hash for the given message that can be -// safely used to calculate a signature from. -// -// The hash is calulcated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). -// -// This gives context to the signed message and prevents signing of transactions. -func signHash(data []byte) []byte { - msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) - return crypto.Keccak256([]byte(msg)) -} - // Sign calculates an Ethereum ECDSA signature for: // keccack256("\x19Ethereum Signed Message:\n" + len(message) + message)) // @@ -439,7 +423,7 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c return nil, err } // Assemble sign the data with the wallet - signature, err := wallet.SignHashWithPassphrase(account, passwd, signHash(data)) + signature, err := wallet.SignTextWithPassphrase(account, passwd, data) if err != nil { log.Warn("Failed data sign attempt", "address", addr, "err", err) return nil, err @@ -467,7 +451,7 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt } sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 - rpk, err := crypto.SigToPub(signHash(data), sig) + rpk, err := crypto.SigToPub(accounts.TextHash(data), sig) if err != nil { return common.Address{}, err } @@ -675,41 +659,54 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A // CallArgs represents the arguments for a call. type CallArgs struct { - From common.Address `json:"from"` + From *common.Address `json:"from"` To *common.Address `json:"to"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice hexutil.Big `json:"gasPrice"` - Value hexutil.Big `json:"value"` - Data hexutil.Bytes `json:"data"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Value *hexutil.Big `json:"value"` + Data *hexutil.Bytes `json:"data"` } -func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) { +func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) - state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) + state, header, err := b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { return nil, 0, false, err } // Set sender address or use a default if none specified - addr := args.From - if addr == (common.Address{}) { - if wallets := s.b.AccountManager().Wallets(); len(wallets) > 0 { + var addr common.Address + if args.From == nil { + if wallets := b.AccountManager().Wallets(); len(wallets) > 0 { if accounts := wallets[0].Accounts(); len(accounts) > 0 { addr = accounts[0].Address } } + } else { + addr = *args.From } // Set default gas & gas price if none were set - gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt() - if gas == 0 { - gas = math.MaxUint64 / 2 + gas := uint64(math.MaxUint64 / 2) + if args.Gas != nil { + gas = uint64(*args.Gas) } - if gasPrice.Sign() == 0 { - gasPrice = new(big.Int).SetUint64(defaultGasPrice) + gasPrice := new(big.Int).SetUint64(defaultGasPrice) + if args.GasPrice != nil { + gasPrice = args.GasPrice.ToInt() + } + + value := new(big.Int) + if args.Value != nil { + value = args.Value.ToInt() + } + + var data []byte + if args.Data != nil { + data = []byte(*args.Data) } // Create new call message - msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false) + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false) // Setup context so it may be cancelled the call has completed // or, in case of unmetered gas, setup a context with a timeout. @@ -724,7 +721,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr defer cancel() // Get a new instance of the EVM. - evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) + evm, vmError, err := b.GetEVM(ctx, msg, state, header) if err != nil { return nil, 0, false, err } @@ -748,24 +745,22 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Call executes the given transaction on the state for the given block number. // It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values. func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { - result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{}, 5*time.Second) + result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second) return (hexutil.Bytes)(result), err } -// EstimateGas returns an estimate of the amount of gas needed to execute the -// given transaction against the current pending block. -func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) { +func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) { // Binary search the gas requirement, as it may be higher than the amount used var ( lo uint64 = params.TxGas - 1 hi uint64 cap uint64 ) - if uint64(args.Gas) >= params.TxGas { - hi = uint64(args.Gas) + if args.Gas != nil && uint64(*args.Gas) >= params.TxGas { + hi = uint64(*args.Gas) } else { - // Retrieve the current pending block to act as the gas ceiling - block, err := s.b.BlockByNumber(ctx, rpc.PendingBlockNumber) + // Retrieve the block to act as the gas ceiling + block, err := b.BlockByNumber(ctx, blockNr) if err != nil { return 0, err } @@ -775,9 +770,9 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h // Create a helper to check if a gas allowance results in an executable transaction executable := func(gas uint64) bool { - args.Gas = hexutil.Uint64(gas) + args.Gas = (*hexutil.Uint64)(&gas) - _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}, 0) + _, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0) if err != nil || failed { return false } @@ -801,6 +796,12 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h return hexutil.Uint64(hi), nil } +// EstimateGas returns an estimate of the amount of gas needed to execute the +// given transaction against the current pending block. +func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) { + return DoEstimateGas(ctx, s.b, args, rpc.PendingBlockNumber) +} + // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value @@ -825,7 +826,7 @@ type StructLogRes struct { Storage *map[string]string `json:"storage,omitempty"` } -// formatLogs formats EVM returned structured logs for json output +// FormatLogs formats EVM returned structured logs for json output func FormatLogs(logs []vm.StructLog) []StructLogRes { formatted := make([]StructLogRes, len(logs)) for index, trace := range logs { @@ -1074,6 +1075,15 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx cont // GetTransactionCount returns the number of transactions the given address has sent for the given block number func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { + // Ask transaction pool for the nonce which includes pending transactions + if blockNr == rpc.PendingBlockNumber { + nonce, err := s.b.GetPoolNonce(ctx, address) + if err != nil { + return nil, err + } + return (*hexutil.Uint64)(&nonce), nil + } + // Resolve block number and use its state to ask for the nonce state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { return nil, err @@ -1172,11 +1182,7 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti return nil, err } // Request the wallet to sign the transaction - var chainID *big.Int - if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { - chainID = config.ChainID - } - return wallet.SignTx(account, tx, chainID) + return wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) } // SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool. @@ -1247,8 +1253,8 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) } -// submitTransaction is a helper function that submits tx to txPool and logs a message. -func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) { +// SubmitTransaction is a helper function that submits tx to txPool and logs a message. +func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) { if err := b.SendTx(ctx, tx); err != nil { return common.Hash{}, err } @@ -1292,15 +1298,11 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen // Assemble the transaction and sign with the wallet tx := args.toTransaction() - var chainID *big.Int - if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { - chainID = config.ChainID - } - signed, err := wallet.SignTx(account, tx, chainID) + signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) if err != nil { return common.Hash{}, err } - return submitTransaction(ctx, s.b, signed) + return SubmitTransaction(ctx, s.b, signed) } // SendRawTransaction will add the signed transaction to the transaction pool. @@ -1310,7 +1312,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod if err := rlp.DecodeBytes(encodedTx, tx); err != nil { return common.Hash{}, err } - return submitTransaction(ctx, s.b, tx) + return SubmitTransaction(ctx, s.b, tx) } // Sign calculates an ECDSA signature for: @@ -1331,7 +1333,7 @@ func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) return nil, err } // Sign the requested hash with the wallet - signature, err := wallet.SignHash(account, signHash(data)) + signature, err := wallet.SignText(account, data) if err == nil { signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper } @@ -1467,6 +1469,45 @@ func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (stri return fmt.Sprintf("%x", encoded), nil } +// TestSignCliqueBlock fetches the given block number, and attempts to sign it as a clique header with the +// given address, returning the address of the recovered signature +// +// This is a temporary method to debug the externalsigner integration, +// TODO: Remove this method when the integration is mature +func (api *PublicDebugAPI) TestSignCliqueBlock(ctx context.Context, address common.Address, number uint64) (common.Address, error) { + block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) + if block == nil { + return common.Address{}, fmt.Errorf("block #%d not found", number) + } + header := block.Header() + header.Extra = make([]byte, 32+65) + encoded := clique.CliqueRLP(header) + + // Look up the wallet containing the requested signer + account := accounts.Account{Address: address} + wallet, err := api.b.AccountManager().Find(account) + if err != nil { + return common.Address{}, err + } + + signature, err := wallet.SignData(account, accounts.MimetypeClique, encoded) + if err != nil { + return common.Address{}, err + } + sealHash := clique.SealHash(header).Bytes() + log.Info("test signing of clique block", + "Sealhash", fmt.Sprintf("%x", sealHash), + "signature", fmt.Sprintf("%x", signature)) + pubkey, err := crypto.Ecrecover(sealHash, signature) + if err != nil { + return common.Address{}, err + } + var signer common.Address + copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) + + return signer, nil +} + // PrintBlock retrieves a block and returns its pretty printed form. func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) @@ -1514,16 +1555,9 @@ func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) { } func (api *PrivateDebugAPI) ChaindbCompact() error { - ldb, ok := api.b.ChainDb().(interface { - LDB() *leveldb.DB - }) - if !ok { - return fmt.Errorf("chaindbCompact does not work for memory databases") - } for b := byte(0); b < 255; b++ { log.Info("Compacting chain database", "range", fmt.Sprintf("0x%0.2X-0x%0.2X", b, b+1)) - err := ldb.LDB().CompactRange(util.Range{Start: []byte{b}, Limit: []byte{b + 1}}) - if err != nil { + if err := api.b.ChainDb().Compact([]byte{b}, []byte{b + 1}); err != nil { log.Error("Database compaction failed", "err", err) return err } diff --git a/vendor/github.com/ethereum/go-ethereum/internal/ethapi/backend.go b/vendor/github.com/ethereum/go-ethereum/internal/ethapi/backend.go index c9ffe230..e23ee03b 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/ethapi/backend.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/ethapi/backend.go @@ -53,7 +53,7 @@ type Backend interface { GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetTd(blockHash common.Hash) *big.Int - GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) + GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription diff --git a/vendor/github.com/ethereum/go-ethereum/internal/jsre/jsre.go b/vendor/github.com/ethereum/go-ethereum/internal/jsre/jsre.go index 4c7664f1..1b3528a0 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/jsre/jsre.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/jsre/jsre.go @@ -32,8 +32,8 @@ import ( ) var ( - BigNumber_JS = deps.MustAsset("bignumber.js") - Web3_JS = deps.MustAsset("web3.js") + BignumberJs = deps.MustAsset("bignumber.js") + Web3Js = deps.MustAsset("web3.js") ) /* diff --git a/vendor/github.com/ethereum/go-ethereum/internal/web3ext/web3ext.go b/vendor/github.com/ethereum/go-ethereum/internal/web3ext/web3ext.go index a5f31965..e1577fe2 100644 --- a/vendor/github.com/ethereum/go-ethereum/internal/web3ext/web3ext.go +++ b/vendor/github.com/ethereum/go-ethereum/internal/web3ext/web3ext.go @@ -18,22 +18,23 @@ package web3ext var Modules = map[string]string{ - "admin": Admin_JS, - "chequebook": Chequebook_JS, - "clique": Clique_JS, - "ethash": Ethash_JS, - "debug": Debug_JS, - "eth": Eth_JS, - "miner": Miner_JS, - "net": Net_JS, - "personal": Personal_JS, - "rpc": RPC_JS, - "shh": Shh_JS, - "swarmfs": SWARMFS_JS, - "txpool": TxPool_JS, + "accounting": AccountingJs, + "admin": AdminJs, + "chequebook": ChequebookJs, + "clique": CliqueJs, + "ethash": EthashJs, + "debug": DebugJs, + "eth": EthJs, + "miner": MinerJs, + "net": NetJs, + "personal": PersonalJs, + "rpc": RpcJs, + "shh": ShhJs, + "swarmfs": SwarmfsJs, + "txpool": TxpoolJs, } -const Chequebook_JS = ` +const ChequebookJs = ` web3._extend({ property: 'chequebook', methods: [ @@ -64,7 +65,7 @@ web3._extend({ }); ` -const Clique_JS = ` +const CliqueJs = ` web3._extend({ property: 'clique', methods: [ @@ -110,7 +111,7 @@ web3._extend({ }); ` -const Ethash_JS = ` +const EthashJs = ` web3._extend({ property: 'ethash', methods: [ @@ -138,7 +139,7 @@ web3._extend({ }); ` -const Admin_JS = ` +const AdminJs = ` web3._extend({ property: 'admin', methods: [ @@ -216,7 +217,7 @@ web3._extend({ }); ` -const Debug_JS = ` +const DebugJs = ` web3._extend({ property: 'debug', methods: [ @@ -230,6 +231,12 @@ web3._extend({ call: 'debug_getBlockRlp', params: 1 }), + new web3._extend.Method({ + name: 'testSignCliqueBlock', + call: 'debug_testSignCliqueBlock', + params: 2, + inputFormatters: [web3._extend.formatters.inputAddressFormatter, null], + }), new web3._extend.Method({ name: 'setHead', call: 'debug_setHead', @@ -384,6 +391,18 @@ web3._extend({ params: 1, inputFormatter: [null] }), + new web3._extend.Method({ + name: 'standardTraceBadBlockToFile', + call: 'debug_standardTraceBadBlockToFile', + params: 2, + inputFormatter: [null, null] + }), + new web3._extend.Method({ + name: 'standardTraceBlockToFile', + call: 'debug_standardTraceBlockToFile', + params: 2, + inputFormatter: [null, null] + }), new web3._extend.Method({ name: 'traceBlockByNumber', call: 'debug_traceBlockByNumber', @@ -435,7 +454,7 @@ web3._extend({ }); ` -const Eth_JS = ` +const EthJs = ` web3._extend({ property: 'eth', methods: [ @@ -505,7 +524,7 @@ web3._extend({ }); ` -const Miner_JS = ` +const MinerJs = ` web3._extend({ property: 'miner', methods: [ @@ -550,7 +569,7 @@ web3._extend({ }); ` -const Net_JS = ` +const NetJs = ` web3._extend({ property: 'net', methods: [], @@ -563,7 +582,7 @@ web3._extend({ }); ` -const Personal_JS = ` +const PersonalJs = ` web3._extend({ property: 'personal', methods: [ @@ -609,7 +628,7 @@ web3._extend({ }) ` -const RPC_JS = ` +const RpcJs = ` web3._extend({ property: 'rpc', methods: [], @@ -622,7 +641,7 @@ web3._extend({ }); ` -const Shh_JS = ` +const ShhJs = ` web3._extend({ property: 'shh', methods: [ @@ -642,7 +661,7 @@ web3._extend({ }); ` -const SWARMFS_JS = ` +const SwarmfsJs = ` web3._extend({ property: 'swarmfs', methods: @@ -666,7 +685,7 @@ web3._extend({ }); ` -const TxPool_JS = ` +const TxpoolJs = ` web3._extend({ property: 'txpool', methods: [], @@ -692,3 +711,47 @@ web3._extend({ ] }); ` + +const AccountingJs = ` +web3._extend({ + property: 'accounting', + methods: [ + new web3._extend.Property({ + name: 'balance', + getter: 'account_balance' + }), + new web3._extend.Property({ + name: 'balanceCredit', + getter: 'account_balanceCredit' + }), + new web3._extend.Property({ + name: 'balanceDebit', + getter: 'account_balanceDebit' + }), + new web3._extend.Property({ + name: 'bytesCredit', + getter: 'account_bytesCredit' + }), + new web3._extend.Property({ + name: 'bytesDebit', + getter: 'account_bytesDebit' + }), + new web3._extend.Property({ + name: 'msgCredit', + getter: 'account_msgCredit' + }), + new web3._extend.Property({ + name: 'msgDebit', + getter: 'account_msgDebit' + }), + new web3._extend.Property({ + name: 'peerDrops', + getter: 'account_peerDrops' + }), + new web3._extend.Property({ + name: 'selfDrops', + getter: 'account_selfDrops' + }), + ] +}); +` diff --git a/vendor/github.com/ethereum/go-ethereum/les/api.go b/vendor/github.com/ethereum/go-ethereum/les/api.go new file mode 100644 index 00000000..a933cbd0 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/api.go @@ -0,0 +1,454 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package les + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/rpc" +) + +var ( + ErrMinCap = errors.New("capacity too small") + ErrTotalCap = errors.New("total capacity exceeded") + ErrUnknownBenchmarkType = errors.New("unknown benchmark type") + + dropCapacityDelay = time.Second // delay applied to decreasing capacity changes +) + +// PrivateLightServerAPI provides an API to access the LES light server. +// It offers only methods that operate on public data that is freely available to anyone. +type PrivateLightServerAPI struct { + server *LesServer +} + +// NewPrivateLightServerAPI creates a new LES light server API. +func NewPrivateLightServerAPI(server *LesServer) *PrivateLightServerAPI { + return &PrivateLightServerAPI{ + server: server, + } +} + +// TotalCapacity queries total available capacity for all clients +func (api *PrivateLightServerAPI) TotalCapacity() hexutil.Uint64 { + return hexutil.Uint64(api.server.priorityClientPool.totalCapacity()) +} + +// SubscribeTotalCapacity subscribes to changed total capacity events. +// If onlyUnderrun is true then notification is sent only if the total capacity +// drops under the total capacity of connected priority clients. +// +// Note: actually applying decreasing total capacity values is delayed while the +// notification is sent instantly. This allows lowering the capacity of a priority client +// or choosing which one to drop before the system drops some of them automatically. +func (api *PrivateLightServerAPI) SubscribeTotalCapacity(ctx context.Context, onlyUnderrun bool) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + rpcSub := notifier.CreateSubscription() + api.server.priorityClientPool.subscribeTotalCapacity(&tcSubscription{notifier, rpcSub, onlyUnderrun}) + return rpcSub, nil +} + +type ( + // tcSubscription represents a total capacity subscription + tcSubscription struct { + notifier *rpc.Notifier + rpcSub *rpc.Subscription + onlyUnderrun bool + } + tcSubs map[*tcSubscription]struct{} +) + +// send sends a changed total capacity event to the subscribers +func (s tcSubs) send(tc uint64, underrun bool) { + for sub := range s { + select { + case <-sub.rpcSub.Err(): + delete(s, sub) + case <-sub.notifier.Closed(): + delete(s, sub) + default: + if underrun || !sub.onlyUnderrun { + sub.notifier.Notify(sub.rpcSub.ID, tc) + } + } + } +} + +// MinimumCapacity queries minimum assignable capacity for a single client +func (api *PrivateLightServerAPI) MinimumCapacity() hexutil.Uint64 { + return hexutil.Uint64(minCapacity) +} + +// FreeClientCapacity queries the capacity provided for free clients +func (api *PrivateLightServerAPI) FreeClientCapacity() hexutil.Uint64 { + return hexutil.Uint64(api.server.freeClientCap) +} + +// SetClientCapacity sets the priority capacity assigned to a given client. +// If the assigned capacity is bigger than zero then connection is always +// guaranteed. The sum of capacity assigned to priority clients can not exceed +// the total available capacity. +// +// Note: assigned capacity can be changed while the client is connected with +// immediate effect. +func (api *PrivateLightServerAPI) SetClientCapacity(id enode.ID, cap uint64) error { + if cap != 0 && cap < minCapacity { + return ErrMinCap + } + return api.server.priorityClientPool.setClientCapacity(id, cap) +} + +// GetClientCapacity returns the capacity assigned to a given client +func (api *PrivateLightServerAPI) GetClientCapacity(id enode.ID) hexutil.Uint64 { + api.server.priorityClientPool.lock.Lock() + defer api.server.priorityClientPool.lock.Unlock() + + return hexutil.Uint64(api.server.priorityClientPool.clients[id].cap) +} + +// clientPool is implemented by both the free and priority client pools +type clientPool interface { + peerSetNotify + setLimits(count int, totalCap uint64) +} + +// priorityClientPool stores information about prioritized clients +type priorityClientPool struct { + lock sync.Mutex + child clientPool + ps *peerSet + clients map[enode.ID]priorityClientInfo + totalCap, totalCapAnnounced uint64 + totalConnectedCap, freeClientCap uint64 + maxPeers, priorityCount int + + subs tcSubs + updateSchedule []scheduledUpdate + scheduleCounter uint64 +} + +// scheduledUpdate represents a delayed total capacity update +type scheduledUpdate struct { + time mclock.AbsTime + totalCap, id uint64 +} + +// priorityClientInfo entries exist for all prioritized clients and currently connected non-priority clients +type priorityClientInfo struct { + cap uint64 // zero for non-priority clients + connected bool + peer *peer +} + +// newPriorityClientPool creates a new priority client pool +func newPriorityClientPool(freeClientCap uint64, ps *peerSet, child clientPool) *priorityClientPool { + return &priorityClientPool{ + clients: make(map[enode.ID]priorityClientInfo), + freeClientCap: freeClientCap, + ps: ps, + child: child, + } +} + +// registerPeer is called when a new client is connected. If the client has no +// priority assigned then it is passed to the child pool which may either keep it +// or disconnect it. +// +// Note: priorityClientPool also stores a record about free clients while they are +// connected in order to be able to assign priority to them later. +func (v *priorityClientPool) registerPeer(p *peer) { + v.lock.Lock() + defer v.lock.Unlock() + + id := p.ID() + c := v.clients[id] + if c.connected { + return + } + if c.cap == 0 && v.child != nil { + v.child.registerPeer(p) + } + if c.cap != 0 && v.totalConnectedCap+c.cap > v.totalCap { + go v.ps.Unregister(p.id) + return + } + + c.connected = true + c.peer = p + v.clients[id] = c + if c.cap != 0 { + v.priorityCount++ + v.totalConnectedCap += c.cap + if v.child != nil { + v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) + } + p.updateCapacity(c.cap) + } +} + +// unregisterPeer is called when a client is disconnected. If the client has no +// priority assigned then it is also removed from the child pool. +func (v *priorityClientPool) unregisterPeer(p *peer) { + v.lock.Lock() + defer v.lock.Unlock() + + id := p.ID() + c := v.clients[id] + if !c.connected { + return + } + if c.cap != 0 { + c.connected = false + v.clients[id] = c + v.priorityCount-- + v.totalConnectedCap -= c.cap + if v.child != nil { + v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) + } + } else { + if v.child != nil { + v.child.unregisterPeer(p) + } + delete(v.clients, id) + } +} + +// setLimits updates the allowed peer count and total capacity of the priority +// client pool. Since the free client pool is a child of the priority pool the +// remaining peer count and capacity is assigned to the free pool by calling its +// own setLimits function. +// +// Note: a decreasing change of the total capacity is applied with a delay. +func (v *priorityClientPool) setLimits(count int, totalCap uint64) { + v.lock.Lock() + defer v.lock.Unlock() + + v.totalCapAnnounced = totalCap + if totalCap > v.totalCap { + v.setLimitsNow(count, totalCap) + v.subs.send(totalCap, false) + return + } + v.setLimitsNow(count, v.totalCap) + if totalCap < v.totalCap { + v.subs.send(totalCap, totalCap < v.totalConnectedCap) + for i, s := range v.updateSchedule { + if totalCap >= s.totalCap { + s.totalCap = totalCap + v.updateSchedule = v.updateSchedule[:i+1] + return + } + } + v.updateSchedule = append(v.updateSchedule, scheduledUpdate{time: mclock.Now() + mclock.AbsTime(dropCapacityDelay), totalCap: totalCap}) + if len(v.updateSchedule) == 1 { + v.scheduleCounter++ + id := v.scheduleCounter + v.updateSchedule[0].id = id + time.AfterFunc(dropCapacityDelay, func() { v.checkUpdate(id) }) + } + } else { + v.updateSchedule = nil + } +} + +// checkUpdate performs the next scheduled update if possible and schedules +// the one after that +func (v *priorityClientPool) checkUpdate(id uint64) { + v.lock.Lock() + defer v.lock.Unlock() + + if len(v.updateSchedule) == 0 || v.updateSchedule[0].id != id { + return + } + v.setLimitsNow(v.maxPeers, v.updateSchedule[0].totalCap) + v.updateSchedule = v.updateSchedule[1:] + if len(v.updateSchedule) != 0 { + v.scheduleCounter++ + id := v.scheduleCounter + v.updateSchedule[0].id = id + dt := time.Duration(v.updateSchedule[0].time - mclock.Now()) + time.AfterFunc(dt, func() { v.checkUpdate(id) }) + } +} + +// setLimits updates the allowed peer count and total capacity immediately +func (v *priorityClientPool) setLimitsNow(count int, totalCap uint64) { + if v.priorityCount > count || v.totalConnectedCap > totalCap { + for id, c := range v.clients { + if c.connected { + c.connected = false + v.totalConnectedCap -= c.cap + v.priorityCount-- + v.clients[id] = c + go v.ps.Unregister(c.peer.id) + if v.priorityCount <= count && v.totalConnectedCap <= totalCap { + break + } + } + } + } + v.maxPeers = count + v.totalCap = totalCap + if v.child != nil { + v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) + } +} + +// totalCapacity queries total available capacity for all clients +func (v *priorityClientPool) totalCapacity() uint64 { + v.lock.Lock() + defer v.lock.Unlock() + + return v.totalCapAnnounced +} + +// subscribeTotalCapacity subscribes to changed total capacity events +func (v *priorityClientPool) subscribeTotalCapacity(sub *tcSubscription) { + v.lock.Lock() + defer v.lock.Unlock() + + v.subs[sub] = struct{}{} +} + +// setClientCapacity sets the priority capacity assigned to a given client +func (v *priorityClientPool) setClientCapacity(id enode.ID, cap uint64) error { + v.lock.Lock() + defer v.lock.Unlock() + + c := v.clients[id] + if c.cap == cap { + return nil + } + if c.connected { + if v.totalConnectedCap+cap > v.totalCap+c.cap { + return ErrTotalCap + } + if c.cap == 0 { + if v.child != nil { + v.child.unregisterPeer(c.peer) + } + v.priorityCount++ + } + if cap == 0 { + v.priorityCount-- + } + v.totalConnectedCap += cap - c.cap + if v.child != nil { + v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) + } + if cap == 0 { + if v.child != nil { + v.child.registerPeer(c.peer) + } + c.peer.updateCapacity(v.freeClientCap) + } else { + c.peer.updateCapacity(cap) + } + } + if cap != 0 || c.connected { + c.cap = cap + v.clients[id] = c + } else { + delete(v.clients, id) + } + return nil +} + +// Benchmark runs a request performance benchmark with a given set of measurement setups +// in multiple passes specified by passCount. The measurement time for each setup in each +// pass is specified in milliseconds by length. +// +// Note: measurement time is adjusted for each pass depending on the previous ones. +// Therefore a controlled total measurement time is achievable in multiple passes. +func (api *PrivateLightServerAPI) Benchmark(setups []map[string]interface{}, passCount, length int) ([]map[string]interface{}, error) { + benchmarks := make([]requestBenchmark, len(setups)) + for i, setup := range setups { + if t, ok := setup["type"].(string); ok { + getInt := func(field string, def int) int { + if value, ok := setup[field].(float64); ok { + return int(value) + } + return def + } + getBool := func(field string, def bool) bool { + if value, ok := setup[field].(bool); ok { + return value + } + return def + } + switch t { + case "header": + benchmarks[i] = &benchmarkBlockHeaders{ + amount: getInt("amount", 1), + skip: getInt("skip", 1), + byHash: getBool("byHash", false), + reverse: getBool("reverse", false), + } + case "body": + benchmarks[i] = &benchmarkBodiesOrReceipts{receipts: false} + case "receipts": + benchmarks[i] = &benchmarkBodiesOrReceipts{receipts: true} + case "proof": + benchmarks[i] = &benchmarkProofsOrCode{code: false} + case "code": + benchmarks[i] = &benchmarkProofsOrCode{code: true} + case "cht": + benchmarks[i] = &benchmarkHelperTrie{ + bloom: false, + reqCount: getInt("amount", 1), + } + case "bloom": + benchmarks[i] = &benchmarkHelperTrie{ + bloom: true, + reqCount: getInt("amount", 1), + } + case "txSend": + benchmarks[i] = &benchmarkTxSend{} + case "txStatus": + benchmarks[i] = &benchmarkTxStatus{} + default: + return nil, ErrUnknownBenchmarkType + } + } else { + return nil, ErrUnknownBenchmarkType + } + } + rs := api.server.protocolManager.runBenchmark(benchmarks, passCount, time.Millisecond*time.Duration(length)) + result := make([]map[string]interface{}, len(setups)) + for i, r := range rs { + res := make(map[string]interface{}) + if r.err == nil { + res["totalCount"] = r.totalCount + res["avgTime"] = r.avgTime + res["maxInSize"] = r.maxInSize + res["maxOutSize"] = r.maxOutSize + } else { + res["error"] = r.err.Error() + } + result[i] = res + } + return result, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/api_backend.go b/vendor/github.com/ethereum/go-ethereum/les/api_backend.go index aa748a4e..75313962 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/api_backend.go +++ b/vendor/github.com/ethereum/go-ethereum/les/api_backend.go @@ -105,10 +105,10 @@ func (b *LesApiBackend) GetTd(hash common.Hash) *big.Int { return b.eth.blockchain.GetTdByHash(hash) } -func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { +func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) { state.SetBalance(msg.From(), math.MaxBig256) context := core.NewEVMContext(msg, header, b.eth.blockchain, nil) - return vm.NewEVM(context, state, b.eth.chainConfig, vmCfg), state.Error, nil + return vm.NewEVM(context, state, b.eth.chainConfig, vm.Config{}), state.Error, nil } func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { diff --git a/vendor/github.com/ethereum/go-ethereum/les/api_test.go b/vendor/github.com/ethereum/go-ethereum/les/api_test.go new file mode 100644 index 00000000..cec94596 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/api_test.go @@ -0,0 +1,525 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package les + +import ( + "context" + "errors" + "flag" + "fmt" + "io/ioutil" + "math/rand" + "os" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/les/flowcontrol" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/rpc" + colorable "github.com/mattn/go-colorable" +) + +/* +This test is not meant to be a part of the automatic testing process because it +runs for a long time and also requires a large database in order to do a meaningful +request performance test. When testServerDataDir is empty, the test is skipped. +*/ + +const ( + testServerDataDir = "" // should always be empty on the master branch + testServerCapacity = 200 + testMaxClients = 10 + testTolerance = 0.1 + minRelCap = 0.2 +) + +func TestCapacityAPI3(t *testing.T) { + testCapacityAPI(t, 3) +} + +func TestCapacityAPI6(t *testing.T) { + testCapacityAPI(t, 6) +} + +func TestCapacityAPI10(t *testing.T) { + testCapacityAPI(t, 10) +} + +// testCapacityAPI runs an end-to-end simulation test connecting one server with +// a given number of clients. It sets different priority capacities to all clients +// except a randomly selected one which runs in free client mode. All clients send +// similar requests at the maximum allowed rate and the test verifies whether the +// ratio of processed requests is close enough to the ratio of assigned capacities. +// Running multiple rounds with different settings ensures that changing capacity +// while connected and going back and forth between free and priority mode with +// the supplied API calls is also thoroughly tested. +func testCapacityAPI(t *testing.T, clientCount int) { + if testServerDataDir == "" { + // Skip test if no data dir specified + return + } + + for !testSim(t, 1, clientCount, []string{testServerDataDir}, nil, func(ctx context.Context, net *simulations.Network, servers []*simulations.Node, clients []*simulations.Node) bool { + if len(servers) != 1 { + t.Fatalf("Invalid number of servers: %d", len(servers)) + } + server := servers[0] + + clientRpcClients := make([]*rpc.Client, len(clients)) + + serverRpcClient, err := server.Client() + if err != nil { + t.Fatalf("Failed to obtain rpc client: %v", err) + } + headNum, headHash := getHead(ctx, t, serverRpcClient) + totalCap := getTotalCap(ctx, t, serverRpcClient) + minCap := getMinCap(ctx, t, serverRpcClient) + testCap := totalCap * 3 / 4 + fmt.Printf("Server testCap: %d minCap: %d head number: %d head hash: %064x\n", testCap, minCap, headNum, headHash) + reqMinCap := uint64(float64(testCap) * minRelCap / (minRelCap + float64(len(clients)-1))) + if minCap > reqMinCap { + t.Fatalf("Minimum client capacity (%d) bigger than required minimum for this test (%d)", minCap, reqMinCap) + } + + freeIdx := rand.Intn(len(clients)) + freeCap := getFreeCap(ctx, t, serverRpcClient) + + for i, client := range clients { + var err error + clientRpcClients[i], err = client.Client() + if err != nil { + t.Fatalf("Failed to obtain rpc client: %v", err) + } + + fmt.Println("connecting client", i) + if i != freeIdx { + setCapacity(ctx, t, serverRpcClient, client.ID(), testCap/uint64(len(clients))) + } + net.Connect(client.ID(), server.ID()) + + for { + select { + case <-ctx.Done(): + t.Fatalf("Timeout") + default: + } + num, hash := getHead(ctx, t, clientRpcClients[i]) + if num == headNum && hash == headHash { + fmt.Println("client", i, "synced") + break + } + time.Sleep(time.Millisecond * 200) + } + } + + var wg sync.WaitGroup + stop := make(chan struct{}) + + reqCount := make([]uint64, len(clientRpcClients)) + + for i, c := range clientRpcClients { + wg.Add(1) + i, c := i, c + go func() { + queue := make(chan struct{}, 100) + var count uint64 + for { + select { + case queue <- struct{}{}: + select { + case <-stop: + wg.Done() + return + case <-ctx.Done(): + wg.Done() + return + default: + wg.Add(1) + go func() { + ok := testRequest(ctx, t, c) + wg.Done() + <-queue + if ok { + count++ + atomic.StoreUint64(&reqCount[i], count) + } + }() + } + case <-stop: + wg.Done() + return + case <-ctx.Done(): + wg.Done() + return + } + } + }() + } + + processedSince := func(start []uint64) []uint64 { + res := make([]uint64, len(reqCount)) + for i := range reqCount { + res[i] = atomic.LoadUint64(&reqCount[i]) + if start != nil { + res[i] -= start[i] + } + } + return res + } + + weights := make([]float64, len(clients)) + for c := 0; c < 5; c++ { + setCapacity(ctx, t, serverRpcClient, clients[freeIdx].ID(), freeCap) + freeIdx = rand.Intn(len(clients)) + var sum float64 + for i := range clients { + if i == freeIdx { + weights[i] = 0 + } else { + weights[i] = rand.Float64()*(1-minRelCap) + minRelCap + } + sum += weights[i] + } + for i, client := range clients { + weights[i] *= float64(testCap-freeCap-100) / sum + capacity := uint64(weights[i]) + if i != freeIdx && capacity < getCapacity(ctx, t, serverRpcClient, client.ID()) { + setCapacity(ctx, t, serverRpcClient, client.ID(), capacity) + } + } + setCapacity(ctx, t, serverRpcClient, clients[freeIdx].ID(), 0) + for i, client := range clients { + capacity := uint64(weights[i]) + if i != freeIdx && capacity > getCapacity(ctx, t, serverRpcClient, client.ID()) { + setCapacity(ctx, t, serverRpcClient, client.ID(), capacity) + } + } + weights[freeIdx] = float64(freeCap) + for i := range clients { + weights[i] /= float64(testCap) + } + + time.Sleep(flowcontrol.DecParamDelay) + fmt.Println("Starting measurement") + fmt.Printf("Relative weights:") + for i := range clients { + fmt.Printf(" %f", weights[i]) + } + fmt.Println() + start := processedSince(nil) + for { + select { + case <-ctx.Done(): + t.Fatalf("Timeout") + default: + } + + totalCap = getTotalCap(ctx, t, serverRpcClient) + if totalCap < testCap { + fmt.Println("Total capacity underrun") + close(stop) + wg.Wait() + return false + } + + processed := processedSince(start) + var avg uint64 + fmt.Printf("Processed") + for i, p := range processed { + fmt.Printf(" %d", p) + processed[i] = uint64(float64(p) / weights[i]) + avg += processed[i] + } + avg /= uint64(len(processed)) + + if avg >= 10000 { + var maxDev float64 + for _, p := range processed { + dev := float64(int64(p-avg)) / float64(avg) + fmt.Printf(" %7.4f", dev) + if dev < 0 { + dev = -dev + } + if dev > maxDev { + maxDev = dev + } + } + fmt.Printf(" max deviation: %f totalCap: %d\n", maxDev, totalCap) + if maxDev <= testTolerance { + fmt.Println("success") + break + } + } else { + fmt.Println() + } + time.Sleep(time.Millisecond * 200) + } + } + + close(stop) + wg.Wait() + + for i, count := range reqCount { + fmt.Println("client", i, "processed", count) + } + return true + }) { + fmt.Println("restarting test") + } +} + +func getHead(ctx context.Context, t *testing.T, client *rpc.Client) (uint64, common.Hash) { + res := make(map[string]interface{}) + if err := client.CallContext(ctx, &res, "eth_getBlockByNumber", "latest", false); err != nil { + t.Fatalf("Failed to obtain head block: %v", err) + } + numStr, ok := res["number"].(string) + if !ok { + t.Fatalf("RPC block number field invalid") + } + num, err := hexutil.DecodeUint64(numStr) + if err != nil { + t.Fatalf("Failed to decode RPC block number: %v", err) + } + hashStr, ok := res["hash"].(string) + if !ok { + t.Fatalf("RPC block number field invalid") + } + hash := common.HexToHash(hashStr) + return num, hash +} + +func testRequest(ctx context.Context, t *testing.T, client *rpc.Client) bool { + //res := make(map[string]interface{}) + var res string + var addr common.Address + rand.Read(addr[:]) + c, _ := context.WithTimeout(ctx, time.Second*12) + // if err := client.CallContext(ctx, &res, "eth_getProof", addr, nil, "latest"); err != nil { + err := client.CallContext(c, &res, "eth_getBalance", addr, "latest") + if err != nil { + fmt.Println("request error:", err) + } + return err == nil +} + +func setCapacity(ctx context.Context, t *testing.T, server *rpc.Client, clientID enode.ID, cap uint64) { + if err := server.CallContext(ctx, nil, "les_setClientCapacity", clientID, cap); err != nil { + t.Fatalf("Failed to set client capacity: %v", err) + } +} + +func getCapacity(ctx context.Context, t *testing.T, server *rpc.Client, clientID enode.ID) uint64 { + var s string + if err := server.CallContext(ctx, &s, "les_getClientCapacity", clientID); err != nil { + t.Fatalf("Failed to get client capacity: %v", err) + } + cap, err := hexutil.DecodeUint64(s) + if err != nil { + t.Fatalf("Failed to decode client capacity: %v", err) + } + return cap +} + +func getTotalCap(ctx context.Context, t *testing.T, server *rpc.Client) uint64 { + var s string + if err := server.CallContext(ctx, &s, "les_totalCapacity"); err != nil { + t.Fatalf("Failed to query total capacity: %v", err) + } + total, err := hexutil.DecodeUint64(s) + if err != nil { + t.Fatalf("Failed to decode total capacity: %v", err) + } + return total +} + +func getMinCap(ctx context.Context, t *testing.T, server *rpc.Client) uint64 { + var s string + if err := server.CallContext(ctx, &s, "les_minimumCapacity"); err != nil { + t.Fatalf("Failed to query minimum capacity: %v", err) + } + min, err := hexutil.DecodeUint64(s) + if err != nil { + t.Fatalf("Failed to decode minimum capacity: %v", err) + } + return min +} + +func getFreeCap(ctx context.Context, t *testing.T, server *rpc.Client) uint64 { + var s string + if err := server.CallContext(ctx, &s, "les_freeClientCapacity"); err != nil { + t.Fatalf("Failed to query free client capacity: %v", err) + } + free, err := hexutil.DecodeUint64(s) + if err != nil { + t.Fatalf("Failed to decode free client capacity: %v", err) + } + return free +} + +func init() { + flag.Parse() + // register the Delivery service which will run as a devp2p + // protocol when using the exec adapter + adapters.RegisterServices(services) + + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + +var ( + adapter = flag.String("adapter", "exec", "type of simulation: sim|socket|exec|docker") + loglevel = flag.Int("loglevel", 0, "verbosity of logs") + nodes = flag.Int("nodes", 0, "number of nodes") +) + +var services = adapters.Services{ + "lesclient": newLesClientService, + "lesserver": newLesServerService, +} + +func NewNetwork() (*simulations.Network, func(), error) { + adapter, adapterTeardown, err := NewAdapter(*adapter, services) + if err != nil { + return nil, adapterTeardown, err + } + defaultService := "streamer" + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "0", + DefaultService: defaultService, + }) + teardown := func() { + adapterTeardown() + net.Shutdown() + } + + return net, teardown, nil +} + +func NewAdapter(adapterType string, services adapters.Services) (adapter adapters.NodeAdapter, teardown func(), err error) { + teardown = func() {} + switch adapterType { + case "sim": + adapter = adapters.NewSimAdapter(services) + // case "socket": + // adapter = adapters.NewSocketAdapter(services) + case "exec": + baseDir, err0 := ioutil.TempDir("", "les-test") + if err0 != nil { + return nil, teardown, err0 + } + teardown = func() { os.RemoveAll(baseDir) } + adapter = adapters.NewExecAdapter(baseDir) + /*case "docker": + adapter, err = adapters.NewDockerAdapter() + if err != nil { + return nil, teardown, err + }*/ + default: + return nil, teardown, errors.New("adapter needs to be one of sim, socket, exec, docker") + } + return adapter, teardown, nil +} + +func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []string, test func(ctx context.Context, net *simulations.Network, servers []*simulations.Node, clients []*simulations.Node) bool) bool { + net, teardown, err := NewNetwork() + defer teardown() + if err != nil { + t.Fatalf("Failed to create network: %v", err) + } + timeout := 1800 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + servers := make([]*simulations.Node, serverCount) + clients := make([]*simulations.Node, clientCount) + + for i := range clients { + clientconf := adapters.RandomNodeConfig() + clientconf.Services = []string{"lesclient"} + if len(clientDir) == clientCount { + clientconf.DataDir = clientDir[i] + } + client, err := net.NewNodeWithConfig(clientconf) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + clients[i] = client + } + + for i := range servers { + serverconf := adapters.RandomNodeConfig() + serverconf.Services = []string{"lesserver"} + if len(serverDir) == serverCount { + serverconf.DataDir = serverDir[i] + } + server, err := net.NewNodeWithConfig(serverconf) + if err != nil { + t.Fatalf("Failed to create server: %v", err) + } + servers[i] = server + } + + for _, client := range clients { + if err := net.Start(client.ID()); err != nil { + t.Fatalf("Failed to start client node: %v", err) + } + } + for _, server := range servers { + if err := net.Start(server.ID()); err != nil { + t.Fatalf("Failed to start server node: %v", err) + } + } + + return test(ctx, net, servers, clients) +} + +func newLesClientService(ctx *adapters.ServiceContext) (node.Service, error) { + config := eth.DefaultConfig + config.SyncMode = downloader.LightSync + config.Ethash.PowMode = ethash.ModeFake + return New(ctx.NodeContext, &config) +} + +func newLesServerService(ctx *adapters.ServiceContext) (node.Service, error) { + config := eth.DefaultConfig + config.SyncMode = downloader.FullSync + config.LightServ = testServerCapacity + config.LightPeers = testMaxClients + ethereum, err := eth.New(ctx.NodeContext, &config) + if err != nil { + return nil, err + } + + server, err := NewLesServer(ethereum, &config) + if err != nil { + return nil, err + } + ethereum.AddLesServer(server) + return ethereum, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/backend.go b/vendor/github.com/ethereum/go-ethereum/les/backend.go index a3474a68..bc4d0f21 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/backend.go +++ b/vendor/github.com/ethereum/go-ethereum/les/backend.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" @@ -78,11 +79,11 @@ type LightEthereum struct { } func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { - chainDb, err := eth.CreateDB(ctx, config, "lightchaindata") + chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } @@ -100,7 +101,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { chainConfig: chainConfig, eventMux: ctx.EventMux, peers: peers, - reqDist: newRequestDistributor(peers, quitSync), + reqDist: newRequestDistributor(peers, quitSync, &mclock.System{}), accountManager: ctx.AccountManager, engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb), shutdownChan: make(chan bool), @@ -109,8 +110,12 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), } + var trustedNodes []string + if leth.config.ULC != nil { + trustedNodes = leth.config.ULC.TrustedServers + } leth.relay = NewLesTxRelay(peers, leth.reqDist) - leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg) + leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg, trustedNodes) leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) @@ -136,10 +141,33 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { } leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) - if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, light.DefaultClientIndexerConfig, true, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, leth.serverPool, quitSync, &leth.wg); err != nil { + + if leth.protocolManager, err = NewProtocolManager( + leth.chainConfig, + light.DefaultClientIndexerConfig, + true, + config.NetworkId, + leth.eventMux, + leth.engine, + leth.peers, + leth.blockchain, + nil, + chainDb, + leth.odr, + leth.relay, + leth.serverPool, + quitSync, + &leth.wg, + config.ULC); err != nil { return nil, err } + + if leth.protocolManager.isULCEnabled() { + log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.protocolManager.ulc.trustedKeys), "minTrustedFraction", leth.protocolManager.ulc.minTrustedFraction) + leth.blockchain.DisableCheckFreq() + } leth.ApiBackend = &LesApiBackend{leth, nil} + gpoParams := config.GPO if gpoParams.Default == nil { gpoParams.Default = config.MinerGasPrice diff --git a/vendor/github.com/ethereum/go-ethereum/les/benchmark.go b/vendor/github.com/ethereum/go-ethereum/les/benchmark.go new file mode 100644 index 00000000..cb302c6e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/benchmark.go @@ -0,0 +1,353 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package les + +import ( + "encoding/binary" + "fmt" + "math/big" + "math/rand" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/les/flowcontrol" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +// requestBenchmark is an interface for different randomized request generators +type requestBenchmark interface { + // init initializes the generator for generating the given number of randomized requests + init(pm *ProtocolManager, count int) error + // request initiates sending a single request to the given peer + request(peer *peer, index int) error +} + +// benchmarkBlockHeaders implements requestBenchmark +type benchmarkBlockHeaders struct { + amount, skip int + reverse, byHash bool + offset, randMax int64 + hashes []common.Hash +} + +func (b *benchmarkBlockHeaders) init(pm *ProtocolManager, count int) error { + d := int64(b.amount-1) * int64(b.skip+1) + b.offset = 0 + b.randMax = pm.blockchain.CurrentHeader().Number.Int64() + 1 - d + if b.randMax < 0 { + return fmt.Errorf("chain is too short") + } + if b.reverse { + b.offset = d + } + if b.byHash { + b.hashes = make([]common.Hash, count) + for i := range b.hashes { + b.hashes[i] = rawdb.ReadCanonicalHash(pm.chainDb, uint64(b.offset+rand.Int63n(b.randMax))) + } + } + return nil +} + +func (b *benchmarkBlockHeaders) request(peer *peer, index int) error { + if b.byHash { + return peer.RequestHeadersByHash(0, 0, b.hashes[index], b.amount, b.skip, b.reverse) + } else { + return peer.RequestHeadersByNumber(0, 0, uint64(b.offset+rand.Int63n(b.randMax)), b.amount, b.skip, b.reverse) + } +} + +// benchmarkBodiesOrReceipts implements requestBenchmark +type benchmarkBodiesOrReceipts struct { + receipts bool + hashes []common.Hash +} + +func (b *benchmarkBodiesOrReceipts) init(pm *ProtocolManager, count int) error { + randMax := pm.blockchain.CurrentHeader().Number.Int64() + 1 + b.hashes = make([]common.Hash, count) + for i := range b.hashes { + b.hashes[i] = rawdb.ReadCanonicalHash(pm.chainDb, uint64(rand.Int63n(randMax))) + } + return nil +} + +func (b *benchmarkBodiesOrReceipts) request(peer *peer, index int) error { + if b.receipts { + return peer.RequestReceipts(0, 0, []common.Hash{b.hashes[index]}) + } else { + return peer.RequestBodies(0, 0, []common.Hash{b.hashes[index]}) + } +} + +// benchmarkProofsOrCode implements requestBenchmark +type benchmarkProofsOrCode struct { + code bool + headHash common.Hash +} + +func (b *benchmarkProofsOrCode) init(pm *ProtocolManager, count int) error { + b.headHash = pm.blockchain.CurrentHeader().Hash() + return nil +} + +func (b *benchmarkProofsOrCode) request(peer *peer, index int) error { + key := make([]byte, 32) + rand.Read(key) + if b.code { + return peer.RequestCode(0, 0, []CodeReq{{BHash: b.headHash, AccKey: key}}) + } else { + return peer.RequestProofs(0, 0, []ProofReq{{BHash: b.headHash, Key: key}}) + } +} + +// benchmarkHelperTrie implements requestBenchmark +type benchmarkHelperTrie struct { + bloom bool + reqCount int + sectionCount, headNum uint64 +} + +func (b *benchmarkHelperTrie) init(pm *ProtocolManager, count int) error { + if b.bloom { + b.sectionCount, b.headNum, _ = pm.server.bloomTrieIndexer.Sections() + } else { + b.sectionCount, _, _ = pm.server.chtIndexer.Sections() + b.sectionCount /= (params.CHTFrequencyClient / params.CHTFrequencyServer) + b.headNum = b.sectionCount*params.CHTFrequencyClient - 1 + } + if b.sectionCount == 0 { + return fmt.Errorf("no processed sections available") + } + return nil +} + +func (b *benchmarkHelperTrie) request(peer *peer, index int) error { + reqs := make([]HelperTrieReq, b.reqCount) + + if b.bloom { + bitIdx := uint16(rand.Intn(2048)) + for i := range reqs { + key := make([]byte, 10) + binary.BigEndian.PutUint16(key[:2], bitIdx) + binary.BigEndian.PutUint64(key[2:], uint64(rand.Int63n(int64(b.sectionCount)))) + reqs[i] = HelperTrieReq{Type: htBloomBits, TrieIdx: b.sectionCount - 1, Key: key} + } + } else { + for i := range reqs { + key := make([]byte, 8) + binary.BigEndian.PutUint64(key[:], uint64(rand.Int63n(int64(b.headNum)))) + reqs[i] = HelperTrieReq{Type: htCanonical, TrieIdx: b.sectionCount - 1, Key: key, AuxReq: auxHeader} + } + } + + return peer.RequestHelperTrieProofs(0, 0, reqs) +} + +// benchmarkTxSend implements requestBenchmark +type benchmarkTxSend struct { + txs types.Transactions +} + +func (b *benchmarkTxSend) init(pm *ProtocolManager, count int) error { + key, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(key.PublicKey) + signer := types.NewEIP155Signer(big.NewInt(18)) + b.txs = make(types.Transactions, count) + + for i := range b.txs { + data := make([]byte, txSizeCostLimit) + rand.Read(data) + tx, err := types.SignTx(types.NewTransaction(0, addr, new(big.Int), 0, new(big.Int), data), signer, key) + if err != nil { + panic(err) + } + b.txs[i] = tx + } + return nil +} + +func (b *benchmarkTxSend) request(peer *peer, index int) error { + enc, _ := rlp.EncodeToBytes(types.Transactions{b.txs[index]}) + return peer.SendTxs(0, 0, enc) +} + +// benchmarkTxStatus implements requestBenchmark +type benchmarkTxStatus struct{} + +func (b *benchmarkTxStatus) init(pm *ProtocolManager, count int) error { + return nil +} + +func (b *benchmarkTxStatus) request(peer *peer, index int) error { + var hash common.Hash + rand.Read(hash[:]) + return peer.RequestTxStatus(0, 0, []common.Hash{hash}) +} + +// benchmarkSetup stores measurement data for a single benchmark type +type benchmarkSetup struct { + req requestBenchmark + totalCount int + totalTime, avgTime time.Duration + maxInSize, maxOutSize uint32 + err error +} + +// runBenchmark runs a benchmark cycle for all benchmark types in the specified +// number of passes +func (pm *ProtocolManager) runBenchmark(benchmarks []requestBenchmark, passCount int, targetTime time.Duration) []*benchmarkSetup { + setup := make([]*benchmarkSetup, len(benchmarks)) + for i, b := range benchmarks { + setup[i] = &benchmarkSetup{req: b} + } + for i := 0; i < passCount; i++ { + log.Info("Running benchmark", "pass", i+1, "total", passCount) + todo := make([]*benchmarkSetup, len(benchmarks)) + copy(todo, setup) + for len(todo) > 0 { + // select a random element + index := rand.Intn(len(todo)) + next := todo[index] + todo[index] = todo[len(todo)-1] + todo = todo[:len(todo)-1] + + if next.err == nil { + // calculate request count + count := 50 + if next.totalTime > 0 { + count = int(uint64(next.totalCount) * uint64(targetTime) / uint64(next.totalTime)) + } + if err := pm.measure(next, count); err != nil { + next.err = err + } + } + } + } + log.Info("Benchmark completed") + + for _, s := range setup { + if s.err == nil { + s.avgTime = s.totalTime / time.Duration(s.totalCount) + } + } + return setup +} + +// meteredPipe implements p2p.MsgReadWriter and remembers the largest single +// message size sent through the pipe +type meteredPipe struct { + rw p2p.MsgReadWriter + maxSize uint32 +} + +func (m *meteredPipe) ReadMsg() (p2p.Msg, error) { + return m.rw.ReadMsg() +} + +func (m *meteredPipe) WriteMsg(msg p2p.Msg) error { + if msg.Size > m.maxSize { + m.maxSize = msg.Size + } + return m.rw.WriteMsg(msg) +} + +// measure runs a benchmark for a single type in a single pass, with the given +// number of requests +func (pm *ProtocolManager) measure(setup *benchmarkSetup, count int) error { + clientPipe, serverPipe := p2p.MsgPipe() + clientMeteredPipe := &meteredPipe{rw: clientPipe} + serverMeteredPipe := &meteredPipe{rw: serverPipe} + var id enode.ID + rand.Read(id[:]) + clientPeer := pm.newPeer(lpv2, NetworkId, p2p.NewPeer(id, "client", nil), clientMeteredPipe) + serverPeer := pm.newPeer(lpv2, NetworkId, p2p.NewPeer(id, "server", nil), serverMeteredPipe) + serverPeer.sendQueue = newExecQueue(count) + serverPeer.announceType = announceTypeNone + serverPeer.fcCosts = make(requestCostTable) + c := &requestCosts{} + for code := range requests { + serverPeer.fcCosts[code] = c + } + serverPeer.fcParams = flowcontrol.ServerParams{BufLimit: 1, MinRecharge: 1} + serverPeer.fcClient = flowcontrol.NewClientNode(pm.server.fcManager, serverPeer.fcParams) + defer serverPeer.fcClient.Disconnect() + + if err := setup.req.init(pm, count); err != nil { + return err + } + + errCh := make(chan error, 10) + start := mclock.Now() + + go func() { + for i := 0; i < count; i++ { + if err := setup.req.request(clientPeer, i); err != nil { + errCh <- err + return + } + } + }() + go func() { + for i := 0; i < count; i++ { + if err := pm.handleMsg(serverPeer); err != nil { + errCh <- err + return + } + } + }() + go func() { + for i := 0; i < count; i++ { + msg, err := clientPipe.ReadMsg() + if err != nil { + errCh <- err + return + } + var i interface{} + msg.Decode(&i) + } + // at this point we can be sure that the other two + // goroutines finished successfully too + close(errCh) + }() + select { + case err := <-errCh: + if err != nil { + return err + } + case <-pm.quitSync: + clientPipe.Close() + serverPipe.Close() + return fmt.Errorf("Benchmark cancelled") + } + + setup.totalTime += time.Duration(mclock.Now() - start) + setup.totalCount += count + setup.maxInSize = clientMeteredPipe.maxSize + setup.maxOutSize = serverMeteredPipe.maxSize + clientPipe.Close() + serverPipe.Close() + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/costtracker.go b/vendor/github.com/ethereum/go-ethereum/les/costtracker.go new file mode 100644 index 00000000..69531937 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/costtracker.go @@ -0,0 +1,388 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more detailct. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package les + +import ( + "encoding/binary" + "math" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/les/flowcontrol" + "github.com/ethereum/go-ethereum/log" +) + +const makeCostStats = false // make request cost statistics during operation + +var ( + // average request cost estimates based on serving time + reqAvgTimeCost = requestCostTable{ + GetBlockHeadersMsg: {150000, 30000}, + GetBlockBodiesMsg: {0, 700000}, + GetReceiptsMsg: {0, 1000000}, + GetCodeMsg: {0, 450000}, + GetProofsV1Msg: {0, 600000}, + GetProofsV2Msg: {0, 600000}, + GetHeaderProofsMsg: {0, 1000000}, + GetHelperTrieProofsMsg: {0, 1000000}, + SendTxMsg: {0, 450000}, + SendTxV2Msg: {0, 450000}, + GetTxStatusMsg: {0, 250000}, + } + // maximum incoming message size estimates + reqMaxInSize = requestCostTable{ + GetBlockHeadersMsg: {40, 0}, + GetBlockBodiesMsg: {0, 40}, + GetReceiptsMsg: {0, 40}, + GetCodeMsg: {0, 80}, + GetProofsV1Msg: {0, 80}, + GetProofsV2Msg: {0, 80}, + GetHeaderProofsMsg: {0, 20}, + GetHelperTrieProofsMsg: {0, 20}, + SendTxMsg: {0, 66000}, + SendTxV2Msg: {0, 66000}, + GetTxStatusMsg: {0, 50}, + } + // maximum outgoing message size estimates + reqMaxOutSize = requestCostTable{ + GetBlockHeadersMsg: {0, 556}, + GetBlockBodiesMsg: {0, 100000}, + GetReceiptsMsg: {0, 200000}, + GetCodeMsg: {0, 50000}, + GetProofsV1Msg: {0, 4000}, + GetProofsV2Msg: {0, 4000}, + GetHeaderProofsMsg: {0, 4000}, + GetHelperTrieProofsMsg: {0, 4000}, + SendTxMsg: {0, 0}, + SendTxV2Msg: {0, 100}, + GetTxStatusMsg: {0, 100}, + } + minBufLimit = uint64(50000000 * maxCostFactor) // minimum buffer limit allowed for a client + minCapacity = (minBufLimit-1)/bufLimitRatio + 1 // minimum capacity allowed for a client +) + +const ( + maxCostFactor = 2 // ratio of maximum and average cost estimates + gfInitWeight = time.Second * 10 + gfMaxWeight = time.Hour + gfUsageThreshold = 0.5 + gfUsageTC = time.Second + gfDbKey = "_globalCostFactor" +) + +// costTracker is responsible for calculating costs and cost estimates on the +// server side. It continuously updates the global cost factor which is defined +// as the number of cost units per nanosecond of serving time in a single thread. +// It is based on statistics collected during serving requests in high-load periods +// and practically acts as a one-dimension request price scaling factor over the +// pre-defined cost estimate table. Instead of scaling the cost values, the real +// value of cost units is changed by applying the factor to the serving times. This +// is more convenient because the changes in the cost factor can be applied immediately +// without always notifying the clients about the changed cost tables. +type costTracker struct { + db ethdb.Database + stopCh chan chan struct{} + + inSizeFactor, outSizeFactor float64 + gf, utilTarget float64 + + gfUpdateCh chan gfUpdate + gfLock sync.RWMutex + totalRechargeCh chan uint64 + + stats map[uint64][]uint64 +} + +// newCostTracker creates a cost tracker and loads the cost factor statistics from the database +func newCostTracker(db ethdb.Database, config *eth.Config) *costTracker { + utilTarget := float64(config.LightServ) * flowcontrol.FixedPointMultiplier / 100 + ct := &costTracker{ + db: db, + stopCh: make(chan chan struct{}), + utilTarget: utilTarget, + } + if config.LightBandwidthIn > 0 { + ct.inSizeFactor = utilTarget / float64(config.LightBandwidthIn) + } + if config.LightBandwidthOut > 0 { + ct.outSizeFactor = utilTarget / float64(config.LightBandwidthOut) + } + if makeCostStats { + ct.stats = make(map[uint64][]uint64) + for code := range reqAvgTimeCost { + ct.stats[code] = make([]uint64, 10) + } + } + ct.gfLoop() + return ct +} + +// stop stops the cost tracker and saves the cost factor statistics to the database +func (ct *costTracker) stop() { + stopCh := make(chan struct{}) + ct.stopCh <- stopCh + <-stopCh + if makeCostStats { + ct.printStats() + } +} + +// makeCostList returns upper cost estimates based on the hardcoded cost estimate +// tables and the optionally specified incoming/outgoing bandwidth limits +func (ct *costTracker) makeCostList() RequestCostList { + maxCost := func(avgTime, inSize, outSize uint64) uint64 { + globalFactor := ct.globalFactor() + + cost := avgTime * maxCostFactor + inSizeCost := uint64(float64(inSize) * ct.inSizeFactor * globalFactor * maxCostFactor) + if inSizeCost > cost { + cost = inSizeCost + } + outSizeCost := uint64(float64(outSize) * ct.outSizeFactor * globalFactor * maxCostFactor) + if outSizeCost > cost { + cost = outSizeCost + } + return cost + } + var list RequestCostList + for code, data := range reqAvgTimeCost { + list = append(list, requestCostListItem{ + MsgCode: code, + BaseCost: maxCost(data.baseCost, reqMaxInSize[code].baseCost, reqMaxOutSize[code].baseCost), + ReqCost: maxCost(data.reqCost, reqMaxInSize[code].reqCost, reqMaxOutSize[code].reqCost), + }) + } + return list +} + +type gfUpdate struct { + avgTime, servingTime float64 +} + +// gfLoop starts an event loop which updates the global cost factor which is +// calculated as a weighted average of the average estimate / serving time ratio. +// The applied weight equals the serving time if gfUsage is over a threshold, +// zero otherwise. gfUsage is the recent average serving time per time unit in +// an exponential moving window. This ensures that statistics are collected only +// under high-load circumstances where the measured serving times are relevant. +// The total recharge parameter of the flow control system which controls the +// total allowed serving time per second but nominated in cost units, should +// also be scaled with the cost factor and is also updated by this loop. +func (ct *costTracker) gfLoop() { + var gfUsage, gfSum, gfWeight float64 + lastUpdate := mclock.Now() + expUpdate := lastUpdate + + data, _ := ct.db.Get([]byte(gfDbKey)) + if len(data) == 16 { + gfSum = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) + gfWeight = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) + } + if gfWeight < float64(gfInitWeight) { + gfSum = float64(gfInitWeight) + gfWeight = float64(gfInitWeight) + } + gf := gfSum / gfWeight + ct.gf = gf + ct.gfUpdateCh = make(chan gfUpdate, 100) + + go func() { + for { + select { + case r := <-ct.gfUpdateCh: + now := mclock.Now() + max := r.servingTime * gf + if r.avgTime > max { + max = r.avgTime + } + dt := float64(now - expUpdate) + expUpdate = now + gfUsage = gfUsage*math.Exp(-dt/float64(gfUsageTC)) + max*1000000/float64(gfUsageTC) + + if gfUsage >= gfUsageThreshold*ct.utilTarget*gf { + gfSum += r.avgTime + gfWeight += r.servingTime + if time.Duration(now-lastUpdate) > time.Second { + gf = gfSum / gfWeight + if gfWeight >= float64(gfMaxWeight) { + gfSum = gf * float64(gfMaxWeight) + gfWeight = float64(gfMaxWeight) + } + lastUpdate = now + ct.gfLock.Lock() + ct.gf = gf + ch := ct.totalRechargeCh + ct.gfLock.Unlock() + if ch != nil { + select { + case ct.totalRechargeCh <- uint64(ct.utilTarget * gf): + default: + } + } + log.Debug("global cost factor updated", "gf", gf, "weight", time.Duration(gfWeight)) + } + } + case stopCh := <-ct.stopCh: + var data [16]byte + binary.BigEndian.PutUint64(data[0:8], math.Float64bits(gfSum)) + binary.BigEndian.PutUint64(data[8:16], math.Float64bits(gfWeight)) + ct.db.Put([]byte(gfDbKey), data[:]) + log.Debug("global cost factor saved", "sum", time.Duration(gfSum), "weight", time.Duration(gfWeight)) + close(stopCh) + return + } + } + }() +} + +// globalFactor returns the current value of the global cost factor +func (ct *costTracker) globalFactor() float64 { + ct.gfLock.RLock() + defer ct.gfLock.RUnlock() + + return ct.gf +} + +// totalRecharge returns the current total recharge parameter which is used by +// flowcontrol.ClientManager and is scaled by the global cost factor +func (ct *costTracker) totalRecharge() uint64 { + ct.gfLock.RLock() + defer ct.gfLock.RUnlock() + + return uint64(ct.gf * ct.utilTarget) +} + +// subscribeTotalRecharge returns all future updates to the total recharge value +// through a channel and also returns the current value +func (ct *costTracker) subscribeTotalRecharge(ch chan uint64) uint64 { + ct.gfLock.Lock() + defer ct.gfLock.Unlock() + + ct.totalRechargeCh = ch + return uint64(ct.gf * ct.utilTarget) +} + +// updateStats updates the global cost factor and (if enabled) the real cost vs. +// average estimate statistics +func (ct *costTracker) updateStats(code, amount, servingTime, realCost uint64) { + avg := reqAvgTimeCost[code] + avgTime := avg.baseCost + amount*avg.reqCost + select { + case ct.gfUpdateCh <- gfUpdate{float64(avgTime), float64(servingTime)}: + default: + } + if makeCostStats { + realCost <<= 4 + l := 0 + for l < 9 && realCost > avgTime { + l++ + realCost >>= 1 + } + atomic.AddUint64(&ct.stats[code][l], 1) + } +} + +// realCost calculates the final cost of a request based on actual serving time, +// incoming and outgoing message size +// +// Note: message size is only taken into account if bandwidth limitation is applied +// and the cost based on either message size is greater than the cost based on +// serving time. A maximum of the three costs is applied instead of their sum +// because the three limited resources (serving thread time and i/o bandwidth) can +// also be maxed out simultaneously. +func (ct *costTracker) realCost(servingTime uint64, inSize, outSize uint32) uint64 { + cost := float64(servingTime) + inSizeCost := float64(inSize) * ct.inSizeFactor + if inSizeCost > cost { + cost = inSizeCost + } + outSizeCost := float64(outSize) * ct.outSizeFactor + if outSizeCost > cost { + cost = outSizeCost + } + return uint64(cost * ct.globalFactor()) +} + +// printStats prints the distribution of real request cost relative to the average estimates +func (ct *costTracker) printStats() { + if ct.stats == nil { + return + } + for code, arr := range ct.stats { + log.Info("Request cost statistics", "code", code, "1/16", arr[0], "1/8", arr[1], "1/4", arr[2], "1/2", arr[3], "1", arr[4], "2", arr[5], "4", arr[6], "8", arr[7], "16", arr[8], ">16", arr[9]) + } +} + +type ( + // requestCostTable assigns a cost estimate function to each request type + // which is a linear function of the requested amount + // (cost = baseCost + reqCost * amount) + requestCostTable map[uint64]*requestCosts + requestCosts struct { + baseCost, reqCost uint64 + } + + // RequestCostList is a list representation of request costs which is used for + // database storage and communication through the network + RequestCostList []requestCostListItem + requestCostListItem struct { + MsgCode, BaseCost, ReqCost uint64 + } +) + +// getCost calculates the estimated cost for a given request type and amount +func (table requestCostTable) getCost(code, amount uint64) uint64 { + costs := table[code] + return costs.baseCost + amount*costs.reqCost +} + +// decode converts a cost list to a cost table +func (list RequestCostList) decode() requestCostTable { + table := make(requestCostTable) + for _, e := range list { + table[e.MsgCode] = &requestCosts{ + baseCost: e.BaseCost, + reqCost: e.ReqCost, + } + } + return table +} + +// testCostList returns a dummy request cost list used by tests +func testCostList() RequestCostList { + cl := make(RequestCostList, len(reqAvgTimeCost)) + var max uint64 + for code := range reqAvgTimeCost { + if code > max { + max = code + } + } + i := 0 + for code := uint64(0); code <= max; code++ { + if _, ok := reqAvgTimeCost[code]; ok { + cl[i].MsgCode = code + cl[i].BaseCost = 0 + cl[i].ReqCost = 0 + i++ + } + } + return cl +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/distributor.go b/vendor/github.com/ethereum/go-ethereum/les/distributor.go index f90765b6..1de267f2 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/distributor.go +++ b/vendor/github.com/ethereum/go-ethereum/les/distributor.go @@ -14,20 +14,21 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package les import ( "container/list" "sync" "time" + + "github.com/ethereum/go-ethereum/common/mclock" ) // requestDistributor implements a mechanism that distributes requests to // suitable peers, obeying flow control rules and prioritizing them in creation // order (even when a resend is necessary). type requestDistributor struct { + clock mclock.Clock reqQueue *list.List lastReqOrder uint64 peers map[distPeer]struct{} @@ -67,8 +68,9 @@ type distReq struct { } // newRequestDistributor creates a new request distributor -func newRequestDistributor(peers *peerSet, stopChn chan struct{}) *requestDistributor { +func newRequestDistributor(peers *peerSet, stopChn chan struct{}, clock mclock.Clock) *requestDistributor { d := &requestDistributor{ + clock: clock, reqQueue: list.New(), loopChn: make(chan struct{}, 2), stopChn: stopChn, @@ -148,7 +150,7 @@ func (d *requestDistributor) loop() { wait = distMaxWait } go func() { - time.Sleep(wait) + d.clock.Sleep(wait) d.loopChn <- struct{}{} }() break loop diff --git a/vendor/github.com/ethereum/go-ethereum/les/distributor_test.go b/vendor/github.com/ethereum/go-ethereum/les/distributor_test.go index 8c7621f2..d2247212 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/distributor_test.go +++ b/vendor/github.com/ethereum/go-ethereum/les/distributor_test.go @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package les import ( @@ -23,6 +21,8 @@ import ( "sync" "testing" "time" + + "github.com/ethereum/go-ethereum/common/mclock" ) type testDistReq struct { @@ -121,7 +121,7 @@ func testRequestDistributor(t *testing.T, resend bool) { stop := make(chan struct{}) defer close(stop) - dist := newRequestDistributor(nil, stop) + dist := newRequestDistributor(nil, stop, &mclock.System{}) var peers [testDistPeerCount]*testDistPeer for i := range peers { peers[i] = &testDistPeer{} diff --git a/vendor/github.com/ethereum/go-ethereum/les/fetcher.go b/vendor/github.com/ethereum/go-ethereum/les/fetcher.go index f0d3b188..057552f5 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/fetcher.go +++ b/vendor/github.com/ethereum/go-ethereum/les/fetcher.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( @@ -43,7 +42,7 @@ const ( type lightFetcher struct { pm *ProtocolManager odr *LesOdr - chain *light.LightChain + chain lightChain lock sync.Mutex // lock protects access to the fetcher's internal state variables except sent requests maxConfirmedTd *big.Int @@ -52,11 +51,19 @@ type lightFetcher struct { syncing bool syncDone chan *peer - reqMu sync.RWMutex // reqMu protects access to sent header fetch requests - requested map[uint64]fetchRequest - deliverChn chan fetchResponse - timeoutChn chan uint64 - requestChn chan bool // true if initiated from outside + reqMu sync.RWMutex // reqMu protects access to sent header fetch requests + requested map[uint64]fetchRequest + deliverChn chan fetchResponse + timeoutChn chan uint64 + requestChn chan bool // true if initiated from outside + lastTrustedHeader *types.Header +} + +// lightChain extends the BlockChain interface by locking. +type lightChain interface { + BlockChain + LockChain() + UnlockChain() } // fetcherPeerInfo holds fetcher-specific information about each active peer @@ -141,36 +148,40 @@ func (f *lightFetcher) syncLoop() { s := requesting requesting = false var ( - rq *distReq - reqID uint64 + rq *distReq + reqID uint64 + syncing bool ) + if !f.syncing && !(newAnnounce && s) { - rq, reqID = f.nextRequest() + rq, reqID, syncing = f.nextRequest() } - syncing := f.syncing f.lock.Unlock() if rq != nil { requesting = true - _, ok := <-f.pm.reqDist.queue(rq) - if !ok { + if _, ok := <-f.pm.reqDist.queue(rq); ok { + if syncing { + f.lock.Lock() + f.syncing = true + f.lock.Unlock() + } else { + go func() { + time.Sleep(softRequestTimeout) + f.reqMu.Lock() + req, ok := f.requested[reqID] + if ok { + req.timeout = true + f.requested[reqID] = req + } + f.reqMu.Unlock() + // keep starting new requests while possible + f.requestChn <- false + }() + } + } else { f.requestChn <- false } - - if !syncing { - go func() { - time.Sleep(softRequestTimeout) - f.reqMu.Lock() - req, ok := f.requested[reqID] - if ok { - req.timeout = true - f.requested[reqID] = req - } - f.reqMu.Unlock() - // keep starting new requests while possible - f.requestChn <- false - }() - } } case reqID := <-f.timeoutChn: f.reqMu.Lock() @@ -209,6 +220,7 @@ func (f *lightFetcher) syncLoop() { f.checkSyncedHeaders(p) f.syncing = false f.lock.Unlock() + f.requestChn <- false } } } @@ -223,7 +235,6 @@ func (f *lightFetcher) registerPeer(p *peer) { f.lock.Lock() defer f.lock.Unlock() - f.peers[p] = &fetcherPeerInfo{nodeByHash: make(map[common.Hash]*fetcherTreeNode)} } @@ -276,8 +287,10 @@ func (f *lightFetcher) announce(p *peer, head *announceData) { fp.nodeCnt = 0 fp.nodeByHash = make(map[common.Hash]*fetcherTreeNode) } + // check if the node count is too high to add new nodes, discard oldest ones if necessary if n != nil { - // check if the node count is too high to add new nodes, discard oldest ones if necessary + // n is now the reorg common ancestor, add a new branch of nodes + // check if the node count is too high to add new nodes locked := false for uint64(fp.nodeCnt)+head.Number-n.number > maxNodeCount && fp.root != nil { if !locked { @@ -321,6 +334,7 @@ func (f *lightFetcher) announce(p *peer, head *announceData) { fp.nodeByHash[n.hash] = n } } + if n == nil { // could not find reorg common ancestor or had to delete entire tree, a new root and a resync is needed if fp.root != nil { @@ -405,102 +419,156 @@ func (f *lightFetcher) requestedID(reqID uint64) bool { // nextRequest selects the peer and announced head to be requested next, amount // to be downloaded starting from the head backwards is also returned -func (f *lightFetcher) nextRequest() (*distReq, uint64) { +func (f *lightFetcher) nextRequest() (*distReq, uint64, bool) { var ( - bestHash common.Hash - bestAmount uint64 + bestHash common.Hash + bestAmount uint64 + bestTd *big.Int + bestSyncing bool ) - bestTd := f.maxConfirmedTd - bestSyncing := false + bestHash, bestAmount, bestTd, bestSyncing = f.findBestRequest() - for p, fp := range f.peers { - for hash, n := range fp.nodeByHash { - if !f.checkKnownNode(p, n) && !n.requested && (bestTd == nil || n.td.Cmp(bestTd) >= 0) { - amount := f.requestAmount(p, n) - if bestTd == nil || n.td.Cmp(bestTd) > 0 || amount < bestAmount { - bestHash = hash - bestAmount = amount - bestTd = n.td - bestSyncing = fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root) - } - } - } - } if bestTd == f.maxConfirmedTd { - return nil, 0 + return nil, 0, false } - f.syncing = bestSyncing - var rq *distReq reqID := genReqID() - if f.syncing { - rq = &distReq{ - getCost: func(dp distPeer) uint64 { - return 0 - }, - canSend: func(dp distPeer) bool { - p := dp.(*peer) - f.lock.Lock() - defer f.lock.Unlock() - - fp := f.peers[p] - return fp != nil && fp.nodeByHash[bestHash] != nil - }, - request: func(dp distPeer) func() { - go func() { - p := dp.(*peer) - p.Log().Debug("Synchronisation started") - f.pm.synchronise(p) - f.syncDone <- p - }() - return nil - }, - } + if bestSyncing { + rq = f.newFetcherDistReqForSync(bestHash) } else { - rq = &distReq{ - getCost: func(dp distPeer) uint64 { - p := dp.(*peer) - return p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)) - }, - canSend: func(dp distPeer) bool { - p := dp.(*peer) - f.lock.Lock() - defer f.lock.Unlock() + rq = f.newFetcherDistReq(bestHash, reqID, bestAmount) + } + return rq, reqID, bestSyncing +} - fp := f.peers[p] - if fp == nil { - return false - } - n := fp.nodeByHash[bestHash] - return n != nil && !n.requested - }, - request: func(dp distPeer) func() { - p := dp.(*peer) - f.lock.Lock() - fp := f.peers[p] - if fp != nil { - n := fp.nodeByHash[bestHash] - if n != nil { - n.requested = true - } - } - f.lock.Unlock() +// findBestRequest finds the best head to request that has been announced by but not yet requested from a known peer. +// It also returns the announced Td (which should be verified after fetching the head), +// the necessary amount to request and whether a downloader sync is necessary instead of a normal header request. +func (f *lightFetcher) findBestRequest() (bestHash common.Hash, bestAmount uint64, bestTd *big.Int, bestSyncing bool) { + bestTd = f.maxConfirmedTd + bestSyncing = false - cost := p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)) - p.fcServer.QueueRequest(reqID, cost) - f.reqMu.Lock() - f.requested[reqID] = fetchRequest{hash: bestHash, amount: bestAmount, peer: p, sent: mclock.Now()} - f.reqMu.Unlock() - go func() { - time.Sleep(hardRequestTimeout) - f.timeoutChn <- reqID - }() - return func() { p.RequestHeadersByHash(reqID, cost, bestHash, int(bestAmount), 0, true) } - }, + for p, fp := range f.peers { + for hash, n := range fp.nodeByHash { + if f.checkKnownNode(p, n) || n.requested { + continue + } + + //if ulc mode is disabled, isTrustedHash returns true + amount := f.requestAmount(p, n) + if (bestTd == nil || n.td.Cmp(bestTd) > 0 || amount < bestAmount) && (f.isTrustedHash(hash) || f.maxConfirmedTd.Int64() == 0) { + bestHash = hash + bestTd = n.td + bestAmount = amount + bestSyncing = fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root) + } } } - return rq, reqID + return +} + +// isTrustedHash checks if the block can be trusted by the minimum trusted fraction. +func (f *lightFetcher) isTrustedHash(hash common.Hash) bool { + if !f.pm.isULCEnabled() { + return true + } + + var numAgreed int + for p, fp := range f.peers { + if !p.isTrusted { + continue + } + if _, ok := fp.nodeByHash[hash]; !ok { + continue + } + + numAgreed++ + } + + return 100*numAgreed/len(f.pm.ulc.trustedKeys) >= f.pm.ulc.minTrustedFraction +} + +func (f *lightFetcher) newFetcherDistReqForSync(bestHash common.Hash) *distReq { + return &distReq{ + getCost: func(dp distPeer) uint64 { + return 0 + }, + canSend: func(dp distPeer) bool { + p := dp.(*peer) + f.lock.Lock() + defer f.lock.Unlock() + + if p.isOnlyAnnounce { + return false + } + + fp := f.peers[p] + return fp != nil && fp.nodeByHash[bestHash] != nil + }, + request: func(dp distPeer) func() { + if f.pm.isULCEnabled() { + //keep last trusted header before sync + f.setLastTrustedHeader(f.chain.CurrentHeader()) + } + go func() { + p := dp.(*peer) + p.Log().Debug("Synchronisation started") + f.pm.synchronise(p) + f.syncDone <- p + }() + return nil + }, + } +} + +// newFetcherDistReq creates a new request for the distributor. +func (f *lightFetcher) newFetcherDistReq(bestHash common.Hash, reqID uint64, bestAmount uint64) *distReq { + return &distReq{ + getCost: func(dp distPeer) uint64 { + p := dp.(*peer) + return p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)) + }, + canSend: func(dp distPeer) bool { + p := dp.(*peer) + f.lock.Lock() + defer f.lock.Unlock() + + if p.isOnlyAnnounce { + return false + } + + fp := f.peers[p] + if fp == nil { + return false + } + n := fp.nodeByHash[bestHash] + return n != nil && !n.requested + }, + request: func(dp distPeer) func() { + p := dp.(*peer) + f.lock.Lock() + fp := f.peers[p] + if fp != nil { + n := fp.nodeByHash[bestHash] + if n != nil { + n.requested = true + } + } + f.lock.Unlock() + + cost := p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)) + p.fcServer.QueuedRequest(reqID, cost) + f.reqMu.Lock() + f.requested[reqID] = fetchRequest{hash: bestHash, amount: bestAmount, peer: p, sent: mclock.Now()} + f.reqMu.Unlock() + go func() { + time.Sleep(hardRequestTimeout) + f.timeoutChn <- reqID + }() + return func() { p.RequestHeadersByHash(reqID, cost, bestHash, int(bestAmount), 0, true) } + }, + } } // deliverHeaders delivers header download request responses for processing @@ -518,6 +586,7 @@ func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) boo for i, header := range resp.headers { headers[int(req.amount)-1-i] = header } + if _, err := f.chain.InsertHeaderChain(headers, 1); err != nil { if err == consensus.ErrFutureBlock { return true @@ -542,6 +611,7 @@ func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) boo // downloaded and validated batch or headers func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) { var maxTd *big.Int + for p, fp := range f.peers { if !f.checkAnnouncedHeaders(fp, headers, tds) { p.Log().Debug("Inconsistent announcement") @@ -551,6 +621,7 @@ func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) { maxTd = fp.confirmedTd } } + if maxTd != nil { f.updateMaxConfirmedTd(maxTd) } @@ -638,22 +709,72 @@ func (f *lightFetcher) checkSyncedHeaders(p *peer) { p.Log().Debug("Unknown peer to check sync headers") return } + n := fp.lastAnnounced var td *big.Int + + var h *types.Header + if f.pm.isULCEnabled() { + var unapprovedHashes []common.Hash + // Overwrite last announced for ULC mode + h, unapprovedHashes = f.lastTrustedTreeNode(p) + //rollback untrusted blocks + f.chain.Rollback(unapprovedHashes) + //overwrite to last trusted + n = fp.nodeByHash[h.Hash()] + } + + //find last valid block for n != nil { if td = f.chain.GetTd(n.hash, n.number); td != nil { break } n = n.parent } - // now n is the latest downloaded header after syncing + + // Now n is the latest downloaded/approved header after syncing if n == nil { p.Log().Debug("Synchronisation failed") go f.pm.removePeer(p.id) - } else { - header := f.chain.GetHeader(n.hash, n.number) - f.newHeaders([]*types.Header{header}, []*big.Int{td}) + return } + header := f.chain.GetHeader(n.hash, n.number) + f.newHeaders([]*types.Header{header}, []*big.Int{td}) +} + +// lastTrustedTreeNode return last approved treeNode and a list of unapproved hashes +func (f *lightFetcher) lastTrustedTreeNode(p *peer) (*types.Header, []common.Hash) { + unapprovedHashes := make([]common.Hash, 0) + current := f.chain.CurrentHeader() + + if f.lastTrustedHeader == nil { + return current, unapprovedHashes + } + + canonical := f.chain.CurrentHeader() + if canonical.Number.Uint64() > f.lastTrustedHeader.Number.Uint64() { + canonical = f.chain.GetHeaderByNumber(f.lastTrustedHeader.Number.Uint64()) + } + commonAncestor := rawdb.FindCommonAncestor(f.pm.chainDb, canonical, f.lastTrustedHeader) + if commonAncestor == nil { + log.Error("Common ancestor of last trusted header and canonical header is nil", "canonical hash", canonical.Hash(), "trusted hash", f.lastTrustedHeader.Hash()) + return current, unapprovedHashes + } + + for current.Hash() == commonAncestor.Hash() { + if f.isTrustedHash(current.Hash()) { + break + } + unapprovedHashes = append(unapprovedHashes, current.Hash()) + current = f.chain.GetHeader(current.ParentHash, current.Number.Uint64()-1) + } + return current, unapprovedHashes +} + +func (f *lightFetcher) setLastTrustedHeader(h *types.Header) { + f.lock.Lock() + defer f.lock.Unlock() + f.lastTrustedHeader = h } // checkKnownNode checks if a block tree node is known (downloaded and validated) @@ -745,6 +866,7 @@ func (f *lightFetcher) updateMaxConfirmedTd(td *big.Int) { if f.lastUpdateStats != nil { f.lastUpdateStats.next = newEntry } + f.lastUpdateStats = newEntry for p := range f.peers { f.checkUpdateStats(p, newEntry) @@ -767,6 +889,7 @@ func (f *lightFetcher) checkUpdateStats(p *peer, newEntry *updateStatsEntry) { p.Log().Debug("Unknown peer to check update stats") return } + if newEntry != nil && fp.firstUpdateStats == nil { fp.firstUpdateStats = newEntry } diff --git a/vendor/github.com/ethereum/go-ethereum/les/fetcher_test.go b/vendor/github.com/ethereum/go-ethereum/les/fetcher_test.go new file mode 100644 index 00000000..cc678c8c --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/fetcher_test.go @@ -0,0 +1,152 @@ +package les + +import ( + "math/big" + "testing" + + "net" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +func TestFetcherULCPeerSelector(t *testing.T) { + id1 := newNodeID(t).ID() + id2 := newNodeID(t).ID() + id3 := newNodeID(t).ID() + id4 := newNodeID(t).ID() + + ftn1 := &fetcherTreeNode{ + hash: common.HexToHash("1"), + td: big.NewInt(1), + } + ftn2 := &fetcherTreeNode{ + hash: common.HexToHash("2"), + td: big.NewInt(2), + parent: ftn1, + } + ftn3 := &fetcherTreeNode{ + hash: common.HexToHash("3"), + td: big.NewInt(3), + parent: ftn2, + } + lf := lightFetcher{ + pm: &ProtocolManager{ + ulc: &ulc{ + trustedKeys: map[string]struct{}{ + id1.String(): {}, + id2.String(): {}, + id3.String(): {}, + id4.String(): {}, + }, + minTrustedFraction: 70, + }, + }, + maxConfirmedTd: ftn1.td, + + peers: map[*peer]*fetcherPeerInfo{ + { + id: "peer1", + Peer: p2p.NewPeer(id1, "peer1", []p2p.Cap{}), + isTrusted: true, + }: { + nodeByHash: map[common.Hash]*fetcherTreeNode{ + ftn1.hash: ftn1, + ftn2.hash: ftn2, + }, + }, + { + Peer: p2p.NewPeer(id2, "peer2", []p2p.Cap{}), + id: "peer2", + isTrusted: true, + }: { + nodeByHash: map[common.Hash]*fetcherTreeNode{ + ftn1.hash: ftn1, + ftn2.hash: ftn2, + }, + }, + { + id: "peer3", + Peer: p2p.NewPeer(id3, "peer3", []p2p.Cap{}), + isTrusted: true, + }: { + nodeByHash: map[common.Hash]*fetcherTreeNode{ + ftn1.hash: ftn1, + ftn2.hash: ftn2, + ftn3.hash: ftn3, + }, + }, + { + id: "peer4", + Peer: p2p.NewPeer(id4, "peer4", []p2p.Cap{}), + isTrusted: true, + }: { + nodeByHash: map[common.Hash]*fetcherTreeNode{ + ftn1.hash: ftn1, + }, + }, + }, + chain: &lightChainStub{ + tds: map[common.Hash]*big.Int{}, + headers: map[common.Hash]*types.Header{ + ftn1.hash: {}, + ftn2.hash: {}, + ftn3.hash: {}, + }, + }, + } + bestHash, bestAmount, bestTD, sync := lf.findBestRequest() + + if bestTD == nil { + t.Fatal("Empty result") + } + + if bestTD.Cmp(ftn2.td) != 0 { + t.Fatal("bad td", bestTD) + } + if bestHash != ftn2.hash { + t.Fatal("bad hash", bestTD) + } + + _, _ = bestAmount, sync +} + +type lightChainStub struct { + BlockChain + tds map[common.Hash]*big.Int + headers map[common.Hash]*types.Header + insertHeaderChainAssertFunc func(chain []*types.Header, checkFreq int) (int, error) +} + +func (l *lightChainStub) GetHeader(hash common.Hash, number uint64) *types.Header { + if h, ok := l.headers[hash]; ok { + return h + } + + return nil +} + +func (l *lightChainStub) LockChain() {} +func (l *lightChainStub) UnlockChain() {} + +func (l *lightChainStub) GetTd(hash common.Hash, number uint64) *big.Int { + if td, ok := l.tds[hash]; ok { + return td + } + return nil +} + +func (l *lightChainStub) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { + return l.insertHeaderChainAssertFunc(chain, checkFreq) +} + +func newNodeID(t *testing.T) *enode.Node { + key, err := crypto.GenerateKey() + if err != nil { + t.Fatal("generate key err:", err) + } + return enode.NewV4(&key.PublicKey, net.IP{}, 35000, 35000) +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/control.go b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/control.go index d50eb809..c03f673b 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/control.go +++ b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/control.go @@ -18,167 +18,339 @@ package flowcontrol import ( + "fmt" "sync" "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/log" ) -const fcTimeConst = time.Millisecond +const ( + // fcTimeConst is the time constant applied for MinRecharge during linear + // buffer recharge period + fcTimeConst = time.Millisecond + // DecParamDelay is applied at server side when decreasing capacity in order to + // avoid a buffer underrun error due to requests sent by the client before + // receiving the capacity update announcement + DecParamDelay = time.Second * 2 + // keepLogs is the duration of keeping logs; logging is not used if zero + keepLogs = 0 +) +// ServerParams are the flow control parameters specified by a server for a client +// +// Note: a server can assign different amounts of capacity to each client by giving +// different parameters to them. type ServerParams struct { BufLimit, MinRecharge uint64 } -type ClientNode struct { - params *ServerParams - bufValue uint64 - lastTime mclock.AbsTime - lock sync.Mutex - cm *ClientManager - cmNode *cmNode +// scheduledUpdate represents a delayed flow control parameter update +type scheduledUpdate struct { + time mclock.AbsTime + params ServerParams } -func NewClientNode(cm *ClientManager, params *ServerParams) *ClientNode { +// ClientNode is the flow control system's representation of a client +// (used in server mode only) +type ClientNode struct { + params ServerParams + bufValue uint64 + lastTime mclock.AbsTime + updateSchedule []scheduledUpdate + sumCost uint64 // sum of req costs received from this client + accepted map[uint64]uint64 // value = sumCost after accepting the given req + lock sync.Mutex + cm *ClientManager + log *logger + cmNodeFields +} + +// NewClientNode returns a new ClientNode +func NewClientNode(cm *ClientManager, params ServerParams) *ClientNode { node := &ClientNode{ cm: cm, params: params, bufValue: params.BufLimit, - lastTime: mclock.Now(), + lastTime: cm.clock.Now(), + accepted: make(map[uint64]uint64), } - node.cmNode = cm.addNode(node) + if keepLogs > 0 { + node.log = newLogger(keepLogs) + } + cm.connect(node) return node } -func (peer *ClientNode) Remove(cm *ClientManager) { - cm.removeNode(peer.cmNode) +// Disconnect should be called when a client is disconnected +func (node *ClientNode) Disconnect() { + node.cm.disconnect(node) } -func (peer *ClientNode) recalcBV(time mclock.AbsTime) { - dt := uint64(time - peer.lastTime) - if time < peer.lastTime { +// update recalculates the buffer value at a specified time while also performing +// scheduled flow control parameter updates if necessary +func (node *ClientNode) update(now mclock.AbsTime) { + for len(node.updateSchedule) > 0 && node.updateSchedule[0].time <= now { + node.recalcBV(node.updateSchedule[0].time) + node.updateParams(node.updateSchedule[0].params, now) + node.updateSchedule = node.updateSchedule[1:] + } + node.recalcBV(now) +} + +// recalcBV recalculates the buffer value at a specified time +func (node *ClientNode) recalcBV(now mclock.AbsTime) { + dt := uint64(now - node.lastTime) + if now < node.lastTime { dt = 0 } - peer.bufValue += peer.params.MinRecharge * dt / uint64(fcTimeConst) - if peer.bufValue > peer.params.BufLimit { - peer.bufValue = peer.params.BufLimit + node.bufValue += node.params.MinRecharge * dt / uint64(fcTimeConst) + if node.bufValue > node.params.BufLimit { + node.bufValue = node.params.BufLimit } - peer.lastTime = time + if node.log != nil { + node.log.add(now, fmt.Sprintf("updated bv=%d MRR=%d BufLimit=%d", node.bufValue, node.params.MinRecharge, node.params.BufLimit)) + } + node.lastTime = now } -func (peer *ClientNode) AcceptRequest() (uint64, bool) { - peer.lock.Lock() - defer peer.lock.Unlock() +// UpdateParams updates the flow control parameters of a client node +func (node *ClientNode) UpdateParams(params ServerParams) { + node.lock.Lock() + defer node.lock.Unlock() - time := mclock.Now() - peer.recalcBV(time) - return peer.bufValue, peer.cm.accept(peer.cmNode, time) -} - -func (peer *ClientNode) RequestProcessed(cost uint64) (bv, realCost uint64) { - peer.lock.Lock() - defer peer.lock.Unlock() - - time := mclock.Now() - peer.recalcBV(time) - peer.bufValue -= cost - peer.recalcBV(time) - rcValue, rcost := peer.cm.processed(peer.cmNode, time) - if rcValue < peer.params.BufLimit { - bv := peer.params.BufLimit - rcValue - if bv > peer.bufValue { - peer.bufValue = bv + now := node.cm.clock.Now() + node.update(now) + if params.MinRecharge >= node.params.MinRecharge { + node.updateSchedule = nil + node.updateParams(params, now) + } else { + for i, s := range node.updateSchedule { + if params.MinRecharge >= s.params.MinRecharge { + s.params = params + node.updateSchedule = node.updateSchedule[:i+1] + return + } } + node.updateSchedule = append(node.updateSchedule, scheduledUpdate{time: now + mclock.AbsTime(DecParamDelay), params: params}) } - return peer.bufValue, rcost } +// updateParams updates the flow control parameters of the node +func (node *ClientNode) updateParams(params ServerParams, now mclock.AbsTime) { + diff := params.BufLimit - node.params.BufLimit + if int64(diff) > 0 { + node.bufValue += diff + } else if node.bufValue > params.BufLimit { + node.bufValue = params.BufLimit + } + node.cm.updateParams(node, params, now) +} + +// AcceptRequest returns whether a new request can be accepted and the missing +// buffer amount if it was rejected due to a buffer underrun. If accepted, maxCost +// is deducted from the flow control buffer. +func (node *ClientNode) AcceptRequest(reqID, index, maxCost uint64) (accepted bool, bufShort uint64, priority int64) { + node.lock.Lock() + defer node.lock.Unlock() + + now := node.cm.clock.Now() + node.update(now) + if maxCost > node.bufValue { + if node.log != nil { + node.log.add(now, fmt.Sprintf("rejected reqID=%d bv=%d maxCost=%d", reqID, node.bufValue, maxCost)) + node.log.dump(now) + } + return false, maxCost - node.bufValue, 0 + } + node.bufValue -= maxCost + node.sumCost += maxCost + if node.log != nil { + node.log.add(now, fmt.Sprintf("accepted reqID=%d bv=%d maxCost=%d sumCost=%d", reqID, node.bufValue, maxCost, node.sumCost)) + } + node.accepted[index] = node.sumCost + return true, 0, node.cm.accepted(node, maxCost, now) +} + +// RequestProcessed should be called when the request has been processed +func (node *ClientNode) RequestProcessed(reqID, index, maxCost, realCost uint64) (bv uint64) { + node.lock.Lock() + defer node.lock.Unlock() + + now := node.cm.clock.Now() + node.update(now) + node.cm.processed(node, maxCost, realCost, now) + bv = node.bufValue + node.sumCost - node.accepted[index] + if node.log != nil { + node.log.add(now, fmt.Sprintf("processed reqID=%d bv=%d maxCost=%d realCost=%d sumCost=%d oldSumCost=%d reportedBV=%d", reqID, node.bufValue, maxCost, realCost, node.sumCost, node.accepted[index], bv)) + } + delete(node.accepted, index) + return +} + +// ServerNode is the flow control system's representation of a server +// (used in client mode only) type ServerNode struct { + clock mclock.Clock bufEstimate uint64 + bufRecharge bool lastTime mclock.AbsTime - params *ServerParams + params ServerParams sumCost uint64 // sum of req costs sent to this server pending map[uint64]uint64 // value = sumCost after sending the given req + log *logger lock sync.RWMutex } -func NewServerNode(params *ServerParams) *ServerNode { - return &ServerNode{ +// NewServerNode returns a new ServerNode +func NewServerNode(params ServerParams, clock mclock.Clock) *ServerNode { + node := &ServerNode{ + clock: clock, bufEstimate: params.BufLimit, - lastTime: mclock.Now(), + bufRecharge: false, + lastTime: clock.Now(), params: params, pending: make(map[uint64]uint64), } + if keepLogs > 0 { + node.log = newLogger(keepLogs) + } + return node } -func (peer *ServerNode) recalcBLE(time mclock.AbsTime) { - dt := uint64(time - peer.lastTime) - if time < peer.lastTime { - dt = 0 +// UpdateParams updates the flow control parameters of the node +func (node *ServerNode) UpdateParams(params ServerParams) { + node.lock.Lock() + defer node.lock.Unlock() + + node.recalcBLE(mclock.Now()) + if params.BufLimit > node.params.BufLimit { + node.bufEstimate += params.BufLimit - node.params.BufLimit + } else { + if node.bufEstimate > params.BufLimit { + node.bufEstimate = params.BufLimit + } } - peer.bufEstimate += peer.params.MinRecharge * dt / uint64(fcTimeConst) - if peer.bufEstimate > peer.params.BufLimit { - peer.bufEstimate = peer.params.BufLimit + node.params = params +} + +// recalcBLE recalculates the lowest estimate for the client's buffer value at +// the given server at the specified time +func (node *ServerNode) recalcBLE(now mclock.AbsTime) { + if now < node.lastTime { + return + } + if node.bufRecharge { + dt := uint64(now - node.lastTime) + node.bufEstimate += node.params.MinRecharge * dt / uint64(fcTimeConst) + if node.bufEstimate >= node.params.BufLimit { + node.bufEstimate = node.params.BufLimit + node.bufRecharge = false + } + } + node.lastTime = now + if node.log != nil { + node.log.add(now, fmt.Sprintf("updated bufEst=%d MRR=%d BufLimit=%d", node.bufEstimate, node.params.MinRecharge, node.params.BufLimit)) } - peer.lastTime = time } // safetyMargin is added to the flow control waiting time when estimated buffer value is low const safetyMargin = time.Millisecond -func (peer *ServerNode) canSend(maxCost uint64) (time.Duration, float64) { - peer.recalcBLE(mclock.Now()) - maxCost += uint64(safetyMargin) * peer.params.MinRecharge / uint64(fcTimeConst) - if maxCost > peer.params.BufLimit { - maxCost = peer.params.BufLimit - } - if peer.bufEstimate >= maxCost { - return 0, float64(peer.bufEstimate-maxCost) / float64(peer.params.BufLimit) - } - return time.Duration((maxCost - peer.bufEstimate) * uint64(fcTimeConst) / peer.params.MinRecharge), 0 -} - // CanSend returns the minimum waiting time required before sending a request // with the given maximum estimated cost. Second return value is the relative // estimated buffer level after sending the request (divided by BufLimit). -func (peer *ServerNode) CanSend(maxCost uint64) (time.Duration, float64) { - peer.lock.RLock() - defer peer.lock.RUnlock() +func (node *ServerNode) CanSend(maxCost uint64) (time.Duration, float64) { + node.lock.RLock() + defer node.lock.RUnlock() - return peer.canSend(maxCost) -} - -// QueueRequest should be called when the request has been assigned to the given -// server node, before putting it in the send queue. It is mandatory that requests -// are sent in the same order as the QueueRequest calls are made. -func (peer *ServerNode) QueueRequest(reqID, maxCost uint64) { - peer.lock.Lock() - defer peer.lock.Unlock() - - peer.bufEstimate -= maxCost - peer.sumCost += maxCost - peer.pending[reqID] = peer.sumCost -} - -// GotReply adjusts estimated buffer value according to the value included in -// the latest request reply. -func (peer *ServerNode) GotReply(reqID, bv uint64) { - - peer.lock.Lock() - defer peer.lock.Unlock() - - if bv > peer.params.BufLimit { - bv = peer.params.BufLimit + now := node.clock.Now() + node.recalcBLE(now) + maxCost += uint64(safetyMargin) * node.params.MinRecharge / uint64(fcTimeConst) + if maxCost > node.params.BufLimit { + maxCost = node.params.BufLimit } - sc, ok := peer.pending[reqID] + if node.bufEstimate >= maxCost { + relBuf := float64(node.bufEstimate-maxCost) / float64(node.params.BufLimit) + if node.log != nil { + node.log.add(now, fmt.Sprintf("canSend bufEst=%d maxCost=%d true relBuf=%f", node.bufEstimate, maxCost, relBuf)) + } + return 0, relBuf + } + timeLeft := time.Duration((maxCost - node.bufEstimate) * uint64(fcTimeConst) / node.params.MinRecharge) + if node.log != nil { + node.log.add(now, fmt.Sprintf("canSend bufEst=%d maxCost=%d false timeLeft=%v", node.bufEstimate, maxCost, timeLeft)) + } + return timeLeft, 0 +} + +// QueuedRequest should be called when the request has been assigned to the given +// server node, before putting it in the send queue. It is mandatory that requests +// are sent in the same order as the QueuedRequest calls are made. +func (node *ServerNode) QueuedRequest(reqID, maxCost uint64) { + node.lock.Lock() + defer node.lock.Unlock() + + now := node.clock.Now() + node.recalcBLE(now) + // Note: we do not know when requests actually arrive to the server so bufRecharge + // is not turned on here if buffer was full; in this case it is going to be turned + // on by the first reply's bufValue feedback + if node.bufEstimate >= maxCost { + node.bufEstimate -= maxCost + } else { + log.Error("Queued request with insufficient buffer estimate") + node.bufEstimate = 0 + } + node.sumCost += maxCost + node.pending[reqID] = node.sumCost + if node.log != nil { + node.log.add(now, fmt.Sprintf("queued reqID=%d bufEst=%d maxCost=%d sumCost=%d", reqID, node.bufEstimate, maxCost, node.sumCost)) + } +} + +// ReceivedReply adjusts estimated buffer value according to the value included in +// the latest request reply. +func (node *ServerNode) ReceivedReply(reqID, bv uint64) { + node.lock.Lock() + defer node.lock.Unlock() + + now := node.clock.Now() + node.recalcBLE(now) + if bv > node.params.BufLimit { + bv = node.params.BufLimit + } + sc, ok := node.pending[reqID] if !ok { return } - delete(peer.pending, reqID) - cc := peer.sumCost - sc - peer.bufEstimate = 0 + delete(node.pending, reqID) + cc := node.sumCost - sc + newEstimate := uint64(0) if bv > cc { - peer.bufEstimate = bv - cc + newEstimate = bv - cc + } + if newEstimate > node.bufEstimate { + // Note: we never reduce the buffer estimate based on the reported value because + // this can only happen because of the delayed delivery of the latest reply. + // The lowest estimate based on the previous reply can still be considered valid. + node.bufEstimate = newEstimate + } + + node.bufRecharge = node.bufEstimate < node.params.BufLimit + node.lastTime = now + if node.log != nil { + node.log.add(now, fmt.Sprintf("received reqID=%d bufEst=%d reportedBv=%d sumCost=%d oldSumCost=%d", reqID, node.bufEstimate, bv, node.sumCost, sc)) + } +} + +// DumpLogs dumps the event log if logging is used +func (node *ServerNode) DumpLogs() { + node.lock.Lock() + defer node.lock.Unlock() + + if node.log != nil { + node.log.dump(node.clock.Now()) } - peer.lastTime = mclock.Now() } diff --git a/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/logger.go b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/logger.go new file mode 100644 index 00000000..fcd1285a --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/logger.go @@ -0,0 +1,65 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package flowcontrol + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +// logger collects events in string format and discards events older than the +// "keep" parameter +type logger struct { + events map[uint64]logEvent + writePtr, delPtr uint64 + keep time.Duration +} + +// logEvent describes a single event +type logEvent struct { + time mclock.AbsTime + event string +} + +// newLogger creates a new logger +func newLogger(keep time.Duration) *logger { + return &logger{ + events: make(map[uint64]logEvent), + keep: keep, + } +} + +// add adds a new event and discards old events if possible +func (l *logger) add(now mclock.AbsTime, event string) { + keepAfter := now - mclock.AbsTime(l.keep) + for l.delPtr < l.writePtr && l.events[l.delPtr].time <= keepAfter { + delete(l.events, l.delPtr) + l.delPtr++ + } + l.events[l.writePtr] = logEvent{now, event} + l.writePtr++ +} + +// dump prints all stored events +func (l *logger) dump(now mclock.AbsTime) { + for i := l.delPtr; i < l.writePtr; i++ { + e := l.events[i] + fmt.Println(time.Duration(e.time-now), e.event) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager.go b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager.go index 28cc6f0f..532e6a40 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager.go +++ b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,211 +14,388 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package flowcontrol implements a client side flow control mechanism package flowcontrol import ( + "fmt" + "math" "sync" "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/common/prque" ) -const rcConst = 1000000 - -type cmNode struct { - node *ClientNode - lastUpdate mclock.AbsTime - serving, recharging bool - rcWeight uint64 - rcValue, rcDelta, startValue int64 - finishRecharge mclock.AbsTime +// cmNodeFields are ClientNode fields used by the client manager +// Note: these fields are locked by the client manager's mutex +type cmNodeFields struct { + corrBufValue int64 // buffer value adjusted with the extra recharge amount + rcLastIntValue int64 // past recharge integrator value when corrBufValue was last updated + rcFullIntValue int64 // future recharge integrator value when corrBufValue will reach maximum + queueIndex int // position in the recharge queue (-1 if not queued) } -func (node *cmNode) update(time mclock.AbsTime) { - dt := int64(time - node.lastUpdate) - node.rcValue += node.rcDelta * dt / rcConst - node.lastUpdate = time - if node.recharging && time >= node.finishRecharge { - node.recharging = false - node.rcDelta = 0 - node.rcValue = 0 - } -} +// FixedPointMultiplier is applied to the recharge integrator and the recharge curve. +// +// Note: fixed point arithmetic is required for the integrator because it is a +// constantly increasing value that can wrap around int64 limits (which behavior is +// also supported by the priority queue). A floating point value would gradually lose +// precision in this application. +// The recharge curve and all recharge values are encoded as fixed point because +// sumRecharge is frequently updated by adding or subtracting individual recharge +// values and perfect precision is required. +const FixedPointMultiplier = 1000000 -func (node *cmNode) set(serving bool, simReqCnt, sumWeight uint64) { - if node.serving && !serving { - node.recharging = true - sumWeight += node.rcWeight - } - node.serving = serving - if node.recharging && serving { - node.recharging = false - sumWeight -= node.rcWeight - } - - node.rcDelta = 0 - if serving { - node.rcDelta = int64(rcConst / simReqCnt) - } - if node.recharging { - node.rcDelta = -int64(node.node.cm.rcRecharge * node.rcWeight / sumWeight) - node.finishRecharge = node.lastUpdate + mclock.AbsTime(node.rcValue*rcConst/(-node.rcDelta)) - } -} +var ( + capFactorDropTC = 1 / float64(time.Second*10) // time constant for dropping the capacity factor + capFactorRaiseTC = 1 / float64(time.Hour) // time constant for raising the capacity factor + capFactorRaiseThreshold = 0.75 // connected / total capacity ratio threshold for raising the capacity factor +) +// ClientManager controls the capacity assigned to the clients of a server. +// Since ServerParams guarantee a safe lower estimate for processable requests +// even in case of all clients being active, ClientManager calculates a +// corrigated buffer value and usually allows a higher remaining buffer value +// to be returned with each reply. type ClientManager struct { - lock sync.Mutex - nodes map[*cmNode]struct{} - simReqCnt, sumWeight, rcSumValue uint64 - maxSimReq, maxRcSum uint64 - rcRecharge uint64 - resumeQueue chan chan bool - time mclock.AbsTime + clock mclock.Clock + lock sync.Mutex + enabledCh chan struct{} + + curve PieceWiseLinear + sumRecharge, totalRecharge, totalConnected uint64 + capLogFactor, totalCapacity float64 + capLastUpdate mclock.AbsTime + totalCapacityCh chan uint64 + + // recharge integrator is increasing in each moment with a rate of + // (totalRecharge / sumRecharge)*FixedPointMultiplier or 0 if sumRecharge==0 + rcLastUpdate mclock.AbsTime // last time the recharge integrator was updated + rcLastIntValue int64 // last updated value of the recharge integrator + // recharge queue is a priority queue with currently recharging client nodes + // as elements. The priority value is rcFullIntValue which allows to quickly + // determine which client will first finish recharge. + rcQueue *prque.Prque } -func NewClientManager(rcTarget, maxSimReq, maxRcSum uint64) *ClientManager { +// NewClientManager returns a new client manager. +// Client manager enhances flow control performance by allowing client buffers +// to recharge quicker than the minimum guaranteed recharge rate if possible. +// The sum of all minimum recharge rates (sumRecharge) is updated each time +// a clients starts or finishes buffer recharging. Then an adjusted total +// recharge rate is calculated using a piecewise linear recharge curve: +// +// totalRecharge = curve(sumRecharge) +// (totalRecharge >= sumRecharge is enforced) +// +// Then the "bonus" buffer recharge is distributed between currently recharging +// clients proportionally to their minimum recharge rates. +// +// Note: total recharge is proportional to the average number of parallel running +// serving threads. A recharge value of 1000000 corresponds to one thread in average. +// The maximum number of allowed serving threads should always be considerably +// higher than the targeted average number. +// +// Note 2: although it is possible to specify a curve allowing the total target +// recharge starting from zero sumRecharge, it makes sense to add a linear ramp +// starting from zero in order to not let a single low-priority client use up +// the entire server capacity and thus ensure quick availability for others at +// any moment. +func NewClientManager(curve PieceWiseLinear, clock mclock.Clock) *ClientManager { cm := &ClientManager{ - nodes: make(map[*cmNode]struct{}), - resumeQueue: make(chan chan bool), - rcRecharge: rcConst * rcConst / (100*rcConst/rcTarget - rcConst), - maxSimReq: maxSimReq, - maxRcSum: maxRcSum, + clock: clock, + rcQueue: prque.New(func(a interface{}, i int) { a.(*ClientNode).queueIndex = i }), + capLastUpdate: clock.Now(), + } + if curve != nil { + cm.SetRechargeCurve(curve) } - go cm.queueProc() return cm } -func (self *ClientManager) Stop() { - self.lock.Lock() - defer self.lock.Unlock() +// SetRechargeCurve updates the recharge curve +func (cm *ClientManager) SetRechargeCurve(curve PieceWiseLinear) { + cm.lock.Lock() + defer cm.lock.Unlock() - // signal any waiting accept routines to return false - self.nodes = make(map[*cmNode]struct{}) - close(self.resumeQueue) -} - -func (self *ClientManager) addNode(cnode *ClientNode) *cmNode { - time := mclock.Now() - node := &cmNode{ - node: cnode, - lastUpdate: time, - finishRecharge: time, - rcWeight: 1, + now := cm.clock.Now() + cm.updateRecharge(now) + cm.updateCapFactor(now, false) + cm.curve = curve + if len(curve) > 0 { + cm.totalRecharge = curve[len(curve)-1].Y + } else { + cm.totalRecharge = 0 } - self.lock.Lock() - defer self.lock.Unlock() - - self.nodes[node] = struct{}{} - self.update(mclock.Now()) - return node + cm.refreshCapacity() } -func (self *ClientManager) removeNode(node *cmNode) { - self.lock.Lock() - defer self.lock.Unlock() +// connect should be called when a client is connected, before passing it to any +// other ClientManager function +func (cm *ClientManager) connect(node *ClientNode) { + cm.lock.Lock() + defer cm.lock.Unlock() - time := mclock.Now() - self.stop(node, time) - delete(self.nodes, node) - self.update(time) + now := cm.clock.Now() + cm.updateRecharge(now) + node.corrBufValue = int64(node.params.BufLimit) + node.rcLastIntValue = cm.rcLastIntValue + node.queueIndex = -1 + cm.updateCapFactor(now, true) + cm.totalConnected += node.params.MinRecharge } -// recalc sumWeight -func (self *ClientManager) updateNodes(time mclock.AbsTime) (rce bool) { - var sumWeight, rcSum uint64 - for node := range self.nodes { - rc := node.recharging - node.update(time) - if rc && !node.recharging { - rce = true - } - if node.recharging { - sumWeight += node.rcWeight - } - rcSum += uint64(node.rcValue) +// disconnect should be called when a client is disconnected +func (cm *ClientManager) disconnect(node *ClientNode) { + cm.lock.Lock() + defer cm.lock.Unlock() + + now := cm.clock.Now() + cm.updateRecharge(cm.clock.Now()) + cm.updateCapFactor(now, true) + cm.totalConnected -= node.params.MinRecharge +} + +// accepted is called when a request with given maximum cost is accepted. +// It returns a priority indicator for the request which is used to determine placement +// in the serving queue. Older requests have higher priority by default. If the client +// is almost out of buffer, request priority is reduced. +func (cm *ClientManager) accepted(node *ClientNode, maxCost uint64, now mclock.AbsTime) (priority int64) { + cm.lock.Lock() + defer cm.lock.Unlock() + + cm.updateNodeRc(node, -int64(maxCost), &node.params, now) + rcTime := (node.params.BufLimit - uint64(node.corrBufValue)) * FixedPointMultiplier / node.params.MinRecharge + return -int64(now) - int64(rcTime) +} + +// processed updates the client buffer according to actual request cost after +// serving has been finished. +// +// Note: processed should always be called for all accepted requests +func (cm *ClientManager) processed(node *ClientNode, maxCost, realCost uint64, now mclock.AbsTime) { + cm.lock.Lock() + defer cm.lock.Unlock() + + if realCost > maxCost { + realCost = maxCost + } + cm.updateNodeRc(node, int64(maxCost-realCost), &node.params, now) + if uint64(node.corrBufValue) > node.bufValue { + if node.log != nil { + node.log.add(now, fmt.Sprintf("corrected bv=%d oldBv=%d", node.corrBufValue, node.bufValue)) + } + node.bufValue = uint64(node.corrBufValue) } - self.sumWeight = sumWeight - self.rcSumValue = rcSum - return } -func (self *ClientManager) update(time mclock.AbsTime) { - for { - firstTime := time - for node := range self.nodes { - if node.recharging && node.finishRecharge < firstTime { - firstTime = node.finishRecharge - } +// updateParams updates the flow control parameters of a client node +func (cm *ClientManager) updateParams(node *ClientNode, params ServerParams, now mclock.AbsTime) { + cm.lock.Lock() + defer cm.lock.Unlock() + + cm.updateRecharge(now) + cm.updateCapFactor(now, true) + cm.totalConnected += params.MinRecharge - node.params.MinRecharge + cm.updateNodeRc(node, 0, ¶ms, now) +} + +// updateRecharge updates the recharge integrator and checks the recharge queue +// for nodes with recently filled buffers +func (cm *ClientManager) updateRecharge(now mclock.AbsTime) { + lastUpdate := cm.rcLastUpdate + cm.rcLastUpdate = now + // updating is done in multiple steps if node buffers are filled and sumRecharge + // is decreased before the given target time + for cm.sumRecharge > 0 { + bonusRatio := cm.curve.ValueAt(cm.sumRecharge) / float64(cm.sumRecharge) + if bonusRatio < 1 { + bonusRatio = 1 } - if self.updateNodes(firstTime) { - for node := range self.nodes { - if node.recharging { - node.set(node.serving, self.simReqCnt, self.sumWeight) - } - } - } else { - self.time = time + dt := now - lastUpdate + // fetch the client that finishes first + rcqNode := cm.rcQueue.PopItem().(*ClientNode) // if sumRecharge > 0 then the queue cannot be empty + // check whether it has already finished + dtNext := mclock.AbsTime(float64(rcqNode.rcFullIntValue-cm.rcLastIntValue) / bonusRatio) + if dt < dtNext { + // not finished yet, put it back, update integrator according + // to current bonusRatio and return + cm.rcQueue.Push(rcqNode, -rcqNode.rcFullIntValue) + cm.rcLastIntValue += int64(bonusRatio * float64(dt)) return } + lastUpdate += dtNext + // finished recharging, update corrBufValue and sumRecharge if necessary and do next step + if rcqNode.corrBufValue < int64(rcqNode.params.BufLimit) { + rcqNode.corrBufValue = int64(rcqNode.params.BufLimit) + cm.updateCapFactor(lastUpdate, true) + cm.sumRecharge -= rcqNode.params.MinRecharge + } + cm.rcLastIntValue = rcqNode.rcFullIntValue } } -func (self *ClientManager) canStartReq() bool { - return self.simReqCnt < self.maxSimReq && self.rcSumValue < self.maxRcSum +// updateNodeRc updates a node's corrBufValue and adds an external correction value. +// It also adds or removes the rcQueue entry and updates ServerParams and sumRecharge if necessary. +func (cm *ClientManager) updateNodeRc(node *ClientNode, bvc int64, params *ServerParams, now mclock.AbsTime) { + cm.updateRecharge(now) + wasFull := true + if node.corrBufValue != int64(node.params.BufLimit) { + wasFull = false + node.corrBufValue += (cm.rcLastIntValue - node.rcLastIntValue) * int64(node.params.MinRecharge) / FixedPointMultiplier + if node.corrBufValue > int64(node.params.BufLimit) { + node.corrBufValue = int64(node.params.BufLimit) + } + node.rcLastIntValue = cm.rcLastIntValue + } + node.corrBufValue += bvc + if node.corrBufValue < 0 { + node.corrBufValue = 0 + } + diff := int64(params.BufLimit - node.params.BufLimit) + if diff > 0 { + node.corrBufValue += diff + } + isFull := false + if node.corrBufValue >= int64(params.BufLimit) { + node.corrBufValue = int64(params.BufLimit) + isFull = true + } + sumRecharge := cm.sumRecharge + if !wasFull { + sumRecharge -= node.params.MinRecharge + } + if params != &node.params { + node.params = *params + } + if !isFull { + sumRecharge += node.params.MinRecharge + if node.queueIndex != -1 { + cm.rcQueue.Remove(node.queueIndex) + } + node.rcLastIntValue = cm.rcLastIntValue + node.rcFullIntValue = cm.rcLastIntValue + (int64(node.params.BufLimit)-node.corrBufValue)*FixedPointMultiplier/int64(node.params.MinRecharge) + cm.rcQueue.Push(node, -node.rcFullIntValue) + } + if sumRecharge != cm.sumRecharge { + cm.updateCapFactor(now, true) + cm.sumRecharge = sumRecharge + } + } -func (self *ClientManager) queueProc() { - for rc := range self.resumeQueue { - for { - time.Sleep(time.Millisecond * 10) - self.lock.Lock() - self.update(mclock.Now()) - cs := self.canStartReq() - self.lock.Unlock() - if cs { - break +// updateCapFactor updates the total capacity factor. The capacity factor allows +// the total capacity of the system to go over the allowed total recharge value +// if the sum of momentarily recharging clients only exceeds the total recharge +// allowance in a very small fraction of time. +// The capacity factor is dropped quickly (with a small time constant) if sumRecharge +// exceeds totalRecharge. It is raised slowly (with a large time constant) if most +// of the total capacity is used by connected clients (totalConnected is larger than +// totalCapacity*capFactorRaiseThreshold) and sumRecharge stays under +// totalRecharge*totalConnected/totalCapacity. +func (cm *ClientManager) updateCapFactor(now mclock.AbsTime, refresh bool) { + if cm.totalRecharge == 0 { + return + } + dt := now - cm.capLastUpdate + cm.capLastUpdate = now + + var d float64 + if cm.sumRecharge > cm.totalRecharge { + d = (1 - float64(cm.sumRecharge)/float64(cm.totalRecharge)) * capFactorDropTC + } else { + totalConnected := float64(cm.totalConnected) + var connRatio float64 + if totalConnected < cm.totalCapacity { + connRatio = totalConnected / cm.totalCapacity + } else { + connRatio = 1 + } + if connRatio > capFactorRaiseThreshold { + sumRecharge := float64(cm.sumRecharge) + limit := float64(cm.totalRecharge) * connRatio + if sumRecharge < limit { + d = (1 - sumRecharge/limit) * (connRatio - capFactorRaiseThreshold) * (1 / (1 - capFactorRaiseThreshold)) * capFactorRaiseTC } } - close(rc) } -} - -func (self *ClientManager) accept(node *cmNode, time mclock.AbsTime) bool { - self.lock.Lock() - defer self.lock.Unlock() - - self.update(time) - if !self.canStartReq() { - resume := make(chan bool) - self.lock.Unlock() - self.resumeQueue <- resume - <-resume - self.lock.Lock() - if _, ok := self.nodes[node]; !ok { - return false // reject if node has been removed or manager has been stopped + if d != 0 { + cm.capLogFactor += d * float64(dt) + if cm.capLogFactor < 0 { + cm.capLogFactor = 0 + } + if refresh { + cm.refreshCapacity() } } - self.simReqCnt++ - node.set(true, self.simReqCnt, self.sumWeight) - node.startValue = node.rcValue - self.update(self.time) - return true } -func (self *ClientManager) stop(node *cmNode, time mclock.AbsTime) { - if node.serving { - self.update(time) - self.simReqCnt-- - node.set(false, self.simReqCnt, self.sumWeight) - self.update(time) +// refreshCapacity recalculates the total capacity value and sends an update to the subscription +// channel if the relative change of the value since the last update is more than 0.1 percent +func (cm *ClientManager) refreshCapacity() { + totalCapacity := float64(cm.totalRecharge) * math.Exp(cm.capLogFactor) + if totalCapacity >= cm.totalCapacity*0.999 && totalCapacity <= cm.totalCapacity*1.001 { + return + } + cm.totalCapacity = totalCapacity + if cm.totalCapacityCh != nil { + select { + case cm.totalCapacityCh <- uint64(cm.totalCapacity): + default: + } } } -func (self *ClientManager) processed(node *cmNode, time mclock.AbsTime) (rcValue, rcCost uint64) { - self.lock.Lock() - defer self.lock.Unlock() +// SubscribeTotalCapacity returns all future updates to the total capacity value +// through a channel and also returns the current value +func (cm *ClientManager) SubscribeTotalCapacity(ch chan uint64) uint64 { + cm.lock.Lock() + defer cm.lock.Unlock() - self.stop(node, time) - return uint64(node.rcValue), uint64(node.rcValue - node.startValue) + cm.totalCapacityCh = ch + return uint64(cm.totalCapacity) +} + +// PieceWiseLinear is used to describe recharge curves +type PieceWiseLinear []struct{ X, Y uint64 } + +// ValueAt returns the curve's value at a given point +func (pwl PieceWiseLinear) ValueAt(x uint64) float64 { + l := 0 + h := len(pwl) + if h == 0 { + return 0 + } + for h != l { + m := (l + h) / 2 + if x > pwl[m].X { + l = m + 1 + } else { + h = m + } + } + if l == 0 { + return float64(pwl[0].Y) + } + l-- + if h == len(pwl) { + return float64(pwl[l].Y) + } + dx := pwl[h].X - pwl[l].X + if dx < 1 { + return float64(pwl[l].Y) + } + return float64(pwl[l].Y) + float64(pwl[h].Y-pwl[l].Y)*float64(x-pwl[l].X)/float64(dx) +} + +// Valid returns true if the X coordinates of the curve points are non-strictly monotonic +func (pwl PieceWiseLinear) Valid() bool { + var lastX uint64 + for _, i := range pwl { + if i.X < lastX { + return false + } + lastX = i.X + } + return true } diff --git a/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager_test.go b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager_test.go new file mode 100644 index 00000000..4e7746d4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/flowcontrol/manager_test.go @@ -0,0 +1,123 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package flowcontrol + +import ( + "math/rand" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +type testNode struct { + node *ClientNode + bufLimit, capacity uint64 + waitUntil mclock.AbsTime + index, totalCost uint64 +} + +const ( + testMaxCost = 1000000 + testLength = 100000 +) + +// testConstantTotalCapacity simulates multiple request sender nodes and verifies +// whether the total amount of served requests matches the expected value based on +// the total capacity and the duration of the test. +// Some nodes are sending requests occasionally so that their buffer should regularly +// reach the maximum while other nodes (the "max capacity nodes") are sending at the +// maximum permitted rate. The max capacity nodes are changed multiple times during +// a single test. +func TestConstantTotalCapacity(t *testing.T) { + testConstantTotalCapacity(t, 10, 1, 0) + testConstantTotalCapacity(t, 10, 1, 1) + testConstantTotalCapacity(t, 30, 1, 0) + testConstantTotalCapacity(t, 30, 2, 3) + testConstantTotalCapacity(t, 100, 1, 0) + testConstantTotalCapacity(t, 100, 3, 5) + testConstantTotalCapacity(t, 100, 5, 10) +} + +func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, randomSend int) { + clock := &mclock.Simulated{} + nodes := make([]*testNode, nodeCount) + var totalCapacity uint64 + for i := range nodes { + nodes[i] = &testNode{capacity: uint64(50000 + rand.Intn(100000))} + totalCapacity += nodes[i].capacity + } + m := NewClientManager(PieceWiseLinear{{0, totalCapacity}}, clock) + for _, n := range nodes { + n.bufLimit = n.capacity * 6000 //uint64(2000+rand.Intn(10000)) + n.node = NewClientNode(m, ServerParams{BufLimit: n.bufLimit, MinRecharge: n.capacity}) + } + maxNodes := make([]int, maxCapacityNodes) + for i := range maxNodes { + // we don't care if some indexes are selected multiple times + // in that case we have fewer max nodes + maxNodes[i] = rand.Intn(nodeCount) + } + + for i := 0; i < testLength; i++ { + now := clock.Now() + for _, idx := range maxNodes { + for nodes[idx].send(t, now) { + } + } + if rand.Intn(testLength) < maxCapacityNodes*3 { + maxNodes[rand.Intn(maxCapacityNodes)] = rand.Intn(nodeCount) + } + + sendCount := randomSend + for sendCount > 0 { + if nodes[rand.Intn(nodeCount)].send(t, now) { + sendCount-- + } + } + + clock.Run(time.Millisecond) + } + + var totalCost uint64 + for _, n := range nodes { + totalCost += n.totalCost + } + ratio := float64(totalCost) / float64(totalCapacity) / testLength + if ratio < 0.98 || ratio > 1.02 { + t.Errorf("totalCost/totalCapacity/testLength ratio incorrect (expected: 1, got: %f)", ratio) + } + +} + +func (n *testNode) send(t *testing.T, now mclock.AbsTime) bool { + if now < n.waitUntil { + return false + } + n.index++ + if ok, _, _ := n.node.AcceptRequest(0, n.index, testMaxCost); !ok { + t.Fatalf("Rejected request after expected waiting time has passed") + } + rcost := uint64(rand.Int63n(testMaxCost)) + bv := n.node.RequestProcessed(0, n.index, testMaxCost, rcost) + if bv < testMaxCost { + n.waitUntil = now + mclock.AbsTime((testMaxCost-bv)*1001000/n.capacity) + } + //n.waitUntil = now + mclock.AbsTime(float64(testMaxCost)*1001000/float64(n.capacity)*(1-float64(bv)/float64(n.bufLimit))) + n.totalCost += rcost + return true +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/freeclient.go b/vendor/github.com/ethereum/go-ethereum/les/freeclient.go index 5ee607be..d859337c 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/freeclient.go +++ b/vendor/github.com/ethereum/go-ethereum/les/freeclient.go @@ -14,12 +14,12 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( "io" "math" + "net" "sync" "time" @@ -44,12 +44,14 @@ import ( // value for the client. Currently the LES protocol manager uses IP addresses // (without port address) to identify clients. type freeClientPool struct { - db ethdb.Database - lock sync.Mutex - clock mclock.Clock - closed bool + db ethdb.Database + lock sync.Mutex + clock mclock.Clock + closed bool + removePeer func(string) connectedLimit, totalLimit int + freeClientCap uint64 addressMap map[string]*freeClientPoolEntry connPool, disconnPool *prque.Prque @@ -64,15 +66,16 @@ const ( ) // newFreeClientPool creates a new free client pool -func newFreeClientPool(db ethdb.Database, connectedLimit, totalLimit int, clock mclock.Clock) *freeClientPool { +func newFreeClientPool(db ethdb.Database, freeClientCap uint64, totalLimit int, clock mclock.Clock, removePeer func(string)) *freeClientPool { pool := &freeClientPool{ - db: db, - clock: clock, - addressMap: make(map[string]*freeClientPoolEntry), - connPool: prque.New(poolSetIndex), - disconnPool: prque.New(poolSetIndex), - connectedLimit: connectedLimit, - totalLimit: totalLimit, + db: db, + clock: clock, + addressMap: make(map[string]*freeClientPoolEntry), + connPool: prque.New(poolSetIndex), + disconnPool: prque.New(poolSetIndex), + freeClientCap: freeClientCap, + totalLimit: totalLimit, + removePeer: removePeer, } pool.loadFromDb() return pool @@ -85,22 +88,34 @@ func (f *freeClientPool) stop() { f.lock.Unlock() } +// registerPeer implements clientPool +func (f *freeClientPool) registerPeer(p *peer) { + if addr, ok := p.RemoteAddr().(*net.TCPAddr); ok { + if !f.connect(addr.IP.String(), p.id) { + f.removePeer(p.id) + } + } +} + // connect should be called after a successful handshake. If the connection was // rejected, there is no need to call disconnect. -// -// Note: the disconnectFn callback should not block. -func (f *freeClientPool) connect(address string, disconnectFn func()) bool { +func (f *freeClientPool) connect(address, id string) bool { f.lock.Lock() defer f.lock.Unlock() if f.closed { return false } + + if f.connectedLimit == 0 { + log.Debug("Client rejected", "address", address) + return false + } e := f.addressMap[address] now := f.clock.Now() var recentUsage int64 if e == nil { - e = &freeClientPoolEntry{address: address, index: -1} + e = &freeClientPoolEntry{address: address, index: -1, id: id} f.addressMap[address] = e } else { if e.connected { @@ -115,12 +130,7 @@ func (f *freeClientPool) connect(address string, disconnectFn func()) bool { i := f.connPool.PopItem().(*freeClientPoolEntry) if e.linUsage+int64(connectedBias)-i.linUsage < 0 { // kick it out and accept the new client - f.connPool.Remove(i.index) - f.calcLogUsage(i, now) - i.connected = false - f.disconnPool.Push(i, -i.logUsage) - log.Debug("Client kicked out", "address", i.address) - i.disconnectFn() + f.dropClient(i, now) } else { // keep the old client and reject the new one f.connPool.Push(i, i.linUsage) @@ -130,7 +140,7 @@ func (f *freeClientPool) connect(address string, disconnectFn func()) bool { } f.disconnPool.Remove(e.index) e.connected = true - e.disconnectFn = disconnectFn + e.id = id f.connPool.Push(e, e.linUsage) if f.connPool.Size()+f.disconnPool.Size() > f.totalLimit { f.disconnPool.Pop() @@ -139,6 +149,13 @@ func (f *freeClientPool) connect(address string, disconnectFn func()) bool { return true } +// unregisterPeer implements clientPool +func (f *freeClientPool) unregisterPeer(p *peer) { + if addr, ok := p.RemoteAddr().(*net.TCPAddr); ok { + f.disconnect(addr.IP.String()) + } +} + // disconnect should be called when a connection is terminated. If the disconnection // was initiated by the pool itself using disconnectFn then calling disconnect is // not necessary but permitted. @@ -163,6 +180,34 @@ func (f *freeClientPool) disconnect(address string) { log.Debug("Client disconnected", "address", address) } +// setConnLimit sets the maximum number of free client slots and also drops +// some peers if necessary +func (f *freeClientPool) setLimits(count int, totalCap uint64) { + f.lock.Lock() + defer f.lock.Unlock() + + f.connectedLimit = int(totalCap / f.freeClientCap) + if count < f.connectedLimit { + f.connectedLimit = count + } + now := mclock.Now() + for f.connPool.Size() > f.connectedLimit { + i := f.connPool.PopItem().(*freeClientPoolEntry) + f.dropClient(i, now) + } +} + +// dropClient disconnects a client and also moves it from the connected to the +// disconnected pool +func (f *freeClientPool) dropClient(i *freeClientPoolEntry, now mclock.AbsTime) { + f.connPool.Remove(i.index) + f.calcLogUsage(i, now) + i.connected = false + f.disconnPool.Push(i, -i.logUsage) + log.Debug("Client kicked out", "address", i.address) + f.removePeer(i.id) +} + // logOffset calculates the time-dependent offset for the logarithmic // representation of recent usage func (f *freeClientPool) logOffset(now mclock.AbsTime) int64 { @@ -245,7 +290,7 @@ func (f *freeClientPool) saveToDb() { // even though they are close to each other at any time they may wrap around int64 // limits over time. Comparison should be performed accordingly. type freeClientPoolEntry struct { - address string + address, id string connected bool disconnectFn func() linUsage, logUsage int64 diff --git a/vendor/github.com/ethereum/go-ethereum/les/freeclient_test.go b/vendor/github.com/ethereum/go-ethereum/les/freeclient_test.go index e95abc7a..19182226 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/freeclient_test.go +++ b/vendor/github.com/ethereum/go-ethereum/les/freeclient_test.go @@ -14,18 +14,17 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package les import ( "fmt" "math/rand" + "strconv" "testing" "time" "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/core/rawdb" ) func TestFreeClientPoolL10C100(t *testing.T) { @@ -44,32 +43,38 @@ const testFreeClientPoolTicks = 500000 func testFreeClientPool(t *testing.T, connLimit, clientCount int) { var ( - clock mclock.Simulated - db = ethdb.NewMemDatabase() - pool = newFreeClientPool(db, connLimit, 10000, &clock) - connected = make([]bool, clientCount) - connTicks = make([]int, clientCount) - disconnCh = make(chan int, clientCount) - ) - peerId := func(i int) string { - return fmt.Sprintf("test peer #%d", i) - } - disconnFn := func(i int) func() { - return func() { + clock mclock.Simulated + db = rawdb.NewMemoryDatabase() + connected = make([]bool, clientCount) + connTicks = make([]int, clientCount) + disconnCh = make(chan int, clientCount) + peerAddress = func(i int) string { + return fmt.Sprintf("addr #%d", i) + } + peerId = func(i int) string { + return fmt.Sprintf("id #%d", i) + } + disconnFn = func(id string) { + i, err := strconv.Atoi(id[4:]) + if err != nil { + panic(err) + } disconnCh <- i } - } + pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn) + ) + pool.setLimits(connLimit, uint64(connLimit)) // pool should accept new peers up to its connected limit for i := 0; i < connLimit; i++ { - if pool.connect(peerId(i), disconnFn(i)) { + if pool.connect(peerAddress(i), peerId(i)) { connected[i] = true } else { t.Fatalf("Test peer #%d rejected", i) } } // since all accepted peers are new and should not be kicked out, the next one should be rejected - if pool.connect(peerId(connLimit), disconnFn(connLimit)) { + if pool.connect(peerAddress(connLimit), peerId(connLimit)) { connected[connLimit] = true t.Fatalf("Peer accepted over connected limit") } @@ -80,11 +85,11 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) { i := rand.Intn(clientCount) if connected[i] { - pool.disconnect(peerId(i)) + pool.disconnect(peerAddress(i)) connected[i] = false connTicks[i] += tickCounter } else { - if pool.connect(peerId(i), disconnFn(i)) { + if pool.connect(peerAddress(i), peerId(i)) { connected[i] = true connTicks[i] -= tickCounter } @@ -93,7 +98,7 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) { for { select { case i := <-disconnCh: - pool.disconnect(peerId(i)) + pool.disconnect(peerAddress(i)) if connected[i] { connTicks[i] += tickCounter connected[i] = false @@ -119,20 +124,21 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) { } // a previously unknown peer should be accepted now - if !pool.connect("newPeer", func() {}) { + if !pool.connect("newAddr", "newId") { t.Fatalf("Previously unknown peer rejected") } // close and restart pool pool.stop() - pool = newFreeClientPool(db, connLimit, 10000, &clock) + pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn) + pool.setLimits(connLimit, uint64(connLimit)) // try connecting all known peers (connLimit should be filled up) for i := 0; i < clientCount; i++ { - pool.connect(peerId(i), func() {}) + pool.connect(peerAddress(i), peerId(i)) } // expect pool to remember known nodes and kick out one of them to accept a new one - if !pool.connect("newPeer2", func() {}) { + if !pool.connect("newAddr2", "newId2") { t.Errorf("Previously unknown peer rejected after restarting pool") } pool.stop() diff --git a/vendor/github.com/ethereum/go-ethereum/les/handler.go b/vendor/github.com/ethereum/go-ethereum/les/handler.go index 19ccbcd2..7c290b71 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/handler.go +++ b/vendor/github.com/ethereum/go-ethereum/les/handler.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( @@ -22,17 +21,16 @@ import ( "encoding/json" "fmt" "math/big" - "net" "sync" "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -74,7 +72,7 @@ type BlockChain interface { GetHeaderByHash(hash common.Hash) *types.Header CurrentHeader() *types.Header GetTd(hash common.Hash, number uint64) *big.Int - State() (*state.StateDB, error) + StateCache() state.Database InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) Rollback(chain []common.Hash) GetHeaderByNumber(number uint64) *types.Header @@ -89,21 +87,21 @@ type txPool interface { } type ProtocolManager struct { - lightSync bool - txpool txPool - txrelay *LesTxRelay - networkId uint64 - chainConfig *params.ChainConfig - iConfig *light.IndexerConfig - blockchain BlockChain - chainDb ethdb.Database - odr *LesOdr - server *LesServer - serverPool *serverPool - clientPool *freeClientPool - lesTopic discv5.Topic - reqDist *requestDistributor - retriever *retrieveManager + lightSync bool + txpool txPool + txrelay *LesTxRelay + networkId uint64 + chainConfig *params.ChainConfig + iConfig *light.IndexerConfig + blockchain BlockChain + chainDb ethdb.Database + odr *LesOdr + server *LesServer + serverPool *serverPool + lesTopic discv5.Topic + reqDist *requestDistributor + retriever *retrieveManager + servingQueue *servingQueue downloader *downloader.Downloader fetcher *lightFetcher @@ -119,12 +117,29 @@ type ProtocolManager struct { // wait group is used for graceful shutdowns during downloading // and processing - wg *sync.WaitGroup + wg *sync.WaitGroup + ulc *ulc } // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // with the ethereum network. -func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.IndexerConfig, lightSync bool, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, serverPool *serverPool, quitSync chan struct{}, wg *sync.WaitGroup) (*ProtocolManager, error) { +func NewProtocolManager( + chainConfig *params.ChainConfig, + indexerConfig *light.IndexerConfig, + lightSync bool, + networkId uint64, + mux *event.TypeMux, + engine consensus.Engine, + peers *peerSet, + blockchain BlockChain, + txpool txPool, + chainDb ethdb.Database, + odr *LesOdr, + txrelay *LesTxRelay, + serverPool *serverPool, + quitSync chan struct{}, + wg *sync.WaitGroup, + ulcConfig *eth.ULCConfig) (*ProtocolManager, error) { // Create the protocol manager with the base fields manager := &ProtocolManager{ lightSync: lightSync, @@ -147,6 +162,12 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In if odr != nil { manager.retriever = odr.retriever manager.reqDist = odr.retriever.dist + } else { + manager.servingQueue = newServingQueue(int64(time.Millisecond * 10)) + } + + if ulcConfig != nil { + manager.ulc = newULC(ulcConfig) } removePeer := manager.removePeer @@ -159,7 +180,6 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In manager.peers.notify((*downloaderPeerNotify)(manager)) manager.fetcher = newLightFetcher(manager) } - return manager, nil } @@ -170,11 +190,9 @@ func (pm *ProtocolManager) removePeer(id string) { func (pm *ProtocolManager) Start(maxPeers int) { pm.maxPeers = maxPeers - if pm.lightSync { go pm.syncer() } else { - pm.clientPool = newFreeClientPool(pm.chainDb, maxPeers, 10000, mclock.System{}) go func() { for range pm.newPeerCh { } @@ -192,8 +210,9 @@ func (pm *ProtocolManager) Stop() { pm.noMorePeers <- struct{}{} close(pm.quitSync) // quits syncer, fetcher - if pm.clientPool != nil { - pm.clientPool.stop() + + if pm.servingQueue != nil { + pm.servingQueue.stop() } // Disconnect existing sessions. @@ -234,7 +253,11 @@ func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWrit } func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { - return newPeer(pv, nv, p, newMeteredMsgWriter(rw)) + var isTrusted bool + if pm.isULCEnabled() { + isTrusted = pm.ulc.isTrusted(p.ID()) + } + return newPeer(pv, nv, isTrusted, p, newMeteredMsgWriter(rw)) } // handle is the callback invoked to manage the life cycle of a les peer. When @@ -260,33 +283,23 @@ func (pm *ProtocolManager) handle(p *peer) error { p.Log().Debug("Light Ethereum handshake failed", "err", err) return err } - - if !pm.lightSync && !p.Peer.Info().Network.Trusted { - addr, ok := p.RemoteAddr().(*net.TCPAddr) - // test peer address is not a tcp address, don't use client pool if can not typecast - if ok { - id := addr.IP.String() - if !pm.clientPool.connect(id, func() { go pm.removePeer(p.id) }) { - return p2p.DiscTooManyPeers - } - defer pm.clientPool.disconnect(id) - } + if p.fcClient != nil { + defer p.fcClient.Disconnect() } if rw, ok := p.rw.(*meteredMsgReadWriter); ok { rw.Init(p.version) } + // Register the peer locally if err := pm.peers.Register(p); err != nil { p.Log().Error("Light Ethereum peer registration failed", "err", err) return err } defer func() { - if pm.server != nil && pm.server.fcManager != nil && p.fcClient != nil { - p.fcClient.Remove(pm.server.fcManager) - } pm.removePeer(p.id) }() + // Register the peer in the downloader. If the downloader considers it banned, we disconnect if pm.lightSync { p.lock.Lock() @@ -301,34 +314,26 @@ func (pm *ProtocolManager) handle(p *peer) error { } } - stop := make(chan struct{}) - defer close(stop) - go func() { - // new block announce loop - for { - select { - case announce := <-p.announceChn: - p.SendAnnounce(announce) - case <-stop: - return - } - } - }() - // main loop. handle incoming messages. for { if err := pm.handleMsg(p); err != nil { p.Log().Debug("Light Ethereum message handling failed", "err", err) + if p.fcServer != nil { + p.fcServer.DumpLogs() + } return err } } } -var reqList = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, GetProofsV1Msg, SendTxMsg, SendTxV2Msg, GetTxStatusMsg, GetHeaderProofsMsg, GetProofsV2Msg, GetHelperTrieProofsMsg} - // handleMsg is invoked whenever an inbound message is received from a remote // peer. The remote connection is torn down upon returning any error. func (pm *ProtocolManager) handleMsg(p *peer) error { + select { + case err := <-p.errCh: + return err + default: + } // Read the next message from the remote peer, and ensure it's fully consumed msg, err := p.rw.ReadMsg() if err != nil { @@ -336,22 +341,31 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size) - costs := p.fcCosts[msg.Code] - reject := func(reqCnt, maxCnt uint64) bool { + p.responseCount++ + responseCount := p.responseCount + var ( + maxCost uint64 + task *servingTask + ) + + accept := func(reqID, reqCnt, maxCnt uint64) bool { + if reqCnt == 0 { + return false + } if p.fcClient == nil || reqCnt > maxCnt { - return true + return false } - bufValue, _ := p.fcClient.AcceptRequest() - cost := costs.baseCost + reqCnt*costs.reqCost - if cost > pm.server.defParams.BufLimit { - cost = pm.server.defParams.BufLimit + maxCost = p.fcCosts.getCost(msg.Code, reqCnt) + + if accepted, bufShort, servingPriority := p.fcClient.AcceptRequest(reqID, responseCount, maxCost); !accepted { + if bufShort > 0 { + p.Log().Error("Request came too early", "remaining", common.PrettyDuration(time.Duration(bufShort*1000000/p.fcParams.MinRecharge))) + } + return false + } else { + task = pm.servingQueue.newTask(servingPriority) } - if cost > bufValue { - recharge := time.Duration((cost - bufValue) * 1000000 / pm.server.defParams.MinRecharge) - p.Log().Error("Request came too early", "recharge", common.PrettyDuration(recharge)) - return true - } - return false + return task.start() } if msg.Size > ProtocolMaxMsgSize { @@ -361,6 +375,34 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { var deliverMsg *Msg + sendResponse := func(reqID, amount uint64, reply *reply, servingTime uint64) { + p.responseLock.Lock() + defer p.responseLock.Unlock() + + var replySize uint32 + if reply != nil { + replySize = reply.size() + } + var realCost uint64 + if pm.server.costTracker != nil { + realCost = pm.server.costTracker.realCost(servingTime, msg.Size, replySize) + pm.server.costTracker.updateStats(msg.Code, amount, servingTime, realCost) + } else { + realCost = maxCost + } + bv := p.fcClient.RequestProcessed(reqID, responseCount, maxCost, realCost) + if reply != nil { + p.queueSend(func() { + if err := reply.send(bv); err != nil { + select { + case p.errCh <- err: + default: + } + } + }) + } + } + // Handle the message depending on its contents switch msg.Code { case StatusMsg: @@ -371,26 +413,33 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // Block header query, collect the requested headers and reply case AnnounceMsg: p.Log().Trace("Received announce message") - if p.requestAnnounceType == announceTypeNone { - return errResp(ErrUnexpectedResponse, "") - } - var req announceData if err := msg.Decode(&req); err != nil { return errResp(ErrDecode, "%v: %v", msg, err) } - if p.requestAnnounceType == announceTypeSigned { - if err := req.checkSignature(p.ID()); err != nil { - p.Log().Trace("Invalid announcement signature", "err", err) - return err - } - p.Log().Trace("Valid announcement signature") + update, size := req.Update.decode() + if p.rejectUpdate(size) { + return errResp(ErrRequestRejected, "") } + p.updateFlowControl(update) - p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) - if pm.fetcher != nil { - pm.fetcher.announce(p, &req) + if req.Hash != (common.Hash{}) { + if p.announceType == announceTypeNone { + return errResp(ErrUnexpectedResponse, "") + } + if p.announceType == announceTypeSigned { + if err := req.checkSignature(p.ID(), update); err != nil { + p.Log().Trace("Invalid announcement signature", "err", err) + return err + } + p.Log().Trace("Valid announcement signature") + } + + p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth) + if pm.fetcher != nil { + pm.fetcher.announce(p, &req) + } } case GetBlockHeadersMsg: @@ -405,93 +454,94 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } query := req.Query - if reject(query.Amount, MaxHeaderFetch) { + if !accept(req.ReqID, query.Amount, MaxHeaderFetch) { return errResp(ErrRequestRejected, "") } + go func() { + hashMode := query.Origin.Hash != (common.Hash{}) + first := true + maxNonCanonical := uint64(100) - hashMode := query.Origin.Hash != (common.Hash{}) - first := true - maxNonCanonical := uint64(100) - - // Gather headers until the fetch or network limits is reached - var ( - bytes common.StorageSize - headers []*types.Header - unknown bool - ) - for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit { - // Retrieve the next header satisfying the query - var origin *types.Header - if hashMode { - if first { - first = false - origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) - if origin != nil { - query.Origin.Number = origin.Number.Uint64() + // Gather headers until the fetch or network limits is reached + var ( + bytes common.StorageSize + headers []*types.Header + unknown bool + ) + for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit { + if !first && !task.waitOrStop() { + return + } + // Retrieve the next header satisfying the query + var origin *types.Header + if hashMode { + if first { + origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) + if origin != nil { + query.Origin.Number = origin.Number.Uint64() + } + } else { + origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number) } } else { - origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number) + origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) } - } else { - origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) - } - if origin == nil { - break - } - headers = append(headers, origin) - bytes += estHeaderRlpSize + if origin == nil { + break + } + headers = append(headers, origin) + bytes += estHeaderRlpSize - // Advance to the next header of the query - switch { - case hashMode && query.Reverse: - // Hash based traversal towards the genesis block - ancestor := query.Skip + 1 - if ancestor == 0 { - unknown = true - } else { - query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical) - unknown = (query.Origin.Hash == common.Hash{}) - } - case hashMode && !query.Reverse: - // Hash based traversal towards the leaf block - var ( - current = origin.Number.Uint64() - next = current + query.Skip + 1 - ) - if next <= current { - infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ") - p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos) - unknown = true - } else { - if header := pm.blockchain.GetHeaderByNumber(next); header != nil { - nextHash := header.Hash() - expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical) - if expOldHash == query.Origin.Hash { - query.Origin.Hash, query.Origin.Number = nextHash, next + // Advance to the next header of the query + switch { + case hashMode && query.Reverse: + // Hash based traversal towards the genesis block + ancestor := query.Skip + 1 + if ancestor == 0 { + unknown = true + } else { + query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical) + unknown = (query.Origin.Hash == common.Hash{}) + } + case hashMode && !query.Reverse: + // Hash based traversal towards the leaf block + var ( + current = origin.Number.Uint64() + next = current + query.Skip + 1 + ) + if next <= current { + infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ") + p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos) + unknown = true + } else { + if header := pm.blockchain.GetHeaderByNumber(next); header != nil { + nextHash := header.Hash() + expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical) + if expOldHash == query.Origin.Hash { + query.Origin.Hash, query.Origin.Number = nextHash, next + } else { + unknown = true + } } else { unknown = true } + } + case query.Reverse: + // Number based traversal towards the genesis block + if query.Origin.Number >= query.Skip+1 { + query.Origin.Number -= query.Skip + 1 } else { unknown = true } - } - case query.Reverse: - // Number based traversal towards the genesis block - if query.Origin.Number >= query.Skip+1 { - query.Origin.Number -= query.Skip + 1 - } else { - unknown = true - } - case !query.Reverse: - // Number based traversal towards the leaf block - query.Origin.Number += query.Skip + 1 + case !query.Reverse: + // Number based traversal towards the leaf block + query.Origin.Number += query.Skip + 1 + } + first = false } - } - - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + query.Amount*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, query.Amount, rcost) - return p.SendBlockHeaders(req.ReqID, bv, headers) + sendResponse(req.ReqID, query.Amount, p.ReplyBlockHeaders(req.ReqID, headers), task.done()) + }() case BlockHeadersMsg: if pm.downloader == nil { @@ -507,7 +557,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) if pm.fetcher != nil && pm.fetcher.requestedID(resp.ReqID) { pm.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) } else { @@ -533,24 +583,27 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bodies []rlp.RawValue ) reqCnt := len(req.Hashes) - if reject(uint64(reqCnt), MaxBodyFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxBodyFetch) { return errResp(ErrRequestRejected, "") } - for _, hash := range req.Hashes { - if bytes >= softResponseLimit { - break - } - // Retrieve the requested block body, stopping if enough was found - if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { - if data := rawdb.ReadBodyRLP(pm.chainDb, hash, *number); len(data) != 0 { - bodies = append(bodies, data) - bytes += len(data) + go func() { + for i, hash := range req.Hashes { + if i != 0 && !task.waitOrStop() { + return + } + if bytes >= softResponseLimit { + break + } + // Retrieve the requested block body, stopping if enough was found + if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { + if data := rawdb.ReadBodyRLP(pm.chainDb, hash, *number); len(data) != 0 { + bodies = append(bodies, data) + bytes += len(data) + } } } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendBlockBodiesRLP(req.ReqID, bv, bodies) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyBlockBodiesRLP(req.ReqID, bodies), task.done()) + }() case BlockBodiesMsg: if pm.odr == nil { @@ -566,7 +619,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgBlockBodies, ReqID: resp.ReqID, @@ -589,33 +642,45 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { data [][]byte ) reqCnt := len(req.Reqs) - if reject(uint64(reqCnt), MaxCodeFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxCodeFetch) { return errResp(ErrRequestRejected, "") } - for _, req := range req.Reqs { - // Retrieve the requested state entry, stopping if enough was found - if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil { - if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil { - statedb, err := pm.blockchain.State() - if err != nil { - continue - } - account, err := pm.getAccount(statedb, header.Root, common.BytesToHash(req.AccKey)) - if err != nil { - continue - } - code, _ := statedb.Database().TrieDB().Node(common.BytesToHash(account.CodeHash)) + go func() { + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + // Look up the root hash belonging to the request + number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash) + if number == nil { + p.Log().Warn("Failed to retrieve block num for code", "hash", req.BHash) + continue + } + header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number) + if header == nil { + p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", req.BHash) + continue + } + triedb := pm.blockchain.StateCache().TrieDB() - data = append(data, code) - if bytes += len(code); bytes >= softResponseLimit { - break - } + account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(req.AccKey)) + if err != nil { + p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err) + continue + } + code, err := triedb.Node(common.BytesToHash(account.CodeHash)) + if err != nil { + p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err) + continue + } + // Accumulate the code and abort if enough data was retrieved + data = append(data, code) + if bytes += len(code); bytes >= softResponseLimit { + break } } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendCode(req.ReqID, bv, data) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done()) + }() case CodeMsg: if pm.odr == nil { @@ -631,7 +696,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgCode, ReqID: resp.ReqID, @@ -654,34 +719,37 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { receipts []rlp.RawValue ) reqCnt := len(req.Hashes) - if reject(uint64(reqCnt), MaxReceiptFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxReceiptFetch) { return errResp(ErrRequestRejected, "") } - for _, hash := range req.Hashes { - if bytes >= softResponseLimit { - break - } - // Retrieve the requested block's receipts, skipping if unknown to us - var results types.Receipts - if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { - results = rawdb.ReadReceipts(pm.chainDb, hash, *number) - } - if results == nil { - if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { - continue + go func() { + for i, hash := range req.Hashes { + if i != 0 && !task.waitOrStop() { + return + } + if bytes >= softResponseLimit { + break + } + // Retrieve the requested block's receipts, skipping if unknown to us + var results types.Receipts + if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { + results = rawdb.ReadReceipts(pm.chainDb, hash, *number) + } + if results == nil { + if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { + continue + } + } + // If known, encode and queue for response packet + if encoded, err := rlp.EncodeToBytes(results); err != nil { + log.Error("Failed to encode receipt", "err", err) + } else { + receipts = append(receipts, encoded) + bytes += len(encoded) } } - // If known, encode and queue for response packet - if encoded, err := rlp.EncodeToBytes(results); err != nil { - log.Error("Failed to encode receipt", "err", err) - } else { - receipts = append(receipts, encoded) - bytes += len(encoded) - } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendReceiptsRLP(req.ReqID, bv, receipts) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyReceiptsRLP(req.ReqID, receipts), task.done()) + }() case ReceiptsMsg: if pm.odr == nil { @@ -697,7 +765,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgReceipts, ReqID: resp.ReqID, @@ -720,42 +788,63 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { proofs proofsData ) reqCnt := len(req.Reqs) - if reject(uint64(reqCnt), MaxProofsFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxProofsFetch) { return errResp(ErrRequestRejected, "") } - for _, req := range req.Reqs { - // Retrieve the requested state entry, stopping if enough was found - if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil { - if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil { - statedb, err := pm.blockchain.State() - if err != nil { + go func() { + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + // Look up the root hash belonging to the request + number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash) + if number == nil { + p.Log().Warn("Failed to retrieve block num for proof", "hash", req.BHash) + continue + } + header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number) + if header == nil { + p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", req.BHash) + continue + } + // Open the account or storage trie for the request + statedb := pm.blockchain.StateCache() + + var trie state.Trie + switch len(req.AccKey) { + case 0: + // No account key specified, open an account trie + trie, err = statedb.OpenTrie(header.Root) + if trie == nil || err != nil { + p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", header.Root, "err", err) continue } - var trie state.Trie - if len(req.AccKey) > 0 { - account, err := pm.getAccount(statedb, header.Root, common.BytesToHash(req.AccKey)) - if err != nil { - continue - } - trie, _ = statedb.Database().OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root) - } else { - trie, _ = statedb.Database().OpenTrie(header.Root) + default: + // Account key specified, open a storage trie + account, err := pm.getAccount(statedb.TrieDB(), header.Root, common.BytesToHash(req.AccKey)) + if err != nil { + p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err) + continue } - if trie != nil { - var proof light.NodeList - trie.Prove(req.Key, 0, &proof) - - proofs = append(proofs, proof) - if bytes += proof.DataSize(); bytes >= softResponseLimit { - break - } + trie, err = statedb.OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root) + if trie == nil || err != nil { + p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "root", account.Root, "err", err) + continue } } + // Prove the user's request from the account or stroage trie + var proof light.NodeList + if err := trie.Prove(req.Key, 0, &proof); err != nil { + p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err) + continue + } + proofs = append(proofs, proof) + if bytes += proof.DataSize(); bytes >= softResponseLimit { + break + } } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendProofs(req.ReqID, bv, proofs) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofs(req.ReqID, proofs), task.done()) + }() case GetProofsV2Msg: p.Log().Trace("Received les/2 proofs request") @@ -770,54 +859,73 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // Gather state data until the fetch or network limits is reached var ( lastBHash common.Hash - statedb *state.StateDB root common.Hash ) reqCnt := len(req.Reqs) - if reject(uint64(reqCnt), MaxProofsFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxProofsFetch) { return errResp(ErrRequestRejected, "") } + go func() { + nodes := light.NewNodeSet() - nodes := light.NewNodeSet() + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + // Look up the root hash belonging to the request + var ( + number *uint64 + header *types.Header + trie state.Trie + ) + if req.BHash != lastBHash { + root, lastBHash = common.Hash{}, req.BHash - for _, req := range req.Reqs { - // Look up the state belonging to the request - if statedb == nil || req.BHash != lastBHash { - statedb, root, lastBHash = nil, common.Hash{}, req.BHash + if number = rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number == nil { + p.Log().Warn("Failed to retrieve block num for proof", "hash", req.BHash) + continue + } + if header = rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header == nil { + p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", req.BHash) + continue + } + root = header.Root + } + // Open the account or storage trie for the request + statedb := pm.blockchain.StateCache() - if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil { - if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil { - statedb, _ = pm.blockchain.State() - root = header.Root + switch len(req.AccKey) { + case 0: + // No account key specified, open an account trie + trie, err = statedb.OpenTrie(root) + if trie == nil || err != nil { + p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err) + continue + } + default: + // Account key specified, open a storage trie + account, err := pm.getAccount(statedb.TrieDB(), root, common.BytesToHash(req.AccKey)) + if err != nil { + p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err) + continue + } + trie, err = statedb.OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root) + if trie == nil || err != nil { + p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "root", account.Root, "err", err) + continue } } - } - if statedb == nil { - continue - } - // Pull the account or storage trie of the request - var trie state.Trie - if len(req.AccKey) > 0 { - account, err := pm.getAccount(statedb, root, common.BytesToHash(req.AccKey)) - if err != nil { + // Prove the user's request from the account or stroage trie + if err := trie.Prove(req.Key, req.FromLevel, nodes); err != nil { + p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err) continue } - trie, _ = statedb.Database().OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root) - } else { - trie, _ = statedb.Database().OpenTrie(root) + if nodes.DataSize() >= softResponseLimit { + break + } } - if trie == nil { - continue - } - // Prove the user's request from the account or stroage trie - trie.Prove(req.Key, req.FromLevel, nodes) - if nodes.DataSize() >= softResponseLimit { - break - } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendProofsV2(req.ReqID, bv, nodes.NodeList()) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done()) + }() case ProofsV1Msg: if pm.odr == nil { @@ -833,7 +941,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgProofsV1, ReqID: resp.ReqID, @@ -854,7 +962,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgProofsV2, ReqID: resp.ReqID, @@ -877,34 +985,37 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { proofs []ChtResp ) reqCnt := len(req.Reqs) - if reject(uint64(reqCnt), MaxHelperTrieProofsFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxHelperTrieProofsFetch) { return errResp(ErrRequestRejected, "") } - trieDb := trie.NewDatabase(ethdb.NewTable(pm.chainDb, light.ChtTablePrefix)) - for _, req := range req.Reqs { - if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil { - sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*pm.iConfig.ChtSize-1) - if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) { - trie, err := trie.New(root, trieDb) - if err != nil { - continue - } - var encNumber [8]byte - binary.BigEndian.PutUint64(encNumber[:], req.BlockNum) + go func() { + trieDb := trie.NewDatabase(rawdb.NewTable(pm.chainDb, light.ChtTablePrefix)) + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil { + sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*pm.iConfig.ChtSize-1) + if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) { + trie, err := trie.New(root, trieDb) + if err != nil { + continue + } + var encNumber [8]byte + binary.BigEndian.PutUint64(encNumber[:], req.BlockNum) - var proof light.NodeList - trie.Prove(encNumber[:], 0, &proof) + var proof light.NodeList + trie.Prove(encNumber[:], 0, &proof) - proofs = append(proofs, ChtResp{Header: header, Proof: proof}) - if bytes += proof.DataSize() + estHeaderRlpSize; bytes >= softResponseLimit { - break + proofs = append(proofs, ChtResp{Header: header, Proof: proof}) + if bytes += proof.DataSize() + estHeaderRlpSize; bytes >= softResponseLimit { + break + } } } } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendHeaderProofs(req.ReqID, bv, proofs) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHeaderProofs(req.ReqID, proofs), task.done()) + }() case GetHelperTrieProofsMsg: p.Log().Trace("Received helper trie proof request") @@ -922,50 +1033,53 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { auxData [][]byte ) reqCnt := len(req.Reqs) - if reject(uint64(reqCnt), MaxHelperTrieProofsFetch) { + if !accept(req.ReqID, uint64(reqCnt), MaxHelperTrieProofsFetch) { return errResp(ErrRequestRejected, "") } + go func() { - var ( - lastIdx uint64 - lastType uint - root common.Hash - auxTrie *trie.Trie - ) - nodes := light.NewNodeSet() - for _, req := range req.Reqs { - if auxTrie == nil || req.Type != lastType || req.TrieIdx != lastIdx { - auxTrie, lastType, lastIdx = nil, req.Type, req.TrieIdx + var ( + lastIdx uint64 + lastType uint + root common.Hash + auxTrie *trie.Trie + ) + nodes := light.NewNodeSet() + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + if auxTrie == nil || req.Type != lastType || req.TrieIdx != lastIdx { + auxTrie, lastType, lastIdx = nil, req.Type, req.TrieIdx - var prefix string - if root, prefix = pm.getHelperTrie(req.Type, req.TrieIdx); root != (common.Hash{}) { - auxTrie, _ = trie.New(root, trie.NewDatabase(ethdb.NewTable(pm.chainDb, prefix))) + var prefix string + if root, prefix = pm.getHelperTrie(req.Type, req.TrieIdx); root != (common.Hash{}) { + auxTrie, _ = trie.New(root, trie.NewDatabase(rawdb.NewTable(pm.chainDb, prefix))) + } } - } - if req.AuxReq == auxRoot { - var data []byte - if root != (common.Hash{}) { - data = root[:] - } - auxData = append(auxData, data) - auxBytes += len(data) - } else { - if auxTrie != nil { - auxTrie.Prove(req.Key, req.FromLevel, nodes) - } - if req.AuxReq != 0 { - data := pm.getHelperTrieAuxData(req) + if req.AuxReq == auxRoot { + var data []byte + if root != (common.Hash{}) { + data = root[:] + } auxData = append(auxData, data) auxBytes += len(data) + } else { + if auxTrie != nil { + auxTrie.Prove(req.Key, req.FromLevel, nodes) + } + if req.AuxReq != 0 { + data := pm.getHelperTrieAuxData(req) + auxData = append(auxData, data) + auxBytes += len(data) + } + } + if nodes.DataSize()+auxBytes >= softResponseLimit { + break } } - if nodes.DataSize()+auxBytes >= softResponseLimit { - break - } - } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendHelperTrieProofs(req.ReqID, bv, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}), task.done()) + }() case HeaderProofsMsg: if pm.odr == nil { @@ -980,7 +1094,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&resp); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgHeaderProofs, ReqID: resp.ReqID, @@ -1001,7 +1115,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) deliverMsg = &Msg{ MsgType: MsgHelperTrieProofs, ReqID: resp.ReqID, @@ -1018,13 +1132,18 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } reqCnt := len(txs) - if reject(uint64(reqCnt), MaxTxSend) { + if !accept(0, uint64(reqCnt), MaxTxSend) { return errResp(ErrRequestRejected, "") } - pm.txpool.AddRemotes(txs) - - _, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) + go func() { + for i, tx := range txs { + if i != 0 && !task.waitOrStop() { + return + } + pm.txpool.AddRemotes([]*types.Transaction{tx}) + } + sendResponse(0, uint64(reqCnt), nil, task.done()) + }() case SendTxV2Msg: if pm.txpool == nil { @@ -1039,29 +1158,27 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } reqCnt := len(req.Txs) - if reject(uint64(reqCnt), MaxTxSend) { + if !accept(req.ReqID, uint64(reqCnt), MaxTxSend) { return errResp(ErrRequestRejected, "") } - - hashes := make([]common.Hash, len(req.Txs)) - for i, tx := range req.Txs { - hashes[i] = tx.Hash() - } - stats := pm.txStatus(hashes) - for i, stat := range stats { - if stat.Status == core.TxStatusUnknown { - if errs := pm.txpool.AddRemotes([]*types.Transaction{req.Txs[i]}); errs[0] != nil { - stats[i].Error = errs[0].Error() - continue + go func() { + stats := make([]txStatus, len(req.Txs)) + for i, tx := range req.Txs { + if i != 0 && !task.waitOrStop() { + return + } + hash := tx.Hash() + stats[i] = pm.txStatus(hash) + if stats[i].Status == core.TxStatusUnknown { + if errs := pm.txpool.AddRemotes([]*types.Transaction{tx}); errs[0] != nil { + stats[i].Error = errs[0].Error() + continue + } + stats[i] = pm.txStatus(hash) } - stats[i] = pm.txStatus([]common.Hash{hashes[i]})[0] } - } - - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - - return p.SendTxStatus(req.ReqID, bv, stats) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done()) + }() case GetTxStatusMsg: if pm.txpool == nil { @@ -1076,13 +1193,19 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } reqCnt := len(req.Hashes) - if reject(uint64(reqCnt), MaxTxStatus) { + if !accept(req.ReqID, uint64(reqCnt), MaxTxStatus) { return errResp(ErrRequestRejected, "") } - bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) - pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - - return p.SendTxStatus(req.ReqID, bv, pm.txStatus(req.Hashes)) + go func() { + stats := make([]txStatus, len(req.Hashes)) + for i, hash := range req.Hashes { + if i != 0 && !task.waitOrStop() { + return + } + stats[i] = pm.txStatus(hash) + } + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done()) + }() case TxStatusMsg: if pm.odr == nil { @@ -1098,7 +1221,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } - p.fcServer.GotReply(resp.ReqID, resp.BV) + p.fcServer.ReceivedReply(resp.ReqID, resp.BV) default: p.Log().Trace("Received unknown message", "code", msg.Code) @@ -1118,8 +1241,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } // getAccount retrieves an account from the state based at root. -func (pm *ProtocolManager) getAccount(statedb *state.StateDB, root, hash common.Hash) (state.Account, error) { - trie, err := trie.New(root, statedb.Database().TrieDB()) +func (pm *ProtocolManager) getAccount(triedb *trie.Database, root, hash common.Hash) (state.Account, error) { + trie, err := trie.New(root, triedb) if err != nil { return state.Account{}, err } @@ -1158,21 +1281,25 @@ func (pm *ProtocolManager) getHelperTrieAuxData(req HelperTrieReq) []byte { return nil } -func (pm *ProtocolManager) txStatus(hashes []common.Hash) []txStatus { - stats := make([]txStatus, len(hashes)) - for i, stat := range pm.txpool.Status(hashes) { - // Save the status we've got from the transaction pool - stats[i].Status = stat - - // If the transaction is unknown to the pool, try looking it up locally - if stat == core.TxStatusUnknown { - if block, number, index := rawdb.ReadTxLookupEntry(pm.chainDb, hashes[i]); block != (common.Hash{}) { - stats[i].Status = core.TxStatusIncluded - stats[i].Lookup = &rawdb.TxLookupEntry{BlockHash: block, BlockIndex: number, Index: index} - } +func (pm *ProtocolManager) txStatus(hash common.Hash) txStatus { + var stat txStatus + stat.Status = pm.txpool.Status([]common.Hash{hash})[0] + // If the transaction is unknown to the pool, try looking it up locally + if stat.Status == core.TxStatusUnknown { + if tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(pm.chainDb, hash); tx != nil { + stat.Status = core.TxStatusIncluded + stat.Lookup = &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex} } } - return stats + return stat +} + +// isULCEnabled returns true if we can use ULC +func (pm *ProtocolManager) isULCEnabled() bool { + if pm.ulc == nil || len(pm.ulc.trustedKeys) == 0 { + return false + } + return true } // downloaderPeerNotify implements peerSetNotify @@ -1200,7 +1327,7 @@ func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, s request: func(dp distPeer) func() { peer := dp.(*peer) cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) - peer.fcServer.QueueRequest(reqID, cost) + peer.fcServer.QueuedRequest(reqID, cost) return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) } }, } @@ -1224,7 +1351,7 @@ func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip request: func(dp distPeer) func() { peer := dp.(*peer) cost := peer.GetRequestCost(GetBlockHeadersMsg, amount) - peer.fcServer.QueueRequest(reqID, cost) + peer.fcServer.QueuedRequest(reqID, cost) return func() { peer.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) } }, } diff --git a/vendor/github.com/ethereum/go-ethereum/les/handler_test.go b/vendor/github.com/ethereum/go-ethereum/les/handler_test.go index 43be7f41..5cf31b8f 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/handler_test.go +++ b/vendor/github.com/ethereum/go-ethereum/les/handler_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -405,7 +404,7 @@ func testGetCHTProofs(t *testing.T, protocol int) { switch protocol { case 1: root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(frequency-1).Hash()) - trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(server.db, light.ChtTablePrefix))) + trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) var proof light.NodeList trie.Prove(key, 0, &proof) @@ -413,7 +412,7 @@ func testGetCHTProofs(t *testing.T, protocol int) { case 2: root := light.GetChtRoot(server.db, (frequency/config.ChtSize)-1, bc.GetHeaderByNumber(frequency-1).Hash()) - trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(server.db, light.ChtTablePrefix))) + trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) trie.Prove(key, 0, &proofsV2.Proofs) } // Assemble the requests for the different protocols @@ -480,7 +479,7 @@ func TestGetBloombitsProofs(t *testing.T) { var proofs HelperTrieResps root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash()) - trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(server.db, light.BloomTrieTablePrefix))) + trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix))) trie.Prove(key, 0, &proofs.Proofs) // Send the proof request and verify the response @@ -493,8 +492,8 @@ func TestGetBloombitsProofs(t *testing.T) { } func TestTransactionStatusLes2(t *testing.T) { - db := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db) + db := rawdb.NewMemoryDatabase() + pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db, nil) chain := pm.blockchain.(*core.BlockChain) config := core.DefaultTxPoolConfig config.Journal = "" @@ -559,8 +558,8 @@ func TestTransactionStatusLes2(t *testing.T) { // check if their status is included now block1hash := rawdb.ReadCanonicalHash(db, 1) - test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) - test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) + test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) + test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) // create a reorg that rolls them back gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 2, func(i int, block *core.BlockGen) {}) diff --git a/vendor/github.com/ethereum/go-ethereum/les/helper_test.go b/vendor/github.com/ethereum/go-ethereum/les/helper_test.go index b46d41f1..020c69e1 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/helper_test.go +++ b/vendor/github.com/ethereum/go-ethereum/les/helper_test.go @@ -27,8 +27,10 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -133,20 +135,10 @@ func testIndexers(db ethdb.Database, odr light.OdrBackend, iConfig *light.Indexe return chtIndexer, bloomIndexer, bloomTrieIndexer } -func testRCL() RequestCostList { - cl := make(RequestCostList, len(reqList)) - for i, code := range reqList { - cl[i].MsgCode = code - cl[i].BaseCost = 0 - cl[i].ReqCost = 0 - } - return cl -} - // newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, potential notification // channels for different events and relative chain indexers array. -func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database) (*ProtocolManager, error) { +func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) (*ProtocolManager, error) { var ( evmux = new(event.TypeMux) engine = ethash.NewFaker() @@ -176,21 +168,21 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor if lightSync { indexConfig = light.TestClientIndexerConfig } - pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup)) + pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig) if err != nil { return nil, err } if !lightSync { srv := &LesServer{lesCommons: lesCommons{protocolManager: pm}} pm.server = srv + pm.servingQueue.setThreads(4) - srv.defParams = &flowcontrol.ServerParams{ + srv.defParams = flowcontrol.ServerParams{ BufLimit: testBufLimit, MinRecharge: 1, } - srv.fcManager = flowcontrol.NewClientManager(50, 10, 1000000000) - srv.fcCostStats = newCostStats(nil) + srv.fcManager = flowcontrol.NewClientManager(nil, &mclock.System{}) } pm.Start(1000) return pm, nil @@ -200,8 +192,8 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor // with the given number of blocks already known, potential notification // channels for different events and relative chain indexers array. In case of an error, the constructor force- // fails the test. -func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database) *ProtocolManager { - pm, err := newTestProtocolManager(lightSync, blocks, generator, odr, peers, db) +func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) *ProtocolManager { + pm, err := newTestProtocolManager(lightSync, blocks, generator, odr, peers, db, ulcConfig) if err != nil { t.Fatalf("Failed to create protocol manager: %v", err) } @@ -304,7 +296,7 @@ func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNu expList = expList.add("txRelay", nil) expList = expList.add("flowControl/BL", testBufLimit) expList = expList.add("flowControl/MRR", uint64(1)) - expList = expList.add("flowControl/MRC", testRCL()) + expList = expList.add("flowControl/MRC", testCostList()) if err := p2p.ExpectMsg(p.app, StatusMsg, expList); err != nil { t.Fatalf("status recv: %v", err) @@ -313,7 +305,7 @@ func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNu t.Fatalf("status send: %v", err) } - p.fcServerParams = &flowcontrol.ServerParams{ + p.fcParams = flowcontrol.ServerParams{ BufLimit: testBufLimit, MinRecharge: 1, } @@ -340,10 +332,10 @@ type TestEntity struct { // newServerEnv creates a server testing environment with a connected test peer for testing purpose. func newServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer)) (*TestEntity, func()) { - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() cIndexer, bIndexer, btIndexer := testIndexers(db, nil, light.TestServerIndexerConfig) - pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, nil, db) + pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, nil, db, nil) peer, _ := newTestPeer(t, "peer", protocol, pm, true) cIndexer.Start(pm.blockchain.(*core.BlockChain)) @@ -372,10 +364,10 @@ func newServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*cor // newClientServerEnv creates a client/server arch environment with a connected les server and light client pair // for testing purpose. func newClientServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer), newPeer bool) (*TestEntity, *TestEntity, func()) { - db, ldb := ethdb.NewMemDatabase(), ethdb.NewMemDatabase() + db, ldb := rawdb.NewMemoryDatabase(), rawdb.NewMemoryDatabase() peers, lPeers := newPeerSet(), newPeerSet() - dist := newRequestDistributor(lPeers, make(chan struct{})) + dist := newRequestDistributor(lPeers, make(chan struct{}), &mclock.System{}) rm := newRetrieveManager(lPeers, dist, nil) odr := NewLesOdr(ldb, light.TestClientIndexerConfig, rm) @@ -383,8 +375,8 @@ func newClientServerEnv(t *testing.T, blocks int, protocol int, waitIndexers fun lcIndexer, lbIndexer, lbtIndexer := testIndexers(ldb, odr, light.TestClientIndexerConfig) odr.SetIndexers(lcIndexer, lbtIndexer, lbIndexer) - pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, peers, db) - lpm := newTestProtocolManagerMust(t, true, 0, nil, odr, lPeers, ldb) + pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, peers, db, nil) + lpm := newTestProtocolManagerMust(t, true, 0, nil, odr, lPeers, ldb, nil) startIndexers := func(clientMode bool, pm *ProtocolManager) { if clientMode { diff --git a/vendor/github.com/ethereum/go-ethereum/les/odr.go b/vendor/github.com/ethereum/go-ethereum/les/odr.go index 9def05a6..5d98c66a 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/odr.go +++ b/vendor/github.com/ethereum/go-ethereum/les/odr.go @@ -109,12 +109,15 @@ func (odr *LesOdr) Retrieve(ctx context.Context, req light.OdrRequest) (err erro }, canSend: func(dp distPeer) bool { p := dp.(*peer) - return lreq.CanSend(p) + if !p.isOnlyAnnounce { + return lreq.CanSend(p) + } + return false }, request: func(dp distPeer) func() { p := dp.(*peer) cost := lreq.GetCost(p) - p.fcServer.QueueRequest(reqID, cost) + p.fcServer.QueuedRequest(reqID, cost) return func() { lreq.Request(reqID, p) } }, } diff --git a/vendor/github.com/ethereum/go-ethereum/les/odr_requests.go b/vendor/github.com/ethereum/go-ethereum/les/odr_requests.go index 0f2e5dd9..6bd4a293 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/odr_requests.go +++ b/vendor/github.com/ethereum/go-ethereum/les/odr_requests.go @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package les import ( @@ -560,7 +558,7 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { // readTraceDB stores the keys of database reads. We use this to check that received node // sets contain only the trie nodes necessary to make proofs pass. type readTraceDB struct { - db trie.DatabaseReader + db ethdb.Reader reads map[string]struct{} } diff --git a/vendor/github.com/ethereum/go-ethereum/les/peer.go b/vendor/github.com/ethereum/go-ethereum/les/peer.go index 678384f0..0c15add9 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/peer.go +++ b/vendor/github.com/ethereum/go-ethereum/les/peer.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( @@ -25,6 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/les/flowcontrol" @@ -42,6 +42,17 @@ var ( const maxResponseErrors = 50 // number of invalid responses tolerated (makes the protocol less brittle but still avoids spam) +// capacity limitation for parameter updates +const ( + allowedUpdateBytes = 100000 // initial/maximum allowed update size + allowedUpdateRate = time.Millisecond * 10 // time constant for recharging one byte of allowance +) + +// if the total encoded size of a sent transaction batch is over txSizeCostLimit +// per transaction then the request cost is calculated as proportional to the +// encoded size instead of the transaction count +const txSizeCostLimit = 0x10000 + const ( announceTypeNone = iota announceTypeSimple @@ -56,39 +67,69 @@ type peer struct { version int // Protocol version negotiated network uint64 // Network ID being on - announceType, requestAnnounceType uint64 + announceType uint64 id string headInfo *announceData lock sync.RWMutex - announceChn chan announceData - sendQueue *execQueue + sendQueue *execQueue + + errCh chan error + // responseLock ensures that responses are queued in the same order as + // RequestProcessed is called + responseLock sync.Mutex + responseCount uint64 poolEntry *poolEntry hasBlock func(common.Hash, uint64, bool) bool responseErrors int + updateCounter uint64 + updateTime mclock.AbsTime - fcClient *flowcontrol.ClientNode // nil if the peer is server only - fcServer *flowcontrol.ServerNode // nil if the peer is client only - fcServerParams *flowcontrol.ServerParams - fcCosts requestCostTable + fcClient *flowcontrol.ClientNode // nil if the peer is server only + fcServer *flowcontrol.ServerNode // nil if the peer is client only + fcParams flowcontrol.ServerParams + fcCosts requestCostTable + + isTrusted bool + isOnlyAnnounce bool } -func newPeer(version int, network uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { - id := p.ID() - +func newPeer(version int, network uint64, isTrusted bool, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { return &peer{ - Peer: p, - rw: rw, - version: version, - network: network, - id: fmt.Sprintf("%x", id[:8]), - announceChn: make(chan announceData, 20), + Peer: p, + rw: rw, + version: version, + network: network, + id: fmt.Sprintf("%x", p.ID().Bytes()), + isTrusted: isTrusted, + errCh: make(chan error, 1), } } +// rejectUpdate returns true if a parameter update has to be rejected because +// the size and/or rate of updates exceed the capacity limitation +func (p *peer) rejectUpdate(size uint64) bool { + now := mclock.Now() + if p.updateCounter == 0 { + p.updateTime = now + } else { + dt := now - p.updateTime + r := uint64(dt / mclock.AbsTime(allowedUpdateRate)) + if p.updateCounter > r { + p.updateCounter -= r + p.updateTime += mclock.AbsTime(allowedUpdateRate * time.Duration(r)) + } else { + p.updateCounter = 0 + p.updateTime = now + } + } + p.updateCounter += size + return p.updateCounter > allowedUpdateBytes +} + func (p *peer) canQueue() bool { return p.sendQueue.canQueue() } @@ -143,6 +184,20 @@ func (p *peer) waitBefore(maxCost uint64) (time.Duration, float64) { return p.fcServer.CanSend(maxCost) } +// updateCapacity updates the request serving capacity assigned to a given client +// and also sends an announcement about the updated flow control parameters +func (p *peer) updateCapacity(cap uint64) { + p.responseLock.Lock() + defer p.responseLock.Unlock() + + p.fcParams = flowcontrol.ServerParams{MinRecharge: cap, BufLimit: cap * bufLimitRatio} + p.fcClient.UpdateParams(p.fcParams) + var kvList keyValueList + kvList = kvList.add("flowControl/MRR", cap) + kvList = kvList.add("flowControl/BL", cap*bufLimitRatio) + p.queueSend(func() { p.SendAnnounce(announceData{Update: kvList}) }) +} + func sendRequest(w p2p.MsgWriter, msgcode, reqID, cost uint64, data interface{}) error { type req struct { ReqID uint64 @@ -151,12 +206,27 @@ func sendRequest(w p2p.MsgWriter, msgcode, reqID, cost uint64, data interface{}) return p2p.Send(w, msgcode, req{reqID, data}) } -func sendResponse(w p2p.MsgWriter, msgcode, reqID, bv uint64, data interface{}) error { +// reply struct represents a reply with the actual data already RLP encoded and +// only the bv (buffer value) missing. This allows the serving mechanism to +// calculate the bv value which depends on the data size before sending the reply. +type reply struct { + w p2p.MsgWriter + msgcode, reqID uint64 + data rlp.RawValue +} + +// send sends the reply with the calculated buffer value +func (r *reply) send(bv uint64) error { type resp struct { ReqID, BV uint64 - Data interface{} + Data rlp.RawValue } - return p2p.Send(w, msgcode, resp{reqID, bv, data}) + return p2p.Send(r.w, r.msgcode, resp{r.reqID, bv, r.data}) +} + +// size returns the RLP encoded size of the message data +func (r *reply) size() uint32 { + return uint32(len(r.data)) } func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 { @@ -164,8 +234,34 @@ func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 { defer p.lock.RUnlock() cost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(amount) - if cost > p.fcServerParams.BufLimit { - cost = p.fcServerParams.BufLimit + if cost > p.fcParams.BufLimit { + cost = p.fcParams.BufLimit + } + return cost +} + +func (p *peer) GetTxRelayCost(amount, size int) uint64 { + p.lock.RLock() + defer p.lock.RUnlock() + + var msgcode uint64 + switch p.version { + case lpv1: + msgcode = SendTxMsg + case lpv2: + msgcode = SendTxV2Msg + default: + panic(nil) + } + + cost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(amount) + sizeCost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(size)/txSizeCostLimit + if sizeCost > cost { + cost = sizeCost + } + + if cost > p.fcParams.BufLimit { + cost = p.fcParams.BufLimit } return cost } @@ -184,52 +280,61 @@ func (p *peer) SendAnnounce(request announceData) error { return p2p.Send(p.rw, AnnounceMsg, request) } -// SendBlockHeaders sends a batch of block headers to the remote peer. -func (p *peer) SendBlockHeaders(reqID, bv uint64, headers []*types.Header) error { - return sendResponse(p.rw, BlockHeadersMsg, reqID, bv, headers) +// ReplyBlockHeaders creates a reply with a batch of block headers +func (p *peer) ReplyBlockHeaders(reqID uint64, headers []*types.Header) *reply { + data, _ := rlp.EncodeToBytes(headers) + return &reply{p.rw, BlockHeadersMsg, reqID, data} } -// SendBlockBodiesRLP sends a batch of block contents to the remote peer from +// ReplyBlockBodiesRLP creates a reply with a batch of block contents from // an already RLP encoded format. -func (p *peer) SendBlockBodiesRLP(reqID, bv uint64, bodies []rlp.RawValue) error { - return sendResponse(p.rw, BlockBodiesMsg, reqID, bv, bodies) +func (p *peer) ReplyBlockBodiesRLP(reqID uint64, bodies []rlp.RawValue) *reply { + data, _ := rlp.EncodeToBytes(bodies) + return &reply{p.rw, BlockBodiesMsg, reqID, data} } -// SendCodeRLP sends a batch of arbitrary internal data, corresponding to the +// ReplyCode creates a reply with a batch of arbitrary internal data, corresponding to the // hashes requested. -func (p *peer) SendCode(reqID, bv uint64, data [][]byte) error { - return sendResponse(p.rw, CodeMsg, reqID, bv, data) +func (p *peer) ReplyCode(reqID uint64, codes [][]byte) *reply { + data, _ := rlp.EncodeToBytes(codes) + return &reply{p.rw, CodeMsg, reqID, data} } -// SendReceiptsRLP sends a batch of transaction receipts, corresponding to the +// ReplyReceiptsRLP creates a reply with a batch of transaction receipts, corresponding to the // ones requested from an already RLP encoded format. -func (p *peer) SendReceiptsRLP(reqID, bv uint64, receipts []rlp.RawValue) error { - return sendResponse(p.rw, ReceiptsMsg, reqID, bv, receipts) +func (p *peer) ReplyReceiptsRLP(reqID uint64, receipts []rlp.RawValue) *reply { + data, _ := rlp.EncodeToBytes(receipts) + return &reply{p.rw, ReceiptsMsg, reqID, data} } -// SendProofs sends a batch of legacy LES/1 merkle proofs, corresponding to the ones requested. -func (p *peer) SendProofs(reqID, bv uint64, proofs proofsData) error { - return sendResponse(p.rw, ProofsV1Msg, reqID, bv, proofs) +// ReplyProofs creates a reply with a batch of legacy LES/1 merkle proofs, corresponding to the ones requested. +func (p *peer) ReplyProofs(reqID uint64, proofs proofsData) *reply { + data, _ := rlp.EncodeToBytes(proofs) + return &reply{p.rw, ProofsV1Msg, reqID, data} } -// SendProofsV2 sends a batch of merkle proofs, corresponding to the ones requested. -func (p *peer) SendProofsV2(reqID, bv uint64, proofs light.NodeList) error { - return sendResponse(p.rw, ProofsV2Msg, reqID, bv, proofs) +// ReplyProofsV2 creates a reply with a batch of merkle proofs, corresponding to the ones requested. +func (p *peer) ReplyProofsV2(reqID uint64, proofs light.NodeList) *reply { + data, _ := rlp.EncodeToBytes(proofs) + return &reply{p.rw, ProofsV2Msg, reqID, data} } -// SendHeaderProofs sends a batch of legacy LES/1 header proofs, corresponding to the ones requested. -func (p *peer) SendHeaderProofs(reqID, bv uint64, proofs []ChtResp) error { - return sendResponse(p.rw, HeaderProofsMsg, reqID, bv, proofs) +// ReplyHeaderProofs creates a reply with a batch of legacy LES/1 header proofs, corresponding to the ones requested. +func (p *peer) ReplyHeaderProofs(reqID uint64, proofs []ChtResp) *reply { + data, _ := rlp.EncodeToBytes(proofs) + return &reply{p.rw, HeaderProofsMsg, reqID, data} } -// SendHelperTrieProofs sends a batch of HelperTrie proofs, corresponding to the ones requested. -func (p *peer) SendHelperTrieProofs(reqID, bv uint64, resp HelperTrieResps) error { - return sendResponse(p.rw, HelperTrieProofsMsg, reqID, bv, resp) +// ReplyHelperTrieProofs creates a reply with a batch of HelperTrie proofs, corresponding to the ones requested. +func (p *peer) ReplyHelperTrieProofs(reqID uint64, resp HelperTrieResps) *reply { + data, _ := rlp.EncodeToBytes(resp) + return &reply{p.rw, HelperTrieProofsMsg, reqID, data} } -// SendTxStatus sends a batch of transaction status records, corresponding to the ones requested. -func (p *peer) SendTxStatus(reqID, bv uint64, stats []txStatus) error { - return sendResponse(p.rw, TxStatusMsg, reqID, bv, stats) +// ReplyTxStatus creates a reply with a batch of transaction status records, corresponding to the ones requested. +func (p *peer) ReplyTxStatus(reqID uint64, stats []txStatus) *reply { + data, _ := rlp.EncodeToBytes(stats) + return &reply{p.rw, TxStatusMsg, reqID, data} } // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the @@ -307,9 +412,9 @@ func (p *peer) RequestTxStatus(reqID, cost uint64, txHashes []common.Hash) error return sendRequest(p.rw, GetTxStatusMsg, reqID, cost, txHashes) } -// SendTxStatus sends a batch of transactions to be added to the remote transaction pool. -func (p *peer) SendTxs(reqID, cost uint64, txs types.Transactions) error { - p.Log().Debug("Fetching batch of transactions", "count", len(txs)) +// SendTxStatus creates a reply with a batch of transactions to be added to the remote transaction pool. +func (p *peer) SendTxs(reqID, cost uint64, txs rlp.RawValue) error { + p.Log().Debug("Sending batch of transactions", "size", len(txs)) switch p.version { case lpv1: return p2p.Send(p.rw, SendTxMsg, txs) // old message format does not include reqID @@ -340,12 +445,14 @@ func (l keyValueList) add(key string, val interface{}) keyValueList { return append(l, entry) } -func (l keyValueList) decode() keyValueMap { +func (l keyValueList) decode() (keyValueMap, uint64) { m := make(keyValueMap) + var size uint64 for _, entry := range l { m[entry.Key] = entry.Value + size += uint64(len(entry.Key)) + uint64(len(entry.Value)) + 8 } - return m + return m, size } func (m keyValueMap) get(key string, val interface{}) error { @@ -401,24 +508,41 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis send = send.add("headNum", headNum) send = send.add("genesisHash", genesis) if server != nil { - send = send.add("serveHeaders", nil) - send = send.add("serveChainSince", uint64(0)) - send = send.add("serveStateSince", uint64(0)) - send = send.add("txRelay", nil) + if !server.onlyAnnounce { + //only announce server. It sends only announse requests + send = send.add("serveHeaders", nil) + send = send.add("serveChainSince", uint64(0)) + send = send.add("serveStateSince", uint64(0)) + send = send.add("txRelay", nil) + } send = send.add("flowControl/BL", server.defParams.BufLimit) send = send.add("flowControl/MRR", server.defParams.MinRecharge) - list := server.fcCostStats.getCurrentList() - send = send.add("flowControl/MRC", list) - p.fcCosts = list.decode() + var costList RequestCostList + if server.costTracker != nil { + costList = server.costTracker.makeCostList() + } else { + costList = testCostList() + } + send = send.add("flowControl/MRC", costList) + p.fcCosts = costList.decode() + p.fcParams = server.defParams } else { - p.requestAnnounceType = announceTypeSimple // set to default until "very light" client mode is implemented - send = send.add("announceType", p.requestAnnounceType) + //on client node + p.announceType = announceTypeSimple + if p.isTrusted { + p.announceType = announceTypeSigned + } + send = send.add("announceType", p.announceType) } + recvList, err := p.sendReceiveHandshake(send) if err != nil { return err } - recv := recvList.decode() + recv, size := recvList.decode() + if p.rejectUpdate(size) { + return errResp(ErrRequestRejected, "") + } var rGenesis, rHash common.Hash var rVersion, rNetwork, rNum uint64 @@ -452,26 +576,34 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis if int(rVersion) != p.version { return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", rVersion, p.version) } + if server != nil { // until we have a proper peer connectivity API, allow LES connection to other servers /*if recv.get("serveStateSince", nil) == nil { return errResp(ErrUselessPeer, "wanted client, got server") }*/ if recv.get("announceType", &p.announceType) != nil { + //set default announceType on server side p.announceType = announceTypeSimple } p.fcClient = flowcontrol.NewClientNode(server.fcManager, server.defParams) } else { + //mark OnlyAnnounce server if "serveHeaders", "serveChainSince", "serveStateSince" or "txRelay" fields don't exist if recv.get("serveChainSince", nil) != nil { - return errResp(ErrUselessPeer, "peer cannot serve chain") + p.isOnlyAnnounce = true } if recv.get("serveStateSince", nil) != nil { - return errResp(ErrUselessPeer, "peer cannot serve state") + p.isOnlyAnnounce = true } if recv.get("txRelay", nil) != nil { - return errResp(ErrUselessPeer, "peer cannot relay transactions") + p.isOnlyAnnounce = true } - params := &flowcontrol.ServerParams{} + + if p.isOnlyAnnounce && !p.isTrusted { + return errResp(ErrUselessPeer, "peer cannot serve requests") + } + + var params flowcontrol.ServerParams if err := recv.get("flowControl/BL", ¶ms.BufLimit); err != nil { return err } @@ -482,15 +614,38 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis if err := recv.get("flowControl/MRC", &MRC); err != nil { return err } - p.fcServerParams = params - p.fcServer = flowcontrol.NewServerNode(params) + p.fcParams = params + p.fcServer = flowcontrol.NewServerNode(params, &mclock.System{}) p.fcCosts = MRC.decode() } - p.headInfo = &announceData{Td: rTd, Hash: rHash, Number: rNum} return nil } +// updateFlowControl updates the flow control parameters belonging to the server +// node if the announced key/value set contains relevant fields +func (p *peer) updateFlowControl(update keyValueMap) { + if p.fcServer == nil { + return + } + params := p.fcParams + updateParams := false + if update.get("flowControl/BL", ¶ms.BufLimit) == nil { + updateParams = true + } + if update.get("flowControl/MRR", ¶ms.MinRecharge) == nil { + updateParams = true + } + if updateParams { + p.fcParams = params + p.fcServer.UpdateParams(params) + } + var MRC RequestCostList + if update.get("flowControl/MRC", &MRC) == nil { + p.fcCosts = MRC.decode() + } +} + // String implements fmt.Stringer. func (p *peer) String() string { return fmt.Sprintf("Peer %s [%s]", p.id, @@ -576,8 +731,10 @@ func (ps *peerSet) Unregister(id string) error { for _, n := range peers { n.unregisterPeer(p) } + p.sendQueue.quit() p.Peer.Disconnect(p2p.DiscUselessPeer) + return nil } } diff --git a/vendor/github.com/ethereum/go-ethereum/les/peer_test.go b/vendor/github.com/ethereum/go-ethereum/les/peer_test.go new file mode 100644 index 00000000..8b12dd29 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/peer_test.go @@ -0,0 +1,290 @@ +package les + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/les/flowcontrol" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rlp" +) + +const ( + test_networkid = 10 + protocol_version = 2123 +) + +var ( + hash = common.HexToHash("some string") + genesis = common.HexToHash("genesis hash") + headNum = uint64(1234) + td = big.NewInt(123) +) + +//ulc connects to trusted peer and send announceType=announceTypeSigned +func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testing.T) { + id := newNodeID(t).ID() + + //peer to connect(on ulc side) + p := peer{ + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + isTrusted: true, + rw: &rwStub{ + WriteHook: func(recvList keyValueList) { + //checking that ulc sends to peer allowedRequests=onlyAnnounceRequests and announceType = announceTypeSigned + recv, _ := recvList.decode() + var reqType uint64 + + err := recv.get("announceType", &reqType) + if err != nil { + t.Fatal(err) + } + + if reqType != announceTypeSigned { + t.Fatal("Expected announceTypeSigned") + } + }, + ReadHook: func(l keyValueList) keyValueList { + l = l.add("serveHeaders", nil) + l = l.add("serveChainSince", uint64(0)) + l = l.add("serveStateSince", uint64(0)) + l = l.add("txRelay", nil) + l = l.add("flowControl/BL", uint64(0)) + l = l.add("flowControl/MRR", uint64(0)) + l = l.add("flowControl/MRC", RequestCostList{}) + + return l + }, + }, + network: test_networkid, + } + + err := p.Handshake(td, hash, headNum, genesis, nil) + if err != nil { + t.Fatalf("Handshake error: %s", err) + } + + if p.announceType != announceTypeSigned { + t.Fatal("Incorrect announceType") + } +} + +func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testing.T) { + id := newNodeID(t).ID() + p := peer{ + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + rw: &rwStub{ + WriteHook: func(recvList keyValueList) { + //checking that ulc sends to peer allowedRequests=noRequests and announceType != announceTypeSigned + recv, _ := recvList.decode() + var reqType uint64 + + err := recv.get("announceType", &reqType) + if err != nil { + t.Fatal(err) + } + + if reqType == announceTypeSigned { + t.Fatal("Expected not announceTypeSigned") + } + }, + ReadHook: func(l keyValueList) keyValueList { + l = l.add("serveHeaders", nil) + l = l.add("serveChainSince", uint64(0)) + l = l.add("serveStateSince", uint64(0)) + l = l.add("txRelay", nil) + l = l.add("flowControl/BL", uint64(0)) + l = l.add("flowControl/MRR", uint64(0)) + l = l.add("flowControl/MRC", RequestCostList{}) + + return l + }, + }, + network: test_networkid, + } + + err := p.Handshake(td, hash, headNum, genesis, nil) + if err != nil { + t.Fatal(err) + } + if p.announceType == announceTypeSigned { + t.Fatal("Incorrect announceType") + } +} + +func TestPeerHandshakeDefaultAllRequests(t *testing.T) { + id := newNodeID(t).ID() + + s := generateLesServer() + + p := peer{ + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + rw: &rwStub{ + ReadHook: func(l keyValueList) keyValueList { + l = l.add("announceType", uint64(announceTypeSigned)) + l = l.add("allowedRequests", uint64(0)) + + return l + }, + }, + network: test_networkid, + } + + err := p.Handshake(td, hash, headNum, genesis, s) + if err != nil { + t.Fatal(err) + } + + if p.isOnlyAnnounce { + t.Fatal("Incorrect announceType") + } +} + +func TestPeerHandshakeServerSendOnlyAnnounceRequestsHeaders(t *testing.T) { + id := newNodeID(t).ID() + + s := generateLesServer() + s.onlyAnnounce = true + + p := peer{ + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + rw: &rwStub{ + ReadHook: func(l keyValueList) keyValueList { + l = l.add("announceType", uint64(announceTypeSigned)) + + return l + }, + WriteHook: func(l keyValueList) { + for _, v := range l { + if v.Key == "serveHeaders" || + v.Key == "serveChainSince" || + v.Key == "serveStateSince" || + v.Key == "txRelay" { + t.Fatalf("%v exists", v.Key) + } + } + }, + }, + network: test_networkid, + } + + err := p.Handshake(td, hash, headNum, genesis, s) + if err != nil { + t.Fatal(err) + } +} +func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) { + id := newNodeID(t).ID() + + p := peer{ + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + rw: &rwStub{ + ReadHook: func(l keyValueList) keyValueList { + l = l.add("flowControl/BL", uint64(0)) + l = l.add("flowControl/MRR", uint64(0)) + l = l.add("flowControl/MRC", RequestCostList{}) + + l = l.add("announceType", uint64(announceTypeSigned)) + + return l + }, + }, + network: test_networkid, + isTrusted: true, + } + + err := p.Handshake(td, hash, headNum, genesis, nil) + if err != nil { + t.Fatal(err) + } + + if !p.isOnlyAnnounce { + t.Fatal("isOnlyAnnounce must be true") + } +} + +func TestPeerHandshakeClientReturnErrorOnUselessPeer(t *testing.T) { + id := newNodeID(t).ID() + + p := peer{ + Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), + version: protocol_version, + rw: &rwStub{ + ReadHook: func(l keyValueList) keyValueList { + l = l.add("flowControl/BL", uint64(0)) + l = l.add("flowControl/MRR", uint64(0)) + l = l.add("flowControl/MRC", RequestCostList{}) + + l = l.add("announceType", uint64(announceTypeSigned)) + + return l + }, + }, + network: test_networkid, + } + + err := p.Handshake(td, hash, headNum, genesis, nil) + if err == nil { + t.FailNow() + } +} + +func generateLesServer() *LesServer { + s := &LesServer{ + defParams: flowcontrol.ServerParams{ + BufLimit: uint64(300000000), + MinRecharge: uint64(50000), + }, + fcManager: flowcontrol.NewClientManager(nil, &mclock.System{}), + } + return s +} + +type rwStub struct { + ReadHook func(l keyValueList) keyValueList + WriteHook func(l keyValueList) +} + +func (s *rwStub) ReadMsg() (p2p.Msg, error) { + payload := keyValueList{} + payload = payload.add("protocolVersion", uint64(protocol_version)) + payload = payload.add("networkId", uint64(test_networkid)) + payload = payload.add("headTd", td) + payload = payload.add("headHash", hash) + payload = payload.add("headNum", headNum) + payload = payload.add("genesisHash", genesis) + + if s.ReadHook != nil { + payload = s.ReadHook(payload) + } + + size, p, err := rlp.EncodeToReader(payload) + if err != nil { + return p2p.Msg{}, err + } + + return p2p.Msg{ + Size: uint32(size), + Payload: p, + }, nil +} + +func (s *rwStub) WriteMsg(m p2p.Msg) error { + recvList := keyValueList{} + if err := m.Decode(&recvList); err != nil { + return err + } + + if s.WriteHook != nil { + s.WriteHook(recvList) + } + + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/protocol.go b/vendor/github.com/ethereum/go-ethereum/les/protocol.go index 0b24f5ae..65395ac0 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/protocol.go +++ b/vendor/github.com/ethereum/go-ethereum/les/protocol.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( @@ -81,6 +80,25 @@ const ( TxStatusMsg = 0x15 ) +type requestInfo struct { + name string + maxCount uint64 +} + +var requests = map[uint64]requestInfo{ + GetBlockHeadersMsg: {"GetBlockHeaders", MaxHeaderFetch}, + GetBlockBodiesMsg: {"GetBlockBodies", MaxBodyFetch}, + GetReceiptsMsg: {"GetReceipts", MaxReceiptFetch}, + GetProofsV1Msg: {"GetProofsV1", MaxProofsFetch}, + GetCodeMsg: {"GetCode", MaxCodeFetch}, + SendTxMsg: {"SendTx", MaxTxSend}, + GetHeaderProofsMsg: {"GetHeaderProofs", MaxHelperTrieProofsFetch}, + GetProofsV2Msg: {"GetProofsV2", MaxProofsFetch}, + GetHelperTrieProofsMsg: {"GetHelperTrieProofs", MaxHelperTrieProofsFetch}, + SendTxV2Msg: {"SendTxV2", MaxTxSend}, + GetTxStatusMsg: {"GetTxStatus", MaxTxStatus}, +} + type errCode int const ( @@ -146,9 +164,9 @@ func (a *announceData) sign(privKey *ecdsa.PrivateKey) { } // checkSignature verifies if the block announcement has a valid signature by the given pubKey -func (a *announceData) checkSignature(id enode.ID) error { +func (a *announceData) checkSignature(id enode.ID, update keyValueMap) error { var sig []byte - if err := a.Update.decode().get("sign", &sig); err != nil { + if err := update.get("sign", &sig); err != nil { return err } rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td}) @@ -221,6 +239,6 @@ type proofsData [][]rlp.RawValue type txStatus struct { Status core.TxStatus - Lookup *rawdb.TxLookupEntry `rlp:"nil"` + Lookup *rawdb.LegacyTxLookupEntry `rlp:"nil"` Error string } diff --git a/vendor/github.com/ethereum/go-ethereum/les/randselect.go b/vendor/github.com/ethereum/go-ethereum/les/randselect.go index 1cc1d3d3..8efe0c94 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/randselect.go +++ b/vendor/github.com/ethereum/go-ethereum/les/randselect.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( diff --git a/vendor/github.com/ethereum/go-ethereum/les/retrieve.go b/vendor/github.com/ethereum/go-ethereum/les/retrieve.go index d77cfea7..dd9d1459 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/retrieve.go +++ b/vendor/github.com/ethereum/go-ethereum/les/retrieve.go @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package les import ( diff --git a/vendor/github.com/ethereum/go-ethereum/les/server.go b/vendor/github.com/ethereum/go-ethereum/les/server.go index 2fa0456d..3716685e 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/server.go +++ b/vendor/github.com/ethereum/go-ethereum/les/server.go @@ -14,44 +14,67 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( "crypto/ecdsa" - "encoding/binary" - "math" "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discv5" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" ) +const bufLimitRatio = 6000 // fixed bufLimit/MRR ratio + type LesServer struct { lesCommons - fcManager *flowcontrol.ClientManager // nil if our node is client only - fcCostStats *requestCostStats - defParams *flowcontrol.ServerParams - lesTopics []discv5.Topic - privateKey *ecdsa.PrivateKey - quitSync chan struct{} + fcManager *flowcontrol.ClientManager // nil if our node is client only + costTracker *costTracker + defParams flowcontrol.ServerParams + lesTopics []discv5.Topic + privateKey *ecdsa.PrivateKey + quitSync chan struct{} + onlyAnnounce bool + + thcNormal, thcBlockProcessing int // serving thread count for normal operation and block processing mode + + maxPeers int + freeClientCap uint64 + freeClientPool *freeClientPool + priorityClientPool *priorityClientPool } func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { quitSync := make(chan struct{}) - pm, err := NewProtocolManager(eth.BlockChain().Config(), light.DefaultServerIndexerConfig, false, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup)) + pm, err := NewProtocolManager( + eth.BlockChain().Config(), + light.DefaultServerIndexerConfig, + false, + config.NetworkId, + eth.EventMux(), + eth.Engine(), + newPeerSet(), + eth.BlockChain(), + eth.TxPool(), + eth.ChainDb(), + nil, + nil, + nil, + quitSync, + new(sync.WaitGroup), + config.ULC) if err != nil { return nil, err } @@ -70,11 +93,20 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), protocolManager: pm, }, - quitSync: quitSync, - lesTopics: lesTopics, + costTracker: newCostTracker(eth.ChainDb(), config), + quitSync: quitSync, + lesTopics: lesTopics, + onlyAnnounce: config.OnlyAnnounce, } logger := log.New() + pm.server = srv + srv.thcNormal = config.LightServ * 4 / 100 + if srv.thcNormal < 4 { + srv.thcNormal = 4 + } + srv.thcBlockProcessing = config.LightServ/100 + 1 + srv.fcManager = flowcontrol.NewClientManager(nil, &mclock.System{}) chtV1SectionCount, _, _ := srv.chtIndexer.Sections() // indexer still uses LES/1 4k section size for backwards server compatibility chtV2SectionCount := chtV1SectionCount / (params.CHTFrequencyClient / params.CHTFrequencyServer) @@ -96,23 +128,92 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { } srv.chtIndexer.Start(eth.BlockChain()) - pm.server = srv - - srv.defParams = &flowcontrol.ServerParams{ - BufLimit: 300000000, - MinRecharge: 50000, - } - srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000) - srv.fcCostStats = newCostStats(eth.ChainDb()) return srv, nil } +func (s *LesServer) APIs() []rpc.API { + return []rpc.API{ + { + Namespace: "les", + Version: "1.0", + Service: NewPrivateLightServerAPI(s), + Public: false, + }, + } +} + +// startEventLoop starts an event handler loop that updates the recharge curve of +// the client manager and adjusts the client pool's size according to the total +// capacity updates coming from the client manager +func (s *LesServer) startEventLoop() { + s.protocolManager.wg.Add(1) + + var processing bool + blockProcFeed := make(chan bool, 100) + s.protocolManager.blockchain.(*core.BlockChain).SubscribeBlockProcessingEvent(blockProcFeed) + totalRechargeCh := make(chan uint64, 100) + totalRecharge := s.costTracker.subscribeTotalRecharge(totalRechargeCh) + totalCapacityCh := make(chan uint64, 100) + updateRecharge := func() { + if processing { + s.protocolManager.servingQueue.setThreads(s.thcBlockProcessing) + s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge, totalRecharge}}) + } else { + s.protocolManager.servingQueue.setThreads(s.thcNormal) + s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 10, totalRecharge}, {totalRecharge, totalRecharge}}) + } + } + updateRecharge() + totalCapacity := s.fcManager.SubscribeTotalCapacity(totalCapacityCh) + s.priorityClientPool.setLimits(s.maxPeers, totalCapacity) + + go func() { + for { + select { + case processing = <-blockProcFeed: + updateRecharge() + case totalRecharge = <-totalRechargeCh: + updateRecharge() + case totalCapacity = <-totalCapacityCh: + s.priorityClientPool.setLimits(s.maxPeers, totalCapacity) + case <-s.protocolManager.quitSync: + s.protocolManager.wg.Done() + return + } + } + }() +} + func (s *LesServer) Protocols() []p2p.Protocol { return s.makeProtocols(ServerProtocolVersions) } // Start starts the LES server func (s *LesServer) Start(srvr *p2p.Server) { + s.maxPeers = s.config.LightPeers + totalRecharge := s.costTracker.totalRecharge() + if s.maxPeers > 0 { + s.freeClientCap = minCapacity //totalRecharge / uint64(s.maxPeers) + if s.freeClientCap < minCapacity { + s.freeClientCap = minCapacity + } + if s.freeClientCap > 0 { + s.defParams = flowcontrol.ServerParams{ + BufLimit: s.freeClientCap * bufLimitRatio, + MinRecharge: s.freeClientCap, + } + } + } + freePeers := int(totalRecharge / s.freeClientCap) + if freePeers < s.maxPeers { + log.Warn("Light peer count limited", "specified", s.maxPeers, "allowed", freePeers) + } + + s.freeClientPool = newFreeClientPool(s.chainDb, s.freeClientCap, 10000, mclock.System{}, func(id string) { go s.protocolManager.removePeer(id) }) + s.priorityClientPool = newPriorityClientPool(s.freeClientCap, s.protocolManager.peers, s.freeClientPool) + + s.protocolManager.peers.notify(s.priorityClientPool) + s.startEventLoop() s.protocolManager.Start(s.config.LightPeers) if srvr.DiscV5 != nil { for _, topic := range s.lesTopics { @@ -138,187 +239,14 @@ func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { func (s *LesServer) Stop() { s.chtIndexer.Close() // bloom trie indexer is closed by parent bloombits indexer - s.fcCostStats.store() - s.fcManager.Stop() go func() { <-s.protocolManager.noMorePeers }() + s.freeClientPool.stop() + s.costTracker.stop() s.protocolManager.Stop() } -type requestCosts struct { - baseCost, reqCost uint64 -} - -type requestCostTable map[uint64]*requestCosts - -type RequestCostList []struct { - MsgCode, BaseCost, ReqCost uint64 -} - -func (list RequestCostList) decode() requestCostTable { - table := make(requestCostTable) - for _, e := range list { - table[e.MsgCode] = &requestCosts{ - baseCost: e.BaseCost, - reqCost: e.ReqCost, - } - } - return table -} - -type linReg struct { - sumX, sumY, sumXX, sumXY float64 - cnt uint64 -} - -const linRegMaxCnt = 100000 - -func (l *linReg) add(x, y float64) { - if l.cnt >= linRegMaxCnt { - sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt - l.sumX -= l.sumX * sub - l.sumY -= l.sumY * sub - l.sumXX -= l.sumXX * sub - l.sumXY -= l.sumXY * sub - l.cnt = linRegMaxCnt - 1 - } - l.cnt++ - l.sumX += x - l.sumY += y - l.sumXX += x * x - l.sumXY += x * y -} - -func (l *linReg) calc() (b, m float64) { - if l.cnt == 0 { - return 0, 0 - } - cnt := float64(l.cnt) - d := cnt*l.sumXX - l.sumX*l.sumX - if d < 0.001 { - return l.sumY / cnt, 0 - } - m = (cnt*l.sumXY - l.sumX*l.sumY) / d - b = (l.sumY / cnt) - (m * l.sumX / cnt) - return b, m -} - -func (l *linReg) toBytes() []byte { - var arr [40]byte - binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX)) - binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY)) - binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX)) - binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY)) - binary.BigEndian.PutUint64(arr[32:40], l.cnt) - return arr[:] -} - -func linRegFromBytes(data []byte) *linReg { - if len(data) != 40 { - return nil - } - l := &linReg{} - l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) - l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) - l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24])) - l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32])) - l.cnt = binary.BigEndian.Uint64(data[32:40]) - return l -} - -type requestCostStats struct { - lock sync.RWMutex - db ethdb.Database - stats map[uint64]*linReg -} - -type requestCostStatsRlp []struct { - MsgCode uint64 - Data []byte -} - -var rcStatsKey = []byte("_requestCostStats") - -func newCostStats(db ethdb.Database) *requestCostStats { - stats := make(map[uint64]*linReg) - for _, code := range reqList { - stats[code] = &linReg{cnt: 100} - } - - if db != nil { - data, err := db.Get(rcStatsKey) - var statsRlp requestCostStatsRlp - if err == nil { - err = rlp.DecodeBytes(data, &statsRlp) - } - if err == nil { - for _, r := range statsRlp { - if stats[r.MsgCode] != nil { - if l := linRegFromBytes(r.Data); l != nil { - stats[r.MsgCode] = l - } - } - } - } - } - - return &requestCostStats{ - db: db, - stats: stats, - } -} - -func (s *requestCostStats) store() { - s.lock.Lock() - defer s.lock.Unlock() - - statsRlp := make(requestCostStatsRlp, len(reqList)) - for i, code := range reqList { - statsRlp[i].MsgCode = code - statsRlp[i].Data = s.stats[code].toBytes() - } - - if data, err := rlp.EncodeToBytes(statsRlp); err == nil { - s.db.Put(rcStatsKey, data) - } -} - -func (s *requestCostStats) getCurrentList() RequestCostList { - s.lock.Lock() - defer s.lock.Unlock() - - list := make(RequestCostList, len(reqList)) - //fmt.Println("RequestCostList") - for idx, code := range reqList { - b, m := s.stats[code].calc() - //fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000) - if m < 0 { - b += m - m = 0 - } - if b < 0 { - b = 0 - } - - list[idx].MsgCode = code - list[idx].BaseCost = uint64(b * 2) - list[idx].ReqCost = uint64(m * 2) - } - return list -} - -func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) { - s.lock.Lock() - defer s.lock.Unlock() - - c, ok := s.stats[msgCode] - if !ok || reqCnt == 0 { - return - } - c.add(float64(reqCnt), float64(cost)) -} - func (pm *ProtocolManager) blockLoop() { pm.wg.Add(1) headCh := make(chan core.ChainHeadEvent, 10) @@ -352,27 +280,17 @@ func (pm *ProtocolManager) blockLoop() { ) for _, p := range peers { + p := p switch p.announceType { - case announceTypeSimple: - select { - case p.announceChn <- announce: - default: - pm.removePeer(p.id) - } - + p.queueSend(func() { p.SendAnnounce(announce) }) case announceTypeSigned: if !signed { signedAnnounce = announce signedAnnounce.sign(pm.server.privateKey) signed = true } - - select { - case p.announceChn <- signedAnnounce: - default: - pm.removePeer(p.id) - } + p.queueSend(func() { p.SendAnnounce(signedAnnounce) }) } } } diff --git a/vendor/github.com/ethereum/go-ethereum/les/serverpool.go b/vendor/github.com/ethereum/go-ethereum/les/serverpool.go index 0fe6e49b..668f39c5 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/serverpool.go +++ b/vendor/github.com/ethereum/go-ethereum/les/serverpool.go @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package les implements the Light Ethereum Subprotocol. package les import ( @@ -126,22 +125,22 @@ type serverPool struct { discNodes chan *enode.Node discLookups chan bool + trustedNodes map[enode.ID]*enode.Node entries map[enode.ID]*poolEntry timeout, enableRetry chan *poolEntry adjustStats chan poolStatAdjust - connCh chan *connReq - disconnCh chan *disconnReq - registerCh chan *registerReq - knownQueue, newQueue poolEntryQueue knownSelect, newSelect *weightedRandomSelect knownSelected, newSelected int fastDiscover bool + connCh chan *connReq + disconnCh chan *disconnReq + registerCh chan *registerReq } // newServerPool creates a new serverPool instance -func newServerPool(db ethdb.Database, quit chan struct{}, wg *sync.WaitGroup) *serverPool { +func newServerPool(db ethdb.Database, quit chan struct{}, wg *sync.WaitGroup, trustedNodes []string) *serverPool { pool := &serverPool{ db: db, quit: quit, @@ -156,7 +155,9 @@ func newServerPool(db ethdb.Database, quit chan struct{}, wg *sync.WaitGroup) *s knownSelect: newWeightedRandomSelect(), newSelect: newWeightedRandomSelect(), fastDiscover: true, + trustedNodes: parseTrustedNodes(trustedNodes), } + pool.knownQueue = newPoolEntryQueue(maxKnownEntries, pool.removeEntry) pool.newQueue = newPoolEntryQueue(maxNewEntries, pool.removeEntry) return pool @@ -168,6 +169,7 @@ func (pool *serverPool) start(server *p2p.Server, topic discv5.Topic) { pool.dbKey = append([]byte("serverPool/"), []byte(topic)...) pool.wg.Add(1) pool.loadNodes() + pool.connectToTrustedNodes() if pool.server.DiscV5 != nil { pool.discSetPeriod = make(chan time.Duration, 1) @@ -337,8 +339,10 @@ func (pool *serverPool) eventLoop() { } case node := <-pool.discNodes: - entry := pool.findOrNewNode(node) - pool.updateCheckDial(entry) + if pool.trustedNodes[node.ID()] == nil { + entry := pool.findOrNewNode(node) + pool.updateCheckDial(entry) + } case conv := <-pool.discLookups: if conv { @@ -355,29 +359,34 @@ func (pool *serverPool) eventLoop() { } case req := <-pool.connCh: - // Handle peer connection requests. - entry := pool.entries[req.p.ID()] - if entry == nil { - entry = pool.findOrNewNode(req.node) - } - if entry.state == psConnected || entry.state == psRegistered { + if pool.trustedNodes[req.p.ID()] != nil { + // ignore trusted nodes req.result <- nil - continue + } else { + // Handle peer connection requests. + entry := pool.entries[req.p.ID()] + if entry == nil { + entry = pool.findOrNewNode(req.node) + } + if entry.state == psConnected || entry.state == psRegistered { + req.result <- nil + continue + } + pool.connWg.Add(1) + entry.peer = req.p + entry.state = psConnected + addr := &poolEntryAddress{ + ip: req.node.IP(), + port: uint16(req.node.TCP()), + lastSeen: mclock.Now(), + } + entry.lastConnected = addr + entry.addr = make(map[string]*poolEntryAddress) + entry.addr[addr.strKey()] = addr + entry.addrSelect = *newWeightedRandomSelect() + entry.addrSelect.update(addr) + req.result <- entry } - pool.connWg.Add(1) - entry.peer = req.p - entry.state = psConnected - addr := &poolEntryAddress{ - ip: req.node.IP(), - port: uint16(req.node.TCP()), - lastSeen: mclock.Now(), - } - entry.lastConnected = addr - entry.addr = make(map[string]*poolEntryAddress) - entry.addr[addr.strKey()] = addr - entry.addrSelect = *newWeightedRandomSelect() - entry.addrSelect.update(addr) - req.result <- entry case req := <-pool.registerCh: // Handle peer registration requests. @@ -470,11 +479,42 @@ func (pool *serverPool) loadNodes() { "response", fmt.Sprintf("%v/%v", time.Duration(e.responseStats.avg), e.responseStats.weight), "timeout", fmt.Sprintf("%v/%v", e.timeoutStats.avg, e.timeoutStats.weight)) pool.entries[e.node.ID()] = e - pool.knownQueue.setLatest(e) - pool.knownSelect.update((*knownEntry)(e)) + if pool.trustedNodes[e.node.ID()] == nil { + pool.knownQueue.setLatest(e) + pool.knownSelect.update((*knownEntry)(e)) + } } } +// connectToTrustedNodes adds trusted server nodes as static trusted peers. +// +// Note: trusted nodes are not handled by the server pool logic, they are not +// added to either the known or new selection pools. They are connected/reconnected +// by p2p.Server whenever possible. +func (pool *serverPool) connectToTrustedNodes() { + //connect to trusted nodes + for _, node := range pool.trustedNodes { + pool.server.AddTrustedPeer(node) + pool.server.AddPeer(node) + log.Debug("Added trusted node", "id", node.ID().String()) + } +} + +// parseTrustedNodes returns valid and parsed enodes +func parseTrustedNodes(trustedNodes []string) map[enode.ID]*enode.Node { + nodes := make(map[enode.ID]*enode.Node) + + for _, node := range trustedNodes { + node, err := enode.ParseV4(node) + if err != nil { + log.Warn("Trusted node URL invalid", "enode", node, "err", err) + continue + } + nodes[node.ID()] = node + } + return nodes +} + // saveNodes saves known nodes and their statistics into the database. Nodes are // ordered from least to most recently connected. func (pool *serverPool) saveNodes() { @@ -683,7 +723,7 @@ func (e *poolEntry) DecodeRLP(s *rlp.Stream) error { } func encodePubkey64(pub *ecdsa.PublicKey) []byte { - return crypto.FromECDSAPub(pub)[:1] + return crypto.FromECDSAPub(pub)[1:] } func decodePubkey64(b []byte) (*ecdsa.PublicKey, error) { diff --git a/vendor/github.com/ethereum/go-ethereum/les/servingqueue.go b/vendor/github.com/ethereum/go-ethereum/les/servingqueue.go new file mode 100644 index 00000000..2438fdfe --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/servingqueue.go @@ -0,0 +1,261 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package les + +import ( + "sync" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/common/prque" +) + +// servingQueue allows running tasks in a limited number of threads and puts the +// waiting tasks in a priority queue +type servingQueue struct { + tokenCh chan runToken + queueAddCh, queueBestCh chan *servingTask + stopThreadCh, quit chan struct{} + setThreadsCh chan int + + wg sync.WaitGroup + threadCount int // number of currently running threads + queue *prque.Prque // priority queue for waiting or suspended tasks + best *servingTask // the highest priority task (not included in the queue) + suspendBias int64 // priority bias against suspending an already running task +} + +// servingTask represents a request serving task. Tasks can be implemented to +// run in multiple steps, allowing the serving queue to suspend execution between +// steps if higher priority tasks are entered. The creator of the task should +// set the following fields: +// +// - priority: greater value means higher priority; values can wrap around the int64 range +// - run: execute a single step; return true if finished +// - after: executed after run finishes or returns an error, receives the total serving time +type servingTask struct { + sq *servingQueue + servingTime uint64 + priority int64 + biasAdded bool + token runToken + tokenCh chan runToken +} + +// runToken received by servingTask.start allows the task to run. Closing the +// channel by servingTask.stop signals the thread controller to allow a new task +// to start running. +type runToken chan struct{} + +// start blocks until the task can start and returns true if it is allowed to run. +// Returning false means that the task should be cancelled. +func (t *servingTask) start() bool { + select { + case t.token = <-t.sq.tokenCh: + default: + t.tokenCh = make(chan runToken, 1) + select { + case t.sq.queueAddCh <- t: + case <-t.sq.quit: + return false + } + select { + case t.token = <-t.tokenCh: + case <-t.sq.quit: + return false + } + } + if t.token == nil { + return false + } + t.servingTime -= uint64(mclock.Now()) + return true +} + +// done signals the thread controller about the task being finished and returns +// the total serving time of the task in nanoseconds. +func (t *servingTask) done() uint64 { + t.servingTime += uint64(mclock.Now()) + close(t.token) + return t.servingTime +} + +// waitOrStop can be called during the execution of the task. It blocks if there +// is a higher priority task waiting (a bias is applied in favor of the currently +// running task). Returning true means that the execution can be resumed. False +// means the task should be cancelled. +func (t *servingTask) waitOrStop() bool { + t.done() + if !t.biasAdded { + t.priority += t.sq.suspendBias + t.biasAdded = true + } + return t.start() +} + +// newServingQueue returns a new servingQueue +func newServingQueue(suspendBias int64) *servingQueue { + sq := &servingQueue{ + queue: prque.New(nil), + suspendBias: suspendBias, + tokenCh: make(chan runToken), + queueAddCh: make(chan *servingTask, 100), + queueBestCh: make(chan *servingTask), + stopThreadCh: make(chan struct{}), + quit: make(chan struct{}), + setThreadsCh: make(chan int, 10), + } + sq.wg.Add(2) + go sq.queueLoop() + go sq.threadCountLoop() + return sq +} + +// newTask creates a new task with the given priority +func (sq *servingQueue) newTask(priority int64) *servingTask { + return &servingTask{ + sq: sq, + priority: priority, + } +} + +// threadController is started in multiple goroutines and controls the execution +// of tasks. The number of active thread controllers equals the allowed number of +// concurrently running threads. It tries to fetch the highest priority queued +// task first. If there are no queued tasks waiting then it can directly catch +// run tokens from the token channel and allow the corresponding tasks to run +// without entering the priority queue. +func (sq *servingQueue) threadController() { + for { + token := make(runToken) + select { + case best := <-sq.queueBestCh: + best.tokenCh <- token + default: + select { + case best := <-sq.queueBestCh: + best.tokenCh <- token + case sq.tokenCh <- token: + case <-sq.stopThreadCh: + sq.wg.Done() + return + case <-sq.quit: + sq.wg.Done() + return + } + } + <-token + select { + case <-sq.stopThreadCh: + sq.wg.Done() + return + case <-sq.quit: + sq.wg.Done() + return + default: + } + } +} + +// addTask inserts a task into the priority queue +func (sq *servingQueue) addTask(task *servingTask) { + if sq.best == nil { + sq.best = task + } else if task.priority > sq.best.priority { + sq.queue.Push(sq.best, sq.best.priority) + sq.best = task + return + } else { + sq.queue.Push(task, task.priority) + } +} + +// queueLoop is an event loop running in a goroutine. It receives tasks from queueAddCh +// and always tries to send the highest priority task to queueBestCh. Successfully sent +// tasks are removed from the queue. +func (sq *servingQueue) queueLoop() { + for { + if sq.best != nil { + select { + case task := <-sq.queueAddCh: + sq.addTask(task) + case sq.queueBestCh <- sq.best: + if sq.queue.Size() == 0 { + sq.best = nil + } else { + sq.best, _ = sq.queue.PopItem().(*servingTask) + } + case <-sq.quit: + sq.wg.Done() + return + } + } else { + select { + case task := <-sq.queueAddCh: + sq.addTask(task) + case <-sq.quit: + sq.wg.Done() + return + } + } + } +} + +// threadCountLoop is an event loop running in a goroutine. It adjusts the number +// of active thread controller goroutines. +func (sq *servingQueue) threadCountLoop() { + var threadCountTarget int + for { + for threadCountTarget > sq.threadCount { + sq.wg.Add(1) + go sq.threadController() + sq.threadCount++ + } + if threadCountTarget < sq.threadCount { + select { + case threadCountTarget = <-sq.setThreadsCh: + case sq.stopThreadCh <- struct{}{}: + sq.threadCount-- + case <-sq.quit: + sq.wg.Done() + return + } + } else { + select { + case threadCountTarget = <-sq.setThreadsCh: + case <-sq.quit: + sq.wg.Done() + return + } + } + } +} + +// setThreads sets the allowed processing thread count, suspending tasks as soon as +// possible if necessary. +func (sq *servingQueue) setThreads(threadCount int) { + select { + case sq.setThreadsCh <- threadCount: + case <-sq.quit: + return + } +} + +// stop stops task processing as soon as possible and shuts down the serving queue. +func (sq *servingQueue) stop() { + close(sq.quit) + sq.wg.Wait() +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/txrelay.go b/vendor/github.com/ethereum/go-ethereum/les/txrelay.go index 7a02cc83..a790bbec 100644 --- a/vendor/github.com/ethereum/go-ethereum/les/txrelay.go +++ b/vendor/github.com/ethereum/go-ethereum/les/txrelay.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" ) type ltrInfo struct { @@ -113,21 +114,22 @@ func (self *LesTxRelay) send(txs types.Transactions, count int) { for p, list := range sendTo { pp := p ll := list + enc, _ := rlp.EncodeToBytes(ll) reqID := genReqID() rq := &distReq{ getCost: func(dp distPeer) uint64 { peer := dp.(*peer) - return peer.GetRequestCost(SendTxMsg, len(ll)) + return peer.GetTxRelayCost(len(ll), len(enc)) }, canSend: func(dp distPeer) bool { - return dp.(*peer) == pp + return !dp.(*peer).isOnlyAnnounce && dp.(*peer) == pp }, request: func(dp distPeer) func() { peer := dp.(*peer) - cost := peer.GetRequestCost(SendTxMsg, len(ll)) - peer.fcServer.QueueRequest(reqID, cost) - return func() { peer.SendTxs(reqID, cost, ll) } + cost := peer.GetTxRelayCost(len(ll), len(enc)) + peer.fcServer.QueuedRequest(reqID, cost) + return func() { peer.SendTxs(reqID, cost, enc) } }, } self.reqDist.queue(rq) diff --git a/vendor/github.com/ethereum/go-ethereum/les/ulc.go b/vendor/github.com/ethereum/go-ethereum/les/ulc.go new file mode 100644 index 00000000..d9f7dc76 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/ulc.go @@ -0,0 +1,39 @@ +package les + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +type ulc struct { + trustedKeys map[string]struct{} + minTrustedFraction int +} + +func newULC(ulcConfig *eth.ULCConfig) *ulc { + if ulcConfig == nil { + return nil + } + + m := make(map[string]struct{}, len(ulcConfig.TrustedServers)) + for _, id := range ulcConfig.TrustedServers { + node, err := enode.ParseV4(id) + if err != nil { + fmt.Println("node:", id, " err:", err) + continue + } + m[node.ID().String()] = struct{}{} + } + + return &ulc{m, ulcConfig.MinTrustedFraction} +} + +func (u *ulc) isTrusted(p enode.ID) bool { + if u.trustedKeys == nil { + return false + } + _, ok := u.trustedKeys[p.String()] + return ok +} diff --git a/vendor/github.com/ethereum/go-ethereum/les/ulc_test.go b/vendor/github.com/ethereum/go-ethereum/les/ulc_test.go new file mode 100644 index 00000000..81986fa1 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/les/ulc_test.go @@ -0,0 +1,238 @@ +package les + +import ( + "crypto/ecdsa" + "fmt" + "math/big" + "net" + "reflect" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/light" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +func TestULCSyncWithOnePeer(t *testing.T) { + f := newFullPeerPair(t, 1, 4, testChainGen) + ulcConfig := ð.ULCConfig{ + MinTrustedFraction: 100, + TrustedServers: []string{f.Node.String()}, + } + + l := newLightPeer(t, ulcConfig) + + if reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { + t.Fatal("blocks are equal") + } + + _, _, err := connectPeers(f, l, 2) + if err != nil { + t.Fatal(err) + } + + l.PM.fetcher.lock.Lock() + l.PM.fetcher.nextRequest() + l.PM.fetcher.lock.Unlock() + + if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { + t.Fatal("sync doesn't work") + } +} + +func TestULCReceiveAnnounce(t *testing.T) { + f := newFullPeerPair(t, 1, 4, testChainGen) + ulcConfig := ð.ULCConfig{ + MinTrustedFraction: 100, + TrustedServers: []string{f.Node.String()}, + } + + l := newLightPeer(t, ulcConfig) + fPeer, lPeer, err := connectPeers(f, l, 2) + if err != nil { + t.Fatal(err) + } + + l.PM.synchronise(fPeer) + + //check that the sync is finished correctly + if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { + t.Fatal("sync doesn't work") + } + + l.PM.peers.lock.Lock() + if len(l.PM.peers.peers) == 0 { + t.Fatal("peer list should not be empty") + } + l.PM.peers.lock.Unlock() + + time.Sleep(time.Second) + //send a signed announce message(payload doesn't matter) + td := f.PM.blockchain.GetTd(l.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Number.Uint64()) + announce := announceData{ + Number: l.PM.blockchain.CurrentHeader().Number.Uint64() + 1, + Td: td.Add(td, big.NewInt(1)), + } + announce.sign(f.Key) + lPeer.SendAnnounce(announce) +} + +func TestULCShouldNotSyncWithTwoPeersOneHaveEmptyChain(t *testing.T) { + f1 := newFullPeerPair(t, 1, 4, testChainGen) + f2 := newFullPeerPair(t, 2, 0, nil) + ulcConf := &ulc{minTrustedFraction: 100, trustedKeys: make(map[string]struct{})} + ulcConf.trustedKeys[f1.Node.ID().String()] = struct{}{} + ulcConf.trustedKeys[f2.Node.ID().String()] = struct{}{} + ulcConfig := ð.ULCConfig{ + MinTrustedFraction: 100, + TrustedServers: []string{f1.Node.String(), f2.Node.String()}, + } + l := newLightPeer(t, ulcConfig) + l.PM.ulc.minTrustedFraction = 100 + + _, _, err := connectPeers(f1, l, 2) + if err != nil { + t.Fatal(err) + } + _, _, err = connectPeers(f2, l, 2) + if err != nil { + t.Fatal(err) + } + + l.PM.fetcher.lock.Lock() + l.PM.fetcher.nextRequest() + l.PM.fetcher.lock.Unlock() + + if reflect.DeepEqual(f2.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { + t.Fatal("Incorrect hash: second peer has empty chain") + } +} + +func TestULCShouldNotSyncWithThreePeersOneHaveEmptyChain(t *testing.T) { + f1 := newFullPeerPair(t, 1, 3, testChainGen) + f2 := newFullPeerPair(t, 2, 4, testChainGen) + f3 := newFullPeerPair(t, 3, 0, nil) + + ulcConfig := ð.ULCConfig{ + MinTrustedFraction: 60, + TrustedServers: []string{f1.Node.String(), f2.Node.String(), f3.Node.String()}, + } + + l := newLightPeer(t, ulcConfig) + _, _, err := connectPeers(f1, l, 2) + if err != nil { + t.Fatal(err) + } + + _, _, err = connectPeers(f2, l, 2) + if err != nil { + t.Fatal(err) + } + + _, _, err = connectPeers(f3, l, 2) + if err != nil { + t.Fatal(err) + } + + l.PM.fetcher.lock.Lock() + l.PM.fetcher.nextRequest() + l.PM.fetcher.lock.Unlock() + + if !reflect.DeepEqual(f1.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { + t.Fatal("Incorrect hash") + } +} + +type pairPeer struct { + Name string + Node *enode.Node + PM *ProtocolManager + Key *ecdsa.PrivateKey +} + +func connectPeers(full, light pairPeer, version int) (*peer, *peer, error) { + // Create a message pipe to communicate through + app, net := p2p.MsgPipe() + + peerLight := full.PM.newPeer(version, NetworkId, p2p.NewPeer(light.Node.ID(), light.Name, nil), net) + peerFull := light.PM.newPeer(version, NetworkId, p2p.NewPeer(full.Node.ID(), full.Name, nil), app) + + // Start the peerLight on a new thread + errc1 := make(chan error, 1) + errc2 := make(chan error, 1) + go func() { + select { + case light.PM.newPeerCh <- peerFull: + errc1 <- light.PM.handle(peerFull) + case <-light.PM.quitSync: + errc1 <- p2p.DiscQuitting + } + }() + go func() { + select { + case full.PM.newPeerCh <- peerLight: + errc2 <- full.PM.handle(peerLight) + case <-full.PM.quitSync: + errc2 <- p2p.DiscQuitting + } + }() + + select { + case <-time.After(time.Millisecond * 100): + case err := <-errc1: + return nil, nil, fmt.Errorf("peerLight handshake error: %v", err) + case err := <-errc2: + return nil, nil, fmt.Errorf("peerFull handshake error: %v", err) + } + + return peerFull, peerLight, nil +} + +// newFullPeerPair creates node with full sync mode +func newFullPeerPair(t *testing.T, index int, numberOfblocks int, chainGen func(int, *core.BlockGen)) pairPeer { + db := rawdb.NewMemoryDatabase() + + pmFull := newTestProtocolManagerMust(t, false, numberOfblocks, chainGen, nil, nil, db, nil) + + peerPairFull := pairPeer{ + Name: "full node", + PM: pmFull, + } + key, err := crypto.GenerateKey() + if err != nil { + t.Fatal("generate key err:", err) + } + peerPairFull.Key = key + peerPairFull.Node = enode.NewV4(&key.PublicKey, net.ParseIP("127.0.0.1"), 35000, 35000) + return peerPairFull +} + +// newLightPeer creates node with light sync mode +func newLightPeer(t *testing.T, ulcConfig *eth.ULCConfig) pairPeer { + peers := newPeerSet() + dist := newRequestDistributor(peers, make(chan struct{}), &mclock.System{}) + rm := newRetrieveManager(peers, dist, nil) + ldb := rawdb.NewMemoryDatabase() + + odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm) + + pmLight := newTestProtocolManagerMust(t, true, 0, nil, odr, peers, ldb, ulcConfig) + peerPairLight := pairPeer{ + Name: "ulc node", + PM: pmLight, + } + + key, err := crypto.GenerateKey() + if err != nil { + t.Fatal("generate key err:", err) + } + peerPairLight.Key = key + peerPairLight.Node = enode.NewV4(&key.PublicKey, net.IP{}, 35000, 35000) + return peerPairLight +} diff --git a/vendor/github.com/ethereum/go-ethereum/light/lightchain.go b/vendor/github.com/ethereum/go-ethereum/light/lightchain.go index 8e2734c2..38f1f634 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/lightchain.go +++ b/vendor/github.com/ethereum/go-ethereum/light/lightchain.go @@ -14,6 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +// Package light implements on-demand retrieval capable state and chain objects +// for the Ethereum Light Client. package light import ( @@ -35,7 +37,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru" ) var ( @@ -50,6 +52,7 @@ type LightChain struct { hc *core.HeaderChain indexerConfig *IndexerConfig chainDb ethdb.Database + engine consensus.Engine odr OdrBackend chainFeed event.Feed chainSideFeed event.Feed @@ -57,20 +60,18 @@ type LightChain struct { scope event.SubscriptionScope genesisBlock *types.Block - mu sync.RWMutex - chainmu sync.RWMutex - bodyCache *lru.Cache // Cache for the most recent block bodies bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format blockCache *lru.Cache // Cache for the most recent entire blocks + chainmu sync.RWMutex // protects header inserts quit chan struct{} - running int32 // running must be called automically - // procInterrupt must be atomically called - procInterrupt int32 // interrupt signaler for block processing - wg sync.WaitGroup + wg sync.WaitGroup - engine consensus.Engine + // Atomic boolean switches: + running int32 // whether LightChain is running or stopped + procInterrupt int32 // interrupts chain insert + disableCheckFreq int32 // disables header verification } // NewLightChain returns a fully initialised light chain using information @@ -118,45 +119,45 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. } // addTrustedCheckpoint adds a trusted checkpoint to the blockchain -func (self *LightChain) addTrustedCheckpoint(cp *params.TrustedCheckpoint) { - if self.odr.ChtIndexer() != nil { - StoreChtRoot(self.chainDb, cp.SectionIndex, cp.SectionHead, cp.CHTRoot) - self.odr.ChtIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) +func (lc *LightChain) addTrustedCheckpoint(cp *params.TrustedCheckpoint) { + if lc.odr.ChtIndexer() != nil { + StoreChtRoot(lc.chainDb, cp.SectionIndex, cp.SectionHead, cp.CHTRoot) + lc.odr.ChtIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } - if self.odr.BloomTrieIndexer() != nil { - StoreBloomTrieRoot(self.chainDb, cp.SectionIndex, cp.SectionHead, cp.BloomRoot) - self.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) + if lc.odr.BloomTrieIndexer() != nil { + StoreBloomTrieRoot(lc.chainDb, cp.SectionIndex, cp.SectionHead, cp.BloomRoot) + lc.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } - if self.odr.BloomIndexer() != nil { - self.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) + if lc.odr.BloomIndexer() != nil { + lc.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } - log.Info("Added trusted checkpoint", "chain", cp.Name, "block", (cp.SectionIndex+1)*self.indexerConfig.ChtSize-1, "hash", cp.SectionHead) + log.Info("Added trusted checkpoint", "chain", cp.Name, "block", (cp.SectionIndex+1)*lc.indexerConfig.ChtSize-1, "hash", cp.SectionHead) } -func (self *LightChain) getProcInterrupt() bool { - return atomic.LoadInt32(&self.procInterrupt) == 1 +func (lc *LightChain) getProcInterrupt() bool { + return atomic.LoadInt32(&lc.procInterrupt) == 1 } // Odr returns the ODR backend of the chain -func (self *LightChain) Odr() OdrBackend { - return self.odr +func (lc *LightChain) Odr() OdrBackend { + return lc.odr } // loadLastState loads the last known chain state from the database. This method // assumes that the chain manager mutex is held. -func (self *LightChain) loadLastState() error { - if head := rawdb.ReadHeadHeaderHash(self.chainDb); head == (common.Hash{}) { +func (lc *LightChain) loadLastState() error { + if head := rawdb.ReadHeadHeaderHash(lc.chainDb); head == (common.Hash{}) { // Corrupt or empty database, init from scratch - self.Reset() + lc.Reset() } else { - if header := self.GetHeaderByHash(head); header != nil { - self.hc.SetCurrentHeader(header) + if header := lc.GetHeaderByHash(head); header != nil { + lc.hc.SetCurrentHeader(header) } } // Issue a status log and return - header := self.hc.CurrentHeader() - headerTd := self.GetTd(header.Hash(), header.Number.Uint64()) + header := lc.hc.CurrentHeader() + headerTd := lc.GetTd(header.Hash(), header.Number.Uint64()) log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(header.Time.Int64(), 0))) return nil @@ -164,181 +165,180 @@ func (self *LightChain) loadLastState() error { // SetHead rewinds the local chain to a new head. Everything above the new // head will be deleted and the new one set. -func (bc *LightChain) SetHead(head uint64) { - bc.mu.Lock() - defer bc.mu.Unlock() +func (lc *LightChain) SetHead(head uint64) { + lc.chainmu.Lock() + defer lc.chainmu.Unlock() - bc.hc.SetHead(head, nil) - bc.loadLastState() + lc.hc.SetHead(head, nil) + lc.loadLastState() } // GasLimit returns the gas limit of the current HEAD block. -func (self *LightChain) GasLimit() uint64 { - return self.hc.CurrentHeader().GasLimit +func (lc *LightChain) GasLimit() uint64 { + return lc.hc.CurrentHeader().GasLimit } // Reset purges the entire blockchain, restoring it to its genesis state. -func (bc *LightChain) Reset() { - bc.ResetWithGenesisBlock(bc.genesisBlock) +func (lc *LightChain) Reset() { + lc.ResetWithGenesisBlock(lc.genesisBlock) } // ResetWithGenesisBlock purges the entire blockchain, restoring it to the // specified genesis state. -func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) { +func (lc *LightChain) ResetWithGenesisBlock(genesis *types.Block) { // Dump the entire block chain and purge the caches - bc.SetHead(0) + lc.SetHead(0) - bc.mu.Lock() - defer bc.mu.Unlock() + lc.chainmu.Lock() + defer lc.chainmu.Unlock() // Prepare the genesis block and reinitialise the chain - rawdb.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()) - rawdb.WriteBlock(bc.chainDb, genesis) + rawdb.WriteTd(lc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()) + rawdb.WriteBlock(lc.chainDb, genesis) - bc.genesisBlock = genesis - bc.hc.SetGenesis(bc.genesisBlock.Header()) - bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) + lc.genesisBlock = genesis + lc.hc.SetGenesis(lc.genesisBlock.Header()) + lc.hc.SetCurrentHeader(lc.genesisBlock.Header()) } // Accessors // Engine retrieves the light chain's consensus engine. -func (bc *LightChain) Engine() consensus.Engine { return bc.engine } +func (lc *LightChain) Engine() consensus.Engine { return lc.engine } // Genesis returns the genesis block -func (bc *LightChain) Genesis() *types.Block { - return bc.genesisBlock +func (lc *LightChain) Genesis() *types.Block { + return lc.genesisBlock } -// State returns a new mutable state based on the current HEAD block. -func (bc *LightChain) State() (*state.StateDB, error) { - return nil, errors.New("not implemented, needs client/server interface split") +func (lc *LightChain) StateCache() state.Database { + panic("not implemented") } // GetBody retrieves a block body (transactions and uncles) from the database // or ODR service by hash, caching it if found. -func (self *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) { +func (lc *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) { // Short circuit if the body's already in the cache, retrieve otherwise - if cached, ok := self.bodyCache.Get(hash); ok { + if cached, ok := lc.bodyCache.Get(hash); ok { body := cached.(*types.Body) return body, nil } - number := self.hc.GetBlockNumber(hash) + number := lc.hc.GetBlockNumber(hash) if number == nil { return nil, errors.New("unknown block") } - body, err := GetBody(ctx, self.odr, hash, *number) + body, err := GetBody(ctx, lc.odr, hash, *number) if err != nil { return nil, err } // Cache the found body for next time and return - self.bodyCache.Add(hash, body) + lc.bodyCache.Add(hash, body) return body, nil } // GetBodyRLP retrieves a block body in RLP encoding from the database or // ODR service by hash, caching it if found. -func (self *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) { +func (lc *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) { // Short circuit if the body's already in the cache, retrieve otherwise - if cached, ok := self.bodyRLPCache.Get(hash); ok { + if cached, ok := lc.bodyRLPCache.Get(hash); ok { return cached.(rlp.RawValue), nil } - number := self.hc.GetBlockNumber(hash) + number := lc.hc.GetBlockNumber(hash) if number == nil { return nil, errors.New("unknown block") } - body, err := GetBodyRLP(ctx, self.odr, hash, *number) + body, err := GetBodyRLP(ctx, lc.odr, hash, *number) if err != nil { return nil, err } // Cache the found body for next time and return - self.bodyRLPCache.Add(hash, body) + lc.bodyRLPCache.Add(hash, body) return body, nil } // HasBlock checks if a block is fully present in the database or not, caching // it if present. -func (bc *LightChain) HasBlock(hash common.Hash, number uint64) bool { - blk, _ := bc.GetBlock(NoOdr, hash, number) +func (lc *LightChain) HasBlock(hash common.Hash, number uint64) bool { + blk, _ := lc.GetBlock(NoOdr, hash, number) return blk != nil } // GetBlock retrieves a block from the database or ODR service by hash and number, // caching it if found. -func (self *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) { +func (lc *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) { // Short circuit if the block's already in the cache, retrieve otherwise - if block, ok := self.blockCache.Get(hash); ok { + if block, ok := lc.blockCache.Get(hash); ok { return block.(*types.Block), nil } - block, err := GetBlock(ctx, self.odr, hash, number) + block, err := GetBlock(ctx, lc.odr, hash, number) if err != nil { return nil, err } // Cache the found block for next time and return - self.blockCache.Add(block.Hash(), block) + lc.blockCache.Add(block.Hash(), block) return block, nil } // GetBlockByHash retrieves a block from the database or ODR service by hash, // caching it if found. -func (self *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - number := self.hc.GetBlockNumber(hash) +func (lc *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { + number := lc.hc.GetBlockNumber(hash) if number == nil { return nil, errors.New("unknown block") } - return self.GetBlock(ctx, hash, *number) + return lc.GetBlock(ctx, hash, *number) } // GetBlockByNumber retrieves a block from the database or ODR service by // number, caching it (associated with its hash) if found. -func (self *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) { - hash, err := GetCanonicalHash(ctx, self.odr, number) +func (lc *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) { + hash, err := GetCanonicalHash(ctx, lc.odr, number) if hash == (common.Hash{}) || err != nil { return nil, err } - return self.GetBlock(ctx, hash, number) + return lc.GetBlock(ctx, hash, number) } // Stop stops the blockchain service. If any imports are currently in progress // it will abort them using the procInterrupt. -func (bc *LightChain) Stop() { - if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { +func (lc *LightChain) Stop() { + if !atomic.CompareAndSwapInt32(&lc.running, 0, 1) { return } - close(bc.quit) - atomic.StoreInt32(&bc.procInterrupt, 1) + close(lc.quit) + atomic.StoreInt32(&lc.procInterrupt, 1) - bc.wg.Wait() + lc.wg.Wait() log.Info("Blockchain manager stopped") } // Rollback is designed to remove a chain of links from the database that aren't // certain enough to be valid. -func (self *LightChain) Rollback(chain []common.Hash) { - self.mu.Lock() - defer self.mu.Unlock() +func (lc *LightChain) Rollback(chain []common.Hash) { + lc.chainmu.Lock() + defer lc.chainmu.Unlock() for i := len(chain) - 1; i >= 0; i-- { hash := chain[i] - if head := self.hc.CurrentHeader(); head.Hash() == hash { - self.hc.SetCurrentHeader(self.GetHeader(head.ParentHash, head.Number.Uint64()-1)) + if head := lc.hc.CurrentHeader(); head.Hash() == hash { + lc.hc.SetCurrentHeader(lc.GetHeader(head.ParentHash, head.Number.Uint64()-1)) } } } // postChainEvents iterates over the events generated by a chain insertion and // posts them into the event feed. -func (self *LightChain) postChainEvents(events []interface{}) { +func (lc *LightChain) postChainEvents(events []interface{}) { for _, event := range events { switch ev := event.(type) { case core.ChainEvent: - if self.CurrentHeader().Hash() == ev.Hash { - self.chainHeadFeed.Send(core.ChainHeadEvent{Block: ev.Block}) + if lc.CurrentHeader().Hash() == ev.Hash { + lc.chainHeadFeed.Send(core.ChainHeadEvent{Block: ev.Block}) } - self.chainFeed.Send(ev) + lc.chainFeed.Send(ev) case core.ChainSideEvent: - self.chainSideFeed.Send(ev) + lc.chainSideFeed.Send(ev) } } } @@ -354,28 +354,25 @@ func (self *LightChain) postChainEvents(events []interface{}) { // // In the case of a light chain, InsertHeaderChain also creates and posts light // chain events when necessary. -func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { +func (lc *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { + if atomic.LoadInt32(&lc.disableCheckFreq) == 1 { + checkFreq = 0 + } start := time.Now() - if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil { + if i, err := lc.hc.ValidateHeaderChain(chain, checkFreq); err != nil { return i, err } // Make sure only one thread manipulates the chain at once - self.chainmu.Lock() - defer func() { - self.chainmu.Unlock() - time.Sleep(time.Millisecond * 10) // ugly hack; do not hog chain lock in case syncing is CPU-limited by validation - }() + lc.chainmu.Lock() + defer lc.chainmu.Unlock() - self.wg.Add(1) - defer self.wg.Done() + lc.wg.Add(1) + defer lc.wg.Done() var events []interface{} whFunc := func(header *types.Header) error { - self.mu.Lock() - defer self.mu.Unlock() - - status, err := self.hc.WriteHeader(header) + status, err := lc.hc.WriteHeader(header) switch status { case core.CanonStatTy: @@ -388,51 +385,51 @@ func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) } return err } - i, err := self.hc.InsertHeaderChain(chain, whFunc, start) - self.postChainEvents(events) + i, err := lc.hc.InsertHeaderChain(chain, whFunc, start) + lc.postChainEvents(events) return i, err } // CurrentHeader retrieves the current head header of the canonical chain. The // header is retrieved from the HeaderChain's internal cache. -func (self *LightChain) CurrentHeader() *types.Header { - return self.hc.CurrentHeader() +func (lc *LightChain) CurrentHeader() *types.Header { + return lc.hc.CurrentHeader() } // GetTd retrieves a block's total difficulty in the canonical chain from the // database by hash and number, caching it if found. -func (self *LightChain) GetTd(hash common.Hash, number uint64) *big.Int { - return self.hc.GetTd(hash, number) +func (lc *LightChain) GetTd(hash common.Hash, number uint64) *big.Int { + return lc.hc.GetTd(hash, number) } // GetTdByHash retrieves a block's total difficulty in the canonical chain from the // database by hash, caching it if found. -func (self *LightChain) GetTdByHash(hash common.Hash) *big.Int { - return self.hc.GetTdByHash(hash) +func (lc *LightChain) GetTdByHash(hash common.Hash) *big.Int { + return lc.hc.GetTdByHash(hash) } // GetHeader retrieves a block header from the database by hash and number, // caching it if found. -func (self *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header { - return self.hc.GetHeader(hash, number) +func (lc *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header { + return lc.hc.GetHeader(hash, number) } // GetHeaderByHash retrieves a block header from the database by hash, caching it if // found. -func (self *LightChain) GetHeaderByHash(hash common.Hash) *types.Header { - return self.hc.GetHeaderByHash(hash) +func (lc *LightChain) GetHeaderByHash(hash common.Hash) *types.Header { + return lc.hc.GetHeaderByHash(hash) } // HasHeader checks if a block header is present in the database or not, caching // it if present. -func (bc *LightChain) HasHeader(hash common.Hash, number uint64) bool { - return bc.hc.HasHeader(hash, number) +func (lc *LightChain) HasHeader(hash common.Hash, number uint64) bool { + return lc.hc.HasHeader(hash, number) } // GetBlockHashesFromHash retrieves a number of block hashes starting at a given // hash, fetching towards the genesis block. -func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { - return self.hc.GetBlockHashesFromHash(hash, max) +func (lc *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { + return lc.hc.GetBlockHashesFromHash(hash, max) } // GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or @@ -440,56 +437,56 @@ func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []c // number of blocks to be individually checked before we reach the canonical chain. // // Note: ancestor == 0 returns the same block, 1 returns its parent and so on. -func (bc *LightChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { - bc.chainmu.Lock() - defer bc.chainmu.Unlock() +func (lc *LightChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { + lc.chainmu.RLock() + defer lc.chainmu.RUnlock() - return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical) + return lc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical) } // GetHeaderByNumber retrieves a block header from the database by number, // caching it (associated with its hash) if found. -func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header { - return self.hc.GetHeaderByNumber(number) +func (lc *LightChain) GetHeaderByNumber(number uint64) *types.Header { + return lc.hc.GetHeaderByNumber(number) } // GetHeaderByNumberOdr retrieves a block header from the database or network // by number, caching it (associated with its hash) if found. -func (self *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) { - if header := self.hc.GetHeaderByNumber(number); header != nil { +func (lc *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) { + if header := lc.hc.GetHeaderByNumber(number); header != nil { return header, nil } - return GetHeaderByNumber(ctx, self.odr, number) + return GetHeaderByNumber(ctx, lc.odr, number) } // Config retrieves the header chain's chain configuration. -func (self *LightChain) Config() *params.ChainConfig { return self.hc.Config() } +func (lc *LightChain) Config() *params.ChainConfig { return lc.hc.Config() } -func (self *LightChain) SyncCht(ctx context.Context) bool { +func (lc *LightChain) SyncCht(ctx context.Context) bool { // If we don't have a CHT indexer, abort - if self.odr.ChtIndexer() == nil { + if lc.odr.ChtIndexer() == nil { return false } // Ensure the remote CHT head is ahead of us - head := self.CurrentHeader().Number.Uint64() - sections, _, _ := self.odr.ChtIndexer().Sections() + head := lc.CurrentHeader().Number.Uint64() + sections, _, _ := lc.odr.ChtIndexer().Sections() - latest := sections*self.indexerConfig.ChtSize - 1 - if clique := self.hc.Config().Clique; clique != nil { + latest := sections*lc.indexerConfig.ChtSize - 1 + if clique := lc.hc.Config().Clique; clique != nil { latest -= latest % clique.Epoch // epoch snapshot for clique } if head >= latest { return false } // Retrieve the latest useful header and update to it - if header, err := GetHeaderByNumber(ctx, self.odr, latest); header != nil && err == nil { - self.mu.Lock() - defer self.mu.Unlock() + if header, err := GetHeaderByNumber(ctx, lc.odr, latest); header != nil && err == nil { + lc.chainmu.Lock() + defer lc.chainmu.Unlock() // Ensure the chain didn't move past the latest block while retrieving it - if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { + if lc.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { log.Info("Updated latest header based on CHT", "number", header.Number, "hash", header.Hash(), "age", common.PrettyAge(time.Unix(header.Time.Int64(), 0))) - self.hc.SetCurrentHeader(header) + lc.hc.SetCurrentHeader(header) } return true } @@ -498,38 +495,48 @@ func (self *LightChain) SyncCht(ctx context.Context) bool { // LockChain locks the chain mutex for reading so that multiple canonical hashes can be // retrieved while it is guaranteed that they belong to the same version of the chain -func (self *LightChain) LockChain() { - self.chainmu.RLock() +func (lc *LightChain) LockChain() { + lc.chainmu.RLock() } // UnlockChain unlocks the chain mutex -func (self *LightChain) UnlockChain() { - self.chainmu.RUnlock() +func (lc *LightChain) UnlockChain() { + lc.chainmu.RUnlock() } // SubscribeChainEvent registers a subscription of ChainEvent. -func (self *LightChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { - return self.scope.Track(self.chainFeed.Subscribe(ch)) +func (lc *LightChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { + return lc.scope.Track(lc.chainFeed.Subscribe(ch)) } // SubscribeChainHeadEvent registers a subscription of ChainHeadEvent. -func (self *LightChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { - return self.scope.Track(self.chainHeadFeed.Subscribe(ch)) +func (lc *LightChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + return lc.scope.Track(lc.chainHeadFeed.Subscribe(ch)) } // SubscribeChainSideEvent registers a subscription of ChainSideEvent. -func (self *LightChain) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { - return self.scope.Track(self.chainSideFeed.Subscribe(ch)) +func (lc *LightChain) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { + return lc.scope.Track(lc.chainSideFeed.Subscribe(ch)) } // SubscribeLogsEvent implements the interface of filters.Backend // LightChain does not send logs events, so return an empty subscription. -func (self *LightChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { - return self.scope.Track(new(event.Feed).Subscribe(ch)) +func (lc *LightChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { + return lc.scope.Track(new(event.Feed).Subscribe(ch)) } // SubscribeRemovedLogsEvent implements the interface of filters.Backend // LightChain does not send core.RemovedLogsEvent, so return an empty subscription. -func (self *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { - return self.scope.Track(new(event.Feed).Subscribe(ch)) +func (lc *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + return lc.scope.Track(new(event.Feed).Subscribe(ch)) +} + +// DisableCheckFreq disables header validation. This is used for ultralight mode. +func (lc *LightChain) DisableCheckFreq() { + atomic.StoreInt32(&lc.disableCheckFreq, 1) +} + +// EnableCheckFreq enables header validation. +func (lc *LightChain) EnableCheckFreq() { + atomic.StoreInt32(&lc.disableCheckFreq, 0) } diff --git a/vendor/github.com/ethereum/go-ethereum/light/lightchain_test.go b/vendor/github.com/ethereum/go-ethereum/light/lightchain_test.go index d45c0656..58ea9304 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/lightchain_test.go +++ b/vendor/github.com/ethereum/go-ethereum/light/lightchain_test.go @@ -52,7 +52,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [ // chain. Depending on the full flag, if creates either a full block chain or a // header only chain. func newCanonical(n int) (ethdb.Database, *LightChain, error) { - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker()) @@ -69,7 +69,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { // newTestLightChain creates a LightChain that doesn't validate anything. func newTestLightChain() *LightChain { - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() gspec := &core.Genesis{ Difficulty: big.NewInt(1), Config: params.TestChainConfig, @@ -122,10 +122,10 @@ func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error return err } // Manually insert the header into the database, but don't reorganize (allows subsequent testing) - lightchain.mu.Lock() + lightchain.chainmu.Lock() rawdb.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash))) rawdb.WriteHeader(lightchain.chainDb, header) - lightchain.mu.Unlock() + lightchain.chainmu.Unlock() } return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/light/nodeset.go b/vendor/github.com/ethereum/go-ethereum/light/nodeset.go index 6f25219c..a8bf4f6c 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/nodeset.go +++ b/vendor/github.com/ethereum/go-ethereum/light/nodeset.go @@ -60,6 +60,15 @@ func (db *NodeSet) Put(key []byte, value []byte) error { return nil } +// Delete removes a node from the set +func (db *NodeSet) Delete(key []byte) error { + db.lock.Lock() + defer db.lock.Unlock() + + delete(db.nodes, string(key)) + return nil +} + // Get returns a stored node func (db *NodeSet) Get(key []byte) ([]byte, error) { db.lock.RLock() @@ -106,7 +115,7 @@ func (db *NodeSet) NodeList() NodeList { } // Store writes the contents of the set to the given database -func (db *NodeSet) Store(target ethdb.Putter) { +func (db *NodeSet) Store(target ethdb.Writer) { db.lock.RLock() defer db.lock.RUnlock() @@ -115,11 +124,11 @@ func (db *NodeSet) Store(target ethdb.Putter) { } } -// NodeList stores an ordered list of trie nodes. It implements ethdb.Putter. +// NodeList stores an ordered list of trie nodes. It implements ethdb.Writer. type NodeList []rlp.RawValue // Store writes the contents of the list to the given database -func (n NodeList) Store(db ethdb.Putter) { +func (n NodeList) Store(db ethdb.Writer) { for _, node := range n { db.Put(crypto.Keccak256(node), node) } @@ -138,6 +147,11 @@ func (n *NodeList) Put(key []byte, value []byte) error { return nil } +// Delete panics as there's no reason to remove a node from the list. +func (n *NodeList) Delete(key []byte) error { + panic("not supported") +} + // DataSize returns the aggregated data size of nodes in the list func (n NodeList) DataSize() int { var size int diff --git a/vendor/github.com/ethereum/go-ethereum/light/odr.go b/vendor/github.com/ethereum/go-ethereum/light/odr.go index 900be054..95f1948e 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/odr.go +++ b/vendor/github.com/ethereum/go-ethereum/light/odr.go @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package light import ( diff --git a/vendor/github.com/ethereum/go-ethereum/light/odr_test.go b/vendor/github.com/ethereum/go-ethereum/light/odr_test.go index 3da7b305..c1762c43 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/odr_test.go +++ b/vendor/github.com/ethereum/go-ethereum/light/odr_test.go @@ -250,8 +250,8 @@ func testChainGen(i int, block *core.BlockGen) { func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { var ( - sdb = ethdb.NewMemDatabase() - ldb = ethdb.NewMemDatabase() + sdb = rawdb.NewMemoryDatabase() + ldb = rawdb.NewMemoryDatabase() gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} genesis = gspec.MustCommit(sdb) ) diff --git a/vendor/github.com/ethereum/go-ethereum/light/odr_util.go b/vendor/github.com/ethereum/go-ethereum/light/odr_util.go index 073f0d64..00103a76 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/odr_util.go +++ b/vendor/github.com/ethereum/go-ethereum/light/odr_util.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -var sha3_nil = crypto.Keccak256Hash(nil) +var sha3Nil = crypto.Keccak256Hash(nil) func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { db := odr.Database() diff --git a/vendor/github.com/ethereum/go-ethereum/light/postprocess.go b/vendor/github.com/ethereum/go-ethereum/light/postprocess.go index 1cfd7535..2030782b 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/postprocess.go +++ b/vendor/github.com/ethereum/go-ethereum/light/postprocess.go @@ -154,15 +154,15 @@ type ChtIndexerBackend struct { // NewChtIndexer creates a Cht chain indexer func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64) *core.ChainIndexer { - trieTable := ethdb.NewTable(db, ChtTablePrefix) + trieTable := rawdb.NewTable(db, ChtTablePrefix) backend := &ChtIndexerBackend{ diskdb: db, odr: odr, trieTable: trieTable, - triedb: trie.NewDatabase(trieTable), + triedb: trie.NewDatabaseWithCache(trieTable, 1), // Use a tiny cache only to keep memory down sectionSize: size, } - return core.NewChainIndexer(db, ethdb.NewTable(db, "chtIndex-"), backend, size, confirms, time.Millisecond*100, "cht") + return core.NewChainIndexer(db, rawdb.NewTable(db, "chtIndex-"), backend, size, confirms, time.Millisecond*100, "cht") } // fetchMissingNodes tries to retrieve the last entry of the latest trusted CHT from the @@ -276,18 +276,18 @@ type BloomTrieIndexerBackend struct { // NewBloomTrieIndexer creates a BloomTrie chain indexer func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uint64) *core.ChainIndexer { - trieTable := ethdb.NewTable(db, BloomTrieTablePrefix) + trieTable := rawdb.NewTable(db, BloomTrieTablePrefix) backend := &BloomTrieIndexerBackend{ diskdb: db, odr: odr, trieTable: trieTable, - triedb: trie.NewDatabase(trieTable), + triedb: trie.NewDatabaseWithCache(trieTable, 1), // Use a tiny cache only to keep memory down parentSize: parentSize, size: size, } backend.bloomTrieRatio = size / parentSize backend.sectionHeads = make([]common.Hash, backend.bloomTrieRatio) - return core.NewChainIndexer(db, ethdb.NewTable(db, "bltIndex-"), backend, size, 0, time.Millisecond*100, "bloomtrie") + return core.NewChainIndexer(db, rawdb.NewTable(db, "bltIndex-"), backend, size, 0, time.Millisecond*100, "bloomtrie") } // fetchMissingNodes tries to retrieve the last entries of the latest trusted bloom trie from the diff --git a/vendor/github.com/ethereum/go-ethereum/light/trie.go b/vendor/github.com/ethereum/go-ethereum/light/trie.go index c07e9946..27abb1dc 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/trie.go +++ b/vendor/github.com/ethereum/go-ethereum/light/trie.go @@ -67,7 +67,7 @@ func (db *odrDatabase) CopyTrie(t state.Trie) state.Trie { } func (db *odrDatabase) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - if codeHash == sha3_nil { + if codeHash == sha3Nil { return nil, nil } if code, err := db.backend.Database().Get(codeHash[:]); err == nil { @@ -108,7 +108,7 @@ func (t *odrTrie) TryGet(key []byte) ([]byte, error) { func (t *odrTrie) TryUpdate(key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.TryUpdate(key, value) }) } @@ -141,7 +141,7 @@ func (t *odrTrie) GetKey(sha []byte) []byte { return nil } -func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { +func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Writer) error { return errors.New("not implemented, needs client/server interface split") } diff --git a/vendor/github.com/ethereum/go-ethereum/light/trie_test.go b/vendor/github.com/ethereum/go-ethereum/light/trie_test.go index 51ce9017..4919f896 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/trie_test.go +++ b/vendor/github.com/ethereum/go-ethereum/light/trie_test.go @@ -25,17 +25,17 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" ) func TestNodeIterator(t *testing.T) { var ( - fulldb = ethdb.NewMemDatabase() - lightdb = ethdb.NewMemDatabase() + fulldb = rawdb.NewMemoryDatabase() + lightdb = rawdb.NewMemoryDatabase() gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} genesis = gspec.MustCommit(fulldb) ) @@ -64,7 +64,7 @@ func diffTries(t1, t2 state.Trie) error { spew.Dump(i2) return fmt.Errorf("tries have different keys %x, %x", i1.Key, i2.Key) } - if !bytes.Equal(i2.Value, i2.Value) { + if !bytes.Equal(i1.Value, i2.Value) { return fmt.Errorf("tries differ at key %x", i1.Key) } } diff --git a/vendor/github.com/ethereum/go-ethereum/light/txpool.go b/vendor/github.com/ethereum/go-ethereum/light/txpool.go index 767a797b..e945ef2e 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/txpool.go +++ b/vendor/github.com/ethereum/go-ethereum/light/txpool.go @@ -390,81 +390,81 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error // add validates a new transaction and sets its state pending if processable. // It also updates the locally stored nonce if necessary. -func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error { +func (pool *TxPool) add(ctx context.Context, tx *types.Transaction) error { hash := tx.Hash() - if self.pending[hash] != nil { + if pool.pending[hash] != nil { return fmt.Errorf("Known transaction (%x)", hash[:4]) } - err := self.validateTx(ctx, tx) + err := pool.validateTx(ctx, tx) if err != nil { return err } - if _, ok := self.pending[hash]; !ok { - self.pending[hash] = tx + if _, ok := pool.pending[hash]; !ok { + pool.pending[hash] = tx nonce := tx.Nonce() + 1 - addr, _ := types.Sender(self.signer, tx) - if nonce > self.nonce[addr] { - self.nonce[addr] = nonce + addr, _ := types.Sender(pool.signer, tx) + if nonce > pool.nonce[addr] { + pool.nonce[addr] = nonce } // Notify the subscribers. This event is posted in a goroutine // because it's possible that somewhere during the post "Remove transaction" // gets called which will then wait for the global tx pool lock and deadlock. - go self.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}}) + go pool.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}}) } // Print a log message if low enough level is set - log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(self.signer, tx); return from }}, "to", tx.To()) + log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(pool.signer, tx); return from }}, "to", tx.To()) return nil } // Add adds a transaction to the pool if valid and passes it to the tx relay // backend -func (self *TxPool) Add(ctx context.Context, tx *types.Transaction) error { - self.mu.Lock() - defer self.mu.Unlock() +func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error { + pool.mu.Lock() + defer pool.mu.Unlock() data, err := rlp.EncodeToBytes(tx) if err != nil { return err } - if err := self.add(ctx, tx); err != nil { + if err := pool.add(ctx, tx); err != nil { return err } //fmt.Println("Send", tx.Hash()) - self.relay.Send(types.Transactions{tx}) + pool.relay.Send(types.Transactions{tx}) - self.chainDb.Put(tx.Hash().Bytes(), data) + pool.chainDb.Put(tx.Hash().Bytes(), data) return nil } // AddTransactions adds all valid transactions to the pool and passes them to // the tx relay backend -func (self *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) { - self.mu.Lock() - defer self.mu.Unlock() +func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) { + pool.mu.Lock() + defer pool.mu.Unlock() var sendTx types.Transactions for _, tx := range txs { - if err := self.add(ctx, tx); err == nil { + if err := pool.add(ctx, tx); err == nil { sendTx = append(sendTx, tx) } } if len(sendTx) > 0 { - self.relay.Send(sendTx) + pool.relay.Send(sendTx) } } // GetTransaction returns a transaction if it is contained in the pool // and nil otherwise. -func (tp *TxPool) GetTransaction(hash common.Hash) *types.Transaction { +func (pool *TxPool) GetTransaction(hash common.Hash) *types.Transaction { // check the txs first - if tx, ok := tp.pending[hash]; ok { + if tx, ok := pool.pending[hash]; ok { return tx } return nil @@ -472,13 +472,13 @@ func (tp *TxPool) GetTransaction(hash common.Hash) *types.Transaction { // GetTransactions returns all currently processable transactions. // The returned slice may be modified by the caller. -func (self *TxPool) GetTransactions() (txs types.Transactions, err error) { - self.mu.RLock() - defer self.mu.RUnlock() +func (pool *TxPool) GetTransactions() (txs types.Transactions, err error) { + pool.mu.RLock() + defer pool.mu.RUnlock() - txs = make(types.Transactions, len(self.pending)) + txs = make(types.Transactions, len(pool.pending)) i := 0 - for _, tx := range self.pending { + for _, tx := range pool.pending { txs[i] = tx i++ } @@ -487,14 +487,14 @@ func (self *TxPool) GetTransactions() (txs types.Transactions, err error) { // Content retrieves the data content of the transaction pool, returning all the // pending as well as queued transactions, grouped by account and nonce. -func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { - self.mu.RLock() - defer self.mu.RUnlock() +func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { + pool.mu.RLock() + defer pool.mu.RUnlock() // Retrieve all the pending transactions and sort by account and by nonce pending := make(map[common.Address]types.Transactions) - for _, tx := range self.pending { - account, _ := types.Sender(self.signer, tx) + for _, tx := range pool.pending { + account, _ := types.Sender(pool.signer, tx) pending[account] = append(pending[account], tx) } // There are no queued transactions in a light pool, just return an empty map @@ -503,20 +503,20 @@ func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common } // RemoveTransactions removes all given transactions from the pool. -func (self *TxPool) RemoveTransactions(txs types.Transactions) { - self.mu.Lock() - defer self.mu.Unlock() +func (pool *TxPool) RemoveTransactions(txs types.Transactions) { + pool.mu.Lock() + defer pool.mu.Unlock() var hashes []common.Hash - batch := self.chainDb.NewBatch() + batch := pool.chainDb.NewBatch() for _, tx := range txs { hash := tx.Hash() - delete(self.pending, hash) + delete(pool.pending, hash) batch.Delete(hash.Bytes()) hashes = append(hashes, hash) } batch.Write() - self.relay.Discard(hashes) + pool.relay.Discard(hashes) } // RemoveTx removes the transaction with the given hash from the pool. diff --git a/vendor/github.com/ethereum/go-ethereum/light/txpool_test.go b/vendor/github.com/ethereum/go-ethereum/light/txpool_test.go index ce77573e..4f446c6c 100644 --- a/vendor/github.com/ethereum/go-ethereum/light/txpool_test.go +++ b/vendor/github.com/ethereum/go-ethereum/light/txpool_test.go @@ -26,9 +26,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -81,8 +81,8 @@ func TestTxPool(t *testing.T) { } var ( - sdb = ethdb.NewMemDatabase() - ldb = ethdb.NewMemDatabase() + sdb = rawdb.NewMemoryDatabase() + ldb = rawdb.NewMemoryDatabase() gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} genesis = gspec.MustCommit(sdb) ) diff --git a/vendor/github.com/ethereum/go-ethereum/metrics/influxdb/influxdb.go b/vendor/github.com/ethereum/go-ethereum/metrics/influxdb/influxdb.go index 31a5c21b..6619915f 100644 --- a/vendor/github.com/ethereum/go-ethereum/metrics/influxdb/influxdb.go +++ b/vendor/github.com/ethereum/go-ethereum/metrics/influxdb/influxdb.go @@ -58,11 +58,40 @@ func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, userna rep.run() } +// InfluxDBWithTagsOnce runs once an InfluxDB reporter and post the given metrics.Registry with the specified tags +func InfluxDBWithTagsOnce(r metrics.Registry, url, database, username, password, namespace string, tags map[string]string) error { + u, err := uurl.Parse(url) + if err != nil { + return fmt.Errorf("Unable to parse InfluxDB. url: %s, err: %v", url, err) + } + + rep := &reporter{ + reg: r, + url: *u, + database: database, + username: username, + password: password, + namespace: namespace, + tags: tags, + cache: make(map[string]int64), + } + if err := rep.makeClient(); err != nil { + return fmt.Errorf("Unable to make InfluxDB client. err: %v", err) + } + + if err := rep.send(); err != nil { + return fmt.Errorf("Unable to send to InfluxDB. err: %v", err) + } + + return nil +} + func (r *reporter) makeClient() (err error) { r.client, err = client.NewClient(client.Config{ URL: r.url, Username: r.username, Password: r.password, + Timeout: 10 * time.Second, }) return diff --git a/vendor/github.com/ethereum/go-ethereum/metrics/metrics.go b/vendor/github.com/ethereum/go-ethereum/metrics/metrics.go index 2a2b804e..8ae7aec4 100644 --- a/vendor/github.com/ethereum/go-ethereum/metrics/metrics.go +++ b/vendor/github.com/ethereum/go-ethereum/metrics/metrics.go @@ -15,24 +15,41 @@ import ( ) // Enabled is checked by the constructor functions for all of the -// standard metrics. If it is true, the metric returned is a stub. +// standard metrics. If it is true, the metric returned is a stub. // // This global kill-switch helps quantify the observer effect and makes // for less cluttered pprof profiles. -var Enabled bool = false +var Enabled = false -// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. -const MetricsEnabledFlag = "metrics" -const DashboardEnabledFlag = "dashboard" +// EnabledExpensive is a soft-flag meant for external packages to check if costly +// metrics gathering is allowed or not. The goal is to separate standard metrics +// for health monitoring and debug metrics that might impact runtime performance. +var EnabledExpensive = false + +// enablerFlags is the CLI flag names to use to enable metrics collections. +var enablerFlags = []string{"metrics", "dashboard"} + +// expensiveEnablerFlags is the CLI flag names to use to enable metrics collections. +var expensiveEnablerFlags = []string{"metrics.expensive"} // Init enables or disables the metrics system. Since we need this to run before // any other code gets to create meters and timers, we'll actually do an ugly hack // and peek into the command line args for the metrics flag. func init() { for _, arg := range os.Args { - if flag := strings.TrimLeft(arg, "-"); flag == MetricsEnabledFlag || flag == DashboardEnabledFlag { - log.Info("Enabling metrics collection") - Enabled = true + flag := strings.TrimLeft(arg, "-") + + for _, enabler := range enablerFlags { + if !Enabled && flag == enabler { + log.Info("Enabling metrics collection") + Enabled = true + } + } + for _, enabler := range expensiveEnablerFlags { + if !EnabledExpensive && flag == enabler { + log.Info("Enabling expensive metrics collection") + EnabledExpensive = true + } } } } diff --git a/vendor/github.com/ethereum/go-ethereum/metrics/opentsdb.go b/vendor/github.com/ethereum/go-ethereum/metrics/opentsdb.go index df7f152e..3fde5545 100644 --- a/vendor/github.com/ethereum/go-ethereum/metrics/opentsdb.go +++ b/vendor/github.com/ethereum/go-ethereum/metrics/opentsdb.go @@ -10,7 +10,7 @@ import ( "time" ) -var shortHostName string = "" +var shortHostName = "" // OpenTSDBConfig provides a container with configuration parameters for // the OpenTSDB exporter diff --git a/vendor/github.com/ethereum/go-ethereum/metrics/registry.go b/vendor/github.com/ethereum/go-ethereum/metrics/registry.go index c1cf7906..c5435adf 100644 --- a/vendor/github.com/ethereum/go-ethereum/metrics/registry.go +++ b/vendor/github.com/ethereum/go-ethereum/metrics/registry.go @@ -312,8 +312,9 @@ func (r *PrefixedRegistry) UnregisterAll() { } var ( - DefaultRegistry = NewRegistry() - EphemeralRegistry = NewRegistry() + DefaultRegistry = NewRegistry() + EphemeralRegistry = NewRegistry() + AccountingRegistry = NewRegistry() // registry used in swarm ) // Call the given function for each registered metric. diff --git a/vendor/github.com/ethereum/go-ethereum/miner/stress_clique.go b/vendor/github.com/ethereum/go-ethereum/miner/stress_clique.go index 7e19975a..8a355a4d 100644 --- a/vendor/github.com/ethereum/go-ethereum/miner/stress_clique.go +++ b/vendor/github.com/ethereum/go-ethereum/miner/stress_clique.go @@ -69,7 +69,7 @@ func main() { if err != nil { panic(err) } - defer node.Stop() + defer node.Close() for node.Server().NodeInfo().Ports.Listener == 0 { time.Sleep(250 * time.Millisecond) diff --git a/vendor/github.com/ethereum/go-ethereum/miner/stress_ethash.go b/vendor/github.com/ethereum/go-ethereum/miner/stress_ethash.go index 044ca9a2..040af9fb 100644 --- a/vendor/github.com/ethereum/go-ethereum/miner/stress_ethash.go +++ b/vendor/github.com/ethereum/go-ethereum/miner/stress_ethash.go @@ -69,7 +69,7 @@ func main() { if err != nil { panic(err) } - defer node.Stop() + defer node.Close() for node.Server().NodeInfo().Ports.Listener == 0 { time.Sleep(250 * time.Millisecond) diff --git a/vendor/github.com/ethereum/go-ethereum/miner/worker.go b/vendor/github.com/ethereum/go-ethereum/miner/worker.go index 8579c5c8..80c1771b 100644 --- a/vendor/github.com/ethereum/go-ethereum/miner/worker.go +++ b/vendor/github.com/ethereum/go-ethereum/miner/worker.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -567,6 +566,11 @@ func (w *worker) resultLoop() { logs []*types.Log ) for i, receipt := range task.receipts { + // add block location fields + receipt.BlockHash = hash + receipt.BlockNumber = block.Number() + receipt.TransactionIndex = uint(i) + receipts[i] = new(types.Receipt) *receipts[i] = *receipt // Update the block hash in all logs since it is now available and not when the @@ -692,7 +696,7 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, vm.Config{}) + receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err diff --git a/vendor/github.com/ethereum/go-ethereum/miner/worker_test.go b/vendor/github.com/ethereum/go-ethereum/miner/worker_test.go index 7c8f167a..99a671ae 100644 --- a/vendor/github.com/ethereum/go-ethereum/miner/worker_test.go +++ b/vendor/github.com/ethereum/go-ethereum/miner/worker_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -79,7 +80,7 @@ type testWorkerBackend struct { func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, n int) *testWorkerBackend { var ( - db = ethdb.NewMemDatabase() + db = rawdb.NewMemoryDatabase() gspec = core.Genesis{ Config: chainConfig, Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, @@ -142,7 +143,7 @@ func TestPendingStateAndBlockEthash(t *testing.T) { testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker()) } func TestPendingStateAndBlockClique(t *testing.T) { - testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) + testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) } func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { @@ -174,7 +175,7 @@ func TestEmptyWorkEthash(t *testing.T) { testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) } func TestEmptyWorkClique(t *testing.T) { - testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) + testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) } func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { @@ -224,7 +225,7 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens for i := 0; i < 2; i += 1 { select { case <-taskCh: - case <-time.NewTimer(time.Second).C: + case <-time.NewTimer(2 * time.Second).C: t.Error("new task timeout") } } @@ -291,7 +292,7 @@ func TestRegenerateMiningBlockEthash(t *testing.T) { } func TestRegenerateMiningBlockClique(t *testing.T) { - testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) + testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) } func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { @@ -356,7 +357,7 @@ func TestAdjustIntervalEthash(t *testing.T) { } func TestAdjustIntervalClique(t *testing.T) { - testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) + testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) } func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { diff --git a/vendor/github.com/ethereum/go-ethereum/mobile/big.go b/vendor/github.com/ethereum/go-ethereum/mobile/big.go index dd7b1587..86ea9324 100644 --- a/vendor/github.com/ethereum/go-ethereum/mobile/big.go +++ b/vendor/github.com/ethereum/go-ethereum/mobile/big.go @@ -84,6 +84,13 @@ func (bi *BigInt) SetString(x string, base int) { // BigInts represents a slice of big ints. type BigInts struct{ bigints []*big.Int } +// NewBigInts creates a slice of uninitialized big numbers. +func NewBigInts(size int) *BigInts { + return &BigInts{ + bigints: make([]*big.Int, size), + } +} + // Size returns the number of big ints in the slice. func (bi *BigInts) Size() int { return len(bi.bigints) diff --git a/vendor/github.com/ethereum/go-ethereum/mobile/geth.go b/vendor/github.com/ethereum/go-ethereum/mobile/geth.go index e3e2e905..fba3e571 100644 --- a/vendor/github.com/ethereum/go-ethereum/mobile/geth.go +++ b/vendor/github.com/ethereum/go-ethereum/mobile/geth.go @@ -76,6 +76,9 @@ type NodeConfig struct { // Listening address of pprof server. PprofAddress string + + // Ultra Light client options + ULC *eth.ULCConfig } // defaultNodeConfig contains the default node configuration values to use if all @@ -131,6 +134,7 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { MaxPeers: config.MaxPeers, }, } + rawStack, err := node.New(nodeConf) if err != nil { return nil, err @@ -188,6 +192,12 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { return &Node{rawStack}, nil } +// Close terminates a running node along with all it's services, tearing internal +// state doen too. It's not possible to restart a closed node. +func (n *Node) Close() error { + return n.node.Close() +} + // Start creates a live P2P node and starts running it. func (n *Node) Start() error { return n.node.Start() diff --git a/vendor/github.com/ethereum/go-ethereum/mobile/types.go b/vendor/github.com/ethereum/go-ethereum/mobile/types.go index 443d07ea..1a0389cb 100644 --- a/vendor/github.com/ethereum/go-ethereum/mobile/types.go +++ b/vendor/github.com/ethereum/go-ethereum/mobile/types.go @@ -197,8 +197,18 @@ type Transaction struct { tx *types.Transaction } -// NewTransaction creates a new transaction with the given properties. +// NewContractCreation creates a new transaction for deploying a new contract with +// the given properties. +func NewContractCreation(nonce int64, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { + return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} +} + +// NewTransaction creates a new transaction with the given properties. Contracts +// can be created by transacting with a nil recipient. func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { + if to == nil { + return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} + } return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} } diff --git a/vendor/github.com/ethereum/go-ethereum/node/config.go b/vendor/github.com/ethereum/go-ethereum/node/config.go index 8f10f4f6..2f871e47 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/config.go +++ b/vendor/github.com/ethereum/go-ethereum/node/config.go @@ -24,8 +24,10 @@ import ( "path/filepath" "runtime" "strings" + "sync" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/common" @@ -79,6 +81,9 @@ type Config struct { // is created by New and destroyed when the node is stopped. KeyStoreDir string `toml:",omitempty"` + // ExternalSigner specifies an external URI for a clef-type signer + ExternalSigner string `toml:"omitempty"` + // UseLightweightKDF lowers the memory and CPU requirements of the key store // scrypt KDF at the expense of security. UseLightweightKDF bool `toml:",omitempty"` @@ -101,6 +106,29 @@ type Config struct { // for ephemeral nodes). HTTPPort int `toml:",omitempty"` + // GraphQLHost is the host interface on which to start the GraphQL server. If this + // field is empty, no GraphQL API endpoint will be started. + GraphQLHost string `toml:",omitempty"` + + // GraphQLPort is the TCP port number on which to start the GraphQL server. The + // default zero value is/ valid and will pick a port number randomly (useful + // for ephemeral nodes). + GraphQLPort int `toml:",omitempty"` + + // GraphQLCors is the Cross-Origin Resource Sharing header to send to requesting + // clients. Please be aware that CORS is a browser enforced security, it's fully + // useless for custom HTTP clients. + GraphQLCors []string `toml:",omitempty"` + + // GraphQLVirtualHosts is the list of virtual hostnames which are allowed on incoming requests. + // This is by default {'localhost'}. Using this prevents attacks like + // DNS rebinding, which bypasses SOP by simply masquerading as being within the same + // origin. These attacks do not utilize CORS, since they are not cross-domain. + // By explicitly checking the Host-header, the server will not allow requests + // made against the server with a malicious host domain. + // Requests using ip address directly are not affected + GraphQLVirtualHosts []string `toml:",omitempty"` + // HTTPCors is the Cross-Origin Resource Sharing header to send to requesting // clients. Please be aware that CORS is a browser enforced security, it's fully // useless for custom HTTP clients. @@ -152,6 +180,10 @@ type Config struct { // Logger is a custom logger to use with the p2p.Server. Logger log.Logger `toml:",omitempty"` + + staticNodesWarning bool + trustedNodesWarning bool + oldGethResourceWarning bool } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into @@ -208,6 +240,15 @@ func (c *Config) HTTPEndpoint() string { return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort) } +// GraphQLEndpoint resolves a GraphQL endpoint based on the configured host interface +// and port parameters. +func (c *Config) GraphQLEndpoint() string { + if c.GraphQLHost == "" { + return "" + } + return fmt.Sprintf("%s:%d", c.GraphQLHost, c.GraphQLPort) +} + // DefaultHTTPEndpoint returns the HTTP endpoint used by default. func DefaultHTTPEndpoint() string { config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort} @@ -263,8 +304,8 @@ var isOldGethResource = map[string]bool{ "chaindata": true, "nodes": true, "nodekey": true, - "static-nodes.json": true, - "trusted-nodes.json": true, + "static-nodes.json": false, // no warning for these because they have their + "trusted-nodes.json": false, // own separate warning. } // ResolvePath resolves path in the instance directory. @@ -277,13 +318,15 @@ func (c *Config) ResolvePath(path string) string { } // Backwards-compatibility: ensure that data directory files created // by geth 1.4 are used if they exist. - if c.name() == "geth" && isOldGethResource[path] { + if warn, isOld := isOldGethResource[path]; isOld { oldpath := "" - if c.Name == "geth" { + if c.name() == "geth" { oldpath = filepath.Join(c.DataDir, path) } if oldpath != "" && common.FileExist(oldpath) { - // TODO: print warning + if warn { + c.warnOnce(&c.oldGethResourceWarning, "Using deprecated resource file %s, please move this file to the 'geth' subdirectory of datadir.", oldpath) + } return oldpath } } @@ -337,17 +380,17 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { // StaticNodes returns a list of node enode URLs configured as static nodes. func (c *Config) StaticNodes() []*enode.Node { - return c.parsePersistentNodes(c.ResolvePath(datadirStaticNodes)) + return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes)) } // TrustedNodes returns a list of node enode URLs configured as trusted nodes. func (c *Config) TrustedNodes() []*enode.Node { - return c.parsePersistentNodes(c.ResolvePath(datadirTrustedNodes)) + return c.parsePersistentNodes(&c.trustedNodesWarning, c.ResolvePath(datadirTrustedNodes)) } // parsePersistentNodes parses a list of discovery node URLs loaded from a .json // file from within the data directory. -func (c *Config) parsePersistentNodes(path string) []*enode.Node { +func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node { // Short circuit if no node config is present if c.DataDir == "" { return nil @@ -355,10 +398,12 @@ func (c *Config) parsePersistentNodes(path string) []*enode.Node { if _, err := os.Stat(path); err != nil { return nil } + c.warnOnce(w, "Found deprecated node list file %s, please use the TOML config file instead.", path) + // Load the nodes from the config file. var nodelist []string if err := common.LoadJSON(path, &nodelist); err != nil { - log.Error(fmt.Sprintf("Can't load node file %s: %v", path, err)) + log.Error(fmt.Sprintf("Can't load node list file: %v", err)) return nil } // Interpret the list as a discovery node array @@ -421,22 +466,53 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { return nil, "", err } // Assemble the account manager and supported backends - backends := []accounts.Backend{ - keystore.NewKeyStore(keydir, scryptN, scryptP), - } - if !conf.NoUSB { - // Start a USB hub for Ledger hardware wallets - if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) + var backends []accounts.Backend + if len(conf.ExternalSigner) > 0 { + log.Info("Using external signer", "url", conf.ExternalSigner) + if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { + backends = append(backends, extapi) } else { - backends = append(backends, ledgerhub) - } - // Start a USB hub for Trezor hardware wallets - if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) - } else { - backends = append(backends, trezorhub) + log.Info("Error configuring external signer", "error", err) } } + if len(backends) == 0 { + // For now, we're using EITHER external signer OR local signers. + // If/when we implement some form of lockfile for USB and keystore wallets, + // we can have both, but it's very confusing for the user to see the same + // accounts in both externally and locally, plus very racey. + backends = append(backends, keystore.NewKeyStore(keydir, scryptN, scryptP)) + if !conf.NoUSB { + // Start a USB hub for Ledger hardware wallets + if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) + } else { + backends = append(backends, ledgerhub) + } + // Start a USB hub for Trezor hardware wallets + if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + } else { + backends = append(backends, trezorhub) + } + } + } + return accounts.NewManager(backends...), ephemeral, nil } + +var warnLock sync.Mutex + +func (c *Config) warnOnce(w *bool, format string, args ...interface{}) { + warnLock.Lock() + defer warnLock.Unlock() + + if *w { + return + } + l := c.Logger + if l == nil { + l = log.Root() + } + l.Warn(fmt.Sprintf(format, args...)) + *w = true +} diff --git a/vendor/github.com/ethereum/go-ethereum/node/config_test.go b/vendor/github.com/ethereum/go-ethereum/node/config_test.go index b81d3d61..00c24a23 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/config_test.go +++ b/vendor/github.com/ethereum/go-ethereum/node/config_test.go @@ -38,14 +38,22 @@ func TestDatadirCreation(t *testing.T) { } defer os.RemoveAll(dir) - if _, err := New(&Config{DataDir: dir}); err != nil { + node, err := New(&Config{DataDir: dir}) + if err != nil { t.Fatalf("failed to create stack with existing datadir: %v", err) } + if err := node.Close(); err != nil { + t.Fatalf("failed to close node: %v", err) + } // Generate a long non-existing datadir path and check that it gets created by a node dir = filepath.Join(dir, "a", "b", "c", "d", "e", "f") - if _, err := New(&Config{DataDir: dir}); err != nil { + node, err = New(&Config{DataDir: dir}) + if err != nil { t.Fatalf("failed to create stack with creatable datadir: %v", err) } + if err := node.Close(); err != nil { + t.Fatalf("failed to close node: %v", err) + } if _, err := os.Stat(dir); err != nil { t.Fatalf("freshly created datadir not accessible: %v", err) } @@ -57,8 +65,12 @@ func TestDatadirCreation(t *testing.T) { defer os.Remove(file.Name()) dir = filepath.Join(file.Name(), "invalid/path") - if _, err := New(&Config{DataDir: dir}); err == nil { + node, err = New(&Config{DataDir: dir}) + if err == nil { t.Fatalf("protocol stack created with an invalid datadir") + if err := node.Close(); err != nil { + t.Fatalf("failed to close node: %v", err) + } } } diff --git a/vendor/github.com/ethereum/go-ethereum/node/defaults.go b/vendor/github.com/ethereum/go-ethereum/node/defaults.go index c1376dba..71e76334 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/defaults.go +++ b/vendor/github.com/ethereum/go-ethereum/node/defaults.go @@ -28,10 +28,12 @@ import ( ) const ( - DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server - DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server - DefaultWSHost = "localhost" // Default host interface for the websocket RPC server - DefaultWSPort = 8546 // Default TCP port for the websocket RPC server + DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server + DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server + DefaultWSHost = "localhost" // Default host interface for the websocket RPC server + DefaultWSPort = 8546 // Default TCP port for the websocket RPC server + DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server + DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server ) // DefaultConfig contains reasonable default settings. @@ -56,11 +58,20 @@ func DefaultDataDir() string { // Try to place the data folder in the user's home dir home := homeDir() if home != "" { - if runtime.GOOS == "darwin" { + switch runtime.GOOS { + case "darwin": return filepath.Join(home, "Library", "Ethereum") - } else if runtime.GOOS == "windows" { - return filepath.Join(home, "AppData", "Roaming", "Ethereum") - } else { + case "windows": + // We used to put everything in %HOME%\AppData\Roaming, but this caused + // problems with non-typical setups. If this fallback location exists and + // is non-empty, use it, otherwise DTRT and check %LOCALAPPDATA%. + fallback := filepath.Join(home, "AppData", "Roaming", "Ethereum") + appdata := windowsAppData() + if appdata == "" || isNonEmptyDir(fallback) { + return fallback + } + return filepath.Join(appdata, "Ethereum") + default: return filepath.Join(home, ".ethereum") } } @@ -68,6 +79,27 @@ func DefaultDataDir() string { return "" } +func windowsAppData() string { + v := os.Getenv("LOCALAPPDATA") + if v == "" { + // Windows XP and below don't have LocalAppData. Crash here because + // we don't support Windows XP and undefining the variable will cause + // other issues. + panic("environment variable LocalAppData is undefined") + } + return v +} + +func isNonEmptyDir(dir string) bool { + f, err := os.Open(dir) + if err != nil { + return false + } + names, _ := f.Readdir(1) + f.Close() + return len(names) > 0 +} + func homeDir() string { if home := os.Getenv("HOME"); home != "" { return home diff --git a/vendor/github.com/ethereum/go-ethereum/node/node.go b/vendor/github.com/ethereum/go-ethereum/node/node.go index 85299dba..bd031bd0 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/node.go +++ b/vendor/github.com/ethereum/go-ethereum/node/node.go @@ -27,6 +27,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/debug" @@ -121,6 +122,29 @@ func New(conf *Config) (*Node, error) { }, nil } +// Close stops the Node and releases resources acquired in +// Node constructor New. +func (n *Node) Close() error { + var errs []error + + // Terminate all subsystems and collect any errors + if err := n.Stop(); err != nil && err != ErrNodeStopped { + errs = append(errs, err) + } + if err := n.accman.Close(); err != nil { + errs = append(errs, err) + } + // Report any errors that might have occurred + switch len(errs) { + case 0: + return nil + case 1: + return errs[0] + default: + return fmt.Errorf("%v", errs) + } +} + // Register injects a new service into the node's stack. The service created by // the passed constructor must be unique in its type with regard to sibling ones. func (n *Node) Register(constructor ServiceConstructor) error { @@ -197,7 +221,7 @@ func (n *Node) Start() error { return convertFileLockError(err) } // Start each of the services - started := []reflect.Type{} + var started []reflect.Type for kind, service := range services { // Start the next service, stopping all previous upon failure if err := service.Start(running); err != nil { @@ -287,7 +311,7 @@ func (n *Node) startInProc(apis []rpc.API) error { if err := handler.RegisterName(api.Namespace, api.Service); err != nil { return err } - n.log.Debug("InProc registered", "service", api.Service, "namespace", api.Namespace) + n.log.Debug("InProc registered", "namespace", api.Namespace) } n.inprocHandler = handler return nil @@ -322,7 +346,7 @@ func (n *Node) stopIPC() { n.ipcListener.Close() n.ipcListener = nil - n.log.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint) + n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint) } if n.ipcHandler != nil { n.ipcHandler.Stop() @@ -578,11 +602,11 @@ func (n *Node) EventMux() *event.TypeMux { // OpenDatabase opens an existing database with the given name (or creates one if no // previous can be found) from within the node's instance directory. If the node is // ephemeral, a memory database is returned. -func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { +func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) { if n.config.DataDir == "" { - return ethdb.NewMemDatabase(), nil + return rawdb.NewMemoryDatabase(), nil } - return ethdb.NewLDBDatabase(n.config.ResolvePath(name), cache, handles) + return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace) } // ResolvePath returns the absolute path of a resource in the instance directory. diff --git a/vendor/github.com/ethereum/go-ethereum/node/node_example_test.go b/vendor/github.com/ethereum/go-ethereum/node/node_example_test.go index ee06f406..57b18855 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/node_example_test.go +++ b/vendor/github.com/ethereum/go-ethereum/node/node_example_test.go @@ -46,6 +46,8 @@ func ExampleService() { if err != nil { log.Fatalf("Failed to create network node: %v", err) } + defer stack.Close() + // Create and register a simple network service. This is done through the definition // of a node.ServiceConstructor that will instantiate a node.Service. The reason for // the factory method approach is to support service restarts without relying on the diff --git a/vendor/github.com/ethereum/go-ethereum/node/node_test.go b/vendor/github.com/ethereum/go-ethereum/node/node_test.go index f833cd68..c464771c 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/node_test.go +++ b/vendor/github.com/ethereum/go-ethereum/node/node_test.go @@ -46,6 +46,8 @@ func TestNodeLifeCycle(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Ensure that a stopped node can be stopped again for i := 0; i < 3; i++ { if err := stack.Stop(); err != ErrNodeStopped { @@ -88,6 +90,8 @@ func TestNodeUsedDataDir(t *testing.T) { if err != nil { t.Fatalf("failed to create original protocol stack: %v", err) } + defer original.Close() + if err := original.Start(); err != nil { t.Fatalf("failed to start original protocol stack: %v", err) } @@ -98,6 +102,8 @@ func TestNodeUsedDataDir(t *testing.T) { if err != nil { t.Fatalf("failed to create duplicate protocol stack: %v", err) } + defer duplicate.Close() + if err := duplicate.Start(); err != ErrDatadirUsed { t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) } @@ -109,6 +115,8 @@ func TestServiceRegistry(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Register a batch of unique services and ensure they start successfully services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC} for i, constructor := range services { @@ -141,6 +149,8 @@ func TestServiceLifeCycle(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Register a batch of life-cycle instrumented services services := map[string]InstrumentingWrapper{ "A": InstrumentedServiceMakerA, @@ -191,6 +201,8 @@ func TestServiceRestarts(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Define a service that does not support restarts var ( running bool @@ -239,6 +251,8 @@ func TestServiceConstructionAbortion(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Define a batch of good services services := map[string]InstrumentingWrapper{ "A": InstrumentedServiceMakerA, @@ -286,6 +300,8 @@ func TestServiceStartupAbortion(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Register a batch of good services services := map[string]InstrumentingWrapper{ "A": InstrumentedServiceMakerA, @@ -339,6 +355,8 @@ func TestServiceTerminationGuarantee(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Register a batch of good services services := map[string]InstrumentingWrapper{ "A": InstrumentedServiceMakerA, @@ -414,6 +432,8 @@ func TestServiceRetrieval(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + if err := stack.Register(NewNoopService); err != nil { t.Fatalf("noop service registration failed: %v", err) } @@ -449,6 +469,8 @@ func TestProtocolGather(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Register a batch of services with some configured number of protocols services := map[string]struct { Count int @@ -505,6 +527,8 @@ func TestAPIGather(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() + // Register a batch of services with some configured APIs calls := make(chan string, 1) makeAPI := func(result string) *OneMethodAPI { diff --git a/vendor/github.com/ethereum/go-ethereum/node/service.go b/vendor/github.com/ethereum/go-ethereum/node/service.go index 6a96d9b1..4f6cb667 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/service.go +++ b/vendor/github.com/ethereum/go-ethereum/node/service.go @@ -20,6 +20,7 @@ import ( "reflect" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" @@ -39,11 +40,11 @@ type ServiceContext struct { // OpenDatabase opens an existing database with the given name (or creates one // if no previous can be found) from within the node's data directory. If the // node is an ephemeral one, a memory database is returned. -func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (ethdb.Database, error) { +func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string) (ethdb.Database, error) { if ctx.config.DataDir == "" { - return ethdb.NewMemDatabase(), nil + return rawdb.NewMemoryDatabase(), nil } - db, err := ethdb.NewLDBDatabase(ctx.config.ResolvePath(name), cache, handles) + db, err := rawdb.NewLevelDBDatabase(ctx.config.ResolvePath(name), cache, handles, namespace) if err != nil { return nil, err } diff --git a/vendor/github.com/ethereum/go-ethereum/node/service_test.go b/vendor/github.com/ethereum/go-ethereum/node/service_test.go index a7ae439e..63004a51 100644 --- a/vendor/github.com/ethereum/go-ethereum/node/service_test.go +++ b/vendor/github.com/ethereum/go-ethereum/node/service_test.go @@ -39,7 +39,7 @@ func TestContextDatabases(t *testing.T) { } // Request the opening/creation of a database and ensure it persists to disk ctx := &ServiceContext{config: &Config{Name: "unit-test", DataDir: dir}} - db, err := ctx.OpenDatabase("persistent", 0, 0) + db, err := ctx.OpenDatabase("persistent", 0, 0, "") if err != nil { t.Fatalf("failed to open persistent database: %v", err) } @@ -50,7 +50,7 @@ func TestContextDatabases(t *testing.T) { } // Request th opening/creation of an ephemeral database and ensure it's not persisted ctx = &ServiceContext{config: &Config{DataDir: ""}} - db, err = ctx.OpenDatabase("ephemeral", 0, 0) + db, err = ctx.OpenDatabase("ephemeral", 0, 0, "") if err != nil { t.Fatalf("failed to open ephemeral database: %v", err) } @@ -67,6 +67,7 @@ func TestContextServices(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } + defer stack.Close() // Define a verifier that ensures a NoopA is before it and NoopB after verifier := func(ctx *ServiceContext) (Service, error) { var objA *NoopServiceA diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discover/node.go b/vendor/github.com/ethereum/go-ethereum/p2p/discover/node.go index 7ddf04fe..8d4af166 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discover/node.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discover/node.go @@ -33,7 +33,8 @@ import ( // The fields of Node may not be modified. type node struct { enode.Node - addedAt time.Time // time when the node was added to the table + addedAt time.Time // time when the node was added to the table + livenessChecks uint // how often liveness was checked } type encPubkey [64]byte diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discover/table.go b/vendor/github.com/ethereum/go-ethereum/p2p/discover/table.go index afd4c9a2..ef0c08af 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discover/table.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discover/table.go @@ -75,8 +75,10 @@ type Table struct { net transport refreshReq chan chan struct{} initDone chan struct{} - closeReq chan struct{} - closed chan struct{} + + closeOnce sync.Once + closeReq chan struct{} + closed chan struct{} nodeAddedHook func(*node) // for testing } @@ -180,16 +182,14 @@ func (tab *Table) ReadRandomNodes(buf []*enode.Node) (n int) { // Close terminates the network listener and flushes the node database. func (tab *Table) Close() { - if tab.net != nil { - tab.net.close() - } - - select { - case <-tab.closed: - // already closed. - case tab.closeReq <- struct{}{}: - <-tab.closed // wait for refreshLoop to end. - } + tab.closeOnce.Do(func() { + if tab.net != nil { + tab.net.close() + } + // Wait for loop to end. + close(tab.closeReq) + <-tab.closed + }) } // setFallbackNodes sets the initial points of contact. These nodes @@ -290,12 +290,16 @@ func (tab *Table) lookup(targetKey encPubkey, refreshIfEmpty bool) []*node { // we have asked all closest nodes, stop the search break } - // wait for the next reply - for _, n := range <-reply { - if n != nil && !seen[n.ID()] { - seen[n.ID()] = true - result.push(n, bucketSize) + select { + case nodes := <-reply: + for _, n := range nodes { + if n != nil && !seen[n.ID()] { + seen[n.ID()] = true + result.push(n, bucketSize) + } } + case <-tab.closeReq: + return nil // shutdown, no need to continue. } pendingQueries-- } @@ -303,24 +307,28 @@ func (tab *Table) lookup(targetKey encPubkey, refreshIfEmpty bool) []*node { } func (tab *Table) findnode(n *node, targetKey encPubkey, reply chan<- []*node) { - fails := tab.db.FindFails(n.ID()) + fails := tab.db.FindFails(n.ID(), n.IP()) r, err := tab.net.findnode(n.ID(), n.addr(), targetKey) - if err != nil || len(r) == 0 { + if err == errClosed { + // Avoid recording failures on shutdown. + reply <- nil + return + } else if err != nil || len(r) == 0 { fails++ - tab.db.UpdateFindFails(n.ID(), fails) + tab.db.UpdateFindFails(n.ID(), n.IP(), fails) log.Trace("Findnode failed", "id", n.ID(), "failcount", fails, "err", err) if fails >= maxFindnodeFailures { log.Trace("Too many findnode failures, dropping", "id", n.ID(), "failcount", fails) tab.delete(n) } } else if fails > 0 { - tab.db.UpdateFindFails(n.ID(), fails-1) + tab.db.UpdateFindFails(n.ID(), n.IP(), fails-1) } // Grab as many nodes as possible. Some of them might not be alive anymore, but we'll // just remove those again during revalidation. for _, n := range r { - tab.add(n) + tab.addSeenNode(n) } reply <- r } @@ -329,7 +337,7 @@ func (tab *Table) refresh() <-chan struct{} { done := make(chan struct{}) select { case tab.refreshReq <- done: - case <-tab.closed: + case <-tab.closeReq: close(done) } return done @@ -433,9 +441,9 @@ func (tab *Table) loadSeedNodes() { seeds = append(seeds, tab.nursery...) for i := range seeds { seed := seeds[i] - age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.LastPongReceived(seed.ID())) }} - log.Debug("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) - tab.add(seed) + age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) }} + log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) + tab.addSeenNode(seed) } } @@ -458,16 +466,17 @@ func (tab *Table) doRevalidate(done chan<- struct{}) { b := tab.buckets[bi] if err == nil { // The node responded, move it to the front. - log.Debug("Revalidated node", "b", bi, "id", last.ID()) - b.bump(last) + last.livenessChecks++ + log.Debug("Revalidated node", "b", bi, "id", last.ID(), "checks", last.livenessChecks) + tab.bumpInBucket(b, last) return } // No reply received, pick a replacement or delete the node if there aren't // any replacements. if r := tab.replace(b, last); r != nil { - log.Debug("Replaced dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "r", r.ID(), "rip", r.IP()) + log.Debug("Replaced dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks, "r", r.ID(), "rip", r.IP()) } else { - log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP()) + log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks) } } @@ -502,7 +511,7 @@ func (tab *Table) copyLiveNodes() { now := time.Now() for _, b := range &tab.buckets { for _, n := range b.entries { - if now.Sub(n.addedAt) >= seedMinTableTime { + if n.livenessChecks > 0 && now.Sub(n.addedAt) >= seedMinTableTime { tab.db.UpdateNode(unwrapNode(n)) } } @@ -518,7 +527,9 @@ func (tab *Table) closest(target enode.ID, nresults int) *nodesByDistance { close := &nodesByDistance{target: target} for _, b := range &tab.buckets { for _, n := range b.entries { - close.push(n, nresults) + if n.livenessChecks > 0 { + close.push(n, nresults) + } } } return close @@ -540,12 +551,12 @@ func (tab *Table) bucket(id enode.ID) *bucket { return tab.buckets[d-bucketMinDistance-1] } -// add attempts to add the given node to its corresponding bucket. If the bucket has space -// available, adding the node succeeds immediately. Otherwise, the node is added if the -// least recently active node in the bucket does not respond to a ping packet. +// addSeenNode adds a node which may or may not be live to the end of a bucket. If the +// bucket has space available, adding the node succeeds immediately. Otherwise, the node is +// added to the replacements list. // // The caller must not hold tab.mutex. -func (tab *Table) add(n *node) { +func (tab *Table) addSeenNode(n *node) { if n.ID() == tab.self().ID() { return } @@ -553,39 +564,67 @@ func (tab *Table) add(n *node) { tab.mutex.Lock() defer tab.mutex.Unlock() b := tab.bucket(n.ID()) - if !tab.bumpOrAdd(b, n) { - // Node is not in table. Add it to the replacement list. + if contains(b.entries, n.ID()) { + // Already in bucket, don't add. + return + } + if len(b.entries) >= bucketSize { + // Bucket full, maybe add as replacement. tab.addReplacement(b, n) + return + } + if !tab.addIP(b, n.IP()) { + // Can't add: IP limit reached. + return + } + // Add to end of bucket: + b.entries = append(b.entries, n) + b.replacements = deleteNode(b.replacements, n) + n.addedAt = time.Now() + if tab.nodeAddedHook != nil { + tab.nodeAddedHook(n) } } -// addThroughPing adds the given node to the table. Compared to plain -// 'add' there is an additional safety measure: if the table is still -// initializing the node is not added. This prevents an attack where the -// table could be filled by just sending ping repeatedly. +// addVerifiedNode adds a node whose existence has been verified recently to the front of a +// bucket. If the node is already in the bucket, it is moved to the front. If the bucket +// has no space, the node is added to the replacements list. +// +// There is an additional safety measure: if the table is still initializing the node +// is not added. This prevents an attack where the table could be filled by just sending +// ping repeatedly. // // The caller must not hold tab.mutex. -func (tab *Table) addThroughPing(n *node) { +func (tab *Table) addVerifiedNode(n *node) { if !tab.isInitDone() { return } - tab.add(n) -} + if n.ID() == tab.self().ID() { + return + } -// stuff adds nodes the table to the end of their corresponding bucket -// if the bucket is not full. The caller must not hold tab.mutex. -func (tab *Table) stuff(nodes []*node) { tab.mutex.Lock() defer tab.mutex.Unlock() - - for _, n := range nodes { - if n.ID() == tab.self().ID() { - continue // don't add self - } - b := tab.bucket(n.ID()) - if len(b.entries) < bucketSize { - tab.bumpOrAdd(b, n) - } + b := tab.bucket(n.ID()) + if tab.bumpInBucket(b, n) { + // Already in bucket, moved to front. + return + } + if len(b.entries) >= bucketSize { + // Bucket full, maybe add as replacement. + tab.addReplacement(b, n) + return + } + if !tab.addIP(b, n.IP()) { + // Can't add: IP limit reached. + return + } + // Add to front of bucket. + b.entries, _ = pushNode(b.entries, n, bucketSize) + b.replacements = deleteNode(b.replacements, n) + n.addedAt = time.Now() + if tab.nodeAddedHook != nil { + tab.nodeAddedHook(n) } } @@ -657,12 +696,21 @@ func (tab *Table) replace(b *bucket, last *node) *node { return r } -// bump moves the given node to the front of the bucket entry list +// bumpInBucket moves the given node to the front of the bucket entry list // if it is contained in that list. -func (b *bucket) bump(n *node) bool { +func (tab *Table) bumpInBucket(b *bucket, n *node) bool { for i := range b.entries { if b.entries[i].ID() == n.ID() { - // move it to the front + if !n.IP().Equal(b.entries[i].IP()) { + // Endpoint has changed, ensure that the new IP fits into table limits. + tab.removeIP(b, b.entries[i].IP()) + if !tab.addIP(b, n.IP()) { + // It doesn't, put the previous one back. + tab.addIP(b, b.entries[i].IP()) + return false + } + } + // Move it to the front. copy(b.entries[1:], b.entries[:i]) b.entries[0] = n return true @@ -671,29 +719,20 @@ func (b *bucket) bump(n *node) bool { return false } -// bumpOrAdd moves n to the front of the bucket entry list or adds it if the list isn't -// full. The return value is true if n is in the bucket. -func (tab *Table) bumpOrAdd(b *bucket, n *node) bool { - if b.bump(n) { - return true - } - if len(b.entries) >= bucketSize || !tab.addIP(b, n.IP()) { - return false - } - b.entries, _ = pushNode(b.entries, n, bucketSize) - b.replacements = deleteNode(b.replacements, n) - n.addedAt = time.Now() - if tab.nodeAddedHook != nil { - tab.nodeAddedHook(n) - } - return true -} - func (tab *Table) deleteInBucket(b *bucket, n *node) { b.entries = deleteNode(b.entries, n) tab.removeIP(b, n.IP()) } +func contains(ns []*node, id enode.ID) bool { + for _, n := range ns { + if n.ID() == id { + return true + } + } + return false +} + // pushNode adds n to the front of list, keeping at most max items. func pushNode(list []*node, n *node, max int) ([]*node, *node) { if len(list) < max { diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_test.go index 6b4cd2d1..233687d7 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/p2p/netutil" ) func TestTable_pingReplace(t *testing.T) { @@ -50,8 +51,8 @@ func TestTable_pingReplace(t *testing.T) { func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding bool) { transport := newPingRecorder() tab, db := newTestTable(transport) - defer tab.Close() defer db.Close() + defer tab.Close() <-tab.initDone @@ -64,7 +65,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding // its bucket if it is unresponsive. Revalidate again to ensure that transport.dead[last.ID()] = !lastInBucketIsResponding transport.dead[pingSender.ID()] = !newNodeIsResponding - tab.add(pingSender) + tab.addSeenNode(pingSender) tab.doRevalidate(make(chan struct{}, 1)) tab.doRevalidate(make(chan struct{}, 1)) @@ -114,10 +115,14 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { } prop := func(nodes []*node, bumps []int) (ok bool) { + tab, db := newTestTable(newPingRecorder()) + defer db.Close() + defer tab.Close() + b := &bucket{entries: make([]*node, len(nodes))} copy(b.entries, nodes) for i, pos := range bumps { - b.bump(b.entries[pos]) + tab.bumpInBucket(b, b.entries[pos]) if hasDuplicates(b.entries) { t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps)) for _, n := range b.entries { @@ -126,6 +131,7 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { return false } } + checkIPLimitInvariant(t, tab) return true } if err := quick.Check(prop, cfg); err != nil { @@ -137,33 +143,51 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { func TestTable_IPLimit(t *testing.T) { transport := newPingRecorder() tab, db := newTestTable(transport) - defer tab.Close() defer db.Close() + defer tab.Close() for i := 0; i < tableIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)}) - tab.add(n) + tab.addSeenNode(n) } if tab.len() > tableIPLimit { t.Errorf("too many nodes in table") } + checkIPLimitInvariant(t, tab) } // This checks that the per-bucket IP limit is applied correctly. func TestTable_BucketIPLimit(t *testing.T) { transport := newPingRecorder() tab, db := newTestTable(transport) - defer tab.Close() defer db.Close() + defer tab.Close() d := 3 for i := 0; i < bucketIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), d, net.IP{172, 0, 1, byte(i)}) - tab.add(n) + tab.addSeenNode(n) } if tab.len() > bucketIPLimit { t.Errorf("too many nodes in table") } + checkIPLimitInvariant(t, tab) +} + +// checkIPLimitInvariant checks that ip limit sets contain an entry for every +// node in the table and no extra entries. +func checkIPLimitInvariant(t *testing.T, tab *Table) { + t.Helper() + + tabset := netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit} + for _, b := range tab.buckets { + for _, n := range b.entries { + tabset.Add(n.IP()) + } + } + if tabset.String() != tab.ips.String() { + t.Errorf("table IP set is incorrect:\nhave: %v\nwant: %v", tab.ips, tabset) + } } func TestTable_closest(t *testing.T) { @@ -173,9 +197,9 @@ func TestTable_closest(t *testing.T) { // for any node table, Target and N transport := newPingRecorder() tab, db := newTestTable(transport) - defer tab.Close() defer db.Close() - tab.stuff(test.All) + defer tab.Close() + fillTable(tab, test.All) // check that closest(Target, N) returns nodes result := tab.closest(test.Target, test.N).entries @@ -234,13 +258,13 @@ func TestTable_ReadRandomNodesGetAll(t *testing.T) { test := func(buf []*enode.Node) bool { transport := newPingRecorder() tab, db := newTestTable(transport) - defer tab.Close() defer db.Close() + defer tab.Close() <-tab.initDone for i := 0; i < len(buf); i++ { ld := cfg.Rand.Intn(len(tab.buckets)) - tab.stuff([]*node{nodeAtDistance(tab.self().ID(), ld, intIP(ld))}) + fillTable(tab, []*node{nodeAtDistance(tab.self().ID(), ld, intIP(ld))}) } gotN := tab.ReadRandomNodes(buf) if gotN != tab.len() { @@ -272,16 +296,82 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { N: rand.Intn(bucketSize), } for _, id := range gen([]enode.ID{}, rand).([]enode.ID) { - n := enode.SignNull(new(enr.Record), id) - t.All = append(t.All, wrapNode(n)) + r := new(enr.Record) + r.Set(enr.IP(genIP(rand))) + n := wrapNode(enode.SignNull(r, id)) + n.livenessChecks = 1 + t.All = append(t.All, n) } return reflect.ValueOf(t) } +func TestTable_addVerifiedNode(t *testing.T) { + tab, db := newTestTable(newPingRecorder()) + <-tab.initDone + defer db.Close() + defer tab.Close() + + // Insert two nodes. + n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) + n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) + tab.addSeenNode(n1) + tab.addSeenNode(n2) + + // Verify bucket content: + bcontent := []*node{n1, n2} + if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { + t.Fatalf("wrong bucket content: %v", tab.bucket(n1.ID()).entries) + } + + // Add a changed version of n2. + newrec := n2.Record() + newrec.Set(enr.IP{99, 99, 99, 99}) + newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) + tab.addVerifiedNode(newn2) + + // Check that bucket is updated correctly. + newBcontent := []*node{newn2, n1} + if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, newBcontent) { + t.Fatalf("wrong bucket content after update: %v", tab.bucket(n1.ID()).entries) + } + checkIPLimitInvariant(t, tab) +} + +func TestTable_addSeenNode(t *testing.T) { + tab, db := newTestTable(newPingRecorder()) + <-tab.initDone + defer db.Close() + defer tab.Close() + + // Insert two nodes. + n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) + n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) + tab.addSeenNode(n1) + tab.addSeenNode(n2) + + // Verify bucket content: + bcontent := []*node{n1, n2} + if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { + t.Fatalf("wrong bucket content: %v", tab.bucket(n1.ID()).entries) + } + + // Add a changed version of n2. + newrec := n2.Record() + newrec.Set(enr.IP{99, 99, 99, 99}) + newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) + tab.addSeenNode(newn2) + + // Check that bucket content is unchanged. + if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { + t.Fatalf("wrong bucket content after update: %v", tab.bucket(n1.ID()).entries) + } + checkIPLimitInvariant(t, tab) +} + func TestTable_Lookup(t *testing.T) { tab, db := newTestTable(lookupTestnet) - defer tab.Close() defer db.Close() + defer tab.Close() // lookup on empty table returns no nodes if results := tab.lookup(lookupTestnet.target, false); len(results) > 0 { @@ -289,8 +379,9 @@ func TestTable_Lookup(t *testing.T) { } // seed table with initial node (otherwise lookup will terminate immediately) seedKey, _ := decodePubkey(lookupTestnet.dists[256][0]) - seed := wrapNode(enode.NewV4(seedKey, net.IP{}, 0, 256)) - tab.stuff([]*node{seed}) + seed := wrapNode(enode.NewV4(seedKey, net.IP{127, 0, 0, 1}, 0, 256)) + seed.livenessChecks = 1 + fillTable(tab, []*node{seed}) results := tab.lookup(lookupTestnet.target, true) t.Logf("results:") @@ -531,9 +622,10 @@ func (tn *preminedTestnet) findnode(toid enode.ID, toaddr *net.UDPAddr, target e } func (*preminedTestnet) close() {} -func (*preminedTestnet) waitping(from enode.ID) error { return nil } func (*preminedTestnet) ping(toid enode.ID, toaddr *net.UDPAddr) error { return nil } +var _ = (*preminedTestnet).mine // avoid linter warning about mine being dead code. + // mine generates a testnet struct literal with nodes at // various distances to the given target. func (tn *preminedTestnet) mine(target encPubkey) { @@ -578,6 +670,12 @@ func gen(typ interface{}, rand *rand.Rand) interface{} { return v.Interface() } +func genIP(rand *rand.Rand) net.IP { + ip := make(net.IP, 4) + rand.Read(ip) + return ip +} + func quickcfg() *quick.Config { return &quick.Config{ MaxCount: 5000, diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_util_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_util_test.go index d4151945..f4dbc25a 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_util_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discover/table_util_test.go @@ -17,7 +17,6 @@ package discover import ( - "crypto/ecdsa" "encoding/hex" "fmt" "math/rand" @@ -83,6 +82,14 @@ func fillBucket(tab *Table, n *node) (last *node) { return b.entries[bucketSize-1] } +// fillTable adds nodes the table to the end of their corresponding bucket +// if the bucket is not full. The caller must not hold tab.mutex. +func fillTable(tab *Table, nodes []*node) { + for _, n := range nodes { + tab.addSeenNode(n) + } +} + type pingRecorder struct { mu sync.Mutex dead, pinged map[enode.ID]bool @@ -109,10 +116,6 @@ func (t *pingRecorder) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPu return nil, nil } -func (t *pingRecorder) waitping(from enode.ID) error { - return nil // remote always pings -} - func (t *pingRecorder) ping(toid enode.ID, toaddr *net.UDPAddr) error { t.mu.Lock() defer t.mu.Unlock() @@ -141,15 +144,6 @@ func hasDuplicates(slice []*node) bool { return false } -func contains(ns []*node, id enode.ID) bool { - for _, n := range ns { - if n.ID() == id { - return true - } - } - return false -} - func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { var last enode.ID for i, e := range slice { @@ -172,11 +166,3 @@ func hexEncPubkey(h string) (ret encPubkey) { copy(ret[:], b) return ret } - -func hexPubkey(h string) *ecdsa.PublicKey { - k, err := decodePubkey(hexEncPubkey(h)) - if err != nil { - panic(err) - } - return k -} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp.go b/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp.go index 37a04490..e386af36 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp.go @@ -54,6 +54,11 @@ const ( ntpFailureThreshold = 32 // Continuous timeouts after which to check NTP ntpWarningCooldown = 10 * time.Minute // Minimum amount of time to pass before repeating NTP warning driftThreshold = 10 * time.Second // Allowed clock drift before warning user + + // Discovery packets are defined to be no larger than 1280 bytes. + // Packets larger than this size will be cut at the end and treated + // as invalid because their hash won't match. + maxPacketSize = 1280 ) // RPC packet types @@ -67,6 +72,8 @@ const ( // RPC request structures type ( ping struct { + senderKey *ecdsa.PublicKey // filled in by preverify + Version uint From, To rpcEndpoint Expiration uint64 @@ -155,8 +162,13 @@ func nodeToRPC(n *node) rpcNode { return rpcNode{ID: ekey, IP: n.IP(), UDP: uint16(n.UDP()), TCP: uint16(n.TCP())} } +// packet is implemented by all protocol messages. type packet interface { - handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error + // preverify checks whether the packet is valid and should be handled at all. + preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error + // handle handles the packet. + handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) + // name returns the name of the packet for logging purposes. name() string } @@ -177,43 +189,48 @@ type udp struct { tab *Table wg sync.WaitGroup - addpending chan *pending - gotreply chan reply - closing chan struct{} + addReplyMatcher chan *replyMatcher + gotreply chan reply + closing chan struct{} } // pending represents a pending reply. // -// some implementations of the protocol wish to send more than one -// reply packet to findnode. in general, any neighbors packet cannot +// Some implementations of the protocol wish to send more than one +// reply packet to findnode. In general, any neighbors packet cannot // be matched up with a specific findnode packet. // -// our implementation handles this by storing a callback function for -// each pending reply. incoming packets from a node are dispatched -// to all the callback functions for that node. -type pending struct { +// Our implementation handles this by storing a callback function for +// each pending reply. Incoming packets from a node are dispatched +// to all callback functions for that node. +type replyMatcher struct { // these fields must match in the reply. from enode.ID + ip net.IP ptype byte // time when the request must complete deadline time.Time - // callback is called when a matching reply arrives. if it returns - // true, the callback is removed from the pending reply queue. - // if it returns false, the reply is considered incomplete and - // the callback will be invoked again for the next matching reply. - callback func(resp interface{}) (done bool) + // callback is called when a matching reply arrives. If it returns matched == true, the + // reply was acceptable. The second return value indicates whether the callback should + // be removed from the pending reply queue. If it returns false, the reply is considered + // incomplete and the callback will be invoked again for the next matching reply. + callback replyMatchFunc // errc receives nil when the callback indicates completion or an // error if no further reply is received within the timeout. errc chan<- error } +type replyMatchFunc func(interface{}) (matched bool, requestDone bool) + type reply struct { from enode.ID + ip net.IP ptype byte - data interface{} + data packet + // loop indicates whether there was // a matching request by sending on this channel. matched chan<- bool @@ -247,14 +264,14 @@ func ListenUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, error) { func newUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, *udp, error) { udp := &udp{ - conn: c, - priv: cfg.PrivateKey, - netrestrict: cfg.NetRestrict, - localNode: ln, - db: ln.Database(), - closing: make(chan struct{}), - gotreply: make(chan reply), - addpending: make(chan *pending), + conn: c, + priv: cfg.PrivateKey, + netrestrict: cfg.NetRestrict, + localNode: ln, + db: ln.Database(), + closing: make(chan struct{}), + gotreply: make(chan reply), + addReplyMatcher: make(chan *replyMatcher), } tab, err := newTable(udp, ln.Database(), cfg.Bootnodes) if err != nil { @@ -304,35 +321,37 @@ func (t *udp) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) <-ch errc <- err return errc } - errc := t.pending(toid, pongPacket, func(p interface{}) bool { - ok := bytes.Equal(p.(*pong).ReplyTok, hash) - if ok && callback != nil { + // Add a matcher for the reply to the pending reply queue. Pongs are matched if they + // reference the ping we're about to send. + errc := t.pending(toid, toaddr.IP, pongPacket, func(p interface{}) (matched bool, requestDone bool) { + matched = bytes.Equal(p.(*pong).ReplyTok, hash) + if matched && callback != nil { callback() } - return ok + return matched, matched }) + // Send the packet. t.localNode.UDPContact(toaddr) - t.write(toaddr, req.name(), packet) + t.write(toaddr, toid, req.name(), packet) return errc } -func (t *udp) waitping(from enode.ID) error { - return <-t.pending(from, pingPacket, func(interface{}) bool { return true }) -} - // findnode sends a findnode request to the given node and waits until // the node has sent up to k neighbors. func (t *udp) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) { // If we haven't seen a ping from the destination node for a while, it won't remember // our endpoint proof and reject findnode. Solicit a ping first. - if time.Since(t.db.LastPingReceived(toid)) > bondExpiration { + if time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration { t.ping(toid, toaddr) - t.waitping(toid) + // Wait for them to ping back and process our pong. + time.Sleep(respTimeout) } + // Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is + // active until enough nodes have been received. nodes := make([]*node, 0, bucketSize) nreceived := 0 - errc := t.pending(toid, neighborsPacket, func(r interface{}) bool { + errc := t.pending(toid, toaddr.IP, neighborsPacket, func(r interface{}) (matched bool, requestDone bool) { reply := r.(*neighbors) for _, rn := range reply.Nodes { nreceived++ @@ -343,22 +362,22 @@ func (t *udp) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([] } nodes = append(nodes, n) } - return nreceived >= bucketSize + return true, nreceived >= bucketSize }) - t.send(toaddr, findnodePacket, &findnode{ + t.send(toaddr, toid, findnodePacket, &findnode{ Target: target, Expiration: uint64(time.Now().Add(expiration).Unix()), }) return nodes, <-errc } -// pending adds a reply callback to the pending reply queue. -// see the documentation of type pending for a detailed explanation. -func (t *udp) pending(id enode.ID, ptype byte, callback func(interface{}) bool) <-chan error { +// pending adds a reply matcher to the pending reply queue. +// see the documentation of type replyMatcher for a detailed explanation. +func (t *udp) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) <-chan error { ch := make(chan error, 1) - p := &pending{from: id, ptype: ptype, callback: callback, errc: ch} + p := &replyMatcher{from: id, ip: ip, ptype: ptype, callback: callback, errc: ch} select { - case t.addpending <- p: + case t.addReplyMatcher <- p: // loop will handle it case <-t.closing: ch <- errClosed @@ -366,10 +385,12 @@ func (t *udp) pending(id enode.ID, ptype byte, callback func(interface{}) bool) return ch } -func (t *udp) handleReply(from enode.ID, ptype byte, req packet) bool { +// handleReply dispatches a reply packet, invoking reply matchers. It returns +// whether any matcher considered the packet acceptable. +func (t *udp) handleReply(from enode.ID, fromIP net.IP, ptype byte, req packet) bool { matched := make(chan bool, 1) select { - case t.gotreply <- reply{from, ptype, req, matched}: + case t.gotreply <- reply{from, fromIP, ptype, req, matched}: // loop will handle it return <-matched case <-t.closing: @@ -385,8 +406,8 @@ func (t *udp) loop() { var ( plist = list.New() timeout = time.NewTimer(0) - nextTimeout *pending // head of plist when timeout was last reset - contTimeouts = 0 // number of continuous timeouts to do NTP checks + nextTimeout *replyMatcher // head of plist when timeout was last reset + contTimeouts = 0 // number of continuous timeouts to do NTP checks ntpWarnTime = time.Unix(0, 0) ) <-timeout.C // ignore first timeout @@ -399,7 +420,7 @@ func (t *udp) loop() { // Start the timer so it fires when the next pending reply has expired. now := time.Now() for el := plist.Front(); el != nil; el = el.Next() { - nextTimeout = el.Value.(*pending) + nextTimeout = el.Value.(*replyMatcher) if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout { timeout.Reset(dist) return @@ -420,25 +441,23 @@ func (t *udp) loop() { select { case <-t.closing: for el := plist.Front(); el != nil; el = el.Next() { - el.Value.(*pending).errc <- errClosed + el.Value.(*replyMatcher).errc <- errClosed } return - case p := <-t.addpending: + case p := <-t.addReplyMatcher: p.deadline = time.Now().Add(respTimeout) plist.PushBack(p) case r := <-t.gotreply: - var matched bool + var matched bool // whether any replyMatcher considered the reply acceptable. for el := plist.Front(); el != nil; el = el.Next() { - p := el.Value.(*pending) - if p.from == r.from && p.ptype == r.ptype { - matched = true - // Remove the matcher if its callback indicates - // that all replies have been received. This is - // required for packet types that expect multiple - // reply packets. - if p.callback(r.data) { + p := el.Value.(*replyMatcher) + if p.from == r.from && p.ptype == r.ptype && p.ip.Equal(r.ip) { + ok, requestDone := p.callback(r.data) + matched = matched || ok + // Remove the matcher if callback indicates that all replies have been received. + if requestDone { p.errc <- nil plist.Remove(el) } @@ -453,7 +472,7 @@ func (t *udp) loop() { // Notify and remove callbacks whose deadline is in the past. for el := plist.Front(); el != nil; el = el.Next() { - p := el.Value.(*pending) + p := el.Value.(*replyMatcher) if now.After(p.deadline) || now.Equal(p.deadline) { p.errc <- errTimeout plist.Remove(el) @@ -482,7 +501,7 @@ var ( headSpace = make([]byte, headSize) // Neighbors replies are sent across multiple packets to - // stay below the 1280 byte limit. We compute the maximum number + // stay below the packet size limit. We compute the maximum number // of entries by stuffing a packet until it grows too large. maxNeighbors int ) @@ -497,24 +516,24 @@ func init() { // If this ever happens, it will be caught by the unit tests. panic("cannot encode: " + err.Error()) } - if headSize+size+1 >= 1280 { + if headSize+size+1 >= maxPacketSize { maxNeighbors = n break } } } -func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) ([]byte, error) { +func (t *udp) send(toaddr *net.UDPAddr, toid enode.ID, ptype byte, req packet) ([]byte, error) { packet, hash, err := encodePacket(t.priv, ptype, req) if err != nil { return hash, err } - return hash, t.write(toaddr, req.name(), packet) + return hash, t.write(toaddr, toid, req.name(), packet) } -func (t *udp) write(toaddr *net.UDPAddr, what string, packet []byte) error { +func (t *udp) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error { _, err := t.conn.WriteToUDP(packet, toaddr) - log.Trace(">> "+what, "addr", toaddr, "err", err) + log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err) return err } @@ -548,10 +567,7 @@ func (t *udp) readLoop(unhandled chan<- ReadPacket) { defer close(unhandled) } - // Discovery packets are defined to be no larger than 1280 bytes. - // Packets larger than this size will be cut at the end and treated - // as invalid because their hash won't match. - buf := make([]byte, 1280) + buf := make([]byte, maxPacketSize) for { nbytes, from, err := t.conn.ReadFromUDP(buf) if netutil.IsTemporaryError(err) { @@ -573,13 +589,19 @@ func (t *udp) readLoop(unhandled chan<- ReadPacket) { } func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { - packet, fromID, hash, err := decodePacket(buf) + packet, fromKey, hash, err := decodePacket(buf) if err != nil { log.Debug("Bad discv4 packet", "addr", from, "err", err) return err } - err = packet.handle(t, from, fromID, hash) - log.Trace("<< "+packet.name(), "addr", from, "err", err) + fromID := fromKey.id() + if err == nil { + err = packet.preverify(t, from, fromID, fromKey) + } + log.Trace("<< "+packet.name(), "id", fromID, "addr", from, "err", err) + if err == nil { + packet.handle(t, from, fromID, hash) + } return err } @@ -615,54 +637,67 @@ func decodePacket(buf []byte) (packet, encPubkey, []byte, error) { return req, fromKey, hash, err } -func (req *ping) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error { +// Packet Handlers + +func (req *ping) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error { if expired(req.Expiration) { return errExpired } key, err := decodePubkey(fromKey) if err != nil { - return fmt.Errorf("invalid public key: %v", err) + return errors.New("invalid public key") } - t.send(from, pongPacket, &pong{ + req.senderKey = key + return nil +} + +func (req *ping) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) { + // Reply. + t.send(from, fromID, pongPacket, &pong{ To: makeEndpoint(from, req.From.TCP), ReplyTok: mac, Expiration: uint64(time.Now().Add(expiration).Unix()), }) - n := wrapNode(enode.NewV4(key, from.IP, int(req.From.TCP), from.Port)) - t.handleReply(n.ID(), pingPacket, req) - if time.Since(t.db.LastPongReceived(n.ID())) > bondExpiration { - t.sendPing(n.ID(), from, func() { t.tab.addThroughPing(n) }) + + // Ping back if our last pong on file is too far in the past. + n := wrapNode(enode.NewV4(req.senderKey, from.IP, int(req.From.TCP), from.Port)) + if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { + t.sendPing(fromID, from, func() { + t.tab.addVerifiedNode(n) + }) } else { - t.tab.addThroughPing(n) + t.tab.addVerifiedNode(n) } + + // Update node database and endpoint predictor. + t.db.UpdateLastPingReceived(n.ID(), from.IP, time.Now()) t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) - t.db.UpdateLastPingReceived(n.ID(), time.Now()) - return nil } func (req *ping) name() string { return "PING/v4" } -func (req *pong) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error { +func (req *pong) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error { if expired(req.Expiration) { return errExpired } - fromID := fromKey.id() - if !t.handleReply(fromID, pongPacket, req) { + if !t.handleReply(fromID, from.IP, pongPacket, req) { return errUnsolicitedReply } - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) - t.db.UpdateLastPongReceived(fromID, time.Now()) return nil } +func (req *pong) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) { + t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) + t.db.UpdateLastPongReceived(fromID, from.IP, time.Now()) +} + func (req *pong) name() string { return "PONG/v4" } -func (req *findnode) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error { +func (req *findnode) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error { if expired(req.Expiration) { return errExpired } - fromID := fromKey.id() - if time.Since(t.db.LastPongReceived(fromID)) > bondExpiration { + if time.Since(t.db.LastPongReceived(fromID, from.IP)) > bondExpiration { // No endpoint proof pong exists, we don't process the packet. This prevents an // attack vector where the discovery protocol could be used to amplify traffic in a // DDOS attack. A malicious actor would send a findnode request with the IP address @@ -671,43 +706,50 @@ func (req *findnode) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac [] // findnode) to the victim. return errUnknownNode } + return nil +} + +func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) { + // Determine closest nodes. target := enode.ID(crypto.Keccak256Hash(req.Target[:])) t.tab.mutex.Lock() closest := t.tab.closest(target, bucketSize).entries t.tab.mutex.Unlock() + // Send neighbors in chunks with at most maxNeighbors per packet + // to stay below the packet size limit. p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool - // Send neighbors in chunks with at most maxNeighbors per packet - // to stay below the 1280 byte limit. for _, n := range closest { if netutil.CheckRelayIP(from.IP, n.IP()) == nil { p.Nodes = append(p.Nodes, nodeToRPC(n)) } if len(p.Nodes) == maxNeighbors { - t.send(from, neighborsPacket, &p) + t.send(from, fromID, neighborsPacket, &p) p.Nodes = p.Nodes[:0] sent = true } } if len(p.Nodes) > 0 || !sent { - t.send(from, neighborsPacket, &p) + t.send(from, fromID, neighborsPacket, &p) } - return nil } func (req *findnode) name() string { return "FINDNODE/v4" } -func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte) error { +func (req *neighbors) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error { if expired(req.Expiration) { return errExpired } - if !t.handleReply(fromKey.id(), neighborsPacket, req) { + if !t.handleReply(fromID, from.IP, neighborsPacket, req) { return errUnsolicitedReply } return nil } +func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) { +} + func (req *neighbors) name() string { return "NEIGHBORS/v4" } func expired(ts uint64) bool { diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp_test.go index a4ddaf75..3d53c930 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discover/udp_test.go @@ -19,6 +19,7 @@ package discover import ( "bytes" "crypto/ecdsa" + crand "crypto/rand" "encoding/binary" "encoding/hex" "errors" @@ -57,6 +58,7 @@ type udpTest struct { t *testing.T pipe *dgramPipe table *Table + db *enode.DB udp *udp sent [][]byte localkey, remotekey *ecdsa.PrivateKey @@ -71,22 +73,32 @@ func newUDPTest(t *testing.T) *udpTest { remotekey: newkey(), remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303}, } - db, _ := enode.OpenDB("") - ln := enode.NewLocalNode(db, test.localkey) + test.db, _ = enode.OpenDB("") + ln := enode.NewLocalNode(test.db, test.localkey) test.table, test.udp, _ = newUDP(test.pipe, ln, Config{PrivateKey: test.localkey}) // Wait for initial refresh so the table doesn't send unexpected findnode. <-test.table.initDone return test } +func (test *udpTest) close() { + test.table.Close() + test.db.Close() +} + // handles a packet as if it had been sent to the transport. func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error { - enc, _, err := encodePacket(test.remotekey, ptype, data) + return test.packetInFrom(wantError, test.remotekey, test.remoteaddr, ptype, data) +} + +// handles a packet as if it had been sent to the transport by the key/endpoint. +func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr *net.UDPAddr, ptype byte, data packet) error { + enc, _, err := encodePacket(key, ptype, data) if err != nil { return test.errorf("packet (%d) encode error: %v", ptype, err) } test.sent = append(test.sent, enc) - if err = test.udp.handlePacket(test.remoteaddr, enc); err != wantError { + if err = test.udp.handlePacket(addr, enc); err != wantError { return test.errorf("error mismatch: got %q, want %q", err, wantError) } return nil @@ -94,19 +106,19 @@ func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error { // waits for a packet to be sent by the transport. // validate should have type func(*udpTest, X) error, where X is a packet type. -func (test *udpTest) waitPacketOut(validate interface{}) ([]byte, error) { +func (test *udpTest) waitPacketOut(validate interface{}) (*net.UDPAddr, []byte, error) { dgram := test.pipe.waitPacketOut() - p, _, hash, err := decodePacket(dgram) + p, _, hash, err := decodePacket(dgram.data) if err != nil { - return hash, test.errorf("sent packet decode error: %v", err) + return &dgram.to, hash, test.errorf("sent packet decode error: %v", err) } fn := reflect.ValueOf(validate) exptype := fn.Type().In(0) if reflect.TypeOf(p) != exptype { - return hash, test.errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype) + return &dgram.to, hash, test.errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype) } fn.Call([]reflect.Value{reflect.ValueOf(p)}) - return hash, nil + return &dgram.to, hash, nil } func (test *udpTest) errorf(format string, args ...interface{}) error { @@ -125,7 +137,7 @@ func (test *udpTest) errorf(format string, args ...interface{}) error { func TestUDP_packetErrors(t *testing.T) { test := newUDPTest(t) - defer test.table.Close() + defer test.close() test.packetIn(errExpired, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 4}) test.packetIn(errUnsolicitedReply, pongPacket, &pong{ReplyTok: []byte{}, Expiration: futureExp}) @@ -136,7 +148,7 @@ func TestUDP_packetErrors(t *testing.T) { func TestUDP_pingTimeout(t *testing.T) { t.Parallel() test := newUDPTest(t) - defer test.table.Close() + defer test.close() toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222} toid := enode.ID{1, 2, 3, 4} @@ -148,7 +160,7 @@ func TestUDP_pingTimeout(t *testing.T) { func TestUDP_responseTimeouts(t *testing.T) { t.Parallel() test := newUDPTest(t) - defer test.table.Close() + defer test.close() rand.Seed(time.Now().UnixNano()) randomDuration := func(max time.Duration) time.Duration { @@ -166,20 +178,20 @@ func TestUDP_responseTimeouts(t *testing.T) { // with ptype <= 128 will not get a reply and should time out. // For all other requests, a reply is scheduled to arrive // within the timeout window. - p := &pending{ + p := &replyMatcher{ ptype: byte(rand.Intn(255)), - callback: func(interface{}) bool { return true }, + callback: func(interface{}) (bool, bool) { return true, true }, } binary.BigEndian.PutUint64(p.from[:], uint64(i)) if p.ptype <= 128 { p.errc = timeoutErr - test.udp.addpending <- p + test.udp.addReplyMatcher <- p nTimeouts++ } else { p.errc = nilErr - test.udp.addpending <- p + test.udp.addReplyMatcher <- p time.AfterFunc(randomDuration(60*time.Millisecond), func() { - if !test.udp.handleReply(p.from, p.ptype, nil) { + if !test.udp.handleReply(p.from, p.ip, p.ptype, nil) { t.Logf("not matched: %v", p) } }) @@ -220,7 +232,7 @@ func TestUDP_responseTimeouts(t *testing.T) { func TestUDP_findnodeTimeout(t *testing.T) { t.Parallel() test := newUDPTest(t) - defer test.table.Close() + defer test.close() toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222} toid := enode.ID{1, 2, 3, 4} @@ -236,50 +248,65 @@ func TestUDP_findnodeTimeout(t *testing.T) { func TestUDP_findnode(t *testing.T) { test := newUDPTest(t) - defer test.table.Close() + defer test.close() // put a few nodes into the table. their exact // distribution shouldn't matter much, although we need to // take care not to overflow any bucket. nodes := &nodesByDistance{target: testTarget.id()} - for i := 0; i < bucketSize; i++ { + live := make(map[enode.ID]bool) + numCandidates := 2 * bucketSize + for i := 0; i < numCandidates; i++ { key := newkey() - n := wrapNode(enode.NewV4(&key.PublicKey, net.IP{10, 13, 0, 1}, 0, i)) - nodes.push(n, bucketSize) + ip := net.IP{10, 13, 0, byte(i)} + n := wrapNode(enode.NewV4(&key.PublicKey, ip, 0, 2000)) + // Ensure half of table content isn't verified live yet. + if i > numCandidates/2 { + n.livenessChecks = 1 + live[n.ID()] = true + } + nodes.push(n, numCandidates) } - test.table.stuff(nodes.entries) + fillTable(test.table, nodes.entries) // ensure there's a bond with the test node, // findnode won't be accepted otherwise. remoteID := encodePubkey(&test.remotekey.PublicKey).id() - test.table.db.UpdateLastPongReceived(remoteID, time.Now()) + test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.IP, time.Now()) // check that closest neighbors are returned. - test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp}) expected := test.table.closest(testTarget.id(), bucketSize) - + test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp}) waitNeighbors := func(want []*node) { test.waitPacketOut(func(p *neighbors) { if len(p.Nodes) != len(want) { t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), bucketSize) } - for i := range p.Nodes { - if p.Nodes[i].ID.id() != want[i].ID() { - t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, p.Nodes[i], expected.entries[i]) + for i, n := range p.Nodes { + if n.ID.id() != want[i].ID() { + t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, n, expected.entries[i]) + } + if !live[n.ID.id()] { + t.Errorf("result includes dead node %v", n.ID.id()) } } }) } - waitNeighbors(expected.entries[:maxNeighbors]) - waitNeighbors(expected.entries[maxNeighbors:]) + // Receive replies. + want := expected.entries + if len(want) > maxNeighbors { + waitNeighbors(want[:maxNeighbors]) + want = want[maxNeighbors:] + } + waitNeighbors(want) } func TestUDP_findnodeMultiReply(t *testing.T) { test := newUDPTest(t) - defer test.table.Close() + defer test.close() rid := enode.PubkeyToIDV4(&test.remotekey.PublicKey) - test.table.db.UpdateLastPingReceived(rid, time.Now()) + test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.IP, time.Now()) // queue a pending findnode request resultc, errc := make(chan []*node), make(chan error) @@ -329,11 +356,40 @@ func TestUDP_findnodeMultiReply(t *testing.T) { } } +func TestUDP_pingMatch(t *testing.T) { + test := newUDPTest(t) + defer test.close() + + randToken := make([]byte, 32) + crand.Read(randToken) + + test.packetIn(nil, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) + test.waitPacketOut(func(*pong) error { return nil }) + test.waitPacketOut(func(*ping) error { return nil }) + test.packetIn(errUnsolicitedReply, pongPacket, &pong{ReplyTok: randToken, To: testLocalAnnounced, Expiration: futureExp}) +} + +func TestUDP_pingMatchIP(t *testing.T) { + test := newUDPTest(t) + defer test.close() + + test.packetIn(nil, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) + test.waitPacketOut(func(*pong) error { return nil }) + + _, hash, _ := test.waitPacketOut(func(*ping) error { return nil }) + wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 1, 2}, Port: 30000} + test.packetInFrom(errUnsolicitedReply, test.remotekey, wrongAddr, pongPacket, &pong{ + ReplyTok: hash, + To: testLocalAnnounced, + Expiration: futureExp, + }) +} + func TestUDP_successfulPing(t *testing.T) { test := newUDPTest(t) added := make(chan *node, 1) test.table.nodeAddedHook = func(n *node) { added <- n } - defer test.table.Close() + defer test.close() // The remote side sends a ping packet to initiate the exchange. go test.packetIn(nil, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) @@ -356,7 +412,7 @@ func TestUDP_successfulPing(t *testing.T) { }) // remote is unknown, the table pings back. - hash, _ := test.waitPacketOut(func(p *ping) error { + _, hash, _ := test.waitPacketOut(func(p *ping) error { if !reflect.DeepEqual(p.From, test.udp.ourEndpoint()) { t.Errorf("got ping.From %#v, want %#v", p.From, test.udp.ourEndpoint()) } @@ -510,7 +566,12 @@ type dgramPipe struct { cond *sync.Cond closing chan struct{} closed bool - queue [][]byte + queue []dgram +} + +type dgram struct { + to net.UDPAddr + data []byte } func newpipe() *dgramPipe { @@ -531,7 +592,7 @@ func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) { if c.closed { return 0, errors.New("closed") } - c.queue = append(c.queue, msg) + c.queue = append(c.queue, dgram{*to, b}) c.cond.Signal() return len(b), nil } @@ -556,7 +617,7 @@ func (c *dgramPipe) LocalAddr() net.Addr { return &net.UDPAddr{IP: testLocal.IP, Port: int(testLocal.UDP)} } -func (c *dgramPipe) waitPacketOut() []byte { +func (c *dgramPipe) waitPacketOut() dgram { c.mu.Lock() defer c.mu.Unlock() for len(c.queue) == 0 { diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/discv5/net.go b/vendor/github.com/ethereum/go-ethereum/p2p/discv5/net.go index a6cabf08..de7d8de6 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/discv5/net.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/discv5/net.go @@ -27,10 +27,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) var ( @@ -567,12 +567,11 @@ loop: net.ticketStore.searchLookupDone(res.target, res.nodes, func(n *Node, topic Topic) []byte { if n.state != nil && n.state.canQuery { return net.conn.send(n, topicQueryPacket, topicQuery{Topic: topic}) // TODO: set expiration - } else { - if n.state == unknown { - net.ping(n, n.addr()) - } - return nil } + if n.state == unknown { + net.ping(n, n.addr()) + } + return nil }) case <-statsDump.C: @@ -801,7 +800,7 @@ func (n *nodeNetGuts) startNextQuery(net *Network) { func (q *findnodeQuery) start(net *Network) bool { // Satisfy queries against the local node directly. if q.remote == net.tab.self { - closest := net.tab.closest(crypto.Keccak256Hash(q.target[:]), bucketSize) + closest := net.tab.closest(q.target, bucketSize) q.reply <- closest.entries return true } @@ -1235,7 +1234,7 @@ func (net *Network) checkTopicRegister(data *topicRegister) (*pong, error) { } func rlpHash(x interface{}) (h common.Hash) { - hw := sha3.NewKeccak256() + hw := sha3.NewLegacyKeccak256() rlp.Encode(hw, x) hw.Sum(h[:0]) return h diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/enode/idscheme.go b/vendor/github.com/ethereum/go-ethereum/p2p/enode/idscheme.go index 9b495fd4..c1834f06 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/enode/idscheme.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/enode/idscheme.go @@ -23,9 +23,9 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) // List of known secure identity schemes. @@ -48,7 +48,7 @@ func SignV4(r *enr.Record, privkey *ecdsa.PrivateKey) error { cpy.Set(enr.ID("v4")) cpy.Set(Secp256k1(privkey.PublicKey)) - h := sha3.NewKeccak256() + h := sha3.NewLegacyKeccak256() rlp.Encode(h, cpy.AppendElements(nil)) sig, err := crypto.Sign(h.Sum(nil), privkey) if err != nil { @@ -69,7 +69,7 @@ func (V4ID) Verify(r *enr.Record, sig []byte) error { return fmt.Errorf("invalid public key") } - h := sha3.NewKeccak256() + h := sha3.NewLegacyKeccak256() rlp.Encode(h, r.AppendElements(nil)) if !crypto.VerifySignature(entry, h.Sum(nil), sig) { return enr.ErrInvalidSig diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb.go b/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb.go index 7ee0c09a..a43e6386 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb.go @@ -21,11 +21,11 @@ import ( "crypto/rand" "encoding/binary" "fmt" + "net" "os" "sync" "time" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" @@ -37,24 +37,31 @@ import ( // Keys in the node database. const ( - dbVersionKey = "version" // Version of the database to flush if changes - dbItemPrefix = "n:" // Identifier to prefix node entries with + dbVersionKey = "version" // Version of the database to flush if changes + dbNodePrefix = "n:" // Identifier to prefix node entries with + dbLocalPrefix = "local:" + dbDiscoverRoot = "v4" - dbDiscoverRoot = ":discover" - dbDiscoverSeq = dbDiscoverRoot + ":seq" - dbDiscoverPing = dbDiscoverRoot + ":lastping" - dbDiscoverPong = dbDiscoverRoot + ":lastpong" - dbDiscoverFindFails = dbDiscoverRoot + ":findfail" - dbLocalRoot = ":local" - dbLocalSeq = dbLocalRoot + ":seq" + // These fields are stored per ID and IP, the full key is "n::v4::findfail". + // Use nodeItemKey to create those keys. + dbNodeFindFails = "findfail" + dbNodePing = "lastping" + dbNodePong = "lastpong" + dbNodeSeq = "seq" + + // Local information is keyed by ID only, the full key is "local::seq". + // Use localItemKey to create those keys. + dbLocalSeq = "seq" ) -var ( +const ( dbNodeExpiration = 24 * time.Hour // Time after which an unseen node should be dropped. dbCleanupCycle = time.Hour // Time period for running the expiration task. - dbVersion = 7 + dbVersion = 9 ) +var zeroIP = make(net.IP, 16) + // DB is the node database, storing previously seen nodes and any collected metadata about // them for QoS purposes. type DB struct { @@ -119,27 +126,58 @@ func newPersistentDB(path string) (*DB, error) { return &DB{lvl: db, quit: make(chan struct{})}, nil } -// makeKey generates the leveldb key-blob from a node id and its particular -// field of interest. -func makeKey(id ID, field string) []byte { - if (id == ID{}) { - return []byte(field) - } - return append([]byte(dbItemPrefix), append(id[:], field...)...) +// nodeKey returns the database key for a node record. +func nodeKey(id ID) []byte { + key := append([]byte(dbNodePrefix), id[:]...) + key = append(key, ':') + key = append(key, dbDiscoverRoot...) + return key } -// splitKey tries to split a database key into a node id and a field part. -func splitKey(key []byte) (id ID, field string) { - // If the key is not of a node, return it plainly - if !bytes.HasPrefix(key, []byte(dbItemPrefix)) { - return ID{}, string(key) +// splitNodeKey returns the node ID of a key created by nodeKey. +func splitNodeKey(key []byte) (id ID, rest []byte) { + if !bytes.HasPrefix(key, []byte(dbNodePrefix)) { + return ID{}, nil } - // Otherwise split the id and field - item := key[len(dbItemPrefix):] + item := key[len(dbNodePrefix):] copy(id[:], item[:len(id)]) - field = string(item[len(id):]) + return id, item[len(id)+1:] +} - return id, field +// nodeItemKey returns the database key for a node metadata field. +func nodeItemKey(id ID, ip net.IP, field string) []byte { + ip16 := ip.To16() + if ip16 == nil { + panic(fmt.Errorf("invalid IP (length %d)", len(ip))) + } + return bytes.Join([][]byte{nodeKey(id), ip16, []byte(field)}, []byte{':'}) +} + +// splitNodeItemKey returns the components of a key created by nodeItemKey. +func splitNodeItemKey(key []byte) (id ID, ip net.IP, field string) { + id, key = splitNodeKey(key) + // Skip discover root. + if string(key) == dbDiscoverRoot { + return id, nil, "" + } + key = key[len(dbDiscoverRoot)+1:] + // Split out the IP. + ip = net.IP(key[:16]) + if ip4 := ip.To4(); ip4 != nil { + ip = ip4 + } + key = key[16+1:] + // Field is the remainder of key. + field = string(key) + return id, ip, field +} + +// localItemKey returns the key of a local node item. +func localItemKey(id ID, field string) []byte { + key := append([]byte(dbLocalPrefix), id[:]...) + key = append(key, ':') + key = append(key, field...) + return key } // fetchInt64 retrieves an integer associated with a particular key. @@ -181,7 +219,7 @@ func (db *DB) storeUint64(key []byte, n uint64) error { // Node retrieves a node with a given id from the database. func (db *DB) Node(id ID) *Node { - blob, err := db.lvl.Get(makeKey(id, dbDiscoverRoot), nil) + blob, err := db.lvl.Get(nodeKey(id), nil) if err != nil { return nil } @@ -207,15 +245,15 @@ func (db *DB) UpdateNode(node *Node) error { if err != nil { return err } - if err := db.lvl.Put(makeKey(node.ID(), dbDiscoverRoot), blob, nil); err != nil { + if err := db.lvl.Put(nodeKey(node.ID()), blob, nil); err != nil { return err } - return db.storeUint64(makeKey(node.ID(), dbDiscoverSeq), node.Seq()) + return db.storeUint64(nodeItemKey(node.ID(), zeroIP, dbNodeSeq), node.Seq()) } // NodeSeq returns the stored record sequence number of the given node. func (db *DB) NodeSeq(id ID) uint64 { - return db.fetchUint64(makeKey(id, dbDiscoverSeq)) + return db.fetchUint64(nodeItemKey(id, zeroIP, dbNodeSeq)) } // Resolve returns the stored record of the node if it has a larger sequence @@ -227,15 +265,17 @@ func (db *DB) Resolve(n *Node) *Node { return db.Node(n.ID()) } -// DeleteNode deletes all information/keys associated with a node. -func (db *DB) DeleteNode(id ID) error { - deleter := db.lvl.NewIterator(util.BytesPrefix(makeKey(id, "")), nil) - for deleter.Next() { - if err := db.lvl.Delete(deleter.Key(), nil); err != nil { - return err - } +// DeleteNode deletes all information associated with a node. +func (db *DB) DeleteNode(id ID) { + deleteRange(db.lvl, nodeKey(id)) +} + +func deleteRange(db *leveldb.DB, prefix []byte) { + it := db.NewIterator(util.BytesPrefix(prefix), nil) + defer it.Release() + for it.Next() { + db.Delete(it.Key(), nil) } - return nil } // ensureExpirer is a small helper method ensuring that the data expiration @@ -259,9 +299,7 @@ func (db *DB) expirer() { for { select { case <-tick.C: - if err := db.expireNodes(); err != nil { - log.Error("Failed to expire nodedb items", "err", err) - } + db.expireNodes() case <-db.quit: return } @@ -269,71 +307,85 @@ func (db *DB) expirer() { } // expireNodes iterates over the database and deletes all nodes that have not -// been seen (i.e. received a pong from) for some allotted time. -func (db *DB) expireNodes() error { - threshold := time.Now().Add(-dbNodeExpiration) - - // Find discovered nodes that are older than the allowance - it := db.lvl.NewIterator(nil, nil) +// been seen (i.e. received a pong from) for some time. +func (db *DB) expireNodes() { + it := db.lvl.NewIterator(util.BytesPrefix([]byte(dbNodePrefix)), nil) defer it.Release() - - for it.Next() { - // Skip the item if not a discovery node - id, field := splitKey(it.Key()) - if field != dbDiscoverRoot { - continue - } - // Skip the node if not expired yet (and not self) - if seen := db.LastPongReceived(id); seen.After(threshold) { - continue - } - // Otherwise delete all associated information - db.DeleteNode(id) + if !it.Next() { + return + } + + var ( + threshold = time.Now().Add(-dbNodeExpiration).Unix() + youngestPong int64 + atEnd = false + ) + for !atEnd { + id, ip, field := splitNodeItemKey(it.Key()) + if field == dbNodePong { + time, _ := binary.Varint(it.Value()) + if time > youngestPong { + youngestPong = time + } + if time < threshold { + // Last pong from this IP older than threshold, remove fields belonging to it. + deleteRange(db.lvl, nodeItemKey(id, ip, "")) + } + } + atEnd = !it.Next() + nextID, _ := splitNodeKey(it.Key()) + if atEnd || nextID != id { + // We've moved beyond the last entry of the current ID. + // Remove everything if there was no recent enough pong. + if youngestPong > 0 && youngestPong < threshold { + deleteRange(db.lvl, nodeKey(id)) + } + youngestPong = 0 + } } - return nil } // LastPingReceived retrieves the time of the last ping packet received from // a remote node. -func (db *DB) LastPingReceived(id ID) time.Time { - return time.Unix(db.fetchInt64(makeKey(id, dbDiscoverPing)), 0) +func (db *DB) LastPingReceived(id ID, ip net.IP) time.Time { + return time.Unix(db.fetchInt64(nodeItemKey(id, ip, dbNodePing)), 0) } // UpdateLastPingReceived updates the last time we tried contacting a remote node. -func (db *DB) UpdateLastPingReceived(id ID, instance time.Time) error { - return db.storeInt64(makeKey(id, dbDiscoverPing), instance.Unix()) +func (db *DB) UpdateLastPingReceived(id ID, ip net.IP, instance time.Time) error { + return db.storeInt64(nodeItemKey(id, ip, dbNodePing), instance.Unix()) } // LastPongReceived retrieves the time of the last successful pong from remote node. -func (db *DB) LastPongReceived(id ID) time.Time { +func (db *DB) LastPongReceived(id ID, ip net.IP) time.Time { // Launch expirer db.ensureExpirer() - return time.Unix(db.fetchInt64(makeKey(id, dbDiscoverPong)), 0) + return time.Unix(db.fetchInt64(nodeItemKey(id, ip, dbNodePong)), 0) } // UpdateLastPongReceived updates the last pong time of a node. -func (db *DB) UpdateLastPongReceived(id ID, instance time.Time) error { - return db.storeInt64(makeKey(id, dbDiscoverPong), instance.Unix()) +func (db *DB) UpdateLastPongReceived(id ID, ip net.IP, instance time.Time) error { + return db.storeInt64(nodeItemKey(id, ip, dbNodePong), instance.Unix()) } // FindFails retrieves the number of findnode failures since bonding. -func (db *DB) FindFails(id ID) int { - return int(db.fetchInt64(makeKey(id, dbDiscoverFindFails))) +func (db *DB) FindFails(id ID, ip net.IP) int { + return int(db.fetchInt64(nodeItemKey(id, ip, dbNodeFindFails))) } // UpdateFindFails updates the number of findnode failures since bonding. -func (db *DB) UpdateFindFails(id ID, fails int) error { - return db.storeInt64(makeKey(id, dbDiscoverFindFails), int64(fails)) +func (db *DB) UpdateFindFails(id ID, ip net.IP, fails int) error { + return db.storeInt64(nodeItemKey(id, ip, dbNodeFindFails), int64(fails)) } // LocalSeq retrieves the local record sequence counter. func (db *DB) localSeq(id ID) uint64 { - return db.fetchUint64(makeKey(id, dbLocalSeq)) + return db.fetchUint64(localItemKey(id, dbLocalSeq)) } // storeLocalSeq stores the local record sequence counter. func (db *DB) storeLocalSeq(id ID, n uint64) { - db.storeUint64(makeKey(id, dbLocalSeq), n) + db.storeUint64(localItemKey(id, dbLocalSeq), n) } // QuerySeeds retrieves random nodes to be used as potential seed nodes @@ -355,14 +407,14 @@ seek: ctr := id[0] rand.Read(id[:]) id[0] = ctr + id[0]%16 - it.Seek(makeKey(id, dbDiscoverRoot)) + it.Seek(nodeKey(id)) n := nextNode(it) if n == nil { id[0] = 0 continue seek // iterator exhausted } - if now.Sub(db.LastPongReceived(n.ID())) > maxAge { + if now.Sub(db.LastPongReceived(n.ID(), n.IP())) > maxAge { continue seek } for i := range nodes { @@ -379,8 +431,8 @@ seek: // database entries. func nextNode(it iterator.Iterator) *Node { for end := false; !end; end = !it.Next() { - id, field := splitKey(it.Key()) - if field != dbDiscoverRoot { + id, rest := splitNodeKey(it.Key()) + if string(rest) != dbDiscoverRoot { continue } return mustDecodeNode(id[:], it.Value()) diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb_test.go index 96794827..21283524 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/enode/nodedb_test.go @@ -28,42 +28,54 @@ import ( "time" ) -var nodeDBKeyTests = []struct { - id ID - field string - key []byte -}{ - { - id: ID{}, - field: "version", - key: []byte{0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e}, // field - }, - { - id: HexID("51232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - field: ":discover", - key: []byte{ - 0x6e, 0x3a, // prefix - 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // node id - 0x2b, 0x29, 0xb5, 0x4b, 0x81, 0xcd, 0xef, 0xb9, // - 0xb3, 0xe9, 0xc3, 0x7d, 0x7f, 0xd5, 0xf6, 0x32, // - 0x70, 0xbc, 0xc9, 0xe1, 0xa6, 0xf6, 0xa4, 0x39, // - 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, // field - }, - }, +var keytestID = HexID("51232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") + +func TestDBNodeKey(t *testing.T) { + enc := nodeKey(keytestID) + want := []byte{ + 'n', ':', + 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // node id + 0x2b, 0x29, 0xb5, 0x4b, 0x81, 0xcd, 0xef, 0xb9, // + 0xb3, 0xe9, 0xc3, 0x7d, 0x7f, 0xd5, 0xf6, 0x32, // + 0x70, 0xbc, 0xc9, 0xe1, 0xa6, 0xf6, 0xa4, 0x39, // + ':', 'v', '4', + } + if !bytes.Equal(enc, want) { + t.Errorf("wrong encoded key:\ngot %q\nwant %q", enc, want) + } + id, _ := splitNodeKey(enc) + if id != keytestID { + t.Errorf("wrong ID from splitNodeKey") + } } -func TestDBKeys(t *testing.T) { - for i, tt := range nodeDBKeyTests { - if key := makeKey(tt.id, tt.field); !bytes.Equal(key, tt.key) { - t.Errorf("make test %d: key mismatch: have 0x%x, want 0x%x", i, key, tt.key) - } - id, field := splitKey(tt.key) - if !bytes.Equal(id[:], tt.id[:]) { - t.Errorf("split test %d: id mismatch: have 0x%x, want 0x%x", i, id, tt.id) - } - if field != tt.field { - t.Errorf("split test %d: field mismatch: have 0x%x, want 0x%x", i, field, tt.field) - } +func TestDBNodeItemKey(t *testing.T) { + wantIP := net.IP{127, 0, 0, 3} + wantField := "foobar" + enc := nodeItemKey(keytestID, wantIP, wantField) + want := []byte{ + 'n', ':', + 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // node id + 0x2b, 0x29, 0xb5, 0x4b, 0x81, 0xcd, 0xef, 0xb9, // + 0xb3, 0xe9, 0xc3, 0x7d, 0x7f, 0xd5, 0xf6, 0x32, // + 0x70, 0xbc, 0xc9, 0xe1, 0xa6, 0xf6, 0xa4, 0x39, // + ':', 'v', '4', ':', + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IP + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x03, // + ':', 'f', 'o', 'o', 'b', 'a', 'r', + } + if !bytes.Equal(enc, want) { + t.Errorf("wrong encoded key:\ngot %q\nwant %q", enc, want) + } + id, ip, field := splitNodeItemKey(enc) + if id != keytestID { + t.Errorf("splitNodeItemKey returned wrong ID: %v", id) + } + if !ip.Equal(wantIP) { + t.Errorf("splitNodeItemKey returned wrong IP: %v", ip) + } + if field != wantField { + t.Errorf("splitNodeItemKey returned wrong field: %q", field) } } @@ -113,33 +125,33 @@ func TestDBFetchStore(t *testing.T) { defer db.Close() // Check fetch/store operations on a node ping object - if stored := db.LastPingReceived(node.ID()); stored.Unix() != 0 { + if stored := db.LastPingReceived(node.ID(), node.IP()); stored.Unix() != 0 { t.Errorf("ping: non-existing object: %v", stored) } - if err := db.UpdateLastPingReceived(node.ID(), inst); err != nil { + if err := db.UpdateLastPingReceived(node.ID(), node.IP(), inst); err != nil { t.Errorf("ping: failed to update: %v", err) } - if stored := db.LastPingReceived(node.ID()); stored.Unix() != inst.Unix() { + if stored := db.LastPingReceived(node.ID(), node.IP()); stored.Unix() != inst.Unix() { t.Errorf("ping: value mismatch: have %v, want %v", stored, inst) } // Check fetch/store operations on a node pong object - if stored := db.LastPongReceived(node.ID()); stored.Unix() != 0 { + if stored := db.LastPongReceived(node.ID(), node.IP()); stored.Unix() != 0 { t.Errorf("pong: non-existing object: %v", stored) } - if err := db.UpdateLastPongReceived(node.ID(), inst); err != nil { + if err := db.UpdateLastPongReceived(node.ID(), node.IP(), inst); err != nil { t.Errorf("pong: failed to update: %v", err) } - if stored := db.LastPongReceived(node.ID()); stored.Unix() != inst.Unix() { + if stored := db.LastPongReceived(node.ID(), node.IP()); stored.Unix() != inst.Unix() { t.Errorf("pong: value mismatch: have %v, want %v", stored, inst) } // Check fetch/store operations on a node findnode-failure object - if stored := db.FindFails(node.ID()); stored != 0 { + if stored := db.FindFails(node.ID(), node.IP()); stored != 0 { t.Errorf("find-node fails: non-existing object: %v", stored) } - if err := db.UpdateFindFails(node.ID(), num); err != nil { + if err := db.UpdateFindFails(node.ID(), node.IP(), num); err != nil { t.Errorf("find-node fails: failed to update: %v", err) } - if stored := db.FindFails(node.ID()); stored != num { + if stored := db.FindFails(node.ID(), node.IP()); stored != num { t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) } // Check fetch/store operations on an actual node object @@ -256,7 +268,7 @@ func testSeedQuery() error { if err := db.UpdateNode(seed.node); err != nil { return fmt.Errorf("node %d: failed to insert: %v", i, err) } - if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil { + if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IP(), seed.pong); err != nil { return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err) } } @@ -321,10 +333,12 @@ func TestDBPersistency(t *testing.T) { } var nodeDBExpirationNodes = []struct { - node *Node - pong time.Time - exp bool + node *Node + pong time.Time + storeNode bool + exp bool }{ + // Node has new enough pong time and isn't expired: { node: NewV4( hexPubkey("8d110e2ed4b446d9b5fb50f117e5f37fb7597af455e1dab0e6f045a6eeaa786a6781141659020d38bdc5e698ed3d4d2bafa8b5061810dfa63e8ac038db2e9b67"), @@ -332,17 +346,79 @@ var nodeDBExpirationNodes = []struct { 30303, 30303, ), - pong: time.Now().Add(-dbNodeExpiration + time.Minute), - exp: false, - }, { + storeNode: true, + pong: time.Now().Add(-dbNodeExpiration + time.Minute), + exp: false, + }, + // Node with pong time before expiration is removed: + { node: NewV4( hexPubkey("913a205579c32425b220dfba999d215066e5bdbf900226b11da1907eae5e93eb40616d47412cf819664e9eacbdfcca6b0c6e07e09847a38472d4be46ab0c3672"), net.IP{127, 0, 0, 2}, 30303, 30303, ), - pong: time.Now().Add(-dbNodeExpiration - time.Minute), - exp: true, + storeNode: true, + pong: time.Now().Add(-dbNodeExpiration - time.Minute), + exp: true, + }, + // Just pong time, no node stored: + { + node: NewV4( + hexPubkey("b56670e0b6bad2c5dab9f9fe6f061a16cf78d68b6ae2cfda3144262d08d97ce5f46fd8799b6d1f709b1abe718f2863e224488bd7518e5e3b43809ac9bd1138ca"), + net.IP{127, 0, 0, 3}, + 30303, + 30303, + ), + storeNode: false, + pong: time.Now().Add(-dbNodeExpiration - time.Minute), + exp: true, + }, + // Node with multiple pong times, all older than expiration. + { + node: NewV4( + hexPubkey("29f619cebfd32c9eab34aec797ed5e3fe15b9b45be95b4df3f5fe6a9ae892f433eb08d7698b2ef3621568b0fb70d57b515ab30d4e72583b798298e0f0a66b9d1"), + net.IP{127, 0, 0, 4}, + 30303, + 30303, + ), + storeNode: true, + pong: time.Now().Add(-dbNodeExpiration - time.Minute), + exp: true, + }, + { + node: NewV4( + hexPubkey("29f619cebfd32c9eab34aec797ed5e3fe15b9b45be95b4df3f5fe6a9ae892f433eb08d7698b2ef3621568b0fb70d57b515ab30d4e72583b798298e0f0a66b9d1"), + net.IP{127, 0, 0, 5}, + 30303, + 30303, + ), + storeNode: false, + pong: time.Now().Add(-dbNodeExpiration - 2*time.Minute), + exp: true, + }, + // Node with multiple pong times, one newer, one older than expiration. + { + node: NewV4( + hexPubkey("3b73a9e5f4af6c4701c57c73cc8cfa0f4802840b24c11eba92aac3aef65644a3728b4b2aec8199f6d72bd66be2c65861c773129039bd47daa091ca90a6d4c857"), + net.IP{127, 0, 0, 6}, + 30303, + 30303, + ), + storeNode: true, + pong: time.Now().Add(-dbNodeExpiration + time.Minute), + exp: false, + }, + { + node: NewV4( + hexPubkey("3b73a9e5f4af6c4701c57c73cc8cfa0f4802840b24c11eba92aac3aef65644a3728b4b2aec8199f6d72bd66be2c65861c773129039bd47daa091ca90a6d4c857"), + net.IP{127, 0, 0, 7}, + 30303, + 30303, + ), + storeNode: false, + pong: time.Now().Add(-dbNodeExpiration - time.Minute), + exp: true, }, } @@ -350,23 +426,39 @@ func TestDBExpiration(t *testing.T) { db, _ := OpenDB("") defer db.Close() - // Add all the test nodes and set their last pong time + // Add all the test nodes and set their last pong time. for i, seed := range nodeDBExpirationNodes { - if err := db.UpdateNode(seed.node); err != nil { - t.Fatalf("node %d: failed to insert: %v", i, err) + if seed.storeNode { + if err := db.UpdateNode(seed.node); err != nil { + t.Fatalf("node %d: failed to insert: %v", i, err) + } } - if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil { + if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IP(), seed.pong); err != nil { t.Fatalf("node %d: failed to update bondTime: %v", i, err) } } - // Expire some of them, and check the rest - if err := db.expireNodes(); err != nil { - t.Fatalf("failed to expire nodes: %v", err) - } + + db.expireNodes() + + // Check that expired entries have been removed. + unixZeroTime := time.Unix(0, 0) for i, seed := range nodeDBExpirationNodes { node := db.Node(seed.node.ID()) - if (node == nil && !seed.exp) || (node != nil && seed.exp) { - t.Errorf("node %d: expiration mismatch: have %v, want %v", i, node, seed.exp) + pong := db.LastPongReceived(seed.node.ID(), seed.node.IP()) + if seed.exp { + if seed.storeNode && node != nil { + t.Errorf("node %d (%s) shouldn't be present after expiration", i, seed.node.ID().TerminalString()) + } + if !pong.Equal(unixZeroTime) { + t.Errorf("pong time %d (%s %v) shouldn't be present after expiration", i, seed.node.ID().TerminalString(), seed.node.IP()) + } + } else { + if seed.storeNode && node == nil { + t.Errorf("node %d (%s) should be present after expiration", i, seed.node.ID().TerminalString()) + } + if !pong.Equal(seed.pong.Truncate(1 * time.Second)) { + t.Errorf("pong time %d (%s) should be %v after expiration, but is %v", i, seed.node.ID().TerminalString(), seed.pong, pong) + } } } } diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/metrics.go b/vendor/github.com/ethereum/go-ethereum/p2p/metrics.go index 8df82bb0..2b1ad6df 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/metrics.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/metrics.go @@ -161,6 +161,7 @@ func (c *meteredConn) Write(b []byte) (n int, err error) { // the ingress and the egress traffic registries using the peer's IP and node ID, // also emits connect event. func (c *meteredConn) handshakeDone(id enode.ID) { + // TODO (kurkomisi): use the node URL instead of the pure node ID. (the String() method of *Node) if atomic.AddInt32(&meteredPeerCount, 1) >= MeteredPeerLimit { // Don't register the peer in the traffic registries. atomic.AddInt32(&meteredPeerCount, -1) diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting.go index 06a1a584..55824725 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting.go @@ -16,34 +16,37 @@ package protocols -import "github.com/ethereum/go-ethereum/metrics" +import ( + "time" -//define some metrics -var ( - //NOTE: these metrics just define the interfaces and are currently *NOT persisted* over sessions - //All metrics are cumulative - - //total amount of units credited - mBalanceCredit = metrics.NewRegisteredCounterForced("account.balance.credit", nil) - //total amount of units debited - mBalanceDebit = metrics.NewRegisteredCounterForced("account.balance.debit", nil) - //total amount of bytes credited - mBytesCredit = metrics.NewRegisteredCounterForced("account.bytes.credit", nil) - //total amount of bytes debited - mBytesDebit = metrics.NewRegisteredCounterForced("account.bytes.debit", nil) - //total amount of credited messages - mMsgCredit = metrics.NewRegisteredCounterForced("account.msg.credit", nil) - //total amount of debited messages - mMsgDebit = metrics.NewRegisteredCounterForced("account.msg.debit", nil) - //how many times local node had to drop remote peers - mPeerDrops = metrics.NewRegisteredCounterForced("account.peerdrops", nil) - //how many times local node overdrafted and dropped - mSelfDrops = metrics.NewRegisteredCounterForced("account.selfdrops", nil) + "github.com/ethereum/go-ethereum/metrics" ) -//Prices defines how prices are being passed on to the accounting instance +// define some metrics +var ( + // All metrics are cumulative + + // total amount of units credited + mBalanceCredit = metrics.NewRegisteredCounterForced("account.balance.credit", metrics.AccountingRegistry) + // total amount of units debited + mBalanceDebit = metrics.NewRegisteredCounterForced("account.balance.debit", metrics.AccountingRegistry) + // total amount of bytes credited + mBytesCredit = metrics.NewRegisteredCounterForced("account.bytes.credit", metrics.AccountingRegistry) + // total amount of bytes debited + mBytesDebit = metrics.NewRegisteredCounterForced("account.bytes.debit", metrics.AccountingRegistry) + // total amount of credited messages + mMsgCredit = metrics.NewRegisteredCounterForced("account.msg.credit", metrics.AccountingRegistry) + // total amount of debited messages + mMsgDebit = metrics.NewRegisteredCounterForced("account.msg.debit", metrics.AccountingRegistry) + // how many times local node had to drop remote peers + mPeerDrops = metrics.NewRegisteredCounterForced("account.peerdrops", metrics.AccountingRegistry) + // how many times local node overdrafted and dropped + mSelfDrops = metrics.NewRegisteredCounterForced("account.selfdrops", metrics.AccountingRegistry) +) + +// Prices defines how prices are being passed on to the accounting instance type Prices interface { - //Return the Price for a message + // Return the Price for a message Price(interface{}) *Price } @@ -54,20 +57,20 @@ const ( Receiver = Payer(false) ) -//Price represents the costs of a message +// Price represents the costs of a message type Price struct { - Value uint64 // - PerByte bool //True if the price is per byte or for unit + Value uint64 + PerByte bool // True if the price is per byte or for unit Payer Payer } -//For gives back the price for a message -//A protocol provides the message price in absolute value -//This method then returns the correct signed amount, -//depending on who pays, which is identified by the `payer` argument: -//`Send` will pass a `Sender` payer, `Receive` will pass the `Receiver` argument. -//Thus: If Sending and sender pays, amount positive, otherwise negative -//If Receiving, and receiver pays, amount positive, otherwise negative +// For gives back the price for a message +// A protocol provides the message price in absolute value +// This method then returns the correct signed amount, +// depending on who pays, which is identified by the `payer` argument: +// `Send` will pass a `Sender` payer, `Receive` will pass the `Receiver` argument. +// Thus: If Sending and sender pays, amount positive, otherwise negative +// If Receiving, and receiver pays, amount positive, otherwise negative func (p *Price) For(payer Payer, size uint32) int64 { price := p.Value if p.PerByte { @@ -79,22 +82,22 @@ func (p *Price) For(payer Payer, size uint32) int64 { return int64(price) } -//Balance is the actual accounting instance -//Balance defines the operations needed for accounting -//Implementations internally maintain the balance for every peer +// Balance is the actual accounting instance +// Balance defines the operations needed for accounting +// Implementations internally maintain the balance for every peer type Balance interface { - //Adds amount to the local balance with remote node `peer`; - //positive amount = credit local node - //negative amount = debit local node + // Adds amount to the local balance with remote node `peer`; + // positive amount = credit local node + // negative amount = debit local node Add(amount int64, peer *Peer) error } -//Accounting implements the Hook interface -//It interfaces to the balances through the Balance interface, -//while interfacing with protocols and its prices through the Prices interface +// Accounting implements the Hook interface +// It interfaces to the balances through the Balance interface, +// while interfacing with protocols and its prices through the Prices interface type Accounting struct { - Balance //interface to accounting logic - Prices //interface to prices logic + Balance // interface to accounting logic + Prices // interface to prices logic } func NewAccounting(balance Balance, po Prices) *Accounting { @@ -105,59 +108,66 @@ func NewAccounting(balance Balance, po Prices) *Accounting { return ah } -//Implement Hook.Send +// SetupAccountingMetrics uses a separate registry for p2p accounting metrics; +// this registry should be independent of any other metrics as it persists at different endpoints. +// It also starts the persisting go-routine which +// at the passed interval writes the metrics to a LevelDB +func SetupAccountingMetrics(reportInterval time.Duration, path string) *AccountingMetrics { + // create the DB and start persisting + return NewAccountingMetrics(metrics.AccountingRegistry, reportInterval, path) +} + // Send takes a peer, a size and a msg and -// - calculates the cost for the local node sending a msg of size to peer using the Prices interface -// - credits/debits local node using balance interface +// - calculates the cost for the local node sending a msg of size to peer using the Prices interface +// - credits/debits local node using balance interface func (ah *Accounting) Send(peer *Peer, size uint32, msg interface{}) error { - //get the price for a message (through the protocol spec) + // get the price for a message (through the protocol spec) price := ah.Price(msg) - //this message doesn't need accounting + // this message doesn't need accounting if price == nil { return nil } - //evaluate the price for sending messages + // evaluate the price for sending messages costToLocalNode := price.For(Sender, size) - //do the accounting + // do the accounting err := ah.Add(costToLocalNode, peer) - //record metrics: just increase counters for user-facing metrics + // record metrics: just increase counters for user-facing metrics ah.doMetrics(costToLocalNode, size, err) return err } -//Implement Hook.Receive // Receive takes a peer, a size and a msg and -// - calculates the cost for the local node receiving a msg of size from peer using the Prices interface -// - credits/debits local node using balance interface +// - calculates the cost for the local node receiving a msg of size from peer using the Prices interface +// - credits/debits local node using balance interface func (ah *Accounting) Receive(peer *Peer, size uint32, msg interface{}) error { - //get the price for a message (through the protocol spec) + // get the price for a message (through the protocol spec) price := ah.Price(msg) - //this message doesn't need accounting + // this message doesn't need accounting if price == nil { return nil } - //evaluate the price for receiving messages + // evaluate the price for receiving messages costToLocalNode := price.For(Receiver, size) - //do the accounting + // do the accounting err := ah.Add(costToLocalNode, peer) - //record metrics: just increase counters for user-facing metrics + // record metrics: just increase counters for user-facing metrics ah.doMetrics(costToLocalNode, size, err) return err } -//record some metrics -//this is not an error handling. `err` is returned by both `Send` and `Receive` -//`err` will only be non-nil if a limit has been violated (overdraft), in which case the peer has been dropped. -//if the limit has been violated and `err` is thus not nil: -// * if the price is positive, local node has been credited; thus `err` implicitly signals the REMOTE has been dropped -// * if the price is negative, local node has been debited, thus `err` implicitly signals LOCAL node "overdraft" +// record some metrics +// this is not an error handling. `err` is returned by both `Send` and `Receive` +// `err` will only be non-nil if a limit has been violated (overdraft), in which case the peer has been dropped. +// if the limit has been violated and `err` is thus not nil: +// * if the price is positive, local node has been credited; thus `err` implicitly signals the REMOTE has been dropped +// * if the price is negative, local node has been debited, thus `err` implicitly signals LOCAL node "overdraft" func (ah *Accounting) doMetrics(price int64, size uint32, err error) { if price > 0 { mBalanceCredit.Inc(price) mBytesCredit.Inc(int64(size)) mMsgCredit.Inc(1) if err != nil { - //increase the number of times a remote node has been dropped due to "overdraft" + // increase the number of times a remote node has been dropped due to "overdraft" mPeerDrops.Inc(1) } } else { @@ -165,7 +175,7 @@ func (ah *Accounting) doMetrics(price int64, size uint32, err error) { mBytesDebit.Inc(int64(size)) mMsgDebit.Inc(1) if err != nil { - //increase the number of times the local node has done an "overdraft" in respect to other nodes + // increase the number of times the local node has done an "overdraft" in respect to other nodes mSelfDrops.Inc(1) } } diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_api.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_api.go new file mode 100644 index 00000000..48e2af9f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_api.go @@ -0,0 +1,94 @@ +package protocols + +import ( + "errors" +) + +// Textual version number of accounting API +const AccountingVersion = "1.0" + +var errNoAccountingMetrics = errors.New("accounting metrics not enabled") + +// AccountingApi provides an API to access account related information +type AccountingApi struct { + metrics *AccountingMetrics +} + +// NewAccountingApi creates a new AccountingApi +// m will be used to check if accounting metrics are enabled +func NewAccountingApi(m *AccountingMetrics) *AccountingApi { + return &AccountingApi{m} +} + +// Balance returns local node balance (units credited - units debited) +func (self *AccountingApi) Balance() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + balance := mBalanceCredit.Count() - mBalanceDebit.Count() + return balance, nil +} + +// BalanceCredit returns total amount of units credited by local node +func (self *AccountingApi) BalanceCredit() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mBalanceCredit.Count(), nil +} + +// BalanceCredit returns total amount of units debited by local node +func (self *AccountingApi) BalanceDebit() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mBalanceDebit.Count(), nil +} + +// BytesCredit returns total amount of bytes credited by local node +func (self *AccountingApi) BytesCredit() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mBytesCredit.Count(), nil +} + +// BalanceCredit returns total amount of bytes debited by local node +func (self *AccountingApi) BytesDebit() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mBytesDebit.Count(), nil +} + +// MsgCredit returns total amount of messages credited by local node +func (self *AccountingApi) MsgCredit() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mMsgCredit.Count(), nil +} + +// MsgDebit returns total amount of messages debited by local node +func (self *AccountingApi) MsgDebit() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mMsgDebit.Count(), nil +} + +// PeerDrops returns number of times when local node had to drop remote peers +func (self *AccountingApi) PeerDrops() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mPeerDrops.Count(), nil +} + +// SelfDrops returns number of times when local node was overdrafted and dropped +func (self *AccountingApi) SelfDrops() (int64, error) { + if self.metrics == nil { + return 0, errNoAccountingMetrics + } + return mSelfDrops.Count(), nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_simulation_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_simulation_test.go index 65b737ab..464b5989 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_simulation_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/accounting_simulation_test.go @@ -20,7 +20,10 @@ import ( "context" "flag" "fmt" + "io/ioutil" "math/rand" + "os" + "path/filepath" "reflect" "sync" "testing" @@ -66,6 +69,13 @@ func init() { func TestAccountingSimulation(t *testing.T) { //setup the balances objects for every node bal := newBalances(*nodes) + //setup the metrics system or tests will fail trying to write metrics + dir, err := ioutil.TempDir("", "account-sim") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + SetupAccountingMetrics(1*time.Second, filepath.Join(dir, "metrics.db")) //define the node.Service for this test services := adapters.Services{ "accounting": func(ctx *adapters.ServiceContext) (node.Service, error) { @@ -149,8 +159,9 @@ func TestAccountingSimulation(t *testing.T) { // (n entries in the array will not be filled - // the balance of a node with itself) type matrix struct { - n int //number of nodes - m []int64 //array of balances + n int //number of nodes + m []int64 //array of balances + lock sync.Mutex } // create a new matrix @@ -167,7 +178,9 @@ func (m *matrix) add(i, j int, v int64) error { // i * number of nodes + remote node mi := i*m.n + j // register that balance + m.lock.Lock() m.m[mi] += v + m.lock.Unlock() return nil } diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol.go index 7dddd852..1600a11f 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol.go @@ -381,15 +381,17 @@ func (p *Peer) handleIncoming(handle func(ctx context.Context, msg interface{}) // * arguments // * context // * the local handshake to be sent to the remote peer -// * funcion to be called on the remote handshake (can be nil) +// * function to be called on the remote handshake (can be nil) // * expects a remote handshake back of the same type // * the dialing peer needs to send the handshake first and then waits for remote // * the listening peer waits for the remote handshake and then sends it // returns the remote handshake and an error -func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interface{}) error) (rhs interface{}, err error) { +func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interface{}) error) (interface{}, error) { if _, ok := p.spec.GetCode(hs); !ok { return nil, errorf(ErrHandshake, "unknown handshake message type: %T", hs) } + + var rhs interface{} errc := make(chan error, 2) handle := func(ctx context.Context, msg interface{}) error { rhs = msg @@ -412,6 +414,7 @@ func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interf }() for i := 0; i < 2; i++ { + var err error select { case err = <-errc: case <-ctx.Done(): @@ -423,3 +426,17 @@ func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interf } return rhs, nil } + +// HasCap returns true if Peer has a capability +// with provided name. +func (p *Peer) HasCap(capName string) (yes bool) { + if p == nil || p.Peer == nil { + return false + } + for _, c := range p.Caps() { + if c.Name == capName { + return true + } + } + return false +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol_test.go index a26222cd..9ac76ea2 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/protocol_test.go @@ -21,11 +21,13 @@ import ( "context" "errors" "fmt" + "sync" "testing" "time" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" @@ -142,9 +144,12 @@ func newProtocol(pp *p2ptest.TestPeerPool) func(*p2p.Peer, p2p.MsgReadWriter) er } } -func protocolTester(t *testing.T, pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester { - conf := adapters.RandomNodeConfig() - return p2ptest.NewProtocolTester(t, conf.ID, 2, newProtocol(pp)) +func protocolTester(pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester { + prvkey, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + return p2ptest.NewProtocolTester(prvkey, 2, newProtocol(pp)) } func protoHandshakeExchange(id enode.ID, proto *protoHandshake) []p2ptest.Exchange { @@ -172,8 +177,11 @@ func protoHandshakeExchange(id enode.ID, proto *protoHandshake) []p2ptest.Exchan } func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) { + t.Helper() pp := p2ptest.NewTestPeerPool() - s := protocolTester(t, pp) + s := protocolTester(pp) + defer s.Stop() + // TODO: make this more than one handshake node := s.Nodes[0] if err := s.TestExchanges(protoHandshakeExchange(node.ID(), proto)...); err != nil { @@ -195,6 +203,7 @@ type dummyHook struct { send bool err error waitC chan struct{} + mu sync.Mutex } type dummyMsg struct { @@ -202,6 +211,9 @@ type dummyMsg struct { } func (d *dummyHook) Send(peer *Peer, size uint32, msg interface{}) error { + d.mu.Lock() + defer d.mu.Unlock() + d.peer = peer d.size = size d.msg = msg @@ -210,6 +222,9 @@ func (d *dummyHook) Send(peer *Peer, size uint32, msg interface{}) error { } func (d *dummyHook) Receive(peer *Peer, size uint32, msg interface{}) error { + d.mu.Lock() + defer d.mu.Unlock() + d.peer = peer d.size = size d.msg = msg @@ -249,9 +264,12 @@ func TestProtocolHook(t *testing.T) { return peer.Run(handle) } - conf := adapters.RandomNodeConfig() - tester := p2ptest.NewProtocolTester(t, conf.ID, 2, runFunc) - err := tester.TestExchanges(p2ptest.Exchange{ + prvkey, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + tester := p2ptest.NewProtocolTester(prvkey, 2, runFunc) + err = tester.TestExchanges(p2ptest.Exchange{ Expects: []p2ptest.Expect{ { Code: 0, @@ -263,18 +281,23 @@ func TestProtocolHook(t *testing.T) { if err != nil { t.Fatal(err) } + testHook.mu.Lock() if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "handshake" { t.Fatal("Expected msg to be set, but it is not") } if !testHook.send { t.Fatal("Expected a send message, but it is not") } - if testHook.peer == nil || testHook.peer.ID() != tester.Nodes[0].ID() { - t.Fatal("Expected peer ID to be set correctly, but it is not") + if testHook.peer == nil { + t.Fatal("Expected peer to be set, is nil") + } + if peerId := testHook.peer.ID(); peerId != tester.Nodes[0].ID() && peerId != tester.Nodes[1].ID() { + t.Fatalf("Expected peer ID to be set correctly, but it is not (got %v, exp %v or %v", peerId, tester.Nodes[0].ID(), tester.Nodes[1].ID()) } if testHook.size != 11 { //11 is the length of the encoded message t.Fatalf("Expected size to be %d, but it is %d ", 1, testHook.size) } + testHook.mu.Unlock() err = tester.TestExchanges(p2ptest.Exchange{ Triggers: []p2ptest.Trigger{ @@ -291,6 +314,8 @@ func TestProtocolHook(t *testing.T) { if err != nil { t.Fatal(err) } + + testHook.mu.Lock() if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "response" { t.Fatal("Expected msg to be set, but it is not") } @@ -303,6 +328,7 @@ func TestProtocolHook(t *testing.T) { if testHook.size != 10 { //11 is the length of the encoded message t.Fatalf("Expected size to be %d, but it is %d ", 1, testHook.size) } + testHook.mu.Unlock() testHook.err = fmt.Errorf("dummy error") err = tester.TestExchanges(p2ptest.Exchange{ @@ -322,7 +348,6 @@ func TestProtocolHook(t *testing.T) { if err != nil { t.Fatalf("Expected a specific disconnect error, but got different one: %v", err) } - } //We need to test that if the hook is not defined, then message infrastructure @@ -339,16 +364,19 @@ func TestNoHook(t *testing.T) { ctx := context.TODO() msg := &perBytesMsgSenderPays{Content: "testBalance"} //send a message - err := peer.Send(ctx, msg) - if err != nil { + + if err := peer.Send(ctx, msg); err != nil { t.Fatal(err) } //simulate receiving a message rw.msg = msg - peer.handleIncoming(func(ctx context.Context, msg interface{}) error { + handler := func(ctx context.Context, msg interface{}) error { return nil - }) - //all should just work and not result in any error + } + + if err := peer.handleIncoming(handler); err != nil { + t.Fatal(err) + } } func TestProtoHandshakeVersionMismatch(t *testing.T) { @@ -388,8 +416,11 @@ func moduleHandshakeExchange(id enode.ID, resp uint) []p2ptest.Exchange { } func runModuleHandshake(t *testing.T, resp uint, errs ...error) { + t.Helper() pp := p2ptest.NewTestPeerPool() - s := protocolTester(t, pp) + s := protocolTester(pp) + defer s.Stop() + node := s.Nodes[0] if err := s.TestExchanges(protoHandshakeExchange(node.ID(), &protoHandshake{42, "420"})...); err != nil { t.Fatal(err) @@ -468,8 +499,10 @@ func testMultiPeerSetup(a, b enode.ID) []p2ptest.Exchange { } func runMultiplePeers(t *testing.T, peer int, errs ...error) { + t.Helper() pp := p2ptest.NewTestPeerPool() - s := protocolTester(t, pp) + s := protocolTester(pp) + defer s.Stop() if err := s.TestExchanges(testMultiPeerSetup(s.Nodes[0].ID(), s.Nodes[1].ID())...); err != nil { t.Fatal(err) @@ -539,14 +572,14 @@ WAIT: } } -func XTestMultiplePeersDropSelf(t *testing.T) { +func TestMultiplePeersDropSelf(t *testing.T) { runMultiplePeers(t, 0, fmt.Errorf("subprotocol error"), fmt.Errorf("Message handler error: (msg code 3): dropped"), ) } -func XTestMultiplePeersDropOther(t *testing.T) { +func TestMultiplePeersDropOther(t *testing.T) { runMultiplePeers(t, 1, fmt.Errorf("Message handler error: (msg code 3): dropped"), fmt.Errorf("subprotocol error"), diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/reporter.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/reporter.go new file mode 100644 index 00000000..9612b4a4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/reporter.go @@ -0,0 +1,162 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package protocols + +import ( + "encoding/binary" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + + "github.com/syndtr/goleveldb/leveldb" +) + +//AccountMetrics abstracts away the metrics DB and +//the reporter to persist metrics +type AccountingMetrics struct { + reporter *reporter +} + +//Close will be called when the node is being shutdown +//for a graceful cleanup +func (am *AccountingMetrics) Close() { + close(am.reporter.quit) + // wait for reporter loop to finish saving metrics + // before reporter database is closed + select { + case <-time.After(10 * time.Second): + log.Error("accounting metrics reporter timeout") + case <-am.reporter.done: + } + am.reporter.db.Close() +} + +//reporter is an internal structure used to write p2p accounting related +//metrics to a LevelDB. It will periodically write the accrued metrics to the DB. +type reporter struct { + reg metrics.Registry //the registry for these metrics (independent of other metrics) + interval time.Duration //duration at which the reporter will persist metrics + db *leveldb.DB //the actual DB + quit chan struct{} //quit the reporter loop + done chan struct{} //signal that reporter loop is done +} + +//NewMetricsDB creates a new LevelDB instance used to persist metrics defined +//inside p2p/protocols/accounting.go +func NewAccountingMetrics(r metrics.Registry, d time.Duration, path string) *AccountingMetrics { + var val = make([]byte, 8) + var err error + + //Create the LevelDB + db, err := leveldb.OpenFile(path, nil) + if err != nil { + log.Error(err.Error()) + return nil + } + + //Check for all defined metrics that there is a value in the DB + //If there is, assign it to the metric. This means that the node + //has been running before and that metrics have been persisted. + metricsMap := map[string]metrics.Counter{ + "account.balance.credit": mBalanceCredit, + "account.balance.debit": mBalanceDebit, + "account.bytes.credit": mBytesCredit, + "account.bytes.debit": mBytesDebit, + "account.msg.credit": mMsgCredit, + "account.msg.debit": mMsgDebit, + "account.peerdrops": mPeerDrops, + "account.selfdrops": mSelfDrops, + } + //iterate the map and get the values + for key, metric := range metricsMap { + val, err = db.Get([]byte(key), nil) + //until the first time a value is being written, + //this will return an error. + //it could be beneficial though to log errors later, + //but that would require a different logic + if err == nil { + metric.Inc(int64(binary.BigEndian.Uint64(val))) + } + } + + //create the reporter + rep := &reporter{ + reg: r, + interval: d, + db: db, + quit: make(chan struct{}), + done: make(chan struct{}), + } + + //run the go routine + go rep.run() + + m := &AccountingMetrics{ + reporter: rep, + } + + return m +} + +//run is the goroutine which periodically sends the metrics to the configured LevelDB +func (r *reporter) run() { + // signal that the reporter loop is done + defer close(r.done) + + intervalTicker := time.NewTicker(r.interval) + + for { + select { + case <-intervalTicker.C: + //at each tick send the metrics + if err := r.save(); err != nil { + log.Error("unable to send metrics to LevelDB", "err", err) + //If there is an error in writing, exit the routine; we assume here that the error is + //severe and don't attempt to write again. + //Also, this should prevent leaking when the node is stopped + return + } + case <-r.quit: + //graceful shutdown + if err := r.save(); err != nil { + log.Error("unable to send metrics to LevelDB", "err", err) + } + return + } + } +} + +//send the metrics to the DB +func (r *reporter) save() error { + //create a LevelDB Batch + batch := leveldb.Batch{} + //for each metric in the registry (which is independent)... + r.reg.Each(func(name string, i interface{}) { + metric, ok := i.(metrics.Counter) + if ok { + //assuming every metric here to be a Counter (separate registry) + //...create a snapshot... + ms := metric.Snapshot() + byteVal := make([]byte, 8) + binary.BigEndian.PutUint64(byteVal, uint64(ms.Count())) + //...and save the value to the DB + batch.Put([]byte(name), byteVal) + } + }) + return r.db.Write(&batch, nil) +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/protocols/reporter_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/reporter_test.go new file mode 100644 index 00000000..9b0da09b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/p2p/protocols/reporter_test.go @@ -0,0 +1,83 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package protocols + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + "github.com/ethereum/go-ethereum/log" +) + +//TestReporter tests that the metrics being collected for p2p accounting +//are being persisted and available after restart of a node. +//It simulates restarting by just recreating the DB as if the node had restarted. +func TestReporter(t *testing.T) { + //create a test directory + dir, err := ioutil.TempDir("", "reporter-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + //setup the metrics + log.Debug("Setting up metrics first time") + reportInterval := 2 * time.Millisecond + metrics := SetupAccountingMetrics(reportInterval, filepath.Join(dir, "test.db")) + log.Debug("Done.") + + //change metrics + mBalanceCredit.Inc(12) + mBytesCredit.Inc(34) + mMsgDebit.Inc(9) + + //store expected metrics + expectedBalanceCredit := mBalanceCredit.Count() + expectedBytesCredit := mBytesCredit.Count() + expectedMsgDebit := mMsgDebit.Count() + + //give the reporter time to write the metrics to DB + time.Sleep(20 * time.Millisecond) + + //close the DB also, or we can't create a new one + metrics.Close() + + //clear the metrics - this effectively simulates the node having shut down... + mBalanceCredit.Clear() + mBytesCredit.Clear() + mMsgDebit.Clear() + + //setup the metrics again + log.Debug("Setting up metrics second time") + metrics = SetupAccountingMetrics(reportInterval, filepath.Join(dir, "test.db")) + defer metrics.Close() + log.Debug("Done.") + + //now check the metrics, they should have the same value as before "shutdown" + if mBalanceCredit.Count() != expectedBalanceCredit { + t.Fatalf("Expected counter to be %d, but is %d", expectedBalanceCredit, mBalanceCredit.Count()) + } + if mBytesCredit.Count() != expectedBytesCredit { + t.Fatalf("Expected counter to be %d, but is %d", expectedBytesCredit, mBytesCredit.Count()) + } + if mMsgDebit.Count() != expectedMsgDebit { + t.Fatalf("Expected counter to be %d, but is %d", expectedMsgDebit, mMsgDebit.Count()) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/rlpx.go b/vendor/github.com/ethereum/go-ethereum/p2p/rlpx.go index 22a27dd9..67cc1d9b 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/rlpx.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/rlpx.go @@ -39,9 +39,9 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" "github.com/golang/snappy" + "golang.org/x/crypto/sha3" ) const ( @@ -253,10 +253,10 @@ func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) { } // setup sha3 instances for the MACs - mac1 := sha3.NewKeccak256() + mac1 := sha3.NewLegacyKeccak256() mac1.Write(xor(s.MAC, h.respNonce)) mac1.Write(auth) - mac2 := sha3.NewKeccak256() + mac2 := sha3.NewLegacyKeccak256() mac2.Write(xor(s.MAC, h.initNonce)) mac2.Write(authResp) if h.initiator { diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/rlpx_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/rlpx_test.go index 64172217..5d898180 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/rlpx_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/rlpx_test.go @@ -34,9 +34,9 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/p2p/simulations/pipes" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) func TestSharedSecret(t *testing.T) { @@ -334,8 +334,8 @@ func TestRLPXFrameRW(t *testing.T) { s1 := secrets{ AES: aesSecret, MAC: macSecret, - EgressMAC: sha3.NewKeccak256(), - IngressMAC: sha3.NewKeccak256(), + EgressMAC: sha3.NewLegacyKeccak256(), + IngressMAC: sha3.NewLegacyKeccak256(), } s1.EgressMAC.Write(egressMACinit) s1.IngressMAC.Write(ingressMACinit) @@ -344,8 +344,8 @@ func TestRLPXFrameRW(t *testing.T) { s2 := secrets{ AES: aesSecret, MAC: macSecret, - EgressMAC: sha3.NewKeccak256(), - IngressMAC: sha3.NewKeccak256(), + EgressMAC: sha3.NewLegacyKeccak256(), + IngressMAC: sha3.NewLegacyKeccak256(), } s2.EgressMAC.Write(ingressMACinit) s2.IngressMAC.Write(egressMACinit) diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/server.go b/vendor/github.com/ethereum/go-ethereum/p2p/server.go index 66786086..566f01ff 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/server.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/server.go @@ -22,7 +22,6 @@ import ( "crypto/ecdsa" "encoding/hex" "errors" - "fmt" "net" "sort" "sync" @@ -391,7 +390,7 @@ type sharedUDPConn struct { func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { packet, ok := <-s.unhandled if !ok { - return 0, nil, fmt.Errorf("Connection was closed") + return 0, nil, errors.New("Connection was closed") } l := len(packet.Data) if l > len(b) { @@ -425,7 +424,7 @@ func (srv *Server) Start() (err error) { // static fields if srv.PrivateKey == nil { - return fmt.Errorf("Server.PrivateKey must be set to a non-nil key") + return errors.New("Server.PrivateKey must be set to a non-nil key") } if srv.newTransport == nil { srv.newTransport = newRLPX @@ -903,7 +902,7 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro if dialDest != nil { dialPubkey = new(ecdsa.PublicKey) if err := dialDest.Load((*enode.Secp256k1)(dialPubkey)); err != nil { - return fmt.Errorf("dial destination doesn't have a secp256k1 public key") + return errors.New("dial destination doesn't have a secp256k1 public key") } } // Run the encryption handshake. @@ -937,7 +936,7 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro return err } if id := c.node.ID(); !bytes.Equal(crypto.Keccak256(phs.ID), id[:]) { - clog.Trace("Wrong devp2p handshake identity", "phsid", fmt.Sprintf("%x", phs.ID)) + clog.Trace("Wrong devp2p handshake identity", "phsid", hex.EncodeToString(phs.ID)) return DiscUnexpectedIdentity } c.caps, c.name = phs.Caps, phs.Name diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/server_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/server_test.go index 7e11577d..f665c142 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/server_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/server_test.go @@ -26,10 +26,10 @@ import ( "time" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" + "golang.org/x/crypto/sha3" ) // func init() { @@ -48,8 +48,8 @@ func newTestTransport(rpub *ecdsa.PublicKey, fd net.Conn) transport { wrapped.rw = newRLPXFrameRW(fd, secrets{ MAC: zero16, AES: zero16, - IngressMAC: sha3.NewKeccak256(), - EgressMAC: sha3.NewKeccak256(), + IngressMAC: sha3.NewLegacyKeccak256(), + EgressMAC: sha3.NewLegacyKeccak256(), }) return &testTransport{rpub: rpub, rlpx: wrapped} } diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/exec.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/exec.go index abb19671..106b179e 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/exec.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/exec.go @@ -46,7 +46,7 @@ import ( func init() { // Register a reexec function to start a simulation node when the current binary is - // executed as "p2p-node" (rather than whataver the main() function would normally do). + // executed as "p2p-node" (rather than whatever the main() function would normally do). reexec.Register("p2p-node", execP2PNode) } @@ -92,12 +92,20 @@ func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) { return nil, fmt.Errorf("error creating node directory: %s", err) } + err := config.initDummyEnode() + if err != nil { + return nil, err + } // generate the config conf := &execNodeConfig{ Stack: node.DefaultConfig, Node: config, } - conf.Stack.DataDir = filepath.Join(dir, "data") + if config.DataDir != "" { + conf.Stack.DataDir = config.DataDir + } else { + conf.Stack.DataDir = filepath.Join(dir, "data") + } conf.Stack.WSHost = "127.0.0.1" conf.Stack.WSPort = 0 conf.Stack.WSOrigins = []string{"*"} @@ -403,6 +411,13 @@ func startExecNodeStack() (*node.Node, error) { if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { return nil, fmt.Errorf("error decoding %s: %v", envNodeConfig, err) } + + // create enode record + nodeTcpConn, err := net.ResolveTCPAddr("tcp", conf.Stack.P2P.ListenAddr) + if nodeTcpConn.IP == nil { + nodeTcpConn.IP = net.IPv4(127, 0, 0, 1) + } + conf.Node.initEnode(nodeTcpConn.IP, nodeTcpConn.Port, nodeTcpConn.Port) conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey conf.Stack.Logger = log.New("node.id", conf.Node.ID.String()) diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/inproc.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/inproc.go index 52a662be..c1cf23a1 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/inproc.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/inproc.go @@ -71,8 +71,13 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { s.mtx.Lock() defer s.mtx.Unlock() - // check a node with the ID doesn't already exist id := config.ID + // verify that the node has a private key in the config + if config.PrivateKey == nil { + return nil, fmt.Errorf("node is missing private key: %s", id) + } + + // check a node with the ID doesn't already exist if _, exists := s.nodes[id]; exists { return nil, fmt.Errorf("node already exists: %s", id) } @@ -87,6 +92,11 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { } } + err := config.initDummyEnode() + if err != nil { + return nil, err + } + n, err := node.New(&node.Config{ P2P: p2p.Config{ PrivateKey: config.PrivateKey, @@ -130,7 +140,7 @@ func (s *SimAdapter) Dial(dest *enode.Node) (conn net.Conn, err error) { return nil, err } // this is simulated 'listening' - // asynchronously call the dialed destintion node's p2p server + // asynchronously call the dialed destination node's p2p server // to set up connection on the 'listening' side go srv.SetupConn(pipe1, 0, nil) return pipe2, nil @@ -172,6 +182,12 @@ type SimNode struct { registerOnce sync.Once } +// Close closes the underlaying node.Node to release +// acquired resources. +func (sn *SimNode) Close() error { + return sn.node.Close() +} + // Addr returns the node's discovery address func (sn *SimNode) Addr() []byte { return []byte(sn.Node().String()) @@ -351,17 +367,3 @@ func (sn *SimNode) NodeInfo() *p2p.NodeInfo { } return server.NodeInfo() } - -func setSocketBuffer(conn net.Conn, socketReadBuffer int, socketWriteBuffer int) error { - if v, ok := conn.(*net.UnixConn); ok { - err := v.SetReadBuffer(socketReadBuffer) - if err != nil { - return err - } - err = v.SetWriteBuffer(socketWriteBuffer) - if err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/types.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/types.go index 6681726e..f65ce7b6 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/types.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/adapters/types.go @@ -27,9 +27,11 @@ import ( "github.com/docker/docker/pkg/reexec" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rpc" ) @@ -90,12 +92,21 @@ type NodeConfig struct { // Name is a human friendly name for the node like "node01" Name string + // Use an existing database instead of a temporary one if non-empty + DataDir string + // Services are the names of the services which should be run when // starting the node (for SimNodes it should be the names of services // contained in SimAdapter.services, for other nodes it should be // services registered by calling the RegisterService function) Services []string + // Enode + node *enode.Node + + // ENR Record with entries to overwrite + Record enr.Record + // function to sanction or prevent suggesting a peer Reachable func(id enode.ID) bool @@ -165,26 +176,27 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error { // Node returns the node descriptor represented by the config. func (n *NodeConfig) Node() *enode.Node { - return enode.NewV4(&n.PrivateKey.PublicKey, net.IP{127, 0, 0, 1}, int(n.Port), int(n.Port)) + return n.node } // RandomNodeConfig returns node configuration with a randomly generated ID and // PrivateKey func RandomNodeConfig() *NodeConfig { - key, err := crypto.GenerateKey() + prvkey, err := crypto.GenerateKey() if err != nil { panic("unable to generate key") } - id := enode.PubkeyToIDV4(&key.PublicKey) port, err := assignTCPPort() if err != nil { panic("unable to assign tcp port") } + + enodId := enode.PubkeyToIDV4(&prvkey.PublicKey) return &NodeConfig{ - ID: id, - Name: fmt.Sprintf("node_%s", id.String()), - PrivateKey: key, + PrivateKey: prvkey, + ID: enodId, + Name: fmt.Sprintf("node_%s", enodId.String()), Port: port, EnableMsgEvents: true, } @@ -254,3 +266,30 @@ func RegisterServices(services Services) { os.Exit(0) } } + +// adds the host part to the configuration's ENR, signs it +// creates and the corresponding enode object to the configuration +func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error { + enrIp := enr.IP(ip) + n.Record.Set(&enrIp) + enrTcpPort := enr.TCP(tcpport) + n.Record.Set(&enrTcpPort) + enrUdpPort := enr.UDP(udpport) + n.Record.Set(&enrUdpPort) + + err := enode.SignV4(&n.Record, n.PrivateKey) + if err != nil { + return fmt.Errorf("unable to generate ENR: %v", err) + } + nod, err := enode.New(enode.V4ID{}, &n.Record) + if err != nil { + return fmt.Errorf("unable to create enode: %v", err) + } + log.Trace("simnode new", "record", n.Record) + n.node = nod + return nil +} + +func (n *NodeConfig) initDummyEnode() error { + return n.initEnode(net.IPv4(127, 0, 0, 1), 0, 0) +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/connect.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/connect.go new file mode 100644 index 00000000..ede96b34 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/connect.go @@ -0,0 +1,153 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package simulations + +import ( + "errors" + "strings" + + "github.com/ethereum/go-ethereum/p2p/enode" +) + +var ( + ErrNodeNotFound = errors.New("node not found") +) + +// ConnectToLastNode connects the node with provided NodeID +// to the last node that is up, and avoiding connection to self. +// It is useful when constructing a chain network topology +// when Network adds and removes nodes dynamically. +func (net *Network) ConnectToLastNode(id enode.ID) (err error) { + net.lock.Lock() + defer net.lock.Unlock() + + ids := net.getUpNodeIDs() + l := len(ids) + if l < 2 { + return nil + } + last := ids[l-1] + if last == id { + last = ids[l-2] + } + return net.connectNotConnected(last, id) +} + +// ConnectToRandomNode connects the node with provided NodeID +// to a random node that is up. +func (net *Network) ConnectToRandomNode(id enode.ID) (err error) { + net.lock.Lock() + defer net.lock.Unlock() + + selected := net.getRandomUpNode(id) + if selected == nil { + return ErrNodeNotFound + } + return net.connectNotConnected(selected.ID(), id) +} + +// ConnectNodesFull connects all nodes one to another. +// It provides a complete connectivity in the network +// which should be rarely needed. +func (net *Network) ConnectNodesFull(ids []enode.ID) (err error) { + net.lock.Lock() + defer net.lock.Unlock() + + if ids == nil { + ids = net.getUpNodeIDs() + } + for i, lid := range ids { + for _, rid := range ids[i+1:] { + if err = net.connectNotConnected(lid, rid); err != nil { + return err + } + } + } + return nil +} + +// ConnectNodesChain connects all nodes in a chain topology. +// If ids argument is nil, all nodes that are up will be connected. +func (net *Network) ConnectNodesChain(ids []enode.ID) (err error) { + net.lock.Lock() + defer net.lock.Unlock() + + return net.connectNodesChain(ids) +} + +func (net *Network) connectNodesChain(ids []enode.ID) (err error) { + if ids == nil { + ids = net.getUpNodeIDs() + } + l := len(ids) + for i := 0; i < l-1; i++ { + if err := net.connectNotConnected(ids[i], ids[i+1]); err != nil { + return err + } + } + return nil +} + +// ConnectNodesRing connects all nodes in a ring topology. +// If ids argument is nil, all nodes that are up will be connected. +func (net *Network) ConnectNodesRing(ids []enode.ID) (err error) { + net.lock.Lock() + defer net.lock.Unlock() + + if ids == nil { + ids = net.getUpNodeIDs() + } + l := len(ids) + if l < 2 { + return nil + } + if err := net.connectNodesChain(ids); err != nil { + return err + } + return net.connectNotConnected(ids[l-1], ids[0]) +} + +// ConnectNodesStar connects all nodes into a star topology +// If ids argument is nil, all nodes that are up will be connected. +func (net *Network) ConnectNodesStar(ids []enode.ID, center enode.ID) (err error) { + net.lock.Lock() + defer net.lock.Unlock() + + if ids == nil { + ids = net.getUpNodeIDs() + } + for _, id := range ids { + if center == id { + continue + } + if err := net.connectNotConnected(center, id); err != nil { + return err + } + } + return nil +} + +func (net *Network) connectNotConnected(oneID, otherID enode.ID) error { + return ignoreAlreadyConnectedErr(net.connect(oneID, otherID)) +} + +func ignoreAlreadyConnectedErr(err error) error { + if err == nil || strings.Contains(err.Error(), "already connected") { + return nil + } + return err +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/connect_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/connect_test.go new file mode 100644 index 00000000..32d18347 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/connect_test.go @@ -0,0 +1,172 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package simulations + +import ( + "testing" + + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" +) + +func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) { + t.Helper() + adapter := adapters.NewSimAdapter(adapters.Services{ + "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) { + return NewNoopService(nil), nil + }, + }) + + // create network + network := NewNetwork(adapter, &NetworkConfig{ + DefaultService: "noopwoop", + }) + + // create and start nodes + ids := make([]enode.ID, nodeCount) + for i := range ids { + conf := adapters.RandomNodeConfig() + node, err := network.NewNodeWithConfig(conf) + if err != nil { + t.Fatalf("error creating node: %s", err) + } + if err := network.Start(node.ID()); err != nil { + t.Fatalf("error starting node: %s", err) + } + ids[i] = node.ID() + } + + if len(network.Conns) > 0 { + t.Fatal("no connections should exist after just adding nodes") + } + + return network, ids +} + +func TestConnectToLastNode(t *testing.T) { + net, ids := newTestNetwork(t, 10) + defer net.Shutdown() + + first := ids[0] + if err := net.ConnectToLastNode(first); err != nil { + t.Fatal(err) + } + + last := ids[len(ids)-1] + for i, id := range ids { + if id == first || id == last { + continue + } + + if net.GetConn(first, id) != nil { + t.Errorf("connection must not exist with node(ind: %v, id: %v)", i, id) + } + } + + if net.GetConn(first, last) == nil { + t.Error("first and last node must be connected") + } +} + +func TestConnectToRandomNode(t *testing.T) { + net, ids := newTestNetwork(t, 10) + defer net.Shutdown() + + err := net.ConnectToRandomNode(ids[0]) + if err != nil { + t.Fatal(err) + } + + var cc int + for i, a := range ids { + for _, b := range ids[i:] { + if net.GetConn(a, b) != nil { + cc++ + } + } + } + + if cc != 1 { + t.Errorf("expected one connection, got %v", cc) + } +} + +func TestConnectNodesFull(t *testing.T) { + tests := []struct { + name string + nodeCount int + }{ + {name: "no node", nodeCount: 0}, + {name: "single node", nodeCount: 1}, + {name: "2 nodes", nodeCount: 2}, + {name: "3 nodes", nodeCount: 3}, + {name: "even number of nodes", nodeCount: 12}, + {name: "odd number of nodes", nodeCount: 13}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + net, ids := newTestNetwork(t, test.nodeCount) + defer net.Shutdown() + + err := net.ConnectNodesFull(ids) + if err != nil { + t.Fatal(err) + } + + VerifyFull(t, net, ids) + }) + } +} + +func TestConnectNodesChain(t *testing.T) { + net, ids := newTestNetwork(t, 10) + defer net.Shutdown() + + err := net.ConnectNodesChain(ids) + if err != nil { + t.Fatal(err) + } + + VerifyChain(t, net, ids) +} + +func TestConnectNodesRing(t *testing.T) { + net, ids := newTestNetwork(t, 10) + defer net.Shutdown() + + err := net.ConnectNodesRing(ids) + if err != nil { + t.Fatal(err) + } + + VerifyRing(t, net, ids) +} + +func TestConnectNodesStar(t *testing.T) { + net, ids := newTestNetwork(t, 10) + defer net.Shutdown() + + pivotIndex := 2 + + err := net.ConnectNodesStar(ids, ids[pivotIndex]) + if err != nil { + t.Fatal(err) + } + + VerifyStar(t, net, ids, pivotIndex) +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/events.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/events.go index 9b2a990e..984c2e08 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/events.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/events.go @@ -100,7 +100,7 @@ func ControlEvent(v interface{}) *Event { func (e *Event) String() string { switch e.Type { case EventTypeNode: - return fmt.Sprintf(" id: %s up: %t", e.Node.ID().TerminalString(), e.Node.Up) + return fmt.Sprintf(" id: %s up: %t", e.Node.ID().TerminalString(), e.Node.Up()) case EventTypeConn: return fmt.Sprintf(" nodes: %s->%s up: %t", e.Conn.One.TerminalString(), e.Conn.Other.TerminalString(), e.Conn.Up) case EventTypeMsg: diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/http_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/http_test.go index d9513caa..ed43c0ed 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/http_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/http_test.go @@ -35,7 +35,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" - colorable "github.com/mattn/go-colorable" + "github.com/mattn/go-colorable" ) var ( @@ -294,6 +294,7 @@ var testServices = adapters.Services{ } func testHTTPServer(t *testing.T) (*Network, *httptest.Server) { + t.Helper() adapter := adapters.NewSimAdapter(testServices) network := NewNetwork(adapter, &NetworkConfig{ DefaultService: "test", @@ -420,14 +421,15 @@ type expectEvents struct { } func (t *expectEvents) nodeEvent(id string, up bool) *Event { + node := Node{ + Config: &adapters.NodeConfig{ + ID: enode.HexID(id), + }, + up: up, + } return &Event{ Type: EventTypeNode, - Node: &Node{ - Config: &adapters.NodeConfig{ - ID: enode.HexID(id), - }, - Up: up, - }, + Node: &node, } } @@ -479,6 +481,7 @@ loop: } func (t *expectEvents) expect(events ...*Event) { + t.Helper() timeout := time.After(10 * time.Second) i := 0 for { @@ -500,8 +503,8 @@ func (t *expectEvents) expect(events ...*Event) { if event.Node.ID() != expected.Node.ID() { t.Fatalf("expected node event %d to have id %q, got %q", i, expected.Node.ID().TerminalString(), event.Node.ID().TerminalString()) } - if event.Node.Up != expected.Node.Up { - t.Fatalf("expected node event %d to have up=%t, got up=%t", i, expected.Node.Up, event.Node.Up) + if event.Node.Up() != expected.Node.Up() { + t.Fatalf("expected node event %d to have up=%t, got up=%t", i, expected.Node.Up(), event.Node.Up()) } case EventTypeConn: diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/mocker_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/mocker_test.go index 7c7016a5..06904025 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/mocker_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/mocker_test.go @@ -15,7 +15,7 @@ // along with the go-ethereum library. If not, see . // Package simulations simulates p2p networks. -// A mokcer simulates starting and stopping real nodes in a network. +// A mocker simulates starting and stopping real nodes in a network. package simulations import ( @@ -90,15 +90,12 @@ func TestMocker(t *testing.T) { for { select { case event := <-events: - //if the event is a node Up event only - if event.Node != nil && event.Node.Up { + if isNodeUp(event) { //add the correspondent node ID to the map nodemap[event.Node.Config.ID] = true //this means all nodes got a nodeUp event, so we can continue the test if len(nodemap) == nodeCount { nodesComplete = true - //wait for 3s as the mocker will need time to connect the nodes - //time.Sleep( 3 *time.Second) } } else if event.Conn != nil && nodesComplete { connCount += 1 @@ -135,13 +132,13 @@ func TestMocker(t *testing.T) { wg.Wait() //check there are nodeCount number of nodes in the network - nodes_info, err := client.GetNodes() + nodesInfo, err := client.GetNodes() if err != nil { t.Fatalf("Could not get nodes list: %s", err) } - if len(nodes_info) != nodeCount { - t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodes_info)) + if len(nodesInfo) != nodeCount { + t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodesInfo)) } //stop the mocker @@ -160,12 +157,16 @@ func TestMocker(t *testing.T) { } //now the number of nodes in the network should be zero - nodes_info, err = client.GetNodes() + nodesInfo, err = client.GetNodes() if err != nil { t.Fatalf("Could not get nodes list: %s", err) } - if len(nodes_info) != 0 { - t.Fatalf("Expected empty list of nodes, got: %d", len(nodes_info)) + if len(nodesInfo) != 0 { + t.Fatalf("Expected empty list of nodes, got: %d", len(nodesInfo)) } } + +func isNodeUp(event *Event) bool { + return event.Node != nil && event.Node.Up() +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network.go index 92ccfde8..f03c953e 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network.go @@ -20,7 +20,10 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" + "io" + "math/rand" "sync" "time" @@ -134,7 +137,7 @@ func (net *Network) Config() *NetworkConfig { // StartAll starts all nodes in the network func (net *Network) StartAll() error { for _, node := range net.Nodes { - if node.Up { + if node.Up() { continue } if err := net.Start(node.ID()); err != nil { @@ -147,7 +150,7 @@ func (net *Network) StartAll() error { // StopAll stops all nodes in the network func (net *Network) StopAll() error { for _, node := range net.Nodes { - if !node.Up { + if !node.Up() { continue } if err := net.Stop(node.ID()); err != nil { @@ -172,7 +175,7 @@ func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) if node == nil { return fmt.Errorf("node %v does not exist", id) } - if node.Up { + if node.Up() { return fmt.Errorf("node %v already up", id) } log.Trace("Starting node", "id", id, "adapter", net.nodeAdapter.Name()) @@ -180,10 +183,10 @@ func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) log.Warn("Node startup failed", "id", id, "err", err) return err } - node.Up = true + node.SetUp(true) log.Info("Started node", "id", id) - - net.events.Send(NewEvent(node)) + ev := NewEvent(node) + net.events.Send(ev) // subscribe to peer events client, err := node.Client() @@ -208,12 +211,14 @@ func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub // assume the node is now down net.lock.Lock() defer net.lock.Unlock() + node := net.getNode(id) if node == nil { return } - node.Up = false - net.events.Send(NewEvent(node)) + node.SetUp(false) + ev := NewEvent(node) + net.events.Send(ev) }() for { select { @@ -249,34 +254,57 @@ func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub // Stop stops the node with the given ID func (net *Network) Stop(id enode.ID) error { - net.lock.Lock() - node := net.getNode(id) - if node == nil { - return fmt.Errorf("node %v does not exist", id) - } - if !node.Up { - return fmt.Errorf("node %v already down", id) - } - node.Up = false - net.lock.Unlock() + // IMPORTANT: node.Stop() must NOT be called under net.lock as + // node.Reachable() closure has a reference to the network and + // calls net.InitConn() what also locks the network. => DEADLOCK + // That holds until the following ticket is not resolved: - err := node.Stop() - if err != nil { + var err error + + node, err := func() (*Node, error) { net.lock.Lock() - node.Up = true - net.lock.Unlock() + defer net.lock.Unlock() + + node := net.getNode(id) + if node == nil { + return nil, fmt.Errorf("node %v does not exist", id) + } + if !node.Up() { + return nil, fmt.Errorf("node %v already down", id) + } + node.SetUp(false) + return node, nil + }() + if err != nil { + return err + } + + err = node.Stop() // must be called without net.lock + + net.lock.Lock() + defer net.lock.Unlock() + + if err != nil { + node.SetUp(true) return err } log.Info("Stopped node", "id", id, "err", err) - net.events.Send(ControlEvent(node)) + ev := ControlEvent(node) + net.events.Send(ev) return nil } // Connect connects two nodes together by calling the "admin_addPeer" RPC // method on the "one" node so that it connects to the "other" node func (net *Network) Connect(oneID, otherID enode.ID) error { + net.lock.Lock() + defer net.lock.Unlock() + return net.connect(oneID, otherID) +} + +func (net *Network) connect(oneID, otherID enode.ID) error { log.Debug("Connecting nodes with addPeer", "id", oneID, "other", otherID) - conn, err := net.InitConn(oneID, otherID) + conn, err := net.initConn(oneID, otherID) if err != nil { return err } @@ -369,28 +397,11 @@ func (net *Network) DidReceive(sender, receiver enode.ID, proto string, code uin // GetNode gets the node with the given ID, returning nil if the node does not // exist func (net *Network) GetNode(id enode.ID) *Node { - net.lock.Lock() - defer net.lock.Unlock() + net.lock.RLock() + defer net.lock.RUnlock() return net.getNode(id) } -// GetNode gets the node with the given name, returning nil if the node does -// not exist -func (net *Network) GetNodeByName(name string) *Node { - net.lock.Lock() - defer net.lock.Unlock() - return net.getNodeByName(name) -} - -// GetNodes returns the existing nodes -func (net *Network) GetNodes() (nodes []*Node) { - net.lock.Lock() - defer net.lock.Unlock() - - nodes = append(nodes, net.Nodes...) - return nodes -} - func (net *Network) getNode(id enode.ID) *Node { i, found := net.nodeMap[id] if !found { @@ -399,6 +410,14 @@ func (net *Network) getNode(id enode.ID) *Node { return net.Nodes[i] } +// GetNode gets the node with the given name, returning nil if the node does +// not exist +func (net *Network) GetNodeByName(name string) *Node { + net.lock.RLock() + defer net.lock.RUnlock() + return net.getNodeByName(name) +} + func (net *Network) getNodeByName(name string) *Node { for _, node := range net.Nodes { if node.Config.Name == name { @@ -408,11 +427,85 @@ func (net *Network) getNodeByName(name string) *Node { return nil } +// GetNodes returns the existing nodes +func (net *Network) GetNodes() (nodes []*Node) { + net.lock.RLock() + defer net.lock.RUnlock() + + return net.getNodes() +} + +func (net *Network) getNodes() (nodes []*Node) { + nodes = append(nodes, net.Nodes...) + return nodes +} + +// GetRandomUpNode returns a random node on the network, which is running. +func (net *Network) GetRandomUpNode(excludeIDs ...enode.ID) *Node { + net.lock.RLock() + defer net.lock.RUnlock() + return net.getRandomUpNode(excludeIDs...) +} + +// GetRandomUpNode returns a random node on the network, which is running. +func (net *Network) getRandomUpNode(excludeIDs ...enode.ID) *Node { + return net.getRandomNode(net.getUpNodeIDs(), excludeIDs) +} + +func (net *Network) getUpNodeIDs() (ids []enode.ID) { + for _, node := range net.Nodes { + if node.Up() { + ids = append(ids, node.ID()) + } + } + return ids +} + +// GetRandomDownNode returns a random node on the network, which is stopped. +func (net *Network) GetRandomDownNode(excludeIDs ...enode.ID) *Node { + net.lock.RLock() + defer net.lock.RUnlock() + return net.getRandomNode(net.getDownNodeIDs(), excludeIDs) +} + +func (net *Network) getDownNodeIDs() (ids []enode.ID) { + for _, node := range net.getNodes() { + if !node.Up() { + ids = append(ids, node.ID()) + } + } + return ids +} + +func (net *Network) getRandomNode(ids []enode.ID, excludeIDs []enode.ID) *Node { + filtered := filterIDs(ids, excludeIDs) + + l := len(filtered) + if l == 0 { + return nil + } + return net.getNode(filtered[rand.Intn(l)]) +} + +func filterIDs(ids []enode.ID, excludeIDs []enode.ID) []enode.ID { + exclude := make(map[enode.ID]bool) + for _, id := range excludeIDs { + exclude[id] = true + } + var filtered []enode.ID + for _, id := range ids { + if _, found := exclude[id]; !found { + filtered = append(filtered, id) + } + } + return filtered +} + // GetConn returns the connection which exists between "one" and "other" // regardless of which node initiated the connection func (net *Network) GetConn(oneID, otherID enode.ID) *Conn { - net.lock.Lock() - defer net.lock.Unlock() + net.lock.RLock() + defer net.lock.RUnlock() return net.getConn(oneID, otherID) } @@ -458,7 +551,7 @@ func (net *Network) getConn(oneID, otherID enode.ID) *Conn { return net.Conns[i] } -// InitConn(one, other) retrieves the connectiton model for the connection between +// InitConn(one, other) retrieves the connection model for the connection between // peers one and other, or creates a new one if it does not exist // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) // it checks if the connection is already up, and if the nodes are running @@ -469,6 +562,10 @@ func (net *Network) getConn(oneID, otherID enode.ID) *Conn { func (net *Network) InitConn(oneID, otherID enode.ID) (*Conn, error) { net.lock.Lock() defer net.lock.Unlock() + return net.initConn(oneID, otherID) +} + +func (net *Network) initConn(oneID, otherID enode.ID) (*Conn, error) { if oneID == otherID { return nil, fmt.Errorf("refusing to connect to self %v", oneID) } @@ -500,12 +597,18 @@ func (net *Network) Shutdown() { if err := node.Stop(); err != nil { log.Warn("Can't stop node", "id", node.ID(), "err", err) } + // If the node has the close method, call it. + if closer, ok := node.Node.(io.Closer); ok { + if err := closer.Close(); err != nil { + log.Warn("Can't close node", "id", node.ID(), "err", err) + } + } } close(net.quitc) } -//Reset resets all network properties: -//emtpies the nodes and the connection list +// Reset resets all network properties: +// empties the nodes and the connection list func (net *Network) Reset() { net.lock.Lock() defer net.lock.Unlock() @@ -526,8 +629,21 @@ type Node struct { // Config if the config used to created the node Config *adapters.NodeConfig `json:"config"` - // Up tracks whether or not the node is running - Up bool `json:"up"` + // up tracks whether or not the node is running + up bool + upMu sync.RWMutex +} + +func (n *Node) Up() bool { + n.upMu.RLock() + defer n.upMu.RUnlock() + return n.up +} + +func (n *Node) SetUp(up bool) { + n.upMu.Lock() + defer n.upMu.Unlock() + n.up = up } // ID returns the ID of the node @@ -561,10 +677,29 @@ func (n *Node) MarshalJSON() ([]byte, error) { }{ Info: n.NodeInfo(), Config: n.Config, - Up: n.Up, + Up: n.Up(), }) } +// UnmarshalJSON implements json.Unmarshaler interface so that we don't lose +// Node.up status. IMPORTANT: The implementation is incomplete; we lose +// p2p.NodeInfo. +func (n *Node) UnmarshalJSON(raw []byte) error { + // TODO: How should we turn back NodeInfo into n.Node? + // Ticket: https://github.com/ethersphere/go-ethereum/issues/1177 + node := struct { + Config *adapters.NodeConfig `json:"config,omitempty"` + Up bool `json:"up"` + }{} + if err := json.Unmarshal(raw, &node); err != nil { + return err + } + + n.SetUp(node.Up) + n.Config = node.Config + return nil +} + // Conn represents a connection between two nodes in the network type Conn struct { // One is the node which initiated the connection @@ -584,10 +719,10 @@ type Conn struct { // nodesUp returns whether both nodes are currently up func (c *Conn) nodesUp() error { - if !c.one.Up { + if !c.one.Up() { return fmt.Errorf("one %v is not up", c.One) } - if !c.other.Up { + if !c.other.Up() { return fmt.Errorf("other %v is not up", c.Other) } return nil @@ -659,7 +794,7 @@ func (net *Network) snapshot(addServices []string, removeServices []string) (*Sn } for i, node := range net.Nodes { snap.Nodes[i] = NodeSnapshot{Node: *node} - if !node.Up { + if !node.Up() { continue } snapshots, err := node.Snapshots() @@ -705,22 +840,89 @@ func (net *Network) snapshot(addServices []string, removeServices []string) (*Sn return snap, nil } +// longrunning tests may need a longer timeout +var snapshotLoadTimeout = 900 * time.Second + // Load loads a network snapshot func (net *Network) Load(snap *Snapshot) error { + // Start nodes. for _, n := range snap.Nodes { if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { return err } - if !n.Node.Up { + if !n.Node.Up() { continue } if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { return err } } + + // Prepare connection events counter. + allConnected := make(chan struct{}) // closed when all connections are established + done := make(chan struct{}) // ensures that the event loop goroutine is terminated + defer close(done) + + // Subscribe to event channel. + // It needs to be done outside of the event loop goroutine (created below) + // to ensure that the event channel is blocking before connect calls are made. + events := make(chan *Event) + sub := net.Events().Subscribe(events) + defer sub.Unsubscribe() + + go func() { + // Expected number of connections. + total := len(snap.Conns) + // Set of all established connections from the snapshot, not other connections. + // Key array element 0 is the connection One field value, and element 1 connection Other field. + connections := make(map[[2]enode.ID]struct{}, total) + + for { + select { + case e := <-events: + // Ignore control events as they do not represent + // connect or disconnect (Up) state change. + if e.Control { + continue + } + // Detect only connection events. + if e.Type != EventTypeConn { + continue + } + connection := [2]enode.ID{e.Conn.One, e.Conn.Other} + // Nodes are still not connected or have been disconnected. + if !e.Conn.Up { + // Delete the connection from the set of established connections. + // This will prevent false positive in case disconnections happen. + delete(connections, connection) + log.Warn("load snapshot: unexpected disconnection", "one", e.Conn.One, "other", e.Conn.Other) + continue + } + // Check that the connection is from the snapshot. + for _, conn := range snap.Conns { + if conn.One == e.Conn.One && conn.Other == e.Conn.Other { + // Add the connection to the set of established connections. + connections[connection] = struct{}{} + if len(connections) == total { + // Signal that all nodes are connected. + close(allConnected) + return + } + + break + } + } + case <-done: + // Load function returned, terminate this goroutine. + return + } + } + }() + + // Start connecting. for _, conn := range snap.Conns { - if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up { + if !net.GetNode(conn.One).Up() || !net.GetNode(conn.Other).Up() { //in this case, at least one of the nodes of a connection is not up, //so it would result in the snapshot `Load` to fail continue @@ -729,6 +931,14 @@ func (net *Network) Load(snap *Snapshot) error { return err } } + + select { + // Wait until all connections from the snapshot are established. + case <-allConnected: + // Make sure that we do not wait forever. + case <-time.After(snapshotLoadTimeout): + return errors.New("snapshot connections not established") + } return nil } @@ -766,7 +976,7 @@ func (net *Network) executeControlEvent(event *Event) { } func (net *Network) executeNodeEvent(e *Event) error { - if !e.Node.Up { + if !e.Node.Up() { return net.Stop(e.Node.ID()) } diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network_test.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network_test.go index f3493526..01cd1000 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network_test.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/network_test.go @@ -18,14 +18,267 @@ package simulations import ( "context" + "encoding/json" "fmt" + "reflect" + "strconv" + "strings" "testing" "time" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) +// Tests that a created snapshot with a minimal service only contains the expected connections +// and that a network when loaded with this snapshot only contains those same connections +func TestSnapshot(t *testing.T) { + + // PART I + // create snapshot from ring network + + // this is a minimal service, whose protocol will take exactly one message OR close of connection before quitting + adapter := adapters.NewSimAdapter(adapters.Services{ + "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) { + return NewNoopService(nil), nil + }, + }) + + // create network + network := NewNetwork(adapter, &NetworkConfig{ + DefaultService: "noopwoop", + }) + // \todo consider making a member of network, set to true threadsafe when shutdown + runningOne := true + defer func() { + if runningOne { + network.Shutdown() + } + }() + + // create and start nodes + nodeCount := 20 + ids := make([]enode.ID, nodeCount) + for i := 0; i < nodeCount; i++ { + conf := adapters.RandomNodeConfig() + node, err := network.NewNodeWithConfig(conf) + if err != nil { + t.Fatalf("error creating node: %s", err) + } + if err := network.Start(node.ID()); err != nil { + t.Fatalf("error starting node: %s", err) + } + ids[i] = node.ID() + } + + // subscribe to peer events + evC := make(chan *Event) + sub := network.Events().Subscribe(evC) + defer sub.Unsubscribe() + + // connect nodes in a ring + // spawn separate thread to avoid deadlock in the event listeners + go func() { + for i, id := range ids { + peerID := ids[(i+1)%len(ids)] + if err := network.Connect(id, peerID); err != nil { + t.Fatal(err) + } + } + }() + + // collect connection events up to expected number + ctx, cancel := context.WithTimeout(context.TODO(), time.Second) + defer cancel() + checkIds := make(map[enode.ID][]enode.ID) + connEventCount := nodeCount +OUTER: + for { + select { + case <-ctx.Done(): + t.Fatal(ctx.Err()) + case ev := <-evC: + if ev.Type == EventTypeConn && !ev.Control { + + // fail on any disconnect + if !ev.Conn.Up { + t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) + } + checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other) + checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One) + connEventCount-- + log.Debug("ev", "count", connEventCount) + if connEventCount == 0 { + break OUTER + } + } + } + } + + // create snapshot of current network + snap, err := network.Snapshot() + if err != nil { + t.Fatal(err) + } + j, err := json.Marshal(snap) + if err != nil { + t.Fatal(err) + } + log.Debug("snapshot taken", "nodes", len(snap.Nodes), "conns", len(snap.Conns), "json", string(j)) + + // verify that the snap element numbers check out + if len(checkIds) != len(snap.Conns) || len(checkIds) != len(snap.Nodes) { + t.Fatalf("snapshot wrong node,conn counts %d,%d != %d", len(snap.Nodes), len(snap.Conns), len(checkIds)) + } + + // shut down sim network + runningOne = false + sub.Unsubscribe() + network.Shutdown() + + // check that we have all the expected connections in the snapshot + for nodid, nodConns := range checkIds { + for _, nodConn := range nodConns { + var match bool + for _, snapConn := range snap.Conns { + if snapConn.One == nodid && snapConn.Other == nodConn { + match = true + break + } else if snapConn.Other == nodid && snapConn.One == nodConn { + match = true + break + } + } + if !match { + t.Fatalf("snapshot missing conn %v -> %v", nodid, nodConn) + } + } + } + log.Info("snapshot checked") + + // PART II + // load snapshot and verify that exactly same connections are formed + + adapter = adapters.NewSimAdapter(adapters.Services{ + "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) { + return NewNoopService(nil), nil + }, + }) + network = NewNetwork(adapter, &NetworkConfig{ + DefaultService: "noopwoop", + }) + defer func() { + network.Shutdown() + }() + + // subscribe to peer events + // every node up and conn up event will generate one additional control event + // therefore multiply the count by two + evC = make(chan *Event, (len(snap.Conns)*2)+(len(snap.Nodes)*2)) + sub = network.Events().Subscribe(evC) + defer sub.Unsubscribe() + + // load the snapshot + // spawn separate thread to avoid deadlock in the event listeners + err = network.Load(snap) + if err != nil { + t.Fatal(err) + } + + // collect connection events up to expected number + ctx, cancel = context.WithTimeout(context.TODO(), time.Second*3) + defer cancel() + + connEventCount = nodeCount + +OuterTwo: + for { + select { + case <-ctx.Done(): + t.Fatal(ctx.Err()) + case ev := <-evC: + if ev.Type == EventTypeConn && !ev.Control { + + // fail on any disconnect + if !ev.Conn.Up { + t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) + } + log.Debug("conn", "on", ev.Conn.One, "other", ev.Conn.Other) + checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other) + checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One) + connEventCount-- + log.Debug("ev", "count", connEventCount) + if connEventCount == 0 { + break OuterTwo + } + } + } + } + + // check that we have all expected connections in the network + for _, snapConn := range snap.Conns { + var match bool + for nodid, nodConns := range checkIds { + for _, nodConn := range nodConns { + if snapConn.One == nodid && snapConn.Other == nodConn { + match = true + break + } else if snapConn.Other == nodid && snapConn.One == nodConn { + match = true + break + } + } + } + if !match { + t.Fatalf("network missing conn %v -> %v", snapConn.One, snapConn.Other) + } + } + + // verify that network didn't generate any other additional connection events after the ones we have collected within a reasonable period of time + ctx, cancel = context.WithTimeout(context.TODO(), time.Second) + defer cancel() + select { + case <-ctx.Done(): + case ev := <-evC: + if ev.Type == EventTypeConn { + t.Fatalf("Superfluous conn found %v -> %v", ev.Conn.One, ev.Conn.Other) + } + } + + // This test validates if all connections from the snapshot + // are created in the network. + t.Run("conns after load", func(t *testing.T) { + // Create new network. + n := NewNetwork( + adapters.NewSimAdapter(adapters.Services{ + "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) { + return NewNoopService(nil), nil + }, + }), + &NetworkConfig{ + DefaultService: "noopwoop", + }, + ) + defer n.Shutdown() + + // Load the same snapshot. + err := n.Load(snap) + if err != nil { + t.Fatal(err) + } + + // Check every connection from the snapshot + // if it is in the network, too. + for _, c := range snap.Conns { + if n.GetConn(c.One, c.Other) == nil { + t.Errorf("missing connection: %s -> %s", c.One, c.Other) + } + } + }) +} + // TestNetworkSimulation creates a multi-node simulation network with each node // connected in a ring topology, checks that all nodes successfully handshake // with each other and that a snapshot fully represents the desired topology @@ -158,3 +411,212 @@ func triggerChecks(ctx context.Context, ids []enode.ID, trigger chan enode.ID, i } } } + +// \todo: refactor to implement shapshots +// and connect configuration methods once these are moved from +// swarm/network/simulations/connect.go +func BenchmarkMinimalService(b *testing.B) { + b.Run("ring/32", benchmarkMinimalServiceTmp) +} + +func benchmarkMinimalServiceTmp(b *testing.B) { + + // stop timer to discard setup time pollution + args := strings.Split(b.Name(), "/") + nodeCount, err := strconv.ParseInt(args[2], 10, 16) + if err != nil { + b.Fatal(err) + } + + for i := 0; i < b.N; i++ { + // this is a minimal service, whose protocol will close a channel upon run of protocol + // making it possible to bench the time it takes for the service to start and protocol actually to be run + protoCMap := make(map[enode.ID]map[enode.ID]chan struct{}) + adapter := adapters.NewSimAdapter(adapters.Services{ + "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) { + protoCMap[ctx.Config.ID] = make(map[enode.ID]chan struct{}) + svc := NewNoopService(protoCMap[ctx.Config.ID]) + return svc, nil + }, + }) + + // create network + network := NewNetwork(adapter, &NetworkConfig{ + DefaultService: "noopwoop", + }) + defer network.Shutdown() + + // create and start nodes + ids := make([]enode.ID, nodeCount) + for i := 0; i < int(nodeCount); i++ { + conf := adapters.RandomNodeConfig() + node, err := network.NewNodeWithConfig(conf) + if err != nil { + b.Fatalf("error creating node: %s", err) + } + if err := network.Start(node.ID()); err != nil { + b.Fatalf("error starting node: %s", err) + } + ids[i] = node.ID() + } + + // ready, set, go + b.ResetTimer() + + // connect nodes in a ring + for i, id := range ids { + peerID := ids[(i+1)%len(ids)] + if err := network.Connect(id, peerID); err != nil { + b.Fatal(err) + } + } + + // wait for all protocols to signal to close down + ctx, cancel := context.WithTimeout(context.TODO(), time.Second) + defer cancel() + for nodid, peers := range protoCMap { + for peerid, peerC := range peers { + log.Debug("getting ", "node", nodid, "peer", peerid) + select { + case <-ctx.Done(): + b.Fatal(ctx.Err()) + case <-peerC: + } + } + } + } +} + +func TestNode_UnmarshalJSON(t *testing.T) { + t.Run( + "test unmarshal of Node up field", + func(t *testing.T) { + runNodeUnmarshalJSON(t, casesNodeUnmarshalJSONUpField()) + }, + ) + t.Run( + "test unmarshal of Node Config field", + func(t *testing.T) { + runNodeUnmarshalJSON(t, casesNodeUnmarshalJSONConfigField()) + }, + ) +} + +func runNodeUnmarshalJSON(t *testing.T, tests []nodeUnmarshalTestCase) { + t.Helper() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got Node + if err := got.UnmarshalJSON([]byte(tt.marshaled)); err != nil { + expectErrorMessageToContain(t, err, tt.wantErr) + } + expectNodeEquality(t, got, tt.want) + }) + } +} + +type nodeUnmarshalTestCase struct { + name string + marshaled string + want Node + wantErr string +} + +func expectErrorMessageToContain(t *testing.T, got error, want string) { + t.Helper() + if got == nil && want == "" { + return + } + + if got == nil && want != "" { + t.Errorf("error was expected, got: nil, want: %v", want) + return + } + + if !strings.Contains(got.Error(), want) { + t.Errorf( + "unexpected error message, got %v, want: %v", + want, + got, + ) + } +} + +func expectNodeEquality(t *testing.T, got Node, want Node) { + t.Helper() + if !reflect.DeepEqual(got, want) { + t.Errorf("Node.UnmarshalJSON() = %v, want %v", got, want) + } +} + +func casesNodeUnmarshalJSONUpField() []nodeUnmarshalTestCase { + return []nodeUnmarshalTestCase{ + { + name: "empty json", + marshaled: "{}", + want: Node{ + up: false, + }, + }, + { + name: "a stopped node", + marshaled: "{\"up\": false}", + want: Node{ + up: false, + }, + }, + { + name: "a running node", + marshaled: "{\"up\": true}", + want: Node{ + up: true, + }, + }, + { + name: "invalid JSON value on valid key", + marshaled: "{\"up\": foo}", + wantErr: "invalid character", + }, + { + name: "invalid JSON key and value", + marshaled: "{foo: bar}", + wantErr: "invalid character", + }, + { + name: "bool value expected but got something else (string)", + marshaled: "{\"up\": \"true\"}", + wantErr: "cannot unmarshal string into Go struct", + }, + } +} + +func casesNodeUnmarshalJSONConfigField() []nodeUnmarshalTestCase { + // Don't do a big fuss around testing, as adapters.NodeConfig should + // handle it's own serialization. Just do a sanity check. + return []nodeUnmarshalTestCase{ + { + name: "Config field is omitted", + marshaled: "{}", + want: Node{ + Config: nil, + }, + }, + { + name: "Config field is nil", + marshaled: "{\"config\": nil}", + want: Node{ + Config: nil, + }, + }, + { + name: "a non default Config field", + marshaled: "{\"config\":{\"name\":\"node_ecdd0\",\"port\":44665}}", + want: Node{ + Config: &adapters.NodeConfig{ + Name: "node_ecdd0", + Port: 44665, + }, + }, + }, + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/simulations/test.go b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/test.go new file mode 100644 index 00000000..beeb414e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/p2p/simulations/test.go @@ -0,0 +1,134 @@ +package simulations + +import ( + "testing" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rpc" +) + +// NoopService is the service that does not do anything +// but implements node.Service interface. +type NoopService struct { + c map[enode.ID]chan struct{} +} + +func NewNoopService(ackC map[enode.ID]chan struct{}) *NoopService { + return &NoopService{ + c: ackC, + } +} + +func (t *NoopService) Protocols() []p2p.Protocol { + return []p2p.Protocol{ + { + Name: "noop", + Version: 666, + Length: 0, + Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error { + if t.c != nil { + t.c[peer.ID()] = make(chan struct{}) + close(t.c[peer.ID()]) + } + rw.ReadMsg() + return nil + }, + NodeInfo: func() interface{} { + return struct{}{} + }, + PeerInfo: func(id enode.ID) interface{} { + return struct{}{} + }, + Attributes: []enr.Entry{}, + }, + } +} + +func (t *NoopService) APIs() []rpc.API { + return []rpc.API{} +} + +func (t *NoopService) Start(server *p2p.Server) error { + return nil +} + +func (t *NoopService) Stop() error { + return nil +} + +func VerifyRing(t *testing.T, net *Network, ids []enode.ID) { + t.Helper() + n := len(ids) + for i := 0; i < n; i++ { + for j := i + 1; j < n; j++ { + c := net.GetConn(ids[i], ids[j]) + if i == j-1 || (i == 0 && j == n-1) { + if c == nil { + t.Errorf("nodes %v and %v are not connected, but they should be", i, j) + } + } else { + if c != nil { + t.Errorf("nodes %v and %v are connected, but they should not be", i, j) + } + } + } + } +} + +func VerifyChain(t *testing.T, net *Network, ids []enode.ID) { + t.Helper() + n := len(ids) + for i := 0; i < n; i++ { + for j := i + 1; j < n; j++ { + c := net.GetConn(ids[i], ids[j]) + if i == j-1 { + if c == nil { + t.Errorf("nodes %v and %v are not connected, but they should be", i, j) + } + } else { + if c != nil { + t.Errorf("nodes %v and %v are connected, but they should not be", i, j) + } + } + } + } +} + +func VerifyFull(t *testing.T, net *Network, ids []enode.ID) { + t.Helper() + n := len(ids) + var connections int + for i, lid := range ids { + for _, rid := range ids[i+1:] { + if net.GetConn(lid, rid) != nil { + connections++ + } + } + } + + want := n * (n - 1) / 2 + if connections != want { + t.Errorf("wrong number of connections, got: %v, want: %v", connections, want) + } +} + +func VerifyStar(t *testing.T, net *Network, ids []enode.ID, centerIndex int) { + t.Helper() + n := len(ids) + for i := 0; i < n; i++ { + for j := i + 1; j < n; j++ { + c := net.GetConn(ids[i], ids[j]) + if i == centerIndex || j == centerIndex { + if c == nil { + t.Errorf("nodes %v and %v are not connected, but they should be", i, j) + } + } else { + if c != nil { + t.Errorf("nodes %v and %v are connected, but they should not be", i, j) + } + } + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/p2p/testing/protocoltester.go b/vendor/github.com/ethereum/go-ethereum/p2p/testing/protocoltester.go index afc03b00..1e1752af 100644 --- a/vendor/github.com/ethereum/go-ethereum/p2p/testing/protocoltester.go +++ b/vendor/github.com/ethereum/go-ethereum/p2p/testing/protocoltester.go @@ -25,12 +25,12 @@ package testing import ( "bytes" + "crypto/ecdsa" "fmt" "io" "io/ioutil" "strings" "sync" - "testing" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -52,7 +52,7 @@ type ProtocolTester struct { // NewProtocolTester constructs a new ProtocolTester // it takes as argument the pivot node id, the number of dummy peers and the // protocol run function called on a peer connection by the p2p server -func NewProtocolTester(t *testing.T, id enode.ID, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester { +func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester { services := adapters.Services{ "test": func(ctx *adapters.ServiceContext) (node.Service, error) { return &testNode{run}, nil @@ -63,23 +63,30 @@ func NewProtocolTester(t *testing.T, id enode.ID, n int, run func(*p2p.Peer, p2p } adapter := adapters.NewSimAdapter(services) net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{}) - if _, err := net.NewNodeWithConfig(&adapters.NodeConfig{ - ID: id, + nodeConfig := &adapters.NodeConfig{ + PrivateKey: prvkey, EnableMsgEvents: true, Services: []string{"test"}, - }); err != nil { + } + if _, err := net.NewNodeWithConfig(nodeConfig); err != nil { panic(err.Error()) } - if err := net.Start(id); err != nil { + if err := net.Start(nodeConfig.ID); err != nil { panic(err.Error()) } - node := net.GetNode(id).Node.(*adapters.SimNode) - peers := make([]*adapters.NodeConfig, n) - nodes := make([]*enode.Node, n) - for i := 0; i < n; i++ { + node := net.GetNode(nodeConfig.ID).Node.(*adapters.SimNode) + peers := make([]*adapters.NodeConfig, nodeCount) + nodes := make([]*enode.Node, nodeCount) + for i := 0; i < nodeCount; i++ { peers[i] = adapters.RandomNodeConfig() peers[i].Services = []string{"mock"} + if _, err := net.NewNodeWithConfig(peers[i]); err != nil { + panic(fmt.Sprintf("error initializing peer %v: %v", peers[i].ID, err)) + } + if err := net.Start(peers[i].ID); err != nil { + panic(fmt.Sprintf("error starting peer %v: %v", peers[i].ID, err)) + } nodes[i] = peers[i].Node() } events := make(chan *p2p.PeerEvent, 1000) @@ -95,28 +102,20 @@ func NewProtocolTester(t *testing.T, id enode.ID, n int, run func(*p2p.Peer, p2p network: net, } - self.Connect(id, peers...) + self.Connect(nodeConfig.ID, peers...) return self } // Stop stops the p2p server -func (t *ProtocolTester) Stop() error { +func (t *ProtocolTester) Stop() { t.Server.Stop() - return nil } // Connect brings up the remote peer node and connects it using the // p2p/simulations network connection with the in memory network adapter func (t *ProtocolTester) Connect(selfID enode.ID, peers ...*adapters.NodeConfig) { for _, peer := range peers { - log.Trace(fmt.Sprintf("start node %v", peer.ID)) - if _, err := t.network.NewNodeWithConfig(peer); err != nil { - panic(fmt.Sprintf("error starting peer %v: %v", peer.ID, err)) - } - if err := t.network.Start(peer.ID); err != nil { - panic(fmt.Sprintf("error starting peer %v: %v", peer.ID, err)) - } log.Trace(fmt.Sprintf("connect to %v", peer.ID)) if err := t.network.Connect(selfID, peer.ID); err != nil { panic(fmt.Sprintf("error connecting to peer %v: %v", peer.ID, err)) diff --git a/vendor/github.com/ethereum/go-ethereum/params/bootnodes.go b/vendor/github.com/ethereum/go-ethereum/params/bootnodes.go index c7190ae6..bdaa4a18 100644 --- a/vendor/github.com/ethereum/go-ethereum/params/bootnodes.go +++ b/vendor/github.com/ethereum/go-ethereum/params/bootnodes.go @@ -47,6 +47,20 @@ var RinkebyBootnodes = []string{ "enode://b6b28890b006743680c52e64e0d16db57f28124885595fa03a562be1d2bf0f3a1da297d56b13da25fb992888fd556d4c1a27b1f39d531bde7de1921c90061cc6@159.89.28.211:30303", // AKASHA } +// GoerliBootnodes are the enode URLs of the P2P bootstrap nodes running on the +// Görli test network. +var GoerliBootnodes = []string{ + // Upstrem bootnodes + "enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303", + "enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303", + "enode://46add44b9f13965f7b9875ac6b85f016f341012d84f975377573800a863526f4da19ae2c620ec73d11591fa9510e992ecc03ad0751f53cc02f7c7ed6d55c7291@94.237.54.114:30313", + "enode://c1f8b7c2ac4453271fa07d8e9ecf9a2e8285aa0bd0c07df0131f47153306b0736fd3db8924e7a9bf0bed6b1d8d4f87362a71b033dc7c64547728d953e43e59b2@52.64.155.147:30303", + "enode://f4a9c6ee28586009fb5a96c8af13a58ed6d8315a9eee4772212c1d4d9cebe5a8b8a78ea4434f318726317d04a3f531a1ef0420cf9752605a562cfe858c46e263@213.186.16.82:30303", + + // Ethereum Foundation bootnode + "enode://573b6607cd59f241e30e4c4943fd50e99e2b6f42f9bd5ca111659d309c06741247f4f1e93843ad3e8c8c18b6e2d94c161b7ef67479b3938780a97134b618b5ce@52.56.136.200:30303", +} + // DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the // experimental RLPx v5 topic-discovery network. var DiscoveryV5Bootnodes = []string{ diff --git a/vendor/github.com/ethereum/go-ethereum/params/config.go b/vendor/github.com/ethereum/go-ethereum/params/config.go index 007e4a66..44b2ffeb 100644 --- a/vendor/github.com/ethereum/go-ethereum/params/config.go +++ b/vendor/github.com/ethereum/go-ethereum/params/config.go @@ -42,17 +42,18 @@ var ( EIP155Block: big.NewInt(2675000), EIP158Block: big.NewInt(2675000), ByzantiumBlock: big.NewInt(4370000), - ConstantinopleBlock: nil, + ConstantinopleBlock: big.NewInt(7280000), + PetersburgBlock: big.NewInt(7280000), Ethash: new(EthashConfig), } // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. MainnetTrustedCheckpoint = &TrustedCheckpoint{ Name: "mainnet", - SectionIndex: 203, - SectionHead: common.HexToHash("0xc9e05fc67c6a9815adc8072eb18805b53da53a9a6a273e05541e1b7542cf937a"), - CHTRoot: common.HexToHash("0xb85f42447d59f7c3e6679b9a37ed983593fd52efd6251b883592662e95769d5b"), - BloomRoot: common.HexToHash("0xf93d50cb4c49b403c6fd33cd60896d3b36184275be0a51bae4df5e8844ac624c"), + SectionIndex: 216, + SectionHead: common.HexToHash("0xae3e551c8d60d06fd411a8e6008e90625d3bb0cbbf664b65d5ed90b318553541"), + CHTRoot: common.HexToHash("0xeea7d2ab3545a37deecc66fc43c9556ae337c3ea1c6893e401428207bdb8e434"), + BloomRoot: common.HexToHash("0xb0d4176d160d67b99a9f963281e52bce0583a566b74b4497fe3ed24ae04004ff"), } // TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network. @@ -67,16 +68,17 @@ var ( EIP158Block: big.NewInt(10), ByzantiumBlock: big.NewInt(1700000), ConstantinopleBlock: big.NewInt(4230000), + PetersburgBlock: big.NewInt(4939394), Ethash: new(EthashConfig), } // TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. TestnetTrustedCheckpoint = &TrustedCheckpoint{ Name: "testnet", - SectionIndex: 134, - SectionHead: common.HexToHash("0x17053ecbe045bebefaa01e7716cc85a4e22647e181416cc1098ccbb73a088931"), - CHTRoot: common.HexToHash("0x4d2b86422e46ed76f0e3f50f06632c409f809c8375e53c8bc0f782bcb93dd49a"), - BloomRoot: common.HexToHash("0xccba62232ee56c2967afc58f136a47ba7dc545ae586e6be666430d94516306c7"), + SectionIndex: 148, + SectionHead: common.HexToHash("0x4d3181bedb6aa96a6f3efa866c71f7802400d0fb4a6906946c453630d850efc0"), + CHTRoot: common.HexToHash("0x25df2f9d63a5f84b2852988f0f0f7af5a7877da061c11b85c812780b5a27a5ec"), + BloomRoot: common.HexToHash("0x0584834e5222471a06c669d210e302ca602780eaaddd04634fd65471c2a91419"), } // RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network. @@ -90,7 +92,8 @@ var ( EIP155Block: big.NewInt(3), EIP158Block: big.NewInt(3), ByzantiumBlock: big.NewInt(1035301), - ConstantinopleBlock: nil, + ConstantinopleBlock: big.NewInt(3660663), + PetersburgBlock: big.NewInt(9999999), //TODO! Insert Rinkeby block number Clique: &CliqueConfig{ Period: 15, Epoch: 30000, @@ -100,10 +103,37 @@ var ( // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. RinkebyTrustedCheckpoint = &TrustedCheckpoint{ Name: "rinkeby", - SectionIndex: 100, - SectionHead: common.HexToHash("0xf18f9b43e16f37b12e68818536ffe455ff18d676274ffdd856a8520ed61bb514"), - CHTRoot: common.HexToHash("0x473f5d603b1fedad75d97fd58692130b9ac9ade1aca01eb9363d79bd1c43c791"), - BloomRoot: common.HexToHash("0xa39ced3ddbb87e909c7531df2afb6414bea9c9a60ab94da9c6b467535f05326e"), + SectionIndex: 113, + SectionHead: common.HexToHash("0xb812f3095af3af1cb2de7d7c2086ee807736a7315992c461b0986699185daf77"), + CHTRoot: common.HexToHash("0x5416d0924925eb835987ad3d1f059ecc66778c51959c8246a7a35b22ec5f3109"), + BloomRoot: common.HexToHash("0xcf74ca2c14e843b366561dab4fc64237bf6bb335119cbc97d723f3b501863470"), + } + + // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. + GoerliChainConfig = &ChainConfig{ + ChainID: big.NewInt(5), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + Clique: &CliqueConfig{ + Period: 15, + Epoch: 30000, + }, + } + + // GoerliTrustedCheckpoint contains the light client trusted checkpoint for the Görli test network. + GoerliTrustedCheckpoint = &TrustedCheckpoint{ + Name: "goerli", + SectionIndex: 0, + SectionHead: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + CHTRoot: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + BloomRoot: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced @@ -111,16 +141,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -158,6 +188,7 @@ type ChainConfig struct { ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) + PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) // Various consensus engines @@ -195,7 +226,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Engine: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v ConstantinopleFix: %v Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -205,6 +236,7 @@ func (c *ChainConfig) String() string { c.EIP158Block, c.ByzantiumBlock, c.ConstantinopleBlock, + c.PetersburgBlock, engine, ) } @@ -244,6 +276,13 @@ func (c *ChainConfig) IsConstantinople(num *big.Int) bool { return isForked(c.ConstantinopleBlock, num) } +// IsPetersburg returns whether num is either +// - equal to or greater than the PetersburgBlock fork block, +// - OR is nil, and Constantinople is active +func (c *ChainConfig) IsPetersburg(num *big.Int) bool { + return isForked(c.PetersburgBlock, num) || c.PetersburgBlock == nil && isForked(c.ConstantinopleBlock, num) +} + // IsEWASM returns whether num represents a block number after the EWASM fork func (c *ChainConfig) IsEWASM(num *big.Int) bool { return isForked(c.EWASMBlock, num) @@ -314,6 +353,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) { return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock) } + if isForkIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, head) { + return newCompatError("ConstantinopleFix fork block", c.PetersburgBlock, newcfg.PetersburgBlock) + } if isForkIncompatible(c.EWASMBlock, newcfg.EWASMBlock, head) { return newCompatError("ewasm fork block", c.EWASMBlock, newcfg.EWASMBlock) } @@ -381,9 +423,9 @@ func (err *ConfigCompatError) Error() string { // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. type Rules struct { - ChainID *big.Int - IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool - IsByzantium, IsConstantinople bool + ChainID *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool + IsByzantium, IsConstantinople, IsPetersburg bool } // Rules ensures c's ChainID is not nil. @@ -400,5 +442,6 @@ func (c *ChainConfig) Rules(num *big.Int) Rules { IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num), IsConstantinople: c.IsConstantinople(num), + IsPetersburg: c.IsPetersburg(num), } } diff --git a/vendor/github.com/ethereum/go-ethereum/params/protocol_params.go b/vendor/github.com/ethereum/go-ethereum/params/protocol_params.go index c8b6609a..14750f6a 100644 --- a/vendor/github.com/ethereum/go-ethereum/params/protocol_params.go +++ b/vendor/github.com/ethereum/go-ethereum/params/protocol_params.go @@ -52,7 +52,7 @@ const ( NetSstoreResetRefund uint64 = 4800 // Once per SSTORE operation for resetting to the original non-zero value NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value - JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero. + JumpdestGas uint64 = 1 // Once per JUMPDEST operation. EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. CallGas uint64 = 40 // Once per CALL operation & message call transaction. CreateDataGas uint64 = 200 // diff --git a/vendor/github.com/ethereum/go-ethereum/params/version.go b/vendor/github.com/ethereum/go-ethereum/params/version.go index 1abbd1a7..d3954e0b 100644 --- a/vendor/github.com/ethereum/go-ethereum/params/version.go +++ b/vendor/github.com/ethereum/go-ethereum/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 8 // Minor version component of the current release - VersionPatch = 18 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 9 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. diff --git a/vendor/github.com/ethereum/go-ethereum/rlp/decode.go b/vendor/github.com/ethereum/go-ethereum/rlp/decode.go index dbbe5995..e638c01e 100644 --- a/vendor/github.com/ethereum/go-ethereum/rlp/decode.go +++ b/vendor/github.com/ethereum/go-ethereum/rlp/decode.go @@ -26,6 +26,7 @@ import ( "math/big" "reflect" "strings" + "sync" ) var ( @@ -48,6 +49,10 @@ var ( errUintOverflow = errors.New("rlp: uint overflow") errNoPointer = errors.New("rlp: interface given to Decode must be a pointer") errDecodeIntoNil = errors.New("rlp: pointer given to Decode must not be nil") + + streamPool = sync.Pool{ + New: func() interface{} { return new(Stream) }, + } ) // Decoder is implemented by types that require custom RLP @@ -126,17 +131,24 @@ type Decoder interface { // // NewStream(r, limit).Decode(val) func Decode(r io.Reader, val interface{}) error { - // TODO: this could use a Stream from a pool. - return NewStream(r, 0).Decode(val) + stream := streamPool.Get().(*Stream) + defer streamPool.Put(stream) + + stream.Reset(r, 0) + return stream.Decode(val) } // DecodeBytes parses RLP data from b into val. // Please see the documentation of Decode for the decoding rules. // The input must contain exactly one value and no trailing data. func DecodeBytes(b []byte, val interface{}) error { - // TODO: this could use a Stream from a pool. r := bytes.NewReader(b) - if err := NewStream(r, uint64(len(b))).Decode(val); err != nil { + + stream := streamPool.Get().(*Stream) + defer streamPool.Put(stream) + + stream.Reset(r, uint64(len(b))) + if err := stream.Decode(val); err != nil { return err } if r.Len() > 0 { @@ -853,6 +865,7 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) { if s.uintbuf == nil { s.uintbuf = make([]byte, 8) } + s.byteval = 0 } // Kind returns the kind and size of the next value in the diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/client.go b/vendor/github.com/ethereum/go-ethereum/rpc/client.go index 6254c95f..02029dc8 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/client.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/client.go @@ -18,17 +18,13 @@ package rpc import ( "bytes" - "container/list" "context" "encoding/json" "errors" "fmt" - "net" "net/url" "reflect" "strconv" - "strings" - "sync" "sync/atomic" "time" @@ -39,13 +35,14 @@ var ( ErrClientQuit = errors.New("client is closed") ErrNoResult = errors.New("no result in JSON-RPC response") ErrSubscriptionQueueOverflow = errors.New("subscription queue overflow") + errClientReconnected = errors.New("client reconnected") + errDead = errors.New("connection lost") ) const ( // Timeouts tcpKeepAliveInterval = 30 * time.Second - defaultDialTimeout = 10 * time.Second // used when dialing if the context has no deadline - defaultWriteTimeout = 10 * time.Second // used for calls if the context has no deadline + defaultDialTimeout = 10 * time.Second // used if context has no deadline subscribeTimeout = 5 * time.Second // overall timeout eth_subscribe, rpc_modules calls ) @@ -76,56 +73,57 @@ type BatchElem struct { Error error } -// A value of this type can a JSON-RPC request, notification, successful response or -// error response. Which one it is depends on the fields. -type jsonrpcMessage struct { - Version string `json:"jsonrpc"` - ID json.RawMessage `json:"id,omitempty"` - Method string `json:"method,omitempty"` - Params json.RawMessage `json:"params,omitempty"` - Error *jsonError `json:"error,omitempty"` - Result json.RawMessage `json:"result,omitempty"` -} - -func (msg *jsonrpcMessage) isNotification() bool { - return msg.ID == nil && msg.Method != "" -} - -func (msg *jsonrpcMessage) isResponse() bool { - return msg.hasValidID() && msg.Method == "" && len(msg.Params) == 0 -} - -func (msg *jsonrpcMessage) hasValidID() bool { - return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '[' -} - -func (msg *jsonrpcMessage) String() string { - b, _ := json.Marshal(msg) - return string(b) -} - // Client represents a connection to an RPC server. type Client struct { - idCounter uint32 - connectFunc func(ctx context.Context) (net.Conn, error) - isHTTP bool + idgen func() ID // for subscriptions + isHTTP bool + services *serviceRegistry - // writeConn is only safe to access outside dispatch, with the - // write lock held. The write lock is taken by sending on - // requestOp and released by sending on sendDone. - writeConn net.Conn + idCounter uint32 + + // This function, if non-nil, is called when the connection is lost. + reconnectFunc reconnectFunc + + // writeConn is used for writing to the connection on the caller's goroutine. It should + // only be accessed outside of dispatch, with the write lock held. The write lock is + // taken by sending on requestOp and released by sending on sendDone. + writeConn jsonWriter // for dispatch close chan struct{} - closing chan struct{} // closed when client is quitting - didClose chan struct{} // closed when client quits - reconnected chan net.Conn // where write/reconnect sends the new connection - readErr chan error // errors from read - readResp chan []*jsonrpcMessage // valid messages from read - requestOp chan *requestOp // for registering response IDs - sendDone chan error // signals write completion, releases write lock - respWait map[string]*requestOp // active requests - subs map[string]*ClientSubscription // active subscriptions + closing chan struct{} // closed when client is quitting + didClose chan struct{} // closed when client quits + reconnected chan ServerCodec // where write/reconnect sends the new connection + readOp chan readOp // read messages + readErr chan error // errors from read + reqInit chan *requestOp // register response IDs, takes write lock + reqSent chan error // signals write completion, releases write lock + reqTimeout chan *requestOp // removes response IDs when call timeout expires +} + +type reconnectFunc func(ctx context.Context) (ServerCodec, error) + +type clientContextKey struct{} + +type clientConn struct { + codec ServerCodec + handler *handler +} + +func (c *Client) newClientConn(conn ServerCodec) *clientConn { + ctx := context.WithValue(context.Background(), clientContextKey{}, c) + handler := newHandler(ctx, conn, c.idgen, c.services) + return &clientConn{conn, handler} +} + +func (cc *clientConn) close(err error, inflightReq *requestOp) { + cc.handler.close(err, inflightReq) + cc.codec.Close() +} + +type readOp struct { + msgs []*jsonrpcMessage + batch bool } type requestOp struct { @@ -135,9 +133,14 @@ type requestOp struct { sub *ClientSubscription // only set for EthSubscribe requests } -func (op *requestOp) wait(ctx context.Context) (*jsonrpcMessage, error) { +func (op *requestOp) wait(ctx context.Context, c *Client) (*jsonrpcMessage, error) { select { case <-ctx.Done(): + // Send the timeout to dispatch so it can remove the request IDs. + select { + case c.reqTimeout <- op: + case <-c.closing: + } return nil, ctx.Err() case resp := <-op.resp: return resp, op.err @@ -181,36 +184,57 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) { } } -func newClient(initctx context.Context, connectFunc func(context.Context) (net.Conn, error)) (*Client, error) { - conn, err := connectFunc(initctx) +// Client retrieves the client from the context, if any. This can be used to perform +// 'reverse calls' in a handler method. +func ClientFromContext(ctx context.Context) (*Client, bool) { + client, ok := ctx.Value(clientContextKey{}).(*Client) + return client, ok +} + +func newClient(initctx context.Context, connect reconnectFunc) (*Client, error) { + conn, err := connect(initctx) if err != nil { return nil, err } + c := initClient(conn, randomIDGenerator(), new(serviceRegistry)) + c.reconnectFunc = connect + return c, nil +} + +func initClient(conn ServerCodec, idgen func() ID, services *serviceRegistry) *Client { _, isHTTP := conn.(*httpConn) c := &Client{ - writeConn: conn, + idgen: idgen, isHTTP: isHTTP, - connectFunc: connectFunc, + services: services, + writeConn: conn, close: make(chan struct{}), closing: make(chan struct{}), didClose: make(chan struct{}), - reconnected: make(chan net.Conn), + reconnected: make(chan ServerCodec), + readOp: make(chan readOp), readErr: make(chan error), - readResp: make(chan []*jsonrpcMessage), - requestOp: make(chan *requestOp), - sendDone: make(chan error, 1), - respWait: make(map[string]*requestOp), - subs: make(map[string]*ClientSubscription), + reqInit: make(chan *requestOp), + reqSent: make(chan error, 1), + reqTimeout: make(chan *requestOp), } if !isHTTP { go c.dispatch(conn) } - return c, nil + return c +} + +// RegisterName creates a service for the given receiver type under the given name. When no +// methods on the given receiver match the criteria to be either a RPC method or a +// subscription an error is returned. Otherwise a new service is created and added to the +// service collection this client provides to the server. +func (c *Client) RegisterName(name string, receiver interface{}) error { + return c.services.registerName(name, receiver) } func (c *Client) nextID() json.RawMessage { id := atomic.AddUint32(&c.idCounter, 1) - return []byte(strconv.FormatUint(uint64(id), 10)) + return strconv.AppendUint(nil, uint64(id), 10) } // SupportedModules calls the rpc_modules method, retrieving the list of @@ -267,7 +291,7 @@ func (c *Client) CallContext(ctx context.Context, result interface{}, method str } // dispatch has accepted the request and will close the channel when it quits. - switch resp, err := op.wait(ctx); { + switch resp, err := op.wait(ctx, c); { case err != nil: return err case resp.Error != nil: @@ -325,7 +349,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { // Wait for all responses to come back. for n := 0; n < len(b) && err == nil; n++ { var resp *jsonrpcMessage - resp, err = op.wait(ctx) + resp, err = op.wait(ctx, c) if err != nil { break } @@ -352,6 +376,22 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { return err } +// Notify sends a notification, i.e. a method call that doesn't expect a response. +func (c *Client) Notify(ctx context.Context, method string, args ...interface{}) error { + op := new(requestOp) + msg, err := c.newMessage(method, args...) + if err != nil { + return err + } + msg.ID = nil + + if c.isHTTP { + return c.sendHTTP(ctx, op, msg) + } else { + return c.send(ctx, op, msg) + } +} + // EthSubscribe registers a subscripion under the "eth" namespace. func (c *Client) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) { return c.Subscribe(ctx, "eth", channel, args...) @@ -402,30 +442,30 @@ func (c *Client) Subscribe(ctx context.Context, namespace string, channel interf if err := c.send(ctx, op, msg); err != nil { return nil, err } - if _, err := op.wait(ctx); err != nil { + if _, err := op.wait(ctx, c); err != nil { return nil, err } return op.sub, nil } func (c *Client) newMessage(method string, paramsIn ...interface{}) (*jsonrpcMessage, error) { - params, err := json.Marshal(paramsIn) - if err != nil { - return nil, err + msg := &jsonrpcMessage{Version: vsn, ID: c.nextID(), Method: method} + if paramsIn != nil { // prevent sending "params":null + var err error + if msg.Params, err = json.Marshal(paramsIn); err != nil { + return nil, err + } } - return &jsonrpcMessage{Version: "2.0", ID: c.nextID(), Method: method, Params: params}, nil + return msg, nil } // send registers op with the dispatch loop, then sends msg on the connection. // if sending fails, op is deregistered. func (c *Client) send(ctx context.Context, op *requestOp, msg interface{}) error { select { - case c.requestOp <- op: - log.Trace("", "msg", log.Lazy{Fn: func() string { - return fmt.Sprint("sending ", msg) - }}) + case c.reqInit <- op: err := c.write(ctx, msg) - c.sendDone <- err + c.reqSent <- err return err case <-ctx.Done(): // This can happen if the client is overloaded or unable to keep up with @@ -433,25 +473,17 @@ func (c *Client) send(ctx context.Context, op *requestOp, msg interface{}) error return ctx.Err() case <-c.closing: return ErrClientQuit - case <-c.didClose: - return ErrClientQuit } } func (c *Client) write(ctx context.Context, msg interface{}) error { - deadline, ok := ctx.Deadline() - if !ok { - deadline = time.Now().Add(defaultWriteTimeout) - } // The previous write failed. Try to establish a new connection. if c.writeConn == nil { if err := c.reconnect(ctx); err != nil { return err } } - c.writeConn.SetWriteDeadline(deadline) - err := json.NewEncoder(c.writeConn).Encode(msg) - c.writeConn.SetWriteDeadline(time.Time{}) + err := c.writeConn.Write(ctx, msg) if err != nil { c.writeConn = nil } @@ -459,9 +491,18 @@ func (c *Client) write(ctx context.Context, msg interface{}) error { } func (c *Client) reconnect(ctx context.Context) error { - newconn, err := c.connectFunc(ctx) + if c.reconnectFunc == nil { + return errDead + } + + if _, ok := ctx.Deadline(); !ok { + var cancel func() + ctx, cancel = context.WithTimeout(ctx, defaultDialTimeout) + defer cancel() + } + newconn, err := c.reconnectFunc(ctx) if err != nil { - log.Trace(fmt.Sprintf("reconnect failed: %v", err)) + log.Trace("RPC client reconnect failed", "err", err) return err } select { @@ -477,322 +518,107 @@ func (c *Client) reconnect(ctx context.Context) error { // dispatch is the main loop of the client. // It sends read messages to waiting calls to Call and BatchCall // and subscription notifications to registered subscriptions. -func (c *Client) dispatch(conn net.Conn) { - // Spawn the initial read loop. - go c.read(conn) - +func (c *Client) dispatch(codec ServerCodec) { var ( - lastOp *requestOp // tracks last send operation - requestOpLock = c.requestOp // nil while the send lock is held - reading = true // if true, a read loop is running + lastOp *requestOp // tracks last send operation + reqInitLock = c.reqInit // nil while the send lock is held + conn = c.newClientConn(codec) + reading = true ) - defer close(c.didClose) defer func() { close(c.closing) - c.closeRequestOps(ErrClientQuit) - conn.Close() if reading { - // Empty read channels until read is dead. - for { - select { - case <-c.readResp: - case <-c.readErr: - return - } - } + conn.close(ErrClientQuit, nil) + c.drainRead() } + close(c.didClose) }() + // Spawn the initial read loop. + go c.read(codec) + for { select { case <-c.close: return - // Read path. - case batch := <-c.readResp: - for _, msg := range batch { - switch { - case msg.isNotification(): - log.Trace("", "msg", log.Lazy{Fn: func() string { - return fmt.Sprint("<-readResp: notification ", msg) - }}) - c.handleNotification(msg) - case msg.isResponse(): - log.Trace("", "msg", log.Lazy{Fn: func() string { - return fmt.Sprint("<-readResp: response ", msg) - }}) - c.handleResponse(msg) - default: - log.Debug("", "msg", log.Lazy{Fn: func() string { - return fmt.Sprint("<-readResp: dropping weird message", msg) - }}) - // TODO: maybe close - } + // Read path: + case op := <-c.readOp: + if op.batch { + conn.handler.handleBatch(op.msgs) + } else { + conn.handler.handleMsg(op.msgs[0]) } case err := <-c.readErr: - log.Debug("<-readErr", "err", err) - c.closeRequestOps(err) - conn.Close() + conn.handler.log.Debug("RPC connection read error", "err", err) + conn.close(err, lastOp) reading = false - case newconn := <-c.reconnected: - log.Debug("<-reconnected", "reading", reading, "remote", conn.RemoteAddr()) + // Reconnect: + case newcodec := <-c.reconnected: + log.Debug("RPC client reconnected", "reading", reading, "conn", newcodec.RemoteAddr()) if reading { - // Wait for the previous read loop to exit. This is a rare case. - conn.Close() - <-c.readErr + // Wait for the previous read loop to exit. This is a rare case which + // happens if this loop isn't notified in time after the connection breaks. + // In those cases the caller will notice first and reconnect. Closing the + // handler terminates all waiting requests (closing op.resp) except for + // lastOp, which will be transferred to the new handler. + conn.close(errClientReconnected, lastOp) + c.drainRead() } - go c.read(newconn) + go c.read(newcodec) reading = true - conn = newconn + conn = c.newClientConn(newcodec) + // Re-register the in-flight request on the new handler + // because that's where it will be sent. + conn.handler.addRequestOp(lastOp) - // Send path. - case op := <-requestOpLock: - // Stop listening for further send ops until the current one is done. - requestOpLock = nil + // Send path: + case op := <-reqInitLock: + // Stop listening for further requests until the current one has been sent. + reqInitLock = nil lastOp = op - for _, id := range op.ids { - c.respWait[string(id)] = op - } + conn.handler.addRequestOp(op) - case err := <-c.sendDone: + case err := <-c.reqSent: if err != nil { - // Remove response handlers for the last send. We remove those here - // because the error is already handled in Call or BatchCall. When the - // read loop goes down, it will signal all other current operations. - for _, id := range lastOp.ids { - delete(c.respWait, string(id)) - } + // Remove response handlers for the last send. When the read loop + // goes down, it will signal all other current operations. + conn.handler.removeRequestOp(lastOp) } - // Listen for send ops again. - requestOpLock = c.requestOp + // Let the next request in. + reqInitLock = c.reqInit lastOp = nil + + case op := <-c.reqTimeout: + conn.handler.removeRequestOp(op) } } } -// closeRequestOps unblocks pending send ops and active subscriptions. -func (c *Client) closeRequestOps(err error) { - didClose := make(map[*requestOp]bool) - - for id, op := range c.respWait { - // Remove the op so that later calls will not close op.resp again. - delete(c.respWait, id) - - if !didClose[op] { - op.err = err - close(op.resp) - didClose[op] = true - } - } - for id, sub := range c.subs { - delete(c.subs, id) - sub.quitWithError(err, false) - } -} - -func (c *Client) handleNotification(msg *jsonrpcMessage) { - if !strings.HasSuffix(msg.Method, notificationMethodSuffix) { - log.Debug("dropping non-subscription message", "msg", msg) - return - } - var subResult struct { - ID string `json:"subscription"` - Result json.RawMessage `json:"result"` - } - if err := json.Unmarshal(msg.Params, &subResult); err != nil { - log.Debug("dropping invalid subscription message", "msg", msg) - return - } - if c.subs[subResult.ID] != nil { - c.subs[subResult.ID].deliver(subResult.Result) - } -} - -func (c *Client) handleResponse(msg *jsonrpcMessage) { - op := c.respWait[string(msg.ID)] - if op == nil { - log.Debug("unsolicited response", "msg", msg) - return - } - delete(c.respWait, string(msg.ID)) - // For normal responses, just forward the reply to Call/BatchCall. - if op.sub == nil { - op.resp <- msg - return - } - // For subscription responses, start the subscription if the server - // indicates success. EthSubscribe gets unblocked in either case through - // the op.resp channel. - defer close(op.resp) - if msg.Error != nil { - op.err = msg.Error - return - } - if op.err = json.Unmarshal(msg.Result, &op.sub.subid); op.err == nil { - go op.sub.start() - c.subs[op.sub.subid] = op.sub - } -} - -// Reading happens on a dedicated goroutine. - -func (c *Client) read(conn net.Conn) error { - var ( - buf json.RawMessage - dec = json.NewDecoder(conn) - ) - readMessage := func() (rs []*jsonrpcMessage, err error) { - buf = buf[:0] - if err = dec.Decode(&buf); err != nil { - return nil, err - } - if isBatch(buf) { - err = json.Unmarshal(buf, &rs) - } else { - rs = make([]*jsonrpcMessage, 1) - err = json.Unmarshal(buf, &rs[0]) - } - return rs, err - } - +// drainRead drops read messages until an error occurs. +func (c *Client) drainRead() { for { - resp, err := readMessage() + select { + case <-c.readOp: + case <-c.readErr: + return + } + } +} + +// read decodes RPC messages from a codec, feeding them into dispatch. +func (c *Client) read(codec ServerCodec) { + for { + msgs, batch, err := codec.Read() + if _, ok := err.(*json.SyntaxError); ok { + codec.Write(context.Background(), errorMessage(&parseError{err.Error()})) + } if err != nil { c.readErr <- err - return err + return } - c.readResp <- resp + c.readOp <- readOp{msgs, batch} } } - -// Subscriptions. - -// A ClientSubscription represents a subscription established through EthSubscribe. -type ClientSubscription struct { - client *Client - etype reflect.Type - channel reflect.Value - namespace string - subid string - in chan json.RawMessage - - quitOnce sync.Once // ensures quit is closed once - quit chan struct{} // quit is closed when the subscription exits - errOnce sync.Once // ensures err is closed once - err chan error -} - -func newClientSubscription(c *Client, namespace string, channel reflect.Value) *ClientSubscription { - sub := &ClientSubscription{ - client: c, - namespace: namespace, - etype: channel.Type().Elem(), - channel: channel, - quit: make(chan struct{}), - err: make(chan error, 1), - in: make(chan json.RawMessage), - } - return sub -} - -// Err returns the subscription error channel. The intended use of Err is to schedule -// resubscription when the client connection is closed unexpectedly. -// -// The error channel receives a value when the subscription has ended due -// to an error. The received error is nil if Close has been called -// on the underlying client and no other error has occurred. -// -// The error channel is closed when Unsubscribe is called on the subscription. -func (sub *ClientSubscription) Err() <-chan error { - return sub.err -} - -// Unsubscribe unsubscribes the notification and closes the error channel. -// It can safely be called more than once. -func (sub *ClientSubscription) Unsubscribe() { - sub.quitWithError(nil, true) - sub.errOnce.Do(func() { close(sub.err) }) -} - -func (sub *ClientSubscription) quitWithError(err error, unsubscribeServer bool) { - sub.quitOnce.Do(func() { - // The dispatch loop won't be able to execute the unsubscribe call - // if it is blocked on deliver. Close sub.quit first because it - // unblocks deliver. - close(sub.quit) - if unsubscribeServer { - sub.requestUnsubscribe() - } - if err != nil { - if err == ErrClientQuit { - err = nil // Adhere to subscription semantics. - } - sub.err <- err - } - }) -} - -func (sub *ClientSubscription) deliver(result json.RawMessage) (ok bool) { - select { - case sub.in <- result: - return true - case <-sub.quit: - return false - } -} - -func (sub *ClientSubscription) start() { - sub.quitWithError(sub.forward()) -} - -func (sub *ClientSubscription) forward() (err error, unsubscribeServer bool) { - cases := []reflect.SelectCase{ - {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.quit)}, - {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.in)}, - {Dir: reflect.SelectSend, Chan: sub.channel}, - } - buffer := list.New() - defer buffer.Init() - for { - var chosen int - var recv reflect.Value - if buffer.Len() == 0 { - // Idle, omit send case. - chosen, recv, _ = reflect.Select(cases[:2]) - } else { - // Non-empty buffer, send the first queued item. - cases[2].Send = reflect.ValueOf(buffer.Front().Value) - chosen, recv, _ = reflect.Select(cases) - } - - switch chosen { - case 0: // <-sub.quit - return nil, false - case 1: // <-sub.in - val, err := sub.unmarshal(recv.Interface().(json.RawMessage)) - if err != nil { - return err, true - } - if buffer.Len() == maxClientSubscriptionBuffer { - return ErrSubscriptionQueueOverflow, true - } - buffer.PushBack(val) - case 2: // sub.channel<- - cases[2].Send = reflect.Value{} // Don't hold onto the value. - buffer.Remove(buffer.Front()) - } - } -} - -func (sub *ClientSubscription) unmarshal(result json.RawMessage) (interface{}, error) { - val := reflect.New(sub.etype) - err := json.Unmarshal(result, val.Interface()) - return val.Elem().Interface(), err -} - -func (sub *ClientSubscription) requestUnsubscribe() error { - var result interface{} - return sub.client.Call(&result, sub.namespace+unsubscribeMethodSuffix, sub.subid) -} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/client_example_test.go b/vendor/github.com/ethereum/go-ethereum/rpc/client_example_test.go index 9c21c12d..3bb8717b 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/client_example_test.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/client_example_test.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -// In this example, our client whishes to track the latest 'block number' +// In this example, our client wishes to track the latest 'block number' // known to the server. The server supports two methods: // // eth_getBlockByNumber("latest", {}) diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/client_test.go b/vendor/github.com/ethereum/go-ethereum/rpc/client_test.go index a8195c0a..80fe29f8 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/client_test.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/client_test.go @@ -35,13 +35,13 @@ import ( ) func TestClientRequest(t *testing.T) { - server := newTestServer("service", new(Service)) + server := newTestServer() defer server.Stop() client := DialInProc(server) defer client.Close() var resp Result - if err := client.Call(&resp, "service_echo", "hello", 10, &Args{"world"}); err != nil { + if err := client.Call(&resp, "test_echo", "hello", 10, &Args{"world"}); err != nil { t.Fatal(err) } if !reflect.DeepEqual(resp, Result{"hello", 10, &Args{"world"}}) { @@ -50,19 +50,19 @@ func TestClientRequest(t *testing.T) { } func TestClientBatchRequest(t *testing.T) { - server := newTestServer("service", new(Service)) + server := newTestServer() defer server.Stop() client := DialInProc(server) defer client.Close() batch := []BatchElem{ { - Method: "service_echo", + Method: "test_echo", Args: []interface{}{"hello", 10, &Args{"world"}}, Result: new(Result), }, { - Method: "service_echo", + Method: "test_echo", Args: []interface{}{"hello2", 11, &Args{"world"}}, Result: new(Result), }, @@ -77,12 +77,12 @@ func TestClientBatchRequest(t *testing.T) { } wantResult := []BatchElem{ { - Method: "service_echo", + Method: "test_echo", Args: []interface{}{"hello", 10, &Args{"world"}}, Result: &Result{"hello", 10, &Args{"world"}}, }, { - Method: "service_echo", + Method: "test_echo", Args: []interface{}{"hello2", 11, &Args{"world"}}, Result: &Result{"hello2", 11, &Args{"world"}}, }, @@ -90,7 +90,7 @@ func TestClientBatchRequest(t *testing.T) { Method: "no_such_method", Args: []interface{}{1, 2, 3}, Result: new(int), - Error: &jsonError{Code: -32601, Message: "The method no_such_method_ does not exist/is not available"}, + Error: &jsonError{Code: -32601, Message: "the method no_such_method does not exist/is not available"}, }, } if !reflect.DeepEqual(batch, wantResult) { @@ -98,6 +98,17 @@ func TestClientBatchRequest(t *testing.T) { } } +func TestClientNotify(t *testing.T) { + server := newTestServer() + defer server.Stop() + client := DialInProc(server) + defer client.Close() + + if err := client.Notify(context.Background(), "test_echo", "hello", 10, &Args{"world"}); err != nil { + t.Fatal(err) + } +} + // func TestClientCancelInproc(t *testing.T) { testClientCancel("inproc", t) } func TestClientCancelWebsocket(t *testing.T) { testClientCancel("ws", t) } func TestClientCancelHTTP(t *testing.T) { testClientCancel("http", t) } @@ -106,7 +117,12 @@ func TestClientCancelIPC(t *testing.T) { testClientCancel("ipc", t) } // This test checks that requests made through CallContext can be canceled by canceling // the context. func testClientCancel(transport string, t *testing.T) { - server := newTestServer("service", new(Service)) + // These tests take a lot of time, run them all at once. + // You probably want to run with -parallel 1 or comment out + // the call to t.Parallel if you enable the logging. + t.Parallel() + + server := newTestServer() defer server.Stop() // What we want to achieve is that the context gets canceled @@ -142,11 +158,6 @@ func testClientCancel(transport string, t *testing.T) { panic("unknown transport: " + transport) } - // These tests take a lot of time, run them all at once. - // You probably want to run with -parallel 1 or comment out - // the call to t.Parallel if you enable the logging. - t.Parallel() - // The actual test starts here. var ( wg sync.WaitGroup @@ -174,7 +185,8 @@ func testClientCancel(transport string, t *testing.T) { } // Now perform a call with the context. // The key thing here is that no call will ever complete successfully. - err := client.CallContext(ctx, nil, "service_sleep", 2*maxContextCancelTimeout) + sleepTime := maxContextCancelTimeout + 20*time.Millisecond + err := client.CallContext(ctx, nil, "test_sleep", sleepTime) if err != nil { log.Debug(fmt.Sprint("got expected error:", err)) } else { @@ -191,7 +203,7 @@ func testClientCancel(transport string, t *testing.T) { } func TestClientSubscribeInvalidArg(t *testing.T) { - server := newTestServer("service", new(Service)) + server := newTestServer() defer server.Stop() client := DialInProc(server) defer client.Close() @@ -221,14 +233,14 @@ func TestClientSubscribeInvalidArg(t *testing.T) { } func TestClientSubscribe(t *testing.T) { - server := newTestServer("eth", new(NotificationTestService)) + server := newTestServer() defer server.Stop() client := DialInProc(server) defer client.Close() nc := make(chan int) count := 10 - sub, err := client.EthSubscribe(context.Background(), nc, "someSubscription", count, 0) + sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", count, 0) if err != nil { t.Fatal("can't subscribe:", err) } @@ -251,46 +263,17 @@ func TestClientSubscribe(t *testing.T) { } } -func TestClientSubscribeCustomNamespace(t *testing.T) { - namespace := "custom" - server := newTestServer(namespace, new(NotificationTestService)) - defer server.Stop() - client := DialInProc(server) - defer client.Close() - - nc := make(chan int) - count := 10 - sub, err := client.Subscribe(context.Background(), namespace, nc, "someSubscription", count, 0) - if err != nil { - t.Fatal("can't subscribe:", err) - } - for i := 0; i < count; i++ { - if val := <-nc; val != i { - t.Fatalf("value mismatch: got %d, want %d", val, i) - } - } - - sub.Unsubscribe() - select { - case v := <-nc: - t.Fatal("received value after unsubscribe:", v) - case err := <-sub.Err(): - if err != nil { - t.Fatalf("Err returned a non-nil error after explicit unsubscribe: %q", err) - } - case <-time.After(1 * time.Second): - t.Fatalf("subscription not closed within 1s after unsubscribe") - } -} - -// In this test, the connection drops while EthSubscribe is -// waiting for a response. +// In this test, the connection drops while Subscribe is waiting for a response. func TestClientSubscribeClose(t *testing.T) { - service := &NotificationTestService{ + server := newTestServer() + service := ¬ificationTestService{ gotHangSubscriptionReq: make(chan struct{}), unblockHangSubscription: make(chan struct{}), } - server := newTestServer("eth", service) + if err := server.RegisterName("nftest2", service); err != nil { + t.Fatal(err) + } + defer server.Stop() client := DialInProc(server) defer client.Close() @@ -302,7 +285,7 @@ func TestClientSubscribeClose(t *testing.T) { err error ) go func() { - sub, err = client.EthSubscribe(context.Background(), nc, "hangSubscription", 999) + sub, err = client.Subscribe(context.Background(), "nftest2", nc, "hangSubscription", 999) errc <- err }() @@ -313,27 +296,26 @@ func TestClientSubscribeClose(t *testing.T) { select { case err := <-errc: if err == nil { - t.Errorf("EthSubscribe returned nil error after Close") + t.Errorf("Subscribe returned nil error after Close") } if sub != nil { - t.Error("EthSubscribe returned non-nil subscription after Close") + t.Error("Subscribe returned non-nil subscription after Close") } case <-time.After(1 * time.Second): - t.Fatalf("EthSubscribe did not return within 1s after Close") + t.Fatalf("Subscribe did not return within 1s after Close") } } // This test reproduces https://github.com/ethereum/go-ethereum/issues/17837 where the // client hangs during shutdown when Unsubscribe races with Client.Close. func TestClientCloseUnsubscribeRace(t *testing.T) { - service := &NotificationTestService{} - server := newTestServer("eth", service) + server := newTestServer() defer server.Stop() for i := 0; i < 20; i++ { client := DialInProc(server) nc := make(chan int) - sub, err := client.EthSubscribe(context.Background(), nc, "someSubscription", 3, 1) + sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", 3, 1) if err != nil { t.Fatal(err) } @@ -350,7 +332,7 @@ func TestClientCloseUnsubscribeRace(t *testing.T) { // This test checks that Client doesn't lock up when a single subscriber // doesn't read subscription events. func TestClientNotificationStorm(t *testing.T) { - server := newTestServer("eth", new(NotificationTestService)) + server := newTestServer() defer server.Stop() doTest := func(count int, wantError bool) { @@ -362,7 +344,7 @@ func TestClientNotificationStorm(t *testing.T) { // Subscribe on the server. It will start sending many notifications // very quickly. nc := make(chan int) - sub, err := client.EthSubscribe(ctx, nc, "someSubscription", count, 0) + sub, err := client.Subscribe(ctx, "nftest", nc, "someSubscription", count, 0) if err != nil { t.Fatal("can't subscribe:", err) } @@ -384,7 +366,7 @@ func TestClientNotificationStorm(t *testing.T) { return } var r int - err := client.CallContext(ctx, &r, "eth_echo", i) + err := client.CallContext(ctx, &r, "nftest_echo", i) if err != nil { if !wantError { t.Fatalf("(%d/%d) call error: %v", i, count, err) @@ -399,7 +381,7 @@ func TestClientNotificationStorm(t *testing.T) { } func TestClientHTTP(t *testing.T) { - server := newTestServer("service", new(Service)) + server := newTestServer() defer server.Stop() client, hs := httpTestClient(server, "http", nil) @@ -416,7 +398,7 @@ func TestClientHTTP(t *testing.T) { for i := range results { i := i go func() { - errc <- client.Call(&results[i], "service_echo", + errc <- client.Call(&results[i], "test_echo", wantResult.String, wantResult.Int, wantResult.Args) }() } @@ -445,16 +427,16 @@ func TestClientHTTP(t *testing.T) { func TestClientReconnect(t *testing.T) { startServer := func(addr string) (*Server, net.Listener) { - srv := newTestServer("service", new(Service)) + srv := newTestServer() l, err := net.Listen("tcp", addr) if err != nil { - t.Fatal(err) + t.Fatal("can't listen:", err) } go http.Serve(l, srv.WebsocketHandler([]string{"*"})) return srv, l } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second) defer cancel() // Start a server and corresponding client. @@ -466,21 +448,22 @@ func TestClientReconnect(t *testing.T) { // Perform a call. This should work because the server is up. var resp Result - if err := client.CallContext(ctx, &resp, "service_echo", "", 1, nil); err != nil { + if err := client.CallContext(ctx, &resp, "test_echo", "", 1, nil); err != nil { t.Fatal(err) } - // Shut down the server and try calling again. It shouldn't work. + // Shut down the server and allow for some cool down time so we can listen on the same + // address again. l1.Close() s1.Stop() - if err := client.CallContext(ctx, &resp, "service_echo", "", 2, nil); err == nil { + time.Sleep(2 * time.Second) + + // Try calling again. It shouldn't work. + if err := client.CallContext(ctx, &resp, "test_echo", "", 2, nil); err == nil { t.Error("successful call while the server is down") t.Logf("resp: %#v", resp) } - // Allow for some cool down time so we can listen on the same address again. - time.Sleep(2 * time.Second) - // Start it up again and call again. The connection should be reestablished. // We spawn multiple calls here to check whether this hangs somehow. s2, l2 := startServer(l1.Addr().String()) @@ -493,7 +476,7 @@ func TestClientReconnect(t *testing.T) { go func() { <-start var resp Result - errors <- client.CallContext(ctx, &resp, "service_echo", "", 3, nil) + errors <- client.CallContext(ctx, &resp, "test_echo", "", 3, nil) }() } close(start) @@ -503,20 +486,12 @@ func TestClientReconnect(t *testing.T) { errcount++ } } - t.Log("err:", err) + t.Logf("%d errors, last error: %v", errcount, err) if errcount > 1 { t.Errorf("expected one error after disconnect, got %d", errcount) } } -func newTestServer(serviceName string, service interface{}) *Server { - server := NewServer() - if err := server.RegisterName(serviceName, service); err != nil { - panic(err) - } - return server -} - func httpTestClient(srv *Server, transport string, fl *flakeyListener) (*Client, *httptest.Server) { // Create the HTTP server. var hs *httptest.Server diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/doc.go b/vendor/github.com/ethereum/go-ethereum/rpc/doc.go index 9a6c4abb..e5840c32 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/doc.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/doc.go @@ -15,43 +15,49 @@ // along with the go-ethereum library. If not, see . /* -Package rpc provides access to the exported methods of an object across a network -or other I/O connection. After creating a server instance objects can be registered, -making it visible from the outside. Exported methods that follow specific -conventions can be called remotely. It also has support for the publish/subscribe -pattern. + +Package rpc implements bi-directional JSON-RPC 2.0 on multiple transports. + +It provides access to the exported methods of an object across a network or other I/O +connection. After creating a server or client instance, objects can be registered to make +them visible as 'services'. Exported methods that follow specific conventions can be +called remotely. It also has support for the publish/subscribe pattern. + +RPC Methods Methods that satisfy the following criteria are made available for remote access: - - object must be exported + - method must be exported - method returns 0, 1 (response or error) or 2 (response and error) values - method argument(s) must be exported or builtin types - method returned value(s) must be exported or builtin types An example method: + func (s *CalcService) Add(a, b int) (int, error) -When the returned error isn't nil the returned integer is ignored and the error is -send back to the client. Otherwise the returned integer is send back to the client. +When the returned error isn't nil the returned integer is ignored and the error is sent +back to the client. Otherwise the returned integer is sent back to the client. -Optional arguments are supported by accepting pointer values as arguments. E.g. -if we want to do the addition in an optional finite field we can accept a mod -argument as pointer value. +Optional arguments are supported by accepting pointer values as arguments. E.g. if we want +to do the addition in an optional finite field we can accept a mod argument as pointer +value. - func (s *CalService) Add(a, b int, mod *int) (int, error) + func (s *CalcService) Add(a, b int, mod *int) (int, error) -This RPC method can be called with 2 integers and a null value as third argument. -In that case the mod argument will be nil. Or it can be called with 3 integers, -in that case mod will be pointing to the given third argument. Since the optional -argument is the last argument the RPC package will also accept 2 integers as -arguments. It will pass the mod argument as nil to the RPC method. +This RPC method can be called with 2 integers and a null value as third argument. In that +case the mod argument will be nil. Or it can be called with 3 integers, in that case mod +will be pointing to the given third argument. Since the optional argument is the last +argument the RPC package will also accept 2 integers as arguments. It will pass the mod +argument as nil to the RPC method. -The server offers the ServeCodec method which accepts a ServerCodec instance. It will -read requests from the codec, process the request and sends the response back to the -client using the codec. The server can execute requests concurrently. Responses -can be sent back to the client out of order. +The server offers the ServeCodec method which accepts a ServerCodec instance. It will read +requests from the codec, process the request and sends the response back to the client +using the codec. The server can execute requests concurrently. Responses can be sent back +to the client out of order. An example server which uses the JSON codec: + type CalculatorService struct {} func (s *CalculatorService) Add(a, b int) int { @@ -73,26 +79,40 @@ An example server which uses the JSON codec: for { c, _ := l.AcceptUnix() codec := v2.NewJSONCodec(c) - go server.ServeCodec(codec) + go server.ServeCodec(codec, 0) } +Subscriptions + The package also supports the publish subscribe pattern through the use of subscriptions. -A method that is considered eligible for notifications must satisfy the following criteria: - - object must be exported +A method that is considered eligible for notifications must satisfy the following +criteria: + - method must be exported - first method argument type must be context.Context - method argument(s) must be exported or builtin types - - method must return the tuple Subscription, error + - method must have return types (rpc.Subscription, error) An example method: - func (s *BlockChainService) NewBlocks(ctx context.Context) (Subscription, error) { + + func (s *BlockChainService) NewBlocks(ctx context.Context) (rpc.Subscription, error) { ... } -Subscriptions are deleted when: - - the user sends an unsubscribe request - - the connection which was used to create the subscription is closed. This can be initiated - by the client and server. The server will close the connection on a write error or when - the queue of buffered notifications gets too big. +When the service containing the subscription method is registered to the server, for +example under the "blockchain" namespace, a subscription is created by calling the +"blockchain_subscribe" method. + +Subscriptions are deleted when the user sends an unsubscribe request or when the +connection which was used to create the subscription is closed. This can be initiated by +the client and server. The server will close the connection for any write error. + +For more information about subscriptions, see https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB. + +Reverse Calls + +In any method handler, an instance of rpc.Client can be accessed through the +ClientFromContext method. Using this client instance, server-to-client method calls can be +performed on the RPC connection. */ package rpc diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/errors.go b/vendor/github.com/ethereum/go-ethereum/rpc/errors.go index 9cf9dc60..c3aa826c 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/errors.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/errors.go @@ -18,18 +18,31 @@ package rpc import "fmt" -// request is for an unknown service -type methodNotFoundError struct { - service string - method string -} +const defaultErrorCode = -32000 + +type methodNotFoundError struct{ method string } func (e *methodNotFoundError) ErrorCode() int { return -32601 } func (e *methodNotFoundError) Error() string { - return fmt.Sprintf("The method %s%s%s does not exist/is not available", e.service, serviceMethodSeparator, e.method) + return fmt.Sprintf("the method %s does not exist/is not available", e.method) } +type subscriptionNotFoundError struct{ namespace, subscription string } + +func (e *subscriptionNotFoundError) ErrorCode() int { return -32601 } + +func (e *subscriptionNotFoundError) Error() string { + return fmt.Sprintf("no %q subscription in %s namespace", e.subscription, e.namespace) +} + +// Invalid JSON was received by the server. +type parseError struct{ message string } + +func (e *parseError) ErrorCode() int { return -32700 } + +func (e *parseError) Error() string { return e.message } + // received message isn't a valid request type invalidRequestError struct{ message string } @@ -50,17 +63,3 @@ type invalidParamsError struct{ message string } func (e *invalidParamsError) ErrorCode() int { return -32602 } func (e *invalidParamsError) Error() string { return e.message } - -// logic error, callback returned an error -type callbackError struct{ message string } - -func (e *callbackError) ErrorCode() int { return -32000 } - -func (e *callbackError) Error() string { return e.message } - -// issued when a request is received after the server is issued to stop. -type shutdownError struct{} - -func (e *shutdownError) ErrorCode() int { return -32000 } - -func (e *shutdownError) Error() string { return "server is shutting down" } diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/handler.go b/vendor/github.com/ethereum/go-ethereum/rpc/handler.go new file mode 100644 index 00000000..bc03ef25 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/handler.go @@ -0,0 +1,397 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rpc + +import ( + "context" + "encoding/json" + "reflect" + "strconv" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" +) + +// handler handles JSON-RPC messages. There is one handler per connection. Note that +// handler is not safe for concurrent use. Message handling never blocks indefinitely +// because RPCs are processed on background goroutines launched by handler. +// +// The entry points for incoming messages are: +// +// h.handleMsg(message) +// h.handleBatch(message) +// +// Outgoing calls use the requestOp struct. Register the request before sending it +// on the connection: +// +// op := &requestOp{ids: ...} +// h.addRequestOp(op) +// +// Now send the request, then wait for the reply to be delivered through handleMsg: +// +// if err := op.wait(...); err != nil { +// h.removeRequestOp(op) // timeout, etc. +// } +// +type handler struct { + reg *serviceRegistry + unsubscribeCb *callback + idgen func() ID // subscription ID generator + respWait map[string]*requestOp // active client requests + clientSubs map[string]*ClientSubscription // active client subscriptions + callWG sync.WaitGroup // pending call goroutines + rootCtx context.Context // canceled by close() + cancelRoot func() // cancel function for rootCtx + conn jsonWriter // where responses will be sent + log log.Logger + allowSubscribe bool + + subLock sync.Mutex + serverSubs map[ID]*Subscription +} + +type callProc struct { + ctx context.Context + notifiers []*Notifier +} + +func newHandler(connCtx context.Context, conn jsonWriter, idgen func() ID, reg *serviceRegistry) *handler { + rootCtx, cancelRoot := context.WithCancel(connCtx) + h := &handler{ + reg: reg, + idgen: idgen, + conn: conn, + respWait: make(map[string]*requestOp), + clientSubs: make(map[string]*ClientSubscription), + rootCtx: rootCtx, + cancelRoot: cancelRoot, + allowSubscribe: true, + serverSubs: make(map[ID]*Subscription), + log: log.Root(), + } + if conn.RemoteAddr() != "" { + h.log = h.log.New("conn", conn.RemoteAddr()) + } + h.unsubscribeCb = newCallback(reflect.Value{}, reflect.ValueOf(h.unsubscribe)) + return h +} + +// handleBatch executes all messages in a batch and returns the responses. +func (h *handler) handleBatch(msgs []*jsonrpcMessage) { + // Emit error response for empty batches: + if len(msgs) == 0 { + h.startCallProc(func(cp *callProc) { + h.conn.Write(cp.ctx, errorMessage(&invalidRequestError{"empty batch"})) + }) + return + } + + // Handle non-call messages first: + calls := make([]*jsonrpcMessage, 0, len(msgs)) + for _, msg := range msgs { + if handled := h.handleImmediate(msg); !handled { + calls = append(calls, msg) + } + } + if len(calls) == 0 { + return + } + // Process calls on a goroutine because they may block indefinitely: + h.startCallProc(func(cp *callProc) { + answers := make([]*jsonrpcMessage, 0, len(msgs)) + for _, msg := range calls { + if answer := h.handleCallMsg(cp, msg); answer != nil { + answers = append(answers, answer) + } + } + h.addSubscriptions(cp.notifiers) + if len(answers) > 0 { + h.conn.Write(cp.ctx, answers) + } + for _, n := range cp.notifiers { + n.activate() + } + }) +} + +// handleMsg handles a single message. +func (h *handler) handleMsg(msg *jsonrpcMessage) { + if ok := h.handleImmediate(msg); ok { + return + } + h.startCallProc(func(cp *callProc) { + answer := h.handleCallMsg(cp, msg) + h.addSubscriptions(cp.notifiers) + if answer != nil { + h.conn.Write(cp.ctx, answer) + } + for _, n := range cp.notifiers { + n.activate() + } + }) +} + +// close cancels all requests except for inflightReq and waits for +// call goroutines to shut down. +func (h *handler) close(err error, inflightReq *requestOp) { + h.cancelAllRequests(err, inflightReq) + h.cancelRoot() + h.callWG.Wait() + h.cancelServerSubscriptions(err) +} + +// addRequestOp registers a request operation. +func (h *handler) addRequestOp(op *requestOp) { + for _, id := range op.ids { + h.respWait[string(id)] = op + } +} + +// removeRequestOps stops waiting for the given request IDs. +func (h *handler) removeRequestOp(op *requestOp) { + for _, id := range op.ids { + delete(h.respWait, string(id)) + } +} + +// cancelAllRequests unblocks and removes pending requests and active subscriptions. +func (h *handler) cancelAllRequests(err error, inflightReq *requestOp) { + didClose := make(map[*requestOp]bool) + if inflightReq != nil { + didClose[inflightReq] = true + } + + for id, op := range h.respWait { + // Remove the op so that later calls will not close op.resp again. + delete(h.respWait, id) + + if !didClose[op] { + op.err = err + close(op.resp) + didClose[op] = true + } + } + for id, sub := range h.clientSubs { + delete(h.clientSubs, id) + sub.quitWithError(err, false) + } +} + +func (h *handler) addSubscriptions(nn []*Notifier) { + h.subLock.Lock() + defer h.subLock.Unlock() + + for _, n := range nn { + if sub := n.takeSubscription(); sub != nil { + h.serverSubs[sub.ID] = sub + } + } +} + +// cancelServerSubscriptions removes all subscriptions and closes their error channels. +func (h *handler) cancelServerSubscriptions(err error) { + h.subLock.Lock() + defer h.subLock.Unlock() + + for id, s := range h.serverSubs { + s.err <- err + close(s.err) + delete(h.serverSubs, id) + } +} + +// startCallProc runs fn in a new goroutine and starts tracking it in the h.calls wait group. +func (h *handler) startCallProc(fn func(*callProc)) { + h.callWG.Add(1) + go func() { + ctx, cancel := context.WithCancel(h.rootCtx) + defer h.callWG.Done() + defer cancel() + fn(&callProc{ctx: ctx}) + }() +} + +// handleImmediate executes non-call messages. It returns false if the message is a +// call or requires a reply. +func (h *handler) handleImmediate(msg *jsonrpcMessage) bool { + start := time.Now() + switch { + case msg.isNotification(): + if strings.HasSuffix(msg.Method, notificationMethodSuffix) { + h.handleSubscriptionResult(msg) + return true + } + return false + case msg.isResponse(): + h.handleResponse(msg) + h.log.Trace("Handled RPC response", "reqid", idForLog{msg.ID}, "t", time.Since(start)) + return true + default: + return false + } +} + +// handleSubscriptionResult processes subscription notifications. +func (h *handler) handleSubscriptionResult(msg *jsonrpcMessage) { + var result subscriptionResult + if err := json.Unmarshal(msg.Params, &result); err != nil { + h.log.Debug("Dropping invalid subscription message") + return + } + if h.clientSubs[result.ID] != nil { + h.clientSubs[result.ID].deliver(result.Result) + } +} + +// handleResponse processes method call responses. +func (h *handler) handleResponse(msg *jsonrpcMessage) { + op := h.respWait[string(msg.ID)] + if op == nil { + h.log.Debug("Unsolicited RPC response", "reqid", idForLog{msg.ID}) + return + } + delete(h.respWait, string(msg.ID)) + // For normal responses, just forward the reply to Call/BatchCall. + if op.sub == nil { + op.resp <- msg + return + } + // For subscription responses, start the subscription if the server + // indicates success. EthSubscribe gets unblocked in either case through + // the op.resp channel. + defer close(op.resp) + if msg.Error != nil { + op.err = msg.Error + return + } + if op.err = json.Unmarshal(msg.Result, &op.sub.subid); op.err == nil { + go op.sub.start() + h.clientSubs[op.sub.subid] = op.sub + } +} + +// handleCallMsg executes a call message and returns the answer. +func (h *handler) handleCallMsg(ctx *callProc, msg *jsonrpcMessage) *jsonrpcMessage { + start := time.Now() + switch { + case msg.isNotification(): + h.handleCall(ctx, msg) + h.log.Debug("Served "+msg.Method, "t", time.Since(start)) + return nil + case msg.isCall(): + resp := h.handleCall(ctx, msg) + if resp.Error != nil { + h.log.Info("Served "+msg.Method, "reqid", idForLog{msg.ID}, "t", time.Since(start), "err", resp.Error.Message) + } else { + h.log.Debug("Served "+msg.Method, "reqid", idForLog{msg.ID}, "t", time.Since(start)) + } + return resp + case msg.hasValidID(): + return msg.errorResponse(&invalidRequestError{"invalid request"}) + default: + return errorMessage(&invalidRequestError{"invalid request"}) + } +} + +// handleCall processes method calls. +func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage { + if msg.isSubscribe() { + return h.handleSubscribe(cp, msg) + } + var callb *callback + if msg.isUnsubscribe() { + callb = h.unsubscribeCb + } else { + callb = h.reg.callback(msg.Method) + } + if callb == nil { + return msg.errorResponse(&methodNotFoundError{method: msg.Method}) + } + args, err := parsePositionalArguments(msg.Params, callb.argTypes) + if err != nil { + return msg.errorResponse(&invalidParamsError{err.Error()}) + } + + return h.runMethod(cp.ctx, msg, callb, args) +} + +// handleSubscribe processes *_subscribe method calls. +func (h *handler) handleSubscribe(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage { + if !h.allowSubscribe { + return msg.errorResponse(ErrNotificationsUnsupported) + } + + // Subscription method name is first argument. + name, err := parseSubscriptionName(msg.Params) + if err != nil { + return msg.errorResponse(&invalidParamsError{err.Error()}) + } + namespace := msg.namespace() + callb := h.reg.subscription(namespace, name) + if callb == nil { + return msg.errorResponse(&subscriptionNotFoundError{namespace, name}) + } + + // Parse subscription name arg too, but remove it before calling the callback. + argTypes := append([]reflect.Type{stringType}, callb.argTypes...) + args, err := parsePositionalArguments(msg.Params, argTypes) + if err != nil { + return msg.errorResponse(&invalidParamsError{err.Error()}) + } + args = args[1:] + + // Install notifier in context so the subscription handler can find it. + n := &Notifier{h: h, namespace: namespace} + cp.notifiers = append(cp.notifiers, n) + ctx := context.WithValue(cp.ctx, notifierKey{}, n) + + return h.runMethod(ctx, msg, callb, args) +} + +// runMethod runs the Go callback for an RPC method. +func (h *handler) runMethod(ctx context.Context, msg *jsonrpcMessage, callb *callback, args []reflect.Value) *jsonrpcMessage { + result, err := callb.call(ctx, msg.Method, args) + if err != nil { + return msg.errorResponse(err) + } + return msg.response(result) +} + +// unsubscribe is the callback function for all *_unsubscribe calls. +func (h *handler) unsubscribe(ctx context.Context, id ID) (bool, error) { + h.subLock.Lock() + defer h.subLock.Unlock() + + s := h.serverSubs[id] + if s == nil { + return false, ErrSubscriptionNotFound + } + close(s.err) + delete(h.serverSubs, id) + return true, nil +} + +type idForLog struct{ json.RawMessage } + +func (id idForLog) String() string { + if s, err := strconv.Unquote(string(id.RawMessage)); err == nil { + return s + } + return string(id.RawMessage) +} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/http.go b/vendor/github.com/ethereum/go-ethereum/rpc/http.go index af79858e..518b3b87 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/http.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/http.go @@ -36,35 +36,40 @@ import ( ) const ( - contentType = "application/json" maxRequestContentLength = 1024 * 512 + contentType = "application/json" ) -var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0") +// https://www.jsonrpc.org/historical/json-rpc-over-http.html#id13 +var acceptedContentTypes = []string{contentType, "application/json-rpc", "application/jsonrequest"} type httpConn struct { client *http.Client req *http.Request closeOnce sync.Once - closed chan struct{} + closed chan interface{} } // httpConn is treated specially by Client. -func (hc *httpConn) LocalAddr() net.Addr { return nullAddr } -func (hc *httpConn) RemoteAddr() net.Addr { return nullAddr } -func (hc *httpConn) SetReadDeadline(time.Time) error { return nil } -func (hc *httpConn) SetWriteDeadline(time.Time) error { return nil } -func (hc *httpConn) SetDeadline(time.Time) error { return nil } -func (hc *httpConn) Write([]byte) (int, error) { panic("Write called") } - -func (hc *httpConn) Read(b []byte) (int, error) { - <-hc.closed - return 0, io.EOF +func (hc *httpConn) Write(context.Context, interface{}) error { + panic("Write called on httpConn") } -func (hc *httpConn) Close() error { +func (hc *httpConn) RemoteAddr() string { + return hc.req.URL.String() +} + +func (hc *httpConn) Read() ([]*jsonrpcMessage, bool, error) { + <-hc.closed + return nil, false, io.EOF +} + +func (hc *httpConn) Close() { hc.closeOnce.Do(func() { close(hc.closed) }) - return nil +} + +func (hc *httpConn) Closed() <-chan interface{} { + return hc.closed } // HTTPTimeouts represents the configuration params for the HTTP RPC server. @@ -110,8 +115,8 @@ func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) { req.Header.Set("Accept", contentType) initctx := context.Background() - return newClient(initctx, func(context.Context) (net.Conn, error) { - return &httpConn{client: client, req: req, closed: make(chan struct{})}, nil + return newClient(initctx, func(context.Context) (ServerCodec, error) { + return &httpConn{client: client, req: req, closed: make(chan interface{})}, nil }) } @@ -180,21 +185,34 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos return resp.Body, nil } -// httpReadWriteNopCloser wraps a io.Reader and io.Writer with a NOP Close method. -type httpReadWriteNopCloser struct { +// httpServerConn turns a HTTP connection into a Conn. +type httpServerConn struct { io.Reader io.Writer + r *http.Request } -// Close does nothing and returns always nil -func (t *httpReadWriteNopCloser) Close() error { - return nil +func newHTTPServerConn(r *http.Request, w http.ResponseWriter) ServerCodec { + body := io.LimitReader(r.Body, maxRequestContentLength) + conn := &httpServerConn{Reader: body, Writer: w, r: r} + return NewJSONCodec(conn) } +// Close does nothing and always returns nil. +func (t *httpServerConn) Close() error { return nil } + +// RemoteAddr returns the peer address of the underlying connection. +func (t *httpServerConn) RemoteAddr() string { + return t.r.RemoteAddr +} + +// SetWriteDeadline does nothing and always returns nil. +func (t *httpServerConn) SetWriteDeadline(time.Time) error { return nil } + // NewHTTPServer creates a new HTTP RPC server around an API provider. // // Deprecated: Server implements http.Handler -func NewHTTPServer(cors []string, vhosts []string, timeouts HTTPTimeouts, srv *Server) *http.Server { +func NewHTTPServer(cors []string, vhosts []string, timeouts HTTPTimeouts, srv http.Handler) *http.Server { // Wrap the CORS-handler within a host-handler handler := newCorsHandler(srv, cors) handler = newVHostHandler(vhosts, handler) @@ -222,7 +240,7 @@ func NewHTTPServer(cors []string, vhosts []string, timeouts HTTPTimeouts, srv *S } // ServeHTTP serves JSON-RPC requests over HTTP. -func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Permit dumb empty requests for remote health-checks (AWS) if r.Method == http.MethodGet && r.ContentLength == 0 && r.URL.RawQuery == "" { return @@ -245,12 +263,10 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx = context.WithValue(ctx, "Origin", origin) } - body := io.LimitReader(r.Body, maxRequestContentLength) - codec := NewJSONCodec(&httpReadWriteNopCloser{body, w}) - defer codec.Close() - w.Header().Set("content-type", contentType) - srv.ServeSingleRequest(ctx, codec, OptionMethodInvocation) + codec := newHTTPServerConn(r, w) + defer codec.Close() + s.serveSingleRequest(ctx, codec) } // validateRequest returns a non-zero response code and error message if the @@ -263,15 +279,24 @@ func validateRequest(r *http.Request) (int, error) { err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxRequestContentLength) return http.StatusRequestEntityTooLarge, err } - mt, _, err := mime.ParseMediaType(r.Header.Get("content-type")) - if r.Method != http.MethodOptions && (err != nil || mt != contentType) { - err := fmt.Errorf("invalid content type, only %s is supported", contentType) - return http.StatusUnsupportedMediaType, err + // Allow OPTIONS (regardless of content-type) + if r.Method == http.MethodOptions { + return 0, nil } - return 0, nil + // Check content-type + if mt, _, err := mime.ParseMediaType(r.Header.Get("content-type")); err == nil { + for _, accepted := range acceptedContentTypes { + if accepted == mt { + return 0, nil + } + } + } + // Invalid content-type + err := fmt.Errorf("invalid content type, only %s is supported", contentType) + return http.StatusUnsupportedMediaType, err } -func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler { +func newCorsHandler(srv http.Handler, allowedOrigins []string) http.Handler { // disable CORS support if user has not specified a custom CORS configuration if len(allowedOrigins) == 0 { return srv diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/inproc.go b/vendor/github.com/ethereum/go-ethereum/rpc/inproc.go index cbe65d10..c4456cfc 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/inproc.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/inproc.go @@ -24,10 +24,10 @@ import ( // DialInProc attaches an in-process connection to the given RPC server. func DialInProc(handler *Server) *Client { initctx := context.Background() - c, _ := newClient(initctx, func(context.Context) (net.Conn, error) { + c, _ := newClient(initctx, func(context.Context) (ServerCodec, error) { p1, p2 := net.Pipe() go handler.ServeCodec(NewJSONCodec(p1), OptionMethodInvocation|OptionSubscriptions) - return p2, nil + return NewJSONCodec(p2), nil }) return c } diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/ipc.go b/vendor/github.com/ethereum/go-ethereum/rpc/ipc.go index b05e503d..ad8ce030 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/ipc.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/ipc.go @@ -25,7 +25,7 @@ import ( ) // ServeListener accepts connections on l, serving JSON-RPC on them. -func (srv *Server) ServeListener(l net.Listener) error { +func (s *Server) ServeListener(l net.Listener) error { for { conn, err := l.Accept() if netutil.IsTemporaryError(err) { @@ -34,8 +34,8 @@ func (srv *Server) ServeListener(l net.Listener) error { } else if err != nil { return err } - log.Trace("Accepted connection", "addr", conn.RemoteAddr()) - go srv.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions) + log.Trace("Accepted RPC connection", "conn", conn.RemoteAddr()) + go s.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions) } } @@ -46,7 +46,11 @@ func (srv *Server) ServeListener(l net.Listener) error { // The context is used for the initial connection establishment. It does not // affect subsequent interactions with the client. func DialIPC(ctx context.Context, endpoint string) (*Client, error) { - return newClient(ctx, func(ctx context.Context) (net.Conn, error) { - return newIPCConnection(ctx, endpoint) + return newClient(ctx, func(ctx context.Context) (ServerCodec, error) { + conn, err := newIPCConnection(ctx, endpoint) + if err != nil { + return nil, err + } + return NewJSONCodec(conn), err }) } diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/ipc_unix.go b/vendor/github.com/ethereum/go-ethereum/rpc/ipc_unix.go index 0851ea61..707b47fd 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/ipc_unix.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/ipc_unix.go @@ -20,13 +20,31 @@ package rpc import ( "context" + "fmt" "net" "os" "path/filepath" + + "github.com/ethereum/go-ethereum/log" ) +/* +#include + +int max_socket_path_size() { +struct sockaddr_un s; +return sizeof(s.sun_path); +} +*/ +import "C" + // ipcListen will create a Unix socket on the given endpoint. func ipcListen(endpoint string) (net.Listener, error) { + if len(endpoint) > int(C.max_socket_path_size()) { + log.Warn(fmt.Sprintf("The ipc endpoint is longer than %d characters. ", C.max_socket_path_size()), + "endpoint", endpoint) + } + // Ensure the IPC path exists and remove any previous leftover if err := os.MkdirAll(filepath.Dir(endpoint), 0751); err != nil { return nil, err diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/json.go b/vendor/github.com/ethereum/go-ethereum/rpc/json.go index a523eeb8..b2e8c7ba 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/json.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/json.go @@ -18,36 +18,104 @@ package rpc import ( "bytes" + "context" "encoding/json" + "errors" "fmt" "io" "reflect" - "strconv" "strings" "sync" - - "github.com/ethereum/go-ethereum/log" + "time" ) const ( - jsonrpcVersion = "2.0" + vsn = "2.0" serviceMethodSeparator = "_" subscribeMethodSuffix = "_subscribe" unsubscribeMethodSuffix = "_unsubscribe" notificationMethodSuffix = "_subscription" + + defaultWriteTimeout = 10 * time.Second // used if context has no deadline ) -type jsonRequest struct { - Method string `json:"method"` - Version string `json:"jsonrpc"` - Id json.RawMessage `json:"id,omitempty"` - Payload json.RawMessage `json:"params,omitempty"` +var null = json.RawMessage("null") + +type subscriptionResult struct { + ID string `json:"subscription"` + Result json.RawMessage `json:"result,omitempty"` } -type jsonSuccessResponse struct { - Version string `json:"jsonrpc"` - Id interface{} `json:"id,omitempty"` - Result interface{} `json:"result"` +// A value of this type can a JSON-RPC request, notification, successful response or +// error response. Which one it is depends on the fields. +type jsonrpcMessage struct { + Version string `json:"jsonrpc,omitempty"` + ID json.RawMessage `json:"id,omitempty"` + Method string `json:"method,omitempty"` + Params json.RawMessage `json:"params,omitempty"` + Error *jsonError `json:"error,omitempty"` + Result json.RawMessage `json:"result,omitempty"` +} + +func (msg *jsonrpcMessage) isNotification() bool { + return msg.ID == nil && msg.Method != "" +} + +func (msg *jsonrpcMessage) isCall() bool { + return msg.hasValidID() && msg.Method != "" +} + +func (msg *jsonrpcMessage) isResponse() bool { + return msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil) +} + +func (msg *jsonrpcMessage) hasValidID() bool { + return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '[' +} + +func (msg *jsonrpcMessage) isSubscribe() bool { + return strings.HasSuffix(msg.Method, subscribeMethodSuffix) +} + +func (msg *jsonrpcMessage) isUnsubscribe() bool { + return strings.HasSuffix(msg.Method, unsubscribeMethodSuffix) +} + +func (msg *jsonrpcMessage) namespace() string { + elem := strings.SplitN(msg.Method, serviceMethodSeparator, 2) + return elem[0] +} + +func (msg *jsonrpcMessage) String() string { + b, _ := json.Marshal(msg) + return string(b) +} + +func (msg *jsonrpcMessage) errorResponse(err error) *jsonrpcMessage { + resp := errorMessage(err) + resp.ID = msg.ID + return resp +} + +func (msg *jsonrpcMessage) response(result interface{}) *jsonrpcMessage { + enc, err := json.Marshal(result) + if err != nil { + // TODO: wrap with 'internal server error' + return msg.errorResponse(err) + } + return &jsonrpcMessage{Version: vsn, ID: msg.ID, Result: enc} +} + +func errorMessage(err error) *jsonrpcMessage { + msg := &jsonrpcMessage{Version: vsn, ID: null, Error: &jsonError{ + Code: defaultErrorCode, + Message: err.Error(), + }} + ec, ok := err.(Error) + if ok { + msg.Error.Code = ec.ErrorCode() + } + return msg } type jsonError struct { @@ -56,35 +124,6 @@ type jsonError struct { Data interface{} `json:"data,omitempty"` } -type jsonErrResponse struct { - Version string `json:"jsonrpc"` - Id interface{} `json:"id,omitempty"` - Error jsonError `json:"error"` -} - -type jsonSubscription struct { - Subscription string `json:"subscription"` - Result interface{} `json:"result,omitempty"` -} - -type jsonNotification struct { - Version string `json:"jsonrpc"` - Method string `json:"method"` - Params jsonSubscription `json:"params"` -} - -// jsonCodec reads and writes JSON-RPC messages to the underlying connection. It -// also has support for parsing arguments and serializing (result) objects. -type jsonCodec struct { - closer sync.Once // close closed channel once - closed chan interface{} // closed on Close - decMu sync.Mutex // guards the decoder - decode func(v interface{}) error // decoder to allow multiple transports - encMu sync.Mutex // guards the encoder - encode func(v interface{}) error // encoder to allow multiple transports - rw io.ReadWriteCloser // connection -} - func (err *jsonError) Error() string { if err.Message == "" { return fmt.Sprintf("json-rpc error %d", err.Code) @@ -96,34 +135,126 @@ func (err *jsonError) ErrorCode() int { return err.Code } +// Conn is a subset of the methods of net.Conn which are sufficient for ServerCodec. +type Conn interface { + io.ReadWriteCloser + SetWriteDeadline(time.Time) error +} + +// ConnRemoteAddr wraps the RemoteAddr operation, which returns a description +// of the peer address of a connection. If a Conn also implements ConnRemoteAddr, this +// description is used in log messages. +type ConnRemoteAddr interface { + RemoteAddr() string +} + +// connWithRemoteAddr overrides the remote address of a connection. +type connWithRemoteAddr struct { + Conn + addr string +} + +func (c connWithRemoteAddr) RemoteAddr() string { return c.addr } + +// jsonCodec reads and writes JSON-RPC messages to the underlying connection. It also has +// support for parsing arguments and serializing (result) objects. +type jsonCodec struct { + remoteAddr string + closer sync.Once // close closed channel once + closed chan interface{} // closed on Close + decode func(v interface{}) error // decoder to allow multiple transports + encMu sync.Mutex // guards the encoder + encode func(v interface{}) error // encoder to allow multiple transports + conn Conn +} + // NewCodec creates a new RPC server codec with support for JSON-RPC 2.0 based // on explicitly given encoding and decoding methods. -func NewCodec(rwc io.ReadWriteCloser, encode, decode func(v interface{}) error) ServerCodec { - return &jsonCodec{ +func NewCodec(conn Conn, encode, decode func(v interface{}) error) ServerCodec { + codec := &jsonCodec{ closed: make(chan interface{}), encode: encode, decode: decode, - rw: rwc, + conn: conn, } + if ra, ok := conn.(ConnRemoteAddr); ok { + codec.remoteAddr = ra.RemoteAddr() + } + return codec } // NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0. -func NewJSONCodec(rwc io.ReadWriteCloser) ServerCodec { - enc := json.NewEncoder(rwc) - dec := json.NewDecoder(rwc) +func NewJSONCodec(conn Conn) ServerCodec { + enc := json.NewEncoder(conn) + dec := json.NewDecoder(conn) dec.UseNumber() + return NewCodec(conn, enc.Encode, dec.Decode) +} - return &jsonCodec{ - closed: make(chan interface{}), - encode: enc.Encode, - decode: dec.Decode, - rw: rwc, +func (c *jsonCodec) RemoteAddr() string { + return c.remoteAddr +} + +func (c *jsonCodec) Read() (msg []*jsonrpcMessage, batch bool, err error) { + // Decode the next JSON object in the input stream. + // This verifies basic syntax, etc. + var rawmsg json.RawMessage + if err := c.decode(&rawmsg); err != nil { + return nil, false, err } + msg, batch = parseMessage(rawmsg) + return msg, batch, nil +} + +// Write sends a message to client. +func (c *jsonCodec) Write(ctx context.Context, v interface{}) error { + c.encMu.Lock() + defer c.encMu.Unlock() + + deadline, ok := ctx.Deadline() + if !ok { + deadline = time.Now().Add(defaultWriteTimeout) + } + c.conn.SetWriteDeadline(deadline) + return c.encode(v) +} + +// Close the underlying connection +func (c *jsonCodec) Close() { + c.closer.Do(func() { + close(c.closed) + c.conn.Close() + }) +} + +// Closed returns a channel which will be closed when Close is called +func (c *jsonCodec) Closed() <-chan interface{} { + return c.closed +} + +// parseMessage parses raw bytes as a (batch of) JSON-RPC message(s). There are no error +// checks in this function because the raw message has already been syntax-checked when it +// is called. Any non-JSON-RPC messages in the input return the zero value of +// jsonrpcMessage. +func parseMessage(raw json.RawMessage) ([]*jsonrpcMessage, bool) { + if !isBatch(raw) { + msgs := []*jsonrpcMessage{{}} + json.Unmarshal(raw, &msgs[0]) + return msgs, false + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.Token() // skip '[' + var msgs []*jsonrpcMessage + for dec.More() { + msgs = append(msgs, new(jsonrpcMessage)) + dec.Decode(&msgs[len(msgs)-1]) + } + return msgs, true } // isBatch returns true when the first non-whitespace characters is '[' -func isBatch(msg json.RawMessage) bool { - for _, c := range msg { +func isBatch(raw json.RawMessage) bool { + for _, c := range raw { // skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt) if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d { continue @@ -133,231 +264,67 @@ func isBatch(msg json.RawMessage) bool { return false } -// ReadRequestHeaders will read new requests without parsing the arguments. It will -// return a collection of requests, an indication if these requests are in batch -// form or an error when the incoming message could not be read/parsed. -func (c *jsonCodec) ReadRequestHeaders() ([]rpcRequest, bool, Error) { - c.decMu.Lock() - defer c.decMu.Unlock() - - var incomingMsg json.RawMessage - if err := c.decode(&incomingMsg); err != nil { - return nil, false, &invalidRequestError{err.Error()} - } - if isBatch(incomingMsg) { - return parseBatchRequest(incomingMsg) - } - return parseRequest(incomingMsg) -} - -// checkReqId returns an error when the given reqId isn't valid for RPC method calls. -// valid id's are strings, numbers or null -func checkReqId(reqId json.RawMessage) error { - if len(reqId) == 0 { - return fmt.Errorf("missing request id") - } - if _, err := strconv.ParseFloat(string(reqId), 64); err == nil { - return nil - } - var str string - if err := json.Unmarshal(reqId, &str); err == nil { - return nil - } - return fmt.Errorf("invalid request id") -} - -// parseRequest will parse a single request from the given RawMessage. It will return -// the parsed request, an indication if the request was a batch or an error when -// the request could not be parsed. -func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) { - var in jsonRequest - if err := json.Unmarshal(incomingMsg, &in); err != nil { - return nil, false, &invalidMessageError{err.Error()} - } - - if err := checkReqId(in.Id); err != nil { - return nil, false, &invalidMessageError{err.Error()} - } - - // subscribe are special, they will always use `subscribeMethod` as first param in the payload - if strings.HasSuffix(in.Method, subscribeMethodSuffix) { - reqs := []rpcRequest{{id: &in.Id, isPubSub: true}} - if len(in.Payload) > 0 { - // first param must be subscription name - var subscribeMethod [1]string - if err := json.Unmarshal(in.Payload, &subscribeMethod); err != nil { - log.Debug(fmt.Sprintf("Unable to parse subscription method: %v\n", err)) - return nil, false, &invalidRequestError{"Unable to parse subscription request"} - } - - reqs[0].service, reqs[0].method = strings.TrimSuffix(in.Method, subscribeMethodSuffix), subscribeMethod[0] - reqs[0].params = in.Payload - return reqs, false, nil - } - return nil, false, &invalidRequestError{"Unable to parse subscription request"} - } - - if strings.HasSuffix(in.Method, unsubscribeMethodSuffix) { - return []rpcRequest{{id: &in.Id, isPubSub: true, - method: in.Method, params: in.Payload}}, false, nil - } - - elems := strings.Split(in.Method, serviceMethodSeparator) - if len(elems) != 2 { - return nil, false, &methodNotFoundError{in.Method, ""} - } - - // regular RPC call - if len(in.Payload) == 0 { - return []rpcRequest{{service: elems[0], method: elems[1], id: &in.Id}}, false, nil - } - - return []rpcRequest{{service: elems[0], method: elems[1], id: &in.Id, params: in.Payload}}, false, nil -} - -// parseBatchRequest will parse a batch request into a collection of requests from the given RawMessage, an indication -// if the request was a batch or an error when the request could not be read. -func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) { - var in []jsonRequest - if err := json.Unmarshal(incomingMsg, &in); err != nil { - return nil, false, &invalidMessageError{err.Error()} - } - - requests := make([]rpcRequest, len(in)) - for i, r := range in { - if err := checkReqId(r.Id); err != nil { - return nil, false, &invalidMessageError{err.Error()} - } - - id := &in[i].Id - - // subscribe are special, they will always use `subscriptionMethod` as first param in the payload - if strings.HasSuffix(r.Method, subscribeMethodSuffix) { - requests[i] = rpcRequest{id: id, isPubSub: true} - if len(r.Payload) > 0 { - // first param must be subscription name - var subscribeMethod [1]string - if err := json.Unmarshal(r.Payload, &subscribeMethod); err != nil { - log.Debug(fmt.Sprintf("Unable to parse subscription method: %v\n", err)) - return nil, false, &invalidRequestError{"Unable to parse subscription request"} - } - - requests[i].service, requests[i].method = strings.TrimSuffix(r.Method, subscribeMethodSuffix), subscribeMethod[0] - requests[i].params = r.Payload - continue - } - - return nil, true, &invalidRequestError{"Unable to parse (un)subscribe request arguments"} - } - - if strings.HasSuffix(r.Method, unsubscribeMethodSuffix) { - requests[i] = rpcRequest{id: id, isPubSub: true, method: r.Method, params: r.Payload} - continue - } - - if len(r.Payload) == 0 { - requests[i] = rpcRequest{id: id, params: nil} - } else { - requests[i] = rpcRequest{id: id, params: r.Payload} - } - if elem := strings.Split(r.Method, serviceMethodSeparator); len(elem) == 2 { - requests[i].service, requests[i].method = elem[0], elem[1] - } else { - requests[i].err = &methodNotFoundError{r.Method, ""} - } - } - - return requests, true, nil -} - -// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given -// types. It returns the parsed values or an error when the parsing failed. -func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interface{}) ([]reflect.Value, Error) { - if args, ok := params.(json.RawMessage); !ok { - return nil, &invalidParamsError{"Invalid params supplied"} - } else { - return parsePositionalArguments(args, argTypes) - } -} - // parsePositionalArguments tries to parse the given args to an array of values with the // given types. It returns the parsed values or an error when the args could not be // parsed. Missing optional arguments are returned as reflect.Zero values. -func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, Error) { - // Read beginning of the args array. +func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) { dec := json.NewDecoder(bytes.NewReader(rawArgs)) - if tok, _ := dec.Token(); tok != json.Delim('[') { - return nil, &invalidParamsError{"non-array args"} - } - // Read args. - args := make([]reflect.Value, 0, len(types)) - for i := 0; dec.More(); i++ { - if i >= len(types) { - return nil, &invalidParamsError{fmt.Sprintf("too many arguments, want at most %d", len(types))} + var args []reflect.Value + tok, err := dec.Token() + switch { + case err == io.EOF || tok == nil && err == nil: + // "params" is optional and may be empty. Also allow "params":null even though it's + // not in the spec because our own client used to send it. + case err != nil: + return nil, err + case tok == json.Delim('['): + // Read argument array. + if args, err = parseArgumentArray(dec, types); err != nil { + return nil, err } - argval := reflect.New(types[i]) - if err := dec.Decode(argval.Interface()); err != nil { - return nil, &invalidParamsError{fmt.Sprintf("invalid argument %d: %v", i, err)} - } - if argval.IsNil() && types[i].Kind() != reflect.Ptr { - return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} - } - args = append(args, argval.Elem()) - } - // Read end of args array. - if _, err := dec.Token(); err != nil { - return nil, &invalidParamsError{err.Error()} + default: + return nil, errors.New("non-array args") } // Set any missing args to nil. for i := len(args); i < len(types); i++ { if types[i].Kind() != reflect.Ptr { - return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} + return nil, fmt.Errorf("missing value for required argument %d", i) } args = append(args, reflect.Zero(types[i])) } return args, nil } -// CreateResponse will create a JSON-RPC success response with the given id and reply as result. -func (c *jsonCodec) CreateResponse(id interface{}, reply interface{}) interface{} { - return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: reply} +func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Value, error) { + args := make([]reflect.Value, 0, len(types)) + for i := 0; dec.More(); i++ { + if i >= len(types) { + return args, fmt.Errorf("too many arguments, want at most %d", len(types)) + } + argval := reflect.New(types[i]) + if err := dec.Decode(argval.Interface()); err != nil { + return args, fmt.Errorf("invalid argument %d: %v", i, err) + } + if argval.IsNil() && types[i].Kind() != reflect.Ptr { + return args, fmt.Errorf("missing value for required argument %d", i) + } + args = append(args, argval.Elem()) + } + // Read end of args array. + _, err := dec.Token() + return args, err } -// CreateErrorResponse will create a JSON-RPC error response with the given id and error. -func (c *jsonCodec) CreateErrorResponse(id interface{}, err Error) interface{} { - return &jsonErrResponse{Version: jsonrpcVersion, Id: id, Error: jsonError{Code: err.ErrorCode(), Message: err.Error()}} -} - -// CreateErrorResponseWithInfo will create a JSON-RPC error response with the given id and error. -// info is optional and contains additional information about the error. When an empty string is passed it is ignored. -func (c *jsonCodec) CreateErrorResponseWithInfo(id interface{}, err Error, info interface{}) interface{} { - return &jsonErrResponse{Version: jsonrpcVersion, Id: id, - Error: jsonError{Code: err.ErrorCode(), Message: err.Error(), Data: info}} -} - -// CreateNotification will create a JSON-RPC notification with the given subscription id and event as params. -func (c *jsonCodec) CreateNotification(subid, namespace string, event interface{}) interface{} { - return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix, - Params: jsonSubscription{Subscription: subid, Result: event}} -} - -// Write message to client -func (c *jsonCodec) Write(res interface{}) error { - c.encMu.Lock() - defer c.encMu.Unlock() - - return c.encode(res) -} - -// Close the underlying connection -func (c *jsonCodec) Close() { - c.closer.Do(func() { - close(c.closed) - c.rw.Close() - }) -} - -// Closed returns a channel which will be closed when Close is called -func (c *jsonCodec) Closed() <-chan interface{} { - return c.closed +// parseSubscriptionName extracts the subscription name from an encoded argument array. +func parseSubscriptionName(rawArgs json.RawMessage) (string, error) { + dec := json.NewDecoder(bytes.NewReader(rawArgs)) + if tok, _ := dec.Token(); tok != json.Delim('[') { + return "", errors.New("non-array args") + } + v, _ := dec.Token() + method, ok := v.(string) + if !ok { + return "", errors.New("expected subscription name as first argument") + } + return method, nil } diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/json_test.go b/vendor/github.com/ethereum/go-ethereum/rpc/json_test.go deleted file mode 100644 index 5048d2f7..00000000 --- a/vendor/github.com/ethereum/go-ethereum/rpc/json_test.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "bufio" - "bytes" - "encoding/json" - "reflect" - "strconv" - "testing" -) - -type RWC struct { - *bufio.ReadWriter -} - -func (rwc *RWC) Close() error { - return nil -} - -func TestJSONRequestParsing(t *testing.T) { - server := NewServer() - service := new(Service) - - if err := server.RegisterName("calc", service); err != nil { - t.Fatalf("%v", err) - } - - req := bytes.NewBufferString(`{"id": 1234, "jsonrpc": "2.0", "method": "calc_add", "params": [11, 22]}`) - var str string - reply := bytes.NewBufferString(str) - rw := &RWC{bufio.NewReadWriter(bufio.NewReader(req), bufio.NewWriter(reply))} - - codec := NewJSONCodec(rw) - - requests, batch, err := codec.ReadRequestHeaders() - if err != nil { - t.Fatalf("%v", err) - } - - if batch { - t.Fatalf("Request isn't a batch") - } - - if len(requests) != 1 { - t.Fatalf("Expected 1 request but got %d requests - %v", len(requests), requests) - } - - if requests[0].service != "calc" { - t.Fatalf("Expected service 'calc' but got '%s'", requests[0].service) - } - - if requests[0].method != "add" { - t.Fatalf("Expected method 'Add' but got '%s'", requests[0].method) - } - - if rawId, ok := requests[0].id.(*json.RawMessage); ok { - id, e := strconv.ParseInt(string(*rawId), 0, 64) - if e != nil { - t.Fatalf("%v", e) - } - if id != 1234 { - t.Fatalf("Expected id 1234 but got %d", id) - } - } else { - t.Fatalf("invalid request, expected *json.RawMesage got %T", requests[0].id) - } - - var arg int - args := []reflect.Type{reflect.TypeOf(arg), reflect.TypeOf(arg)} - - v, err := codec.ParseRequestArguments(args, requests[0].params) - if err != nil { - t.Fatalf("%v", err) - } - - if len(v) != 2 { - t.Fatalf("Expected 2 argument values, got %d", len(v)) - } - - if v[0].Int() != 11 || v[1].Int() != 22 { - t.Fatalf("expected %d == 11 && %d == 22", v[0].Int(), v[1].Int()) - } -} - -func TestJSONRequestParamsParsing(t *testing.T) { - - var ( - stringT = reflect.TypeOf("") - intT = reflect.TypeOf(0) - intPtrT = reflect.TypeOf(new(int)) - - stringV = reflect.ValueOf("abc") - i = 1 - intV = reflect.ValueOf(i) - intPtrV = reflect.ValueOf(&i) - ) - - var validTests = []struct { - input string - argTypes []reflect.Type - expected []reflect.Value - }{ - {`[]`, []reflect.Type{}, []reflect.Value{}}, - {`[]`, []reflect.Type{intPtrT}, []reflect.Value{intPtrV}}, - {`[1]`, []reflect.Type{intT}, []reflect.Value{intV}}, - {`[1,"abc"]`, []reflect.Type{intT, stringT}, []reflect.Value{intV, stringV}}, - {`[null]`, []reflect.Type{intPtrT}, []reflect.Value{intPtrV}}, - {`[null,"abc"]`, []reflect.Type{intPtrT, stringT, intPtrT}, []reflect.Value{intPtrV, stringV, intPtrV}}, - {`[null,"abc",null]`, []reflect.Type{intPtrT, stringT, intPtrT}, []reflect.Value{intPtrV, stringV, intPtrV}}, - } - - codec := jsonCodec{} - - for _, test := range validTests { - params := (json.RawMessage)([]byte(test.input)) - args, err := codec.ParseRequestArguments(test.argTypes, params) - - if err != nil { - t.Fatal(err) - } - - var match []interface{} - json.Unmarshal([]byte(test.input), &match) - - if len(args) != len(test.argTypes) { - t.Fatalf("expected %d parsed args, got %d", len(test.argTypes), len(args)) - } - - for i, arg := range args { - expected := test.expected[i] - - if arg.Kind() != expected.Kind() { - t.Errorf("expected type for param %d in %s", i, test.input) - } - - if arg.Kind() == reflect.Int && arg.Int() != expected.Int() { - t.Errorf("expected int(%d), got int(%d) in %s", expected.Int(), arg.Int(), test.input) - } - - if arg.Kind() == reflect.String && arg.String() != expected.String() { - t.Errorf("expected string(%s), got string(%s) in %s", expected.String(), arg.String(), test.input) - } - } - } - - var invalidTests = []struct { - input string - argTypes []reflect.Type - }{ - {`[]`, []reflect.Type{intT}}, - {`[null]`, []reflect.Type{intT}}, - {`[1]`, []reflect.Type{stringT}}, - {`[1,2]`, []reflect.Type{stringT}}, - {`["abc", null]`, []reflect.Type{stringT, intT}}, - } - - for i, test := range invalidTests { - if _, err := codec.ParseRequestArguments(test.argTypes, test.input); err == nil { - t.Errorf("expected test %d - %s to fail", i, test.input) - } - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/server.go b/vendor/github.com/ethereum/go-ethereum/rpc/server.go index 214e1d3e..5a92847f 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/server.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/server.go @@ -18,11 +18,7 @@ package rpc import ( "context" - "fmt" - "reflect" - "runtime" - "strings" - "sync" + "io" "sync/atomic" mapset "github.com/deckarep/golang-set" @@ -31,7 +27,9 @@ import ( const MetadataApi = "rpc" -// CodecOption specifies which type of messages this codec supports +// CodecOption specifies which type of messages a codec supports. +// +// Deprecated: this option is no longer honored by Server. type CodecOption int const ( @@ -42,22 +40,94 @@ const ( OptionSubscriptions = 1 << iota // support pub sub ) -// NewServer will create a new server instance with no registered handlers. -func NewServer() *Server { - server := &Server{ - services: make(serviceRegistry), - codecs: mapset.NewSet(), - run: 1, - } +// Server is an RPC server. +type Server struct { + services serviceRegistry + idgen func() ID + run int32 + codecs mapset.Set +} - // register a default service which will provide meta information about the RPC service such as the services and - // methods it offers. +// NewServer creates a new server instance with no registered handlers. +func NewServer() *Server { + server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet(), run: 1} + // Register the default service providing meta information about the RPC service such + // as the services and methods it offers. rpcService := &RPCService{server} server.RegisterName(MetadataApi, rpcService) - return server } +// RegisterName creates a service for the given receiver type under the given name. When no +// methods on the given receiver match the criteria to be either a RPC method or a +// subscription an error is returned. Otherwise a new service is created and added to the +// service collection this server provides to clients. +func (s *Server) RegisterName(name string, receiver interface{}) error { + return s.services.registerName(name, receiver) +} + +// ServeCodec reads incoming requests from codec, calls the appropriate callback and writes +// the response back using the given codec. It will block until the codec is closed or the +// server is stopped. In either case the codec is closed. +// +// Note that codec options are no longer supported. +func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { + defer codec.Close() + + // Don't serve if server is stopped. + if atomic.LoadInt32(&s.run) == 0 { + return + } + + // Add the codec to the set so it can be closed by Stop. + s.codecs.Add(codec) + defer s.codecs.Remove(codec) + + c := initClient(codec, s.idgen, &s.services) + <-codec.Closed() + c.Close() +} + +// serveSingleRequest reads and processes a single RPC request from the given codec. This +// is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in +// this mode. +func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { + // Don't serve if server is stopped. + if atomic.LoadInt32(&s.run) == 0 { + return + } + + h := newHandler(ctx, codec, s.idgen, &s.services) + h.allowSubscribe = false + defer h.close(io.EOF, nil) + + reqs, batch, err := codec.Read() + if err != nil { + if err != io.EOF { + codec.Write(ctx, errorMessage(&invalidMessageError{"parse error"})) + } + return + } + if batch { + h.handleBatch(reqs) + } else { + h.handleMsg(reqs[0]) + } +} + +// Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending +// requests to finish, then closes all codecs which will cancel pending requests and +// subscriptions. +func (s *Server) Stop() { + if atomic.CompareAndSwapInt32(&s.run, 1, 0) { + log.Debug("RPC server shutting down") + s.codecs.Each(func(c interface{}) bool { + c.(ServerCodec).Close() + return true + }) + } +} + // RPCService gives meta information about the server. // e.g. gives information about the loaded modules. type RPCService struct { @@ -66,377 +136,12 @@ type RPCService struct { // Modules returns the list of RPC services with their version number func (s *RPCService) Modules() map[string]string { + s.server.services.mu.Lock() + defer s.server.services.mu.Unlock() + modules := make(map[string]string) - for name := range s.server.services { + for name := range s.server.services.services { modules[name] = "1.0" } return modules } - -// RegisterName will create a service for the given rcvr type under the given name. When no methods on the given rcvr -// match the criteria to be either a RPC method or a subscription an error is returned. Otherwise a new service is -// created and added to the service collection this server instance serves. -func (s *Server) RegisterName(name string, rcvr interface{}) error { - if s.services == nil { - s.services = make(serviceRegistry) - } - - svc := new(service) - svc.typ = reflect.TypeOf(rcvr) - rcvrVal := reflect.ValueOf(rcvr) - - if name == "" { - return fmt.Errorf("no service name for type %s", svc.typ.String()) - } - if !isExported(reflect.Indirect(rcvrVal).Type().Name()) { - return fmt.Errorf("%s is not exported", reflect.Indirect(rcvrVal).Type().Name()) - } - - methods, subscriptions := suitableCallbacks(rcvrVal, svc.typ) - - if len(methods) == 0 && len(subscriptions) == 0 { - return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr) - } - - // already a previous service register under given name, merge methods/subscriptions - if regsvc, present := s.services[name]; present { - for _, m := range methods { - regsvc.callbacks[formatName(m.method.Name)] = m - } - for _, s := range subscriptions { - regsvc.subscriptions[formatName(s.method.Name)] = s - } - return nil - } - - svc.name = name - svc.callbacks, svc.subscriptions = methods, subscriptions - - s.services[svc.name] = svc - return nil -} - -// serveRequest will reads requests from the codec, calls the RPC callback and -// writes the response to the given codec. -// -// If singleShot is true it will process a single request, otherwise it will handle -// requests until the codec returns an error when reading a request (in most cases -// an EOF). It executes requests in parallel when singleShot is false. -func (s *Server) serveRequest(ctx context.Context, codec ServerCodec, singleShot bool, options CodecOption) error { - var pend sync.WaitGroup - - defer func() { - if err := recover(); err != nil { - const size = 64 << 10 - buf := make([]byte, size) - buf = buf[:runtime.Stack(buf, false)] - log.Error(string(buf)) - } - s.codecsMu.Lock() - s.codecs.Remove(codec) - s.codecsMu.Unlock() - }() - - // ctx, cancel := context.WithCancel(context.Background()) - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // if the codec supports notification include a notifier that callbacks can use - // to send notification to clients. It is tied to the codec/connection. If the - // connection is closed the notifier will stop and cancels all active subscriptions. - if options&OptionSubscriptions == OptionSubscriptions { - ctx = context.WithValue(ctx, notifierKey{}, newNotifier(codec)) - } - s.codecsMu.Lock() - if atomic.LoadInt32(&s.run) != 1 { // server stopped - s.codecsMu.Unlock() - return &shutdownError{} - } - s.codecs.Add(codec) - s.codecsMu.Unlock() - - // test if the server is ordered to stop - for atomic.LoadInt32(&s.run) == 1 { - reqs, batch, err := s.readRequest(codec) - if err != nil { - // If a parsing error occurred, send an error - if err.Error() != "EOF" { - log.Debug(fmt.Sprintf("read error %v\n", err)) - codec.Write(codec.CreateErrorResponse(nil, err)) - } - // Error or end of stream, wait for requests and tear down - pend.Wait() - return nil - } - - // check if server is ordered to shutdown and return an error - // telling the client that his request failed. - if atomic.LoadInt32(&s.run) != 1 { - err = &shutdownError{} - if batch { - resps := make([]interface{}, len(reqs)) - for i, r := range reqs { - resps[i] = codec.CreateErrorResponse(&r.id, err) - } - codec.Write(resps) - } else { - codec.Write(codec.CreateErrorResponse(&reqs[0].id, err)) - } - return nil - } - // If a single shot request is executing, run and return immediately - if singleShot { - if batch { - s.execBatch(ctx, codec, reqs) - } else { - s.exec(ctx, codec, reqs[0]) - } - return nil - } - // For multi-shot connections, start a goroutine to serve and loop back - pend.Add(1) - - go func(reqs []*serverRequest, batch bool) { - defer pend.Done() - if batch { - s.execBatch(ctx, codec, reqs) - } else { - s.exec(ctx, codec, reqs[0]) - } - }(reqs, batch) - } - return nil -} - -// ServeCodec reads incoming requests from codec, calls the appropriate callback and writes the -// response back using the given codec. It will block until the codec is closed or the server is -// stopped. In either case the codec is closed. -func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { - defer codec.Close() - s.serveRequest(context.Background(), codec, false, options) -} - -// ServeSingleRequest reads and processes a single RPC request from the given codec. It will not -// close the codec unless a non-recoverable error has occurred. Note, this method will return after -// a single request has been processed! -func (s *Server) ServeSingleRequest(ctx context.Context, codec ServerCodec, options CodecOption) { - s.serveRequest(ctx, codec, true, options) -} - -// Stop will stop reading new requests, wait for stopPendingRequestTimeout to allow pending requests to finish, -// close all codecs which will cancel pending requests/subscriptions. -func (s *Server) Stop() { - if atomic.CompareAndSwapInt32(&s.run, 1, 0) { - log.Debug("RPC Server shutdown initiatied") - s.codecsMu.Lock() - defer s.codecsMu.Unlock() - s.codecs.Each(func(c interface{}) bool { - c.(ServerCodec).Close() - return true - }) - } -} - -// createSubscription will call the subscription callback and returns the subscription id or error. -func (s *Server) createSubscription(ctx context.Context, c ServerCodec, req *serverRequest) (ID, error) { - // subscription have as first argument the context following optional arguments - args := []reflect.Value{req.callb.rcvr, reflect.ValueOf(ctx)} - args = append(args, req.args...) - reply := req.callb.method.Func.Call(args) - - if !reply[1].IsNil() { // subscription creation failed - return "", reply[1].Interface().(error) - } - - return reply[0].Interface().(*Subscription).ID, nil -} - -// handle executes a request and returns the response from the callback. -func (s *Server) handle(ctx context.Context, codec ServerCodec, req *serverRequest) (interface{}, func()) { - if req.err != nil { - return codec.CreateErrorResponse(&req.id, req.err), nil - } - - if req.isUnsubscribe { // cancel subscription, first param must be the subscription id - if len(req.args) >= 1 && req.args[0].Kind() == reflect.String { - notifier, supported := NotifierFromContext(ctx) - if !supported { // interface doesn't support subscriptions (e.g. http) - return codec.CreateErrorResponse(&req.id, &callbackError{ErrNotificationsUnsupported.Error()}), nil - } - - subid := ID(req.args[0].String()) - if err := notifier.unsubscribe(subid); err != nil { - return codec.CreateErrorResponse(&req.id, &callbackError{err.Error()}), nil - } - - return codec.CreateResponse(req.id, true), nil - } - return codec.CreateErrorResponse(&req.id, &invalidParamsError{"Expected subscription id as first argument"}), nil - } - - if req.callb.isSubscribe { - subid, err := s.createSubscription(ctx, codec, req) - if err != nil { - return codec.CreateErrorResponse(&req.id, &callbackError{err.Error()}), nil - } - - // active the subscription after the sub id was successfully sent to the client - activateSub := func() { - notifier, _ := NotifierFromContext(ctx) - notifier.activate(subid, req.svcname) - } - - return codec.CreateResponse(req.id, subid), activateSub - } - - // regular RPC call, prepare arguments - if len(req.args) != len(req.callb.argTypes) { - rpcErr := &invalidParamsError{fmt.Sprintf("%s%s%s expects %d parameters, got %d", - req.svcname, serviceMethodSeparator, req.callb.method.Name, - len(req.callb.argTypes), len(req.args))} - return codec.CreateErrorResponse(&req.id, rpcErr), nil - } - - arguments := []reflect.Value{req.callb.rcvr} - if req.callb.hasCtx { - arguments = append(arguments, reflect.ValueOf(ctx)) - } - if len(req.args) > 0 { - arguments = append(arguments, req.args...) - } - - // execute RPC method and return result - reply := req.callb.method.Func.Call(arguments) - if len(reply) == 0 { - return codec.CreateResponse(req.id, nil), nil - } - if req.callb.errPos >= 0 { // test if method returned an error - if !reply[req.callb.errPos].IsNil() { - e := reply[req.callb.errPos].Interface().(error) - res := codec.CreateErrorResponse(&req.id, &callbackError{e.Error()}) - return res, nil - } - } - return codec.CreateResponse(req.id, reply[0].Interface()), nil -} - -// exec executes the given request and writes the result back using the codec. -func (s *Server) exec(ctx context.Context, codec ServerCodec, req *serverRequest) { - var response interface{} - var callback func() - if req.err != nil { - response = codec.CreateErrorResponse(&req.id, req.err) - } else { - response, callback = s.handle(ctx, codec, req) - } - - if err := codec.Write(response); err != nil { - log.Error(fmt.Sprintf("%v\n", err)) - codec.Close() - } - - // when request was a subscribe request this allows these subscriptions to be actived - if callback != nil { - callback() - } -} - -// execBatch executes the given requests and writes the result back using the codec. -// It will only write the response back when the last request is processed. -func (s *Server) execBatch(ctx context.Context, codec ServerCodec, requests []*serverRequest) { - responses := make([]interface{}, len(requests)) - var callbacks []func() - for i, req := range requests { - if req.err != nil { - responses[i] = codec.CreateErrorResponse(&req.id, req.err) - } else { - var callback func() - if responses[i], callback = s.handle(ctx, codec, req); callback != nil { - callbacks = append(callbacks, callback) - } - } - } - - if err := codec.Write(responses); err != nil { - log.Error(fmt.Sprintf("%v\n", err)) - codec.Close() - } - - // when request holds one of more subscribe requests this allows these subscriptions to be activated - for _, c := range callbacks { - c() - } -} - -// readRequest requests the next (batch) request from the codec. It will return the collection -// of requests, an indication if the request was a batch, the invalid request identifier and an -// error when the request could not be read/parsed. -func (s *Server) readRequest(codec ServerCodec) ([]*serverRequest, bool, Error) { - reqs, batch, err := codec.ReadRequestHeaders() - if err != nil { - return nil, batch, err - } - - requests := make([]*serverRequest, len(reqs)) - - // verify requests - for i, r := range reqs { - var ok bool - var svc *service - - if r.err != nil { - requests[i] = &serverRequest{id: r.id, err: r.err} - continue - } - - if r.isPubSub && strings.HasSuffix(r.method, unsubscribeMethodSuffix) { - requests[i] = &serverRequest{id: r.id, isUnsubscribe: true} - argTypes := []reflect.Type{reflect.TypeOf("")} // expect subscription id as first arg - if args, err := codec.ParseRequestArguments(argTypes, r.params); err == nil { - requests[i].args = args - } else { - requests[i].err = &invalidParamsError{err.Error()} - } - continue - } - - if svc, ok = s.services[r.service]; !ok { // rpc method isn't available - requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} - continue - } - - if r.isPubSub { // eth_subscribe, r.method contains the subscription method name - if callb, ok := svc.subscriptions[r.method]; ok { - requests[i] = &serverRequest{id: r.id, svcname: svc.name, callb: callb} - if r.params != nil && len(callb.argTypes) > 0 { - argTypes := []reflect.Type{reflect.TypeOf("")} - argTypes = append(argTypes, callb.argTypes...) - if args, err := codec.ParseRequestArguments(argTypes, r.params); err == nil { - requests[i].args = args[1:] // first one is service.method name which isn't an actual argument - } else { - requests[i].err = &invalidParamsError{err.Error()} - } - } - } else { - requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} - } - continue - } - - if callb, ok := svc.callbacks[r.method]; ok { // lookup RPC method - requests[i] = &serverRequest{id: r.id, svcname: svc.name, callb: callb} - if r.params != nil && len(callb.argTypes) > 0 { - if args, err := codec.ParseRequestArguments(callb.argTypes, r.params); err == nil { - requests[i].args = args - } else { - requests[i].err = &invalidParamsError{err.Error()} - } - } - continue - } - - requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} - } - - return requests, batch, nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/server_test.go b/vendor/github.com/ethereum/go-ethereum/rpc/server_test.go index 90d62f26..39099546 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/server_test.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/server_test.go @@ -17,146 +17,136 @@ package rpc import ( - "context" - "encoding/json" + "bufio" + "bytes" + "io" + "io/ioutil" "net" - "reflect" + "path/filepath" + "strings" "testing" "time" ) -type Service struct{} - -type Args struct { - S string -} - -func (s *Service) NoArgsRets() { -} - -type Result struct { - String string - Int int - Args *Args -} - -func (s *Service) Echo(str string, i int, args *Args) Result { - return Result{str, i, args} -} - -func (s *Service) EchoWithCtx(ctx context.Context, str string, i int, args *Args) Result { - return Result{str, i, args} -} - -func (s *Service) Sleep(ctx context.Context, duration time.Duration) { - select { - case <-time.After(duration): - case <-ctx.Done(): - } -} - -func (s *Service) Rets() (string, error) { - return "", nil -} - -func (s *Service) InvalidRets1() (error, string) { - return nil, "" -} - -func (s *Service) InvalidRets2() (string, string) { - return "", "" -} - -func (s *Service) InvalidRets3() (string, string, error) { - return "", "", nil -} - -func (s *Service) Subscription(ctx context.Context) (*Subscription, error) { - return nil, nil -} - func TestServerRegisterName(t *testing.T) { server := NewServer() - service := new(Service) - - if err := server.RegisterName("calc", service); err != nil { - t.Fatalf("%v", err) - } - - if len(server.services) != 2 { - t.Fatalf("Expected 2 service entries, got %d", len(server.services)) - } - - svc, ok := server.services["calc"] - if !ok { - t.Fatalf("Expected service calc to be registered") - } - - if len(svc.callbacks) != 5 { - t.Errorf("Expected 5 callbacks for service 'calc', got %d", len(svc.callbacks)) - } - - if len(svc.subscriptions) != 1 { - t.Errorf("Expected 1 subscription for service 'calc', got %d", len(svc.subscriptions)) - } -} - -func testServerMethodExecution(t *testing.T, method string) { - server := NewServer() - service := new(Service) + service := new(testService) if err := server.RegisterName("test", service); err != nil { t.Fatalf("%v", err) } - stringArg := "string arg" - intArg := 1122 - argsArg := &Args{"abcde"} - params := []interface{}{stringArg, intArg, argsArg} + if len(server.services.services) != 2 { + t.Fatalf("Expected 2 service entries, got %d", len(server.services.services)) + } - request := map[string]interface{}{ - "id": 12345, - "method": "test_" + method, - "version": "2.0", - "params": params, + svc, ok := server.services.services["test"] + if !ok { + t.Fatalf("Expected service calc to be registered") + } + + wantCallbacks := 7 + if len(svc.callbacks) != wantCallbacks { + t.Errorf("Expected %d callbacks for service 'service', got %d", wantCallbacks, len(svc.callbacks)) + } +} + +func TestServer(t *testing.T) { + files, err := ioutil.ReadDir("testdata") + if err != nil { + t.Fatal("where'd my testdata go?") + } + for _, f := range files { + if f.IsDir() || strings.HasPrefix(f.Name(), ".") { + continue + } + path := filepath.Join("testdata", f.Name()) + name := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) + t.Run(name, func(t *testing.T) { + runTestScript(t, path) + }) + } +} + +func runTestScript(t *testing.T, file string) { + server := newTestServer() + content, err := ioutil.ReadFile(file) + if err != nil { + t.Fatal(err) } clientConn, serverConn := net.Pipe() defer clientConn.Close() - - go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation) - - out := json.NewEncoder(clientConn) - in := json.NewDecoder(clientConn) - - if err := out.Encode(request); err != nil { - t.Fatal(err) - } - - response := jsonSuccessResponse{Result: &Result{}} - if err := in.Decode(&response); err != nil { - t.Fatal(err) - } - - if result, ok := response.Result.(*Result); ok { - if result.String != stringArg { - t.Errorf("expected %s, got : %s\n", stringArg, result.String) + go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) + readbuf := bufio.NewReader(clientConn) + for _, line := range strings.Split(string(content), "\n") { + line = strings.TrimSpace(line) + switch { + case len(line) == 0 || strings.HasPrefix(line, "//"): + // skip comments, blank lines + continue + case strings.HasPrefix(line, "--> "): + t.Log(line) + // write to connection + clientConn.SetWriteDeadline(time.Now().Add(5 * time.Second)) + if _, err := io.WriteString(clientConn, line[4:]+"\n"); err != nil { + t.Fatalf("write error: %v", err) + } + case strings.HasPrefix(line, "<-- "): + t.Log(line) + want := line[4:] + // read line from connection and compare text + clientConn.SetReadDeadline(time.Now().Add(5 * time.Second)) + sent, err := readbuf.ReadString('\n') + if err != nil { + t.Fatalf("read error: %v", err) + } + sent = strings.TrimRight(sent, "\r\n") + if sent != want { + t.Errorf("wrong line from server\ngot: %s\nwant: %s", sent, want) + } + default: + panic("invalid line in test script: " + line) } - if result.Int != intArg { - t.Errorf("expected %d, got %d\n", intArg, result.Int) - } - if !reflect.DeepEqual(result.Args, argsArg) { - t.Errorf("expected %v, got %v\n", argsArg, result) - } - } else { - t.Fatalf("invalid response: expected *Result - got: %T", response.Result) } } -func TestServerMethodExecution(t *testing.T) { - testServerMethodExecution(t, "echo") -} +// This test checks that responses are delivered for very short-lived connections that +// only carry a single request. +func TestServerShortLivedConn(t *testing.T) { + server := newTestServer() + defer server.Stop() -func TestServerMethodWithCtx(t *testing.T) { - testServerMethodExecution(t, "echoWithCtx") + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("can't listen:", err) + } + defer listener.Close() + go server.ServeListener(listener) + + var ( + request = `{"jsonrpc":"2.0","id":1,"method":"rpc_modules"}` + "\n" + wantResp = `{"jsonrpc":"2.0","id":1,"result":{"nftest":"1.0","rpc":"1.0","test":"1.0"}}` + "\n" + deadline = time.Now().Add(10 * time.Second) + ) + for i := 0; i < 20; i++ { + conn, err := net.Dial("tcp", listener.Addr().String()) + if err != nil { + t.Fatal("can't dial:", err) + } + defer conn.Close() + conn.SetDeadline(deadline) + // Write the request, then half-close the connection so the server stops reading. + conn.Write([]byte(request)) + conn.(*net.TCPConn).CloseWrite() + // Now try to get the response. + buf := make([]byte, 2000) + n, err := conn.Read(buf) + if err != nil { + t.Fatal("read error:", err) + } + if !bytes.Equal(buf[:n], []byte(wantResp)) { + t.Fatalf("wrong response: %s", buf[:n]) + } + } } diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/service.go b/vendor/github.com/ethereum/go-ethereum/rpc/service.go new file mode 100644 index 00000000..a9426c6b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/service.go @@ -0,0 +1,285 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rpc + +import ( + "context" + "errors" + "fmt" + "reflect" + "runtime" + "strings" + "sync" + "unicode" + "unicode/utf8" + + "github.com/ethereum/go-ethereum/log" +) + +var ( + contextType = reflect.TypeOf((*context.Context)(nil)).Elem() + errorType = reflect.TypeOf((*error)(nil)).Elem() + subscriptionType = reflect.TypeOf(Subscription{}) + stringType = reflect.TypeOf("") +) + +type serviceRegistry struct { + mu sync.Mutex + services map[string]service +} + +// service represents a registered object. +type service struct { + name string // name for service + callbacks map[string]*callback // registered handlers + subscriptions map[string]*callback // available subscriptions/notifications +} + +// callback is a method callback which was registered in the server +type callback struct { + fn reflect.Value // the function + rcvr reflect.Value // receiver object of method, set if fn is method + argTypes []reflect.Type // input argument types + hasCtx bool // method's first argument is a context (not included in argTypes) + errPos int // err return idx, of -1 when method cannot return error + isSubscribe bool // true if this is a subscription callback +} + +func (r *serviceRegistry) registerName(name string, rcvr interface{}) error { + rcvrVal := reflect.ValueOf(rcvr) + if name == "" { + return fmt.Errorf("no service name for type %s", rcvrVal.Type().String()) + } + callbacks := suitableCallbacks(rcvrVal) + if len(callbacks) == 0 { + return fmt.Errorf("service %T doesn't have any suitable methods/subscriptions to expose", rcvr) + } + + r.mu.Lock() + defer r.mu.Unlock() + if r.services == nil { + r.services = make(map[string]service) + } + svc, ok := r.services[name] + if !ok { + svc = service{ + name: name, + callbacks: make(map[string]*callback), + subscriptions: make(map[string]*callback), + } + r.services[name] = svc + } + for name, cb := range callbacks { + if cb.isSubscribe { + svc.subscriptions[name] = cb + } else { + svc.callbacks[name] = cb + } + } + return nil +} + +// callback returns the callback corresponding to the given RPC method name. +func (r *serviceRegistry) callback(method string) *callback { + elem := strings.SplitN(method, serviceMethodSeparator, 2) + if len(elem) != 2 { + return nil + } + r.mu.Lock() + defer r.mu.Unlock() + return r.services[elem[0]].callbacks[elem[1]] +} + +// subscription returns a subscription callback in the given service. +func (r *serviceRegistry) subscription(service, name string) *callback { + r.mu.Lock() + defer r.mu.Unlock() + return r.services[service].subscriptions[name] +} + +// suitableCallbacks iterates over the methods of the given type. It determines if a method +// satisfies the criteria for a RPC callback or a subscription callback and adds it to the +// collection of callbacks. See server documentation for a summary of these criteria. +func suitableCallbacks(receiver reflect.Value) map[string]*callback { + typ := receiver.Type() + callbacks := make(map[string]*callback) + for m := 0; m < typ.NumMethod(); m++ { + method := typ.Method(m) + if method.PkgPath != "" { + continue // method not exported + } + cb := newCallback(receiver, method.Func) + if cb == nil { + continue // function invalid + } + name := formatName(method.Name) + callbacks[name] = cb + } + return callbacks +} + +// newCallback turns fn (a function) into a callback object. It returns nil if the function +// is unsuitable as an RPC callback. +func newCallback(receiver, fn reflect.Value) *callback { + fntype := fn.Type() + c := &callback{fn: fn, rcvr: receiver, errPos: -1, isSubscribe: isPubSub(fntype)} + // Determine parameter types. They must all be exported or builtin types. + c.makeArgTypes() + if !allExportedOrBuiltin(c.argTypes) { + return nil + } + // Verify return types. The function must return at most one error + // and/or one other non-error value. + outs := make([]reflect.Type, fntype.NumOut()) + for i := 0; i < fntype.NumOut(); i++ { + outs[i] = fntype.Out(i) + } + if len(outs) > 2 || !allExportedOrBuiltin(outs) { + return nil + } + // If an error is returned, it must be the last returned value. + switch { + case len(outs) == 1 && isErrorType(outs[0]): + c.errPos = 0 + case len(outs) == 2: + if isErrorType(outs[0]) || !isErrorType(outs[1]) { + return nil + } + c.errPos = 1 + } + return c +} + +// makeArgTypes composes the argTypes list. +func (c *callback) makeArgTypes() { + fntype := c.fn.Type() + // Skip receiver and context.Context parameter (if present). + firstArg := 0 + if c.rcvr.IsValid() { + firstArg++ + } + if fntype.NumIn() > firstArg && fntype.In(firstArg) == contextType { + c.hasCtx = true + firstArg++ + } + // Add all remaining parameters. + c.argTypes = make([]reflect.Type, fntype.NumIn()-firstArg) + for i := firstArg; i < fntype.NumIn(); i++ { + c.argTypes[i-firstArg] = fntype.In(i) + } +} + +// call invokes the callback. +func (c *callback) call(ctx context.Context, method string, args []reflect.Value) (res interface{}, errRes error) { + // Create the argument slice. + fullargs := make([]reflect.Value, 0, 2+len(args)) + if c.rcvr.IsValid() { + fullargs = append(fullargs, c.rcvr) + } + if c.hasCtx { + fullargs = append(fullargs, reflect.ValueOf(ctx)) + } + fullargs = append(fullargs, args...) + + // Catch panic while running the callback. + defer func() { + if err := recover(); err != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + log.Error("RPC method " + method + " crashed: " + fmt.Sprintf("%v\n%s", err, buf)) + errRes = errors.New("method handler crashed") + } + }() + // Run the callback. + results := c.fn.Call(fullargs) + if len(results) == 0 { + return nil, nil + } + if c.errPos >= 0 && !results[c.errPos].IsNil() { + // Method has returned non-nil error value. + err := results[c.errPos].Interface().(error) + return reflect.Value{}, err + } + return results[0].Interface(), nil +} + +// Is this an exported - upper case - name? +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// Are all those types exported or built-in? +func allExportedOrBuiltin(types []reflect.Type) bool { + for _, typ := range types { + for typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + // PkgPath will be non-empty even for an exported type, + // so we need to check the type name as well. + if !isExported(typ.Name()) && typ.PkgPath() != "" { + return false + } + } + return true +} + +// Is t context.Context or *context.Context? +func isContextType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t == contextType +} + +// Does t satisfy the error interface? +func isErrorType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.Implements(errorType) +} + +// Is t Subscription or *Subscription? +func isSubscriptionType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t == subscriptionType +} + +// isPubSub tests whether the given method has as as first argument a context.Context and +// returns the pair (Subscription, error). +func isPubSub(methodType reflect.Type) bool { + // numIn(0) is the receiver type + if methodType.NumIn() < 2 || methodType.NumOut() != 2 { + return false + } + return isContextType(methodType.In(1)) && + isSubscriptionType(methodType.Out(0)) && + isErrorType(methodType.Out(1)) +} + +// formatName converts to first character of name to lowercase. +func formatName(name string) string { + ret := []rune(name) + if len(ret) > 0 { + ret[0] = unicode.ToLower(ret[0]) + } + return string(ret) +} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/stdio.go b/vendor/github.com/ethereum/go-ethereum/rpc/stdio.go index ea552cca..d5dc066c 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/stdio.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/stdio.go @@ -19,6 +19,7 @@ package rpc import ( "context" "errors" + "io" "net" "os" "time" @@ -26,39 +27,38 @@ import ( // DialStdIO creates a client on stdin/stdout. func DialStdIO(ctx context.Context) (*Client, error) { - return newClient(ctx, func(_ context.Context) (net.Conn, error) { - return stdioConn{}, nil + return DialIO(ctx, os.Stdin, os.Stdout) +} + +// DialIO creates a client which uses the given IO channels +func DialIO(ctx context.Context, in io.Reader, out io.Writer) (*Client, error) { + return newClient(ctx, func(_ context.Context) (ServerCodec, error) { + return NewJSONCodec(stdioConn{ + in: in, + out: out, + }), nil }) } -type stdioConn struct{} +type stdioConn struct { + in io.Reader + out io.Writer +} func (io stdioConn) Read(b []byte) (n int, err error) { - return os.Stdin.Read(b) + return io.in.Read(b) } func (io stdioConn) Write(b []byte) (n int, err error) { - return os.Stdout.Write(b) + return io.out.Write(b) } func (io stdioConn) Close() error { return nil } -func (io stdioConn) LocalAddr() net.Addr { - return &net.UnixAddr{Name: "stdio", Net: "stdio"} -} - -func (io stdioConn) RemoteAddr() net.Addr { - return &net.UnixAddr{Name: "stdio", Net: "stdio"} -} - -func (io stdioConn) SetDeadline(t time.Time) error { - return &net.OpError{Op: "set", Net: "stdio", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} -} - -func (io stdioConn) SetReadDeadline(t time.Time) error { - return &net.OpError{Op: "set", Net: "stdio", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +func (io stdioConn) RemoteAddr() string { + return "/dev/stdin" } func (io stdioConn) SetWriteDeadline(t time.Time) error { diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/subscription.go b/vendor/github.com/ethereum/go-ethereum/rpc/subscription.go index 6bbb6f75..c1e869b8 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/subscription.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/subscription.go @@ -17,9 +17,19 @@ package rpc import ( + "bufio" + "container/list" "context" + crand "crypto/rand" + "encoding/binary" + "encoding/hex" + "encoding/json" "errors" + "math/rand" + "reflect" + "strings" "sync" + "time" ) var ( @@ -29,10 +39,147 @@ var ( ErrSubscriptionNotFound = errors.New("subscription not found") ) +var globalGen = randomIDGenerator() + // ID defines a pseudo random number that is used to identify RPC subscriptions. type ID string -// a Subscription is created by a notifier and tight to that notifier. The client can use +// NewID returns a new, random ID. +func NewID() ID { + return globalGen() +} + +// randomIDGenerator returns a function generates a random IDs. +func randomIDGenerator() func() ID { + seed, err := binary.ReadVarint(bufio.NewReader(crand.Reader)) + if err != nil { + seed = int64(time.Now().Nanosecond()) + } + var ( + mu sync.Mutex + rng = rand.New(rand.NewSource(seed)) + ) + return func() ID { + mu.Lock() + defer mu.Unlock() + id := make([]byte, 16) + rng.Read(id) + return encodeID(id) + } +} + +func encodeID(b []byte) ID { + id := hex.EncodeToString(b) + id = strings.TrimLeft(id, "0") + if id == "" { + id = "0" // ID's are RPC quantities, no leading zero's and 0 is 0x0. + } + return ID("0x" + id) +} + +type notifierKey struct{} + +// NotifierFromContext returns the Notifier value stored in ctx, if any. +func NotifierFromContext(ctx context.Context) (*Notifier, bool) { + n, ok := ctx.Value(notifierKey{}).(*Notifier) + return n, ok +} + +// Notifier is tied to a RPC connection that supports subscriptions. +// Server callbacks use the notifier to send notifications. +type Notifier struct { + h *handler + namespace string + + mu sync.Mutex + sub *Subscription + buffer []json.RawMessage + callReturned bool + activated bool +} + +// CreateSubscription returns a new subscription that is coupled to the +// RPC connection. By default subscriptions are inactive and notifications +// are dropped until the subscription is marked as active. This is done +// by the RPC server after the subscription ID is send to the client. +func (n *Notifier) CreateSubscription() *Subscription { + n.mu.Lock() + defer n.mu.Unlock() + + if n.sub != nil { + panic("can't create multiple subscriptions with Notifier") + } else if n.callReturned { + panic("can't create subscription after subscribe call has returned") + } + n.sub = &Subscription{ID: n.h.idgen(), namespace: n.namespace, err: make(chan error, 1)} + return n.sub +} + +// Notify sends a notification to the client with the given data as payload. +// If an error occurs the RPC connection is closed and the error is returned. +func (n *Notifier) Notify(id ID, data interface{}) error { + enc, err := json.Marshal(data) + if err != nil { + return err + } + + n.mu.Lock() + defer n.mu.Unlock() + + if n.sub == nil { + panic("can't Notify before subscription is created") + } else if n.sub.ID != id { + panic("Notify with wrong ID") + } + if n.activated { + return n.send(n.sub, enc) + } + n.buffer = append(n.buffer, enc) + return nil +} + +// Closed returns a channel that is closed when the RPC connection is closed. +// Deprecated: use subscription error channel +func (n *Notifier) Closed() <-chan interface{} { + return n.h.conn.Closed() +} + +// takeSubscription returns the subscription (if one has been created). No subscription can +// be created after this call. +func (n *Notifier) takeSubscription() *Subscription { + n.mu.Lock() + defer n.mu.Unlock() + n.callReturned = true + return n.sub +} + +// acticate is called after the subscription ID was sent to client. Notifications are +// buffered before activation. This prevents notifications being sent to the client before +// the subscription ID is sent to the client. +func (n *Notifier) activate() error { + n.mu.Lock() + defer n.mu.Unlock() + + for _, data := range n.buffer { + if err := n.send(n.sub, data); err != nil { + return err + } + } + n.activated = true + return nil +} + +func (n *Notifier) send(sub *Subscription, data json.RawMessage) error { + params, _ := json.Marshal(&subscriptionResult{ID: string(sub.ID), Result: data}) + ctx := context.Background() + return n.h.conn.Write(ctx, &jsonrpcMessage{ + Version: vsn, + Method: n.namespace + notificationMethodSuffix, + Params: params, + }) +} + +// A Subscription is created by a notifier and tight to that notifier. The client can use // this subscription to wait for an unsubscribe request for the client, see Err(). type Subscription struct { ID ID @@ -45,105 +192,136 @@ func (s *Subscription) Err() <-chan error { return s.err } -// notifierKey is used to store a notifier within the connection context. -type notifierKey struct{} - -// Notifier is tight to a RPC connection that supports subscriptions. -// Server callbacks use the notifier to send notifications. -type Notifier struct { - codec ServerCodec - subMu sync.Mutex - active map[ID]*Subscription - inactive map[ID]*Subscription - buffer map[ID][]interface{} // unsent notifications of inactive subscriptions +// MarshalJSON marshals a subscription as its ID. +func (s *Subscription) MarshalJSON() ([]byte, error) { + return json.Marshal(s.ID) } -// newNotifier creates a new notifier that can be used to send subscription -// notifications to the client. -func newNotifier(codec ServerCodec) *Notifier { - return &Notifier{ - codec: codec, - active: make(map[ID]*Subscription), - inactive: make(map[ID]*Subscription), - buffer: make(map[ID][]interface{}), +// ClientSubscription is a subscription established through the Client's Subscribe or +// EthSubscribe methods. +type ClientSubscription struct { + client *Client + etype reflect.Type + channel reflect.Value + namespace string + subid string + in chan json.RawMessage + + quitOnce sync.Once // ensures quit is closed once + quit chan struct{} // quit is closed when the subscription exits + errOnce sync.Once // ensures err is closed once + err chan error +} + +func newClientSubscription(c *Client, namespace string, channel reflect.Value) *ClientSubscription { + sub := &ClientSubscription{ + client: c, + namespace: namespace, + etype: channel.Type().Elem(), + channel: channel, + quit: make(chan struct{}), + err: make(chan error, 1), + in: make(chan json.RawMessage), } + return sub } -// NotifierFromContext returns the Notifier value stored in ctx, if any. -func NotifierFromContext(ctx context.Context) (*Notifier, bool) { - n, ok := ctx.Value(notifierKey{}).(*Notifier) - return n, ok +// Err returns the subscription error channel. The intended use of Err is to schedule +// resubscription when the client connection is closed unexpectedly. +// +// The error channel receives a value when the subscription has ended due +// to an error. The received error is nil if Close has been called +// on the underlying client and no other error has occurred. +// +// The error channel is closed when Unsubscribe is called on the subscription. +func (sub *ClientSubscription) Err() <-chan error { + return sub.err } -// CreateSubscription returns a new subscription that is coupled to the -// RPC connection. By default subscriptions are inactive and notifications -// are dropped until the subscription is marked as active. This is done -// by the RPC server after the subscription ID is send to the client. -func (n *Notifier) CreateSubscription() *Subscription { - s := &Subscription{ID: NewID(), err: make(chan error)} - n.subMu.Lock() - n.inactive[s.ID] = s - n.subMu.Unlock() - return s +// Unsubscribe unsubscribes the notification and closes the error channel. +// It can safely be called more than once. +func (sub *ClientSubscription) Unsubscribe() { + sub.quitWithError(nil, true) + sub.errOnce.Do(func() { close(sub.err) }) } -// Notify sends a notification to the client with the given data as payload. -// If an error occurs the RPC connection is closed and the error is returned. -func (n *Notifier) Notify(id ID, data interface{}) error { - n.subMu.Lock() - defer n.subMu.Unlock() - - if sub, active := n.active[id]; active { - n.send(sub, data) - } else { - n.buffer[id] = append(n.buffer[id], data) - } - return nil -} - -func (n *Notifier) send(sub *Subscription, data interface{}) error { - notification := n.codec.CreateNotification(string(sub.ID), sub.namespace, data) - err := n.codec.Write(notification) - if err != nil { - n.codec.Close() - } - return err -} - -// Closed returns a channel that is closed when the RPC connection is closed. -func (n *Notifier) Closed() <-chan interface{} { - return n.codec.Closed() -} - -// unsubscribe a subscription. -// If the subscription could not be found ErrSubscriptionNotFound is returned. -func (n *Notifier) unsubscribe(id ID) error { - n.subMu.Lock() - defer n.subMu.Unlock() - if s, found := n.active[id]; found { - close(s.err) - delete(n.active, id) - return nil - } - return ErrSubscriptionNotFound -} - -// activate enables a subscription. Until a subscription is enabled all -// notifications are dropped. This method is called by the RPC server after -// the subscription ID was sent to client. This prevents notifications being -// send to the client before the subscription ID is send to the client. -func (n *Notifier) activate(id ID, namespace string) { - n.subMu.Lock() - defer n.subMu.Unlock() - - if sub, found := n.inactive[id]; found { - sub.namespace = namespace - n.active[id] = sub - delete(n.inactive, id) - // Send buffered notifications. - for _, data := range n.buffer[id] { - n.send(sub, data) +func (sub *ClientSubscription) quitWithError(err error, unsubscribeServer bool) { + sub.quitOnce.Do(func() { + // The dispatch loop won't be able to execute the unsubscribe call + // if it is blocked on deliver. Close sub.quit first because it + // unblocks deliver. + close(sub.quit) + if unsubscribeServer { + sub.requestUnsubscribe() } - delete(n.buffer, id) + if err != nil { + if err == ErrClientQuit { + err = nil // Adhere to subscription semantics. + } + sub.err <- err + } + }) +} + +func (sub *ClientSubscription) deliver(result json.RawMessage) (ok bool) { + select { + case sub.in <- result: + return true + case <-sub.quit: + return false } } + +func (sub *ClientSubscription) start() { + sub.quitWithError(sub.forward()) +} + +func (sub *ClientSubscription) forward() (err error, unsubscribeServer bool) { + cases := []reflect.SelectCase{ + {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.quit)}, + {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.in)}, + {Dir: reflect.SelectSend, Chan: sub.channel}, + } + buffer := list.New() + defer buffer.Init() + for { + var chosen int + var recv reflect.Value + if buffer.Len() == 0 { + // Idle, omit send case. + chosen, recv, _ = reflect.Select(cases[:2]) + } else { + // Non-empty buffer, send the first queued item. + cases[2].Send = reflect.ValueOf(buffer.Front().Value) + chosen, recv, _ = reflect.Select(cases) + } + + switch chosen { + case 0: // <-sub.quit + return nil, false + case 1: // <-sub.in + val, err := sub.unmarshal(recv.Interface().(json.RawMessage)) + if err != nil { + return err, true + } + if buffer.Len() == maxClientSubscriptionBuffer { + return ErrSubscriptionQueueOverflow, true + } + buffer.PushBack(val) + case 2: // sub.channel<- + cases[2].Send = reflect.Value{} // Don't hold onto the value. + buffer.Remove(buffer.Front()) + } + } +} + +func (sub *ClientSubscription) unmarshal(result json.RawMessage) (interface{}, error) { + val := reflect.New(sub.etype) + err := json.Unmarshal(result, val.Interface()) + return val.Elem().Interface(), err +} + +func (sub *ClientSubscription) requestUnsubscribe() error { + var result interface{} + return sub.client.Call(&result, sub.namespace+unsubscribeMethodSuffix, sub.subid) +} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/subscription_test.go b/vendor/github.com/ethereum/go-ethereum/rpc/subscription_test.go index 24febc91..eba19245 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/subscription_test.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/subscription_test.go @@ -17,232 +17,62 @@ package rpc import ( - "context" "encoding/json" "fmt" "net" - "sync" + "strings" "testing" "time" ) -type NotificationTestService struct { - mu sync.Mutex - unsubscribed chan string - gotHangSubscriptionReq chan struct{} - unblockHangSubscription chan struct{} -} +func TestNewID(t *testing.T) { + hexchars := "0123456789ABCDEFabcdef" + for i := 0; i < 100; i++ { + id := string(NewID()) + if !strings.HasPrefix(id, "0x") { + t.Fatalf("invalid ID prefix, want '0x...', got %s", id) + } -func (s *NotificationTestService) Echo(i int) int { - return i -} + id = id[2:] + if len(id) == 0 || len(id) > 32 { + t.Fatalf("invalid ID length, want len(id) > 0 && len(id) <= 32), got %d", len(id)) + } -func (s *NotificationTestService) Unsubscribe(subid string) { - if s.unsubscribed != nil { - s.unsubscribed <- subid - } -} - -func (s *NotificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { - notifier, supported := NotifierFromContext(ctx) - if !supported { - return nil, ErrNotificationsUnsupported - } - - // by explicitly creating an subscription we make sure that the subscription id is send back to the client - // before the first subscription.Notify is called. Otherwise the events might be send before the response - // for the eth_subscribe method. - subscription := notifier.CreateSubscription() - - go func() { - // test expects n events, if we begin sending event immediately some events - // will probably be dropped since the subscription ID might not be send to - // the client. - for i := 0; i < n; i++ { - if err := notifier.Notify(subscription.ID, val+i); err != nil { - return + for i := 0; i < len(id); i++ { + if strings.IndexByte(hexchars, id[i]) == -1 { + t.Fatalf("unexpected byte, want any valid hex char, got %c", id[i]) } } - - select { - case <-notifier.Closed(): - case <-subscription.Err(): - } - if s.unsubscribed != nil { - s.unsubscribed <- string(subscription.ID) - } - }() - - return subscription, nil -} - -// HangSubscription blocks on s.unblockHangSubscription before -// sending anything. -func (s *NotificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { - notifier, supported := NotifierFromContext(ctx) - if !supported { - return nil, ErrNotificationsUnsupported - } - - s.gotHangSubscriptionReq <- struct{}{} - <-s.unblockHangSubscription - subscription := notifier.CreateSubscription() - - go func() { - notifier.Notify(subscription.ID, val) - }() - return subscription, nil -} - -func TestNotifications(t *testing.T) { - server := NewServer() - service := &NotificationTestService{unsubscribed: make(chan string)} - - if err := server.RegisterName("eth", service); err != nil { - t.Fatalf("unable to register test service %v", err) - } - - clientConn, serverConn := net.Pipe() - - go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) - - out := json.NewEncoder(clientConn) - in := json.NewDecoder(clientConn) - - n := 5 - val := 12345 - request := map[string]interface{}{ - "id": 1, - "method": "eth_subscribe", - "version": "2.0", - "params": []interface{}{"someSubscription", n, val}, - } - - // create subscription - if err := out.Encode(request); err != nil { - t.Fatal(err) - } - - var subid string - response := jsonSuccessResponse{Result: subid} - if err := in.Decode(&response); err != nil { - t.Fatal(err) - } - - var ok bool - if _, ok = response.Result.(string); !ok { - t.Fatalf("expected subscription id, got %T", response.Result) - } - - for i := 0; i < n; i++ { - var notification jsonNotification - if err := in.Decode(¬ification); err != nil { - t.Fatalf("%v", err) - } - - if int(notification.Params.Result.(float64)) != val+i { - t.Fatalf("expected %d, got %d", val+i, notification.Params.Result) - } - } - - clientConn.Close() // causes notification unsubscribe callback to be called - select { - case <-service.unsubscribed: - case <-time.After(1 * time.Second): - t.Fatal("Unsubscribe not called after one second") } } -func waitForMessages(t *testing.T, in *json.Decoder, successes chan<- jsonSuccessResponse, - failures chan<- jsonErrResponse, notifications chan<- jsonNotification, errors chan<- error) { - - // read and parse server messages - for { - var rmsg json.RawMessage - if err := in.Decode(&rmsg); err != nil { - return - } - - var responses []map[string]interface{} - if rmsg[0] == '[' { - if err := json.Unmarshal(rmsg, &responses); err != nil { - errors <- fmt.Errorf("Received invalid message: %s", rmsg) - return - } - } else { - var msg map[string]interface{} - if err := json.Unmarshal(rmsg, &msg); err != nil { - errors <- fmt.Errorf("Received invalid message: %s", rmsg) - return - } - responses = append(responses, msg) - } - - for _, msg := range responses { - // determine what kind of msg was received and broadcast - // it to over the corresponding channel - if _, found := msg["result"]; found { - successes <- jsonSuccessResponse{ - Version: msg["jsonrpc"].(string), - Id: msg["id"], - Result: msg["result"], - } - continue - } - if _, found := msg["error"]; found { - params := msg["params"].(map[string]interface{}) - failures <- jsonErrResponse{ - Version: msg["jsonrpc"].(string), - Id: msg["id"], - Error: jsonError{int(params["subscription"].(float64)), params["message"].(string), params["data"]}, - } - continue - } - if _, found := msg["params"]; found { - params := msg["params"].(map[string]interface{}) - notifications <- jsonNotification{ - Version: msg["jsonrpc"].(string), - Method: msg["method"].(string), - Params: jsonSubscription{params["subscription"].(string), params["result"]}, - } - continue - } - errors <- fmt.Errorf("Received invalid message: %s", msg) - } - } -} - -// TestSubscriptionMultipleNamespaces ensures that subscriptions can exists -// for multiple different namespaces. -func TestSubscriptionMultipleNamespaces(t *testing.T) { +func TestSubscriptions(t *testing.T) { var ( namespaces = []string{"eth", "shh", "bzz"} - service = NotificationTestService{} - subCount = len(namespaces) * 2 + service = ¬ificationTestService{} + subCount = len(namespaces) notificationCount = 3 server = NewServer() clientConn, serverConn = net.Pipe() out = json.NewEncoder(clientConn) in = json.NewDecoder(clientConn) - successes = make(chan jsonSuccessResponse) - failures = make(chan jsonErrResponse) - notifications = make(chan jsonNotification) - errors = make(chan error, 10) + successes = make(chan subConfirmation) + notifications = make(chan subscriptionResult) + errors = make(chan error, subCount*notificationCount+1) ) // setup and start server for _, namespace := range namespaces { - if err := server.RegisterName(namespace, &service); err != nil { + if err := server.RegisterName(namespace, service); err != nil { t.Fatalf("unable to register test service %v", err) } } - go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions) defer server.Stop() // wait for message and write them to the given channels - go waitForMessages(t, in, successes, failures, notifications, errors) + go waitForMessages(in, successes, notifications, errors) // create subscriptions one by one for i, namespace := range namespaces { @@ -252,27 +82,11 @@ func TestSubscriptionMultipleNamespaces(t *testing.T) { "version": "2.0", "params": []interface{}{"someSubscription", notificationCount, i}, } - if err := out.Encode(&request); err != nil { t.Fatalf("Could not create subscription: %v", err) } } - // create all subscriptions in 1 batch - var requests []interface{} - for i, namespace := range namespaces { - requests = append(requests, map[string]interface{}{ - "id": i, - "method": fmt.Sprintf("%s_subscribe", namespace), - "version": "2.0", - "params": []interface{}{"someSubscription", notificationCount, i}, - }) - } - - if err := out.Encode(&requests); err != nil { - t.Fatalf("Could not create subscription in batch form: %v", err) - } - timeout := time.After(30 * time.Second) subids := make(map[string]string, subCount) count := make(map[string]int, subCount) @@ -285,17 +99,14 @@ func TestSubscriptionMultipleNamespaces(t *testing.T) { } return done } - for !allReceived() { select { - case suc := <-successes: // subscription created - subids[namespaces[int(suc.Id.(float64))]] = suc.Result.(string) + case confirmation := <-successes: // subscription created + subids[namespaces[confirmation.reqid]] = string(confirmation.subid) case notification := <-notifications: - count[notification.Params.Subscription]++ + count[notification.ID]++ case err := <-errors: t.Fatal(err) - case failure := <-failures: - t.Errorf("received error: %v", failure.Error) case <-timeout: for _, namespace := range namespaces { subid, found := subids[namespace] @@ -311,3 +122,85 @@ func TestSubscriptionMultipleNamespaces(t *testing.T) { } } } + +// This test checks that unsubscribing works. +func TestServerUnsubscribe(t *testing.T) { + // Start the server. + server := newTestServer() + service := ¬ificationTestService{unsubscribed: make(chan string)} + server.RegisterName("nftest2", service) + p1, p2 := net.Pipe() + go server.ServeCodec(NewJSONCodec(p1), OptionMethodInvocation|OptionSubscriptions) + + p2.SetDeadline(time.Now().Add(10 * time.Second)) + + // Subscribe. + p2.Write([]byte(`{"jsonrpc":"2.0","id":1,"method":"nftest2_subscribe","params":["someSubscription",0,10]}`)) + + // Handle received messages. + resps := make(chan subConfirmation) + notifications := make(chan subscriptionResult) + errors := make(chan error) + go waitForMessages(json.NewDecoder(p2), resps, notifications, errors) + + // Receive the subscription ID. + var sub subConfirmation + select { + case sub = <-resps: + case err := <-errors: + t.Fatal(err) + } + + // Unsubscribe and check that it is handled on the server side. + p2.Write([]byte(`{"jsonrpc":"2.0","method":"nftest2_unsubscribe","params":["` + sub.subid + `"]}`)) + for { + select { + case id := <-service.unsubscribed: + if id != string(sub.subid) { + t.Errorf("wrong subscription ID unsubscribed") + } + return + case err := <-errors: + t.Fatal(err) + case <-notifications: + // drop notifications + } + } +} + +type subConfirmation struct { + reqid int + subid ID +} + +func waitForMessages(in *json.Decoder, successes chan subConfirmation, notifications chan subscriptionResult, errors chan error) { + for { + var msg jsonrpcMessage + if err := in.Decode(&msg); err != nil { + errors <- fmt.Errorf("decode error: %v", err) + return + } + switch { + case msg.isNotification(): + var res subscriptionResult + if err := json.Unmarshal(msg.Params, &res); err != nil { + errors <- fmt.Errorf("invalid subscription result: %v", err) + } else { + notifications <- res + } + case msg.isResponse(): + var c subConfirmation + if msg.Error != nil { + errors <- msg.Error + } else if err := json.Unmarshal(msg.Result, &c.subid); err != nil { + errors <- fmt.Errorf("invalid response: %v", err) + } else { + json.Unmarshal(msg.ID, &c.reqid) + successes <- c + } + default: + errors <- fmt.Errorf("unrecognized message: %v", msg) + return + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-badid.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-badid.js new file mode 100644 index 00000000..2202b8cc --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-badid.js @@ -0,0 +1,7 @@ +// This test checks processing of messages with invalid ID. + +--> {"id":[],"method":"test_foo"} +<-- {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}} + +--> {"id":{},"method":"test_foo"} +<-- {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-batch.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-batch.js new file mode 100644 index 00000000..f470574f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-batch.js @@ -0,0 +1,14 @@ +// This test checks the behavior of batches with invalid elements. +// Empty batches are not allowed. Batches may contain junk. + +--> [] +<-- {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"empty batch"}} + +--> [1] +<-- [{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}}] + +--> [1,2,3] +<-- [{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}},{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}},{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}}] + +--> [{"jsonrpc":"2.0","id":1,"method":"test_echo","params":["foo",1]},55,{"jsonrpc":"2.0","id":2,"method":"unknown_method"},{"foo":"bar"}] +<-- [{"jsonrpc":"2.0","id":1,"result":{"String":"foo","Int":1,"Args":null}},{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}},{"jsonrpc":"2.0","id":2,"error":{"code":-32601,"message":"the method unknown_method does not exist/is not available"}},{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}}] diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-idonly.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-idonly.js new file mode 100644 index 00000000..79997bee --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-idonly.js @@ -0,0 +1,7 @@ +// This test checks processing of messages that contain just the ID and nothing else. + +--> {"id":1} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} + +--> {"jsonrpc":"2.0","id":1} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-nonobj.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-nonobj.js new file mode 100644 index 00000000..4b9f4d99 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-nonobj.js @@ -0,0 +1,4 @@ +// This test checks behavior for invalid requests. + +--> 1 +<-- {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request"}} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-syntax.json b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-syntax.json new file mode 100644 index 00000000..b1942996 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/invalid-syntax.json @@ -0,0 +1,5 @@ +// This test checks that an error is written for invalid JSON requests. + +--> 'f +<-- {"jsonrpc":"2.0","id":null,"error":{"code":-32700,"message":"invalid character '\\'' looking for beginning of value"}} + diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-batch.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-batch.js new file mode 100644 index 00000000..977af766 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-batch.js @@ -0,0 +1,8 @@ +// There is no response for all-notification batches. + +--> [{"jsonrpc":"2.0","method":"test_echo","params":["x",99]}] + +// This test checks regular batch calls. + +--> [{"jsonrpc":"2.0","id":2,"method":"test_echo","params":[]}, {"jsonrpc":"2.0","id": 3,"method":"test_echo","params":["x",3]}] +<-- [{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"missing value for required argument 0"}},{"jsonrpc":"2.0","id":3,"result":{"String":"x","Int":3,"Args":null}}] diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-echo.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-echo.js new file mode 100644 index 00000000..7a9e9032 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-echo.js @@ -0,0 +1,16 @@ +// This test calls the test_echo method. + +--> {"jsonrpc": "2.0", "id": 2, "method": "test_echo", "params": []} +<-- {"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"missing value for required argument 0"}} + +--> {"jsonrpc": "2.0", "id": 2, "method": "test_echo", "params": ["x"]} +<-- {"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"missing value for required argument 1"}} + +--> {"jsonrpc": "2.0", "id": 2, "method": "test_echo", "params": ["x", 3]} +<-- {"jsonrpc":"2.0","id":2,"result":{"String":"x","Int":3,"Args":null}} + +--> {"jsonrpc": "2.0", "id": 2, "method": "test_echo", "params": ["x", 3, {"S": "foo"}]} +<-- {"jsonrpc":"2.0","id":2,"result":{"String":"x","Int":3,"Args":{"S":"foo"}}} + +--> {"jsonrpc": "2.0", "id": 2, "method": "test_echoWithCtx", "params": ["x", 3, {"S": "foo"}]} +<-- {"jsonrpc":"2.0","id":2,"result":{"String":"x","Int":3,"Args":{"S":"foo"}}} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-namedparam.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-namedparam.js new file mode 100644 index 00000000..9a9372b0 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-namedparam.js @@ -0,0 +1,5 @@ +// This test checks that an error response is sent for calls +// with named parameters. + +--> {"jsonrpc":"2.0","method":"test_echo","params":{"int":23},"id":3} +<-- {"jsonrpc":"2.0","id":3,"error":{"code":-32602,"message":"non-array args"}} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-noargsrets.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-noargsrets.js new file mode 100644 index 00000000..e61cc708 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-noargsrets.js @@ -0,0 +1,4 @@ +// This test calls the test_noArgsRets method. + +--> {"jsonrpc": "2.0", "id": "foo", "method": "test_noArgsRets", "params": []} +<-- {"jsonrpc":"2.0","id":"foo","result":null} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-nomethod.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-nomethod.js new file mode 100644 index 00000000..58ea6f30 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-nomethod.js @@ -0,0 +1,4 @@ +// This test calls a method that doesn't exist. + +--> {"jsonrpc": "2.0", "id": 2, "method": "invalid_method", "params": [2, 3]} +<-- {"jsonrpc":"2.0","id":2,"error":{"code":-32601,"message":"the method invalid_method does not exist/is not available"}} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-noparam.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-noparam.js new file mode 100644 index 00000000..2edf486d --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-noparam.js @@ -0,0 +1,4 @@ +// This test checks that calls with no parameters work. + +--> {"jsonrpc":"2.0","method":"test_noArgsRets","id":3} +<-- {"jsonrpc":"2.0","id":3,"result":null} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-paramsnull.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-paramsnull.js new file mode 100644 index 00000000..8a01bae1 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/reqresp-paramsnull.js @@ -0,0 +1,4 @@ +// This test checks that calls with "params":null work. + +--> {"jsonrpc":"2.0","method":"test_noArgsRets","params":null,"id":3} +<-- {"jsonrpc":"2.0","id":3,"result":null} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/revcall.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/revcall.js new file mode 100644 index 00000000..695d9858 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/revcall.js @@ -0,0 +1,6 @@ +// This test checks reverse calls. + +--> {"jsonrpc":"2.0","id":2,"method":"test_callMeBack","params":["foo",[1]]} +<-- {"jsonrpc":"2.0","id":1,"method":"foo","params":[1]} +--> {"jsonrpc":"2.0","id":1,"result":"my result"} +<-- {"jsonrpc":"2.0","id":2,"result":"my result"} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/revcall2.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/revcall2.js new file mode 100644 index 00000000..acab4655 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/revcall2.js @@ -0,0 +1,7 @@ +// This test checks reverse calls. + +--> {"jsonrpc":"2.0","id":2,"method":"test_callMeBackLater","params":["foo",[1]]} +<-- {"jsonrpc":"2.0","id":2,"result":null} +<-- {"jsonrpc":"2.0","id":1,"method":"foo","params":[1]} +--> {"jsonrpc":"2.0","id":1,"result":"my result"} + diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testdata/subscription.js b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/subscription.js new file mode 100644 index 00000000..9f100730 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testdata/subscription.js @@ -0,0 +1,12 @@ +// This test checks basic subscription support. + +--> {"jsonrpc":"2.0","id":1,"method":"nftest_subscribe","params":["someSubscription",5,1]} +<-- {"jsonrpc":"2.0","id":1,"result":"0x1"} +<-- {"jsonrpc":"2.0","method":"nftest_subscription","params":{"subscription":"0x1","result":1}} +<-- {"jsonrpc":"2.0","method":"nftest_subscription","params":{"subscription":"0x1","result":2}} +<-- {"jsonrpc":"2.0","method":"nftest_subscription","params":{"subscription":"0x1","result":3}} +<-- {"jsonrpc":"2.0","method":"nftest_subscription","params":{"subscription":"0x1","result":4}} +<-- {"jsonrpc":"2.0","method":"nftest_subscription","params":{"subscription":"0x1","result":5}} + +--> {"jsonrpc":"2.0","id":2,"method":"nftest_echo","params":[11]} +<-- {"jsonrpc":"2.0","id":2,"result":11} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/testservice_test.go b/vendor/github.com/ethereum/go-ethereum/rpc/testservice_test.go new file mode 100644 index 00000000..470870ba --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/rpc/testservice_test.go @@ -0,0 +1,180 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rpc + +import ( + "context" + "encoding/binary" + "errors" + "sync" + "time" +) + +func newTestServer() *Server { + server := NewServer() + server.idgen = sequentialIDGenerator() + if err := server.RegisterName("test", new(testService)); err != nil { + panic(err) + } + if err := server.RegisterName("nftest", new(notificationTestService)); err != nil { + panic(err) + } + return server +} + +func sequentialIDGenerator() func() ID { + var ( + mu sync.Mutex + counter uint64 + ) + return func() ID { + mu.Lock() + defer mu.Unlock() + counter++ + id := make([]byte, 8) + binary.BigEndian.PutUint64(id, counter) + return encodeID(id) + } +} + +type testService struct{} + +type Args struct { + S string +} + +type Result struct { + String string + Int int + Args *Args +} + +func (s *testService) NoArgsRets() {} + +func (s *testService) Echo(str string, i int, args *Args) Result { + return Result{str, i, args} +} + +func (s *testService) EchoWithCtx(ctx context.Context, str string, i int, args *Args) Result { + return Result{str, i, args} +} + +func (s *testService) Sleep(ctx context.Context, duration time.Duration) { + time.Sleep(duration) +} + +func (s *testService) Rets() (string, error) { + return "", nil +} + +func (s *testService) InvalidRets1() (error, string) { + return nil, "" +} + +func (s *testService) InvalidRets2() (string, string) { + return "", "" +} + +func (s *testService) InvalidRets3() (string, string, error) { + return "", "", nil +} + +func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) { + c, ok := ClientFromContext(ctx) + if !ok { + return nil, errors.New("no client") + } + var result interface{} + err := c.Call(&result, method, args...) + return result, err +} + +func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error { + c, ok := ClientFromContext(ctx) + if !ok { + return errors.New("no client") + } + go func() { + <-ctx.Done() + var result interface{} + c.Call(&result, method, args...) + }() + return nil +} + +func (s *testService) Subscription(ctx context.Context) (*Subscription, error) { + return nil, nil +} + +type notificationTestService struct { + unsubscribed chan string + gotHangSubscriptionReq chan struct{} + unblockHangSubscription chan struct{} +} + +func (s *notificationTestService) Echo(i int) int { + return i +} + +func (s *notificationTestService) Unsubscribe(subid string) { + if s.unsubscribed != nil { + s.unsubscribed <- subid + } +} + +func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) { + notifier, supported := NotifierFromContext(ctx) + if !supported { + return nil, ErrNotificationsUnsupported + } + + // By explicitly creating an subscription we make sure that the subscription id is send + // back to the client before the first subscription.Notify is called. Otherwise the + // events might be send before the response for the *_subscribe method. + subscription := notifier.CreateSubscription() + go func() { + for i := 0; i < n; i++ { + if err := notifier.Notify(subscription.ID, val+i); err != nil { + return + } + } + select { + case <-notifier.Closed(): + case <-subscription.Err(): + } + if s.unsubscribed != nil { + s.unsubscribed <- string(subscription.ID) + } + }() + return subscription, nil +} + +// HangSubscription blocks on s.unblockHangSubscription before sending anything. +func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) { + notifier, supported := NotifierFromContext(ctx) + if !supported { + return nil, ErrNotificationsUnsupported + } + s.gotHangSubscriptionReq <- struct{}{} + <-s.unblockHangSubscription + subscription := notifier.CreateSubscription() + + go func() { + notifier.Notify(subscription.ID, val) + }() + return subscription, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/types.go b/vendor/github.com/ethereum/go-ethereum/rpc/types.go index 4252c360..f31f09a7 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/types.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/types.go @@ -17,13 +17,11 @@ package rpc import ( + "context" "fmt" "math" - "reflect" "strings" - "sync" - mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -35,57 +33,6 @@ type API struct { Public bool // indication if the methods must be considered safe for public use } -// callback is a method callback which was registered in the server -type callback struct { - rcvr reflect.Value // receiver of method - method reflect.Method // callback - argTypes []reflect.Type // input argument types - hasCtx bool // method's first argument is a context (not included in argTypes) - errPos int // err return idx, of -1 when method cannot return error - isSubscribe bool // indication if the callback is a subscription -} - -// service represents a registered object -type service struct { - name string // name for service - typ reflect.Type // receiver type - callbacks callbacks // registered handlers - subscriptions subscriptions // available subscriptions/notifications -} - -// serverRequest is an incoming request -type serverRequest struct { - id interface{} - svcname string - callb *callback - args []reflect.Value - isUnsubscribe bool - err Error -} - -type serviceRegistry map[string]*service // collection of services -type callbacks map[string]*callback // collection of RPC callbacks -type subscriptions map[string]*callback // collection of subscription callbacks - -// Server represents a RPC server -type Server struct { - services serviceRegistry - - run int32 - codecsMu sync.Mutex - codecs mapset.Set -} - -// rpcRequest represents a raw incoming RPC request -type rpcRequest struct { - service string - method string - id interface{} - isPubSub bool - params interface{} - err Error // invalid batch element -} - // Error wraps RPC errors, which contain an error code in addition to the message. type Error interface { Error() string // returns the message @@ -96,24 +43,19 @@ type Error interface { // a RPC session. Implementations must be go-routine safe since the codec can be called in // multiple go-routines concurrently. type ServerCodec interface { - // Read next request - ReadRequestHeaders() ([]rpcRequest, bool, Error) - // Parse request argument to the given types - ParseRequestArguments(argTypes []reflect.Type, params interface{}) ([]reflect.Value, Error) - // Assemble success response, expects response id and payload - CreateResponse(id interface{}, reply interface{}) interface{} - // Assemble error response, expects response id and error - CreateErrorResponse(id interface{}, err Error) interface{} - // Assemble error response with extra information about the error through info - CreateErrorResponseWithInfo(id interface{}, err Error, info interface{}) interface{} - // Create notification response - CreateNotification(id, namespace string, event interface{}) interface{} - // Write msg to client. - Write(msg interface{}) error - // Close underlying data stream + Read() (msgs []*jsonrpcMessage, isBatch bool, err error) Close() - // Closed when underlying connection is closed + jsonWriter +} + +// jsonWriter can write JSON messages to its underlying connection. +// Implementations must be safe for concurrent use. +type jsonWriter interface { + Write(context.Context, interface{}) error + // Closed returns a channel which is closed when the connection is closed. Closed() <-chan interface{} + // RemoteAddr returns the peer address of the connection. + RemoteAddr() string } type BlockNumber int64 diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/utils.go b/vendor/github.com/ethereum/go-ethereum/rpc/utils.go deleted file mode 100644 index 7f7ac452..00000000 --- a/vendor/github.com/ethereum/go-ethereum/rpc/utils.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "bufio" - "context" - crand "crypto/rand" - "encoding/binary" - "encoding/hex" - "math/rand" - "reflect" - "strings" - "sync" - "time" - "unicode" - "unicode/utf8" -) - -var ( - subscriptionIDGenMu sync.Mutex - subscriptionIDGen = idGenerator() -) - -// Is this an exported - upper case - name? -func isExported(name string) bool { - rune, _ := utf8.DecodeRuneInString(name) - return unicode.IsUpper(rune) -} - -// Is this type exported or a builtin? -func isExportedOrBuiltinType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - // PkgPath will be non-empty even for an exported type, - // so we need to check the type name as well. - return isExported(t.Name()) || t.PkgPath() == "" -} - -var contextType = reflect.TypeOf((*context.Context)(nil)).Elem() - -// isContextType returns an indication if the given t is of context.Context or *context.Context type -func isContextType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t == contextType -} - -var errorType = reflect.TypeOf((*error)(nil)).Elem() - -// Implements this type the error interface -func isErrorType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t.Implements(errorType) -} - -var subscriptionType = reflect.TypeOf((*Subscription)(nil)).Elem() - -// isSubscriptionType returns an indication if the given t is of Subscription or *Subscription type -func isSubscriptionType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t == subscriptionType -} - -// isPubSub tests whether the given method has as as first argument a context.Context -// and returns the pair (Subscription, error) -func isPubSub(methodType reflect.Type) bool { - // numIn(0) is the receiver type - if methodType.NumIn() < 2 || methodType.NumOut() != 2 { - return false - } - - return isContextType(methodType.In(1)) && - isSubscriptionType(methodType.Out(0)) && - isErrorType(methodType.Out(1)) -} - -// formatName will convert to first character to lower case -func formatName(name string) string { - ret := []rune(name) - if len(ret) > 0 { - ret[0] = unicode.ToLower(ret[0]) - } - return string(ret) -} - -// suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria -// for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server -// documentation for a summary of these criteria. -func suitableCallbacks(rcvr reflect.Value, typ reflect.Type) (callbacks, subscriptions) { - callbacks := make(callbacks) - subscriptions := make(subscriptions) - -METHODS: - for m := 0; m < typ.NumMethod(); m++ { - method := typ.Method(m) - mtype := method.Type - mname := formatName(method.Name) - if method.PkgPath != "" { // method must be exported - continue - } - - var h callback - h.isSubscribe = isPubSub(mtype) - h.rcvr = rcvr - h.method = method - h.errPos = -1 - - firstArg := 1 - numIn := mtype.NumIn() - if numIn >= 2 && mtype.In(1) == contextType { - h.hasCtx = true - firstArg = 2 - } - - if h.isSubscribe { - h.argTypes = make([]reflect.Type, numIn-firstArg) // skip rcvr type - for i := firstArg; i < numIn; i++ { - argType := mtype.In(i) - if isExportedOrBuiltinType(argType) { - h.argTypes[i-firstArg] = argType - } else { - continue METHODS - } - } - - subscriptions[mname] = &h - continue METHODS - } - - // determine method arguments, ignore first arg since it's the receiver type - // Arguments must be exported or builtin types - h.argTypes = make([]reflect.Type, numIn-firstArg) - for i := firstArg; i < numIn; i++ { - argType := mtype.In(i) - if !isExportedOrBuiltinType(argType) { - continue METHODS - } - h.argTypes[i-firstArg] = argType - } - - // check that all returned values are exported or builtin types - for i := 0; i < mtype.NumOut(); i++ { - if !isExportedOrBuiltinType(mtype.Out(i)) { - continue METHODS - } - } - - // when a method returns an error it must be the last returned value - h.errPos = -1 - for i := 0; i < mtype.NumOut(); i++ { - if isErrorType(mtype.Out(i)) { - h.errPos = i - break - } - } - - if h.errPos >= 0 && h.errPos != mtype.NumOut()-1 { - continue METHODS - } - - switch mtype.NumOut() { - case 0, 1, 2: - if mtype.NumOut() == 2 && h.errPos == -1 { // method must one return value and 1 error - continue METHODS - } - callbacks[mname] = &h - } - } - - return callbacks, subscriptions -} - -// idGenerator helper utility that generates a (pseudo) random sequence of -// bytes that are used to generate identifiers. -func idGenerator() *rand.Rand { - if seed, err := binary.ReadVarint(bufio.NewReader(crand.Reader)); err == nil { - return rand.New(rand.NewSource(seed)) - } - return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) -} - -// NewID generates a identifier that can be used as an identifier in the RPC interface. -// e.g. filter and subscription identifier. -func NewID() ID { - subscriptionIDGenMu.Lock() - defer subscriptionIDGenMu.Unlock() - - id := make([]byte, 16) - for i := 0; i < len(id); i += 7 { - val := subscriptionIDGen.Int63() - for j := 0; i+j < len(id) && j < 7; j++ { - id[i+j] = byte(val) - val >>= 8 - } - } - - rpcId := hex.EncodeToString(id) - // rpc ID's are RPC quantities, no leading zero's and 0 is 0x0 - rpcId = strings.TrimLeft(rpcId, "0") - if rpcId == "" { - rpcId = "0" - } - - return ID("0x" + rpcId) -} diff --git a/vendor/github.com/ethereum/go-ethereum/rpc/websocket.go b/vendor/github.com/ethereum/go-ethereum/rpc/websocket.go index eae8320e..c5383667 100644 --- a/vendor/github.com/ethereum/go-ethereum/rpc/websocket.go +++ b/vendor/github.com/ethereum/go-ethereum/rpc/websocket.go @@ -22,6 +22,7 @@ import ( "crypto/tls" "encoding/base64" "encoding/json" + "errors" "fmt" "net" "net/http" @@ -56,24 +57,39 @@ var websocketJSONCodec = websocket.Codec{ // // allowedOrigins should be a comma-separated list of allowed origin URLs. // To allow connections with any origin, pass "*". -func (srv *Server) WebsocketHandler(allowedOrigins []string) http.Handler { +func (s *Server) WebsocketHandler(allowedOrigins []string) http.Handler { return websocket.Server{ Handshake: wsHandshakeValidator(allowedOrigins), Handler: func(conn *websocket.Conn) { - // Create a custom encode/decode pair to enforce payload size and number encoding - conn.MaxPayloadBytes = maxRequestContentLength - - encoder := func(v interface{}) error { - return websocketJSONCodec.Send(conn, v) - } - decoder := func(v interface{}) error { - return websocketJSONCodec.Receive(conn, v) - } - srv.ServeCodec(NewCodec(conn, encoder, decoder), OptionMethodInvocation|OptionSubscriptions) + codec := newWebsocketCodec(conn) + s.ServeCodec(codec, OptionMethodInvocation|OptionSubscriptions) }, } } +func newWebsocketCodec(conn *websocket.Conn) ServerCodec { + // Create a custom encode/decode pair to enforce payload size and number encoding + conn.MaxPayloadBytes = maxRequestContentLength + encoder := func(v interface{}) error { + return websocketJSONCodec.Send(conn, v) + } + decoder := func(v interface{}) error { + return websocketJSONCodec.Receive(conn, v) + } + rpcconn := Conn(conn) + if conn.IsServerConn() { + // Override remote address with the actual socket address because + // package websocket crashes if there is no request origin. + addr := conn.Request().RemoteAddr + if wsaddr := conn.RemoteAddr().(*websocket.Addr); wsaddr.URL != nil { + // Add origin if present. + addr += "(" + wsaddr.URL.String() + ")" + } + rpcconn = connWithRemoteAddr{conn, addr} + } + return NewCodec(rpcconn, encoder, decoder) +} + // NewWSServer creates a new websocket RPC server around an API provider. // // Deprecated: use Server.WebsocketHandler @@ -105,15 +121,23 @@ func wsHandshakeValidator(allowedOrigins []string) func(*websocket.Config, *http } } - log.Debug(fmt.Sprintf("Allowed origin(s) for WS RPC interface %v\n", origins.ToSlice())) + log.Debug(fmt.Sprintf("Allowed origin(s) for WS RPC interface %v", origins.ToSlice())) f := func(cfg *websocket.Config, req *http.Request) error { + // Skip origin verification if no Origin header is present. The origin check + // is supposed to protect against browser based attacks. Browsers always set + // Origin. Non-browser software can put anything in origin and checking it doesn't + // provide additional security. + if _, ok := req.Header["Origin"]; !ok { + return nil + } + // Verify origin against whitelist. origin := strings.ToLower(req.Header.Get("Origin")) if allowAllOrigins || origins.Contains(origin) { return nil } - log.Warn(fmt.Sprintf("origin '%s' not allowed on WS-RPC interface\n", origin)) - return fmt.Errorf("origin %s not allowed", origin) + log.Warn("Rejected WebSocket connection", "origin", origin) + return errors.New("origin not allowed") } return f @@ -155,8 +179,12 @@ func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error return nil, err } - return newClient(ctx, func(ctx context.Context) (net.Conn, error) { - return wsDialContext(ctx, config) + return newClient(ctx, func(ctx context.Context) (ServerCodec, error) { + conn, err := wsDialContext(ctx, config) + if err != nil { + return nil, err + } + return newWebsocketCodec(conn), nil }) } diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper.go b/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper.go index 0fef2493..88c1da03 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper.go @@ -17,17 +17,16 @@ package core import ( + "bytes" "encoding/json" "fmt" "io/ioutil" + "os" + "regexp" "strings" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - - "bytes" - "os" - "regexp" ) type decodedArgument struct { @@ -178,7 +177,9 @@ func NewAbiDBFromFile(path string) (*AbiDb, error) { if err != nil { return nil, err } - json.Unmarshal(raw, &db.db) + if err := json.Unmarshal(raw, &db.db); err != nil { + return nil, err + } return db, nil } @@ -193,14 +194,18 @@ func NewAbiDBFromFiles(standard, custom string) (*AbiDb, error) { if err != nil { return nil, err } - json.Unmarshal(raw, &db.db) + if err := json.Unmarshal(raw, &db.db); err != nil { + return nil, err + } // Custom file may not exist. Will be created during save, if needed if _, err := os.Stat(custom); err == nil { raw, err = ioutil.ReadFile(custom) if err != nil { return nil, err } - json.Unmarshal(raw, &db.customdb) + if err := json.Unmarshal(raw, &db.customdb); err != nil { + return nil, err + } } return db, nil diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper_test.go b/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper_test.go index 878210be..4a3a2f06 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper_test.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/abihelper_test.go @@ -18,12 +18,11 @@ package core import ( "fmt" - "strings" - "testing" - "io/ioutil" "math/big" "reflect" + "strings" + "testing" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/api.go b/vendor/github.com/ethereum/go-ethereum/signer/core/api.go index 2b96cdb5..184b9031 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/api.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/api.go @@ -21,52 +21,55 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "math/big" "reflect" + "strings" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/signer/storage" ) -// numberOfAccountsToDerive For hardware wallets, the number of accounts to derive -const numberOfAccountsToDerive = 10 +const ( + // numberOfAccountsToDerive For hardware wallets, the number of accounts to derive + numberOfAccountsToDerive = 10 + // ExternalAPIVersion -- see extapi_changelog.md + ExternalAPIVersion = "6.0.0" + // InternalAPIVersion -- see intapi_changelog.md + InternalAPIVersion = "6.0.0" +) // ExternalAPI defines the external API through which signing requests are made. type ExternalAPI interface { // List available accounts List(ctx context.Context) ([]common.Address, error) // New request to create a new account - New(ctx context.Context) (accounts.Account, error) + New(ctx context.Context) (common.Address, error) // SignTransaction request to sign the specified transaction SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) - // Sign - request to sign the given data (plus prefix) - Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) - // Export - request to export an account - Export(ctx context.Context, addr common.Address) (json.RawMessage, error) - // Import - request to import an account - // Should be moved to Internal API, in next phase when we have - // bi-directional communication - //Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) + // SignData - request to sign the given data (plus prefix) + SignData(ctx context.Context, contentType string, addr common.MixedcaseAddress, data interface{}) (hexutil.Bytes, error) + // SignTypedData - request to sign the given structured data (plus prefix) + SignTypedData(ctx context.Context, addr common.MixedcaseAddress, data TypedData) (hexutil.Bytes, error) + // EcRecover - recover public key from given message and signature + EcRecover(ctx context.Context, data hexutil.Bytes, sig hexutil.Bytes) (common.Address, error) + // Version info about the APIs + Version(ctx context.Context) (string, error) } -// SignerUI specifies what method a UI needs to implement to be able to be used as a UI for the signer -type SignerUI interface { +// UIClientAPI specifies what method a UI needs to implement to be able to be used as a +// UI for the signer +type UIClientAPI interface { // ApproveTx prompt the user for confirmation to request to sign Transaction ApproveTx(request *SignTxRequest) (SignTxResponse, error) // ApproveSignData prompt the user for confirmation to request to sign data ApproveSignData(request *SignDataRequest) (SignDataResponse, error) - // ApproveExport prompt the user for confirmation to export encrypted Account json - ApproveExport(request *ExportRequest) (ExportResponse, error) - // ApproveImport prompt the user for confirmation to import Account json - ApproveImport(request *ImportRequest) (ImportResponse, error) // ApproveListing prompt the user for confirmation to list accounts // the list of accounts to list can be modified by the UI ApproveListing(request *ListRequest) (ListResponse, error) @@ -82,18 +85,21 @@ type SignerUI interface { // OnSignerStartup is invoked when the signer boots, and tells the UI info about external API location and version // information OnSignerStartup(info StartupInfo) - // OnInputRequried is invoked when clef requires user input, for example master password or + // OnInputRequired is invoked when clef requires user input, for example master password or // pin-code for unlocking hardware wallets OnInputRequired(info UserInputRequest) (UserInputResponse, error) + // RegisterUIServer tells the UI to use the given UIServerAPI for ui->clef communication + RegisterUIServer(api *UIServerAPI) } // SignerAPI defines the actual implementation of ExternalAPI type SignerAPI struct { - chainID *big.Int - am *accounts.Manager - UI SignerUI - validator *Validator - rejectMode bool + chainID *big.Int + am *accounts.Manager + UI UIClientAPI + validator *Validator + rejectMode bool + credentials storage.Storage } // Metadata about a request @@ -105,6 +111,37 @@ type Metadata struct { Origin string `json:"Origin"` } +func StartClefAccountManager(ksLocation string, nousb, lightKDF bool) *accounts.Manager { + var ( + backends []accounts.Backend + n, p = keystore.StandardScryptN, keystore.StandardScryptP + ) + if lightKDF { + n, p = keystore.LightScryptN, keystore.LightScryptP + } + // support password based accounts + if len(ksLocation) > 0 { + backends = append(backends, keystore.NewKeyStore(ksLocation, n, p)) + } + if !nousb { + // Start a USB hub for Ledger hardware wallets + if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) + } else { + backends = append(backends, ledgerhub) + log.Debug("Ledger support enabled") + } + // Start a USB hub for Trezor hardware wallets + if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + } else { + backends = append(backends, trezorhub) + log.Debug("Trezor support enabled") + } + } + return accounts.NewManager(backends...) +} + // MetadataFromContext extracts Metadata from a given context.Context func MetadataFromContext(ctx context.Context) Metadata { m := Metadata{"NA", "NA", "NA", "", ""} // batman @@ -149,66 +186,40 @@ type ( //The UI may make changes to the TX Transaction SendTxArgs `json:"transaction"` Approved bool `json:"approved"` - Password string `json:"password"` - } - // ExportRequest info about query to export accounts - ExportRequest struct { - Address common.Address `json:"address"` - Meta Metadata `json:"meta"` - } - // ExportResponse response to export-request - ExportResponse struct { - Approved bool `json:"approved"` - } - // ImportRequest info about request to import an Account - ImportRequest struct { - Meta Metadata `json:"meta"` - } - ImportResponse struct { - Approved bool `json:"approved"` - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` } SignDataRequest struct { - Address common.MixedcaseAddress `json:"address"` - Rawdata hexutil.Bytes `json:"raw_data"` - Message string `json:"message"` - Hash hexutil.Bytes `json:"hash"` - Meta Metadata `json:"meta"` + ContentType string `json:"content_type"` + Address common.MixedcaseAddress `json:"address"` + Rawdata []byte `json:"raw_data"` + Message []*NameValueType `json:"message"` + Hash hexutil.Bytes `json:"hash"` + Meta Metadata `json:"meta"` } SignDataResponse struct { Approved bool `json:"approved"` - Password string } NewAccountRequest struct { Meta Metadata `json:"meta"` } NewAccountResponse struct { - Approved bool `json:"approved"` - Password string `json:"password"` + Approved bool `json:"approved"` } ListRequest struct { - Accounts []Account `json:"accounts"` - Meta Metadata `json:"meta"` + Accounts []accounts.Account `json:"accounts"` + Meta Metadata `json:"meta"` } ListResponse struct { - Accounts []Account `json:"accounts"` + Accounts []accounts.Account `json:"accounts"` } Message struct { Text string `json:"text"` } - PasswordRequest struct { - Prompt string `json:"prompt"` - } - PasswordResponse struct { - Password string `json:"password"` - } StartupInfo struct { Info map[string]interface{} `json:"info"` } UserInputRequest struct { - Prompt string `json:"prompt"` Title string `json:"title"` + Prompt string `json:"prompt"` IsPassword bool `json:"isPassword"` } UserInputResponse struct { @@ -223,38 +234,11 @@ var ErrRequestDenied = errors.New("Request denied") // key that is generated when a new Account is created. // noUSB disables USB support that is required to support hardware devices such as // ledger and trezor. -func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *AbiDb, lightKDF bool, advancedMode bool) *SignerAPI { - var ( - backends []accounts.Backend - n, p = keystore.StandardScryptN, keystore.StandardScryptP - ) - if lightKDF { - n, p = keystore.LightScryptN, keystore.LightScryptP - } - // support password based accounts - if len(ksLocation) > 0 { - backends = append(backends, keystore.NewKeyStore(ksLocation, n, p)) - } +func NewSignerAPI(am *accounts.Manager, chainID int64, noUSB bool, ui UIClientAPI, abidb *AbiDb, advancedMode bool, credentials storage.Storage) *SignerAPI { if advancedMode { log.Info("Clef is in advanced mode: will warn instead of reject") } - if !noUSB { - // Start a USB hub for Ledger hardware wallets - if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) - } else { - backends = append(backends, ledgerhub) - log.Debug("Ledger support enabled") - } - // Start a USB hub for Trezor hardware wallets - if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) - } else { - backends = append(backends, trezorhub) - log.Debug("Trezor support enabled") - } - } - signer := &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, NewValidator(abidb), !advancedMode} + signer := &SignerAPI{big.NewInt(chainID), am, ui, NewValidator(abidb), !advancedMode, credentials} if !noUSB { signer.startUSBListener() } @@ -347,12 +331,9 @@ func (api *SignerAPI) startUSBListener() { // List returns the set of wallet this signer manages. Each wallet can contain // multiple accounts. func (api *SignerAPI) List(ctx context.Context) ([]common.Address, error) { - var accs []Account + var accs []accounts.Account for _, wallet := range api.am.Wallets() { - for _, acc := range wallet.Accounts() { - acc := Account{Typ: "Account", URL: wallet.URL(), Address: acc.Address} - accs = append(accs, acc) - } + accs = append(accs, wallet.Accounts()...) } result, err := api.UI.ApproveListing(&ListRequest{Accounts: accs, Meta: MetadataFromContext(ctx)}) if err != nil { @@ -362,7 +343,6 @@ func (api *SignerAPI) List(ctx context.Context) ([]common.Address, error) { return nil, ErrRequestDenied } - addresses := make([]common.Address, 0) for _, acc := range result.Accounts { addresses = append(addresses, acc.Address) @@ -374,33 +354,37 @@ func (api *SignerAPI) List(ctx context.Context) ([]common.Address, error) { // New creates a new password protected Account. The private key is protected with // the given password. Users are responsible to backup the private key that is stored // in the keystore location thas was specified when this API was created. -func (api *SignerAPI) New(ctx context.Context) (accounts.Account, error) { +func (api *SignerAPI) New(ctx context.Context) (common.Address, error) { be := api.am.Backends(keystore.KeyStoreType) if len(be) == 0 { - return accounts.Account{}, errors.New("password based accounts not supported") + return common.Address{}, errors.New("password based accounts not supported") } - var ( - resp NewAccountResponse - err error - ) + if resp, err := api.UI.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)}); err != nil { + return common.Address{}, err + } else if !resp.Approved { + return common.Address{}, ErrRequestDenied + } + // Three retries to get a valid password for i := 0; i < 3; i++ { - resp, err = api.UI.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)}) + resp, err := api.UI.OnInputRequired(UserInputRequest{ + "New account password", + fmt.Sprintf("Please enter a password for the new account to be created (attempt %d of 3)", i), + true}) if err != nil { - return accounts.Account{}, err + log.Warn("error obtaining password", "attempt", i, "error", err) + continue } - if !resp.Approved { - return accounts.Account{}, ErrRequestDenied - } - if pwErr := ValidatePasswordFormat(resp.Password); pwErr != nil { + if pwErr := ValidatePasswordFormat(resp.Text); pwErr != nil { api.UI.ShowError(fmt.Sprintf("Account creation attempt #%d failed due to password requirements: %v", (i + 1), pwErr)) } else { // No error - return be[0].(*keystore.KeyStore).NewAccount(resp.Password) + acc, err := be[0].(*keystore.KeyStore).NewAccount(resp.Text) + return acc.Address, err } } // Otherwise fail, with generic error message - return accounts.Account{}, errors.New("account creation failed") + return common.Address{}, errors.New("account creation failed") } // logDiff logs the difference between the incoming (original) transaction and the one returned from the signer. @@ -449,6 +433,24 @@ func logDiff(original *SignTxRequest, new *SignTxResponse) bool { return modified } +func (api *SignerAPI) lookupPassword(address common.Address) string { + return api.credentials.Get(strings.ToLower(address.String())) +} +func (api *SignerAPI) lookupOrQueryPassword(address common.Address, title, prompt string) (string, error) { + if pw := api.lookupPassword(address); pw != "" { + return pw, nil + } else { + pwResp, err := api.UI.OnInputRequired(UserInputRequest{title, prompt, true}) + if err != nil { + log.Warn("error obtaining password", "error", err) + // We'll not forward the error here, in case the error contains info about the response from the UI, + // which could leak the password if it was malformed json or something + return "", errors.New("internal error") + } + return pwResp.Text, nil + } +} + // SignTransaction signs the given Transaction and returns it both as json and rlp-encoded form func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) { var ( @@ -492,9 +494,14 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth } // Convert fields into a real transaction var unsignedTx = result.Transaction.toTransaction() - + // Get the password for the transaction + pw, err := api.lookupOrQueryPassword(acc.Address, "Account password", + fmt.Sprintf("Please enter the password for account %s", acc.Address.String())) + if err != nil { + return nil, err + } // The one to sign is the one that was returned from the UI - signedTx, err := wallet.SignTxWithPassphrase(acc, result.Password, unsignedTx, api.chainID) + signedTx, err := wallet.SignTxWithPassphrase(acc, pw, unsignedTx, api.chainID) if err != nil { api.UI.ShowError(err.Error()) return nil, err @@ -510,103 +517,8 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth } -// Sign calculates an Ethereum ECDSA signature for: -// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message)) -// -// Note, the produced signature conforms to the secp256k1 curve R, S and V values, -// where the V value will be 27 or 28 for legacy reasons. -// -// The key used to calculate the signature is decrypted with the given password. -// -// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign -func (api *SignerAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) { - sighash, msg := SignHash(data) - // We make the request prior to looking up if we actually have the account, to prevent - // account-enumeration via the API - req := &SignDataRequest{Address: addr, Rawdata: data, Message: msg, Hash: sighash, Meta: MetadataFromContext(ctx)} - res, err := api.UI.ApproveSignData(req) - - if err != nil { - return nil, err - } - if !res.Approved { - return nil, ErrRequestDenied - } - // Look up the wallet containing the requested signer - account := accounts.Account{Address: addr.Address()} - wallet, err := api.am.Find(account) - if err != nil { - return nil, err - } - // Assemble sign the data with the wallet - signature, err := wallet.SignHashWithPassphrase(account, res.Password, sighash) - if err != nil { - api.UI.ShowError(err.Error()) - return nil, err - } - signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper - return signature, nil -} - -// SignHash is a helper function that calculates a hash for the given message that can be -// safely used to calculate a signature from. -// -// The hash is calculated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). -// -// This gives context to the signed message and prevents signing of transactions. -func SignHash(data []byte) ([]byte, string) { - msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) - return crypto.Keccak256([]byte(msg)), msg -} - -// Export returns encrypted private key associated with the given address in web3 keystore format. -func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { - res, err := api.UI.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)}) - - if err != nil { - return nil, err - } - if !res.Approved { - return nil, ErrRequestDenied - } - // Look up the wallet containing the requested signer - wallet, err := api.am.Find(accounts.Account{Address: addr}) - if err != nil { - return nil, err - } - if wallet.URL().Scheme != keystore.KeyStoreScheme { - return nil, fmt.Errorf("Account is not a keystore-account") - } - return ioutil.ReadFile(wallet.URL().Path) -} - -// Import tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be -// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful -// decryption it will encrypt the key with the given newPassphrase and store it in the keystore. -// OBS! This method is removed from the public API. It should not be exposed on the external API -// for a couple of reasons: -// 1. Even though it is encrypted, it should still be seen as sensitive data -// 2. It can be used to DoS clef, by using malicious data with e.g. extreme large -// values for the kdfparams. -func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) { - be := api.am.Backends(keystore.KeyStoreType) - - if len(be) == 0 { - return Account{}, errors.New("password based accounts not supported") - } - res, err := api.UI.ApproveImport(&ImportRequest{Meta: MetadataFromContext(ctx)}) - - if err != nil { - return Account{}, err - } - if !res.Approved { - return Account{}, ErrRequestDenied - } - acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, res.OldPassword, res.NewPassword) - if err != nil { - api.UI.ShowError(err.Error()) - return Account{}, err - } - return Account{Typ: "Account", URL: acc.URL, Address: acc.Address}, nil +// Returns the external api version. This method does not require user acceptance. Available methods are +// available via enumeration anyway, and this info does not contain user-specific data +func (api *SignerAPI) Version(ctx context.Context) (string, error) { + return ExternalAPIVersion, nil } diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/api_test.go b/vendor/github.com/ethereum/go-ethereum/signer/core/api_test.go index a8aa2389..3225c10e 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/api_test.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/api_test.go @@ -19,7 +19,6 @@ package core import ( "bytes" "context" - "errors" "fmt" "io/ioutil" "math/big" @@ -28,71 +27,60 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/signer/storage" ) //Used for testing -type HeadlessUI struct { - controller chan string +type headlessUi struct { + approveCh chan string // to send approve/deny + inputCh chan string // to send password } -func (ui *HeadlessUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { - return UserInputResponse{}, errors.New("not implemented") +func (ui *headlessUi) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { + input := <-ui.inputCh + return UserInputResponse{Text: input}, nil } -func (ui *HeadlessUI) OnSignerStartup(info StartupInfo) { -} +func (ui *headlessUi) OnSignerStartup(info StartupInfo) {} +func (ui *headlessUi) RegisterUIServer(api *UIServerAPI) {} +func (ui *headlessUi) OnApprovedTx(tx ethapi.SignTransactionResult) {} -func (ui *HeadlessUI) OnApprovedTx(tx ethapi.SignTransactionResult) { - fmt.Printf("OnApproved()\n") -} +func (ui *headlessUi) ApproveTx(request *SignTxRequest) (SignTxResponse, error) { -func (ui *HeadlessUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error) { - - switch <-ui.controller { + switch <-ui.approveCh { case "Y": - return SignTxResponse{request.Transaction, true, <-ui.controller}, nil - case "M": //Modify + return SignTxResponse{request.Transaction, true}, nil + case "M": // modify + // The headless UI always modifies the transaction old := big.Int(request.Transaction.Value) newVal := big.NewInt(0).Add(&old, big.NewInt(1)) request.Transaction.Value = hexutil.Big(*newVal) - return SignTxResponse{request.Transaction, true, <-ui.controller}, nil + return SignTxResponse{request.Transaction, true}, nil default: - return SignTxResponse{request.Transaction, false, ""}, nil + return SignTxResponse{request.Transaction, false}, nil } } -func (ui *HeadlessUI) ApproveSignData(request *SignDataRequest) (SignDataResponse, error) { - if "Y" == <-ui.controller { - return SignDataResponse{true, <-ui.controller}, nil - } - return SignDataResponse{false, ""}, nil +func (ui *headlessUi) ApproveSignData(request *SignDataRequest) (SignDataResponse, error) { + approved := "Y" == <-ui.approveCh + return SignDataResponse{approved}, nil } -func (ui *HeadlessUI) ApproveExport(request *ExportRequest) (ExportResponse, error) { - return ExportResponse{<-ui.controller == "Y"}, nil - -} - -func (ui *HeadlessUI) ApproveImport(request *ImportRequest) (ImportResponse, error) { - if "Y" == <-ui.controller { - return ImportResponse{true, <-ui.controller, <-ui.controller}, nil - } - return ImportResponse{false, "", ""}, nil -} - -func (ui *HeadlessUI) ApproveListing(request *ListRequest) (ListResponse, error) { - switch <-ui.controller { +func (ui *headlessUi) ApproveListing(request *ListRequest) (ListResponse, error) { + approval := <-ui.approveCh + //fmt.Printf("approval %s\n", approval) + switch approval { case "A": return ListResponse{request.Accounts}, nil case "1": - l := make([]Account, 1) + l := make([]accounts.Account, 1) l[0] = request.Accounts[1] return ListResponse{l}, nil default: @@ -100,19 +88,19 @@ func (ui *HeadlessUI) ApproveListing(request *ListRequest) (ListResponse, error) } } -func (ui *HeadlessUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { - if "Y" == <-ui.controller { - return NewAccountResponse{true, <-ui.controller}, nil +func (ui *headlessUi) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { + if "Y" == <-ui.approveCh { + return NewAccountResponse{true}, nil } - return NewAccountResponse{false, ""}, nil + return NewAccountResponse{false}, nil } -func (ui *HeadlessUI) ShowError(message string) { +func (ui *headlessUi) ShowError(message string) { //stdout is used by communication fmt.Fprintln(os.Stderr, message) } -func (ui *HeadlessUI) ShowInfo(message string) { +func (ui *headlessUi) ShowInfo(message string) { //stdout is used by communication fmt.Fprintln(os.Stderr, message) } @@ -129,30 +117,20 @@ func tmpDirName(t *testing.T) string { return d } -func setup(t *testing.T) (*SignerAPI, chan string) { - - controller := make(chan string, 20) - +func setup(t *testing.T) (*SignerAPI, *headlessUi) { db, err := NewAbiDBFromFile("../../cmd/clef/4byte.json") if err != nil { - utils.Fatalf(err.Error()) + t.Fatal(err.Error()) } - var ( - ui = &HeadlessUI{controller} - api = NewSignerAPI( - 1, - tmpDirName(t), - true, - ui, - db, - true, true) - ) - return api, controller -} -func createAccount(control chan string, api *SignerAPI, t *testing.T) { + ui := &headlessUi{make(chan string, 20), make(chan string, 20)} + am := StartClefAccountManager(tmpDirName(t), true, true) + api := NewSignerAPI(am, 1337, true, ui, db, true, &storage.NoStorage{}) + return api, ui - control <- "Y" - control <- "a_long_password" +} +func createAccount(ui *headlessUi, api *SignerAPI, t *testing.T) { + ui.approveCh <- "Y" + ui.inputCh <- "a_long_password" _, err := api.New(context.Background()) if err != nil { t.Fatal(err) @@ -161,48 +139,48 @@ func createAccount(control chan string, api *SignerAPI, t *testing.T) { time.Sleep(250 * time.Millisecond) } -func failCreateAccountWithPassword(control chan string, api *SignerAPI, password string, t *testing.T) { +func failCreateAccountWithPassword(ui *headlessUi, api *SignerAPI, password string, t *testing.T) { - control <- "Y" - control <- password - control <- "Y" - control <- password - control <- "Y" - control <- password + ui.approveCh <- "Y" + // We will be asked three times to provide a suitable password + ui.inputCh <- password + ui.inputCh <- password + ui.inputCh <- password - acc, err := api.New(context.Background()) + addr, err := api.New(context.Background()) if err == nil { t.Fatal("Should have returned an error") } - if acc.Address != (common.Address{}) { + if addr != (common.Address{}) { t.Fatal("Empty address should be returned") } } -func failCreateAccount(control chan string, api *SignerAPI, t *testing.T) { - control <- "N" - acc, err := api.New(context.Background()) +func failCreateAccount(ui *headlessUi, api *SignerAPI, t *testing.T) { + ui.approveCh <- "N" + addr, err := api.New(context.Background()) if err != ErrRequestDenied { t.Fatal(err) } - if acc.Address != (common.Address{}) { + if addr != (common.Address{}) { t.Fatal("Empty address should be returned") } } -func list(control chan string, api *SignerAPI, t *testing.T) []common.Address { - control <- "A" - list, err := api.List(context.Background()) - if err != nil { - t.Fatal(err) - } - return list +func list(ui *headlessUi, api *SignerAPI, t *testing.T) ([]common.Address, error) { + ui.approveCh <- "A" + return api.List(context.Background()) + } func TestNewAcc(t *testing.T) { api, control := setup(t) verifyNum := func(num int) { - if list := list(control, api, t); len(list) != num { + list, err := list(control, api, t) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + if len(list) != num { t.Errorf("Expected %d accounts, got %d", num, len(list)) } } @@ -215,18 +193,16 @@ func TestNewAcc(t *testing.T) { failCreateAccount(control, api, t) createAccount(control, api, t) failCreateAccount(control, api, t) - verifyNum(4) // Fail to create this, due to bad password failCreateAccountWithPassword(control, api, "short", t) failCreateAccountWithPassword(control, api, "longerbutbad\rfoo", t) - verifyNum(4) // Testing listing: // Listing one Account - control <- "1" + control.approveCh <- "1" list, err := api.List(context.Background()) if err != nil { t.Fatal(err) @@ -235,7 +211,7 @@ func TestNewAcc(t *testing.T) { t.Fatalf("List should only show one Account") } // Listing denied - control <- "Nope" + control.approveCh <- "Nope" list, err = api.List(context.Background()) if len(list) != 0 { t.Fatalf("List should be empty") @@ -245,45 +221,6 @@ func TestNewAcc(t *testing.T) { } } -func TestSignData(t *testing.T) { - api, control := setup(t) - //Create two accounts - createAccount(control, api, t) - createAccount(control, api, t) - control <- "1" - list, err := api.List(context.Background()) - if err != nil { - t.Fatal(err) - } - a := common.NewMixedcaseAddress(list[0]) - - control <- "Y" - control <- "wrongpassword" - h, err := api.Sign(context.Background(), a, []byte("EHLO world")) - if h != nil { - t.Errorf("Expected nil-data, got %x", h) - } - if err != keystore.ErrDecrypt { - t.Errorf("Expected ErrLocked! %v", err) - } - control <- "No way" - h, err = api.Sign(context.Background(), a, []byte("EHLO world")) - if h != nil { - t.Errorf("Expected nil-data, got %x", h) - } - if err != ErrRequestDenied { - t.Errorf("Expected ErrRequestDenied! %v", err) - } - control <- "Y" - control <- "a_long_password" - h, err = api.Sign(context.Background(), a, []byte("EHLO world")) - if err != nil { - t.Fatal(err) - } - if h == nil || len(h) != 65 { - t.Errorf("Expected 65 byte signature (got %d bytes)", len(h)) - } -} func mkTestTx(from common.MixedcaseAddress) SendTxArgs { to := common.NewMixedcaseAddress(common.HexToAddress("0x1337")) gas := hexutil.Uint64(21000) @@ -311,7 +248,7 @@ func TestSignTx(t *testing.T) { api, control := setup(t) createAccount(control, api, t) - control <- "A" + control.approveCh <- "A" list, err = api.List(context.Background()) if err != nil { t.Fatal(err) @@ -321,8 +258,8 @@ func TestSignTx(t *testing.T) { methodSig := "test(uint)" tx := mkTestTx(a) - control <- "Y" - control <- "wrongpassword" + control.approveCh <- "Y" + control.inputCh <- "wrongpassword" res, err = api.SignTransaction(context.Background(), tx, &methodSig) if res != nil { t.Errorf("Expected nil-response, got %v", res) @@ -330,7 +267,7 @@ func TestSignTx(t *testing.T) { if err != keystore.ErrDecrypt { t.Errorf("Expected ErrLocked! %v", err) } - control <- "No way" + control.approveCh <- "No way" res, err = api.SignTransaction(context.Background(), tx, &methodSig) if res != nil { t.Errorf("Expected nil-response, got %v", res) @@ -338,8 +275,9 @@ func TestSignTx(t *testing.T) { if err != ErrRequestDenied { t.Errorf("Expected ErrRequestDenied! %v", err) } - control <- "Y" - control <- "a_long_password" + // Sign with correct password + control.approveCh <- "Y" + control.inputCh <- "a_long_password" res, err = api.SignTransaction(context.Background(), tx, &methodSig) if err != nil { @@ -352,8 +290,8 @@ func TestSignTx(t *testing.T) { if parsedTx.Value().Cmp(tx.Value.ToInt()) != 0 { t.Errorf("Expected value to be unchanged, expected %v got %v", tx.Value, parsedTx.Value()) } - control <- "Y" - control <- "a_long_password" + control.approveCh <- "Y" + control.inputCh <- "a_long_password" res2, err = api.SignTransaction(context.Background(), tx, &methodSig) if err != nil { @@ -364,8 +302,8 @@ func TestSignTx(t *testing.T) { } //The tx is modified by the UI - control <- "M" - control <- "a_long_password" + control.approveCh <- "M" + control.inputCh <- "a_long_password" res2, err = api.SignTransaction(context.Background(), tx, &methodSig) if err != nil { @@ -383,31 +321,3 @@ func TestSignTx(t *testing.T) { } } - -/* -func TestAsyncronousResponses(t *testing.T){ - - //Set up one account - api, control := setup(t) - createAccount(control, api, t) - - // Two transactions, the second one with larger value than the first - tx1 := mkTestTx() - newVal := big.NewInt(0).Add((*big.Int) (tx1.Value), big.NewInt(1)) - tx2 := mkTestTx() - tx2.Value = (*hexutil.Big)(newVal) - - control <- "W" //wait - control <- "Y" // - control <- "a_long_password" - control <- "Y" // - control <- "a_long_password" - - var err error - - h1, err := api.SignTransaction(context.Background(), common.HexToAddress("1111"), tx1, nil) - h2, err := api.SignTransaction(context.Background(), common.HexToAddress("2222"), tx2, nil) - - - } -*/ diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/auditlog.go b/vendor/github.com/ethereum/go-ethereum/signer/core/auditlog.go index 1f9c9091..9593ad7a 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/auditlog.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/auditlog.go @@ -19,9 +19,6 @@ package core import ( "context" - "encoding/json" - - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -41,7 +38,7 @@ func (l *AuditLogger) List(ctx context.Context) ([]common.Address, error) { return res, e } -func (l *AuditLogger) New(ctx context.Context) (accounts.Account, error) { +func (l *AuditLogger) New(ctx context.Context) (common.Address, error) { return l.api.New(ctx) } @@ -63,31 +60,37 @@ func (l *AuditLogger) SignTransaction(ctx context.Context, args SendTxArgs, meth return res, e } -func (l *AuditLogger) Sign(ctx context.Context, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) { - l.log.Info("Sign", "type", "request", "metadata", MetadataFromContext(ctx).String(), - "addr", addr.String(), "data", common.Bytes2Hex(data)) - b, e := l.api.Sign(ctx, addr, data) - l.log.Info("Sign", "type", "response", "data", common.Bytes2Hex(b), "error", e) +func (l *AuditLogger) SignData(ctx context.Context, contentType string, addr common.MixedcaseAddress, data interface{}) (hexutil.Bytes, error) { + l.log.Info("SignData", "type", "request", "metadata", MetadataFromContext(ctx).String(), + "addr", addr.String(), "data", data, "content-type", contentType) + b, e := l.api.SignData(ctx, contentType, addr, data) + l.log.Info("SignData", "type", "response", "data", common.Bytes2Hex(b), "error", e) return b, e } -func (l *AuditLogger) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { - l.log.Info("Export", "type", "request", "metadata", MetadataFromContext(ctx).String(), - "addr", addr.Hex()) - j, e := l.api.Export(ctx, addr) - // In this case, we don't actually log the json-response, which may be extra sensitive - l.log.Info("Export", "type", "response", "json response size", len(j), "error", e) - return j, e +func (l *AuditLogger) SignTypedData(ctx context.Context, addr common.MixedcaseAddress, data TypedData) (hexutil.Bytes, error) { + l.log.Info("SignTypedData", "type", "request", "metadata", MetadataFromContext(ctx).String(), + "addr", addr.String(), "data", data) + b, e := l.api.SignTypedData(ctx, addr, data) + l.log.Info("SignTypedData", "type", "response", "data", common.Bytes2Hex(b), "error", e) + return b, e } -//func (l *AuditLogger) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) { -// // Don't actually log the json contents -// l.log.Info("Import", "type", "request", "metadata", MetadataFromContext(ctx).String(), -// "keyJSON size", len(keyJSON)) -// a, e := l.api.Import(ctx, keyJSON) -// l.log.Info("Import", "type", "response", "addr", a.String(), "error", e) -// return a, e -//} +func (l *AuditLogger) EcRecover(ctx context.Context, data hexutil.Bytes, sig hexutil.Bytes) (common.Address, error) { + l.log.Info("EcRecover", "type", "request", "metadata", MetadataFromContext(ctx).String(), + "data", common.Bytes2Hex(data), "sig", common.Bytes2Hex(sig)) + b, e := l.api.EcRecover(ctx, data, sig) + l.log.Info("EcRecover", "type", "response", "address", b.String(), "error", e) + return b, e +} + +func (l *AuditLogger) Version(ctx context.Context) (string, error) { + l.log.Info("Version", "type", "request", "metadata", MetadataFromContext(ctx).String()) + data, err := l.api.Version(ctx) + l.log.Info("Version", "type", "response", "data", data, "error", err) + return data, err + +} func NewAuditLogger(path string, api ExternalAPI) (*AuditLogger, error) { l := log.New("api", "signer") diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/cliui.go b/vendor/github.com/ethereum/go-ethereum/signer/core/cliui.go index 940f1f43..cf710144 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/cliui.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/cliui.go @@ -18,13 +18,12 @@ package core import ( "bufio" + "encoding/json" "fmt" "os" "strings" - "sync" - "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" @@ -40,6 +39,10 @@ func NewCommandlineUI() *CommandlineUI { return &CommandlineUI{in: bufio.NewReader(os.Stdin)} } +func (ui *CommandlineUI) RegisterUIServer(api *UIServerAPI) { + // noop +} + // readString reads a single line from stdin, trimming if from spaces, enforcing // non-emptyness. func (ui *CommandlineUI) readString() string { @@ -84,9 +87,10 @@ func (ui *CommandlineUI) readPasswordText(inputstring string) string { } func (ui *CommandlineUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { - fmt.Println(info.Title) - fmt.Println(info.Prompt) + + fmt.Printf("## %s\n\n%s\n", info.Title, info.Prompt) if info.IsPassword { + fmt.Printf("> ") text, err := terminal.ReadPassword(int(os.Stdin.Fd())) if err != nil { log.Error("Failed to read password", "err", err) @@ -153,9 +157,9 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest) (SignTxResponse, erro showMetadata(request.Meta) fmt.Printf("-------------------------------------------\n") if !ui.confirm() { - return SignTxResponse{request.Transaction, false, ""}, nil + return SignTxResponse{request.Transaction, false}, nil } - return SignTxResponse{request.Transaction, true, ui.readPassword()}, nil + return SignTxResponse{request.Transaction, true}, nil } // ApproveSignData prompt the user for confirmation to request to sign data @@ -165,46 +169,19 @@ func (ui *CommandlineUI) ApproveSignData(request *SignDataRequest) (SignDataResp fmt.Printf("-------- Sign data request--------------\n") fmt.Printf("Account: %s\n", request.Address.String()) - fmt.Printf("message: \n%q\n", request.Message) - fmt.Printf("raw data: \n%v\n", request.Rawdata) + fmt.Printf("message:\n") + for _, nvt := range request.Message { + fmt.Printf("%v\n", nvt.Pprint(1)) + } + //fmt.Printf("message: \n%v\n", request.Message) + fmt.Printf("raw data: \n%q\n", request.Rawdata) fmt.Printf("message hash: %v\n", request.Hash) fmt.Printf("-------------------------------------------\n") showMetadata(request.Meta) if !ui.confirm() { - return SignDataResponse{false, ""}, nil + return SignDataResponse{false}, nil } - return SignDataResponse{true, ui.readPassword()}, nil -} - -// ApproveExport prompt the user for confirmation to export encrypted Account json -func (ui *CommandlineUI) ApproveExport(request *ExportRequest) (ExportResponse, error) { - ui.mu.Lock() - defer ui.mu.Unlock() - - fmt.Printf("-------- Export Account request--------------\n") - fmt.Printf("A request has been made to export the (encrypted) keyfile\n") - fmt.Printf("Approving this operation means that the caller obtains the (encrypted) contents\n") - fmt.Printf("\n") - fmt.Printf("Account: %x\n", request.Address) - //fmt.Printf("keyfile: \n%v\n", request.file) - fmt.Printf("-------------------------------------------\n") - showMetadata(request.Meta) - return ExportResponse{ui.confirm()}, nil -} - -// ApproveImport prompt the user for confirmation to import Account json -func (ui *CommandlineUI) ApproveImport(request *ImportRequest) (ImportResponse, error) { - ui.mu.Lock() - defer ui.mu.Unlock() - - fmt.Printf("-------- Import Account request--------------\n") - fmt.Printf("A request has been made to import an encrypted keyfile\n") - fmt.Printf("-------------------------------------------\n") - showMetadata(request.Meta) - if !ui.confirm() { - return ImportResponse{false, "", ""}, nil - } - return ImportResponse{true, ui.readPasswordText("Old password"), ui.readPasswordText("New password")}, nil + return SignDataResponse{true}, nil } // ApproveListing prompt the user for confirmation to list accounts @@ -220,7 +197,6 @@ func (ui *CommandlineUI) ApproveListing(request *ListRequest) (ListResponse, err for _, account := range request.Accounts { fmt.Printf(" [x] %v\n", account.Address.Hex()) fmt.Printf(" URL: %v\n", account.URL) - fmt.Printf(" Type: %v\n", account.Typ) } fmt.Printf("-------------------------------------------\n") showMetadata(request.Meta) @@ -242,26 +218,29 @@ func (ui *CommandlineUI) ApproveNewAccount(request *NewAccountRequest) (NewAccou fmt.Printf("and the address is returned to the external caller\n\n") showMetadata(request.Meta) if !ui.confirm() { - return NewAccountResponse{false, ""}, nil + return NewAccountResponse{false}, nil } - return NewAccountResponse{true, ui.readPassword()}, nil + return NewAccountResponse{true}, nil } // ShowError displays error message to user func (ui *CommandlineUI) ShowError(message string) { - fmt.Printf("-------- Error message from Clef-----------\n") - fmt.Println(message) + fmt.Printf("## Error \n%s\n", message) fmt.Printf("-------------------------------------------\n") } // ShowInfo displays info message to user func (ui *CommandlineUI) ShowInfo(message string) { - fmt.Printf("Info: %v\n", message) + fmt.Printf("## Info \n%s\n", message) } func (ui *CommandlineUI) OnApprovedTx(tx ethapi.SignTransactionResult) { fmt.Printf("Transaction signed:\n ") - spew.Dump(tx.Tx) + if jsn, err := json.MarshalIndent(tx.Tx, " ", " "); err != nil { + fmt.Printf("WARN: marshalling error %v\n", err) + } else { + fmt.Println(string(jsn)) + } } func (ui *CommandlineUI) OnSignerStartup(info StartupInfo) { diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/signed_data.go b/vendor/github.com/ethereum/go-ethereum/signer/core/signed_data.go new file mode 100644 index 00000000..475a8837 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/signed_data.go @@ -0,0 +1,917 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . +// +package core + +import ( + "bytes" + "context" + "errors" + "fmt" + "math/big" + "mime" + "regexp" + "sort" + "strconv" + "strings" + "unicode" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/clique" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +type SigFormat struct { + Mime string + ByteVersion byte +} + +var ( + TextValidator = SigFormat{ + accounts.MimetypeTextWithValidator, + 0x00, + } + DataTyped = SigFormat{ + accounts.MimetypeTypedData, + 0x01, + } + ApplicationClique = SigFormat{ + accounts.MimetypeClique, + 0x02, + } + TextPlain = SigFormat{ + accounts.MimetypeTextPlain, + 0x45, + } +) + +type ValidatorData struct { + Address common.Address + Message hexutil.Bytes +} + +type TypedData struct { + Types Types `json:"types"` + PrimaryType string `json:"primaryType"` + Domain TypedDataDomain `json:"domain"` + Message TypedDataMessage `json:"message"` +} + +type Type struct { + Name string `json:"name"` + Type string `json:"type"` +} + +func (t *Type) isArray() bool { + return strings.HasSuffix(t.Type, "[]") +} + +// typeName returns the canonical name of the type. If the type is 'Person[]', then +// this method returns 'Person' +func (t *Type) typeName() string { + if strings.HasSuffix(t.Type, "[]") { + return strings.TrimSuffix(t.Type, "[]") + } + return t.Type +} + +func (t *Type) isReferenceType() bool { + // Reference types must have a leading uppercase characer + return unicode.IsUpper([]rune(t.Type)[0]) +} + +type Types map[string][]Type + +type TypePriority struct { + Type string + Value uint +} + +type TypedDataMessage = map[string]interface{} + +type TypedDataDomain struct { + Name string `json:"name"` + Version string `json:"version"` + ChainId *big.Int `json:"chainId"` + VerifyingContract string `json:"verifyingContract"` + Salt string `json:"salt"` +} + +var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[\])?$`) + +// sign receives a request and produces a signature + +// Note, the produced signature conforms to the secp256k1 curve R, S and V values, +// where the V value will be 27 or 28 for legacy reasons, if legacyV==true. +func (api *SignerAPI) sign(addr common.MixedcaseAddress, req *SignDataRequest, legacyV bool) (hexutil.Bytes, error) { + + // We make the request prior to looking up if we actually have the account, to prevent + // account-enumeration via the API + res, err := api.UI.ApproveSignData(req) + if err != nil { + return nil, err + } + if !res.Approved { + return nil, ErrRequestDenied + } + // Look up the wallet containing the requested signer + account := accounts.Account{Address: addr.Address()} + wallet, err := api.am.Find(account) + if err != nil { + return nil, err + } + pw, err := api.lookupOrQueryPassword(account.Address, + "Password for signing", + fmt.Sprintf("Please enter password for signing data with account %s", account.Address.Hex())) + if err != nil { + return nil, err + } + // Sign the data with the wallet + signature, err := wallet.SignDataWithPassphrase(account, pw, req.ContentType, req.Rawdata) + if err != nil { + return nil, err + } + if legacyV { + signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper + } + return signature, nil +} + +// SignData signs the hash of the provided data, but does so differently +// depending on the content-type specified. +// +// Different types of validation occur. +func (api *SignerAPI) SignData(ctx context.Context, contentType string, addr common.MixedcaseAddress, data interface{}) (hexutil.Bytes, error) { + var req, transformV, err = api.determineSignatureFormat(ctx, contentType, addr, data) + if err != nil { + return nil, err + } + + signature, err := api.sign(addr, req, transformV) + if err != nil { + api.UI.ShowError(err.Error()) + return nil, err + } + return signature, nil +} + +// determineSignatureFormat determines which signature method should be used based upon the mime type +// In the cases where it matters ensure that the charset is handled. The charset +// resides in the 'params' returned as the second returnvalue from mime.ParseMediaType +// charset, ok := params["charset"] +// As it is now, we accept any charset and just treat it as 'raw'. +// This method returns the mimetype for signing along with the request +func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType string, addr common.MixedcaseAddress, data interface{}) (*SignDataRequest, bool, error) { + var ( + req *SignDataRequest + useEthereumV = true // Default to use V = 27 or 28, the legacy Ethereum format + ) + mediaType, _, err := mime.ParseMediaType(contentType) + if err != nil { + return nil, useEthereumV, err + } + + switch mediaType { + case TextValidator.Mime: + // Data with an intended validator + validatorData, err := UnmarshalValidatorData(data) + if err != nil { + return nil, useEthereumV, err + } + sighash, msg := SignTextValidator(validatorData) + message := []*NameValueType{ + { + Name: "message", + Typ: "text", + Value: msg, + }, + } + req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Message: message, Hash: sighash} + case ApplicationClique.Mime: + // Clique is the Ethereum PoA standard + stringData, ok := data.(string) + if !ok { + return nil, useEthereumV, fmt.Errorf("input for %v must be an hex-encoded string", ApplicationClique.Mime) + } + cliqueData, err := hexutil.Decode(stringData) + if err != nil { + return nil, useEthereumV, err + } + header := &types.Header{} + if err := rlp.DecodeBytes(cliqueData, header); err != nil { + return nil, useEthereumV, err + } + // The incoming clique header is already truncated, sent to us with a extradata already shortened + if len(header.Extra) < 65 { + // Need to add it back, to get a suitable length for hashing + newExtra := make([]byte, len(header.Extra)+65) + copy(newExtra, header.Extra) + header.Extra = newExtra + } + // Get back the rlp data, encoded by us + sighash, cliqueRlp, err := cliqueHeaderHashAndRlp(header) + if err != nil { + return nil, useEthereumV, err + } + message := []*NameValueType{ + { + Name: "Clique header", + Typ: "clique", + Value: fmt.Sprintf("clique header %d [0x%x]", header.Number, header.Hash()), + }, + } + // Clique uses V on the form 0 or 1 + useEthereumV = false + req = &SignDataRequest{ContentType: mediaType, Rawdata: cliqueRlp, Message: message, Hash: sighash} + default: // also case TextPlain.Mime: + // Calculates an Ethereum ECDSA signature for: + // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // We expect it to be a string + if stringData, ok := data.(string); !ok { + return nil, useEthereumV, fmt.Errorf("input for text/plain must be an hex-encoded string") + } else { + if textData, err := hexutil.Decode(stringData); err != nil { + return nil, useEthereumV, err + } else { + sighash, msg := accounts.TextAndHash(textData) + message := []*NameValueType{ + { + Name: "message", + Typ: accounts.MimetypeTextPlain, + Value: msg, + }, + } + req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Message: message, Hash: sighash} + } + } + } + req.Address = addr + req.Meta = MetadataFromContext(ctx) + return req, useEthereumV, nil + +} + +// SignTextWithValidator signs the given message which can be further recovered +// with the given validator. +// hash = keccak256("\x19\x00"${address}${data}). +func SignTextValidator(validatorData ValidatorData) (hexutil.Bytes, string) { + msg := fmt.Sprintf("\x19\x00%s%s", string(validatorData.Address.Bytes()), string(validatorData.Message)) + fmt.Printf("SignTextValidator:%s\n", msg) + return crypto.Keccak256([]byte(msg)), msg +} + +// cliqueHeaderHashAndRlp returns the hash which is used as input for the proof-of-authority +// signing. It is the hash of the entire header apart from the 65 byte signature +// contained at the end of the extra data. +// +// The method requires the extra data to be at least 65 bytes -- the original implementation +// in clique.go panics if this is the case, thus it's been reimplemented here to avoid the panic +// and simply return an error instead +func cliqueHeaderHashAndRlp(header *types.Header) (hash, rlp []byte, err error) { + if len(header.Extra) < 65 { + err = fmt.Errorf("clique header extradata too short, %d < 65", len(header.Extra)) + return + } + rlp = clique.CliqueRLP(header) + hash = clique.SealHash(header).Bytes() + return hash, rlp, err +} + +// SignTypedData signs EIP-712 conformant typed data +// hash = keccak256("\x19${byteVersion}${domainSeparator}${hashStruct(message)}") +func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAddress, typedData TypedData) (hexutil.Bytes, error) { + domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) + if err != nil { + return nil, err + } + typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) + if err != nil { + return nil, err + } + rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) + sighash := crypto.Keccak256(rawData) + message := typedData.Format() + req := &SignDataRequest{ContentType: DataTyped.Mime, Rawdata: rawData, Message: message, Hash: sighash} + signature, err := api.sign(addr, req, true) + if err != nil { + api.UI.ShowError(err.Error()) + return nil, err + } + return signature, nil +} + +// HashStruct generates a keccak256 hash of the encoding of the provided data +func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage) (hexutil.Bytes, error) { + encodedData, err := typedData.EncodeData(primaryType, data, 1) + if err != nil { + return nil, err + } + return crypto.Keccak256(encodedData), nil +} + +// Dependencies returns an array of custom types ordered by their hierarchical reference tree +func (typedData *TypedData) Dependencies(primaryType string, found []string) []string { + includes := func(arr []string, str string) bool { + for _, obj := range arr { + if obj == str { + return true + } + } + return false + } + + if includes(found, primaryType) { + return found + } + if typedData.Types[primaryType] == nil { + return found + } + found = append(found, primaryType) + for _, field := range typedData.Types[primaryType] { + for _, dep := range typedData.Dependencies(field.Type, found) { + if !includes(found, dep) { + found = append(found, dep) + } + } + } + return found +} + +// EncodeType generates the following encoding: +// `name ‖ "(" ‖ member₁ ‖ "," ‖ member₂ ‖ "," ‖ … ‖ memberₙ ")"` +// +// each member is written as `type ‖ " " ‖ name` encodings cascade down and are sorted by name +func (typedData *TypedData) EncodeType(primaryType string) hexutil.Bytes { + // Get dependencies primary first, then alphabetical + deps := typedData.Dependencies(primaryType, []string{}) + slicedDeps := deps[1:] + sort.Strings(slicedDeps) + deps = append([]string{primaryType}, slicedDeps...) + + // Format as a string with fields + var buffer bytes.Buffer + for _, dep := range deps { + buffer.WriteString(dep) + buffer.WriteString("(") + for _, obj := range typedData.Types[dep] { + buffer.WriteString(obj.Type) + buffer.WriteString(" ") + buffer.WriteString(obj.Name) + buffer.WriteString(",") + } + buffer.Truncate(buffer.Len() - 1) + buffer.WriteString(")") + } + return buffer.Bytes() +} + +// TypeHash creates the keccak256 hash of the data +func (typedData *TypedData) TypeHash(primaryType string) hexutil.Bytes { + return crypto.Keccak256(typedData.EncodeType(primaryType)) +} + +// EncodeData generates the following encoding: +// `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)` +// +// each encoded member is 32-byte long +func (typedData *TypedData) EncodeData(primaryType string, data map[string]interface{}, depth int) (hexutil.Bytes, error) { + if err := typedData.validate(); err != nil { + return nil, err + } + + buffer := bytes.Buffer{} + + // Verify extra data + if len(typedData.Types[primaryType]) < len(data) { + return nil, errors.New("there is extra data provided in the message") + } + + // Add typehash + buffer.Write(typedData.TypeHash(primaryType)) + + // Add field contents. Structs and arrays have special handlers. + for _, field := range typedData.Types[primaryType] { + encType := field.Type + encValue := data[field.Name] + if encType[len(encType)-1:] == "]" { + arrayValue, ok := encValue.([]interface{}) + if !ok { + return nil, dataMismatchError(encType, encValue) + } + + arrayBuffer := bytes.Buffer{} + parsedType := strings.Split(encType, "[")[0] + for _, item := range arrayValue { + if typedData.Types[parsedType] != nil { + mapValue, ok := item.(map[string]interface{}) + if !ok { + return nil, dataMismatchError(parsedType, item) + } + encodedData, err := typedData.EncodeData(parsedType, mapValue, depth+1) + if err != nil { + return nil, err + } + arrayBuffer.Write(encodedData) + } else { + bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth) + if err != nil { + return nil, err + } + arrayBuffer.Write(bytesValue) + } + } + + buffer.Write(crypto.Keccak256(arrayBuffer.Bytes())) + } else if typedData.Types[field.Type] != nil { + mapValue, ok := encValue.(map[string]interface{}) + if !ok { + return nil, dataMismatchError(encType, encValue) + } + encodedData, err := typedData.EncodeData(field.Type, mapValue, depth+1) + if err != nil { + return nil, err + } + buffer.Write(crypto.Keccak256(encodedData)) + } else { + byteValue, err := typedData.EncodePrimitiveValue(encType, encValue, depth) + if err != nil { + return nil, err + } + buffer.Write(byteValue) + } + } + return buffer.Bytes(), nil +} + +// EncodePrimitiveValue deals with the primitive values found +// while searching through the typed data +func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interface{}, depth int) ([]byte, error) { + + switch encType { + case "address": + stringValue, ok := encValue.(string) + if !ok || !common.IsHexAddress(stringValue) { + return nil, dataMismatchError(encType, encValue) + } + retval := make([]byte, 32) + copy(retval[12:], common.HexToAddress(stringValue).Bytes()) + return retval, nil + case "bool": + boolValue, ok := encValue.(bool) + if !ok { + return nil, dataMismatchError(encType, encValue) + } + if boolValue { + return math.PaddedBigBytes(common.Big1, 32), nil + } + return math.PaddedBigBytes(common.Big0, 32), nil + case "string": + strVal, ok := encValue.(string) + if !ok { + return nil, dataMismatchError(encType, encValue) + } + return crypto.Keccak256([]byte(strVal)), nil + case "bytes": + bytesValue, ok := encValue.([]byte) + if !ok { + return nil, dataMismatchError(encType, encValue) + } + return crypto.Keccak256(bytesValue), nil + } + if strings.HasPrefix(encType, "bytes") { + lengthStr := strings.TrimPrefix(encType, "bytes") + length, err := strconv.Atoi(lengthStr) + if err != nil { + return nil, fmt.Errorf("invalid size on bytes: %v", lengthStr) + } + if length < 0 || length > 32 { + return nil, fmt.Errorf("invalid size on bytes: %d", length) + } + if byteValue, ok := encValue.(hexutil.Bytes); !ok { + return nil, dataMismatchError(encType, encValue) + } else { + return math.PaddedBigBytes(new(big.Int).SetBytes(byteValue), 32), nil + } + } + if strings.HasPrefix(encType, "int") || strings.HasPrefix(encType, "uint") { + length := 0 + if encType == "int" || encType == "uint" { + length = 256 + } else { + lengthStr := "" + if strings.HasPrefix(encType, "uint") { + lengthStr = strings.TrimPrefix(encType, "uint") + } else { + lengthStr = strings.TrimPrefix(encType, "int") + } + atoiSize, err := strconv.Atoi(lengthStr) + if err != nil { + return nil, fmt.Errorf("invalid size on integer: %v", lengthStr) + } + length = atoiSize + } + bigIntValue, ok := encValue.(*big.Int) + if bigIntValue.BitLen() > length { + return nil, fmt.Errorf("integer larger than '%v'", encType) + } + if !ok { + return nil, dataMismatchError(encType, encValue) + } + return abi.U256(bigIntValue), nil + } + return nil, fmt.Errorf("unrecognized type '%s'", encType) + +} + +// dataMismatchError generates an error for a mismatch between +// the provided type and data +func dataMismatchError(encType string, encValue interface{}) error { + return fmt.Errorf("provided data '%v' doesn't match type '%s'", encValue, encType) +} + +// EcRecover recovers the address associated with the given sig. +// Only compatible with `text/plain` +func (api *SignerAPI) EcRecover(ctx context.Context, data hexutil.Bytes, sig hexutil.Bytes) (common.Address, error) { + // Returns the address for the Account that was used to create the signature. + // + // Note, this function is compatible with eth_sign and personal_sign. As such it recovers + // the address of: + // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // addr = ecrecover(hash, signature) + // + // Note, the signature must conform to the secp256k1 curve R, S and V values, where + // the V value must be be 27 or 28 for legacy reasons. + // + // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover + if len(sig) != 65 { + return common.Address{}, fmt.Errorf("signature must be 65 bytes long") + } + if sig[64] != 27 && sig[64] != 28 { + return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") + } + sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 + hash := accounts.TextHash(data) + rpk, err := crypto.SigToPub(hash, sig) + if err != nil { + return common.Address{}, err + } + return crypto.PubkeyToAddress(*rpk), nil +} + +// UnmarshalValidatorData converts the bytes input to typed data +func UnmarshalValidatorData(data interface{}) (ValidatorData, error) { + raw, ok := data.(map[string]interface{}) + if !ok { + return ValidatorData{}, errors.New("validator input is not a map[string]interface{}") + } + addr, ok := raw["address"].(string) + if !ok { + return ValidatorData{}, errors.New("validator address is not sent as a string") + } + addrBytes, err := hexutil.Decode(addr) + if err != nil { + return ValidatorData{}, err + } + if !ok || len(addrBytes) == 0 { + return ValidatorData{}, errors.New("validator address is undefined") + } + + message, ok := raw["message"].(string) + if !ok { + return ValidatorData{}, errors.New("message is not sent as a string") + } + messageBytes, err := hexutil.Decode(message) + if err != nil { + return ValidatorData{}, err + } + if !ok || len(messageBytes) == 0 { + return ValidatorData{}, errors.New("message is undefined") + } + + return ValidatorData{ + Address: common.BytesToAddress(addrBytes), + Message: messageBytes, + }, nil +} + +// validate makes sure the types are sound +func (typedData *TypedData) validate() error { + if err := typedData.Types.validate(); err != nil { + return err + } + if err := typedData.Domain.validate(); err != nil { + return err + } + return nil +} + +// Map generates a map version of the typed data +func (typedData *TypedData) Map() map[string]interface{} { + dataMap := map[string]interface{}{ + "types": typedData.Types, + "domain": typedData.Domain.Map(), + "primaryType": typedData.PrimaryType, + "message": typedData.Message, + } + return dataMap +} + +// PrettyPrint generates a nice output to help the users +// of clef present data in their apps +func (typedData *TypedData) PrettyPrint() string { + output := bytes.Buffer{} + formatted := typedData.Format() + for _, item := range formatted { + output.WriteString(fmt.Sprintf("%v\n", item.Pprint(0))) + } + return output.String() +} + +// Format returns a representation of typedData, which can be easily displayed by a user-interface +// without in-depth knowledge about 712 rules +func (typedData *TypedData) Format() []*NameValueType { + var nvts []*NameValueType + nvts = append(nvts, &NameValueType{ + Name: "EIP712Domain", + Value: typedData.formatData("EIP712Domain", typedData.Domain.Map()), + Typ: "domain", + }) + nvts = append(nvts, &NameValueType{ + Name: typedData.PrimaryType, + Value: typedData.formatData(typedData.PrimaryType, typedData.Message), + Typ: "primary type", + }) + return nvts +} + +func (typedData *TypedData) formatData(primaryType string, data map[string]interface{}) []*NameValueType { + var output []*NameValueType + + // Add field contents. Structs and arrays have special handlers. + for _, field := range typedData.Types[primaryType] { + encName := field.Name + encValue := data[encName] + item := &NameValueType{ + Name: encName, + Typ: field.Type, + } + if field.isArray() { + arrayValue, _ := encValue.([]interface{}) + parsedType := field.typeName() + for _, v := range arrayValue { + if typedData.Types[parsedType] != nil { + mapValue, _ := v.(map[string]interface{}) + mapOutput := typedData.formatData(parsedType, mapValue) + item.Value = mapOutput + } else { + primitiveOutput := formatPrimitiveValue(field.Type, encValue) + item.Value = primitiveOutput + } + } + } else if typedData.Types[field.Type] != nil { + mapValue, _ := encValue.(map[string]interface{}) + mapOutput := typedData.formatData(field.Type, mapValue) + item.Value = mapOutput + } else { + primitiveOutput := formatPrimitiveValue(field.Type, encValue) + item.Value = primitiveOutput + } + output = append(output, item) + } + return output +} + +func formatPrimitiveValue(encType string, encValue interface{}) string { + switch encType { + case "address": + stringValue, _ := encValue.(string) + return common.HexToAddress(stringValue).String() + case "bool": + boolValue, _ := encValue.(bool) + return fmt.Sprintf("%t", boolValue) + case "bytes", "string": + return fmt.Sprintf("%s", encValue) + } + if strings.HasPrefix(encType, "bytes") { + return fmt.Sprintf("%s", encValue) + } else if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") { + bigIntValue, _ := encValue.(*big.Int) + return fmt.Sprintf("%d (0x%x)", bigIntValue, bigIntValue) + } + return "NA" +} + +// NameValueType is a very simple struct with Name, Value and Type. It's meant for simple +// json structures used to communicate signing-info about typed data with the UI +type NameValueType struct { + Name string `json:"name"` + Value interface{} `json:"value"` + Typ string `json:"type"` +} + +// Pprint returns a pretty-printed version of nvt +func (nvt *NameValueType) Pprint(depth int) string { + output := bytes.Buffer{} + output.WriteString(strings.Repeat("\u00a0", depth*2)) + output.WriteString(fmt.Sprintf("%s [%s]: ", nvt.Name, nvt.Typ)) + if nvts, ok := nvt.Value.([]*NameValueType); ok { + output.WriteString("\n") + for _, next := range nvts { + sublevel := next.Pprint(depth + 1) + output.WriteString(sublevel) + } + } else { + output.WriteString(fmt.Sprintf("%q\n", nvt.Value)) + } + return output.String() +} + +// Validate checks if the types object is conformant to the specs +func (t Types) validate() error { + for typeKey, typeArr := range t { + for _, typeObj := range typeArr { + if typeKey == typeObj.Type { + return fmt.Errorf("type '%s' cannot reference itself", typeObj.Type) + } + if typeObj.isReferenceType() { + if _, exist := t[typeObj.Type]; !exist { + return fmt.Errorf("reference type '%s' is undefined", typeObj.Type) + } + if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) { + return fmt.Errorf("unknown reference type '%s", typeObj.Type) + } + } else if !isPrimitiveTypeValid(typeObj.Type) { + return fmt.Errorf("unknown type '%s'", typeObj.Type) + } + } + } + return nil +} + +// Checks if the primitive value is valid +func isPrimitiveTypeValid(primitiveType string) bool { + if primitiveType == "address" || + primitiveType == "address[]" || + primitiveType == "bool" || + primitiveType == "bool[]" || + primitiveType == "string" || + primitiveType == "string[]" { + return true + } + if primitiveType == "bytes" || + primitiveType == "bytes[]" || + primitiveType == "bytes1" || + primitiveType == "bytes1[]" || + primitiveType == "bytes2" || + primitiveType == "bytes2[]" || + primitiveType == "bytes3" || + primitiveType == "bytes3[]" || + primitiveType == "bytes4" || + primitiveType == "bytes4[]" || + primitiveType == "bytes5" || + primitiveType == "bytes5[]" || + primitiveType == "bytes6" || + primitiveType == "bytes6[]" || + primitiveType == "bytes7" || + primitiveType == "bytes7[]" || + primitiveType == "bytes8" || + primitiveType == "bytes8[]" || + primitiveType == "bytes9" || + primitiveType == "bytes9[]" || + primitiveType == "bytes10" || + primitiveType == "bytes10[]" || + primitiveType == "bytes11" || + primitiveType == "bytes11[]" || + primitiveType == "bytes12" || + primitiveType == "bytes12[]" || + primitiveType == "bytes13" || + primitiveType == "bytes13[]" || + primitiveType == "bytes14" || + primitiveType == "bytes14[]" || + primitiveType == "bytes15" || + primitiveType == "bytes15[]" || + primitiveType == "bytes16" || + primitiveType == "bytes16[]" || + primitiveType == "bytes17" || + primitiveType == "bytes17[]" || + primitiveType == "bytes18" || + primitiveType == "bytes18[]" || + primitiveType == "bytes19" || + primitiveType == "bytes19[]" || + primitiveType == "bytes20" || + primitiveType == "bytes20[]" || + primitiveType == "bytes21" || + primitiveType == "bytes21[]" || + primitiveType == "bytes22" || + primitiveType == "bytes22[]" || + primitiveType == "bytes23" || + primitiveType == "bytes23[]" || + primitiveType == "bytes24" || + primitiveType == "bytes24[]" || + primitiveType == "bytes25" || + primitiveType == "bytes25[]" || + primitiveType == "bytes26" || + primitiveType == "bytes26[]" || + primitiveType == "bytes27" || + primitiveType == "bytes27[]" || + primitiveType == "bytes28" || + primitiveType == "bytes28[]" || + primitiveType == "bytes29" || + primitiveType == "bytes29[]" || + primitiveType == "bytes30" || + primitiveType == "bytes30[]" || + primitiveType == "bytes31" || + primitiveType == "bytes31[]" { + return true + } + if primitiveType == "int" || + primitiveType == "int[]" || + primitiveType == "int8" || + primitiveType == "int8[]" || + primitiveType == "int16" || + primitiveType == "int16[]" || + primitiveType == "int32" || + primitiveType == "int32[]" || + primitiveType == "int64" || + primitiveType == "int64[]" || + primitiveType == "int128" || + primitiveType == "int128[]" || + primitiveType == "int256" || + primitiveType == "int256[]" { + return true + } + if primitiveType == "uint" || + primitiveType == "uint[]" || + primitiveType == "uint8" || + primitiveType == "uint8[]" || + primitiveType == "uint16" || + primitiveType == "uint16[]" || + primitiveType == "uint32" || + primitiveType == "uint32[]" || + primitiveType == "uint64" || + primitiveType == "uint64[]" || + primitiveType == "uint128" || + primitiveType == "uint128[]" || + primitiveType == "uint256" || + primitiveType == "uint256[]" { + return true + } + return false +} + +// validate checks if the given domain is valid, i.e. contains at least +// the minimum viable keys and values +func (domain *TypedDataDomain) validate() error { + if domain.ChainId == big.NewInt(0) { + return errors.New("chainId must be specified according to EIP-155") + } + + if len(domain.Name) == 0 && len(domain.Version) == 0 && len(domain.VerifyingContract) == 0 && len(domain.Salt) == 0 { + return errors.New("domain is undefined") + } + + return nil +} + +// Map is a helper function to generate a map version of the domain +func (domain *TypedDataDomain) Map() map[string]interface{} { + dataMap := map[string]interface{}{ + "chainId": domain.ChainId, + } + + if len(domain.Name) > 0 { + dataMap["name"] = domain.Name + } + + if len(domain.Version) > 0 { + dataMap["version"] = domain.Version + } + + if len(domain.VerifyingContract) > 0 { + dataMap["verifyingContract"] = domain.VerifyingContract + } + + if len(domain.Salt) > 0 { + dataMap["salt"] = domain.Salt + } + return dataMap +} diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/signed_data_test.go b/vendor/github.com/ethereum/go-ethereum/signer/core/signed_data_test.go new file mode 100644 index 00000000..76e1b72e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/signed_data_test.go @@ -0,0 +1,774 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . +// +package core + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var typesStandard = Types{ + "EIP712Domain": { + { + Name: "name", + Type: "string", + }, + { + Name: "version", + Type: "string", + }, + { + Name: "chainId", + Type: "uint256", + }, + { + Name: "verifyingContract", + Type: "address", + }, + }, + "Person": { + { + Name: "name", + Type: "string", + }, + { + Name: "wallet", + Type: "address", + }, + }, + "Mail": { + { + Name: "from", + Type: "Person", + }, + { + Name: "to", + Type: "Person", + }, + { + Name: "contents", + Type: "string", + }, + }, +} + +var jsonTypedData = ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "test", + "type": "uint8" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "test": 3, + "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } +` + +const primaryType = "Mail" + +var domainStandard = TypedDataDomain{ + "Ether Mail", + "1", + big.NewInt(1), + "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + "", +} + +var messageStandard = map[string]interface{}{ + "from": map[string]interface{}{ + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + }, + "to": map[string]interface{}{ + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + }, + "contents": "Hello, Bob!", +} + +var typedData = TypedData{ + Types: typesStandard, + PrimaryType: primaryType, + Domain: domainStandard, + Message: messageStandard, +} + +func TestSignData(t *testing.T) { + api, control := setup(t) + //Create two accounts + createAccount(control, api, t) + createAccount(control, api, t) + control.approveCh <- "1" + list, err := api.List(context.Background()) + if err != nil { + t.Fatal(err) + } + a := common.NewMixedcaseAddress(list[0]) + + control.approveCh <- "Y" + control.inputCh <- "wrongpassword" + signature, err := api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) + if signature != nil { + t.Errorf("Expected nil-data, got %x", signature) + } + if err != keystore.ErrDecrypt { + t.Errorf("Expected ErrLocked! '%v'", err) + } + control.approveCh <- "No way" + signature, err = api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) + if signature != nil { + t.Errorf("Expected nil-data, got %x", signature) + } + if err != ErrRequestDenied { + t.Errorf("Expected ErrRequestDenied! '%v'", err) + } + // text/plain + control.approveCh <- "Y" + control.inputCh <- "a_long_password" + signature, err = api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) + if err != nil { + t.Fatal(err) + } + if signature == nil || len(signature) != 65 { + t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) + } + // data/typed + control.approveCh <- "Y" + control.inputCh <- "a_long_password" + signature, err = api.SignTypedData(context.Background(), a, typedData) + if err != nil { + t.Fatal(err) + } + if signature == nil || len(signature) != 65 { + t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) + } +} + +func TestHashStruct(t *testing.T) { + hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) + if err != nil { + t.Fatal(err) + } + mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) + if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" { + t.Errorf("Expected different hashStruct result (got %s)", mainHash) + } + + hash, err = typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) + if err != nil { + t.Error(err) + } + domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) + if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" { + t.Errorf("Expected different domain hashStruct result (got %s)", domainHash) + } +} + +func TestEncodeType(t *testing.T) { + domainTypeEncoding := string(typedData.EncodeType("EIP712Domain")) + if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" { + t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding) + } + + mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType)) + if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" { + t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding) + } +} + +func TestTypeHash(t *testing.T) { + mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType))) + if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" { + t.Errorf("Expected different typeHash result (got %s)", mailTypeHash) + } +} + +func TestEncodeData(t *testing.T) { + hash, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0) + if err != nil { + t.Fatal(err) + } + dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) + if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" { + t.Errorf("Expected different encodeData result (got %s)", dataEncoding) + } +} + +func TestMalformedDomainkeys(t *testing.T) { + // Verifies that malformed domain keys are properly caught: + //{ + // "name": "Ether Mail", + // "version": "1", + // "chainId": 1, + // "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + //} + jsonTypedData := ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } +` + var malformedDomainTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &malformedDomainTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + _, err = malformedDomainTypedData.HashStruct("EIP712Domain", malformedDomainTypedData.Domain.Map()) + if err == nil || err.Error() != "provided data '' doesn't match type 'address'" { + t.Errorf("Expected `provided data '' doesn't match type 'address'`, got '%v'", err) + } +} + +func TestMalformedTypesAndExtradata(t *testing.T) { + // Verifies several quirks + // 1. Using dynamic types and only validating the prefix: + //{ + // "name": "chainId", + // "type": "uint256 ... and now for something completely different" + //} + // 2. Extra data in message: + //{ + // "blahonga": "zonk bonk" + //} + jsonTypedData := ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256 ... and now for something completely different" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } +` + var malformedTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + + malformedTypedData.Types["EIP712Domain"][2].Type = "uint256" + malformedTypedData.Message["blahonga"] = "zonk bonk" + _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) + if err == nil || err.Error() != "there is extra data provided in the message" { + t.Errorf("Expected `there is extra data provided in the message`, got '%v'", err) + } +} + +func TestTypeMismatch(t *testing.T) { + // Verifies that: + // 1. Mismatches between the given type and data, i.e. `Person` and + // the data item is a string, are properly caught: + //{ + // "name": "contents", + // "type": "Person" + //}, + //{ + // "contents": "Hello, Bob!" <-- string not "Person" + //} + // 2. Nonexistent types are properly caught: + //{ + // "name": "contents", + // "type": "Blahonga" + //} + jsonTypedData := ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "Person" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } +` + var mismatchTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &mismatchTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) + if err.Error() != "provided data 'Hello, Bob!' doesn't match type 'Person'" { + t.Errorf("Expected `provided data 'Hello, Bob!' doesn't match type 'Person'`, got '%v'", err) + } + + mismatchTypedData.Types["Mail"][2].Type = "Blahonga" + _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) + if err == nil || err.Error() != "reference type 'Blahonga' is undefined" { + t.Fatalf("Expected `reference type 'Blahonga' is undefined`, got '%v'", err) + } +} + +func TestTypeOverflow(t *testing.T) { + // Verifies data that doesn't fit into it: + //{ + // "test": 65536 <-- test defined as uint8 + //} + var overflowTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &overflowTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + // Set test to something outside uint8 + (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(65536) + + _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) + if err == nil || err.Error() != "integer larger than 'uint8'" { + t.Fatalf("Expected `integer larger than 'uint8'`, got '%v'", err) + } + + (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(3) + (overflowTypedData.Message["to"]).(map[string]interface{})["test"] = big.NewInt(4) + + _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) + } +} + +func TestArray(t *testing.T) { + // Makes sure that arrays work fine + //{ + // "type": "address[]" + //}, + //{ + // "type": "string[]" + //}, + //{ + // "type": "uint16[]", + //} + + jsonTypedData := ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Foo": [ + { + "name": "bar", + "type": "address[]" + } + ] + }, + "primaryType": "Foo", + "domain": { + "name": "Lorem", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "bar": [ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003" + ] + } + } + ` + var arrayTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &arrayTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) + } + + // Change array to string + arrayTypedData.Types["Foo"][0].Type = "string[]" + arrayTypedData.Message["bar"] = []interface{}{ + "lorem", + "ipsum", + "dolores", + } + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) + } + + // Change array to uint + arrayTypedData.Types["Foo"][0].Type = "uint[]" + arrayTypedData.Message["bar"] = []interface{}{ + big.NewInt(1955), + big.NewInt(108), + big.NewInt(44010), + } + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) + } + + // Should not work with fixed-size arrays + arrayTypedData.Types["Foo"][0].Type = "uint[3]" + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err == nil || err.Error() != "unknown type 'uint[3]'" { + t.Fatalf("Expected `unknown type 'uint[3]'`, got '%v'", err) + } +} + +func TestCustomTypeAsArray(t *testing.T) { + var jsonTypedData = ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Person[]": [ + { + "name": "baz", + "type": "string" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person[]" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": {"baz": "foo"}, + "contents": "Hello, Bob!" + } + } + +` + var malformedTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + _, err = malformedTypedData.HashStruct("EIP712Domain", malformedTypedData.Domain.Map()) + if err != nil { + t.Errorf("Expected no error, got '%v'", err) + } +} + +func TestFormatter(t *testing.T) { + + var d TypedData + err := json.Unmarshal([]byte(jsonTypedData), &d) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + formatted := d.Format() + for _, item := range formatted { + fmt.Printf("'%v'\n", item.Pprint(0)) + } + + j, _ := json.Marshal(formatted) + fmt.Printf("'%v'\n", string(j)) +} diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/stdioui.go b/vendor/github.com/ethereum/go-ethereum/signer/core/stdioui.go index 64032386..0edb72de 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/stdioui.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/stdioui.go @@ -32,12 +32,16 @@ type StdIOUI struct { } func NewStdIOUI() *StdIOUI { - log.Info("NewStdIOUI") client, err := rpc.DialContext(context.Background(), "stdio://") if err != nil { log.Crit("Could not create stdio client", "err", err) } - return &StdIOUI{client: *client} + ui := &StdIOUI{client: *client} + return ui +} + +func (ui *StdIOUI) RegisterUIServer(api *UIServerAPI) { + ui.client.RegisterName("clef", api) } // dispatch sends a request over the stdio @@ -49,73 +53,71 @@ func (ui *StdIOUI) dispatch(serviceMethod string, args interface{}, reply interf return err } +// notify sends a request over the stdio, and does not listen for a response +func (ui *StdIOUI) notify(serviceMethod string, args interface{}) error { + ctx := context.Background() + err := ui.client.Notify(ctx, serviceMethod, args) + if err != nil { + log.Info("Error", "exc", err.Error()) + } + return err +} + func (ui *StdIOUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error) { var result SignTxResponse - err := ui.dispatch("ApproveTx", request, &result) + err := ui.dispatch("ui_approveTx", request, &result) return result, err } func (ui *StdIOUI) ApproveSignData(request *SignDataRequest) (SignDataResponse, error) { var result SignDataResponse - err := ui.dispatch("ApproveSignData", request, &result) - return result, err -} - -func (ui *StdIOUI) ApproveExport(request *ExportRequest) (ExportResponse, error) { - var result ExportResponse - err := ui.dispatch("ApproveExport", request, &result) - return result, err -} - -func (ui *StdIOUI) ApproveImport(request *ImportRequest) (ImportResponse, error) { - var result ImportResponse - err := ui.dispatch("ApproveImport", request, &result) + err := ui.dispatch("ui_approveSignData", request, &result) return result, err } func (ui *StdIOUI) ApproveListing(request *ListRequest) (ListResponse, error) { var result ListResponse - err := ui.dispatch("ApproveListing", request, &result) + err := ui.dispatch("ui_approveListing", request, &result) return result, err } func (ui *StdIOUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { var result NewAccountResponse - err := ui.dispatch("ApproveNewAccount", request, &result) + err := ui.dispatch("ui_approveNewAccount", request, &result) return result, err } func (ui *StdIOUI) ShowError(message string) { - err := ui.dispatch("ShowError", &Message{message}, nil) + err := ui.notify("ui_showError", &Message{message}) if err != nil { - log.Info("Error calling 'ShowError'", "exc", err.Error(), "msg", message) + log.Info("Error calling 'ui_showError'", "exc", err.Error(), "msg", message) } } func (ui *StdIOUI) ShowInfo(message string) { - err := ui.dispatch("ShowInfo", Message{message}, nil) + err := ui.notify("ui_showInfo", Message{message}) if err != nil { - log.Info("Error calling 'ShowInfo'", "exc", err.Error(), "msg", message) + log.Info("Error calling 'ui_showInfo'", "exc", err.Error(), "msg", message) } } func (ui *StdIOUI) OnApprovedTx(tx ethapi.SignTransactionResult) { - err := ui.dispatch("OnApprovedTx", tx, nil) + err := ui.notify("ui_onApprovedTx", tx) if err != nil { - log.Info("Error calling 'OnApprovedTx'", "exc", err.Error(), "tx", tx) + log.Info("Error calling 'ui_onApprovedTx'", "exc", err.Error(), "tx", tx) } } func (ui *StdIOUI) OnSignerStartup(info StartupInfo) { - err := ui.dispatch("OnSignerStartup", info, nil) + err := ui.notify("ui_onSignerStartup", info) if err != nil { - log.Info("Error calling 'OnSignerStartup'", "exc", err.Error(), "info", info) + log.Info("Error calling 'ui_onSignerStartup'", "exc", err.Error(), "info", info) } } func (ui *StdIOUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { var result UserInputResponse - err := ui.dispatch("OnInputRequired", info, &result) + err := ui.dispatch("ui_onInputRequired", info, &result) if err != nil { - log.Info("Error calling 'OnInputRequired'", "exc", err.Error(), "info", info) + log.Info("Error calling 'ui_onInputRequired'", "exc", err.Error(), "info", info) } return result, err } diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/types.go b/vendor/github.com/ethereum/go-ethereum/signer/core/types.go index 12805577..8743746b 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/types.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/types.go @@ -19,40 +19,14 @@ package core import ( "encoding/json" "fmt" + "math/big" "strings" - "math/big" - - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" ) -type Accounts []Account - -func (as Accounts) String() string { - var output []string - for _, a := range as { - output = append(output, a.String()) - } - return strings.Join(output, "\n") -} - -type Account struct { - Typ string `json:"type"` - URL accounts.URL `json:"url"` - Address common.Address `json:"address"` -} - -func (a Account) String() string { - s, err := json.Marshal(a) - if err == nil { - return string(s) - } - return err.Error() -} - type ValidationInfo struct { Typ string `json:"type"` Message string `json:"message"` @@ -101,7 +75,7 @@ type SendTxArgs struct { Nonce hexutil.Uint64 `json:"nonce"` // We accept "data" and "input" for backwards-compatibility reasons. Data *hexutil.Bytes `json:"data"` - Input *hexutil.Bytes `json:"input"` + Input *hexutil.Bytes `json:"input,omitempty"` } func (args SendTxArgs) String() string { diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/uiapi.go b/vendor/github.com/ethereum/go-ethereum/signer/core/uiapi.go new file mode 100644 index 00000000..6dc68313 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/uiapi.go @@ -0,0 +1,201 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . +// + +package core + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "math/big" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +// SignerUIAPI implements methods Clef provides for a UI to query, in the bidirectional communication +// channel. +// This API is considered secure, since a request can only +// ever arrive from the UI -- and the UI is capable of approving any action, thus we can consider these +// requests pre-approved. +// NB: It's very important that these methods are not ever exposed on the external service +// registry. +type UIServerAPI struct { + extApi *SignerAPI + am *accounts.Manager +} + +// NewUIServerAPI creates a new UIServerAPI +func NewUIServerAPI(extapi *SignerAPI) *UIServerAPI { + return &UIServerAPI{extapi, extapi.am} +} + +// List available accounts. As opposed to the external API definition, this method delivers +// the full Account object and not only Address. +// Example call +// {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4} +func (s *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) { + var accs []accounts.Account + for _, wallet := range s.am.Wallets() { + accs = append(accs, wallet.Accounts()...) + } + return accs, nil +} + +// rawWallet is a JSON representation of an accounts.Wallet interface, with its +// data contents extracted into plain fields. +type rawWallet struct { + URL string `json:"url"` + Status string `json:"status"` + Failure string `json:"failure,omitempty"` + Accounts []accounts.Account `json:"accounts,omitempty"` +} + +// ListWallets will return a list of wallets that clef manages +// Example call +// {"jsonrpc":"2.0","method":"clef_listWallets","params":[], "id":5} +func (s *UIServerAPI) ListWallets() []rawWallet { + wallets := make([]rawWallet, 0) // return [] instead of nil if empty + for _, wallet := range s.am.Wallets() { + status, failure := wallet.Status() + + raw := rawWallet{ + URL: wallet.URL().String(), + Status: status, + Accounts: wallet.Accounts(), + } + if failure != nil { + raw.Failure = failure.Error() + } + wallets = append(wallets, raw) + } + return wallets +} + +// DeriveAccount requests a HD wallet to derive a new account, optionally pinning +// it for later reuse. +// Example call +// {"jsonrpc":"2.0","method":"clef_deriveAccount","params":["ledger://","m/44'/60'/0'", false], "id":6} +func (s *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { + wallet, err := s.am.Wallet(url) + if err != nil { + return accounts.Account{}, err + } + derivPath, err := accounts.ParseDerivationPath(path) + if err != nil { + return accounts.Account{}, err + } + if pin == nil { + pin = new(bool) + } + return wallet.Derive(derivPath, *pin) +} + +// fetchKeystore retrives the encrypted keystore from the account manager. +func fetchKeystore(am *accounts.Manager) *keystore.KeyStore { + return am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) +} + +// ImportRawKey stores the given hex encoded ECDSA key into the key directory, +// encrypting it with the passphrase. +// Example call (should fail on password too short) +// {"jsonrpc":"2.0","method":"clef_importRawKey","params":["1111111111111111111111111111111111111111111111111111111111111111","test"], "id":6} +func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) { + key, err := crypto.HexToECDSA(privkey) + if err != nil { + return accounts.Account{}, err + } + if err := ValidatePasswordFormat(password); err != nil { + return accounts.Account{}, fmt.Errorf("password requirements not met: %v", err) + } + // No error + return fetchKeystore(s.am).ImportECDSA(key, password) +} + +// OpenWallet initiates a hardware wallet opening procedure, establishing a USB +// connection and attempting to authenticate via the provided passphrase. Note, +// the method may return an extra challenge requiring a second open (e.g. the +// Trezor PIN matrix challenge). +// Example +// {"jsonrpc":"2.0","method":"clef_openWallet","params":["ledger://",""], "id":6} +func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error { + wallet, err := s.am.Wallet(url) + if err != nil { + return err + } + pass := "" + if passphrase != nil { + pass = *passphrase + } + return wallet.Open(pass) +} + +// ChainId returns the chainid in use for Eip-155 replay protection +// Example call +// {"jsonrpc":"2.0","method":"clef_chainId","params":[], "id":8} +func (s *UIServerAPI) ChainId() math.HexOrDecimal64 { + return (math.HexOrDecimal64)(s.extApi.chainID.Uint64()) +} + +// SetChainId sets the chain id to use when signing transactions. +// Example call to set Ropsten: +// {"jsonrpc":"2.0","method":"clef_setChainId","params":["3"], "id":8} +func (s *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 { + s.extApi.chainID = new(big.Int).SetUint64(uint64(id)) + return s.ChainId() +} + +// Export returns encrypted private key associated with the given address in web3 keystore format. +// Example +// {"jsonrpc":"2.0","method":"clef_export","params":["0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a"], "id":4} +func (s *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { + // Look up the wallet containing the requested signer + wallet, err := s.am.Find(accounts.Account{Address: addr}) + if err != nil { + return nil, err + } + if wallet.URL().Scheme != keystore.KeyStoreScheme { + return nil, fmt.Errorf("Account is not a keystore-account") + } + return ioutil.ReadFile(wallet.URL().Path) +} + +// Import tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be +// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful +// decryption it will encrypt the key with the given newPassphrase and store it in the keystore. +// Example (the address in question has privkey `11...11`): +// {"jsonrpc":"2.0","method":"clef_import","params":[{"address":"19e7e376e7c213b7e7e7e46cc70a5dd086daff2a","crypto":{"cipher":"aes-128-ctr","ciphertext":"33e4cd3756091d037862bb7295e9552424a391a6e003272180a455ca2a9fb332","cipherparams":{"iv":"b54b263e8f89c42bb219b6279fba5cce"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e4ca94644fd30569c1b1afbbc851729953c92637b7fe4bb9840bbb31ffbc64a5"},"mac":"f4092a445c2b21c0ef34f17c9cd0d873702b2869ec5df4439a0c2505823217e7"},"id":"216c7eac-e8c1-49af-a215-fa0036f29141","version":3},"test","yaddayadda"], "id":4} +func (api *UIServerAPI) Import(ctx context.Context, keyJSON json.RawMessage, oldPassphrase, newPassphrase string) (accounts.Account, error) { + be := api.am.Backends(keystore.KeyStoreType) + + if len(be) == 0 { + return accounts.Account{}, errors.New("password based accounts not supported") + } + if err := ValidatePasswordFormat(newPassphrase); err != nil { + return accounts.Account{}, fmt.Errorf("password requirements not met: %v", err) + } + return be[0].(*keystore.KeyStore).Import(keyJSON, oldPassphrase, newPassphrase) +} + +// Other methods to be added, not yet implemented are: +// - Ruleset interaction: add rules, attest rulefiles +// - Store metadata about accounts, e.g. naming of accounts diff --git a/vendor/github.com/ethereum/go-ethereum/signer/core/validation_test.go b/vendor/github.com/ethereum/go-ethereum/signer/core/validation_test.go index 155b25e9..1e2e69ec 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/core/validation_test.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/core/validation_test.go @@ -25,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) -func hexAddr(a string) common.Address { return common.BytesToAddress(common.FromHex(a)) } func mixAddr(a string) (*common.MixedcaseAddress, error) { return common.NewMixedcaseAddressFromString(a) } diff --git a/vendor/github.com/ethereum/go-ethereum/signer/rules/rules.go b/vendor/github.com/ethereum/go-ethereum/signer/rules/rules.go index 07c34db2..5ebffa3a 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/rules/rules.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/rules/rules.go @@ -22,7 +22,6 @@ import ( "os" "strings" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/signer/core" @@ -42,29 +41,30 @@ func consoleOutput(call otto.FunctionCall) otto.Value { for _, argument := range call.ArgumentList { output = append(output, fmt.Sprintf("%v", argument)) } - fmt.Fprintln(os.Stdout, strings.Join(output, " ")) + fmt.Fprintln(os.Stderr, strings.Join(output, " ")) return otto.Value{} } -// rulesetUI provides an implementation of SignerUI that evaluates a javascript +// rulesetUI provides an implementation of UIClientAPI that evaluates a javascript // file for each defined UI-method type rulesetUI struct { - next core.SignerUI // The next handler, for manual processing - storage storage.Storage - credentials storage.Storage - jsRules string // The rules to use + next core.UIClientAPI // The next handler, for manual processing + storage storage.Storage + jsRules string // The rules to use } -func NewRuleEvaluator(next core.SignerUI, jsbackend, credentialsBackend storage.Storage) (*rulesetUI, error) { +func NewRuleEvaluator(next core.UIClientAPI, jsbackend storage.Storage) (*rulesetUI, error) { c := &rulesetUI{ - next: next, - storage: jsbackend, - credentials: credentialsBackend, - jsRules: "", + next: next, + storage: jsbackend, + jsRules: "", } return c, nil } +func (r *rulesetUI) RegisterUIServer(api *core.UIServerAPI) { + // TODO, make it possible to query from js +} func (r *rulesetUI) Init(javascriptRules string) error { r.jsRules = javascriptRules @@ -150,18 +150,12 @@ func (r *rulesetUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, if approved { return core.SignTxResponse{ Transaction: request.Transaction, - Approved: true, - Password: r.lookupPassword(request.Transaction.From.Address()), - }, + Approved: true}, nil } return core.SignTxResponse{Approved: false}, err } -func (r *rulesetUI) lookupPassword(address common.Address) string { - return r.credentials.Get(strings.ToLower(address.String())) -} - func (r *rulesetUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { jsonreq, err := json.Marshal(request) approved, err := r.checkApproval("ApproveSignData", jsonreq, err) @@ -170,28 +164,9 @@ func (r *rulesetUI) ApproveSignData(request *core.SignDataRequest) (core.SignDat return r.next.ApproveSignData(request) } if approved { - return core.SignDataResponse{Approved: true, Password: r.lookupPassword(request.Address.Address())}, nil + return core.SignDataResponse{Approved: true}, nil } - return core.SignDataResponse{Approved: false, Password: ""}, err -} - -func (r *rulesetUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { - jsonreq, err := json.Marshal(request) - approved, err := r.checkApproval("ApproveExport", jsonreq, err) - if err != nil { - log.Info("Rule-based approval error, going to manual", "error", err) - return r.next.ApproveExport(request) - } - if approved { - return core.ExportResponse{Approved: true}, nil - } - return core.ExportResponse{Approved: false}, err -} - -func (r *rulesetUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { - // This cannot be handled by rules, requires setting a password - // dispatch to next - return r.next.ApproveImport(request) + return core.SignDataResponse{Approved: false}, err } // OnInputRequired not handled by rules diff --git a/vendor/github.com/ethereum/go-ethereum/signer/rules/rules_test.go b/vendor/github.com/ethereum/go-ethereum/signer/rules/rules_test.go index 0b520a15..19d9049c 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/rules/rules_test.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/rules/rules_test.go @@ -77,28 +77,18 @@ type alwaysDenyUI struct{} func (alwaysDenyUI) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) { return core.UserInputResponse{}, nil } +func (alwaysDenyUI) RegisterUIServer(api *core.UIServerAPI) { +} func (alwaysDenyUI) OnSignerStartup(info core.StartupInfo) { } -func (alwaysDenyUI) OnMasterPassword(request *core.PasswordRequest) (core.PasswordResponse, error) { - return core.PasswordResponse{}, nil -} - func (alwaysDenyUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { - return core.SignTxResponse{Transaction: request.Transaction, Approved: false, Password: ""}, nil + return core.SignTxResponse{Transaction: request.Transaction, Approved: false}, nil } func (alwaysDenyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { - return core.SignDataResponse{Approved: false, Password: ""}, nil -} - -func (alwaysDenyUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { - return core.ExportResponse{Approved: false}, nil -} - -func (alwaysDenyUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { - return core.ImportResponse{Approved: false, OldPassword: "", NewPassword: ""}, nil + return core.SignDataResponse{Approved: false}, nil } func (alwaysDenyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { @@ -106,7 +96,7 @@ func (alwaysDenyUI) ApproveListing(request *core.ListRequest) (core.ListResponse } func (alwaysDenyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { - return core.NewAccountResponse{Approved: false, Password: ""}, nil + return core.NewAccountResponse{Approved: false}, nil } func (alwaysDenyUI) ShowError(message string) { @@ -122,7 +112,7 @@ func (alwaysDenyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { } func initRuleEngine(js string) (*rulesetUI, error) { - r, err := NewRuleEvaluator(&alwaysDenyUI{}, storage.NewEphemeralStorage(), storage.NewEphemeralStorage()) + r, err := NewRuleEvaluator(&alwaysDenyUI{}, storage.NewEphemeralStorage()) if err != nil { return nil, fmt.Errorf("failed to create js engine: %v", err) } @@ -133,11 +123,11 @@ func initRuleEngine(js string) (*rulesetUI, error) { } func TestListRequest(t *testing.T) { - accs := make([]core.Account, 5) + accs := make([]accounts.Account, 5) for i := range accs { addr := fmt.Sprintf("000000000000000000000000000000000000000%x", i) - acc := core.Account{ + acc := accounts.Account{ Address: common.BytesToAddress(common.Hex2Bytes(addr)), URL: accounts.URL{Scheme: "test", Path: fmt.Sprintf("acc-%d", i)}, } @@ -208,6 +198,10 @@ type dummyUI struct { calls []string } +func (d *dummyUI) RegisterUIServer(api *core.UIServerAPI) { + panic("implement me") +} + func (d *dummyUI) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) { d.calls = append(d.calls, "OnInputRequired") return core.UserInputResponse{}, nil @@ -223,16 +217,6 @@ func (d *dummyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataR return core.SignDataResponse{}, core.ErrRequestDenied } -func (d *dummyUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { - d.calls = append(d.calls, "ApproveExport") - return core.ExportResponse{}, core.ErrRequestDenied -} - -func (d *dummyUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { - d.calls = append(d.calls, "ApproveImport") - return core.ImportResponse{}, core.ErrRequestDenied -} - func (d *dummyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { d.calls = append(d.calls, "ApproveListing") return core.ListResponse{}, core.ErrRequestDenied @@ -255,10 +239,6 @@ func (d *dummyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { d.calls = append(d.calls, "OnApprovedTx") } -func (d *dummyUI) OnMasterPassword(request *core.PasswordRequest) (core.PasswordResponse, error) { - return core.PasswordResponse{}, nil -} - func (d *dummyUI) OnSignerStartup(info core.StartupInfo) { } @@ -268,8 +248,7 @@ func TestForwarding(t *testing.T) { js := "" ui := &dummyUI{make([]string, 0)} jsBackend := storage.NewEphemeralStorage() - credBackend := storage.NewEphemeralStorage() - r, err := NewRuleEvaluator(ui, jsBackend, credBackend) + r, err := NewRuleEvaluator(ui, jsBackend) if err != nil { t.Fatalf("Failed to create js engine: %v", err) } @@ -278,17 +257,15 @@ func TestForwarding(t *testing.T) { } r.ApproveSignData(nil) r.ApproveTx(nil) - r.ApproveImport(nil) r.ApproveNewAccount(nil) r.ApproveListing(nil) - r.ApproveExport(nil) r.ShowError("test") r.ShowInfo("test") //This one is not forwarded r.OnApprovedTx(ethapi.SignTransactionResult{}) - expCalls := 8 + expCalls := 6 if len(ui.calls) != expCalls { t.Errorf("Expected %d forwarded calls, got %d: %s", expCalls, len(ui.calls), strings.Join(ui.calls, ",")) @@ -531,12 +508,10 @@ func (d *dontCallMe) OnInputRequired(info core.UserInputRequest) (core.UserInput d.t.Fatalf("Did not expect next-handler to be called") return core.UserInputResponse{}, nil } - -func (d *dontCallMe) OnSignerStartup(info core.StartupInfo) { +func (d *dontCallMe) RegisterUIServer(api *core.UIServerAPI) { } -func (d *dontCallMe) OnMasterPassword(request *core.PasswordRequest) (core.PasswordResponse, error) { - return core.PasswordResponse{}, nil +func (d *dontCallMe) OnSignerStartup(info core.StartupInfo) { } func (d *dontCallMe) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { @@ -549,16 +524,6 @@ func (d *dontCallMe) ApproveSignData(request *core.SignDataRequest) (core.SignDa return core.SignDataResponse{}, core.ErrRequestDenied } -func (d *dontCallMe) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) { - d.t.Fatalf("Did not expect next-handler to be called") - return core.ExportResponse{}, core.ErrRequestDenied -} - -func (d *dontCallMe) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) { - d.t.Fatalf("Did not expect next-handler to be called") - return core.ImportResponse{}, core.ErrRequestDenied -} - func (d *dontCallMe) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { d.t.Fatalf("Did not expect next-handler to be called") return core.ListResponse{}, core.ErrRequestDenied @@ -601,7 +566,7 @@ func TestContextIsCleared(t *testing.T) { } ` ui := &dontCallMe{t} - r, err := NewRuleEvaluator(ui, storage.NewEphemeralStorage(), storage.NewEphemeralStorage()) + r, err := NewRuleEvaluator(ui, storage.NewEphemeralStorage()) if err != nil { t.Fatalf("Failed to create js engine: %v", err) } @@ -624,7 +589,7 @@ func TestSignData(t *testing.T) { function ApproveSignData(r){ if( r.address.toLowerCase() == "0x694267f14675d7e1b9494fd8d72fefe1755710fa") { - if(r.message.indexOf("bazonk") >= 0){ + if(r.message[0].value.indexOf("bazonk") >= 0){ return "Approve" } return "Reject" @@ -636,18 +601,25 @@ function ApproveSignData(r){ t.Errorf("Couldn't create evaluator %v", err) return } - message := []byte("baz bazonk foo") - hash, msg := core.SignHash(message) - raw := hexutil.Bytes(message) + message := "baz bazonk foo" + hash, rawdata := accounts.TextAndHash([]byte(message)) addr, _ := mixAddr("0x694267f14675d7e1b9494fd8d72fefe1755710fa") fmt.Printf("address %v %v\n", addr.String(), addr.Original()) + + nvt := []*core.NameValueType{ + { + Name: "message", + Typ: "text/plain", + Value: message, + }, + } resp, err := r.ApproveSignData(&core.SignDataRequest{ Address: *addr, - Message: msg, + Message: nvt, Hash: hash, Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, - Rawdata: raw, + Rawdata: []byte(rawdata), }) if err != nil { t.Fatalf("Unexpected error %v", err) diff --git a/vendor/github.com/ethereum/go-ethereum/signer/storage/storage.go b/vendor/github.com/ethereum/go-ethereum/signer/storage/storage.go index 60f4e389..50c55e45 100644 --- a/vendor/github.com/ethereum/go-ethereum/signer/storage/storage.go +++ b/vendor/github.com/ethereum/go-ethereum/signer/storage/storage.go @@ -17,10 +17,6 @@ package storage -import ( - "fmt" -) - type Storage interface { // Put stores a value by key. 0-length keys results in no-op Put(key, value string) @@ -39,7 +35,7 @@ func (s *EphemeralStorage) Put(key, value string) { if len(key) == 0 { return } - fmt.Printf("storage: put %v -> %v\n", key, value) + //fmt.Printf("storage: put %v -> %v\n", key, value) s.data[key] = value } @@ -47,7 +43,7 @@ func (s *EphemeralStorage) Get(key string) string { if len(key) == 0 { return "" } - fmt.Printf("storage: get %v\n", key) + //fmt.Printf("storage: get %v\n", key) if v, exist := s.data[key]; exist { return v } @@ -60,3 +56,11 @@ func NewEphemeralStorage() Storage { } return s } + +// NoStorage is a dummy construct which doesn't remember anything you tell it +type NoStorage struct{} + +func (s *NoStorage) Put(key, value string) {} +func (s *NoStorage) Get(key string) string { + return "" +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/OWNERS b/vendor/github.com/ethereum/go-ethereum/swarm/OWNERS index d4204e08..4b9ca96e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/OWNERS +++ b/vendor/github.com/ethereum/go-ethereum/swarm/OWNERS @@ -7,7 +7,6 @@ swarm ├── fuse ────────────────── @jmozah, @holisticode ├── grafana_dashboards ──── @nonsense ├── metrics ─────────────── @nonsense, @holisticode -├── multihash ───────────── @nolash ├── network ─────────────── ethersphere │ ├── bitvector ───────── @zelig, @janos, @gbalint │ ├── priorityqueue ───── @zelig, @janos, @gbalint diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/act.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/act.go index e54369f9..a79f1944 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/act.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/act.go @@ -15,11 +15,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/sctx" "github.com/ethereum/go-ethereum/swarm/storage" "golang.org/x/crypto/scrypt" + "golang.org/x/crypto/sha3" cli "gopkg.in/urfave/cli.v1" ) @@ -33,7 +33,7 @@ var ( } ) -const EMPTY_CREDENTIALS = "" +const EmptyCredentials = "" type AccessEntry struct { Type AccessType @@ -336,7 +336,7 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva } func (a *API) getACTDecryptionKey(ctx context.Context, actManifestAddress storage.Address, sessionKey []byte) (found bool, ciphertext, decryptionKey []byte, err error) { - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() hasher.Write(append(sessionKey, 0)) lookupKey := hasher.Sum(nil) hasher.Reset() @@ -462,7 +462,7 @@ func DoACT(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees return nil, nil, nil, err } - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() hasher.Write(append(sessionKey, 0)) lookupKey := hasher.Sum(nil) @@ -484,7 +484,7 @@ func DoACT(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees if err != nil { return nil, nil, nil, err } - hasher := sha3.NewKeccak256() + hasher := sha3.NewLegacyKeccak256() hasher.Write(append(sessionKey, 0)) lookupKey := hasher.Sum(nil) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/api.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/api.go index 7bb63196..86c11192 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/api.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/api.go @@ -42,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/multihash" "github.com/ethereum/go-ethereum/swarm/spancontext" "github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage/feed" @@ -51,10 +50,6 @@ import ( opentracing "github.com/opentracing/opentracing-go" ) -var ( - ErrNotFound = errors.New("not found") -) - var ( apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil) apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil) @@ -137,13 +132,6 @@ func MultiResolverOptionWithResolver(r ResolveValidator, tld string) MultiResolv } } -// MultiResolverOptionWithNameHash is unused at the time of this writing -func MultiResolverOptionWithNameHash(nameHash func(string) common.Hash) MultiResolverOption { - return func(m *MultiResolver) { - m.nameHash = nameHash - } -} - // NewMultiResolver creates a new instance of MultiResolver. func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) { m = &MultiResolver{ @@ -174,40 +162,6 @@ func (m *MultiResolver) Resolve(addr string) (h common.Hash, err error) { return } -// ValidateOwner checks the ENS to validate that the owner of the given domain is the given eth address -func (m *MultiResolver) ValidateOwner(name string, address common.Address) (bool, error) { - rs, err := m.getResolveValidator(name) - if err != nil { - return false, err - } - var addr common.Address - for _, r := range rs { - addr, err = r.Owner(m.nameHash(name)) - // we hide the error if it is not for the last resolver we check - if err == nil { - return addr == address, nil - } - } - return false, err -} - -// HeaderByNumber uses the validator of the given domainname and retrieves the header for the given block number -func (m *MultiResolver) HeaderByNumber(ctx context.Context, name string, blockNr *big.Int) (*types.Header, error) { - rs, err := m.getResolveValidator(name) - if err != nil { - return nil, err - } - for _, r := range rs { - var header *types.Header - header, err = r.HeaderByNumber(ctx, blockNr) - // we hide the error if it is not for the last resolver we check - if err == nil { - return header, nil - } - } - return nil, err -} - // getResolveValidator uses the hostname to retrieve the resolver associated with the top level domain func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, error) { rs := m.resolvers[""] @@ -225,11 +179,6 @@ func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, er return rs, nil } -// SetNameHash sets the hasher function that hashes the domain into a name hash that ENS uses -func (m *MultiResolver) SetNameHash(nameHash func(string) common.Hash) { - m.nameHash = nameHash -} - /* API implements webserver/file system related content storage and retrieval on top of the FileStore @@ -266,9 +215,6 @@ func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt b return a.fileStore.Store(ctx, data, size, toEncrypt) } -// ErrResolve is returned when an URI cannot be resolved from ENS. -type ErrResolve error - // Resolve a name into a content-addressed hash // where address could be an ENS name, or a content addressed hash func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) { @@ -417,7 +363,7 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage return reader, mimeType, status, nil, err } // get the data of the update - _, rsrcData, err := a.feed.GetContent(entry.Feed) + _, contentAddr, err := a.feed.GetContent(entry.Feed) if err != nil { apiGetNotFound.Inc(1) status = http.StatusNotFound @@ -425,23 +371,23 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage return reader, mimeType, status, nil, err } - // extract multihash - decodedMultihash, err := multihash.FromMultihash(rsrcData) - if err != nil { + // extract content hash + if len(contentAddr) != storage.AddressLength { apiGetInvalid.Inc(1) status = http.StatusUnprocessableEntity - log.Warn("invalid multihash in feed update", "err", err) - return reader, mimeType, status, nil, err + errorMessage := fmt.Sprintf("invalid swarm hash in feed update. Expected %d bytes. Got %d", storage.AddressLength, len(contentAddr)) + log.Warn(errorMessage) + return reader, mimeType, status, nil, errors.New(errorMessage) } - manifestAddr = storage.Address(decodedMultihash) - log.Trace("feed update contains multihash", "key", manifestAddr) + manifestAddr = storage.Address(contentAddr) + log.Trace("feed update contains swarm hash", "key", manifestAddr) - // get the manifest the multihash digest points to + // get the manifest the swarm hash points to trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt) if err != nil { apiGetNotFound.Inc(1) status = http.StatusNotFound - log.Warn(fmt.Sprintf("loadManifestTrie (feed update multihash) error: %v", err)) + log.Warn(fmt.Sprintf("loadManifestTrie (feed update) error: %v", err)) return reader, mimeType, status, nil, err } @@ -451,8 +397,8 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage if entry == nil { status = http.StatusNotFound apiGetNotFound.Inc(1) - err = fmt.Errorf("manifest (feed update multihash) entry for '%s' not found", path) - log.Trace("manifest (feed update multihash) entry not found", "key", manifestAddr, "path", path) + err = fmt.Errorf("manifest (feed update) entry for '%s' not found", path) + log.Trace("manifest (feed update) entry not found", "key", manifestAddr, "path", path) return reader, mimeType, status, nil, err } } @@ -472,7 +418,7 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage // no entry found status = http.StatusNotFound apiGetNotFound.Inc(1) - err = fmt.Errorf("manifest entry for '%s' not found", path) + err = fmt.Errorf("Not found: could not find resource '%s'", path) log.Trace("manifest entry not found", "key", contentAddr, "path", path) } return @@ -485,7 +431,7 @@ func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Add apiDeleteFail.Inc(1) return nil, err } - key, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) + key, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { return nil, err @@ -697,7 +643,7 @@ func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content [] apiAddFileFail.Inc(1) return nil, "", err } - mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) + mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { apiAddFileFail.Inc(1) return nil, "", err @@ -814,7 +760,7 @@ func (a *API) RemoveFile(ctx context.Context, mhash string, path string, fname s apiRmFileFail.Inc(1) return "", err } - mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) + mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { apiRmFileFail.Inc(1) return "", err @@ -881,7 +827,7 @@ func (a *API) AppendFile(ctx context.Context, mhash, path, fname string, existin apiAppendFileFail.Inc(1) return nil, "", err } - mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) + mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { apiAppendFileFail.Inc(1) return nil, "", err @@ -981,11 +927,6 @@ func (a *API) FeedsUpdate(ctx context.Context, request *feed.Request) (storage.A return a.feed.Update(ctx, request) } -// FeedsHashSize returned the size of the digest produced by Swarm feeds' hashing function -func (a *API) FeedsHashSize() int { - return a.feed.HashSize -} - // ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest") diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client.go index d9837ca7..5e293cca 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client.go @@ -19,6 +19,7 @@ package client import ( "archive/tar" "bytes" + "context" "encoding/json" "errors" "fmt" @@ -26,6 +27,7 @@ import ( "io/ioutil" "mime/multipart" "net/http" + "net/http/httptrace" "net/textproto" "net/url" "os" @@ -33,14 +35,14 @@ import ( "regexp" "strconv" "strings" + "time" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/spancontext" "github.com/ethereum/go-ethereum/swarm/storage/feed" -) - -var ( - DefaultGateway = "http://localhost:8500" - DefaultClient = NewClient(DefaultGateway) + "github.com/pborman/uuid" ) var ( @@ -474,6 +476,11 @@ type UploadFn func(file *File) error // TarUpload uses the given Uploader to upload files to swarm as a tar stream, // returning the resulting manifest hash func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, toEncrypt bool) (string, error) { + ctx, sp := spancontext.StartSpan(context.Background(), "api.client.tarupload") + defer sp.Finish() + + var tn time.Time + reqR, reqW := io.Pipe() defer reqR.Close() addr := hash @@ -489,6 +496,12 @@ func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, t if err != nil { return "", err } + + trace := GetClientTrace("swarm api client - upload tar", "api.client.uploadtar", uuid.New()[:8], &tn) + + req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) + transport := http.DefaultTransport + req.Header.Set("Content-Type", "application/x-tar") if defaultPath != "" { q := req.URL.Query() @@ -529,8 +542,8 @@ func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, t } reqW.CloseWithError(err) }() - - res, err := http.DefaultClient.Do(req) + tn = time.Now() + res, err := transport.RoundTrip(req) if err != nil { return "", err } @@ -728,3 +741,57 @@ func (c *Client) GetFeedRequest(query *feed.Query, manifestAddressOrDomain strin } return &metadata, nil } + +func GetClientTrace(traceMsg, metricPrefix, ruid string, tn *time.Time) *httptrace.ClientTrace { + trace := &httptrace.ClientTrace{ + GetConn: func(_ string) { + log.Trace(traceMsg+" - http get", "event", "GetConn", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".getconn", nil).Update(time.Since(*tn)) + }, + GotConn: func(_ httptrace.GotConnInfo) { + log.Trace(traceMsg+" - http get", "event", "GotConn", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".gotconn", nil).Update(time.Since(*tn)) + }, + PutIdleConn: func(err error) { + log.Trace(traceMsg+" - http get", "event", "PutIdleConn", "ruid", ruid, "err", err) + metrics.GetOrRegisterResettingTimer(metricPrefix+".putidle", nil).Update(time.Since(*tn)) + }, + GotFirstResponseByte: func() { + log.Trace(traceMsg+" - http get", "event", "GotFirstResponseByte", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".firstbyte", nil).Update(time.Since(*tn)) + }, + Got100Continue: func() { + log.Trace(traceMsg, "event", "Got100Continue", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".got100continue", nil).Update(time.Since(*tn)) + }, + DNSStart: func(_ httptrace.DNSStartInfo) { + log.Trace(traceMsg, "event", "DNSStart", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".dnsstart", nil).Update(time.Since(*tn)) + }, + DNSDone: func(_ httptrace.DNSDoneInfo) { + log.Trace(traceMsg, "event", "DNSDone", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".dnsdone", nil).Update(time.Since(*tn)) + }, + ConnectStart: func(network, addr string) { + log.Trace(traceMsg, "event", "ConnectStart", "ruid", ruid, "network", network, "addr", addr) + metrics.GetOrRegisterResettingTimer(metricPrefix+".connectstart", nil).Update(time.Since(*tn)) + }, + ConnectDone: func(network, addr string, err error) { + log.Trace(traceMsg, "event", "ConnectDone", "ruid", ruid, "network", network, "addr", addr, "err", err) + metrics.GetOrRegisterResettingTimer(metricPrefix+".connectdone", nil).Update(time.Since(*tn)) + }, + WroteHeaders: func() { + log.Trace(traceMsg, "event", "WroteHeaders(request)", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".wroteheaders", nil).Update(time.Since(*tn)) + }, + Wait100Continue: func() { + log.Trace(traceMsg, "event", "Wait100Continue", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".wait100continue", nil).Update(time.Since(*tn)) + }, + WroteRequest: func(_ httptrace.WroteRequestInfo) { + log.Trace(traceMsg, "event", "WroteRequest", "ruid", ruid) + metrics.GetOrRegisterResettingTimer(metricPrefix+".wroterequest", nil).Update(time.Since(*tn)) + }, + } + return trace +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client_test.go index 76b34939..39f6e479 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/client/client_test.go @@ -25,13 +25,13 @@ import ( "sort" "testing" + "github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/swarm/api" swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" - "github.com/ethereum/go-ethereum/swarm/multihash" "github.com/ethereum/go-ethereum/swarm/storage/feed" ) @@ -368,58 +368,99 @@ func newTestSigner() (*feed.GenericSigner, error) { return feed.NewGenericSigner(privKey), nil } -// test the transparent resolving of multihash feed updates with bzz:// scheme +// Test the transparent resolving of feed updates with bzz:// scheme // -// first upload data, and store the multihash to the resulting manifest in a feed update -// retrieving the update with the multihash should return the manifest pointing directly to the data +// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update. +// This effectively uses a feed to store a pointer to content rather than the content itself +// Retrieving the update with the Swarm hash should return the manifest pointing directly to the data // and raw retrieve of that hash should return the data -func TestClientCreateFeedMultihash(t *testing.T) { +func TestClientBzzWithFeed(t *testing.T) { signer, _ := newTestSigner() + // Initialize a Swarm test server srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - client := NewClient(srv.URL) + swarmClient := NewClient(srv.URL) defer srv.Close() - // add the data our multihash aliased manifest will point to - databytes := []byte("bar") + // put together some data for our test: + dataBytes := []byte(` + // + // Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update. + // So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it: + // + // MANIFEST HASH --> DATA + // + // Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this, + // we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash. + // + // FEED MANIFEST HASH --> MANIFEST HASH --> DATA + // + // Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash** + // stays constant, we have effectively created a fixed address to changing content. (Applause) + // + // FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2) + // + `) - swarmHash, err := client.UploadRaw(bytes.NewReader(databytes), int64(len(databytes)), false) - if err != nil { - t.Fatalf("Error uploading raw test data: %s", err) + // Create a virtual File out of memory containing the above data + f := &File{ + ReadCloser: ioutil.NopCloser(bytes.NewReader(dataBytes)), + ManifestEntry: api.ManifestEntry{ + ContentType: "text/plain", + Mode: 0660, + Size: int64(len(dataBytes)), + }, } - s := common.FromHex(swarmHash) - mh := multihash.ToMultihash(s) + // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded. + manifestAddressHex, err := swarmClient.Upload(f, "", false) + if err != nil { + t.Fatalf("Error creating manifest: %s", err) + } - // our feed topic - topic, _ := feed.NewTopic("foo.eth", nil) + // convert the hex-encoded manifest hash to a 32-byte slice + manifestAddress := common.FromHex(manifestAddressHex) - createRequest := feed.NewFirstRequest(topic) + if len(manifestAddress) != storage.AddressLength { + t.Fatalf("Something went wrong. Got a hash of an unexpected length. Expected %d bytes. Got %d", storage.AddressLength, len(manifestAddress)) + } - createRequest.SetData(mh) - if err := createRequest.Sign(signer); err != nil { + // Now create a **feed manifest**. For that, we need a topic: + topic, _ := feed.NewTopic("interesting topic indeed", nil) + + // Build a feed request to update data + request := feed.NewFirstRequest(topic) + + // Put the 32-byte address of the manifest into the feed update + request.SetData(manifestAddress) + + // Sign the update + if err := request.Sign(signer); err != nil { t.Fatalf("Error signing update: %s", err) } - feedManifestHash, err := client.CreateFeedWithManifest(createRequest) - + // Publish the update and at the same time request a **feed manifest** to be created + feedManifestAddressHex, err := swarmClient.CreateFeedWithManifest(request) if err != nil { t.Fatalf("Error creating feed manifest: %s", err) } - correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" - if feedManifestHash != correctManifestAddrHex { - t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) + // Check we have received the exact **feed manifest** to be expected + // given the topic and user signing the updates: + correctFeedManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2" + if feedManifestAddressHex != correctFeedManifestAddrHex { + t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctFeedManifestAddrHex, feedManifestAddressHex) } // Check we get a not found error when trying to get feed updates with a made-up manifest - _, err = client.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + _, err = swarmClient.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") if err != ErrNoFeedUpdatesFound { t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err) } - reader, err := client.QueryFeed(nil, correctManifestAddrHex) + // If we query the feed directly we should get **manifest hash** back: + reader, err := swarmClient.QueryFeed(nil, correctFeedManifestAddrHex) if err != nil { t.Fatalf("Error retrieving feed updates: %s", err) } @@ -428,10 +469,27 @@ func TestClientCreateFeedMultihash(t *testing.T) { if err != nil { t.Fatal(err) } - if !bytes.Equal(mh, gotData) { - t.Fatalf("Expected: %v, got %v", mh, gotData) + + //Check that indeed the **manifest hash** is retrieved + if !bytes.Equal(manifestAddress, gotData) { + t.Fatalf("Expected: %v, got %v", manifestAddress, gotData) } + // Now the final test we were looking for: Use bzz:// and that should resolve all manifests + // and return the original data directly: + f, err = swarmClient.Download(feedManifestAddressHex, "") + if err != nil { + t.Fatal(err) + } + gotData, err = ioutil.ReadAll(f) + if err != nil { + t.Fatal(err) + } + + // Check that we get back the original data: + if !bytes.Equal(dataBytes, gotData) { + t.Fatalf("Expected: %v, got %v", manifestAddress, gotData) + } } // TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client. diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/config.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/config.go index be738540..0a7100c5 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/config.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/config.go @@ -24,11 +24,11 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/contracts/ens" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/pss" "github.com/ethereum/go-ethereum/swarm/services/swap" @@ -47,9 +47,8 @@ type Config struct { *storage.FileStoreParams *storage.LocalStoreParams *network.HiveParams - Swap *swap.LocalProfile - Pss *pss.PssParams - //*network.SyncParams + Swap *swap.LocalProfile + Pss *pss.PssParams Contract common.Address EnsRoot common.Address EnsAPIs []string @@ -58,7 +57,7 @@ type Config struct { Port string PublicKey string BzzKey string - NodeID string + Enode *enode.Node `toml:"-"` NetworkID uint64 SwapEnabled bool SyncEnabled bool @@ -66,10 +65,12 @@ type Config struct { DeliverySkipCheck bool MaxStreamPeerServers int LightNodeEnabled bool + BootnodeMode bool SyncUpdateDelay time.Duration SwapAPI string Cors string BzzAccount string + GlobalStoreAPI string privateKey *ecdsa.PrivateKey } @@ -77,10 +78,9 @@ type Config struct { func NewConfig() (c *Config) { c = &Config{ - LocalStoreParams: storage.NewDefaultLocalStoreParams(), - FileStoreParams: storage.NewFileStoreParams(), - HiveParams: network.NewHiveParams(), - //SyncParams: network.NewDefaultSyncParams(), + LocalStoreParams: storage.NewDefaultLocalStoreParams(), + FileStoreParams: storage.NewFileStoreParams(), + HiveParams: network.NewHiveParams(), Swap: swap.NewDefaultSwapParams(), Pss: pss.NewPssParams(), ListenAddr: DefaultHTTPListenAddr, @@ -103,33 +103,38 @@ func NewConfig() (c *Config) { //some config params need to be initialized after the complete //config building phase is completed (e.g. due to overriding flags) -func (c *Config) Init(prvKey *ecdsa.PrivateKey) { +func (c *Config) Init(prvKey *ecdsa.PrivateKey, nodeKey *ecdsa.PrivateKey) error { - address := crypto.PubkeyToAddress(prvKey.PublicKey) - c.Path = filepath.Join(c.Path, "bzz-"+common.Bytes2Hex(address.Bytes())) - err := os.MkdirAll(c.Path, os.ModePerm) + // create swarm dir and record key + err := c.createAndSetPath(c.Path, prvKey) if err != nil { - log.Error(fmt.Sprintf("Error creating root swarm data directory: %v", err)) - return + return fmt.Errorf("Error creating root swarm data directory: %v", err) + } + c.setKey(prvKey) + + // create the new enode record + // signed with the ephemeral node key + enodeParams := &network.EnodeParams{ + PrivateKey: prvKey, + EnodeKey: nodeKey, + Lightnode: c.LightNodeEnabled, + Bootnode: c.BootnodeMode, + } + c.Enode, err = network.NewEnode(enodeParams) + if err != nil { + return fmt.Errorf("Error creating enode: %v", err) } - pubkey := crypto.FromECDSAPub(&prvKey.PublicKey) - pubkeyhex := common.ToHex(pubkey) - keyhex := crypto.Keccak256Hash(pubkey).Hex() - - c.PublicKey = pubkeyhex - c.BzzKey = keyhex - c.NodeID = enode.PubkeyToIDV4(&prvKey.PublicKey).String() - + // initialize components that depend on the swarm instance's private key if c.SwapEnabled { c.Swap.Init(c.Contract, prvKey) } - c.privateKey = prvKey c.LocalStoreParams.Init(c.Path) - c.LocalStoreParams.BaseKey = common.FromHex(keyhex) + c.LocalStoreParams.BaseKey = common.FromHex(c.BzzKey) c.Pss = c.Pss.WithPrivateKey(c.privateKey) + return nil } func (c *Config) ShiftPrivateKey() (privKey *ecdsa.PrivateKey) { @@ -139,3 +144,25 @@ func (c *Config) ShiftPrivateKey() (privKey *ecdsa.PrivateKey) { } return privKey } + +func (c *Config) setKey(prvKey *ecdsa.PrivateKey) { + bzzkeybytes := network.PrivateKeyToBzzKey(prvKey) + pubkey := crypto.FromECDSAPub(&prvKey.PublicKey) + pubkeyhex := hexutil.Encode(pubkey) + keyhex := hexutil.Encode(bzzkeybytes) + + c.privateKey = prvKey + c.PublicKey = pubkeyhex + c.BzzKey = keyhex +} + +func (c *Config) createAndSetPath(datadirPath string, prvKey *ecdsa.PrivateKey) error { + address := crypto.PubkeyToAddress(prvKey.PublicKey) + bzzdirPath := filepath.Join(datadirPath, "bzz-"+common.Bytes2Hex(address.Bytes())) + err := os.MkdirAll(bzzdirPath, os.ModePerm) + if err != nil { + return err + } + c.Path = bzzdirPath + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/config_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/config_test.go index bd7e1d87..a55da6f7 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/config_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/config_test.go @@ -27,11 +27,16 @@ import ( func TestConfig(t *testing.T) { var hexprvkey = "65138b2aa745041b372153550584587da326ab440576b2a1191dd95cee30039c" + var hexnodekey = "75138b2aa745041b372153550584587da326ab440576b2a1191dd95cee30039c" prvkey, err := crypto.HexToECDSA(hexprvkey) if err != nil { t.Fatalf("failed to load private key: %v", err) } + nodekey, err := crypto.HexToECDSA(hexnodekey) + if err != nil { + t.Fatalf("failed to load private key: %v", err) + } one := NewConfig() two := NewConfig() @@ -41,7 +46,10 @@ func TestConfig(t *testing.T) { t.Fatal("Two default configs are not equal") } - one.Init(prvkey) + err = one.Init(prvkey, nodekey) + if err != nil { + t.Fatal(err) + } //the init function should set the following fields if one.BzzKey == "" { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/encrypt.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/encrypt.go index ffe6c16d..0d516b3d 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/encrypt.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/encrypt.go @@ -20,8 +20,8 @@ import ( "encoding/binary" "errors" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/swarm/storage/encryption" + "golang.org/x/crypto/sha3" ) type RefEncryption struct { @@ -39,12 +39,12 @@ func NewRefEncryption(refSize int) *RefEncryption { } func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) { - spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewKeccak256) + spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256) encryptedSpan, err := spanEncryption.Encrypt(re.span) if err != nil { return nil, err } - dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewKeccak256) + dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256) encryptedData, err := dataEncryption.Encrypt(ref) if err != nil { return nil, err @@ -57,7 +57,7 @@ func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) { } func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) { - spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewKeccak256) + spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256) decryptedSpan, err := spanEncryption.Decrypt(ref[:8]) if err != nil { return nil, err @@ -68,7 +68,7 @@ func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) { return nil, errors.New("invalid span in encrypted reference") } - dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewKeccak256) + dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256) decryptedRef, err := dataEncryption.Decrypt(ref[8:]) if err != nil { return nil, err diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/http/middleware.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/http/middleware.go index ccc040c5..320da304 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/http/middleware.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/http/middleware.go @@ -5,6 +5,7 @@ import ( "net/http" "runtime/debug" "strings" + "time" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/swarm/api" @@ -73,9 +74,15 @@ func ParseURI(h http.Handler) http.Handler { func InitLoggingResponseWriter(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + tn := time.Now() + writer := newLoggingResponseWriter(w) h.ServeHTTP(writer, r) - log.Debug("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode) + + ts := time.Since(tn) + log.Info("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode, "time", ts) + metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.time", r.Method), nil).Update(ts) + metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.%d.time", r.Method, writer.statusCode), nil).Update(ts) }) } @@ -88,6 +95,7 @@ func InstrumentOpenTracing(h http.Handler) http.Handler { } spanName := fmt.Sprintf("http.%s.%s", r.Method, uri.Scheme) ctx, sp := spancontext.StartSpan(r.Context(), spanName) + defer sp.Finish() h.ServeHTTP(w, r.WithContext(ctx)) }) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/http/server_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/http/server_test.go index 1ef3deec..e82762ce 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/http/server_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/http/server_test.go @@ -45,7 +45,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/swarm/api" swarm "github.com/ethereum/go-ethereum/swarm/api/client" - "github.com/ethereum/go-ethereum/swarm/multihash" "github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage/feed" "github.com/ethereum/go-ethereum/swarm/testutil" @@ -69,60 +68,91 @@ func newTestSigner() (*feed.GenericSigner, error) { return feed.NewGenericSigner(privKey), nil } -// test the transparent resolving of multihash-containing feed updates with bzz:// scheme +// Test the transparent resolving of feed updates with bzz:// scheme // -// first upload data, and store the multihash to the resulting manifest in a feed update -// retrieving the update with the multihash should return the manifest pointing directly to the data +// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update. +// This effectively uses a feed to store a pointer to content rather than the content itself +// Retrieving the update with the Swarm hash should return the manifest pointing directly to the data // and raw retrieve of that hash should return the data -func TestBzzFeedMultihash(t *testing.T) { +func TestBzzWithFeed(t *testing.T) { signer, _ := newTestSigner() + // Initialize Swarm test server srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() - // add the data our multihash aliased manifest will point to - databytes := "bar" - testBzzUrl := fmt.Sprintf("%s/bzz:/", srv.URL) - resp, err := http.Post(testBzzUrl, "text/plain", bytes.NewReader([]byte(databytes))) + // put together some data for our test: + dataBytes := []byte(` + // + // Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update. + // So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it: + // + // MANIFEST HASH --> DATA + // + // Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this, + // we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash. + // + // FEED MANIFEST HASH --> MANIFEST HASH --> DATA + // + // Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash** + // stays constant, we have effectively created a fixed address to changing content. (Applause) + // + // FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2) ... + // + `) + + // POST data to bzz and get back a content-addressed **manifest hash** pointing to it. + resp, err := http.Post(fmt.Sprintf("%s/bzz:/", srv.URL), "text/plain", bytes.NewReader([]byte(dataBytes))) if err != nil { t.Fatal(err) } + defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("err %s", resp.Status) } - b, err := ioutil.ReadAll(resp.Body) + manifestAddressHex, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } - s := common.FromHex(string(b)) - mh := multihash.ToMultihash(s) - log.Info("added data", "manifest", string(b), "data", common.ToHex(mh)) + manifestAddress := common.FromHex(string(manifestAddressHex)) - topic, _ := feed.NewTopic("foo.eth", nil) + log.Info("added data", "manifest", string(manifestAddressHex)) + + // At this point we have uploaded the data and have a manifest pointing to it + // Now store that manifest address in a feed update. + // We also want a feed manifest, so we can use it to refer to the feed. + + // First, create a topic for our feed: + topic, _ := feed.NewTopic("interesting topic indeed", nil) + + // Create a feed update request: updateRequest := feed.NewFirstRequest(topic) - updateRequest.SetData(mh) + // Store the **manifest address** as data into the feed update. + updateRequest.SetData(manifestAddress) + // Sign the update if err := updateRequest.Sign(signer); err != nil { t.Fatal(err) } - log.Info("added data", "manifest", string(b), "data", common.ToHex(mh)) + log.Info("added data", "data", common.ToHex(manifestAddress)) - testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) + // Build the feed update http request: + feedUpdateURL, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) if err != nil { t.Fatal(err) } - query := testUrl.Query() + query := feedUpdateURL.Query() body := updateRequest.AppendValues(query) // this adds all query parameters and returns the data to be posted - query.Set("manifest", "1") // indicate we want a manifest back - testUrl.RawQuery = query.Encode() + query.Set("manifest", "1") // indicate we want a feed manifest back + feedUpdateURL.RawQuery = query.Encode() - // create the multihash update - resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) + // submit the feed update request to Swarm + resp, err = http.Post(feedUpdateURL.String(), "application/octet-stream", bytes.NewReader(body)) if err != nil { t.Fatal(err) } @@ -130,24 +160,25 @@ func TestBzzFeedMultihash(t *testing.T) { if resp.StatusCode != http.StatusOK { t.Fatalf("err %s", resp.Status) } - b, err = ioutil.ReadAll(resp.Body) + + feedManifestAddressHex, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } - rsrcResp := &storage.Address{} - err = json.Unmarshal(b, rsrcResp) + feedManifestAddress := &storage.Address{} + err = json.Unmarshal(feedManifestAddressHex, feedManifestAddress) if err != nil { - t.Fatalf("data %s could not be unmarshaled: %v", b, err) + t.Fatalf("data %s could not be unmarshaled: %v", feedManifestAddressHex, err) } - correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" - if rsrcResp.Hex() != correctManifestAddrHex { - t.Fatalf("Response feed manifest address mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) + correctManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2" + if feedManifestAddress.Hex() != correctManifestAddrHex { + t.Fatalf("Response feed manifest address mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestAddress.Hex()) } // get bzz manifest transparent feed update resolve - testBzzUrl = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp) - resp, err = http.Get(testBzzUrl) + getBzzURL := fmt.Sprintf("%s/bzz:/%s", srv.URL, feedManifestAddress) + resp, err = http.Get(getBzzURL) if err != nil { t.Fatal(err) } @@ -155,12 +186,12 @@ func TestBzzFeedMultihash(t *testing.T) { if resp.StatusCode != http.StatusOK { t.Fatalf("err %s", resp.Status) } - b, err = ioutil.ReadAll(resp.Body) + retrievedData, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } - if !bytes.Equal(b, []byte(databytes)) { - t.Fatalf("retrieved data mismatch, expected %x, got %x", databytes, b) + if !bytes.Equal(retrievedData, []byte(dataBytes)) { + t.Fatalf("retrieved data mismatch, expected %x, got %x", dataBytes, retrievedData) } } @@ -245,7 +276,8 @@ func TestBzzFeed(t *testing.T) { t.Fatalf("Expected manifest Feed '%s', got '%s'", correctFeedHex, manifest.Entries[0].Feed.Hex()) } - // get bzz manifest transparent feed update resolve + // take the chance to have bzz: crash on resolving a feed update that does not contain + // a swarm hash: testBzzUrl := fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp) resp, err = http.Get(testBzzUrl) if err != nil { @@ -253,7 +285,7 @@ func TestBzzFeed(t *testing.T) { } defer resp.Body.Close() if resp.StatusCode == http.StatusOK { - t.Fatal("Expected error status since feed update does not contain multihash. Received 200 OK") + t.Fatal("Expected error status since feed update does not contain a Swarm hash. Received 200 OK") } _, err = ioutil.ReadAll(resp.Body) if err != nil { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/inspector.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/inspector.go new file mode 100644 index 00000000..ea3c4c04 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/inspector.go @@ -0,0 +1,67 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package api + +import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +type Inspector struct { + api *API + hive *network.Hive + netStore *storage.NetStore +} + +func NewInspector(api *API, hive *network.Hive, netStore *storage.NetStore) *Inspector { + return &Inspector{api, hive, netStore} +} + +// Hive prints the kademlia table +func (inspector *Inspector) Hive() string { + return inspector.hive.String() +} + +func (inspector *Inspector) ListKnown() []string { + res := []string{} + for _, v := range inspector.hive.Kademlia.ListKnown() { + res = append(res, fmt.Sprintf("%v", v)) + } + return res +} + +type HasInfo struct { + Addr string `json:"address"` + Has bool `json:"has"` +} + +// Has checks whether each chunk address is present in the underlying datastore, +// the bool in the returned structs indicates if the underlying datastore has +// the chunk stored with the given address (true), or not (false) +func (inspector *Inspector) Has(chunkAddresses []storage.Address) []HasInfo { + results := make([]HasInfo, 0) + for _, addr := range chunkAddresses { + res := HasInfo{} + res.Addr = addr.String() + res.Has = inspector.netStore.Has(context.Background(), addr) + results = append(results, res) + } + return results +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/storage.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/storage.go index 8a48fe5b..254375b7 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/storage.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/storage.go @@ -83,23 +83,3 @@ func (s *Storage) Get(ctx context.Context, bzzpath string) (*Response, error) { } return &Response{mimeType, status, expsize, string(body[:size])}, err } - -// Modify(rootHash, basePath, contentHash, contentType) takes th e manifest trie rooted in rootHash, -// and merge on to it. creating an entry w conentType (mime) -// -// DEPRECATED: Use the HTTP API instead -func (s *Storage) Modify(ctx context.Context, rootHash, path, contentHash, contentType string) (newRootHash string, err error) { - uri, err := Parse("bzz:/" + rootHash) - if err != nil { - return "", err - } - addr, err := s.api.Resolve(ctx, uri.Addr) - if err != nil { - return "", err - } - addr, err = s.api.Modify(ctx, addr, path, contentHash, contentType) - if err != nil { - return "", err - } - return addr.Hex(), nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/uri_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/api/uri_test.go index ea649e27..a03874c4 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/uri_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/api/uri_test.go @@ -26,17 +26,15 @@ import ( func TestParseURI(t *testing.T) { type test struct { - uri string - expectURI *URI - expectErr bool - expectRaw bool - expectImmutable bool - expectList bool - expectHash bool - expectDeprecatedRaw bool - expectDeprecatedImmutable bool - expectValidKey bool - expectAddr storage.Address + uri string + expectURI *URI + expectErr bool + expectRaw bool + expectImmutable bool + expectList bool + expectHash bool + expectValidKey bool + expectAddr storage.Address } tests := []test{ { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt.go b/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt.go index a85d4369..18eab5a2 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt.go @@ -61,7 +61,7 @@ const ( ) // BaseHasherFunc is a hash.Hash constructor function used for the base hash of the BMT. -// implemented by Keccak256 SHA3 sha3.NewKeccak256 +// implemented by Keccak256 SHA3 sha3.NewLegacyKeccak256 type BaseHasherFunc func() hash.Hash // Hasher a reusable hasher for fixed maximum size chunks representing a BMT diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt_test.go index 683ba4f5..ab712d08 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/bmt/bmt_test.go @@ -26,8 +26,8 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/crypto/sha3" ) // the actual data length generated (could be longer than max datalength of the BMT) @@ -44,7 +44,7 @@ var counts = []int{1, 2, 3, 4, 5, 8, 9, 15, 16, 17, 32, 37, 42, 53, 63, 64, 65, // calculates the Keccak256 SHA3 hash of the data func sha3hash(data ...[]byte) []byte { - h := sha3.NewKeccak256() + h := sha3.NewLegacyKeccak256() return doSum(h, nil, data...) } @@ -121,7 +121,7 @@ func TestRefHasher(t *testing.T) { t.Run(fmt.Sprintf("%d_segments_%d_bytes", segmentCount, length), func(t *testing.T) { data := testutil.RandomBytes(i, length) expected := x.expected(data) - actual := NewRefHasher(sha3.NewKeccak256, segmentCount).Hash(data) + actual := NewRefHasher(sha3.NewLegacyKeccak256, segmentCount).Hash(data) if !bytes.Equal(actual, expected) { t.Fatalf("expected %x, got %x", expected, actual) } @@ -133,7 +133,7 @@ func TestRefHasher(t *testing.T) { // tests if hasher responds with correct hash comparing the reference implementation return value func TestHasherEmptyData(t *testing.T) { - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 var data []byte for _, count := range counts { t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { @@ -153,7 +153,7 @@ func TestHasherEmptyData(t *testing.T) { // tests sequential write with entire max size written in one go func TestSyncHasherCorrectness(t *testing.T) { data := testutil.RandomBytes(1, BufferSize) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 size := hasher().Size() var err error @@ -179,7 +179,7 @@ func TestSyncHasherCorrectness(t *testing.T) { // tests order-neutral concurrent writes with entire max size written in one go func TestAsyncCorrectness(t *testing.T) { data := testutil.RandomBytes(1, BufferSize) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 size := hasher().Size() whs := []whenHash{first, last, random} @@ -226,7 +226,7 @@ func TestHasherReuse(t *testing.T) { // tests if bmt reuse is not corrupting result func testHasherReuse(poolsize int, t *testing.T) { - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 pool := NewTreePool(hasher, segmentCount, poolsize) defer pool.Drain(0) bmt := New(pool) @@ -243,7 +243,7 @@ func testHasherReuse(poolsize int, t *testing.T) { // Tests if pool can be cleanly reused even in concurrent use by several hasher func TestBMTConcurrentUse(t *testing.T) { - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 pool := NewTreePool(hasher, segmentCount, PoolSize) defer pool.Drain(0) cycles := 100 @@ -277,7 +277,7 @@ LOOP: // Tests BMT Hasher io.Writer interface is working correctly // even multiple short random write buffers func TestBMTWriterBuffers(t *testing.T) { - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 for _, count := range counts { t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { @@ -410,7 +410,7 @@ func BenchmarkPool(t *testing.B) { // benchmarks simple sha3 hash on chunks func benchmarkSHA3(t *testing.B, n int) { data := testutil.RandomBytes(1, n) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 h := hasher() t.ReportAllocs() @@ -426,7 +426,7 @@ func benchmarkSHA3(t *testing.B, n int) { // the premise is that this is the minimum computation needed for a BMT // therefore this serves as a theoretical optimum for concurrent implementations func benchmarkBMTBaseline(t *testing.B, n int) { - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 hashSize := hasher().Size() data := testutil.RandomBytes(1, hashSize) @@ -453,7 +453,7 @@ func benchmarkBMTBaseline(t *testing.B, n int) { // benchmarks BMT Hasher func benchmarkBMT(t *testing.B, n int) { data := testutil.RandomBytes(1, n) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 pool := NewTreePool(hasher, segmentCount, PoolSize) bmt := New(pool) @@ -467,7 +467,7 @@ func benchmarkBMT(t *testing.B, n int) { // benchmarks BMT hasher with asynchronous concurrent segment/section writes func benchmarkBMTAsync(t *testing.B, n int, wh whenHash, double bool) { data := testutil.RandomBytes(1, n) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 pool := NewTreePool(hasher, segmentCount, PoolSize) bmt := New(pool).NewAsyncWriter(double) idxs, segments := splitAndShuffle(bmt.SectionSize(), data) @@ -485,7 +485,7 @@ func benchmarkBMTAsync(t *testing.B, n int, wh whenHash, double bool) { // benchmarks 100 concurrent bmt hashes with pool capacity func benchmarkPool(t *testing.B, poolsize, n int) { data := testutil.RandomBytes(1, n) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 pool := NewTreePool(hasher, segmentCount, poolsize) cycles := 100 @@ -508,7 +508,7 @@ func benchmarkPool(t *testing.B, poolsize, n int) { // benchmarks the reference hasher func benchmarkRefHasher(t *testing.B, n int) { data := testutil.RandomBytes(1, n) - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 rbmt := NewRefHasher(hasher, 128) t.ReportAllocs() diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/chunk/chunk.go b/vendor/github.com/ethereum/go-ethereum/swarm/chunk/chunk.go index 1449efcc..7540af8c 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/chunk/chunk.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/chunk/chunk.go @@ -1,5 +1,109 @@ package chunk -const ( - DefaultSize = 4096 +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" ) + +const ( + DefaultSize = 4096 + MaxPO = 16 + AddressLength = 32 +) + +var ( + ErrChunkNotFound = errors.New("chunk not found") + ErrChunkInvalid = errors.New("invalid chunk") +) + +type Chunk interface { + Address() Address + Data() []byte +} + +type chunk struct { + addr Address + sdata []byte +} + +func NewChunk(addr Address, data []byte) *chunk { + return &chunk{ + addr: addr, + sdata: data, + } +} + +func (c *chunk) Address() Address { + return c.addr +} + +func (c *chunk) Data() []byte { + return c.sdata +} + +func (self *chunk) String() string { + return fmt.Sprintf("Address: %v Chunksize: %v", self.addr.Log(), len(self.sdata)) +} + +type Address []byte + +var ZeroAddr = Address(common.Hash{}.Bytes()) + +func (a Address) Hex() string { + return fmt.Sprintf("%064x", []byte(a[:])) +} + +func (a Address) Log() string { + if len(a[:]) < 8 { + return fmt.Sprintf("%x", []byte(a[:])) + } + return fmt.Sprintf("%016x", []byte(a[:8])) +} + +func (a Address) String() string { + return fmt.Sprintf("%064x", []byte(a)) +} + +func (a Address) MarshalJSON() (out []byte, err error) { + return []byte(`"` + a.String() + `"`), nil +} + +func (a *Address) UnmarshalJSON(value []byte) error { + s := string(value) + *a = make([]byte, 32) + h := common.Hex2Bytes(s[1 : len(s)-1]) + copy(*a, h) + return nil +} + +// Proximity returns the proximity order of the MSB distance between x and y +// +// The distance metric MSB(x, y) of two equal length byte sequences x an y is the +// value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed. +// the binary cast is big endian: most significant bit first (=MSB). +// +// Proximity(x, y) is a discrete logarithmic scaling of the MSB distance. +// It is defined as the reverse rank of the integer part of the base 2 +// logarithm of the distance. +// It is calculated by counting the number of common leading zeros in the (MSB) +// binary representation of the x^y. +// +// (0 farthest, 255 closest, 256 self) +func Proximity(one, other []byte) (ret int) { + b := (MaxPO-1)/8 + 1 + if b > len(one) { + b = len(one) + } + m := 8 + for i := 0; i < b; i++ { + oxo := one[i] ^ other[i] + for j := 0; j < m; j++ { + if (oxo>>uint8(7-j))&0x01 != 0 { + return i*8 + j + } + } + } + return MaxPO +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/chunk/proximity_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/chunk/proximity_test.go new file mode 100644 index 00000000..5632114b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/chunk/proximity_test.go @@ -0,0 +1,186 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package chunk + +import ( + "strconv" + "testing" +) + +// TestProximity validates Proximity function with explicit +// values in a table-driven test. It is highly dependant on +// MaxPO constant and it validates cases up to MaxPO=32. +func TestProximity(t *testing.T) { + // integer from base2 encoded string + bx := func(s string) uint8 { + i, err := strconv.ParseUint(s, 2, 8) + if err != nil { + t.Fatal(err) + } + return uint8(i) + } + // adjust expected bins in respect to MaxPO + limitPO := func(po uint8) uint8 { + if po > MaxPO { + return MaxPO + } + return po + } + base := []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000000")} + for _, tc := range []struct { + addr []byte + po uint8 + }{ + { + addr: base, + po: MaxPO, + }, + { + addr: []byte{bx("10000000"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(0), + }, + { + addr: []byte{bx("01000000"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(1), + }, + { + addr: []byte{bx("00100000"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(2), + }, + { + addr: []byte{bx("00010000"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(3), + }, + { + addr: []byte{bx("00001000"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(4), + }, + { + addr: []byte{bx("00000100"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(5), + }, + { + addr: []byte{bx("00000010"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(6), + }, + { + addr: []byte{bx("00000001"), bx("00000000"), bx("00000000"), bx("00000000")}, + po: limitPO(7), + }, + { + addr: []byte{bx("00000000"), bx("10000000"), bx("00000000"), bx("00000000")}, + po: limitPO(8), + }, + { + addr: []byte{bx("00000000"), bx("01000000"), bx("00000000"), bx("00000000")}, + po: limitPO(9), + }, + { + addr: []byte{bx("00000000"), bx("00100000"), bx("00000000"), bx("00000000")}, + po: limitPO(10), + }, + { + addr: []byte{bx("00000000"), bx("00010000"), bx("00000000"), bx("00000000")}, + po: limitPO(11), + }, + { + addr: []byte{bx("00000000"), bx("00001000"), bx("00000000"), bx("00000000")}, + po: limitPO(12), + }, + { + addr: []byte{bx("00000000"), bx("00000100"), bx("00000000"), bx("00000000")}, + po: limitPO(13), + }, + { + addr: []byte{bx("00000000"), bx("00000010"), bx("00000000"), bx("00000000")}, + po: limitPO(14), + }, + { + addr: []byte{bx("00000000"), bx("00000001"), bx("00000000"), bx("00000000")}, + po: limitPO(15), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("10000000"), bx("00000000")}, + po: limitPO(16), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("01000000"), bx("00000000")}, + po: limitPO(17), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00100000"), bx("00000000")}, + po: limitPO(18), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00010000"), bx("00000000")}, + po: limitPO(19), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00001000"), bx("00000000")}, + po: limitPO(20), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000100"), bx("00000000")}, + po: limitPO(21), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000010"), bx("00000000")}, + po: limitPO(22), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000001"), bx("00000000")}, + po: limitPO(23), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("10000000")}, + po: limitPO(24), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("01000000")}, + po: limitPO(25), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00100000")}, + po: limitPO(26), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00010000")}, + po: limitPO(27), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00001000")}, + po: limitPO(28), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000100")}, + po: limitPO(29), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000010")}, + po: limitPO(30), + }, + { + addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000001")}, + po: limitPO(31), + }, + } { + got := uint8(Proximity(base, tc.addr)) + if got != tc.po { + t.Errorf("got %v bin, want %v", got, tc.po) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/docker/Dockerfile b/vendor/github.com/ethereum/go-ethereum/swarm/docker/Dockerfile new file mode 100644 index 00000000..9450609d --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/docker/Dockerfile @@ -0,0 +1,32 @@ +FROM golang:1.11-alpine as builder + +ARG VERSION + +RUN apk add --update git gcc g++ linux-headers +RUN mkdir -p $GOPATH/src/github.com/ethereum && \ + cd $GOPATH/src/github.com/ethereum && \ + git clone https://github.com/ethersphere/go-ethereum && \ + cd $GOPATH/src/github.com/ethereum/go-ethereum && \ + git checkout ${VERSION} && \ + go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm && \ + go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm/swarm-smoke && \ + go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm/global-store && \ + go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/geth + + +FROM alpine:3.8 as swarm-smoke +WORKDIR / +COPY --from=builder /go/bin/swarm-smoke / +ADD run-smoke.sh /run-smoke.sh +ENTRYPOINT ["/run-smoke.sh"] + +FROM alpine:3.8 as swarm-global-store +WORKDIR / +COPY --from=builder /go/bin/global-store / +ENTRYPOINT ["/global-store"] + +FROM alpine:3.8 as swarm +WORKDIR / +COPY --from=builder /go/bin/swarm /go/bin/geth / +ADD run.sh /run.sh +ENTRYPOINT ["/run.sh"] diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/docker/run-smoke.sh b/vendor/github.com/ethereum/go-ethereum/swarm/docker/run-smoke.sh new file mode 100755 index 00000000..ba57a7ec --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/docker/run-smoke.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -o errexit +set -o pipefail +set -o nounset + +/swarm-smoke $@ 2>&1 || true diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/docker/run.sh b/vendor/github.com/ethereum/go-ethereum/swarm/docker/run.sh new file mode 100755 index 00000000..3e613b56 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/docker/run.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +set -o errexit +set -o pipefail +set -o nounset + +PASSWORD=${PASSWORD:-} +DATADIR=${DATADIR:-/root/.ethereum/} + +if [ "$PASSWORD" == "" ]; then echo "Password must be set, in order to use swarm non-interactively." && exit 1; fi + +echo $PASSWORD > /password + +KEYFILE=`find $DATADIR | grep UTC | head -n 1` || true +if [ ! -f "$KEYFILE" ]; then echo "No keyfile found. Generating..." && /geth --datadir $DATADIR --password /password account new; fi +KEYFILE=`find $DATADIR | grep UTC | head -n 1` || true +if [ ! -f "$KEYFILE" ]; then echo "Could not find nor generate a BZZ keyfile." && exit 1; else echo "Found keyfile $KEYFILE"; fi + +VERSION=`/swarm version` +echo "Running Swarm:" +echo $VERSION + +export BZZACCOUNT="`echo -n $KEYFILE | tail -c 40`" || true +if [ "$BZZACCOUNT" == "" ]; then echo "Could not parse BZZACCOUNT from keyfile." && exit 1; fi + +exec /swarm --bzzaccount=$BZZACCOUNT --password /password --datadir $DATADIR $@ 2>&1 diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs.go b/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs.go index c7aa983b..db6aefb5 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs.go @@ -24,10 +24,10 @@ import ( ) const ( - Swarmfs_Version = "0.1" - mountTimeout = time.Second * 5 - unmountTimeout = time.Second * 10 - maxFuseMounts = 5 + SwarmFSVersion = "0.1" + mountTimeout = time.Second * 5 + unmountTimeout = time.Second * 10 + maxFUSEMounts = 5 ) var ( diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs_unix.go b/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs_unix.go index 9ff55cc3..54b879a4 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs_unix.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/fuse/swarmfs_unix.go @@ -96,7 +96,7 @@ func (swarmfs *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { noOfActiveMounts := len(swarmfs.activeMounts) log.Debug("swarmfs mount", "# active mounts", noOfActiveMounts) - if noOfActiveMounts >= maxFuseMounts { + if noOfActiveMounts >= maxFUSEMounts { return nil, errMaxMountCount } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/grafana_dashboards/ldbstore.json b/vendor/github.com/ethereum/go-ethereum/swarm/grafana_dashboards/ldbstore.json deleted file mode 100644 index 2d64380b..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/grafana_dashboards/ldbstore.json +++ /dev/null @@ -1,2278 +0,0 @@ -{ - "annotations": { - "list": [ - { - "$$hashKey": "object:325", - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 1, - "id": 5, - "iteration": 1527598894689, - "links": [], - "panels": [ - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 40, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 42, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.cachehit.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get cachehit", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 43, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.cachemiss.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get cachemiss", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 7 - }, - "id": 44, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Total LocalStore.GetOrCreateRequest", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 7 - }, - "id": 47, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.errfetching.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore GetOrCreateRequest ErrFetching", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 13 - }, - "id": 45, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.hit.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore.GetOrCreateRequest hit", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 13 - }, - "id": 49, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.miss.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore GetOrCreateRequest miss", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 19 - }, - "id": 48, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.error.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get error", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 19 - }, - "id": 46, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.errfetching.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get ErrFetching", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "title": "LocalStore", - "type": "row" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 1 - }, - "id": 27, - "panels": [], - "title": "LDBStore", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 2 - }, - "id": 29, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.get.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore get", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 2 - }, - "id": 30, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.put.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore put", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 8 - }, - "id": 31, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.synciterator.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore SyncIterator", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 8 - }, - "id": 32, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.synciterator.seek.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore SyncIterator Seek/Next", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 14 - }, - "id": 50, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.collectgarbage.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore Collect Garbage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 14 - }, - "id": 51, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.collectgarbage.delete.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore Collect Garbage - Actual Deletes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 20 - }, - "id": 34, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 39 - }, - "id": 36, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbdatabase.get.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBDatabase get", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 39 - }, - "id": 37, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbdatabase.write.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBDatabase write", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 45 - }, - "id": 38, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbdatabase.newiterator.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBDatabase NewIterator", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "title": "LDBDatabase", - "type": "row" - } - ], - "refresh": "10s", - "schemaVersion": 16, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "auto": false, - "auto_count": 30, - "auto_min": "10s", - "current": { - "text": "10s", - "value": "10s" - }, - "hide": 0, - "label": "resolution", - "name": "myinterval", - "options": [ - { - "selected": false, - "text": "5s", - "value": "5s" - }, - { - "selected": true, - "text": "10s", - "value": "10s" - }, - { - "selected": false, - "text": "30s", - "value": "30s" - }, - { - "selected": false, - "text": "100s", - "value": "100s" - } - ], - "query": "5s,10s,30s,100s", - "refresh": 2, - "type": "interval" - }, - { - "allValue": null, - "current": { - "text": "swarm_30399 + swarm_30400 + swarm_30401", - "value": [ - "swarm_30399", - "swarm_30400", - "swarm_30401" - ] - }, - "datasource": "metrics", - "hide": 0, - "includeAll": true, - "label": null, - "multi": true, - "name": "host", - "options": [], - "query": "SHOW TAG VALUES WITH KEY = \"host\"", - "refresh": 1, - "regex": "", - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "swarm.http.request.GET.time.span", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-15m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "LDBStore and LDBDatabase", - "uid": "zS6beG7iz", - "version": 28 -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/grafana_dashboards/swarm.json b/vendor/github.com/ethereum/go-ethereum/swarm/grafana_dashboards/swarm.json deleted file mode 100644 index 3ee244d1..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/grafana_dashboards/swarm.json +++ /dev/null @@ -1,3198 +0,0 @@ -{ - "annotations": { - "list": [ - { - "$$hashKey": "object:147", - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 1, - "id": 2, - "iteration": 1527598859072, - "links": [], - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 34, - "panels": [], - "title": "P2P", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 36, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.send.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "P2P Send() - messages sent", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 9, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 37, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "p95($tag_host)", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.send_t.span", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "p95" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "P2P Send() timer - 95%ile", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 10 - }, - "id": 38, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "1 $tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.sendpriority.1.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [] - }, - { - "alias": "2 $tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.sendpriority.2.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [] - }, - { - "alias": "3 $tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.sendpriority.3.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "P2P SendPriority() - messages sent", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 9, - "w": 12, - "x": 12, - "y": 10 - }, - "id": 39, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "1 $tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.sendpriority_t.1.span", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "p95" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "2 $tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.sendpriority_t.2.span", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "p95" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "P2P SendPriority() timer - 95%ile", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 19 - }, - "id": 40, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "measurement": "swarm.registry.peers.gauge", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "last" - } - ] - ], - "tags": [] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Registry Peers", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 28 - }, - "id": 32, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 2 - }, - "id": 14, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.stack.uptime.gauge", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Uptime", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "title": "Uptime", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 29 - }, - "id": 28, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 7 - }, - "id": 2, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "GET", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "swarm.http.request.GET.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - }, - { - "alias": "POST", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "swarm.http.request.POST.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Total HTTP Requests", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 7 - }, - "id": 26, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.http.request.GET.time.span", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "p95" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "HTTP GET requests 95% timer", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 13 - }, - "id": 15, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.http.request.GET.time.span", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "p50" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "HTTP GET requests 50% timer", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 13 - }, - "id": 8, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "POST", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.http.request.POST.time.span", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "p95" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "HTTP POST requests 95% timer", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "title": "HTTP", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 30 - }, - "id": 30, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 5, - "w": 12, - "x": 0, - "y": 8 - }, - "id": 16, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.lazychunkreader.read.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LazyChunkReader read() calls", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 8 - }, - "id": 18, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.lazychunkreader.read.err.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LazyChunkReader read errors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 5, - "w": 12, - "x": 0, - "y": 13 - }, - "id": 17, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.lazychunkreader.read.bytes.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LazyChunkReader bytes read", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "title": "LazyChunkReader", - "type": "row" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 31 - }, - "id": 25, - "panels": [], - "title": "All measurements", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 32 - }, - "id": 3, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.api.get.count.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "API Get (BZZ)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 32 - }, - "id": 13, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.network.stream.request_from_peers.count.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Request from peers", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 38 - }, - "id": 11, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.network.stream.received_chunks.count.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Received chunks", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 38 - }, - "id": 12, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.storage.cache.requests.size.gauge", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "max" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Requests cache entries", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 44 - }, - "id": 9, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.network.stream.handle_retrieve_request_msg.count.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Handle retrieve request msg", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 44 - }, - "id": 20, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.syncer.setnextbatch.iterator.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "syncer setnextbatch iterator calls", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 50 - }, - "id": 21, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.handlewantedhashesmsg.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "peer HandleWantedHashesMsg", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 50 - }, - "id": 22, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.handlesubscribemsg.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "peer HandleSubscribeMsg", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 56 - }, - "id": 23, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.handlewantedhashesmsg.actualget.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "peer HandleWantedHashesMsg actual get", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 56 - }, - "id": 19, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.peer.handleofferedhashes.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "peer OfferedHashesMsg", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "refresh": "30s", - "schemaVersion": 16, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "auto": false, - "auto_count": 30, - "auto_min": "10s", - "current": { - "text": "10s", - "value": "10s" - }, - "hide": 0, - "label": "resolution", - "name": "myinterval", - "options": [ - { - "selected": false, - "text": "5s", - "value": "5s" - }, - { - "selected": true, - "text": "10s", - "value": "10s" - }, - { - "selected": false, - "text": "30s", - "value": "30s" - }, - { - "selected": false, - "text": "100s", - "value": "100s" - } - ], - "query": "5s,10s,30s,100s", - "refresh": 2, - "type": "interval" - }, - { - "allValue": null, - "current": { - "text": "swarm_30399 + swarm_30400 + swarm_30401 + swarm_30402", - "value": [ - "swarm_30399", - "swarm_30400", - "swarm_30401", - "swarm_30402" - ] - }, - "datasource": "metrics", - "hide": 0, - "includeAll": true, - "label": null, - "multi": true, - "name": "host", - "options": [], - "query": "SHOW TAG VALUES WITH KEY = \"host\"", - "refresh": 1, - "regex": "", - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "swarm.http.request.GET.time.span", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-15m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "Swarm", - "uid": "vmEtxxgmz", - "version": 138 -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/metrics/flags.go b/vendor/github.com/ethereum/go-ethereum/swarm/metrics/flags.go index 79490fd3..d348dc3e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/metrics/flags.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/metrics/flags.go @@ -23,72 +23,86 @@ import ( gethmetrics "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics/influxdb" "github.com/ethereum/go-ethereum/swarm/log" - "gopkg.in/urfave/cli.v1" + cli "gopkg.in/urfave/cli.v1" ) var ( - metricsEnableInfluxDBExportFlag = cli.BoolFlag{ + MetricsEnableInfluxDBExportFlag = cli.BoolFlag{ Name: "metrics.influxdb.export", Usage: "Enable metrics export/push to an external InfluxDB database", } - metricsInfluxDBEndpointFlag = cli.StringFlag{ + MetricsEnableInfluxDBAccountingExportFlag = cli.BoolFlag{ + Name: "metrics.influxdb.accounting", + Usage: "Enable accounting metrics export/push to an external InfluxDB database", + } + MetricsInfluxDBEndpointFlag = cli.StringFlag{ Name: "metrics.influxdb.endpoint", Usage: "Metrics InfluxDB endpoint", Value: "http://127.0.0.1:8086", } - metricsInfluxDBDatabaseFlag = cli.StringFlag{ + MetricsInfluxDBDatabaseFlag = cli.StringFlag{ Name: "metrics.influxdb.database", Usage: "Metrics InfluxDB database", Value: "metrics", } - metricsInfluxDBUsernameFlag = cli.StringFlag{ + MetricsInfluxDBUsernameFlag = cli.StringFlag{ Name: "metrics.influxdb.username", Usage: "Metrics InfluxDB username", Value: "", } - metricsInfluxDBPasswordFlag = cli.StringFlag{ + MetricsInfluxDBPasswordFlag = cli.StringFlag{ Name: "metrics.influxdb.password", Usage: "Metrics InfluxDB password", Value: "", } - // The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. - // It is used so that we can group all nodes and average a measurement across all of them, but also so - // that we can select a specific node and inspect its measurements. + // Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. + // For example `host` tag could be used so that we can group all nodes and average a measurement + // across all of them, but also so that we can select a specific node and inspect its measurements. // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key - metricsInfluxDBHostTagFlag = cli.StringFlag{ - Name: "metrics.influxdb.host.tag", - Usage: "Metrics InfluxDB `host` tag attached to all measurements", - Value: "localhost", + MetricsInfluxDBTagsFlag = cli.StringFlag{ + Name: "metrics.influxdb.tags", + Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", + Value: "host=localhost", } ) // Flags holds all command-line flags required for metrics collection. var Flags = []cli.Flag{ utils.MetricsEnabledFlag, - metricsEnableInfluxDBExportFlag, - metricsInfluxDBEndpointFlag, metricsInfluxDBDatabaseFlag, metricsInfluxDBUsernameFlag, metricsInfluxDBPasswordFlag, metricsInfluxDBHostTagFlag, + MetricsEnableInfluxDBExportFlag, + MetricsEnableInfluxDBAccountingExportFlag, + MetricsInfluxDBEndpointFlag, + MetricsInfluxDBDatabaseFlag, + MetricsInfluxDBUsernameFlag, + MetricsInfluxDBPasswordFlag, + MetricsInfluxDBTagsFlag, } func Setup(ctx *cli.Context) { if gethmetrics.Enabled { log.Info("Enabling swarm metrics collection") var ( - enableExport = ctx.GlobalBool(metricsEnableInfluxDBExportFlag.Name) - endpoint = ctx.GlobalString(metricsInfluxDBEndpointFlag.Name) - database = ctx.GlobalString(metricsInfluxDBDatabaseFlag.Name) - username = ctx.GlobalString(metricsInfluxDBUsernameFlag.Name) - password = ctx.GlobalString(metricsInfluxDBPasswordFlag.Name) - hosttag = ctx.GlobalString(metricsInfluxDBHostTagFlag.Name) + endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) + database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) + username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) + password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) + enableExport = ctx.GlobalBool(MetricsEnableInfluxDBExportFlag.Name) + enableAccountingExport = ctx.GlobalBool(MetricsEnableInfluxDBAccountingExportFlag.Name) ) // Start system runtime metrics collection go gethmetrics.CollectProcessMetrics(2 * time.Second) + tagsMap := utils.SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) + if enableExport { log.Info("Enabling swarm metrics export to InfluxDB") - go influxdb.InfluxDBWithTags(gethmetrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "swarm.", map[string]string{ - "host": hosttag, - }) + go influxdb.InfluxDBWithTags(gethmetrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "swarm.", tagsMap) + } + + if enableAccountingExport { + log.Info("Exporting swarm accounting metrics to InfluxDB") + go influxdb.InfluxDBWithTags(gethmetrics.AccountingRegistry, 10*time.Second, endpoint, database, username, password, "accounting.", tagsMap) } } } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/multihash/multihash.go b/vendor/github.com/ethereum/go-ethereum/swarm/multihash/multihash.go deleted file mode 100644 index 3306e3a6..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/multihash/multihash.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package multihash - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" -) - -const ( - defaultMultihashLength = 32 - defaultMultihashTypeCode = 0x1b -) - -var ( - multihashTypeCode uint8 - MultihashLength = defaultMultihashLength -) - -func init() { - multihashTypeCode = defaultMultihashTypeCode - MultihashLength = defaultMultihashLength -} - -// check if valid swarm multihash -func isSwarmMultihashType(code uint8) bool { - return code == multihashTypeCode -} - -// GetMultihashLength returns the digest length of the provided multihash -// It will fail if the multihash is not a valid swarm mulithash -func GetMultihashLength(data []byte) (int, int, error) { - cursor := 0 - typ, c := binary.Uvarint(data) - if c <= 0 { - return 0, 0, errors.New("unreadable hashtype field") - } - if !isSwarmMultihashType(uint8(typ)) { - return 0, 0, fmt.Errorf("hash code %x is not a swarm hashtype", typ) - } - cursor += c - hashlength, c := binary.Uvarint(data[cursor:]) - if c <= 0 { - return 0, 0, errors.New("unreadable length field") - } - cursor += c - - // we cheekily assume hashlength < maxint - inthashlength := int(hashlength) - if len(data[c:]) < inthashlength { - return 0, 0, errors.New("length mismatch") - } - return inthashlength, cursor, nil -} - -// FromMulithash returns the digest portion of the multihash -// It will fail if the multihash is not a valid swarm multihash -func FromMultihash(data []byte) ([]byte, error) { - hashLength, _, err := GetMultihashLength(data) - if err != nil { - return nil, err - } - return data[len(data)-hashLength:], nil -} - -// ToMulithash wraps the provided digest data with a swarm mulithash header -func ToMultihash(hashData []byte) []byte { - buf := bytes.NewBuffer(nil) - b := make([]byte, 8) - c := binary.PutUvarint(b, uint64(multihashTypeCode)) - buf.Write(b[:c]) - c = binary.PutUvarint(b, uint64(len(hashData))) - buf.Write(b[:c]) - buf.Write(hashData) - return buf.Bytes() -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/multihash/multihash_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/multihash/multihash_test.go deleted file mode 100644 index 85df741d..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/multihash/multihash_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package multihash - -import ( - "bytes" - "math/rand" - "testing" -) - -// parse multihash, and check that invalid multihashes fail -func TestCheckMultihash(t *testing.T) { - hashbytes := make([]byte, 32) - c, err := rand.Read(hashbytes) - if err != nil { - t.Fatal(err) - } else if c < 32 { - t.Fatal("short read") - } - - expected := ToMultihash(hashbytes) - - l, hl, _ := GetMultihashLength(expected) - if l != 32 { - t.Fatalf("expected length %d, got %d", 32, l) - } else if hl != 2 { - t.Fatalf("expected header length %d, got %d", 2, hl) - } - if _, _, err := GetMultihashLength(expected[1:]); err == nil { - t.Fatal("expected failure on corrupt header") - } - if _, _, err := GetMultihashLength(expected[:len(expected)-2]); err == nil { - t.Fatal("expected failure on short content") - } - dh, _ := FromMultihash(expected) - if !bytes.Equal(dh, hashbytes) { - t.Fatalf("expected content hash %x, got %x", hashbytes, dh) - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/bitvector/bitvector.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/bitvector/bitvector.go index edc7c50c..95832850 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/bitvector/bitvector.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/bitvector/bitvector.go @@ -60,7 +60,3 @@ func (bv *BitVector) Set(i int, v bool) { func (bv *BitVector) Bytes() []byte { return bv.b } - -func (bv *BitVector) Length() int { - return bv.len -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery.go index 21703e70..4c503047 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery.go @@ -65,7 +65,7 @@ func (d *Peer) HandleMsg(ctx context.Context, msg interface{}) error { // NotifyDepth sends a message to all connections if depth of saturation is changed func NotifyDepth(depth uint8, kad *Kademlia) { - f := func(val *Peer, po int, _ bool) bool { + f := func(val *Peer, po int) bool { val.NotifyDepth(depth) return true } @@ -74,7 +74,7 @@ func NotifyDepth(depth uint8, kad *Kademlia) { // NotifyPeer informs all peers about a newly added node func NotifyPeer(p *BzzAddr, k *Kademlia) { - f := func(val *Peer, po int, _ bool) bool { + f := func(val *Peer, po int) bool { val.NotifyPeer(p, uint8(po)) return true } @@ -160,8 +160,8 @@ func (d *Peer) handleSubPeersMsg(msg *subPeersMsg) error { if !d.sentPeers { d.setDepth(msg.Depth) var peers []*BzzAddr - d.kad.EachConn(d.Over(), 255, func(p *Peer, po int, isproxbin bool) bool { - if pob, _ := pof(d, d.kad.BaseAddr(), 0); pob > po { + d.kad.EachConn(d.Over(), 255, func(p *Peer, po int) bool { + if pob, _ := Pof(d, d.kad.BaseAddr(), 0); pob > po { return false } if !d.seen(p.BzzAddr) { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery_test.go index dd3299c0..ea0d776e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/discovery_test.go @@ -29,7 +29,10 @@ import ( */ func TestDiscovery(t *testing.T) { params := NewHiveParams() - s, pp := newHiveTester(t, params, 1, nil) + s, pp, err := newHiveTester(t, params, 1, nil) + if err != nil { + t.Fatal(err) + } node := s.Nodes[0] raddr := NewAddr(node) @@ -40,7 +43,7 @@ func TestDiscovery(t *testing.T) { defer pp.Stop() // send subPeersMsg to the peer - err := s.TestExchanges(p2ptest.Exchange{ + err = s.TestExchanges(p2ptest.Exchange{ Label: "outgoing subPeersMsg", Expects: []p2ptest.Expect{ { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/enr.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/enr.go new file mode 100644 index 00000000..6d7fa2ae --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/enr.go @@ -0,0 +1,93 @@ +package network + +import ( + "fmt" + "io" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/swarm/log" +) + +// ENRAddrEntry is the entry type to store the bzz key in the enode +type ENRAddrEntry struct { + data []byte +} + +func NewENRAddrEntry(addr []byte) *ENRAddrEntry { + return &ENRAddrEntry{ + data: addr, + } +} + +func (b ENRAddrEntry) Address() []byte { + return b.data +} + +// ENRKey implements enr.Entry +func (b ENRAddrEntry) ENRKey() string { + return "bzzkey" +} + +// EncodeRLP implements rlp.Encoder +func (b ENRAddrEntry) EncodeRLP(w io.Writer) error { + log.Debug("in encoderlp", "b", b, "p", fmt.Sprintf("%p", &b)) + return rlp.Encode(w, &b.data) +} + +// DecodeRLP implements rlp.Decoder +func (b *ENRAddrEntry) DecodeRLP(s *rlp.Stream) error { + byt, err := s.Bytes() + if err != nil { + return err + } + b.data = byt + log.Debug("in decoderlp", "b", b, "p", fmt.Sprintf("%p", &b)) + return nil +} + +type ENRLightNodeEntry bool + +func (b ENRLightNodeEntry) ENRKey() string { + return "bzzlightnode" +} + +type ENRBootNodeEntry bool + +func (b ENRBootNodeEntry) ENRKey() string { + return "bzzbootnode" +} + +func getENRBzzPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *protocols.Spec) *BzzPeer { + var lightnode ENRLightNodeEntry + var bootnode ENRBootNodeEntry + + // retrieve the ENR Record data + record := p.Node().Record() + record.Load(&lightnode) + record.Load(&bootnode) + + // get the address; separate function as long as we need swarm/network:NewAddr() to call it + addr := getENRBzzAddr(p.Node()) + + // build the peer using the retrieved data + return &BzzPeer{ + Peer: protocols.NewPeer(p, rw, spec), + LightNode: bool(lightnode), + BzzAddr: addr, + } +} + +func getENRBzzAddr(nod *enode.Node) *BzzAddr { + var addr ENRAddrEntry + + record := nod.Record() + record.Load(&addr) + + return &BzzAddr{ + OAddr: addr.data, + UAddr: []byte(nod.String()), + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher.go index 6aed57e2..5c0dfefc 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher.go @@ -18,28 +18,34 @@ package network import ( "context" + "fmt" "sync" "time" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/tracing" + olog "github.com/opentracing/opentracing-go/log" ) -var searchTimeout = 1 * time.Second +const ( + defaultSearchTimeout = 1 * time.Second + // maximum number of forwarded requests (hops), to make sure requests are not + // forwarded forever in peer loops + maxHopCount uint8 = 20 +) // Time to consider peer to be skipped. // Also used in stream delivery. var RequestTimeout = 10 * time.Second -var maxHopCount uint8 = 20 // maximum number of forwarded requests (hops), to make sure requests are not forwarded forever in peer loops - type RequestFunc func(context.Context, *Request) (*enode.ID, chan struct{}, error) // Fetcher is created when a chunk is not found locally. It starts a request handler loop once and // keeps it alive until all active requests are completed. This can happen: // 1. either because the chunk is delivered -// 2. or becuse the requestor cancelled/timed out +// 2. or because the requester cancelled/timed out // Fetcher self destroys itself after it is completed. // TODO: cancel all forward requests after termination type Fetcher struct { @@ -47,7 +53,9 @@ type Fetcher struct { addr storage.Address // the address of the chunk to be fetched offerC chan *enode.ID // channel of sources (peer node id strings) requestC chan uint8 // channel for incoming requests (with the hopCount value in it) + searchTimeout time.Duration skipCheck bool + ctx context.Context } type Request struct { @@ -79,7 +87,7 @@ func (r *Request) SkipPeer(nodeID string) bool { } t, ok := val.(time.Time) if ok && time.Now().After(t.Add(RequestTimeout)) { - // deadine expired + // deadline expired r.peersToSkip.Delete(nodeID) return false } @@ -100,32 +108,35 @@ func NewFetcherFactory(request RequestFunc, skipCheck bool) *FetcherFactory { } } -// New contructs a new Fetcher, for the given chunk. All peers in peersToSkip are not requested to -// deliver the given chunk. peersToSkip should always contain the peers which are actively requesting -// this chunk, to make sure we don't request back the chunks from them. +// New constructs a new Fetcher, for the given chunk. All peers in peersToSkip +// are not requested to deliver the given chunk. peersToSkip should always +// contain the peers which are actively requesting this chunk, to make sure we +// don't request back the chunks from them. // The created Fetcher is started and returned. -func (f *FetcherFactory) New(ctx context.Context, source storage.Address, peersToSkip *sync.Map) storage.NetFetcher { - fetcher := NewFetcher(source, f.request, f.skipCheck) - go fetcher.run(ctx, peersToSkip) +func (f *FetcherFactory) New(ctx context.Context, source storage.Address, peers *sync.Map) storage.NetFetcher { + fetcher := NewFetcher(ctx, source, f.request, f.skipCheck) + go fetcher.run(peers) return fetcher } // NewFetcher creates a new Fetcher for the given chunk address using the given request function. -func NewFetcher(addr storage.Address, rf RequestFunc, skipCheck bool) *Fetcher { +func NewFetcher(ctx context.Context, addr storage.Address, rf RequestFunc, skipCheck bool) *Fetcher { return &Fetcher{ addr: addr, protoRequestFunc: rf, offerC: make(chan *enode.ID), requestC: make(chan uint8), + searchTimeout: defaultSearchTimeout, skipCheck: skipCheck, + ctx: ctx, } } // Offer is called when an upstream peer offers the chunk via syncing as part of `OfferedHashesMsg` and the node does not have the chunk locally. -func (f *Fetcher) Offer(ctx context.Context, source *enode.ID) { +func (f *Fetcher) Offer(source *enode.ID) { // First we need to have this select to make sure that we return if context is done select { - case <-ctx.Done(): + case <-f.ctx.Done(): return default: } @@ -134,15 +145,15 @@ func (f *Fetcher) Offer(ctx context.Context, source *enode.ID) { // push to offerC instead if offerC is available (see number 2 in https://golang.org/ref/spec#Select_statements) select { case f.offerC <- source: - case <-ctx.Done(): + case <-f.ctx.Done(): } } // Request is called when an upstream peer request the chunk as part of `RetrieveRequestMsg`, or from a local request through FileStore, and the node does not have the chunk locally. -func (f *Fetcher) Request(ctx context.Context, hopCount uint8) { +func (f *Fetcher) Request(hopCount uint8) { // First we need to have this select to make sure that we return if context is done select { - case <-ctx.Done(): + case <-f.ctx.Done(): return default: } @@ -156,13 +167,13 @@ func (f *Fetcher) Request(ctx context.Context, hopCount uint8) { // push to offerC instead if offerC is available (see number 2 in https://golang.org/ref/spec#Select_statements) select { case f.requestC <- hopCount + 1: - case <-ctx.Done(): + case <-f.ctx.Done(): } } // start prepares the Fetcher // it keeps the Fetcher alive within the lifecycle of the passed context -func (f *Fetcher) run(ctx context.Context, peers *sync.Map) { +func (f *Fetcher) run(peers *sync.Map) { var ( doRequest bool // determines if retrieval is initiated in the current iteration wait *time.Timer // timer for search timeout @@ -176,7 +187,7 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) { // loop that keeps the fetching process alive // after every request a timer is set. If this goes off we request again from another peer // note that the previous request is still alive and has the chance to deliver, so - // rerequesting extends the search. ie., + // requesting again extends the search. ie., // if a peer we requested from is gone we issue a new request, so the number of active // requests never decreases for { @@ -193,36 +204,36 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) { // incoming request case hopCount = <-f.requestC: - log.Trace("new request", "request addr", f.addr) // 2) chunk is requested, set requested flag // launch a request iff none been launched yet doRequest = !requested + log.Trace("new request", "request addr", f.addr, "doRequest", doRequest) requested = true // peer we requested from is gone. fall back to another // and remove the peer from the peers map case id := <-gone: - log.Trace("peer gone", "peer id", id.String(), "request addr", f.addr) peers.Delete(id.String()) doRequest = requested + log.Trace("peer gone", "peer id", id.String(), "request addr", f.addr, "doRequest", doRequest) // search timeout: too much time passed since the last request, // extend the search to a new peer if we can find one case <-waitC: - log.Trace("search timed out: rerequesting", "request addr", f.addr) doRequest = requested + log.Trace("search timed out: requesting", "request addr", f.addr, "doRequest", doRequest) // all Fetcher context closed, can quit - case <-ctx.Done(): + case <-f.ctx.Done(): log.Trace("terminate fetcher", "request addr", f.addr) - // TODO: send cancelations to all peers left over in peers map (i.e., those we requested from) + // TODO: send cancellations to all peers left over in peers map (i.e., those we requested from) return } // need to issue a new request if doRequest { var err error - sources, err = f.doRequest(ctx, gone, peers, sources, hopCount) + sources, err = f.doRequest(gone, peers, sources, hopCount) if err != nil { log.Info("unable to request", "request addr", f.addr, "err", err) } @@ -231,7 +242,7 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) { // if wait channel is not set, set it to a timer if requested { if wait == nil { - wait = time.NewTimer(searchTimeout) + wait = time.NewTimer(f.searchTimeout) defer wait.Stop() waitC = wait.C } else { @@ -242,8 +253,8 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) { default: } } - // reset the timer to go off after searchTimeout - wait.Reset(searchTimeout) + // reset the timer to go off after defaultSearchTimeout + wait.Reset(f.searchTimeout) } } doRequest = false @@ -260,7 +271,7 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) { // * the peer's address is added to the set of peers to skip // * the peer's address is removed from prospective sources, and // * a go routine is started that reports on the gone channel if the peer is disconnected (or terminated their streamer) -func (f *Fetcher) doRequest(ctx context.Context, gone chan *enode.ID, peersToSkip *sync.Map, sources []*enode.ID, hopCount uint8) ([]*enode.ID, error) { +func (f *Fetcher) doRequest(gone chan *enode.ID, peersToSkip *sync.Map, sources []*enode.ID, hopCount uint8) ([]*enode.ID, error) { var i int var sourceID *enode.ID var quit chan struct{} @@ -277,7 +288,8 @@ func (f *Fetcher) doRequest(ctx context.Context, gone chan *enode.ID, peersToSki for i = 0; i < len(sources); i++ { req.Source = sources[i] var err error - sourceID, quit, err = f.protoRequestFunc(ctx, req) + log.Trace("fetcher.doRequest", "request addr", f.addr, "peer", req.Source.String()) + sourceID, quit, err = f.protoRequestFunc(f.ctx, req) if err == nil { // remove the peer from known sources // Note: we can modify the source although we are looping on it, because we break from the loop immediately @@ -291,7 +303,7 @@ func (f *Fetcher) doRequest(ctx context.Context, gone chan *enode.ID, peersToSki if !foundSource { req.Source = nil var err error - sourceID, quit, err = f.protoRequestFunc(ctx, req) + sourceID, quit, err = f.protoRequestFunc(f.ctx, req) if err != nil { // if no peers found to request from return sources, err @@ -308,7 +320,16 @@ func (f *Fetcher) doRequest(ctx context.Context, gone chan *enode.ID, peersToSki select { case <-quit: gone <- sourceID - case <-ctx.Done(): + case <-f.ctx.Done(): + } + + // finish the request span + spanId := fmt.Sprintf("stream.send.request.%v.%v", *sourceID, req.Addr) + span := tracing.ShiftSpanByKey(spanId) + + if span != nil { + span.LogFields(olog.String("finish", "from doRequest")) + span.Finish() } }() return sources, nil diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher_test.go index 3a926f47..4e464f10 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/fetcher_test.go @@ -69,7 +69,11 @@ func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode func TestFetcherSingleRequest(t *testing.T) { requester := newMockRequester() addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) peers := []string{"a", "b", "c", "d"} peersToSkip := &sync.Map{} @@ -77,13 +81,9 @@ func TestFetcherSingleRequest(t *testing.T) { peersToSkip.Store(p, time.Now()) } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + go fetcher.run(peersToSkip) - go fetcher.run(ctx, peersToSkip) - - rctx := context.Background() - fetcher.Request(rctx, 0) + fetcher.Request(0) select { case request := <-requester.requestC: @@ -115,20 +115,19 @@ func TestFetcherSingleRequest(t *testing.T) { func TestFetcherCancelStopsFetcher(t *testing.T) { requester := newMockRequester() addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} ctx, cancel := context.WithCancel(context.Background()) + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + // we start the fetcher, and then we immediately cancel the context - go fetcher.run(ctx, peersToSkip) + go fetcher.run(peersToSkip) cancel() - rctx, rcancel := context.WithTimeout(ctx, 100*time.Millisecond) - defer rcancel() // we call Request with an active context - fetcher.Request(rctx, 0) + fetcher.Request(0) // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening select { @@ -140,23 +139,23 @@ func TestFetcherCancelStopsFetcher(t *testing.T) { // TestFetchCancelStopsRequest tests that calling a Request function with a cancelled context does not initiate a request func TestFetcherCancelStopsRequest(t *testing.T) { + t.Skip("since context is now per fetcher, this test is likely redundant") + requester := newMockRequester(100 * time.Millisecond) addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // we start the fetcher with an active context - go fetcher.run(ctx, peersToSkip) + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - rctx, rcancel := context.WithCancel(context.Background()) - rcancel() + peersToSkip := &sync.Map{} + + // we start the fetcher with an active context + go fetcher.run(peersToSkip) // we call Request with a cancelled context - fetcher.Request(rctx, 0) + fetcher.Request(0) // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening select { @@ -166,8 +165,7 @@ func TestFetcherCancelStopsRequest(t *testing.T) { } // if there is another Request with active context, there should be a request, because the fetcher itself is not cancelled - rctx = context.Background() - fetcher.Request(rctx, 0) + fetcher.Request(0) select { case <-requester.requestC: @@ -182,19 +180,19 @@ func TestFetcherCancelStopsRequest(t *testing.T) { func TestFetcherOfferUsesSource(t *testing.T) { requester := newMockRequester(100 * time.Millisecond) addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // start the fetcher - go fetcher.run(ctx, peersToSkip) + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + + // start the fetcher + go fetcher.run(peersToSkip) - rctx := context.Background() // call the Offer function with the source peer - fetcher.Offer(rctx, &sourcePeerID) + fetcher.Offer(&sourcePeerID) // fetcher should not initiate request select { @@ -204,8 +202,7 @@ func TestFetcherOfferUsesSource(t *testing.T) { } // call Request after the Offer - rctx = context.Background() - fetcher.Request(rctx, 0) + fetcher.Request(0) // there should be exactly 1 request coming from fetcher var request *Request @@ -234,19 +231,19 @@ func TestFetcherOfferUsesSource(t *testing.T) { func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { requester := newMockRequester(100 * time.Millisecond) addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} ctx, cancel := context.WithCancel(context.Background()) defer cancel() + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + // start the fetcher - go fetcher.run(ctx, peersToSkip) + go fetcher.run(peersToSkip) // call Request first - rctx := context.Background() - fetcher.Request(rctx, 0) + fetcher.Request(0) // there should be a request coming from fetcher var request *Request @@ -260,7 +257,7 @@ func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { } // after the Request call Offer - fetcher.Offer(context.Background(), &sourcePeerID) + fetcher.Offer(&sourcePeerID) // there should be a request coming from fetcher select { @@ -283,25 +280,21 @@ func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { func TestFetcherRetryOnTimeout(t *testing.T) { requester := newMockRequester() addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} - - // set searchTimeOut to low value so the test is quicker - defer func(t time.Duration) { - searchTimeout = t - }(searchTimeout) - searchTimeout = 250 * time.Millisecond ctx, cancel := context.WithCancel(context.Background()) defer cancel() + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + // set searchTimeOut to low value so the test is quicker + fetcher.searchTimeout = 250 * time.Millisecond + + peersToSkip := &sync.Map{} + // start the fetcher - go fetcher.run(ctx, peersToSkip) + go fetcher.run(peersToSkip) // call the fetch function with an active context - rctx := context.Background() - fetcher.Request(rctx, 0) + fetcher.Request(0) // after 100ms the first request should be initiated time.Sleep(100 * time.Millisecond) @@ -343,7 +336,7 @@ func TestFetcherFactory(t *testing.T) { fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) - fetcher.Request(context.Background(), 0) + fetcher.Request(0) // check if the created fetchFunction really starts a fetcher and initiates a request select { @@ -357,23 +350,21 @@ func TestFetcherFactory(t *testing.T) { func TestFetcherRequestQuitRetriesRequest(t *testing.T) { requester := newMockRequester() addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) - - // make sure searchTimeout is long so it is sure the request is not retried because of timeout - defer func(t time.Duration) { - searchTimeout = t - }(searchTimeout) - searchTimeout = 10 * time.Second - - peersToSkip := &sync.Map{} ctx, cancel := context.WithCancel(context.Background()) defer cancel() - go fetcher.run(ctx, peersToSkip) + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - rctx := context.Background() - fetcher.Request(rctx, 0) + // make sure the searchTimeout is long so it is sure the request is not + // retried because of timeout + fetcher.searchTimeout = 10 * time.Second + + peersToSkip := &sync.Map{} + + go fetcher.run(peersToSkip) + + fetcher.Request(0) select { case <-requester.requestC: @@ -466,17 +457,15 @@ func TestRequestSkipPeerPermanent(t *testing.T) { func TestFetcherMaxHopCount(t *testing.T) { requester := newMockRequester() addr := make([]byte, 32) - fetcher := NewFetcher(addr, requester.doRequest, true) ctx, cancel := context.WithCancel(context.Background()) defer cancel() + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + peersToSkip := &sync.Map{} - go fetcher.run(ctx, peersToSkip) - - rctx := context.Background() - fetcher.Request(rctx, maxHopCount) + go fetcher.run(peersToSkip) // if hopCount is already at max no request should be initiated select { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/hive.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/hive.go index 1aa1ae42..a0b6b988 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/hive.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/hive.go @@ -114,7 +114,7 @@ func (h *Hive) Stop() error { } } log.Info(fmt.Sprintf("%08x hive stopped, dropping peers", h.BaseAddr()[:4])) - h.EachConn(nil, 255, func(p *Peer, _ int, _ bool) bool { + h.EachConn(nil, 255, func(p *Peer, _ int) bool { log.Info(fmt.Sprintf("%08x dropping peer %08x", h.BaseAddr()[:4], p.Address()[:4])) p.Drop(nil) return true @@ -165,8 +165,8 @@ func (h *Hive) Run(p *BzzPeer) error { // otherwise just send depth to new peer dp.NotifyDepth(depth) } + NotifyPeer(p.BzzAddr, h.Kademlia) } - NotifyPeer(p.BzzAddr, h.Kademlia) defer h.Off(dp) return dp.Run(dp.HandleMsg) } @@ -228,7 +228,7 @@ func (h *Hive) loadPeers() error { // savePeers, savePeer implement persistence callback/ func (h *Hive) savePeers() error { var peers []*BzzAddr - h.Kademlia.EachAddr(nil, 256, func(pa *BzzAddr, i int, _ bool) bool { + h.Kademlia.EachAddr(nil, 256, func(pa *BzzAddr, i int) bool { if pa == nil { log.Warn(fmt.Sprintf("empty addr: %v", i)) return true diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/hive_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/hive_test.go index 56adc5a8..ddae95a4 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/hive_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/hive_test.go @@ -18,50 +18,96 @@ package network import ( "io/ioutil" - "log" "os" "testing" + "time" + "github.com/ethereum/go-ethereum/crypto" p2ptest "github.com/ethereum/go-ethereum/p2p/testing" "github.com/ethereum/go-ethereum/swarm/state" ) -func newHiveTester(t *testing.T, params *HiveParams, n int, store state.Store) (*bzzTester, *Hive) { +func newHiveTester(t *testing.T, params *HiveParams, n int, store state.Store) (*bzzTester, *Hive, error) { // setup - addr := RandomAddr() // tested peers peer address - to := NewKademlia(addr.OAddr, NewKadParams()) + prvkey, err := crypto.GenerateKey() + if err != nil { + return nil, nil, err + } + addr := PrivateKeyToBzzKey(prvkey) + to := NewKademlia(addr, NewKadParams()) pp := NewHive(params, to, store) // hive - return newBzzBaseTester(t, n, addr, DiscoverySpec, pp.Run), pp + bt, err := newBzzBaseTester(t, n, prvkey, DiscoverySpec, pp.Run) + if err != nil { + return nil, nil, err + } + return bt, pp, nil } +// TestRegisterAndConnect verifies that the protocol runs successfully +// and that the peer connection exists afterwards func TestRegisterAndConnect(t *testing.T) { params := NewHiveParams() - s, pp := newHiveTester(t, params, 1, nil) + s, pp, err := newHiveTester(t, params, 1, nil) + if err != nil { + t.Fatal(err) + } node := s.Nodes[0] raddr := NewAddr(node) pp.Register(raddr) - // start the hive and wait for the connection - err := pp.Start(s.Server) + // start the hive + err = pp.Start(s.Server) if err != nil { t.Fatal(err) } defer pp.Stop() - // retrieve and broadcast + + // both hive connect and disconect check have time delays + // therefore we need to verify that peer is connected + // so that we are sure that the disconnect timeout doesn't complete + // before the hive connect method is run at least once + timeout := time.After(time.Second) + for { + select { + case <-timeout: + t.Fatalf("expected connection") + default: + } + i := 0 + pp.Kademlia.EachConn(nil, 256, func(addr *Peer, po int) bool { + i++ + return true + }) + if i > 0 { + break + } + time.Sleep(time.Millisecond) + } + + // check that the connection actually exists + // the timeout error means no disconnection events + // were received within the a certain timeout err = s.TestDisconnected(&p2ptest.Disconnect{ Peer: s.Nodes[0].ID(), Error: nil, }) if err == nil || err.Error() != "timed out waiting for peers to disconnect" { - t.Fatalf("expected peer to connect") + t.Fatalf("expected no disconnection event") } } +// TestHiveStatePersistance creates a protocol simulation with n peers for a node +// After protocols complete, the node is shut down and the state is stored. +// Another simulation is created, where 0 nodes are created, but where the stored state is passed +// The test succeeds if all the peers from the stored state are known after the protocols of the +// second simulation have completed +// +// Actual connectivity is not in scope for this test, as the peers loaded from state are not known to +// the simulation; the test only verifies that the peers are known to the node func TestHiveStatePersistance(t *testing.T) { - log.SetOutput(os.Stdout) dir, err := ioutil.TempDir("", "hive_test_store") if err != nil { @@ -75,8 +121,10 @@ func TestHiveStatePersistance(t *testing.T) { } params := NewHiveParams() - s, pp := newHiveTester(t, params, 5, store) - + s, pp, err := newHiveTester(t, params, 5, store) + if err != nil { + t.Fatal(err) + } peers := make(map[string]bool) for _, node := range s.Nodes { raddr := NewAddr(node) @@ -84,7 +132,8 @@ func TestHiveStatePersistance(t *testing.T) { peers[raddr.String()] = true } - // start the hive and wait for the connection + // start and stop the hive + // the known peers should be saved upon stopping err = pp.Start(s.Server) if err != nil { t.Fatal(err) @@ -92,26 +141,32 @@ func TestHiveStatePersistance(t *testing.T) { pp.Stop() store.Close() - persistedStore, err := state.NewDBStore(dir) //start the hive with an empty dbstore + // start the hive with an empty dbstore + persistedStore, err := state.NewDBStore(dir) if err != nil { t.Fatal(err) } - s1, pp := newHiveTester(t, params, 1, persistedStore) - - //start the hive and wait for the connection + s1, pp, err := newHiveTester(t, params, 0, persistedStore) + if err != nil { + t.Fatal(err) + } + // start the hive and check that we know of all expected peers pp.Start(s1.Server) i := 0 - pp.Kademlia.EachAddr(nil, 256, func(addr *BzzAddr, po int, nn bool) bool { + pp.Kademlia.EachAddr(nil, 256, func(addr *BzzAddr, po int) bool { delete(peers, addr.String()) i++ return true }) + // TODO remove this line when verified that test passes + time.Sleep(time.Second) if i != 5 { - t.Errorf("invalid number of entries: got %v, want %v", i, 5) + t.Fatalf("invalid number of entries: got %v, want %v", i, 5) } if len(peers) != 0 { t.Fatalf("%d peers left over: %v", len(peers), peers) } + } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia.go index cd94741b..304f9cd7 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/pot" + sv "github.com/ethereum/go-ethereum/swarm/version" ) /* @@ -49,32 +50,32 @@ a guaranteed constant maximum limit on the number of hops needed to reach one node from the other. */ -var pof = pot.DefaultPof(256) +var Pof = pot.DefaultPof(256) // KadParams holds the config params for Kademlia type KadParams struct { // adjustable parameters - MaxProxDisplay int // number of rows the table shows - MinProxBinSize int // nearest neighbour core minimum cardinality - MinBinSize int // minimum number of peers in a row - MaxBinSize int // maximum number of peers in a row before pruning - RetryInterval int64 // initial interval before a peer is first redialed - RetryExponent int // exponent to multiply retry intervals with - MaxRetries int // maximum number of redial attempts + MaxProxDisplay int // number of rows the table shows + NeighbourhoodSize int // nearest neighbour core minimum cardinality + MinBinSize int // minimum number of peers in a row + MaxBinSize int // maximum number of peers in a row before pruning + RetryInterval int64 // initial interval before a peer is first redialed + RetryExponent int // exponent to multiply retry intervals with + MaxRetries int // maximum number of redial attempts // function to sanction or prevent suggesting a peer - Reachable func(*BzzAddr) bool + Reachable func(*BzzAddr) bool `json:"-"` } // NewKadParams returns a params struct with default values func NewKadParams() *KadParams { return &KadParams{ - MaxProxDisplay: 16, - MinProxBinSize: 2, - MinBinSize: 2, - MaxBinSize: 4, - RetryInterval: 4200000000, // 4.2 sec - MaxRetries: 42, - RetryExponent: 2, + MaxProxDisplay: 16, + NeighbourhoodSize: 2, + MinBinSize: 2, + MaxBinSize: 4, + RetryInterval: 4200000000, // 4.2 sec + MaxRetries: 42, + RetryExponent: 2, } } @@ -139,19 +140,32 @@ func (k *Kademlia) Register(peers ...*BzzAddr) error { defer k.lock.Unlock() var known, size int for _, p := range peers { + log.Trace("kademlia trying to register", "addr", p) // error if self received, peer should know better // and should be punished for this if bytes.Equal(p.Address(), k.base) { return fmt.Errorf("add peers: %x is self", k.base) } var found bool - k.addrs, _, found, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { + k.addrs, _, found, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { // if not found if v == nil { + log.Trace("registering new peer", "addr", p) // insert new offline peer into conns return newEntry(p) } - // found among known peers, do nothing + + e := v.(*entry) + + // if underlay address is different, still add + if !bytes.Equal(e.BzzAddr.UAddr, p.UAddr) { + log.Trace("underlay addr is different, so add again", "new", p, "old", e.BzzAddr) + // insert new offline peer into conns + return newEntry(p) + } + + log.Trace("found among known peers, underlay addr is same, do nothing", "new", p, "old", e.BzzAddr) + return v }) if found { @@ -168,82 +182,115 @@ func (k *Kademlia) Register(peers ...*BzzAddr) error { return nil } -// SuggestPeer returns a known peer for the lowest proximity bin for the -// lowest bincount below depth -// naturally if there is an empty row it returns a peer for that -func (k *Kademlia) SuggestPeer() (a *BzzAddr, o int, want bool) { +// SuggestPeer returns an unconnected peer address as a peer suggestion for connection +func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, changed bool) { k.lock.Lock() defer k.lock.Unlock() - minsize := k.MinBinSize - depth := k.neighbourhoodDepth() - // if there is a callable neighbour within the current proxBin, connect - // this makes sure nearest neighbour set is fully connected - var ppo int - k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool { - if po < depth { - return false + radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) + // collect undersaturated bins in ascending order of number of connected peers + // and from shallow to deep (ascending order of PO) + // insert them in a map of bin arrays, keyed with the number of connected peers + saturation := make(map[int][]int) + var lastPO int // the last non-empty PO bin in the iteration + saturationDepth = -1 // the deepest PO such that all shallower bins have >= k.MinBinSize peers + var pastDepth bool // whether po of iteration >= depth + k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { + // process skipped empty bins + for ; lastPO < po; lastPO++ { + // find the lowest unsaturated bin + if saturationDepth == -1 { + saturationDepth = lastPO + } + // if there is an empty bin, depth is surely passed + pastDepth = true + saturation[0] = append(saturation[0], lastPO) } - e := val.(*entry) - c := k.callable(e) - if c { - a = e.BzzAddr + lastPO = po + 1 + // past radius, depth is surely passed + if po >= radius { + pastDepth = true } - ppo = po - return !c + // beyond depth the bin is treated as unsaturated even if size >= k.MinBinSize + // in order to achieve full connectivity to all neighbours + if pastDepth && size >= k.MinBinSize { + size = k.MinBinSize - 1 + } + // process non-empty unsaturated bins + if size < k.MinBinSize { + // find the lowest unsaturated bin + if saturationDepth == -1 { + saturationDepth = po + } + saturation[size] = append(saturation[size], po) + } + return true }) - if a != nil { - log.Trace(fmt.Sprintf("%08x candidate nearest neighbour found: %v (%v)", k.BaseAddr()[:4], a, ppo)) - return a, 0, false + // to trigger peer requests for peers closer than closest connection, include + // all bins from nearest connection upto nearest address as unsaturated + var nearestAddrAt int + k.addrs.EachNeighbour(k.base, Pof, func(_ pot.Val, po int) bool { + nearestAddrAt = po + return false + }) + // including bins as size 0 has the effect that requesting connection + // is prioritised over non-empty shallower bins + for ; lastPO <= nearestAddrAt; lastPO++ { + saturation[0] = append(saturation[0], lastPO) } - - var bpo []int - prev := -1 - k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { - prev++ - for ; prev < po; prev++ { - bpo = append(bpo, prev) - minsize = 0 - } - if size < minsize { - bpo = append(bpo, po) - minsize = size - } - return size > 0 && po < depth - }) - // all buckets are full, ie., minsize == k.MinBinSize - if len(bpo) == 0 { + // all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested + if len(saturation) == 0 { return nil, 0, false } - // as long as we got candidate peers to connect to - // dont ask for new peers (want = false) - // try to select a candidate peer - // find the first callable peer - nxt := bpo[0] - k.addrs.EachBin(k.base, pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool { - // for each bin (up until depth) we find callable candidate peers - if po >= depth { - return false + // find the first callable peer in the address book + // starting from the bins with smallest size proceeding from shallow to deep + // for each bin (up until neighbourhood radius) we find callable candidate peers + for size := 0; size < k.MinBinSize && suggestedPeer == nil; size++ { + bins, ok := saturation[size] + if !ok { + // no bin with this size + continue } - return f(func(val pot.Val, _ int) bool { - e := val.(*entry) - c := k.callable(e) - if c { - a = e.BzzAddr + cur := 0 + curPO := bins[0] + k.addrs.EachBin(k.base, Pof, curPO, func(po, _ int, f func(func(pot.Val) bool) bool) bool { + curPO = bins[cur] + // find the next bin that has size size + if curPO == po { + cur++ + } else { + // skip bins that have no addresses + for ; cur < len(bins) && curPO < po; cur++ { + curPO = bins[cur] + } + if po < curPO { + cur-- + return true + } + // stop if there are no addresses + if curPO < po { + return false + } } - return !c + // curPO found + // find a callable peer out of the addresses in the unsaturated bin + // stop if found + f(func(val pot.Val) bool { + e := val.(*entry) + if k.callable(e) { + suggestedPeer = e.BzzAddr + return false + } + return true + }) + return cur < len(bins) && suggestedPeer == nil }) - }) - // found a candidate - if a != nil { - return a, 0, false } - // no candidate peer found, request for the short bin - var changed bool - if uint8(nxt) < k.depth { - k.depth = uint8(nxt) - changed = true + + if uint8(saturationDepth) < k.depth { + k.depth = uint8(saturationDepth) + return suggestedPeer, saturationDepth, true } - return a, nxt, changed + return suggestedPeer, 0, false } // On inserts the peer as a kademlia peer into the live peers @@ -251,7 +298,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) { k.lock.Lock() defer k.lock.Unlock() var ins bool - k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val { + k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(v pot.Val) pot.Val { // if not found live if v == nil { ins = true @@ -265,7 +312,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) { a := newEntry(p.BzzAddr) a.conn = p // insert new online peer into addrs - k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { + k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { return a }) // send new address count value only if the peer is inserted @@ -275,7 +322,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) { } log.Trace(k.string()) // calculate if depth of saturation changed - depth := uint8(k.saturation(k.MinBinSize)) + depth := uint8(k.saturation()) var changed bool if depth != k.depth { changed = true @@ -289,6 +336,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) { // neighbourhood depth on each change. // Not receiving from the returned channel will block On function // when the neighbourhood depth is changed. +// TODO: Why is this exported, and if it should be; why can't we have more subscribers than one? func (k *Kademlia) NeighbourhoodDepthC() <-chan int { k.lock.Lock() defer k.lock.Unlock() @@ -298,6 +346,18 @@ func (k *Kademlia) NeighbourhoodDepthC() <-chan int { return k.nDepthC } +// CloseNeighbourhoodDepthC closes the channel returned by +// NeighbourhoodDepthC and stops sending neighbourhood change. +func (k *Kademlia) CloseNeighbourhoodDepthC() { + k.lock.Lock() + defer k.lock.Unlock() + + if k.nDepthC != nil { + close(k.nDepthC) + k.nDepthC = nil + } +} + // sendNeighbourhoodDepthChange sends new neighbourhood depth to k.nDepth channel // if it is initialized. func (k *Kademlia) sendNeighbourhoodDepthChange() { @@ -305,7 +365,7 @@ func (k *Kademlia) sendNeighbourhoodDepthChange() { // It provides signaling of neighbourhood depth change. // This part of the code is sending new neighbourhood depth to nDepthC if that condition is met. if k.nDepthC != nil { - nDepth := k.neighbourhoodDepth() + nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) if nDepth != k.nDepth { k.nDepth = nDepth k.nDepthC <- nDepth @@ -318,19 +378,34 @@ func (k *Kademlia) sendNeighbourhoodDepthChange() { // Not receiving from the returned channel will block Register function // when address count value changes. func (k *Kademlia) AddrCountC() <-chan int { + k.lock.Lock() + defer k.lock.Unlock() + if k.addrCountC == nil { k.addrCountC = make(chan int) } return k.addrCountC } +// CloseAddrCountC closes the channel returned by +// AddrCountC and stops sending address count change. +func (k *Kademlia) CloseAddrCountC() { + k.lock.Lock() + defer k.lock.Unlock() + + if k.addrCountC != nil { + close(k.addrCountC) + k.addrCountC = nil + } +} + // Off removes a peer from among live peers func (k *Kademlia) Off(p *Peer) { k.lock.Lock() defer k.lock.Unlock() var del bool if !p.BzzPeer.LightNode { - k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { + k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { // v cannot be nil, must check otherwise we overwrite entry if v == nil { panic(fmt.Sprintf("connected peer not found %v", p)) @@ -343,7 +418,7 @@ func (k *Kademlia) Off(p *Peer) { } if del { - k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val { + k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { // v cannot be nil, but no need to check return nil }) @@ -355,92 +430,128 @@ func (k *Kademlia) Off(p *Peer) { } } -func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn *Peer, po int) bool) { - k.lock.RLock() - defer k.lock.RUnlock() +func (k *Kademlia) ListKnown() []*BzzAddr { + res := []*BzzAddr{} - var startPo int - var endPo int - kadDepth := k.neighbourhoodDepth() - - k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { - if startPo > 0 && endPo != k.MaxProxDisplay { - startPo = endPo + 1 - } - if po < kadDepth { - endPo = po - } else { - endPo = k.MaxProxDisplay - } - - for bin := startPo; bin <= endPo; bin++ { - f(func(val pot.Val, _ int) bool { - return eachBinFunc(val.(*Peer), bin) - }) - } + k.addrs.Each(func(val pot.Val) bool { + e := val.(*entry) + res = append(res, e.BzzAddr) return true }) + + return res } // EachConn is an iterator with args (base, po, f) applies f to each live peer // that has proximity order po or less as measured from the base // if base is nil, kademlia base address is used -func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int, bool) bool) { +func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) { k.lock.RLock() defer k.lock.RUnlock() k.eachConn(base, o, f) } -func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) { +func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { if len(base) == 0 { base = k.base } - depth := k.neighbourhoodDepth() - k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool { + k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { if po > o { return true } - return f(val.(*Peer), po, po >= depth) + return f(val.(*Peer), po) }) } // EachAddr called with (base, po, f) is an iterator applying f to each known peer -// that has proximity order po or less as measured from the base +// that has proximity order o or less as measured from the base // if base is nil, kademlia base address is used -func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) { +func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { k.lock.RLock() defer k.lock.RUnlock() k.eachAddr(base, o, f) } -func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) { +func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { if len(base) == 0 { base = k.base } - depth := k.neighbourhoodDepth() - k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool { + k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { if po > o { return true } - return f(val.(*entry).BzzAddr, po, po >= depth) + return f(val.(*entry).BzzAddr, po) }) } -// neighbourhoodDepth returns the proximity order that defines the distance of -// the nearest neighbour set with cardinality >= MinProxBinSize -// if there is altogether less than MinProxBinSize peers it returns 0 +// NeighbourhoodDepth returns the depth for the pot, see depthForPot +func (k *Kademlia) NeighbourhoodDepth() (depth int) { + k.lock.RLock() + defer k.lock.RUnlock() + return depthForPot(k.conns, k.NeighbourhoodSize, k.base) +} + +// neighbourhoodRadiusForPot returns the neighbourhood radius of the kademlia +// neighbourhood radius encloses the nearest neighbour set with size >= neighbourhoodSize +// i.e., neighbourhood radius is the deepest PO such that all bins not shallower altogether +// contain at least neighbourhoodSize connected peers +// if there is altogether less than neighbourhoodSize peers connected, it returns 0 // caller must hold the lock -func (k *Kademlia) neighbourhoodDepth() (depth int) { - if k.conns.Size() < k.MinProxBinSize { +func neighbourhoodRadiusForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { + if p.Size() <= neighbourhoodSize { return 0 } + // total number of peers in iteration var size int f := func(v pot.Val, i int) bool { + // po == 256 means that addr is the pivot address(self) + if i == 256 { + return true + } size++ - depth = i - return size < k.MinProxBinSize + + // this means we have all nn-peers. + // depth is by default set to the bin of the farthest nn-peer + if size == neighbourhoodSize { + depth = i + return false + } + + return true } - k.conns.EachNeighbour(k.base, pof, f) + p.EachNeighbour(pivotAddr, Pof, f) + return depth +} + +// depthForPot returns the depth for the pot +// depth is the radius of the minimal extension of nearest neighbourhood that +// includes all empty PO bins. I.e., depth is the deepest PO such that +// - it is not deeper than neighbourhood radius +// - all bins shallower than depth are not empty +// caller must hold the lock +func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { + if p.Size() <= neighbourhoodSize { + return 0 + } + // determining the depth is a two-step process + // first we find the proximity bin of the shallowest of the neighbourhoodSize peers + // the numeric value of depth cannot be higher than this + maxDepth := neighbourhoodRadiusForPot(p, neighbourhoodSize, pivotAddr) + + // the second step is to test for empty bins in order from shallowest to deepest + // if an empty bin is found, this will be the actual depth + // we stop iterating if we hit the maxDepth determined in the first step + p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool { + if po == depth { + if maxDepth == depth { + return false + } + depth++ + return true + } + return false + }) + return depth } @@ -494,22 +605,25 @@ func (k *Kademlia) string() string { var rows []string rows = append(rows, "=========================================================================") + if len(sv.GitCommit) > 0 { + rows = append(rows, fmt.Sprintf("commit hash: %s", sv.GitCommit)) + } rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3])) - rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.MinProxBinSize, k.MinBinSize, k.MaxBinSize)) + rows = append(rows, fmt.Sprintf("population: %d (%d), NeighbourhoodSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.NeighbourhoodSize, k.MinBinSize, k.MaxBinSize)) liverows := make([]string, k.MaxProxDisplay) peersrows := make([]string, k.MaxProxDisplay) - depth := k.neighbourhoodDepth() + depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) rest := k.conns.Size() - k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { + k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { var rowlen int if po >= k.MaxProxDisplay { po = k.MaxProxDisplay - 1 } row := []string{fmt.Sprintf("%2d", size)} rest -= size - f(func(val pot.Val, vpo int) bool { + f(func(val pot.Val) bool { e := val.(*Peer) row = append(row, fmt.Sprintf("%x", e.Address()[:2])) rowlen++ @@ -521,7 +635,7 @@ func (k *Kademlia) string() string { return true }) - k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { + k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { var rowlen int if po >= k.MaxProxDisplay { po = k.MaxProxDisplay - 1 @@ -531,7 +645,7 @@ func (k *Kademlia) string() string { } row := []string{fmt.Sprintf("%2d", size)} // we are displaying live peers too - f(func(val pot.Val, vpo int) bool { + f(func(val pot.Val) bool { e := val.(*entry) row = append(row, Label(e)) rowlen++ @@ -559,155 +673,186 @@ func (k *Kademlia) string() string { return "\n" + strings.Join(rows, "\n") } -// PeerPot keeps info about expected nearest neighbours and empty bins +// PeerPot keeps info about expected nearest neighbours // used for testing only +// TODO move to separate testing tools file type PeerPot struct { - NNSet [][]byte - EmptyBins []int + NNSet [][]byte + PeersPerBin []int } // NewPeerPotMap creates a map of pot record of *BzzAddr with keys // as hexadecimal representations of the address. +// the NeighbourhoodSize of the passed kademlia is used // used for testing only -func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot { +// TODO move to separate testing tools file +func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot { + // create a table of all nodes for health check np := pot.NewPot(nil, 0) for _, addr := range addrs { - np, _, _ = pot.Add(np, addr, pof) + np, _, _ = pot.Add(np, addr, Pof) } ppmap := make(map[string]*PeerPot) + // generate an allknowing source of truth for connections + // for every kademlia passed for i, a := range addrs { - pl := 256 - prev := 256 - var emptyBins []int + + // actual kademlia depth + depth := depthForPot(np, neighbourhoodSize, a) + + // all nn-peers var nns [][]byte - np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool { - a := val.([]byte) + peersPerBin := make([]int, depth) + + // iterate through the neighbours, going from the deepest to the shallowest + np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool { + addr := val.([]byte) + // po == 256 means that addr is the pivot address(self) + // we do not include self in the map if po == 256 { return true } - if pl == 256 || pl == po { - nns = append(nns, a) + // append any neighbors found + // a neighbor is any peer in or deeper than the depth + if po >= depth { + nns = append(nns, addr) + } else { + // for peers < depth, we just count the number in each bin + // the bin is the index of the slice + peersPerBin[po]++ } - if pl == 256 && len(nns) >= kadMinProxSize { - pl = po - prev = po - } - if prev < pl { - for j := prev; j > po; j-- { - emptyBins = append(emptyBins, j) - } - } - prev = po - 1 return true }) - for j := prev; j >= 0; j-- { - emptyBins = append(emptyBins, j) + + log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s, peersPerBin", addrs[i][:4], LogAddrs(nns))) + ppmap[common.Bytes2Hex(a)] = &PeerPot{ + NNSet: nns, + PeersPerBin: peersPerBin, } - log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns))) - ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins} } return ppmap } -// saturation returns the lowest proximity order that the bin for that order -// has less than n peers -// It is used in Healthy function for testing only -func (k *Kademlia) saturation(n int) int { +// saturation returns the smallest po value in which the node has less than MinBinSize peers +// if the iterator reaches neighbourhood radius, then the last bin + 1 is returned +func (k *Kademlia) saturation() int { prev := -1 - k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { + radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) + k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { prev++ - return prev == po && size >= n + if po >= radius { + return false + } + return prev == po && size >= k.MinBinSize }) - depth := k.neighbourhoodDepth() - if depth < prev { - return depth + if prev < 0 { + return 0 } return prev } -// full returns true if all required bins have connected peers. -// It is used in Healthy function for testing only -func (k *Kademlia) full(emptyBins []int) (full bool) { - prev := 0 - e := len(emptyBins) - ok := true - depth := k.neighbourhoodDepth() - k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool { - if prev == depth+1 { - return true - } - for i := prev; i < po; i++ { - e-- - if e < 0 { - ok = false - return false - } - if emptyBins[e] != i { - log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins))) - if emptyBins[e] < i { - panic("incorrect peerpot") - } - ok = false - return false - } - } - prev = po + 1 - return true - }) - if !ok { +// isSaturated returns true if the kademlia is considered saturated, or false if not. +// It checks this by checking an array of ints called unsaturatedBins; each item in that array corresponds +// to the bin which is unsaturated (number of connections < k.MinBinSize). +// The bin is considered unsaturated only if there are actual peers in that PeerPot's bin (peersPerBin) +// (if there is no peer for a given bin, then no connection could ever be established; +// in a God's view this is relevant as no more peers will ever appear on that bin) +func (k *Kademlia) isSaturated(peersPerBin []int, depth int) bool { + // depth could be calculated from k but as this is called from `GetHealthInfo()`, + // the depth has already been calculated so we can require it as a parameter + + // early check for depth + if depth != len(peersPerBin) { return false } - return e == 0 -} + unsaturatedBins := make([]int, 0) + k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { -// knowNearestNeighbours tests if all known nearest neighbours given as arguments -// are found in the addressbook -// It is used in Healthy function for testing only -func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool { - pm := make(map[string]bool) - - k.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool { - if !nn { + if po >= depth { return false } - pk := fmt.Sprintf("%x", p.Address()) + log.Trace("peers per bin", "peersPerBin[po]", peersPerBin[po], "po", po) + // if there are actually peers in the PeerPot who can fulfill k.MinBinSize + if size < k.MinBinSize && size < peersPerBin[po] { + log.Trace("connections for po", "po", po, "size", size) + unsaturatedBins = append(unsaturatedBins, po) + } + return true + }) + + log.Trace("list of unsaturated bins", "unsaturatedBins", unsaturatedBins) + return len(unsaturatedBins) == 0 +} + +// knowNeighbours tests if all neighbours in the peerpot +// are found among the peers known to the kademlia +// It is used in Healthy function for testing only +// TODO move to separate testing tools file +func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) { + pm := make(map[string]bool) + depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) + // create a map with all peers at depth and deeper known in the kademlia + k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool { + // in order deepest to shallowest compared to the kademlia base address + // all bins (except self) are included (0 <= bin <= 255) + if po < depth { + return false + } + pk := common.Bytes2Hex(p.Address()) pm[pk] = true return true }) - for _, p := range peers { - pk := fmt.Sprintf("%x", p) - if !pm[pk] { - log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8])) - return false - } - } - return true -} -// gotNearestNeighbours tests if all known nearest neighbours given as arguments -// are connected peers -// It is used in Healthy function for testing only -func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { - pm := make(map[string]bool) - - k.eachConn(nil, 255, func(p *Peer, po int, nn bool) bool { - if !nn { - return false - } - pk := fmt.Sprintf("%x", p.Address()) - pm[pk] = true - return true - }) + // iterate through nearest neighbors in the peerpot map + // if we can't find the neighbor in the map we created above + // then we don't know all our neighbors + // (which sadly is all too common in modern society) var gots int var culprits [][]byte - for _, p := range peers { - pk := fmt.Sprintf("%x", p) + for _, p := range addrs { + pk := common.Bytes2Hex(p) if pm[pk] { gots++ } else { - log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8])) + log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk)) + culprits = append(culprits, p) + } + } + return gots == len(addrs), gots, culprits +} + +// connectedNeighbours tests if all neighbours in the peerpot +// are currently connected in the kademlia +// It is used in Healthy function for testing only +func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { + pm := make(map[string]bool) + + // create a map with all peers at depth and deeper that are connected in the kademlia + // in order deepest to shallowest compared to the kademlia base address + // all bins (except self) are included (0 <= bin <= 255) + depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) + k.eachConn(nil, 255, func(p *Peer, po int) bool { + if po < depth { + return false + } + pk := common.Bytes2Hex(p.Address()) + pm[pk] = true + return true + }) + + // iterate through nearest neighbors in the peerpot map + // if we can't find the neighbor in the map we created above + // then we don't know all our neighbors + var gots int + var culprits [][]byte + for _, p := range peers { + pk := common.Bytes2Hex(p) + if pm[pk] { + gots++ + } else { + log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk)) culprits = append(culprits, p) } } @@ -717,31 +862,58 @@ func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missin // Health state of the Kademlia // used for testing only type Health struct { - KnowNN bool // whether node knows all its nearest neighbours - GotNN bool // whether node is connected to all its nearest neighbours - CountNN int // amount of nearest neighbors connected to - CulpritsNN [][]byte // which known NNs are missing - Full bool // whether node has a peer in each kademlia bin (where there is such a peer) - Hive string + KnowNN bool // whether node knows all its neighbours + CountKnowNN int // amount of neighbors known + MissingKnowNN [][]byte // which neighbours we should have known but we don't + ConnectNN bool // whether node is connected to all its neighbours + CountConnectNN int // amount of neighbours connected to + MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not + // Saturated: if in all bins < depth number of connections >= MinBinsize or, + // if number of connections < MinBinSize, to the number of available peers in that bin + Saturated bool + Hive string } -// Healthy reports the health state of the kademlia connectivity -// returns a Health struct +// GetHealthInfo reports the health state of the kademlia connectivity +// +// The PeerPot argument provides an all-knowing view of the network +// The resulting Health object is a result of comparisons between +// what is the actual composition of the kademlia in question (the receiver), and +// what SHOULD it have been when we take all we know about the network into consideration. +// // used for testing only -func (k *Kademlia) Healthy(pp *PeerPot) *Health { +func (k *Kademlia) GetHealthInfo(pp *PeerPot) *Health { k.lock.RLock() defer k.lock.RUnlock() - gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet) - knownn := k.knowNearestNeighbours(pp.NNSet) - full := k.full(pp.EmptyBins) - log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full)) - return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()} + if len(pp.NNSet) < k.NeighbourhoodSize { + log.Warn("peerpot NNSet < NeighbourhoodSize") + } + gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet) + knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet) + depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) + + // check saturation + saturated := k.isSaturated(pp.PeersPerBin, depth) + + log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated)) + return &Health{ + KnowNN: knownn, + CountKnowNN: countknownn, + MissingKnowNN: culpritsknownn, + ConnectNN: gotnn, + CountConnectNN: countgotnn, + MissingConnectNN: culpritsgotnn, + Saturated: saturated, + Hive: k.string(), + } } -func logEmptyBins(ebs []int) string { - var ebss []string - for _, eb := range ebs { - ebss = append(ebss, fmt.Sprintf("%d", eb)) - } - return strings.Join(ebss, ", ") +// Healthy return the strict interpretation of `Healthy` given a `Health` struct +// definition of strict health: all conditions must be true: +// - we at least know one peer +// - we know all neighbors +// - we are connected to all known neighbors +// - it is saturated +func (h *Health) Healthy() bool { + return h.KnowNN && h.ConnectNN && h.CountKnowNN > 0 && h.Saturated } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia_test.go index d2e051f4..b4663eee 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/kademlia_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -17,7 +17,6 @@ package network import ( - "bytes" "fmt" "os" "testing" @@ -25,6 +24,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/protocols" "github.com/ethereum/go-ethereum/swarm/pot" ) @@ -38,53 +40,326 @@ func testKadPeerAddr(s string) *BzzAddr { return &BzzAddr{OAddr: a, UAddr: a} } -func newTestKademlia(b string) *Kademlia { +func newTestKademliaParams() *KadParams { params := NewKadParams() - params.MinBinSize = 1 - params.MinProxBinSize = 2 + params.MinBinSize = 2 + params.NeighbourhoodSize = 2 + return params +} + +type testKademlia struct { + *Kademlia + t *testing.T +} + +func newTestKademlia(t *testing.T, b string) *testKademlia { base := pot.NewAddressFromString(b) - return NewKademlia(base, params) + return &testKademlia{ + Kademlia: NewKademlia(base, newTestKademliaParams()), + t: t, + } } -func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer { - return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, k) +func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer { + return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia) } -func On(k *Kademlia, ons ...string) { +func (tk *testKademlia) On(ons ...string) { for _, s := range ons { - k.On(newTestKadPeer(k, s, false)) + tk.Kademlia.On(tk.newTestKadPeer(s, false)) } } -func Off(k *Kademlia, offs ...string) { +func (tk *testKademlia) Off(offs ...string) { for _, s := range offs { - k.Off(newTestKadPeer(k, s, false)) + tk.Kademlia.Off(tk.newTestKadPeer(s, false)) } } -func Register(k *Kademlia, regs ...string) { +func (tk *testKademlia) Register(regs ...string) { var as []*BzzAddr for _, s := range regs { as = append(as, testKadPeerAddr(s)) } - err := k.Register(as...) + err := tk.Kademlia.Register(as...) if err != nil { panic(err.Error()) } } -func testSuggestPeer(k *Kademlia, expAddr string, expPo int, expWant bool) error { - addr, o, want := k.SuggestPeer() +// tests the validity of neighborhood depth calculations +// +// in particular, it tests that if there are one or more consecutive +// empty bins above the farthest "nearest neighbor-peer" then +// the depth should be set at the farthest of those empty bins +// +// TODO: Make test adapt to change in NeighbourhoodSize +func TestNeighbourhoodDepth(t *testing.T) { + baseAddressBytes := RandomAddr().OAddr + kad := NewKademlia(baseAddressBytes, NewKadParams()) + + baseAddress := pot.NewAddressFromBytes(baseAddressBytes) + + // generate the peers + var peers []*Peer + for i := 0; i < 7; i++ { + addr := pot.RandomAddressAt(baseAddress, i) + peers = append(peers, newTestDiscoveryPeer(addr, kad)) + } + var sevenPeers []*Peer + for i := 0; i < 2; i++ { + addr := pot.RandomAddressAt(baseAddress, 7) + sevenPeers = append(sevenPeers, newTestDiscoveryPeer(addr, kad)) + } + + testNum := 0 + // first try with empty kademlia + depth := kad.NeighbourhoodDepth() + if depth != 0 { + t.Fatalf("%d expected depth 0, was %d", testNum, depth) + } + testNum++ + + // add one peer on 7 + kad.On(sevenPeers[0]) + depth = kad.NeighbourhoodDepth() + if depth != 0 { + t.Fatalf("%d expected depth 0, was %d", testNum, depth) + } + testNum++ + + // add a second on 7 + kad.On(sevenPeers[1]) + depth = kad.NeighbourhoodDepth() + if depth != 0 { + t.Fatalf("%d expected depth 0, was %d", testNum, depth) + } + testNum++ + + // add from 0 to 6 + for i, p := range peers { + kad.On(p) + depth = kad.NeighbourhoodDepth() + if depth != i+1 { + t.Fatalf("%d.%d expected depth %d, was %d", i+1, testNum, i, depth) + } + } + testNum++ + + kad.Off(sevenPeers[1]) + depth = kad.NeighbourhoodDepth() + if depth != 6 { + t.Fatalf("%d expected depth 6, was %d", testNum, depth) + } + testNum++ + + kad.Off(peers[4]) + depth = kad.NeighbourhoodDepth() + if depth != 4 { + t.Fatalf("%d expected depth 4, was %d", testNum, depth) + } + testNum++ + + kad.Off(peers[3]) + depth = kad.NeighbourhoodDepth() + if depth != 3 { + t.Fatalf("%d expected depth 3, was %d", testNum, depth) + } + testNum++ +} + +// TestHighMinBinSize tests that the saturation function also works +// if MinBinSize is > 2, the connection count is < k.MinBinSize +// and there are more peers available than connected +func TestHighMinBinSize(t *testing.T) { + // a function to test for different MinBinSize values + testKad := func(minBinSize int) { + // create a test kademlia + tk := newTestKademlia(t, "11111111") + // set its MinBinSize to desired value + tk.KadParams.MinBinSize = minBinSize + + // add a couple of peers (so we have NN and depth) + tk.On("00000000") // bin 0 + tk.On("11100000") // bin 3 + tk.On("11110000") // bin 4 + + first := "10000000" // add a first peer at bin 1 + tk.Register(first) // register it + // we now have one registered peer at bin 1; + // iterate and connect one peer at each iteration; + // should be unhealthy until at minBinSize - 1 + // we connect the unconnected but registered peer + for i := 1; i < minBinSize; i++ { + peer := fmt.Sprintf("1000%b", 8|i) + tk.On(peer) + if i == minBinSize-1 { + tk.On(first) + tk.checkHealth(true) + return + } + tk.checkHealth(false) + } + } + // test MinBinSizes of 3 to 5 + testMinBinSizes := []int{3, 4, 5} + for _, k := range testMinBinSizes { + testKad(k) + } +} + +// TestHealthStrict tests the simplest definition of health +// Which means whether we are connected to all neighbors we know of +func TestHealthStrict(t *testing.T) { + + // base address is all zeros + // no peers + // unhealthy (and lonely) + tk := newTestKademlia(t, "11111111") + tk.checkHealth(false) + + // know one peer but not connected + // unhealthy + tk.Register("11100000") + tk.checkHealth(false) + + // know one peer and connected + // unhealthy: not saturated + tk.On("11100000") + tk.checkHealth(true) + + // know two peers, only one connected + // unhealthy + tk.Register("11111100") + tk.checkHealth(false) + + // know two peers and connected to both + // healthy + tk.On("11111100") + tk.checkHealth(true) + + // know three peers, connected to the two deepest + // healthy + tk.Register("00000000") + tk.checkHealth(false) + + // know three peers, connected to all three + // healthy + tk.On("00000000") + tk.checkHealth(true) + + // add fourth peer deeper than current depth + // unhealthy + tk.Register("11110000") + tk.checkHealth(false) + + // connected to three deepest peers + // healthy + tk.On("11110000") + tk.checkHealth(true) + + // add additional peer in same bin as deepest peer + // unhealthy + tk.Register("11111101") + tk.checkHealth(false) + + // four deepest of five peers connected + // healthy + tk.On("11111101") + tk.checkHealth(true) + + // add additional peer in bin 0 + // unhealthy: unsaturated bin 0, 2 known but 1 connected + tk.Register("00000001") + tk.checkHealth(false) + + // Connect second in bin 0 + // healthy + tk.On("00000001") + tk.checkHealth(true) + + // add peer in bin 1 + // unhealthy, as it is known but not connected + tk.Register("10000000") + tk.checkHealth(false) + + // connect peer in bin 1 + // depth change, is now 1 + // healthy, 1 peer in bin 1 known and connected + tk.On("10000000") + tk.checkHealth(true) + + // add second peer in bin 1 + // unhealthy, as it is known but not connected + tk.Register("10000001") + tk.checkHealth(false) + + // connect second peer in bin 1 + // healthy, + tk.On("10000001") + tk.checkHealth(true) + + // connect third peer in bin 1 + // healthy, + tk.On("10000011") + tk.checkHealth(true) + + // add peer in bin 2 + // unhealthy, no depth change + tk.Register("11000000") + tk.checkHealth(false) + + // connect peer in bin 2 + // depth change - as we already have peers in bin 3 and 4, + // we have contiguous bins, no bin < po 5 is empty -> depth 5 + // healthy, every bin < depth has the max available peers, + // even if they are < MinBinSize + tk.On("11000000") + tk.checkHealth(true) + + // add peer in bin 2 + // unhealthy, peer bin is below depth 5 but + // has more available peers (2) than connected ones (1) + // --> unsaturated + tk.Register("11000011") + tk.checkHealth(false) +} + +func (tk *testKademlia) checkHealth(expectHealthy bool) { + tk.t.Helper() + kid := common.Bytes2Hex(tk.BaseAddr()) + addrs := [][]byte{tk.BaseAddr()} + tk.EachAddr(nil, 255, func(addr *BzzAddr, po int) bool { + addrs = append(addrs, addr.Address()) + return true + }) + + pp := NewPeerPotMap(tk.NeighbourhoodSize, addrs) + healthParams := tk.GetHealthInfo(pp[kid]) + + // definition of health, all conditions but be true: + // - we at least know one peer + // - we know all neighbors + // - we are connected to all known neighbors + health := healthParams.Healthy() + if expectHealthy != health { + tk.t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, tk.String()) + } +} + +func (tk *testKademlia) checkSuggestPeer(expAddr string, expDepth int, expChanged bool) { + tk.t.Helper() + addr, depth, changed := tk.SuggestPeer() + log.Trace("suggestPeer return", "addr", addr, "depth", depth, "changed", changed) if binStr(addr) != expAddr { - return fmt.Errorf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) + tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) } - if o != expPo { - return fmt.Errorf("incorrect prox order suggested. expected %v, got %v", expPo, o) + if depth != expDepth { + tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth) } - if want != expWant { - return fmt.Errorf("expected SuggestPeer to want peers: %v", expWant) + if changed != expChanged { + tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed) } - return nil } func binStr(a *BzzAddr) string { @@ -94,553 +369,194 @@ func binStr(a *BzzAddr) string { return pot.ToBin(a.Address())[:8] } -func TestSuggestPeerBug(t *testing.T) { - // 2 row gap, unsaturated proxbin, no callables -> want PO 0 - k := newTestKademlia("00000000") - On(k, - "10000000", "11000000", - "01000000", - - "00010000", "00011000", - ) - Off(k, - "01000000", - ) - err := testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } -} - func TestSuggestPeerFindPeers(t *testing.T) { - // 2 row gap, unsaturated proxbin, no callables -> want PO 0 - k := newTestKademlia("00000000") - On(k, "00100000") - err := testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk := newTestKademlia(t, "00000000") + tk.On("00100000") + tk.checkSuggestPeer("", 0, false) - // 2 row gap, saturated proxbin, no callables -> want PO 0 - On(k, "00010000") - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("00010000") + tk.checkSuggestPeer("", 0, false) - // 1 row gap (1 less), saturated proxbin, no callables -> want PO 1 - On(k, "10000000") - err = testSuggestPeer(k, "", 1, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("10000000", "10000001") + tk.checkSuggestPeer("", 0, false) - // no gap (1 less), saturated proxbin, no callables -> do not want more - On(k, "01000000", "00100001") - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("01000000") + tk.Off("10000001") + tk.checkSuggestPeer("10000001", 0, true) - // oversaturated proxbin, > do not want more - On(k, "00100001") - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } - - // reintroduce gap, disconnected peer callable - Off(k, "01000000") - err = testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("00100001") + tk.Off("01000000") + tk.checkSuggestPeer("01000000", 0, false) // second time disconnected peer not callable // with reasonably set Interval - err = testSuggestPeer(k, "", 1, true) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("", 0, false) // on and off again, peer callable again - On(k, "01000000") - Off(k, "01000000") - err = testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("01000000") + tk.Off("01000000") + tk.checkSuggestPeer("01000000", 0, false) - On(k, "01000000") - // new closer peer appears, it is immediately wanted - Register(k, "00010001") - err = testSuggestPeer(k, "00010001", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("01000000", "10000001") + tk.checkSuggestPeer("", 0, false) - // PO1 disconnects - On(k, "00010001") - log.Info(k.String()) - Off(k, "01000000") - log.Info(k.String()) - // second time, gap filling - err = testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Register("00010001") + tk.checkSuggestPeer("00010001", 0, false) - On(k, "01000000") - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("00010001") + tk.Off("01000000") + tk.checkSuggestPeer("01000000", 0, false) - k.MinBinSize = 2 - err = testSuggestPeer(k, "", 0, true) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("01000000") + tk.checkSuggestPeer("", 0, false) - Register(k, "01000001") - err = testSuggestPeer(k, "01000001", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Register("01000001") + tk.checkSuggestPeer("01000001", 0, false) - On(k, "10000001") - log.Trace(fmt.Sprintf("Kad:\n%v", k.String())) - err = testSuggestPeer(k, "", 1, true) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("01000001") + tk.checkSuggestPeer("", 0, false) - On(k, "01000001") - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Register("10000010", "01000010", "00100010") + tk.checkSuggestPeer("", 0, false) - k.MinBinSize = 3 - Register(k, "10000010") - err = testSuggestPeer(k, "10000010", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Register("00010010") + tk.checkSuggestPeer("00010010", 0, false) - On(k, "10000010") - err = testSuggestPeer(k, "", 1, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Off("00100001") + tk.checkSuggestPeer("00100010", 2, true) - On(k, "01000010") - err = testSuggestPeer(k, "", 2, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Off("01000001") + tk.checkSuggestPeer("01000010", 1, true) - On(k, "00100010") - err = testSuggestPeer(k, "", 3, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("01000001", 0, false) + tk.checkSuggestPeer("00100001", 0, false) + tk.checkSuggestPeer("", 0, false) - On(k, "00010010") - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.On("01000001", "00100001") + tk.Register("10000100", "01000100", "00100100") + tk.Register("00000100", "00000101", "00000110") + tk.Register("00000010", "00000011", "00000001") + + tk.checkSuggestPeer("00000110", 0, false) + tk.checkSuggestPeer("00000101", 0, false) + tk.checkSuggestPeer("00000100", 0, false) + tk.checkSuggestPeer("00000011", 0, false) + tk.checkSuggestPeer("00000010", 0, false) + tk.checkSuggestPeer("00000001", 0, false) + tk.checkSuggestPeer("", 0, false) } // a node should stay in the address book if it's removed from the kademlia func TestOffEffectingAddressBookNormalNode(t *testing.T) { - k := newTestKademlia("00000000") + tk := newTestKademlia(t, "00000000") // peer added to kademlia - k.On(newTestKadPeer(k, "01000000", false)) + tk.On("01000000") // peer should be in the address book - if k.addrs.Size() != 1 { + if tk.addrs.Size() != 1 { t.Fatal("known peer addresses should contain 1 entry") } // peer should be among live connections - if k.conns.Size() != 1 { + if tk.conns.Size() != 1 { t.Fatal("live peers should contain 1 entry") } // remove peer from kademlia - k.Off(newTestKadPeer(k, "01000000", false)) + tk.Off("01000000") // peer should be in the address book - if k.addrs.Size() != 1 { + if tk.addrs.Size() != 1 { t.Fatal("known peer addresses should contain 1 entry") } // peer should not be among live connections - if k.conns.Size() != 0 { + if tk.conns.Size() != 0 { t.Fatal("live peers should contain 0 entry") } } // a light node should not be in the address book func TestOffEffectingAddressBookLightNode(t *testing.T) { - k := newTestKademlia("00000000") + tk := newTestKademlia(t, "00000000") // light node peer added to kademlia - k.On(newTestKadPeer(k, "01000000", true)) + tk.Kademlia.On(tk.newTestKadPeer("01000000", true)) // peer should not be in the address book - if k.addrs.Size() != 0 { + if tk.addrs.Size() != 0 { t.Fatal("known peer addresses should contain 0 entry") } // peer should be among live connections - if k.conns.Size() != 1 { + if tk.conns.Size() != 1 { t.Fatal("live peers should contain 1 entry") } // remove peer from kademlia - k.Off(newTestKadPeer(k, "01000000", true)) + tk.Kademlia.Off(tk.newTestKadPeer("01000000", true)) // peer should not be in the address book - if k.addrs.Size() != 0 { + if tk.addrs.Size() != 0 { t.Fatal("known peer addresses should contain 0 entry") } // peer should not be among live connections - if k.conns.Size() != 0 { + if tk.conns.Size() != 0 { t.Fatal("live peers should contain 0 entry") } } func TestSuggestPeerRetries(t *testing.T) { - k := newTestKademlia("00000000") - k.RetryInterval = int64(300 * time.Millisecond) // cycle - k.MaxRetries = 50 - k.RetryExponent = 2 + tk := newTestKademlia(t, "00000000") + tk.RetryInterval = int64(300 * time.Millisecond) // cycle + tk.MaxRetries = 50 + tk.RetryExponent = 2 sleep := func(n int) { - ts := k.RetryInterval + ts := tk.RetryInterval for i := 1; i < n; i++ { - ts *= int64(k.RetryExponent) + ts *= int64(tk.RetryExponent) } time.Sleep(time.Duration(ts)) } - Register(k, "01000000") - On(k, "00000001", "00000010") - err := testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.Register("01000000") + tk.On("00000001", "00000010") + tk.checkSuggestPeer("01000000", 0, false) - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("", 0, false) sleep(1) - err = testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("01000000", 0, false) - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("", 0, false) sleep(1) - err = testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("01000000", 0, false) - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("", 0, false) sleep(2) - err = testSuggestPeer(k, "01000000", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("01000000", 0, false) - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } + tk.checkSuggestPeer("", 0, false) sleep(2) - err = testSuggestPeer(k, "", 0, false) - if err != nil { - t.Fatal(err.Error()) - } - + tk.checkSuggestPeer("", 0, false) } func TestKademliaHiveString(t *testing.T) { - k := newTestKademlia("00000000") - On(k, "01000000", "00100000") - Register(k, "10000000", "10000001") - k.MaxProxDisplay = 8 - h := k.String() - expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), MinProxBinSize: 2, MinBinSize: 1, MaxBinSize: 4\n000 0 | 2 8100 (0) 8000 (0)\n============ DEPTH: 1 ==========================================\n001 1 4000 | 1 4000 (0)\n002 1 2000 | 1 2000 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n=========================================================================" + tk := newTestKademlia(t, "00000000") + tk.On("01000000", "00100000") + tk.Register("10000000", "10000001") + tk.MaxProxDisplay = 8 + h := tk.String() + expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 0 | 2 8100 (0) 8000 (0)\n001 1 4000 | 1 4000 (0)\n002 1 2000 | 1 2000 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n=========================================================================" if expH[104:] != h[104:] { t.Fatalf("incorrect hive output. expected %v, got %v", expH, h) } } -// testKademliaCase constructs the kademlia and PeerPot map to validate -// the SuggestPeer and Healthy methods for provided hex-encoded addresses. -// Argument pivotAddr is the address of the kademlia. -func testKademliaCase(t *testing.T, pivotAddr string, addrs ...string) { - addr := common.FromHex(pivotAddr) - addrs = append(addrs, pivotAddr) - - k := NewKademlia(addr, NewKadParams()) - - as := make([][]byte, len(addrs)) - for i, a := range addrs { - as[i] = common.FromHex(a) - } - - for _, a := range as { - if bytes.Equal(a, addr) { - continue - } - p := &BzzAddr{OAddr: a, UAddr: a} - if err := k.Register(p); err != nil { - t.Fatal(err) - } - } - - ppmap := NewPeerPotMap(2, as) - - pp := ppmap[pivotAddr] - - for { - a, _, _ := k.SuggestPeer() - if a == nil { - break - } - k.On(NewPeer(&BzzPeer{BzzAddr: a}, k)) - } - - h := k.Healthy(pp) - if !(h.GotNN && h.KnowNN && h.Full) { - t.Fatalf("not healthy: %#v\n%v", h, k.String()) +func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer { + rw := &p2p.MsgPipeRW{} + p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{}) + pp := protocols.NewPeer(p, rw, &protocols.Spec{}) + bp := &BzzPeer{ + Peer: pp, + BzzAddr: &BzzAddr{ + OAddr: addr.Bytes(), + UAddr: []byte(fmt.Sprintf("%x", addr[:])), + }, } -} - -/* -The regression test for the following invalid kademlia edge case. - -Addresses used in this test are discovered as part of the simulation network -in higher level tests for streaming. They were generated randomly. - -========================================================================= -Mon Apr 9 12:18:24 UTC 2018 KΛÐΞMLIΛ hive: queen's address: 7efef1 -population: 9 (49), MinProxBinSize: 2, MinBinSize: 2, MaxBinSize: 4 -000 2 d7e5 ec56 | 18 ec56 (0) d7e5 (0) d9e0 (0) c735 (0) -001 2 18f1 3176 | 14 18f1 (0) 10bb (0) 10d1 (0) 0421 (0) -002 2 52aa 47cd | 11 52aa (0) 51d9 (0) 5161 (0) 5130 (0) -003 1 646e | 1 646e (0) -004 0 | 3 769c (0) 76d1 (0) 7656 (0) -============ DEPTH: 5 ========================================== -005 1 7a48 | 1 7a48 (0) -006 1 7cbd | 1 7cbd (0) -007 0 | 0 -008 0 | 0 -009 0 | 0 -010 0 | 0 -011 0 | 0 -012 0 | 0 -013 0 | 0 -014 0 | 0 -015 0 | 0 -========================================================================= -*/ -func TestKademliaCase1(t *testing.T) { - testKademliaCase(t, - "7efef1c41d77f843ad167be95f6660567eb8a4a59f39240000cce2e0d65baf8e", - "ec560e6a4806aa37f147ee83687f3cf044d9953e61eedb8c34b6d50d9e2c5623", - "646e9540c84f6a2f9cf6585d45a4c219573b4fd1b64a3c9a1386fc5cf98c0d4d", - "18f13c5fba653781019025ab10e8d2fdc916d6448729268afe9e928ffcdbb8e8", - "317617acf99b4ffddda8a736f8fc6c6ede0bf690bc23d834123823e6d03e2f69", - "d7e52d9647a5d1c27a68c3ee65d543be3947ae4b68537b236d71ef9cb15fb9ab", - "7a48f75f8ca60487ae42d6f92b785581b40b91f2da551ae73d5eae46640e02e8", - "7cbd42350bde8e18ae5b955b5450f8e2cef3419f92fbf5598160c60fd78619f0", - "52aa3ddec61f4d48dd505a2385403c634f6ad06ee1d99c5c90a5ba6006f9af9c", - "47cdb6fa93eeb8bc91a417ff4e3b14a9c2ea85137462e2f575fae97f0c4be60d", - "5161943eb42e2a03e715fe8afa1009ff5200060c870ead6ab103f63f26cb107f", - "a38eaa1255f76bf883ca0830c86e8c4bb7eed259a8348aae9b03f21f90105bee", - "b2522bdf1ab26f324e75424fdf6e493b47e8a27687fe76347607b344fc010075", - "5bd7213964efb2580b91d02ac31ef126838abeba342f5dbdbe8d4d03562671a2", - "0b531adb82744768b694d7f94f73d4f0c9de591266108daeb8c74066bfc9c9ca", - "28501f59f70e888d399570145ed884353e017443c675aa12731ada7c87ea14f7", - "4a45f1fc63e1a9cb9dfa44c98da2f3d20c2923e5d75ff60b2db9d1bdb0c54d51", - "b193431ee35cd32de95805e7c1c749450c47486595aae7195ea6b6019a64fd61", - "baebf36a1e35a7ed834e1c72faf44ba16c159fa47d3289ceb3ca35fefa8739b5", - "a3659bd32e05fa36c8d20dbaaed8362bf1a8a7bd116aed62d8a43a2efbdf513f", - "10d1b50881a4770ebebdd0a75589dabb931e6716747b0f65fd6b080b88c4fdb6", - "3c76b8ca5c7ce6a03320646826213f59229626bf5b9d25da0c3ec0662dcb8ff3", - "4d72a04ddeb851a68cd197ef9a92a3e2ff01fbbff638e64929dd1a9c2e150112", - "c7353d320987956075b5bc1668571c7a36c800d5598fdc4832ec6569561e15d1", - "d9e0c7c90878c20ab7639d5954756f54775404b3483407fe1b483635182734f6", - "8fca67216b7939c0824fb06c5279901a94da41da9482b000f56df9906736ee75", - "460719d7f7aa7d7438f0eaf30333484fa3bd0f233632c10ba89e6e46dd3604be", - "0421d92c8a1c79ed5d01305a3d25aaf22a8f5f9e3d4bc80da47ee16ce20465fe", - "3441d9d9c0f05820a1bb6459fc7d8ef266a1bd929e7db939a10f544efe8261ea", - "ab198a66c293586746758468c610e5d3914d4ce629147eff6dd55a31f863ff8f", - "3a1c8c16b0763f3d2c35269f454ff779d1255e954d2deaf6c040fb3f0bcdc945", - "5561c0ea3b203e173b11e6aa9d0e621a4e10b1d8b178b8fe375220806557b823", - "7656caccdc79cd8d7ce66d415cc96a718e8271c62fb35746bfc2b49faf3eebf3", - "5130594fd54c1652cf2debde2c4204573ed76555d1e26757fe345b409af1544a", - "76d1e83c71ca246d042e37ff1db181f2776265fbcfdc890ce230bfa617c9c2f0", - "89580231962624c53968c1b0095b4a2732b2a2640a19fdd7d21fd064fcc0a5ef", - "3d10d001fff44680c7417dd66ecf2e984f0baa20a9bbcea348583ba5ff210c4f", - "43754e323f0f3a1155b1852bd6edd55da86b8c4cfe3df8b33733fca50fc202b8", - "a9e7b1bb763ae6452ddcacd174993f82977d81a85206bb2ae3c842e2d8e19b4c", - "10bb07da7bc7c7757f74149eff167d528a94a253cdc694a863f4d50054c00b6d", - "28f0bc1b44658548d6e05dd16d4c2fe77f1da5d48b6774bc4263b045725d0c19", - "835fbbf1d16ba7347b6e2fc552d6e982148d29c624ea20383850df3c810fa8fc", - "8e236c56a77d7f46e41e80f7092b1a68cd8e92f6156365f41813ad1ca2c6b6f3", - "51d9c857e9238c49186e37b4eccf17a82de3d5739f026f6043798ab531456e73", - "bbddf7db6a682225301f36a9fd5b0d0121d2951753e1681295f3465352ad511f", - "2690a910c33ee37b91eb6c4e0731d1d345e2dc3b46d308503a6e85bbc242c69e", - "769ce86aa90b518b7ed382f9fdacfbed93574e18dc98fe6c342e4f9f409c2d5a", - "ba3bebec689ce51d3e12776c45f80d25164fdfb694a8122d908081aaa2e7122c", - "3a51f4146ea90a815d0d283d1ceb20b928d8b4d45875e892696986a3c0d8fb9b", - "81968a2d8fb39114342ee1da85254ec51e0608d7f0f6997c2a8354c260a71009", - ) -} - -/* -The regression test for the following invalid kademlia edge case. - -Addresses used in this test are discovered as part of the simulation network -in higher level tests for streaming. They were generated randomly. - -========================================================================= -Mon Apr 9 18:43:48 UTC 2018 KΛÐΞMLIΛ hive: queen's address: bc7f3b -population: 9 (49), MinProxBinSize: 2, MinBinSize: 2, MaxBinSize: 4 -000 2 0f49 67ff | 28 0f49 (0) 0211 (0) 07b2 (0) 0703 (0) -001 2 e84b f3a4 | 13 f3a4 (0) e84b (0) e58b (0) e60b (0) -002 1 8dba | 1 8dba (0) -003 2 a008 ad72 | 2 ad72 (0) a008 (0) -004 0 | 3 b61f (0) b27f (0) b027 (0) -============ DEPTH: 5 ========================================== -005 1 ba19 | 1 ba19 (0) -006 0 | 0 -007 1 bdd6 | 1 bdd6 (0) -008 0 | 0 -009 0 | 0 -010 0 | 0 -011 0 | 0 -012 0 | 0 -013 0 | 0 -014 0 | 0 -015 0 | 0 -========================================================================= -*/ -func TestKademliaCase2(t *testing.T) { - testKademliaCase(t, - "bc7f3b6a4a7e3c91b100ca6680b6c06ff407972b88956324ca853295893e0237", "67ffb61d3aa27449d277016188f35f19e2321fbda5008c68cf6303faa080534f", "600cd54c842eadac1729c04abfc369bc244572ca76117105b9dd910283b82730", "d955a05409650de151218557425105a8aa2867bb6a0e0462fa1cf90abcf87ad6", "7a6b726de45abdf7bb3e5fd9fb0dc8932270ca4dedef92238c80c05bcdb570e3", "263e99424ebfdb652adb4e3dcd27d59e11bb7ae1c057b3ef6f390d0228006254", "ba195d1a53aafde68e661c64d39db8c2a73505bf336125c15c3560de3b48b7ed", "3458c762169937115f67cabc35a6c384ed70293a8aec37b077a6c1b8e02d510e", "4ef4dc2e28ac6efdba57e134ac24dd4e0be68b9d54f7006515eb9509105f700c", "2a8782b79b0c24b9714dfd2c8ff1932bebc08aa6520b4eaeaa59ff781238890c", "625d02e960506f4524e9cdeac85b33faf3ea437fceadbd478b62b78720cf24fc", "e051a36a8c8637f520ba259c9ed3fadaf740dadc6a04c3f0e21778ebd4cd6ac4", "e34bc014fa2504f707bb3d904872b56c2fa250bee3cb19a147a0418541f1bd90", "28036dc79add95799916893890add5d8972f3b95325a509d6ded3d448f4dc652", "1b013c407794fa2e4c955d8f51cbc6bd78588a174b6548246b291281304b5409", "34f71b68698e1534095ff23ee9c35bf64c7f12b8463e7c6f6b19c25cf03928b4", "c712c6e9bbb7076832972a95890e340b94ed735935c3c0bb788e61f011b59479", "a008d5becdcda4b9dbfdaafc3cec586cf61dcf2d4b713b6168fff02e3b9f0b08", "29de15555cdbebaab214009e416ee92f947dcec5dab9894129f50f1b17138f34", "5df9449f700bd4b5a23688b68b293f2e92fa6ca524c93bc6bb9936efba9d9ada", "3ab0168a5f87fedc6a39b53c628256ac87a98670d8691bbdaaecec22418d13a2", "1ee299b2d2a74a568494130e6869e66d57982d345c482a0e0eeb285ac219ae3b", "e0e0e3b860cea9b7a74cf1b0675cc632dc64e80a02f20bbc5e96e2e8bb670606", "dc1ba6f169b0fcdcca021dcebaf39fe5d4875e7e69b854fad65687c1d7719ec0", "d321f73e42fcfb1d3a303eddf018ca5dffdcfd5567cd5ec1212f045f6a07e47d", "070320c3da7b542e5ca8aaf6a0a53d2bb5113ed264ab1db2dceee17c729edcb1", "17d314d65fdd136b50d182d2c8f5edf16e7838c2be8cf2c00abe4b406dbcd1d8", "e60b99e0a06f7d2d99d84085f67cdf8cc22a9ae22c339365d80f90289834a2b4", "02115771e18932e1f67a45f11f5bf743c5dae97fbc477d34d35c996012420eac", "3102a40eb2e5060353dd19bf61eeec8782dd1bebfcb57f4c796912252b591827", "8dbaf231062f2dc7ddaba5f9c7761b0c21292be51bf8c2ef503f31d4a2f63f79", "b02787b713c83a9f9183216310f04251994e04c2763a9024731562e8978e7cc4", "b27fe6cd33989e10909ce794c4b0b88feae286b614a59d49a3444c1a7b51ea82", "07b2d2c94fdc6fd148fe23be2ed9eff54f5e12548f29ed8416e6860fc894466f", "e58bf9f451ef62ac44ff0a9bb0610ec0fd14d423235954f0d3695e83017cbfc4", "bdd600b91bb79d1ee0053b854de308cfaa7e2abce575ea6815a0a7b3449609c2", "0f49c93c1edc7999920b21977cedd51a763940dac32e319feb9c1df2da0f3071", "7cbf0297cd41acf655cd6f960d7aaf61479edb4189d5c001cbc730861f0deb41", "79265193778d87ad626a5f59397bc075872d7302a12634ce2451a767d0a82da2", "2fe7d705f7c370b9243dbaafe007d555ff58d218822fca49d347b12a0282457c", "e84bc0c83d05e55a0080eed41dda5a795da4b9313a4da697142e69a65834cbb3", "cc4d278bd9aa0e9fb3cd8d2e0d68fb791aab5de4b120b845c409effbed47a180", "1a2317a8646cd4b6d3c4aa4cc25f676533abb689cf180787db216880a1239ad8", "cbafd6568cf8e99076208e6b6843f5808a7087897c67aad0c54694669398f889", "7b7c8357255fc37b4dae0e1af61589035fd39ff627e0938c6b3da8b4e4ec5d23", "2b8d782c1f5bac46c922cf439f6aa79f91e9ba5ffc0020d58455188a2075b334", "b61f45af2306705740742e76197a119235584ced01ef3f7cf3d4370f6c557cd1", "2775612e7cdae2780bf494c370bdcbe69c55e4a1363b1dc79ea0135e61221cce", "f3a49bb22f40885e961299abfa697a7df690a79f067bf3a4847a3ad48d826c9f", "ad724ac218dc133c0aadf4618eae21fdd0c2f3787af279846b49e2b4f97ff167", - ) -} - -/* -The regression test for the following invalid kademlia edge case. - -Addresses used in this test are discovered as part of the simulation network -in higher level tests for streaming. They were generated randomly. - -========================================================================= -Mon Apr 9 19:04:35 UTC 2018 KΛÐΞMLIΛ hive: queen's address: b4822e -population: 8 (49), MinProxBinSize: 2, MinBinSize: 2, MaxBinSize: 4 -000 2 786c 774b | 29 774b (0) 786c (0) 7a79 (0) 7d2f (0) -001 2 d9de cf19 | 10 cf19 (0) d9de (0) d2ff (0) d2a2 (0) -002 2 8ca1 8d74 | 5 8d74 (0) 8ca1 (0) 9793 (0) 9f51 (0) -003 0 | 0 -004 0 | 3 bfac (0) bcbb (0) bde9 (0) -005 0 | 0 -============ DEPTH: 6 ========================================== -006 1 b660 | 1 b660 (0) -007 0 | 0 -008 1 b450 | 1 b450 (0) -009 0 | 0 -010 0 | 0 -011 0 | 0 -012 0 | 0 -013 0 | 0 -014 0 | 0 -015 0 | 0 -========================================================================= -*/ -func TestKademliaCase3(t *testing.T) { - testKademliaCase(t, - "b4822e874a01b94ac3a35c821e6db131e785c2fcbb3556e84b36102caf09b091", "2ecf54ea38d58f9cfc3862e54e5854a7c506fbc640e0b38e46d7d45a19794999", "442374092be50fc7392e8dd3f6fab3158ff7f14f26ff98060aed9b2eecf0b97d", "b450a4a67fcfa3b976cf023d8f1f15052b727f712198ce901630efe2f95db191", "9a7291638eb1c989a6dd6661a42c735b23ac6605b5d3e428aa5ffe650e892c85", "67f62eeab9804cfcac02b25ebeab9113d1b9d03dd5200b1c5a324cc0163e722f", "2e4a0e4b53bca4a9d7e2734150e9f579f29a255ade18a268461b20d026c9ee90", "30dd79c5fcdaa1b106f6960c45c9fde7c046aa3d931088d98c52ab759d0b2ac4", "97936fb5a581e59753c54fa5feec493714f2218245f61f97a62eafd4699433e4", "3a2899b6e129e3e193f6e2aefb82589c948c246d2ec1d4272af32ef3b2660f44", "f0e2a8aa88e67269e9952431ef12e5b29b7f41a1871fbfc38567fad95655d607", "7fa12b3f3c5f8383bfc644b958f72a486969733fa097d8952b3eb4f7b4f73192", "360c167aad5fc992656d6010ec45fdce5bcd492ad9608bc515e2be70d4e430c1", "fe21bc969b3d8e5a64a6484a829c1e04208f26f3cd4de6afcbc172a5bd17f1f1", "b660a1f40141d7ccd282fe5bd9838744119bd1cb3780498b5173578cc5ad308f", "44dcb3370e76680e2fba8cd986ad45ff0b77ca45680ee8d950e47922c4af6226", "8ca126923d17fccb689647307b89f38aa14e2a7b9ebcf3c1e31ccf3d2291a3bc", "f0ae19ae9ce6329327cbf42baf090e084c196b0877d8c7b69997e0123be23ef8", "d2a2a217385158e3e1e348883a14bc423e57daa12077e8c49797d16121ea0810", "f5467ccd85bb4ebe768527db520a210459969a5f1fae6e07b43f519799f0b224", "68be5fd9f9d142a5099e3609011fe3bab7bb992c595999e31e0b3d1668dfb3cf", "4d49a8a476e4934afc6b5c36db9bece3ed1804f20b952da5a21b2b0de766aa73", "ea7155745ef3fb2d099513887a2ba279333ced65c65facbd890ce58bd3fce772", "cf19f51f4e848053d289ac95a9138cdd23fc3077ae913cd58cda8cc7a521b2e1", "590b1cd41c7e6144e76b5cd515a3a4d0a4317624620a3f1685f43ae68bdcd890", "d2ffe0626b5f94a7e00fa0b506e7455a3d9399c15800db108d5e715ef5f6e346", "69630878c50a91f6c2edd23a706bfa0b50bd5661672a37d67bab38e6bca3b698", "445e9067079899bb5faafaca915ae6c0f6b1b730a5a628835dd827636f7feb1e", "6461c77491f1c4825958949f23c153e6e1759a5be53abbcee17c9da3867f3141", "23a235f4083771ccc207771daceda700b525a59ab586788d4f6892e69e34a6e2", "bde99f79ef41a81607ddcf92b9f95dcbc6c3537e91e8bf740e193dc73b19485e", "177957c0e5f0fbd12b88022a91768095d193830986caec8d888097d3ff4310b8", "bcbbdbaa4cdf8352422072f332e05111b732354a35c4d7c617ce1fc3b8b42a5a", "774b6717fdfb0d1629fb9d4c04a9ca40079ae2955d7f82e897477055ed017abb", "16443bf625be6d39ecaa6f114e5d2c1d47a64bfd3c13808d94b55b6b6acef2ee", "8d7495d9008066505ed00ce8198af82bfa5a6b4c08768b4c9fb3aa4eb0b0cca2", "15800849a53349508cb382959527f6c3cf1a46158ff1e6e2316b7dea7967e35f", "7a792f0f4a2b731781d1b244b2a57947f1a2e32900a1c0793449f9f7ae18a7b7", "5e517c2832c9deaa7df77c7bad4d20fd6eda2b7815e155e68bc48238fac1416f", "9f51a14f0019c72bd1d472706d8c80a18c1873c6a0663e754b60eae8094483d7", "7d2fabb565122521d22ba99fed9e5be6a458fbc93156d54db27d97a00b8c3a97", "786c9e412a7db4ec278891fa534caa9a1d1a028c631c6f3aeb9c4d96ad895c36", "3bd6341d40641c2632a5a0cd7a63553a04e251efd7195897a1d27e02a7a8bfde", "31efd1f5fb57b8cff0318d77a1a9e8d67e1d1c8d18ce90f99c3a240dff48cdc8", "d9de3e1156ce1380150948acbcfecd99c96e7f4b0bc97745f4681593d017f74f", "427a2201e09f9583cd990c03b81b58148c297d474a3b50f498d83b1c7a9414cd", "bfaca11596d3dec406a9fcf5d97536516dfe7f0e3b12078428a7e1700e25218a", "351c4770a097248a650008152d0cab5825d048bef770da7f3364f59d1e721bc0", "ee00f205d1486b2be7381d962bd2867263758e880529e4e2bfedfa613bbc0e71", "6aa3b6418d89e3348e4859c823ef4d6d7cd46aa7f7e77aba586c4214d760d8f8", - ) -} - -/* -The regression test for the following invalid kademlia edge case. - -Addresses used in this test are discovered as part of the simulation network -in higher level tests for streaming. They were generated randomly. - -========================================================================= -Mon Apr 9 19:16:25 UTC 2018 KΛÐΞMLIΛ hive: queen's address: 9a90fe -population: 8 (49), MinProxBinSize: 2, MinBinSize: 2, MaxBinSize: 4 -000 2 72ef 4e6c | 24 0b1e (0) 0d66 (0) 17f5 (0) 17e8 (0) -001 2 fc2b fa47 | 13 fa47 (0) fc2b (0) fffd (0) ecef (0) -002 2 b847 afa8 | 6 afa8 (0) ad77 (0) bb7c (0) b847 (0) -003 0 | 0 -004 0 | 4 91fc (0) 957d (0) 9482 (0) 949a (0) -============ DEPTH: 5 ========================================== -005 1 9ccf | 1 9ccf (0) -006 0 | 0 -007 1 9bb2 | 1 9bb2 (0) -008 0 | 0 -009 0 | 0 -010 0 | 0 -011 0 | 0 -012 0 | 0 -013 0 | 0 -014 0 | 0 -015 0 | 0 -========================================================================= -*/ -func TestKademliaCase4(t *testing.T) { - testKademliaCase(t, - "9a90fe3506277244549064b8c3276abb06284a199d9063a97331947f2b7da7f4", - "c19359eddef24b7be1a833b4475f212cd944263627a53f9ef4837d106c247730", "fc2b6fef99ef947f7e57c3df376891769e2a2fd83d2b8e634e0fc1e91eaa080c", "ecefc0e1a8ea7bb4b48c469e077401fce175dd75294255b96c4e54f6a2950a55", "bb7ce598efc056bba343cc2614aa3f67a575557561290b44c73a63f8f433f9f7", "55fbee6ca52dfd7f0be0db969ee8e524b654ab4f0cce7c05d83887d7d2a15460", "afa852b6b319998c6a283cc0c82d2f5b8e9410075d7700f3012761f1cfbd0f76", "36c370cfb63f2087971ba6e58d7585b04e16b8f0da335efb91554c2dd8fe191c", "6be41e029985edebc901fb77fc4fb65516b6d85086e2a98bfa3159c99391e585", "dd3cfc72ea553e7d2b28f0037a65646b30955b929d29ba4c40f4a2a811248e77", "da3a8f18e09c7b0ca235c4e33e1441a5188f1df023138bf207753ee63e768f7d", "de9e3ab4dc572d54a2d4b878329fd832bb51a149f4ce167316eeb177b61e7e01", "4e6c1ecde6ed917706257fe020a1d02d2e9d87fca4c85f0f7b132491008c5032", "72ef04b77a070e13463b3529dd312bcacfb7a12d20dc597f5ec3de0501e9b834", "3fef57186675d524ab8bb1f54ba8cb68610babca1247c0c46dbb60aed003c69d", "1d8e6b71f7a052865d6558d4ba44ad5fab7b908cc1badf5766822e1c20d0d823", "6be2f2b4ffa173014d4ec7df157d289744a2bda54bb876b264ccfa898a0da315", "b0ba3fff8643f9985c744327b0c4c869763509fd5da2de9a80a4a0a082021255", "9ccf40b9406ba2e6567101fb9b4e5334a9ec74263eff47267da266ba45e6c158", "d7347f02c180a448e60f73931845062ce00048750b584790278e9c93ef31ad81", "b68c6359a22b3bee6fecb8804311cfd816648ea31d530c9fb48e477e029d707a", "0d668a18ad7c2820214df6df95a6c855ce19fb1cb765f8ca620e45db76686d37", "3fbd2663bff65533246f1fabb9f38086854c6218aeb3dc9ac6ac73d4f0988f91", "949aa5719ca846052bfaa1b38c97b6eca3df3e24c0e0630042c6bccafbb4cdb5", "77b8a2b917bef5d54f3792183b014cca7798f713ff14fe0b2ac79b4c9f6f996d", "17e853cbd8dc00cba3cd9ffeb36f26a9f41a0eb92f80b62c2cda16771c935388", "5f682ed7a8cf2f98387c3def7c97f9f05ae39e39d393eeca3cf621268d6347f8", "ad77487eaf11fd8084ba4517a51766eb0e5b77dd3492dfa79aa3a2802fb29d20", "d247cfcacf9a8200ebaddf639f8c926ab0a001abe682f40df3785e80ed124e91", "195589442e11907eede1ee6524157f1125f68399f3170c835ff81c603b069f6c", "5b5ca0a67f3c54e7d3a6a862ef56168ec9ed1f4945e6c24de6d336b2be2e6f8c", "56430e4caa253015f1f998dce4a48a88af1953f68e94eca14f53074ae9c3e467", "0b1eed6a5bf612d1d8e08f5c546f3d12e838568fd3aa43ed4c537f10c65545d6", "7058db19a56dfff01988ac4a62e1310597f9c8d7ebde6890dadabf047d722d39", "b847380d6888ff7cd11402d086b19eccc40950b52c9d67e73cb4f8462f5df078", "df6c048419a2290ab546d527e9eeba349e7f7e1759bafe4adac507ce60ef9670", "91fc5b4b24fc3fbfea7f9a3d0f0437cb5733c0c2345d8bdffd7048d6e3b8a37b", "957d8ea51b37523952b6f5ae95462fcd4aed1483ef32cc80b69580aaeee03606", "efa82e4e91ad9ab781977400e9ac0bb9de7389aaedebdae979b73d1d3b8d72b0", "7400c9f3f3fc0cc6fe8cc37ab24b9771f44e9f78be913f73cd35fc4be030d6bd", "9bb28f4122d61f7bb56fe27ef706159fb802fef0f5de9dfa32c9c5b3183235f1", "40a8de6e98953498b806614532ea4abf8b99ad7f9719fb68203a6eae2efa5b2a", "412de0b218b8f7dcacc9205cd16ffb4eca5b838f46a2f4f9f534026061a47308", "17f56ecad51075080680ad9faa0fd8946b824d3296ddb20be07f9809fe8d1c5a", "fffd4e7ae885a41948a342b6647955a7ec8a8039039f510cff467ef597675457", "35e78e11b5ac46a29dd04ab0043136c3291f4ca56cb949ace33111ed56395463", "94824fc80230af82077c83bfc01dc9675b1f9d3d538b1e5f41c21ac753598691", "fa470ae314ca3fce493f21b423eef2a49522e09126f6f2326fa3c9cac0b344f7", "7078860b5b621b21ac7b95f9fc4739c8235ce5066a8b9bd7d938146a34fa88ec", "eea53560f0428bfd2eca4f86a5ce9dec5ff1309129a975d73465c1c9e9da71d1", - ) -} - -/* -The regression test for the following invalid kademlia edge case. - -Addresses used in this test are discovered as part of the simulation network -in higher level tests for streaming. They were generated randomly. - -========================================================================= -Mon Apr 9 19:25:18 UTC 2018 KΛÐΞMLIΛ hive: queen's address: 5dd5c7 -population: 13 (49), MinProxBinSize: 2, MinBinSize: 2, MaxBinSize: 4 -000 2 e528 fad0 | 22 fad0 (0) e528 (0) e3bb (0) ed13 (0) -001 3 3f30 18e0 1dd3 | 7 3f30 (0) 23db (0) 10b6 (0) 18e0 (0) -002 4 7c54 7804 61e4 60f9 | 10 61e4 (0) 60f9 (0) 636c (0) 7186 (0) -003 2 40ae 4bae | 5 4bae (0) 4d5c (0) 403a (0) 40ae (0) -004 0 | 0 -005 0 | 3 5808 (0) 5a0e (0) 5bdb (0) -============ DEPTH: 6 ========================================== -006 2 5f14 5f61 | 2 5f14 (0) 5f61 (0) -007 0 | 0 -008 0 | 0 -009 0 | 0 -010 0 | 0 -011 0 | 0 -012 0 | 0 -013 0 | 0 -014 0 | 0 -015 0 | 0 -========================================================================= -*/ -func TestKademliaCase5(t *testing.T) { - testKademliaCase(t, - "5dd5c77dd9006a800478fcebb02d48d4036389e7d3c8f6a83b97dbad13f4c0a9", - "78fafa0809929a1279ece089a51d12457c2d8416dff859aeb2ccc24bb50df5ec", "1dd39b1257e745f147cbbc3cadd609ccd6207c41056dbc4254bba5d2527d3ee5", "5f61dd66d4d94aec8fcc3ce0e7885c7edf30c43143fa730e2841c5d28e3cd081", "8aa8b0472cb351d967e575ad05c4b9f393e76c4b01ef4b3a54aac5283b78abc9", "4502f385152a915b438a6726ce3ea9342e7a6db91a23c2f6bee83a885ed7eb82", "718677a504249db47525e959ef1784bed167e1c46f1e0275b9c7b588e28a3758", "7c54c6ed1f8376323896ed3a4e048866410de189e9599dd89bf312ca4adb96b5", "18e03bd3378126c09e799a497150da5c24c895aedc84b6f0dbae41fc4bac081a", "23db76ac9e6e58d9f5395ca78252513a7b4118b4155f8462d3d5eec62486cadc", "40ae0e8f065e96c7adb7fa39505136401f01780481e678d718b7f6dbb2c906ec", "c1539998b8bae19d339d6bbb691f4e9daeb0e86847545229e80fe0dffe716e92", "ed139d73a2699e205574c08722ca9f030ad2d866c662f1112a276b91421c3cb9", "5bdb19584b7a36d09ca689422ef7e6bb681b8f2558a6b2177a8f7c812f631022", "636c9de7fe234ffc15d67a504c69702c719f626c17461d3f2918e924cd9d69e2", "de4455413ff9335c440d52458c6544191bd58a16d85f700c1de53b62773064ea", "de1963310849527acabc7885b6e345a56406a8f23e35e436b6d9725e69a79a83", "a80a50a467f561210a114cba6c7fb1489ed43a14d61a9edd70e2eb15c31f074d", "7804f12b8d8e6e4b375b242058242068a3809385e05df0e64973cde805cf729c", "60f9aa320c02c6f2e6370aa740cf7cea38083fa95fca8c99552cda52935c1520", "d8da963602390f6c002c00ce62a84b514edfce9ebde035b277a957264bb54d21", "8463d93256e026fe436abad44697152b9a56ac8e06a0583d318e9571b83d073c", "9a3f78fcefb9a05e40a23de55f6153d7a8b9d973ede43a380bf46bb3b3847de1", "e3bb576f4b3760b9ca6bff59326f4ebfc4a669d263fb7d67ab9797adea54ed13", "4d5cdbd6dcca5bdf819a0fe8d175dc55cc96f088d37462acd5ea14bc6296bdbe", "5a0ed28de7b5258c727cb85447071c74c00a5fbba9e6bc0393bc51944d04ab2a", "61e4ddb479c283c638f4edec24353b6cc7a3a13b930824aad016b0996ca93c47", "7e3610868acf714836cafaaa7b8c009a9ac6e3a6d443e5586cf661530a204ee2", "d74b244d4345d2c86e30a097105e4fb133d53c578320285132a952cdaa64416e", "cfeed57d0f935bfab89e3f630a7c97e0b1605f0724d85a008bbfb92cb47863a8", "580837af95055670e20d494978f60c7f1458dc4b9e389fc7aa4982b2aca3bce3", "df55c0c49e6c8a83d82dfa1c307d3bf6a20e18721c80d8ec4f1f68dc0a137ced", "5f149c51ce581ba32a285439a806c063ced01ccd4211cd024e6a615b8f216f95", "1eb76b00aeb127b10dd1b7cd4c3edeb4d812b5a658f0feb13e85c4d2b7c6fe06", "7a56ba7c3fb7cbfb5561a46a75d95d7722096b45771ec16e6fa7bbfab0b35dfe", "4bae85ad88c28470f0015246d530adc0cd1778bdd5145c3c6b538ee50c4e04bd", "afd1892e2a7145c99ec0ebe9ded0d3fec21089b277a68d47f45961ec5e39e7e0", "953138885d7b36b0ef79e46030f8e61fd7037fbe5ce9e0a94d728e8c8d7eab86", "de761613ef305e4f628cb6bf97d7b7dc69a9d513dc233630792de97bcda777a6", "3f3087280063d09504c084bbf7fdf984347a72b50d097fd5b086ffabb5b3fb4c", "7d18a94bb1ebfdef4d3e454d2db8cb772f30ca57920dd1e402184a9e598581a0", "a7d6fbdc9126d9f10d10617f49fb9f5474ffe1b229f76b7dd27cebba30eccb5d", "fad0246303618353d1387ec10c09ee991eb6180697ed3470ed9a6b377695203d", "1cf66e09ea51ee5c23df26615a9e7420be2ac8063f28f60a3bc86020e94fe6f3", "8269cdaa153da7c358b0b940791af74d7c651cd4d3f5ed13acfe6d0f2c539e7f", "90d52eaaa60e74bf1c79106113f2599471a902d7b1c39ac1f55b20604f453c09", "9788fd0c09190a3f3d0541f68073a2f44c2fcc45bb97558a7c319f36c25a75b3", "10b68fc44157ecfdae238ee6c1ce0333f906ad04d1a4cb1505c8e35c3c87fbb0", "e5284117fdf3757920475c786e0004cb00ba0932163659a89b36651a01e57394", "403ad51d911e113dcd5f9ff58c94f6d278886a2a4da64c3ceca2083282c92de3", - ) + return NewPeer(bp, kad) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/network.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/network.go new file mode 100644 index 00000000..c5c7e9b2 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/network.go @@ -0,0 +1,105 @@ +package network + +import ( + "crypto/ecdsa" + "fmt" + "net" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" +) + +// BzzAddr implements the PeerAddr interface +type BzzAddr struct { + OAddr []byte + UAddr []byte +} + +// Address implements OverlayPeer interface to be used in Overlay. +func (a *BzzAddr) Address() []byte { + return a.OAddr +} + +// Over returns the overlay address. +func (a *BzzAddr) Over() []byte { + return a.OAddr +} + +// Under returns the underlay address. +func (a *BzzAddr) Under() []byte { + return a.UAddr +} + +// ID returns the node identifier in the underlay. +func (a *BzzAddr) ID() enode.ID { + n, err := enode.ParseV4(string(a.UAddr)) + if err != nil { + return enode.ID{} + } + return n.ID() +} + +// Update updates the underlay address of a peer record +func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { + return &BzzAddr{a.OAddr, na.UAddr} +} + +// String pretty prints the address +func (a *BzzAddr) String() string { + return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) +} + +// RandomAddr is a utility method generating an address from a public key +func RandomAddr() *BzzAddr { + key, err := crypto.GenerateKey() + if err != nil { + panic("unable to generate key") + } + node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303) + return NewAddr(node) +} + +// NewAddr constucts a BzzAddr from a node record. +func NewAddr(node *enode.Node) *BzzAddr { + return &BzzAddr{OAddr: node.ID().Bytes(), UAddr: []byte(node.String())} +} + +func PrivateKeyToBzzKey(prvKey *ecdsa.PrivateKey) []byte { + pubkeyBytes := crypto.FromECDSAPub(&prvKey.PublicKey) + return crypto.Keccak256Hash(pubkeyBytes).Bytes() +} + +type EnodeParams struct { + PrivateKey *ecdsa.PrivateKey + EnodeKey *ecdsa.PrivateKey + Lightnode bool + Bootnode bool +} + +func NewEnodeRecord(params *EnodeParams) (*enr.Record, error) { + + if params.PrivateKey == nil { + return nil, fmt.Errorf("all param private keys must be defined") + } + + bzzkeybytes := PrivateKeyToBzzKey(params.PrivateKey) + + var record enr.Record + record.Set(NewENRAddrEntry(bzzkeybytes)) + record.Set(ENRLightNodeEntry(params.Lightnode)) + record.Set(ENRBootNodeEntry(params.Bootnode)) + return &record, nil +} + +func NewEnode(params *EnodeParams) (*enode.Node, error) { + record, err := NewEnodeRecord(params) + if err != nil { + return nil, err + } + err = enode.SignV4(record, params.EnodeKey) + if err != nil { + return nil, fmt.Errorf("ENR create fail: %v", err) + } + return enode.New(enode.V4ID{}, record) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/networkid_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/networkid_test.go index d1d359de..9d47cf9f 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/networkid_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/networkid_test.go @@ -44,7 +44,7 @@ var ( const ( NumberOfNets = 4 - MaxTimeout = 6 + MaxTimeout = 15 * time.Second ) func init() { @@ -76,13 +76,12 @@ func TestNetworkID(t *testing.T) { if err != nil { t.Fatalf("Error setting up network: %v", err) } - defer func() { - //shutdown the snapshot network - log.Trace("Shutting down network") - net.Shutdown() - }() //let's sleep to ensure all nodes are connected time.Sleep(1 * time.Second) + // shutdown the the network to avoid race conditions + // on accessing kademlias global map while network nodes + // are accepting messages + net.Shutdown() //for each group sharing the same network ID... for _, netIDGroup := range nodeMap { log.Trace("netIDGroup size", "size", len(netIDGroup)) @@ -92,11 +91,10 @@ func TestNetworkID(t *testing.T) { if kademlias[node].addrs.Size() != len(netIDGroup)-1 { t.Fatalf("Kademlia size has not expected peer size. Kademlia size: %d, expected size: %d", kademlias[node].addrs.Size(), len(netIDGroup)-1) } - kademlias[node].EachAddr(nil, 0, func(addr *BzzAddr, _ int, _ bool) bool { + kademlias[node].EachAddr(nil, 0, func(addr *BzzAddr, _ int) bool { found := false for _, nd := range netIDGroup { - p := nd.Bytes() - if bytes.Equal(p, addr.Address()) { + if bytes.Equal(kademlias[nd].BaseAddr(), addr.Address()) { found = true } } @@ -148,7 +146,7 @@ func setupNetwork(numnodes int) (net *simulations.Network, err error) { return nil, fmt.Errorf("create node %d rpc client fail: %v", i, err) } //now setup and start event watching in order to know when we can upload - ctx, watchCancel := context.WithTimeout(context.Background(), MaxTimeout*time.Second) + ctx, watchCancel := context.WithTimeout(context.Background(), MaxTimeout) defer watchCancel() watchSubscriptionEvents(ctx, nodes[i].ID(), client, errc, quitC) //on every iteration we connect to all previous ones @@ -189,7 +187,7 @@ func newServices() adapters.Services { return k } params := NewKadParams() - params.MinProxBinSize = 2 + params.NeighbourhoodSize = 2 params.MaxBinSize = 3 params.MinBinSize = 1 params.MaxRetries = 1000 diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/priorityqueue/priorityqueue.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/priorityqueue/priorityqueue.go index 53850260..056e85ec 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/priorityqueue/priorityqueue.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/priorityqueue/priorityqueue.go @@ -28,8 +28,9 @@ package priorityqueue import ( "context" "errors" + "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" ) var ( @@ -69,13 +70,16 @@ READ: case <-ctx.Done(): return case x := <-q: - log.Trace("priority.queue f(x)", "p", p, "len(Queues[p])", len(pq.Queues[p])) - f(x) + val := x.(struct { + v interface{} + t time.Time + }) + f(val.v) + metrics.GetOrRegisterResettingTimer("pq.run", nil).UpdateSince(val.t) p = top default: if p > 0 { p-- - log.Trace("priority.queue p > 0", "p", p) continue READ } p = top @@ -83,7 +87,6 @@ READ: case <-ctx.Done(): return case <-pq.wakeup: - log.Trace("priority.queue wakeup", "p", p) } } } @@ -95,9 +98,15 @@ func (pq *PriorityQueue) Push(x interface{}, p int) error { if p < 0 || p >= len(pq.Queues) { return errBadPriority } - log.Trace("priority.queue push", "p", p, "len(Queues[p])", len(pq.Queues[p])) + val := struct { + v interface{} + t time.Time + }{ + x, + time.Now(), + } select { - case pq.Queues[p] <- x: + case pq.Queues[p] <- val: default: return ErrContention } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol.go index 66ae94a8..fcceb5c3 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol.go @@ -20,11 +20,9 @@ import ( "context" "errors" "fmt" - "net" "sync" "time" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/protocols" @@ -35,8 +33,6 @@ import ( const ( DefaultNetworkID = 3 - // ProtocolMaxMsgSize maximum allowed message size - ProtocolMaxMsgSize = 10 * 1024 * 1024 // timeout for waiting bzzHandshakeTimeout = 3000 * time.Millisecond ) @@ -44,7 +40,7 @@ const ( // BzzSpec is the spec of the generic swarm handshake var BzzSpec = &protocols.Spec{ Name: "bzz", - Version: 7, + Version: 8, MaxMsgSize: 10 * 1024 * 1024, Messages: []interface{}{ HandshakeMsg{}, @@ -54,7 +50,7 @@ var BzzSpec = &protocols.Spec{ // DiscoverySpec is the spec for the bzz discovery subprotocols var DiscoverySpec = &protocols.Spec{ Name: "hive", - Version: 6, + Version: 8, MaxMsgSize: 10 * 1024 * 1024, Messages: []interface{}{ peersMsg{}, @@ -69,6 +65,7 @@ type BzzConfig struct { HiveParams *HiveParams NetworkID uint64 LightNode bool + BootnodeMode bool } // Bzz is the swarm protocol bundle @@ -89,7 +86,7 @@ type Bzz struct { // * overlay driver // * peer store func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec *protocols.Spec, streamerRun func(*BzzPeer) error) *Bzz { - return &Bzz{ + bzz := &Bzz{ Hive: NewHive(config.HiveParams, kad, store), NetworkID: config.NetworkID, LightNode: config.LightNode, @@ -98,6 +95,13 @@ func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec *p streamerRun: streamerRun, streamerSpec: streamerSpec, } + + if config.BootnodeMode { + bzz.streamerRun = nil + bzz.streamerSpec = nil + } + + return bzz } // UpdateLocalAddr updates underlayaddress of the running node @@ -170,7 +174,7 @@ func (b *Bzz) APIs() []rpc.API { func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(*p2p.Peer, p2p.MsgReadWriter) error { return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { // wait for the bzz protocol to perform the handshake - handshake, _ := b.GetHandshake(p.ID()) + handshake, _ := b.GetOrCreateHandshake(p.ID()) defer b.removeHandshake(p.ID()) select { case <-handshake.done: @@ -215,7 +219,7 @@ func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error // runBzz is the p2p protocol run function for the bzz base protocol // that negotiates the bzz handshake func (b *Bzz) runBzz(p *p2p.Peer, rw p2p.MsgReadWriter) error { - handshake, _ := b.GetHandshake(p.ID()) + handshake, _ := b.GetOrCreateHandshake(p.ID()) if !<-handshake.init { return fmt.Errorf("%08x: bzz already started on peer %08x", b.localAddr.Over()[:4], p.ID().Bytes()[:4]) } @@ -250,11 +254,6 @@ func NewBzzPeer(p *protocols.Peer) *BzzPeer { return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())} } -// LastActive returns the time the peer was last active -func (p *BzzPeer) LastActive() time.Time { - return p.lastActive -} - // ID returns the peer's underlay node identifier. func (p *BzzPeer) ID() enode.ID { // This is here to resolve a method tie: both protocols.Peer and BzzAddr are embedded @@ -310,7 +309,7 @@ func (b *Bzz) removeHandshake(peerID enode.ID) { } // GetHandshake returns the bzz handhake that the remote peer with peerID sent -func (b *Bzz) GetHandshake(peerID enode.ID) (*HandshakeMsg, bool) { +func (b *Bzz) GetOrCreateHandshake(peerID enode.ID) (*HandshakeMsg, bool) { b.mtx.Lock() defer b.mtx.Unlock() handshake, found := b.handshakes[peerID] @@ -331,58 +330,3 @@ func (b *Bzz) GetHandshake(peerID enode.ID) (*HandshakeMsg, bool) { return handshake, found } - -// BzzAddr implements the PeerAddr interface -type BzzAddr struct { - OAddr []byte - UAddr []byte -} - -// Address implements OverlayPeer interface to be used in Overlay. -func (a *BzzAddr) Address() []byte { - return a.OAddr -} - -// Over returns the overlay address. -func (a *BzzAddr) Over() []byte { - return a.OAddr -} - -// Under returns the underlay address. -func (a *BzzAddr) Under() []byte { - return a.UAddr -} - -// ID returns the node identifier in the underlay. -func (a *BzzAddr) ID() enode.ID { - n, err := enode.ParseV4(string(a.UAddr)) - if err != nil { - return enode.ID{} - } - return n.ID() -} - -// Update updates the underlay address of a peer record -func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { - return &BzzAddr{a.OAddr, na.UAddr} -} - -// String pretty prints the address -func (a *BzzAddr) String() string { - return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) -} - -// RandomAddr is a utility method generating an address from a public key -func RandomAddr() *BzzAddr { - key, err := crypto.GenerateKey() - if err != nil { - panic("unable to generate key") - } - node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303) - return NewAddr(node) -} - -// NewAddr constucts a BzzAddr from a node record. -func NewAddr(node *enode.Node) *BzzAddr { - return &BzzAddr{OAddr: node.ID().Bytes(), UAddr: []byte(node.String())} -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol_test.go index f0d26662..1e7bb04a 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/protocol_test.go @@ -17,21 +17,24 @@ package network import ( + "crypto/ecdsa" "flag" "fmt" "os" - "sync" "testing" + "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/protocols" p2ptest "github.com/ethereum/go-ethereum/p2p/testing" ) const ( - TestProtocolVersion = 7 + TestProtocolVersion = 8 TestProtocolNetworkID = 3 ) @@ -44,31 +47,7 @@ func init() { log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) } -type testStore struct { - sync.Mutex - - values map[string][]byte -} - -func (t *testStore) Load(key string) ([]byte, error) { - t.Lock() - defer t.Unlock() - v, ok := t.values[key] - if !ok { - return nil, fmt.Errorf("key not found: %s", key) - } - return v, nil -} - -func (t *testStore) Save(key string, v []byte) error { - t.Lock() - defer t.Unlock() - t.values[key] = v - return nil -} - func HandshakeMsgExchange(lhs, rhs *HandshakeMsg, id enode.ID) []p2ptest.Exchange { - return []p2ptest.Exchange{ { Expects: []p2ptest.Expect{ @@ -91,7 +70,7 @@ func HandshakeMsgExchange(lhs, rhs *HandshakeMsg, id enode.ID) []p2ptest.Exchang } } -func newBzzBaseTester(t *testing.T, n int, addr *BzzAddr, spec *protocols.Spec, run func(*BzzPeer) error) *bzzTester { +func newBzzBaseTester(t *testing.T, n int, prvkey *ecdsa.PrivateKey, spec *protocols.Spec, run func(*BzzPeer) error) (*bzzTester, error) { cs := make(map[string]chan bool) srv := func(p *BzzPeer) error { @@ -107,9 +86,22 @@ func newBzzBaseTester(t *testing.T, n int, addr *BzzAddr, spec *protocols.Spec, return srv(&BzzPeer{Peer: protocols.NewPeer(p, rw, spec), BzzAddr: NewAddr(p.Node())}) } - s := p2ptest.NewProtocolTester(t, addr.ID(), n, protocol) + s := p2ptest.NewProtocolTester(prvkey, n, protocol) + var record enr.Record + bzzKey := PrivateKeyToBzzKey(prvkey) + record.Set(NewENRAddrEntry(bzzKey)) + err := enode.SignV4(&record, prvkey) + if err != nil { + return nil, fmt.Errorf("unable to generate ENR: %v", err) + } + nod, err := enode.New(enode.V4ID{}, &record) + if err != nil { + return nil, fmt.Errorf("unable to create enode: %v", err) + } + addr := getENRBzzAddr(nod) for _, node := range s.Nodes { + log.Warn("node", "node", node) cs[node.ID().String()] = make(chan bool) } @@ -117,7 +109,7 @@ func newBzzBaseTester(t *testing.T, n int, addr *BzzAddr, spec *protocols.Spec, addr: addr, ProtocolTester: s, cs: cs, - } + }, nil } type bzzTester struct { @@ -140,15 +132,28 @@ func newBzz(addr *BzzAddr, lightNode bool) *Bzz { return bzz } -func newBzzHandshakeTester(t *testing.T, n int, addr *BzzAddr, lightNode bool) *bzzTester { +func newBzzHandshakeTester(n int, prvkey *ecdsa.PrivateKey, lightNode bool) (*bzzTester, error) { + + var record enr.Record + bzzkey := PrivateKeyToBzzKey(prvkey) + record.Set(NewENRAddrEntry(bzzkey)) + record.Set(ENRLightNodeEntry(lightNode)) + err := enode.SignV4(&record, prvkey) + if err != nil { + return nil, err + } + nod, err := enode.New(enode.V4ID{}, &record) + addr := getENRBzzAddr(nod) + bzz := newBzz(addr, lightNode) - pt := p2ptest.NewProtocolTester(t, addr.ID(), n, bzz.runBzz) + + pt := p2ptest.NewProtocolTester(prvkey, n, bzz.runBzz) return &bzzTester{ addr: addr, ProtocolTester: pt, bzz: bzz, - } + }, nil } // should test handshakes in one exchange? parallelisation @@ -189,12 +194,18 @@ func correctBzzHandshake(addr *BzzAddr, lightNode bool) *HandshakeMsg { func TestBzzHandshakeNetworkIDMismatch(t *testing.T) { lightNode := false - addr := RandomAddr() - s := newBzzHandshakeTester(t, 1, addr, lightNode) + prvkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + s, err := newBzzHandshakeTester(1, prvkey, lightNode) + if err != nil { + t.Fatal(err) + } node := s.Nodes[0] - err := s.testHandshake( - correctBzzHandshake(addr, lightNode), + err = s.testHandshake( + correctBzzHandshake(s.addr, lightNode), &HandshakeMsg{Version: TestProtocolVersion, NetworkID: 321, Addr: NewAddr(node)}, &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): network id mismatch 321 (!= 3)")}, ) @@ -206,12 +217,18 @@ func TestBzzHandshakeNetworkIDMismatch(t *testing.T) { func TestBzzHandshakeVersionMismatch(t *testing.T) { lightNode := false - addr := RandomAddr() - s := newBzzHandshakeTester(t, 1, addr, lightNode) + prvkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + s, err := newBzzHandshakeTester(1, prvkey, lightNode) + if err != nil { + t.Fatal(err) + } node := s.Nodes[0] - err := s.testHandshake( - correctBzzHandshake(addr, lightNode), + err = s.testHandshake( + correctBzzHandshake(s.addr, lightNode), &HandshakeMsg{Version: 0, NetworkID: TestProtocolNetworkID, Addr: NewAddr(node)}, &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): version mismatch 0 (!= %d)", TestProtocolVersion)}, ) @@ -223,12 +240,18 @@ func TestBzzHandshakeVersionMismatch(t *testing.T) { func TestBzzHandshakeSuccess(t *testing.T) { lightNode := false - addr := RandomAddr() - s := newBzzHandshakeTester(t, 1, addr, lightNode) + prvkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + s, err := newBzzHandshakeTester(1, prvkey, lightNode) + if err != nil { + t.Fatal(err) + } node := s.Nodes[0] - err := s.testHandshake( - correctBzzHandshake(addr, lightNode), + err = s.testHandshake( + correctBzzHandshake(s.addr, lightNode), &HandshakeMsg{Version: TestProtocolVersion, NetworkID: TestProtocolNetworkID, Addr: NewAddr(node)}, ) @@ -248,13 +271,20 @@ func TestBzzHandshakeLightNode(t *testing.T) { for _, test := range lightNodeTests { t.Run(test.name, func(t *testing.T) { - randomAddr := RandomAddr() - pt := newBzzHandshakeTester(t, 1, randomAddr, false) + prvkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + pt, err := newBzzHandshakeTester(1, prvkey, false) + if err != nil { + t.Fatal(err) + } + node := pt.Nodes[0] addr := NewAddr(node) - err := pt.testHandshake( - correctBzzHandshake(randomAddr, false), + err = pt.testHandshake( + correctBzzHandshake(pt.addr, false), &HandshakeMsg{Version: TestProtocolVersion, NetworkID: TestProtocolNetworkID, Addr: addr, LightNode: test.lightNode}, ) @@ -262,8 +292,14 @@ func TestBzzHandshakeLightNode(t *testing.T) { t.Fatal(err) } - if pt.bzz.handshakes[node.ID()].LightNode != test.lightNode { - t.Fatalf("peer LightNode flag is %v, should be %v", pt.bzz.handshakes[node.ID()].LightNode, test.lightNode) + select { + + case <-pt.bzz.handshakes[node.ID()].done: + if pt.bzz.handshakes[node.ID()].LightNode != test.lightNode { + t.Fatalf("peer LightNode flag is %v, should be %v", pt.bzz.handshakes[node.ID()].LightNode, test.lightNode) + } + case <-time.After(10 * time.Second): + t.Fatal("test timeout") } }) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket.go index bd15ea2a..49a1f430 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket.go @@ -21,7 +21,7 @@ import "github.com/ethereum/go-ethereum/p2p/enode" // BucketKey is the type that should be used for keys in simulation buckets. type BucketKey string -// NodeItem returns an item set in ServiceFunc function for a particualar node. +// NodeItem returns an item set in ServiceFunc function for a particular node. func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool) { s.mu.Lock() defer s.mu.Unlock() diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket_test.go index 69df19bf..2273d35a 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/bucket_test.go @@ -24,7 +24,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) -// TestServiceBucket tests all bucket functionalities using subtests. +// TestServiceBucket tests all bucket functionality using subtests. // It constructs a simulation of two nodes by adding items to their buckets // in ServiceFunc constructor, then by SetNodeItem. Testing UpNodesItems // is done by stopping one node and validating availability of its items. diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/connect.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/connect.go deleted file mode 100644 index 8b2aa1bf..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/connect.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "strings" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -// ConnectToPivotNode connects the node with provided NodeID -// to the pivot node, already set by Simulation.SetPivotNode method. -// It is useful when constructing a star network topology -// when simulation adds and removes nodes dynamically. -func (s *Simulation) ConnectToPivotNode(id enode.ID) (err error) { - pid := s.PivotNodeID() - if pid == nil { - return ErrNoPivotNode - } - return s.connect(*pid, id) -} - -// ConnectToLastNode connects the node with provided NodeID -// to the last node that is up, and avoiding connection to self. -// It is useful when constructing a chain network topology -// when simulation adds and removes nodes dynamically. -func (s *Simulation) ConnectToLastNode(id enode.ID) (err error) { - ids := s.UpNodeIDs() - l := len(ids) - if l < 2 { - return nil - } - lid := ids[l-1] - if lid == id { - lid = ids[l-2] - } - return s.connect(lid, id) -} - -// ConnectToRandomNode connects the node with provieded NodeID -// to a random node that is up. -func (s *Simulation) ConnectToRandomNode(id enode.ID) (err error) { - n := s.RandomUpNode(id) - if n == nil { - return ErrNodeNotFound - } - return s.connect(n.ID, id) -} - -// ConnectNodesFull connects all nodes one to another. -// It provides a complete connectivity in the network -// which should be rarely needed. -func (s *Simulation) ConnectNodesFull(ids []enode.ID) (err error) { - if ids == nil { - ids = s.UpNodeIDs() - } - l := len(ids) - for i := 0; i < l; i++ { - for j := i + 1; j < l; j++ { - err = s.connect(ids[i], ids[j]) - if err != nil { - return err - } - } - } - return nil -} - -// ConnectNodesChain connects all nodes in a chain topology. -// If ids argument is nil, all nodes that are up will be connected. -func (s *Simulation) ConnectNodesChain(ids []enode.ID) (err error) { - if ids == nil { - ids = s.UpNodeIDs() - } - l := len(ids) - for i := 0; i < l-1; i++ { - err = s.connect(ids[i], ids[i+1]) - if err != nil { - return err - } - } - return nil -} - -// ConnectNodesRing connects all nodes in a ring topology. -// If ids argument is nil, all nodes that are up will be connected. -func (s *Simulation) ConnectNodesRing(ids []enode.ID) (err error) { - if ids == nil { - ids = s.UpNodeIDs() - } - l := len(ids) - if l < 2 { - return nil - } - for i := 0; i < l-1; i++ { - err = s.connect(ids[i], ids[i+1]) - if err != nil { - return err - } - } - return s.connect(ids[l-1], ids[0]) -} - -// ConnectNodesStar connects all nodes in a star topology -// with the center at provided NodeID. -// If ids argument is nil, all nodes that are up will be connected. -func (s *Simulation) ConnectNodesStar(id enode.ID, ids []enode.ID) (err error) { - if ids == nil { - ids = s.UpNodeIDs() - } - l := len(ids) - for i := 0; i < l; i++ { - if id == ids[i] { - continue - } - err = s.connect(id, ids[i]) - if err != nil { - return err - } - } - return nil -} - -// ConnectNodesStarPivot connects all nodes in a star topology -// with the center at already set pivot node. -// If ids argument is nil, all nodes that are up will be connected. -func (s *Simulation) ConnectNodesStarPivot(ids []enode.ID) (err error) { - id := s.PivotNodeID() - if id == nil { - return ErrNoPivotNode - } - return s.ConnectNodesStar(*id, ids) -} - -// connect connects two nodes but ignores already connected error. -func (s *Simulation) connect(oneID, otherID enode.ID) error { - return ignoreAlreadyConnectedErr(s.Net.Connect(oneID, otherID)) -} - -func ignoreAlreadyConnectedErr(err error) error { - if err == nil || strings.Contains(err.Error(), "already connected") { - return nil - } - return err -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/connect_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/connect_test.go deleted file mode 100644 index 6c94b3a0..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/connect_test.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "testing" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -func TestConnectToPivotNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - pid, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - sim.SetPivotNode(pid) - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - err = sim.ConnectToPivotNode(id) - if err != nil { - t.Fatal(err) - } - - if sim.Net.GetConn(id, pid) == nil { - t.Error("node did not connect to pivot node") - } -} - -func TestConnectToLastNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - n := 10 - - ids, err := sim.AddNodes(n) - if err != nil { - t.Fatal(err) - } - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - err = sim.ConnectToLastNode(id) - if err != nil { - t.Fatal(err) - } - - for _, i := range ids[:n-2] { - if sim.Net.GetConn(id, i) != nil { - t.Error("node connected to the node that is not the last") - } - } - - if sim.Net.GetConn(id, ids[n-1]) == nil { - t.Error("node did not connect to the last node") - } -} - -func TestConnectToRandomNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - n := 10 - - ids, err := sim.AddNodes(n) - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - err = sim.ConnectToRandomNode(ids[0]) - if err != nil { - t.Fatal(err) - } - - var cc int - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - if sim.Net.GetConn(ids[i], ids[j]) != nil { - cc++ - } - } - } - - if cc != 1 { - t.Errorf("expected one connection, got %v", cc) - } -} - -func TestConnectNodesFull(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodes(12) - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - err = sim.ConnectNodesFull(ids) - if err != nil { - t.Fatal(err) - } - - testFull(t, sim, ids) -} - -func testFull(t *testing.T, sim *Simulation, ids []enode.ID) { - n := len(ids) - var cc int - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - if sim.Net.GetConn(ids[i], ids[j]) != nil { - cc++ - } - } - } - - want := n * (n - 1) / 2 - - if cc != want { - t.Errorf("expected %v connection, got %v", want, cc) - } -} - -func TestConnectNodesChain(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodes(10) - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - err = sim.ConnectNodesChain(ids) - if err != nil { - t.Fatal(err) - } - - testChain(t, sim, ids) -} - -func testChain(t *testing.T, sim *Simulation, ids []enode.ID) { - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := sim.Net.GetConn(ids[i], ids[j]) - if i == j-1 { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func TestConnectNodesRing(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodes(10) - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - err = sim.ConnectNodesRing(ids) - if err != nil { - t.Fatal(err) - } - - testRing(t, sim, ids) -} - -func testRing(t *testing.T, sim *Simulation, ids []enode.ID) { - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := sim.Net.GetConn(ids[i], ids[j]) - if i == j-1 || (i == 0 && j == n-1) { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func TestConnectToNodesStar(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodes(10) - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - centerIndex := 2 - - err = sim.ConnectNodesStar(ids[centerIndex], ids) - if err != nil { - t.Fatal(err) - } - - testStar(t, sim, ids, centerIndex) -} - -func testStar(t *testing.T, sim *Simulation, ids []enode.ID, centerIndex int) { - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := sim.Net.GetConn(ids[i], ids[j]) - if i == centerIndex || j == centerIndex { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func TestConnectToNodesStarPivot(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodes(10) - if err != nil { - t.Fatal(err) - } - - if len(sim.Net.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - pivotIndex := 4 - - sim.SetPivotNode(ids[pivotIndex]) - - err = sim.ConnectNodesStarPivot(ids) - if err != nil { - t.Fatal(err) - } - - testStar(t, sim, ids, pivotIndex) -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events.go index 594d3622..d73c3af4 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events.go @@ -20,16 +20,18 @@ import ( "context" "sync" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations" ) // PeerEvent is the type of the channel returned by Simulation.PeerEvents. type PeerEvent struct { // NodeID is the ID of node that the event is caught on. NodeID enode.ID + // PeerID is the ID of the peer node that the event is caught on. + PeerID enode.ID // Event is the event that is caught. - Event *p2p.PeerEvent + Event *simulations.Event // Error is the error that may have happened during event watching. Error error } @@ -37,9 +39,13 @@ type PeerEvent struct { // PeerEventsFilter defines a filter on PeerEvents to exclude messages with // defined properties. Use PeerEventsFilter methods to set required options. type PeerEventsFilter struct { - t *p2p.PeerEventType - protocol *string - msgCode *uint64 + eventType simulations.EventType + + connUp *bool + + msgReceive *bool + protocol *string + msgCode *uint64 } // NewPeerEventsFilter returns a new PeerEventsFilter instance. @@ -47,20 +53,48 @@ func NewPeerEventsFilter() *PeerEventsFilter { return &PeerEventsFilter{} } -// Type sets the filter to only one peer event type. -func (f *PeerEventsFilter) Type(t p2p.PeerEventType) *PeerEventsFilter { - f.t = &t +// Connect sets the filter to events when two nodes connect. +func (f *PeerEventsFilter) Connect() *PeerEventsFilter { + f.eventType = simulations.EventTypeConn + b := true + f.connUp = &b + return f +} + +// Drop sets the filter to events when two nodes disconnect. +func (f *PeerEventsFilter) Drop() *PeerEventsFilter { + f.eventType = simulations.EventTypeConn + b := false + f.connUp = &b + return f +} + +// ReceivedMessages sets the filter to only messages that are received. +func (f *PeerEventsFilter) ReceivedMessages() *PeerEventsFilter { + f.eventType = simulations.EventTypeMsg + b := true + f.msgReceive = &b + return f +} + +// SentMessages sets the filter to only messages that are sent. +func (f *PeerEventsFilter) SentMessages() *PeerEventsFilter { + f.eventType = simulations.EventTypeMsg + b := false + f.msgReceive = &b return f } // Protocol sets the filter to only one message protocol. func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter { + f.eventType = simulations.EventTypeMsg f.protocol = &p return f } // MsgCode sets the filter to only one msg code. func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter { + f.eventType = simulations.EventTypeMsg f.msgCode = &c return f } @@ -80,19 +114,8 @@ func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ... go func(id enode.ID) { defer s.shutdownWG.Done() - client, err := s.Net.GetNode(id).Client() - if err != nil { - subsWG.Done() - eventC <- PeerEvent{NodeID: id, Error: err} - return - } - events := make(chan *p2p.PeerEvent) - sub, err := client.Subscribe(ctx, "admin", events, "peerEvents") - if err != nil { - subsWG.Done() - eventC <- PeerEvent{NodeID: id, Error: err} - return - } + events := make(chan *simulations.Event) + sub := s.Net.Events().Subscribe(events) defer sub.Unsubscribe() subsWG.Done() @@ -110,28 +133,55 @@ func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ... case <-s.Done(): return case e := <-events: + // ignore control events + if e.Control { + continue + } match := len(filters) == 0 // if there are no filters match all events for _, f := range filters { - if f.t != nil && *f.t != e.Type { - continue + if f.eventType == simulations.EventTypeConn && e.Conn != nil { + if *f.connUp != e.Conn.Up { + continue + } + // all connection filter parameters matched, break the loop + match = true + break } - if f.protocol != nil && *f.protocol != e.Protocol { - continue + if f.eventType == simulations.EventTypeMsg && e.Msg != nil { + if f.msgReceive != nil && *f.msgReceive != e.Msg.Received { + continue + } + if f.protocol != nil && *f.protocol != e.Msg.Protocol { + continue + } + if f.msgCode != nil && *f.msgCode != e.Msg.Code { + continue + } + // all message filter parameters matched, break the loop + match = true + break } - if f.msgCode != nil && e.MsgCode != nil && *f.msgCode != *e.MsgCode { - continue + } + var peerID enode.ID + switch e.Type { + case simulations.EventTypeConn: + peerID = e.Conn.One + if peerID == id { + peerID = e.Conn.Other + } + case simulations.EventTypeMsg: + peerID = e.Msg.One + if peerID == id { + peerID = e.Msg.Other } - // all filter parameters matched, break the loop - match = true - break } if match { select { - case eventC <- PeerEvent{NodeID: id, Event: e}: + case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Event: e}: case <-ctx.Done(): if err := ctx.Err(); err != nil { select { - case eventC <- PeerEvent{NodeID: id, Error: err}: + case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Error: err}: case <-s.Done(): } } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events_test.go index 0c185d97..52984481 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/events_test.go @@ -59,7 +59,7 @@ func TestPeerEvents(t *testing.T) { } }() - err = sim.ConnectNodesChain(sim.NodeIDs()) + err = sim.Net.ConnectNodesChain(sim.NodeIDs()) if err != nil { t.Fatal(err) } @@ -81,6 +81,7 @@ func TestPeerEventsTimeout(t *testing.T) { events := sim.PeerEvents(ctx, sim.NodeIDs()) done := make(chan struct{}) + errC := make(chan error) go func() { for e := range events { if e.Error == context.Canceled { @@ -90,14 +91,16 @@ func TestPeerEventsTimeout(t *testing.T) { close(done) return } else { - t.Fatal(e.Error) + errC <- e.Error } } }() select { case <-time.After(time.Second): - t.Error("no context deadline received") + t.Fatal("no context deadline received") + case err := <-errC: + t.Fatal(err) case <-done: // all good, context deadline detected } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/example_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/example_test.go index 84b0634b..9d149297 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/example_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/example_test.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network/simulation" @@ -32,8 +31,9 @@ import ( // Every node can have a Kademlia associated using the node bucket under // BucketKeyKademlia key. This allows to use WaitTillHealthy to block until -// all nodes have the their Kadmlias healthy. +// all nodes have the their Kademlias healthy. func ExampleSimulation_WaitTillHealthy() { + sim := simulation.New(map[string]simulation.ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { addr := network.NewAddr(ctx.Config.Node()) @@ -61,7 +61,7 @@ func ExampleSimulation_WaitTillHealthy() { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - ill, err := sim.WaitTillHealthy(ctx, 2) + ill, err := sim.WaitTillHealthy(ctx) if err != nil { // inspect the latest detected not healthy kademlias for id, kad := range ill { @@ -72,6 +72,7 @@ func ExampleSimulation_WaitTillHealthy() { } // continue with the test + } // Watch all peer events in the simulation network, buy receiving from a channel. @@ -87,7 +88,7 @@ func ExampleSimulation_PeerEvents() { log.Error("peer event", "err", e.Error) continue } - log.Info("peer event", "node", e.NodeID, "peer", e.Event.Peer, "msgcode", e.Event.MsgCode) + log.Info("peer event", "node", e.NodeID, "peer", e.PeerID, "type", e.Event.Type) } }() } @@ -100,7 +101,7 @@ func ExampleSimulation_PeerEvents_disconnections() { disconnections := sim.PeerEvents( context.Background(), sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), + simulation.NewPeerEventsFilter().Drop(), ) go func() { @@ -109,7 +110,7 @@ func ExampleSimulation_PeerEvents_disconnections() { log.Error("peer drop", "err", d.Error) continue } - log.Warn("peer drop", "node", d.NodeID, "peer", d.Event.Peer) + log.Warn("peer drop", "node", d.NodeID, "peer", d.PeerID) } }() } @@ -124,8 +125,8 @@ func ExampleSimulation_PeerEvents_multipleFilters() { context.Background(), sim.NodeIDs(), // Watch when bzz messages 1 and 4 are received. - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("bzz").MsgCode(1), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("bzz").MsgCode(4), + simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(1), + simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(4), ) go func() { @@ -134,7 +135,7 @@ func ExampleSimulation_PeerEvents_multipleFilters() { log.Error("bzz message", "err", m.Error) continue } - log.Info("bzz message", "node", m.NodeID, "peer", m.Event.Peer) + log.Info("bzz message", "node", m.NodeID, "peer", m.PeerID) } }() } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/http_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/http_test.go index 775cf921..dffd03a0 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/http_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/http_test.go @@ -73,7 +73,8 @@ func TestSimulationWithHTTPServer(t *testing.T) { //this time the timeout should be long enough so that it doesn't kick in too early ctx, cancel2 := context.WithTimeout(context.Background(), 5*time.Second) defer cancel2() - go sendRunSignal(t) + errC := make(chan error, 1) + go triggerSimulationRun(t, errC) result = sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { log.Debug("This run waits for the run signal from `frontend`...") //ensure with a Sleep that simulation doesn't terminate before the signal is received @@ -83,10 +84,13 @@ func TestSimulationWithHTTPServer(t *testing.T) { if result.Error != nil { t.Fatal(result.Error) } + if err := <-errC; err != nil { + t.Fatal(err) + } log.Debug("Test terminated successfully") } -func sendRunSignal(t *testing.T) { +func triggerSimulationRun(t *testing.T, errC chan error) { //We need to first wait for the sim HTTP server to start running... time.Sleep(2 * time.Second) //then we can send the signal @@ -94,16 +98,13 @@ func sendRunSignal(t *testing.T) { log.Debug("Sending run signal to simulation: POST /runsim...") resp, err := http.Post(fmt.Sprintf("http://localhost%s/runsim", DefaultHTTPSimAddr), "application/json", nil) if err != nil { - t.Fatalf("Request failed: %v", err) + errC <- fmt.Errorf("Request failed: %v", err) + return } - defer func() { - err := resp.Body.Close() - if err != nil { - log.Error("Error closing response body", "err", err) - } - }() log.Debug("Signal sent") if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) + errC <- fmt.Errorf("err %s", resp.Status) + return } + errC <- resp.Body.Close() } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia.go index f895181d..00e870a0 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia.go @@ -18,30 +18,34 @@ package simulation import ( "context" + "encoding/binary" "encoding/hex" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/swarm/network" ) // BucketKeyKademlia is the key to be used for storing the kademlia -// instance for particuar node, usually inside the ServiceFunc function. +// instance for particular node, usually inside the ServiceFunc function. var BucketKeyKademlia BucketKey = "kademlia" // WaitTillHealthy is blocking until the health of all kademlias is true. // If error is not nil, a map of kademlia that was found not healthy is returned. -func (s *Simulation) WaitTillHealthy(ctx context.Context, kadMinProxSize int) (ill map[enode.ID]*network.Kademlia, err error) { +// TODO: Check correctness since change in kademlia depth calculation logic +func (s *Simulation) WaitTillHealthy(ctx context.Context) (ill map[enode.ID]*network.Kademlia, err error) { // Prepare PeerPot map for checking Kademlia health var ppmap map[string]*network.PeerPot kademlias := s.kademlias() addrs := make([][]byte, 0, len(kademlias)) + // TODO verify that all kademlias have same params for _, k := range kademlias { addrs = append(addrs, k.BaseAddr()) } - ppmap = network.NewPeerPotMap(kadMinProxSize, addrs) + ppmap = network.NewPeerPotMap(s.neighbourhoodSize, addrs) // Wait for healthy Kademlia on every node before checking files ticker := time.NewTicker(200 * time.Millisecond) @@ -56,19 +60,19 @@ func (s *Simulation) WaitTillHealthy(ctx context.Context, kadMinProxSize int) (i for k := range ill { delete(ill, k) } - log.Debug("kademlia health check", "addr count", len(addrs)) + log.Debug("kademlia health check", "addr count", len(addrs), "kad len", len(kademlias)) for id, k := range kademlias { //PeerPot for this node addr := common.Bytes2Hex(k.BaseAddr()) pp := ppmap[addr] //call Healthy RPC - h := k.Healthy(pp) + h := k.GetHealthInfo(pp) //print info log.Debug(k.String()) - log.Debug("kademlia", "empty bins", pp.EmptyBins, "gotNN", h.GotNN, "knowNN", h.KnowNN, "full", h.Full) - log.Debug("kademlia", "health", h.GotNN && h.KnowNN && h.Full, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) - log.Debug("kademlia", "ill condition", !h.GotNN || !h.Full, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) - if !h.GotNN || !h.Full { + log.Debug("kademlia", "connectNN", h.ConnectNN, "knowNN", h.KnowNN) + log.Debug("kademlia", "health", h.ConnectNN && h.KnowNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) + log.Debug("kademlia", "ill condition", !h.ConnectNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) + if !h.Healthy() { ill[id] = k } } @@ -83,6 +87,7 @@ func (s *Simulation) WaitTillHealthy(ctx context.Context, kadMinProxSize int) (i // in simulation bucket. func (s *Simulation) kademlias() (ks map[enode.ID]*network.Kademlia) { items := s.UpNodesItems(BucketKeyKademlia) + log.Debug("kademlia len items", "len", len(items)) ks = make(map[enode.ID]*network.Kademlia, len(items)) for id, v := range items { k, ok := v.(*network.Kademlia) @@ -93,3 +98,106 @@ func (s *Simulation) kademlias() (ks map[enode.ID]*network.Kademlia) { } return ks } + +// WaitTillSnapshotRecreated is blocking until all the connections specified +// in the snapshot are registered in the kademlia. +// It differs from WaitTillHealthy, which waits only until all the kademlias are +// healthy (it might happen even before all the connections are established). +func (s *Simulation) WaitTillSnapshotRecreated(ctx context.Context, snap *simulations.Snapshot) error { + expected := getSnapshotConnections(snap.Conns) + ticker := time.NewTicker(150 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + actual := s.getActualConnections() + if isAllDeployed(expected, actual) { + return nil + } + } + } +} + +func (s *Simulation) getActualConnections() (res []uint64) { + kademlias := s.kademlias() + for base, k := range kademlias { + k.EachConn(base[:], 256, func(p *network.Peer, _ int) bool { + res = append(res, getConnectionHash(base, p.ID())) + return true + }) + } + + // only list those connections that appear twice (both peers should recognize connection as active) + res = removeDuplicatesAndSingletons(res) + return res +} + +func getSnapshotConnections(conns []simulations.Conn) (res []uint64) { + for _, c := range conns { + res = append(res, getConnectionHash(c.One, c.Other)) + } + return res +} + +// returns an integer connection identifier (similar to 8-byte hash) +func getConnectionHash(a, b enode.ID) uint64 { + var h [8]byte + for i := 0; i < 8; i++ { + h[i] = a[i] ^ b[i] + } + res := binary.LittleEndian.Uint64(h[:]) + return res +} + +// returns true if all connections in expected are listed in actual +func isAllDeployed(expected []uint64, actual []uint64) bool { + if len(expected) == 0 { + return true + } + + exp := make([]uint64, len(expected)) + copy(exp, expected) + for _, c := range actual { + // remove value c from exp + for i := 0; i < len(exp); i++ { + if exp[i] == c { + exp = removeListElement(exp, i) + if len(exp) == 0 { + return true + } + } + } + } + return len(exp) == 0 +} + +func removeListElement(arr []uint64, i int) []uint64 { + last := len(arr) - 1 + arr[i] = arr[last] + arr = arr[:last] + return arr +} + +func removeDuplicatesAndSingletons(arr []uint64) []uint64 { + for i := 0; i < len(arr); { + found := false + for j := i + 1; j < len(arr); j++ { + if arr[i] == arr[j] { + arr = removeListElement(arr, j) // remove duplicate + found = true + break + } + } + + if found { + i++ + } else { + arr = removeListElement(arr, i) // remove singleton + } + } + + return arr +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia_test.go index 285644a0..0ac1e780 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/kademlia_test.go @@ -22,17 +22,115 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/swarm/network" ) +/* + TestWaitTillHealthy tests that we indeed get a healthy network after we wait for it. + For this to be tested, a bit of a snake tail bite needs to happen: + * First we create a first simulation + * Run it as nodes connected in a ring + * Wait until the network is healthy + * Then we create a snapshot + * With this snapshot we create a new simulation + * This simulation is expected to have a healthy configuration, as it uses the snapshot + * Thus we just iterate all nodes and check that their kademlias are healthy + * If all kademlias are healthy, the test succeeded, otherwise it failed +*/ func TestWaitTillHealthy(t *testing.T) { - sim := New(map[string]ServiceFunc{ + + testNodesNum := 10 + + // create the first simulation + sim := New(createSimServiceMap(true)) + + // connect and... + nodeIDs, err := sim.AddNodesAndConnectRing(testNodesNum) + if err != nil { + t.Fatal(err) + } + + // array of all overlay addresses + var addrs [][]byte + // iterate once to be able to build the peer map + for _, node := range nodeIDs { + //get the kademlia overlay address from this ID + a := node.Bytes() + //append it to the array of all overlay addresses + addrs = append(addrs, a) + } + // build a PeerPot only once + pp := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) + + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + // ...wait until healthy + ill, err := sim.WaitTillHealthy(ctx) + if err != nil { + for id, kad := range ill { + t.Log("Node", id) + t.Log(kad.String()) + } + t.Fatal(err) + } + + // now create a snapshot of this network + snap, err := sim.Net.Snapshot() + if err != nil { + t.Fatal(err) + } + + // close the initial simulation + sim.Close() + // create a control simulation + controlSim := New(createSimServiceMap(false)) + defer controlSim.Close() + + // load the snapshot into this control simulation + err = controlSim.Net.Load(snap) + if err != nil { + t.Fatal(err) + } + _, err = controlSim.WaitTillHealthy(ctx) + if err != nil { + t.Fatal(err) + } + + for _, node := range nodeIDs { + // ...get its kademlia + item, ok := controlSim.NodeItem(node, BucketKeyKademlia) + if !ok { + t.Fatal("No kademlia bucket item") + } + kad := item.(*network.Kademlia) + // get its base address + kid := common.Bytes2Hex(kad.BaseAddr()) + + //get the health info + info := kad.GetHealthInfo(pp[kid]) + log.Trace("Health info", "info", info) + // check that it is healthy + healthy := info.Healthy() + if !healthy { + t.Fatalf("Expected node %v of control simulation to be healthy, but it is not, unhealthy kademlias: %v", node, kad.String()) + } + } +} + +// createSimServiceMap returns the services map +// this function will create the sim services with or without discovery enabled +// based on the flag passed +func createSimServiceMap(discovery bool) map[string]ServiceFunc { + return map[string]ServiceFunc{ "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { addr := network.NewAddr(ctx.Config.Node()) hp := network.NewHiveParams() - hp.Discovery = false + hp.Discovery = discovery config := &network.BzzConfig{ OverlayAddr: addr.Over(), UnderlayAddr: addr.Under(), @@ -44,24 +142,168 @@ func TestWaitTillHealthy(t *testing.T) { b.Store(BucketKeyKademlia, kad) return network.NewBzz(config, kad, nil, nil, nil), nil, nil }, - }) - defer sim.Close() + } +} - _, err := sim.AddNodesAndConnectRing(10) +// TestWaitTillSnapshotRecreated tests that we indeed have a network +// configuration specified in the snapshot file, after we wait for it. +// +// First we create a first simulation +// Run it as nodes connected in a ring +// Wait until the network is healthy +// Then we create a snapshot +// With this snapshot we create a new simulation +// Call WaitTillSnapshotRecreated() function and wait until it returns +// Iterate the nodes and check if all the connections are successfully recreated +func TestWaitTillSnapshotRecreated(t *testing.T) { + var err error + sim := New(createSimServiceMap(true)) + _, err = sim.AddNodesAndConnectRing(16) + if err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + _, err = sim.WaitTillHealthy(ctx) if err != nil { t.Fatal(err) } - ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) - defer cancel() - ill, err := sim.WaitTillHealthy(ctx, 2) + originalConnections := sim.getActualConnections() + snap, err := sim.Net.Snapshot() + sim.Close() if err != nil { - for id, kad := range ill { - t.Log("Node", id) - t.Log(kad.String()) - } - if err != nil { - t.Fatal(err) + t.Fatal(err) + } + + controlSim := New(createSimServiceMap(false)) + defer controlSim.Close() + err = controlSim.Net.Load(snap) + if err != nil { + t.Fatal(err) + } + err = controlSim.WaitTillSnapshotRecreated(ctx, snap) + if err != nil { + t.Fatal(err) + } + controlConnections := controlSim.getActualConnections() + + for _, c := range originalConnections { + if !exist(controlConnections, c) { + t.Fatal("connection was not recreated") } } } + +// exist returns true if val is found in arr +func exist(arr []uint64, val uint64) bool { + for _, c := range arr { + if c == val { + return true + } + } + return false +} + +func TestRemoveDuplicatesAndSingletons(t *testing.T) { + singletons := []uint64{ + 0x3c127c6f6cb026b0, + 0x0f45190d72e71fc5, + 0xb0184c02449e0bb6, + 0xa85c7b84239c54d3, + 0xe3b0c44298fc1c14, + 0x9afbf4c8996fb924, + 0x27ae41e4649b934c, + 0xa495991b7852b855, + } + + doubles := []uint64{ + 0x1b879f878de7fc7a, + 0xc6791470521bdab4, + 0xdd34b0ee39bbccc6, + 0x4d904fbf0f31da10, + 0x6403c2560432c8f8, + 0x18954e33cf3ad847, + 0x90db00e98dc7a8a6, + 0x92886b0dfcc1809b, + } + + var arr []uint64 + arr = append(arr, doubles...) + arr = append(arr, singletons...) + arr = append(arr, doubles...) + arr = removeDuplicatesAndSingletons(arr) + + for _, i := range singletons { + if exist(arr, i) { + t.Fatalf("singleton not removed: %d", i) + } + } + + for _, i := range doubles { + if !exist(arr, i) { + t.Fatalf("wrong value removed: %d", i) + } + } + + for j := 0; j < len(doubles); j++ { + v := doubles[j] + singletons[j] + if exist(arr, v) { + t.Fatalf("non-existing value found, index: %d", j) + } + } +} + +func TestIsAllDeployed(t *testing.T) { + a := []uint64{ + 0x3c127c6f6cb026b0, + 0x0f45190d72e71fc5, + 0xb0184c02449e0bb6, + 0xa85c7b84239c54d3, + 0xe3b0c44298fc1c14, + 0x9afbf4c8996fb924, + 0x27ae41e4649b934c, + 0xa495991b7852b855, + } + + b := []uint64{ + 0x1b879f878de7fc7a, + 0xc6791470521bdab4, + 0xdd34b0ee39bbccc6, + 0x4d904fbf0f31da10, + 0x6403c2560432c8f8, + 0x18954e33cf3ad847, + 0x90db00e98dc7a8a6, + 0x92886b0dfcc1809b, + } + + var c []uint64 + c = append(c, a...) + c = append(c, b...) + + if !isAllDeployed(a, c) { + t.Fatal("isAllDeployed failed") + } + + if !isAllDeployed(b, c) { + t.Fatal("isAllDeployed failed") + } + + if isAllDeployed(c, a) { + t.Fatal("isAllDeployed failed: false positive") + } + + if isAllDeployed(c, b) { + t.Fatal("isAllDeployed failed: false positive") + } + + c = c[2:] + + if isAllDeployed(a, c) { + t.Fatal("isAllDeployed failed: false positive") + } + + if !isAllDeployed(b, c) { + t.Fatal("isAllDeployed failed") + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node.go index a916d3fc..46c2bb86 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node.go @@ -17,17 +17,26 @@ package simulation import ( + "bytes" + "context" + "crypto/ecdsa" "encoding/json" "errors" "io/ioutil" "math/rand" "os" + "sync" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/network" +) + +var ( + BucketKeyBzzPrivateKey BucketKey = "bzzprivkey" ) // NodeIDs returns NodeIDs for all nodes in the network. @@ -44,7 +53,7 @@ func (s *Simulation) NodeIDs() (ids []enode.ID) { func (s *Simulation) UpNodeIDs() (ids []enode.ID) { nodes := s.Net.GetNodes() for _, node := range nodes { - if node.Up { + if node.Up() { ids = append(ids, node.ID()) } } @@ -55,7 +64,7 @@ func (s *Simulation) UpNodeIDs() (ids []enode.ID) { func (s *Simulation) DownNodeIDs() (ids []enode.ID) { nodes := s.Net.GetNodes() for _, node := range nodes { - if !node.Up { + if !node.Up() { ids = append(ids, node.ID()) } } @@ -96,10 +105,32 @@ func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) { if len(conf.Services) == 0 { conf.Services = s.serviceNames } + + // add ENR records to the underlying node + // most importantly the bzz overlay address + // + // for now we have no way of setting bootnodes or lightnodes in sims + // so we just let them be set to false + // they should perhaps be possible to override them with AddNodeOption + bzzPrivateKey, err := BzzPrivateKeyFromConfig(conf) + if err != nil { + return enode.ID{}, err + } + + enodeParams := &network.EnodeParams{ + PrivateKey: bzzPrivateKey, + } + record, err := network.NewEnodeRecord(enodeParams) + conf.Record = *record + + // Add the bzz address to the node config node, err := s.Net.NewNodeWithConfig(conf) if err != nil { return id, err } + s.buckets[node.ID()] = new(sync.Map) + s.SetNodeItem(node.ID(), BucketKeyBzzPrivateKey, bzzPrivateKey) + return node.ID(), s.Net.Start(node.ID()) } @@ -127,7 +158,7 @@ func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (i if err != nil { return nil, err } - err = s.ConnectNodesFull(ids) + err = s.Net.ConnectNodesFull(ids) if err != nil { return nil, err } @@ -145,7 +176,7 @@ func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) ( if err != nil { return nil, err } - err = s.ConnectToLastNode(id) + err = s.Net.ConnectToLastNode(id) if err != nil { return nil, err } @@ -154,7 +185,7 @@ func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) ( return nil, err } ids = append([]enode.ID{id}, ids...) - err = s.ConnectNodesChain(ids) + err = s.Net.ConnectNodesChain(ids) if err != nil { return nil, err } @@ -171,7 +202,7 @@ func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (i if err != nil { return nil, err } - err = s.ConnectNodesRing(ids) + err = s.Net.ConnectNodesRing(ids) if err != nil { return nil, err } @@ -188,76 +219,46 @@ func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (i if err != nil { return nil, err } - err = s.ConnectNodesStar(ids[0], ids[1:]) + err = s.Net.ConnectNodesStar(ids[1:], ids[0]) if err != nil { return nil, err } return ids, nil } -//UploadSnapshot uploads a snapshot to the simulation -//This method tries to open the json file provided, applies the config to all nodes -//and then loads the snapshot into the Simulation network -func (s *Simulation) UploadSnapshot(snapshotFile string, opts ...AddNodeOption) error { +// UploadSnapshot uploads a snapshot to the simulation +// This method tries to open the json file provided, applies the config to all nodes +// and then loads the snapshot into the Simulation network +func (s *Simulation) UploadSnapshot(ctx context.Context, snapshotFile string, opts ...AddNodeOption) error { f, err := os.Open(snapshotFile) if err != nil { return err } - defer func() { - err := f.Close() - if err != nil { - log.Error("Error closing snapshot file", "err", err) - } - }() + defer f.Close() + jsonbyte, err := ioutil.ReadAll(f) if err != nil { return err } var snap simulations.Snapshot - err = json.Unmarshal(jsonbyte, &snap) - if err != nil { + if err := json.Unmarshal(jsonbyte, &snap); err != nil { return err } //the snapshot probably has the property EnableMsgEvents not set - //just in case, set it to true! - //(we need this to wait for messages before uploading) - for _, n := range snap.Nodes { - n.Node.Config.EnableMsgEvents = true - n.Node.Config.Services = s.serviceNames + //set it to true (we need this to wait for messages before uploading) + for i := range snap.Nodes { + snap.Nodes[i].Node.Config.EnableMsgEvents = true + snap.Nodes[i].Node.Config.Services = s.serviceNames for _, o := range opts { - o(n.Node.Config) + o(snap.Nodes[i].Node.Config) } } - log.Info("Waiting for p2p connections to be established...") - - //now we can load the snapshot - err = s.Net.Load(&snap) - if err != nil { + if err := s.Net.Load(&snap); err != nil { return err } - log.Info("Snapshot loaded") - return nil -} - -// SetPivotNode sets the NodeID of the network's pivot node. -// Pivot node is just a specific node that should be treated -// differently then other nodes in test. SetPivotNode and -// PivotNodeID are just a convenient functions to set and -// retrieve it. -func (s *Simulation) SetPivotNode(id enode.ID) { - s.mu.Lock() - defer s.mu.Unlock() - s.pivotNodeID = &id -} - -// PivotNodeID returns NodeID of the pivot node set by -// Simulation.SetPivotNode method. -func (s *Simulation) PivotNodeID() (id *enode.ID) { - s.mu.Lock() - defer s.mu.Unlock() - return s.pivotNodeID + return s.WaitTillSnapshotRecreated(ctx, &snap) } // StartNode starts a node by NodeID. @@ -267,27 +268,26 @@ func (s *Simulation) StartNode(id enode.ID) (err error) { // StartRandomNode starts a random node. func (s *Simulation) StartRandomNode() (id enode.ID, err error) { - n := s.randomDownNode() + n := s.Net.GetRandomDownNode() if n == nil { return id, ErrNodeNotFound } - return n.ID, s.Net.Start(n.ID) + return n.ID(), s.Net.Start(n.ID()) } // StartRandomNodes starts random nodes. func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error) { ids = make([]enode.ID, 0, count) - downIDs := s.DownNodeIDs() for i := 0; i < count; i++ { - n := s.randomNode(downIDs, ids...) + n := s.Net.GetRandomDownNode() if n == nil { return nil, ErrNodeNotFound } - err = s.Net.Start(n.ID) + err = s.Net.Start(n.ID()) if err != nil { return nil, err } - ids = append(ids, n.ID) + ids = append(ids, n.ID()) } return ids, nil } @@ -299,27 +299,26 @@ func (s *Simulation) StopNode(id enode.ID) (err error) { // StopRandomNode stops a random node. func (s *Simulation) StopRandomNode() (id enode.ID, err error) { - n := s.RandomUpNode() + n := s.Net.GetRandomUpNode() if n == nil { return id, ErrNodeNotFound } - return n.ID, s.Net.Stop(n.ID) + return n.ID(), s.Net.Stop(n.ID()) } // StopRandomNodes stops random nodes. func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) { ids = make([]enode.ID, 0, count) - upIDs := s.UpNodeIDs() for i := 0; i < count; i++ { - n := s.randomNode(upIDs, ids...) + n := s.Net.GetRandomUpNode() if n == nil { return nil, ErrNodeNotFound } - err = s.Net.Stop(n.ID) + err = s.Net.Stop(n.ID()) if err != nil { return nil, err } - ids = append(ids, n.ID) + ids = append(ids, n.ID()) } return ids, nil } @@ -329,34 +328,14 @@ func init() { rand.Seed(time.Now().UnixNano()) } -// RandomUpNode returns a random SimNode that is up. -// Arguments are NodeIDs for nodes that should not be returned. -func (s *Simulation) RandomUpNode(exclude ...enode.ID) *adapters.SimNode { - return s.randomNode(s.UpNodeIDs(), exclude...) -} - -// randomDownNode returns a random SimNode that is not up. -func (s *Simulation) randomDownNode(exclude ...enode.ID) *adapters.SimNode { - return s.randomNode(s.DownNodeIDs(), exclude...) -} - -// randomNode returns a random SimNode from the slice of NodeIDs. -func (s *Simulation) randomNode(ids []enode.ID, exclude ...enode.ID) *adapters.SimNode { - for _, e := range exclude { - var i int - for _, id := range ids { - if id == e { - ids = append(ids[:i], ids[i+1:]...) - } else { - i++ - } - } +// derive a private key for swarm for the node key +// returns the private key used to generate the bzz key +func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error) { + // pad the seed key some arbitrary data as ecdsa.GenerateKey takes 40 bytes seed data + privKeyBuf := append(crypto.FromECDSA(conf.PrivateKey), []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a}...) + bzzPrivateKey, err := ecdsa.GenerateKey(crypto.S256(), bytes.NewReader(privKeyBuf)) + if err != nil { + return nil, err } - l := len(ids) - if l == 0 { - return nil - } - n := s.Net.GetNode(ids[rand.Intn(l)]) - node, _ := n.Node.(*adapters.SimNode) - return node + return bzzPrivateKey, nil } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node_test.go index 086ab606..e1e20a0f 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/node_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/swarm/network" ) @@ -53,7 +54,7 @@ func TestUpDownNodeIDs(t *testing.T) { gotIDs = sim.UpNodeIDs() for _, id := range gotIDs { - if !sim.Net.GetNode(id).Up { + if !sim.Net.GetNode(id).Up() { t.Errorf("node %s should not be down", id) } } @@ -65,7 +66,7 @@ func TestUpDownNodeIDs(t *testing.T) { gotIDs = sim.DownNodeIDs() for _, id := range gotIDs { - if sim.Net.GetNode(id).Up { + if sim.Net.GetNode(id).Up() { t.Errorf("node %s should not be up", id) } } @@ -111,7 +112,7 @@ func TestAddNode(t *testing.T) { t.Fatal("node not found") } - if !n.Up { + if !n.Up() { t.Error("node not started") } } @@ -160,6 +161,41 @@ func TestAddNodeWithService(t *testing.T) { } } +func TestAddNodeMultipleServices(t *testing.T) { + sim := New(map[string]ServiceFunc{ + "noop1": noopServiceFunc, + "noop2": noopService2Func, + }) + defer sim.Close() + + id, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } + + n := sim.Net.GetNode(id).Node.(*adapters.SimNode) + if n.Service("noop1") == nil { + t.Error("service noop1 not found on node") + } + if n.Service("noop2") == nil { + t.Error("service noop2 not found on node") + } +} + +func TestAddNodeDuplicateServiceError(t *testing.T) { + sim := New(map[string]ServiceFunc{ + "noop1": noopServiceFunc, + "noop2": noopServiceFunc, + }) + defer sim.Close() + + wantErr := "duplicate service: *simulation.noopService" + _, err := sim.AddNode() + if err.Error() != wantErr { + t.Errorf("got error %q, want %q", err, wantErr) + } +} + func TestAddNodes(t *testing.T) { sim := New(noopServiceFuncMap) defer sim.Close() @@ -193,7 +229,7 @@ func TestAddNodesAndConnectFull(t *testing.T) { t.Fatal(err) } - testFull(t, sim, ids) + simulations.VerifyFull(t, sim.Net, ids) } func TestAddNodesAndConnectChain(t *testing.T) { @@ -212,7 +248,7 @@ func TestAddNodesAndConnectChain(t *testing.T) { t.Fatal(err) } - testChain(t, sim, sim.UpNodeIDs()) + simulations.VerifyChain(t, sim.Net, sim.UpNodeIDs()) } func TestAddNodesAndConnectRing(t *testing.T) { @@ -224,7 +260,7 @@ func TestAddNodesAndConnectRing(t *testing.T) { t.Fatal(err) } - testRing(t, sim, ids) + simulations.VerifyRing(t, sim.Net, ids) } func TestAddNodesAndConnectStar(t *testing.T) { @@ -236,7 +272,7 @@ func TestAddNodesAndConnectStar(t *testing.T) { t.Fatal(err) } - testStar(t, sim, ids, 0) + simulations.VerifyStar(t, sim.Net, ids, 0) } //To test that uploading a snapshot works @@ -253,6 +289,7 @@ func TestUploadSnapshot(t *testing.T) { HiveParams: hp, } kad := network.NewKademlia(addr.Over(), network.NewKadParams()) + b.Store(BucketKeyKademlia, kad) return network.NewBzz(config, kad, nil, nil, nil), nil, nil }, }) @@ -260,12 +297,13 @@ func TestUploadSnapshot(t *testing.T) { nodeCount := 16 log.Debug("Uploading snapshot") - err := s.UploadSnapshot(fmt.Sprintf("../stream/testing/snapshot_%d.json", nodeCount)) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + err := s.UploadSnapshot(ctx, fmt.Sprintf("../stream/testing/snapshot_%d.json", nodeCount)) if err != nil { t.Fatalf("Error uploading snapshot to simulation network: %v", err) } - ctx := context.Background() log.Debug("Starting simulation...") s.Run(ctx, func(ctx context.Context, sim *Simulation) error { log.Debug("Checking") @@ -278,45 +316,6 @@ func TestUploadSnapshot(t *testing.T) { log.Debug("Done.") } -func TestPivotNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - id2, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - if sim.PivotNodeID() != nil { - t.Error("expected no pivot node") - } - - sim.SetPivotNode(id) - - pid := sim.PivotNodeID() - - if pid == nil { - t.Error("pivot node not set") - } else if *pid != id { - t.Errorf("expected pivot node %s, got %s", id, *pid) - } - - sim.SetPivotNode(id2) - - pid = sim.PivotNodeID() - - if pid == nil { - t.Error("pivot node not set") - } else if *pid != id2 { - t.Errorf("expected pivot node %s, got %s", id2, *pid) - } -} - func TestStartStopNode(t *testing.T) { sim := New(noopServiceFuncMap) defer sim.Close() @@ -330,7 +329,7 @@ func TestStartStopNode(t *testing.T) { if n == nil { t.Fatal("node not found") } - if !n.Up { + if !n.Up() { t.Error("node not started") } @@ -338,26 +337,17 @@ func TestStartStopNode(t *testing.T) { if err != nil { t.Fatal(err) } - if n.Up { + if n.Up() { t.Error("node not stopped") } - // Sleep here to ensure that Network.watchPeerEvents defer function - // has set the `node.Up = false` before we start the node again. - // p2p/simulations/network.go:215 - // - // The same node is stopped and started again, and upon start - // watchPeerEvents is started in a goroutine. If the node is stopped - // and then very quickly started, that goroutine may be scheduled later - // then start and force `node.Up = false` in its defer function. - // This will make this test unreliable. - time.Sleep(time.Second) + waitForPeerEventPropagation() err = sim.StartNode(id) if err != nil { t.Fatal(err) } - if !n.Up { + if !n.Up() { t.Error("node not started") } } @@ -380,7 +370,7 @@ func TestStartStopRandomNode(t *testing.T) { if n == nil { t.Fatal("node not found") } - if n.Up { + if n.Up() { t.Error("node not stopped") } @@ -389,16 +379,7 @@ func TestStartStopRandomNode(t *testing.T) { t.Fatal(err) } - // Sleep here to ensure that Network.watchPeerEvents defer function - // has set the `node.Up = false` before we start the node again. - // p2p/simulations/network.go:215 - // - // The same node is stopped and started again, and upon start - // watchPeerEvents is started in a goroutine. If the node is stopped - // and then very quickly started, that goroutine may be scheduled later - // then start and force `node.Up = false` in its defer function. - // This will make this test unreliable. - time.Sleep(time.Second) + waitForPeerEventPropagation() idStarted, err := sim.StartRandomNode() if err != nil { @@ -429,21 +410,12 @@ func TestStartStopRandomNodes(t *testing.T) { if n == nil { t.Fatal("node not found") } - if n.Up { + if n.Up() { t.Error("node not stopped") } } - // Sleep here to ensure that Network.watchPeerEvents defer function - // has set the `node.Up = false` before we start the node again. - // p2p/simulations/network.go:215 - // - // The same node is stopped and started again, and upon start - // watchPeerEvents is started in a goroutine. If the node is stopped - // and then very quickly started, that goroutine may be scheduled later - // then start and force `node.Up = false` in its defer function. - // This will make this test unreliable. - time.Sleep(time.Second) + waitForPeerEventPropagation() ids, err = sim.StartRandomNodes(2) if err != nil { @@ -455,8 +427,20 @@ func TestStartStopRandomNodes(t *testing.T) { if n == nil { t.Fatal("node not found") } - if !n.Up { + if !n.Up() { t.Error("node not started") } } } + +func waitForPeerEventPropagation() { + // Sleep here to ensure that Network.watchPeerEvents defer function + // has set the `node.Up() = false` before we start the node again. + // + // The same node is stopped and started again, and upon start + // watchPeerEvents is started in a goroutine. If the node is stopped + // and then very quickly started, that goroutine may be scheduled later + // then start and force `node.Up() = false` in its defer function. + // This will make this test unreliable. + time.Sleep(1 * time.Second) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/service.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/service.go index 819602e9..0ac8149a 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/service.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/service.go @@ -39,7 +39,7 @@ func (s *Simulation) Service(name string, id enode.ID) node.Service { // RandomService returns a single Service by name on a // randomly chosen node that is up. func (s *Simulation) RandomService(name string) node.Service { - n := s.RandomUpNode() + n := s.Net.GetRandomUpNode().Node.(*adapters.SimNode) if n == nil { return nil } @@ -52,7 +52,7 @@ func (s *Simulation) Services(name string) (services map[enode.ID]node.Service) nodes := s.Net.GetNodes() services = make(map[enode.ID]node.Service) for _, node := range nodes { - if !node.Up { + if !node.Up() { continue } simNode, ok := node.Node.(*adapters.SimNode) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation.go index f6d3ce22..5787cafd 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation.go @@ -28,12 +28,12 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/network" ) // Common errors that are returned by functions in this package. var ( ErrNodeNotFound = errors.New("node not found") - ErrNoPivotNode = errors.New("no pivot node set") ) // Simulation provides methods on network, nodes and services @@ -43,13 +43,13 @@ type Simulation struct { // of p2p/simulations.Network. Net *simulations.Network - serviceNames []string - cleanupFuncs []func() - buckets map[enode.ID]*sync.Map - pivotNodeID *enode.ID - shutdownWG sync.WaitGroup - done chan struct{} - mu sync.RWMutex + serviceNames []string + cleanupFuncs []func() + buckets map[enode.ID]*sync.Map + shutdownWG sync.WaitGroup + done chan struct{} + mu sync.RWMutex + neighbourhoodSize int httpSrv *http.Server //attach a HTTP server via SimulationOptions handler *simulations.Server //HTTP handler for the server @@ -66,25 +66,35 @@ type Simulation struct { // after network shutdown. type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) -// New creates a new Simulation instance with new -// simulations.Network initialized with provided services. +// New creates a new simulation instance +// Services map must have unique keys as service names and +// every ServiceFunc must return a node.Service of the unique type. +// This restriction is required by node.Node.Start() function +// which is used to start node.Service returned by ServiceFunc. func New(services map[string]ServiceFunc) (s *Simulation) { s = &Simulation{ - buckets: make(map[enode.ID]*sync.Map), - done: make(chan struct{}), + buckets: make(map[enode.ID]*sync.Map), + done: make(chan struct{}), + neighbourhoodSize: network.NewKadParams().NeighbourhoodSize, } adapterServices := make(map[string]adapters.ServiceFunc, len(services)) for name, serviceFunc := range services { + // Scope this variables correctly + // as they will be in the adapterServices[name] function accessed later. + name, serviceFunc := name, serviceFunc s.serviceNames = append(s.serviceNames, name) adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) { - b := new(sync.Map) + s.mu.Lock() + defer s.mu.Unlock() + b, ok := s.buckets[ctx.Config.ID] + if !ok { + b = new(sync.Map) + } service, cleanup, err := serviceFunc(ctx, b) if err != nil { return nil, err } - s.mu.Lock() - defer s.mu.Unlock() if cleanup != nil { s.cleanupFuncs = append(s.cleanupFuncs, cleanup) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation_test.go index eed09bf5..1d0338f5 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulation/simulation_test.go @@ -26,10 +26,9 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - colorable "github.com/mattn/go-colorable" + "github.com/mattn/go-colorable" ) var ( @@ -125,7 +124,7 @@ func TestClose(t *testing.T) { var upNodeCount int for _, n := range sim.Net.GetNodes() { - if n.Up { + if n.Up() { upNodeCount++ } } @@ -141,7 +140,7 @@ func TestClose(t *testing.T) { upNodeCount = 0 for _, n := range sim.Net.GetNodes() { - if n.Up { + if n.Up() { upNodeCount++ } } @@ -178,30 +177,27 @@ var noopServiceFuncMap = map[string]ServiceFunc{ } // a helper function for most basic noop service -func noopServiceFunc(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { +func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { return newNoopService(), nil, nil } -// noopService is the service that does not do anything -// but implements node.Service interface. -type noopService struct{} - func newNoopService() node.Service { return &noopService{} } -func (t *noopService) Protocols() []p2p.Protocol { - return []p2p.Protocol{} +// a helper function for most basic Noop service +// of a different type then NoopService to test +// multiple services on one node. +func noopService2Func(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { + return new(noopService2), nil, nil } -func (t *noopService) APIs() []rpc.API { - return []rpc.API{} +// NoopService2 is the service that does not do anything +// but implements node.Service interface. +type noopService2 struct { + simulations.NoopService } -func (t *noopService) Start(server *p2p.Server) error { - return nil -} - -func (t *noopService) Stop() error { - return nil +type noopService struct { + simulations.NoopService } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/discovery/discovery_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/discovery/discovery_test.go index cd5456b7..99a0c772 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/discovery/discovery_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/discovery/discovery_test.go @@ -18,19 +18,18 @@ package discovery import ( "context" - "encoding/json" - "errors" "flag" "fmt" "io/ioutil" - "math/rand" "os" "path" "strings" - "sync" "testing" "time" + "github.com/ethereum/go-ethereum/swarm/testutil" + + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" @@ -45,7 +44,7 @@ import ( // serviceName is used with the exec adapter so the exec'd binary knows which // service to execute const serviceName = "discovery" -const testMinProxBinSize = 2 +const testNeighbourhoodSize = 2 const discoveryPersistenceDatadir = "discovery_persistence_test_store" var discoveryPersistencePath = path.Join(os.TempDir(), discoveryPersistenceDatadir) @@ -85,14 +84,19 @@ func getDbStore(nodeID string) (*state.DBStore, error) { } var ( - nodeCount = flag.Int("nodes", 10, "number of nodes to create (default 10)") - initCount = flag.Int("conns", 1, "number of originally connected peers (default 1)") - snapshotFile = flag.String("snapshot", "", "path to create snapshot file in") - loglevel = flag.Int("loglevel", 3, "verbosity of logs") - rawlog = flag.Bool("rawlog", false, "remove terminal formatting from logs") - serviceOverride = flag.String("services", "", "remove or add services to the node snapshot; prefix with \"+\" to add, \"-\" to remove; example: +pss,-discovery") + nodeCount = flag.Int("nodes", defaultNodeCount(), "number of nodes to create (default 32)") + initCount = flag.Int("conns", 1, "number of originally connected peers (default 1)") + loglevel = flag.Int("loglevel", 3, "verbosity of logs") + rawlog = flag.Bool("rawlog", false, "remove terminal formatting from logs") ) +func defaultNodeCount() int { + if testutil.RaceEnabled { + return 8 + } + return 32 +} + func init() { flag.Parse() // register the discovery service which will run as a devp2p @@ -244,28 +248,17 @@ func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simul action := func(ctx context.Context) error { return nil } - wg := sync.WaitGroup{} for i := range ids { // collect the overlay addresses, to addrs = append(addrs, ids[i].Bytes()) - for j := 0; j < conns; j++ { - var k int - if j == 0 { - k = (i + 1) % len(ids) - } else { - k = rand.Intn(len(ids)) - } - wg.Add(1) - go func(i, k int) { - defer wg.Done() - net.Connect(ids[i], ids[k]) - }(i, k) - } } - wg.Wait() + err := net.ConnectNodesChain(nil) + if err != nil { + return nil, err + } log.Debug(fmt.Sprintf("nodes: %v", len(addrs))) // construct the peer pot, so that kademlia health can be checked - ppmap := network.NewPeerPotMap(testMinProxBinSize, addrs) + ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) check := func(ctx context.Context, id enode.ID) (bool, error) { select { case <-ctx.Done(): @@ -281,12 +274,13 @@ func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simul if err != nil { return false, fmt.Errorf("error getting node client: %s", err) } + healthy := &network.Health{} - if err := client.Call(&healthy, "hive_healthy", ppmap[id.String()]); err != nil { + if err := client.Call(&healthy, "hive_getHealthInfo", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil { return false, fmt.Errorf("error getting node health: %s", err) } - log.Debug(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v, saturated: %v\n%v", id, healthy.GotNN, healthy.KnowNN, healthy.Full, healthy.Hive)) - return healthy.KnowNN && healthy.GotNN && healthy.Full, nil + log.Debug(fmt.Sprintf("node %4s healthy: connected nearest neighbours: %v, know nearest neighbours: %v,\n\n%v", id, healthy.ConnectNN, healthy.KnowNN, healthy.Hive)) + return healthy.KnowNN && healthy.ConnectNN, nil } // 64 nodes ~ 1min @@ -305,40 +299,6 @@ func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simul if result.Error != nil { return result, nil } - - if *snapshotFile != "" { - var err error - var snap *simulations.Snapshot - if len(*serviceOverride) > 0 { - var addServices []string - var removeServices []string - for _, osvc := range strings.Split(*serviceOverride, ",") { - if strings.Index(osvc, "+") == 0 { - addServices = append(addServices, osvc[1:]) - } else if strings.Index(osvc, "-") == 0 { - removeServices = append(removeServices, osvc[1:]) - } else { - panic("stick to the rules, you know what they are") - } - } - snap, err = net.SnapshotWithServices(addServices, removeServices) - } else { - snap, err = net.Snapshot() - } - - if err != nil { - return nil, errors.New("no shapshot dude") - } - jsonsnapshot, err := json.Marshal(snap) - if err != nil { - return nil, fmt.Errorf("corrupt json snapshot: %v", err) - } - log.Info("writing snapshot", "file", *snapshotFile) - err = ioutil.WriteFile(*snapshotFile, jsonsnapshot, 0755) - if err != nil { - return nil, err - } - } return result, nil } @@ -371,6 +331,7 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt if err := triggerChecks(trigger, net, node.ID()); err != nil { return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) } + // TODO we shouldn't be equating underaddr and overaddr like this, as they are not the same in production ids[i] = node.ID() a := ids[i].Bytes() @@ -379,7 +340,6 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt // run a simulation which connects the 10 nodes in a ring and waits // for full peer discovery - ppmap := network.NewPeerPotMap(testMinProxBinSize, addrs) var restartTime time.Time @@ -400,12 +360,18 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt } healthy := &network.Health{} addr := id.String() - if err := client.Call(&healthy, "hive_healthy", ppmap[addr]); err != nil { + ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) + if err := client.Call(&healthy, "hive_getHealthInfo", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil { return fmt.Errorf("error getting node health: %s", err) } - log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.GotNN && healthy.KnowNN && healthy.Full)) - if !healthy.GotNN || !healthy.Full { + log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.ConnectNN && healthy.KnowNN && healthy.CountKnowNN > 0)) + var nodeStr string + if err := client.Call(&nodeStr, "hive_string"); err != nil { + return fmt.Errorf("error getting node string %s", err) + } + log.Info(nodeStr) + if !healthy.ConnectNN || healthy.CountKnowNN == 0 { isHealthy = false break } @@ -444,23 +410,7 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt return nil } - //connects in a chain - wg := sync.WaitGroup{} - //connects in a ring - for i := range ids { - for j := 1; j <= conns; j++ { - k := (i + j) % len(ids) - if k == i { - k = (k + 1) % len(ids) - } - wg.Add(1) - go func(i, k int) { - defer wg.Done() - net.Connect(ids[i], ids[k]) - }(i, k) - } - } - wg.Wait() + net.ConnectNodesChain(nil) log.Debug(fmt.Sprintf("nodes: %v", len(addrs))) // construct the peer pot, so that kademlia health can be checked check := func(ctx context.Context, id enode.ID) (bool, error) { @@ -479,12 +429,14 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt return false, fmt.Errorf("error getting node client: %s", err) } healthy := &network.Health{} - if err := client.Call(&healthy, "hive_healthy", ppmap[id.String()]); err != nil { + ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) + + if err := client.Call(&healthy, "hive_getHealthInfo", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil { return false, fmt.Errorf("error getting node health: %s", err) } - log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v, saturated: %v", id, healthy.GotNN, healthy.KnowNN, healthy.Full)) + log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v", id, healthy.ConnectNN, healthy.KnowNN)) - return healthy.KnowNN && healthy.GotNN && healthy.Full, nil + return healthy.KnowNN && healthy.ConnectNN, nil } // 64 nodes ~ 1min @@ -551,7 +503,7 @@ func newService(ctx *adapters.ServiceContext) (node.Service, error) { addr := network.NewAddr(ctx.Config.Node()) kp := network.NewKadParams() - kp.MinProxBinSize = testMinProxBinSize + kp.NeighbourhoodSize = testNeighbourhoodSize if ctx.Config.Reachable != nil { kp.Reachable = func(o *network.BzzAddr) bool { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay.go index caf7ff1f..63938809 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay.go @@ -64,12 +64,12 @@ func init() { type Simulation struct { mtx sync.Mutex - stores map[enode.ID]*state.InmemoryStore + stores map[enode.ID]state.Store } func NewSimulation() *Simulation { return &Simulation{ - stores: make(map[enode.ID]*state.InmemoryStore), + stores: make(map[enode.ID]state.Store), } } @@ -86,7 +86,7 @@ func (s *Simulation) NewService(ctx *adapters.ServiceContext) (node.Service, err addr := network.NewAddr(node) kp := network.NewKadParams() - kp.MinProxBinSize = 2 + kp.NeighbourhoodSize = 2 kp.MaxBinSize = 4 kp.MinBinSize = 1 kp.MaxRetries = 1000 diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay_test.go index 6ccdb5ce..e024e2b1 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/simulations/overlay_test.go @@ -32,7 +32,7 @@ import ( ) var ( - nodeCount = 16 + nodeCount = 10 ) //This test is used to test the overlay simulation. @@ -43,7 +43,6 @@ var ( //It also provides a documentation on the steps needed by frontends //to use the simulations func TestOverlaySim(t *testing.T) { - t.Skip("Test is flaky, see: https://github.com/ethersphere/go-ethereum/issues/592") //start the simulation log.Info("Start simulation backend") //get the simulation networ; needed to subscribe for up events @@ -179,7 +178,7 @@ func watchSimEvents(net *simulations.Network, ctx context.Context, trigger chan case ev := <-events: //only catch node up events if ev.Type == simulations.EventTypeNode { - if ev.Node.Up { + if ev.Node.Up() { log.Debug("got node up event", "event", ev, "node", ev.Node.Config.ID) select { case trigger <- ev.Node.Config.ID: diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/common_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/common_test.go index 721b873b..917c440d 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/common_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/common_test.go @@ -26,19 +26,20 @@ import ( "math/rand" "os" "strings" + "sync" "sync/atomic" - "testing" "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" p2ptest "github.com/ethereum/go-ethereum/p2p/testing" "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/pot" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" - mockdb "github.com/ethereum/go-ethereum/swarm/storage/mock/db" + mockmem "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" "github.com/ethereum/go-ethereum/swarm/testutil" colorable "github.com/mattn/go-colorable" ) @@ -58,7 +59,7 @@ var ( bucketKeyRegistry = simulation.BucketKey("registry") chunkSize = 4096 - pof = pot.DefaultPof(256) + pof = network.Pof ) func init() { @@ -69,22 +70,84 @@ func init() { log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) } -func createGlobalStore() (string, *mockdb.GlobalStore, error) { - var globalStore *mockdb.GlobalStore - globalStoreDir, err := ioutil.TempDir("", "global.store") +// newNetStoreAndDelivery is a default constructor for BzzAddr, NetStore and Delivery, used in Simulations +func newNetStoreAndDelivery(ctx *adapters.ServiceContext, bucket *sync.Map) (*network.BzzAddr, *storage.NetStore, *Delivery, func(), error) { + addr := network.NewAddr(ctx.Config.Node()) + + netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) if err != nil { - log.Error("Error initiating global store temp directory!", "err", err) - return "", nil, err + return nil, nil, nil, nil, err } - globalStore, err = mockdb.NewGlobalStore(globalStoreDir) - if err != nil { - log.Error("Error initiating global store!", "err", err) - return "", nil, err - } - return globalStoreDir, globalStore, nil + + netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New + + return addr, netStore, delivery, cleanup, nil } -func newStreamerTester(t *testing.T, registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) { +// newNetStoreAndDeliveryWithBzzAddr is a constructor for NetStore and Delivery, used in Simulations, accepting any BzzAddr +func newNetStoreAndDeliveryWithBzzAddr(ctx *adapters.ServiceContext, bucket *sync.Map, addr *network.BzzAddr) (*storage.NetStore, *Delivery, func(), error) { + netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) + if err != nil { + return nil, nil, nil, err + } + + netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New + + return netStore, delivery, cleanup, nil +} + +// newNetStoreAndDeliveryWithRequestFunc is a constructor for NetStore and Delivery, used in Simulations, accepting any NetStore.RequestFunc +func newNetStoreAndDeliveryWithRequestFunc(ctx *adapters.ServiceContext, bucket *sync.Map, rf network.RequestFunc) (*network.BzzAddr, *storage.NetStore, *Delivery, func(), error) { + addr := network.NewAddr(ctx.Config.Node()) + + netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) + if err != nil { + return nil, nil, nil, nil, err + } + + netStore.NewNetFetcherFunc = network.NewFetcherFactory(rf, true).New + + return addr, netStore, delivery, cleanup, nil +} + +func netStoreAndDeliveryWithAddr(ctx *adapters.ServiceContext, bucket *sync.Map, addr *network.BzzAddr) (*storage.NetStore, *Delivery, func(), error) { + n := ctx.Config.Node() + + store, datadir, err := createTestLocalStorageForID(n.ID(), addr) + if *useMockStore { + store, datadir, err = createMockStore(mockmem.NewGlobalStore(), n.ID(), addr) + } + if err != nil { + return nil, nil, nil, err + } + localStore := store.(*storage.LocalStore) + netStore, err := storage.NewNetStore(localStore, nil) + if err != nil { + return nil, nil, nil, err + } + + fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) + + kad := network.NewKademlia(addr.Over(), network.NewKadParams()) + delivery := NewDelivery(kad, netStore) + + bucket.Store(bucketKeyStore, store) + bucket.Store(bucketKeyDB, netStore) + bucket.Store(bucketKeyDelivery, delivery) + bucket.Store(bucketKeyFileStore, fileStore) + // for the kademlia object, we use the global key from the simulation package, + // as the simulation will try to access it in the WaitTillHealthy with that key + bucket.Store(simulation.BucketKeyKademlia, kad) + + cleanup := func() { + netStore.Close() + os.RemoveAll(datadir) + } + + return netStore, delivery, cleanup, nil +} + +func newStreamerTester(registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) { // setup addr := network.RandomAddr() // tested peers peer address to := network.NewKademlia(addr.OAddr, network.NewKadParams()) @@ -92,7 +155,7 @@ func newStreamerTester(t *testing.T, registryOptions *RegistryOptions) (*p2ptest // temp datadir datadir, err := ioutil.TempDir("", "streamer") if err != nil { - return nil, nil, nil, func() {}, err + return nil, nil, nil, nil, err } removeDataDir := func() { os.RemoveAll(datadir) @@ -104,25 +167,34 @@ func newStreamerTester(t *testing.T, registryOptions *RegistryOptions) (*p2ptest localStore, err := storage.NewTestLocalStoreForAddr(params) if err != nil { - return nil, nil, nil, removeDataDir, err + removeDataDir() + return nil, nil, nil, nil, err } netStore, err := storage.NewNetStore(localStore, nil) if err != nil { - return nil, nil, nil, removeDataDir, err + removeDataDir() + return nil, nil, nil, nil, err } delivery := NewDelivery(to, netStore) netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New - streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions) + streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil) teardown := func() { streamer.Close() removeDataDir() } - protocolTester := p2ptest.NewProtocolTester(t, addr.ID(), 1, streamer.runProtocol) - - err = waitForPeers(streamer, 1*time.Second, 1) + prvkey, err := crypto.GenerateKey() if err != nil { + removeDataDir() + return nil, nil, nil, nil, err + } + + protocolTester := p2ptest.NewProtocolTester(prvkey, 1, streamer.runProtocol) + + err = waitForPeers(streamer, 10*time.Second, 1) + if err != nil { + teardown() return nil, nil, nil, nil, errors.New("timeout: peer is not created") } @@ -155,6 +227,11 @@ func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { } } +// not used in this context, only to fulfill ChunkStore interface +func (rrs *roundRobinStore) Has(ctx context.Context, addr storage.Address) bool { + panic("RoundRobinStor doesn't support HasChunk") +} + func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) { return nil, errors.New("get not well defined on round robin store") } @@ -253,3 +330,54 @@ func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.Ch } return store, datadir, nil } + +// watchDisconnections receives simulation peer events in a new goroutine and sets atomic value +// disconnected to true in case of a disconnect event. +func watchDisconnections(ctx context.Context, sim *simulation.Simulation) (disconnected *boolean) { + log.Debug("Watching for disconnections") + disconnections := sim.PeerEvents( + ctx, + sim.NodeIDs(), + simulation.NewPeerEventsFilter().Drop(), + ) + disconnected = new(boolean) + go func() { + for { + select { + case <-ctx.Done(): + return + case d := <-disconnections: + if d.Error != nil { + log.Error("peer drop event error", "node", d.NodeID, "peer", d.PeerID, "err", d.Error) + } else { + log.Error("peer drop", "node", d.NodeID, "peer", d.PeerID) + } + disconnected.set(true) + } + } + }() + return disconnected +} + +// boolean is used to concurrently set +// and read a boolean value. +type boolean struct { + v bool + mu sync.RWMutex +} + +// set sets the value. +func (b *boolean) set(v bool) { + b.mu.Lock() + defer b.mu.Unlock() + + b.v = v +} + +// bool reads the value. +func (b *boolean) bool() bool { + b.mu.RLock() + defer b.mu.RUnlock() + + return b.v +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery.go index 0109fbde..bc4f1f66 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery.go @@ -19,7 +19,6 @@ package stream import ( "context" "errors" - "fmt" "github.com/ethereum/go-ethereum/metrics" @@ -28,7 +27,9 @@ import ( "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/spancontext" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/tracing" opentracing "github.com/opentracing/opentracing-go" + olog "github.com/opentracing/opentracing-go/log" ) const ( @@ -39,6 +40,7 @@ const ( var ( processReceivedChunksCount = metrics.NewRegisteredCounter("network.stream.received_chunks.count", nil) handleRetrieveRequestMsgCount = metrics.NewRegisteredCounter("network.stream.handle_retrieve_request_msg.count", nil) + retrieveChunkFail = metrics.NewRegisteredCounter("network.stream.retrieve_chunks_fail.count", nil) requestFromPeersCount = metrics.NewRegisteredCounter("network.stream.request_from_peers.count", nil) requestFromPeersEachCount = metrics.NewRegisteredCounter("network.stream.request_from_peers_each.count", nil) @@ -143,8 +145,9 @@ func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req * var osp opentracing.Span ctx, osp = spancontext.StartSpan( ctx, - "retrieve.request") - defer osp.Finish() + "stream.handle.retrieve") + + osp.LogFields(olog.String("ref", req.Addr.String())) s, err := sp.getServer(NewStream(swarmChunkServerStreamName, "", true)) if err != nil { @@ -167,19 +170,25 @@ func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req * }() go func() { + defer osp.Finish() chunk, err := d.chunkStore.Get(ctx, req.Addr) if err != nil { - log.Warn("ChunkStore.Get can not retrieve chunk", "err", err) + retrieveChunkFail.Inc(1) + log.Debug("ChunkStore.Get can not retrieve chunk", "peer", sp.ID().String(), "addr", req.Addr, "hopcount", req.HopCount, "err", err) return } if req.SkipCheck { syncing := false + osp.LogFields(olog.Bool("skipCheck", true)) + err = sp.Deliver(ctx, chunk, s.priority, syncing) if err != nil { log.Warn("ERROR in handleRetrieveRequestMsg", "err", err) } + osp.LogFields(olog.Bool("delivered", true)) return } + osp.LogFields(olog.Bool("skipCheck", false)) select { case streamer.deliveryC <- chunk.Address()[:]: case <-streamer.quit: @@ -206,18 +215,31 @@ type ChunkDeliveryMsgRetrieval ChunkDeliveryMsg //defines a chunk delivery for syncing (without accounting) type ChunkDeliveryMsgSyncing ChunkDeliveryMsg -// TODO: Fix context SNAFU +// chunk delivery msg is response to retrieverequest msg func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error { var osp opentracing.Span ctx, osp = spancontext.StartSpan( ctx, - "chunk.delivery") - defer osp.Finish() + "handle.chunk.delivery") processReceivedChunksCount.Inc(1) + // retrieve the span for the originating retrieverequest + spanId := fmt.Sprintf("stream.send.request.%v.%v", sp.ID(), req.Addr) + span := tracing.ShiftSpanByKey(spanId) + + log.Trace("handle.chunk.delivery", "ref", req.Addr, "from peer", sp.ID()) + go func() { + defer osp.Finish() + + if span != nil { + span.LogFields(olog.String("finish", "from handleChunkDeliveryMsg")) + defer span.Finish() + } + req.peer = sp + log.Trace("handle.chunk.delivery", "put", req.Addr) err := d.chunkStore.Put(ctx, storage.NewChunk(req.Addr, req.SData)) if err != nil { if err == storage.ErrChunkInvalid { @@ -227,11 +249,14 @@ func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *Ch req.peer.Drop(err) } } + log.Trace("handle.chunk.delivery", "done put", req.Addr, "err", err) }() return nil } -// RequestFromPeers sends a chunk retrieve request to +// RequestFromPeers sends a chunk retrieve request to a peer +// The most eligible peer that hasn't already been sent to is chosen +// TODO: define "eligible" func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) (*enode.ID, chan struct{}, error) { requestFromPeersCount.Inc(1) var sp *Peer @@ -243,7 +268,7 @@ func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) ( return nil, nil, fmt.Errorf("source peer %v not found", spID.String()) } } else { - d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int, nn bool) bool { + d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int) bool { id := p.ID() if p.LightNode { // skip light nodes @@ -254,8 +279,8 @@ func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) ( return true } sp = d.getPeer(id) + // sp is nil, when we encounter a peer that is not registered for delivery, i.e. doesn't support the `stream` protocol if sp == nil { - log.Warn("Delivery.RequestFromPeers: peer not found", "id", id) return true } spID = &id @@ -266,6 +291,11 @@ func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) ( } } + // setting this value in the context creates a new span that can persist across the sendpriority queue and the network roundtrip + // this span will finish only when delivery is handled (or times out) + ctx = context.WithValue(ctx, tracing.StoreLabelId, "stream.send.request") + ctx = context.WithValue(ctx, tracing.StoreLabelMeta, fmt.Sprintf("%v.%v", sp.ID(), req.Addr)) + log.Trace("request.from.peers", "peer", sp.ID(), "ref", req.Addr) err := sp.SendPriority(ctx, &RetrieveRequestMsg{ Addr: req.Addr, SkipCheck: req.SkipCheck, diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery_test.go index c9a53011..50b78815 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/delivery_test.go @@ -19,8 +19,8 @@ package stream import ( "bytes" "context" + "errors" "fmt" - "os" "sync" "testing" "time" @@ -46,11 +46,11 @@ func TestStreamerRetrieveRequest(t *testing.T) { Retrieval: RetrievalClientOnly, Syncing: SyncingDisabled, } - tester, streamer, _, teardown, err := newStreamerTester(t, regOpts) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(regOpts) if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] @@ -95,14 +95,14 @@ func TestStreamerRetrieveRequest(t *testing.T) { //Test requesting a chunk from a peer then issuing a "empty" OfferedHashesMsg (no hashes available yet) //Should time out as the peer does not have the chunk (no syncing happened previously) func TestStreamerUpstreamRetrieveRequestMsgExchangeWithoutStore(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, &RegistryOptions{ + tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ Retrieval: RetrievalEnabled, Syncing: SyncingDisabled, //do no syncing }) - defer teardown() if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] @@ -167,14 +167,14 @@ func TestStreamerUpstreamRetrieveRequestMsgExchangeWithoutStore(t *testing.T) { // upstream request server receives a retrieve Request and responds with // offered hashes or delivery if skipHash is set to true func TestStreamerUpstreamRetrieveRequestMsgExchange(t *testing.T) { - tester, streamer, localStore, teardown, err := newStreamerTester(t, &RegistryOptions{ + tester, streamer, localStore, teardown, err := newStreamerTester(&RegistryOptions{ Retrieval: RetrievalEnabled, Syncing: SyncingDisabled, }) - defer teardown() if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] @@ -290,7 +290,7 @@ func TestRequestFromPeers(t *testing.T) { Peer: protocolsPeer, }, to) to.On(peer) - r := NewRegistry(addr.ID(), delivery, nil, nil, nil) + r := NewRegistry(addr.ID(), delivery, nil, nil, nil, nil) // an empty priorityQueue has to be created to prevent a goroutine being called after the test has finished sp := &Peer{ @@ -331,7 +331,7 @@ func TestRequestFromPeersWithLightNode(t *testing.T) { Peer: protocolsPeer, }, to) to.On(peer) - r := NewRegistry(addr.ID(), delivery, nil, nil, nil) + r := NewRegistry(addr.ID(), delivery, nil, nil, nil, nil) // an empty priorityQueue has to be created to prevent a goroutine being called after the test has finished sp := &Peer{ Peer: protocolsPeer, @@ -357,14 +357,14 @@ func TestRequestFromPeersWithLightNode(t *testing.T) { } func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) { - tester, streamer, localStore, teardown, err := newStreamerTester(t, &RegistryOptions{ + tester, streamer, localStore, teardown, err := newStreamerTester(&RegistryOptions{ Retrieval: RetrievalDisabled, Syncing: SyncingDisabled, }) - defer teardown() if err != nil { t.Fatal(err) } + defer teardown() streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { return &testClient{ @@ -442,163 +442,147 @@ func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) { } func TestDeliveryFromNodes(t *testing.T) { - testDeliveryFromNodes(t, 2, 1, dataChunkCount, true) - testDeliveryFromNodes(t, 2, 1, dataChunkCount, false) - testDeliveryFromNodes(t, 4, 1, dataChunkCount, true) - testDeliveryFromNodes(t, 4, 1, dataChunkCount, false) - testDeliveryFromNodes(t, 8, 1, dataChunkCount, true) - testDeliveryFromNodes(t, 8, 1, dataChunkCount, false) - testDeliveryFromNodes(t, 16, 1, dataChunkCount, true) - testDeliveryFromNodes(t, 16, 1, dataChunkCount, false) + testDeliveryFromNodes(t, 2, dataChunkCount, true) + testDeliveryFromNodes(t, 2, dataChunkCount, false) + testDeliveryFromNodes(t, 4, dataChunkCount, true) + testDeliveryFromNodes(t, 4, dataChunkCount, false) + + if testutil.RaceEnabled { + // Travis cannot handle more nodes with -race; would time out. + return + } + + testDeliveryFromNodes(t, 8, dataChunkCount, true) + testDeliveryFromNodes(t, 8, dataChunkCount, false) + testDeliveryFromNodes(t, 16, dataChunkCount, true) + testDeliveryFromNodes(t, 16, dataChunkCount, false) } -func testDeliveryFromNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck bool) { - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - node := ctx.Config.Node() - addr := network.NewAddr(node) - store, datadir, err := createTestLocalStorageForID(node.ID(), addr) - if err != nil { - return nil, nil, err - } - bucket.Store(bucketKeyStore, store) - cleanup = func() { - os.RemoveAll(datadir) - store.Close() - } - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - SkipCheck: skipCheck, - Syncing: SyncingDisabled, - Retrieval: RetrievalEnabled, - }) - bucket.Store(bucketKeyRegistry, r) - - fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) - bucket.Store(bucketKeyFileStore, fileStore) - - return r, cleanup, nil - - }, - }) - defer sim.Close() - - log.Info("Adding nodes to simulation") - _, err := sim.AddNodesAndConnectChain(nodes) - if err != nil { - t.Fatal(err) - } - - log.Info("Starting simulation") - ctx := context.Background() - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - nodeIDs := sim.UpNodeIDs() - //determine the pivot node to be the first node of the simulation - sim.SetPivotNode(nodeIDs[0]) - //distribute chunks of a random file into Stores of nodes 1 to nodes - //we will do this by creating a file store with an underlying round-robin store: - //the file store will create a hash for the uploaded file, but every chunk will be - //distributed to different nodes via round-robin scheduling - log.Debug("Writing file to round-robin file store") - //to do this, we create an array for chunkstores (length minus one, the pivot node) - stores := make([]storage.ChunkStore, len(nodeIDs)-1) - //we then need to get all stores from the sim.... - lStores := sim.NodesItems(bucketKeyStore) - i := 0 - //...iterate the buckets... - for id, bucketVal := range lStores { - //...and remove the one which is the pivot node - if id == *sim.PivotNodeID() { - continue - } - //the other ones are added to the array... - stores[i] = bucketVal.(storage.ChunkStore) - i++ - } - //...which then gets passed to the round-robin file store - roundRobinFileStore := storage.NewFileStore(newRoundRobinStore(stores...), storage.NewFileStoreParams()) - //now we can actually upload a (random) file to the round-robin store - size := chunkCount * chunkSize - log.Debug("Storing data to file store") - fileHash, wait, err := roundRobinFileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false) - // wait until all chunks stored - if err != nil { - return err - } - err = wait(ctx) - if err != nil { - return err - } - - log.Debug("Waiting for kademlia") - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - return err - } - - //get the pivot node's filestore - item, ok := sim.NodeItem(*sim.PivotNodeID(), bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - pivotFileStore := item.(*storage.FileStore) - log.Debug("Starting retrieval routine") - go func() { - // start the retrieval on the pivot node - this will spawn retrieve requests for missing chunks - // we must wait for the peer connections to have started before requesting - n, err := readAll(pivotFileStore, fileHash) - log.Info(fmt.Sprintf("retrieved %v", fileHash), "read", n, "err", err) - if err != nil { - t.Fatalf("requesting chunks action error: %v", err) - } - }() - - log.Debug("Watching for disconnections") - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - - go func() { - for d := range disconnections { - if d.Error != nil { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - t.Fatal(d.Error) +func testDeliveryFromNodes(t *testing.T, nodes, chunkCount int, skipCheck bool) { + t.Helper() + t.Run(fmt.Sprintf("testDeliveryFromNodes_%d_%d_skipCheck_%t", nodes, chunkCount, skipCheck), func(t *testing.T) { + sim := simulation.New(map[string]simulation.ServiceFunc{ + "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) + if err != nil { + return nil, nil, err } - } - }() - //finally check that the pivot node gets all chunks via the root hash - log.Debug("Check retrieval") - success := true - var total int64 - total, err = readAll(pivotFileStore, fileHash) + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + SkipCheck: skipCheck, + Syncing: SyncingDisabled, + Retrieval: RetrievalEnabled, + }, nil) + bucket.Store(bucketKeyRegistry, r) + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, + }) + defer sim.Close() + + log.Info("Adding nodes to simulation") + _, err := sim.AddNodesAndConnectChain(nodes) if err != nil { - return err - } - log.Info(fmt.Sprintf("check if %08x is available locally: number of bytes read %v/%v (error: %v)", fileHash, total, size, err)) - if err != nil || total != int64(size) { - success = false + t.Fatal(err) } - if !success { - return fmt.Errorf("Test failed, chunks not available on all nodes") + log.Info("Starting simulation") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { + nodeIDs := sim.UpNodeIDs() + //determine the pivot node to be the first node of the simulation + pivot := nodeIDs[0] + + //distribute chunks of a random file into Stores of nodes 1 to nodes + //we will do this by creating a file store with an underlying round-robin store: + //the file store will create a hash for the uploaded file, but every chunk will be + //distributed to different nodes via round-robin scheduling + log.Debug("Writing file to round-robin file store") + //to do this, we create an array for chunkstores (length minus one, the pivot node) + stores := make([]storage.ChunkStore, len(nodeIDs)-1) + //we then need to get all stores from the sim.... + lStores := sim.NodesItems(bucketKeyStore) + i := 0 + //...iterate the buckets... + for id, bucketVal := range lStores { + //...and remove the one which is the pivot node + if id == pivot { + continue + } + //the other ones are added to the array... + stores[i] = bucketVal.(storage.ChunkStore) + i++ + } + //...which then gets passed to the round-robin file store + roundRobinFileStore := storage.NewFileStore(newRoundRobinStore(stores...), storage.NewFileStoreParams()) + //now we can actually upload a (random) file to the round-robin store + size := chunkCount * chunkSize + log.Debug("Storing data to file store") + fileHash, wait, err := roundRobinFileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false) + // wait until all chunks stored + if err != nil { + return err + } + err = wait(ctx) + if err != nil { + return err + } + + //get the pivot node's filestore + item, ok := sim.NodeItem(pivot, bucketKeyFileStore) + if !ok { + return fmt.Errorf("No filestore") + } + pivotFileStore := item.(*storage.FileStore) + log.Debug("Starting retrieval routine") + retErrC := make(chan error) + go func() { + // start the retrieval on the pivot node - this will spawn retrieve requests for missing chunks + // we must wait for the peer connections to have started before requesting + n, err := readAll(pivotFileStore, fileHash) + log.Info(fmt.Sprintf("retrieved %v", fileHash), "read", n, "err", err) + retErrC <- err + }() + + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") + } + }() + + //finally check that the pivot node gets all chunks via the root hash + log.Debug("Check retrieval") + success := true + var total int64 + total, err = readAll(pivotFileStore, fileHash) + if err != nil { + return err + } + log.Info(fmt.Sprintf("check if %08x is available locally: number of bytes read %v/%v (error: %v)", fileHash, total, size, err)) + if err != nil || total != int64(size) { + success = false + } + + if !success { + return fmt.Errorf("Test failed, chunks not available on all nodes") + } + if err := <-retErrC; err != nil { + return fmt.Errorf("requesting chunks: %v", err) + } + log.Debug("Test terminated successfully") + return nil + }) + if result.Error != nil { + t.Fatal(result.Error) } - log.Debug("Test terminated successfully") - return nil }) - if result.Error != nil { - t.Fatal(result.Error) - } } func BenchmarkDeliveryFromNodesWithoutCheck(b *testing.B) { @@ -607,7 +591,7 @@ func BenchmarkDeliveryFromNodesWithoutCheck(b *testing.B) { b.Run( fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), func(b *testing.B) { - benchmarkDeliveryFromNodes(b, i, 1, chunks, true) + benchmarkDeliveryFromNodes(b, i, chunks, true) }, ) } @@ -620,48 +604,35 @@ func BenchmarkDeliveryFromNodesWithCheck(b *testing.B) { b.Run( fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), func(b *testing.B) { - benchmarkDeliveryFromNodes(b, i, 1, chunks, false) + benchmarkDeliveryFromNodes(b, i, chunks, false) }, ) } } } -func benchmarkDeliveryFromNodes(b *testing.B, nodes, conns, chunkCount int, skipCheck bool) { +func benchmarkDeliveryFromNodes(b *testing.B, nodes, chunkCount int, skipCheck bool) { sim := simulation.New(map[string]simulation.ServiceFunc{ "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - node := ctx.Config.Node() - addr := network.NewAddr(node) - store, datadir, err := createTestLocalStorageForID(node.ID(), addr) + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) if err != nil { return nil, nil, err } - bucket.Store(bucketKeyStore, store) - cleanup = func() { - os.RemoveAll(datadir) - store.Close() - } - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ SkipCheck: skipCheck, Syncing: SyncingDisabled, Retrieval: RetrievalDisabled, SyncUpdateDelay: 0, - }) + }, nil) + bucket.Store(bucketKeyRegistry, r) - fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) - bucket.Store(bucketKeyFileStore, fileStore) + cleanup = func() { + r.Close() + clean() + } return r, cleanup, nil - }, }) defer sim.Close() @@ -672,40 +643,33 @@ func benchmarkDeliveryFromNodes(b *testing.B, nodes, conns, chunkCount int, skip b.Fatal(err) } - ctx := context.Background() - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { nodeIDs := sim.UpNodeIDs() node := nodeIDs[len(nodeIDs)-1] item, ok := sim.NodeItem(node, bucketKeyFileStore) if !ok { - b.Fatal("No filestore") + return errors.New("No filestore") } remoteFileStore := item.(*storage.FileStore) pivotNode := nodeIDs[0] item, ok = sim.NodeItem(pivotNode, bucketKeyNetStore) if !ok { - b.Fatal("No filestore") + return errors.New("No filestore") } netStore := item.(*storage.NetStore) - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { + if _, err := sim.WaitTillHealthy(ctx); err != nil { return err } - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - - go func() { - for d := range disconnections { - if d.Error != nil { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - b.Fatal(d.Error) - } + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") } }() // benchmark loop @@ -720,12 +684,12 @@ func benchmarkDeliveryFromNodes(b *testing.B, nodes, conns, chunkCount int, skip ctx := context.TODO() hash, wait, err := remoteFileStore.Store(ctx, testutil.RandomReader(i, chunkSize), int64(chunkSize), false) if err != nil { - b.Fatalf("expected no error. got %v", err) + return fmt.Errorf("store: %v", err) } // wait until all chunks stored err = wait(ctx) if err != nil { - b.Fatalf("expected no error. got %v", err) + return fmt.Errorf("wait store: %v", err) } // collect the hashes hashes[i] = hash @@ -761,10 +725,7 @@ func benchmarkDeliveryFromNodes(b *testing.B, nodes, conns, chunkCount int, skip break Loop } } - if err != nil { - b.Fatal(err) - } - return nil + return err }) if result.Error != nil { b.Fatal(result.Error) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals/store_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals/store_test.go index 0ab14c06..a36814b7 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals/store_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals/store_test.go @@ -17,14 +17,11 @@ package intervals import ( - "errors" "testing" "github.com/ethereum/go-ethereum/swarm/state" ) -var ErrNotFound = errors.New("not found") - // TestInmemoryStore tests basic functionality of InmemoryStore. func TestInmemoryStore(t *testing.T) { testStore(t, state.NewInmemoryStore()) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals_test.go index 037984f2..009a941e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/intervals_test.go @@ -19,18 +19,16 @@ package stream import ( "context" "encoding/binary" + "errors" "fmt" - "os" "sync" "testing" "time" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network/simulation" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" @@ -53,6 +51,7 @@ func TestIntervalsLiveAndHistory(t *testing.T) { } func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { + nodes := 2 chunkCount := dataChunkCount externalStreamName := "externalStream" @@ -60,32 +59,17 @@ func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { externalStreamMaxKeys := uint64(100) sim := simulation.New(map[string]simulation.ServiceFunc{ - "intervalsStreamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - n := ctx.Config.Node() - addr := network.NewAddr(n) - store, datadir, err := createTestLocalStorageForID(n.ID(), addr) + "intervalsStreamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) { + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) if err != nil { return nil, nil, err } - bucket.Store(bucketKeyStore, store) - cleanup = func() { - store.Close() - os.RemoveAll(datadir) - } - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ Retrieval: RetrievalDisabled, Syncing: SyncingRegisterOnly, SkipCheck: skipCheck, - }) + }, nil) bucket.Store(bucketKeyRegistry, r) r.RegisterClientFunc(externalStreamName, func(p *Peer, t string, live bool) (Client, error) { @@ -95,11 +79,12 @@ func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil }) - fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams()) - bucket.Store(bucketKeyFileStore, fileStore) + cleanup := func() { + r.Close() + clean() + } return r, cleanup, nil - }, }) defer sim.Close() @@ -113,11 +98,11 @@ func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { + if _, err := sim.WaitTillHealthy(ctx); err != nil { t.Fatal(err) } - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { nodeIDs := sim.UpNodeIDs() storer := nodeIDs[0] checker := nodeIDs[1] @@ -132,13 +117,11 @@ func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { _, wait, err := fileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false) if err != nil { - log.Error("Store error: %v", "err", err) - t.Fatal(err) + return fmt.Errorf("store: %v", err) } err = wait(ctx) if err != nil { - log.Error("Wait error: %v", "err", err) - t.Fatal(err) + return fmt.Errorf("wait store: %v", err) } item, ok = sim.NodeItem(checker, bucketKeyRegistry) @@ -150,24 +133,15 @@ func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { liveErrC := make(chan error) historyErrC := make(chan error) - log.Debug("Watching for disconnections") - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - err = registry.Subscribe(storer, NewStream(externalStreamName, "", live), history, Top) if err != nil { return err } - go func() { - for d := range disconnections { - if d.Error != nil { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - t.Fatal(d.Error) - } + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") } }() diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/lightnode_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/lightnode_test.go index 65cde241..501660fa 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/lightnode_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/lightnode_test.go @@ -28,11 +28,11 @@ func TestLigthnodeRetrieveRequestWithRetrieve(t *testing.T) { Retrieval: RetrievalClientOnly, Syncing: SyncingDisabled, } - tester, _, _, teardown, err := newStreamerTester(t, registryOptions) - defer teardown() + tester, _, _, teardown, err := newStreamerTester(registryOptions) if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] @@ -67,11 +67,11 @@ func TestLigthnodeRetrieveRequestWithoutRetrieve(t *testing.T) { Retrieval: RetrievalDisabled, Syncing: SyncingDisabled, } - tester, _, _, teardown, err := newStreamerTester(t, registryOptions) - defer teardown() + tester, _, _, teardown, err := newStreamerTester(registryOptions) if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] @@ -111,11 +111,11 @@ func TestLigthnodeRequestSubscriptionWithSync(t *testing.T) { Retrieval: RetrievalDisabled, Syncing: SyncingRegisterOnly, } - tester, _, _, teardown, err := newStreamerTester(t, registryOptions) - defer teardown() + tester, _, _, teardown, err := newStreamerTester(registryOptions) if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] @@ -156,11 +156,11 @@ func TestLigthnodeRequestSubscriptionWithoutSync(t *testing.T) { Retrieval: RetrievalDisabled, Syncing: SyncingDisabled, } - tester, _, _, teardown, err := newStreamerTester(t, registryOptions) - defer teardown() + tester, _, _, teardown, err := newStreamerTester(registryOptions) if err != nil { t.Fatal(err) } + defer teardown() node := tester.Nodes[0] diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/messages.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/messages.go index eb1b2983..b293724c 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/messages.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/messages.go @@ -336,7 +336,7 @@ func (p *Peer) handleWantedHashesMsg(ctx context.Context, req *WantedHashesMsg) // launch in go routine since GetBatch blocks until new hashes arrive go func() { if err := p.SendOfferedHashes(s, req.From, req.To); err != nil { - log.Warn("SendOfferedHashes error", "err", err) + log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) } }() // go p.SendOfferedHashes(s, req.From, req.To) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/peer.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/peer.go index 4bccf56f..152814bd 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/peer.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/peer.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/swarm/spancontext" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/tracing" opentracing "github.com/opentracing/opentracing-go" ) @@ -100,20 +101,20 @@ func NewPeer(peer *protocols.Peer, streamer *Registry) *Peer { for { select { case <-ticker.C: - var len_maxi int - var cap_maxi int + var lenMaxi int + var capMaxi int for k := range pq.Queues { - if len_maxi < len(pq.Queues[k]) { - len_maxi = len(pq.Queues[k]) + if lenMaxi < len(pq.Queues[k]) { + lenMaxi = len(pq.Queues[k]) } - if cap_maxi < cap(pq.Queues[k]) { - cap_maxi = cap(pq.Queues[k]) + if capMaxi < cap(pq.Queues[k]) { + capMaxi = cap(pq.Queues[k]) } } - metrics.GetOrRegisterGauge(fmt.Sprintf("pq_len_%s", p.ID().TerminalString()), nil).Update(int64(len_maxi)) - metrics.GetOrRegisterGauge(fmt.Sprintf("pq_cap_%s", p.ID().TerminalString()), nil).Update(int64(cap_maxi)) + metrics.GetOrRegisterGauge(fmt.Sprintf("pq_len_%s", p.ID().TerminalString()), nil).Update(int64(lenMaxi)) + metrics.GetOrRegisterGauge(fmt.Sprintf("pq_cap_%s", p.ID().TerminalString()), nil).Update(int64(capMaxi)) case <-p.quit: return } @@ -122,6 +123,7 @@ func NewPeer(peer *protocols.Peer, streamer *Registry) *Peer { go func() { <-p.quit + cancel() }() return p @@ -130,7 +132,6 @@ func NewPeer(peer *protocols.Peer, streamer *Registry) *Peer { // Deliver sends a storeRequestMsg protocol message to the peer // Depending on the `syncing` parameter we send different message types func (p *Peer) Deliver(ctx context.Context, chunk storage.Chunk, priority uint8, syncing bool) error { - var sp opentracing.Span var msg interface{} spanName := "send.chunk.delivery" @@ -151,26 +152,23 @@ func (p *Peer) Deliver(ctx context.Context, chunk storage.Chunk, priority uint8, } spanName += ".retrieval" } - ctx, sp = spancontext.StartSpan( - ctx, - spanName) - defer sp.Finish() + ctx = context.WithValue(ctx, "stream_send_tag", nil) return p.SendPriority(ctx, msg, priority) } // SendPriority sends message to the peer using the outgoing priority queue func (p *Peer) SendPriority(ctx context.Context, msg interface{}, priority uint8) error { defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("peer.sendpriority_t.%d", priority), nil).UpdateSince(time.Now()) + ctx = tracing.StartSaveSpan(ctx) metrics.GetOrRegisterCounter(fmt.Sprintf("peer.sendpriority.%d", priority), nil).Inc(1) wmsg := WrappedPriorityMsg{ Context: ctx, Msg: msg, } err := p.pq.Push(wmsg, int(priority)) - if err == pq.ErrContention { - log.Warn("dropping peer on priority queue contention", "peer", p.ID()) - p.Drop(err) + if err != nil { + log.Error("err on p.pq.Push", "err", err, "peer", p.ID()) } return err } @@ -180,9 +178,12 @@ func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error { var sp opentracing.Span ctx, sp := spancontext.StartSpan( context.TODO(), - "send.offered.hashes") + "send.offered.hashes", + ) defer sp.Finish() + defer metrics.GetOrRegisterResettingTimer("send.offered.hashes", nil).UpdateSince(time.Now()) + hashes, from, to, proof, err := s.setNextBatch(f, t) if err != nil { return err @@ -205,6 +206,7 @@ func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error { Stream: s.stream, } log.Trace("Swarm syncer offer batch", "peer", p.ID(), "stream", s.stream, "len", len(hashes), "from", from, "to", to) + ctx = context.WithValue(ctx, "stream_send_tag", "send.offered.hashes") return p.SendPriority(ctx, msg, s.priority) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_retrieval_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_retrieval_test.go index ad151934..2957999f 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_retrieval_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_retrieval_test.go @@ -18,7 +18,6 @@ package stream import ( "context" "fmt" - "os" "sync" "testing" "time" @@ -27,10 +26,10 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network/simulation" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/testutil" ) //constants for random file generation @@ -45,23 +44,24 @@ const ( //Files are uploaded to nodes, other nodes try to retrieve the file //Number of nodes can be provided via commandline too. func TestFileRetrieval(t *testing.T) { + var nodeCount []int + if *nodes != 0 { - err := runFileRetrievalTest(*nodes) - if err != nil { - t.Fatal(err) - } + nodeCount = []int{*nodes} } else { - nodeCnt := []int{16} - //if the `longrunning` flag has been provided - //run more test combinations + nodeCount = []int{16} + if *longrunning { - nodeCnt = append(nodeCnt, 32, 64, 128) + nodeCount = append(nodeCount, 32, 64) + } else if testutil.RaceEnabled { + nodeCount = []int{4} } - for _, n := range nodeCnt { - err := runFileRetrievalTest(n) - if err != nil { - t.Fatal(err) - } + + } + + for _, nc := range nodeCount { + if err := runFileRetrievalTest(nc); err != nil { + t.Error(err) } } } @@ -76,72 +76,60 @@ func TestRetrieval(t *testing.T) { //if nodes/chunks have been provided via commandline, //run the tests with these values if *nodes != 0 && *chunks != 0 { - err := runRetrievalTest(*chunks, *nodes) + err := runRetrievalTest(t, *chunks, *nodes) if err != nil { t.Fatal(err) } } else { - var nodeCnt []int - var chnkCnt []int - //if the `longrunning` flag has been provided - //run more test combinations + nodeCnt := []int{16} + chnkCnt := []int{32} + if *longrunning { - nodeCnt = []int{16, 32, 128} + nodeCnt = []int{16, 32, 64} chnkCnt = []int{4, 32, 256} - } else { - //default test - nodeCnt = []int{16} - chnkCnt = []int{32} + } else if testutil.RaceEnabled { + nodeCnt = []int{4} + chnkCnt = []int{4} } + for _, n := range nodeCnt { for _, c := range chnkCnt { - err := runRetrievalTest(c, n) - if err != nil { - t.Fatal(err) - } + t.Run(fmt.Sprintf("TestRetrieval_%d_%d", n, c), func(t *testing.T) { + err := runRetrievalTest(t, c, n) + if err != nil { + t.Fatal(err) + } + }) } } } } var retrievalSimServiceMap = map[string]simulation.ServiceFunc{ - "streamer": retrievalStreamerFunc, -} + "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) + if err != nil { + return nil, nil, err + } -func retrievalStreamerFunc(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - n := ctx.Config.Node() - addr := network.NewAddr(n) - store, datadir, err := createTestLocalStorageForID(n.ID(), addr) - if err != nil { - return nil, nil, err - } - bucket.Store(bucketKeyStore, store) + syncUpdateDelay := 1 * time.Second + if *longrunning { + syncUpdateDelay = 3 * time.Second + } - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + Retrieval: RetrievalEnabled, + Syncing: SyncingAutoSubscribe, + SyncUpdateDelay: syncUpdateDelay, + }, nil) - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Retrieval: RetrievalEnabled, - Syncing: SyncingAutoSubscribe, - SyncUpdateDelay: 3 * time.Second, - }) + cleanup = func() { + r.Close() + clean() + } - fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) - bucket.Store(bucketKeyFileStore, fileStore) - - cleanup = func() { - os.RemoveAll(datadir) - netStore.Close() - r.Close() - } - - return r, cleanup, nil + return r, cleanup, nil + }, } /* @@ -156,7 +144,7 @@ func runFileRetrievalTest(nodeCount int) error { sim := simulation.New(retrievalSimServiceMap) defer sim.Close() - log.Info("Initializing test config") + log.Info("Initializing test config", "node count", nodeCount) conf := &synctestConfig{} //map of discover ID to indexes of chunks expected at that ID @@ -166,13 +154,16 @@ func runFileRetrievalTest(nodeCount int) error { //array where the generated chunk hashes will be stored conf.hashes = make([]storage.Address, 0) - err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) + ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancelSimRun() + + filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) + err := sim.UploadSnapshot(ctx, filename) if err != nil { return err } - ctx, cancelSimRun := context.WithTimeout(context.Background(), 1*time.Minute) - defer cancelSimRun() + log.Info("Starting simulation") result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { nodeIDs := sim.UpNodeIDs() @@ -197,9 +188,8 @@ func runFileRetrievalTest(nodeCount int) error { if err != nil { return err } - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - return err - } + + log.Info("network healthy, start file checks") // File retrieval check is repeated until all uploaded files are retrieved from all nodes // or until the timeout is reached. @@ -228,6 +218,8 @@ func runFileRetrievalTest(nodeCount int) error { } }) + log.Info("Simulation terminated") + if result.Error != nil { return result.Error } @@ -245,7 +237,8 @@ simulation's `action` function. The snapshot should have 'streamer' in its service list. */ -func runRetrievalTest(chunkCount int, nodeCount int) error { +func runRetrievalTest(t *testing.T, chunkCount int, nodeCount int) error { + t.Helper() sim := simulation.New(retrievalSimServiceMap) defer sim.Close() @@ -257,12 +250,15 @@ func runRetrievalTest(chunkCount int, nodeCount int) error { //array where the generated chunk hashes will be stored conf.hashes = make([]storage.Address, 0) - err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) + err := sim.UploadSnapshot(ctx, filename) if err != nil { return err } - ctx := context.Background() result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { nodeIDs := sim.UpNodeIDs() for _, n := range nodeIDs { @@ -277,19 +273,16 @@ func runRetrievalTest(chunkCount int, nodeCount int) error { } //this is the node selected for upload - node := sim.RandomUpNode() - item, ok := sim.NodeItem(node.ID, bucketKeyStore) + node := sim.Net.GetRandomUpNode() + item, ok := sim.NodeItem(node.ID(), bucketKeyStore) if !ok { return fmt.Errorf("No localstore") } lstore := item.(*storage.LocalStore) - conf.hashes, err = uploadFileToSingleNodeStore(node.ID, chunkCount, lstore) + conf.hashes, err = uploadFileToSingleNodeStore(node.ID(), chunkCount, lstore) if err != nil { return err } - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - return err - } // File retrieval check is repeated until all uploaded files are retrieved from all nodes // or until the timeout is reached. diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_sync_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_sync_test.go index 4bd7f38f..ce1e69db 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_sync_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/snapshot_sync_test.go @@ -17,6 +17,7 @@ package stream import ( "context" + "errors" "fmt" "os" "runtime" @@ -27,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" @@ -36,12 +36,11 @@ import ( "github.com/ethereum/go-ethereum/swarm/pot" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" - mockdb "github.com/ethereum/go-ethereum/swarm/storage/mock/db" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + mockmem "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" "github.com/ethereum/go-ethereum/swarm/testutil" ) -const MaxTimeout = 600 - type synctestConfig struct { addrs [][]byte hashes []storage.Address @@ -78,107 +77,60 @@ func TestSyncingViaGlobalSync(t *testing.T) { if runtime.GOOS == "darwin" && os.Getenv("TRAVIS") == "true" { t.Skip("Flaky on mac on travis") } + + if testutil.RaceEnabled { + t.Skip("Segfaults on Travis with -race") + } + //if nodes/chunks have been provided via commandline, //run the tests with these values if *nodes != 0 && *chunks != 0 { log.Info(fmt.Sprintf("Running test with %d chunks and %d nodes...", *chunks, *nodes)) testSyncingViaGlobalSync(t, *chunks, *nodes) } else { - var nodeCnt []int - var chnkCnt []int - //if the `longrunning` flag has been provided - //run more test combinations - if *longrunning { - chnkCnt = []int{1, 8, 32, 256, 1024} - nodeCnt = []int{16, 32, 64, 128, 256} - } else { - //default test - chnkCnt = []int{4, 32} - nodeCnt = []int{32, 16} - } - for _, chnk := range chnkCnt { - for _, n := range nodeCnt { - log.Info(fmt.Sprintf("Long running test with %d chunks and %d nodes...", chnk, n)) - testSyncingViaGlobalSync(t, chnk, n) - } - } - } -} + chunkCounts := []int{4, 32} + nodeCounts := []int{32, 16} -func TestSyncingViaDirectSubscribe(t *testing.T) { - if runtime.GOOS == "darwin" && os.Getenv("TRAVIS") == "true" { - t.Skip("Flaky on mac on travis") - } - //if nodes/chunks have been provided via commandline, - //run the tests with these values - if *nodes != 0 && *chunks != 0 { - log.Info(fmt.Sprintf("Running test with %d chunks and %d nodes...", *chunks, *nodes)) - err := testSyncingViaDirectSubscribe(t, *chunks, *nodes) - if err != nil { - t.Fatal(err) - } - } else { - var nodeCnt []int - var chnkCnt []int //if the `longrunning` flag has been provided //run more test combinations if *longrunning { - chnkCnt = []int{1, 8, 32, 256, 1024} - nodeCnt = []int{32, 16} - } else { - //default test - chnkCnt = []int{4, 32} - nodeCnt = []int{32, 16} + chunkCounts = []int{64, 128} + nodeCounts = []int{32, 64} } - for _, chnk := range chnkCnt { - for _, n := range nodeCnt { - log.Info(fmt.Sprintf("Long running test with %d chunks and %d nodes...", chnk, n)) - err := testSyncingViaDirectSubscribe(t, chnk, n) - if err != nil { - t.Fatal(err) - } + + for _, chunkCount := range chunkCounts { + for _, n := range nodeCounts { + log.Info(fmt.Sprintf("Long running test with %d chunks and %d nodes...", chunkCount, n)) + testSyncingViaGlobalSync(t, chunkCount, n) } } } } var simServiceMap = map[string]simulation.ServiceFunc{ - "streamer": streamerFunc, -} + "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + addr, netStore, delivery, clean, err := newNetStoreAndDeliveryWithRequestFunc(ctx, bucket, dummyRequestFromPeers) + if err != nil { + return nil, nil, err + } -func streamerFunc(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - n := ctx.Config.Node() - addr := network.NewAddr(n) - store, datadir, err := createTestLocalStorageForID(n.ID(), addr) - if err != nil { - return nil, nil, err - } - bucket.Store(bucketKeyStore, store) - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(dummyRequestFromPeers, true).New + store := state.NewInmemoryStore() - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Retrieval: RetrievalDisabled, - Syncing: SyncingAutoSubscribe, - SyncUpdateDelay: 3 * time.Second, - }) + r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingAutoSubscribe, + SyncUpdateDelay: 3 * time.Second, + }, nil) - bucket.Store(bucketKeyRegistry, r) + bucket.Store(bucketKeyRegistry, r) - cleanup = func() { - os.RemoveAll(datadir) - netStore.Close() - r.Close() - } - - return r, cleanup, nil + cleanup = func() { + r.Close() + clean() + } + return r, cleanup, nil + }, } func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) { @@ -195,34 +147,16 @@ func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) { //array where the generated chunk hashes will be stored conf.hashes = make([]storage.Address, 0) - err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) + ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancelSimRun() + + filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) + err := sim.UploadSnapshot(ctx, filename) if err != nil { t.Fatal(err) } - ctx, cancelSimRun := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancelSimRun() - - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - t.Fatal(err) - } - - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - - go func() { - for d := range disconnections { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - t.Fatal("unexpected disconnect") - cancelSimRun() - } - }() - result := runSim(conf, ctx, sim, chunkCount) - if result.Error != nil { t.Fatal(result.Error) } @@ -231,7 +165,14 @@ func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) { func runSim(conf *synctestConfig, ctx context.Context, sim *simulation.Simulation, chunkCount int) simulation.Result { - return sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + return sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") + } + }() + nodeIDs := sim.UpNodeIDs() for _, n := range nodeIDs { //get the kademlia overlay address from this ID @@ -246,20 +187,20 @@ func runSim(conf *synctestConfig, ctx context.Context, sim *simulation.Simulatio //get the node at that index //this is the node selected for upload - node := sim.RandomUpNode() - item, ok := sim.NodeItem(node.ID, bucketKeyStore) + node := sim.Net.GetRandomUpNode() + item, ok := sim.NodeItem(node.ID(), bucketKeyStore) if !ok { return fmt.Errorf("No localstore") } lstore := item.(*storage.LocalStore) - hashes, err := uploadFileToSingleNodeStore(node.ID, chunkCount, lstore) + hashes, err := uploadFileToSingleNodeStore(node.ID(), chunkCount, lstore) if err != nil { return err } for _, h := range hashes { evt := &simulations.Event{ Type: EventTypeChunkCreated, - Node: sim.Net.GetNode(node.ID), + Node: sim.Net.GetNode(node.ID()), Data: h.String(), } sim.Net.Events().Send(evt) @@ -269,20 +210,9 @@ func runSim(conf *synctestConfig, ctx context.Context, sim *simulation.Simulatio // File retrieval check is repeated until all uploaded files are retrieved from all nodes // or until the timeout is reached. - var gDir string - var globalStore *mockdb.GlobalStore + var globalStore mock.GlobalStorer if *useMockStore { - gDir, globalStore, err = createGlobalStore() - if err != nil { - return fmt.Errorf("Something went wrong; using mockStore enabled but globalStore is nil") - } - defer func() { - os.RemoveAll(gDir) - err := globalStore.Close() - if err != nil { - log.Error("Error closing global store! %v", "err", err) - } - }() + globalStore = mockmem.NewGlobalStore() } REPEAT: for { @@ -328,234 +258,6 @@ func runSim(conf *synctestConfig, ctx context.Context, sim *simulation.Simulatio }) } -/* -The test generates the given number of chunks - -For every chunk generated, the nearest node addresses -are identified, we verify that the nodes closer to the -chunk addresses actually do have the chunks in their local stores. - -The test loads a snapshot file to construct the swarm network, -assuming that the snapshot file identifies a healthy -kademlia network. The snapshot should have 'streamer' in its service list. -*/ -func testSyncingViaDirectSubscribe(t *testing.T, chunkCount int, nodeCount int) error { - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - n := ctx.Config.Node() - addr := network.NewAddr(n) - store, datadir, err := createTestLocalStorageForID(n.ID(), addr) - if err != nil { - return nil, nil, err - } - bucket.Store(bucketKeyStore, store) - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(dummyRequestFromPeers, true).New - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Retrieval: RetrievalDisabled, - Syncing: SyncingRegisterOnly, - }) - bucket.Store(bucketKeyRegistry, r) - - fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) - bucket.Store(bucketKeyFileStore, fileStore) - - cleanup = func() { - os.RemoveAll(datadir) - netStore.Close() - r.Close() - } - - return r, cleanup, nil - - }, - }) - defer sim.Close() - - ctx, cancelSimRun := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancelSimRun() - - conf := &synctestConfig{} - //map of discover ID to indexes of chunks expected at that ID - conf.idToChunksMap = make(map[enode.ID][]int) - //map of overlay address to discover ID - conf.addrToIDMap = make(map[string]enode.ID) - //array where the generated chunk hashes will be stored - conf.hashes = make([]storage.Address, 0) - - err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) - if err != nil { - return err - } - - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - return err - } - - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - - go func() { - for d := range disconnections { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - t.Fatal("unexpected disconnect") - cancelSimRun() - } - }() - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - nodeIDs := sim.UpNodeIDs() - for _, n := range nodeIDs { - //get the kademlia overlay address from this ID - a := n.Bytes() - //append it to the array of all overlay addresses - conf.addrs = append(conf.addrs, a) - //the proximity calculation is on overlay addr, - //the p2p/simulations check func triggers on enode.ID, - //so we need to know which overlay addr maps to which nodeID - conf.addrToIDMap[string(a)] = n - } - - var subscriptionCount int - - filter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(4) - eventC := sim.PeerEvents(ctx, nodeIDs, filter) - - for j, node := range nodeIDs { - log.Trace(fmt.Sprintf("Start syncing subscriptions: %d", j)) - //start syncing! - item, ok := sim.NodeItem(node, bucketKeyRegistry) - if !ok { - return fmt.Errorf("No registry") - } - registry := item.(*Registry) - - var cnt int - cnt, err = startSyncing(registry, conf) - if err != nil { - return err - } - //increment the number of subscriptions we need to wait for - //by the count returned from startSyncing (SYNC subscriptions) - subscriptionCount += cnt - } - - for e := range eventC { - if e.Error != nil { - return e.Error - } - subscriptionCount-- - if subscriptionCount == 0 { - break - } - } - //select a random node for upload - node := sim.RandomUpNode() - item, ok := sim.NodeItem(node.ID, bucketKeyStore) - if !ok { - return fmt.Errorf("No localstore") - } - lstore := item.(*storage.LocalStore) - hashes, err := uploadFileToSingleNodeStore(node.ID, chunkCount, lstore) - if err != nil { - return err - } - conf.hashes = append(conf.hashes, hashes...) - mapKeysToNodes(conf) - - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - return err - } - - var gDir string - var globalStore *mockdb.GlobalStore - if *useMockStore { - gDir, globalStore, err = createGlobalStore() - if err != nil { - return fmt.Errorf("Something went wrong; using mockStore enabled but globalStore is nil") - } - defer os.RemoveAll(gDir) - } - // File retrieval check is repeated until all uploaded files are retrieved from all nodes - // or until the timeout is reached. - REPEAT: - for { - for _, id := range nodeIDs { - //for each expected chunk, check if it is in the local store - localChunks := conf.idToChunksMap[id] - for _, ch := range localChunks { - //get the real chunk by the index in the index array - chunk := conf.hashes[ch] - log.Trace(fmt.Sprintf("node has chunk: %s:", chunk)) - //check if the expected chunk is indeed in the localstore - var err error - if *useMockStore { - //use the globalStore if the mockStore should be used; in that case, - //the complete localStore stack is bypassed for getting the chunk - _, err = globalStore.Get(common.BytesToAddress(id.Bytes()), chunk) - } else { - //use the actual localstore - item, ok := sim.NodeItem(id, bucketKeyStore) - if !ok { - return fmt.Errorf("Error accessing localstore") - } - lstore := item.(*storage.LocalStore) - _, err = lstore.Get(ctx, chunk) - } - if err != nil { - log.Debug(fmt.Sprintf("Chunk %s NOT found for id %s", chunk, id)) - // Do not get crazy with logging the warn message - time.Sleep(500 * time.Millisecond) - continue REPEAT - } - log.Debug(fmt.Sprintf("Chunk %s IS FOUND for id %s", chunk, id)) - } - } - return nil - } - }) - - if result.Error != nil { - return result.Error - } - - log.Info("Simulation ended") - return nil -} - -//the server func to start syncing -//issues `RequestSubscriptionMsg` to peers, based on po, by iterating over -//the kademlia's `EachBin` function. -//returns the number of subscriptions requested -func startSyncing(r *Registry, conf *synctestConfig) (int, error) { - var err error - kad := r.delivery.kad - subCnt := 0 - //iterate over each bin and solicit needed subscription to bins - kad.EachBin(r.addr[:], pof, 0, func(conn *network.Peer, po int) bool { - //identify begin and start index of the bin(s) we want to subscribe to - subCnt++ - err = r.RequestSubscription(conf.addrToIDMap[string(conn.Address())], NewStream("SYNC", FormatSyncBinKey(uint8(po)), true), NewRange(0, 0), High) - if err != nil { - log.Error(fmt.Sprintf("Error in RequestSubsciption! %v", err)) - return false - } - return true - - }) - return subCnt, nil -} - //map chunk keys to addresses which are responsible func mapKeysToNodes(conf *synctestConfig) { nodemap := make(map[string][]int) @@ -567,9 +269,7 @@ func mapKeysToNodes(conf *synctestConfig) { np, _, _ = pot.Add(np, a, pof) } - var kadMinProxSize = 2 - - ppmap := network.NewPeerPotMap(kadMinProxSize, conf.addrs) + ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, conf.addrs) //for each address, run EachNeighbour on the chunk hashes pot to identify closest nodes log.Trace(fmt.Sprintf("Generated hash chunk(s): %v", conf.hashes)) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/stream.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/stream.go index 695ff0c5..1038e52d 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/stream.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/stream.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "math" + "reflect" "sync" "time" @@ -32,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network/stream/intervals" - "github.com/ethereum/go-ethereum/swarm/pot" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" ) @@ -47,31 +47,36 @@ const ( HashSize = 32 ) -//Enumerate options for syncing and retrieval +// Enumerate options for syncing and retrieval type SyncingOption int type RetrievalOption int -//Syncing options +// Syncing options const ( - //Syncing disabled + // Syncing disabled SyncingDisabled SyncingOption = iota - //Register the client and the server but not subscribe + // Register the client and the server but not subscribe SyncingRegisterOnly - //Both client and server funcs are registered, subscribe sent automatically + // Both client and server funcs are registered, subscribe sent automatically SyncingAutoSubscribe ) const ( - //Retrieval disabled. Used mostly for tests to isolate syncing features (i.e. syncing only) + // Retrieval disabled. Used mostly for tests to isolate syncing features (i.e. syncing only) RetrievalDisabled RetrievalOption = iota - //Only the client side of the retrieve request is registered. - //(light nodes do not serve retrieve requests) - //once the client is registered, subscription to retrieve request stream is always sent + // Only the client side of the retrieve request is registered. + // (light nodes do not serve retrieve requests) + // once the client is registered, subscription to retrieve request stream is always sent RetrievalClientOnly - //Both client and server funcs are registered, subscribe sent automatically + // Both client and server funcs are registered, subscribe sent automatically RetrievalEnabled ) +// subscriptionFunc is used to determine what to do in order to perform subscriptions +// usually we would start to really subscribe to nodes, but for tests other functionality may be needed +// (see TestRequestPeerSubscriptions in streamer_test.go) +var subscriptionFunc = doRequestSubscription + // Registry registry for outgoing and incoming streamer constructors type Registry struct { addr enode.ID @@ -85,30 +90,36 @@ type Registry struct { peers map[enode.ID]*Peer delivery *Delivery intervalsStore state.Store - autoRetrieval bool //automatically subscribe to retrieve request stream + autoRetrieval bool // automatically subscribe to retrieve request stream maxPeerServers int + spec *protocols.Spec //this protocol's spec + balance protocols.Balance //implements protocols.Balance, for accounting + prices protocols.Prices //implements protocols.Prices, provides prices to accounting + quit chan struct{} // terminates registry goroutines } // RegistryOptions holds optional values for NewRegistry constructor. type RegistryOptions struct { SkipCheck bool - Syncing SyncingOption //Defines syncing behavior - Retrieval RetrievalOption //Defines retrieval behavior + Syncing SyncingOption // Defines syncing behavior + Retrieval RetrievalOption // Defines retrieval behavior SyncUpdateDelay time.Duration MaxPeerServers int // The limit of servers for each peer in registry } // NewRegistry is Streamer constructor -func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.SyncChunkStore, intervalsStore state.Store, options *RegistryOptions) *Registry { +func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.SyncChunkStore, intervalsStore state.Store, options *RegistryOptions, balance protocols.Balance) *Registry { if options == nil { options = &RegistryOptions{} } if options.SyncUpdateDelay <= 0 { options.SyncUpdateDelay = 15 * time.Second } - //check if retriaval has been disabled + // check if retrieval has been disabled retrieval := options.Retrieval != RetrievalDisabled + quit := make(chan struct{}) + streamer := &Registry{ addr: localID, skipCheck: options.SkipCheck, @@ -119,11 +130,16 @@ func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.Sy intervalsStore: intervalsStore, autoRetrieval: retrieval, maxPeerServers: options.MaxPeerServers, + balance: balance, + quit: quit, } + + streamer.setupSpec() + streamer.api = NewAPI(streamer) delivery.getPeer = streamer.getPeer - //if retrieval is enabled, register the server func, so that retrieve requests will be served (non-light nodes only) + // if retrieval is enabled, register the server func, so that retrieve requests will be served (non-light nodes only) if options.Retrieval == RetrievalEnabled { streamer.RegisterServerFunc(swarmChunkServerStreamName, func(_ *Peer, _ string, live bool) (Server, error) { if !live { @@ -133,20 +149,20 @@ func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.Sy }) } - //if retrieval is not disabled, register the client func (both light nodes and normal nodes can issue retrieve requests) + // if retrieval is not disabled, register the client func (both light nodes and normal nodes can issue retrieve requests) if options.Retrieval != RetrievalDisabled { streamer.RegisterClientFunc(swarmChunkServerStreamName, func(p *Peer, t string, live bool) (Client, error) { return NewSwarmSyncerClient(p, syncChunkStore, NewStream(swarmChunkServerStreamName, t, live)) }) } - //If syncing is not disabled, the syncing functions are registered (both client and server) + // If syncing is not disabled, the syncing functions are registered (both client and server) if options.Syncing != SyncingDisabled { RegisterSwarmSyncerServer(streamer, syncChunkStore) RegisterSwarmSyncerClient(streamer, syncChunkStore) } - //if syncing is set to automatically subscribe to the syncing stream, start the subscription process + // if syncing is set to automatically subscribe to the syncing stream, start the subscription process if options.Syncing == SyncingAutoSubscribe { // latestIntC function ensures that // - receiving from the in chan is not blocked by processing inside the for loop @@ -160,25 +176,41 @@ func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.Sy go func() { defer close(out) - for i := range in { + for { select { - case <-out: - default: + case i, ok := <-in: + if !ok { + return + } + select { + case <-out: + default: + } + out <- i + case <-quit: + return } - out <- i } }() return out } + kad := streamer.delivery.kad + // get notification channels from Kademlia before returning + // from this function to avoid race with Close method and + // the goroutine created below + depthC := latestIntC(kad.NeighbourhoodDepthC()) + addressBookSizeC := latestIntC(kad.AddrCountC()) + go func() { // wait for kademlia table to be healthy - time.Sleep(options.SyncUpdateDelay) - - kad := streamer.delivery.kad - depthC := latestIntC(kad.NeighbourhoodDepthC()) - addressBookSizeC := latestIntC(kad.AddrCountC()) + // but return if Registry is closed before + select { + case <-time.After(options.SyncUpdateDelay): + case <-quit: + return + } // initial requests for syncing subscription to peers streamer.updateSyncing() @@ -217,6 +249,8 @@ func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.Sy <-timer.C } timer.Reset(options.SyncUpdateDelay) + case <-quit: + break loop } } timer.Stop() @@ -228,6 +262,21 @@ func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.Sy return streamer } +// This is an accounted protocol, therefore we need to provide a pricing Hook to the spec +// For simulations to be able to run multiple nodes and not override the hook's balance, +// we need to construct a spec instance per node instance +func (r *Registry) setupSpec() { + // first create the "bare" spec + r.createSpec() + // now create the pricing object + r.createPriceOracle() + // if balance is nil, this node has been started without swap support (swapEnabled flag is false) + if r.balance != nil && !reflect.ValueOf(r.balance).IsNil() { + // swap is enabled, so setup the hook + r.spec.Hook = protocols.NewAccounting(r.balance, r.prices) + } +} + // RegisterClient registers an incoming streamer constructor func (r *Registry) RegisterClientFunc(stream string, f func(*Peer, string, bool) (Client, error)) { r.clientMu.Lock() @@ -370,15 +419,12 @@ func (r *Registry) Quit(peerId enode.ID, s Stream) error { return peer.Send(context.TODO(), msg) } -func (r *Registry) NodeInfo() interface{} { - return nil -} - -func (r *Registry) PeerInfo(id enode.ID) interface{} { - return nil -} - func (r *Registry) Close() error { + // Stop sending neighborhood depth change and address count + // change from Kademlia that were initiated in NewRegistry constructor. + r.delivery.kad.CloseNeighbourhoodDepthC() + r.delivery.kad.CloseAddrCountC() + close(r.quit) return r.intervalsStore.Close() } @@ -453,24 +499,8 @@ func (r *Registry) updateSyncing() { } r.peersMu.RUnlock() - // request subscriptions for all nodes and bins - kad.EachBin(r.addr[:], pot.DefaultPof(256), 0, func(p *network.Peer, bin int) bool { - log.Debug(fmt.Sprintf("Requesting subscription by: registry %s from peer %s for bin: %d", r.addr, p.ID(), bin)) - - // bin is always less then 256 and it is safe to convert it to type uint8 - stream := NewStream("SYNC", FormatSyncBinKey(uint8(bin)), true) - if streams, ok := subs[p.ID()]; ok { - // delete live and history streams from the map, so that it won't be removed with a Quit request - delete(streams, stream) - delete(streams, getHistoryStream(stream)) - } - err := r.RequestSubscription(p.ID(), stream, NewRange(0, 0), High) - if err != nil { - log.Debug("Request subscription", "err", err, "peer", p.ID(), "stream", stream) - return false - } - return true - }) + // start requesting subscriptions from peers + r.requestPeerSubscriptions(kad, subs) // remove SYNC servers that do not need to be subscribed for id, streams := range subs { @@ -491,8 +521,73 @@ func (r *Registry) updateSyncing() { } } +// requestPeerSubscriptions calls on each live peer in the kademlia table +// and sends a `RequestSubscription` to peers according to their bin +// and their relationship with kademlia's depth. +// Also check `TestRequestPeerSubscriptions` in order to understand the +// expected behavior. +// The function expects: +// * the kademlia +// * a map of subscriptions +// * the actual function to subscribe +// (in case of the test, it doesn't do real subscriptions) +func (r *Registry) requestPeerSubscriptions(kad *network.Kademlia, subs map[enode.ID]map[Stream]struct{}) { + + var startPo int + var endPo int + var ok bool + + // kademlia's depth + kadDepth := kad.NeighbourhoodDepth() + // request subscriptions for all nodes and bins + // nil as base takes the node's base; we need to pass 255 as `EachConn` runs + // from deepest bins backwards + kad.EachConn(nil, 255, func(p *network.Peer, po int) bool { + // nodes that do not provide stream protocol + // should not be subscribed, e.g. bootnodes + if !p.HasCap("stream") { + return true + } + //if the peer's bin is shallower than the kademlia depth, + //only the peer's bin should be subscribed + if po < kadDepth { + startPo = po + endPo = po + } else { + //if the peer's bin is equal or deeper than the kademlia depth, + //each bin from the depth up to k.MaxProxDisplay should be subscribed + startPo = kadDepth + endPo = kad.MaxProxDisplay + } + + for bin := startPo; bin <= endPo; bin++ { + //do the actual subscription + ok = subscriptionFunc(r, p, uint8(bin), subs) + } + return ok + }) +} + +// doRequestSubscription sends the actual RequestSubscription to the peer +func doRequestSubscription(r *Registry, p *network.Peer, bin uint8, subs map[enode.ID]map[Stream]struct{}) bool { + log.Debug("Requesting subscription by registry:", "registry", r.addr, "peer", p.ID(), "bin", bin) + // bin is always less then 256 and it is safe to convert it to type uint8 + stream := NewStream("SYNC", FormatSyncBinKey(bin), true) + if streams, ok := subs[p.ID()]; ok { + // delete live and history streams from the map, so that it won't be removed with a Quit request + delete(streams, stream) + delete(streams, getHistoryStream(stream)) + } + err := r.RequestSubscription(p.ID(), stream, NewRange(0, 0), High) + if err != nil { + log.Debug("Request subscription", "err", err, "peer", p.ID(), "stream", stream) + return false + } + return true +} + func (r *Registry) runProtocol(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := protocols.NewPeer(p, rw, Spec) + peer := protocols.NewPeer(p, rw, r.spec) bp := network.NewBzzPeer(peer) np := network.NewPeer(bp, r.delivery.kad) r.delivery.kad.On(np) @@ -502,6 +597,16 @@ func (r *Registry) runProtocol(p *p2p.Peer, rw p2p.MsgReadWriter) error { // HandleMsg is the message handler that delegates incoming messages func (p *Peer) HandleMsg(ctx context.Context, msg interface{}) error { + select { + case <-p.streamer.quit: + log.Trace("message received after the streamer is closed", "peer", p.ID()) + // return without an error since streamer is closed and + // no messages should be handled as other subcomponents like + // storage leveldb may be closed + return nil + default: + } + switch msg := msg.(type) { case *SubscribeMsg: @@ -523,11 +628,11 @@ func (p *Peer) HandleMsg(ctx context.Context, msg interface{}) error { return p.handleWantedHashesMsg(ctx, msg) case *ChunkDeliveryMsgRetrieval: - //handling chunk delivery is the same for retrieval and syncing, so let's cast the msg + // handling chunk delivery is the same for retrieval and syncing, so let's cast the msg return p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg))) case *ChunkDeliveryMsgSyncing: - //handling chunk delivery is the same for retrieval and syncing, so let's cast the msg + // handling chunk delivery is the same for retrieval and syncing, so let's cast the msg return p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg))) case *RetrieveRequestMsg: @@ -603,17 +708,16 @@ func peerStreamIntervalsKey(p *Peer, s Stream) string { return p.ID().String() + s.String() } -func (c client) AddInterval(start, end uint64) (err error) { +func (c *client) AddInterval(start, end uint64) (err error) { i := &intervals.Intervals{} - err = c.intervalsStore.Get(c.intervalsKey, i) - if err != nil { + if err = c.intervalsStore.Get(c.intervalsKey, i); err != nil { return err } i.Add(start, end) return c.intervalsStore.Put(c.intervalsKey, i) } -func (c client) NextInterval() (start, end uint64, err error) { +func (c *client) NextInterval() (start, end uint64, err error) { i := &intervals.Intervals{} err = c.intervalsStore.Get(c.intervalsKey, i) if err != nil { @@ -662,6 +766,7 @@ func (c *client) batchDone(p *Peer, req *OfferedHashesMsg, hashes []byte) error if err != nil { return err } + if err := p.SendPriority(context.TODO(), tp, c.priority); err != nil { return err } @@ -670,11 +775,7 @@ func (c *client) batchDone(p *Peer, req *OfferedHashesMsg, hashes []byte) error } return nil } - // TODO: make a test case for testing if the interval is added when the batch is done - if err := c.AddInterval(req.From, req.To); err != nil { - return err - } - return nil + return c.AddInterval(req.From, req.To) } func (c *client) close() { @@ -716,35 +817,89 @@ func (c *clientParams) clientCreated() { close(c.clientCreatedC) } -// Spec is the spec of the streamer protocol -var Spec = &protocols.Spec{ - Name: "stream", - Version: 8, - MaxMsgSize: 10 * 1024 * 1024, - Messages: []interface{}{ - UnsubscribeMsg{}, - OfferedHashesMsg{}, - WantedHashesMsg{}, - TakeoverProofMsg{}, - SubscribeMsg{}, - RetrieveRequestMsg{}, - ChunkDeliveryMsgRetrieval{}, - SubscribeErrorMsg{}, - RequestSubscriptionMsg{}, - QuitMsg{}, - ChunkDeliveryMsgSyncing{}, - }, +// GetSpec returns the streamer spec to callers +// This used to be a global variable but for simulations with +// multiple nodes its fields (notably the Hook) would be overwritten +func (r *Registry) GetSpec() *protocols.Spec { + return r.spec +} + +func (r *Registry) createSpec() { + // Spec is the spec of the streamer protocol + var spec = &protocols.Spec{ + Name: "stream", + Version: 8, + MaxMsgSize: 10 * 1024 * 1024, + Messages: []interface{}{ + UnsubscribeMsg{}, + OfferedHashesMsg{}, + WantedHashesMsg{}, + TakeoverProofMsg{}, + SubscribeMsg{}, + RetrieveRequestMsg{}, + ChunkDeliveryMsgRetrieval{}, + SubscribeErrorMsg{}, + RequestSubscriptionMsg{}, + QuitMsg{}, + ChunkDeliveryMsgSyncing{}, + }, + } + r.spec = spec +} + +// An accountable message needs some meta information attached to it +// in order to evaluate the correct price +type StreamerPrices struct { + priceMatrix map[reflect.Type]*protocols.Price + registry *Registry +} + +// Price implements the accounting interface and returns the price for a specific message +func (sp *StreamerPrices) Price(msg interface{}) *protocols.Price { + t := reflect.TypeOf(msg).Elem() + return sp.priceMatrix[t] +} + +// Instead of hardcoding the price, get it +// through a function - it could be quite complex in the future +func (sp *StreamerPrices) getRetrieveRequestMsgPrice() uint64 { + return uint64(1) +} + +// Instead of hardcoding the price, get it +// through a function - it could be quite complex in the future +func (sp *StreamerPrices) getChunkDeliveryMsgRetrievalPrice() uint64 { + return uint64(1) +} + +// createPriceOracle sets up a matrix which can be queried to get +// the price for a message via the Price method +func (r *Registry) createPriceOracle() { + sp := &StreamerPrices{ + registry: r, + } + sp.priceMatrix = map[reflect.Type]*protocols.Price{ + reflect.TypeOf(ChunkDeliveryMsgRetrieval{}): { + Value: sp.getChunkDeliveryMsgRetrievalPrice(), // arbitrary price for now + PerByte: true, + Payer: protocols.Receiver, + }, + reflect.TypeOf(RetrieveRequestMsg{}): { + Value: sp.getRetrieveRequestMsgPrice(), // arbitrary price for now + PerByte: false, + Payer: protocols.Sender, + }, + } + r.prices = sp } func (r *Registry) Protocols() []p2p.Protocol { return []p2p.Protocol{ { - Name: Spec.Name, - Version: Spec.Version, - Length: Spec.Length(), + Name: r.spec.Name, + Version: r.spec.Version, + Length: r.spec.Length(), Run: r.runProtocol, - // NodeInfo: , - // PeerInfo: , }, } } @@ -755,7 +910,7 @@ func (r *Registry) APIs() []rpc.API { Namespace: "stream", Version: "3.0", Service: r.api, - Public: true, + Public: false, }, } } @@ -812,3 +967,33 @@ func (api *API) SubscribeStream(peerId enode.ID, s Stream, history *Range, prior func (api *API) UnsubscribeStream(peerId enode.ID, s Stream) error { return api.streamer.Unsubscribe(peerId, s) } + +/* +GetPeerSubscriptions is a API function which allows to query a peer for stream subscriptions it has. +It can be called via RPC. +It returns a map of node IDs with an array of string representations of Stream objects. +*/ +func (api *API) GetPeerSubscriptions() map[string][]string { + //create the empty map + pstreams := make(map[string][]string) + + //iterate all streamer peers + api.streamer.peersMu.RLock() + defer api.streamer.peersMu.RUnlock() + + for id, p := range api.streamer.peers { + var streams []string + //every peer has a map of stream servers + //every stream server represents a subscription + p.serverMu.RLock() + for s := range p.servers { + //append the string representation of the stream + //to the list for this peer + streams = append(streams, s.String()) + } + p.serverMu.RUnlock() + //set the array of stream servers to the map + pstreams[id.String()] = streams + } + return pstreams +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/streamer_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/streamer_test.go index 16c74d3b..bdd3087b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/streamer_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/streamer_test.go @@ -20,20 +20,34 @@ import ( "bytes" "context" "errors" + "fmt" + "os" "strconv" + "strings" + "sync" "testing" "time" - "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/swarm/testutil" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" p2ptest "github.com/ethereum/go-ethereum/p2p/testing" + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/network/simulation" + "github.com/ethereum/go-ethereum/swarm/state" + "golang.org/x/crypto/sha3" ) func TestStreamerSubscribe(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", true) err = streamer.Subscribe(tester.Nodes[0].ID(), stream, NewRange(0, 0), Top) @@ -43,11 +57,11 @@ func TestStreamerSubscribe(t *testing.T) { } func TestStreamerRequestSubscription(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", false) err = streamer.RequestSubscription(tester.Nodes[0].ID(), stream, &Range{}, Top) @@ -134,11 +148,11 @@ func (self *testServer) Close() { } func TestStreamerDownstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { return newTestClient(t), nil @@ -227,11 +241,11 @@ func TestStreamerDownstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { } func TestStreamerUpstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", false) @@ -294,11 +308,11 @@ func TestStreamerUpstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { } func TestStreamerUpstreamSubscribeUnsubscribeMsgExchangeLive(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", true) @@ -360,11 +374,11 @@ func TestStreamerUpstreamSubscribeUnsubscribeMsgExchangeLive(t *testing.T) { } func TestStreamerUpstreamSubscribeErrorMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { return newTestServer(t, 0), nil @@ -404,11 +418,11 @@ func TestStreamerUpstreamSubscribeErrorMsgExchange(t *testing.T) { } func TestStreamerUpstreamSubscribeLiveAndHistory(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", true) @@ -467,11 +481,11 @@ func TestStreamerUpstreamSubscribeLiveAndHistory(t *testing.T) { } func TestStreamerDownstreamCorruptHashesMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", true) @@ -532,11 +546,11 @@ func TestStreamerDownstreamCorruptHashesMsgExchange(t *testing.T) { } func TestStreamerDownstreamOfferedHashesMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() stream := NewStream("foo", "", true) @@ -631,11 +645,11 @@ func TestStreamerDownstreamOfferedHashesMsgExchange(t *testing.T) { } func TestStreamerRequestSubscriptionQuitMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(t, nil) - defer teardown() + tester, streamer, _, teardown, err := newStreamerTester(nil) if err != nil { t.Fatal(err) } + defer teardown() streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { return newTestServer(t, 10), nil @@ -764,15 +778,15 @@ func TestStreamerRequestSubscriptionQuitMsgExchange(t *testing.T) { // leaving place for new streams. func TestMaxPeerServersWithUnsubscribe(t *testing.T) { var maxPeerServers = 6 - tester, streamer, _, teardown, err := newStreamerTester(t, &RegistryOptions{ + tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ Retrieval: RetrievalDisabled, Syncing: SyncingDisabled, MaxPeerServers: maxPeerServers, }) - defer teardown() if err != nil { t.Fatal(err) } + defer teardown() streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { return newTestServer(t, 0), nil @@ -840,13 +854,13 @@ func TestMaxPeerServersWithUnsubscribe(t *testing.T) { // error message exchange. func TestMaxPeerServersWithoutUnsubscribe(t *testing.T) { var maxPeerServers = 6 - tester, streamer, _, teardown, err := newStreamerTester(t, &RegistryOptions{ + tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ MaxPeerServers: maxPeerServers, }) - defer teardown() if err != nil { t.Fatal(err) } + defer teardown() streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { return newTestServer(t, 0), nil @@ -921,3 +935,443 @@ func TestMaxPeerServersWithoutUnsubscribe(t *testing.T) { } } } + +//TestHasPriceImplementation is to check that the Registry has a +//`Price` interface implementation +func TestHasPriceImplementation(t *testing.T) { + _, r, _, teardown, err := newStreamerTester(&RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingDisabled, + }) + if err != nil { + t.Fatal(err) + } + defer teardown() + + if r.prices == nil { + t.Fatal("No prices implementation available for the stream protocol") + } + + pricesInstance, ok := r.prices.(*StreamerPrices) + if !ok { + t.Fatal("`Registry` does not have the expected Prices instance") + } + price := pricesInstance.Price(&ChunkDeliveryMsgRetrieval{}) + if price == nil || price.Value == 0 || price.Value != pricesInstance.getChunkDeliveryMsgRetrievalPrice() { + t.Fatal("No prices set for chunk delivery msg") + } + + price = pricesInstance.Price(&RetrieveRequestMsg{}) + if price == nil || price.Value == 0 || price.Value != pricesInstance.getRetrieveRequestMsgPrice() { + t.Fatal("No prices set for chunk delivery msg") + } +} + +/* +TestRequestPeerSubscriptions is a unit test for stream's pull sync subscriptions. + +The test does: + * assign each connected peer to a bin map + * build up a known kademlia in advance + * run the EachConn function, which returns supposed subscription bins + * store all supposed bins per peer in a map + * check that all peers have the expected subscriptions + +This kad table and its peers are copied from network.TestKademliaCase1, +it represents an edge case but for the purpose of testing the +syncing subscriptions it is just fine. + +Addresses used in this test are discovered as part of the simulation network +in higher level tests for streaming. They were generated randomly. + +The resulting kademlia looks like this: +========================================================================= +Fri Dec 21 20:02:39 UTC 2018 KΛÐΞMLIΛ hive: queen's address: 7efef1 +population: 12 (12), MinProxBinSize: 2, MinBinSize: 2, MaxBinSize: 4 +000 2 8196 835f | 2 8196 (0) 835f (0) +001 2 2690 28f0 | 2 2690 (0) 28f0 (0) +002 2 4d72 4a45 | 2 4d72 (0) 4a45 (0) +003 1 646e | 1 646e (0) +004 3 769c 76d1 7656 | 3 769c (0) 76d1 (0) 7656 (0) +============ DEPTH: 5 ========================================== +005 1 7a48 | 1 7a48 (0) +006 1 7cbd | 1 7cbd (0) +007 0 | 0 +008 0 | 0 +009 0 | 0 +010 0 | 0 +011 0 | 0 +012 0 | 0 +013 0 | 0 +014 0 | 0 +015 0 | 0 +========================================================================= +*/ +func TestRequestPeerSubscriptions(t *testing.T) { + // the pivot address; this is the actual kademlia node + pivotAddr := "7efef1c41d77f843ad167be95f6660567eb8a4a59f39240000cce2e0d65baf8e" + + // a map of bin number to addresses from the given kademlia + binMap := make(map[int][]string) + binMap[0] = []string{ + "835fbbf1d16ba7347b6e2fc552d6e982148d29c624ea20383850df3c810fa8fc", + "81968a2d8fb39114342ee1da85254ec51e0608d7f0f6997c2a8354c260a71009", + } + binMap[1] = []string{ + "28f0bc1b44658548d6e05dd16d4c2fe77f1da5d48b6774bc4263b045725d0c19", + "2690a910c33ee37b91eb6c4e0731d1d345e2dc3b46d308503a6e85bbc242c69e", + } + binMap[2] = []string{ + "4a45f1fc63e1a9cb9dfa44c98da2f3d20c2923e5d75ff60b2db9d1bdb0c54d51", + "4d72a04ddeb851a68cd197ef9a92a3e2ff01fbbff638e64929dd1a9c2e150112", + } + binMap[3] = []string{ + "646e9540c84f6a2f9cf6585d45a4c219573b4fd1b64a3c9a1386fc5cf98c0d4d", + } + binMap[4] = []string{ + "7656caccdc79cd8d7ce66d415cc96a718e8271c62fb35746bfc2b49faf3eebf3", + "76d1e83c71ca246d042e37ff1db181f2776265fbcfdc890ce230bfa617c9c2f0", + "769ce86aa90b518b7ed382f9fdacfbed93574e18dc98fe6c342e4f9f409c2d5a", + } + binMap[5] = []string{ + "7a48f75f8ca60487ae42d6f92b785581b40b91f2da551ae73d5eae46640e02e8", + } + binMap[6] = []string{ + "7cbd42350bde8e18ae5b955b5450f8e2cef3419f92fbf5598160c60fd78619f0", + } + + // create the pivot's kademlia + addr := common.FromHex(pivotAddr) + k := network.NewKademlia(addr, network.NewKadParams()) + + // construct the peers and the kademlia + for _, binaddrs := range binMap { + for _, a := range binaddrs { + addr := common.FromHex(a) + k.On(network.NewPeer(&network.BzzPeer{BzzAddr: &network.BzzAddr{OAddr: addr}}, k)) + } + } + + // TODO: check kad table is same + // currently k.String() prints date so it will never be the same :) + // --> implement JSON representation of kad table + log.Debug(k.String()) + + // simulate that we would do subscriptions: just store the bin numbers + fakeSubscriptions := make(map[string][]int) + //after the test, we need to reset the subscriptionFunc to the default + defer func() { subscriptionFunc = doRequestSubscription }() + // define the function which should run for each connection + // instead of doing real subscriptions, we just store the bin numbers + subscriptionFunc = func(r *Registry, p *network.Peer, bin uint8, subs map[enode.ID]map[Stream]struct{}) bool { + // get the peer ID + peerstr := fmt.Sprintf("%x", p.Over()) + // create the array of bins per peer + if _, ok := fakeSubscriptions[peerstr]; !ok { + fakeSubscriptions[peerstr] = make([]int, 0) + } + // store the (fake) bin subscription + log.Debug(fmt.Sprintf("Adding fake subscription for peer %s with bin %d", peerstr, bin)) + fakeSubscriptions[peerstr] = append(fakeSubscriptions[peerstr], int(bin)) + return true + } + // create just a simple Registry object in order to be able to call... + r := &Registry{} + r.requestPeerSubscriptions(k, nil) + // calculate the kademlia depth + kdepth := k.NeighbourhoodDepth() + + // now, check that all peers have the expected (fake) subscriptions + // iterate the bin map + for bin, peers := range binMap { + // for every peer... + for _, peer := range peers { + // ...get its (fake) subscriptions + fakeSubsForPeer := fakeSubscriptions[peer] + // if the peer's bin is shallower than the kademlia depth... + if bin < kdepth { + // (iterate all (fake) subscriptions) + for _, subbin := range fakeSubsForPeer { + // ...only the peer's bin should be "subscribed" + // (and thus have only one subscription) + if subbin != bin || len(fakeSubsForPeer) != 1 { + t.Fatalf("Did not get expected subscription for bin < depth; bin of peer %s: %d, subscription: %d", peer, bin, subbin) + } + } + } else { //if the peer's bin is equal or higher than the kademlia depth... + // (iterate all (fake) subscriptions) + for i, subbin := range fakeSubsForPeer { + // ...each bin from the peer's bin number up to k.MaxProxDisplay should be "subscribed" + // as we start from depth we can use the iteration index to check + if subbin != i+kdepth { + t.Fatalf("Did not get expected subscription for bin > depth; bin of peer %s: %d, subscription: %d", peer, bin, subbin) + } + // the last "subscription" should be k.MaxProxDisplay + if i == len(fakeSubsForPeer)-1 && subbin != k.MaxProxDisplay { + t.Fatalf("Expected last subscription to be: %d, but is: %d", k.MaxProxDisplay, subbin) + } + } + } + } + } + // print some output + for p, subs := range fakeSubscriptions { + log.Debug(fmt.Sprintf("Peer %s has the following fake subscriptions: ", p)) + for _, bin := range subs { + log.Debug(fmt.Sprintf("%d,", bin)) + } + } +} + +// TestGetSubscriptions is a unit test for the api.GetPeerSubscriptions() function +func TestGetSubscriptions(t *testing.T) { + // create an amount of dummy peers + testPeerCount := 8 + // every peer will have this amount of dummy servers + testServerCount := 4 + // the peerMap which will store this data for the registry + peerMap := make(map[enode.ID]*Peer) + // create the registry + r := &Registry{} + api := NewAPI(r) + // call once, at this point should be empty + regs := api.GetPeerSubscriptions() + if len(regs) != 0 { + t.Fatal("Expected subscription count to be 0, but it is not") + } + + // now create a number of dummy servers for each node + for i := 0; i < testPeerCount; i++ { + addr := network.RandomAddr() + id := addr.ID() + p := &Peer{} + p.servers = make(map[Stream]*server) + for k := 0; k < testServerCount; k++ { + s := Stream{ + Name: strconv.Itoa(k), + Key: "", + Live: false, + } + p.servers[s] = &server{} + } + peerMap[id] = p + } + r.peers = peerMap + + // call the subscriptions again + regs = api.GetPeerSubscriptions() + // count how many (fake) subscriptions there are + cnt := 0 + for _, reg := range regs { + for range reg { + cnt++ + } + } + // check expected value + expectedCount := testPeerCount * testServerCount + if cnt != expectedCount { + t.Fatalf("Expected %d subscriptions, but got %d", expectedCount, cnt) + } +} + +/* +TestGetSubscriptionsRPC sets up a simulation network of `nodeCount` nodes, +starts the simulation, waits for SyncUpdateDelay in order to kick off +stream registration, then tests that there are subscriptions. +*/ +func TestGetSubscriptionsRPC(t *testing.T) { + + if testutil.RaceEnabled && os.Getenv("TRAVIS") == "true" { + t.Skip("flaky with -race on Travis") + // Note: related ticket https://github.com/ethersphere/go-ethereum/issues/1234 + } + + // arbitrarily set to 4 + nodeCount := 4 + // set the syncUpdateDelay for sync registrations to start + syncUpdateDelay := 200 * time.Millisecond + // run with more nodes if `longrunning` flag is set + if *longrunning { + nodeCount = 64 + syncUpdateDelay = 10 * time.Second + } + // holds the msg code for SubscribeMsg + var subscribeMsgCode uint64 + var ok bool + var expectedMsgCount counter + + // this channel signalizes that the expected amount of subscriptiosn is done + allSubscriptionsDone := make(chan struct{}) + // after the test, we need to reset the subscriptionFunc to the default + defer func() { subscriptionFunc = doRequestSubscription }() + + // we use this subscriptionFunc for this test: just increases count and calls the actual subscription + subscriptionFunc = func(r *Registry, p *network.Peer, bin uint8, subs map[enode.ID]map[Stream]struct{}) bool { + // syncing starts after syncUpdateDelay and loops after that Duration; we only want to count at the first iteration + // in the first iteration, subs will be empty (no existing subscriptions), thus we can use this check + // this avoids flakyness + if len(subs) == 0 { + expectedMsgCount.inc() + } + doRequestSubscription(r, p, bin, subs) + return true + } + // create a standard sim + sim := simulation.New(map[string]simulation.ServiceFunc{ + "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + addr, netStore, delivery, clean, err := newNetStoreAndDeliveryWithRequestFunc(ctx, bucket, dummyRequestFromPeers) + if err != nil { + return nil, nil, err + } + + // configure so that sync registrations actually happen + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + Retrieval: RetrievalEnabled, + Syncing: SyncingAutoSubscribe, //enable sync registrations + SyncUpdateDelay: syncUpdateDelay, + }, nil) + + // get the SubscribeMsg code + subscribeMsgCode, ok = r.GetSpec().GetCode(SubscribeMsg{}) + if !ok { + t.Fatal("Message code for SubscribeMsg not found") + } + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, + }) + defer sim.Close() + + ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancelSimRun() + + // setup the filter for SubscribeMsg + msgs := sim.PeerEvents( + context.Background(), + sim.UpNodeIDs(), + simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("stream").MsgCode(subscribeMsgCode), + ) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) + if err := sim.UploadSnapshot(ctx, filename); err != nil { + t.Fatal(err) + } + + // strategy: listen to all SubscribeMsg events; after every event we wait + // if after `waitDuration` no more messages are being received, we assume the + // subscription phase has terminated! + + // the loop in this go routine will either wait for new message events + // or times out after 1 second, which signals that we are not receiving + // any new subscriptions any more + go func() { + //for long running sims, waiting 1 sec will not be enough + waitDuration := 1 * time.Second + if *longrunning { + waitDuration = 3 * time.Second + } + for { + select { + case <-ctx.Done(): + return + case m := <-msgs: // just reset the loop + if m.Error != nil { + log.Error("stream message", "err", m.Error) + continue + } + log.Trace("stream message", "node", m.NodeID, "peer", m.PeerID) + case <-time.After(waitDuration): + // one second passed, don't assume more subscriptions + allSubscriptionsDone <- struct{}{} + log.Info("All subscriptions received") + return + + } + } + }() + + //run the simulation + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + log.Info("Simulation running") + nodes := sim.Net.Nodes + + //wait until all subscriptions are done + select { + case <-allSubscriptionsDone: + case <-ctx.Done(): + return errors.New("Context timed out") + } + + log.Debug("Expected message count: ", "expectedMsgCount", expectedMsgCount.count()) + //now iterate again, this time we call each node via RPC to get its subscriptions + realCount := 0 + for _, node := range nodes { + //create rpc client + client, err := node.Client() + if err != nil { + return fmt.Errorf("create node 1 rpc client fail: %v", err) + } + + //ask it for subscriptions + pstreams := make(map[string][]string) + err = client.Call(&pstreams, "stream_getPeerSubscriptions") + if err != nil { + return fmt.Errorf("client call stream_getPeerSubscriptions: %v", err) + } + //length of the subscriptions can not be smaller than number of peers + log.Debug("node subscriptions", "node", node.String()) + for p, ps := range pstreams { + log.Debug("... with", "peer", p) + for _, s := range ps { + log.Debug(".......", "stream", s) + // each node also has subscriptions to RETRIEVE_REQUEST streams, + // we need to ignore those, we are only counting SYNC streams + if !strings.HasPrefix(s, "RETRIEVE_REQUEST") { + realCount++ + } + } + } + log.Debug("All node streams counted", "realCount", realCount) + } + emc := expectedMsgCount.count() + // after a subscription request, internally a live AND a history stream will be subscribed, + // thus the real count should be half of the actual request subscriptions sent + if realCount/2 != emc { + return fmt.Errorf("Real subscriptions and expected amount don't match; real: %d, expected: %d", realCount/2, emc) + } + return nil + }) + if result.Error != nil { + t.Fatal(result.Error) + } +} + +// counter is used to concurrently increment +// and read an integer value. +type counter struct { + v int + mu sync.RWMutex +} + +// Increment the counter. +func (c *counter) inc() { + c.mu.Lock() + defer c.mu.Unlock() + + c.v++ +} + +// Read the counter value. +func (c *counter) count() int { + c.mu.RLock() + defer c.mu.RUnlock() + + return c.v +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer.go index 4bfbac8b..5f03dcff 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer.go @@ -107,6 +107,11 @@ func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint6 metrics.GetOrRegisterCounter("syncer.setnextbatch.iterator", nil).Inc(1) err := s.store.Iterator(from, to, s.po, func(key storage.Address, idx uint64) bool { + select { + case <-s.quit: + return false + default: + } batch = append(batch, key[:]...) i++ to = idx @@ -127,19 +132,9 @@ func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint6 // SwarmSyncerClient type SwarmSyncerClient struct { - sessionAt uint64 - nextC chan struct{} - sessionRoot storage.Address - sessionReader storage.LazySectionReader - retrieveC chan *storage.Chunk - storeC chan *storage.Chunk - store storage.SyncChunkStore - // chunker storage.Chunker - currentRoot storage.Address - requestFunc func(chunk *storage.Chunk) - end, start uint64 - peer *Peer - stream Stream + store storage.SyncChunkStore + peer *Peer + stream Stream } // NewSwarmSyncerClient is a contructor for provable data exchange syncer @@ -209,46 +204,6 @@ func (s *SwarmSyncerClient) BatchDone(stream Stream, from uint64, hashes []byte, return nil } -func (s *SwarmSyncerClient) TakeoverProof(stream Stream, from uint64, hashes []byte, root storage.Address) (*TakeoverProof, error) { - // for provable syncer currentRoot is non-zero length - // TODO: reenable this with putter/getter - // if s.chunker != nil { - // if from > s.sessionAt { // for live syncing currentRoot is always updated - // //expRoot, err := s.chunker.Append(s.currentRoot, bytes.NewReader(hashes), s.retrieveC, s.storeC) - // expRoot, _, err := s.chunker.Append(s.currentRoot, bytes.NewReader(hashes), s.retrieveC) - // if err != nil { - // return nil, err - // } - // if !bytes.Equal(root, expRoot) { - // return nil, fmt.Errorf("HandoverProof mismatch") - // } - // s.currentRoot = root - // } else { - // expHashes := make([]byte, len(hashes)) - // _, err := s.sessionReader.ReadAt(expHashes, int64(s.end*HashSize)) - // if err != nil && err != io.EOF { - // return nil, err - // } - // if !bytes.Equal(expHashes, hashes) { - // return nil, errors.New("invalid proof") - // } - // } - // return nil, nil - // } - s.end += uint64(len(hashes)) / HashSize - takeover := &Takeover{ - Stream: stream, - Start: s.start, - End: s.end, - Root: root, - } - // serialise and sign - return &TakeoverProof{ - Takeover: takeover, - Sig: nil, - }, nil -} - func (s *SwarmSyncerClient) Close() {} // base for parsing and formating sync bin key diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer_test.go index a543cae0..07586714 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/syncer_test.go @@ -18,6 +18,7 @@ package stream import ( "context" + "errors" "fmt" "io/ioutil" "math" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/swarm/log" @@ -36,20 +36,26 @@ import ( "github.com/ethereum/go-ethereum/swarm/network/simulation" "github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/storage" - mockdb "github.com/ethereum/go-ethereum/swarm/storage/mock/db" + "github.com/ethereum/go-ethereum/swarm/storage/mock" "github.com/ethereum/go-ethereum/swarm/testutil" ) const dataChunkCount = 200 func TestSyncerSimulation(t *testing.T) { - testSyncBetweenNodes(t, 2, 1, dataChunkCount, true, 1) - testSyncBetweenNodes(t, 4, 1, dataChunkCount, true, 1) - testSyncBetweenNodes(t, 8, 1, dataChunkCount, true, 1) - testSyncBetweenNodes(t, 16, 1, dataChunkCount, true, 1) + testSyncBetweenNodes(t, 2, dataChunkCount, true, 1) + // This test uses much more memory when running with + // race detector. Allow it to finish successfully by + // reducing its scope, and still check for data races + // with the smallest number of nodes. + if !testutil.RaceEnabled { + testSyncBetweenNodes(t, 4, dataChunkCount, true, 1) + testSyncBetweenNodes(t, 8, dataChunkCount, true, 1) + testSyncBetweenNodes(t, 16, dataChunkCount, true, 1) + } } -func createMockStore(globalStore *mockdb.GlobalStore, id enode.ID, addr *network.BzzAddr) (lstore storage.ChunkStore, datadir string, err error) { +func createMockStore(globalStore mock.GlobalStorer, id enode.ID, addr *network.BzzAddr) (lstore storage.ChunkStore, datadir string, err error) { address := common.BytesToAddress(id.Bytes()) mockStore := globalStore.NewNodeStore(address) params := storage.NewDefaultLocalStoreParams() @@ -67,65 +73,50 @@ func createMockStore(globalStore *mockdb.GlobalStore, id enode.ID, addr *network return lstore, datadir, nil } -func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck bool, po uint8) { +func testSyncBetweenNodes(t *testing.T, nodes, chunkCount int, skipCheck bool, po uint8) { + sim := simulation.New(map[string]simulation.ServiceFunc{ "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - var store storage.ChunkStore - var globalStore *mockdb.GlobalStore - var gDir, datadir string - - node := ctx.Config.Node() - addr := network.NewAddr(node) + addr := network.NewAddr(ctx.Config.Node()) //hack to put addresses in same space addr.OAddr[0] = byte(0) - if *useMockStore { - gDir, globalStore, err = createGlobalStore() + netStore, delivery, clean, err := newNetStoreAndDeliveryWithBzzAddr(ctx, bucket, addr) + if err != nil { + return nil, nil, err + } + + var dir string + var store *state.DBStore + if testutil.RaceEnabled { + // Use on-disk DBStore to reduce memory consumption in race tests. + dir, err = ioutil.TempDir("", "swarm-stream-") if err != nil { - return nil, nil, fmt.Errorf("Something went wrong; using mockStore enabled but globalStore is nil") + return nil, nil, err + } + store, err = state.NewDBStore(dir) + if err != nil { + return nil, nil, err } - store, datadir, err = createMockStore(globalStore, node.ID(), addr) } else { - store, datadir, err = createTestLocalStorageForID(node.ID(), addr) + store = state.NewInmemoryStore() } - if err != nil { - return nil, nil, err - } - bucket.Store(bucketKeyStore, store) - cleanup = func() { - store.Close() - os.RemoveAll(datadir) - if *useMockStore { - err := globalStore.Close() - if err != nil { - log.Error("Error closing global store! %v", "err", err) - } - os.RemoveAll(gDir) - } - } - localStore := store.(*storage.LocalStore) - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, nil, err - } - bucket.Store(bucketKeyDB, netStore) - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New - bucket.Store(bucketKeyDelivery, delivery) - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ Retrieval: RetrievalDisabled, Syncing: SyncingAutoSubscribe, SkipCheck: skipCheck, - }) + }, nil) - fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) - bucket.Store(bucketKeyFileStore, fileStore) + cleanup = func() { + r.Close() + clean() + if dir != "" { + os.RemoveAll(dir) + } + } return r, cleanup, nil - }, }) defer sim.Close() @@ -140,7 +131,7 @@ func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck if err != nil { t.Fatal(err) } - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { nodeIDs := sim.UpNodeIDs() nodeIndex := make(map[enode.ID]int) @@ -148,18 +139,10 @@ func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck nodeIndex[id] = i } - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - - go func() { - for d := range disconnections { - if d.Error != nil { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - t.Fatal(d.Error) - } + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") } }() @@ -168,7 +151,7 @@ func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck id := nodeIDs[j] client, err := sim.Net.GetNode(id).Client() if err != nil { - t.Fatal(err) + return fmt.Errorf("node %s client: %v", id, err) } sid := nodeIDs[j+1] client.CallContext(ctx, nil, "stream_subscribeStream", sid, NewStream("SYNC", FormatSyncBinKey(1), false), NewRange(0, 0), Top) @@ -184,16 +167,12 @@ func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck size := chunkCount * chunkSize _, wait, err := fileStore.Store(ctx, testutil.RandomReader(j, size), int64(size), false) if err != nil { - t.Fatal(err.Error()) + return fmt.Errorf("fileStore.Store: %v", err) } wait(ctx) } } // here we distribute chunks of a random file into stores 1...nodes - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - return err - } - // collect hashes in po 1 bin for each node hashes := make([][]storage.Address, nodes) totalHashes := 0 @@ -244,3 +223,133 @@ func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck t.Fatal(result.Error) } } + +//TestSameVersionID just checks that if the version is not changed, +//then streamer peers see each other +func TestSameVersionID(t *testing.T) { + //test version ID + v := uint(1) + sim := simulation.New(map[string]simulation.ServiceFunc{ + "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) + if err != nil { + return nil, nil, err + } + + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingAutoSubscribe, + }, nil) + bucket.Store(bucketKeyRegistry, r) + + //assign to each node the same version ID + r.spec.Version = v + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, + }) + defer sim.Close() + + //connect just two nodes + log.Info("Adding nodes to simulation") + _, err := sim.AddNodesAndConnectChain(2) + if err != nil { + t.Fatal(err) + } + + log.Info("Starting simulation") + ctx := context.Background() + //make sure they have time to connect + time.Sleep(200 * time.Millisecond) + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + //get the pivot node's filestore + nodes := sim.UpNodeIDs() + + item, ok := sim.NodeItem(nodes[0], bucketKeyRegistry) + if !ok { + return fmt.Errorf("No filestore") + } + registry := item.(*Registry) + + //the peers should connect, thus getting the peer should not return nil + if registry.getPeer(nodes[1]) == nil { + return errors.New("Expected the peer to not be nil, but it is") + } + return nil + }) + if result.Error != nil { + t.Fatal(result.Error) + } + log.Info("Simulation ended") +} + +//TestDifferentVersionID proves that if the streamer protocol version doesn't match, +//then the peers are not connected at streamer level +func TestDifferentVersionID(t *testing.T) { + //create a variable to hold the version ID + v := uint(0) + sim := simulation.New(map[string]simulation.ServiceFunc{ + "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) + if err != nil { + return nil, nil, err + } + + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingAutoSubscribe, + }, nil) + bucket.Store(bucketKeyRegistry, r) + + //increase the version ID for each node + v++ + r.spec.Version = v + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, + }) + defer sim.Close() + + //connect the nodes + log.Info("Adding nodes to simulation") + _, err := sim.AddNodesAndConnectChain(2) + if err != nil { + t.Fatal(err) + } + + log.Info("Starting simulation") + ctx := context.Background() + //make sure they have time to connect + time.Sleep(200 * time.Millisecond) + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + //get the pivot node's filestore + nodes := sim.UpNodeIDs() + + item, ok := sim.NodeItem(nodes[0], bucketKeyRegistry) + if !ok { + return fmt.Errorf("No filestore") + } + registry := item.(*Registry) + + //getting the other peer should fail due to the different version numbers + if registry.getPeer(nodes[1]) != nil { + return errors.New("Expected the peer to be nil, but it is not") + } + return nil + }) + if result.Error != nil { + t.Fatal(result.Error) + } + log.Info("Simulation ended") + +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_128.json b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_128.json index 9b5eb501..d25fa51c 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_128.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_128.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","private_key":"73015943fd2c673001da6bf6658a12a22e057fc545ac0ebc78421f90f1370093","name":"node_a9e0b763852706722dc904b494293f9399c0fa32255890aa720285b8160335bb618f36b68a81b875a805384179f600defef474d486b4ea04b003ef6477ab7907","services":["streamer"],"enable_msg_events":true,"port":63042},"up":true}},{"node":{"config":{"id":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","private_key":"89cbfe6d806f2aeaee6a59667df3c3059ff7531bb33d64661586b004fcb6b831","name":"node_87e696a354d249493217dc4e0190082f30e09616873803efa376871d4b34f86f0eeb4643d4822d8a0fbcdedb27cd6ba5438e98943d358d960c4835e82261c93e","services":["streamer"],"enable_msg_events":true,"port":63043},"up":true}},{"node":{"config":{"id":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","private_key":"ff2ac479a33dc7fff5f87e4bb3078dfbcbb1567b76e35792faf104a383ebf896","name":"node_18bb6572965f4263c5a4d59a73027abc57a46122125ee58d871e95c993e6a1e8230438ce696a5f8880a08749837268b54319f7b0aa254c1a5bd453a8e9bcf84f","services":["streamer"],"enable_msg_events":true,"port":63044},"up":true}},{"node":{"config":{"id":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","private_key":"4800e21ac6431c61873444c525e207b48bb7a09ba2793b482ba6cf8cce81e353","name":"node_3103510e00a3f49a5e715719049fc8c9c67a2373a548f326458aeb6d9c75ed92b94373638fd075def0209113b4e85d972c23f064539f7b041596184e40d7f9a2","services":["streamer"],"enable_msg_events":true,"port":63045},"up":true}},{"node":{"config":{"id":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","private_key":"7e26b011ae2eabac951145e7840169b1f279577c06c40b4ba3a62da3ddb58de5","name":"node_077d2d032874e5ce70e9b928b7fe72c0326ba92394e16245e31d48b5731d3d32bfd86acf40825decff54bcd735e9ebfd94eba677c418ea7007baec9db4af676d","services":["streamer"],"enable_msg_events":true,"port":63046},"up":true}},{"node":{"config":{"id":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","private_key":"1fbf6b44eeb20ef012046cf8b7d3400ef3e586586aaf1cf6a2e5115ff5e3d868","name":"node_d90a81a583c82d626b92f27244f027da4a0ae76e6d3bdc1de0af7be01798f1fb04b34ce60c6d8651a39d7a70915438a4aa63e5adf844a9f7e38dbf0b1dba754d","services":["streamer"],"enable_msg_events":true,"port":63047},"up":true}},{"node":{"config":{"id":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","private_key":"f32eafbb366e4b7655d302a06aac2e62ff8f4b9c07bb18175e58e534193b8554","name":"node_31ac37862416c0e229c4a088ec179f23bdd1bf12dd464eb11c630ad531d7c3438671862e5458e2f6fbb32b857f857e6b8c17e5d93eb29a0e78bb5a65d7eb648c","services":["streamer"],"enable_msg_events":true,"port":63048},"up":true}},{"node":{"config":{"id":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","private_key":"6a809d9de0380db0b8bae8769cf41f9b05576137d0e2eefa69b7ddd921c6ac77","name":"node_1e3c83cabbe6852c987ae521b7fcb33185cf855c59b6235ebb8e57a6f860ccc159ddc01b4a21d251c8faca4559ceb271e046a51493ba148c0d3aed97ad208969","services":["streamer"],"enable_msg_events":true,"port":63049},"up":true}},{"node":{"config":{"id":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","private_key":"f23b80b698ec97210ddaa65807a07cee7b411018ddd96c9d700e92a83120cf9e","name":"node_2fdb4382c4bc2950948a8cff13a7df65627bc0b20661cae20fd29acab166c97701594ee3151d75c006ba86d1d68b624b1d1f78e3d1e2fc297844956ef82208a8","services":["streamer"],"enable_msg_events":true,"port":63050},"up":true}},{"node":{"config":{"id":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","private_key":"d2d74e454118a6e150810c74080ee7707b92b4575e7fe13c8887caf521cc734d","name":"node_87fce129511a1be2777052d24b606acdfe7067f4e874ab04674a68664b378ea208975f7269a72af889d3d23cd930b6a181afa2cdef3f9f9491f715bd96ad8dc0","services":["streamer"],"enable_msg_events":true,"port":63051},"up":true}},{"node":{"config":{"id":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","private_key":"cdc72a1d2e475117e77abccdee1816e4d84fb059d712b717e8bd063239b6fd58","name":"node_c773af3af01ee8ab9fa8d06987baf4f10c394fdd386d69b7a7362f4b68fd6fc082337d3b33a19d584c5801a3e9198225d7b61f6629e34ce823be70908339f4c7","services":["streamer"],"enable_msg_events":true,"port":63052},"up":true}},{"node":{"config":{"id":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","private_key":"b1b2452fe8ea070ff3b181fdc538144e1231f0c6f467713712662375dc6c4bb1","name":"node_56b25623ac935f3a8aac1e2603a6bd15ace1e5714671954b47f2cab960cf47922828f415105602408d0a732a893ebeea6f9afab7f889bb235c81589548d09391","services":["streamer"],"enable_msg_events":true,"port":63053},"up":true}},{"node":{"config":{"id":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","private_key":"e87535b0ec914ff93ea21f722eff61dd6cfea4f5542f68aab0af93c58e2afc25","name":"node_09b60de1e85bb6f7d2caf5b1ab58204d7d04531ece300dcd7bcc9157b8b3ef2a182758808a0eec6056034f29f52caadb7c690f498c1c8832ff7a6a9ecff308bd","services":["streamer"],"enable_msg_events":true,"port":63054},"up":true}},{"node":{"config":{"id":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","private_key":"3ae9a961f597c04b695a6d25fd0e6e47b131854f55f89d8ac25cce7411aa4107","name":"node_f2ea93f43be9d0c3fa21f1496dc13c778977a6afdcba24c8b146de7dca2cdde62a5b792aab969e5b4b6c56f63066b336580d911f206049cc24cac32a25fc4306","services":["streamer"],"enable_msg_events":true,"port":63055},"up":true}},{"node":{"config":{"id":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","private_key":"1676fda16b41e3ec275f0d30ad691055248be71252ad15422b9c0260671aaf4c","name":"node_872cdbb6d74fb55fd2d51877ef7804bdd2eeb6de0297eb2ce18b67e52379b147d54a46d2385ec9293eb21736bed4191d92c5c75e8e81fc5a6c691970e019f570","services":["streamer"],"enable_msg_events":true,"port":63056},"up":true}},{"node":{"config":{"id":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","private_key":"6c989b24f2387e5a639effc8cd15b6d60c587fd14615496c9463d1f1a7ff6ad5","name":"node_da3e0fd71eb96ba2cab7f920d32f5425d1aad41d00765fdffb0b215d9dd5b60e2bc5929eafebee5b2b5a11aec164e141beff19d828aac7d1fabd3ffb0bfb8450","services":["streamer"],"enable_msg_events":true,"port":63057},"up":true}},{"node":{"config":{"id":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","private_key":"a1befe78e67ca8b4972ba564c3bd03ad2ca6b996ded22166468d7a268a4c77d3","name":"node_489660042a8867d90a16ebb013968db26ca3edfc70f53320f511e35b3703eed09fbd787be5c06726a570a54aa15d129cd10db741523adf297929f909be4a0c71","services":["streamer"],"enable_msg_events":true,"port":63058},"up":true}},{"node":{"config":{"id":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","private_key":"6b9ad7d1da45cff60c3bdcac68f0af30e0a6e0e30e4ad73731c00368e9b0254a","name":"node_4448a59bde9edb93edcdb4a77f3e2277b9c01ffea45496ee0533eb5192955a08a0f982e25cf772e0dae68735a55b7acd221f6ba7b134f1e999087bee182330e8","services":["streamer"],"enable_msg_events":true,"port":63059},"up":true}},{"node":{"config":{"id":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","private_key":"157e46312708757a331443dd95e1a0c012502430f4a8f8756f0aeaf35bde1f6d","name":"node_73319a301ad3cf0ec09549d817c9523d61b74abb0cad87b737d41d900321e52722a84355f6f87bc7a5f848818c89a021bb0f3e5994f67c9a7b5bbfc98188a376","services":["streamer"],"enable_msg_events":true,"port":63060},"up":true}},{"node":{"config":{"id":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","private_key":"11148e1d9812b7bb8870b7960332ba4b32ea6aa43a57f9a27c30c2fafb609570","name":"node_caad8529d498a4a1e1ba7573689a913500bd409345ef8e3656abca748269eb73b919282f7f2eb0087f81f7bc52c367657ac8be0cdac65d2490c7c50c874444b7","services":["streamer"],"enable_msg_events":true,"port":63061},"up":true}},{"node":{"config":{"id":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","private_key":"896c3ee65d71ddcbf6030b920c0bf7748971170583e45fa2e33c19b3222e3945","name":"node_44462055ba68fdef337dd19d8123aace9a12284c13bc97687416b6b4ca0c94234ba7db6823651fc021d6ac1539e0c5321e763a7a12c9e7c8a583aac5369817d8","services":["streamer"],"enable_msg_events":true,"port":63062},"up":true}},{"node":{"config":{"id":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","private_key":"043c2adc5bdb3449b2f770e1207eac21128e77e89c9e1fe8876cecf1792f8b24","name":"node_ecbdca037cd7892752345b48b4219478b1b334f83ce7140fcc72eb71784436b690ce7a41b03e013cefc19d64a34a20cfef1b9e2b535d938bcdcb39fe63645a42","services":["streamer"],"enable_msg_events":true,"port":63063},"up":true}},{"node":{"config":{"id":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","private_key":"88f2cc06ba260e7c09cdd93e48c55c000d7a988ef65ccfc5331d1eac3c66d7b1","name":"node_51ba4faf0988717a37dcddc0a60a70ead33bde310184fc450f9ca73c67f931e6767ad5930bcf409e5aeb613a9ff7a03e47de6fc13b33d8af0b87b38822ae6888","services":["streamer"],"enable_msg_events":true,"port":63064},"up":true}},{"node":{"config":{"id":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","private_key":"8c64fc376a830b9237a1d1609a24e18396eb82cd6cd64b8ff572c9f946aaab2c","name":"node_750ca601f07d65f426f6ea5f34e06238f9d7a931f022f9b0ebc811943d3725500cb3c6f00c8d05eb8d5b353c6534136dff38b9a8d3d4dc5bf49cd96875704d07","services":["streamer"],"enable_msg_events":true,"port":63065},"up":true}},{"node":{"config":{"id":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","private_key":"545e42fc4dfd38b62f1481fe46895a3cb9c6632930c8df8358d66a3988e6fe72","name":"node_41994605708232b4ca7448c3bc0760a7b86bf26d442091e5ce6e92eac94925721d7e0eca04bdd03bb1bba1ef92deeccd4bf1b7c6c3318b7e8d031965c6646761","services":["streamer"],"enable_msg_events":true,"port":63066},"up":true}},{"node":{"config":{"id":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","private_key":"3e5b24d432307724a3e619c479ad5c87a93c6ee96d2b6ab0dad17da7e84eea55","name":"node_28afc20d8f4779b285bb14870062dbb54796ec77623302e51bc1bafed9e2c35751c8469ffc482718e059875dfa2226195ed10999e251498cba3a444896cb67db","services":["streamer"],"enable_msg_events":true,"port":63067},"up":true}},{"node":{"config":{"id":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","private_key":"cab0eaf666548a84a7ceb4a34a29b7079c66b0df29e7fd315e851e02a8c9a5ed","name":"node_805d784527be4e32e84ddf045baee1ccf348cdf8288de3aae1a5379f762576b957525ef358d9b42c68a93394017880adc09bb2b1b5e01102dc7e4240baf2af95","services":["streamer"],"enable_msg_events":true,"port":63068},"up":true}},{"node":{"config":{"id":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","private_key":"8c48ba58bc5ac8c0f3f0295c73df1572e80465f15a97f1c5537735474b11da89","name":"node_9c6dcfef0e128dbfeca58b8ac625b08fb447b0d579bd3f18bc0e2be60d1ec2274595d0554ddba0ca7eb660099d3ea146d8076792b46c93841d2ecf8cf608f5ba","services":["streamer"],"enable_msg_events":true,"port":63069},"up":true}},{"node":{"config":{"id":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","private_key":"0939af4a1ac3398bd818e5ac35e1003530a80a0abba5bf4c586664ab0b15a391","name":"node_6ce3a68cb1e2924ad97f22006094c709a3dd8b4ca1546fbb037f841a9e5ac62def242015dbf6221bda610153db064edcbb58a78a35a06077b8c02bf5b2a33c04","services":["streamer"],"enable_msg_events":true,"port":63070},"up":true}},{"node":{"config":{"id":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","private_key":"bfdc13ed4844405928ae3f67e209353779af203143a9f43fd8d1fc899ddd56a7","name":"node_178d5ce398a7114a63a0c953a59932e769891420f6b1544f08c082cd37b531b66757652d279b3036b03b04f8d46eceb0b46fb95646c6668e2921af75c06c3d97","services":["streamer"],"enable_msg_events":true,"port":63071},"up":true}},{"node":{"config":{"id":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","private_key":"d52f5bca67f434e20d72348971b791cb18def6182b002a3342c721ed06e9ad84","name":"node_59730132a01ba848a3c050bb6234bca9a72deba33716960fc3ec89b186bfcd313b9bbf049939d5805ff98db2c53a9421ce6ec97d8b4cdbaea53ba264d80d0734","services":["streamer"],"enable_msg_events":true,"port":63072},"up":true}},{"node":{"config":{"id":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","private_key":"7d5751c36a856dbc2403a058a432e1f2bd142ae438444db9febdaa22480dd404","name":"node_93987e431a0058f2e942ccf8d3486d249cd2734d6494131b343e2c3a8fdd86cfcb12d0aaaf8fcb911ad3cdd682cc82118198195a7fdc915ab7853223f012eab6","services":["streamer"],"enable_msg_events":true,"port":63073},"up":true}},{"node":{"config":{"id":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","private_key":"5cb8cc7f27d0f0e28e9ca55b592a38839058155cfce8528b5a464f98025eb54d","name":"node_665c3288c14dc1c17d85d17d634910f42183482c7e77c47e68f9b4f475b93e8c152246b9e34781606315ff6ef0f8360342500d15e4a2d67d9df6b72f30af64a7","services":["streamer"],"enable_msg_events":true,"port":63074},"up":true}},{"node":{"config":{"id":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","private_key":"3901f39cd02354a635723259be3a5e7c28de3f7406c889fc9353d3adb22b9d82","name":"node_562119edffe8270f6f7a5ad9b13d4c65d643e52a2331d1fee16f7e9b5567f44cfea62df3e8965a22cf08db8fa918f0a0bcae8da2936677e6d25bc88ed85ed2f1","services":["streamer"],"enable_msg_events":true,"port":63075},"up":true}},{"node":{"config":{"id":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","private_key":"4e740dfca715720a19f56d32d6b9783810e1d6da09425e01dfbe3b55714416c0","name":"node_2502fc8ee0ccda79ad1dbd9c7cec625da85980b9116bdd56dc367d508039e25e5f65183293006e5b0df72fa9037a48bd2b133a757940d3587ff77ae2392e3eaf","services":["streamer"],"enable_msg_events":true,"port":63076},"up":true}},{"node":{"config":{"id":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","private_key":"765219c4fea7ac80a0c5d26a096829226933310ad22d889ee19eb23915363fda","name":"node_e9f7e58fda4b504275441d51929fbc98214abdc9ed552c7aa94c600a85d4e791d60c032304b29ae028adccec94984fc9a3d705a81462632f50ef45024eb0f64e","services":["streamer"],"enable_msg_events":true,"port":63077},"up":true}},{"node":{"config":{"id":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","private_key":"edf1f1608ee4b7c320472a071f2d60d53c7b74e58fba190b5353e92056f30751","name":"node_9e6c1c6e871638182c4b54ac89352ef5c2bca0a99424a1369013e7c182883da0e8d7ab96b3c8254c31fa315b941d8ddee153157626821fc78c2cae951c1c9053","services":["streamer"],"enable_msg_events":true,"port":63078},"up":true}},{"node":{"config":{"id":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","private_key":"16e405179555f907062a85c408713f0fa46a5f1f6714c99272bb705ae226b2a5","name":"node_bfef26733f5196a11484bcc28d88776e747189ae7cec883ff39a27cfeee6d9d1efb34560c9f8e75eec43fc069a2ce5f0c78107a36cc8a569d37bd5306aecf23a","services":["streamer"],"enable_msg_events":true,"port":63079},"up":true}},{"node":{"config":{"id":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","private_key":"8337241aad3fa93ccc78bab1ff15a2aa218fbd7d026bffe74b7dadd8e6aa787f","name":"node_f6a07a1d361a4671e997d5eaadae61736291aff3896cb69f06bbc19bf7536dd152e0b15422b2fd9f8a9d2f9a251c9a07d0140319900e2cc9f25a59025c7dc91f","services":["streamer"],"enable_msg_events":true,"port":63080},"up":true}},{"node":{"config":{"id":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","private_key":"af0eb33b99b22cff74cc8137b4bb9477f8f47c895a61807279436daefaf9cac8","name":"node_08900197e74e285a5a8a9cc53fbd420bb35043ab27eb2d9eab22615e736a093abfa235c17f667dcc791cb50b9022082eafd9fba030194cc84f0358b769adc85b","services":["streamer"],"enable_msg_events":true,"port":63081},"up":true}},{"node":{"config":{"id":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","private_key":"3c9a377e5ae9212adee118e04b3cd9cead5b4830ee51492dffbec8f015b5b757","name":"node_afb5754b4748b7ac5628e32b242c90aab0e2fc7da58d8d5c8c775d13d8a6fd32240f1b89021587858168cbe7b3ea7ad07807728655eae0a9907060494a7c99ca","services":["streamer"],"enable_msg_events":true,"port":63082},"up":true}},{"node":{"config":{"id":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","private_key":"5ccc64d0c951c9f50f0f7053504f54f965e22a22fb06b0bd14f206d72d822fa6","name":"node_8f625a4e4f4fd980c796d3aa535e58a39722492480cf6982d43fab02de63a5b4c1b5c7cd8402171dd792bb5d9c3e2bdd38176c061dbe3e5b0592af1339e3fd82","services":["streamer"],"enable_msg_events":true,"port":63083},"up":true}},{"node":{"config":{"id":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","private_key":"f44a9e23990fd65de4da61711cb5a720a4474421ea0a653c7ce5ed76149b335d","name":"node_ab3814579882e9fd8d464f4f3c8a421be37822ba7f42c5f5e787e81125ec032f9ccf90a138c0b57f0a813b55b583f80d66284f795e2c82d80d2869e1fc770be5","services":["streamer"],"enable_msg_events":true,"port":63084},"up":true}},{"node":{"config":{"id":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","private_key":"4fd7ee5ba8003bb9b914612e6283cf5738550412c71e4475e07eb8bef32e96a4","name":"node_670949178a5fad22da03af1e206c814a797c0e9eb4e3371f83612f121e5b56e767706a3ae36628cd0c86dd7bd1586ca4df57e2de27b28a31284ecf9176d330e5","services":["streamer"],"enable_msg_events":true,"port":63085},"up":true}},{"node":{"config":{"id":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","private_key":"d0df7b482eb60b2f1ed4c2562768f60fe5ee8997e542bc9c7310db55391553d4","name":"node_fd12c5c96df6ee76dd7beb9e4e4768dda4d2c498851b6435f13ca0175980d0e4a4ff1c002e4daf41a995f118500604764f88496fb9b2c22e28308d8649b525ce","services":["streamer"],"enable_msg_events":true,"port":63086},"up":true}},{"node":{"config":{"id":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","private_key":"7771ce12670dba4c28198f6df284ad58c9ca877a25ceb912ec3af5ac83f6e143","name":"node_ed1ab28230ed533abf25633508d54f32bbff78a10c7a15fad5c2320cda9d9669c6d0e15689d8885400e64cbcd81730456f8f4bd5c98681d2cd8a8d4e1daec553","services":["streamer"],"enable_msg_events":true,"port":63087},"up":true}},{"node":{"config":{"id":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","private_key":"97cc28baaa8c94c905d348295eb19ef607599d22742989105d03eff39a5d6d51","name":"node_a05a18161c2d01a0f122548c66509dd1fcf3ee52975035bc79fb059e9613b743a16cd6f5ac54090e68f51bcf76ff21fb3805ba3197a96b4236afb80f791df802","services":["streamer"],"enable_msg_events":true,"port":63088},"up":true}},{"node":{"config":{"id":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","private_key":"9f191333ec4b20a2380317b819e71ffc234e63e85ec57548c407e1740c07f41f","name":"node_c89dbada7195464e732671ac6fff014cacfb4c879b63b6b84e7c1bce367522f759bd06e504b15f43a1735c6322356747fa5c4951882d4fd6cdf6f7cf13726719","services":["streamer"],"enable_msg_events":true,"port":63089},"up":true}},{"node":{"config":{"id":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","private_key":"9b597a8aa9ae03a20ec963fd3eeaca13823d7efd28a70c4c44ebfa6e147bb24a","name":"node_51302ef7b50922398ad802e917390bb4a3c24c877f2c2bcb7fcb34de9feca22673a2c594639914fe46a28837ffadfd03bb673afbc856aff5e59caf8e76082482","services":["streamer"],"enable_msg_events":true,"port":63090},"up":true}},{"node":{"config":{"id":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","private_key":"342dbb181da6045ae41eacef680b93f58765c7c5d65713f25f8b0627863c7983","name":"node_a40391285d1a97f1fb368b20c8e4d02be1bdebc0db41f00f99aac2f01893dc12256cd5a711117a981fbb3f9dfea18c19cf3603e925dbd67c4032b22b41eab8d5","services":["streamer"],"enable_msg_events":true,"port":63091},"up":true}},{"node":{"config":{"id":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","private_key":"af173c26c979843230716c1a7f4aade4f9a19a23e2ee665d0a0ecae0f793188e","name":"node_e0420ba2a293315d810928a0e09a507c6aaf93977ba2c7598e9b83723b4a66682398ea17542c26767c7ff0f4ca09c537d3cc10dad283f079f1de73e25e87cb5c","services":["streamer"],"enable_msg_events":true,"port":63092},"up":true}},{"node":{"config":{"id":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","private_key":"4598804bbccfa26a362afa9773f283bfbc0ab7660240791e38f7ba858e45280d","name":"node_33e3ab7108ced43102003c3b3192b194100f32b6bcb67bb772ea9696e35721196699cf01e443f7cdf8076ad83aaf7468b75c71d03efb95f4c07cf0742ea9af81","services":["streamer"],"enable_msg_events":true,"port":63093},"up":true}},{"node":{"config":{"id":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","private_key":"253935f834190e90b6bf0646618d2992233bf386ea31a58770e1926cb063050c","name":"node_cbed12dcab0aa04a96ec7e25bc2ee03b337c7b2006391baa7d2aff042c17ec70b82c5fb2dc916d085a7948541719d329f9b528b67ec6adb1ac2cc594d4ef1e42","services":["streamer"],"enable_msg_events":true,"port":63094},"up":true}},{"node":{"config":{"id":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","private_key":"f6d280904f13397798c441bffafc78ab98461c9d84f01f4b9b73de50d5595fd0","name":"node_03d2d77c008b5fa1063b1abc3152b879a529fe4fdb2dc174d6d85312264a38ee4cc49b342507a10fff1a4b0730f1ef8e008b0897d97bfd6f70050adb124d3596","services":["streamer"],"enable_msg_events":true,"port":63095},"up":true}},{"node":{"config":{"id":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","private_key":"5237d9097b72efee4e45c4d3d14e320e49ded470809478f3ccf6a9a7cf732d74","name":"node_f0299035cbddfdf7a78e5e3a400aaedf2d719d04e907ac0f9f067525e2f9bb913d985308a3a0d05467a64adf58c68a615c6327acf716c23631d0e829903f8b34","services":["streamer"],"enable_msg_events":true,"port":63096},"up":true}},{"node":{"config":{"id":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","private_key":"a8d169922df4dcd07e1f102e3eae5692eb87b1f368124cb5c65fcca22f9743aa","name":"node_276256790c9317d09ff7802f4ad0a85840fe62527390ce1790e1e3186e8b3f04acfaa41dcd02303d333423678a4037e4f4854676e79ced3232a3dbd772cc2680","services":["streamer"],"enable_msg_events":true,"port":63097},"up":true}},{"node":{"config":{"id":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","private_key":"8b927156a8aa7b6cc711c9c2ce3016cab2e9d1ce220e9792207cc5b40fca3047","name":"node_155805f787600f9f9518cf8836f491885b64868bfe0023975bcd12776925a424fb5aa3199dc178e83294e97f347a373d05d2422578a08eeeb2d15a178d28964f","services":["streamer"],"enable_msg_events":true,"port":63098},"up":true}},{"node":{"config":{"id":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","private_key":"d2b8d940f626faf3204dd38721f5528e1c9db4b5d0cc28d0d627c7d191c1f21f","name":"node_4de606aa7e722197b918c5f7f0db86a3081d48e89d21428b04f19c3ff3755eac0bddbff5fad8bda94b9e57f58fba2fecdbabbf710f7afb381bf4f1a4fe55cd93","services":["streamer"],"enable_msg_events":true,"port":63099},"up":true}},{"node":{"config":{"id":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","private_key":"1cd1a1e084096aa4f8f9933b0871657638dad24b3f47d18c9eb0007595ce46f1","name":"node_82a774be7146766585d2bec6b69b7803aa956f492a53d8ed5f071becdbbc617562885d8430f0afd505210aab7b032428fbea32c82dffbd12d9ccba776ef4729b","services":["streamer"],"enable_msg_events":true,"port":63100},"up":true}},{"node":{"config":{"id":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","private_key":"8ec23f2c16d923996d6bd74aa374cb6e5a69fab748ea8efa538d01a12ac62e16","name":"node_340420ee18d55913f790d0fcc2305b40b1e7bef2eddb79dda57801690aeeead693ebd1a9ff8557671f5ae136b3e65733306924bd00444cbc6e7c6235e5a2c77f","services":["streamer"],"enable_msg_events":true,"port":63101},"up":true}},{"node":{"config":{"id":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","private_key":"b7a9a55daea83c1d769fe68e820de46f4a8df4c425ea7ab98a44cb7ad3c7963e","name":"node_7a509686ebce91778fe22e834a94ab03f92457d41385099ba657fe62c7469a9669bddb9a3d7b0150efa1d2f40c69bc786c7f4ede1cf8b19411eea1d23cb7d56c","services":["streamer"],"enable_msg_events":true,"port":63102},"up":true}},{"node":{"config":{"id":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","private_key":"c1478fa3ebc5b2bd2a32567455e71e73a1787b1c8c6571fd94ee0d487d5fea4d","name":"node_816e91fa8ff68ba067a89390ef61e7f23211e5e05049daa103ad1ff84b94fbcf535a6f6b515fb571939f5656869767c608513808800baba7e5d2b5f3a17a9691","services":["streamer"],"enable_msg_events":true,"port":63103},"up":true}},{"node":{"config":{"id":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","private_key":"bb118c1ce93cddc4fb540863d575d6ae584ebc2f2e2f221c9622cc105e7fd7b9","name":"node_77327983685f39f006806170fe351063a58ff1bd8dedc222d538e86cfd18abdfefd548328f25fc5afde8170aa5c35311353019468f2b439c331837ddfbb25a52","services":["streamer"],"enable_msg_events":true,"port":63104},"up":true}},{"node":{"config":{"id":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","private_key":"7cbe501dc7bdd1bafc62c5c56af215559b06aef4ed398d4a3acdb78f3c84a735","name":"node_7a18392b8338108a996196ee190a93a1b9954c8e05a062c421da513a1828dfa739e7b224878c0670cf74bbc743c7ca7ee8cfee6b6a602fe1f4a82ecfbd38c2f4","services":["streamer"],"enable_msg_events":true,"port":63105},"up":true}},{"node":{"config":{"id":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","private_key":"e853260ddb20771587ed33007ef55b07368a08f79ea0a64cf9830ab69498238f","name":"node_e7bb63c5187ee85d965fed5cb33d1678c0e090b4e4c3f3d859755565db18046cb60025453bdebf136373c416a2e6e56be063bca6c9257b7b175dcf966e274205","services":["streamer"],"enable_msg_events":true,"port":63106},"up":true}},{"node":{"config":{"id":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","private_key":"23c3dd23f790b16480c58305ab528346a7046dddd1d9f5c699a4963bfb926fb3","name":"node_545850cb90787d49c579b1ed54a753ebd00eaafe3f1bd04d57266e4912fb1cdd654446ef054a973a583ce8dfc6cc130b6f90e63bcf75372fc21c445f8e1e6005","services":["streamer"],"enable_msg_events":true,"port":63107},"up":true}},{"node":{"config":{"id":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","private_key":"e0f2a273dc23035aaf88bb97d7f5ccf57ee6304b184e7d61183556b28040076b","name":"node_86b84ddf64d301f6a9c4504c59eb4031d3167fb74101abea3b694845a009dc522be7b2e2720097ceea9f36058e160f42a2a438a33034929a5c1a7793c7ccef7b","services":["streamer"],"enable_msg_events":true,"port":63108},"up":true}},{"node":{"config":{"id":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","private_key":"dacac1dfd252a4ad8878c023bd34aa1bc81b63d66d70c8ba9aafcfa8425bb253","name":"node_bf1e6eeb8b229f63b49213db499b71dcfe0ae45ee3f14685c7cbfa3f0a2150e52a89c853f4cd8c7a92e6e5f6083044efddfa17391662e3cff6290da679520404","services":["streamer"],"enable_msg_events":true,"port":63109},"up":true}},{"node":{"config":{"id":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","private_key":"57a2dcb70aa306ae204744fce4dd4b4ad9b02516e080dca195604406e240627c","name":"node_a58a2dd3f5ee2471f0ddd555ffcc45d86e2d8c325585e3fe55eee878b8a626faccce73679d32811fc5d068c153e671673f4cd020f3c7fb37bc6fd9646931646a","services":["streamer"],"enable_msg_events":true,"port":63110},"up":true}},{"node":{"config":{"id":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","private_key":"4314dbd43bea3cdbe75a24ef256ee0dca9008f5133f8b1d6c9adf9a84210c2e1","name":"node_896c74ca4cc4cbb9d2b6606d0ebfd6427952c2e16aedbf36933fa3d01f1c505fcd663f3d01c0cf096bef9cfd0bae4595ec7c221cfc362e19a5b7c60614a9658b","services":["streamer"],"enable_msg_events":true,"port":63111},"up":true}},{"node":{"config":{"id":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","private_key":"2b4bd5ee9da5de0932418460699900ba0e40139dc910b087c586210e52816b77","name":"node_1e0a46ff50fb6d9a2c218a851763ff86c42e4d61dddffb7188481febc0f3180bc8f31973d336b2a6e25802acd4fed6d905d89c6d4d7d8080fb12741f9c5ab7e6","services":["streamer"],"enable_msg_events":true,"port":63112},"up":true}},{"node":{"config":{"id":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","private_key":"dd2b5c2e466c7276ff4c6c1a641ac204a34ddcb145523ab175701ba31faf44de","name":"node_b2bea653b6ec9629c6f934be72fccf30acf836698e21e81dd8085f070ba8259ba43eee43c342738a4b782f5fbddd44caa28f56dffc08237ca7567c965ac3beca","services":["streamer"],"enable_msg_events":true,"port":63113},"up":true}},{"node":{"config":{"id":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","private_key":"17f5b5341d575c1cfe673efd9957ca29a50fa23c028c5f5f7561b23e7dc92e04","name":"node_5771bef7f50439f9b81d2a7bf7060b1ad4b38675d8f6abbac3cc4c215fb0cb5dd07f6873545b42218337556925566025476e2915b7b98e662a3dcd28bebf0eb4","services":["streamer"],"enable_msg_events":true,"port":63114},"up":true}},{"node":{"config":{"id":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","private_key":"eeb9367b7cabbd3e4076edb5fb97cc2fba7445cf37f523685f2b24e617d718c3","name":"node_0e8c1a6b70524c4fdc492c74348bac4ccd5d140bd41352607e8cfba45561afb1e6e12f3e2fcf03c1778c9ae5ae19cb9218ee2d613983768f54e3f54e69bb6600","services":["streamer"],"enable_msg_events":true,"port":63115},"up":true}},{"node":{"config":{"id":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","private_key":"a9a6414dc37916ed5794a644a51d6cc1c23c27d707b2dfb9957f9ee28af64e60","name":"node_d71c50805f284ed3a759e2e81f220fbc73d6d0a7a261b4c9e7878c3da143cfc07afa83e1635b6a45530f71a60b9f17c485a2fd6617c6c2bff82bacc71c208087","services":["streamer"],"enable_msg_events":true,"port":63116},"up":true}},{"node":{"config":{"id":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","private_key":"29c714e8c1983b179cad17ffaa617cfbdd50272b496803b4a602afdb05d78117","name":"node_06472c89def07fa73188d253cf1acddc2be984842f3a234edb3db95449ba74928ab1395eca1b8978987769863afffb488fc27c9ac723aa24837b66c12f38d735","services":["streamer"],"enable_msg_events":true,"port":63117},"up":true}},{"node":{"config":{"id":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","private_key":"f00cf99cd4b64e4242b7c878a4ce70044f1fe91966dd723b940e3a312f1b9f63","name":"node_eb097186ff58d96a7ead7a7f9c05a44075d84537bd4fd3f82857bf2c45bee1c6dece434a7707cde69e96f02366859cab4c991fdb7615e113a868d4b9c7524a45","services":["streamer"],"enable_msg_events":true,"port":63118},"up":true}},{"node":{"config":{"id":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","private_key":"d089b29e9ea18a2cf17256e0e06c907164f712564fbebce476b40f67e39bcc73","name":"node_57bfbde13c71e035c96513870aa8215198f78806e7cdb01c54fbdb392de2c40386d768d6fdc4c68534a67e531867ca74d8ca4dcf34ff7f7f64ec35edee3e5f68","services":["streamer"],"enable_msg_events":true,"port":63119},"up":true}},{"node":{"config":{"id":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","private_key":"219f34180d582584fdc64b9b7712bb15e490bcb2eaa2f4d2847f838196c6afe0","name":"node_5b4de68680c5d1a75cccd5e7a82319c031f5d61d79cbb6532e1254ab81c833c3fafb54390cca7a770e84690c490fcba90482b35321870f8506335a2f57cc052e","services":["streamer"],"enable_msg_events":true,"port":63120},"up":true}},{"node":{"config":{"id":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","private_key":"223faa782246247751eeb3191f8823874455005721e6738d5f5b5b631cda858b","name":"node_cd0e9a45b45f9a67417fcde29d9f92c45ca4db46eebbfe47dcf6999e23e549e4205f42ada8e3fcd00e2fb5f832bb92a27a59b43c4a5909148d81399c2e8ce492","services":["streamer"],"enable_msg_events":true,"port":63121},"up":true}},{"node":{"config":{"id":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","private_key":"2e3b422e1762ce5c22bc9cd6fa78cfb62f3ada7732d7e0b16d91ecc5f5ab9047","name":"node_5d917ffc9d70a38670941ce206aa7ea1b9ea65c1d783f14ebdf7c7afa6ca8b237112aaa9b1a3f757132093a604ef378280c5bdef02c2688049a91a412c399bfe","services":["streamer"],"enable_msg_events":true,"port":63122},"up":true}},{"node":{"config":{"id":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","private_key":"a3f487830e9fd87b5b404bc91d0f49d866cddfa869d32c08853273b9a2eaea7b","name":"node_26cf4ea45b9a76daab82a57126f9c6f8726d2eb973e205ab4ab69c8b8be11a32a7eb5c3807e952cd428ce5ddd88f143d4fc9ff8c3de3d159855675afce715615","services":["streamer"],"enable_msg_events":true,"port":63123},"up":true}},{"node":{"config":{"id":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","private_key":"9a3fe8b50af54e2b6ea84f05b832426f911dd557e1e874bb291075981a46baa7","name":"node_20f171ab01a814a2856a6cbe7929269f18f6329914289515e2cb9d078ac14ebdae457789dd638c6415b062799114570f556147d4bf9ac850f00b6d0762765ac1","services":["streamer"],"enable_msg_events":true,"port":63124},"up":true}},{"node":{"config":{"id":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","private_key":"8e83e239128a2ef402e58ceaffa0fe2d59d913588d12536ba4e7a88bac14ab5a","name":"node_f0b2f1e8d46be656109adb18c60677ac9eb8fce7f42e15d9dbb25f94b4e426064780eaf32b79954b9bb72ea89953175da8de35380aaba18931cca374a7de2b11","services":["streamer"],"enable_msg_events":true,"port":63125},"up":true}},{"node":{"config":{"id":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","private_key":"81b194e85dff3ff43272bbf73e58a6dac8a9e3ad125f7ba3e71cb5de5341a975","name":"node_a6ca1d5340f2d7021f541c81cf9aea519675462c8443bb6ddd93919962561b8f5a8431c3ec7e7e7d46c600b653e9a0638d2bb07cf4e29516bf9c4d3653f451b0","services":["streamer"],"enable_msg_events":true,"port":63126},"up":true}},{"node":{"config":{"id":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","private_key":"b4ec9b24f6a962422bb63d20e415a5dc2f85168297e8abed3cb20e3fc0d70e25","name":"node_d8cfadac10473b31a4560c711636a05615f13054388065344642ff1d04246fb62eafeec06805264eafead111ed8134e11a8e21f42a0eb950c23b142e627bd8cb","services":["streamer"],"enable_msg_events":true,"port":63127},"up":true}},{"node":{"config":{"id":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","private_key":"cd0667c4d17b56321858cceaca611f1c46758fa276d3d991f3a9fbb0c686af3a","name":"node_49eb706cd7e95ad78502a508487d88b818861d94334aee36b2acef5c25cfff5c0efc2df9dc5dbb18acd4003d5cc0c843d3b40363adf2f62a14c04d814268fdee","services":["streamer"],"enable_msg_events":true,"port":63128},"up":true}},{"node":{"config":{"id":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","private_key":"4556340931a4e95daa2043706f516eba3744d2ba4340bcb95358b58c95534090","name":"node_c93cb2df7ba6de8009872f5f7565891040d42e3b193ef1cdb321a0c167cc8fb8138900982bb8f6918fbaefac6e02dda01ee40f7a6beba1990dd44abe03cc3d01","services":["streamer"],"enable_msg_events":true,"port":63129},"up":true}},{"node":{"config":{"id":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","private_key":"f1b36e9da20cfc2416f02f9194a0522b426be8679b6478118962624b4963af27","name":"node_3e9c0bbd146d8b1040b4f379eecf802c27c4d0a70e64a9fb2e941a7edab9b00396b0b67fc5c891652743cdba3b342973ed49615b32da54b925954a799240431c","services":["streamer"],"enable_msg_events":true,"port":63130},"up":true}},{"node":{"config":{"id":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","private_key":"7f720ab5ccb4e3dbca347ff7104c677d8215261910d8e8e2ade703020d566842","name":"node_b38213eaa5b419de787b70073ad8c7c819e48c5f76dec1507b54f1d7cb027211facbe7a170ac50212abe130935e8947d5a19d6b13790114e71cc18357902a889","services":["streamer"],"enable_msg_events":true,"port":63131},"up":true}},{"node":{"config":{"id":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","private_key":"1a4d1e1d6e198ac61f91d9ccba4212fdd32e9075df2fda41caa11a0a25e694f0","name":"node_20bdc859d58d8bf419df64fd6ee1d4363c1d5f403af3abef2720d7d3933924672e12e23e5d76b28e0f6726acf58bdc5eb258cba635e327cbd0b564523305da75","services":["streamer"],"enable_msg_events":true,"port":63132},"up":true}},{"node":{"config":{"id":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","private_key":"9fc5b25f84b416e8224c296213b062e1dec7eb7074402a494a23cc1c70ef394b","name":"node_c6d1404873174254c0f15f25804da9a9d90db9c11c5cc895fab613b4deb7820f1733680b4ba9e4b61a664642ed6ee9ff012e13a0619c64ae067be6bab26962c6","services":["streamer"],"enable_msg_events":true,"port":63133},"up":true}},{"node":{"config":{"id":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","private_key":"43a6ff2fe67bdd16cdd0a4e7ba3eb8188632a796b90d34b477fcb5e0f5ba0b43","name":"node_f04c3ae9fe957a14c249acf3ea2e8407d04d108fc01e75f6d52aaf5073b3450025012d138a75b857473eea4d20e57c99b92bff9041f269d995543d7c67a92ec6","services":["streamer"],"enable_msg_events":true,"port":63134},"up":true}},{"node":{"config":{"id":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","private_key":"9202da3ce5dfea8df87f9f6145867414b45131634f70cd32dffffeb8975e0e86","name":"node_8e8de10fb3f53bd3a48455ebfa0a38ea5bd28c607e65506b263ece53a24d2361c2af7d7cd207e45b11bf71a3c33fa325fc8fd40a18b9c73019cce219c757c7ef","services":["streamer"],"enable_msg_events":true,"port":63135},"up":true}},{"node":{"config":{"id":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","private_key":"6f53e22eece8ebd80ce64720dacf85c36c8aa737fe54d05c884ae9ad693144fb","name":"node_cdd86dea7dde96ff7cc1e3248fd17d107c83f2cc7ce2111c41530448962763309e91a05b5dad4663d0e02db59ed4129ab0c3e1eedc42c654e39d29f99038063b","services":["streamer"],"enable_msg_events":true,"port":63136},"up":true}},{"node":{"config":{"id":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","private_key":"ba12a0d7056bd5d7f8b80a1e30c126d8641ec4a20b2e8c9b890764785350cb7f","name":"node_da15d60a4b9a8816ce24c20f6c941c51229c1fb5e070b8b29be2977c2f7b41f8f17e4b6efe75f465e7935ded1ba17472f046eac73393db7197018fa86d11c31f","services":["streamer"],"enable_msg_events":true,"port":63137},"up":true}},{"node":{"config":{"id":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","private_key":"f68a07d7241789486ffebae385ee73f2b9050d22612e9770a1aad1870e347556","name":"node_03e478a3aae82e06e215e40272a420037a61442d11c49c367a5ee6a21868d29a17ea8b9284f013d020c4740f296a6a22bc64d33d1c2807f9ab8dc48c0cfec18a","services":["streamer"],"enable_msg_events":true,"port":63138},"up":true}},{"node":{"config":{"id":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","private_key":"f9fa950ad709b5c36e36f5f49a4260ab81e08145d8c10611a2d46e1395ac87f6","name":"node_3df030a522a157e36f6b369aab048b9287792743a411a47073c4f9ef7686528f39bf7bf91c48e4d46afe180c8d08430b012bd216d50876baa3b1e7bc17cb55ef","services":["streamer"],"enable_msg_events":true,"port":63139},"up":true}},{"node":{"config":{"id":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","private_key":"27eb2337ccaec369a786c3e86e92bfc20b6bd03e70244b7d1266e783f087a16f","name":"node_4bd17847bdf60ea93a670a84a0ff8fe028d35228e814d6ebc0ae4fa586ddef03cd79390d541d28ca3c05a7241ffe92ac182e63c251176b40db8fe05fefaa82be","services":["streamer"],"enable_msg_events":true,"port":63140},"up":true}},{"node":{"config":{"id":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","private_key":"dc23bae09e0ef5811f615cd80fa3c264a5011f501f3fa6f91cf6772a408ba5b3","name":"node_f8052e328014f39157036f3dcecdb23419c0959473a88282605f10add681ef5cbfb1e926b522f98b8401272113b677a67225874d1afb0bff4b11140cc071de44","services":["streamer"],"enable_msg_events":true,"port":63141},"up":true}},{"node":{"config":{"id":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","private_key":"f37b323598ac406038a1fba2fb8acf1ac7899c6606f263470141e3d8f364c70a","name":"node_3274b5f48e6929e2305e980b558a4ca3c7cf800b75a6445ea2875cb379e127f3e793e9450a11e927682aa91b8af52e9560dece633833e0f207a8a8a38b7b9c54","services":["streamer"],"enable_msg_events":true,"port":63142},"up":true}},{"node":{"config":{"id":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","private_key":"fa14be3b746acd18c44299337f26807c3f0034349cc7eb6ad398a32061e68e12","name":"node_e59940a6dfe35a6214e2e3daba9ad94e630004cd8f029e13a6649a56dc528ff94bc09d8d21a2f14a56b4ff759b60ebf3d27c1029862c183b8416fa3e950bdb55","services":["streamer"],"enable_msg_events":true,"port":63143},"up":true}},{"node":{"config":{"id":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","private_key":"67c3621e70643b370db5377452ca3a8bfe78a01172983da0ba5fb979ce341bd1","name":"node_f7637cdd5ef26de40b9055c1df91a45725670c8df11ae934c0d99d2547c3eb4c42a16dbb2e75bcaf4b1b9347c48db65f549a0623179a08dd8cbad92f5bca08cf","services":["streamer"],"enable_msg_events":true,"port":63144},"up":true}},{"node":{"config":{"id":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","private_key":"e4e774ffb3fee42b1fb038f560cbb7ef3f4ec4f12d077fd90c38de877841eddd","name":"node_fa897ba112f34839064c6871a4c9504c5d709eff5095a137c6a42726d58eb623af976cb96cc30db67e6ac9347c769f032aa4ebda884285a057059040c008ad3e","services":["streamer"],"enable_msg_events":true,"port":63145},"up":true}},{"node":{"config":{"id":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","private_key":"9fdcb97101ee0351d72b1cb7b832fc95f339a434e9d1e146af4062d0d43a88c6","name":"node_5d96577324edf1b5a1626999925982af1e0ba7bed8edcc3f740ba434f4b003cbbe2d632cad327c76e5b490d08c091c4a7b473353ab59139493657eb9525b8be2","services":["streamer"],"enable_msg_events":true,"port":63146},"up":true}},{"node":{"config":{"id":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","private_key":"05ba41be88727fe8ceb3dd01ae6314f6eb66de9c223da829a6cb0fcb9633dbc7","name":"node_b09af9e5552e72f918174963dad58a4492d3afa120f78e43820df7bff7fae9f6b52bc6c8c73d3a9af91d20134f4ff1b037db2ef0bc3d8c495a771d63de678bc0","services":["streamer"],"enable_msg_events":true,"port":63147},"up":true}},{"node":{"config":{"id":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","private_key":"4f458de05e760aece8dffaa29333d3a51382cceb7bb8265be7a25ea65cfaf2d2","name":"node_1955bedf0bc9044b13a2c16158087123197c74147c86aa3b9389d308a364e80edbc573bcc836d8a262a77f3c9233ebddb1b82eca83cd0a0e4bda6564c443bb70","services":["streamer"],"enable_msg_events":true,"port":63148},"up":true}},{"node":{"config":{"id":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","private_key":"c2adb7237525d3d280b964361432cfe1d2863e3011b4b83167648da04a8b22fb","name":"node_5984a296b49bfba30315501ce2ae88ed0392ab2959ac4e7e6b9a29090f344b9dd13873ca137e8317c402cd2e14a61965d5707065b8ded46c41a054731933719f","services":["streamer"],"enable_msg_events":true,"port":63149},"up":true}},{"node":{"config":{"id":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","private_key":"43223de0a2e5b61580a85a150f19528acd484002efde9df5041f8b93b5d9f0e9","name":"node_9c3be147f9fe0fa34e553d9e4332969086ea7fa65294b61ca35c9f731f6b81d0b70cdcfe2ba52b6cea3c0de14b7ea40031b5cc40661c4bb821147894130d7bf5","services":["streamer"],"enable_msg_events":true,"port":63150},"up":true}},{"node":{"config":{"id":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","private_key":"863d1cfaeee0df7e89ff906a00c0165a9e579fda9f82bc3fd9b694a593e37139","name":"node_ce1309c8505b446363ae37cd3b1ee3e03ced537bed20aca5d8c4be2133917c408845ef5d0f65876974be2803dfb824827cf5c5a2d050d6ef26cdabcbf3a2dc31","services":["streamer"],"enable_msg_events":true,"port":63151},"up":true}},{"node":{"config":{"id":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","private_key":"f8f2976509e8c27362fc450e79db0e7b99ee036277d5a1c860f265be28b6525c","name":"node_3e7820bb15c07f515bd63791b66136723dcc9878b3145fe0f238f6b41e3f2f7565ae55ef24f08ae461950ce1ae0c8a80fe5e4fd4f2f88c4acf4a2c94640df239","services":["streamer"],"enable_msg_events":true,"port":63152},"up":true}},{"node":{"config":{"id":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","private_key":"eac78f03be8f9529f9c85dceadffbc6ff39de01456bab5c864f9ea5a4198ee23","name":"node_dafb58b2fc8a14f2b23b7df33d28aa7847a08f80e9c21a654d4c97d928e1afe6585644d27f22442cf70d229c32783be6a03c0920be153fc4d9f3b273dfa90ec3","services":["streamer"],"enable_msg_events":true,"port":63153},"up":true}},{"node":{"config":{"id":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","private_key":"6488421507de8fcdef9f2e89a73b5e9182ec8c0cb7d564e630dfe38ebcd732a1","name":"node_622646c74fdbae39ba191dbafff4906fb683fe0b0f2c303d080f5577a070876c41c8d3786ae7b953e5f682b8ec647727550d47302229ebb9f82bed24cea61132","services":["streamer"],"enable_msg_events":true,"port":63154},"up":true}},{"node":{"config":{"id":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","private_key":"7f547289aa8ba8dade535a2e50bfc2111536e7149162e360ea5e4db15c12d42a","name":"node_2d6d55edd34c0d9a0130b4806e409bbe18cdda5c2b221cf46136718ec20ffc9d8e92838d78aff92fbcc85f5d081da361dd1e3d7f3d4e1ea57877d6bb7aa0b6f7","services":["streamer"],"enable_msg_events":true,"port":63155},"up":true}},{"node":{"config":{"id":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","private_key":"f3d8d6aa0db8c604198cf9a317b45fb96b8407cb029951d7ef06042abedf5e1f","name":"node_f62bd19b0fd052207743ce53c3d48a3a71e9219b75e41a9497a43e6368e559d5487ff1ab644f2df4106b500583e4344515f73187eec773115deb977b4ebc3514","services":["streamer"],"enable_msg_events":true,"port":63156},"up":true}},{"node":{"config":{"id":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","private_key":"cc5627eea1858ac168bbf1e34a3bb3410ade5b379cde7f67601bbe359506e76d","name":"node_a1b2d0c6f24f5924c61e057fc65b994d9a6755560d740018b4c9ad0bb69212ec69974e22cb037dfeb7ea90a4493997f4c94029870bcc5fd47013b51ca0a26b5d","services":["streamer"],"enable_msg_events":true,"port":63157},"up":true}},{"node":{"config":{"id":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","private_key":"77d99b72e19bbe2da2d6d931653dc7b541dfe27092b944936562bafddd6114fa","name":"node_188bf77c9c1e45f009efe7aefdb040bdb47763980fe7eb0851295d657fa2a8978efbd2997c1dc30f4f0874eecf9ca9550487cf41da237b84d071963d35b6baff","services":["streamer"],"enable_msg_events":true,"port":63158},"up":true}},{"node":{"config":{"id":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","private_key":"e6874592c3f2d2fa94b126d565cec571767e64ef9067970a9f8d1f8ce7e88d0f","name":"node_f06ec3a90d34300f9fa2d48aea0c6b5f2f01f7833ffb0fad30e7f57e3916e344f3a4f9efe38e222443b8b00d3c7f5221c672491a129e4958e574afc283bd45b1","services":["streamer"],"enable_msg_events":true,"port":63159},"up":true}},{"node":{"config":{"id":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","private_key":"d733b22563798aae07facf0a489367c7cf0d6d3ebf786992b6ae98696d295cd2","name":"node_3c6faa2e75a1699ddadd0e21fd35d3d6215715cfdc2dc89961cfd66773d2541776e785f3ebc833a70e3d1017a4edc571a5d5d9f9fbfc3fa0a8588f6c5023c164","services":["streamer"],"enable_msg_events":true,"port":63160},"up":true}},{"node":{"config":{"id":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","private_key":"145ffd39a00647c0142f3bce7ba2f21f4e168663488e0683b4c8cc72afa7b02b","name":"node_56e8f792ec9a75ec9e91d472b8a4b023655dd68c2a448a33397b125fe3584a5efa1b492e47077b24acfe0396b73e1cb564a6a6b2aee1b457781dfaf6d43fcaed","services":["streamer"],"enable_msg_events":true,"port":63161},"up":true}},{"node":{"config":{"id":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","private_key":"83fa451e08386b0966a5b8ec4b56c861bc367f0cbaa7e6e3a8c20564dbc0f1af","name":"node_3572a22097a313b3adef95a7b6cc679f8d1201a156d764e61a9fbc63d123fb4826f7125402fb6569beed359e1c1e5e6cb6993a75975da6cd4ce15669a2eea758","services":["streamer"],"enable_msg_events":true,"port":63162},"up":true}},{"node":{"config":{"id":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","private_key":"2057ae928cb89d7759bda21739956c8527bf11bb02571ee2e9bda07702779aae","name":"node_e3f2e777a96b2137b3104b84d5d827d484eac9ee1b585430e09f790d7e26978da12802325927c3c483bc19973e09cd3f70c513c34798e5da650f8d2f0c8c5c47","services":["streamer"],"enable_msg_events":true,"port":63163},"up":true}},{"node":{"config":{"id":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","private_key":"4fb682db9263cc8ae4d32757a0837296654120fc17593b9d0c3219a307193655","name":"node_1480f62d85ea32226d9f77ccd31780b3e704fb60618a588ae85dcd1c0e84e878c5fc092adfb306e8ebc7abba9ec429cb2447754502ef847cf931467f31fa50b2","services":["streamer"],"enable_msg_events":true,"port":63164},"up":true}},{"node":{"config":{"id":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","private_key":"7f212e2fa6d29b93f32d27a27b02eab5b9aa946ba044f1a20bada9f7db133907","name":"node_3540d888c3207d6df233afd1164ff9dde2551730862772547e04f7311de364968e113f38a7dea1ab0916a7f8307017de5b49578fa4ebcc39651e541fde51be48","services":["streamer"],"enable_msg_events":true,"port":63165},"up":true}},{"node":{"config":{"id":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","private_key":"d209b8a302d27579c28dd86104e2eab3c74101ff06bb17200388b614ec3f05ff","name":"node_077bcadade93e0d361e94f76dff464d61912bc067ce2ce17ebcabd757cca201cd64624ea809d99dd8ecb749d40528db9b3eb503ef5ec05e8845044cfaef720dc","services":["streamer"],"enable_msg_events":true,"port":63166},"up":true}},{"node":{"config":{"id":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","private_key":"f0317274abc992d76728cf9a59b6dfd16b1422fea0c0089a47f0cbffbce53c34","name":"node_73be4d2291c68ca4554a86fa170f7595210e1b6bbbeef3c1d5623a2b5d03a8fd6e26caa26afc639c20c8a351a89dad1086f91734f09afab62d28ec17b700fa01","services":["streamer"],"enable_msg_events":true,"port":63167},"up":true}},{"node":{"config":{"id":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","private_key":"8d5bfe9aaf70d634b185efff991adfde6d80ee5d1c60e68eb1a105c17a4e03af","name":"node_a5cdff211813e17fadd43ec55a6cf4e97e6ca0c3b2cef0db58923b27d36207fd1a77146efb6093bd94d7eb89cc77d8c735fc64ab098839efc74a00b5e8687555","services":["streamer"],"enable_msg_events":true,"port":63168},"up":true}},{"node":{"config":{"id":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","private_key":"bd99f18955320e921a98f8103d8b4c1713d800d49c0a7bc946cb52fdf79e03d4","name":"node_27fb8fcda1986644f985d68430c399f0299644b00b234c355362721081d12f9eb7686eea8f92eabda1d342bf56255e51c07b200c6233f95ac009f15b874eee97","services":["streamer"],"enable_msg_events":true,"port":63169},"up":true}}],"conns":[{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","other":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","up":true},{"one":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","up":true},{"one":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","up":true},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":true},{"one":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":true},{"one":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","up":true},{"one":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","up":true},{"one":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","up":true},{"one":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","other":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","up":true},{"one":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","up":true},{"one":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","other":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","up":true},{"one":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":true},{"one":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","other":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":true},{"one":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":true},{"one":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","up":true},{"one":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","other":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","other":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","other":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","up":true},{"one":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","up":true},{"one":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","other":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","other":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":true},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","up":true},{"one":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","other":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","up":true},{"one":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","other":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","other":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","other":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":true},{"one":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","other":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","other":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":true},{"one":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","up":true},{"one":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","up":true},{"one":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","other":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","up":true},{"one":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","up":true},{"one":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","other":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","other":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","up":true},{"one":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","other":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"c35893ea35ab764005fd81ee10d1a9ab3f361e044aa53e28ee64effca928d09d","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","other":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"1385e97b879da9021aba65b2df36b91650aafb354a09c5be8a9532d1eb7d472b","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":true},{"one":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","other":"e39e8092c97b53dbeaf5ca73d95c71e8e41a2906aaa377fe0c1b23752c8c7423","up":true},{"one":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","other":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","other":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","up":true},{"one":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"c7fd88864731e6b79acf436a76908b91c61ba07680699c2cda316179c3719e8a","other":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"609958921d9107eaae6f3141e94f12b3a28fec203eb0e5b674ed8268934becc7","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":true},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","up":true},{"one":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"740bebf4546e2ed32b2bd277555685e3be071aca4b1990c7c095e12e24fa4699","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"30a0ef4bf1f66ab4d02a027a24ba1f9b288ea93e86a5ceab64e1985aa4efcbd0","up":true},{"one":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","other":"2feed66b03b7b057e1a64a3f877ad9c28ada96e30b98a78393b54ea31b98f4fa","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","up":true},{"one":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","other":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","other":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"87e0232acc7127ea47604a5bfe84d80e38292902502c2a714e0f96d8090eb4fe","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","up":true},{"one":"1ea89c3f15b82385c5df8810ec7cbd30e8e4a4e05c1ddf5dbe7102edaa07afd2","other":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":true},{"one":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"11a60d43d627470df1c1ebdc404093f6ae83c75b3a95469316b89a0185eeaa86","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"6cf1d30b063cf8352795a92c6af26c154fc44be06c69ea9fd4d9f6dcc626eda1","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","up":true},{"one":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","other":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"b1bf7a0572c1efcf034bf42f54f7334743c59f77b67225aa3c7d93552074ab56","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"ca9721b51497c5d570738eadc37c79fc8d5525749defb98c252371793c2a6f5c","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","other":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","up":true},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","up":true},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"60ad041deb8cf72f0d2b29accb204a7e1838347b250e105ac72a0a4f17dc5f47","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"d79838c419be793292a24feaf1b9d26c67f0c5afe15bae85689420de3436ad95","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"40871cbc7eff896f15e558e2c638ac980fd89c718881cd110a086c3397b564c0","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"83bc840da4e1f9201f0e85db2c44364f06c188fedef30fd2f72cbde70f6cfdb9","other":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","up":true},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":true},{"one":"004710b2e2194a8cd11292efe8b6f81bec4c1b673a9c8a45b7b5391f5f049895","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":true},{"one":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"ea51459c5ac142391297bb73aa26501eae65bc6f661b534a91a344de8dba2f4f","up":true},{"one":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"b9e5006b90bffae809136ad57e36b784b18e35f7491c47319807f6869d624465","up":true},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"7692399f01177f2a8976d4c393a6813c53820e5f4edf54934414d1bcdfb8392c","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":true},{"one":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","other":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","up":true},{"one":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":true},{"one":"8230e499c9c01cb6e5717336f3a88b6a8c1010081712fbfab96c301e23044d14","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","up":true},{"one":"bf7b0b9825b9c878f7730014c7458fc52ee3490c98ee5ae2f647a8d73e4464f3","other":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","up":true},{"one":"3d3acee3657d98168e2f4e6463947646560b5ad1ca24b4a8a97e4284c39b02e1","other":"4124e83515480818c250a3ca2d8a7b159c890983c35165ee531d2e15066c7203","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"aa19fb3565a2677828b1384f483e3eb7ea112940d21d0aaa7b16139c753c69d7","up":true},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":true},{"one":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","other":"1943c1442da29872e77e4cfd282e9a81490c613e99cbe4503e470b7f23ce75fb","up":false},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"3e4fbab650cbd539383f7e26128c0aaa770f12c4a1fa44d553de9dda073f0cb2","other":"314e1e8a8d9ae18d0b5510341a6fab0f8654a7263a5db895480aca606b6a9859","up":true},{"one":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"f29ff736fb944f8f8339a4e10f69ee72f108ed1d68b5a80d06a814b0807e8686","up":true},{"one":"1ab1591431f8ba2a5aa1110ff97926cbf80d080ded09192dcae0c4bfeaea1ec0","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","up":true},{"one":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":true},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"d192c64e09879b5107507e193fea23b0244a574e0d66e444f7a325de32c123fd","up":true},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"6640a8343b810399525545ee1545a50e3c76548f776c83d55465071cb55a00b1","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":false},{"one":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"f99503dc6a4ace3317320d8454b3ac1a5977f508ae810c4d506001ed0126838b","up":true},{"one":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":true},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","up":true},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"f80e1ce23869c7da4453f06521fa320632057194c9f9b3dcdd777cc1f06603eb","up":true},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"2aef8c4da4e38b6a885785e406912cef6087344b4be9e135e2c597468b003315","up":true},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"93868ef90fc89dff185d7e59dba34b3e9449ab0336fff12c64ff4ecc3f033b78","up":false},{"one":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","other":"83119770a801a40f0f4015ce8a8cc6cfa6dbc211deaee193c5db05130002f9a7","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":true},{"one":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","other":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":false},{"one":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":false},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"db596f4ff3f8c25835f9f10176e87a8823eaf1d39a513882f1ceab931dabfed9","up":true},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"d382e36db7f13180cca7b169e8511c9b920bb481a340d8a61dd9e4969a5605b6","up":false},{"one":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","other":"6c1f82c3a7bc3274cfdac710caec4fc814c9f5a6797674457414dd94be577a9b","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"e3c3f763b77a0bb72932d5d3dfca016e28d27b1c377690d2b074881b1a2a3259","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"7f620d306e05bac0f07838b7de6a2db69aa6494df3db09f26624ed167318a75a","up":false},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"a8ba308efec0ed318d68bd3561a41fbb0af84383e3f5333e2642ac9d60005ab9","up":true},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":true},{"one":"d3864c160e6d8fcb3f540b864e6ee11d91ca708f2cbe1e5fd04beb2b6c1d8930","other":"811d75e7ee506a20ed40f8451066f5d9f6d63c5774004aa26bd30540137ffd30","up":true},{"one":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","other":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","up":false},{"one":"0400b7958d9f0270dbe3146b80fa821dbae8b0cf70d11c9a3d3d14b14012fe4a","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":false},{"one":"f07c1ee0f9cadf2971a0cb0022d1c67fa82c79f63cb98769b31ccfb04d05c0a8","other":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","up":false},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":false},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"a12e73ee9cf7369825c1423608ce079cf70df75d0f0bbc56d07d484169fca26d","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","up":true},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"311fc84bce90b1bc1d1983c78e45b1e82a703cdb7cfbe54d51e9bc40cfe04103","up":true},{"one":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","other":"44540a152f9fc924f10fefc013059d9ad228e74f921a67866ef28758f1886320","up":true},{"one":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","other":"a60b45dbab9c1de18783fed9eed8af6dabafbc33fdc5b3fef1ef4569bc6c70d9","up":false},{"one":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","other":"6ac71d55e984abe323c74ea85ac1aed1b06e56632c07c389e780268274a23810","up":true},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"d68e095e77246c3c08df2eaec294965bca2d01fa2819d9cd06c6ef8730c59ab4","up":false},{"one":"feb3455336b26365b81dfc8cba2a390690ce996e07fcb7f1226720d263205adf","other":"f3a1438cfc8b09a3a9c1fc8455ead9041e9532ef3e9a77ffee8e5ef62af2670c","up":false},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":false},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"7628bcf64532ca3ec293d26f60791a2a62542b2f5f3f1c782799075383ccde00","up":true},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"b22078d9b5f3d57dec3fb1796599d5f04fcb32d4288939431ecea8516be76b58","up":true},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"fba89f80c35e5f6ffbe6e5521f2011caec985d820fe42759ef1aaa36d4902f37","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"fa62b685ae8a9aac669d245102ce68b030f0f270d95d7c88969bfdc9978f9070","up":true},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":true},{"one":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":true},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"5d6da3260504f8063af24960ac901bdc0c54a126b82d415656a083c496c8b6b8","up":false},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":true},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":false},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"f836b3ca82f75bc0901d83b2c02e24174bee78c5eab9b55af9c492406942637a","up":true},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":true},{"one":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","other":"d7f956d0f6445202699bf63700da408237fdcecd27e2e8ad969e51d7e8e61483","up":false},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"c243003b111259b3cdfdd4acc3610ac8da65bf58288d51133d03e680a42d7034","up":true},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","up":true},{"one":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","other":"cac97c7026184a2d6ba2b17fcd0c5440bec538961af836a60f2fadb78a310a77","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","up":false},{"one":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":true},{"one":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":true},{"one":"97a5959b95662f6e820a1b011a7e87568e0efd2257a73bf91868c98c46e5a571","other":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","up":true},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":false},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"3f1ee2912d5446e4cdf7a42582f2e30a24bcddd6422a9b6a61f287da256d0bde","up":false},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":false},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","other":"981be0d21bdb11ac807dc29937c6a3ac2ae3c2f45269c0edc21172d5550f4da9","up":true},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":false},{"one":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":false},{"one":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","other":"57dfed651ba7f0ab6f9e1d5d2d4ae18fee51a200f50925a88c861982bb4769cb","up":false},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"8fe212fc9af12821f59b5f364f86f78b545be501933b926fc47b6d7deafca941","up":false},{"one":"8ec663c22eff8ed185b8194c1240ff58df131c5f310df0a91b9790ec166e4346","other":"8e317152297d5d048ca4512f733e63e48c3dc66910bad541d33f3cfc76828cb9","up":false},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","up":false},{"one":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":false},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"d55213d3dc27542a780472564a4a8c1ce47668e05710be178baf3238ca8886b6","up":false},{"one":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","other":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","up":false},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","up":false},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"5b36b0ab4872865a4f86f2aa137ba8bb4273090e57fde30ec27a58acb158c22f","up":false},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"d9169f80683a2552475d60e6982f70c6605f9b40300f2b60895aa21cdc42db89","up":false},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":false},{"one":"f2b809e97d3c3a652c4ddce19ca12b01c1de25f2ce007d561fd5606e85540d64","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":false},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":false},{"one":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","other":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","up":false},{"one":"8bf59dc9ce97e6e2f2be364380aca38f98ddec248e730422f581f5bb56171e34","other":"8c5b95bf1743e2d8a97210c5b64b6732f3615c4369fa3a52e426f93e168ae16f","up":false},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","up":false},{"one":"d87f983aefd8f732c29718a95f4dfc54a10640d5c9fdd73b772c3c30df269d88","other":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","up":false},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"e5cd769dbcc429587e3a92b192575965c0ac18e88c9a54b9f75936d929c43c62","up":false},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"6838b88ff71c5419d3fd22a4c007a7b822405b1842d53427a9c075d093c13047","up":false},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"92e2f8ec301e5858f7168b785040955d28bffae0c98e5d3f59ff9fa8636fe423","up":false},{"one":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","other":"9cbc96aad8fbdde0c2f084f3cef79b56c150ec7fc30dcc2d8535efe9b337f4c2","up":false},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"e4254cda903275296f17b47e5dcabbf16d1fa7432b64e0e6e0562fcd89de534d","up":false},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"4309c2d963d91e65f7e8e8ab42df52e75f8d377d4eb07d1a048c0082af4f501e","up":false},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":false},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"931a36980ca0788616cb1c9851f6069e44d94671a2a056e12a7d7cafe597dee5","up":false},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"7e65067fa5db52d40c0a162432200ca6d0d3917b25cad15ce498fa6b5375bc8d","up":false},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"6e8315dc552c8112dcb01e9302b5e47fef7fbdc81fbe7a1d0b27e0cf80a65ca4","up":false},{"one":"6632a8b23d42dfc55a103d625a3644f0067abaae554eb75a78b1094ad7b24c16","other":"61207f4fc13c899b88e9b727eb202a8bab00868bd07d945100b2e56dbcd67683","up":false},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"06db6e244213745e02175cca1101e72799c09236838affd8a020a05e5b88e2bd","up":false},{"one":"6a57cd355d641d1506957a988d93b2d3f9a613a7354c24130ad97dbc4c8296ce","other":"6aef7e94602e6e74ab4cdb57668fb751fa20807751f786d0232870da0ae32cfd","up":false},{"one":"96e99adfb8d8d5386d57334975f9525de0abd4418e528f2a8c1a61cc21871423","other":"96b723de0840f656c914674ad20204da830c04d4d6956c32e20154cbcc40f9ef","up":false},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"e0ac6b34d04bc036026767288a8f0f96720f4a3efa5b52b3b86439fba562bcf4","up":false},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"425959a8050805baa98c05ccd640261edd3f26e6cf3205b4a79d2b086c070339","up":false},{"one":"48a19dea03eb8068e8925407c582a0913fd24127a4f76b38360171c5b0b0c545","other":"500f2135db1adafe22d8a62af63f1659d6f4538f490ee8151e9db970fa24389b","up":false},{"one":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","other":"1f2a162a4e78c8935ed17eee206a8512ef37e126bb7ad9ff744f7b46c4b19aee","up":false},{"one":"78bfaf122d10ee5e5304fdd247434c02b32de577bb410dc04d8ffe1906294fdb","other":"7c766b57273777cc67f74870560449c9542cfec734b58b167aef99e09aeae962","up":false},{"one":"a3fcef8ff8bc702c6452b0c4a7b899dfc551bb8293b17f2f6133cc78d66581d8","other":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","up":false},{"one":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","other":"4ae614490d8739205773d16c8027c46b67d93bd336c33071d8707fea6ac1acf3","up":false},{"one":"7bcfc9285f6a2ce0d3c3cc4455c026a00e96ed6363016e09ed62ec03a2c9f681","other":"7f5f9f955e368c906746d42953e30e781a8eb73428af5aa608af96af9bf4f60a","up":false},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":false},{"one":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","other":"ebf9a6425b47a78df1c99fe4d62a48c26d2f4ef966a8592802d5b5e95e6c12eb","up":false},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"18f6cc40773a42ddad3e3e6c5fd865a652cbb42e9054f0e46dfaed17a41d4f4f","up":false},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"aec520f507eedd5d752b6ba8a0b509f14105e5e457eef0b6537015e39569762b","up":false},{"one":"954a22c6fd7d63fce47d8685d32bb892bcc0feab4209d5dc7c3601efc28e7d6d","other":"9f9700ca395f36c84a38838c11f6889d00015d97aac7943c27cf74393e3fc22f","up":false},{"one":"ea9490f17813e0e5f39e8065f4c3954163f3bca6e80afca7a2c76d5ca3116e53","other":"ec3b5ea0bc43c1ef1ae2744ea747887dc58ef3526ea8601856f1e18e7f01a197","up":false},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"4778cff42bfc5ecf6a87e7a4e5a632839d30b8fb10e62f81eb75d915e6f457ae","up":false},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"42365cb134e329e7205559838f924affea893c832ea9d86c4e1b19ec2c6ce5b1","up":false},{"one":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","other":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","up":false},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"237b54aa7ef077972fc65fb222ce70df0129f8c8d4d35505fcbdc281bb7d28ce","up":false},{"one":"dc2ae81b708a14f8b6e134986075835994c71d284b9bd9fa19d2efa73346f35e","other":"d80b59b187b7765439b0e4c940f766ae71a903f599ac41a84d972e8703f7c9ff","up":false},{"one":"059a2d0e5db2c0204c10b66ef04bacc96d64453073efeee81ba7e30d43061a61","other":"265040d12d0b79c8609232060b3ddd6ac16fb895b52bb7f3fee5c6e8b63a4d79","up":false},{"one":"a2504bc38c94b7912bfafc42c7a4531cd27775473071e7a26173c4db932bf9ec","other":"ac23190ee9ee30dd793bf3edef355450522d3f56973ab6b1acbb6dfd9d64137a","up":false},{"one":"2a2bcb40404a427a50538ad9d1bfff1c5b1a7673990cbd20d830787fd96a00e5","other":"2dc2914f76ec9b291b2085bea6d2e0f6d45beb55bba5e3a90059b96e83010318","up":false},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"53eaa90913134a5bdaa780d18bcd33e85b1932d9b15bcc1096fc4658ea5ea7f8","up":false},{"one":"48274a353dee6c042537c999f89ccdddd7a9c139fa8b824750496bd7cf2726b2","other":"436c8c2a56cbc03310237c646c7226f8e4bd672f68251ac8cc9678d3126e7aa8","up":false}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","name":"node_dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","enode":"enode://dfc47747201ccdd02b200ec672c3884626a10fd4d395d729cd67e3172635873cbb9f20e1a9d402fe058c43705671b2b7b51b4fda33b1c71f67dc48fc8f80c93e@127.0.0.1:0","enr":"0xf88fb840de2ad283128b20ac2fb81c51ce7b4cc5e0fa78eee1fe7f79570a47d850263a8a1aa7e04415d06c9e35cfb89705a7574d3bc05b7881ace913df570dc72bdc27d10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102dfc47747201ccdd02b200ec672c3884626a10fd4d395d729cd67e3172635873c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3ZKz1CQU/V7/XB5MpVxjzXA2Y0BJmVtyogzffKEyGXg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dd92b3\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0f31 5c62 64e6 | 68 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n001 7 b4e2 a9fa a861 957e | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 8 ea3d ed12 ed2e efd6 | 17 efd6 (0) ee2b (0) eceb (0) ed12 (0)\n003 6 c2f9 c0ad cabf ce01 | 8 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n004 3 d125 d18a d23c | 3 d18a (0) d125 (0) d23c (0)\n============ DEPTH: 5 ==========================================\n005 1 d9d3 | 1 d9d3 (0)\n006 1 deec | 1 deec (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","private_key":"009fe52f1950de37f99e7888e92c1d26717ca84232a756701b4a642f2b642869","name":"node_dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","services":["streamer"],"enable_msg_events":true,"port":45169},"up":true}},{"node":{"info":{"id":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","name":"node_fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","enode":"enode://d70fb3399dab49d5d0085dad53fc1383a10fe708bdbc54abcd67fe3207984bcb145ce8859b7576b0a6faa795fdf64eeb6c63759bac66f5c5baba4e6e522cead7@127.0.0.1:0","enr":"0xf88fb840f7f08be963b0a1326da55df415a377468da1b99d0e12583ab97b3af05ea36f930c3913e7e58b6154d71478ccf5836a56140d9ad60b819d94197d4c4892a10b870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d70fb3399dab49d5d0085dad53fc1383a10fe708bdbc54abcd67fe3207984bcb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+sgIt5kjkx/r1U42EbeYEbOXPHd+dQK9VrmAPQxL94U=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fac808\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 3775 4746 4775 4589 | 68 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n001 6 836e a861 a192 b245 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 4 ce01 d18a deec dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 5 eb01 efd6 ee2b eceb | 8 efd6 (0) ee2b (0) eceb (0) ed12 (0)\n004 6 f4a0 f611 f177 f005 | 6 f177 (0) f005 (0) f33c (0) f3d5 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 fa65 | 1 fa65 (0)\n009 1 fa9a | 1 fa9a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","private_key":"59a3d47a5b2fa0f6cff34a3b7923fe5bd5bcd027704761ffaa4d22752484fe79","name":"node_fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","services":["streamer"],"enable_msg_events":true,"port":34267},"up":true}},{"node":{"info":{"id":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","name":"node_b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","enode":"enode://f9fa2390fdb8807909e77cb819962e0e99aff947653d98f8214cd66694386f1ddb1902f61be1598592f66184534da5b7519cf7eacbdcde753ff8e9359f1ad7cd@127.0.0.1:0","enr":"0xf88fb8407259bd30798ce82b8b4d9dd309e5fa69a46bc8d320221016d5cc98922b865e5968fbe4704097f55dee037fe7f3638efec032c6fb00f2e850035a729c1407bd850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f9fa2390fdb8807909e77cb819962e0e99aff947653d98f8214cd66694386f1d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uGlb7GyOHmeUu5Q7g2Kc0skQBn5uF49vjjPE8PotdPQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8695b\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3e19 4d75 72a5 | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 7 cabf ee2b ed2e f611 | 31 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n002 2 8012 8330 | 9 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n003 4 a9fa a861 acf8 a192 | 6 aedc (0) acf8 (0) aba7 (0) a861 (0)\n004 4 b5fc b4e2 b355 b245 | 5 b245 (0) b355 (0) b60e (0) b5fc (0)\n============ DEPTH: 5 ==========================================\n005 7 be0f bc71 bc29 bd48 | 7 be0f (0) bd48 (0) bd96 (0) bddb (0)\n006 0 | 0\n007 1 b9d9 | 1 b9d9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","private_key":"097a05bf51118f924f1adb26e6a452bb90533346ba3a28a13f3d0d984eccf2b6","name":"node_b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","services":["streamer"],"enable_msg_events":true,"port":44203},"up":true}},{"node":{"info":{"id":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","name":"node_72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","enode":"enode://05e3a75ccb0d9a1554a071d18873ceef4aec0d0ecb15840824ce3826f6c07e9e3fc43284c66bcbc0a57268a6efef655d7cf4cd12d9052f071e8c8374907716ef@127.0.0.1:0","enr":"0xf88fb840c57b532df76cb5be5b002107b74ba9b52855af33fe4d5233521e04bd89496c5472f49ace6d880f2d12d87c4e9296883a61ed286682e8e4cebe6a0092268f49770183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10305e3a75ccb0d9a1554a071d18873ceef4aec0d0ecb15840824ce3826f6c07e9e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cqU/D7G1GFXLQFSjnL0TCadqhi024Yr5ugRWpgMlwG4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 72a53f\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 c0ad eb01 ee2b fac8 | 60 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n001 4 0807 0a21 27b5 3e19 | 30 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n002 9 4a37 4bc8 4efa 4746 | 20 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n003 5 6975 68a6 62f0 672a | 9 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n004 3 7a68 7bcb 7bee | 3 7a68 (0) 7bcb (0) 7bee (0)\n005 3 75e2 772a 77ee | 3 772a (0) 77ee (0) 75e2 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 73d0 | 1 73d0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 1 72a7 | 1 72a7 (0)\n015 0 | 0\n========================================================================="}},"config":{"id":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","private_key":"b43306b3e3a12c45a24bacbc053382c7c985c642252fd778f0397ba9b30bfb78","name":"node_72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","services":["streamer"],"enable_msg_events":true,"port":40757},"up":true}},{"node":{"info":{"id":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","name":"node_f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","enode":"enode://935e2d2fb4ec2899b4a4fae26ea6325ff296a698da7c81b5a67870eba307c1869c91558f7b8835a8d6e78ff772a4330447bc3a1e94298a2e15733bc0272b4ad0@127.0.0.1:0","enr":"0xf88fb8406b3720141a112476eb8640a2b4253f2f73929aca065cf93cb76e6b04cc2e2b890c1657f0755ff355ad24af42636fcd866c96e5431800daa692711baa906569e20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102935e2d2fb4ec2899b4a4fae26ea6325ff296a698da7c81b5a67870eba307c186","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"89UIEe8QZh0++ZeAd81xgThymPMGgzq24n8ly7d0Nc0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f3d508\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3e19 72a5 | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 9 957e 8330 8012 a9fa | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 2 d23c cabf | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 6 ea3d eb01 ed2e ee2b | 8 e06f (0) efd6 (0) ee2b (0) eceb (0)\n004 2 fa65 fac8 | 3 fa9a (0) fac8 (0) fa65 (0)\n005 2 f4a0 f611 | 2 f611 (0) f4a0 (0)\n============ DEPTH: 6 ==========================================\n006 2 f177 f005 | 2 f177 (0) f005 (0)\n007 0 | 0\n008 1 f33c | 1 f33c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","private_key":"1400f36ad2ebedcf9c8897f84d4c1145757c0b829eeead178385d6e58b8af6d2","name":"node_f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","services":["streamer"],"enable_msg_events":true,"port":44709},"up":true}},{"node":{"info":{"id":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","name":"node_3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","enode":"enode://7dd2bef04deecdcb459658589d12dd5ccd1e8946309bac3a44e77161a25762e2eca61c3f151d0502c1d87a6617b91e39007101f5b9cad7b3c72ec216f566f436@127.0.0.1:0","enr":"0xf88fb840ff54e5bf97acf0f558d8bdda0e66ded18a9a0147bb097d7e18a3107d9b0720f13117a5b72582ebb9c81320b0ed489e15b31d85ae5c31684331caefd43e3173a00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027dd2bef04deecdcb459658589d12dd5ccd1e8946309bac3a44e77161a25762e2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PhlZspu6yzzn3M+kHD5RuH8a/HAKPG5HE8OMwP43kN8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3e1959\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b355 b869 d23c e06f | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 9 4589 4775 52b4 62f0 | 38 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n002 7 184e 1929 1740 127c | 13 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n003 5 27b5 2471 2354 2803 | 11 2803 (0) 2dd4 (0) 2d53 (0) 21dc (0)\n004 3 36d5 3775 3590 | 3 3590 (0) 3775 (0) 36d5 (0)\n============ DEPTH: 5 ==========================================\n005 2 3871 3b83 | 2 3871 (0) 3b83 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","private_key":"79b77704fc404ea988a22902c0829368cc662928cff0a0cd1da58204d8798187","name":"node_3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","services":["streamer"],"enable_msg_events":true,"port":45515},"up":true}},{"node":{"info":{"id":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","name":"node_fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","enode":"enode://1bd15b81ce9c254be30f589cb832521a921c02c85d2816b7908cac8f0087244fb472c89900fdd6295768deef48504061995e3912039a46881d149fd5f38eebe0@127.0.0.1:0","enr":"0xf88fb84006acad544c50bd08be034b2ed91454d521ae949b4a8420cac9aa8a44849871fc14b06caa330bfc823a926ae6b2af2ec87c9d78a9ddd222cf1f35ef26518baf300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021bd15b81ce9c254be30f589cb832521a921c02c85d2816b7908cac8f0087244f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+mVbSIJXnmWTehSrHGvLoCFYDwpevATEhCT1rnK31bQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fa655b\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 7bcb 4a3c 4589 27b5 | 68 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n001 4 836e a192 b245 bc71 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 5 d18a d125 cc9f cabf | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 7 e06f eb01 ee2b efd6 | 8 e06f (0) efd6 (0) ee2b (0) eceb (0)\n004 6 f177 f005 f33c f3d5 | 6 f611 (0) f4a0 (0) f177 (0) f005 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 2 fa9a fac8 | 2 fa9a (0) fac8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","private_key":"57a4b89b8685312b36e106e0ad52cb8ee76e8ded6c198f02a1ec38b354c211e5","name":"node_fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","services":["streamer"],"enable_msg_events":true,"port":42203},"up":true}},{"node":{"info":{"id":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","name":"node_2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","enode":"enode://782260bab233d14554e8f786b5415ffd70ac89c7c221556fdb89ffb4e8f6977ab28d8918a8255aecfcc50ac131dd44231c431d6bf85229f36f8f095b62a91bbe@127.0.0.1:0","enr":"0xf88fb84089e932678501d708a5f4b9ffb2523f4716179e653f829dc22d15905cea0441b67ab9de8d2d9e91914f5ff28e37867036b36714fa1ea6e017dd084e64029850c50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102782260bab233d14554e8f786b5415ffd70ac89c7c221556fdb89ffb4e8f6977a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JHF3YDfVWgXfKxW87+UssfTJQunhUROrwqDB/Lql1iY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 247177\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 a192 acf8 a9fa a861 | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 5 4775 5c62 62f0 64e6 | 38 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n002 5 0e34 0a21 127c 1929 | 13 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n003 3 36d5 3871 3e19 | 6 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n004 3 2803 2dd4 2d53 | 3 2803 (0) 2dd4 (0) 2d53 (0)\n005 5 216e 21dc 221c 22bb | 5 216e (0) 21dc (0) 22bb (0) 221c (0)\n============ DEPTH: 6 ==========================================\n006 2 27db 27b5 | 2 27db (0) 27b5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","private_key":"4fb235ecc4c97edf33736a85d3641e652e3713b0c77d9870ab993eb9d10afcc2","name":"node_2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","services":["streamer"],"enable_msg_events":true,"port":41591},"up":true}},{"node":{"info":{"id":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","name":"node_27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","enode":"enode://2c8d76747698073fd7707081b9c643e9bd58242098e91b191f417fbbcc60dc236b8df6bb2011488880af007b77f3f826285fb2ce1ff1bcbe04c21d6fb373c111@127.0.0.1:0","enr":"0xf88fb8400b8f821da1310d4ecd5caff36e8ddaa69544654cd1241aa92aae063aac2a9f9472aa9f4b065c3a29a54feff65021b136e635a9379f9af99e57923535df10c73c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032c8d76747698073fd7707081b9c643e9bd58242098e91b191f417fbbcc60dc23","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J7VjAqiWBag1Y7p7ZtSR7CXt+tDqEBCTf8req0065YI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 27b563\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 fa65 ea3d | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 8 7bee 72a5 64e6 672a | 38 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n002 5 184e 127c 0e34 0807 | 13 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n003 2 3e19 36d5 | 6 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n004 2 2803 2d53 | 3 2803 (0) 2dd4 (0) 2d53 (0)\n005 5 216e 21dc 2354 221c | 5 216e (0) 21dc (0) 221c (0) 22bb (0)\n============ DEPTH: 6 ==========================================\n006 1 2471 | 1 2471 (0)\n007 0 | 0\n008 0 | 0\n009 1 27db | 1 27db (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","private_key":"e230f8ba6e49724537db8be23422f340405faa744171eda44d4414b8841f8d65","name":"node_27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","services":["streamer"],"enable_msg_events":true,"port":37611},"up":true}},{"node":{"info":{"id":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","name":"node_ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","enode":"enode://e3382fa3db3fda2f1f3729fc5eab5747a80c97abf5536b24fe20890ac988d61c0e3df2f91553c2768db16fdd48bfa36ec3c3e2ac4696137162859d238e4d8509@127.0.0.1:0","enr":"0xf88fb8409cf06d414b5b67bcf1e38e69f509a14cb0dcbb61db09fab4ce36203ef99b5a287b96c3febcbc9686f75736cdc30446d392ac7ad1e3cae7afece3d609b3c964f00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e3382fa3db3fda2f1f3729fc5eab5747a80c97abf5536b24fe20890ac988d61c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6j1qpQrVodVkfSE/m1z+Zxgznux+74ZESH6zwiPHvN4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ea3d6a\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 4d75 4775 4746 4589 | 68 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n001 4 a9fa a192 8330 8012 | 29 9472 (0) 957e (0) 8fb8 (0) 8d3e (0)\n002 7 c52a c2f9 d9d3 dd92 | 14 d18a (0) d125 (0) d23c (0) d9d3 (0)\n003 5 fa9a f3d5 f33c f177 | 9 fa9a (0) fac8 (0) fa65 (0) f33c (0)\n004 1 e06f | 1 e06f (0)\n============ DEPTH: 5 ==========================================\n005 5 eceb ed12 ed2e efd6 | 5 eceb (0) ed12 (0) ed2e (0) efd6 (0)\n006 0 | 0\n007 1 eb01 | 1 eb01 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","private_key":"7c2c7b1ed36aa7347eb5dd1069e933f2226e857d909980a5d78571de6aeb6867","name":"node_ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","services":["streamer"],"enable_msg_events":true,"port":46599},"up":true}},{"node":{"info":{"id":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","name":"node_f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","enode":"enode://71e720933310fdd429e11130816957617b45fd95d2e8bb1ac6e70b351c3bf2e1ad4934cef5497f766939836952bc939d6c4d694db17ee23aa22e687f7e4f1e61@127.0.0.1:0","enr":"0xf88fb840f9c7fe83c3c9fd5157e8e3320ab57aa3c67f6e1c4330581593214ef13e34ec42370db0c4aeed95c3133bf33247f122a93905351c98c5558e6d7274dd63258c0a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10371e720933310fdd429e11130816957617b45fd95d2e8bb1ac6e70b351c3bf2e1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9KD3azC89Zh8+j9PSwqjRF851gofUVGfpmDCe12DPd4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4a0f7\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 72a5 4efa 4bc8 4a37 | 68 55fd (0) 52b4 (0) 51c2 (0) 5008 (0)\n001 4 b245 a192 836e 8330 | 29 9472 (0) 957e (0) 8fb8 (0) 8d3e (0)\n002 5 cc5f c2f9 c0ad d23c | 14 d18a (0) d125 (0) d23c (0) d9d3 (0)\n003 4 efd6 ee2b eb01 ea3d | 8 e06f (0) eceb (0) ed12 (0) ed2e (0)\n004 3 fac8 fa9a fa65 | 3 fa9a (0) fac8 (0) fa65 (0)\n============ DEPTH: 5 ==========================================\n005 4 f005 f177 f33c f3d5 | 4 f005 (0) f177 (0) f33c (0) f3d5 (0)\n006 1 f611 | 1 f611 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","private_key":"ea1b57ee39036543e929539274921246c082c626d3338b562352e1570697b380","name":"node_f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","services":["streamer"],"enable_msg_events":true,"port":36907},"up":true}},{"node":{"info":{"id":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","name":"node_184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","enode":"enode://e7521d45b3c81db4b1bfc556f89dbdbc47fc7ac609fe1eafc0a7e830bee2b50f8b128616da05f3eeed91033d64402dbec46238c619da3c159c67c715fcc42c96@127.0.0.1:0","enr":"0xf88fb84045617828d5c7c09265f7dd67603ac0e5cb3e13bfd1aa995f4fa2f933c1257a6476590491ceb0211c9174c55e57d0a600bc20d608f2b1ced80363254101b91a290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e7521d45b3c81db4b1bfc556f89dbdbc47fc7ac609fe1eafc0a7e830bee2b50f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GE6eAKtP4WadTZn7M9QY0z7/kn2jjMmX9pZ5RDwksgs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 184e9e\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b355 a192 d23c e06f | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 9 5c62 52b4 4746 4d75 | 38 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n002 8 2354 27b5 2471 2803 | 17 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n003 7 0639 034d 03eb 01a6 | 8 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n============ DEPTH: 4 ==========================================\n004 3 1740 1385 127c | 3 1740 (0) 1385 (0) 127c (0)\n005 0 | 0\n006 0 | 0\n007 1 1929 | 1 1929 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","private_key":"3d7c42c0ee77391c165bc551bc1353809a10a3dc98a861729720d549f7b63386","name":"node_184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","services":["streamer"],"enable_msg_events":true,"port":43977},"up":true}},{"node":{"info":{"id":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","name":"node_64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","enode":"enode://78910b44088439d364d5486fd9eee45c43f910ad4e7a1fa7bd925bef18455f7f3e21397047344aa0abca519d7f19211c5998fb9d1977c9eb0c3586a7f3cd6c9a@127.0.0.1:0","enr":"0xf88fb8402ae44f0913233c76e5590653b9801497737a50b397a877f4bf3e49c453aa41f57cbc4a5fc6a128aa2726ea9f4bac6411fd90ef86c39ad02424c4842187c11ce30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10278910b44088439d364d5486fd9eee45c43f910ad4e7a1fa7bd925bef18455f7f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZOZC3iZnp1Y8d0BQ02iFjZmv9DPvvRy2g2Hj4kRimwM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 64e642\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ee2b dd92 bc71 | 60 d23c (0) d18a (0) d125 (0) d9d3 (0)\n001 9 2354 2471 27b5 2d53 | 30 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n002 2 4746 4a3c | 20 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n003 3 7bee 75e2 72a5 | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 2 68a6 6975 | 3 6daa (0) 6975 (0) 68a6 (0)\n005 2 62f0 6379 | 2 6379 (0) 62f0 (0)\n006 1 672a | 1 672a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 6450 641a | 2 6450 (0) 641a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","private_key":"01c1a76aef076f97db9bf60e66af44d4d529abe0f71f0b856c4508431e1792c9","name":"node_64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","services":["streamer"],"enable_msg_events":true,"port":41283},"up":true}},{"node":{"info":{"id":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","name":"node_bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","enode":"enode://0f1575d3b450347bb3500ed09bb0e0ff0fbf252b802e2a0e8e1ede7fedf7f6b64e2326928de87bb45800a8498d20b6bdfdd80fbd0041d7bbed546c86cbe8953e@127.0.0.1:0","enr":"0xf88fb840a158d2da63bc36da645177c654f2ca0a6cec837921556ecb04a65d57509dc46f66b7c4edfbefc8233e72992e4a8a3e41523af33e57ccd3966ae53be8491f3d3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f1575d3b450347bb3500ed09bb0e0ff0fbf252b802e2a0e8e1ede7fedf7f6b6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vHHz5AntuYniZgdEhJFTDFRRBTtYLqZNiCUlRRrJQLs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bc71f3\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 64e6 75e2 | 68 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n001 3 cabf f3d5 fa65 | 31 f33c (0) f3d5 (0) f177 (0) f005 (0)\n002 7 957e 9472 8fb8 8284 | 9 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n003 3 a861 a9fa a192 | 6 aedc (0) acf8 (0) aba7 (0) a9fa (0)\n004 3 b4e2 b355 b245 | 5 b60e (0) b5fc (0) b4e2 (0) b355 (0)\n005 2 b869 b9d9 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n============ DEPTH: 7 ==========================================\n007 4 bd48 bd96 bddb bde9 | 4 bd48 (0) bd96 (0) bddb (0) bde9 (0)\n008 0 | 0\n009 1 bc29 | 1 bc29 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","private_key":"6dccee837e7d946fc35f7afeb74d1977abaa3488cdf673d9e8a0a0d9d6ed0c21","name":"node_bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","services":["streamer"],"enable_msg_events":true,"port":36167},"up":true}},{"node":{"info":{"id":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","name":"node_75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","enode":"enode://0929c1d89eedea4cba85836dfc498319bbc4fa3a811ad84aef807af863b80365d86fc93e87d85f44822c9930d62eb6668cc64ad0fab431c7afe2824529e934f7@127.0.0.1:0","enr":"0xf88fb840d80d8a682e3360189c74b617f133ec7585e50d9dbed3329e8625c30c1d7471353fdf1a49ca51ca63b7c0dff86d48c2bd2d19f6c45fae4b5587fe23c6781bee3f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030929c1d89eedea4cba85836dfc498319bbc4fa3a811ad84aef807af863b80365","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"deKCwPPTVaQFc+ZXjFqsmOcmKXCpI59Nzv0m1vAItVM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 75e282\npopulation: 42 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 ee2b eb01 c0ad cc5f | 60 f33c (0) f3d5 (0) f005 (0) f177 (0)\n001 5 0807 0a21 3e19 2d53 | 30 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n002 12 5008 52b4 5a8b 5c62 | 20 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n003 9 64e6 6450 641a 672a | 9 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n004 3 7a68 7bcb 7bee | 3 7a68 (0) 7bcb (0) 7bee (0)\n005 3 73d0 72a5 72a7 | 3 73d0 (0) 72a7 (0) 72a5 (0)\n============ DEPTH: 6 ==========================================\n006 2 772a 77ee | 2 772a (0) 77ee (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","private_key":"cdafa79406c7b344d079038e1495604987c7c5cb47cc80bb494dc78d10085474","name":"node_75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","services":["streamer"],"enable_msg_events":true,"port":39125},"up":true}},{"node":{"info":{"id":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","name":"node_cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","enode":"enode://1a24350591770da447d5dbf6fba74dd85dd27050cc1a68603b8cb89e76b2eb77b4022b9d2cfbadc9d4a727b883104cc0b56287d9675b33d8c4d0f4f32f75e4e4@127.0.0.1:0","enr":"0xf88fb840b98c3132ab4d278a63670e3ae4432632206c358799c769ff7083d4b91cbad7d65f7b5fd6d79c96d8841b3e81ce9c3e58d82837512f7cfdd3619ddebea6e926e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021a24350591770da447d5dbf6fba74dd85dd27050cc1a68603b8cb89e76b2eb77","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zF+i1JIQ4kCYOwhT/xUAPw02bwXLH2SGuuKGLMqFLMU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc5fa2\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0f31 01a6 68a6 75e2 | 68 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n001 4 be0f b4e2 a9fa 8012 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 6 eceb ed12 ed2e f177 | 17 f33c (0) f3d5 (0) f177 (0) f005 (0)\n003 6 deec dd92 d9d3 d23c | 6 d18a (0) d125 (0) d23c (0) d9d3 (0)\n004 3 c52a c0ad c2f9 | 3 c52a (0) c2f9 (0) c0ad (0)\n005 2 c9ef cabf | 2 c9ef (0) cabf (0)\n============ DEPTH: 6 ==========================================\n006 1 ce01 | 1 ce01 (0)\n007 0 | 0\n008 1 cc9f | 1 cc9f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","private_key":"e1260778d751d38a387d4a88c5e115edf9e5478423866b27485a2292dc8e8c5a","name":"node_cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","services":["streamer"],"enable_msg_events":true,"port":35235},"up":true}},{"node":{"info":{"id":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","name":"node_68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","enode":"enode://45b4b209ea27a1478d3439b7b1c5e07f0f8021590ce28e6e498788ffc5a97d2372743f9b838796df1a3784a7e7d36abacf6f765e69941f4735b52eeab4bbcac5@127.0.0.1:0","enr":"0xf88fb840adb223ccf956ef0b48ac44f1fb4955cd78f315fae65a8a26fe14a6b0516b68982cd7f7c163fd51357a9c9f8cf8b7d7a8b002b933909fa33e717cb15e8a9e5bbb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10345b4b209ea27a1478d3439b7b1c5e07f0f8021590ce28e6e498788ffc5a97d23","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aKY+vEgz3t/bbVNEOP/MzQQvYENL7g459Ms3JudBPno=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 68a63e\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 b9d9 a192 a861 a9fa | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 4 0807 03eb 27b5 3e19 | 30 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n002 4 52b4 5a8b 4bc8 4a3c | 20 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n003 3 7bee 75e2 72a5 | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 6 6379 62f0 672a 6450 | 6 6379 (0) 62f0 (0) 672a (0) 6450 (0)\n============ DEPTH: 5 ==========================================\n005 1 6daa | 1 6daa (0)\n006 0 | 0\n007 1 6975 | 1 6975 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","private_key":"5b70dd7e5dac1e6c7338aa2968162aec253e332ea3599bec657be6d04f612da6","name":"node_68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","services":["streamer"],"enable_msg_events":true,"port":33311},"up":true}},{"node":{"info":{"id":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","name":"node_4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","enode":"enode://4ab4e0bfbba774d3dff10d02b4464d3a06ef1a9c14fd4084ec4c239a398653aa3e6c1a58462ffd6fe0d0d27c3dc284999c3560886891b362e8e99ad385747b84@127.0.0.1:0","enr":"0xf88fb840b36e6eecac0592d08346ad3d82fd3b0879b1b73d47026222ac4afb89289daf5504012dd22594a354b108a7396d8c509bc3b373adcd376aa441dc778d6c2c72ea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024ab4e0bfbba774d3dff10d02b4464d3a06ef1a9c14fd4084ec4c239a398653aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Sjw58ETEJcFT1JANsw+DnXhmyOD09NONkgXmf7VAmI4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a3c39\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 e06f eb01 fa65 fac8 | 60 f3d5 (0) f33c (0) f177 (0) f005 (0)\n001 2 184e 27b5 | 30 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n002 3 75e2 64e6 68a6 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 5008 52b4 5a8b 5c62 | 9 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n004 3 4746 459b 4589 | 4 459b (0) 4589 (0) 4746 (0) 4775 (0)\n005 2 4d75 4efa | 4 4c21 (0) 4cc2 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4bc8 | 1 4bc8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 4a37 | 1 4a37 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","private_key":"1dfd38b15db0c055f13b2e98bdef34c32d745b817c9f37516af52c78e2ba2a3e","name":"node_4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","services":["streamer"],"enable_msg_events":true,"port":34469},"up":true}},{"node":{"info":{"id":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","name":"node_8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","enode":"enode://3fc2da9e04199b0c080846d5f56ed8ab73bed014a03c242832e9be303880d706f671d59b5e15d134f4da9410d101204d0567afcde9ab261c83461744ce520751@127.0.0.1:0","enr":"0xf88fb84072d464b640b8c4621eea600036ab5b62f29ca3e9b26135a37947d95f54e9890f6559c3a84ea0b623de61d0d0ad41f9b85abe44906f2bf8e22df934c061fe6cd90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033fc2da9e04199b0c080846d5f56ed8ab73bed014a03c242832e9be303880d706","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gzDiuK4vGEu43F4VP6+k2v6G+E7GktPukUE8wHsc2eI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8330e2\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 2471 127c 0e34 0807 | 68 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n001 10 d125 dd92 c2f9 cabf | 31 f177 (0) f005 (0) f33c (0) f3d5 (0)\n002 12 a861 acf8 a192 bc71 | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 3 8fb8 8d3e 8b35 | 3 8b35 (0) 8d3e (0) 8fb8 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 8012 | 1 8012 (0)\n007 1 8284 | 1 8284 (0)\n008 0 | 0\n009 1 836e | 1 836e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","private_key":"655f2ae9378e87cd580544c9cb99036bcfb2795b603d200b06e0df9f41438877","name":"node_8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","services":["streamer"],"enable_msg_events":true,"port":46233},"up":true}},{"node":{"info":{"id":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","name":"node_b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","enode":"enode://d3a39529d6f6310edfbbecde895c8a3024336ed33e9904646e9e3e86718ed5248faaa14fd06beb2acbc38689cef3d1d7235845d431d25deb99ca91471a529092@127.0.0.1:0","enr":"0xf88fb840f566ab01e80bef9b69c5c6341ef1ee20605368864011471a8ae8bb9a47a27b434331d6c7e2b361e2766764ed97aacb871ec2912f49c7f45f1e90f321c4c9c02a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d3a39529d6f6310edfbbecde895c8a3024336ed33e9904646e9e3e86718ed524","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"skU8bnVaMO+5EZT6YHszUtdbaQXESLCa9K6t86RFtjM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2453c\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 672a 75e2 72a5 5c62 | 68 58a9 (0) 5a8b (0) 5be6 (0) 5cc1 (0)\n001 8 e06f fa65 fac8 f4a0 | 31 f005 (0) f177 (0) f3d5 (0) f33c (0)\n002 4 8d3e 8012 836e 8330 | 9 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n003 4 a192 acf8 a9fa a861 | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 5 b9d9 b869 bc71 bde9 | 9 b9d9 (0) b869 (0) be0f (0) bd48 (0)\n============ DEPTH: 5 ==========================================\n005 3 b60e b5fc b4e2 | 3 b60e (0) b5fc (0) b4e2 (0)\n006 0 | 0\n007 1 b355 | 1 b355 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","private_key":"34a8d5008ee38c02fa2deffed8ac1eb5e4238f26925bba625642248ee6f4b502","name":"node_b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","services":["streamer"],"enable_msg_events":true,"port":44445},"up":true}},{"node":{"info":{"id":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","name":"node_c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","enode":"enode://e8139ca6fd25a63ec0226a7e0d1b3e24dd4a64e28de32b96e967dce072e64ca1eda7974197edb2b54bce2bff0c78543b0d9b29eb6ea9610bad964a9177b0f40a@127.0.0.1:0","enr":"0xf88fb840ea7ff8e5655a5641139c8258f6ea2d2fcaf6b7e83105a5a3489aa0c3611a21c5763a5b6a12671c24fd597686f485cdcc17d168e4ec02458d74c3be1cf0455d480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8139ca6fd25a63ec0226a7e0d1b3e24dd4a64e28de32b96e967dce072e64ca1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wK3zlK99VnDBzoxr6ikvvAPFauK2NuLzAzEaRVuzUA8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c0adf3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 62f0 672a 7bee 75e2 | 68 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n001 5 9472 8b35 a9fa b4e2 | 29 957e (0) 9472 (0) 8fb8 (0) 8d3e (0)\n002 5 f4a0 fa65 ed12 ed2e | 17 f3d5 (0) f33c (0) f177 (0) f005 (0)\n003 5 d23c d18a d125 dd92 | 6 d18a (0) d125 (0) d23c (0) deec (0)\n004 5 ce01 cc5f cc9f c9ef | 5 c9ef (0) cabf (0) ce01 (0) cc5f (0)\n============ DEPTH: 5 ==========================================\n005 1 c52a | 1 c52a (0)\n006 1 c2f9 | 1 c2f9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","private_key":"269f2338eae4174d5d03bcc681f76dc898907e6bcaa160114424dc97aa7307b8","name":"node_c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","services":["streamer"],"enable_msg_events":true,"port":36773},"up":true}},{"node":{"info":{"id":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","name":"node_2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","enode":"enode://3f4db397fc277b2e70200ee0df565958becb600266ad3362cb2fcf934318cca69ae8ac6ecf3040c7bc23192473e12a8828383ac4106878567e97fc0c3ff63339@127.0.0.1:0","enr":"0xf88fb840e7c428cebdf711272fc568f71b015bf4dcf2c02936b88067d975ddf1d00fd52a28c15718e1c7dd0120d9614b4063392c515e52ffdf2c222ea70d6651df4cc9830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033f4db397fc277b2e70200ee0df565958becb600266ad3362cb2fcf934318cca6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LVMcUBg/ARUmmz/q7PRZJ6OsROG+KiY8fl0idNg3mxw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2d531c\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e06f ee2b c0ad | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 7 4775 5c62 64e6 672a | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 6 0639 03eb 0a21 0e34 | 13 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n003 3 36d5 3b83 3e19 | 6 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n004 7 2471 27db 27b5 216e | 8 216e (0) 21dc (0) 22bb (0) 221c (0)\n============ DEPTH: 5 ==========================================\n005 1 2803 | 1 2803 (0)\n006 0 | 0\n007 0 | 0\n008 1 2dd4 | 1 2dd4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","private_key":"ee9db292a301dd892d1aedca4ef8a90d737b64e572c05b6cca13f334c41ba6dd","name":"node_2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","services":["streamer"],"enable_msg_events":true,"port":45347},"up":true}},{"node":{"info":{"id":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","name":"node_ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","enode":"enode://82b34fd84b01efb9af41bd124c2681e968807afaca2443d11d60658225bdd803500d87c13fa9c5211d1653afd9bf44755a722f01f91e518459780203fad0cd43@127.0.0.1:0","enr":"0xf88fb840f0a7a792a4415787d483eb211eff11116792290e2670e5a0bd87f67c81f5dc54301614339b1960d225318d4f7745e6af895493e42d6c270f429fd4def2e241560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10382b34fd84b01efb9af41bd124c2681e968807afaca2443d11d60658225bdd803","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7isK/2GphG0T3jpycS7wvzykKtjaV+gXWcJCeXJY7+w=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ee2b0a\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 6975 68a6 62f0 672a | 68 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n001 10 bc29 be0f b9d9 b869 | 29 a192 (0) aedc (0) acf8 (0) aba7 (0)\n002 3 d125 d9d3 cc9f | 14 d23c (0) d18a (0) d125 (0) deec (0)\n003 6 f33c f3d5 f611 f4a0 | 9 f3d5 (0) f33c (0) f177 (0) f005 (0)\n004 1 e06f | 1 e06f (0)\n005 2 ea3d eb01 | 2 ea3d (0) eb01 (0)\n============ DEPTH: 6 ==========================================\n006 3 eceb ed12 ed2e | 3 ed12 (0) ed2e (0) eceb (0)\n007 1 efd6 | 1 efd6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","private_key":"51ff90bcd8f1d150186f82b07c3bf74723a2111416020b1205876876d1456e91","name":"node_ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","services":["streamer"],"enable_msg_events":true,"port":34721},"up":true}},{"node":{"info":{"id":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","name":"node_8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","enode":"enode://638906e18d86b361cea53902fae144fb0a7bbe1c7f674a34e10247c074d176f58a797837069d5a21666ffb9476348fb394b80ecc0b1023d2111a85eb5c1952fb@127.0.0.1:0","enr":"0xf88fb84024f9e170931c28fb70978c7ce403865edd91dde7ffbb04e68f03512bf8ed726d5db895185177805ad4e5c9c73717ea1e97430505269dd32916cc5949aa72e7410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103638906e18d86b361cea53902fae144fb0a7bbe1c7f674a34e10247c074d176f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gBKnr3HXbYgiAs+TclI0eMzr6iNEMAbH8pwqgxBs0bM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8012a7\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 2471 0a21 4775 | 68 21dc (0) 216e (0) 221c (0) 22bb (0)\n001 14 dd92 d23c d125 c2f9 | 31 d23c (0) d18a (0) d125 (0) deec (0)\n002 12 acf8 a861 a9fa a192 | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 3 8b35 8d3e 8fb8 | 3 8b35 (0) 8d3e (0) 8fb8 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 8284 836e 8330 | 3 8284 (0) 836e (0) 8330 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","private_key":"9a9f5d8e07fc393a86b48129afcd4aa66dda3b5ff3498c7239e89572c4f218a1","name":"node_8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","services":["streamer"],"enable_msg_events":true,"port":33055},"up":true}},{"node":{"info":{"id":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","name":"node_47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","enode":"enode://ea98a4cc6d36e0a9e09061c40743fd14032109b1a0d8d20d2e20b419275c526f99c5c19b6123a6e78d21c5497e16fb49ca279795954f2ceac05ea01c772c83a4@127.0.0.1:0","enr":"0xf88fb8403249a6dba1fd864f716568258f1c1c1044871b1ab897dfccb42a89c5ad14ee743a196a92533717f40d4e17de9d9a9cd2cd14cc87855f4c270ac5407a6c8e0e530183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ea98a4cc6d36e0a9e09061c40743fd14032109b1a0d8d20d2e20b419275c526f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R3U/3KhV6nmr9me1CqnJChMtRL3RVyw+PEEcjufltfQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 47753f\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 fac8 f4a0 ea3d efd6 | 60 d23c (0) d18a (0) d125 (0) deec (0)\n001 9 27b5 2471 2354 2d53 | 30 3b83 (0) 3871 (0) 3e19 (0) 3590 (0)\n002 4 672a 62f0 72a5 75e2 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 3 5c62 5a8b 5008 | 9 58a9 (0) 5be6 (0) 5a8b (0) 5cc1 (0)\n004 5 4a37 4bc8 4d75 4c21 | 7 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 459b 4589 | 2 459b (0) 4589 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 4746 | 1 4746 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","private_key":"3f946790db720a1aff2dcaef0a931c26359587ade7dbbd5611d6e4e4c48b45a7","name":"node_47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","services":["streamer"],"enable_msg_events":true,"port":39017},"up":true}},{"node":{"info":{"id":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","name":"node_efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","enode":"enode://36e15237c01d8907bd512448e053510123d7742258fc18294dd99bc2dd171d87f1f14fd30584dff7196d37ab49ee7eb689238aeb159e0162efb3c35ba47d4723@127.0.0.1:0","enr":"0xf88fb84010215926d38f4b9af18d9d9e2831fd468800ada49bcdf6dcf9254373c72e00187ee5495c9979f3684cd5ee9750204e55dd9154ae90f78e9775578a2a221c8fd20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10336e15237c01d8907bd512448e053510123d7742258fc18294dd99bc2dd171d87","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"79aNLJk0bKCFye+Ja+5hJa2GOEEylRCPOpKyR6Qcpik=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: efd68d\npopulation: 22 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 127c 4775 | 68 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n001 2 8012 8330 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 5 c9ef cabf d23c d9d3 | 14 d18a (0) d125 (0) d23c (0) deec (0)\n003 6 f3d5 f4a0 f611 fac8 | 9 f177 (0) f005 (0) f33c (0) f3d5 (0)\n004 1 e06f | 1 e06f (0)\n005 2 ea3d eb01 | 2 ea3d (0) eb01 (0)\n============ DEPTH: 6 ==========================================\n006 3 eceb ed12 ed2e | 3 eceb (0) ed12 (0) ed2e (0)\n007 1 ee2b | 1 ee2b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","private_key":"245b148ec129e7a6491d45cc5c65217870ae2de275e5b688021b636011178055","name":"node_efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","services":["streamer"],"enable_msg_events":true,"port":34239},"up":true}},{"node":{"info":{"id":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","name":"node_127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","enode":"enode://7db629e8af234327ae65a632ab973188f8d44b4dc9336cc42246df45a87caa6a64c3a3b41a68f623e284a4bf0462a85ab81b0a51c28dedf1cb3357451a56d5c6@127.0.0.1:0","enr":"0xf88fb840acbb379c02f6b49e0fcc45220b6ed91e7e13bfc2beaf4a0ef7644b445216a379260871c4d3b022edab98a8cd70bbc4ca98623ea4c3b365840e157dd64c2147470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027db629e8af234327ae65a632ab973188f8d44b4dc9336cc42246df45a87caa6a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EnyJ6ulLGV3y6163tE9jSttzwRTSCJzZBLVpiMhnThE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 127c89\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b355 8d3e 836e 8330 | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 5 4d75 4746 5008 7bcb | 38 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n002 6 36d5 3e19 2d53 2471 | 17 3e19 (0) 3871 (0) 3b83 (0) 3590 (0)\n003 6 01a6 03eb 0a21 0807 | 8 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n004 2 1929 184e | 2 1929 (0) 184e (0)\n============ DEPTH: 5 ==========================================\n005 1 1740 | 1 1740 (0)\n006 0 | 0\n007 1 1385 | 1 1385 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","private_key":"54a20d22b4654e13d2547690e34e3de3cae15187e8034f587fe718896fa946f7","name":"node_127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","services":["streamer"],"enable_msg_events":true,"port":45857},"up":true}},{"node":{"info":{"id":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","name":"node_69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","enode":"enode://08a249844dec3d48a57ec53c79310b2f24cc27fedf91464cc30bd2213ec844437a00e3cc7d5e2f97b99516b21901ffe2e2a451340f594023bfac4463750c1ccf@127.0.0.1:0","enr":"0xf88fb84026ec31c1451ae3cc1ab533f52d87c62368080c439aff174f1f0a67fe50b956cc31c5260e382dcee5546e815dfa2dc26802922227f77d4bb25e5b47975222653a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10308a249844dec3d48a57ec53c79310b2f24cc27fedf91464cc30bd2213ec84443","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aXU4ZarKr3LZv20mXIhdP3BYBP9LJnX3qoYGQdrKsqA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 697538\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ee2b cc9f 836e bd96 | 60 f177 (0) f005 (0) f3d5 (0) f33c (0)\n001 6 2d53 03eb 0e34 0807 | 30 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n002 5 5a8b 52b4 5008 4bc8 | 20 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n003 3 72a5 77ee 75e2 | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 6 6379 62f0 672a 641a | 6 672a (0) 641a (0) 6450 (0) 64e6 (0)\n============ DEPTH: 5 ==========================================\n005 1 6daa | 1 6daa (0)\n006 0 | 0\n007 1 68a6 | 1 68a6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","private_key":"ce7b2f3ec596e7541804d73b0233cf93b061d33437fded3aae42df7d2fed2431","name":"node_69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","services":["streamer"],"enable_msg_events":true,"port":42103},"up":true}},{"node":{"info":{"id":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","name":"node_bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","enode":"enode://6ff77126c9946af5efe7c6850f8e59fa25bf6b808b00fade65d30e736f8eae7cc9fa35eb0f4382f95e5408b1cb030919d4f43e911ad1019ea5908d31ace54fb0@127.0.0.1:0","enr":"0xf88fb84047976194f9b1bbc1d405c1f0db707474b3b32a9a96750e1efcc39c5af51fa41213297557f076cbdd35bde4e8f909eeafe16d9694c5ce304ebcec675c7b7e11ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ff77126c9946af5efe7c6850f8e59fa25bf6b808b00fade65d30e736f8eae7c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vZYH1fV/e2909K2YG+NomI70i18x4/2WyrO7eQ1WgVA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bd9607\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4589 6975 | 68 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n001 5 cabf f611 f33c f005 | 31 f177 (0) f005 (0) f3d5 (0) f33c (0)\n002 4 8d3e 8012 836e 8330 | 9 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n003 4 a192 a9fa a861 acf8 | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 5 b4e2 b5fc b60e b355 | 5 b60e (0) b5fc (0) b4e2 (0) b355 (0)\n005 2 b9d9 b869 | 2 b869 (0) b9d9 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc29 bc71 | 2 bc29 (0) bc71 (0)\n008 1 bd48 | 1 bd48 (0)\n============ DEPTH: 9 ==========================================\n009 2 bddb bde9 | 2 bddb (0) bde9 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","private_key":"cbe3758f2717e1a3a9e53818d435eee8edc340e4e3d507cee9efdab8eddab838","name":"node_bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","services":["streamer"],"enable_msg_events":true,"port":40601},"up":true}},{"node":{"info":{"id":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","name":"node_45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","enode":"enode://99d33a9f9eebfa22c429478e4a0a01fa06d35e27b162331e8e4464a87d2adf5ec35e26697560f760cc58c5afd36ced8e1be393168089020b5881a44264fe609d@127.0.0.1:0","enr":"0xf88fb840b358458a817fa640619f1d3a7f3aaa81f7de7b7830255d88d70eb1aaf9b3c921433aea9123e9756df8724646634423960203427b8ff8e7f8929a6a501a51c6740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10399d33a9f9eebfa22c429478e4a0a01fa06d35e27b162331e8e4464a87d2adf5e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RYla/2dAefa+AuTMdJFNYxJcP+SLtpBWwHDHExn+ofo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 45895a\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 ed2e eceb ea3d e06f | 60 f3d5 (0) f33c (0) f177 (0) f005 (0)\n001 9 2dd4 2803 36d5 3e19 | 30 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n002 4 75e2 72a5 672a 6975 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 55fd 5008 5c62 5a8b | 9 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n004 4 4d75 4efa 4bc8 4a3c | 7 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 4775 4746 | 2 4746 (0) 4775 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 459b | 1 459b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","private_key":"4be326b4bad9ec6d897672d72f86d7c21742af31459c61ff9d29a7c4f2b87288","name":"node_45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","services":["streamer"],"enable_msg_events":true,"port":35991},"up":true}},{"node":{"info":{"id":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","name":"node_0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","enode":"enode://55140e8f1873f8006a1e1a309e31669c0442eb381ea30f7e4261c7979760b5b10030ca2c72d35492c2c3d456c560f898249944dfbd3d408c456b3ded66c13e5d@127.0.0.1:0","enr":"0xf88fb840a3583d99fad5b4703c5847493453e0b451c4d555d6ee5a8833671be976378a823cf88dd213ebdd319ff433e569d46dd3d19c6e06e909f79ce6d847f6145a430b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10355140e8f1873f8006a1e1a309e31669c0442eb381ea30f7e4261c7979760b5b1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CiFcd2W+LK6/dq0+gBe7wqqt+ODdSFmveBlToFZMXVk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0a215c\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d23c fa9a e06f 8d3e | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 7 672a 64e6 75e2 72a7 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 7 3e19 3871 36d5 2d53 | 17 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n003 5 1385 127c 1740 1929 | 5 1929 (0) 184e (0) 1740 (0) 1385 (0)\n004 4 0639 01a6 034d 03eb | 4 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n============ DEPTH: 5 ==========================================\n005 2 0f31 0e34 | 2 0f31 (0) 0e34 (0)\n006 1 0807 | 1 0807 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","private_key":"48398a9192cbe71d3dae01f8cd736bd6fa81f40d86363732910ab557934ac32a","name":"node_0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","services":["streamer"],"enable_msg_events":true,"port":32803},"up":true}},{"node":{"info":{"id":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","name":"node_0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","enode":"enode://a657bea94ef83334a2eb69fa819e389faa047abb53fdce1ada5de9f2ad8577331fc88094fd258ff4dfb4ecc38e37cc65b0807dc8c13d0f933d0975b4930a152a@127.0.0.1:0","enr":"0xf88fb840e7a038b940736e411d390aa7ac6e0d5380fb096ac5b06fb69e561038d33eece64602defd9da5012d991e93b78ce269e66ae7083c78fa635400a7941b55511bd50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a657bea94ef83334a2eb69fa819e389faa047abb53fdce1ada5de9f2ad857733","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DjRMbifCO9Nr3T3c76Tld/3JRh5Sx84gE1czoIuYe4I=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e344c\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 d23c e06f b355 8330 | 60 f3d5 (0) f33c (0) f177 (0) f005 (0)\n001 4 7bcb 6975 4746 4775 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 6 36d5 3e19 2d53 2471 | 17 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n003 4 1929 184e 1740 127c | 5 1929 (0) 184e (0) 1740 (0) 1385 (0)\n004 3 034d 03eb 01a6 | 4 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n============ DEPTH: 5 ==========================================\n005 2 0807 0a21 | 2 0807 (0) 0a21 (0)\n006 0 | 0\n007 1 0f31 | 1 0f31 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","private_key":"bd217ea07881a97e7c8d265ab1ea058cd33f23e29d61169327cafa40e7eb7e35","name":"node_0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","services":["streamer"],"enable_msg_events":true,"port":32907},"up":true}},{"node":{"info":{"id":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","name":"node_836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","enode":"enode://7955513f0867be5484a68700771fab5ed2bcaff4c5fe81e88b07b95e273742fe920d733d44b7b187d1d5ddca6eccb92921a69f1a5f1874d9eee4d61f4e849f3d@127.0.0.1:0","enr":"0xf88fb840e3fdd157b8d17ad9462935700437f5e3379cc6b910e447979420623db2209a132159463905a57dace86b0516654cfb2e39b3e9c5a376652fd559309c05dcf4410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037955513f0867be5484a68700771fab5ed2bcaff4c5fe81e88b07b95e273742fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g25l3+bwHh0pNGVcGEbLhv7W5B6pUaEJ16ILsUy0wQo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 836e65\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 4589 6975 68a6 62f0 | 68 7bcb (0) 7bee (0) 7a68 (0) 73d0 (0)\n001 8 fac8 fa9a fa65 f4a0 | 31 f177 (0) f005 (0) f3d5 (0) f33c (0)\n002 6 b9d9 bc71 bd96 b245 | 20 be0f (0) bc29 (0) bc71 (0) bd48 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 3 8b35 8fb8 8d3e | 3 8b35 (0) 8fb8 (0) 8d3e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 8012 | 1 8012 (0)\n007 1 8284 | 1 8284 (0)\n008 0 | 0\n009 1 8330 | 1 8330 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","private_key":"828792ee935c8a9739d8fffdccb73fdb38a998850e0a4e5f3a67fad91701cc2c","name":"node_836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","services":["streamer"],"enable_msg_events":true,"port":46599},"up":true}},{"node":{"info":{"id":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","name":"node_cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","enode":"enode://fcd2ab0c2237f9a09130eef63262c5dbe407ec25a8ff88d55dae0c65c7352a829f879f303aebfdc8d979b2843b7b61933608d4f89ebe778995455c135371ba78@127.0.0.1:0","enr":"0xf88fb840ebf4dbd2665552b22575e2991f43e3d416eff9488c23d9f3580a78a225117d891a35ec6b32c752922b70470cc162564533cd54db06d6b9cf023e19932ef864e10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fcd2ab0c2237f9a09130eef63262c5dbe407ec25a8ff88d55dae0c65c7352a82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zJ9l1zTxo7vGAZ4Wb+NVvX/DO7SIcEOlzPUyqbo1Y3k=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc9f65\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6975 62f0 0f31 01a6 | 68 7a68 (0) 7bcb (0) 7bee (0) 772a (0)\n001 2 acf8 836e | 29 b4e2 (0) b5fc (0) b60e (0) b355 (0)\n002 6 f33c fa65 eceb ed2e | 17 f177 (0) f005 (0) f3d5 (0) f33c (0)\n003 5 d125 d23c deec dd92 | 6 d23c (0) d18a (0) d125 (0) deec (0)\n004 3 c0ad c2f9 c52a | 3 c52a (0) c2f9 (0) c0ad (0)\n005 2 cabf c9ef | 2 c9ef (0) cabf (0)\n============ DEPTH: 6 ==========================================\n006 1 ce01 | 1 ce01 (0)\n007 0 | 0\n008 1 cc5f | 1 cc5f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","private_key":"4a1901aae6d17a696581fa1df5fb404606b4894884e5ce2ae52f014c1f7ab1ec","name":"node_cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","services":["streamer"],"enable_msg_events":true,"port":45379},"up":true}},{"node":{"info":{"id":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","name":"node_eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","enode":"enode://6570b12362a67ae69eb59bbb7ef187f002e9d8c189bc44e7a66d49e48442754fb3c332e796a34094a0c32ca763a56bf77272b15090ea404f1fde0f8f02f69d9a@127.0.0.1:0","enr":"0xf88fb840a0eb32cba24198285bd35892feb415dc76bca095952a0b36d8b453aadb7c61fc63195b1956ee0ca78f7e50df142ed78fea1741090dc0988605592bd8b167af1a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026570b12362a67ae69eb59bbb7ef187f002e9d8c189bc44e7a66d49e48442754f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6wH/gDB6+/x0V8lllM1LpNAKy3/SWnVx0SIxaL1m/wk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb01ff\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4a3c 7bee 72a7 72a5 | 68 7a68 (0) 7bcb (0) 7bee (0) 772a (0)\n001 3 8012 a861 bd96 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 4 c52a c0ad c9ef cc9f | 14 d18a (0) d125 (0) d23c (0) deec (0)\n003 7 f4a0 f611 f3d5 f33c | 9 f177 (0) f005 (0) f3d5 (0) f33c (0)\n004 1 e06f | 1 e06f (0)\n============ DEPTH: 5 ==========================================\n005 5 ed12 ed2e eceb efd6 | 5 efd6 (0) ee2b (0) ed12 (0) ed2e (0)\n006 0 | 0\n007 1 ea3d | 1 ea3d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","private_key":"e5be2c35a1499c508166c81de8a45fd1cda4bea223164bf47ba8c974725fdf75","name":"node_eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","services":["streamer"],"enable_msg_events":true,"port":33263},"up":true}},{"node":{"info":{"id":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","name":"node_08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","enode":"enode://7d4f4b1f1c3dc1f6418391214afa500757d43f64aea2f11d7694de79d243af3e1c1c1662233b71306cc1c060ddf7e21dbdbbac53d0bcfe2fd3b6f29c7656e69f@127.0.0.1:0","enr":"0xf88fb840da1dfdefbe43711df3887e5825a698e2931b2e4fda60051803d6402f11fe21a14ee3b5bac8cf9543cad98736a88ae0734609ac9b8ba3d04815d21c44e5c2551e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037d4f4b1f1c3dc1f6418391214afa500757d43f64aea2f11d7694de79d243af3e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CAd8DOjUEwwURkST6RZKi65htGRrHsSImedfL2+bjGY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08077c\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eb01 8d3e 8330 a861 | 60 c52a (0) c2f9 (0) c0ad (0) cabf (0)\n001 10 4589 4775 4746 7bcb | 38 7bee (0) 7bcb (0) 7a68 (0) 73d0 (0)\n002 5 3e19 3871 3b83 27b5 | 17 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n003 4 1740 1385 127c 184e | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0639 01a6 034d 03eb | 4 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n============ DEPTH: 5 ==========================================\n005 2 0f31 0e34 | 2 0e34 (0) 0f31 (0)\n006 1 0a21 | 1 0a21 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","private_key":"97f4ac0685f5a566c69307b57852116db766c3319995e5a30c98d0b770d9ebf8","name":"node_08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","services":["streamer"],"enable_msg_events":true,"port":34207},"up":true}},{"node":{"info":{"id":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","name":"node_a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","enode":"enode://288eb859b2b3db8e349860a6324c65887218b6162fb33a09fc8b18ae24bfc20a7f490f036a7c5b889d68f8eb9efe590b77d3983019b8f8ef4d3cfa76dafc655e@127.0.0.1:0","enr":"0xf88fb8404a25f16978fe1fb9671930db81e544e0cff37050b6c6325193d7feccf29e22c45e8bef40ecda5b29e9cea5d10e7e70ee0a8a02744a915a78858248804e87186e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102288eb859b2b3db8e349860a6324c65887218b6162fb33a09fc8b18ae24bfc20a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qGEXFHt48gptiD03cV2oUXjK2J7/ZQp0qonnvBG8Rac=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a86117\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 73d0 68a6 5008 2471 | 68 7bee (0) 7bcb (0) 7a68 (0) 73d0 (0)\n001 8 dd92 c2f9 f3d5 f611 | 31 f611 (0) f4a0 (0) f177 (0) f005 (0)\n002 4 8d3e 8012 8330 836e | 9 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n003 9 b9d9 b869 bd48 bde9 | 14 b355 (0) b245 (0) b5fc (0) b4e2 (0)\n004 1 a192 | 1 a192 (0)\n005 2 aedc acf8 | 2 aedc (0) acf8 (0)\n============ DEPTH: 6 ==========================================\n006 1 aba7 | 1 aba7 (0)\n007 1 a9fa | 1 a9fa (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","private_key":"e91c4e7ef86a9d2c9e2d4949d79f0188a6fe4c317a21ff93d7517b08b03a84ad","name":"node_a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","services":["streamer"],"enable_msg_events":true,"port":42373},"up":true}},{"node":{"info":{"id":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","name":"node_5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","enode":"enode://4352662356e5f6fed37ae1e0853e8f9d1d52e8c8291718bd69f73ff06f3a3904f070a2ee34d6b3c4ce86429317a48c1aae1ee3a95565f2164240c1289d49d409@127.0.0.1:0","enr":"0xf88fb84075269349b759660c79167f80db6ab17f351f923baab541b3fc9a2b78dd6577a7610b64e2d804fe4670d11df5a743a6d4e2c73b726a72c4539f380470c2795c300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034352662356e5f6fed37ae1e0853e8f9d1d52e8c8291718bd69f73ff06f3a3904","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UAjvVa2AiPcGQ7D5O8tHlTG8sK/o4BshXb+Fl+yGY2k=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5008ef\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ea3d f4a0 d9d3 b245 | 60 f611 (0) f4a0 (0) f177 (0) f005 (0)\n001 5 1740 127c 03eb 01a6 | 30 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n002 3 75e2 62f0 6975 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 4a3c 459b 4589 4775 | 11 4efa (0) 4c21 (0) 4cc2 (0) 4d75 (0)\n004 4 5c62 5cc1 58a9 5a8b | 5 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n005 1 55fd | 1 55fd (0)\n============ DEPTH: 6 ==========================================\n006 1 52b4 | 1 52b4 (0)\n007 1 51c2 | 1 51c2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","private_key":"40ffe414c67c7872869542bbaf010af4e063dbc9e734ec01ebc6ffe7f09a289b","name":"node_5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","services":["streamer"],"enable_msg_events":true,"port":42611},"up":true}},{"node":{"info":{"id":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","name":"node_d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","enode":"enode://10520254bae35bd2c92f66f483de02b78d1753df0d2969aa22382c5dfb51a967e47e6189437e2326a96b6f902faa6ae5cf59af59f3b0cd4021dc6ecb0dbe0ed7@127.0.0.1:0","enr":"0xf88fb8406d769c006c5ed31a452a2a90135f9d37fea25bd1eff0888fcf8d995e9994b13437c02d2f21b826af8f36fff78e9f23b13e1af4851c0df81af662729cd81cccb40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10310520254bae35bd2c92f66f483de02b78d1753df0d2969aa22382c5dfb51a967","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2dMLmyEr1IEaROvjBLo5NerTq+Mkf5mJP69lZkExwp0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d9d30b\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0f31 01a6 03eb 5008 | 68 3775 (0) 36d5 (0) 3590 (0) 3e19 (0)\n001 2 acf8 b9d9 | 29 957e (0) 9472 (0) 8b35 (0) 8fb8 (0)\n002 6 ea3d eceb efd6 ee2b | 17 f611 (0) f4a0 (0) f177 (0) f005 (0)\n003 6 c9ef cc5f cc9f c52a | 8 c52a (0) c0ad (0) c2f9 (0) cabf (0)\n004 3 d125 d18a d23c | 3 d125 (0) d18a (0) d23c (0)\n============ DEPTH: 5 ==========================================\n005 2 dd92 deec | 2 dd92 (0) deec (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","private_key":"70b8e572ba811ae79bbcaffd1421381dc00b020737f2e6f4c1311ebe984fa426","name":"node_d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","services":["streamer"],"enable_msg_events":true,"port":36959},"up":true}},{"node":{"info":{"id":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","name":"node_03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","enode":"enode://118cbd671c6e8b583a18aa14af1eeddb499047376ff5e84c160f3eec13f5b5d33f390b65cf2428621ced70ec419935c37ef4236a8f63f7b5cf81f58a0dfb59f3@127.0.0.1:0","enr":"0xf88fb840c91599a2365e987a7355bef1ad535065e3c907887c577bfbf22416ec8c60a63e28c13dfc44d51262f3a3514757c2ff8c315eb57f44ce1c58397816c8e8bd2fea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103118cbd671c6e8b583a18aa14af1eeddb499047376ff5e84c160f3eec13f5b5d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A+suku0JI/aWJp56A/7HMdjD+N8ngCOpywCGe1M6PKM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 03eb2e\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fa9a c9ef c2f9 d9d3 | 60 957e (0) 9472 (0) 8b35 (0) 8fb8 (0)\n001 11 62f0 6975 68a6 72a7 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 4 2dd4 2d53 22bb 2354 | 17 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n003 3 184e 1740 127c | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0e34 0f31 0807 0a21 | 4 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n005 1 0639 | 1 0639 (0)\n============ DEPTH: 6 ==========================================\n006 1 01a6 | 1 01a6 (0)\n007 0 | 0\n008 1 034d | 1 034d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","private_key":"bb068a5ae255ce7c42cb5928785a16dd2b717db214b975dc7af82a56d1465fa4","name":"node_03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","services":["streamer"],"enable_msg_events":true,"port":41317},"up":true}},{"node":{"info":{"id":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","name":"node_5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","enode":"enode://1e7d80f4aab757649946e09a942ec9dc561f7fab556def6e20e6449f154eddd1d6acc7d2e24db2f0951152d4ccd3eaa9ad32b54b1dedc60eb4c15078f2281cc6@127.0.0.1:0","enr":"0xf88fb8404b1fe1c4ca1bb536ead1b7c7fa4e49b2514aaa26ad2076329d9316b78adc03db18a0e3c270a9cfd2e61e06f850436d2bd103ae39b7c61106619bef3f3fdfb8a90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021e7d80f4aab757649946e09a942ec9dc561f7fab556def6e20e6449f154eddd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WoukBHxEVuglvRs0yWH1x/N798J7xIvucbhDDH0TVIY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a8ba4\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c9ef c2f9 | 60 d23c (0) d18a (0) d125 (0) deec (0)\n001 3 1740 03eb 2354 | 30 1929 (0) 184e (0) 1385 (0) 127c (0)\n002 7 62f0 6975 68a6 73d0 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 4bc8 4a3c 4775 4589 | 11 4efa (0) 4c21 (0) 4cc2 (0) 4d75 (0)\n004 3 55fd 52b4 5008 | 4 55fd (0) 52b4 (0) 51c2 (0) 5008 (0)\n005 2 5cc1 5c62 | 2 5cc1 (0) 5c62 (0)\n============ DEPTH: 6 ==========================================\n006 1 58a9 | 1 58a9 (0)\n007 1 5be6 | 1 5be6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","private_key":"dbec70bb9a08cabd1e7f19877731d486591fa448c65d8e48175658b5a46d7708","name":"node_5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","services":["streamer"],"enable_msg_events":true,"port":35767},"up":true}},{"node":{"info":{"id":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","name":"node_2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","enode":"enode://5f6d6715804fb0fa79d11569c038c51fdb2c154b06f8403d57d7362c87b361147a3bbf7d990c650a857a7aed53df21bc7a6d08540b1d0894db1cd83e1e69d0bd@127.0.0.1:0","enr":"0xf88fb8400295eb2dd56032a5f0ef15321413956120d8ea0924e56ebba770b064f823e42c015ddb67c6964e293c937f596999883d7a6d3c8b1fd7364e6afe36b4c0ca679f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035f6d6715804fb0fa79d11569c038c51fdb2c154b06f8403d57d7362c87b36114","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"I1TTr1xtygXX3CErEAES83qyn7iz9DGYhyMKTUIPXZ0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2354d3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c9ef cc9f | 60 d23c (0) d18a (0) d125 (0) deec (0)\n001 5 64e6 4d75 4775 5008 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 7 0e34 0807 01a6 03eb | 13 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n003 4 36d5 3e19 3871 3b83 | 6 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n004 3 2803 2dd4 2d53 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 27b5 27db 2471 | 3 27db (0) 27b5 (0) 2471 (0)\n006 2 21dc 216e | 2 21dc (0) 216e (0)\n============ DEPTH: 7 ==========================================\n007 2 221c 22bb | 2 221c (0) 22bb (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","private_key":"33f99c8fc27af3dfbab6afb6eca5cf61ff93788a211883b10a12d2696ebc18a5","name":"node_2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","services":["streamer"],"enable_msg_events":true,"port":37965},"up":true}},{"node":{"info":{"id":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","name":"node_17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","enode":"enode://0163c2caaad749b2a1877dee27794e363304a8dfa3af56d253c7021217545cd1f31f24a821594b340e18ef78a6498656b65c7a12ba99a7e1a2ef34ef9da4c04d@127.0.0.1:0","enr":"0xf88fb840737226882bb1d943eb2e9cd4dfcfa63deca2a52dc312ea55f2cb29cf6f44704976ad5889976d9d00a3e0b745a7870999b20eb3a8f915f0c0b797c878cbe77fdf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030163c2caaad749b2a1877dee27794e363304a8dfa3af56d253c7021217545cd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F0Bt6lBG8A4n6vdOFmqUXJSFE51u3N/NhPWwP1Du3Qo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 17406d\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 be0f 8d3e fa9a c2f9 | 60 d23c (0) d125 (0) d18a (0) dd92 (0)\n001 6 6975 73d0 77ee 5a8b | 38 4a37 (0) 4a3c (0) 4bc8 (0) 4efa (0)\n002 7 3e19 3b83 3871 2dd4 | 17 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n003 7 0a21 0807 0e34 0f31 | 8 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n004 2 1929 184e | 2 184e (0) 1929 (0)\n============ DEPTH: 5 ==========================================\n005 2 1385 127c | 2 1385 (0) 127c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","private_key":"96f0245c4b78bbf5a569ca11e55db6399d83ce08e6ec692e63acaebac837a9ea","name":"node_17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","services":["streamer"],"enable_msg_events":true,"port":33857},"up":true}},{"node":{"info":{"id":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","name":"node_01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","enode":"enode://946ba7faf16b78557ada55aa61d2ce4df1f255db899d3719d93c2005e88fd20aba59f9cdb4bc62d86b4b405a24bd310a8af3f1e4baf9cf5dbd548cf4e8d35557@127.0.0.1:0","enr":"0xf88fb8403960e3e45dce252d35faa9910dff31d41ef445f18ea2ff3d8fdeffb2716ef6fe40bdf310ee963cc581fc397dcd35c02571b7ff73bad2e0f63fde62678c392aa50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103946ba7faf16b78557ada55aa61d2ce4df1f255db899d3719d93c2005e88fd20a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AaY1dcOE9oblc54b0HnkpMVUIc1tiblE4sYd0XT6K/Y=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 01a635\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 fa9a c9ef cc9f cc5f | 60 d18a (0) d125 (0) d23c (0) dd92 (0)\n001 4 6450 4d75 5008 55fd | 38 4a37 (0) 4a3c (0) 4bc8 (0) 4efa (0)\n002 7 2dd4 22bb 2354 216e | 17 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n003 4 184e 1385 127c 1740 | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0a21 0807 0f31 0e34 | 4 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n005 1 0639 | 1 0639 (0)\n============ DEPTH: 6 ==========================================\n006 2 034d 03eb | 2 034d (0) 03eb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","private_key":"cc2f52f2da8baa58e999a96ec31dc946b081f0fc546742bfe885a4d65048f0ba","name":"node_01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","services":["streamer"],"enable_msg_events":true,"port":32789},"up":true}},{"node":{"info":{"id":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","name":"node_acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","enode":"enode://2051ad3d9ecac3a9242bc33d92f20eb0265d19c75f91c5541715e4125dbc793b8cbbfaae8f549e0526d334b28142f61dd82fef168e2078e10046d42de98a8d84@127.0.0.1:0","enr":"0xf88fb840633de8fb5d405d72f5575e854e513bca5fa24ec6fb1e75838c27118b118fc3334af4ce9f07c4717bcd139c61925a6ad329754aad8fc5a3a441bbbe120d6386270183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022051ad3d9ecac3a9242bc33d92f20eb0265d19c75f91c5541715e4125dbc793b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rPiI7XgfU1hJPi5QSGkazDnqwyQMqekJO7QFKx9iQyU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: acf888\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 73d0 68a6 2471 0f31 | 68 4a37 (0) 4a3c (0) 4bc8 (0) 4efa (0)\n001 6 ee2b f33c d9d3 c2f9 | 31 d23c (0) d125 (0) d18a (0) dd92 (0)\n002 4 8012 8330 836e 8d3e | 9 957e (0) 9472 (0) 8284 (0) 8330 (0)\n003 7 b869 b9d9 bd48 bd96 | 14 b355 (0) b245 (0) b60e (0) b4e2 (0)\n004 1 a192 | 1 a192 (0)\n============ DEPTH: 5 ==========================================\n005 3 aba7 a9fa a861 | 3 aba7 (0) a9fa (0) a861 (0)\n006 1 aedc | 1 aedc (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","private_key":"e3da942e1ebba4519becee21a2285ae952467d7639501faab88c017ed66d238e","name":"node_acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","services":["streamer"],"enable_msg_events":true,"port":35297},"up":true}},{"node":{"info":{"id":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","name":"node_0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","enode":"enode://5c476e3ae360f530756888a27af18afcec729c3d9485832d85b55f4910e22be32fe20aff65f08973bdb22a46239654a0b9ff97c4d3dbef485d21d6fbf2d21a25@127.0.0.1:0","enr":"0xf88fb8402d28c83dbd79c5e95b11079daad1069cecc4337f35abae0ff0a87d06300a14aa33ea3dde14e4082892622446978b18063fe5621c543b4392139e8066ebf634b50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035c476e3ae360f530756888a27af18afcec729c3d9485832d85b55f4910e22be3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DzEGrf5wrvtHTEqYqVkyMHOR3iy3D70uEd0xyeaV7YM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0f3106\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 cc9f cc5f d23c d9d3 | 60 d23c (0) d125 (0) d18a (0) dd92 (0)\n001 5 459b 7bcb 6daa 6450 | 38 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n002 5 3b83 3871 2dd4 221c | 17 36d5 (0) 3775 (0) 3590 (0) 3e19 (0)\n003 3 1385 127c 1740 | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0639 01a6 034d 03eb | 4 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n============ DEPTH: 5 ==========================================\n005 2 0807 0a21 | 2 0a21 (0) 0807 (0)\n006 0 | 0\n007 1 0e34 | 1 0e34 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","private_key":"6241837c865bfdb4b5200d2c76fbd45a87b9de82bb790d1ac679ceb517449a82","name":"node_0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","services":["streamer"],"enable_msg_events":true,"port":37821},"up":true}},{"node":{"info":{"id":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","name":"node_62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","enode":"enode://6a42ebbfda57a4727b4f686c785b5030992d3a2ecba2aa780527153ed432dc4a779c1a0c496e6503ec67f7063c21eaf924c996c37a2eb1dd29b86afddc735518@127.0.0.1:0","enr":"0xf88fb840844c5f5293365e47b6ea31282d2a2bcab345eb98290e20d878c868cf51faef74771a2271eef6d5e86d681144a1b449acbea967e03cc390b2d2472e714054391a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a42ebbfda57a4727b4f686c785b5030992d3a2ecba2aa780527153ed432dc4a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YvAHySqK9GbpDtCx5ecalVrSc+x5OUjd/AOXfxMe0tE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 62f007\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ee2b c0ad cc9f 836e | 60 d23c (0) d18a (0) d125 (0) dd92 (0)\n001 8 2471 2dd4 3e19 3b83 | 30 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n002 4 4775 5a8b 55fd 5008 | 20 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n003 5 75e2 77ee 72a7 72a5 | 9 7a68 (0) 7bee (0) 7bcb (0) 72a5 (0)\n004 3 6daa 68a6 6975 | 3 6daa (0) 6975 (0) 68a6 (0)\n============ DEPTH: 5 ==========================================\n005 4 6450 641a 64e6 672a | 4 672a (0) 64e6 (0) 6450 (0) 641a (0)\n006 0 | 0\n007 1 6379 | 1 6379 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","private_key":"ebf64acc962af28b6b8ed56078a7ae4726b851e322cebb1c852e24267f1c4a1d","name":"node_62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","services":["streamer"],"enable_msg_events":true,"port":43977},"up":true}},{"node":{"info":{"id":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","name":"node_b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","enode":"enode://d97b0fcc83cc71942a961140d70fbed0f9819f50795a64dce5d018ea28bcc04486d39682cb07a8f2084f401a987298d2a5385a1068133929a838255afd71df1b@127.0.0.1:0","enr":"0xf88fb84000536ff0e44a6e9ea1b978d39a2b2b4c28b4c30d63cc253d1996f9c000c0cee949b1904a5eee67b25704fbb2ba12b15f995cc6b9ac5717d610cc101ed5e3e75a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d97b0fcc83cc71942a961140d70fbed0f9819f50795a64dce5d018ea28bcc044","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"udkG5Aaw/GB4wiu8FzBD3x91gQYbT2zNdpvFaNlLQzk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b9d906\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 22bb 55fd 73d0 68a6 | 68 3775 (0) 36d5 (0) 3590 (0) 3e19 (0)\n001 4 c52a d9d3 ee2b eceb | 31 d23c (0) d125 (0) d18a (0) dd92 (0)\n002 4 8012 8330 836e 8d3e | 9 957e (0) 9472 (0) 8012 (0) 8284 (0)\n003 5 a861 a9fa aba7 acf8 | 6 a192 (0) aba7 (0) a9fa (0) a861 (0)\n004 5 b355 b245 b4e2 b5fc | 5 b355 (0) b245 (0) b4e2 (0) b5fc (0)\n============ DEPTH: 5 ==========================================\n005 7 be0f bd48 bddb bde9 | 7 be0f (0) bc29 (0) bc71 (0) bd48 (0)\n006 0 | 0\n007 1 b869 | 1 b869 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","private_key":"908ebb48b37c8f9239e22db00fb7161ba4a14b3f5857a1142bcaf9d46586ad23","name":"node_b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","services":["streamer"],"enable_msg_events":true,"port":34371},"up":true}},{"node":{"info":{"id":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","name":"node_eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","enode":"enode://3419c9288c2eff070d8db3ecdf0c5675a6978ff0ca5e459886f451fb7c6a1c79f40f74557de8e513ea6e3db67a52a99933260c4838d0c88e1329e8c23f8e367b@127.0.0.1:0","enr":"0xf88fb840d19d680dca990e3894d8e63f0c7e053bb4beccc2b28b26e2156c3de7cfd0293637e634f6f398e2c52a3767d0f82b356f5387e7cbd65eb778d17d253d500eb9f00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033419c9288c2eff070d8db3ecdf0c5675a6978ff0ca5e459886f451fb7c6a1c79","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7Ot9xTJZbotoB0ET25YF49FcsV4ugPdfGmbZWhIhx9w=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eceb7d\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 772a 4589 58a9 216e | 68 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n001 7 8d3e 8012 836e aba7 | 29 9472 (0) 957e (0) 8284 (0) 8330 (0)\n002 7 deec d9d3 cc9f cc5f | 14 d23c (0) d18a (0) d125 (0) dd92 (0)\n003 6 f33c f177 f005 fa9a | 9 f4a0 (0) f611 (0) f177 (0) f005 (0)\n004 1 e06f | 1 e06f (0)\n005 2 ea3d eb01 | 2 ea3d (0) eb01 (0)\n006 2 efd6 ee2b | 2 efd6 (0) ee2b (0)\n============ DEPTH: 7 ==========================================\n007 2 ed2e ed12 | 2 ed2e (0) ed12 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","private_key":"ebb9302277d87e1d7ead59e5bcd7f4c125c61b0d09ede9e8a3a87f788b8cb3ab","name":"node_eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","services":["streamer"],"enable_msg_events":true,"port":39661},"up":true}},{"node":{"info":{"id":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","name":"node_c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","enode":"enode://3e0ee81dad3d6e6b7e146766e689ca44b20c076cd0dac90a0b937c80ffe51e87a731bb789fe07f1e3781e5aa25ea70150eb3b053fe0b179e7f7d94fbc180ed2a@127.0.0.1:0","enr":"0xf88fb84019f7283cf95d09b72f63e06b3411e0b049c15d2b86dfd18369f70d4ee944372e5c12e658b704f83f4482400458b31a516d5604fa0469210d467fe77d8e64f7dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023e0ee81dad3d6e6b7e146766e689ca44b20c076cd0dac90a0b937c80ffe51e87","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wvm0q+2caoOf5MA6gL05b9GHqHhLpHqDaH06VLfi7d8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c2f9b4\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0639 03eb 1740 772a | 68 1929 (0) 184e (0) 127c (0) 1385 (0)\n001 6 acf8 aba7 a861 8330 | 29 957e (0) 9472 (0) 8284 (0) 836e (0)\n002 4 f33c f4a0 ea3d eceb | 17 f611 (0) f4a0 (0) f005 (0) f177 (0)\n003 4 d23c d9d3 dd92 deec | 6 d18a (0) d125 (0) d23c (0) dd92 (0)\n004 4 cc5f cc9f cabf c9ef | 5 ce01 (0) cc5f (0) cc9f (0) cabf (0)\n============ DEPTH: 5 ==========================================\n005 1 c52a | 1 c52a (0)\n006 1 c0ad | 1 c0ad (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","private_key":"f980e9ba4f79f9f79e3659e3ba6dd1900868076a78a0cb0390b5c13fdfc2e105","name":"node_c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","services":["streamer"],"enable_msg_events":true,"port":37679},"up":true}},{"node":{"info":{"id":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","name":"node_c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","enode":"enode://b88aef73e2d38fb6fd1c0be8112453bc96dac9df272e9366494bb266ab6591c01482a93613d919a26bf6a4f62920343fe26b4dd5b8f13c4642fccd588d1b6407@127.0.0.1:0","enr":"0xf88fb8403c2ce4e2ffb11a365ec4903ac72a546b354de5dceec18acb0ce931dfdf593c9364716fab2b08ab7d23681b95c4ea160944780a2fb5eda9a5186c40196ed6fd350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b88aef73e2d38fb6fd1c0be8112453bc96dac9df272e9366494bb266ab6591c0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ye9Wr+0tQNs5atOdb19fOPQFi2sNHgK3HWqpLb6vffc=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c9ef56\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 772a 72a7 4cc2 58a9 | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 2 b60e acf8 | 29 b869 (0) b9d9 (0) be0f (0) bc71 (0)\n002 5 eb01 efd6 eceb f33c | 17 e06f (0) ee2b (0) efd6 (0) ed2e (0)\n003 2 deec d9d3 | 6 d23c (0) d125 (0) d18a (0) dd92 (0)\n004 3 c52a c0ad c2f9 | 3 c52a (0) c0ad (0) c2f9 (0)\n============ DEPTH: 5 ==========================================\n005 3 ce01 cc9f cc5f | 3 ce01 (0) cc5f (0) cc9f (0)\n006 1 cabf | 1 cabf (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","private_key":"e39438d65893f9aa29c4f0b62c56230930d90dcaab3cbb07ea3c19d0cad5136e","name":"node_c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","services":["streamer"],"enable_msg_events":true,"port":36083},"up":true}},{"node":{"info":{"id":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","name":"node_fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","enode":"enode://d27fa62643cd7eea1b635af3b3ce578baf185fffc47830a4c13ec296f90c46d2663dc1789046b5a79d796c57546e1ef68a15dbc440d08cc6644a8fa0ae887549@127.0.0.1:0","enr":"0xf88fb840f341ded7be4fe1c85a832c0eebf0214215e6fa10536fb974fad93566458010b2239adb66b6817d8493b1ec12ac407bb97cb2b1fbf6c36bb8809e809809df05c10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d27fa62643cd7eea1b635af3b3ce578baf185fffc47830a4c13ec296f90c46d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+pqAnwFgl9lJ+hRjocjwiHHH045gt99tPiirBMzToUM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fa9a80\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 0a21 01a6 03eb 034d | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 5 836e be0f b60e aba7 | 29 be0f (0) bc71 (0) bc29 (0) bde9 (0)\n002 4 deec d9d3 c52a c9ef | 14 d23c (0) d125 (0) d18a (0) dd92 (0)\n003 5 eceb ed2e efd6 ea3d | 8 e06f (0) ee2b (0) efd6 (0) ed12 (0)\n004 4 f4a0 f611 f177 f33c | 6 f611 (0) f4a0 (0) f005 (0) f177 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 fa65 | 1 fa65 (0)\n009 1 fac8 | 1 fac8 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","private_key":"d7298e7ba76d8700d47fe74a50ac92478020ce786a9d1c343e118f94dd564864","name":"node_fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","services":["streamer"],"enable_msg_events":true,"port":41357},"up":true}},{"node":{"info":{"id":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","name":"node_55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","enode":"enode://3eae4ff354105cae615e8ed7499a263aab368017815886ccf3875219dfb6ae72174bc5241ef3c91c0c7baa54a3e833da1c27f41b8861dbb86b34351780ce8b18@127.0.0.1:0","enr":"0xf88fb8403c706e742e24e2e3e8bfcc48604544f9b4593b9fac94f97664fe76d2d9a02a183b24baf1ebfac2e908c29886fb61952983d054555cc677f2b4795e38cf5768dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023eae4ff354105cae615e8ed7499a263aab368017815886ccf3875219dfb6ae72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Vf2tAzA6dGkgdzIXxWijfSAEhp/zQJb75FGX9x66K2M=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 55fdad\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b5fc b245 bd48 b9d9 | 60 be0f (0) bc71 (0) bc29 (0) bde9 (0)\n001 6 1740 03eb 01a6 3b83 | 30 184e (0) 1929 (0) 127c (0) 1385 (0)\n002 4 6daa 62f0 73d0 77ee | 18 672a (0) 64e6 (0) 6450 (0) 641a (0)\n003 4 4c21 4cc2 4589 459b | 11 4bc8 (0) 4a3c (0) 4a37 (0) 4efa (0)\n004 5 5be6 5a8b 58a9 5c62 | 5 58a9 (0) 5be6 (0) 5a8b (0) 5c62 (0)\n============ DEPTH: 5 ==========================================\n005 3 5008 51c2 52b4 | 3 52b4 (0) 51c2 (0) 5008 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","private_key":"9ffae4eb3efdf717dce58938868a5816422239bac33c7d104cae4e18b73feaa8","name":"node_55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","services":["streamer"],"enable_msg_events":true,"port":37795},"up":true}},{"node":{"info":{"id":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","name":"node_22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","enode":"enode://0fcdb40b9980223ca221f90fca68efae8db086998c519d8725f451e9e351346836103fb5aa037e39188b71cb4b3f0625b313e7aee625e297edb036c44566f728@127.0.0.1:0","enr":"0xf88fb840d0cc3284ff4f87d20c3a83d7047fd8ab950c8bda00565839b26d7c9d24e7abf205c14a5d4714dbea74bf7a6de1731a8f80b41519fdf01063bbf6ed3322b874be0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020fcdb40b9980223ca221f90fca68efae8db086998c519d8725f451e9e3513468","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IruzI2peChlHocRzWqrPkSIXN4mgKgbnZTEDvcri+CM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 22bbb3\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b5fc b60e b9d9 | 60 be0f (0) bc71 (0) bc29 (0) bde9 (0)\n001 2 77ee 55fd | 38 6975 (0) 68a6 (0) 6daa (0) 672a (0)\n002 8 1385 1740 0639 01a6 | 13 1929 (0) 184e (0) 127c (0) 1385 (0)\n003 2 3871 3b83 | 6 36d5 (0) 3775 (0) 3590 (0) 3e19 (0)\n004 3 2803 2d53 2dd4 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27db 27b5 | 3 2471 (0) 27b5 (0) 27db (0)\n006 2 216e 21dc | 2 21dc (0) 216e (0)\n============ DEPTH: 7 ==========================================\n007 1 2354 | 1 2354 (0)\n008 1 221c | 1 221c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","private_key":"cce6899e27a53e544f7f5b8aad86ab94d88cb44d56c3990527df6186741b5448","name":"node_22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","services":["streamer"],"enable_msg_events":true,"port":46859},"up":true}},{"node":{"info":{"id":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","name":"node_77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","enode":"enode://30c18cf67d3de082cf0bf79b9f1722fa4816434fd18609381488df512c8f3759e7c9bbccea6cd0e592c81ac1169d277e6b45beb59dec2f4678ba549b19370751@127.0.0.1:0","enr":"0xf88fb840054a553fdf6785422e9ba595a831b259bb7cc62c4c3a41861f937338904e08c1117e88ce97c436f3ea15af9cd139711452a589831e746d9b174c404df5b9b6130183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10330c18cf67d3de082cf0bf79b9f1722fa4816434fd18609381488df512c8f3759","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d+7crAyEex1pPd/wfFhor7HCAIsty0igKZFDqxRhGWk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 77eedc\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 eb01 f33c 8d3e | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 7 0807 0639 034d 03eb | 30 1929 (0) 184e (0) 127c (0) 1385 (0)\n002 3 459b 5a8b 55fd | 20 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n003 5 6450 641a 62f0 6975 | 9 6379 (0) 62f0 (0) 672a (0) 64e6 (0)\n004 3 7bcb 7bee 7a68 | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 72a5 72a7 73d0 | 3 72a5 (0) 72a7 (0) 73d0 (0)\n============ DEPTH: 6 ==========================================\n006 1 75e2 | 1 75e2 (0)\n007 0 | 0\n008 1 772a | 1 772a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","private_key":"e1e6b3e6225cad6b1df7fc028cf8a745346a7c26d5dea6825108ae2f483d8c04","name":"node_77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","services":["streamer"],"enable_msg_events":true,"port":44643},"up":true}},{"node":{"info":{"id":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","name":"node_8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","enode":"enode://ba544e97e0b245ef40d6515136e3b0b9af76a2d9f7eadfb8fde90b979079abcf9c60d1c43f5ab07731dc0d72a59a501b9cb7c951d9f5da576f16e19c5b1fdfbc@127.0.0.1:0","enr":"0xf88fb8400a1d7ba92c3ca031f366592c2d92fdb57881f30a2584f776614e94451218ba5a10ece049d25fcc363f9f3f26915edc173410d3a2393d5b83e18893e89e6a074f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ba544e97e0b245ef40d6515136e3b0b9af76a2d9f7eadfb8fde90b979079abcf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jT4NnGky00IgJDlJmOlDMJtnnWZzlNDrYi8OII5/zwo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8d3e0d\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0f31 0807 0a21 127c | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 4 eceb f33c c2f9 c52a | 31 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n002 12 a9fa a861 aba7 acf8 | 20 b869 (0) b9d9 (0) be0f (0) bc29 (0)\n003 2 957e 9472 | 2 957e (0) 9472 (0)\n004 3 8012 8330 836e | 4 8012 (0) 8284 (0) 836e (0) 8330 (0)\n============ DEPTH: 5 ==========================================\n005 1 8b35 | 1 8b35 (0)\n006 1 8fb8 | 1 8fb8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","private_key":"f2b2db3ab3bb25ad92063630dd8898f4437d0af687073abd25e341b1649e41cf","name":"node_8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","services":["streamer"],"enable_msg_events":true,"port":35799},"up":true}},{"node":{"info":{"id":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","name":"node_c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","enode":"enode://d0cbe2c3073b8e2da7f2d750d97719714b354e4a823141560a5c7e6bcc460dfe7a1fbab94d94d8bf48a64cb16c59489ef1d6b9a47d6f9e7e96bce190cc7f8d4d@127.0.0.1:0","enr":"0xf88fb8403bf91f39e315b53cdc4b2dbbf4b41e95542ff5660d7a2916fe2ee858ecc2c5723462999e9c22d592f05fe322d42caddf25eee3e855d5d9599b6f438f7627589c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d0cbe2c3073b8e2da7f2d750d97719714b354e4a823141560a5c7e6bcc460dfe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xSpo2DiKIQE+Tuzvnqhm2x9esWu+DsyCuL+v0z5OAU8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c52a68\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 7bcb 72a7 641a 58a9 | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 3 b9d9 b5fc 8d3e | 29 b869 (0) b9d9 (0) bc71 (0) bc29 (0)\n002 6 ea3d eb01 eceb fa9a | 17 e06f (0) ea3d (0) eb01 (0) ee2b (0)\n003 4 d18a d125 deec d9d3 | 6 d23c (0) d125 (0) d18a (0) d9d3 (0)\n004 5 ce01 cc5f cc9f cabf | 5 ce01 (0) cc5f (0) cc9f (0) cabf (0)\n============ DEPTH: 5 ==========================================\n005 2 c0ad c2f9 | 2 c0ad (0) c2f9 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","private_key":"f49dc248179df01ec6c8b426228f64aaa30b16ea7f8e9e9bf4f933d061d58bb6","name":"node_c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","services":["streamer"],"enable_msg_events":true,"port":42373},"up":true}},{"node":{"info":{"id":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","name":"node_3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","enode":"enode://8d83c109e42a329f480a3a51a9dde5516d6731233ddd28de467ff3ef255a8e5342765c79c446fdb28e14ead4c4c590b2ba5ba740b3f96be1eee5bbc837ee5963@127.0.0.1:0","enr":"0xf88fb84031a328c351d984beccbc346fa806f81c52b5e33a6ca23e3c378b6ce2cf71e60f7936466c5c8ef78d0cbbef2c09fa6b3fc77fafb99cdb8bcbf90a26a50dc0d0580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038d83c109e42a329f480a3a51a9dde5516d6731233ddd28de467ff3ef255a8e53","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OHFJLIxizXTL5lqZNmnkl4zGQYeaUiPda55ofwUKHEA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 387149\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eceb c52a 8b35 aedc | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 8 6daa 62f0 7bcb 772a | 38 4bc8 (0) 4a37 (0) 4a3c (0) 4efa (0)\n002 8 1929 1385 1740 034d | 13 184e (0) 1929 (0) 127c (0) 1385 (0)\n003 8 2dd4 2471 27db 21dc | 11 2803 (0) 2d53 (0) 2dd4 (0) 27b5 (0)\n004 3 36d5 3775 3590 | 3 36d5 (0) 3775 (0) 3590 (0)\n============ DEPTH: 5 ==========================================\n005 1 3e19 | 1 3e19 (0)\n006 1 3b83 | 1 3b83 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","private_key":"834f76d47474f2c89e8e0405186442df99beaa572593e766307382a90766efae","name":"node_3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","services":["streamer"],"enable_msg_events":true,"port":44349},"up":true}},{"node":{"info":{"id":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","name":"node_aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","enode":"enode://de0a47f289a5e5d540db8adc0ef05baf590d55abad62f68a25d5262181ce611b0a3aa703cdf027fc666dd62e66ce6be0ebc78179e341b06fa407ffee34176330@127.0.0.1:0","enr":"0xf88fb840870ed3339b049cab40a19dacd5afe7e4f8139c5f9da6053b795be3d6ac9447070011c7efbcdf83ab755f08ffcd03df0cabffa76734712b57822864e8514bce850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102de0a47f289a5e5d540db8adc0ef05baf590d55abad62f68a25d5262181ce611b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rtybR4IE7/3LrRqJIzPxXAYfvRQjs3D4pQ+SmyovaVI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aedc9b\npopulation: 21 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 73d0 216e 3871 | 68 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n001 3 deec f33c fa9a | 31 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n002 4 9472 8284 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 836e (0)\n003 6 b60e b5fc b9d9 bc29 | 14 b869 (0) b9d9 (0) bc71 (0) bc29 (0)\n004 1 a192 | 1 a192 (0)\n============ DEPTH: 5 ==========================================\n005 3 a9fa a861 aba7 | 3 a9fa (0) a861 (0) aba7 (0)\n006 1 acf8 | 1 acf8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","private_key":"d0b21651e7458eb9235717900d45d5d655a60530764fcc4ca99ade40d39e4f0c","name":"node_aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","services":["streamer"],"enable_msg_events":true,"port":34417},"up":true}},{"node":{"info":{"id":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","name":"node_216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","enode":"enode://683e4c5a8d928aee37c2f41441e3d7550c42d486625db97883eb2046e9bafc9713f50ee269f4801f3a3c6220af6b097c4100ae92a1970333d9253f86d23c8a0c@127.0.0.1:0","enr":"0xf88fb8401dfe814edc9bad85208abd4a89df104f3d8a58386eb8a593a97d41fa5b72ae395106fc13f4897da7efe6c140ffef9097cd2f468a4920b060d8ea5bc13a46c2940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102683e4c5a8d928aee37c2f41441e3d7550c42d486625db97883eb2046e9bafc97","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IW4DcBEeLgOSe4A654j5lH3o4kHUHb9qcJg88OzWivE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 216e03\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eceb aedc | 60 d23c (0) d18a (0) d125 (0) d9d3 (0)\n001 8 4d75 4c21 4efa 4bc8 | 38 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n002 4 1929 1385 01a6 0639 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 5 3590 36d5 3775 3871 | 6 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n004 3 2803 2d53 2dd4 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27b5 27db | 3 2471 (0) 27b5 (0) 27db (0)\n============ DEPTH: 6 ==========================================\n006 3 2354 221c 22bb | 3 2354 (0) 22bb (0) 221c (0)\n007 0 | 0\n008 1 21dc | 1 21dc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","private_key":"03956bb84d1d10be6b5626b2c0175cefa443ca6cafbff149baba36309c2be8fd","name":"node_216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","services":["streamer"],"enable_msg_events":true,"port":44971},"up":true}},{"node":{"info":{"id":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","name":"node_73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","enode":"enode://9ac8ba21114f8c40f21f83d7747cd65cc99c986ab59bb477956d068c8cd04001712f8a843e0101b065abbcb2c3b2bd5472dc79345af64d86af2442b35eb0fb68@127.0.0.1:0","enr":"0xf88fb8405197213d021e7a00219b2701909e28eea2507aacb71f2ac2ead5dca945e66d7d1ba4dfa641f44981ca3e8b71b479abb37209113213d5e81f5fb709dead3663300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029ac8ba21114f8c40f21f83d7747cd65cc99c986ab59bb477956d068c8cd04001","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c9DR1KK3JQ9R5XwTzEi8ayBoIyDOEu6OV2Wv7vfZ3kI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 73d0d1\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 b60e b5fc be0f bd48 | 60 957e (0) 9472 (0) 8012 (0) 8330 (0)\n001 2 1740 216e | 30 1929 (0) 184e (0) 1740 (0) 127c (0)\n002 7 4a37 4cc2 459b 5cc1 | 20 4bc8 (0) 4a3c (0) 4a37 (0) 4efa (0)\n003 4 6450 6379 62f0 6daa | 9 672a (0) 64e6 (0) 6450 (0) 641a (0)\n004 3 7bee 7bcb 7a68 | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 75e2 772a 77ee | 3 75e2 (0) 77ee (0) 772a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 72a5 72a7 | 2 72a5 (0) 72a7 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","private_key":"5c8a42c979ee0b2447144c7dd26b2c6e8a98d27f055aa74c3e8e5559e2cb46bf","name":"node_73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","services":["streamer"],"enable_msg_events":true,"port":39577},"up":true}},{"node":{"info":{"id":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","name":"node_f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","enode":"enode://bb701e37ec5c4eb7faf97cc3aeb366de572c8d5d69e00eb267fecf7d1057eae9b583d3c64a9c0cd2374c0386113db63a61c256ab2b7cf358a6d90a7e9794260d@127.0.0.1:0","enr":"0xf88fb8406c2273c5e5619bccbf0c95225591124b18297b1ae02303095104b37745795d1b4b1d98f175c9198c719d3e2039226b02017e0d5a579e852f53ab0abcbb6a63c30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bb701e37ec5c4eb7faf97cc3aeb366de572c8d5d69e00eb267fecf7d1057eae9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8zwHqBiGOjWDWJiexxUEq608oKfIG1Sq1ZB1p2b61QE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f33c07\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 034d 27db 221c 2dd4 | 68 184e (0) 1929 (0) 1740 (0) 127c (0)\n001 8 9472 8d3e b245 be0f | 29 957e (0) 9472 (0) 8012 (0) 8284 (0)\n002 6 deec d9d3 c9ef cc9f | 14 d23c (0) d18a (0) d125 (0) d9d3 (0)\n003 6 eceb ed2e ed12 ee2b | 8 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n004 3 fa65 fac8 fa9a | 3 fa65 (0) fac8 (0) fa9a (0)\n005 2 f4a0 f611 | 2 f4a0 (0) f611 (0)\n============ DEPTH: 6 ==========================================\n006 2 f005 f177 | 2 f005 (0) f177 (0)\n007 0 | 0\n008 1 f3d5 | 1 f3d5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","private_key":"cc252064f7892875bcbb546a3d781327da4ab0042adaa0dd77dda609e9dbeacc","name":"node_f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","services":["streamer"],"enable_msg_events":true,"port":40171},"up":true}},{"node":{"info":{"id":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","name":"node_3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","enode":"enode://0009f6f563c6452d012e984f5cbe5de59f3838507fa83b32de8e12fc72d7abc3722c4b2b439eb90ccb5268e246b24cd30b2f317e7d1c855c25ef4d429d5b867b@127.0.0.1:0","enr":"0xf88fb8400938dcfa0fa11e741c028a9b8cbcb9e6b12b58464a8c5d0b8581f6103d56571352e10574431842737cf1f8e857b861b51a7b4094d046eac4cc42a317b5fbcd260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030009f6f563c6452d012e984f5cbe5de59f3838507fa83b32de8e12fc72d7abc3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O4MMKuVGPKLyJgF2t3uN2iMEgleqeAJVxpzxu7xvtkw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b830c\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b60e f33c | 60 957e (0) 9472 (0) 8330 (0) 836e (0)\n001 7 7bcb 6daa 62f0 4589 | 38 52b4 (0) 5008 (0) 51c2 (0) 55fd (0)\n002 6 0f31 0807 034d 01a6 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 8 2d53 2dd4 27db 21dc | 11 2803 (0) 2d53 (0) 2dd4 (0) 2471 (0)\n004 3 36d5 3775 3590 | 3 36d5 (0) 3775 (0) 3590 (0)\n============ DEPTH: 5 ==========================================\n005 1 3e19 | 1 3e19 (0)\n006 1 3871 | 1 3871 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","private_key":"a26abbb5971ae2f14bf7f9cf3604375ed01076a0a5f87bdb169a057aba393510","name":"node_3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","services":["streamer"],"enable_msg_events":true,"port":44047},"up":true}},{"node":{"info":{"id":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","name":"node_b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","enode":"enode://8056da3baf80eb4e505b24fa85d6983cd0c08e57ff29de4fcd7cc5265957b4b951f2c346254e6476b70b57f3d47a2acd98577851778d4f96c6cf16f3cbcef6bd@127.0.0.1:0","enr":"0xf88fb840dc084998ced183bd31314071c4467df4b73013e165b0d232050ea6a34da27200541f9558182b77822222c499c6e0dac4fce02d7e39368547197e7f396dbcc66d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038056da3baf80eb4e505b24fa85d6983cd0c08e57ff29de4fcd7cc5265957b4b9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tg53xA3cnceKStNGrdN+YPEPKZneg2YV21NSRIfR7ek=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b60e77\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 73d0 6daa 22bb 3b83 | 68 52b4 (0) 5008 (0) 51c2 (0) 55fd (0)\n001 3 fa9a c9ef deec | 31 d23c (0) d125 (0) d18a (0) d9d3 (0)\n002 3 9472 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 8330 (0)\n003 5 acf8 aedc a9fa a861 | 6 a192 (0) acf8 (0) aedc (0) a9fa (0)\n004 4 b9d9 bd96 bd48 be0f | 9 b869 (0) b9d9 (0) bc29 (0) bc71 (0)\n005 2 b355 b245 | 2 b355 (0) b245 (0)\n============ DEPTH: 6 ==========================================\n006 2 b4e2 b5fc | 2 b4e2 (0) b5fc (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","private_key":"a9b81b86acde80334419f584fa1f17b478272a646091fd3c7250f8b10ba99c10","name":"node_b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","services":["streamer"],"enable_msg_events":true,"port":36265},"up":true}},{"node":{"info":{"id":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","name":"node_b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","enode":"enode://ad94d5da30a8e6fa7eed9bdffb921e1092d69a95a807d03810dc03bc57ead17b20c03d139f43048113b82ef53df5e92169655c100e4f408de936364aa731dda4@127.0.0.1:0","enr":"0xf88fb840ee7e922aec199035d2d62046ea3b1a19143ec54359003e49b68d8cbd84b539f27d0e7caf904f7f220035c6210d38e15b618abecbfb9c4db3d503b741aa37f6dc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ad94d5da30a8e6fa7eed9bdffb921e1092d69a95a807d03810dc03bc57ead17b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tfxD6MDfMnnWoSzYsDASy40iBSCDJAGMeucldFqZovM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5fc43\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 55fd 73d0 6450 22bb | 68 52b4 (0) 51c2 (0) 5008 (0) 55fd (0)\n001 2 c52a deec | 31 d23c (0) d18a (0) d125 (0) d9d3 (0)\n002 3 9472 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 8330 (0)\n003 3 aedc acf8 aba7 | 6 a192 (0) acf8 (0) aedc (0) a9fa (0)\n004 7 b869 b9d9 bc29 bd96 | 9 b869 (0) b9d9 (0) bc71 (0) bc29 (0)\n005 2 b355 b245 | 2 b245 (0) b355 (0)\n============ DEPTH: 6 ==========================================\n006 1 b60e | 1 b60e (0)\n007 1 b4e2 | 1 b4e2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","private_key":"0134c954441986806c11920e8f351540b3c6bdd309245a07f647cc4e169a81da","name":"node_b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","services":["streamer"],"enable_msg_events":true,"port":38321},"up":true}},{"node":{"info":{"id":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","name":"node_0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","enode":"enode://2d6b0e5f0d91f9894a0dabb941a7d6dc48de6b6554cfb6d7a8a9cec18c826ee0e655dae74f3e10a713ab5f85c916b579dddf8520a9921fab3f12b73a87e6f701@127.0.0.1:0","enr":"0xf88fb840dfa210d668f3a2c36acd290f3d30342b0e7d83f74443a6c6a50ea14f016dc5ec5ecf5395805d6322a9ff4fe28ee4f0d3b5cca2fc3be0fe8ac43f39650231ef750183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032d6b0e5f0d91f9894a0dabb941a7d6dc48de6b6554cfb6d7a8a9cec18c826ee0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BjnwEINPW8SXeY8tJ1u8YL+81TyD44mGtyYDEMYAFCA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0639f0\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 fa9a c2f9 c9ef 8b35 | 60 cc9f (0) cc5f (0) ce01 (0) cabf (0)\n001 7 5be6 6daa 6450 77ee | 38 6975 (0) 68a6 (0) 6daa (0) 62f0 (0)\n002 8 3775 3590 2d53 2dd4 | 17 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n003 4 184e 1929 1740 1385 | 5 184e (0) 1929 (0) 1740 (0) 127c (0)\n004 3 0f31 0807 0a21 | 4 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n============ DEPTH: 5 ==========================================\n005 3 01a6 03eb 034d | 3 01a6 (0) 03eb (0) 034d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","private_key":"77308f10c71498c40a49e4aeb7c93c863895a490407505b02a488c452abf01e9","name":"node_0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","services":["streamer"],"enable_msg_events":true,"port":38359},"up":true}},{"node":{"info":{"id":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","name":"node_221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","enode":"enode://4c0f14e6659005f725d17c49e95e9bba43b97f7a4c2cec6f8ae665dca6f9113e7a8b8f561014b4b2f850b5f135e0f0189d7efb4e74795d3dee5848cf6d07e6aa@127.0.0.1:0","enr":"0xf88fb840aa25c219ac37cc27c5582211fa9de0891c9aab80d7e185863532cc15a1c8eda84507ccbc3f09570329c6d2c0eacb3910cf2c29d9299eef9ce1a8ceffbeb4b0880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c0f14e6659005f725d17c49e95e9bba43b97f7a4c2cec6f8ae665dca6f9113e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IhzY6gom8NP4H3gvHeOQKCQV7NnPQCJLSUWgCJeJW04=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 221cd8\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c52a f33c | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 3 5cc1 7a68 772a | 38 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n002 5 1385 1740 1929 0f31 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 4 3590 3775 3871 3b83 | 6 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n004 3 2803 2d53 2dd4 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27b5 27db | 3 2471 (0) 27b5 (0) 27db (0)\n006 2 216e 21dc | 2 21dc (0) 216e (0)\n============ DEPTH: 7 ==========================================\n007 1 2354 | 1 2354 (0)\n008 1 22bb | 1 22bb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","private_key":"c103c3cd8b3ec73103ecffab8a4778ba17c4ef1c7764c4edae06bb253bb4a1c7","name":"node_221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","services":["streamer"],"enable_msg_events":true,"port":34123},"up":true}},{"node":{"info":{"id":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","name":"node_2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","enode":"enode://2185c184311e0733ef3b385df4a2aaa3999aff53d34d3eef8fd026b46623c06a22c8ed8af0ec2827ea684193eb59cf3f6983f8c15a76b59a1fd8f2ee927f7070@127.0.0.1:0","enr":"0xf88fb8407c20d1f26dca6179ace9bc2df0f2e49e8ce46a9ab6ffc3ebc4b70f5448c300b604be2f148e16830139c9afb09d266af5fee0f6826901a4fcb31a79a39a3e48f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022185c184311e0733ef3b385df4a2aaa3999aff53d34d3eef8fd026b46623c06a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LdStg+/8O6c+cvVllYPlmHJBvaVjVjIAtQxGzOAKHZs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2dd4ad\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c52a f33c | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 62f0 5cc1 4589 459b | 38 6379 (0) 62f0 (0) 672a (0) 64e6 (0)\n002 7 1385 1740 0639 01a6 | 13 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n003 5 36d5 3775 3590 3b83 | 6 36d5 (0) 3775 (0) 3590 (0) 3e19 (0)\n004 7 2471 27db 21dc 216e | 8 2471 (0) 27b5 (0) 27db (0) 21dc (0)\n============ DEPTH: 5 ==========================================\n005 1 2803 | 1 2803 (0)\n006 0 | 0\n007 0 | 0\n008 1 2d53 | 1 2d53 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","private_key":"7780b155f127c1e2df9bd24187ab68f6bcfbc96c9ef1d8e6bfb2453180d4d177","name":"node_2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","services":["streamer"],"enable_msg_events":true,"port":41059},"up":true}},{"node":{"info":{"id":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","name":"node_459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","enode":"enode://596d8f8a3f115e739480cfc90bc3ed52bd3c6db976e8b44dd13b7c598ae1592b213998fcd92d010932001f405ea0d17a35cf0ee9dbd4d27cf7f5a665cec3dc63@127.0.0.1:0","enr":"0xf88fb8409cc2805d0639562a229301ca59a539f4a081f7b38ac8f293061de8340bca1d2645d0c65b2fc1170fff5f9386d3ab9f0357bfab057f46159767025ca2d20a0cf70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103596d8f8a3f115e739480cfc90bc3ed52bd3c6db976e8b44dd13b7c598ae1592b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RZufsrf045bejPh0CmgEyOW5bKEf+itRBsFN+7q2XJU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 459b9f\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c52a f33c | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 4 03eb 0f31 3871 2dd4 | 30 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n002 8 6daa 6450 641a 7a68 | 18 6379 (0) 62f0 (0) 672a (0) 64e6 (0)\n003 3 5008 55fd 58a9 | 9 52b4 (0) 5008 (0) 51c2 (0) 55fd (0)\n004 5 4a3c 4efa 4d75 4c21 | 7 4bc8 (0) 4a37 (0) 4a3c (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 4775 4746 | 2 4775 (0) 4746 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 4589 | 1 4589 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","private_key":"a5637f6dfe5f01c6cc2f881f665ff337c05147527c551e16933839046d2f0402","name":"node_459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","services":["streamer"],"enable_msg_events":true,"port":43667},"up":true}},{"node":{"info":{"id":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","name":"node_58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","enode":"enode://a316c9e7d1d346e81a1fec594ce6e35c607b9c61382ae1d43ee823bff44691073f86d5d9c0855bc150802216453072291e4fcf13a75b9e7c24f4c050c5b8f383@127.0.0.1:0","enr":"0xf88fb840989fd084c3dc88c500954c17cbe02ddeb37aec1afd002fbec87e88f3efa1758b10901f9c502b0e252254124e32464db5744f524bf2e090d035e4cb986373579c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a316c9e7d1d346e81a1fec594ce6e35c607b9c61382ae1d43ee823bff4469107","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WKkLWIWEF6TpcmJkIe2OeLGz5axp/O3SLFioq0xhR98=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 58a90b\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 deec c9ef c52a c2f9 | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 3 1385 034d 3b83 | 30 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n002 5 73d0 6379 6450 641a | 18 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n003 3 4a37 4c21 459b | 11 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n004 3 5008 51c2 55fd | 4 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n005 2 5c62 5cc1 | 2 5c62 (0) 5cc1 (0)\n============ DEPTH: 6 ==========================================\n006 2 5a8b 5be6 | 2 5a8b (0) 5be6 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","private_key":"f76a3f3cb8f63a53ab4db362f8c406b8b64c653bfeb32a8e730eb9386f52f057","name":"node_58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","services":["streamer"],"enable_msg_events":true,"port":43195},"up":true}},{"node":{"info":{"id":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","name":"node_be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","enode":"enode://eeded07e99fa4ff2d426439e42dc4604dd4b1b48d79b02496e61ff86d21658dc4ece7ba599e544ef99d326c12c01c70509c8cfd486228c14db2d8c2b15648571@127.0.0.1:0","enr":"0xf88fb840bf0cf1c25f6277811da44fc4d073295fcffa375500de088bd154cff1aa9770737b9e677865a1873a4a10103f43db1289382f15e37cebe4e4d8cc60b013ff2a1c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eeded07e99fa4ff2d426439e42dc4604dd4b1b48d79b02496e61ff86d21658dc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vg+ytEC5HnGcIPUbZz658vZsevd7CwreMSmYzf/MUEU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be0fb2\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 3775 1740 1385 034d | 68 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n001 12 f611 f177 f33c f3d5 | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 3 9472 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 836e (0)\n003 2 aedc aba7 | 6 a192 (0) acf8 (0) aedc (0) a861 (0)\n004 3 b355 b60e b5fc | 5 b245 (0) b355 (0) b4e2 (0) b5fc (0)\n005 2 b869 b9d9 | 2 b869 (0) b9d9 (0)\n============ DEPTH: 6 ==========================================\n006 6 bc71 bc29 bd96 bde9 | 6 bc71 (0) bc29 (0) bd96 (0) bde9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","private_key":"38ca3287eddd306f53a09e7f411c72cd416a6fea9372c3be4307ffa2b66a5e84","name":"node_be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","services":["streamer"],"enable_msg_events":true,"port":33661},"up":true}},{"node":{"info":{"id":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","name":"node_deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","enode":"enode://f76349ec766de9d4431151d18ef460cbf69350f3bfa572661117e66b942e7c43605b02eb8805192c15a2c6a5fa47fefe5f4faf57cff643dffd13cfe84d80dcd2@127.0.0.1:0","enr":"0xf88fb840a8e8b269bcf4e00811769f0b731ba2d12904fea4ba28727d8c02b71eb17799531e0b15265ed663ef981c53c77bcbd0a2bb3e8607ade87aef661238ac26892bfb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f76349ec766de9d4431151d18ef460cbf69350f3bfa572661117e66b942e7c43","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3uxqi+tOXkQd1CMRNUGUw775RI6IWbTM1AFkW2khfRI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: deec6a\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 58a9 5cc1 4c21 7bcb | 68 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n001 7 9472 aedc aba7 b60e | 29 957e (0) 9472 (0) 8012 (0) 836e (0)\n002 8 eceb ed12 ed2e fa9a | 17 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n003 6 c52a c2f9 c9ef ce01 | 8 cc5f (0) cc9f (0) ce01 (0) cabf (0)\n004 3 d23c d18a d125 | 3 d23c (0) d18a (0) d125 (0)\n============ DEPTH: 5 ==========================================\n005 1 d9d3 | 1 d9d3 (0)\n006 1 dd92 | 1 dd92 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","private_key":"e937ad3db719737f604c22bd1bc3702c56cab3b5ef6aeddadad798027099af81","name":"node_deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","services":["streamer"],"enable_msg_events":true,"port":42029},"up":true}},{"node":{"info":{"id":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","name":"node_13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","enode":"enode://233f1ef8d53ba1f2f35253d6fd30975d21193041f84c41e99efa3680301dbd2dc630d0ac490193182b8f32036c6cc7fd56f8396c42f02d6797074cabfec0aa1c@127.0.0.1:0","enr":"0xf88fb8404cb34513bd8303f7d3bf75384dd785ab45af5e1ddb4087f14b97cb418a03dcac17b596bc11aec73cbf0795c77a2d1b84f895a76f54d0ee90d842fc74759bace40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102233f1ef8d53ba1f2f35253d6fd30975d21193041f84c41e99efa3680301dbd2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E4U0B9J4pF4V1LFI/Djrs1xPWO5VLuDkQBxsmMRbjj4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 138534\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 8b35 8d3e b355 be0f | 60 8012 (0) 8284 (0) 836e (0) 8330 (0)\n001 10 6450 6daa 7bcb 77ee | 38 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n002 10 3775 3590 3871 3b83 | 17 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n003 6 0f31 0a21 0807 01a6 | 8 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n004 2 184e 1929 | 2 184e (0) 1929 (0)\n============ DEPTH: 5 ==========================================\n005 1 1740 | 1 1740 (0)\n006 0 | 0\n007 1 127c | 1 127c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","private_key":"7da06589109c392355e1be112c5b857ab81263c8a0d024f4bb9a295c1e7e7835","name":"node_13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","services":["streamer"],"enable_msg_events":true,"port":46227},"up":true}},{"node":{"info":{"id":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","name":"node_aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","enode":"enode://682bf60eaccc8c0ea6b95167841aee6e412a1d544017d3a9a894ed557cf576fb38146ddd775e94eedff062a3ef8030515beeea9982f8904c148790d6ff5ca40b@127.0.0.1:0","enr":"0xf88fb840ca36c7659c737b8ebbb2cf6ae6954a5dc378e4a3ba74cdf832186b307b46ab6942e82c3c7562eb653e7dc998e912f2a78935d1573fd6f2faa4e0366888622e0e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103682bf60eaccc8c0ea6b95167841aee6e412a1d544017d3a9a894ed557cf576fb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"q6eT5jX3EWkQWtBzIlzI25FN5rcR/p8ixdlKyMuF4us=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aba793\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 73d0 772a 1385 | 68 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n001 8 ee2b eceb fa9a f611 | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 2 8d3e 9472 | 9 8012 (0) 8284 (0) 836e (0) 8330 (0)\n003 7 b5fc b60e b9d9 bc29 | 14 b245 (0) b355 (0) b4e2 (0) b5fc (0)\n004 1 a192 | 1 a192 (0)\n005 2 acf8 aedc | 2 acf8 (0) aedc (0)\n============ DEPTH: 6 ==========================================\n006 2 a861 a9fa | 2 a861 (0) a9fa (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","private_key":"2fedc92f155f2df9c7680e003208e896d4afe676f8d42a34e9c052876a8eba05","name":"node_aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","services":["streamer"],"enable_msg_events":true,"port":44069},"up":true}},{"node":{"info":{"id":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","name":"node_772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","enode":"enode://705fa39aa2e54e3cf627d29d6b986190ac5c50c3ef5702ebf41f048db0b691596ce6cf281898420112ed749a1dbeb4ad5160a62cb8cac2fc23aafc9eeeeaab54@127.0.0.1:0","enr":"0xf88fb8404f14a1ec789a7e2c007912c3209baae1e1b9bdb005a66efc25bcf1e48324aab522e9eddebd99b287bc2240719d578f848243a42d5e6ed9b0db297261eceb6fde0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102705fa39aa2e54e3cf627d29d6b986190ac5c50c3ef5702ebf41f048db0b69159","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dyp5MCUo/c5qIWyYyV4oEzMpLIHf5JCuqkp4v+sZgMg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 772a79\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 c2f9 c9ef ce01 f33c | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 3871 3590 221c 0639 | 30 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n002 8 5cc1 51c2 459b 4bc8 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 4 6daa 6379 641a 6450 | 9 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n004 3 7bee 7bcb 7a68 | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 72a7 72a5 73d0 | 3 73d0 (0) 72a5 (0) 72a7 (0)\n============ DEPTH: 6 ==========================================\n006 1 75e2 | 1 75e2 (0)\n007 0 | 0\n008 1 77ee | 1 77ee (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","private_key":"20f8e29f129c023ce09631a3c2b173e7f73cf8040aa372de1eca8d2b5d6aa3f6","name":"node_772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","services":["streamer"],"enable_msg_events":true,"port":34307},"up":true}},{"node":{"info":{"id":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","name":"node_7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","enode":"enode://3c14067242581a41318e20b5bf461a2010c6163ce865664c0846d3c020ec076876b38593cb72579d5e5d1c5eda4182195bbacda4a6cd6f75246d0dac4b348f88@127.0.0.1:0","enr":"0xf88fb84015230ae1b2f1e7e93185930792b34197809d010451d124ef701f64630aec586a16d0a8cd37cdeaeef002bef58bd34243cf3c0a97216cb08ec2e4937ed48313b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c14067242581a41318e20b5bf461a2010c6163ce865664c0846d3c020ec0768","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"emj6RLvsGHJy4tXfvW7YrzGho2WqcqpQ2wI1Dr6YyFk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7a68fa\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8284 9472 f33c deec | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 3 221c 0639 034d | 30 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n002 5 5cc1 459b 4a37 4cc2 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 4 6daa 6379 641a 6450 | 9 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n004 6 72a5 72a7 73d0 75e2 | 6 73d0 (0) 72a5 (0) 72a7 (0) 75e2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 2 7bee 7bcb | 2 7bee (0) 7bcb (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","private_key":"55bb3e30ef20d49d0cfe74562140bde2e178fe9c68c22a323aee1342c262a374","name":"node_7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","services":["streamer"],"enable_msg_events":true,"port":33619},"up":true}},{"node":{"info":{"id":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","name":"node_034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","enode":"enode://e6424d57236a8e78654448dbacf849545ea5f8d8963a1839bda9e7e2ed7b9f75235ce65da8cd8658f6907052e5ff7500aab3d5bf41e7ef55cf6a0c51d0531da1@127.0.0.1:0","enr":"0xf88fb84031fe742fa635670041f5fe96872983f924cd30e5949074833ecf42feafa3d792135e91a69af260875cb6b8e0b99148175b0570494dc64dfed550c4b594b2be780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e6424d57236a8e78654448dbacf849545ea5f8d8963a1839bda9e7e2ed7b9f75","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A03mZ3TtomuT40LJuUud6util2UMgZsUSlgyvr/msC8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 034de6\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 b355 be0f 8b35 957e | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 10 58a9 4d75 4cc2 6daa | 38 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n002 9 2803 2dd4 27db 22bb | 17 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n003 3 1385 184e 1929 | 5 184e (0) 1929 (0) 1740 (0) 127c (0)\n004 4 0807 0a21 0e34 0f31 | 4 0e34 (0) 0f31 (0) 0807 (0) 0a21 (0)\n005 1 0639 | 1 0639 (0)\n============ DEPTH: 6 ==========================================\n006 1 01a6 | 1 01a6 (0)\n007 0 | 0\n008 1 03eb | 1 03eb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","private_key":"85899df9a7c186468ac564ef2a386b2657c6d63c3f0751f128882d292dbda09a","name":"node_034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","services":["streamer"],"enable_msg_events":true,"port":37491},"up":true}},{"node":{"info":{"id":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","name":"node_72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","enode":"enode://f0232c32322d105dcc559017d690018c44958df27f400c2da47688421eb9446788c84dc8f1295f282f2af16f62dcb6cc6e25d06c58031bbe1179d859904b568a@127.0.0.1:0","enr":"0xf88fb840d8f5c3b3a865e6fb673db1e14223e95eebbf821ed0ebedb85ca36ed6d7b8e8b810af20b72f1321af49040b9636f9f653b88821f970089c882da2faf5ae94cb590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0232c32322d105dcc559017d690018c44958df27f400c2da47688421eb94467","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cqdvZo2bkjkUhg60+Fd7yYwVP23SIs02oLve8rq38Gg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 72a76f\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 d125 c52a ce01 c9ef | 60 e06f (0) ea3d (0) eb01 (0) ee2b (0)\n001 4 3e19 0a21 03eb 034d | 30 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n002 8 459b 4bc8 4a37 4cc2 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 6 6daa 62f0 6379 672a | 9 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n004 3 7a68 7bee 7bcb | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 75e2 772a 77ee | 3 75e2 (0) 77ee (0) 772a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 73d0 | 1 73d0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 1 72a5 | 1 72a5 (0)\n015 0 | 0\n========================================================================="}},"config":{"id":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","private_key":"2dbcb1f5dc3a4230a4b221acbcb0ddd1e7178bd47ef73c82eed7ffecc7740e8f","name":"node_72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","services":["streamer"],"enable_msg_events":true,"port":36137},"up":true}},{"node":{"info":{"id":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","name":"node_bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","enode":"enode://d1614db3ef30a1d4e4082531616f3fe131a586eacc407b1d4041e9714d0dc98600467eaa2d408b5686dbb3cace24919099715a04a8e829bc0a0eac80f3d8fda5@127.0.0.1:0","enr":"0xf88fb8409b8ce0903002c146be1f872e039e3a98a5226c19fa7fab111327cc0f7d31fa6f0abde0b02ff8f05e228e94511987c311a2c0a577eb3196f305e3a5ed95b97bc60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d1614db3ef30a1d4e4082531616f3fe131a586eacc407b1d4041e9714d0dc986","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vUhuHhXfTHU5sa1bVPdWbdSDakMOn301A4gfp54ljZs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bd486e\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 55fd 4c21 73d0 72a7 | 68 3e19 (0) 3871 (0) 3b83 (0) 36d5 (0)\n001 2 f177 deec | 31 e06f (0) eb01 (0) ea3d (0) ee2b (0)\n002 4 9472 8b35 8d3e 8fb8 | 9 8012 (0) 836e (0) 8330 (0) 8284 (0)\n003 5 a861 a9fa aba7 acf8 | 6 a192 (0) acf8 (0) aedc (0) a861 (0)\n004 4 b355 b60e b4e2 b5fc | 5 b355 (0) b245 (0) b4e2 (0) b5fc (0)\n005 2 b869 b9d9 | 2 b869 (0) b9d9 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc71 bc29 | 2 bc71 (0) bc29 (0)\n============ DEPTH: 8 ==========================================\n008 3 bd96 bde9 bddb | 3 bd96 (0) bde9 (0) bddb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","private_key":"7caa80d81addc9906ff055f89b4f28d67c666b90d9fd0030cf4a4a9e2372f478","name":"node_bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","services":["streamer"],"enable_msg_events":true,"port":45371},"up":true}},{"node":{"info":{"id":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","name":"node_4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","enode":"enode://6fbec307bce183850f96a0e0401fe05f26abb60c34295c692aecaaf353766314ccece95987b85ab3cf2c43c4fc8090823c86539f548ba5727d9030c99f049180@127.0.0.1:0","enr":"0xf88fb840a324b4bf2450128b22b8e99d9e7863140c8d4deab6e51d53891a5eab787249f45bbd942c8a73aa78acd0d87997764ddee5241040c712f0633281cbc5bb2dca790183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026fbec307bce183850f96a0e0401fe05f26abb60c34295c692aecaaf353766314","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TCEcEX5VXCrIMdVohhW2tMXjHx18eQazTwy828RUgrQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c211c\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 deec 8fb8 bd48 | 60 e06f (0) ea3d (0) eb01 (0) ee2b (0)\n001 3 1385 216e 21dc | 30 184e (0) 1929 (0) 1740 (0) 127c (0)\n002 3 772a 7a68 6450 | 18 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n003 6 5cc1 58a9 5be6 55fd | 9 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n004 3 4775 4746 459b | 4 4775 (0) 4746 (0) 4589 (0) 459b (0)\n005 2 4bc8 4a37 | 3 4a3c (0) 4a37 (0) 4bc8 (0)\n006 1 4efa | 1 4efa (0)\n============ DEPTH: 7 ==========================================\n007 1 4d75 | 1 4d75 (0)\n008 1 4cc2 | 1 4cc2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","private_key":"7534963388dc983ea5464538eec56a62b0acd0fc995c8549f2679755d385c2e8","name":"node_4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","services":["streamer"],"enable_msg_events":true,"port":45341},"up":true}},{"node":{"info":{"id":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","name":"node_21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","enode":"enode://88a1d0469479ab5a39001ece4f2c99ead3dc557053ca176ac22316ff7ed86ae4388683a54c38ba0f1bd78859cce8e650171fff2fa49006461c4c0d3ccff806fa@127.0.0.1:0","enr":"0xf88fb84056e42be02ea67947908fe9561498acbc10dddbec310fabfefb996e2eea72b4572e347aa61c0cab4658f9d6e382d08411d5da74a9f076c5a9f9d79e4242a9678e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10288a1d0469479ab5a39001ece4f2c99ead3dc557053ca176ac22316ff7ed86ae4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Idz7iTpUy1bSE1X8VkWDBX/FGzJQOoYn51dWYHJadic=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 21dcfb\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 deec f177 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 6daa 5cc1 4d75 4c21 | 38 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n002 4 01a6 034d 1929 1385 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 5 3871 3b83 3590 36d5 | 6 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n004 2 2dd4 2803 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27b5 27db | 3 2471 (0) 27b5 (0) 27db (0)\n============ DEPTH: 6 ==========================================\n006 3 2354 221c 22bb | 3 2354 (0) 22bb (0) 221c (0)\n007 0 | 0\n008 1 216e | 1 216e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","private_key":"f08efc99ef01728ff510e5f92b7180a1367519e8326761e78161233efa455123","name":"node_21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","services":["streamer"],"enable_msg_events":true,"port":42527},"up":true}},{"node":{"info":{"id":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","name":"node_6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","enode":"enode://9a9ce2e0b9a084ec93e5bf364d61450a6f630e3fcaf89692e6c084ef927d2c6acb1d0f5c3f0df97fd53807055774ed027dff214b337e644f766673ee959d6691@127.0.0.1:0","enr":"0xf88fb84044d9d55ee6ab6484a0a3ddabbc5227af358b46ebb1f61eb0155d882e31e9cd2010a81e6d888667b79f2121cd96793570539b6ec00410f3e171a61bef9431fb480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039a9ce2e0b9a084ec93e5bf364d61450a6f630e3fcaf89692e6c084ef927d2c6a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bar1FZmcmjSRyWP3a+gu1gBWFr97qYJHsB1qiamvHXE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6daaf5\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b60e f177 deec | 60 cabf (0) c9ef (0) cc9f (0) cc5f (0)\n001 9 0f31 0639 034d 1385 | 30 184e (0) 1929 (0) 1740 (0) 127c (0)\n002 4 459b 55fd 58a9 5cc1 | 20 4775 (0) 4746 (0) 4589 (0) 459b (0)\n003 8 7a68 7bee 7bcb 75e2 | 9 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n004 5 6379 62f0 672a 6450 | 6 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n============ DEPTH: 5 ==========================================\n005 2 6975 68a6 | 2 68a6 (0) 6975 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","private_key":"cddadd9acb99e1d405844e54f8c99b3b8971ab5210eafaba25db3fe4f8fcd91d","name":"node_6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","services":["streamer"],"enable_msg_events":true,"port":44965},"up":true}},{"node":{"info":{"id":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","name":"node_5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","enode":"enode://c734583d55ba85edc61b6e6737e43bce10a56dba57f05d4fc8bd3ade2e47a0eefabac7e83bda748a41c8b90a8a4bd965aa9da73b25b50b2ae9b57dfdd330ae7a@127.0.0.1:0","enr":"0xf88fb8403795468f0460cb1e3426dae834bdf0a6407814c00628447ad37ea9cdd7ad51535c32b9ef97d29a71a3958d034f6a01527a5b2c6230934e8f27c513f758b3d58e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c734583d55ba85edc61b6e6737e43bce10a56dba57f05d4fc8bd3ade2e47a0ee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XMHCjq/ZdY6AeigVmhp6bqMT+n6Hj95dR/zI9aXCUXI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5cc1c2\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8fb8 ce01 deec f177 | 60 c0ad (0) c2f9 (0) c52a (0) cabf (0)\n001 7 3871 3b83 27db 216e | 30 2803 (0) 2d53 (0) 2dd4 (0) 2354 (0)\n002 7 72a7 73d0 772a 7a68 | 18 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n003 4 4a37 4efa 4c21 4cc2 | 11 4775 (0) 4746 (0) 4589 (0) 459b (0)\n004 4 51c2 5008 52b4 55fd | 4 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n============ DEPTH: 5 ==========================================\n005 3 58a9 5a8b 5be6 | 3 58a9 (0) 5a8b (0) 5be6 (0)\n006 0 | 0\n007 0 | 0\n008 1 5c62 | 1 5c62 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","private_key":"e9b5e89040faaac07a9024be985c1b6a79cda66a0910b7a2ffa0a5c78b9afe61","name":"node_5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","services":["streamer"],"enable_msg_events":true,"port":45281},"up":true}},{"node":{"info":{"id":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","name":"node_4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","enode":"enode://d7ef3fd82861a99d09be17b9ed57768a386d22fbde25e097e376cb18f34b8b8e0bee1e3478fbd5fe0910f2306d0b0fa4df665e27e5a12611abc392c179d239e9@127.0.0.1:0","enr":"0xf88fb840289078a8d405c68188e3f1a163789ae0179de25d0af8223e4979d2ae17c304985bc8f4d436fab339c12b3f5ef00c5a2fda52f8622285df4f76335f4402dcf9170183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d7ef3fd82861a99d09be17b9ed57768a386d22fbde25e097e376cb18f34b8b8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TMI4aob9IQv2mcbZMXOwh5wyENRvVypiuxVMtgp9LLE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4cc238\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c9ef c2f9 c52a 9472 | 60 c0ad (0) c2f9 (0) c52a (0) cabf (0)\n001 2 1385 034d | 30 184e (0) 1929 (0) 1740 (0) 127c (0)\n002 7 6450 6379 72a7 73d0 | 18 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n003 3 51c2 55fd 5cc1 | 9 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n004 2 4746 459b | 4 4775 (0) 4746 (0) 4589 (0) 459b (0)\n005 2 4bc8 4a37 | 3 4bc8 (0) 4a3c (0) 4a37 (0)\n006 1 4efa | 1 4efa (0)\n============ DEPTH: 7 ==========================================\n007 1 4d75 | 1 4d75 (0)\n008 1 4c21 | 1 4c21 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","private_key":"ab042a555a4b63b145f4de3bbfccdf1f9b84b6cb627f349b61aa1180b6fe933f","name":"node_4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","services":["streamer"],"enable_msg_events":true,"port":36183},"up":true}},{"node":{"info":{"id":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","name":"node_947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","enode":"enode://3ca90095f93c4f83cffc3cf6da5e155328580ae3f82119872f3088143f19bcc006916f2dddcf8f4325de936f67e88f96446e448c4a59def92228dfade44c5901@127.0.0.1:0","enr":"0xf88fb84036ea2f3f5156386eb2d22329ca9cb82df354d2411a505c41eb3cd0455f9f4e706903cbbe26ecebe77942a1650c5475a289f05cbeaca4a648322982b30b84a2a60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033ca90095f93c4f83cffc3cf6da5e155328580ae3f82119872f3088143f19bcc0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lHIF/YWhczCm1cUaZlSMX2l3nHarEkCPj8bTPXxrjp0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 947205\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 034d 5be6 4cc2 73d0 | 68 184e (0) 1929 (0) 1740 (0) 127c (0)\n001 6 c0ad ce01 d18a deec | 31 c2f9 (0) c0ad (0) c52a (0) c9ef (0)\n002 12 b60e b5fc b4e2 be0f | 20 a192 (0) acf8 (0) aedc (0) aba7 (0)\n============ DEPTH: 3 ==========================================\n003 7 8fb8 8d3e 8b35 8012 | 7 8012 (0) 836e (0) 8330 (0) 8284 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 957e | 1 957e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","private_key":"eaf46b142d5bbbd82ca1980c2bf40b52e6c63c995e5e99fb80517e644adea556","name":"node_947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","services":["streamer"],"enable_msg_events":true,"port":33771},"up":true}},{"node":{"info":{"id":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","name":"node_641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","enode":"enode://97de2f10991b84b4170cadcc248b4222bd846e91b5212930b3a721cb99af24894df3ba5ba33a7b6cc18dd6cbfba935526b69cb0a5e6b93dec26a696f32c580ea@127.0.0.1:0","enr":"0xf88fb840dd1c643add167311c80939c5d5ff43fac27e87b7bff2726cb3d5e156638744383d3370833f2730acccd609cd6d0813ed5993951c83b59cc7b51fe835f7a457d10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10297de2f10991b84b4170cadcc248b4222bd846e91b5212930b3a721cb99af2489","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZBoWX4vg7uNvU8Erro4qNKcJrbjR3NZn6I5OkMnuJAE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 641a16\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 ed12 f611 ce01 c52a | 60 d23c (0) d125 (0) d18a (0) d9d3 (0)\n001 2 1929 034d | 30 1740 (0) 127c (0) 1385 (0) 184e (0)\n002 4 4bc8 459b 58a9 51c2 | 20 5c62 (0) 5cc1 (0) 58a9 (0) 5a8b (0)\n003 6 75e2 772a 77ee 72a7 | 9 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n004 3 6975 68a6 6daa | 3 6975 (0) 68a6 (0) 6daa (0)\n005 2 62f0 6379 | 2 62f0 (0) 6379 (0)\n006 1 672a | 1 672a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 64e6 | 1 64e6 (0)\n009 1 6450 | 1 6450 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","private_key":"f38953abdf59b216747d7c22e600d0f55aa03853782359e4f1d890ee6ccd3795","name":"node_641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","services":["streamer"],"enable_msg_events":true,"port":45833},"up":true}},{"node":{"info":{"id":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","name":"node_51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","enode":"enode://19c4efcab79f59b42b632f546d5075b30aebe0cf70b190e194aa53b3cb07a57e054266625288519f7f1ec51933e8a173ee31de9ae1c3ed7a3e52e881e1320bc2@127.0.0.1:0","enr":"0xf88fb840a924d32fa5c0500800c3babdaeff831b1c13855d864a74e91f06b59765c5112f7d5587255be9743f22305b6b734594f50af53545f49998d89400accb44da1a7c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10219c4efcab79f59b42b632f546d5075b30aebe0cf70b190e194aa53b3cb07a57e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UcKFSJ/xRigmiuiGlF4c0tpkxqCoyxhKramFZ6tCm24=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 51c285\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ce01 8fb8 957e bddb | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 3 1385 1929 3590 | 30 1740 (0) 127c (0) 1385 (0) 184e (0)\n002 5 7bee 772a 72a7 6379 | 18 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n003 7 4746 4efa 4d75 4cc2 | 11 4589 (0) 459b (0) 4775 (0) 4746 (0)\n004 4 5cc1 5c62 58a9 5be6 | 5 5c62 (0) 5cc1 (0) 58a9 (0) 5a8b (0)\n005 1 55fd | 1 55fd (0)\n============ DEPTH: 6 ==========================================\n006 1 52b4 | 1 52b4 (0)\n007 1 5008 | 1 5008 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","private_key":"21aeef42b1bca1386305b8a2618ef22c9d57c0a69e14dacf5e9b23b4bd23b510","name":"node_51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","services":["streamer"],"enable_msg_events":true,"port":34421},"up":true}},{"node":{"info":{"id":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","name":"node_3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","enode":"enode://dd24910cfba19349898ab2b4cf2312f77e8c9cbaecebe966a4a599e93acd4ab317c4f64219c14c87eff8676c5f7fba8c5077c9bab707839809585cf3c19e6128@127.0.0.1:0","enr":"0xf88fb8402ed923c581464c45b4e676ff07c79106b7ceff7a57d96353d044e4d884c8a90116f8ec71e379e0311d071f53601855786da347a3d69d1aae9b1d3a07292ecd090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102dd24910cfba19349898ab2b4cf2312f77e8c9cbaecebe966a4a599e93acd4ab3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NZCvzRD7j1jDn3IGhmHZp3K3fg79V7vWAwZjL7BI+jo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3590af\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 8b35 957e a9fa bddb | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 7 7bcb 7bee 772a 6379 | 38 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n002 4 0639 034d 1385 1929 | 13 1740 (0) 127c (0) 1385 (0) 184e (0)\n003 6 2dd4 2803 221c 216e | 11 2dd4 (0) 2d53 (0) 2803 (0) 2354 (0)\n004 3 3e19 3871 3b83 | 3 3e19 (0) 3b83 (0) 3871 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 36d5 3775 | 2 36d5 (0) 3775 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","private_key":"1835770333937be27e295723616d36666fa8de13a77c315e3b4697160def434c","name":"node_3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","services":["streamer"],"enable_msg_events":true,"port":32919},"up":true}},{"node":{"info":{"id":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","name":"node_6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","enode":"enode://6d3336dba794e0658e4fcbecdb6aa6751876ce7d97023c4c68f1c6cf7fa19f6df34069acfdbbd0df6374dad95a86536fa70adefe67496703bc6cc0ca00bc0d6b@127.0.0.1:0","enr":"0xf88fb840a5c366f1069400f50edc7a3dcf5ced0b5f36fc8ac4add80658a7ae4e069e242d0e234a304d1f3f0906667c9331ecc0ea06215873ca2359615ea2539b09849b710183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036d3336dba794e0658e4fcbecdb6aa6751876ce7d97023c4c68f1c6cf7fa19f6d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZFC7XogEEavLYCWNhWCUn29w2Sunv6mk14RUY8SNqzA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6450bb\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b355 b4e2 b5fc a9fa | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 9 1929 1385 0f31 01a6 | 30 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n002 6 58a9 459b 4bc8 4d75 | 20 4746 (0) 4775 (0) 4589 (0) 459b (0)\n003 7 75e2 77ee 772a 73d0 | 9 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n004 3 6daa 68a6 6975 | 3 68a6 (0) 6975 (0) 6daa (0)\n005 2 62f0 6379 | 2 62f0 (0) 6379 (0)\n006 1 672a | 1 672a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 64e6 | 1 64e6 (0)\n009 1 641a | 1 641a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","private_key":"d9d71e00271234db6e058d9dd56ff836e602ba475c91f715471e599e1bed5a5c","name":"node_6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","services":["streamer"],"enable_msg_events":true,"port":40239},"up":true}},{"node":{"info":{"id":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","name":"node_f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","enode":"enode://29ba5c4d8b75150f0c292d475cbafdcad1c6083b68404ea2c937aff1d74a2c8a718c535eaa698de476e4023d6a8dff115d7a6a18d4ef2df8919f5c0af5369179@127.0.0.1:0","enr":"0xf88fb840c816b422b2f4e87c16b25211009de1d65a9e678d98a60bf481a498341d8bf07f11c27a00cac462bf811b306a3b6f7178df60428c1069862f6eba19f0827d7e8c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329ba5c4d8b75150f0c292d475cbafdcad1c6083b68404ea2c937aff1d74a2c8a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8XfuZ2enile3JdvmfsN39Qf1d300WiiJKw+/uADcRDo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f177ee\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 3775 27db 21dc 5cc1 | 68 0807 (0) 0a21 (0) 0f31 (0) 0e34 (0)\n001 5 aba7 be0f bd48 bddb | 29 a192 (0) acf8 (0) aedc (0) aba7 (0)\n002 6 c52a cc5f ce01 deec | 14 d9d3 (0) dd92 (0) deec (0) d23c (0)\n003 5 eceb ed12 ed2e ea3d | 8 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n004 3 fa9a fac8 fa65 | 3 fa65 (0) fa9a (0) fac8 (0)\n005 2 f611 f4a0 | 2 f4a0 (0) f611 (0)\n============ DEPTH: 6 ==========================================\n006 2 f3d5 f33c | 2 f33c (0) f3d5 (0)\n007 1 f005 | 1 f005 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","private_key":"025f98a103e82b260c7f1e0786cc7c7b322ecac23e4bf433a8c3b6ca3c0a7ce1","name":"node_f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","services":["streamer"],"enable_msg_events":true,"port":40657},"up":true}},{"node":{"info":{"id":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","name":"node_5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","enode":"enode://0411dc978683dba8f21f9b8342e621825888fc4937c3657235a2544564af2cf596f918e981af49789225b6548f0476ddcb2c478c561a7ccf2de5cf175b2bd667@127.0.0.1:0","enr":"0xf88fb8402bd016128d16428094936d2baa4cea722a02b856589d60f027fb7ea3cf0d2d312ea4efc1fb1cc49b83d8d28e225fc859c87d2d63e94977820e53d6c4793e95850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030411dc978683dba8f21f9b8342e621825888fc4937c3657235a2544564af2cf5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W+bfIyAfxcAL5lCEnIv+VYHkQDPvGQEoNvl8mPOVRHE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5be6df\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 957e 9472 bc29 bddb | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 3 0639 1385 3775 | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 2 72a7 7bcb | 18 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n003 4 4a37 4efa 4c21 4d75 | 11 4775 (0) 4746 (0) 459b (0) 4589 (0)\n004 3 55fd 52b4 51c2 | 4 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n005 2 5c62 5cc1 | 2 5c62 (0) 5cc1 (0)\n============ DEPTH: 6 ==========================================\n006 1 58a9 | 1 58a9 (0)\n007 1 5a8b | 1 5a8b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","private_key":"b70a8c0d588327194e8b81c1f09b2403aa37aa56914bbfd6ef7e9b7c383a61f7","name":"node_5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","services":["streamer"],"enable_msg_events":true,"port":39601},"up":true}},{"node":{"info":{"id":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","name":"node_37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","enode":"enode://9a0c7c70a6abc8d8d6312e26526241fbaac88e2599c2e8ddc70a0d82155c8a19e306a320af2a0b0ba2a91333c804b1d9aaf1ff34059e1560391b141ec0195be3@127.0.0.1:0","enr":"0xf88fb840299e881f43f4d0b0fc892936f7f58feda81693023bf5890163c50e85520efc40047960a98b178845a87a28261d6fd072ea58cc313c5caa59e80ba89e01ca917c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039a0c7c70a6abc8d8d6312e26526241fbaac88e2599c2e8ddc70a0d82155c8a19","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"N3UfJ5ST3FzltcPFWm7C5BGe7e/hBpsoP2/4x7ydFBE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 37751f\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 ed2e fac8 f611 f177 | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 6 6daa 7bcb 7bee 4d75 | 38 6975 (0) 68a6 (0) 6daa (0) 62f0 (0)\n002 5 0639 034d 1385 184e | 13 0e34 (0) 0f31 (0) 0807 (0) 0a21 (0)\n003 6 2803 2dd4 27db 221c | 11 2dd4 (0) 2d53 (0) 2803 (0) 2354 (0)\n004 3 3e19 3871 3b83 | 3 3e19 (0) 3b83 (0) 3871 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 3590 | 1 3590 (0)\n007 1 36d5 | 1 36d5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","private_key":"bbe213c9c2af2fb4cf312a148364ca68ebecd37b64368e153ea9e51c67042ad5","name":"node_37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","services":["streamer"],"enable_msg_events":true,"port":35275},"up":true}},{"node":{"info":{"id":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","name":"node_8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","enode":"enode://d73cda92a018755888f77a3e564e7551c42f9b0293dce5f7926ad51f152e0608a98f76043b29a2ccee8b56829e6abb11f11bcc8f37138dcff09a22e9883b5da0@127.0.0.1:0","enr":"0xf88fb8406aaa1bd0ce40aedb00ca17a8b54f37666e5fda8c5fd73f70cb28d4f94789bbdd28ccfa1a85414025663af2b020c3b3d80b719d4163d059196efeb1c35caf0e8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d73cda92a018755888f77a3e564e7551c42f9b0293dce5f7926ad51f152e0608","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"j7ggi3Fn3QbMCHeLUHzNhWdR099t+66sGLn1J7ZihSM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8fb820\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 51c2 5cc1 5c62 4efa | 68 4589 (0) 459b (0) 4746 (0) 4775 (0)\n001 5 f005 f611 ed12 d18a | 31 fa9a (0) fac8 (0) fa65 (0) f4a0 (0)\n002 7 b4e2 bc71 bc29 bde9 | 20 a192 (0) acf8 (0) aedc (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 4 8012 836e 8330 8284 | 4 8012 (0) 8330 (0) 836e (0) 8284 (0)\n============ DEPTH: 5 ==========================================\n005 1 8b35 | 1 8b35 (0)\n006 1 8d3e | 1 8d3e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","private_key":"278f3a6445da6b4d5dace451a1c2a3561bdef9784b8326ca0bcae3a8028ed69f","name":"node_8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","services":["streamer"],"enable_msg_events":true,"port":36235},"up":true}},{"node":{"info":{"id":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","name":"node_8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","enode":"enode://5e607646d00042ef14c4f21aea45ea5bd505be570b97f2b1b4ef73a22adf25cde1a8964defec14140b92ef5121092f391b5f2dff5345edd747ebff330059a77f@127.0.0.1:0","enr":"0xf88fb8400a07d6729478c8bd73bee4a5c31564b940112b25c41614e61d55d98ef2e09178170274aae5097d373ef2e01384f6b60f630c75a3185e1254b5a02193b3a74aa90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035e607646d00042ef14c4f21aea45ea5bd505be570b97f2b1b4ef73a22adf25cd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"izUjbamZML+PXvbHVVuxi4DOLjQ2G7v9a69Vpkg+VP8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8b3523\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3590 3871 1929 1385 | 68 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n001 3 ed12 c0ad ce01 | 31 fa9a (0) fac8 (0) fa65 (0) f4a0 (0)\n002 11 aedc a9fa b60e b5fc | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n003 2 957e 9472 | 2 9472 (0) 957e (0)\n004 4 8012 836e 8330 8284 | 4 8012 (0) 836e (0) 8330 (0) 8284 (0)\n============ DEPTH: 5 ==========================================\n005 2 8d3e 8fb8 | 2 8d3e (0) 8fb8 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","private_key":"3322d061eb98b1819a131c74f1241090bf160874985ca4e58cc11e1286ac0c3a","name":"node_8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","services":["streamer"],"enable_msg_events":true,"port":40641},"up":true}},{"node":{"info":{"id":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","name":"node_7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","enode":"enode://466c01046515dee738d0579e73a747c68ced8223155312c012c3f51c97298abc594772c6662ce7511bc515aac473d52bb9bbcf8e44b04576ed927cdcc214dab9@127.0.0.1:0","enr":"0xf88fb840fe0d278bd98464c794a3d0874a16b75432ba8b26f9011bfccc1461bc081260dc5b2fad42936698153126bd2792daec579d9481ecf3c53f7a9efaf80cb867b9240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103466c01046515dee738d0579e73a747c68ced8223155312c012c3f51c97298abc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e8sNe5+ErtQTz5sqeFG6bRE42FOCqiDmyTmkPI5ZwDQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7bcb0d\npopulation: 46 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 c52a ce01 d18a d125 | 60 fac8 (0) fa9a (0) fa65 (0) f4a0 (0)\n001 14 1929 127c 1385 034d | 30 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n002 6 4a37 4bc8 4efa 4cc2 | 20 459b (0) 4589 (0) 4775 (0) 4746 (0)\n003 4 6daa 672a 6450 641a | 9 6975 (0) 68a6 (0) 6daa (0) 672a (0)\n004 6 73d0 72a5 72a7 75e2 | 6 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 7a68 | 1 7a68 (0)\n008 0 | 0\n009 0 | 0\n010 1 7bee | 1 7bee (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","private_key":"a18a91aea9caebd371fccc6f16fbdbae7309ab0a75d82690d6762dfbf43e8237","name":"node_7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","services":["streamer"],"enable_msg_events":true,"port":34329},"up":true}},{"node":{"info":{"id":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","name":"node_27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","enode":"enode://81447592a9952d8e82cbde99d9a3a804c8251313e257587d4fd1441ccab4589209ef2eca6be2a90dd162a15afa8fa1c46112377c94317e710a692ebf3ecab3f5@127.0.0.1:0","enr":"0xf88fb84050691fa1ed8df80d90662ae933a8efbb5e3a89c1e11702c156c0c4d86c410f626a9409a01ad627a3bf48c1f787d9e70306cb6bc2068a36b1d5a6fb5c814b171b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10381447592a9952d8e82cbde99d9a3a804c8251313e257587d4fd1441ccab45892","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J9tm0T7oForKiXhv69aXHdHWxVS8qFAQUgZctHYxVg0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 27db66\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f611 f177 f33c 957e | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 6 4d75 4efa 4bc8 4a37 | 38 459b (0) 4589 (0) 4775 (0) 4746 (0)\n002 4 034d 0639 1385 1929 | 13 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n003 5 3871 3b83 3775 36d5 | 6 3e19 (0) 3b83 (0) 3871 (0) 3590 (0)\n004 3 2d53 2dd4 2803 | 3 2dd4 (0) 2d53 (0) 2803 (0)\n005 5 2354 22bb 221c 216e | 5 2354 (0) 22bb (0) 221c (0) 216e (0)\n============ DEPTH: 6 ==========================================\n006 1 2471 | 1 2471 (0)\n007 0 | 0\n008 0 | 0\n009 1 27b5 | 1 27b5 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","private_key":"0a5ec02539f87d3f1bbe5e084133ad7fc6656fcc73cc18afb174f48e0bf9d670","name":"node_27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","services":["streamer"],"enable_msg_events":true,"port":35267},"up":true}},{"node":{"info":{"id":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","name":"node_bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","enode":"enode://838a4d55191548d17c665566c483b72340302b64549e2745f5e0d48c4e0e76359349919ae4cd0afacd5a4d9da24aebb15ca6d9bf5a028223df52d12f3aa2b77e@127.0.0.1:0","enr":"0xf88fb840ed735da037c65b1531755f40ecb8315e80fed6331af749996e684fbbf86560aa2ffdad12f343a38edb1feefc8de2de8de90416ea256ed794d06e29aa212e9cf00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102838a4d55191548d17c665566c483b72340302b64549e2745f5e0d48c4e0e7635","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vCmg2bYPPiw0IkzsGHz0Tq3EYoCG1VlGZu0CXacefno=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bc29a0\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 4d75 5be6 51c2 1929 | 68 4589 (0) 459b (0) 4775 (0) 4746 (0)\n001 6 cabf d18a f005 f611 | 31 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n002 6 8330 8284 8b35 8fb8 | 9 9472 (0) 957e (0) 8012 (0) 836e (0)\n003 4 aedc aba7 a9fa a192 | 6 a192 (0) acf8 (0) aedc (0) aba7 (0)\n004 3 b355 b5fc b4e2 | 5 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n005 2 b9d9 b869 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n============ DEPTH: 7 ==========================================\n007 4 bd48 bd96 bde9 bddb | 4 bd48 (0) bd96 (0) bde9 (0) bddb (0)\n008 0 | 0\n009 1 bc71 | 1 bc71 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","private_key":"2cf6d0e467db44e155c5ad07c701eba3784d380456d0bd1e248e88e4bd50db52","name":"node_bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","services":["streamer"],"enable_msg_events":true,"port":43139},"up":true}},{"node":{"info":{"id":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","name":"node_1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","enode":"enode://faa781fe46eab677d200731251f2be1aede682a047df2f555335072653b2cf1ad6b90a43c223c2567e8eb00b40a89e31b5d22ddd20563a80e01232f1ba4e151b@127.0.0.1:0","enr":"0xf88fb84098c7e67161c619f0c3c62c007544d6ea9adb3dbc6b48de51b49786232388fca74a3c88c994b07222dfcbba9fb8dbdd2711d9aa0c33c94ecef3d10b9e0e9ab7e20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103faa781fe46eab677d200731251f2be1aede682a047df2f555335072653b2cf1a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GSmwHA+Fr3RSoPNYtU9rNmQKGWs2aQkXKvWUoWSP5kw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1929b0\npopulation: 39 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f005 d23c ce01 8b35 | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 13 4746 4d75 4efa 4a37 | 38 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n002 11 3871 3e19 3590 36d5 | 17 3b83 (0) 3871 (0) 3e19 (0) 3590 (0)\n003 4 0e34 0a21 0639 034d | 8 0f31 (0) 0e34 (0) 0807 (0) 0a21 (0)\n============ DEPTH: 4 ==========================================\n004 3 1740 127c 1385 | 3 1740 (0) 127c (0) 1385 (0)\n005 0 | 0\n006 0 | 0\n007 1 184e | 1 184e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","private_key":"f3de60891a8eef22fd764c76d7b6d43b2af723a9731661df6e11020da0718b7c","name":"node_1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","services":["streamer"],"enable_msg_events":true,"port":41623},"up":true}},{"node":{"info":{"id":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","name":"node_ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","enode":"enode://1c368e379ede78380a9710e4d82c88489f66cbc28792aff7702313c087a47b0289a9c8db20c4181b75184f84aac33116cb707ffe2e01e033f014f7f14a082ef1@127.0.0.1:0","enr":"0xf88fb84077b68fee63a81bffa263efd74f643a807ceacce488968c34836eeedf7883e9da6c52dcd816863207878248ea60ba2d67c99473148fe275966dad15341798430d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031c368e379ede78380a9710e4d82c88489f66cbc28792aff7702313c087a47b02","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zgEjRmEwkSe7hy1p043Fvxm8TeLgoLUEHNNi0HPfT/g=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ce0123\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 7bcb 772a 72a7 641a | 68 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n001 6 b4e2 a9fa 8fb8 8b35 | 29 a192 (0) acf8 (0) aedc (0) aba7 (0)\n002 6 fac8 f611 f177 f005 | 17 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n003 5 deec dd92 d23c d18a | 6 d9d3 (0) dd92 (0) deec (0) d23c (0)\n004 2 c52a c0ad | 3 c52a (0) c2f9 (0) c0ad (0)\n005 2 c9ef cabf | 2 c9ef (0) cabf (0)\n============ DEPTH: 6 ==========================================\n006 2 cc9f cc5f | 2 cc5f (0) cc9f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","private_key":"95cc1ce48219ce51e9d9520f9ed3968f753d9bce3da5e3bd7ea9362f1f51a509","name":"node_ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","services":["streamer"],"enable_msg_events":true,"port":45409},"up":true}},{"node":{"info":{"id":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","name":"node_957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","enode":"enode://8b3a82a0b62bf9f4fe01d9c72712b70dd78140dfd808de3b5d4e2daa6d1e0bc78137035a1c4888ca82d1ae29cd2ed1e42db6210f629a415080082cacbcf3bf48@127.0.0.1:0","enr":"0xf88fb84018ff9330c436aa3ccef762f9c9a9d020113f1b7b955b454631d5bcc2c441ce99132e51acf27ba2589be6a6d018a52f3110342b94391caa43e26f3ba790a0248f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028b3a82a0b62bf9f4fe01d9c72712b70dd78140dfd808de3b5d4e2daa6d1e0bc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lX7WGU5u9W6Wlr5DoaAljyuk9I9W15DkK9BmPD/Gqq4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 957ed6\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 1929 034d 2803 2471 | 68 3e19 (0) 3b83 (0) 3871 (0) 3590 (0)\n001 7 f005 f3d5 f611 dd92 | 31 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n002 7 a9fa b4e2 b355 bc71 | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n============ DEPTH: 3 ==========================================\n003 7 8b35 8d3e 8fb8 8012 | 7 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 9472 | 1 9472 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","private_key":"c249537590c459e98e22f7a70786699bfd3c23aef26288b9f589ee97574d33cc","name":"node_957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","services":["streamer"],"enable_msg_events":true,"port":42809},"up":true}},{"node":{"info":{"id":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","name":"node_6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","enode":"enode://9b66200ba83d63d75740082432f6c3831ad635f6d3fe228458bd67d7e49cbaa1df293dffbf9406b165a041c7d284b6979057355ab46f925a4ae75a21e35fdf2e@127.0.0.1:0","enr":"0xf88fb8403156b1191369fe50cd749c6aac2c8795c35461c3f5bcc76313ab9a54c9248041081d5084353de2c4357294d870533e298b6954e3d9ca93644323f9cbaefb2a5b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029b66200ba83d63d75740082432f6c3831ad635f6d3fe228458bd67d7e49cbaa1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Y3m01hHN1uNgSAwUs/Z4Q2Dyj3ArWm83XtpO873n7zM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6379b4\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bddb 957e | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 2 3590 1929 | 30 0807 (0) 0a21 (0) 0f31 (0) 0e34 (0)\n002 6 4cc2 58a9 5cc1 5c62 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 5 7a68 75e2 772a 73d0 | 9 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n004 3 6daa 68a6 6975 | 3 6975 (0) 68a6 (0) 6daa (0)\n============ DEPTH: 5 ==========================================\n005 4 672a 64e6 6450 641a | 4 672a (0) 64e6 (0) 641a (0) 6450 (0)\n006 0 | 0\n007 1 62f0 | 1 62f0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","private_key":"024d0a70b86bc13cf4efc5e5bd5144a351300f43a58a6e6b95684a79ddd6fa69","name":"node_6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","services":["streamer"],"enable_msg_events":true,"port":38231},"up":true}},{"node":{"info":{"id":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","name":"node_bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","enode":"enode://fee39a564023c233a4363d4b025275561497b7b7c8e82b20160ec71631ec4adebe8afa63a77c3eb4a2d29f8c5038d08cc1ae180ea5bc95ed479297b2eaf84354@127.0.0.1:0","enr":"0xf88fb8408b6f5d1b485209e0c27b986c8f1f4356f21252247a203ff1e10fe4d511299bb01096acece8f2bf01e7674f4a3b9f315ecced47e671df32ae11bc7dcde6c0636d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fee39a564023c233a4363d4b025275561497b7b7c8e82b20160ec71631ec4ade","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vdvf88vSL87d3AfeJxJYGarHK+csMSa6iYYhxJbLlaI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bddbdf\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3590 4d75 5be6 51c2 | 68 0f31 (0) 0e34 (0) 0807 (0) 0a21 (0)\n001 2 f177 ed12 | 31 d9d3 (0) dd92 (0) deec (0) d23c (0)\n002 5 9472 957e 8fb8 8b35 | 9 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n003 3 a192 aba7 a9fa | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 3 b5fc b4e2 b355 | 5 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n005 2 b9d9 b869 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc71 bc29 | 2 bc71 (0) bc29 (0)\n008 1 bd48 | 1 bd48 (0)\n============ DEPTH: 9 ==========================================\n009 1 bd96 | 1 bd96 (0)\n010 1 bde9 | 1 bde9 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","private_key":"4d7f0353e69c74cd0ffd1788c11c34ed5bf024705a9d91fcc91364dcc0170d44","name":"node_bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","services":["streamer"],"enable_msg_events":true,"port":40129},"up":true}},{"node":{"info":{"id":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","name":"node_82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","enode":"enode://e2446d4ba20cf04f7587b21f065505bf06a0b763ad10228db7fac2f3d0ce85b065c6ae7856d0cf0de33e54f769d982a19db0166690996d05cfe8789eefcd061c@127.0.0.1:0","enr":"0xf88fb840390e501e8aea6582161ebc4735fea5ea709f34fdce68c3bea1d8ac01a9bee38b1f74f6c9802e7101930fa56f8379569b9e68aeca2f58c3af3f64fc0346e8bf000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e2446d4ba20cf04f7587b21f065505bf06a0b763ad10228db7fac2f3d0ce85b0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"goR6SvT1BiJlDQNfaRUbICvM1fySMCphdgLJdGA+2Zc=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82847a\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 72a7 75e2 772a 7a68 | 68 6975 (0) 68a6 (0) 6daa (0) 62f0 (0)\n001 7 dd92 d23c d18a d125 | 31 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n002 8 aedc a9fa b355 b4e2 | 20 a192 (0) acf8 (0) aedc (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 2 8b35 8fb8 | 3 8b35 (0) 8d3e (0) 8fb8 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 8012 | 1 8012 (0)\n007 2 836e 8330 | 2 8330 (0) 836e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","private_key":"8ad165530adf15657647eec0c9ad139e69f7656f1deca7792c1fc0de289a1add","name":"node_82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","services":["streamer"],"enable_msg_events":true,"port":45695},"up":true}},{"node":{"info":{"id":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","name":"node_2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","enode":"enode://89fa1305c12aff15670cc1bd8b563b83fe9f1674d1001a07b9603e7da4f267a84dfb81b00c1b2a8b6515fa90ad36b8790ed0d0bca1509e9bf434327d50ff6375@127.0.0.1:0","enr":"0xf88fb840f7c3b1530907dfcb9ba22825a0bac829dd204d31f686d97d7f4481599308bb0536112276a86c5ce46f913fb6817457bd19a2b684046c47fcbd14827391e52f080183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10389fa1305c12aff15670cc1bd8b563b83fe9f1674d1001a07b9603e7da4f267a8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KAPyEutKpPSSJLFrLeiLqGUq0RUyHuHmDNvZJuza04o=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2803f2\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 957e 8284 f005 e06f | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 9 6450 64e6 672a 7bee | 38 6daa (0) 68a6 (0) 6975 (0) 62f0 (0)\n002 3 034d 184e 1929 | 13 0f31 (0) 0e34 (0) 0a21 (0) 0807 (0)\n003 4 3e19 3590 3775 36d5 | 6 3e19 (0) 3871 (0) 3b83 (0) 3590 (0)\n004 8 22bb 221c 2354 216e | 8 2471 (0) 27b5 (0) 27db (0) 2354 (0)\n============ DEPTH: 5 ==========================================\n005 2 2dd4 2d53 | 2 2dd4 (0) 2d53 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","private_key":"b37365e96591f61ba1f1f4c9438ef43bd78f2207737972de4ecc9bc85640c7c5","name":"node_2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","services":["streamer"],"enable_msg_events":true,"port":46045},"up":true}},{"node":{"info":{"id":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","name":"node_ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","enode":"enode://0b74c99f74b309c85f91b8ac4c7ebd527e900a0e3ec1355dfbfcc3f9e3bdeba8f75f27696f1412ccfa6d1580c769641f74289f5ac39347e2af880b54dbe1bdb4@127.0.0.1:0","enr":"0xf88fb840d82da58cd4d87e8a9a7bc9fa59302a31d713ec01ba8a8a0f3c989a2975ed12a41cec56ba3214c6dff113d27ed34285dd89654def2164131e72eb4d7fa553aacb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020b74c99f74b309c85f91b8ac4c7ebd527e900a0e3ec1355dfbfcc3f9e3bdeba8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7RLHjnAL+AVmnEil1i8eVnkSY8SyzlvTRYfqm8kxo+U=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed12c7\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 641a 72a7 7bcb 4d75 | 68 6daa (0) 68a6 (0) 6975 (0) 6379 (0)\n001 6 be0f bc29 bddb 8fb8 | 29 a192 (0) aedc (0) acf8 (0) aba7 (0)\n002 9 d23c d125 d18a dd92 | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 5 fa65 f33c f177 f005 | 9 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n004 1 e06f | 1 e06f (0)\n005 2 eb01 ea3d | 2 eb01 (0) ea3d (0)\n006 2 efd6 ee2b | 2 efd6 (0) ee2b (0)\n============ DEPTH: 7 ==========================================\n007 1 eceb | 1 eceb (0)\n008 0 | 0\n009 0 | 0\n010 1 ed2e | 1 ed2e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","private_key":"f54883fc517f0e3c2eddab9bdc23da7263abbb18620926ea60fdc8e1c54f341e","name":"node_ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","services":["streamer"],"enable_msg_events":true,"port":41603},"up":true}},{"node":{"info":{"id":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","name":"node_4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","enode":"enode://ed37ba950278a3c20524b27d1e9a25e94d01f5fa944c8c34d28feea810dc7c9ff037e34daa95ad6d532439949b2f4ce551f3e01eb652ca662e40b561560bf690@127.0.0.1:0","enr":"0xf88fb84074cdf17f902a07b1fe1cf0d4977a986ae645bb8d982f6feeae2a955a91b8eb3b25a8c65e204fbb42b090a2ca073f7de07f6fe8bb3ae3dc993c9f193ce5f800930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ed37ba950278a3c20524b27d1e9a25e94d01f5fa944c8c34d28feea810dc7c9f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TXUGZtwOniwkTENJKAHB1+xiCJVKDLX4u3k7kSRAdTo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d7506\npopulation: 45 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 957e 8fb8 b869 bddb | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 14 127c 1385 1929 184e | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 4 672a 6450 75e2 7bee | 18 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n003 4 52b4 51c2 5c62 5be6 | 9 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n004 4 4589 459b 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 3 4bc8 4a3c 4a37 | 3 4a3c (0) 4a37 (0) 4bc8 (0)\n006 1 4efa | 1 4efa (0)\n============ DEPTH: 7 ==========================================\n007 2 4c21 4cc2 | 2 4cc2 (0) 4c21 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","private_key":"86b527d54feaa68feaa47006bfdddb5ed3db2af4f2d2c66c08442c78bfddeb4a","name":"node_4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","services":["streamer"],"enable_msg_events":true,"port":43481},"up":true}},{"node":{"info":{"id":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","name":"node_7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","enode":"enode://ee6f1a851bbd2d48a78f56ee08516649226a2b2c490ecede0f8144fd1bd0c94113ed85d0f117ed7d577e6ca4fc62f21ff3f1bc4fda1504ef8f9120b7836fa78b@127.0.0.1:0","enr":"0xf88fb840d7c73ae301629d49e06baa43aba331e7eabb685bf4c4d420b746acdbf05acb7b2468e5c944470383ac2d8aeb608a478c483b1d7fd866cec2f9b38244934394260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ee6f1a851bbd2d48a78f56ee08516649226a2b2c490ecede0f8144fd1bd0c941","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e+55Z/97ByQ77VW20GDV7CofKLUw7WXNBV3FtGig+Hg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7bee79\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 b4e2 8284 8fb8 9472 | 60 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n001 7 184e 1929 3590 3775 | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 5 51c2 52b4 4bc8 4efa | 20 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n003 4 6daa 68a6 64e6 672a | 9 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n004 6 77ee 772a 75e2 73d0 | 6 77ee (0) 772a (0) 75e2 (0) 73d0 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 7a68 | 1 7a68 (0)\n008 0 | 0\n009 0 | 0\n010 1 7bcb | 1 7bcb (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","private_key":"2ba96f376fb0ff9f7f829af5f4ac836ee1973e1a0198f5e9fcdfd002aa55f7db","name":"node_7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","services":["streamer"],"enable_msg_events":true,"port":45185},"up":true}},{"node":{"info":{"id":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","name":"node_d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","enode":"enode://111a2f319dc9db157c329c910ac39ad991b4a51e524947cdef3771765b1de028196a000955e727277027e2120a5fc6a1ad482b9b905988222c43895d74b496da@127.0.0.1:0","enr":"0xf88fb8404522aa5ddd38e1612c0c481686380332cc9624a872608456ad811feebe30a98e417d969aa10b1db80af028c334406d20531319decbc1dc63339222303e8379a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102111a2f319dc9db157c329c910ac39ad991b4a51e524947cdef3771765b1de028","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0Yoe3SZmEGn7QB/uiqhalhSjGI4uBma/6TB/kdKarUk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d18a1e\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4a37 641a 7bcb 7bee | 68 0e34 (0) 0f31 (0) 0a21 (0) 0807 (0)\n001 7 a9fa b4e2 bc29 8284 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 9 e06f ed2e ed12 ea3d | 17 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n003 5 c52a c0ad cabf cc5f | 8 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n004 3 d9d3 deec dd92 | 3 d9d3 (0) deec (0) dd92 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 d23c | 1 d23c (0)\n007 0 | 0\n008 1 d125 | 1 d125 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","private_key":"1254e1b68ce774b5f389113becbac1ac48e7cd670611899a781849e45f626f93","name":"node_d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","services":["streamer"],"enable_msg_events":true,"port":36067},"up":true}},{"node":{"info":{"id":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","name":"node_f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","enode":"enode://44c0501c60e75da3cff66ec0cc1f38a048f0236760ae5a715e180477166acef0f3861d57d16ece9860e9ab79f1d0c0d8d2e72d224b7b2efeaef3851ee781dd2c@127.0.0.1:0","enr":"0xf88fb840c322770a94cf0d299ed2c66f6698f6cc8cf2c1297f7f1f0f4db86c08c7eb44b2451dc9ee8f9f0e2a30068eb28c80097b8413bfb5bbbb41ec8bb3f2b3d9a384e30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10244c0501c60e75da3cff66ec0cc1f38a048f0236760ae5a715e180477166acef0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8AWk00U9UkNPK1vkAG5lO1C1KtMZJtZUci/D3wDxaJw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f005a4\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 2803 3775 36d5 034d | 68 0807 (0) 0a21 (0) 0f31 (0) 0e34 (0)\n001 12 8fb8 8012 8330 8284 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 2 ce01 d18a | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 3 eceb ed12 ed2e | 8 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n004 2 fa65 fac8 | 3 fa65 (0) fa9a (0) fac8 (0)\n005 2 f4a0 f611 | 2 f4a0 (0) f611 (0)\n============ DEPTH: 6 ==========================================\n006 2 f33c f3d5 | 2 f33c (0) f3d5 (0)\n007 1 f177 | 1 f177 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","private_key":"22efd63c6544702dc87aeb332bfd579220f67ee8aeb6de7e8d074f5c0bc7406d","name":"node_f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","services":["streamer"],"enable_msg_events":true,"port":35571},"up":true}},{"node":{"info":{"id":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","name":"node_4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","enode":"enode://8932a57b3a5d0667185be53dfc1c53a171fb4ed6de334b49c24440e48bd85288cb827ff2141fedab03949eaaac6340211b64e434f80dc83e4c21b24e907b54aa@127.0.0.1:0","enr":"0xf88fb84026d7e9844328cc3aead03b756a7922f94121db28001850d34df1b7f2513ec69e30437cc7a321d10338c447945422db8b68c70409fd74fb560da1a45823fa40840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028932a57b3a5d0667185be53dfc1c53a171fb4ed6de334b49c24440e48bd85288","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Sjc1cUdeK0woDS1LIvEKJJ7gn8+Qf1IIHsA5iotepvI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a3735\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8fb8 a9fa d18a fac8 | 60 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n001 5 216e 27db 36d5 3775 | 30 0e34 (0) 0f31 (0) 0807 (0) 0a21 (0)\n002 7 7bcb 7a68 73d0 72a7 | 18 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n003 6 5cc1 5c62 58a9 5be6 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 2 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 4 4efa 4cc2 4c21 4d75 | 4 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4bc8 | 1 4bc8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 4a3c | 1 4a3c (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","private_key":"01b16147c78c71594879cbc9eace48bccf5f46f6c50604ec8fee98e1e91914b2","name":"node_4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","services":["streamer"],"enable_msg_events":true,"port":43203},"up":true}},{"node":{"info":{"id":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","name":"node_a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","enode":"enode://37b1fbaed8a69d74dcb79c7269e934ef02b048bc42b77b82e5e62866160ba5cad476950f99f99285f882b0a904a19b9cc97400347dd8913ebdbf6698e62f4490@127.0.0.1:0","enr":"0xf88fb840651a030a5371bc567448dc8f7027e7e4d9aca1dffba13e9503cbd1be66c51de02e5ee41bbc0d27c11c4d68d95ed088f1108e358ae435ebb57803627f6d7712ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10237b1fbaed8a69d74dcb79c7269e934ef02b048bc42b77b82e5e62866160ba5ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qfooEXpLaQa1zjkxVz4KGe7Dy0/NkUG+LSWKK+BvO2E=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a9fa28\npopulation: 46 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 2471 3590 68a6 6450 | 68 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n001 14 d18a d125 d23c dd92 | 31 c52a (0) c2f9 (0) c0ad (0) cc9f (0)\n002 7 9472 957e 8b35 8d3e | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 12 b245 b355 b60e b4e2 | 14 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n004 1 a192 | 1 a192 (0)\n005 2 aedc acf8 | 2 aedc (0) acf8 (0)\n============ DEPTH: 6 ==========================================\n006 1 aba7 | 1 aba7 (0)\n007 1 a861 | 1 a861 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","private_key":"eea6155ca80745d78b3a9c8c63fc2618254022771e70abd50cc80a7bcee4129c","name":"node_a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","services":["streamer"],"enable_msg_events":true,"port":35285},"up":true}},{"node":{"info":{"id":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","name":"node_4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","enode":"enode://83716365bf8c5748254c76a38079e43293468d4a67d489df3092fc33447390a566e18708a5ef396134e35ca5f2ff58e96ea27ed6941bc20dc6c3d1be57960d9b@127.0.0.1:0","enr":"0xf88fb840beee55803b074f7f9ec59bf2276feeb7849256026ecb0b230f47905554a0b7721dc5f36ac09fcad8662a9da7962463ba1c8380d27ebc363edf966b1b4fffd7970183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10383716365bf8c5748254c76a38079e43293468d4a67d489df3092fc33447390a5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Tvqrqw1dxZ8Jiu5NujhoJjQRpVYVosR0pz5u7CIR3sw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4efaab\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f4a0 fac8 8fb8 bde9 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 1929 216e 27db 2803 | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 6 7bee 7bcb 72a7 72a5 | 18 73d0 (0) 72a7 (0) 72a5 (0) 77ee (0)\n003 5 52b4 51c2 5cc1 5c62 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 4 459b 4589 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 3 4bc8 4a37 4a3c | 3 4a3c (0) 4a37 (0) 4bc8 (0)\n============ DEPTH: 6 ==========================================\n006 3 4cc2 4c21 4d75 | 3 4cc2 (0) 4c21 (0) 4d75 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","private_key":"9adb7214565c62d93b6daada5fb947a4aa641f07396dc29def6a399d06534b3f","name":"node_4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","services":["streamer"],"enable_msg_events":true,"port":41679},"up":true}},{"node":{"info":{"id":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","name":"node_bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","enode":"enode://18c5769fcc3cebeb0f8151e2f4b84902c268fe8db07c01b90e0992abf123891768735738fa07913a22d143ae1b0852d830f7b49fd9b022b48765b518bccf8166@127.0.0.1:0","enr":"0xf88fb84006231adc86baddad575a6b04c656320bf5c226c2f4907c98a80d09ffd30a9c5e5f4ef4e17a92c907e3fa90a57634dec8277905a2298a73fea645bf359a400e910183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10218c5769fcc3cebeb0f8151e2f4b84902c268fe8db07c01b90e0992abf1238917","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vekKqg8fen65Zf8whxjSm1WoCxyoTfuhbBaeq+Kw1d4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bde90a\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5be6 4bc8 4d75 4efa | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 2 e06f ed2e | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 6 957e 8fb8 8b35 8012 | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 3 a9fa a861 a192 | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 3 b4e2 b245 b355 | 5 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n005 2 b9d9 b869 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc71 bc29 | 2 bc71 (0) bc29 (0)\n008 1 bd48 | 1 bd48 (0)\n============ DEPTH: 9 ==========================================\n009 1 bd96 | 1 bd96 (0)\n010 1 bddb | 1 bddb (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","private_key":"5c9ecf07c02ad229e4278ffee6d3f401fd8e6605ec8cda65cd1de164bdb2c4c9","name":"node_bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","services":["streamer"],"enable_msg_events":true,"port":37049},"up":true}},{"node":{"info":{"id":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","name":"node_b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","enode":"enode://05ec349b77cce593afc87d277f22c4664825e5cda0f4685461bf1161b262a3c29837580c1f80a96fd1953be71e7083284fbb28a7cbd63df5ceea63f89d1c429d@127.0.0.1:0","enr":"0xf88fb8403b39c4a274c55d5fda8b8b8e52dfdb970bff69c0055370a4553ff68fd90d149f41ff2b874b4b9c2258a91d1256de830ec8c0ea3cf7881acab5e8dce0fff835bb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10305ec349b77cce593afc87d277f22c4664825e5cda0f4685461bf1161b262a3c2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s1VbqnZMRWKTW5NTPubFpt9jHoRsOrUS/bHWuQGmjGA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b3555b\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 3775 3e19 184e 1929 | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 3 f005 e06f ed2e | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 5 957e 8b35 8012 8284 | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 3 a9fa a861 a192 | 6 a192 (0) acf8 (0) aedc (0) aba7 (0)\n004 9 b9d9 b869 be0f bc29 | 9 b9d9 (0) b869 (0) be0f (0) bc71 (0)\n============ DEPTH: 5 ==========================================\n005 3 b60e b4e2 b5fc | 3 b60e (0) b5fc (0) b4e2 (0)\n006 0 | 0\n007 1 b245 | 1 b245 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","private_key":"590969da498fe95b0a99340a0c185e65d4cc9eb3ee04b3629e91bdc6b8ce18c6","name":"node_b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","services":["streamer"],"enable_msg_events":true,"port":39871},"up":true}},{"node":{"info":{"id":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","name":"node_4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","enode":"enode://29d89497ada4c78fa702d02812539dddff2d5b2a38b2eabf3ccca262ca18d8a7781a78b87287b1d2e204171814e04a54d268c692c64f9da0079ff9b143f8b386@127.0.0.1:0","enr":"0xf88fb840933154156e40944b295ca276bd44fdccde6fa8f9ca5ec52169c14e3d609078a3554a271fdcc0e539e728506b39331131141632c216ce5728688f16aa2367a0590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10229d89497ada4c78fa702d02812539dddff2d5b2a38b2eabf3ccca262ca18d8a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"S8jfv4R5TSbXpXPJ2JiXTqo6IWfhnLeoqkYIB6YDrNQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4bc8df\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f4a0 fac8 d125 bde9 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 184e 216e 27db 36d5 | 30 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n002 10 6450 641a 6975 68a6 | 18 73d0 (0) 72a7 (0) 72a5 (0) 77ee (0)\n003 4 5a8b 5c62 52b4 51c2 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 3 4589 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 4 4efa 4d75 4cc2 4c21 | 4 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 4a37 4a3c | 2 4a3c (0) 4a37 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","private_key":"2b3a544890fa52405c7779653a8a4e5269283d9f341ab7aa99823d9135a96263","name":"node_4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","services":["streamer"],"enable_msg_events":true,"port":44129},"up":true}},{"node":{"info":{"id":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","name":"node_d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","enode":"enode://d2dec9507d007942f28636ef9f81f1a1a872649603fd6a91663cd0130f4cda18defe6e621a84a16b090128c8f34cb74030ccb6da91c4d4f738ef2fc72fa7a14a@127.0.0.1:0","enr":"0xf88fb840625c10b99f412c5021f6b462a097936033b6ce377281de62adfcf031f36be69c099ffbd4039c05d2c01fd4020579a384db855daf9ddae3b84112d2ba0fd359000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d2dec9507d007942f28636ef9f81f1a1a872649603fd6a91663cd0130f4cda18","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0SUxe0kt9Gp91JbTDG0Hg57Wv6GWq95Ihs57yPm1wB8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d12531\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 72a7 7bcb 641a 672a | 68 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n001 6 8012 8330 8284 b4e2 | 29 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n002 7 ea3d ed12 ed2e ee2b | 17 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n003 6 c52a c0ad cabf cc5f | 8 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n004 3 d9d3 deec dd92 | 3 d9d3 (0) deec (0) dd92 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 d23c | 1 d23c (0)\n007 0 | 0\n008 1 d18a | 1 d18a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","private_key":"f481929f9772f78b97a8f3aec412d8fcce1c6413a74f05ae88a2a1f966ac73ea","name":"node_d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","services":["streamer"],"enable_msg_events":true,"port":35019},"up":true}},{"node":{"info":{"id":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","name":"node_672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","enode":"enode://7b6be04d1749751b5092a9e161b023476c969249f8f813aaa7d55bb11ea59589a48186fdbd5669729d96c2e6aa36e602be0dd2affbb4f9b746cffe9d6ce980c6@127.0.0.1:0","enr":"0xf88fb840a265ed80e2605099ff7573c1400c1e72f63aeba4a2ab3fa32bcd5983f0f0bd89046d176ca64735155279f50bfabb42326955276866cdb505549743cee3f0e7190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027b6be04d1749751b5092a9e161b023476c969249f8f813aaa7d55bb11ea59589","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZypWbHwq6x2R5u5OQ5hAUN+LlWDZI9YNwfsj+3OxoEY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 672a56\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ee2b c0ad d125 8284 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 6 27b5 2d53 2803 0a21 | 30 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n002 6 4d75 4589 4746 4775 | 20 459b (0) 4589 (0) 4775 (0) 4746 (0)\n003 5 75e2 72a7 72a5 7bcb | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 3 6daa 6975 68a6 | 3 6daa (0) 6975 (0) 68a6 (0)\n005 2 62f0 6379 | 2 6379 (0) 62f0 (0)\n============ DEPTH: 6 ==========================================\n006 3 64e6 641a 6450 | 3 641a (0) 6450 (0) 64e6 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","private_key":"310d5355dc6d53293d04e7e253fbbc07b4f8990b7da8ed4a43b288b8091dae9a","name":"node_672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","services":["streamer"],"enable_msg_events":true,"port":38621},"up":true}},{"node":{"info":{"id":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","name":"node_b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","enode":"enode://34eec1960cf31fc2dbdcebf909d70107e4589b1136173b360bd9428e5403683b9cbf3d075784c2059942ece65d262f429c184c07f0ca0b3e9cf609484e99b01f@127.0.0.1:0","enr":"0xf88fb840328330bce745f0a6aecebf965760649d16f77adfe7dc13e07094a7d3d2238d1304692cb5d4fbbac1caf45e4c5ca08e54fcfd1a30d2a8e9d6fefe7108a3355d010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10334eec1960cf31fc2dbdcebf909d70107e4589b1136173b360bd9428e5403683b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tOKd5L1XUfMRlerYqhVI0wWlP7T5m+mTGFDmJz3o81k=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b4e29d\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 4d75 5be6 5c62 7bee | 68 01a6 (0) 03eb (0) 034d (0) 0639 (0)\n001 11 d125 d18a d23c dd92 | 31 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n002 7 957e 9472 8b35 8fb8 | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 2 a192 a9fa | 6 aedc (0) acf8 (0) aba7 (0) a861 (0)\n004 8 b9d9 b869 bc29 bc71 | 9 b9d9 (0) b869 (0) be0f (0) bc29 (0)\n005 2 b355 b245 | 2 b245 (0) b355 (0)\n============ DEPTH: 6 ==========================================\n006 1 b60e | 1 b60e (0)\n007 1 b5fc | 1 b5fc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","private_key":"91d529071d81ab2bdb9e196080d3e71c4e0b1489d32f062fed6384af3da301ba","name":"node_b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","services":["streamer"],"enable_msg_events":true,"port":43795},"up":true}},{"node":{"info":{"id":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","name":"node_f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","enode":"enode://7c45bf66c718bd1786d40d630447ad12d162cab1cda004e9cda42d46e902793a21486f69dc05cbdf2668185e67b050e7a0201cb4795acf046008819e31bf0b3a@127.0.0.1:0","enr":"0xf88fb840ecb85cd88a5e53a505d6f8fc3bfba676551879609d7600f44cf989c3954b6b295b9001b005ec206366f0e2e2b4568301bdd7800a4931e26d253ea68cb93da85a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027c45bf66c718bd1786d40d630447ad12d162cab1cda004e9cda42d46e902793a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9hHYA5OFrVYmCrORdj42J6rdJ1ZWX+3D7JX3YSTaDvw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f611d8\npopulation: 45 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 27db 3775 641a 7bcb | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 16 8fb8 8330 836e 8284 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 7 d18a d23c deec dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 6 e06f eb01 efd6 ee2b | 8 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n004 3 fac8 fa9a fa65 | 3 fa65 (0) fa9a (0) fac8 (0)\n============ DEPTH: 5 ==========================================\n005 4 f33c f3d5 f177 f005 | 4 f177 (0) f005 (0) f33c (0) f3d5 (0)\n006 1 f4a0 | 1 f4a0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","private_key":"7ab918155f49b16772c29096b650cf6baa603a51b6d2bde3aa338c699ac4bcff","name":"node_f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","services":["streamer"],"enable_msg_events":true,"port":40431},"up":true}},{"node":{"info":{"id":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","name":"node_5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","enode":"enode://233c4654af0c29a6d9f1fd643f00e4c77b24df2f4a388dc96f185a6492c67af3875580e0e3df923cfc1857baf0933fcfc451fd1af522d0ae636212c787ac549a@127.0.0.1:0","enr":"0xf88fb8409ba9b9726a6f75d6349a441f7afacdfcd153e89635e530e301aba363979b95be152ab2b042540762f8e738257928ed7cb0e1dcc276af3f5a178dc3cdf78733c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102233c4654af0c29a6d9f1fd643f00e4c77b24df2f4a388dc96f185a6492c67af3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XGI/oBAxCNCx4k5tAaZiTOO1mp58QixF38EhFnZ4VUI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5c623f\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 8fb8 957e b245 b4e2 | 60 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n001 7 1929 184e 2471 27b5 | 30 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n002 4 75e2 72a5 6379 672a | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 8 4bc8 4a37 4a3c 4efa | 11 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n004 4 55fd 5008 51c2 52b4 | 4 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n============ DEPTH: 5 ==========================================\n005 3 58a9 5a8b 5be6 | 3 58a9 (0) 5a8b (0) 5be6 (0)\n006 0 | 0\n007 0 | 0\n008 1 5cc1 | 1 5cc1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","private_key":"59601d5a451dc893a0eacd7c9a58064f127f7a6006cb91d3ce285e840eba9ccb","name":"node_5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","services":["streamer"],"enable_msg_events":true,"port":44553},"up":true}},{"node":{"info":{"id":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","name":"node_4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","enode":"enode://da0cf3977228d65352ccef3b882334d901b72fbb167e3f5b4c45f62e52526ed3eb3d50ec8227e9d6b8c14a9d43a769265337e2a228575b810b885e3db5eb2f49@127.0.0.1:0","enr":"0xf88fb84051a2a5e0e8760be8f291be6f24a97796a1aee5a826d1d5b7b7736aba877749a15622871be3c2e8363c03a126114650ad0459f143f01b34abc25b3c1c909a34d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103da0cf3977228d65352ccef3b882334d901b72fbb167e3f5b4c45f62e52526ed3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R0Y3khK5HuHBPBM26POnOoRAi3Y2wiLBG9J859ck5sY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 474637\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b245 ce01 fac8 f4a0 | 60 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n001 7 184e 1929 127c 0e34 | 30 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n002 4 672a 64e6 72a5 75e2 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 2 51c2 5c62 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 7 4bc8 4a37 4a3c 4efa | 7 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 459b 4589 | 2 459b (0) 4589 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 4775 | 1 4775 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","private_key":"7f51642b5475141f99f5c1b1ae83d37f562df9bc05930b615f2d9e36c631eb09","name":"node_4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","services":["streamer"],"enable_msg_events":true,"port":42479},"up":true}},{"node":{"info":{"id":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","name":"node_ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","enode":"enode://69f46f822ed108a3341c1b99942e66e6fdcd74e0d37a20ab54831a0ef22b1686782dd6547d34e038a8402a5d39fca494365e445c5e24646340677ee07478b1d1@127.0.0.1:0","enr":"0xf88fb8403cf3999ab1acccd527ca14d5712142e6de9dbe055b041c09ed9a97c8c904c3615dd568f79fba4871ebba52e4d28fc8645c9db1fe5fa6bcb3534dc7ed8079b5d80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10369f46f822ed108a3341c1b99942e66e6fdcd74e0d37a20ab54831a0ef22b1686","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7S7GaBvzJYh3aHA3eczzpieHMRGM0+yJBJCj3lD2iaw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed2ec6\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3775 36d5 72a7 4589 | 68 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n001 4 b355 b869 be0f bde9 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 10 d23c d18a d125 dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 8 fa65 fa9a fac8 f33c | 9 fa65 (0) fa9a (0) fac8 (0) f177 (0)\n004 1 e06f | 1 e06f (0)\n005 2 eb01 ea3d | 2 eb01 (0) ea3d (0)\n006 2 efd6 ee2b | 2 efd6 (0) ee2b (0)\n============ DEPTH: 7 ==========================================\n007 1 eceb | 1 eceb (0)\n008 0 | 0\n009 0 | 0\n010 1 ed12 | 1 ed12 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","private_key":"1f0f2deaf715e265a0dc7e04ebce7f7ab8f71ce370739dbb27f3a69c46cf5ed5","name":"node_ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","services":["streamer"],"enable_msg_events":true,"port":36339},"up":true}},{"node":{"info":{"id":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","name":"node_36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","enode":"enode://ece93da9ec83a6c37b2bd0240c13c80cf1a175d1883e1881c7cc9122756be72dc17964a01f72b5e570f8948296665c11f34a28691feb337825be71830dd71aa4@127.0.0.1:0","enr":"0xf88fb8400bb1875a3bb9340c4f3442f8cb86cc57892d5c1f6f6149b97ce85a88fe97d6bf3fcef5348de2c000530c8320f52890fd28a31a6393aa7f7d304e3574646bf6ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ece93da9ec83a6c37b2bd0240c13c80cf1a175d1883e1881c7cc9122756be72d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NtWVJoXJXkK+8U93tjcFiXynHSTSHk6e/HctnKvSESI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 36d595\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f005 e06f ed2e d23c | 60 9472 (0) 957e (0) 8d3e (0) 8fb8 (0)\n001 10 64e6 7bee 4d75 4a37 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 5 0e34 0a21 127c 1929 | 13 01a6 (0) 03eb (0) 034d (0) 0639 (0)\n003 9 21dc 216e 2354 2471 | 11 2dd4 (0) 2d53 (0) 2803 (0) 21dc (0)\n004 3 3e19 3871 3b83 | 3 3871 (0) 3b83 (0) 3e19 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 3590 | 1 3590 (0)\n007 1 3775 | 1 3775 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","private_key":"6f7f6fa8cf239e96150cce6db5caa458629888f8f5f726b8cc6bbcbe09dfcb2c","name":"node_36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","services":["streamer"],"enable_msg_events":true,"port":34495},"up":true}},{"node":{"info":{"id":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","name":"node_cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","enode":"enode://49eae8779e617a7104cbd74223738ff9b987295433994660ab89955cd4e1fb8bbce3608ed7e0acb995c78f652e038d6b6ae87a9ce968bd82de552f8b86994ff2@127.0.0.1:0","enr":"0xf88fb840c2b4c4f501dbf7f98654d927a7fb975ad27786b3cbc874c1994dfc8cd97b89522e882d0fc4258d3d6c928f131df7e96aff65485d5b56a5f54d0e0938ea80751f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10249eae8779e617a7104cbd74223738ff9b987295433994660ab89955cd4e1fb8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yr/ft4nMIJYuq6Hb5o1twEZuaZ0i3Fsp8npc1VU5h5U=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cabfdf\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 52b4 36d5 | 68 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n001 9 8012 8330 b4e2 bd96 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 6 fa65 f611 f3d5 efd6 | 17 fa65 (0) fa9a (0) fac8 (0) f177 (0)\n003 4 dd92 d125 d18a d23c | 6 d9d3 (0) deec (0) dd92 (0) d18a (0)\n004 3 c52a c2f9 c0ad | 3 c52a (0) c2f9 (0) c0ad (0)\n============ DEPTH: 5 ==========================================\n005 3 ce01 cc9f cc5f | 3 ce01 (0) cc9f (0) cc5f (0)\n006 1 c9ef | 1 c9ef (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","private_key":"50c1b7e67b07c5e3e977aa0690b20a2bcc1ffea472bef560311f987eda352d1d","name":"node_cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","services":["streamer"],"enable_msg_events":true,"port":32801},"up":true}},{"node":{"info":{"id":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","name":"node_d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","enode":"enode://59e6798c8baabbf319576e50e1a709538aa094df1468e5a787b1593fc175622fdb8c56a5b1fea1b6ddfdb8099c602aa7d542cfcc0736b0f8e90761c1672a0057@127.0.0.1:0","enr":"0xf88fb8406107c3f070686e09872ca8a041ab9bbb404d2aca874e09f6dc628aa7efcfe23f671b20e5d229ff36fce675f9954b02e453337d800619251a0ffa0a997c4604ed0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10359e6798c8baabbf319576e50e1a709538aa094df1468e5a787b1593fc175622f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0jyXvrzeJvXjUcS5dcdqr2BP0gb5uQY+y9pTjnpS9RQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d23c97\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 3e19 36d5 184e 1929 | 68 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n001 6 8284 8012 957e b4e2 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 7 ea3d ed12 ed2e efd6 | 17 f177 (0) f005 (0) f33c (0) f3d5 (0)\n003 6 c2f9 c0ad ce01 cc5f | 8 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n004 3 d9d3 deec dd92 | 3 d9d3 (0) deec (0) dd92 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 d18a d125 | 2 d18a (0) d125 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","private_key":"7ef7bc7466fca587aab3f839ece8ec307619523af4dc22ab14b3129c81978144","name":"node_d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","services":["streamer"],"enable_msg_events":true,"port":39477},"up":true}},{"node":{"info":{"id":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","name":"node_a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","enode":"enode://3c5d51d426ffa9069eae24c2f0c108b2f543255bbef13b8ddf2a2dfdd34bf1fee87505e6163e90fa9f7432ec9865f90490aefc0bbd8049fddf18d8eecd8bb076@127.0.0.1:0","enr":"0xf88fb840c935263f2fe7bcceed68a1f97aa98b1f4898056415975bfe6af3a937a3e8afbc664cfe541a801aa79c8a84efac3ec10512e3c34b32d5fa16b9383f850a5ca9bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c5d51d426ffa9069eae24c2f0c108b2f543255bbef13b8ddf2a2dfdd34bf1fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oZKfcEZkyoXYKaw7q2LmiGR6fP3LyfA8YbASTPkJNQU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a1929f\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 2471 184e 68a6 6450 | 68 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n001 11 ee2b ea3d e06f f611 | 31 f177 (0) f005 (0) f33c (0) f3d5 (0)\n002 3 9472 8012 8330 | 9 957e (0) 9472 (0) 8b35 (0) 8d3e (0)\n003 9 b355 b245 b4e2 bde9 | 14 b245 (0) b355 (0) b60e (0) b5fc (0)\n============ DEPTH: 4 ==========================================\n004 5 aba7 a9fa a861 aedc | 5 aedc (0) acf8 (0) aba7 (0) a861 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","private_key":"9037f029de76f869c02e95928a58d061068ff690b7a5ce42fe021987910ec074","name":"node_a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","services":["streamer"],"enable_msg_events":true,"port":42239},"up":true}},{"node":{"info":{"id":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","name":"node_52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","enode":"enode://fc05173b55aa81517b3ac06d2d7c2c6a7f3ce4a2b37780ab5111f90a2d537c3081147d82c05d274eee69f1576a40da8d1065dd9f951547cb1c072f2748bae488@127.0.0.1:0","enr":"0xf88fb840b0c717a2ac8079ccf35009302f2fdb71fc7d427791e0db68bd05457b484f738c6c8cba664f215e4772f08a743818e428827b0dbb2e2b213bd427367bd64659900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fc05173b55aa81517b3ac06d2d7c2c6a7f3ce4a2b37780ab5111f90a2d537c30","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UrR9Ur9KGv2hYEt5QgGcjSrEx2DF60WX4c4t16jhz00=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 52b47d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 cabf d23c fac8 ea3d | 60 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n001 4 2803 36d5 3e19 184e | 30 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n002 7 7bee 75e2 72a5 68a6 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 6 4efa 4c21 4d75 4bc8 | 11 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n004 4 5be6 5a8b 5cc1 5c62 | 5 58a9 (0) 5be6 (0) 5a8b (0) 5cc1 (0)\n005 1 55fd | 1 55fd (0)\n============ DEPTH: 6 ==========================================\n006 2 5008 51c2 | 2 5008 (0) 51c2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","private_key":"a160ffd0d147d08006e444e85b70fb9e8f982c3e0a7ad72f8005d6a040a65682","name":"node_52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","services":["streamer"],"enable_msg_events":true,"port":37611},"up":true}},{"node":{"info":{"id":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","name":"node_e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","enode":"enode://c527957ba9cb7743e768b25580478414c9740bf57540523a69f55a7e40c6e1d5f2f53b2d72c9e017219e008e4c68cc9f6f9209d12dbe5e617557b73b0c465cab@127.0.0.1:0","enr":"0xf88fb84055bcf73035487cb5632f8ed4d3f298da2d47da173342acd58a537bec7b17f1981d6d0060dff9891b4f3b79168a713b0ea134bf4a724cea40a0a0a20e9df661980183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c527957ba9cb7743e768b25580478414c9740bf57540523a69f55a7e40c6e1d5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4G9YsUT6plD5ZGWCXSU7Y9fgYeOjxCKK1eG2Za+8zDc=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e06f58\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 2d53 2803 3e19 36d5 | 68 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n001 7 836e bde9 b4e2 b245 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 3 d18a d125 dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 4 fa65 f611 f177 f3d5 | 9 f177 (0) f005 (0) f33c (0) f3d5 (0)\n============ DEPTH: 4 ==========================================\n004 7 ea3d eb01 efd6 ee2b | 7 efd6 (0) ee2b (0) eceb (0) ed12 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","private_key":"1fb267b5c56dc43486cd338b223dbdd81bbe0d2ca10ce150e87fafd8ea7fb55d","name":"node_e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","services":["streamer"],"enable_msg_events":true,"port":36611},"up":true}}],"conns":[{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_16.json b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_16.json index e818da05..e209f568 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_16.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_16.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","private_key":"3ff3a0c7dc8b63cac9255233d84cccad53d61f8c9e47539329c07e4f248fc6dd","name":"node_279f0a191892115b8db4e2689cc5e1bc19019e8f5228f4f093f35c48fa2f606fd00a2ec5cf0fa4657ad3606e14643c3be8d49350ad2673f2ad12e17c0174b0d8","services":["streamer"],"enable_msg_events":true,"port":62851},"up":true}},{"node":{"config":{"id":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","private_key":"1ab5fd3f1885661af1829b42683ca1379ca90b1b2c5a0132027346c74001a154","name":"node_2c3d17a3b019d9d32922f06aef03ac03f67777e382f0b86c6e4dac07e590f2dbf4cbd1cc7ed136b52bba897e7163dee926caa627111db6d948581ad1b2edbc3f","services":["streamer"],"enable_msg_events":true,"port":62852},"up":true}},{"node":{"config":{"id":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","private_key":"a90fea5197ac84a162db7a06ec739e075ee334026e792d83a3269526888c8b5d","name":"node_6e327c2d9d3ffdae707ed067d15b83ad0ea81b96bb2a07331436f01c1e194ed90f630ef0eb6511f4849ede30c403e3c4ff3c2cb8021317de97f3ed5b1d990f49","services":["streamer"],"enable_msg_events":true,"port":62853},"up":true}},{"node":{"config":{"id":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","private_key":"76b6f09c28f5568e7724e9850116bdbd6356152fefedc4b0a9747361d712964b","name":"node_9aa1df8ddddd035e81ffc950f063714c3b6be24013108f8b99c32c25fc3a8582904f68c73fe63ebfb96143a12ab398f36c4070a3055c039491ca2f20be6774c2","services":["streamer"],"enable_msg_events":true,"port":62854},"up":true}},{"node":{"config":{"id":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","private_key":"f7e7d60abb7d43d973131804e684ec99e77e81bf38165dda29f3ae026eb169f1","name":"node_a1226991909b92dd4f22150b798e2b6312ffc62bad7a47d250e811c7e60cf5ceb6a87998f295e0bd392c0f5c15213115000781e498dd7eae79b67c7e7e19cf81","services":["streamer"],"enable_msg_events":true,"port":62855},"up":true}},{"node":{"config":{"id":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","private_key":"f88cd88c2c219d13b699ba7c7cf9adf16fc10be5d8e1f35b2ea260e7987ab76e","name":"node_1dcbfc79418f9a665e3154e07663b296ce086e54c23458b7113a011dca62e635245cab144d392716e5e90b60336b60927270b72bb4a1c5c85fbf959060fb3ee4","services":["streamer"],"enable_msg_events":true,"port":62856},"up":true}},{"node":{"config":{"id":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","private_key":"8fa1673a72b2ab000a4a7c8ad4540484d5286b69c93a5c608ef0977f783b7c4c","name":"node_571afb6ce94d28cb7d5cd49b3af35d2b1e44c917a9d3d207ab6c7ae960eb625377334e62317f6c69b3004e2eef92682649df828f4a645a75309ee7014ee4a940","services":["streamer"],"enable_msg_events":true,"port":62857},"up":true}},{"node":{"config":{"id":"615c7fcf7a80635e42719c0ae1fb924ba703ee39e021898be56b81ef0f575f62","private_key":"daa9c74fbb0b897acdf20f1b955a608b086ce5b45dc8e2b76a44f277d25e3377","name":"node_f1e669bb6e5b89c04e07e3dcdc445d498ac54c8ab2e9a62e622a492b6f9781bfa27f75ef7448d06caa28d9afa40c1c089066358cbcca40018bc0f903eab9508e","services":["streamer"],"enable_msg_events":true,"port":62858},"up":true}},{"node":{"config":{"id":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","private_key":"eb94b600be5949e3ca545e81b4d0a5fff3ae9f51f63c722d10f5098f9e1a883a","name":"node_526d25e0aa47e64d8f681255348a3d3c94fc68bedcb7111532f4ed50d47ef064b1e97e3a6bcd13ac8eaf44ce676b22d2b343a94dfa38b48cf964bfc3f338d4bd","services":["streamer"],"enable_msg_events":true,"port":62859},"up":true}},{"node":{"config":{"id":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","private_key":"4e5d074bc46efbd0d18310e6a74e72e98b92080329d9c4e2b5ae99eb2fcfaf89","name":"node_fa81c440829adcbb3eba9196dc8255e319a976e53db0aceedcda25c2605f21b8778bf8c89e08744f7455c909568855f2a5be7bc88646796d21598ddda810390a","services":["streamer"],"enable_msg_events":true,"port":62860},"up":true}},{"node":{"config":{"id":"6d8b6881d36bc5f4a4a82f5d707807af2eef2eaf4527eb6b16f62cd75a92bb8c","private_key":"73c752d26f3438acdc54e9eaae6b1194d3706c65932939a593f1c8c5d451daf6","name":"node_5702eeccd7cb8c18dd25e5700919a544fb5e15fd53c5d4b56226021a9031a2206a694eb3b7334e4bd24fc510f7c1ea4f7a98e17e3394b4bd8d356a4d048b47dc","services":["streamer"],"enable_msg_events":true,"port":62861},"up":true}},{"node":{"config":{"id":"55cc9bd08390eec7bc050924e3011b251c6c4e088ac2adda27493064b75f0ab8","private_key":"2e6321d9dda81fc0f863f09868b280dea3300105cf9d224294aa138caf10b4a6","name":"node_6311f5a830849b47094d84129fd987fcd3d511d000bf0a8b888c9a457545950fdae6ae10a2a85b47721a1d1ece8c1c62d866a26577380048d30f205c4e7cd7e8","services":["streamer"],"enable_msg_events":true,"port":62862},"up":true}},{"node":{"config":{"id":"a873e971042dfd5aaeb56d7d9089e35bc8dd410451a66740ebe7ea0752870120","private_key":"200b7caaf8a33b8ea47947eb842fb8d8aac90951c70bb2f555f902380eb7f1ee","name":"node_dbef367277df652c8d3380efcf5f9d445d77fa6e7957b50b2467f90b7190e70d4eb4febbbffa6b3fc2b04bbf74dc7191e2b98923c3a62ecb80ba5336195994c7","services":["streamer"],"enable_msg_events":true,"port":62863},"up":true}},{"node":{"config":{"id":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","private_key":"b58a24805bb0c417e5666f2bf3f3342b8359d3c0d30a631c0104fcdfb6d0809b","name":"node_a4cdf723b3d7ead36bcb1bba582c8758271d5f08651694e1def0ae2ceca079d4fca81730a84a14749a81bc3ea41a66f1320788310823de5d1ceecd608ed5b88e","services":["streamer"],"enable_msg_events":true,"port":62864},"up":true}},{"node":{"config":{"id":"fc373cf4e892501073ed87b98231f0d001e6db70a1a08148035fbdfa2dffb3d3","private_key":"422d3b2c1b37b851ad524c8f26700fb5eec0d9a2fff1cb157ae931baa52d9521","name":"node_67cc8be0fd092c82e53efc53c418db257eff1135ad0058fd10e3eb77b205cb3e6fa87dfed4ec008c371f77546d4c117d8c34734bfe594da4c96fc08e0d2ede32","services":["streamer"],"enable_msg_events":true,"port":62865},"up":true}},{"node":{"config":{"id":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","private_key":"7871010c8b88b9594c71b9f43aecfefdca39da348e31f47ef2645c20c100d072","name":"node_4da7d1c9577afb52a5fe1de9f99824ceff314828c581caed8a3a33168df699d7b3befb4e888419264a9eeb3c9e5e9dac468e01edd71eb6f0ef41d15f7651042d","services":["streamer"],"enable_msg_events":true,"port":62866},"up":true}}],"conns":[{"one":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","other":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","up":true},{"one":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","other":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","up":true},{"one":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","other":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","up":true},{"one":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","other":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","up":true},{"one":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","other":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","up":true},{"one":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","other":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","up":true},{"one":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","other":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","up":true},{"one":"6d8b6881d36bc5f4a4a82f5d707807af2eef2eaf4527eb6b16f62cd75a92bb8c","other":"55cc9bd08390eec7bc050924e3011b251c6c4e088ac2adda27493064b75f0ab8","up":true},{"one":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","other":"615c7fcf7a80635e42719c0ae1fb924ba703ee39e021898be56b81ef0f575f62","up":true},{"one":"615c7fcf7a80635e42719c0ae1fb924ba703ee39e021898be56b81ef0f575f62","other":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","up":true},{"one":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","other":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","up":true},{"one":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","other":"6d8b6881d36bc5f4a4a82f5d707807af2eef2eaf4527eb6b16f62cd75a92bb8c","up":true},{"one":"a873e971042dfd5aaeb56d7d9089e35bc8dd410451a66740ebe7ea0752870120","other":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","up":true},{"one":"55cc9bd08390eec7bc050924e3011b251c6c4e088ac2adda27493064b75f0ab8","other":"a873e971042dfd5aaeb56d7d9089e35bc8dd410451a66740ebe7ea0752870120","up":true},{"one":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","other":"fc373cf4e892501073ed87b98231f0d001e6db70a1a08148035fbdfa2dffb3d3","up":true},{"one":"fc373cf4e892501073ed87b98231f0d001e6db70a1a08148035fbdfa2dffb3d3","other":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","up":true},{"one":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","other":"a873e971042dfd5aaeb56d7d9089e35bc8dd410451a66740ebe7ea0752870120","up":true},{"one":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","other":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","up":true},{"one":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","other":"fc373cf4e892501073ed87b98231f0d001e6db70a1a08148035fbdfa2dffb3d3","up":true},{"one":"a873e971042dfd5aaeb56d7d9089e35bc8dd410451a66740ebe7ea0752870120","other":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","up":true},{"one":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","other":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","up":true},{"one":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","other":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","up":true},{"one":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","other":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","up":true},{"one":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","other":"fc373cf4e892501073ed87b98231f0d001e6db70a1a08148035fbdfa2dffb3d3","up":true},{"one":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","other":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","up":true},{"one":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","other":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","up":true},{"one":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","other":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","up":true},{"one":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","other":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","up":true},{"one":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","other":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","up":true},{"one":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","other":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","up":true},{"one":"a873e971042dfd5aaeb56d7d9089e35bc8dd410451a66740ebe7ea0752870120","other":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","up":true},{"one":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","other":"6d8b6881d36bc5f4a4a82f5d707807af2eef2eaf4527eb6b16f62cd75a92bb8c","up":true},{"one":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","other":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","up":true},{"one":"55cc9bd08390eec7bc050924e3011b251c6c4e088ac2adda27493064b75f0ab8","other":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","up":true},{"one":"615c7fcf7a80635e42719c0ae1fb924ba703ee39e021898be56b81ef0f575f62","other":"6d8b6881d36bc5f4a4a82f5d707807af2eef2eaf4527eb6b16f62cd75a92bb8c","up":true},{"one":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","other":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","up":true},{"one":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","other":"af99d46c187735ff037e1264f2dbca2985694d906de0e2c9e52d5513a6feb331","up":true},{"one":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","other":"55cc9bd08390eec7bc050924e3011b251c6c4e088ac2adda27493064b75f0ab8","up":true},{"one":"615c7fcf7a80635e42719c0ae1fb924ba703ee39e021898be56b81ef0f575f62","other":"55cc9bd08390eec7bc050924e3011b251c6c4e088ac2adda27493064b75f0ab8","up":true},{"one":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","other":"9121c3fea7ccc99775fb5ade460f7a0cb76003231d13d44ed3e4f3cca1947227","up":true},{"one":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","other":"f64d3106d2bb99e69e26c07de168f7fceaf85672859f7c1c038fd4dd6b6d7588","up":true},{"one":"6d8b6881d36bc5f4a4a82f5d707807af2eef2eaf4527eb6b16f62cd75a92bb8c","other":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","up":true},{"one":"fc373cf4e892501073ed87b98231f0d001e6db70a1a08148035fbdfa2dffb3d3","other":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","up":true},{"one":"3c4287b7722f71eb03a3d54fb6b18aeb0bf8495cffbe8c103fe90229f08392ca","other":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","up":true},{"one":"615c7fcf7a80635e42719c0ae1fb924ba703ee39e021898be56b81ef0f575f62","other":"4ce65548fc8490c02e4c6c0549be7329a8a05c090d62870ad1075e52e204a3b5","up":true},{"one":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","other":"9fcdef2b818e8a4fcc07fedb706d9f88cc59703230af4f52043c84f9bd37cc57","up":true},{"one":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","other":"a3790562c8209b7e96e7abef9ad28de2e470a01927234e4848966e0cd15652e9","up":true},{"one":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","other":"91129c7135bff2b7cb1e1162bdd5399192790bdb4fc2eaa5b4cea53fe7a69d8c","up":true},{"one":"8bf97ec29b6b3ca638ed82fa30d03d0d8309c9e8f1db2071f4a37de805327108","other":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","up":true},{"one":"84842bc52628c0bed88539ee40f211de307b3e728ab5c0ca78032b86028b49db","other":"fb555885b96d5742a10e688bd7c1bb842f0434c319bf076d07f545e4c0550601","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","name":"node_427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","enode":"enode://7f2eecc4ffd81993f1f7f961ca00f52eacd77fb52f215cea32246a5742deb627c6b2be0a2112d7114b5d26a898de7c6dcfe18595458e0f50181497fe5631ba8a@127.0.0.1:0","enr":"0xf88fb8408e4b56b8de4863c72f40c38f16925319181e8079bc13b5b14c5ac1626070b4670ff42821d18b044558b1a6e81c4e6afacbcd917915b9c26b325e1775ec15fea00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027f2eecc4ffd81993f1f7f961ca00f52eacd77fb52f215cea32246a5742deb627","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Qn4CiLWkdNlwTfR78uuXuK+Xm9oZn4a3vViCSTOVgSc=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 427e02\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a010 c55a | 9 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n003 1 5942 | 1 5942 (0)\n============ DEPTH: 4 ==========================================\n004 2 4ebd 4c14 | 2 4ebd (0) 4c14 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","private_key":"2939b9a1fe2ce1f27e9d22f9f00cb77563507ca8b5a62bb93fe2a7e1dd5daf4b","name":"node_427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","services":["streamer"],"enable_msg_events":true,"port":39289},"up":true}},{"node":{"info":{"id":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","name":"node_c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","enode":"enode://0e17a602ec55b9499390093d13ef045635eb8b755783f80b0bd57c784cc2a6d52901b4170ec9202ce13084de51eafb9ab6d225f9e83266f280649eecbe332b47@127.0.0.1:0","enr":"0xf88fb8408658caccb6f16b440efbf35061f2e13adc4b3b4469df310a00d8801f752ceed24190e9a75879b496bb999add5be68c8d03127351456f69a3e45a6810f3f1e2900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030e17a602ec55b9499390093d13ef045635eb8b755783f80b0bd57c784cc2a6d5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xVoXaxwYXlJuF9KsJVbll5a8HTprgU7s2wypUZyMUWM=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c55a17\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2653 427e | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 bdf0 a010 | 4 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 d6f7 dd12 | 2 dd12 (0) d6f7 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 c5bf | 1 c5bf (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","private_key":"0cb4fe0b34f942bcabc5485300829a5110c4ed6571e8064f63c88fcd1669485f","name":"node_c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","services":["streamer"],"enable_msg_events":true,"port":46727},"up":true}},{"node":{"info":{"id":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","name":"node_2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","enode":"enode://fd7a5476ddb69019642a906aa79f22a853228df3bc57104c329683b8dd0c70f2a329ef7ec24ef92baa6a39c8abac12cf16a916cc605aecc84e4ab1fc52bbd87b@127.0.0.1:0","enr":"0xf88fb840b9c3ae42b41ec15fee9985def0ab98f7ddf14501eb0963671e974ced1c9f4ad963ed4466ac5d767f55188b6ab91097e0848f8d7a65d532f5d31bd1d78f36c2570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fd7a5476ddb69019642a906aa79f22a853228df3bc57104c329683b8dd0c70f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JlPD140cEf06noBDrlx3A3sB4F3dKj1PYoSETQmKI+U=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2653c3\npopulation: 11 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 95b4 edd7 dd12 c5bf | 9 bdf0 (0) a010 (0) a61c (0) 95b4 (0)\n============ DEPTH: 1 ==========================================\n001 5 427e 4c14 4ebd 5942 | 5 6ff9 (0) 5942 (0) 4ebd (0) 4c14 (0)\n002 1 0d52 | 1 0d52 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","private_key":"35e97c6f9bf750dbe7d8d2c5bb9c3021af68e2d9143010fabf1934073a446c5d","name":"node_2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","services":["streamer"],"enable_msg_events":true,"port":36223},"up":true}},{"node":{"info":{"id":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","name":"node_95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","enode":"enode://3903c8019e85c8d7fe4bca9363b929984a2dcda6c45c42bd8deb02e8128dc87b22db7eb84d96815d349e4cc6e7aeebca10fcf2303783e19b4601e36970874caf@127.0.0.1:0","enr":"0xf88fb8407a344f969c3c14d7152c36b0e5fff71c51a514bbb1725b08f74462b88f3e9d197e473c1d43512ee405d57c7a77b17f38e61e96315f31afa03ec6d07390a839c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033903c8019e85c8d7fe4bca9363b929984a2dcda6c45c42bd8deb02e8128dc87b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lbSKnRlPQrjxnvjM3jN80iFSXgSEhDGm2EP/lopfTfU=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 95b48a\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5942 2653 | 7 6ff9 (0) 4c14 (0) 4ebd (0) 427e (0)\n001 3 dd12 c5bf edd7 | 5 edd7 (0) dd12 (0) d6f7 (0) c5bf (0)\n============ DEPTH: 2 ==========================================\n002 3 bdf0 a010 a61c | 3 bdf0 (0) a010 (0) a61c (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","private_key":"d3b3aee83368bb48feefe0e7782a19a55e4d210864402337e2117313dcd5b189","name":"node_95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","services":["streamer"],"enable_msg_events":true,"port":38325},"up":true}},{"node":{"info":{"id":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","name":"node_594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","enode":"enode://6718e290bc219c921b7b7fa26a7c29176e3175c6eaf273a80bb13b4edc560ff829385aba50dd0171f098716ad83eece60222801b9a074f9c926980dd93813aa3@127.0.0.1:0","enr":"0xf88fb84035a56b10844271058e2d9ca9b3e3c67de90a8c8323d7e5f8531f02952e855a5c0aa53aeb41b6de4638cf94d7301476ccd46e9bdea86f61ef61d97d22957a23a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036718e290bc219c921b7b7fa26a7c29176e3175c6eaf273a80bb13b4edc560ff8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WUIDyPoXC+zh6xKsVpsXMbhqYD0H9QIqfXsr8gX8YVE=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 594203\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 edd7 95b4 | 9 edd7 (0) dd12 (0) d6f7 (0) c5bf (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n============ DEPTH: 3 ==========================================\n003 3 427e 4c14 4ebd | 3 427e (0) 4c14 (0) 4ebd (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","private_key":"fefef9454f2f776b9e1f7baffba1b6008e32ec48486a4183819a5d611d5a4928","name":"node_594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","services":["streamer"],"enable_msg_events":true,"port":37077},"up":true}},{"node":{"info":{"id":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","name":"node_4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","enode":"enode://4d2df1c9d3ed42f561416caf0af60ff21b68e7a24e706595f10893a5cad5c13f5f4f0fe27897ed3eb1717b4e3444574b129900211652b85a56bd9c7bd13cc460@127.0.0.1:0","enr":"0xf88fb840633f9b9c1dce11bb4eb9f00b99b7f31aecc61374fc1ed19ceb3bd40f45a3ba4236f7623af2e69b74ca218e371d317023ae589c23ca11949cb431bfe36defd40f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024d2df1c9d3ed42f561416caf0af60ff21b68e7a24e706595f10893a5cad5c13f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Tr2hznl2ESnOhy9QvqmuLfOdR+TNeh2PG7mIyCuGZ6k=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4ebda1\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 edd7 a61c | 9 edd7 (0) d6f7 (0) dd12 (0) c5bf (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n003 1 5942 | 1 5942 (0)\n============ DEPTH: 4 ==========================================\n004 1 427e | 1 427e (0)\n005 0 | 0\n006 1 4c14 | 1 4c14 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","private_key":"1f13487aa3f685a730149f567e1e95ab7ea53d54717151390b1bf8d236ac93c1","name":"node_4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","services":["streamer"],"enable_msg_events":true,"port":45609},"up":true}},{"node":{"info":{"id":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","name":"node_a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","enode":"enode://16e487d4bc68f28f54477a9bf864b80c62a2802f4f902e69be114c51e8c756ee5e4cda3d522050beb554d731c791ca777cf2a0db1612513434577336ce2f6a16@127.0.0.1:0","enr":"0xf88fb8404beea9a3e5a8fddfbb54ee788fd2b1c2908f9d0c50c1807416315024e491dc9702a1a7a778d302e03937e2bde114fb8d8246f39b32e8e5785147f7eb15f988d30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10216e487d4bc68f28f54477a9bf864b80c62a2802f4f902e69be114c51e8c756ee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"phwP5UGlYrCNkvq9ZDpIaU+/uvcE0ceCWVrQ6Td6BrY=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a61c0f\npopulation: 7 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0d52 4ebd | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 d6f7 edd7 | 5 edd7 (0) d6f7 (0) dd12 (0) c5bf (0)\n002 1 95b4 | 1 95b4 (0)\n============ DEPTH: 3 ==========================================\n003 1 bdf0 | 1 bdf0 (0)\n004 0 | 0\n005 1 a010 | 1 a010 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","private_key":"aca753870ec0d4820df685f13895e1e883e0c533dd949d7957b54a7278e2fa2f","name":"node_a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","services":["streamer"],"enable_msg_events":true,"port":36847},"up":true}},{"node":{"info":{"id":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","name":"node_a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","enode":"enode://da90e12ec1d6737b50a34a3ee3e75fa3e164a4c510506bad503721813291f09bad6b8f3008810a6e738d31e6365ca2a56a278477d23fd18e86e258dce44ab378@127.0.0.1:0","enr":"0xf88fb8404256771ae0b0cd6d23b73a6df956fef179cccc697e78699e807513021fa9c80a4ddd2398cd82f160a433345b7ca8f651ef08d43e87416be27744f146f325e7c10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102da90e12ec1d6737b50a34a3ee3e75fa3e164a4c510506bad503721813291f09b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oBCdbEGjF+hX8ynzCJj3Mo3TgS0fxwCKaP445tgEt6I=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a0109d\npopulation: 11 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6ff9 4c14 427e 0d52 | 7 6ff9 (0) 5942 (0) 427e (0) 4c14 (0)\n001 4 dd12 d6f7 c5bf c55a | 5 c5bf (0) c55a (0) d6f7 (0) dd12 (0)\n002 1 95b4 | 1 95b4 (0)\n============ DEPTH: 3 ==========================================\n003 1 bdf0 | 1 bdf0 (0)\n004 0 | 0\n005 1 a61c | 1 a61c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","private_key":"2def6be33926ceb95119b6eef9b225e963b37378a26743dd6dea6f52e6b188ed","name":"node_a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","services":["streamer"],"enable_msg_events":true,"port":46777},"up":true}},{"node":{"info":{"id":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","name":"node_0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","enode":"enode://3c12b2884039d0d47926d5fe5fe932ed2231c1df1e29c39ec02452bdfd172fee3db62b4568adc560ddbf71cce469b473e124fff10b3f083910526d18b33c42b2@127.0.0.1:0","enr":"0xf88fb84051550b2edf140f46ee64c9c9fad39caafba3103379cfc9b363025cdafb9002d0665ba3a2c0f0701f0e80299e78c9ab7930d8e19fb5251a0406408d5d5bf95cae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c12b2884039d0d47926d5fe5fe932ed2231c1df1e29c39ec02452bdfd172fee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DVKdFGR0NnXZH8QEnXD0KLMm84TojqFMU/8jouRaZb4=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d529d\npopulation: 12 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d6f7 dd12 edd7 bdf0 | 9 c55a (0) c5bf (0) d6f7 (0) dd12 (0)\n============ DEPTH: 1 ==========================================\n001 5 6ff9 5942 4ebd 4c14 | 5 5942 (0) 427e (0) 4c14 (0) 4ebd (0)\n002 1 2653 | 1 2653 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","private_key":"be1de243c5450fb51af634ada17a96c06515fbca77202cdd848c126934749c1b","name":"node_0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","services":["streamer"],"enable_msg_events":true,"port":34387},"up":true}},{"node":{"info":{"id":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","name":"node_bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","enode":"enode://4410ea88db94cde9ffbf85ead5e867e226979f908d82cb1f3d8583ead0e2ca4a3ba5a2f016df89ec0f0d76c3dccddc0b68a9df33783ed942d3df6f138e8169d8@127.0.0.1:0","enr":"0xf88fb8406f933c472c99bd51a9e066d03732148e70013d2eadb5a57bf1ca3d7f0c2266140e8626ff05a46e283a22ff5e16c10fecd00ae7bcbd2e746440733bbeca6c78940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024410ea88db94cde9ffbf85ead5e867e226979f908d82cb1f3d8583ead0e2ca4a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vfASJpjJ2jE3QNLJhUrFwXfGPNzJXjq0Fe7W7r1mFLY=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bdf012\npopulation: 7 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6ff9 0d52 | 7 5942 (0) 427e (0) 4c14 (0) 4ebd (0)\n001 2 c5bf c55a | 5 c55a (0) c5bf (0) d6f7 (0) dd12 (0)\n002 1 95b4 | 1 95b4 (0)\n============ DEPTH: 3 ==========================================\n003 2 a61c a010 | 2 a61c (0) a010 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","private_key":"f89bc000169f6a15dd6881cb70ec8f841a60aceddbde85af267a2515c91e394b","name":"node_bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","services":["streamer"],"enable_msg_events":true,"port":40993},"up":true}},{"node":{"info":{"id":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","name":"node_6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","enode":"enode://6936d2429208f3e456ef654a7a0511e310ec4fb728a62d03861c0a4a8e9d22f5f0f3a90b8bf03d3654afb675e371e2bb5f7065f2662292078a5e3c73a0c9ee04@127.0.0.1:0","enr":"0xf88fb840f98c7122fa9802971ba1acc50caa9e447e49b0dbe4372fc40405128ca954f4dd07b794976a20880bfdd2a586adc2438ddd9e35fc93e6106371af5363ede39d2b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026936d2429208f3e456ef654a7a0511e310ec4fb728a62d03861c0a4a8e9d22f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"b/mj9vH4AZ42a1nM4H43N7Hm5LorTtkBLN0raDkIsAQ=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ff9a3\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a010 bdf0 c5bf | 9 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n001 2 0d52 2653 | 2 2653 (0) 0d52 (0)\n============ DEPTH: 2 ==========================================\n002 4 5942 427e 4c14 4ebd | 4 5942 (0) 427e (0) 4c14 (0) 4ebd (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","private_key":"1dd45d1d581cf612c3b51e58a8a76daac07d6c3e6060e9ebed1d697999257945","name":"node_6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","services":["streamer"],"enable_msg_events":true,"port":33543},"up":true}},{"node":{"info":{"id":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","name":"node_c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","enode":"enode://939e9a819895e0193947e390c9d561c3b1bca8eb6e19eaaef503a49b811b4e436932430dec5d7e01184cc7c7f4680964ccd2d7d1f31e6284148cb65190aea8fc@127.0.0.1:0","enr":"0xf88fb840aa054cfdc1388722d83c8026d2d2c4a9a79187fbcfef0e7cd0454597a55ce9e3129ffec027b96b03efabc975a4461caa27973336fd65caeb105a861e825e72b20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102939e9a819895e0193947e390c9d561c3b1bca8eb6e19eaaef503a49b811b4e43","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xb+GfJ7g24MVBDlbREp79sX2xtjQtsdBKW/KsDIISR8=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c5bf86\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2653 6ff9 | 7 2653 (0) 0d52 (0) 5942 (0) 427e (0)\n001 3 95b4 bdf0 a010 | 4 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 dd12 d6f7 | 2 d6f7 (0) dd12 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 c55a | 1 c55a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","private_key":"f55426e1ac52ab19cd155aeec3bf75415a3c75bfe89987b9747b3bb5cfe2ab54","name":"node_c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","services":["streamer"],"enable_msg_events":true,"port":38361},"up":true}},{"node":{"info":{"id":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","name":"node_edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","enode":"enode://4db77ce0656ae19063ee88a21dab483fc39b82eab3ce8a5a60287a32acd7585f163ee6ec724f66bcf40f40fec9cdb9e4e4c28ec4b7342960eeb505ac8de2d14a@127.0.0.1:0","enr":"0xf88fb840a6875960f8077f6e6a7f474110885c3e4748b3cf61e6348bd9b42efb3def651d35ab2bf6b780587204f2ae2b56019cbbe01464e2b2e221a3bc50d27052b963bd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024db77ce0656ae19063ee88a21dab483fc39b82eab3ce8a5a60287a32acd7585f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7deyKhf+w4JNd9uIK1+06CsIvsqNWeDy3Ikk971vjO4=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: edd7b2\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4ebd 5942 2653 0d52 | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 a61c 95b4 | 4 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n============ DEPTH: 2 ==========================================\n002 4 d6f7 dd12 c55a c5bf | 4 d6f7 (0) dd12 (0) c55a (0) c5bf (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","private_key":"e9fb7f15ab0c529f7fbd15c7fead7762c5ff8563f928d0c77e5fac982a5c6cb3","name":"node_edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","services":["streamer"],"enable_msg_events":true,"port":41753},"up":true}},{"node":{"info":{"id":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","name":"node_dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","enode":"enode://57d7341b933399ef218e3b4e9155299740435d8f39d51bcd55eb0e0206cf3872b5d8edeabcb29fc52a10fb13b2332945895992ed536818ae3d5ca724da435216@127.0.0.1:0","enr":"0xf88fb840be4d387446799bfc72ee406a3f5bff45cefff30cb27b353e2b5d804cffcf842f47af74326db8059b3f239b4aed3f7aaf70e88870dacc93c7700ecde11e125b2d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10257d7341b933399ef218e3b4e9155299740435d8f39d51bcd55eb0e0206cf3872","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3RID4AYNsanC1ABSB4dWrf227EhVlOQRapl7nbyvkAI=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dd1203\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2653 0d52 | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 a010 95b4 | 4 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 c5bf c55a | 2 c5bf (0) c55a (0)\n004 1 d6f7 | 1 d6f7 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","private_key":"1d61966a5bf6ace65cb3663c40fcf26e51904e8ac267f799ba3804f58bc2515b","name":"node_dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","services":["streamer"],"enable_msg_events":true,"port":36287},"up":true}},{"node":{"info":{"id":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","name":"node_d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","enode":"enode://ccca2d21c63669239abca558b432ffda2abd413d3b4564be1c878d3ef8658697d42ef55b3c5fd79afd363a5d60e776e162371e6f50f49b2d78005d54d1212ed7@127.0.0.1:0","enr":"0xf88fb840be7cf77f4591f92fcdb31616f1dd8a29cb45f576ab0ac5ca1336aa394c6c9aad15013911a39a06cf43a096dd158fe05af68f9b36e3e68ab1ffe4663d5519ce730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ccca2d21c63669239abca558b432ffda2abd413d3b4564be1c878d3ef8658697","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1ver1O99kUTidqW6P8QIfsoRBt6tMz86IZyhjirElCI=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d6f7ab\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0d52 4c14 | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 a61c a010 | 4 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 c55a c5bf | 2 c5bf (0) c55a (0)\n004 1 dd12 | 1 dd12 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","private_key":"689c424f352a14e065158f6edd016775422abd2ca2e3b67121797457f8cb6b57","name":"node_d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","services":["streamer"],"enable_msg_events":true,"port":45859},"up":true}},{"node":{"info":{"id":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","name":"node_4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","enode":"enode://55b49fb5af1798f20da9536cf2b6b9be5f8660d6def0b5ab2031ed6ae8e4041f0a8787aa1e58f5b493fcb8839bf95058e4955790e5723c6c088ae104d10b42c5@127.0.0.1:0","enr":"0xf88fb840b116a8086d357c160f4515a7f567b528bd41cbf6da84bc00623ea30cd4d4cf052ada52dcb295f404c509d1319cd51139b0d12e9ad279da4a31483922e11a73730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10355b49fb5af1798f20da9536cf2b6b9be5f8660d6def0b5ab2031ed6ae8e4041f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TBRKwvTuSoZTo2Bc7CAWA4TPRxof369pSnIXcKKSVDQ=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c144a\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a010 d6f7 | 9 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n003 1 5942 | 1 5942 (0)\n============ DEPTH: 4 ==========================================\n004 1 427e | 1 427e (0)\n005 0 | 0\n006 1 4ebd | 1 4ebd (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","private_key":"20caf36455148590aefee286656630f80eaf3452f0e12a90d0bec13e3319653b","name":"node_4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","services":["streamer"],"enable_msg_events":true,"port":43573},"up":true}}],"conns":[{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","other":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","up":true},{"one":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","up":true},{"one":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","other":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_256.json b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_256.json index df5f7f4e..5e400d92 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_256.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_256.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","private_key":"859f1f6b352bfdd6f8b7a7a80ef60a7fa41a514a091d5c19d0ea7ab44c24c614","name":"node_57fb1bb32bb2b1a87e44c6a7557e9c47c2032d107bcb0e34acd9ffd54d5d3df5701232db16f62f7549ba2721021898b03160b1dc5201e79606648c1dbc4a373b","services":["streamer"],"enable_msg_events":true,"port":63226},"up":true}},{"node":{"config":{"id":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","private_key":"681d7bb10f2022ae6f74a5afa7e0d42dfa6efd2e55abe22a395db640b6f5c70b","name":"node_7f357b8d81bc2e5c6fcb081f23a42b3e2439f050d45c45851994a268d1c71fcb1f39f8c3f75ce921d3fbf80fc0e73f0b9609d72001dc4a6b65b526d312a4f43a","services":["streamer"],"enable_msg_events":true,"port":63227},"up":true}},{"node":{"config":{"id":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","private_key":"fe0d4b827c015eddc1928a6f9691bb26ba2100a6232168890d11ebc7f7222891","name":"node_cb94a8270d0050378116b5815ff17dafbe20f5303839c4fd57b981d4687a4b145e4bccec7e9af9b9475005930148ffbfa97781a0762c8e9f352dc95565fc8732","services":["streamer"],"enable_msg_events":true,"port":63228},"up":true}},{"node":{"config":{"id":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","private_key":"0172e330c8b3ba8151689716c455034d43e9600eafceaffa6c9b162c36920109","name":"node_76cbf9fc0f3517fb615fa96104780218e85d064ee5a1d518f3b78f4dbebf144df38c427445fdd6c9b436489c00ff9497d747a8fd70f380f95601d59e52e021e8","services":["streamer"],"enable_msg_events":true,"port":63229},"up":true}},{"node":{"config":{"id":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","private_key":"2e9b4ad5021be5fdbcdd374c9569d467f370261662cb56e23b98ff5588c8d99d","name":"node_e023a51c5bd26e1754d6461345143e94baeac799947579ec7adeccd105de39f85afbceeb5037cfc0b820b9f4446433f034d9e7de7326d45df5a967a8099dbb10","services":["streamer"],"enable_msg_events":true,"port":63230},"up":true}},{"node":{"config":{"id":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","private_key":"059dc1a60c68b91d75f771391bae103fb3d7dc30c5dfdc9498980591bc09e0df","name":"node_68cc8b9a995eef6170abf88bd5fedca06ffcc8d75f247f6041c13e7dfd292727ebda1ff86b776e33b6634355c55e0f8c22fcdb5f9a6e2f22fe1af7854c3b4273","services":["streamer"],"enable_msg_events":true,"port":63231},"up":true}},{"node":{"config":{"id":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","private_key":"bf0aa2cb855d1702f8353aaf7cf03b846cbe1bdc6a0b66b18dfa8f03ab7dee43","name":"node_54b3c57a4adf4dbaf31b85ed1b8dccd6249faa16dd96dd230189f47f57970caeed36627cc8e1b0794707418d580f5bd6001c07be6a79216695f1253db24926bb","services":["streamer"],"enable_msg_events":true,"port":63232},"up":true}},{"node":{"config":{"id":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","private_key":"8b9685b4c43d0de26290fc8646737787fe8ff7e6c32c082060380b41fe2c5f3c","name":"node_df4c3505e09e1baa88470117b964e758c94f77a4546489ab5ab7f4aebfdce424729ace8867475715fb68f05c66c9674a5767549e266c4fadd1c703ddd735908f","services":["streamer"],"enable_msg_events":true,"port":63233},"up":true}},{"node":{"config":{"id":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","private_key":"a5bf3b5b166cc21128321759e5be62f691455e382d8ed35e48805cbb2d884a97","name":"node_24662a43944228e4ff74736bcf0a0a4f79c87ecfdb739225b2fc45110c11bfc38aaf2d09d98e5817477848e553f187ac5408bdb864518dfa7f5df542768828db","services":["streamer"],"enable_msg_events":true,"port":63234},"up":true}},{"node":{"config":{"id":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","private_key":"b64868a78b7e20e3914999f841765a445e99246e67a0d8706639a2e940c1dfef","name":"node_27d9048707a89f1a61e44fdae523c0128f2a7050308bd3cfefa6c3e03040a0e22f11ab41275f22b8706e6695ab93320e2af35179d772581db5f49f960750f2f7","services":["streamer"],"enable_msg_events":true,"port":63235},"up":true}},{"node":{"config":{"id":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","private_key":"f72fdd8aca59748c35831f451f405cbd0aa950ce62699f1f7c9c10d76cf1e588","name":"node_ea57884dd42aec5a76eab43483bf7c4ae2c19eebf365013731de64494d10a3b4cfe34c86c79437f9012bc8cf6bd761435eefadec17600f4b9e4bc234532d6282","services":["streamer"],"enable_msg_events":true,"port":63236},"up":true}},{"node":{"config":{"id":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","private_key":"9a8b5a154d6b376a8d8a1c5357272f164206a01554ae4fcdf479ffa3e80ec4a6","name":"node_3b570117addeec03c2694baf28e246f91907268fe665c6c90356120332794258ee57a60853c19e9fe25d042ca42a5be7fe0797d84199174de8132f1ef4a9349b","services":["streamer"],"enable_msg_events":true,"port":63237},"up":true}},{"node":{"config":{"id":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","private_key":"5007a8f6bdeaf7620240976e1d41aca23e841378ec3a157b199d5fea27b1e0c7","name":"node_0cacda5560faff9d20e29a0625d3cd340ec075f198a50ab8b79338cee0e0db84c7c7e71042fd8c8f73e507b570de5d26c39473136b575f0167625a1168309ec5","services":["streamer"],"enable_msg_events":true,"port":63238},"up":true}},{"node":{"config":{"id":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","private_key":"a7d2d7f12b632dd6c409c8e7cd5da6f2009d1ed9d27eff101c0e850934695ee6","name":"node_88d5c5fe61ee1e6fa5878e0eaa13bdabaa0ec3d38a5d25b95a467da7627424f25fb5d30535aa0a5ad01c16fe2598dbf570b78cc152a7f4ef66d46fc9ae43592f","services":["streamer"],"enable_msg_events":true,"port":63239},"up":true}},{"node":{"config":{"id":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","private_key":"9e7d9771bc8ee20b1bf0743ba1e8cf1501c54606fcf9e174930cf61de03ba696","name":"node_80d997b87856099d844187d3d1fa40846ded652a62c1611b35919c2543915b64ff62476636488556f678e436ea26fcc40db7c6b6bbcb78f590d61c1ff0e424b5","services":["streamer"],"enable_msg_events":true,"port":63240},"up":true}},{"node":{"config":{"id":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","private_key":"f28a26c4cb4589d2ffe6731d30ce96e197684de24e886f252b6cda9eb4bca962","name":"node_6bf9fb6a25521c16c2ebeb6203d046d7dd40f29cc2ddb067c0222ef56d7012d2ee5d037f71f6668ea56767610b2a54c144aed74b7f68d06993cbd52fa1dc7630","services":["streamer"],"enable_msg_events":true,"port":63241},"up":true}},{"node":{"config":{"id":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","private_key":"03c65c150995cc6ea4d0a925bbeb304f8b289d695855b69197bd9284c537e8e5","name":"node_23f9bdc82efbf57d3d40a1f2617d0311678fb4a3d6a50cb7e608c649bb618124a76c7ffd17387de963e1cd28d2bd5a61c98613f6e009a8a2a90d989827b35de0","services":["streamer"],"enable_msg_events":true,"port":63242},"up":true}},{"node":{"config":{"id":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","private_key":"0af9f76e6251f7612eb7fde7f20ebf9dc8334ae1139a6e2dd068a97a896860ba","name":"node_f6ca39b3ad803e99f4e4e9cf759fff6abdf06e6972bdbe524f6eb930c669d6f0e9b91f3de9df394b0d661b068273861391bdbac948ad911351c48cf02f874db6","services":["streamer"],"enable_msg_events":true,"port":63243},"up":true}},{"node":{"config":{"id":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","private_key":"1058a6e2e08d811ed1ab6b6eb927323ad28292591a70269330779d52491c6d64","name":"node_385168340139236a0e0f537fa693122db9fa02a377c96f31aae54718e92624fc0288164877e63616651565e055c53f7074ab2fdd18a837da6faf644941305bf0","services":["streamer"],"enable_msg_events":true,"port":63244},"up":true}},{"node":{"config":{"id":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","private_key":"85e1a2673b4ec4f876778b6fb175fae0e36e9e6456c8d8fa2a11bca2dcc8b376","name":"node_9194a3a4c8f3235203e48bdb10902d958d26c342805ea6365af9711213536509719d917c694f9a4fbdde6889a4c92299a5301f0275bda4dbcd2541b5bff5b271","services":["streamer"],"enable_msg_events":true,"port":63245},"up":true}},{"node":{"config":{"id":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","private_key":"54906c0600d9da9afc0e64bb94c7902ff60042840c9143900f2ae8fe9ba69c63","name":"node_c2705ee7238ef9305e4da196653cde707649435a1e8b5b797d164e5ca06184a77af5bd7fa938c995fdfcbce724fa7eca3d908ee34891ab62cc6dfd411c3fa1da","services":["streamer"],"enable_msg_events":true,"port":63246},"up":true}},{"node":{"config":{"id":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","private_key":"b798233dd61ca3bf4bcf5729b06de9bee5447b3c0c4f604eb12e856ff1363492","name":"node_bf4ff51cc3d9a9d8cefd7e346ce1384d06450228a6086fe12fb0c60fec54bb6478f090bb638fbdbf8f41f7bc6420cd8a5c8b1b8566229b6851167375ef412f46","services":["streamer"],"enable_msg_events":true,"port":63247},"up":true}},{"node":{"config":{"id":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","private_key":"529b3a0af71a5e49aeaa2a7ec622d5a1fb3a920fa64f8d200af8f96f0c2d5d21","name":"node_f33d1f3e460574706ac1c7fc9ebb4683b173496ce3e80017d1c3521bca03d5a41a9c7a6cde8347d2238917b7cc58cab000ce7ccf6bb408561015a2ecbe613408","services":["streamer"],"enable_msg_events":true,"port":63248},"up":true}},{"node":{"config":{"id":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","private_key":"d6dd6c5f414a03e6e909bb7447653cbdc2b5adf6bcb2a4643c2cc7572e574a11","name":"node_083e67bb19e30d14e4df6d2483367d6659d9b56744d53d9cf7fd15954c327e1bc88a5d0db8833634e1dad7209164451f8934b59f76b5990059261abfd650519a","services":["streamer"],"enable_msg_events":true,"port":63249},"up":true}},{"node":{"config":{"id":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","private_key":"ad02d38ce01c0291ad949b92338b10b0427a30de149df0a3c7457c2b2340a963","name":"node_0c14dd51a56130c51009e3ce47c96b2afef26b7e86cfca65d8a9bae1abef13b3a7a192b422d894c39e24ab00be412d166a3571cc259ff4462d4ad8925a153766","services":["streamer"],"enable_msg_events":true,"port":63250},"up":true}},{"node":{"config":{"id":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","private_key":"5f33ccc756728e5919332381312dc8eb9f6009e9a407654eb70b995c12338ee7","name":"node_855bdf057f4a6b095e2000ada199447b5b4f2f8d78d2ecbaa0ff1fbf761788870ee999266ad3b26efa02be1a46a4d92ac0debb85a2ceab3442394ee7d99e5355","services":["streamer"],"enable_msg_events":true,"port":63251},"up":true}},{"node":{"config":{"id":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","private_key":"7645086a0c4af854131d0ff4a95ef3a1d8ed9bb6620c934708a2b4f317c6f964","name":"node_b53078000796f1cdb04dfeac424d5e3e37e30f00bd5bebf9a9ea0525c62917612b3a8f508df6bea59e3c7e4cd1aa530841f9a8af54e44f5617a13dee2c6ff007","services":["streamer"],"enable_msg_events":true,"port":63252},"up":true}},{"node":{"config":{"id":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","private_key":"96bc72358e15d649f871e17f6fbb7ddec911aaeb3b5bbd55929512756cee6a67","name":"node_5526d86ba9df651091d88460a9bedb9cedb957d452a635e1db46b9fed78082022adec0047cd7485956a4ecbb0e18107595de0de3c35242527cd302bf74a19260","services":["streamer"],"enable_msg_events":true,"port":63253},"up":true}},{"node":{"config":{"id":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","private_key":"3348eec47933810a23d583715b1a18b2a8332e8cd45bdc57bcc5232c6b5c0164","name":"node_a7378ee34876af17c6cd94a69b6b741ec7891ff5375bc4241d48608d047455ed48e6baae80ee88d4710c69ae615cf195cee26c94b54de1bb935628ce1e3a723a","services":["streamer"],"enable_msg_events":true,"port":63254},"up":true}},{"node":{"config":{"id":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","private_key":"553bb09d30fcd504ead604d830aeb0e3d0a5edfa58c94ec3da1508184f7c059c","name":"node_3e488a7208ce0e097ce47fc6651a13e95cae137d1a054a09b04d2f59d45faa2594a8c3b395e77ad1a3c2edcd827dda73c0c97dbaa6d9519a79184a0aca01ac4b","services":["streamer"],"enable_msg_events":true,"port":63255},"up":true}},{"node":{"config":{"id":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","private_key":"60b600c6cca2712771a98d797a46fbeb7be68a054d94d8eaabb8ecac6d3520a2","name":"node_07f25fdeab2b44b2e92fc80fca7de9e4a8547d27a98a54593b3395c270a9ff3f2a5da62a2e8531ce86359f0cdc5b6513b773dfd64cce1b83e47065d9760a2c7e","services":["streamer"],"enable_msg_events":true,"port":63256},"up":true}},{"node":{"config":{"id":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","private_key":"4bb86dfcc439dc83032e6189165d986a8f315558aa7fe1b6bb2f91e521a837b8","name":"node_0f9f7e2dce4ca266c3ac0ec3a8854200b54487f5308e3db418461aeb5f67c81d332619b6441b468e480941e63100ed1b263e7adc20689dc3dcda578bfca538fa","services":["streamer"],"enable_msg_events":true,"port":63257},"up":true}},{"node":{"config":{"id":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","private_key":"ff9eae2bb1fe93a164f54d3ac907b4c4ec79fa41eece5a44aeb70c083ad80ce6","name":"node_a1560ce7c1f1d5972f027a8e9cff820611d84764aa067434a75b63887bc4268a259101486d34b7fe83dd735e799789986cd3e9b156c86ede598bd86af4454924","services":["streamer"],"enable_msg_events":true,"port":63258},"up":true}},{"node":{"config":{"id":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","private_key":"f23f43541bab9bd56083d663c140d382c5a9461060c285f1c1b1c6621d8e2e1b","name":"node_e06a789a7f6988e1ba5e8358b6cd4292555c7f9f7f0dda6fc01cc26d24e49a8c1ad694423ad74aec6d80f4b99e2bedc49b6a5f2670744cedee3a3e1848e6dd07","services":["streamer"],"enable_msg_events":true,"port":63259},"up":true}},{"node":{"config":{"id":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","private_key":"e3853d7bcb9111bc645eaaec38093b38a0b16e80774deb42bbf5431e78e9ae9a","name":"node_57b47f692f4d69a5d2c9c193680eb4ccb5a6c574662df0138504a549f3ea74f20c5b866ac4d9e76c4b49c83f5fd692ead928ea20dfcf643a11a1c1e841c0ec42","services":["streamer"],"enable_msg_events":true,"port":63260},"up":true}},{"node":{"config":{"id":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","private_key":"cf8c79a1a70472ac10e1dcd59e8a498cce13cc78f13a28a1b31ef8070e8201af","name":"node_2ddd49fae11d8bd2e7e75a481be267fa846f51cc1160bc326aeea51c542323ff444909de11e2731e835140bc0b1b32020e1e73fa652511a381222bf0aebc4081","services":["streamer"],"enable_msg_events":true,"port":63261},"up":true}},{"node":{"config":{"id":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","private_key":"872f89492c87094f84d4db636ac19e5c87ac57cce008931d2db6d7aca72dc552","name":"node_420b9c90584651c5a3fe3c16aa377444a321dca934f8a097d01a616554067feabebf2fdc8d2a25797f29a8fef30d5e2c82f8e85b20f509a880367b9b0ccdea47","services":["streamer"],"enable_msg_events":true,"port":63262},"up":true}},{"node":{"config":{"id":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","private_key":"9c7cd9b75a3b821c0ec74e08d8727fa6ce5aa184479038762b1ae4f3c07b3782","name":"node_5bf29c02f07faf7ae8e46389e1b98df4f5e88c9316b5151685e6ae7b4e622cf171ff09f996aaa8ad846643b3bfcbd1ad96cdc249afccce439bb5c55246b95801","services":["streamer"],"enable_msg_events":true,"port":63263},"up":true}},{"node":{"config":{"id":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","private_key":"ea03297fa8e550df89d0595b3026c5367bd7b0076c7a9fd5c6071f0944373202","name":"node_e3c8a97a2d95dd543f9e2b41d9dce6256e284296f866f4f92e9925f8c7519dea23fd6d1a11153b93c10d6a32295e7b9bcc16024e690e4a0dc84fd25ee0f31b2c","services":["streamer"],"enable_msg_events":true,"port":63264},"up":true}},{"node":{"config":{"id":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","private_key":"dc424f98922ec5d19a5a8d5ee2acaf077778ed0fd92db276f88bda3cc4fdb5a6","name":"node_7aaf7817b93aa6d2f50513791f9ad7629a901ed0dcb151189f44763f83423446b20ec79a48fa260cd9bc2907d5f0ad06b2c4c5e6d812f3d8876c8020ebe41019","services":["streamer"],"enable_msg_events":true,"port":63265},"up":true}},{"node":{"config":{"id":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","private_key":"baad13cad07e0edde7209f5e70451c82d07d1c4d4bd5ad6f85acefd48d14a253","name":"node_062e0ca43a1885c4a7ab2a5169790f9081e3e9a2dfa286b8cc592d5ccbf13d7a82b72d23361a19026d04fcf41b752ea320d98359d770aedfcee626e21c3494b3","services":["streamer"],"enable_msg_events":true,"port":63266},"up":true}},{"node":{"config":{"id":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","private_key":"613f528e83e5bfe55db16791b917891c139ea8ab7599058a204c7836f71feb95","name":"node_f9ffe87c52ff4c22bd9696af32e0a9d34bb81fb84d9d8bf5aafe2ef9696e7b3d6460bf2a93aecb066133f53416bde841a02d6967bd06e3d4a714f3b2c123a947","services":["streamer"],"enable_msg_events":true,"port":63267},"up":true}},{"node":{"config":{"id":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","private_key":"873d0f70715479bbed36c4b74c9391b723fce386d150bbbd613d33eaf08cf257","name":"node_bcf8e831821a5bca359fb824c7dc4d66906de82f3663a0a853d96880a8ca0bdddcceb1b66dd1f13f75ee20fde50fc9de545bc25767f228baee910e0dbfa8cc27","services":["streamer"],"enable_msg_events":true,"port":63268},"up":true}},{"node":{"config":{"id":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","private_key":"48e7cd643d45488597f25de324e8b7553c26e1cf8e8d44261d610ee9041c898d","name":"node_3d2df188704eeac09c8b291bf275a73888199a231c832c51dbc3d746968d4b51a7d5eae0c7c9b8c8e19f5e28d38c375e01abefa343f31dbe221deb837ab8a0df","services":["streamer"],"enable_msg_events":true,"port":63269},"up":true}},{"node":{"config":{"id":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","private_key":"f88a54bfc74bebed6bc8bf6d7b98aad4ea4f8b8aea6cb1514aecf398bee41960","name":"node_8f88c7ec044f758f29bd8d12a5170bd973aec8f6cddbf512b910c4b75a0fec09c5e198bcd65622037f897759db68da2328b4a7ca93585dc9cb62e46d2a6c0864","services":["streamer"],"enable_msg_events":true,"port":63270},"up":true}},{"node":{"config":{"id":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","private_key":"a5b02d5d5ff64f5330758019a5ba0583f2b74b423be4695b4ffd94231ffd58c8","name":"node_4314b0b04331973ed29a58843951f144ac3d09bd5d57b6cd9aaff9b73a7b2ec81e344a3e4ece462bd2081b837a06310e787ef3bb889dabad46fe7efd394c8342","services":["streamer"],"enable_msg_events":true,"port":63271},"up":true}},{"node":{"config":{"id":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","private_key":"9e96b56ea6abe86960b688d477b9c689309a7f304c5e4bd108459144e68448c4","name":"node_3612863ce0456c91785a829bf5c9d2b2fb97dda083a1847e5a4ebaa6fce1260faf4d1eb374c2225431a82774163835fb59c8cb0fa9fc0969eab5410c71109cc2","services":["streamer"],"enable_msg_events":true,"port":63272},"up":true}},{"node":{"config":{"id":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","private_key":"5bec215e5024e8ce65d46fbf9b69e1718c1173478f8654d2ef451b6217ac6db3","name":"node_2ac522ebfa49d37f86c6270ad4cdad0e766493f0e463b18c9906c70fbd2e5c6ff6b0d5879de6e3894418370636963a78b0c0cf087a8684c2ca30c9c736e49228","services":["streamer"],"enable_msg_events":true,"port":63273},"up":true}},{"node":{"config":{"id":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","private_key":"00dd6637412fc5209eeee1423b4eae49fbba97d8d5c37c9ae6819f7afc53569e","name":"node_62666b24d1026345349edb6a878cdc27d6fee8254e83f79a298ce2805260d97aa46423deae440f86ced5cd99b30e970c8e1ea1046752b17d8c80dc68d9a49b60","services":["streamer"],"enable_msg_events":true,"port":63274},"up":true}},{"node":{"config":{"id":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","private_key":"88ceb50dc965b4e3279c8e7729db14ea34238126f1ab694c621d5ab9183acb52","name":"node_9ce6b9decb69d66075993e903a0727ec109a04335634616097c0e60b08f94f764634fa00891b1070f6ea1ce896bc7d11d3aea92a00f281f902d960894cef296f","services":["streamer"],"enable_msg_events":true,"port":63275},"up":true}},{"node":{"config":{"id":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","private_key":"638176a3cb343c140131c887892f37f9ad69e9c87c0a256dbbf2fbf8dd2a6b08","name":"node_b870935867183bbfb84add16b9f56c02c834b7042fc24ce6bcb2a7f174e6d2239357a00be4272c1ef05c7f9baf5a9f16b53bc18328a9b7aca8540c2916805b57","services":["streamer"],"enable_msg_events":true,"port":63276},"up":true}},{"node":{"config":{"id":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","private_key":"4da9834c8665dcfed17ee5eb89c5bfa3c0d1cc4340088a4038f746dae4cc23e6","name":"node_c83985973a9564ade7d90aa54911ac57077600676a1d27292d98e058bf1315887bad84ccd708cb7f52a695a1405fb7d491d7ca2ae9caa3ff58a5ad78ce4dc9d9","services":["streamer"],"enable_msg_events":true,"port":63277},"up":true}},{"node":{"config":{"id":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","private_key":"05eb5751d81653e8ce409be43c9da42ff90f90c6e68981e69cd03a867d93b800","name":"node_acb4088c27ee2ee130ece3506596432afdb9e9757ec11ebdd35c5a6e87239545c48466913a646980104c8fd7a9a335e177f04efffe9dc952dfd7cd5c1bb9aac6","services":["streamer"],"enable_msg_events":true,"port":63278},"up":true}},{"node":{"config":{"id":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","private_key":"846035be661387d6163b5472ea225ecc9d3851349f480fb901d2e31bb8ffe858","name":"node_b4fd11306b1416a9bcf4719578976188e104b8c5028b9abd3214d257446b97b70a22e6c00934d80caddde15e8e4d16af03bb399583047983fba373d8313226b7","services":["streamer"],"enable_msg_events":true,"port":63279},"up":true}},{"node":{"config":{"id":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","private_key":"b34c69cee56a834b8a36ae964f1847d1825821a21d104396039175a8dce5ac73","name":"node_7b35c856916eb3fc1b1f451667e240b95aff8f4731cc0f6743740923081ff1ddf2eec81bdccf4691a7bcc053d23eacfc15809c384a73448f618317bf605bd1cd","services":["streamer"],"enable_msg_events":true,"port":63280},"up":true}},{"node":{"config":{"id":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","private_key":"3d1ea95ac16f7d903cb8630a8c06052560a974b0abd3410d9f8b2968e7cf653d","name":"node_2ab9513899c3c829b6284e56bf2b9862dd0156ec052b58615dba77d450dac642e534ec36ae5d3234262aff54e19f99856e908b9d8c1da660a7834a445610715b","services":["streamer"],"enable_msg_events":true,"port":63281},"up":true}},{"node":{"config":{"id":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","private_key":"70a577ae497edece947ef065da29014e45dcc1d942969597600a64b55e8bf718","name":"node_e087230634f556b818a416b66ba3f1d1dbe3e0dd0698bbb26fa86a2499acd169466f564dc18adf2f9be4d1ada0e86c11549754097601e10aff4f3a57ddffa24a","services":["streamer"],"enable_msg_events":true,"port":63282},"up":true}},{"node":{"config":{"id":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","private_key":"28ee397105a113c5c4e7d7cb1b3dd17b6db66c3cd8f3b621df0271e544fb446c","name":"node_66beee3968dbcf3addc6feaf070a4e3e82b5bb164fb72f40add89f732c12e8d0a31a7ee1f1e24a4674e4dfc9a4912b02c17ce3c224d257d78b7156544d6507dc","services":["streamer"],"enable_msg_events":true,"port":63283},"up":true}},{"node":{"config":{"id":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","private_key":"b6feae1f667895ada3116380a2cabb0c702b44b24d45415edd143d27dfe5643d","name":"node_a08e47137bf611dfbd20308a22bdd3ca00121386f121d6d712ade86e9a1601a4237766887cd91c8516e20b6e323d2ef49c1c7e177a0afb4c813f0f344daf779b","services":["streamer"],"enable_msg_events":true,"port":63284},"up":true}},{"node":{"config":{"id":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","private_key":"a643e845285aa039d6f84cb124b618bac45c970fe0b15fdbbbdef834300b4857","name":"node_990b1db3ab1390219e8866d39fa4441bb5bb89ad786b3e255771869fcd08906dcf63f34007481769c7462edbcc665acc0a552e3733360b8d8c310c9321a5550f","services":["streamer"],"enable_msg_events":true,"port":63285},"up":true}},{"node":{"config":{"id":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","private_key":"1b31bc34d4ea49b0c1df457ad06513d0f47c56ab106b0f0ac97c43ccdc64db31","name":"node_7865b82e44add2cea6ebcbaba9c152184331a2940fe73f6f9bb940bda8a59ab4cf4760894b9cadcaa54e36fbb712ad619346a49a85e32cdf2b53cda1ac1e0658","services":["streamer"],"enable_msg_events":true,"port":63286},"up":true}},{"node":{"config":{"id":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","private_key":"b380737ac46f320eb5884ca8a60e1693caba904545b68396e33fb92cd19aa18e","name":"node_292c78c8e41606e98428096bc6f4609a7aa48e5c4d17eecc64d65faae4a7270b0c15f0cd74274015688ea0a9aff34f215c29118222e362a29c8d637963973a55","services":["streamer"],"enable_msg_events":true,"port":63287},"up":true}},{"node":{"config":{"id":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","private_key":"d18c1536cd7d9771bc9b64595184285ed499519ef810b3f013fca2fc01018048","name":"node_ee36d1d5dd69fd30242d7da2e941b34ade5581c7164fcc43288ecfc52937a98f1b31ade5d1e4dbf611cbe1c7875b2840c89435081cde471c271d7bc60e9ef211","services":["streamer"],"enable_msg_events":true,"port":63288},"up":true}},{"node":{"config":{"id":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","private_key":"186743aa8dc07042c40bb95b2efe30149139f3c2ea4a4bd193d3be68e8f4485a","name":"node_bd1a7c63fca9e1fcc67d7fd62670beefe2bce483cf1dc1233ee85eb90db607917cd9a5d7170b10e80b925a20e2af2c54d286b01805ac34967410859f4f03da09","services":["streamer"],"enable_msg_events":true,"port":63289},"up":true}},{"node":{"config":{"id":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","private_key":"2e960819700f3330b00d2d58461403843026ffc7629b2514568c6b571fc99488","name":"node_9db1f94d74a00d1e5e2a391f1bcddf16b6d0670a2c6d91d946d38112c58634444b6fea8e8c05ab4b73bacdd62a0b575f6fb8729978edc216c7842b177b9f9cd9","services":["streamer"],"enable_msg_events":true,"port":63290},"up":true}},{"node":{"config":{"id":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","private_key":"50c27493a6d9ddee175040dafa1f40c6ad503b55590479001ec085212c5cc08b","name":"node_934a5fe1b91c1891ef4df7f67c027e0eb115d4c2ca4a1b76a135ebd4315c4fb835d6625223194e6a134407b38b0d3928fbc7bc924a3c6a538989a6cf200bf4bd","services":["streamer"],"enable_msg_events":true,"port":63291},"up":true}},{"node":{"config":{"id":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","private_key":"4c67752b215e2cfc06120964f06976fce2a1dba599c0f32c0f4393b9d77ef872","name":"node_485825745d97654cbb92a14e0cd1078691d3c28f4d82b1046284b676a42b44ca58eb43474e45e415d3bd3f3c383f9a1a3365821ed7ba6a9f2603b29d58031dc7","services":["streamer"],"enable_msg_events":true,"port":63292},"up":true}},{"node":{"config":{"id":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","private_key":"21acc46816414d3a1d76bca30d2c2e1e55d420e9ce704d0720696f7f7fa0bf33","name":"node_5bae82d4832092c17bd11474f7748015b8b69b896ab8f683a7c0024fc98740cecbb9e31c6275269f9000e5bfe51d7f45cd5dcd4433e0c87b5741685b40fe3983","services":["streamer"],"enable_msg_events":true,"port":63293},"up":true}},{"node":{"config":{"id":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","private_key":"4542e37f43858e396004d8d8801bae1905d2496a3ab44f75cc29bd2c2a472f94","name":"node_732393b99c490c76fa45e3e404ee095f2fa445fcc123af7ac8ab1d2fdd7cf2483f5b82bb818bd8a82b1a3b73e63bcc2c83d8f24d9aad9afe36503735e7967be7","services":["streamer"],"enable_msg_events":true,"port":63294},"up":true}},{"node":{"config":{"id":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","private_key":"a8e588af7acfd6024b3d71be7be630345ca80708a69214fd31e3b4485f039c90","name":"node_4de378164d77a28c90cf162dd1b465e0282ee17aa7d3bb3179252466f72da33a36c9f298f7c9498e38dba4018e7ce3e5fe631c83842cd9059e23a7fece366d87","services":["streamer"],"enable_msg_events":true,"port":63295},"up":true}},{"node":{"config":{"id":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","private_key":"e3d1a9d4621d7f77d9c2fa224f0d8c8211c2bf461554a1d50afa8f34a82a4754","name":"node_155e4879643a472420012e040a87dbff776fc1976814c0c6cd0d5e157f0d0baac04aa7f2535786c09acc2700547383d2119b64a6f62115f1aff1708738844d8c","services":["streamer"],"enable_msg_events":true,"port":63296},"up":true}},{"node":{"config":{"id":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","private_key":"6522d077629e8c313d832a7a87e5dce9e989618cd1eff1b1eb3c8b63756159e5","name":"node_81288bb0584b7ffc1546043e052e1df10fd5371b35dedd0bb42ec5b30ce69b741b2f7857af5984d4754b39d7253575fde9298504999b78380ef602d391c4bb1d","services":["streamer"],"enable_msg_events":true,"port":63297},"up":true}},{"node":{"config":{"id":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","private_key":"f90016392c8768d222055de5cd1c3a512d3c46b7c7be34a93cbd016aea9ce753","name":"node_109556abac422a912ecffec0d8796f8f16e92e8f95cecf72dc89e97a8bf1fd37aad3c66aa3cf134acade6d065c31821f977171d5c5463305b57ce3eee99a7ab4","services":["streamer"],"enable_msg_events":true,"port":63298},"up":true}},{"node":{"config":{"id":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","private_key":"49f3b1f88009b94bc7beef8d891816672e9075f3015f5954a9ae9d13c8c07290","name":"node_759f46661056bcbb30c7706c9fb87e22a30feb523bd53ae5d18db043efa45b49a2b8982abebdd598fe0912a05896390ec2eabe5e160cbafc0771990708ad8c28","services":["streamer"],"enable_msg_events":true,"port":63299},"up":true}},{"node":{"config":{"id":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","private_key":"65f5fa03f2989a02e37bb664102504038f14adb483b2116b07355296346912f7","name":"node_baa5924e1547c177011285d292aa161a15e5ff282da2cd0afb83c9caffb07bdbb3662c227fa7b26e6dc8be9b8863e647eb5f8ce81640532f8f5c9a7f36557e63","services":["streamer"],"enable_msg_events":true,"port":63300},"up":true}},{"node":{"config":{"id":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","private_key":"87514536801d0d46fcca5c10334c9a6a34ad982fbbcf65b2f881e99a0c8ab27e","name":"node_deb7af800cd20a647335f0feff5bfb3e182f99f4c2d1ade10da36ecfdbac3b5fba4e8f0a4595443fe395b44af3a95617669850944655def85d57cc81c5682a3b","services":["streamer"],"enable_msg_events":true,"port":63301},"up":true}},{"node":{"config":{"id":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","private_key":"c69b71039aa3f28c158e5e639d35069ee66cc88565ae886e75651d88fae8aacf","name":"node_17917fa4da06068b587c17899569dcc768b9cd2c27117a4ed67aab26a7e70cf8d32b881db258061ffd89a332a3b29bfd963d8e171a06c3e208ba0de1c42a2b39","services":["streamer"],"enable_msg_events":true,"port":63302},"up":true}},{"node":{"config":{"id":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","private_key":"76998bb1133735934b6d8cbebf029318feaf9b103165cd460a4a9ae04ad26c5d","name":"node_032b9bf2f59f15571821611d3ee541aa748c86d47fbe5f049fd0069be53e5d7c41991d82957e9c727654c3aa73ec94997c03d8a6c1d2007c9bb1a703f6215158","services":["streamer"],"enable_msg_events":true,"port":63303},"up":true}},{"node":{"config":{"id":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","private_key":"424a19356346001136b4df8a6119a510d526b508d0378eb5b67ffbc471757c08","name":"node_be026dfb24847cac2d00f483104edad06ca8ecb9e1229c479ef5650c7b427cd5dc34a1cf06172c17c9d0406ce17009712e82446394743d4cd9bbc41c537ebc14","services":["streamer"],"enable_msg_events":true,"port":63304},"up":true}},{"node":{"config":{"id":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","private_key":"06aade0419624ec355a3e8e47144b1efd1853293246628e0d3ce856bf3bb64be","name":"node_389b5c1a805f87427e6d647ec5488342a3f7d700615943d5ad98ca5c111f33c7ee007970b4d3e475892095c0d5a79b7ed52d12598398818159000d4b9b719126","services":["streamer"],"enable_msg_events":true,"port":63305},"up":true}},{"node":{"config":{"id":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","private_key":"903c726d393f3a34e861aee6a1b42ea078da78c23d1dcdbd0fd8c30e80b65bf1","name":"node_c57ea182bdb42ba9b0870b5c870e467f52693e5c0df752fb6eb0dfbacce7763f73caee10db40f4fd90f19f504ee586eaf9da41f5ee93ee515d885fec99374116","services":["streamer"],"enable_msg_events":true,"port":63306},"up":true}},{"node":{"config":{"id":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","private_key":"29f2f00196b61b834638899c2e440c57b99668fbd93d7eed220c4556a76cf89e","name":"node_2ac93c31937ca205d61cc5c2a1b9037871cac55e9b306b999b28e19566b3316f6539455e014840ea50c2db8a7c97d78804d3a2dcd7cd9c1f32ace0d36e5dd339","services":["streamer"],"enable_msg_events":true,"port":63307},"up":true}},{"node":{"config":{"id":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","private_key":"682a2f9130cdf75915282000edc627563ea4e9de499ddc8d55efad472a94091b","name":"node_ca1aff0d847c6fdacb623ad9078a0885b3208614fea20d5ff11779779b486bf5e9c794aacf848d3c2d58cfcc1eda8356df82f5fbdd0a5236beffe8e6042848c4","services":["streamer"],"enable_msg_events":true,"port":63308},"up":true}},{"node":{"config":{"id":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","private_key":"d1b4b3adc1b17a79626152a1c7362bddd7c47886990759955595a1de27f7b70b","name":"node_2e409baefbd821485a151993356730e5989810d581e68190fbaa142799c9335bcf98310ad188fed10ae6eb6e2e789730393e509962ec5c0fef0342d72ed088d9","services":["streamer"],"enable_msg_events":true,"port":63309},"up":true}},{"node":{"config":{"id":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","private_key":"34a5057b2a2c507010da7a091827d28ddba4f59c9b5f15f7cb7bf0578e4141c3","name":"node_7b5c0e81c7f4e3ae29d745f6028cfa10b29a16a9c261b65fb8dd05d6eccc634612ad5d3029c8e9f39863a2cdb2682c25f090139bf5c4950e25647e39dcb40e63","services":["streamer"],"enable_msg_events":true,"port":63310},"up":true}},{"node":{"config":{"id":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","private_key":"7b608c298477c4687c50adba466567e19c08492da2684417c129d730caef7594","name":"node_663535b22018a4ef0b151572ef286fa66c22c6e9b2913a69c4a735d4b0149bdf6c84bd83d710f8aa2627e8993b7f020750fbc6f56a3365ce4c840e2b3de1a6c1","services":["streamer"],"enable_msg_events":true,"port":63311},"up":true}},{"node":{"config":{"id":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","private_key":"d9d17f1baee1ccba3fea764f5f5797475ebb9f206d735105ba8fa2c32fe02f0d","name":"node_7b1e20217f594f87350542df31ff5ae8a635679bac7962d49c97e02190c644b673d03e7eba2626b45ca7ebf98d8a972dadbba02c18a8d2cbfc3e7a4cced5b4b7","services":["streamer"],"enable_msg_events":true,"port":63312},"up":true}},{"node":{"config":{"id":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","private_key":"cea9931b34475ad432aecae3d385d895f0ab3e93cdf1d9fdbb356753ec9c7a59","name":"node_84abcbc7b5598ecfd91ceace0927921a5a3404fdb274fc2a2549abbede5f8e4f62c15688a4dc9a2d80262c45970c88898da245c6eb779f327a81d53a17bbc74c","services":["streamer"],"enable_msg_events":true,"port":63313},"up":true}},{"node":{"config":{"id":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","private_key":"362c6622af8998cc3c5cf88ad71f308b632f8f7d0e8ea7ae341f8c8ad44cda5e","name":"node_eab86c521f8f1ac67c015ab713f1236a08b0200757a96bf87ab8301e7967ae62361f0e14da14ca294fc8cb3b4726b52f4773101e21b032977c6a647241b59c73","services":["streamer"],"enable_msg_events":true,"port":63314},"up":true}},{"node":{"config":{"id":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","private_key":"9b28fbe1dfa137bce975e179d3acfe046e5d148e1f9b1aeb16bdbc2cf7abd071","name":"node_e6779e3bbecf81dde8b27d652ed2726c45c205db0d0405c4580014a4c91d739830276f77079108c98ac516ffa00194e77a0795f7140bdf36069b6475e58213f9","services":["streamer"],"enable_msg_events":true,"port":63315},"up":true}},{"node":{"config":{"id":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","private_key":"85e559f97ba5553b0773479fed666bd92a928924af8164f41e92e8acfd51e896","name":"node_9133b0b3c8f680286eae90c3beebc3099a13de38775a3ff2abdeced62d05eb2ced5ac85eac0870156be03101024da5e1d9fbf3e1066ddb3f088221e64149acec","services":["streamer"],"enable_msg_events":true,"port":63316},"up":true}},{"node":{"config":{"id":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","private_key":"652705ca7c47c641c033e01212d96759539f317508df53dcf7397dcee0e20422","name":"node_e1ecad3beeb6c19dce551e4a603c7b440b4498c44e298dc67bfaf4ed2c75bbea95df48b1cd1318e2ccb962cbae7c30ff258e73f8c3fc6b7e9ae7a47f7cf8e53c","services":["streamer"],"enable_msg_events":true,"port":63317},"up":true}},{"node":{"config":{"id":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","private_key":"2578458d6da6ee18aceaf48f57a0f211f9b0a0a49149cc71356d1ccb989b55d8","name":"node_1d0244a13affe60996fe3cf51ba624adc746de0c7ea68ec5a31311a36077c5b5495e3d95c9642875db44c7ecae6ffed22e45f2e2d024d486760be2af9f4cf2cd","services":["streamer"],"enable_msg_events":true,"port":63318},"up":true}},{"node":{"config":{"id":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","private_key":"35b91179894d9195f220f768d849bcef7b2752c1d63a4d373be189c4e35b68a4","name":"node_d9bbcdfd949010e6b2cbf6d0f34b27593ae410bdc1838876aeca35679571fe431d040a5ab085c0a77f111688bebed891da3587277cd794702437cb20d6aa4256","services":["streamer"],"enable_msg_events":true,"port":63319},"up":true}},{"node":{"config":{"id":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","private_key":"62fbe89ba6bc5d8f608f65baf5a0a87c9cffd1f428ecacaadcc777a117a88fa2","name":"node_0a4eec7b0e05da799aca5b36d9e2530f2a89d1426b1fcb7d8f9a662df8a8b5b763767a20db3c9c63e0bd13c2a6e16d3ba8f03baf84f5e5d24917b3f211d9bcfc","services":["streamer"],"enable_msg_events":true,"port":63320},"up":true}},{"node":{"config":{"id":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","private_key":"85b477146d09b052deacbb0f7cc22f61fe3093095e7677ce89c086db68c8c939","name":"node_9bbbfac8be4a000f51a4ce8d024d2595b5d491afec0138922dddfde5ef62c664040c2e9304cc6b7bc688233b5d0c4644b8c8793227c078285a3ab894ef0497a3","services":["streamer"],"enable_msg_events":true,"port":63321},"up":true}},{"node":{"config":{"id":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","private_key":"b3caf8e1271504098be33349fd983395e57f6cc7f4c0d74df8dec7643c0cd09b","name":"node_016f8f4619a16a07fbde5a18e362158d696e4d9f104a77787f26e32a25cd7d278256f8e0db865c488a99511ec27a5eddd5ebbd1c1397fa7f8db111062e5fe959","services":["streamer"],"enable_msg_events":true,"port":63322},"up":true}},{"node":{"config":{"id":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","private_key":"a61a6a7469d5c9abf20daf3df75109b9139cf36c1194d9bc00046d1359c44823","name":"node_7acddc7fb6ac587b7e343804c768e4291cd28dd2b2b9207dea6ee82360d848a52d84f94e4c49e9c421f4f90e2d24f6291e2358783ab0230e6ecde82e69b4ac52","services":["streamer"],"enable_msg_events":true,"port":63323},"up":true}},{"node":{"config":{"id":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","private_key":"629bf1b9c1de816ee9d1abd91d2cef359ce96216dc1d798c7f246ecc5bba8ed4","name":"node_9b59b76dc61223c7b37083b0ebdda22d3599563b3e3986f5db9d5b12f8c806cbdeb2345454efe957cbfa11eea9c7896aefd9a461210524805452ca100a9ea431","services":["streamer"],"enable_msg_events":true,"port":63324},"up":true}},{"node":{"config":{"id":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","private_key":"880c61b8c84f87c55e85aa9b07944500eed52b76b64b6d15c93d8e7c23000042","name":"node_e2e0419a41bdfc5bd76deae2ddce6ac865f886d764c9bd18799b79fa3b2b6ba66d765d26da2037e98317e1d7e8232a61e63c1d0cfa98c9137424151b46e07171","services":["streamer"],"enable_msg_events":true,"port":63325},"up":true}},{"node":{"config":{"id":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","private_key":"dc74709b0972c1ec957a2c056059ce117c9291997ea47107228e80d28af70acd","name":"node_5df58ba12334a1b4f983d642fe435901261767cd81f8f37c43e359f5584664e4d287e8c2275995604a3b3a4823418e35cd899a3db2a7db31570e19512f375481","services":["streamer"],"enable_msg_events":true,"port":63326},"up":true}},{"node":{"config":{"id":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","private_key":"52e14edd67adc3154d0d5a91f91e042773a79af41c5cce9120e2dc03318a7fdd","name":"node_5e86f39cf8338ba098a85d41e601a303fde311662b216ad32a2b7bfaf2b2b6dd1af3775784b39f2d85ac5fac96f05f3abdd8a2bd28ba16d939725fd6a33ae1b6","services":["streamer"],"enable_msg_events":true,"port":63327},"up":true}},{"node":{"config":{"id":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","private_key":"ba201a301c109cac7dc4f762066312478f6a3b92b80495c19d238b8e728e3f63","name":"node_df54af3bae257d437c5657905484e0d72e9560c46f8ba6b3437730234e05259b404cca40b0831e911605ff8a68a19e8fd7e958069ec8b40595928892f4fa220c","services":["streamer"],"enable_msg_events":true,"port":63328},"up":true}},{"node":{"config":{"id":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","private_key":"4f8dbb09790674afc8ae90210897ff3196d82a7d8cacd67ab970ab02fd61136e","name":"node_4ee37acec2178ef120166265aaa2b64b09b315fb53861405ef46f2503c273eb9692e9cb4c2e67a8652254d430fd6e02dd3fe4cded20bb231a9fb834d292b0b24","services":["streamer"],"enable_msg_events":true,"port":63329},"up":true}},{"node":{"config":{"id":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","private_key":"fd9060fd74b7db28d5b02541febcaab4e1706cb1ae50b22d20a7f619fbc774cb","name":"node_abd8f5a4d700c06ec00684b23d2d25c4df1a9554fcfc57b0ddc3fa476e6a699ba75e1213449f900803f83ab8194c6746664b547202047f35b8b3e216c7147bf8","services":["streamer"],"enable_msg_events":true,"port":63330},"up":true}},{"node":{"config":{"id":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","private_key":"3034bb94560e7e8d146cf275664f91426fbeadbea78cc96662a0e762f5491d3c","name":"node_cb321c9b0fe2eb3617b8e2461aab170a9dad2c9b04a10eead4e37e551197ea0a7500eb1cb7b155efe1886486ef3d252d8ff0d309f2906a1126ca011d037da70a","services":["streamer"],"enable_msg_events":true,"port":63331},"up":true}},{"node":{"config":{"id":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","private_key":"1e3e9ddcbac955dd113066c5a41e5b3b16da5cd7bfa036ee1066ff3ceb69d7c9","name":"node_c665a6b1b7ad39b86bd4b1fe38b7ee95a0fbb1db15e91381ec9e5a235e33b69ffdc92c60dafd74b7b4dafca1b000e9274bf045abe5b93b1a9c2b31ae071a9898","services":["streamer"],"enable_msg_events":true,"port":63332},"up":true}},{"node":{"config":{"id":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","private_key":"9dcf01557c9cd252eba6d06bab3e12ad039e64f5d33b732bae4afdee4f4c63af","name":"node_53df9cce9b0169e58ced53a123d1d8f6e8fdcfb4c2d781ecbb91bb7c8eba36946dd9d21c749259769825d8a6b3faa6bb87c8c6085a522f8a3e376061f59144d9","services":["streamer"],"enable_msg_events":true,"port":63333},"up":true}},{"node":{"config":{"id":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","private_key":"290d07cdf29c35f369b7053b54ad174e4db589026d3d4b0553bcccc0a0e4145d","name":"node_d7a319f69013b8375e64d19f015547462c84565b882337998f9e669c5fadd3d2ecf6374109903003e09f5d453424b5c7fdf52163d2cc8084cf81f94844946b63","services":["streamer"],"enable_msg_events":true,"port":63334},"up":true}},{"node":{"config":{"id":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","private_key":"2a549958a13f2e346b477edf55e1056a1c7c1051b3cb277aba17bd7db522aba6","name":"node_f38a9d792173a29c61389f5d84c005d78eac6e750659aad42e2d6df883f04eb3126b2c38fac95076eeed455b2031aaf694143922aa93a2d50412a2454dc56e28","services":["streamer"],"enable_msg_events":true,"port":63335},"up":true}},{"node":{"config":{"id":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","private_key":"72cba007b6bddfa0e57451e0f28d74cd7936955babeefb16b4c3de62400c8ef2","name":"node_4f5ab12b9c5127c16739ad0d4f51adce90ba6736cd096eb185ea632789f4b26f1ebabdea4fd3b39dda5409ece6c2d92fd469cf4aecf9d29453e3e042c19b893b","services":["streamer"],"enable_msg_events":true,"port":63336},"up":true}},{"node":{"config":{"id":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","private_key":"5a603b46da0d4b5d7b48ca9ee9f08ca4cde411e8e279454ac25624f0a81580d5","name":"node_11d560045536e9d1b0b1b9e8944e00f0ca7f1e6788c9fdb51061820bbb3008ead92bb7836621bf58da7035c87a28328faecb4cb2e3cdb9d7fa4f45790e6bf352","services":["streamer"],"enable_msg_events":true,"port":63337},"up":true}},{"node":{"config":{"id":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","private_key":"955c0d00b5c9a641e3e9958a032163ac01fd30e25660ec50db255cf9349573cf","name":"node_94088fe273f76e62ca4e43c095ad12215b4ae4c59942328b3985416fb19bbda0cacc143a49eff3fb644ad53a19d3f043260e43dbb70a0aa9c15829c21cecd3c7","services":["streamer"],"enable_msg_events":true,"port":63338},"up":true}},{"node":{"config":{"id":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","private_key":"3a0fa647e1aa93088fd931cceb89e4426c10861ebbddde0f14a58e2a3969c252","name":"node_535f93057d46c4aae0902546550880be0b5ba67dca12350117d471d67f4f2b3f7bdff29bdc918767974c465df8fa1afa6bd6c29c0a36d51f71c4183673d906f3","services":["streamer"],"enable_msg_events":true,"port":63339},"up":true}},{"node":{"config":{"id":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","private_key":"22c2b405d07e440cdef6e1e9d93738f3bf3add71f54493b68b2fa368c3187755","name":"node_7ac5b07eb555af3bb4ca3f0f4b45204d43cc3798c244435909b97d9a32fc3abf0b50666e260e046bce826a7a102a92d389f8f39c5311e83bb34beddac29d50e3","services":["streamer"],"enable_msg_events":true,"port":63340},"up":true}},{"node":{"config":{"id":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","private_key":"98f9b63dc3d1c346c60957731df1731c8b5f7cbfa63ec1e4de06d1b9f70f7597","name":"node_1944f98d4db32c56a5efda5a79aa5f276bfab1e084d6611fec0e735b8bc0f45b457cdb74a23fc83b2377821fa8316123c9877acd6db7c41058ca5d3cfedaecf9","services":["streamer"],"enable_msg_events":true,"port":63341},"up":true}},{"node":{"config":{"id":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","private_key":"fef764b306a01b333cb965c1faf6970b6bf206dd19c10f666d0188e532d27a7c","name":"node_1c2f7ce55a6e38487f3b3fe6083a79f914cd6d7e4aee8f5d56b4a61b3eb584e128c56998db0e13e775edee3adacf54f09960a041dab3daa80a4f8a3b42760c1c","services":["streamer"],"enable_msg_events":true,"port":63342},"up":true}},{"node":{"config":{"id":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","private_key":"aa54e42fb6be9a738ce973816a814b29759c40f5ae5c57ef972c8957be9d1cdf","name":"node_6ab6ec15635b2fda22542c99df0a3313ad4583ba0fb3f31b8f314e3ecad446d3fb0fdfcd2be9b08374b1a7e049fb68e69e8dacdd13f1df5007a656f6b11adc5b","services":["streamer"],"enable_msg_events":true,"port":63343},"up":true}},{"node":{"config":{"id":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","private_key":"c0a44ebed32208583420c7444e83ac3526001946e4f7f6b561c24d98f96cc0a6","name":"node_74d84cfdaf32cd4cc67771f29878f1365120bd65cc14848008d5386a81f495bf88eb4132fa38a2cc109ae1e7f02c9b97597ab9d1a9c19c945e710ab9df07cdcd","services":["streamer"],"enable_msg_events":true,"port":63344},"up":true}},{"node":{"config":{"id":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","private_key":"d38eae2be9d262c3b37bbd8afb82bc0cd431e4c484ae92747ad064e4138e9f33","name":"node_6b4e376e9c94242b6d42688c22aa9ab418cb6dfb1cbca1c69de0feceec8d3af29fb005017aaa6e503cc0c03cf0dc5bcab55e01cd6f64b9efa02ed87c03020003","services":["streamer"],"enable_msg_events":true,"port":63345},"up":true}},{"node":{"config":{"id":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","private_key":"e345c696901db291ce988a19c0ad31ca0a38628ebc03c0bc87307d2c8f031346","name":"node_92d6ef729992f0de886076e5f8cdc42cbbd70b29e79c25e0b3d22b6575d3d2508d47b42f581e335455483d43625bce4e55f88cab9ff2073ee8dab746357864fd","services":["streamer"],"enable_msg_events":true,"port":63346},"up":true}},{"node":{"config":{"id":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","private_key":"7149ecac9f7173c182b233a94bfcf854714955592618e1d9500c622a08fc3faf","name":"node_57cd4c0048b459192ee46e19ec7df777e600f256e0dc8c3019431eb7bec3c020b9504ec7aea3dba8188658ca5b830ec40af6a8540ce10e04badc6c695d009271","services":["streamer"],"enable_msg_events":true,"port":63347},"up":true}},{"node":{"config":{"id":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","private_key":"cf6da8ba09884f084c279f1f25340712041f3c36c9b6be1c0fec270bdf17a875","name":"node_831cde5b651ba327b059da4c7f84b184bdd6bb99c6690ae816affe25d42c6c3dbe5b59e2b6bf23e9d0f6c485bd341ea57ba1a8220d18b0a40e156b77d84f79ef","services":["streamer"],"enable_msg_events":true,"port":63348},"up":true}},{"node":{"config":{"id":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","private_key":"2acdb11a79e469d5e7e20a391253ad6909ecab541c9931d5f7422de792574b6b","name":"node_71f89efcf939294bb94ac669c8afd00def58c8dfad519c226adfa068692d588ef797116d42aa146b9d34f3be35ec7c014022640ab3c0f1f9034e44ab1a26e246","services":["streamer"],"enable_msg_events":true,"port":63349},"up":true}},{"node":{"config":{"id":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","private_key":"63cfea5298455b0cf7952a47db686e5c91ca2f2e16610167e5c15337e67feeab","name":"node_4ff66e9b5d3fd345990bd7605bdc222b78946f0c13b72bf80352812b2426d8f1d36c93e6c8713566004615e8a78ecab12ab0cfba254c0967eeecf8875b25bdae","services":["streamer"],"enable_msg_events":true,"port":63350},"up":true}},{"node":{"config":{"id":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","private_key":"28315ffa74cadce008f22997503621aee7c6df8dd478536421715a17ebb97a74","name":"node_9bd4f0adb9a966cc5ba632f1b540fe9cd6c8e39fe1a041b315697679cfb04b735952062ce057d456677cc34a84301f26bb727a4ab2646fee734f80a22c620746","services":["streamer"],"enable_msg_events":true,"port":63351},"up":true}},{"node":{"config":{"id":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","private_key":"1177b8e7b7ed31f6a54030f8b4341593d3a1d72aae40f9156861650da1746f2e","name":"node_58cfb20d3da3641e0ad529b9edbd4b590a8d1dc9d1ed7b44ed3187dba9260bd7c732fc10981f5b9bffd31d362cb05150173618aa36138984431d94a323a9b313","services":["streamer"],"enable_msg_events":true,"port":63352},"up":true}},{"node":{"config":{"id":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","private_key":"d007b46d1a1f6a2d085b54b2073f46bebdad50a651920b7083908d388be5e5ef","name":"node_094f9d0fd3bacb17ac67a2edb8ed394fbbd1c8d478233d3269cf217e7b788e21042374936b885bf23ee4f9e03babbe4e08db283dfc2a6e052a8a5ba133717dd5","services":["streamer"],"enable_msg_events":true,"port":63353},"up":true}},{"node":{"config":{"id":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","private_key":"260581578bd37f4523054c95aee9f6b4beea4ed6b39edfb8b9506264d93337d7","name":"node_7646d08b3e24183e3814de130235c41eb88a5a2abff23eaff3c91954ad3ef55fe27da422dac5b894312276bf1a2f1aebb8b636a8d4a0c93d9b016d441df3fa19","services":["streamer"],"enable_msg_events":true,"port":63354},"up":true}},{"node":{"config":{"id":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","private_key":"49be559b16c8e23e2031acd1d93ffd182c0f09e54f7893335d04febec1b48e99","name":"node_9b618ad34d0dfe0fccbd5b8af365cbcdbb43e802df5f23e91c20d21f3ead6169d52bf0db7e5e111abef630c9853419fb33a88cf111d8507b8708208b5d65e35e","services":["streamer"],"enable_msg_events":true,"port":63355},"up":true}},{"node":{"config":{"id":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","private_key":"7b742610b213ed9b0492c97d62574eafc92dd73cb24ba74c4f1023fb4d8843ae","name":"node_4a030ebcb1a59230759d25a3c87daed22906b520d55a78eab2083bb52358ddc3a5d2d7c3265e6c54a990bf32d0dacb85905a4173d72ac18fcd74c43ecb8635c5","services":["streamer"],"enable_msg_events":true,"port":63356},"up":true}},{"node":{"config":{"id":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","private_key":"c90aa4ff988d9d5aa9ed033d3c8076c073ebcdcb0131604299ca721f38d363ad","name":"node_e0f78c59a61f2a953553cd5742c58f4a82e38e35ac7eaa237a6ffc9fb0a3a26a2d1d1afae249e611d1320f2cb25804bdbdfb6d77336449716b0f4beb3298b8aa","services":["streamer"],"enable_msg_events":true,"port":63357},"up":true}},{"node":{"config":{"id":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","private_key":"77bd908de80bb222465d000554b9467681aef696c9e1a81e51dba688310dc7af","name":"node_84dfd4e4d9f1204893f190eacc4c3999e175c433f70de86e335d27477c097a0552f211a21764f01a708da4c9e9e6552191a61d3e48f41d0e84f01e7ae3beb34e","services":["streamer"],"enable_msg_events":true,"port":63358},"up":true}},{"node":{"config":{"id":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","private_key":"529ac85f80c2ef25f0cca3417a1745d3573eef2b8cd611eab45c6bf857c87158","name":"node_ba21a373781966135d6225adae024a3f3e421b852f72f8b0569cb92fcff87c33f7e5b799a509b8eff6ec6dc46a9b17d5bae1e91ec7c54c0c712d893d54b140fa","services":["streamer"],"enable_msg_events":true,"port":63359},"up":true}},{"node":{"config":{"id":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","private_key":"46d69d2cb90a6ff16facb7994569557da8b0c76f74d238381a2a53cadbd1d8de","name":"node_fd4968df03d767a223bf7e4dbe26b5c27048298df40e81cad50b344fb3e6837965f2646dab7ffb2891a5c507343ed84bb8bbe403287b51dae538d58fcb6e7623","services":["streamer"],"enable_msg_events":true,"port":63360},"up":true}},{"node":{"config":{"id":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","private_key":"668577a2160c0a19ddd60a032636f42ef4b0f8d7f8b15129b39bc693b04951b3","name":"node_07c63ca5d0309e30d1ab12e7fc142e6d37904b552639cfa97850161491f28f20d87e0304be29357bcfc2ff52fc52fd0d4f6e6011ebb239cced8b5c8dad7abf45","services":["streamer"],"enable_msg_events":true,"port":63361},"up":true}},{"node":{"config":{"id":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","private_key":"ccd33f1981701e030d7880879453393ccb90b02d71fc85a89d82f903d1a81066","name":"node_920a301186bdf665a721676ece7c180413369ea6eff7537f42049d9eb409f28cc864099590116e885f57368959fb2cff7003697d9b1515e68bf3fa7aee0278ef","services":["streamer"],"enable_msg_events":true,"port":63362},"up":true}},{"node":{"config":{"id":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","private_key":"1859e8cc62440d9e1d1c35f842b8bab336798e87932bc4f2456c327fdc777a7d","name":"node_89a5b92a9ca045f12c35a70084e6f41f9775a25d6f105f8c9349c7b5e107179d8a96bdbb113b2680edf5183e9a42fd64bd7b29d0dc7797c583b833f869313699","services":["streamer"],"enable_msg_events":true,"port":63363},"up":true}},{"node":{"config":{"id":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","private_key":"45dad25ea664452913d4fb09debe8987c94b88ef752b058a7bf352f144a9c6ea","name":"node_beec648d79437a5d7b4140ced45d82d035c6f64f9c67c58386703811d97c3846787eaf274d2298df809475f0b7519df696563cb8e9a5fb0a9cc419ab13fa8d41","services":["streamer"],"enable_msg_events":true,"port":63364},"up":true}},{"node":{"config":{"id":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","private_key":"042b5ccd68b8dd6c125ecd889c304299fa18c22841c95b5fae01a22fa98ce96d","name":"node_c73d088ade8756c74832c73542bcdb3e52f670f7a74ad3a7eac2a9e3ece6bd081f782a8e1d3f9a40b9aa9201509110f37fc57fcb10ee1ef3ef07b7eab019782e","services":["streamer"],"enable_msg_events":true,"port":63365},"up":true}},{"node":{"config":{"id":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","private_key":"1a8c7f2f97bcaa5711578ec1de04829d7735f81ba5761087e79a977405ec1801","name":"node_62dab8b21640e1b44dea452dd7e7de93f27a44840da72d56b11aa96e8463f3a4bb15e75a954d19fc897ae0030b16181d271b79d8198b7cffcddaa9ffcfdcce73","services":["streamer"],"enable_msg_events":true,"port":63366},"up":true}},{"node":{"config":{"id":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","private_key":"d7a4980a0fc96842e8e570863a3b8e078baefe4ca8ab2ddf85c7c5d8f541fabb","name":"node_9e621c3eb534855ca292efa27a3fbc89b4f05c80a4bc65bcff2f14ff28ef43cbe14137d2fddc6fe2658bb06947d918476b479dde71469b8680e5d8a7a01619b5","services":["streamer"],"enable_msg_events":true,"port":63367},"up":true}},{"node":{"config":{"id":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","private_key":"d2e98b0004a9b7bdb030d5e729716e7065aa1a8c48efacf471718bc5da8ec990","name":"node_afe5b217dc512eee45575c189826ee5640d11a0ac9e8e4b03e9e62e6cf6df9de500bc8a36cb7d82a2280ce184409164f1772cc5c9e59ad04361522d2b8c364e0","services":["streamer"],"enable_msg_events":true,"port":63368},"up":true}},{"node":{"config":{"id":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","private_key":"bd3302dac250b294208d6ed14b0a14a6d60d75be1f68ce5cd1e250a47032fb3d","name":"node_db8ba71afeaea1f2964e8978a6eceeb9efa3958424424022213c8193443f8d5afd18490afa954c76360c681404809c7cfaf7e4ebd8bd1a42d403f7f1915b0d29","services":["streamer"],"enable_msg_events":true,"port":63369},"up":true}},{"node":{"config":{"id":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","private_key":"f5832a55177daebfda3bcaf8b5ebc11eb44f4d5207b8384fd35999944d2fcab0","name":"node_2f1967b4410ea2ea8fbaf46771ba82c2846d00aecdb6f873aceae33ab38f72d0a2c2dc6046d3034f514efd090d42011d48e9ab0cb4e3caa2b49a96ef732215a1","services":["streamer"],"enable_msg_events":true,"port":63370},"up":true}},{"node":{"config":{"id":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","private_key":"8285330088dc95f441c68f12765ee99f065fc41f665b54a257172d9b4ff6e017","name":"node_a99852c5bf08ea4713af9cade5343d1259bfb90401aca7fcff18c58cd56a98804dd16c61fea71039c0ac31b9bbbb9dc5aeaf0c2f074d3365e88d17031802d636","services":["streamer"],"enable_msg_events":true,"port":63371},"up":true}},{"node":{"config":{"id":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","private_key":"96a76a56912e05cbd480fde154743a65f4bdaba5395cf685c22681fa403807b3","name":"node_4e68553db7be307b8379e8bec383b5c92e4b23debcefca575d24504e2062618f74c26e60e0d9e47f096997a7f841e2c32c994124f495ef3352ef964b33fd3a51","services":["streamer"],"enable_msg_events":true,"port":63372},"up":true}},{"node":{"config":{"id":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","private_key":"bf0a6c406d390baa5a33fc469dd8b3ec25e406364bafa8ad3d9b422dd58b4a87","name":"node_a608a746f46d4b2e9267c65283380d6d6cb8885a64428fb77df9934bcf4dd1723587ee7c8f4a642dce266a12a6a4cf4e5c6db7fa1024158425a6753e7ab7264c","services":["streamer"],"enable_msg_events":true,"port":63373},"up":true}},{"node":{"config":{"id":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","private_key":"4010f083fe123b4e1e1091a054b7af104d76038c1313c71470b38aa16a05688b","name":"node_fde7705f5013c3b6b76a35505c1e3d57c033a337f2a71e912ec3a3d2da8e113bd7c36d94908357e9f7654660621f647ad8c66b0126dfe91dbfa3b8c7bd2183d3","services":["streamer"],"enable_msg_events":true,"port":63374},"up":true}},{"node":{"config":{"id":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","private_key":"e2894e5fef7fae6c4a6969fdf39bb99e8fb16849881a5a7d45cfde92ab16232f","name":"node_3dfd733dde9414af916625ab981777ff1ad7ca0f6d1e4e7d9e2739969e21182fd13d85e281868653e7325b20069356b11524b54143c47fd3955a911cf7325ad4","services":["streamer"],"enable_msg_events":true,"port":63375},"up":true}},{"node":{"config":{"id":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","private_key":"1273dc5cdf253e8042d52ca10f80d25481d40b5cc80b37b3e128edafde8fabec","name":"node_5142eea687de4248b2184e9896b245563117648e7a156255d9a7ae730313d5d383db3be1125b5accd7e743c2a5d8c3289ec559ef7cbb803b9e82cd49bb213d9f","services":["streamer"],"enable_msg_events":true,"port":63376},"up":true}},{"node":{"config":{"id":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","private_key":"082369e49a61588917d594d0a90c2d53968db7910a1fa9a978da33f53d8f5166","name":"node_b597c9ba4da20c49fc4ba019571321d2579588636cdaceb9f225706574970adbf4771dcf186b1decd4e14cd5d257e30a36ca829829598c1775902201ad9793e2","services":["streamer"],"enable_msg_events":true,"port":63377},"up":true}},{"node":{"config":{"id":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","private_key":"5ac4501287d61d0083f3143a6184fca450c07d149279fdb3a19ae3dbcf456732","name":"node_72e30d4562673c5c8fb03709d93f73322747858d723b7eb5ef2fbb88e0331252946b7e93ffe434fcb599c4fff57800afb29e6c60a719f18f49dba541c3591c6e","services":["streamer"],"enable_msg_events":true,"port":63378},"up":true}},{"node":{"config":{"id":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","private_key":"cbc289ddf69a20e78f479b1587fe2955c2ee7a0bc7a743ce61c13c07139b33c1","name":"node_eaca77d20c4ad6b87649eba21b750a4b1a2c575e06bc42679d18fce16fea15212e9a7408c16f3b24d8dfd1e397314637e72e292845d09534a39035bd9203ee9e","services":["streamer"],"enable_msg_events":true,"port":63379},"up":true}},{"node":{"config":{"id":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","private_key":"dce8d0367de94896d0c24049979fda6a48f77b8e98974d66472666a5a4365865","name":"node_d3105ede6c21bc643d523afcd1309a5dcf03f70797a92f167c3a19f86ae98882fe1a9d4094d7a3dee4a0833b8075b6c3e9aaa7f4879dc47bb388c3ae85522288","services":["streamer"],"enable_msg_events":true,"port":63380},"up":true}},{"node":{"config":{"id":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","private_key":"138e8952e22f78dbf4ea1aad84cc393a1553192402f5cb23a8d15459d9254240","name":"node_6f60ef501b41f9049419b033ae8d793a18067bdcd60347537b0dc3873bdd9a2d10d24909cca7c39781765746128c2165596f6537a94f58279523faee71f9c51d","services":["streamer"],"enable_msg_events":true,"port":63381},"up":true}},{"node":{"config":{"id":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","private_key":"b50b26bf10abf56d51a891c4449915de09ce392d6c5a8170ae5ea5eb3a082d8f","name":"node_453779010ed7c59761da47ccd8869d3fa8349795e57edb9eea416c0712301ea622c7683858e309d19ab137ddb0edef161d0d00a361abeecf0628c3ffabc629ea","services":["streamer"],"enable_msg_events":true,"port":63382},"up":true}},{"node":{"config":{"id":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","private_key":"269797dfe5cc0dab8d44b114878dd8ec081d6551214db901b361817184a58bcc","name":"node_e2a27dcdee1f89fa362a85c4397840cd8be4ad8d1b9ccb23188c303bcab7619f38772f71385922d090390973b62fb8249efc103f71bc761041bcb3880ec0b935","services":["streamer"],"enable_msg_events":true,"port":63383},"up":true}},{"node":{"config":{"id":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","private_key":"09082c0128f28346808a35b0b607d4e7d6c9ab7e894b5166958bb2eba5f4c0b3","name":"node_97981f4b825620985b746c85824d7a4d307ee25d60a72c2b7de4b1d4f3b1c002652adc3045842d350f849789e410a0357a0b42fa637a1b4fc9d39e44f8a674d7","services":["streamer"],"enable_msg_events":true,"port":63384},"up":true}},{"node":{"config":{"id":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","private_key":"ca130a8083cac47d964d46dbbded845892b326aa4fa12489d21578f9f018d45b","name":"node_fe62314839c93d2f6e3aee984d5f0b321897c6f39e66800d3de8b773baf6f19e0a03cae025df512aea8d5f1b667b6dbb15c192a90a76d3031c14e33e5c16c4f7","services":["streamer"],"enable_msg_events":true,"port":63385},"up":true}},{"node":{"config":{"id":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","private_key":"5d649fb189f6b462f678a083e7ad8d874c6bdeaafe0817cf4b361448024d9428","name":"node_c903c5ee3d9cd65bea3ea777e39282c33e1349d945411fb2f16321bf582c2f400956a98fbafe5873fc5f6f6a9a051df5da7e94cbd340f935abe80f91e79ef875","services":["streamer"],"enable_msg_events":true,"port":63386},"up":true}},{"node":{"config":{"id":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","private_key":"74fcb757f856401d62426a3e62cff6870099b0b261afb281d8d9e7dcf355a87b","name":"node_5420da16f7ed5de6b498dbc9a83b7e92e1f9900a6d04ef7351a0bfdfd442b98a5634f28fcea32ba3f3166d21c8ff5a39be70895b32acbdf7592d1d616a345a21","services":["streamer"],"enable_msg_events":true,"port":63387},"up":true}},{"node":{"config":{"id":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","private_key":"3e1263efdc899dcd32f1fd206de2370195ae82fccb81eb354dd9cb52fc5994e6","name":"node_f54335964d9b4eb9813eb05f40ef1c523bbf0faac5a04c4737467d590fb6b55c7fa1fc5d4d32c5491d8766b9be6fdfd3ebdb25c5ffe1719f36c86ddf87ae3a85","services":["streamer"],"enable_msg_events":true,"port":63388},"up":true}},{"node":{"config":{"id":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","private_key":"a7cb8f80391de65478acf12a59fd0a0e9c5f04f0e4bc1da34b9acd35c586fe98","name":"node_40bdac599b00e9c41ad6476ee415c33d9c17c5aa672692c2404e523b29dc315da929a86874bed87fd9009871805d1dbf3098e7a817193e3b08a6eee66346da79","services":["streamer"],"enable_msg_events":true,"port":63389},"up":true}},{"node":{"config":{"id":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","private_key":"dbbe33233150cc109e4ec1b6d6bf5f14bb573d87551440db2407ec75821b4ee6","name":"node_b26f7c0113a5ae885f7c0e608aea7022a9c8bfc40c5643e60b2ba7343ff09c5be0bc08be34dde3c6b85fea192a46d4764770c12cbaa233df4231a1b99627ef9d","services":["streamer"],"enable_msg_events":true,"port":63390},"up":true}},{"node":{"config":{"id":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","private_key":"1058ecb8bc4354469a7fbef819dd8efc60c72db3101ff2f4d3d8089876ae94d1","name":"node_829b074b70d757da6aa00f7bace3cf1b5d2d4eeadb7f370c1a85374a01a70b54ac53d747267e386f3b41e6d790fecdd6e74b8f89745501ee82439a66ea54443a","services":["streamer"],"enable_msg_events":true,"port":63391},"up":true}},{"node":{"config":{"id":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","private_key":"7a22f9270103c5214bec5fccac665913b7e9ba442667ca7ca7f1bead2d44e594","name":"node_302c37f28c69fdcf00b39ce0c0223de0d94cebc2c0b068315b95b76b5432573ead0656569441029ba9054d8d3d959fd8735e73913af5ce3f1132f8271fd437ef","services":["streamer"],"enable_msg_events":true,"port":63392},"up":true}},{"node":{"config":{"id":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","private_key":"32e05e400e6938d31aa93e7666905a5a12e2b4b706354eae5f34259cf6880e60","name":"node_4e95fb8943ef6502fa470870a7ace4ca11e18589bd2073167543a922317b35e40b5068934d07e56c8fdd23354dfad51fd2899db854f189841f02b5914cd97749","services":["streamer"],"enable_msg_events":true,"port":63393},"up":true}},{"node":{"config":{"id":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","private_key":"f6b0641261c3c0741d61572a591e72180deb8ba2c9922ea5db694c5b372aef6f","name":"node_807340e5fdf6c21a56ef2fd158c32e92201206ca85fcc147165a408f7a735964afd47c397e663610ac53870ae722c0317291732b0422f8aeedae783d9c730218","services":["streamer"],"enable_msg_events":true,"port":63394},"up":true}},{"node":{"config":{"id":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","private_key":"5809952239bc91701c49a3ca4362fe2f96294405e789a467c4899d1dc94f88ff","name":"node_c9cd9dfb9f90a7948ac5a42c7bd63263f2eef6e1d85547559f7d2ecbf5f9cd1eab051b8e9e661b573c275d84091a44e73f6fc6bcc91dcdb674bd5d939190fc01","services":["streamer"],"enable_msg_events":true,"port":63395},"up":true}},{"node":{"config":{"id":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","private_key":"284f36dbabbb181f068bce762670de591bac534570ddba3da4c91381188cc3a8","name":"node_1bc1d6155ba35d29ea16938994e08df76ebd8f16bd180bd6a9b9d8798d0745889fe72d641dd78bd8ec13526929f7eb5aaa6a388430fa69033d6db581e53c6422","services":["streamer"],"enable_msg_events":true,"port":63396},"up":true}},{"node":{"config":{"id":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","private_key":"c1b4e417ecbce61a39ecf4a30b86e303e82534bd890eea7c30b6ab4d0bdca861","name":"node_e267e71c2dcdbe5a500b23444d2d4037ea15afba8f4f2b1c0e54a274450404fbee6fa5439f7cddf4ba1aa28fa93e434b01c239add58e30a5423ca3a481584d6b","services":["streamer"],"enable_msg_events":true,"port":63397},"up":true}},{"node":{"config":{"id":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","private_key":"eda1f1637d46610c0a885d4e08d8d4e776868f98be4dca745ebfadda65f2a81b","name":"node_e98a08e8e3544727f5ee27f4465375a67ffba490fcdbfe7bfdc909f6b68bd279f776c65d38c2ccfc33079f852f76349c94d68fc6989c0d981f22333f036a4bb5","services":["streamer"],"enable_msg_events":true,"port":63398},"up":true}},{"node":{"config":{"id":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","private_key":"51d301cb37e7206eeee2847d753aa67cbf0513b6e7cd41022003c2e7b3ef5581","name":"node_cb310c0e86aa455d7c9af6394ae38561c901da30a51d7ccb7e66a09d9a8f192ae8caeff106043426d56397088f141c4e01e3b98f1ee583ffc7318b5f730f3ac7","services":["streamer"],"enable_msg_events":true,"port":63399},"up":true}},{"node":{"config":{"id":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","private_key":"30d23072d68ccfe357cba2b3294b9584b591e8c7898031f7c4dbaaadfdd05e1b","name":"node_1090e9d89cb278a30063a5396d9ba795d3bbc237c76915a6fb7d23aa1822c8535d2fccc44cc8cd2acec68444c0bf1bdf5195ebb9f3cad8dac3d94a4d9c0e5309","services":["streamer"],"enable_msg_events":true,"port":63400},"up":true}},{"node":{"config":{"id":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","private_key":"90d8283793c2eb15b76d7d9e492b3c3e7136115c74bf027ad9985179380a82b8","name":"node_4b784f072b7c96c30612767425f552e30e45157e70139dfbe0ae4ff86dc31601adec60f8a3ad9747b02b5219073d8813af9b09d59eaf7ddb7ee24856aff6fa8f","services":["streamer"],"enable_msg_events":true,"port":63401},"up":true}},{"node":{"config":{"id":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","private_key":"b9111f0cf5ecf0a5dd7683f07c58f581a175bfbdf307224db008d7792e30c6a3","name":"node_22010c9829626a6892258b09cb3f3edc3f21382fb487b5dbf0dd20e198e37e26134aab850e30337f398d1491b5126839aeb1953ec144bc19aeb889c832f67c6a","services":["streamer"],"enable_msg_events":true,"port":63402},"up":true}},{"node":{"config":{"id":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","private_key":"7652297b6b2c9a5339f9d375aac2c9b81f0274e3949b4033e513c02802f040bd","name":"node_043fe7085e8c90c18270f84dba5fab138e50216a1cf8d81a3794d156fad7fc81d1422aff169b244b13f91d73eebb5de464f97b1b93b3ad2a58959cff19238842","services":["streamer"],"enable_msg_events":true,"port":63403},"up":true}},{"node":{"config":{"id":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","private_key":"7971b1a36d0caacd64acbd61a149d41c05102d757fc313f2c49c6b2185bc22d9","name":"node_329145e75496cecb5f5c8f00313a52ddd8c0e8cd27ef1b2bc1b2b56e4d4089aaf5a7a3c4d9a40bdb92483fa05bd24d1cd0fd51883e30439dffa0fc855e1a7cd0","services":["streamer"],"enable_msg_events":true,"port":63404},"up":true}},{"node":{"config":{"id":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","private_key":"62692081cdf8e04e73d8942c5fb423f153ea6d32d16fc0e3b05c10927bcc42c3","name":"node_2a63d875e715c2a43302d32d86d30c7d7faed46c08a67bf488762637216b99dd87333a66df6d9f3a57df863b1f1a219ddbeebb9f3e92e523bd08540a195448ca","services":["streamer"],"enable_msg_events":true,"port":63405},"up":true}},{"node":{"config":{"id":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","private_key":"bff5d02d0e187260b2ac19e027a5a8c72d358aa420a1dd22dcc8d34a921a81f7","name":"node_0deda014fa3c0bc8f37d853e1448f95f56f97048c28797d72258fd3ba2f1f776ae11566197466596356cd172847ab02a89f4cf047e58383249fb2a4cd69b6206","services":["streamer"],"enable_msg_events":true,"port":63406},"up":true}},{"node":{"config":{"id":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","private_key":"e2478cb11c2e4c83e5be5962e0a2e9dd367bc4bed98c7bcd08c211f35010b4f8","name":"node_c332fe1f9b6e25f72c7150631ffa6e0929ff6eeab5d17aa45eaf669bdde869cf404505ae990a529aa3ca797cd0a96f31cc41431a5d4a163132be566f91623c08","services":["streamer"],"enable_msg_events":true,"port":63407},"up":true}},{"node":{"config":{"id":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","private_key":"c4dc5aeb69312070307af3c8a24d468a0284733f29b07b5407e0819cb054fbdf","name":"node_5566111b7f14d8ec83ba6456488f3fc5c7e2c86bf406dead33b814e1ee9b569d34015a4d88226b7e28fff7784395c086d106287cbbc80acfe75b05cd6e12903d","services":["streamer"],"enable_msg_events":true,"port":63408},"up":true}},{"node":{"config":{"id":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","private_key":"6832f6f7e27fc6e2c9745c44ea7004ffd4f6bd869b779e15ac0a4a2ffade7999","name":"node_b4a5efa9028b2d196855393892f79993c2812d02b758f98813ddf82c5d943faf6d66eff811cc5a51936c118f4c768c0d13b54902095e040c602761e63c08655e","services":["streamer"],"enable_msg_events":true,"port":63409},"up":true}},{"node":{"config":{"id":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","private_key":"3362a08daff495b41e00fcb4786a68fff7a58eda86b6f6cb61bef90aaa604daa","name":"node_adfba6d883cacbb141cd8c59ee04d7e5d520f1ce31a81e5db2d8b2380bf801c1fe4b265a66b71f9643d13a41cb1f6fb4b83399be786da4b6e171b6784bc56e49","services":["streamer"],"enable_msg_events":true,"port":63410},"up":true}},{"node":{"config":{"id":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","private_key":"1d18aaec8f9b90606b18283e8527016a8122999804aa11d280ab2bb37f14a948","name":"node_2bfba66ec9d63e928d77d455f2e10a14d6213e515099d5db14fa44a8bfc147eb0fa7afa9aaccdc86453c6903b55556059a2e13dd61fc494127d4a3ec173bf9ea","services":["streamer"],"enable_msg_events":true,"port":63411},"up":true}},{"node":{"config":{"id":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","private_key":"757285cfa33b746d1bf24044430d43f5ff7401cef2452217ac9fe5fbce629acb","name":"node_0b7e1e5acabcde503ad827e45724402406114a513f81040a379b0f82df2eab4456b348b27936369c49e3c264d971c6a9e2c2217fdbc5e5b93ac6fc219957834d","services":["streamer"],"enable_msg_events":true,"port":63412},"up":true}},{"node":{"config":{"id":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","private_key":"cc0bf84e41ddcab9146ec892653a911dce5007786d77ec7a32e490fea0a29687","name":"node_7554993f6efd8d9016ff525ae73c41ee2e0dbd4970c563ba9b61a99c1c8943b433c4b7d48450f6e0fbc9ac198d907698093de20e6c1f7755520fb1e1cbee4eb4","services":["streamer"],"enable_msg_events":true,"port":63413},"up":true}},{"node":{"config":{"id":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","private_key":"d1add26924dcfc37eefccd6271759a9b0a2052607f3698be305e1c9bcb47ea66","name":"node_4fe37f2dfb03707c90a6fe91dbcfd7497db70ffc20043091d50e1cee573210c144e8749340f2c3cb70fe8fc51b317d49e8734dc51ce64b3cdccdd639ae35d1ae","services":["streamer"],"enable_msg_events":true,"port":63414},"up":true}},{"node":{"config":{"id":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","private_key":"fb8563b48e2c07948cc2347d50c953b2b4bcd79a535c2ac597d8f8c7f1ffa8e6","name":"node_a7507aa5665e165ab2e2a07def272f0677f9d6d35bb82268a34214384e7d8ef7635a299368752e63cfd02d4e60231076baf23cfa10d17492e55181b391ecf335","services":["streamer"],"enable_msg_events":true,"port":63415},"up":true}},{"node":{"config":{"id":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","private_key":"f7b5d2c9faba98230f0e0bbd82106d1fb949413a7940eec52e71e9c5c7266d3e","name":"node_7e2b0b4f3b55e97bd7241b984ad117af33bf3baacd22b3ed503a8a59f75828df745fb3ce3be4276d83eb484e64d9aa251103fa994ef119eaddb97a3503b9f292","services":["streamer"],"enable_msg_events":true,"port":63416},"up":true}},{"node":{"config":{"id":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","private_key":"61a9bec441ae9ada2f3ed71874596db20f2807e921453ec39145770056e3cee5","name":"node_460531928a4b084686343c8464b37c3452bb3566045698d08a4692864de5581a9eb1dc632329e7d3ccb73ec31ee7693787d69df8458efaba9a7105d87ee2e053","services":["streamer"],"enable_msg_events":true,"port":63417},"up":true}},{"node":{"config":{"id":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","private_key":"56e11a31d85d33461e13dd635ea6c0d0be892feb3ccc9dadc327bbd855401d2c","name":"node_70ee3c7e02a123f78345d41c386e413f06b51f1ab346c2c472891eed7dd26a1f14e213a0f4f2d872859b9b535936a6d9b072d2604456f76221a422710411822f","services":["streamer"],"enable_msg_events":true,"port":63418},"up":true}},{"node":{"config":{"id":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","private_key":"6df50913c97d23ce9e4ed894465ae4eb0f562d595e46d694b47e72d31c8bc8fd","name":"node_049a2b0ab4d49789dbbe1837e2d2ee5220a9401729ea87ab29385b24d79cdce255c3d2b5de6484d49ca6ce07bd41832598260c0a8c290e01d133d77f066f2f99","services":["streamer"],"enable_msg_events":true,"port":63419},"up":true}},{"node":{"config":{"id":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","private_key":"164a5b537bdf9173b59b281a68d7da48819c2367e5b5faa1c94c74453a413015","name":"node_1f6d803a4ca186463772850ca0901fb920af7e74fdd2480c3c368fa707838ee91bbcfb57d5e3510c802b9b85f2d954f04c9b675414274bdaebae6488dcf94c10","services":["streamer"],"enable_msg_events":true,"port":63420},"up":true}},{"node":{"config":{"id":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","private_key":"0b14673d7790bcbb1b3f0d042dd9b22953002e6dd901486b6f203063bb8b5a79","name":"node_979838eaefcff456cf1cd9c47ea46854704f5757d8d7ab907019bc422b01af4d62252579bf045d143fab491b0bab823190e2782a457fbf51aa99ae17ec9e145f","services":["streamer"],"enable_msg_events":true,"port":63421},"up":true}},{"node":{"config":{"id":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","private_key":"5d6c015866ee2afba25f1435274fb61e0b11b93829309bccad6cb662e5a4c8fb","name":"node_ed6c793eb4565aa9d883a76fad6c97ad0b878b9ef0235e11e89db1af25a9653205f725c6ea258b84bde134f1a6437c6d109b859d17509e5016c4ab98be59032a","services":["streamer"],"enable_msg_events":true,"port":63422},"up":true}},{"node":{"config":{"id":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","private_key":"acbf964dfcd41c86715a5ecb9c03818b577cbb0755692cde879ff1e4b09e5df6","name":"node_6c143960dbe3ba4c95e8debc1fda5f420a2a673eb46f7ff7d9a30f4cd2067e67ef8926bf17f0c99b16c79b6dc066b52409a11d47117d4fda4211636b1b74f96c","services":["streamer"],"enable_msg_events":true,"port":63423},"up":true}},{"node":{"config":{"id":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","private_key":"0b325cafe8524b8c126e860a6295fdeff6cf26da5e8eb426b86b25ba049c942b","name":"node_7bbb3f3ed51cf84c077806fbd6d3578e105bc32aa6043da188793f066ad6df383a9f7cc0bd3124f4c887704bd188d480ce264fcdf178905bbda3b270927ea138","services":["streamer"],"enable_msg_events":true,"port":63424},"up":true}},{"node":{"config":{"id":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","private_key":"e03e1d397bdd121257b1cd781c14847cf220f23fa837a4ba7b48f7b0b51cdc3c","name":"node_2b70e5ffcc0bb1c4f8acc09dd1016e67c9c96c92d091ad481efbb71bd8b2a5a5869c6d668617a9b2cbfe91baf5edfe150c3824c84d90899a974099071d171441","services":["streamer"],"enable_msg_events":true,"port":63425},"up":true}},{"node":{"config":{"id":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","private_key":"8e1b0bcbebda90c6f0ba8edadd9133b28b77e49b584580e1219654aeeb9e3a2c","name":"node_f5c1215a84a56d52f92ca0dc3a32df98c98a9c2ea2e9a34560210c16de1b440d20d043c8c25955dda8c22e55e92ddb49fd82e8b9b84072aabaa755a229bb19f4","services":["streamer"],"enable_msg_events":true,"port":63426},"up":true}},{"node":{"config":{"id":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","private_key":"ec0e383740a40976e4b9195b6a89e9497e9562729d196b3febbfea319be5dbcb","name":"node_8c6d77833bf1a98beabe7a92d985d13d52fb2e50768719ffbc6fce21ea676802a074b6e620b3ef80e12fad04f94a3c288d91df9716a6cfae09ef073b9dc1f2cb","services":["streamer"],"enable_msg_events":true,"port":63427},"up":true}},{"node":{"config":{"id":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","private_key":"a8c69a5c41f2362bc5de8589f3686f3c59b02b58cb7139ba2325f1a7ff62c39e","name":"node_b3316f4fd7dec218a52331f25d17a2faf0f2a417808d7dbb80038154abfbcd2d78da074837b648cff28675f4aa0d65ddb7d15abf3d7e0391d401e313a3ef24a2","services":["streamer"],"enable_msg_events":true,"port":63428},"up":true}},{"node":{"config":{"id":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","private_key":"65ded6c2ad477ee077e81c1aa90fba5d4e0d794ea8dd5241a1545869c895185e","name":"node_60725e8d0e9333636e598dd666f459b4be898d9abc095ee2c1db289673e7e969b50e2093956fef5a2f1d23e2040159bbabaaeab17fc6dbbac3f6acab766e9e60","services":["streamer"],"enable_msg_events":true,"port":63429},"up":true}},{"node":{"config":{"id":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","private_key":"9e522b8e7f94aa50d51d7ac396a12701677f86d0f9ad7111b329ba8229880db1","name":"node_48a5e01e06e297dc1c640ac9601171495bd70fea461c60e7e6e2532695e45fcf68183c2e58b5e6931a6c1c094f5331efbd7f2d93d5f84efdec5a35afa2124438","services":["streamer"],"enable_msg_events":true,"port":63430},"up":true}},{"node":{"config":{"id":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","private_key":"2325b0e86e0abaef149e6063ff789995d1f6d863de595a5abcebffdad494ebb9","name":"node_5dc69635f6d573c824ea83b18593a47f9f21a6f91ce18d2bf977c97d21f8d2a8ce88829244d12a07d949bbd52fe8a2035bc89685fe1bdd4ee20d766d75d3deee","services":["streamer"],"enable_msg_events":true,"port":63431},"up":true}},{"node":{"config":{"id":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","private_key":"dbdf629720f7cd6d4a8e26a5bb6da882212d6cbf43ddcda4712539c3db89bbf5","name":"node_ae4e21e1587a8475afd299e00ca7085c7bf2a44c2c64a3068f12223d9202b0125094385319034691ec26b497ec9cf18fe8c0839224bac1b84279410241cef979","services":["streamer"],"enable_msg_events":true,"port":63432},"up":true}},{"node":{"config":{"id":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","private_key":"315e74a348a3f8e172319c29da33577435f6415466e8cc289af2dc7e142987d7","name":"node_0b30b36e155db04c448b662c4df695068b2331cdbe2772aae5fda84159e977515a5ff2e156bc225a9281fef2383926ba8cb11e9c1846fb40db241e524ac14e29","services":["streamer"],"enable_msg_events":true,"port":63433},"up":true}},{"node":{"config":{"id":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","private_key":"510061145b0b868f1fb7e83b850d0901227724f4559e912c0561ac310308ea80","name":"node_17a79cb279306b6bbd35219278f6bba03111079d6c4fadcd3c5e57b09678e111bda5f8e36ca3d223e51e255d6e857363b7741e438b32ec6e6c0dc1b224071081","services":["streamer"],"enable_msg_events":true,"port":63434},"up":true}},{"node":{"config":{"id":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","private_key":"b4c3b4d3b3fb735ed7f1b4dbfa53fb08ca505f7570d376ca8ff9ba10c108fea8","name":"node_617595a230e0a74a3db3b47cd27b941e02bdee9a84cdfa8eaa63a55941eb5caa79e20fb69726a4d46a0e5aeed24039f8c5a20679a692df0bc140f42558ca9a2b","services":["streamer"],"enable_msg_events":true,"port":63435},"up":true}},{"node":{"config":{"id":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","private_key":"0ceaf25d118fd30dfa73bfe157c4bfdbdd7bcdc44e699e71e2e397eff0988045","name":"node_7808fb798d22e78fb1d39b87ddf99a503f820993bc64149eca9e81d9d58fc1adea60d8de14a4f06cb89f3190c0ef0c5e182621a14c9361ccb7e0cee667599cc3","services":["streamer"],"enable_msg_events":true,"port":63436},"up":true}},{"node":{"config":{"id":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","private_key":"b8dcd04f9dd7c7d9522112f1d10c32738ce2283cb755c14b83b3e7d8d645c4f1","name":"node_f039df8a3206e6e17eee8e95010038c450cb4cc0b5580ed5795d4c21802e1e9d360f4528bdca794f457932b1d6a818862ec847357a861c488332ef6d9480daa6","services":["streamer"],"enable_msg_events":true,"port":63437},"up":true}},{"node":{"config":{"id":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","private_key":"e0f1d278d1346984b7b19789e39ae0ee607d17f0fc7538e8dc8537b44c09e142","name":"node_ce0a09bb6fe4c9c93c3dbd800ca9c9ac0714f26a8f8dac2149b6ce7a9011912a5621ea2e45de35c4d31dfe5add00558fdba5dd21acf2d81ba391e82b5b3a5804","services":["streamer"],"enable_msg_events":true,"port":63438},"up":true}},{"node":{"config":{"id":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","private_key":"6c9376463118cd8a2c68423af478150a6e0a1b811b922aa7d35974ec65943ad1","name":"node_b2538d4edfa736bfe2cc21326a44ce62f716b3480eac93584a2233b69c98883a2bb255f246218a58cecab1d0d176e6d1fbba9782fd70d4603e01742299b9ea9c","services":["streamer"],"enable_msg_events":true,"port":63439},"up":true}},{"node":{"config":{"id":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","private_key":"d391fbaa56954f68499674edef05d07d58c5512ae18166b141c961a4dea175fa","name":"node_aa9a94d6e4eaaed20113c21752c224e3a052abd3769bd6e832759dbaf5154a943cf094eacdcb0727c2fe51a11bd7fc0793d7d5e3312b0aba89d428a00e1fde0c","services":["streamer"],"enable_msg_events":true,"port":63440},"up":true}},{"node":{"config":{"id":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","private_key":"199542f222419c9f399da0655278169815321c4420c8e39a377faf1446b6da1f","name":"node_65e954e60837bda10654480b227fa3bcc6e63356c52079002a27e836cd82ae2934ba77da60080e4b9f2d9324b982b24959bfd9624302e6c330408381054b43e9","services":["streamer"],"enable_msg_events":true,"port":63441},"up":true}},{"node":{"config":{"id":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","private_key":"ff50f9bc8f6ce42cff12b697c1d4880461773518aaf5f25e5c8a03a8af128fa5","name":"node_8ca3b63cb84f1e9883d82809a9b6777ec1029ecda96fe93b4d494ee9cbefcad13f381b3e480136e542e01054fe1ede66c65db84a0009871ce49383db461c8438","services":["streamer"],"enable_msg_events":true,"port":63442},"up":true}},{"node":{"config":{"id":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","private_key":"2c15cd49d4a7fc8bf1acbb4f86987efe85c77ba2712f82531bf893084ef4654a","name":"node_caaf695c76cf7c047d3f3bfe019d01618e4871cee8ff3f347913da815bbcde145771486f916a44d03f59ea9bc217f169fd0c0765fda3f9b9b28d02a522e180b4","services":["streamer"],"enable_msg_events":true,"port":63443},"up":true}},{"node":{"config":{"id":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","private_key":"4c9c04de05a7a437923df855213efcc8c9489ba08352e267097b6bca9e840fba","name":"node_b080891d4ba6d3ab224984360597f9c555bd1367630f5420bfaf230419a05b2be58bebf1554e53eb4c0da81cfb66d4f7697dd65143f11841ff62d8a0d82b6b67","services":["streamer"],"enable_msg_events":true,"port":63444},"up":true}},{"node":{"config":{"id":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","private_key":"5b756c056cbcd8e0a9a926f6ebf3360d7587152f836459cd22eafd76c3984af8","name":"node_2ca05ffc0ad771e1e045a47f1c0a79ce374a25e3c0e53c2a80d67e7479677003f62880251a83a5074f1c9651d828f1ff7e352935a9df141c1eb75a0c59b00a8b","services":["streamer"],"enable_msg_events":true,"port":63445},"up":true}},{"node":{"config":{"id":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","private_key":"fd26d9072de53e5f0a3d88d7c32e80650d289f661906c9837a7a0a003f3520ac","name":"node_8d4920d6e3a6717699b5a3af068cbdfc16858d7e393d158d41b1b5f345b47129eef89e1d055386c518f400b134678c21590f0317dea3436d4cef60f45455cf12","services":["streamer"],"enable_msg_events":true,"port":63446},"up":true}},{"node":{"config":{"id":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","private_key":"3e2d345fa05f2ec2c8c4ae80fa808f0acaa098d08a2a0e7be1a2749f7d01f0e7","name":"node_b6a998dea59194cc60ce97c7c9702368411889cb6905516b23f41cc5116fba8d0f237d418318eb0c333cad18003c0e9a6bd8c99080520771f2bad640e2e5ec1c","services":["streamer"],"enable_msg_events":true,"port":63447},"up":true}},{"node":{"config":{"id":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","private_key":"69afb2f43d398d53995f3880ed20e91b1d92307e4f7b40cc63a785ebe01f5e9c","name":"node_ff6f94005d1df7677600069764855c1c2aa0543cbe9f480f8feefec76c49d9e2c7bb2d8e38c89e9430f53f8b593d93f143c45985a56a5a32c736128214c95eda","services":["streamer"],"enable_msg_events":true,"port":63448},"up":true}},{"node":{"config":{"id":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","private_key":"30cd694a144038e53930a6b5e32f95f2c9caa886829d241c282f385107d7b824","name":"node_315b8a1711f680c2eaa607e35ef7a9e19c2b61721af8a7e08f1325dde1fe33cf1f47b3cc4acf12d541631041cf1b42754875fd1c9b66ee32797b72b9f7711256","services":["streamer"],"enable_msg_events":true,"port":63449},"up":true}},{"node":{"config":{"id":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","private_key":"c1480926443179b2e410d0303830b51d36dcce107b45da1494d87d2bcfb4f2dc","name":"node_396c703d27bfdddf91761f134cbf665fe61e0b3a5d24036a4105a625f72e8c28b821e9200f20d6e8f8b3ed6b95bda6b8accdd840c2f786720b7431e3af2af981","services":["streamer"],"enable_msg_events":true,"port":63450},"up":true}},{"node":{"config":{"id":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","private_key":"e91e000d37d0a336fb7eaab8ca7baa4db177108f2140ee86f7bef5959b617e13","name":"node_cd8815d66aee8bd488d4e5e25f0cc9c71cc65349f701ea26b1d6cd9c039d16fcb473dbf270a3b33187720ccf4b0ce4f78a6d6edd05f4fe804772d5b6ec45bbd3","services":["streamer"],"enable_msg_events":true,"port":63451},"up":true}},{"node":{"config":{"id":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","private_key":"991b1ea8ca82edeaa0c2d410b9cc297064d8d6668b9c8fb3277a6e7a934bbdcc","name":"node_7174eca109a1f717653918224c8cfe1b7fbd666405196760913593401eb79f2c7e41003b01f5a458940695b27a4673443c7621a169db7fd968994e552995dbbb","services":["streamer"],"enable_msg_events":true,"port":63452},"up":true}},{"node":{"config":{"id":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","private_key":"0c19513041b301f0745e678aa627a44b7cc58099c6616d5fed0f4e4774c5378e","name":"node_59b53f8a562bee519276e0eeccfcf8c975d3102f5d0cccf5abcce291a8a5bb817c04604f123686177a50a03b9d7559ac469962d0159d1d93e4ce58a304d04b55","services":["streamer"],"enable_msg_events":true,"port":63453},"up":true}},{"node":{"config":{"id":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","private_key":"c4406e8f5a2cc5a62bb4c36a3c52cd7831b3a82f06cc18e2286589a6e76a68eb","name":"node_f915e2398aa5d4370de87504dd76c21a7d0be2581c2ab55b7a47743f1bbaef36384eaacec22760f1e914ceac9d96a10c3d66eb27475ef444e77fee979e6e88cb","services":["streamer"],"enable_msg_events":true,"port":63454},"up":true}},{"node":{"config":{"id":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","private_key":"770f973cf2fda14f46f1e91ae608e0b87e0f06b2f8935bba64a43c6998737b9d","name":"node_1b6cad4f9851cc584c5d1405f976bb51a52e27ef4525847df543dcca65ca5eb1ef229dcc68ccbaaf00ab1e044cb5990dd213c805bdb4adcceb6fa70b5c61fdb4","services":["streamer"],"enable_msg_events":true,"port":63455},"up":true}},{"node":{"config":{"id":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","private_key":"2e741e89b7e631818e4edeaee9d795f912805724f2eaaa83e73a3a9e660da435","name":"node_ae2a996d3b562cb47a564934037949da83b1bfe194c23754f3dbe2372ec27654f4f3b6cb7f394570f308025589c065870477667e5560dbe5a8ea1625740699cf","services":["streamer"],"enable_msg_events":true,"port":63456},"up":true}},{"node":{"config":{"id":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","private_key":"c8d2153c48467773449a0c055a3527062b7ed043e491b6a81c6285b5bea823fe","name":"node_ddaf3f8478501cda872c056c72063eb64d5b871fc5fff70704872802289dd2d348f73bc342b7f148a90cfaae2448ebf16fea196be9df891dc71a57fb410d59dd","services":["streamer"],"enable_msg_events":true,"port":63457},"up":true}},{"node":{"config":{"id":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","private_key":"784f624bd696dc1d6afb5bb977c5e6e76ab280e55c95949a68349a62fcc32c70","name":"node_5eccdbcb15ef42dc96abcbcd8b8db75d9230de10e3c650620737f6cc04ba4fdbf59ded5daa801901c191be186c329ebcd37ba83bcf794064ad4e11bf10d3f775","services":["streamer"],"enable_msg_events":true,"port":63458},"up":true}},{"node":{"config":{"id":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","private_key":"f4e049b715346f2e7ac1e31341d0df32e7ba9ae1ab6d9165b7407873add289cd","name":"node_8dd8ad560af84bec579cadb33d51711aa61b6ed22705010336df5a71a94591173b25e869457429c4a199b205fce8e73530e28203e18b971c2001715e610f152a","services":["streamer"],"enable_msg_events":true,"port":63459},"up":true}},{"node":{"config":{"id":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","private_key":"98e1264b7003ea79b1e799c87cb3c8e1aab2ea2e68531cf41f093c4b9f6a98a2","name":"node_28d3232c43de54ffdaf08f97b334c012738648b04e2876c7e751a2e352aaf4d550d6efa976c5a8edbfa8e88b9d04a0fca492b81c3756ef673ab74d34182ca711","services":["streamer"],"enable_msg_events":true,"port":63460},"up":true}},{"node":{"config":{"id":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","private_key":"357e1ab3ea555b0928cf10ec54d8842dc9c0b24a90fbe32ad1a819c018b0c26a","name":"node_be514f5f17f3177235acb24112b578edf0e373c469073226e547d18080905fd062d572be18e943f13bf9fcf5871e89ceb630a1b848a0e370ef8ef8c6d997a363","services":["streamer"],"enable_msg_events":true,"port":63461},"up":true}},{"node":{"config":{"id":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","private_key":"ad08dbea349545a36c8160aa460902c7d2744218b8ff5b8af229a17675560755","name":"node_66d0c5da973d9dd65350ae1ec63776872cdb7ded6afb6f51ae82259f6fd35e884375d15de290625f02ed2e5cdc3f591decb45e5fc64d5b0f835a216fd196f5a3","services":["streamer"],"enable_msg_events":true,"port":63462},"up":true}},{"node":{"config":{"id":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","private_key":"8e27f11572dc1832939cc80ada2ce9604fb91d0633410f87cd7bf68e4629b32d","name":"node_2f360209383d6de4ebd3b4abaf77796520b8654270b03f2151eac4a01b4417d7e0668c1f9ad30c20ff49aa8a0ab33dba5e6095619d1cf04b7af841722ab773da","services":["streamer"],"enable_msg_events":true,"port":63463},"up":true}},{"node":{"config":{"id":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","private_key":"4a7cb437d9c60831cf5e8c6d02e0f62205c1a2de83d9879d1d82ecb6e9b99031","name":"node_b35f418c7935cc54278e90978c3ef1521ab91daeaf9f1ebc1cd25211611ade091cac4e1f009d71059279d507322a4536501980ac0dd44caddc52fd4c593879f7","services":["streamer"],"enable_msg_events":true,"port":63464},"up":true}},{"node":{"config":{"id":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","private_key":"18216d0babc8a162ed03e1c866e0e90d0ea5fd5c2c2ea3f411886de38bf58640","name":"node_fe8ac5d33cd8ab6a1dad9567cdfb89b431a5c4f4a584fc608b92e7dfd06f70988e71e2f11f9fda9ee797c9ffba83bc085939fdf2522dde39f28202be92650566","services":["streamer"],"enable_msg_events":true,"port":63465},"up":true}},{"node":{"config":{"id":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","private_key":"bb317b572ed4481d33b6a67a267264366929dc0e2c12ade71a203b8b3159be03","name":"node_352407b42726dcd1aacc46a912ed8124b8b6a3da4e33dab742e40aa2452953d35dc8f42eddc76695ae2317e9f15dde2cd21be4ce826934695ad1847455661d1b","services":["streamer"],"enable_msg_events":true,"port":63466},"up":true}},{"node":{"config":{"id":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","private_key":"bd9c51ff7ece28d9a9808386358197110aa9a2a7d4715cd033a94c4d1d54ee76","name":"node_b137cf2291b530a39516d882200848e7f27a2710e0839b4d25b4f367bea6a0c3aaef8c7c7851c00a2945adcd819ea0508610afc1f453b8bc512b7b4d4faacdf3","services":["streamer"],"enable_msg_events":true,"port":63467},"up":true}},{"node":{"config":{"id":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","private_key":"6113b0494786bde04defd28e36030dad5b4368563b7b6b63c08475c18980a380","name":"node_1b063741c76fe65e62b4eae42751319d0cce66f22dde9f1cf83d6cca249a0e65bc7f6f22597697362fadd226222fb3847f8e146961969d1b4c9f7e475389cd8e","services":["streamer"],"enable_msg_events":true,"port":63468},"up":true}},{"node":{"config":{"id":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","private_key":"9875ab2bbcb806524e7fca84b6aba663cbbbec2d533a47e2df6f3fc85e1d8e55","name":"node_657d5370319128d24d925b41065eb619409d63ec6280975d78877a4028287463f6442f5206dd703569a05b2b542ad8bbb99803da265408208d6356a26d283d08","services":["streamer"],"enable_msg_events":true,"port":63469},"up":true}},{"node":{"config":{"id":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","private_key":"43de756eb52b963762bf62085de3293461cb2c53dd70baced6e3c86981545add","name":"node_a127faa19dcb7da585983d36a8e9d3e9a44a6db68507b60c70da71011f44ce377944802f39cd65f5a705cd8249ac1ef7ed8fd699349098f3f8e23b37592c80ae","services":["streamer"],"enable_msg_events":true,"port":63470},"up":true}},{"node":{"config":{"id":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","private_key":"af731618471023aff01cd45c69001d7fa95752c4d42c68df95eab820bb70bff5","name":"node_2e42f845d0393d1682add54ee30b60a953ed283e75d347bc6719ae0e91f6676282e7960f1fd52e5803d6b341fb3582c724b4f9cfd7bce9ce85f13ca480c7e72e","services":["streamer"],"enable_msg_events":true,"port":63471},"up":true}},{"node":{"config":{"id":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","private_key":"3444df2021104f7c577b25a23c3fc0231efb2cae1375cbae67db5602cbbe13d9","name":"node_6b01079463ec2f649db8634cb7a596261c79a8f714d954c772528e0547b017f8ce405e4a0ea9d32270848180e0f77b8c0b022cf95c85e777626edd4d24ea21d2","services":["streamer"],"enable_msg_events":true,"port":63472},"up":true}},{"node":{"config":{"id":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","private_key":"638383a2262ab3e1cb5a1cdf134fb5a0077f21e3bf90118cc03311db43b1cf0a","name":"node_2245f3bf1a3b4e92f912affc75f757cf648b20474c11ffe947884f216b8f24f9dcb6e6a0358a4061b8517478ec15027e185b2f05a777573b4940375bf4aaf2be","services":["streamer"],"enable_msg_events":true,"port":63473},"up":true}},{"node":{"config":{"id":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","private_key":"269f2cacd5854ad6634cd178738e910a093dbfb55bcf42ecd1f1d621f5829499","name":"node_d4b7c787981abec24353c7d496661692233797e3758189bf909a69fe87935bf6da0940daa4f12e81f20c5e88f70b472113688b71a0ae2f91a73ee0e6ff4c8591","services":["streamer"],"enable_msg_events":true,"port":63474},"up":true}},{"node":{"config":{"id":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","private_key":"1f5c7e0be8cb7bacb5c28bf9283884761fcbe8c6b353b5c821d204938da6aab3","name":"node_9c30ad8c85adc7bb52ddcfab2e661cc3a854a689eaa59128d35129d02cd5b0f8da4a44cdd33934a8e2c8fab1760c16d6f2e1c5eb227dc819e85624e63343c069","services":["streamer"],"enable_msg_events":true,"port":63475},"up":true}},{"node":{"config":{"id":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","private_key":"975ccce3cea6896e2dc7fb2fb8399b56deea3eac98f96dfe331602f06386ebe2","name":"node_c8b0dba45104fc7c7dff3ce078a0d3f5ade6198bb4656e2bee8076387929133e5ef2bd293b130a9d4f6a6974ca17e8b4a8f406d1219880f1e0f99c65c63af5a4","services":["streamer"],"enable_msg_events":true,"port":63476},"up":true}},{"node":{"config":{"id":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","private_key":"381480a705e57052adb222beb50053c41122d1c2c10b111a16abfc01e2314d28","name":"node_ff1e34fd51953ed641b431aa657da21cb4c81d23e4eaa13c9cce526f1f1b34593d41f9b87a0e10387fe400c623638677c0efab15dbd1014a0ccc11f9ec92c417","services":["streamer"],"enable_msg_events":true,"port":63477},"up":true}},{"node":{"config":{"id":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","private_key":"22c94340e76bf6f9d70e933f2b3cc96d24f64282bc3d4a61621712e78500fead","name":"node_a78f18691e0dbf3c08fe9d7dec188e6a05a93833432fb99eb2b3924ab0bde7a44db2a102a65544bbdc4fb61bc3a3d569230d9843a335bf619167fb045d78ab3c","services":["streamer"],"enable_msg_events":true,"port":63478},"up":true}},{"node":{"config":{"id":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","private_key":"9b0568309c2ef3f512d43d9016f801f55741346b5f56da355dfe5dc54d652821","name":"node_e67e495385e7cacfe659b40d1ba94d4b1ff55eada70a4d9740a9e452fbf221672bd0a897b940e2a6bed71e2a16867fe45bf0ea0015435ac6d815690e263b1899","services":["streamer"],"enable_msg_events":true,"port":63479},"up":true}},{"node":{"config":{"id":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","private_key":"8ee8a33f33bc96603d61297c73e11d545ac229d887345e12f9fe834c7532e648","name":"node_aacff366e601e072a2113add9020e19b6612f3e85b6e607fdc8cc1b6991f43be0b1f835ed3dc41d1f2b3e0caf7fac252c8eb4c150667d48207fa92ea5f0a7455","services":["streamer"],"enable_msg_events":true,"port":63480},"up":true}},{"node":{"config":{"id":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","private_key":"105fa3b2d400eefda08235ac7c0db7af48667dd5a51b8d001d39e06753e93872","name":"node_2f903b2fd4f9432b7d91b5c3e4c7ee3cb9c56fe7efc4baff0edd06fc75e4b7492f2c3c929755746df59c9f95d437a12ba40ac138d08f5bc7aa091f49f3b852c2","services":["streamer"],"enable_msg_events":true,"port":63481},"up":true}}],"conns":[{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":false},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":false},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":false},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":false},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":false},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":false},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":false},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":false},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":false},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":false},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","up":false},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":true},{"one":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":false},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":false},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":false},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":false},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":false},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":true},{"one":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":false},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":false},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","other":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":false},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":false},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":false},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":false},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":false},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":false},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":false},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":false},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":false},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","up":true},{"one":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":false},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":false},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":false},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":true},{"one":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","other":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":false},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":false},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":false},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":false},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":false},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":true},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":false},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":false},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":false},{"one":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":false},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":false},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":false},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":false},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":false},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":false},{"one":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":false},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":false},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":false},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":false},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":false},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":false},{"one":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":false},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","other":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","up":true},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","other":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":false},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":false},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":false},{"one":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":false},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":false},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":false},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":true},{"one":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","other":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","up":true},{"one":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":true},{"one":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":false},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":false},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","other":"00c83e87900972472e247a13acd65450a014a4edf0ab1548199699edeb50886c","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","other":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":true},{"one":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","up":true},{"one":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":false},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","other":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":false},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":true},{"one":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"b40da884b5e0ab429b3608ce6030c0f7f542d008713ed1a444c70d9c00989ecf","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":true},{"one":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":true},{"one":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":true},{"one":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":false},{"one":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","other":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","up":true},{"one":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","up":false},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"d2ac9af919a7bfea9d0acd11bc63874beb8c7213941128ba7e7741c7e79e871f","up":true},{"one":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":false},{"one":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","other":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":false},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":true},{"one":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","up":false},{"one":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":false},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"57ee6d3d13e021ae5bb1a7e82c4cbdfeb02164d4305c0b4619a5ea3184d19354","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":true},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"b7aa334a49788734068ac73e4b11bc554776217500c24eb76a85fe02f55ef037","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","other":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"17a00226ac9b2bb0f83e9add9c0ca1bcc830a30e36b1462007fbe261090f7a9a","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":false},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":true},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"aa7876d43dd0ce40f421f68c0d13c8c718d7a7a5e7c567dd20d87d19934cdc05","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","up":true},{"one":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","up":false},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"91088ea79cd8f27da8879760dd21c363aa9be1135437c2b87464426874b597e5","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"69d8801f9f19fec51b636cc27fca2c93e67dac8f3650aea35259d01293d5c9e6","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":true},{"one":"bd39cdc673c4184193347f0efd74bb894f7f36a994c154ffe3dadcd456efe460","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":false},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":true},{"one":"c7fa3f5dd856ac0cd8fc3f2933180cfe1e605b31c630731f3e0a00d392f4097a","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":true},{"one":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","up":true},{"one":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","other":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","up":true},{"one":"0bc30a547e60dc358f1b431b8f44d46471c19de546723da15e5ec3d3afd2ddf8","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","up":true},{"one":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":false},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":false},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":true},{"one":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"2a7d1316da51fc5e1378366a543a73fc40db1eb7355b3e199ee237cc1db81abf","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":true},{"one":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"48ec978577e2dbf0448ab119a3821be5d25dbf5a295fd4f695b9311429538a26","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":false},{"one":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"8ea97f6abd40d70717688c5dd38daf6f6b12005df21ae397dfb700fbfe3447ac","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":true},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":false},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":false},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f1b97eeabc889cdb4f67c699fdb30ad896abe08e603b154abdf5e122bb1e49ce","up":true},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":true},{"one":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","other":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"208e648a32b59b77c2abbeac0402c8d009485a19dd4a04a216cd91d0c6713929","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","up":true},{"one":"2224bdce114e9e87621ab44d1a54b11e7714f30ba695c8353a9573adfcf822fa","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":true},{"one":"510c70916948815cd32759c451515bb024e38e0db8bb128710396978dc705a67","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":false},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":true},{"one":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":true},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"802f9e88535e40c179cb5f7d2a16500696e2af2115d3f7ca0cac5c2f634109c2","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","other":"8a5439adf9987f8e0df052b5c32599dba0a25d3e45dce4cafdf2d2ddfdae2f42","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"89efed66fb192f1530bad978261c660cf18473bc2ad4dcb6c3336afefe8aebf2","other":"8d3c0c717a2ead135c414b69841ade94e126eb0a89132a2c6f531728c62a9180","up":true},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":false},{"one":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"f0b803dcfec89e1d68739ca05cf0c9c04e80a2b1cd47496a83168a71184fd4cf","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":true},{"one":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"a9dfced37b98d1dfabb96e5c68f0744c615385328aa469af16fbcf8f28d2062d","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","other":"05a4778e1be7da949c1a7bffa3408020b66b4ee3c98e1f62e35d212c77e83ada","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":true},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":true},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":false},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"3054ce9b542ef2af36ab2b5d4590f2b9794107bbbe55cac109ecd5dfe56d8c32","up":false},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":false},{"one":"3c5ae3bb462b109222b4a1ac1cf9b04508fcd53a2d13796880965e99e0216ee8","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":false},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","up":true},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":true},{"one":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"d0443f24523af0eec6c20b21d84b2d54cb0ba8d4d1a205b41328bb22e8d3cd63","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"d3bd76f9b178b34e0a97bd0130c61a8dfa2097fcbc667f6e4f4eb77227425693","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"fd44f2616755aad3efacba9ecf1d92d0ab986ba679007f735c8bcf3c6b94c150","other":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","up":false},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":true},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":false},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":false},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":true},{"one":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","other":"d90b75bd11ea3243e097f2318bd95a35590c9f113324ffa1f94cd701a5d3eb32","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"e2554d1bf145ec0e7027ca8e8ba0c85fc697bc4b54e36a6cdc53f1efa37a6634","up":true},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e3d8cbd8840509034f081859422bc599750fa4f040d2f90302b9513b433847f8","up":true},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":true},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":true},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":false},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":true},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":true},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","up":true},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":true},{"one":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":true},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":true},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":false},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":true},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f1ad1843560ead294e9d60c9bfc99d8a827f2cfe557e0f9fe7ebf82aec56926d","up":true},{"one":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":true},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":true},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":true},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","other":"d96e430326c7fc91fcd19c4e85b472a41ba24317ff09e5bd8eb2bd7a306499be","up":true},{"one":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":false},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"56bbd975ff675f73b566b447e894d311b8631438163b625436685b019a15213b","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"3ff80089a2ef377b1844881300b3e85041b16f0e7508b01e59a0e76b63c8244e","up":true},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"baafd0d5d03e5072341e9e3e69b8c48041cd6a9ca3da56a1a4934084db6e22bd","up":true},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","up":true},{"one":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"4b8acc021ddea1fff036b4b0e5939c38507ef792490701f7b341e4ff10a78567","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":false},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":false},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":true},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":true},{"one":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","other":"f054c2c66725837bdf1d64602f9d1627d83a3c970d9bcabda7f4d390cd40a438","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":true},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":false},{"one":"0ad654954ad9b21c75831389c89574a7871a6ba8e1d54c92cf26c64c33148b42","other":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","up":true},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":true},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"14e40f9abe8b2c845f2fc62a8f4347ff3630918cd62a33af7788e4bf599cfb96","up":true},{"one":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":false},{"one":"43fbbefa7ed5fb3b496c126bf54a77b7cc65b40c67facbf9605fafbe4e0397ad","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":false},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":true},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":true},{"one":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"fd3fcb327e1988c4786dad45a6e325b2fa9ef07ee62721aa5cdafd5529bd125d","up":true},{"one":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","up":true},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":false},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","up":true},{"one":"d56025bb110210216fdc8f86ad205607c6fb4744d3d444931aa17512a854356a","other":"c4090ec37cddfca2dfae52d85993a635cf47547c917e5c69190e24a48db7cafd","up":false},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":true},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":true},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"d60644fb69edf1d360a5b3d480030df97600a3d94a189da98b58c43758c98331","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"8ee7f2d5c359bd5c37ec03d4e02ef8084768e12d094a7cd27cb5def6738b61c5","up":true},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":false},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":true},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"a105c9ec1789d99c59f23257f63e048c0c923e3748d35e6108c8c0a8d10e6ec1","up":false},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","up":true},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":true},{"one":"523768400c5056078f368a95723448fae6747917fb3a9c642930ebfd979d9e05","other":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","up":false},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":false},{"one":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":false},{"one":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","other":"cba44046d693629a872a22812ebcc9919ddd8148ec7085b23bbb828f258b48f2","up":true},{"one":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","other":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","up":true},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"7e4585b52254f6081e19191e737fd1898528a0af77e3d752a081d29b92ac13a5","up":false},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","up":true},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":false},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":true},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":false},{"one":"cf771ee06f5ab9cfb00084a5ee8929d15e434f2ffbc4ba4289cb2471104146fb","other":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","up":false},{"one":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":true},{"one":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","other":"4b70964ce2916bb056cec6da31283f4eb3cdf774b86f3ba36b13f56fec18c6db","up":false},{"one":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":true},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":true},{"one":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"bb3198bb61f3dc96365a99b7141c0b85720614de4640afa76458d27484e1353a","up":false},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":true},{"one":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":false},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":false},{"one":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","other":"f293658b2837cd41cfb4f9eaa18d0025fc5877bcec701a97df914882f4bfe43e","up":false},{"one":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","other":"853bc86aad69d6b5ae27f27b7979f504a3d1033000a4fa164f563357414f2fcd","up":false},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","up":true},{"one":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":false},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":false},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"d66f440d86e43ad7e153ed9f101bd1632e64ddd2e75791fcd3fe819bd190e665","up":false},{"one":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"09d15d7dac32cbd6f9b5b292e6bcb5082d95d24edbb8ddef871890409aab60e7","other":"0d97827f6ea850c310c312598ebe1a92ceae08d1e055ca170f1e305f836ba398","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":true},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"3ab20836f88aab49491e82cfd1f1e8a59b5794cf91644b663d40cb22c5460be4","up":false},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"f97e87f80e6db30609a0811bef5cc7a5884326abed5cc970f3ce580476d0935c","up":false},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":false},{"one":"cbd3dc416cd646687d2cc0373bdd79f44d77f5ee775e298a083d8c62be248f3c","other":"ca8c1a36e8c6998028b7cf45086f6478a622f00878bcd2643bcb021efc8cf50b","up":false},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"6923d78400f277fe29c35ba38a416edd7c960cc75d94c35aa3446b4d5e2f6c3b","up":true},{"one":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":false},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":false},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","up":false},{"one":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":false},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":true},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"c95a481b19583fc85e9b079fa0b5cf51eb46e71b9f57fc6df2e3b78389d8de2f","up":false},{"one":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","other":"bbcbaf233465acdcce94920a2a643c20772074af094a33ffb96cc915e30ffd8a","up":false},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"03059077d3fadf62794756f6947fc32ed00d82162dbe3e6ebcd32952bd421321","up":false},{"one":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":false},{"one":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":true},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"574101500f64e9a1bfbf31f4f379a60a0ea9bee449af1cd29962214dd960b3c6","up":false},{"one":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":false},{"one":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":false},{"one":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","other":"d7c1b747ad01a39ca048916de03c0288d80aede0c968c392a9656f616903ffd3","up":true},{"one":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":false},{"one":"398bb8a4dfcbf50a93de93688331fed42454d4941b367c569e9bc568d18fbc00","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":false},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"6caa4a84138eeb4cbe5573edf4c2381edf01bd386c57f527dde377983301a563","up":true},{"one":"bf6b5c5f8d8b6beab2d82c1ba9616309fa7a3052050e31e5f46ecac4636fd10e","other":"beb777c02dda420daeecd9fafbaadcd2592ed51e9a8a5c5dd7abe43743a88001","up":false},{"one":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":false},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":false},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"d717377aed09d9b0d4f072abd13f49d3e4f64fd8ec40aa45a47d10fdc716e225","up":false},{"one":"85642219f8bb8ce048cfce5aecddc8acd035afa035a0137c354f5b6fc3e3889d","other":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","up":true},{"one":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"98aa8f9e3f434905222090453f2b0a97b7d60a252e0ecd519451645e0e685319","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"df52d5de0f5e69e7e4c9e0ffcec1f9df86d38044bb57e5a0cb18bde354ecb66d","up":false},{"one":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":true},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"1af6b4d9b354555f37c5be62feb691dfa76a531404ed4de5ad2b905c84fc37fa","up":false},{"one":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":false},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"34e48bd6562a308ccf6a4a0257f253e908e97d16defe2f1a31e046d5558a4769","up":false},{"one":"0fa02bedceaa28618f48f319d38b657a356099ac98734f402c4c846a4c35b678","other":"0c728c174a25e11bc171d7d35eaaa3974859a4dbf7a64e1d9c9da6b3ad63b21a","up":false},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"1587ed904df26ed711e2235fea41e5812a7d33ce5dab2ebb4e88515b18f43d6e","up":false},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":false},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":false},{"one":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","other":"e1909ff70b17f666d74c73e8d9803df1e6e20733e4aeecdc78e444b6632d92c9","up":false},{"one":"949386e823234d1afdf2a2134630a8028868bdcdf26443da4db22ece78871899","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":false},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","up":false},{"one":"41b2b713dba3a11683ad83d1cb4beb9ff4f5aaf49f2ad1ac2247c84a85d40a56","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":false},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":false},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"4bf8d8c5550940df9712d758be4711014366af3ea6b5988c5c8610f331f37042","up":false},{"one":"67ee67b8f4d3ee50d8cdd027ba96e4b2f8ef9017bac217bd5a2d9dca35325519","other":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","up":false},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"307c36a947f5c4c597075d8346a5db6133fbd2c14da099f85c1d2b7d6d8331f2","up":false},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":false},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":false},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"0c1956cad397c9cb93524cb23fbfab99df2a79780ae596b93c77fd9db06f7f7a","up":true},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"3388123bad3bf1debf51c5921c09d06f7627d05f6115af39d92dbe9b2f2313dc","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":false},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":false},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":false},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":true},{"one":"d0b76e826a6eaeabdc060a0588bd1becc1901b60a8eb4e8adbe61107883a2987","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":false},{"one":"63de4cd08e00a3dbc071adafe1d1ca255cc6d672e3c5aa6596ab60ed5cc82c5e","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"308528d445007e189c31e695f2bc74af3debab473f57bffd866c601155ffc3d3","up":false},{"one":"8ae89e105f03ff1bacbf53e47ac7bd9af66e0fbc0decb1c11bc60778cf97476a","other":"ffb73c715498775efa3d82de417a4469c66a155ca1149fec7a1ca0a227eab4f3","up":false},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"1fabca181afff59bda173b8de38b04169f9b299880bf72674fdc8abd1f546e9c","up":false},{"one":"0f65210e727ede01a854c3c8d256adced79866c368d0d51fb3ade9c390b02318","other":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","up":false},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"37347d159418873210a3dcfa60c0f6ca50f9007ce6f0126eeea6918bda08b2de","up":false},{"one":"0ca9d19acb9c459358eb69ddaad98dca0b4c13b14cf1610716ed4f84dd972563","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":false},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":false},{"one":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":false},{"one":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":false},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":false},{"one":"5caea6ca046c5e2d3c9e2389600c36d3feba80a455944842c2eb55c5b144318a","other":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","up":false},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":false},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":false},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"2cab6becfcdafacbc9e5387c79bc70dcb9c16e1789b404edf57e05354f05679d","up":false},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","up":true},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","up":false},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"b45fd6b4ce2541816834066dcc1cee4bfb343ec965db53eda986e6b037513460","up":true},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":false},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":false},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":false},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"581ab9df0d109d94291331b68cbbf8bc700d969b2f9e43d0717f88f5409fb815","up":false},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"de1d3e466a171aef4bd47b6546d25c12a1f3120f0a5f68d377dc01362b408a2e","up":false},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"c914c96fb6c0ecd51e043f0395c7c63595ccd990c94d9ee241b14da352aa8773","up":false},{"one":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":false},{"one":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":false},{"one":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":false},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"1953df7e29813b00b0137118623b6ce34113d17d4f9aaa608b81f2ee58ea3fe3","up":false},{"one":"d1bc26382a2c66d93f96f82baa6324a62a1a5574b7a7078b579c452429e61cae","other":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","up":false},{"one":"d07c2c3d684684a3178bac8f4578d1447117f604bc475efe108dce5621643846","other":"d35c12f352b5e8603b6e354434de8310e35f9901af563a3ec775bfa00b806f23","up":false},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":true},{"one":"5c9be78d69b28013fe73a16d07240b540f3399e041c92fc263a94632b1ed255d","other":"57657e7b7d2642c6e5daefd27000d0da41982491486fd1aee57d0f99f072a471","up":false},{"one":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":false},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","up":true},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"3799c5f3ebaad70130fcf00bb8131c78951a8f4bbd67ad2bdadfff4a8f667143","up":false},{"one":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","other":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","up":false},{"one":"f2f5e82cf81f07f8cf82c7171c5ee5a42b7963619fafd4295137357cea1b7bb0","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":false},{"one":"5062d74876fdf425a8e576ed5e56d9719a2e506f45219fc10c48ed44d2f0360b","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","up":true},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":false},{"one":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","other":"dad35b937a6501fcd7483467d81296a6c8541def88d0ce45a702a1d1725bf567","up":false},{"one":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","other":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","up":false},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"1a8ecbde88be22a9bbb5f3ef19be5377923d655fd9cd838f9d08a442614742c3","up":false},{"one":"a1f1f5ce0313b3f63ec10fd5c19aa91fc56309ff599e08e19ed15e43c115950e","other":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","up":false},{"one":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","other":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","up":false},{"one":"715b38eca0c630aad73e5f7d65453c6666f459994e3cc4bba586af75d78e8fe4","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":false},{"one":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","other":"36589cecb182e45d3e9f35e2405ed9a8bccc452028b903d30728ce099323fd5b","up":false},{"one":"3ef6bb1dcd37360fe4a463b70add6cd4ba112a293112911b2304ab05b4c1b543","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":false},{"one":"e56cd20d7e387065be2d52a5c3ea1682765c9378521709887c6e29cbf24b43e0","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":false},{"one":"507060be030344850df6fc76719d503254b38d96d77eb25f49ca9d955944b10a","other":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","up":false},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":false},{"one":"c9114dc588a9d7ba73e41a943d08c528f3a4e811dc8b216cd4ab58171d0f642c","other":"af8fb611627063b408d2b96c1ab68fafb223a86d947de3dac3a59649cd13e0cf","up":false},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":true},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":true},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":false},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":true},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"e5d23024ad9e5dc8915f8d31428e9b3d62f1c4843e276451f17ebb766d06b456","up":false},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":false},{"one":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":false},{"one":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","other":"2cb18a6dd5643091b3b41538bb32dc414785fcf180a5c51f10c8bbcdbc6a7847","up":false},{"one":"9a09aa168f7f4ebd90652d6900ace1ba88b8785290b2687783d4a23e9bdb90ee","other":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","up":false},{"one":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","other":"0daf815b74975070a8ef053b82b2f4fa7919d4888d472f7c57d7b60c7b56e056","up":false},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","up":false},{"one":"910da662d9444f160ff5d934ef667f1f3aaba1fc3275e6ba152f9aa7e85bb24d","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":false},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","up":false},{"one":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":false},{"one":"99eb314acf9de2b6f7085da247a552125e61c97c6b54388a21c0474d717e3590","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":false},{"one":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","other":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"e54d69f3bb061c62dede6e5a8704700bf9b8063edead7c755c9586f4d96754f1","up":false},{"one":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","other":"24f87fd89a8aabaee05033a0a3eefc01ccbb5bbc6a53d615ef34f646a46b0156","up":true},{"one":"eee15b5c5ffcbd0aa56877a6a45aaa323367614180d3e5cf7b4aeefa789d8317","other":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","up":false},{"one":"5a67bff220db75aa2266742614cf15025b9c06aa733c805d0372f10882c292a1","other":"539980a9bfc5ce74bc35d81cc264f4c0d529a75df0c870b9e0b9ce45650a9f29","up":false},{"one":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":false},{"one":"0a3fe6516edff33cde6afc46c6174a8562f17454b6f3ad41be8c12ebf1b0a07d","other":"b04931ea8428258af41286377042ca4ef7b2f507ef3ba14512b36a043a184253","up":true},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"efbb3dd3b0fb3daf4a8a7091d400d834fd9532ce0c3dbebb60d391559d64acb1","up":true},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","up":true},{"one":"6f1c48453e1bfb9c474d7f888d8c437c75db569e2c900867c4eaf3e6504847aa","other":"7ec4083eca4749caa706ac08afc0c91cdcec42f18e4d360f18695a79de362115","up":false},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"ec785af2fb66c0af4c7d6ac750e337a5a8a795a22022cafa8a43df7fba11d9e1","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":false},{"one":"4dc43c820a6c34797152a558339bf468aa48c64e1e54c6158d5ea333a8f3dce8","other":"48df69314a57a6ab2fc31108104aae2242ad2a941d2f87119a151250344aee02","up":false},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"992959c1dabb655a57cbadfeb18436f21226a56968ff0c9926a69b86692cf289","up":false},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"42d6afeae77ae9e99c6bb727126dde5e1338b5421cafe2787251bd19d2b54d3a","up":false},{"one":"e7243f48530c3f040827c02fdc67642c7a0569138337a498517d4fb4d38f10af","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":false},{"one":"47a8e9918ad3b957a888540a497fe46dc4b64a1d1f1f8e1bacefdf6813d91d70","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":false},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":false},{"one":"5e3efcd12d75bb47f842261d24f509018dfa5687e3195e1d1bb2bc602cc9c291","other":"5b308b25cfe30d0b68784dc73be464dfa85a8e49ddd6f6271ff0ee2b63798928","up":false},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":false},{"one":"ce7128ea0b68755aea6e2dd5d5da1100a1e29ebc2d34ce02c0d025a4a700ea15","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":false},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":false},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"c301dfd7e7510fa72b94531ead6c51cceeea230a004a91f9fb472fb19b39bc06","up":false},{"one":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","other":"ebc9b288de5534f762a4ab0e6522955a8f83ad15b662426e45956a820401d0a0","up":true},{"one":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","other":"1a85e13e2ad82c8ffa10ad52b382947e638036120188ae611fb1fb333cb5232b","up":false},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":true},{"one":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","other":"e4e95f8381568c1cba7e8f64dd710554b923241a1c988dddb42a2cd96434705f","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"36070b5229906c010f3d756c6b9501f80757fdba261e38ea2a294b5047f67739","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"1dfcaab676a9d9a83c7f076449aa0d8446770ec0960655e1202fd7ee426383eb","up":false},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":false},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":true},{"one":"44b7013bcd5e0bd36ed526602614f13a91c9fcfa8613312ae22d9c87377a5949","other":"413b15ae74e38b8610dd5edd52e05630f8acfa4139a1b361775afa8e748ebbfc","up":false},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"2737567dbc8dbfa2a23fbd4264d1bf7cd126b54f1bc3aefdf4170bb80bc4c5a7","up":false},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"efdd79da474a0784c7421ed246f6f8db721bd3551ad6e3793070c432181679f3","up":false},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"86113f8a7d4304ffe158ccc0e94af9194cddbb27604ccc08dd2adbea9878be2f","up":false},{"one":"96419a246f5ca44f2796d91ccc55b3ac477e1754e74d202cdd133e6b5b96051b","other":"9f4c2e7b1c80175a9d7d85c983d9ee406e5d7ba644b0f8e85196c8bc7cbcbf71","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"b30eed51a958a822528b126471cf7088424a7913a5e89d6aaf989c968a0c4be9","up":true},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"6701b38360d0a72ddc355c17385af34b7ed9eeec00bc3867e162b5571af69e3f","up":false},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","up":false},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","up":true},{"one":"1ea1653a07ce2e07a40018f3a5e8dce0258177e95696a78c57ea3eecc26e6949","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":false},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":false},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"83d0ffd43e2469b9c3498862d0186e413cc4d205f7854bf9dd73c4d74379217c","up":false},{"one":"e4d6b7889d454cd01ee933f9ae28221702495d79acbd10458082ce90c09fb691","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":false},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"c60e0a8c32d6842453792124d495af30721e79f29947938135f35b341c433ef4","up":false},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"d455034d04322ce766b48f825dcac69ea9b0f749bd5cb8ab2c4e3a18b1c70ef8","up":true},{"one":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","other":"c3d8b4ee532f606e460666e45569c7f54baf4acc69e1ed027af4d7f11e194dae","up":false},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"a0c98f72caba5cb7a4009937ff949b745b2330ed8b1a71ce70f4e59d50459449","up":false},{"one":"b3910e693ef69c37cdfc9f831f04fa8549797edd16ac316a95fe5f9fde3ab3a2","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":true},{"one":"7299df5ce4d90e2e7bfae929fc3fca7175b8899681e626041d8e5721b2ce8e9f","other":"07a6873c7eadb651196a76ab30241cc1c984549c5086f1c3bb1be7bd493346be","up":false},{"one":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","other":"efc128ce65a388db303d97f1f1844f2050f8d0a95820e8859865490ee273b0ce","up":false},{"one":"1daa2b253dc95a37bc9d238e1ac71be213d6f725b3bbb84c5c93f512e2ee501a","other":"ecff394703253e8778a1501c97b3a6a170e3d9d2b3fd8aa83443dec0edf19896","up":false},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"4bbc289546fd7ade8b214daa4e8a23139a85d7e46d70a557025339f6fbbee87e","up":false},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"71bfc67cadc7f06e638f2c87b0e25a4cec35b6655adb27f72b37774125bd38d3","up":false},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","up":true},{"one":"9b87fdd4d96b82263003c90346fc097008ff681bd246227a35eff3b431d6342e","other":"9918da1c179414f75c8d27103c3297a3bf5ccc62ae0bb13859611046536a5959","up":false},{"one":"8434ffb624f336f300f8c4f3315edcaeb99b7f542c8b3c2c972aa6bc210d1302","other":"802e9fa524f1a6a27fdcebf7f25ab28a5c043439b7844b1fc34da8242b6017a0","up":false},{"one":"98bc7e8a4941b065b98f6611935fab096dd4e0bdfd38a9f2ca4b63f2851e2704","other":"940415ad0c47373416bdaea50ed36062a47feb2e09537401f86893f337824ad8","up":false},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"ee3f23e7e62f9af2906703eb9a1dd51a8c2ab3a9ca79c460e08085e565806eb3","up":false},{"one":"8d853eca48be257b7444327d61cf588218da71c688be9847ee9987d54eaed1ab","other":"86d32fe2816f5523698b81c638eaeca28efb3bc4775cdfb4679e0f99bec8a703","up":false},{"one":"e9fa1a8529dddce276f66c78223ca06ceb02fac95ea6e18b5118a0417b370a09","other":"ee527dffd4bae1880e3c5ddcba2e2fb1706c4d40804e102c9f3d514137ab073e","up":false},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"a3f2a0d3dff1914624ae113dd0dfef72175f03ded5cba89ebf75e350c4651525","up":false},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"384305aff56982a885d643f2b7289c5f35658ad5c36a76c1d97030af60ed975f","up":true},{"one":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":false},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f2b24713b8f8bcab21081bd17d11d859dd5ffb21c9baddd971fdf2d4b51c1ac6","up":false},{"one":"fc881a3a0da605c7781ba6b122f0507f303fa998185a351976aeae89f4ef8b8b","other":"f6a64941b0561dbbfb387a5d448e40eec0493f1c0c1fae4dcd314a1a51f6b02d","up":false},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"d777e45233aa4d8b723f6a6aa9cbf5de4c0b19f6fd00af6d538b67ec01b74ab5","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"3baa42389305677f589107a8ef58e129ab29d0e16820df4ce2195113eeb0f295","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"15ecfd0ece9d43df1cb05bf2cf319c9d954557f3c269f7b0cd7f3edb6c89e581","up":false},{"one":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","other":"60bc3e01e8aace7338d7a326ea7945b5b9d829ae83c5c70dc69fe919b9a31481","up":false},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":false},{"one":"ebe8037a1344f9b599cca1aca404861c4194529ab7cb23b3f7a081f615427575","other":"a1b6a1a989455f9f1955276a0b3b5b4c19726acf8fa3f7218fab420036fa988f","up":false},{"one":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":false},{"one":"a478f5caa8ae441d8e933f636ff6c1166753c0b443742e20434619044a85081d","other":"e850535d4bce69008b1ac52bfc95a9ed7cde04fbe849a5ade3dbb9fa13a67c9a","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a3174cb06f0ed08c640fc23d2840e002f537a07a93ad464beacd92c140a78a9e","up":true},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":true},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","up":true},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"0536088e14b81899b914cfcebd2a3c3ddbbbef905ffb69375613d4853667be18","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"e31eb44ccf3beb2579ad10ba30c0adb12deeccc54f9c477d30fe6fd8308c1010","up":true},{"one":"9bc3cc7ff18f1eccd36948e6831ce14d0223a27b233d5b839b8662e16f9fb435","other":"175873005cd8b0db7da431cc6cc077615a5c79a88c4698a1ae61f3bea212996f","up":false},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"4c97be06dae9d63322656fea7bf0de266346b61674f95d1eaff0f14618623b5b","up":false},{"one":"44c8c26204fe5a0a48c62466be8079a60b445b4381422242584d8e1918cde748","other":"464b80305ce1b2094c1294c41aa842aeee31680ac90230dfcf26a3606a07f9a6","up":false},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"294066bf056b1530308d096871b08a046086abcbc7ed7a0a97d9fb46cccd6003","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"b820b318a3a12a7a7f45d06fff7f5d7e3ca2ca8097c396c1d76c735e1c915cc0","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"11a0676648caea71425ae79a55acd71a0f2fdea70bb0dafbb53ac1b8e1249af0","up":false},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"10b16d53d16acc9fcc9d2321bec7cf6ab7600bf11da955dd4f628d0bb92d99ce","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"1d5b85468d868cec2f1be5f1c7dc89b33f61d27ab04e750a556b1e3aaf3f7c15","up":false},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"0020768d96fca0cf47a9632ca25ff794c996042f07a7242ec7c70fbc75e0e45e","up":false},{"one":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","other":"020f57c369b6521552f7498e444aed21ac57832ed3ffaa7b45f607793ea1a86c","up":false},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"e4697202e563f447c9c93f498365f4dc95d14633ed40387b934c485dc3aac575","up":false},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"3a182b774ac0fa9d6ea04720cae972bae0cbb9d9673891abab8ae17e463e582f","up":true},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"1254b1e5c9e80b367520bfefc35cf32a60aff56c48315107c4b07aa1a7866af9","up":false},{"one":"a75dd3af0823e79d336f78762b8d12e55429736f363e540c2c99a8b7bbc535d6","other":"e40694edf0f70c242ad2058bd94fdac0676c19ef93043829e03f7c8a7a23f179","up":false},{"one":"caa321a50e80a5ab3d73f717008f4601f57a21efa873e4f1cc4d6f356fbafdae","other":"3227103897adafbe4fe3aad206bab8253bb802bd980a0c6188500be89e656edd","up":true},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"e6b7994917b34a1a760a48cca74f592aef94f8afd91686b5db8d0389ded09281","up":true},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"78109d560f529ec24cc69b69eef6055548225c2965e8c23cf8c0650d2d3dfd2e","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"7aef1625409f479ee1abad565f8d7e73b17714e77f54d1ac1b2fe80382a058cc","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"77bc5628edeafaced10f1f3727a4f579bc69e457720127686d2754bf9803a446","up":true},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"65a670260af4f38603757fba904cde5dc8f1d3240ad5ec6bca3153a4bebc147a","up":true},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2c4eb13e3d02c91e043130f04f9e248c3d1eb9ac7578b3825fabcb30884fd3b0","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2e3b4fb6298c357d2a4cfcdb2fcc0be2cbae0a11219e4cac2d0c01de3925dd52","up":false},{"one":"3d17891f506b4c968758f1d58eb35ca883fdd61ae9ad34ec2c076b506c124229","other":"293f6e407f98ce24090e5ed53fe606bbb272b61a3eec3859203ea54d16991e88","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2f1f2c4c25b97fcd8fbe79506e748b7c0df5b3bc15b884701df127e49548844e","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"ac62fbb8e18ecc4bb4e6f5d4a999bc86815803106d451200457b29730619353a","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"a9365c4cb8daf8bb018a6ec9bb03e9c75eb1955b26d8847b868db8e302a7aff5","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2c16611229217e96e69d3d4a06f7d44d7cc26e511a816db0362eb52bca1ce3e0","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"76a5d17fde4e1c671e0338548501da39332c8ef59329d999b0fb6ff704060591","up":false},{"one":"38d707dcfe1a9d09c03b606dd4db89e6ced004c12f61d8b573b5c9f742f512bb","other":"7239f6fcd537b5d59b85071c962d4958806800de127b172c167c2b814cec4d84","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a0e4e6ba6dda0b76cd43f93e7c7b3923e5223d3cb144715f2f38045e5923f99b","up":false},{"one":"1dfde87c7820c28cd673e6da6fa8c9b73542de6b5acfd99dd1316a22af5eb163","other":"167bc81f7d26f99ceeeda814de5bbfa75f8f2a61575570596bc5a3c618f5d230","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a011c924104e072ec415cf72255167582e5d3f189f541066ba88b3ae0041b508","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"92d565b13068e8b9af102af40e1112a00b91e398ef0c42a292e88d406c55b4f2","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"93f88beedce7f9581ecc05615ba15fb313006a32a159adf169f2e02ecc697598","up":false},{"one":"22206b3ddff20a245a900b7bfbf2f400709c2670f0c49713be25eb57136e9f1b","other":"2f230166de0362acabe4258a19fe19d493912e0e0613674a6cc963cf48b376f1","up":false},{"one":"a6bdbd75f03fa311700a17ff4054ebf2855f05ab3f2f4af82cad573d91417a83","other":"a077a6f8832a5d7d2146d9b08de0c9f4ae3515a3f87f2751592e1158adb04155","up":false},{"one":"985f1b6d642a9fb71302fe325b3f39aaaf3c1c7ecd3fedb308c3753f7dd4e235","other":"97474907a03344503279f1d86695233962b6d36e597b6e41b11c941c2ca2dc46","up":false}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","name":"node_a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","enode":"enode://e70237456671b100c2341a568d85185f57c09cd699045f8c51f5a7bd09217bbf764379a2ad51b60e5671b978ee72cd33416e17520c75e471b4722f59533e3a4d@127.0.0.1:0","enr":"0xf88fb840ea2e2964e4c4bac440d5d5167638da0163abb3df513fa17601c4b04def5883ec78df971cc20ed10c00a8e9b5ba290305181507c49589c3c9026d28161f7dbe080183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e70237456671b100c2341a568d85185f57c09cd699045f8c51f5a7bd09217bbf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pG3VNeO8jxEaiyzlWUti6HdBw5Xoorj7rjPt0py4yvg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a46dd5\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 605a 00c6 0ff2 154b | 146 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n001 6 eb98 e775 fbc8 fbf5 | 63 e027 (0) e5ad (0) e5d7 (0) e547 (0)\n002 6 8505 8f21 88a1 9076 | 20 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n003 6 b2a5 b02b bcc6 bb90 | 17 bcc6 (0) baf2 (0) badd (0) ba88 (0)\n004 4 ad98 af02 ae2b aeb4 | 5 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n005 2 a369 a34e | 2 a369 (0) a34e (0)\n============ DEPTH: 6 ==========================================\n006 2 a653 a6fb | 2 a653 (0) a6fb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","private_key":"1e57a9344381e01bf32e09a979ec63d899dde10dd84d70ecb6404de10ff2fae7","name":"node_a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","services":["streamer"],"enable_msg_events":true,"port":43161},"up":true}},{"node":{"info":{"id":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","name":"node_13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","enode":"enode://101db8d36d797326a36adc76ff41e54a39cfe68b7948bd87bab4e7658bd81db7a962be72ffe4d52e15e65a5605b4fd7b3c5faba7fbeffcf6ce906951a9c4c520@127.0.0.1:0","enr":"0xf88fb84015cb00dd3c456518171748d8926d78335c0854b346464bf9bded32abbcc19aef5852275615470f0fe25130dd8ee37eff80afaa0ef7c7d14ea0f4f60e98b56ce20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102101db8d36d797326a36adc76ff41e54a39cfe68b7948bd87bab4e7658bd81db7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E9bLkxbiiZI+LR3n88lm0MurzjrNuAFxIpRPSrsUCRI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 13d6cb\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 cc20 d3b0 a46d | 110 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n001 4 53fe 4e5a 6e68 605a | 70 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n002 3 2f32 2c79 33b5 | 32 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n003 5 0b72 0af9 0ff2 0fc5 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n004 4 19fa 1e2a 1c8a 1c9c | 10 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n005 8 17db 179f 1672 165f | 9 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 6 ==========================================\n006 2 11d4 103b | 2 11d4 (0) 103b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","private_key":"37ebe30b2c356984a7e460228a022af51a6d955b24fb5e602226fc9b7cda2062","name":"node_13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","services":["streamer"],"enable_msg_events":true,"port":39877},"up":true}},{"node":{"info":{"id":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","name":"node_d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","enode":"enode://05700e757f48449baa479d9e9476883768725b33e1fc661afe18f3974b21d96fe414ceb6c1b7d6e501532e17c7ff740237837c2c812daabed849b5e7797917fe@127.0.0.1:0","enr":"0xf88fb840fac5d8d078a46572c426af0322faba829283795e739c471fc3d33d0395f8e49c52370fb9373e1c6299bc9c5b3716e5af57a39614e8848375d97a3687d2ee89480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10205700e757f48449baa479d9e9476883768725b33e1fc661afe18f3974b21d96f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"07Deod06xx5+SjCUFjLuxTy5gKp8ts2slQQqVACoeMM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3b0de\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 53fe 7dd3 605a 13d6 | 146 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n001 5 9076 a46d a34e b911 | 47 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n002 10 e54b e775 eb98 e883 | 37 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n003 6 c1f9 c6cf c620 c832 | 15 c26f (0) c1f9 (0) c49c (0) c441 (0)\n004 3 daec db6a d887 | 6 df1e (0) d863 (0) d887 (0) db6a (0)\n005 2 d7ac d640 | 2 d7ac (0) d640 (0)\n============ DEPTH: 6 ==========================================\n006 1 d1d7 | 1 d1d7 (0)\n007 1 d299 | 1 d299 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","private_key":"ca03d9ece7d38bee50629933e237f3019a21e19182e1bd49826c89f10e625121","name":"node_d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","services":["streamer"],"enable_msg_events":true,"port":42617},"up":true}},{"node":{"info":{"id":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","name":"node_605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","enode":"enode://a621f4d598855f913a837abe294df8a44fde676e99ed3976972afa30e977462ef16b40a84fb8f439031420d103f4021f5540aa0936b9d4d1e466aa23cae18e32@127.0.0.1:0","enr":"0xf88fb840ed422154098e8b2ec11a4d63bf0da7d8edd6aec4b81b5e574a6a95562ed8c0656a0983ebe8fba7fd52f8a50a73f3e705730466a0881af12efe9e510ad718fd680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a621f4d598855f913a837abe294df8a44fde676e99ed3976972afa30e977462e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YFpGmRrxXNYOZ0E8cSuZ/48hFzyWp5kPJyitbKwrudg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 605a46\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a46d d3b0 | 110 8f21 (0) 898d (0) 886a (0) 88fe (0)\n001 7 0ff2 154b 103b 13d6 | 76 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n002 12 5efb 5cd2 5823 5308 | 38 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n003 3 7125 7920 7dd3 | 12 77d2 (0) 775e (0) 7290 (0) 738c (0)\n004 2 6c73 6e68 | 11 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n005 2 67dc 66e7 | 3 67aa (0) 67dc (0) 66e7 (0)\n006 3 6337 6251 628e | 3 6337 (0) 6251 (0) 628e (0)\n============ DEPTH: 7 ==========================================\n007 1 6103 | 1 6103 (0)\n008 1 60d7 | 1 60d7 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","private_key":"09e7ba543ec6e7608729d561d0dfecef5bd8e50c9849d1baedfbf09f6be28e97","name":"node_605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","services":["streamer"],"enable_msg_events":true,"port":40563},"up":true}},{"node":{"info":{"id":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","name":"node_2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","enode":"enode://09caa0d3176bb2ab29defcb47bc43b066d3f667c2b923fcec05025ee44028c3c8f8151181b4715a567bfe6442b1696c1b5d4436e2673dae648713c1ced646d9d@127.0.0.1:0","enr":"0xf88fb8407cecec0b472dc2d08e251d9584eb234456d972c76227ef38539f0041d03df5e22e4ba13445b3e93db9a066c6c96db30cee8dc4ded48f5cd06f2161f2c21a1fc80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10309caa0d3176bb2ab29defcb47bc43b066d3f667c2b923fcec05025ee44028c3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LHmvfqhfltt4l8+M200AKtIwgZTgOYGHbtuNkE72UTc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c79af\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c620 cc20 b911 | 110 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n001 5 4e5a 53fe 6c73 6e68 | 70 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n002 8 00c6 0fc5 0ff2 1c9c | 44 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n003 9 3e8e 39d1 3b78 3630 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n004 2 2101 21a0 | 6 256e (0) 24b8 (0) 20ae (0) 217f (0)\n005 3 2995 2abb 2a97 | 4 2995 (0) 2a0a (0) 2a97 (0) 2abb (0)\n006 1 2f32 | 1 2f32 (0)\n007 1 2d36 | 1 2d36 (0)\n============ DEPTH: 8 ==========================================\n008 1 2ccf | 1 2ccf (0)\n009 1 2c38 | 1 2c38 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","private_key":"3721498524efb06914a5509b27d864ad186f58e36aab5c7593d0e9cd263282a7","name":"node_2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","services":["streamer"],"enable_msg_events":true,"port":43339},"up":true}},{"node":{"info":{"id":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","name":"node_33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","enode":"enode://7bd8d32df25aaea11952de45f43b3067ec805d9e5c021d0f3ef3ec8916a479dd7ecbfee5a23baed4b751b218c345dd7c9670b8838660d0f010cd1389511e67d5@127.0.0.1:0","enr":"0xf88fb840a37a97fe62ec10c3a463048f5dcaa531e72b6859a704ec6633378ca65afe843a02afe1d4678cd54a8f60a67f20f71a50363415c56c3e3107b4b11d493015e53e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037bd8d32df25aaea11952de45f43b3067ec805d9e5c021d0f3ef3ec8916a479dd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"M7XFIbQgjiZBTbLgXJqMzAAaUk2ShXnUTS500UpWWT4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 33b5c5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b02b b911 | 110 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n001 7 6e68 6c73 605a 7dd3 | 70 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n002 6 00c6 0ff2 0fc5 1c9c | 44 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n003 3 21a0 2f32 2c79 | 15 256e (0) 24b8 (0) 20ae (0) 217f (0)\n004 7 39d1 3b88 3b78 3f94 | 7 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n005 3 3630 378e 35e6 | 4 35e6 (0) 3780 (0) 378e (0) 3630 (0)\n006 3 314a 30be 3089 | 3 30be (0) 3089 (0) 314a (0)\n============ DEPTH: 7 ==========================================\n007 1 3237 | 1 3237 (0)\n008 1 3373 | 1 3373 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","private_key":"fa8a4740b23a1fa3955c662fee2883cc8d1a1e26853b72c3acc66583d6aa2898","name":"node_33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","services":["streamer"],"enable_msg_events":true,"port":39497},"up":true}},{"node":{"info":{"id":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","name":"node_b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","enode":"enode://f909dfa9cf0586fa20c170d7affbef6b9b835d1603c91ed04c0854b16fa42c4eff293cff2e695634d99bdd6ec5a61f219637eb7d885c25b232685d17bd3572b2@127.0.0.1:0","enr":"0xf88fb84004bc964ea8b933d6a3b0265d90808e3f4109cca5b450a732ab97fedfaa6a55b245cab741804fbe671adca5d7a5ad32223302e2908db90622ca8acdba2f84920b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f909dfa9cf0586fa20c170d7affbef6b9b835d1603c91ed04c0854b16fa42c4e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uRG44tclMrfGb/X3v/pw9d2+6mkDqG+TMzmfDEtfD+g=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b911b8\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4990 53fe 2c79 33b5 | 146 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n001 4 fbf5 d887 d3b0 cc20 | 63 e027 (0) e5d7 (0) e5ad (0) e547 (0)\n002 5 9852 9076 90a8 8f21 | 20 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n003 2 a34e a46d | 10 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n004 3 b7ca b2a5 b02b | 8 b5b2 (0) b502 (0) b626 (0) b65e (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 baf2 badd ba88 bb90 | 4 baf2 (0) badd (0) ba88 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b820 b897 | 2 b897 (0) b820 (0)\n008 0 | 0\n009 1 b95d | 1 b95d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","private_key":"2cb79ca016623c39541a82f657e334cd812977188909b562564102890d58ec54","name":"node_b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","services":["streamer"],"enable_msg_events":true,"port":45307},"up":true}},{"node":{"info":{"id":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","name":"node_53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","enode":"enode://b3104e6e79d026630bfe72e7d9efdb57be3f806110418652fb6840c1361f7d1e0e8521b82a7cf884571ce3b7bedf9787826e57b92e334766c65f24eb470f23ed@127.0.0.1:0","enr":"0xf88fb84015b01d0b7cd1ab6245a7bc8d8bb6c97f6032ed9a1ecc96eb5da3cbc3a3aa79f52a326ea510a5735c19c69a5ee802c07098946041df153aab94dad596c2bc21f50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b3104e6e79d026630bfe72e7d9efdb57be3f806110418652fb6840c1361f7d1e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U/4sE5JlB6emwn0PswosNYxMe/pA34tfqOyJhsJFBRk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 53fe2c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 cc20 d3b0 b02b b911 | 110 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n001 5 33b5 2c79 0ff2 103b | 76 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n002 5 6c73 628e 605a 7125 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 6 41d9 4109 4646 4c9e | 23 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n004 4 5efb 5cd2 58ed 5823 | 7 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n005 1 574f | 1 574f (0)\n006 2 512e 51db | 2 512e (0) 51db (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 5308 534b | 2 5308 (0) 534b (0)\n009 1 53a8 | 1 53a8 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","private_key":"70c31ba2f1ff647ffa877b174d1fe7441de6f4ed5e17bbd9857812f35ab10cba","name":"node_53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","services":["streamer"],"enable_msg_events":true,"port":46299},"up":true}},{"node":{"info":{"id":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","name":"node_4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","enode":"enode://2065647ff3dd80dc4e4ebc9a2a8be828f0efaefbb62e2d2b4ccd246f0cc30aa51459e66d352c9ed8b5126ea9e76aeab74cdf95dcad19c9c9cc2fc3706e83d12b@127.0.0.1:0","enr":"0xf88fb840822110c309aaded4c3d0d3c1fca5a0910e094971e98cd41b5225e201d8a965831ec1d234aeb2560ed5dd98a3db6a230653d4e43c14afb51e34bfbf8de69341d90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032065647ff3dd80dc4e4ebc9a2a8be828f0efaefbb62e2d2b4ccd246f0cc30aa5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TlpGwAToXPhqAv378iQwGIJdAV3r+5oHehKD0wIpOzo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4e5a46\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b02b cc20 | 110 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n001 5 154b 103b 13d6 2c79 | 76 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n002 6 7920 7dd3 7125 6c73 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 5 5823 5cd2 5308 534b | 15 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n004 4 4646 461c 4109 41d9 | 12 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n005 4 4bcf 49cd 49ea 4990 | 6 4ac7 (0) 4a8b (0) 4bcf (0) 4990 (0)\n============ DEPTH: 6 ==========================================\n006 4 4c9e 4d10 4d6b 4d59 | 4 4c9e (0) 4d10 (0) 4d6b (0) 4d59 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","private_key":"cd1095af24a2b4f0a0fa3730f681b7d6c26b93a51081cc8f382764a83a73fb86","name":"node_4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","services":["streamer"],"enable_msg_events":true,"port":39501},"up":true}},{"node":{"info":{"id":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","name":"node_cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","enode":"enode://502433c8d1cf2f8fd7b92aefbf87918e268ee26b2850e20aeb3c4ce61c1cb2049af306124476e27a64b98fe49f9261b104ac5bc18643219c3718fd8c03296707@127.0.0.1:0","enr":"0xf88fb8404a286e1fcc023da2601459dc781096bc67a869b3de88ab00755589aa44b0389e18638b7526b4bb40b059179c918c417acbde016bb95edc6c9eefd89121cc42990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103502433c8d1cf2f8fd7b92aefbf87918e268ee26b2850e20aeb3c4ce61c1cb204","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zCA3wIlCoJTfEvRYMfKOABX8OsBNW48k/+qb86CwLDk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc2037\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 00c6 13d6 2c79 7dd3 | 146 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n001 5 9076 aeb4 a46d b911 | 47 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n002 9 e775 e883 e854 eb98 | 37 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n003 3 d887 daec d3b0 | 11 df1e (0) d863 (0) d887 (0) db6a (0)\n004 4 c1f9 c26f c6cf c620 | 9 c26f (0) c1f9 (0) c59e (0) c49c (0)\n============ DEPTH: 5 ==========================================\n005 5 ca04 caf6 c9f5 c832 | 5 ca04 (0) caf6 (0) c9f5 (0) c832 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","private_key":"d23c0a28f40bce284a142b72daad5397f586194601126aedc3df40587d9d45f6","name":"node_cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","services":["streamer"],"enable_msg_events":true,"port":35445},"up":true}},{"node":{"info":{"id":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","name":"node_b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","enode":"enode://08f5b135b35456f2574282474266d863656df0ef0eb157876e12d53c7d6e01e0260e147f6ba3f2b2a1119697aeb464cf61f20f648990b075b98572cb11685c0d@127.0.0.1:0","enr":"0xf88fb8406c19c1ab095388f46d4d6ef2da794ca56fc16daaece67a7e979009f62b74daee01fd0cea0017acf50b872bb9015ad225678c2ca166e45f0d74a1a305d7ded0110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10308f5b135b35456f2574282474266d863656df0ef0eb157876e12d53c7d6e01e0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sCsBpcN8sFwoej3H0E4wXeJvjWLcOIVC7rQ+l9t7QoI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b02b01\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 33b5 6e68 53fe 4990 | 146 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n001 8 e854 eb98 f925 fbf5 | 63 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n002 9 90a8 9076 9fa0 9852 | 20 8f21 (0) 898d (0) 886a (0) 88fe (0)\n003 5 aeb4 ae2b a6fb a46d | 10 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n004 7 bcc6 badd ba88 bb90 | 9 bcc6 (0) baf2 (0) badd (0) ba88 (0)\n005 4 b5b2 b626 b65e b7ca | 5 b5b2 (0) b502 (0) b626 (0) b65e (0)\n============ DEPTH: 6 ==========================================\n006 2 b2b5 b2a5 | 2 b2b5 (0) b2a5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","private_key":"473b45c9196c27d9ae4135ac8cbc2ea31c3a7f7c0b77117fe484b2a4ecd3913e","name":"node_b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","services":["streamer"],"enable_msg_events":true,"port":38045},"up":true}},{"node":{"info":{"id":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","name":"node_a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","enode":"enode://340c7a971a97f9d8f8868b1336bacbe73503e3e1088ac108d216a23c970b04c677ff52e704844600618f76887b06e7083345056961f77a396e2366191ae76f87@127.0.0.1:0","enr":"0xf88fb840f67e5492b185e03ad9fba3676256587139f92c1a0395454a66d28eab0ddfcd3f02717c57b13697f286929dc5ec9737a829e17a8632a202512d46dd89a8406a2c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103340c7a971a97f9d8f8868b1336bacbe73503e3e1088ac108d216a23c970b04c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"o06i6H1MEq2yfWbCyVMAYD/1BBWXTgALvMaaWuBZ2/E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a34ea2\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0ff2 1c9c 6e68 7dd3 | 146 1400 (0) 1436 (0) 14df (0) 154b (0)\n001 6 c620 daec d3b0 e775 | 63 df1e (0) d863 (0) d887 (0) db6a (0)\n002 6 82dd 8505 9076 9fa0 | 20 898d (0) 886a (0) 88fe (0) 88a1 (0)\n003 7 bcc6 b897 b820 b95d | 17 bcc6 (0) ba88 (0) baf2 (0) badd (0)\n004 3 ae2b aeb4 af02 | 5 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n============ DEPTH: 5 ==========================================\n005 3 a653 a6fb a46d | 3 a653 (0) a6fb (0) a46d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 a369 | 1 a369 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","private_key":"68b17ea93b738afd30952707cc7ba1bcc7dbb9a01631477f8d2b2a7f76a83fb5","name":"node_a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","services":["streamer"],"enable_msg_events":true,"port":44293},"up":true}},{"node":{"info":{"id":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","name":"node_7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","enode":"enode://60f4239fd937907e183edf421b9d1df38ea30f43d5bee23ed23f4b7e9e7b801d14006d4e11987b57cd00d7470c31b17e35e6534bdb642b68fcb9f6becdbc4a41@127.0.0.1:0","enr":"0xf88fb84086961ac0d94caace96d4805f4c5c2470e4da31be8b2a85bde0d3ca0b156472865a13c690728f4e37c1986d173045b80d817727c2ebe0a139bffcdde97847468c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10360f4239fd937907e183edf421b9d1df38ea30f43d5bee23ed23f4b7e9e7b801d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fdMHjHEIeriNTSapYoILy3m4zjDpHB+aadS/jTgIaWA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dd307\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d3b0 daec c620 cc20 | 110 df1e (0) d863 (0) d887 (0) db6a (0)\n001 6 39d1 33b5 2f32 11d4 | 76 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n002 12 49ea 4990 4d59 4e5a | 38 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n003 8 66e7 628e 6337 6103 | 20 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n004 5 7125 7290 738c 77d2 | 5 77d2 (0) 775e (0) 7290 (0) 738c (0)\n005 3 7b90 7a60 7920 | 3 7b90 (0) 7a60 (0) 7920 (0)\n006 1 7e04 | 1 7e04 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 7dbb | 1 7dbb (0)\n010 0 | 0\n011 1 7dc2 | 1 7dc2 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","private_key":"02f0e74d872f0a512a39d40801b92a40eb0a1e27e97da040a97c75e0af22af6f","name":"node_7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","services":["streamer"],"enable_msg_events":true,"port":35881},"up":true}},{"node":{"info":{"id":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","name":"node_6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","enode":"enode://6076aa2f272b91cbd2e5db03c497a76d92991b2fb747c5f3aeaef27c702b0e65edaea0879b23d0e37e2812ff67bc7a92c4131c69a912819fd4d2627fade5427a@127.0.0.1:0","enr":"0xf88fb8400138d5775c80387427a7dff700a0cc533dba63b5a23dd02a7fb85988266d0ce64206c9dc261a206b4784a306a82fe5f001cab02a87039a50c4ed1fec2a1f41250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026076aa2f272b91cbd2e5db03c497a76d92991b2fb747c5f3aeaef27c702b0e65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bmjqhkQHBqDXOpUI8iR0klQxY/j6fi3CqmK3TVAmG4s=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e68ea\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b02b a34e fbf5 | 110 898d (0) 886a (0) 88fe (0) 88a1 (0)\n001 9 0ff2 1c9c 13d6 165f | 76 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n002 9 5efb 5cd2 5823 4646 | 38 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n003 2 7125 7dd3 | 12 77d2 (0) 775e (0) 7290 (0) 738c (0)\n004 6 67dc 66e7 628e 6251 | 9 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n005 2 6831 6967 | 2 6831 (0) 6967 (0)\n006 2 6c4d 6c73 | 2 6c4d (0) 6c73 (0)\n007 3 6fe9 6f2d 6f5f | 3 6fe9 (0) 6f2d (0) 6f5f (0)\n============ DEPTH: 8 ==========================================\n008 2 6ecb 6ea5 | 2 6ecb (0) 6ea5 (0)\n009 1 6e05 | 1 6e05 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","private_key":"b20c8d0606ea1db41eabd7ee0f74574539d2cb45d6d4241b6f259b11ac5c2d24","name":"node_6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","services":["streamer"],"enable_msg_events":true,"port":35593},"up":true}},{"node":{"info":{"id":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","name":"node_7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","enode":"enode://e0da25d10aa370ec66f23c45b05eb96ffd8c7378b53214086b29b8e7800cecdc291eb7be7c52ae40f148f79cc7f7417d37617a7dc017b52b4e7692cd22d59b94@127.0.0.1:0","enr":"0xf88fb8409127cf3b56541dad915db116d184cbf4b62a37124cc76bc88b18b2861040ba7f76dca86df9a3fd341069ce7f7e319d900b1fb1f423bfe91145a0347aceb60f3b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e0da25d10aa370ec66f23c45b05eb96ffd8c7378b53214086b29b8e7800cecdc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cSXgW/G/5t+UjJJ2tivHVfxrDsjUrHckth6klZGtzyU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7125e0\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9076 8505 82dd fbf5 | 110 886a (0) 88fe (0) 88a1 (0) 898d (0)\n001 4 39d1 33b5 2f32 1c9c | 76 3b88 (0) 3b78 (0) 39d1 (0) 3f94 (0)\n002 11 5efb 5cd2 53fe 534b | 38 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n003 6 66e7 628e 6103 605a | 20 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n004 5 7920 7e04 7dd3 7dc2 | 7 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n005 2 77d2 775e | 2 77d2 (0) 775e (0)\n============ DEPTH: 6 ==========================================\n006 2 7290 738c | 2 7290 (0) 738c (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","private_key":"0320cf6d59b1fdfd3bd90c7b0e801cb9f574b5bda4809f6842e344263d8a9c4c","name":"node_7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","services":["streamer"],"enable_msg_events":true,"port":34651},"up":true}},{"node":{"info":{"id":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","name":"node_fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","enode":"enode://044552ed8018a3d7a6edcd78b62c7b776f3ea64af85049a170539a9353c32990f61afd5aed5a849eebb4c541418048952b2a969128241782caf66fff588c5576@127.0.0.1:0","enr":"0xf88fb840fb8c98615b2fd9a6ce30296aa151456746d7ff6f93f25567ad09135e11d5912567e796ddb7e02868851acd52d94dabe5f73d7421af7f4e91cb511b49744b23710183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102044552ed8018a3d7a6edcd78b62c7b776f3ea64af85049a170539a9353c32990","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+/XpF75F6QlpepOTxHeCBjM88d2aEDl46NcWIso7HMg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fbf5e9\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 154b 1c9c 0ff2 0fc5 | 146 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n001 7 8f21 9076 9852 b911 | 47 898d (0) 886a (0) 88fe (0) 88a1 (0)\n002 2 d3b0 cc20 | 26 c26f (0) c1f9 (0) c59e (0) c49c (0)\n003 5 e883 e854 eb98 e54b | 18 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n004 12 f27f f31c f629 f7fa | 13 f629 (0) f7fa (0) f7ba (0) f773 (0)\n005 3 ff36 fe21 fe31 | 3 ff36 (0) fe31 (0) fe21 (0)\n============ DEPTH: 6 ==========================================\n006 1 f925 | 1 f925 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 fbc8 | 1 fbc8 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","private_key":"abe3a2c3b4d87e1896b5eeb333bb2fae65888f42d5708e88df6eec9d4d6f2a89","name":"node_fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","services":["streamer"],"enable_msg_events":true,"port":42599},"up":true}},{"node":{"info":{"id":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","name":"node_0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","enode":"enode://22e0f016453557931968739b1927c6a2a96b3b3ef0720b9f574365f821ff4afa7d162aced052618c51e939baeec49bbda090ea6f2a5b14b3ced028e3587b4d51@127.0.0.1:0","enr":"0xf88fb8402397168cccae2be13f6646db7bd1f2d478d9124f8397e08ceae0045ca8baa3242f68f4c83fd1744b397234b474e6f46b048fd0d74acb55d3f44dc78d0dfede6b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10322e0f016453557931968739b1927c6a2a96b3b3ef0720b9f574365f821ff4afa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D8Wb0ErJ3jGV48nQ61c5UqWAXdLn5XIHi26ZZ3it7HM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0fc59b\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 90a8 9076 82dd 8505 | 110 898d (0) 886a (0) 88fe (0) 88a1 (0)\n001 2 7dd3 41d9 | 70 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n002 4 3e8e 33b5 2c79 2f32 | 32 3b78 (0) 3b88 (0) 39d1 (0) 3f94 (0)\n003 4 165f 154b 13d6 1c9c | 22 14df (0) 1400 (0) 1436 (0) 154b (0)\n004 4 0328 00c6 045b 0661 | 11 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n005 3 0b72 0a00 0af9 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 5 0d8a 0de3 0cf5 0c64 | 5 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 7 ==========================================\n007 1 0e5e | 1 0e5e (0)\n008 0 | 0\n009 0 | 0\n010 1 0ff2 | 1 0ff2 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","private_key":"ab99d1389adc583c136dfe3f4569fbb9ce9ea477cc13a503e1a4aa3f557edffc","name":"node_0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","services":["streamer"],"enable_msg_events":true,"port":44559},"up":true}},{"node":{"info":{"id":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","name":"node_0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","enode":"enode://e62b09e34b132f4e59783ab65b9fb191398665c73b314a5fb36715728f869e8e608b374a91e22c4de5eae4fdff9ec4d2e9509c8e1a9c32e675fcf6fee76714f2@127.0.0.1:0","enr":"0xf88fb8409dc12163f250583e65c4c1bb7a368c6d27bbf9a62a49b5b3e99603fa802b0e227379f85879f46521bb12306b9d59b270796787b4da47ad4e0a1a688a4a5ac66c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e62b09e34b132f4e59783ab65b9fb191398665c73b314a5fb36715728f869e8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D/LSxJVH7ryWZ14LiAc96l6Qkb7hhD/+VnEn40SGw0g=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ff2d2\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a34e a46d 9076 9852 | 110 88fe (0) 88a1 (0) 886a (0) 898d (0)\n001 7 6e68 6c73 66e7 605a | 70 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n002 4 3e8e 33b5 2f32 2c79 | 32 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n003 5 154b 179f 165f 13d6 | 22 11d4 (0) 103b (0) 13d6 (0) 1400 (0)\n004 5 0661 045b 0328 0067 | 11 0438 (0) 0451 (0) 045b (0) 0743 (0)\n005 3 0b72 0af9 0a00 | 3 0b72 (0) 0af9 (0) 0a00 (0)\n006 4 0d8a 0de3 0cf5 0c28 | 5 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 7 ==========================================\n007 1 0e5e | 1 0e5e (0)\n008 0 | 0\n009 0 | 0\n010 1 0fc5 | 1 0fc5 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","private_key":"b07ba37d3566d0d06613c70c3b970828a35c02d35d3ef97c26f1e431564cbc71","name":"node_0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","services":["streamer"],"enable_msg_events":true,"port":36663},"up":true}},{"node":{"info":{"id":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","name":"node_582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","enode":"enode://e1459426b83f1c65c5a4dac403ae9a8773d1fadf7f57014afe1f5632b40de446b925e309ac581a098f0a8597f54b231887ddef9fb033832546b7b1c438536514@127.0.0.1:0","enr":"0xf88fb84034a6c607747bfdaaddea35634f841a275979e6eb07a13c4806c7988076977d676c9cbe2a8b59da6776cf329633bf937933eebe202770e6b4cd1dc70b794785850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e1459426b83f1c65c5a4dac403ae9a8773d1fadf7f57014afe1f5632b40de446","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WCMw2LjEkzGyrseQ3HMluc1IP8gSkyPTHsQp1UUEKWQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 582330\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eb98 fbf5 | 110 8f21 (0) 898d (0) 886a (0) 88fe (0)\n001 2 1c9c 0ff2 | 76 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n002 5 7920 7dd3 605a 6e68 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 7 4c9e 4d6b 4d59 4e5a | 23 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n004 7 574f 51db 524d 5308 | 8 574f (0) 512e (0) 51db (0) 524d (0)\n005 3 5cd2 5db0 5efb | 4 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n============ DEPTH: 6 ==========================================\n006 1 5b63 | 1 5b63 (0)\n007 0 | 0\n008 1 58ed | 1 58ed (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","private_key":"e0e4076ce60393be8ae8f561ab3bbb784e5d4b9cf9044cbea245608f94062e9f","name":"node_582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","services":["streamer"],"enable_msg_events":true,"port":44383},"up":true}},{"node":{"info":{"id":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","name":"node_41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","enode":"enode://f68ed6030af61743ebafe811b9833a5cc29e35d00e6e0181d06feef9ca714898bed30f326a49a3c145cd1002a24d9c5ae79c2787464e58cd24dcf59fd0760bc1@127.0.0.1:0","enr":"0xf88fb8408b71d88c0475a30d0141a21ead67266d6a40391c609d4fbb1c376e0f05e920160e6dbbc8db17d82a85e5121346b02f6c670e28e88acba5d763a1986cea5bedf90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f68ed6030af61743ebafe811b9833a5cc29e35d00e6e0181d06feef9ca714898","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QdnAPkS+w/hKYTnOQO8eOQUw847RGGBXWs+tA6SdsJU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 41d9c0\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 daec eb98 fbf5 | 110 ad98 (0) ac4d (0) af02 (0) ae2b (0)\n001 3 314a 0fc5 1c9c | 76 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n002 8 7125 7920 7dd3 66e7 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 5 534b 53fe 5efb 5cd2 | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 7 4990 49ea 4bcf 4c9e | 11 49cd (0) 49ea (0) 4990 (0) 4a8b (0)\n============ DEPTH: 5 ==========================================\n005 10 47bf 4782 46fe 4646 | 10 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n006 0 | 0\n007 0 | 0\n008 1 4109 | 1 4109 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","private_key":"1165ce19cad30464dac1767d11f8462ee17a275b99240f7757f516575dae8bd3","name":"node_41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","services":["streamer"],"enable_msg_events":true,"port":39051},"up":true}},{"node":{"info":{"id":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","name":"node_1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","enode":"enode://27e2579492f09c50dbc56b6542114d27789897327092c0ddacbabe5f3916be86362afe3b61ec3ea54eb7d39401f7a9307901cacc84a5cb54ab868b4b8c28cbe0@127.0.0.1:0","enr":"0xf88fb840a0df68e76ebed32c21b033b1570b6dcdb45783053022b12bc2763acfd7929fbe3ac0306848c56ad630845f8c05dfc0b47d2976e01c8e1f91cc270fd9f6846edf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10227e2579492f09c50dbc56b6542114d27789897327092c0ddacbabe5f3916be86","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HJyvAo3zFoGxRXpU1LOrIACfn6W9EkF6G6fv4MZg5r0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1c9caf\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a34e 9852 daec fbf5 | 110 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n001 7 66e7 6e68 7125 534b | 70 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n002 5 314a 33b5 3e8e 2c79 | 32 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n003 5 0661 00c6 0af9 0fc5 | 22 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n004 10 154b 1400 1436 14df | 12 11d4 (0) 103b (0) 13d6 (0) 1400 (0)\n005 3 1a2a 18f6 19fa | 4 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n006 3 1f85 1f67 1e2a | 3 1f67 (0) 1f85 (0) 1e2a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 1c47 | 1 1c47 (0)\n009 0 | 0\n010 0 | 0\n011 1 1c8a | 1 1c8a (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","private_key":"67941e3130de030151f98c59f040e588508b299893d26eede53fbfd0400f76a6","name":"node_1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","services":["streamer"],"enable_msg_events":true,"port":40355},"up":true}},{"node":{"info":{"id":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","name":"node_4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","enode":"enode://eb61dee424d25e9ca5147121a89b8dfc8e186fd83ad973d590fe6f050e5ad71094b18d539d127b7699769bd08e722bf1d253c42d9dcd7bd744efb8d90b7517bc@127.0.0.1:0","enr":"0xf88fb8409303866ac69b06db6e9cd2c5bf37b2046d4ba9be08473191181141ebc1a822e37088c33aaa9d396ad7398756422d234de878117f2cce3bd9477b23860a9bcea00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102eb61dee424d25e9ca5147121a89b8dfc8e186fd83ad973d590fe6f050e5ad710","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TVnPGu7PNw6Up6IxiHRQzvlwU7nIin/RHiEIQK8HDik=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d59cf\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9852 c898 eb98 | 110 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n001 2 1c9c 2f32 | 76 02d8 (0) 03cc (0) 0328 (0) 0067 (0)\n002 6 7125 7dd3 7920 605a | 32 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n003 4 5823 5cd2 534b 53fe | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 3 4646 4109 41d9 | 12 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n005 3 4990 49ea 4bcf | 6 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n006 1 4e5a | 1 4e5a (0)\n007 1 4c9e | 1 4c9e (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 4d10 | 1 4d10 (0)\n010 1 4d6b | 1 4d6b (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","private_key":"37294667aa7ef5913f670784ca64ca2422b73d30730798e5ba9d0dce067d5f04","name":"node_4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","services":["streamer"],"enable_msg_events":true,"port":41171},"up":true}},{"node":{"info":{"id":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","name":"node_2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","enode":"enode://27ddb367d5d4a30ad5888523d743494926b5a27942077719cc6c537b73f04bb87f65cddfb3cfc09a733c1691c43c7a9afe8b9e268ee323af1f8d8a85beea4cb5@127.0.0.1:0","enr":"0xf88fb840772057c835ac9c84a2eaa07977982bbc77cdb5dbc67b095e1b64eba4bd7364362a8286caab1fac316b5f9c128103397f945e78d6d1f10dbe310fb1a21a5657680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10327ddb367d5d4a30ad5888523d743494926b5a27942077719cc6c537b73f04bb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LzLVTwaYnvtspUMbdM11n7oF2+827P+P1QbmYgJq+YM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2f32d5\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9852 c620 daec eb98 | 110 ad98 (0) ac4d (0) af02 (0) ae2b (0)\n001 5 6e68 7125 7dd3 534b | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 6 0661 0ff2 0fc5 13d6 | 44 02d8 (0) 03cc (0) 0328 (0) 0067 (0)\n003 6 314a 33b5 3b78 3efc | 17 3780 (0) 378e (0) 3630 (0) 35e6 (0)\n004 4 256e 24b8 2101 21a0 | 6 24b8 (0) 256e (0) 20ae (0) 217f (0)\n005 2 2a97 2abb | 4 2995 (0) 2a0a (0) 2a97 (0) 2abb (0)\n============ DEPTH: 6 ==========================================\n006 4 2d36 2ccf 2c38 2c79 | 4 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","private_key":"fb9c0c109d964d1f2840834912ab8fb4d275c821c47cbacf4865721f774ad246","name":"node_2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","services":["streamer"],"enable_msg_events":true,"port":37983},"up":true}},{"node":{"info":{"id":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","name":"node_eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","enode":"enode://e478db1e6ae924395ba7c3eed4a3c1161fed7757938dbc6e802fca7e8daac58d16f9cf87017d684499f9aa2c5ea3ebbf74805e24b5454661a4f12af2bd9b4e69@127.0.0.1:0","enr":"0xf88fb84083fabf1c86dbfb7ea406905cb02c1a05b4cd8e41ee010679b981abb41d7ef8ba1e5f916713c12c739fd237f35952c0e01b65faf2bdffe581e53b602ef397cd470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e478db1e6ae924395ba7c3eed4a3c1161fed7757938dbc6e802fca7e8daac58d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"65j7Rd1XVPJPnfDJ7LuTky49nXc1zW0N3UqGdbtO9VQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb98fb\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5823 41d9 4d59 103b | 146 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n001 5 b820 b02b a46d a34e | 47 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n002 6 d3b0 d887 daec c898 | 26 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n003 9 fbc8 fbf5 f925 f773 | 19 f629 (0) f7fa (0) f7ba (0) f773 (0)\n004 5 e027 e775 e7fa e514 | 8 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n005 5 ed2d ee5e ef1b ef07 | 6 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n============ DEPTH: 6 ==========================================\n006 3 e8ef e883 e854 | 3 e8ef (0) e883 (0) e854 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","private_key":"ab86a41209d246a5d6b5c8bf86ba8d32901ffa817d143a63719c1189703ae84f","name":"node_eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","services":["streamer"],"enable_msg_events":true,"port":43213},"up":true}},{"node":{"info":{"id":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","name":"node_9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","enode":"enode://e78bf7b14baa9f968a1eab4abb0ffcc6aaf7f6a3152a59d6b404ef00232ff35cf55fa13f6190c6cb6bcfa4394bb912d7dab1d491f2d39ed7b43029d0f99319d0@127.0.0.1:0","enr":"0xf88fb84029d6cf3fe0d8101f62b9bf17bad9b25f903639962d22b9643a3a6216b8946f00593519afbe56588bbd1e0e52d3a0339778deb5c4c780a818db4c44140fd7bd930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e78bf7b14baa9f968a1eab4abb0ffcc6aaf7f6a3152a59d6b404ef00232ff35c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mFLOJn1TEGpuWE1u3bCOAGLrSkItKo05rW3MrrrFUv8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9852ce\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0ff2 165f 1c9c 2f32 | 146 3780 (0) 378e (0) 3630 (0) 35e6 (0)\n001 4 daec fbc8 fbf5 eb98 | 63 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n002 9 b02b b2a5 bcc6 b911 | 27 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n003 5 8f21 88a1 8505 849b | 10 898d (0) 886a (0) 88fe (0) 88a1 (0)\n004 4 9076 90a8 976e 96fc | 6 959f (0) 976e (0) 96fc (0) 915d (0)\n============ DEPTH: 5 ==========================================\n005 2 9d0f 9fa0 | 2 9d0f (0) 9fa0 (0)\n006 0 | 0\n007 0 | 0\n008 1 9890 | 1 9890 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","private_key":"ce304c9eade55eb825a72feda5a3d11f9ae9261aadf2bdd54ccd8f3e963dc251","name":"node_9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","services":["streamer"],"enable_msg_events":true,"port":43037},"up":true}},{"node":{"info":{"id":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","name":"node_daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","enode":"enode://8a808e57c6bcbab9333ebbeb571f922303b1bb3197db84c5ff936033294f12429f7b8b06da61e7c04ad7f7c039e2b765b324069428cf86ad8a2d4bddca8d9948@127.0.0.1:0","enr":"0xf88fb84027da20f74a296f9b64d09eb538af5e462aececd8a624e3ac95423f168b062f7c4c6368ee7acf0f9bed1ce235bef0b932517a9ff281c24a84ab5bb5a307b560fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028a808e57c6bcbab9333ebbeb571f922303b1bb3197db84c5ff936033294f1242","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2uxF7KQPSIQ7QfcCZ8B+lJls7YKfAnEPFTVPvibhd+c=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: daec45\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 7dd3 6c73 6251 41d9 | 146 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n001 6 a34e b02b b2a5 b820 | 47 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n002 11 f456 f45f f773 f31c | 37 f629 (0) f7ba (0) f7fa (0) f773 (0)\n003 5 cc20 c9f5 c898 c1f9 | 15 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n004 3 d1d7 d3b0 d299 | 5 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n005 1 df1e | 1 df1e (0)\n006 2 d887 d863 | 2 d887 (0) d863 (0)\n============ DEPTH: 7 ==========================================\n007 1 db6a | 1 db6a (0)\n008 1 da67 | 1 da67 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","private_key":"56866cfeb6cabc6b29d13eb7d3d7f08b4638fcf8f8d6c84303c8af5fa371a1a5","name":"node_daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","services":["streamer"],"enable_msg_events":true,"port":41737},"up":true}},{"node":{"info":{"id":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","name":"node_c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","enode":"enode://87345615c0805d99ec1ea2d9a2524323283810eec32d47fb14165619987edcb9c7d0cc052960238c4beda0cb4692412848cf083744f4287c1d3e3d3549ec8a17@127.0.0.1:0","enr":"0xf88fb84019bfcc1148e643a0381e48afe5c5e9d093b752843123d526ed1df4f62f0c9bdc3ccdc2c80c5be269b4a5674da87b07f2bfea41b969d01926921086864a6914940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10387345615c0805d99ec1ea2d9a2524323283810eec32d47fb14165619987edcb9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xiB1Kgg8of8DmJNyNc+WQTOTlFLCk8eZzgf/iqK95CA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c62075\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2c79 2f32 7dd3 6c73 | 146 24b8 (0) 256e (0) 20ae (0) 2101 (0)\n001 6 b2a5 b02b b820 a34e | 47 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n002 11 fbc8 f925 f31c f773 | 37 f629 (0) f7ba (0) f7fa (0) f773 (0)\n003 3 d3b0 d887 daec | 11 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n004 4 cc20 c9f5 c832 c898 | 6 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n005 2 c26f c1f9 | 2 c26f (0) c1f9 (0)\n006 3 c59e c43f c441 | 4 c59e (0) c49c (0) c43f (0) c441 (0)\n============ DEPTH: 7 ==========================================\n007 1 c786 | 1 c786 (0)\n008 1 c6cf | 1 c6cf (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","private_key":"6819c930fa19b056e7757bb4f0b87d2eba8bbd661c6bec9f68594559199669e9","name":"node_c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","services":["streamer"],"enable_msg_events":true,"port":39637},"up":true}},{"node":{"info":{"id":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","name":"node_6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","enode":"enode://80cc5420bd8d38bbd9b86077f10f27e11ac8ba32e9faa57dae75f0ebd5b605deaba207fc0912b1b93cbd29ad868bdcb0ecfc77c35f8d02e63729e09e8ccf1050@127.0.0.1:0","enr":"0xf88fb840f9be773757b0f5b1b3eecf7c1e53f23d4c24f84948d5fa49b2024cafcd7e7fce1dde3a795a557af1919771bb29869e79054b383ecb6413dbd5a7ad5637552c130183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10280cc5420bd8d38bbd9b86077f10f27e11ac8ba32e9faa57dae75f0ebd5b605de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bHMVBJDovpZ3xACG3grv7Rk5WBBI4m9Kk/XKJlcaGo8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c7315\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9076 e854 daec c620 | 110 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n001 6 21a0 2c79 3e8e 33b5 | 76 24b8 (0) 256e (0) 20ae (0) 217f (0)\n002 9 53fe 534b 5823 4646 | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 6 7125 738c 775e 7dbb | 12 77d2 (0) 775e (0) 7290 (0) 738c (0)\n004 6 67dc 66e7 60d7 605a | 9 6103 (0) 60d7 (0) 605a (0) 6337 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n============ DEPTH: 6 ==========================================\n006 7 6fe9 6f5f 6f2d 6ecb | 7 6fe9 (0) 6f5f (0) 6f2d (0) 6ecb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 6c4d | 1 6c4d (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","private_key":"1d02f4867632ec5b85fbb3116d676151cc62887e6c539870ba0c42f929299581","name":"node_6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","services":["streamer"],"enable_msg_events":true,"port":34593},"up":true}},{"node":{"info":{"id":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","name":"node_e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","enode":"enode://427720d085bc2d3fdde2d55df27162448b78a2e49d4d68bd8566b41345c87af64019cab4042a4228010b78ccc0935eb8d1fbbd6e147127d103557cff767e43fe@127.0.0.1:0","enr":"0xf88fb8400983bdd51a44197b57c4edd3528554d739aeb0876d2c50da898b134a951aea4d0045cd49590984531c7ba95e99489cb0155a426655d50bc36483d8da6e90af5b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102427720d085bc2d3fdde2d55df27162448b78a2e49d4d68bd8566b41345c87af6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6FSLXfFa3w8qmX/1cJgnvrXh02uwii8tAXdG1cDoP8o=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8548b\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 103b 165f 7920 6c73 | 146 24b8 (0) 256e (0) 20ae (0) 217f (0)\n001 3 b02b b820 9076 | 47 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n002 5 d3b0 daec c620 cc20 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 7 fbc8 fbf5 f925 f27f | 19 f629 (0) f7fa (0) f7ba (0) f773 (0)\n004 3 e775 e7fa e54b | 8 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n005 6 ec52 ed2d efea ef07 | 6 ec52 (0) ed2d (0) ee5e (0) efea (0)\n006 1 eb98 | 1 eb98 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e8ef e883 | 2 e8ef (0) e883 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","private_key":"a54bb672dc9321d27af926996f1bd8561f767a940f45b2ae7b50641aafc296b2","name":"node_e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","services":["streamer"],"enable_msg_events":true,"port":46437},"up":true}},{"node":{"info":{"id":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","name":"node_165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","enode":"enode://4201b86b495b4d95596ac23ba0cc4d0f467eb4570eae4bb2406f02acd483a0b590572cb93ff3d5e15951430b17eb765cfc57f0dd0f98d54facc4840a2f3c7446@127.0.0.1:0","enr":"0xf88fb8402d57c75cdbe7f54cfca4be2a9df2fd02b13b64e4abe4a8777dfcc5ac11a951a14393317578595f7833b5b2c12b361607c6f94305581f0499823944b40349d6d20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024201b86b495b4d95596ac23ba0cc4d0f467eb4570eae4bb2406f02acd483a0b5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Fl8a9nqh0kVp4L3/YdKbPDnpMlAHHY8ltb5vrOIJrGo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 165f1a\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9852 9076 daec e775 | 110 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n001 5 66e7 6831 6e68 6c73 | 70 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n002 4 2c79 2f32 314a 3e8e | 32 256e (0) 24b8 (0) 20ae (0) 217f (0)\n003 6 0328 0661 045b 0b72 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0d8a (0)\n004 4 1e2a 1c9c 1c8a 19fa | 10 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n005 3 11d4 103b 13d6 | 3 11d4 (0) 103b (0) 13d6 (0)\n006 3 1436 14df 154b | 4 1400 (0) 1436 (0) 14df (0) 154b (0)\n============ DEPTH: 7 ==========================================\n007 3 1704 17db 179f | 3 1704 (0) 17db (0) 179f (0)\n008 0 | 0\n009 0 | 0\n010 1 1672 | 1 1672 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","private_key":"a5255c5dfef55c549d9899c6086c1aa7f58eeab3dae94d863d16c3e8e5e6f308","name":"node_165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","services":["streamer"],"enable_msg_events":true,"port":37147},"up":true}},{"node":{"info":{"id":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","name":"node_7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","enode":"enode://9abcce8e8480c2df00f55c8b10f7cbcc56979a41c870eb9fc81ebf37df92ee56d47d9a3d76b9e87204e7cb20d39b04d584ce00ac702f1328606752cabc70d246@127.0.0.1:0","enr":"0xf88fb840246ddc3f6e34e2c10b5ef70b569b15a2579675614e0994c18a8ebf51041a206f4a5a670c168fed69567e6ce63b8b4308bd28e430a270bf4c36bc8e090a29e4780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029abcce8e8480c2df00f55c8b10f7cbcc56979a41c870eb9fc81ebf37df92ee56","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eSDWnPfkWPzgeB6hpOB3aOGmn2gYCQ7/Cr8LSgwsNfg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7920d6\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b2a5 e854 e775 | 110 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n001 2 3e8e 165f | 76 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n002 6 524d 5823 41d9 4bcf | 38 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n003 9 67dc 66e7 6251 628e | 20 67aa (0) 67dc (0) 66e7 (0) 6103 (0)\n004 3 738c 7125 775e | 5 77d2 (0) 775e (0) 7290 (0) 738c (0)\n005 4 7e04 7dbb 7dc2 7dd3 | 4 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n============ DEPTH: 6 ==========================================\n006 2 7a60 7b90 | 2 7a60 (0) 7b90 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","private_key":"9a81a3bcde96713d5d92389b259485aaaff9b59596864bb8933d09ef5ebb1d41","name":"node_7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","services":["streamer"],"enable_msg_events":true,"port":42903},"up":true}},{"node":{"info":{"id":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","name":"node_e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","enode":"enode://beda928185a8d044cb7303a817ba03b2c76bcf663ef5e852bb6f1f00730bdc445f98b40f8e29f427d9a802c2a3b74ad3403a3d47efb577b555ed87c05ebf83f7@127.0.0.1:0","enr":"0xf88fb840f9fda3d64eba7bad62497dba8a4c99a8e256a8159a4d7b38855bea2e5055a81b7ac9f978137e928e9116c805cca511efdcc58fb9b2473f5c08c4f0d0061cc1e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103beda928185a8d044cb7303a817ba03b2c76bcf663ef5e852bb6f1f00730bdc44","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"53XpdZ1HAb2bQ8IvHRvnPBJisnUrsjyzhXSF2vHcrS0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e775e9\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 103b 165f 7920 | 146 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n001 5 aeb4 af02 a34e a46d | 47 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n002 4 d3b0 c1f9 cc20 c898 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 8 f925 fbf5 fbc8 f773 | 19 f629 (0) f7fa (0) f7ba (0) f773 (0)\n004 6 ee5e ef1b efea eb98 | 10 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n005 1 e027 | 1 e027 (0)\n============ DEPTH: 6 ==========================================\n006 5 e5d7 e5ad e54b e547 | 5 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n007 0 | 0\n008 1 e7fa | 1 e7fa (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","private_key":"6be6c403a2ff471a0099cbeee98c75dbf2d356237b388e44e9620413135bfe37","name":"node_e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","services":["streamer"],"enable_msg_events":true,"port":46777},"up":true}},{"node":{"info":{"id":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","name":"node_90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","enode":"enode://475b303a40b4441c17f91b7ad399fa70524c60f241f66ac9139de672f06daa5b470a82c16372cb24c759bd76074ca5fb3161083dc6e1131d8f5f4de86ee8542e@127.0.0.1:0","enr":"0xf88fb84067ea7594026da51603b1294b65583b247f3a11286470ba680919f1cfd860bdd20a177b4b4dc916ba757482dac7f6f796677756f635eaa61bb8342f18bad700a20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102475b303a40b4441c17f91b7ad399fa70524c60f241f66ac9139de672f06daa5b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kHZbcig/Wb5M+b96npoi/W23AcNgPLwIF7St8vjpzgg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 90765b\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 3e8e 0fc5 0ff2 165f | 146 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n001 9 fbc8 fbf5 f456 e854 | 63 f629 (0) f7ba (0) f7fa (0) f773 (0)\n002 13 a46d a34e ad98 af02 | 27 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n003 5 8f21 88a1 8505 849b | 10 8f21 (0) 898d (0) 886a (0) 88fe (0)\n004 4 9852 9890 9fa0 9d0f | 4 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n005 3 959f 976e 96fc | 3 976e (0) 96fc (0) 959f (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 915d | 1 915d (0)\n008 1 90a8 | 1 90a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","private_key":"e212701e3a46630b79ca2e6bd4d1a4a4abe893d524fc5bb0327380b4c6ab4c0f","name":"node_90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","services":["streamer"],"enable_msg_events":true,"port":41311},"up":true}},{"node":{"info":{"id":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","name":"node_c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","enode":"enode://825fc662eadb1275f9fcd9e791cf12186b5446a81da414669c827c420f43b5550dc05c59267237d34248e57aa77bb1ca04b16a1667f06f1f277e76df0da74bd4@127.0.0.1:0","enr":"0xf88fb8405d639cdcd2181b1bbc1d50557f4ec79e187fddc491c03234d9b07f7968f78a8e49bc2c34d44a6790e07bdf309cb28c8fa1e0fa7ca95b2d5c9c2e34a676f4a9040183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102825fc662eadb1275f9fcd9e791cf12186b5446a81da414669c827c420f43b555","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yJhoceRvAB0V7Ytw8qoP6orjCdXlZxpQD2GeOzSMjBU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c89868\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7dd3 4bcf 4d6b 4d59 | 146 4e5a (0) 4c9e (0) 4d10 (0) 4d6b (0)\n001 4 b820 b2a5 82dd 9076 | 47 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n002 12 fbc8 f773 f5dc f5b2 | 37 f629 (0) f7ba (0) f7fa (0) f773 (0)\n003 3 d3b0 d887 daec | 11 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n004 4 c26f c1f9 c6cf c620 | 9 c26f (0) c1f9 (0) c59e (0) c43f (0)\n005 1 cc20 | 1 cc20 (0)\n006 2 caf6 ca04 | 2 caf6 (0) ca04 (0)\n============ DEPTH: 7 ==========================================\n007 1 c9f5 | 1 c9f5 (0)\n008 1 c832 | 1 c832 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","private_key":"6a52946fb72e66e0da1a45ae5641b7e4bd71cd109d0f8b0bd84c912f21a62a29","name":"node_c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","services":["streamer"],"enable_msg_events":true,"port":42015},"up":true}},{"node":{"info":{"id":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","name":"node_3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","enode":"enode://eb36b8be16b143563e4e6a0d40a3059746dd4073e875a344c54ac9da33c5687b346497f5efcb5b8ae55c7c077ad93fa8ddd69dc4aca6f257f892f8f0535e83bd@127.0.0.1:0","enr":"0xf88fb840606ae288441ca25000384f3327aab7b6a889361a45eed00f010a8711ec569a9304f1c0084e167f0f4f050196deb0d8c3321fe2266446fa5e76b11908918001c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eb36b8be16b143563e4e6a0d40a3059746dd4073e875a344c54ac9da33c5687b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Po78rzACUis5Bl6jDBVCbR61WRZJnv+OtagU451BhTw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3e8efc\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9076 b2a5 fbc8 c898 | 110 a653 (0) a6fb (0) a46d (0) a369 (0)\n001 7 534b 7dbb 7920 6c73 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 6 0661 0328 0ff2 0fc5 | 44 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n003 4 21a0 2abb 2c79 2f32 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 3 3373 33b5 314a | 10 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n005 3 39d1 3b78 3b88 | 3 39d1 (0) 3b78 (0) 3b88 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 3f94 | 1 3f94 (0)\n008 0 | 0\n009 2 3ec5 3efc | 2 3ec5 (0) 3efc (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","private_key":"4de210de6f44b43eebcea0e42a320de5fe4a52ee899ce93696e65018dff1943b","name":"node_3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","services":["streamer"],"enable_msg_events":true,"port":39127},"up":true}},{"node":{"info":{"id":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","name":"node_fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","enode":"enode://a017d5ec65ed0ff2bae902195ea9a509c51eade81c818bc111bd6e344ab51bbdb90239fbef510e247dd4917ee5be1cdee2b4f7206adccc675c6b1ef1ac1b70d6@127.0.0.1:0","enr":"0xf88fb840fb39a6e6bc63eb34afc956930c4bb747b7653c69db586b3e5e8986f527c8d08142c0bbc03752bb77e1109ac8a562274d065fd633c69ea3597394362919a720f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a017d5ec65ed0ff2bae902195ea9a509c51eade81c818bc111bd6e344ab51bbd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+8gIenI8VkygE5MpkC55dIr0Zpnqe+JNV5Cafo6W9oE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fbc808\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 534b 179f 3e8e | 146 7290 (0) 738c (0) 7125 (0) 77d2 (0)\n001 9 8f21 8505 9076 9fa0 | 47 959f (0) 976e (0) 96fc (0) 915d (0)\n002 3 daec c620 c898 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 ef1b eb98 e854 e883 | 18 ed2d (0) ec52 (0) ee5e (0) ef07 (0)\n004 9 f773 f456 f45f f4e0 | 13 f629 (0) f7fa (0) f7ba (0) f773 (0)\n005 3 fe31 fe21 ff36 | 3 fe31 (0) fe21 (0) ff36 (0)\n============ DEPTH: 6 ==========================================\n006 1 f925 | 1 f925 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 fbf5 | 1 fbf5 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","private_key":"459e90cfb3188b5829214e99ecdfdc92c3ca4a8df6a164a5c4c61f79eeefe059","name":"node_fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","services":["streamer"],"enable_msg_events":true,"port":35587},"up":true}},{"node":{"info":{"id":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","name":"node_f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","enode":"enode://ad212ba24b9f1cd7ee7e5431309edc1714e9c5ff6610fc49c63be97528ebacc2013bdd5f987b388cb1d6a6a7645d8ea7c5a98b90c4b0f70f4fca6793eb1f01f4@127.0.0.1:0","enr":"0xf88fb840cdd1cdeb2532d9112faf9bdd13f0ab62954f54b6d55a30181ff5f719725dd1b3761a25fdd94173632cf3aa481a3430b30a1bb5341e26c05b8e0ae738e0ace46c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ad212ba24b9f1cd7ee7e5431309edc1714e9c5ff6610fc49c63be97528ebacc2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8n8QRHd+BfP2AWXQ0vw+dmf+FI4Mp6CXgF1gufYQJfc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f27f10\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0661 534b | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 2 b820 b2a5 | 47 959f (0) 976e (0) 96fc (0) 915d (0)\n002 4 d3b0 daec c1f9 c898 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 e54b e775 ef1b eb98 | 18 ec52 (0) ed2d (0) ee5e (0) ef1b (0)\n004 3 f925 fbf5 fbc8 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 9 f629 f7ba f773 f528 | 10 f629 (0) f7fa (0) f7ba (0) f773 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f31c | 1 f31c (0)\n008 1 f2d5 | 1 f2d5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","private_key":"ce524e315364068c85c93ee7c34cfc6e5532742848a01bf543d213e2cf22f9ee","name":"node_f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","services":["streamer"],"enable_msg_events":true,"port":40031},"up":true}},{"node":{"info":{"id":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","name":"node_b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","enode":"enode://a5a8a40f361adf355086fefe1a9d530ee072ff7dda43026954c2e20dfdcdc445873d72bf613dea981c6fe57941e79af6b837431625892eae841bcecec8fa5ea1@127.0.0.1:0","enr":"0xf88fb840a9cc6dfb9ffae8d02cc4343351e64345b21f117b53ef86ee469eed2d5d3929f67c1084a5e8b4ce788894461222a59beb00152452d61f6acc04724857718931030183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a5a8a40f361adf355086fefe1a9d530ee072ff7dda43026954c2e20dfdcdc445","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sqVjrFm6tN/d97bie4Duev3rLkKVQREHkD9IS8+fxPI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2a563\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0661 3e8e 7920 628e | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 6 daec c620 c898 fbc8 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 6 9fa0 9852 9890 9076 | 20 959f (0) 976e (0) 96fc (0) 915d (0)\n003 5 af02 aeb4 a6fb a46d | 10 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n004 8 bcc6 ba88 badd bb90 | 9 bcc6 (0) baf2 (0) badd (0) ba88 (0)\n005 3 b5b2 b502 b7ca | 5 b5b2 (0) b502 (0) b626 (0) b65e (0)\n============ DEPTH: 6 ==========================================\n006 1 b02b | 1 b02b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 b2b5 | 1 b2b5 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","private_key":"d311ffc3650bc45898ce1480ced3b3fabaed9a8a9877d26a97b2710c9318716f","name":"node_b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","services":["streamer"],"enable_msg_events":true,"port":44537},"up":true}},{"node":{"info":{"id":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","name":"node_b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","enode":"enode://7f841ce185c998f72468ded1e943d2a109a834b4b15c957132af2e5f364df4111c57d1b83651a4b899bf40a3131509505ff6d750e182af6b711511f92bc594a5@127.0.0.1:0","enr":"0xf88fb840c1a87287bf9a406351496453395ee3cc77e00b626375a7e86abedcd951c907f875178719162b1663979a6ec05a5f949286e03f2611eecf13bfb9caca0f670c200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037f841ce185c998f72468ded1e943d2a109a834b4b15c957132af2e5f364df411","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uCDkgDVAAMg3sXgewcST6HdrSDQlLmRTQlrAW5JbWlg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b820e4\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0661 66e7 628e 534b | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 11 c898 c620 daec e883 | 63 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n002 6 9890 9852 9fa0 9076 | 20 959f (0) 976e (0) 96fc (0) 915d (0)\n003 3 a34e a46d af02 | 10 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n004 2 b02b b2a5 | 8 b626 (0) b65e (0) b7ca (0) b5b2 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 badd ba88 bb90 | 4 baf2 (0) badd (0) ba88 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b911 b95d | 2 b95d (0) b911 (0)\n008 1 b897 | 1 b897 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","private_key":"61fe17d5be2ccee74b17d7c47a21cef62eea82042e68eb5bc32139b57bf6ee76","name":"node_b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","services":["streamer"],"enable_msg_events":true,"port":36559},"up":true}},{"node":{"info":{"id":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","name":"node_534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","enode":"enode://b948e96344e56ff7ae61c23f8751d2dcc3cb818bb11e981357d1acc94c3c662987cc236e5ecbac4288b68cac7f704edbd39a158a7ec1477817e6379b9d3f06ac@127.0.0.1:0","enr":"0xf88fb8408d7d8db1b2d8e46e0446181eb4d5f2d93967e8f7c55430e17ce80fa7269dbadc2a24bddd9024c14a94deea3ad1cfa69efd5b3e6156e87d8b0afaac9d3ff4a6680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b948e96344e56ff7ae61c23f8751d2dcc3cb818bb11e981357d1acc94c3c6629","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U0vKqYz5GSs1tgFMZQrgZ+dDMsAV67UW1jYBQn1zdrg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 534bca\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c898 fbc8 f27f b2a5 | 110 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n001 7 1c9c 0661 2abb 2f32 | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 6 7dc2 775e 7125 6c73 | 32 7290 (0) 738c (0) 7125 (0) 77d2 (0)\n003 7 41d9 44a1 4e5a 4c9e | 23 4782 (0) 47bf (0) 46fe (0) 461c (0)\n004 3 5efb 5cd2 5823 | 7 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n005 1 574f | 1 574f (0)\n006 2 51db 512e | 2 512e (0) 51db (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 53a8 53fe | 2 53a8 (0) 53fe (0)\n009 1 5308 | 1 5308 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","private_key":"c7f75190502386c9d3b3434c24956d84b4c9e41c91671f2b28496a7f4fcdc39e","name":"node_534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","services":["streamer"],"enable_msg_events":true,"port":45967},"up":true}},{"node":{"info":{"id":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","name":"node_66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","enode":"enode://71bc46e6ba9589ea0718de84c96b5d58b5d7f0781e021b003f14b1cda7ff7ccbe697f9d910349ec8830341cfc00ce73729b28d91bf6c66989a46e72d3c5853f7@127.0.0.1:0","enr":"0xf88fb8402f952b1b8ee3a0cdd608676ac1b0422c05695038e3da52824da26933ab776cae7a335c51043e1d2c6b35d878ed54ffa2c4acd71f3870c1ac2db03fdda4be24880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10371bc46e6ba9589ea0718de84c96b5d58b5d7f0781e021b003f14b1cda7ff7ccb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Zuf8LfUfXfjXMphR/pNX2JXp1d/cJfjZK9sQqWD34Vo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 66e7fc\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b820 82dd | 110 959f (0) 976e (0) 96fc (0) 915d (0)\n001 8 0ff2 1c9c 165f 1672 | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 6 44a1 4109 41d9 4bcf | 38 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n003 4 7125 7920 7dd3 7dbb | 12 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n004 5 6967 6fe9 6ea5 6e68 | 11 6831 (0) 6967 (0) 6f5f (0) 6f2d (0)\n005 6 6103 60d7 605a 6337 | 6 6103 (0) 60d7 (0) 605a (0) 6337 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 67aa 67dc | 2 67aa (0) 67dc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","private_key":"73edf61ff541e3a6ba465ffea56c19839af7e9bc3782ff09216905843c204e08","name":"node_66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","services":["streamer"],"enable_msg_events":true,"port":46675},"up":true}},{"node":{"info":{"id":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","name":"node_628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","enode":"enode://753579fc0f9683818e057900626e09327d6610fdbc6996be1b4faea9431977b3c78dd63e7e603523b19dd2b55c8a90b6ea21e91edd926513843de5fc1eea9b26@127.0.0.1:0","enr":"0xf88fb8406e4b52980cff25be487a37763583146103d0312687b7183e3dd02233a6f94b387c1b61ccb793d70ea879dedb92e32c45923debbec85a24bd00f68780acc0da170183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102753579fc0f9683818e057900626e09327d6610fdbc6996be1b4faea9431977b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Yo59ozWe1tnc+6/HWBlm5OCSRcMh7HjKdVh8nLtEaX8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 628e7d\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e883 82dd b2a5 b820 | 110 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n001 6 21a0 3e8e 1672 0ff2 | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 6 41d9 4bcf 4d6b 4d59 | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 7 775e 7125 738c 7920 | 12 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n004 4 6967 6e68 6f2d 6c73 | 11 6831 (0) 6967 (0) 6fe9 (0) 6f5f (0)\n005 3 67aa 67dc 66e7 | 3 67aa (0) 67dc (0) 66e7 (0)\n006 3 6103 60d7 605a | 3 6103 (0) 60d7 (0) 605a (0)\n============ DEPTH: 7 ==========================================\n007 1 6337 | 1 6337 (0)\n008 1 6251 | 1 6251 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","private_key":"83ebb4dfd7e07f53a417d7d2d026d506a6d45dc6ec03f3acc64b473cf238454a","name":"node_628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","services":["streamer"],"enable_msg_events":true,"port":39369},"up":true}},{"node":{"info":{"id":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","name":"node_06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","enode":"enode://299e207d28b61a8754f9056b7c66999601d85c166abf2d5e28b58bb9af5d07ae1191a60f6b7daa7f1db158847cf41042bacd8d65caced5aae6b785279c7db9c9@127.0.0.1:0","enr":"0xf88fb8405c00f8abb44fe6724d6ec81f03c33ed424ef532ff6d7f23711109c46205f12793e95b225e5830489b2b439f04128e4ee2e2aa0732db7eb8c69c53030da7f9b2f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103299e207d28b61a8754f9056b7c66999601d85c166abf2d5e28b58bb9af5d07ae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BmGNgpqKcxepjxpA7PiGThyUxOJwqeTACCKdx8+Te34=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 06618d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b820 b2a5 8505 e54b | 110 a653 (0) a6fb (0) a46d (0) a369 (0)\n001 4 534b 4bcf 7dbb 628e | 70 5cd2 (0) 5db0 (0) 5f00 (0) 5efb (0)\n002 5 2abb 2f32 21a0 3e8e | 32 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n003 5 1c9c 19fa 165f 1672 | 22 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n004 5 0af9 0de3 0c28 0ff2 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n005 4 0067 00c6 03cc 0328 | 5 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n006 3 0438 0451 045b | 3 0438 (0) 0451 (0) 045b (0)\n============ DEPTH: 7 ==========================================\n007 2 0743 07a8 | 2 0743 (0) 07a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","private_key":"8d4e48a151d1f68c567c3be3325aab9baa3b0abb8bf08d65ce6cb448cf056f5b","name":"node_06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","services":["streamer"],"enable_msg_events":true,"port":35915},"up":true}},{"node":{"info":{"id":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","name":"node_f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","enode":"enode://5b2117cf5005122b31d4139c5ecffbfb0b3b5b3ccc04122ecee2b65ddc3b5f365fc02b4df864cce4b6b626a9c76bdee3d791ae0dd8acf96c0844b2a6e5641b39@127.0.0.1:0","enr":"0xf88fb840e2d50d151f647dccd99b24b546d0c033602555711b5e9b696b397c56e0301e34144f5201dc6446c2708545baa267d5ab59974b796a1af49a6cde843af933d35e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035b2117cf5005122b31d4139c5ecffbfb0b3b5b3ccc04122ecee2b65ddc3b5f36","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9FZd0sQowD16jV+th6bdX5KucGUp62FS02+lhOfNvk0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4565d\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7dbb 4bcf 0661 | 146 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n001 6 b820 b2a5 9fa0 9076 | 47 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n002 5 daec d3b0 c620 c1f9 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 ed2d eb98 e854 e883 | 18 e027 (0) e7fa (0) e775 (0) e5ad (0)\n004 3 f925 fbc8 fbf5 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 2 f31c f27f | 3 f31c (0) f2d5 (0) f27f (0)\n006 2 f7ba f773 | 4 f629 (0) f7fa (0) f7ba (0) f773 (0)\n007 3 f528 f5b2 f5dc | 3 f528 (0) f5dc (0) f5b2 (0)\n============ DEPTH: 8 ==========================================\n008 1 f4e0 | 1 f4e0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 f45f | 1 f45f (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","private_key":"b9015ed803b33c63a30a8abe7812408ed9cc2ba7efcdb5fcd69f0a681d123675","name":"node_f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","services":["streamer"],"enable_msg_events":true,"port":39127},"up":true}},{"node":{"info":{"id":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","name":"node_4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","enode":"enode://88c7ac31971ce995e22e0820ae73cd53e1bda565f636bea5b3c0472c44d54a66a23d6143ecad625bef9fb09e3e64da6fd629ead736b184981cb9052a1cb0489f@127.0.0.1:0","enr":"0xf88fb840c74ff09f194ac5d818ba51ea9fd29c00ac3ebd753d02ec50dfe7c1438f754d9c794455cf5ee526e53b257971614e8b756a1a4c0da3fbcac597cbf2044a14e7e20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10388c7ac31971ce995e22e0820ae73cd53e1bda565f636bea5b3c0472c44d54a66","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"S89OtTHV7Esx2Z6DVK8D+XZSTHhYoecEPptwVTJvCVI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4bcf4e\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 82dd c898 e883 f456 | 110 a653 (0) a6fb (0) a46d (0) a369 (0)\n001 6 2abb 314a 179f 1672 | 76 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n002 10 6ea5 6c73 628e 67dc | 32 6831 (0) 6967 (0) 6fe9 (0) 6f5f (0)\n003 2 5823 534b | 15 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n004 6 4636 4646 44a1 4559 | 12 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n005 4 4e5a 4d6b 4d59 4c9e | 5 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n006 3 4990 49cd 49ea | 3 4990 (0) 49cd (0) 49ea (0)\n============ DEPTH: 7 ==========================================\n007 2 4ac7 4a8b | 2 4ac7 (0) 4a8b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","private_key":"4cc4751021f2e7e361f1abe34a0ae098305a4d7cfae9fff4e3d9c198f765536c","name":"node_4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","services":["streamer"],"enable_msg_events":true,"port":37843},"up":true}},{"node":{"info":{"id":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","name":"node_82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","enode":"enode://9e0bd5f9048e54e757f441f6e806f675359f125df0759d69c99dfa05b612264f47f2e4ef3b1e8c33ea12203b3539baa8e8f7112a42c09fba13c8088012abf854@127.0.0.1:0","enr":"0xf88fb840ce5cbe31c864fb919be4b8bbaeb4aac9af3baceddb264f0fc41711cfe79eac031fef6d0c4e5186833885990f4fb8bf788dfde9ec3140e53dd617c1a301f7da460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029e0bd5f9048e54e757f441f6e806f675359f125df0759d69c99dfa05b612264f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gt2Dg4y5griVBe8knTU6IOQ0NG3Xi3HNm4CfcdXBEto=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82dd83\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0fc5 66e7 628e 7125 | 146 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n001 8 daec c898 c1f9 f456 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 6 b820 b2a5 b02b af02 | 27 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n003 5 96fc 9076 9852 9890 | 10 959f (0) 976e (0) 96fc (0) 915d (0)\n004 5 8f21 898d 886a 88a1 | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n005 2 849b 8505 | 2 849b (0) 8505 (0)\n============ DEPTH: 6 ==========================================\n006 1 8025 | 1 8025 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 82f9 | 1 82f9 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","private_key":"40b87f812144699438e8ce3203329a31e5e6fd191ccc6d632b53acd2dabf009a","name":"node_82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","services":["streamer"],"enable_msg_events":true,"port":36651},"up":true}},{"node":{"info":{"id":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","name":"node_7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","enode":"enode://c6f41778e207aa191bfcc7583d517dc276591cb6e4ea45a7f640b9e296d6ac32ed466e046bd8e3cd7213d78408c82594ab0d4f91fff4af306e45e91e25568f08@127.0.0.1:0","enr":"0xf88fb840cd11dd01b07641a3cc440cc6247d249d33f4f5f6f8812ff8f209b221f42611e934dd83397f8ce608353435eff2358217cfcee195e78947e92f7f10ae9c8dface0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c6f41778e207aa191bfcc7583d517dc276591cb6e4ea45a7f640b9e296d6ac32","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fbveujcx4f9DBy+MvYbbFHdh4bYXU+6nAkd02/RpFL0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dbbde\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f456 e54b 8505 82dd | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 8 1672 179f 0328 0661 | 76 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n002 3 524d 4d6b 4bcf | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 9 6ea5 6f2d 6c73 6c4d | 20 6831 (0) 6967 (0) 6fe9 (0) 6f5f (0)\n004 3 738c 7125 775e | 5 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n005 3 7920 7b90 7a60 | 3 7a60 (0) 7b90 (0) 7920 (0)\n006 1 7e04 | 1 7e04 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 2 7dd3 7dc2 | 2 7dd3 (0) 7dc2 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","private_key":"30869970089e876f509073901dbe3a34c332d7a6755999e960da313f0d41bdda","name":"node_7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","services":["streamer"],"enable_msg_events":true,"port":42487},"up":true}},{"node":{"info":{"id":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","name":"node_314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","enode":"enode://2ddf028c09516742c8f18d9dc30575448afbf80f0999e2cccc53671e4b12c97af49c3251151d20ff3c38c6e4885805039f3e31e32101cdb9ccb70596e29e6e97@127.0.0.1:0","enr":"0xf88fb84084eb7ae1c3f66517fa8698e26815ca4ddd8d95653248080c4cf1ae2af93c9ae76806cd1ba9bd6bce2079c1762ba8bc13a96e07869d8fc5fde206d61c694ac4010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032ddf028c09516742c8f18d9dc30575448afbf80f0999e2cccc53671e4b12c97a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MUo1MKXgw31WCRSbOunC4HhXM0a9j848dp666zFybsE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 314a35\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 af02 8505 daec e54b | 110 a369 (0) a34e (0) a653 (0) a6fb (0)\n001 7 534b 41d9 4d6b 4bcf | 70 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n002 6 1c9c 19fa 165f 0c28 | 44 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n003 6 2c79 2f32 2abb 256e | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 6 39d1 3b78 3b88 3efc | 7 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n005 4 35e6 378e 3780 3630 | 4 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n006 3 3237 33b5 3373 | 3 3237 (0) 3373 (0) 33b5 (0)\n============ DEPTH: 7 ==========================================\n007 2 3089 30be | 2 3089 (0) 30be (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","private_key":"65cff60a3a02082e25d44b652a89286c56814d6e8a124c9cd481c53d6bfc7d14","name":"node_314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","services":["streamer"],"enable_msg_events":true,"port":34143},"up":true}},{"node":{"info":{"id":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","name":"node_e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","enode":"enode://2ff0f6983a8df852e410db35700f5eb2e9b6626b555eb6a0f46ed3b1039c11d99e30fa7fb8ef8a5e04f6747539a8fa3b422b0e167e3740bfd0dfc6f05b7811c0@127.0.0.1:0","enr":"0xf88fb84073d5865ea6eef52ccbd4fb0579988b8c89f10c04bf0aab24b530bccf20477019412b8e906f69332ba31a2b366d9cf41dc6b91c1c3dbf0201b5c1815aba93e7990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022ff0f6983a8df852e410db35700f5eb2e9b6626b555eb6a0f46ed3b1039c11d9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6IMPKy99CN8VvTP0soQdAdnWLBYhI0vWroZ0PlI2Dz4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8830f\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 628e 4bcf 4d6b 103b | 146 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n001 4 b820 9890 82dd 8505 | 47 a46d (0) a653 (0) a6fb (0) a369 (0)\n002 5 d3b0 daec c1f9 cc20 | 26 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n003 6 fbf5 fbc8 f773 f456 | 19 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n004 4 e027 e7fa e775 e54b | 8 e027 (0) e7fa (0) e775 (0) e5ad (0)\n005 4 ed2d efea ef07 ee5e | 6 ec52 (0) ed2d (0) ee5e (0) ef1b (0)\n006 1 eb98 | 1 eb98 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 e854 | 1 e854 (0)\n009 1 e8ef | 1 e8ef (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","private_key":"300d395f69d29389b4951f1054ccdecbbb0aa4ee4359e0a42916d279feed61b9","name":"node_e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","services":["streamer"],"enable_msg_events":true,"port":44709},"up":true}},{"node":{"info":{"id":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","name":"node_e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","enode":"enode://88d397dae0a821bb3ade7f8b6934b521491617f1f55ce053be63153915a1d422f16ab186007929b0232d9a7fd420cf692a7df1d9f419a191a1e9e57698485728@127.0.0.1:0","enr":"0xf88fb8405030079ea6a64ac5c86f5eb9955181bb9c23d35cbc28ed8a13410b3c9e9a234928490232594c4773176af76896b5283dffb7979ca1082589e48a45d54473d9e70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10288d397dae0a821bb3ade7f8b6934b521491617f1f55ce053be63153915a1d422","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5UtkPLyV2fXSfsN2DYkraAKYG/q/T5l5Jn1mJZ35gsc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e54b64\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4d6b 7dbb 1672 0661 | 146 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n001 5 b820 9890 9fa0 82dd | 47 a653 (0) a6fb (0) a46d (0) a369 (0)\n002 5 daec d3b0 c898 c1f9 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 fbf5 fbc8 f31c f27f | 19 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n004 7 ed2d ee5e ef1b efea | 10 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e7fa (0) e775 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e5d7 e5ad | 2 e5d7 (0) e5ad (0)\n009 1 e514 | 1 e514 (0)\n010 0 | 0\n011 0 | 0\n012 1 e547 | 1 e547 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","private_key":"727ffbf99e8a4a3259aa56178cd67759e1efcf9d6a0d1bbc5eced5778195a6bb","name":"node_e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","services":["streamer"],"enable_msg_events":true,"port":35117},"up":true}},{"node":{"info":{"id":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","name":"node_850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","enode":"enode://f96b8378f9a6fdb344b192c08fa716f806c81b10d9ff1be769f2f147f0a3e59be1d63e3458c6bb0be3826901cc82855dcb176ea550580ce3c1353f45411effa8@127.0.0.1:0","enr":"0xf88fb840e608377b110a66c37a6402a52005fab9cbbd1293d2faf8ac2f2d11f21c86074e65803f9af2fd8a4652da5a03c3a8f62c56bedc2b504966b9def8bec4d14aa6f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f96b8378f9a6fdb344b192c08fa716f806c81b10d9ff1be769f2f147f0a3e59b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hQV1V31rQgqHq6OIr0geDARML3XPKf+TTa9WdDGKYbo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 850575\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0fc5 0661 314a 7125 | 146 0a00 (0) 0af9 (0) 0b72 (0) 0e5e (0)\n001 5 c620 fbc8 f456 e883 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 9 af02 aeb4 a46d a6fb | 27 a369 (0) a34e (0) a653 (0) a6fb (0)\n003 6 9fa0 9852 9890 9076 | 10 959f (0) 976e (0) 96fc (0) 915d (0)\n004 5 898d 886a 88a1 88fe | 5 898d (0) 886a (0) 88fe (0) 88a1 (0)\n============ DEPTH: 5 ==========================================\n005 3 8025 82f9 82dd | 3 8025 (0) 82f9 (0) 82dd (0)\n006 0 | 0\n007 1 849b | 1 849b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","private_key":"771aa77f7ed2c88cec05f7d2bbe77ca3b3baed77808bcede79d47430b855ef8c","name":"node_850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","services":["streamer"],"enable_msg_events":true,"port":38191},"up":true}},{"node":{"info":{"id":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","name":"node_4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","enode":"enode://65fe4500b12d8a6300f6dfa00c6053c96a116b98d8c08d706534d0b0cd73def015021b00da0ea48952faaf26fb6860612ae6f05dc69e3152a60467c474513524@127.0.0.1:0","enr":"0xf88fb840e4f68b9d9c982c9d702d4e773ac1559d8ef54db673accfcab9b83cf5f16a0d191460f4acfcad1a8c86b72017692073a6ad12e178800fa4dd5c30f7958acfb4530183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10265fe4500b12d8a6300f6dfa00c6053c96a116b98d8c08d706534d0b0cd73def0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TWuTn7ZzOMSElIq5KyzupNS2Ztfgh3NnPNfI+D9JW4k=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d6b93\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c898 e54b e883 8505 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 4 314a 2abb 0328 179f | 76 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n002 7 67dc 628e 6ea5 775e | 32 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n003 2 5823 534b | 15 5f00 (0) 5efb (0) 5db0 (0) 5cd2 (0)\n004 5 4559 44a1 4646 4636 | 12 47bf (0) 4782 (0) 46fe (0) 4646 (0)\n005 6 4bcf 4ac7 4a8b 4990 | 6 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n006 1 4e5a | 1 4e5a (0)\n007 1 4c9e | 1 4c9e (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 4d10 | 1 4d10 (0)\n010 1 4d59 | 1 4d59 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","private_key":"ec9be85f4525323e3e5fba6d38fddd6e2c490c51f04e40824f612945338ff314","name":"node_4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","services":["streamer"],"enable_msg_events":true,"port":33119},"up":true}},{"node":{"info":{"id":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","name":"node_9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","enode":"enode://74dcd08206970995c262f6fdc36f05eb33b2efd6a76f8dad6d50f4c990fdfff532b14e3a48ae9fdad2e8969bb28c472b5fa4e037266ed8ab1b223d351b00c58c@127.0.0.1:0","enr":"0xf88fb840e8a03ba6a2bd809293a3aa9fc2cd67a032f701eda802d05b9fed7988cd354f6228072d95e1279cfdbb332a0b3f7b6bcc772dd13ef98a3cab034c0beef16d15840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10274dcd08206970995c262f6fdc36f05eb33b2efd6a76f8dad6d50f4c990fdfff5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"n6AhXpgNyQffTMR6tJN/NlJ9ePmDdJMBb9T8UeYXKZw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9fa021\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2abb 21a0 1672 179f | 146 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n001 7 fbc8 f45f f456 f773 | 63 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n002 8 af02 a6fb a34e b2a5 | 27 a369 (0) a34e (0) a46d (0) a653 (0)\n003 5 8505 849b 8025 82f9 | 10 898d (0) 886a (0) 88fe (0) 88a1 (0)\n004 6 9076 90a8 915d 959f | 6 959f (0) 976e (0) 96fc (0) 915d (0)\n============ DEPTH: 5 ==========================================\n005 2 9852 9890 | 2 9852 (0) 9890 (0)\n006 1 9d0f | 1 9d0f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","private_key":"2151ae4bd0c0dbe72d08c6cc2dc2d42d45d5929d158953f98802508bcc7b6abc","name":"node_9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","services":["streamer"],"enable_msg_events":true,"port":42793},"up":true}},{"node":{"info":{"id":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","name":"node_179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","enode":"enode://45316c9ce2f7458c2170694fa0458bb6bc612e0fe7e98d5776eaa2deb243090f2112f86d6378e3fbf2bc3581294561eba34c820855dde3c62fbbd0fb00d464bc@127.0.0.1:0","enr":"0xf88fb840ba7939a13853c684f0fbba8aabd321c8c18392c860e899d661b8ae62334778bc3a1cc6bd039962763203c07b6f86aa8b247af81fb2c72e4b1e9de83cd2f02d3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10245316c9ce2f7458c2170694fa0458bb6bc612e0fe7e98d5776eaa2deb243090f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F58h0uBCG4BW7pomC8CYW/pkpSo20Kj7zk4D8xINHWU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 179f21\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c1f9 c898 daec fbc8 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 3 7dbb 4bcf 4d6b | 70 6fe9 (0) 6f5f (0) 6f2d (0) 6e05 (0)\n002 3 3b88 21a0 2abb | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 6 0ff2 0c28 00c6 0328 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n004 3 19fa 1c9c 1c8a | 10 1f67 (0) 1f85 (0) 1e2a (0) 1c47 (0)\n005 3 13d6 11d4 103b | 3 13d6 (0) 11d4 (0) 103b (0)\n006 4 14df 1400 1436 154b | 4 14df (0) 1400 (0) 1436 (0) 154b (0)\n007 2 165f 1672 | 2 165f (0) 1672 (0)\n============ DEPTH: 8 ==========================================\n008 1 1704 | 1 1704 (0)\n009 1 17db | 1 17db (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","private_key":"6fc4e9abe82ac6f220359e1a24c752a8538ca3d77fa2a44721ec006e4dac96c8","name":"node_179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","services":["streamer"],"enable_msg_events":true,"port":46579},"up":true}},{"node":{"info":{"id":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","name":"node_2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","enode":"enode://079b150d46590810199925ef6914c54c274297aa5ddbaec77e0e1881fb11e67c597e4310d3fa518e919ba3530c7863fb75e67892ba8a3ee5385446aded8bd46c@127.0.0.1:0","enr":"0xf88fb840e4c34bba2889adb60fd7f03da39f9172c73803337915b8a91a787ecd1e15f7ac32b8c5ebc60e9bc30a9f10e582b6c56955e330b874275d8f785b67b3d2b7ad7a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102079b150d46590810199925ef6914c54c274297aa5ddbaec77e0e1881fb11e67c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KruTi4iaLrc1E0RimFpWBWvkjxibW4nSO2U4ZMdkJ/Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2abb93\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e883 c1f9 af02 9fa0 | 110 d7ac (0) d640 (0) d3b0 (0) d299 (0)\n001 6 7dbb 6967 66e7 534b | 70 6c4d (0) 6c73 (0) 6fe9 (0) 6f5f (0)\n002 6 0c28 0661 045b 19fa | 44 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n003 5 3b88 3e8e 3ec5 3efc | 17 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n004 3 256e 24b8 21a0 | 6 24b8 (0) 256e (0) 20ae (0) 2101 (0)\n005 5 2d36 2c79 2c38 2ccf | 5 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n006 1 2995 | 1 2995 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 2a0a | 1 2a0a (0)\n009 0 | 0\n010 1 2a97 | 1 2a97 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","private_key":"5f2d2d97cebeab930620649942a1d9ff3fb18cfdfe20065c115c21fcc1736417","name":"node_2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","services":["streamer"],"enable_msg_events":true,"port":46385},"up":true}},{"node":{"info":{"id":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","name":"node_16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","enode":"enode://e24763610f818132ec0e495f6371f3e94f8822100ee5956998fc7585d7e09a222bbdb9a02937e628ca33f6902fe511b8711405899f5cddfa93a1035ac09af4b8@127.0.0.1:0","enr":"0xf88fb840df13ef5dcc1c0cb21d197b2cdfd5d86b8bec8a3882f2c8ba0166a590276699446bccccceac9b5ccb0bcf42d3f59ee925945d58295588d35de7077b7910c5401f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e24763610f818132ec0e495f6371f3e94f8822100ee5956998fc7585d7e09a22","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FnJeMYMiNTvvwvKroRLwmEvAEYIbsWyY4s2LOc1irqE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 16725e\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e54b c1f9 9fa0 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 8 4bcf 6831 66e7 628e | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 3 3b88 21a0 2abb | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 4 0c28 045b 0661 0328 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n004 2 1c9c 19fa | 10 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n005 3 13d6 103b 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 4 14df 1400 1436 154b | 4 14df (0) 1400 (0) 1436 (0) 154b (0)\n============ DEPTH: 7 ==========================================\n007 3 1704 17db 179f | 3 1704 (0) 17db (0) 179f (0)\n008 0 | 0\n009 0 | 0\n010 1 165f | 1 165f (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","private_key":"0e22a97f0fa9df60515e999107287dd670bbfba6496b95e7419f1ae24ac1430f","name":"node_16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","services":["streamer"],"enable_msg_events":true,"port":42487},"up":true}},{"node":{"info":{"id":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","name":"node_03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","enode":"enode://3960e88898c09e1856391d4ff8b0e413551efaa9d41b29dbe1d131c4c23d0f3debf2451b0019c3cd1a3cced4e5b0ead9dd73ca011cf6f319d3a6440623ce12c3@127.0.0.1:0","enr":"0xf88fb8403059f7dae44ef458aafb69f9b519e35847da261c7fc2415beb3027871fc5f55b0a37db22d9d2e503fae99b8dce9317e0aab1999b6dc73f581ac8fdabbc40cb7e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033960e88898c09e1856391d4ff8b0e413551efaa9d41b29dbe1d131c4c23d0f3d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AyheBmVwMneP7/C0OCjJZNv53mafYxca61h6oaH6zAo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 03285e\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c1f9 f31c | 110 d7ac (0) d640 (0) d3b0 (0) d299 (0)\n001 7 7dbb 7dc2 628e 6251 | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 4 3e8e 3ec5 3b88 21a0 | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 4 19fa 179f 165f 1672 | 22 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n004 6 0a00 0af9 0c28 0de3 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n005 4 045b 0438 07a8 0661 | 6 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n006 2 0067 00c6 | 2 0067 (0) 00c6 (0)\n============ DEPTH: 7 ==========================================\n007 1 02d8 | 1 02d8 (0)\n008 1 03cc | 1 03cc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","private_key":"eb65890ae3df82c2a8355c7b7a50e258abb0c833e93aacc2a5dbd51ee15664d4","name":"node_03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","services":["streamer"],"enable_msg_events":true,"port":37579},"up":true}},{"node":{"info":{"id":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","name":"node_21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","enode":"enode://af8cb83192683c7397ab76929a7a6ebd42a34f250c74baa77449624ec14ff1014486c342f70c70454d60192f7a52ad16cab58958b752e01feea05491ad7b7915@127.0.0.1:0","enr":"0xf88fb84060c1ac919d32f84d9c226ded0dc92ed0cb32034912167e68663f93a3644a8e6b1235368600a6006c4a63078fec8299adecdc0afc9a016fa9eace65a141581d610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103af8cb83192683c7397ab76929a7a6ebd42a34f250c74baa77449624ec14ff101","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IaBE53K3yVX+Sm+3w6miDpXUi3/WuVGHQXgvBPXx9cI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 21a044\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 af02 9fa0 c1f9 ed2d | 110 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n001 10 534b 6967 6c73 6ea5 | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 8 19fa 1436 179f 1672 | 44 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n003 6 3ec5 3efc 3e8e 3b88 | 17 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n004 3 2f32 2c79 2abb | 9 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 20ae | 1 20ae (0)\n008 2 217f 2101 | 2 217f (0) 2101 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","private_key":"e8c622b14e0b37df0fd9611ed22903fd62f8b8823866163156b933c17f3fc9b3","name":"node_21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","services":["streamer"],"enable_msg_events":true,"port":40127},"up":true}},{"node":{"info":{"id":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","name":"node_f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","enode":"enode://2d511a834e682276a6f3a8650f3728bec644ab1efd34d504e37aeb317f3a3ee4c0ee0db1c4fa4fd0db73a1da15fef34b527a2587be73d68b35da971c09e6ad5e@127.0.0.1:0","enr":"0xf88fb840d947ce6d973f74d7e2c06e2aa7b0511cf2a30fb7f6565a76dd01220c3071d124635ae79845e4bf315d6a2e0e07acaf661c378ed6998c33219c8cf3158949cc840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022d511a834e682276a6f3a8650f3728bec644ab1efd34d504e37aeb317f3a3ee4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8xzHROqSH+6DZMUmmxzn7GtfDAy7aIXvv2At5bNvYWk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f31cc7\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 775e 0328 21a0 | 146 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n001 6 b95d af02 82dd 849b | 47 b65e (0) b626 (0) b7ca (0) b5b2 (0)\n002 6 d1d7 daec c898 cc20 | 26 d640 (0) d7ac (0) d3b0 (0) d299 (0)\n003 8 e027 e54b e7fa ee5e | 18 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n004 5 f925 fbc8 fbf5 ff36 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 9 f4e0 f45f f456 f528 | 10 f528 (0) f5b2 (0) f5dc (0) f4e0 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 f2d5 f27f | 2 f2d5 (0) f27f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","private_key":"7b96931ae2b82181dbbf1ce714ef7dcd8a73ee4ba37b6cd3e5a38c185179b50a","name":"node_f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","services":["streamer"],"enable_msg_events":true,"port":43987},"up":true}},{"node":{"info":{"id":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","name":"node_c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","enode":"enode://3e653640cb83949eb33046e1f53f3cea2dfc41dda2b5b820f8f519198a9ef5be60bb4feb02bcab43abc24d6283d318be1d4e79ff8530dfe9c9a0cd3b0583460f@127.0.0.1:0","enr":"0xf88fb84070b2190039d9877fc8133fa67fa8c4ce0339ca41fe322a61637d2f6a0501d7d41dfbf0f867138735e708a26fcc2df5419d72eb535ba75a4ab36df55305b825e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033e653640cb83949eb33046e1f53f3cea2dfc41dda2b5b820f8f519198a9ef5be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wfno4dUJ/r3x8me7IndB5RNCAEii5mmsnu9LBaKc8Qs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c1f9e8\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 738c 6251 179f 1672 | 146 5b63 (0) 58ed (0) 5823 (0) 5db0 (0)\n001 6 b95d af02 82dd 849b | 47 b65e (0) b626 (0) b7ca (0) b5b2 (0)\n002 14 e883 efea ee5e ed2d | 37 ec52 (0) ed2d (0) ef07 (0) ef1b (0)\n003 4 d1d7 d3b0 d887 daec | 11 df1e (0) d863 (0) d887 (0) db6a (0)\n004 3 cc20 ca04 c898 | 6 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n============ DEPTH: 5 ==========================================\n005 7 c59e c49c c441 c43f | 7 c59e (0) c49c (0) c441 (0) c43f (0)\n006 1 c26f | 1 c26f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","private_key":"d1af3c939ccb6fbd80b3e800e90fc304fe1a95e5093d4b8a8014d2c2bcc614ef","name":"node_c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","services":["streamer"],"enable_msg_events":true,"port":38941},"up":true}},{"node":{"info":{"id":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","name":"node_f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","enode":"enode://ebdf19a2508ec342f90a571ea57e25d9fe086842827fb7122f9040f247be1782a6f73e3830e0d4a6d15fb9ba45deaefdd93c4c7ff95d9062fc9fa64149f98e39@127.0.0.1:0","enr":"0xf88fb84074708297591a962a8f10e1c5023c61300d115facd722246df478257dcb61eab468084b00d42034c7472dc28fa7dd04a6e8c31f4478bfb790e7d6a45f9a011a6f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ebdf19a2508ec342f90a571ea57e25d9fe086842827fb7122f9040f247be1782","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"93O4Pxod4qtmYO2wt2XPzOxneAYe4lxahPloYlaG72A=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f773b8\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3ec5 045b 7dc2 | 146 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n001 5 b95d af02 849b 9fa0 | 47 b626 (0) b65e (0) b7ca (0) b5b2 (0)\n002 7 daec d299 d1d7 c898 | 26 d7ac (0) d640 (0) d3b0 (0) d299 (0)\n003 8 ed2d ee5e eb98 e854 | 18 ec52 (0) ed2d (0) ef07 (0) ef1b (0)\n004 4 fe21 f925 fbf5 fbc8 | 6 fe31 (0) fe21 (0) ff36 (0) f925 (0)\n005 3 f2d5 f27f f31c | 3 f2d5 (0) f27f (0) f31c (0)\n006 6 f528 f5b2 f5dc f4e0 | 6 f528 (0) f5b2 (0) f5dc (0) f4e0 (0)\n007 1 f629 | 1 f629 (0)\n============ DEPTH: 8 ==========================================\n008 2 f7fa f7ba | 2 f7fa (0) f7ba (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","private_key":"e898408c6a69bdbbb2b3d144d09beeb11db724b09c3b43d166192d7af9c168a9","name":"node_f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","services":["streamer"],"enable_msg_events":true,"port":37133},"up":true}},{"node":{"info":{"id":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","name":"node_7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","enode":"enode://ce63a767ab6f112649325e6862410a7e4788fec965925e83abcbc055deca8a04c3beb8619a415ae9a767691bbec01ec218ee44b8a1afd11a06ccbdd63e64d135@127.0.0.1:0","enr":"0xf88fb8400698b27f1b516079af94fb615edaac2e5afe70b2961bcf8525534071441b3b0409021a48a66ad2e700e4d9d46ee752d9aebb9a55dbcac1c6aa072024a7139b260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ce63a767ab6f112649325e6862410a7e4788fec965925e83abcbc055deca8a04","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fcKpVz8lPzYu8bIbv8wUSxGm/rxYqjxEMCJBYOn6c4w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dc2a9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9890 f45f f773 | 110 b502 (0) b5b2 (0) b7ca (0) b65e (0)\n001 3 1672 0328 045b | 76 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n002 7 524d 534b 44a1 4559 | 38 58ed (0) 5823 (0) 5b63 (0) 5f00 (0)\n003 8 6c4d 6ea5 6f2d 6831 | 20 6c73 (0) 6c4d (0) 6fe9 (0) 6f5f (0)\n004 5 775e 77d2 7125 7290 | 5 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n005 3 7a60 7b90 7920 | 3 7a60 (0) 7b90 (0) 7920 (0)\n006 1 7e04 | 1 7e04 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 7dbb | 1 7dbb (0)\n010 0 | 0\n011 1 7dd3 | 1 7dd3 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","private_key":"202bed44b0e5747d57db0077e83d62aa8814b4a640a338a0b0e200d4231f69dc","name":"node_7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","services":["streamer"],"enable_msg_events":true,"port":38091},"up":true}},{"node":{"info":{"id":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","name":"node_045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","enode":"enode://a8da5558c682d2a891ea880bbed34a14cb1087c5fe6ee20c66210ab1eac9fd69dc13a6fc924f84bb35b5dfb838f499895a1226efd887e3e0ac1e76b92ea358b8@127.0.0.1:0","enr":"0xf88fb840e00bd27f128a7ceab96f9085ff60dba7842de4f23816bc8e957a96a3d4807a3b209f5c0675fe420cd322fe7bcc131344e5aae695d4a6b95c0224634bcf102c0c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a8da5558c682d2a891ea880bbed34a14cb1087c5fe6ee20c66210ab1eac9fd69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BFuo2kZB2j8LgFi7DZ2Kr7uBSW3ByuKj/ZwDmn4cr7Y=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 045ba8\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c1f9 f773 9890 | 110 ec52 (0) ed2d (0) ef1b (0) ef07 (0)\n001 2 775e 7dc2 | 70 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n002 6 3b88 3efc 3ec5 314a | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 4 1672 165f 179f 19fa | 22 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n004 4 0ff2 0fc5 0de3 0c28 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n005 4 0328 02d8 0067 00c6 | 5 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n006 2 07a8 0661 | 3 0743 (0) 07a8 (0) 0661 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 0438 | 1 0438 (0)\n010 0 | 0\n011 0 | 0\n012 1 0451 | 1 0451 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","private_key":"be4604105acf932a56aeb47b672aa90728f8e2a6b5e4eac4c582dd5646f61358","name":"node_045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","services":["streamer"],"enable_msg_events":true,"port":37847},"up":true}},{"node":{"info":{"id":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","name":"node_9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","enode":"enode://9ca38a60e6b0d6f83aca233c9b27c0817b0d3ab7644e05fc12cd158726f9a752b4904052a3ec36b45ed9cd04fa8563b84a94d384ce66831e18f71cd74f9c6951@127.0.0.1:0","enr":"0xf88fb840d0e03834031b00b0b1497f467bf9bca7abd4b7e83a8a6534025d2f58b88220556789b327681ded4921f921cd6711f0f7b181b548c87ffefc722fb53c5fdb7f210183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039ca38a60e6b0d6f83aca233c9b27c0817b0d3ab7644e05fc12cd158726f9a752","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mJDm67LG+ae+xMJ3jgd+NxDOOvNW+CrptNMkgy0Vnvc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9890e6\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7dc2 775e 045b | 146 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n001 7 c1f9 e54b e883 fbc8 | 63 ec52 (0) ed2d (0) ef1b (0) ef07 (0)\n002 7 af02 a34e b95d b897 | 27 b626 (0) b65e (0) b7ca (0) b5b2 (0)\n003 3 8505 849b 82dd | 10 898d (0) 886a (0) 88fe (0) 88a1 (0)\n004 5 9076 90a8 959f 976e | 6 959f (0) 976e (0) 96fc (0) 915d (0)\n============ DEPTH: 5 ==========================================\n005 2 9d0f 9fa0 | 2 9d0f (0) 9fa0 (0)\n006 0 | 0\n007 0 | 0\n008 1 9852 | 1 9852 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","private_key":"91c1cd51e3963ac4ebcb1fe6e859426d29a1872f98d56582b779f77a16d76109","name":"node_9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","services":["streamer"],"enable_msg_events":true,"port":36407},"up":true}},{"node":{"info":{"id":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","name":"node_775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","enode":"enode://0fbe2eb4516d803819afa51e4a2f9d86b0e2500f1f9c664c51c812be957a1eb071e0ff91c18545685b7c8d58366451323dfd6e919071e515387c9a9be992b424@127.0.0.1:0","enr":"0xf88fb8407865c59fc952191a2f0320a38291d0936783b994a63bb99bcbbc58fadc871a32638de097c22553f495619842efee63e70aa5550fc1bf656088bd1938df45ed5d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020fbe2eb4516d803819afa51e4a2f9d86b0e2500f1f9c664c51c812be957a1eb0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d1575QLfj9k4z5xC7k+sM+RgpLaZK57+uNwf993lxA8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 775e7b\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f31c 9890 | 110 ec52 (0) ed2d (0) ef07 (0) ef1b (0)\n001 3 045b 1672 19fa | 76 2f32 (0) 2d36 (0) 2ccf (0) 2c38 (0)\n002 5 534b 524d 4bcf 4c9e | 38 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n003 9 6ecb 6ea5 6c4d 6c73 | 20 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n004 6 7b90 7920 7e04 7dc2 | 7 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n============ DEPTH: 5 ==========================================\n005 3 7125 7290 738c | 3 7125 (0) 7290 (0) 738c (0)\n006 0 | 0\n007 0 | 0\n008 1 77d2 | 1 77d2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","private_key":"1d0023ab98fa043da972badeee9fd4d8df9514307a8158fdddee5c7ba1df9405","name":"node_775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","services":["streamer"],"enable_msg_events":true,"port":38817},"up":true}},{"node":{"info":{"id":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","name":"node_738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","enode":"enode://cda9d251eca9ce01ba41a3c17fa3b1f665bd822176bb5e8713e9865c8aa07e087f75d33c65c897484f96471c8877a32f746463e4fb55a0bb3d2ec550abbf66d8@127.0.0.1:0","enr":"0xf88fb8406c67c864c9f890ffca30545b73befcd0c86f9fd8ad5e355d00b6a3c631ebdab07b4d54f271fd817f63f621d48593488c298ce9abf52c8ecdc08d65dbf149c5070183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cda9d251eca9ce01ba41a3c17fa3b1f665bd822176bb5e8713e9865c8aa07e08","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c4wtQkWJZdA8j58FXq8OPt89+ipN4KBI7AW3jnt2XJA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 738c2d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 af02 b897 849b c1f9 | 110 915d (0) 90a8 (0) 9076 (0) 959f (0)\n001 3 21a0 1672 19fa | 76 2f32 (0) 2d36 (0) 2ccf (0) 2c38 (0)\n002 6 524d 44a1 4559 4bcf | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 9 6c73 6c4d 6ea5 6831 | 20 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n004 6 7920 7b90 7e04 7dbb | 7 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n005 2 77d2 775e | 2 77d2 (0) 775e (0)\n============ DEPTH: 6 ==========================================\n006 1 7125 | 1 7125 (0)\n007 1 7290 | 1 7290 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","private_key":"728881169692d835251307412b70e5bf5bab2e025d4075c0571eb4575cd8fa0a","name":"node_738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","services":["streamer"],"enable_msg_events":true,"port":44907},"up":true}},{"node":{"info":{"id":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","name":"node_e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","enode":"enode://f4feccd03c0ab9c061130b9bc469d72e44850b40c65c1dfca65ebd585d1ff154419ac9cae4b7253273128994742c14550d13d278cddc876adbe481e1a8acc07d@127.0.0.1:0","enr":"0xf88fb840c5269e2a1ffb34a29af3d3688ea0843b35546e0313938addaccbde1f97c82c823c987f0b038109c00a1a3552cef7c3dcdd95180fbe5ed39821c257e0a378f34d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f4feccd03c0ab9c061130b9bc469d72e44850b40c65c1dfca65ebd585d1ff154","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5/pxEq3HsCPdWWXmICdxIlQhU/h+r13urMilHxd4unc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e7fa71\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 3efc 19fa 67dc 738c | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 4 849b b897 b95d af02 | 47 915d (0) 90a8 (0) 9076 (0) 959f (0)\n002 6 db6a daec d299 d1d7 | 26 df1e (0) d887 (0) d863 (0) db6a (0)\n003 3 f31c f528 f45f | 19 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n004 7 eb98 e854 e8ef e883 | 10 eb98 (0) e854 (0) e8ef (0) e883 (0)\n005 1 e027 | 1 e027 (0)\n============ DEPTH: 6 ==========================================\n006 5 e5d7 e5ad e514 e547 | 5 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n007 0 | 0\n008 1 e775 | 1 e775 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","private_key":"3698971ede47de5ef29ce2ab0eb433184d7570578147e4189713e90a2cfc37a6","name":"node_e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","services":["streamer"],"enable_msg_events":true,"port":44579},"up":true}},{"node":{"info":{"id":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","name":"node_f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","enode":"enode://dbf1445ea421e785c6e095596b2a52a7179cd19f387200d9c0e855c53419fefcee80384b81636c5d042ef9bbebaaa11d1b32df623a942e01ab10692f3db30324@127.0.0.1:0","enr":"0xf88fb840946cc04d7fc58d61080fd4bb13dd8e38ec6b5e85d92296892845774c4a0a3b496587cd1807eda5a924c4eb9a6d9377f0ff6c65b98f0d35e0b8cebeb91c0c49350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102dbf1445ea421e785c6e095596b2a52a7179cd19f387200d9c0e855c53419fefc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9F8fLlnpR+BPoVvPh/hy721ztz93jhLR+biTDqFm7vw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f45f1f\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7dc2 738c 67dc 3ec5 | 146 4109 (0) 41d9 (0) 46fe (0) 461c (0)\n001 10 82dd 849b 96fc 9fa0 | 47 915d (0) 90a8 (0) 9076 (0) 959f (0)\n002 5 daec d1d7 d299 c620 | 26 df1e (0) d863 (0) d887 (0) db6a (0)\n003 5 ee5e eb98 e027 e775 | 18 eb98 (0) e854 (0) e8ef (0) e883 (0)\n004 4 fe21 fbf5 fbc8 f925 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 2 f31c f27f | 3 f2d5 (0) f27f (0) f31c (0)\n006 2 f7ba f773 | 4 f629 (0) f7fa (0) f7ba (0) f773 (0)\n007 3 f528 f5dc f5b2 | 3 f528 (0) f5b2 (0) f5dc (0)\n============ DEPTH: 8 ==========================================\n008 1 f4e0 | 1 f4e0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 f456 | 1 f456 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","private_key":"dbee637d6a6f6facfb47a418c9c1b36a97b04592930833d23aba31c3ca7d5c3d","name":"node_f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","services":["streamer"],"enable_msg_events":true,"port":34023},"up":true}},{"node":{"info":{"id":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","name":"node_19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","enode":"enode://f6f1250fa9e6af3e6fd9195d9f8f7c0608e1afc6f538eecc930b507ee1225cac227a89b3bf1012473ba75ab38aa7a4147f2696b9f562aeda5bdd0ad29550f285@127.0.0.1:0","enr":"0xf88fb840d2cc7d831dfc47bb778b496762213f2d10d8f52b0403aff469b5adf2362312877560ab18951eae9326f58eeba05ce563d4e39a48953e8184de4f0f55d4447d260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f6f1250fa9e6af3e6fd9195d9f8f7c0608e1afc6f538eecc930b507ee1225cac","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GfqviR62pxaQLsKdIB3CCU7kdKz/GIrob6+XYGdLLTc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 19faaf\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e7fa f45f | 110 959f (0) 976e (0) 96fc (0) 915d (0)\n001 4 524d 775e 738c 67dc | 70 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n002 5 2abb 21a0 314a 3ec5 | 32 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n003 4 0c28 0328 0661 045b | 22 0b72 (0) 0a00 (0) 0af9 (0) 0fc5 (0)\n004 10 11d4 103b 13d6 154b | 12 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n005 3 1f85 1c8a 1c9c | 6 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n============ DEPTH: 6 ==========================================\n006 2 1a2a 1b83 | 2 1a2a (0) 1b83 (0)\n007 1 18f6 | 1 18f6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","private_key":"05c69a8793e77331075909934a1e61ac9f380584e32a35ecc8f42887d20cb77a","name":"node_19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","services":["streamer"],"enable_msg_events":true,"port":35641},"up":true}},{"node":{"info":{"id":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","name":"node_67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","enode":"enode://0f351aaf6a4b09eb918bb712e8a79718d083d4214c2406c36f0074d8ad70802689f53f164b38cb9e83e59edb887df1b27e57e48214a7070b32cdc903da0cfd38@127.0.0.1:0","enr":"0xf88fb8404bcca6e121f7562863b5b6ac375f6e953cdb6ab0c36f265ef3366ba7eefdf7ef01ad1990f3c942767f70f2e5d5887ffccb367ad0e344b78133814537196687920183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f351aaf6a4b09eb918bb712e8a79718d083d4214c2406c36f0074d8ad708026","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z9z9IezjC0Gjm8VcCYb8qPQBuzrLqCGWlRnwnQkz6L0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67dcfd\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e7fa f45f af02 | 110 915d (0) 90a8 (0) 9076 (0) 959f (0)\n001 3 21a0 0328 19fa | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 5 524d 44a1 4bcf 4d6b | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 7 7920 7e04 7dbb 7dc2 | 12 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n004 6 6c73 6c4d 6e68 6ea5 | 11 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n005 5 6103 605a 6337 628e | 6 6103 (0) 60d7 (0) 605a (0) 6337 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 66e7 | 1 66e7 (0)\n008 0 | 0\n009 1 67aa | 1 67aa (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","private_key":"9f85db9ae6c9cd4db65d7ccb16a9d89efce6ec7d02aac8d35721d5a94ef55f76","name":"node_67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","services":["streamer"],"enable_msg_events":true,"port":45525},"up":true}},{"node":{"info":{"id":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","name":"node_af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","enode":"enode://6b4c01daeddfe0f12d5f3bf6f1e60b261982605a1312d4ddacaa9f6a761f8d4da61c42c09410ac2eff9ab2f5b4a650fc3b92480df5822f85f07f632bc7ee2fd2@127.0.0.1:0","enr":"0xf88fb840c68f36e51ad8efcb6e966d5d8b2a31e1b13e6da82559ded1950420552c3f7c4770459222d11e203f7a841ae5148f9d021adbd26d94a04210def38224db50977c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026b4c01daeddfe0f12d5f3bf6f1e60b261982605a1312d4ddacaa9f6a761f8d4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rwK10QezoX9TnH+QIOvnQyJDRjTnDEIKf1Z3brXZ23M=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: af02b5\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0c28 21a0 2abb 314a | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 6 c1f9 f31c f45f f773 | 63 df1e (0) d887 (0) d863 (0) db6a (0)\n002 8 96fc 9076 9fa0 9890 | 20 959f (0) 976e (0) 96fc (0) 915d (0)\n003 6 b502 b2a5 b2b5 b897 | 17 b7ca (0) b626 (0) b65e (0) b5b2 (0)\n004 5 a369 a34e a46d a653 | 5 a369 (0) a34e (0) a46d (0) a653 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 ac4d ad98 | 2 ac4d (0) ad98 (0)\n007 2 ae2b aeb4 | 2 ae2b (0) aeb4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","private_key":"272d73cf1639238294e76d97933c731ba4d307d8b4551361e31c99a5548b352c","name":"node_af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","services":["streamer"],"enable_msg_events":true,"port":34209},"up":true}},{"node":{"info":{"id":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","name":"node_6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","enode":"enode://aacecc9f59aaf5f89dccbc0f54658dc28b0c01036b15e949465c69469611f86d685911890629199edbcc30c5f8c9de080fa95cdfc4bd9e4ba48ca6572b425efc@127.0.0.1:0","enr":"0xf88fb840466f1c17c93f63d6256f50ab183789dcb5f940f2f5965173b02e3411c452bf525d835c457a1e62bbb60313212f47c91f20e1042e0ec85130d9872724cd47b7890183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102aacecc9f59aaf5f89dccbc0f54658dc28b0c01036b15e949465c69469611f86d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YlHpVARIcmpgFpnvTNGeUMlpp0baJyKJZzOM3AnWKL8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6251e9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ee5e daec d1d7 c1f9 | 110 df1e (0) d863 (0) d887 (0) db6a (0)\n001 3 0328 21a0 3efc | 76 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n002 3 44a1 4c9e 524d | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 7 7920 7dc2 7dbb 7e04 | 12 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n004 6 6f2d 6e68 6c73 6c4d | 11 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n005 3 66e7 67aa 67dc | 3 66e7 (0) 67aa (0) 67dc (0)\n006 3 6103 60d7 605a | 3 6103 (0) 60d7 (0) 605a (0)\n============ DEPTH: 7 ==========================================\n007 1 6337 | 1 6337 (0)\n008 1 628e | 1 628e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","private_key":"60256936fed4be723c1215b22d031aac3b557568a1f9ad98436a946002f6ceb1","name":"node_6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","services":["streamer"],"enable_msg_events":true,"port":42317},"up":true}},{"node":{"info":{"id":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","name":"node_3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","enode":"enode://c250393ff34081bb09b6ee97df2aa2fe93d7335b4623376a0ede17dd046719e32496e4a67a7e160efda5985e2d384b75b04416aaa0b99627c1fc87ba118e3033@127.0.0.1:0","enr":"0xf88fb840696ee67e59754db968f1147865e6fefc0faf7d85b54e7bcefbfa391263921be65b031de9a59d4b9285fea97cbdbdbfe81217ed0070911cf050644c3c4d0b2d590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c250393ff34081bb09b6ee97df2aa2fe93d7335b4623376a0ede17dd046719e3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PvxLEgs+7qwYa/OkzULrjGR/ftsIwj7mQ+K+ydcsW+0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3efc4b\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e7fa f45f 849b af02 | 110 df1e (0) d887 (0) d863 (0) db6a (0)\n001 4 4c9e 524d 6ea5 6251 | 70 4109 (0) 41d9 (0) 46fe (0) 4646 (0)\n002 4 1c8a 19fa 045b 0c28 | 44 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n003 5 21a0 256e 24b8 2f32 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 4 314a 33b5 3780 378e | 10 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n005 2 3b78 3b88 | 3 39d1 (0) 3b78 (0) 3b88 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 3f94 | 1 3f94 (0)\n008 0 | 0\n009 1 3e8e | 1 3e8e (0)\n010 1 3ec5 | 1 3ec5 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","private_key":"c5e74524cfda7833835e2f15a5bdb1a551e63bf87e2ba94faf778776acaa422e","name":"node_3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","services":["streamer"],"enable_msg_events":true,"port":44145},"up":true}},{"node":{"info":{"id":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","name":"node_6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","enode":"enode://f87232a3077f74f8aadead28608baee93a2b0f196b7b40dbba13f3f3b68381bbe474b527aba8bf8df37c35ec861c9ca430a6fb1fd568aaf8ecc439e4638888bd@127.0.0.1:0","enr":"0xf88fb840e62f5938f4645beb16ccd0ff2cda19b29599be7deb95ca52b1e6c0cfe5c5d94742d1407950829383b339174f1b9927df3bda8368d7ac143d0fbc8e1e15290dd90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f87232a3077f74f8aadead28608baee93a2b0f196b7b40dbba13f3f3b68381bb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bqUftuR4PzUdu/pHtQjHjHMjPrqtpAnftVRGIX+SxL0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ea51f\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 af02 b95d b897 | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 3 0c28 21a0 3efc | 76 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n002 5 524d 44a1 4bcf 4d6b | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 6 775e 738c 7920 7dbb | 12 7a60 (0) 7b90 (0) 7920 (0) 7dbb (0)\n004 4 60d7 66e7 67aa 67dc | 9 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n005 2 6831 6967 | 2 6831 (0) 6967 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 3 6fe9 6f5f 6f2d | 3 6fe9 (0) 6f5f (0) 6f2d (0)\n============ DEPTH: 8 ==========================================\n008 2 6e05 6e68 | 2 6e05 (0) 6e68 (0)\n009 1 6ecb | 1 6ecb (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","private_key":"ed77945ec41ca5949c86e0e85e2dcc36e3334a85b705187ec4227bcdb3122ea8","name":"node_6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","services":["streamer"],"enable_msg_events":true,"port":46181},"up":true}},{"node":{"info":{"id":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","name":"node_0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","enode":"enode://bec2d78f8d965930c57e3156c95b56aedc58439ffffea7b36857dcdfe54089c9cee8b61b907fcca85cbea54e1ccafd63b48eefd700e841fe21da9ea70d00c9a3@127.0.0.1:0","enr":"0xf88fb8407399470e3737fa8272666e8fbd34bdca814621e3e955369900b266e29c0fa58744c674080c49ca4e6b59676ee2486cb144a30a95904959d8b5878edb805a4faa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bec2d78f8d965930c57e3156c95b56aedc58439ffffea7b36857dcdfe54089c9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DCjNExWJBimJbQ/lUXUk1Ot4j3REcJwTXqaQuk5hA9U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0c28cd\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ee5e f45f af02 b95d | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 5 4c9e 44a1 524d 6967 | 70 4109 (0) 41d9 (0) 46fe (0) 4646 (0)\n002 7 21a0 256e 2abb 378e | 32 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n003 6 1436 179f 1672 1f85 | 22 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n004 5 0328 00c6 0661 07a8 | 11 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n005 2 0a00 0af9 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 2 0ff2 0fc5 | 3 0e5e (0) 0ff2 (0) 0fc5 (0)\n007 2 0d8a 0de3 | 2 0d8a (0) 0de3 (0)\n============ DEPTH: 8 ==========================================\n008 1 0cf5 | 1 0cf5 (0)\n009 1 0c64 | 1 0c64 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","private_key":"e4f96de1ae6c788aee624501af093f341f540fac893f97ced8d5f1189c24c67f","name":"node_0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","services":["streamer"],"enable_msg_events":true,"port":36203},"up":true}},{"node":{"info":{"id":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","name":"node_6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","enode":"enode://e505e79cdb3fcf2ca7c4f9dd26a2c8fe2b7f6ae9b788f6a904eaf8fbc4160d011c02333c5127215f980fba718d4b3a285c2e88a4fb44a15d266a91377d3b48e5@127.0.0.1:0","enr":"0xf88fb840d716acddd75f7eb58dd24dbcafe9a68ab943a8c16e6bd0e8c2895345b80d0a91716890cb91bd5d41bcaa60a862cb05a82b25fd626cda6d8930c48fb6619437e90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e505e79cdb3fcf2ca7c4f9dd26a2c8fe2b7f6ae9b788f6a904eaf8fbc4160d01","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aWfnQ4ElwgRdV1659Ae0o40b+dzRwcGpf3UNpqIa7/c=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6967e7\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ee5e 849b | 110 df1e (0) d863 (0) d887 (0) db6a (0)\n001 5 3b88 314a 21a0 2abb | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 2 4c9e 524d | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 5 7dc2 7e04 77d2 775e | 12 7a60 (0) 7b90 (0) 7920 (0) 7dbb (0)\n004 5 66e7 67aa 67dc 628e | 9 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n============ DEPTH: 5 ==========================================\n005 9 6c73 6c4d 6fe9 6f5f | 9 6c73 (0) 6c4d (0) 6fe9 (0) 6f5f (0)\n006 0 | 0\n007 1 6831 | 1 6831 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","private_key":"b2e4ecb1d88acc51fd5c7268060e5bc618f3e72b5b7c52f4e455216d80962dc0","name":"node_6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","services":["streamer"],"enable_msg_events":true,"port":35593},"up":true}},{"node":{"info":{"id":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","name":"node_849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","enode":"enode://b0afa8b09566cfd0a41f4197f7997a219c84adac6259015ce3698a009fb6abf8d1cdbe5450429b7e05c28a0d49b2b9f8f2bdd7335fc98e834b8bb0628eae7fc7@127.0.0.1:0","enr":"0xf88fb840393a953e4ec2059acf7f9d3275f18559d6680009999862bd154f9fd1ee1f999d45494fe71181ffbc753878d558571d57d1b697d91b82b240075a2dcd39fefbfb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b0afa8b09566cfd0a41f4197f7997a219c84adac6259015ce3698a009fb6abf8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hJvLub5Dt5n+/F5onvx1El2if1Nul+W3khAxUgrm5dg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 849bcb\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 0c28 3b88 3ec5 3efc | 146 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n001 7 c1f9 f31c f773 f45f | 63 df1e (0) d887 (0) d863 (0) da67 (0)\n002 6 a6fb af02 b502 b2b5 | 27 a369 (0) a34e (0) a46d (0) a653 (0)\n003 6 9fa0 9852 9890 9076 | 10 915d (0) 90a8 (0) 9076 (0) 959f (0)\n004 4 8f21 898d 88a1 88fe | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n============ DEPTH: 5 ==========================================\n005 3 8025 82f9 82dd | 3 8025 (0) 82f9 (0) 82dd (0)\n006 0 | 0\n007 1 8505 | 1 8505 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","private_key":"a069eed892fd44938d06d266a1b6e95863c80eac1fa44fccaeebc41efc5ed441","name":"node_849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","services":["streamer"],"enable_msg_events":true,"port":41647},"up":true}},{"node":{"info":{"id":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","name":"node_b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","enode":"enode://616dc404ad737ba64ed652df2d9b1eb7fbc7d27072123ffacbd5768b7b3a2808cc1ea3f7273bc1a8e881a0ed5cf764d793fc0ee1fda9a62a2e5219a90f7b97e4@127.0.0.1:0","enr":"0xf88fb8403b649d56e05ba7d5845e7dc235d0b38a8817441e5e2a7dae66c6959b44f3331a4718237e4751e5b45041e65998db19f244b263394f454f246db8d863a0b2f9a80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102616dc404ad737ba64ed652df2d9b1eb7fbc7d27072123ffacbd5768b7b3a2808","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uJeTw8zZ6mQggHKHMs598zd4ZT/tPR2POiXmBnDjMyU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b89793\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7e04 738c 6ea5 44a1 | 146 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n001 5 f45f f5dc e7fa efea | 63 df1e (0) d863 (0) d887 (0) da67 (0)\n002 5 96fc 9076 9890 9fa0 | 20 915d (0) 90a8 (0) 9076 (0) 959f (0)\n003 4 af02 a6fb a369 a34e | 10 ac4d (0) ad98 (0) aeb4 (0) ae2b (0)\n004 4 b502 b02b b2a5 b2b5 | 8 b65e (0) b626 (0) b7ca (0) b5b2 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 badd baf2 ba88 bb90 | 4 baf2 (0) badd (0) ba88 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b911 b95d | 2 b911 (0) b95d (0)\n008 1 b820 | 1 b820 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","private_key":"0bc50a7b766d6bc874ba369321f3b4a7f46e967445811ba2511e2698ca848d6f","name":"node_b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","services":["streamer"],"enable_msg_events":true,"port":37439},"up":true}},{"node":{"info":{"id":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","name":"node_3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","enode":"enode://21eeb4f1bb6f01a16243e4a426ed7cc92b6fbc6f8004c7bd662db3891b43f68ff5952440f106b72cac72fb55e0d2e9efa1696011cd33351094dc6c2e13fa3a67@127.0.0.1:0","enr":"0xf88fb840be1d0ed9539666492df4644d2aed2cad4aa9462d5e4bea665e163639db67f4da335d828dd4a5e24ed611a8d48ce089696a907d9a7f47829e9c5413c90360eeec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10321eeb4f1bb6f01a16243e4a426ed7cc92b6fbc6f8004c7bd662db3891b43f68f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PsUwdh3bh/kw/akZvmffGAdMbweVKSrdGyqR/z2cOeM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3ec530\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 ee5e ed2d f773 f5dc | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 2 4c9e 524d | 70 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n002 7 1436 17db 19fa 0328 | 44 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n003 5 21a0 24b8 256e 2f32 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 4 378e 33b5 30be 314a | 10 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n005 2 3b78 3b88 | 3 39d1 (0) 3b78 (0) 3b88 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 3f94 | 1 3f94 (0)\n008 0 | 0\n009 1 3e8e | 1 3e8e (0)\n010 1 3efc | 1 3efc (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","private_key":"c4b8862c8a0e3546078dca8083dcf8de77697d5dc9c4287a249fe5593f2ca90d","name":"node_3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","services":["streamer"],"enable_msg_events":true,"port":37999},"up":true}},{"node":{"info":{"id":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","name":"node_524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","enode":"enode://99f219a31926c42a84a19fd9aea063ef2ccb9f87f3f3ce40a8f04c86844559a054cd3b92341e71f2c349582310c55ba9d086a6f5c3306860778bedbb03528ec0@127.0.0.1:0","enr":"0xf88fb8402ab8e87c3dbe9a6ec2cac6b5b115117c51c3fa4a47a0cdb6eb173d6c313304c33d04648bd348128c2a2214fc92458c6056d91e66d8698ef94c65f0eecbe6c2320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10299f219a31926c42a84a19fd9aea063ef2ccb9f87f3f3ce40a8f04c86844559a0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Uk24GxNa+Nwwm5QsCCpykd3bhRhm/GCHU/k37ncBW+A=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 524db8\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ee5e b897 b95d | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 5 19fa 0c28 3b88 3efc | 76 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n002 15 7920 7dbb 7dc2 7e04 | 32 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n003 4 4636 44a1 4559 4c9e | 23 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n004 2 5823 5cd2 | 7 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n005 1 574f | 1 574f (0)\n006 2 51db 512e | 2 51db (0) 512e (0)\n============ DEPTH: 7 ==========================================\n007 4 53a8 53fe 5308 534b | 4 53a8 (0) 53fe (0) 5308 (0) 534b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","private_key":"2f5862456985e522a96e35955f2236ea2996dbc1ae46e4cd98b90a43a097da88","name":"node_524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","services":["streamer"],"enable_msg_events":true,"port":36823},"up":true}},{"node":{"info":{"id":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","name":"node_b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","enode":"enode://36447aeebafb12ba1c78c6a46a110934e1cd8927ed11dface43f85436177abde695118ad9a8539534b4f4141d990d917f905f7ecaa18baaebc0916b0205c8e2e@127.0.0.1:0","enr":"0xf88fb84085f456734d0dc37f56567ca4283aaf0355c1fa8925ff4c21ea20d7528816d28d2f74360586c27977522735076e9fd0f4e0c89ff5e78369ea4fefb33a06c132730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10236447aeebafb12ba1c78c6a46a110934e1cd8927ed11dface43f85436177abde","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uV2I/2US746qpr2EL6RBdcFIT8LoYBuD1Qpf+pkr+jo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b95d88\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3b88 0c28 7e04 6ea5 | 146 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n001 8 c1f9 ee5e ed2d e7fa | 63 df1e (0) d887 (0) d863 (0) db6a (0)\n002 4 9890 9fa0 96fc 849b | 20 915d (0) 90a8 (0) 9076 (0) 959f (0)\n003 3 af02 a34e a6fb | 10 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n004 4 b2b5 b2a5 b626 b502 | 8 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 badd baf2 bb90 | 4 ba88 (0) badd (0) baf2 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b820 b897 | 2 b820 (0) b897 (0)\n008 0 | 0\n009 1 b911 | 1 b911 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","private_key":"7dd97b58fb51f901cffaf8552811e55ed1f745fbc8de989e59715731046e1c58","name":"node_b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","services":["streamer"],"enable_msg_events":true,"port":40425},"up":true}},{"node":{"info":{"id":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","name":"node_4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","enode":"enode://403136530469a350901a30c33fc7c809363b53c13ca95dcd6a7080ec55a3b2fcbbd3f07db1278c257db628914b8b98ebfe5410a5359cd0b5c72fcdeb559100cf@127.0.0.1:0","enr":"0xf88fb8409ef5c3e51708bd096ce7dcdf5540f7e5db79918330956f05073be4da985467075fbed23d2dba3eeb49140ac47e83bf6d93b7353a47dd6d7fd4df928eb9dc79200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103403136530469a350901a30c33fc7c809363b53c13ca95dcd6a7080ec55a3b2fc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TJ6rirRUBabUurRkMO/AS45q7B2UT4hDXspBNhkl83k=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c9eab\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ee5e 849b b95d | 110 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n001 4 0c28 3efc 3ec5 3b88 | 76 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n002 10 7dc2 7e04 738c 775e | 32 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n003 5 5823 574f 534b 53fe | 15 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n004 5 4646 4636 44a1 4559 | 12 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n005 4 49cd 4ac7 4a8b 4bcf | 6 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n006 1 4e5a | 1 4e5a (0)\n============ DEPTH: 7 ==========================================\n007 3 4d10 4d6b 4d59 | 3 4d10 (0) 4d59 (0) 4d6b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","private_key":"7a577f1da7e66657ebe473b20ef72d95fc90848f65d8f7227f9eedb8dd2d3e36","name":"node_4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","services":["streamer"],"enable_msg_events":true,"port":38639},"up":true}},{"node":{"info":{"id":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","name":"node_ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","enode":"enode://e66e86a0d8b4fe8bc6037006527db1566125b2f17053e993b1e6e0a5cf3096da8e44246fd1f52fa9c677d078df9bf67486a1f1a1a08a9a633b509a9a01cc0d52@127.0.0.1:0","enr":"0xf88fb8404bb9f05fb11c108c893d2acac05872631cf5338eb304846ac251737b9548d01240a48e2b9001871de694d6c2f671520f9e9ffbb8005f99e4f6e949e9fed7dadb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e66e86a0d8b4fe8bc6037006527db1566125b2f17053e993b1e6e0a5cf3096da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7l5332kDKcEy8vf8oiPP04S3vDTsOHY6TrQngOBYVlY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ee5e77\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0c28 3ec5 524d 4c9e | 146 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n001 4 849b a6fb b95d b897 | 47 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n002 7 c6cf c43f c1f9 c26f | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 6 fe21 f31c f773 f45f | 19 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n004 4 e027 e54b e775 e7fa | 8 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n005 4 eb98 e854 e8ef e883 | 4 eb98 (0) e854 (0) e8ef (0) e883 (0)\n006 2 ec52 ed2d | 2 ec52 (0) ed2d (0)\n============ DEPTH: 7 ==========================================\n007 3 ef1b ef07 efea | 3 ef1b (0) ef07 (0) efea (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","private_key":"5622bc6c32ee27ea32ea20654dd0ce86eaf3f03c76b7873bae6de889e3b89961","name":"node_ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","services":["streamer"],"enable_msg_events":true,"port":39579},"up":true}},{"node":{"info":{"id":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","name":"node_68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","enode":"enode://b128b6cecc8f2cf260a135b1c480349d02ac0d60843d4e5112e6b974c18ef523effc3437092835f6f1fa3db2059063ace1de775116568700f3058a2adb47dc7b@127.0.0.1:0","enr":"0xf88fb840ceddc27e475fd5b30430a62f464bf89b48b1cae471a6a1e058e20dbf6641057e1a29eaeb0a05c85c688b1f83254fcc847704c40740dfd0ee7942ad5792f29c780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b128b6cecc8f2cf260a135b1c480349d02ac0d60843d4e5112e6b974c18ef523","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aDF0MeT6Vb5KcA41xqV4MHzDK3IzZnm1xWGLYi7wxgI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 683174\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a6fb 849b ee5e | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 5 1436 165f 1672 17db | 76 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n002 4 524d 4636 44a1 4c9e | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 4 7e04 7dc2 738c 775e | 12 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n004 3 67aa 67dc 6251 | 9 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n============ DEPTH: 5 ==========================================\n005 9 6c73 6c4d 6fe9 6f5f | 9 6fe9 (0) 6f5f (0) 6f2d (0) 6e68 (0)\n006 0 | 0\n007 1 6967 | 1 6967 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","private_key":"1411ce49011b5e54719d32b3c8ee30e4e193aca2197047ff1878ec787ac339ac","name":"node_68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","services":["streamer"],"enable_msg_events":true,"port":45763},"up":true}},{"node":{"info":{"id":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","name":"node_3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","enode":"enode://f83fbc7b2e60a5ff4336bb527a72e161cd34aa8263923321c51a04ac74a3e361817581c460f34af4383da37b22729b7ba4bf4c15d7cbe276e9c889012ed3914a@127.0.0.1:0","enr":"0xf88fb840d4647a73a557c64ec9967abd7177386635f95f0ca12c9448349e1ba7e51b526e0f5690e7a06679eb95a475414adb1a6bf0d787343a9310b45114284f99eda12a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f83fbc7b2e60a5ff4336bb527a72e161cd34aa8263923321c51a04ac74a3e361","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O4ikcr66Shj430VniIj9NZusOCOQDuz+ADf9ya1U1BY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b88a4\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 d1d7 f5dc e027 efea | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 8 524d 49cd 4c9e 44a1 | 70 5b63 (0) 5823 (0) 58ed (0) 5db0 (0)\n002 8 0de3 045b 07a8 0328 | 44 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n003 4 2abb 21a0 256e 24b8 | 15 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n004 5 33b5 30be 314a 3780 | 10 3237 (0) 3373 (0) 33b5 (0) 3089 (0)\n005 4 3f94 3e8e 3efc 3ec5 | 4 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n============ DEPTH: 6 ==========================================\n006 1 39d1 | 1 39d1 (0)\n007 0 | 0\n008 1 3b78 | 1 3b78 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","private_key":"375d6617b99adaf6d42a2645a0cf39107d821b1de2bd8a65b429b3a08f5a9bf5","name":"node_3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","services":["streamer"],"enable_msg_events":true,"port":44069},"up":true}},{"node":{"info":{"id":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","name":"node_44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","enode":"enode://2a7158451573eff25378de21fbabcff17326a0fc8247f6458d8aa97d024f7a8323240b745cfe394201f1be22313612dcbaac070227f39a01884f31e654543103@127.0.0.1:0","enr":"0xf88fb8400c1b56475eeb14186a876e72f3a08af9d4bff9d3ef73358874e77af19f982809410403a991c8fdc1f40ffdbc049f9e227cbbe0c21be45c526004d08af4db1cee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032a7158451573eff25378de21fbabcff17326a0fc8247f6458d8aa97d024f7a83","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RKEFMMN2shW6/4Ux7rKvuNZxTE0DUNGm8ydhqXzWx+w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 44a105\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 a6fb b95d b897 849b | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 3 0de3 0c28 3b88 | 76 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n002 10 6251 66e7 67aa 67dc | 32 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n003 3 524d 534b 574f | 15 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n004 5 49cd 4bcf 4a8b 4c9e | 11 4990 (0) 49ea (0) 49cd (0) 4ac7 (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 6 47bf 4782 46fe 4646 | 6 47bf (0) 4782 (0) 46fe (0) 4646 (0)\n============ DEPTH: 7 ==========================================\n007 2 4558 4559 | 2 4558 (0) 4559 (0)\n008 1 4447 | 1 4447 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","private_key":"c92c1299282223ac7bd3a783268df8976213e2780f5b1fa979226ac67dc17d66","name":"node_44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","services":["streamer"],"enable_msg_events":true,"port":38773},"up":true}},{"node":{"info":{"id":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","name":"node_7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","enode":"enode://bb02c7e6af72f5794c6c0e8f70aa4cb3f84690c0f191cd8a7826c0ffb077510cf3a26fd6ad876b06f2e5944db84ec2eae05a4d0d9a5096ec4efffe3f3e3a7afc@127.0.0.1:0","enr":"0xf88fb8409f4cf59b81d3287012b59795e4be8f109968bd13739a36e9aa83cd88d152dc653f4d5471a570a8b3b5edf29c145584dcc9a9c43c40eaf96267ad7030b77ce96b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bb02c7e6af72f5794c6c0e8f70aa4cb3f84690c0f191cd8a7826c0ffb077510c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fgRY7N9wgUQ8q1QSUp85SOzmWfrKygMghJbIDdE25wQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7e0458\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 a6fb b897 b95d 849b | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 5 0de3 1c8a 17db 1436 | 76 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n002 6 574f 524d 4c9e 4636 | 38 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n003 7 6251 67dc 6831 6967 | 20 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n004 5 7125 7290 738c 77d2 | 5 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n005 3 7a60 7b90 7920 | 3 7920 (0) 7a60 (0) 7b90 (0)\n============ DEPTH: 6 ==========================================\n006 3 7dbb 7dd3 7dc2 | 3 7dbb (0) 7dd3 (0) 7dc2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","private_key":"ea6c1bb2edf4d57e62ea561fcc9ba70c43c2a1090c7a34f31e047846d20e1ecd","name":"node_7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","services":["streamer"],"enable_msg_events":true,"port":40827},"up":true}},{"node":{"info":{"id":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","name":"node_f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","enode":"enode://08d06f19a921d3ea71d5c21913f5a847342419531a220f0da8d9e08bcefd1a0378205d1540b494ce8614bf2735320a49b00e7e9b4c73bc7845cbb81de6b1bf3a@127.0.0.1:0","enr":"0xf88fb8408b284fdc213acbd87073a716711d397be5a8b101dd3611a4833b0871cb3afdac21356d090fbe7737468658f36f642f1e0a2dad2c4179385a98354e9c23d5669f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10208d06f19a921d3ea71d5c21913f5a847342419531a220f0da8d9e08bcefd1a03","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9dx4/3GmP8IBS5VTcj7mdsY/wHijKka3yxcvNXoRgUA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f5dc78\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 3b88 3ec5 17db 4559 | 146 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n001 5 96fc 849b b897 b95d | 47 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n002 7 c898 caf6 c786 c43f | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 4 e027 ee5e efea ed2d | 18 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n004 4 fbf5 fbc8 ff36 fe21 | 6 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n005 3 f2d5 f27f f31c | 3 f2d5 (0) f27f (0) f31c (0)\n006 3 f629 f7fa f773 | 4 f629 (0) f7ba (0) f7fa (0) f773 (0)\n007 3 f4e0 f45f f456 | 3 f456 (0) f45f (0) f4e0 (0)\n============ DEPTH: 8 ==========================================\n008 1 f528 | 1 f528 (0)\n009 1 f5b2 | 1 f5b2 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","private_key":"a6746718798088d317cd7d6225dda0a32b67a827b88d4a80a28bcde59066ed49","name":"node_f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","services":["streamer"],"enable_msg_events":true,"port":33297},"up":true}},{"node":{"info":{"id":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","name":"node_a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","enode":"enode://0f12517c087f26001777a74267986c3d70abd56b9d17bd9061733e04d502ac2e7e9feb69aa0ac8aaa716add8e77c398c539e99e4665d1a48c81b74b30caafde0@127.0.0.1:0","enr":"0xf88fb840ff6e1d2403a5021cfc7a38d52571942b9c94756c73ba48c5ed420b788bc58ece089b54204b870f0a6c6a56ba811234ec38f78bb09ac098bef92436427f751c410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f12517c087f26001777a74267986c3d70abd56b9d17bd9061733e04d502ac2e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pvvha4HSQP8vLtbJPP2VkHMd+y5+w/zhwJj+VCvt8pk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a6fbe1\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3b88 17db 1c8a 44a1 | 146 11d4 (0) 103b (0) 13d6 (0) 154b (0)\n001 9 c6cf d299 d1d7 f4e0 | 63 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n002 7 96fc 9fa0 82dd 82f9 | 20 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n003 8 b502 b5b2 b626 b02b | 17 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n004 3 ad98 aeb4 af02 | 5 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n005 2 a369 a34e | 2 a369 (0) a34e (0)\n============ DEPTH: 6 ==========================================\n006 1 a46d | 1 a46d (0)\n007 0 | 0\n008 1 a653 | 1 a653 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","private_key":"23841056b6597d35a5a91856ad166332b11761512af382f62b98d43b330c665d","name":"node_a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","services":["streamer"],"enable_msg_events":true,"port":45043},"up":true}},{"node":{"info":{"id":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","name":"node_ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","enode":"enode://a21876606bf6da53567f80f07c547c2c1d78eec18c7a793474aa1e554ed619945557b52c8557ad72b0b0953245c3dccc6a7c2e6969fa67cdb47559104f684454@127.0.0.1:0","enr":"0xf88fb8402a854c764d8a54505e85302e872616bb82bc6a7a4b1449e2edb01bfe25178a005d5002aa7cc69c8483eacebcbcd5eba719144823d665af12e4fb859eceec2bce0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a21876606bf6da53567f80f07c547c2c1d78eec18c7a793474aa1e554ed61994","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7S0+HlaTtESUgIkHyY7FTW0IMxlF0qLAPjETD+8dJYY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed2d3e\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0de3 1436 1c8a 21a0 | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 3 96fc b95d a6fb | 47 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n002 8 c6cf c43f c26f c1f9 | 26 c9f5 (0) c832 (0) c898 (0) ca04 (0)\n003 7 fe21 f31c f773 f4e0 | 19 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n004 4 e7fa e54b e547 e027 | 8 e5d7 (0) e5ad (0) e514 (0) e54b (0)\n005 4 eb98 e854 e883 e8ef | 4 eb98 (0) e854 (0) e8ef (0) e883 (0)\n============ DEPTH: 6 ==========================================\n006 4 efea ef07 ef1b ee5e | 4 ee5e (0) ef07 (0) ef1b (0) efea (0)\n007 1 ec52 | 1 ec52 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","private_key":"2f00e9f328828c2ef1bbf37d3db3377e0b4a02e7b9f6c3c721de6b28d64e6524","name":"node_ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","services":["streamer"],"enable_msg_events":true,"port":39543},"up":true}},{"node":{"info":{"id":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","name":"node_6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","enode":"enode://c17a20dfd7be57a18cf26dcd1c304d5d01f2bb6068e09de961e1e30ffe334f151dac48d199bf561c8521dd3eaaed28583b57f2d8aca1c073f06b13ac7c771e0f@127.0.0.1:0","enr":"0xf88fb840044d1bdf571743721ed4e147a3d9a181174532883199678affb2bc6db47eca1001a2b0b3f97cc98c720570887c8551261489998bce175bfc7e7c5148b30f4b510183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c17a20dfd7be57a18cf26dcd1c304d5d01f2bb6068e09de961e1e30ffe334f15","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bE3N/e4BZKmj9BlDBybdUfkZjGX/bn3nqqb2MtzeZ5Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c4dcd\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc a6fb c6cf d1d7 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 6 378e 3b88 0de3 1436 | 76 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n002 5 574f 524d 4c9e 4636 | 38 58ed (0) 5823 (0) 5b63 (0) 5db0 (0)\n003 7 738c 775e 77d2 7b90 | 12 7125 (0) 7290 (0) 738c (0) 775e (0)\n004 4 67dc 67aa 60d7 6251 | 9 6103 (0) 605a (0) 60d7 (0) 6337 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n============ DEPTH: 6 ==========================================\n006 7 6e05 6e68 6ecb 6ea5 | 7 6e68 (0) 6e05 (0) 6ecb (0) 6ea5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 6c73 | 1 6c73 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","private_key":"14959eff979bd6f1bd74aacbc23ad2c7cb285be7e1675fab6d17567cf10fad34","name":"node_6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","services":["streamer"],"enable_msg_events":true,"port":35017},"up":true}},{"node":{"info":{"id":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","name":"node_efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","enode":"enode://ddf6985e527e42d2f0b37b8e4efc6da2a5f68c0dcb89c92077390d6d6710adc001c172965c9ad744734a92ac1538392df4a714953a5ac33ec6e68fe8c9b0e3a3@127.0.0.1:0","enr":"0xf88fb84018e335f1758ad544ccb9a6381d6f5eeab5d27dab2936bb0dfad1e1e9623305ba03de5b05753d9cc1598585baef377ec5c714e6f06d43b7ab651e5fa82cc2c27b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ddf6985e527e42d2f0b37b8e4efc6da2a5f68c0dcb89c92077390d6d6710adc0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7+rjt/YQ3BCsxRBo53GIdtFHzXipooeIxduluzppUNw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: efeae3\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1436 24b8 378e 3b88 | 146 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n001 3 b502 b897 96fc | 47 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n002 5 c6cf c43f c1f9 c26f | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 5 fe21 f31c f4e0 f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 6 e027 e7fa e775 e5ad | 8 e5d7 (0) e5ad (0) e514 (0) e54b (0)\n005 4 eb98 e854 e883 e8ef | 4 eb98 (0) e854 (0) e8ef (0) e883 (0)\n006 2 ed2d ec52 | 2 ec52 (0) ed2d (0)\n007 1 ee5e | 1 ee5e (0)\n============ DEPTH: 8 ==========================================\n008 2 ef1b ef07 | 2 ef07 (0) ef1b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","private_key":"3551e1831fe811a97293215d19ab637fc344bb26a2e7c28837cc25d9d3052c96","name":"node_efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","services":["streamer"],"enable_msg_events":true,"port":41545},"up":true}},{"node":{"info":{"id":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","name":"node_96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","enode":"enode://72736087dff95f03e9af1a0bbdd5858d8f4a50191b1009fa72ad6139b18353b15f3279fefbc352d1152aeb84a63f03a86daada01292ac8355b7b2cc5c0bdbb80@127.0.0.1:0","enr":"0xf88fb840a74a4a8f60d5b3cc5affc9d1801b03958b73091bc0eae33da8a9ea19859e87aa7a447fe2e68fdd6cd94e10757d1d8ce01334922460cca97c80b2dc26a2c4dd380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10272736087dff95f03e9af1a0bbdd5858d8f4a50191b1009fa72ad6139b18353b1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lvzxTH+QNQCRrG/LWDBsz7nko409pZ+KtlaFQzKETL0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 96fcf1\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 4559 44a1 7e04 6c4d | 146 58ed (0) 5823 (0) 5b63 (0) 5db0 (0)\n001 11 c26f c786 c6cf d299 | 63 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n002 7 a6fb af02 b2b5 b5b2 | 27 bcc6 (0) ba88 (0) badd (0) baf2 (0)\n003 6 88fe 8505 849b 82f9 | 10 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n004 4 9d0f 9fa0 9852 9890 | 4 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n005 3 90a8 9076 915d | 3 90a8 (0) 9076 (0) 915d (0)\n============ DEPTH: 6 ==========================================\n006 1 959f | 1 959f (0)\n007 1 976e | 1 976e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","private_key":"dfe1f61a9d85c8c6b37a649568512c4247752f892548a5d10128c68168c53fa0","name":"node_96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","services":["streamer"],"enable_msg_events":true,"port":38025},"up":true}},{"node":{"info":{"id":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","name":"node_0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","enode":"enode://0ced9e64272a4cb6b4f08a7577cfb1318c6de0fc82b45829643a3864110c0b809d0431af3ccd8700544fb5b6bba382810ba02181f15aca5e3d22d19361ab6657@127.0.0.1:0","enr":"0xf88fb84043c00b34db2f00d166f5f835baedf82ade48ba0751e49942a1e43eea487b20731c17c117fd43602af8059005c27d4f1534b92e310f5e5c63e0a7cf7bc51ac0850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030ced9e64272a4cb6b4f08a7577cfb1318c6de0fc82b45829643a3864110c0b80","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DeORWwvMaAQMiqdvvSz6BxTps0ydvgg4p8uoHE9zWBw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0de391\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 96fc d1d7 ed2d e027 | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 4 6c4d 7e04 44a1 4559 | 70 58ed (0) 5823 (0) 5b63 (0) 5db0 (0)\n002 5 378e 3ec5 3b88 256e | 32 2d36 (0) 2c79 (0) 2c38 (0) 2ccf (0)\n003 5 1400 1436 17db 1f85 | 22 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n004 6 02d8 0328 045b 0438 | 11 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n005 3 0b72 0a00 0af9 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 2 0fc5 0ff2 | 3 0e5e (0) 0fc5 (0) 0ff2 (0)\n============ DEPTH: 7 ==========================================\n007 3 0cf5 0c64 0c28 | 3 0cf5 (0) 0c64 (0) 0c28 (0)\n008 0 | 0\n009 1 0d8a | 1 0d8a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","private_key":"b229b8d1f2575dc4c211d64fbcf552eadcf00482f0c55c8dfa3336ffe81b010e","name":"node_0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","services":["streamer"],"enable_msg_events":true,"port":38979},"up":true}},{"node":{"info":{"id":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","name":"node_e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","enode":"enode://42f4817eb446d17b96c18c2538bfdf9fee4b7d278972ce27ed86dda5d91ea3ec330cbb910a82891a66844c42127955360c97e744cd8c46592d82f0ae51f31845@127.0.0.1:0","enr":"0xf88fb840c0e372772fcb685e048c3e5fa6f01d0c119feb88cdc1cb7cdee06d41fd6b143c37da7e6ff58e2fdaa90c07a05779586aa7dd6e4678007678b886c09c39a532690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10342f4817eb446d17b96c18c2538bfdf9fee4b7d278972ce27ed86dda5d91ea3ec","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4Cep9xUmQcSkEVT4zk2v0jiVwxIVDv6oa/QVLIjQyoY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e027a9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7e04 3b88 1436 0de3 | 146 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n001 2 a6fb 96fc | 47 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n002 4 c43f c6cf db6a d1d7 | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 7 fe21 f31c f773 f4e0 | 19 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n004 6 eb98 e8ef e883 efea | 10 eb98 (0) e854 (0) e8ef (0) e883 (0)\n============ DEPTH: 5 ==========================================\n005 7 e5d7 e5ad e514 e54b | 7 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","private_key":"42236a2ba130a7a24f34201b6bceda8e237a0e2e4c4780e6dd8c423e79719722","name":"node_e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","services":["streamer"],"enable_msg_events":true,"port":33483},"up":true}},{"node":{"info":{"id":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","name":"node_d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","enode":"enode://80bb1c84b9239a4dcaca4b19398c7a54833efb060f0491e8f5efdb7549edffa41a10442da7ce9a44959a7220411d56f2ca686b1d2351ec652d3074a9bbecd50a@127.0.0.1:0","enr":"0xf88fb84099d84c8e0b6d56c16e509e6809e9057dfe42891fff4ff8e974189245419b9371212e1e3ecd5c2ec314cafb25c996d8ef320486b364a58b8f1e533b4afb42de240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10280bb1c84b9239a4dcaca4b19398c7a54833efb060f0491e8f5efdb7549edffa4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0dcZzh3KUHWYRJr+lmOWwWCtJa1jIRKrJosdkTtJDb0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d1d719\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 4559 44a1 7e04 6251 | 146 7125 (0) 7290 (0) 738c (0) 775e (0)\n001 3 b2b5 a6fb 96fc | 47 bcc6 (0) bb90 (0) ba88 (0) baf2 (0)\n002 11 fe21 f31c f773 f45f | 37 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n003 4 c1f9 c26f c43f c6cf | 15 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n004 5 df1e d887 daec da67 | 6 df1e (0) d887 (0) d863 (0) daec (0)\n005 2 d7ac d640 | 2 d7ac (0) d640 (0)\n============ DEPTH: 6 ==========================================\n006 2 d3b0 d299 | 2 d3b0 (0) d299 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","private_key":"c8c5ea87fb82c55c9d58f48496b2fd47c86008f9ed782575bb4d64dedd096136","name":"node_d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","services":["streamer"],"enable_msg_events":true,"port":42295},"up":true}},{"node":{"info":{"id":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","name":"node_1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","enode":"enode://ccb62edd9cbb83630d2c5ca827a44633de8aa6a65c68b263563159e02cec0d8554ae6c1bbc6450aa60f4900f3acca4d2ba529b6462d17792e360a5256b0e7517@127.0.0.1:0","enr":"0xf88fb8402251f72e3876c375bdf5474dd9b47aa6a4ec1c1cb255bd976fb6a7607c35a8f45943221daba85c637fa764b89f1d4e637e7edfc5bfb242e35a690f9bc6c3109a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ccb62edd9cbb83630d2c5ca827a44633de8aa6a65c68b263563159e02cec0d85","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HIoQ7L1yrLK7u4t36lQE+ekPTb8wbsgTTP7XC0Cu85k=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1c8a10\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc a6fb ed2d f4e0 | 110 bcc6 (0) bb90 (0) badd (0) baf2 (0)\n001 4 7e04 77d2 6c4d 4559 | 70 7920 (0) 7a60 (0) 7b90 (0) 7dd3 (0)\n002 6 256e 24b8 3efc 3b88 | 32 2f32 (0) 2d36 (0) 2ccf (0) 2c79 (0)\n003 4 07a8 0c28 0d8a 0de3 | 22 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n004 7 13d6 154b 1400 1436 | 12 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n005 3 19fa 1a2a 1b83 | 4 18f6 (0) 19fa (0) 1a2a (0) 1b83 (0)\n006 3 1e2a 1f67 1f85 | 3 1e2a (0) 1f67 (0) 1f85 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 1c47 | 1 1c47 (0)\n009 0 | 0\n010 0 | 0\n011 1 1c9c | 1 1c9c (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","private_key":"530e6c41fc6e6889ceddd163a578f3db02856187b2f0466de53f7f29408159b3","name":"node_1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","services":["streamer"],"enable_msg_events":true,"port":45657},"up":true}},{"node":{"info":{"id":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","name":"node_17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","enode":"enode://e7d8ae7faaa3f720519c1ea490e184f238bf3e3c0be1da066ff25d1814339b79b018b95285a4db1d0d13e73503d99f590591dc1258d7bec591ae354c82a53839@127.0.0.1:0","enr":"0xf88fb840cec78fd16c7bdeaeb29d0f2f4fe3acb0f668c0432a9dac2be2d42460e02005a7493749ccc7b1b4faa5e51dae74cb0f39aac4d54d801dd26bfc466b82b76984390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e7d8ae7faaa3f720519c1ea490e184f238bf3e3c0be1da066ff25d1814339b79","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F9sViTvzm0JZPuHel1q6aDIEbZ2ltLST7EQnJziinO8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 17db15\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a6fb 96fc f4e0 f5dc | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 5 7e04 77d2 6831 6c4d | 70 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n002 5 24b8 256e 3b88 3ec5 | 32 2d36 (0) 2c79 (0) 2c38 (0) 2ccf (0)\n003 2 07a8 0de3 | 22 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n004 4 19fa 1b83 1f85 1c8a | 10 18f6 (0) 19fa (0) 1a2a (0) 1b83 (0)\n005 3 13d6 11d4 103b | 3 13d6 (0) 11d4 (0) 103b (0)\n006 4 1436 1400 14df 154b | 4 154b (0) 14df (0) 1400 (0) 1436 (0)\n007 2 165f 1672 | 2 165f (0) 1672 (0)\n============ DEPTH: 8 ==========================================\n008 1 1704 | 1 1704 (0)\n009 1 179f | 1 179f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","private_key":"2e941f41c9fc6b53b84ce73e68eaa0a486a0a2c4030d915897f04f366440d05e","name":"node_17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","services":["streamer"],"enable_msg_events":true,"port":41487},"up":true}},{"node":{"info":{"id":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","name":"node_455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","enode":"enode://4dc18460e3997bb0a5e9952976154083a46b2bf6b0c7f2810f7eee10b4b2254a8489d82eaed18436650b62980b531b8b1fb1808cfcc121d7749d3af1d718b12f@127.0.0.1:0","enr":"0xf88fb8402972e719eafce249c1d6c5b0af19eba09f751e4788398e88be87ee8619739c1c7d34faa74943a0227a4606a4a1c7ec1ecefdfc40a4cb0eca51ee1aa0dcaf300d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034dc18460e3997bb0a5e9952976154083a46b2bf6b0c7f2810f7eee10b4b2254a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RVk2/SLEN5Tm4hBP2R0/XSRuOCPo/46vjcJ6qfPS7gg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 455936\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc f4e0 f5dc d1d7 | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 6 378e 07a8 0de3 1c8a | 76 2ccf (0) 2c38 (0) 2c79 (0) 2d36 (0)\n002 6 77d2 738c 7dc2 7e04 | 32 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n003 2 574f 524d | 15 5b63 (0) 58ed (0) 5823 (0) 5db0 (0)\n004 5 49cd 4bcf 4a8b 4d6b | 11 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 5 4646 4636 46fe 47bf | 6 47bf (0) 4782 (0) 46fe (0) 4646 (0)\n============ DEPTH: 7 ==========================================\n007 2 4447 44a1 | 2 4447 (0) 44a1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 4558 | 1 4558 (0)\n========================================================================="}},"config":{"id":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","private_key":"7dbb064b0d47a7fc81d65e512613d0f099b690b6148f3867d9a2a7b689e3ff0e","name":"node_455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","services":["streamer"],"enable_msg_events":true,"port":44695},"up":true}},{"node":{"info":{"id":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","name":"node_1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","enode":"enode://c5e2dced64cebb7bcf961588b05aa6135f14b133db83b9f039adea823547e6ca6a4ae66dd060942b5ddf0e35a7cf9c23aeef18cfefb07822f52a3a0d6e01b12f@127.0.0.1:0","enr":"0xf88fb84093bfc5b68fff885df3ca3ca5159f4ac4816cd313e0880bd4b9fc9dc6642606263cdb0d436c19251deec31df9fe25f1d7038d04d44f93325c8f5ee48ed202a2540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c5e2dced64cebb7bcf961588b05aa6135f14b133db83b9f039adea823547e6ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FDaqqHcOnxxilOSfQGbBaxyqUFJOm4/QWAWeQWV9KoM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1436aa\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc d299 efea ed2d | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 5 7e04 6831 6c4d 4636 | 70 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n002 5 256e 24b8 21a0 3ec5 | 32 2d36 (0) 2c38 (0) 2c79 (0) 2ccf (0)\n003 3 07a8 0c28 0de3 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 5 1b83 19fa 1c9c 1c8a | 10 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n005 2 11d4 13d6 | 3 103b (0) 11d4 (0) 13d6 (0)\n006 5 165f 1672 1704 17db | 5 165f (0) 1672 (0) 1704 (0) 179f (0)\n007 1 154b | 1 154b (0)\n============ DEPTH: 8 ==========================================\n008 1 14df | 1 14df (0)\n009 0 | 0\n010 1 1400 | 1 1400 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","private_key":"30f78566606a3588a6ae7452aae120e984a681f8c1dfe235806102b387d1b5e1","name":"node_1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","services":["streamer"],"enable_msg_events":true,"port":37199},"up":true}},{"node":{"info":{"id":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","name":"node_378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","enode":"enode://62d1a6cca7bfbd3f31cbd86708971f47cf9eab3c318a42ca0784a3c76ed5bb697a9f7ec6987f2456c84aeaf468b4a99277dd1c85fb850c51d91f683ec2bfd821@127.0.0.1:0","enr":"0xf88fb84096dbe71818bc9bff8cab39cad479b1e8be50f63de0e73a02ab147856d3a7eb6866b2acfcb4f171d75eb8d44e9075bd3fc106e373e87ecbb2424c2c443996816f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10362d1a6cca7bfbd3f31cbd86708971f47cf9eab3c318a42ca0784a3c76ed5bb69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"N45698wBkYbU8mmedT4tcTAvjzVlVywTt6GxxctHRDw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 378e7a\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ed2d efea f4e0 d299 | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 6 6c4d 6f2d 77d2 49cd | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 8 0c28 0de3 07a8 1f85 | 44 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n003 2 256e 24b8 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 3 3b88 3efc 3ec5 | 7 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n005 5 3373 33b5 314a 3089 | 6 3237 (0) 3373 (0) 33b5 (0) 314a (0)\n006 1 35e6 | 1 35e6 (0)\n============ DEPTH: 7 ==========================================\n007 1 3630 | 1 3630 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 3780 | 1 3780 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","private_key":"f87ae143c4de5fb51892f311d616d4800d4963ecf3e3d1db6a4e31639d894c37","name":"node_378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","services":["streamer"],"enable_msg_events":true,"port":42999},"up":true}},{"node":{"info":{"id":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","name":"node_c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","enode":"enode://445bc4dbafd666bb2218c9ec6a582bf6bfb2fadbc7624ea9f724fb35a0b58d12a074a968505f280eb85b7240f437aac8986ba15cae3fb075b916c7620784004e@127.0.0.1:0","enr":"0xf88fb840ac8583022ed007db510135b8c593b46044e897f3fee1fd57fc3b04847325b40c5166ebd8aa464b82755d700da0d197da02f5d7be64bc2a5df55409f7040a10610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102445bc4dbafd666bb2218c9ec6a582bf6bfb2fadbc7624ea9f724fb35a0b58d12","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xs9GI5B47fs0PGRfA5cl/e4bu6iwptoC4sxFa5IjyaI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c6cf46\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 77d2 6c4d 6f2d 4559 | 146 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n001 4 a6fb b2b5 8025 96fc | 47 ac4d (0) ad98 (0) aeb4 (0) ae2b (0)\n002 5 ed2d ee5e efea e027 | 37 eb98 (0) e854 (0) e8ef (0) e883 (0)\n003 5 da67 db6a d299 d3b0 | 11 df1e (0) d863 (0) d887 (0) daec (0)\n004 4 cc20 c898 caf6 ca04 | 6 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n005 2 c26f c1f9 | 2 c1f9 (0) c26f (0)\n006 4 c59e c49c c43f c441 | 4 c59e (0) c49c (0) c441 (0) c43f (0)\n============ DEPTH: 7 ==========================================\n007 1 c786 | 1 c786 (0)\n008 1 c620 | 1 c620 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","private_key":"1227a7906f23478558c2ff562b54e86b2e16710eb7290823a1a7587ff14161e7","name":"node_c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","services":["streamer"],"enable_msg_events":true,"port":42921},"up":true}},{"node":{"info":{"id":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","name":"node_f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","enode":"enode://d57c1ed1af3de513ab3ca9168f80d3a51ffcb3af7a20c1f854d01312afa00097dd7257ccdc5bf0bed966eaabd495e22ee59207246b35d88a2f1027f2cb696b90@127.0.0.1:0","enr":"0xf88fb840ce18c84e0bf1b525d2a1ffc03cc7281c5c032526b3c258ba6e0c1b428e830b3b56b8c158871961b7f6fb5bcee112aa4bdba312e2c333b52e613e50ef0855ac980183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d57c1ed1af3de513ab3ca9168f80d3a51ffcb3af7a20c1f854d01312afa00097","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9OCfiSh70a94M6zYW6fMcf2z/zTy9AnhzyqHjc0xg9w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4e09f\npopulation: 44 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 4559 6f2d 24b8 378e | 146 103b (0) 11d4 (0) 13d6 (0) 1672 (0)\n001 5 a6fb b502 b2b5 8025 | 47 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n002 11 da67 db6a d7ac d1d7 | 26 df1e (0) d863 (0) d887 (0) daec (0)\n003 4 e027 ed2d ee5e efea | 18 eb98 (0) e854 (0) e8ef (0) e883 (0)\n004 4 fe21 ff36 fbf5 fbc8 | 6 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n005 3 f2d5 f27f f31c | 3 f2d5 (0) f27f (0) f31c (0)\n006 3 f629 f7fa f773 | 4 f629 (0) f7ba (0) f7fa (0) f773 (0)\n007 3 f528 f5dc f5b2 | 3 f5b2 (0) f5dc (0) f528 (0)\n============ DEPTH: 8 ==========================================\n008 2 f45f f456 | 2 f456 (0) f45f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","private_key":"068db7a4942ca7125ac96d19e14274fd6a94b300707941d0c28a2a334ec18d10","name":"node_f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","services":["streamer"],"enable_msg_events":true,"port":39333},"up":true}},{"node":{"info":{"id":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","name":"node_d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","enode":"enode://9921bbce6608fb1ad3311caeaf2d70b08c24b0c5097af6a7702cf8d750b57627cdfc9327ded122c82ad215e428777e2bc5bf667722eb531e3ababb25ed49e0a5@127.0.0.1:0","enr":"0xf88fb840de77d70c78a672c75090aa9196c7f37e174342b0b89db3c3d8208df199e66ae61c6c9d6d0849f2e4283008fbb2df674c815c4fadcbc9c5b1a3f5205d19eb1cca0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039921bbce6608fb1ad3311caeaf2d70b08c24b0c5097af6a7702cf8d750b57627","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0plB1ris2GzzL9HCGB2jqx2jwggxNLBoyknOKaqGt4M=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d29941\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 256e 378e 07a8 1436 | 146 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n001 4 96fc 8025 a6fb b2b5 | 47 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n002 7 e7fa ee5e ed2d fe21 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 5 ca04 c6cf c59e c43f | 15 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n004 5 d887 d863 daec da67 | 6 df1e (0) d887 (0) d863 (0) daec (0)\n005 2 d640 d7ac | 2 d640 (0) d7ac (0)\n============ DEPTH: 6 ==========================================\n006 1 d1d7 | 1 d1d7 (0)\n007 1 d3b0 | 1 d3b0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","private_key":"ed9cc2d516c3a37362d70e5337c6285651e7d1478038434939544e5f0a2558c5","name":"node_d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","services":["streamer"],"enable_msg_events":true,"port":35669},"up":true}},{"node":{"info":{"id":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","name":"node_6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","enode":"enode://6cadca795e1a9332ff620a0fa3972acbc4701938fd9ee90a2e0e3b06e0c12bc10e743b1605698003c58cbb67f3f6695e5b4a7b939a5f95e29661fdbed5c174b2@127.0.0.1:0","enr":"0xf88fb84086f29094a4468911665b009f5ad2ec7bb6dd33e9faab8e89844e394b676e514d1f1765853026e1c53a16b6a854ac35880408fdda19598f40e0550620310caa9a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026cadca795e1a9332ff620a0fa3972acbc4701938fd9ee90a2e0e3b06e0c12bc1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"by11ZWbdW0oT/+6p9ofHhRSPNAelAuKLnW7f0DuQX9w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6f2d75\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f4e0 c6cf d299 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 3 378e 24b8 07a8 | 76 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n002 4 4636 44a1 4559 574f | 38 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n003 8 7e04 7dbb 7dc2 7dd3 | 12 7920 (0) 7a60 (0) 7b90 (0) 7dd3 (0)\n004 4 60d7 6251 628e 67aa | 9 6337 (0) 628e (0) 6251 (0) 6103 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 4 6e68 6e05 6ecb 6ea5 | 4 6e68 (0) 6e05 (0) 6ecb (0) 6ea5 (0)\n============ DEPTH: 8 ==========================================\n008 1 6fe9 | 1 6fe9 (0)\n009 1 6f5f | 1 6f5f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","private_key":"3d64f67a082f7e4185e83ea4414849a0146c7104250ce8de6eb30c628b9b8459","name":"node_6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","services":["streamer"],"enable_msg_events":true,"port":43877},"up":true}},{"node":{"info":{"id":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","name":"node_07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","enode":"enode://3f7f839709363b1db97fd83da689de1fe397a6c4574f1186f20116ae3674c3777d47487ba386136c9f90670450caaaa8d08942f2d5b57e66e54333609ea826fb@127.0.0.1:0","enr":"0xf88fb8407eb35279cb43bd4502b17e6cf9227e0948b7d39a193d9dd1a66d0718d0f3a9ee4998694774985993b7ac021e4705e12e04741158f1838372359ff61c5a7fea0b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033f7f839709363b1db97fd83da689de1fe397a6c4574f1186f20116ae3674c377","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"B6jJAP7GxHdYDtWziEioaB3FKhnln6TNMvVx/n+yODo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 07a8c9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b2b5 c6cf d299 f4e0 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 6 574f 53a8 4559 4636 | 70 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n002 4 3b88 378e 256e 24b8 | 32 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n003 6 1436 1400 17db 1b83 | 22 103b (0) 11d4 (0) 13d6 (0) 165f (0)\n004 3 0c28 0d8a 0de3 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n005 3 00c6 02d8 0328 | 5 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n006 2 0438 045b | 3 0438 (0) 0451 (0) 045b (0)\n============ DEPTH: 7 ==========================================\n007 1 0661 | 1 0661 (0)\n008 1 0743 | 1 0743 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","private_key":"57fbc15d67af2d8593073c689c611a38db6bde0721b57199615b19d8038b5653","name":"node_07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","services":["streamer"],"enable_msg_events":true,"port":38689},"up":true}},{"node":{"info":{"id":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","name":"node_24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","enode":"enode://f4d9569b664ccde6dbfd8ffeb4524cf63fb038a8310e6faacf75999847a8a2aebf5463047743c0bbe50bfbf096cd1a88cc77c287c65777fe1aa700b92ff22931@127.0.0.1:0","enr":"0xf88fb84064a70dff70951c7ae9cd2b2c670490da42501b1011736ec633815cc654d0de98202748d2e22ba9fc5a5b006d005036985328ad38f7efe4ee0a095ed6983caa3a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f4d9569b664ccde6dbfd8ffeb4524cf63fb038a8310e6faacf75999847a8a2ae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JLhcEPCYclk46n2HzSSksQNYEpkG/Kl5D8Jm6oeEtTg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 24b85c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8025 96fc b502 b2b5 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 4 4636 49cd 6f2d 77d2 | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 7 17db 1436 1400 1c8a | 44 103b (0) 11d4 (0) 13d6 (0) 165f (0)\n003 6 3ec5 3efc 3b88 314a | 17 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n004 3 2f32 2ccf 2abb | 9 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n============ DEPTH: 5 ==========================================\n005 4 20ae 2101 217f 21a0 | 4 20ae (0) 2101 (0) 217f (0) 21a0 (0)\n006 0 | 0\n007 1 256e | 1 256e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","private_key":"c43bfbf2bb506dcd5608000c4a2f2a4ad8be5b1c1d5ecb3bc1bc59109c0b6b16","name":"node_24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","services":["streamer"],"enable_msg_events":true,"port":38967},"up":true}},{"node":{"info":{"id":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","name":"node_1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","enode":"enode://73040f7d8f962f54e6691a4b9f2c4b324d3dfbbe742387c453b5950b1adfc52a5f12c4a3b6511e824f9be6bf49cf996c448cff189ae3068d639a50438b0fbd22@127.0.0.1:0","enr":"0xf88fb840976c5a30ad5f6c348eaf3a368ab63084b1eae6ff36dfd982c5aeb47271554dc577959a9ce734707a16bc9bd64d23dca99b3c766c6b4243d75249708abd5189fd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10273040f7d8f962f54e6691a4b9f2c4b324d3dfbbe742387c453b5950b1adfc52a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"H4W4wF5dzv8L2CVvj22A1LkCqXVM65UtleouEVDvnlk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1f85b8\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b2b5 fe21 f4e0 c26f | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 3 574f 4636 77d2 | 70 5823 (0) 58ed (0) 5b63 (0) 5cd2 (0)\n002 4 378e 30be 256e 24b8 | 32 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n003 4 0c28 0de3 0d8a 07a8 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0ff2 (0)\n004 3 17db 1400 1436 | 12 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n005 4 19fa 18f6 1a2a 1b83 | 4 19fa (0) 18f6 (0) 1a2a (0) 1b83 (0)\n006 3 1c47 1c9c 1c8a | 3 1c47 (0) 1c9c (0) 1c8a (0)\n============ DEPTH: 7 ==========================================\n007 1 1e2a | 1 1e2a (0)\n008 1 1f67 | 1 1f67 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","private_key":"59c61bd4b5c1b4f8c1995c2c5162afae8f31e9c643be34f24fa05cc989be881e","name":"node_1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","services":["streamer"],"enable_msg_events":true,"port":38831},"up":true}},{"node":{"info":{"id":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","name":"node_77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","enode":"enode://d75b2925001a8eeae3e6c484278d65e4c64b829e79e4f4f9ffbfbfda98e713f2c194160e65c7afd3241b956106959174badaa1127f984a992d0d653bafad1ef2@127.0.0.1:0","enr":"0xf88fb84090355b49c231a49d0a8588ce047d0541ad615d101206c5f0d3460bdd3cb0046703875d1527046828aaab5698f064414207e768132bd4c870cfdefbc386c1c61a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d75b2925001a8eeae3e6c484278d65e4c64b829e79e4f4f9ffbfbfda98e713f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d9LsUtq9XX8ybUxq/SqtEQSHxr3/ophAYFKHFrqHNGI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 77d2ec\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d299 c26f c43f c6cf | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 7 07a8 17db 1c8a 1f85 | 76 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n002 7 4636 4559 4a8b 5f00 | 38 5efb (0) 5f00 (0) 5db0 (0) 5cd2 (0)\n003 10 67aa 67dc 6251 6103 | 20 6337 (0) 628e (0) 6251 (0) 6103 (0)\n004 5 7b90 7a60 7dd3 7dc2 | 7 7dbb (0) 7dd3 (0) 7dc2 (0) 7e04 (0)\n============ DEPTH: 5 ==========================================\n005 3 7125 738c 7290 | 3 7125 (0) 738c (0) 7290 (0)\n006 0 | 0\n007 0 | 0\n008 1 775e | 1 775e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","private_key":"682c5165cd7b0aefc0947ef86781161eeab41ef910322502ffe6b2db732e6f00","name":"node_77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","services":["streamer"],"enable_msg_events":true,"port":36957},"up":true}},{"node":{"info":{"id":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","name":"node_256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","enode":"enode://53a39015a7a349078a4861f507013efbe2e42c44a48210c7f41dfad8fe09503c0d8604c8ba351fa6b5da4179e598f7987bd5a4f5072028ea6c35867f4e0e3452@127.0.0.1:0","enr":"0xf88fb84096ffa0a393f3fa959e87c33678cde0b74e73829a0e1cc5a53e580d06d9d9b14373e52acbfd14808c4cfdb02cb4f2511fd88bbe7fb76ff0c58d87afb2f286bd960183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10253a39015a7a349078a4861f507013efbe2e42c44a48210c7f41dfad8fe09503c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JW6Bxab7Q700M0VHf4+WqhlH8HrDKX9jGrA/BgFHsGI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 256e81\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 fe21 c6cf d299 db6a | 110 df1e (0) d887 (0) d863 (0) daec (0)\n001 5 574f 49cd 4636 67aa | 70 5b63 (0) 58ed (0) 5823 (0) 5cd2 (0)\n002 9 0c28 0d8a 0de3 07a8 | 44 0a00 (0) 0af9 (0) 0b72 (0) 0e5e (0)\n003 7 3b88 3efc 3ec5 3780 | 17 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n004 3 2f32 2ccf 2abb | 9 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n============ DEPTH: 5 ==========================================\n005 4 20ae 217f 2101 21a0 | 4 20ae (0) 217f (0) 2101 (0) 21a0 (0)\n006 0 | 0\n007 1 24b8 | 1 24b8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","private_key":"45dc210e5a7309cf6d363540be2d1d849e0f2dc92ab7bb5df059d521246f9ff1","name":"node_256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","services":["streamer"],"enable_msg_events":true,"port":41465},"up":true}},{"node":{"info":{"id":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","name":"node_8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","enode":"enode://f14e1b9f746918024f3f3b5afb64d85f230790c5f8e6f530da3723875e1ba92922eec9c790e3bcf9a0266fa565f0af0d840edb1fa61b03c7f58196c038833999@127.0.0.1:0","enr":"0xf88fb840b4e407fbcca71bbbd27293f0aa73df4b38c2e5d75e916f3bb6f68b312823e00b6e349f5500dee5e74f29eff4153d436fabd7fbccfdd803ff167002ad2244b3450183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f14e1b9f746918024f3f3b5afb64d85f230790c5f8e6f530da3723875e1ba929","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gCXB/LmOU/knZ9HUOjBXoKzR6JlLtKfj9eJEEQ4Nz5E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8025c1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 512e 574f 4558 4636 | 146 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n001 7 c26f c43f c6cf d299 | 63 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n002 3 a6fb b502 b2b5 | 27 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n003 5 9d0f 9fa0 959f 96fc | 10 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n004 3 898d 886a 88fe | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n005 2 8505 849b | 2 8505 (0) 849b (0)\n============ DEPTH: 6 ==========================================\n006 2 82dd 82f9 | 2 82dd (0) 82f9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","private_key":"0c41aca505e0136ca72a3c58217ecd9a78eea3796b96dd546d96472f328cf37f","name":"node_8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","services":["streamer"],"enable_msg_events":true,"port":41367},"up":true}},{"node":{"info":{"id":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","name":"node_4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","enode":"enode://10f863a5bc8ec93dee6896e14260ef8642e83ee113ee0ed55e0ee9d2ad4feba5670b38d5e529811d454fffb530187992f11f0151ac5031122b0837f845acc95c@127.0.0.1:0","enr":"0xf88fb8405098b23b6301b63dedf00769712c97314e7c701599028eabebef4e123b8d775622dfd46163d23effb9dc9e0738d925989bb5b390f4fe66a740815305619af8b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10210f863a5bc8ec93dee6896e14260ef8642e83ee113ee0ed55e0ee9d2ad4feba5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RjbwC+YKm0lKPryatBzHy1PsCwvv8hTbLQokjcOutq8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4636f0\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8025 b2b5 | 110 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n001 6 378e 24b8 256e 07a8 | 76 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n002 7 67aa 6f2d 6c4d 6831 | 32 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n003 3 5b63 524d 574f | 15 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n004 5 49cd 4a8b 4bcf 4c9e | 11 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 4 4558 4559 4447 44a1 | 4 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n007 2 47bf 4782 | 2 47bf (0) 4782 (0)\n008 1 46fe | 1 46fe (0)\n============ DEPTH: 9 ==========================================\n009 1 4646 | 1 4646 (0)\n010 1 461c | 1 461c (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","private_key":"c7fd7cc73cf8fe60e42f0df8dba49b5b7c12529c7fabb2b5b769965ce13afb0b","name":"node_4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","services":["streamer"],"enable_msg_events":true,"port":40557},"up":true}},{"node":{"info":{"id":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","name":"node_b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","enode":"enode://d15330bc0ac2d05c53b502c8a5c9017e56f190332491742de058a920784f5ab943f482c2d1872603adc7d3bd42e77cb875434f3520ca93b47fe35a21fa62669a@127.0.0.1:0","enr":"0xf88fb840574761f8bb54fcd95cfa7b75775147cd15e5320d20cb64c70eda14db527c1ea24a6fde40dcbe9cd641f83d726c2d55878fbb2dfe0777ff514fd17b8bbfd106ee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d15330bc0ac2d05c53b502c8a5c9017e56f190332491742de058a920784f5ab9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"srW6G7GI8Y95spXywNSMUsHR1EnsublLmYTzpheXMsc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2b5ba\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 24b8 256e 07a8 1f85 | 146 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n001 9 ca04 c6cf c26f da67 | 63 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n002 6 9076 96fc 976e 849b | 20 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n003 2 af02 a6fb | 10 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n004 3 baf2 b95d b897 | 9 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n005 5 b7ca b65e b626 b5b2 | 5 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n============ DEPTH: 6 ==========================================\n006 1 b02b | 1 b02b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 b2a5 | 1 b2a5 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","private_key":"6e70ae5c645585cea4f6e117e84118dcdc9efb654cc766a374ca297817172dc0","name":"node_b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","services":["streamer"],"enable_msg_events":true,"port":33709},"up":true}},{"node":{"info":{"id":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","name":"node_fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","enode":"enode://efdfaaad939ceb845670e7c93e476a841dbc743aa1d3ba9836be214025381c0bf8fe8967634b433603fc4657ee30d1b0e860ac88f70406374d23c7b72532f3f5@127.0.0.1:0","enr":"0xf88fb8402b581c48bc9b046b1ac97ca1d73ba39bd09847eb3b4ccaee9cfb8cb46ef2d7393cde50a04a69fd36f4c6a06b66252d6372ff5781a97a9eba519a182ab6ff34ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103efdfaaad939ceb845670e7c93e476a841dbc743aa1d3ba9836be214025381c0b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/iFn/TPzgxEOs/bKp72QXKVPoMgQ8bijRIOoRvPL3as=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fe2167\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 256e 1f85 574f | 146 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n001 3 8025 b502 b2b5 | 47 9fa0 (0) 9d0f (0) 9852 (0) 9890 (0)\n002 7 d1d7 d299 da67 db6a | 26 d7ac (0) d640 (0) d1d7 (0) d3b0 (0)\n003 6 ed2d ee5e efea e5ad | 18 eb98 (0) e854 (0) e883 (0) e8ef (0)\n004 8 f2d5 f31c f773 f629 | 13 f31c (0) f27f (0) f2d5 (0) f629 (0)\n005 3 f925 fbf5 fbc8 | 3 f925 (0) fbf5 (0) fbc8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ff36 | 1 ff36 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 fe31 | 1 fe31 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","private_key":"82f871774e58e78c4be095210436adb4fb35f177d17042837b069f1793339635","name":"node_fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","services":["streamer"],"enable_msg_events":true,"port":40051},"up":true}},{"node":{"info":{"id":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","name":"node_c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","enode":"enode://89a40b4828258a45ddffc2eeca354e23356b818fc965a12c6a7e026d0e8bf72b43c98d81e2fa73356eff0f6100ae19475e42fa933113c8767b13dd5b04b84f5a@127.0.0.1:0","enr":"0xf88fb840d5565171400508ba844253cef0a659a7007e98b0ea4ea1d3174005f982b12e0f5d79bc818df366da989fde409077401d9b95cabac335c1d33761dfb511833e550183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10289a40b4828258a45ddffc2eeca354e23356b818fc965a12c6a7e026d0e8bf72b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wm/V5lBMez8KbZEz/4fJjBEOscIBxfO89rEGU/K5ctI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c26fd5\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1f85 67aa 77d2 574f | 146 0067 (0) 00c6 (0) 03cc (0) 0328 (0)\n001 6 96fc 976e 8025 82f9 | 47 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n002 8 ed2d efea ee5e e547 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 7 da67 db6a d863 d640 | 11 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n004 4 cc20 c898 caf6 ca04 | 6 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n============ DEPTH: 5 ==========================================\n005 7 c49c c43f c441 c59e | 7 c786 (0) c620 (0) c6cf (0) c59e (0)\n006 1 c1f9 | 1 c1f9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","private_key":"736c6a6244885a1ad39fb0d125a7a2bf50d5515f38b1360dcf2c82a12f76fac5","name":"node_c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","services":["streamer"],"enable_msg_events":true,"port":39119},"up":true}},{"node":{"info":{"id":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","name":"node_574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","enode":"enode://5f9fe022355b31091330921e29c0ad61c9fdf8ee82f66c36fb03b2302f8fe2e3c32b931a30a66613a2c8f79c5788077e652cb6abdeeb0a330c9d264a8db6fad7@127.0.0.1:0","enr":"0xf88fb8404d529d52c3e76b4faa7d0a3bd82b1141a7a6c579aa512fc3f8a9d7d980c977a8626eb6d9c3351103f11cff3b7d222edf1f0c5c4b6ba304f2215882fc818b63bd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035f9fe022355b31091330921e29c0ad61c9fdf8ee82f66c36fb03b2302f8fe2e3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V09lhnSCCRruJ3QDMRbCM1Je6nEXBrWum6CbVOiW0wI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 574f65\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 8025 b2b5 b502 f528 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 4 256e 0d8a 07a8 1f85 | 76 0067 (0) 00c6 (0) 03cc (0) 0328 (0)\n002 7 7e04 7b90 7290 77d2 | 32 7dbb (0) 7dd3 (0) 7dc2 (0) 7e04 (0)\n003 9 4c9e 49cd 4a8b 44a1 | 23 4109 (0) 41d9 (0) 4559 (0) 4558 (0)\n004 2 5823 5b63 | 7 5cd2 (0) 5db0 (0) 5f00 (0) 5efb (0)\n============ DEPTH: 5 ==========================================\n005 7 51db 512e 5308 534b | 7 51db (0) 512e (0) 5308 (0) 534b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","private_key":"d229f5b69bcdd60b64b4dbd3bbb0d8f06e4ce741c0ef2df9ccf7efa269b788e6","name":"node_574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","services":["streamer"],"enable_msg_events":true,"port":34895},"up":true}},{"node":{"info":{"id":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","name":"node_db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","enode":"enode://5eafc16cce4d7660bd2fbb314e96cc2cf9eb8ea56939776d7278b6d59cc46da7f9bd3236f1171a955cf401d05ba08861cadec21cd434a8fb1be4d95ba9e8334a@127.0.0.1:0","enr":"0xf88fb8405f6b3f6d51114a126675f72d0b280db019f6e5068b71d72e5a522e4083436c64689a304c802a95d836e8f5e273f123dba269e9df3e99b8b9760e25b4fef30abc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025eafc16cce4d7660bd2fbb314e96cc2cf9eb8ea56939776d7278b6d59cc46da7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"22ofazQva+lRf43wEAN5fBHIN9mu4826W3hZIws2w10=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: db6a1f\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1f85 256e 574f | 146 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n001 5 b2b5 b502 976e 82f9 | 47 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n002 8 ed2d ee5e e7fa e547 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 7 c9f5 caf6 ca04 c26f | 15 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n004 5 d7ac d640 d3b0 d299 | 5 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n005 1 df1e | 1 df1e (0)\n006 2 d887 d863 | 2 d887 (0) d863 (0)\n============ DEPTH: 7 ==========================================\n007 2 daec da67 | 2 daec (0) da67 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","private_key":"dfd2fca92d5a4f222ac845159014d664d54ea1f9b33035068dc1f2572296fc46","name":"node_db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","services":["streamer"],"enable_msg_events":true,"port":39263},"up":true}},{"node":{"info":{"id":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","name":"node_c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","enode":"enode://3fc6aafc24fea946b6e17b7a684b14df9e9eb28514b7332fa30fd325816de5cc8cc49b992cd85f654a3fac88deea0804c52317cc6de693cd9f057f26fddb4c5a@127.0.0.1:0","enr":"0xf88fb840f87236d325dbf8011e68c5678b19ce6e8c0f1f66642a6a0af4028d2d16dc012e4d16b88c631287a65df9c7a7cc2267c8da224e6c804be3d605675c79e68988940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023fc6aafc24fea946b6e17b7a684b14df9e9eb28514b7332fa30fd325816de5cc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xD++6VOAAHJ0uPIx/jS81ZtcDvCDCxdJZ9RwJieYT8Y=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c43fbe\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1400 0d8a 77d2 7290 | 146 00c6 (0) 0067 (0) 03cc (0) 0328 (0)\n001 4 976e 8025 82f9 b502 | 47 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n002 8 efea ee5e ed2d e027 | 37 ef07 (0) ef1b (0) efea (0) ee5e (0)\n003 5 d7ac d1d7 d299 da67 | 11 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n004 2 caf6 ca04 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c26f c1f9 | 2 c1f9 (0) c26f (0)\n006 3 c6cf c620 c786 | 3 c786 (0) c620 (0) c6cf (0)\n007 1 c59e | 1 c59e (0)\n============ DEPTH: 8 ==========================================\n008 1 c49c | 1 c49c (0)\n009 1 c441 | 1 c441 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","private_key":"6be49afc08c546676c011c401073a17e9b8840fa9edd1182f255e19073662d73","name":"node_c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","services":["streamer"],"enable_msg_events":true,"port":46219},"up":true}},{"node":{"info":{"id":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","name":"node_b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","enode":"enode://9d7d6722f1a51680a6f8affc6d1a10ede4ab4b4aa4ae1a4d406eec85c93875f1def190fdb2692f50153e62406fba95d939b2ca56910888b306eb3c9d50d76250@127.0.0.1:0","enr":"0xf88fb840beb0423e5654bf643406b5a5c35aa97675d9d7c3fef9bb2ddf7a0bfdb63b17b24b0224e5c5a31332fdc59e32c64eea5e59861707e1baa864e3e439cd273fcd430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029d7d6722f1a51680a6f8affc6d1a10ede4ab4b4aa4ae1a4d406eec85c93875f1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tQJdFTWB0zO0TfS5v6adh94TiQUXLk/TF+FvcJml/Pg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5025d\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 24b8 67aa 77d2 7290 | 146 3f94 (0) 3efc (0) 3ec5 (0) 3e8e (0)\n001 9 e5ad efea fe21 f4e0 | 63 eb98 (0) e854 (0) e883 (0) e8ef (0)\n002 6 88fe 849b 8025 82f9 | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 3 a6fb a653 af02 | 10 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n004 3 baf2 b95d b897 | 9 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n005 2 b2a5 b2b5 | 3 b02b (0) b2a5 (0) b2b5 (0)\n============ DEPTH: 6 ==========================================\n006 3 b7ca b65e b626 | 3 b7ca (0) b65e (0) b626 (0)\n007 0 | 0\n008 1 b5b2 | 1 b5b2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","private_key":"3a7659e35466d850264b95d5726e83847b52c4fe2ef8e76a5feac0100809deb4","name":"node_b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","services":["streamer"],"enable_msg_events":true,"port":45515},"up":true}},{"node":{"info":{"id":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","name":"node_f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","enode":"enode://9684e28e4a62f154f17f11253fb9011cc96e2d0d4ba400d12cf1b503cf26af50e7a8bf6e7f70c1536728100d6130ed58e2df364130255fbebe0d5d04b1fd70ed@127.0.0.1:0","enr":"0xf88fb8402dba0c34158122d8574a009ad32db3fe3e685cb1ca434ffbb06840fdc6eedf0918916d137d709bfd379a9142fb8a368674eaa6a9069a88209fb456b34b32b26d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039684e28e4a62f154f17f11253fb9011cc96e2d0d4ba400d12cf1b503cf26af50","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9Siqr9Z7INr9zhAdsiSqAccPk73JHBT1D6jbHb+fw4Y=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f528aa\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 574f 49cd 67aa 7290 | 146 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n001 3 b502 82f9 976e | 47 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n002 5 db6a da67 ca04 c26f | 26 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n003 7 ed2d efea e8ef e027 | 18 ee5e (0) ef1b (0) ef07 (0) efea (0)\n004 5 fbc8 fbf5 ff36 fe31 | 6 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n005 3 f31c f27f f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 3 f629 f7fa f773 | 4 f629 (0) f7ba (0) f7fa (0) f773 (0)\n007 3 f4e0 f45f f456 | 3 f456 (0) f45f (0) f4e0 (0)\n============ DEPTH: 8 ==========================================\n008 2 f5b2 f5dc | 2 f5b2 (0) f5dc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","private_key":"0074e098350248a953ff96635c5646441ade6fbfa6928e7e7750f648e3b500ee","name":"node_f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","services":["streamer"],"enable_msg_events":true,"port":43141},"up":true}},{"node":{"info":{"id":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","name":"node_976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","enode":"enode://f1a481f05b3add0348b325714cd13f8a882a8d2b664914693d9941f93594ca157866eea0d82ebc7cb2fe170adeff113230c00d363f046910cd52ab0d55492ebe@127.0.0.1:0","enr":"0xf88fb84014a108662ac31a996bb4e33b0cf7555059548c4001a3ef8a193d8466ea9d19560d11b9724d49c733a3cb7a33e6b586c3c1e7d29b5cfaec3a6ae783fc8cdd11100183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f1a481f05b3add0348b325714cd13f8a882a8d2b664914693d9941f93594ca15","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"l25X0MMiJyIr/Qy7gC8mm9zVLV0zz2icZrEsAj9fqL8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 976e57\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 512e 4558 46fe 4782 | 146 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n001 7 ca04 c26f c786 c43f | 63 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n002 4 b2b5 b626 b5b2 b502 | 27 aeb4 (0) ae2b (0) af02 (0) ad98 (0)\n003 5 898d 88fe 849b 8025 | 10 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n004 4 9852 9890 9fa0 9d0f | 4 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n005 3 90a8 9076 915d | 3 90a8 (0) 9076 (0) 915d (0)\n============ DEPTH: 6 ==========================================\n006 1 959f | 1 959f (0)\n007 1 96fc | 1 96fc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","private_key":"773efb429c0f38acad55b6036ac34ae481afe60385254d46a9bde06da2cb9688","name":"node_976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","services":["streamer"],"enable_msg_events":true,"port":34309},"up":true}},{"node":{"info":{"id":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","name":"node_7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","enode":"enode://5a17da2705e5b0debd1d99553696c4a5bbafb01aed9d25a59cc3138327b93cab177c0bcf0e776be1303d3ff5f00776f20c7014e244b21f403862867c778811b7@127.0.0.1:0","enr":"0xf88fb840e597671ce4248b4b2e417ca6323a8a567e7ef2d7410a33b01a359dbd7ecb815c2d88ee75860442c11680c729d27a72df1fb9720fae553a7935ef2d26436f68190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035a17da2705e5b0debd1d99553696c4a5bbafb01aed9d25a59cc3138327b93cab","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cpDNOv+t5fnnKdGwNUms6vslds28Z4n9aIyVSV8Qus0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7290cd\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c43f da67 f528 b502 | 110 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n001 3 02d8 0d8a 1400 | 76 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n002 9 5b63 53a8 574f 4558 | 38 51db (0) 512e (0) 524d (0) 5308 (0)\n003 5 6ecb 6fe9 6337 60d7 | 20 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n004 5 7e04 7dd3 7dc2 7b90 | 7 7e04 (0) 7dbb (0) 7dd3 (0) 7dc2 (0)\n005 2 775e 77d2 | 2 775e (0) 77d2 (0)\n============ DEPTH: 6 ==========================================\n006 1 7125 | 1 7125 (0)\n007 1 738c | 1 738c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","private_key":"c64631a1d6a68b8a5627d9020f3e5b7139f946885d83e07bc5704da66d3166c7","name":"node_7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","services":["streamer"],"enable_msg_events":true,"port":41897},"up":true}},{"node":{"info":{"id":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","name":"node_82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","enode":"enode://491601ffb74c3a9ebf3de209bc241d4c92ac22845e14acc401f895473f0bc655a9cfea75088a8c844eb406d545723ae828d2f12c500b0b54af2dd1fa476fb492@127.0.0.1:0","enr":"0xf88fb8403595298556b2fc3d72aad1199b8884bb4964f0329c3e542b25cdb97b44aa51647ad064f3bb12519401f2d5e1a205f0437711a1a9ae0d7ced24515e75874358490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102491601ffb74c3a9ebf3de209bc241d4c92ac22845e14acc401f895473f0bc655","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gvnJAJ8J3i1qd7VJdtFMFCEermXYhvbtV1YMcAcW3Vw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82f9c9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4558 4a8b 49cd 67aa | 146 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n001 6 ca04 c26f c43f db6a | 63 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n002 5 a6fb b2b5 b626 b5b2 | 27 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n003 6 9d0f 9fa0 915d 959f | 10 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n004 4 8f21 898d 886a 88fe | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n005 2 8505 849b | 2 8505 (0) 849b (0)\n============ DEPTH: 6 ==========================================\n006 1 8025 | 1 8025 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 82dd | 1 82dd (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","private_key":"0ef1f1623ac066de7c84777cf3fdec022dd693c8afd056e66d11862de46a6b46","name":"node_82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","services":["streamer"],"enable_msg_events":true,"port":35447},"up":true}},{"node":{"info":{"id":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","name":"node_67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","enode":"enode://df05a5d2153d7fb7c457936ec0e15ff559604a97443ea6452b72f52f0bf4f7141b33e639ea57beeef6f9a66105875690ff4b2ab4747566fd982574190e3de8ad@127.0.0.1:0","enr":"0xf88fb840a795f4ec6f1fdb826e6b2093cab7198649eb34d52ca4b62ce368e45ac4faa1f528a90244e6f7e816652c6b385873781f7c5100d927d40bba2c80f904ae4bfe140183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df05a5d2153d7fb7c457936ec0e15ff559604a97443ea6452b72f52f0bf4f714","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z6pUY+SzKzY7PQHSpBzLAxmUEQVydvSWLQUxYL4ppu8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67aa54\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f528 c26f c43f da67 | 110 ef1b (0) ef07 (0) efea (0) ee5e (0)\n001 5 256e 30be 02d8 0d8a | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 7 524d 53a8 574f 44a1 | 38 574f (0) 524d (0) 5308 (0) 534b (0)\n003 4 7a60 7b90 77d2 7290 | 12 7dd3 (0) 7dc2 (0) 7dbb (0) 7e04 (0)\n004 7 6831 6967 6c4d 6ea5 | 11 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n005 5 6337 6251 628e 6103 | 6 628e (0) 6251 (0) 6337 (0) 6103 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 66e7 | 1 66e7 (0)\n008 0 | 0\n009 1 67dc | 1 67dc (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","private_key":"b796ff6a7ea6c2ded46cda26187abc9f36f967d9926239cfadb31eb97c349ca6","name":"node_67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","services":["streamer"],"enable_msg_events":true,"port":41807},"up":true}},{"node":{"info":{"id":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","name":"node_49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","enode":"enode://3c3dd1934b208eb8c478606579f8392337b4793113196b083d2ab9599f30a2217b82e47b41b2446956ef7bc98a5c7017010d405e89625cfaa7ec82503202e598@127.0.0.1:0","enr":"0xf88fb840bef6e7ddcbe9097f31c066f2007867456dac705bcafc0d983fafa95339cf22cf0dbe62c98d695ab072cf52a83210e68e4ccd1ae28c315d504b31c18875a7a6280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c3dd1934b208eb8c478606579f8392337b4793113196b083d2ab9599f30a221","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Sc0e/talanivTqSrQIEwE+dsal+50gKe4C212A9eQaY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 49cd1e\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c43f ca04 f528 b502 | 110 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n001 10 30be 378e 3780 3b88 | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 4 7b90 7290 60d7 67aa | 32 7dd3 (0) 7dc2 (0) 7dbb (0) 7e04 (0)\n003 5 512e 53a8 574f 5f00 | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 8 4447 44a1 4559 4558 | 12 4109 (0) 41d9 (0) 44a1 (0) 4447 (0)\n005 3 4e5a 4c9e 4d6b | 5 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n006 3 4bcf 4ac7 4a8b | 3 4bcf (0) 4ac7 (0) 4a8b (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 4990 | 1 4990 (0)\n010 1 49ea | 1 49ea (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","private_key":"563539e7699dfba87188db2ed5bd0040cfa037d5206f5a9aea1126ba8152310e","name":"node_49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","services":["streamer"],"enable_msg_events":true,"port":41057},"up":true}},{"node":{"info":{"id":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","name":"node_46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","enode":"enode://a0de85bf37f6c9a5f3721d82e07290b2aff2e6a485e2f5ddf83375faa1ce9e2d017ddc7b100b4380ed76cfdecc7b264e3c387ea994ae3e04084de10b9ce0debe@127.0.0.1:0","enr":"0xf88fb840a6baf80ae45dad3d244387e2e3306969fc26628f3f7f6d0c4db267ea2c532b6b2afab9ca8d89a8c3e90d540e1ddff77ea90e5a57af1485e6cdf579d33d54d8990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a0de85bf37f6c9a5f3721d82e07290b2aff2e6a485e2f5ddf83375faa1ce9e2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rv7mna2LamqH01bRDbJdg1oMThVL8Xnoj7TMZfl9ctc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 46fee6\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b502 976e ca04 da67 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 3 0d8a 1b83 1400 | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 6 7290 7a60 7b90 6fe9 | 32 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n003 4 5b63 574f 53a8 512e | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 3 4ac7 4a8b 49cd | 11 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 4 4447 44a1 4559 4558 | 4 44a1 (0) 4447 (0) 4559 (0) 4558 (0)\n007 2 47bf 4782 | 2 47bf (0) 4782 (0)\n============ DEPTH: 8 ==========================================\n008 3 4646 461c 4636 | 3 4646 (0) 461c (0) 4636 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","private_key":"6fc017c68b2b6d1e4693c27cfaf816ee8b7e583f9c28e3236413cc80fef9a431","name":"node_46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","services":["streamer"],"enable_msg_events":true,"port":44839},"up":true}},{"node":{"info":{"id":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","name":"node_4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","enode":"enode://de5cedf56d1615e739c3b5ca058d2eea156785daef1c7f6e902c2bff170ea20cf2d7bbb3675b4e578abc41a540756f95f3737dc19ebd04edabd1f16878ff499b@127.0.0.1:0","enr":"0xf88fb840020d593599f4d4fdd4b673eaa585fd98665cc182ed5584ba2d601525f0a039d052b21ad75071dad2b20f02fc88ac764fb23d96be4848d01c42922b552755b01d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103de5cedf56d1615e739c3b5ca058d2eea156785daef1c7f6e902c2bff170ea20c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SothDgnTWqIcQquMPjjeYAqUTAlOa4bqVoKLXmkE8fc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a8b61\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b502 976e 82f9 da67 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 2 0d8a 1400 | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 5 60d7 7b90 7a60 77d2 | 32 7dbb (0) 7dd3 (0) 7dc2 (0) 7e04 (0)\n003 4 512e 53a8 574f 5b63 | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 8 4447 44a1 4559 4558 | 12 41d9 (0) 4109 (0) 44a1 (0) 4447 (0)\n005 2 4d6b 4c9e | 5 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n006 3 4990 49ea 49cd | 3 4990 (0) 49ea (0) 49cd (0)\n============ DEPTH: 7 ==========================================\n007 1 4bcf | 1 4bcf (0)\n008 0 | 0\n009 1 4ac7 | 1 4ac7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","private_key":"3deb6c6e230a0dae4c0fedc0272e1053d1abd2a0db710d50aef93887fa30a915","name":"node_4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","services":["streamer"],"enable_msg_events":true,"port":46571},"up":true}},{"node":{"info":{"id":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","name":"node_478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","enode":"enode://8fccdf07a7c9e466c0b785b6e7c08ab0f94389a6dd46b9a57854589a96a603e97aa8de47419c1d494b354330e85090d9c6caaeb9c4b9569614ed744bb18a812d@127.0.0.1:0","enr":"0xf88fb8405875381eb6fee735b5b8a7f7d40d20b341a0100ea48efe8538f28a4f40cd5a1323c240cd86add212d1642a4178d5f89048e6a9c2ddb9ff519e8baacfeffa0bbc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038fccdf07a7c9e466c0b785b6e7c08ab0f94389a6dd46b9a57854589a96a603e9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R4J4GHzZr3megzQKL0mwt/Ei+44IwKNyqHeVQm6rNks=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 478278\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b502 976e da67 | 110 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n001 2 1400 0d8a | 76 2995 (0) 2a0a (0) 2a97 (0) 2abb (0)\n002 2 7290 60d7 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 4 5b63 574f 53a8 512e | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 2 49cd 4a8b | 11 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 4 4447 44a1 4559 4558 | 4 44a1 (0) 4447 (0) 4559 (0) 4558 (0)\n============ DEPTH: 7 ==========================================\n007 4 4646 461c 4636 46fe | 4 4646 (0) 461c (0) 4636 (0) 46fe (0)\n008 0 | 0\n009 0 | 0\n010 1 47bf | 1 47bf (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","private_key":"7134099c68806e422529987394e8a1ad8f242e3afdeaae1cbfc9502144f217d7","name":"node_478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","services":["streamer"],"enable_msg_events":true,"port":34389},"up":true}},{"node":{"info":{"id":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","name":"node_da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","enode":"enode://09c17ada4739980768a07f0c58b53d5a85809644bfc0eec14c46c61dc3e49b9b0464027601e91df63272219003508fbadb50af0b1e50cbf277df9393cf564a43@127.0.0.1:0","enr":"0xf88fb84026df424d93a356c6547f1236e5f3bcc0d324405bae4298855c59614f051e780b5a8e7f8b31e16a6c03c68c5b14c7f57b56aeec3423be94288bd6122dc84744bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10309c17ada4739980768a07f0c58b53d5a85809644bfc0eec14c46c61dc3e49b9b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2mes409wdqHVULxhvCox2ojWzZ+d9DsUKoxrut4bSu4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: da67ac\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 02d8 0d8a 1400 7290 | 146 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n001 3 b2b5 976e 82f9 | 47 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n002 6 e547 ed2d e8ef fe21 | 37 ee5e (0) ef1b (0) ef07 (0) efea (0)\n003 7 c26f c59e c43f c49c | 15 c1f9 (0) c26f (0) c620 (0) c6cf (0)\n004 4 d1d7 d299 d7ac d640 | 5 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n005 1 df1e | 1 df1e (0)\n006 2 d887 d863 | 2 d887 (0) d863 (0)\n============ DEPTH: 7 ==========================================\n007 1 db6a | 1 db6a (0)\n008 1 daec | 1 daec (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","private_key":"fe594383342620bd1c9a63e85f0d89178817a1ee319e2ae87883c4ea5095460e","name":"node_da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","services":["streamer"],"enable_msg_events":true,"port":38619},"up":true}},{"node":{"info":{"id":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","name":"node_ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","enode":"enode://314cf099608d4d93ba78e270ccccdc14e79ba93f1a35a21f22026b5185704dac75d3be0c47fa7ec804e43c36778fa2465de371bc88b65f0fe0fe7a20fcad4d41@127.0.0.1:0","enr":"0xf88fb840991f1a646d5b8c7b7ac450787d726b85d140b857b28b860546b9845b01192b1d33b0a9e2e8c65650934640d7cfda928a758c700c424697626a27fb804accd7f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103314cf099608d4d93ba78e270ccccdc14e79ba93f1a35a21f22026b5185704dac","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ygQdoNxRRkPQF0WNCP9pYuxSyeZlcaI57DldyLJUZwk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ca041d\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1400 02d8 0d8a 46fe | 146 2a97 (0) 2abb (0) 2a0a (0) 2995 (0)\n001 7 82f9 976e baf2 b2b5 | 47 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n002 4 e547 e5ad f4e0 f528 | 37 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n003 5 d299 d7ac d640 db6a | 11 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n004 8 c6cf c786 c59e c49c | 9 c1f9 (0) c26f (0) c59e (0) c49c (0)\n005 1 cc20 | 1 cc20 (0)\n============ DEPTH: 6 ==========================================\n006 3 c9f5 c832 c898 | 3 c9f5 (0) c832 (0) c898 (0)\n007 0 | 0\n008 1 caf6 | 1 caf6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","private_key":"9cc996c03300b4fbea17d12fdd08e09b69c5fb6285146a6ba449e039c93eb995","name":"node_ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","services":["streamer"],"enable_msg_events":true,"port":43867},"up":true}},{"node":{"info":{"id":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","name":"node_60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","enode":"enode://a14e22f8e8c82419c10076d96cdbe472237999f2149eee60543d344bb340cc0aba0065b6d152c59b8c5e95b6c85aad12133aa728af74492d114c66589b78a993@127.0.0.1:0","enr":"0xf88fb8408bf40ac90d17fcdb8b9194819add563ad27402ad5360ee89d31cd70ecae375697c825f76d7f9ff1386c1f4effce6a27828d685ca5f67dbdbdeffb230ebac73700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a14e22f8e8c82419c10076d96cdbe472237999f2149eee60543d344bb340cc0a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YNczfvgGvpXMr3udZjpCifmvxo7c7WKQSrUGAc8RP0U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 60d733\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e547 e5ad da67 ca04 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 3 1b83 1400 0d8a | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 7 512e 5b63 4a8b 49cd | 38 574f (0) 524d (0) 5308 (0) 534b (0)\n003 4 77d2 7290 7a60 7b90 | 12 775e (0) 77d2 (0) 7125 (0) 738c (0)\n004 6 6c73 6c4d 6ea5 6e05 | 11 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n005 2 66e7 67aa | 3 66e7 (0) 67dc (0) 67aa (0)\n006 3 6337 628e 6251 | 3 6337 (0) 628e (0) 6251 (0)\n============ DEPTH: 7 ==========================================\n007 1 6103 | 1 6103 (0)\n008 1 605a | 1 605a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","private_key":"d865723cac5fd73301f42e8bd68cfc9378898c91568207d80b7594237cbee540","name":"node_60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","services":["streamer"],"enable_msg_events":true,"port":37363},"up":true}},{"node":{"info":{"id":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","name":"node_0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","enode":"enode://9f72dc03cfdcb02e051151d117994d208c6b1accb3fa75fd4c8f6973b90760fa21a742f873bbdd6abb98b45feab218b475d88600d83f3e155c0cd3a2bc8cd8e0@127.0.0.1:0","enr":"0xf88fb8401d3b8aa52b102a17d0ec1a0fbb92d0c4d45b8c64280e68a6de5c10d42ac23c57363fb8dd32efeb83e9578e85d240b6e9e6cb00753baf3d5a7877201720e406c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029f72dc03cfdcb02e051151d117994d208c6b1accb3fa75fd4c8f6973b90760fa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DYqRkgf7LVcY6rfalfjv6wGk4a45YC0xX4ui/xdS2do=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d8a91\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e547 da67 c43f ca04 | 110 aeb4 (0) ae2b (0) af02 (0) ad98 (0)\n001 12 53a8 574f 5b63 49cd | 70 574f (0) 524d (0) 534b (0) 5308 (0)\n002 4 256e 2ccf 3780 30be | 32 21a0 (0) 2101 (0) 217f (0) 20ae (0)\n003 4 1c8a 1f85 1b83 1400 | 22 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n004 4 0438 0743 07a8 02d8 | 11 045b (0) 0451 (0) 0438 (0) 0661 (0)\n005 2 0af9 0b72 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 3 0e5e 0fc5 0ff2 | 3 0e5e (0) 0fc5 (0) 0ff2 (0)\n============ DEPTH: 7 ==========================================\n007 3 0cf5 0c64 0c28 | 3 0cf5 (0) 0c64 (0) 0c28 (0)\n008 0 | 0\n009 1 0de3 | 1 0de3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","private_key":"714005eb63c1f681f6e6d248618fbb384992707e07292f666ee9d475997ad0fe","name":"node_0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","services":["streamer"],"enable_msg_events":true,"port":36819},"up":true}},{"node":{"info":{"id":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","name":"node_140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","enode":"enode://e1ccb6417d15f6494ffafaa9d244c8b4dde696a72ca60fbd5dd6ad25d2b01530265fb2dff62548999fb9e9c7e4d8721cd1605b3e2259032ce3740e125a2724d9@127.0.0.1:0","enr":"0xf88fb840c1aba5fa71e995c2d05e38311251405e2aed69381bc4256421eefc3e58022db80bf4ee6dbb83cce873b18448ea8e2943c0c07ffcad5e79649279e3adec6b95d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e1ccb6417d15f6494ffafaa9d244c8b4dde696a72ca60fbd5dd6ad25d2b01530","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FAAgojqEC4hAugwsOE+FOmBjMOl0OIXplnz0lTPbKC4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 140020\npopulation: 45 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 e5ad e547 c43f ca04 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 13 53a8 46fe 4782 4558 | 70 574f (0) 524d (0) 5308 (0) 534b (0)\n002 4 256e 24b8 378e 30be | 32 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n003 6 0438 07a8 02d8 0cf5 | 22 045b (0) 0451 (0) 0438 (0) 0661 (0)\n004 8 1c47 1c9c 1c8a 1e2a | 10 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n005 2 13d6 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 4 1672 17db 179f 1704 | 5 165f (0) 1672 (0) 1704 (0) 179f (0)\n007 1 154b | 1 154b (0)\n============ DEPTH: 8 ==========================================\n008 1 14df | 1 14df (0)\n009 0 | 0\n010 1 1436 | 1 1436 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","private_key":"556950a90a1dad390b6fc5d9b5b1c233161f015de2d7fef6e8e6079733d4f698","name":"node_140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","services":["streamer"],"enable_msg_events":true,"port":35227},"up":true}},{"node":{"info":{"id":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","name":"node_7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","enode":"enode://5d077c804ebd13e7fa79b13210a9f8eaf0a72b5eb61816e9b780eb88a9794cf264334213ab605cbd538f71e0d354cc87c7c65b6ca6d492ca04a11f64dc401ee2@127.0.0.1:0","enr":"0xf88fb84044f3dd1993ede3a59f643421431f806409d41c9f6212b331bac4586d156afc1f75c391daa990c8e52046f96d52133b6b52ac0607d88f47108c0cb28b4e2ccb990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025d077c804ebd13e7fa79b13210a9f8eaf0a72b5eb61816e9b780eb88a9794cf2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e5DpOa4qJA8NdKkjr7a78R9tW5mnv4Xxglseo2vOdEw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7b90e9\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b626 da67 e547 | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 3 1b83 1400 02d8 | 76 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n002 10 4ac7 4a8b 49cd 46fe | 38 574f (0) 524d (0) 5308 (0) 534b (0)\n003 8 6c4d 6fe9 6f2d 6ecb | 20 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n004 4 7290 738c 77d2 775e | 5 775e (0) 77d2 (0) 7125 (0) 738c (0)\n005 4 7e04 7dbb 7dd3 7dc2 | 4 7e04 (0) 7dbb (0) 7dd3 (0) 7dc2 (0)\n============ DEPTH: 6 ==========================================\n006 1 7920 | 1 7920 (0)\n007 1 7a60 | 1 7a60 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","private_key":"e008f9a954df6848345e13074de64581f826eb05f1c85014a22afe07d7afd655","name":"node_7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","services":["streamer"],"enable_msg_events":true,"port":40801},"up":true}},{"node":{"info":{"id":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","name":"node_02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","enode":"enode://92a4724c2dc7a409c261888c4cd9cf6414fc6cf9df011f8877dcafb8a0f09fccc292ad4cea02561c68b2226b6058e8803230ac5adce4d829a6be49161e9672a6@127.0.0.1:0","enr":"0xf88fb840545027bb61080c38c187a5d84369aa4b4790c385613ee02331515b99e60b1dd8228951b517cb1ff48bf5de46057359f0dfa5c064e46b20ccfbe05526e9aa9daa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10292a4724c2dc7a409c261888c4cd9cf6414fc6cf9df011f8877dcafb8a0f09fcc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Athbn45HdiJK5QiGg6h4N7grK/t+BHzzc6KDk+espuE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 02d85b\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b626 da67 ca04 e5ad | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 9 53a8 512e 5b63 4558 | 70 574f (0) 524d (0) 534b (0) 5308 (0)\n002 4 2ccf 2995 3780 30be | 32 20ae (0) 21a0 (0) 2101 (0) 217f (0)\n003 2 1b83 1400 | 22 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n004 3 0cf5 0de3 0d8a | 11 0b72 (0) 0a00 (0) 0af9 (0) 0fc5 (0)\n005 5 07a8 0743 0451 045b | 6 0661 (0) 07a8 (0) 0743 (0) 045b (0)\n006 2 00c6 0067 | 2 00c6 (0) 0067 (0)\n============ DEPTH: 7 ==========================================\n007 2 03cc 0328 | 2 03cc (0) 0328 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","private_key":"e4ec3c40d474533d24394b73a40c70a533fdc023259146333c3ba30a6ef2e9ab","name":"node_02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","services":["streamer"],"enable_msg_events":true,"port":36493},"up":true}},{"node":{"info":{"id":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","name":"node_e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","enode":"enode://7171c11a093b51b6cc82078234ce48f2d0ebb3b56cc76ae5f988726c9857d7d69bc3fb5a01f4c6af0c862751c134804f1bdf13dc430fc007ae9c2dd5d0d6ff83@127.0.0.1:0","enr":"0xf88fb8408b53c905f3415f9c2c6e63f66a60385e30d6ff9285113905d760adb0db4eac275fefd5031cc64d050f70a502687314d59a1bd9c113edfd553d48a55a7a9c204e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037171c11a093b51b6cc82078234ce48f2d0ebb3b56cc76ae5f988726c9857d7d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5UeEz7zYnDfI91iq5w7OOrS3+MMPtO91Q+BKqJ/0OGs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e54784\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 1400 1b83 0d8a 02d8 | 146 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n001 4 9d0f 959f 915d b626 | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 10 c26f c786 c49c c59e | 26 df1e (0) d887 (0) d863 (0) db6a (0)\n003 3 fe21 f2d5 f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 3 e8ef ed2d efea | 10 ec52 (0) ed2d (0) ee5e (0) ef1b (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e775 (0) e7fa (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e5d7 e5ad | 2 e5d7 (0) e5ad (0)\n009 1 e514 | 1 e514 (0)\n010 0 | 0\n011 0 | 0\n012 1 e54b | 1 e54b (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","private_key":"6855155d7773437dde5625696c1fd21e0b93d11b8f418fe17b83735999241de6","name":"node_e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","services":["streamer"],"enable_msg_events":true,"port":44601},"up":true}},{"node":{"info":{"id":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","name":"node_45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","enode":"enode://1d85f00468f786d1f65c994867636f183a120622cffb3f2934c00dba86d528843a0c8b82e64a43212e3cb8b496fd71390b505c78ab6e3be9415fd3c56318aff7@127.0.0.1:0","enr":"0xf88fb840afb40932bf66ca7c121a0c54ece652628981b3fae02dd8c65f5de31913ddfd985cc09c42a7843bf6fc85803cae0b508643b06bb46b9c38f9c7c4570dc325063c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031d85f00468f786d1f65c994867636f183a120622cffb3f2934c00dba86d52884","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RVhKS+u5SO9fe1XUhG7FVJ12I2ghacDtyrWzUj5ox9o=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 45584a\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8025 82f9 959f 976e | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 4 30be 02d8 1400 1b83 | 76 2101 (0) 217f (0) 21a0 (0) 20ae (0)\n002 5 60d7 6fe9 7290 7a60 | 32 66e7 (0) 67dc (0) 67aa (0) 6251 (0)\n003 4 574f 53a8 512e 5b63 | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 3 49cd 4a8b 4ac7 | 11 4e5a (0) 4d10 (0) 4d6b (0) 4d59 (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 6 4646 4636 461c 46fe | 6 4646 (0) 461c (0) 4636 (0) 46fe (0)\n============ DEPTH: 7 ==========================================\n007 2 44a1 4447 | 2 44a1 (0) 4447 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 4559 | 1 4559 (0)\n========================================================================="}},"config":{"id":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","private_key":"9608a1c360a2f5a546c575e523d9afd2b89f14ea1058b2f3be09cb1ba5ba4240","name":"node_45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","services":["streamer"],"enable_msg_events":true,"port":44403},"up":true}},{"node":{"info":{"id":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","name":"node_1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","enode":"enode://73130b08d35d59e21a3991dc309b956f7bcd8dc6946b53bba74e40d612c993b6b8bfc34ee4e2cebfb54120afb070360aba61e91ebf845a4d0bc2f5a94f7918b2@127.0.0.1:0","enr":"0xf88fb84087efc4c166904eeedc3b6692d887773016e8af688980eff63dbd8053a6662a994b81ef2f726fb80b4fb522f0551ebbe913fedbb471e94c6e1b6c26882f9e963b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10273130b08d35d59e21a3991dc309b956f7bcd8dc6946b53bba74e40d612c993b6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"G4MO1ISydKlux7ovmkK2hZQStTNKVkAU/z8RWX6joy0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1b830e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c786 e547 | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 8 60d7 6fe9 7b90 7a60 | 70 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n002 3 2ccf 3780 30be | 32 20ae (0) 21a0 (0) 2101 (0) 217f (0)\n003 5 07a8 0438 02d8 0cf5 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 4 1704 17db 1436 1400 | 12 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n005 4 1f67 1f85 1c47 1c8a | 6 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n============ DEPTH: 6 ==========================================\n006 2 19fa 18f6 | 2 19fa (0) 18f6 (0)\n007 1 1a2a | 1 1a2a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","private_key":"9a7dd3d621d32ff5a718455ac877ef986e5aaa5f787e0c07a01221179c5655a6","name":"node_1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","services":["streamer"],"enable_msg_events":true,"port":44895},"up":true}},{"node":{"info":{"id":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","name":"node_5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","enode":"enode://7180d5a2452d8f6f57da742809146caacf5d03be267b31242048646bfa4961bf2284cfeab0b4af050aca2a42f14742163ac4fdfe364bb31111ee5aad221f17da@127.0.0.1:0","enr":"0xf88fb84057305ca13e6cae11290507a0fc500d9008b375e0f3e6c6a47714cc7fe9c0c390643b679806a97c42225f87daf53e3b30ee361ed30fb4980947d7d1734dfeb46e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027180d5a2452d8f6f57da742809146caacf5d03be267b31242048646bfa4961bf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W2Mur3ANFz/xX0cnuFgX5hcyKMMEtCJDSgjCytQ4uCU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5b632e\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b626 e5ad e547 d7ac | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 4 30be 0d8a 02d8 1b83 | 76 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n002 8 6337 60d7 6e05 6fe9 | 32 66e7 (0) 67dc (0) 67aa (0) 6337 (0)\n003 9 49cd 4a8b 4ac7 4636 | 23 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n004 4 574f 53a8 51db 512e | 8 574f (0) 524d (0) 534b (0) 5308 (0)\n005 3 5cd2 5db0 5f00 | 4 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n============ DEPTH: 6 ==========================================\n006 2 5823 58ed | 2 5823 (0) 58ed (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","private_key":"745b337c790505716596b24711aeb834f9da50436f3c21c469cc58d9ed44bade","name":"node_5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","services":["streamer"],"enable_msg_events":true,"port":39847},"up":true}},{"node":{"info":{"id":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","name":"node_512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","enode":"enode://1ab954a0243f9922c7cc2353fed4531e695ab0f6c7d1f8b71ad381ce5b816d82d3e28fec5e7c29b4803a212c4b95b2e36764a217983fe60077800f6cc1042e8f@127.0.0.1:0","enr":"0xf88fb84083fbd1c8452f3f73ce4a2b36c81e402e17ae6440d2848e50b2948a3e01e62a840e4e008afd0dbb92800b63a93d399149a0cf7181d700305c34a238931bf5eca00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031ab954a0243f9922c7cc2353fed4531e695ab0f6c7d1f8b71ad381ce5b816d82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"US7Fwua014hIJGLZQRF8gfzA5z8MFVRXlN0bTgO/IQI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 512ec5\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 915d 976e 959f 8025 | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 2 02d8 30be | 76 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n002 4 60d7 6fe9 7b90 7a60 | 32 66e7 (0) 67dc (0) 67aa (0) 6251 (0)\n003 8 49cd 4ac7 4a8b 4447 | 23 4c9e (0) 4d10 (0) 4d59 (0) 4d6b (0)\n004 2 5f00 5b63 | 7 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n005 1 574f | 1 574f (0)\n============ DEPTH: 6 ==========================================\n006 5 524d 5308 534b 53fe | 5 524d (0) 5308 (0) 534b (0) 53fe (0)\n007 0 | 0\n008 1 51db | 1 51db (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","private_key":"a9936124e7fb45265f6f877d31652c355a01c95aafa0759b600b0b01bda446eb","name":"node_512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","services":["streamer"],"enable_msg_events":true,"port":42415},"up":true}},{"node":{"info":{"id":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","name":"node_c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","enode":"enode://0f947b6b5ef1e5851a56a3a6852d472207b64d611146bc3070524184aa3530da88475fb850affcc256762fd9be921202f017475ff8cd8ffaeed209ab886fff12@127.0.0.1:0","enr":"0xf88fb840f891417b94f031211a81ebabc83fda5d22dee1e76ffbf5ed206cdfdc2e0ad84110d709ff637d2b0727e8e5968902fd13220cd26f881e0b8b8cf2978d2cf78daf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f947b6b5ef1e5851a56a3a6852d472207b64d611146bc3070524184aa3530da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"x4b/hmf1CbWpUZmEwdlcg6XS4ldQCnFCno8jr2EM53E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c786ff\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 30be 1b83 5b63 512e | 146 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n001 5 96fc 976e 959f 9d0f | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 9 f5dc f4e0 f925 fe31 | 37 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n003 5 d863 db6a da67 d640 | 11 df1e (0) d887 (0) d863 (0) db6a (0)\n004 4 c9f5 c832 ca04 caf6 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 4 c59e c441 c43f c49c | 4 c43f (0) c441 (0) c49c (0) c59e (0)\n============ DEPTH: 7 ==========================================\n007 2 c620 c6cf | 2 c620 (0) c6cf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","private_key":"ac3f95d0c0be51c8eb8e612f911fc75f2c7796eb845e974b365f8ca34e1cf47f","name":"node_c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","services":["streamer"],"enable_msg_events":true,"port":33023},"up":true}},{"node":{"info":{"id":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","name":"node_7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","enode":"enode://bcc004d204a81c01d6723867a47b697318eb158b54dcd5ded13d8dcc571f81e8bb51e56b4f5d2dae98a48aa41e77429bf1aed102194df88ce7a4ec9761c78733@127.0.0.1:0","enr":"0xf88fb840cdabbbf5e1facab29f6e6f89d212c7fae606ccfa0ebe589ea48a109bc0e55ada757e2d5d4c65db8cb1a08f565d4a76dc5e565ba64f9411dfb4335217027c424f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bcc004d204a81c01d6723867a47b697318eb158b54dcd5ded13d8dcc571f81e8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"emCNLPnR2cWBncH56I5csoUqreoBxA4EfC4YS2LnFjw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7a608d\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b5b2 e8ef e5ad d7ac | 110 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n001 5 02d8 0d8a 1400 1b83 | 76 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n002 9 4a8b 4ac7 4558 46fe | 38 4c9e (0) 4d10 (0) 4d59 (0) 4d6b (0)\n003 9 6103 60d7 6337 67aa | 20 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n004 2 77d2 7290 | 5 775e (0) 77d2 (0) 7125 (0) 738c (0)\n005 4 7e04 7dbb 7dc2 7dd3 | 4 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n============ DEPTH: 6 ==========================================\n006 1 7920 | 1 7920 (0)\n007 1 7b90 | 1 7b90 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","private_key":"1482a769e4374b6a63d26c4cd99ac2a877d146de855386acc89bbbf8d92d634d","name":"node_7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","services":["streamer"],"enable_msg_events":true,"port":43929},"up":true}},{"node":{"info":{"id":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","name":"node_e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","enode":"enode://45396d74120c86243ba2a5201eb5c426df1e01a818cab326b1f835329328113dcbfc080c8d30f25d4b3100a6881df18cbedf46901fa1eba42e8b67217a03b6d4@127.0.0.1:0","enr":"0xf88fb840ef39cfe61b95ba34b613f30b0c843f8b08e7b8d7e1612460f235e2864e40110d59b1705cfc07c7f088345f97da1704cd0b1336fe5f79ef916551e2f99d9573240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10245396d74120c86243ba2a5201eb5c426df1e01a818cab326b1f835329328113d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5a2gQVyS7xURsV0E7fOVl2Rkr9mtw+kpxB1NIdJeMYI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5ada0\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 02d8 1400 30be 5b63 | 146 13d6 (0) 11d4 (0) 103b (0) 1672 (0)\n001 4 88fe b502 b5b2 b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 7 d7ac d640 caf6 ca04 | 26 df1e (0) d887 (0) d863 (0) db6a (0)\n003 3 fe21 f2d5 f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 3 ec52 efea e8ef | 10 ee5e (0) ef1b (0) ef07 (0) efea (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e775 (0) e7fa (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 3 e514 e54b e547 | 3 e514 (0) e54b (0) e547 (0)\n009 1 e5d7 | 1 e5d7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","private_key":"412a46a21e6ae42d21149e1e5a99ab8147be24ca5ca741bc0806394903c6a4e9","name":"node_e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","services":["streamer"],"enable_msg_events":true,"port":44795},"up":true}},{"node":{"info":{"id":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","name":"node_30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","enode":"enode://d4938f13c3e1a21366991a0040a5de8e8d3200ec4fa2e95ebd57bf291ae843e2e484f992690d2fbbc475b3fbf3d9ac44d29ff8b2bfaced1a76f0fca80a1e8499@127.0.0.1:0","enr":"0xf88fb840eff44640732004cd295f6d11cea92ed4934e714036a514bc63ea49a498010ad0630d6f351de844e1ad07c248cb15476b934e9ae674722be12109c12fceb667440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d4938f13c3e1a21366991a0040a5de8e8d3200ec4fa2e95ebd57bf291ae843e2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ML7HzQp9ACg5rtdlQSm9L+Lizn9CqnuuFWDov3GJVMM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 30bec7\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b626 d7ac c786 c59e | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 10 5b63 53a8 512e 49cd | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 6 02d8 0d8a 1400 1f85 | 44 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n003 6 20ae 217f 24b8 256e | 15 20ae (0) 21a0 (0) 2101 (0) 217f (0)\n004 2 3b88 3ec5 | 7 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n005 3 3630 3780 378e | 4 35e6 (0) 3630 (0) 378e (0) 3780 (0)\n006 2 3237 33b5 | 3 3373 (0) 33b5 (0) 3237 (0)\n============ DEPTH: 7 ==========================================\n007 1 314a | 1 314a (0)\n008 0 | 0\n009 0 | 0\n010 1 3089 | 1 3089 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","private_key":"457e22ce24b3272b31f979367cff7d1675ce728dd8758a7e66779eab01b1f39a","name":"node_30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","services":["streamer"],"enable_msg_events":true,"port":40077},"up":true}},{"node":{"info":{"id":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","name":"node_6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","enode":"enode://e2ff496895056d4524e8809a260658da6ceec4c10793af4bcb6c057c8e49b09e58f567ba6f5276f0b7f0a77d9fdf7faa3240a2bd679395fcedabee5b9f3351a7@127.0.0.1:0","enr":"0xf88fb84070b049df191da1faabfd595e42918747d388a4aefef434acda7b08e59e72eef27c77b287320a2242d7483326ca4c879b2a973a90e8de4f7d318ae7837f2485a20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e2ff496895056d4524e8809a260658da6ceec4c10793af4bcb6c057c8e49b09e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"b+mgLpUKXDpf8Ca3WSLtaH1ZeVuo65wJKo0JpcZNJFM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6fe9a0\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 e8ef e5ad c49c c786 | 110 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n001 4 02d8 1400 1b83 30be | 76 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n002 9 53a8 512e 5f00 5b63 | 38 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n003 3 7290 7b90 7a60 | 12 775e (0) 77d2 (0) 7125 (0) 738c (0)\n004 5 66e7 67aa 6337 6103 | 9 66e7 (0) 67dc (0) 67aa (0) 6251 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 4 6e05 6e68 6ea5 6ecb | 4 6ea5 (0) 6ecb (0) 6e68 (0) 6e05 (0)\n============ DEPTH: 8 ==========================================\n008 2 6f5f 6f2d | 2 6f5f (0) 6f2d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","private_key":"879ee7d6a5c3b9955ff62eaf879fe7b1cfccac856af66e529973919c66e623fc","name":"node_6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","services":["streamer"],"enable_msg_events":true,"port":39807},"up":true}},{"node":{"info":{"id":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","name":"node_b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","enode":"enode://bcb24f203bc073123e592cbe910596246943b55a8b23f83c44d9a9792ce617b3881167f7ea10979b8e0edbb7477d3caa2536b87ab288635a7f606b7f12e6fdf6@127.0.0.1:0","enr":"0xf88fb840bb20ffbb4f9e317c0920fd1e3c9ab49f236431a644b4ed2d281206876654ea5175878382b830f9312bf112a8799f0609ac8d280355c23d6062b4299a6d4957d40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bcb24f203bc073123e592cbe910596246943b55a8b23f83c44d9a9792ce617b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tibUcrVV5vlQpxQng9uN60Q6dOY+9r1yqH6vGvFMqAU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b626d4\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 02d8 30be 5b63 53a8 | 146 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n001 11 f2d5 e8ef e547 e5ad | 63 fbc8 (0) fbf5 (0) f925 (0) fe31 (0)\n002 5 915d 959f 976e 82f9 | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 3 ac4d a6fb a653 | 10 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n004 4 b95d ba88 badd baf2 | 9 bcc6 (0) b820 (0) b897 (0) b911 (0)\n005 2 b02b b2b5 | 3 b02b (0) b2a5 (0) b2b5 (0)\n006 2 b5b2 b502 | 2 b502 (0) b5b2 (0)\n============ DEPTH: 7 ==========================================\n007 1 b7ca | 1 b7ca (0)\n008 0 | 0\n009 1 b65e | 1 b65e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","private_key":"a8c00eca98c6cb671796a4d64ed46a6e68a4299a429d774c69674a2844e1b7eb","name":"node_b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","services":["streamer"],"enable_msg_events":true,"port":45367},"up":true}},{"node":{"info":{"id":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","name":"node_d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","enode":"enode://af8ad49dda536a983269aeea2d7dca08e480fe8314968145e98dc97cd7b009ed461036eccaa3b638ee49d16e627b2234eb3f362ec7d15abc46e5c36b54e53638@127.0.0.1:0","enr":"0xf88fb840e94ce96dfda68df3191de91c495debd7006cfc51027649581bd11c598e9ab2f214d984a700cab94c2e6de920ccb7f73533a32c3f8dfb71f22d53f5e21ffd7b320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102af8ad49dda536a983269aeea2d7dca08e480fe8314968145e98dc97cd7b009ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"16yo8hgrxiXSs8lCvRFhyFvPHCs07L4+L9I8+ua4qHE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d7aca8\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 30be 7a60 6fe9 5b63 | 146 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n001 3 88fe b5b2 b626 | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 9 e8ef ec52 e547 e5ad | 37 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n003 8 ca04 caf6 c26f c786 | 15 cc20 (0) c898 (0) c832 (0) c9f5 (0)\n004 4 df1e d863 da67 db6a | 6 df1e (0) d887 (0) d863 (0) db6a (0)\n============ DEPTH: 5 ==========================================\n005 3 d1d7 d3b0 d299 | 3 d1d7 (0) d3b0 (0) d299 (0)\n006 0 | 0\n007 1 d640 | 1 d640 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","private_key":"0301a81bf982f07c1bb98bf99f353b8d2a82b03e69c21e1d74c8ceaad8396be0","name":"node_d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","services":["streamer"],"enable_msg_events":true,"port":34989},"up":true}},{"node":{"info":{"id":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","name":"node_4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","enode":"enode://518d6f5949bd69109142c1b8c458304de346817905a7cffb3be16be375f045f0c8d104d1d8dfeb19c79400877a63ad2ee8e87d9a1f57ce8f80ae645cbf4eef67@127.0.0.1:0","enr":"0xf88fb8406bb867b351cac2f28189ea4e9784fdf036ef21c4f2f01e0e0219a597544f9e026023632fca76371095ae079ec4432604b31db489477ff2bcb07772cf56116cc20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103518d6f5949bd69109142c1b8c458304de346817905a7cffb3be16be375f045f0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SsdVEj3MZO9E25KAMRr1Hz96k+De5nNw1nMmEiA1brk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4ac755\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b5b2 b626 e8ef d7ac | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 5 0d8a 1400 1b83 3780 | 76 13d6 (0) 11d4 (0) 103b (0) 1672 (0)\n002 3 7b90 7a60 6fe9 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 4 5f00 5b63 512e 53a8 | 15 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n004 4 4447 4558 46fe 47bf | 12 41d9 (0) 4109 (0) 44a1 (0) 4447 (0)\n005 2 4c9e 4d6b | 5 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n006 3 4990 49ea 49cd | 3 4990 (0) 49ea (0) 49cd (0)\n============ DEPTH: 7 ==========================================\n007 1 4bcf | 1 4bcf (0)\n008 0 | 0\n009 1 4a8b | 1 4a8b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","private_key":"f8fa80aec89f65eae7ced03937bb7d9ffb1cfecd1ac8217600cf47c3bff7bfed","name":"node_4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","services":["streamer"],"enable_msg_events":true,"port":38749},"up":true}},{"node":{"info":{"id":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","name":"node_c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","enode":"enode://3909a562bce9e929066fb8e20922518612b890356bb3e697259c816e2517f826e527c1899afe88e6b7c605624fb9260ec468201d8baa1e17fc0ca07e1629ac74@127.0.0.1:0","enr":"0xf88fb84055d8b49729febc40ab5a07b226db8df1a30bab38bbffbcdf525ad479d3d859e360ab5dcb1431b296f0eeaff955d7f74ddc76c4af156067256afe7dd5d718293e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023909a562bce9e929066fb8e20922518612b890356bb3e697259c816e2517f826","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xZ45U7ZOW5/75TmQo1iRTy+o41UdM/krnjpEG9G68s0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c59e39\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 30be 47bf 4ac7 | 146 0b72 (0) 0a00 (0) 0af9 (0) 0fc5 (0)\n001 4 959f 88fe b5b2 b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 3 e8ef e547 e5ad | 37 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n003 6 da67 d863 df1e d299 | 11 df1e (0) d887 (0) d863 (0) db6a (0)\n004 2 ca04 caf6 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 3 c786 c620 c6cf | 3 c620 (0) c6cf (0) c786 (0)\n============ DEPTH: 7 ==========================================\n007 3 c43f c441 c49c | 3 c43f (0) c441 (0) c49c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","private_key":"2d2665fd12ac020bb8aa6997cba5174e95d07b7f2dd9687d68abd431a6133895","name":"node_c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","services":["streamer"],"enable_msg_events":true,"port":42839},"up":true}},{"node":{"info":{"id":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","name":"node_47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","enode":"enode://99a8f99fc0cfe5ad73c6d3c6784bd3c8a36e664d0c586724f2a5dacd88ae1de2c2b2afe39786236af913ea9ea1d6f81726598d4fedf4f9698bc4d622dfa74456@127.0.0.1:0","enr":"0xf88fb84003f4b14b4db4abd57728bdc34701e10c40aa56b4937b21e60de55c6e0dc32a4e429766f47337d209a05d753ba33fb2e781dbccc3dece305fca6b5aa020f556b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10299a8f99fc0cfe5ad73c6d3c6784bd3c8a36e664d0c586724f2a5dacd88ae1de2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R7+jdnzvzAgx1BDVQC6TluikEsjJb69VtFHT/zEPOwI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 47bfa3\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 88fe b5b2 b626 e8ef | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 2 3780 30be | 76 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n002 3 6e05 6fe9 7a60 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 4 5f00 5b63 512e 53a8 | 15 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n004 3 49cd 4a8b 4ac7 | 11 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n005 2 41d9 4109 | 2 41d9 (0) 4109 (0)\n006 4 44a1 4447 4559 4558 | 4 4559 (0) 4558 (0) 44a1 (0) 4447 (0)\n============ DEPTH: 7 ==========================================\n007 4 4646 4636 461c 46fe | 4 4646 (0) 461c (0) 4636 (0) 46fe (0)\n008 0 | 0\n009 0 | 0\n010 1 4782 | 1 4782 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","private_key":"e14e52fa9b610fd29123ec266b01cb4554f23f0985eaf4f397ee8e36da9fb734","name":"node_47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","services":["streamer"],"enable_msg_events":true,"port":36519},"up":true}},{"node":{"info":{"id":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","name":"node_53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","enode":"enode://7cb2f74beeafb23eb1c3733aa06b15fcf9ec81c7bcd0c7fca13880190575b2efc50576733e125720aa8ca507c8763d15fc8c6a2d45ece04586cec04a52cf219f@127.0.0.1:0","enr":"0xf88fb8406637aa6250f6d822fa890a388e4a0568c5ba66b7f182fc1e3bde5ea9387252335b403469fdffbc037d26e4abdb86926c506f134f6bb74408cd656037fe7f8a250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037cb2f74beeafb23eb1c3733aa06b15fcf9ec81c7bcd0c7fca13880190575b2ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U6iFlo1o2Ov37VFOZizBP6AxhtI2EACgNXZTH9yiol8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 53a885\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 88fe b5b2 b626 c49c | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 7 1400 0d8a 02d8 0438 | 76 0661 (0) 0743 (0) 07a8 (0) 0451 (0)\n002 6 67aa 6fe9 6e05 7290 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 8 49cd 4a8b 4ac7 4558 | 23 4e5a (0) 4d10 (0) 4d6b (0) 4d59 (0)\n004 4 5f00 5efb 5b63 5823 | 7 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n005 1 574f | 1 574f (0)\n006 2 51db 512e | 2 51db (0) 512e (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 534b 5308 | 2 534b (0) 5308 (0)\n009 1 53fe | 1 53fe (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","private_key":"969e9079ff9417e9019194be48bd5ca8390e4b1da63300776d6ba493e5b0e3df","name":"node_53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","services":["streamer"],"enable_msg_events":true,"port":34549},"up":true}},{"node":{"info":{"id":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","name":"node_e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","enode":"enode://61681c2fcd285866105bfa4d3e47a2c7d765368cde74a62218935aecf0fd15966a88226b5f12e371f41954a0063b806cce53468884b34e817120d5b41386fe22@127.0.0.1:0","enr":"0xf88fb840276c3036a03aa8627db3a54002f6257878aa8046c3174fd3a3052160dafc7a8445e68a88d8bfd35ff1174b47c53c3fec471867db75b9f0670a68993bcf09c1f40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261681c2fcd285866105bfa4d3e47a2c7d765368cde74a62218935aecf0fd1596","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6O/oAW/mz2SbJ1W+4i2jXMxsnFXUBNU4XWH26ie4Q4A=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8efe8\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 30be 7a60 6fe9 4ac7 | 146 13d6 (0) 103b (0) 11d4 (0) 1704 (0)\n001 4 88fe baf2 b626 b5b2 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 6 caf6 c49c c59e da67 | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 4 f2d5 f629 f7fa f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 5 e027 e7fa e547 e5d7 | 8 e027 (0) e775 (0) e7fa (0) e514 (0)\n005 6 ee5e ef1b ef07 efea | 6 ee5e (0) ef1b (0) ef07 (0) efea (0)\n006 1 eb98 | 1 eb98 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 e854 | 1 e854 (0)\n009 1 e883 | 1 e883 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","private_key":"8ce9e530f5c91869432f678c7427fbcae8495679b569edd4de349825b348c94a","name":"node_e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","services":["streamer"],"enable_msg_events":true,"port":41325},"up":true}},{"node":{"info":{"id":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","name":"node_d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","enode":"enode://17dda987ab35c708fe928fd6daff3da8a18784789c581cb861079dca3d05584c6516824bb15729d0d6e4ca77908c3ae96a4a8f8edfb415eef4f9f31481e0b2cf@127.0.0.1:0","enr":"0xf88fb8401e90e884b49904ec677447f4c5edbe69de30ec6df088f673b1b613313d66a2c30ec1b3b452bf12152b16f4361f665f5cbce63a6f2680effd69ef9dcda94114440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10317dda987ab35c708fe928fd6daff3da8a18784789c581cb861079dca3d05584c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1kBHI1GWmlV45UGspyt2QMWDuZX9YmB/8+4/PzE5qv0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d64047\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 47bf 53a8 | 146 13d6 (0) 11d4 (0) 103b (0) 1672 (0)\n001 4 b626 b5b2 915d 88fe | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 7 f629 f2d5 e5d7 e5ad | 37 fbc8 (0) fbf5 (0) f925 (0) fe31 (0)\n003 8 c9f5 ca04 caf6 c26f | 15 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n004 4 df1e d863 db6a da67 | 6 df1e (0) d887 (0) d863 (0) db6a (0)\n============ DEPTH: 5 ==========================================\n005 3 d299 d3b0 d1d7 | 3 d1d7 (0) d3b0 (0) d299 (0)\n006 0 | 0\n007 1 d7ac | 1 d7ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","private_key":"7dda4f1f1b00b27dcba963ca38a79091c69eacbc993590b9774b515e9138ddca","name":"node_d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","services":["streamer"],"enable_msg_events":true,"port":39283},"up":true}},{"node":{"info":{"id":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","name":"node_c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","enode":"enode://0c6d8311b47b26830eeecd5200414fb26fc1147f01b938dcc610c2407af63cf617079655416b03336b0695f7ed5d42efc11803d5dbee44fd5d05c487921f1548@127.0.0.1:0","enr":"0xf88fb840154c57974260b37e441e6874dff8009220b1b7cb71ed9271d0543f018a32274012616ddf46d4aec53d939099c377e0f189c1c9259858e7ec80a7c1e23fb1c6520183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c6d8311b47b26830eeecd5200414fb26fc1147f01b938dcc610c2407af63cf6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xJyv8Thi3AifH5uBgNbvpFVkg3VmJxknIQLE+AKHmdY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c49caf\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7a60 6e05 6fe9 53a8 | 146 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n001 5 915d 88fe b65e b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 8 f2d5 f629 f7fa e5d7 | 37 e027 (0) e775 (0) e7fa (0) e514 (0)\n003 5 df1e da67 d863 d7ac | 11 df1e (0) d887 (0) d863 (0) db6a (0)\n004 2 ca04 caf6 | 6 cc20 (0) c898 (0) c832 (0) c9f5 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 2 c6cf c786 | 3 c620 (0) c6cf (0) c786 (0)\n007 1 c59e | 1 c59e (0)\n============ DEPTH: 8 ==========================================\n008 2 c441 c43f | 2 c43f (0) c441 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","private_key":"751d508bcd33604fcc32799146ee07845fc1159580d23d46d4c8f86939cfd368","name":"node_c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","services":["streamer"],"enable_msg_events":true,"port":35349},"up":true}},{"node":{"info":{"id":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","name":"node_caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","enode":"enode://032b6cb479ba63501feaba6ea9a5a1c0a5952e228ce6223a71ce74de13ee98d0b1f5167229e9609313ed643e1dbf3ff6124ec3c1158ea76885378b1867f90d54@127.0.0.1:0","enr":"0xf88fb8405c6b6d2ebf985d21c8d0ac47d9fde8e7bb43b8b2dcc9731ed7adea09b973a34f1407c6d0801c18739521dc7e60fd663a0f8888a1dfd86e3d8284aab6b811246e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102032b6cb479ba63501feaba6ea9a5a1c0a5952e228ce6223a71ce74de13ee98d0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yvao43/UHB5q13qFdc2QNUuxaTiTlSMBycrrR3nDONM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: caf6a8\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3780 6e05 53a8 4447 | 146 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n001 5 915d 88fe b65e b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 9 e8ef ec52 e5ad e5d7 | 37 e027 (0) e775 (0) e7fa (0) e514 (0)\n003 4 d863 db6a d7ac d640 | 11 d887 (0) d863 (0) db6a (0) daec (0)\n004 7 c26f c6cf c786 c59e | 9 c1f9 (0) c26f (0) c620 (0) c6cf (0)\n005 1 cc20 | 1 cc20 (0)\n============ DEPTH: 6 ==========================================\n006 3 c9f5 c898 c832 | 3 c9f5 (0) c898 (0) c832 (0)\n007 0 | 0\n008 1 ca04 | 1 ca04 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","private_key":"7404cb8ddf7d531f80b522df15471c04183be2225349a44f9f07d118e9b508be","name":"node_caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","services":["streamer"],"enable_msg_events":true,"port":37023},"up":true}},{"node":{"info":{"id":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","name":"node_b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","enode":"enode://6ba4f9939fe79c2fa62906da87f6145579ce26244c232ef3a0ee23ceb8298c98cefef00b37faae81fc5535255f16604e5be09f2a544cb2dd1007f489ca73d910@127.0.0.1:0","enr":"0xf88fb840a537a74b55567b80ec626e0a4a8e8e4515acc8a9fe9b893068e006a292c9609609a11873cee2c6bff37d1b5e2b0406d5b61c997e3a28f76fa0a3f561d6d293810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ba4f9939fe79c2fa62906da87f6145579ce26244c232ef3a0ee23ceb8298c98","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tbJFMtKBDjEeELHWBrr2AH+RJLiKF4sycTzx7drgib4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5b245\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 53a8 4ac7 4447 47bf | 146 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n001 9 f2d5 e5ad e8ef d7ac | 63 e027 (0) e775 (0) e7fa (0) e514 (0)\n002 6 959f 96fc 976e 915d | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 4 ac4d ad98 a6fb a653 | 10 ae2b (0) aeb4 (0) af02 (0) ad98 (0)\n004 3 ba88 badd baf2 | 9 bcc6 (0) b911 (0) b95d (0) b820 (0)\n005 3 b02b b2a5 b2b5 | 3 b02b (0) b2a5 (0) b2b5 (0)\n============ DEPTH: 6 ==========================================\n006 3 b65e b626 b7ca | 3 b7ca (0) b65e (0) b626 (0)\n007 0 | 0\n008 1 b502 | 1 b502 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","private_key":"bb9cccb7fbaaf1b02e691345fdc13fbfb49ed17129b679b20e4cd008ed173b26","name":"node_b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","services":["streamer"],"enable_msg_events":true,"port":35555},"up":true}},{"node":{"info":{"id":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","name":"node_88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","enode":"enode://d002db12f24e09a012d47d716f63576d836cb4e6af9bbc4c563fffdeb4fb138675904bd4ee8ae0325a2be23e1017032cbda9124ba121b6df6bf3f129d4101cf4@127.0.0.1:0","enr":"0xf88fb840595a1f1435cf159c616f21eb11caab1ff821b51aa99b5f08bccb592945e7e073140d4625a0d25290d1a867fe36afe9b7b9740c374a72727f3375d7c9b75013190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d002db12f24e09a012d47d716f63576d836cb4e6af9bbc4c563fffdeb4fb1386","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iP77dQYQXA4mm69SlVoBsZ9VUEsTEzusC+q0HJ9uaUI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 88fefb\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6e05 512e 53a8 4447 | 146 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n001 9 f7fa f2d5 e5ad e8ef | 63 d887 (0) d863 (0) db6a (0) daec (0)\n002 6 a653 baf2 b65e b626 | 27 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n003 5 9d0f 959f 96fc 976e | 10 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n004 5 849b 8505 8025 82dd | 5 8505 (0) 849b (0) 8025 (0) 82dd (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 898d | 1 898d (0)\n008 1 886a | 1 886a (0)\n009 1 88a1 | 1 88a1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","private_key":"60486eb333333a142330c9bf765d7fb5ea28918c3185e0013df6b65a50992256","name":"node_88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","services":["streamer"],"enable_msg_events":true,"port":36621},"up":true}},{"node":{"info":{"id":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","name":"node_37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","enode":"enode://ebdc2cb76ffdb28b7bc171d5210f6b3747caf9ef2a30848b043adff7d009ffbbd7e98427ef4035a46cbd69fd4f3f584d1d8f3bb96e36d865e626e4d9c82e4a91@127.0.0.1:0","enr":"0xf88fb8407932c8f5686fbbe250ac8a2d185c457889e6e4a89dce92326c0617685aa6f95212bd56382e464dac57d4be61991248c9485e070205d6e4065e47d40a1ad024860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ebdc2cb76ffdb28b7bc171d5210f6b3747caf9ef2a30848b043adff7d009ffbb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"N4AejX1GFD94kk7WYJn2WKlNN+39L1jQKsuFrdA+GJQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 37801e\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f2d5 caf6 c441 c49c | 110 db6a (0) daec (0) da67 (0) d887 (0)\n001 6 53a8 4ac7 49cd 47bf | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 5 1b83 02d8 0438 0cf5 | 44 103b (0) 11d4 (0) 13d6 (0) 1672 (0)\n003 6 256e 20ae 217f 2a0a | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 3 3b88 3efc 3f94 | 7 39d1 (0) 3b78 (0) 3b88 (0) 3e8e (0)\n005 4 3373 314a 3089 30be | 6 3237 (0) 33b5 (0) 3373 (0) 314a (0)\n006 1 35e6 | 1 35e6 (0)\n============ DEPTH: 7 ==========================================\n007 1 3630 | 1 3630 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 378e | 1 378e (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","private_key":"369eb71eeb7b71c096c321177228fa31e9c9a28aa40a86cbfa645ba35b159f4f","name":"node_37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","services":["streamer"],"enable_msg_events":true,"port":46281},"up":true}},{"node":{"info":{"id":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","name":"node_915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","enode":"enode://22e79b248e289cce0fc5fa7dca0ce3cfdb2050b0151cc1435e3c0023cd1a07de7719d47f0dd8db4755266a2ec1bac0074f9753c8999c21cc1bcb5bf2f3abcd24@127.0.0.1:0","enr":"0xf88fb84078cc030ac8045a0e60c0ae70e0eb9bb3fd12770df422402905e64920ed3a568e19abd70ff4ea28b81fd7266a1eda7bb7aa25062222117467acd36f13d37fd78a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10222e79b248e289cce0fc5fa7dca0ce3cfdb2050b0151cc1435e3c0023cd1a07de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kV16BRC60ZJm7vjwDKDLLvw0AlN3VwZJX8qLkWC1Esw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 915d7a\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 512e 4558 4447 6e05 | 146 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n001 10 f2d5 f7fa f629 ec52 | 63 d887 (0) d863 (0) db6a (0) daec (0)\n002 4 a653 baf2 b626 b5b2 | 27 af02 (0) aeb4 (0) ae2b (0) ad98 (0)\n003 4 82f9 898d 886a 88fe | 10 8505 (0) 849b (0) 8025 (0) 82dd (0)\n004 2 9fa0 9d0f | 4 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n005 3 96fc 976e 959f | 3 96fc (0) 976e (0) 959f (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 9076 90a8 | 2 9076 (0) 90a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","private_key":"46f8ff7c336416d502bd2c3ba10235eec55193182d1b1c0e74fc4763e2f12cb2","name":"node_915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","services":["streamer"],"enable_msg_events":true,"port":37115},"up":true}},{"node":{"info":{"id":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","name":"node_6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","enode":"enode://6cb33a608378cb32052368b80030aab00ffa4d25aeab3b017a18abcc39e2a8ca270fc88bfbe418dd31d426abd53107fdd99fcc230eb92632b5444644f101ac7c@127.0.0.1:0","enr":"0xf88fb8408e844dc2f0db4b3e2208b2adec83b24a99e19229c8902879c8c81877e506b4e32d3209a9af0119e2aa59342192dba0e72b3c74064f9f23a08ae09aa91199fb080183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026cb33a608378cb32052368b80030aab00ffa4d25aeab3b017a18abcc39e2a8ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bgUXnckKj2ZU0Mmj8GFzNx3PsYuFL9138191448nMSU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e0517\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 c49c c441 caf6 f2d5 | 110 db6a (0) daec (0) da67 (0) d887 (0)\n001 5 0743 0438 217f 2ccf | 76 103b (0) 11d4 (0) 13d6 (0) 1672 (0)\n002 5 53a8 5f00 5b63 47bf | 38 5823 (0) 58ed (0) 5b63 (0) 5cd2 (0)\n003 2 7b90 7a60 | 12 775e (0) 77d2 (0) 7125 (0) 738c (0)\n004 4 67aa 6103 60d7 6337 | 9 66e7 (0) 67dc (0) 67aa (0) 6103 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 3 6fe9 6f2d 6f5f | 3 6f2d (0) 6f5f (0) 6fe9 (0)\n============ DEPTH: 8 ==========================================\n008 2 6ea5 6ecb | 2 6ea5 (0) 6ecb (0)\n009 1 6e68 | 1 6e68 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","private_key":"1b7026a2b010aecd3db0637e03b2e0cf0bddfa9b0ad9d677056e091a03970305","name":"node_6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","services":["streamer"],"enable_msg_events":true,"port":35543},"up":true}},{"node":{"info":{"id":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","name":"node_f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","enode":"enode://0bed55a524855cf4b0ffa7a813b7cbbe61499512bd4579832af6444cce55217dc68f57f430feed9ef8214a49dbe0779600980fe1fa51afe837f8a9185d799ee6@127.0.0.1:0","enr":"0xf88fb84037c16835f858e5ccd867b9239f718531d6980f0b8d13d0eb0407dee672e37425392b42e2a352333d146fbebe5306020187121998d97f4caa33944a2667c4010c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020bed55a524855cf4b0ffa7a813b7cbbe61499512bd4579832af6444cce55217d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8tVTPu1LDBhJUthZ1n5Eq+WnWl3mERyMEGuPSy2Mz8Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f2d553\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3780 217f 2ccf 4447 | 146 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n001 8 88fe 915d 959f a653 | 47 af02 (0) aeb4 (0) ae2b (0) ad98 (0)\n002 7 d863 d7ac d640 c49c | 26 d1d7 (0) d3b0 (0) d299 (0) d7ac (0)\n003 6 ef07 ef1b e8ef e547 | 18 e027 (0) e775 (0) e7fa (0) e514 (0)\n004 3 fe31 fe21 ff36 | 6 f925 (0) fbc8 (0) fbf5 (0) fe21 (0)\n005 7 f4e0 f5dc f528 f629 | 10 f456 (0) f45f (0) f4e0 (0) f5b2 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f31c | 1 f31c (0)\n008 1 f27f | 1 f27f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","private_key":"6e3b2aeb1f3f715a86807af2cd2090519998b92df4dfd138d51b3cce2526dbb0","name":"node_f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","services":["streamer"],"enable_msg_events":true,"port":44807},"up":true}},{"node":{"info":{"id":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","name":"node_444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","enode":"enode://9ef94c855735b705843c447b2998afbb14eb30166ca1c8dbc09b763fa8e04e67376ebc830d745404753f08b76f454e3948b4546c340209c1d2e4739e170a8bec@127.0.0.1:0","enr":"0xf88fb84033c73ee216ccaa7cd66408fa60642ea37fcf44ff76073b098a962c13f1a4df8a4ce4188d4a34a26de1df6c40daa70adfb66850b5cf39eeda6218fabb91bf4ea70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029ef94c855735b705843c447b2998afbb14eb30166ca1c8dbc09b763fa8e04e67","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"REcioVsBoNjmeUeY0jn+Yh1ZvfwIgjq0fL2Lms69I7Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 444722\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 915d 88fe b5b2 b65e | 110 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n001 9 1a2a 0438 0cf5 3780 | 76 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n002 4 6337 6fe9 6ecb 6e05 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 5 5db0 5f00 5b63 512e | 15 5823 (0) 58ed (0) 5b63 (0) 5cd2 (0)\n004 3 49cd 4ac7 4a8b | 11 4e5a (0) 4d59 (0) 4d6b (0) 4d10 (0)\n005 2 4109 41d9 | 2 41d9 (0) 4109 (0)\n006 6 4646 4636 461c 46fe | 6 4646 (0) 4636 (0) 461c (0) 46fe (0)\n============ DEPTH: 7 ==========================================\n007 2 4559 4558 | 2 4559 (0) 4558 (0)\n008 1 44a1 | 1 44a1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","private_key":"1a57d82b5818ffcf64fda640f5ed8c9fc1578d29faabdd9297f9bafcedf16afc","name":"node_444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","services":["streamer"],"enable_msg_events":true,"port":36309},"up":true}},{"node":{"info":{"id":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","name":"node_c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","enode":"enode://9cef4cd1c3b7a978ced64f36c0c3a9098aba2c07c45787c884a7946e6d21976321f7c05ebe7abfd92c63f1ca54c46acddb27b2c6bfd01759cb09c78a4ec0544f@127.0.0.1:0","enr":"0xf88fb8400693860ca7cd4d67ebdb615eaaf42fa1ae8f5ff87a593cd0ad7e2a34020e6e2748358c72363e272974698017a897ccbb600b0be698450de6df9d6870ed976fa10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039cef4cd1c3b7a978ced64f36c0c3a9098aba2c07c45787c884a7946e6d219763","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xEHSel9KuqjjsPBApu+Fu4yXADHWpXUDpnTjaz1pFdk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c441d2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2ccf 217f 3780 6e05 | 146 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n001 5 898d 959f 915d b65e | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 5 f2d5 f629 f7fa ec52 | 37 ee5e (0) efea (0) ef1b (0) ef07 (0)\n003 4 d863 df1e d640 d7ac | 11 d3b0 (0) d299 (0) d1d7 (0) d7ac (0)\n004 4 ca04 caf6 c9f5 c832 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 3 c620 c6cf c786 | 3 c620 (0) c6cf (0) c786 (0)\n007 1 c59e | 1 c59e (0)\n============ DEPTH: 8 ==========================================\n008 1 c49c | 1 c49c (0)\n009 1 c43f | 1 c43f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","private_key":"a67d3fd0aeb245cdd802262166fd8226b4f6034f416053f7ef9956a99c473419","name":"node_c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","services":["streamer"],"enable_msg_events":true,"port":37581},"up":true}},{"node":{"info":{"id":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","name":"node_baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","enode":"enode://1c3d285d17974092dcbdb97e35e1885bbf94addb9dba5954e71c3ffc7348c4c58fdbf99598683dd6298c32ebaa5e7220e01715f4f5d2907af981f3b3167bdcce@127.0.0.1:0","enr":"0xf88fb840753f3903e7fa19460a5e7e20abc7555ba49cf8d52c7bbccd74918fc7f82461cb1e68b9970b23609530b70fd3059329b633f8639230949e4fe2cbdcd6af87edc40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021c3d285d17974092dcbdb97e35e1885bbf94addb9dba5954e71c3ffc7348c4c5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uvIZ6SKZIbdz0a1+t+tSFs+mDM7Ko8XEh+O3HLYAuhI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: baf219\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6e05 4447 3780 217f | 146 7125 (0) 738c (0) 7290 (0) 77d2 (0)\n001 6 f2d5 e5d7 e8ef ec52 | 63 eb98 (0) e854 (0) e883 (0) e8ef (0)\n002 3 88fe 915d 959f | 20 8505 (0) 849b (0) 8025 (0) 82dd (0)\n003 3 ad98 ac4d a653 | 10 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n004 5 b2b5 b502 b5b2 b626 | 8 b02b (0) b2a5 (0) b2b5 (0) b502 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 b897 b95d b911 | 4 b820 (0) b897 (0) b95d (0) b911 (0)\n007 1 bb90 | 1 bb90 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 ba88 | 1 ba88 (0)\n010 1 badd | 1 badd (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","private_key":"a5e1aa7f7374964afa85de3c3c1b2fa8a1caf2a27cf7be2844136deaf4f0ffa7","name":"node_baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","services":["streamer"],"enable_msg_events":true,"port":40635},"up":true}},{"node":{"info":{"id":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","name":"node_2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","enode":"enode://f81b4d7e1b4722dad58825039b3c38ddbebefc1a236c2080a520401e9483f6584433e2692ec15fcdc707d03bb9a6bf0ff7c912be023789af49c0a309da7631d4@127.0.0.1:0","enr":"0xf88fb8408bebaa03804d729c21adf92503814a0abf62421bf5f9a3830e95f47bcbf6fdb235a690cfd4e81ca66a5934af140d762788ac0f9c110afd2a54400eb8429453320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f81b4d7e1b4722dad58825039b3c38ddbebefc1a236c2080a520401e9483f658","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LM+1sfOSPTX++Ig4xQi5i1UWxdQJZDiB0jBK5J5Q7tM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2ccfb5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c441 ec52 f7fa f2d5 | 110 fbc8 (0) fbf5 (0) f925 (0) fe31 (0)\n001 4 6337 6e05 49cd 4447 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 7 1b83 1c47 0438 02d8 | 44 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n003 3 30be 3089 3780 | 17 3e8e (0) 3efc (0) 3ec5 (0) 3f94 (0)\n004 5 256e 24b8 20ae 2101 | 6 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n005 4 2995 2a0a 2abb 2a97 | 4 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n006 1 2f32 | 1 2f32 (0)\n007 1 2d36 | 1 2d36 (0)\n============ DEPTH: 8 ==========================================\n008 2 2c79 2c38 | 2 2c79 (0) 2c38 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","private_key":"056d524a765c48a6c1ab41c42f6cf836183cf10b73481f79cc49b79a3f6b5769","name":"node_2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","services":["streamer"],"enable_msg_events":true,"port":43231},"up":true}},{"node":{"info":{"id":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","name":"node_217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","enode":"enode://37f0965106672daa2a8e343623357ad538b5115d0f80fe74ef78f1d21863978762f82a776b97a1ea718ac52944af0a9e3c616d9f0c89f719a5aa940dd5b27a05@127.0.0.1:0","enr":"0xf88fb840f5488dc6acca9725c22fa1877fdf275cc7fc44feb78fb19f3cc4d712b78fa4820df8834c815cd7f6aeda861ba2236c7d6b425861780f726bd4f1277b707c2f390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10337f0965106672daa2a8e343623357ad538b5115d0f80fe74ef78f1d218639787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IX+ZUq8etY1cpax752NxbP4sCk883U6+S131Y/kZ4tI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 217f99\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c441 f7fa f2d5 ec52 | 110 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n001 4 6337 6e05 49cd 4447 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 3 0cf5 03cc 0438 | 44 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n003 4 3089 30be 3630 3780 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3e8e (0)\n004 6 2995 2a97 2a0a 2d36 | 9 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 20ae | 1 20ae (0)\n008 1 21a0 | 1 21a0 (0)\n009 1 2101 | 1 2101 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","private_key":"2713b4b4549ba404d31cc2bc1f2bef523f8e70e0d00cca2667bb393532c2ec78","name":"node_217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","services":["streamer"],"enable_msg_events":true,"port":36795},"up":true}},{"node":{"info":{"id":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","name":"node_0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","enode":"enode://2a609a2f7bee18e9ace30fb43ae2c4440d114f3c4888ec0a34d24ebd1fa6156d633c4f2aa0f3eaed2db3abdc5fd1f634fb8a511fce8c719cde7248d202de66df@127.0.0.1:0","enr":"0xf88fb8408d5e6847e83be24d36a5259f7935a065f251552352ee158a5edfa798e6e86fbe00cbbc7bc7f90319931c1b7398f3e81894b504f3abfde6bcdec7daa4a90062350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032a609a2f7bee18e9ace30fb43ae2c4440d114f3c4888ec0a34d24ebd1fa6156d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BDj1ZwRdRVag56aXAo1ons/QriD56FwJtI2fH9DuR2U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0438f5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f7fa e5d7 b65e 959f | 110 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n001 4 53a8 4447 6e05 6337 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 4 3780 3089 2ccf 217f | 32 3b88 (0) 3b78 (0) 39d1 (0) 3f94 (0)\n003 6 1704 1400 1b83 1a2a | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 5 0b72 0de3 0d8a 0c64 | 11 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n005 5 0067 00c6 03cc 0328 | 5 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n006 3 0661 07a8 0743 | 3 0661 (0) 07a8 (0) 0743 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 2 045b 0451 | 2 045b (0) 0451 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","private_key":"7550104c3b78bd70d311385917b9e119ce140cd3584dfe07f18913b06e289257","name":"node_0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","services":["streamer"],"enable_msg_events":true,"port":39107},"up":true}},{"node":{"info":{"id":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","name":"node_959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","enode":"enode://94c05c36e8bda926576025fad9d891d1ae55f406eadb1b2a7040191907ac20a4618ab4af002e997762e3f4a747f417b9c66d3341b0819cb39514b2cfcbf633f8@127.0.0.1:0","enr":"0xf88fb840de6c271ba449dd87a205230febdcc13445277635cb2fb770e1bc7d4df1a6d488210fe6caff9e998f66112dba40d39585301fd3e88f2e0493f3f02c71a684f6e10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10294c05c36e8bda926576025fad9d891d1ae55f406eadb1b2a7040191907ac20a4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lZ/aCGbTwY6TmemEhdYnBEB51vhrB17a6pMVQC9dk5U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 959fda\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4558 512e 5f00 6337 | 146 574f (0) 524d (0) 534b (0) 5308 (0)\n001 9 c786 c59e c441 f7fa | 63 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n002 6 ac4d a653 baf2 b5b2 | 27 aeb4 (0) ae2b (0) af02 (0) ad98 (0)\n003 5 8025 82f9 88fe 886a | 10 8505 (0) 849b (0) 8025 (0) 82dd (0)\n004 3 9890 9fa0 9d0f | 4 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n005 3 90a8 9076 915d | 3 9076 (0) 90a8 (0) 915d (0)\n============ DEPTH: 6 ==========================================\n006 2 96fc 976e | 2 96fc (0) 976e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","private_key":"a67fcf115dfe059791011d5d3825dec2155cabd72c208e838b3fbb2f28ac41a9","name":"node_959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","services":["streamer"],"enable_msg_events":true,"port":36529},"up":true}},{"node":{"info":{"id":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","name":"node_b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","enode":"enode://26664c55fa01411c68d45ee7e420631080f79cb0864dab6839e3fbd228061380f8d6ec4ed7e0d1fccfb3a6db94d25e49381fbd05f82d256e83694b44e75d326b@127.0.0.1:0","enr":"0xf88fb840b6133c0426dafd1efb3e89f6bc48cc63eca4c7bdf38f294f43a2805d2298640c241968809a87cf5d2889912bce5dbad860521fe9d6baf1a7b79d82530f26d4a00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10326664c55fa01411c68d45ee7e420631080f79cb0864dab6839e3fbd228061380","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tl7iVJU2qAbO70p8zJVEVnyv5iBAgJKfyEffCjeBzMk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b65ee2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6e05 5f00 4447 217f | 146 574f (0) 51db (0) 512e (0) 524d (0)\n001 9 df1e c441 c49c caf6 | 63 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n002 5 898d 886a 88fe 9d0f | 20 8505 (0) 849b (0) 8025 (0) 82dd (0)\n003 2 ac4d a653 | 10 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n004 3 ba88 badd baf2 | 9 bcc6 (0) b897 (0) b820 (0) b95d (0)\n005 2 b02b b2b5 | 3 b2a5 (0) b2b5 (0) b02b (0)\n006 2 b5b2 b502 | 2 b502 (0) b5b2 (0)\n============ DEPTH: 7 ==========================================\n007 1 b7ca | 1 b7ca (0)\n008 0 | 0\n009 1 b626 | 1 b626 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","private_key":"318a101c039a46bd0175afcb703828e82134ecef76cdcb18287938d57831ee61","name":"node_b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","services":["streamer"],"enable_msg_events":true,"port":44539},"up":true}},{"node":{"info":{"id":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","name":"node_0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","enode":"enode://450a836838f2759b33e799ec371253efe81e90e74db6f41b868bacb6429d0683dcf1fa1a8b4b761114fbc8826a796bcfc02f6a1798640d4ca58d845f064cadfd@127.0.0.1:0","enr":"0xf88fb840a59d9bcd8c093e82d30493da5fae7fd2e389dcd1428aeb3e828ddecadc97eb861f318f3f6d9652abb3e775bd5fa6fd84f4eb2b2d5c72ddb8ed22919c30f07dab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103450a836838f2759b33e799ec371253efe81e90e74db6f41b868bacb6429d0683","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DPWWr5HrmwQf5tvmsojFcwQThQMhtasXbIFEfjTvecU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0cf596\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e5d7 b65e | 110 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n001 3 4447 5f00 6337 | 70 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n002 5 3780 3089 20ae 217f | 32 39d1 (0) 3b88 (0) 3b78 (0) 3e8e (0)\n003 6 1c47 18f6 1a2a 1b83 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 6 0067 02d8 03cc 0743 | 11 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n005 3 0b72 0af9 0a00 | 3 0b72 (0) 0af9 (0) 0a00 (0)\n006 3 0fc5 0ff2 0e5e | 3 0fc5 (0) 0ff2 (0) 0e5e (0)\n007 2 0d8a 0de3 | 2 0de3 (0) 0d8a (0)\n============ DEPTH: 8 ==========================================\n008 2 0c28 0c64 | 2 0c28 (0) 0c64 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","private_key":"aa043f31ce0392fc2403ba8df2e8a31397d5e5f23c22dabce1e4f94a3ae1ae3a","name":"node_0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","services":["streamer"],"enable_msg_events":true,"port":33613},"up":true}},{"node":{"info":{"id":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","name":"node_e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","enode":"enode://62058bc379f81fa123e4296db03c67338ae62a539937d7b70a28a703624cdd451e739398d8dc6ed3f1b8c73cbb334b5cb7784d308b033ec5a9e61bedd06b050f@127.0.0.1:0","enr":"0xf88fb840e8da211f089ba6f711e92e1ad129af4bb030723cd33a3e2ad4e50fe4b81095403bbe8888a9e5b4ce5c0100c564b97767d80733b74ee5bafd5fc702364ecab3a10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10362058bc379f81fa123e4296db03c67338ae62a539937d7b70a28a703624cdd45","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5deU1kADclp0ZC8JfA7nZwbXhBm28+qBnUQLwK0Wbqw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5d794\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5f00 6337 3089 217f | 146 4e5a (0) 4c9e (0) 4d10 (0) 4d6b (0)\n001 6 b65e baf2 a653 9d0f | 47 8505 (0) 849b (0) 82dd (0) 82f9 (0)\n002 8 d640 d7ac d863 df1e | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 4 ff36 f2d5 f629 f7fa | 19 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n004 4 e8ef ef1b ef07 ec52 | 10 eb98 (0) e854 (0) e883 (0) e8ef (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e775 (0) e7fa (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 3 e514 e54b e547 | 3 e514 (0) e54b (0) e547 (0)\n009 1 e5ad | 1 e5ad (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","private_key":"d57174d811911d6109444b6859f566feda29464787037865b1e86f3d852d82c3","name":"node_e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","services":["streamer"],"enable_msg_events":true,"port":33845},"up":true}},{"node":{"info":{"id":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","name":"node_ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","enode":"enode://78ada9ae0e9eeed303dfc34f560a3a254035857113ab0dd666ec66af33f65a057e050f3c0689eb1960f76f1cbd66ce97d03969c529ac8e264419b8c97aeb5b33@127.0.0.1:0","enr":"0xf88fb84019543c86b688b2e1ac9bb456d94ff1626ea0e8f1afe71fbd92ac278bc30265d850ecec065550473c16a03073e2eb1955d5307248437930167b599a69c298e7610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10378ada9ae0e9eeed303dfc34f560a3a254035857113ab0dd666ec66af33f65a05","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7FInBgQAdnPRv9oe29i/qUWiEUHv2F5CtoSp8w+M3a4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec5227\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 217f 2ccf 0743 1c47 | 146 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n001 6 9d0f 959f 915d b65e | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 10 c786 c441 c49c c9f5 | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 4 ff36 f629 f7ba f7fa | 19 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n004 3 e514 e5ad e5d7 | 8 e027 (0) e775 (0) e7fa (0) e54b (0)\n005 2 e854 e8ef | 4 eb98 (0) e854 (0) e883 (0) e8ef (0)\n============ DEPTH: 6 ==========================================\n006 4 ee5e efea ef1b ef07 | 4 ee5e (0) efea (0) ef1b (0) ef07 (0)\n007 1 ed2d | 1 ed2d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","private_key":"2eef17b1cd655ba656219906144f6dd5423e5c13fb8cfa3888a3fd60cc378cbd","name":"node_ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","services":["streamer"],"enable_msg_events":true,"port":43813},"up":true}},{"node":{"info":{"id":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","name":"node_63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","enode":"enode://e8a75bd7d2c0fa2c24d5e2505d6498a8158fa26cb0d97c3b4b68beb3abc827f44a87c3ecf11c56c0378c0572dd72d089765fe6598de6d897bb96cf033f27e730@127.0.0.1:0","enr":"0xf88fb8402480841002b2349bc7b775205391159f0d46294fd74c074f0e498aa92ba083f758bfa4f1b5b909441c0ac5304e35b6fb23b60d61ac7ca6a63cc099dae63215e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8a75bd7d2c0fa2c24d5e2505d6498a8158fa26cb0d97c3b4b68beb3abc827f4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YzcOKIqy5LhAPGZ46cRK5cdJa16tYUMG/OuFmG7SnRg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 63370e\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 9d0f 959f a653 f629 | 110 8025 (0) 82dd (0) 82f9 (0) 8505 (0)\n001 12 2a0a 2ccf 20ae 2101 | 76 256e (0) 24b8 (0) 21a0 (0) 2101 (0)\n002 5 4447 5308 5b63 5f00 | 38 4e5a (0) 4c9e (0) 4d6b (0) 4d59 (0)\n003 5 7290 738c 7dd3 7b90 | 12 775e (0) 77d2 (0) 7125 (0) 7290 (0)\n004 4 6f5f 6fe9 6ecb 6e05 | 11 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n005 3 66e7 67aa 67dc | 3 66e7 (0) 67dc (0) 67aa (0)\n006 3 60d7 605a 6103 | 3 60d7 (0) 605a (0) 6103 (0)\n============ DEPTH: 7 ==========================================\n007 2 628e 6251 | 2 628e (0) 6251 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","private_key":"abec58c20cbfc6963e54b76ae6003547d7125c820d4c878b12e7e7ffcee87cae","name":"node_63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","services":["streamer"],"enable_msg_events":true,"port":35121},"up":true}},{"node":{"info":{"id":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","name":"node_f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","enode":"enode://760e043d37f149548183d41cdc870ab25e79461d0fb8ffdea5449bc04a3a83556d528ac0d81aba167a040d28e4ed2698c1022c1c2d0363d2c5f06f81563a721d@127.0.0.1:0","enr":"0xf88fb840a766a95d16d134be07e5941a44194fdc8e04d99ff58c3a35bd21692a7e8659921b69df71c2d402ac905d91f8f8c1bfe4b13117faf6aa42d79df4319efb5ea6c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103760e043d37f149548183d41cdc870ab25e79461d0fb8ffdea5449bc04a3a8355","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9/ophuyfhIIrEaawC9A6HdJvKg+rkLGzCPCMrq1Dz+E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f7fa29\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5f00 6337 2ccf 217f | 146 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n001 8 9d0f 959f 915d 898d | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 8 c832 c9f5 caf6 c49c | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 5 e5d7 e8ef ef1b ef07 | 18 e027 (0) e775 (0) e7fa (0) e514 (0)\n004 3 fbf5 fe31 ff36 | 6 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n005 2 f31c f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 4 f4e0 f5b2 f5dc f528 | 6 f456 (0) f45f (0) f4e0 (0) f5b2 (0)\n007 1 f629 | 1 f629 (0)\n============ DEPTH: 8 ==========================================\n008 1 f773 | 1 f773 (0)\n009 1 f7ba | 1 f7ba (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","private_key":"5b66c852efc722720d943acdff6e44cf35572b3ebc9e25c2efb6d44a44ec4f34","name":"node_f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","services":["streamer"],"enable_msg_events":true,"port":37377},"up":true}},{"node":{"info":{"id":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","name":"node_03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","enode":"enode://f5754931b229bb88a9054a16e5a825c93b24fa190fd5cb1346f9c8d3ef63f4df173e4ca8cdf98ff3be0fc5d3ab44524bd95a9089a8d071964cc628219d22c11f@127.0.0.1:0","enr":"0xf88fb84071325b9451536f678c1dfebe4f7aa8106a51d55f3bff1e449d2721a6fbededad0602cb742328ce7c26870565fea9a7efa0b78c561848cf9d9bd1a185fca960dc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f5754931b229bb88a9054a16e5a825c93b24fa190fd5cb1346f9c8d3ef63f4df","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A8zY1SWX0YwLF4q3Nh2EfWOq06+SCig0WXeuFwodr80=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 03ccd8\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 898d 9d0f f7fa | 110 8505 (0) 849b (0) 8025 (0) 82dd (0)\n001 3 6ecb 6337 5f00 | 70 7125 (0) 738c (0) 7290 (0) 775e (0)\n002 5 2a0a 2ccf 217f 20ae | 32 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n003 5 1704 18f6 1a2a 1f67 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 4 0a00 0e5e 0cf5 0c64 | 11 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n005 4 0661 0743 0438 0451 | 6 045b (0) 0451 (0) 0438 (0) 0661 (0)\n006 2 00c6 0067 | 2 00c6 (0) 0067 (0)\n============ DEPTH: 7 ==========================================\n007 1 02d8 | 1 02d8 (0)\n008 1 0328 | 1 0328 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","private_key":"f9bcfddd59b4cd6907137f85a165d8d1d046ea6f941259d24d6f2665345cf86b","name":"node_03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","services":["streamer"],"enable_msg_events":true,"port":41855},"up":true}},{"node":{"info":{"id":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","name":"node_1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","enode":"enode://63429a53e98ea2c805da1f72629bc2dfa38477f37e946c23a9a556e105170d09ba9fc04a92c9c002f5afacb97323330dd80c7b6facee5c66d70acb13f0a2ef07@127.0.0.1:0","enr":"0xf88fb840c8a077c9b0ef7333f8f167874fe84783be8d6e18a6017fc6cacf229dab3e7a4b1f898958a70aebef08571f0bc40a3de1545c0b4c6bd945f28c5615df92fa47050183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10363429a53e98ea2c805da1f72629bc2dfa38477f37e946c23a9a556e105170d09","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HEetW9iEb3d9r1lYf+zMMI9Nxj9tJ7E4X/gIXHW7Gqw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1c47ad\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ec52 f629 a653 | 110 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n001 2 6337 5f00 | 70 7125 (0) 738c (0) 7290 (0) 775e (0)\n002 4 3089 2ccf 2a0a 20ae | 32 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n003 6 0cf5 0c64 0451 0438 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 2 1400 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n005 3 18f6 1b83 1a2a | 4 19fa (0) 18f6 (0) 1b83 (0) 1a2a (0)\n006 3 1e2a 1f85 1f67 | 3 1e2a (0) 1f85 (0) 1f67 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 1c9c 1c8a | 2 1c9c (0) 1c8a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","private_key":"ebc5324f8eb3a357f8d1969f069ce39c7c3fb22ccf7525110318b3ac880c1ca3","name":"node_1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","services":["streamer"],"enable_msg_events":true,"port":42947},"up":true}},{"node":{"info":{"id":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","name":"node_5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","enode":"enode://480ba1e732c94f5f601e880599ab5b96e240599a8966fe2ddda4073307a99742a535dff51f6af5bd1b53fce8537be4bc5e2fa76c49449c0415442adba987460a@127.0.0.1:0","enr":"0xf88fb8401875d2a45f120ec3d8f94c4cf3efefff3c45785956e1a09d0446b9ea48b3cb1820585e3f5ab525ca7b0fb517ce83fbebc51c66913a99e3e1a3121c9d2583f0950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102480ba1e732c94f5f601e880599ab5b96e240599a8966fe2ddda4073307a99742","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XwCzvr7y9UhP8ThimK3WimdDoQYgCuihOifbtScU7o8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5f00b3\npopulation: 45 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 d863 df1e ec52 e5d7 | 110 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n001 12 2a0a 2c38 2d36 2101 | 76 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n002 9 7b90 7a60 77d2 6337 | 32 7125 (0) 738c (0) 7290 (0) 775e (0)\n003 6 4447 47bf 461c 4646 | 23 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n004 4 53a8 5308 512e 51db | 8 574f (0) 524d (0) 53fe (0) 53a8 (0)\n005 2 5b63 58ed | 3 5b63 (0) 5823 (0) 58ed (0)\n============ DEPTH: 6 ==========================================\n006 2 5cd2 5db0 | 2 5cd2 (0) 5db0 (0)\n007 1 5efb | 1 5efb (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","private_key":"9b3dc4d343d8005de0a128e913e4ed62e5caec6a02eb7c00580bec4be6126b5e","name":"node_5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","services":["streamer"],"enable_msg_events":true,"port":36775},"up":true}},{"node":{"info":{"id":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","name":"node_0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","enode":"enode://19c7cdd72825b48029116b58a6a68b357fcc7dade4a419c159b7a1479b9aaaca9040f86319f2e30d881a255728459f53f62e11907116fb7f0d95b17cf8acd4ce@127.0.0.1:0","enr":"0xf88fb84082a5fb67d177a01d43d741c548086b575590cb32e8f8ca21ea57c96b5d3e3b247a3aa5b69c1cf6eb5ea7e667736efd50f3bf23a658d2738640b8e8f01c8684780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10219c7cdd72825b48029116b58a6a68b357fcc7dade4a419c159b7a1479b9aaaca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"B0O88qqnfpFvSjZ9YVlHPH2A9GouTL6e80bkI9OdcHI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0743bc\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 fe31 f629 e5d7 ec52 | 110 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n001 4 6f5f 6ecb 6e05 5f00 | 70 77d2 (0) 775e (0) 7125 (0) 738c (0)\n002 3 2a0a 20ae 3089 | 32 2f32 (0) 2c79 (0) 2c38 (0) 2ccf (0)\n003 3 1704 1f67 1c47 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 4 0e5e 0d8a 0c64 0cf5 | 11 0af9 (0) 0a00 (0) 0b72 (0) 0fc5 (0)\n005 3 0067 03cc 02d8 | 5 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n006 2 0451 0438 | 3 045b (0) 0451 (0) 0438 (0)\n============ DEPTH: 7 ==========================================\n007 1 0661 | 1 0661 (0)\n008 1 07a8 | 1 07a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","private_key":"47ac9bcf8a80092ec709388ead63309357c024e48a9d084b0242dfc58046fd79","name":"node_0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","services":["streamer"],"enable_msg_events":true,"port":44873},"up":true}},{"node":{"info":{"id":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","name":"node_a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","enode":"enode://613e2fd1046ee6d486077d07c0150b2097f1f5ed197194b6be66369087dcc6e8c069a8c8a08f5688f7510670ba92b71f21713a7771e353b6f2f32f07ff2050d6@127.0.0.1:0","enr":"0xf88fb84069a4ec3dacd9e94a16a63e64b329fd81c61bd7485b97b81e2469e3c26c6844cd09ddfcf98ba00def4ea96b1a61fab34b651e8087daa8b49677211a8bf3b616e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102613e2fd1046ee6d486077d07c0150b2097f1f5ed197194b6be66369087dcc6e8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"plMwJzDfPVj3lpBqk5M6qBSU8liNlIWrdnbsOwzLtCY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a65330\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 6337 5f00 2a0a 20ae | 146 775e (0) 77d2 (0) 7125 (0) 738c (0)\n001 7 df1e d863 e5d7 ec52 | 63 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n002 5 88fe 898d 9d0f 915d | 20 82dd (0) 82f9 (0) 8025 (0) 849b (0)\n003 5 baf2 b502 b5b2 b626 | 17 bcc6 (0) b95d (0) b911 (0) b820 (0)\n004 5 af02 ae2b aeb4 ad98 | 5 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n005 2 a34e a369 | 2 a34e (0) a369 (0)\n============ DEPTH: 6 ==========================================\n006 1 a46d | 1 a46d (0)\n007 0 | 0\n008 1 a6fb | 1 a6fb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","private_key":"0b39a127c1bcb229d9f78601108abe82d675a725983831143efa53f899d08bdf","name":"node_a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","services":["streamer"],"enable_msg_events":true,"port":43953},"up":true}},{"node":{"info":{"id":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","name":"node_30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","enode":"enode://77bb6be6fe33a79ce2b05a3ea945520fb76c9262e75002a66961e3d27470fec41d9d93ee7fa847b6848f95fbf48806f4e9b0dd1a7e2a75738eaf6ff87e566696@127.0.0.1:0","enr":"0xf88fb8408975a075a76b03b6e862198c62788a23869e631fc2f37775f9a9269229cab59419c1f12dfa51ed37f6993170944a259abdee74afa02303737414e5824a67173a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10277bb6be6fe33a79ce2b05a3ea945520fb76c9262e75002a66961e3d27470fec4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MIl0koJLGVQNE+8XxwhFvm3eRV3KTk+Ez8oUosNzlp8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 308974\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f629 e5d7 d863 df1e | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 3 6ecb 6337 5f00 | 70 7125 (0) 738c (0) 7290 (0) 77d2 (0)\n002 9 1704 1a2a 1c47 1f67 | 44 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n003 9 2ccf 2c38 2d36 2995 | 15 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n004 2 39d1 3f94 | 7 3b88 (0) 3b78 (0) 39d1 (0) 3e8e (0)\n005 4 35e6 3630 378e 3780 | 4 35e6 (0) 3630 (0) 378e (0) 3780 (0)\n006 3 33b5 3373 3237 | 3 33b5 (0) 3373 (0) 3237 (0)\n============ DEPTH: 7 ==========================================\n007 1 314a | 1 314a (0)\n008 0 | 0\n009 0 | 0\n010 1 30be | 1 30be (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","private_key":"dbfd3f618dd2960c68e8eeac259fef1c20d8154f8fcafa4992bc5568c7c8a9d9","name":"node_30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","services":["streamer"],"enable_msg_events":true,"port":38135},"up":true}},{"node":{"info":{"id":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","name":"node_0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","enode":"enode://ecda090f3e2fbbd974141d7beee44746688e9b805c8a76e68f3b4ac9d9e5a22f006596991f82625fa651aebd36ccab7262fd90a08040402982a11b92c8301e4e@127.0.0.1:0","enr":"0xf88fb8400ac80bea14f01369a3774d4c98b4218c5d0d180bda798635c393bdc35befe3c72cca308d1e84b165fd5b1012e749086db6634a096cb618c14645c91e59e906480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ecda090f3e2fbbd974141d7beee44746688e9b805c8a76e68f3b4ac9d9e5a22f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DGTlr4abFmX9QBaubQTI7t1CNjbwbXjsuUTujjJyqCo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0c64e5\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a653 886a 898d f629 | 110 82f9 (0) 82dd (0) 8025 (0) 8505 (0)\n001 3 5f00 6337 6ecb | 70 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n002 4 2d36 2a0a 20ae 3089 | 32 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n003 5 1704 1f67 1e2a 1c47 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 6 0743 0451 0438 00c6 | 11 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n005 2 0af9 0a00 | 3 0b72 (0) 0af9 (0) 0a00 (0)\n006 2 0fc5 0e5e | 3 0ff2 (0) 0fc5 (0) 0e5e (0)\n007 2 0de3 0d8a | 2 0de3 (0) 0d8a (0)\n============ DEPTH: 8 ==========================================\n008 1 0cf5 | 1 0cf5 (0)\n009 1 0c28 | 1 0c28 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","private_key":"7c777cdb8d0d0d9cf6dc20d975185908b22a1774e4e9abf683b3ee25c8ccc5a8","name":"node_0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","services":["streamer"],"enable_msg_events":true,"port":38547},"up":true}},{"node":{"info":{"id":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","name":"node_f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","enode":"enode://f12ee7006d3189d601c33a5aa4d0852e4f5aa621abedc967a106064c05dfb5de7f813d8356ae58fdad01d1453a563482e960120fb92cfa61d3ebba3c9c331b41@127.0.0.1:0","enr":"0xf88fb840d30cb092c1b2933d7cc9b7444ef7da1f3fe07ae780285ecced6998041385ca0d14e88aa1dea59469ff033450bc73e099bc2bb9773d568846e4d640c797590b160183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f12ee7006d3189d601c33a5aa4d0852e4f5aa621abedc967a106064c05dfb5de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9im4ueecdaxVna+b9PyGcr/dWVzyxdF6iIUoJib8ZaU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f629b8\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 6ecb 6337 5f00 3089 | 146 7e04 (0) 7dc2 (0) 7dd3 (0) 7dbb (0)\n001 6 898d 915d 959f b65e | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 9 c832 c9f5 caf6 c49c | 26 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n003 5 e5d7 e8ef ef1b ef07 | 18 e027 (0) e775 (0) e7fa (0) e54b (0)\n004 4 fbf5 ff36 fe21 fe31 | 6 f925 (0) fbc8 (0) fbf5 (0) fe21 (0)\n005 2 f27f f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 4 f4e0 f5b2 f5dc f528 | 6 f456 (0) f45f (0) f4e0 (0) f5b2 (0)\n============ DEPTH: 7 ==========================================\n007 3 f773 f7ba f7fa | 3 f773 (0) f7ba (0) f7fa (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","private_key":"ed331558b7b08a35ac962ee04dd387cf1355874a1e4998244fb9c4530bc3036c","name":"node_f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","services":["streamer"],"enable_msg_events":true,"port":43737},"up":true}},{"node":{"info":{"id":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","name":"node_20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","enode":"enode://e0e6fe997dda2f2ae96f021131f1f3975da9807d14dbb610fd82ef3b8d37ac6934e616d60bf7cdba99b9db2edcb0991febc119d93ad7ff35e4b6ce09903446ae@127.0.0.1:0","enr":"0xf88fb840946c1b232e0d6a23993e1b0b244cc3b22c4f091277d1507a29146bda9aad796e3d1c7dcd6a3de9c37c9355fe2f6a4db100ed11f07d0acfaab3676e42175906470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e0e6fe997dda2f2ae96f021131f1f3975da9807d14dbb610fd82ef3b8d37ac69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IK6xT1Z90W8GsNO1ibgyg9qgCl7RDkR4YL2pRrrM3S0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 20aeb1\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a653 9d0f df1e f7fa | 110 8505 (0) 849b (0) 8025 (0) 82dd (0)\n001 4 4447 5f00 6337 6ecb | 70 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n002 7 03cc 0743 0cf5 0c64 | 44 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n003 6 3f94 3780 3373 3237 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3efc (0)\n004 6 2ccf 2c38 2d36 2995 | 9 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 21a0 217f 2101 | 3 21a0 (0) 217f (0) 2101 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","private_key":"2e8fb7fdd8a9a42774dbb1e04397d0092d1722e16dc44ee9ec98dcceef319366","name":"node_20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","services":["streamer"],"enable_msg_events":true,"port":33621},"up":true}},{"node":{"info":{"id":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","name":"node_2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","enode":"enode://41ce2c9d43b344d3ee113b760fcf2e9254f4e650568be23a964a1cf6e0354ef3616bd129e46a868f713a9a507acdc6b219d5923a7aa09b96092f161d2f76fad4@127.0.0.1:0","enr":"0xf88fb840cb2dee7c73e503707c6b93468e93e8602d07fb552da0e1429d5e05393a553625665eaedb8ac4db4f1fc86bf952d9a3937b0d40f9df2b5d81a6900949b0cc79140183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10241ce2c9d43b344d3ee113b760fcf2e9254f4e650568be23a964a1cf6e0354ef3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KgqOrxonSeaPi4QVeMFgaZz3kH/yOELG1hatiE5fYT4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a0a8e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a653 9d0f d863 df1e | 110 8505 (0) 849b (0) 82dd (0) 82f9 (0)\n001 5 5f00 5db0 4447 6337 | 70 4990 (0) 49ea (0) 49cd (0) 4bcf (0)\n002 6 0743 03cc 0c64 1f67 | 44 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n003 4 3f94 35e6 3780 3089 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3ec5 (0)\n004 3 2101 217f 20ae | 6 24b8 (0) 256e (0) 21a0 (0) 217f (0)\n005 3 2d36 2ccf 2c38 | 5 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n006 1 2995 | 1 2995 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 2abb 2a97 | 2 2abb (0) 2a97 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","private_key":"5ed9141147ced7a970cf200754db9d56e55104e714e7b8b6ab0372ea8e987b34","name":"node_2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","services":["streamer"],"enable_msg_events":true,"port":37145},"up":true}},{"node":{"info":{"id":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","name":"node_1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","enode":"enode://ce8284583c6db3b9420355ed2e31812b19ceb6157b78b991cf2275cba03fc42a1fc5ca4be2e339ce47a981b7c3fea09fb4ef0489234d5660488ab4cbde59044c@127.0.0.1:0","enr":"0xf88fb84069d4576c9390bdd8b0b134b81758b7b133feddbb1077abc43b3afdf7d3e40e8514903b6f2a002df47f3f977fae861bb7ad48e28cfd6037488e74e727929721ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ce8284583c6db3b9420355ed2e31812b19ceb6157b78b991cf2275cba03fc42a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GioOC7+DzUCTaZVnRBiuRpqiuSh2pM7qvYEo9Ta316I=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1a2a0e\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d863 df1e 9d0f | 110 c26f (0) c1f9 (0) c786 (0) c620 (0)\n001 7 4447 5db0 5f00 6337 | 70 49ea (0) 49cd (0) 4990 (0) 4bcf (0)\n002 4 3089 2101 20ae 2a0a | 32 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n003 5 03cc 0451 0438 0cf5 | 22 0067 (0) 00c6 (0) 02d8 (0) 0328 (0)\n004 2 1400 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n005 6 1e2a 1f85 1f67 1c8a | 6 1e2a (0) 1f85 (0) 1f67 (0) 1c8a (0)\n============ DEPTH: 6 ==========================================\n006 2 19fa 18f6 | 2 19fa (0) 18f6 (0)\n007 1 1b83 | 1 1b83 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","private_key":"66cedc68f62643418971c63cf6032c5cbfd77b99e9d052c406d568d23ad4a0a9","name":"node_1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","services":["streamer"],"enable_msg_events":true,"port":43217},"up":true}},{"node":{"info":{"id":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","name":"node_9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","enode":"enode://12a7d6a36db53d873c0acc5a559d296451cf06d07aa94a306ace9b6043fb3c2d9e1e1c49b9ebfc9564a9611e315d5fb1eb7967526de503234970b110793753da@127.0.0.1:0","enr":"0xf88fb8408f502648e715faaf2434932bad996cfe6aeb6abb2a2ea6e7c78e3397d1b442a6242b093c33df73b486aede52745c085f7081b037099ed3a238e285da2177b9bb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212a7d6a36db53d873c0acc5a559d296451cf06d07aa94a306ace9b6043fb3c2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nQ+ASEm3I5dka6SCCLoeAdz03gTniAFsShoMk+ZQ3fU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9d0f80\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 6337 6ecb 3089 2d36 | 146 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n001 8 f7fa ff36 ec52 e547 | 63 eb98 (0) e854 (0) e883 (0) e8ef (0)\n002 5 badd b7ca b65e a653 | 27 bcc6 (0) b820 (0) b897 (0) b911 (0)\n003 6 8025 82f9 8f21 88fe | 10 8505 (0) 849b (0) 8025 (0) 82dd (0)\n004 6 9076 90a8 915d 96fc | 6 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n============ DEPTH: 5 ==========================================\n005 2 9852 9890 | 2 9852 (0) 9890 (0)\n006 1 9fa0 | 1 9fa0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","private_key":"5a3b48cfd6ec1d644a7c6a7c880a16141fb04b6362ca8b077c18e25508f97a8a","name":"node_9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","services":["streamer"],"enable_msg_events":true,"port":41537},"up":true}},{"node":{"info":{"id":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","name":"node_df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","enode":"enode://43a859488ad22646b38f98737b2ac09af8c9280038408f13c72deb3aa3bc0405f6d6b9d25961b7a83efe20f7700411dd0c70215ffce26d0b46e6581c902a6a6d@127.0.0.1:0","enr":"0xf88fb84024940eb9de5536da259f0f58a1e16285099071949f0e9ad9ed71742a5af3100c76f2ab3c852b256f9db69e18317adbb05ecf1dcff3e87fed713d59174e0c61780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10343a859488ad22646b38f98737b2ac09af8c9280038408f13c72deb3aa3bc0405","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3x5ORujsJsrXS081qwcPEsj2/dyjWsRMEhj/YP4ea6s=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: df1e4e\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 5f00 6ecb 3089 2d36 | 146 4990 (0) 49ea (0) 49cd (0) 4bcf (0)\n001 6 b65e a653 ac4d 886a | 47 bcc6 (0) b897 (0) b820 (0) b911 (0)\n002 8 ec52 ef07 ef1b e514 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 5 c832 c9f5 c59e c49c | 15 c1f9 (0) c26f (0) c786 (0) c6cf (0)\n004 3 d1d7 d7ac d640 | 5 d3b0 (0) d299 (0) d1d7 (0) d7ac (0)\n============ DEPTH: 5 ==========================================\n005 5 daec da67 db6a d887 | 5 daec (0) da67 (0) db6a (0) d887 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","private_key":"374fa339ea3cf4a0d8163261f0d431dfec275bd3323d60ffdd0e99868f234d3b","name":"node_df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","services":["streamer"],"enable_msg_events":true,"port":33131},"up":true}},{"node":{"info":{"id":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","name":"node_1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","enode":"enode://b38f84e3fb5c5995741a2a998215c68d6eee0548072f49bea0d3e3f638779977df96caf15932edea56c8b18e27fb660a269dffcdb628ef6fea0c86a8faa6c560@127.0.0.1:0","enr":"0xf88fb840060e7e6c9c1f7f7cfbf60354cd454fa5d169bf184f13f458845764571079a9e6070092d3d33322c88d0eb91c50376453e016e118f6636745d50bf17b9bee95190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b38f84e3fb5c5995741a2a998215c68d6eee0548072f49bea0d3e3f638779977","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"H2cMU7TFl76v+s2E46aXIlsEze2SGdCijh/lJaPK3PU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1f670c\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ac4d d863 df1e | 110 bcc6 (0) b911 (0) b95d (0) b820 (0)\n001 3 6103 6f5f 6ecb | 70 49cd (0) 49ea (0) 4990 (0) 4bcf (0)\n002 6 3089 2d36 2a0a 2995 | 32 3b88 (0) 3b78 (0) 39d1 (0) 3e8e (0)\n003 6 0c64 0067 03cc 0451 | 22 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n004 4 11d4 14df 154b 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 1436 (0)\n005 3 1b83 1a2a 18f6 | 4 19fa (0) 18f6 (0) 1b83 (0) 1a2a (0)\n006 3 1c8a 1c9c 1c47 | 3 1c8a (0) 1c9c (0) 1c47 (0)\n============ DEPTH: 7 ==========================================\n007 1 1e2a | 1 1e2a (0)\n008 1 1f85 | 1 1f85 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","private_key":"8b2847a2b9e1ffbd91e4f0e7386339eb2dbf3391956547ad876d3d7fafbdda9c","name":"node_1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","services":["streamer"],"enable_msg_events":true,"port":43053},"up":true}},{"node":{"info":{"id":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","name":"node_d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","enode":"enode://f9a61c9819677e84a716705685a63dc1bc77bfc1e9c23cf9127e4e00228d82f7487a4133ee6f5a39686c64e5f95e222dbefdbd0d2c59ea4d4ed69e49843236d5@127.0.0.1:0","enr":"0xf88fb8407f43c74479afec5cde0df2a8e4c7452558c0414e10ac7319c29567d1fe9706597c8d0fac508af58ce2b580e31877a08fa7ea9a712348c98bbf5debbdbb5a3e640183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f9a61c9819677e84a716705685a63dc1bc77bfc1e9c23cf9127e4e00228d82f7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2GO6dAXrB8zdvx0077y+woZ6k6EJ7ZQT2a7PMNNkWmo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d863ba\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 5f00 6ecb 0743 1704 | 146 4bcf (0) 4a8b (0) 4ac7 (0) 4990 (0)\n001 4 898d 9d0f ac4d a653 | 47 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n002 6 ff36 f2d5 f629 f7fa | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 8 c26f c786 c441 c49c | 15 c1f9 (0) c26f (0) c620 (0) c6cf (0)\n004 3 d299 d7ac d640 | 5 d1d7 (0) d3b0 (0) d299 (0) d7ac (0)\n005 1 df1e | 1 df1e (0)\n============ DEPTH: 6 ==========================================\n006 3 daec da67 db6a | 3 daec (0) da67 (0) db6a (0)\n007 0 | 0\n008 1 d887 | 1 d887 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","private_key":"8febd8aeb1300031923fe49da5869050860d96d11eb4508c497687c8ccddc31f","name":"node_d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","services":["streamer"],"enable_msg_events":true,"port":39911},"up":true}},{"node":{"info":{"id":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","name":"node_2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","enode":"enode://5a16cc82bdff422be5114cecf38c16efaa5cf372e4b9da981b04bf795e5d6dd58f2128d1ea860d1fc5ab50341562b3fe220930224978c5fc9cc470236e731f8a@127.0.0.1:0","enr":"0xf88fb8402065a0e31a085320c01f09fe4cac1f3443c89d2aa42a78120ab8af3197c6c3a00501e91b9adefc7a55eccc59b6a25a614cea33a121aa6e794419d8a9990d90ce0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025a16cc82bdff422be5114cecf38c16efaa5cf372e4b9da981b04bf795e5d6dd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LTZFxP35ooCakJB2ue5fuY+ogPb67/kU8aKYevkozXk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2d3645\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ac4d 9d0f ff36 f629 | 110 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n001 2 5f00 6ecb | 70 4bcf (0) 4a8b (0) 4ac7 (0) 49cd (0)\n002 4 1f67 1704 0c64 0451 | 44 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n003 7 39d1 3b78 3f94 35e6 | 17 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n004 3 20ae 217f 2101 | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 4 2995 2abb 2a97 2a0a | 4 2abb (0) 2a97 (0) 2a0a (0) 2995 (0)\n006 1 2f32 | 1 2f32 (0)\n============ DEPTH: 7 ==========================================\n007 3 2c79 2c38 2ccf | 3 2ccf (0) 2c79 (0) 2c38 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","private_key":"60acfdf5adccd8cecfff6c7041a09ca32eaa3aa3a70df16eb20f58826c441ecd","name":"node_2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","services":["streamer"],"enable_msg_events":true,"port":41863},"up":true}},{"node":{"info":{"id":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","name":"node_6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","enode":"enode://04684e9608ae1597b26dcf982a1102e6cdd9d2437b9b0d2e4dc0c1acada0b112d11b3d80dd326baea3005f626e94985b91e0cca937f63323a0ff9dd434f31601@127.0.0.1:0","enr":"0xf88fb8401c006cfaa1eed4491442b8516c8bdf525694e5c4b6e1e65cfd0409927b90027e5242612b7461f7b42127f5f0de749f08eec7d18fe8b3292fdf06dd809f43c4d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10304684e9608ae1597b26dcf982a1102e6cdd9d2437b9b0d2e4dc0c1acada0b112","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bstcNvwBUMKHRGroqGgtYpodOTQSMHFyBiGbq+O99lk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ecb5c\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 898d 9d0f f629 ff36 | 110 eb98 (0) e854 (0) e883 (0) e8ef (0)\n001 12 0c64 03cc 0743 0451 | 76 0af9 (0) 0a00 (0) 0b72 (0) 0ff2 (0)\n002 8 58ed 5f00 5db0 5308 | 38 49cd (0) 49ea (0) 4990 (0) 4bcf (0)\n003 5 7290 77d2 775e 7b90 | 12 7125 (0) 738c (0) 7290 (0) 77d2 (0)\n004 2 6337 6103 | 9 67dc (0) 67aa (0) 66e7 (0) 605a (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c4d 6c73 | 2 6c73 (0) 6c4d (0)\n007 3 6fe9 6f2d 6f5f | 3 6fe9 (0) 6f2d (0) 6f5f (0)\n============ DEPTH: 8 ==========================================\n008 2 6e68 6e05 | 2 6e68 (0) 6e05 (0)\n009 1 6ea5 | 1 6ea5 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","private_key":"6ccda16d24593d76eeb7948a4af3fb05397678300cffc7c91a33b30131038c07","name":"node_6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","services":["streamer"],"enable_msg_events":true,"port":45685},"up":true}},{"node":{"info":{"id":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","name":"node_21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","enode":"enode://98c213523753d4a7653cb5b73bab12b51338713fea9dc6f12a63a8336614c389ffdf44b011e51bd2c8083da8e80e4f1918739bbae11667d68f310f526fd020cb@127.0.0.1:0","enr":"0xf88fb840abbddde7f121cefe95a32471993c96b1df78fac759c6d32c3c2f3a5442d3b96d0f4cb71c4dabeadd6ea7962640f6d04e731dc0b3d6f37c63316c9e7b10919cd40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10398c213523753d4a7653cb5b73bab12b51338713fea9dc6f12a63a8336614c389","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IQEqOm7x7OSP2dfP/mLcdYOd0GLvzzrF+WLCN4FNpAc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 21012a\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 df1e ff36 9d0f ac4d | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 5 51db 5f00 6337 6103 | 70 49ea (0) 49cd (0) 4990 (0) 4bcf (0)\n002 5 0451 1f67 1a2a 18f6 | 44 0a00 (0) 0af9 (0) 0b72 (0) 0ff2 (0)\n003 5 3b78 39d1 3f94 35e6 | 17 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n004 8 2a0a 2a97 2995 2f32 | 9 2abb (0) 2a97 (0) 2a0a (0) 2995 (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 20ae | 1 20ae (0)\n008 1 21a0 | 1 21a0 (0)\n009 1 217f | 1 217f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","private_key":"0c649ddaf655f9e8eee8b3a2d2050c9b93305a4e7a28f3684f68aee88ab0ef2e","name":"node_21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","services":["streamer"],"enable_msg_events":true,"port":38963},"up":true}},{"node":{"info":{"id":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","name":"node_17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","enode":"enode://319cd6619ea64ca816341d84c8b1ca4aa41b3a0eca34fbdf923acd1396287078e2808d85b58fbb61dbffc5c14b726c002731803095ec20ebe8079edf94ef274c@127.0.0.1:0","enr":"0xf88fb8402778c296526d28fd3bd0b985c90367db08c61a457ddf60dd9e79024d56fdd6dc78b02d84ec47cdabda998e2326ffca652eeb8fad6517d8e5238bdacffc6fdeba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102319cd6619ea64ca816341d84c8b1ca4aa41b3a0eca34fbdf923acd1396287078","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FwQKOq1ZMNjg3hAR/SmWt9CSJZifDcGuj356Ut0mq04=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 17040a\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d863 ff36 898d ac4d | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 3 5db0 6f5f 6ecb | 70 4990 (0) 49cd (0) 49ea (0) 4bcf (0)\n002 6 3089 2d36 2c38 2995 | 32 3b88 (0) 3b78 (0) 39d1 (0) 3e8e (0)\n003 8 0e5e 0cf5 0c64 03cc | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 6 1c47 1e2a 1f67 1b83 | 10 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n005 2 103b 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 4 154b 1436 1400 14df | 4 154b (0) 1436 (0) 1400 (0) 14df (0)\n007 2 165f 1672 | 2 165f (0) 1672 (0)\n============ DEPTH: 8 ==========================================\n008 2 179f 17db | 2 179f (0) 17db (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","private_key":"6fd569b047d43c53be962cedfa9155cbdd5b612bf6ae51d3b02aa8c1bab608c1","name":"node_17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","services":["streamer"],"enable_msg_events":true,"port":38715},"up":true}},{"node":{"info":{"id":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","name":"node_04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","enode":"enode://52bb359e4ef492631139b8f55c6bd84f6fdf764b06373ff664baec44a296aefa8a30ce0f4a3792af214e4f1025f5d4f5d67c52b754720ee7f8cff0b069716439@127.0.0.1:0","enr":"0xf88fb840cab6c885934f1ff7d8d41a71e525765c7eec705d6d47779bc453c39f000c9be43e5d2c812ef5c9fddbf705cfba32604383775a77297727a3b98fbe0937845b110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10352bb359e4ef492631139b8f55c6bd84f6fdf764b06373ff664baec44a296aefa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BFGNcSD6ilKNmDyh7m1dCbokpOhT+yK8kITN80mV6V8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 04518d\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fe31 ff36 898d ac4d | 110 c1f9 (0) c26f (0) c786 (0) c6cf (0)\n001 4 5db0 6f5f 6ecb 6103 | 70 4990 (0) 49cd (0) 49ea (0) 4bcf (0)\n002 5 2101 2a97 2995 2d36 | 32 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n003 6 1f67 1e2a 1c47 1a2a | 22 1c8a (0) 1c9c (0) 1c47 (0) 1e2a (0)\n004 5 0a00 0b72 0e5e 0cf5 | 11 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n005 3 02d8 03cc 0067 | 5 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n006 2 0661 0743 | 3 0661 (0) 07a8 (0) 0743 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 0438 | 1 0438 (0)\n010 0 | 0\n011 0 | 0\n012 1 045b | 1 045b (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","private_key":"2e166ac09eefef316a31e45dc6fa94185d8d91cc1d537f03044c7cb46ab00347","name":"node_04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","services":["streamer"],"enable_msg_events":true,"port":33881},"up":true}},{"node":{"info":{"id":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","name":"node_610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","enode":"enode://27461fddb23d01661d9e0752253b5f1ff25fd09606c0f07fd3161be1d08015a00addcfe28ebcdd5bd3974ce43579047df1d16e2de978b55a62885a3f9b919aeb@127.0.0.1:0","enr":"0xf88fb8402aa36d20ffb02eb4363c646927544d3ef64e739c150d0cf86e67c9f1e55d968171dc7a65d680a25f704a35163488cb3427ded17d666bdb22ef7be92242260d3c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10327461fddb23d01661d9e0752253b5f1ff25fd09606c0f07fd3161be1d08015a0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YQM0oHctNBRlK1dfLKpvLbMiJJB8JNBv2mQ9ufLsKv4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 610334\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ff36 898d ac4d | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 7 2101 2995 2c38 1f67 | 76 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n002 8 4109 461c 4d10 5308 | 38 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n003 6 7dd3 7dbb 7920 7a60 | 12 775e (0) 77d2 (0) 7290 (0) 738c (0)\n004 5 6fe9 6f5f 6e68 6e05 | 11 6967 (0) 6831 (0) 6c4d (0) 6c73 (0)\n005 3 66e7 67aa 67dc | 3 66e7 (0) 67aa (0) 67dc (0)\n006 3 6251 628e 6337 | 3 6251 (0) 628e (0) 6337 (0)\n============ DEPTH: 7 ==========================================\n007 2 60d7 605a | 2 60d7 (0) 605a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","private_key":"a239693a1557643d38ba187a95721a30768f347591e6f8868b289ec3f95b5e3f","name":"node_610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","services":["streamer"],"enable_msg_events":true,"port":46809},"up":true}},{"node":{"info":{"id":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","name":"node_ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","enode":"enode://134ad215979bb59e0854da374768a63faad6b7322ab9e96996f9d5121bf3f3093736c2b9e465cc3141fe55ae189e6e708af53bdb2f165ddfb934adbfd15f8b13@127.0.0.1:0","enr":"0xf88fb8400b13e5d05cf91166873c521a1779fec8d2519ba5960b369a7ca65f83fcc01cea397a6dec2e9098a898ae93a78056944abf096f46e1a62592a7d067b013da30f00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103134ad215979bb59e0854da374768a63faad6b7322ab9e96996f9d5121bf3f309","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rE0taDbizfTIgiH2ATqscKRR3RW8QDKIvRDQuRHNmis=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ac4d2d\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 2c38 2d36 2a97 2995 | 146 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n001 6 c832 df1e d863 f629 | 63 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n002 3 959f 9d0f 898d | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 6 b5b2 b626 b65e ba88 | 17 bcc6 (0) b897 (0) b820 (0) b95d (0)\n004 2 a369 a653 | 5 a34e (0) a369 (0) a46d (0) a6fb (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 af02 aeb4 ae2b | 3 af02 (0) aeb4 (0) ae2b (0)\n007 1 ad98 | 1 ad98 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","private_key":"aaaa8d07b535646ac07aef1d6dbe233da8938015e1fbb22d29bb1667cccdbd9c","name":"node_ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","services":["streamer"],"enable_msg_events":true,"port":44875},"up":true}},{"node":{"info":{"id":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","name":"node_ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","enode":"enode://caea642b8d5bd71c4dc4f25c29351b369cae4b0b2cc5c09805f09dbe91dff565c639652d2997ef93df5a8814a088dcb6eeb10cde26ef5114f39f86f96c61dfe1@127.0.0.1:0","enr":"0xf88fb840a8727941728a486f3f2399e65bacb4139c6b4ffcda9c78b7ba54db0561b8b3496543e9ac4ddc130e407c629d8346439a2ac645f858ff17da07fa89b93e4cfbe00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103caea642b8d5bd71c4dc4f25c29351b369cae4b0b2cc5c09805f09dbe91dff565","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/zaogQ3UT20fpCqpH/Yga8+0wf+6sN9zoYHa7OMp4OM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ff36a8\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 6f5f 6ecb 6103 18f6 | 146 1c9c (0) 1c8a (0) 1c47 (0) 1e2a (0)\n001 5 9d0f 886a 898d ad98 | 47 96fc (0) 976e (0) 959f (0) 9076 (0)\n002 5 c786 c9f5 c832 d863 | 26 c26f (0) c1f9 (0) c6cf (0) c620 (0)\n003 5 e514 e5d7 ec52 ef1b | 18 e027 (0) e775 (0) e7fa (0) e54b (0)\n004 9 f31c f2d5 f528 f5dc | 13 f31c (0) f27f (0) f2d5 (0) f45f (0)\n005 3 fbf5 fbc8 f925 | 3 fbf5 (0) fbc8 (0) f925 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 fe21 fe31 | 2 fe21 (0) fe31 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","private_key":"2e244474154628879e0fe12f4e3f1fbd5803d0a643d609efa8b704912812cd68","name":"node_ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","services":["streamer"],"enable_msg_events":true,"port":44299},"up":true}},{"node":{"info":{"id":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","name":"node_2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","enode":"enode://47952da4c6b64e3f0d74a7444c626ac5ec1dc5cc34a4a62e8cbfb6016015afddb5e37081dbee4fd825dddc79d455d4ed6e589e93bb20b43dd9be174c885c9a19@127.0.0.1:0","enr":"0xf88fb840adbbd5eaf9c32e9a2af15ed32ea2cfb62da1704c409d35e7467a4a3290586ef679381b40e61f36d843e27f7fa96add6a5c419f50d30455c897732b2ba0a615b80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10347952da4c6b64e3f0d74a7444c626ac5ec1dc5cc34a4a62e8cbfb6016015afdd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LDiUtuR88ZrH7p/iExljEvZ2JW9nDf8lsDVjSSVQvHQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c3894\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ff36 ac4d 898d | 110 d299 (0) d3b0 (0) d1d7 (0) d7ac (0)\n001 6 4447 461c 51db 5f00 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 5 18f6 1e2a 1704 0067 | 44 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n003 8 39d1 3f94 3373 3237 | 17 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n004 3 20ae 217f 2101 | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 4 2abb 2a97 2a0a 2995 | 4 2a0a (0) 2abb (0) 2a97 (0) 2995 (0)\n006 1 2f32 | 1 2f32 (0)\n007 1 2d36 | 1 2d36 (0)\n============ DEPTH: 8 ==========================================\n008 1 2ccf | 1 2ccf (0)\n009 1 2c79 | 1 2c79 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","private_key":"1fb0fb0f5bfcd2c5012cb4dcbf3d383d99034d7fc8646fe2fa0239e1f7b51453","name":"node_2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","services":["streamer"],"enable_msg_events":true,"port":33033},"up":true}},{"node":{"info":{"id":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","name":"node_898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","enode":"enode://29ee8c7cc132a4f84a34e6c9a61e9f98998e563662619c46f89e5a5c92e5b62c66230acaaf18ebc8b957a8a49a939fb01da5f5a3493fc7730cfc9e060c72b79f@127.0.0.1:0","enr":"0xf88fb840293b9155cb46e3fe29d5d357c867f2782ac2bc5187314b335ebef943733badfd73796b642fdbc11e618e294d62120f11f47d2c59854f164e09788562a607f4ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329ee8c7cc132a4f84a34e6c9a61e9f98998e563662619c46f89e5a5c92e5b62c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iY0vfUa0lhtkbVphQtVNYjO3+A9mjOI0Ui3QLizFRcs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 898d2f\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 5db0 6103 6ecb 2a97 | 146 775e (0) 77d2 (0) 738c (0) 7290 (0)\n001 7 df1e d863 c441 c832 | 63 d1d7 (0) d3b0 (0) d299 (0) d7ac (0)\n002 7 b7ca b65e badd ba88 | 27 bcc6 (0) b820 (0) b897 (0) b95d (0)\n003 5 90a8 915d 976e 959f | 10 96fc (0) 976e (0) 959f (0) 915d (0)\n004 5 8505 849b 8025 82dd | 5 8505 (0) 849b (0) 8025 (0) 82dd (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 886a 88fe 88a1 | 3 88a1 (0) 88fe (0) 886a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","private_key":"25e10afa4ffc02c1856aaba9b6fa69c4caf4ae6c8d973c1750b152061c409dad","name":"node_898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","services":["streamer"],"enable_msg_events":true,"port":35709},"up":true}},{"node":{"info":{"id":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","name":"node_18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","enode":"enode://df37042646f5b0435bb902440a5d413958bd9962f689e0d6961bae39f3d57cb89b2d3d68f1c1fabd9e003f19da6adafaa8ff0562d694b0971ef0f8e2e0f86ed0@127.0.0.1:0","enr":"0xf88fb84034efdfae1a4a243bc8ceefd19e7c4e762ea36361737f82c06ef963c92c4d112353472336b474557faf93d9ce5a1c58bd8b9bcba68785b4e52629ee8ffd7354590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102df37042646f5b0435bb902440a5d413958bd9962f689e0d6961bae39f3d57cb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GPbmbhzI5iCAiQG1cf31Je6PQYUPrAvQ5cWk3nDF+HM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 18f6e6\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ff36 df1e c832 ad98 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 2 5db0 6103 | 70 775e (0) 77d2 (0) 7290 (0) 738c (0)\n002 3 2101 2c38 2a97 | 32 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n003 6 0b72 0e5e 0cf5 03cc | 22 0a00 (0) 0af9 (0) 0b72 (0) 0ff2 (0)\n004 3 11d4 154b 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 1436 (0)\n005 5 1c9c 1c47 1f85 1f67 | 6 1c8a (0) 1c9c (0) 1c47 (0) 1f85 (0)\n============ DEPTH: 6 ==========================================\n006 2 1a2a 1b83 | 2 1b83 (0) 1a2a (0)\n007 1 19fa | 1 19fa (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","private_key":"f7529dd416080bdc3c1016be896cd1e6d87fb71bc55f747c44045c3c9402c95b","name":"node_18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","services":["streamer"],"enable_msg_events":true,"port":43611},"up":true}},{"node":{"info":{"id":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","name":"node_2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","enode":"enode://c54171c617812d43a66bacc6697a272aefbfe1ea882f9a9842b2e79e50d9db13428c9eaff2ffcfc8e81379c05ecfb7c2ffbf49be202d77295d7a5fec2acb9871@127.0.0.1:0","enr":"0xf88fb840eaa8f6fbd8efdf7f4ac5c88ea73f5cee6af1b1758a94af489c271983e5bb2c4f3bb50aeb95ce0a622acd1b27df421f79272a7b9c7586105d10d13eff4da67a590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c54171c617812d43a66bacc6697a272aefbfe1ea882f9a9842b2e79e50d9db13","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KpfTCKcgJ0pEDfppAcoKVICvm6tY3YpsSv25yD6pZMM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a97d3\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 898d ad98 ac4d c832 | 110 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n001 4 6f5f 461c 51db 5db0 | 70 7125 (0) 7290 (0) 738c (0) 775e (0)\n002 5 0e5e 0451 0067 1704 | 44 0a00 (0) 0af9 (0) 0b72 (0) 0de3 (0)\n003 7 39d1 3f94 35e6 3630 | 17 314a (0) 30be (0) 3089 (0) 3237 (0)\n004 3 20ae 2101 217f | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 5 2f32 2ccf 2c79 2c38 | 5 2f32 (0) 2d36 (0) 2ccf (0) 2c79 (0)\n006 1 2995 | 1 2995 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 2a0a | 1 2a0a (0)\n009 0 | 0\n010 1 2abb | 1 2abb (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","private_key":"2b2842453e6ed09eca9428c5db19b8b65672776bc2596ca6a169f7e0c1f3267e","name":"node_2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","services":["streamer"],"enable_msg_events":true,"port":37171},"up":true}},{"node":{"info":{"id":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","name":"node_29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","enode":"enode://3d3730044b8ce4d12ccf3b85eb20d027bf821a3bc0bba763f66d0e201835ec7251c7e983adadb9fc9ad2fb49970947d933cfe6879c5177ee537e2296f637da44@127.0.0.1:0","enr":"0xf88fb840d429fc88603170892285ce1f6086380d3216e336fd781e762f59b9bafe65394e20fb7f1b86aa2fa9cb38deb354e1d1f709002da5bc651bfefc311dac483657af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023d3730044b8ce4d12ccf3b85eb20d027bf821a3bc0bba763f66d0e201835ec72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KZV+jpKSWox5vfUTKV2Wv7Yvv8WX7hz3Z8fvQI8bEpU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 29957e\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ef07 ff36 c832 ac4d | 110 e027 (0) e775 (0) e7fa (0) e5d7 (0)\n001 4 461c 5db0 6103 6f5f | 70 4bcf (0) 4ac7 (0) 4a8b (0) 49cd (0)\n002 5 1704 1f67 02d8 0067 | 44 1c8a (0) 1c9c (0) 1c47 (0) 1e2a (0)\n003 6 3b78 3f94 3089 3237 | 17 314a (0) 30be (0) 3089 (0) 3237 (0)\n004 3 20ae 217f 2101 | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 4 2d36 2ccf 2c79 2c38 | 5 2f32 (0) 2d36 (0) 2ccf (0) 2c79 (0)\n============ DEPTH: 6 ==========================================\n006 3 2a0a 2abb 2a97 | 3 2a0a (0) 2abb (0) 2a97 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","private_key":"ecb685b96196b2b1ed90974c8c85cfed18d6274a7639640eecea3d33df729790","name":"node_29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","services":["streamer"],"enable_msg_events":true,"port":40859},"up":true}},{"node":{"info":{"id":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","name":"node_6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","enode":"enode://86a0201b07812ffcb8509f76f8966046bb1d05e0aee48cb884b9929d0a20359fe1ac35441ba1519a58dbfa6590727410bae272f3d71a30b917d894e1e5cc8989@127.0.0.1:0","enr":"0xf88fb8401f19a5134f5248a512cc0875add535eef2498e2fac24985b79b3428e94f87a440936fb0de43a4848b4b08bb438377153809518e99bd2b3b41ab92877893578fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10386a0201b07812ffcb8509f76f8966046bb1d05e0aee48cb884b9929d0a20359f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"b19ad+YJLiXlMIQT4CumLBxVkCSJOn+5jiaw80/ti/4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6f5f5a\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 ef07 f7ba ff36 c9f5 | 110 fbf5 (0) fbc8 (0) f925 (0) fe21 (0)\n001 8 0451 0743 1f67 1e2a | 76 1c9c (0) 1c8a (0) 1c47 (0) 1e2a (0)\n002 9 4d10 4109 4646 461c | 38 4bcf (0) 4a8b (0) 4ac7 (0) 49cd (0)\n003 2 77d2 7a60 | 12 738c (0) 7290 (0) 7125 (0) 775e (0)\n004 2 6337 6103 | 9 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c4d 6c73 | 2 6c4d (0) 6c73 (0)\n007 4 6e68 6e05 6ea5 6ecb | 4 6e68 (0) 6e05 (0) 6ea5 (0) 6ecb (0)\n============ DEPTH: 8 ==========================================\n008 1 6fe9 | 1 6fe9 (0)\n009 1 6f2d | 1 6f2d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","private_key":"92f754c50871b54e305f835a6faf7722bfb219adcd6aea6b430a4fe082d5dca5","name":"node_6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","services":["streamer"],"enable_msg_events":true,"port":38657},"up":true}},{"node":{"info":{"id":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","name":"node_886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","enode":"enode://d5df6e2d4f88e0e6096cd3273f0008286a9f7a36e5c6705f89116595e4ea8c52e37570e6afe957ff70d0a32871c3e5a6a3ab64e9d2927eeba8ef68030010c6c4@127.0.0.1:0","enr":"0xf88fb840f7ff3872ab2265f9c5aafbf228e1003c7903bf3c757e67fdff401a6bfd8a886223114715cada6784003648d4e7484150b8ec46c245a46acf0330afde54cefd7e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d5df6e2d4f88e0e6096cd3273f0008286a9f7a36e5c6705f89116595e4ea8c52","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iGr/Hx47hr/pAQZrt5SEUcGP4/jNG3MYsFFUiQyo9zg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 886aff\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0c64 0067 2995 461c | 146 1c8a (0) 1c9c (0) 1c47 (0) 1e2a (0)\n001 8 fe31 ff36 f7fa f7ba | 63 fbf5 (0) fbc8 (0) f925 (0) fe21 (0)\n002 5 b65e b7ca ba88 badd | 27 b2b5 (0) b2a5 (0) b02b (0) b502 (0)\n003 4 959f 915d 90a8 9d0f | 10 96fc (0) 976e (0) 959f (0) 915d (0)\n004 4 8505 82f9 82dd 8025 | 5 8025 (0) 82dd (0) 82f9 (0) 849b (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 898d | 1 898d (0)\n008 2 88a1 88fe | 2 88a1 (0) 88fe (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","private_key":"4cb5893d2151dd13ceab60cbb42058108639b9cc2b3914cbc6145530b864a491","name":"node_886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","services":["streamer"],"enable_msg_events":true,"port":39861},"up":true}},{"node":{"info":{"id":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","name":"node_5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","enode":"enode://a13bd5a44dd15b8d08f8dd72bb7a2c87930d339c65d0073457d89576d4efa9aae2dc8c1cf98cf1849ffbb3025d74e4ba6d7ab69d0f7de9a01b3fcd1c33602678@127.0.0.1:0","enr":"0xf88fb840c81df54245181d95cd7921f23a74ae3d33fd56b42989c6460164f5738ac8b5153164e33366793fcadd86b527e176f78b30442e14f9d726c55e28e808ff75a6860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a13bd5a44dd15b8d08f8dd72bb7a2c87930d339c65d0073457d89576d4efa9aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XbCENsZPTMnis5UONbyK1zmCXj76Z6ZCx3HZWzTLQgw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5db084\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f7ba ad98 898d 886a | 110 f925 (0) fbf5 (0) fbc8 (0) fe21 (0)\n001 9 1704 1a2a 18f6 0451 | 76 1c8a (0) 1c9c (0) 1c47 (0) 1f85 (0)\n002 4 6337 6103 6ecb 6f5f | 32 775e (0) 77d2 (0) 738c (0) 7290 (0)\n003 3 4d10 4447 461c | 23 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n004 2 5308 51db | 8 574f (0) 524d (0) 53a8 (0) 53fe (0)\n005 3 58ed 5823 5b63 | 3 5b63 (0) 5823 (0) 58ed (0)\n============ DEPTH: 6 ==========================================\n006 2 5efb 5f00 | 2 5efb (0) 5f00 (0)\n007 1 5cd2 | 1 5cd2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","private_key":"3ded975bfe84c252cd54697144ffcd0ac6978fc1c80ab6663d4c0b2cb7338d2a","name":"node_5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","services":["streamer"],"enable_msg_events":true,"port":34077},"up":true}},{"node":{"info":{"id":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","name":"node_ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","enode":"enode://909113f035bbc97985e3d769ea806d56160d43b644c84bde7c5f980a314c36cf1016ceab475ccd4f4bda05f0e4143c2d74ac98f7f9ccb910d7864406f2f8865e@127.0.0.1:0","enr":"0xf88fb840148b90cf90d9ca81f69924d5705f155d5adc230d87a2b48d4b1bdedf4936c9a8421003eef921a088bbc6e7b5cdf66d0f50b88dadfff07ee128418404cc5314c90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102909113f035bbc97985e3d769ea806d56160d43b644c84bde7c5f980a314c36cf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rZiZ94ZZSS7CSKiEknp1fz87TnbNKrxGrYdmJR/Yr+0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ad9899\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 2a97 18f6 0067 6f5f | 146 314a (0) 30be (0) 3089 (0) 3237 (0)\n001 6 fe31 ff36 f7ba ef07 | 63 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n002 3 9076 898d 886a | 20 96fc (0) 976e (0) 959f (0) 915d (0)\n003 6 b5b2 b7ca bb90 badd | 17 bcc6 (0) b820 (0) b897 (0) b95d (0)\n004 4 a369 a46d a6fb a653 | 5 a46d (0) a6fb (0) a653 (0) a34e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 af02 ae2b aeb4 | 3 af02 (0) aeb4 (0) ae2b (0)\n007 1 ac4d | 1 ac4d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","private_key":"c8586e1c253506ff671677e75e7d636dfd48f90798d59c6b42bfb77250056cba","name":"node_ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","services":["streamer"],"enable_msg_events":true,"port":33071},"up":true}},{"node":{"info":{"id":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","name":"node_c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","enode":"enode://76942d9ce0d444b30dbb6499273c4aca434d908d0bbe244316cd5621a4921967b8be1024dc9585544e08d91e53aa2e00ad209181beffa6caccc40b66f975dc55@127.0.0.1:0","enr":"0xf88fb840bf9df113c1a80e0937a0f28c991d4bb2c73ebc27ac1aa51c6db9806d3de0ec1439b8249fa929666c4c5b8cfee951e52e670ec77c7a2d5ec4ecd12bc3609e127e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10376942d9ce0d444b30dbb6499273c4aca434d908d0bbe244316cd5621a4921967","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yDK0rWShfaS3lv/KxkbCqmZrJ2qrt+s7/nmB1kpNpAI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c832b4\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 18f6 0067 2a97 2995 | 146 314a (0) 30be (0) 3089 (0) 3237 (0)\n001 4 898d 886a ac4d ad98 | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 9 e514 ec52 ef1b ef07 | 37 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n003 4 d3b0 df1e d887 d863 | 11 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n004 3 c620 c786 c441 | 9 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n005 1 cc20 | 1 cc20 (0)\n006 2 ca04 caf6 | 2 ca04 (0) caf6 (0)\n============ DEPTH: 7 ==========================================\n007 1 c9f5 | 1 c9f5 (0)\n008 1 c898 | 1 c898 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","private_key":"c35521b3ce161ef9f4891093a65fe799e2f359c3418a145bbe0b8d59330fd18a","name":"node_c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","services":["streamer"],"enable_msg_events":true,"port":41037},"up":true}},{"node":{"info":{"id":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","name":"node_461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","enode":"enode://7edde69d3daf04827701687380c3a97d52cdc2358ddae6c097ff34bc5eeeeac0aa926cd6fb97c888a0c344fb17b07929f21de48835de2a3c805e343f66814cf2@127.0.0.1:0","enr":"0xf88fb84011bf54c1453a78871d09dfbf3b20f2efedcd347c5a3fce32edf95929f083231527adad0d0e0ceb8cad68d1bcb7dc5c32ead8fd94aca4aca3e9bb6abc8b1bce3b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027edde69d3daf04827701687380c3a97d52cdc2358ddae6c097ff34bc5eeeeac0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RhzJ8GTm9PBv844NHz8A74gHujHHJY5FPMaC6VUbscY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 461cc9\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ad98 886a ef07 c9f5 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 7 0067 3f94 3237 3373 | 76 314a (0) 30be (0) 3089 (0) 3237 (0)\n002 3 6103 6ecb 6f5f | 32 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n003 6 5308 51db 58ed 5f00 | 15 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n004 2 4e5a 4d10 | 11 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n005 2 41d9 4109 | 2 41d9 (0) 4109 (0)\n006 3 4558 44a1 4447 | 4 4559 (0) 4558 (0) 44a1 (0) 4447 (0)\n007 2 4782 47bf | 2 4782 (0) 47bf (0)\n008 1 46fe | 1 46fe (0)\n============ DEPTH: 9 ==========================================\n009 1 4646 | 1 4646 (0)\n010 1 4636 | 1 4636 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","private_key":"af9f5d0414462a64a90ff3a2fee02742a99043e9971bd04754fbca5a117064c8","name":"node_461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","services":["streamer"],"enable_msg_events":true,"port":45431},"up":true}},{"node":{"info":{"id":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","name":"node_ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","enode":"enode://2d13e3fbcf2f401951af67ee410e6785e91904619b76822ce4337ddae7965c663773cfd671554e0c6ede7518907b8911f6676b5565313b08c451c90a8dcba823@127.0.0.1:0","enr":"0xf88fb84024126a4f41bfdaa7a672735c056cbdcd6917db518e518e9ad6d43d687a7275bb61f0232ccea5eeefd3ee8ffa770501c2a89ba614f63ec29b1f2ac08ba2bb5b8c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032d13e3fbcf2f401951af67ee410e6785e91904619b76822ce4337ddae7965c66","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7we+VZkU7EtZMNkNjYtvMtq566I6zDbxTVEjB/mXQ0g=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ef07be\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2a97 2995 0067 6f5f | 146 314a (0) 30be (0) 3089 (0) 3237 (0)\n001 4 8f21 886a badd ad98 | 47 976e (0) 96fc (0) 959f (0) 915d (0)\n002 3 df1e c9f5 c832 | 26 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n003 6 ff36 fe31 f2d5 f629 | 19 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n004 2 e5d7 e514 | 8 e027 (0) e7fa (0) e775 (0) e5ad (0)\n005 4 eb98 e854 e883 e8ef | 4 eb98 (0) e854 (0) e883 (0) e8ef (0)\n006 2 ed2d ec52 | 2 ed2d (0) ec52 (0)\n007 1 ee5e | 1 ee5e (0)\n============ DEPTH: 8 ==========================================\n008 1 efea | 1 efea (0)\n009 0 | 0\n010 0 | 0\n011 1 ef1b | 1 ef1b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","private_key":"cffbac62882babf0b4dfc14cd40307088b5ce5ccaa138a4f172914575e6393a3","name":"node_ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","services":["streamer"],"enable_msg_events":true,"port":38781},"up":true}},{"node":{"info":{"id":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","name":"node_006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","enode":"enode://f73c1f0ca14af6b0b8fb1eba1c49d0d653a7833cb03dd69d112260a24154d15515ed2fa276e27d6e70ac92d7f11b594ce55a25be21a9637d56289ac3b2294306@127.0.0.1:0","enr":"0xf88fb8400367dfb7465473b46b2a6502bf1f47fd2b2fe0f11e74a750c1c44e3d798efceb606a9f68a49de5f6c4d6a5606653c80257a8f993dd8f600042cbb5cea1b908ab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f73c1f0ca14af6b0b8fb1eba1c49d0d653a7833cb03dd69d112260a24154d155","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AGcn3G9ZsSCyTBe45j+A7zQ5EF+BGP/u1AjxBaSO5gw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 006727\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 886a ad98 c832 fe31 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 4 461c 51db 58ed 5db0 | 70 775e (0) 77d2 (0) 7290 (0) 738c (0)\n002 3 2c38 2a97 2995 | 32 314a (0) 30be (0) 3089 (0) 3237 (0)\n003 6 11d4 14df 1704 18f6 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 7 0af9 0a00 0b72 0cf5 | 11 0af9 (0) 0a00 (0) 0b72 (0) 0d8a (0)\n005 5 0661 0743 0438 045b | 6 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n============ DEPTH: 6 ==========================================\n006 3 02d8 0328 03cc | 3 02d8 (0) 0328 (0) 03cc (0)\n007 0 | 0\n008 1 00c6 | 1 00c6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","private_key":"5eb85f550595a12882aba16bce31535a88504fca1f6f49492226c3baed943110","name":"node_006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","services":["streamer"],"enable_msg_events":true,"port":45081},"up":true}},{"node":{"info":{"id":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","name":"node_f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","enode":"enode://17cec2abc9a0e660f7fe13e3aab5154a566cbbde2e9e0abea28d40e39eb63ec0a917c1040c10c1b2522fc87afce58949b5d8512d66bd953577e7c8ffe29b2727@127.0.0.1:0","enr":"0xf88fb840d12213ec977f33e55ead3ff1c891eadaf9d35e5d9f80da8f41e1723cfc228d17411a705b829183356338bfb66a6e6a3f22d4cd095d3e916ee50c79501b6a92f20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10317cec2abc9a0e660f7fe13e3aab5154a566cbbde2e9e0abea28d40e39eb63ec0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"97rvh2piuS6+XKnsagheDrVP0x4kJeZi7sdH3zzXdZI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f7baef\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6f5f 58ed 5db0 0067 | 146 775e (0) 77d2 (0) 7125 (0) 7290 (0)\n001 6 8f21 886a ac4d ad98 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 2 c832 c9f5 | 26 d3b0 (0) d299 (0) d1d7 (0) d7ac (0)\n003 4 e514 ec52 ef1b ef07 | 18 e027 (0) e7fa (0) e775 (0) e5ad (0)\n004 4 fbf5 f925 ff36 fe31 | 6 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n005 3 f31c f27f f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 3 f45f f456 f5b2 | 6 f4e0 (0) f45f (0) f456 (0) f528 (0)\n007 1 f629 | 1 f629 (0)\n============ DEPTH: 8 ==========================================\n008 1 f773 | 1 f773 (0)\n009 1 f7fa | 1 f7fa (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","private_key":"bd8f1323739a31a9df6d3249c8a7c3b7f087513627688a48ae214cdf08c40828","name":"node_f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","services":["streamer"],"enable_msg_events":true,"port":35911},"up":true}},{"node":{"info":{"id":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","name":"node_c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","enode":"enode://ef16c8f953e0c91672402036963d6771c490e9e0b99eca6f2d42e524b671f062bd499b0de306fe5eed171f48df7bc9f34bd943010925328c9d60ef086579968b@127.0.0.1:0","enr":"0xf88fb840262713d5977cf6a3bafd1062509bc016e5c191c3afe9c7a08a48ed97868b7d933211c89aba69029de45bd8e766b7ff6f2d419b47a5c830ca236eeb4da5ffee270183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ef16c8f953e0c91672402036963d6771c490e9e0b99eca6f2d42e524b671f062","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yfWsr7v4xmZH3gWwhI15RR7uSQcJ1T8Rj8IFFBDMggM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c9f5ac\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6f5f 461c 58ed 5308 | 146 02d8 (0) 0328 (0) 03cc (0) 00c6 (0)\n001 5 886a b7ca badd ba88 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 12 e5d7 e514 ec52 ef1b | 37 e027 (0) e775 (0) e7fa (0) e5ad (0)\n003 6 d640 df1e daec db6a | 11 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n004 3 c441 c620 c786 | 9 c26f (0) c1f9 (0) c6cf (0) c620 (0)\n005 1 cc20 | 1 cc20 (0)\n006 2 ca04 caf6 | 2 ca04 (0) caf6 (0)\n============ DEPTH: 7 ==========================================\n007 2 c898 c832 | 2 c898 (0) c832 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","private_key":"a8e9d35f1da0d512396196bd7847bf29fbc3e45dab549c77015562a5cd6c1d01","name":"node_c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","services":["streamer"],"enable_msg_events":true,"port":36247},"up":true}},{"node":{"info":{"id":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","name":"node_fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","enode":"enode://29c3a81b46834e3d0f6c4169b27c4ce7dea09b4f8ecdf8cafa3b4705fa9fd804d95a4d7f8639754533998af29d1c1681ffd26bf51aa4576a6bf66fd4e59c4636@127.0.0.1:0","enr":"0xf88fb8406318ee2852832b8479302a86a8c52101e4032df0a3751458a30005834cac33085a7c35b08af5014dc752719fbe5642f4752139c909996b751458d0b79ff759420183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10229c3a81b46834e3d0f6c4169b27c4ce7dea09b4f8ecdf8cafa3b4705fa9fd804","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/jFmeeyg4OuCMyWBKlb9J9oCZTsGraL9A7J1Ab2oNxo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fe3166\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0b72 0067 0743 0451 | 146 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n001 6 8f21 886a ad98 b7ca | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 3 c786 c832 c9f5 | 26 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n003 3 e514 ef1b ef07 | 18 e027 (0) e775 (0) e7fa (0) e5ad (0)\n004 5 f2d5 f528 f629 f7fa | 13 f31c (0) f27f (0) f2d5 (0) f4e0 (0)\n005 3 fbc8 fbf5 f925 | 3 fbc8 (0) fbf5 (0) f925 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ff36 | 1 ff36 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 fe21 | 1 fe21 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","private_key":"4cb7e774b4209f69e673c60ecdf42b2d97a6c7acee80dac037fc744274c03d0c","name":"node_fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","services":["streamer"],"enable_msg_events":true,"port":36479},"up":true}},{"node":{"info":{"id":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","name":"node_51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","enode":"enode://c015318af105b1c0aaec79e08f9e9487e8c204c3decc0f161307ee66a71cc5eb7857085301967316982edbd1b3af1895278747273ba557b313f39de6467cef30@127.0.0.1:0","enr":"0xf88fb84065c1481d82bab43cf2b73a6409653ca03d1143d68af8825b5abe412f0ffc61ac5d2f9f6521e6f02a0242b8fb6bff45bbfe129f271e03dd3a7df92a3ddf9a9b990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c015318af105b1c0aaec79e08f9e9487e8c204c3decc0f161307ee66a71cc5eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UdsRSlKCf1t0CIvQ/IfTUinndA59EhvXaZKYOWUWqIA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 51db11\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b7ca badd c9f5 fe31 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 7 39d1 3f94 2101 2a97 | 76 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n002 3 6103 6ecb 6f5f | 32 775e (0) 77d2 (0) 7290 (0) 738c (0)\n003 4 4d10 4109 4646 461c | 23 4a8b (0) 4ac7 (0) 4bcf (0) 49cd (0)\n004 7 5efb 5f00 5cd2 5db0 | 7 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n005 1 574f | 1 574f (0)\n============ DEPTH: 6 ==========================================\n006 5 524d 53a8 53fe 534b | 5 524d (0) 53a8 (0) 53fe (0) 534b (0)\n007 0 | 0\n008 1 512e | 1 512e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","private_key":"463982e5e17d8853a2119047040024cc3e05d9d4fed44bca081b9a757de79e78","name":"node_51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","services":["streamer"],"enable_msg_events":true,"port":46747},"up":true}},{"node":{"info":{"id":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","name":"node_58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","enode":"enode://35dd66ee032741a2c01c7184c5d372ac89b1bfa19121e0208b6bc4554e26a48e2866d923d323b999aa49db2e9c87ad0ba78da81a35d099d44b2ac12e4577c026@127.0.0.1:0","enr":"0xf88fb840043496ba46ff1222fe7d2927803a795654e938ed8bb711b917672f048ef3180357b54d37aa9fd541158c55dea24adf4c62ed7d291e7875c0d5f76a14a12be1670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10235dd66ee032741a2c01c7184c5d372ac89b1bfa19121e0208b6bc4554e26a48e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WO10aVv1J7rJo1DIbTBeU+CMSZl5XhHNOyo29c0l1jc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 58ed74\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c9f5 ef1b f7ba b7ca | 110 e027 (0) e7fa (0) e775 (0) e5ad (0)\n001 5 3f94 35e6 0b72 0e5e | 76 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n002 3 6103 6ecb 6f5f | 32 775e (0) 77d2 (0) 7290 (0) 738c (0)\n003 3 4d10 4109 461c | 23 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n004 3 53fe 5308 51db | 8 574f (0) 524d (0) 53a8 (0) 53fe (0)\n005 4 5db0 5cd2 5efb 5f00 | 4 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n============ DEPTH: 6 ==========================================\n006 1 5b63 | 1 5b63 (0)\n007 0 | 0\n008 1 5823 | 1 5823 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","private_key":"6eeff6ab23e21598ffa4724e7f1c6d198e55378b5315c3e87a2b049bdec8dbba","name":"node_58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","services":["streamer"],"enable_msg_events":true,"port":46637},"up":true}},{"node":{"info":{"id":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","name":"node_baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","enode":"enode://4c1086d46d650500110758f88911d8de08c282320cb28b478685c979ba504a460324e40bf1c4d18435044daf1db70bf50fbad5e5bc783f75141ee51671da1c2a@127.0.0.1:0","enr":"0xf88fb84011f51bcd70f0e65f6e7ff877cd39d60fca04b7df569eecb3f9200c5983c30c66090beb6cfac47e9a17f3d69aa7771c4d48640fc4436bbb1499789941189d0bb00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c1086d46d650500110758f88911d8de08c282320cb28b478685c979ba504a46","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ut3HeK6pes27tbyZdEpVRaurn2BHyB8yh2FkUoesORw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: baddc7\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0e5e 5308 51db 58ed | 146 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n001 5 c9f5 ef07 ef1b fe31 | 63 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n002 4 9d0f 90a8 898d 886a | 20 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n003 5 a369 aeb4 ae2b ad98 | 10 a46d (0) a6fb (0) a653 (0) a34e (0)\n004 6 b2a5 b02b b5b2 b626 | 8 b02b (0) b2b5 (0) b2a5 (0) b502 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 b820 b897 b95d b911 | 4 b897 (0) b820 (0) b95d (0) b911 (0)\n007 1 bb90 | 1 bb90 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 ba88 | 1 ba88 (0)\n010 1 baf2 | 1 baf2 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","private_key":"1b341e606e667d2dee5a1c605b8ab560bf7350972aac6daa482f10d3fcced991","name":"node_baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","services":["streamer"],"enable_msg_events":true,"port":42801},"up":true}},{"node":{"info":{"id":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","name":"node_b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","enode":"enode://830e8810ca164c9d2a65e2235aba3b15b5907afbf93dabb8c5a00c2a21f50b3a0f3f17a4add3a9dc11b898dfaffb40ed51faeaf15f8e8ca83bc7f9bdb499650b@127.0.0.1:0","enr":"0xf88fb8409a15792c3e8fda0fc6163a89bf642573178c1828ebfac480954ce5384512a9144d6ab33233a340364e8b2b24cbce1de306889b420de971650d2efea448ac33f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103830e8810ca164c9d2a65e2235aba3b15b5907afbf93dabb8c5a00c2a21f50b3a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"t8r+1B2sAd1Z4ryuqqtVHr/quOqh+XwYZv4N2udygHs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b7cafe\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0e5e 3f94 35e6 5308 | 146 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n001 5 c9f5 e514 ef1b f7ba | 63 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n002 6 90a8 9d0f 8f21 898d | 20 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n003 3 a369 ae2b ad98 | 10 a46d (0) a6fb (0) a653 (0) a34e (0)\n004 5 bcc6 b911 bb90 ba88 | 9 bcc6 (0) b897 (0) b820 (0) b95d (0)\n005 3 b2b5 b2a5 b02b | 3 b2b5 (0) b2a5 (0) b02b (0)\n006 2 b502 b5b2 | 2 b502 (0) b5b2 (0)\n============ DEPTH: 7 ==========================================\n007 2 b626 b65e | 2 b626 (0) b65e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","private_key":"8734418063f761c7aebb5bd811d651e4eefd0a332a238b3407eab389d174d344","name":"node_b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","services":["streamer"],"enable_msg_events":true,"port":35765},"up":true}},{"node":{"info":{"id":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","name":"node_ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","enode":"enode://e65f236dc029e0361b5115dc919118463ccd09476638ef7c4cf88151a41986426bd3623c7dee6acc1cb636f084e8f2c1cd6a783627bbf0cb45ddbafd57e1c4d2@127.0.0.1:0","enr":"0xf88fb840673785f36dc917ec90991ef9b8599a3710d9a0c7d36ea2aecdc3ebc730f1f9531104d6620e68027de87d0f8574a91458fb0346324b22795901a3dffe062dc4540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e65f236dc029e0361b5115dc919118463ccd09476638ef7c4cf88151a4198642","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uohOXPoe5us4IXGBcR4Buww3s+M9FCTfqJ7T4p72IFs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ba884e\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0e5e 3f94 3373 35e6 | 146 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n001 4 c9f5 ef1b e514 fe31 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 4 90a8 8f21 898d 886a | 20 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n003 4 a369 ae2b ac4d ad98 | 10 a6fb (0) a653 (0) a46d (0) a34e (0)\n004 6 b2a5 b02b b5b2 b626 | 8 b2b5 (0) b2a5 (0) b02b (0) b502 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 b897 b820 b911 | 4 b820 (0) b897 (0) b95d (0) b911 (0)\n007 1 bb90 | 1 bb90 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 baf2 badd | 2 baf2 (0) badd (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","private_key":"ea93ee284f5d410641b1a5125b7deca5a425eb767d97519816ce904c9a5109d4","name":"node_ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","services":["streamer"],"enable_msg_events":true,"port":41725},"up":true}},{"node":{"info":{"id":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","name":"node_53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","enode":"enode://7faeabed37c1721532d3cf55386ceb61d7127283ea741074062c7387ae1b7c9ff851941e9c92460053143e3f856fd6defb1749214ca54c839ac64fe96a8a0c13@127.0.0.1:0","enr":"0xf88fb84025b6f7edf9c4cdbcc94eaa1b1c4f4a202e55a443e4ace9d9896d487de9e2b050369275954c54148b295eb47404201100c10320546a8e4ad3516ba4c280288ea20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037faeabed37c1721532d3cf55386ceb61d7127283ea741074062c7387ae1b7c9f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UwhwhHCMxe5jrEWbGPoQrlKoIxObTsumyGkdSTTy+XE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 530870\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c9f5 e514 ef1b b7ca | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 5 3f94 39d1 3630 1e2a | 76 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n002 6 7dd3 605a 6103 6337 | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 5 4e5a 4d10 4646 461c | 23 4559 (0) 4558 (0) 44a1 (0) 4447 (0)\n004 5 5f00 5cd2 5db0 5823 | 7 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n005 1 574f | 1 574f (0)\n006 2 512e 51db | 2 512e (0) 51db (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 53a8 53fe | 2 53a8 (0) 53fe (0)\n009 1 534b | 1 534b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","private_key":"9d1b128357783fdd85833562ee5ae70767a77d42c4a39b16e33cfceae74fe8cd","name":"node_53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","services":["streamer"],"enable_msg_events":true,"port":43957},"up":true}},{"node":{"info":{"id":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","name":"node_0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","enode":"enode://9de20b1b75da752d129b0fbd52eda941af9eceb5d14f591ba77175f5f153ab996b82146163328ca097a16b7fb0ed20190dd92ac98b14c785e70658a8c5be1929@127.0.0.1:0","enr":"0xf88fb8406df78c1282722ffe5f759e7116db3a62ef5c3b47ea34e4cef4aa028184b113d7735724260b3e1bf01753094e4c48687c79e5c9e7c7f58b547bec67fbeb7c49c80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039de20b1b75da752d129b0fbd52eda941af9eceb5d14f591ba77175f5f153ab99","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Dl4LsTg7LsVpsVeh0q5pAFkquJKig2f1YTpOKcsmUIg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e5e0b\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 90a8 b7ca ba88 badd | 110 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n001 3 4d10 58ed 5308 | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 4 2a97 3f94 3373 35e6 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 5 1704 14df 11d4 18f6 | 22 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n004 4 0743 0451 03cc 0067 | 11 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n005 3 0af9 0a00 0b72 | 3 0af9 (0) 0a00 (0) 0b72 (0)\n006 3 0d8a 0cf5 0c64 | 5 0de3 (0) 0d8a (0) 0cf5 (0) 0c28 (0)\n============ DEPTH: 7 ==========================================\n007 2 0ff2 0fc5 | 2 0fc5 (0) 0ff2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","private_key":"46271e4b8bcd11ac7ea284e6e69d5fbfdab7754d5a04213ffd66697dfea46bcd","name":"node_0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","services":["streamer"],"enable_msg_events":true,"port":36611},"up":true}},{"node":{"info":{"id":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","name":"node_ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","enode":"enode://eac5fa35e65602ec70fd918c6e95a35d1a117b246fe5000ae4bafc6295f7671e4c06e415eb09e684abf780512fc18b2d866c3b71bb3b3c9d43fc4398da38f10e@127.0.0.1:0","enr":"0xf88fb8400fa87d3bd5c13cdf564484f96122c2ebb1bdcce71fdd18d75afe908594a3866c456fe3a118e4261abc0ecce7cbb42c18f1d8566d6c83c5ebd5d07919eb17d5a40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102eac5fa35e65602ec70fd918c6e95a35d1a117b246fe5000ae4bafc6295f7671e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7xtwvwkLyZlLHUXigSxW7LQwqJw0akNr0QiAvNpwA1E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ef1b70\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 4d10 58ed 5308 3f94 | 146 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n001 8 8f21 88a1 90a8 a369 | 47 8025 (0) 82dd (0) 82f9 (0) 849b (0)\n002 4 df1e d887 c9f5 c832 | 26 d299 (0) d3b0 (0) d1d7 (0) d7ac (0)\n003 9 f27f f2d5 f5b2 f629 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 4 e775 e5d7 e54b e514 | 8 e027 (0) e7fa (0) e775 (0) e5ad (0)\n005 3 eb98 e8ef e854 | 4 e883 (0) e8ef (0) e854 (0) eb98 (0)\n006 2 ed2d ec52 | 2 ed2d (0) ec52 (0)\n007 1 ee5e | 1 ee5e (0)\n============ DEPTH: 8 ==========================================\n008 1 efea | 1 efea (0)\n009 0 | 0\n010 0 | 0\n011 1 ef07 | 1 ef07 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","private_key":"108631b63afbc1b7d0f969a4d149576ac6bc3f55beffefa542345c2ff98ac10b","name":"node_ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","services":["streamer"],"enable_msg_events":true,"port":40971},"up":true}},{"node":{"info":{"id":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","name":"node_1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","enode":"enode://35cb12ad89b825a27459675abdf8b7d44cf40ebf61f8a6c848840c068f6cd8a7604420513fa6d34094211e2874d871f3664257b8bbde8d919848cf1ee30c9173@127.0.0.1:0","enr":"0xf88fb840eeddfc21dd882af77ed82462e015105a4fee9ec50091947b3ffb91eadd0bb4f061e244bedab8fcf2d9bd87b0d1c83cbaa50258bc33fac86e0dabb2d263e2f6c40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10335cb12ad89b825a27459675abdf8b7d44cf40ebf61f8a6c848840c068f6cd8a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HirKk/qUQqADSujSlVMN3hb8v6jDcifi5oY7q7D4fDQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1e2aca\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e514 ef1b | 110 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n001 4 6f5f 51db 5308 4d10 | 70 7290 (0) 738c (0) 7125 (0) 77d2 (0)\n002 7 2c38 3373 3237 3630 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 7 0451 0067 0b72 0af9 | 22 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n004 8 11d4 103b 13d6 165f | 12 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n005 2 1a2a 18f6 | 4 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n006 3 1c8a 1c9c 1c47 | 3 1c47 (0) 1c8a (0) 1c9c (0)\n============ DEPTH: 7 ==========================================\n007 2 1f67 1f85 | 2 1f85 (0) 1f67 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","private_key":"ca298ecc80c2176e1dce1fbf5ccfa90cf337a507c12be6f986d2de3350d01f28","name":"node_1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","services":["streamer"],"enable_msg_events":true,"port":34411},"up":true}},{"node":{"info":{"id":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","name":"node_e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","enode":"enode://fd27bc291857dfd075b45f5afda76cffc42c2fd3c6cbbd041160f4468daccd297f427de0a2d6d348a61fd628559798012d4a700d99f5d9c2ccefc12424e71a9e@127.0.0.1:0","enr":"0xf88fb8406833bd658c2dee1b0266e4979790bf604d3a078226e16c2bfcfbba4b009599331864bee8af31e7b121cd49e9caf0d21533f91bc0cdac69a7ff3660f0093e1a320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fd27bc291857dfd075b45f5afda76cffc42c2fd3c6cbbd041160f4468daccd29","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5RSc7dmQBy8qqpc1qSWfKJc8RYdmYMLYasEF5WzKjmg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5149c\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5308 4d10 3f94 3373 | 146 775e (0) 77d2 (0) 7290 (0) 738c (0)\n001 7 8f21 88a1 90a8 ae2b | 47 849b (0) 8505 (0) 8025 (0) 82dd (0)\n002 4 df1e d887 c832 c9f5 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 5 f5b2 f7ba f925 ff36 | 19 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n004 4 eb98 ec52 ef07 ef1b | 10 e854 (0) e883 (0) e8ef (0) eb98 (0)\n005 1 e027 | 1 e027 (0)\n006 2 e7fa e775 | 2 e7fa (0) e775 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e5ad e5d7 | 2 e5ad (0) e5d7 (0)\n009 2 e547 e54b | 2 e547 (0) e54b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","private_key":"4f4ad194adef3b2bc3e2726a7b609ae7bda912d4e2086f1a13e4c4ba668c60ac","name":"node_e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","services":["streamer"],"enable_msg_events":true,"port":42997},"up":true}},{"node":{"info":{"id":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","name":"node_35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","enode":"enode://6c8c3cbf0d25b5021ca9930a6ec6a174a1408d306e91b340285357ce11ef1be7595292e2c9d678ecaad46e85c67e2548b6f8d001240ab47711a7bf12d84ccf82@127.0.0.1:0","enr":"0xf88fb84040cae853fa9515e6bbe0adcbf29a86d0a760543dcbc0e6d834dbbf0fa17b67074b1ac65a884606be1e2fd6bce5dee242940fccc40d35cb5189481b6a539a036f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026c8c3cbf0d25b5021ca9930a6ec6a174a1408d306e91b340285357ce11ef1be7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Neax0x9ZTAa3WVJUNKfnF+vm8nygGI8kftEkdmSlBWM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 35e6b1\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 8f21 90a8 ae2b ba88 | 110 849b (0) 8505 (0) 8025 (0) 82dd (0)\n001 2 58ed 4d10 | 70 7920 (0) 7a60 (0) 7b90 (0) 7e04 (0)\n002 2 0e5e 1e2a | 44 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n003 7 2101 2d36 2c79 2c38 | 15 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n004 3 39d1 3b78 3f94 | 7 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n005 5 314a 3089 3373 33b5 | 6 314a (0) 30be (0) 3089 (0) 3237 (0)\n============ DEPTH: 6 ==========================================\n006 3 3630 378e 3780 | 3 378e (0) 3780 (0) 3630 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","private_key":"2a62a26311a24b08194c69ebc1ed52e217472f0342db63d881497f987b889e06","name":"node_35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","services":["streamer"],"enable_msg_events":true,"port":46321},"up":true}},{"node":{"info":{"id":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","name":"node_3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","enode":"enode://218760aa13e26a18b74d2337eef240198ccd4014e8a65b603ed92ccdb48ccd8b943f256eb6e58c6fbdce24b409b2775b2d6004401320c919188e7fcb09244fd1@127.0.0.1:0","enr":"0xf88fb840177a2dfc1f89c96d70eddc71b4f1b0bac49f90fee6d0eac21cbb5d5d2405a3a942e28c9535399cbe5914256c761ecb4a5f3f6563090d48314533f0c5234aa2dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103218760aa13e26a18b74d2337eef240198ccd4014e8a65b603ed92ccdb48ccd8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"P5RpV9kQF5x+GoPEQ2mqz8MfVyexpkIaAcipeMzTSaI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3f9469\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 e514 ef1b 90a8 a369 | 110 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n001 5 5308 51db 58ed 461c | 70 738c (0) 7290 (0) 7125 (0) 77d2 (0)\n002 3 0e5e 0b72 1e2a | 44 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n003 7 20ae 2101 2a0a 2a97 | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 7 3089 3237 33b5 3373 | 10 314a (0) 30be (0) 3089 (0) 3237 (0)\n005 3 3b88 3b78 39d1 | 3 3b88 (0) 3b78 (0) 39d1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 3ec5 3efc 3e8e | 3 3ec5 (0) 3efc (0) 3e8e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","private_key":"de36f03ed3bf0ec0a7710fc3c4999f66c685bbfddcfb8e9d4317b92303a74e11","name":"node_3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","services":["streamer"],"enable_msg_events":true,"port":33705},"up":true}},{"node":{"info":{"id":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","name":"node_4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","enode":"enode://9fecc8c4179e541e1fdf6df9acbe9fae124b26643c32c708bf43248ffa03ddc74085be1fbc7c6b26380bd54278b407e48f5ec005564f3715ddefef423e750ba0@127.0.0.1:0","enr":"0xf88fb84029f04153f5367d5275a8df9d644838126a5b32d2c4a8f463c54a8609f02f5ad3544851613d9bb9b0bd12cf4b0dfc60c0172093608372dfa04498cc981d46ed330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029fecc8c4179e541e1fdf6df9acbe9fae124b26643c32c708bf43248ffa03ddc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TRA+xa/uVZpakkLo1lC2cwHq7BDpb8LxhONNSFVBCKI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d103e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 90a8 ef1b e514 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 9 1e2a 0e5e 0b72 3630 | 76 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n002 3 6f5f 6ecb 6103 | 32 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n003 5 5308 51db 5efb 5db0 | 15 5cd2 (0) 5db0 (0) 5f00 (0) 5efb (0)\n004 3 461c 4646 4109 | 12 4558 (0) 4559 (0) 44a1 (0) 4447 (0)\n005 2 49ea 4990 | 6 4a8b (0) 4ac7 (0) 4bcf (0) 49cd (0)\n006 1 4e5a | 1 4e5a (0)\n007 1 4c9e | 1 4c9e (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 4d6b 4d59 | 2 4d6b (0) 4d59 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","private_key":"ad04bf4b2168140a7de043f21b791b383b022dac606699911e318f75f7e012a6","name":"node_4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","services":["streamer"],"enable_msg_events":true,"port":33673},"up":true}},{"node":{"info":{"id":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","name":"node_33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","enode":"enode://50cec87bfc82507362c651f325c755f33d697e3e496e3eb72eb1c8f641ced88174ccc2b56cb7eba56579b61aceb18409c188d359f42f940805f5719740feb48e@127.0.0.1:0","enr":"0xf88fb840fd82bf7592c1d6a7814691efa8bd411452d956b60e269042831484ddceacc538104f0cb3828b7c706e383762f656ed7ec9fd288aa59b3c8d81f301a7a7f324f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10250cec87bfc82507362c651f325c755f33d697e3e496e3eb72eb1c8f641ced881","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"M3N991u6wbQcY/Beos8VI7ly3xfyK9oCbbhKSaw14eM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 33737d\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ef1b e514 ae2b a369 | 110 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n001 3 461c 4109 4d10 | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 4 1e2a 0e5e 0a00 0b72 | 44 13d6 (0) 103b (0) 11d4 (0) 17db (0)\n003 5 20ae 2c38 2c79 2995 | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 4 3b78 39d1 3e8e 3f94 | 7 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n005 4 35e6 378e 3780 3630 | 4 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n006 2 314a 3089 | 3 314a (0) 30be (0) 3089 (0)\n============ DEPTH: 7 ==========================================\n007 1 3237 | 1 3237 (0)\n008 1 33b5 | 1 33b5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","private_key":"9f972993b709e1ac19e7f49e4661fb3fb6e83534f66a12560073a6b5f59e7a0c","name":"node_33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","services":["streamer"],"enable_msg_events":true,"port":45909},"up":true}},{"node":{"info":{"id":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","name":"node_0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","enode":"enode://54b6d4a2a040be9a1af28fe91fcc2b187d4d6db27d970a10e744a69da4ac97260a7c57234a2c4e8ca82d46c4c72fd473d0023c622618c46fa794574590533fc8@127.0.0.1:0","enr":"0xf88fb840557305af7ee9557cc3f0d4e0ddc142adc3005a0b56e35a383a8f246c5b42adb234b65621b68d96643290b25ed4e6fc5777c5fa7a380d5f7806b6778a185a98340183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10254b6d4a2a040be9a1af28fe91fcc2b187d4d6db27d970a10e744a69da4ac9726","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"C3IFRAP3imSnh/Runya/Dee7ulpgyxBeau6kbLSh2f4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0b7205\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 fe31 e514 a369 ae2b | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 3 58ed 4109 4d10 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 5 39d1 3f94 3630 3237 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 6 1e2a 18f6 13d6 11d4 | 22 103b (0) 11d4 (0) 13d6 (0) 17db (0)\n004 4 0438 0451 00c6 0067 | 11 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n005 6 0d8a 0de3 0cf5 0ff2 | 8 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 0af9 0a00 | 2 0a00 (0) 0af9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","private_key":"2f67175c7773d3b089b81b72210bd644855f6736a44e7e931e02c64a35326338","name":"node_0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","services":["streamer"],"enable_msg_events":true,"port":38921},"up":true}},{"node":{"info":{"id":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","name":"node_90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","enode":"enode://a2ad93ada8513b3feec771d73b08d372a7b89a5c6454e82f911e9fcd3b0f23929a604336b8501f89709f9eec253ed726d85e6c8ab08fc2473ba7fc9e96850147@127.0.0.1:0","enr":"0xf88fb840254e8f00ffa322391cdce60e7cd38fdbd46e5ee8cafdd7062a8985c381f69bce78fbb9bd468d7bd2d237a777c29badc74945574f72987aa21368ce6417bd55280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a2ad93ada8513b3feec771d73b08d372a7b89a5c6454e82f911e9fcd3b0f2392","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kKhctzY+3hYewhzIn4udQ1DlZs8QWGpm0xsKhndiCqE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 90a85c\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 4109 4990 4d10 39d1 | 146 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n001 5 d887 f5b2 f925 ef1b | 63 f31c (0) f2d5 (0) f27f (0) f629 (0)\n002 11 b02b b7ca bcc6 b911 | 27 b2b5 (0) b2a5 (0) b02b (0) b502 (0)\n003 5 8505 898d 886a 88a1 | 10 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n004 4 9fa0 9d0f 9852 9890 | 4 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n005 3 96fc 976e 959f | 3 96fc (0) 976e (0) 959f (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 915d | 1 915d (0)\n008 1 9076 | 1 9076 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","private_key":"ffbd3e52d4e07351ecaee805eb3df2eb83b6551d4ccecf49abe430b00d7b91ef","name":"node_90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","services":["streamer"],"enable_msg_events":true,"port":39339},"up":true}},{"node":{"info":{"id":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","name":"node_32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","enode":"enode://e26885995135217d285cbb3b0e44b2071d1247163affddea0fcd9f8b15a18fa900829a0118a2b2d366315f76b3811f4eb2be6a1edeaee8822be120da9629c074@127.0.0.1:0","enr":"0xf88fb8402421fb3a7727b2a4dbe62787a620aae3cda4704b08fd927939ffcf06d34d03a2386a8a340e265804a54d9c97eafe0cd662091e66bc27ad1a15fb88004c154a800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e26885995135217d285cbb3b0e44b2071d1247163affddea0fcd9f8b15a18fa9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MjcXRBY/Czrv05VdxId+frgrF++VQcMzypwKn4rsMEU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 323717\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a369 88a1 90a8 | 110 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n001 3 4d10 461c 4109 | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 6 0b72 0af9 0a00 14df | 44 13d6 (0) 103b (0) 11d4 (0) 17db (0)\n003 6 20ae 2a97 2995 2d36 | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 3 3f94 3b78 39d1 | 7 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n005 2 35e6 3630 | 4 35e6 (0) 378e (0) 3780 (0) 3630 (0)\n006 3 314a 30be 3089 | 3 314a (0) 30be (0) 3089 (0)\n============ DEPTH: 7 ==========================================\n007 2 33b5 3373 | 2 33b5 (0) 3373 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","private_key":"109c5f2cf1f93926c20d740de91bde530a1068766dcdbd6f5a6c9eb561fad11e","name":"node_32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","services":["streamer"],"enable_msg_events":true,"port":40865},"up":true}},{"node":{"info":{"id":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","name":"node_3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","enode":"enode://902e0d821e6d4faadd41284e24f3566060b4d34a47a6a0b333365eef089321dbf8bf9a37c56df31c9f8d4d8489a329022bff87a8cb8bd8017a3b18f328fd984e@127.0.0.1:0","enr":"0xf88fb8401181684970ecc7675258fe5a3c5d354b1a7cab6dd97d2507ab00388013e7c8a76456556bdd0950ab1348bc7afa60ba1c68dae5634f81e10f5b475f7e83ba68c50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102902e0d821e6d4faadd41284e24f3566060b4d34a47a6a0b333365eef089321db","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NjDgUya6zqj8xznexCCF+EX0Ft3GmMdv+R8JnrHcUAc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3630e0\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ae2b 90a8 88a1 | 110 f31c (0) f2d5 (0) f27f (0) f629 (0)\n001 4 5308 5efb 4d10 4109 | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 6 0af9 0a00 0b72 1e2a | 44 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n003 4 217f 2c79 2c38 2a97 | 15 256e (0) 24b8 (0) 21a0 (0) 217f (0)\n004 3 3f94 3b78 39d1 | 7 3efc (0) 3ec5 (0) 3e8e (0) 3f94 (0)\n005 6 30be 3089 314a 33b5 | 6 30be (0) 3089 (0) 314a (0) 33b5 (0)\n006 1 35e6 | 1 35e6 (0)\n============ DEPTH: 7 ==========================================\n007 2 378e 3780 | 2 378e (0) 3780 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","private_key":"4f229a82b34c1d7a77db8b8205e0b0b31f129792a80377a9f140d310e6b27d84","name":"node_3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","services":["streamer"],"enable_msg_events":true,"port":43205},"up":true}},{"node":{"info":{"id":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","name":"node_88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","enode":"enode://748dfc4bce4346bdaee02bcdfc7b514fc6f9f0b74a7a2004e7beed2f9d7aa6eb82f41ede70c832e42af0767aaca3b7057427d140425ca9c052769d13382a475e@127.0.0.1:0","enr":"0xf88fb840e79a123d27b2f56ef3ee3b91fba3d7b33bade6191df9567cb607d85c896d09d51ee353973b9b6f21075dbea43685d639fa90e16d920e31bc814d94e1e55fe06d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102748dfc4bce4346bdaee02bcdfc7b514fc6f9f0b74a7a2004e7beed2f9d7aa6eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iKFBxgcBlHfHsSClBihachjK0vqgOAguC53fzJy3jQc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 88a141\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4990 4109 14df 3b78 | 146 77d2 (0) 775e (0) 7290 (0) 738c (0)\n001 5 f925 f5b2 e514 ef1b | 63 eb98 (0) e854 (0) e8ef (0) e883 (0)\n002 9 b7ca b02b bcc6 b911 | 27 b5b2 (0) b502 (0) b626 (0) b65e (0)\n003 3 9852 9076 90a8 | 10 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n004 3 849b 8505 82dd | 5 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 898d | 1 898d (0)\n008 1 886a | 1 886a (0)\n009 1 88fe | 1 88fe (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","private_key":"7c46b2b4c2eb41cbdc91b22dd94083a9d5a9ebcefddb2dca52e0356c8ab2d0f2","name":"node_88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","services":["streamer"],"enable_msg_events":true,"port":33659},"up":true}},{"node":{"info":{"id":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","name":"node_a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","enode":"enode://fc254f0aa0e39064101549ffcc69b2251433b96a80b540da96bfcde9c4e3f979f38f7351eb100fb11660b20a5da1e8c221073a719d331eaae06053de933916b8@127.0.0.1:0","enr":"0xf88fb840b3a10df042ede6a04af90f6ea1f32e3cc6144419c04ed87f500e8da294aec02e0a48ec2a277af3cf3663ad966204d93a0e74d0c581f38b72819a5f3bb3439db20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fc254f0aa0e39064101549ffcc69b2251433b96a80b540da96bfcde9c4e3f979","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"o2k4AakRgEEM8+hdfAmsgFSnaeex1VyeekaFDLghfaA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a36938\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0b72 14df 11d4 3373 | 146 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n001 5 d887 f5b2 f925 ef1b | 63 eb98 (0) e883 (0) e8ef (0) e854 (0)\n002 4 90a8 8505 8f21 88a1 | 20 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n003 5 b7ca b897 badd ba88 | 17 b502 (0) b5b2 (0) b626 (0) b65e (0)\n004 5 ac4d ad98 af02 aeb4 | 5 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n============ DEPTH: 5 ==========================================\n005 3 a46d a6fb a653 | 3 a6fb (0) a653 (0) a46d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 a34e | 1 a34e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","private_key":"9086c71a5873a4830e93448202ba724d3b0a168a8ef3a9fc05037416ae0e9ac9","name":"node_a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","services":["streamer"],"enable_msg_events":true,"port":41127},"up":true}},{"node":{"info":{"id":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","name":"node_41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","enode":"enode://48e3c3f7c9a9799de669a30ca9e8a74ed910aafd4ec3152cfe8688c9ce67997a955265bf9d18f30d988b81bcadb058fdfcd5822e37085fafd1cf3e3f0994a91c@127.0.0.1:0","enr":"0xf88fb840217cf3239a54cb3b089cbdc4bfa0fc3bd9e7921e1d28b05f7310e8c3a6f02b7c041bc83c1b95c201a33cbeedb581a51ce4fbdf683bc86ac1d6aaaa1127b7b8cd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10248e3c3f7c9a9799de669a30ca9e8a74ed910aafd4ec3152cfe8688c9ce67997a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QQkshS+sYw3yqcoIYnFvjp+4VmyQSknJY4kHEEa8aZ0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 41092c\npopulation: 45 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d887 90a8 8f21 88a1 | 110 e854 (0) e8ef (0) e883 (0) eb98 (0)\n001 9 0af9 0b72 11d4 14df | 76 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n002 7 6f5f 6e68 66e7 6103 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 6 5cd2 5823 58ed 51db | 15 574f (0) 524d (0) 53a8 (0) 53fe (0)\n004 6 4bcf 49ea 4990 4e5a | 11 4a8b (0) 4ac7 (0) 4bcf (0) 49cd (0)\n============ DEPTH: 5 ==========================================\n005 10 4559 4558 4447 44a1 | 10 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n006 0 | 0\n007 0 | 0\n008 1 41d9 | 1 41d9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","private_key":"6ddd3b1c12e06aba0ea262fc99bafec26b2f94fb5f347ab60518afc39741fdc9","name":"node_41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","services":["streamer"],"enable_msg_events":true,"port":39355},"up":true}},{"node":{"info":{"id":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","name":"node_ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","enode":"enode://63c769772cdc9c83c9254df508ecd82cf62909028da5d232e02375859a0c0e16ab09257681fccde8b6f99302465f29d7119a5a679e9eb722dd84aeeafad3290e@127.0.0.1:0","enr":"0xf88fb840ffd15988f81a75ca61b73d7267d740abba2f0fc56d28354888cf7f21cc6d5c006b2b1189d3572d77a3d8fb9067ff3678f24b6eff94085bb0fa0693f5ea885f8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10263c769772cdc9c83c9254df508ecd82cf62909028da5d232e02375859a0c0e16","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ris4dr29Y4h4G2XjHeGCVkxdgfRRHK+WWIsaKHdgs90=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ae2b38\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0b72 14df 3373 35e6 | 146 0438 (0) 045b (0) 0451 (0) 07a8 (0)\n001 5 f925 f5b2 ef1b e514 | 63 eb98 (0) e854 (0) e8ef (0) e883 (0)\n002 4 9076 90a8 8f21 88a1 | 20 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n003 6 b7ca b02b bcc6 badd | 17 b5b2 (0) b502 (0) b626 (0) b65e (0)\n004 4 a653 a46d a34e a369 | 5 a653 (0) a6fb (0) a46d (0) a34e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 ac4d ad98 | 2 ac4d (0) ad98 (0)\n007 1 af02 | 1 af02 (0)\n008 1 aeb4 | 1 aeb4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","private_key":"9812258a3e70549d501e1fb2b90b4728c6dcfc8ccbbb9892c370214b60d40535","name":"node_ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","services":["streamer"],"enable_msg_events":true,"port":36649},"up":true}},{"node":{"info":{"id":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","name":"node_39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","enode":"enode://64dd3388d784dcfff0bac93ac16b10d6a237024d609e79fd786f239d70d11292965e419f1feda3335a52b909229e85aeaa913d608cae51f7e22ea404a014b802@127.0.0.1:0","enr":"0xf88fb8403d980a1425e3cf5c0382d08284c76c76c84e06a2cc0019ff0fc7dbeb15976c6172bfe4f485c7d23c69f0e8139964ba0c7e55a3e460b1b9a18b3da2df51b4ae950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10264dd3388d784dcfff0bac93ac16b10d6a237024d609e79fd786f239d70d11292","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OdH8ri0jx3UhSYglFQXFd7mse2hRVY3fmkN9/hQ/OEU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39d1fc\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f5b2 d887 90a8 88a1 | 110 e854 (0) e8ef (0) e883 (0) eb98 (0)\n001 12 7125 7dd3 605a 6e68 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 8 00c6 0b72 0af9 0a00 | 44 0438 (0) 045b (0) 0451 (0) 07a8 (0)\n003 5 2a97 2d36 2c38 2c79 | 15 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n004 7 314a 3089 33b5 3373 | 10 314a (0) 30be (0) 3089 (0) 33b5 (0)\n005 2 3e8e 3f94 | 4 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n============ DEPTH: 6 ==========================================\n006 2 3b88 3b78 | 2 3b88 (0) 3b78 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","private_key":"3cba669ea7a686fe849ec5128b993a7fec64971638bff4ec54c386bff7214559","name":"node_39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","services":["streamer"],"enable_msg_events":true,"port":42159},"up":true}},{"node":{"info":{"id":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","name":"node_8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","enode":"enode://c61eb191e326e233f19223d31784f89dd3cb5712942a686877717d74afd735e118acf5e05da708b122eed47a681888a14c93072ccb1b425c3c58ffc60b1b6f7c@127.0.0.1:0","enr":"0xf88fb8401d4e08ac54c6ca41a0cbd145e8a06eada8b2a58062c2c9552957749da5bbd29c371325ed9de3b9214139dda907e2c2be86e1710583b02f6fe8550c6fa50e022c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c61eb191e326e233f19223d31784f89dd3cb5712942a686877717d74afd735e1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jyGCwsLQ7rLoh9vDUK5yV4GfU2AyhR/98p54QssaYsw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8f2182\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4646 4109 11d4 35e6 | 146 67aa (0) 67dc (0) 66e7 (0) 6251 (0)\n001 10 d887 ef1b ef07 e514 | 63 e854 (0) e8ef (0) e883 (0) eb98 (0)\n002 10 b02b b7ca bcc6 b911 | 27 b502 (0) b5b2 (0) b626 (0) b65e (0)\n003 4 9d0f 9852 9076 90a8 | 10 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n004 4 82dd 82f9 849b 8505 | 5 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n============ DEPTH: 5 ==========================================\n005 4 898d 886a 88fe 88a1 | 4 898d (0) 886a (0) 88fe (0) 88a1 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","private_key":"7da220e22f5a60bbb45c6c72883ee7c9680618b47c02741e3ffa840db42e0d8e","name":"node_8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","services":["streamer"],"enable_msg_events":true,"port":33809},"up":true}},{"node":{"info":{"id":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","name":"node_11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","enode":"enode://5a7570e6530a10db24b16f65a03b866013f409038c203dbdd432072f7d5048d389a66e7235576389e8633012bd367d983c5325a693ebc5bfe2b18a86e22ae598@127.0.0.1:0","enr":"0xf88fb840227240ac5b5e7e60e5754fbd36dadae2db7ba6a39745b0b02fc5303803afa203490c7fba99331c4338d767e68ce601f95e92d0cc9d4136708fca9cc5d9766a110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025a7570e6530a10db24b16f65a03b866013f409038c203dbdd432072f7d5048d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EdQ/btDd1a+lyKer98YqT6hlt6Je4pW/GklwHvMIE2M=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 11d43f\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d887 bb90 a369 8f21 | 110 eb98 (0) e8ef (0) e883 (0) e854 (0)\n001 5 7dd3 4990 49ea 4109 | 70 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n002 4 3237 3630 39d1 3b78 | 32 256e (0) 24b8 (0) 20ae (0) 217f (0)\n003 6 00c6 0067 0e5e 0b72 | 22 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n004 5 18f6 19fa 1e2a 1f67 | 10 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n005 9 1704 17db 179f 1672 | 9 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 6 ==========================================\n006 1 13d6 | 1 13d6 (0)\n007 1 103b | 1 103b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","private_key":"219dac0c9e412e884796b76e8f34df3ab01ed79aec554cede6881de4d40236f8","name":"node_11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","services":["streamer"],"enable_msg_events":true,"port":40541},"up":true}},{"node":{"info":{"id":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","name":"node_3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","enode":"enode://24fd229270ea0d538333b0a4aafd5aff71f1783569175335b1d90f0edffade66ba7c66972ba0e5e1862b468c0cb4245f1852e5778d8eefc014daa1f55136a7af@127.0.0.1:0","enr":"0xf88fb840c92aeac9460bef8b28eecae10683b0871da8063062965e99ecc8a759dfdc230820f2a00376fb89d159b3f24bd098f7f2689ad9750ad6e7b960138598b3afc0b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10324fd229270ea0d538333b0a4aafd5aff71f1783569175335b1d90f0edffade66","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O3i8mHx8MclOitqbSxG125OH/nDdAc5/PpdtO+xDPew=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b78bc\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 88a1 bb90 a369 ae2b | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 4 5efb 4990 4646 4109 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 6 00c6 0af9 0a00 14df | 44 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n003 5 2101 2995 2f32 2d36 | 15 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n004 6 3630 35e6 314a 3237 | 10 314a (0) 30be (0) 3089 (0) 33b5 (0)\n005 4 3e8e 3ec5 3efc 3f94 | 4 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n============ DEPTH: 6 ==========================================\n006 1 39d1 | 1 39d1 (0)\n007 0 | 0\n008 1 3b88 | 1 3b88 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","private_key":"005d083eb3a257750c097d09e17a10c58264917fa06535586128643b104277c2","name":"node_3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","services":["streamer"],"enable_msg_events":true,"port":36675},"up":true}},{"node":{"info":{"id":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","name":"node_14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","enode":"enode://2a6142cda1601b228a9c6960fa90278c011610caf1c0109047931f409d5c69beb1383db75c7edd51dcae1b4a0a74af47ddbfb3cb14d4b9adac497d92c870ee2c@127.0.0.1:0","enr":"0xf88fb840a90ca3b818792d943f2120428d70855db44a6aa36d9a209e3ef9aadc13b3a3380939a0ea38235e3a786c5fa856c56bee157f75c45bc64251e000f5110bccf84c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022a6142cda1601b228a9c6960fa90278c011610caf1c0109047931f409d5c69be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FN+4QU0Xst8V6vWVcajP7Jmx/WdFYdpj7pmvhTvaB9o=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 14dfb8\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 88a1 a369 ae2b d887 | 110 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n001 4 49ea 4990 4109 4646 | 70 77d2 (0) 775e (0) 738c (0) 7290 (0)\n002 4 3237 3630 39d1 3b78 | 32 256e (0) 24b8 (0) 20ae (0) 217f (0)\n003 6 0067 00c6 0e5e 0b72 | 22 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n004 3 1c9c 1f67 1e2a | 10 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n005 3 13d6 103b 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 5 1704 17db 179f 1672 | 5 1704 (0) 17db (0) 179f (0) 1672 (0)\n007 1 154b | 1 154b (0)\n============ DEPTH: 8 ==========================================\n008 2 1400 1436 | 2 1400 (0) 1436 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","private_key":"9f60424e94bf49f4831f8875a348ff8684b25041feb915b3062e329bc6bde720","name":"node_14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","services":["streamer"],"enable_msg_events":true,"port":33225},"up":true}},{"node":{"info":{"id":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","name":"node_d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","enode":"enode://e27e5fe8c0fc1d5c19e4c43062e74e25d5b285ab4d87d9f6f0639f977473f6132ebec497112fb9ae28257aba65e66cff848d950d90d74301faee81243b2b354e@127.0.0.1:0","enr":"0xf88fb840d61802d9193750fd40278a66d4f73473dfb6ff6577a0f122efdee8265ca9f02a080bed7a061796672fa8e20230725617a89f348724b82705106550e47856543e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e27e5fe8c0fc1d5c19e4c43062e74e25d5b285ab4d87d9f6f0639f977473f613","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2IcHCgVoKCxp6WzmVhK6ctXqJrXIBnFDXW4e0sS0kwE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d88707\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 49ea 4109 4646 39d1 | 146 775e (0) 77d2 (0) 7290 (0) 738c (0)\n001 9 90a8 8f21 88a1 a369 | 47 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n002 5 eb98 ef1b e514 f925 | 37 e027 (0) e7fa (0) e775 (0) e5ad (0)\n003 6 c1f9 c620 c9f5 c898 | 15 c26f (0) c1f9 (0) c49c (0) c441 (0)\n004 3 d1d7 d299 d3b0 | 5 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n005 1 df1e | 1 df1e (0)\n============ DEPTH: 6 ==========================================\n006 3 db6a daec da67 | 3 db6a (0) da67 (0) daec (0)\n007 0 | 0\n008 1 d863 | 1 d863 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","private_key":"04afc55a06d4cfd448c6d6574905560d45f4bc8fffe230c686d444d678257ec8","name":"node_d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","services":["streamer"],"enable_msg_events":true,"port":46277},"up":true}},{"node":{"info":{"id":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","name":"node_0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","enode":"enode://ba05d71907202ec66f1ef7f46da693468efea28d0cff6a320b4ed04465b73789f7fb6a9b638d00d75c054815a86c8c71512c605c8a5328aa4f3de656dc83aa4b@127.0.0.1:0","enr":"0xf88fb84081e05173f55c4568ba75436e5ec395bddec7a8bbae9c3c65a8f91b42698bda8407a5e40cacce44a4cecb0384cc14285aaa07669a28a9e69cceb2ec18a4e73f2c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ba05d71907202ec66f1ef7f46da693468efea28d0cff6a320b4ed04465b73789","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CgBeucEMXMn3IM/sKmVYEdORZxWXtPMtEt8pHsdrLBM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0a005e\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bb90 d887 | 110 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n001 4 5efb 49ea 4990 4646 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 5 3630 3373 3237 3b78 | 32 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n003 3 1e2a 11d4 14df | 22 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n004 5 0451 03cc 0328 0067 | 11 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n005 7 0de3 0cf5 0c28 0c64 | 8 0d8a (0) 0de3 (0) 0cf5 (0) 0c28 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 0b72 | 1 0b72 (0)\n008 1 0af9 | 1 0af9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","private_key":"f1681c7b1205d9314840edd16ac9c55cfd362b4feeb60b0066c0a1c69f42f1c4","name":"node_0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","services":["streamer"],"enable_msg_events":true,"port":35965},"up":true}},{"node":{"info":{"id":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","name":"node_0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","enode":"enode://58412ea457c3c490d9c0792f1b0274281f17c3794c31304f2eed90d45520cc37cf639e4f5f2194743af16fedabea43bbc5071077a286b03cc4b65601983ab04d@127.0.0.1:0","enr":"0xf88fb8407fbed396b8c08f1a08e239904d9fbd388627aec4b0e21c946b6d6112154a7d327f8f868440c35fb7a46ceb36684ebaf4437f4472cd88a0983375e4f5b50d610a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10358412ea457c3c490d9c0792f1b0274281f17c3794c31304f2eed90d45520cc37","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Cvmlei9mg1zT5OcbwCYBOoqZyjN6e2tsw04R2NohKk8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0af9a5\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bb90 f5b2 d887 | 110 e027 (0) e7fa (0) e775 (0) e5ad (0)\n001 4 4990 49ea 4109 4646 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 4 3630 3237 3b78 39d1 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 6 1c9c 1e2a 11d4 103b | 22 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n004 4 0661 0328 0067 00c6 | 11 0438 (0) 0451 (0) 045b (0) 0743 (0)\n005 8 0d8a 0de3 0cf5 0c28 | 8 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 0b72 | 1 0b72 (0)\n008 1 0a00 | 1 0a00 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","private_key":"b5347eaddd49eda049687bb250949eca56628c3bddafbccae680b571175f1efe","name":"node_0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","services":["streamer"],"enable_msg_events":true,"port":45487},"up":true}},{"node":{"info":{"id":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","name":"node_4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","enode":"enode://29467abcaeb0c2dcf2dbb6835fbab644652983d04c3c5964c37eaed3c9b33a41f488528f8f11c8b4a73ae223a7c738bc6b1f8e56a5f319556a4c1ffd68865d13@127.0.0.1:0","enr":"0xf88fb84050850c1513e8379df0027113c46bb5f7df2ee2338d8768c7c7e14d4552813c9939b9417c32904d11dcdb010051f77a9f697ea2b46d603e852665b5a9293f08e70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329467abcaeb0c2dcf2dbb6835fbab644652983d04c3c5964c37eaed3c9b33a41","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rkb+TBGQeHOGErRKNWCJs8c6COEc/ZEGddIRrmsguP0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4646fe\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f5b2 d887 8f21 aeb4 | 110 c26f (0) c1f9 (0) c59e (0) c49c (0)\n001 6 3b78 39d1 11d4 14df | 76 256e (0) 24b8 (0) 20ae (0) 217f (0)\n002 6 605a 6c73 6f5f 6e68 | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 6 51db 5308 53fe 5f00 | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 8 4e5a 4c9e 4d10 4d6b | 11 4c9e (0) 4d10 (0) 4d6b (0) 4d59 (0)\n005 2 41d9 4109 | 2 41d9 (0) 4109 (0)\n006 4 4558 4559 4447 44a1 | 4 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n007 2 47bf 4782 | 2 4782 (0) 47bf (0)\n008 1 46fe | 1 46fe (0)\n============ DEPTH: 9 ==========================================\n009 2 461c 4636 | 2 461c (0) 4636 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","private_key":"d31b7865721d5d0ce0dcf9cca1a8187d793be7b377d9d03fc2cb2ee745bee6f3","name":"node_4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","services":["streamer"],"enable_msg_events":true,"port":41715},"up":true}},{"node":{"info":{"id":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","name":"node_bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","enode":"enode://ca69ebb1f7477323104e6a62f28c17ba29b748f75e2f49756f4cbe9393dc68781a244148d0137abd6fb1e4a1b33ffb03045681754e7ddbb371a57dbb88a315c8@127.0.0.1:0","enr":"0xf88fb840fb7786d0be189148e7144a7b9550267ba300810396855dd94b67bc0ba2072fd71c282ccdb2547c15206ad380a71a34fbf70dbfcfecd67df851f468c0b5294c050183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ca69ebb1f7477323104e6a62f28c17ba29b748f75e2f49756f4cbe9393dc6878","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"u5BGT3aahVScFQ+GF3WqZ5JMfGUfOT9scHcnBzdqXH4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bb9046\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 3b78 11d4 0a00 0af9 | 146 256e (0) 24b8 (0) 20ae (0) 217f (0)\n001 3 d887 f925 f5b2 | 63 c26f (0) c1f9 (0) c59e (0) c43f (0)\n002 3 90a8 88a1 8f21 | 20 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n003 5 ad98 aeb4 ae2b a46d | 10 a6fb (0) a653 (0) a46d (0) a34e (0)\n004 3 b7ca b2a5 b02b | 8 b5b2 (0) b502 (0) b626 (0) b65e (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 b897 b820 b95d b911 | 4 b897 (0) b820 (0) b95d (0) b911 (0)\n============ DEPTH: 7 ==========================================\n007 3 ba88 baf2 badd | 3 baf2 (0) badd (0) ba88 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","private_key":"1681a07f3bae8df9da96df7d590316463371480d0ff13eeb1581b97efa00c074","name":"node_bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","services":["streamer"],"enable_msg_events":true,"port":42761},"up":true}},{"node":{"info":{"id":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","name":"node_49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","enode":"enode://00ec342238cfe51f0c655c27411369dca96d92b20f550c84552b0a23cbe14033c1624dff2ff2418e3d11c01f508f68c296985b7f14b508613b8b93d45b743aa7@127.0.0.1:0","enr":"0xf88fb840b31c9684d99503737f5f45f02a3a43e20c768eed666bd2e56982eebc3d5167b06146d790a41a931e1aa570ebfd5928fceb5d9fc58e3520d92c42f2296c8384ce0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10300ec342238cfe51f0c655c27411369dca96d92b20f550c84552b0a23cbe14033","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SeqtaNI91j7yYCn6P04lePPeyocIu8g4dQ2Lbb6eqjg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 49eaad\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f5b2 f925 d887 bb90 | 110 c26f (0) c1f9 (0) c59e (0) c49c (0)\n001 7 39d1 14df 11d4 103b | 76 24b8 (0) 256e (0) 20ae (0) 217f (0)\n002 5 7125 7dd3 605a 6c73 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 2 5cd2 5efb | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 3 4109 41d9 4646 | 12 41d9 (0) 4109 (0) 4447 (0) 44a1 (0)\n005 4 4e5a 4d10 4d6b 4d59 | 5 4c9e (0) 4d10 (0) 4d6b (0) 4d59 (0)\n006 3 4ac7 4a8b 4bcf | 3 4ac7 (0) 4a8b (0) 4bcf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 4990 | 1 4990 (0)\n010 1 49cd | 1 49cd (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","private_key":"9ab9903f8ffceadd1d6a7976373b073696a0ee0055a7208414a8f1679f35e70f","name":"node_49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","services":["streamer"],"enable_msg_events":true,"port":38883},"up":true}},{"node":{"info":{"id":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","name":"node_499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","enode":"enode://c582e81e3c1308e84e2faa3d0e6bc500e0b221cb23082c6d74785246b56e0cef2e971f545dfa3adef1ab1beff9b70e5325cdeff37b7b9c5dd20e1440a73fb632@127.0.0.1:0","enr":"0xf88fb840387099c7431e9b63d69d94cae6d580f16aebc307b79c74b73b25243f0bbf6c8216bc5d70f677116c8007b76373d3e7b4f18e47409a9965230fcc2373473836dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c582e81e3c1308e84e2faa3d0e6bc500e0b221cb23082c6d74785246b56e0cef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SZA2650Q/AA8kD8J6g7gDA0ns5VkmI1nrhEfNHPSLwc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 499036\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b911 b02b 90a8 88a1 | 110 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n001 6 3b78 11d4 14df 0a00 | 76 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n002 4 7125 7dd3 6e68 605a | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 2 5cd2 5efb | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 3 4109 41d9 4646 | 12 41d9 (0) 4109 (0) 4447 (0) 44a1 (0)\n005 4 4d10 4d6b 4d59 4e5a | 5 4c9e (0) 4d59 (0) 4d6b (0) 4d10 (0)\n006 3 4ac7 4a8b 4bcf | 3 4ac7 (0) 4a8b (0) 4bcf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 2 49cd 49ea | 2 49cd (0) 49ea (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","private_key":"c1e2eeef980866cd77150633a76d6a829b17e8cfd20808fb1e2d37307ba092bd","name":"node_499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","services":["streamer"],"enable_msg_events":true,"port":44049},"up":true}},{"node":{"info":{"id":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","name":"node_f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","enode":"enode://e46f5b92ac1643853152ba3b247bd5b51cca33a1be2f8811912a8a4c5a5eb0164fb72f56315e64256925e324661087a4c7a679a181f5afc78f2294e6b2c4d482@127.0.0.1:0","enr":"0xf88fb840a9aa17d842225b019dc9bfc778d998c52b179d856b377bca673ec81ba5fc96043cd2edc2a04f0e9115fe2b78b12778948c8db42f5dd89e0826f0f3ab746be0960183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e46f5b92ac1643853152ba3b247bd5b51cca33a1be2f8811912a8a4c5a5eb016","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9bJKH9LNKQi0CFYvmiZe4aaSsTfncBN6+l/foHsjciE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f5b24a\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 39d1 0af9 00c6 5efb | 146 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n001 8 90a8 8f21 88a1 bcc6 | 47 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n002 5 c620 c898 cc20 d3b0 | 26 c26f (0) c1f9 (0) c59e (0) c49c (0)\n003 5 e514 e775 ef1b e854 | 18 e027 (0) e7fa (0) e775 (0) e5ad (0)\n004 4 ff36 fbf5 fbc8 f925 | 6 fe21 (0) fe31 (0) ff36 (0) fbc8 (0)\n005 2 f31c f27f | 3 f31c (0) f2d5 (0) f27f (0)\n006 4 f629 f7fa f7ba f773 | 4 f629 (0) f7fa (0) f7ba (0) f773 (0)\n007 3 f4e0 f45f f456 | 3 f4e0 (0) f45f (0) f456 (0)\n============ DEPTH: 8 ==========================================\n008 1 f528 | 1 f528 (0)\n009 1 f5dc | 1 f5dc (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","private_key":"dbbb9c96e746abd3f4c880d9fbab46e390a208e8a8fca9b24e83fc12054d6601","name":"node_f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","services":["streamer"],"enable_msg_events":true,"port":38193},"up":true}},{"node":{"info":{"id":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","name":"node_aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","enode":"enode://408575dfa357953549c9a106e6944f5fe874044b6931be8662fe92bda869094fc8a63d0beb139bef8cc4084fea888f605755214a178949930042d4111a9d863f@127.0.0.1:0","enr":"0xf88fb84023e003cb4dba2e193bfda36d19918aba6afe1dd732715d94307795abadfc3f161cda9e4fa8067ebb95e9ee4e057d4be121f96ce68c706483ca3d278da0d210950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103408575dfa357953549c9a106e6944f5fe874044b6931be8662fe92bda869094f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rrTHWlfM/JrAU6PTY898Hj4gFAZYd2mrZhXVwvhqVBA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aeb4c7\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 154b 00c6 4646 5efb | 146 256e (0) 24b8 (0) 20ae (0) 217f (0)\n001 5 d887 cc20 e775 f925 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 6 9852 90a8 9076 8505 | 20 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n003 5 b2a5 b02b bb90 badd | 17 b502 (0) b5b2 (0) b626 (0) b65e (0)\n004 5 a6fb a653 a46d a34e | 5 a6fb (0) a653 (0) a46d (0) a34e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 ac4d ad98 | 2 ac4d (0) ad98 (0)\n007 1 af02 | 1 af02 (0)\n008 1 ae2b | 1 ae2b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","private_key":"557f3cfbd77e4d7aed5ee5eb12fe2b64a66b62b1565779336756894798686fba","name":"node_aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","services":["streamer"],"enable_msg_events":true,"port":41457},"up":true}},{"node":{"info":{"id":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","name":"node_5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","enode":"enode://09a213671160d6c9f446228ec2692c94080d1b2dc94c9d7731e95b0bc481bee4fc4ab0d06fd374a143939d8f7edec35b9412902e448f760d46dce08de953fbfc@127.0.0.1:0","enr":"0xf88fb84028e698a16106eee1826e468d8c150a43995c15e006336c12f9f855178ab5b7e5299f2f54ccdab44826172fc7c3b95fe6748aadccbfe2abc713b61a087af3a3540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10209a213671160d6c9f446228ec2692c94080d1b2dc94c9d7731e95b0bc481bee4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XNI3ciaCXcfqWCMVzRCNI1At9OnHwJ/AfntKpWRA3ik=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5cd237\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f925 bcc6 aeb4 | 110 df1e (0) db6a (0) da67 (0) daec (0)\n001 4 39d1 00c6 154b 103b | 76 24b8 (0) 256e (0) 20ae (0) 217f (0)\n002 4 7dd3 7125 6e68 605a | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 8 41d9 4109 461c 4646 | 23 41d9 (0) 4109 (0) 4558 (0) 4559 (0)\n004 5 51db 524d 5308 534b | 8 574f (0) 512e (0) 51db (0) 524d (0)\n005 3 5b63 5823 58ed | 3 5b63 (0) 58ed (0) 5823 (0)\n============ DEPTH: 6 ==========================================\n006 2 5f00 5efb | 2 5f00 (0) 5efb (0)\n007 1 5db0 | 1 5db0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","private_key":"a4284995d54ea16fb6c05b66a7661d7af0bcad9d23da505a56922f494792bcac","name":"node_5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","services":["streamer"],"enable_msg_events":true,"port":37509},"up":true}},{"node":{"info":{"id":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","name":"node_f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","enode":"enode://77fb0fa620b93ebe2af5e929eaa9f0cdaad26a3530f84e2026b2870c54d5e3f5204889e8ceb85a934b36b96f787031eae04a738bc4b32a53ff25d06f890ccd3f@127.0.0.1:0","enr":"0xf88fb84036fe76e82d48bc24b57dc4307d10a6168bc316938eedbd1a097ba018675fb30b1ab095482cf7f33c126a535acd04e34af2ab224d982993c49222da20f868a17d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10377fb0fa620b93ebe2af5e929eaa9f0cdaad26a3530f84e2026b2870c54d5e3f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+SXIXmRXrAHwzWspcVX5065hFgOJDY86ReE5bZN/hoA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f925c8\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 154b 00c6 49ea 5cd2 | 146 35e6 (0) 378e (0) 3780 (0) 3630 (0)\n001 9 8f21 88a1 90a8 a369 | 47 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n002 6 d887 d3b0 c786 c620 | 26 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n003 4 e514 e775 e854 eb98 | 18 e027 (0) e5ad (0) e5d7 (0) e547 (0)\n004 7 f31c f27f f773 f7ba | 13 f31c (0) f2d5 (0) f27f (0) f629 (0)\n005 3 ff36 fe21 fe31 | 3 ff36 (0) fe21 (0) fe31 (0)\n============ DEPTH: 6 ==========================================\n006 2 fbf5 fbc8 | 2 fbc8 (0) fbf5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","private_key":"68be1214b78195a55f8a0048f9bec727e50425b7c72b445f3e9b0cba006ce587","name":"node_f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","services":["streamer"],"enable_msg_events":true,"port":46319},"up":true}},{"node":{"info":{"id":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","name":"node_5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","enode":"enode://f0602e87ed48ff8c9e5b32418ddf3f1b1342911057a98f5c3cb1cb1c8053887b84f07d0aef26934db2ee88c543ffa8c5e60dbccbc693e1162466a2a84304ac34@127.0.0.1:0","enr":"0xf88fb8400ca2ddfc019ef6efe386c9432134ddcf621cc7d5d6d6c2a4df4b691968397ad32e8730138bac99bdfa701024d5590bb583ac57b4a314223baf49ba604b6daa7a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0602e87ed48ff8c9e5b32418ddf3f1b1342911057a98f5c3cb1cb1c8053887b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Xvs7/BmfVAj3m9a9UXG0vzMsaKjkkkLrT2pYm5Y1ZcY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5efb3b\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 aeb4 f5b2 f925 | 110 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n001 6 3630 39d1 3b78 154b | 76 3237 (0) 3373 (0) 33b5 (0) 30be (0)\n002 4 7dd3 7125 6e68 605a | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 5 4d10 4990 49ea 41d9 | 23 4109 (0) 41d9 (0) 4447 (0) 44a1 (0)\n004 4 51db 53fe 53a8 534b | 8 574f (0) 512e (0) 51db (0) 524d (0)\n005 2 58ed 5823 | 3 5b63 (0) 58ed (0) 5823 (0)\n============ DEPTH: 6 ==========================================\n006 2 5db0 5cd2 | 2 5db0 (0) 5cd2 (0)\n007 1 5f00 | 1 5f00 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","private_key":"dc9b24b93ea85bbf21ab6cc53fa814b1e43b7c727edeef705de678992d971ee6","name":"node_5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","services":["streamer"],"enable_msg_events":true,"port":40995},"up":true}},{"node":{"info":{"id":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","name":"node_00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","enode":"enode://7ca882c01f3ef0c979b3991b30d470a4e12d4daddb20ff5209e75e679be8d75e9d6b98c06a763dc9d6340daa2d98079a8ed5348c7b332d26dbe72cf162227e37@127.0.0.1:0","enr":"0xf88fb8400b62eaff12a9192a15e894c5eab3f37b7ed634294a51288c0c6a83ecf0fd4a6b542b6cb20fb7bd8435de98cc27008a3cf625eadd4938433921102803ed3c11cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037ca882c01f3ef0c979b3991b30d470a4e12d4daddb20ff5209e75e679be8d75e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AMZIioQuznqLDa8GTkBd4DpCV9MIhA6lK/1I0j9U2JU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 00c648\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 cc20 f925 f5b2 a46d | 110 df1e (0) db6a (0) da67 (0) daec (0)\n001 4 49ea 4990 5cd2 5efb | 70 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n002 4 3b78 39d1 33b5 2c79 | 32 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n003 7 1c9c 179f 14df 154b | 22 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n004 7 0b72 0af9 0a00 0c64 | 11 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n005 4 0438 045b 07a8 0661 | 6 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n============ DEPTH: 6 ==========================================\n006 3 02d8 03cc 0328 | 3 02d8 (0) 03cc (0) 0328 (0)\n007 0 | 0\n008 1 0067 | 1 0067 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","private_key":"264248088585a6d226623f7f606b7d9b2a5a80474bb9fbe6c2194848b7dc0586","name":"node_00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","services":["streamer"],"enable_msg_events":true,"port":46209},"up":true}},{"node":{"info":{"id":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","name":"node_bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","enode":"enode://e9d6493fb95f0cead7320163b4766f3eeb98040a441ca69854ad152ecc40f844b80748c9a40686ed50aeb691c54ebc32ed19e793294170171e644ac9cc903756@127.0.0.1:0","enr":"0xf88fb84006b4143a56faaab9a4674c3bf9dccdab55411262af7d7178d0d90275ac6bf97b13323f2de3c85480f392843ae1172ab763680293f68350afae51376861d75f460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e9d6493fb95f0cead7320163b4766f3eeb98040a441ca69854ad152ecc40f844","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vMZyTlT3YTYfhRR+sQKo0aGjiBCpQM52seNh3crayqM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bcc672\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5cd2 103b 00c6 | 146 77d2 (0) 775e (0) 7290 (0) 738c (0)\n001 3 d887 f5b2 f925 | 63 df1e (0) db6a (0) da67 (0) daec (0)\n002 5 90a8 9076 9852 8f21 | 20 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n003 4 a34e a46d ae2b aeb4 | 10 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n004 3 b7ca b2a5 b02b | 8 b5b2 (0) b502 (0) b626 (0) b65e (0)\n============ DEPTH: 5 ==========================================\n005 8 baf2 badd ba88 bb90 | 8 baf2 (0) badd (0) ba88 (0) bb90 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","private_key":"abbd7b59425714f0316c2a0b0d09c70ac6a18bf91c5c6f8bacc927aa55e2e249","name":"node_bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","services":["streamer"],"enable_msg_events":true,"port":36589},"up":true}},{"node":{"info":{"id":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","name":"node_103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","enode":"enode://ab61a89b8c96d76938394e59d68d35411dd069a2913459c3b93753e155054808072826f8c3486e851277442229448a9a5aea76f1e5677d9d63bd233f662349f8@127.0.0.1:0","enr":"0xf88fb840ef3ce505f3f25f1acbd8cb9d485be9cf25dcd915112ff3c33982c65dce7331c020dc2aaedc07c497e5b48c7aafb32221e5879fd926cb39cce242f3fc1e70182c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ab61a89b8c96d76938394e59d68d35411dd069a2913459c3b93753e155054808","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EDsjJVK5QJAjIZXciPhII3AfNa5Ta1r23TP6ZVozy64=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 103b23\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 eb98 e883 e854 e775 | 110 e027 (0) e5ad (0) e5d7 (0) e547 (0)\n001 5 605a 49ea 4e5a 53fe | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 3 3b78 39d1 2c79 | 32 3f94 (0) 3ec5 (0) 3efc (0) 3e8e (0)\n003 2 0af9 00c6 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n004 3 19fa 1e2a 1c9c | 10 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n005 7 1704 17db 179f 1672 | 9 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 6 ==========================================\n006 1 13d6 | 1 13d6 (0)\n007 1 11d4 | 1 11d4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","private_key":"416b236190cb9412038f2b53f7d6d2b804e6e2e47266fed6212b9950c7aaaa19","name":"node_103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","services":["streamer"],"enable_msg_events":true,"port":35829},"up":true}},{"node":{"info":{"id":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","name":"node_154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","enode":"enode://175ecd2838e0febb3825043e19c3da58fc7b0dbc13785420d0f6a9c558cf1f58bdebd47f93bac8cf9eb1b7fd91b13f8888481aa8a08adcb1ccad83d11306e4e1@127.0.0.1:0","enr":"0xf88fb840818f538de2e08485786c679ee895bb4922fb60fe5137ed730e676b8d4e033cbb5bf437ded58aeb37c30db94ed1d80e76fb52d999f936280a4107b502891b09710183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103175ecd2838e0febb3825043e19c3da58fc7b0dbc13785420d0f6a9c558cf1f58","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FUvpJV6a69E0qRQHD15vPUu6B52cpzi3QkTbFOG1ht0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 154be9\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fbf5 f925 aeb4 a46d | 110 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n001 5 7dd3 605a 5cd2 5efb | 70 775e (0) 77d2 (0) 7290 (0) 738c (0)\n002 2 33b5 2c79 | 32 3f94 (0) 3ec5 (0) 3efc (0) 3e8e (0)\n003 3 0ff2 0fc5 00c6 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n004 6 18f6 19fa 1f67 1e2a | 10 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n005 3 13d6 11d4 103b | 3 13d6 (0) 11d4 (0) 103b (0)\n006 5 1704 17db 179f 1672 | 5 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 7 ==========================================\n007 3 14df 1400 1436 | 3 14df (0) 1400 (0) 1436 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","private_key":"324821a542a5b9cbe5f5cde557280f1fa601cbb5592c2b60a578fd741be35770","name":"node_154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","services":["streamer"],"enable_msg_events":true,"port":41653},"up":true}}],"conns":[{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_32.json b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_32.json index 55bd2f22..527474d0 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_32.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_32.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","private_key":"b571efd8e722db149f98412648275074a828e5137b46722413039489eb617b36","name":"node_d2a392e9e7383b895587a7d6eea4a157de20caa9e2c62b4da5a8ff3186d129fee1330ddf3d180b1f59e1aa83686cd163222e38c84a84a0f60139968d6a56cbca","services":["streamer"],"enable_msg_events":true,"port":61468},"up":true}},{"node":{"config":{"id":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","private_key":"fbd2e7bb8b511ed0878fc14a5923105866ab2c3bdf5ee2c52c1a2bc7c00a185e","name":"node_6c0b3b7c1c08bb558d92f0172fb8bfabe52a4bf8348b2f82e50c6d492a595dd0677b4559d7d2cd5a6e51ecdaf9a0f898f154730b87a8d9b265c6a54f9f6802a7","services":["streamer"],"enable_msg_events":true,"port":61469},"up":true}},{"node":{"config":{"id":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","private_key":"60a362da222a74d3d81ed679549417d55a92c79b8e0aab1bf05eb2d01f82c0b2","name":"node_dc63b83b488b7b505d5b2a60680b7dc87b1c5b61509e8030ebc67512ba72c0f616c1594946878dfb29e79f351d7134306778a74d5f5b7d5e08dbdb6dd6ade359","services":["streamer"],"enable_msg_events":true,"port":61470},"up":true}},{"node":{"config":{"id":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","private_key":"00625fb0f90ed61656987faecdd0690f0a97c88e33f6e339fa3a8f4bfc1e640f","name":"node_eaa3ad48682b08d9c91907a79e82938c1b30108745b276788c830dfcb0c0e752134369d751230e95fb7ab9777c38dcd105ad123ec5cc86ef6dbdd11fe31aea93","services":["streamer"],"enable_msg_events":true,"port":61471},"up":true}},{"node":{"config":{"id":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","private_key":"fbb38d0ed3ef4726052fdec97ddd7eb3a3feb3d2fd5ea6cffe8ff97b621958ce","name":"node_331084cce2884ad912d5a20467c68fc261a02d6df0b60ff5b1427edc0885eab66a4f0f7e7fc9c676e994842f8126a3b34dbde91243f26bed6a0ba14babed56cc","services":["streamer"],"enable_msg_events":true,"port":61472},"up":true}},{"node":{"config":{"id":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","private_key":"b5c12698375aa5215df48003ed13c94e00e6bee1a0b05277237d40f0fcfc625e","name":"node_e00f9a5611008d54bbbfe6a1cf402e011c92f540b47a82b7795508d1b857eee4a522e26c8351ddf6e303d353ee35afecbf9f54d7aae36e6736174473ac4caf73","services":["streamer"],"enable_msg_events":true,"port":61473},"up":true}},{"node":{"config":{"id":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","private_key":"90e044c682c33ed90f5f5cac9b8181ee978d2cc9d3d3f545140858d324f1d7e1","name":"node_e4b7b3bbeda388842ecb3688c041fe58bbd7e4566818a58b679e96215553dbf8569032a3ae941b3f8bb3e75886852d245bda5abf0c3cf70f532c38235e1a2175","services":["streamer"],"enable_msg_events":true,"port":61474},"up":true}},{"node":{"config":{"id":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","private_key":"2371e6ff2ecc4144ee61efa958488eed6c1f739e81f27bf775db1e9b66e89054","name":"node_0679dbbb51fa0283bcba387daa2180955d402a0ed42155095fcaffb96dbfd6b4b1bb0ed2ccf11cd990dfed4a3b320ee3f64286116a7b617a35989a448c367119","services":["streamer"],"enable_msg_events":true,"port":61475},"up":true}},{"node":{"config":{"id":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","private_key":"87a3816c95159c72a7ad1b466ae9a095f12c7db210fcddd8dbaaa697220f88bb","name":"node_a197cd9e7e2d19287745f486582b7242c991f36183e8b2bf4983d7a9b9026e9884e3295183f376cd796b814fdf352b1c8c5c609a0e5f5d5155ab925d4b6fdeb9","services":["streamer"],"enable_msg_events":true,"port":61476},"up":true}},{"node":{"config":{"id":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","private_key":"6729988ebc04b9398883c068277630ff0de16f16e3f67114380acfdb0d1b530b","name":"node_eb11498b8cebc767d535481938c664359c6c84674da4d8fac729df64e288248bb020477ad4422cf1b7cea844db5ee12bb5cea82ac6e89a338d8ca1073e061f4c","services":["streamer"],"enable_msg_events":true,"port":61477},"up":true}},{"node":{"config":{"id":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","private_key":"208068d7a920e42db04340bf473f822d4d663f5139d664c4375294dd61b1dff3","name":"node_d3b5df108f35a82e569016a06fefadb52797dafb505de1981f6678e2156574893a169b0adcc595377267dec0b7d620b5b50c7e7696c39eecee2c3e5f7bf71d18","services":["streamer"],"enable_msg_events":true,"port":61478},"up":true}},{"node":{"config":{"id":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","private_key":"b3a7fa29c4cbf15e8fbbf289ab9876b438bc80092284efedde8e8d41ac76ad78","name":"node_1be1903b1104bfae07438fb888993cb3e812fc38c8f26af2e68bff9f1758e9a69b29be3636ee24060c09ce900bad2004681e1083792b2a6e532bbfc07a3a0459","services":["streamer"],"enable_msg_events":true,"port":61479},"up":true}},{"node":{"config":{"id":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","private_key":"91b7188a3178bda6cd2991a615801d744f4963a3de963adb8afb3f12d02cbc0d","name":"node_26a6b8d30e0a8954bd9a0424b817ff79fec2e0521c1313c8262be9a3b9a0d1ee7f109be78d65ca9eb811a1634a813f4ba609887fd3c0085628b2a8ebd3426031","services":["streamer"],"enable_msg_events":true,"port":61480},"up":true}},{"node":{"config":{"id":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","private_key":"235b967cd72cdb90b423f2b5604e9157f660b253cd2df62369f204f45c3c4d7e","name":"node_255c353a7585ab1bab41bcca409383dcdff5837bdcd7cebece1b6896fc06d0f65346ba618dc057c77734439612cb8cc3fd8aa068eb7569f0ad9e9e172daea678","services":["streamer"],"enable_msg_events":true,"port":61481},"up":true}},{"node":{"config":{"id":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","private_key":"f97bf73ba53833e4f4c44023e87cef8ef7aeae380553e4a5a4f3215748646a27","name":"node_c88ceea7f4d5148de8e2d71ffefc5c336cc62d322eb4371e457cbb97573b6323d200ff7678f94ef481c7b9daca3a9a7bab1e658d51fa279d433e19305df57814","services":["streamer"],"enable_msg_events":true,"port":61482},"up":true}},{"node":{"config":{"id":"35b6e31caedb996b4a87a6b12b9a29eaacb4aba4c334543ba84b26d6bcbd65f0","private_key":"c4c2ee3b5792dc5d86b51c4e13c813df452094ff2f6296403d801adb1f75a500","name":"node_4299205173b81c2822767a53cb4728fd5c0e1602d5976ee5db63b8118e489e4645ccdad399d9367e9b87b0a1f39e7988db86af687fe8cfff35d618b19d64b1a9","services":["streamer"],"enable_msg_events":true,"port":61483},"up":true}},{"node":{"config":{"id":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","private_key":"b39dd34865d2f02c1d4c5ef2ca635ef5be43c4b2318b133d281b02dacd8f5420","name":"node_5ed2923d11037da9799d933ea62cd23ce1aacec66a83a6d3a7e420ea0c66ec00af37977a78374df12dc0facb426d0c39cf306bea15abaf40f9072eacc4cf40fe","services":["streamer"],"enable_msg_events":true,"port":61484},"up":true}},{"node":{"config":{"id":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","private_key":"a93bc07ea3d259a03c75a6777e9401f062a8064f6837fda8a1abd518774a75ac","name":"node_66ce6e2c75f429c4bc7de6f1c785258686cfd66867336a1030830bbcc78bf642f4d1920ab5fc68953b70b7aca02ec518515d48d20397ed207ccbeb88c36e7057","services":["streamer"],"enable_msg_events":true,"port":61485},"up":true}},{"node":{"config":{"id":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","private_key":"787adc2aab8500ce6ca1768040b4c81511e7982f525c0280830f8c32486a6fa0","name":"node_cf7d1a8ec1c3e68e862ef18947098ccbf6238fa7f85ee0018b7ac63b5387d6a9dbf194e3aad7edd1fda63ea63f2f5b8692ff885084adfd1f7b6613593960afc4","services":["streamer"],"enable_msg_events":true,"port":61486},"up":true}},{"node":{"config":{"id":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","private_key":"6a830e44eac33e88e29c9119fef789abd89503a44ae8b8dd64c0a26046df4bf7","name":"node_a54b9c0cbc07e65b216f78bc0f56cd7003896641f1aa361fdc11e0bc208ee6bc876a455e89dee8abf67c259c7b6a82e7ac0d6d06cc304ee05fbc26783c09863a","services":["streamer"],"enable_msg_events":true,"port":61487},"up":true}},{"node":{"config":{"id":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","private_key":"71341041894a268f86cf62e8e80605911c19f38266bc49358c54f9955b4bd984","name":"node_82bd5207dec292f911ff7dbcd242bf8962ab256057b1173dba2d71cd8cc77d41f38bf8d9a4eed83edeeb0e6f5bfabe8c7cae9490cc17dca1f454b9ad1b76224b","services":["streamer"],"enable_msg_events":true,"port":61488},"up":true}},{"node":{"config":{"id":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","private_key":"1a7bf17688ee55a634ddbf081213180f5a6e171a4b04679f50a949e88287591f","name":"node_61cbdddf6163152f5f8bbe3c710eeb9afb22dbec78d8f7eb3fd45ba44493b9387765527f059a10e694842786959c501303b1e62d3454c84870c14e0f36a58b0a","services":["streamer"],"enable_msg_events":true,"port":61489},"up":true}},{"node":{"config":{"id":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","private_key":"87d1292398bace7bdd961dc2e1f028d405eeafebf90ef8d8f4b411fdfd74d767","name":"node_74d5d4ec7fdc749d9148b1a338b643e0a06abe03720b1d20b505da1ff1585b09d2cf7053293544fae1409cf26a27144870125787a473a73a1c4ca98509dc67ca","services":["streamer"],"enable_msg_events":true,"port":61490},"up":true}},{"node":{"config":{"id":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","private_key":"1d65bea3808741aeabc5293fcb863c594c7ec07c955b3f23e28d2ef4b0b6e578","name":"node_12934e06d8821c5e149d944ee7a831428dc6c9eee8705f3b21046fdadc2864a9ffe2bdad60a4ba5a34d7a79c22631d52b62d511e81971b6b98896acae9427e94","services":["streamer"],"enable_msg_events":true,"port":61491},"up":true}},{"node":{"config":{"id":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","private_key":"f067299a421cd124f8652427793dc41c8a5e6bf1dc2c4de59ef396ca08e80256","name":"node_e0e0e90fa669023a1a9c564727cc657ce564c23e05b1c2b61f6bfbd5eb03feb75d34b029886e3426e1bbe4a49398794dfefa0557b7db57c15700c69c0e038029","services":["streamer"],"enable_msg_events":true,"port":61492},"up":true}},{"node":{"config":{"id":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","private_key":"5f76a5630d4f1979d6d03dfb0c8836de7852e4ad14536f4b999e565b599027b8","name":"node_1149e4bcd71c75b14ba7492587fa77e4a4de14e5c580a165ad8835258d1afcb15e65d02257ad8884b0e47be061d3129d8e3af90cbe4a1a96f828a1f84e0d72c6","services":["streamer"],"enable_msg_events":true,"port":61493},"up":true}},{"node":{"config":{"id":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","private_key":"0e4febbd0bb937f5992d0e640d5b599a0dfc3b40740d7a0a5fd16423dfcc87fb","name":"node_695e5706cece9d923c19a147283b772dd1ffa79e8d08506d2ed897d89545ffbdac1a130bd7ceeb82a2a57f2b4a613aa6e7264911b909fb9bff27cd435b802687","services":["streamer"],"enable_msg_events":true,"port":61494},"up":true}},{"node":{"config":{"id":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","private_key":"54d714717b902eb733a693d473a4b4b243318a9fd68d1b8abe98eabcbaa8c015","name":"node_e28c769630f19e79966bc354bb38313522778e4f06cd0872db8bd3afd7651882eba7b0403d82701cd063cbaee4ba0ba4a97c0c488fb44e8c8b72368d6881fdcf","services":["streamer"],"enable_msg_events":true,"port":61495},"up":true}},{"node":{"config":{"id":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","private_key":"43e07e3593646f9ec6c3b630daa34ba80dc37bc0f5c57e3f3097f3503de413dc","name":"node_2b1d1ec3ee35fa63571f46a2781d5fb14379319da2d67e482c24b27bacc2b792cd61a2c1138b8ba27673b1c08588064fdf9c73c80f0278e4f0ba133d78127337","services":["streamer"],"enable_msg_events":true,"port":61496},"up":true}},{"node":{"config":{"id":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","private_key":"ef8ebfc1df0b19885db4b08df697c11a86c2442bce48d5f6f807b7e8dec70e04","name":"node_b5e3b3cc7ac15224ff10cf8974ceaf7ad2ebb18ab9505bbb342c42e6ca65fe3541c14e1ee10ac3a0e7a0d87c29e25114e0c0d957d5dbbadf6136805be3046b4c","services":["streamer"],"enable_msg_events":true,"port":61497},"up":true}},{"node":{"config":{"id":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","private_key":"1cb586254c20e9a6f4cc428f878dcfbcc8257f00c21efa88519de7a425cb5e4f","name":"node_fb6e36b9de5eef05780efcf16113fc9098a699ac525bd970dc5b6a92f596da6ffca044e434b97cd712a4035c38dd3ab08488042519f6269bc5057853b643bbcc","services":["streamer"],"enable_msg_events":true,"port":61498},"up":true}},{"node":{"config":{"id":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","private_key":"2621e61b3b896a37c2b4ee05a264bb685f4a70c3caf8a162eee28dd6e64fa2fd","name":"node_aca2af376ef1c983514f75cd717c0852e9d4321e705517196fab4fafe109c1f3581866e1865d41977f8c23a31ec7fa218c11db0c87eb4bb96390025a96386f9a","services":["streamer"],"enable_msg_events":true,"port":61499},"up":true}}],"conns":[{"one":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","other":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","up":true},{"one":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","other":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","up":true},{"one":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","other":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","up":true},{"one":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","other":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","up":true},{"one":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","other":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","up":true},{"one":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","other":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","up":true},{"one":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","other":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","up":true},{"one":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","other":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","up":true},{"one":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","other":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","up":true},{"one":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","other":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","up":true},{"one":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","other":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","up":true},{"one":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","other":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","up":true},{"one":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","other":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","up":true},{"one":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","other":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","up":true},{"one":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","other":"35b6e31caedb996b4a87a6b12b9a29eaacb4aba4c334543ba84b26d6bcbd65f0","up":true},{"one":"35b6e31caedb996b4a87a6b12b9a29eaacb4aba4c334543ba84b26d6bcbd65f0","other":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","up":true},{"one":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","other":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","up":true},{"one":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","other":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","up":true},{"one":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","other":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","up":true},{"one":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","other":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","up":true},{"one":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","other":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","up":true},{"one":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","other":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","up":true},{"one":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","other":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","up":true},{"one":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","other":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","up":true},{"one":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","other":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","up":true},{"one":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","other":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","up":true},{"one":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","other":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","up":true},{"one":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","other":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","up":true},{"one":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","other":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","up":true},{"one":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","other":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","up":true},{"one":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","other":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","up":true},{"one":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","other":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","up":true},{"one":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","other":"35b6e31caedb996b4a87a6b12b9a29eaacb4aba4c334543ba84b26d6bcbd65f0","up":true},{"one":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","other":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","up":true},{"one":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","other":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","up":true},{"one":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","other":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","up":true},{"one":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","other":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","up":true},{"one":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","other":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","up":true},{"one":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","other":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","up":true},{"one":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","other":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","up":true},{"one":"35b6e31caedb996b4a87a6b12b9a29eaacb4aba4c334543ba84b26d6bcbd65f0","other":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","up":true},{"one":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","other":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","up":true},{"one":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","other":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","up":true},{"one":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","other":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","up":true},{"one":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","other":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","up":true},{"one":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","other":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","up":true},{"one":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","other":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","up":true},{"one":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","other":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","up":true},{"one":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","other":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","up":true},{"one":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","other":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","up":true},{"one":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","other":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","up":true},{"one":"35b6e31caedb996b4a87a6b12b9a29eaacb4aba4c334543ba84b26d6bcbd65f0","other":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","up":true},{"one":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","other":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","up":true},{"one":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","other":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","up":true},{"one":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","other":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","up":true},{"one":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","other":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","up":true},{"one":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","other":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","up":true},{"one":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","other":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","up":true},{"one":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","other":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","up":true},{"one":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","other":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","up":true},{"one":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","other":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","up":true},{"one":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","other":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","up":true},{"one":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","other":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","up":true},{"one":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","other":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","up":true},{"one":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","other":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","up":true},{"one":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","other":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","up":true},{"one":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","other":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","up":true},{"one":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","other":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","up":true},{"one":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","other":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","up":true},{"one":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","other":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","up":true},{"one":"231cf4ad6466edcff849ba5f44069f51267dfda535d31a4d7241f5d83c1a521a","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","other":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","up":true},{"one":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","other":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","up":true},{"one":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","other":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","up":true},{"one":"24a154986fbc308c5f2e3fba99f3263743b669ad88ffdd2252cce5fe0c02c279","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","other":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","up":true},{"one":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","other":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","up":true},{"one":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","other":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","up":true},{"one":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"59a3ef9ba5d0a0137eab9442657cbaaae5bfcd6e77f9678b1b2616d44e442caf","other":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","up":true},{"one":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","other":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","up":true},{"one":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","other":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","up":true},{"one":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","other":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","up":true},{"one":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","other":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","up":true},{"one":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","other":"8e5f934e6d0f0bf34425c3db2db405d238f6512cf132926ebd0b596fc721fbe4","up":true},{"one":"d668b8cc215cdbc92be719a33623494090ae0fb1a80f53bde0315b1a8fb3d139","other":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","up":true},{"one":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","other":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","up":true},{"one":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","other":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","up":true},{"one":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","other":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","up":true},{"one":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","other":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","up":true},{"one":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","other":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","up":true},{"one":"7514001adcdeb5c9a0e88fb54082e96a5c162430dfc56b6da858607880366ff5","other":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","up":true},{"one":"484875287058e78ed92396e00f34e75f907a1f42d5597b9e8c30afcbe50c1810","other":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","up":true},{"one":"5ec7e6ffb44f67eccc35adbf0923755cd5b6a8abcdd371db9b1be555780ca5a1","other":"391e49ed641480c2c40febdb23263264c83b2b6cdf3400f6526f7939c0245c17","up":true},{"one":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","other":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","up":true},{"one":"8f7dc84801ba8da80761fe1e0d2fe72a48e45fa753cc8bbe930bf9277a219432","other":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","up":true},{"one":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","other":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","up":true},{"one":"914839ec95b100922429a3616522daffc51c1a4c39b297d1d8cec591567b4ccc","other":"8d0984a32d4b044065588b4bbe48531a30881bb869399c81b90b349e57f07ffc","up":true},{"one":"d5355c5eced7ca0b210934d2e4f11ae09bec1c62246548ea092dc29e9987171f","other":"de95f5a58a8880b9e98f71c687afa472882244c012439719b6b066930355c993","up":true},{"one":"e7ac9c3a8ca80703b3499a376d57e2a9523b3bd3c5cf35b7a450f0af44680686","other":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","up":true},{"one":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","other":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","up":true},{"one":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","other":"7b889ec7b0674ca8f6508a35d920149f1826d410b796e52bfa72306b1fafbae4","up":true},{"one":"d514861e573828617604db5b88f407b152409308657454f99fc2820b44a45088","other":"dab5098cf929579a87e26d30f9a8b001ad3158afe0f6231c50e58f33c6d62207","up":true},{"one":"930de56c1ea44a1b39f2f99f6780ce284042d59238adb1047167c6329be4a291","other":"bfb02423df06888f87e8fbde52c2373020896f2a3dea69ecd2efa89c1aa298ac","up":true},{"one":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","other":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","up":true},{"one":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","other":"a1b5ab3013c0031a169e72847a4509e83b994086fdd82b07fb6ca0d7cfe9d537","up":true},{"one":"9756cdaac61a9ec4d346e352862ddbdb627f56b5bab132a31348359f62652824","other":"a82935d4ce212895fad97829cc8e04bd1ae1c53323af4e6d8e2c673b7dfaabb9","up":true},{"one":"c71983aed3779037757e433a4f916be40f5199e89861a3998ccdd7e5e76f69b4","other":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","up":true},{"one":"a4e6f50a17347a8475d6b704484b06869d9625993761acbde6a0ae5ac0b40762","other":"b412abec3dd5145d9236498056db35e50e0e90697016c757724c15a2e9b187af","up":true},{"one":"d81271c644a75f0bf9d785319aded8b7a0e9323f85e81e94ef951e8c66251e75","other":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","up":true},{"one":"deeef9d38d9afb206ee7e6447e80befaf387c2af476a7e0c60c55c73dd36450d","other":"d19a0c646122e8d0b8148da1f64b3cb781fe974687a071e5a8522e9a22bc6646","up":true},{"one":"a0ca706ab2ba950ff9bb92123c66c95132a63b9c93975b9b6e0d485937dd8f65","other":"b17b568780b3a029d4292a742890d41be6a71031b15e6276792a77a9746f0699","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","name":"node_427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","enode":"enode://e94f375f0c1c7974305cf5d1fecd64491ad73661ce194a272f674e89051c5d5b951abfebae5a5fa9dbc8a26adeec802ea6188fdf67b7577fabf7355e92cc5d27@127.0.0.1:0","enr":"0xf88fb840ec3deb0830cbb5f0f9a78c5de4a7ca5fdecd378778a9255dad6ed45bd13d5ee61278d01af7de31abfce7aeb9e6d5421c0f614db1be5e98fc2fc82806a56fdd590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e94f375f0c1c7974305cf5d1fecd64491ad73661ce194a272f674e89051c5d5b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Qn9L39OFeWivXaNu7qBBk46ncbxsXpDujTWFz1efE7c=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 427f4b\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e4f7 d756 | 15 e4f7 (0) eed4 (0) f4b8 (0) fb64 (0)\n001 2 2529 2f17 | 5 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n002 2 76cb 6ef5 | 8 76cb (0) 74b7 (0) 729a (0) 6646 (0)\n003 1 577b | 1 577b (0)\n============ DEPTH: 4 ==========================================\n004 1 4c5f | 1 4c5f (0)\n005 1 4601 | 1 4601 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","private_key":"fcb9f591c3d058107af08804ccd4dfda279051673a0b48360a625d6df6a02de9","name":"node_427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","services":["streamer"],"enable_msg_events":true,"port":45919},"up":true}},{"node":{"info":{"id":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","name":"node_6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","enode":"enode://bad4b2d1652369de53e8b0f8f6c150f6bc3b38fb2f0d308b9f04d67964fa9440fc07581d83ba0e665be33aeadaf738bd53f4bbecfe55e4fc31c5af587ef74c8e@127.0.0.1:0","enr":"0xf88fb840f17e139df282d76ab7238fe8faa15fb41d782a0664a4732df0f7ade8fbb865db350f23fdf65ac06bff32805a321d85092a22e6b315fc0400a4ef16b16f215f200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bad4b2d1652369de53e8b0f8f6c150f6bc3b38fb2f0d308b9f04d67964fa9440","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bvXeXByOVbyJlIvxCnoq0RsHFw87XwSeQKheJEEk7uQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ef5de\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eed4 e4f7 | 15 e4f7 (0) eed4 (0) f4b8 (0) fb64 (0)\n001 2 2643 11bd | 5 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n002 2 577b 427f | 4 577b (0) 4c5f (0) 4601 (0) 427f (0)\n003 2 729a 76cb | 3 76cb (0) 74b7 (0) 729a (0)\n============ DEPTH: 4 ==========================================\n004 4 6013 6304 62ac 6646 | 4 6646 (0) 6013 (0) 62ac (0) 6304 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","private_key":"9f0d5a60a7b0980371a7eef29848b7d3c4273955e10456b6bdc71881ee7154eb","name":"node_6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","services":["streamer"],"enable_msg_events":true,"port":37449},"up":true}},{"node":{"info":{"id":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","name":"node_11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","enode":"enode://4b00f923b2c2e9c70b840f0c0e90d0941bb0875cca7fa12ec8f43c5eeb563448b209ae04c2a8e7e6e9cf2a9e9ab9ffb3c6d463db1351d8a990be553742f34fe7@127.0.0.1:0","enr":"0xf88fb8400c58fcc017555e27e75db6ed84521f731670fb55dd5e1f57543d23daf810a39a4ea3d74ca6680f4fb340829a17fd81d21c970e3feb3f9a04b8d1c29f974c75930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034b00f923b2c2e9c70b840f0c0e90d0941bb0875cca7fa12ec8f43c5eeb563448","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Eb2BD3ukH0SBbzOhnZxwPSbyzK6ijEr4JfUoiAcK2Nc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 11bd81\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 cbd4 9e27 | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 6 577b 729a 76cb 6304 | 12 577b (0) 4c5f (0) 4601 (0) 427f (0)\n============ DEPTH: 2 ==========================================\n002 3 2529 2643 2f17 | 3 2f17 (0) 2529 (0) 2643 (0)\n003 1 08ff | 1 08ff (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","private_key":"ff99d767a883944922bbba96c25e19cb78641c0e9f32b2de37db70a29151473f","name":"node_11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","services":["streamer"],"enable_msg_events":true,"port":43277},"up":true}},{"node":{"info":{"id":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","name":"node_9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","enode":"enode://1140e5da7f3da364ca5e55f8598cd121887f4b1c780b8900f090cd35ef5b52873dad20397e7d2d1ba3da0c1c16df19be8d373165c5fe8af1fcab7c3daaa501aa@127.0.0.1:0","enr":"0xf88fb8400194560390e74c85e87bea47d73cf330581219f8acc6a7c4e5941f10b3d2970326116cf7258109729e7226bcc66d4624264aa4d717825090b70494d0664452810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021140e5da7f3da364ca5e55f8598cd121887f4b1c780b8900f090cd35ef5b5287","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nids22IiFQifDyAlKmq6IPV1Id+U1AHvoT9gS2JTTIA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9e276c\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 11bd 4c5f | 17 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 a11b bf27 | 4 bf27 (0) a11b (0) aa7e (0) ad46 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 94a2 | 1 94a2 (0)\n005 1 9934 | 1 9934 (0)\n006 1 9c93 | 1 9c93 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","private_key":"5509584c52b0fc75d12256db74098c2d08e2a03d515c415f6760c94ee65396a7","name":"node_9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","services":["streamer"],"enable_msg_events":true,"port":42197},"up":true}},{"node":{"info":{"id":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","name":"node_4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","enode":"enode://b4b928549c694b7d425330835de106ba3900fed27db077d7ef47b9de24d3f171dce1edfb7bc05dbb087d1935b11690fdefeeb8d52cb86c400241c739408077b0@127.0.0.1:0","enr":"0xf88fb8404932a241c860d9e3781f3d3e3dc57c0d0e9aa03ee53aa2e9cf343ca198f189e26f5912ca878cccc0b0e91669105af390f60cd802aa9c4d858eec97139ead6ab40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b4b928549c694b7d425330835de106ba3900fed27db077d7ef47b9de24d3f171","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TF+rt6F8Oj9YnH0uyjwN1aa4IXqrxUMjurdbavODrGw=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c5fab\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ad46 9934 9c93 9e27 | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 2 2529 2f17 | 5 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n002 7 6304 62ac 6013 6646 | 8 729a (0) 76cb (0) 74b7 (0) 6646 (0)\n003 1 577b | 1 577b (0)\n============ DEPTH: 4 ==========================================\n004 2 4601 427f | 2 427f (0) 4601 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","private_key":"c8a57fa979d839a728714a0cc091d9c35560d850ce2faa0431b758abd3363c79","name":"node_4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","services":["streamer"],"enable_msg_events":true,"port":37685},"up":true}},{"node":{"info":{"id":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","name":"node_ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","enode":"enode://a1662488c10698fca196fe9453c596e65bcc779371b4d765754a24a188cd6b680c1c8e07e21686f6caf4241f9e661ceddbbf57663a59fd739d4d01d845ca26f5@127.0.0.1:0","enr":"0xf88fb840e0f39d0e5ddeae60c3fd876087f642a075cea50df66869f0ab54b49f320750ed3f59eb3a2f096cbf67fbc0eb018b819416073d12c1d4c8d14b02697b305448fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a1662488c10698fca196fe9453c596e65bcc779371b4d765754a24a188cd6b68","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rUZDWDqggrO+984buNz1X+LjIbiVQADPrGvHLEnoX1A=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ad4643\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2643 4c5f | 17 11bd (0) 08ff (0) 2f17 (0) 2529 (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 9c93 9934 | 4 9934 (0) 9c93 (0) 9e27 (0) 94a2 (0)\n003 1 bf27 | 1 bf27 (0)\n============ DEPTH: 4 ==========================================\n004 1 a11b | 1 a11b (0)\n005 1 aa7e | 1 aa7e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","private_key":"4bfc56ea8d973de3d6f451825ca9fcfcb36e1d6624c0f1d1641bee8e6683bc59","name":"node_ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","services":["streamer"],"enable_msg_events":true,"port":45407},"up":true}},{"node":{"info":{"id":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","name":"node_2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","enode":"enode://40b0f23d8cdc7ece33f3ebe012b2ad3c7b5d78c141883364116214d980d525cbd06bfce04c2312415cdbf028886a45ce1ff0e8b997c2a8b692415d5087f34641@127.0.0.1:0","enr":"0xf88fb8402fa9bc618382dbb09eb218dc9c159ceaf6b7f5daf74d44a16a47906fc9beaa9e2bdb5b7f188450d97625ec4536570e127e386356252f969bfe411c70d4c6d6390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10340b0f23d8cdc7ece33f3ebe012b2ad3c7b5d78c141883364116214d980d525cb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JkMINELunmlRf1AI5MpU2/pAcmveIiFrU7+QOJWqCuA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 264308\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f9ca ad46 94a2 | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 4 6013 6646 6ef5 74b7 | 12 6ef5 (0) 6646 (0) 62ac (0) 6304 (0)\n002 2 08ff 11bd | 2 11bd (0) 08ff (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 2f17 | 1 2f17 (0)\n005 0 | 0\n006 1 2529 | 1 2529 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","private_key":"de0328d5a7218ee32122b35212270355692c913773c59472d65894e53fac078c","name":"node_2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","services":["streamer"],"enable_msg_events":true,"port":37731},"up":true}},{"node":{"info":{"id":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","name":"node_94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","enode":"enode://943fb91f74aa53ab508162a6a27dec3da1265ead68613c62d2a8f6b75ca0862b94fb31c62d341adfaf3cba1b76a202633d46fc3b36115454b2fa4eaed4697376@127.0.0.1:0","enr":"0xf88fb8402f7f395a5e543c79b6700821d943be0527fff861c0faa5ad5ba3084922ac6733115483c5bb7d7d238ca7689f756d5814d916c5cefb739e622cfd7842f0392daa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102943fb91f74aa53ab508162a6a27dec3da1265ead68613c62d2a8f6b75ca0862b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lKKvprwS/pV2Xwn1eCjHfMnqRzzQ6eZVyp9G4burriI=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 94a2af\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 62ac 2529 2643 | 17 6ef5 (0) 6646 (0) 62ac (0) 6304 (0)\n001 5 eed4 e4f7 f4b8 fb64 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 a11b bf27 | 4 bf27 (0) a11b (0) aa7e (0) ad46 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 3 9c93 9e27 9934 | 3 9934 (0) 9c93 (0) 9e27 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","private_key":"830a6d825c4e4bd95f3f10d11739fcceb8aa5299d256b9530ee1c7928d4daa83","name":"node_94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","services":["streamer"],"enable_msg_events":true,"port":39189},"up":true}},{"node":{"info":{"id":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","name":"node_f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","enode":"enode://c65f56752b8a6c94d1b6aff48cdcb120cc05451e84e37a9af3284bc09212a1418f67818e62449dc6939cde59f698b48437516d84c29f89cb8ac9078838c53549@127.0.0.1:0","enr":"0xf88fb840dfd8ab1f1fa9679d9c6e818c3b9e3fc25c9ae3d006363c318df0eca480300692324e71c7c66011df3e78f5b8044c0714a7ac208dcddf8a1cb59fad30400d4f8e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c65f56752b8a6c94d1b6aff48cdcb120cc05451e84e37a9af3284bc09212a141","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+crJW0yRvqZw5eZyvGTkAOY94LVcQj7aXxSZzyGOskQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f9cac9\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2643 74b7 | 17 2643 (0) 2529 (0) 2f17 (0) 11bd (0)\n001 2 bf27 94a2 | 8 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n002 2 d756 cbd4 | 2 cbd4 (0) d756 (0)\n003 2 e4f7 eed4 | 2 eed4 (0) e4f7 (0)\n============ DEPTH: 4 ==========================================\n004 1 f4b8 | 1 f4b8 (0)\n005 0 | 0\n006 1 fb64 | 1 fb64 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","private_key":"74feff500b31c6440e380f5bdd141aa2925f0abf00745572b50929d2244efe98","name":"node_f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","services":["streamer"],"enable_msg_events":true,"port":37021},"up":true}},{"node":{"info":{"id":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","name":"node_74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","enode":"enode://68cd12c71355f1284f696a0c62da83c4088e91a867af6368efdd74ce3d7eff265e1589cb822ef12e50c8626eeb8eb774893fc9016f33d8458f268c44bfe7074c@127.0.0.1:0","enr":"0xf88fb840d287a3644573ef6ebbc18a1e6fb2782814e728d6a430103bf57e1dc4ff67c6c24f44514803e4eb41bce24de090ffbe118ebebe127131f9ab9a60dc1ac8a8f0c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10268cd12c71355f1284f696a0c62da83c4088e91a867af6368efdd74ce3d7eff26","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dLcg/Nk/+QfgovnI9i6TFeZML80CMYTr3f1IXXgrqV8=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 74b720\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bf27 f9ca | 15 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n001 2 2529 2643 | 5 2643 (0) 2529 (0) 2f17 (0) 11bd (0)\n002 2 4c5f 577b | 4 577b (0) 4c5f (0) 427f (0) 4601 (0)\n003 4 6646 6304 62ac 6013 | 5 6ef5 (0) 6646 (0) 62ac (0) 6304 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 1 729a | 1 729a (0)\n006 1 76cb | 1 76cb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","private_key":"83492b92e97ad908351537aa0f01d5614452490cf85d56215d3006e338bb389c","name":"node_74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","services":["streamer"],"enable_msg_events":true,"port":44117},"up":true}},{"node":{"info":{"id":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","name":"node_6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","enode":"enode://8cda75928f71a74705a2ed5f5be1de1c8691e042595382f84f23bebbbe69477e0ba0a568d97fe91e18861bdc4e7c9c0d9a466e22f6e00beab183543e864f4769@127.0.0.1:0","enr":"0xf88fb840a1c957342355083dacdeffbfef817d1a37e22e1bbb4ff136c9815dcf336050f93ae809fb2490493975a93d6f949147035cc66f88d474bf97f76a3eb34134c9b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038cda75928f71a74705a2ed5f5be1de1c8691e042595382f84f23bebbbe69477e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YBPUDAwV9aex3dWo72qAdX3pAisghTWTiwk3uRUHceA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6013d4\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bf27 e4f7 | 15 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n001 2 2643 2f17 | 5 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n002 2 4c5f 577b | 4 577b (0) 4c5f (0) 427f (0) 4601 (0)\n003 2 729a 74b7 | 3 729a (0) 76cb (0) 74b7 (0)\n004 1 6ef5 | 1 6ef5 (0)\n005 1 6646 | 1 6646 (0)\n============ DEPTH: 6 ==========================================\n006 2 6304 62ac | 2 62ac (0) 6304 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","private_key":"2275b1fd6c200d65748673efc3a9afdd59ff34baf765acaf0f008a928367dd28","name":"node_6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","services":["streamer"],"enable_msg_events":true,"port":40301},"up":true}},{"node":{"info":{"id":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","name":"node_e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","enode":"enode://69efa89de7d90f3f3edad743eef4e6e36934a6a14fa9e9e1080320e890a94a7da29546296e7bcd07d2b061ee43e244f07340fb03a1a3b269f92feddacd0a9b67@127.0.0.1:0","enr":"0xf88fb840ff8a7a209199998d93974593321244f0a2ee30732cdda0e24ea6aa4dc0d6f9a42a576b74fd95f259aa67c31deec2b7d34e85330281f60bfceca4d877a7745cda0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10369efa89de7d90f3f3edad743eef4e6e36934a6a14fa9e9e1080320e890a94a7d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5Pd23d2eR2YI+zNasi//GDYwm5RA7k7g/Teiun/KhQc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e4f776\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 427f 6ef5 6013 | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 d756 cbd4 | 2 cbd4 (0) d756 (0)\n============ DEPTH: 3 ==========================================\n003 3 f4b8 f9ca fb64 | 3 f4b8 (0) f9ca (0) fb64 (0)\n004 1 eed4 | 1 eed4 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","private_key":"4c402cd5bad71d24a8e1c56fa5ee6561720f8305502388535804bdc29597dc94","name":"node_e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","services":["streamer"],"enable_msg_events":true,"port":43119},"up":true}},{"node":{"info":{"id":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","name":"node_fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","enode":"enode://d50974428f44cbaf9fd8c7fa9472900980d63e4682d2997b985c1185abe3450c25406281ce806a8529ce399d671123ea32b363c7ea7f65d1d897bdc336f701d3@127.0.0.1:0","enr":"0xf88fb840848de2e989e6ff63e20a5895cf88ae9de52c8db2f19690ec42f4e41e7ee318a04c3600ad148eb7bcad1aa256c4dbef4597fea0e324996af6c61d7d8fdb252db20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d50974428f44cbaf9fd8c7fa9472900980d63e4682d2997b985c1185abe3450c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+2Q3C8BwchXkGvsNoaU/irpeEfRxuuT43EvYWjtmgno=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fb6437\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2f17 4601 | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 d756 cbd4 | 2 cbd4 (0) d756 (0)\n003 2 eed4 e4f7 | 2 eed4 (0) e4f7 (0)\n============ DEPTH: 4 ==========================================\n004 1 f4b8 | 1 f4b8 (0)\n005 0 | 0\n006 1 f9ca | 1 f9ca (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","private_key":"fba40333131adaf83dd0444a5f805a739af0de3f2e625a2d2a02ecbe0efbe070","name":"node_fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","services":["streamer"],"enable_msg_events":true,"port":46323},"up":true}},{"node":{"info":{"id":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","name":"node_460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","enode":"enode://7c183d9bceaff51f943081c68a318028c043466b0910f4bcdb80d8cea48ece224b458ac2c812cce8dd550b35a4fd52d07622f970b2c1aa6638ec8e62550c1da8@127.0.0.1:0","enr":"0xf88fb840fa49b18d0242ef72eb77b319e3a923d60f566facee5a69e8115a614a4be438dc4578fdb50fbfa54de817c0d391bbe60368231734f291232d222b7ea9e70ae5b30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027c183d9bceaff51f943081c68a318028c043466b0910f4bcdb80d8cea48ece22","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RgFIuERLcUtH8JKFqgzijcNBjLa59Fi1ICwFMyBfgqQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 460148\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 fb64 9c93 aa7e | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 2 08ff 2f17 | 5 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n002 4 76cb 729a 6646 6304 | 8 729a (0) 76cb (0) 74b7 (0) 6ef5 (0)\n003 1 577b | 1 577b (0)\n============ DEPTH: 4 ==========================================\n004 1 4c5f | 1 4c5f (0)\n005 1 427f | 1 427f (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","private_key":"459d2f0468a2f990289cf0a0ec59948f82ede34b97dbab4f8ddd68dd7fc9639c","name":"node_460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","services":["streamer"],"enable_msg_events":true,"port":35919},"up":true}},{"node":{"info":{"id":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","name":"node_aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","enode":"enode://15ce819f63a4f20fde81216cd54aa442b1e47a86085d2a887e8b482da64bc15a125a2e31dfc8b65aff9a7babe1813162e591c204e8ec3e2d37ece40c9f42eb1e@127.0.0.1:0","enr":"0xf88fb8407e05321ea1e0ebf79e030cf98817c8e7b61df62645db829c2b2699afba8443297692b19615479f37442bec12f5a6d72301a8a661cc3e391997e699f0377c87e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10215ce819f63a4f20fde81216cd54aa442b1e47a86085d2a887e8b482da64bc15a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qn5F1Fg1cP44KCjk/z1gzNUmzqATJSEdh87rbMFK91M=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aa7e45\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2f17 4601 | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 9934 9c93 | 4 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n003 1 bf27 | 1 bf27 (0)\n============ DEPTH: 4 ==========================================\n004 1 a11b | 1 a11b (0)\n005 1 ad46 | 1 ad46 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","private_key":"b623e785770ec4f9bbecb44c624cc704b1a8cfbb565744fa329235d240453d32","name":"node_aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","services":["streamer"],"enable_msg_events":true,"port":36243},"up":true}},{"node":{"info":{"id":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","name":"node_9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","enode":"enode://8eb7c4844662e4bec44d1a6c0eeea367815e9c378910f5891c6d1288ef8e695c7d1970934d8f00c26efe46d0119ba01c90f3564e2f56e3ca062713cf0161d960@127.0.0.1:0","enr":"0xf88fb8409f6890c59e203693b5137924950100d7ea0bb4095f006df9c4ea5520bc66d3536d3a5a0f8f684b7301e33c0bd9e07a11139776e1f1072758400835dbd411fa7f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028eb7c4844662e4bec44d1a6c0eeea367815e9c378910f5891c6d1288ef8e695c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nJNfqvtBp7072hiovQIoeBBb+EU6W4PSv6TaRtjJCPg=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9c935f\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4c5f 4601 | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) fb64 (0) f9ca (0)\n002 2 ad46 aa7e | 4 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 94a2 | 1 94a2 (0)\n005 1 9934 | 1 9934 (0)\n006 1 9e27 | 1 9e27 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","private_key":"3a9fc1630c5328ae9c4cfded644dab18a8eae96ddac7dc65542f37918447df3f","name":"node_9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","services":["streamer"],"enable_msg_events":true,"port":43587},"up":true}},{"node":{"info":{"id":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","name":"node_9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","enode":"enode://8f2dd1bb62e9253f7a43f26fd9de2181d827183eef6b578c4246637ed66324ef4487bcf99259f32b59dd66d2d314b939e0ec66b08917a933b4697615252093ab@127.0.0.1:0","enr":"0xf88fb8403e5081fcaca0fe89abed76a93405df6e2416d260e7986ad71d2b554ff81be728584602b1049e0767ecce05662e43acff92a0c720e9ff3068782c88c5333f53c20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038f2dd1bb62e9253f7a43f26fd9de2181d827183eef6b578c4246637ed66324ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mTQpX73jfUp/hnyafh9kKMSZbRtDhj28Wi9SpUZknvA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 993429\npopulation: 17 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6304 62ac 4c5f 2f17 | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 6 fb64 f4b8 eed4 e4f7 | 7 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n002 3 a11b aa7e ad46 | 4 aa7e (0) ad46 (0) a11b (0) bf27 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 94a2 | 1 94a2 (0)\n005 2 9e27 9c93 | 2 9e27 (0) 9c93 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","private_key":"498b023a2d77a2bcdf5fc8faee54349c6d9bcc7bcc3847c665145494c6395e63","name":"node_9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","services":["streamer"],"enable_msg_events":true,"port":33825},"up":true}},{"node":{"info":{"id":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","name":"node_08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","enode":"enode://0dd78993fa0c2b78e8abf537fef7b683f90255b48e4c5d62a676b4c5c06f0a9deba8777bfc8476e26af45438819993b89ab9697465a52396923ab63ea46de6d1@127.0.0.1:0","enr":"0xf88fb840df5e81a8734f5835674758db9c12bdea17ce6724347b9b3ee12ef8b19e645abe7a9ba7898badf352fe74e273f66e00800fc1a64cf4a1d94de871ef51116c5e670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030dd78993fa0c2b78e8abf537fef7b683f90255b48e4c5d62a676b4c5c06f0a9d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CP9UtgMHz7vZsgm/B8em8WQZK4DJ3V7q3SbjaK28fbw=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08ff54\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bf27 9934 | 15 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n001 4 729a 76cb 4601 577b | 12 4c5f (0) 4601 (0) 427f (0) 577b (0)\n============ DEPTH: 2 ==========================================\n002 3 2643 2529 2f17 | 3 2f17 (0) 2643 (0) 2529 (0)\n003 1 11bd | 1 11bd (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","private_key":"ee655daff35bf421813437b35da4b5cbc518cfadeb319c82c5211d697a821466","name":"node_08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","services":["streamer"],"enable_msg_events":true,"port":45679},"up":true}},{"node":{"info":{"id":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","name":"node_bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","enode":"enode://890aca84b10caa9057d6dca9730544992a7bcdf38b78e82508f5be6e0b2149592fbcd837b829232ccaa8310759a27aab18addec6239becffddc5942760d3aac4@127.0.0.1:0","enr":"0xf88fb840a1b52878b681cfd6dffb3a53f24aa4920cf5b65dc92c1bed8511407085072b7f5ebc71f1a59fae35d1e8e4896b3a9ee980cb318061f8c6a6652a353633b98f700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102890aca84b10caa9057d6dca9730544992a7bcdf38b78e82508f5be6e0b214959","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vyfczW95zIbTitejdbgzElrqrQYL4RfCPBtxKXsHLAA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bf27dc\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 74b7 6013 6646 08ff | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 3 f9ca cbd4 d756 | 7 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n002 2 9e27 94a2 | 4 94a2 (0) 9e27 (0) 9c93 (0) 9934 (0)\n============ DEPTH: 3 ==========================================\n003 3 a11b ad46 aa7e | 3 aa7e (0) ad46 (0) a11b (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","private_key":"d572f42e4c4b69acd62f2ced7411ffb238c6b5abd9039b6e3c47f01f6d1fde1b","name":"node_bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","services":["streamer"],"enable_msg_events":true,"port":44805},"up":true}},{"node":{"info":{"id":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","name":"node_6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","enode":"enode://fb3cece5266da81615d3398f3c34f6552eaaa9e55c79123f7282951226be7fab8db0cd0487ebcc3a5799d7dd25b91d3b4064c1959bc590ca6ddb8f10508e196b@127.0.0.1:0","enr":"0xf88fb84076bdf43d4d5251b70d43c1c650b2da1304cc4d6762d8368b75fa7063f92cde8b5129e9443fe40a0f3f421fb7a430eb451780ef473ce3caccde600cc00bafbc2f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fb3cece5266da81615d3398f3c34f6552eaaa9e55c79123f7282951226be7fab","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZkbsyHOY4J5UsOsZ5X1UPTE8PnNX/4TcqIhrg/ra4PQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6646ec\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a11b bf27 | 15 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n001 2 2643 2f17 | 5 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n002 2 4601 4c5f | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 3 74b7 76cb 729a | 3 729a (0) 74b7 (0) 76cb (0)\n004 1 6ef5 | 1 6ef5 (0)\n============ DEPTH: 5 ==========================================\n005 3 62ac 6304 6013 | 3 62ac (0) 6304 (0) 6013 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","private_key":"685914c526e3efe92ebef3400b22a51a7a4771de5c87ffd5f9da4e8db9d1282c","name":"node_6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","services":["streamer"],"enable_msg_events":true,"port":40729},"up":true}},{"node":{"info":{"id":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","name":"node_a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","enode":"enode://3c0855f7cf4fc19e61b4aeb52f69cc6eafe9800738da596b60366854eec2b55e1b82583803a6564d6f3f5fac83bcf41748cd8f4a316e131afe54b1a93ba235ec@127.0.0.1:0","enr":"0xf88fb84005478b240adc6c61921f460140f141ddceb6ae0cdbdf49cb0952cb457849b3ce4080fcf91b3b80ac6eb08e75e78f0ed80169a9269845bb24999a1828b5b7fd3d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c0855f7cf4fc19e61b4aeb52f69cc6eafe9800738da596b60366854eec2b55e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oRs8Z+o21BJk/clxI6QchYaDcZlJZ4LnmUtr6DFXG3c=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a11b3c\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6646 577b | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 cbd4 d756 | 7 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n002 3 9e27 9934 94a2 | 4 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n003 1 bf27 | 1 bf27 (0)\n============ DEPTH: 4 ==========================================\n004 2 ad46 aa7e | 2 aa7e (0) ad46 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","private_key":"100fcd428dcc5043b3dbdd4bbb18ee89cd22a1e122e6daa5173b38d971e81dd4","name":"node_a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","services":["streamer"],"enable_msg_events":true,"port":40597},"up":true}},{"node":{"info":{"id":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","name":"node_577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","enode":"enode://20ee1cefe65d31d3bbef59fc59deb8cd34a06204403fef7c4c52143e62d207bce55396cf2cd302a103fb15ef7df24832502feab7478b558c6d549555a4b9fbda@127.0.0.1:0","enr":"0xf88fb8402bb8237b2f944ce884436ea3d41fb22fda669660233b5844733075ba1d9e8e4163169f20b8fcb972c30375d9fa5af751434559d55d174c300c2842f899763ee40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10220ee1cefe65d31d3bbef59fc59deb8cd34a06204403fef7c4c52143e62d207bc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V3szQogDWbn6Qm/c6PwxXOpkBZK3h+bjrb3sZpn0sqo=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 577b33\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d756 a11b | 15 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n001 2 11bd 08ff | 5 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n002 4 74b7 6ef5 6013 62ac | 8 729a (0) 74b7 (0) 76cb (0) 6ef5 (0)\n============ DEPTH: 3 ==========================================\n003 3 4c5f 4601 427f | 3 4c5f (0) 4601 (0) 427f (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","private_key":"8b2f5863391217a259d77ab4007f410d37eb2f81f76b87497e738c1a6dc07042","name":"node_577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","services":["streamer"],"enable_msg_events":true,"port":41231},"up":true}},{"node":{"info":{"id":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","name":"node_62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","enode":"enode://0761ae452c8e6d8803e4dd3dd4b66a50b5f17ba7c25babf1f41b273572d90ba7fa6de5b9ff53bd29fb89c0f0aee57b9d4bd7508b58411c184c27c6b4d113c38c@127.0.0.1:0","enr":"0xf88fb840e15454baf140946f84455b01b25479ab82d8df1e547d32eb511a08db1b6d2fa13417e78cfaa91a62ff85b5be203ca4c525537fc21651ab6b721781ebe2367eba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020761ae452c8e6d8803e4dd3dd4b66a50b5f17ba7c25babf1f41b273572d90ba7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Yqxq8IrhZrDVYSvGWgfkFIdqOKNVIJHUYcgIxfa0cbA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 62ac6a\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9934 94a2 | 15 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n001 2 11bd 2529 | 5 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n002 2 4c5f 577b | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 2 74b7 729a | 3 729a (0) 74b7 (0) 76cb (0)\n004 1 6ef5 | 1 6ef5 (0)\n005 1 6646 | 1 6646 (0)\n============ DEPTH: 6 ==========================================\n006 1 6013 | 1 6013 (0)\n007 1 6304 | 1 6304 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","private_key":"c094ade67efd8691772e76ed09d41e9dcd2d0c478331223fdd1c7736d84736e8","name":"node_62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","services":["streamer"],"enable_msg_events":true,"port":33431},"up":true}},{"node":{"info":{"id":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","name":"node_2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","enode":"enode://d31fbb6c9836fc684468eaa5865756779ef13e13bfc5af8a819f68a3d388b5e9c8c54b17cbd5ddfb355e15fee71d1ec86dfed0472309edcfa84dce531caf3e4d@127.0.0.1:0","enr":"0xf88fb8404566296b99cb998abb9c6d5f61d4df6674dfed5706ae4bd804f2b0d1d2088bd35e152e18aaca113522024b0ed409292b8d596c50093d18e319240bb27f055fe00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d31fbb6c9836fc684468eaa5865756779ef13e13bfc5af8a819f68a3d388b5e9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JSnrbvu61FE8Ev//9yLCwklnWbXrPZUwL/m/fqzA1Cc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2529eb\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 94a2 eed4 | 15 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n001 4 427f 4c5f 74b7 62ac | 12 4c5f (0) 4601 (0) 427f (0) 577b (0)\n002 2 11bd 08ff | 2 11bd (0) 08ff (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 2f17 | 1 2f17 (0)\n005 0 | 0\n006 1 2643 | 1 2643 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","private_key":"f8cc4cad963f73aff2b340dfcf30ab658e08f58928824419a15246c2532c43e7","name":"node_2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","services":["streamer"],"enable_msg_events":true,"port":35361},"up":true}},{"node":{"info":{"id":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","name":"node_eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","enode":"enode://e11c49200047bdb02fac35163462fdeb3e40477670420f345db00b3f0cc008ed768b308bce67bf5ddf3c5728ccadf39f8362d18eafedd9c7c0f916e62d491470@127.0.0.1:0","enr":"0xf88fb8403e683663f20a82e4d0a4a2750956048ae4f294e82db9c02f2d31e574d2564b9605f5ca54db82f1e460613dbfa8570cb35a0badd8fdc581ce43f6fcab0026556a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e11c49200047bdb02fac35163462fdeb3e40477670420f345db00b3f0cc008ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7tS5oGvI+gtxlb7v8b+3l53zfHIN7JyJFGggq/SDaBo=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eed4b9\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6ef5 76cb 2529 | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 cbd4 d756 | 2 d756 (0) cbd4 (0)\n============ DEPTH: 3 ==========================================\n003 3 f4b8 fb64 f9ca | 3 fb64 (0) f9ca (0) f4b8 (0)\n004 1 e4f7 | 1 e4f7 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","private_key":"00b0480a2de8f0b9a04988e6b64da01d184d36d84da1b6c377b19d991c6bfdc2","name":"node_eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","services":["streamer"],"enable_msg_events":true,"port":39613},"up":true}},{"node":{"info":{"id":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","name":"node_76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","enode":"enode://eb693286d13dd7d22dbf20c8a7bd9df2cec24474ed4f059cff8fbbb7013081d12ca2caa7d5e2084225ae04d7c6070fc61158f0f7de6e16213b48c01aea446f47@127.0.0.1:0","enr":"0xf88fb840af4b0c315818be89b44fbbed80450d4973e3ae933823e9dd5302edce8e5059744c616a175dc2d6d818ce0ad591f864fa0d9381df6d8a065beef99449ec3ecbb20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eb693286d13dd7d22dbf20c8a7bd9df2cec24474ed4f059cff8fbbb7013081d1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dstH66hKeuDp8A8TgbqFwu3p+n+JmoePlOSTt+KrQBc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 76cb47\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f4b8 eed4 | 15 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n001 2 11bd 08ff | 5 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n002 3 427f 4601 4c5f | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 2 6646 6ef5 | 5 6ef5 (0) 6646 (0) 6013 (0) 6304 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 1 729a | 1 729a (0)\n006 1 74b7 | 1 74b7 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","private_key":"8ddfa941097daa1adbf355c69b301a9b9b4e984f51fbc021d6abbd2df8eb5391","name":"node_76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","services":["streamer"],"enable_msg_events":true,"port":33051},"up":true}},{"node":{"info":{"id":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","name":"node_f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","enode":"enode://8e1bd7a84722a0d831f2ce96f52c463bc3232306ab90de59ad821884df222db8cf6204e33398d2ccb347156b73088661c96f16da9b37a53c48f1cdc00897700e@127.0.0.1:0","enr":"0xf88fb840e5deda0993da1e8b4297c89a66ddf4b197118fc19c40d2eb65d35c08c607922252bfa120d52fcdacaa4d68bd36af44be179038dce4b9857b9b3b29737d9b508a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028e1bd7a84722a0d831f2ce96f52c463bc3232306ab90de59ad821884df222db8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9LipUFZzCgOm0XtnVDhg+V7tJrbkPwWhmS8nOZ09MSY=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4b8a9\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6304 76cb | 17 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 cbd4 d756 | 2 d756 (0) cbd4 (0)\n003 2 eed4 e4f7 | 2 e4f7 (0) eed4 (0)\n============ DEPTH: 4 ==========================================\n004 2 f9ca fb64 | 2 fb64 (0) f9ca (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","private_key":"ffe54ea17543345a77321ae2e3776751db00762580f661c0f15896f42500959e","name":"node_f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","services":["streamer"],"enable_msg_events":true,"port":33473},"up":true}},{"node":{"info":{"id":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","name":"node_6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","enode":"enode://d07fabc00b19f95c1732019dafb44716ccc4e19dce5e9985d4dc8237790811a6e7973a650f98183de314b6061f815b190dd620fd33a6ae2e398c10c57614224e@127.0.0.1:0","enr":"0xf88fb8408d97738fe8da5aeda2e04c10e3c563f61ecc6911afcf669e9e50b306b67b4e023292aec1a2d35c5dcec0c612b0d5cd02f21098fd8b3e3ad40679b1778be6dcc10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d07fabc00b19f95c1732019dafb44716ccc4e19dce5e9985d4dc8237790811a6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YwTisTVFXOAiA+vD9RS19ik+a7DJqYEpt7DW9svJjO8=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6304e2\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9934 f4b8 | 15 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n001 2 11bd 2f17 | 5 11bd (0) 08ff (0) 2643 (0) 2529 (0)\n002 2 4c5f 4601 | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 2 74b7 729a | 3 729a (0) 74b7 (0) 76cb (0)\n004 1 6ef5 | 1 6ef5 (0)\n005 1 6646 | 1 6646 (0)\n============ DEPTH: 6 ==========================================\n006 1 6013 | 1 6013 (0)\n007 1 62ac | 1 62ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","private_key":"80cf26c0793a22bf69aa3bf4d71052a9ede84d73135a7b39d1ec068bdd2929c7","name":"node_6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","services":["streamer"],"enable_msg_events":true,"port":34879},"up":true}},{"node":{"info":{"id":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","name":"node_2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","enode":"enode://df8c978c17fbed86c3fc257bb0d3aca0a8831d358b13cf87413888240c12cf92840bd89e98350dc7aeb45c91a97a7bace5b60b42bac6831972ef0eecb5180c03@127.0.0.1:0","enr":"0xf88fb84015eb3d3b46b7b35f89720cf53396e495bda8dee9ac4fe55ad75cc91a7a3358f23e5c8fe05da05dbd5ecba9d42d131646b563810ac1603f78569e9b059c719fd60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df8c978c17fbed86c3fc257bb0d3aca0a8831d358b13cf87413888240c12cf92","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LxfhgNB4MkaOaqkVlknNabGZMTyyxv6S8VmNhvY02jM=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2f17e1\npopulation: 14 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 aa7e 9934 fb64 cbd4 | 15 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n001 6 4601 427f 4c5f 6646 | 12 577b (0) 4c5f (0) 4601 (0) 427f (0)\n002 2 08ff 11bd | 2 11bd (0) 08ff (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 2 2529 2643 | 2 2643 (0) 2529 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","private_key":"256815d05345b0618e277d6f2618ac89ef4fa493b339bf65f0eaec5cbd404e92","name":"node_2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","services":["streamer"],"enable_msg_events":true,"port":37517},"up":true}},{"node":{"info":{"id":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","name":"node_cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","enode":"enode://5cca6a56e89c4aed55749ad75c465e9fb86ff85723c02abb5037ef5db3c05b5fc45dc735575b737fec5a5bc572466e636c0fe7bdd56d98ea684a5314ea065f84@127.0.0.1:0","enr":"0xf88fb8405b51d4e5f768fab1263aad5fc3d836b5a9299f2e915bd7fde99ee1632440e56c40d1fae3bad1fc292927c07694c0a31e4bdaa4214df6ab41b5bd9eb847202c170183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025cca6a56e89c4aed55749ad75c465e9fb86ff85723c02abb5037ef5db3c05b5f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"y9SqXhRWbEepN1W1N9LRB3U0bvEabGQis30GYclImUE=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cbd4aa\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 729a 11bd 2f17 | 17 577b (0) 4c5f (0) 4601 (0) 427f (0)\n001 7 bf27 a11b aa7e ad46 | 8 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n============ DEPTH: 2 ==========================================\n002 5 eed4 e4f7 f4b8 fb64 | 5 e4f7 (0) eed4 (0) fb64 (0) f9ca (0)\n003 1 d756 | 1 d756 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","private_key":"c8cfa60b5e127e3bacb81f83e2b754b73a42724cda004a2a5ed5fbcf22dfddd4","name":"node_cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","services":["streamer"],"enable_msg_events":true,"port":44323},"up":true}},{"node":{"info":{"id":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","name":"node_729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","enode":"enode://fd9832b9b0eef81dc9fcab0852581e32bd63572f5e46a85c7aa0ad26596ca899a680f1c02bc80e2f9d9834a24a79071b26a4e040c8d4e7acfacfd07d1d8f7939@127.0.0.1:0","enr":"0xf88fb8402f0c70d6cc93f4019ac80464fe97225e30532a384869ad2228660e40a240ca1852d6750396d22e257cb2a1b79b4eeeb4c65303d87a91af08ce3c213c0751abf30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fd9832b9b0eef81dc9fcab0852581e32bd63572f5e46a85c7aa0ad26596ca899","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cpoYV5+tL8dda0RRZ+c1YV6Au3A3nnqSR6CbppFlecA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 729a18\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d756 cbd4 | 15 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n001 2 11bd 08ff | 5 11bd (0) 08ff (0) 2529 (0) 2643 (0)\n002 2 4601 4c5f | 4 577b (0) 4c5f (0) 4601 (0) 427f (0)\n003 5 6ef5 6646 6013 62ac | 5 6ef5 (0) 6646 (0) 6013 (0) 62ac (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 74b7 76cb | 2 74b7 (0) 76cb (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","private_key":"675a65f43358f973c940f285b96994d598a5a63b511de041e959d415fc38f605","name":"node_729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","services":["streamer"],"enable_msg_events":true,"port":41717},"up":true}},{"node":{"info":{"id":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","name":"node_d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","enode":"enode://46a796a7e0ef14bf01598dafad914d15b6e16a7a15252f2e318dfb509897cc5e25fe3727de0e8cfd6d6ee2ed1c27981737b15038237650981465e6410f49e6b9@127.0.0.1:0","enr":"0xf88fb84039e08ba3a29f958abdbd524c52eb953e01d52dfc9c1f0259d81debaa7bf88aeb11819630685dbe6939805e57357068d0768dc6a4c7233564b1b783b45a4a4fc90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10346a796a7e0ef14bf01598dafad914d15b6e16a7a15252f2e318dfb509897cc5e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"11Y9bcagN4QGs3WOHMpCiklLdlJuBvrq20M1DK2YZ5I=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d7563d\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 577b 427f 729a | 17 11bd (0) 08ff (0) 2529 (0) 2643 (0)\n001 7 bf27 aa7e ad46 a11b | 8 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n============ DEPTH: 2 ==========================================\n002 5 e4f7 eed4 f9ca fb64 | 5 e4f7 (0) eed4 (0) fb64 (0) f9ca (0)\n003 1 cbd4 | 1 cbd4 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","private_key":"eeeffb7fefb163eb424dbeedafc3a4b2de7c7aff8f531b8969b5bc809c4232ab","name":"node_d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","services":["streamer"],"enable_msg_events":true,"port":37925},"up":true}}],"conns":[{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","other":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","other":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","other":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_4.json b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_4.json new file mode 100644 index 00000000..81afb03f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_4.json @@ -0,0 +1 @@ +{"nodes":[{"node":{"info":{"id":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","name":"node_0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","enode":"enode://918f13e29fcea21b47e553c60ea0ae63f856db5745c6010e31b566f819195f9a5f250788862c43b230dd93fbc24cb6b3d33c86069cc21de3a3612b2f32eeccbe@127.0.0.1:0","enr":"0xf88fb840ad1a67c3b07299bb50337351be97595ef05e5ab7988ab7831e06a3003d1fc4ad74e925ec495ab312ccc889eb9c05f2e14f625e56f813a76dc53ddd94ea0955f90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102918f13e29fcea21b47e553c60ea0ae63f856db5745c6010e31b566f819195f9a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"C0Bd7YfOTnEqrrswVecHFslx/gSaVJYSlMenoEcdEvY=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0b405d\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 a430 | 1 a430 (0)\n============ DEPTH: 1 ==========================================\n001 2 77ba 675c | 2 77ba (0) 675c (0)\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","private_key":"173c23bc3aec26afe7d299eb9556e7c189851378fe56125d929966ac7207bcb6","name":"node_0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","services":["streamer"],"enable_msg_events":true,"port":38277},"up":true}},{"node":{"info":{"id":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","name":"node_a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","enode":"enode://89b66f574168570cc5d347051c0e2b05b33578d42142ef8cc930f1fbb384266f2827e4b087f5e2985a32d8f2b353fb7be416193632da5c692cace99d1b9e4274@127.0.0.1:0","enr":"0xf88fb8402e6392d3d5377977fc4b4d29f4dbf4ca96e963df056ead84ec2fcb7ee071996670a935d3b49250455e02c392baacb4c8499f815f74b09c405316a5d2fdee94e60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10289b66f574168570cc5d347051c0e2b05b33578d42142ef8cc930f1fbb384266f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pDAQRcDN5ay1QG4fukbshowFZDmrQ+95WDB0j7a6Llo=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a43010\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 3 675c 77ba 0b40 | 3 675c (0) 77ba (0) 0b40 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","private_key":"5bcd3bbb886e5ad2317a6ac1de2b19ebe27db9337ba8e7daa76a1cdaa6a3d158","name":"node_a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","services":["streamer"],"enable_msg_events":true,"port":41325},"up":true}},{"node":{"info":{"id":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","name":"node_77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","enode":"enode://ecb56004a128067628a3198244080ba4ac79860cb2cf74407d7571955a80fb9243ad5f8265063a5aa209ea95329b4b57d0f1b492a85835ab87fce79881a895a9@127.0.0.1:0","enr":"0xf88fb84035ed878b2a99ed1bbd55df1701cd82115aebc649b1e8e68302e7caf5480a61322c74189d1fe66f2d16e79174f0e3479213f0bf963a4518d583078e164bd94a220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ecb56004a128067628a3198244080ba4ac79860cb2cf74407d7571955a80fb92","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d7oUWkYjucg+ChSjdbpJxocZ8qvhYv/KZt5+8uMadfg=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 77ba14\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 a430 | 1 a430 (0)\n============ DEPTH: 1 ==========================================\n001 1 0b40 | 1 0b40 (0)\n002 0 | 0\n003 1 675c | 1 675c (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","private_key":"6f30c3d0135202cbf540669c8c76d9144bd53764aaf4ae18e8bee98ce05c6211","name":"node_77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","services":["streamer"],"enable_msg_events":true,"port":40785},"up":true}},{"node":{"info":{"id":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","name":"node_675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","enode":"enode://64a6b33b028b818a1961272651d1d7a976329e541b6e3e983f518d89326d7427f4c9243f78bb03fd2e2dc059f610ee50d1e664e3107db01ac603b9c3b20ebb4f@127.0.0.1:0","enr":"0xf88fb8407dbbb99300e04c6917c27d61bf396481aae19287c2869e8dd74e11b0f2ebb74174376a6152c26af95173a4868a0349aaf3be5d063918590fd5962f4af174e0010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10364a6b33b028b818a1961272651d1d7a976329e541b6e3e983f518d89326d7427","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z1z+0Ke0YfQ8/r1qEOzIho01skU4HXMavsRgi23OJQo=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 675cfe\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 a430 | 1 a430 (0)\n============ DEPTH: 1 ==========================================\n001 1 0b40 | 1 0b40 (0)\n002 0 | 0\n003 1 77ba | 1 77ba (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","private_key":"d77006035afa5194053c0347021f7825a71f9643028c45b65756ef88ee53e6dd","name":"node_675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","services":["streamer"],"enable_msg_events":true,"port":37069},"up":true}}],"conns":[{"one":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","other":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","up":true},{"one":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","other":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","up":true},{"one":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","other":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","up":true},{"one":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","other":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","up":true},{"one":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","other":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","up":true},{"one":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","other":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_64.json b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_64.json index 8785c9e0..71548556 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_64.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/testing/snapshot_64.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","private_key":"0736b1ccd6a1d7c513e312d29a8afa6e1231954e17a66886d0bbcf0dc191b170","name":"node_a48a667469a1344cb70f269b21fb3ca9e83823226749fd9c232be1b86ab9427888f2ecb20ddfa56da361463a061e192570f2f8da3fa967c473320ca85e382c53","services":["streamer"],"enable_msg_events":true,"port":62976},"up":true}},{"node":{"config":{"id":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","private_key":"edcc0061564101058d0caf2a7dd7cd178a2fd7f5de93263f1b2abac25ce28360","name":"node_8f6fb4a5baf715e001b060ce72378829279ce06a3247bd4a6faa3c725ee1b949570373e4231de82981020563e704297e77172506101b1444fcacfcc5f211827e","services":["streamer"],"enable_msg_events":true,"port":62977},"up":true}},{"node":{"config":{"id":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","private_key":"911635b150029a2a56d4a5b647162774df1ff5e6946c727ba21e3e8cad2c41ce","name":"node_e7b1563d6e089e030983b075b590abb8a3205e9bce953f562b755ba150a3edc2dc3377259d96c05cc7363a23aed613711ca049e26253fd9273ac4c0483087015","services":["streamer"],"enable_msg_events":true,"port":62978},"up":true}},{"node":{"config":{"id":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","private_key":"4bd5083735663222c8e8948125c8f606952ef887a4a07888d39d8aa6af0568e8","name":"node_d0718ce0dafea66ee16c79626e020355273cdd062c0fceb122e391c4ca6e4e408a1b0e8230c4ade5bc95803916bdd6d98c99d2b6ea70c32e17fa1f2c98741a90","services":["streamer"],"enable_msg_events":true,"port":62979},"up":true}},{"node":{"config":{"id":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","private_key":"8cb2a950934e687c8aea0a72114b26989bccfcdf508f584a549d05091aef2c3f","name":"node_af3f9dc00ce3cc156000f16a06c55c123ccdfabed89c9aee4478ff439b6f52a89d0501cff626d36b7f1852737955f7a036b25cf259580e8f46a3e0e44340b539","services":["streamer"],"enable_msg_events":true,"port":62980},"up":true}},{"node":{"config":{"id":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","private_key":"3c147cdf4e85087a9c0e37ff5d96de7d977ce3d3711090f64d2c3bea39790167","name":"node_95c3ca2362de2eb0ac8efdd243918ed216f5d124bc6f5b9d83a6ee1aaf8a0fbdbd70ca1710d1ed825d6871f13a15954725f1aa1b27b48307844c0bc27baec0db","services":["streamer"],"enable_msg_events":true,"port":62981},"up":true}},{"node":{"config":{"id":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","private_key":"fb505af88aa3fc8134b3ad647d78f182e0aee007261c066024d9fdda0bd9d297","name":"node_c73f8fe9f54b89634cb0e8e332407a3a90cbbd347c0abc93823db13a7a39c46e7bd30d3f557316d92dd731cfc686afc308448682ff06c77246e3fb02b9a025ba","services":["streamer"],"enable_msg_events":true,"port":62982},"up":true}},{"node":{"config":{"id":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","private_key":"833d044f5a00d0018f8b2a7d4d825831f351dbe3f3e7074d96103c3597bb0a37","name":"node_9529ff2b0692ad2608b55ec8ec0d1c9ccb8ee300412d99d389009162a76f7eec28d1090cbfb571aa8396b365074770b17106bfa3354857878dff164f42686142","services":["streamer"],"enable_msg_events":true,"port":62983},"up":true}},{"node":{"config":{"id":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","private_key":"f08b159c68739d221adc0060225f8feb89dc3aa1f016cef59508d2787a4232a9","name":"node_5b456e429f7adae30366206e681ba46439a3372fec3806f666425cb3f12983c0b427e089fb163b70e6a56220b1529ee392ff701bc2f4621d51e23aa6305150e8","services":["streamer"],"enable_msg_events":true,"port":62984},"up":true}},{"node":{"config":{"id":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","private_key":"bbadcfc9e554aabf08f9cdea8f1174f4f47b85c5a615efa6f0d5a4db7e6e9f67","name":"node_5e92b025cc087c8823423c287f274a32a3dc0065afdf189475ba96b0da7b785cd493b7f2a7f3bb8195c73025bfbb402cbb4e0f6ae0d5e0caab223193cf6f2e5c","services":["streamer"],"enable_msg_events":true,"port":62985},"up":true}},{"node":{"config":{"id":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","private_key":"91980cc1a6aa75dabe27a4bed1a4a2299ed286387f066d12c1a05ab514245966","name":"node_f6e4b1dc1fa95ceae2b932b178afdc2dd515832a191e0f49c916d5a04548d58ef9f8c1dda3fbc93a45e6d82517e6a573310b7bfb14bc38c57000aec9ff010391","services":["streamer"],"enable_msg_events":true,"port":62986},"up":true}},{"node":{"config":{"id":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","private_key":"9f2513f57cafcbb35e549fae622387037b8da11772eef7bbb45d44f81712155b","name":"node_707a9ae4bc8b37fff43dc3ba83ecb735bd428b720a751a11112452eec1ca49c09139bc437666add2823dd205e45cc793f8657c66ccbc6911cc60771d4512e038","services":["streamer"],"enable_msg_events":true,"port":62987},"up":true}},{"node":{"config":{"id":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","private_key":"a198f5ac31e6bef23d8f266075f8363ce66698d0f8b1193072f813b2a1717236","name":"node_78216c6660fff0b96e38084941a2f237996732118033bf842e5f9e533b22b36c2da996df28e866424311b7b6414d4627db1f22a235ae777f7de34d9696043ecb","services":["streamer"],"enable_msg_events":true,"port":62988},"up":true}},{"node":{"config":{"id":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","private_key":"9f8eddf3160bc4b13285e9587f6736c82305632b55fe833a12f1f821c0f311e4","name":"node_d472383c453e6b0f1a632010bdd6c42a9668d328a8f8071e0407069f6fe413e2a0fd0551a09cc56ee5245d472e39a7b6295491dd256ae42e200a257f297743e3","services":["streamer"],"enable_msg_events":true,"port":62989},"up":true}},{"node":{"config":{"id":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","private_key":"601ed94a775c7129de2ddd82e23249e13176478817e5376a1c18389de0016283","name":"node_351ceaf2e95e098a8e15e81c82073b523f641848326d1bbd379f40f886b50ce2c377c4e3a2dfc2662d6f25ac04dede41063a075cf00be1cf36f95b0267717ab8","services":["streamer"],"enable_msg_events":true,"port":62990},"up":true}},{"node":{"config":{"id":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","private_key":"dd64b8659254425a4553501bcc275b1dc0a6c7bc79a538f780716cd64d46a8c2","name":"node_8da9cdb3c78776ed230497b21d4ac172f0ce73e921dfddd483da7bc6bbcd1951dd78fd5f70a0acbad855b2984e4c4bdb408c4bc25cab40684fe5a4408ec7ab9c","services":["streamer"],"enable_msg_events":true,"port":62991},"up":true}},{"node":{"config":{"id":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","private_key":"7216dc13943bfd0a8c2e93d621a44a2dd4baab7b68fa87be06f2e649f533f72c","name":"node_0a45a0aa4b4eee71b2828c794281d698019667288cf51311ffae7d8ea895f8ae29f7958dbfcda8763d9d8e9c097dccc5f92ac9d09fb4ccbde178d7f5ebda4d35","services":["streamer"],"enable_msg_events":true,"port":62992},"up":true}},{"node":{"config":{"id":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","private_key":"01a2779483d6e089da8b3943f81cff48c8bfd1bd7d0281bceb152e41a7f5acb7","name":"node_f70c92be150cb3f65f6bd904c8c161bfb0cea717bab0b24da63714de83e0872c8c369960ada1629607a1e166a19b6cfa887603e4868e7912ae5512744e8cc1c0","services":["streamer"],"enable_msg_events":true,"port":62993},"up":true}},{"node":{"config":{"id":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","private_key":"2954d35fce94938f074043b9f9dd87157a6730bdd8e3a1b6f19b8a55ad1505df","name":"node_d563716fbe2068cc940f7b12dc2bacb345c95f01e78e3b1f0105a441f300fdb00cc72e677aec102360fb904b63055d8581555f5b74b8f2392706569d8357c53f","services":["streamer"],"enable_msg_events":true,"port":62994},"up":true}},{"node":{"config":{"id":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","private_key":"6f87c529d5b17354bd3ba6b59d6ff3a0f71550a41d949d702e27f50957cfc3ba","name":"node_46bb2acc087482d40ab2ccbb387723158411ff4931423414e4d09891be8a31d11929e939e4be94b0cc355c49883e1835785ba1955d865f78748c2a0a2f6eee0a","services":["streamer"],"enable_msg_events":true,"port":62995},"up":true}},{"node":{"config":{"id":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","private_key":"ea386dc625e681a5d5d7c4e8ede4b3ffb8f2f13061c65acdde2750e2a19ef417","name":"node_8da75cb4e63d968a7999ca4b49572b5ae592a91fa442d44bb7c42fb4b174a365e1affa1dbc45b2a0406444505f178100768e7783831f2886d53e7d1b8a3a7291","services":["streamer"],"enable_msg_events":true,"port":62996},"up":true}},{"node":{"config":{"id":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","private_key":"e9b9261c569da5418d3aeabf28dff1faada23ae1a3a1552035aefe56bdf3136d","name":"node_6d1af44ab259cc080a14c07bf5efabfd70cb847fe338f016c00138c84bddf6a6ce94047d1bffcfc7e9bc772dd7a080468a84655d5351d0056f97f13358b91547","services":["streamer"],"enable_msg_events":true,"port":62997},"up":true}},{"node":{"config":{"id":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","private_key":"19334395c71250dd3eeeef4eb4032e2769839d57cd6080f2f51e1de3630789fe","name":"node_0dcef49b94fdcff024d706030fd4f513d0c6ad5f00b06a8b67abc454bbe5c2c74e939d491c0700e47ecee5cd7c7084603f62e626c34b454868b8f22d8c2dfb10","services":["streamer"],"enable_msg_events":true,"port":62998},"up":true}},{"node":{"config":{"id":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","private_key":"d587a8503da404e7a74e24d731daf63b9585ae41b555035979da013ab723b4b8","name":"node_e7d4478b412ef497741943736946a3b0679d21ae0c4cbdde6809c7236dcf1a40291088d872e469f06da19ed4ef77b9844aee7066c40fcd45b0931aff847de1d7","services":["streamer"],"enable_msg_events":true,"port":62999},"up":true}},{"node":{"config":{"id":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","private_key":"724511e7e57416a6b4627079b0b9079fb4fd5649dd018d7f3a64dbf6a1dd9adc","name":"node_7722d7d06c66afb0642d5f9ae0b22ed812c632f2d62ce64315da40eb003feb3fae1b337c10df21d297beabe51b3879f2c0a725f08ee78a8e09c75f86bd0e2092","services":["streamer"],"enable_msg_events":true,"port":63000},"up":true}},{"node":{"config":{"id":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","private_key":"922f3ca85ccc577429654b566f1561a301bbad054e4f3a8f312db841329899c9","name":"node_e479930845e1dac2d5908894548cc06c132fc5820810c6f46d9adc2bc252dd40b64642a3b2005ad3688d2637c43967f570bd153db9ee6742e1b23dbfb72537fa","services":["streamer"],"enable_msg_events":true,"port":63001},"up":true}},{"node":{"config":{"id":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","private_key":"c94a8e8e535d7431b0610ebfaa70d76c37bf6fbcaaa83ec4be0bed5527780670","name":"node_61b32cded1b5ea3e2ca545a55c84251daaaacf51e6fed98fbdf4c5b6b91a554081e1e577aaaaaa4f911780f92703c1d715695d86c1be641b0bd1794f4107c2be","services":["streamer"],"enable_msg_events":true,"port":63002},"up":true}},{"node":{"config":{"id":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","private_key":"7a1378d2cad0ac18e37694b3ec5c08580aa1887916e98030c66accf6197f615b","name":"node_9e51eb48f59886e70eb8d02e1c0c4423de3f0ce79c7a62bfd91bc2048cf643f40a91e2d2a1a8a19a9e4ba4a96aed0965aefcd941c068208abe8bf5029eb27d55","services":["streamer"],"enable_msg_events":true,"port":63003},"up":true}},{"node":{"config":{"id":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","private_key":"6e834fb9046bc38179a4c8be1cd4c2c540df1f73aa208e9794701234202211ca","name":"node_7a1f97c41c9efd7a2903af78f72d02cfff3631dc6260d3ceb2364c2a8e06965710e8feae6aa9f99b48b2475da10b2f9581c76d47b4cd2bfee09c43dcb5e3e5d9","services":["streamer"],"enable_msg_events":true,"port":63004},"up":true}},{"node":{"config":{"id":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","private_key":"819e80fcd487bf15502fff3d31651efcd9b5e7d5e18ca4d836ce53736bf23d11","name":"node_7a45fa46f161fae3ef9013e9ab81145f4a76fa6ae22160424d6dc111acbd477ce43d4c10db89cb7451c97ea1fbd78428997d01fd17e1851f8b559b404ede6da7","services":["streamer"],"enable_msg_events":true,"port":63005},"up":true}},{"node":{"config":{"id":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","private_key":"c2fff99bd9d70ab2149a1ace8ad0dc26b4b78cbfd60fe9215e0f69885e0cede6","name":"node_07138ce506125910af81bd1bae11c22bfab9a81e1e057cc3d84769475c5da9873eb3f11edc6aca83ef486bfb63eba15a6233676d29d93ac9e774f10cd42c8cbd","services":["streamer"],"enable_msg_events":true,"port":63006},"up":true}},{"node":{"config":{"id":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","private_key":"5d8862df181e186646d6fa8accaceed89b18a384ce5e63de34ecd1bd80d7f0c9","name":"node_f360c6599a0911337c7b96365fda1b2f64890bdb4483bb7e86bca15484f24c4efc0d1f6f56aa0c4fa5c205e6c1dbbf20d2ca3c2f8734f703fe6d672fa76a0d45","services":["streamer"],"enable_msg_events":true,"port":63007},"up":true}},{"node":{"config":{"id":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","private_key":"411b4485e7f793c1db7387d9e8f179d02d939de2702166248953f8f0813cb5f0","name":"node_f5272b71c228eb14b9e0e221deefc0a91353a5f17d01475f57fad54bb8e50e375f58019c7200a9ca45b0f1da6538708c61242e478d917499871df7a9d5857f1a","services":["streamer"],"enable_msg_events":true,"port":63008},"up":true}},{"node":{"config":{"id":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","private_key":"9b1297e565c13eeb81e2b19c31f635253081d34a65eb1ebf889f30635e4eccea","name":"node_e53cfad611bc38a1090d28e4cc58e4738ccaa83a00bf5447cd30ec70e492dea5811b67e79b9ca8856e79801741a675c6f54eb7a1c39e95ab735164855eae0fb7","services":["streamer"],"enable_msg_events":true,"port":63009},"up":true}},{"node":{"config":{"id":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","private_key":"eb698ae5696bf1cef4f4e6cb8ef2eb5e79cd298fcb55e0449bbaab6d048e09b6","name":"node_4f1a219f31e135208bf4caa314a14d8d48a5682941793431539efb5666b06bb5e3e9cb29b019ca414fb32961460556f2d99a04b12dc8ecbf05f43efe108803f5","services":["streamer"],"enable_msg_events":true,"port":63010},"up":true}},{"node":{"config":{"id":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","private_key":"cc474d341e32e674a1c1d607789df8bb6097ab392eace2d366da2496c5413cef","name":"node_25c64a52c298035be2184243082b5eba8a3a5d55c5334cea76e177d722945c8bf014a4ce9ef2ed76dc17a44234c97697337c6e001261533e72cc8266ee0e2fe4","services":["streamer"],"enable_msg_events":true,"port":63011},"up":true}},{"node":{"config":{"id":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","private_key":"4ec4a7d75323558dd822f09ab9f992afd016604bc77aec05f89cfdae6f50611b","name":"node_1691538e4cc41441c18fc92969c0c59f51da063814e8c45311605405284293503ee1570722cc7ae12f9cd63b899afaf5b3e66ca012115996074e8aaa71fda48c","services":["streamer"],"enable_msg_events":true,"port":63012},"up":true}},{"node":{"config":{"id":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","private_key":"b049d01349524a669db50fd817ef70811ea5cb5517adaa016f4ae426184188e8","name":"node_8e1a66c9029330c25b9abe95a11878f41cef1a32b567a931ffa781c2f70a1336efa03ba1a66dac0080304803c1239be443991a251f24d0e9c2e26aebeb5437f8","services":["streamer"],"enable_msg_events":true,"port":63013},"up":true}},{"node":{"config":{"id":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","private_key":"9eb7b1e41bd77e46a9746723ab4367fcdb9950d5f99c32bb1efddc9b5c60daf7","name":"node_c8e9cc707ce2a278371d1b4f64714cdae425b7c3606d18af6588dacaca35c7a171a07629247af351e667d2ddd9e71598f862125c827cc869c463cf87e4daeed0","services":["streamer"],"enable_msg_events":true,"port":63014},"up":true}},{"node":{"config":{"id":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","private_key":"229b6c150e858a0e81d1c720a9697bda4c9f26e531d85db8837ca5d1a24ff8dd","name":"node_43b91c24dd7fd217a76f00ab97920e4223bd2ee085abe7ac34e915e8676400e1643d3bbb4a864c8a6df1298bf229cabd1bdc9879eafdcbcab064708e8266e88d","services":["streamer"],"enable_msg_events":true,"port":63015},"up":true}},{"node":{"config":{"id":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","private_key":"ab42d800bd5b0bcaedd3009d4805e827ca6c41f54fb7fd38cc021f9c72bf3aed","name":"node_14136fa967f2d4825845ba4a43a5921d8fcf03f9c71c5595037e000b2ef6ff0a5eaad0980aea0a170cafda3529f982aea1107f58aa42485550c9480e86f5e9f3","services":["streamer"],"enable_msg_events":true,"port":63016},"up":true}},{"node":{"config":{"id":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","private_key":"15e0330ce9f82833faa08bbacae92d3eff516eeb4bfd1be0b7d8ecc8a311d8a8","name":"node_39d0aa13a6d7e709c9b914cb16f007c3f16af40532afa47c8cf9abf6d604d4380883103c995ec696ca593c4dc9bf0290979b965c9c6ade7c616d3973c5f0b1f0","services":["streamer"],"enable_msg_events":true,"port":63017},"up":true}},{"node":{"config":{"id":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","private_key":"a2ffbdb8b486d91c6d2b579b5ae3f1a8f09feaf0451b375d8985f0ddea952926","name":"node_e73af1e2a834ee132564dd2e983c877b3ae230808d2b42da2ec91472eee6ee6595c439800ce980186b4b0d9a56b96babf747006c07b07513543eead8e102fff7","services":["streamer"],"enable_msg_events":true,"port":63018},"up":true}},{"node":{"config":{"id":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","private_key":"48bdb744f1c9b25e7b2170b88fb956619976670186b82382029c84f3ef780930","name":"node_c0f2f1409cf83d7a777f6af95931181eb5a36b14a156f444075071c896fc5b435638ead23c65a242105db527c809e2c46f7805c862c0eb5d444749ddf22a5060","services":["streamer"],"enable_msg_events":true,"port":63019},"up":true}},{"node":{"config":{"id":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","private_key":"49376794edff5cc56583fc3ce9e6987e0210c537f798bfc00cd523927052bbf2","name":"node_e021950ce89ce2bd79649aad2ed504789636b09870d0652fefa5e16631cb32a5d41c6cc4a540b7a0fca6bc3d5adf9b372a22cf714adc7b3e9b968d4c840017d4","services":["streamer"],"enable_msg_events":true,"port":63020},"up":true}},{"node":{"config":{"id":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","private_key":"b59aef84a0b7166aab7dc4edd8bfc66f56b77097cbbb4e937277ecd23c051473","name":"node_16bd57b6590df0c69c440d178da8359b0a3e00b9c5362155eae42709bdc4d0488e437fa7e8396d5b429cebe356ebd1407039b21eefa8d9164b357845132edb28","services":["streamer"],"enable_msg_events":true,"port":63021},"up":true}},{"node":{"config":{"id":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","private_key":"961cb451a05a1f043539e0417e0c612286d8a86116a4bd3ac4f301444bc0abc7","name":"node_393eb8d2acf9244f1cdc220711c00d8fa7619394893643bc32e1ee0f821e5a2afed07badbdf97d710843c4ea6de3f74c113ad4c548afd23534d6dea5c37c6d9d","services":["streamer"],"enable_msg_events":true,"port":63022},"up":true}},{"node":{"config":{"id":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","private_key":"a56a9d4ff921fba9e03ecffbd71d75f97cc9b7c5f389cf54b9bf66e689bb60b5","name":"node_62b8e67a4ca956c1cf2ba7a538d39bfe8bccf747fe65be48c88270ad44ee7711c0e9a43bb3821feffc492dba9b58397768c755810121add9c980c9a2c696feb0","services":["streamer"],"enable_msg_events":true,"port":63023},"up":true}},{"node":{"config":{"id":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","private_key":"f80db180b4c58031447688bd4b5f9d32cfee3dc85506153782a0368873110317","name":"node_17c7eb5833687a98087daadda564e54b1c770f946efb7efd69370a9caf6e6939e408f04a3fa1aa042d9463992a711786e504072fae56d007d696851696fc5643","services":["streamer"],"enable_msg_events":true,"port":63024},"up":true}},{"node":{"config":{"id":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","private_key":"5750e8b20da0147e055f965d6ba4ee434812f658663383ebfe7e88f13fdf59ab","name":"node_f5efffc8e894cecc065f6892ad2a846c8fc4982d1c8c7fc729421d5108d519c501cc9f2f7a0046ec08d47cf2369753aaf287dfc3ef7ecd34d24d294efb933658","services":["streamer"],"enable_msg_events":true,"port":63025},"up":true}},{"node":{"config":{"id":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","private_key":"f841751579683b856a59eb75f3493a4b3e39183d8818a2638559100bb6f5e66a","name":"node_7c273dd4218e9e5b92e19d250832a424ff2ac5482ad70953746de780100669eb143247e15ccfca14cce9a49a003c82be71ca034a2900bed4c89fb10bdbfcc7c3","services":["streamer"],"enable_msg_events":true,"port":63026},"up":true}},{"node":{"config":{"id":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","private_key":"be9f2207e4e7a93758129c0d6fa34877b685210cf0e8f8d233e5425d8fa461f9","name":"node_8959c5cf825ebab14efeacf2807ad9498256a9e89a2ef00690c9ee23a3e934e111c52a5ddcc791b93f49424ac008095d8cb0da6905dfdeb62309fc4f6672e59e","services":["streamer"],"enable_msg_events":true,"port":63027},"up":true}},{"node":{"config":{"id":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","private_key":"4a245ec64e442d4cad2468d96914df5728633c568ed3d063990ac8932be63222","name":"node_dcf2401cbc26f3db27bb85c24984b1d755b3503fe400c139a0bedbe5de24db3f27c8f4f40adc1880b6142d20e67a40f3d45d36ba7fce122ffa44703e65622198","services":["streamer"],"enable_msg_events":true,"port":63028},"up":true}},{"node":{"config":{"id":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","private_key":"1771927f1f06912915f5498e857816fd8f73b2bde10f88ba4a856684bcc2a6fa","name":"node_38b3adde25c6407f29c2a721f1f5c082cc94ddad09fc5afda2bbb2309212a9b54b1553731a65ec8b58769fc11d488169c8000ee15fe8966bd44a3879e0c9e534","services":["streamer"],"enable_msg_events":true,"port":63029},"up":true}},{"node":{"config":{"id":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","private_key":"986bc0252067c4c3ace80099cbc843d6f16f7483719e9ecf7a3a0f876a461ee8","name":"node_6593097e880701f3d0573df7bff9ba7af40f4f83b828bfc11bdabea62fb94ed39c8233d8d40275c2af9ceddae44514e029a546fe9df73abbd3821d37933aba49","services":["streamer"],"enable_msg_events":true,"port":63030},"up":true}},{"node":{"config":{"id":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","private_key":"39848c3aa21a67751f95ffc8938b36264eeee342816d41b37816f2164e59858e","name":"node_578666c4113e196a7c738fdbae0bd68ade450283eb835efd06591798f1893f7f7d9cde0691faff670b5ae24e58cbc2f549d2196f244dddc00e82852c38e8539e","services":["streamer"],"enable_msg_events":true,"port":63031},"up":true}},{"node":{"config":{"id":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","private_key":"d5dee04f1435fa7ab6d65e89de8c4c6bf156111bfb9ee5de0ab617cc3be19681","name":"node_e1082b4577aa370a5171b7602282208697dcead854f0c82acb5628d179fa5990a0fc85c5343a47177aab81c7fa6c1be8a27a3484acddc353582ddeb61892ef94","services":["streamer"],"enable_msg_events":true,"port":63032},"up":true}},{"node":{"config":{"id":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","private_key":"044a1acc0d565f7080db7b625baefe8a5f7aef9009a7bcd338fc31a02d704d8c","name":"node_a4fbd2ffc25d2c3bd37beecd637dda5983cb5817ecb6da62aec16ea59aaf7e71966649211461564ba808174361898a1d2265f1a42e94434bc00d5d3e04b67a8a","services":["streamer"],"enable_msg_events":true,"port":63033},"up":true}},{"node":{"config":{"id":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","private_key":"8be74288552caed392476d39780f806f2c21b50a9990c5a3a5ed37397b218a6d","name":"node_eb08a7774ca5252237d059a8bbad68044c83b2c332024be98bdc0c58508867a80cd34cb4162bd55a47fecc93301c8b2a7a1edbfd807ebb5623499cac80ea42de","services":["streamer"],"enable_msg_events":true,"port":63034},"up":true}},{"node":{"config":{"id":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","private_key":"e644c54ce52ddb2788fc683264f175a24485082eb88ebe0a83c94ecce77d7175","name":"node_6eeb951b8f6d5ac519132910222777d5a409325e6c64d89708a00e55cb0fe85889aac1baa724e29fa7f064323b164a9c40c5114a65736e3dd16f0336283d9c7b","services":["streamer"],"enable_msg_events":true,"port":63035},"up":true}},{"node":{"config":{"id":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","private_key":"77445377572b915c2e3802f70fc9eae8d29e767f54f80a29701ae5d1fe0c8677","name":"node_6419279b600da3e2ee8d0b2a5b0319bc6cd496086955b49a8d2168fd4c35d5688291bc9313076b1b8e070f25dc593788d72b8f8c1d2ad828741a45deea35e58d","services":["streamer"],"enable_msg_events":true,"port":63036},"up":true}},{"node":{"config":{"id":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","private_key":"f6b20f29a1cdcad8f8bd88acc4f6ffba7b3027e46ab60784e2c2b77edb3d3630","name":"node_032b1ce6881413b7ade1918e56691c7acd9f24111f47792ca50c33e570afba433caa132ad2326d03f9c0544fdc09fa0ca65f61de9fe61d6dd92c5d25a8df69af","services":["streamer"],"enable_msg_events":true,"port":63037},"up":true}},{"node":{"config":{"id":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","private_key":"25bb03224302b9c89585681c4bb30dc9d95fe417e5c0f13627154083cda7492b","name":"node_86d55ece15e6bb4da7601f6587654505f760ee2b87abdb115091eefa93f61cf29fd695601bb8c6ae2c76400de24b8bca9ca32b50e4b849ae76f5320b03276bfc","services":["streamer"],"enable_msg_events":true,"port":63038},"up":true}},{"node":{"config":{"id":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","private_key":"a4eb160b838f392946a844b9fbc36006c459ff6f9ef46a832d000f17f2aa834c","name":"node_31cbd7c029d69715e59f31bccf362cd76e0a87839f1f63c6623be437d2af227a38f12c5fb9c659cc543976833caf22a52f5191c7c465a9ba36ac4235c12add72","services":["streamer"],"enable_msg_events":true,"port":63039},"up":true}}],"conns":[{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","other":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","up":true},{"one":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","other":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","up":true},{"one":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","up":true},{"one":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","other":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","up":true},{"one":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","other":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","up":true},{"one":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","other":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","up":true},{"one":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","other":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","up":true},{"one":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","up":true},{"one":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","other":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","up":true},{"one":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","other":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","up":true},{"one":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","other":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","up":true},{"one":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","other":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","up":true},{"one":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","other":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","up":true},{"one":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","other":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","other":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","up":true},{"one":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","other":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","other":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","up":true},{"one":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","other":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","up":true},{"one":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","other":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","up":true},{"one":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","other":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","up":true},{"one":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","other":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","up":true},{"one":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","other":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","up":true},{"one":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","other":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","up":true},{"one":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","other":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","other":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","up":true},{"one":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","other":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","other":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","up":true},{"one":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","other":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","up":true},{"one":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","other":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","up":true},{"one":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","other":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","up":true},{"one":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","other":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","up":true},{"one":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","up":true},{"one":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","other":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","up":true},{"one":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","other":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","up":true},{"one":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","other":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","up":true},{"one":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","other":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","up":true},{"one":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","other":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","up":true},{"one":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","up":true},{"one":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","up":true},{"one":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","up":true},{"one":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","up":true},{"one":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","other":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","up":true},{"one":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","up":true},{"one":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","other":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","up":true},{"one":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","other":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","up":true},{"one":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","other":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","up":true},{"one":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","other":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","up":true},{"one":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","up":true},{"one":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","other":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","other":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","up":true},{"one":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","up":true},{"one":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","other":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","up":true},{"one":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","other":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","up":true},{"one":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","other":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","up":true},{"one":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","up":true},{"one":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","up":true},{"one":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","other":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","up":true},{"one":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","up":true},{"one":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","other":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","up":true},{"one":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","other":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","up":true},{"one":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","other":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","up":true},{"one":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","other":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","up":true},{"one":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","other":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","other":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","up":true},{"one":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","other":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","up":true},{"one":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","other":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","up":true},{"one":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","other":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","up":true},{"one":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","other":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","up":true},{"one":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","up":true},{"one":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","other":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","other":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","up":true},{"one":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","other":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","up":true},{"one":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","other":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","up":true},{"one":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","other":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","up":true},{"one":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","other":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","up":true},{"one":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","other":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","up":true},{"one":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","up":true},{"one":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","other":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","up":true},{"one":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","other":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","up":true},{"one":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","other":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","up":true},{"one":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","other":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","up":true},{"one":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","up":true},{"one":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","other":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","other":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","up":true},{"one":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","up":true},{"one":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","other":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","other":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","up":true},{"one":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","other":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","up":true},{"one":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","up":true},{"one":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","other":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","up":true},{"one":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"9f2d72c6e30ec363bdcf9ecf28fcf5553f98357680d8530581fcd815389005ec","other":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","up":true},{"one":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","other":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","up":true},{"one":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","other":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","up":true},{"one":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","up":true},{"one":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","other":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","up":true},{"one":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","up":true},{"one":"66230e0bec41cfcf3667d7ddc7312888ae4887e8430c57dedafcdbadb6c12364","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","other":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","up":true},{"one":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","other":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","up":true},{"one":"72f779e91460990aee45e99b0565246a2620d4939cc3ab0fe021fefe71aae761","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","other":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","up":true},{"one":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","other":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","up":true},{"one":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","other":"634c2562544e0979530cc4dba918c849f24f85c87813e592c54e1f6d8d73bb6f","up":true},{"one":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","up":true},{"one":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","other":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","up":true},{"one":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","other":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","other":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"83870b048b374ed527d4b25256900d4b53fad11d900b54e366f9e3fe7ae50079","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"56ac3ac4cc04e94c93d986a0ed9da8b68d97f13c8b5ec35d56703592fc05bc43","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","other":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","up":true},{"one":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"d8d872ef5b1632eabca51f1d2755fa5a3f16dc487d4d8be960930ee4462a2633","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","other":"dbc536e11d371786bf8c61eec755d2cb22242c27e8edd7985dae612a9d2cac05","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","up":true},{"one":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"3c93b64143bf1bf130545806917472f3ca16ad6f223f0388f445ddc353140042","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","other":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"1087495bf04e6967257f84b8e5de084e2000b9d748216e31c9f33fc9caedb715","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","up":true},{"one":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","other":"b4bee8054b3b7bc3ef0748937602699173983a764814e85f173916fd70f1e3ed","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"9ecf217e2076c229f6d15bfe29df85aa129f1fb12d2a8307907327b5fe2f80c5","up":true},{"one":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","other":"544ad921e03de7d1d656038e23452dd3a9c7ef041520f17f8318326ecc58683b","up":true},{"one":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","other":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","up":true},{"one":"29077dd2f4869b69ffc3ed40e82e4ef051292c3461888b5faf7b4c4b14d4928f","other":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","up":true},{"one":"c0f0bec8a3506280df599d57abc414d007696967381b9690bcf63a093586307c","other":"df9ad5c2cd2375a5a227841841a47876765f6552a8b2cb9fa8cdedaeca2371ed","up":true},{"one":"a070c42951b523531f065cb8376eb8ca0c431b473ce9ebc44a3fc383f1f878b3","other":"be6906254ba2d3748ff8ce2ebbabaa03bad1c92d2eadc1ab6470548cb8d7c524","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"d10e58907f84eef0dfcfd3c81457b60eef9b1ea5b9a462e22f0c4e643a6e7140","up":true},{"one":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","other":"f03f47bf8f6241cbda878f301783e30cac333e8cea3d6bf9bc2be3b7fc2cf1c3","up":true},{"one":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","other":"6c4bdfe4650525d5efc1a4ca8d92ebbea33b1877bfac69656e81adbbad4f286a","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","up":true},{"one":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","other":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"30d80772ad22d78f8a4e948a06677b5676aadb8a9c040f3ffb59a7e608e0929e","other":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","up":true},{"one":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","other":"61c24980b9ef4ee7fc33c51310f981a8e74e4276509a545a3f471370082dab4b","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"51db0d8fefeedfab3394f8f398b6d8f4540b24bc6cbd8e66bc5a7480db0228f5","other":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"f066d5d314253a872ab27df90d85ba5824da06032f92ce8bf20020b61971e199","up":true},{"one":"ada8540c63062347d3162850cf2a4820a20ed96514fb01b95d995bbfff97a212","other":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","up":true},{"one":"be9f880ccfd8dd0f5fde587c4e9fbdcb2d3551df0c4504d9938d4301a9276e72","other":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","up":true},{"one":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"9dc2c4166fa9410d7be67cbb5ac572aa42a9a78c2efe5ea601ddd37c356196da","up":true},{"one":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","other":"1abcab4e898966c42c11d1a92b1c1911fc779089c5a20ea1ddf005f76632b171","up":true},{"one":"de9eff7b7b80323f544746b9596e7da6b43b91e6c6d0660ad38df1e877ab8f99","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","other":"f0ee0274e24a7cc3d1b0d38cd46d205ccbf791d0cc038d022f2a0c50ae6a5cd5","up":true},{"one":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","other":"1be4ba2f068e060a0aabac445094f1dc8b22fe1e5575c98df8d8783aa3d95177","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","up":true},{"one":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","other":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"5d056a38c3a7c3bfcd431b767662903454f41429d2e03b9b30273e5b1b8e5c97","up":true},{"one":"ce614a2fd326ce57b0ead5750d0a08f3c7dd94e1d2935861697e3df4652a22b6","other":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","up":true},{"one":"358eef3cf9964bf89e056afe0f4b46ce85bcb079bab922a4ae9dfa555001abfc","other":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"14645ab9b2ebbf4436466df07ff28e68b92774c6b5a0d311a174765e350c7089","up":true},{"one":"dfe389ee7fe03c809d7a4afa1f04dde9ab9a50d8c6ca5bf2489debb2e8329541","other":"fbbe14109dc4fa8251e852a181f3663b4245c93b737fa9c4921a53ed9949019d","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"36c28c0237be6b2131280452c3113affcae28f6c7066811a8e1ee1a0a01decc3","up":true},{"one":"3ff43d13b6ee84b128db4215c47c73909f6616039b87ca70abdd2108e29dddfb","other":"3ea2554db02021f0413529426d7a7b0ac9abe80643993f6d80fdfff93a765c40","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"e3c20117761e1b3c3d7c3d133e1bf68e594ee25950cd4311a8d964923c4164da","up":true},{"one":"332f7b60a1fbb6cd1e251dc68d1093b7f0bb05c1eefce5e61f124dff9445f14d","other":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"77687d9e478a52555674f12aa654ad931a3ee83920b9cdc8fecc03653ed7e386","up":true},{"one":"68d45eec895b91f081026e86ed164092dad8d4087918cd50c6f77767d9577f6d","other":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"23e4f18d302b6a545530b89eca007c141c751cdcde471bc3378bf72fd68b91c6","up":true},{"one":"cfa6cfc1f856e69430370d5c52130519502c7a9e4fb14c7c8d9b309612a3c1bb","other":"c678643c5249eb90385aad201d6756f9f364024938d4c9f59f4aa51d64d48bd7","up":true},{"one":"37debce0cbe19a2ab88f15dffa390df392938e7060970b93eae968a8c2497650","other":"2f4492429ab2ecd080a36451153990587de2458ebd9421fb989d8e27d4a88422","up":true},{"one":"c6c479f1c83f5158eb77d57e6321d5ed062964870775f51254461010c8882c10","other":"e5eea2a0ac0175a0ad41239d8e36e537ce7d428d6b44e23e8e33ff0be11bac72","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"5cdc4493f01d6ebec3070b028275bd94ede61db21a4f5d3b282a366d1d3484b8","up":true},{"one":"44b1544b5795a1c77094832bae47c84eb38482b1e1aaefbaecacbc7ef9d10e3e","other":"577b9ea47bc00cde25b11ca03861df0ccfaad8ce281500efede88d25e012b1e3","up":true},{"one":"7a56b4203ee1cad781b23d2a78694f63eb7dfe6d9ac24fc181e6a63516c9efa5","other":"0d48477e33d7cfc4a7660048e4b1ece9f37e9759e96e6f1f47a86de091b0ee97","up":true},{"one":"3c38aba43a15a61b680fa767353cce7e4165cbc996968f990001d7595ff243c8","other":"2d831f78c7d670e4e1f19a47c80ec2df144da210ff3aaa00ca6c4990e4da0922","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"5c3ca7f91551934bbfa4020433d7b19e40d04d9291c2b26686ef85225f872bbf","up":true},{"one":"43900b2a084097a0ddf8bf4d0375624f731bd14c85300007c87269986a12eb3b","other":"bfa0a02816da29b40215fb3c26de9360505e4c69fca55086324f0e35de7486a5","up":false},{"one":"7a1f03dc26ef21a5bd1673eb8418af7a7cbcb2ab1654882ebdcda2d1e6ad4836","other":"76933265c3d872b2d20e7a961f3f4e858afe11aee773b5caf678553e56ad3537","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","name":"node_33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","enode":"enode://189f684252bf3145e01947ecea3430ca79da66c9c79baba0c7afac7577fd8eb6cc663b270219bf730d98b9221eaea5dfeaf64c3a0097aba12ccc9bd2fea77174@127.0.0.1:0","enr":"0xf88fb8409210a452686c812613891a7481ab1ecb134964d862f61460027f50b5b112d39a256f7cd8dc529b01f133a7fb15be96b7a8ee77dcb92f1c3e39cb0d2cd3af09830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102189f684252bf3145e01947ecea3430ca79da66c9c79baba0c7afac7577fd8eb6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"M/5taXBpDo2eKwj/I0yx6vM2uqU7OYURzQeNzOLIsto=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 33fe6d\npopulation: 26 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c05d c67d c62e ff06 | 35 ce82 (0) c851 (0) c34b (0) c05d (0)\n001 8 5bf6 4e4e 4853 4443 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 5 0e8f 041c 10d5 1a93 | 8 10d5 (0) 12b8 (0) 1a93 (0) 1dd4 (0)\n============ DEPTH: 3 ==========================================\n003 5 2f1a 2b80 2b79 27c2 | 5 2293 (0) 27c2 (0) 2f1a (0) 2b79 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","private_key":"58cdd771550771fd62cd26564dda083ef20e140c1d5530cd86a85b7df1f7f269","name":"node_33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","services":["streamer"],"enable_msg_events":true,"port":45167},"up":true}},{"node":{"info":{"id":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","name":"node_b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","enode":"enode://b91f0615ca78edb614985f7643eeb09bdc0476aa30b73d0b711f87d59eaf466246423fc97d81dbd96192287bf373174ed814b96413bfcd872d4ccd53d3c4841c@127.0.0.1:0","enr":"0xf88fb8405b40eaf3f4b6452b70caa681969bd278b3912b26df53438d01543d219a38254e1ea4b61d25c38733700b16acb82ee9c22c26a62e9d21bbac2e105c734fd985ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b91f0615ca78edb614985f7643eeb09bdc0476aa30b73d0b711f87d59eaf4662","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sml6Py3m6g0TWGplVGN4JQlpHW8F2Q9F/QiCPn6vWgs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2697a\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6049 46af 5b93 33fe | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 4 ec08 c034 c67d c62e | 21 ce82 (0) c851 (0) c34b (0) c05d (0)\n002 2 83aa 8934 | 6 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n003 4 a259 ab25 aeff adfd | 4 a259 (0) aeff (0) adfd (0) ab25 (0)\n============ DEPTH: 4 ==========================================\n004 3 bbbc bc3e be5d | 3 be5d (0) bc3e (0) bbbc (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","private_key":"f7d4ee33924c6fecc03e8531d4a760dfa3f045c2070ead81351cc717118b94c4","name":"node_b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","services":["streamer"],"enable_msg_events":true,"port":45247},"up":true}},{"node":{"info":{"id":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","name":"node_8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","enode":"enode://594fd2ab5b614c45fcf39e323750e1d17a2f4054d8a9939c433993f5050e3990638006f044b8fe5f095108e0df4bb507375ddde04c9973283856f126fc553237@127.0.0.1:0","enr":"0xf88fb840c50ff8109fb29d7550e93a6b0c1e4411d83ff6d612cef057b29b0fe5d8f7fa193cc9d16dec8587e4b27c4cdc32c7304cf80b7c32087c779c819970be16ba18830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103594fd2ab5b614c45fcf39e323750e1d17a2f4054d8a9939c433993f5050e3990","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iTTua7/JyRKlpfsATrPfC2UxPiLozrjcPz4T0QhTIo8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8934ee\npopulation: 27 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0e8f 1dd4 2b79 27c2 | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 9 f16d fef2 ec3e e59a | 21 ce82 (0) c851 (0) c34b (0) c05d (0)\n002 5 aeff adfd ab25 be5d | 8 a259 (0) aeff (0) adfd (0) ab25 (0)\n003 3 9637 9009 9861 | 3 9861 (0) 9009 (0) 9637 (0)\n============ DEPTH: 4 ==========================================\n004 1 83aa | 1 83aa (0)\n005 1 8cb7 | 1 8cb7 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","private_key":"c1a5ff4b52beb6e91e007799d9b94a2afe91ad74a387ea3de8ae5a1b3daddcc0","name":"node_8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","services":["streamer"],"enable_msg_events":true,"port":35697},"up":true}},{"node":{"info":{"id":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","name":"node_4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","enode":"enode://426b52190ebc9cfa8e1d426d495ed10688ea702182bb347c25a37f362f2fc457df723fbafc48abbfcfb00d71ed2fb35bc642ea3fe52cf099a2513006165fa780@127.0.0.1:0","enr":"0xf88fb840f9687dee63db3d7523fc5e5345328e7d01d34286124dfb1d8565aebf86f3f2fb5c22b30d3c61ac8c8a3692d3c5dd1b4702c24da65bcd3c9e06c35e9eef56e5ed0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102426b52190ebc9cfa8e1d426d495ed10688ea702182bb347c25a37f362f2fc457","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"REOzSXCSyfIA/n1DwypTP4/J+nEpIm4eLH/V9/J+FxE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4443b3\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ce82 8934 | 35 ce82 (0) c851 (0) c34b (0) c05d (0)\n001 3 33fe 2293 2b80 | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 2 6271 62c0 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 2 55a2 5bf6 | 4 55a2 (0) 5b87 (0) 5b93 (0) 5bf6 (0)\n004 2 4853 4e4e | 2 4e4e (0) 4853 (0)\n005 1 404b | 1 404b (0)\n============ DEPTH: 6 ==========================================\n006 1 46af | 1 46af (0)\n007 1 4541 | 1 4541 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","private_key":"1fdc1683e025dbb4aabcc2b580cac31c8d7bd3862f5eaa0786c55ba1d5fe2e3a","name":"node_4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","services":["streamer"],"enable_msg_events":true,"port":35969},"up":true}},{"node":{"info":{"id":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","name":"node_5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","enode":"enode://d7953737b7f648f15413610ae2e027887e3ac47d3a49ff0c53b5813d980758bf1d3f12e711e824d7948bc24e2ba00d5558fccb7155232570ecd58236c2aa35ff@127.0.0.1:0","enr":"0xf88fb840f2731673fc9ef09cb16f3be083528cdc666e5d0e3ad5a8473aeda9cca202c5683d9af6f21212e6f6711983b993e9bcddb6b061addbacabed0e1ae01fd8061f9c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d7953737b7f648f15413610ae2e027887e3ac47d3a49ff0c53b5813d980758bf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W/ai/kgUErGyDwzCMloRGf2p40xN7z0fQCaojcDJkqw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5bf6a2\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d165 adfd bbbc | 35 d165 (0) dbef (0) d87b (0) dd48 (0)\n001 3 33fe 2293 2b80 | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 3 62c0 6049 75bf | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 5 4853 4e4e 404b 4541 | 6 4e4e (0) 4853 (0) 404b (0) 46af (0)\n004 1 55a2 | 1 55a2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 2 5b93 5b87 | 2 5b87 (0) 5b93 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","private_key":"fa8bc1f234fa77f91ac5a9338da6e6f227e45a18646baf568d4d6dfd6d1450ac","name":"node_5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","services":["streamer"],"enable_msg_events":true,"port":38467},"up":true}},{"node":{"info":{"id":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","name":"node_bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","enode":"enode://cc1d8b904cb61eeebf263eab856b6a39494abcc5f24a872d894cebb307123b3c21d4ad23093725c55431ea19b33f656d149a1546c5f4160410c2f15a3b8e96f0@127.0.0.1:0","enr":"0xf88fb840055d7f85d85a26105bc7165f2a6b6f5d76cdd64185015fc469f27b2f031c50ff47437f48acadbc971a934d387191f68159ab7cbbfcd0e9eadfffc11d84ba76150183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cc1d8b904cb61eeebf263eab856b6a39494abcc5f24a872d894cebb307123b3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"u7zMAYD+JgW+dI2uq7H8AubIhws383E1nzjuEU8Jdx8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bbbccc\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7a5c 46af 5bf6 | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 3 ec08 c034 d165 | 21 d165 (0) d87b (0) dbef (0) dd48 (0)\n002 2 9861 9637 | 6 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n003 3 aeff adfd a259 | 4 a259 (0) adfd (0) aeff (0) ab25 (0)\n004 1 b269 | 1 b269 (0)\n============ DEPTH: 5 ==========================================\n005 2 bc3e be5d | 2 bc3e (0) be5d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","private_key":"8e11dcf297e93d5064f7c16e21897f433b43b84640233484bdcb47c2986f8804","name":"node_bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","services":["streamer"],"enable_msg_events":true,"port":39121},"up":true}},{"node":{"info":{"id":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","name":"node_7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","enode":"enode://4aab8f1241e23af8e2dd0e60b55405d53a91654a387bd7cf812ae58bcd9d4a0402a8f608c6e0db8c43437c367f31326f3820f08d7afed4ee75622a2f05b37eaa@127.0.0.1:0","enr":"0xf88fb84038eea6fad2a04f841af87c2daf250d05a7047b23a61c49705e63401965b90bb16420d5734fe9622caa7b9e22f7c11e69f5c992a8d326d6f7addef874754fc92a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024aab8f1241e23af8e2dd0e60b55405d53a91654a387bd7cf812ae58bcd9d4a04","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"elxEaT3iCtw8U7EwL7AKqzKkYmWrx1Y726M/flxPnXQ=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7a5c44\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 d87b dbef c34b ec3e | 35 d165 (0) d87b (0) dbef (0) dd48 (0)\n001 5 10d5 041c 2b79 2293 | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 4 46af 4853 4e4e 5b93 | 10 4e4e (0) 4853 (0) 404b (0) 46af (0)\n============ DEPTH: 3 ==========================================\n003 3 62c0 6271 6049 | 3 6049 (0) 62c0 (0) 6271 (0)\n004 1 75bf | 1 75bf (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","private_key":"d779095ed5a31b33c8a0b0b0198e6417edf79f53b2a14a0eb5eb1e1e7369f12e","name":"node_7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","services":["streamer"],"enable_msg_events":true,"port":35791},"up":true}},{"node":{"info":{"id":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","name":"node_f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","enode":"enode://5901c788ea558d95661b2e50b68ca1e5e3c79c6293c1bcc73361993fa647db34891c6bc5d5952c43bc105ee6eb5d115a6eef3f26c87229b10777f2d86b12f587@127.0.0.1:0","enr":"0xf88fb840288340dcdbed401c8ce3bde43d0216d5df3e47dcc1c7d7d0a0d0ca4cc681176764d55a2920e5817f97fae70545a30a44acbfc65d43eb435f829b28d2655444590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035901c788ea558d95661b2e50b68ca1e5e3c79c6293c1bcc73361993fa647db34","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9vMY4lokxEnnJ8YMYQcZqqNtC6+CajpJMa1oSr+by7o=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f6f318\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2f1a 404b 6271 7a5c | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 2 a259 ab25 | 14 a259 (0) adfd (0) aeff (0) ab25 (0)\n002 2 c67d dd48 | 12 d165 (0) dbef (0) d87b (0) dd48 (0)\n003 2 ec08 ec3e | 3 e59a (0) ec3e (0) ec08 (0)\n004 2 ff06 fef2 | 2 fef2 (0) ff06 (0)\n============ DEPTH: 5 ==========================================\n005 3 f090 f16d f1e1 | 3 f1e1 (0) f16d (0) f090 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","private_key":"4d482c4424098c2a71c88f47c73227e568fcab0f63d5a6a716f3e716773f19b4","name":"node_f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","services":["streamer"],"enable_msg_events":true,"port":45669},"up":true}},{"node":{"info":{"id":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","name":"node_627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","enode":"enode://2ee80aae24fb663157cb638843b9fb21700a01f5ea5dcec4c69214f2b80eec02717985080fed1618333c85522a39caf9a7ba76b52ba0f480ff3ebb8186f5a69c@127.0.0.1:0","enr":"0xf88fb840fa1436482f2747ab816902e843a51484a4cbc4152e7ec2ad801cae3ded5c889236cca1756f6f103cc630767f9ff82a3a2f4e736ea92418c62499f129946c4bbb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022ee80aae24fb663157cb638843b9fb21700a01f5ea5dcec4c69214f2b80eec02","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YnEFlXqgtYepuhsPJz/BlAO2lVlA55SjWa3onNfUDfs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 627105\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 de4f c62e f6f3 | 35 a259 (0) adfd (0) aeff (0) ab25 (0)\n001 3 1a93 27c2 33fe | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 3 4443 55a2 5b87 | 10 55a2 (0) 5b87 (0) 5b93 (0) 5bf6 (0)\n003 2 75bf 7a5c | 2 75bf (0) 7a5c (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 6049 | 1 6049 (0)\n007 0 | 0\n008 1 62c0 | 1 62c0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","private_key":"23966103833d36e192d35e9cfe2670b5319f5499072ede1f11cedd9024940533","name":"node_627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","services":["streamer"],"enable_msg_events":true,"port":32927},"up":true}},{"node":{"info":{"id":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","name":"node_c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","enode":"enode://a5b7729faa9896d27289883c8cec64d7eb741cd7cb745f93db938d30ad11655e5e6d8db4b9a81aba84c7112ea14816c7726c946678e0554b909627c400069fce@127.0.0.1:0","enr":"0xf88fb840e2e531e37debff2425fab0e7db5ecc75f9746078803605fb200a96a2a92984c5671e0f4b88fc7cdc89c9c09b97f9ef3f5a97d6a1be898e5e0594bf71e977c1280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a5b7729faa9896d27289883c8cec64d7eb741cd7cb745f93db938d30ad11655e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xi5LIwLNYvV4yMZHrcOkr/7232WlI2MChl24WJfvwBU=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c62e4b\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2293 33fe 4853 6271 | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 3 b269 8934 9637 | 14 a259 (0) adfd (0) aeff (0) ab25 (0)\n002 4 f1e1 e59a ec3e ec08 | 9 e59a (0) ec3e (0) ec08 (0) fef2 (0)\n003 2 d87b dbef | 5 d87b (0) dbef (0) dd48 (0) de4f (0)\n004 2 ce82 c851 | 2 c851 (0) ce82 (0)\n============ DEPTH: 5 ==========================================\n005 3 c034 c05d c34b | 3 c34b (0) c05d (0) c034 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 c67d | 1 c67d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","private_key":"d56adf646d4edd18118697876a2b6c8f969d89f806dd57944e91d7ea8678c854","name":"node_c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","services":["streamer"],"enable_msg_events":true,"port":42935},"up":true}},{"node":{"info":{"id":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","name":"node_9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","enode":"enode://b2038dcdc21c0342ed4add7724ca7f5c70acbda4803e675e7a927cddf0d0acd0f8c470e2424aed644fe6369b849182c846e00a92c6ccb376fe303c1a46818595@127.0.0.1:0","enr":"0xf88fb840198e6a345712a2e48389ef9eb36c43f88bb2b34aa5711694ec4d386a7517b5cf5223d928910d5887731c99bcc03fcf179cb74267e67df478cae4059bab7e31740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b2038dcdc21c0342ed4add7724ca7f5c70acbda4803e675e7a927cddf0d0acd0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ljf6XsgL1ASjZv6G96iaVzUpgzCXwTARSzAVdUiGVF0=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9637fa\npopulation: 12 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 55a2 2b80 0f03 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 2 ce82 c62e | 21 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n002 2 a259 bbbc | 8 b269 (0) bc3e (0) be5d (0) bbbc (0)\n003 3 83aa 8cb7 8934 | 3 8cb7 (0) 8934 (0) 83aa (0)\n============ DEPTH: 4 ==========================================\n004 1 9861 | 1 9861 (0)\n005 1 9009 | 1 9009 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","private_key":"6cb0afbaa74888bcc3ca1555cc1235945258f49c75828c56a9e5c4d47637bbc2","name":"node_9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","services":["streamer"],"enable_msg_events":true,"port":41485},"up":true}},{"node":{"info":{"id":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","name":"node_0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","enode":"enode://287e97ae6cca5147329515ea229510ab6fbbed836fcf6267080988eb4521ca19fca56a67c19b8cdcc1818525d01765fdfa986478d2d22e10dc38f511bf9f66c1@127.0.0.1:0","enr":"0xf88fb8400a5646e83f67d36a442e286b23ed0eb1938e670917068d01ce00c8b6a1a44f471b7807fd83e22f4eb89c4398eeae14885b253e135d5d201bea3b4af9af1c89240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103287e97ae6cca5147329515ea229510ab6fbbed836fcf6267080988eb4521ca19","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DwOlu1HD9ZlGnP6eXaChC40GulAaieGAB3p18cWXFGc=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0f03a5\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8cb7 9637 | 35 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n001 3 62c0 6049 404b | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 2b80 27c2 2293 | 6 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n003 4 12b8 10d5 1a93 1dd4 | 4 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n004 1 041c | 1 041c (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 0d7f | 1 0d7f (0)\n007 1 0e8f | 1 0e8f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","private_key":"f3151faafed66691b7c7fe654fb8b3e32de80b36c07bfaf63b9ce5d571749b79","name":"node_0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","services":["streamer"],"enable_msg_events":true,"port":38513},"up":true}},{"node":{"info":{"id":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","name":"node_404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","enode":"enode://35c2c08791cc1c705a6126041e3383cba8baf51922829224bd290662116349bb20ac4774bbbeca9adf7266b8731664ad8255a17469fde0fdeffc60b1287b0b5a@127.0.0.1:0","enr":"0xf88fb840f7059937b3fb094126531a32fa1c349cd67da70cefdb5158e95ef285d03af1ec44ff0691cbeb5bc2a09af995303f9a5a61923166d8f92f1811559758e6c8be700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10235c2c08791cc1c705a6126041e3383cba8baf51922829224bd290662116349bb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QEtwxqxylyz9nnzxFcfwQ70V0OS5qVm/wpJMci63Evc=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 404b70\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f090 f6f3 ff06 | 35 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n001 2 2f1a 0f03 | 14 33fe (0) 2293 (0) 27c2 (0) 2b80 (0)\n002 2 62c0 6049 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 3 55a2 5bf6 5b93 | 4 55a2 (0) 5bf6 (0) 5b87 (0) 5b93 (0)\n004 2 4853 4e4e | 2 4e4e (0) 4853 (0)\n============ DEPTH: 5 ==========================================\n005 3 46af 4541 4443 | 3 46af (0) 4443 (0) 4541 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","private_key":"39ac08b99ed5a6af6a54d2ac5321be553f9143d2695a8505e15e42661d1e037e","name":"node_404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","services":["streamer"],"enable_msg_events":true,"port":40259},"up":true}},{"node":{"info":{"id":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","name":"node_2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","enode":"enode://13799436c7d312b56cc9e0e3efc7a244cd310752235ed2d531f3756fb4c329b8f4beed1ae628979c46857255291e4a89eca3d777309d735ccd52a1fd086eb37a@127.0.0.1:0","enr":"0xf88fb840a18583a1a4a283a6cb8ec25c1bf4c3f964e23314193307d2b5cb271cde21b81b48c60cf629544c76de4d3e4616a1311dfc70306df454ce056bfa7231738b81580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10213799436c7d312b56cc9e0e3efc7a244cd310752235ed2d531f3756fb4c329b8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LxoVw5vLDpU/jBYJM/aePdopuDRXV0LE9DLrOExd2d8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2f1a15\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f090 f6f3 ab25 | 35 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n001 4 62c0 6049 4853 404b | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 1dd4 1a93 12b8 | 8 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n003 1 33fe | 1 33fe (0)\n004 2 27c2 2293 | 2 2293 (0) 27c2 (0)\n============ DEPTH: 5 ==========================================\n005 2 2b79 2b80 | 2 2b80 (0) 2b79 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","private_key":"edc9fc2f574b8ae4c0f349dcfca0fb04cfdf47fc9405889b34be78c770fc4acf","name":"node_2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","services":["streamer"],"enable_msg_events":true,"port":45277},"up":true}},{"node":{"info":{"id":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","name":"node_ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","enode":"enode://d7dddfa4efbb58706320eaf3223ec745504d5d8d4b2bc5385b5dc670985287398ee138b1cb976bc08fe72de2b0b59452a0194bce9614f4df7c5e9faf58ef85d4@127.0.0.1:0","enr":"0xf88fb840d1e80f4b38afbcd783a882fe818fc87a0fc6df4a9e49d2d21e51e3494648bf771a06c6b548b8e2242ea69ad4c3677834df3e83510ddc5010347390435467866d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d7dddfa4efbb58706320eaf3223ec745504d5d8d4b2bc5385b5dc67098528739","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qyVcQOObqP0vtDn/JtE1qrOUT7kVnlQ3D0/nNZBtAxM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ab255c\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 041c 2f1a | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 dd48 f090 f6f3 | 21 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n002 2 8cb7 8934 | 6 8934 (0) 8cb7 (0) 83aa (0) 9009 (0)\n003 3 b269 be5d bc3e | 4 b269 (0) bc3e (0) be5d (0) bbbc (0)\n004 1 a259 | 1 a259 (0)\n============ DEPTH: 5 ==========================================\n005 2 aeff adfd | 2 adfd (0) aeff (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","private_key":"e097903ff73cba0125e376909f8f08ea09638c36b5e540c8b86d2c0370445bf7","name":"node_ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","services":["streamer"],"enable_msg_events":true,"port":40173},"up":true}},{"node":{"info":{"id":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","name":"node_041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","enode":"enode://bf082dde14615af13c8a4cd17d9d4aba390cb871d34006a5e4e27eeac55c37ed4b160b1c7fa573b079291477f5c34df7389fb207202d36cb020bb1e11b1770ae@127.0.0.1:0","enr":"0xf88fb840ee4895d2879885f7fcb08b7d5d3a2ebdb4617198888190d13eed5f53b6e2c48518e2429a8c73ab55c0f5bfb46f4144cf3d97557bf7a6065d62c6bf38af64d1f90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bf082dde14615af13c8a4cd17d9d4aba390cb871d34006a5e4e27eeac55c37ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BBxKP5QlNuZ68IfaMFQD4moZ4DDc9RRzpZdDF1OivsI=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 041c4a\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dd48 c034 8cb7 ab25 | 35 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n001 6 4541 5b87 55a2 62c0 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 2b80 2293 33fe | 6 33fe (0) 2293 (0) 27c2 (0) 2b80 (0)\n003 4 1dd4 1a93 12b8 10d5 | 4 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n============ DEPTH: 4 ==========================================\n004 3 0d7f 0f03 0e8f | 3 0d7f (0) 0e8f (0) 0f03 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","private_key":"0c395ad41017794ece1bb20e02f995d3d71b784e80b6972127d60e11b9416033","name":"node_041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","services":["streamer"],"enable_msg_events":true,"port":45519},"up":true}},{"node":{"info":{"id":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","name":"node_c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","enode":"enode://56c5533688bc45c78eab8abe6fdbcc89c9ff51b6b2e78b4aa94c1e9d24f9269468c3d7061b1898f46535308665012ae49ce7768fe52a097e0f29eba58264f339@127.0.0.1:0","enr":"0xf88fb8402ff8750dfe7251a484fddf76d16ae3c3704a2faf12eb06a51b8f7409190bb26958d90e58f0a89ef2e488bb66c090ec33b0434b315fc7d2aafca5ac24482e5deb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10356c5533688bc45c78eab8abe6fdbcc89c9ff51b6b2e78b4aa94c1e9d24f92694","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wDRxluyH9R+XIpFAtdZgFc//J4HMGv9tPiB8P6NTJzI=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c03471\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6049 041c | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 b269 bc3e bbbc | 14 b269 (0) bc3e (0) be5d (0) bbbc (0)\n002 2 ff06 fef2 | 9 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n003 2 de4f d165 | 5 dd48 (0) de4f (0) d87b (0) dbef (0)\n004 2 c851 ce82 | 2 ce82 (0) c851 (0)\n005 2 c62e c67d | 2 c67d (0) c62e (0)\n============ DEPTH: 6 ==========================================\n006 1 c34b | 1 c34b (0)\n007 0 | 0\n008 0 | 0\n009 1 c05d | 1 c05d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","private_key":"5a906a787cb78df16ad69dfd4eefb997694bce2b8b171b223cd01db89f2cfe56","name":"node_c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","services":["streamer"],"enable_msg_events":true,"port":42833},"up":true}},{"node":{"info":{"id":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","name":"node_d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","enode":"enode://d3715cf48dd521184951b76f82e30bef59b728fb780c33aafac3b501ec3a082cabdd4fbf1d191b0fc6fd4e329aca56f96d8820b1d3d7c38ff169bb66398379ef@127.0.0.1:0","enr":"0xf88fb84082fc9a1da6b7ab89a49f98c25a59627c4f54319e0d439c5f8605a75ddf74b1f0099cb2a276f366bd085ef8f6fbfbc4ae9b86b4530d0a31ce50fe3cbd8c98c6670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d3715cf48dd521184951b76f82e30bef59b728fb780c33aafac3b501ec3a082c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0WUT8w1IXTF1MhwaCqWlJcEVrhPDlff6Pesc9NHsabw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d16513\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5bf6 1a93 12b8 | 29 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n001 2 bbbc 9861 | 14 b269 (0) bc3e (0) be5d (0) bbbc (0)\n002 3 f090 ff06 fef2 | 9 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n003 5 ce82 c67d c34b c05d | 7 ce82 (0) c851 (0) c67d (0) c62e (0)\n============ DEPTH: 4 ==========================================\n004 4 dd48 de4f d87b dbef | 4 dd48 (0) de4f (0) d87b (0) dbef (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","private_key":"18698a5fd9c496b1d243f171696350d10fc3580717073a40f6d99520412f83d5","name":"node_d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","services":["streamer"],"enable_msg_events":true,"port":45987},"up":true}},{"node":{"info":{"id":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","name":"node_9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","enode":"enode://17306034b66dfcdbc97a6f9ba35033107edc8cbb03353fe5e6eb8df030ac6752cd0ed1f6edfcd7b57c456a10519e1563141ab10a463ab00d6c46cc315805d60f@127.0.0.1:0","enr":"0xf88fb84064b8824d317bdfdbd6d0f8e6d48f0b8a8faef43af8108d93c63e8d5b3b0239bd0221d18dbfe9bc21d49506094150e4abc556274dca3f62cf87b393001cdfbbab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10317306034b66dfcdbc97a6f9ba35033107edc8cbb03353fe5e6eb8df030ac6752","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mGHXyrFf13zlRKoEb52vYa9/fHjaf4TJ07wcGfny4HE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9861d7\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 2b80 55a2 4541 | 29 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n001 4 f16d f090 ce82 d165 | 21 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n002 3 bbbc a259 aeff | 8 b269 (0) bc3e (0) be5d (0) bbbc (0)\n003 3 83aa 8cb7 8934 | 3 8934 (0) 8cb7 (0) 83aa (0)\n============ DEPTH: 4 ==========================================\n004 2 9637 9009 | 2 9009 (0) 9637 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","private_key":"4df06f9461343c2fda87c2dad86b4b3cf8a4f9ca58c88bae635d03da92ea006b","name":"node_9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","services":["streamer"],"enable_msg_events":true,"port":46151},"up":true}},{"node":{"info":{"id":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","name":"node_45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","enode":"enode://a686970d89c6c9d2e4c69d94f1b6694d904581304de0fc9efb180891260b3099a5b46700b2aa72d09afb7266ef786abc5dada1f9b0fe5f3a78daec8cc6f66c53@127.0.0.1:0","enr":"0xf88fb840241ea258a71f40249cdf5e63289c8632db6eca503178586fa7803de62e853e4a3dd497f51b52eb68afac7dce913cf61574c069499d3a4f31f727f83262c49b180183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a686970d89c6c9d2e4c69d94f1b6694d904581304de0fc9efb180891260b3099","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RUEadILK5Q3R3Y2QE4oowNxhsEuqlZL5J/nUFbCXClM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 45411a\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ec08 9861 | 35 ce82 (0) c851 (0) c67d (0) c62e (0)\n001 3 041c 0d7f 0e8f | 14 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n002 2 6049 62c0 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 2 5bf6 55a2 | 4 55a2 (0) 5bf6 (0) 5b87 (0) 5b93 (0)\n004 2 4853 4e4e | 2 4e4e (0) 4853 (0)\n005 1 404b | 1 404b (0)\n============ DEPTH: 6 ==========================================\n006 1 46af | 1 46af (0)\n007 1 4443 | 1 4443 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","private_key":"e7b54819c42e18dc0898157b7f12a62003c3ca0b175bb3478c3e18364ad4d72d","name":"node_45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","services":["streamer"],"enable_msg_events":true,"port":39521},"up":true}},{"node":{"info":{"id":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","name":"node_ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","enode":"enode://d4e917601f1e529ba3150bc6547ed2baa812c622541b179807e35b3d19b6f024b3babc685cc9052d03ac6af21cd734b458f7010c55cf32997f230b64626a5a37@127.0.0.1:0","enr":"0xf88fb8406a26e3870ba17f1f806d807b45527a32c7fb63b96a757f20b191a4b827cb4f840cbfeef46ad28b8d65bb14e1677cff14604cd8e288cf6f25367dac70f3fc1e740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d4e917601f1e529ba3150bc6547ed2baa812c622541b179807e35b3d19b6f024","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7AhSQ2Rcbl/b7/sTfM0RkFO9ZV52sdmmteAiEYN2TkM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec0852\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6049 4e4e 4541 5b93 | 29 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n001 5 a259 b269 be5d bc3e | 14 b269 (0) bc3e (0) be5d (0) bbbc (0)\n002 8 d87b dd48 c851 ce82 | 12 ce82 (0) c851 (0) c67d (0) c62e (0)\n003 4 fef2 ff06 f6f3 f1e1 | 6 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n============ DEPTH: 4 ==========================================\n004 1 e59a | 1 e59a (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 ec3e | 1 ec3e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","private_key":"564658b59ef3923b2cfa270f76d2885719f4d8d5a4640218cef7fd7cc5803538","name":"node_ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","services":["streamer"],"enable_msg_events":true,"port":43959},"up":true}},{"node":{"info":{"id":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","name":"node_5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","enode":"enode://7cfb88f94a2ce6d8382ad72e15d58c728ccf68134cada4852553c46446caf2244b21821d261c193ef0f96bd15aa704cc0ff3c808d6f46572af769d98f5662856@127.0.0.1:0","enr":"0xf88fb8404835ccf9f26f0c1ced47b4f024d3eb722f652257cb4bbf0c7122ea46b1f338d061f8d1c3ff1e6a17350e0a573500841cd7eaa7b532e66ac094ad8f5e2642d0740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027cfb88f94a2ce6d8382ad72e15d58c728ccf68134cada4852553c46446caf224","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W5NjQdpwnRGzS23wB/OP/wOWt4WhT5RlOq+SHY5FCj8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5b9363\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bc3e b269 ec08 | 35 b269 (0) bc3e (0) be5d (0) bbbc (0)\n001 4 1dd4 0e8f 2293 27c2 | 14 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n002 3 62c0 6049 7a5c | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 3 4e4e 46af 404b | 6 404b (0) 46af (0) 4443 (0) 4541 (0)\n004 1 55a2 | 1 55a2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 5bf6 | 1 5bf6 (0)\n010 0 | 0\n011 1 5b87 | 1 5b87 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","private_key":"10d7b03ff60d1351f7b6be0726cb6c950befc858ef8f870ef7f19335efe1b2e9","name":"node_5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","services":["streamer"],"enable_msg_events":true,"port":41261},"up":true}},{"node":{"info":{"id":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","name":"node_27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","enode":"enode://643ed7e6dce73138a35c06ad2e7dd22b9fb60bfe8c62df0e78ba66158a01ee8c5105a61257adc96ceefe709d7f1a33501118a7f788cfc64a9ab1d5f8dabd02f0@127.0.0.1:0","enr":"0xf88fb8404d9287db19102ad4463ec35d232a539755701e2fa7d275048045a82a349c00ac7db9f3d723cc349a77840cb6643cf59aafffac21d27bfa52933fedcd68b91a4c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102643ed7e6dce73138a35c06ad2e7dd22b9fb60bfe8c62df0e78ba66158a01ee8c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J8I2WD3/cUowAKyvv9MwhWbIEnH4JerI9PDP+Dp/8Sc=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 27c236\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c05d c67d fef2 ff06 | 35 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n001 5 6271 7a5c 46af 4e4e | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 1dd4 10d5 0f03 | 8 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n003 1 33fe | 1 33fe (0)\n============ DEPTH: 4 ==========================================\n004 3 2b79 2b80 2f1a | 3 2f1a (0) 2b80 (0) 2b79 (0)\n005 1 2293 | 1 2293 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","private_key":"d83c8e0152983bd8a5e3e5bbbe5fcd0962af9a8d3c3e74b2766a616a662ce1fc","name":"node_27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","services":["streamer"],"enable_msg_events":true,"port":33423},"up":true}},{"node":{"info":{"id":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","name":"node_83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","enode":"enode://124f0cb5dff8cbe3f2b4879314e1c7e445847ab4107a0172bdb2cc3c8c117e31f5b7d10237c9a2e01cf4b308684c6ae532267b2316bec3efd66e418e51df05c4@127.0.0.1:0","enr":"0xf88fb840e0882134a9c0bab94463ea2fb53f1227c478c4b6573df8c6e0d225495bff145000ae070b7539cc26f159f626b7ce494e2f7830c5cb9a091059ccf0b950947b200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102124f0cb5dff8cbe3f2b4879314e1c7e445847ab4107a0172bdb2cc3c8c117e31","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g6rVuX4eqMQFN+VZPeSBDHs1+rFWBTQC3adY1unqkFU=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 83aad5\npopulation: 26 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5b87 4853 0e8f 1dd4 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 10 f16d f1e1 fef2 e59a | 21 ce82 (0) c851 (0) c67d (0) c62e (0)\n002 5 aeff adfd be5d bc3e | 8 b269 (0) bc3e (0) be5d (0) bbbc (0)\n003 3 9861 9009 9637 | 3 9637 (0) 9009 (0) 9861 (0)\n============ DEPTH: 4 ==========================================\n004 2 8cb7 8934 | 2 8cb7 (0) 8934 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","private_key":"cb01a75bc3c400c6de710019b74759a8aa1dd7e7362e86928ef1ea2b04805e0f","name":"node_83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","services":["streamer"],"enable_msg_events":true,"port":45083},"up":true}},{"node":{"info":{"id":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","name":"node_48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","enode":"enode://8cd9a1d7a69bf057290a9f420a465a9e82ca398b542cb8cbd444121f06a56a50a1488496a7786bc41fa750eebde2519b30e91d6a254979aafe5b362f291b3342@127.0.0.1:0","enr":"0xf88fb8405c96c6659930b28d8e7fc70e709db26a72cfb94922dbf7d4cfb4fac0083d70037a3eb75c1117b50851f09570ca994003cebee249134d8c8f7f1604ba717afaac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028cd9a1d7a69bf057290a9f420a465a9e82ca398b542cb8cbd444121f06a56a50","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SFNKU4/XCMDmFsvfqUhZYEi32qd+8J3WnBZSpfbQXvw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48534a\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c62e c851 ce82 83aa | 35 ce82 (0) c851 (0) c62e (0) c67d (0)\n001 3 2f1a 33fe 12b8 | 14 33fe (0) 2f1a (0) 2b80 (0) 2b79 (0)\n002 3 7a5c 62c0 6049 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 3 55a2 5bf6 5b87 | 4 55a2 (0) 5bf6 (0) 5b87 (0) 5b93 (0)\n============ DEPTH: 4 ==========================================\n004 4 404b 4443 4541 46af | 4 404b (0) 46af (0) 4443 (0) 4541 (0)\n005 1 4e4e | 1 4e4e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","private_key":"8b7949320c5ad8130070a34702abd57dc0f7b7ddd7da1abd2b8a3aabad87dca1","name":"node_48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","services":["streamer"],"enable_msg_events":true,"port":38627},"up":true}},{"node":{"info":{"id":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","name":"node_12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","enode":"enode://149300b78ce42863b2bff34e21322a35ae2558dfe528efca3cbcc8b9a90003d8cba8a3cb24dba7d83d923e4565689cef7d48c1988c109bb94b1bc92bf348c5dd@127.0.0.1:0","enr":"0xf88fb840731cd5d3da6e6990435abc04b71ca41ee0c7e99f6f7baf78f4f4dd25cc64f546516fdf07f114321703f8ad413ff912c769f3e636e3f2435ad48390bf3325da4f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103149300b78ce42863b2bff34e21322a35ae2558dfe528efca3cbcc8b9a90003d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Erh2ng6ZYBHO/0iaP1a6jlVdVFtprMtbQ5berXM1qNs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 12b876\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d165 aeff | 35 ce82 (0) c851 (0) c62e (0) c67d (0)\n001 3 62c0 6049 4853 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 2 2b79 2f1a | 6 33fe (0) 2f1a (0) 2b80 (0) 2b79 (0)\n003 4 041c 0f03 0e8f 0d7f | 4 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n============ DEPTH: 4 ==========================================\n004 2 1a93 1dd4 | 2 1a93 (0) 1dd4 (0)\n005 0 | 0\n006 1 10d5 | 1 10d5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","private_key":"2508a321d22ccd27c53ebf00259ba720d9dee11266d3f043f356c7a542bf5213","name":"node_12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","services":["streamer"],"enable_msg_events":true,"port":38733},"up":true}},{"node":{"info":{"id":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","name":"node_aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","enode":"enode://680e1e24fb480dd22e272d12a2154d05d2da6969852d46f6b506b4a1282fb34600add98e4ca61da2fb843cf9cda458b570644726887f2050db271b98b1c0db17@127.0.0.1:0","enr":"0xf88fb8408aac439c83ee5ca37fe399d1d5b6c1e934d183768e15180da3383420881be7c53b0a80526aadd31a64143fd0a5260c48f9d7d5737a91adacae76980c9c76f9110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103680e1e24fb480dd22e272d12a2154d05d2da6969852d46f6b506b4a1282fb346","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rv+IpcdJczcH+ZuHbB7PfbcbMqaRbPm70mavPmn5ToI=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aeff88\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 62c0 6049 12b8 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 dd48 ce82 ec3e | 21 ce82 (0) c851 (0) c62e (0) c67d (0)\n002 3 8934 83aa 9861 | 6 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n003 2 bbbc b269 | 4 b269 (0) bbbc (0) bc3e (0) be5d (0)\n004 1 a259 | 1 a259 (0)\n============ DEPTH: 5 ==========================================\n005 1 ab25 | 1 ab25 (0)\n006 1 adfd | 1 adfd (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","private_key":"6362a429c515516bd38d57f294a819e354a5c339c513bbaab341d2c5a7f13394","name":"node_aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","services":["streamer"],"enable_msg_events":true,"port":40299},"up":true}},{"node":{"info":{"id":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","name":"node_ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","enode":"enode://78e0de844f3eb1a777d730bab86c1a0b567be81f22b68a37e6982ea9125e90bd7bc29f61d61244aa891f590fbfd8b5007806f51cf694267bb8e3b97a08572afb@127.0.0.1:0","enr":"0xf88fb840ee54b5b6a8c22c569f160e440cf7be54568f91bb8830054e562bf3befdd1d714319c55af25103db7e6a23762cbe773952246ac5142ec549a063fbea2b66725470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10378e0de844f3eb1a777d730bab86c1a0b567be81f22b68a37e6982ea9125e90bd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7D6E+Aq3HfCaRMecjUr42mj98919vOdFE2O4qhZjBJM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec3e84\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4e4e 6049 7a5c 75bf | 29 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n001 4 8934 be5d a259 aeff | 14 8934 (0) 8cb7 (0) 83aa (0) 9637 (0)\n002 5 dd48 de4f c62e ce82 | 12 ce82 (0) c851 (0) c62e (0) c67d (0)\n003 5 fef2 ff06 f6f3 f16d | 6 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n============ DEPTH: 4 ==========================================\n004 1 e59a | 1 e59a (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 ec08 | 1 ec08 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","private_key":"9cd9fa1a605cd0ed1669a0dd7bdedc839592f58445855d00f026f10b963dcafc","name":"node_ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","services":["streamer"],"enable_msg_events":true,"port":36709},"up":true}},{"node":{"info":{"id":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","name":"node_2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","enode":"enode://e5b1f4c67a9ddf4aa86df910ed695036a223dd512855d568edab958376cdd219581d2630660fde2afdc7ee817e216363ceb5fe859fe22b1cac314f5ca41d5c6a@127.0.0.1:0","enr":"0xf88fb840d2019a30e5ccc8ec4bcbdee28917513d1f3af8f8d0a0ca778e4198ff0de51ae22ac27b43f7d4c6a255487960932f592d5cde6b85398068b56960e6b05ee82faa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e5b1f4c67a9ddf4aa86df910ed695036a223dd512855d568edab958376cdd219","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IpOx6ftE7m2znbk2YpH8C04obDVVR3UN4Z6Wwy4Cvfk=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2293b1\npopulation: 22 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8934 c62e c05d ec3e | 35 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n001 6 75bf 7a5c 46af 4443 | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 7 10d5 1dd4 1a93 041c | 8 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n003 1 33fe | 1 33fe (0)\n============ DEPTH: 4 ==========================================\n004 3 2b80 2b79 2f1a | 3 2f1a (0) 2b80 (0) 2b79 (0)\n005 1 27c2 | 1 27c2 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","private_key":"a7e22c8e32897aa84673ffac362e3ce8b479502494dc0749e76bdfd84a0adb9c","name":"node_2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","services":["streamer"],"enable_msg_events":true,"port":42613},"up":true}},{"node":{"info":{"id":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","name":"node_0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","enode":"enode://0c0ef588e8b1199c6721bf84dcb2c30de56f14db707cb02e310a245b8b3ce5c62ae119bc2950db881cc79b4bc1a2386f24bc14b0b3b7ba4e2e2f37b5a1cff032@127.0.0.1:0","enr":"0xf88fb8403221a6d46572817f3fc0af52de678dc02fff0e264b852ad32144056b20ebe5eb256f63a332afe90b856b498ea1e44ba84e339efbe95ed453fbb8bf7eb3be2f0e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c0ef588e8b1199c6721bf84dcb2c30de56f14db707cb02e310a245b8b3ce5c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Do+z4ldGp/GPM+McECAOXsIetUrVkrrVNpubWE/oDhs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e8fb3\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8cb7 8934 83aa f16d | 35 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n001 3 4541 5b87 5b93 | 15 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n002 2 33fe 2293 | 6 33fe (0) 2f1a (0) 2b80 (0) 2b79 (0)\n003 4 10d5 12b8 1a93 1dd4 | 4 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n004 1 041c | 1 041c (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 0d7f | 1 0d7f (0)\n007 1 0f03 | 1 0f03 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","private_key":"e4fb6f87c8b9945ae6a519e730732fdde0730aca6c9f6337c91d93cd6c1c2480","name":"node_0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","services":["streamer"],"enable_msg_events":true,"port":42649},"up":true}},{"node":{"info":{"id":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","name":"node_f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","enode":"enode://d53eecb3d3f3d9ff017ec25bcdfcb2f3ce3232f6231b66d85ed3be04cf3f6cc65c8dde5e8fe596ad8525a3e57a7f32f6978897df1999e44a5d45eb5cd6b8e9a7@127.0.0.1:0","enr":"0xf88fb8406945726d8a4e02936737ad2da763a772efedf913a0000b71b47a1f44d9a385ea6b033e2dfc7fd4744edcf9516d7af9601eff2844b8039d985f9b575cd4a993dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d53eecb3d3f3d9ff017ec25bcdfcb2f3ce3232f6231b66d85ed3be04cf3f6cc6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8W3GW1ip+lBgZ0ynQVMYkf1Etj2axeq+oYV0UEnkdMo=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f16dc6\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 75bf 0d7f 0e8f | 29 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n001 3 8934 83aa 9861 | 14 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n002 2 ce82 dbef | 12 ce82 (0) c851 (0) c62e (0) c67d (0)\n003 2 e59a ec3e | 3 ec08 (0) ec3e (0) e59a (0)\n004 2 fef2 ff06 | 2 ff06 (0) fef2 (0)\n005 1 f6f3 | 1 f6f3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f090 | 1 f090 (0)\n008 1 f1e1 | 1 f1e1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","private_key":"6e17a7cb8b4de986f9326d40d3f75a0548c328b5dcee6251d75d9660ff38b25f","name":"node_f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","services":["streamer"],"enable_msg_events":true,"port":36431},"up":true}},{"node":{"info":{"id":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","name":"node_dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","enode":"enode://a8545ee5288608aa97011ceaad769754e2fef8de716fde9f03da6fd3443dee98a58ad2f20866d444df2aff3ebb9178512cbe0a88c70c13d763ad2f21a2d31518@127.0.0.1:0","enr":"0xf88fb840a5d951670a83dfbad4108b1a6e4daad3ec8234952811451a02187bb09cecbb095ae0eb3bb7f2c41e5a07f629cc716628c546b82b93c5895b8749b0af44aa53440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a8545ee5288608aa97011ceaad769754e2fef8de716fde9f03da6fd3443dee98","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2+/TIuTzfz4UKtFRoIyL13hPsNskkySv9Hn1tmMhLnY=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dbefd3\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7a5c 75bf 62c0 | 29 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n001 3 83aa 8cb7 8934 | 14 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n002 2 e59a f16d | 9 ec08 (0) ec3e (0) e59a (0) ff06 (0)\n003 3 c67d c62e c34b | 7 ce82 (0) c851 (0) c62e (0) c67d (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 de4f dd48 | 2 dd48 (0) de4f (0)\n006 1 d87b | 1 d87b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","private_key":"8537c2f509c410459184963d560347c250fc3f2631bcc456ac9b79da484bc101","name":"node_dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","services":["streamer"],"enable_msg_events":true,"port":35725},"up":true}},{"node":{"info":{"id":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","name":"node_c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","enode":"enode://0245124f48570389a2866e65303f7d57c8a4254666fb9e7ec6e6f3ace35f5e45ca64226350e6b6445dfd1091d1394796df617f005159041b940524f8adda73a1@127.0.0.1:0","enr":"0xf88fb8404535d47dbfda01f3c3a68b4bd60c11c4768d1649b38384b158512d85b4e5cc43499e0e607bddd4361d5b54a390b17ae72e26d3080276c9d687c9efae40f005860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030245124f48570389a2866e65303f7d57c8a4254666fb9e7ec6e6f3ace35f5e45","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"w0vS4gn8EeJ/geE1lUXyjIFnhxJ7QYEdwXEPpOU/zvo=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c34bd2\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 75bf 7a5c 62c0 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 83aa 8cb7 8934 | 14 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n002 2 ec08 f090 | 9 ec08 (0) ec3e (0) e59a (0) ff06 (0)\n003 2 d165 dbef | 5 d165 (0) dd48 (0) de4f (0) d87b (0)\n004 2 c851 ce82 | 2 ce82 (0) c851 (0)\n005 2 c67d c62e | 2 c62e (0) c67d (0)\n============ DEPTH: 6 ==========================================\n006 2 c05d c034 | 2 c034 (0) c05d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","private_key":"ecb3f67dada43226ea1f5c5c177ca97188784e759b87b5d7701b36bbbcee941b","name":"node_c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","services":["streamer"],"enable_msg_events":true,"port":38173},"up":true}},{"node":{"info":{"id":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","name":"node_f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","enode":"enode://796dd862e2916c5900370aa18abb58eb7ba061bd52bf8bb48806ac1deec33d5f6627fbd4cdccb07ca96c2661bc2e8b28c2899f2dc77b58affcbb938e197868b7@127.0.0.1:0","enr":"0xf88fb84022132521c6b77045f87c62858e909b70e05b1eb03074a66cdbf5ddd612c6497c0d7965fa4bf8da77b47dd9876098ae4e83e897a656a7fead1080c84ad489a9800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103796dd862e2916c5900370aa18abb58eb7ba061bd52bf8bb48806ac1deec33d5f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8JDZCflPaXDQdJSBFeT0bmfk+1c19TeIntKxaf8r02g=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f090d9\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 404b 2f1a 2b79 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 2 9861 ab25 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 2 d165 c34b | 12 d165 (0) dd48 (0) de4f (0) d87b (0)\n003 2 e59a ec3e | 3 ec08 (0) ec3e (0) e59a (0)\n004 2 fef2 ff06 | 2 ff06 (0) fef2 (0)\n005 1 f6f3 | 1 f6f3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 f1e1 f16d | 2 f1e1 (0) f16d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","private_key":"3dfe370e85ca228b6903e2d360a8514dce89675639f3a9264664edb96fdca3dc","name":"node_f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","services":["streamer"],"enable_msg_events":true,"port":41687},"up":true}},{"node":{"info":{"id":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","name":"node_2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","enode":"enode://370dcdd12168f383c15bd0ec87531e7bdaa52736c12bcea00741789b1751854b7e14b84fc913da88db24c127860eef70289cd36c30e870b2e60ae232f705b520@127.0.0.1:0","enr":"0xf88fb8403028d93ddd84c729bf844b16597a912772cc40c7db867507dad911da33bfe6d55295b0a2878cb609e92f19940ef46dd3702138aec69e6760ec1467fbce88f9fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102370dcdd12168f383c15bd0ec87531e7bdaa52736c12bcea00741789b1751854b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"K3kPvKjadMfelxW0kZzgPNzxSkYIZxzUc5srmaBS5jY=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2b790f\npopulation: 12 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 8934 83aa f090 | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 2 7a5c 5b87 | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 2 0d7f 12b8 | 8 041c (0) 0e8f (0) 0f03 (0) 0d7f (0)\n003 1 33fe | 1 33fe (0)\n004 2 2293 27c2 | 2 27c2 (0) 2293 (0)\n============ DEPTH: 5 ==========================================\n005 1 2f1a | 1 2f1a (0)\n006 0 | 0\n007 0 | 0\n008 1 2b80 | 1 2b80 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","private_key":"d4f121c855c9e92f96585641e9e11a9f25db6aa8086675165215c749e9931cc6","name":"node_2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","services":["streamer"],"enable_msg_events":true,"port":39687},"up":true}},{"node":{"info":{"id":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","name":"node_5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","enode":"enode://c1760651e80b5c22381bc3145277a8ea0e69ca9ccb7eec2abbf5d25763af1434adb24df08ef0563f360c47e13df5274f4a306c6c58d563001c737b1a6e8f6077@127.0.0.1:0","enr":"0xf88fb84049138c3a1759cf719d4a36e6e0af5ed94ddcc90a5151a6bf2f2c4a1ab71fb59e1c02d825fd42a203c2b2638a1e777ba95a1f07e2a1b276029d6f689aa0dd9c6f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c1760651e80b5c22381bc3145277a8ea0e69ca9ccb7eec2abbf5d25763af1434","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W4dHjOb5aYjVctJJFAymcW9mrsj24ENef4vp/KXtOKA=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5b8747\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 adfd 8cb7 8934 83aa | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 4 1dd4 0e8f 041c 2b79 | 14 041c (0) 0e8f (0) 0f03 (0) 0d7f (0)\n002 2 6271 75bf | 5 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n003 2 46af 4853 | 6 404b (0) 46af (0) 4443 (0) 4541 (0)\n004 1 55a2 | 1 55a2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 5bf6 | 1 5bf6 (0)\n010 0 | 0\n011 1 5b93 | 1 5b93 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","private_key":"8d3cdf3d5a28844fd7e67364be1e82e3718d8f5eb3b28b7c219f3bfd3a4482ff","name":"node_5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","services":["streamer"],"enable_msg_events":true,"port":45565},"up":true}},{"node":{"info":{"id":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","name":"node_c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","enode":"enode://8efe3d05a04ad75bac960e82749f90285a60965cbabf117520172a430cee7e1beabe22d9402056d1fcd0bd54060e8aef112a62ab850079d330d861bcdd7816cb@127.0.0.1:0","enr":"0xf88fb8405e37f5ab79e815ac91da5441a580c06abf98a4ea7d3ed49b9aaa5dd4b5c8356a4a4a3a5f0f457122d3ef8ef8d3d0ab266d55390d8c1dec965faa04061944e7180183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038efe3d05a04ad75bac960e82749f90285a60965cbabf117520172a430cee7e1b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yFEfiJbTxCJtXYyGAJbGqQg5/OUAp3uDBDlfW0gzsoQ=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8511f\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1dd4 1a93 4853 5b87 | 29 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n001 2 8cb7 83aa | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 3 e59a ec08 ec3e | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 dd48 d87b | 5 d165 (0) de4f (0) dd48 (0) dbef (0)\n============ DEPTH: 4 ==========================================\n004 5 c34b c034 c05d c62e | 5 c62e (0) c67d (0) c034 (0) c05d (0)\n005 1 ce82 | 1 ce82 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","private_key":"7edb500de3d27c2f1c20281b4a363269e854385d629b21f00110159d97b3607e","name":"node_c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","services":["streamer"],"enable_msg_events":true,"port":44825},"up":true}},{"node":{"info":{"id":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","name":"node_d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","enode":"enode://df025390a37a450f77f57f29730f1cdcf861dafe454be915480b15a7618c3dd0fa0614cd563fafc92b49c299f8ca1a67fa45a5e339ef81f7eb0313063ec7fcd7@127.0.0.1:0","enr":"0xf88fb840f20d1eb7eba00a7c4cad26a78536b6a072c53c985418b4cca4a279004d36316d3b04274929a19f4967819c2b69986716fdb97b7224be8c43b3152c9a09b6f1450183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df025390a37a450f77f57f29730f1cdcf861dafe454be915480b15a7618c3dd0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2HumV1dpaAWPzIZXnD9SqniQWQmwqUOTivYhxu2Z++o=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d87ba6\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6049 7a5c 75bf | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 8cb7 8934 83aa | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 2 ec08 f1e1 | 9 ec08 (0) ec3e (0) e59a (0) ff06 (0)\n003 2 c62e c851 | 7 c62e (0) c67d (0) c034 (0) c05d (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 de4f dd48 | 2 de4f (0) dd48 (0)\n006 1 dbef | 1 dbef (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","private_key":"93f0687cbba5779fbb6cb10ab57fdb2d731263d9454254b0d068517de95318c3","name":"node_d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","services":["streamer"],"enable_msg_events":true,"port":42845},"up":true}},{"node":{"info":{"id":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","name":"node_f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","enode":"enode://484250cb629a55eb8908406ea682b88bd1095dbc5c8b47d7dcf788b58af2aca80bcc8048c730f61123f714da50af301fbf0bb5544d6a12265dd64f6d6caa7622@127.0.0.1:0","enr":"0xf88fb840c0b62c373941d77a9db85a25dd2254d9ed63ab322b5103757f67b539c0637fa45e0227414a8f3c80030c5c4f3c63066f12d2f43a348b054df1baec631a2b24ab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102484250cb629a55eb8908406ea682b88bd1095dbc5c8b47d7dcf788b58af2aca8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8eFRvu8MIllmmslQElqgBLArpweL8thySKS30lxiWF4=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f1e151\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0d7f 10d5 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 adfd 83aa 8cb7 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 3 c67d c62e d87b | 12 c62e (0) c67d (0) c34b (0) c034 (0)\n003 2 e59a ec08 | 3 ec08 (0) ec3e (0) e59a (0)\n004 2 ff06 fef2 | 2 ff06 (0) fef2 (0)\n005 1 f6f3 | 1 f6f3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f090 | 1 f090 (0)\n008 1 f16d | 1 f16d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","private_key":"acc2b5405b67970f8bd4ed395c8d529244748d6ac6a154cb9ff921ece215fb88","name":"node_f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","services":["streamer"],"enable_msg_events":true,"port":41401},"up":true}},{"node":{"info":{"id":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","name":"node_10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","enode":"enode://89a7090143be61d5f0802e125024559acf78c2f4425833355773894fb50f276b8fdda028da973cf879caedfc187dd1addcdf96518411c22acaa2481c2e286f0e@127.0.0.1:0","enr":"0xf88fb8406fe88139d195b80e137f45124e24df45a21c7cd29b132466d90f172da4a4bc3827089aa2a8a2e90d2dffe86715fe8fa4fcb3e92946b1d1ba13c05fced90ccdf10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10289a7090143be61d5f0802e125024559acf78c2f4425833355773894fb50f276b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ENV5UjrLrTDj5Q1hDw0ykfdRhIZ3PI2UBIVr8TSRKL8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 10d579\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 fef2 f1e1 | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 3 6049 7a5c 75bf | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 3 33fe 2293 27c2 | 6 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n003 3 0f03 0e8f 041c | 4 041c (0) 0e8f (0) 0f03 (0) 0d7f (0)\n============ DEPTH: 4 ==========================================\n004 2 1a93 1dd4 | 2 1a93 (0) 1dd4 (0)\n005 0 | 0\n006 1 12b8 | 1 12b8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","private_key":"aed9b1cd2e417b73e0eafef6d800fb05144bbd30fde59e856931febfceef38fa","name":"node_10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","services":["streamer"],"enable_msg_events":true,"port":36265},"up":true}},{"node":{"info":{"id":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","name":"node_fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","enode":"enode://336313478a56abfa3294828046976fbf1cb48cdea139aa491ca1cd88448e89b3740139f57abadcff5bc46002f2e491114ae0145b2dd38143675777c06d03ef60@127.0.0.1:0","enr":"0xf88fb840aa6cf0fb83fdcdc187e00d76cbbbcb8be6d3beceab21d139ad8b0e8380aafaa62f686200f97847175179cad675ea37ee3c5b6db44cd6241386602d8d410691ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102336313478a56abfa3294828046976fbf1cb48cdea139aa491ca1cd88448e89b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/vJ6NgQIF56v1RTfxxAW898IW8sug7vetfueXNGTVpY=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fef27a\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 75bf 7a5c 27c2 10d5 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 83aa 8934 8cb7 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 3 d165 c034 c05d | 12 d165 (0) de4f (0) dd48 (0) dbef (0)\n003 3 e59a ec3e ec08 | 3 ec08 (0) ec3e (0) e59a (0)\n============ DEPTH: 4 ==========================================\n004 4 f090 f1e1 f16d f6f3 | 4 f6f3 (0) f090 (0) f16d (0) f1e1 (0)\n005 0 | 0\n006 0 | 0\n007 1 ff06 | 1 ff06 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","private_key":"49a6d4a219bf4b1ad421bd6639b794b3f12fabb5f218155ca4722238da50e33f","name":"node_fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","services":["streamer"],"enable_msg_events":true,"port":45845},"up":true}},{"node":{"info":{"id":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","name":"node_c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","enode":"enode://611dae74107d3503af1ac4fa2d17a00533063b2247085dd393337640911e8c5ca30c1e485845c6dc12c408705af5ecfcfc593bb6503d859b9ddd51eb2b40fa71@127.0.0.1:0","enr":"0xf88fb8401cb70183d2bfd84ae541dc21ef3417ac61c4e11bc8d80f2adc3b475b1ea5011a7767542e90a84bd5e76da6acfe25c5d8b7c0236a7b7ff85fc81506fbe874e1b00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103611dae74107d3503af1ac4fa2d17a00533063b2247085dd393337640911e8c5c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wF2dkZnBsb+Er0uIabNpIDgvA1DVjdUQBwDNDSfxZas=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c05d9d\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 33fe 27c2 2293 | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 3 8934 83aa be5d | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 2 ec08 fef2 | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 d165 de4f | 5 d165 (0) de4f (0) dd48 (0) dbef (0)\n004 2 c851 ce82 | 2 ce82 (0) c851 (0)\n005 2 c67d c62e | 2 c62e (0) c67d (0)\n============ DEPTH: 6 ==========================================\n006 1 c34b | 1 c34b (0)\n007 0 | 0\n008 0 | 0\n009 1 c034 | 1 c034 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","private_key":"d8106f622a5e169381999bd3370e0a0ee143ac4bd5f679a957c78402600e345b","name":"node_c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","services":["streamer"],"enable_msg_events":true,"port":41355},"up":true}},{"node":{"info":{"id":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","name":"node_be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","enode":"enode://1461c352c31d8c7158d0bae6915d42f1353f1b5608ebca9ab6ef2bc08035155f3fb075962f54495806fe9b8cd85a22b42ac099cbf299571ff5e5ba91271a2f17@127.0.0.1:0","enr":"0xf88fb840a191693ed026822c26a8b3823cb888fc5e2607612bcfe9d4a6ee5ede28060aef2608c9121b792343c21884f298aa1dcff8431d0acf48205f66a6cd156b4089360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031461c352c31d8c7158d0bae6915d42f1353f1b5608ebca9ab6ef2bc08035155f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vl2g60vHbAyjpjQjVo2/ok04VJmUWwaDCKKHTtQkPrM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be5da0\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 27c2 33fe 4e4e | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 3 ec3e ec08 c05d | 21 ec08 (0) ec3e (0) e59a (0) f090 (0)\n002 3 83aa 8934 8cb7 | 6 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n003 2 ab25 a259 | 4 a259 (0) ab25 (0) aeff (0) adfd (0)\n004 1 b269 | 1 b269 (0)\n============ DEPTH: 5 ==========================================\n005 1 bbbc | 1 bbbc (0)\n006 1 bc3e | 1 bc3e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","private_key":"9d95c4e61d120dc2c67a63e93da0b69a257ae7dd8ca30eda036335366d1508de","name":"node_be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","services":["streamer"],"enable_msg_events":true,"port":36717},"up":true}},{"node":{"info":{"id":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","name":"node_4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","enode":"enode://41e5ef400615590acfce1feaa4f723da88b7fee03c125e8feeb03201c364a22a14bfab06b86ce8c50bbf67843d5c300284b03c113f769c22ec8d0c0efa7bdb88@127.0.0.1:0","enr":"0xf88fb840d9ed9f340c2d0edc3d9f2fb6dc8cab0028f8ad74cb6931445c8752a95d3d1f0905c1ba22a04418eeb093a35bafd184eff3faa6fd110606e175e07ece0216c8930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10241e5ef400615590acfce1feaa4f723da88b7fee03c125e8feeb03201c364a22a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Tk7V+Q3FOZ4zYtJpHLVYevhieuVCxSTi8qEpQouRqJs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4e4ed5\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e59a ec3e ec08 be5d | 35 ec08 (0) ec3e (0) e59a (0) f090 (0)\n001 3 27c2 33fe 0d7f | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 2 7a5c 75bf | 5 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n003 2 5bf6 5b93 | 4 5bf6 (0) 5b87 (0) 5b93 (0) 55a2 (0)\n============ DEPTH: 4 ==========================================\n004 4 46af 4541 4443 404b | 4 404b (0) 4443 (0) 4541 (0) 46af (0)\n005 1 4853 | 1 4853 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","private_key":"30dde001235a31362e50d4c106edd3ceaf6526ef026eca049fedc0a8fc0b96e1","name":"node_4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","services":["streamer"],"enable_msg_events":true,"port":42507},"up":true}},{"node":{"info":{"id":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","name":"node_0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","enode":"enode://91e81df107a4406cac255c8d4ba60fd18e5dcd96fd1cb877eb7024c046b695df3f48d299aeef695da5d4fea7069487cc20c4c48c1fd27528eb3f2f627b952342@127.0.0.1:0","enr":"0xf88fb8401644e0ac4bf24a23935aa075cfd9c4d6d785825325cbf7a21768c96abc96a92e5f47057330b9c09e916850fddfb4b3d689a4a0b98ba012c7b01e0123da1726900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10291e81df107a4406cac255c8d4ba60fd18e5dcd96fd1cb877eb7024c046b695df","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DX9KZirMctL+2ZnhOIDNEHDXu4aKku40OlLc+EzwY5U=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d7f4a\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 dd48 f16d f1e1 8cb7 | 35 f1e1 (0) f16d (0) f090 (0) f6f3 (0)\n001 3 55a2 4541 4e4e | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 2 2b79 2293 | 6 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n003 2 1a93 12b8 | 4 10d5 (0) 12b8 (0) 1a93 (0) 1dd4 (0)\n004 1 041c | 1 041c (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 0e8f 0f03 | 2 0f03 (0) 0e8f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","private_key":"52ff6622d57b5556228f56e411af84d7d5e876ec0b0ef9a3910cf4dacf19295a","name":"node_0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","services":["streamer"],"enable_msg_events":true,"port":35159},"up":true}},{"node":{"info":{"id":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","name":"node_adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","enode":"enode://b05e0fa469e2a12f94369fc64122362af6019a567958df1faa114a1d2c667a835201b99b789eff01bddf4da25a4801ca96f3eaa056156808eeff5f4ecbd9cd36@127.0.0.1:0","enr":"0xf88fb840e775dd44d761e5b3b2c18b047cd086b5c5ca6dbba08ba0744c495cde6f289bf958930628ace3e04c30d4347c0ed18bcc9d021bcc5bfa395a05423d6042f5fe600183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b05e0fa469e2a12f94369fc64122362af6019a567958df1faa114a1d2c667a83","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rf0mQdjlet4ua4AsvrDAtzNkMKZ9HR86vFFStN8Ga5E=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: adfd26\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5b87 5bf6 0d7f | 29 5bf6 (0) 5b87 (0) 5b93 (0) 55a2 (0)\n001 2 f1e1 ff06 | 21 f1e1 (0) f16d (0) f090 (0) f6f3 (0)\n002 3 8934 83aa 9009 | 6 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n003 3 bbbc bc3e b269 | 4 b269 (0) bbbc (0) be5d (0) bc3e (0)\n004 1 a259 | 1 a259 (0)\n============ DEPTH: 5 ==========================================\n005 1 ab25 | 1 ab25 (0)\n006 1 aeff | 1 aeff (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","private_key":"0315f5fb99c9777433fed108cc4c6deb7db717796e405b5e6a3aa389299b87b4","name":"node_adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","services":["streamer"],"enable_msg_events":true,"port":35001},"up":true}},{"node":{"info":{"id":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","name":"node_9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","enode":"enode://093522f714ffd69ed9f6db15bb1cde0bc555925225a9e372b375bd301de6cb9d950b7b8c0b78c4de65bbeee2cd2ac0dcb1901f0bc3de835e1a24d76ca813c2ae@127.0.0.1:0","enr":"0xf88fb840c1c3fa0a54f8946b866c65b93538aac7322c9d5b26aff75c0dd8033fde1dde1627786a0478d2407b93c96f661b093b4a13d1aa4b5bd03a067492d76988b6a6800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102093522f714ffd69ed9f6db15bb1cde0bc555925225a9e372b375bd301de6cb9d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kAnO8yucxC6XuBK6OjW5d9pdNzmQu5UhpRbflGZAHV0=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9009ce\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 27c2 33fe 62c0 | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 3 ce82 de4f ff06 | 21 d165 (0) de4f (0) dd48 (0) dbef (0)\n002 2 bc3e adfd | 8 b269 (0) bbbc (0) be5d (0) bc3e (0)\n003 3 83aa 8934 8cb7 | 3 83aa (0) 8934 (0) 8cb7 (0)\n============ DEPTH: 4 ==========================================\n004 1 9861 | 1 9861 (0)\n005 1 9637 | 1 9637 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","private_key":"1bc6fe30378e57ca0c15b6f6f5f2d74ba8cdafbe43f76592ab80c52dc0f52728","name":"node_9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","services":["streamer"],"enable_msg_events":true,"port":35487},"up":true}},{"node":{"info":{"id":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","name":"node_62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","enode":"enode://c81f541ba227667d8becb3345c579943bfbb3a8bcd62b439cb005efda334f6c8c1d6d2af9fa49dad450a5875a0646b9a04f7083c19087bd7c433ab3db9094628@127.0.0.1:0","enr":"0xf88fb8403f4920feda458e968679a926fd71a565a684927ea66ae2650f2db9bd6c6ee43e1fc9cd1d73b370ecd2ba7c6b42518f316edc250d1e926c34b391d1b6480cdb330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c81f541ba227667d8becb3345c579943bfbb3a8bcd62b439cb005efda334f6c8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YsCWkN1xeE4GtDjXxWJW4Ql8Bf5+uDuQ/lsCd6S4hWg=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 62c096\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 de4f dbef c34b e59a | 35 d165 (0) de4f (0) dd48 (0) dbef (0)\n001 6 0f03 041c 12b8 1a93 | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 7 4853 404b 4443 4541 | 10 5b87 (0) 5b93 (0) 5bf6 (0) 55a2 (0)\n003 2 75bf 7a5c | 2 7a5c (0) 75bf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 6049 | 1 6049 (0)\n007 0 | 0\n008 1 6271 | 1 6271 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","private_key":"269dd3ac6136b86cb9f66421970333cf6b067b5e2ad659c74a12a454391a781b","name":"node_62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","services":["streamer"],"enable_msg_events":true,"port":43131},"up":true}},{"node":{"info":{"id":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","name":"node_e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","enode":"enode://f5fe3b4e018db5568948b9ef30185053e250d458a82b652689af29835dd52c49183ff839f32d445eb8106cc99df2f214878755161589f635c59336b92e24fdad@127.0.0.1:0","enr":"0xf88fb840a740cd0c6245b675fe0d492a0d4d735796337ec26f5662c4f9da84de9e48a03f5558dc622db428dea3a93145610b4c70871ada7d76383a1148c2343ac86a40bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f5fe3b4e018db5568948b9ef30185053e250d458a82b652689af29835dd52c49","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5Zp0tlcJzZ521NUx0HioowVQYe3cTVFa/7/A+ZyuIqw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e59a74\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1dd4 4e4e 6049 62c0 | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 4 a259 83aa 8934 8cb7 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 5 c62e c851 ce82 de4f | 12 d165 (0) dbef (0) d87b (0) de4f (0)\n003 4 fef2 f16d f1e1 f090 | 6 f090 (0) f1e1 (0) f16d (0) f6f3 (0)\n============ DEPTH: 4 ==========================================\n004 2 ec3e ec08 | 2 ec08 (0) ec3e (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","private_key":"6e4dcbf79fca1a42fc07f76fb66b645ff15ad89bf3b5ee627bc4294089d2770b","name":"node_e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","services":["streamer"],"enable_msg_events":true,"port":41179},"up":true}},{"node":{"info":{"id":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","name":"node_1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","enode":"enode://091c7d3991885b5205a7ad94190d2c5ca8169b7a2b7cee4fd6892d2dbe13ae3471441239ab4accb7bcd14852193c18d5617b8862678cc87887b11e6d41649b11@127.0.0.1:0","enr":"0xf88fb840c63763385c1eda51cd29a392364bf9f8be18399e4f9607b47bab1b59152f0587723422ca8629675ecacc5ffa0aeb859c37e02ffc2af0369b0979891a56d18e5d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103091c7d3991885b5205a7ad94190d2c5ca8169b7a2b7cee4fd6892d2dbe13ae34","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HdTCyNrGRlJrGv0YfzJnEtp17Xpxdmi/yJx3A6lk1IA=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1dd4c2\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8934 83aa c851 e59a | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 3 5b87 5b93 75bf | 15 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n002 4 2f1a 2293 27c2 33fe | 6 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n003 3 041c 0f03 0e8f | 4 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n============ DEPTH: 4 ==========================================\n004 2 10d5 12b8 | 2 12b8 (0) 10d5 (0)\n005 1 1a93 | 1 1a93 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","private_key":"15434ad1577984b2ae25fc53d127261f8a1d1b643edf1cfe7f49714a1ed8619b","name":"node_1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","services":["streamer"],"enable_msg_events":true,"port":46023},"up":true}},{"node":{"info":{"id":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","name":"node_75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","enode":"enode://5196fd22b79e08c920e19716c9cf53c83634acda9a39d03f9e09e1241417eb955553103a82a5e58351a4696f61b7910bb9ce0e40105fef8f988d891d2b37b63d@127.0.0.1:0","enr":"0xf88fb840924cb202bf2e42bbe4204422d11630c955bb55e1c35949af2ab69a72a890f7c00a9429df6f78ec5295745029133eccea9fdd9c81b7ff637c884cd01bc527398b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035196fd22b79e08c920e19716c9cf53c83634acda9a39d03f9e09e1241417eb95","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"db+IG2rL9RLyq89C5dhqwy5d2EnnpBbjknWXmitr9Do=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 75bf88\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f16d fef2 ec3e c34b | 35 e59a (0) ec08 (0) ec3e (0) f090 (0)\n001 3 2293 10d5 1dd4 | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 3 4e4e 5bf6 5b87 | 10 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n============ DEPTH: 3 ==========================================\n003 3 6049 62c0 6271 | 3 6271 (0) 62c0 (0) 6049 (0)\n004 1 7a5c | 1 7a5c (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","private_key":"1d04f36e8b1b0b6d54f6361f0951803d47e9635eca0750c712509153f7ecf942","name":"node_75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","services":["streamer"],"enable_msg_events":true,"port":35973},"up":true}},{"node":{"info":{"id":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","name":"node_a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","enode":"enode://a475a32447cded8bbb47d0d8fe2373bdd01422752a81c31c2845b8f630c501c57e5e1df81ac50100e84cc9c7c29c7a5217d80933bb076ae900c4e9b39b8d3192@127.0.0.1:0","enr":"0xf88fb840c305671d9a97ae99f8a21d0af8cb920e8343e1157f891978be2c6593c9ccd2b606f3d350e8f146686ba9e55de1988b02886a36cb7782c11fbed93a7a1987a3ff0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a475a32447cded8bbb47d0d8fe2373bdd01422752a81c31c2845b8f630c501c5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"olkE+YxzoJo3A09XnYZBP+Mf2aBSoD10Jmdg1OpzuOk=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a25904\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6049 75bf | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 4 ec3e ec08 e59a f6f3 | 21 e59a (0) ec08 (0) ec3e (0) f090 (0)\n002 2 9637 9861 | 6 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n003 3 b269 bbbc be5d | 4 b269 (0) bbbc (0) be5d (0) bc3e (0)\n============ DEPTH: 4 ==========================================\n004 3 ab25 aeff adfd | 3 ab25 (0) aeff (0) adfd (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","private_key":"9c19a3fae05635da15fc8499e2d30b15ab154d5aebd6e911ffe18c8b9bdf7e06","name":"node_a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","services":["streamer"],"enable_msg_events":true,"port":37579},"up":true}},{"node":{"info":{"id":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","name":"node_604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","enode":"enode://f7775a8758c3725f763c0806ba1d52f74e6b312de69eaf6ed8cc0c7a88625c53e47053e304eb9b567843da94010ca4447b98699a541ba1425f0aa147e444b86e@127.0.0.1:0","enr":"0xf88fb8403f292e1bf244a35875921965cd6bb6dd93bb0241082ee3ebf32a0ed161c646941d2ff14e735c34f9cda2916a1e96e9f80b22d2c60195d45433c614157e330c900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f7775a8758c3725f763c0806ba1d52f74e6b312de69eaf6ed8cc0c7a88625c53","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YEli8AZKyWEqGbRZlk9y2ifFR8cKW/Evuf8++cBsWkE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 604962\npopulation: 27 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 c034 d87b de4f ec3e | 35 e59a (0) ec08 (0) ec3e (0) f090 (0)\n001 7 1a93 10d5 12b8 0f03 | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 6 5b93 5bf6 4853 404b | 10 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n003 2 75bf 7a5c | 2 7a5c (0) 75bf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 62c0 6271 | 2 6271 (0) 62c0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","private_key":"d43fc183927a1d97aee7b09b4977f66657a79a7132440f1085e72dac4f111b29","name":"node_604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","services":["streamer"],"enable_msg_events":true,"port":36711},"up":true}},{"node":{"info":{"id":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","name":"node_46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","enode":"enode://51afc950250580c6016fe6e1cc591b90a31257d89b57df0cee54184ed0fe09c1e5777398b9ea7cbf355e475dff29a8a57cf7af461f2544f09595281730b0421b@127.0.0.1:0","enr":"0xf88fb840c55fc03f59e481c9056bb420d743110b252edb232b677c6eded69cb1f9de070f214517d43e7bd121063ff69d83b53ef77f2cb60ea36ee3fd501c4ce5f941c5d00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10351afc950250580c6016fe6e1cc591b90a31257d89b57df0cee54184ed0fe09c1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rq+9e3Hp9VeBNe9Xxumvrx7ekUJf1YB9ayV+R/k9gwo=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 46afbd\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bbbc b269 c67d | 35 b269 (0) bbbc (0) be5d (0) bc3e (0)\n001 3 2293 27c2 33fe | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 2 7a5c 6049 | 5 7a5c (0) 75bf (0) 6271 (0) 62c0 (0)\n003 2 5b93 5b87 | 4 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n004 2 4e4e 4853 | 2 4853 (0) 4e4e (0)\n005 1 404b | 1 404b (0)\n============ DEPTH: 6 ==========================================\n006 2 4443 4541 | 2 4541 (0) 4443 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","private_key":"c83d6d9cc57a48d84d57d3c6bb8bea3f077d62d280265de50dcd32e06d248f03","name":"node_46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","services":["streamer"],"enable_msg_events":true,"port":34261},"up":true}},{"node":{"info":{"id":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","name":"node_c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","enode":"enode://9f5e3ba7425458e07339268d779ab9edafb03e2b1b67169a1123d0c6082374c60f34ef62398c7fff491e9a586e010737c16cc6fee1c969b773e5d9036bb2d2d5@127.0.0.1:0","enr":"0xf88fb840331107dbd5f067ec688710841e8f2feb84a5139e0b4b8b5fc9e775a99353e7c160a1dfa9939df3d039103b453a571a574a36f7ba55ed3f64ea23917b4f1d48570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039f5e3ba7425458e07339268d779ab9edafb03e2b1b67169a1123d0c6082374c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xn2ygvie5cf+M8zrbWBmcsBPJz+SR0ePMjyCJ/cJty0=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c67db2\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 27c2 33fe 46af | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 2 b269 8cb7 | 14 b269 (0) bbbc (0) be5d (0) bc3e (0)\n002 3 ec08 f1e1 f6f3 | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 d165 dbef | 5 d165 (0) dbef (0) d87b (0) de4f (0)\n004 2 ce82 c851 | 2 c851 (0) ce82 (0)\n============ DEPTH: 5 ==========================================\n005 3 c05d c034 c34b | 3 c34b (0) c034 (0) c05d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 c62e | 1 c62e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","private_key":"c5f0dbfaf1bc89108010b5a6b4fdd44434a9c6f91328d5eadbbfa0108072ccb8","name":"node_c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","services":["streamer"],"enable_msg_events":true,"port":36251},"up":true}},{"node":{"info":{"id":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","name":"node_8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","enode":"enode://de0a8da74b3df44a50a35257ac834a3fe752fa615fb7d9b39d2c716b9b5f7edc32874d826d50224f2e37fb1a07f7526070f08674414124367465abf02cbf5ff4@127.0.0.1:0","enr":"0xf88fb840189409bc37dbd9a8810613dce78f7b24e5c24579fe5ede271045352b0a50969802f6e75f3b631cb61f415fbb4a7a68e994cb620ba81be2ece91909c5f01e673f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102de0a8da74b3df44a50a35257ac834a3fe752fa615fb7d9b39d2c716b9b5f7edc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jLfaTvIVjQfCIsDwjex/m1gDdiP0ZYJLQRmp8lsxoAU=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8cb7da\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5b87 041c 0d7f 0e8f | 29 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n001 9 e59a fef2 f1e1 c851 | 21 ec08 (0) ec3e (0) e59a (0) f090 (0)\n002 2 ab25 be5d | 8 b269 (0) bbbc (0) be5d (0) bc3e (0)\n003 3 9861 9637 9009 | 3 9861 (0) 9637 (0) 9009 (0)\n============ DEPTH: 4 ==========================================\n004 1 83aa | 1 83aa (0)\n005 1 8934 | 1 8934 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","private_key":"6cb4589e98325b9101a5f706969483cdb93fe451d2fe83dcbec1e6fde1986836","name":"node_8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","services":["streamer"],"enable_msg_events":true,"port":38013},"up":true}},{"node":{"info":{"id":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","name":"node_dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","enode":"enode://89555a99503427e59874c6cfce334350add1c85b4b935dad096d2755bb8bda4223becd8f73fc3bda4dc5239d7407dac529cf3f943d1129f29af26dc8c10b04d9@127.0.0.1:0","enr":"0xf88fb8402389226733f4287a4f18cdd6b9ca854dded27d7f7c9cdf1fe5f0ff2b60a3e75a1ea809d39554ccd2b2c97c0b8cff5ea61d51f91c69e821da8b45ed186c4833570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10389555a99503427e59874c6cfce334350add1c85b4b935dad096d2755bb8bda42","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3UgRJxAH+QtkpRt1ivx+vIxa8wbLahuIzNwsyI/ZaEs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dd4811\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0d7f 041c 2b80 | 29 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n001 3 aeff ab25 8cb7 | 14 ab25 (0) aeff (0) adfd (0) a259 (0)\n002 3 ec3e ec08 f6f3 | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 ce82 c851 | 7 c851 (0) ce82 (0) c34b (0) c034 (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 d87b dbef | 2 dbef (0) d87b (0)\n006 1 de4f | 1 de4f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","private_key":"4a8e7f4ee986a36520c7faff2f4957ba20b7db18fd59de5604f3889db1eb8dd9","name":"node_dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","services":["streamer"],"enable_msg_events":true,"port":33135},"up":true}},{"node":{"info":{"id":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","name":"node_2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","enode":"enode://f6640b5930abb9a111010f89da0b40002e956167f60a2bd769b53430ab64bdce724abbd610813dc99a92fbe4e15cc33c164bb6ae05e965490ebd84c5cfecf306@127.0.0.1:0","enr":"0xf88fb840f9d875b3913769d2201f5c0a0b1dddddb9416184e14f986671f98b799fb7bc7c3b1853a972ca0dce95c27a7f6195e3f8fd87da8e9708d9ce4b224e940a2d319b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f6640b5930abb9a111010f89da0b40002e956167f60a2bd769b53430ab64bdce","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"K4BPbSojVEHPC1tSp/sqqGLIRRDtSC8KWuySxNiatIQ=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2b804f\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9637 9861 dd48 | 35 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n001 3 4443 5bf6 55a2 | 15 6049 (0) 6271 (0) 62c0 (0) 7a5c (0)\n002 2 041c 0f03 | 8 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n003 1 33fe | 1 33fe (0)\n004 2 2293 27c2 | 2 27c2 (0) 2293 (0)\n============ DEPTH: 5 ==========================================\n005 1 2f1a | 1 2f1a (0)\n006 0 | 0\n007 0 | 0\n008 1 2b79 | 1 2b79 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","private_key":"482d8c479e055a2cd97d27a00578bfbe177ae0ca405f9b3a2a08e55ad11f0da8","name":"node_2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","services":["streamer"],"enable_msg_events":true,"port":42125},"up":true}},{"node":{"info":{"id":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","name":"node_55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","enode":"enode://0e1f60835d710b5bce7825c96b4002cfe63ef0308ad175b5e4e4bcf6fbf5187d01c5b296ce5a87affae58239bbbd0d8bbd425a558e2d5eee41d6cddbea15b939@127.0.0.1:0","enr":"0xf88fb84058ce2d6dde0e4febc7e1b9b68901a2399228ed0dc3972db83041f6511414997e295b9340c70b1cb50884a5dd3f193a346b3aac3f8d2d860c2ef0066ad6315cbe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030e1f60835d710b5bce7825c96b4002cfe63ef0308ad175b5e4e4bcf6fbf5187d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VaJDtL33j/JGBTPFIWILEbTOqmejyWdg4qn6zGcn9Q8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 55a243\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9637 9861 ce82 | 35 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n001 3 0d7f 041c 2b80 | 14 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n002 2 6271 62c0 | 5 6049 (0) 62c0 (0) 6271 (0) 7a5c (0)\n003 4 4853 404b 4541 4443 | 6 46af (0) 4541 (0) 4443 (0) 404b (0)\n============ DEPTH: 4 ==========================================\n004 3 5b87 5b93 5bf6 | 3 5b87 (0) 5b93 (0) 5bf6 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","private_key":"22bc669edb33e88cc2edf332fe24eeb77672294a38ee9ad3fa4a1cc3a2b6c916","name":"node_55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","services":["streamer"],"enable_msg_events":true,"port":35969},"up":true}},{"node":{"info":{"id":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","name":"node_ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","enode":"enode://a7e3b7f8243c44f711eaa63305c75e94cc5c280f85bba57a8153591777c08edd2c46d54768f3e3be5682ceb74a4b7d51c3404faadcead2f9abf0fca9e08496d9@127.0.0.1:0","enr":"0xf88fb84089be519b3e126e4daefeb96ab3a6fad77d8957bcec90ad01848bdae2a1158d7b0625a8ca5453dbac3b83c87abe19b7ee6d9db1a0a469dd9455c871eddc751eef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a7e3b7f8243c44f711eaa63305c75e94cc5c280f85bba57a8153591777c08edd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zoK5gFv6We8/GLRtXi2MRRPhM/hlAN+DtV4TMxrkKYw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ce82b9\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1a93 4443 4853 55a2 | 29 33fe (0) 2293 (0) 27c2 (0) 2f1a (0)\n001 5 aeff 83aa 9861 9009 | 14 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n002 4 f16d e59a ec3e ec08 | 9 e59a (0) ec3e (0) ec08 (0) f090 (0)\n003 2 d165 dd48 | 5 d165 (0) dbef (0) d87b (0) de4f (0)\n============ DEPTH: 4 ==========================================\n004 5 c62e c67d c34b c034 | 5 c34b (0) c034 (0) c05d (0) c67d (0)\n005 1 c851 | 1 c851 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","private_key":"755137d90f904038ad62a2a3a4c884831de662050430fc5bc44c0e776122f890","name":"node_ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","services":["streamer"],"enable_msg_events":true,"port":34417},"up":true}},{"node":{"info":{"id":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","name":"node_1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","enode":"enode://6441a0fb862b2ad19dca82baf54880795e459ccb977d3dec2f5945041080887d4e18924c1f76a70f0cc6aa5e516d4bff2813cba7fd94f9f5990af5d7ba081ba2@127.0.0.1:0","enr":"0xf88fb84089526e1437560f8885e8dec6fdcb7f89033526e82f59e94698507fa850c9e19a3fb9333403aa92eb996e936774dcf266d18fc8c2210f28637ab27102e7f5d0390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026441a0fb862b2ad19dca82baf54880795e459ccb977d3dec2f5945041080887d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GpMQvGFQXQjEWOq6DnzRtcHnpk4A/LogNNoaF6L6oVw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1a9310\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 bc3e d165 c851 ce82 | 35 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n001 3 6049 6271 62c0 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 2f1a 2293 33fe | 6 33fe (0) 2293 (0) 27c2 (0) 2f1a (0)\n003 4 041c 0e8f 0f03 0d7f | 4 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n============ DEPTH: 4 ==========================================\n004 2 10d5 12b8 | 2 12b8 (0) 10d5 (0)\n005 1 1dd4 | 1 1dd4 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","private_key":"3d1bc8c36e5611d1524cba438ab612087f7fe9210a0ddb9f80b7bb94bebf28d0","name":"node_1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","services":["streamer"],"enable_msg_events":true,"port":38755},"up":true}},{"node":{"info":{"id":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","name":"node_bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","enode":"enode://c8fb04e5496759ed67612814155cdc9e564c33e6151e1328db3e3d733ef3be481febd2026453482338b6cf323c0293a196cc120abffb4ee215877ecce683dcea@127.0.0.1:0","enr":"0xf88fb8409592035288ec2ea45833c8d7fcd2795780db3698a74d8f87077300514fcd2205330b0bab53a6dfebdf54779337d6761e4bf024cc5038e4dd4a9f7941eb7d19570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c8fb04e5496759ed67612814155cdc9e564c33e6151e1328db3e3d733ef3be48","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vD4H7gmLrdc5xOm5ZSdfb79jMfdraSCJYErEQCXPC8w=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bc3e07\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6049 5b93 1a93 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 ec08 c034 de4f | 21 e59a (0) ec3e (0) ec08 (0) f1e1 (0)\n002 2 83aa 9009 | 6 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n003 2 ab25 adfd | 4 aeff (0) adfd (0) ab25 (0) a259 (0)\n004 1 b269 | 1 b269 (0)\n============ DEPTH: 5 ==========================================\n005 1 bbbc | 1 bbbc (0)\n006 1 be5d | 1 be5d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","private_key":"aedc9b1c86a50c21ebc168086896d03dc0ff1d2d366426a35678be1bb1f8cd46","name":"node_bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","services":["streamer"],"enable_msg_events":true,"port":38905},"up":true}},{"node":{"info":{"id":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","name":"node_de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","enode":"enode://9f62e657f5258fdc9d473a088077877e003e1ad5e336214b8517cafa34581a7b83eeb731bdaeaee23b09a1739c0c1cbfc75fd0715b014baf301c3ce66dea9210@127.0.0.1:0","enr":"0xf88fb8403b3bfb23ac7a5fe81b2cac041477fe3f148ec11dce658a17042c6be5047af9766810b4b7d33d10350eef6ae57c979f6400cdb549c72f79b6d1938b73ed206c5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029f62e657f5258fdc9d473a088077877e003e1ad5e336214b8517cafa34581a7b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3k8Wi3tnDBNI2AHbcNmp5/pE3XKQMLpcBd+WI5Z8QLE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: de4f16\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6049 6271 62c0 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 2 9009 bc3e | 14 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n002 3 ec3e e59a ff06 | 9 e59a (0) ec3e (0) ec08 (0) f1e1 (0)\n003 2 c034 c05d | 7 ce82 (0) c851 (0) c34b (0) c034 (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 d87b dbef | 2 d87b (0) dbef (0)\n006 1 dd48 | 1 dd48 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","private_key":"56f97537df39cd2e28da49629a002972b36e5ac32df3a117fa710b9cabe52aa8","name":"node_de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","services":["streamer"],"enable_msg_events":true,"port":46139},"up":true}},{"node":{"info":{"id":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","name":"node_ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","enode":"enode://cb17dde808303f1bbd012517614e105867070959f82e17c94a6af3d5ac085fb14656af8db156f67f5f64480d8221e11c6f8b172b785e6e9c57848833f437b8d8@127.0.0.1:0","enr":"0xf88fb840d2fed0376fa9577d9adabbeb81ace57c4cbf4073222b71a010f99d6b9c4228fc2ad8ec5bcefbfce0225b7f05d0e59e4b02c99cec57387ef602959f4b90d9ed820183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cb17dde808303f1bbd012517614e105867070959f82e17c94a6af3d5ac085fb1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/wbWzDUh0gwKm813nIcvV2AjyOqvrXKJhkFAsxOlxHs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ff06d6\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 404b 27c2 33fe | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 2 9009 adfd | 14 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n002 3 c034 d165 de4f | 12 ce82 (0) c851 (0) c34b (0) c05d (0)\n003 2 ec3e ec08 | 3 e59a (0) ec3e (0) ec08 (0)\n============ DEPTH: 4 ==========================================\n004 4 f6f3 f090 f1e1 f16d | 4 f1e1 (0) f16d (0) f090 (0) f6f3 (0)\n005 0 | 0\n006 0 | 0\n007 1 fef2 | 1 fef2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","private_key":"a519551fcbce37d32e6dbc7b4489172d0fb096ebd57e6ee332422c809ae61862","name":"node_ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","services":["streamer"],"enable_msg_events":true,"port":45295},"up":true}}],"conns":[{"one":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","other":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","other":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/visualized_snapshot_sync_sim_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/visualized_snapshot_sync_sim_test.go deleted file mode 100644 index 437c17e5..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network/stream/visualized_snapshot_sync_sim_test.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build withserver - -package stream - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -/* -The tests in this file need to be executed with - - -tags=withserver - -Also, they will stall if executed stand-alone, because they wait -for the visualization frontend to send a POST /runsim message. -*/ - -//setup the sim, evaluate nodeCount and chunkCount and create the sim -func setupSim(serviceMap map[string]simulation.ServiceFunc) (int, int, *simulation.Simulation) { - nodeCount := *nodes - chunkCount := *chunks - - if nodeCount == 0 || chunkCount == 0 { - nodeCount = 32 - chunkCount = 1 - } - - //setup the simulation with server, which means the sim won't run - //until it receives a POST /runsim from the frontend - sim := simulation.New(serviceMap).WithServer(":8888") - return nodeCount, chunkCount, sim -} - -//watch for disconnections and wait for healthy -func watchSim(sim *simulation.Simulation) (context.Context, context.CancelFunc) { - ctx, cancelSimRun := context.WithTimeout(context.Background(), 1*time.Minute) - - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { - panic(err) - } - - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), - ) - - go func() { - for d := range disconnections { - log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) - panic("unexpected disconnect") - cancelSimRun() - } - }() - - return ctx, cancelSimRun -} - -//This test requests bogus hashes into the network -func TestNonExistingHashesWithServer(t *testing.T) { - nodeCount, _, sim := setupSim(retrievalSimServiceMap) - defer sim.Close() - - err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) - if err != nil { - panic(err) - } - - ctx, cancelSimRun := watchSim(sim) - defer cancelSimRun() - - //in order to get some meaningful visualization, it is beneficial - //to define a minimum duration of this test - testDuration := 20 * time.Second - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - //check on the node's FileStore (netstore) - id := sim.RandomUpNode().ID - item, ok := sim.NodeItem(id, bucketKeyFileStore) - if !ok { - t.Fatalf("No filestore") - } - fileStore := item.(*storage.FileStore) - //create a bogus hash - fakeHash := storage.GenerateRandomChunk(1000).Address() - //try to retrieve it - will propagate RetrieveRequestMsg into the network - reader, _ := fileStore.Retrieve(context.TODO(), fakeHash) - if _, err := reader.Size(ctx, nil); err != nil { - log.Debug("expected error for non-existing chunk") - } - //sleep so that the frontend can have something to display - time.Sleep(testDuration) - - return nil - }) - if result.Error != nil { - sendSimTerminatedEvent(sim) - t.Fatal(result.Error) - } - - sendSimTerminatedEvent(sim) - -} - -//send a termination event to the frontend -func sendSimTerminatedEvent(sim *simulation.Simulation) { - evt := &simulations.Event{ - Type: EventTypeSimTerminated, - Control: false, - } - sim.Net.Events().Send(evt) -} - -//This test is the same as the snapshot sync test, -//but with a HTTP server -//It also sends some custom events so that the frontend -//can visualize messages like SendOfferedMsg, WantedHashesMsg, DeliveryMsg -func TestSnapshotSyncWithServer(t *testing.T) { - - nodeCount, chunkCount, sim := setupSim(simServiceMap) - defer sim.Close() - - log.Info("Initializing test config") - - conf := &synctestConfig{} - //map of discover ID to indexes of chunks expected at that ID - conf.idToChunksMap = make(map[discover.NodeID][]int) - //map of overlay address to discover ID - conf.addrToIDMap = make(map[string]discover.NodeID) - //array where the generated chunk hashes will be stored - conf.hashes = make([]storage.Address, 0) - - err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) - if err != nil { - panic(err) - } - - ctx, cancelSimRun := watchSim(sim) - defer cancelSimRun() - - //setup filters in the event feed - offeredHashesFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(1) - wantedFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(2) - deliveryFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(6) - eventC := sim.PeerEvents(ctx, sim.UpNodeIDs(), offeredHashesFilter, wantedFilter, deliveryFilter) - - quit := make(chan struct{}) - - go func() { - for e := range eventC { - select { - case <-quit: - fmt.Println("quitting event loop") - return - default: - } - if e.Error != nil { - t.Fatal(e.Error) - } - if *e.Event.MsgCode == uint64(1) { - evt := &simulations.Event{ - Type: EventTypeChunkOffered, - Node: sim.Net.GetNode(e.NodeID), - Control: false, - } - sim.Net.Events().Send(evt) - } else if *e.Event.MsgCode == uint64(2) { - evt := &simulations.Event{ - Type: EventTypeChunkWanted, - Node: sim.Net.GetNode(e.NodeID), - Control: false, - } - sim.Net.Events().Send(evt) - } else if *e.Event.MsgCode == uint64(6) { - evt := &simulations.Event{ - Type: EventTypeChunkDelivered, - Node: sim.Net.GetNode(e.NodeID), - Control: false, - } - sim.Net.Events().Send(evt) - } - } - }() - //run the sim - result := runSim(conf, ctx, sim, chunkCount) - - //send terminated event - evt := &simulations.Event{ - Type: EventTypeSimTerminated, - Control: false, - } - sim.Net.Events().Send(evt) - - if result.Error != nil { - panic(result.Error) - } - close(quit) - log.Info("Simulation ended") -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/network_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/network_test.go index d84f2814..97bdd07b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/network_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/network_test.go @@ -28,6 +28,8 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/swarm/testutil" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -36,7 +38,7 @@ import ( "github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/network/simulation" "github.com/ethereum/go-ethereum/swarm/storage" - colorable "github.com/mattn/go-colorable" + "github.com/mattn/go-colorable" ) var ( @@ -57,12 +59,7 @@ func init() { // static and dynamic Swarm nodes in network simulation, by // uploading files to every node and retrieving them. func TestSwarmNetwork(t *testing.T) { - for _, tc := range []struct { - name string - steps []testSwarmNetworkStep - options *testSwarmNetworkOptions - disabled bool - }{ + var tests = []testSwarmNetworkCase{ { name: "10_nodes", steps: []testSwarmNetworkStep{ @@ -86,6 +83,61 @@ func TestSwarmNetwork(t *testing.T) { SkipCheck: true, }, }, + { + name: "dec_inc_node_count", + steps: []testSwarmNetworkStep{ + { + nodeCount: 3, + }, + { + nodeCount: 1, + }, + { + nodeCount: 5, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 90 * time.Second, + }, + }, + } + + if *longrunning { + tests = append(tests, longRunningCases()...) + } else if testutil.RaceEnabled { + tests = shortCaseForRace() + + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + testSwarmNetwork(t, tc.options, tc.steps...) + }) + } +} + +type testSwarmNetworkCase struct { + name string + steps []testSwarmNetworkStep + options *testSwarmNetworkOptions +} + +// testSwarmNetworkStep is the configuration +// for the state of the simulation network. +type testSwarmNetworkStep struct { + // number of swarm nodes that must be in the Up state + nodeCount int +} + +// testSwarmNetworkOptions contains optional parameters for running +// testSwarmNetwork. +type testSwarmNetworkOptions struct { + Timeout time.Duration + SkipCheck bool +} + +func longRunningCases() []testSwarmNetworkCase { + return []testSwarmNetworkCase{ { name: "50_nodes", steps: []testSwarmNetworkStep{ @@ -96,7 +148,6 @@ func TestSwarmNetwork(t *testing.T) { options: &testSwarmNetworkOptions{ Timeout: 3 * time.Minute, }, - disabled: !*longrunning, }, { name: "50_nodes_skip_check", @@ -109,7 +160,6 @@ func TestSwarmNetwork(t *testing.T) { Timeout: 3 * time.Minute, SkipCheck: true, }, - disabled: !*longrunning, }, { name: "inc_node_count", @@ -127,7 +177,6 @@ func TestSwarmNetwork(t *testing.T) { options: &testSwarmNetworkOptions{ Timeout: 90 * time.Second, }, - disabled: !*longrunning, }, { name: "dec_node_count", @@ -145,24 +194,6 @@ func TestSwarmNetwork(t *testing.T) { options: &testSwarmNetworkOptions{ Timeout: 90 * time.Second, }, - disabled: !*longrunning, - }, - { - name: "dec_inc_node_count", - steps: []testSwarmNetworkStep{ - { - nodeCount: 3, - }, - { - nodeCount: 1, - }, - { - nodeCount: 5, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 90 * time.Second, - }, }, { name: "inc_dec_node_count", @@ -186,7 +217,6 @@ func TestSwarmNetwork(t *testing.T) { options: &testSwarmNetworkOptions{ Timeout: 5 * time.Minute, }, - disabled: !*longrunning, }, { name: "inc_dec_node_count_skip_check", @@ -211,23 +241,25 @@ func TestSwarmNetwork(t *testing.T) { Timeout: 5 * time.Minute, SkipCheck: true, }, - disabled: !*longrunning, }, - } { - if tc.disabled { - continue - } - t.Run(tc.name, func(t *testing.T) { - testSwarmNetwork(t, tc.options, tc.steps...) - }) } } -// testSwarmNetworkStep is the configuration -// for the state of the simulation network. -type testSwarmNetworkStep struct { - // number of swarm nodes that must be in the Up state - nodeCount int +func shortCaseForRace() []testSwarmNetworkCase { + // As for now, Travis with -race can only run 8 nodes + return []testSwarmNetworkCase{ + { + name: "8_nodes", + steps: []testSwarmNetworkStep{ + { + nodeCount: 8, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 1 * time.Minute, + }, + }, + } } // file represents the file uploaded on a particular node. @@ -244,13 +276,6 @@ type check struct { nodeID enode.ID } -// testSwarmNetworkOptions contains optional parameters for running -// testSwarmNetwork. -type testSwarmNetworkOptions struct { - Timeout time.Duration - SkipCheck bool -} - // testSwarmNetwork is a helper function used for testing different // static and dynamic Swarm network simulations. // It is responsible for: @@ -259,6 +284,8 @@ type testSwarmNetworkOptions struct { // - May wait for Kademlia on every node to be healthy. // - Checking if a file is retrievable from all nodes. func testSwarmNetwork(t *testing.T, o *testSwarmNetworkOptions, steps ...testSwarmNetworkStep) { + t.Helper() + if o == nil { o = new(testSwarmNetworkOptions) } @@ -284,8 +311,12 @@ func testSwarmNetwork(t *testing.T, o *testSwarmNetworkOptions, steps ...testSwa if err != nil { return nil, cleanup, err } + nodekey, err := crypto.GenerateKey() + if err != nil { + return nil, cleanup, err + } - config.Init(privkey) + config.Init(privkey, nodekey) config.DeliverySkipCheck = o.SkipCheck config.Port = "" @@ -352,7 +383,7 @@ func testSwarmNetwork(t *testing.T, o *testSwarmNetworkOptions, steps ...testSwa } if *waitKademlia { - if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { + if _, err := sim.WaitTillHealthy(ctx); err != nil { return err } } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pot/address.go b/vendor/github.com/ethereum/go-ethereum/swarm/pot/address.go index 728dac14..91cada2e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pot/address.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pot/address.go @@ -41,10 +41,6 @@ func NewAddressFromBytes(b []byte) Address { return Address(h) } -func (a Address) IsZero() bool { - return a.Bin() == zerosBin -} - func (a Address) String() string { return fmt.Sprintf("%x", a[:]) } @@ -166,7 +162,6 @@ func ToBytes(v Val) []byte { } // DefaultPof returns a proximity order comparison operator function -// where all func DefaultPof(max int) func(one, other Val, pos int) (int, bool) { return func(one, other Val, pos int) (int, bool) { po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos) @@ -178,6 +173,9 @@ func DefaultPof(max int) func(one, other Val, pos int) (int, bool) { } } +// proximityOrder returns two parameters: +// 1. relative proximity order of the arguments one & other; +// 2. boolean indicating whether the full match occurred (one == other). func proximityOrder(one, other []byte, pos int) (int, bool) { for i := pos / 8; i < len(one); i++ { if one[i] == other[i] { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot.go b/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot.go index dfda8480..7e3967f3 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot.go @@ -144,13 +144,10 @@ func add(t *Pot, val Val, pof Pof) (*Pot, int, bool) { return r, po, found } -// Remove called on (v) deletes v from the Pot and returns -// the proximity order of v and a boolean value indicating -// if the value was found -// Remove called on (t, v) returns a new Pot that contains all the elements of t -// minus the value v, using the applicative remove -// the second return value is the proximity order of the inserted element -// the third is boolean indicating if the item was found +// Remove deletes element v from the Pot t and returns three parameters: +// 1. new Pot that contains all the elements of t minus the element v; +// 2. proximity order of the removed element v; +// 3. boolean indicating whether the item was found. func Remove(t *Pot, v Val, pof Pof) (*Pot, int, bool) { return remove(t, v, pof) } @@ -161,10 +158,7 @@ func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) { if found { size-- if size == 0 { - r = &Pot{ - po: t.po, - } - return r, po, true + return &Pot{}, po, true } i := len(t.bins) - 1 last := t.bins[i] @@ -201,7 +195,7 @@ func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) { } bins = append(bins, t.bins[j:]...) r = &Pot{ - pin: val, + pin: t.pin, size: size, po: t.po, bins: bins, @@ -453,64 +447,50 @@ func union(t0, t1 *Pot, pof Pof) (*Pot, int) { return n, common } -// Each called with (f) is a synchronous iterator over the bins of a node -// respecting an ordering -// proximity > pinnedness -func (t *Pot) Each(f func(Val, int) bool) bool { +// Each is a synchronous iterator over the elements of pot with function f. +func (t *Pot) Each(f func(Val) bool) bool { return t.each(f) } -func (t *Pot) each(f func(Val, int) bool) bool { - var next bool - for _, n := range t.bins { - if n == nil { - return true - } - next = n.each(f) - if !next { - return false - } - } - if t.size == 0 { +// each is a synchronous iterator over the elements of pot with function f. +// the iteration ends if the function return false or there are no more elements. +func (t *Pot) each(f func(Val) bool) bool { + if t == nil || t.size == 0 { return false } - return f(t.pin, t.po) -} - -// EachFrom called with (f, start) is a synchronous iterator over the elements of a Pot -// within the inclusive range starting from proximity order start -// the function argument is passed the value and the proximity order wrt the root pin -// it does NOT include the pinned item of the root -// respecting an ordering -// proximity > pinnedness -// the iteration ends if the function return false or there are no more elements -// end of a po range can be implemented since po is passed to the function -func (t *Pot) EachFrom(f func(Val, int) bool, po int) bool { - return t.eachFrom(f, po) -} - -func (t *Pot) eachFrom(f func(Val, int) bool, po int) bool { - var next bool - _, lim := t.getPos(po) - for i := lim; i < len(t.bins); i++ { - n := t.bins[i] - next = n.each(f) - if !next { + for _, n := range t.bins { + if !n.each(f) { return false } } - return f(t.pin, t.po) + return f(t.pin) +} + +// eachFrom is a synchronous iterator over the elements of pot with function f, +// starting from certain proximity order po, which is passed as a second parameter. +// the iteration ends if the function return false or there are no more elements. +func (t *Pot) eachFrom(f func(Val) bool, po int) bool { + if t == nil || t.size == 0 { + return false + } + _, beg := t.getPos(po) + for i := beg; i < len(t.bins); i++ { + if !t.bins[i].each(f) { + return false + } + } + return f(t.pin) } // EachBin iterates over bins of the pivot node and offers iterators to the caller on each // subtree passing the proximity order and the size // the iteration continues until the function's return value is false // or there are no more subtries -func (t *Pot) EachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) { +func (t *Pot) EachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val) bool) bool) bool) { t.eachBin(val, pof, po, f) } -func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) { +func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val) bool) bool) bool) { if t == nil || t.size == 0 { return } @@ -530,8 +510,8 @@ func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val V } if lim == len(t.bins) { if spr >= po { - f(spr, 1, func(g func(Val, int) bool) bool { - return g(t.pin, spr) + f(spr, 1, func(g func(Val) bool) bool { + return g(t.pin) }) } return @@ -545,9 +525,9 @@ func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val V size += n.size } if spr >= po { - if !f(spr, t.size-size, func(g func(Val, int) bool) bool { - return t.eachFrom(func(v Val, j int) bool { - return g(v, spr) + if !f(spr, t.size-size, func(g func(Val) bool) bool { + return t.eachFrom(func(v Val) bool { + return g(v) }, spo) }) { return @@ -595,7 +575,7 @@ func (t *Pot) eachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool { } for i := l - 1; i > ir; i-- { - next = t.bins[i].each(func(v Val, _ int) bool { + next = t.bins[i].each(func(v Val) bool { return f(v, po) }) if !next { @@ -605,7 +585,7 @@ func (t *Pot) eachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool { for i := il - 1; i >= 0; i-- { n := t.bins[i] - next = n.each(func(v Val, _ int) bool { + next = n.each(func(v Val) bool { return f(v, n.po) }) if !next { @@ -719,7 +699,7 @@ func (t *Pot) eachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(V wg.Add(m) } go func(pn *Pot, pm int) { - pn.each(func(v Val, _ int) bool { + pn.each(func(v Val) bool { if wg != nil { defer wg.Done() } @@ -746,7 +726,7 @@ func (t *Pot) eachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(V wg.Add(m) } go func(pn *Pot, pm int) { - pn.each(func(v Val, _ int) bool { + pn.each(func(v Val) bool { if wg != nil { defer wg.Done() } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot_test.go index aeb23dfc..83d60491 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pot/pot_test.go @@ -65,14 +65,13 @@ func randomtestAddr(n int, i int) *testAddr { return newTestAddr(v, i) } -func indexes(t *Pot) (i []int, po []int) { - t.Each(func(v Val, p int) bool { +func indexes(t *Pot) (i []int) { + t.Each(func(v Val) bool { a := v.(*testAddr) i = append(i, a.i) - po = append(po, p) return true }) - return i, po + return i } func testAdd(t *Pot, pof Pof, j int, values ...string) (_ *Pot, n int, f bool) { @@ -82,6 +81,69 @@ func testAdd(t *Pot, pof Pof, j int, values ...string) (_ *Pot, n int, f bool) { return t, n, f } +// removing non-existing element from pot +func TestPotRemoveNonExisting(t *testing.T) { + pof := DefaultPof(8) + n := NewPot(newTestAddr("00111100", 0), 0) + n, _, _ = Remove(n, newTestAddr("00000101", 0), pof) + exp := "00111100" + got := Label(n.Pin()) + if got[:8] != exp { + t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got[:8]) + } +} + +// this test creates hierarchical pot tree, and therefore any child node will have +// child_po = parent_po + 1. +// then removes a node from the middle of the tree. +func TestPotRemoveSameBin(t *testing.T) { + pof := DefaultPof(8) + n := NewPot(newTestAddr("11111111", 0), 0) + n, _, _ = testAdd(n, pof, 1, "00000000", "01000000", "01100000", "01110000", "01111000") + n, _, _ = Remove(n, newTestAddr("01110000", 0), pof) + inds := indexes(n) + goti := n.Size() + expi := 5 + if goti != expi { + t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) + } + inds = indexes(n) + got := fmt.Sprintf("%v", inds) + exp := "[5 3 2 1 0]" + if got != exp { + t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) + } +} + +// this test creates a flat pot tree (all the elements are leafs of one root), +// and therefore they all have the same po. +// then removes an arbitrary element from the pot. +func TestPotRemoveDifferentBins(t *testing.T) { + pof := DefaultPof(8) + n := NewPot(newTestAddr("11111111", 0), 0) + n, _, _ = testAdd(n, pof, 1, "00000000", "10000000", "11000000", "11100000", "11110000") + n, _, _ = Remove(n, newTestAddr("11100000", 0), pof) + inds := indexes(n) + goti := n.Size() + expi := 5 + if goti != expi { + t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) + } + inds = indexes(n) + got := fmt.Sprintf("%v", inds) + exp := "[1 2 3 5 0]" + if got != exp { + t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) + } + n, _, _ = testAdd(n, pof, 4, "11100000") + inds = indexes(n) + got = fmt.Sprintf("%v", inds) + exp = "[1 2 3 4 5 0]" + if got != exp { + t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) + } +} + func TestPotAdd(t *testing.T) { pof := DefaultPof(8) n := NewPot(newTestAddr("00111100", 0), 0) @@ -105,17 +167,12 @@ func TestPotAdd(t *testing.T) { if goti != expi { t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) } - inds, po := indexes(n) + inds := indexes(n) got = fmt.Sprintf("%v", inds) exp = "[3 4 2]" if got != exp { t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) } - got = fmt.Sprintf("%v", po) - exp = "[1 2 0]" - if got != exp { - t.Fatalf("incorrect po-s in iteration over Pot. Expected %v, got %v", exp, got) - } } func TestPotRemove(t *testing.T) { @@ -134,26 +191,25 @@ func TestPotRemove(t *testing.T) { if goti != expi { t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) } - inds, po := indexes(n) + inds := indexes(n) got = fmt.Sprintf("%v", inds) - exp = "[2 4 0]" + exp = "[2 4 1]" if got != exp { t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) } - got = fmt.Sprintf("%v", po) - exp = "[1 3 0]" + n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) // remove again same element + inds = indexes(n) + got = fmt.Sprintf("%v", inds) if got != exp { - t.Fatalf("incorrect po-s in iteration over Pot. Expected %v, got %v", exp, got) + t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) } - // remove again - n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) - inds, _ = indexes(n) + n, _, _ = Remove(n, newTestAddr("00000000", 0), pof) // remove the first element + inds = indexes(n) got = fmt.Sprintf("%v", inds) exp = "[2 4]" if got != exp { t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) } - } func TestPotSwap(t *testing.T) { @@ -202,7 +258,7 @@ func TestPotSwap(t *testing.T) { }) } sum := 0 - n.Each(func(v Val, i int) bool { + n.Each(func(v Val) bool { if v == nil { return true } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/api.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/api.go index eba7bb72..4556d7b7 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/api.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/api.go @@ -51,7 +51,7 @@ func NewAPI(ps *Pss) *API { // // All incoming messages to the node matching this topic will be encapsulated in the APIMsg // struct and sent to the subscriber -func (pssapi *API) Receive(ctx context.Context, topic Topic) (*rpc.Subscription, error) { +func (pssapi *API) Receive(ctx context.Context, topic Topic, raw bool, prox bool) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return nil, fmt.Errorf("Subscribe not supported") @@ -59,7 +59,7 @@ func (pssapi *API) Receive(ctx context.Context, topic Topic) (*rpc.Subscription, psssub := notifier.CreateSubscription() - handler := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + hndlr := NewHandler(func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { apimsg := &APIMsg{ Msg: hexutil.Bytes(msg), Asymmetric: asymmetric, @@ -69,9 +69,15 @@ func (pssapi *API) Receive(ctx context.Context, topic Topic) (*rpc.Subscription, log.Warn(fmt.Sprintf("notification on pss sub topic rpc (sub %v) msg %v failed!", psssub.ID, msg)) } return nil + }) + if raw { + hndlr.caps.raw = true + } + if prox { + hndlr.caps.prox = true } - deregf := pssapi.Register(&topic, handler) + deregf := pssapi.Register(&topic, hndlr) go func() { defer deregf() select { @@ -86,7 +92,7 @@ func (pssapi *API) Receive(ctx context.Context, topic Topic) (*rpc.Subscription, } func (pssapi *API) GetAddress(topic Topic, asymmetric bool, key string) (PssAddress, error) { - var addr *PssAddress + var addr PssAddress if asymmetric { peer, ok := pssapi.Pss.pubKeyPool[key][topic] if !ok { @@ -101,7 +107,7 @@ func (pssapi *API) GetAddress(topic Topic, asymmetric bool, key string) (PssAddr addr = peer.address } - return *addr, nil + return addr, nil } // Retrieves the node's base address in hex form @@ -122,7 +128,7 @@ func (pssapi *API) SetPeerPublicKey(pubkey hexutil.Bytes, topic Topic, addr PssA if err != nil { return fmt.Errorf("Cannot unmarshal pubkey: %x", pubkey) } - err = pssapi.Pss.SetPeerPublicKey(pk, topic, &addr) + err = pssapi.Pss.SetPeerPublicKey(pk, topic, addr) if err != nil { return fmt.Errorf("Invalid key: %x", pk) } @@ -135,11 +141,11 @@ func (pssapi *API) GetSymmetricKey(symkeyid string) (hexutil.Bytes, error) { } func (pssapi *API) GetSymmetricAddressHint(topic Topic, symkeyid string) (PssAddress, error) { - return *pssapi.Pss.symKeyPool[symkeyid][topic].address, nil + return pssapi.Pss.symKeyPool[symkeyid][topic].address, nil } func (pssapi *API) GetAsymmetricAddressHint(topic Topic, pubkeyid string) (PssAddress, error) { - return *pssapi.Pss.pubKeyPool[pubkeyid][topic].address, nil + return pssapi.Pss.pubKeyPool[pubkeyid][topic].address, nil } func (pssapi *API) StringToTopic(topicstring string) (Topic, error) { @@ -151,13 +157,26 @@ func (pssapi *API) StringToTopic(topicstring string) (Topic, error) { } func (pssapi *API) SendAsym(pubkeyhex string, topic Topic, msg hexutil.Bytes) error { + if err := validateMsg(msg); err != nil { + return err + } return pssapi.Pss.SendAsym(pubkeyhex, topic, msg[:]) } func (pssapi *API) SendSym(symkeyhex string, topic Topic, msg hexutil.Bytes) error { + if err := validateMsg(msg); err != nil { + return err + } return pssapi.Pss.SendSym(symkeyhex, topic, msg[:]) } +func (pssapi *API) SendRaw(addr hexutil.Bytes, topic Topic, msg hexutil.Bytes) error { + if err := validateMsg(msg); err != nil { + return err + } + return pssapi.Pss.SendRaw(PssAddress(addr), topic, msg[:]) +} + func (pssapi *API) GetPeerTopics(pubkeyhex string) ([]Topic, error) { topics, _, err := pssapi.Pss.GetPublickeyPeers(pubkeyhex) return topics, err @@ -167,3 +186,10 @@ func (pssapi *API) GetPeerTopics(pubkeyhex string) ([]Topic, error) { func (pssapi *API) GetPeerAddress(pubkeyhex string, topic Topic) (PssAddress, error) { return pssapi.Pss.getPeerAddress(pubkeyhex, topic) } + +func validateMsg(msg []byte) error { + if len(msg) == 0 { + return errors.New("invalid message length") + } + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client.go index d541081d..5ee387aa 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client.go @@ -236,7 +236,7 @@ func (c *Client) RunProtocol(ctx context.Context, proto *p2p.Protocol) error { topichex := topicobj.String() msgC := make(chan pss.APIMsg) c.peerPool[topicobj] = make(map[string]*pssRPCRW) - sub, err := c.rpc.Subscribe(ctx, "pss", msgC, "receive", topichex) + sub, err := c.rpc.Subscribe(ctx, "pss", msgC, "receive", topichex, false, false) if err != nil { return fmt.Errorf("pss event subscription failed: %v", err) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client_test.go index 8f2f0e80..1bd340cf 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/client/client_test.go @@ -23,7 +23,6 @@ import ( "fmt" "math/rand" "os" - "sync" "testing" "time" @@ -38,7 +37,7 @@ import ( "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/pss" "github.com/ethereum/go-ethereum/swarm/state" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) type protoCtrl struct { @@ -238,7 +237,7 @@ func newServices() adapters.Services { return k } params := network.NewKadParams() - params.MinProxBinSize = 2 + params.NeighbourhoodSize = 2 params.MaxBinSize = 3 params.MinBinSize = 1 params.MaxRetries = 1000 @@ -286,18 +285,3 @@ func newServices() adapters.Services { }, } } - -// copied from swarm/network/protocol_test_go -type testStore struct { - sync.Mutex - - values map[string][]byte -} - -func (t *testStore) Load(key string) ([]byte, error) { - return nil, nil -} - -func (t *testStore) Save(key string, v []byte) error { - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/forwarding_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/forwarding_test.go new file mode 100644 index 00000000..746d4dc4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/forwarding_test.go @@ -0,0 +1,357 @@ +package pss + +import ( + "fmt" + "math/rand" + "testing" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/pot" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" +) + +type testCase struct { + name string + recipient []byte + peers []pot.Address + expected []int + exclusive bool + nFails int + success bool + errors string +} + +var testCases []testCase + +// the purpose of this test is to see that pss.forward() function correctly +// selects the peers for message forwarding, depending on the message address +// and kademlia constellation. +func TestForwardBasic(t *testing.T) { + baseAddrBytes := make([]byte, 32) + for i := 0; i < len(baseAddrBytes); i++ { + baseAddrBytes[i] = 0xFF + } + var c testCase + base := pot.NewAddressFromBytes(baseAddrBytes) + var peerAddresses []pot.Address + const depth = 10 + for i := 0; i <= depth; i++ { + // add two peers for each proximity order + a := pot.RandomAddressAt(base, i) + peerAddresses = append(peerAddresses, a) + a = pot.RandomAddressAt(base, i) + peerAddresses = append(peerAddresses, a) + } + + // skip one level, add one peer at one level deeper. + // as a result, we will have an edge case of three peers in nearest neighbours' bin. + peerAddresses = append(peerAddresses, pot.RandomAddressAt(base, depth+2)) + + kad := network.NewKademlia(base[:], network.NewKadParams()) + ps := createPss(t, kad) + defer ps.Stop() + addPeers(kad, peerAddresses) + + const firstNearest = depth * 2 // shallowest peer in the nearest neighbours' bin + nearestNeighbours := []int{firstNearest, firstNearest + 1, firstNearest + 2} + var all []int // indices of all the peers + for i := 0; i < len(peerAddresses); i++ { + all = append(all, i) + } + + for i := 0; i < len(peerAddresses); i++ { + // send msg directly to the known peers (recipient address == peer address) + c = testCase{ + name: fmt.Sprintf("Send direct to known, id: [%d]", i), + recipient: peerAddresses[i][:], + peers: peerAddresses, + expected: []int{i}, + exclusive: false, + } + testCases = append(testCases, c) + } + + for i := 0; i < firstNearest; i++ { + // send random messages with proximity orders, corresponding to PO of each bin, + // with one peer being closer to the recipient address + a := pot.RandomAddressAt(peerAddresses[i], 64) + c = testCase{ + name: fmt.Sprintf("Send random to each PO, id: [%d]", i), + recipient: a[:], + peers: peerAddresses, + expected: []int{i}, + exclusive: false, + } + testCases = append(testCases, c) + } + + for i := 0; i < firstNearest; i++ { + // send random messages with proximity orders, corresponding to PO of each bin, + // with random proximity relative to the recipient address + po := i / 2 + a := pot.RandomAddressAt(base, po) + c = testCase{ + name: fmt.Sprintf("Send direct to known, id: [%d]", i), + recipient: a[:], + peers: peerAddresses, + expected: []int{po * 2, po*2 + 1}, + exclusive: true, + } + testCases = append(testCases, c) + } + + for i := firstNearest; i < len(peerAddresses); i++ { + // recipient address falls into the nearest neighbours' bin + a := pot.RandomAddressAt(base, i) + c = testCase{ + name: fmt.Sprintf("recipient address falls into the nearest neighbours' bin, id: [%d]", i), + recipient: a[:], + peers: peerAddresses, + expected: nearestNeighbours, + exclusive: false, + } + testCases = append(testCases, c) + } + + // send msg with proximity order much deeper than the deepest nearest neighbour + a2 := pot.RandomAddressAt(base, 77) + c = testCase{ + name: "proximity order much deeper than the deepest nearest neighbour", + recipient: a2[:], + peers: peerAddresses, + expected: nearestNeighbours, + exclusive: false, + } + testCases = append(testCases, c) + + // test with partial addresses + const part = 12 + + for i := 0; i < firstNearest; i++ { + // send messages with partial address falling into different proximity orders + po := i / 2 + if i%8 != 0 { + c = testCase{ + name: fmt.Sprintf("partial address falling into different proximity orders, id: [%d]", i), + recipient: peerAddresses[i][:i], + peers: peerAddresses, + expected: []int{po * 2, po*2 + 1}, + exclusive: true, + } + testCases = append(testCases, c) + } + c = testCase{ + name: fmt.Sprintf("extended partial address falling into different proximity orders, id: [%d]", i), + recipient: peerAddresses[i][:part], + peers: peerAddresses, + expected: []int{po * 2, po*2 + 1}, + exclusive: true, + } + testCases = append(testCases, c) + } + + for i := firstNearest; i < len(peerAddresses); i++ { + // partial address falls into the nearest neighbours' bin + c = testCase{ + name: fmt.Sprintf("partial address falls into the nearest neighbours' bin, id: [%d]", i), + recipient: peerAddresses[i][:part], + peers: peerAddresses, + expected: nearestNeighbours, + exclusive: false, + } + testCases = append(testCases, c) + } + + // partial address with proximity order deeper than any of the nearest neighbour + a3 := pot.RandomAddressAt(base, part) + c = testCase{ + name: "partial address with proximity order deeper than any of the nearest neighbour", + recipient: a3[:part], + peers: peerAddresses, + expected: nearestNeighbours, + exclusive: false, + } + testCases = append(testCases, c) + + // special cases where partial address matches a large group of peers + + // zero bytes of address is given, msg should be delivered to all the peers + c = testCase{ + name: "zero bytes of address is given", + recipient: []byte{}, + peers: peerAddresses, + expected: all, + exclusive: false, + } + testCases = append(testCases, c) + + // luminous radius of 8 bits, proximity order 8 + indexAtPo8 := 16 + c = testCase{ + name: "luminous radius of 8 bits", + recipient: []byte{0xFF}, + peers: peerAddresses, + expected: all[indexAtPo8:], + exclusive: false, + } + testCases = append(testCases, c) + + // luminous radius of 256 bits, proximity order 8 + a4 := pot.Address{} + a4[0] = 0xFF + c = testCase{ + name: "luminous radius of 256 bits", + recipient: a4[:], + peers: peerAddresses, + expected: []int{indexAtPo8, indexAtPo8 + 1}, + exclusive: true, + } + testCases = append(testCases, c) + + // check correct behaviour in case send fails + for i := 2; i < firstNearest-3; i += 2 { + po := i / 2 + // send random messages with proximity orders, corresponding to PO of each bin, + // with different numbers of failed attempts. + // msg should be received by only one of the deeper peers. + a := pot.RandomAddressAt(base, po) + c = testCase{ + name: fmt.Sprintf("Send direct to known, id: [%d]", i), + recipient: a[:], + peers: peerAddresses, + expected: all[i+1:], + exclusive: true, + nFails: rand.Int()%3 + 2, + } + testCases = append(testCases, c) + } + + for _, c := range testCases { + testForwardMsg(t, ps, &c) + } +} + +// this function tests the forwarding of a single message. the recipient address is passed as param, +// along with addresses of all peers, and indices of those peers which are expected to receive the message. +func testForwardMsg(t *testing.T, ps *Pss, c *testCase) { + recipientAddr := c.recipient + peers := c.peers + expected := c.expected + exclusive := c.exclusive + nFails := c.nFails + tries := 0 // number of previous failed tries + + resultMap := make(map[pot.Address]int) + + defer func() { sendFunc = sendMsg }() + sendFunc = func(_ *Pss, sp *network.Peer, _ *PssMsg) bool { + if tries < nFails { + tries++ + return false + } + a := pot.NewAddressFromBytes(sp.Address()) + resultMap[a]++ + return true + } + + msg := newTestMsg(recipientAddr) + ps.forward(msg) + + // check test results + var fail bool + precision := len(recipientAddr) + if precision > 4 { + precision = 4 + } + s := fmt.Sprintf("test [%s]\nmsg address: %x..., radius: %d", c.name, recipientAddr[:precision], 8*len(recipientAddr)) + + // false negatives (expected message didn't reach peer) + if exclusive { + var cnt int + for _, i := range expected { + a := peers[i] + cnt += resultMap[a] + resultMap[a] = 0 + } + if cnt != 1 { + s += fmt.Sprintf("\n%d messages received by %d peers with indices: [%v]", cnt, len(expected), expected) + fail = true + } + } else { + for _, i := range expected { + a := peers[i] + received := resultMap[a] + if received != 1 { + s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", i, a[:4], received) + fail = true + } + resultMap[a] = 0 + } + } + + // false positives (unexpected message reached peer) + for k, v := range resultMap { + if v != 0 { + // find the index of the false positive peer + var j int + for j = 0; j < len(peers); j++ { + if peers[j] == k { + break + } + } + s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", j, k[:4], v) + fail = true + } + } + + if fail { + t.Fatal(s) + } +} + +func addPeers(kad *network.Kademlia, addresses []pot.Address) { + for _, a := range addresses { + p := newTestDiscoveryPeer(a, kad) + kad.On(p) + } +} + +func createPss(t *testing.T, kad *network.Kademlia) *Pss { + privKey, err := crypto.GenerateKey() + pssp := NewPssParams().WithPrivateKey(privKey) + ps, err := NewPss(kad, pssp) + if err != nil { + t.Fatal(err.Error()) + } + return ps +} + +func newTestDiscoveryPeer(addr pot.Address, kad *network.Kademlia) *network.Peer { + rw := &p2p.MsgPipeRW{} + p := p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}) + pp := protocols.NewPeer(p, rw, &protocols.Spec{}) + bp := &network.BzzPeer{ + Peer: pp, + BzzAddr: &network.BzzAddr{ + OAddr: addr.Bytes(), + UAddr: []byte(fmt.Sprintf("%x", addr[:])), + }, + } + return network.NewPeer(bp, kad) +} + +func newTestMsg(addr []byte) *PssMsg { + msg := newPssMsg(&msgParams{}) + msg.To = addr[:] + msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) + msg.Payload = &whisper.Envelope{ + Topic: [4]byte{}, + Data: []byte("i have nothing to hide"), + } + return msg +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake.go index e3ead77d..ec3bffa3 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake.go @@ -106,6 +106,7 @@ func NewHandshakeParams() *HandshakeParams { type HandshakeController struct { pss *Pss keyC map[string]chan []string // adds a channel to report when a handshake succeeds + keyCMu sync.Mutex // protects keyC map lock sync.Mutex symKeyRequestTimeout time.Duration symKeyExpiryTimeout time.Duration @@ -165,9 +166,9 @@ func (ctl *HandshakeController) validKeys(pubkeyid string, topic *Topic, in bool for _, key := range *keystore { if key.limit <= key.count { - ctl.releaseKey(*key.symKeyID, topic) + ctl.releaseKeyNoLock(*key.symKeyID, topic) } else if !key.expiredAt.IsZero() && key.expiredAt.Before(now) { - ctl.releaseKey(*key.symKeyID, topic) + ctl.releaseKeyNoLock(*key.symKeyID, topic) } else { validkeys = append(validkeys, key.symKeyID) } @@ -205,15 +206,23 @@ func (ctl *HandshakeController) updateKeys(pubkeyid string, topic *Topic, in boo limit: limit, } *keystore = append(*keystore, storekey) + ctl.pss.mx.Lock() ctl.pss.symKeyPool[*storekey.symKeyID][*topic].protected = true + ctl.pss.mx.Unlock() } for i := 0; i < len(*keystore); i++ { ctl.symKeyIndex[*(*keystore)[i].symKeyID] = &((*keystore)[i]) } } -// Expire a symmetric key, making it elegible for garbage collection func (ctl *HandshakeController) releaseKey(symkeyid string, topic *Topic) bool { + ctl.lock.Lock() + defer ctl.lock.Unlock() + return ctl.releaseKeyNoLock(symkeyid, topic) +} + +// Expire a symmetric key, making it eligible for garbage collection +func (ctl *HandshakeController) releaseKeyNoLock(symkeyid string, topic *Topic) bool { if ctl.symKeyIndex[symkeyid] == nil { log.Debug("no symkey", "symkeyid", symkeyid) return false @@ -276,30 +285,49 @@ func (ctl *HandshakeController) clean() { } } +func (ctl *HandshakeController) getSymKey(symkeyid string) *handshakeKey { + ctl.lock.Lock() + defer ctl.lock.Unlock() + return ctl.symKeyIndex[symkeyid] +} + // Passed as a PssMsg handler for the topic handshake is activated on // Handles incoming key exchange messages and -// ccunts message usage by symmetric key (expiry limit control) +// counts message usage by symmetric key (expiry limit control) // Only returns error if key handler fails func (ctl *HandshakeController) handler(msg []byte, p *p2p.Peer, asymmetric bool, symkeyid string) error { - if !asymmetric { - if ctl.symKeyIndex[symkeyid] != nil { - if ctl.symKeyIndex[symkeyid].count >= ctl.symKeyIndex[symkeyid].limit { - return fmt.Errorf("discarding message using expired key: %s", symkeyid) + if asymmetric { + keymsg := &handshakeMsg{} + err := rlp.DecodeBytes(msg, keymsg) + if err == nil { + err := ctl.handleKeys(symkeyid, keymsg) + if err != nil { + log.Error("handlekeys fail", "error", err) } - ctl.symKeyIndex[symkeyid].count++ - log.Trace("increment symkey recv use", "symsymkeyid", symkeyid, "count", ctl.symKeyIndex[symkeyid].count, "limit", ctl.symKeyIndex[symkeyid].limit, "receiver", common.ToHex(crypto.FromECDSAPub(ctl.pss.PublicKey()))) + return err } return nil } - keymsg := &handshakeMsg{} - err := rlp.DecodeBytes(msg, keymsg) - if err == nil { - err := ctl.handleKeys(symkeyid, keymsg) - if err != nil { - log.Error("handlekeys fail", "error", err) - } - return err + return ctl.registerSymKeyUse(symkeyid) +} + +func (ctl *HandshakeController) registerSymKeyUse(symkeyid string) error { + ctl.lock.Lock() + defer ctl.lock.Unlock() + + symKey, ok := ctl.symKeyIndex[symkeyid] + if !ok { + return nil } + + if symKey.count >= symKey.limit { + return fmt.Errorf("symetric key expired (id: %s)", symkeyid) + } + symKey.count++ + + receiver := common.ToHex(crypto.FromECDSAPub(ctl.pss.PublicKey())) + log.Trace("increment symkey recv use", "symsymkeyid", symkeyid, "count", symKey.count, "limit", symKey.limit, "receiver", receiver) + return nil } @@ -321,9 +349,7 @@ func (ctl *HandshakeController) handleKeys(pubkeyid string, keymsg *handshakeMsg for _, key := range keymsg.Keys { sendsymkey := make([]byte, len(key)) copy(sendsymkey, key) - var address PssAddress - copy(address[:], keymsg.From) - sendsymkeyid, err := ctl.pss.setSymmetricKey(sendsymkey, keymsg.Topic, &address, false, false) + sendsymkeyid, err := ctl.pss.setSymmetricKey(sendsymkey, keymsg.Topic, PssAddress(keymsg.From), false, false) if err != nil { return err } @@ -356,7 +382,7 @@ func (ctl *HandshakeController) handleKeys(pubkeyid string, keymsg *handshakeMsg func (ctl *HandshakeController) sendKey(pubkeyid string, topic *Topic, keycount uint8) ([]string, error) { var requestcount uint8 - to := &PssAddress{} + to := PssAddress{} if _, ok := ctl.pss.pubKeyPool[pubkeyid]; !ok { return []string{}, errors.New("Invalid public key") } else if psp, ok := ctl.pss.pubKeyPool[pubkeyid][*topic]; ok { @@ -419,6 +445,8 @@ func (ctl *HandshakeController) sendKey(pubkeyid string, topic *Topic, keycount // Enables callback for keys received from a key exchange request func (ctl *HandshakeController) alertHandshake(pubkeyid string, symkeys []string) chan []string { + ctl.keyCMu.Lock() + defer ctl.keyCMu.Unlock() if len(symkeys) > 0 { if _, ok := ctl.keyC[pubkeyid]; ok { ctl.keyC[pubkeyid] <- symkeys @@ -486,7 +514,7 @@ func (api *HandshakeAPI) Handshake(pubkeyid string, topic Topic, sync bool, flus // Activate handshake functionality on a topic func (api *HandshakeAPI) AddHandshake(topic Topic) error { - api.ctrl.deregisterFuncs[topic] = api.ctrl.pss.Register(&topic, api.ctrl.handler) + api.ctrl.deregisterFuncs[topic] = api.ctrl.pss.Register(&topic, NewHandler(api.ctrl.handler)) return nil } @@ -521,7 +549,7 @@ func (api *HandshakeAPI) GetHandshakeKeys(pubkeyid string, topic Topic, in bool, // Returns the amount of messages the specified symmetric key // is still valid for under the handshake scheme func (api *HandshakeAPI) GetHandshakeKeyCapacity(symkeyid string) (uint16, error) { - storekey := api.ctrl.symKeyIndex[symkeyid] + storekey := api.ctrl.getSymKey(symkeyid) if storekey == nil { return 0, fmt.Errorf("invalid symkey id %s", symkeyid) } @@ -531,7 +559,7 @@ func (api *HandshakeAPI) GetHandshakeKeyCapacity(symkeyid string) (uint16, error // Returns the byte representation of the public key in ascii hex // associated with the given symmetric key func (api *HandshakeAPI) GetHandshakePublicKey(symkeyid string) (string, error) { - storekey := api.ctrl.symKeyIndex[symkeyid] + storekey := api.ctrl.getSymKey(symkeyid) if storekey == nil { return "", fmt.Errorf("invalid symkey id %s", symkeyid) } @@ -557,12 +585,8 @@ func (api *HandshakeAPI) ReleaseHandshakeKey(pubkeyid string, topic Topic, symke // for message expiry control func (api *HandshakeAPI) SendSym(symkeyid string, topic Topic, msg hexutil.Bytes) (err error) { err = api.ctrl.pss.SendSym(symkeyid, topic, msg[:]) - if api.ctrl.symKeyIndex[symkeyid] != nil { - if api.ctrl.symKeyIndex[symkeyid].count >= api.ctrl.symKeyIndex[symkeyid].limit { - return errors.New("attempted send with expired key") - } - api.ctrl.symKeyIndex[symkeyid].count++ - log.Trace("increment symkey send use", "symkeyid", symkeyid, "count", api.ctrl.symKeyIndex[symkeyid].count, "limit", api.ctrl.symKeyIndex[symkeyid].limit, "receiver", common.ToHex(crypto.FromECDSAPub(api.ctrl.pss.PublicKey()))) + if otherErr := api.ctrl.registerSymKeyUse(symkeyid); otherErr != nil { + return otherErr } - return + return err } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake_test.go index 0fc7e798..f4effc02 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/handshake_test.go @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build foo - package pss import ( @@ -46,7 +44,7 @@ func testHandshake(t *testing.T) { // set up two nodes directly connected // (we are not testing pss routing here) - clients, err := setupNetwork(2) + clients, err := setupNetwork(2, true) if err != nil { t.Fatal(err) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/keystore.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/keystore.go new file mode 100644 index 00000000..5c44cb24 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/keystore.go @@ -0,0 +1,281 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package pss + +import ( + "crypto/ecdsa" + "errors" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/log" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" +) + +type KeyStore struct { + w *whisper.Whisper // key and encryption backend + + mx sync.RWMutex + pubKeyPool map[string]map[Topic]*pssPeer // mapping of hex public keys to peer address by topic. + symKeyPool map[string]map[Topic]*pssPeer // mapping of symkeyids to peer address by topic. + symKeyDecryptCache []*string // fast lookup of symkeys recently used for decryption; last used is on top of stack + symKeyDecryptCacheCursor int // modular cursor pointing to last used, wraps on symKeyDecryptCache array +} + +func loadKeyStore() *KeyStore { + return &KeyStore{ + w: whisper.New(&whisper.DefaultConfig), + + pubKeyPool: make(map[string]map[Topic]*pssPeer), + symKeyPool: make(map[string]map[Topic]*pssPeer), + symKeyDecryptCache: make([]*string, defaultSymKeyCacheCapacity), + } +} + +func (ks *KeyStore) isSymKeyStored(key string) bool { + ks.mx.RLock() + defer ks.mx.RUnlock() + var ok bool + _, ok = ks.symKeyPool[key] + return ok +} + +func (ks *KeyStore) isPubKeyStored(key string) bool { + ks.mx.RLock() + defer ks.mx.RUnlock() + var ok bool + _, ok = ks.pubKeyPool[key] + return ok +} + +func (ks *KeyStore) getPeerSym(symkeyid string, topic Topic) (*pssPeer, bool) { + ks.mx.RLock() + defer ks.mx.RUnlock() + psp, ok := ks.symKeyPool[symkeyid][topic] + return psp, ok +} + +func (ks *KeyStore) getPeerPub(pubkeyid string, topic Topic) (*pssPeer, bool) { + ks.mx.RLock() + defer ks.mx.RUnlock() + psp, ok := ks.pubKeyPool[pubkeyid][topic] + return psp, ok +} + +// Links a peer ECDSA public key to a topic. +// This is required for asymmetric message exchange on the given topic. +// The value in `address` will be used as a routing hint for the public key / topic association. +func (ks *KeyStore) SetPeerPublicKey(pubkey *ecdsa.PublicKey, topic Topic, address PssAddress) error { + if err := validateAddress(address); err != nil { + return err + } + pubkeybytes := crypto.FromECDSAPub(pubkey) + if len(pubkeybytes) == 0 { + return fmt.Errorf("invalid public key: %v", pubkey) + } + pubkeyid := common.ToHex(pubkeybytes) + psp := &pssPeer{ + address: address, + } + ks.mx.Lock() + if _, ok := ks.pubKeyPool[pubkeyid]; !ok { + ks.pubKeyPool[pubkeyid] = make(map[Topic]*pssPeer) + } + ks.pubKeyPool[pubkeyid][topic] = psp + ks.mx.Unlock() + log.Trace("added pubkey", "pubkeyid", pubkeyid, "topic", topic, "address", address) + return nil +} + +// adds a symmetric key to the pss key pool, and optionally adds the key to the +// collection of keys used to attempt symmetric decryption of incoming messages +func (ks *KeyStore) addSymmetricKeyToPool(keyid string, topic Topic, address PssAddress, addtocache bool, protected bool) { + psp := &pssPeer{ + address: address, + protected: protected, + } + ks.mx.Lock() + if _, ok := ks.symKeyPool[keyid]; !ok { + ks.symKeyPool[keyid] = make(map[Topic]*pssPeer) + } + ks.symKeyPool[keyid][topic] = psp + ks.mx.Unlock() + if addtocache { + ks.symKeyDecryptCacheCursor++ + ks.symKeyDecryptCache[ks.symKeyDecryptCacheCursor%cap(ks.symKeyDecryptCache)] = &keyid + } +} + +// Returns all recorded topic and address combination for a specific public key +func (ks *KeyStore) GetPublickeyPeers(keyid string) (topic []Topic, address []PssAddress, err error) { + ks.mx.RLock() + defer ks.mx.RUnlock() + for t, peer := range ks.pubKeyPool[keyid] { + topic = append(topic, t) + address = append(address, peer.address) + } + return topic, address, nil +} + +func (ks *KeyStore) getPeerAddress(keyid string, topic Topic) (PssAddress, error) { + ks.mx.RLock() + defer ks.mx.RUnlock() + if peers, ok := ks.pubKeyPool[keyid]; ok { + if t, ok := peers[topic]; ok { + return t.address, nil + } + } + return nil, fmt.Errorf("peer with pubkey %s, topic %x not found", keyid, topic) +} + +// Attempt to decrypt, validate and unpack a symmetrically encrypted message. +// If successful, returns the unpacked whisper ReceivedMessage struct +// encapsulating the decrypted message, and the whisper backend id +// of the symmetric key used to decrypt the message. +// It fails if decryption of the message fails or if the message is corrupted. +func (ks *KeyStore) processSym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) { + metrics.GetOrRegisterCounter("pss.process.sym", nil).Inc(1) + + for i := ks.symKeyDecryptCacheCursor; i > ks.symKeyDecryptCacheCursor-cap(ks.symKeyDecryptCache) && i > 0; i-- { + symkeyid := ks.symKeyDecryptCache[i%cap(ks.symKeyDecryptCache)] + symkey, err := ks.w.GetSymKey(*symkeyid) + if err != nil { + continue + } + recvmsg, err := envelope.OpenSymmetric(symkey) + if err != nil { + continue + } + if !recvmsg.ValidateAndParse() { + return nil, "", nil, errors.New("symmetrically encrypted message has invalid signature or is corrupt") + } + var from PssAddress + ks.mx.RLock() + if ks.symKeyPool[*symkeyid][Topic(envelope.Topic)] != nil { + from = ks.symKeyPool[*symkeyid][Topic(envelope.Topic)].address + } + ks.mx.RUnlock() + ks.symKeyDecryptCacheCursor++ + ks.symKeyDecryptCache[ks.symKeyDecryptCacheCursor%cap(ks.symKeyDecryptCache)] = symkeyid + return recvmsg, *symkeyid, from, nil + } + return nil, "", nil, errors.New("could not decrypt message") +} + +// Attempt to decrypt, validate and unpack an asymmetrically encrypted message. +// If successful, returns the unpacked whisper ReceivedMessage struct +// encapsulating the decrypted message, and the byte representation of +// the public key used to decrypt the message. +// It fails if decryption of message fails, or if the message is corrupted. +func (ks *Pss) processAsym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) { + metrics.GetOrRegisterCounter("pss.process.asym", nil).Inc(1) + + recvmsg, err := envelope.OpenAsymmetric(ks.privateKey) + if err != nil { + return nil, "", nil, fmt.Errorf("could not decrypt message: %s", err) + } + // check signature (if signed), strip padding + if !recvmsg.ValidateAndParse() { + return nil, "", nil, errors.New("invalid message") + } + pubkeyid := common.ToHex(crypto.FromECDSAPub(recvmsg.Src)) + var from PssAddress + ks.mx.RLock() + if ks.pubKeyPool[pubkeyid][Topic(envelope.Topic)] != nil { + from = ks.pubKeyPool[pubkeyid][Topic(envelope.Topic)].address + } + ks.mx.RUnlock() + return recvmsg, pubkeyid, from, nil +} + +// Symkey garbage collection +// a key is removed if: +// - it is not marked as protected +// - it is not in the incoming decryption cache +func (ks *Pss) cleanKeys() (count int) { + ks.mx.Lock() + defer ks.mx.Unlock() + for keyid, peertopics := range ks.symKeyPool { + var expiredtopics []Topic + for topic, psp := range peertopics { + if psp.protected { + continue + } + + var match bool + for i := ks.symKeyDecryptCacheCursor; i > ks.symKeyDecryptCacheCursor-cap(ks.symKeyDecryptCache) && i > 0; i-- { + cacheid := ks.symKeyDecryptCache[i%cap(ks.symKeyDecryptCache)] + if *cacheid == keyid { + match = true + } + } + if !match { + expiredtopics = append(expiredtopics, topic) + } + } + for _, topic := range expiredtopics { + delete(ks.symKeyPool[keyid], topic) + log.Trace("symkey cleanup deletion", "symkeyid", keyid, "topic", topic, "val", ks.symKeyPool[keyid]) + count++ + } + } + return count +} + +// Automatically generate a new symkey for a topic and address hint +func (ks *KeyStore) GenerateSymmetricKey(topic Topic, address PssAddress, addToCache bool) (string, error) { + keyid, err := ks.w.GenerateSymKey() + if err == nil { + ks.addSymmetricKeyToPool(keyid, topic, address, addToCache, false) + } + return keyid, err +} + +// Returns a symmetric key byte sequence stored in the whisper backend by its unique id. +// Passes on the error value from the whisper backend. +func (ks *KeyStore) GetSymmetricKey(symkeyid string) ([]byte, error) { + return ks.w.GetSymKey(symkeyid) +} + +// Links a peer symmetric key (arbitrary byte sequence) to a topic. +// +// This is required for symmetrically encrypted message exchange on the given topic. +// +// The key is stored in the whisper backend. +// +// If addtocache is set to true, the key will be added to the cache of keys +// used to attempt symmetric decryption of incoming messages. +// +// Returns a string id that can be used to retrieve the key bytes +// from the whisper backend (see pss.GetSymmetricKey()) +func (ks *KeyStore) SetSymmetricKey(key []byte, topic Topic, address PssAddress, addtocache bool) (string, error) { + if err := validateAddress(address); err != nil { + return "", err + } + return ks.setSymmetricKey(key, topic, address, addtocache, true) +} + +func (ks *KeyStore) setSymmetricKey(key []byte, topic Topic, address PssAddress, addtocache bool, protected bool) (string, error) { + keyid, err := ks.w.AddSymKeyDirect(key) + if err == nil { + ks.addSymmetricKeyToPool(keyid, topic, address, addtocache, protected) + } + return keyid, err +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify.go index 3731fb9d..e9d40dc3 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify.go @@ -113,7 +113,7 @@ func NewController(ps *pss.Pss) *Controller { notifiers: make(map[string]*notifier), subscriptions: make(map[string]*subscription), } - ctrl.pss.Register(&controlTopic, ctrl.Handler) + ctrl.pss.Register(&controlTopic, pss.NewHandler(ctrl.Handler)) return ctrl } @@ -138,7 +138,7 @@ func (c *Controller) Subscribe(name string, pubkey *ecdsa.PublicKey, address pss c.mu.Lock() defer c.mu.Unlock() msg := NewMsg(MsgCodeStart, name, c.pss.BaseAddr()) - c.pss.SetPeerPublicKey(pubkey, controlTopic, &address) + c.pss.SetPeerPublicKey(pubkey, controlTopic, address) pubkeyId := hexutil.Encode(crypto.FromECDSAPub(pubkey)) smsg, err := rlp.EncodeToBytes(msg) if err != nil { @@ -271,7 +271,7 @@ func (c *Controller) addToBin(ntfr *notifier, address []byte) (symKeyId string, currentBin.count++ symKeyId = currentBin.symKeyId } else { - symKeyId, err = c.pss.GenerateSymmetricKey(ntfr.topic, &pssAddress, false) + symKeyId, err = c.pss.GenerateSymmetricKey(ntfr.topic, pssAddress, false) if err != nil { return "", nil, err } @@ -312,7 +312,7 @@ func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) { if err != nil { return err } - err = c.pss.SetPeerPublicKey(pubkey, controlTopic, &pssAddress) + err = c.pss.SetPeerPublicKey(pubkey, controlTopic, pssAddress) if err != nil { return err } @@ -335,8 +335,8 @@ func (c *Controller) handleNotifyWithKeyMsg(msg *Msg) error { // \TODO keep track of and add actual address updaterAddr := pss.PssAddress([]byte{}) - c.pss.SetSymmetricKey(symkey, topic, &updaterAddr, true) - c.pss.Register(&topic, c.Handler) + c.pss.SetSymmetricKey(symkey, topic, updaterAddr, true) + c.pss.Register(&topic, pss.NewHandler(c.Handler)) return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload[:len(msg.Payload)-symKeyLength]) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify_test.go index d4d383a6..cda069b9 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/notify/notify_test.go @@ -19,7 +19,7 @@ import ( "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/pss" "github.com/ethereum/go-ethereum/swarm/state" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) var ( @@ -51,6 +51,7 @@ func TestStart(t *testing.T) { ID: "0", DefaultService: "bzz", }) + defer net.Shutdown() leftNodeConf := adapters.RandomNodeConfig() leftNodeConf.Services = []string{"bzz", "pss"} leftNode, err := net.NewNodeWithConfig(leftNodeConf) @@ -121,14 +122,14 @@ func TestStart(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) defer cancel() rmsgC := make(chan *pss.APIMsg) - rightSub, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", controlTopic) + rightSub, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", controlTopic, false, false) if err != nil { t.Fatal(err) } defer rightSub.Unsubscribe() updateC := make(chan []byte) - updateMsg := []byte{} + var updateMsg []byte ctrlClient := NewController(psses[rightPub]) ctrlNotifier := NewController(psses[leftPub]) ctrlNotifier.NewNotifier("foo.eth", 2, updateC) @@ -145,17 +146,24 @@ func TestStart(t *testing.T) { if err != nil { t.Fatal(err) } + + copyOfUpdateMsg := make([]byte, len(updateMsg)) + copy(copyOfUpdateMsg, updateMsg) + ctrlClientError := make(chan error, 1) ctrlClient.Subscribe(rsrcName, pubkey, addrbytes, func(s string, b []byte) error { - if s != "foo.eth" || !bytes.Equal(updateMsg, b) { - t.Fatalf("unexpected result in client handler: '%s':'%x'", s, b) + if s != "foo.eth" || !bytes.Equal(copyOfUpdateMsg, b) { + ctrlClientError <- fmt.Errorf("unexpected result in client handler: '%s':'%x'", s, b) + } else { + log.Info("client handler receive", "s", s, "b", b) } - log.Info("client handler receive", "s", s, "b", b) return nil }) var inMsg *pss.APIMsg select { case inMsg = <-rmsgC: + case err := <-ctrlClientError: + t.Fatal(err) case <-ctx.Done(): t.Fatal(ctx.Err()) } @@ -174,7 +182,7 @@ func TestStart(t *testing.T) { t.Fatalf("expected payload length %d, have %d", len(updateMsg)+symKeyLength, len(dMsg.Payload)) } - rightSubUpdate, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", rsrcTopic) + rightSubUpdate, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", rsrcTopic, false, false) if err != nil { t.Fatal(err) } @@ -209,7 +217,7 @@ func newServices(allowRaw bool) adapters.Services { return k } params := network.NewKadParams() - params.MinProxBinSize = 2 + params.NeighbourhoodSize = 2 params.MaxBinSize = 3 params.MinBinSize = 1 params.MaxRetries = 1000 diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol.go index 5fcae090..7f186f61 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol.go @@ -241,20 +241,16 @@ func (p *Protocol) AddPeer(peer *p2p.Peer, topic Topic, asymmetric bool, key str rw.sendFunc = p.Pss.SendSym } if asymmetric { - p.Pss.pubKeyPoolMu.Lock() - if _, ok := p.Pss.pubKeyPool[key]; !ok { + if !p.Pss.isPubKeyStored(key) { return nil, fmt.Errorf("asym key does not exist: %s", key) } - p.Pss.pubKeyPoolMu.Unlock() p.RWPoolMu.Lock() p.pubKeyRWPool[key] = rw p.RWPoolMu.Unlock() } else { - p.Pss.symKeyPoolMu.Lock() - if _, ok := p.Pss.symKeyPool[key]; !ok { + if !p.Pss.isSymKeyStored(key) { return nil, fmt.Errorf("symkey does not exist: %s", key) } - p.Pss.symKeyPoolMu.Unlock() p.RWPoolMu.Lock() p.symKeyRWPool[key] = rw p.RWPoolMu.Unlock() diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol_test.go index 4ef3e90a..520c48a2 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/protocol_test.go @@ -92,7 +92,7 @@ func testProtocol(t *testing.T) { lmsgC := make(chan APIMsg) lctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) + lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false) if err != nil { t.Fatal(err) } @@ -100,7 +100,7 @@ func testProtocol(t *testing.T) { rmsgC := make(chan APIMsg) rctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) + rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) if err != nil { t.Fatal(err) } @@ -130,6 +130,7 @@ func testProtocol(t *testing.T) { log.Debug("lnode ok") case cerr := <-lctx.Done(): t.Fatalf("test message timed out: %v", cerr) + return } select { case <-rmsgC: diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/prox_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/prox_test.go new file mode 100644 index 00000000..bc32e612 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/prox_test.go @@ -0,0 +1,473 @@ +package pss + +import ( + "context" + "crypto/ecdsa" + "encoding/binary" + "errors" + "fmt" + "strconv" + "strings" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/network/simulation" + "github.com/ethereum/go-ethereum/swarm/pot" + "github.com/ethereum/go-ethereum/swarm/state" +) + +// needed to make the enode id of the receiving node available to the handler for triggers +type handlerContextFunc func(*testData, *adapters.NodeConfig) *handler + +// struct to notify reception of messages to simulation driver +// TODO To make code cleaner: +// - consider a separate pss unwrap to message event in sim framework (this will make eventual message propagation analysis with pss easier/possible in the future) +// - consider also test api calls to inspect handling results of messages +type handlerNotification struct { + id enode.ID + serial uint64 +} + +type testData struct { + mu sync.Mutex + sim *simulation.Simulation + handlerDone bool // set to true on termination of the simulation run + requiredMessages int + allowedMessages int + messageCount int + kademlias map[enode.ID]*network.Kademlia + nodeAddrs map[enode.ID][]byte // make predictable overlay addresses from the generated random enode ids + recipients map[int][]enode.ID // for logging output only + allowed map[int][]enode.ID // allowed recipients + expectedMsgs map[enode.ID][]uint64 // message serials we expect respective nodes to receive + allowedMsgs map[enode.ID][]uint64 // message serials we expect respective nodes to receive + senders map[int]enode.ID // originating nodes of the messages (intention is to choose as far as possible from the receiving neighborhood) + handlerC chan handlerNotification // passes message from pss message handler to simulation driver + doneC chan struct{} // terminates the handler channel listener + errC chan error // error to pass to main sim thread + msgC chan handlerNotification // message receipt notification to main sim thread + msgs [][]byte // recipient addresses of messages +} + +var ( + pof = pot.DefaultPof(256) // generate messages and index them + topic = BytesToTopic([]byte{0xf3, 0x9e, 0x06, 0x82}) +) + +func (d *testData) getMsgCount() int { + d.mu.Lock() + defer d.mu.Unlock() + return d.messageCount +} + +func (d *testData) incrementMsgCount() int { + d.mu.Lock() + defer d.mu.Unlock() + d.messageCount++ + return d.messageCount +} + +func (d *testData) isDone() bool { + d.mu.Lock() + defer d.mu.Unlock() + return d.handlerDone +} + +func (d *testData) setDone() { + d.mu.Lock() + defer d.mu.Unlock() + d.handlerDone = true +} + +func getCmdParams(t *testing.T) (int, int, time.Duration) { + args := strings.Split(t.Name(), "/") + msgCount, err := strconv.ParseInt(args[2], 10, 16) + if err != nil { + t.Fatal(err) + } + nodeCount, err := strconv.ParseInt(args[1], 10, 16) + if err != nil { + t.Fatal(err) + } + timeoutStr := fmt.Sprintf("%ss", args[3]) + timeoutDur, err := time.ParseDuration(timeoutStr) + if err != nil { + t.Fatal(err) + } + return int(msgCount), int(nodeCount), timeoutDur +} + +func newTestData() *testData { + return &testData{ + kademlias: make(map[enode.ID]*network.Kademlia), + nodeAddrs: make(map[enode.ID][]byte), + recipients: make(map[int][]enode.ID), + allowed: make(map[int][]enode.ID), + expectedMsgs: make(map[enode.ID][]uint64), + allowedMsgs: make(map[enode.ID][]uint64), + senders: make(map[int]enode.ID), + handlerC: make(chan handlerNotification), + doneC: make(chan struct{}), + errC: make(chan error), + msgC: make(chan handlerNotification), + } +} + +func (d *testData) getKademlia(nodeId *enode.ID) (*network.Kademlia, error) { + kadif, ok := d.sim.NodeItem(*nodeId, simulation.BucketKeyKademlia) + if !ok { + return nil, fmt.Errorf("no kademlia entry for %v", nodeId) + } + kad, ok := kadif.(*network.Kademlia) + if !ok { + return nil, fmt.Errorf("invalid kademlia entry for %v", nodeId) + } + return kad, nil +} + +func (d *testData) init(msgCount int) error { + log.Debug("TestProxNetwork start") + + for _, nodeId := range d.sim.NodeIDs() { + kad, err := d.getKademlia(&nodeId) + if err != nil { + return err + } + d.nodeAddrs[nodeId] = kad.BaseAddr() + } + + for i := 0; i < int(msgCount); i++ { + msgAddr := pot.RandomAddress() // we choose message addresses randomly + d.msgs = append(d.msgs, msgAddr.Bytes()) + smallestPo := 256 + var targets []enode.ID + var closestPO int + + // loop through all nodes and find the required and allowed recipients of each message + // (for more information, please see the comment to the main test function) + for _, nod := range d.sim.Net.GetNodes() { + po, _ := pof(d.msgs[i], d.nodeAddrs[nod.ID()], 0) + depth := d.kademlias[nod.ID()].NeighbourhoodDepth() + + // only nodes with closest IDs (wrt the msg address) will be required recipients + if po > closestPO { + closestPO = po + targets = nil + targets = append(targets, nod.ID()) + } else if po == closestPO { + targets = append(targets, nod.ID()) + } + + if po >= depth { + d.allowedMessages++ + d.allowed[i] = append(d.allowed[i], nod.ID()) + d.allowedMsgs[nod.ID()] = append(d.allowedMsgs[nod.ID()], uint64(i)) + } + + // a node with the smallest PO (wrt msg) will be the sender, + // in order to increase the distance the msg must travel + if po < smallestPo { + smallestPo = po + d.senders[i] = nod.ID() + } + } + + d.requiredMessages += len(targets) + for _, id := range targets { + d.recipients[i] = append(d.recipients[i], id) + d.expectedMsgs[id] = append(d.expectedMsgs[id], uint64(i)) + } + + log.Debug("nn for msg", "targets", len(d.recipients[i]), "msgidx", i, "msg", common.Bytes2Hex(msgAddr[:8]), "sender", d.senders[i], "senderpo", smallestPo) + } + log.Debug("msgs to receive", "count", d.requiredMessages) + return nil +} + +// Here we test specific functionality of the pss, setting the prox property of +// the handler. The tests generate a number of messages with random addresses. +// Then, for each message it calculates which nodes have the msg address +// within its nearest neighborhood depth, and stores those nodes as possible +// recipients. Those nodes that are the closest to the message address (nodes +// belonging to the deepest PO wrt the msg address) are stored as required +// recipients. The difference between allowed and required recipients results +// from the fact that the nearest neighbours are not necessarily reciprocal. +// Upon sending the messages, the test verifies that the respective message is +// passed to the message handlers of these required recipients. The test fails +// if a message is handled by recipient which is not listed among the allowed +// recipients of this particular message. It also fails after timeout, if not +// all the required recipients have received their respective messages. +// +// For example, if proximity order of certain msg address is 4, and node X +// has PO=5 wrt the message address, and nodes Y and Z have PO=6, then: +// nodes Y and Z will be considered required recipients of the msg, +// whereas nodes X, Y and Z will be allowed recipients. +func TestProxNetwork(t *testing.T) { + t.Run("16/16/15", testProxNetwork) +} + +// params in run name: nodes/msgs +func TestProxNetworkLong(t *testing.T) { + if !*longrunning { + t.Skip("run with --longrunning flag to run extensive network tests") + } + t.Run("8/100/30", testProxNetwork) + t.Run("16/100/30", testProxNetwork) + t.Run("32/100/60", testProxNetwork) + t.Run("64/100/60", testProxNetwork) + t.Run("128/100/120", testProxNetwork) +} + +func testProxNetwork(t *testing.T) { + tstdata := newTestData() + msgCount, nodeCount, timeout := getCmdParams(t) + handlerContextFuncs := make(map[Topic]handlerContextFunc) + handlerContextFuncs[topic] = nodeMsgHandler + services := newProxServices(tstdata, true, handlerContextFuncs, tstdata.kademlias) + tstdata.sim = simulation.New(services) + defer tstdata.sim.Close() + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + filename := fmt.Sprintf("testdata/snapshot_%d.json", nodeCount) + err := tstdata.sim.UploadSnapshot(ctx, filename) + if err != nil { + t.Fatal(err) + } + err = tstdata.init(msgCount) // initialize the test data + if err != nil { + t.Fatal(err) + } + wrapper := func(c context.Context, _ *simulation.Simulation) error { + return testRoutine(tstdata, c) + } + result := tstdata.sim.Run(ctx, wrapper) // call the main test function + if result.Error != nil { + // context deadline exceeded + // however, it might just mean that not all possible messages are received + // now we must check if all required messages are received + cnt := tstdata.getMsgCount() + log.Debug("TestProxNetwork finished", "rcv", cnt) + if cnt < tstdata.requiredMessages { + t.Fatal(result.Error) + } + } + t.Logf("completed %d", result.Duration) +} + +func (tstdata *testData) sendAllMsgs() { + for i, msg := range tstdata.msgs { + log.Debug("sending msg", "idx", i, "from", tstdata.senders[i]) + nodeClient, err := tstdata.sim.Net.GetNode(tstdata.senders[i]).Client() + if err != nil { + tstdata.errC <- err + } + var uvarByte [8]byte + binary.PutUvarint(uvarByte[:], uint64(i)) + nodeClient.Call(nil, "pss_sendRaw", hexutil.Encode(msg), hexutil.Encode(topic[:]), hexutil.Encode(uvarByte[:])) + } + log.Debug("all messages sent") +} + +// testRoutine is the main test function, called by Simulation.Run() +func testRoutine(tstdata *testData, ctx context.Context) error { + go handlerChannelListener(tstdata, ctx) + go tstdata.sendAllMsgs() + received := 0 + + // collect incoming messages and terminate with corresponding status when message handler listener ends + for { + select { + case err := <-tstdata.errC: + return err + case hn := <-tstdata.msgC: + received++ + log.Debug("msg received", "msgs_received", received, "total_expected", tstdata.requiredMessages, "id", hn.id, "serial", hn.serial) + if received == tstdata.allowedMessages { + close(tstdata.doneC) + return nil + } + } + } + return nil +} + +func handlerChannelListener(tstdata *testData, ctx context.Context) { + for { + select { + case <-tstdata.doneC: // graceful exit + tstdata.setDone() + tstdata.errC <- nil + return + + case <-ctx.Done(): // timeout or cancel + tstdata.setDone() + tstdata.errC <- ctx.Err() + return + + // incoming message from pss message handler + case handlerNotification := <-tstdata.handlerC: + // check if recipient has already received all its messages and notify to fail the test if so + aMsgs := tstdata.allowedMsgs[handlerNotification.id] + if len(aMsgs) == 0 { + tstdata.setDone() + tstdata.errC <- fmt.Errorf("too many messages received by recipient %x", handlerNotification.id) + return + } + + // check if message serial is in expected messages for this recipient and notify to fail the test if not + idx := -1 + for i, msg := range aMsgs { + if handlerNotification.serial == msg { + idx = i + break + } + } + if idx == -1 { + tstdata.setDone() + tstdata.errC <- fmt.Errorf("message %d received by wrong recipient %v", handlerNotification.serial, handlerNotification.id) + return + } + + // message is ok, so remove that message serial from the recipient expectation array and notify the main sim thread + aMsgs[idx] = aMsgs[len(aMsgs)-1] + aMsgs = aMsgs[:len(aMsgs)-1] + tstdata.msgC <- handlerNotification + } + } +} + +func nodeMsgHandler(tstdata *testData, config *adapters.NodeConfig) *handler { + return &handler{ + f: func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + cnt := tstdata.incrementMsgCount() + log.Debug("nodeMsgHandler rcv", "cnt", cnt) + + // using simple serial in message body, makes it easy to keep track of who's getting what + serial, c := binary.Uvarint(msg) + if c <= 0 { + log.Crit(fmt.Sprintf("corrupt message received by %x (uvarint parse returned %d)", config.ID, c)) + } + + if tstdata.isDone() { + return errors.New("handlers aborted") // terminate if simulation is over + } + + // pass message context to the listener in the simulation + tstdata.handlerC <- handlerNotification{ + id: config.ID, + serial: serial, + } + return nil + }, + caps: &handlerCaps{ + raw: true, // we use raw messages for simplicity + prox: true, + }, + } +} + +// an adaptation of the same services setup as in pss_test.go +// replaces pss_test.go when those tests are rewritten to the new swarm/network/simulation package +func newProxServices(tstdata *testData, allowRaw bool, handlerContextFuncs map[Topic]handlerContextFunc, kademlias map[enode.ID]*network.Kademlia) map[string]simulation.ServiceFunc { + stateStore := state.NewInmemoryStore() + kademlia := func(id enode.ID, bzzkey []byte) *network.Kademlia { + if k, ok := kademlias[id]; ok { + return k + } + params := network.NewKadParams() + params.MaxBinSize = 3 + params.MinBinSize = 1 + params.MaxRetries = 1000 + params.RetryExponent = 2 + params.RetryInterval = 1000000 + kademlias[id] = network.NewKademlia(bzzkey, params) + return kademlias[id] + } + return map[string]simulation.ServiceFunc{ + "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + var err error + var bzzPrivateKey *ecdsa.PrivateKey + // normally translation of enode id to swarm address is concealed by the network package + // however, we need to keep track of it in the test driver as well. + // if the translation in the network package changes, that can cause these tests to unpredictably fail + // therefore we keep a local copy of the translation here + addr := network.NewAddr(ctx.Config.Node()) + bzzPrivateKey, err = simulation.BzzPrivateKeyFromConfig(ctx.Config) + if err != nil { + return nil, nil, err + } + addr.OAddr = network.PrivateKeyToBzzKey(bzzPrivateKey) + b.Store(simulation.BucketKeyBzzPrivateKey, bzzPrivateKey) + hp := network.NewHiveParams() + hp.Discovery = false + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + return network.NewBzz(config, kademlia(ctx.Config.ID, addr.OAddr), stateStore, nil, nil), nil, nil + }, + "pss": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + // execadapter does not exec init() + initTest() + + // create keys in whisper and set up the pss object + ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second*3) + defer cancel() + keys, err := wapi.NewKeyPair(ctxlocal) + privkey, err := w.GetPrivateKey(keys) + pssp := NewPssParams().WithPrivateKey(privkey) + pssp.AllowRaw = allowRaw + bzzPrivateKey, err := simulation.BzzPrivateKeyFromConfig(ctx.Config) + if err != nil { + return nil, nil, err + } + bzzKey := network.PrivateKeyToBzzKey(bzzPrivateKey) + pskad := kademlia(ctx.Config.ID, bzzKey) + ps, err := NewPss(pskad, pssp) + if err != nil { + return nil, nil, err + } + + // register the handlers we've been passed + var deregisters []func() + for tpc, hndlrFunc := range handlerContextFuncs { + deregisters = append(deregisters, ps.Register(&tpc, hndlrFunc(tstdata, ctx.Config))) + } + + // if handshake mode is set, add the controller + // TODO: This should be hooked to the handshake test file + if useHandshake { + SetHandshakeController(ps, NewHandshakeParams()) + } + + // we expose some api calls for cheating + ps.addAPI(rpc.API{ + Namespace: "psstest", + Version: "0.3", + Service: NewAPITest(ps), + Public: false, + }) + + b.Store(simulation.BucketKeyKademlia, pskad) + + // return Pss and cleanups + return ps, func() { + // run the handler deregister functions in reverse order + for i := len(deregisters); i > 0; i-- { + deregisters[i-1]() + } + }, nil + }, + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss.go index e1e24e1f..0d02c9b8 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss.go @@ -23,6 +23,7 @@ import ( "crypto/rand" "errors" "fmt" + "hash" "sync" "time" @@ -37,7 +38,8 @@ import ( "github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/pot" "github.com/ethereum/go-ethereum/swarm/storage" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" + "golang.org/x/crypto/sha3" ) const ( @@ -79,7 +81,7 @@ type senderPeer interface { // member `protected` prevents garbage collection of the instance type pssPeer struct { lastSeen time.Time - address *PssAddress + address PssAddress protected bool } @@ -110,10 +112,11 @@ func (params *PssParams) WithPrivateKey(privatekey *ecdsa.PrivateKey) *PssParams // // Implements node.Service type Pss struct { - *network.Kademlia // we can get the Kademlia address from this - privateKey *ecdsa.PrivateKey // pss can have it's own independent key - w *whisper.Whisper // key and encryption backend - auxAPIs []rpc.API // builtins (handshake, test) can add APIs + *network.Kademlia // we can get the Kademlia address from this + *KeyStore + + privateKey *ecdsa.PrivateKey // pss can have it's own independent key + auxAPIs []rpc.API // builtins (handshake, test) can add APIs // sending and forwarding fwdPool map[string]*protocols.Peer // keep track of all peers sitting on the pssmsg routing layer @@ -126,20 +129,12 @@ type Pss struct { capstring string outbox chan *PssMsg - // keys and peers - pubKeyPool map[string]map[Topic]*pssPeer // mapping of hex public keys to peer address by topic. - pubKeyPoolMu sync.RWMutex - symKeyPool map[string]map[Topic]*pssPeer // mapping of symkeyids to peer address by topic. - symKeyPoolMu sync.RWMutex - symKeyDecryptCache []*string // fast lookup of symkeys recently used for decryption; last used is on top of stack - symKeyDecryptCacheCursor int // modular cursor pointing to last used, wraps on symKeyDecryptCache array - symKeyDecryptCacheCapacity int // max amount of symkeys to keep. - // message handling - handlers map[Topic]map[*Handler]bool // topic and version based pss payload handlers. See pss.Handle() - handlersMu sync.RWMutex - allowRaw bool - hashPool sync.Pool + handlers map[Topic]map[*handler]bool // topic and version based pss payload handlers. See pss.Handle() + handlersMu sync.RWMutex + hashPool sync.Pool + topicHandlerCaps map[Topic]*handlerCaps // caches capabilities of each topic's handlers + topicHandlerCapsMu sync.RWMutex // process quitC chan struct{} @@ -162,9 +157,10 @@ func NewPss(k *network.Kademlia, params *PssParams) (*Pss, error) { Version: pssVersion, } ps := &Pss{ - Kademlia: k, + Kademlia: k, + KeyStore: loadKeyStore(), + privateKey: params.privateKey, - w: whisper.New(&whisper.DefaultConfig), quitC: make(chan struct{}), fwdPool: make(map[string]*protocols.Peer), @@ -175,16 +171,12 @@ func NewPss(k *network.Kademlia, params *PssParams) (*Pss, error) { capstring: cap.String(), outbox: make(chan *PssMsg, defaultOutboxCapacity), - pubKeyPool: make(map[string]map[Topic]*pssPeer), - symKeyPool: make(map[string]map[Topic]*pssPeer), - symKeyDecryptCache: make([]*string, params.SymKeyCacheCapacity), - symKeyDecryptCacheCapacity: params.SymKeyCacheCapacity, + handlers: make(map[Topic]map[*handler]bool), + topicHandlerCaps: make(map[Topic]*handlerCaps), - handlers: make(map[Topic]map[*Handler]bool), - allowRaw: params.AllowRaw, hashPool: sync.Pool{ New: func() interface{} { - return storage.MakeHashFunc(storage.DefaultHash)() + return sha3.NewLegacyKeccak256() }, }, } @@ -304,6 +296,19 @@ func (p *Pss) PublicKey() *ecdsa.PublicKey { // SECTION: Message handling ///////////////////////////////////////////////////////////////////// +func (p *Pss) getTopicHandlerCaps(topic Topic) (hc *handlerCaps, found bool) { + p.topicHandlerCapsMu.RLock() + defer p.topicHandlerCapsMu.RUnlock() + hc, found = p.topicHandlerCaps[topic] + return +} + +func (p *Pss) setTopicHandlerCaps(topic Topic, hc *handlerCaps) { + p.topicHandlerCapsMu.Lock() + defer p.topicHandlerCapsMu.Unlock() + p.topicHandlerCaps[topic] = hc +} + // Links a handler function to a Topic // // All incoming messages with an envelope Topic matching the @@ -313,33 +318,55 @@ func (p *Pss) PublicKey() *ecdsa.PublicKey { // // Returns a deregister function which needs to be called to // deregister the handler, -func (p *Pss) Register(topic *Topic, handler Handler) func() { +func (p *Pss) Register(topic *Topic, hndlr *handler) func() { p.handlersMu.Lock() defer p.handlersMu.Unlock() handlers := p.handlers[*topic] if handlers == nil { - handlers = make(map[*Handler]bool) + handlers = make(map[*handler]bool) p.handlers[*topic] = handlers + log.Debug("registered handler", "capabilities", hndlr.caps) } - handlers[&handler] = true - return func() { p.deregister(topic, &handler) } + if hndlr.caps == nil { + hndlr.caps = &handlerCaps{} + } + handlers[hndlr] = true + + capabilities, ok := p.getTopicHandlerCaps(*topic) + if !ok { + capabilities = &handlerCaps{} + p.setTopicHandlerCaps(*topic, capabilities) + } + + if hndlr.caps.raw { + capabilities.raw = true + } + if hndlr.caps.prox { + capabilities.prox = true + } + return func() { p.deregister(topic, hndlr) } } -func (p *Pss) deregister(topic *Topic, h *Handler) { + +func (p *Pss) deregister(topic *Topic, hndlr *handler) { p.handlersMu.Lock() defer p.handlersMu.Unlock() handlers := p.handlers[*topic] - if len(handlers) == 1 { + if len(handlers) > 1 { delete(p.handlers, *topic) + // topic caps might have changed now that a handler is gone + caps := &handlerCaps{} + for h := range handlers { + if h.caps.raw { + caps.raw = true + } + if h.caps.prox { + caps.prox = true + } + } + p.setTopicHandlerCaps(*topic, caps) return } - delete(handlers, h) -} - -// get all registered handlers for respective topics -func (p *Pss) getHandlers(topic Topic) map[*Handler]bool { - p.handlersMu.RLock() - defer p.handlersMu.RUnlock() - return p.handlers[topic] + delete(handlers, hndlr) } // Filters incoming messages for processing or forwarding. @@ -348,12 +375,11 @@ func (p *Pss) getHandlers(topic Topic) map[*Handler]bool { // Only passes error to pss protocol handler if payload is not valid pssmsg func (p *Pss) handlePssMsg(ctx context.Context, msg interface{}) error { metrics.GetOrRegisterCounter("pss.handlepssmsg", nil).Inc(1) - pssmsg, ok := msg.(*PssMsg) - if !ok { return fmt.Errorf("invalid message type. Expected *PssMsg, got %T ", msg) } + log.Trace("handler", "self", label(p.Kademlia.BaseAddr()), "topic", label(pssmsg.Payload.Topic[:])) if int64(pssmsg.Expire) < time.Now().Unix() { metrics.GetOrRegisterCounter("pss.expire", nil).Inc(1) log.Warn("pss filtered expired message", "from", common.ToHex(p.Kademlia.BaseAddr()), "to", common.ToHex(pssmsg.To)) @@ -365,42 +391,62 @@ func (p *Pss) handlePssMsg(ctx context.Context, msg interface{}) error { } p.addFwdCache(pssmsg) - if !p.isSelfPossibleRecipient(pssmsg) { - log.Trace("pss was for someone else :'( ... forwarding", "pss", common.ToHex(p.BaseAddr())) + psstopic := Topic(pssmsg.Payload.Topic) + + // raw is simplest handler contingency to check, so check that first + var isRaw bool + if pssmsg.isRaw() { + if capabilities, ok := p.getTopicHandlerCaps(psstopic); ok { + if !capabilities.raw { + log.Debug("No handler for raw message", "topic", psstopic) + return nil + } + } + isRaw = true + } + + // check if we can be recipient: + // - no prox handler on message and partial address matches + // - prox handler on message and we are in prox regardless of partial address match + // store this result so we don't calculate again on every handler + var isProx bool + if capabilities, ok := p.getTopicHandlerCaps(psstopic); ok { + isProx = capabilities.prox + } + isRecipient := p.isSelfPossibleRecipient(pssmsg, isProx) + if !isRecipient { + log.Trace("pss msg forwarding ===>", "pss", common.ToHex(p.BaseAddr()), "prox", isProx) return p.enqueue(pssmsg) } - log.Trace("pss for us, yay! ... let's process!", "pss", common.ToHex(p.BaseAddr())) - if err := p.process(pssmsg); err != nil { + log.Trace("pss msg processing <===", "pss", common.ToHex(p.BaseAddr()), "prox", isProx, "raw", isRaw, "topic", label(pssmsg.Payload.Topic[:])) + if err := p.process(pssmsg, isRaw, isProx); err != nil { qerr := p.enqueue(pssmsg) if qerr != nil { return fmt.Errorf("process fail: processerr %v, queueerr: %v", err, qerr) } } return nil - } // Entry point to processing a message for which the current node can be the intended recipient. // Attempts symmetric and asymmetric decryption with stored keys. // Dispatches message to all handlers matching the message topic -func (p *Pss) process(pssmsg *PssMsg) error { +func (p *Pss) process(pssmsg *PssMsg, raw bool, prox bool) error { metrics.GetOrRegisterCounter("pss.process", nil).Inc(1) var err error var recvmsg *whisper.ReceivedMessage var payload []byte - var from *PssAddress + var from PssAddress var asymmetric bool var keyid string - var keyFunc func(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, *PssAddress, error) + var keyFunc func(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) envelope := pssmsg.Payload psstopic := Topic(envelope.Topic) - if pssmsg.isRaw() { - if !p.allowRaw { - return errors.New("raw message support disabled") - } + + if raw { payload = pssmsg.Payload.Data } else { if pssmsg.isSym() { @@ -417,24 +463,38 @@ func (p *Pss) process(pssmsg *PssMsg) error { payload = recvmsg.Payload } - if len(pssmsg.To) < addressLength { - if err := p.enqueue(pssmsg); err != nil { - return err - } + if len(pssmsg.To) < addressLength || prox { + err = p.enqueue(pssmsg) } - p.executeHandlers(psstopic, payload, from, asymmetric, keyid) - - return nil - + p.executeHandlers(psstopic, payload, from, raw, prox, asymmetric, keyid) + return err } -func (p *Pss) executeHandlers(topic Topic, payload []byte, from *PssAddress, asymmetric bool, keyid string) { +// copy all registered handlers for respective topic in order to avoid data race or deadlock +func (p *Pss) getHandlers(topic Topic) (ret []*handler) { + p.handlersMu.RLock() + defer p.handlersMu.RUnlock() + for k := range p.handlers[topic] { + ret = append(ret, k) + } + return ret +} + +func (p *Pss) executeHandlers(topic Topic, payload []byte, from PssAddress, raw bool, prox bool, asymmetric bool, keyid string) { handlers := p.getHandlers(topic) peer := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%x", from), []p2p.Cap{}) - for f := range handlers { - err := (*f)(payload, peer, asymmetric, keyid) + for _, h := range handlers { + if !h.caps.raw && raw { + log.Warn("norawhandler") + continue + } + if !h.caps.prox && prox { + log.Warn("noproxhandler") + continue + } + err := (h.f)(payload, peer, asymmetric, keyid) if err != nil { - log.Warn("Pss handler %p failed: %v", f, err) + log.Warn("Pss handler failed", "err", err) } } } @@ -445,224 +505,23 @@ func (p *Pss) isSelfRecipient(msg *PssMsg) bool { } // test match of leftmost bytes in given message to node's Kademlia address -func (p *Pss) isSelfPossibleRecipient(msg *PssMsg) bool { +func (p *Pss) isSelfPossibleRecipient(msg *PssMsg, prox bool) bool { local := p.Kademlia.BaseAddr() - return bytes.Equal(msg.To, local[:len(msg.To)]) -} -///////////////////////////////////////////////////////////////////// -// SECTION: Encryption -///////////////////////////////////////////////////////////////////// + // if a partial address matches we are possible recipient regardless of prox + // if not and prox is not set, we are surely not + if bytes.Equal(msg.To, local[:len(msg.To)]) { -// Links a peer ECDSA public key to a topic -// -// This is required for asymmetric message exchange -// on the given topic -// -// The value in `address` will be used as a routing hint for the -// public key / topic association -func (p *Pss) SetPeerPublicKey(pubkey *ecdsa.PublicKey, topic Topic, address *PssAddress) error { - pubkeybytes := crypto.FromECDSAPub(pubkey) - if len(pubkeybytes) == 0 { - return fmt.Errorf("invalid public key: %v", pubkey) - } - pubkeyid := common.ToHex(pubkeybytes) - psp := &pssPeer{ - address: address, - } - p.pubKeyPoolMu.Lock() - if _, ok := p.pubKeyPool[pubkeyid]; !ok { - p.pubKeyPool[pubkeyid] = make(map[Topic]*pssPeer) - } - p.pubKeyPool[pubkeyid][topic] = psp - p.pubKeyPoolMu.Unlock() - log.Trace("added pubkey", "pubkeyid", pubkeyid, "topic", topic, "address", common.ToHex(*address)) - return nil -} - -// Automatically generate a new symkey for a topic and address hint -func (p *Pss) GenerateSymmetricKey(topic Topic, address *PssAddress, addToCache bool) (string, error) { - keyid, err := p.w.GenerateSymKey() - if err != nil { - return "", err - } - p.addSymmetricKeyToPool(keyid, topic, address, addToCache, false) - return keyid, nil -} - -// Links a peer symmetric key (arbitrary byte sequence) to a topic -// -// This is required for symmetrically encrypted message exchange -// on the given topic -// -// The key is stored in the whisper backend. -// -// If addtocache is set to true, the key will be added to the cache of keys -// used to attempt symmetric decryption of incoming messages. -// -// Returns a string id that can be used to retrieve the key bytes -// from the whisper backend (see pss.GetSymmetricKey()) -func (p *Pss) SetSymmetricKey(key []byte, topic Topic, address *PssAddress, addtocache bool) (string, error) { - return p.setSymmetricKey(key, topic, address, addtocache, true) -} - -func (p *Pss) setSymmetricKey(key []byte, topic Topic, address *PssAddress, addtocache bool, protected bool) (string, error) { - keyid, err := p.w.AddSymKeyDirect(key) - if err != nil { - return "", err - } - p.addSymmetricKeyToPool(keyid, topic, address, addtocache, protected) - return keyid, nil -} - -// adds a symmetric key to the pss key pool, and optionally adds the key -// to the collection of keys used to attempt symmetric decryption of -// incoming messages -func (p *Pss) addSymmetricKeyToPool(keyid string, topic Topic, address *PssAddress, addtocache bool, protected bool) { - psp := &pssPeer{ - address: address, - protected: protected, - } - p.symKeyPoolMu.Lock() - if _, ok := p.symKeyPool[keyid]; !ok { - p.symKeyPool[keyid] = make(map[Topic]*pssPeer) - } - p.symKeyPool[keyid][topic] = psp - p.symKeyPoolMu.Unlock() - if addtocache { - p.symKeyDecryptCacheCursor++ - p.symKeyDecryptCache[p.symKeyDecryptCacheCursor%cap(p.symKeyDecryptCache)] = &keyid - } - key, _ := p.GetSymmetricKey(keyid) - log.Trace("added symkey", "symkeyid", keyid, "symkey", common.ToHex(key), "topic", topic, "address", fmt.Sprintf("%p", address), "cache", addtocache) -} - -// Returns a symmetric key byte seqyence stored in the whisper backend -// by its unique id -// -// Passes on the error value from the whisper backend -func (p *Pss) GetSymmetricKey(symkeyid string) ([]byte, error) { - symkey, err := p.w.GetSymKey(symkeyid) - if err != nil { - return nil, err - } - return symkey, nil -} - -// Returns all recorded topic and address combination for a specific public key -func (p *Pss) GetPublickeyPeers(keyid string) (topic []Topic, address []PssAddress, err error) { - p.pubKeyPoolMu.RLock() - defer p.pubKeyPoolMu.RUnlock() - for t, peer := range p.pubKeyPool[keyid] { - topic = append(topic, t) - address = append(address, *peer.address) + return true + } else if !prox { + return false } - return topic, address, nil -} + depth := p.Kademlia.NeighbourhoodDepth() + po, _ := network.Pof(p.Kademlia.BaseAddr(), msg.To, 0) + log.Trace("selfpossible", "po", po, "depth", depth) -func (p *Pss) getPeerAddress(keyid string, topic Topic) (PssAddress, error) { - p.pubKeyPoolMu.RLock() - defer p.pubKeyPoolMu.RUnlock() - if peers, ok := p.pubKeyPool[keyid]; ok { - if t, ok := peers[topic]; ok { - return *t.address, nil - } - } - return nil, fmt.Errorf("peer with pubkey %s, topic %x not found", keyid, topic) -} - -// Attempt to decrypt, validate and unpack a -// symmetrically encrypted message -// If successful, returns the unpacked whisper ReceivedMessage struct -// encapsulating the decrypted message, and the whisper backend id -// of the symmetric key used to decrypt the message. -// It fails if decryption of the message fails or if the message is corrupted -func (p *Pss) processSym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, *PssAddress, error) { - metrics.GetOrRegisterCounter("pss.process.sym", nil).Inc(1) - - for i := p.symKeyDecryptCacheCursor; i > p.symKeyDecryptCacheCursor-cap(p.symKeyDecryptCache) && i > 0; i-- { - symkeyid := p.symKeyDecryptCache[i%cap(p.symKeyDecryptCache)] - symkey, err := p.w.GetSymKey(*symkeyid) - if err != nil { - continue - } - recvmsg, err := envelope.OpenSymmetric(symkey) - if err != nil { - continue - } - if !recvmsg.Validate() { - return nil, "", nil, fmt.Errorf("symmetrically encrypted message has invalid signature or is corrupt") - } - p.symKeyPoolMu.Lock() - from := p.symKeyPool[*symkeyid][Topic(envelope.Topic)].address - p.symKeyPoolMu.Unlock() - p.symKeyDecryptCacheCursor++ - p.symKeyDecryptCache[p.symKeyDecryptCacheCursor%cap(p.symKeyDecryptCache)] = symkeyid - return recvmsg, *symkeyid, from, nil - } - return nil, "", nil, fmt.Errorf("could not decrypt message") -} - -// Attempt to decrypt, validate and unpack an -// asymmetrically encrypted message -// If successful, returns the unpacked whisper ReceivedMessage struct -// encapsulating the decrypted message, and the byte representation of -// the public key used to decrypt the message. -// It fails if decryption of message fails, or if the message is corrupted -func (p *Pss) processAsym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, *PssAddress, error) { - metrics.GetOrRegisterCounter("pss.process.asym", nil).Inc(1) - - recvmsg, err := envelope.OpenAsymmetric(p.privateKey) - if err != nil { - return nil, "", nil, fmt.Errorf("could not decrypt message: %s", err) - } - // check signature (if signed), strip padding - if !recvmsg.Validate() { - return nil, "", nil, fmt.Errorf("invalid message") - } - pubkeyid := common.ToHex(crypto.FromECDSAPub(recvmsg.Src)) - var from *PssAddress - p.pubKeyPoolMu.Lock() - if p.pubKeyPool[pubkeyid][Topic(envelope.Topic)] != nil { - from = p.pubKeyPool[pubkeyid][Topic(envelope.Topic)].address - } - p.pubKeyPoolMu.Unlock() - return recvmsg, pubkeyid, from, nil -} - -// Symkey garbage collection -// a key is removed if: -// - it is not marked as protected -// - it is not in the incoming decryption cache -func (p *Pss) cleanKeys() (count int) { - for keyid, peertopics := range p.symKeyPool { - var expiredtopics []Topic - for topic, psp := range peertopics { - if psp.protected { - continue - } - - var match bool - for i := p.symKeyDecryptCacheCursor; i > p.symKeyDecryptCacheCursor-cap(p.symKeyDecryptCache) && i > 0; i-- { - cacheid := p.symKeyDecryptCache[i%cap(p.symKeyDecryptCache)] - if *cacheid == keyid { - match = true - } - } - if !match { - expiredtopics = append(expiredtopics, topic) - } - } - for _, topic := range expiredtopics { - p.symKeyPoolMu.Lock() - delete(p.symKeyPool[keyid], topic) - log.Trace("symkey cleanup deletion", "symkeyid", keyid, "topic", topic, "val", p.symKeyPool[keyid]) - p.symKeyPoolMu.Unlock() - count++ - } - } - return + return depth <= po } ///////////////////////////////////////////////////////////////////// @@ -684,8 +543,8 @@ func (p *Pss) enqueue(msg *PssMsg) error { // // Will fail if raw messages are disallowed func (p *Pss) SendRaw(address PssAddress, topic Topic, msg []byte) error { - if !p.allowRaw { - return errors.New("Raw messages not enabled") + if err := validateAddress(address); err != nil { + return err } pssMsgParams := &msgParams{ raw: true, @@ -699,7 +558,19 @@ func (p *Pss) SendRaw(address PssAddress, topic Topic, msg []byte) error { pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) pssMsg.Payload = payload p.addFwdCache(pssMsg) - return p.enqueue(pssMsg) + err := p.enqueue(pssMsg) + if err != nil { + return err + } + + // if we have a proxhandler on this topic + // also deliver message to ourselves + if capabilities, ok := p.getTopicHandlerCaps(topic); ok { + if p.isSelfPossibleRecipient(pssMsg, true) && capabilities.prox { + return p.process(pssMsg, true, true) + } + } + return nil } // Send a message using symmetric encryption @@ -710,16 +581,11 @@ func (p *Pss) SendSym(symkeyid string, topic Topic, msg []byte) error { if err != nil { return fmt.Errorf("missing valid send symkey %s: %v", symkeyid, err) } - p.symKeyPoolMu.Lock() - psp, ok := p.symKeyPool[symkeyid][topic] - p.symKeyPoolMu.Unlock() + psp, ok := p.getPeerSym(symkeyid, topic) if !ok { return fmt.Errorf("invalid topic '%s' for symkey '%s'", topic.String(), symkeyid) - } else if psp.address == nil { - return fmt.Errorf("no address hint for topic '%s' symkey '%s'", topic.String(), symkeyid) } - err = p.send(*psp.address, topic, msg, false, symkey) - return err + return p.send(psp.address, topic, msg, false, symkey) } // Send a message using asymmetric encryption @@ -729,18 +595,11 @@ func (p *Pss) SendAsym(pubkeyid string, topic Topic, msg []byte) error { if _, err := crypto.UnmarshalPubkey(common.FromHex(pubkeyid)); err != nil { return fmt.Errorf("Cannot unmarshal pubkey: %x", pubkeyid) } - p.pubKeyPoolMu.Lock() - psp, ok := p.pubKeyPool[pubkeyid][topic] - p.pubKeyPoolMu.Unlock() + psp, ok := p.getPeerPub(pubkeyid, topic) if !ok { return fmt.Errorf("invalid topic '%s' for pubkey '%s'", topic.String(), pubkeyid) - } else if psp.address == nil { - return fmt.Errorf("no address hint for topic '%s' pubkey '%s'", topic.String(), pubkeyid) } - go func() { - p.send(*psp.address, topic, msg, true, common.FromHex(pubkeyid)) - }() - return nil + return p.send(psp.address, topic, msg, true, common.FromHex(pubkeyid)) } // Send is payload agnostic, and will accept any byte slice as payload @@ -800,71 +659,109 @@ func (p *Pss) send(to []byte, topic Topic, msg []byte, asymmetric bool, key []by pssMsg.To = to pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) pssMsg.Payload = envelope - return p.enqueue(pssMsg) + err = p.enqueue(pssMsg) + if err != nil { + return err + } + if capabilities, ok := p.getTopicHandlerCaps(topic); ok { + if p.isSelfPossibleRecipient(pssMsg, true) && capabilities.prox { + return p.process(pssMsg, true, true) + } + } + return nil } -// Forwards a pss message to the peer(s) closest to the to recipient address in the PssMsg struct -// The recipient address can be of any length, and the byte slice will be matched to the MSB slice -// of the peer address of the equivalent length. +// sendFunc is a helper function that tries to send a message and returns true on success. +// It is set here for usage in production, and optionally overridden in tests. +var sendFunc = sendMsg + +// tries to send a message, returns true if successful +func sendMsg(p *Pss, sp *network.Peer, msg *PssMsg) bool { + var isPssEnabled bool + info := sp.Info() + for _, capability := range info.Caps { + if capability == p.capstring { + isPssEnabled = true + break + } + } + if !isPssEnabled { + log.Error("peer doesn't have matching pss capabilities, skipping", "peer", info.Name, "caps", info.Caps) + return false + } + + // get the protocol peer from the forwarding peer cache + p.fwdPoolMu.RLock() + pp := p.fwdPool[sp.Info().ID] + p.fwdPoolMu.RUnlock() + + err := pp.Send(context.TODO(), msg) + if err != nil { + metrics.GetOrRegisterCounter("pss.pp.send.error", nil).Inc(1) + log.Error(err.Error()) + } + + return err == nil +} + +// Forwards a pss message to the peer(s) based on recipient address according to the algorithm +// described below. The recipient address can be of any length, and the byte slice will be matched +// to the MSB slice of the peer address of the equivalent length. +// +// If the recipient address (or partial address) is within the neighbourhood depth of the forwarding +// node, then it will be forwarded to all the nearest neighbours of the forwarding node. In case of +// partial address, it should be forwarded to all the peers matching the partial address, if there +// are any; otherwise only to one peer, closest to the recipient address. In any case, if the message +// forwarding fails, the node should try to forward it to the next best peer, until the message is +// successfully forwarded to at least one peer. func (p *Pss) forward(msg *PssMsg) error { metrics.GetOrRegisterCounter("pss.forward", nil).Inc(1) - + sent := 0 // number of successful sends to := make([]byte, addressLength) copy(to[:len(msg.To)], msg.To) + neighbourhoodDepth := p.Kademlia.NeighbourhoodDepth() - // send with kademlia - // find the closest peer to the recipient and attempt to send - sent := 0 - p.Kademlia.EachConn(to, 256, func(sp *network.Peer, po int, isproxbin bool) bool { - info := sp.Info() + // luminosity is the opposite of darkness. the more bytes are removed from the address, the higher is darkness, + // but the luminosity is less. here luminosity equals the number of bits given in the destination address. + luminosityRadius := len(msg.To) * 8 - // check if the peer is running pss - var ispss bool - for _, cap := range info.Caps { - if cap == p.capstring { - ispss = true - break + // proximity order function matching up to neighbourhoodDepth bits (po <= neighbourhoodDepth) + pof := pot.DefaultPof(neighbourhoodDepth) + + // soft threshold for msg broadcast + broadcastThreshold, _ := pof(to, p.BaseAddr(), 0) + if broadcastThreshold > luminosityRadius { + broadcastThreshold = luminosityRadius + } + + var onlySendOnce bool // indicates if the message should only be sent to one peer with closest address + + // if measured from the recipient address as opposed to the base address (see Kademlia.EachConn + // call below), then peers that fall in the same proximity bin as recipient address will appear + // [at least] one bit closer, but only if these additional bits are given in the recipient address. + if broadcastThreshold < luminosityRadius && broadcastThreshold < neighbourhoodDepth { + broadcastThreshold++ + onlySendOnce = true + } + + p.Kademlia.EachConn(to, addressLength*8, func(sp *network.Peer, po int) bool { + if po < broadcastThreshold && sent > 0 { + return false // stop iterating + } + if sendFunc(p, sp, msg) { + sent++ + if onlySendOnce { + return false + } + if po == addressLength*8 { + // stop iterating if successfully sent to the exact recipient (perfect match of full address) + return false } } - if !ispss { - log.Trace("peer doesn't have matching pss capabilities, skipping", "peer", info.Name, "caps", info.Caps) - return true - } - - // get the protocol peer from the forwarding peer cache - sendMsg := fmt.Sprintf("MSG TO %x FROM %x VIA %x", to, p.BaseAddr(), sp.Address()) - p.fwdPoolMu.RLock() - pp := p.fwdPool[sp.Info().ID] - p.fwdPoolMu.RUnlock() - - // attempt to send the message - err := pp.Send(context.TODO(), msg) - if err != nil { - metrics.GetOrRegisterCounter("pss.pp.send.error", nil).Inc(1) - log.Error(err.Error()) - return true - } - sent++ - log.Trace(fmt.Sprintf("%v: successfully forwarded", sendMsg)) - - // continue forwarding if: - // - if the peer is end recipient but the full address has not been disclosed - // - if the peer address matches the partial address fully - // - if the peer is in proxbin - if len(msg.To) < addressLength && bytes.Equal(msg.To, sp.Address()[:len(msg.To)]) { - log.Trace(fmt.Sprintf("Pss keep forwarding: Partial address + full partial match")) - return true - } else if isproxbin { - log.Trace(fmt.Sprintf("%x is in proxbin, keep forwarding", common.ToHex(sp.Address()))) - return true - } - // at this point we stop forwarding, and the state is as follows: - // - the peer is end recipient and we have full address - // - we are not in proxbin (directed routing) - // - partial addresses don't fully match - return false + return true }) + // if we failed to send to anyone, re-insert message in the send-queue if sent == 0 { log.Debug("unable to forward to any peers") if err := p.enqueue(msg); err != nil { @@ -895,6 +792,10 @@ func (p *Pss) cleanFwdCache() { } } +func label(b []byte) string { + return fmt.Sprintf("%04x", b[:2]) +} + // add a message to the cache func (p *Pss) addFwdCache(msg *PssMsg) error { metrics.GetOrRegisterCounter("pss.addfwdcache", nil).Inc(1) @@ -934,12 +835,23 @@ func (p *Pss) checkFwdCache(msg *PssMsg) bool { // Digest of message func (p *Pss) digest(msg *PssMsg) pssDigest { - hasher := p.hashPool.Get().(storage.SwarmHash) + return p.digestBytes(msg.serialize()) +} + +func (p *Pss) digestBytes(msg []byte) pssDigest { + hasher := p.hashPool.Get().(hash.Hash) defer p.hashPool.Put(hasher) hasher.Reset() - hasher.Write(msg.serialize()) + hasher.Write(msg) digest := pssDigest{} key := hasher.Sum(nil) copy(digest[:], key[:digestLength]) return digest } + +func validateAddress(addr PssAddress) error { + if len(addr) > addressLength { + return errors.New("address too long") + } + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss_test.go index 66a90be6..ea7a591b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/pss_test.go @@ -38,8 +38,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/metrics/influxdb" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" @@ -48,20 +46,23 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/pot" "github.com/ethereum/go-ethereum/swarm/state" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) var ( - initOnce = sync.Once{} - debugdebugflag = flag.Bool("vv", false, "veryverbose") - debugflag = flag.Bool("v", false, "verbose") - longrunning = flag.Bool("longrunning", false, "do run long-running tests") - w *whisper.Whisper - wapi *whisper.PublicWhisperAPI - psslogmain log.Logger - pssprotocols map[string]*protoCtrl - useHandshake bool + initOnce = sync.Once{} + loglevel = flag.Int("loglevel", 2, "logging verbosity") + longrunning = flag.Bool("longrunning", false, "do run long-running tests") + w *whisper.Whisper + wapi *whisper.PublicWhisperAPI + psslogmain log.Logger + pssprotocols map[string]*protoCtrl + useHandshake bool + noopHandlerFunc = func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + return nil + } ) func init() { @@ -75,16 +76,9 @@ func init() { func initTest() { initOnce.Do( func() { - loglevel := log.LvlInfo - if *debugflag { - loglevel = log.LvlDebug - } else if *debugdebugflag { - loglevel = log.LvlTrace - } - psslogmain = log.New("psslog", "*") hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) - hf := log.LvlFilterHandler(loglevel, hs) + hf := log.LvlFilterHandler(log.Lvl(*loglevel), hs) h := log.CallerFileHandler(hf) log.Root().SetHandler(h) @@ -174,6 +168,7 @@ func TestCache(t *testing.T) { t.Fatal(err) } ps := newTestPss(privkey, nil, nil) + defer ps.Stop() pp := NewPssParams().WithPrivateKey(privkey) data := []byte("foo") datatwo := []byte("bar") @@ -280,15 +275,14 @@ func TestAddressMatch(t *testing.T) { } pssmsg := &PssMsg{ - To: remoteaddr, - Payload: &whisper.Envelope{}, + To: remoteaddr, } // differ from first byte if ps.isSelfRecipient(pssmsg) { t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) } - if ps.isSelfPossibleRecipient(pssmsg) { + if ps.isSelfPossibleRecipient(pssmsg, false) { t.Fatalf("isSelfPossibleRecipient true but %x != %x", remoteaddr[:8], localaddr[:8]) } @@ -297,7 +291,7 @@ func TestAddressMatch(t *testing.T) { if ps.isSelfRecipient(pssmsg) { t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) } - if !ps.isSelfPossibleRecipient(pssmsg) { + if !ps.isSelfPossibleRecipient(pssmsg, false) { t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) } @@ -306,13 +300,342 @@ func TestAddressMatch(t *testing.T) { if !ps.isSelfRecipient(pssmsg) { t.Fatalf("isSelfRecipient false but %x == %x", remoteaddr, localaddr) } - if !ps.isSelfPossibleRecipient(pssmsg) { + if !ps.isSelfPossibleRecipient(pssmsg, false) { t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) } + +} + +// test that message is handled by sender if a prox handler exists and sender is in prox of message +func TestProxShortCircuit(t *testing.T) { + + // sender node address + localAddr := network.RandomAddr().Over() + localPotAddr := pot.NewAddressFromBytes(localAddr) + + // set up kademlia + kadParams := network.NewKadParams() + kad := network.NewKademlia(localAddr, kadParams) + peerCount := kad.MinBinSize + 1 + + // set up pss + privKey, err := crypto.GenerateKey() + pssp := NewPssParams().WithPrivateKey(privKey) + ps, err := NewPss(kad, pssp) + if err != nil { + t.Fatal(err.Error()) + } + + // create kademlia peers, so we have peers both inside and outside minproxlimit + var peers []*network.Peer + proxMessageAddress := pot.RandomAddressAt(localPotAddr, peerCount).Bytes() + distantMessageAddress := pot.RandomAddressAt(localPotAddr, 0).Bytes() + + for i := 0; i < peerCount; i++ { + rw := &p2p.MsgPipeRW{} + ptpPeer := p2p.NewPeer(enode.ID{}, "wanna be with me? [ ] yes [ ] no", []p2p.Cap{}) + protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) + peerAddr := pot.RandomAddressAt(localPotAddr, i) + bzzPeer := &network.BzzPeer{ + Peer: protoPeer, + BzzAddr: &network.BzzAddr{ + OAddr: peerAddr.Bytes(), + UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), + }, + } + peer := network.NewPeer(bzzPeer, kad) + kad.On(peer) + peers = append(peers, peer) + } + + // register it marking prox capability + delivered := make(chan struct{}) + rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + log.Trace("in allowraw handler") + delivered <- struct{}{} + return nil + } + topic := BytesToTopic([]byte{0x2a}) + hndlrProxDereg := ps.Register(&topic, &handler{ + f: rawHandlerFunc, + caps: &handlerCaps{ + raw: true, + prox: true, + }, + }) + defer hndlrProxDereg() + + // send message too far away for sender to be in prox + // reception of this message should time out + errC := make(chan error) + go func() { + err := ps.SendRaw(distantMessageAddress, topic, []byte("foo")) + if err != nil { + errC <- err + } + }() + + ctx, cancel := context.WithTimeout(context.TODO(), time.Second) + defer cancel() + select { + case <-delivered: + t.Fatal("raw distant message delivered") + case err := <-errC: + t.Fatal(err) + case <-ctx.Done(): + } + + // send message that should be within sender prox + // this message should be delivered + go func() { + err := ps.SendRaw(proxMessageAddress, topic, []byte("bar")) + if err != nil { + errC <- err + } + }() + + ctx, cancel = context.WithTimeout(context.TODO(), time.Second) + defer cancel() + select { + case <-delivered: + case err := <-errC: + t.Fatal(err) + case <-ctx.Done(): + t.Fatal("raw timeout") + } + + // try the same prox message with sym and asym send + proxAddrPss := PssAddress(proxMessageAddress) + symKeyId, err := ps.GenerateSymmetricKey(topic, proxAddrPss, true) + go func() { + err := ps.SendSym(symKeyId, topic, []byte("baz")) + if err != nil { + errC <- err + } + }() + ctx, cancel = context.WithTimeout(context.TODO(), time.Second) + defer cancel() + select { + case <-delivered: + case err := <-errC: + t.Fatal(err) + case <-ctx.Done(): + t.Fatal("sym timeout") + } + + err = ps.SetPeerPublicKey(&privKey.PublicKey, topic, proxAddrPss) + if err != nil { + t.Fatal(err) + } + pubKeyId := hexutil.Encode(crypto.FromECDSAPub(&privKey.PublicKey)) + go func() { + err := ps.SendAsym(pubKeyId, topic, []byte("xyzzy")) + if err != nil { + errC <- err + } + }() + ctx, cancel = context.WithTimeout(context.TODO(), time.Second) + defer cancel() + select { + case <-delivered: + case err := <-errC: + t.Fatal(err) + case <-ctx.Done(): + t.Fatal("asym timeout") + } } -// -func TestHandlerConditions(t *testing.T) { +// verify that node can be set as recipient regardless of explicit message address match if minimum one handler of a topic is explicitly set to allow it +// note that in these tests we use the raw capability on handlers for convenience +func TestAddressMatchProx(t *testing.T) { + + // recipient node address + localAddr := network.RandomAddr().Over() + localPotAddr := pot.NewAddressFromBytes(localAddr) + + // set up kademlia + kadparams := network.NewKadParams() + kad := network.NewKademlia(localAddr, kadparams) + nnPeerCount := kad.MinBinSize + peerCount := nnPeerCount + 2 + + // set up pss + privKey, err := crypto.GenerateKey() + pssp := NewPssParams().WithPrivateKey(privKey) + ps, err := NewPss(kad, pssp) + if err != nil { + t.Fatal(err.Error()) + } + + // create kademlia peers, so we have peers both inside and outside minproxlimit + var peers []*network.Peer + for i := 0; i < peerCount; i++ { + rw := &p2p.MsgPipeRW{} + ptpPeer := p2p.NewPeer(enode.ID{}, "362436 call me anytime", []p2p.Cap{}) + protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) + peerAddr := pot.RandomAddressAt(localPotAddr, i) + bzzPeer := &network.BzzPeer{ + Peer: protoPeer, + BzzAddr: &network.BzzAddr{ + OAddr: peerAddr.Bytes(), + UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), + }, + } + peer := network.NewPeer(bzzPeer, kad) + kad.On(peer) + peers = append(peers, peer) + } + + // TODO: create a test in the network package to make a table with n peers where n-m are proxpeers + // meanwhile test regression for kademlia since we are compiling the test parameters from different packages + var proxes int + var conns int + depth := kad.NeighbourhoodDepth() + kad.EachConn(nil, peerCount, func(p *network.Peer, po int) bool { + conns++ + if po >= depth { + proxes++ + } + return true + }) + if proxes != nnPeerCount { + t.Fatalf("expected %d proxpeers, have %d", nnPeerCount, proxes) + } else if conns != peerCount { + t.Fatalf("expected %d peers total, have %d", peerCount, proxes) + } + + // remote address distances from localAddr to try and the expected outcomes if we use prox handler + remoteDistances := []int{ + 255, + nnPeerCount + 1, + nnPeerCount, + nnPeerCount - 1, + 0, + } + expects := []bool{ + true, + true, + true, + false, + false, + } + + // first the unit test on the method that calculates possible receipient using prox + for i, distance := range remoteDistances { + pssMsg := newPssMsg(&msgParams{}) + pssMsg.To = make([]byte, len(localAddr)) + copy(pssMsg.To, localAddr) + var byteIdx = distance / 8 + pssMsg.To[byteIdx] ^= 1 << uint(7-(distance%8)) + log.Trace(fmt.Sprintf("addrmatch %v", bytes.Equal(pssMsg.To, localAddr))) + if ps.isSelfPossibleRecipient(pssMsg, true) != expects[i] { + t.Fatalf("expected distance %d to be %v", distance, expects[i]) + } + } + + // we move up to higher level and test the actual message handler + // for each distance check if we are possible recipient when prox variant is used is set + + // this handler will increment a counter for every message that gets passed to the handler + var receives int + rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + log.Trace("in allowraw handler") + receives++ + return nil + } + + // register it marking prox capability + topic := BytesToTopic([]byte{0x2a}) + hndlrProxDereg := ps.Register(&topic, &handler{ + f: rawHandlerFunc, + caps: &handlerCaps{ + raw: true, + prox: true, + }, + }) + + // test the distances + var prevReceive int + for i, distance := range remoteDistances { + remotePotAddr := pot.RandomAddressAt(localPotAddr, distance) + remoteAddr := remotePotAddr.Bytes() + + var data [32]byte + rand.Read(data[:]) + pssMsg := newPssMsg(&msgParams{raw: true}) + pssMsg.To = remoteAddr + pssMsg.Expire = uint32(time.Now().Unix() + 4200) + pssMsg.Payload = &whisper.Envelope{ + Topic: whisper.TopicType(topic), + Data: data[:], + } + + log.Trace("withprox addrs", "local", localAddr, "remote", remoteAddr) + ps.handlePssMsg(context.TODO(), pssMsg) + if (!expects[i] && prevReceive != receives) || (expects[i] && prevReceive == receives) { + t.Fatalf("expected distance %d recipient %v when prox is set for handler", distance, expects[i]) + } + prevReceive = receives + } + + // now add a non prox-capable handler and test + ps.Register(&topic, &handler{ + f: rawHandlerFunc, + caps: &handlerCaps{ + raw: true, + }, + }) + receives = 0 + prevReceive = 0 + for i, distance := range remoteDistances { + remotePotAddr := pot.RandomAddressAt(localPotAddr, distance) + remoteAddr := remotePotAddr.Bytes() + + var data [32]byte + rand.Read(data[:]) + pssMsg := newPssMsg(&msgParams{raw: true}) + pssMsg.To = remoteAddr + pssMsg.Expire = uint32(time.Now().Unix() + 4200) + pssMsg.Payload = &whisper.Envelope{ + Topic: whisper.TopicType(topic), + Data: data[:], + } + + log.Trace("withprox addrs", "local", localAddr, "remote", remoteAddr) + ps.handlePssMsg(context.TODO(), pssMsg) + if (!expects[i] && prevReceive != receives) || (expects[i] && prevReceive == receives) { + t.Fatalf("expected distance %d recipient %v when prox is set for handler", distance, expects[i]) + } + prevReceive = receives + } + + // now deregister the prox capable handler, now none of the messages will be handled + hndlrProxDereg() + receives = 0 + + for _, distance := range remoteDistances { + remotePotAddr := pot.RandomAddressAt(localPotAddr, distance) + remoteAddr := remotePotAddr.Bytes() + + pssMsg := newPssMsg(&msgParams{raw: true}) + pssMsg.To = remoteAddr + pssMsg.Expire = uint32(time.Now().Unix() + 4200) + pssMsg.Payload = &whisper.Envelope{ + Topic: whisper.TopicType(topic), + Data: []byte(remotePotAddr.String()), + } + + log.Trace("noprox addrs", "local", localAddr, "remote", remoteAddr) + ps.handlePssMsg(context.TODO(), pssMsg) + if receives != 0 { + t.Fatalf("expected distance %d to not be recipient when prox is not set for handler", distance) + } + + } +} + +// verify that message queueing happens when it should, and that expired and corrupt messages are dropped +func TestMessageProcessing(t *testing.T) { t.Skip("Disabled due to probable faulty logic for outbox expectations") // setup @@ -324,15 +647,15 @@ func TestHandlerConditions(t *testing.T) { addr := make([]byte, 32) addr[0] = 0x01 ps := newTestPss(privkey, network.NewKademlia(addr, network.NewKadParams()), NewPssParams()) + defer ps.Stop() // message should pass - msg := &PssMsg{ - To: addr, - Expire: uint32(time.Now().Add(time.Second * 60).Unix()), - Payload: &whisper.Envelope{ - Topic: [4]byte{}, - Data: []byte{0x66, 0x6f, 0x6f}, - }, + msg := newPssMsg(&msgParams{}) + msg.To = addr + msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) + msg.Payload = &whisper.Envelope{ + Topic: [4]byte{}, + Data: []byte{0x66, 0x6f, 0x6f}, } if err := ps.handlePssMsg(context.TODO(), msg); err != nil { t.Fatal(err.Error()) @@ -457,20 +780,21 @@ func TestKeys(t *testing.T) { t.Fatalf("failed to retrieve 'their' private key") } ps := newTestPss(ourprivkey, nil, nil) + defer ps.Stop() // set up peer with mock address, mapped to mocked publicaddress and with mocked symkey addr := make(PssAddress, 32) copy(addr, network.RandomAddr().Over()) outkey := network.RandomAddr().Over() topicobj := BytesToTopic([]byte("foo:42")) - ps.SetPeerPublicKey(&theirprivkey.PublicKey, topicobj, &addr) - outkeyid, err := ps.SetSymmetricKey(outkey, topicobj, &addr, false) + ps.SetPeerPublicKey(&theirprivkey.PublicKey, topicobj, addr) + outkeyid, err := ps.SetSymmetricKey(outkey, topicobj, addr, false) if err != nil { t.Fatalf("failed to set 'our' outgoing symmetric key") } // make a symmetric key that we will send to peer for encrypting messages to us - inkeyid, err := ps.GenerateSymmetricKey(topicobj, &addr, true) + inkeyid, err := ps.GenerateSymmetricKey(topicobj, addr, true) if err != nil { t.Fatalf("failed to set 'our' incoming symmetric key") } @@ -493,11 +817,12 @@ func TestKeys(t *testing.T) { // check that the key is stored in the peerpool psp := ps.symKeyPool[inkeyid][topicobj] - if psp.address != &addr { - t.Fatalf("inkey address does not match; %p != %p", psp.address, &addr) + if !bytes.Equal(psp.address, addr) { + t.Fatalf("inkey address does not match; %p != %p", psp.address, addr) } } +// check that we can retrieve previously added public key entires per topic and peer func TestGetPublickeyEntries(t *testing.T) { privkey, err := crypto.GenerateKey() @@ -505,6 +830,7 @@ func TestGetPublickeyEntries(t *testing.T) { t.Fatal(err) } ps := newTestPss(privkey, nil, nil) + defer ps.Stop() peeraddr := network.RandomAddr().Over() topicaddr := make(map[Topic]PssAddress) @@ -557,7 +883,7 @@ OUTER: } // forwarding should skip peers that do not have matching pss capabilities -func TestMismatch(t *testing.T) { +func TestPeerCapabilityMismatch(t *testing.T) { // create privkey for forwarder node privkey, err := crypto.GenerateKey() @@ -608,6 +934,7 @@ func TestMismatch(t *testing.T) { Payload: &whisper.Envelope{}, } ps := newTestPss(privkey, kad, nil) + defer ps.Stop() // run the forward // it is enough that it completes; trying to send to incapable peers would create segfault @@ -615,6 +942,105 @@ func TestMismatch(t *testing.T) { } +// verifies that message handlers for raw messages only are invoked when minimum one handler for the topic exists in which raw messages are explicitly allowed +func TestRawAllow(t *testing.T) { + + // set up pss like so many times before + privKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + baseAddr := network.RandomAddr() + kad := network.NewKademlia((baseAddr).Over(), network.NewKadParams()) + ps := newTestPss(privKey, kad, nil) + defer ps.Stop() + topic := BytesToTopic([]byte{0x2a}) + + // create handler innards that increments every time a message hits it + var receives int + rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + log.Trace("in allowraw handler") + receives++ + return nil + } + + // wrap this handler function with a handler without raw capability and register it + hndlrNoRaw := &handler{ + f: rawHandlerFunc, + } + ps.Register(&topic, hndlrNoRaw) + + // test it with a raw message, should be poo-poo + pssMsg := newPssMsg(&msgParams{ + raw: true, + }) + pssMsg.To = baseAddr.OAddr + pssMsg.Expire = uint32(time.Now().Unix() + 4200) + pssMsg.Payload = &whisper.Envelope{ + Topic: whisper.TopicType(topic), + } + ps.handlePssMsg(context.TODO(), pssMsg) + if receives > 0 { + t.Fatalf("Expected handler not to be executed with raw cap off") + } + + // now wrap the same handler function with raw capabilities and register it + hndlrRaw := &handler{ + f: rawHandlerFunc, + caps: &handlerCaps{ + raw: true, + }, + } + deregRawHandler := ps.Register(&topic, hndlrRaw) + + // should work now + pssMsg.Payload.Data = []byte("Raw Deal") + ps.handlePssMsg(context.TODO(), pssMsg) + if receives == 0 { + t.Fatalf("Expected handler to be executed with raw cap on") + } + + // now deregister the raw capable handler + prevReceives := receives + deregRawHandler() + + // check that raw messages fail again + pssMsg.Payload.Data = []byte("Raw Trump") + ps.handlePssMsg(context.TODO(), pssMsg) + if receives != prevReceives { + t.Fatalf("Expected handler not to be executed when raw handler is retracted") + } +} + +// BELOW HERE ARE TESTS USING THE SIMULATION FRAMEWORK + +// tests that the API layer can handle edge case values +func TestApi(t *testing.T) { + clients, err := setupNetwork(2, true) + if err != nil { + t.Fatal(err) + } + + topic := "0xdeadbeef" + + err = clients[0].Call(nil, "pss_sendRaw", "0x", topic, "0x666f6f") + if err != nil { + t.Fatal(err) + } + + err = clients[0].Call(nil, "pss_sendRaw", "0xabcdef", topic, "0x") + if err == nil { + t.Fatal("expected error on empty msg") + } + + overflowAddr := [33]byte{} + err = clients[0].Call(nil, "pss_sendRaw", hexutil.Encode(overflowAddr[:]), topic, "0x666f6f") + if err == nil { + t.Fatal("expected error on send too big address") + } +} + +// verifies that nodes can send and receive raw (verbatim) messages func TestSendRaw(t *testing.T) { t.Run("32", testSendRaw) t.Run("8", testSendRaw) @@ -658,19 +1084,19 @@ func testSendRaw(t *testing.T) { lmsgC := make(chan APIMsg) lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) defer lcancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) + lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, true, false) log.Trace("lsub", "id", lsub) defer lsub.Unsubscribe() rmsgC := make(chan APIMsg) rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) defer rcancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) + rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, true, false) log.Trace("rsub", "id", rsub) defer rsub.Unsubscribe() // send and verify delivery lmsg := []byte("plugh") - err = clients[1].Call(nil, "pss_sendRaw", loaddrhex, topic, lmsg) + err = clients[1].Call(nil, "pss_sendRaw", loaddrhex, topic, hexutil.Encode(lmsg)) if err != nil { t.Fatal(err) } @@ -683,7 +1109,7 @@ func testSendRaw(t *testing.T) { t.Fatalf("test message (left) timed out: %v", cerr) } rmsg := []byte("xyzzy") - err = clients[0].Call(nil, "pss_sendRaw", roaddrhex, topic, rmsg) + err = clients[0].Call(nil, "pss_sendRaw", roaddrhex, topic, hexutil.Encode(rmsg)) if err != nil { t.Fatal(err) } @@ -757,13 +1183,13 @@ func testSendSym(t *testing.T) { lmsgC := make(chan APIMsg) lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) defer lcancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) + lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false) log.Trace("lsub", "id", lsub) defer lsub.Unsubscribe() rmsgC := make(chan APIMsg) rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) defer rcancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) + rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) log.Trace("rsub", "id", rsub) defer rsub.Unsubscribe() @@ -872,13 +1298,13 @@ func testSendAsym(t *testing.T) { lmsgC := make(chan APIMsg) lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) defer lcancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) + lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false) log.Trace("lsub", "id", lsub) defer lsub.Unsubscribe() rmsgC := make(chan APIMsg) rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) defer rcancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) + rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) log.Trace("rsub", "id", rsub) defer rsub.Unsubscribe() @@ -941,8 +1367,6 @@ func TestNetwork(t *testing.T) { // nodes/msgs/addrbytes/adaptertype // if adaptertype is exec uses execadapter, simadapter otherwise func TestNetwork2000(t *testing.T) { - //enableMetrics() - if !*longrunning { t.Skip("run with --longrunning flag to run extensive network tests") } @@ -953,8 +1377,6 @@ func TestNetwork2000(t *testing.T) { } func TestNetwork5000(t *testing.T) { - //enableMetrics() - if !*longrunning { t.Skip("run with --longrunning flag to run extensive network tests") } @@ -965,8 +1387,6 @@ func TestNetwork5000(t *testing.T) { } func TestNetwork10000(t *testing.T) { - //enableMetrics() - if !*longrunning { t.Skip("run with --longrunning flag to run extensive network tests") } @@ -1037,7 +1457,7 @@ func testNetwork(t *testing.T) { msgC := make(chan APIMsg) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", topic) + sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", topic, false, false) if err != nil { t.Fatal(err) } @@ -1209,7 +1629,7 @@ func TestDeduplication(t *testing.T) { rmsgC := make(chan APIMsg) rctx, cancel := context.WithTimeout(context.Background(), time.Second*1) defer cancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) + rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) log.Trace("rsub", "id", rsub) defer rsub.Unsubscribe() @@ -1269,12 +1689,13 @@ func benchmarkSymKeySend(b *testing.B) { keys, err := wapi.NewKeyPair(ctx) privkey, err := w.GetPrivateKey(keys) ps := newTestPss(privkey, nil, nil) + defer ps.Stop() msg := make([]byte, msgsize) rand.Read(msg) topic := BytesToTopic([]byte("foo")) to := make(PssAddress, 32) copy(to[:], network.RandomAddr().Over()) - symkeyid, err := ps.GenerateSymmetricKey(topic, &to, true) + symkeyid, err := ps.GenerateSymmetricKey(topic, to, true) if err != nil { b.Fatalf("could not generate symkey: %v", err) } @@ -1282,7 +1703,7 @@ func benchmarkSymKeySend(b *testing.B) { if err != nil { b.Fatalf("could not retrieve symkey: %v", err) } - ps.SetSymmetricKey(symkey, topic, &to, false) + ps.SetSymmetricKey(symkey, topic, to, false) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -1313,12 +1734,13 @@ func benchmarkAsymKeySend(b *testing.B) { keys, err := wapi.NewKeyPair(ctx) privkey, err := w.GetPrivateKey(keys) ps := newTestPss(privkey, nil, nil) + defer ps.Stop() msg := make([]byte, msgsize) rand.Read(msg) topic := BytesToTopic([]byte("foo")) to := make(PssAddress, 32) copy(to[:], network.RandomAddr().Over()) - ps.SetPeerPublicKey(&privkey.PublicKey, topic, &to) + ps.SetPeerPublicKey(&privkey.PublicKey, topic, to) b.ResetTimer() for i := 0; i < b.N; i++ { ps.SendAsym(common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey)), topic, msg) @@ -1363,11 +1785,12 @@ func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { } else { ps = newTestPss(privkey, nil, nil) } + defer ps.Stop() topic := BytesToTopic([]byte("foo")) for i := 0; i < int(keycount); i++ { to := make(PssAddress, 32) copy(to[:], network.RandomAddr().Over()) - keyid, err = ps.GenerateSymmetricKey(topic, &to, true) + keyid, err = ps.GenerateSymmetricKey(topic, to, true) if err != nil { b.Fatalf("cant generate symkey #%d: %v", i, err) } @@ -1392,8 +1815,8 @@ func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { if err != nil { b.Fatalf("could not generate whisper envelope: %v", err) } - ps.Register(&topic, func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - return nil + ps.Register(&topic, &handler{ + f: noopHandlerFunc, }) pssmsgs = append(pssmsgs, &PssMsg{ To: to, @@ -1402,7 +1825,7 @@ func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - if err := ps.process(pssmsgs[len(pssmsgs)-(i%len(pssmsgs))-1]); err != nil { + if err := ps.process(pssmsgs[len(pssmsgs)-(i%len(pssmsgs))-1], false, false); err != nil { b.Fatalf("pss processing failed: %v", err) } } @@ -1446,10 +1869,11 @@ func benchmarkSymkeyBruteforceSameaddr(b *testing.B) { } else { ps = newTestPss(privkey, nil, nil) } + defer ps.Stop() topic := BytesToTopic([]byte("foo")) for i := 0; i < int(keycount); i++ { copy(addr[i], network.RandomAddr().Over()) - keyid, err = ps.GenerateSymmetricKey(topic, &addr[i], true) + keyid, err = ps.GenerateSymmetricKey(topic, addr[i], true) if err != nil { b.Fatalf("cant generate symkey #%d: %v", i, err) } @@ -1476,15 +1900,15 @@ func benchmarkSymkeyBruteforceSameaddr(b *testing.B) { if err != nil { b.Fatalf("could not generate whisper envelope: %v", err) } - ps.Register(&topic, func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - return nil + ps.Register(&topic, &handler{ + f: noopHandlerFunc, }) pssmsg := &PssMsg{ To: addr[len(addr)-1][:], Payload: env, } for i := 0; i < b.N; i++ { - if err := ps.process(pssmsg); err != nil { + if err := ps.process(pssmsg, false, false); err != nil { b.Fatalf("pss processing failed: %v", err) } } @@ -1543,7 +1967,7 @@ func newServices(allowRaw bool) adapters.Services { return k } params := network.NewKadParams() - params.MinProxBinSize = 2 + params.NeighbourhoodSize = 2 params.MaxBinSize = 3 params.MinBinSize = 1 params.MaxRetries = 1000 @@ -1581,7 +2005,12 @@ func newServices(allowRaw bool) adapters.Services { if useHandshake { SetHandshakeController(ps, NewHandshakeParams()) } - ps.Register(&PingTopic, pp.Handle) + ps.Register(&PingTopic, &handler{ + f: pp.Handle, + caps: &handlerCaps{ + raw: true, + }, + }) ps.addAPI(rpc.API{ Namespace: "psstest", Version: "0.3", @@ -1618,7 +2047,7 @@ func newTestPss(privkey *ecdsa.PrivateKey, kad *network.Kademlia, ppextra *PssPa // set up routing if kademlia is not passed to us if kad == nil { kp := network.NewKadParams() - kp.MinProxBinSize = 3 + kp.NeighbourhoodSize = 3 kad = network.NewKademlia(nid[:], kp) } @@ -1645,12 +2074,13 @@ func NewAPITest(ps *Pss) *APITest { return &APITest{Pss: ps} } -func (apitest *APITest) SetSymKeys(pubkeyid string, recvsymkey []byte, sendsymkey []byte, limit uint16, topic Topic, to PssAddress) ([2]string, error) { - recvsymkeyid, err := apitest.SetSymmetricKey(recvsymkey, topic, &to, true) +func (apitest *APITest) SetSymKeys(pubkeyid string, recvsymkey []byte, sendsymkey []byte, limit uint16, topic Topic, to hexutil.Bytes) ([2]string, error) { + + recvsymkeyid, err := apitest.SetSymmetricKey(recvsymkey, topic, PssAddress(to), true) if err != nil { return [2]string{}, err } - sendsymkeyid, err := apitest.SetSymmetricKey(sendsymkey, topic, &to, false) + sendsymkeyid, err := apitest.SetSymmetricKey(sendsymkey, topic, PssAddress(to), false) if err != nil { return [2]string{}, err } @@ -1660,11 +2090,3 @@ func (apitest *APITest) SetSymKeys(pubkeyid string, recvsymkey []byte, sendsymke func (apitest *APITest) Clean() (int, error) { return apitest.Pss.cleanKeys(), nil } - -// enableMetrics is starting InfluxDB reporter so that we collect stats when running tests locally -func enableMetrics() { - metrics.Enabled = true - go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 1*time.Second, "http://localhost:8086", "metrics", "admin", "admin", "swarm.", map[string]string{ - "host": "test", - }) -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/addpsstodiscoverytestsnapshot.pl b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/addpsstodiscoverytestsnapshot.pl deleted file mode 100644 index b75cc989..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/addpsstodiscoverytestsnapshot.pl +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/perl - -use JSON; - -my $f; -my $jsontext; -my $nodelist; -my $network; - -open($f, "<", $ARGV[0]) || die "cant open " . $ARGV[0]; -while (<$f>) { - $jsontext .= $_; -} -close($f); - -$network = decode_json($jsontext); -$nodelist = $network->{'nodes'}; - -for ($i = 0; $i < 0+@$nodelist; $i++) { - #my $protocollist = $$nodelist[$i]{'node'}{'info'}{'protocols'}; - #$$protocollist{'pss'} = "pss"; - my $svc = $$nodelist[$i]{'node'}{'config'}{'services'}; - pop(@$svc); - push(@$svc, "pss"); - push(@$svc, "bzz"); -} - -print encode_json($network); diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/addpsstodiscoverytestsnapshot.sh b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/addpsstodiscoverytestsnapshot.sh deleted file mode 100644 index 7d3c2849..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/addpsstodiscoverytestsnapshot.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -sed -e 's/\(\"services\"\):\["discovery\"]/\1:["pss","bzz"]/' diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_128.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_128.json index 7bafd358..8e1bc88b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_128.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_128.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","private_key":"79eaaa1c3a9339a90cf54c511649caf683f2910588a872d2c12919355b7d5d28","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","private_key":"b067839f81534251ade8651e682dbd8324dfb83c7034aff4a48909e9310c990a","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","private_key":"4233e4c480ae197c265975cc7c83cc7b0cf1a8d67e4728bac4bcecaee63ad935","name":"node03","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","private_key":"ca0c9f1baad4f60ddeaafe287d43b4ef8ec4b96c4ef12da194074325ca6cc4ef","name":"node04","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","private_key":"b6c09a581c2a6d85a63c11e586391346fe9d9d24292de15333ae230a33c52c1e","name":"node05","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","private_key":"378e3e11e738557d2eea27e070d52c8355f8abe0c5f8607ac0792455a1d50bae","name":"node06","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","private_key":"e6710b29bb9b7f00ee1e921bd548fc7622d73a0aae3f25de7a3f3650191147a8","name":"node07","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","private_key":"2bed1cf9737dbf8239f560ab8b4e57dc47cf57a28ebd203e6fb159093fbe52c0","name":"node08","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","private_key":"3f63c3dd3bf2b5be6e9af3ce596eb65cb58a36749d0baff1759d8dc6f4da8993","name":"node09","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","private_key":"38ffbfff1b5ab2f905daabcbbc12a5e28aad826a80d0a40988a04d6653942a50","name":"node10","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","private_key":"aa2cc30f2f6e589ca122890fc95845f4a81ad7e57f2661343ff6af3d401c46f3","name":"node11","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","private_key":"5b4a4da121c72f3d0d453394e6f09fc9ddaa5a13e44acb1ef6684867b4cac14c","name":"node12","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","private_key":"98f5b9f4be5d997b66834ae619c58f54d941623dfcb9a6783bfce77fdb3f3d4b","name":"node13","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","private_key":"cbbe3c5ab5aafd2dae03deda6db9a3e7e58ffaad5c1edd37d7a13951aa733590","name":"node14","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","private_key":"62a83d45655860933bf8a2348695dd695176f3225f4ba72e70284b648130d330","name":"node15","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","private_key":"8c72a0c564073065c5300e822a476fe3dd8b373cfd0dabaf0cdb056ca0ece2f9","name":"node16","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","private_key":"b6eb72555f9952a32406b7576ac85ead5cbe9004f37b6ebe8f7c3b6e17973104","name":"node17","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","private_key":"e9bdb2a275f0f2fd6ef4266bca55fad475c5d9e4ee0db2951ae91fd629cb2029","name":"node18","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","private_key":"d9a2bcdb02288fd5844d0be689ea4286f27991bfc82c76f6050a3e3d2f0858a1","name":"node19","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","private_key":"8ee0c4634570903c3d7383adb12cd35a82bb1c9be593755bd77c90a1bd6bbdfe","name":"node20","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","private_key":"16df12116ebc93bdc671ba1351bf03b763d3e67b2c9c468e56177c80b0dcbf84","name":"node21","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","private_key":"1a78b7fedaab9310b17675717481b1331eed3fa3c77cd96addf6bf9abd778aae","name":"node22","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","private_key":"3d37e996f181b4f57d5c5a61a07f86f1869c760604dfe9166d5b3552acf1a43b","name":"node23","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","private_key":"5895ce723440eaa77daf0a8779cc52992427524e420e3ce71ce1b24f3bd4658c","name":"node24","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","private_key":"cf20ef905d7d3d1141c472afefd12332bff10edecc695e409af38086c7a1a5d1","name":"node25","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","private_key":"1a7c744024c7baee8c43425861a5a4ff2ea80533fe6549a58e61b50c93059fed","name":"node26","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","private_key":"7399aa5562abb3ca2add08c810d607ad6fed7a036622eaea561da8a5aa51c0af","name":"node27","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","private_key":"ded7b34b0c8218bfba59e8d061b50cea365a9f137b9a66064e2287ef660dc789","name":"node28","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","private_key":"39ac5498c92329fc18c4eb0ec36cca3c5270f322084a1fc42fad1be0b5f32081","name":"node29","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","private_key":"add3ad2926ebf0b30f111796475cf160bcd1f1756866dfaa19e048c6954975c9","name":"node30","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","private_key":"d5290ae40b68ae7b51fe7ce7d83ab96841aa97a3457fc1bcf70065a2d2b60c20","name":"node31","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","private_key":"ba7abd532b10496c6363f35e231ff80aef25246315302fd138dd977d5ece20e5","name":"node32","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","private_key":"e58bb287592c2b89814ed3475004f5c9b2eb226483fcb8235619b6b42747d10c","name":"node33","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","private_key":"53e9afc6c039fee226bd9a0b537355f23e93457dc0eabbdce75e4d1ad7a473e6","name":"node34","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","private_key":"079cf6730627562bbbff031d22ab1ae9e65b7747497adc327830e5d6768d6b04","name":"node35","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","private_key":"c3157fe034d3a477f697b756cd9ae1de532b0ae42bb5039f6d2bf399bb2ddbbd","name":"node36","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","private_key":"d4472d7bc821536231d70dbdb3f0a5e3fdd104dcbf5a97c9521b0778d9491680","name":"node37","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","private_key":"23c79a6a5af06f9e9cdb6f4b4e40e25eca8793ac91db22cde17e0a3851c1f48e","name":"node38","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","private_key":"0295fa1706ccdcbdc8d7943b8d2011c6f46225d85b574d2d02b4a8dec66f9a29","name":"node39","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","private_key":"34d1685a48b56e62b30247fffb44ba2b41f2d806344fe52f7dc9049a778c667f","name":"node40","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","private_key":"b6273af6a94c07db54566d0d2f93121d0ddf239921e8e46af19babd2fa9930a7","name":"node41","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","private_key":"362244251a7f1bf4bc855ff3b272b1c7c7fe5d8338af0c581fee2f49e2939ed8","name":"node42","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","private_key":"bf6cd10025d018c0abfae2c88aa7c46c3d12d612580e6b4aacdc51fd52476270","name":"node43","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","private_key":"0659e3a41adc716b493c6ad765c5b26d35c95a1edb254efc8ab967e71e3e0a16","name":"node44","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","private_key":"f6d48b4c10f3257bba2f626d48192d94a1b1de3ab1480b618a0bff07eb20396e","name":"node45","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","private_key":"4a487eb7a3b924414d988104fce6f87a70502db2d5d71dcbc1a115b37212cb06","name":"node46","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","private_key":"9e2309fa485ace73ce907035f5113e7b13e5719c819479b10fd9386a3ad5236f","name":"node47","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","private_key":"e511c730e803371042c631512a12d74b1c31a53caab237719b8fa007e4cef9ea","name":"node48","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","private_key":"bb4c6b3c0931311ef5e31087f74a1a95aa39da470737c4c1a2a730ea2cac1c76","name":"node49","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","private_key":"88c0abdb64c6dee8117b7b720d5782321ce583fcc76e6eed2ee1f6279a82ea39","name":"node50","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","private_key":"e6eef1e846329e10e247843f7cee455af8ad3579e5a1e6360aea0ecc51982759","name":"node51","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","private_key":"ffd961376b67cbfafd47d89610291ec8fc2af2c16bc31e6851f804e15b2e9cd7","name":"node52","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","private_key":"db9ca337fd3ecf30fa6c217606072c214028b8d723ce82de57cfb4f0266a653d","name":"node53","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","private_key":"40e9de0543bd2c35509ebfcf51aa5a543d9616831505b5644e982144f4971f3a","name":"node54","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","private_key":"f2806927e5ba924b002b05116a66bdd62d4eed7900e91f3e31892288bd06ebd1","name":"node55","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","private_key":"f38a84e8d30f9c12d52071b696ff7fbd355dc875cbf937d2f491f4f3e193fc8e","name":"node56","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","private_key":"a3895eb5276ca39ba15c02895c3537a6c3a7be75de7b2ee2bee1fc5b9a313240","name":"node57","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","private_key":"8135cdd3f1b3d517b1f4a11407dfcdf6a31b3dc087ddfe2224999f16ee7ca9de","name":"node58","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","private_key":"29e270aecc8603f2224bee7f11039231b7a28efc5b29deeb9d98d0af388a87d0","name":"node59","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","private_key":"04d1ab0b03908f14773c60464c51526f925e192645efc3781a7117f22bdc4835","name":"node60","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","private_key":"f7320ebd494ac4fd8d6871123b7531dee97fba428ff30994f4d3ecc3f9312001","name":"node61","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","private_key":"b71a899f42faf2bdf9824d145f6f5959178f61f05e460e888c862ba8b03b5448","name":"node62","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","private_key":"43ea846524b82ef37cdaa1546b555e1a8d7510fc0cc7f11a6e040b79a5fcf054","name":"node63","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","private_key":"0f863dee7eca46274fc2ec03645bf96424ffebbe6f5c26631051127cf730e223","name":"node64","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","private_key":"a70d3a2696371a3cdee8702bbc4b008a564f36a8570b3bef778d00e5c4bc7da6","name":"node65","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","private_key":"24cc61b4c4e59317c2927bd635bd3ad2863c0598321f0e5d60c3b534ed151558","name":"node66","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","private_key":"36459a9e26fc4c00dd4c89bdf4c86c717b9701169ad7154228b8fbfff55661d9","name":"node67","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","private_key":"b947082437b645032dfff6e9d20e2eed52aace2d5e29cc268b06898cededdabd","name":"node68","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","private_key":"5ac248334fa8c619d900ac284274784dc99fe0ae517e749c989a15bad1652ccf","name":"node69","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","private_key":"7c46fa70253c48efad70d0b3da97e5c5680b1fb430147ac6f821729a836c667d","name":"node70","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","private_key":"2d39f1bc0c0b3b7bdd1b9ef4fdfd54dd5b7db9743a16baa7c5f8b50948062e8d","name":"node71","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","private_key":"d4e45cb0946161c0f4333c4db19bdeabceb81b4db44982a776556e8da0bf3928","name":"node72","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","private_key":"df8fd4bcf5cb62281500f76bc0b09d7ac1576ffd0edadbb8d39301406ac8e0fd","name":"node73","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","private_key":"5ec7e6e237997309e30846fed2a2074e5a150ae82804f581cb4a69ea69fe0118","name":"node74","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","private_key":"06d5dc287feafe3797b6302002258d7ea058679dc501e7a05f64fabd41b1b701","name":"node75","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","private_key":"a06a77e7469d86991954524d4a1495b5aeb80bb413c0b1293479dcc8ce511108","name":"node76","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","private_key":"9e6c3d21c05d371fd69225b2eef1d1eabedad577ae026b6d8ad8f728a53d657b","name":"node77","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","private_key":"cd8b5f4a6c0d361bc118318b1f1c5e69ef7b546e5ded44742e97124cfb80c52e","name":"node78","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","private_key":"04ed808eb12d991a68104f16e8965f3e6d60ba0b0dabff4fe33b3878c63d25f7","name":"node79","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","private_key":"175d97bb42b8f0effb21274a929a499f0e49e8e6ecad97b853a164464ad20bde","name":"node80","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","private_key":"34dbf4adc051f2ab18ea18c1faaec6726857cc5e0fcb3181fb296a723d2971c7","name":"node81","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","private_key":"21c776bf36961c727b36ff521a7527764077944b7932dfb901ca6489b2e123e7","name":"node82","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","private_key":"db4ace065dad27967a83ad918dedd4b4d7b1aaa331057ca1a2033fcba3e16df6","name":"node83","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","private_key":"2642ed9d36375a48a74d6aee878a935a15e7bd219d39bbdf455b0a168c98a8b5","name":"node84","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","private_key":"c1c1f7cd104f6f7163fe144041570269558b335ae6ddbdb80c79687faf55f5bb","name":"node85","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","private_key":"89501ac0b58fa2ee82ba6ef2b45a3c0ab6d8f54f4b92da1111d97ecfedbf5fc3","name":"node86","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","private_key":"cf649d632a25375b28cc6f7821de3e0df16b52ad9e0ff8978b231e20d6ed37ee","name":"node87","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","private_key":"bceddc4ac81042ad71089e4c861518f8d018601263d1faa17238f1c326e4b317","name":"node88","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","private_key":"a870aecb16e345ef241f69348d08489eb250b113f2072ab6371dda815d799f3f","name":"node89","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","private_key":"07af0af8e7e43f2822c2c0c3d34a1742faf6e11328b6194a760e9acefb5dedc8","name":"node90","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","private_key":"683b9cd98aab26ece4c2e53dd44a1fde3ae2303f80f99dc7e7e5d4b80e5a40e2","name":"node91","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","private_key":"31b3da34d338fb902b718378f7b5ebbdcdff30e4e3d3deff8b021e3979a7c6de","name":"node92","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","private_key":"997bcdc19c47350a268aa991a33d767bb6fc29de16593e0b099e793aa1db638d","name":"node93","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","private_key":"393e54787cdfec2d8d987f785700170fbcb31fd541c9c05199cd77d3a16a6dc4","name":"node94","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","private_key":"0cd4a911f2b1193b22efc0823fc2ed9beddafb7705f5597ce6d7335aadae0e1a","name":"node95","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","private_key":"fb0590eb4eb2624363f0740cbc794f9adb8356ccbaf6650c8baca183edfde3b8","name":"node96","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","private_key":"40d4caee240073f0bfc9307eed26d4286f944f467837b7250ee206f40d2880d4","name":"node97","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","private_key":"207c5a4e99506c7afdfff66611cf0baefe929f7c8a1a7a802cb44df3fa650618","name":"node98","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","private_key":"fa964e311f099e564ffa3ff9820a9ad3a8723f738fce6da11be604636f275831","name":"node99","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","private_key":"23f2913103e5295ddfdc6485c2ea3c33bfda3e0ceea62cac5401ceabdda0668a","name":"node100","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","private_key":"f3c37d7a8e80e1e71fba834055bf934536fd9e117f496b156d46bca96632ba5c","name":"node101","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","private_key":"f4151729479b0ae76a7b853aa9d3460ee67adcedc364ac97248fb383478ba113","name":"node102","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","private_key":"482aa546e8e665988c7329424342961c10084e439d562aed129d21a8c212d007","name":"node103","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","private_key":"2641708c3c6101db41db1a7eba5ed6b54e7ebc3014cb575ed71d291a6aacfc28","name":"node104","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","private_key":"9b9c1c2253292c4de58f82fd6bba15922acfa246fa0717a869c0d651ce19e826","name":"node105","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","private_key":"7cc79c34ac4847aaba7f1e2de8d23910301dbfe606d052cce33ad0340a1f82fb","name":"node106","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","private_key":"4047502d07951bf2380ef595036f9e99db3b0f7e1229040e21da5fbc49e7d820","name":"node107","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","private_key":"02a6713184cf6e413a6ed6a6839150cad9c72d40951b265a754e56b5bdb74cbf","name":"node108","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","private_key":"12d74d71de5166524deeed2ba475f9ad46c296668af272f0ade12162bed0f50f","name":"node109","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","private_key":"4fff513c0f905a42d6d18a90ae6a78c60757490480579162c9e0760361baf184","name":"node110","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","private_key":"5db638bd9bfaf4c2e1af1f3f1dc1e89382a6a2982f303fc80504b44aac1a6264","name":"node111","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","private_key":"6caa9dcb10b84a658d4ef791909b6532395f0793f9f8bce99a3a1b985ce619b9","name":"node112","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","private_key":"63375740be7dc5d3a76a7b3249786a4c7382eaf8b648e5a39a7a850722bad29a","name":"node113","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","private_key":"110a610c6c2f1720584929baf4ab9c8490923fc7b421bd251e444b752f8f8957","name":"node114","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","private_key":"7a8380aa7312fe4859408a51876e9f44b56151086e4bc36569a8f55bfb3a007b","name":"node115","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","private_key":"1e498dce32dcdfdf4b6c691fa203e3809fddf1b19b1b1da0b1162b9037ecc303","name":"node116","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","private_key":"03de0803048f078de61e3eef039a9ecb0e761216573392a6692630f3f291cc25","name":"node117","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","private_key":"934aa39349989614a1b0a71785880e61c60bb2579a9d52b832887849de94ec24","name":"node118","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","private_key":"011d6fce7eed10fc8c5a7a9ca21769efc6581023c2c857c28d97a6ebb1c43a53","name":"node119","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","private_key":"76d98f9c684d01fe8121cf715f01457e9fc38146a717958c8bb325a3b4ea44ce","name":"node120","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","private_key":"7aa614585809bea3b748e6df2e1a8da2b201a9ae84f11c819b5669234a10f76d","name":"node121","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","private_key":"71857ed16ee507ae0dd576370348a196d43274a3895f26fb8659ec79c1ecb79c","name":"node122","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","private_key":"3e5c543d406054ba1338ea28c37198eb8153a157eb5a0aecc186dceb04e10632","name":"node123","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","private_key":"3771d716bd74a4be3b8e154d3aa3b2302700b5ca1607923f7414c147a7cf67b7","name":"node124","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","private_key":"25dc939bff90ac541a61b59e0d2b4d3b9891379de3893645f06891c5be0d5695","name":"node125","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","private_key":"e6ad803abcef9554bdff08a4f4b6a7a65dc574bf92d32ee882413c9269fd31f3","name":"node126","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","private_key":"a482a87960aae2e446cd2aeb304e7baeff9a24d2bace4d5f919b5bda00a5f0eb","name":"node127","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","private_key":"214126811a121d6fc0443ce66e59372bc72dea9e220ab6e7d6da961741590d47","name":"node128","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","up":true},{"one":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","other":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","up":true},{"one":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","other":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","other":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","up":true},{"one":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","other":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","other":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","up":true},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","up":true},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","up":true},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":true},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":true},{"one":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","other":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","other":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","up":true},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","up":true},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":true},{"one":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","other":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","up":true},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","other":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","up":true},{"one":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","other":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","up":true},{"one":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":true},{"one":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","other":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","up":true},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":true},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":true},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","up":true},{"one":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":true},{"one":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","up":true},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":true},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","other":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","up":true},{"one":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","other":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","up":true},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","up":true},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","up":true},{"one":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","other":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":true},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","up":true},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","other":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","up":true},{"one":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","up":true},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","up":true},{"one":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","up":true},{"one":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","other":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","up":true},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","other":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","up":true},{"one":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","up":true},{"one":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","other":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","up":true},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","up":true},{"one":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":true},{"one":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","up":true},{"one":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","up":true},{"one":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","other":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","other":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","up":true},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","up":true},{"one":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","other":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","up":true},{"one":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","up":true},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","other":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","up":true},{"one":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":true},{"one":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":true},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":true},{"one":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","up":true},{"one":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","up":true},{"one":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":true},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","other":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","up":true},{"one":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","up":true},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","other":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","up":true},{"one":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","other":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","up":true},{"one":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","other":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":true},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":true},{"one":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","up":true},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","up":true},{"one":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","other":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","up":true},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","up":true},{"one":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","other":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","up":true},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":true},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","other":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":true},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","up":true},{"one":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","up":true},{"one":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","other":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","up":true},{"one":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":true},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":true},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":true},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","up":true},{"one":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":true},{"one":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","up":true},{"one":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":true},{"one":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","other":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","up":true},{"one":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","up":true},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","up":true},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","other":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","up":true},{"one":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","other":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","up":true},{"one":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","up":true},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","other":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":true},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":true},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","other":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","up":true},{"one":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":true},{"one":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","up":true},{"one":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":true},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":true},{"one":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":true},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":true},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","other":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","up":true},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":true},{"one":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","up":true},{"one":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":true},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","up":true},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"45cdaac4c087e6b737507fa29936d09f2fbea14f49ef0ce91c18080456a7459b","other":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","up":true},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":true},{"one":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","up":true},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":true},{"one":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":true},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","up":true},{"one":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","other":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":true},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":true},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":true},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","up":true},{"one":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","other":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","up":true},{"one":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"88a9b808cabfadb31c1a01b5a09eb4dc6cb7e011348f095920dd12e330ba9c0a","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","up":true},{"one":"aff775d47ebe35fbaaad26c627470abb8481558cb5a08c42a44597a98408a919","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":true},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","other":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","up":true},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","up":true},{"one":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","other":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","other":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","up":true},{"one":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":true},{"one":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"247dcb2c787abfa845b39cb9d7f9a6d59ea915006f250a4d760cdd8e16b3a5a6","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","up":true},{"one":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","other":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","up":true},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","up":true},{"one":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","up":true},{"one":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","other":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","other":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","up":true},{"one":"d6e3d3ffd3858b8284bc9495b2d90b4b1124009a4a7d7394182977a8ae39df55","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":false},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"20c4c3a3523960ad74538e726e1caaeda987cbc16dcd3beeb63fca6eebd31405","up":false},{"one":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"07c79aaa7fa759f797b88d8c495c5bfaa12f15289c6a567bbc363fd070227830","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"0066352177d6c225842362ab424a632f569980b02ac55a13a71593af94cb8c2d","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":true},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":false},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":true},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":false},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":false},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":false},{"one":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","other":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":true},{"one":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":true},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","other":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":false},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":true},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":false},{"one":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"0104c3fa3f6b9237565759debed3f1fcebfa75efba7f01e81f06a53274cdf619","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":true},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":true},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","other":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","up":true},{"one":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":false},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","other":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":true},{"one":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"6c29a1bc0f1025207b4524fadd7c8cd3dd956816fdfc57bb525c4ad3bcca9169","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":true},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":true},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":true},{"one":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":true},{"one":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":true},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","up":true},{"one":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":false},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":true},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":false},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":true},{"one":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":true},{"one":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","other":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","up":true},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":false},{"one":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","other":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","up":false},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":false},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":true},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":false},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"adfde69b7633188d7c5a44e51e856d023c946d4cd8fd16bf539e6d1764dd7e04","up":false},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":false},{"one":"051c8d430b54d843feb325c2b56e36524566d64f48f6c770739748409af44364","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":false},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":false},{"one":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","other":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","up":true},{"one":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","other":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","up":false},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"22b84df73059c92bf59fdad51fe574e027c7cc555dddbf363d745c1c422a89fd","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":false},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":false},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","up":true},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","up":true},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","up":true},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"ac3887308a4c3591293c43f5d5f312874b30e0dc19faa57626fdc6b830d3e433","other":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","up":true},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"776fdbabbca42ecb49cc5451b860305ec3020889b47adaa2add6ea359afe379f","up":false},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","up":false},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":false},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","up":true},{"one":"78db863d7f60eda6a275cc9f4d1696cb32f5d46de747d278aa17ecd06c791135","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":false},{"one":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","other":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","up":true},{"one":"1d531b5c8dd7bbbbf8c2db8f6984d2c9b23d5fee33876379e9d3e62a920e04b9","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":true},{"one":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":true},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"e884bd666b0215cfe88ee19457c67c747fb1c6815855160f1c243c149b24e923","up":false},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":false},{"one":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":true},{"one":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","other":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","up":true},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"6b7da636e8eccac658c0abf6aa8ddd74be6d4cf9c5e0333bd28d9a6d1fe43ab3","up":false},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":false},{"one":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":true},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","up":true},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":false},{"one":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","other":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","up":false},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":true},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","up":true},{"one":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":true},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"a93b2360b87425860185535aca8fbf3225e0c141d27690d60144689ae0f28534","up":false},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","up":false},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":false},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":false},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":false},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"960eb6f745966f47aadb13d488aee1187486c99e6bc78c679a6d9b3d421d8eb0","up":false},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","up":false},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":false},{"one":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","other":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","up":false},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":false},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"6b1f3a9b65ce3a168fc98dee2b14b1de6912fd02ee2609b047b2c56f6c3b53e9","up":true},{"one":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":false},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","up":true},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","up":true},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":false},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"6ad608f1087b8af40359db45e7d78e43c3465fdae5cc01a9a9ab6c149cb6fdf3","other":"69baf7ee43b360a3238ad3b175e0ad9c24967dae60c7e91d1ca7ee55167b2bdb","up":true},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":true},{"one":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","other":"e8d0bd04fa5b56fcd50cb4b1d550855c21192f1294f2954401348c8a28b455ab","up":true},{"one":"60cbf513366da3f6ee288d3572dc3971ae256b02e5492595e63c31a7b1b0d5a8","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":false},{"one":"c42f36bf6728b24721ce5ac1272a1058e202a236d276af1265a1eaa675f8fd85","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":false},{"one":"a20d591ea15722712e83fcc6c17732f2370034ef870234a0fa0b2f4aea572fd5","other":"a6cad8da6a7949d7624b7ea636fd2d72de6a9b14f899df6263ccb4b3e5351c6a","up":false},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":false},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":false},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":false},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":false},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","up":true},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":false},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":true},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","up":true},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"351d1ed5c4012f8870ef2acadc7c0fea2cb697f5688b92e0150c5f670661c617","up":false},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":false},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","up":false},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":false},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":true},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","up":false},{"one":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":false},{"one":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":false},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":false},{"one":"58207fc8d92e44a8274398d6105b90d763981afba7021b57be98591e7b739272","other":"6c2fd129c8493cea7634a91aae559ceb64f01cebc45ec59aebd7e709b65941be","up":true},{"one":"1030a5d27a502aeb868e7158373c48af6a85e829ee3a84f4a0b78f9a30bd5a6a","other":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","up":false},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":false},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":true},{"one":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":false},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","up":true},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":false},{"one":"1a696462de3d83ff271f30f6d66de968325e37a36877dd67b45d9cdd7e644b5b","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":false},{"one":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":true},{"one":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":false},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","up":true},{"one":"f9e4dbb28099af8ca5f28c641a51672f4c6ab54b7037f765a7172a399acb8edc","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"766b61b773ad34c6cfd30b9c2e94840d151c31ab8cbcf546943eb5821d5a8f36","up":false},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"944e8231f9f661435f1f94abfaa17862a005877487df5c5d3a566c4dbe46be3f","up":true},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","up":true},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":false},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":false},{"one":"c6edfd613f216f48a1ea05be84faa5b9a69dd97c6e5d72e0bd339ea62c1b19e1","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":false},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":false},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":true},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":false},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"9dc8a0545acfdd12cb985532b9625d8860b8c87aa871f07f9c91f1599860831e","up":true},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":false},{"one":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":false},{"one":"d6a203c341b618c47ae53b339563b22c31dfc12d89dea7ba0c33e1812829684c","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":false},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","up":false},{"one":"7d14fd0b6c554f218249fed7709df51946baf91a3045ed99fb662c32cc97541b","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":false},{"one":"5f8eb6ff0f6ed720eaae86390757833f4b9cdfa52564457ed90c3de260ab6c30","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":false},{"one":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","other":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","up":true},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"62d5162001253b3964e6772d35bc31aa372a42e87ce450d48dbb84f5d3c9e8f2","up":false},{"one":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":false},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"212479d1ab813951780af2bc09a8119dbf62e603c05c0ea26329625036f6708a","up":false},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","up":true},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":false},{"one":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":false},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":false},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"39b5d09d1227a776f8d65b7239cd03e04499e7d519e5d1ff4c4870a1a949dd91","up":false},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":false},{"one":"ede2568d60ce7a12b4380818a31d2895fcb9b815cfb5526d28b2a82ff62e0381","other":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","up":false},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":false},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","up":false},{"one":"57d3361ee59d006e1dba3e1ae9ea624444ee09f70410dff492d624d7e7786d2d","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":true},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":false},{"one":"7c992ceefe03187bce1edbf8f80ccd1cab80b3908e625a61fef21ec6d35d04a3","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":false},{"one":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":false},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"4e6eab6eb3d49b20e2f3dee169d4647ebf26d07044698ff93d51c5fc30fb4ae0","up":false},{"one":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","other":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","up":false},{"one":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":false},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"8357eeaa65808f09b9a83362cb07508878becee9f843a5e1e70d025167b198ea","up":false},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"f7cd1cc174a21f190a715dad84857f563908db960f2a5943ef015caf6220a8d3","up":false},{"one":"0561b40886edc84497731c7b64acdabb63a22abe573847b78f74887afd86d71e","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":false},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"1b6168d6a369029690e836d26ffe017e26769ce504c142abf2a4a65774ecb66d","up":false},{"one":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":false},{"one":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","other":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","up":false},{"one":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","other":"0ef0bf53ddadd2c942f21e7e09d5a902d166f13920aabb2aa6652b70c423f575","up":false},{"one":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","other":"893773caa8e126430f189186956f3e80b49107ce52777972f5e8c11027c072d6","up":false},{"one":"4f7abbc51265dfe22d58f3ac5cde2c05ec56053efe79e3ebb6ece96183dcc17a","other":"5258fdc94d78bb45d6634f2672bc2eacdbc896fc5a39784ecc9d8a7dd52cb1e7","up":false},{"one":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","other":"795d813cab67300b8c59c78b6b99403c8111920ca47c1e56edfb513bc4999f3f","up":false},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","up":false},{"one":"2742110997dcb690946885e5a4aaa039f72c9f92025e62f1d371922acf5e27a7","other":"1a16e158f1d35f2573d20b05ba51a2c9cc196547038e3b7be97ddc7598e81257","up":false},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":false},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","up":false},{"one":"1f1580f6bf3df2ce7a50ec53be2511d22149fede99ca6194b611471adabfafaa","other":"746898d197934d17cd93b958ab20aaa85dba99057495048d2cabc8a996926e05","up":false},{"one":"ce12d7b26736d08eaa424a5f972a5a1fd50d05aab330340f3605dbab8007bf28","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":false},{"one":"c1c13885e3f543804e62e3b34c0d9762778866e5b8fe9d9df0caa6a64ec41428","other":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","up":false},{"one":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","other":"b26eff0d882918a40b909b2fc79489a671a9f990cc0dd3d835493bcb52a468ea","up":false},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":false},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"bb9c9f07ee2f8bc2bb0f011309f8314de7c1777a6f683f90506b180ef6f5aab4","up":false},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","up":false},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"fcf3ccf76c4699752670103e9cb98ac1294339a357876c71673f7e486d02f08b","up":false},{"one":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","other":"567206d70bc58993b08719afd9c007c562aad99437599356763b74cd4707083c","up":false},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"171f8d32719c1c3a330cdec42e47f0a5876bb2cc1cac8f13579f9cd19887c531","up":false},{"one":"816609d5b9bdb0c7bad6cbe9400fd506df8662b14ad0e0a61bc7b49482548e39","other":"a3e87b083776e34d10941832ec078fe9a7b8bae8cefe6fecdd5561549561a7f3","up":false},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"e22c1f74c4b480fdd2fbe84ad321a98230efb98fb1cdec4f79e4e50b2b0d5cc4","up":false},{"one":"66f6ff5fbc2526c1db5db491e49138362bef23032c6344ed4ead7dcb58bd1e6c","other":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","up":false},{"one":"41f407b92b1462b93400819a6af8815797b9dbc505afaf0162bbaea795205716","other":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","up":false},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":false},{"one":"016e174a29dc18857107fbebc876689b401c1174964ac6cacb31a4cb847a4d30","other":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","up":false},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"869fc21fff150ce9e1bc4512b183559433767cfc1cb7b6baae6d2a1313245ae8","up":false},{"one":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","other":"88dc5f31a2b295e8b43bc6e7abaae130061c2d44c49c95bcca3d9dd0a268324c","up":false},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"85845413850f5e38cce69548e20179b477bf383dd2b22428358715d9d72421ac","up":false},{"one":"ef40fdb37f2f89ec77833e48b1bd210b2241949b9ef8f6dca6bf6189503abb2c","other":"efdee7c9bab75e85302e3cac95ca2434af63ccb731ed24e0bda419e7a471cdde","up":false},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"74a4ffb0d717a523ec72e07cc5efe3e98d55932d6e0592ef45fe54b378e4e952","up":false},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"2c3d7e056f87daf540821a31ea8fe9377d00ed3a55ffba67b8bb716cdd9b7303","up":false},{"one":"fb211f405a7dc3a07b6d4f18522c6273ffa4e18325958eea159e33f768eae846","other":"fd54f34d1deead333014c472182bf5cb2db1d1b1ab55caa70f5dc70108622f17","up":false},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":false},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":false},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"fe9d68b6f0d0add106d4a9e132308cf5caa867624784d652f071f5d1fe87ff8b","up":false},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":false},{"one":"6421894e25e421d16eccd8858aed3354fce2d04c9d5c46d4005ee1f16944ccfd","other":"7a46bf03f327b100dc00140c97828a3b607280b6cd57220703be393ae4fdddbc","up":false},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","up":false},{"one":"b87c0ee719d0656cd325300b756f203310675021f3c508b30542deb1114ec7ac","other":"81748a1a38162f9e8613ffa562add1b75893b66199840e74c0774db92bfd7ca0","up":false},{"one":"6d307f348cc71e8a471ba662c1b5bd9d6e6930c22024f350465cccc7f2208a59","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":false},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"30c022df9209b4515213fe3fa67135c05d960afbd76f8455caa9c83ab5e493b6","up":false},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"12df4927ff743d4dd9dfb0a7d13d39012b172f6a35921aaef1547d5d02ad38fe","up":false},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"580a650c2c3e95d35e66264df6f48e28a091bacd20dc2c9828a5b563353d2052","up":false},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"d48642f8008e8aa791ba89c9b3a5b8d2d7aeb7e9078caee8813777679608075c","up":false},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"cd944ad4c50c4357005ff26ef26369ba3375a1205eec532b6e51b22bf25510bc","up":false},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","up":false},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"0d90040b9d0cd742149654262198aa8dc4fc96cfdf9b84cfe833277c3e23831f","up":false},{"one":"1263f18bf8cb4f5a3335f545cdd5d42f1b84da9edf4fa7346572c2bc38c87eb3","other":"089fe22a0bd48d3120cc8171eb9d698532c17f36768dbc25f554f2c53de11ab0","up":false},{"one":"43d797cb7fced78dd7141ef452ea367d7484d5c0fec2431caebe1317c4aa6340","other":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","up":false},{"one":"4a2d15b867a620653f099d66839b80c2dd32aec95caf906f0d5c8146192edf62","other":"4067997c26042749c16f17169caac66e647b71e3557f7581dbec739d0baa2ef0","up":false},{"one":"00b98e790fb954975837ff95abb1bdc2673dd8a0ce315986cc0dda5b0cefb05d","other":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","up":false},{"one":"165d670ad20922226e1f3275abd153b6fe8d9ffe3e45e6c1fcae3f5a3d2ec35a","other":"0f19fb4d0c6cfe36f7f59c8fe54d2e169687603e1bde0fe6b3a5e864fa51f2f0","up":false},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":false},{"one":"160c0401bcd1b38db7b4ae82470244ac9a9923755fc475aa67eb6dedc703c223","other":"24263ec4b92f390e07193d00e5a032ea2649f560027be02878da656e37d4a1b1","up":false},{"one":"11b53fa40926ac84d75d9d698f46b9611b90194857c1397e117931a890447078","other":"13165fffc318dd5f182601384e1ac69dd591236a03e88dfd1c637ea21a01b2dd","up":false},{"one":"18b0fcbba2350241088129e8f6a07742857c3edaacd6ef1ec0861cc8e48492ce","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":false},{"one":"f84317ef488d8c1495b429b7a1fa21ea53a73e737b3c1aa890c20e38658ab148","other":"f9265e3c23cd931ad51faec142636a6a8c8bd90a23e77f5327861c81cf4dfe17","up":false},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"3547871df541d0734c374e4c42f610f235f0c923d8b2bdc88c17fadb2c8e25ea","up":false},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"9a8c60732ff0d0b7403b181cdc5bb9e6db0aa4cf5c7158c40e548fcb76726f87","up":false},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"459a945c8d6e67437bdfa0e067962b3591dfa0aa7c1177f8327ba1557bbf1569","up":false},{"one":"cb704e26ceff5b613d8211423375fe0ded4d867bc892894a70d71289f1a9c1c1","other":"d24a8781af0c8ff19eca66388e308569bcce48144e559dc4c543f5a2ab0fe7c3","up":false},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"b77832f3f26323f09b37f31d208361d77ca08cec3ff829b9451fa3f00ff61fd0","up":false},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":false},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"9835fa9db1ce53ad2a526d36050eefd2c593121df4036c269cd09e1be4746a15","up":false},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"958e075a7f22c092360d325dd0c0449e9442c398b2882009c5c3720cbcd3584f","up":false},{"one":"5f1c751641e1727871c44f0d5779b278871c77f5e05324dc91a8620bed72e627","other":"5958a4ccd5333e8bfed5f18c78d365b201ffc2b9af3afd31748adb8e4f8118bc","up":false},{"one":"9d60b67d731aee2e6ac86d17c9e6a6aa5aaeec6b6803bae5c5fbc02643f7358c","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":false},{"one":"9265383ecf776ce1da66e99e5f0a9c1af593d8e56ceef21f42aad4be7e34bc45","other":"b270e0d21a173f4717882b1c6dc942d703fe11cd6adf997b3ecd0944fcea6c7b","up":false},{"one":"8ff601de9537c9e5d79a3707a312fe893383bef000d00acee3d4552068ef6030","other":"9b240fbf12d9de7975803b09aacdbab94cd978130de62bc89497bb1056e462c0","up":false},{"one":"41cd903abdaf445bfbcc3d5f28c10aba473be8a3ddc614c7f124b0ed7f91fd1d","other":"4610c06c8f5e1e24a75d9e46a432f4c1a6b9da6c3dbd122d3d3881752d930736","up":false}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","name":"node_7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","enode":"enode://0c52fa76a36dd072dbe11c5e7ebc82ef6efdd0fa3da10a006f64a34abc8a9f4d721a5c4fc4ef5415438ff721ed76effac71cb456683d037aace2db5f49026522@127.0.0.1:0","enr":"0xf88fb84036d1f0bc1cc1963dccf82616505bc245b2af797a3ded53470756e0453fd7fde54210f291c7326eae82253d256d7367b7b8568b05250d5a2f08e6c83b1981d1cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c52fa76a36dd072dbe11c5e7ebc82ef6efdd0fa3da10a006f64a34abc8a9f4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fcXo2BgMG8frvuEaR/yW6P6LLXHDDLxKoc+Z6Otq/Kw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dc5e8\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 cfbb c3a1 d6ff d0f3 | 63 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n001 2 0bcf 027f | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 3 539d 48b6 4b24 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 7 6742 667e 6982 6e5c | 11 6210 (0) 645b (0) 667e (0) 6742 (0)\n004 5 73b8 734e 7355 772e | 6 7639 (0) 772e (0) 757a (0) 73b8 (0)\n005 2 78cb 7b92 | 2 78cb (0) 7b92 (0)\n============ DEPTH: 6 ==========================================\n006 2 7f87 7fbc | 2 7f87 (0) 7fbc (0)\n007 1 7cf4 | 1 7cf4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","private_key":"c917cec67eeafea4150785766f590f1c97310aa195be916d29051a26b3171a53","name":"node_7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","services":["bzz","pss"],"enable_msg_events":true,"port":33259},"up":true}},{"node":{"info":{"id":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","name":"node_027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","enode":"enode://d49541d31306ef162578a3f30e389a71136992741d3611b524f2a1b37836ce7ee1dd57cc939af45575d8d483f71883fd82b19a52373b635a06117cf4a4ef067e@127.0.0.1:0","enr":"0xf88fb840ca9a8de2b1e9313144320c6cda217eccf7965c113dfd13a673882f078c78b4c16eaa6a88000df314c35dbc9734baea21b359cead3b4fc396d771f9ddb0347d1e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d49541d31306ef162578a3f30e389a71136992741d3611b524f2a1b37836ce7e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"An+0lkOHglg/ePt2mZM27tf7ZyqcnqUNBN9YDm6yE3c=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 027fb4\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 9d3c 9626 91eb aebd | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 8 4cd0 4b24 6c82 667e | 38 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n002 5 3cb1 3ee4 2459 26d1 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 4 1929 1be4 109e 13bc | 4 109e (0) 13bc (0) 1be4 (0) 1929 (0)\n004 3 0ff6 0ab9 0bcf | 3 0ff6 (0) 0ab9 (0) 0bcf (0)\n005 3 06b9 0427 0506 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n007 1 0390 | 1 0390 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 0218 | 1 0218 (0)\n010 0 | 0\n011 1 026d | 1 026d (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","private_key":"35e8d68fdca3b15bdf43c1cde2ec85199450a4588a06d9669dadc25c6921fa02","name":"node_027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","services":["bzz","pss"],"enable_msg_events":true,"port":41117},"up":true}},{"node":{"info":{"id":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","name":"node_03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","enode":"enode://fec12f13138cbdff7808d59f28b3b381ead6ce29e9e229304138d734fe76ca3c3a45e95962022868018fcf1f1fa0e1ac1d8882564c7e0cde1529db9b3232b19a@127.0.0.1:0","enr":"0xf88fb840dfe0f2eb384187472aca67b943618b6dbaf1909ced3442bcc018bee08cc8a00a216115d3306fae614384ddd4ecedd94e35505ba6c7a8f8a8fc9a2f17ea862a4b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fec12f13138cbdff7808d59f28b3b381ead6ce29e9e229304138d734fe76ca3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A5BzgK/NUiOPPYSo3uPfWZx/L5uQ+8EnHuiL21KsvVg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 039073\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 91eb 9d3c ed32 e16b | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 4 4b24 757a 667e 6ecb | 38 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n002 5 39db 3ee4 3cb1 26d1 | 12 286a (0) 2a22 (0) 213b (0) 2459 (0)\n003 4 13bc 109e 1be4 1929 | 4 109e (0) 13bc (0) 1be4 (0) 1929 (0)\n004 3 0ab9 0bcf 0ff6 | 3 0ff6 (0) 0ab9 (0) 0bcf (0)\n005 3 06b9 0427 0506 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n============ DEPTH: 7 ==========================================\n007 3 0218 026d 027f | 3 0218 (0) 026d (0) 027f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","private_key":"b4db734c8cd058c2d749fff4c60c20dc42442061273efc31e209e2410ea38934","name":"node_03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","services":["bzz","pss"],"enable_msg_events":true,"port":33597},"up":true}},{"node":{"info":{"id":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","name":"node_1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","enode":"enode://7b0a4f58064407b6a89a456dd7c991fa39ac01667f7731f4086a9e77cac79dbcaad821bf88ef0eae4cc2a07b14ea9bfea96ab342de836f2071b9a1a92bef83f4@127.0.0.1:0","enr":"0xf88fb840a4ea2bad27e691d6f015407aeb49fd6ef8e053ce798b351ed6925d81856bfe6736edaccb49c93ac2255f173fa0fda36fed07b165e6efe95bf93d54cd4bffabf30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027b0a4f58064407b6a89a456dd7c991fa39ac01667f7731f4086a9e77cac79dbc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GSmoS81kvwAtCvsWJJRmxbZgEjF0ofwb+IGRP4yH0f0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1929a8\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 a2ba 9d3c 895b e16b | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 3 4b24 757a 6ecb | 38 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n002 9 2459 26d1 2a22 3ee4 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 10 0ff6 0bcf 0ab9 0427 | 11 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n============ DEPTH: 4 ==========================================\n004 2 109e 13bc | 2 109e (0) 13bc (0)\n005 0 | 0\n006 1 1be4 | 1 1be4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","private_key":"db5a5448de2eddbf38d0c7d1521fef311345df8517384c0d6b57a7e674ddad53","name":"node_1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","services":["bzz","pss"],"enable_msg_events":true,"port":45321},"up":true}},{"node":{"info":{"id":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","name":"node_6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","enode":"enode://e21a50afba059b155fdd0211a966f7169bcbdb74404cb9ed08f192236eceea4c7b9ced1604b358e45c7153c5a7f75a6749f191d7021e0208d4df9aae45f23804@127.0.0.1:0","enr":"0xf88fb840997c2ef382cf15d5ad18e430d159fc5502d452c770bd172de18a323d9d5f59bc6432167188e9894a86efc4fa5721f7d28bafc11fee19e45a03f76624374b4fa30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e21a50afba059b155fdd0211a966f7169bcbdb74404cb9ed08f192236eceea4c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bssR/FrMFuzXA1FBD6GOxEoqg9nneM8luFp1NUk0Vrc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ecb11\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 f410 f5c4 e16b e0b1 | 63 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n001 3 3ee4 0390 1929 | 27 286a (0) 2a22 (0) 213b (0) 2459 (0)\n002 9 5d60 5abc 539d 5776 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 7 7355 734e 73b8 772e | 12 78cb (0) 7b92 (0) 7fbc (0) 7f87 (0)\n004 2 667e 6728 | 5 6210 (0) 645b (0) 667e (0) 6742 (0)\n005 1 6982 | 1 6982 (0)\n============ DEPTH: 6 ==========================================\n006 3 6c82 6c02 6d60 | 3 6d60 (0) 6c82 (0) 6c02 (0)\n007 0 | 0\n008 1 6e5c | 1 6e5c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","private_key":"28fb42373087a7839e6469456ad91bd1d4c1ac2998d4255bdb18559e6594b6d8","name":"node_6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","services":["bzz","pss"],"enable_msg_events":true,"port":44113},"up":true}},{"node":{"info":{"id":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","name":"node_ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","enode":"enode://3d426d150fd9ee0de2b594986006891aed8ab3f74cde7ad6cc686e3a10992f727c3211fd7e1c70bd5d1a018adf0672f4c56fe30638e9c51da6156884ccb284e5@127.0.0.1:0","enr":"0xf88fb84061b157c270f717e96d2170c813f51c28cb513f10730481c1f0dd8325c02d72c512a23741c2968d0ca703d403e549c557be9ccba33b9817ab6cff09ec2630c41e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d426d150fd9ee0de2b594986006891aed8ab3f74cde7ad6cc686e3a10992f72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rQ0NxdQRTuRILWyb1ORmgzJ6vyuS3w0kLXkBmWOHZmg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ad0d0d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 109e 0bcf 6210 6ecb | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 2 cfbb d0f3 | 30 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n002 11 8cf9 895b 89c8 8be4 | 16 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n003 5 b70e b2b9 b381 b841 | 8 b8e1 (0) b841 (0) b92a (0) b486 (0)\n004 5 a7a6 a75a a085 a320 | 5 a320 (0) a2ba (0) a085 (0) a7a6 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 afa3 ae67 aebd | 3 ae67 (0) aebd (0) afa3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","private_key":"d01704345488dae1946ebc66f4903380ce4b938bed28d2aca5e644e493351f6d","name":"node_ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","services":["bzz","pss"],"enable_msg_events":true,"port":34797},"up":true}},{"node":{"info":{"id":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","name":"node_d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","enode":"enode://4237bb190c2cafcef9ac7ba0cbccf2e75e97a4e8c624e8adc279e935d9c7c0738ab94cb32406678bb61010467d21fc56071334a2860ca5d3e2fd5d414d293f73@127.0.0.1:0","enr":"0xf88fb8405ab3e3f555db63f58404371549be2cf78e94aa9475e7f4b9adc6aa73b5e878df2480291bc05f8cf0166ddea6c24f0fa246e9646d59fce792c15ea71c97be36010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034237bb190c2cafcef9ac7ba0cbccf2e75e97a4e8c624e8adc279e935d9c7c073","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0POYlpSA8981h/bUdUb/EmHK1NLpwm/zB341rhsmFT4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d0f398\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 38ab 26d1 2a22 4b24 | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 4 895b 92a1 a75a ad0d | 33 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n002 6 ebca e55d e0b1 e16b | 15 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n003 5 c3a1 c8e5 ca03 cbc5 | 9 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n004 3 db08 dfae dc97 | 3 db08 (0) dfae (0) dc97 (0)\n============ DEPTH: 5 ==========================================\n005 1 d6ff | 1 d6ff (0)\n006 1 d224 | 1 d224 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","private_key":"875e777570710eaf1d860d33b1d4e4afa6b44b0660cfe5be4aa6cc294c546e66","name":"node_d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","services":["bzz","pss"],"enable_msg_events":true,"port":33929},"up":true}},{"node":{"info":{"id":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","name":"node_cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","enode":"enode://8efcf09e90d2d51bd3c092605c42b4779dd2e58033f47e0334f6888cb53a11d9671659ea85a7b0c22913977f61e1a604b39360d562853873d8b3def8ab011126@127.0.0.1:0","enr":"0xf88fb840f2c79356478735337278a426353488d61e749b316e38e2d4f04fe88cd92f738a2546d62d6fe2bcce1af65b06b7d7345dc3f7c8571101680d66301f4a71c87b3a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028efcf09e90d2d51bd3c092605c42b4779dd2e58033f47e0334f6888cb53a11d9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"z7uepoK+yt6rELvQgLqOk1EAhah6xRnkNJZPqiIvwnU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cfbb9e\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4b24 6d60 6c02 7fbc | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 4 92a1 9d3c b381 ad0d | 33 86ca (0) 83dc (0) 82f0 (0) 8b76 (0)\n002 5 e55d e0ea e0b1 e16b | 15 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n003 4 dc97 d6ff d224 d0f3 | 6 db08 (0) dfae (0) dc97 (0) d6ff (0)\n004 2 c181 c3a1 | 2 c181 (0) c3a1 (0)\n005 3 c8e5 ca03 cbc5 | 3 c8e5 (0) ca03 (0) cbc5 (0)\n006 1 cdcd | 1 cdcd (0)\n============ DEPTH: 7 ==========================================\n007 2 cec3 ce99 | 2 cec3 (0) ce99 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","private_key":"4269717f6ea28ec4c5441c5b5423a2e7c38b7d2b7d7ccc5172da8fad2d709f3b","name":"node_cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","services":["bzz","pss"],"enable_msg_events":true,"port":35713},"up":true}},{"node":{"info":{"id":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","name":"node_734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","enode":"enode://8bf678fe58741608b5ef92a443588c6eb7f2fe2cf9185e03f908d034e13b4c764e4ed1dc17c36b695812a5c110abb0c18ef88c32727ee10b3868acd09bba0cb4@127.0.0.1:0","enr":"0xf88fb84070de48a3c1c962367c4ff449d327203595b0e1c1ca9e490abd350b47ea74aa7e444e094ec367c1f4ebac57f0289314f2e165f40c16cd4631859c490adce7dc3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028bf678fe58741608b5ef92a443588c6eb7f2fe2cf9185e03f908d034e13b4c76","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c04CntJUhe3Um5PdnoW252V/hg5N7UvIpQlPUSrlg2s=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 734e02\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 e55d f5c4 d6ff d0f3 | 63 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n001 2 2a22 0bcf | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n002 7 5abc 539d 419a 4167 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 10 6c02 6d60 6ecb 6e5c | 11 6210 (0) 645b (0) 667e (0) 6742 (0)\n004 4 7b92 7f87 7dc5 7cf4 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 7639 772e 757a | 3 7639 (0) 772e (0) 757a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 73b8 | 1 73b8 (0)\n009 0 | 0\n010 0 | 0\n011 1 7355 | 1 7355 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","private_key":"0bb7de51881b72244a45a762173749b52aac74eb3a8c1d48f3a62ccd0302fc4a","name":"node_734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","services":["bzz","pss"],"enable_msg_events":true,"port":41955},"up":true}},{"node":{"info":{"id":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","name":"node_f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","enode":"enode://961a9e131513a2c5774c0dc13eb30f2ef01d760ff0d89e535cfda5a6f9295b8f3b0bd2e14350fd396460c2dfab8522f1257f4331f3ea483868e6079a1fb5da7a@127.0.0.1:0","enr":"0xf88fb8409230987fe11342ff370645f1e38d4fdf2d2d9d2c49f2cd3207b760f02c7c517c15952dc852b3d4d0c2dc88387b2c301f5f0ae7c0e668b9616d8ed680cad31ca10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102961a9e131513a2c5774c0dc13eb30f2ef01d760ff0d89e535cfda5a6f9295b8f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9cTSjfWXPsApIiGodehEYyPzOUCdk/D3OFmQEmkIo8M=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f5c4d2\npopulation: 39 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 3ee4 13bc 1929 027f | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 11 b70e b381 b2b9 a085 | 33 b486 (0) b70e (0) b16d (0) b2b9 (0)\n002 6 c3a1 ca03 cfbb d6ff | 15 db08 (0) dfae (0) dc97 (0) d6ff (0)\n003 6 ed32 ea0e ebca e16b | 10 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 f361 f360 | 2 f361 (0) f360 (0)\n006 1 f74e | 1 f74e (0)\n007 1 f410 | 1 f410 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","private_key":"46e5632ca34485b42e08ec702fe84421169074e80c41bc39e596de3815c6e021","name":"node_f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","services":["bzz","pss"],"enable_msg_events":true,"port":39029},"up":true}},{"node":{"info":{"id":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","name":"node_91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","enode":"enode://ae0bd86a797b580157ab4c21533c6f6c1780cb3c0cee9d7e2ff134e014f06b850f6d15e48654d074b11ee4d02fe3ea740579c66308e511746fd4105e2d21afff@127.0.0.1:0","enr":"0xf88fb84001756e4ad603612a22013c330b2cf03e87dc2141a015bede20c5765ed475cacb68aa1b9cec229906947a5e70ca06f66834998d2f887e2017ac427b638f9a09220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ae0bd86a797b580157ab4c21533c6f6c1780cb3c0cee9d7e2ff134e014f06b85","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"keup+cjykp049DoMfvqAnA0tWaMcvydgyQ5z0gJm1Sg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 91eba9\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7b92 39db 109e 0390 | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 3 c3a1 e16b f5c4 | 30 db08 (0) dfae (0) dc97 (0) d6ff (0)\n002 6 afa3 a320 b70e b2b9 | 17 b486 (0) b70e (0) b16d (0) b2b9 (0)\n003 2 89c8 895b | 8 86ca (0) 83dc (0) 82f0 (0) 8b76 (0)\n004 4 9d3c 9e02 9ee7 9a92 | 4 9a92 (0) 9ee7 (0) 9e02 (0) 9d3c (0)\n============ DEPTH: 5 ==========================================\n005 2 9626 957d | 2 957d (0) 9626 (0)\n006 1 92a1 | 1 92a1 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","private_key":"4836585cbd3b3547cff5060ac87f6987ada66424120a9b9538775f47d0f7df73","name":"node_91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","services":["bzz","pss"],"enable_msg_events":true,"port":44261},"up":true}},{"node":{"info":{"id":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","name":"node_e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","enode":"enode://13b2a9865ee51fe3d87fc17ec8cfe97872514aba0eff2dd9a2c4ad9fc1c23b95d14c057a24db7f653bd6a8beb80be7154482ae88ebd1c6a6cfbea08c7fc93951@127.0.0.1:0","enr":"0xf88fb84082f8084805a5a7bd16721d9d3440e711bcb186978b79670fdd73217dd65bbb844a407d171eebfa8bfacff33277985dddc10db2c12f6a3e2bdc0e776ca994dad80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10313b2a9865ee51fe3d87fc17ec8cfe97872514aba0eff2dd9a2c4ad9fc1c23b95","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4WsSxwi8XgVFAJ2u1EczxS10UMzHl9FY3UGjvJUHtr4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e16b12\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 6728 6ecb 6982 7dc5 | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 10 b381 afa3 a085 8cf9 | 33 b486 (0) b70e (0) b16d (0) b2b9 (0)\n002 5 c3a1 cfbb dfae d224 | 15 db08 (0) dfae (0) dc97 (0) d6ff (0)\n003 5 f360 f361 f410 f5c4 | 5 f361 (0) f360 (0) f74e (0) f410 (0)\n004 3 ed32 edc8 ea0e | 5 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n005 2 e77f e55d | 2 e77f (0) e55d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 e0ea e0b1 | 2 e0ea (0) e0b1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","private_key":"5ea17901397d5aaeb179c857d6c09266e923a0215431888d768e5539165ad4e8","name":"node_e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","services":["bzz","pss"],"enable_msg_events":true,"port":37359},"up":true}},{"node":{"info":{"id":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","name":"node_962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","enode":"enode://bfd89002d57335d3e459e80f6a6d01e10639d4fcc760c399b6ca84a4ac5af371aae339acaf6d3a3af784091aec154057c194534e146eec65c841ee33441bf00f@127.0.0.1:0","enr":"0xf88fb84052f31a4caf0d9b1de4fc6c97990f405550c3648b4538d159b61e3b3e25d7125368269c12bc6fbf114ab141f378f013d37094dee41bd8ca773529195ea998253e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bfd89002d57335d3e459e80f6a6d01e10639d4fcc760c399b6ca84a4ac5af371","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"liZ2gYwX+uH/xS/CkxjET5uMmAr9bT6YIXtAiNVoqAg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 962676\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 0ab9 0bcf 0506 018a | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 3 c3a1 f361 e16b | 30 db08 (0) dfae (0) dc97 (0) d6ff (0)\n002 3 b92a a320 ad0d | 17 b486 (0) b70e (0) b16d (0) b2b9 (0)\n003 7 86ca 83dc 82f0 8cf9 | 8 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n004 3 9d3c 9e02 9a92 | 4 9d3c (0) 9ee7 (0) 9e02 (0) 9a92 (0)\n============ DEPTH: 5 ==========================================\n005 2 92a1 91eb | 2 92a1 (0) 91eb (0)\n006 1 957d | 1 957d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","private_key":"85a02e6c73fe7d4d4c93334d0c723acd5ff2e71b08e80169c82302596e77fc01","name":"node_962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","services":["bzz","pss"],"enable_msg_events":true,"port":45605},"up":true}},{"node":{"info":{"id":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","name":"node_6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","enode":"enode://e19d4c9793aa8f6a9a32bb81ca986936d9ea49e442c801424ae1b66b0494fc290b62403e22282d1d77439b36dfe907efe0b60126280ca75babc23becb470b1e7@127.0.0.1:0","enr":"0xf88fb84081ecd7a679832795b6c915559cf9bcd02e9b61f37e131f88935755d13d0ff6ab34c388d54a00d8d71d670052b1bac1301f7ff0527db702b60863ca194d14f1210183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e19d4c9793aa8f6a9a32bb81ca986936d9ea49e442c801424ae1b66b0494fc29","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bAKRFKn3PWmkLlkc8tExB+/wONPtqKuwJC2dbRafBcc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c0291\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 f410 cfbb c3a1 d0f3 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 2 3ee4 372d | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n002 7 539d 558e 5a01 5abc | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 6 7b92 7dc5 734e 7355 | 12 78cb (0) 7b92 (0) 7fbc (0) 7f87 (0)\n004 2 667e 6728 | 5 6210 (0) 645b (0) 6742 (0) 6728 (0)\n005 1 6982 | 1 6982 (0)\n006 2 6ecb 6e5c | 2 6e5c (0) 6ecb (0)\n============ DEPTH: 7 ==========================================\n007 1 6d60 | 1 6d60 (0)\n008 1 6c82 | 1 6c82 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","private_key":"40e5884353d6096401012e695c215b05187562c0e32a97ee4abcd43c25a0ad55","name":"node_6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","services":["bzz","pss"],"enable_msg_events":true,"port":37519},"up":true}},{"node":{"info":{"id":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","name":"node_372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","enode":"enode://7cd3bb16716b1076e17d80959f4ef0fc541fc21ed845356a47f3bda9b1b7cc3c69114f4f796a56b301fa411ec706f696106d9b052accfc958fcd51e391c51ffb@127.0.0.1:0","enr":"0xf88fb8406c50fb4ef43704e45da206358753811875825f0bb9f88f7e4510685d0045fdf252af80cdb5e4d427ca21741e0b0fda40d2b789a1cd793aef76efcceebf4250040183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037cd3bb16716b1076e17d80959f4ef0fc541fc21ed845356a47f3bda9b1b7cc3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Ny1HN0pX0YzxNKH4/C0vwQ36z8C+ntiDGDo0nIlrN5M=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 372d47\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ea60 89c8 895b a085 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 8 4a18 48b6 539d 558e | 38 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n002 5 0506 0218 0bcf 1be4 | 15 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n003 5 2a22 213b 2459 2434 | 6 213b (0) 2459 (0) 2434 (0) 26d1 (0)\n============ DEPTH: 4 ==========================================\n004 5 38ab 39db 3e56 3ee4 | 5 39db (0) 38ab (0) 3e56 (0) 3ee4 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","private_key":"1be8d297f334edb94c9ea51d8debf701671d9b6417ac0686d6602848d866ee4e","name":"node_372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","services":["bzz","pss"],"enable_msg_events":true,"port":33327},"up":true}},{"node":{"info":{"id":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","name":"node_a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","enode":"enode://1018042bdefdc2e798c3ddd700486aba9fc20a89da51cae3496187cb9d6255d2b13be34e59108f3b3d1eab3f56f7a0988c0e866f58fcf360f6249fa89511f07d@127.0.0.1:0","enr":"0xf88fb84022e9bba09d0d2e41131e876b802569733bf1059ce20eb77f6b4b622ece181037505657543d3b05deec3ede00996d0c039955058490a884ad00126337c3b92eba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031018042bdefdc2e798c3ddd700486aba9fc20a89da51cae3496187cb9d6255d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p1q9Dc5aSIt+Bvkfq3qS7EKKshvek3LJ6PpIn0jns/4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a75abd\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 757a 109e 372d | 65 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n001 8 cdcd cbc5 c3a1 dc97 | 30 db08 (0) dfae (0) dc97 (0) d6ff (0)\n002 5 9a92 8b76 89c8 895b | 16 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n003 5 b8e1 b92a b381 b2b9 | 8 b16d (0) b2b9 (0) b381 (0) b486 (0)\n004 3 ad0d afa3 ae67 | 4 aebd (0) ae67 (0) afa3 (0) ad0d (0)\n============ DEPTH: 5 ==========================================\n005 3 a320 a2ba a085 | 3 a085 (0) a320 (0) a2ba (0)\n006 0 | 0\n007 0 | 0\n008 1 a7a6 | 1 a7a6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","private_key":"f0d55a442b4523bc34a50224cf58a48983f8e13bf68ed7aef1f210ec4181e4ba","name":"node_a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","services":["bzz","pss"],"enable_msg_events":true,"port":34721},"up":true}},{"node":{"info":{"id":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","name":"node_757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","enode":"enode://bcc2e6a83deced98cbb219f3952ee89113bb72388f8db9468b0ccedc5c9efd497340ca0dab2f4ad807e2a6f7c2083c9c6ff638d982c98e7742df1f7b926737ad@127.0.0.1:0","enr":"0xf88fb840292c38ff3ee7ca5696840d594c2568dfdb75ecbbeefd9b86d835dfc88808eb3b4bc9021d750154c42b701172f70e6763d08126f1989ed3bfbab925235bc983220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bcc2e6a83deced98cbb219f3952ee89113bb72388f8db9468b0ccedc5c9efd49","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dXpVdCTDOtie/YGF7BjXHAJYMOyyrtlR4zyMjZhtWTM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 757a55\npopulation: 46 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 e55d ed32 ea0e f410 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 11 2459 26d1 0bcf 0ab9 | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 0427 (0)\n002 8 517a 539d 558e 5d60 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 5 6ecb 6c02 645b 667e | 11 6982 (0) 6e5c (0) 6ecb (0) 6c82 (0)\n004 5 78cb 7b92 7f87 7cf4 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 7355 734e 73b8 | 3 73b8 (0) 7355 (0) 734e (0)\n============ DEPTH: 6 ==========================================\n006 2 7639 772e | 2 7639 (0) 772e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","private_key":"da2903aa985ff2bebcff008fe5e6086043ded662b94bf703bdd33aa8abbcad68","name":"node_757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","services":["bzz","pss"],"enable_msg_events":true,"port":33351},"up":true}},{"node":{"info":{"id":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","name":"node_4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","enode":"enode://54c96640ca98c787831ec404bd53cf02cf312f521c34f5484e8c9bc0b9b0d95be546ccb2dc35f2350b6b457a5f8d57ec62dfc95fd3f82be2cf6acabfad9383b7@127.0.0.1:0","enr":"0xf88fb840701b1435264d1443865d19c0d29add0cf76d12020726e2685d8e4da0a8eeab31323b97fafbbd0ca3d01635cd7f3b27615bc73d27b4fdbf67c108954bd567c8b00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10354c96640ca98c787831ec404bd53cf02cf312f521c34f5484e8c9bc0b9b0d95b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SyQ6Wuq+xtsOSoCpwlUwDNlFkab74OCqFw2k9s4U7f8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4b243a\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b2b9 d0f3 cfbb | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 10 26d1 2a22 1929 13bc | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 0427 (0)\n002 10 6ecb 6e5c 6d60 6c02 | 23 6982 (0) 6ecb (0) 6e5c (0) 6c82 (0)\n003 5 5abc 558e 5776 517a | 7 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n004 3 47c3 4167 41b9 | 4 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n005 1 4cd0 | 1 4cd0 (0)\n============ DEPTH: 6 ==========================================\n006 1 48b6 | 1 48b6 (0)\n007 1 4a18 | 1 4a18 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","private_key":"4f3791027f035431649d9fcd7cb9f8fd3c894da3f485f2c0e24c2a851fab97fb","name":"node_4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","services":["bzz","pss"],"enable_msg_events":true,"port":36491},"up":true}},{"node":{"info":{"id":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","name":"node_667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","enode":"enode://03bb27a5efeec49cef6564a99f3d8f48962be8be00db2ace069c57a131607c55bf856022b21bd4ec25e48b349b52b09fa2041ed165d3a8385ec34a5d7280d6d7@127.0.0.1:0","enr":"0xf88fb840307d719c21165c858e0413d4b18af8363443e8bba70afc6cc2b8dd5ff08a43a66e9ee7aec6b62b965901f872ab5832443df4fae667d7b3557eaea3c1e9052e020183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10303bb27a5efeec49cef6564a99f3d8f48962be8be00db2ace069c57a131607c55","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Zn7wQuna4YaUWB4EBMPYegmADotCFz0mVxw7+X4po3I=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 667ef0\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b2b9 957d dc97 dfae | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 4 0ab9 0bcf 027f 0390 | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n002 5 539d 5abc 5a01 48b6 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 7 7b92 7dc5 757a 772e | 12 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n004 5 6e5c 6ecb 6c82 6c02 | 6 6982 (0) 6ecb (0) 6e5c (0) 6c82 (0)\n005 1 6210 | 1 6210 (0)\n006 1 645b | 1 645b (0)\n============ DEPTH: 7 ==========================================\n007 2 6742 6728 | 2 6742 (0) 6728 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","private_key":"b61f7c457f7b07d448f38101f0b9a63485fa37f50da9a92362a48addc997a396","name":"node_667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","services":["bzz","pss"],"enable_msg_events":true,"port":46521},"up":true}},{"node":{"info":{"id":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","name":"node_6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","enode":"enode://5fd6f8ed3cd810ee8b1f94209e80e357d598434625f8644da0ebe3e07eb25a80c5ca8fef356aba34c04ca2acbed317344c504ffe32fd7635f0b94c3ce5f5eff2@127.0.0.1:0","enr":"0xf88fb840236d92a5eae6b161341b01c489cd53ae1380191a314d7106c6984b0eb94d216b3bf8b891301e7486d39136a85d0a085f7cd70f33df587aeb879ce0600b7663720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025fd6f8ed3cd810ee8b1f94209e80e357d598434625f8644da0ebe3e07eb25a80","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bWAZUnk1ibxrVzQMRRpqvwLqLBZjfpEO7QTN5u3f4Xo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6d6019\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 b2b9 957d d0f3 d224 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 2 3ee4 3cb1 | 27 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n002 5 48b6 4a18 4b24 5abc | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 7 78cb 7b92 7f87 7dc5 | 12 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n004 4 645b 6742 6728 667e | 5 6210 (0) 645b (0) 6742 (0) 6728 (0)\n005 1 6982 | 1 6982 (0)\n006 2 6e5c 6ecb | 2 6ecb (0) 6e5c (0)\n============ DEPTH: 7 ==========================================\n007 2 6c02 6c82 | 2 6c82 (0) 6c02 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","private_key":"18bc5eca469877f8bfa545da0ad2bd73daec62af973abe276fb20f1d04863e95","name":"node_6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","services":["bzz","pss"],"enable_msg_events":true,"port":33319},"up":true}},{"node":{"info":{"id":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","name":"node_3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","enode":"enode://5fd4ee4ef3698df17ace9e5c9df83f75a95f7e5f95f649cc8bdd52f61a7fac2171d1ee5f86535eee24bae2effb9f7ff69670824dbe6eb14a35b7665c2223da3d@127.0.0.1:0","enr":"0xf88fb840aff409e698e8f4f5cf56ca52947c18b6d9809b5f1e525fc10e843e36ee2ca5241e81898a9433b16d0a08764e529c7fb084f389f43419ee06e71bf301a946d2900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035fd4ee4ef3698df17ace9e5c9df83f75a95f7e5f95f649cc8bdd52f61a7fac21","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PLG0Bpcn3DI6aHyrTKJ2T2QVRQSIcG8bl8XLjKRjRv8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3cb1b4\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 89c8 8cf9 ae67 a085 | 63 db08 (0) dfae (0) dc97 (0) d224 (0)\n001 4 48b6 7355 6e5c 6d60 | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 9 1929 0427 0506 018a | 15 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n003 6 213b 2434 2459 26d1 | 6 213b (0) 2459 (0) 2434 (0) 26d1 (0)\n004 1 372d | 1 372d (0)\n005 2 39db 38ab | 2 39db (0) 38ab (0)\n============ DEPTH: 6 ==========================================\n006 2 3ee4 3e56 | 2 3e56 (0) 3ee4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","private_key":"f18fca734e8631f11eebe52259a8080c6109a0f5fe18f736743c0a34181f2eae","name":"node_3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","services":["bzz","pss"],"enable_msg_events":true,"port":43603},"up":true}},{"node":{"info":{"id":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","name":"node_b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","enode":"enode://c8fe782387da875269f14c7cd4bb3380d51b007537929342fbbdc7ea61b444f205d4e3bc17b6fd54daf1f730ce4aaca7e4af914aff70e0f3dbb2e8edabb226a1@127.0.0.1:0","enr":"0xf88fb840a624988c579ed3e88f99fb8ca769e17361f6331458d1424eff6108f9c6b1152a56461c35819897506a2c1c17c8d17c05b4e88113489bfa3ec2b477dc8e29997e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c8fe782387da875269f14c7cd4bb3380d51b007537929342fbbdc7ea61b444f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uSpxpPw3HgWWU4p/sqM+hTKcOcRAnJl5jZMYvCY6BKE=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b92a71\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0218 2a22 3cb1 | 65 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n001 4 e55d dc97 d6ff c3a1 | 30 db08 (0) dfae (0) dc97 (0) d224 (0)\n002 7 82f0 9a92 9d3c 9e02 | 16 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n003 5 a75a a085 a2ba afa3 | 9 aebd (0) ae67 (0) afa3 (0) ad0d (0)\n004 5 b486 b70e b16d b2b9 | 5 b16d (0) b2b9 (0) b381 (0) b486 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 2 b8e1 b841 | 2 b8e1 (0) b841 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","private_key":"6c47e1823351c4f8273293dc991f5d3e47a310824dc99d1d52beef8c89294f01","name":"node_b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","services":["bzz","pss"],"enable_msg_events":true,"port":42797},"up":true}},{"node":{"info":{"id":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","name":"node_2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","enode":"enode://a7c716f7518d16f027fc0d58cc55ab8ae2162f10c0cf5d81c251ca7871aa0987c94ba79fbe53061f70754735133653680cec4e97749c0ece47ae3d0087d943d4@127.0.0.1:0","enr":"0xf88fb84080004a46ab4e22a502d41f7bfe521c7b28973328433a5a30cba401e5f2fe9a1c100aecae60a1cc71aaac717ef8f08b2e07149090f6be981f06b7f4aa3a2bf7d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a7c716f7518d16f027fc0d58cc55ab8ae2162f10c0cf5d81c251ca7871aa0987","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KiLb7nGg7yfIQCIdtKWS1tyPFxr+2GX/gUo31jOj6qk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a22db\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 9d3c 89c8 a085 b92a | 63 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n001 6 7639 7355 734e 4b24 | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 12 1929 13bc 109e 0ab9 | 15 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n003 5 372d 38ab 39db 3e56 | 6 372d (0) 39db (0) 38ab (0) 3e56 (0)\n============ DEPTH: 4 ==========================================\n004 4 2459 2434 26d1 213b | 4 213b (0) 2459 (0) 2434 (0) 26d1 (0)\n005 0 | 0\n006 1 286a | 1 286a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","private_key":"983e054d5c73ca85071b2217c801a3085251fb1b921de91548a7a6a233b24777","name":"node_2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","services":["bzz","pss"],"enable_msg_events":true,"port":46129},"up":true}},{"node":{"info":{"id":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","name":"node_c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","enode":"enode://7defcbf17d10e9ee01953d449616f3699518c4d3585397ff9bc8593c072c9a6b812acfd3433a4089f86c780620500a11b9e3e2801b235000453c067ad2311f82@127.0.0.1:0","enr":"0xf88fb840de5af3f26f6196388d0546896aa7bf5ac6fc698d19f254306f9dc81a408a11586b063e732170349d2f8894e5ae2b69572727cb59a416373c82b651eca0cb6c580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027defcbf17d10e9ee01953d449616f3699518c4d3585397ff9bc8593c072c9a6b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"w6GzAb8Yf9gyaDEZfZOgJmrAzIKHuQCGMSQOK+yc8zc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c3a1b3\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7dc5 757a 667e 6982 | 65 41b9 (0) 419a (0) 4167 (0) 47c3 (0)\n001 7 a75a b381 b92a 82f0 | 33 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n002 7 f5c4 f74e ea0e ed32 | 15 f360 (0) f361 (0) f74e (0) f410 (0)\n003 5 dfae dc97 d6ff d224 | 6 db08 (0) dc97 (0) dfae (0) d224 (0)\n============ DEPTH: 4 ==========================================\n004 7 c8e5 ca03 cbc5 cdcd | 7 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n005 0 | 0\n006 1 c181 | 1 c181 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","private_key":"484569ae37b3c147f07f84fa525f767a19cb38f2839bdc5ea2c5e66a29a71514","name":"node_c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","services":["bzz","pss"],"enable_msg_events":true,"port":40743},"up":true}},{"node":{"info":{"id":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","name":"node_e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","enode":"enode://9bf89be750b3f7b410f5c7f487664a2e0984a1869ab3028316d121edb1de9c7d0044a57a07671607f39b16c19b4afd6bb65be16f70a2edda4a6c8cfef676f9e7@127.0.0.1:0","enr":"0xf88fb8407f93d5d7b618515bd5cba4bb810d1e7c011dcd28c79b7a11da77ca28ff0159924f52b0a9855f06e431c27bfc00244284259f11bcc2db35e6f81fa2d3e1901f6e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039bf89be750b3f7b410f5c7f487664a2e0984a1869ab3028316d121edb1de9c7d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5V2M2355QLEZKeflyUnva+t5mOUYCh8KPAv2Gu858bg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e55d8c\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 0390 13bc 1929 6ecb | 65 47c3 (0) 41b9 (0) 419a (0) 4167 (0)\n001 10 afa3 ae67 b92a b841 | 33 b16d (0) b2b9 (0) b381 (0) b486 (0)\n002 5 db08 dfae d0f3 cfbb | 15 db08 (0) dfae (0) dc97 (0) d224 (0)\n003 3 f361 f74e f5c4 | 5 f360 (0) f361 (0) f74e (0) f410 (0)\n004 4 ebca ea0e ed32 edc8 | 5 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n============ DEPTH: 5 ==========================================\n005 3 e16b e0b1 e0ea | 3 e0ea (0) e0b1 (0) e16b (0)\n006 1 e77f | 1 e77f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","private_key":"70bfa2dd7936c527af87ad8ba7b3d514378ae9415b80790afbeb8c145ef60da3","name":"node_e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","services":["bzz","pss"],"enable_msg_events":true,"port":40869},"up":true}},{"node":{"info":{"id":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","name":"node_895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","enode":"enode://bdad63bb5585a3b586e639b7f3a5a588a466508ceda1e479e1a9b680bf7306e84cff0f49d32225c68a8e8c4ce351565f80823ea4eb59625cfa0f4e4a4c778940@127.0.0.1:0","enr":"0xf88fb840cf3575b7f89341293c93e42a94e09971765ed95f6b2e7b14e280dbe9f820d785440bcb6c7546cd319062f61ac1ccf8d316d6e62e604ccbdf856585b699e3d0b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bdad63bb5585a3b586e639b7f3a5a588a466508ceda1e479e1a9b680bf7306e8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iVvc0gDMTX7Fwk8XItCo6+3aeLeM3xzMjCKpgZgPV4Y=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 895bdc\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 0ab9 0bcf 018a 026d | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 8 d6ff d0f3 d224 dc97 | 30 db08 (0) dfae (0) dc97 (0) d224 (0)\n002 6 b8e1 ad0d afa3 a75a | 17 b16d (0) b2b9 (0) b381 (0) b486 (0)\n003 5 9a92 9e02 9d3c 9626 | 8 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n004 3 86ca 83dc 82f0 | 3 86ca (0) 83dc (0) 82f0 (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 8b76 8be4 | 2 8be4 (0) 8b76 (0)\n007 0 | 0\n008 1 89c8 | 1 89c8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","private_key":"dcb06c1695510d0ebdf81de665b6c30b1bc31fcffcdeb5a1d949119e3323d009","name":"node_895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","services":["bzz","pss"],"enable_msg_events":true,"port":36481},"up":true}},{"node":{"info":{"id":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","name":"node_a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","enode":"enode://200a1baeeb12eaff4957c04f960bc136c15c981b4ed91f50b6a3cd72f60ce1a9670bf2aada7c27159b884f728294220ddf2f7ab7c25bda08e51af6e0d2ac59cc@127.0.0.1:0","enr":"0xf88fb8409ac56bef876fd1aa5cf1e9dc9750872b7b31e85abe3b3bd7bcbe11b451f4a4a41eca4dab1ec561a4e4e38d69fcf6daf208f8b8a3ffae014bd67e43b9be5e10800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102200a1baeeb12eaff4957c04f960bc136c15c981b4ed91f50b6a3cd72f60ce1a9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"orq+SUEK4Ae8Qf8rfer3Ce2Eni9pZmzlqudqO3H0cIE=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a2babe\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0bcf 109e 13bc 1929 | 65 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n001 2 e0b1 d6ff | 30 f360 (0) f361 (0) f74e (0) f410 (0)\n002 5 83dc 82f0 8cf9 8b76 | 16 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n003 5 b70e b381 b2b9 b8e1 | 8 b16d (0) b2b9 (0) b381 (0) b486 (0)\n004 4 ad0d afa3 aebd ae67 | 4 aebd (0) ae67 (0) afa3 (0) ad0d (0)\n005 2 a7a6 a75a | 2 a7a6 (0) a75a (0)\n============ DEPTH: 6 ==========================================\n006 1 a085 | 1 a085 (0)\n007 1 a320 | 1 a320 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","private_key":"d2327e3f9e0f7d479fd3a5ab6629e91631a909dcea933881e6981e4d8f65f4b1","name":"node_a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","services":["bzz","pss"],"enable_msg_events":true,"port":42677},"up":true}},{"node":{"info":{"id":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","name":"node_8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","enode":"enode://81d1c6b434a911a8540ccca92dc7eb5f6af3c9f8e8661331630b961b9beebbc774961f8c9b6764495cd176cdc7a2234e00b1fe437cf0e0e62ffdebffe804300b@127.0.0.1:0","enr":"0xf88fb840282e7b8b2c9fe6bfd46ecfa1ef9c05c0ce8aa561d6727b69e6112e3458aa1bbd1e729fe940bc2ed0879a33afffe03e9bb6645ef7c6ed882f20af71d138c235810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10381d1c6b434a911a8540ccca92dc7eb5f6af3c9f8e8661331630b961b9beebbc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jPlXv5WmKcYMMdvP517MoUmoHHYfizSFiwT4MY5cdL0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8cf957\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7b92 018a 026d 0ab9 | 65 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n001 11 cec3 f361 f5c4 e0ea | 30 f360 (0) f361 (0) f74e (0) f410 (0)\n002 6 b8e1 ad0d afa3 a75a | 17 b841 (0) b8e1 (0) b92a (0) b16d (0)\n003 4 9626 9a92 9d3c 9e02 | 8 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n004 3 86ca 83dc 82f0 | 3 86ca (0) 83dc (0) 82f0 (0)\n============ DEPTH: 5 ==========================================\n005 4 8be4 8b76 895b 89c8 | 4 8be4 (0) 8b76 (0) 89c8 (0) 895b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","private_key":"7cbecf45c8af825ad55165ca14a5390dc79b63f7d21abc54c8a3baadb93b0050","name":"node_8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","services":["bzz","pss"],"enable_msg_events":true,"port":38617},"up":true}},{"node":{"info":{"id":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","name":"node_9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","enode":"enode://1f9a4a0c1be2d3dc6cbe8fe451547748f181485a135d11125e490c4554edcb2a9c3915bce098a7a2d347392cbed94f9329000fa47ab5bd6611ae18f398feadf2@127.0.0.1:0","enr":"0xf88fb84073df5e59956667788fb2912ac8df533ca51baf49e3d0ab14bd339845667a29bd706b855764a6ae9a2143bd63225a6a73a0e252aaf849de6071447977ffc144f60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f9a4a0c1be2d3dc6cbe8fe451547748f181485a135d11125e490c4554edcb2a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ngLFOEYCpU6QDPpG1Zh7d/FudMunRayFD8raAcevkAQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9e02c5\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 39db 2434 018a 026d | 65 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n001 3 f361 c3a1 d6ff | 30 f360 (0) f361 (0) f74e (0) f410 (0)\n002 6 a320 ad0d afa3 b70e | 17 b841 (0) b8e1 (0) b92a (0) b16d (0)\n003 6 83dc 82f0 8b76 895b | 8 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n004 4 91eb 92a1 957d 9626 | 4 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n005 1 9a92 | 1 9a92 (0)\n============ DEPTH: 6 ==========================================\n006 1 9d3c | 1 9d3c (0)\n007 0 | 0\n008 1 9ee7 | 1 9ee7 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","private_key":"a54d320f74dbd164c2e978d7a70edcb4a6c116debd0e98aeaafdf18a0caf5810","name":"node_9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","services":["bzz","pss"],"enable_msg_events":true,"port":45685},"up":true}},{"node":{"info":{"id":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","name":"node_539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","enode":"enode://79b76c3f04c3fe8a4d8e15ba7832fa0e0cb07d122736b0ddd187f783af4f63fd91451132a818a91e2aaee43e9e6b4aace8e002ee76166005b9a2fe9553283f1a@127.0.0.1:0","enr":"0xf88fb840267a7455083f7f198cb282b60318c8fc45fa5d66c3aa1d1b7cea64ea5940f4dd140ae387c995877ba388099faf98c6e647e66c692c3a237bcb78321b457f26ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10279b76c3f04c3fe8a4d8e15ba7832fa0e0cb07d122736b0ddd187f783af4f63fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U535AtQtyZfGsOJNFq1otUxVfVa0HJcqMg1XYy2/vjw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 539df9\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 e55d b2b9 9e02 | 63 f360 (0) f361 (0) f74e (0) f410 (0)\n001 3 2a22 372d 38ab | 27 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n002 12 667e 6728 6742 6ecb | 23 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n003 8 47c3 4167 419a 41b9 | 8 4167 (0) 41b9 (0) 419a (0) 47c3 (0)\n004 3 5d60 5a01 5abc | 3 5d60 (0) 5a01 (0) 5abc (0)\n============ DEPTH: 5 ==========================================\n005 2 5776 558e | 2 5776 (0) 558e (0)\n006 1 517a | 1 517a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","private_key":"af360c6fe75b63f4d38464596d6a86faff221f4c287bfde6f06204cdadaaa7f8","name":"node_539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","services":["bzz","pss"],"enable_msg_events":true,"port":46373},"up":true}},{"node":{"info":{"id":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","name":"node_38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","enode":"enode://b59c9de0746cb3c3d75539274cc8216e4fe0ba577923dae16c2c38b2459f36f451764f8027ec684def5e6452ba84a2afc62f3729d3889e9c65307ecb10ae0496@127.0.0.1:0","enr":"0xf88fb840e51c952cba32bef6455c273e05c4252fc1e13ec6b7deee195982262b858831046faa9872c55686e7dc575653a070c1ec4d282cf32c09f2426240fa8250585f870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b59c9de0746cb3c3d75539274cc8216e4fe0ba577923dae16c2c38b2459f36f4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OKs9e9+yk7iBIkBMt8ULX7iQznZkwHXalVhVV6QwxAM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 38ab3d\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d0f3 a085 ae67 b70e | 63 f410 (0) f5c4 (0) f74e (0) f360 (0)\n001 4 7b92 7355 5abc 539d | 38 7f87 (0) 7fbc (0) 7dc5 (0) 7cf4 (0)\n002 6 0bcf 0ab9 0506 0218 | 15 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n003 4 2a22 2459 2434 213b | 6 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n004 1 372d | 1 372d (0)\n============ DEPTH: 5 ==========================================\n005 3 3ee4 3e56 3cb1 | 3 3e56 (0) 3ee4 (0) 3cb1 (0)\n006 0 | 0\n007 1 39db | 1 39db (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","private_key":"90080ed19445f25b61f6f51c31c7b5f0901bcc8b4d2af5754eb6200898460782","name":"node_38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","services":["bzz","pss"],"enable_msg_events":true,"port":44377},"up":true}},{"node":{"info":{"id":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","name":"node_b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","enode":"enode://8908b549b763c33a6d64dd794edf15467674ab7744abc8dadfe0a9ffe7edb0f232d68be0ce2cab3a1f1f4c1eb5bc265d2b5d241edb189daedf12f94294f83ece@127.0.0.1:0","enr":"0xf88fb840bd4af476eac6bae70a9bf4b3556d02f449fe1467ed3cb54cea8bcc7e51c1579a6949b225f34052028d4a72b4c7f804c49f2e12d4894046aedad89e4ffbf78d380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028908b549b763c33a6d64dd794edf15467674ab7744abc8dadfe0a9ffe7edb0f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tw6W8BrIlH0t5jIEEq4zEDFsq6ZcJxCK0WsvIAQlW+Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b70e96\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6e5c 0218 109e 38ab | 65 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n001 5 db08 f5c4 f361 e55d | 30 f360 (0) f361 (0) f410 (0) f5c4 (0)\n002 7 91eb 9a92 9d3c 9e02 | 16 86ca (0) 82f0 (0) 83dc (0) 8be4 (0)\n003 8 a2ba a320 a085 a75a | 9 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n004 2 b8e1 b92a | 3 b841 (0) b8e1 (0) b92a (0)\n============ DEPTH: 5 ==========================================\n005 3 b2b9 b381 b16d | 3 b2b9 (0) b381 (0) b16d (0)\n006 1 b486 | 1 b486 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","private_key":"356f88370186e91459aaa1a01150f9a0a07c6ba89835476be5ee3177f2456a90","name":"node_b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","services":["bzz","pss"],"enable_msg_events":true,"port":36567},"up":true}},{"node":{"info":{"id":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","name":"node_6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","enode":"enode://aa49209c98c2acfa233719cd8ab7c559b1a4024986f005f61450405205031b502c13b39557ac3df31f081a1bcc3cf8de29357f78400a37d679e179bd1f15b597@127.0.0.1:0","enr":"0xf88fb840cfbea5c6873c85a8951ee4931c303f2eff6e82813d5e4d86c25d48a82b1a49e341d8b0c006a2036a8eb6cc687fdb9c38595d982c2da6d56ff80606137b1fb5090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103aa49209c98c2acfa233719cd8ab7c559b1a4024986f005f61450405205031b50","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"blwhOi21fq8uHhrMNBxy76uJsOQrbNGNtPmawa8VHWU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e5c21\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d6ff a320 b486 b70e | 63 f360 (0) f361 (0) f410 (0) f5c4 (0)\n001 3 3cb1 0218 109e | 27 2459 (0) 2434 (0) 26d1 (0) 213b (0)\n002 5 41b9 4b24 539d 5a01 | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 7 7f87 7dc5 7b92 78cb | 12 78cb (0) 7b92 (0) 7fbc (0) 7f87 (0)\n004 3 667e 6728 645b | 5 6210 (0) 645b (0) 6742 (0) 6728 (0)\n005 1 6982 | 1 6982 (0)\n============ DEPTH: 6 ==========================================\n006 3 6d60 6c82 6c02 | 3 6c82 (0) 6c02 (0) 6d60 (0)\n007 0 | 0\n008 1 6ecb | 1 6ecb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","private_key":"5f2bdd7f08afe412e3fe6ff84df44e66752bb9b256a47fbc9581d982eadffdd4","name":"node_6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","services":["bzz","pss"],"enable_msg_events":true,"port":33895},"up":true}},{"node":{"info":{"id":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","name":"node_772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","enode":"enode://31b2a3729f35e5f4dd4e1ee95642c5672d2770f7624b097db81350287a180c1e49fff42d6c63128a806950d4128d494b8268a2b96fde995d89607b612ecec782@127.0.0.1:0","enr":"0xf88fb8404462b449bcf2410c7f21823b369db50987ba625ab6e4a803cdc4559caf61851a17783540a154b7d6f3a1d7ab7d08cd0851226dbccd517da51f555ad7c40bf5540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10231b2a3729f35e5f4dd4e1ee95642c5672d2770f7624b097db81350287a180c1e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dy5MgNEo3rUq3wJKDrb+m76hyDNR7ZP1X0kM1eXGkmA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 772e4c\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b486 d6ff f74e ea0e | 63 f360 (0) f361 (0) f410 (0) f5c4 (0)\n001 2 109e 0ab9 | 27 286a (0) 2a22 (0) 2459 (0) 2434 (0)\n002 8 4a18 41b9 5d60 5abc | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 6 667e 645b 6d60 6c02 | 11 6210 (0) 645b (0) 6742 (0) 6728 (0)\n004 6 7f87 7fbc 7dc5 7cf4 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 73b8 734e 7355 | 3 73b8 (0) 7355 (0) 734e (0)\n============ DEPTH: 6 ==========================================\n006 1 757a | 1 757a (0)\n007 1 7639 | 1 7639 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","private_key":"8efd5800758dcfdbeb2cf4d84f54e399c106e2c731f6685f720a2eea4c481817","name":"node_772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","services":["bzz","pss"],"enable_msg_events":true,"port":37837},"up":true}},{"node":{"info":{"id":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","name":"node_0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","enode":"enode://76fd52545682d9fdd0ca8f38321e9b37b84ca6a997956e0069744d0cb0bccb1a617f66c8eafe8dd5ed392d7e9c2efa928347aefe1c976201f3abd3e7a54bfb88@127.0.0.1:0","enr":"0xf88fb84097a8f0f039558e79fbee580fbec1d41e14fbba47472a75f290402f4076cad6492048d5e3a00ebc8742f93aa523bf57f954a31dda07673ea76280d76e01e4c5190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10276fd52545682d9fdd0ca8f38321e9b37b84ca6a997956e0069744d0cb0bccb1a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CrmEXCiQsKZKPlkyJBJF4AuBe3iAlPnuSPhvgLcmT+o=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ab984\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 ea60 e16b 91eb 9626 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 6 5776 4b24 667e 7b92 | 38 4167 (0) 41b9 (0) 419a (0) 47c3 (0)\n002 6 2a22 2434 3ee4 3cb1 | 12 26d1 (0) 2459 (0) 2434 (0) 213b (0)\n003 4 13bc 109e 1929 1be4 | 4 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n004 8 06b9 0506 0427 0390 | 8 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n============ DEPTH: 5 ==========================================\n005 1 0ff6 | 1 0ff6 (0)\n006 0 | 0\n007 1 0bcf | 1 0bcf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","private_key":"846db675d9c428c99df430ba38d3d3faf984abbe2f55df43af95bb096f86e896","name":"node_0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","services":["bzz","pss"],"enable_msg_events":true,"port":34333},"up":true}},{"node":{"info":{"id":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","name":"node_39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","enode":"enode://6ccc67d35840435af60a0430406169efc0037b4828edb5cd76e9bd5ac1e5aca65dd7a77219313f8a6c26f1ca7f5df41afd47dc389720d30b19e6979b52954c32@127.0.0.1:0","enr":"0xf88fb84055b20a8008a1872c0413f0ceea3a6a7121cc4e0dabef2b310f5bc43817bff888247a073d6946b7988936af22a7d1639fa5f109db9887292d255e6e771f8cda810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ccc67d35840435af60a0430406169efc0037b4828edb5cd76e9bd5ac1e5aca6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OdvVRiyQ2sdfSdmveZaEWUO76Sl1TvgSXu5/WnY+ne8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39dbd5\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 ae67 a085 8cf9 89c8 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 5 7355 48b6 41b9 558e | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 5 1929 0506 0390 0bcf | 15 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n003 4 2a22 213b 26d1 2434 | 6 26d1 (0) 2459 (0) 2434 (0) 213b (0)\n004 1 372d | 1 372d (0)\n============ DEPTH: 5 ==========================================\n005 3 3e56 3ee4 3cb1 | 3 3e56 (0) 3ee4 (0) 3cb1 (0)\n006 0 | 0\n007 1 38ab | 1 38ab (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","private_key":"791b9811412b1579e2e6d5f9fe6ddc88ce78a499b261b22e8817e02440f9e875","name":"node_39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","services":["bzz","pss"],"enable_msg_events":true,"port":36547},"up":true}},{"node":{"info":{"id":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","name":"node_d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","enode":"enode://72cbbeef82764d1b224a5af28e3e60dda17a49ccfe5b92cb84263bec1524623133bc14c9d0c60f36575f469f986b97d0bd09896ad8a7a068f1d52c4000c0d8d8@127.0.0.1:0","enr":"0xf88fb840ffaffd6544c636f742b7379273dcff32de002122a72f3ec80a94c93dd7f0347b5c5ab37d8762f17cce7877ddd4a925cb05ac0c19a51a71330445ff05ad5969450183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10272cbbeef82764d1b224a5af28e3e60dda17a49ccfe5b92cb84263bec15246231","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1v+3/SZo6bexM72RRBVvRzYZHvDW5ysHJ1l4LYOTHyI=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d6ffb7\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 6e5c 6d60 6c02 645b | 65 7b92 (0) 78cb (0) 7f87 (0) 7fbc (0)\n001 6 b16d b92a a75a a2ba | 33 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n002 5 f5c4 f74e ea0e ed32 | 15 f360 (0) f361 (0) f410 (0) f5c4 (0)\n003 4 c3a1 ca03 cdcd cfbb | 9 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n004 3 db08 dfae dc97 | 3 db08 (0) dfae (0) dc97 (0)\n============ DEPTH: 5 ==========================================\n005 2 d224 d0f3 | 2 d224 (0) d0f3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","private_key":"7d3834d39e62cf1e8548683eec363e19d020ce2f4971d98743bc58ffe1c91611","name":"node_d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","services":["bzz","pss"],"enable_msg_events":true,"port":42483},"up":true}},{"node":{"info":{"id":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","name":"node_e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","enode":"enode://c7e6fc03f7b10c7235bdd7ae9fd28ea2f96d514a90ddb54312b6f45c15873e47227b36c1c4f9d29e28b16527dc7bf154702a6ec4352a8d7eab15b325c2aba1b6@127.0.0.1:0","enr":"0xf88fb84024831e3097e6342c87a066a5ae145abdf8366f26e351a7a8d3f22d5e5802c8e963e13a456db9f0b08665eb9108b71d23537dd415c9dde62127fc947b89158b630183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c7e6fc03f7b10c7235bdd7ae9fd28ea2f96d514a90ddb54312b6f45c15873e47","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4LHE61tbTfwiNE7mXLlxbOyzjcyACZeT8gZBiE6uSFQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e0b1c4\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0390 13bc 1be4 1929 | 65 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n001 3 83dc a2ba a320 | 33 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n002 8 c3a1 c181 cdcd cfbb | 15 c8e5 (0) cbc5 (0) ca03 (0) cdcd (0)\n003 3 f361 f5c4 f74e | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 5 ed32 edc8 ebca ea60 | 5 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n005 2 e77f e55d | 2 e77f (0) e55d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 e16b | 1 e16b (0)\n008 0 | 0\n009 1 e0ea | 1 e0ea (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","private_key":"42fe12311467a8adbbfb209a06319e950148da4433177621af050a2a0b74e82c","name":"node_e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","services":["bzz","pss"],"enable_msg_events":true,"port":45685},"up":true}},{"node":{"info":{"id":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","name":"node_5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","enode":"enode://019ddc346857752f742b93cabbfc6b3c47c958ee5ad67be36c3c2f8e5acfa786f70344ce1d9b34c190ce414ca4af09b467ca8fdde6fcf4c8b09696c76c45b520@127.0.0.1:0","enr":"0xf88fb840153a0d6eeb5dc102fd9f75d0b8c51c7f01252e5cf45d6a4c5f3b65d4bd90a4d17affa644ffc8fca2d95c9ed93c70e093431ce452acb11d876cd55ca5dd802dba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102019ddc346857752f742b93cabbfc6b3c47c958ee5ad67be36c3c2f8e5acfa786","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WryW9Pp4gS22+3EP1CTdR0FF9+XQC0ztxTc7TFL0LPU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5abc96\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 e0ea e0b1 89c8 | 63 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n001 3 372d 39db 38ab | 27 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n002 12 78cb 734e 7355 772e | 23 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n003 4 4b24 4a18 48b6 41b9 | 8 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n004 4 558e 5776 517a 539d | 4 517a (0) 539d (0) 5776 (0) 558e (0)\n============ DEPTH: 5 ==========================================\n005 1 5d60 | 1 5d60 (0)\n006 0 | 0\n007 0 | 0\n008 1 5a01 | 1 5a01 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","private_key":"4e526a63f698dcdb8bb4a8c1a4a54fb1c3ba10476f285012af7137b504bdc215","name":"node_5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","services":["bzz","pss"],"enable_msg_events":true,"port":34327},"up":true}},{"node":{"info":{"id":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","name":"node_89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","enode":"enode://577ed924a2a73d22ee8998f00a82acbe7ce1e410878d5daa4d988ead6ad2cf4f385217ff0580f3dc311e0d8f79040dcb3e7f2b765f5e89fab86703f153374ace@127.0.0.1:0","enr":"0xf88fb8400137468cd822d505da53b9784f8a1606bb49e810dc372191a35921c562eb016d27a5cfcb4511315e38eefce0dfd07c703aa57dadbd6c14d29c0a504607c089900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102577ed924a2a73d22ee8998f00a82acbe7ce1e410878d5daa4d988ead6ad2cf4f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iciD1qhUcr2jKGZ+P9gFxwh2vFgspnY6uXrmNrF3K+Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 89c883\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 018a 026d 39db 3cb1 | 65 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n001 7 ea0e ea60 f74e f5c4 | 30 f360 (0) f361 (0) f410 (0) f5c4 (0)\n002 5 ad0d a320 a75a b8e1 | 17 b92a (0) b841 (0) b8e1 (0) b16d (0)\n003 3 91eb 9626 9e02 | 8 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n004 2 82f0 83dc | 3 86ca (0) 82f0 (0) 83dc (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 8be4 8b76 | 2 8be4 (0) 8b76 (0)\n007 0 | 0\n008 1 895b | 1 895b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","private_key":"17570e86447615758ea636804ecb65f791a12a421e904e723fbec9ab52e466f6","name":"node_89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","services":["bzz","pss"],"enable_msg_events":true,"port":42067},"up":true}},{"node":{"info":{"id":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","name":"node_dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","enode":"enode://0563ccfaae48ee129eb27f5c779f0c8349a22919de381a54c9a4f704070532a72d2f1926c6767afba2f9b4de908bf854498f5800374956e8c66ea2346df662c1@127.0.0.1:0","enr":"0xf88fb840fba3f24508ab6de5f8772b5dd896fc9b869cb17c48af0bc23b3c14145ef2aa0f76f8eb05025bcc10df608aa7979bda2203c12a4b429d308ce15aa4afabe8f1c50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030563ccfaae48ee129eb27f5c779f0c8349a22919de381a54c9a4f704070532a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3JfBoAGbSCoEi40VlB3+TDwaNEPZste0BGNwvISn5W8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dc97c1\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 6728 667e 6d60 6c02 | 65 5d60 (0) 5abc (0) 5a01 (0) 517a (0)\n001 4 a75a b92a 895b 89c8 | 33 b92a (0) b841 (0) b8e1 (0) b381 (0)\n002 3 f74e f361 e0ea | 15 f360 (0) f361 (0) f410 (0) f5c4 (0)\n003 4 c181 c3a1 cdcd cfbb | 9 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n004 3 d224 d0f3 d6ff | 3 d224 (0) d0f3 (0) d6ff (0)\n============ DEPTH: 5 ==========================================\n005 1 db08 | 1 db08 (0)\n006 1 dfae | 1 dfae (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","private_key":"9599415f62de56a6422afea8e7ebbc2b460cd56cc0f7b1fc73e96b6c8857e728","name":"node_dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","services":["bzz","pss"],"enable_msg_events":true,"port":41683},"up":true}},{"node":{"info":{"id":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","name":"node_e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","enode":"enode://bfb412d3f9e09403659416f8864d6a739bc396ae53bc9e2f6cb30239814538e65dbbf0339670dac268002695d39b8eb59b6c3a51420aa827ee75dce465a22669@127.0.0.1:0","enr":"0xf88fb8402b1a38e980290999c2f075d625bccda4a9614d6097ae9733957386a11a9be0804a2f004dc1383d9b4a35162a400684675d560cd72ec18d107d08e4d5cad01f490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bfb412d3f9e09403659416f8864d6a739bc396ae53bc9e2f6cb30239814538e6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4OpXXQ4u+ii8UfSdHiwkGWoZbaOzGW86Wial4xCAmvU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e0ea57\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 7dc5 6ecb 6728 517a | 65 5d60 (0) 5abc (0) 5a01 (0) 517a (0)\n001 5 957d 8cf9 83dc ae67 | 33 b92a (0) b841 (0) b8e1 (0) b381 (0)\n002 6 cdcd cfbb c181 db08 | 15 c8e5 (0) cbc5 (0) ca03 (0) cdcd (0)\n003 2 f361 f74e | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 4 ed32 edc8 ea60 ea0e | 5 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n005 2 e77f e55d | 2 e77f (0) e55d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 e16b | 1 e16b (0)\n008 0 | 0\n009 1 e0b1 | 1 e0b1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","private_key":"50f25d60500eb49b33f8855dbff5167ed90ae947f01800ca6e143886d4e2129e","name":"node_e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","services":["bzz","pss"],"enable_msg_events":true,"port":44889},"up":true}},{"node":{"info":{"id":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","name":"node_021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","enode":"enode://abd8116f367c9d2e1d15debf2ceadc5df783db3523482238cc8b10c5a61df20eee4a6ca29b99d2e09094fec869b212002aa3e56708b4d7c535f0edb00f6c6abf@127.0.0.1:0","enr":"0xf88fb840c3192e46a155becce8c64f9a7cce7f0bf743a33baf0b74dbde83751433990fe5215de0e3947206cfab59584d2e93f3075825686d26ddd6b4a7cca931dbec15f80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103abd8116f367c9d2e1d15debf2ceadc5df783db3523482238cc8b10c5a61df20e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AhgRpnV73N0voPtoQB3+AJ1ajhKZWM0wT7Qs9R3F0dM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 021811\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 9626 b70e b486 b16d | 63 b92a (0) b841 (0) b8e1 (0) b2b9 (0)\n001 4 4b24 558e 757a 6e5c | 38 7cf4 (0) 7dc5 (0) 7fbc (0) 7f87 (0)\n002 7 2a22 26d1 2434 213b | 12 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n003 4 1be4 1929 13bc 109e | 4 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n004 3 0ff6 0bcf 0ab9 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 3 06b9 0427 0506 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n007 1 0390 | 1 0390 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 027f 026d | 2 027f (0) 026d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","private_key":"f24fd4a4e7b3587f483542c46fe764f2846e84158cfc2282188fac740cb9939f","name":"node_021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","services":["bzz","pss"],"enable_msg_events":true,"port":38993},"up":true}},{"node":{"info":{"id":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","name":"node_109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","enode":"enode://f4df36e91a014ba253c93cc4a738dbeafed71095b9ad41b0e62616bad9b4f4301acd54ced99e80858045d79da80ac42f6d0d594ce127b880a5838fccc7f93da7@127.0.0.1:0","enr":"0xf88fb840a626a87192ca066e77595198c84a535d734661e1db5553a18cb8b62fbb77b6797af9aad58e1149921f53ec0a226a806dd29f5fa2c3f1f4c0309113f09ad4380c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f4df36e91a014ba253c93cc4a738dbeafed71095b9ad41b0e62616bad9b4f430","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EJ7xfIkBBL/FpIl9UmoK+qjJkcnSE2FgMvMFjQ/rfwA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 109ef1\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 91eb 895b a2ba a085 | 63 b92a (0) b841 (0) b8e1 (0) b2b9 (0)\n001 4 4b24 757a 772e 6e5c | 38 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n002 3 2a22 213b 38ab | 12 286a (0) 2a22 (0) 26d1 (0) 2459 (0)\n003 9 0bcf 0ab9 0506 0427 | 11 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n============ DEPTH: 4 ==========================================\n004 2 1929 1be4 | 2 1be4 (0) 1929 (0)\n005 0 | 0\n006 1 13bc | 1 13bc (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","private_key":"e9e24085b5783d5c7c9c652c4de2009dc89e215530c57e92cc3321481e56a5b4","name":"node_109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","services":["bzz","pss"],"enable_msg_events":true,"port":43049},"up":true}},{"node":{"info":{"id":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","name":"node_ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","enode":"enode://627fb4b3d57ec52bd28b0461d1ad5bd965015b0356be2d0727f9b548907a213a877ae14589528acf227113a87fff774a08eb7ca18e9860c62fc2f08a92941b8b@127.0.0.1:0","enr":"0xf88fb840626a2b83b4c2a20b607631df4b27b8945d07fd0ef4ccfce7f4ad41f83fd72d7931a5938937c2d2c8c99a377c59a782b69f9b5c99fd60f7e2d7d1727fb003eccc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103627fb4b3d57ec52bd28b0461d1ad5bd965015b0356be2d0727f9b548907a213a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7TLXTZvgZJ3h6ya5kVE3/kbsiQxlbJa+Uulmq24u0mA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed32d7\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6ecb 7dc5 757a 772e | 65 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n001 3 957d 8cf9 8b76 | 33 b16d (0) b2b9 (0) b381 (0) b486 (0)\n002 4 c3a1 cdcd dfae d6ff | 15 c181 (0) c3a1 (0) c8e5 (0) cbc5 (0)\n003 3 f5c4 f74e f361 | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 5 e55d e77f e16b e0ea | 5 e77f (0) e55d (0) e16b (0) e0ea (0)\n============ DEPTH: 5 ==========================================\n005 3 ebca ea60 ea0e | 3 ebca (0) ea60 (0) ea0e (0)\n006 0 | 0\n007 0 | 0\n008 1 edc8 | 1 edc8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","private_key":"e60060a92fe8c46ac4f8a127abbd9c4d9e36cd927cfe0313a8fc445e8394b94b","name":"node_ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","services":["bzz","pss"],"enable_msg_events":true,"port":42957},"up":true}},{"node":{"info":{"id":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","name":"node_8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","enode":"enode://5552d93b800376a18cd819cd566ae575dedbe4b312bf6130b1c3c5f61d63b0b88680f68f25fb55b72c4fda4a23b178ee3c08e471cbe510bcf6c5c1de2f29cf24@127.0.0.1:0","enr":"0xf88fb840a9d59867b862012cf06f08dc04de0e6cac8ccec89f0305e926bf4a6cb8efcb3a74c771665a71443904b3e60d17b1ee22a23d29ba0a06925d1587f8bd8153e23d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025552d93b800376a18cd819cd566ae575dedbe4b312bf6130b1c3c5f61d63b0b8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"i3YZTxKTCDJMfQBmUw4CysJBDuC6lSgi8OyGbhJGHkQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8b7619\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 018a 39db 2434 213b | 65 7cf4 (0) 7dc5 (0) 7fbc (0) 7f87 (0)\n001 6 c181 cdcd dfae f361 | 30 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n002 10 b70e b486 b16d b8e1 | 17 b2b9 (0) b381 (0) b16d (0) b486 (0)\n003 2 9626 9e02 | 8 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n004 3 86ca 82f0 83dc | 3 86ca (0) 82f0 (0) 83dc (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 895b 89c8 | 2 895b (0) 89c8 (0)\n007 0 | 0\n008 1 8be4 | 1 8be4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","private_key":"e322c8c203344ce73e706dae3f4f6f7e500bb780f43fb03a222aacf8adaef519","name":"node_8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","services":["bzz","pss"],"enable_msg_events":true,"port":44125},"up":true}},{"node":{"info":{"id":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","name":"node_f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","enode":"enode://553cba5427fc16ce1f7fcf4b551e79c45f56c2fe6425442401a0d11eeb052ee63de2ce6c5458a79c564e3744bad912c50520c1369f52e0767e09ed40e9993ff8@127.0.0.1:0","enr":"0xf88fb8400139f5b8abcf514eef980efc398f34b1a0d66124a43a20c323ad1fc720ca5c40626fc02a811970e8641b50a20d6b4aca333b145cddf67c6614ee2cfb65b869fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102553cba5427fc16ce1f7fcf4b551e79c45f56c2fe6425442401a0d11eeb052ee6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"907N4Luqe2Uh+yBbWrnqY3kJJ39uHuHTSQ9c0B0PchY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f74ecd\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1be4 772e 5d60 558e | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 4 a320 83dc 89c8 8b76 | 33 b2b9 (0) b381 (0) b16d (0) b486 (0)\n002 8 db08 dfae dc97 d6ff | 15 c181 (0) c3a1 (0) c8e5 (0) cbc5 (0)\n003 10 edc8 ed32 ebca ea0e | 10 e77f (0) e55d (0) e16b (0) e0ea (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 f361 f360 | 2 f360 (0) f361 (0)\n006 2 f5c4 f410 | 2 f410 (0) f5c4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","private_key":"3e6b050dabdb0eb2468be45fc539a79410db1729eeba39afff4688885dc9b8ef","name":"node_f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","services":["bzz","pss"],"enable_msg_events":true,"port":42027},"up":true}},{"node":{"info":{"id":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","name":"node_a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","enode":"enode://4fd8fe083cbe1905328dfcdefb64a314acbfdec10223d8d960f4b9168ef65580fd762356abcbf5cf995c88f00464d41163bf422cd1d80a6e9f2c6dbea37e12dd@127.0.0.1:0","enr":"0xf88fb8406f2350c3165bd627d97c3623d2fb90d4ded4cd6dd1aa554d6c4c4e017a729e743f44b2ec69aaed61a87bdebb7e1c67143b222f796b4b902b3b820dca88419b690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034fd8fe083cbe1905328dfcdefb64a314acbfdec10223d8d960f4b9168ef65580","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oyBcHE+bcoFPDbaOiI48fviPJ8aB7Q1zHd5fCZn5LMw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a3205c\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6e5c 645b | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 4 e77f e0b1 ea0e f74e | 30 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n002 8 8b76 89c8 895b 8cf9 | 16 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n003 4 b8e1 b16d b70e b486 | 8 b381 (0) b2b9 (0) b16d (0) b486 (0)\n004 3 ad0d aebd ae67 | 4 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n005 2 a7a6 a75a | 2 a7a6 (0) a75a (0)\n============ DEPTH: 6 ==========================================\n006 1 a085 | 1 a085 (0)\n007 1 a2ba | 1 a2ba (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","private_key":"ab56cc2e159cf59b59a2b8abae5e8c927fd16d7844425b0c048bdf0c1c03f561","name":"node_a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","services":["bzz","pss"],"enable_msg_events":true,"port":38749},"up":true}},{"node":{"info":{"id":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","name":"node_ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","enode":"enode://27bd511098d142435c42d80c87870c55f35ecba4851735487a8148f63556be851405b124502231ff210e6674abc11534f6c8d43d28611d0564497cff8b0bbdb2@127.0.0.1:0","enr":"0xf88fb840d7c884944fcfd5f801f1a40862426a14631c18017bf1e8679ce01d826fb6b98e2a2a8e3e2ce8c35859ef1bdf9e6bb1ddc6717e5bd286dc5436a440b6066608200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10227bd511098d142435c42d80c87870c55f35ecba4851735487a8148f63556be85","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6g4d1B/gQrCfJzyY8CEolJz1Vh0g3ASz1COWHv7VIyc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ea0e1d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 5d60 6ecb 78cb 7f87 | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 4 957d 89c8 8cf9 a320 | 33 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n002 5 db08 dfae d6ff c3a1 | 15 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n003 3 f5c4 f74e f361 | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 5 e55d e77f e16b e0b1 | 5 e55d (0) e77f (0) e16b (0) e0ea (0)\n005 2 ed32 edc8 | 2 edc8 (0) ed32 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ebca | 1 ebca (0)\n008 0 | 0\n009 1 ea60 | 1 ea60 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","private_key":"7a2a65840183134657aedc7f4311c4428e3b8341628df92550577eb8c5f61b1c","name":"node_ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","services":["bzz","pss"],"enable_msg_events":true,"port":43851},"up":true}},{"node":{"info":{"id":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","name":"node_2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","enode":"enode://634c327216fdc24e18f6724944cc2cdd81cd854a381e49a422c900ddb07bdbd3355b7de6240c4c3916088e39de937b6cc42f11fc8790d22d7721d0230a62273d@127.0.0.1:0","enr":"0xf88fb8403c29ef7a8afe4804b361f57edb95e1148ca1043464b23d9b238123129fcac29171eaf9a0a70e770cfe8185a3fb3fd61e5c5878f5b71c12487b79da7ab75e0e8d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103634c327216fdc24e18f6724944cc2cdd81cd854a381e49a422c900ddb07bdbd3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JDTGPn8ouD5/7t5/5o6pm5ifhTT2TWOwRnM+L0dFOPU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2434c6\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 a085 b8e1 9626 9e02 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 11 6c82 7639 7b92 78cb | 38 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n002 8 1be4 0ff6 0ab9 0218 | 15 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n003 4 372d 3cb1 38ab 39db | 6 372d (0) 3e56 (0) 3ee4 (0) 3cb1 (0)\n004 2 2a22 286a | 2 286a (0) 2a22 (0)\n005 1 213b | 1 213b (0)\n============ DEPTH: 6 ==========================================\n006 1 26d1 | 1 26d1 (0)\n007 0 | 0\n008 0 | 0\n009 1 2459 | 1 2459 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","private_key":"ea68ee64cd7bec8f6c5c0c14a4f6d55bc6c371c676c88a1657b73135e8183c29","name":"node_2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","services":["bzz","pss"],"enable_msg_events":true,"port":33513},"up":true}},{"node":{"info":{"id":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","name":"node_4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","enode":"enode://2e826c3eb8d5f9e300988ffa5fd5445a26ff486a0170c8b0d79fa439b3801c1851e45d69941f3bea632b20a7fcb3f1a53d0a504a3e886756ca25f61547eb71a3@127.0.0.1:0","enr":"0xf88fb8407eb028f17f3be43ac26f9c531d0ebeb3d8ed2e0920745e17760e6af36431612a5f81dc55334372f469f36342623f7ccd5b59f0b4e084f7aecbb474fe5ac68dc00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032e826c3eb8d5f9e300988ffa5fd5445a26ff486a0170c8b0d79fa439b3801c18","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ShgR3Z/r3hgBpgStgd6EotFTZtC1wzDzDzOY2g0QeCQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a1811\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8b76 dc97 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 4 018a 026d 372d 2434 | 27 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n002 7 772e 757a 7cf4 7f87 | 23 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n003 7 539d 517a 5776 558e | 7 5d60 (0) 5abc (0) 5a01 (0) 539d (0)\n004 4 4167 419a 41b9 47c3 | 4 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n005 1 4cd0 | 1 4cd0 (0)\n============ DEPTH: 6 ==========================================\n006 1 48b6 | 1 48b6 (0)\n007 1 4b24 | 1 4b24 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","private_key":"29e672b50332ffce13e3c1e62ab1c36c98284e8526e6c2010adc9fc40aa4e5a8","name":"node_4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","services":["bzz","pss"],"enable_msg_events":true,"port":45219},"up":true}},{"node":{"info":{"id":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","name":"node_026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","enode":"enode://1bdd224735ef8e9603bb3af3eb143963367ef184ba9c3a6266ffd8c7ea1c9825b0a565da1820ae283c905d35ad9c00c27d94edea8d308d28bb61b153a5c23831@127.0.0.1:0","enr":"0xf88fb840f1a2ef34af51d5a668030bf51780e698f351d5619a059fc5cf9c66b59b570ebc5e4bc9b8580fcb8e3f6196fc3a39e83a9220bf1726189b8e347b96e2818be9cf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031bdd224735ef8e9603bb3af3eb143963367ef184ba9c3a6266ffd8c7ea1c9825","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Am0uQbgtUG2mhaMMznzFdy9sHhZ7fVV+BTH7m3ndT/I=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 026d2e\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 83dc 8cf9 89c8 895b | 63 91eb (0) 92a1 (0) 957d (0) 9626 (0)\n001 8 757a 78cb 7cf4 7f87 | 38 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n002 4 3cb1 2a22 2434 213b | 12 372d (0) 3e56 (0) 3ee4 (0) 3cb1 (0)\n003 4 109e 13bc 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 3 0ff6 0bcf 0ab9 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 3 06b9 0506 0427 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n007 1 0390 | 1 0390 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 0218 | 1 0218 (0)\n010 0 | 0\n011 1 027f | 1 027f (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","private_key":"66e31ccc21cf370ceb1e2bceac1499aeab637ee09f233711ef38ba3a8ba0e258","name":"node_026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","services":["bzz","pss"],"enable_msg_events":true,"port":45529},"up":true}},{"node":{"info":{"id":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","name":"node_dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","enode":"enode://b854fc358c548e135da5fc791782f459cceb3528a48cd2ebb3c35942f92414b98eea4f354c64e8292a610ee59517399f6a9ec07a68e65dce31bb82f1df156b0d@127.0.0.1:0","enr":"0xf88fb840111fd0a9953783fdda698a6547ff1c8670f1b423fe5bcb157c98582d193a643c42c531c98d7b5114d96b1547a7ccc63a03fef119855f7697e1e124a3dbdc6ae90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b854fc358c548e135da5fc791782f459cceb3528a48cd2ebb3c35942f92414b9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"367ryOKcao+FGxK4DPQlZ80qQ+Ndl3MFo8EOUb9BFwo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dfaeeb\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6728 667e 6c02 6d60 | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 5 a75a b16d b8e1 895b | 33 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n002 10 ed32 ea60 ea0e e16b | 15 e55d (0) e77f (0) e16b (0) e0b1 (0)\n003 5 c181 c3a1 ca03 cbc5 | 9 c3a1 (0) c181 (0) c8e5 (0) ca03 (0)\n004 3 d0f3 d224 d6ff | 3 d224 (0) d0f3 (0) d6ff (0)\n============ DEPTH: 5 ==========================================\n005 1 db08 | 1 db08 (0)\n006 1 dc97 | 1 dc97 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","private_key":"f2ca8fe02aa5e39a2995330d19104fe94adc0b9bb890ce50c15ac8987c368a64","name":"node_dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","services":["bzz","pss"],"enable_msg_events":true,"port":46381},"up":true}},{"node":{"info":{"id":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","name":"node_558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","enode":"enode://670a610cec9046cca8a6097ddf0772fcc8b207ce9c573c71356934060ecf3e756298aac965d239846a16ab795b8f20f2d33d1379d6b4da7b0785eac9cb0e706f@127.0.0.1:0","enr":"0xf88fb84039cbdcd9c4550e92047787028d8613d1d69e444a7a231d53694347cc8a8cf913329ac3d692c8320f28ceb7867eb72c22b4b490db3b9c28951b511d6b72692e410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103670a610cec9046cca8a6097ddf0772fcc8b207ce9c573c71356934060ecf3e75","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VY6wIXRL4ZODvprJG5934HR54OslV2vTKjr6qUwjEXg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 558eb0\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 8b76 ae67 f74e dc97 | 63 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n001 5 0218 39db 372d 2434 | 27 3cb1 (0) 3e56 (0) 3ee4 (0) 38ab (0)\n002 6 6c02 6ecb 645b 78cb | 23 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n003 5 41b9 47c3 48b6 4b24 | 8 4167 (0) 419a (0) 41b9 (0) 47c3 (0)\n004 3 5abc 5a01 5d60 | 3 5d60 (0) 5abc (0) 5a01 (0)\n============ DEPTH: 5 ==========================================\n005 2 517a 539d | 2 539d (0) 517a (0)\n006 1 5776 | 1 5776 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","private_key":"5de3f27f03f0565eb69405082120c753d823e962ee08c8e89dfca48ef957830c","name":"node_558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","services":["bzz","pss"],"enable_msg_events":true,"port":45963},"up":true}},{"node":{"info":{"id":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","name":"node_ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","enode":"enode://d5ac1961e227bd9f303a8273244adeaf02add8f9f4007c2f9d9c849ff3b9bbd9950d263905ac606d6dc5c4dd723e991ee27c80acf9584e36de09197b4db5ace5@127.0.0.1:0","enr":"0xf88fb8408715cddf6466f5cf540b8e6c8689a5881979f2696a0160c48f2274fb2ce56db820361055605b93b01a3f4324962a745010a973c17fab26ee763a8ada01abca260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d5ac1961e227bd9f303a8273244adeaf02add8f9f4007c2f9d9c849ff3b9bbd9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rmf65JkNphyokiHFsWdcmSurtNcVtZk55HvRSRs78fQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ae67fa\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 39db 38ab 3cb1 3ee4 | 65 3e56 (0) 3ee4 (0) 3cb1 (0) 38ab (0)\n001 4 e55d e77f e0ea f361 | 30 c181 (0) c3a1 (0) c8e5 (0) cbc5 (0)\n002 3 9d3c 83dc 8b76 | 16 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n003 4 b8e1 b16d b486 b70e | 8 b2b9 (0) b381 (0) b16d (0) b486 (0)\n004 5 a7a6 a75a a085 a320 | 5 a7a6 (0) a75a (0) a085 (0) a2ba (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 ad0d | 1 ad0d (0)\n007 1 afa3 | 1 afa3 (0)\n008 1 aebd | 1 aebd (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","private_key":"20deaabb607e4c2f3c7df5c3c5e310bf29e1fdadae1b52f9d107d40cfb6b264c","name":"node_ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","services":["bzz","pss"],"enable_msg_events":true,"port":33595},"up":true}},{"node":{"info":{"id":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","name":"node_f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","enode":"enode://49397d0356ecc13c5bc27b3b5630f3bbab8e7c1ca7d2d4b5e074ca3c8b8dcfaf2fe2945ba899807de702c7eb3c40a572c9771d6e3211cc0b0d333e96c7990987@127.0.0.1:0","enr":"0xf88fb840a198329ff362f39bc5de95d22e342a70da5fadfb466b8eed4eb1b9f57dd6dc454815ce25795082edc3e776e68b01dc3a5d782775450daba93f28d4b4509f3dab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10349397d0356ecc13c5bc27b3b5630f3bbab8e7c1ca7d2d4b5e074ca3c8b8dcfaf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"82Eg/yULnnFk6WAhR5MyBU9n3mXNL+W240vFHQ/k0pw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f36120\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5d60 517a 1be4 0506 | 65 5776 (0) 558e (0) 539d (0) 517a (0)\n001 10 9e02 9626 8b76 89c8 | 33 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n002 5 ce99 c181 db08 dc97 | 15 d224 (0) d0f3 (0) d6ff (0) db08 (0)\n003 10 edc8 ed32 ebca ea0e | 10 e77f (0) e55d (0) e16b (0) e0b1 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 3 f74e f410 f5c4 | 3 f410 (0) f5c4 (0) f74e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 f360 | 1 f360 (0)\n========================================================================="}},"config":{"id":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","private_key":"71622f176e027738b9284c5ca316f6736d1af20a0c5b2874bc826a6493d3e403","name":"node_f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","services":["bzz","pss"],"enable_msg_events":true,"port":40147},"up":true}},{"node":{"info":{"id":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","name":"node_0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","enode":"enode://c7d55b42435ae9eebddd09b4960f97586b686903470dd4b908acfc157b42c2d6dfc9b4a54f29dfeb3fb84963511229a1b277bac428b07daf80036a03c9075180@127.0.0.1:0","enr":"0xf88fb84017229330778245921bef57e2428e7cec260ff8ddf2ca65fd32d601b6deb58561107253d30829606a2a6848f578bc6a7a38854ff60ef6c34af5b9b791d3c0e5e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c7d55b42435ae9eebddd09b4960f97586b686903470dd4b908acfc157b42c2d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BQbpSXSLYtodNrZj331qfnYCf3LO1dUvdGd/sx1+FQU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0506e9\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 9626 a7a6 db08 c181 | 63 91eb (0) 92a1 (0) 957d (0) 9626 (0)\n001 3 7b92 5d60 517a | 38 558e (0) 5776 (0) 539d (0) 517a (0)\n002 8 372d 39db 38ab 3cb1 | 12 3e56 (0) 3ee4 (0) 3cb1 (0) 38ab (0)\n003 4 13bc 109e 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 3 0ab9 0bcf 0ff6 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 5 018a 0390 026d 027f | 5 0390 (0) 0218 (0) 027f (0) 026d (0)\n============ DEPTH: 6 ==========================================\n006 1 06b9 | 1 06b9 (0)\n007 1 0427 | 1 0427 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","private_key":"d54090bceb0325e7d681953c0c9b885b52b9fde17c87981f51927d5458bdec1f","name":"node_0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","services":["bzz","pss"],"enable_msg_events":true,"port":42705},"up":true}},{"node":{"info":{"id":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","name":"node_cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","enode":"enode://15721bb131c5000be7e9d400500ccf12cd6a04edf750c1fc78e225c6728baa8fb5c18e2e68c16d05b26f9642d009b6ca670eb011fce286318a4281ec930da572@127.0.0.1:0","enr":"0xf88fb840c585ecd30f00f1f4839d519a833ff3434caa90c288ae094854454e6f9b846c84292aa12c66d3327f9e57934efb3cd562b9c14ba7c2c39303c39271dc148bab390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10215721bb131c5000be7e9d400500ccf12cd6a04edf750c1fc78e225c6728baa8f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zc0WVyH2hR82H60LO6iMiHC+mtbWuMvOzHyJ4QaNl5o=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cdcd16\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6d60 645b 0506 | 65 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n001 4 a75a b16d 8b76 83dc | 33 9a92 (0) 9d3c (0) 9e02 (0) 9ee7 (0)\n002 6 f74e e0ea e0b1 edc8 | 15 e55d (0) e77f (0) e16b (0) e0b1 (0)\n003 5 d224 d6ff dc97 dfae | 6 d224 (0) d0f3 (0) d6ff (0) db08 (0)\n004 2 c181 c3a1 | 2 c3a1 (0) c181 (0)\n005 3 c8e5 ca03 cbc5 | 3 c8e5 (0) ca03 (0) cbc5 (0)\n============ DEPTH: 6 ==========================================\n006 3 cfbb ce99 cec3 | 3 cfbb (0) cec3 (0) ce99 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","private_key":"dc9c6faeb1b0ed2241977e5e119fb047b527baa72b57faf6a490bfa2463702b1","name":"node_cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","services":["bzz","pss"],"enable_msg_events":true,"port":44531},"up":true}},{"node":{"info":{"id":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","name":"node_645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","enode":"enode://c5df28a427ebcae9a135bf8f4e05d5507d48467c55937ae432e5453a53516d1d67d16f232b7ec71929f992ebb8d25fa8442c2e4ec12b9b9c2e90365d0ec58d62@127.0.0.1:0","enr":"0xf88fb8407d96a32e90f5234bc9b785b90e5ecbbc3c002e4307bfc19f4141f794943d59ac256d05f75f0afd515d598bdd6a82b8db9167d584b304303c4db1bc563447b0f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c5df28a427ebcae9a135bf8f4e05d5507d48467c55937ae432e5453a53516d1d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZFtOazb8GShyX2J67tJ49GxafWsP/3zP9VoEaNR7I+g=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 645b4e\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8b76 a320 d6ff cdcd | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 2 1be4 213b | 27 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n002 9 5d60 5abc 5a01 5776 | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 6 734e 757a 772e 7cf4 | 12 7fbc (0) 7f87 (0) 7dc5 (0) 7cf4 (0)\n004 3 6c82 6d60 6e5c | 6 6982 (0) 6c82 (0) 6c02 (0) 6d60 (0)\n005 1 6210 | 1 6210 (0)\n============ DEPTH: 6 ==========================================\n006 3 667e 6742 6728 | 3 667e (0) 6742 (0) 6728 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","private_key":"04fc1c10d7b313a061609b0eed8efdc7b1d9fd9169d7d7d5381d5ef4a53086f9","name":"node_645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","services":["bzz","pss"],"enable_msg_events":true,"port":35261},"up":true}},{"node":{"info":{"id":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","name":"node_213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","enode":"enode://761923555d54e992f473a9407939c25446dcfdda08081916f298c2fb2c8380ed0cf602deba79e7ff4ebd2c17f9cece98ae0e15539870f66a634b733171e0ec27@127.0.0.1:0","enr":"0xf88fb84009b10445736e612ea99db7cb50e94305fdfee64d061a1bb4fb2cf291ff6ecffc7311805dc59471a2997aa537f1c1d964a2d26f94a8433a498003cd0ed5bace8b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103761923555d54e992f473a9407939c25446dcfdda08081916f298c2fb2c8380ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ITv2544CpXWFkIx1bwllKXFSw8QAoO1MQHpBHh7FlC0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 213bf6\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ea60 cec3 b16d 89c8 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 4 41b9 5776 558e 645b | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 7 1be4 109e 0506 0427 | 15 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n003 4 372d 3cb1 38ab 39db | 6 3ee4 (0) 3e56 (0) 3cb1 (0) 38ab (0)\n004 2 286a 2a22 | 2 2a22 (0) 286a (0)\n============ DEPTH: 5 ==========================================\n005 3 26d1 2459 2434 | 3 26d1 (0) 2459 (0) 2434 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","private_key":"bb9e629d827643ea4b3d2c1f6c8a26cc16d191cec7709cdbdbf10fcfa47361b6","name":"node_213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","services":["bzz","pss"],"enable_msg_events":true,"port":33711},"up":true}},{"node":{"info":{"id":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","name":"node_018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","enode":"enode://e176b178b7c28353b25e6ae0584c3cd889c856b2bffd5c41cfb6b013ef2ebf3ee736f96dc0ebbb82bb3ebb2fefd70e8465cc77fe5bda8ab3068748044122bae4@127.0.0.1:0","enr":"0xf88fb8402a03da3911096a8fd7d223cc3dbf67101905e23b5b0c57af60f84593af3ac73e58f9d55a0d7ff7284740335e16e4305a45484856e16b8428743a7862d89b2f4d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e176b178b7c28353b25e6ae0584c3cd889c856b2bffd5c41cfb6b013ef2ebf3e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AYrcYT941uyHYnT4ISUf0EnrNlFkbNaeJ+/iEf6I2TY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 018adc\npopulation: 42 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 83dc 8cf9 89c8 895b | 63 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n001 11 6c82 7639 7b92 7f87 | 38 734e (0) 7355 (0) 73b8 (0) 757a (0)\n002 3 3cb1 2a22 213b | 12 372d (0) 3e56 (0) 3ee4 (0) 3cb1 (0)\n003 4 109e 13bc 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 3 0ff6 0bcf 0ab9 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 3 0506 0427 06b9 | 3 06b9 (0) 0427 (0) 0506 (0)\n============ DEPTH: 6 ==========================================\n006 4 0390 0218 027f 026d | 4 0390 (0) 0218 (0) 027f (0) 026d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","private_key":"b416fa1edc6a9481a2700407cc6b4cf1fe22447bcfced748269842bb79bd7be1","name":"node_018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","services":["bzz","pss"],"enable_msg_events":true,"port":38849},"up":true}},{"node":{"info":{"id":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","name":"node_edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","enode":"enode://bcb2c62558ac0c921253415556bb8521bb1f361278884453958a4ad1c6d2d761d9c4ea778253061cbb4a18a63c700bd5ec3b4e98d0ee89f4d68789a49a255c1a@127.0.0.1:0","enr":"0xf88fb840969cc1e8767d29e18d752912b07d4f68a5612caf1a3d7e4b924b03fb8f6f41da1725d64bd2cda2fabf6d5df9b87ac5e7873946a70a71fc605d58f5091e260e2c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bcb2c62558ac0c921253415556bb8521bb1f361278884453958a4ad1c6d2d761","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7ch5QVP7UXCF0nqDpLAOjDs38i0iQrhCyy+rZnZN6f4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: edc879\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 772e 5d60 5a01 1be4 | 65 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n001 3 a7a6 8cf9 83dc | 33 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n002 6 db08 ce99 cdcd ca03 | 15 c8e5 (0) ca03 (0) cbc5 (0) cfbb (0)\n003 3 f361 f360 f74e | 5 f5c4 (0) f410 (0) f74e (0) f360 (0)\n004 5 e16b e0b1 e0ea e55d | 5 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n============ DEPTH: 5 ==========================================\n005 3 ebca ea0e ea60 | 3 ebca (0) ea0e (0) ea60 (0)\n006 0 | 0\n007 0 | 0\n008 1 ed32 | 1 ed32 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","private_key":"cc8bb9100f25964f245e87e3f9bf408be100ad3a6d25298aaf5c1cec3309e03c","name":"node_edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","services":["bzz","pss"],"enable_msg_events":true,"port":46185},"up":true}},{"node":{"info":{"id":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","name":"node_5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","enode":"enode://be300889154a90ed33d9cf94b4ff711ba4b0fd2831f1c923f836379f54c554a322b2ffd67ad31b60921194ecbaf36fb2ae1fcaf4f83b5f8d09d04771a8bd6fde@127.0.0.1:0","enr":"0xf88fb84021eb12c9a4bca577771c8a61b0f665dda93925bca15665a86baca81ba20608c50975baba6dfbe9f8d7c81aed39d6fd56b12badc27b7e8cae94445a3bdf1cc94f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102be300889154a90ed33d9cf94b4ff711ba4b0fd2831f1c923f836379f54c554a3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WgGZP/e0vRL9slnpayagNtDPXUrpybUWvmS2Os7CRDo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a0199\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 dc97 e0ea edc8 b2b9 | 63 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n001 3 372d 2434 1be4 | 27 372d (0) 3cb1 (0) 3ee4 (0) 3e56 (0)\n002 6 757a 667e 645b 6c02 | 23 6210 (0) 6742 (0) 6728 (0) 667e (0)\n003 6 4167 41b9 419a 47c3 | 8 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n004 4 5776 558e 517a 539d | 4 558e (0) 5776 (0) 539d (0) 517a (0)\n============ DEPTH: 5 ==========================================\n005 1 5d60 | 1 5d60 (0)\n006 0 | 0\n007 0 | 0\n008 1 5abc | 1 5abc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","private_key":"33fe2e9d121fb48e9e8ff1552b58a42c5f6d078b47223f83f9aecc781953dd8a","name":"node_5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","services":["bzz","pss"],"enable_msg_events":true,"port":39861},"up":true}},{"node":{"info":{"id":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","name":"node_b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","enode":"enode://3bd0292e58c0d4c952c3d2ff221410cb20c7ffac7848e2c5d351e32cbb578ddba8be42843dd17f2daa62079d6ce7886946d545db1845f9d31cf67dcd9e285c66@127.0.0.1:0","enr":"0xf88fb84069b7f53f8dde1ec32c5ac7119d271f0c63fdcfddf4ba67b3bd0f4a190049baee56b5a605f02fcefc86416f72d03d3a21fe91db5629d059a026b8a2ff9f3450ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023bd0292e58c0d4c952c3d2ff221410cb20c7ffac7848e2c5d351e32cbb578ddb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uOGoDZEhb9X4vD90E8r2it5/EkNU1E/nvRVaCJE0pwo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8e1a8\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2434 109e 0218 06b9 | 65 372d (0) 3cb1 (0) 3e56 (0) 3ee4 (0)\n001 5 e77f e55d db08 dfae | 30 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n002 7 83dc 89c8 895b 8b76 | 16 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n003 5 ae67 a320 a2ba a75a | 9 a085 (0) a2ba (0) a320 (0) a75a (0)\n004 5 b2b9 b381 b16d b70e | 5 b2b9 (0) b381 (0) b16d (0) b70e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 b92a | 1 b92a (0)\n008 1 b841 | 1 b841 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","private_key":"dac5558d2b06b587645b8308b63c3c7a7d9d90ec36353760cb9c656ee41fe6d5","name":"node_b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","services":["bzz","pss"],"enable_msg_events":true,"port":33565},"up":true}},{"node":{"info":{"id":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","name":"node_b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","enode":"enode://f3da79d322438356e44f3b4036211300b07efa604f756ee0e60b1cfa5bd21fe2339ddf44138c970dd83db24f66b75d48e7b97492d75cae27dac3d1da16205d45@127.0.0.1:0","enr":"0xf88fb8403f9763127c7628679fe7fcaba9c97b58e29d4bab1758c67f241c249a66177230530b8da7ce97ec138bedc08717a7e96f184614db39decae489ad12dfe3d606090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f3da79d322438356e44f3b4036211300b07efa604f756ee0e60b1cfa5bd21fe2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tIbOMc6IDbOqoXoKwsLzVUtv5x+cBR7bVyl0NCr0rbk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b486ce\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 6c82 6c02 6e5c 7cf4 | 65 734e (0) 7355 (0) 73b8 (0) 757a (0)\n001 2 db08 c181 | 30 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n002 3 9ee7 8b76 83dc | 16 91eb (0) 92a1 (0) 957d (0) 9626 (0)\n003 4 a7a6 a320 afa3 ae67 | 9 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n004 3 b92a b841 b8e1 | 3 b92a (0) b841 (0) b8e1 (0)\n============ DEPTH: 5 ==========================================\n005 3 b2b9 b381 b16d | 3 b2b9 (0) b381 (0) b16d (0)\n006 1 b70e | 1 b70e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","private_key":"60109f1a20e5d694e88f021d4e588994aae7c2ecfca6a950149c53652f4a5b3a","name":"node_b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","services":["bzz","pss"],"enable_msg_events":true,"port":44351},"up":true}},{"node":{"info":{"id":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","name":"node_1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","enode":"enode://8375557348b05531d3d6a4b6f494f44e33c0a1862c0c63fce6ab3e8a389adb299f4fb14a74d2ef9160d2df04f362af2e9c7021f0cabc9bf4a116663b62dce076@127.0.0.1:0","enr":"0xf88fb8404ea89c730deaca09ae7f36423dd170ee83ef05e71559ce57692a4cb2a14e79a73f552356028fc016ecbee9961b2691884662145357a4c9db80d0d3156feda59c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028375557348b05531d3d6a4b6f494f44e33c0a1862c0c63fce6ab3e8a389adb29","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"G+Q0jsVnDNxPFk13sTVueRC20b5Km3IOVJ0C5Ugqnng=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1be434\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 cec3 cbc5 ea0e ea60 | 63 f5c4 (0) f410 (0) f74e (0) f360 (0)\n001 9 78cb 7f87 6c82 645b | 38 73b8 (0) 7355 (0) 734e (0) 757a (0)\n002 4 372d 286a 213b 2434 | 12 3e56 (0) 3ee4 (0) 3cb1 (0) 38ab (0)\n003 11 0ff6 0bcf 0ab9 018a | 11 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n============ DEPTH: 4 ==========================================\n004 2 13bc 109e | 2 13bc (0) 109e (0)\n005 0 | 0\n006 1 1929 | 1 1929 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","private_key":"f4c9d012e654cc97f045dbff8811d75d2bc28f743389ed83138c83f208c0c4a3","name":"node_1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","services":["bzz","pss"],"enable_msg_events":true,"port":39499},"up":true}},{"node":{"info":{"id":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","name":"node_517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","enode":"enode://84e56a199123357e4baa395c602310fd7ee347f259e1a71c6f6fea49356dee106bdd2103681d15f896df139363b8caf91a70e2927012eb4ed3189abc8574c05f@127.0.0.1:0","enr":"0xf88fb84006dac2d9b267151a93241e398113497441d145d87211a3c352c7f87348ac8ce506d1e2d81d2e99f9e4320692bb2519b52e0ec44d5b98dd50de8964f0f869abef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10384e56a199123357e4baa395c602310fd7ee347f259e1a71c6f6fea49356dee10","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UXqpdwSCR9XRatUaKG/6xNj5EHM/BXiyIiATCMMtGV4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 517aa9\npopulation: 21 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 e0ea e77f f361 | 63 f410 (0) f5c4 (0) f74e (0) f360 (0)\n001 3 018a 0506 1be4 | 27 3cb1 (0) 3e56 (0) 3ee4 (0) 38ab (0)\n002 3 757a 772e 645b | 23 73b8 (0) 734e (0) 7355 (0) 757a (0)\n003 5 4a18 4b24 419a 41b9 | 8 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n004 3 5abc 5a01 5d60 | 3 5abc (0) 5a01 (0) 5d60 (0)\n============ DEPTH: 5 ==========================================\n005 2 558e 5776 | 2 558e (0) 5776 (0)\n006 1 539d | 1 539d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","private_key":"468bb419433b15b2933469b68aecf09e25fe8872c8128a2ee0198d626c5e16a9","name":"node_517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","services":["bzz","pss"],"enable_msg_events":true,"port":43881},"up":true}},{"node":{"info":{"id":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","name":"node_5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","enode":"enode://04a81661386177d0609fc1bd233738fbb96b9280ab323c85ceac159c0854dc725e4c84c8957ba802498745365c937a581e09c8a4a1580b0dce82e5dcaef08ee4@127.0.0.1:0","enr":"0xf88fb840dee34144fcdd9b6e5d1be0361509c91c011d627a6a3b69edbbcb3a90f7252f5b4aa02cec8d59613ac817a9336ddf3e1673f6509927af5c0b4bc44d01a9fb7f440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10204a81661386177d0609fc1bd233738fbb96b9280ab323c85ceac159c0854dc72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XWCOZqF0QgkREctHJyP+OuofK67KpUa1fUlQfGOmHNo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5d608e\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 f74e f361 edc8 ea0e | 63 f5c4 (0) f410 (0) f74e (0) f360 (0)\n001 2 018a 0506 | 27 38ab (0) 39db (0) 3e56 (0) 3ee4 (0)\n002 7 6ecb 645b 757a 772e | 23 73b8 (0) 734e (0) 7355 (0) 757a (0)\n003 3 47c3 41b9 4a18 | 8 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n004 4 5776 558e 539d 517a | 4 558e (0) 5776 (0) 539d (0) 517a (0)\n============ DEPTH: 5 ==========================================\n005 2 5abc 5a01 | 2 5abc (0) 5a01 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","private_key":"81c50622bdad71d45180a827fe4f2709ac6e73ab5b1d7f135ae6c563bdf67dfc","name":"node_5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","services":["bzz","pss"],"enable_msg_events":true,"port":46869},"up":true}},{"node":{"info":{"id":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","name":"node_83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","enode":"enode://9903840de4085e02bf4b40b91137ea82baf327272e40f2a68b0bacc22064465e695d1053d48ade3cc707fe05b2f395540b7e8aaed800b8a746085969ea98a8c1@127.0.0.1:0","enr":"0xf88fb840ef8ed31b921f8a77d4906bb0fa6b72a27e794b68d3615d8c5035c35186f636a554ccec2b28662884c8454b4134c077320be3b5e6472693c92cf8945deab453840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039903840de4085e02bf4b40b91137ea82baf327272e40f2a68b0bacc22064465e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g9xVbtNvN9BnZb4lVP6G6vHsIeKTH7IkAyOEU78CHfs=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 83dc55\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 018a 026d 2434 213b | 65 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n001 11 f361 f74e e77f e0b1 | 30 f410 (0) f5c4 (0) f74e (0) f360 (0)\n002 8 a7a6 a2ba a320 ae67 | 17 b70e (0) b486 (0) b2b9 (0) b381 (0)\n003 5 9626 9a92 9d3c 9e02 | 8 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n004 5 8cf9 895b 89c8 8be4 | 5 8cf9 (0) 8be4 (0) 8b76 (0) 895b (0)\n============ DEPTH: 5 ==========================================\n005 1 86ca | 1 86ca (0)\n006 0 | 0\n007 1 82f0 | 1 82f0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","private_key":"996588cd689e21ae98c63522cc84c5ca8c59901f1738bf888136a0d84745625a","name":"node_83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","services":["bzz","pss"],"enable_msg_events":true,"port":44859},"up":true}},{"node":{"info":{"id":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","name":"node_db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","enode":"enode://0620b99063bcbdca96543150c5bcaa6bbae76cfa9d6a5700cec06bcac3f80ddbb3e87099c7516c8bf7e1fc7bbe1a2c74decdb9beacdc44ed6b5ea859a7681da9@127.0.0.1:0","enr":"0xf88fb8409dedfae6e6fc520e43e7d06cb137d94f183daa858fb40bef2a6b1e677ec9e96c7ae3a0fdbc5513424aed12e0358fad4c8358f48c69e806c50c7d002c899356370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030620b99063bcbdca96543150c5bcaa6bbae76cfa9d6a5700cec06bcac3f80ddb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2wiBA/O28seE127Nmci0p3/Tm7Occt39kcmcGp3Tt1s=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: db0881\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7fbc 0427 0506 | 65 3cb1 (0) 3e56 (0) 3ee4 (0) 38ab (0)\n001 6 b16d b486 b70e b841 | 33 b92a (0) b841 (0) b8e1 (0) b70e (0)\n002 11 f74e f360 f361 e77f | 15 f410 (0) f5c4 (0) f74e (0) f360 (0)\n003 7 ca03 cbc5 c8e5 cdcd | 9 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n004 3 d0f3 d224 d6ff | 3 d224 (0) d0f3 (0) d6ff (0)\n============ DEPTH: 5 ==========================================\n005 2 dc97 dfae | 2 dc97 (0) dfae (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","private_key":"531ff73ac55db42d259eda258c322099463847f19f0e133a69fe506626d432c8","name":"node_db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","services":["bzz","pss"],"enable_msg_events":true,"port":33251},"up":true}},{"node":{"info":{"id":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","name":"node_c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","enode":"enode://c09ff8bce7f3f84fda572912d07e2fd5303e8a9bcd69f3794ebec6268fba90310761b6f73741b9701a1928f9af099bb8eda1d9d38e849a12fd21d9a8a6f43b37@127.0.0.1:0","enr":"0xf88fb8408bae0ad58fe6f74ee5e733985301353441b70d767126573c80639676f5d3c0d94ab77ee9239739d4a1b3ab7328206c2d561f9468e37e76fe16c2d02be7e0c5ab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c09ff8bce7f3f84fda572912d07e2fd5303e8a9bcd69f3794ebec6268fba9031","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wYEFqjAqQ+NS2Zl0Wg+Aavn4y4u4M0k1faXIXol1rNE=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c18105\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 286a 0427 0506 | 65 3cb1 (0) 3ee4 (0) 3e56 (0) 38ab (0)\n001 5 8b76 b16d b486 b8e1 | 33 91eb (0) 92a1 (0) 9626 (0) 957d (0)\n002 5 e0b1 e0ea f74e f360 | 15 f5c4 (0) f410 (0) f74e (0) f360 (0)\n003 4 d224 dc97 dfae db08 | 6 d0f3 (0) d224 (0) d6ff (0) dc97 (0)\n============ DEPTH: 4 ==========================================\n004 7 c8e5 ca03 cbc5 cdcd | 7 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n005 0 | 0\n006 1 c3a1 | 1 c3a1 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","private_key":"7a2924b057c33f05e57a60b815f1c80855c3acc417bf37cd31d281f670cba443","name":"node_c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","services":["bzz","pss"],"enable_msg_events":true,"port":40633},"up":true}},{"node":{"info":{"id":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","name":"node_a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","enode":"enode://f06cb29c4ffab0c600cf7e7834032f1aab24cf48200d31c1c67b6ba2ee38195c9596df70c664d38cc53bdbcda0bb8c9bda598d0e0f3b377f5f6568b3725f7ba2@127.0.0.1:0","enr":"0xf88fb8404d99eb2b83e49511188c6105f0ef75fc98bd4e9871cb3b328d0fbec9f69153952df139a6d1d39c45e99b4baf70040b97087c9ccdf54aed111a2cf7435a6f574b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f06cb29c4ffab0c600cf7e7834032f1aab24cf48200d31c1c67b6ba2ee38195c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p6YYBNJw7WwnpLHopjTDDXzbr2RKHGfLxrCM2EmnEds=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a7a618\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 109e 0ff6 06b9 0506 | 65 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n001 8 f360 f361 f410 ebca | 30 f74e (0) f5c4 (0) f410 (0) f361 (0)\n002 6 92a1 9ee7 8b76 8be4 | 16 957d (0) 9626 (0) 91eb (0) 92a1 (0)\n003 6 b841 b8e1 b486 b70e | 8 b92a (0) b841 (0) b8e1 (0) b70e (0)\n004 4 ad0d afa3 aebd ae67 | 4 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n============ DEPTH: 5 ==========================================\n005 3 a085 a320 a2ba | 3 a085 (0) a2ba (0) a320 (0)\n006 0 | 0\n007 0 | 0\n008 1 a75a | 1 a75a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","private_key":"78a5f9f36119c4686d8fb667f830f052885e6485e92dd09b9fed7f9e01368f83","name":"node_a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","services":["bzz","pss"],"enable_msg_events":true,"port":35649},"up":true}},{"node":{"info":{"id":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","name":"node_b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","enode":"enode://3a9f619551e6b60c9edcac716ff28cd93af12dbc9b07a2c9ea541a8e3666f513d0b05e82cae81eb72534d3784d41a948cba2a1d9db8b3764feee40d52290427b@127.0.0.1:0","enr":"0xf88fb8403bcb9b72c0dd4b343993b4c02c8d3dfd1a66f01fd355938b0d91547730d0fdef30e0150cbf8f5999ecd82b2ba083bb019e0fc5d96ed35baf82b80b3645eb4c4f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033a9f619551e6b60c9edcac716ff28cd93af12dbc9b07a2c9ea541a8e3666f513","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sW3N8f8aVtSeN0Ux2YhdWcG8+7YoYEUg2bHYRmLtuco=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b16dcd\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7f87 78cb 41b9 47c3 | 65 38ab (0) 39db (0) 3cb1 (0) 3e56 (0)\n001 10 ce99 cdcd c8e5 cbc5 | 30 d224 (0) d0f3 (0) d6ff (0) dc97 (0)\n002 4 9d3c 9ee7 8b76 83dc | 16 9626 (0) 957d (0) 91eb (0) 92a1 (0)\n003 3 ae67 a320 a7a6 | 9 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n004 3 b92a b841 b8e1 | 3 b92a (0) b841 (0) b8e1 (0)\n005 2 b70e b486 | 2 b70e (0) b486 (0)\n============ DEPTH: 6 ==========================================\n006 2 b2b9 b381 | 2 b2b9 (0) b381 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","private_key":"ede19b96340b0babe7021d81a8ec746406996af53908a387cd2e9f1551651869","name":"node_b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","services":["bzz","pss"],"enable_msg_events":true,"port":33287},"up":true}},{"node":{"info":{"id":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","name":"node_ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","enode":"enode://a3a82e04610c3851f4b6b80bdd5666f8c2eb2a5c4fe7a79dbfc5fa38de9bbd36ca8dd8a3d794ead924e43a0812bbbcaf1f394e4d77e9662238f80ccac0d8e52a@127.0.0.1:0","enr":"0xf88fb84090c476d24643383a66557141b62c940150453a05a838e91c6eaa1441befcedd441f7ac293638f5a01132227c8daf970bb3ec76d938fcd2257ef6282b758c36a30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a3a82e04610c3851f4b6b80bdd5666f8c2eb2a5c4fe7a79dbfc5fa38de9bbd36","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6mDvfLPyFmpcjihsiFmElDoupa/0cwAVvmoVAxBAzs8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ea60ef\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0ab9 1be4 372d 3e56 | 65 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n001 8 83dc 86ca 89c8 895b | 33 8cf9 (0) 8b76 (0) 8be4 (0) 895b (0)\n002 5 c8e5 ca03 d224 dfae | 15 d224 (0) d0f3 (0) d6ff (0) dc97 (0)\n003 4 f410 f74e f360 f361 | 5 f5c4 (0) f410 (0) f74e (0) f361 (0)\n004 3 e0b1 e0ea e77f | 5 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n005 2 ed32 edc8 | 2 ed32 (0) edc8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ebca | 1 ebca (0)\n008 0 | 0\n009 1 ea0e | 1 ea0e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","private_key":"34572c71c9f4767ddfaee3aa21c52f966a73447695fe12dee7eb9ff693417140","name":"node_ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","services":["bzz","pss"],"enable_msg_events":true,"port":43863},"up":true}},{"node":{"info":{"id":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","name":"node_57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","enode":"enode://802bb2984957e4187577dba69e5a73714c65bc176e785c46c52c725e8cb118d05f0b0840a373188d1ccd56465c20ba7aedf21b7e5411c1c96ac32e6adad2e184@127.0.0.1:0","enr":"0xf88fb8401f7f3cc91efaede856461ce79b9ff9df6ced9d7358d2004d24fd403a006dd7604de40bc6b4f4e14b0292d0f15079e6c6aa69988b38698efb340481039bef5c300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102802bb2984957e4187577dba69e5a73714c65bc176e785c46c52c725e8cb118d0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V3ZFIhYmIMGtCxZqnEN3IlXQzAHknyEi7wnbBGgEpXA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 577645\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c8e5 dc97 e77f ea60 | 63 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n001 12 3ee4 286a 213b 2434 | 27 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n002 8 645b 6ecb 6c82 772e | 23 734e (0) 7355 (0) 73b8 (0) 757a (0)\n003 5 4a18 4b24 47c3 4167 | 8 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n004 3 5d60 5abc 5a01 | 3 5abc (0) 5a01 (0) 5d60 (0)\n============ DEPTH: 5 ==========================================\n005 2 539d 517a | 2 539d (0) 517a (0)\n006 1 558e | 1 558e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","private_key":"9de036860d3dc63ef40d3981f65da10bae27dd10ce542c76134e247073f512f4","name":"node_57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","services":["bzz","pss"],"enable_msg_events":true,"port":37591},"up":true}},{"node":{"info":{"id":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","name":"node_e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","enode":"enode://c80b19cf5a0bbf10af5ae60bf60765387031caab06906033df96362e07dd4e51e043bb824328834e600c0b6affc36df0d06ecd955103721482c11bedfe78e06e@127.0.0.1:0","enr":"0xf88fb84026a761e6c2aae397880443de1d6bb3b7770c8206f473451199148dcb9b74c03849739e4806e81c1ca8482e0712620998d9e4666d25b65e36e773f3c0f543a70f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c80b19cf5a0bbf10af5ae60bf60765387031caab06906033df96362e07dd4e51","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"539qqePfzOCi5dt5RwMiQkmrpgWVB1st+aWwswhVz0Y=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e77f6a\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1be4 5d60 517a 5776 | 65 38ab (0) 39db (0) 3cb1 (0) 3ee4 (0)\n001 13 92a1 957d 9ee7 83dc | 33 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n002 5 db08 dfae c8e5 ca03 | 15 d6ff (0) d224 (0) d0f3 (0) dc97 (0)\n003 4 f74e f410 f361 f360 | 5 f5c4 (0) f410 (0) f74e (0) f361 (0)\n004 5 ed32 edc8 ebca ea0e | 5 ed32 (0) edc8 (0) ebca (0) ea0e (0)\n============ DEPTH: 5 ==========================================\n005 3 e16b e0b1 e0ea | 3 e16b (0) e0b1 (0) e0ea (0)\n006 1 e55d | 1 e55d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","private_key":"c230ff1d7220134fe04e59de10522a8e372830d5b3eccbfbccf4b8e57536d4f9","name":"node_e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","services":["bzz","pss"],"enable_msg_events":true,"port":38009},"up":true}},{"node":{"info":{"id":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","name":"node_cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","enode":"enode://c9307563a6ac3d784c348187f2942d2aa64fb15afdb55d6fdfd6fa0bfc5e4a65281f9b0ef5dc5b155c0c97971411d8decd17c66ad96e3a0bca0f7bbfb6674ce8@127.0.0.1:0","enr":"0xf88fb8409fdaea6e03e3c24cf8967a46c99aaa146e74b7e455c4b7012f9c4b72fe74cbe831d49545d8fd8a8092b357b370922dfafe86853f004fb9f862395a41a00504000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c9307563a6ac3d784c348187f2942d2aa64fb15afdb55d6fdfd6fa0bfc5e4a65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zsPAHBR7NPJRBN3QslB2zvY6wiTq2p2fWgC4UTMxNU8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cec3c0\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 0506 06b9 018a 0ff6 | 65 372d (0) 3cb1 (0) 3ee4 (0) 3e56 (0)\n001 9 b381 83dc 82f0 86ca | 33 86ca (0) 82f0 (0) 83dc (0) 8cf9 (0)\n002 2 f360 e77f | 15 f74e (0) f5c4 (0) f410 (0) f361 (0)\n003 2 d224 db08 | 6 d0f3 (0) d224 (0) d6ff (0) dc97 (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 3 c8e5 ca03 cbc5 | 3 cbc5 (0) ca03 (0) c8e5 (0)\n006 1 cdcd | 1 cdcd (0)\n============ DEPTH: 7 ==========================================\n007 1 cfbb | 1 cfbb (0)\n008 0 | 0\n009 1 ce99 | 1 ce99 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","private_key":"a43b0e0e48e2e4dbd79184eaade1af54404a0a89d0d250b881a1c131de5b2174","name":"node_cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","services":["bzz","pss"],"enable_msg_events":true,"port":44913},"up":true}},{"node":{"info":{"id":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","name":"node_6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","enode":"enode://e94d070b0cd5336bdebbdb63309d23c431e87c6bfa03474b5ffe002182e1fe617f0cb27a3e399ff36cc6eff93a64eae9ce3958400eba3b644a878ec673bc5a6a@127.0.0.1:0","enr":"0xf88fb840ac1282029a97bfacb7298ac94161d57a84cd6347e9fa18bd1e71f37ded792f352b8491cf02668d2daea43f1e02089f892431108a7e4a5708307096b4a57c4cd80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e94d070b0cd5336bdebbdb63309d23c431e87c6bfa03474b5ffe002182e1fe61","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bIL9q9CeDp0PxQdhOgWVHAKylT12OgYqXzKq9cxHfBk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c82fd\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b486 c8e5 cec3 | 63 86ca (0) 82f0 (0) 83dc (0) 8cf9 (0)\n001 9 286a 2459 2434 3e56 | 27 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n002 6 5a01 5776 47c3 41b9 | 15 5d60 (0) 5abc (0) 5a01 (0) 539d (0)\n003 5 78cb 7fbc 7f87 7cf4 | 12 7355 (0) 734e (0) 73b8 (0) 757a (0)\n004 4 6210 645b 667e 6742 | 5 645b (0) 667e (0) 6728 (0) 6742 (0)\n005 1 6982 | 1 6982 (0)\n006 2 6ecb 6e5c | 2 6ecb (0) 6e5c (0)\n============ DEPTH: 7 ==========================================\n007 1 6d60 | 1 6d60 (0)\n008 1 6c02 | 1 6c02 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","private_key":"fdb64dd6356458c4ea0b68ad6552a972f6b174e8db0fecb40fb8c03a61e39561","name":"node_6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","services":["bzz","pss"],"enable_msg_events":true,"port":36231},"up":true}},{"node":{"info":{"id":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","name":"node_c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","enode":"enode://bb7389fc8693197348309cc5f82cd99b2d73b478cefbdcf901844a69e35ea841449888e8cf056b1a4475970b6815a0a091c37e89df251953b7ba15fecb352b8b@127.0.0.1:0","enr":"0xf88fb840ceee340c58b4bfd938dbe46f60634de3127f2f253a2ba4925a2309b4e89c1c276391c132d230217a48dbfe44934f0a5204f62163714f90b0a7901404b5cc51c90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bb7389fc8693197348309cc5f82cd99b2d73b478cefbdcf901844a69e35ea841","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yOWhtFM90N4SrO5NMTafOXhReFaHGLk7vDIeyD4HFPA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8e5a1\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 0427 0506 06b9 018a | 65 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n001 6 b16d 8be4 83dc 82f0 | 33 86ca (0) 82f0 (0) 83dc (0) 8cf9 (0)\n002 5 e77f ea60 ebca edc8 | 15 f74e (0) f5c4 (0) f410 (0) f361 (0)\n003 3 d0f3 d224 db08 | 6 d6ff (0) d224 (0) d0f3 (0) dc97 (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 4 cdcd cfbb cec3 ce99 | 4 cdcd (0) cfbb (0) cec3 (0) ce99 (0)\n============ DEPTH: 6 ==========================================\n006 2 ca03 cbc5 | 2 cbc5 (0) ca03 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","private_key":"71b41bd09467c47283a158151bded935639f103d9452befe2459162ec74df521","name":"node_c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","services":["bzz","pss"],"enable_msg_events":true,"port":46751},"up":true}},{"node":{"info":{"id":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","name":"node_ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","enode":"enode://18280baf1cb264a91130e6abae9d7e90b21447733bc8929577cb926538b2b17dc0add3d3467b320fae85519f6415afb36e9e18ba27105b5d0d33b8636fb5a711@127.0.0.1:0","enr":"0xf88fb840de9d966e41db3e276b1d1d67ae48e915d7689ef8081e41029aea9165c3ac62ff7805be7f8862a63d07c38f176d370349ab59f6917ada9b5ae644e87897df08600183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10318280baf1cb264a91130e6abae9d7e90b21447733bc8929577cb926538b2b17d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zpnp03ERxS6Smxh/4gF5CxpVXfuLa23lTpTffMLUP9Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ce99e9\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7fbc 286a 0427 | 65 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n001 6 b381 b16d a7a6 86ca | 33 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n002 4 edc8 ebca f361 f360 | 15 f74e (0) f410 (0) f5c4 (0) f361 (0)\n003 2 db08 d224 | 6 d6ff (0) d0f3 (0) d224 (0) dc97 (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 3 cbc5 ca03 c8e5 | 3 cbc5 (0) ca03 (0) c8e5 (0)\n006 1 cdcd | 1 cdcd (0)\n============ DEPTH: 7 ==========================================\n007 1 cfbb | 1 cfbb (0)\n008 0 | 0\n009 1 cec3 | 1 cec3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","private_key":"f6a40f6cecf0cb1296f7e100e8ee72b402405531fc277f70a99355650e3d7248","name":"node_ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","services":["bzz","pss"],"enable_msg_events":true,"port":43447},"up":true}},{"node":{"info":{"id":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","name":"node_042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","enode":"enode://0220d1612c3a461835407833a67a205cdc87d1df9aabc985243ad449332e2d38b80f52f8973a28babecac8fc22daf2862497c79efdbeaf82cce5ffe402efde4a@127.0.0.1:0","enr":"0xf88fb84007dcb9c1db66f2f7829bea3542a0b3053a1cae6b9452c7619ecc9080f00be44a7842d6a03474709be30cb31e8a773adaafd033c60d684af4d63ae57f729b446d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020220d1612c3a461835407833a67a205cdc87d1df9aabc985243ad449332e2d38","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BCeI1bcsuEo3VWXRINI5orFP3ziz9fmSKE14U1B3FIo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 042788\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 aebd a7a6 b16d f410 | 63 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n001 4 7639 5776 4cd0 41b9 | 38 6ecb (0) 6e5c (0) 6d60 (0) 6c02 (0)\n002 8 3ee4 3e56 3cb1 2459 | 12 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n003 4 13bc 109e 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 2 0ab9 0ff6 | 3 0bcf (0) 0ab9 (0) 0ff6 (0)\n005 5 0390 0218 027f 026d | 5 0390 (0) 0218 (0) 027f (0) 026d (0)\n============ DEPTH: 6 ==========================================\n006 1 06b9 | 1 06b9 (0)\n007 1 0506 | 1 0506 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","private_key":"ef2c90067d97cab14a4cf2eff2fa9332bc6149d7c6ddc78f3dfddf9fa938b9ba","name":"node_042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","services":["bzz","pss"],"enable_msg_events":true,"port":46141},"up":true}},{"node":{"info":{"id":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","name":"node_41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","enode":"enode://2a29ba5bbf7e82989e16f954d13795448cfffbc9f0d87a5e01c809de44cee798cba2568c3318ad4e7ac48915e5e99c46b3973d7ca9da44d169ced570e274088c@127.0.0.1:0","enr":"0xf88fb8407a50ecfb4ac26fa2aa0595d78a631d0be7ee8d3588ddd05dda07c3dedcfe07d83f0e6e095a3fe0d3382f43949ae3f633f5a780c1ee3921341dbe3c17cf9eec0a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022a29ba5bbf7e82989e16f954d13795448cfffbc9f0d87a5e01c809de44cee798","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QbnuetGWmOl1ibBZrTMzy2TwLBYAbZT7PQutfO2P8jg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 41b9ee\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b16d a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 11 39db 286a 2434 2459 | 27 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n002 9 645b 6c02 6c82 6ecb | 23 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n003 7 5a01 5abc 5d60 539d | 7 5a01 (0) 5abc (0) 5d60 (0) 539d (0)\n004 3 4cd0 4b24 4a18 | 4 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n005 1 47c3 | 1 47c3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 4167 | 1 4167 (0)\n009 0 | 0\n010 1 419a | 1 419a (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","private_key":"beb43b0ce6c2e3a4e7f2ec5be3324f334a3bed25b9becf17d1738a61f2613c93","name":"node_41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","services":["bzz","pss"],"enable_msg_events":true,"port":40537},"up":true}},{"node":{"info":{"id":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","name":"node_78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","enode":"enode://8fe37769462119a45a588a0a6abcb43165093a0ad74a8e18016277a214169950e9f5c7d10bc217d0b80998c4cee74c344027362a9b3ca485d8c98f12dc287640@127.0.0.1:0","enr":"0xf88fb840a0f01bac92cac5d6526e266529aebd70a42a5e443d9e68bb1da73f022bb2fe79551dbcdcaa994812c375e725c8126e32ef46d373f744fcecd8f7bc0ef3f26d1b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028fe37769462119a45a588a0a6abcb43165093a0ad74a8e18016277a214169950","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eMvBmiTQlat4WISQWMZcBhxSKJuR3dks7jS+2YruSlk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 78cbc1\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ea0e b486 b16d a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 6 026d 0ff6 1be4 286a | 27 372d (0) 38ab (0) 39db (0) 3e56 (0)\n002 9 5abc 5d60 558e 5776 | 15 5a01 (0) 5abc (0) 5d60 (0) 539d (0)\n003 6 6982 6e5c 6d60 6c82 | 11 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n004 4 73b8 757a 772e 7639 | 6 734e (0) 7355 (0) 73b8 (0) 757a (0)\n============ DEPTH: 5 ==========================================\n005 4 7dc5 7cf4 7fbc 7f87 | 4 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n006 1 7b92 | 1 7b92 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","private_key":"7de1fbbba1cd14694bd6b63bb00d807182ac42a8ffabee58c1eb352d696871cc","name":"node_78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","services":["bzz","pss"],"enable_msg_events":true,"port":45671},"up":true}},{"node":{"info":{"id":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","name":"node_7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","enode":"enode://a63ffc43cec6078c4261ca9a8bc556c4694f55f153d5ec2065743f7151a3b8e16a1f329f2db489e9646c33005a30ccd6947c2be1189038b9497b1634608cf116@127.0.0.1:0","enr":"0xf88fb84074c9fcda11cf86d8033a7ec003b37f4192bc99d18862396df30d040e21b6ed611ad763446b7690ea37ef1d4237ca2dcec449f1cb3a2df4176f2099ce8b39a9960183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a63ffc43cec6078c4261ca9a8bc556c4694f55f153d5ec2065743f7151a3b8e1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f4fafuVbTIyPnVVBH/iNOgtjv+5qUWkX1J+mJz+1uGo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7f87da\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ea0e b486 b16d a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 6 026d 018a 0ff6 1be4 | 27 372d (0) 3cb1 (0) 3e56 (0) 3ee4 (0)\n002 6 5d60 5776 4a18 419a | 15 5abc (0) 5a01 (0) 5d60 (0) 539d (0)\n003 7 6e5c 6d60 6c82 6982 | 11 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n004 5 734e 73b8 757a 772e | 6 7355 (0) 734e (0) 73b8 (0) 757a (0)\n005 2 7b92 78cb | 2 7b92 (0) 78cb (0)\n============ DEPTH: 6 ==========================================\n006 2 7dc5 7cf4 | 2 7dc5 (0) 7cf4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 7fbc | 1 7fbc (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","private_key":"a7e3fdde74aed0e2ae459190f839adf63156aa7982bde3d6ab0f33a8e8526b9d","name":"node_7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","services":["bzz","pss"],"enable_msg_events":true,"port":39359},"up":true}},{"node":{"info":{"id":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","name":"node_47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","enode":"enode://9b43113635c9212f3a25073df459dd4340386c80a79823d1931a15f6efe8cfa8bc4887bfa1237da6956b72e5c06e1c9a79a8daad206a3e91916b29e0a2027bc5@127.0.0.1:0","enr":"0xf88fb840a37ee48405baa3c5ff376e49a1443eb509afff243b04f89c05b8f4e6eb8c9c7a5756c4c8a97256b7c92d95133662d4d5fb77bc09cf085f06283d82d85c5a62630183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039b43113635c9212f3a25073df459dd4340386c80a79823d1931a15f6efe8cfa8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R8Pg37v86+7OeIZcjJiVdzYM2cxGo7Q/S3sB7RTcMOY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 47c3e0\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 b16d aebd a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 9 3ee4 286a 2434 2459 | 27 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n002 5 645b 6c82 7639 78cb | 23 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n003 6 5a01 5d60 539d 517a | 7 5abc (0) 5a01 (0) 5d60 (0) 539d (0)\n004 4 4cd0 48b6 4b24 4a18 | 4 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n============ DEPTH: 5 ==========================================\n005 3 4167 419a 41b9 | 3 4167 (0) 41b9 (0) 419a (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","private_key":"760e9a634e4459a6137e0a4164c2ff06b954c6bb74a19084566e563f864b8de4","name":"node_47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","services":["bzz","pss"],"enable_msg_events":true,"port":34401},"up":true}},{"node":{"info":{"id":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","name":"node_06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","enode":"enode://5e63692a1ce43cab6bc865e299006fcb429319aa159f11fa0e2d5cde573fce9a20be804b3baa55b8f64ceec46e9e671021661f6724946f19d2ab392d2f6772c7@127.0.0.1:0","enr":"0xf88fb8405aa541c395a887f464be5f1f9cf2706523e11b6aed11376895a795f591303d765ad2220baf9fc3dd3ccf472503e282fb7698969f2cc2a6d9df6ad10f2c7dd32a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035e63692a1ce43cab6bc865e299006fcb429319aa159f11fa0e2d5cde573fce9a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BrlfG6x2ykkl1QmwYhbyETrF3PBR71qgoyCuZAaeC20=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 06b95f\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 cec3 c8e5 cbc5 f410 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 11 6c82 7639 7b92 7cf4 | 38 6982 (0) 6e5c (0) 6ecb (0) 6d60 (0)\n002 5 3ee4 26d1 2434 2459 | 12 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n003 2 13bc 1be4 | 4 109e (0) 13bc (0) 1929 (0) 1be4 (0)\n004 2 0ab9 0ff6 | 3 0bcf (0) 0ab9 (0) 0ff6 (0)\n005 5 0390 026d 027f 0218 | 5 0390 (0) 0218 (0) 026d (0) 027f (0)\n============ DEPTH: 6 ==========================================\n006 2 0427 0506 | 2 0506 (0) 0427 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","private_key":"f46e1e932cac23f40da5e48808b19557c22164c16823eea2720fa52ea9286449","name":"node_06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","services":["bzz","pss"],"enable_msg_events":true,"port":35629},"up":true}},{"node":{"info":{"id":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","name":"node_0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","enode":"enode://f907d19b4970dee3081d1119e31908cb0ebcc915b2aa05c1dde8014b35d9aa0d3d2786013bad40ee4a9b54b615ed3a7236e9f526787cd201f18ab4a210e87ed2@127.0.0.1:0","enr":"0xf88fb840c0b7ab20a60ff949e9036939be157446dee043fa8688afcf67585ec1ce0377cd5af23af126525f9bd3f6170033dc2bd748394bc9398c95fa363d5c317c84bc480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f907d19b4970dee3081d1119e31908cb0ebcc915b2aa05c1dde8014b35d9aa0d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D/Z7Dp7GUJx3hklbez3bF2tPgiH/MA9AnwCj04noh0w=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ff67b\npopulation: 40 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 b381 b2b9 b486 aebd | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 13 5776 4cd0 47c3 4167 | 38 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n002 4 3e56 2434 2459 286a | 12 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n003 3 13bc 1929 1be4 | 4 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n004 8 0390 026d 027f 0218 | 8 0390 (0) 0218 (0) 026d (0) 027f (0)\n============ DEPTH: 5 ==========================================\n005 2 0ab9 0bcf | 2 0ab9 (0) 0bcf (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","private_key":"b19b4a43edf29d1bbb5774dd2c0f184ba873cf22764297c41af632f4d4521b57","name":"node_0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","services":["bzz","pss"],"enable_msg_events":true,"port":41299},"up":true}},{"node":{"info":{"id":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","name":"node_ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","enode":"enode://f32d87347fa320045d0437419b4f64bc07721d44cdc75a314bce969b021b92855772ec300a5cffcbd948b59461a4880ae1a8c59dc3e802876989a9edfc7c1efd@127.0.0.1:0","enr":"0xf88fb84014d558cfdcb467455447b89e2c52d929511fbde130fe2234fc3b57ca137a2f4a479c493406c6012eab1fd459e6315d30b354b20cfaca4f8bdbdecd4949c911af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f32d87347fa320045d0437419b4f64bc07721d44cdc75a314bce969b021b9285","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ygNtHvnmzjZU8tdp8WkmqhSVcZNYZCZInhVTnfqPd2M=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ca036d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6982 7fbc 7639 0ff6 | 65 5a01 (0) 5abc (0) 5d60 (0) 517a (0)\n001 5 b381 b16d 86ca 92a1 | 33 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n002 8 edc8 ebca ea60 e77f | 15 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n003 5 dfae db08 d6ff d224 | 6 dc97 (0) dfae (0) db08 (0) d6ff (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 4 cdcd cfbb ce99 cec3 | 4 cdcd (0) cfbb (0) ce99 (0) cec3 (0)\n============ DEPTH: 6 ==========================================\n006 1 c8e5 | 1 c8e5 (0)\n007 1 cbc5 | 1 cbc5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","private_key":"b23dda65c58838a9d2ba74acdddbfc1935094baca5b3b23176f48999f0ebc423","name":"node_ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","services":["bzz","pss"],"enable_msg_events":true,"port":41163},"up":true}},{"node":{"info":{"id":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","name":"node_7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","enode":"enode://c7b74655869120b2c4706d8c143ddf837a6d4ff7ba2cb1a30bdd8096b461cbd9af42aa144a134bdf16b6ad9b6b03829d1987131098736c2fe041122be46acd7d@127.0.0.1:0","enr":"0xf88fb840ac1c45c3987cfa0bec095840df22a0a404d1b8972dbd3231eb99168cfdad644a4c5f06f117723a23bc327ac428b9d187a2a9f1e96f0f9924e76b7e7b5415ef250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c7b74655869120b2c4706d8c143ddf837a6d4ff7ba2cb1a30bdd8096b461cbd9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"djn5pm6P9w9VTDRvqiX3gUCVfClbdI/EKhLfeXL0/MY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7639f9\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b486 92a1 f360 ca03 | 63 a320 (0) a2ba (0) a085 (0) a75a (0)\n001 12 018a 027f 06b9 0427 | 27 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n002 5 5776 4cd0 47c3 419a | 15 5d60 (0) 5abc (0) 5a01 (0) 539d (0)\n003 4 6742 6210 6982 6c82 | 11 6ecb (0) 6e5c (0) 6d60 (0) 6c02 (0)\n004 5 7f87 7fbc 7cf4 78cb | 6 7b92 (0) 78cb (0) 7dc5 (0) 7cf4 (0)\n005 3 734e 7355 73b8 | 3 734e (0) 7355 (0) 73b8 (0)\n============ DEPTH: 6 ==========================================\n006 1 757a | 1 757a (0)\n007 1 772e | 1 772e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","private_key":"1f28b72e347e6a5c993f2226d06196d963341d6dffe3204efca5eb82a9707088","name":"node_7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","services":["bzz","pss"],"enable_msg_events":true,"port":34577},"up":true}},{"node":{"info":{"id":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","name":"node_f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","enode":"enode://a3b1ef5f74c19769b24261107a80bcb5c7314e85dadcf17d941563517510613feeba9bc1b3b3f57abccfc02fb83d4cb78cd9c7da05a955ce6fe67f03479ad64a@127.0.0.1:0","enr":"0xf88fb840fce892c7ce07a80ebaf87930e850fbe62526831641a569b7c882e674fe6429995831d7b67c7a099dfc693d60591b92835664b864ff2db071138b0c37efa03dc70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a3b1ef5f74c19769b24261107a80bcb5c7314e85dadcf17d941563517510613f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"82CEBIvw/5had/UYN5b3s3twhe5u6ou8X8YlWIVMzmc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f36084\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1be4 419a 6982 7639 | 65 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n001 7 957d 82f0 8be4 a7a6 | 33 a320 (0) a2ba (0) a085 (0) a75a (0)\n002 8 db08 d0f3 c181 cec3 | 15 dfae (0) dc97 (0) db08 (0) d6ff (0)\n003 5 edc8 ea60 ebca e16b | 10 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 3 f74e f410 f5c4 | 3 f74e (0) f5c4 (0) f410 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 f361 | 1 f361 (0)\n========================================================================="}},"config":{"id":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","private_key":"5b7394337e91a274738c8e16b112b9c1d7682e033938b183e88d96322c81f6ee","name":"node_f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","services":["bzz","pss"],"enable_msg_events":true,"port":43813},"up":true}},{"node":{"info":{"id":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","name":"node_419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","enode":"enode://06f9ae5d93bede98bb8d04bad5677a64f79b8f1c3c17543de53e89dce96c87db7c8015e798b254f5490956cbd58a052bd3309ea1ec4b41cdeb763a59e1df2ea0@127.0.0.1:0","enr":"0xf88fb840f48fdca05279f70013ea36233f54604e2e5652203d6586c7f5ac11e49ab9b1c14d6ee24716fd542ede56f18e8d74f6b13de4985d774042f464d3dde6a87e07dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10206f9ae5d93bede98bb8d04bad5677a64f79b8f1c3c17543de53e89dce96c87db","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QZpmJt0CbAQ4RhWSEhmSxr4YaDdQEWVbbUBRZs2O338=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 419a66\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b841 8be4 92a1 9ee7 | 63 a2ba (0) a320 (0) a085 (0) a75a (0)\n001 2 0ff6 06b9 | 27 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n002 10 78cb 7cf4 7f87 7fbc | 23 6ecb (0) 6e5c (0) 6d60 (0) 6c02 (0)\n003 3 539d 517a 5a01 | 7 5d60 (0) 5abc (0) 5a01 (0) 558e (0)\n004 3 4a18 48b6 4cd0 | 4 4cd0 (0) 4b24 (0) 4a18 (0) 48b6 (0)\n005 1 47c3 | 1 47c3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 4167 | 1 4167 (0)\n009 0 | 0\n010 1 41b9 | 1 41b9 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","private_key":"1784affdde58532fc95837b5bd7b50ad427deccd1487d4abe583699bf0056194","name":"node_419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","services":["bzz","pss"],"enable_msg_events":true,"port":45225},"up":true}},{"node":{"info":{"id":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","name":"node_9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","enode":"enode://4fb204c7f877f39de63aaf107893f86e4a577583c7b352b55b873761870d61feeef14c9ae88c1ccf3f5901056645987349fbae583c5290bfaa425cedff42bbae@127.0.0.1:0","enr":"0xf88fb840db1e4e5331aa8fa6e8b15b7dddbce0bf805b41932f86eeb643714780ae1df8f27e4cc31ec2f7a6a984c1c623dfeb0ab29c35155b5294e015213643b1ad9986d40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024fb204c7f877f39de63aaf107893f86e4a577583c7b352b55b873761870d61fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nuez4GtFNhXL2HN8t0UVsVD1GPGi6qLbkOVHCN0WG30=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ee7b3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 06b9 286a 7b92 419a | 65 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n001 6 e77f d224 ca03 c8e5 | 30 dc97 (0) dfae (0) db08 (0) d6ff (0)\n002 8 b841 b8e1 b486 b2b9 | 17 a320 (0) a2ba (0) a085 (0) a75a (0)\n003 4 86ca 82f0 83dc 8be4 | 8 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n004 3 91eb 92a1 957d | 4 9626 (0) 957d (0) 91eb (0) 92a1 (0)\n005 1 9a92 | 1 9a92 (0)\n============ DEPTH: 6 ==========================================\n006 1 9d3c | 1 9d3c (0)\n007 0 | 0\n008 1 9e02 | 1 9e02 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","private_key":"14f6f6dc12c8535f9c0ecd71836c9bf9f02b9aad5a2e86ed0c61e30246f7451a","name":"node_9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","services":["bzz","pss"],"enable_msg_events":true,"port":43061},"up":true}},{"node":{"info":{"id":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","name":"node_286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","enode":"enode://68d1075d86a39ad083dd215a50f24b3428c9189dadaa43b155a9130844d25cd85ea26a1760fefd9019e5a59c2d57b2d76fc6f2f5484471c72f53ebfdd52fdb75@127.0.0.1:0","enr":"0xf88fb84027739fe9f8470c3be7639f03c5d1339a233678f728db90a68fcee15810f3b0d22702adf6eae7e82f5738fa558e2caa4f523ddc3607fff8bf0f865a8183e225870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10368d1075d86a39ad083dd215a50f24b3428c9189dadaa43b155a9130844d25cd8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KGrrpka7pKiqHDcr7p8sn/Cis6u08YvjISJVVcbc5OU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 286aeb\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 ea60 d224 c181 c8e5 | 63 dfae (0) dc97 (0) db08 (0) d6ff (0)\n001 9 5776 47c3 41b9 7f87 | 38 5abc (0) 5a01 (0) 5d60 (0) 539d (0)\n002 5 1be4 0ff6 06b9 0506 | 15 109e (0) 13bc (0) 1929 (0) 1be4 (0)\n003 3 3cb1 3ee4 3e56 | 6 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n============ DEPTH: 4 ==========================================\n004 4 213b 26d1 2434 2459 | 4 213b (0) 26d1 (0) 2434 (0) 2459 (0)\n005 0 | 0\n006 1 2a22 | 1 2a22 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","private_key":"976efa040e6f45cc8e22838f1bbfc9b811fa7841ca2c8092a7cc8e335815e92a","name":"node_286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","services":["bzz","pss"],"enable_msg_events":true,"port":33919},"up":true}},{"node":{"info":{"id":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","name":"node_621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","enode":"enode://dc01b24ab4982764516ace14b88809eb185560373dfbf6fcded5a81bd3fada53e0be683e0c468b1e836de13076e0ccac4e368e8c0946bf24d4390af626af29f1@127.0.0.1:0","enr":"0xf88fb84098e9b3ff2b11a0cacb15bf38a25b7cfe5b534459b7abf909c02314e31e17fd35658770c3cbabde925fb6d0d702842012518483cf082bfa9acb5cd08308a88da60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dc01b24ab4982764516ace14b88809eb185560373dfbf6fcded5a81bd3fada53","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YhB2zmuC5wyQpK3yNapvcbEW4wLdaxXcrgf0qBYBJFU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 621076\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ad0d a7a6 a085 957d | 63 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n001 2 0ff6 286a | 27 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n002 2 419a 4167 | 15 5abc (0) 5a01 (0) 5d60 (0) 517a (0)\n003 8 7cf4 7fbc 7f87 7b92 | 12 7355 (0) 734e (0) 73b8 (0) 757a (0)\n004 2 6982 6c82 | 6 6e5c (0) 6ecb (0) 6d60 (0) 6c02 (0)\n============ DEPTH: 5 ==========================================\n005 4 645b 667e 6728 6742 | 4 645b (0) 667e (0) 6728 (0) 6742 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","private_key":"7c196a80ce1002ecd7f34c4db3cc6862875ca81e18dff1b002bc566b0275f318","name":"node_621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","services":["bzz","pss"],"enable_msg_events":true,"port":45645},"up":true}},{"node":{"info":{"id":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","name":"node_ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","enode":"enode://d5dfcc59c4faaf151e2776e409ecb40fa62ba49cf62037b1857207692f6458d99e28f78a29bb3453d075d55c0a7b1574c3bae19e941395eabbb9934073eef2de@127.0.0.1:0","enr":"0xf88fb840314fdfeda295b7bdfcfa72520885849888dae3f5054cf13b02569d9d15272ec149953ca0fdab37be304e3c314f453a3aff78855724625541e7dbae0ac5a5aea10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d5dfcc59c4faaf151e2776e409ecb40fa62ba49cf62037b1857207692f6458d9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"68pRjlFG9JrHW8qordLvTR0ixc/S4jJsa0GCbUXOVa4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ebca51\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 13bc 7cf4 6982 6210 | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 6 957d 82f0 b381 b841 | 33 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n002 7 db08 d224 d0f3 ce99 | 15 dc97 (0) dfae (0) db08 (0) d6ff (0)\n003 5 f361 f360 f74e f5c4 | 5 f74e (0) f5c4 (0) f410 (0) f361 (0)\n004 3 e0b1 e55d e77f | 5 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n005 2 ed32 edc8 | 2 ed32 (0) edc8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 ea0e ea60 | 2 ea0e (0) ea60 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","private_key":"3d5e22365b5c9d1fdeb13d45cd12ef39ca2553f7d838ed915e74c428827504e0","name":"node_ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","services":["bzz","pss"],"enable_msg_events":true,"port":46379},"up":true}},{"node":{"info":{"id":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","name":"node_cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","enode":"enode://dc20237eda8fa674c764f707dd28b4c1e19ad46cbb7206be66d38eac7d630e4047f8dde066f6946ccef3c6b197e5b3b3a3dc60e0590ed7af75c63287f70a0a75@127.0.0.1:0","enr":"0xf88fb840af3cea3226ce0700aa6c6adfefb1f86b66df4dcfe207c13f42675d0f2375ea654d37d12e6bdfa169779ee5783787cc49c83bd4b25575dfe986252e7aff23216f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dc20237eda8fa674c764f707dd28b4c1e19ad46cbb7206be66d38eac7d630e40","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"y8XUKVG8bhhylrX4zk0E5HLiZnCmKFHznWXzHFCGX2o=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cbc5d4\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0ff6 06b9 0427 027f | 65 109e (0) 13bc (1) 1929 (0) 1be4 (0)\n001 6 92a1 b381 b16d b841 | 33 a75a (0) a7a6 (0) a2ba (0) a320 (0)\n002 3 f360 edc8 ebca | 15 f361 (0) f360 (0) f74e (0) f5c4 (0)\n003 4 dfae db08 d224 d0f3 | 6 dc97 (0) dfae (0) db08 (0) d6ff (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 4 cdcd cfbb ce99 cec3 | 4 cdcd (0) cfbb (0) ce99 (0) cec3 (0)\n============ DEPTH: 6 ==========================================\n006 1 c8e5 | 1 c8e5 (0)\n007 1 ca03 | 1 ca03 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","private_key":"b4f4e78aa0688362953df7a69f8c6cdf22151679efa7d71ae0d29d64348105e8","name":"node_cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","services":["bzz","pss"],"enable_msg_events":true,"port":38181},"up":true}},{"node":{"info":{"id":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","name":"node_7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","enode":"enode://1f9e2e5916cccc7c7134cfa950fd528992f3fe0cbfa44ca1ea2a878752c3e5841e41803494191b3e9009d2cfa0dc612e127490a75d21164eb4adca2514b011b6@127.0.0.1:0","enr":"0xf88fb84035545a7728c7f874e5cb8ed3369cfdc416e36f6462741040c8c5c6693860e0c6084d4da3f1318070c10b0958611e7fe3f63780cb689743695cbaf7f8bffbc4ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f9e2e5916cccc7c7134cfa950fd528992f3fe0cbfa44ca1ea2a878752c3e584","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fPSDinyDpzbOWc+huXRnSgGF2+F6jzzSl5Sju+gUre4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7cf483\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b486 ebca cbc5 | 63 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n001 4 3e56 0ff6 026d 06b9 | 27 109e (0) 13bc (0) 1929 (0) 1be4 (0)\n002 7 5d60 5776 4167 419a | 15 5a01 (0) 5abc (0) 5d60 (0) 539d (0)\n003 5 6210 645b 6742 6c82 | 11 6e5c (0) 6ecb (0) 6d60 (0) 6c02 (0)\n004 5 757a 772e 7639 73b8 | 6 7355 (0) 734e (0) 73b8 (0) 757a (0)\n005 2 78cb 7b92 | 2 7b92 (0) 78cb (0)\n============ DEPTH: 6 ==========================================\n006 2 7f87 7fbc | 2 7f87 (0) 7fbc (0)\n007 1 7dc5 | 1 7dc5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","private_key":"f8097f48d51332321d9d6d051a647bcc23dc5f6d3d90af68302348ec6554eb2c","name":"node_7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","services":["bzz","pss"],"enable_msg_events":true,"port":35111},"up":true}},{"node":{"info":{"id":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","name":"node_7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","enode":"enode://e828a02c476bfb4f9e77624db84d48a68fbe905c50586631faff90022af54eadba081aafe50144c86cb2d8c87f5da11a72f2824fd6e5fee8a4788b73232c0b06@127.0.0.1:0","enr":"0xf88fb840d7e722a5a02da1ba8ba198af44bd707ae67cb31ac9ba6bb979e42378114d7c467b0ae58de3699cd853cab121b1714bbeaa20692c31bf959346c9a2558080616a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e828a02c476bfb4f9e77624db84d48a68fbe905c50586631faff90022af54ead","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f7wYQ+IiLjyONaMhXRu7TVRX2LntM3SeB+IvJbqe5XY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7fbc18\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 ca03 c8e5 cfbb ce99 | 63 dc97 (0) dfae (0) db08 (0) d6ff (0)\n001 3 3e56 0ff6 06b9 | 27 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n002 3 4167 419a 41b9 | 15 5d60 (0) 5a01 (0) 5abc (0) 517a (0)\n003 4 6c82 6982 6210 6742 | 11 645b (0) 667e (0) 6728 (0) 6742 (0)\n004 4 772e 7639 7355 73b8 | 6 734e (0) 7355 (0) 73b8 (0) 757a (0)\n005 2 78cb 7b92 | 2 78cb (0) 7b92 (0)\n============ DEPTH: 6 ==========================================\n006 2 7dc5 7cf4 | 2 7dc5 (0) 7cf4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 7f87 | 1 7f87 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","private_key":"2a6bc25e58ea6c30639feb4e97a394af64178e6a42aaab9b082079c20f02434e","name":"node_7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","services":["bzz","pss"],"enable_msg_events":true,"port":40281},"up":true}},{"node":{"info":{"id":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","name":"node_86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","enode":"enode://160b7b02fe623f5d12e809600a6b47beeb4b30b2951dd67841739f40d54b98b2549eba0adfd40193ef0171a252a403d74752d6b9b7f68c89f18dda26437b2c59@127.0.0.1:0","enr":"0xf88fb8407c73d98812b302dac9f29fe48726b92a0dfa7517895f046594c3773f02a3e4e420da6443c739e51a2ccb79bfa2681764763bf1e4d8dcf515239dd132259941530183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103160b7b02fe623f5d12e809600a6b47beeb4b30b2951dd67841739f40d54b98b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hsoQeNrkDyOuGzrEc5dGDZ7AvyQ6DeNytAU4HWci/LI=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 86ca10\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4167 7fbc | 65 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n001 7 ea60 e77f d224 cec3 | 30 dc97 (0) dfae (0) db08 (0) d6ff (0)\n002 4 a085 a7a6 ad0d aebd | 17 a2ba (0) a320 (0) a085 (0) a75a (0)\n003 5 9ee7 9a92 9626 957d | 8 9a92 (0) 9d3c (0) 9e02 (0) 9ee7 (0)\n004 4 8cf9 895b 8b76 8be4 | 5 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n============ DEPTH: 5 ==========================================\n005 2 83dc 82f0 | 2 83dc (0) 82f0 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","private_key":"f6fd1d1772c650e60c41e06f59fc6bba67d5cc264f8fe14e6908e77e9c43f9e2","name":"node_86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","services":["bzz","pss"],"enable_msg_events":true,"port":46147},"up":true}},{"node":{"info":{"id":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","name":"node_4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","enode":"enode://a7bb630e0a99ad26a47f5bcf331536335c3e04dd4ffdbd27f229ec42dcc5eb7016e0e5f2cb8b3cf3489a317e161fdbc729703ba936b737ee2295a4b87f070e41@127.0.0.1:0","enr":"0xf88fb8402c97a2dc8b64057107147453b6c09e3c44ef973679e5658b0b6d0b2b187c4853555cb891d58dbfd328bb8cb83e55bad3c63f3fb185644e4684308ee0bc87b7550183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a7bb630e0a99ad26a47f5bcf331536335c3e04dd4ffdbd27f229ec42dcc5eb70","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QWeUbeJQsBPhvhbuhL/izKroPmmeYYs48xAWxOQx5ro=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 416794\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f410 86ca | 63 dfae (0) dc97 (0) db08 (0) d6ff (0)\n001 4 13bc 0ff6 018a 06b9 | 27 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n002 13 7b92 78cb 7cf4 7f87 | 23 645b (0) 667e (0) 6728 (0) 6742 (0)\n003 3 5a01 539d 5776 | 7 5d60 (0) 5abc (0) 5a01 (0) 517a (0)\n004 4 4b24 4a18 48b6 4cd0 | 4 4b24 (0) 4a18 (0) 48b6 (0) 4cd0 (0)\n005 1 47c3 | 1 47c3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 2 41b9 419a | 2 41b9 (0) 419a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","private_key":"2e633e4e9e522151a2b2bd98030f66cd31b2e81feb8ab86004b194a703e3fb86","name":"node_4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","services":["bzz","pss"],"enable_msg_events":true,"port":42087},"up":true}},{"node":{"info":{"id":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","name":"node_f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","enode":"enode://df462c25ee8bcaf3bcfd05af911c6466c62d31175cf9c44288595b39729d64e7a2e81626fe01bc61b0036fbf2dadb271171e7e9c6812214526b2f1c83e6c5881@127.0.0.1:0","enr":"0xf88fb8404a32ca40db377ce80d0e646c9643936683374ce6e8ec14963aae37672d13490f2f06bf8861a4b5f426b9f70eb96e75389076f3d92ce641abc9191a362c185bb00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df462c25ee8bcaf3bcfd05af911c6466c62d31175cf9c44288595b39729d64e7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9BDUrJt0jCT6DUjDBTuxzqimfQvMTl/L2yYcDHUizDQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f410d4\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 3ee4 0ff6 06b9 0427 | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 5 b381 a7a6 82f0 957d | 33 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n002 2 ca03 d224 | 15 dc97 (0) dfae (0) db08 (0) d6ff (0)\n003 4 e16b e77f ea60 ebca | 10 e16b (0) e0b1 (0) e0ea (0) e55d (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 f361 f360 | 2 f361 (0) f360 (0)\n006 1 f74e | 1 f74e (0)\n007 1 f5c4 | 1 f5c4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","private_key":"a9a777290064b28ab9e2bd8edfcf9cf14e40ba8fb169ba18ec322bebd1e9796c","name":"node_f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","services":["bzz","pss"],"enable_msg_events":true,"port":46863},"up":true}},{"node":{"info":{"id":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","name":"node_92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","enode":"enode://d4f739677902ad2701144cab8f87489253d25aeda47e8ed5817e4562ddaae678ffe9c52f8716f132ce74f96161ed770ccc5627a11dca2ea4024b49b8a6054f11@127.0.0.1:0","enr":"0xf88fb8400fb72975a9f5e05d571cc9bc2a2acf555ccd87f5b870d76b312c9964b17f7bc45382dd2fc4e0c93ff5987f761bc2e9faa304c2be53ed8588128a89d0b881c5750183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d4f739677902ad2701144cab8f87489253d25aeda47e8ed5817e4562ddaae678","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kqFQHtQeKbt92OtLSs7K6YP0x8g/OYlc1o94ELZF8d0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 92a150\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7b92 7639 419a | 65 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n001 8 d224 d0f3 ca03 cbc5 | 30 c181 (0) c3a1 (0) cdcd (0) cfbb (0)\n002 3 afa3 a7a6 b841 | 17 a320 (0) a2ba (0) a085 (0) a75a (0)\n003 3 8be4 86ca 82f0 | 8 83dc (0) 82f0 (0) 86ca (0) 8cf9 (0)\n004 4 9a92 9d3c 9e02 9ee7 | 4 9d3c (0) 9e02 (0) 9ee7 (0) 9a92 (0)\n============ DEPTH: 5 ==========================================\n005 2 9626 957d | 2 9626 (0) 957d (0)\n006 1 91eb | 1 91eb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","private_key":"d99269d5a3d87afd088aa258ab85c5ee8f988fdd019689f5f639b1e488b7abae","name":"node_92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","services":["bzz","pss"],"enable_msg_events":true,"port":43101},"up":true}},{"node":{"info":{"id":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","name":"node_b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","enode":"enode://8df6b1e4435d4b72ae0f6dcda1002d86349ac28a9b9a182692a0fd2cb5f10255b8f960fddb898e957a04daa3a6b3f6aa6ef97bed544b4b99ad81edff6707d20f@127.0.0.1:0","enr":"0xf88fb840b8517e545b313545c0b7003080e9c0b7e74c291b272d1e018dc8684a4ca24bcc4f7af3c9997eb09cf50e46161d175a929d29372f4a73ec5cb21e06b0c6d0146e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038df6b1e4435d4b72ae0f6dcda1002d86349ac28a9b9a182692a0fd2cb5f10255","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uEEfGY/WWMWiAog1wK8zQhRYOcBsik84LZ+d5IXUbAg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8411f\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 06b9 419a 73b8 | 65 5a01 (0) 5abc (0) 5d60 (0) 5776 (0)\n001 6 db08 cbc5 e77f e55d | 30 f74e (0) f410 (0) f5c4 (0) f361 (0)\n002 6 82f0 8be4 9d3c 9ee7 | 16 83dc (0) 82f0 (0) 86ca (0) 8cf9 (0)\n003 5 a7a6 a085 ad0d afa3 | 9 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n004 4 b486 b16d b381 b2b9 | 5 b70e (0) b486 (0) b16d (0) b381 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 b92a | 1 b92a (0)\n008 1 b8e1 | 1 b8e1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","private_key":"949877f6e6d76788923054b7bd6526b9001f04a77df87bc9161352dc5453e5bc","name":"node_b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","services":["bzz","pss"],"enable_msg_events":true,"port":33251},"up":true}},{"node":{"info":{"id":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","name":"node_8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","enode":"enode://fc32bff950e71029ffb87f1cd11cd8b80e17e8a1bb87da502f53a1ce59ae43cfe17583075dd14d54a9e2e5f0a45ea7a7e66a3ef496ff5fbe5170bb5cf2c94b21@127.0.0.1:0","enr":"0xf88fb840c686f651105296aa062d5461136529224697c9783747504a33939d92f192c56e1b9b95e2c2493d32ede538f135f81cc3e3ec89f91ba1d068c056c407c775d30c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fc32bff950e71029ffb87f1cd11cd8b80e17e8a1bb87da502f53a1ce59ae43cf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"i+RhID9eu1chNI9TezfXaPe9NZrz4Y0ffpry+QHEmEU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8be461\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 419a 7b92 73b8 | 65 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n001 6 ea60 e77f f360 c8e5 | 30 f74e (0) f5c4 (0) f410 (0) f361 (0)\n002 5 a7a6 ad0d afa3 aebd | 17 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n003 5 9d3c 9ee7 9a92 92a1 | 8 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n004 3 86ca 83dc 82f0 | 3 86ca (0) 83dc (0) 82f0 (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 89c8 895b | 2 89c8 (0) 895b (0)\n007 0 | 0\n008 1 8b76 | 1 8b76 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","private_key":"0f6530f636582633a6311f48aa9d253eab18b87cbebe43f367a159aa3c241c46","name":"node_8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","services":["bzz","pss"],"enable_msg_events":true,"port":45015},"up":true}},{"node":{"info":{"id":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","name":"node_aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","enode":"enode://f282cd19ae6a9df87585322507e574bc32df4841972dd882a9a05870050a1b598c8fc33af74f96a6420a9880385812d048ace508f80750a8de0cb24c56212d78@127.0.0.1:0","enr":"0xf88fb84031ffcecf6c8f21aa2106e8d9bbdaa2414c925860a95299b3ade0ebacc68255dc2f7eb3419664abbd0c8819f34be4a3452dfb3fdd59dd7c81c6133f3c7b98d96b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f282cd19ae6a9df87585322507e574bc32df4841972dd882a9a05870050a1b59","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rr1hNdECUrB/iRs6czCQP68T1AnE9xCGMHFfoHVPk44=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aebd61\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 3e56 3ee4 13bc 0ff6 | 65 018a (0) 0390 (0) 0218 (0) 026d (0)\n001 5 f360 e77f ebca d224 | 30 f74e (0) f5c4 (0) f410 (0) f361 (0)\n002 5 9d3c 9ee7 82f0 86ca | 16 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n003 3 b841 b2b9 b381 | 8 b70e (0) b486 (0) b16d (0) b381 (0)\n004 4 a7a6 a320 a2ba a085 | 5 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 ad0d | 1 ad0d (0)\n007 1 afa3 | 1 afa3 (0)\n008 1 ae67 | 1 ae67 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","private_key":"1052de44bfe98977c2f57b1304d18f99ad509385a540c598539f43a9fd01a076","name":"node_aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","services":["bzz","pss"],"enable_msg_events":true,"port":32913},"up":true}},{"node":{"info":{"id":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","name":"node_4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","enode":"enode://26c256c0419d8280c23d163c3dada761578f80e066c614882b6efe25eb4b5d9e06e50aa77e5306508227275d3ad527fc67dca7f4c3066a7e89e5b7d0b48cf106@127.0.0.1:0","enr":"0xf88fb840d136e30739a296b8258bac9b8c021058e3b129b00b86eefcae768e963d71000d436fb91ca2511d958b15dbd33372cf80dd57a8b2d6439fd1a7a261f5d8d66feb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10226c256c0419d8280c23d163c3dada761578f80e066c614882b6efe25eb4b5d9e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TNDzjlKlCPgc+V4TcMmUrqLXpJoqCOPgVPU2KaZhlBA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4cd0f3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b2b9 b381 aebd | 63 f74e (0) f5c4 (0) f410 (0) f361 (0)\n001 7 13bc 0ff6 0bcf 027f | 27 018a (0) 0390 (0) 0218 (0) 026d (0)\n002 9 6728 6742 6ecb 6982 | 23 757a (0) 772e (0) 7639 (0) 734e (0)\n003 2 5a01 539d | 7 558e (0) 5776 (0) 517a (0) 539d (0)\n004 4 47c3 4167 41b9 419a | 4 47c3 (0) 4167 (0) 41b9 (0) 419a (0)\n============ DEPTH: 5 ==========================================\n005 3 4a18 4b24 48b6 | 3 4a18 (0) 4b24 (0) 48b6 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","private_key":"bc76c03a436db84839741888c68b1cdddedd194bc0c48dd035a5b8fce7fa6f2b","name":"node_4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","services":["bzz","pss"],"enable_msg_events":true,"port":38223},"up":true}},{"node":{"info":{"id":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","name":"node_2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","enode":"enode://d7f147b4838d04a590e69acd66b2f879e2de85f8607e998c3e8c35841145bbe75feb3b9a00e5c33fe2185506151da35ab450699981b512c4dcf86ec22e5538e6@127.0.0.1:0","enr":"0xf88fb8400f37b8427aa3076dbc1caa48263b9df3bc54fe10fadece63d56c92ecd89cbe31074c7a98aa40bbd3a1d5adf1c59ce9dbf534f2d891b802986e99ee22585328ec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d7f147b4838d04a590e69acd66b2f879e2de85f8607e998c3e8c35841145bbe7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JFn+klCzMRyGUw0At6m4ulextRUcEmJi5wxV0ejTeSQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2459fe\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 a085 afa3 ea60 cec3 | 63 e0b1 (0) e0ea (0) e16b (0) e77f (0)\n001 11 757a 7639 7355 7b92 | 38 757a (0) 772e (0) 7639 (0) 734e (0)\n002 7 0bcf 0ff6 0427 06b9 | 15 0506 (0) 0427 (0) 06b9 (0) 018a (0)\n003 5 372d 38ab 3cb1 3ee4 | 6 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n004 2 2a22 286a | 2 2a22 (0) 286a (0)\n005 1 213b | 1 213b (0)\n============ DEPTH: 6 ==========================================\n006 1 26d1 | 1 26d1 (0)\n007 0 | 0\n008 0 | 0\n009 1 2434 | 1 2434 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","private_key":"4c8204f3f41c8735aa70c249cbaa8f57ea41b39b651490de8de8c12fd2691eaa","name":"node_2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","services":["bzz","pss"],"enable_msg_events":true,"port":37643},"up":true}},{"node":{"info":{"id":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","name":"node_698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","enode":"enode://d6a014202d01536e4928ed4efbe17f6d6a7fa8fc624bafce75e43cd1f25f6aeb2a474087e08c4e0b49a38a5e4486fa8c08092f00164df92082dec0fbd9834433@127.0.0.1:0","enr":"0xf88fb840151b4bf6e849b0ac2ec218151f8dfa803c5b5d34733bf46e1c711e9d2ba90c6c6a9084cf38dcd6cc4ccc77d3aa6b062ad0ccd53666db1de1d30ace82ce35afb10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d6a014202d01536e4928ed4efbe17f6d6a7fa8fc624bafce75e43cd1f25f6aeb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aYJH0QOokl2LtMVqMFbknF78WV/O0cidSZQ7uboB85Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 698247\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 cbc5 ca03 c8e5 c3a1 | 63 e0ea (0) e0b1 (0) e16b (0) e77f (0)\n001 2 3ee4 2459 | 27 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n002 4 4167 419a 4cd0 48b6 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 10 7639 7355 734e 73b8 | 12 757a (0) 772e (0) 7639 (0) 734e (0)\n004 3 6210 6728 6742 | 5 6210 (0) 645b (0) 667e (0) 6728 (0)\n============ DEPTH: 5 ==========================================\n005 5 6e5c 6ecb 6d60 6c82 | 5 6e5c (0) 6ecb (0) 6c82 (0) 6c02 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","private_key":"20311624a5a56cae7a90aedb142273ff36c5f5d52598fa621d5e388c078ca94f","name":"node_698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","services":["bzz","pss"],"enable_msg_events":true,"port":40773},"up":true}},{"node":{"info":{"id":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","name":"node_6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","enode":"enode://84717a6835e106aad3b6c055224217d5d064ac8909100b55eaabc37dc20949be1f33a3b838405bcd5e71cbfbb69170d21ff07952aab37534f965efccaf979d50@127.0.0.1:0","enr":"0xf88fb840d2f711c921f221581b2944e9166c506e85656605df5d204f343f836509260aa24240127b85cb3cf9945ddb9030e85db8e5e6f393b31b1b7cda2cd36a8eeda4110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10284717a6835e106aad3b6c055224217d5d064ac8909100b55eaabc37dc20949be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z0LMobd4P8vtjQs0BQj5PMTfrKj/PxP9WTVEhsTWKZM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6742cc\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b2b9 b381 957d 82f0 | 63 ed32 (0) edc8 (0) ea60 (0) ea0e (0)\n001 2 26d1 13bc | 27 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n002 5 539d 4167 4cd0 4b24 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 9 7639 734e 7355 73b8 | 12 757a (0) 772e (0) 7639 (0) 734e (0)\n004 3 6d60 6c82 6982 | 6 6e5c (0) 6ecb (0) 6c02 (0) 6c82 (0)\n005 1 6210 | 1 6210 (0)\n006 1 645b | 1 645b (0)\n============ DEPTH: 7 ==========================================\n007 1 667e | 1 667e (0)\n008 0 | 0\n009 1 6728 | 1 6728 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","private_key":"0cb73f4cde658fd3ac83b434133145d5fbd0bf4f9ab6e3923171d443eba90568","name":"node_6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","services":["bzz","pss"],"enable_msg_events":true,"port":40229},"up":true}},{"node":{"info":{"id":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","name":"node_82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","enode":"enode://e8117dddd5f5e8f212dbd7147bd8bf02068ddb0e94123d323731d22a7f0103610057f6ae1a76d6442bef79f3ae52f0faf62c535b759ee126461f402b83ba45bd@127.0.0.1:0","enr":"0xf88fb840d046f5dff4971dc895e66458c436e6e3a27c96b8d53df7b3b9ad0e77f4345ed32a7b206c7a3d662fd18b0f7a404a7dc243abbdc9a8a677f9973dd2b99af279ff0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e8117dddd5f5e8f212dbd7147bd8bf02068ddb0e94123d323731d22a7f010361","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gvA024j9JrR8JrlcP4eh9FT/5FJq6GvrK7HY8sIYwlw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82f034\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6982 6742 | 65 06b9 (0) 0506 (0) 0427 (0) 018a (0)\n001 9 f360 f410 f5c4 ebca | 30 e77f (0) e55d (0) e0ea (0) e0b1 (0)\n002 9 a085 a2ba ad0d aebd | 17 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n003 7 9a92 9ee7 9e02 9d3c | 8 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n004 5 8cf9 89c8 895b 8b76 | 5 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n============ DEPTH: 5 ==========================================\n005 1 86ca | 1 86ca (0)\n006 0 | 0\n007 1 83dc | 1 83dc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","private_key":"c43af8c1c17ec355ac7f8bef6f05ba9db12db47c9e201a266d0d65065798ba3c","name":"node_82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","services":["bzz","pss"],"enable_msg_events":true,"port":33523},"up":true}},{"node":{"info":{"id":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","name":"node_b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","enode":"enode://a22d89dcb4290953d158b22c35c5c68eeb5e11220f22b58314ba70f7fc2b7603b7c6e1ff81f0dd1b53230d0a89eab8629e5629a51e8933fa5561cf04542b202a@127.0.0.1:0","enr":"0xf88fb8400a3de612482002f22886dbd86e19870d74873631d82f29687df78027690518e16dc049dcbcfbe0ea0984b62dd97074247757a9c4675a87c49da61843ca343e2d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a22d89dcb4290953d158b22c35c5c68eeb5e11220f22b58314ba70f7fc2b7603","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"srmsD021iIZZevexnWFQSYrIrXyARnFiiqNDhLj+UF4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2b9ac\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 6d60 6742 6728 667e | 65 5d60 (0) 5abc (0) 5a01 (0) 558e (0)\n001 2 f5c4 d224 | 30 ed32 (0) edc8 (0) ea60 (0) ea0e (0)\n002 5 91eb 9d3c 9ee7 9a92 | 16 9ee7 (0) 9e02 (0) 9d3c (0) 9a92 (0)\n003 6 a75a a085 a2ba ad0d | 9 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n004 3 b92a b8e1 b841 | 3 b92a (0) b8e1 (0) b841 (0)\n005 2 b486 b70e | 2 b486 (0) b70e (0)\n============ DEPTH: 6 ==========================================\n006 1 b16d | 1 b16d (0)\n007 1 b381 | 1 b381 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","private_key":"468f3a0090d15106e770801e7f4f0fc26bf78d3698be131eb3585ca410116084","name":"node_b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","services":["bzz","pss"],"enable_msg_events":true,"port":42099},"up":true}},{"node":{"info":{"id":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","name":"node_3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","enode":"enode://4b65a104001fb3c5edd9eb6477d5e7daca674195a347fa8deb71a83931f3475569a6ee580c248b2243c09b8787be153f817ee6b282fb0572424fa91c9243ffb6@127.0.0.1:0","enr":"0xf88fb8409d8ea451f2658de612662bd9b07a86cb819f781fa9d8f8e1350199a2666dae1d498b271416d9b6f88a3f0468d2f2971a017e78e789d14596d7ca1b56365597d10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024b65a104001fb3c5edd9eb6477d5e7daca674195a347fa8deb71a83931f34755","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PlbUUz7BT2ZW4esl+zXa1HydtHn2Z6a2/po6qMEumC4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3e56d4\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ea60 d224 a085 aebd | 63 ed32 (0) edc8 (0) ea0e (0) ea60 (0)\n001 6 48b6 6c82 7639 7fbc | 38 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n002 5 0427 0ff6 0bcf 1929 | 15 06b9 (0) 0506 (0) 0427 (0) 018a (0)\n003 4 2a22 286a 26d1 2459 | 6 2a22 (0) 286a (0) 213b (0) 2434 (0)\n004 1 372d | 1 372d (0)\n005 2 39db 38ab | 2 39db (0) 38ab (0)\n============ DEPTH: 6 ==========================================\n006 1 3cb1 | 1 3cb1 (0)\n007 0 | 0\n008 1 3ee4 | 1 3ee4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","private_key":"3934a1eb89e5d3bd316aca133dcf3e380fe237373fdc981c7d7c138612ca06c2","name":"node_3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","services":["bzz","pss"],"enable_msg_events":true,"port":44945},"up":true}},{"node":{"info":{"id":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","name":"node_7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","enode":"enode://f8572034b7fc585c1903d4bb5879cf1ffbac94cbc1897edfe98d9b9f84d93d26b67f2abeb88ce77608ed262152ac3840f448f26a5a61afa46eea388e2f4b7a42@127.0.0.1:0","enr":"0xf88fb8400e94e52c2270cce5bdd17883b40ecc21d4ec6157af03e3c97775e38e6fc0370d63efe0aae8270863a14fb499442bdd706b616fb6843938b664eb2f43ba9fce8f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f8572034b7fc585c1903d4bb5879cf1ffbac94cbc1897edfe98d9b9f84d93d26","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e5JCE3+Mwr7Hs+AAP9kwJpIc6xDfrbvVtqpk1hp0814=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7b9242\npopulation: 48 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 8be4 8cf9 957d 9626 | 63 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n001 14 13bc 0ab9 0bcf 0ff6 | 27 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n002 3 4167 48b6 4cd0 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 9 6982 6d60 6c02 6e5c | 11 6210 (0) 645b (0) 667e (0) 6728 (0)\n004 6 7639 772e 757a 734e | 6 757a (0) 772e (0) 7639 (0) 734e (0)\n============ DEPTH: 5 ==========================================\n005 4 7cf4 7dc5 7f87 7fbc | 4 7f87 (0) 7fbc (0) 7cf4 (0) 7dc5 (0)\n006 1 78cb | 1 78cb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","private_key":"5a6b556ff9b73fe0850c45f469fbfd6e6f0d2d5af3f3831f4376a08b8ca8a549","name":"node_7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","services":["bzz","pss"],"enable_msg_events":true,"port":39179},"up":true}},{"node":{"info":{"id":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","name":"node_73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","enode":"enode://14b035995d987becf991740865f7caa23bad70978a889984199627036686ab81a14519d760274790b6bacf5268d2e469987a4470aae895019e00d2d43d366278@127.0.0.1:0","enr":"0xf88fb84057f0098ffc99b981a4c2b43591db40bfbc63ac9be4c3abecc42ba157711a2e2a7c925f830e8fa6b04074eea3c2c534df67e40efc15f1bb75348fbed8d0d468870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10214b035995d987becf991740865f7caa23bad70978a889984199627036686ab81","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c7jRhA0Kj/5pdS7Jb4/d7LDiJybIeYLVcsqazByc2/w=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 73b8d1\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8be4 b841 d6ff d224 | 63 9ee7 (0) 9e02 (0) 9d3c (0) 9a92 (0)\n001 3 3ee4 0bcf 13bc | 27 06b9 (0) 0427 (0) 0506 (0) 0390 (0)\n002 4 419a 4167 48b6 4cd0 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 6 6ecb 6982 667e 6728 | 11 6210 (0) 645b (0) 667e (0) 6728 (0)\n004 6 7dc5 7cf4 7f87 7fbc | 6 7f87 (0) 7fbc (0) 7cf4 (0) 7dc5 (0)\n005 3 772e 7639 757a | 3 772e (0) 7639 (0) 757a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 2 734e 7355 | 2 734e (0) 7355 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","private_key":"29694c9dcdcbd8510814aabcc1c9a32e23b92f4596464ba205244a4954cc0595","name":"node_73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","services":["bzz","pss"],"enable_msg_events":true,"port":36127},"up":true}},{"node":{"info":{"id":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","name":"node_d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","enode":"enode://235360aff6df4553e2efa53a861609209743e1ea81cd07f7bcbe80ae9fbf012a2caca09eb6dbac7be69d14d3805a552d18a626a6e5356659180c8d804f7f7ee3@127.0.0.1:0","enr":"0xf88fb840f7e66d84700fe9e82cd1cdeca1acbb2242b09a69b0e50173bac5c41180f1f8d14138152b7755e0228ce2d6b526c3c01bdddaabf90a2a856f715944f373533aef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103235360aff6df4553e2efa53a861609209743e1ea81cd07f7bcbe80ae9fbf012a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0iRfBnm0NvqrwBZOC4XgLi7/utMG6CKbVVUkpebRpfk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d2245f\npopulation: 43 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 286a 2459 3ee4 3e56 | 65 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n001 12 895b 8be4 86ca 82f0 | 33 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n002 5 ebca ea60 e16b f5c4 | 15 e55d (0) e77f (0) e0ea (0) e0b1 (0)\n003 9 c181 c3a1 c8e5 ca03 | 9 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n004 3 db08 dfae dc97 | 3 dfae (0) dc97 (0) db08 (0)\n============ DEPTH: 5 ==========================================\n005 1 d6ff | 1 d6ff (0)\n006 1 d0f3 | 1 d0f3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","private_key":"658311d7ee69a3bf84aa43c15ac573ea72807a5e080c322310e7bc701ab52fab","name":"node_d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","services":["bzz","pss"],"enable_msg_events":true,"port":38759},"up":true}},{"node":{"info":{"id":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","name":"node_b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","enode":"enode://b72f0a95514b0161e67d4b36b1dc91cb319117d3f1c34731bb2c685769f11741575d3c41f4c1c8188b85f47c62b149e4f3e5f72394ebc5780c85c06528570c33@127.0.0.1:0","enr":"0xf88fb84012121d864e031d97c287200a10956bbe49c61b0fcb145897fa0a4a0da21a317d48aff38a1901706b29ce01ec8bc17ee9be0c1764a516acafc5cd40048dfe61690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b72f0a95514b0161e67d4b36b1dc91cb319117d3f1c34731bb2c685769f11741","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s4HnXlLkzdFoBWJF+C06F0e2f0AOtA6xIDa3Puf+IeU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b381e7\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0ff6 6742 48b6 4cd0 | 65 558e (0) 5776 (0) 517a (0) 539d (0)\n001 13 f5c4 f410 f360 ebca | 30 e77f (0) e55d (0) e0ea (0) e0b1 (0)\n002 5 82f0 9d3c 9ee7 91eb | 16 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n003 7 a7a6 a75a a2ba a085 | 9 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n004 3 b8e1 b841 b92a | 3 b92a (0) b8e1 (0) b841 (0)\n005 2 b486 b70e | 2 b486 (0) b70e (0)\n============ DEPTH: 6 ==========================================\n006 1 b16d | 1 b16d (0)\n007 1 b2b9 | 1 b2b9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","private_key":"78a74e69c0e211af6e3f2806e5cf0475ccdb1b5ccfba14e1968b82747e20be0a","name":"node_b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","services":["bzz","pss"],"enable_msg_events":true,"port":44485},"up":true}},{"node":{"info":{"id":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","name":"node_957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","enode":"enode://61d644b51f9244f36e197d9d614070a5487f071bc7c7753d43edb80f72e5a2c43cda36d5b2f9f070228bb54c8810c5789af96b66be77a6df61aabfffe5da4c8f@127.0.0.1:0","enr":"0xf88fb840d573110433511ff59f78b0fe666d311957c43ee0f9ef6c673d1f53736e1d4b9f6c77c5620e6c97f670e61f3e1d83f77ce36c004b9587fb9ddd3bcc8486e455320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10361d644b51f9244f36e197d9d614070a5487f071bc7c7753d43edb80f72e5a2c4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lX2Km0Erb0zRUcvAe4102UmICuZlxUXeuxgYE4nJnuY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 957d8a\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7b92 6ecb 6d60 6742 | 65 6210 (0) 645b (0) 667e (0) 6742 (0)\n001 13 f5c4 f410 f360 e0ea | 30 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n002 2 b92a b381 | 17 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n003 3 8be4 86ca 82f0 | 8 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n004 4 9a92 9e02 9ee7 9d3c | 4 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n============ DEPTH: 5 ==========================================\n005 2 92a1 91eb | 2 91eb (0) 92a1 (0)\n006 1 9626 | 1 9626 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","private_key":"9cbb036a358368a04ab266b8fd487e4bcfead509da1f1d57b0e7fa3db574c99c","name":"node_957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","services":["bzz","pss"],"enable_msg_events":true,"port":46189},"up":true}},{"node":{"info":{"id":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","name":"node_26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","enode":"enode://1999562f9de6c42f0577c494aec14691db3aec49ed40e75ea9eedb72e5295d9d0d659f4991946f9fbacc74feaeb5e5181dc23ba10299dd01ec1dec9c00d84ad1@127.0.0.1:0","enr":"0xf88fb84017d136a2bd2b8c6b071ea759278494f6636844e06c788ffe4eff0e1226cd0b0864d646c596173bbf67bc7403a5623bcd2d044273ed7d5c0efbeee8916cc39cc70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031999562f9de6c42f0577c494aec14691db3aec49ed40e75ea9eedb72e5295d9d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JtGvH77mVBo2PqdweCXjfaAoFC8Ad5EWVgrSDx3hjns=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26d1af\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 e16b d0f3 a085 89c8 | 63 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n001 8 4b24 48b6 6742 6728 | 38 6210 (0) 645b (0) 667e (0) 6742 (0)\n002 7 13bc 1929 06b9 0390 | 15 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n003 5 372d 39db 3cb1 3e56 | 6 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n004 2 286a 2a22 | 2 286a (0) 2a22 (0)\n005 1 213b | 1 213b (0)\n============ DEPTH: 6 ==========================================\n006 2 2434 2459 | 2 2434 (0) 2459 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","private_key":"7e2c84991a191ba4057e485ef2cfc2020c5ccac17ccaace8db0733f7bea4b410","name":"node_26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","services":["bzz","pss"],"enable_msg_events":true,"port":44455},"up":true}},{"node":{"info":{"id":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","name":"node_3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","enode":"enode://5c685dacbd760c9d05b018f58ac52239966ab2c181ec106125ebad06ab336c7cc4087f4f32a38e9b17edcabd74afe7fd36bbd33e12542ca0646b98bd7e11d489@127.0.0.1:0","enr":"0xf88fb84065e447a80639420887319bbbd8ff453a67c8f00fa8ddcbbbf04b02d24240226a600ae407deabfe11ae74c2b0dc46e86f08d9f08d4d77a1df3e3f3f41dacd5ac10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035c685dacbd760c9d05b018f58ac52239966ab2c181ec106125ebad06ab336c7c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PuSyDAR+cBtYwG/MgWA2S9KVc/YfTZ8ZNdd6wp9qHoY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3ee4b2\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 89c8 a085 aebd ae67 | 63 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n001 8 5776 47c3 7639 73b8 | 38 6d60 (0) 6c82 (0) 6c02 (0) 6e5c (0)\n002 9 0ab9 0bcf 0427 06b9 | 15 0506 (0) 0427 (0) 06b9 (0) 018a (0)\n003 3 286a 2459 26d1 | 6 286a (0) 2a22 (0) 213b (0) 2434 (0)\n004 1 372d | 1 372d (0)\n005 2 39db 38ab | 2 39db (0) 38ab (0)\n============ DEPTH: 6 ==========================================\n006 1 3cb1 | 1 3cb1 (0)\n007 0 | 0\n008 1 3e56 | 1 3e56 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","private_key":"452609d27fac9e357776f968c4726676474f4f5fdc9da0bf89f6362b3ba19ff2","name":"node_3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","services":["bzz","pss"],"enable_msg_events":true,"port":41679},"up":true}},{"node":{"info":{"id":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","name":"node_13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","enode":"enode://6016e452462a437136ffaab5816dde72ff1910f4a456f38c172033a88cc4e204cd4c199e769f890c78f4db86f19416a9522fdeb434384eedc3c2f1ef28b88acc@127.0.0.1:0","enr":"0xf88fb840149fc3c3a63d0f1305a848030d0a2b93385095eec084ca87fb44428c87d118f37da0a3ca28e3f65c085d3befbc01cbe7cf22d90d1d9ed4df2d4ae92c6c4245dc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026016e452462a437136ffaab5816dde72ff1910f4a456f38c172033a88cc4e204","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E7xkU1065JUJjkrGswqR0YBNqwq3mUTyxqxTybzN9i0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 13bc64\npopulation: 40 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 cec3 c3a1 f5c4 f410 | 63 ed32 (0) edc8 (0) ea0e (0) ea60 (0)\n001 8 4cd0 4b24 4167 7b92 | 38 7639 (0) 772e (0) 757a (0) 73b8 (0)\n002 5 2a22 26d1 2459 3e56 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 11 0ff6 0ab9 0bcf 0427 | 11 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n============ DEPTH: 4 ==========================================\n004 2 1be4 1929 | 2 1be4 (0) 1929 (0)\n005 0 | 0\n006 1 109e | 1 109e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","private_key":"8434ae4dfa2723b5719768bc711f7425c5bd0924b3b0ec5d8cc2c9b399b5766a","name":"node_13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","services":["bzz","pss"],"enable_msg_events":true,"port":40705},"up":true}},{"node":{"info":{"id":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","name":"node_9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","enode":"enode://b7082416512639ee57846e95b5e2dbc63995f361401c3b313732cf2d3d033441790dce7c2460efd7937015b4638e6247ed82c823aa0802925c366c91ae09e68b@127.0.0.1:0","enr":"0xf88fb84099372399c4d3fd5cadf0c624920ed74d76194f722b61996a6a6c99fbce6110170e82d7b4d993a5850e772df12e975549b3191f0cf7f6abae21e9a136f6bff1cc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b7082416512639ee57846e95b5e2dbc63995f361401c3b313732cf2d3d033441","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mpIws/fzhlIIId7njr6S6MZKT2pQ8mOTJ8YuRcq0BWM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9a9230\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7b92 7355 39db 13bc | 65 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n001 2 e16b f5c4 | 30 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n002 6 ad0d a75a b70e b2b9 | 17 b92a (0) b8e1 (0) b841 (0) b486 (0)\n003 6 83dc 82f0 86ca 8cf9 | 8 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n004 4 92a1 91eb 957d 9626 | 4 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n============ DEPTH: 5 ==========================================\n005 3 9ee7 9e02 9d3c | 3 9ee7 (0) 9e02 (0) 9d3c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","private_key":"e878354e1d0c9956e28fa14cdc5a61945f6f2b2fbea9a8367dbe5f064b174592","name":"node_9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","services":["bzz","pss"],"enable_msg_events":true,"port":35207},"up":true}},{"node":{"info":{"id":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","name":"node_9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","enode":"enode://4faf10bd09731418ac192c8a57f170f322ffe575d3a2ee2efafec45fb7da6fd3712457dd5a78fd5e1a2efa1003715aea87cca4d49b10fd1d3845b72435b8ee4c@127.0.0.1:0","enr":"0xf88fb84082c3796decac811025287334946817180d001c3d8d7721d3971aa9cb879fed0c0acd50bf82c7fa565e2540bef5f1b5731accc7b6a4c70ebe972111d0deda6a8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024faf10bd09731418ac192c8a57f170f322ffe575d3a2ee2efafec45fb7da6fd3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nTx55KCsTluVqjJUXzuNhvdFlPqiN9XCVmzwL71gsRo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9d3c79\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 7b92 0bcf 0ab9 018a | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 2 e16b cfbb | 30 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n002 11 b16d b381 b2b9 b70e | 17 b92a (0) b8e1 (0) b841 (0) b486 (0)\n003 5 8cf9 8be4 895b 83dc | 8 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n004 4 91eb 92a1 9626 957d | 4 92a1 (0) 91eb (0) 9626 (0) 957d (0)\n005 1 9a92 | 1 9a92 (0)\n============ DEPTH: 6 ==========================================\n006 2 9e02 9ee7 | 2 9ee7 (0) 9e02 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","private_key":"907b7ec9e8b65f1de5310f5964f2c97a21a13adf1c0b9e8a4cb0ba38c73dc24c","name":"node_9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","services":["bzz","pss"],"enable_msg_events":true,"port":37201},"up":true}},{"node":{"info":{"id":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","name":"node_a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","enode":"enode://3699407c49116a8a7ddb656a1e7e586838f3e72cfdf9cd942b81adc4fa745f01cf3dd9f2682d44deb8172544a05e86055f3cae6822aa14e3b98a5870a259ad33@127.0.0.1:0","enr":"0xf88fb840de466b2eda8d1345b19b33da7313d03db5548f84b7f7d728a6a1346a44e29bfe6b37764e639f35270f9df761fdeffb3207f2c4716c87d65a25d30afdff134a5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033699407c49116a8a7ddb656a1e7e586838f3e72cfdf9cd942b81adc4fa745f01","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oIUEXDNc4uR9vf6xrbYs5sO+02qTzzRIxFdXoaiOKV0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a08504\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 109e 3ee4 3e56 3cb1 | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 3 d224 e16b f5c4 | 30 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n002 3 82f0 86ca 9d3c | 16 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n003 5 b92a b841 b70e b2b9 | 8 b8e1 (0) b841 (0) b92a (0) b486 (0)\n004 4 ad0d ae67 aebd afa3 | 4 ad0d (0) ae67 (0) aebd (0) afa3 (0)\n005 2 a7a6 a75a | 2 a7a6 (0) a75a (0)\n============ DEPTH: 6 ==========================================\n006 2 a320 a2ba | 2 a320 (0) a2ba (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","private_key":"40d0f667c75292876d80bf036c58b652ae8eaf08e6543afce8efe01b5ba38af5","name":"node_a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","services":["bzz","pss"],"enable_msg_events":true,"port":33037},"up":true}},{"node":{"info":{"id":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","name":"node_7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","enode":"enode://8f6eaa7d371d5a4d8c1f71c52540914abe2f27afe0a753b8b7ce09e09ceeea61785f53dea26d90c6455d9a37657c52155faf04192b6b8ecef078b8b27ecc7572@127.0.0.1:0","enr":"0xf88fb840ef3018c62f6e420fbce8abac717ede992b1c276bfe0ce90b7b1d8ed88c0a2060783837e6f1f927d5f126a1c274bb6fa274db17107672ef312532d457aeea68200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028f6eaa7d371d5a4d8c1f71c52540914abe2f27afe0a753b8b7ce09e09ceeea61","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c1X6sQWE5DEvXLXDyCbn+cFNp01i0H0KgAfOnG6ZW+k=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7355fa\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d6ff 9a92 a085 | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 7 3cb1 38ab 39db 372d | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 3 5abc 539d 48b6 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 7 6742 667e 6982 6ecb | 11 6982 (0) 6d60 (0) 6c82 (0) 6c02 (0)\n004 3 7fbc 7dc5 7b92 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 7639 772e 757a | 3 7639 (0) 772e (0) 757a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 73b8 | 1 73b8 (0)\n009 0 | 0\n010 0 | 0\n011 1 734e | 1 734e (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","private_key":"65b0005e792636557ba85af62557e19b18b9174bbbef4d0d1a9df6ed86564cd2","name":"node_7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","services":["bzz","pss"],"enable_msg_events":true,"port":35631},"up":true}},{"node":{"info":{"id":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","name":"node_48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","enode":"enode://0cbf237e6aeb863aeb824af9ceface5a8f94eb2330907633723afa315ad810ca5fa9de4f687c6a6035eab2339a4cb9803b61f752c39ec949930c3699850fa0bb@127.0.0.1:0","enr":"0xf88fb8408c25a5258f12cb8ddea2eb309508a3b3bb615e0af2611013a4caa40a060e503d076f528b777885fa04eccb0ab89a0d909844f92a68099ed5b0cb0d3b417c2cda0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030cbf237e6aeb863aeb824af9ceface5a8f94eb2330907633723afa315ad810ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SLYUlYqGkngO9b1cleDbT/Z9603g3LuHjKRHm/uGlX4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48b614\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f5c4 b2b9 b381 afa3 | 63 ed32 (0) edc8 (0) ea0e (0) ea60 (0)\n001 7 39db 3e56 3cb1 372d | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 12 6982 6c02 6d60 6ecb | 23 6982 (0) 6d60 (0) 6c82 (0) 6c02 (0)\n003 3 539d 558e 5abc | 7 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n004 3 47c3 4167 419a | 4 47c3 (0) 4167 (0) 41b9 (0) 419a (0)\n005 1 4cd0 | 1 4cd0 (0)\n============ DEPTH: 6 ==========================================\n006 2 4a18 4b24 | 2 4a18 (0) 4b24 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","private_key":"270a9d9bfe65cba3f7905cabdc33f12696f57f495f5b1f4f717c4f686cb9fb22","name":"node_48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","services":["bzz","pss"],"enable_msg_events":true,"port":33663},"up":true}},{"node":{"info":{"id":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","name":"node_afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","enode":"enode://318bacfd1e44885c89d878b681a769550aa404ad1b963f802ec5bcc8ad70cecde25b68156ac8fce5ab0574e0518f7a5931f1e66b578bc395678f5541d523a0a4@127.0.0.1:0","enr":"0xf88fb840f8a54e090fb7de27c570ae1607b52faecfb241df7ca595859ef729b0b22447b7052a90ae67d12246ec2040000f85a4697bb924b273657efe3faf78db0f755c920183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102318bacfd1e44885c89d878b681a769550aa404ad1b963f802ec5bcc8ad70cecd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"r6PeXOvJ+WzyCjUFj0hW/kO0isWc+ORlZfGU9DhiKlI=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: afa3de\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2459 0bcf 6728 48b6 | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 3 e55d e16b f5c4 | 30 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n002 8 91eb 92a1 9d3c 9e02 | 16 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n003 6 b92a b841 b486 b70e | 8 b8e1 (0) b841 (0) b92a (0) b486 (0)\n004 4 a7a6 a75a a2ba a085 | 5 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 ad0d | 1 ad0d (0)\n007 2 ae67 aebd | 2 ae67 (0) aebd (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","private_key":"e19117f65a5dd05127cf7d2d994fdf61d54c6d9c1113d8cbbd46927df4e3c23a","name":"node_afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","services":["bzz","pss"],"enable_msg_events":true,"port":36875},"up":true}},{"node":{"info":{"id":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","name":"node_67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","enode":"enode://81035bfc5935b3ecdf8f5134d14f109559ce2602e1ef2ae36ff475c43b469a32b2d71d843c6e1a1d45509706538e0956e768594aac04aaf5a712a9a3405251ac@127.0.0.1:0","enr":"0xf88fb840eae38a1667d14d43e83b2c0d0a1c2fb4ccbc358bf1134594c33b2b58d710260809ad16b7f243040e51a0eb368e12ea4ed50a0b438fdbd2f23231d37b12e093010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10281035bfc5935b3ecdf8f5134d14f109559ce2602e1ef2ae36ff475c43b469a32","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZyiPhK2nd4hYE5x0kXsirmmO1D30mmUwpWZkjwdO3kY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67288f\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 d6ff dfae dc97 f5c4 | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 2 26d1 0bcf | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 6 539d 5abc 4167 4cd0 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 4 7b92 734e 73b8 757a | 12 7639 (0) 772e (0) 757a (0) 73b8 (0)\n004 5 6d60 6c02 6e5c 6ecb | 6 6982 (0) 6e5c (0) 6ecb (0) 6d60 (0)\n005 1 6210 | 1 6210 (0)\n006 1 645b | 1 645b (0)\n============ DEPTH: 7 ==========================================\n007 1 667e | 1 667e (0)\n008 0 | 0\n009 1 6742 | 1 6742 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","private_key":"8b748538936665f38549ca75239d192493fd5ff24f126d318b4335bae35d9d6b","name":"node_67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","services":["bzz","pss"],"enable_msg_events":true,"port":43817},"up":true}},{"node":{"info":{"id":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","name":"node_0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","enode":"enode://0379db849a652e76893c5565c230efe72c4d44c416b9bb323529807baef9a4843b1ba9d548fe30e116edbd1e0e376d0a9a983b35542e9d414e227b915231d22e@127.0.0.1:0","enr":"0xf88fb8403c83a4015938e95101f3db5859df1555fc2fb05d2c47650e84388bb516e27426523605a2d76c9118658082f4fb8ef3cecffb3add5ea8986a4b53a1daa0c4e4660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020379db849a652e76893c5565c230efe72c4d44c416b9bb323529807baef9a484","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"C8+KirAGXKjIW4tmQfTG4LDeYOee8y6/b/jxCaxOHXA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0bcf8a\npopulation: 39 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 e16b 895b 9d3c 9626 | 63 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n001 10 4cd0 4b24 48b6 757a | 38 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n002 9 372d 38ab 39db 3cb1 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 4 1be4 1929 109e 13bc | 4 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n004 6 0506 018a 0390 0218 | 8 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n============ DEPTH: 5 ==========================================\n005 1 0ff6 | 1 0ff6 (0)\n006 0 | 0\n007 1 0ab9 | 1 0ab9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","private_key":"a66755f09e07ea306f890663b424f0162339cc7ac848e7ed878743e6e0d7cd71","name":"node_0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","services":["bzz","pss"],"enable_msg_events":true,"port":39147},"up":true}}],"conns":[{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_16.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_16.json index d35df9fc..b6a7bf81 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_16.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_16.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"88621610b5fdbf3e584724e2268a24dc41562da5cdba92357b97edc42d79ec4e","private_key":"2c268d9cf0ca43f4b0ad80f8980f4fe019e0294819f881d505e02382b472b98b","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","private_key":"69ac59cce230e49f10c769fc8f2b717bdadc5ffa5dcf7fae19d8cb15315fa177","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","private_key":"b793f9ace49ecce16c0c86b49495093f7f4c5fa0003675c9eb6efa802c8daafe","name":"node03","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","private_key":"9fecef44b474621ce2ddd57cf67df319bd0e13c27f0f6e9d060c34ef813675ea","name":"node04","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","private_key":"c8f4336f88c90242744e9c04fba1a55027d9ad4295b7a2b0ad99e8dae12463d3","name":"node05","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6629ec867229b28221a6118eb0e097861eb784b624578f55c3811cdf5026c1c7","private_key":"0ca52c3e4781fc413a13448abaae042dae52e2bab5772c52440bc4b2c6a5bda3","name":"node06","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","private_key":"447c97a6c211160f0fb7990812c637bd346003a484cf05c3d92816007ab3745a","name":"node07","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","private_key":"8fa6ac35409a6df21ee32da8c36f61cd007a3515d23bb350351c263c241b851a","name":"node08","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","private_key":"e4143bd79f4a55f463b623afc397fe0166a144f45c41fd8b58f816e208212819","name":"node09","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","private_key":"6a2a32adb2b5cbc66adf29d5da1123b6e345e73ed42916e9535df3058801cb92","name":"node10","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8c92cb1fcda5b67a4b928c200e2e5e324599c997202d9ea98f703239ee3fc3b1","private_key":"ae486490233b1b16e6a35461a3b90573f59362b9bbf0b8c46b65c715b0506bd7","name":"node11","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","private_key":"cbf9da4b4f44f44c0bcf69bb2134e33ddfdda7742d7f5609db74bdf4fb683cfb","name":"node12","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","private_key":"180ee0110d87d330dd416568e300cacfd4d52f8c08875ada1a6d5b4a11142b1d","name":"node13","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","private_key":"d7a364b77d55a53453e94e10d235edf4ceb248653247bded6c1df31fc88ecbca","name":"node14","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","private_key":"7eaec2f68f3b0e562a5438324aa30b9c22746af6e8139b05b21e89103f508c5a","name":"node15","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","private_key":"b130fa04ab1f60d0713b9260156457f9139e819cb2f70bd87a2ea409f135f881","name":"node16","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","other":"88621610b5fdbf3e584724e2268a24dc41562da5cdba92357b97edc42d79ec4e","up":true},{"one":"88621610b5fdbf3e584724e2268a24dc41562da5cdba92357b97edc42d79ec4e","other":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","up":true},{"one":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","other":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","up":true},{"one":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","other":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","up":true},{"one":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","other":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","up":true},{"one":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","other":"6629ec867229b28221a6118eb0e097861eb784b624578f55c3811cdf5026c1c7","up":true},{"one":"6629ec867229b28221a6118eb0e097861eb784b624578f55c3811cdf5026c1c7","other":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","up":true},{"one":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","other":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","up":true},{"one":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","other":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","up":true},{"one":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","other":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","up":true},{"one":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","other":"8c92cb1fcda5b67a4b928c200e2e5e324599c997202d9ea98f703239ee3fc3b1","up":true},{"one":"8c92cb1fcda5b67a4b928c200e2e5e324599c997202d9ea98f703239ee3fc3b1","other":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","up":true},{"one":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","other":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","up":true},{"one":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","other":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","up":true},{"one":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","other":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","up":true},{"one":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","other":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","up":true},{"one":"88621610b5fdbf3e584724e2268a24dc41562da5cdba92357b97edc42d79ec4e","other":"8c92cb1fcda5b67a4b928c200e2e5e324599c997202d9ea98f703239ee3fc3b1","up":true},{"one":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","other":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","up":true},{"one":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","other":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","up":true},{"one":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","other":"8c92cb1fcda5b67a4b928c200e2e5e324599c997202d9ea98f703239ee3fc3b1","up":true},{"one":"6629ec867229b28221a6118eb0e097861eb784b624578f55c3811cdf5026c1c7","other":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","up":true},{"one":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","other":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","up":true},{"one":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","other":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","up":true},{"one":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","other":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","up":true},{"one":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","other":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","up":true},{"one":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","other":"6e8c4a5d6e54dda7c633ff469e8f935935250f4d0034c9058048dc643a4f811e","up":true},{"one":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","other":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","up":true},{"one":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","other":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","up":true},{"one":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","other":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","up":true},{"one":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","other":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","up":true},{"one":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","other":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","up":true},{"one":"88621610b5fdbf3e584724e2268a24dc41562da5cdba92357b97edc42d79ec4e","other":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","up":true},{"one":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","other":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","up":true},{"one":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","other":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","up":true},{"one":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","other":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","up":true},{"one":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","other":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","up":true},{"one":"6629ec867229b28221a6118eb0e097861eb784b624578f55c3811cdf5026c1c7","other":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","up":true},{"one":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","other":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","up":true},{"one":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","other":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","up":true},{"one":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","other":"6629ec867229b28221a6118eb0e097861eb784b624578f55c3811cdf5026c1c7","up":true},{"one":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","other":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","up":true},{"one":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","other":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","up":true},{"one":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","other":"4b6e068e84fecde2bb6a48698233f0c2ae5e66b15a8bad2e0b5d499c31d48b98","up":true},{"one":"c7a2bf651f59149716235fa7bfb4cee835aa4bdd402ccab8c52959aa74dc6af4","other":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","up":true},{"one":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","other":"5989492b2703336b42f59b2be1653a0bce76e801ef262121f627a476581af5e1","up":true},{"one":"d9b0b57a237a8386cf6cf611779d8df3f5b0f9c01719e97230c3b23bf0ab04ae","other":"55ce5ea5772c31de27b337f1e2cf767663c03a61b2f47b71921def1cfc3270ea","up":true},{"one":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","other":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","up":true},{"one":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","other":"8c92cb1fcda5b67a4b928c200e2e5e324599c997202d9ea98f703239ee3fc3b1","up":true},{"one":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","other":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","up":true},{"one":"69d329853a0624dba12949e6be7db093143976d9a5d514b80d72a9bf7fbc568c","other":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","up":true},{"one":"d33e4e6af5ba13ae448a16a4a8183ab1050fa3f983cdbf03dec5c21a5e9dd146","other":"c651a0c924fc01e9d6cd30aba6864cd93631d5d4e21ceeda7db1922f105c5ca8","up":true},{"one":"1ffdd4692bd4fd272ac6b5c2e039354869df92c0d4247abedcd8a8932b057574","other":"9cd2b6b17d2954c0a0d4a340707c71215a08c3c27b5b5b294e96ad20263ba600","up":true},{"one":"c0f23df25018045ddc4035268a9e7468f386ecad306b9ed9053cf66e2f1ab0a2","other":"c553ca20b4f7f1b1e3b71b261829c27eb1cfe6710aa0999f655a42670e6d8813","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","name":"node_26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","enode":"enode://e6b0213542756a047ab018ae745faab8a1c821082dc7bc64d13bee50591b554c10508dc284a7c3e686504bda30edf0ee9d3d5588e926725705014eb57ec321a7@127.0.0.1:0","enr":"0xf88fb840ef67bfea09687245f9a21fbeae2c963d6a827f70953457a32df964dc3fc96f3f1630e241de2d2ba4da049d18c459d2fd798c5be2d6dfbd9290457f678f7628af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e6b0213542756a047ab018ae745faab8a1c821082dc7bc64d13bee50591b554c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JlBMs9mhIiev3EMGVJbMr/cXLk2mKqdNN/JxraPwDcc=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26504c\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 b2f3 | 5 d465 (0) c7c0 (0) ece3 (0) 9ed4 (0)\n001 2 6a51 55bc | 5 689c (0) 6a51 (0) 72d3 (0) 769c (0)\n002 2 0160 0ffa | 2 0ffa (0) 0160 (0)\n============ DEPTH: 3 ==========================================\n003 3 348e 304c 3a9a | 3 3a9a (0) 348e (0) 304c (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","private_key":"1882828490f180d94a676998d372c267a462d3992a1499fdc9535ce176a5a7c0","name":"node_26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","services":["bzz","pss"],"enable_msg_events":true,"port":44851},"up":true}},{"node":{"info":{"id":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","name":"node_b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","enode":"enode://f69f214e3a7a9acc20ceac92869db21701e0dfab27365dbf13271def097914735fa4c6e47ff354aa9b04c0c5b1d42f903a55fa8de2490e66627fe1ae1e1f5ff1@127.0.0.1:0","enr":"0xf88fb840aec067e5c9519ed112d73b546bf81054e0afcadfaf54794b42cc67e8ff3f64ae5aba1b9fa38e9916af5117d49d34acbbc6a9fddf6eb4463fc85e8340738bdb490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f69f214e3a7a9acc20ceac92869db21701e0dfab27365dbf13271def09791473","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"svOmnVL5gDfPvcQKUpYSyJDNSwYb+odBFJPfXG4etdk=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2f3a6\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 55bc 6a51 769c 0160 | 11 689c (0) 6a51 (0) 72d3 (0) 769c (0)\n============ DEPTH: 1 ==========================================\n001 3 d465 c7c0 ece3 | 3 d465 (0) c7c0 (0) ece3 (0)\n002 1 9ed4 | 1 9ed4 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","private_key":"2bc350f43a600469515791e72c828ea18e25dae28a8eba34ad9123f2b2d0e7b4","name":"node_b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","services":["bzz","pss"],"enable_msg_events":true,"port":46035},"up":true}},{"node":{"info":{"id":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","name":"node_ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","enode":"enode://3f0c7d44d331f144a130eff41ad30fa260c30f29f27b2c6a9ce94dc86ade5a4f1457ff241b4e48f42dab7e3f4d4ed626b22ada5032bb29645c0ab5a6c7ddca61@127.0.0.1:0","enr":"0xf88fb8406aa846ed3e1e91c35a8db13e47424870d976fba32a38ecbbd87fef3f04b0bd5c04ab395313a732a3e5121e0c32768abedb704b835b81713c24e136bdc970d1560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033f0c7d44d331f144a130eff41ad30fa260c30f29f27b2c6a9ce94dc86ade5a4f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7OMMXOQMJ2mXPpVL/Ye5c6dTiH9Ks58rY4o8sonspSE=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ece30c\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 689c 72d3 348e 304c | 11 689c (0) 6a51 (0) 72d3 (0) 769c (0)\n001 2 9ed4 b2f3 | 2 9ed4 (0) b2f3 (0)\n============ DEPTH: 2 ==========================================\n002 2 c7c0 d465 | 2 d465 (0) c7c0 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","private_key":"1f5005e874a37bbc0f9f920f3089faf5b0189f3ab1796fa370cb89e58b9517d3","name":"node_ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","services":["bzz","pss"],"enable_msg_events":true,"port":41799},"up":true}},{"node":{"info":{"id":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","name":"node_304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","enode":"enode://25b34252e979970bc75da4174ee863e64564c2a62367a9f03f9a4806a84cbbfd7154163bc5c765cd9993870ed9f39a862e80e9020638355cedb3f5deb6a5f80f@127.0.0.1:0","enr":"0xf88fb840cfc8be3771521eb84480fed1ead36e67bbdb0acf5db42a3d1ad0f6aba80130bf6bc03592b7ab85cafe0d19266c3b004b2057b042ba69ee8e00c4d569d0193d5c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10325b34252e979970bc75da4174ee863e64564c2a62367a9f03f9a4806a84cbbfd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MEwYqasfC8Ql4cDV6C+qQ7yzkSpolu4hJgVvgKpZnHI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 304c18\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c7c0 ece3 | 5 9ed4 (0) b2f3 (0) d465 (0) c7c0 (0)\n001 2 72d3 769c | 5 769c (0) 72d3 (0) 689c (0) 6a51 (0)\n002 2 0ffa 0160 | 2 0160 (0) 0ffa (0)\n003 1 2650 | 1 2650 (0)\n============ DEPTH: 4 ==========================================\n004 1 3a9a | 1 3a9a (0)\n005 1 348e | 1 348e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","private_key":"411d5a05b2233c28b2366e3ffc2e67effdd61216f64124ab18ef047fd2d2b6ed","name":"node_304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","services":["bzz","pss"],"enable_msg_events":true,"port":40347},"up":true}},{"node":{"info":{"id":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","name":"node_c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","enode":"enode://f4bb3d33407ed52c3ed7a46a9394efb0907b2ec97d79e08a4cebde9206d7b9f1d7dbfef2c01efc191b2342e7dcfc725015f6d6c639ce8af7ce3f2240c41a3d24@127.0.0.1:0","enr":"0xf88fb840bfa01ff6980a93944637109a5b15621a9bf50a678e6b21a6cb08b903a5db94e770fa89cdb38ab4a7540b4262ad9f2036ee6a3868b6de7a437d5c3c71402f097f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f4bb3d33407ed52c3ed7a46a9394efb0907b2ec97d79e08a4cebde9206d7b9f1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"x8CAzgtexu3l4A87QIeZUZcE+2KOgXfB7sLnrtfzsbA=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c7c080\npopulation: 6 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0ffa 304c | 11 55bc (0) 769c (0) 72d3 (0) 689c (0)\n001 2 9ed4 b2f3 | 2 b2f3 (0) 9ed4 (0)\n============ DEPTH: 2 ==========================================\n002 1 ece3 | 1 ece3 (0)\n003 1 d465 | 1 d465 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","private_key":"8bd7e85f0ac64efbc80d7952b31f33602531d2e9ce2f589ebfbdc66fceadde81","name":"node_c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","services":["bzz","pss"],"enable_msg_events":true,"port":46599},"up":true}},{"node":{"info":{"id":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","name":"node_0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","enode":"enode://99de6da9abebfa76fefdac94de902456d8450886946933b5e9da18e4b0709d7c27109b17d024419e205fa3b2cc50268f330217b105a0a92126e1c1697b593dfd@127.0.0.1:0","enr":"0xf88fb840e1d27e54275610c9979cc6255e9363b42c5e2c746301dc788af52d58e895775e37d99e021fc6f9746aba2070d0e48855e7a4c8f04bee0d96ef8c49c8234f97840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10399de6da9abebfa76fefdac94de902456d8450886946933b5e9da18e4b0709d7c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D/r+COmRGbJA86Hzbd07vd0fPD8T6IOdRVHkP3llgWo=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ffafe\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 c7c0 | 5 b2f3 (0) 9ed4 (0) ece3 (0) d465 (0)\n001 2 689c 55bc | 5 55bc (0) 769c (0) 72d3 (0) 689c (0)\n============ DEPTH: 2 ==========================================\n002 4 3a9a 304c 348e 2650 | 4 2650 (0) 3a9a (0) 348e (0) 304c (0)\n003 0 | 0\n004 1 0160 | 1 0160 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","private_key":"a19af618fec44371482faf5f2f6366acf984bdaf717c382869e46dc18edea77e","name":"node_0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","services":["bzz","pss"],"enable_msg_events":true,"port":43693},"up":true}},{"node":{"info":{"id":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","name":"node_9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","enode":"enode://ae0f2a151e99e9e9e54938545cf4f19f56a6a10bbad2f1966661dee90753d398c6771c23d7ee70db1715897e3364a561e38ae3fff21349d579e9abf44dcf8d5f@127.0.0.1:0","enr":"0xf88fb840ff4b95dcfbd61ccc46ca0a798ba8dcaa6cb23ae891ee35cfbdfbfb7811614a8a08192ebcced83a5c6afbf3d95c08b6d5fd18af8d5df806d341ed361398e3554f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ae0f2a151e99e9e9e54938545cf4f19f56a6a10bbad2f1966661dee90753d398","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ntQLcOTHKZemyYD2hi0K6PNmsb5Ix3/Pp5ZTYvsd18Y=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ed40b\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 769c 55bc 3a9a 0160 | 11 55bc (0) 769c (0) 72d3 (0) 689c (0)\n============ DEPTH: 1 ==========================================\n001 3 ece3 c7c0 d465 | 3 ece3 (0) c7c0 (0) d465 (0)\n002 1 b2f3 | 1 b2f3 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","private_key":"d19f0df4bba07418a557ec945ed8c8851ed01e20e7760c72954352862bf77ba6","name":"node_9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","services":["bzz","pss"],"enable_msg_events":true,"port":35629},"up":true}},{"node":{"info":{"id":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","name":"node_d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","enode":"enode://338975eb003552bbb837272c2b48a049b7fab8958571e0eb9bc1d1cdc967cbbe42ee93adeed75700391016cf7d311e7d06f48cef371f2b80ff80bfd6a27bd16d@127.0.0.1:0","enr":"0xf88fb840f009eadfddb5e69c6ca89a5d2ba64ee2ec31ebe85623adea4e036e4136f1f4d74d0933a43c9a0bdb66eec46cdbed18bfde269fa892da42d47d2b8bd1b6db3be30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103338975eb003552bbb837272c2b48a049b7fab8958571e0eb9bc1d1cdc967cbbe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1GWYv89EN/iGN8p1VXMBB1NfOLQZycs1M83FNuGWJp8=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d46598\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 348e 2650 72d3 689c | 11 2650 (0) 3a9a (0) 304c (0) 348e (0)\n001 2 b2f3 9ed4 | 2 b2f3 (0) 9ed4 (0)\n============ DEPTH: 2 ==========================================\n002 1 ece3 | 1 ece3 (0)\n003 1 c7c0 | 1 c7c0 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","private_key":"adccac5625a153c4cca90a971fbe0b7b2f9f62af166fd1fcad0a6559e042e2a5","name":"node_d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","services":["bzz","pss"],"enable_msg_events":true,"port":39805},"up":true}},{"node":{"info":{"id":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","name":"node_6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","enode":"enode://0fe608947dab328f476e8dd8d94ea391e604adcf4a15901224e32c9a3bc6e198d13751af168e9b31f140ee82d39e29d0f347cd733cd44797abf34ce629c57a75@127.0.0.1:0","enr":"0xf88fb840bf749d25f9054ed9f97df2a3d695fe170ece0e2d67d097756696bf90d2d5c5dd7f67527f9f8368d18843438f769883c32cc76fab8eeb57768a9d66fedd125e800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030fe608947dab328f476e8dd8d94ea391e604adcf4a15901224e32c9a3bc6e198","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"alFzAxcq/rAXX/M/YjLaqcLPmjdTuc2XPS4aG7ss0cg=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6a5173\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b2f3 d465 | 5 b2f3 (0) 9ed4 (0) ece3 (0) c7c0 (0)\n001 2 3a9a 2650 | 6 2650 (0) 3a9a (0) 304c (0) 348e (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 769c 72d3 | 2 769c (0) 72d3 (0)\n004 0 | 0\n005 0 | 0\n006 1 689c | 1 689c (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","private_key":"0ab9fec01ec19b2a335b0ada3a02e30702d90efb1f3c1a0bf2b9cd36a9f87fc9","name":"node_6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","services":["bzz","pss"],"enable_msg_events":true,"port":41555},"up":true}},{"node":{"info":{"id":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","name":"node_689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","enode":"enode://9e1aac08a4928876280c211e71ffd510eeb78fbebff4ac254af5a302f8913cf798a0f55a79b99735f8a01dc4adc39428659649437d1bb0b88d3383e6b7ad7104@127.0.0.1:0","enr":"0xf88fb8402129c2f1dadb690035ffe0776862b987152c612355ed44a6927c7402b5801fe05b2d540e5e19afb63be6e975809af1bcc385286bad2dd92baacec2f7931386680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029e1aac08a4928876280c211e71ffd510eeb78fbebff4ac254af5a302f8913cf7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aJyaD1eoOEaCWf4u4IJEatFcWW7zYboWwrkrU922ykE=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 689c9a\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 ece3 | 5 ece3 (0) d465 (0) c7c0 (0) b2f3 (0)\n001 2 0160 0ffa | 6 0ffa (0) 0160 (0) 2650 (0) 3a9a (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 769c 72d3 | 2 769c (0) 72d3 (0)\n004 0 | 0\n005 0 | 0\n006 1 6a51 | 1 6a51 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","private_key":"31c956ed431b0b0f061c15e1263dbf111de4a9f4dd5335680fa9f64c0821fa0b","name":"node_689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","services":["bzz","pss"],"enable_msg_events":true,"port":36247},"up":true}},{"node":{"info":{"id":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","name":"node_72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","enode":"enode://d21eb565193ce78749091397af418bba7c9b152f3ccf4199e17df26bd700459fbb87ada766a3cdea29a1fdf9656b6b1372948fcc2eb030dc879b029bdd6b04e5@127.0.0.1:0","enr":"0xf88fb840f89a9aa64661b1f4d6ac8e6aab664af27a58b08bcc3c43066d458d99dcf75bc6536c7326631a031ff2b89404eedfbe566a8beea5d3eb0e0865b206d8ea25bc070183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d21eb565193ce78749091397af418bba7c9b152f3ccf4199e17df26bd700459f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ctPRRIhY45MQPRvSlAk94Ovz7IqLTTtH+mmGrbVcUrI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 72d3d1\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 ece3 | 5 ece3 (0) d465 (0) c7c0 (0) b2f3 (0)\n001 2 304c 348e | 6 0ffa (0) 0160 (0) 2650 (0) 3a9a (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 6a51 689c | 2 6a51 (0) 689c (0)\n004 0 | 0\n005 1 769c | 1 769c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","private_key":"278c5f54c5e9f2d2688383f0a5f98b72a01d76b532799a74162c2f169d8a4819","name":"node_72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","services":["bzz","pss"],"enable_msg_events":true,"port":36181},"up":true}},{"node":{"info":{"id":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","name":"node_348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","enode":"enode://5b1fa3f55ee9c0fd34bf203045faf80d0a8fcded75c21a9a319fe6d628698f8aa78c60d5d78df5b3c54c29fd27f10be4a63c66895cc743e1a0cbe795e87114ca@127.0.0.1:0","enr":"0xf88fb84017bd33bdfe5b6e2c263ef3e95f0acaf1a4e902e79b4cfbe40e6ad57b4f9b21e019473a61a57e1b999ce432c288a6c8fa685df4afd8872c98757be969446b1ff60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025b1fa3f55ee9c0fd34bf203045faf80d0a8fcded75c21a9a319fe6d628698f8a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NI6TUbEGJaai/gROZ2l81UzlfIbaJXBFnst51Ky4bzI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 348e93\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 ece3 | 5 ece3 (0) d465 (0) c7c0 (0) b2f3 (0)\n001 2 55bc 72d3 | 5 55bc (0) 6a51 (0) 689c (0) 769c (0)\n002 2 0160 0ffa | 2 0ffa (0) 0160 (0)\n003 1 2650 | 1 2650 (0)\n============ DEPTH: 4 ==========================================\n004 1 3a9a | 1 3a9a (0)\n005 1 304c | 1 304c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","private_key":"fdb4b30d8d9482f9581193c6f6b57e5213922001901c46407528810f0e598058","name":"node_348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","services":["bzz","pss"],"enable_msg_events":true,"port":37669},"up":true}},{"node":{"info":{"id":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","name":"node_3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","enode":"enode://90143f4ad7bfd6cc2ba948ab8de4587aa7a2948de5b096c65ef276f04ff7c4aa4e043e0add0734c668c1f8c59e7d4294d2bb2bde96490ce04ce95eaaadb4bab3@127.0.0.1:0","enr":"0xf88fb84090f225e54c8dff490b8cdfbcf4d956adc2125d2bd2b2c98c090d6d6775ad78ed3cc047b26c655c81bedff72ccfdeecca053020666d23c3342a27b7ffc339dff30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10390143f4ad7bfd6cc2ba948ab8de4587aa7a2948de5b096c65ef276f04ff7c4aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Opo7ONDc1IRfidcJG4L19nX8NVfQmXnED/wSp7u/5BQ=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3a9a3b\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 3 55bc 6a51 769c | 5 55bc (0) 6a51 (0) 689c (0) 769c (0)\n002 2 0ffa 0160 | 2 0ffa (0) 0160 (0)\n003 1 2650 | 1 2650 (0)\n============ DEPTH: 4 ==========================================\n004 2 304c 348e | 2 304c (0) 348e (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","private_key":"8affc7f653083f993524996d8a2de34d88ba748c3485d4cd721ce02207edacae","name":"node_3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","services":["bzz","pss"],"enable_msg_events":true,"port":46571},"up":true}},{"node":{"info":{"id":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","name":"node_769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","enode":"enode://c1b9d33acbb2c9146cad2b1ff6786740ae264aad8c633fdeead6fc07a584de39e78116f9790d1b88e80590ba6a40b0dba329474f371d2001205f9b5cfcd7e1e3@127.0.0.1:0","enr":"0xf88fb840678a2b8e8007983d072232c0a39be22bad2ab19c2a8010bc814b74e7c1d40edd0169d827cb6191c5b4ed4d7079a6cad6163b76a826017bf524f74655b92d26320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c1b9d33acbb2c9146cad2b1ff6786740ae264aad8c633fdeead6fc07a584de39","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dpyUjXldExlfM2Gvava9t2/dZu09t5bM7BBPfcIf76A=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 769c94\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 3 0160 304c 3a9a | 6 0ffa (0) 0160 (0) 2650 (0) 304c (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 6a51 689c | 2 6a51 (0) 689c (0)\n004 0 | 0\n005 1 72d3 | 1 72d3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","private_key":"dbc7392e8eb09f40ef0971a14aa3db440d1a125b32876942e60f8582ad70c046","name":"node_769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","services":["bzz","pss"],"enable_msg_events":true,"port":35637},"up":true}},{"node":{"info":{"id":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","name":"node_0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","enode":"enode://e7237f8772dd77b211f061e619e63fac712395256ff49128a7152f1bfc4ba15fe7b9339c51e2f98e0824faec48ae462e6a340f94c11ff1d32e692aac18a63c07@127.0.0.1:0","enr":"0xf88fb84013c8bd0c52cc1d01e9d8a1394b7be84bc47f042841d0073347d93646bf6a3d266c3fd3dc41ac81c04d6b2027a7aa4d2688270827ab197f79a29e426130530c7a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e7237f8772dd77b211f061e619e63fac712395256ff49128a7152f1bfc4ba15f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AWBDakeR13v37ZyYIoin9ex6Gg0o9h9n6ujcZWxicsQ=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 016043\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 3 689c 769c 55bc | 5 6a51 (0) 689c (0) 72d3 (0) 769c (0)\n============ DEPTH: 2 ==========================================\n002 4 2650 3a9a 348e 304c | 4 3a9a (0) 348e (0) 304c (0) 2650 (0)\n003 0 | 0\n004 1 0ffa | 1 0ffa (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","private_key":"bec59ef09d2194c27ec1b844af85605ac08c87830784fab76b080d3420c06898","name":"node_0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","services":["bzz","pss"],"enable_msg_events":true,"port":45829},"up":true}},{"node":{"info":{"id":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","name":"node_55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","enode":"enode://2de6037913178726275c8ef050e0dae981406aa551fea37112bdb34d1a403bb5f86fe8cbb04732fbde1f0f362bba71bc6499c16b59fab0f7f0d6f1c0c1d103d6@127.0.0.1:0","enr":"0xf88fb84002914870f5ffed74456e9316ad731fc2686c9a0189c095584882392fe59512a56195aeeabfbb7fd0f7615cfa429568a033dc0447bc5d1a34ba2a05ad8bb762c30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022de6037913178726275c8ef050e0dae981406aa551fea37112bdb34d1a403bb5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Vby/E5LQzXeChqIcl6LSKn5KJJTBlxR8OfXC8k1PuhI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 55bcbf\npopulation: 11 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 5 348e 3a9a 2650 0ffa | 6 3a9a (0) 348e (0) 304c (0) 2650 (0)\n============ DEPTH: 2 ==========================================\n002 4 769c 72d3 689c 6a51 | 4 6a51 (0) 689c (0) 72d3 (0) 769c (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","private_key":"ba62b88bff913813741dd50c907c918e974132dcde3c6f57ea49a0bb1ce5cd26","name":"node_55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","services":["bzz","pss"],"enable_msg_events":true,"port":39363},"up":true}}],"conns":[{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","other":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","other":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","other":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","other":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_2.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_2.json index b01ce303..8be6e0dc 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_2.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_2.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","private_key":"e567b7d9c554e5102cdc99b6523bace02dbb8951415c8816d82ba2d2e97fa23b","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","private_key":"c7526db70acd02f36d3b201ef3e1d85e38c52bee6931453213dbc5edec4d0976","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","other":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","enode":"enode://6a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f9757875b6b8d02f88fafe3fd7f20f0349a0060ace7c0be1d65470e736a3319431b5c14@127.0.0.1:0","enr":"0xf88fb84096f5dd9030fc74da3701ef7b06dfe4d44068118f8041a728876904d70fa8c88c20df197c343522c76d75d3a12507c567213c13b46a94ed4800f47474643f4ee70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f975787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/TfkUhDds2+LXs75ydnT+CAbqVI7/WpwKRMzzzuSB+E=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fd37e4\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 1 3594 | 1 3594 (0)\n001 0 | 0\n002 1 cb08 | 1 cb08 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","private_key":"6a02f87b1d13a15ce24bfa58456af8aaabdcf8cb58b9f86c19ab14c721c80f91","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","services":["bzz","pss"],"enable_msg_events":true,"port":39341},"up":true}},{"node":{"info":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","enode":"enode://0972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03397efbad98888f8d740b7cf55c357d1d6d74b5e8cb935f71b19e0e16ceef03f9@127.0.0.1:0","enr":"0xf88fb840d5f39b1ebcd5b616ef67b1c0239ed4501ef45c6a00e5bd8cd3f2ac88870d4c4b6ce4a4af820afab9a714d99a5fef53ec3c042fc3243f403819bcfb3504c2150d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NZRDinSApcPcBkQOKKFgRMDH0okhnaAvnkHaGBCCeAU=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 359443\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 fd37 cb08 | 2 fd37 (0) cb08 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","private_key":"26266470b7f4e9341cbbbb304b1aed116626cb1bea55d639cdbef1a069c18123","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","services":["bzz","pss"],"enable_msg_events":true,"port":33055},"up":true}}],"conns":[{"one":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","other":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","up":true}]} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_256.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_256.json index 4397a7ea..936956be 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_256.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_256.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","private_key":"c4e98d074abce07e849be2810e5522bdacf2489125ed7577e02b4809f9619700","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","private_key":"d607b8638fa33ef417d88597579e00a2f93e76881193a8692b57d03b27a60ba7","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","private_key":"c4501aa97316685b3e707bd881c1d805e96430723fa88ffc60e1703485eff5b2","name":"node03","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","private_key":"f1fceda785676921048d116f40e4d331ab32873f4b0343fddbd372c836808f2a","name":"node04","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","private_key":"a5baeb4f2e35eedde63d573bbec157e61f0c0ba6ecc7b6cb6a42759bbc165e5b","name":"node05","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","private_key":"1b7e31744236baa89eaadd57ec870b5415111685fda883490b5a0e1dbc321210","name":"node06","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","private_key":"344f9ff7d68ca6a04e3141646044db06e5761248c64a01bb6cc2813fb7745ae4","name":"node07","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","private_key":"869c03072d8108be18544c579cca53ffe17682e3898f44baff9cc37507fc62ed","name":"node08","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","private_key":"1fe668699f54728124bbf993215de07682f072d145dd8acc428f04abd4a46f08","name":"node09","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","private_key":"a3af1294d727198fb3282659a35ae5b27f4b23b28d76e528809b68a6263fd673","name":"node10","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","private_key":"f7ad4635d864376fa4536bf23df764278d30805556cbf13e794e0ebacf389172","name":"node11","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","private_key":"237183f9e7834a03859c43be2a49bb8e4f1c9c7a5c334958f74d4ed36dfbd5a7","name":"node12","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","private_key":"7f7c361b6989c77419ac69848c9a4b06255aeb0f6115454566cde4ca544af085","name":"node13","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","private_key":"00133d03c85e03bcd54ddefc03d9060009ea78ee5ba1f6f335111f47ab8f433f","name":"node14","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","private_key":"ee3f0e3cca3720aa0727efa92a11ea9252c7fe72fe64c8814de2accbb91d049d","name":"node15","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","private_key":"470d12a7459f9fa9f1adf18e94b60340c5c442eadb1329fa871073e64d6bd7aa","name":"node16","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","private_key":"3450c9c68339a76f1f75fb1f770914dac1cfc5e0cb23d6fd703480beb3ddfd4a","name":"node17","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","private_key":"1df10df7cb050098e9713c3773a47962a6cfea944b53b12fd84563c98dc46e7a","name":"node18","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","private_key":"e699fe1e14d46a5a72d5696e397df71ac0d17abf136dc84d850b658e56881c75","name":"node19","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","private_key":"0974ab51554372614954b68ffb0fdde4a82efdc0bf4e6f802dbc3728cb4b5e47","name":"node20","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","private_key":"14ce7db5594270c24ed48fd5881d6f02b9cc6267731612c5117e4d273d3920ca","name":"node21","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","private_key":"32fa52ca7b60e6953e97635659e4a5153688636594be7f560fc5f8468fdf7022","name":"node22","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","private_key":"d28563bbfb6db23928a66e837cdfa794230537066eeb93063ebeff3f531b12ca","name":"node23","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","private_key":"137533f5c2f9257d2a60c22d205407f3cc14c52ec60fc34666b05dcb935178c7","name":"node24","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","private_key":"1dbab5393fba98797db2a32f7d2ee6ad019bbd9e26ee051313e566bb1e21a1b4","name":"node25","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","private_key":"87a7b7028ee1140af69055fb641d23473c44f238544e3cc23e2909a959d1e091","name":"node26","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","private_key":"102d3a405cf636abf7d0b4e4a1fc0a698dc0d4033c288762ce9cc975b91db032","name":"node27","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","private_key":"d8ecd7e813dbc7683f773cf38cd0e344ee9b4e308f12f557b6642eda2ef88ea1","name":"node28","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","private_key":"225f43e03ffb8a97b760538a5cb9cddb61e7a387a3e56e82160300ed8c53e073","name":"node29","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","private_key":"75acc8059053d23505c4513dbfd60777918db43c9713b3577c36836f066e31af","name":"node30","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","private_key":"d6bd6c72597f6ec178becb6cdf6520d7de3f1278f77aa42095d287f45513b1f2","name":"node31","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","private_key":"b329bd7d93dbc0fef82737292076fb91e323da4f34d22a5ee6fe311018203992","name":"node32","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","private_key":"f62b2e6c0ace2c204b4efdf62d3a9e4e41740aaa2a7aee72aa67272b08f65388","name":"node33","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","private_key":"5083c0504c95867fc5a924311192eeb35e80105fb25720516a8af8053516b87d","name":"node34","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","private_key":"52454a2b364cf029dbd0bd0f6880fd3c4a3eea2ef593277ca45c363888b025dc","name":"node35","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","private_key":"822f8bae08da0af5c00b04adc4653e9b425648c538f482224cc7406ed46694b4","name":"node36","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","private_key":"1e41a399b1b77f559bce8b0db22cabd26152fde5eab7c91576e4a2e00cbf3061","name":"node37","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","private_key":"f39163a2c0a70f6eb02436a58c6029082e040ee88271fb27deb0e9c61af2a409","name":"node38","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","private_key":"30358622050808cb05e6c497e4ab00bc0baa126282c0f0bd38a279f15161ebfa","name":"node39","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","private_key":"e96ccd329e3ce59cca1c371e0d97e891c8755d8285c414d227fe2d8dde438ada","name":"node40","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","private_key":"a8af10b8118821f3f7a1c456f857e4ddf50526337a38eddaffe15bbbb383ac32","name":"node41","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","private_key":"aea855db0ccd147bccfb6969c37e5ceb12623a95cde33c7725d51418c2a58e56","name":"node42","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","private_key":"14f5b342ec3c67c89537fc4dbaa64da24b8d7d02242eff9642b680d1923a000a","name":"node43","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","private_key":"b56fd7d35ab0d1f76d30c898f6794ff5399b2d6982c4d5afadacaf72aa535bd4","name":"node44","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","private_key":"59db345b1123f497ab8804ffed255e26dc028f68d9010314f9eebee243ee74cb","name":"node45","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","private_key":"87b0f18d2c52b3f0f6934c09421248a6d0457eab81b8dbd93840877ba7c25006","name":"node46","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","private_key":"86f6a5532361ee4f4511ef6ced21fe2e8d4e12b10d61b8d16f6805d5d6ff869c","name":"node47","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","private_key":"604cbd4183a23b452f0c9add6181effac6084e4411051850ed0bc4f1ae9a33d8","name":"node48","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","private_key":"ada9db22cbb971526fb9a1e050a039ae3bc1b898086642c093f9d2fd1b4a2e30","name":"node49","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","private_key":"c3e1cd6edffbca6121b114763c7cc8d8fce9b4444747af55b56cb111f3803b5e","name":"node50","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","private_key":"e74e4c545f1d04c35176065ee8e6610e9847ba30aa0b4ff9df3d574a9cd04bc5","name":"node51","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","private_key":"d44b65dad6f0fc7d3868207b4d13aa646925f53eef21981d7898ca8eef1f47f3","name":"node52","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","private_key":"5c0b688fe7738cf3e06e8f932ca1986d88f6c00a9f705d50335632433ad7d52a","name":"node53","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","private_key":"8d78762191955f66c6881143b2fbf367eb02b6182eb49c5f11d22381f8e34152","name":"node54","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","private_key":"296788d95df4ddf6af02ab317a50c417d36515453b5cebdae7c71f55a657c7f9","name":"node55","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","private_key":"b229e6aab9cd866a0aecbc7358eeb2986cdf2ff1bcd25ae6d3dc33ad282a03ee","name":"node56","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","private_key":"016f837cc16dfa3e8ed3519599b40bf8ee03872dbe01509e3928f5459be708d9","name":"node57","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","private_key":"fb9bd6643165414424261aa1dfdab87ad7b83e52d9bfcbaa69e1bb116f84b19a","name":"node58","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","private_key":"c761dd84c3923763ca0acfc07e4939b146d57bd6b42efd6c5e8e5c0b63dc1518","name":"node59","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","private_key":"4503d268231fe7b4f60290da3c7f7f67bc51e123b65b7fb48f8ababc2eccbf6a","name":"node60","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","private_key":"c643d7712e7aeffa425505349e837da25e2cae551f446e56a96e5b2df48f2bfe","name":"node61","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","private_key":"cc7a5a2b92089562a184b024a3782da10d925002ca1dac6c95d902ed4df95998","name":"node62","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","private_key":"31d2f152a7b173892132dcb790d697cb779cc886a67355b5907e803ec734a1e0","name":"node63","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","private_key":"f0045a14d36d5d17d8859c51edce3fd7afd083b6722cf6a3668dbd4f1db69e17","name":"node64","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","private_key":"f00404704ec4c556b0ee4cbbc1b8fec0b741d8a587b0baffa9a0ce79648f6560","name":"node65","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","private_key":"5998a146afa95186e2ecf2d1daa4376812bbcbbf22809ba0807dc5e34e5d1e9c","name":"node66","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","private_key":"542904a26056c4d86aafe32a8dbbb30ef4a31b36c81563f47a8ce22145e5da4d","name":"node67","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","private_key":"4feddb131b7fb4c20144641fd72951bf356b4ec190a8a8cb322f2d0819aaf317","name":"node68","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","private_key":"1fa8a1ef0703e81a32dd0faf6d25447a183ecb90d6994f45921c3db0e8dc3d06","name":"node69","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","private_key":"dffd7a3c7cb1c3a0d129522290be15481d609d4d268daa13364cb16e13213398","name":"node70","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","private_key":"c5ab7f8e52d35ba6f3aae971d7215e9dd234f82a3331ca904c2b6b526d2a59db","name":"node71","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","private_key":"07c9b7896ed7f5c9763b72ab6631797941cd615c3ecd431de30169fdbe89cc2a","name":"node72","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","private_key":"da65f19428056c9c512efa6c1e97a409861ab28956b2c9ed0b8a72bba67c010e","name":"node73","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","private_key":"3ea7d8647b5a7f04bdae56288940cc9dc8289c49fcc4a1a79e9d3fd9a6ceab2a","name":"node74","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","private_key":"86dd972691e02a4562fde8ab7cfa9ceb75201e42e506cf2d51c16d9d474bad2d","name":"node75","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","private_key":"cb578a8fabe87c91b214032286af35c973b3f27880dd80fcd1efb929d1dd4756","name":"node76","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","private_key":"d4921582200b69793cc182b16d32031dd9559865007b31b1011d35512379ae8a","name":"node77","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","private_key":"286143c4711912830a900f8a45b11baa1bef2b6b96e9a918484cb95aafd2164f","name":"node78","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","private_key":"48d763e65d8c5b6a83609844cf203d410e1afa134af6eb6ed22a42bbfd55ccb9","name":"node79","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","private_key":"98a9e2aaeb4c53a781d4150faa14cc0ff5f066e7be28098cbc25a0c379be18a4","name":"node80","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","private_key":"97df41163f6dfeb248b196fff24b95edb55e2b6c48c551480226459fde0ce62a","name":"node81","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","private_key":"887a82d3553c5107cd8d6220f2ac36ca2d6d499b8c82b765a17bd6295e9861d4","name":"node82","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","private_key":"b067efa25d200683b69e2fa485be6ac0a6bbc34a18796bc0b0e794d4dadf83b1","name":"node83","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","private_key":"f2b10950651367c628d1675c7a07962c0af4062b2c3c8154075cf61f9635cd67","name":"node84","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","private_key":"55f59b8404f62f76682812c128cde0b37da46140d69661f3de90af132daa04c8","name":"node85","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","private_key":"bc5bbbdd85ae3b09a493f0b43542448acf2976654a249f32bf92eff0d414866c","name":"node86","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","private_key":"f342c7683da21156a1f53ce673f78414f580cdd86eda879596d087439e4475f9","name":"node87","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","private_key":"f9550b9a11e9aece642e0e863b82852f4c5c8cb6044144627d678ce3988cda39","name":"node88","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","private_key":"111dc027f4345175a5a141eff93a8d04d82ec6d67a15d0ed0c53ae7fe954868c","name":"node89","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","private_key":"30caccc4af13ac896656ca1add341299bb51773c44f91f3105a1564abbe84f5b","name":"node90","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","private_key":"ca298279e19e3d8437a361debb136898e8bf05c7946dd3ffdef8d267f1c79049","name":"node91","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","private_key":"d513af6f8087302defbc40f0f03c63b144c07a636b7c5c970e962d445232a6f9","name":"node92","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","private_key":"e5808b0004f64868225ce7362aa1b0d787d6c8bafbf5d08aadf4a804bfa4519a","name":"node93","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","private_key":"68c381bcacc6c4396824a929cd7124a13b8032185de88ce2cc3cb75badc6a5d5","name":"node94","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","private_key":"0d0d4c6da032e6ceb496ec71883cff52efa41a9383d2b83b747d1bc6f8269a17","name":"node95","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","private_key":"53c79eca1a5cc6b186db543273722c0168564d7cecceb76d1433330101f8e62a","name":"node96","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","private_key":"cd3e3585e9c28d16a0a5c11e8efd66671e8cac68915eb6b7bae228e10e867fd8","name":"node97","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","private_key":"60f513f00eb15da948e892d69bec82991bfb0747c9d5879c6c26c2a5a6095365","name":"node98","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","private_key":"94b0c348b1ec7288d57eb195f114f38da5a6fc3f604e8f1ed76135ef26f50c6d","name":"node99","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","private_key":"a6e6ca4e3f494adc69bb1aaa01dfc3dd625d9923fa4c979ec80ee221b83a589b","name":"node100","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","private_key":"2c11691d22adc7bee004f61ad67b543d9ca22c7c65125427e310fc5c8784091f","name":"node101","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","private_key":"1ebabfc78e1b9d17e6fe38508bc354ab54be2a8bf57483b0afe7dc3530533e0f","name":"node102","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","private_key":"9b22a93b1dd1ac5ad34771c2cf183292f9ca7133b4ed8a1d0fceb889d6017170","name":"node103","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","private_key":"b4d7978eed053b73224b969ad03abd7503081764e86f7815f8b650b7ba9a34b0","name":"node104","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","private_key":"18bbd14788534b3f7490b55c2243e84c1ed1d158bd769a47fdc2d8550098ba97","name":"node105","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","private_key":"ff55b25abe67052213c916a734949cb6a98d1ad2f240183bfa1fe694cfa0937a","name":"node106","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","private_key":"406c029264f74f39f2ad851342bc311d4800fe07db744f69557ad9e3e5899aeb","name":"node107","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","private_key":"9f9be5e82bec360e52170374b35e26ab30480bf5effa10bc43527c191d1efc84","name":"node108","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","private_key":"01c46dd80b68bfbc5916277ab36142ff3033b126df71354bc7b21993be4f27b4","name":"node109","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","private_key":"d4ea8e3d466c3fadc709252e0b35240e831250311a3023363aaa2de0d4068efe","name":"node110","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","private_key":"ff786dd6bdf5a54dfd71c73ab93427d94008f2854eec2a87c96223aeaf5a2357","name":"node111","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","private_key":"81d2fd2b16f53fcb3749b3c8575a00ddf39ee32f760cc7e8365c046e364ec849","name":"node112","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","private_key":"5017533627afd71f2684b9ef264ac79ff826f1cbbfedd788d969d9ae1bb87b20","name":"node113","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","private_key":"92a91e558f70fffacaea7b5c86540ae940da57dcb660d8c3e6eb5c7b38f015f0","name":"node114","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","private_key":"91f18de340c4916711d69fea368a4248eca8a13910d576e24ff9125fbccae3a3","name":"node115","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","private_key":"f1e5638e4912ca0ccd446a27531942b75039807eea70118fad6880f5b1ad5ee7","name":"node116","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","private_key":"83bcea8f8c409f9470bca240d19fb29d9fea6cf94435ebbdf0a8faf5f1cb5ca0","name":"node117","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","private_key":"33c3e295cfb9706d4d5e081ec3c220d8c35415d7c256de99511e76474e8c906b","name":"node118","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","private_key":"af0dcfc78e50f0893cd504a3567a8515538bd85a1d3eb72809dd503690d0d274","name":"node119","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","private_key":"8c806f6fed9bc74fb07341b080bc3067c953b5d6093ef5779221924d4ead4bb8","name":"node120","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","private_key":"a1a11eedc4fe78f42dd23b093d9fbcbf1643899eca875296b0374ec0e8ab619c","name":"node121","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","private_key":"15d8362248798e68c5eda882717ee691573e5477b7f0444222fabaaf1a025a8a","name":"node122","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","private_key":"c1d6cf53ce48953f5b6bb0e0b644aaebd16b84a3910894f93c157140c88988a5","name":"node123","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","private_key":"a67b1d8e2abb33c866d215b81af3a23fe0657a9155a8e17754bc0028dcf87852","name":"node124","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","private_key":"b9da682c3a119f650ebbaccf2974166f3162ce600afd50152f95e9be3f688bd4","name":"node125","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","private_key":"a6ca067c4be7a67d6c5b14fe7e0b62a964d844462a6b26a981cb73ffcbb48e46","name":"node126","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","private_key":"08926af18a3a13a1bf786aa6946ab5bde52c531026a8561524925f1d9f0d665c","name":"node127","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","private_key":"793a4b0ec03ee3d4c1cc8fc8084366fc20e5852ecc3aa96ba2882babd7b8ff37","name":"node128","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","private_key":"9d2fd418a2966f748dd746ca5b5f0c3a82496a0a6274355c059d5f48be6870b8","name":"node129","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","private_key":"7c7cfd0cdb3cede7dc5d152c6f5a8d89941656a3e9e560cf993a319c9012f074","name":"node130","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","private_key":"457954e43019a3f3e510a0f818996c28e372410ba50490b5042068ff63f3e17d","name":"node131","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","private_key":"d45a6d15ff3a2073f6d31d9df7fe6778cac0ca1d62aeacec44341aef19924624","name":"node132","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","private_key":"c1e5c2bc35a1030f8bd3ffd9099376d32ca3029eff92b5c79055ae2454a6fd6a","name":"node133","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":false}},{"node":{"config":{"id":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","private_key":"89da1a80c7122d19de9b63637b1f1675ee7e009a5ecf1f6c51cb29b2a09cc908","name":"node134","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","private_key":"e5596012d345aff602e83361bc5fb1f7e3feee7b23782a8c7f0a1c7933ab928c","name":"node135","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","private_key":"91af9b7387bad90d696b549270c0302fbe3805efb01f311e801b317217b92cca","name":"node136","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","private_key":"af83c717380c5132acd3357ec3e29daaacfc4e4a65fd1f5b14479b78e5fb01f6","name":"node137","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","private_key":"2645348387e283c7f69d634a71ee38a65d4fc6928ecc383fb25cea4525fcdad9","name":"node138","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","private_key":"bc25724231b7bb54d17219feff13e1fe8e0486cace91c0cc6f3731a986f4a8ae","name":"node139","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","private_key":"1b90feec9d475fc13f1394c4b39d837fbd09f4c329ef5747d988b17b84967ccc","name":"node140","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","private_key":"392b881dddc671e72fc89ef71b340f19840650943cae22682d6cb6f97570c1ac","name":"node141","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","private_key":"f6541fa1eb8508dbcfde0259a988d0564c192cd25b2051e1299c32cad9ceb149","name":"node142","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","private_key":"59014852ab4f95ef336b10bb7c05d22e54eb0ea453d0f1c56638852ffac3aab0","name":"node143","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","private_key":"45d467a8320183e6e9f9fb0219c71ee08f43352c83c0b2d84da4ae4241b0173c","name":"node144","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","private_key":"3c564ae34741afc14a8ea217a734d5a8bc6d8dfcce3f4943acff14036edbf1c0","name":"node145","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","private_key":"43f552096880ddd297dd590b83f738fa13826e6120ec3d6311ac565b78a252c7","name":"node146","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","private_key":"177c7e7e8e870ff8b4b606ee3bc6f94d6fa57fd6deabefdabb250776939ef9f9","name":"node147","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","private_key":"26c019de3883a787fafed3839e768c71553ec8fe6cf607725f0e2acc80711cee","name":"node148","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","private_key":"943fd9910b9fa6cdb47ec68ec64b2faecd9a56de487fba1b7773a6dd54f94664","name":"node149","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","private_key":"f75e19af5d5e340e6a07d85042608f0500511042eb2e1ccbae8fe8569b9cbc8c","name":"node150","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","private_key":"e400c8293b9474c5aa84b48e37e1f435a53c910af98fd4e1b23ff9bd670bb51f","name":"node151","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","private_key":"f5a6a565c7c14cba96a75712373743d09ba804a9b8332a667492617dd5211abb","name":"node152","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","private_key":"4f592401cb57bcdc263bb96492ca66258130460b5fcb1a1cfafdedef3cee99f7","name":"node153","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","private_key":"97486d2d37010143a830ed6a0be6528a5611fc42962ae80e44a12c9b3399502c","name":"node154","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","private_key":"d93efde40fe67c2f412577aefbc6af1e876bde81b53c22ef6da4a5a23c8c13ad","name":"node155","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","private_key":"eaab112f5381b5b84ac9920fede88f2e04b725398e37a0b1b003442c281e32a1","name":"node156","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","private_key":"f79356978056456eb8f10bcf3c06b107a4afb4d5a8c2fc9380011a7420d59c81","name":"node157","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","private_key":"f0c66841f0adf1a9af04982fcce0c38c5012595de449dd0a8ea97ba06d5e43e9","name":"node158","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","private_key":"cc124633e255f1c6ba0beb16fb978958ed79be0e0f6ebd7968ef82b6d439fcda","name":"node159","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","private_key":"223b2c119cccb5059319a4a0305aec9c1bace6e731215f699cbd4d9a056ec777","name":"node160","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","private_key":"158d4468a6b4e7413f8b1d4112ef2b2c562e6dd26101b022ece2fa57801e6b03","name":"node161","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","private_key":"9b9249eb2418f61bc1e6a582b28e46c0d25eecf549e98414e2ca5ab1d3f5b1f7","name":"node162","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","private_key":"92f63cfcb2341c43aee585f9b965979e49d307de204dcc09b8e869f4e67640b4","name":"node163","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","private_key":"81e7d25a3c5700b592d3ea4cd85440f914f919e65f0a6e55c99ba619a519c70a","name":"node164","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","private_key":"09ab58931e7729bf23cdcb2772b3869d1aacece96070df5790f8343b70ef5e3b","name":"node165","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","private_key":"c330a5f7858f47d6653c52c88207fd10c6c87d8e77c87b9be95165f094918210","name":"node166","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","private_key":"7bbb910a655225eccc1fa6ab5abd3696725591448d5b628656692c1170f1f095","name":"node167","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","private_key":"9a0adb03a36d31dc716a280bc0b0ccdb5a891c5242f507aed5f6c370ea6bca05","name":"node168","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","private_key":"c9271845738bb80612a262956270b72e5152311e2e80fe21b3c7238f394911a7","name":"node169","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","private_key":"1710672c4d27d5363877ec9be4202445a3404d3e16ff221611f0c2d82c34af1c","name":"node170","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","private_key":"fe3ddcd5732357d3e602b35b79a21afd716fadbe7b569e44eb014dd4b944ad49","name":"node171","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","private_key":"85d961e31726c6d75913c901b5db7e115dd67338d9d89584e0c73df8f673a01c","name":"node172","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":false}},{"node":{"config":{"id":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","private_key":"ded7d4f338d0e906b79482b6a79c0a2224820bac1893e3ee083a66eaaebea363","name":"node173","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","private_key":"f2b75f511327f380d86989fed2d67129f32bb0aeafb3aba0250c8e9e5b581d16","name":"node174","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","private_key":"a9bc40abaa967e683f994c9d053b90fa4daa9602fc810cd974a8f6a3629dbd28","name":"node175","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","private_key":"fa312311679e17f36872e8c75b78bd3b730d7423c613f5d7cbcaf653d847419e","name":"node176","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","private_key":"3532d20f2d6b03b910ef2d4dc968b71d89bd0fa3c9a758fd355ec3f8c9b6b62b","name":"node177","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","private_key":"d491504fcc40f961febbbf2089616ac2a2b7cc79e5dc9c01b632ab9d226bca86","name":"node178","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","private_key":"9653af0c5c528f1079ce38ba8e44273a7eed8efe91036d0219e08121fc62ca06","name":"node179","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","private_key":"09d927a912f0daefdca0fdb594feea4e25c384ac07efb663ea46ba893d0f32f9","name":"node180","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","private_key":"b5c4da646e3485b765e530ff19f36c4753764dda9d4aa308fb8d5c3d52d9b04f","name":"node181","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","private_key":"cf80dfc2e5888e69aa7c570430d76fb7a11991c8f8bd4c8dec3e2303085624ad","name":"node182","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","private_key":"33a68fc227f5f745114937915a4678fbcd985ff8c589698f241091a32fd901b2","name":"node183","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","private_key":"ff80b3d224dd48711a8b71840a9762289dbcac4d27cb6c24878fb4dd01b7c55f","name":"node184","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","private_key":"9b8f03ec5acc438bfb8ef1d604066899d9108b46efa0136298d820aad5752cf6","name":"node185","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","private_key":"b3496c97ca4de82c4133936c457c24ece46c36d35193ff6a5cd269701841cfd4","name":"node186","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","private_key":"65f6b15bed8bfb72144314f9aa2a7364bcb356e60cdb0212a7d04a3eb9e2d3af","name":"node187","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","private_key":"fe832e4f1c7485f3906f1807544431a825ca6ff8ea89d3d87a14aba92ba4d995","name":"node188","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","private_key":"50f4adfdd5287853b06a93a0214c09ee109edc00698de65c0c0523e10e7d828b","name":"node189","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","private_key":"e40b799e72dc611e2a8f64d5b8c7ca95535499887a0eb36f5f4f3690097e0ce0","name":"node190","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","private_key":"11535d8be8b31e5bf636e9671c7be140d596984e31eb44adeb0002976fa05b97","name":"node191","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","private_key":"9870e0dfa67e07bbfca9e8eb065c1085adc82bf75d9d75fab9909f3681b654ed","name":"node192","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","private_key":"01d68cdd16950c65e5781ece848e201a6ebbd5097f74dadfd7a5fb007bbcc11d","name":"node193","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","private_key":"7d7d75371a52b4d22411fc3dec135a945466d9fcce8615dbb959ebaf62bcebac","name":"node194","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","private_key":"cdcb88f25a626c1434db6d9ee8ae5934f466813535a8b9425572a888ade1bd98","name":"node195","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","private_key":"70186f9ea20bd1f26270c4a3cc72d7fd6997f6ff1e81fa580ac396cfb8a53d96","name":"node196","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","private_key":"23e586de5f3e3d888e4b5afccbc7bbe9bc569233c4133cf8b4b6a6f722bcbcf4","name":"node197","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","private_key":"fa2860804ef40cd74e911bae08fd20f7fef5ee4d34f163dd456f566b899f18fd","name":"node198","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","private_key":"1552e3359f865f955336c9e44aa94278481ebc3fba1bbac62a7e6c95d3348d6b","name":"node199","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","private_key":"da57c89729140a0f359ddf902197cddcb6b13a00c226d1a8a0975bda02f3a495","name":"node200","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","private_key":"a71ad1e471863026826e723cb60ef8221c29ef9c115f59ec22dccfdbf13724cb","name":"node201","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","private_key":"66b7f7a02087e6dda466b0fb6d05311ce95e179b4baf6cb7dd1fc1052f066367","name":"node202","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","private_key":"f4efac8f64908b896f893bb4b4113b00734dfcbf9aa87245f1aa8e9f65b644ce","name":"node203","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","private_key":"f15da5ee626bdec9e7b303afaff488d87aff1815668f878ea6b1f270c6300ec2","name":"node204","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","private_key":"ec037812b58da37d27db08df00018a39dc06d096116acf7f56921452cf7cfc0b","name":"node205","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","private_key":"9a037c145472a92a10b90fce8fe35501e93af7b73b026641d66a53ccfd3930dd","name":"node206","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","private_key":"14480f714ca25c522c067b4bce766945c9c2e8d0b697eacf9ff286fb0c26dac9","name":"node207","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","private_key":"c756a2bbb4c7b536c169fea0b09c7834ce6ce6f687c4968e598b72606163b8f3","name":"node208","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","private_key":"a837afe73ba3598ea681339261b12f5b9f02f1ce5243d6f7d18c735562b5a485","name":"node209","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","private_key":"6dab6d6b30b7515d850f1f4e7d6fffc75064eafafd86b8754a4000153113b1de","name":"node210","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","private_key":"431d8e4e06f15988a4ea9b3c077ca2b2bfc5b8b04135fea5ad7dee050940422b","name":"node211","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","private_key":"adf12e35cb550ed5a52fb5fa25fe7a6298e71b77a2dae474ebefbf2f9b8aac69","name":"node212","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","private_key":"7a94e705247608b3fe77122138a93f8477964e4a1a5d068091ff655f6ff0acd9","name":"node213","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","private_key":"c121bd7298c0130e294b88e6bb3b99fa0db790e9760b605448356e1fd89a3e5b","name":"node214","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","private_key":"562bd811ced052733cf87caf5888571e4482ae46e14ae1585debfb6b10298249","name":"node215","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","private_key":"8ebd5353e11b993fd7941ca1a936fc21799344607325c2879687b5e90adee6db","name":"node216","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","private_key":"8234acebca52619acf23d978bbc19bf2d8cbbc933bc7e18c7903d4b047471348","name":"node217","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","private_key":"1a4a47a0b83da4f2ccd94ee24a3657f777cc93c6a58b8ec0145586ba2c161429","name":"node218","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","private_key":"5b5aede47f05e99b807a7451cec469c1f77786d45d9f55b5a797b82d76db93af","name":"node219","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","private_key":"96ada7ff2fc583b6dd41941edfff92a81778c698d3b1f9fbf4130c2f7cbbec84","name":"node220","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","private_key":"1616cc42cae550c0104204c1c7f6ed0b3f65da627bd834a2d1239d70cc5b1e77","name":"node221","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","private_key":"1d029cbabb2eaef44889598c8fa2297996a69661d29c14035424dce781deb15e","name":"node222","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","private_key":"83c0403796648d484818f74b9de3c755c56b24f69e3394e062dd55a9d7cecbc3","name":"node223","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","private_key":"3f64513ae7746b16fa9ef3978d1bdf3c87ab4842c75aa3b946385dcdb23a3430","name":"node224","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","private_key":"a9db544f2fa00dc2d658a531934db6efeec93208b76d5b6859e6f0c4abac116d","name":"node225","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","private_key":"d53b2fef355d63448b93647458df0ba5b73bc42492d376377401a568eeb4d81f","name":"node226","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","private_key":"a04acf8d5198d0e7da1a6e9228c8ac6a74542a8d91906d5e83f1db219ae25350","name":"node227","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","private_key":"d5ad27697670f66cacf3e0ffb4473ab4912ed96fba311ddc8af12ad7663adeda","name":"node228","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","private_key":"dd217caf701902c94b57e1eeccbeaeddc4a7837b56d82ae2f034935d2828d222","name":"node229","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","private_key":"69b9f99ba6c47542a17c63be200102194fe3ab24084ea1e684033e68d580b5af","name":"node230","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","private_key":"ead9e2c8c0b3993304cb0a4a0dcb3ebe7c4331a87fee7c70194a3b3690413f43","name":"node231","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","private_key":"96cf35a39c0753abb6cc71c2a23e92fc936169a0600e936611216fd8ec31e310","name":"node232","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","private_key":"12ecde7517662f6d425f22ce7ecde84688ab9ed7fd443de2f309f095857faca9","name":"node233","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","private_key":"bc558cb24210cea0443678c5a9a412b3512b5b965b14df80818039b6fe28fe06","name":"node234","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","private_key":"1f2ab03e6921c321f5f783a3105d69bb69a4c031d50195fb94324c3280d52310","name":"node235","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","private_key":"8f1333ea7bd671c671ba94c4c7c59d6b0687a5c475b21712c6a49600e71f78b5","name":"node236","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","private_key":"e7fceaf57233e8a351a5a97e433d38131867965c883d53430f8f635f0563a168","name":"node237","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","private_key":"c5c6440cb8356bd270d8ce8d543b85c784f5c049b80e951c26fbcc92cfd1669e","name":"node238","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":false}},{"node":{"config":{"id":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","private_key":"64939e66b20f857b3b5c94f6e5f72f15ae524ce46058ebf20c98e796bcc608c8","name":"node239","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","private_key":"9fa335b0c4f3fed78cb6aa4c0137589fe77d15b2127788adbca0633ef881b61c","name":"node240","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","private_key":"a36da338278d776a57dad648f8c5627834918fcaa86367e4aeaccefbb4142c1c","name":"node241","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","private_key":"dfbcc9238ce614f0a4711f04948064ddbd5b2997a19f1e62c8f9636e9961fd5d","name":"node242","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","private_key":"ea0d5ec78fdcca32a257905b595a0c7bc8f2934d088b0f4c695a76927fa9e791","name":"node243","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","private_key":"01bbc4df92bfd5efca325ff653fcab3ac6aca83696f57927d3313fdf03dadafb","name":"node244","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","private_key":"2e16fcbc5651872d962bf9cbbd32cccbef2adac9e86006e4b4e9abbe6c22d7cc","name":"node245","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","private_key":"a26a19f61e9c2c83a632e779651442713ae7026ff3889b0c2ba690ad206500cf","name":"node246","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","private_key":"fd1c4ea6d2c07317eeaebbcd485aaf9267d81f2dc547b2136eba8ed02ae2c635","name":"node247","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","private_key":"a655a637ca80f8c5354e51e46d31d79b36a8a8b44d50e2838a118ea8b33512ee","name":"node248","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","private_key":"02d1f6c1a867e9dd9cf7bff6121f3eb99e7c75866f8fb00d83782e69de6dacc5","name":"node249","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","private_key":"e0f98f6ae876455342403d6cd7ee64b21f5e5d691ed720d81e0db64529d8cd19","name":"node250","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","private_key":"53adafcbccccca52e7bbf9524234d7c6c5874e3a328d3ded48c93c7b07f34428","name":"node251","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","private_key":"b91ef086d245c3849c46234765c2d479c053b5974568062618a768ebb7014b64","name":"node252","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","private_key":"438a2cd1d35d995ba9e35fe1b4086196934e0a6087ca2ae18543512299224b1e","name":"node253","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","private_key":"1945283cb814bb48cbb80a03a2660606e5c5e023e3b8ac887baf7cc912ec5be7","name":"node254","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","private_key":"be6f375f22929e615c683dc9b07e4e2c609a06e07a849a718617c2a0c2ad49f6","name":"node255","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","private_key":"9775c9bb0b01e8a605866b96d386a1f8c3dbba2605cb9f8089c4f85fecfb6c62","name":"node256","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","other":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","up":true},{"one":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","other":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","up":true},{"one":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","other":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","other":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","up":true},{"one":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","other":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","up":true},{"one":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","up":true},{"one":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","other":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","other":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","up":true},{"one":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","other":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","other":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","up":true},{"one":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","up":true},{"one":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","up":true},{"one":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","other":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"c0d1ac430a1466a1a28cb1aa3d29573ccedb13641ac19e6e615f2a96e8f0950b","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","up":true},{"one":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","other":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","other":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","other":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","up":true},{"one":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"29ffd73eb3b36593482208f5bf1b9c82b7f1a92b06173c769db0999d924c8969","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","other":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"29fd4473f1b6c37f8268d73dd5f683a0f7eb64bd793dab2c450c10d8ab0b666d","other":"290fca7596740129fd1a3075bbf56885d8c83381f981adb0fb283799375a3bd5","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","other":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","up":true},{"one":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","other":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"12b9aa0addf45c714ec95fa915294c997f9d73ee4d6ac7832d18d19554ec49a5","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","other":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","up":true},{"one":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","other":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","up":true},{"one":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"4a670fe61711307f7781b3b5a8014fc0e63866efe356a25e61b2e768a7389980","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","up":true},{"one":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","other":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"2f2284537629514837d5c2296d2871d8c4c147719f0ddc28ef7c629efd44dd61","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"2a69e3897d30e0cbe9b6179a55e30eb13c658b284e1dfcfe4dca08a69434df3c","other":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"2af02e62ff3e40be25d22c2f745a505b895b3804a80663cb53db4edd5365c568","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"3a4a300de1009d694bebce2362ca429086ade2f551989d55ba459a68efea15af","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"5fa8a5a29a47694653a5e55fd9b76e9c4f717ecc9b7088a6ec7ee273b291d49e","other":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"2f9f266a3b660fe685de2932de82979bd221706db1e2b954a93edc6609c378d9","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"72acf53ab7dbda90ea70e78d001fe21e7ab88e4054ff0453212e33a26fbbf7f1","other":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","up":true},{"one":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","other":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","up":true},{"one":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","up":true},{"one":"72fae969e2888f7cefa40a544ea66b8c2fd161b1af3ea1f0b8a7012a36188aa1","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","other":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"4af7ccb5c14efcb279502de37f436576eede95efbe5641f12f47e99b2bd9a172","other":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","other":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"52881f1fe0b8e9044a3bc035edbbd6343b9c41d49c0f2c2ca799c2e764489b91","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"5f056f9593be46d3eba4dc8d9e0b93262cd3f00e007c13c4c011d53e7c199628","other":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"15f6bb0640c3ac8ae8ecf10d0d46cc739bb6f86b0c0cf706103aad9f3785219b","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"74062d9dd73e26066fd44e4f6c696f271c9dc6860bdc5ba3fcf447f455c8cafa","other":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","other":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","up":true},{"one":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","other":"14c81fb2fb8fa5a6b47288356ab486012046d09959b9ef4814a09dc3facb4853","up":true},{"one":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"3345e03880c377fc1fe7b6205011ce3e32525cefee5e03161105f1512893f9fb","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c9f391b1c008fbac89791d7135d4d23c245ef6f28258d6ba4f826619da9a54d8","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"52619a523050aa8caa32448e59721a76dc3321dc92cfcb1b05f1cec5b79d424a","other":"50932e2c1f03cbc41d8d9600ce2457f3eacd82c36b61fa09bef512b104eaf8dc","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","up":true},{"one":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","other":"5fd02ea98977d976f5d47a4005300b9865b1dcdac77bf8a98a8920a89b57825c","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","up":true},{"one":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","other":"34fce2b8208c6c8ed005943b3f2cb9f8923739ce262e2040f7ffc048093ef910","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","other":"004e812995bc04f22993466df9889ca1b650bba242cf80bb070ce9564e7bedd8","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"7854fb9f0d2f016653994b9e23033f27e21a2ef186a352c8d068b75ea20beec2","other":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","up":true},{"one":"6dbd2dd8f11adebfbd3ec41289e35e4a8930da1bef5212b152deed8a8ab2f1bc","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","up":true},{"one":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","other":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","up":true},{"one":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"0ea201515867c6793cbe48350f209e69acd3829b9b16b6016d965d84fb6379c5","other":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","up":true},{"one":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","other":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"e8392bdce92a7dcfa5e3196a6e1d4e5dc4814c72e104d3e2aa1f1ab99e2a47a6","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","other":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","up":true},{"one":"458a31b8fdbc42f5e80f01118c9dc041740212c09ddfb4b137c9e7e93ae9ec51","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":true},{"one":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","other":"36485615576c68702382f614054494cc4a40b90fd66db86b9d86a6a131dcc6ac","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","other":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"13d8107c669cc27f6cbc64cef6b2bd11f72db297f2857c2de7323b92632b8231","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"2013ce63483af2990b35f9ecbe5a7653c34b24ded173753575b24451787ed8b9","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"353875d4ae2b9c5cc6cb14059bdfb9540647100c7c3334bc60db2ca2b4ddf3f5","other":"32dd86f3f5c3abe55d6b1fe352e9d1d0cc63d61cfa60b8e70b2ee9db2e28e1aa","up":true},{"one":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","up":true},{"one":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"18f9292fbe6e94ec3df4d0a896c71ed2b1771437e42d8475a7aae63c7992834d","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","other":"b79fd26ce97e98e7432029dea6bf11e48ea9e8f2385dec5c60be0cbd51bbef54","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"b5c764a29cd142acbd83b74989e7d2232eeb2413b74c99ad5769e8e7bec568f6","up":true},{"one":"211a516fb95d093eb43f4716edeb1e6f76ed79d2aeee3393740e244970187840","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","up":true},{"one":"fed15b57e749c5f8f5fdb382eb95abe2ce0dee184c817e557122207f3729b05c","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"2279d612454ff034032a5acf5a039477a11479b9b9a93edc26b61312e8d9b156","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"d5644a72a9adef667fe33fbf5af45214d1dd09331165b24e504e8f5eefb6195e","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"5110c7e54a18df6963919866e7f6c0c3a483045d5ac20fc0dfa5e1926681be7f","up":true},{"one":"1da34e756912c1f9290970e2b60d5d8a88407923c0eac8c409b75f0f470ebc36","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","other":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","up":true},{"one":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"79bd78e5e219d35b8c6f1847c4c77c99e6486db80ec19196e391d7b76232e0c0","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","up":true},{"one":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"21682cd736edfb8b451dfd9c55eb9ea3b7cf2e35cad32537f1f4800644fbf9a7","up":true},{"one":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"0210146e650132dd0ceb8cea779cafc5485822eeeb9fcc17f292af5cef6e9632","up":true},{"one":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","other":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"3e4470c3278bb723d01e1f058cf355bec8d3beca8f589cca6e835d59437591a6","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"7294223c0ab27851df8c25418acf09a28efa95fc238252af8a68390db07b77e4","other":"730749922ce3dcd8e249b988dbfb950c15473a2f6fd5cfe2a8126995fb1dc186","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","other":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","up":true},{"one":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"f048e37427d68c4134a115cc7df6a8924ea95f24e7f2435372ae331e24b5b7fd","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","other":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","up":true},{"one":"194ad126c41c487d95c83b19ed2bb053e4d2ec0605952d3a396dd4304e8e363c","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"aa504681c991c69015c7ef0469902c44fc4e900356b181aa252a1280ffbd2e3b","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"61431b36dd5e311475fd2263650f90731c07b728c1052aedf5bb98d414f07e8f","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":true},{"one":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","other":"396b256b223f346a490844895b9f1046b4790d624af1c43ecae1de318c7214a8","up":true},{"one":"f156942ef74790d1b1b5522f83d7099a4b16bc33f6f4ab2f3e1d7dc5bc6b0529","other":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"63304df8e9960f7a91a6185ce0fb69e7061f2647b9e21cce1237f087ce34a78a","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","up":true},{"one":"3d6baa9da17c330fd34a40cecf331877d4a561f6b4f711cd5adf41bd77d68748","other":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","up":true},{"one":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f0e209f5d6f69f510986085461dde294750cf0e7c2918f01a5c1419ac629de22","up":true},{"one":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"1b1eca7b35086d8b217431c1d6a01fc07dc8bc816196a80015c9e163bed676ff","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","up":true},{"one":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"d3d254a3024a7aac01e97a5f0aff13756741867e599bc94c068f0d1d19ca8176","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","other":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","other":"79abd33d150fdbcbce6f55f3d101608b80e03ede7e4627bc06ba5c1b001538a4","up":true},{"one":"193e52ce29062ceca4f468b49655a06e7d41f6d26ff0cab42c1d896b70bb9218","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"7fa47192bef70d34223a0dad181da09b55e99a1d940e8c48863aefb63c9fb733","other":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"df5ea72c0c257bbea9b43901a1e406bf6055a307d083367e7f1d944e65c2b3cd","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c4844b8046d1c47f699ee1c232d945829105d45af26fba722ce4d0a937c99631","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"4b00ab74395ab00e25470c744b8d32f44152f5419b43540fec1fbbaf491f52c0","up":true},{"one":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","other":"f915fbbce2ef58a4378f62b9c749764e968da46df7bed494b35a422d0359a5dd","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"de827c6af1d3423fa60bf50ca6e12172d21a9fc39a6360e2804f83003710b534","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"a80b39cf280fa80b323370cfc37e8e3ff38de47d5de445c500f36c8cf2390b53","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"259d3874697a0c3192f973c620880b2a86567289f5222d07eb91a51867352559","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"f9243ad864859edd351592d24abdf5c9c4e37f4ffe2ae1201c45f26576ee5725","up":true},{"one":"1e4441309404b0dd8dd9e8b1fe78708b015a0b0278ce86bcdaabc7d2d691791a","other":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","other":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"31edba65e539a9a3c7107a131c4fb4b5a8e2c2d4e2db7874a0116c173961e27c","up":true},{"one":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","other":"4d447ea80bc126e57b9fc91203a310c5f4b242df5ad70d5087d16697a626e601","up":true},{"one":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"275c93677aefd92ab38f9e5b5b4d29f90e809ccaf77b088102071aba26421f3e","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"a749372cccb7001a480b9416c41305bd1d3bc417e15669ae587d4375f2bbcbf7","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","up":true},{"one":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","other":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","up":true},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"ed6570e63fc0e2e2d6290645c4339b70a0f1c14064d286b4e0ba143607bd70c8","up":true},{"one":"7851f67196b812fd6cab7d577b90e254c6f9ea33259c60b5efd91654bd8db44c","other":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","up":true},{"one":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"3f3e66f7c8fc7daae8a7a84a9c90f1ea64faa43930f36fc8f11e2d7b751f8ee9","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"def4f0b988942a8699f6b500cc2531c7dea065e3dc5bdcbeb26bca8f00e1d3a6","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","up":true},{"one":"265d7fc553fb8dc016d7c6ccc31fc372912a11e9e8da0e5822e371a91d82e857","other":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","up":true},{"one":"a485db6ec1929aaf695a84294f52905aa602584954e9ef71b4e18f7b847da31d","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","other":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","up":true},{"one":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","other":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"b8a7578a22a1e9963deaeb7e414137bee0f4590bcb93d327e9525d6dc03b81a2","up":true},{"one":"0f5e34b25f6851d0f3b572c64420de0aec01754bea0854bd7e9910b4b1cc66c3","other":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"604c6bfab4f5d16d5b786318cf8f9e0197fc18e5d8a8e6f4fd345e653d2abe17","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"1d942c85568f640497c46a9bd5a9825bc6fb05571203a3f0f14a3032602d81fc","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","up":true},{"one":"167306fb0e24ddd775c2ac0722103ce5db98bb0ef60159b91f584475d34cb5bf","other":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","up":true},{"one":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"9390ef61753fcf9dae5e585a85650287fe1f792538721a2cf767adc44c5e7ce0","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"b45d1aee940e5d2c71db22e2afbe908d5967e437fbb5bd051edea86ea4ac9d30","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"88da9dccda89c111dde40318fd1e5239e77b670f5a1b88a3e9320b7350885e31","up":true},{"one":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","up":true},{"one":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"4fd6a4b99b1ba76775594673421c8eea175c114519c8554798c2c364175bbaae","other":"4cf655b03778bcb41c32664f13168dc32968354468c8aa699de52b43a2e0dc7d","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"d7abbad732948b66476e1833f0af6bb6250dbbf4ac71b9c75b4fc634b617e8d7","up":true},{"one":"9a82d22b29c88eaca2f20a62e9e63675904065e72c70ce2fbbefc0c9d2e53e90","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"42d403f4ee649ebcb94753e065391afd0b4da995a2628696afdb4b851e9f3774","other":"46c5a266dd46041a62f21946290aad736d2298277bbbb16b1efb4490d9d31fa8","up":false},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"4f90f53754ee50357491dbab7c3e6748b40133e3339920b32f4c3457f4258477","up":true},{"one":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"daa2c427e8ecc566e634908fb0d47077d8e79854bf884342c06c4bcb355e80e6","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","up":true},{"one":"c98d389a6d8e6eb5a1eb5a6f235857d5d939d30e51c16d80c039c9e0eb2f7eca","other":"c883e2850f0a901af58130e87c4f81d898b03be8b88b580ae7075e6c40b33d8e","up":false},{"one":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"89ee628583b6e0345ceb312c2e2cbf5ac410eb00531be903a4b94b60b639993b","up":true},{"one":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"b4c7555a38d1d4e3bd1d01bcc47a84efd6128e8cc0fd803362da8b341f984a4d","up":true},{"one":"95e0529227286d442cdeeed428614f99c19f9223426e6f6cefbef2d9d47ce96f","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":true},{"one":"8c615fbce8dd93846d810857d03235291732e4307cad0e66ffb23f053d2f0ceb","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"ca81f50b5b4921ef7f584972609e1774da124233ebde0bf8f2ca8383017c8a13","other":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","up":true},{"one":"cb69f673a54a75de300d1d1ab989caa04579504cbcaf78f03bc192c9578ec5a0","other":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"9c01d016aaf11f9e7b048ba10cea3c351d9ab5c8c66e8605f78c06772708985c","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"b310299bef4f4e84a1ecc960143e4b1bbe98cd4eb8352458c477569ca9994c20","other":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","up":true},{"one":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"4019ce1dc667d90a85021b5fbf49ad77c1de7fd3443a40a17bdfaf5175efa1e1","other":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","up":true},{"one":"9c0c7b6da33520440b181a5fcc30aa8a7576ec9c6f64acef0c9525d05a2ee393","other":"9eec5d5357732a7acd26cc8aa0bc65f6c6069aedf4f3ab4a6790c7fff6bc2695","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"670d1c31407b4f34bb955031e9a3ab7980273155080b459a082687d53a3b42a6","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"569567603f057518a9dade31f2d12c57c5dde05ee50586ef0f0a6f98f4f63660","other":"571638637156bdaf92d9c715647a1cf64e91877c2d998658b7c6cd27522271bd","up":true},{"one":"abfabc2964ce2f7b8b3702e897a8cc83fb0c009d5af9670b889db582e57ef7c1","other":"aa889f0faaec1a5b7033151ce9d3d68466b128ff81dcb7befc2ce885d9236c77","up":true},{"one":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","other":"1d9364dcc19e9c94459be42a8474207806813d55ac768ea8e74228fbd73be591","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"05e8f826e49722ce09edda07f9016688df5032bc0183589e3c94afda6dd63074","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"67831469d7f9b779df4318cda9d4310c53fdd66332af3740e654233ceb3fbcbc","up":true},{"one":"0eeed90814e9408c94e81296f7b681ac18edacda5eb611af7f69306524f188b8","other":"06aa2f43956f978abe7b8f8f78a5a8cd59decb66ec54b7c81ae50c3752798c5e","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","up":true},{"one":"043f24ce87fbd01f6f663f323ac6c156810a67b12efbec2f219ae9a882a4bd16","other":"05ec2c85c83bbb8edeeba98fd2ef4b765114f5dc36a88175f5017c09e43b7a5a","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"dc3ec6529cec19709403e473d4546ba07f7aaaaec5be7cb0618246a4c0458944","up":false},{"one":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","other":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"237459ba37141f18b3cd40f5ec9cdaf6789fb87aa4511d489fdd98a960ef2883","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"245495250d38095106022d3fc905eb7eb6f54adb2cb0bacdda0b305974eaa50a","other":"2e4c8c371968f3a3cea2e2c1c9bc45f8a0cbed49a7a1fbade17ea34a6e5749cb","up":false},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"ddf8ffe61fdd1440ff2d50d42619d52eb125ab8aa1e8e5ce16274cc4f4728b19","up":true},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f5dd00d94488f3387d64ccc2115cd91e5073c06de36d195a5c1a95db23cd5c68","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"759eacbb4bc23d8f6826d5ff3d38343e4143c973488525ca747e66e6002e2364","up":true},{"one":"86f71d23eb4efeeed4679be7a3d0f58f98b83d23b3e0a8b73f60f1535b51f25c","other":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"af5fcb3714f6da5fe576fed6312f59042cbaa54ac8bd86e7afcd0753743487db","up":true},{"one":"4a81ee929074bd6d9932fb4d970f5207db8680bda0e951aa72a6bd64df45108d","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","up":true},{"one":"d8b0425e4cb5134ddb2de5c05e0ae9b861bd67409c1446ca228318f79f5dd1f6","other":"dae3ea40e4e6e040a4740a614c99ec6b9e644302135cf347ea6ec9ebc87a9f21","up":true},{"one":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"99aaaa7c98113955ecc0163943317f6ec08ae755e96c25c9f79ca1f529c60587","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"99dbf361b67d6c370fd4f201b059e93da50dd88cde2e25d0bcf3c73afbf13535","other":"985c14910d922bbd1556c30620e3ab72170da6553e658dd3806d773a734a1c93","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"ecd2b502d4e9bf77369c62d1142a9fb4ab1071e751cc6971e9e381e953b0fc12","up":true},{"one":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"c64f6bca15d4ef21a37b69c8f8bdbbbfc34e2ce0fc612cbc6a937339c0ccbbdb","up":true},{"one":"5fab772fff883d04cf7e4713266fb1e98fa1746e12faeb04e87bcb37b8b61187","other":"5c5d90a825221bafb2ab726f90422c9a59f9bf97f181c0a2887db2a531798048","up":true},{"one":"bf5ac6f9b651895c8d75ab3ae7994f91981dbbcdce25a7cd718fc996da96946d","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"7ffed78e11c71eccfdddf6a8e5e367831b26a6b11e4d3b60c5b9fc50f4bcdf33","other":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","up":true},{"one":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","other":"14418557af44e33fc8d46369426c3e2fc91622cb08779b3fefce706969ec2163","up":false},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"fb93417c597050f8deeb3098475f6cf0d213926332b59c25a538c1b4e6af89c0","up":true},{"one":"e4c3fa0700516da5650f794067eb1c90ba7eaab2b65019bf34552c26f8c1d9a6","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","other":"47f95708475c9d61ff2016e7707c4a3796f6c87313bd1d2bf91aa620113ba5f8","up":false},{"one":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","other":"c7703c4697637f40a50a5d0b656c4e54010ef1277b64d251ccd0752512e246e9","up":true},{"one":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","other":"566eb2e022a83d49380a94cf17c45955f47faeede4b23f97d357e6e7d7152dae","up":true},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"ed1348b4037004b61bd4d6f9be1648112f835943a3b997b91ac931301311e007","up":true},{"one":"c3f356325eb1e61f2cfd8d80d085fb144c6887e1d710c9d133109b84b823425d","other":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"1a833a4918d6f4ebc0c39ba3bfd4e9de16bb732cbacb963ff58ad3d3198f1336","other":"1b7250dae1f2b07504b381d28084b751a26ac791a1ed842ea5746826ab85ba22","up":true},{"one":"7829673eec0b413d62bb06184e740042e252d3b68b3d1cc174bf01e32f87736f","other":"7a4118d2ce16e8258cc2cdf31c5891945e3787c46c0836fc916601584609b7db","up":true},{"one":"1e42fcbd6735744e505f12f6b0858a9fd17c0a7736a69ab0b969245a3cb1d6e4","other":"1d07520f0ace85fd72f14c881f3d6a5511902b20b6e0f78d2a261191c072ba5d","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"1d5fc65b4121cccaff0d2a853c6bbff0c10b4ec28cfc5ef5cbea8bc28bc4cbec","other":"1c982d886cbac7e6ac5e786a27ad2f8bd42908fca94358cd2838acbc20b5fd31","up":true},{"one":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":true},{"one":"1a02108d9149739be6ba85ddd1e8a3961adeec38f77fcef95ab57f8f2f39f4bb","other":"1b869ca5aec1ff0c9980b06b79084019752fd4557054e251c0091ee5d2c7d478","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"86128689b03706f9a86baf4753154afbb0c535f84089039ef5610d82fb969a6e","up":true},{"one":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"7de7eb0b73f3b02b998e592e0fc51b26c0c3ae6695d41897874d2a3d8ce3554b","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"b71052b072cb98fb79151fd0c6044828e535a0547cace931183c7e4e7f227698","up":true},{"one":"9fee945c89d6bb59e77a24183c2855f4eece0b5d3266f750ea95483eae1e1871","other":"99fba7334f47bfcf21331d6179bfb2eee2ecebd1ea23fd829c542844b10ed974","up":true},{"one":"b60deba7c8676305b67af41d2de866bddd72edc0667d427e51fc3f2e91412b45","other":"b4639751d67db0b32ad1846996fed0d5c59be76b77efaec5f66e64df35eefae8","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"ceee9ac63786ad68d884f5d018248ae1b7b60f0ad434776d29bd4dfcdc0f04c1","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"c8fe626c60d6cd15912a22d2c5872f10a8f8aef5b6f6b2f1070edec6670bf8b1","up":true},{"one":"94aa6cadb94dfc04e2ae3150aeeaeb73b6fc483482156fcabdca4c6596eaa098","other":"96b6ec2cda7c9e962bbc97e7916b92d69b112265c4456d30dade806e09fea62e","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"2fd800d224f124e47038bf140ebd486f1d0ab93169c998d2dfabfd1d3ced96ed","up":true},{"one":"2a2253ec638947fe40b97489b2e2ec0df26ebc77d202276c1d208a3c802c336e","other":"2e9f7d37106b59d6f411dfa0392325d1fa279fe45c18a101e32ece6716e88946","up":false},{"one":"f3d3ba20652827b58c605a137e2f07daa5d139804eb4a9c4270129de3a0de759","other":"f1fcfc064446a432ac7a21efc386fa3d053d0ca4540fd4ddbbb253ec11f9ce94","up":true},{"one":"42c019ddad2fde0f0c7f5041eb584996976844f8b2e08e20458437578d0257ef","other":"43afd835930eac91c0c8947001dd60d8da9112c19cf3f1356589b58b48962166","up":true},{"one":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","other":"6544c4a403d9809697420ff9840ea9de0c9ba6491de28dac288db6257f2dc218","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"887482890b190505bec49838e400f3f1ecb261039ace70bd60c368be94131ee3","up":true},{"one":"388d46d6ea3fd92aa959b04d597ff1096d6133f171181c8fb54e52935b62d33c","other":"3af3bb6c4343a19e3c0f9a89697cd70a3c79c64b1e40afa59b188c5553eed567","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"d6d2d35b3819e03b39d7146c4dd1b53fb7b70681c8860464650d5eb2d09dda2c","up":true},{"one":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","other":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"0592048ae4e6a3000f36e8e1c0e1328c26c0d4bb6369d6cd867a08d847dacb9e","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"03f5f1be5c1ae35469333a5b08622372f65ef8f233746afde56d2647c5273630","up":true},{"one":"1566e3c8e2873d2fbe0f1e9eedbd2cbd5c69161a461e37a48fdfb11d448601e8","other":"0f81caba7d2f752fc670829f74565114bcf10c5b97d7f93252b467d0eee278b3","up":true},{"one":"c8f9cc1fb3ec871e2ce03157f90cfe1c3b01a503c30afdc71d0e8b27ba3a8e19","other":"c99c6a2a2fe7f4613c8d918404c956eae0a00fce544c9eeba5da640e5e958874","up":false},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"4a828523731caf47f9aa2dfa20f8a8895e9a6562b3a034574639a229a733b4a6","other":"487edf32027381256a864bc2e9bca175f7216cc1234731bd4dc90d2cbad6975d","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"77ec3a73ce1d597d307e87ea8d026baae2a7df4d288a657f240eaaaae7fdb456","up":true},{"one":"a6720426faa1ea7e2d55c1c5ad05ba2e8c534d120ebb5e1375cf769d73191708","other":"a03380e51f365445107b59009eaa9040873968cae477be5602efbbdf4a6414ec","up":true},{"one":"57d57ea21e4635857370be02618b158a2b6ed0a8236c67c47070ef41410b3cc4","other":"5571c936426702553d64564d56a909c628a8233ed436acc2a3b9f850c5c6b6f0","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"92325e52babbf2b8ae3c37beec7e440d11efed2d103befa2c4a969315a2eab56","up":true},{"one":"7dc63c8146ed092aa4c9539abd112dc3a703631e364a62fd74b192eee5778123","other":"7471be56a2f617783d5a1ae4390794ad24f453259b7c1f8f65be8f71c8bf8bf7","up":true},{"one":"ad36b802e9b01727e516879c0055e3c46b810845794f7772ad85e8062111b167","other":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"ae715a40e9bf50b4eb954c6b87efbf1a6e7abc3da6d84055e4591aadf5bad5c8","up":true},{"one":"1835f62fe3889f43ba7b4b577869ec764e96fa9a051f1301fb96795daa8b0755","other":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","up":true},{"one":"c15d13aff7f5694fb8fc2a2154846ac703064133feb632e28830777bbfc7c016","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":false},{"one":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","other":"edca23c0fccfd1ec66f4d39bb129462776b9091c2337f6afbfe8737a0ebc0d7d","up":true},{"one":"bfeca898b1755a001eb0bcf8f5ad5713a550d0597f99ef7967ea4e7add8d3e81","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true},{"one":"f644c73e2c7e29dd45506736ca4a0c2cab3f8294c01a6d5decc193cb2d19a473","other":"f5cc76a5a77d79b8f9d3dc2eb53af5f643583aa9392b361aa9578cdad81fd4a5","up":true},{"one":"185a7952985b8efef8ac8ee37283921a458a6a107cba0f7fa33da7480b05c4cf","other":"123fe1d442c7dc905a7206e712fbd9cea640295a6823b39b1945629ffa89e895","up":true},{"one":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","other":"af303f61e91621224d5968e387946d4e1dbf76d1e7ee6f8f2ae60991154d3734","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"c7230d8d56b65a66ab721a8268ed436af78210aae7d068cc2b8afe39b6e61c81","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"bc08af284ab661dcc1cb23859271590e50a09ff8af8073769c812901ea0b9080","up":true},{"one":"8163eebe696123817a6d998d7781612931df6fa2fd0293c0d0dd395d031c53f6","other":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","up":false},{"one":"7d941474f90981a03c95af4cf68be163d01a317e202ac0db82e25f46fc3db8aa","other":"7d45f1e91bcd683d870422b2f591c76f6ab07ff4b079f35c280ce46f7fc364e1","up":true},{"one":"3dca1ae488cc497fe738c630465f987b419a5bb259fdfa17fe7130e238ca3022","other":"3e85d2d3d6750f84500fcf523743e0c242943e69188cb83114adad1787e6c089","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":true},{"one":"e67d72c8c72bbc7bec1d4e936d65adbeab75d1b6cafdf2c39e38bfc723cceebf","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","other":"67a246540c1fa19a0856cf5a99480a3826fc91e125b3bf5ec1e47a2c5aff54be","up":false},{"one":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"df25c443ce1a7b63fe5d89bffcfeb49366a623525660fde8ea509a1934aa050c","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"fd2df4df8f5f7c7cce198cdff07f2adc0e68b646fcc046363d284635c68bbb93","other":"fa7483c3b8652029a3c8599ec3cc1cec5a75181c564a7f6c50094370d43036ff","up":true},{"one":"e44b5f4a563a36e50e57253dfddac4cb5a92137f615f46f638995b4b18863f3b","other":"e76a40477e69f637ff70f1bf393b1dc96a946384340b341d0be97ba01dc12660","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"e6491ee529119721d2c1ce16d220f5d055ba35978f4d7c66c4ec2e3ac36183fa","up":true},{"one":"e3c95a82f373da4522533252549c1d68b6f7621a887feb66199cfd4b7a35b6fc","other":"e787fd35b438dbae3d0283f7181fc4afbeb6f333201ad4cd1b46bf7094a6a85f","up":true},{"one":"c4632e164170d35e91fce46f660265f73795f1d840effce5ab2aae18c73003d7","other":"c63e796efdc44712403199c11c3e5ff28e5d6a4d9ecdf3e95620fbd6afb1bc2d","up":true},{"one":"ae6578693ed933e36a7f499adde340c79bdca0f5f57334dba5646bc1e4d7b717","other":"af358f626738d2e5d17060abbaf24cb0124a48c5edb8f3baeda30bea7b403dfa","up":true},{"one":"d8222a2c177f0cd17baae28327af5c13f2fb551dd01298d17855ce7f6f4f6189","other":"dc86cf92a9640712455824fc7e1eabb939f60370d1be8fff55586c4aaa8b3331","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"d68f504755b48f8d41570169dd3544ef1caea2ab1bb334f8d8c5fb27fe816f01","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"8ac85afde0c46f53269dc42863e9599cfe7ed0ca3222e3718d83ea6481947ab3","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"6d219b0ea4a1620a7ba051cc478da6df9ea443e87dde79e963ec789a5bad7459","up":true},{"one":"8c89e181c6fb18078b404d47b10c70d57d6643393505ed8ac88e63236ea224a0","other":"8ae6a3d0cc665664aed35acd396ef18f642afd2b1e1e23817174b96bedf26793","up":true},{"one":"d3fd74e6049dbeceb5b78ff4681b000da5ad8a3860d4a1070541b5f527d2cc84","other":"d6f37555e9f35a3ef3b8b4d5c18cf0702ed99c1c8b5b0a8554deddcbe542b88c","up":true},{"one":"9461928ad83c196e6a018ea2af138488346fd9c64147b544287e4473ba95ed90","other":"9294e5b39a1cd4230400e033da1ac1f79a4025adab41ce8c0e0e47dda2418cb5","up":false},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f4e0d91ca58ed616918bf268565c2edb4176293e851b8d29cbbda55bdc608534","up":true},{"one":"6ea59b849a9754c022219146efc27fa6561e5aca8338a111847259695198267b","other":"66100e4f9d103d935164f39ea3f0332708f3825ebcf31ac6f8c9714c75a50860","up":false},{"one":"f78a54ba4b3fa75cdb542bdcd6da0d49986a5f7e7939959a51b3b48a87605654","other":"f4eee71a143722ea8288279876bf5687c1ed65eede0129e987e53f5ec76d8543","up":true},{"one":"aca1a0237ccef04bbfff4359cf12945880e485eaad810fe1bc2f2569cc42fea3","other":"adfc03118406bc5af4e3f3c6c89c3448c3fe4f9df20b15bcca9bbacf58ee5457","up":true},{"one":"baf32cface953bd22141970b691567ed375f06043fe31de354598fb4230fb0a3","other":"be0ab3ddc656568900d8e1f42394cc942464596b7565db40f6c5a0c24ee942f2","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","name":"node_e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","enode":"enode://665ca8f57d847b22e62b829c7ca8327fc4a01497fbf18ce0214f19a4b405f2fd118bdc8d27a509942be90c4afff8774dc02810508099969cc215322120c6722b@127.0.0.1:0","enr":"0xf88fb840b69f6ddfa1a4af418eeffe8589e24339f2fdbd6bf67d70b7cae0a2096864dfc82dccb22867e1d5a9145d71caadcefde60e887c16a42164c3db6b4770bcff210b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103665ca8f57d847b22e62b829c7ca8327fc4a01497fbf18ce0214f19a4b405f2fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5oEkSHKLS9pZYq3OsXB7KfZh09GmsszV+Bg8mh9NAbY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e68124\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 48b8 741a 26ab 08bd | 126 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n001 7 81a5 8402 9464 9257 | 75 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n002 5 da36 d3e9 cc33 c603 | 27 d408 (0) d700 (0) d209 (0) d302 (0)\n003 4 f6c0 f1ed f215 ff75 | 14 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n004 4 eff2 ef99 e867 eb68 | 7 ed42 (0) ec90 (0) eebd (0) ef99 (0)\n005 4 e0a0 e09f e2d3 e277 | 4 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n============ DEPTH: 6 ==========================================\n006 1 e471 | 1 e471 (0)\n007 0 | 0\n008 1 e64d | 1 e64d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","private_key":"c62579f0a0c6aaaaa7a8aa18a22d928d27a2d496e9588ec36573b5f174136358","name":"node_e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","services":["bzz","pss"],"enable_msg_events":true,"port":33261},"up":true}},{"node":{"info":{"id":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","name":"node_14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","enode":"enode://1c9940e663ec6a7e9bf3e8add2faed3ad8f989ef1529cafb7f37c82a208f43d00f4ba05c1ea62caf472acb15c91b3587c96849c286efd4f173f438ea2b45d32a@127.0.0.1:0","enr":"0xf88fb840410f25aaf4a49487580fbd3c098fb137c2cbccf0c65806bf66715f0af1be0a5f5f5b20d60466ba1fb85cb219d6f9f1a7b216cfe6486aa9c00152e38dc2d1e66b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021c9940e663ec6a7e9bf3e8add2faed3ad8f989ef1529cafb7f37c82a208f43d0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FISfgRryDOGfspQX0gwV/BbaHkWuvfeVosbMtnHkvaw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 14849f\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9257 eb68 e681 | 130 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n001 3 44ad 4005 741a | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 4 2c85 3a62 3728 36b9 | 28 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n003 7 0e3b 08bd 08e5 08f8 | 21 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n004 6 194e 18e0 1add 1dec | 9 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n005 3 1049 1070 138d | 3 1049 (0) 1070 (0) 138d (0)\n============ DEPTH: 6 ==========================================\n006 2 1686 1784 | 2 1686 (0) 1784 (0)\n007 0 | 0\n008 1 140d | 1 140d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","private_key":"0ce521739058eb06cff2ff0e748a604866b37fa96e7a559c5bf7cabf4161382e","name":"node_14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","services":["bzz","pss"],"enable_msg_events":true,"port":34017},"up":true}},{"node":{"info":{"id":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","name":"node_eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","enode":"enode://0057d96aee5b09baeb627555fe6299fdc637bd55f9be2ddfc59faa67cb940257578d1df147fa29d0539d8eec0fc0d2786aa7530aa346ceae8ee6f8e72d1fb052@127.0.0.1:0","enr":"0xf88fb8405bf3c589a9657ead2e83ff8f2cc355982f3f594e94903e9e6ac19daf8a03e1b84a3d1c607e264646ac31a086ef73bfee66a4f95df458b208a93f2a5441a7607d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020057d96aee5b09baeb627555fe6299fdc637bd55f9be2ddfc59faa67cb940257","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"62hqaG/XDkFlnMaewNtT0VEt/sI4kYr9ClFdjOF31Nk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb686a\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 48b8 741a 26ab 012b | 126 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n001 7 a616 a970 8402 8074 | 75 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n002 5 cc33 c603 c2d0 da36 | 27 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n003 3 ff75 f1ed f215 | 14 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n004 5 e09f e2d3 e277 e471 | 7 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n============ DEPTH: 5 ==========================================\n005 5 ec90 ed42 eebd ef99 | 5 ec90 (0) ed42 (0) eebd (0) ef99 (0)\n006 1 e867 | 1 e867 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","private_key":"37e0f62adb81157cd9de3310d81d70da17cb3a0502320958b7c6d9ca1038d8f6","name":"node_eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","services":["bzz","pss"],"enable_msg_events":true,"port":36177},"up":true}},{"node":{"info":{"id":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","name":"node_9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","enode":"enode://5684177873a4d0e494fceca55b1a36e1a8a19025e03e483ae89cee9173b38082137fbfceb506946ae900a3cbc47697c7ba3c5bd553225e0e76ff5ce7657a7bdb@127.0.0.1:0","enr":"0xf88fb840e67f1444113ce4de2d80f4652cda49192b5c1dee37c8fb129cc60b1e655af7c60190c9a804b2498da20b36cf8aa01e2c492357464bf092615a60192953e13c6f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035684177873a4d0e494fceca55b1a36e1a8a19025e03e483ae89cee9173b38082","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lGStjaGl7/3ANRdC3/+ulB/9n6tGljeySRyuzlPFfcg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9464ad\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 741a 4a95 4b79 012b | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 7 c603 d959 da36 d3e9 | 55 d408 (0) d700 (0) d209 (0) d302 (0)\n002 5 bdc5 bcf8 ba91 a8b5 | 37 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n003 6 8ea2 8b43 8358 80d7 | 21 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n004 3 9c8e 9f7d 9ec8 | 9 9b8e (0) 9959 (0) 9948 (0) 9f0e (0)\n005 2 93c0 9257 | 3 93ea (0) 93c0 (0) 9257 (0)\n006 1 97da | 1 97da (0)\n============ DEPTH: 7 ==========================================\n007 3 95c0 955d 9518 | 3 95c0 (0) 955d (0) 9518 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","private_key":"a5dc0083f0aaf88eee5eaf79c81465d05f0ba64c386da9145ba4a4a3f5c8d143","name":"node_9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","services":["bzz","pss"],"enable_msg_events":true,"port":40977},"up":true}},{"node":{"info":{"id":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","name":"node_9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","enode":"enode://0376a4d936b21276f20e6c33483aeaefb1d89d83a01af38405c081fd675c7c8b1d93cd7eb661bee8fb060ef4f98f6b75eeffe191df26a19f18c2f08c94471f6e@127.0.0.1:0","enr":"0xf88fb840a3a1a51f7bff86552a58bbd5dda6348d6aa82a599d96adbfbf9f19e93e0eace7305ea1d01a495196a928bb866ae512f0244f06e2abaa0dfc679bee3fadec82e10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020376a4d936b21276f20e6c33483aeaefb1d89d83a01af38405c081fd675c7c8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"klfck0378XRztwy4UzPG+rZ+6bYiimRldsT1clPxAE4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9257dc\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1784 1484 08bd | 126 5987 (0) 5814 (0) 5bd8 (0) 5a8b (0)\n001 2 e681 eb68 | 55 d408 (0) d700 (0) d209 (0) d302 (0)\n002 5 b3f9 bdc5 a0c8 a616 | 37 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n003 8 8ea2 8862 8b43 8358 | 21 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n004 2 9c8e 9c21 | 9 9959 (0) 9948 (0) 9b8e (0) 9f0e (0)\n005 5 97da 95c0 955d 9518 | 5 97da (0) 95c0 (0) 955d (0) 9518 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 93ea 93c0 | 2 93ea (0) 93c0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","private_key":"c15e326cf8ee6333e5811786737f8322f412341ae09e5ae9917860bd26ca1947","name":"node_9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","services":["bzz","pss"],"enable_msg_events":true,"port":37221},"up":true}},{"node":{"info":{"id":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","name":"node_08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","enode":"enode://ee9d7c5a65b07eb7d05d2621c99bd374c33ea4438206d3f07d2a6dcfe9adfafeebc06b85d8dfa9ab05c74b2c0295ffb280931ca84b185dbb6ed924fd6be61f9a@127.0.0.1:0","enr":"0xf88fb84032fc3b696637e089700dfa3a41ddefe8e8a6a55db4660a332527484de910804419abdb982ab9fb545f5ee12c11f033e48e66220126f229aedcbb54c3a789b6d60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ee9d7c5a65b07eb7d05d2621c99bd374c33ea4438206d3f07d2a6dcfe9adfafe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CL0eBJhZtKfIB4ypdB/j2qZouf5HjaBtGkNc1VZrPhE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08bd1e\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e681 9464 9257 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 2 4b79 741a | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 6 26ab 2c85 2a50 30fe | 28 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n003 4 1fd0 138d 1784 1484 | 16 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n004 4 0314 035f 0111 012b | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 3 0d1c 0cfc 0e3b | 5 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 0942 096a 09b3 | 3 0942 (0) 096a (0) 09b3 (0)\n008 0 | 0\n009 2 08e5 08f8 | 2 08e5 (0) 08f8 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","private_key":"eeb1d4b4ded34ed420c6f517fa508883a73d457008f055da9edb7156e78474c2","name":"node_08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","services":["bzz","pss"],"enable_msg_events":true,"port":38971},"up":true}},{"node":{"info":{"id":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","name":"node_012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","enode":"enode://54002fd97799e33da3d495d928026863bbec17ed7e7d6ea78725e5259435c2740cb37de72cb4c58f07e09869598312f477b7eccb62b46fb181ba49cffd1bc315@127.0.0.1:0","enr":"0xf88fb840c5a8e2adab6eef8cfcdbd07f1a0fa37ae261091b64e83e95a4e7436cd1c39015121dc7fe55ccbd229c0de2f7ceab2ab9b1c6f500bac9380f6d792dcbf80c555d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10354002fd97799e33da3d495d928026863bbec17ed7e7d6ea78725e5259435c274","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ASuieNWCaRJBh1xMFOrZH/85g+GQ332bQ63jhOhMEfs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 012ba2\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 eb68 9464 8402 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 4 44ad 4b79 741a 7660 | 61 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n002 5 2c85 26ab 30fe 3728 | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 4 1fd0 1dc0 1784 1484 | 16 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n004 5 0e3b 09b3 08e5 08f8 | 11 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n005 4 07f5 046c 0594 0561 | 4 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n006 3 035f 0314 025d | 3 0314 (0) 035f (0) 025d (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0191 | 1 0191 (0)\n009 0 | 0\n010 1 0111 | 1 0111 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","private_key":"8c41148ea8aab694bf31dcfd89a8271ecfb228b4917b2e2d119d11e64ffe2eed","name":"node_012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","services":["bzz","pss"],"enable_msg_events":true,"port":33063},"up":true}},{"node":{"info":{"id":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","name":"node_025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","enode":"enode://789950b2dbebd332a0eef5b3bd998c4a7cb7b2b5bfd38dac2836a078eb6322d32967e68fcc10ab9841df4de5e02ffa4dae77e7ec75235fdfb542285073464c68@127.0.0.1:0","enr":"0xf88fb840bde2b58110c1cdfcae19192e9dc65d42bad215e4fa6ede43f8c3bfc2fc4fcf0e356406d032ece99c466696adf702d2436aa2abf92b0f598d3282aa2974487cb60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102789950b2dbebd332a0eef5b3bd998c4a7cb7b2b5bfd38dac2836a078eb6322d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Al3h0uxSnTp9owLu8PjFSZZhbUDJQMCVbUcP/CoAfzM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 025de1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eb68 8402 | 130 d408 (0) d700 (0) d209 (0) d302 (0)\n001 3 741a 48f1 4a95 | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 6 30fe 3728 36b9 26ab | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 4 1fd0 1dc0 1784 1484 | 16 194e (0) 19ea (0) 18e0 (0) 1b1d (0)\n004 4 0d1c 0e3b 0942 08f8 | 11 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n005 4 07f5 046c 0561 0594 | 4 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n006 3 0191 0111 012b | 3 0191 (0) 0111 (0) 012b (0)\n============ DEPTH: 7 ==========================================\n007 2 0314 035f | 2 0314 (0) 035f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","private_key":"89eff5a9452d1e0c16a61c6b956e8ba73cc6af297693643037294f04f933c9b4","name":"node_025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","services":["bzz","pss"],"enable_msg_events":true,"port":40297},"up":true}},{"node":{"info":{"id":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","name":"node_8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","enode":"enode://5adb68b61a7c2016141b6a2c5f6f62fb6bbaf0055b55208fe1d40c13de6c0f33882fe2c62b81ac1be1dfa20077589c4a2035252280a7fc51de6b283f2402cfbf@127.0.0.1:0","enr":"0xf88fb840c0f93ae82bca086787974a9909d7cb74ab3af63f5282df001769504d385c646d1a08448f09cd3b12b8434eacfb1d951d6d50470fa0c545eac3abc11690ef8bd80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035adb68b61a7c2016141b6a2c5f6f62fb6bbaf0055b55208fe1d40c13de6c0f33","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hAK9YigoEe0jay+h8NQa1LvlTkIO40rcYWTP1Lr4ZY0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8402bd\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4b79 741a 012b 025d | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 5 c603 da36 ff75 eb68 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 2 aaf0 a970 | 37 b8e1 (0) bbaf (0) ba91 (0) bea1 (0)\n003 4 9c8e 9518 9464 9257 | 17 9b8e (0) 9948 (0) 9959 (0) 9f0e (0)\n004 5 8cc3 8ea2 8e7b 8b43 | 9 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n005 7 837f 834f 8358 80d7 | 8 837f (0) 834f (0) 8358 (0) 81a5 (0)\n============ DEPTH: 6 ==========================================\n006 2 87a3 86d6 | 2 87a3 (0) 86d6 (0)\n007 0 | 0\n008 1 84a9 | 1 84a9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","private_key":"0a9e0691c50298a2bc085029a26783b783f3b1d81068d25096da660201582e65","name":"node_8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","services":["bzz","pss"],"enable_msg_events":true,"port":41495},"up":true}},{"node":{"info":{"id":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","name":"node_741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","enode":"enode://b7159c8574bad546d319bf27fe0b85a491ad9e0df9b3974553552f5dcae8ac16db1bdb41f7115872a65027698b5ba532c39b6955a5e8091d9a2158e594a75f69@127.0.0.1:0","enr":"0xf88fb8409311b5e1b31fdf6f1ec55524169f3ce36a87b92068a58be80cba7c7f8bb4e0ee07c122fc032f110c6cf8c75a2855a020d34a069f2acd2066f7b5e4da4ef8b6c80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b7159c8574bad546d319bf27fe0b85a491ad9e0df9b3974553552f5dcae8ac16","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dBqFSuKZ30mnOHJbxYq+YU5eQwL/7NgyC77ehBLRYMA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 741a85\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e681 eb68 9464 8402 | 130 d700 (0) d408 (0) d302 (0) d3e9 (0)\n001 9 2c85 26ab 1fd0 1784 | 65 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n002 7 5a26 5c7c 46bf 4005 | 35 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n003 6 6c01 6d5e 648a 67f3 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 6 7850 7933 7e47 7c46 | 9 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 7049 70f6 | 2 7049 (0) 70f6 (0)\n006 1 7660 | 1 7660 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","private_key":"d86ec48bb09bc70772b1ac1e6c492b9675a44a28adc64095a3be584ce92f8fdc","name":"node_741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","services":["bzz","pss"],"enable_msg_events":true,"port":36283},"up":true}},{"node":{"info":{"id":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","name":"node_4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","enode":"enode://94db8d2b348f151986140b50ea45c8f5983f78caf7ba871b2aeb20a7aefb5e6566c5628c702e8979281130632ade26f0222060bc53728c0c0ddf7137947c5229@127.0.0.1:0","enr":"0xf88fb840558b22c25fa4ad6f7b89ee4a1a18c379bfc0bc76aac0da6365611dff788030f334f0feae2e90705123442b2419a399ad4d6f5f57c8f5f6e781272904113539c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10394db8d2b348f151986140b50ea45c8f5983f78caf7ba871b2aeb20a7aefb5e65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SpXUn1gFewObVaNPZ6NIwFL2F3AGXkEkP/BV78VwqTU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a95d4\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 da36 ba91 9464 | 130 d408 (0) d700 (0) d209 (0) d302 (0)\n001 5 26ab 2c85 2a50 298a | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 4 6c01 6790 648a 741a | 26 68cb (0) 6b4e (0) 6e7f (0) 6d3c (0)\n003 8 5144 50c1 5538 5c37 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 6 435d 4005 402c 46bf | 9 46bf (0) 447c (0) 447a (0) 44ad (0)\n005 2 4d91 4cec | 3 4d38 (0) 4d91 (0) 4cec (0)\n============ DEPTH: 6 ==========================================\n006 5 482e 48b8 48de 48d7 | 5 482e (0) 48b8 (0) 48de (0) 48d7 (0)\n007 1 4b79 | 1 4b79 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","private_key":"aa7a512548b186d6f17490300bba5369b634d9649b74c421af1d43d3f8cafec6","name":"node_4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","services":["bzz","pss"],"enable_msg_events":true,"port":43231},"up":true}},{"node":{"info":{"id":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","name":"node_4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","enode":"enode://7e2ea6ad36e886e7ef31de1d7d85a0a3d85618dea99621ee2bceacb048b10e9b26862e9fe9a918204e39cb7ed0b1c849b19345b1064cf890de27151a144ecdc0@127.0.0.1:0","enr":"0xf88fb8409159ad0c33b90bbed5e06a27c0189aecee7e3eeaf36cc509cf20318bfee1d84d525df4a5b228a2e4fccf906ba509a8318400ec3cfeaf76d800fade5a071b9f560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027e2ea6ad36e886e7ef31de1d7d85a0a3d85618dea99621ee2bceacb048b10e9b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"S3noMYbyqwWTLqqZmCouUzc7g3gOMtIk0VyyyFRiRR8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4b79e8\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ba91 8402 9464 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 3 012b 08bd 08f8 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 3 648a 741a 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 5 5a26 5bd8 5c37 5c7c | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 435d 4005 46bf 447a | 9 46bf (0) 447c (0) 447a (0) 44ad (0)\n005 2 4cec 4d91 | 3 4cec (0) 4d38 (0) 4d91 (0)\n============ DEPTH: 6 ==========================================\n006 5 482e 48b8 48f1 48de | 5 482e (0) 48b8 (0) 48de (0) 48d7 (0)\n007 1 4a95 | 1 4a95 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","private_key":"e6dad134228b16f662707d719d2a5b4104da298ca8bdb6085d4d86557ff74820","name":"node_4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","services":["bzz","pss"],"enable_msg_events":true,"port":42249},"up":true}},{"node":{"info":{"id":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","name":"node_08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","enode":"enode://266b673803b457c94430107ebcaad9bbe27ca7b2d7f2f4a2795330eb1370ef17684e5f79a2b76a8e8b68388a0135357d0643a71451e4475030776a4662c17dd5@127.0.0.1:0","enr":"0xf88fb840f107f7f7c79de397fcaa167703a506621bf1b28b3a12767f3f3b156c7d64d64a4a4bd7e9ec8535b076496f0d44b8077b7597f9b75a20a611dba6ecc55ffe6f900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103266b673803b457c94430107ebcaad9bbe27ca7b2d7f2f4a2795330eb1370ef17","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CPhIeORP7SrbSyaFufKT3Dxz1fm8HEdIcNlD7CrnPb4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08f848\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c42e c2d0 c8ea cdb1 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 5 7660 741a 4005 48f1 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 5 26ab 2c85 3c5b 3728 | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 5 1fd0 1dec 1dc0 1784 | 16 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n004 3 0111 012b 025d | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 4 0d1c 0cfc 0e80 0e3b | 5 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 096a 0942 09b3 | 3 0942 (0) 096a (0) 09b3 (0)\n008 0 | 0\n009 1 08bd | 1 08bd (0)\n010 0 | 0\n011 1 08e5 | 1 08e5 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","private_key":"c9ea240d0ca10a37109b638b6ff80df72e80f58b0bdaab9117ece2449c7ded0f","name":"node_08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","services":["bzz","pss"],"enable_msg_events":true,"port":33617},"up":true}},{"node":{"info":{"id":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","name":"node_81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","enode":"enode://9c7ee34c91cca6a255a1d8adf1770f230ddc3b14a4fd7052094be159092b67122725fa2cbea906cf1014c841ef9be502872b8e7205e080a0861036ac05c947bc@127.0.0.1:0","enr":"0xf88fb84016f0ddeab6ab02fec27c0d81fe6b7c75926f73593cc76cfe70a797016f5de68257234757637d614c0e3afe0b4a62d76a0ea9e61189d9b6cc35df8210941da9800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029c7ee34c91cca6a255a1d8adf1770f230ddc3b14a4fd7052094be159092b6712","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gaWgf5L4E+hbUBsAKOHKpuamx++lGV7LaTzS2R1RMqA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 81a5a0\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5a26 48f1 7660 08f8 | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 3 da36 e681 ff75 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 3 aaf0 a0c8 b3f9 | 37 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n003 2 9c8e 9518 | 17 9b8e (0) 9959 (0) 9948 (0) 9f0e (0)\n004 5 8cc3 8e28 8e7b 8b43 | 9 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n005 4 87a3 86d6 84a9 8402 | 4 87a3 (0) 86d6 (0) 84a9 (0) 8402 (0)\n006 3 837f 834f 8358 | 3 837f (0) 834f (0) 8358 (0)\n============ DEPTH: 7 ==========================================\n007 4 80d7 8073 8074 8006 | 4 80d7 (0) 8006 (0) 8073 (0) 8074 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","private_key":"f268036ece7b4c34b20e291a59e9e6eb8c169846ed02ae120104c2a9db928aa8","name":"node_81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","services":["bzz","pss"],"enable_msg_events":true,"port":41021},"up":true}},{"node":{"info":{"id":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","name":"node_7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","enode":"enode://57d4fa9adc668bc6252f2871ae51f3507be8299126d91348d691d765826efd907e3086acd9c139e0d4f2ad542648e855aed9dd718e7b160ccff5e2d3eda8d109@127.0.0.1:0","enr":"0xf88fb840728d16ca2bed2ed57accf482d7d01246e23016bfb73bffb10c3b7b47db93f7b6528ae999d54cf0807af525b9c502e27200c19a8faaf1f69330d98b8488863ef10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10357d4fa9adc668bc6252f2871ae51f3507be8299126d91348d691d765826efd90","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dmCCj7DI+JIB005vTWHMa6mjDOrW5OuCU/bMkuGEXyM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 766082\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c603 da36 81a5 | 130 c8c8 (0) c8ea (0) c9c3 (0) c961 (0)\n001 5 2c85 3728 36b9 012b | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 10 5a26 5bd8 5663 5144 | 35 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n003 5 6c01 6d5e 6795 6790 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 6 7850 7e47 7d16 7c46 | 9 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 70f6 7049 | 2 70f6 (0) 7049 (0)\n006 1 741a | 1 741a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","private_key":"a661a84382c924fa6b8c1d349120fa836ebbeb7f53552df109787f65a9ea40b1","name":"node_7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","services":["bzz","pss"],"enable_msg_events":true,"port":33705},"up":true}},{"node":{"info":{"id":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","name":"node_48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","enode":"enode://bdc3539551669afb2e5251b20cd32b76991a299ed144c7cdf2df6a562307c9ccb061dc13c4a0428c279b481d48bdc454f8cf3c2d334d023820636940194a536a@127.0.0.1:0","enr":"0xf88fb840166e7488211c50622095d0c7a0a9b5798b716da7a2f18087617760eab6cbd432533b34999879c21ac95d597a2e7afdc751503e82f98018f4988dcfc2255bb7de0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bdc3539551669afb2e5251b20cd32b76991a299ed144c7cdf2df6a562307c9cc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SPHKbUMwGfky+krgPg3svL6j/mNe3/RFimabg/gWK5o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48f1ca\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 da36 81a5 ba91 b3f9 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 2 025d 08f8 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 6c01 6795 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 7 5538 52a8 5144 5c37 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 402c 4005 447a 44ad | 9 46bf (0) 447c (0) 447a (0) 44ad (0)\n005 2 4cec 4d91 | 3 4cec (0) 4d38 (0) 4d91 (0)\n006 2 4b79 4a95 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 1 48b8 | 1 48b8 (0)\n010 2 48d7 48de | 2 48de (0) 48d7 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","private_key":"93ccc60464556d17f764da4d4f9627036f03862e51eedf2272ff4ab6de460bca","name":"node_48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","services":["bzz","pss"],"enable_msg_events":true,"port":44895},"up":true}},{"node":{"info":{"id":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","name":"node_b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","enode":"enode://0fff61eaf24fc39fce31fcc08d7f4530cf34ea9b316c8552a2665bb588bc2b715ac681a15fec8f10bd07b5e7efba1b60dbceb2bda52c437fe7e10bef54e9385b@127.0.0.1:0","enr":"0xf88fb8408e0903553e420a153b07746b27efee96df98e493517320da509b578ea9a335ad7d7f75c1be85cc91b87448690b53259d60f1f1d962827db10e0c45302d5991460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030fff61eaf24fc39fce31fcc08d7f4530cf34ea9b316c8552a2665bb588bc2b71","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s/lfIl4ra3bmx+98hsr4PjUhP2oi2kHmU8ocGQviPJw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b3f95f\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 44ad 4005 48f1 | 126 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n001 5 ff75 e277 c2d0 c603 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 7 9c8e 9257 9518 8cc3 | 38 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n003 10 a330 a0c8 a5ac a505 | 23 a4ee (0) a5ac (0) a505 (0) a7a8 (0)\n004 8 bdc5 bcf8 bea1 be68 | 8 bcf8 (0) bdc5 (0) bea1 (0) be68 (0)\n============ DEPTH: 5 ==========================================\n005 5 b5ea b4a1 b6df b659 | 5 b4a1 (0) b5ea (0) b659 (0) b6df (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","private_key":"b88ec7f2f180fa33cf884de2d17cd8bb2fd54c0091c86a3485fa2253753391f4","name":"node_b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","services":["bzz","pss"],"enable_msg_events":true,"port":38851},"up":true}},{"node":{"info":{"id":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","name":"node_4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","enode":"enode://d59ebe745d21b2e3762354724988cc2e1922981561a7a1b59c692b63aab87866680e05dbd639fbc0e1edeea41158e6f0fc89f9858965ddfb88c4f7a837044694@127.0.0.1:0","enr":"0xf88fb8408bd7fa4d67c32ec7cede14876f0a7782e437190163434552f623d2b45f923ba14d0f771d61ec044c8ba306a6f70b9985dbb9ee95912d035959e20b757ce8a4e80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d59ebe745d21b2e3762354724988cc2e1922981561a7a1b59c692b63aab87866","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QAX9H6j7sxiymmLDaK2leeUSLKBXjmp1xQlVK+S2O3Y=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4005fd\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 da36 ff75 9518 ba91 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 4 2c85 1484 08f8 0e3b | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 4 6790 648a 741a 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 5a26 5bd8 5c7c 5c37 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 4a95 4b79 48b8 48d7 | 10 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n005 4 46bf 447a 447c 44ad | 4 46bf (0) 447c (0) 447a (0) 44ad (0)\n============ DEPTH: 6 ==========================================\n006 3 43d4 43c9 435d | 3 43d4 (0) 43c9 (0) 435d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 402c | 1 402c (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","private_key":"a8676ecb5e3d5d9afec421fe21a57c5fc1d107a450dc67d5f5882520afa62a7c","name":"node_4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","services":["bzz","pss"],"enable_msg_events":true,"port":37241},"up":true}},{"node":{"info":{"id":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","name":"node_ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","enode":"enode://3d2e2c472696bba49a923f035e188a58a75779bfaf0028b65c790cc6a72fcb0522fd663a55e2e7d8e2983cb895d6808cb75263b2e36ab3e6da0795ca222c1eb7@127.0.0.1:0","enr":"0xf88fb840a320a767aa7097e0c7a488fcc471bd6d30e05b616b05a63af5bcc89118d574f21c903d1427e4802c1331a3a2dc43b52ecbed21f4b1bbc488d64a8f640550ba990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d2e2c472696bba49a923f035e188a58a75779bfaf0028b65c790cc6a72fcb05","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/3WxkBfIQSjzjexPY+HyR6VpHcD64YbmZ6/ttf6dLIA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ff75b1\npopulation: 44 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2a50 26ab 0e3b 44ad | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 11 b3f9 a616 a0c8 ab71 | 75 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n002 12 c42e c6a8 c603 c74d | 27 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n003 7 e867 eb68 eff2 e277 | 14 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n004 4 f756 f1ed f305 f215 | 7 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n005 2 f9de f8ff | 3 fa24 (0) f9de (0) f8ff (0)\n============ DEPTH: 6 ==========================================\n006 2 fc51 fc39 | 2 fc51 (0) fc39 (0)\n007 1 feb3 | 1 feb3 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","private_key":"a98bd329cd3c7942c9f230208e49b4c880749a41fcd4ccf7561fab55c6c08641","name":"node_ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","services":["bzz","pss"],"enable_msg_events":true,"port":33251},"up":true}},{"node":{"info":{"id":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","name":"node_44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","enode":"enode://888d38ff57ed4518cedab3e8dd7e3c2974e8a18eb4105f019d5da60aeea595855f40a76650488189d7de83a61938b4546ae8f1bb85109783ec72c771e5689819@127.0.0.1:0","enr":"0xf88fb840e02be04b2b82d311eb77cd1c1af28fba50cdcceb3a24f4bdb29b0f6450344a6d5d8cb185e0ef49a9d8b194f7819fc6ad342d52f9cb50cfc49c284a7c78d351590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103888d38ff57ed4518cedab3e8dd7e3c2974e8a18eb4105f019d5da60aeea59585","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RK2qv5xGYIo3TtgW08QMY7ZkX09uAzp2QxvI+IcT60E=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 44adaa\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ba91 b3f9 ff75 | 130 a4ee (0) a5ac (0) a505 (0) a7a8 (0)\n001 3 1484 012b 0e3b | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 6790 648a 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 5a26 5bd8 5c37 5538 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 48b8 48d7 48f1 4a95 | 10 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n005 4 43d4 435d 402c 4005 | 5 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n006 1 46bf | 1 46bf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 447c 447a | 2 447c (0) 447a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","private_key":"97d76c34244a41e0f1ac5de3b564727ac2f324b9ad5cfca455fe8b70c05abb39","name":"node_44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","services":["bzz","pss"],"enable_msg_events":true,"port":38577},"up":true}},{"node":{"info":{"id":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","name":"node_0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","enode":"enode://cdf4c78c9aa3593dd7a6467f48660ca11115fbe248d9cf9e1d57c19c890c1fc71aca0582ad7017bdc5053ce094c5905b7f77e2be5402f313786253842933cd16@127.0.0.1:0","enr":"0xf88fb840ee3d9598b270079ccc13e4add3d88bee1c6abf8d5e8431c4681a6ae45369d4b0668f324e4de0c56328849c15238ea899fc1710b328f6172fbf89dff1306ab2bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cdf4c78c9aa3593dd7a6467f48660ca11115fbe248d9cf9e1d57c19c890c1fc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Djt3IvP4TYOz10S+pOiTcVoB1N889KHGpoI6H1ya1rg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e3b77\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9518 ff75 da36 | 130 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n001 2 4005 44ad | 61 7895 (0) 7850 (0) 79e5 (0) 7933 (0)\n002 3 26ab 3728 36b9 | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 7 1fd0 1dec 1add 18e0 | 16 194e (0) 19ea (0) 18e0 (0) 1b1d (0)\n004 5 0111 012b 0314 035f | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 6 09b3 0942 096a 08bd | 6 0942 (0) 096a (0) 09b3 (0) 08bd (0)\n006 2 0cfc 0d1c | 2 0cfc (0) 0d1c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0e80 | 1 0e80 (0)\n009 0 | 0\n010 0 | 0\n011 1 0e2b | 1 0e2b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","private_key":"4f28295b9dd454af1f4de9ea11d0d1a2952fc64eb6835cbc1c6c1a564d826654","name":"node_0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","services":["bzz","pss"],"enable_msg_events":true,"port":41795},"up":true}},{"node":{"info":{"id":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","name":"node_da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","enode":"enode://61c96923ec6ffd96df32f0db9954bf468bd5c4c24271a86b243cd934bc8da77f1177964c7a53fc07b86f5ef32a9e1c85af77bb56fd699a99f15caae4fbb38a68@127.0.0.1:0","enr":"0xf88fb8405a4f50ee12c7e45a28c023ae4e6c05ca7407d66aea05f2837e8718b934145bb30f026867c53e3fd3eb1c9ca2829a6fe691a3b5edacee2cdd0fcd600c5614255b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261c96923ec6ffd96df32f0db9954bf468bd5c4c24271a86b243cd934bc8da77f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2jbR35WhWLDT+edAfWY6a2Ed3gp38ApYS5epOatqAN4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: da36d1\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7660 48f1 4a95 4005 | 126 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n001 8 a0c8 acee aaf0 b3f9 | 75 b8e1 (0) bbaf (0) ba91 (0) bea1 (0)\n002 6 e681 e277 eb68 e867 | 28 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n003 9 c8ea cdb1 cc33 c2d0 | 16 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n004 3 d209 d302 d3e9 | 5 d700 (0) d408 (0) d3e9 (0) d302 (0)\n005 1 ddb8 | 1 ddb8 (0)\n006 2 d9cf d959 | 2 d9cf (0) d959 (0)\n============ DEPTH: 7 ==========================================\n007 1 dbd4 | 1 dbd4 (0)\n008 1 dad0 | 1 dad0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","private_key":"2022f7c1008e4670055ca434f78ed6debd0e7564d06d9d22625bafe9c2184bc8","name":"node_da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","services":["bzz","pss"],"enable_msg_events":true,"port":39225},"up":true}},{"node":{"info":{"id":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","name":"node_951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","enode":"enode://e61d35f746dd8b1d91286e1abb0448cbb68371b867574358604ed002233ecaebfcd5a07cbabc0bdca25a58c76fa53abd80a1bf7d62c410f2841611b676334041@127.0.0.1:0","enr":"0xf88fb840f8c031b80bf4308c84323e167eeca84179f0feebb5aad18f694024f8fde4f3424adbec09f917bc90d2d319b9debb6c903064655c754915614dc59b490178d75b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e61d35f746dd8b1d91286e1abb0448cbb68371b867574358604ed002233ecaeb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lRh3s07hU1tQWcSb6wPolg/5wStpTvZHCMd8MP8dxwY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 951877\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4005 0e3b 36b9 2c85 | 126 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n001 3 e867 ff75 da36 | 55 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n002 2 b3f9 ab71 | 37 be68 (0) bea1 (0) bfc7 (0) bcf8 (0)\n003 9 8862 8b43 8cc3 8e7b | 21 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n004 3 9ec8 9f7d 9c8e | 9 9948 (0) 9959 (0) 9b8e (0) 9f0e (0)\n005 3 93c0 93ea 9257 | 3 93ea (0) 93c0 (0) 9257 (0)\n006 1 97da | 1 97da (0)\n007 1 9464 | 1 9464 (0)\n============ DEPTH: 8 ==========================================\n008 1 95c0 | 1 95c0 (0)\n009 1 955d | 1 955d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","private_key":"bc5b57ce450e26704097f3e90b7256f3d38b4a75973b2384deec064351eee3f7","name":"node_951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","services":["bzz","pss"],"enable_msg_events":true,"port":39271},"up":true}},{"node":{"info":{"id":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","name":"node_ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","enode":"enode://ac1fef7e9d3c51f02d8ade00cb8763bb163c214f15f52ba8025bfb6355dca1d1a9779350f5c60d02763b12902f5b176366dec0e51eb4879d0031a407cb80ba6d@127.0.0.1:0","enr":"0xf88fb84047e8f17977626db088d3ce02b567c210e5ded10efc65966d542ffd2e829e25822186597f28307a91d4fde8fc4019ff71797412eb3a69a20aa8deb95f096b3c370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ac1fef7e9d3c51f02d8ade00cb8763bb163c214f15f52ba8025bfb6355dca1d1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"q3GeYKd7pSU/FpDJIN+d2fOmIHHpzOnWLgABpSKzQJ4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ab719e\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 36b9 2c85 | 126 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n001 5 c603 e277 e681 e867 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 3 84a9 9c8e 9518 | 38 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n003 3 ba91 bdc5 b3f9 | 14 bea1 (0) be68 (0) bfc7 (0) bcf8 (0)\n004 3 a616 a330 a0c8 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 2 aeb4 acee | 3 acee (0) af02 (0) aeb4 (0)\n006 4 a970 a8f4 a8ff a8b5 | 4 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n============ DEPTH: 7 ==========================================\n007 1 aaf0 | 1 aaf0 (0)\n008 0 | 0\n009 1 ab3f | 1 ab3f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","private_key":"a4ae96d7ecb3971ea097b37390920857ffaf67fc5bae59c8cabde67de15feeb1","name":"node_ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","services":["bzz","pss"],"enable_msg_events":true,"port":34781},"up":true}},{"node":{"info":{"id":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","name":"node_2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","enode":"enode://b1fe3894a67c4139a898d93a93cacc87e3e6a0072f2e75faa1d692fcdae02da9056ee9d0ef8bd7de2d4cb801bea1a4c92867b686648ccdf4acc15d10ea9e92ab@127.0.0.1:0","enr":"0xf88fb840acad001cebe20e5d67e33bade1ef67f0c02b361f95b012af873d06038de2c89e7a9bcb738bbf325462227e88eefa257d8d3e3fe6567496e9bd6bcf7a4315e7b70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b1fe3894a67c4139a898d93a93cacc87e3e6a0072f2e75faa1d692fcdae02da9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LIX1NhstWrz3md5Q/lix7SAG6hj3WCN0jDPrfpWxzDk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c85f5\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c534 8e7b 9c8e 9518 | 130 e471 (0) e64d (0) e681 (0) e0a0 (0)\n001 7 741a 7660 6795 648a | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 9 1484 1add 1fd0 1dec | 37 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n003 7 3c5b 3cab 3a62 3b02 | 17 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n004 4 244c 24f8 26ac 26ab | 4 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n005 2 298a 2a50 | 2 298a (0) 2a50 (0)\n006 2 2fd2 2e65 | 2 2fd2 (0) 2e65 (0)\n============ DEPTH: 7 ==========================================\n007 1 2ddf | 1 2ddf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 2c80 | 1 2c80 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","private_key":"2a8ffc679012d1aa50e2f65a8e57b2ec4320e84272a5e905cb90098bace2bddb","name":"node_2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","services":["bzz","pss"],"enable_msg_events":true,"port":36571},"up":true}},{"node":{"info":{"id":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","name":"node_36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","enode":"enode://e4d9f33c795e51155d700cb64f1a8d4ead769a1d93d77825a6c680750ad444ef939dbfcecf0020bb04e1bb818d28af91aaa6809d9abb42ebd3088ff3c351ec3f@127.0.0.1:0","enr":"0xf88fb84053bd3c1b1a365ed2377b3066ad1f581f1d671a75bebdf3c21d41c6e15045a85771fe183fc7f77629dcf4d2be91de26315edfc83ccc82cb68b3e900fb1fd3a6330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e4d9f33c795e51155d700cb64f1a8d4ead769a1d93d77825a6c680750ad444ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Nrk2VsqwIhP6dhJK9iURCTVqvF4K5d0eIDxqAT4BRUg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 36b936\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9518 ab71 aaf0 | 130 f305 (0) f215 (0) f2b4 (0) f1ed (0)\n001 5 648a 7660 46bf 5a26 | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 10 1fd0 138d 1784 1484 | 37 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n003 4 26ab 2a50 298a 2c85 | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 7 3c5b 3cab 3f31 3938 | 8 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n005 5 32ff 3051 30fe 31e1 | 6 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n============ DEPTH: 6 ==========================================\n006 1 3411 | 1 3411 (0)\n007 1 3728 | 1 3728 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","private_key":"fc142c5cdb7737fcd9e994ef0aab4a60ef1b23c59685a99f70384ecdcab96da9","name":"node_36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","services":["bzz","pss"],"enable_msg_events":true,"port":34195},"up":true}},{"node":{"info":{"id":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","name":"node_aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","enode":"enode://7108119c77ee1ca51a8cfa49207c81c9236c48de66d0ec4441d03b409214e6cb3e6aeda9074eefc6cab261e2da67787c1e6dc5c56d9face762f3c6d228ddb3bf@127.0.0.1:0","enr":"0xf88fb840e1516801e5e9795f89e9742eb3c020e4aeab9eaa0544e8eaf742e91b186387817613a49d6e2bc5ca531ae9afe63aed360830056c25d161bee0ccf74ec289a82c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037108119c77ee1ca51a8cfa49207c81c9236c48de66d0ec4441d03b409214e6cb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qvBRoIepL4dKP2x5IwFeTP+0uz7zgcl3/ZAvIehB0PQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aaf051\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3728 36b9 | 126 7895 (0) 7850 (0) 79e5 (0) 7933 (0)\n001 5 ff75 e277 e867 da36 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 7 9c8e 8cc3 81a5 8006 | 38 87a3 (0) 86d6 (0) 84a9 (0) 8402 (0)\n003 3 bdc5 ba91 b3f9 | 14 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n004 3 a616 a330 a0c8 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 2 aeb4 acee | 3 acee (0) af02 (0) aeb4 (0)\n006 3 a8f4 a8b5 a970 | 4 a8ff (0) a8f4 (0) a8b5 (0) a970 (0)\n============ DEPTH: 7 ==========================================\n007 2 ab3f ab71 | 2 ab3f (0) ab71 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","private_key":"4faa6df719db312ce7196c8b218ffe31a118192b63af6a064b63993d06809021","name":"node_aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","services":["bzz","pss"],"enable_msg_events":true,"port":43443},"up":true}},{"node":{"info":{"id":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","name":"node_3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","enode":"enode://c114f0b7917ddfc94778644a8fcb80d6219c100706ef4f7685c3a1b20836923b2f8b668cb508c542e5140d0de8dbf3eb6d39dd3fa988cc89e5a35475d33c5ff5@127.0.0.1:0","enr":"0xf88fb8409f56eb9c402420e1ba9d1221c060d99fadee62aa892110c184c542ddc788cb872ee790ce149a666c38cbe359cba9f433a75a62641e1d1f785c7bf1f7e9c0ac220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c114f0b7917ddfc94778644a8fcb80d6219c100706ef4f7685c3a1b20836923b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NygVLIjx5eYfZSOwno87sQI7cA3szcpfzB5kiBNrDlc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 372815\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9c8e aaf0 | 130 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n001 5 7660 648a 5bd8 5144 | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 11 138d 1484 1784 1dc0 | 37 1049 (0) 1070 (0) 138d (0) 1686 (0)\n003 2 26ab 2c85 | 11 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n004 4 3c5b 3cab 3b02 3a62 | 8 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n005 5 30fe 3051 3188 31e6 | 6 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n============ DEPTH: 6 ==========================================\n006 1 3411 | 1 3411 (0)\n007 1 36b9 | 1 36b9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","private_key":"3557d9f64ffafd68249ae21654f5c1fd8576ede29a7e184fa2c80dcfcf01ca7d","name":"node_3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","services":["bzz","pss"],"enable_msg_events":true,"port":41719},"up":true}},{"node":{"info":{"id":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","name":"node_9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","enode":"enode://4c2931c91d607781aedf9552788ec9df705def28333007e9246811be0a3ebfa8eb44baad1ddf0620a99257cb0cf9afaf7f714cae4f241510bffdf3c4b6682350@127.0.0.1:0","enr":"0xf88fb840d76ae62f54de16a707c5789592f92afaa9c1ad444f8e7fa013c8f39c20a34d4f2c0d88f8931465fc033eb4be4b1c1f4fe8150dd91ba8297ce363ffa61f1d4d440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c2931c91d607781aedf9552788ec9df705def28333007e9246811be0a3ebfa8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nI4fI/JgxaRrAAFXJnWxnlKTymXn/fwTHAdhLpxAcvo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9c8e1f\npopulation: 44 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 46bf 08e5 2c85 3728 | 126 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n001 3 ff75 e867 c603 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 9 b3f9 a616 a0c8 a330 | 37 b8e1 (0) bbaf (0) ba91 (0) bea1 (0)\n003 14 87a3 86d6 84a9 8402 | 21 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n004 7 9257 93c0 97da 9464 | 8 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n005 3 9b8e 9948 9959 | 3 9b8e (0) 9959 (0) 9948 (0)\n006 2 9f7d 9ec8 | 3 9f0e (0) 9f7d (0) 9ec8 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 9c21 | 1 9c21 (0)\n009 0 | 0\n010 1 9ca1 | 1 9ca1 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","private_key":"f14ad2c3fc9ee9c4bf7c847d746dbc352159a0f470e5f9c054c623e85b32dd58","name":"node_9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","services":["bzz","pss"],"enable_msg_events":true,"port":41867},"up":true}},{"node":{"info":{"id":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","name":"node_46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","enode":"enode://4d4243ce1bbd72776f1cd9a14309b16117af879a4d6670c2c684a772062c9ca6ce7591b97f0b28a854431891b0d2b0d4517991326bbaf7aba8056bb1eae0fd6b@127.0.0.1:0","enr":"0xf88fb84047ede3289ec2767e1b71b8a461306f27846efb00e6bd82d79a5712ec11cf570a5dd5b750d5ee3254949142a30b40d0a43174a43a895303db9fe7e2794325736e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034d4243ce1bbd72776f1cd9a14309b16117af879a4d6670c2c684a772062c9ca6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rr+ovqVrC+Gr+lrTVhu2v0ntZpXYPuKywZLFoECDR88=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 46bfa8\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9c8e ba91 a0c8 | 130 f6c0 (0) f645 (0) f756 (0) f305 (0)\n001 3 08e5 36b9 3728 | 65 1070 (0) 1049 (0) 138d (0) 1686 (0)\n002 5 6c01 648a 6795 741a | 26 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n003 4 52a8 50c1 5144 5a26 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 4a95 4b79 48b8 48d7 | 10 4d38 (0) 4d91 (0) 4cec (0) 4a95 (0)\n005 4 4005 402c 43d4 435d | 5 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n============ DEPTH: 6 ==========================================\n006 3 447c 447a 44ad | 3 447c (0) 447a (0) 44ad (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","private_key":"b70820e75826e847f92eaf68756a7853fdb2b9405385a07431acd85be07346c3","name":"node_46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","services":["bzz","pss"],"enable_msg_events":true,"port":46727},"up":true}},{"node":{"info":{"id":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","name":"node_a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","enode":"enode://c4dfc6549432092140b323c294e153ed2fce4e66d90c5342dd739a17b6f8e941241ae157f54b265c8c20b6fdbea7d31097672735a366fd0a39cd6b8e3b7a8b9e@127.0.0.1:0","enr":"0xf88fb84096f40381fc8d8894e700731acada297f8d3f467ebe034ffb0fb3ba1aed4804fc2b00a87923ceb549a89ef5c5cf4d2fe663bb50e216cd249ef9a408b6c57ffe2b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c4dfc6549432092140b323c294e153ed2fce4e66d90c5342dd739a17b6f8e941","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oMiLpwWZsOcsGPpq7dFNYHzKPppJpdUBZdCE5wMowt0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a0c88b\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 648a 5144 46bf | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 da36 c603 c6a8 ff75 | 55 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n002 8 9257 9c8e 8e7b 84a9 | 38 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n003 5 b3f9 bdc5 be68 bfc7 | 14 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n004 5 aaf0 ab71 a970 aeb4 | 10 acee (0) af02 (0) aeb4 (0) a8f4 (0)\n005 4 a505 a7a8 a606 a616 | 7 a4ee (0) a5ac (0) a505 (0) a742 (0)\n============ DEPTH: 6 ==========================================\n006 4 a2a1 a2e6 a327 a330 | 4 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n007 1 a1c8 | 1 a1c8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","private_key":"1d99f9d95bb5133e67b3abc4fa875f292bb3ef13fc4c32d522507cb6251a737b","name":"node_a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","services":["bzz","pss"],"enable_msg_events":true,"port":38619},"up":true}},{"node":{"info":{"id":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","name":"node_648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","enode":"enode://d8d46c12cb0b4cecaf8ab1b972365c7b0568897ccea94352a7b702da0ca1bc6bf559f91c6612d9f452d2af2a32d9b56233b6176241e824db5d784bd0f8015b9b@127.0.0.1:0","enr":"0xf88fb84012854e946d3ccd03e5b967f46ecf70aa3b0b1ccebf7bb7d40f2f80c30110a99b478aa38170b4c3aea017b04fbafa023de9fc42342d0643729f55ce9d2b7119760183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d8d46c12cb0b4cecaf8ab1b972365c7b0568897ccea94352a7b702da0ca1bc6b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZIqW1hiY6y0zb/fVoinP63ufWHKC5A+f5kDhga4mvdM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 648a96\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c603 aeb4 a0c8 | 130 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n001 4 2c85 36b9 3728 08e5 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 9 4b79 4a95 402c 4005 | 35 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n003 6 7ce7 7c7c 7e47 7049 | 13 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n004 4 6b4e 6e7f 6d5e 6c01 | 7 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n005 1 60c5 | 1 60c5 (0)\n============ DEPTH: 6 ==========================================\n006 4 6758 67f3 6790 6795 | 4 6758 (0) 67f3 (0) 6790 (0) 6795 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","private_key":"919debfc547283a6f83386441c4f7b3eaec238931b8e97ea9cf7b8f5516ff110","name":"node_648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","services":["bzz","pss"],"enable_msg_events":true,"port":34693},"up":true}},{"node":{"info":{"id":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","name":"node_51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","enode":"enode://61414ffd81e2e685b199ba6089abc6cf7c18cf4bd3654114e8c2a99dfdc4413b8e36b194557bf9b65dc44deaa9478cd4f1c712bbd946ec4ae3e057c878f05610@127.0.0.1:0","enr":"0xf88fb840bb0506fc37a0cd2ae940ab2b93d4b26476b65fbfb40eefe43af7b43776d9a275164cb946279137a07b6bc6cca0ab5bacc802d203049766cf1abf3081b6d7c1ca0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261414ffd81e2e685b199ba6089abc6cf7c18cf4bd3654114e8c2a99dfdc4413b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UUQKtH/FB2wAytFqVCuEbCazKB7OpNvKeVrpuAGD7JA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 51440a\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 aeb4 a0c8 e277 c603 | 130 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n001 3 3728 36b9 08e5 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 7660 6795 648a | 26 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n003 9 48f1 4a95 4b79 435d | 19 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n004 4 5c7c 5c37 5bd8 5a26 | 10 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n005 3 5663 56ca 5538 | 3 5663 (0) 56ca (0) 5538 (0)\n============ DEPTH: 6 ==========================================\n006 1 52a8 | 1 52a8 (0)\n007 1 50c1 | 1 50c1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","private_key":"1e8a712b0dd95600c1e67872aa3bcc3e875f05bfe3dacb2f0d546ccd810825bc","name":"node_51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","services":["bzz","pss"],"enable_msg_events":true,"port":36863},"up":true}},{"node":{"info":{"id":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","name":"node_c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","enode":"enode://bed7f6e2cf97600f47210eb1b764eabd6a4725c42d3a7333ed8c4b102442528805dbb8bbcc925fcb62432d06c6418410818d9acbc7bccc0c5979e978bc71a414@127.0.0.1:0","enr":"0xf88fb84044f3f935b08146d7ec9f7864874f4641340f171f272858a0f0889877add866cb5795ad8f80508454ba568f7a3f082d552beb4897dd6eb51d7f8675869573fcaf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bed7f6e2cf97600f47210eb1b764eabd6a4725c42d3a7333ed8c4b1024425288","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xgMTjkD+L4XMY0AXlWraY5n8qZlp478MHuhCg3TnefE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c60313\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 08e5 7660 648a 5144 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 b3f9 a0c8 aaf0 ab71 | 75 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n002 6 ff75 e681 e277 eff2 | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 5 d3e9 d302 d209 d959 | 11 d408 (0) d700 (0) d3e9 (0) d302 (0)\n004 5 c8c8 c961 cf52 cd6c | 8 c8ea (0) c8c8 (0) c9c3 (0) c961 (0)\n005 3 c190 c272 c2d0 | 3 c190 (0) c272 (0) c2d0 (0)\n006 2 c42e c534 | 2 c42e (0) c534 (0)\n============ DEPTH: 7 ==========================================\n007 1 c74d | 1 c74d (0)\n008 1 c6a8 | 1 c6a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","private_key":"f8c72bb1240635df9cef74f22b6fe80b40ab667b1917f49f50bbdff097c07eb4","name":"node_c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","services":["bzz","pss"],"enable_msg_events":true,"port":35079},"up":true}},{"node":{"info":{"id":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","name":"node_08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","enode":"enode://ea5b166448c3dd527b2c18555655ee6f90b2bbf3b1d4a447c551801ecab3dba7e5dca4dd2877fc63533ca94dbb39d0583cd6551a0e81bc418ac506a0b2fcdf27@127.0.0.1:0","enr":"0xf88fb840c953b80c5d75dd35fac2c5a49c4dc5308f80a1a9482547b48755d37fb417193c0dc806cf8ce00ec289850183f6837f5c684a68add6e9420bdb6fb937684d72b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ea5b166448c3dd527b2c18555655ee6f90b2bbf3b1d4a447c551801ecab3dba7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"COWiaPOXOFxpp/7IVa5NiJz6mK/vW3wJ/EhB4/iJStg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08e5a2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9c8e aeb4 e277 e867 | 130 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n001 4 648a 46bf 5144 5a26 | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 3 2c85 36b9 3728 | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 6 138d 1784 140d 1484 | 16 1049 (0) 1070 (0) 138d (0) 1686 (0)\n004 4 0594 0314 012b 0111 | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 4 0d1c 0cfc 0e2b 0e3b | 5 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 09b3 0942 096a | 3 0942 (0) 096a (0) 09b3 (0)\n008 0 | 0\n009 1 08bd | 1 08bd (0)\n010 0 | 0\n011 1 08f8 | 1 08f8 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","private_key":"23182ea48dee85a9137e3024980f59b9d2ab3ff4d922fcd1b30583fdf83baaca","name":"node_08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","services":["bzz","pss"],"enable_msg_events":true,"port":45333},"up":true}},{"node":{"info":{"id":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","name":"node_5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","enode":"enode://2ef3561ee8a3827e57f043fc9f0ab7cffb1bcd3ae7cdbbcf67699cd748e6b8da52fcbf6de1738f3da9b1101b0accddafdd133fbd61899b1a5c45a148344055d0@127.0.0.1:0","enr":"0xf88fb84086144704d9432e5493c584d85cf6d3997698361f501788b244566421cbd614c02beeeba7a937b9b0f2616fef916d5978e3079068bedcc45fcf6f749fa354a41d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022ef3561ee8a3827e57f043fc9f0ab7cffb1bcd3ae7cdbbcf67699cd748e6b8da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Wiauc+6/J/bb7CQU8Sd6JJ6BSnoGeQ1wYWEOUiewhvY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a26ae\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 84a9 81a5 8006 80d7 | 130 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n001 3 2c85 36b9 08e5 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 6 7c46 7e47 741a 7660 | 26 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n003 9 4b79 4a95 48f1 435d | 19 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n004 2 52a8 5144 | 6 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n005 3 5d82 5c37 5c7c | 4 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n006 2 5814 5987 | 2 5814 (0) 5987 (0)\n007 1 5bd8 | 1 5bd8 (0)\n============ DEPTH: 8 ==========================================\n008 2 5ac0 5a8b | 2 5ac0 (0) 5a8b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","private_key":"be696e717d5a91103bc542c6cd7e0b0be4b48502beeb1853da20425d07766a9f","name":"node_5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","services":["bzz","pss"],"enable_msg_events":true,"port":33893},"up":true}},{"node":{"info":{"id":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","name":"node_e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","enode":"enode://72e1ea4365070797e7b04d70c2fcad2502d98a96da55ad4a160b42dabf961951e630354d7ca7c321cbf1f5626574b2619a9fdc940ba34d9d1a7a4040f7dd292d@127.0.0.1:0","enr":"0xf88fb840825ecb133fee1dc489fa785a34e83053c110b2233e3c247614a64b09fa55a9770f3b85c38cea0f103bbbe6a97b8cac4ee63240e58e4675694db27f5402ff50660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10372e1ea4365070797e7b04d70c2fcad2502d98a96da55ad4a160b42dabf961951","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6GdtF5ZmJcT9rGvZQ3mBoM+GnIsAEIEu3wx5gF4OH/E=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8676d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2a50 1dec 08e5 5a26 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 8862 93c0 9518 9c8e | 75 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n002 4 d209 da36 d959 c603 | 27 d700 (0) d408 (0) d3e9 (0) d302 (0)\n003 6 f756 f215 ff75 fc51 | 14 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n004 6 e471 e64d e681 e09f | 7 e471 (0) e64d (0) e681 (0) e0a0 (0)\n============ DEPTH: 5 ==========================================\n005 5 eff2 ef99 eebd ec90 | 5 ec90 (0) ed42 (0) eebd (0) ef99 (0)\n006 1 eb68 | 1 eb68 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","private_key":"08fe456242f38e34929ed0b545e558015d4a0759d6306e8a146d36cf893d4b5b","name":"node_e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","services":["bzz","pss"],"enable_msg_events":true,"port":45195},"up":true}},{"node":{"info":{"id":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","name":"node_aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","enode":"enode://95bfeea5c376843748c0b4579a13d01255d69aeb09a34f505ba5f0f0a66f5af8c58878ee35613db89c943fddbee64ed3a135d8518501eac5a9adb497b2779202@127.0.0.1:0","enr":"0xf88fb840ba5b589b63f888f95db7ac61bda2976a43eed9b35eac3e78cff7033f9fad31052b057c291e9b5977783d568855bf8ed309fbdaa39fec7b2b08484bfc149e16fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10295bfeea5c376843748c0b4579a13d01255d69aeb09a34f505ba5f0f0a66f5af8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rrRf4QsNvQ9yq2p3+/lxqPRtvN2WwI8jJ50UNLTzix0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aeb45f\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 648a 5144 09b3 08e5 | 126 7895 (0) 7850 (0) 79e5 (0) 7933 (0)\n001 6 c6a8 d302 e64d e277 | 55 d408 (0) d700 (0) d3e9 (0) d302 (0)\n002 6 9c8e 8006 80d7 8862 | 38 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n003 3 b3f9 bfc7 be68 | 14 b8e1 (0) bbaf (0) ba91 (0) bdc5 (0)\n004 4 a505 a616 a0c8 a330 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 7 aaf0 ab3f ab71 a8f4 | 7 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n============ DEPTH: 6 ==========================================\n006 1 acee | 1 acee (0)\n007 1 af02 | 1 af02 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","private_key":"fd2d10c67a8ec4e327748697560a38d057a694d0f889a4a046bfa41de466686e","name":"node_aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","services":["bzz","pss"],"enable_msg_events":true,"port":39549},"up":true}},{"node":{"info":{"id":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","name":"node_e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","enode":"enode://892384debfb7b9e896252f96c210dbb3def7e24f74947e7737c5c68c7d0a4e43a9859926ef56ea490f905c0fc71a8703571b636948be1f5fe6b5f1ade6d4a5f6@127.0.0.1:0","enr":"0xf88fb840f52490d9e0dee88fedf1f1da621cec20d765e3eff7b5e213d5bb3fbda356b49520319ae12d1f41a30d4b20d4b7b0052635b3ab1532ffe66f9935b55c4b7e56b70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102892384debfb7b9e896252f96c210dbb3def7e24f74947e7737c5c68c7d0a4e43","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4ncM73wa0xK3DZTKVXDkXzJMeYoxqTID9QUWeuqxIrY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e2770c\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1add 1dec 08e5 5144 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 b3f9 a0c8 ab71 aaf0 | 75 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n002 5 d209 da36 d959 c74d | 27 d408 (0) d700 (0) d3e9 (0) d302 (0)\n003 6 f215 f756 ff75 fc51 | 14 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n004 6 ed42 eebd ef99 eff2 | 7 ec90 (0) ed42 (0) eebd (0) ef99 (0)\n005 3 e471 e64d e681 | 3 e471 (0) e681 (0) e64d (0)\n============ DEPTH: 6 ==========================================\n006 2 e0a0 e09f | 2 e0a0 (0) e09f (0)\n007 0 | 0\n008 1 e2d3 | 1 e2d3 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","private_key":"2c978daf46f400bc226fdece07412297280001b2715e8c93de73a32f023d5431","name":"node_e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","services":["bzz","pss"],"enable_msg_events":true,"port":38147},"up":true}},{"node":{"info":{"id":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","name":"node_8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","enode":"enode://eaaca956b740a54195744f6fbd39e020a7ed769cde7f3df89d0ad741ab11159109304ecbba955b7a09dc92014980a987cb17974458d5bf95cdb518ebd41ad4c9@127.0.0.1:0","enr":"0xf88fb84076f9d40288370d9a357f38d036465939c57156da3ee6f9beff1bfae263870b645bb1081bff97858367926e3e377114d326935c349eb355349a781b34a81f12c30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eaaca956b740a54195744f6fbd39e020a7ed769cde7f3df89d0ad741ab111591","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jnuW0o7a5xHhpM7g2JTgvZLN9BC6b2FxP32bC+52HUw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8e7b96\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 26ab 298a 2c85 6795 | 126 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n001 3 f8ff eff2 e277 | 55 cf52 (0) cc33 (0) cd6c (0) cdb1 (0)\n002 3 a0c8 aeb4 acee | 37 b8e1 (0) ba91 (0) bbaf (0) bdc5 (0)\n003 2 9518 9c8e | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 9 8402 84a9 837f 8358 | 12 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n005 3 8b43 8862 8854 | 3 8b43 (0) 8854 (0) 8862 (0)\n006 2 8d19 8cc3 | 2 8d19 (0) 8cc3 (0)\n007 1 8f9a | 1 8f9a (0)\n============ DEPTH: 8 ==========================================\n008 1 8ea2 | 1 8ea2 (0)\n009 1 8e28 | 1 8e28 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","private_key":"ad33c8a077ba94e011226ec6b81f81a198f556dce8d1eb447d60309f2ec96157","name":"node_8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","services":["bzz","pss"],"enable_msg_events":true,"port":45223},"up":true}},{"node":{"info":{"id":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","name":"node_679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","enode":"enode://ed0a39e471509e34dba42412c9de5254e84965cf0532fb62288d0ec74098a7bcbc079ad9c063d1c5be83f76623f266d20dedf46ff8a631ebef5304d8062d47c9@127.0.0.1:0","enr":"0xf88fb840f2fb222edf9f0115e6c84901f82209242c979a9850fdb20841b740c82795ec9516c9f9b248ce6f15b12d488ecc61618fb48e78f2cbfc28a11242c72af5571b140183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ed0a39e471509e34dba42412c9de5254e84965cf0532fb62288d0ec74098a7bc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z5VUtBDkFc/N8bFO+HdZJpsryvB/RUESKXfbOkAJHaI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 679554\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eff2 e277 8862 8e7b | 130 c961 (0) c9c3 (0) c8ea (0) c8c8 (0)\n001 4 2c85 3c5b 0111 1dec | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 6 48f1 447a 46bf 402c | 35 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n003 6 7660 741a 7049 7ce7 | 13 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n004 5 6b4e 6e7f 6d3c 6d5e | 7 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 6758 | 1 6758 (0)\n009 1 67f3 | 1 67f3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 6790 | 1 6790 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","private_key":"295ee49e1d8a7a3fe5af430314a49ea88e405bb74583239a90f3a140bd4d5d7d","name":"node_679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","services":["bzz","pss"],"enable_msg_events":true,"port":37471},"up":true}},{"node":{"info":{"id":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","name":"node_8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","enode":"enode://cde94747f8a20e0bb2560ee9a2af2f6b6537e357a16d3405053a591946807074639abe205cc94e3d89e61445686731991d30a685a5e21a23d43f604cd3164970@127.0.0.1:0","enr":"0xf88fb840c4e3c83eec1c9b3873f6d92f1f6c212da5808e380a2298bd31f54eec9e76abc17d44dc112b0c2d2633b2fdf34f53afcc250b2bb0b5b596df651a3eda03d154cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cde94747f8a20e0bb2560ee9a2af2f6b6537e357a16d3405053a591946807074","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iGLNhdcDkRm5hPdSpFisBJXd6pjGn8HRJB23hzpxLBE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8862cd\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5a26 6795 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 3 d959 e867 e277 | 55 cf52 (0) cdb1 (0) cd6c (0) cc33 (0)\n002 3 b3f9 aeb4 acee | 37 b8e1 (0) bbaf (0) ba91 (0) bdc5 (0)\n003 3 9518 9257 9c8e | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 9 86d6 84a9 8402 834f | 12 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n005 5 8cc3 8d19 8e7b 8e28 | 6 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n============ DEPTH: 6 ==========================================\n006 1 8b43 | 1 8b43 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 8854 | 1 8854 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","private_key":"5b139026f24d426829e4000c0729b6cf94f244c94dc6f40c4408a50c7bbc7e2c","name":"node_8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","services":["bzz","pss"],"enable_msg_events":true,"port":33033},"up":true}},{"node":{"info":{"id":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","name":"node_aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","enode":"enode://41590aa46824b94b64e61a0ba359d8b90fd986c1b1ff0556d51bfa03064616d68e5db68d74e7c89ce7a21c7baca305a808a409df46280f96ae5110560aba272d@127.0.0.1:0","enr":"0xf88fb8407a50df7269c86adec9f03aec5a49050ce842bd9f615b6a0c7f718e6bd95d59c153e0b12a99f1e8583eba20470c4bf7315e9376df0e719fb29eb5845d5eee653f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10341590aa46824b94b64e61a0ba359d8b90fd986c1b1ff0556d51bfa03064616d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rO7nWiYNRSUgYP6XHqvUveJfkS20o8bkf0oJVy/gFpc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aceee7\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 09b3 3c5b 6c01 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 5 da36 d959 e64d e277 | 55 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n002 7 9c8e 80d7 8006 8cc3 | 38 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n003 5 ba91 bdc5 bfc7 be68 | 14 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n004 3 a616 a0c8 a330 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 6 a970 a8ff a8b5 aaf0 | 7 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n============ DEPTH: 6 ==========================================\n006 2 af02 aeb4 | 2 af02 (0) aeb4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","private_key":"0aacb09a0fb2947e95aacfb35aee79d77b33577dc33960a8eda97847f015ef58","name":"node_aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","services":["bzz","pss"],"enable_msg_events":true,"port":41855},"up":true}},{"node":{"info":{"id":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","name":"node_6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","enode":"enode://b9df58044341d94dfdfbd7423f9f8e44cbd1988eb021f9af28aff240c9a82a2cd80e372bdf01aff5ea2cfc8f237351d75a33d6b5cedbbaf11e3fc7e01299ac0d@127.0.0.1:0","enr":"0xf88fb84038e531185ddede85a603500b82295e3edf51326825e4ce34730604ab4d3522bd103c828112617841c50911bd782b291d031c80b1847b70b2466f8a594e8228ad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b9df58044341d94dfdfbd7423f9f8e44cbd1988eb021f9af28aff240c9a82a2c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bAFCmE1imuaZWJTenn5euNP+ReFkHX69Y5WdLmFUi6M=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c0142\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eff2 8cc3 84a9 acee | 130 c961 (0) c9c3 (0) c8ea (0) c8c8 (0)\n001 4 3c5b 0111 1add 1dec | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 8 48d7 48f1 4a95 447a | 35 4d38 (0) 4d91 (0) 4cec (0) 4a95 (0)\n003 6 741a 7660 7049 7c7c | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 5 60c5 648a 6758 67f3 | 6 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n005 2 68cb 6b4e | 2 68cb (0) 6b4e (0)\n006 1 6e7f | 1 6e7f (0)\n============ DEPTH: 7 ==========================================\n007 3 6d5e 6d3c 6dd3 | 3 6dd3 (0) 6d3c (0) 6d5e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","private_key":"9ca2399351f822028b5da22e6bc0154901d8ea738bbdf6bdcd4bcc21c3ed0d5b","name":"node_6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","services":["bzz","pss"],"enable_msg_events":true,"port":36003},"up":true}},{"node":{"info":{"id":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","name":"node_eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","enode":"enode://e8b833b40e8298b358b18b45e4339fb6608150de9aac211997746cd94c54f9aaf222cffa82031877b46c104bcf3925b66ec72c0249c56469a6e91915a5e55264@127.0.0.1:0","enr":"0xf88fb84052bdfa57cdb21c78128b249f7474f67fc7914496c70263b47c9c07b65968118861855f3f3557bbe4d668f5f65ac095b39e2e02b29c76aec618aa9680f4dda5570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8b833b40e8298b358b18b45e4339fb6608150de9aac211997746cd94c54f9aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7/JFC+p5f/Ztk+fBwbCXfN3zq7pkv6UbzFCdcoVp4vo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eff245\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1dec 6795 6c01 52a8 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 7 8e7b 8006 80d7 a330 | 75 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n002 4 c603 c74d d209 d959 | 27 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n003 4 fc51 ff75 f9de f8ff | 14 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n004 3 e681 e64d e277 | 7 e471 (0) e681 (0) e64d (0) e09f (0)\n005 2 e867 eb68 | 2 eb68 (0) e867 (0)\n006 2 ec90 ed42 | 2 ec90 (0) ed42 (0)\n============ DEPTH: 7 ==========================================\n007 1 eebd | 1 eebd (0)\n008 0 | 0\n009 1 ef99 | 1 ef99 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","private_key":"5dfe6750469b59c78af3ed5c6d49cda36cf5da33a2b02380cadc1833ffacec3e","name":"node_eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","services":["bzz","pss"],"enable_msg_events":true,"port":44215},"up":true}},{"node":{"info":{"id":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","name":"node_52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","enode":"enode://6d8774da40def7a5b17bb5815e018bc2cefba4129897e17f1a8fe1c9b86218c3d980322811c74b84881232dfa2370d502be9bf56cf705dc2fa1442fab44e1a9f@127.0.0.1:0","enr":"0xf88fb8404567e884ed9478156080ac3b497bacbba7c91cebeb40e60ff39f2fc98237d0bb13fdcab19d93a55bc38c89b23f382274493972d896ce4cb24af71a9f169ab2cd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036d8774da40def7a5b17bb5815e018bc2cefba4129897e17f1a8fe1c9b86218c3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Uqh0fk6jX29Qxy18SBYW9opeQ5YkgzK4/2nTp3LeSaw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 52a874\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d959 eff2 | 130 b8e1 (0) ba91 (0) bbaf (0) bfc7 (0)\n001 4 3c5b 0111 1add 1dec | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 7e47 6795 6c01 | 26 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n003 8 4cec 48f1 435d 402c | 19 4d38 (0) 4d91 (0) 4cec (0) 4b79 (0)\n004 6 5d82 5c7c 5c37 5987 | 10 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n005 2 56ca 5538 | 3 5663 (0) 56ca (0) 5538 (0)\n============ DEPTH: 6 ==========================================\n006 2 50c1 5144 | 2 50c1 (0) 5144 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","private_key":"7184fbc50435ce3da686084be1e05ae373d949ebfd17f019adc5f3d36e027659","name":"node_52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","services":["bzz","pss"],"enable_msg_events":true,"port":38653},"up":true}},{"node":{"info":{"id":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","name":"node_d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","enode":"enode://5f6d3c7b333f15437a8e10851a5e5b69df52d2a88441bf1b087a510149da211b403d95794b7be4b00888e746c0db90dd087f785db90c5ce96e76e977a0c3658d@127.0.0.1:0","enr":"0xf88fb840b90e0d1da9269f37eba660dc778bd68fc19e66ec3e2f8286c01ee9b08b44ac4704329c54f9f909700083ee04d27d04a671277fc4dab0023848748a1f385c96c10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035f6d3c7b333f15437a8e10851a5e5b69df52d2a88441bf1b087a510149da211b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2Vll5EndQGmHY4TPSzT5hnMeJVp5SPCoYtIpsd3bxQI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d95965\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0111 3c5b 52a8 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 5 acee 9464 8862 80d7 | 75 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n002 4 f8ff e277 e867 eff2 | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 4 c8c8 c603 c6a8 c74d | 16 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n004 3 d3e9 d302 d209 | 5 d700 (0) d408 (0) d3e9 (0) d302 (0)\n005 1 ddb8 | 1 ddb8 (0)\n============ DEPTH: 6 ==========================================\n006 3 dbd4 dad0 da36 | 3 dbd4 (0) dad0 (0) da36 (0)\n007 0 | 0\n008 1 d9cf | 1 d9cf (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","private_key":"3e7c884510e8b3aa30441168b9f41d34a41cc93dd314587ff58a092474081075","name":"node_d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","services":["bzz","pss"],"enable_msg_events":true,"port":42317},"up":true}},{"node":{"info":{"id":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","name":"node_8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","enode":"enode://00b96eb6a76e41ed136cbe16d1d887b7bbac5a0bd72bb337756b733add37c60d759a8e32a3de23839c55ca9896ae7de7f3d7e955f907935c60f6837c76407032@127.0.0.1:0","enr":"0xf88fb8404180b1565d27eada9a91fcc9783f8bb81c62344bcfe8f579644b225ff80f24972b11fbbd09b6e8e56b49515a95647d596e31f4aab16005512cc2a95035324c810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10200b96eb6a76e41ed136cbe16d1d887b7bbac5a0bd72bb337756b733add37c60d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gAawgMeKCrVPob51qTm+4jNDIv3tbDVj3hWWsXw2Fyw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8006b0\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5a26 1dec | 126 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n001 3 eff2 d302 d959 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 5 a0c8 a330 aaf0 aeb4 | 37 b8e1 (0) ba91 (0) bbaf (0) bcf8 (0)\n003 2 9518 9c8e | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 3 8862 8cc3 8e7b | 9 8b43 (0) 8854 (0) 8862 (0) 8f9a (0)\n005 4 87a3 86d6 8402 84a9 | 4 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n006 3 837f 8358 834f | 3 837f (0) 8358 (0) 834f (0)\n007 1 81a5 | 1 81a5 (0)\n008 1 80d7 | 1 80d7 (0)\n============ DEPTH: 9 ==========================================\n009 2 8073 8074 | 2 8073 (0) 8074 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","private_key":"fcb5be43acaccb42dc1ccc165ea1cfd8c513cf177216d2c30891da51422d3c28","name":"node_8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","services":["bzz","pss"],"enable_msg_events":true,"port":34767},"up":true}},{"node":{"info":{"id":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","name":"node_1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","enode":"enode://0f9ec77321a98a1f538e0d5d9ef25b2b88fb31c678c3eb96345ec11e120bf502f24062c58885fab4104bcde1c4d556514688684c9f451a52d5296e1e904b553f@127.0.0.1:0","enr":"0xf88fb840a7d34c4c4c304a57c17de44dce8fa8a85dd33c61c06dd8848a767401a5f335044a5ea299bd475fb2a27fc686f0d4f124f75520dc1dde65822225e7467289bafb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030f9ec77321a98a1f538e0d5d9ef25b2b88fb31c678c3eb96345ec11e120bf502","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Hex3wvTK8FPC0FJK40otlwv0dDoNAJ2PxUMHfd/f49A=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1dec77\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 e277 e867 eff2 a330 | 130 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n001 3 6795 6c01 52a8 | 61 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n002 3 2c85 2a50 3c5b | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 5 0e3b 0cfc 08f8 09b3 | 21 0d1c (0) 0cfc (0) 0e80 (0) 0e2b (0)\n004 6 1049 138d 1784 1686 | 7 1070 (0) 1049 (0) 138d (0) 1686 (0)\n005 6 19ea 194e 18e0 1b1d | 6 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n============ DEPTH: 6 ==========================================\n006 1 1fd0 | 1 1fd0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1dc0 | 1 1dc0 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","private_key":"26da41b73f097099d65984b38ff4a2abed7a066916fc7defac16025a9b048f64","name":"node_1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","services":["bzz","pss"],"enable_msg_events":true,"port":44061},"up":true}},{"node":{"info":{"id":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","name":"node_1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","enode":"enode://9548a286c10115387facaf19d1e4f0a89e912d85029c1c487158207abe9e881aa61089ccb01238b15c8cd3cea9a71d520c4253dd1b487a963865c8947790bc2a@127.0.0.1:0","enr":"0xf88fb840ec288c0946306b1c5322ec315d33d13022eaef5463fd9d585df1000c7f70914713feb9d24a31c080bfca34d7f32d2f2f4a7cc8472108a6e5b3a68a74f3777ff80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029548a286c10115387facaf19d1e4f0a89e912d85029c1c487158207abe9e881a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Gt3UqfAUhiEuE+Q6llC395NhfRy1n7jZQScNeuVfV18=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1addd4\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e277 a330 80d7 | 130 f1ed (0) f215 (0) f2b4 (0) f305 (0)\n001 3 52a8 447a 6c01 | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 4 2c85 298a 26ab 3c5b | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 3 0e3b 08e5 0111 | 21 0d1c (0) 0cfc (0) 0e80 (0) 0e2b (0)\n004 3 1784 1484 140d | 7 1049 (0) 1070 (0) 138d (0) 1686 (0)\n005 3 1fd0 1dc0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 19ea 194e 18e0 | 3 19ea (0) 194e (0) 18e0 (0)\n============ DEPTH: 7 ==========================================\n007 2 1b1d 1bd5 | 2 1b1d (0) 1bd5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","private_key":"0913c134c0b143e925b0c88a1fdf7b3b79761d599db43e77f87db4896c1677ea","name":"node_1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","services":["bzz","pss"],"enable_msg_events":true,"port":39027},"up":true}},{"node":{"info":{"id":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","name":"node_80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","enode":"enode://9e5ae61e978f364f62889e17b22a8f9248f40ec009d4b43b3b05f92eda9394c87e382e2459b92a93e6b62e2103ab0f7a3c37c5251ef272e7c4ce8b47145ba2b1@127.0.0.1:0","enr":"0xf88fb840e9a52f21b9b8b379be4383a4cff9a6331d63db696a7236c2b700b217ca1e7bb97104740ffffdf09ddfb44f932fa5534cbd2541e7a4dd75920c0dc26241fa43290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039e5ae61e978f364f62889e17b22a8f9248f40ec009d4b43b3b05f92eda9394c8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gNfokruyaAirsdFTAHf+xrCHaMFRqfIgiB2jyGK64K8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 80d7e8\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5a26 3b02 3c5b 0111 | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 4 eff2 d302 d209 d959 | 55 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n002 5 aaf0 acee aeb4 a0c8 | 37 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n003 6 9c8e 9257 97da 9464 | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 6 8b43 8854 8862 8e7b | 9 8b43 (0) 8854 (0) 8862 (0) 8f9a (0)\n005 4 86d6 87a3 8402 84a9 | 4 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n006 3 837f 8358 834f | 3 837f (0) 8358 (0) 834f (0)\n007 1 81a5 | 1 81a5 (0)\n============ DEPTH: 8 ==========================================\n008 3 8073 8074 8006 | 3 8073 (0) 8074 (0) 8006 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","private_key":"ba50fc539edd826fed0a669af162891458571b2d3feed69df70bd146d17ce4ed","name":"node_80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","services":["bzz","pss"],"enable_msg_events":true,"port":39407},"up":true}},{"node":{"info":{"id":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","name":"node_0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","enode":"enode://5ee976bcaa543b5d2ea1a0bce5b0ff16849ede88771b4d0539bcf66b2a275089315547a16297807f96f1634144fba1112ca22817182c90947739c6db02226d55@127.0.0.1:0","enr":"0xf88fb840b273fc1fa015b0a0b045a26f170ca39c7ded0d15989a8d2f9a15df15c5c1471a3943fd8ce033b73dd6cc8f6d988a1e6f4b6ad088a8148478fe0728cdc8a5b4aa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035ee976bcaa543b5d2ea1a0bce5b0ff16849ede88771b4d0539bcf66b2a275089","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ARHnIKhLMQ+GPCUw++FJ5qIhrLrQEGXF0FLSs+Fxb1Q=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0111e7\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d209 d959 80d7 | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 4 6795 6c01 52a8 447a | 61 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n002 2 2a50 3c5b | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 3 18e0 1add 1dec | 16 1070 (0) 1049 (0) 138d (0) 1686 (0)\n004 6 0cfc 0e3b 09b3 08bd | 11 0d1c (0) 0cfc (0) 0e80 (0) 0e2b (0)\n005 4 046c 0594 0561 07f5 | 4 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n006 3 025d 035f 0314 | 3 025d (0) 035f (0) 0314 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0191 | 1 0191 (0)\n009 0 | 0\n010 1 012b | 1 012b (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","private_key":"91fae292525cee25df7bf4db07a65551f7691e6d2bc6a6919a32b5862b97dc00","name":"node_0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","services":["bzz","pss"],"enable_msg_events":true,"port":44549},"up":true}},{"node":{"info":{"id":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","name":"node_3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","enode":"enode://d5a336637f6123924c25472b63ed0ce1759aaa0df7f6d4a18ab36dd8976db21757be5de42d1a3edef967c5d508a894b841f272453643d4c7827490b2286d7177@127.0.0.1:0","enr":"0xf88fb8404f46f3f9d69855c1359b03501474fc383b4578f1b7b40877d2c279c467756cf54804a11759187a452f18bc0291d786321ce06bae18d6cd130e358172c6c4ee5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d5a336637f6123924c25472b63ed0ce1759aaa0df7f6d4a18ab36dd8976db217","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PFsuElAgyA42dN+crDTeTY86lO4CVW+1V5IbbVSYuTM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3c5b2e\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 d959 c74d acee 80d7 | 130 f1ed (0) f215 (0) f2b4 (0) f305 (0)\n001 6 6c01 6795 402c 447a | 61 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n002 6 1784 1dc0 1dec 1add | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 4 26ab 2c85 298a 2a50 | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 6 3728 36b9 30fe 3051 | 9 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n005 5 3980 3938 397a 3b02 | 5 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n============ DEPTH: 6 ==========================================\n006 1 3f31 | 1 3f31 (0)\n007 0 | 0\n008 1 3cab | 1 3cab (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","private_key":"10f73f4d9bbb99564f267bf19aee5d5029238f913a01009124c433e72e461c43","name":"node_3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","services":["bzz","pss"],"enable_msg_events":true,"port":35855},"up":true}},{"node":{"info":{"id":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","name":"node_84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","enode":"enode://7c5c0013e73e1e336ff20c1718a135e5725dc06c6f0c9f9090220223d8e9ae14776b3d3d2073ec0f9ac79ad91739644142a122c2ac9e79f6fedbeb3d24fbe15a@127.0.0.1:0","enr":"0xf88fb840ffe7dbb7a2a573810eb50ef23e54deecd328d7b7e0502170861ff9dd20f39c683db509751dd87bfb7a1b6e1671d2f50655924fa021c7601cd337daed4a4b0f910183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027c5c0013e73e1e336ff20c1718a135e5725dc06c6f0c9f9090220223d8e9ae14","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hKnbdkXHktw4wfIROo8FkNBOHJTZqMRkqw7IIZMD2WY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 84a9db\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5a26 402c 7e47 67f3 | 126 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n001 4 e64d f8ff c603 c74d | 55 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n002 8 bfc7 be68 b3f9 aaf0 | 37 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n003 3 9c8e 97da 9518 | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 5 8862 8854 8ea2 8e7b | 9 8b43 (0) 8854 (0) 8862 (0) 8f9a (0)\n005 7 837f 8358 834f 81a5 | 8 837f (0) 8358 (0) 834f (0) 81a5 (0)\n============ DEPTH: 6 ==========================================\n006 2 87a3 86d6 | 2 87a3 (0) 86d6 (0)\n007 0 | 0\n008 1 8402 | 1 8402 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","private_key":"942aadc68bdea22f3ce52da3ae7b6f7c03ec9e47e5d2b153161be660d1a0ae91","name":"node_84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","services":["bzz","pss"],"enable_msg_events":true,"port":33215},"up":true}},{"node":{"info":{"id":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","name":"node_c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","enode":"enode://97af56cb76aa2eaec4aeef2c8cec152cbe5b98224f219b0fc82f0c0a3648951cf0b429a35548829391d1a4d9a663cde74dd333c0c012e6a1f8d6e677a006dc00@127.0.0.1:0","enr":"0xf88fb840c23585d8a52b92c0cd98c86cc18d8ea7593dd6740927c3fa9aab25a49c02996a1091206cf56d09a3ac4f253656b976411b2307fdd0c77cbf1607b6df7e163f760183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10297af56cb76aa2eaec4aeef2c8cec152cbe5b98224f219b0fc82f0c0a3648951c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"x02AHoWsD9iVFIDRB7Qe3cXJJ3VhTEiGs/cy+j0aeR0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c74d80\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 447a 3a62 3c5b | 126 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n001 2 8cc3 84a9 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 5 ff75 f8ff e277 e64d | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 6 d209 d302 dbd4 dad0 | 11 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n004 2 cd6c c8c8 | 8 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n005 2 c2d0 c272 | 3 c190 (0) c272 (0) c2d0 (0)\n006 2 c534 c42e | 2 c534 (0) c42e (0)\n============ DEPTH: 7 ==========================================\n007 2 c603 c6a8 | 2 c603 (0) c6a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","private_key":"459826aca20135c53b872b1b2eee49b09c127ff95d3a98d517dc55c101f6562a","name":"node_c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","services":["bzz","pss"],"enable_msg_events":true,"port":46857},"up":true}},{"node":{"info":{"id":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","name":"node_8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","enode":"enode://f5bd9f767508bd665cf322b697829a1c303223f3e1953dac7fb2aa3ecb12f562a82f48929f997d96979eda587e53151f11fb6b0c1a477bcaea877333608f8938@127.0.0.1:0","enr":"0xf88fb84049abb7ae67d8f18e608e10433911a04e12e66842debe93fddfd1b92dd4b5249e2e0d73655939db3ec05377a8ea47300d98f115a6d484239b195f4757342458470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f5bd9f767508bd665cf322b697829a1c303223f3e1953dac7fb2aa3ecb12f562","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jMP7OQCdCtwm/KHi7paCLRaNTevDef1RbBXUtKFiQjE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8cc3fb\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1dec 6c01 7e47 402c | 126 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n001 2 d209 c74d | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 6 be68 b3f9 aaf0 acee | 37 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n003 4 9c8e 93c0 95c0 9518 | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 8 834f 837f 81a5 80d7 | 12 8358 (0) 834f (0) 837f (0) 81a5 (0)\n005 3 8854 8862 8b43 | 3 8b43 (0) 8854 (0) 8862 (0)\n============ DEPTH: 6 ==========================================\n006 4 8f9a 8ea2 8e28 8e7b | 4 8f9a (0) 8ea2 (0) 8e28 (0) 8e7b (0)\n007 1 8d19 | 1 8d19 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","private_key":"ab529b2f870b41497c801949c1e6f8803428c7a8a5401009fb5aecf2146a8021","name":"node_8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","services":["bzz","pss"],"enable_msg_events":true,"port":32793},"up":true}},{"node":{"info":{"id":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","name":"node_a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","enode":"enode://2e41f2b550586042c5f6fc98479cf8647f043156b413c46a8a44e5e748b12ad67219bf8846538c69bd1512ba2b2372b455d2db5bb6833d24f26e6c9a1f59d5c8@127.0.0.1:0","enr":"0xf88fb840ae31abaa7b69ba78463e2aabc17bdba4aab8ffa918141bc3c9628311a50f0e8f60fc4d7edd0a2d6d9d31bdc7358e66ea37b3726c4daa85d3112b655b7bea23220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022e41f2b550586042c5f6fc98479cf8647f043156b413c46a8a44e5e748b12ad6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ozCfi4u6TY+9fGGT12ccuQe5TnEVXvYTjgJIaC/wDlg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a3309f\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 447a 402c 09b3 1dec | 126 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n001 5 f8ff e64d eff2 d302 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 5 9c8e 8006 80d7 84a9 | 38 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n003 3 b3f9 bfc7 be68 | 14 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n004 4 aaf0 ab71 aeb4 acee | 10 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n005 4 a5ac a505 a606 a616 | 7 a4ee (0) a5ac (0) a505 (0) a742 (0)\n006 2 a1c8 a0c8 | 2 a1c8 (0) a0c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a2e6 a2a1 | 2 a2e6 (0) a2a1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a327 | 1 a327 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","private_key":"f5a3649f592d0f7c3eced972c572abd68fb996716ce6c51e2f9c236db5ee5f7f","name":"node_a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","services":["bzz","pss"],"enable_msg_events":true,"port":46725},"up":true}},{"node":{"info":{"id":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","name":"node_2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","enode":"enode://c001df527a6a418a2bb70ac07ea54973e446f8037817071d1099e394bf3cf208a58bf9796e8e5c5f9fe0ab71cde46b1e3b320c911fa86e6af286e603ce8a9d04@127.0.0.1:0","enr":"0xf88fb840543888f27b45d292760976edb014e7c72679a5831e78c7496fd2bc5d78af0c377e0981dcbe633f5465ca9546ada0184be5e5a640dd77b8f6ea51c936515ab1d20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c001df527a6a418a2bb70ac07ea54973e446f8037817071d1099e394bf3cf208","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KlB/XLkhE3pyJcnEmIqFFK8PfjxELLi/K7YS3FIqfa8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a507f\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f9de f8ff ff75 e867 | 130 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n001 3 7e47 4a95 447a | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 6 1dec 08bd 09b3 07f5 | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 11 36b9 3051 3188 31e6 | 17 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n004 4 24f8 244c 26ac 26ab | 4 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n============ DEPTH: 5 ==========================================\n005 5 2fd2 2e65 2ddf 2c80 | 5 2fd2 (0) 2e65 (0) 2ddf (0) 2c80 (0)\n006 1 298a | 1 298a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","private_key":"ba89f2c3d704a1b02be39f28124317f79d2630278219ab9397e5250cbaab1347","name":"node_2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","services":["bzz","pss"],"enable_msg_events":true,"port":40127},"up":true}},{"node":{"info":{"id":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","name":"node_447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","enode":"enode://93cb54d9649a77b0cdde7ac6f47e4b97f7601de7e8881dd99e904b4c0f29e973261a2ca33856145834ad9fa4b35e8100f57851652ae17382da483d915520cef9@127.0.0.1:0","enr":"0xf88fb840f9ca3c35e33f2fe6bfb3114da2e3c50397d620dc275d5fdf0fca027de00c6ba20aceee4ab1ac417c80e3c10d7ab9f21e3b07da298b81aac6a8f6b7b38a4936d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10393cb54d9649a77b0cdde7ac6f47e4b97f7601de7e8881dd99e904b4c0f29e973","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RHpBHID71CK/oMNY0/Kh/mJWwF41rMY1CVjfvmLNW5s=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 447a41\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a330 8cc3 c74d d209 | 130 b78f (0) b659 (0) b6df (0) b5ea (0)\n001 8 140d 1add 0314 0111 | 65 1049 (0) 1070 (0) 138d (0) 1686 (0)\n002 6 6c01 648a 6758 6795 | 26 60c5 (0) 648a (0) 6758 (0) 6790 (0)\n003 8 5bd8 5a8b 5a26 5d82 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 6 48f1 48b8 4b79 4a95 | 10 4a95 (0) 4b79 (0) 482e (0) 48b8 (0)\n005 5 43d4 43c9 435d 4005 | 5 43d4 (0) 43c9 (0) 435d (0) 4005 (0)\n006 1 46bf | 1 46bf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 44ad | 1 44ad (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 447c | 1 447c (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","private_key":"333ffec493a411ee5a1cf2f27903e2738e2967073c019fcbf70844d2c5e221fb","name":"node_447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","services":["bzz","pss"],"enable_msg_events":true,"port":46191},"up":true}},{"node":{"info":{"id":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","name":"node_d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","enode":"enode://fa46b1409f74c7047256751457bb4839d22d4c44e870020c92b9a8094d40fffd0bbe32e0d0e17a80c1a5cda6744641633435612ef66e4d1efe652f2190e9898c@127.0.0.1:0","enr":"0xf88fb840ec8f9457cb967b5716665ff449c2d75e0cba1fb09465164ee48b4a314d3bbb0d2cffff4ac93409d690a86ae7b8031ec765f327ec503895ea2d4ae58be0ea6d490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fa46b1409f74c7047256751457bb4839d22d4c44e870020c92b9a8094d40fffd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0gkxzj2pcv0j6jBuXGBKH72UF7oCZUxc2+J4/iWfddU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d20931\npopulation: 23 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0111 3a62 447a | 126 1070 (0) 1049 (0) 138d (0) 1686 (0)\n001 3 80d7 8cc3 a330 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 5 f8ff e867 eff2 e277 | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 4 c8c8 c74d c6a8 c603 | 16 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n004 4 dbd4 dad0 da36 d959 | 6 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n005 2 d700 d408 | 2 d700 (0) d408 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 d3e9 d302 | 2 d3e9 (0) d302 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","private_key":"1efdf65d1076ab6055d3624a77725affdd2e31a88571efc3f60d3ccaff92f6bb","name":"node_d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","services":["bzz","pss"],"enable_msg_events":true,"port":39387},"up":true}},{"node":{"info":{"id":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","name":"node_3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","enode":"enode://699f62b0ede6090f23dc2599d33c7358ae7b40e7968fafc5a628f37665146f48126c277ba115635c40a4b4b0c21129c569efe2b0088a0e1a2a7c2e79793fd6ad@127.0.0.1:0","enr":"0xf88fb8408c0574ebe34e80bece2feb6738856fa36e55e93c1692ea7e973fb6f5948061ba1afefff01aa4e3ffe13b7ab2318e4d5201b0083ee6a4067fe0a7436c371f93c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103699f62b0ede6090f23dc2599d33c7358ae7b40e7968fafc5a628f37665146f48","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OmKO8XHB8m+glm64khC+ChQwWq6L/tEPTtkBdpj0D0s=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3a628e\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c6a8 c74d d209 | 130 b659 (0) b6df (0) b78f (0) b4a1 (0)\n001 4 7e47 5c37 402c 447a | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 7 1484 140d 1dc0 18e0 | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 4 26ab 2c85 2a50 298a | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 7 36b9 3728 3051 30fe | 9 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n005 3 3f31 3cab 3c5b | 3 3f31 (0) 3cab (0) 3c5b (0)\n============ DEPTH: 6 ==========================================\n006 3 3980 3938 397a | 3 3980 (0) 3938 (0) 397a (0)\n007 1 3b02 | 1 3b02 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","private_key":"dcc4c59e4839e1a65f299219ca7016fdaa5f40089be97dd01f6e44b309e517e1","name":"node_3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","services":["bzz","pss"],"enable_msg_events":true,"port":45801},"up":true}},{"node":{"info":{"id":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","name":"node_031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","enode":"enode://f6a817139fae4583a57556cc9a0a457c0473f3420d9c159dde94147684cef58dee5800eba9eed6ce4bca94ed4f0b5990cf1300abc416d3abe67117ff987e3893@127.0.0.1:0","enr":"0xf88fb840ac7d354eab1b00a4d18d770c7a56c8bd41a723c51be5b45f95ac7541b76ffd8a6b2abb20615da04d0e0b07abf9c9d1a2c014424bc3c8d645913be94303912ddd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f6a817139fae4583a57556cc9a0a457c0473f3420d9c159dde94147684cef58d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AxRQ7CDzU0NbQptfpk9hbQfJ1Yavq8eidy4FrVyIv1A=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 031450\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e64d d302 | 130 b4a1 (0) b5ea (0) b78f (0) b659 (0)\n001 2 447a 402c | 61 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n002 5 2a50 31e1 31e6 3b02 | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 2 18e0 140d | 16 1fd0 (0) 1dc0 (0) 1dec (0) 1b1d (0)\n004 6 0e2b 0e3b 0cfc 08bd | 11 0e80 (0) 0e2b (0) 0e3b (0) 0d1c (0)\n005 3 07f5 0561 0594 | 4 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n006 3 0191 012b 0111 | 3 0191 (0) 012b (0) 0111 (0)\n============ DEPTH: 7 ==========================================\n007 1 025d | 1 025d (0)\n008 0 | 0\n009 1 035f | 1 035f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","private_key":"71841c7c5c5d9ea8a678e5f6274467f74b6f88c13bbf848178459758f86d8039","name":"node_031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","services":["bzz","pss"],"enable_msg_events":true,"port":43487},"up":true}},{"node":{"info":{"id":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","name":"node_402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","enode":"enode://5bc25029b77714e83add4d5587be2adb2f795f9c9a708fa117f943c07da69023a978354c7584edf8e72592dd799def444d777216cbff5e09d84ed2a3e6cfc802@127.0.0.1:0","enr":"0xf88fb8405ae20f58d8ca24088b13d83e73fa85b6edd318d7a36af6bae3b1561d4e35defe0bc84c46bd137181da067946faf218082b19c9f7508adabe054d430ca14ba09b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025bc25029b77714e83add4d5587be2adb2f795f9c9a708fa117f943c07da69023","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QCz50L/6AX6+o07eESB/M2az6kUMBCgCkSmo6AJqu+c=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 402cf9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 84a9 8cc3 a330 e64d | 130 b4a1 (0) b5ea (0) b659 (0) b6df (0)\n001 5 298a 3c5b 3a62 3b02 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 5 6d5e 6c01 648a 6795 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 3 5a26 5144 52a8 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 6 48d7 48f1 4a95 4cec | 10 482e (0) 48b8 (0) 48f1 (0) 48de (0)\n005 4 46bf 44ad 447c 447a | 4 46bf (0) 44ad (0) 447c (0) 447a (0)\n============ DEPTH: 6 ==========================================\n006 3 43d4 43c9 435d | 3 43d4 (0) 43c9 (0) 435d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 4005 | 1 4005 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","private_key":"94e11eac44f6245218d5abd3d9478e311e64c9803c0c5ea086b6de56d4679633","name":"node_402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","services":["bzz","pss"],"enable_msg_events":true,"port":32811},"up":true}},{"node":{"info":{"id":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","name":"node_3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","enode":"enode://713a1cedffa4515ada02fdd05d03e281b216f290f667a579b6122990b58832fda74606019246522aa1ea21612c64c9b061a99f77ecf52541607f91c645c9b911@127.0.0.1:0","enr":"0xf88fb84078578015605b97496872b339f38876ed514660f63b799e2055976f1d31a7256c29c36362b416362b1c38dcd9dbaf0d98160a481b84e0944a33d9103c1cf2c9890183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103713a1cedffa4515ada02fdd05d03e281b216f290f667a579b6122990b58832fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OwIMhPtg9Zd5Mk1FHZdw1oPggTO7qi1XYvYbj9S42f0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b020c\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a330 9f0e 80d7 d302 | 130 b4a1 (0) b5ea (0) b659 (0) b6df (0)\n001 4 6e7f 6b4e 5c37 402c | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 2 138d 0314 | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 4 26ab 2c85 2a50 298a | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 7 3188 31e6 31e1 30fe | 9 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n005 3 3f31 3c5b 3cab | 3 3f31 (0) 3cab (0) 3c5b (0)\n============ DEPTH: 6 ==========================================\n006 3 3980 3938 397a | 3 3980 (0) 3938 (0) 397a (0)\n007 1 3a62 | 1 3a62 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","private_key":"f0c6bf4c9b4e4f3d3db2b470e1adab35d6500594faf84c40d4e589d3b516a6e9","name":"node_3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","services":["bzz","pss"],"enable_msg_events":true,"port":45529},"up":true}},{"node":{"info":{"id":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","name":"node_d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","enode":"enode://1d5fd1a24eda6285258a0e82b28b81dc86c0d970745ed58fd4ee8cf25414dfd16855e91f57f27d49ff28688f9e48d9df98094d7afcb28de571ad2db259f803dd@127.0.0.1:0","enr":"0xf88fb840142c7e76eea3d74e38e90903bb658e1359757cafd5441e5414d06d489b74a4f567b2017ecbbcb487cf547fd852e100846966134719b652071d9580fa25f868360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031d5fd1a24eda6285258a0e82b28b81dc86c0d970745ed58fd4ee8cf25414dfd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0wIqRpVudbyoW6idl7aUo6ZPA8zC2IHtDNaH1D1IaSU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3022a\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 67f3 402c 140d 0cfc | 126 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n001 6 bfc7 aeb4 a330 8854 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 6 e64d ed42 eebd ff75 | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 6 c6a8 c603 c74d cd6c | 16 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n004 5 ddb8 da36 dad0 dbd4 | 6 ddb8 (0) dad0 (0) da36 (0) dbd4 (0)\n005 2 d700 d408 | 2 d700 (0) d408 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 d209 | 1 d209 (0)\n008 1 d3e9 | 1 d3e9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","private_key":"d6122cfb13c379e5e6975a57ca7446d6faa10cf87da8ddde9793a570ba433a96","name":"node_d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","services":["bzz","pss"],"enable_msg_events":true,"port":46297},"up":true}},{"node":{"info":{"id":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","name":"node_298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","enode":"enode://e2572a35a51863ebd4d0e48420c58ffb5088cadae300e5779152fe7e009a73f879306e12e40543ab0f2ea87351f9114b427df2e411379eeaeb2f2dd4f6734383@127.0.0.1:0","enr":"0xf88fb840a94663c556b354f4695fad007ac31ab668951708699de5cfaf696a677d15555c6120984becc7bc3b1c3724a42f37b9e009cb7b6c5f37f23758c3a9d2941638d00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e2572a35a51863ebd4d0e48420c58ffb5088cadae300e5779152fe7e009a73f8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KYrl0XPFNgvJrVtJLtNd47bgyuhoo0v+YxGoul6ph34=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 298ae5\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9f0e 8e7b e64d d302 | 130 b3f9 (0) b78f (0) b659 (0) b6df (0)\n001 5 4a95 402c 447a 7e47 | 61 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n002 8 1add 194e 18e0 140d | 37 138d (0) 1070 (0) 1049 (0) 1784 (0)\n003 11 36b9 3051 3188 31e6 | 17 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n004 3 24f8 26ac 26ab | 4 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n============ DEPTH: 5 ==========================================\n005 5 2fd2 2e65 2ddf 2c80 | 5 2fd2 (0) 2e65 (0) 2ddf (0) 2c80 (0)\n006 1 2a50 | 1 2a50 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","private_key":"b0b337287594e581c25600a9c7123555efd6242dd53a8bc83caa7c7890443ac5","name":"node_298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","services":["bzz","pss"],"enable_msg_events":true,"port":33555},"up":true}},{"node":{"info":{"id":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","name":"node_e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","enode":"enode://1c9f6fc264902a736faaf67f7c0de6faee097992d30a5ed225cb334c2a3525ec83d7a038643357fc6c0f7ed5c86e8d272bb475054048f26964e53a4c23b85c6b@127.0.0.1:0","enr":"0xf88fb84037d31d5c2464b59a7a8c3d22f66575e1d23a2d4ea24038f76b84d3446bcd41e51fd1f5dc7189f516c23bbefa0b11f2e7185ef3277b7aa33a4c84594247c8d7bb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031c9f6fc264902a736faaf67f7c0de6faee097992d30a5ed225cb334c2a3525ec","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5k2QdgzYHk8RK78UMudsgvpBc/1HS5iPQJbOGHNj/YE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e64d90\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 09b3 0594 0314 18e0 | 126 0191 (0) 012b (0) 0111 (0) 025d (0)\n001 6 84a9 be68 a0c8 a330 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 4 d302 d209 c6a8 c74d | 27 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n003 3 ff75 f8ff f9de | 14 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n004 4 e867 ed42 eff2 eebd | 7 eb68 (0) e867 (0) ef99 (0) eff2 (0)\n005 3 e09f e2d3 e277 | 4 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n============ DEPTH: 6 ==========================================\n006 1 e471 | 1 e471 (0)\n007 0 | 0\n008 1 e681 | 1 e681 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","private_key":"7d27024b921b4fc8acb154f5988128977df743101939d754b1b2b55b69bf2b2e","name":"node_e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","services":["bzz","pss"],"enable_msg_events":true,"port":44039},"up":true}},{"node":{"info":{"id":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","name":"node_7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","enode":"enode://12b03573c2a76013619215fba5146b7c44aa72aa214d577e70f611196a80f33b6d2332c3736388f5fdb74a5924f3ee97a4f435093835efe46cfa7b049237fe74@127.0.0.1:0","enr":"0xf88fb840c9ef22c878c1759a06aee668ff6358beb1cf4dd0e15021dce3fd0e637754d3cf1bbebf8a3aa0d6e9bc391e27ad7c93101089f6d54bd0257fb3536766cb4258bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212b03573c2a76013619215fba5146b7c44aa72aa214d577e70f611196a80f33b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fkei+CmEpgDIWDYFqR1cuPLZoYlhhF6cQi7deOIKw6M=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7e47a2\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 84a9 8cc3 c6a8 e64d | 130 ab71 (0) ab3f (0) aaf0 (0) a8b5 (0)\n001 6 298a 2a50 397a 3a62 | 65 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n002 8 5a26 52a8 4d91 4cec | 35 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n003 8 6b4e 6e7f 6d5e 6c01 | 13 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n004 2 7660 741a | 4 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n005 3 7850 79e5 7933 | 4 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n============ DEPTH: 6 ==========================================\n006 4 7d16 7ce7 7c7c 7c46 | 4 7d16 (0) 7ce7 (0) 7c7c (0) 7c46 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","private_key":"aa9445dea3d9ca188039006df2529b909dbd39486296eeeb022fb2dd285c4536","name":"node_7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","services":["bzz","pss"],"enable_msg_events":true,"port":42041},"up":true}},{"node":{"info":{"id":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","name":"node_c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","enode":"enode://454955797f0067874592850e49998fdc19a2c7bd33a4ff25e33927c6558364eaaf7a788b4ec32bb46722acea4d1a61b9755b0779fbdb323a0f1807ccf6337571@127.0.0.1:0","enr":"0xf88fb84055d87acf3986e47cda898bdd603f343a724a7fc35b5f908e71195bea21f0cfae27ff3cda3965530d8614a9170b9f1aed47abe0d78c21209022d88b407fa338f40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103454955797f0067874592850e49998fdc19a2c7bd33a4ff25e33927c6558364ea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xqgiByYkPM6qbyzr2shXoF7+chMj8KBkx/hag0DT2pY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c6a822\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3a62 18e0 7e47 | 126 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n001 5 a0c8 aeb4 95c0 97da | 75 a742 (0) a7a8 (0) a616 (0) a606 (0)\n002 4 e64d eebd ff75 f8ff | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 5 d302 d209 dbd4 da36 | 11 ddb8 (0) dad0 (0) da36 (0) dbd4 (0)\n004 3 cd6c c961 c8c8 | 8 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n005 3 c190 c272 c2d0 | 3 c190 (0) c272 (0) c2d0 (0)\n006 2 c42e c534 | 2 c42e (0) c534 (0)\n============ DEPTH: 7 ==========================================\n007 1 c74d | 1 c74d (0)\n008 1 c603 | 1 c603 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","private_key":"8f0f60c08655c540026e8566ec695b938ce61b2b96646b0264adf44d9e42610e","name":"node_c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","services":["bzz","pss"],"enable_msg_events":true,"port":44073},"up":true}},{"node":{"info":{"id":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","name":"node_18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","enode":"enode://339676ff1a748c6537d18f6876bb9f1909665415872fa5d5c3a62ee4142ccd6fceb523240a14dc3df222a387212b8f68be3b473f1299016b0b9d342152f0d610@127.0.0.1:0","enr":"0xf88fb840a9c71d615a4992252278bfec4f901f2a5c0bcd153ec613f025be3ea3b9ec116e7fc2d46f878030a2375d5d8467b882559e854ec34a52e0633388ca26268d39dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102339676ff1a748c6537d18f6876bb9f1909665415872fa5d5c3a62ee4142ccd6f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GOAKfg+Cahq6P4wPUz7ZBfLu5ge2l//wVu54dNN0rc0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 18e00a\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e64d c6a8 | 130 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n001 3 435d 6d5e 67f3 | 61 5ff0 (0) 5c7c (0) 5c37 (0) 5d82 (0)\n002 5 298a 3051 31e6 31e1 | 28 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n003 8 096a 0cfc 0e3b 07f5 | 21 012b (0) 0111 (0) 0191 (0) 025d (0)\n004 5 1049 138d 1686 1484 | 7 1049 (0) 1070 (0) 138d (0) 1784 (0)\n005 3 1fd0 1dc0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 1b1d 1bd5 1add | 3 1b1d (0) 1bd5 (0) 1add (0)\n============ DEPTH: 7 ==========================================\n007 2 194e 19ea | 2 19ea (0) 194e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","private_key":"69b0a121df38253f732ead7d4d9eeb8e3c8f00aef1fb652004da58fd2ebf948f","name":"node_18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","services":["bzz","pss"],"enable_msg_events":true,"port":34725},"up":true}},{"node":{"info":{"id":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","name":"node_140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","enode":"enode://83dc6dc1925eb88e36d37f5c7526d73f05174a1253f00d127ad745dd1c054fa3b925abc6cb084f944a9e2d9ca49f821e98bec10d624c3deaab9c7e2954f80e4e@127.0.0.1:0","enr":"0xf88fb8404586a446db7c94f54415cdc0dc16014a70c60a090734bcdd910014501ce446962d9ec042f168a1cdec3b66fed17422d985d8e4114b5fe512b80e9cd3bead80a00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10283dc6dc1925eb88e36d37f5c7526d73f05174a1253f00d127ad745dd1c054fa3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FA3SEvKxk+5qnX/BT32jIcfvb9Nn+08ZSST9CtXRNcw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 140dd2\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 97da d302 c8c8 f8ff | 130 a742 (0) a7a8 (0) a616 (0) a606 (0)\n001 5 447c 447a 435d 4d91 | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 3 31e6 3a62 298a | 28 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n003 8 07f5 0594 0561 0314 | 21 012b (0) 0111 (0) 0191 (0) 025d (0)\n004 7 1fd0 1dc0 1dec 1bd5 | 9 1fd0 (0) 1dc0 (0) 1dec (0) 1b1d (0)\n005 3 1049 1070 138d | 3 1049 (0) 1070 (0) 138d (0)\n============ DEPTH: 6 ==========================================\n006 2 1784 1686 | 2 1686 (0) 1784 (0)\n007 0 | 0\n008 1 1484 | 1 1484 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","private_key":"a027baaf8dce7a0533664447524ef6ad27032751f5eb84a289de80342d0fe705","name":"node_140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","services":["bzz","pss"],"enable_msg_events":true,"port":44825},"up":true}},{"node":{"info":{"id":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","name":"node_09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","enode":"enode://9d74be605030a4907946d4c396dbc3848b07c4d4d5b66b9171d8ba6d5e60a2558a4bfb0bb3a6b54e540d6dc7628eefcd573ba70bdb77f1f5f121cc0799e85e60@127.0.0.1:0","enr":"0xf88fb840b3dec516c58c4b1c9e69344e8b6c2d6dd826b010cbb4c7b61bd88a6ea6693da73750485c7a1a3bdc77bf30c5076e8a5b2b144deaecf8527f717b018f22c4adc80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029d74be605030a4907946d4c396dbc3848b07c4d4d5b66b9171d8ba6d5e60a255","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CbP6MHgJMeGLksddHN6vo2VgnFZeTowlPTk4NcuC2Y4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 09b3fa\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 aeb4 acee a330 a505 | 130 a970 (0) a8f4 (0) a8ff (0) a8b5 (0)\n001 3 435d 7e47 6d5e | 61 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n002 6 31e1 3a62 397a 3cab | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 2 1dec 140d | 16 1fd0 (0) 1dc0 (0) 1dec (0) 1bd5 (0)\n004 7 0594 0561 07f5 0111 | 10 012b (0) 0111 (0) 0191 (0) 025d (0)\n005 4 0e80 0e3b 0e2b 0cfc | 5 0e80 (0) 0e2b (0) 0e3b (0) 0d1c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 08bd 08e5 08f8 | 3 08bd (0) 08f8 (0) 08e5 (0)\n008 2 0942 096a | 2 0942 (0) 096a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","private_key":"30b0537c3a07c424ed947f31703b416041d6e1ccd1b086cb191d59b53dc632d8","name":"node_09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","services":["bzz","pss"],"enable_msg_events":true,"port":43439},"up":true}},{"node":{"info":{"id":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","name":"node_f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","enode":"enode://51f9bf866b226268237ad44341962115f0595ddc49c87a900c927b7c2c162dae6a3f123b9555e8c0f82927450546ddf8317d461eafe4931b368e709e84b8f060@127.0.0.1:0","enr":"0xf88fb840286a47e012b67dd7b25cc0b9cb9a212019f9b305881989ae09c749fed48a57e16d518566943216dbd238b448ee51fcae686fbc6b12e927e5ab9cfc2d499505000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10251f9bf866b226268237ad44341962115f0595ddc49c87a900c927b7c2c162dae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+P90QNb0q7HIlJYzaEN0HtU6VEzt7u1x2OvgsIaYQ40=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f8ff74\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6d5e 67f3 2a50 140d | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 7 a330 be68 84a9 8e7b | 75 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n002 8 da36 d959 d209 d302 | 27 ddb8 (0) d9cf (0) d959 (0) da36 (0)\n003 6 e867 ed42 eff2 eebd | 14 eb68 (0) e867 (0) ef99 (0) eff2 (0)\n004 3 f2b4 f305 f756 | 7 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n005 2 fc51 ff75 | 4 feb3 (0) ff75 (0) fc39 (0) fc51 (0)\n============ DEPTH: 6 ==========================================\n006 1 fa24 | 1 fa24 (0)\n007 1 f9de | 1 f9de (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","private_key":"d5ad379d43fa81ba9467d7945d0122c5695d2f7ebdf9d7e1c3384191bd5c4d12","name":"node_f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","services":["bzz","pss"],"enable_msg_events":true,"port":41309},"up":true}},{"node":{"info":{"id":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","name":"node_67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","enode":"enode://e379d322e7ad17953d786c9d00289bcf6921926341c7ecf7c128f043b29b702a5b01c6d92c3a39261f59fe8a2ebe5b26edd01d4971f910d0d6e18250e613e301@127.0.0.1:0","enr":"0xf88fb8400be4b9b202ed1e87dd987244284a9c5a5ad6c866e575c7ec5a929b2e91efad41349b08437a98a0f2909c85c3eedc1f2ba650f16d0a0fcb33ec7276e6cc22801e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e379d322e7ad17953d786c9d00289bcf6921926341c7ecf7c128f043b29b702a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z/OD5TNOm2cB0duyCHbUupp+V4rwR2yu1KfhtwHyvts=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67f383\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 84a9 8854 97da d302 | 130 a8b5 (0) a8ff (0) a8f4 (0) a970 (0)\n001 3 298a 18e0 0594 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 3 4d91 447a 435d | 35 5ff0 (0) 5c7c (0) 5c37 (0) 5d82 (0)\n003 3 741a 7933 7e47 | 13 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n004 6 6b4e 68cb 6e7f 6c01 | 7 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 6758 | 1 6758 (0)\n009 2 6790 6795 | 2 6790 (0) 6795 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","private_key":"b8e7f7fd21a946d988fa718b9babed932cf73070403fbd1c56456f04b8243262","name":"node_67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","services":["bzz","pss"],"enable_msg_events":true,"port":34903},"up":true}},{"node":{"info":{"id":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","name":"node_05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","enode":"enode://b3698b249bc2ecf1f856c3e3f12be6868853b3aa64fe9685b03162dd2a7afd9c491d8328e465d64d17fa49aa429a13c10f1db958b6ab89988370d6465cc0fc01@127.0.0.1:0","enr":"0xf88fb8408c0c34055a93806f387d7f730226b400b33e051c8aabfdda7c998e756544709f2476a88d4935a5c9776c54d5b8a5100260193615759717d3a016f9791a671cc40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b3698b249bc2ecf1f856c3e3f12be6868853b3aa64fe9685b03162dd2a7afd9c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BZSewaWC+nDKuVxZ58DTFVg7+fwyDGDDUmiTHyHpCFM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 05949e\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 97da 8854 ed42 e64d | 130 a970 (0) a8f4 (0) a8ff (0) a8b5 (0)\n001 4 4cec 7e47 6d5e 67f3 | 61 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n002 6 298a 3cab 397a 3a62 | 28 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n003 3 140d 18e0 194e | 16 1fd0 (0) 1dc0 (0) 1dec (0) 1add (0)\n004 5 096a 09b3 08e5 0e2b | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 6 0111 012b 0191 025d | 6 012b (0) 0111 (0) 0191 (0) 025d (0)\n006 1 07f5 | 1 07f5 (0)\n============ DEPTH: 7 ==========================================\n007 1 046c | 1 046c (0)\n008 1 0561 | 1 0561 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","private_key":"13a0aed3cdf03f83f823244e85cbe9e48d61303a1b41e446aadaaf74a2baf6b0","name":"node_05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","services":["bzz","pss"],"enable_msg_events":true,"port":45769},"up":true}},{"node":{"info":{"id":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","name":"node_6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","enode":"enode://191668a4f4a65da7ee37d46e341722e5a4732a0c63dd8b881141e9c281dc8d7f3f148af361d221bf7efa91709c24772b3a1e93236b9605d17fad43e159cbda30@127.0.0.1:0","enr":"0xf88fb840127e770bef790f2f06aeaf24547639a81249e512c9a9e3b2987bb161f1357f021587b4c9c833ef4c5d09f974548ac56b1b375d388486cbb12cd090e542ae43f30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102191668a4f4a65da7ee37d46e341722e5a4732a0c63dd8b881141e9c281dc8d7f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bV7Fka9JZroCTGsq60XgqriqF2L5ysMM45NNpSm3OOk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6d5ec5\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f8ff ed42 97da 8854 | 130 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n001 3 18e0 09b3 0594 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 4d91 402c 435d | 35 5987 (0) 5814 (0) 5bd8 (0) 5a26 (0)\n003 7 70f6 7660 741a 7e47 | 13 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n004 6 60c5 648a 6758 6790 | 6 60c5 (0) 648a (0) 6758 (0) 6790 (0)\n005 2 68cb 6b4e | 2 68cb (0) 6b4e (0)\n006 1 6e7f | 1 6e7f (0)\n007 1 6c01 | 1 6c01 (0)\n============ DEPTH: 8 ==========================================\n008 1 6dd3 | 1 6dd3 (0)\n009 1 6d3c | 1 6d3c (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","private_key":"1ce56a7fe145cc7c87edd8b2675d674db568652b226b80f6da7067c83cba55ec","name":"node_6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","services":["bzz","pss"],"enable_msg_events":true,"port":39153},"up":true}},{"node":{"info":{"id":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","name":"node_435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","enode":"enode://18eb16b8694f440ee7d57163d9cc8181ca5f025dacb16f9afb9e58ea8abdcbbaebed0ab1b856f73ab5ded12b5dd300849b1a721d73e0ac123cc5257373fee65a@127.0.0.1:0","enr":"0xf88fb84017e1348ced6a8488d50ff1773f2ad15c93bee9787be7b6795975b9e5ccb93d777c45645553471401c9fbd354d809e36f1abd98fff3f15723ffdd3f858086833e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10218eb16b8694f440ee7d57163d9cc8181ca5f025dacb16f9afb9e58ea8abdcbba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Q11yGlaOuQagPGnb1xM3JRpVBSGkAEq11KfetvMXBho=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 435d72\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8854 c8c8 | 130 a8b5 (0) a8ff (0) a8f4 (0) a970 (0)\n001 6 3cab 31e1 31e6 140d | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 7e47 67f3 6d5e | 26 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n003 5 5d82 5a8b 5a26 5144 | 16 5ff0 (0) 5c7c (0) 5c37 (0) 5d82 (0)\n004 6 482e 4b79 4a95 4cec | 10 48b8 (0) 48f1 (0) 48de (0) 48d7 (0)\n005 4 46bf 44ad 447a 447c | 4 46bf (0) 44ad (0) 447a (0) 447c (0)\n006 2 4005 402c | 2 4005 (0) 402c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 43d4 43c9 | 2 43d4 (0) 43c9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","private_key":"04326eafbd95ad027f8f4ffe10d64e65b512f2cc4905d138d81f6852b9b0dace","name":"node_435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","services":["bzz","pss"],"enable_msg_events":true,"port":44895},"up":true}},{"node":{"info":{"id":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","name":"node_c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","enode":"enode://c74190c0b1b29a5dd50900f0a04a79e60cdc6b3850d663aee32c681c279fe21cb701d8a3414eb18446e769ba8612766d1ed0240d80c3f6df1a1304d7326c21f0@127.0.0.1:0","enr":"0xf88fb8402b4c635d8867172a6c2a46b297fdd9c8bd917476a45883bc2cf7818442ff495622a30b7d13a6e26a66418c8572b882977e2535a91a46e244bed314001414664e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c74190c0b1b29a5dd50900f0a04a79e60cdc6b3850d663aee32c681c279fe21c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yMipN3nsTZrECSXoIIR4oA7if8Ig3dc9h3TPa/olXEY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8c8a9\npopulation: 23 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 140d 0594 435d | 126 1fd0 (0) 1dc0 (0) 1dec (0) 1b1d (0)\n001 3 be68 8854 97da | 75 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n002 3 ed42 f9de f8ff | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 5 d959 dbd4 dad0 d209 | 11 ddb8 (0) d9cf (0) d959 (0) da36 (0)\n004 3 c74d c603 c6a8 | 8 c190 (0) c2d0 (0) c272 (0) c42e (0)\n005 3 cf52 cdb1 cd6c | 4 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c9c3 c961 | 2 c9c3 (0) c961 (0)\n008 0 | 0\n009 0 | 0\n010 1 c8ea | 1 c8ea (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","private_key":"4e1a61cde64af44b0dda77ec6ccf177754acdcf8296a2f6a28f809a3edd78a51","name":"node_c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","services":["bzz","pss"],"enable_msg_events":true,"port":37665},"up":true}},{"node":{"info":{"id":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","name":"node_97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","enode":"enode://e1a0b593eb6718290b19a241af012bcd050ba91442c444f9cb2728679fbaff94ae18b9344b896242f38d5cc5e5c71365c9b569d2b8c6e75c7237ad6399d03af0@127.0.0.1:0","enr":"0xf88fb8406126b86c32443771ffd4fe3aa1679a8627ee6dac7eb5d4ca51c1cea7b6742a093d407bde58a20a099b8dedea0066471ae30fbef9362c0a2d24ee87b0e22e50f80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e1a0b593eb6718290b19a241af012bcd050ba91442c444f9cb2728679fbaff94","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"l9ryy+A8gM5sTa45zQcd2TyzLtJFqpqncoXhIpaVfKM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 97daf2\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 67f3 6b4e 6d5e 4cec | 126 1fd0 (0) 1dc0 (0) 1dec (0) 1add (0)\n001 5 f8ff f9de ed42 c6a8 | 55 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n002 3 a505 bfc7 be68 | 37 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n003 5 80d7 834f 837f 84a9 | 21 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n004 4 9c8e 9f0e 9959 9948 | 9 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n005 2 9257 93ea | 3 9257 (0) 93c0 (0) 93ea (0)\n============ DEPTH: 6 ==========================================\n006 4 9464 955d 9518 95c0 | 4 9464 (0) 955d (0) 9518 (0) 95c0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","private_key":"65fbf9c544386bb7decc36886fba5c38238694e8e4ed0840b82ca0297e58b620","name":"node_97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","services":["bzz","pss"],"enable_msg_events":true,"port":33903},"up":true}},{"node":{"info":{"id":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","name":"node_885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","enode":"enode://53546a710a035309f1cbff35e8971bc7e690c23561599cf911a655235c34c063b6e49304da7dba56252e94bad64391e6e125b5e05162b0ddadf4822b5a2675b2@127.0.0.1:0","enr":"0xf88fb8407997f2172b5d153c60a8f8632c854da0dfb927a300de8988efc5d43eea68d0b035456f1e0f6f5cb8376ed14fe4c0d5884d94539a49bf8452ad524f86113a29740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10253546a710a035309f1cbff35e8971bc7e690c23561599cf911a655235c34c063","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iFQnMYY0xFijBQ8vJutSRUp1zqShJjue1V5uuJl0OFQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 885427\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0594 31e1 31e6 3cab | 126 012b (0) 0111 (0) 0191 (0) 025d (0)\n001 7 dbd4 d302 c6a8 c8c8 | 55 ddb8 (0) d959 (0) d9cf (0) da36 (0)\n002 7 a8ff acee a2a1 a606 | 37 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n003 7 9959 9948 9c8e 9f0e | 17 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n004 4 84a9 80d7 837f 834f | 12 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n005 5 8cc3 8d19 8f9a 8e28 | 6 8f9a (0) 8ea2 (0) 8e28 (0) 8e7b (0)\n============ DEPTH: 6 ==========================================\n006 1 8b43 | 1 8b43 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 8862 | 1 8862 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","private_key":"2dbbc994f617a8ec6183e97342de018005e6067b99283fdcef5b5d8dee384215","name":"node_885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","services":["bzz","pss"],"enable_msg_events":true,"port":36713},"up":true}},{"node":{"info":{"id":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","name":"node_ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","enode":"enode://a37137b1144735e571b2b0d8386ee87d4a549cfca4fd3fdddcb70745a7ce46fbc54b5d7b73e96de787896a234c4d22462e56a95a8dd6436cce4058d48847b44f@127.0.0.1:0","enr":"0xf88fb8409e3a3caf38d98642bade767220e7e62bad581c331b1e79c7a8fb576b7f80965e6d8d4d2163232397c431ac51260f72fee0862a1d49e2fab3b62f851a6f9a52430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a37137b1144735e571b2b0d8386ee87d4a549cfca4fd3fdddcb70745a7ce46fb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7UJNJNcCUgv3y19rq73EOgeENftKmITtgqk9ZCg54Sc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed424d\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0594 397a 31e1 447c | 126 025d (0) 035f (0) 0314 (0) 0111 (0)\n001 5 be68 bfc7 ab3f 97da | 75 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n002 6 d302 dbd4 dad0 cd6c | 27 ddb8 (0) d959 (0) d9cf (0) da36 (0)\n003 3 f645 f8ff f9de | 14 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n004 2 e64d e277 | 7 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n============ DEPTH: 6 ==========================================\n006 3 eebd ef99 eff2 | 3 ef99 (0) eff2 (0) eebd (0)\n007 1 ec90 | 1 ec90 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","private_key":"88f389b4ef227125edc26120d238800734b5410e04322c15e248c5f216cc79c9","name":"node_ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","services":["bzz","pss"],"enable_msg_events":true,"port":39221},"up":true}},{"node":{"info":{"id":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","name":"node_67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","enode":"enode://cb89fe308a6760281a69d0737d0d373c9115feed0da089e0c2fcbc632089bf098dc65445404a53c75abf5006078392d46230c01bfbc96678614d72ba1f7ed94a@127.0.0.1:0","enr":"0xf88fb84062af8663cd95c946ddf91876f7724b51ef50c4562e116101de9830fa163e131e43857e1a002e03e8cffc1422472e7fc9638932823b58484aac2e28aba63484720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cb89fe308a6760281a69d0737d0d373c9115feed0da089e0c2fcbc632089bf09","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z1hd/YegBbrpv/wszLg8aVNyR8dIhrT6Uih/RseWvLY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67585d\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a505 eebd ed42 | 130 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n001 5 194e 0cfc 31e1 31e6 | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 2 447a 4cec | 35 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n003 4 7850 7933 7c46 7e47 | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 5 6b4e 6e7f 6c01 6dd3 | 7 6e7f (0) 6c01 (0) 6dd3 (0) 6d3c (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 3 67f3 6790 6795 | 3 6790 (0) 6795 (0) 67f3 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","private_key":"269bc398581870d669185abbe5f5c9b2f0e731c8e3f48a13c092c65822208065","name":"node_67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","services":["bzz","pss"],"enable_msg_events":true,"port":38253},"up":true}},{"node":{"info":{"id":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","name":"node_4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","enode":"enode://80e251b60502a0ca85c11875b9277729738dede4fe4d9da6aeac1bb93d7238ca81487fe9498180e00b10f3c24d030f8c399f02859b795d662a07dd7925bac295@127.0.0.1:0","enr":"0xf88fb8402acfbb34a162aefb2c548c72269c23643ae0c7bbc60406858fa6a60e304f225874d92d713f75b155bc9b1e2b135e732ae7a89a0f2dc1d4a1768bf1752a8b72ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10380e251b60502a0ca85c11875b9277729738dede4fe4d9da6aeac1bb93d7238ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TOzpvBNLwrCUAMn3+KTfknDS/jwHfF5EH//JEfz29C4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4cece9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f9de 97da 8854 | 130 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n001 4 0594 194e 140d 31e1 | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 5 7850 7933 7c46 7e47 | 26 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n003 4 52a8 5ac0 5a8b 5d82 | 16 5538 (0) 56ca (0) 5663 (0) 50c1 (0)\n004 5 435d 43d4 402c 447a | 9 46bf (0) 44ad (0) 447a (0) 447c (0)\n005 7 48b8 48f1 48d7 48de | 7 48b8 (0) 48f1 (0) 48d7 (0) 48de (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 4d38 4d91 | 2 4d38 (0) 4d91 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","private_key":"745ab9f5dd6b46c5ac98c2548026c8c305b3a532b9a83e9721126e740be9bb3d","name":"node_4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","services":["bzz","pss"],"enable_msg_events":true,"port":40221},"up":true}},{"node":{"info":{"id":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","name":"node_31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","enode":"enode://f25dcda2d8dc59f4bd92c76bbc67662093243b8b2cfc966b9184fff854c66ec74507189ff7b3d4f89c266f79e8204f53b2ed2528ad9c3988b8d2e102ccd8ca05@127.0.0.1:0","enr":"0xf88fb840f2ed7d35799356b01b8172d9212f95f949f3ac3c3d9805388236bfae93eb4a0a2a4ea72335f7564107155b17384251f99007367bcd5afdea76fc4f8eee53b3920183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f25dcda2d8dc59f4bd92c76bbc67662093243b8b2cfc966b9184fff854c66ec7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MeEpqz334ILMJ8ZJ2e4po+pkbWqX0kF4dbgOP/V2wEc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 31e129\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ed42 8854 97da | 130 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n001 3 6758 435d 4cec | 61 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n002 8 18e0 194e 0314 0191 | 37 025d (0) 035f (0) 0314 (0) 012b (0)\n003 2 2a50 298a | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 7 3a62 3b02 3980 397a | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 3 3411 36b9 3728 | 3 3411 (0) 36b9 (0) 3728 (0)\n006 1 32ff | 1 32ff (0)\n007 2 30fe 3051 | 2 30fe (0) 3051 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 3188 | 1 3188 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 31e6 | 1 31e6 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","private_key":"6f326011c258ea982e622f9e58986cda7a19e77bfef9c62969474eeca0a3d8bd","name":"node_31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","services":["bzz","pss"],"enable_msg_events":true,"port":41755},"up":true}},{"node":{"info":{"id":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","name":"node_31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","enode":"enode://f7c60635eb672476a7495b71f8dbcf2e50096b636d779195890b040d3a29f30617ac3ff34852bd1caadb9357ed844fd29cb9919f774986b1532f30e8fb5701f1@127.0.0.1:0","enr":"0xf88fb8401d011f6dc991e8d64cfd4b5595b6bcfa3a705c57e6f4494f8b1bc0ce443b738a6f0f975dbfaeda383333324db5b52840e0e34f48d194ee2ec25548336a6196aa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f7c60635eb672476a7495b71f8dbcf2e50096b636d779195890b040d3a29f306","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MeZwY4rLo9WPTGfz/y8/Jddp6KXXp4OJJ/TZ0WmoRAQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 31e670\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 97da 8854 f9de | 130 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n001 4 6b4e 6758 435d 4d91 | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 8 138d 140d 18e0 194e | 37 025d (0) 035f (0) 0314 (0) 012b (0)\n003 2 2a50 298a | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 6 3b02 3a62 397a 3f31 | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 2 36b9 3728 | 3 3411 (0) 3728 (0) 36b9 (0)\n006 1 32ff | 1 32ff (0)\n007 2 30fe 3051 | 2 30fe (0) 3051 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 3188 | 1 3188 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 31e1 | 1 31e1 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","private_key":"4d4953737261cf103a7e8d13c536e05949f4fc81404cbb94631badeed94837ae","name":"node_31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","services":["bzz","pss"],"enable_msg_events":true,"port":44433},"up":true}},{"node":{"info":{"id":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","name":"node_f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","enode":"enode://4cbf242837d8648b219a54398f6646ffe9e4729be3c43431284b27b6f6be2ee2f1267c6ea399699ca10b43dc11dcfb86fc2958e56b558b31d7679ae4493a37a9@127.0.0.1:0","enr":"0xf88fb840373f3de0559f7684b4ce5d159798f351f1bdf5f6792f3e506c2ccd904f07acae6955eaa902b5ad78809cebc0dc80ab7000ede03782617ca114ea23734f786c0b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034cbf242837d8648b219a54398f6646ffe9e4729be3c43431284b27b6f6be2ee2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+d7XuD5HPnG+L8AQHVdMRFIclvd/n4SjhHhaOvaxCT0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f9ded7\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4cec 2a50 3cab 31e6 | 126 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n001 4 be68 95c0 97da 8854 | 75 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n002 9 ddb8 d9cf dad0 dbd4 | 27 d700 (0) d408 (0) d209 (0) d3e9 (0)\n003 6 e277 e64d e867 eff2 | 14 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n004 5 f756 f645 f1ed f215 | 7 f756 (0) f6c0 (0) f645 (0) f305 (0)\n005 4 feb3 ff75 fc39 fc51 | 4 ff75 (0) feb3 (0) fc39 (0) fc51 (0)\n============ DEPTH: 6 ==========================================\n006 1 fa24 | 1 fa24 (0)\n007 1 f8ff | 1 f8ff (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","private_key":"560da7a87ffd5a5bf49023d7b80398255aa1e028182ddc8fb2d8d256ecb672cf","name":"node_f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","services":["bzz","pss"],"enable_msg_events":true,"port":35959},"up":true}},{"node":{"info":{"id":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","name":"node_3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","enode":"enode://f292084e170293ef0d10591a7f596160c60090fb507add19279ae94ea15d4a935fee18917eb7afa876ce5961dccb0b6ab2e150bc746f0b6ce06b845fde8484d4@127.0.0.1:0","enr":"0xf88fb840aab20c00818aacbcf3d572ad9eb90bf3e50ed4ddeca68551ddaa751a781060ff1e937ba61f3905c35d7615ed44caed38be61740bf970af0c891c6da983e1dad90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f292084e170293ef0d10591a7f596160c60090fb507add19279ae94ea15d4a93","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PKvTpWf8Tm+Npm6zXZOP4emn8r3S02xNwtDg6RSfXlY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3cabd3\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9f0e 97da 8854 f9de | 130 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n001 3 435d 6758 6b4e | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 4 194e 0594 09b3 0cfc | 37 025d (0) 035f (0) 0314 (0) 012b (0)\n003 4 26ab 2c85 298a 2a50 | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 6 36b9 3728 3051 3188 | 9 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n005 5 3b02 3a62 3980 3938 | 5 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n============ DEPTH: 6 ==========================================\n006 1 3f31 | 1 3f31 (0)\n007 0 | 0\n008 1 3c5b | 1 3c5b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","private_key":"b5d0c48905d715632a6aaabb360e0f68e9cd27a16403c0a46de69e46c63ddcbd","name":"node_3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","services":["bzz","pss"],"enable_msg_events":true,"port":37601},"up":true}},{"node":{"info":{"id":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","name":"node_6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","enode":"enode://6489e2a9199837f8fb02ee32e8a8e76e29774f8596d0fdffe3d8b41ba49e47585c8ed3fd4fc87f5fe51217783eacc9f05e2b81b3388080fed75911cd15725490@127.0.0.1:0","enr":"0xf88fb840ac0ad126e5eaf3e3023aba08512eb98162e314d5a5bb8c9c237526d01a89099e074ee06f4d91f3f53b223df357b13d025dfc152842f36944651f957be64820720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026489e2a9199837f8fb02ee32e8a8e76e29774f8596d0fdffe3d8b41ba49e4758","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"a07htzlCztePl8DQ4iEgmTPmOuc1O7mrPTesQSdZLoY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6b4ee1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 eebd a505 be68 8854 | 130 af02 (0) aeb4 (0) acee (0) a970 (0)\n001 4 0cfc 31e6 3b02 3cab | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 2 447c 4d91 | 35 5538 (0) 56ca (0) 5663 (0) 52a8 (0)\n003 4 7e47 7c46 7850 7933 | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 6 60c5 648a 67f3 6790 | 6 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n============ DEPTH: 5 ==========================================\n005 5 6e7f 6c01 6dd3 6d3c | 5 6c01 (0) 6dd3 (0) 6d3c (0) 6d5e (0)\n006 1 68cb | 1 68cb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","private_key":"55cabfb948c8655f9b1b9a73378029595cbbc8676d1e8109d34bed3ed4d363ec","name":"node_6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","services":["bzz","pss"],"enable_msg_events":true,"port":35557},"up":true}},{"node":{"info":{"id":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","name":"node_4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","enode":"enode://3047ce86e36b5df4ad3ba58da463012de954e7d23e30785281cd29a6cd9b53415ddca770f01615455e2191b2868a81fe90acb8c2c55af4d0b6a28cff220f27d0@127.0.0.1:0","enr":"0xf88fb8408ea2548809d57c51f6a345099fec0eb50bd94967e457cda4f7e809111d8191382d22aae732783fafb04e860e20a244e746261107b3adc670153e02d137b1dfca0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023047ce86e36b5df4ad3ba58da463012de954e7d23e30785281cd29a6cd9b5341","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TZFH47+Yy1mnZI9hbA1/cTqM87fSXjEVIz/1iDEovqs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d9147\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 be68 95c0 ed42 eebd | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 7 140d 1bd5 194e 0cfc | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 4 7e47 67f3 6d5e 6b4e | 26 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n003 2 5d82 5a8b | 16 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n004 4 447c 447a 435d 402c | 9 4005 (0) 402c (0) 43c9 (0) 43d4 (0)\n005 7 4a95 4b79 48b8 48d7 | 7 4b79 (0) 4a95 (0) 48b8 (0) 48f1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4cec | 1 4cec (0)\n008 1 4d38 | 1 4d38 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","private_key":"7dfa845b9c68e8058b6cff027cac1e713602c7d9e8ac4f04b0698a044871211e","name":"node_4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","services":["bzz","pss"],"enable_msg_events":true,"port":36001},"up":true}},{"node":{"info":{"id":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","name":"node_397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","enode":"enode://755abc3fa17f10b0c6bb93f9525352b3827f6e3f98bd74e4e52420017500a44983656b92a4a1253ead59da4030b30232f86d214431ad83949e6b218222c8c520@127.0.0.1:0","enr":"0xf88fb840486c18e5673883f3888ab658643d9e0012443ec6ca0c40e6876961396f39f722009fb44a458d56561c9ac5f302f47b069f97c94986e68ef69e0513431f4d0d9a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102755abc3fa17f10b0c6bb93f9525352b3827f6e3f98bd74e4e52420017500a449","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OXoKDp+ty1cazYmB9b/o4FnnB+D+roqcTGv+h7055mo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 397a0a\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9f0e be68 ed42 eebd | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 3 7e47 7c46 4d91 | 61 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n002 5 0191 0594 09b3 1bd5 | 37 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n003 3 2e65 2a50 298a | 11 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n004 6 3411 36b9 3051 3188 | 9 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n005 3 3f31 3c5b 3cab | 3 3c5b (0) 3cab (0) 3f31 (0)\n006 2 3b02 3a62 | 2 3b02 (0) 3a62 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 3980 | 1 3980 (0)\n009 1 3938 | 1 3938 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","private_key":"e7af2fa49f44ec8fb20007e24a24e4d54f98188bf25d133631e2f2ae2455b7e5","name":"node_397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","services":["bzz","pss"],"enable_msg_events":true,"port":46385},"up":true}},{"node":{"info":{"id":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","name":"node_194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","enode":"enode://c55b0a9cce8421ed641876de3f9fed4b8a2fb2ef501cc2fa2c6c648609322114009de6258aa164d605ba2839658265bbb44a89d9ed9dbdbafa2f6d0451b75999@127.0.0.1:0","enr":"0xf88fb8406b407aefd0711536e0d1d66333664fef8325d87d5c12dcdfe5736ad122c4f05833ae95d2691865c2a66a8400c4112b32b073bb084564d49d1037bdfe563b3c890183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c55b0a9cce8421ed641876de3f9fed4b8a2fb2ef501cc2fa2c6c648609322114","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GU6j4U3F2Z+Y0VYH3ExAV2n1o3Gswi1Bpi0FN9cWvjI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 194ea3\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 95c0 ab3f be68 eebd | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 5 6758 5d82 4cec 4d91 | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 5 298a 31e6 31e1 3cab | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 6 0561 0594 07f5 0191 | 21 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n004 4 1049 1686 1484 140d | 7 138d (0) 1070 (0) 1049 (0) 1784 (0)\n005 2 1fd0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 1b1d 1bd5 1add | 3 1add (0) 1b1d (0) 1bd5 (0)\n============ DEPTH: 7 ==========================================\n007 1 18e0 | 1 18e0 (0)\n008 1 19ea | 1 19ea (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","private_key":"5ff701f0b31e5dfbd321b192941d8a7e41af8a30830fa9c299a338bbfd3a8ee6","name":"node_194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","services":["bzz","pss"],"enable_msg_events":true,"port":40883},"up":true}},{"node":{"info":{"id":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","name":"node_0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","enode":"enode://1c7485ed433143e6155988aead862aabcc93379a3897b443d75e1d2bce71c04cb75fea9591ed5e36b41949620e51fa8503ec72be6dd0b35a6405747b4dafc014@127.0.0.1:0","enr":"0xf88fb8402d44bd3da0be88d95e8011c9ae2754ea517a35bcf004b02da2673b824687e150720f9fc230cb05afe3de5214e1b1fc4da7501f86b228946800880e9f3af671580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021c7485ed433143e6155988aead862aabcc93379a3897b443d75e1d2bce71c04c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DPxzCa+rzut9JIcU6XLPOYcgUyT1q40EjRe+pdyHNp0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0cfc73\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ddb8 d302 d408 95c0 | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 6 5ac0 4d91 447c 6758 | 61 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n002 3 31e6 31e1 3cab | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 5 140d 1dec 1bd5 18e0 | 16 138d (0) 1070 (0) 1049 (0) 1686 (0)\n004 6 0191 0111 0314 07f5 | 10 025d (0) 035f (0) 0314 (0) 012b (0)\n005 5 08bd 08f8 08e5 09b3 | 6 08e5 (0) 08f8 (0) 08bd (0) 09b3 (0)\n============ DEPTH: 6 ==========================================\n006 3 0e80 0e3b 0e2b | 3 0e80 (0) 0e2b (0) 0e3b (0)\n007 1 0d1c | 1 0d1c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","private_key":"35dace76ca3522b7137c5d74398db392e8341bb9003f933fdc14452fd1750019","name":"node_0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","services":["bzz","pss"],"enable_msg_events":true,"port":44149},"up":true}},{"node":{"info":{"id":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","name":"node_95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","enode":"enode://098c38172926d2bea42728e3631de32062e6ec72da225a5737de50e5ec60e3eed42ee486959bdab553e465298a18c4ebf4c31dbdc77cfde7fe165cf86acb2695@127.0.0.1:0","enr":"0xf88fb84033fceafba7c7cd03f8de801dcdc01997dfe2a50ddb89b115c4d5ad40b7834b060eb29e4c2bd6811003ef36b75d39ed9c2effaca4138325ec3793c254b322f4880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103098c38172926d2bea42728e3631de32062e6ec72da225a5737de50e5ec60e3ee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lcCjUft6pmgygNFZp7gIv6Y/Y7/5GhxZNulzsuXTlU8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 95c0a3\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6e7f 6b4e 4d91 194e | 126 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n001 6 dad0 cd6c c6a8 f8ff | 55 d700 (0) d408 (0) d209 (0) d3e9 (0)\n002 3 a505 bfc7 be68 | 37 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n003 6 8854 8e28 8cc3 80d7 | 21 8f9a (0) 8ea2 (0) 8e28 (0) 8e7b (0)\n004 5 9b8e 9948 9959 9c8e | 9 9b8e (0) 9948 (0) 9959 (0) 9ca1 (0)\n005 3 93ea 93c0 9257 | 3 9257 (0) 93c0 (0) 93ea (0)\n006 1 97da | 1 97da (0)\n007 1 9464 | 1 9464 (0)\n============ DEPTH: 8 ==========================================\n008 2 955d 9518 | 2 9518 (0) 955d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","private_key":"7c5cc685e77cf467257beb319c99f13ca9f2ba8294453271e7b01ae359184ca1","name":"node_95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","services":["bzz","pss"],"enable_msg_events":true,"port":38003},"up":true}},{"node":{"info":{"id":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","name":"node_eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","enode":"enode://e9ac9501ff66e4b8ea683a68019f6bf5a21283fbafd33abad3cd4def147e9ec20faed07f28001ad9a4cb0945ef8aab11edf8900123aa675bb29d6cbfb61ded08@127.0.0.1:0","enr":"0xf88fb8401e043e047731f0dcc2fa094bec2d3f0bebfdde7d067a07090d6e6a7ead1363fb2e8a68ddef0fdb8ed02a84edde2858d72a925a8c5e3f18ee29305be781dde3720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e9ac9501ff66e4b8ea683a68019f6bf5a21283fbafd33abad3cd4def147e9ec2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7r1Is2fL/pSjfA3rJ0ppfmKAdPlWC5CeZiKcXHbOaOs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eebd48\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 6758 6b4e 6e7f 447c | 126 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n001 6 ab3f a2a1 b78f bfc7 | 75 acee (0) af02 (0) aeb4 (0) a970 (0)\n002 6 c6a8 cd6c c961 d302 | 27 d700 (0) d408 (0) d209 (0) d3e9 (0)\n003 5 f645 fc51 fa24 f9de | 14 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n004 3 e09f e277 e64d | 7 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n006 2 ec90 ed42 | 2 ec90 (0) ed42 (0)\n============ DEPTH: 7 ==========================================\n007 2 ef99 eff2 | 2 ef99 (0) eff2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","private_key":"4f0005282a0cc3f4b0bbfbd57d4c18e1df8aee920756f2a469757e0670fb809e","name":"node_eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","services":["bzz","pss"],"enable_msg_events":true,"port":34859},"up":true}},{"node":{"info":{"id":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","name":"node_019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","enode":"enode://ac2123ba0df13d4d5dedbf061b751663af9ae100483d32007792511aba8ecca19b25c53b126dc1b230691c0f0e34057f622e2e4a1154f5eb34f872fc4651862d@127.0.0.1:0","enr":"0xf88fb840e6b23feb9b9d2bc1558c310f1a6d9fc8645da4e28517dbef118974963144e2cb477c6621f4cc9338fe7d53e749bd0bcf825ff2b6ae2ddb89ee2fd1963be821f60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ac2123ba0df13d4d5dedbf061b751663af9ae100483d32007792511aba8ecca1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AZEJMR1IiEl6oZTM5KibXvJDQhzw5+e7kRXQhuGh99c=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 019109\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 be68 eebd | 130 aeb4 (0) af02 (0) acee (0) a970 (0)\n001 2 6e7f 447c | 61 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n002 5 31e6 31e1 3051 397a | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 4 1686 1bd5 18e0 194e | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 4 0cfc 0e2b 09b3 096a | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 4 07f5 046c 0594 0561 | 4 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n006 3 0314 035f 025d | 3 025d (0) 035f (0) 0314 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 012b 0111 | 2 012b (0) 0111 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","private_key":"8e22619e3e2e8484ded659b762691a898a0e95db9ecb04fac8c645f9cbaa1ff1","name":"node_019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","services":["bzz","pss"],"enable_msg_events":true,"port":35711},"up":true}},{"node":{"info":{"id":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","name":"node_447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","enode":"enode://256210b1641ad84c86fe1328a20490519df62a633e20426cb397dd62fc45b75971a55b94bb3a9b406e3fa0d56199c6290e89ec39b02021a462dd9ae8c1a74dc4@127.0.0.1:0","enr":"0xf88fb8408521fdc8311021e64bb28400fcfe6d060a33e4e5328f8cd52c882406b2502f1e5a48985f07c853ccba2176cf80d29128a0e61566df6c6b199c27ecf33e00a7fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102256210b1641ad84c86fe1328a20490519df62a633e20426cb397dd62fc45b759","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RHzb8f9GKqZ9akYIWxqE/cSVpBQqsXTI5psnGwlzK00=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 447cdb\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 cd6c ed42 eebd 834f | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 8 3051 3f31 140d 1bd5 | 65 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n002 4 7933 7e47 6b4e 6e7f | 26 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n003 2 5d82 5a8b | 16 5663 (0) 56ca (0) 5538 (0) 52a8 (0)\n004 5 482e 48de 4d91 4d38 | 10 4b79 (0) 4a95 (0) 482e (0) 48b8 (0)\n005 5 4005 402c 43d4 43c9 | 5 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n006 1 46bf | 1 46bf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 44ad | 1 44ad (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 447a | 1 447a (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","private_key":"dfef090814210606651dad73b8ee233161b8f9bf9999725730de043d0e9af4e0","name":"node_447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","services":["bzz","pss"],"enable_msg_events":true,"port":41827},"up":true}},{"node":{"info":{"id":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","name":"node_be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","enode":"enode://974cfe63e11619004662fdf8336b028fbb9f22c98b67ae3e424f35d394030fb8a8ca8ce9412e1a4f349d6df174d3259431ca8a57ae3adf9f664b3a9c5ba9fd24@127.0.0.1:0","enr":"0xf88fb84098bddc1516cbbff113698681b95c27e15ee3b08e6510e799c6802496acf33e326ce1d60e740e9e37500a1b54d2ca357084a0648c7caa43f2a6584cd311682f6b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102974cfe63e11619004662fdf8336b028fbb9f22c98b67ae3e424f35d394030fb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vmgmfXf7UkJCJyZ8ZlyhGToBAzTKwFczisp3tJpLlNo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be6826\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 397a 194e 0191 6b4e | 126 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n001 7 c8c8 cd6c e64d ed42 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 7 8cc3 8854 84a9 837f | 38 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n003 13 a8ff ab3f af02 aeb4 | 23 aeb4 (0) af02 (0) acee (0) a970 (0)\n004 3 b3f9 b5ea b78f | 6 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n005 2 b8e1 bbaf | 3 b8e1 (0) ba91 (0) bbaf (0)\n006 2 bcf8 bdc5 | 2 bcf8 (0) bdc5 (0)\n============ DEPTH: 7 ==========================================\n007 1 bfc7 | 1 bfc7 (0)\n008 1 bea1 | 1 bea1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","private_key":"6641d12829826045dddcad116be9a840aa14ba3542597d5cc4e71324fa29af40","name":"node_be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","services":["bzz","pss"],"enable_msg_events":true,"port":37231},"up":true}},{"node":{"info":{"id":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","name":"node_6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","enode":"enode://3821a5bff1a93183090d662d2451159ebe363ee2df3b361159cded82888ed46322fc6470eb09bfb736355e121b06092eb64120fb8e0448778b948559baa814d9@127.0.0.1:0","enr":"0xf88fb84051b3adb1ee656aaaad0cb4b241aa3c32ffceea4999429eddee1573f06d9477793034a1aa1b8f586fac2c2aba3e5f8ca79f6e01885eee40e0c70983c7ffe8ee950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033821a5bff1a93183090d662d2451159ebe363ee2df3b361159cded82888ed463","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bn8fPWU2Q5lhek2V/dBPLKmwB7I2aUPnulrNRhanpCU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e7f1f\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c961 cd6c eebd 95c0 | 130 f756 (0) f6c0 (0) f645 (0) f305 (0)\n001 7 07f5 0191 0cfc 096a | 65 138d (0) 1070 (0) 1049 (0) 1784 (0)\n002 3 5a8b 4d38 447c | 35 5144 (0) 50c1 (0) 52a8 (0) 5538 (0)\n003 5 7e47 7c46 7d16 7933 | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 5 60c5 648a 6795 67f3 | 6 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n005 2 6b4e 68cb | 2 68cb (0) 6b4e (0)\n============ DEPTH: 6 ==========================================\n006 4 6c01 6dd3 6d3c 6d5e | 4 6c01 (0) 6dd3 (0) 6d3c (0) 6d5e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","private_key":"41525658ab059b89329f02a6c477cd77bc69b94ceae45e0e31f70bb6b70ee671","name":"node_6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","services":["bzz","pss"],"enable_msg_events":true,"port":38077},"up":true}},{"node":{"info":{"id":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","name":"node_bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","enode":"enode://d0595ae566e2dec77e37a408dcf8d7c3157cc52378c66fada8c78b588aa926d2f7350c17cd3f8586f36de2c55a9020e923262ad54d5b7530f063570cc46f3f6b@127.0.0.1:0","enr":"0xf88fb840c153e9a46508c43ea149e6f6f11d3d2077afd262f7b2bb8df75d999927705ad20554753898c4f1f275f901157620f8b3c2e4f9ea4ff600ac2e0fbba78fb70f270183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d0595ae566e2dec77e37a408dcf8d7c3157cc52378c66fada8c78b588aa926d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"v8cReTgwd59Jqlm8b3ogWrTm6uer/a+/O7WhFjp3irI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bfc711\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3f31 6e7f | 126 138d (0) 1070 (0) 1049 (0) 1784 (0)\n001 7 ed42 eebd d302 dad0 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 6 834f 84a9 95c0 97da | 38 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n003 15 ab3f a970 a8ff acee | 23 acee (0) aeb4 (0) af02 (0) a970 (0)\n004 4 b3f9 b5ea b6df b78f | 6 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n005 3 ba91 bbaf b8e1 | 3 bbaf (0) ba91 (0) b8e1 (0)\n006 2 bcf8 bdc5 | 2 bcf8 (0) bdc5 (0)\n============ DEPTH: 7 ==========================================\n007 2 be68 bea1 | 2 bea1 (0) be68 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","private_key":"98697e601711a0c2bc93c85db0434deba8428ccf604641af230ef188b176ceff","name":"node_bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","services":["bzz","pss"],"enable_msg_events":true,"port":46271},"up":true}},{"node":{"info":{"id":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","name":"node_3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","enode":"enode://cd82e53229cae0db1a40d6d3974aceff2b8223d817606879d4d4c82e93d851a5a41a488c441ff25a85dda297bf76cf3ffc924029112a5afc15ff35a1f49aaa6a@127.0.0.1:0","enr":"0xf88fb840a9166c078904cd0604d4a4a19f9884af9ba6a3c08f1da14902b3be746025dca87ef2d6ecc67dcbd2808df07f6a1a911e3f71936e779fba08bc74db71740c34290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cd82e53229cae0db1a40d6d3974aceff2b8223d817606879d4d4c82e93d851a5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PzHsr/qmMRyCyaV1u8ONa8sWYwrIfhnRhTpkqpbJ3N4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3f31ec\npopulation: 21 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 834f bfc7 | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 2 447c 6e7f | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 4 096a 0561 07f5 0191 | 37 138d (0) 1070 (0) 1049 (0) 1784 (0)\n003 2 2a50 298a | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 5 36b9 3188 31e6 31e1 | 9 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n005 4 3b02 3a62 397a 3980 | 5 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n============ DEPTH: 6 ==========================================\n006 2 3c5b 3cab | 2 3c5b (0) 3cab (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","private_key":"3ed9ff27809a5c5e4f61f5343410a2a1291496221e7861971e6d48611b1a9abd","name":"node_3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","services":["bzz","pss"],"enable_msg_events":true,"port":42049},"up":true}},{"node":{"info":{"id":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","name":"node_834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","enode":"enode://69f51e1ebbbb38b8b161722c403f583d6141cff104f2da6dc21f21f0c50e4d41d031f8a4d0523d545691ebe7ba00050d25ac6ef88255fbc453fea197db95fffd@127.0.0.1:0","enr":"0xf88fb84074d162cf5aadfde184fd1c7884869ea76837d6e33b21bfd74ff53d66b50c055c3479080476f1e97ea070cf9ed88ef3445665a36e93f803078d5e4cdd738a77a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10369f51e1ebbbb38b8b161722c403f583d6141cff104f2da6dc21f21f0c50e4d41","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g08U6fMlSCre9iZR3fNoVpDdXr3RgBTyvSZrIUPCkP8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 834f14\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 447c 096a 3f31 | 126 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n001 4 cd6c c961 dad0 dbd4 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 6 a8ff a606 a505 b78f | 37 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n003 4 9f0e 93ea 97da 95c0 | 17 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n004 6 8cc3 8f9a 8e28 8e7b | 9 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n005 3 86d6 8402 84a9 | 4 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n006 5 81a5 8006 8073 8074 | 5 81a5 (0) 8006 (0) 8073 (0) 8074 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 837f | 1 837f (0)\n011 1 8358 | 1 8358 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","private_key":"1496abca4c41e1d57c812b53636296bdad2570659143afc188383905ad3a1d30","name":"node_834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","services":["bzz","pss"],"enable_msg_events":true,"port":44165},"up":true}},{"node":{"info":{"id":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","name":"node_096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","enode":"enode://ff8aff353bd9756ed7a631808ca59009f89f5db4ddc3938b05ea2cf4fef6855ace3f6873b2ee1a35b6bb524b9f310b19db97e635add9ed1075e9907da1b56157@127.0.0.1:0","enr":"0xf88fb84062ef2386cda8f32e286d22df7b0ee0daf321024107b0a4794abfe7b079de98083d2b860770dea2044c50072ee556e6d3ec1d217915acaa11a2dd6b1b31b1ad0b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ff8aff353bd9756ed7a631808ca59009f89f5db4ddc3938b05ea2cf4fef6855a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CWqDArbzacKO2dR3GaUH6tijzByk+h4yMYt/l4c5Vf4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 096a83\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a505 834f | 130 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n001 2 447c 6e7f | 61 5144 (0) 50c1 (0) 52a8 (0) 5538 (0)\n002 4 3f31 31e1 3188 3051 | 28 26ac (0) 26ab (0) 244c (0) 24f8 (0)\n003 5 1686 140d 1bd5 18e0 | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 4 0191 0594 0561 07f5 | 10 025d (0) 035f (0) 0314 (0) 012b (0)\n005 4 0e80 0e3b 0e2b 0cfc | 5 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 08bd 08f8 08e5 | 3 08bd (0) 08f8 (0) 08e5 (0)\n008 1 09b3 | 1 09b3 (0)\n009 0 | 0\n010 1 0942 | 1 0942 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","private_key":"396f35fa7f69257841f0b832cf5f655557fa1b060dbb859461a22429101230cb","name":"node_096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","services":["bzz","pss"],"enable_msg_events":true,"port":43747},"up":true}},{"node":{"info":{"id":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","name":"node_a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","enode":"enode://462c3ca5391ed837a169228797bea3d3f4585a7fb5cb938de1fc15649174b0156940060d152a8486deb4ccfe2c3ca460b5d9a184399db2f4a8b95ec015e86896@127.0.0.1:0","enr":"0xf88fb840dd4c1cd722f83d847e339b92de95082d1413d3b86944796fee5054d09a8390b052018a03749011927e56a0650aa9db5ade2a936687147004585d02d32fe1861b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102462c3ca5391ed837a169228797bea3d3f4585a7fb5cb938de1fc15649174b015","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pQU5WPDO/P8YJr8CUl/amMTclUzDhpDzxD7L8LKtV68=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a50539\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6758 6b4e 3051 09b3 | 126 5144 (0) 50c1 (0) 52a8 (0) 5538 (0)\n001 4 dad0 dbd4 c961 cd6c | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 7 8854 837f 834f 9f0e | 38 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n003 5 b3f9 b78f b8e1 bfc7 | 14 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n004 3 aeb4 a8ff ab3f | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a0c8 a330 a327 a2e6 | 6 a1c8 (0) a0c8 (0) a330 (0) a327 (0)\n006 4 a742 a7a8 a616 a606 | 4 a7a8 (0) a742 (0) a616 (0) a606 (0)\n============ DEPTH: 7 ==========================================\n007 1 a4ee | 1 a4ee (0)\n008 1 a5ac | 1 a5ac (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","private_key":"550f3f019bfee28d84cbafd18523a10069faabebcbe9823512a4f0af5343b627","name":"node_a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","services":["bzz","pss"],"enable_msg_events":true,"port":36993},"up":true}},{"node":{"info":{"id":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","name":"node_305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","enode":"enode://c5f49027f8ad45e617b539a3242f31739ac950203b54ecf8dbe5b2160b85ee594bc40553728846692df15f6859547b5360e6cbf64dd1486b9d5272c378b958ac@127.0.0.1:0","enr":"0xf88fb840ad06f6a9761fd36b8a36707e80761bda29124da842be6b3eef6cb49227944a6709187c9a4d490219f8244eaaec1538b10720b042ad258a64bf7a09438d4673470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c5f49027f8ad45e617b539a3242f31739ac950203b54ecf8dbe5b2160b85ee59","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MFFixHLHHd7yMgsTgQK2fRziuLunni5Yf8gOCFyI5Uc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 305162\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 dbd4 a505 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 5 5a8b 4d91 4d38 447c | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 5 18e0 0191 07f5 0561 | 37 138d (0) 1070 (0) 1049 (0) 1784 (0)\n003 3 26ab 298a 2a50 | 11 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n004 8 3cab 3c5b 3f31 3a62 | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 2 36b9 3728 | 3 3411 (0) 36b9 (0) 3728 (0)\n006 1 32ff | 1 32ff (0)\n============ DEPTH: 7 ==========================================\n007 3 3188 31e6 31e1 | 3 31e1 (0) 31e6 (0) 3188 (0)\n008 1 30fe | 1 30fe (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","private_key":"3ccc59b4b2ef2146a73d043f665a3dec37990b81cf7e81c670ef586260aa4f45","name":"node_305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","services":["bzz","pss"],"enable_msg_events":true,"port":41853},"up":true}},{"node":{"info":{"id":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","name":"node_dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","enode":"enode://12b59aaec065fee81276d23336c7a839dfd34fa213d06a31fa3447894ed5afdefca89b783977333245f76c2e35b74504e51928af9586e4f288a870a6c0db0c2a@127.0.0.1:0","enr":"0xf88fb840c57b5dd80289305003c7726a173a5f1e93a911e51aa052b1ab38f38e9a102c1074a105d65dc177fdff430aeb2e9d2de42f87d2b32d7cc7fbd6b57647999ab64c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212b59aaec065fee81276d23336c7a839dfd34fa213d06a31fa3447894ed5afde","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"29TZDjNC74N7js9cbkkPfECfQZzza3cWKofLLPuK4zw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dbd4d9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3188 3051 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 7 93ea 9f0e 8854 834f | 75 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n002 5 f645 fc51 f9de ed42 | 28 f756 (0) f645 (0) f6c0 (0) f1ed (0)\n003 8 c42e c6a8 c74d c961 | 16 c190 (0) c272 (0) c2d0 (0) c534 (0)\n004 3 d408 d209 d302 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n005 1 ddb8 | 1 ddb8 (0)\n006 2 d959 d9cf | 2 d959 (0) d9cf (0)\n============ DEPTH: 7 ==========================================\n007 2 da36 dad0 | 2 da36 (0) dad0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","private_key":"c2103de042f815312e3c17f6a1334bcbdbc1e4f58d39e436d463cf08b61b060d","name":"node_dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","services":["bzz","pss"],"enable_msg_events":true,"port":45509},"up":true}},{"node":{"info":{"id":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","name":"node_cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","enode":"enode://3f46a3f4016f9803ad015ff459b7b2d3ae3dc814ca3dce437d56046302b1bf2c143203755461e513a4ae4ed11d6548aeca82b83a3026662f06c7ebddeef20c7c@127.0.0.1:0","enr":"0xf88fb840aa6d2306927e37eb5add2079388ffeb2ad0bf5d36ad922dc7dfbbcae12b8511120a7ceaeb6685848468c6434e7add539507eb0305283e9881b35eb5b50cc699d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023f46a3f4016f9803ad015ff459b7b2d3ae3dc814ca3dce437d56046302b1bf2c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zWyLQqCwkvQeaSVXfJ3n0b6hcjG8s9CPPTzOnG/c8i0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cd6c8b\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 7933 6e7f 447c 5a8b | 126 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n001 11 834f 95c0 93ea 9f0e | 75 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n002 8 f2b4 f645 fc51 fa24 | 28 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n003 5 d302 d408 ddb8 d9cf | 11 d209 (0) d3e9 (0) d302 (0) d700 (0)\n004 3 c6a8 c603 c74d | 8 c272 (0) c2d0 (0) c190 (0) c42e (0)\n005 4 c961 c9c3 c8ea c8c8 | 4 c8ea (0) c8c8 (0) c9c3 (0) c961 (0)\n006 1 cf52 | 1 cf52 (0)\n============ DEPTH: 7 ==========================================\n007 1 cc33 | 1 cc33 (0)\n008 1 cdb1 | 1 cdb1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","private_key":"cd14c3cb4c268526af99a387d2e105f126f0d3e4368b46397cc117868140fbaa","name":"node_cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","services":["bzz","pss"],"enable_msg_events":true,"port":45357},"up":true}},{"node":{"info":{"id":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","name":"node_07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","enode":"enode://0214bfe7469b5ed146f1f11d937181680a8dea456f3586d08810ca756337e9fed3e46fe35c99af4496d072125f6b898ab97f5332e16399f3107d15912756daf6@127.0.0.1:0","enr":"0xf88fb840af0cb239eef4aef9f88cfc4a0241d95cb9ef1cbb14c5889164e2d27c2c09a433595a3366678b3e8e1f1933c2ea8bbbe26d0b5dc604e984a43e20e68e4dbd42300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020214bfe7469b5ed146f1f11d937181680a8dea456f3586d08810ca756337e9fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"B/XQlKSyLnPN1shUUrPZKNqbSxaHOCR1nLfopiJBf9U=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 07f5d0\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c961 cd6c | 130 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n001 4 6e7f 7c46 7933 4d38 | 61 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n002 6 2c80 2ddf 298a 2a50 | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 6 1049 1686 140d 1bd5 | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 5 0cfc 0e80 0e2b 09b3 | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 6 035f 0314 025d 0191 | 6 025d (0) 035f (0) 0314 (0) 012b (0)\n============ DEPTH: 6 ==========================================\n006 3 046c 0594 0561 | 3 046c (0) 0594 (0) 0561 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","private_key":"251c21ef6c12491657b20ba5898f537b45474fd62ce9f870aa98b7a2ce906096","name":"node_07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","services":["bzz","pss"],"enable_msg_events":true,"port":45285},"up":true}},{"node":{"info":{"id":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","name":"node_c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","enode":"enode://a32b355f09cbc5a2ccbffb7eea267721cdc1108cab1c29d2dd1e2e7fa7c5c20e04c6a024fa47373e830891a62576084c8bbae862c4044ad94a2c612189282db8@127.0.0.1:0","enr":"0xf88fb8408a9d74f8b002fe6e7cff4d593bbf3bae2a56a10b0f5d1a6187fe6c3387aaa0cf399c033c3390082c7a87ecb9c2e865ca708f2279eb75d132524d4bcb29cba63d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a32b355f09cbc5a2ccbffb7eea267721cdc1108cab1c29d2dd1e2e7fa7c5c20e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yWFG7kfsfNdFUc908AITvDN9ZDxDJzk/DmhI7NSg+NM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c96146\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6e7f 7c46 7933 3188 | 126 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n001 9 b78f bfc7 a606 a5ac | 75 8d19 (0) 8cc3 (0) 8ea2 (0) 8e7b (0)\n002 5 f645 fc51 f9de ed42 | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 6 d302 d408 ddb8 d9cf | 11 d209 (0) d3e9 (0) d302 (0) d700 (0)\n004 2 c603 c6a8 | 8 c272 (0) c2d0 (0) c190 (0) c42e (0)\n005 4 cf52 cd6c cdb1 cc33 | 4 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c8ea c8c8 | 2 c8ea (0) c8c8 (0)\n008 1 c9c3 | 1 c9c3 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","private_key":"11fc592c06dfe93bde5f4e4d007d2c7020e49d7e5ef8de72fb7ad0c39d96d2c2","name":"node_c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","services":["bzz","pss"],"enable_msg_events":true,"port":43471},"up":true}},{"node":{"info":{"id":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","name":"node_dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","enode":"enode://3a93f5d6282a4f76c82c17c35a6f8eac3a2b9b63ae0e3a532ab625fd4df7fa7f4357b01c8f6071b405a85b97e6832ba2b0d8eefc3afec46b0221bd15c2f4d5e6@127.0.0.1:0","enr":"0xf88fb840f5b726c896fc45a7d66c14a7ff0b8cffe4f443829996bcf4bf69388e9b4fb1445eddef566d406b613be72fb97eb94988db3f65a8eb1d51134b93c241fde80a460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023a93f5d6282a4f76c82c17c35a6f8eac3a2b9b63ae0e3a532ab625fd4df7fa7f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2tCJmc0u3DPP3FnqNMitzWo06qFfLoWwYi6YSLIVwdU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dad089\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7c46 7933 3188 1bd5 | 126 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n001 6 a505 bfc7 834f 93ea | 75 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n002 4 f645 f9de ed42 eebd | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 5 c190 c74d c8c8 c9c3 | 16 c2d0 (0) c272 (0) c190 (0) c534 (0)\n004 4 d209 d302 d700 d408 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n005 1 ddb8 | 1 ddb8 (0)\n006 2 d9cf d959 | 2 d959 (0) d9cf (0)\n============ DEPTH: 7 ==========================================\n007 1 dbd4 | 1 dbd4 (0)\n008 1 da36 | 1 da36 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","private_key":"ac54b72de76bbeab526b566706c5324bfab619ac9019078319474c8396bb36f3","name":"node_dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","services":["bzz","pss"],"enable_msg_events":true,"port":40305},"up":true}},{"node":{"info":{"id":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","name":"node_056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","enode":"enode://265ba137f94c59432e330185dfe26176b2833143e001d135ff9bdc74eb6a7dbf46a40c5f27a01cb176086b2a4bcd8b4df935a0e35fc331e5da556d2471d19b46@127.0.0.1:0","enr":"0xf88fb840e995a0df1f38fad4ffb6332b3ccf46fa213f3d0c5b746ecd7ab35dc36e928f8f16ebf9bee964f47e3ceb70b47261c82843d796a2d28785cdd521f7e7add6fbf40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102265ba137f94c59432e330185dfe26176b2833143e001d135ff9bdc74eb6a7dbf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BWFS3Z2uhcQmN400rKuNZkHaZl0vVzWaJ6D/ZS8/PQI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 056152\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a5ac dad0 | 130 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n001 3 7933 5a8b 4d38 | 61 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n002 3 3f31 3188 3051 | 28 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n003 5 1049 1686 140d 194e | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 4 0e2b 0cfc 09b3 096a | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 5 0314 025d 012b 0111 | 6 025d (0) 035f (0) 0314 (0) 012b (0)\n006 1 07f5 | 1 07f5 (0)\n============ DEPTH: 7 ==========================================\n007 1 046c | 1 046c (0)\n008 1 0594 | 1 0594 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","private_key":"faad557bcbab6d34e58f844b5a368fc2c5a4d088352c0bc0d2363aec33462b69","name":"node_056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","services":["bzz","pss"],"enable_msg_events":true,"port":43665},"up":true}},{"node":{"info":{"id":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","name":"node_a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","enode":"enode://8cdb600efbfa331c7bcb78d899595726993e73d7aac802d61673d8b50f7766950f1907d11732fbac2e316d2d8f439f984f54164a7b2db098ae1b35540e8b2902@127.0.0.1:0","enr":"0xf88fb840d11b0126170eb4fee1197420356b363c9efc48d4f5f3ac3ec4139a53443f7d6c5d66e6edbc0a80d5d907f8aa5fba8247287ecc0d7a9e4910801655d67107a7fa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028cdb600efbfa331c7bcb78d899595726993e73d7aac802d61673d8b50f776695","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pawE1TtWnkGO9QB5YUMRVfLCJu4QFXswr3HqSDawgIk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a5ac04\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7933 4d38 1bd5 0561 | 126 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n001 3 dbd4 c961 cd6c | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 4 8854 837f 9f0e 93ea | 38 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n003 4 bfc7 be68 b3f9 b78f | 14 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n004 2 af02 a8ff | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a1c8 a330 a327 a2a1 | 6 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n006 4 a616 a606 a7a8 a742 | 4 a7a8 (0) a742 (0) a616 (0) a606 (0)\n============ DEPTH: 7 ==========================================\n007 1 a4ee | 1 a4ee (0)\n008 1 a505 | 1 a505 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","private_key":"0a918d168aacb95afe15f3eba1e762f144f5ffa60fa01155a81ec8cf4a5c5470","name":"node_a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","services":["bzz","pss"],"enable_msg_events":true,"port":36481},"up":true}},{"node":{"info":{"id":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","name":"node_4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","enode":"enode://98863ce3c7e18d15ece80b94033ae1825556b0a21f84ec04077e72f48df419e525b341d7bef239e3565754f57b3e9cf42b828667a8e0bffc5e9ef9d596888353@127.0.0.1:0","enr":"0xf88fb840c0c7e8479b7d62eac2089ba0a3436acd47f05a6410097ae49bcf77ec309c122a4b04acaa26fddfb564888a144346c8277e2459076aa8758bc1b31d17fdaa6e7b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10398863ce3c7e18d15ece80b94033ae1825556b0a21f84ec04077e72f48df419e5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TTgQFHg5gLL3fw1xFgrZ6dhGcrV29ENczbrhJ1I1DBw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d3810\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 93ea a5ac | 130 f756 (0) f645 (0) f6c0 (0) f1ed (0)\n001 4 3051 3188 07f5 0561 | 65 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n002 4 6e7f 7933 7850 7c46 | 26 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n003 5 56ca 5d82 5ff0 5a8b | 16 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n004 5 402c 43d4 43c9 435d | 9 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n005 3 482e 48b8 48de | 7 4b79 (0) 4a95 (0) 48b8 (0) 48f1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4cec | 1 4cec (0)\n008 1 4d91 | 1 4d91 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","private_key":"f83b2e95c445a50438af645a0f3dd41e2615d85bc9e28834a722b78081960743","name":"node_4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","services":["bzz","pss"],"enable_msg_events":true,"port":34823},"up":true}},{"node":{"info":{"id":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","name":"node_93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","enode":"enode://fb8e6ad0083dd5c9588924daa51194dfc6a4e8e5efd75fb3bd2f76d99c15df4aa355b2419a416d0be44ddabd404b7d503461312253bc36f9c8cb6acf86206faf@127.0.0.1:0","enr":"0xf88fb840de494f8808c9d4cb3dbbe95d92b77102bde20de29cb253862072e62ac37179767dd2aa1e587a6ddff1e42149b96842de7054b91c30a773c04c140030f83054e70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fb8e6ad0083dd5c9588924daa51194dfc6a4e8e5efd75fb3bd2f76d99c15df4a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"k+qO8lH9VrFZ4IDN9zPTPh/fs8euW9mmoyjQv1RYhns=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 93ea8e\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1bd5 3188 7c46 7850 | 126 2fd2 (0) 2e65 (0) 2ddf (0) 2c85 (0)\n001 4 dad0 dbd4 cd6c c961 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 6 bfc7 b78f a2a1 a606 | 37 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n003 4 8854 8e28 834f 837f | 21 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n004 5 9b8e 9948 9959 9ca1 | 9 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n005 4 95c0 9518 955d 97da | 5 97da (0) 9464 (0) 9518 (0) 955d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 9257 | 1 9257 (0)\n008 0 | 0\n009 0 | 0\n010 1 93c0 | 1 93c0 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","private_key":"60b514798a6f6a2f5cf7e85f798280d359067d82ca6c08dd3d5152c9325f8c11","name":"node_93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","services":["bzz","pss"],"enable_msg_events":true,"port":44155},"up":true}},{"node":{"info":{"id":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","name":"node_9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","enode":"enode://1a733925153e123a28e4c6ff215622e6f5f6e3603dd3ecac572db24c88743906db68f57c873814af3004eeee0cec5e7ea31c1fa450a6f60a4d682c5d36d4f7d6@127.0.0.1:0","enr":"0xf88fb8407124e4586da75d58f439871e4d6d59bf6cb2adffd121aa712eb670aa52d490b20045fdd401ff02688127caa8436744fae9ded418d490b1f6bdb678380f0839950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021a733925153e123a28e4c6ff215622e6f5f6e3603dd3ecac572db24c88743906","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nw4r+KliFWyeCoPD1CrT3FrFw+UI8kIAv7FRqtTjlf8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9f0e2b\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 26ac 298a 2c80 3cab | 126 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n001 4 cd6c c961 dbd4 dad0 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 5 bfc7 a2a1 a606 a505 | 37 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n003 3 8854 837f 834f | 21 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n004 3 97da 95c0 93ea | 8 97da (0) 9464 (0) 9518 (0) 955d (0)\n005 3 9b8e 9948 9959 | 3 9b8e (0) 9948 (0) 9959 (0)\n006 2 9ca1 9c21 | 3 9c8e (0) 9ca1 (0) 9c21 (0)\n============ DEPTH: 7 ==========================================\n007 1 9ec8 | 1 9ec8 (0)\n008 0 | 0\n009 1 9f7d | 1 9f7d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","private_key":"5e77db0ba785223e5c1e3ce73ecad087df783ddb123f13e44c126125e5320834","name":"node_9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","services":["bzz","pss"],"enable_msg_events":true,"port":36327},"up":true}},{"node":{"info":{"id":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","name":"node_5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","enode":"enode://78abddf561d75c3f8e4ee5cf729a4ca27a15261a2f7643ba4669070e37568388a95d9ba6ff45b86f63c11bb67c5f0816c8b8e1436db63342080d94b1ec98afe6@127.0.0.1:0","enr":"0xf88fb8404bd00e9812551717571255b2d27db8fdc87870fc9285e293ceb9921910e0c20f68658713acfd38ca573cae42d75bcd43a72edd6c7f0a363fccf5820d7c7b62990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10278abddf561d75c3f8e4ee5cf729a4ca27a15261a2f7643ba4669070e37568388","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WouE32UYcfznLRHLHCbIeuSgzGtMJ0035wUyyU8nKI4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a8b84\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 cd6c a606 a2a1 9f0e | 130 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n001 4 1bd5 0561 3051 3188 | 65 2fd2 (0) 2e65 (0) 2c85 (0) 2c80 (0)\n002 5 6e7f 60c5 7c46 7850 | 26 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n003 8 435d 447a 447c 482e | 19 4005 (0) 402c (0) 43c9 (0) 43d4 (0)\n004 3 52a8 5663 56ca | 6 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n005 3 5d82 5c7c 5ff0 | 4 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n006 2 5987 5814 | 2 5987 (0) 5814 (0)\n007 1 5bd8 | 1 5bd8 (0)\n============ DEPTH: 8 ==========================================\n008 1 5a26 | 1 5a26 (0)\n009 1 5ac0 | 1 5ac0 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","private_key":"213bd7466a810ef9f7851687f3b179a52046eb5522252297a6b1d6145b648669","name":"node_5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","services":["bzz","pss"],"enable_msg_events":true,"port":37077},"up":true}},{"node":{"info":{"id":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","name":"node_793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","enode":"enode://fb36dea27a60b8255d2a142d64db3fe03c31642226d5a683e50b509f351c947fba07533d9b9138973ff4b62119c4bf09a9ccc0519dfba63e01ad9e6fdb04ab04@127.0.0.1:0","enr":"0xf88fb8403034394794df0756ddc241fe1356ff416e555eacb7699f2908a393d11806c4e508ac26d9bfa21ef4c53295da07e7916ab9facfc097f0721e7af81bccf373caa10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fb36dea27a60b8255d2a142d64db3fe03c31642226d5a683e50b509f351c947f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eTMiYIBV1Ic3dqmgpsQLBDeb/S8omorUmn3EVrxl+HE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 793322\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 cd6c c961 dad0 93ea | 130 e681 (0) e64d (0) e471 (0) e09f (0)\n001 4 3980 07f5 0561 1bd5 | 65 26ab (0) 26ac (0) 24f8 (0) 244c (0)\n002 5 4d38 4cec 48de 447c | 35 402c (0) 4005 (0) 43c9 (0) 43d4 (0)\n003 6 6e7f 6d5e 6b4e 67f3 | 13 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n004 3 7049 70f6 741a | 4 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n005 4 7e47 7d16 7ce7 7c46 | 5 7e47 (0) 7d16 (0) 7ce7 (0) 7c7c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 7895 7850 | 2 7895 (0) 7850 (0)\n008 1 79e5 | 1 79e5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","private_key":"9af1743677da1b9215eb659bad537e2f657dbcafdf6b976262914f493b2f65b9","name":"node_793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","services":["bzz","pss"],"enable_msg_events":true,"port":37431},"up":true}},{"node":{"info":{"id":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","name":"node_1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","enode":"enode://104600d1fbf9e41d171d15f36749903ac370ecfe94329b32fbd3f7af774b1d72bc3f133476f5911bef453b17fd722cd5695eed65f7c0f5bf65dddf055bfd9e73@127.0.0.1:0","enr":"0xf88fb840c24991e175917d22a4a701e7eaec5e9384fd92f3dcb1cc9cc0a31364f5588fe0072fff15bcf451255fc65a48eef41cbe3ea148d76132009507c8ee91af5603cd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103104600d1fbf9e41d171d15f36749903ac370ecfe94329b32fbd3f7af774b1d72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"G9WIJjJ0VDcp1UUprp6b9FlttAZJocKj9zFo2BjzS2I=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1bd588\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 c961 dad0 93ea ab3f | 130 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n001 5 5a8b 447c 482e 4d91 | 61 43d4 (0) 43c9 (0) 435d (0) 4005 (0)\n002 4 26ac 397a 3980 3188 | 28 2ddf (0) 2c85 (0) 2c80 (0) 2fd2 (0)\n003 5 096a 0cfc 0191 07f5 | 21 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n004 3 1049 140d 1686 | 7 138d (0) 1070 (0) 1049 (0) 1784 (0)\n005 2 1dc0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 18e0 19ea 194e | 3 18e0 (0) 19ea (0) 194e (0)\n============ DEPTH: 7 ==========================================\n007 1 1add | 1 1add (0)\n008 1 1b1d | 1 1b1d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","private_key":"55ac02ca6376a8c8ade280c4a965ee5c08e93550a6029562e8e86d7dbccf81e5","name":"node_1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","services":["bzz","pss"],"enable_msg_events":true,"port":42121},"up":true}},{"node":{"info":{"id":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","name":"node_318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","enode":"enode://872434e3239345e130ac211904d19315ea542bd330d22ac21629432fadb2635f790530b99c823b4a59df7a4acd5fbbc0a9fb1c2133b86f88473040d3efbd69a6@127.0.0.1:0","enr":"0xf88fb84082f955db5d6323c7cfd3bff029579b8cd70c25e9e9e520f73c3fedce47321114383d187aa1adece14d610b47db85463b6ff60a5ec00e945d211e3f6abd25d18f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102872434e3239345e130ac211904d19315ea542bd330d22ac21629432fadb2635f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MYgo+ok6KMwGUtP4HZfFuOAj6FNoX10+Zf3iBomrzFo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 318828\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 dbd4 dad0 cd6c c961 | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 3 4d38 5a8b 7c46 | 61 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n002 3 096a 0561 1bd5 | 37 0d1c (0) 0cfc (0) 0e80 (0) 0e3b (0)\n003 5 298a 2a50 2e65 2ddf | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 6 3f31 3cab 3a62 3b02 | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 2 3728 3411 | 3 36b9 (0) 3728 (0) 3411 (0)\n006 1 32ff | 1 32ff (0)\n007 2 30fe 3051 | 2 30fe (0) 3051 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 31e1 31e6 | 2 31e6 (0) 31e1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","private_key":"ab2d8316f989485b43a1f14a3b2736c9e506aa0ba33fbeae8fc45dfb0784b50e","name":"node_318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","services":["bzz","pss"],"enable_msg_events":true,"port":45097},"up":true}},{"node":{"info":{"id":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","name":"node_7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","enode":"enode://e9ce5ad62b69c60eaba82ede900643474a4316ff4fb9f8bbd15cc8ef3b5ac9eb2cfacbab6551b57423952f4be2990d95f539368954e42fc7fad8b1561af79002@127.0.0.1:0","enr":"0xf88fb840233a6d08e9c900370f4b86282cd0f45e172bbe22a6ddba170768665f2289363a04022e239dba04e74de46939a2fc3173ef7f8ec3a3c380bc4f96e0f8d57baa3f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e9ce5ad62b69c60eaba82ede900643474a4316ff4fb9f8bbd15cc8ef3b5ac9eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fEZAVOp7bJ6gx9TCCXackvKUqdssoVm47xaOMQoerDo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7c4640\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c961 d9cf dad0 93ea | 130 e681 (0) e64d (0) e471 (0) e09f (0)\n001 4 07f5 2fd2 397a 3188 | 65 0d1c (0) 0cfc (0) 0e80 (0) 0e3b (0)\n002 5 48de 4cec 4d38 5a26 | 35 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n003 5 6b4e 6e7f 6d5e 6758 | 13 68cb (0) 6b4e (0) 6c01 (0) 6dd3 (0)\n004 2 7660 741a | 4 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n005 3 79e5 7933 7850 | 4 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n006 1 7e47 | 1 7e47 (0)\n007 1 7d16 | 1 7d16 (0)\n============ DEPTH: 8 ==========================================\n008 1 7ce7 | 1 7ce7 (0)\n009 0 | 0\n010 1 7c7c | 1 7c7c (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","private_key":"fcc47163c2ab2f499cbb2f337ef53f49309b3865d8038bff9d2bc379d573c1e6","name":"node_7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","services":["bzz","pss"],"enable_msg_events":true,"port":38929},"up":true}},{"node":{"info":{"id":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","name":"node_a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","enode":"enode://3550f2c56a73defeb97f0536204448c4e3e1331335e6e3a3014a4abcc64baa713863be64fced29ef2a307d2dadad652ef223a9ccc585b280a4cc7fcc0c873f95@127.0.0.1:0","enr":"0xf88fb840de06617ae4d0d818ea821d1c9879aee77965e21e891045657c110f6dbfb3933b1e580ab1ec78fad61f0175343ddcf154cbf61d63b77419bfe6bd777d864a3b700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033550f2c56a73defeb97f0536204448c4e3e1331335e6e3a3014a4abcc64baa71","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pgbHmgGKZTU3XYUfzILELMfJUnIKoSBDTO3M9KS+H1k=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a606c7\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1bd5 3188 5a8b 5d82 | 126 0d1c (0) 0cfc (0) 0e80 (0) 0e3b (0)\n001 4 fc51 c9c3 c961 cd6c | 55 e681 (0) e64d (0) e471 (0) e2d3 (0)\n002 4 834f 8854 93ea 9f0e | 38 8b43 (0) 8862 (0) 8854 (0) 8d19 (0)\n003 3 b78f bfc7 be68 | 14 ba91 (0) bbaf (0) b8e1 (0) bcf8 (0)\n004 2 a8ff ab3f | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a0c8 a1c8 a330 a2e6 | 6 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n006 3 a5ac a505 a4ee | 3 a4ee (0) a505 (0) a5ac (0)\n============ DEPTH: 7 ==========================================\n007 2 a742 a7a8 | 2 a7a8 (0) a742 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a616 | 1 a616 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","private_key":"8b6e5a593a7a12ebb029cd578efe25114f3cadc22a3cd3b007eb164cc0a403fe","name":"node_a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","services":["bzz","pss"],"enable_msg_events":true,"port":45851},"up":true}},{"node":{"info":{"id":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","name":"node_a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","enode":"enode://1ce0a6ac890fddf6089a062091b0f114fb6c01ac09e618ad4a23a3b985db8b695448be996b1b51dceb7341aba28d101f31aafe50d1d312d995c03ca64b907a8b@127.0.0.1:0","enr":"0xf88fb8402bd8ecaf0ec85c076464ba4a7314b9946c19a06746bfd1758516d4674fcff67a4f495420e48344d1870f99c43e5e56750a310e1f532fdc3a46b647a06c8fb4a80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031ce0a6ac890fddf6089a062091b0f114fb6c01ac09e618ad4a23a3b985db8b69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oqFjziywkrQRyZTMXV71VdU50tz05+GutSjSIW3EgeU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a2a163\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1bd5 3188 5d82 5a8b | 126 138d (0) 1070 (0) 1049 (0) 1484 (0)\n001 6 eebd f645 fc51 cd6c | 55 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n002 4 8854 8f9a 93ea 9f0e | 38 8b43 (0) 8862 (0) 8854 (0) 8cc3 (0)\n003 5 bbaf b8e1 be68 bfc7 | 14 ba91 (0) bbaf (0) b8e1 (0) bdc5 (0)\n004 4 af02 a8ff a8f4 ab3f | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a4ee a5ac a505 a742 | 7 a4ee (0) a505 (0) a5ac (0) a7a8 (0)\n006 2 a0c8 a1c8 | 2 a0c8 (0) a1c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a330 a327 | 2 a330 (0) a327 (0)\n008 0 | 0\n009 1 a2e6 | 1 a2e6 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","private_key":"c7c3bdf809c4dddc3d69c2437ecee9174c62113e7183c42d4b735143382ca5f2","name":"node_a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","services":["bzz","pss"],"enable_msg_events":true,"port":40591},"up":true}},{"node":{"info":{"id":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","name":"node_b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","enode":"enode://411f2844b08f1aa72a27b2f54a551d3eed6c7b634162cb04ef093d52effa83efc2797db053ce1fb70105d9fc15331a0312d148dc0431310eb2c42c6114cb0d7c@127.0.0.1:0","enr":"0xf88fb8404517ad1475dcc5865807afaa0a472b5446b69dbcc2465732186fb2220224daa510beea5edfe3b120c3ee1f7e942904d4ca137b556ea6feada809a6a61e2788a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102411f2844b08f1aa72a27b2f54a551d3eed6c7b634162cb04ef093d52effa83ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"t4/SHAYwBuLgM9HQD8IeGteteVG7ViHOybVmOXRdZfk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b78fd2\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 7850 5d82 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 10 f2b4 f645 fc51 eebd | 55 e09f (0) e0a0 (0) e277 (0) e2d3 (0)\n002 6 93ea 9948 9959 8e28 | 38 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n003 9 af02 a8ff ab3f a606 | 23 acee (0) aeb4 (0) af02 (0) a970 (0)\n004 4 bbaf b8e1 be68 bfc7 | 8 ba91 (0) bbaf (0) b8e1 (0) bcf8 (0)\n005 1 b3f9 | 1 b3f9 (0)\n006 2 b5ea b4a1 | 2 b4a1 (0) b5ea (0)\n============ DEPTH: 7 ==========================================\n007 2 b659 b6df | 2 b659 (0) b6df (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","private_key":"74aa90f3bd323ba9eb7d36c9d5d71fba2abcc8c139f09a30ae66ad200d31f31a","name":"node_b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","services":["bzz","pss"],"enable_msg_events":true,"port":45951},"up":true}},{"node":{"info":{"id":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","name":"node_5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","enode":"enode://45a546c77bd0b76e5a8c4cfa9b4ffb8e2124519e39fb9ac6862eef3a6b3ab36d2abb6edf5e822fc9e94a5f821a233fec02ed076b5394052bc3e5ac3f92382ef1@127.0.0.1:0","enr":"0xf88fb8406a321e44c0f6e7960b5f4a6d36376704b05c7a3ba49b1eb6acf89dedda8b5e267297203a9b15f97facaee8eaa5c3c25357451b6f70c3ea2c879c2c9c7a6b02b80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10345a546c77bd0b76e5a8c4cfa9b4ffb8e2124519e39fb9ac6862eef3a6b3ab36d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XYKkGGKc++fFcQUwkxmtaVoZhib+NXHeIToS3fYvcwg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5d82a4\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 d9cf ddb8 93ea 837f | 130 e681 (0) e64d (0) e471 (0) e0a0 (0)\n001 4 194e 1686 1049 3980 | 65 138d (0) 1070 (0) 1049 (0) 1484 (0)\n002 2 6dd3 7850 | 26 6b4e (0) 68cb (0) 6c01 (0) 6dd3 (0)\n003 9 435d 43d4 447a 447c | 19 4005 (0) 402c (0) 435d (0) 43c9 (0)\n004 5 52a8 50c1 5663 56ca | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 4 5814 5a26 5a8b 5ac0 | 6 5987 (0) 5814 (0) 5bd8 (0) 5a26 (0)\n006 1 5ff0 | 1 5ff0 (0)\n============ DEPTH: 7 ==========================================\n007 2 5c7c 5c37 | 2 5c7c (0) 5c37 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","private_key":"69766d2192a8d8f57768af92f8ff7baed8f3a52c22d97417f21e6a5fd3de4f42","name":"node_5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","services":["bzz","pss"],"enable_msg_events":true,"port":45337},"up":true}},{"node":{"info":{"id":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","name":"node_7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","enode":"enode://0c0ebe3bbeeb5597d947b1f7b5a2e127a5d6d3b63ef0f3e9729357e767470a8b462ec3cdd15997331c24a9152665d19273a3e79dfc447b7f50381bad46365a7e@127.0.0.1:0","enr":"0xf88fb84028a27a4976245ab6fe76c73b436192338af7ac71f5eb0fb25641c2ced4180b5b5f63f71d6ca7b7ce5129bf98a88efaf0231aba54207434478862b181f9430d2f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c0ebe3bbeeb5597d947b1f7b5a2e127a5d6d3b63ef0f3e9729357e767470a8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eFD17lBIlZVZs68PlWiWabJQ/Dqli8yVRNymHKnJdpw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7850f5\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 d9cf ddb8 93ea 837f | 130 e681 (0) e64d (0) e471 (0) e09f (0)\n001 4 1049 1686 0e2b 3980 | 65 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n002 5 482e 4cec 4d38 5a8b | 35 435d (0) 43c9 (0) 43d4 (0) 4005 (0)\n003 7 68cb 6b4e 6d5e 6dd3 | 13 6b4e (0) 68cb (0) 6c01 (0) 6d5e (0)\n004 3 7049 741a 7660 | 4 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n005 5 7e47 7d16 7ce7 7c7c | 5 7e47 (0) 7d16 (0) 7ce7 (0) 7c7c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 79e5 7933 | 2 79e5 (0) 7933 (0)\n008 1 7895 | 1 7895 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","private_key":"40edb5f8d252880b90ba7fde9823f697100b67c90e06a29fc3ec7a5810ab62c1","name":"node_7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","services":["bzz","pss"],"enable_msg_events":true,"port":32987},"up":true}},{"node":{"info":{"id":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","name":"node_ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","enode":"enode://78199c63a76cbaf76cd9760f290345fb7a8a8a0598e99d6152136896aaf69a6894757d496cb59a95925c3a18fe730382766be78a9f0ed4f3f11f866eb8bcdbc9@127.0.0.1:0","enr":"0xf88fb840e42249c4aa731c39349c743bdccfbcb826dcab6b0976b0262879a51570c9605f2840fb4f81fc6d939000acd0b1047aa6ecb2774a78c7a3c74b6dfe5b9f5c47900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10378199c63a76cbaf76cd9760f290345fb7a8a8a0598e99d6152136896aaf69a68","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qz/5VQM8CiYVky+vhf0gCQuRIcftzI5vfOTE/eCpa4o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ab3ff9\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1049 194e 1bd5 7850 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 5 f2b4 ec90 ed42 eebd | 55 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n002 2 9959 837f | 38 97da (0) 9464 (0) 9518 (0) 955d (0)\n003 3 bfc7 be68 b78f | 14 bdc5 (0) bcf8 (0) bea1 (0) be68 (0)\n004 6 a327 a2e6 a2a1 a505 | 13 a505 (0) a5ac (0) a4ee (0) a7a8 (0)\n005 3 acee aeb4 af02 | 3 acee (0) aeb4 (0) af02 (0)\n006 4 a970 a8b5 a8f4 a8ff | 4 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n============ DEPTH: 7 ==========================================\n007 1 aaf0 | 1 aaf0 (0)\n008 0 | 0\n009 1 ab71 | 1 ab71 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","private_key":"da16d3eec72f2e238edf7ba4f10364552eab2cefb316a7c76c8723d52989563d","name":"node_ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","services":["bzz","pss"],"enable_msg_events":true,"port":33141},"up":true}},{"node":{"info":{"id":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","name":"node_d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","enode":"enode://2042548f0f7c90b6cc2256c4d77e13ecd17a9f61272ad14494e2b21d9ac6029caebf34338de3872e5f3e447fa2ebf066ecd5ebbca76298324eccfade50751e7b@127.0.0.1:0","enr":"0xf88fb8406c1e73483cf923948ac9f54e2c047930e5ea66c902c1040e2c9d6b5a9a00a5c43110236e80ffd8ed3ee80e60f2f9b7395e5956aa2e30c6137271720864699cda0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032042548f0f7c90b6cc2256c4d77e13ecd17a9f61272ad14494e2b21d9ac6029c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2c8ZiV4BXLU02RWu2DwNJr9AoRJEAngS4Xw77G5kWo4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d9cf19\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 60c5 7850 7c46 5d82 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 8 8f9a 837f b8e1 b78f | 75 97da (0) 9464 (0) 9518 (0) 955d (0)\n002 5 f645 f2b4 f9de fa24 | 28 e471 (0) e681 (0) e64d (0) e2d3 (0)\n003 3 c9c3 c961 cd6c | 16 c534 (0) c42e (0) c74d (0) c603 (0)\n004 2 d700 d408 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n005 1 ddb8 | 1 ddb8 (0)\n============ DEPTH: 6 ==========================================\n006 3 dad0 da36 dbd4 | 3 dbd4 (0) da36 (0) dad0 (0)\n007 0 | 0\n008 1 d959 | 1 d959 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","private_key":"d168c43714b032d43709695043aaf1c5458b60b0e73717ccf008b5d9e6af9939","name":"node_d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","services":["bzz","pss"],"enable_msg_events":true,"port":41547},"up":true}},{"node":{"info":{"id":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","name":"node_837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","enode":"enode://ed39f75e6b5a22a7e8c6809ee4d870c133f22f4c93186e3c69457307c78fc12579cf7b7318723f40a0503f854e69da1de58ba5569bdf14e5b61f67446a138ed7@127.0.0.1:0","enr":"0xf88fb840c0e24ca2a2a76ce110f103428f1e7d60a3403afc52473a5aa71b9c63de5b4cb4379c41f9901442f5e2afb7f988f8a6bcc1ccfb6b2fd6494e5fba5c2ae7f45f420183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ed39f75e6b5a22a7e8c6809ee4d870c133f22f4c93186e3c69457307c78fc125","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g38Jk/Y3QDmlrURy1jE+ZHpMXbRYO9J8z6mNNEihdzE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 837f09\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5d82 7850 3980 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 3 c961 ddb8 d9cf | 55 e681 (0) e64d (0) e471 (0) e09f (0)\n002 7 be68 b78f a4ee a505 | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 7 97da 95c0 93ea 9f0e | 17 97da (0) 9464 (0) 9518 (0) 955d (0)\n004 6 8854 8cc3 8d19 8f9a | 9 8b43 (0) 8862 (0) 8854 (0) 8cc3 (0)\n005 4 84a9 8402 87a3 86d6 | 4 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n006 5 81a5 8006 8073 8074 | 5 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 2 8358 834f | 2 8358 (0) 834f (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","private_key":"9f0d233abf6f03526bd7a057b2f9064dfb5632022a186fcc902c6aa7a2600627","name":"node_837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","services":["bzz","pss"],"enable_msg_events":true,"port":41733},"up":true}},{"node":{"info":{"id":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","name":"node_ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","enode":"enode://23b26db5b1294383d9eea76f1d4a21a01a005282ec74c54d51f1d8d1c4ba9b19608cd921c5d735a101be0681eeaf5618e06460964f7d84656def7a07255111c8@127.0.0.1:0","enr":"0xf88fb84045e7162cf3f1ac630c92a7e123116d9b2e1666b1e895bede1122e243f0f35cdf2994006582400b1294fe4fef4deeac77bfe7bdb0e1ccd0e4ea8e52c1240509830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10223b26db5b1294383d9eea76f1d4a21a01a005282ec74c54d51f1d8d1c4ba9b19","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3bi+Ryw9SNxNPREkSObAxKgmoYrz87U/3++M0xBTx18=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ddb8be\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0cfc 3980 5d82 7850 | 126 402c (0) 4005 (0) 43c9 (0) 43d4 (0)\n001 8 b78f b8e1 a2a1 a8ff | 75 a505 (0) a5ac (0) a4ee (0) a7a8 (0)\n002 7 ec90 f645 f2b4 fa24 | 28 e471 (0) e681 (0) e64d (0) e2d3 (0)\n003 5 c534 c190 cd6c c961 | 16 c42e (0) c534 (0) c74d (0) c603 (0)\n004 3 d302 d700 d408 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n============ DEPTH: 5 ==========================================\n005 5 da36 dad0 dbd4 d959 | 5 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","private_key":"18bcdc56f12314ff79470029b0f3813f675978100fef3ddaca5023bc2f8dde78","name":"node_ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","services":["bzz","pss"],"enable_msg_events":true,"port":38607},"up":true}},{"node":{"info":{"id":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","name":"node_9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","enode":"enode://a3d56214ef40b3b64d2662d12f80d743f10da57b12601e31cbf572034244e1b299ce4be5f33a1b2f6c7eee9a79827c5d99e31d4f4b9cf64aa9ed02d901582fab@127.0.0.1:0","enr":"0xf88fb8404add71b1f22ba7a42f2b948ac2455c1e2a37e5d83ec2f50f0116cc91995cd31d2dc7ec48bc5ace7137fecaea8828738c17e66b551ca661a4f724b2ed1395ce3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a3d56214ef40b3b64d2662d12f80d743f10da57b12601e31cbf572034244e1b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mVk4U4Wq3nKNP1djgGWWIivB57mUbCySQHlD0ICzL40=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 995938\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 60c5 0e2b | 126 6b4e (0) 68cb (0) 6c01 (0) 6d5e (0)\n001 2 fc51 ddb8 | 55 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n002 5 b78f a327 af02 ab3f | 37 bdc5 (0) bcf8 (0) bea1 (0) be68 (0)\n003 4 837f 8854 8f9a 8e28 | 21 8b43 (0) 8862 (0) 8854 (0) 8cc3 (0)\n004 4 955d 95c0 97da 93ea | 8 97da (0) 9464 (0) 9518 (0) 955d (0)\n005 6 9ca1 9c8e 9c21 9ec8 | 6 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n============ DEPTH: 6 ==========================================\n006 1 9b8e | 1 9b8e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 9948 | 1 9948 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","private_key":"011707e678d73ecf94ba7f710501f262764a152ffa7dbe48f5b7e7dbef86a807","name":"node_9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","services":["bzz","pss"],"enable_msg_events":true,"port":45157},"up":true}},{"node":{"info":{"id":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","name":"node_0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","enode":"enode://0b612a1ab5d916d8c26372863438f68d00efff720cb1a318c642e37ac4ddc0cbdc0f21d3d1935ad022323a317ef443741ee0e6ce46c01604b94783f86719582b@127.0.0.1:0","enr":"0xf88fb84072f6428c1949285e98cf3010a22fd4023bb5fe817a070b704d991522730917097a117d183bc0722f66f9d163f8eb714e74db79ad6fcb7ac5fca67930f49bd28c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030b612a1ab5d916d8c26372863438f68d00efff720cb1a318c642e37ac4ddc0cb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DitIVYzirx+/7jilV9VgcuMJHPyu6NeEfHydz3vvm/o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e2b48\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 fc51 d408 a8ff 9948 | 130 e471 (0) e681 (0) e64d (0) e09f (0)\n001 6 7850 60c5 56ca 5ac0 | 61 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n002 4 2c80 2ddf 26ac 3980 | 28 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n003 2 1049 1686 | 16 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n004 5 0314 0191 07f5 0594 | 10 025d (0) 035f (0) 0314 (0) 012b (0)\n005 3 08e5 09b3 096a | 6 08bd (0) 08f8 (0) 08e5 (0) 09b3 (0)\n006 2 0d1c 0cfc | 2 0d1c (0) 0cfc (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0e80 | 1 0e80 (0)\n009 0 | 0\n010 0 | 0\n011 1 0e3b | 1 0e3b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","private_key":"510468331a493c1c9e097b948955dfff54c130f51894aed02d4f46d1260021a2","name":"node_0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","services":["bzz","pss"],"enable_msg_events":true,"port":44575},"up":true}},{"node":{"info":{"id":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","name":"node_a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","enode":"enode://b7201bebbe44d4f065e0344f51747c686401af50a2bc1e4bad167b56d0f5b94eaa6e6d50bd5b2708510984708c155ac50ed29d14b941ab71d22312033bbb9a20@127.0.0.1:0","enr":"0xf88fb840a72c72b758119852724dc6373359756fc7224766b257144c15597ba291dfbf8b1d8e2cac36d326b4a0e1ce960e294438b019d49713d6232eeb5dfd63341c13b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b7201bebbe44d4f065e0344f51747c686401af50a2bc1e4bad167b56d0f5b94e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qP+NadyzZGLREW2vpePQxyN79l2+zkgqMWhiyNZuNbY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a8ff8d\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 48de 0e2b | 126 7660 (0) 741a (0) 70f6 (0) 7049 (0)\n001 4 fc51 d408 d9cf ddb8 | 55 e681 (0) e64d (0) e471 (0) e277 (0)\n002 5 8854 8073 837f 834f | 38 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n003 4 be68 bfc7 b8e1 b78f | 14 bcf8 (0) bdc5 (0) bfc7 (0) bea1 (0)\n004 9 a327 a2e6 a2a1 a5ac | 13 a505 (0) a5ac (0) a4ee (0) a7a8 (0)\n005 3 acee aeb4 af02 | 3 acee (0) aeb4 (0) af02 (0)\n006 2 ab71 ab3f | 3 aaf0 (0) ab71 (0) ab3f (0)\n007 1 a970 | 1 a970 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 a8b5 | 1 a8b5 (0)\n010 0 | 0\n011 0 | 0\n012 1 a8f4 | 1 a8f4 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","private_key":"a3dc455b16cb040e97e400cbec5c77f9c6769a891569bafb9020595880600d14","name":"node_a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","services":["bzz","pss"],"enable_msg_events":true,"port":45235},"up":true}},{"node":{"info":{"id":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","name":"node_48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","enode":"enode://9422ff095b3dd7d5bb7caaf864015278473292f40803e5eab069fc7c270309b3386d001c249d10c2dde0f71ca459477ee74f149e5d7e1fe7ece9bf08237ab0dc@127.0.0.1:0","enr":"0xf88fb840df7b0ea5b6e73e0e48e983961669a7dc87cf47c6389512f75462e4d8f28e526567df2cdbb5da10b6d57e809894f1039e00f7f774c8fd1d1d14710dbae4bb8f520183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029422ff095b3dd7d5bb7caaf864015278473292f40803e5eab069fc7c270309b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SN5VPhWv0+ika/w6W6iimBWKo9YPFA0nMCMK9czoCE0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48de55\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c9c3 d9cf d408 fc51 | 130 e09f (0) e0a0 (0) e2d3 (0) e277 (0)\n001 3 1686 0e2b 3980 | 65 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n002 5 7d16 7c46 7933 79e5 | 26 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n003 5 56ca 5a8b 5ac0 5d82 | 16 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n004 3 447c 43c9 43d4 | 9 46bf (0) 44ad (0) 447a (0) 447c (0)\n005 3 4cec 4d91 4d38 | 3 4cec (0) 4d91 (0) 4d38 (0)\n006 2 4a95 4b79 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 1 48b8 | 1 48b8 (0)\n010 1 48f1 | 1 48f1 (0)\n011 0 | 0\n012 1 48d7 | 1 48d7 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","private_key":"fe29ef81976826aba3a92e42c6b3848892672ee26649d67650358d54e85982e9","name":"node_48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","services":["bzz","pss"],"enable_msg_events":true,"port":40001},"up":true}},{"node":{"info":{"id":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","name":"node_398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","enode":"enode://932586d99d84466fce1c3d7a331315a768c320b890811c2a00eae226a62c05023605308437407502d54d2e09910164e7a9c6343a935e4fdb8267d1661a4a11ad@127.0.0.1:0","enr":"0xf88fb840f777fcf141adaf513c8cd83b5b2ad8716fe3f0805c0b83c31d3ee8bc13347b6370696f994cdc0cab03b8363ed9da19e3717ff65f31244ca6a3f22719f3df605c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103932586d99d84466fce1c3d7a331315a768c320b890811c2a00eae226a62c0502","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OYA4gRwcdAL+LmmUyc4vFcgWa46Z83n+qu1mrIdwIGI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 398038\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 fc51 c9c3 d9cf ddb8 | 130 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n001 6 60c5 7933 7850 5ff0 | 61 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n002 5 1b1d 1bd5 1049 1686 | 37 1dec (0) 1dc0 (0) 1fd0 (0) 18e0 (0)\n003 6 24f8 26ac 2e65 2fd2 | 11 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n004 5 3411 32ff 3188 31e1 | 9 36b9 (0) 3728 (0) 3411 (0) 32ff (0)\n005 3 3c5b 3cab 3f31 | 3 3f31 (0) 3c5b (0) 3cab (0)\n006 2 3a62 3b02 | 2 3a62 (0) 3b02 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 3938 397a | 2 3938 (0) 397a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","private_key":"571a1e200af7799e0d7295849ae3beaf1d75ccfa29216b243feedb21761d2bde","name":"node_398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","services":["bzz","pss"],"enable_msg_events":true,"port":43453},"up":true}},{"node":{"info":{"id":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","name":"node_8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","enode":"enode://0703457de466898f77a218b2253e4074f9d84ddc40a4d85a7677e03f1dc45090d8a5c0ae0f3bce42a249384f9f84ed92f79c7d71a80f97e4ea6787fec0979ef7@127.0.0.1:0","enr":"0xf88fb840d9529815a2188630f6e5a9a83b676cc923f44db1dce486279c916e75d9676afc6d6babb5690670e670141db7383ce8f862fe1828478493d343ad4d8e614bda370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030703457de466898f77a218b2253e4074f9d84ddc40a4d85a7677e03f1dc45090","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jigrDyfU+lb+FM/rafrFpT49iCx3eOsZBlPi6rfJP9I=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8e282b\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 60c5 3980 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 4 c9c3 d408 ddb8 fc51 | 55 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n002 7 b78f b5ea bbaf b8e1 | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 6 955d 95c0 93ea 9b8e | 17 97da (0) 9464 (0) 95c0 (0) 9518 (0)\n004 5 81a5 80d7 8073 834f | 12 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n005 3 8b43 8862 8854 | 3 8b43 (0) 8862 (0) 8854 (0)\n006 2 8d19 8cc3 | 2 8cc3 (0) 8d19 (0)\n007 1 8f9a | 1 8f9a (0)\n============ DEPTH: 8 ==========================================\n008 1 8ea2 | 1 8ea2 (0)\n009 1 8e7b | 1 8e7b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","private_key":"5ee46cbe7328b036aa2e3281aec50d734d3fa00761ec99b53bf5a30a940a2006","name":"node_8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","services":["bzz","pss"],"enable_msg_events":true,"port":45567},"up":true}},{"node":{"info":{"id":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","name":"node_994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","enode":"enode://e251495df5e012ceae31fcd4e011f13d611edf3549f6a33eda33b9acbf5757be44d865d329431079380d794b06c97fadb2535cc2f5dbdca5c5aeaec59905c430@127.0.0.1:0","enr":"0xf88fb840fb7050cef033c59b67f105ef731c850b3215a560ec374d2010a4bd2627d51dbb3197c902a18ab6e66e4cf1b7fff54b0f59f9a9ef96b27e68f9293883e3c80f6b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e251495df5e012ceae31fcd4e011f13d611edf3549f6a33eda33b9acbf5757be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mUg55fOluLI67YT7ApQTEkrxeAS3mwJj7Gv9WuxdrXg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 994839\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 48de 5ff0 1686 0e2b | 126 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n001 4 f645 f2b4 ec90 d408 | 55 e471 (0) e681 (0) e64d (0) e0a0 (0)\n002 5 b8e1 b78f b5ea a4ee | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 4 8073 837f 8854 8e28 | 21 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n004 4 93ea 955d 95c0 97da | 8 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n005 6 9c21 9c8e 9ca1 9ec8 | 6 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n============ DEPTH: 6 ==========================================\n006 1 9b8e | 1 9b8e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 9959 | 1 9959 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","private_key":"334ce36c1f8b4c0d2139b19e7e5bb3a3a15fb0ce90610d2e1d1482d7b645c2d8","name":"node_994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","services":["bzz","pss"],"enable_msg_events":true,"port":33079},"up":true}},{"node":{"info":{"id":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","name":"node_d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","enode":"enode://39f55004bcfcc2f16c4a1b4b723534c4c9e589ab5895a3cbe311aafd0c6e6de0bb47140ec73fdaa26a6b50f5227664e84e1e1a80db2796990116ad381c21a936@127.0.0.1:0","enr":"0xf88fb8405ae4c29ace5f03e6d651ba48886e1be64addab49c04c36ac806e5a5fd9788caf222b4d1266aa622022a3e58fd35aebcb70e30a50cbd2abb8826746fbe05420770183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10239f55004bcfcc2f16c4a1b4b723534c4c9e589ab5895a3cbe311aafd0c6e6de0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1Ai7b3rxWQ4fFizgLMAWsbhu3imFHKoyQ0IS/6Kjd8g=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d408bb\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5ff0 48de 482e 0cfc | 126 2a50 (0) 298a (0) 2fd2 (0) 2e65 (0)\n001 5 b8e1 a2e6 a8ff 8e28 | 75 b3f9 (0) b659 (0) b6df (0) b78f (0)\n002 7 ec90 f645 f2b4 f9de | 28 e471 (0) e681 (0) e64d (0) e09f (0)\n003 4 cf52 cd6c c961 c9c3 | 16 c534 (0) c42e (0) c74d (0) c603 (0)\n004 4 ddb8 dbd4 dad0 d9cf | 6 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n============ DEPTH: 5 ==========================================\n005 3 d209 d3e9 d302 | 3 d209 (0) d3e9 (0) d302 (0)\n006 1 d700 | 1 d700 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","private_key":"251a8df09943db0babcf770639c5ccce249b19a3b91f88c6beb4090f8d366ac0","name":"node_d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","services":["bzz","pss"],"enable_msg_events":true,"port":45605},"up":true}},{"node":{"info":{"id":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","name":"node_fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","enode":"enode://e92b9c292a29d8bfb7f4db4dbf539ed52534331fe43603f2c813dc801b4ec9364bff7fc962d375834ac6a1df1673c3615c40bef17b51f6debf2707acc9b17f58@127.0.0.1:0","enr":"0xf88fb840d952b221d3ae5c9e409850d227fa2dbd7c2e1db0634a5bbe1bc2ed2c46085d457766d51c388252a60d37b5490aa17cc4745f7bbe669b67e28838599f027738ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e92b9c292a29d8bfb7f4db4dbf539ed52534331fe43603f2c813dc801b4ec936","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/FFMQ8TrXGJ5hFjaXWIukkim5TDkKIzZAgGaoFxDdNg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fc514c\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0e2b 3980 48de 60c5 | 126 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n001 9 b78f a606 a4ee a2a1 | 75 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n002 7 cd6c c961 c9c3 dbd4 | 27 c534 (0) c42e (0) c74d (0) c603 (0)\n003 6 ec90 eebd ef99 eff2 | 14 e471 (0) e681 (0) e64d (0) e09f (0)\n004 3 f2b4 f6c0 f645 | 7 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n005 3 fa24 f8ff f9de | 3 f8ff (0) f9de (0) fa24 (0)\n============ DEPTH: 6 ==========================================\n006 2 ff75 feb3 | 2 ff75 (0) feb3 (0)\n007 0 | 0\n008 0 | 0\n009 1 fc39 | 1 fc39 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","private_key":"de7c0775a3921769035f59bb73e223f1b8dfa39617f5ee35cac84c7ded6a49a2","name":"node_fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","services":["bzz","pss"],"enable_msg_events":true,"port":44357},"up":true}},{"node":{"info":{"id":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","name":"node_60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","enode":"enode://6e5ef281f10a4795906b37800a284f193c6df512a1c03450197eca7bb6d9ce2d5a4878fb2bc42afc40cf28050d15a8e2888fdc544d06d6f13528265866a5f3a6@127.0.0.1:0","enr":"0xf88fb840ac7b31fb8f269a7992246ec994fbd4a2a7f22777ade012e4b89f058b0686fd46005eb0f24df29c1b5dd22f15fc54a20ef32b2d96a5ee581c1f7ab6e3da71f21d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026e5ef281f10a4795906b37800a284f193c6df512a1c03450197eca7bb6d9ce2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YMVkeu0VJgmXk2b7M9yLKPxgc2CY/2jSMkFYibQ9+lg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 60c564\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 9b8e 9959 8e28 d9cf | 130 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n001 4 26ac 3980 0e2b 1686 | 65 36b9 (0) 3728 (0) 3411 (0) 32ff (0)\n002 5 482e 48de 56ca 5a8b | 35 4005 (0) 402c (0) 435d (0) 43c9 (0)\n003 6 70f6 7d16 7c46 79e5 | 13 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n004 7 6b4e 68cb 6e7f 6c01 | 7 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n============ DEPTH: 5 ==========================================\n005 5 648a 6758 6790 6795 | 5 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","private_key":"89bbc4a8fe5905ca2c155be018babb341d9441135f074af282a327e2977357c6","name":"node_60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","services":["bzz","pss"],"enable_msg_events":true,"port":39295},"up":true}},{"node":{"info":{"id":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","name":"node_16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","enode":"enode://d845540617736b1958a11594e15934337e7127add929bad0c013d12cd65bb64d7dcb2d8dd41977f03a22b4e86e71a1edde519259f5dca5668307527cfe16bcf0@127.0.0.1:0","enr":"0xf88fb840782b90fecea289d4c0215935b270fcc0fd83a631e1fb144bf3134dbf4582abd20975b3712cf657a6d9a1d6ea942967f04741f6c2916f23ddef51ce04bea2d2490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d845540617736b1958a11594e15934337e7127add929bad0c013d12cd65bb64d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FoaOxdj0kKxz6ii06P3aVawUm7Gq+xd1RbVLhKWtU2c=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 16868e\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f645 c9c3 d408 b5ea | 130 e277 (0) e2d3 (0) e0a0 (0) e09f (0)\n001 7 482e 48de 56ca 5d82 | 61 46bf (0) 44ad (0) 447a (0) 447c (0)\n002 4 2ddf 2c80 2e65 3980 | 28 2a50 (0) 298a (0) 2fd2 (0) 2e65 (0)\n003 6 0191 0561 07f5 096a | 21 025d (0) 035f (0) 0314 (0) 012b (0)\n004 6 1dec 18e0 19ea 194e | 9 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n005 3 138d 1070 1049 | 3 138d (0) 1070 (0) 1049 (0)\n============ DEPTH: 6 ==========================================\n006 2 1484 140d | 2 1484 (0) 140d (0)\n007 1 1784 | 1 1784 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","private_key":"bde6dc606a9dc59b55e66e91238cd63fc2c84b7edc67fa0321b927540331ca5e","name":"node_16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","services":["bzz","pss"],"enable_msg_events":true,"port":41853},"up":true}},{"node":{"info":{"id":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","name":"node_9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","enode":"enode://09589964a1f4465dee4d0ce2388504a335ccfb484711b50e3a9a80b8b0671acb75b7d6aac621bf17746a584d606bb0aa677c302a4d44653ae28f11b437df20a9@127.0.0.1:0","enr":"0xf88fb840095da26616eca877077703e0e2b51dd8b7dadf89e7da897184fa333b8cde3d123ae6c94cd31c163ce10dbbf39a9ce6bd32e51570e5aeb9f82ae57427fd2a9b440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10309589964a1f4465dee4d0ce2388504a335ccfb484711b50e3a9a80b8b0671acb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"m45rs6f+TcZayXQE5UbYt3fQaMlLwjVfTxpRCtbBGQU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9b8e6b\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 60c5 5ac0 5ff0 1686 | 126 46bf (0) 44ad (0) 447a (0) 447c (0)\n001 3 f645 fc51 c9c3 | 55 e277 (0) e2d3 (0) e0a0 (0) e09f (0)\n002 5 bbaf af02 a327 a2e6 | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 5 8073 837f 8d19 8f9a | 21 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n004 3 93ea 95c0 955d | 8 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n005 6 9ec8 9f7d 9f0e 9c21 | 6 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n============ DEPTH: 6 ==========================================\n006 2 9948 9959 | 2 9948 (0) 9959 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","private_key":"c540be3b3745151e75287e86c62db0fa68c68a13c06e511d9ccafa0b720969a9","name":"node_9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","services":["bzz","pss"],"enable_msg_events":true,"port":41055},"up":true}},{"node":{"info":{"id":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","name":"node_c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","enode":"enode://9022be2eafd1b596287e78101c820178a736461ebf18c02d293c56d67cc881daa6b234e7b7d1f37ac3f49ececef3b96edbdc462ce5f5fe2bf41079787a8093a5@127.0.0.1:0","enr":"0xf88fb840f7351379bc850fcc93ba2ef5af9d2f0407e068046473feb7b496ec6fa8f56c0151ed144e7a078a2160242e4793f0508666d82ac0bf8b809d7fb1b8c0becc07630183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039022be2eafd1b596287e78101c820178a736461ebf18c02d293c56d67cc881da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ycMC3kr+e03LtvPjZs50cIP53NfVxqAbk52lzcbMyHQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c9c302\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3980 1049 1686 60c5 | 126 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n001 6 b78f a327 a606 af02 | 75 b3f9 (0) b659 (0) b6df (0) b78f (0)\n002 6 ec90 fa24 feb3 fc51 | 28 e471 (0) e681 (0) e64d (0) e2d3 (0)\n003 6 d9cf dbd4 dad0 ddb8 | 11 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n004 2 c272 c190 | 8 c534 (0) c42e (0) c74d (0) c603 (0)\n005 4 cf52 cc33 cdb1 cd6c | 4 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c8ea c8c8 | 2 c8ea (0) c8c8 (0)\n008 1 c961 | 1 c961 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","private_key":"2d2c2ccb0a0c233399b577f4b799b0181de2cd4673c1207b189502c87c899154","name":"node_c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","services":["bzz","pss"],"enable_msg_events":true,"port":33367},"up":true}},{"node":{"info":{"id":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","name":"node_5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","enode":"enode://47a8bfa3642fb14aad3497d548cd0ff911bb2e2a2cb1690be88d88e3a6bf854a4cab67630b26b8aced1d96c0e4c0cea337456b5e7fda0712b0e63b17ce8566d6@127.0.0.1:0","enr":"0xf88fb840c2abefc8eb1e4331f1a75917b53d225e82282d262f0e4bb2f4b77c9bbe6efb7703a6ff2d0f874bd663d1ac50566237c65b0438059ff31730c896e201938003b50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10247a8bfa3642fb14aad3497d548cd0ff911bb2e2a2cb1690be88d88e3a6bf854a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"X/CcaFlzaq16gqO/s/GhqLPA1Y+DGGNUDZwwE901dF4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5ff09c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 af02 a4ee 9948 9b8e | 130 b3f9 (0) b6df (0) b659 (0) b78f (0)\n001 5 2ddf 3980 0e2b 1049 | 65 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n002 5 79e5 6dd3 6d3c 68cb | 26 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n003 5 43d4 43c9 4d38 48de | 19 46bf (0) 44ad (0) 447a (0) 447c (0)\n004 4 50c1 5538 5663 56ca | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 3 5814 5ac0 5a8b | 6 5987 (0) 5814 (0) 5bd8 (0) 5a26 (0)\n============ DEPTH: 6 ==========================================\n006 3 5c37 5c7c 5d82 | 3 5c37 (0) 5c7c (0) 5d82 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","private_key":"00702831aac71a1861099a693ff9a0eb5bbad3993d5054de5722027d2906dc32","name":"node_5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","services":["bzz","pss"],"enable_msg_events":true,"port":45801},"up":true}},{"node":{"info":{"id":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","name":"node_482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","enode":"enode://61e80e865b0692bff9618d89bec4178cc713d2efccfd0c9f11a94a3bb65f510ccae3af079e3ec0db026b08c0f41eef7440b0a04cbf7a88a8e948a7bbe0f09d4b@127.0.0.1:0","enr":"0xf88fb8408eae3376cda8894401f6a76ded081e214dbcdcc35516b057e7e27962ce8e71fb038d41811263fcd3e7ae470ebad950d4ce9de19c18246bbe58efd4e64cd0b4ea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10361e80e865b0692bff9618d89bec4178cc713d2efccfd0c9f11a94a3bb65f510c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SC7D3AVGBXnqm86HZ3vT2aGTDoAfq+umB7ira4cp/xU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 482ec3\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a4ee c9c3 d408 f645 | 130 c74d (0) c6a8 (0) c603 (0) c534 (0)\n001 3 1bd5 1686 1049 | 65 36b9 (0) 3728 (0) 3411 (0) 32ff (0)\n002 5 60c5 68cb 79e5 7850 | 26 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n003 7 5663 56ca 5814 5a8b | 16 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n004 4 447c 435d 43d4 43c9 | 9 46bf (0) 44ad (0) 447a (0) 447c (0)\n005 3 4cec 4d91 4d38 | 3 4cec (0) 4d91 (0) 4d38 (0)\n006 2 4a95 4b79 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 4 48b8 48f1 48d7 48de | 4 48b8 (0) 48f1 (0) 48d7 (0) 48de (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","private_key":"914825085a6c709b5fb3130de8c9b6f9593efcb2fa9db695821c0ad50d637918","name":"node_482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","services":["bzz","pss"],"enable_msg_events":true,"port":41929},"up":true}},{"node":{"info":{"id":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","name":"node_1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","enode":"enode://16980066851e866b8eec7c10d0b26aa7c7839271112682530f4801d3c494f8eca313971c90b19590d0b4f4995e2c799e328795c06bc5c030d200d40c803bfccc@127.0.0.1:0","enr":"0xf88fb84015420addbd5c0cd32d328b36acc314ecc7a045c9197df579feed2a3e4d1db4d930917f78b1bd4a674d1aa7ba04e0e6e3420d30208274bcc61493281b08b9fdc60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10216980066851e866b8eec7c10d0b26aa7c7839271112682530f4801d3c494f8ec","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EEnTIaRQcmzznR186hwQi+O+wTemRLYs3HOoU/Wlois=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1049d3\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c9c3 d408 fa24 f645 | 130 c603 (0) c6a8 (0) c74d (0) c42e (0)\n001 6 7850 7d16 56ca 5d82 | 61 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n002 6 3980 2e65 2c80 2ddf | 28 3728 (0) 36b9 (0) 3411 (0) 32ff (0)\n003 4 0561 07f5 0e80 0e2b | 21 025d (0) 035f (0) 0314 (0) 012b (0)\n004 6 1dec 18e0 19ea 194e | 9 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n005 4 1484 140d 1784 1686 | 4 1484 (0) 140d (0) 1784 (0) 1686 (0)\n============ DEPTH: 6 ==========================================\n006 1 138d | 1 138d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1070 | 1 1070 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","private_key":"199675da9f4b1fd8e250d9ba36169cc5b10d83f69b39656a4b8e5c7536feaef2","name":"node_1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","services":["bzz","pss"],"enable_msg_events":true,"port":46623},"up":true}},{"node":{"info":{"id":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","name":"node_a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","enode":"enode://d9a019201fc917f5e3bb43c74a43fbdb9c66a2ecdc3e751f299e5a984d91e005be151f1d7d28a1c4fff2cec0ee358c79bf2f767e391d4f6ac110a3e268da7f15@127.0.0.1:0","enr":"0xf88fb840755a7a98e81b46c4f8effc43bf335c6043a85c0351fdcad60a80aa1b0033db4b569b0b9e452bf29597b83a24824ae11bca382614a3eaf87ceda9ff79d9de62f60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d9a019201fc917f5e3bb43c74a43fbdb9c66a2ecdc3e751f299e5a984d91e005","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oubJAFEXaMjJlHqw+i5zl1zypM7H/RUher26JcMpMX4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a2e6c9\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 26ac 1049 | 126 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n001 3 d408 fa24 f645 | 55 c534 (0) c42e (0) c74d (0) c603 (0)\n002 4 8073 8f9a 9948 9b8e | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 5 be68 b8e1 bbaf b78f | 14 b3f9 (0) b659 (0) b6df (0) b78f (0)\n004 4 a8ff a8f4 ab3f af02 | 10 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n005 6 a742 a616 a606 a505 | 7 a616 (0) a606 (0) a7a8 (0) a742 (0)\n006 2 a0c8 a1c8 | 2 a0c8 (0) a1c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a330 a327 | 2 a330 (0) a327 (0)\n008 0 | 0\n009 1 a2a1 | 1 a2a1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","private_key":"4662f9a82f5f82c5aab562b02fffb40fe8b62834bae8104220f46efd89898980","name":"node_a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","services":["bzz","pss"],"enable_msg_events":true,"port":33333},"up":true}},{"node":{"info":{"id":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","name":"node_a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","enode":"enode://453ddc011affe7c5cf20098ebed634712f9be29be2f136db7321e21029a732ef5e9318f6500053225345d773e7fce47dd0e219b9c2a29a433e618c2471149840@127.0.0.1:0","enr":"0xf88fb8402c342bd3642c99cf153a0106b072c0342cea619d53b64076d24cf4d67838ed1a20e65fc7c73a613a6cbba324aaec9aa64fe96559e44ab51433b80746e933d9880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102453ddc011affe7c5cf20098ebed634712f9be29be2f136db7321e21029a732ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pO5Juyyqu2uUSLzf8fw8xnOi2wTqufXGLReH8sJZkKA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a4ee49\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1049 26ac 7d16 482e | 126 025d (0) 035f (0) 0314 (0) 012b (0)\n001 4 fc51 fa24 f2b4 f645 | 55 c534 (0) c42e (0) c74d (0) c603 (0)\n002 5 837f 8f9a 8e28 9948 | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 5 be68 bfc7 bbaf b78f | 14 b3f9 (0) b659 (0) b6df (0) b78f (0)\n004 3 a8ff ab3f af02 | 10 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n005 4 a1c8 a327 a2a1 a2e6 | 6 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n006 3 a606 a7a8 a742 | 4 a616 (0) a606 (0) a7a8 (0) a742 (0)\n============ DEPTH: 7 ==========================================\n007 2 a505 a5ac | 2 a505 (0) a5ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","private_key":"59ad354948f16052bee88884c787bea727cb225c8573f641845ac1ac2357d6a5","name":"node_a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","services":["bzz","pss"],"enable_msg_events":true,"port":36935},"up":true}},{"node":{"info":{"id":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","name":"node_f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","enode":"enode://af59e58eb60a9dc748725bc8525d5e216517bd1c27f15728d2959890b8b5997c33a6b7efea09f3ba50b0f8048cace4d001a24b5ac4287ef1721e0c78c577b448@127.0.0.1:0","enr":"0xf88fb8409a8b6d7253f6d169fb548b469ba22aff1ed726350e671757249d57cf12b9b1d54724906cae553e56619591a1da8e799760729eb50980d43b1544427ae48c8c370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102af59e58eb60a9dc748725bc8525d5e216517bd1c27f15728d2959890b8b5997c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9kWqucsr0nCZmLOOV4nJxfaNQHZebL2TuS5jg+tnHbo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f645aa\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1686 1049 26ac 7d16 | 126 07f5 (0) 046c (0) 0594 (0) 0561 (0)\n001 10 8f9a 9948 9b8e b78f | 75 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n002 10 d408 d700 ddb8 d9cf | 27 c534 (0) c42e (0) c74d (0) c603 (0)\n003 4 e0a0 eebd ed42 ec90 | 14 e471 (0) e681 (0) e64d (0) e277 (0)\n004 4 feb3 fc51 f9de fa24 | 7 fc39 (0) fc51 (0) ff75 (0) feb3 (0)\n005 4 f1ed f305 f215 f2b4 | 4 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f756 | 1 f756 (0)\n008 1 f6c0 | 1 f6c0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","private_key":"6ff11e7bc067a6cbe95f29b9359cd01605c91281829e73e543154f78ed8e7962","name":"node_f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","services":["bzz","pss"],"enable_msg_events":true,"port":41177},"up":true}},{"node":{"info":{"id":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","name":"node_5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","enode":"enode://8f9ce802b9786b4a1aa8b5644e566d23306c0d0eb77e6df2965b1e274d690b6e2502e7c011240b18cb138c87af5681de7a883889122b0615c0c638dc31dee213@127.0.0.1:0","enr":"0xf88fb840fa8500339bf2fbc498dadfc8621c437bdb9120747fabf305b106c05d497c3067734896952dafd120f87ca214cb31457fba84b83a7a0b61abd8f185ffe94970ee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038f9ce802b9786b4a1aa8b5644e566d23306c0d0eb77e6df2965b1e274d690b6e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WsDQC41kfexi0m4aaJ/QW4t6GnmrjENJO9bX0gmBbfE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5ac0d0\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 bbaf 8f9a 9b8e f2b4 | 130 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n001 4 0cfc 0e2b 0e80 26ac | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 3 6d3c 79e5 7d16 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 6 43c9 43d4 4cec 4d38 | 19 46bf (0) 44ad (0) 447a (0) 447c (0)\n004 3 5538 56ca 5663 | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 3 5ff0 5c7c 5d82 | 4 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n006 2 5987 5814 | 2 5987 (0) 5814 (0)\n007 1 5bd8 | 1 5bd8 (0)\n============ DEPTH: 8 ==========================================\n008 1 5a26 | 1 5a26 (0)\n009 1 5a8b | 1 5a8b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","private_key":"37d0a7ae7d8c4e2d793d9abd755aad9a8b44f13935e905b00e1f3dfdf0f52095","name":"node_5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","services":["bzz","pss"],"enable_msg_events":true,"port":39637},"up":true}},{"node":{"info":{"id":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","name":"node_7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","enode":"enode://63b48abfe4bd6eb3bb9cd83e20c13d4e1155c4d0e67d9f0f1fd7aa134a3c70b07eff745b46eb65ce17a2586d6bbc99cfe2b09a909211d1bd906dc518c6d028a1@127.0.0.1:0","enr":"0xf88fb84060ab746693d04040fa4a967d48408a7121a17efbe8c2ab834db16aa034e76736313708f92b2c32f579368352ba5953b50658b408af972a1fd6db52ba8b5d31840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10363b48abfe4bd6eb3bb9cd83e20c13d4e1155c4d0e67d9f0f1fd7aa134a3c70b0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fRYqEWYlhfjDjYj7JBYj5nus+QcDBl2ubAkrS1B9ZUM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7d162a\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f645 f2b4 fa24 a4ee | 130 c534 (0) c42e (0) c74d (0) c603 (0)\n001 3 1049 2fd2 26ac | 65 035f (0) 0314 (0) 025d (0) 0191 (0)\n002 5 43d4 48de 482e 56ca | 35 46bf (0) 44ad (0) 447a (0) 447c (0)\n003 5 60c5 68cb 6e7f 6d3c | 13 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n004 3 7660 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 4 7895 7850 7933 79e5 | 4 7895 (0) 7850 (0) 7933 (0) 79e5 (0)\n006 1 7e47 | 1 7e47 (0)\n============ DEPTH: 7 ==========================================\n007 3 7ce7 7c7c 7c46 | 3 7ce7 (0) 7c7c (0) 7c46 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","private_key":"9304de16b2dad1e33f2436981bb04e64cbfbd2b153362b7f99b6e8ed93f2e3c7","name":"node_7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","services":["bzz","pss"],"enable_msg_events":true,"port":43535},"up":true}},{"node":{"info":{"id":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","name":"node_af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","enode":"enode://7651426a392ebbda1e38bda8c61f84d23619acc84c23482c366aa93172e0e69d0db6cec3a0117a8b29b469cfb4867640c19cde672f97b8e0a898721fdfcf81d2@127.0.0.1:0","enr":"0xf88fb840b963eedc19e55fea385cb79ba3edb722a5c9cd6b3837cae1b8b5bd42752a174a1fe5c8c3e1f1317f3f7dbc12ea24d98f7f8c47251ada9f5f7e2ef957f22a4d880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027651426a392ebbda1e38bda8c61f84d23619acc84c23482c366aa93172e0e69d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rwLC9HHparje+9IpIVaVuV5k98eLFFtnk6I4lh9Vb78=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: af02c2\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1049 7d16 5ff0 56ca | 126 025d (0) 035f (0) 0314 (0) 012b (0)\n001 4 c9c3 f645 f2b4 fa24 | 55 c42e (0) c534 (0) c74d (0) c603 (0)\n002 4 955d 9959 9b8e 8f9a | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 8 bfc7 be68 bea1 b8e1 | 14 bcf8 (0) bdc5 (0) bfc7 (0) be68 (0)\n004 7 a7a8 a742 a5ac a4ee | 13 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n005 5 a970 a8b5 a8ff a8f4 | 7 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n============ DEPTH: 6 ==========================================\n006 1 acee | 1 acee (0)\n007 1 aeb4 | 1 aeb4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","private_key":"db442bd6d5c398b9067accca6107d7b8e10ba8c679a04e038cbc5a31c15cb44a","name":"node_af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","services":["bzz","pss"],"enable_msg_events":true,"port":36073},"up":true}},{"node":{"info":{"id":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","name":"node_56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","enode":"enode://3977a7e2abfbb0b874ef30206cf7ae8dbd7ff49318570256ed3a8f50d5185bd2aa2c0a0b605e3b0983036e397760f8b6825426e1854b934902f881f1f2d5177b@127.0.0.1:0","enr":"0xf88fb840deafd8851984faee193023cc0f9b9afc4230fec5d8853a822d9f3af256ffd26c7c696165cdd9fa3bef3492bd9393b312bbb433aa86fcfbdf387c2e4d333607250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033977a7e2abfbb0b874ef30206cf7ae8dbd7ff49318570256ed3a8f50d5185bd2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Vsqd2Ealig/6e0moiq1VmjOLpTWm9zhGi48UbJeJDLI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 56ca9d\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f645 f2b4 af02 | 130 c74d (0) c603 (0) c6a8 (0) c42e (0)\n001 6 0e80 0e2b 1686 1049 | 65 025d (0) 0314 (0) 035f (0) 0111 (0)\n002 3 60c5 79e5 7d16 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 5 43c9 43d4 4d38 48de | 19 46bf (0) 44ad (0) 447a (0) 447c (0)\n004 5 5814 5ac0 5a8b 5d82 | 10 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n005 3 52a8 50c1 5144 | 3 52a8 (0) 5144 (0) 50c1 (0)\n============ DEPTH: 6 ==========================================\n006 1 5538 | 1 5538 (0)\n007 0 | 0\n008 1 5663 | 1 5663 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","private_key":"4b58bf70006ecc4c786de6a7e24d312dbe2dd18a5c61cd2255e343b02f20bb24","name":"node_56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","services":["bzz","pss"],"enable_msg_events":true,"port":33231},"up":true}},{"node":{"info":{"id":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","name":"node_26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","enode":"enode://d555fe464791f46530284107d275f268600ac4b18c0cd90ff85c6b7c0af0050a8b42cf6e631500f750737be9621ba85fbbaab4b8ecc7dcb0dbb7d4c3bf45c066@127.0.0.1:0","enr":"0xf88fb84073b57f889ad85e60f317292c360ebdf010410087fdcdfe33202d93acab67d7f515b57d160ff1e3f046026e03970154f616c655ad78ebf85a16d3534d07e64bd60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d555fe464791f46530284107d275f268600ac4b18c0cd90ff85c6b7c0af0050a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JqzDw3PCkVCvMLvJJk0MRMfGBv9zdzmd34RGNel6/Po=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26acc3\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 9f0e 8f9a a2e6 a4ee | 130 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n001 5 6d3c 60c5 7d16 5ac0 | 61 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n002 4 0e80 0e2b 1bd5 1049 | 37 012b (0) 0111 (0) 0191 (0) 025d (0)\n003 3 3980 32ff 3188 | 17 36b9 (0) 3728 (0) 3411 (0) 30fe (0)\n004 7 298a 2a50 2fd2 2e65 | 7 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 24f8 244c | 2 244c (0) 24f8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 26ab | 1 26ab (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","private_key":"4db62bb95214bf5041d1bcd4a73488fcdaaa5616fe4e911e2621181956f3deda","name":"node_26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","services":["bzz","pss"],"enable_msg_events":true,"port":35363},"up":true}},{"node":{"info":{"id":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","name":"node_fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","enode":"enode://5d3165b8480aceb9a29a4b61b3ab32269c0528b62f0c58315dec25b4567cffff0e9a6e0832a40f555b1f37d268bf1591a93b1fe8858c54d1c41b0786a5f82ed4@127.0.0.1:0","enr":"0xf88fb840384d6f2d0e7aeea7e17230d68adf6c986544d7e0ddb16a747f8ca2ff2e208b65632e299c8bcee387db034659bc60d6fe20be94eed139b54e1c33fea4f0b664c20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025d3165b8480aceb9a29a4b61b3ab32269c0528b62f0c58315dec25b4567cffff","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+iQEEbxPPkTfyj+u3REsd0Ome1IqkQvJlpbvCzFzLuI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fa2404\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 79e5 7d16 1049 2ddf | 126 648a (0) 67f3 (0) 6795 (0) 6790 (0)\n001 8 8f9a bbaf b8e1 b5ea | 75 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n002 6 d408 ddb8 d9cf c190 | 27 c603 (0) c6a8 (0) c74d (0) c534 (0)\n003 4 e0a0 ef99 eebd ec90 | 14 e471 (0) e681 (0) e64d (0) e2d3 (0)\n004 5 f756 f6c0 f645 f305 | 7 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n005 3 fc51 fc39 feb3 | 4 fc39 (0) fc51 (0) ff75 (0) feb3 (0)\n============ DEPTH: 6 ==========================================\n006 2 f8ff f9de | 2 f8ff (0) f9de (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","private_key":"211a1e252e6faf64120c7e80193de1fb9c8574e8839437085db6624c65afb2c3","name":"node_fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","services":["bzz","pss"],"enable_msg_events":true,"port":40123},"up":true}},{"node":{"info":{"id":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","name":"node_f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","enode":"enode://d7318bb4df307ed03251fed0ebc0b514ff6ce6b2953bfc2f41eebd1ed2cc03d3290b1abe8ac51e22661fa91f8cfcacc7e7bdb1405e5cac4cdbf56475483daa9b@127.0.0.1:0","enr":"0xf88fb840f435115eab43ea3daa96fcf671263bd99032cf92a48d2a4331d533663d34cd32064567c172c0bceb4e8160e59433053e1b2b558538748fbda084fd167120e7690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d7318bb4df307ed03251fed0ebc0b514ff6ce6b2953bfc2f41eebd1ed2cc03d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8rSaIkfJxej291WDSjf+XBfyCPmUh44UtwAeQE9S4SU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f2b49a\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 7d16 5ac0 56ca 2e65 | 126 0191 (0) 012b (0) 0111 (0) 0314 (0)\n001 10 9948 8f9a a742 a4ee | 75 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n002 7 cd6c c9c3 c190 d9cf | 27 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n003 2 e0a0 ec90 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 6 feb3 fc39 fc51 f8ff | 7 fc39 (0) fc51 (0) ff75 (0) feb3 (0)\n005 3 f756 f6c0 f645 | 3 f756 (0) f6c0 (0) f645 (0)\n006 1 f1ed | 1 f1ed (0)\n============ DEPTH: 7 ==========================================\n007 1 f305 | 1 f305 (0)\n008 1 f215 | 1 f215 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","private_key":"6f4c1a8084c43a09372f46f2d9c9d47e946032ad4494c25e53ab442810dfb7fc","name":"node_f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","services":["bzz","pss"],"enable_msg_events":true,"port":46219},"up":true}},{"node":{"info":{"id":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","name":"node_b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","enode":"enode://f2200c6d168fd4bf3f5ed5ac408ee95b95a35365e8c342dcfcba922300690d24ca30314c5d635505791f54e2deded324817ffe3129c898cb4a426adf595eb724@127.0.0.1:0","enr":"0xf88fb84021725022f3ac59f570e89280f9dd63209a73639e93974cd54845b965aa169be11392f71f7989121c8b9ba986bcb11b10faa14be90ddaa9ee8a129f76f3e33d360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f2200c6d168fd4bf3f5ed5ac408ee95b95a35365e8c342dcfcba922300690d24","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"teq0hptMtlvcHlyrRcAwFtIC+fW2aL5QBmRRz8+e8pk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5eab4\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1686 0e80 24f8 79e5 | 126 1fd0 (0) 1dec (0) 1dc0 (0) 18e0 (0)\n001 2 fa24 f2b4 | 55 c74d (0) c6a8 (0) c603 (0) c42e (0)\n002 3 9948 8e28 8f9a | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 5 af02 a4ee a742 a2e6 | 23 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n004 6 bfc7 be68 bea1 ba91 | 8 bdc5 (0) bcf8 (0) be68 (0) bea1 (0)\n005 1 b3f9 | 1 b3f9 (0)\n============ DEPTH: 6 ==========================================\n006 3 b78f b659 b6df | 3 b78f (0) b659 (0) b6df (0)\n007 1 b4a1 | 1 b4a1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","private_key":"481278a076dd22f579d2e3224ee46c4efb0adf98a25587e4047dbc41a531583d","name":"node_b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","services":["bzz","pss"],"enable_msg_events":true,"port":37951},"up":true}},{"node":{"info":{"id":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","name":"node_79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","enode":"enode://075d1af75650c9de403f935ba958bd36f2dcb4f54812a57032e064eacf6791b2fadabd15082534259be0de378b8ec19b5c5bece38fd2f85f6d61f696d4ac14e4@127.0.0.1:0","enr":"0xf88fb8403597b43e61519416d408305834e8a89ab71a0a61b3f4f053f11f5968299862341d5ec75769bbb4cf7480c8bef7b24e1b8e3aff66288460abd1ed368813e91d150183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102075d1af75650c9de403f935ba958bd36f2dcb4f54812a57032e064eacf6791b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eeXGxteMiMV5ADzaBEiC7LBFIPutH1/q2+e20j/hg8g=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 79e5c6\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fa24 8f9a a327 b5ea | 130 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n001 4 0e80 2fd2 2c80 2ddf | 65 1dc0 (0) 1dec (0) 1fd0 (0) 18e0 (0)\n002 7 482e 48de 43d4 43c9 | 35 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n003 4 60c5 68cb 6d3c 6dd3 | 13 648a (0) 6758 (0) 6790 (0) 6795 (0)\n004 2 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 5 7e47 7ce7 7c7c 7c46 | 5 7e47 (0) 7ce7 (0) 7c7c (0) 7c46 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 7850 7895 | 2 7895 (0) 7850 (0)\n008 1 7933 | 1 7933 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","private_key":"9457ffd6b462dc1c0231d33b4fb9815c915a5ece2c906083d0545bae269b1838","name":"node_79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","services":["bzz","pss"],"enable_msg_events":true,"port":44929},"up":true}},{"node":{"info":{"id":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","name":"node_8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","enode":"enode://0ba5f5e13ed3f24bcc90ac6187a06331385aa18072a6353970a149cb65da7f8408e3bd27fdc0f2d790ec7a2c5a4f5c645ef4a150cb4fdde987537a60c37142c0@127.0.0.1:0","enr":"0xf88fb8403e7501b357ca709034505ffc033677386293dabf95f8c427892c5366a7ae2e0f69e68bf5b49160bf671794419a71fdbdd1334e34f74f68f77575078e1e3c90f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020ba5f5e13ed3f24bcc90ac6187a06331385aa18072a6353970a149cb65da7f84","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"j5qizTPRjny0SU0Rp1Msl+tKHK4XKyFlwmrk7SSIfA0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8f9aa2\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 26ac 2ddf 5ac0 43d4 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 1add (0)\n001 7 d700 d9cf ddb8 fa24 | 55 da36 (0) dad0 (0) dbd4 (0) d959 (0)\n002 9 a8f4 af02 a2a1 a2e6 | 37 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n003 4 955d 9ca1 9959 9b8e | 17 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n004 3 8073 834f 837f | 12 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n005 2 8b43 8854 | 3 8b43 (0) 8862 (0) 8854 (0)\n006 2 8cc3 8d19 | 2 8cc3 (0) 8d19 (0)\n============ DEPTH: 7 ==========================================\n007 3 8ea2 8e7b 8e28 | 3 8ea2 (0) 8e7b (0) 8e28 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","private_key":"f83575bfe6442b53eb4d8c355e1200c4401c098583e660934bf9987f9300e6fc","name":"node_8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","services":["bzz","pss"],"enable_msg_events":true,"port":35903},"up":true}},{"node":{"info":{"id":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","name":"node_2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","enode":"enode://29e1ab89b8c45319b773556c3422348d68748120f103b1806eb3fa94fb57117771a4e9811a97855b4076957253cfda4e1d7e7d5548464708fa7ec7107eec12d5@127.0.0.1:0","enr":"0xf88fb840979111f3046ade721c9e294e8d0656436a86fbc0cf8b2838b30c39d61a12386f5d18e6f92931a25b2b78f7286b8d8ba013719c6b55a32cb5f035f4668f5a38310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329e1ab89b8c45319b773556c3422348d68748120f103b1806eb3fa94fb571177","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Ld/92/RS8MkmgFinOfV1f7kCgcv9Mb1vdgrMM5L+wSo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2ddffd\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fa24 f2b4 bbaf 8f9a | 130 da36 (0) dad0 (0) dbd4 (0) d959 (0)\n001 3 5ff0 6dd3 79e5 | 61 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n002 5 1686 1049 07f5 0e2b | 37 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n003 4 3980 3411 3188 32ff | 17 36b9 (0) 3728 (0) 3411 (0) 30fe (0)\n004 3 244c 24f8 26ac | 4 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n006 2 2e65 2fd2 | 2 2fd2 (0) 2e65 (0)\n============ DEPTH: 7 ==========================================\n007 2 2c85 2c80 | 2 2c85 (0) 2c80 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","private_key":"3c16c760b1da414e3f0702e51bb7b991c9f8f24d6780298e7f1c4a2211e65148","name":"node_2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","services":["bzz","pss"],"enable_msg_events":true,"port":37059},"up":true}},{"node":{"info":{"id":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","name":"node_bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","enode":"enode://f7560694a563f7b8b45223d669cb0c3bb40c7d6d3c2c7a02edb265933a0cea0746f94f112043dd9614675b71e6aabda899b082aa80ce92a1c4bc2815f48d70ca@127.0.0.1:0","enr":"0xf88fb840dc4fa4b1749e43011079de3d46e7621a199adbd688f08a6430dac3a3a5a968d64ffad4738b308452154a2d6bbf4d88aea49250c65e68297d8e084c6992e98c910183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f7560694a563f7b8b45223d669cb0c3bb40c7d6d3c2c7a02edb265933a0cea07","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"u6+sW6WRXbPIDiiyScrSYLm12tH3KAY8SPqPYddVbhc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bbafac\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5ac0 6dd3 2ddf | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 4 ec90 fa24 feb3 f2b4 | 55 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n002 5 955d 9f7d 9b8e 8e28 | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 6 af02 a4ee a742 a2a1 | 23 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n004 5 b3f9 b6df b78f b4a1 | 6 b3f9 (0) b78f (0) b659 (0) b6df (0)\n005 5 bdc5 bcf8 bfc7 be68 | 5 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n============ DEPTH: 6 ==========================================\n006 1 b8e1 | 1 b8e1 (0)\n007 1 ba91 | 1 ba91 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","private_key":"92e3be78001b291633af182ae0eaa04e18135ff78f3f44ea1807ade09e09f9c4","name":"node_bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","services":["bzz","pss"],"enable_msg_events":true,"port":34263},"up":true}},{"node":{"info":{"id":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","name":"node_a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","enode":"enode://095fd8d08d7c8f838e4b0a8ae5d5dbc252f1f8fa2f4909b00c4e1a76abd7e97f55201ffac074124ec2de620f242c33f3a5a6716f0105311320328bfb71b37613@127.0.0.1:0","enr":"0xf88fb84023807c617fe27431d11170d14386c718cb44cc0bc380888e41340bc3a6b2fed73035c05d36ab2f0c51da29e46bd4188c4e1a10d987249dad7fa69d4e4a2ee2d70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103095fd8d08d7c8f838e4b0a8ae5d5dbc252f1f8fa2f4909b00c4e1a76abd7e97f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oydJ3E4TSk+7A4YYxYp8Bbu6oG8UNt43VDQa+GQCWBs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a32749\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2e65 43d4 79e5 6dd3 | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 6 d9cf c9c3 c190 f1ed | 55 c74d (0) c603 (0) c6a8 (0) c534 (0)\n002 5 9b8e 9959 9f7d 9ca1 | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 4 b4a1 b5ea b8e1 bbaf | 14 b3f9 (0) b78f (0) b659 (0) b6df (0)\n004 4 af02 a8ff a8f4 ab3f | 10 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n005 5 a5ac a505 a4ee a7a8 | 7 a505 (0) a5ac (0) a4ee (0) a616 (0)\n006 2 a0c8 a1c8 | 2 a0c8 (0) a1c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a2a1 a2e6 | 2 a2a1 (0) a2e6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a330 | 1 a330 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","private_key":"abf141d0f41d519d2f0bcfd4e1cab0e3d3b7f49bb2524ddfbcb4ed8087b83b39","name":"node_a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","services":["bzz","pss"],"enable_msg_events":true,"port":42795},"up":true}},{"node":{"info":{"id":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","name":"node_b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","enode":"enode://f04605b84e637cfebd8976e50b34cb2677a4314ffad3de5f827b256c5789bc9395bca075fdc7d093933f7a36b0086da67b41726ecd01f12473dc86a64d648d30@127.0.0.1:0","enr":"0xf88fb8407a74507655e5e4bccef3b4f4be2094d2dfa1f734606fc6fea7a7d5534117bdd212b9fbbc1b5190a3217e08c13dc5b1d5e33d16540dd469bccff2b61d00f169380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f04605b84e637cfebd8976e50b34cb2677a4314ffad3de5f827b256c5789bc93","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uOGoYiwlbvKazVLfezrOUIIPsaFHcWFl/4Yv3Jc6SM0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8e1a8\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6d3c 68cb 0e80 24f8 | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 9 d700 d408 ddb8 d9cf | 55 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n002 5 9948 955d 8d19 8e28 | 38 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n003 9 af02 a8ff a505 a7a8 | 23 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n004 5 b3f9 b78f b6df b4a1 | 6 b3f9 (0) b78f (0) b659 (0) b6df (0)\n005 5 bcf8 bdc5 bfc7 be68 | 5 bcf8 (0) bdc5 (0) bfc7 (0) be68 (0)\n============ DEPTH: 6 ==========================================\n006 2 ba91 bbaf | 2 ba91 (0) bbaf (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","private_key":"16e0a5b28dd4eef0429cfee2457fefee326e70769d72a08220c987d895948535","name":"node_b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","services":["bzz","pss"],"enable_msg_events":true,"port":34709},"up":true}},{"node":{"info":{"id":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","name":"node_2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","enode":"enode://691ca9c06e10ad9e54772ff48bc4ae919f121bdc7c6ae4b100351ac29f5b9c0067cd758acd4b0e25f67dfa21718cc34aeffd02b40dff4f52ff37acbd00fd7501@127.0.0.1:0","enr":"0xf88fb8406bb758fd0d287e48c99c72280182a42c8e1fff4b42972876eb7d7d79532702475aa04a531f8efafd3652264038cd3910f2da1b312b91e88345a53b2ff877cc8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103691ca9c06e10ad9e54772ff48bc4ae919f121bdc7c6ae4b100351ac29f5b9c00","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LIBCUX3+qgFYbpHkkd1BVPskwNhP7bBAS51RNvYNodk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c8042\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c534 f2b4 9f0e a742 | 130 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n001 5 56ca 43d4 68cb 6dd3 | 61 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n002 5 1686 1049 07f5 0e2b | 37 1dc0 (0) 1dec (0) 1fd0 (0) 18e0 (0)\n003 3 3411 32ff 3980 | 17 36b9 (0) 3728 (0) 3411 (0) 30fe (0)\n004 4 24f8 244c 26ab 26ac | 4 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n006 2 2fd2 2e65 | 2 2fd2 (0) 2e65 (0)\n============ DEPTH: 7 ==========================================\n007 1 2ddf | 1 2ddf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 2c85 | 1 2c85 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","private_key":"c3f87c0c78bb12a86da6ad7d36c7291a3895a98586e6e8e099b279f077ffd478","name":"node_2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","services":["bzz","pss"],"enable_msg_events":true,"port":41807},"up":true}},{"node":{"info":{"id":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","name":"node_a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","enode":"enode://1f3ff2039504020c5625d4fbe5c447e27cfb3016aa9ec0e1837d44eaa2fe4172b2731d4ff02a80394e7e3d0f4a32f19cc239a3972f10eab45bf2c69d9d8c65ee@127.0.0.1:0","enr":"0xf88fb840f01697c24bc9fee368002b25d4480ee743229f9cbdc31dbaa122bca564f7c45b35b737cd14a1258f4e4eaded287d70183cc0d4584cd0b1cba3a7f55096fa87a30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f3ff2039504020c5625d4fbe5c447e27cfb3016aa9ec0e1837d44eaa2fe4172","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p0LoUCxhlwPOh4kBEPkIveMrWdxh13okd1nl0AVuDJQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a742e8\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 43d4 1070 0e80 2c80 | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 4 ec90 f2b4 f645 feb3 | 55 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n002 3 9c21 8e28 8f9a | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 5 b4a1 b5ea bfc7 b8e1 | 14 b3f9 (0) b78f (0) b659 (0) b6df (0)\n004 4 a8b5 a8f4 a8ff af02 | 10 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n005 4 a1c8 a2a1 a2e6 a327 | 6 a0c8 (0) a1c8 (0) a2a1 (0) a2e6 (0)\n006 3 a505 a5ac a4ee | 3 a505 (0) a5ac (0) a4ee (0)\n============ DEPTH: 7 ==========================================\n007 2 a616 a606 | 2 a616 (0) a606 (0)\n008 1 a7a8 | 1 a7a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","private_key":"6f1c95c10b82cf6a4a6a6ffba536b6e4d17dca7e822de4e3b740149684932d39","name":"node_a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","services":["bzz","pss"],"enable_msg_events":true,"port":37625},"up":true}},{"node":{"info":{"id":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","name":"node_feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","enode":"enode://27ac651910b9394ef60deb8ececf68b82b3f2bff98cf45cc6dab2a0a0a271bf8f5cd18af48ec4a9eb79821487687a0dfb97af07de26b237f0194f1d1c84587f1@127.0.0.1:0","enr":"0xf88fb840dff98a9839c85f4ca1a944e19e2913b5a74f45e9701a6d6887f3b6fbdeb63db6104a51388fa37505749037788d83e0ed7d3dc9f9f37d696abb5aab32f13633200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10327ac651910b9394ef60deb8ececf68b82b3f2bff98cf45cc6dab2a0a0a271bf8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/rO8F+5zaaT6mInZJQ/tPBJXxwkWhxmW5uq9N03Y3C4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: feb3bc\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2e65 43d4 68cb 6dd3 | 126 1dc0 (0) 1dec (0) 1fd0 (0) 18e0 (0)\n001 5 8f9a bbaf b8e1 a8f4 | 75 9948 (0) 9959 (0) 9b8e (0) 9ec8 (0)\n002 5 c9c3 c190 ddb8 d700 | 27 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n003 3 ec90 e471 e0a0 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 5 f1ed f2b4 f756 f645 | 7 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n005 2 f9de fa24 | 3 f8ff (0) f9de (0) fa24 (0)\n============ DEPTH: 6 ==========================================\n006 2 fc39 fc51 | 2 fc51 (0) fc39 (0)\n007 1 ff75 | 1 ff75 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","private_key":"0612d46e6c5fe2d816f3fcc01eea18407ea659f41290d153e08a780a5313e54c","name":"node_feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","services":["bzz","pss"],"enable_msg_events":true,"port":36801},"up":true}},{"node":{"info":{"id":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","name":"node_6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","enode":"enode://33d552be8155690e7cbe2739fa74ca6e83ead5035cd9a8e26d187ef54b14ca924e3d5485f7bb095dc233d74758321997fe1ae52b5ce5dc070eb0589816b09442@127.0.0.1:0","enr":"0xf88fb8409b453570d61397d255334db062ee118d6af0cc79fd50cda1bb3830f187d56f506eaa18ca5d6dc753b0cf201bfe1614f777a497a0713d90ed07b3bf9f76920e7c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10233d552be8155690e7cbe2739fa74ca6e83ead5035cd9a8e26d187ef54b14ca92","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bdOsD9mgSiznWHXGg9E15S6qFnDLVeeHEWIHEuYP3kc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6dd3ac\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 8f9a bbaf a8f4 a327 | 130 9948 (0) 9959 (0) 9b8e (0) 9ec8 (0)\n001 4 0e80 2ddf 2c80 2e65 | 65 1fd0 (0) 1dec (0) 1dc0 (0) 18e0 (0)\n002 6 5663 5814 5ff0 5d82 | 35 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n003 4 70f6 7d16 7850 79e5 | 13 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n004 3 6758 67f3 60c5 | 6 648a (0) 6758 (0) 6790 (0) 6795 (0)\n005 2 6b4e 68cb | 2 6b4e (0) 68cb (0)\n006 1 6e7f | 1 6e7f (0)\n007 1 6c01 | 1 6c01 (0)\n============ DEPTH: 8 ==========================================\n008 2 6d3c 6d5e | 2 6d5e (0) 6d3c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","private_key":"798b1133c83f1bd8708da776e24e1068611422abe705d8209d07e88f4ae07873","name":"node_6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","services":["bzz","pss"],"enable_msg_events":true,"port":35411},"up":true}},{"node":{"info":{"id":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","name":"node_2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","enode":"enode://224027d2af542674e07dc64ec477cb324c9288d5b917bd302a8b994fb56effd5d4134f71de9dbe75d043d510c3df39b87f5590dd5e53d1512969e65bfc9debad@127.0.0.1:0","enr":"0xf88fb840cfb76c5419d68cf2f3a24256e9324a22f66fc4b5580a187070e857ba42d18a8921c69ca44e1570e72d7281e2ef3c9c2604a2ca5089bb11f8142664ad4552a2970183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103224027d2af542674e07dc64ec477cb324c9288d5b917bd302a8b994fb56effd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LmXQVki3mPr7ybtYLAXm+PiRExJg6MkMpyXdy8gj8xU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2e65d0\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ec90 f2b4 feb3 955d | 130 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n001 2 43d4 6dd3 | 61 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n002 6 0e80 19ea 1b1d 1070 | 37 1484 (0) 140d (0) 1784 (0) 1686 (0)\n003 5 3980 397a 3411 3188 | 17 3f31 (0) 3c5b (0) 3cab (0) 3a62 (0)\n004 4 26ab 26ac 244c 24f8 | 4 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n============ DEPTH: 6 ==========================================\n006 3 2ddf 2c85 2c80 | 3 2ddf (0) 2c85 (0) 2c80 (0)\n007 1 2fd2 | 1 2fd2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","private_key":"2b229760916c74b6ac5f23ef8180077064de49ec26982a14a09a3d1382e474b0","name":"node_2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","services":["bzz","pss"],"enable_msg_events":true,"port":34851},"up":true}},{"node":{"info":{"id":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","name":"node_43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","enode":"enode://e7390b07e9257a295e97c15d41b54e09e2dcdfc3b9fc73b2b0f2e63a0713c9ded792f3a5ee9d6938d4f429c961b091715297661b560bac8df0449449c96346f6@127.0.0.1:0","enr":"0xf88fb8406a94ea3a25ea5935505a1d5b3df6880b4b51723a453f3fe497c93e6dddf6efed7794b6528b6c6e10790083a3893217933ff7b93745ca7a04b03e78564462c9fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e7390b07e9257a295e97c15d41b54e09e2dcdfc3b9fc73b2b0f2e63a0713c9de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Q9Q+nry860gw/B0tUCRlC5Bpgwa70sTQtIQaGo/QnJM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 43d43e\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 c190 ec90 feb3 955d | 130 da36 (0) dad0 (0) dbd4 (0) d959 (0)\n001 4 0e80 32ff 2c80 2e65 | 65 1dec (0) 1dc0 (0) 1fd0 (0) 18e0 (0)\n002 6 79e5 7895 7d16 6d3c | 26 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n003 6 5663 56ca 5ff0 5d82 | 16 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n004 4 4cec 4d38 482e 48de | 10 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n005 4 46bf 447c 447a 44ad | 4 46bf (0) 447a (0) 447c (0) 44ad (0)\n006 2 4005 402c | 2 4005 (0) 402c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 435d | 1 435d (0)\n009 0 | 0\n010 0 | 0\n011 1 43c9 | 1 43c9 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","private_key":"705846d6103b8dcde5526942f8da6f2206687604c468de841c1e3556e63e27f4","name":"node_43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","services":["bzz","pss"],"enable_msg_events":true,"port":33285},"up":true}},{"node":{"info":{"id":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","name":"node_68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","enode":"enode://a3d519e4a1788400163f2db9a838b8229a5d176f4b32736cc11d48510f60bfd57fe2b36b773121bed96bb701a34a777b9b0f9f0a6210a11a5267db32c5709c20@127.0.0.1:0","enr":"0xf88fb840b867c36933c9555cfb4f20df50e1fa2d1c86295c58b5348694874b92dcc369053ef0b25782dc4f892f9a7d6250dd1c42582a0f9a87ced83db2af67d0d5459e660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a3d519e4a1788400163f2db9a838b8229a5d176f4b32736cc11d48510f60bfd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aMvEpTEwgNXcqK006L9SphROD/jvP3ldeunV9kT+IEI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 68cbc4\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 c190 feb3 ec90 b4a1 | 130 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n001 5 3411 2c80 24f8 19ea | 65 3cab (0) 3c5b (0) 3f31 (0) 3a62 (0)\n002 6 5663 5ff0 5814 482e | 35 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n003 5 70f6 79e5 7850 7895 | 13 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n004 2 67f3 60c5 | 6 648a (0) 6758 (0) 6795 (0) 6790 (0)\n============ DEPTH: 5 ==========================================\n005 5 6e7f 6c01 6dd3 6d5e | 5 6e7f (0) 6c01 (0) 6dd3 (0) 6d5e (0)\n006 1 6b4e | 1 6b4e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","private_key":"8dc0ff9e95b0b85f24142f1082c900c64588c269a697412aabd41e4d80197de9","name":"node_68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","services":["bzz","pss"],"enable_msg_events":true,"port":37375},"up":true}},{"node":{"info":{"id":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","name":"node_6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","enode":"enode://39291783101f95a5ab0c6a5d372ab36be799b2f4dd241206519e00c6df4c01d16736ddcf75349c2fa7ee23395b536b4d60d40863664b2d9b15bcdf13a384856b@127.0.0.1:0","enr":"0xf88fb840c8714570044e40edeb9d032662ba2bdcc24c79d2f85ca264d6e7ca490de884235fccc9d43de5859321525bb25b2ed942d3dbfa2f72686bd09b8cad40b7d56cd70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10339291783101f95a5ab0c6a5d372ab36be799b2f4dd241206519e00c6df4c01d1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bTxtsVkA8llihvgcwGZNLIKR6tW60qo1utUVrwiKLkg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6d3c6d\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c190 a8f4 b6df b8e1 | 130 b3f9 (0) b78f (0) b659 (0) b6df (0)\n001 6 3411 26ac 244c 24f8 | 65 3cab (0) 3c5b (0) 3f31 (0) 3b02 (0)\n002 6 5663 5ff0 5ac0 5814 | 35 5c7c (0) 5c37 (0) 5d82 (0) 5ff0 (0)\n003 5 70f6 7d16 7c7c 7895 | 13 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n004 2 6795 60c5 | 6 648a (0) 6758 (0) 67f3 (0) 6790 (0)\n005 2 6b4e 68cb | 2 6b4e (0) 68cb (0)\n006 1 6e7f | 1 6e7f (0)\n007 1 6c01 | 1 6c01 (0)\n============ DEPTH: 8 ==========================================\n008 1 6dd3 | 1 6dd3 (0)\n009 1 6d5e | 1 6d5e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","private_key":"ae7658c745f0e65d13c11825a7164cb7336cc227bb4141dcb4f7a1b69abc8607","name":"node_6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","services":["bzz","pss"],"enable_msg_events":true,"port":46873},"up":true}},{"node":{"info":{"id":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","name":"node_0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","enode":"enode://4c66fe3197799ae8e8b7a9dc282966e1308115243346f02df98a818894f45783aeee959acc426df923f934b3a0948ab96460014c21435cd2a72745cc03f31986@127.0.0.1:0","enr":"0xf88fb840e699bbd1a5ea6afb58628146badd23319b3b2b6ed1e3cfa33efa77d040ac18f34f2d5aa2dba515d6d196f3414f3cfc8cb70045a92f88c46fad4bd4fef1bebd4f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c66fe3197799ae8e8b7a9dc282966e1308115243346f02df98a818894f45783","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DoDbnfqM4pvt+y3gMWIr74gpvuUncTIran77R6/lQOc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e80db\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 b8e1 b5ea b4a1 a8f4 | 130 bfc7 (0) be68 (0) bea1 (0) bdc5 (0)\n001 7 56ca 5ac0 43d4 79e5 | 61 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n002 9 3411 32ff 2e65 2fd2 | 28 3c5b (0) 3cab (0) 3f31 (0) 3b02 (0)\n003 5 19ea 1b1d 1686 1049 | 16 140d (0) 1484 (0) 1784 (0) 1686 (0)\n004 2 046c 07f5 | 10 035f (0) 0314 (0) 025d (0) 0191 (0)\n005 4 08f8 09b3 096a 0942 | 6 08bd (0) 08e5 (0) 08f8 (0) 09b3 (0)\n006 2 0cfc 0d1c | 2 0cfc (0) 0d1c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 0e3b 0e2b | 2 0e3b (0) 0e2b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","private_key":"b9190dcff292030b590acbf97d108aa5e5bdf506556ea496845cee35fdb941c6","name":"node_0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","services":["bzz","pss"],"enable_msg_events":true,"port":36041},"up":true}},{"node":{"info":{"id":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","name":"node_24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","enode":"enode://29812550052d6b16cc2b04fc247361209269007589ab11e66a4dc0928b09a158d46c84eb42f8150e45dc8a1507a2474372b311b26f743eeb615a36094d404313@127.0.0.1:0","enr":"0xf88fb840ea7a6a8262fab073a6840a7ee18670e090fea60cf597a27d2832802826b0a8f068c3ca88013d64b5ff02ccb4f2ff094c590329d9a24cf9a3d7856c6b6fd676070183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329812550052d6b16cc2b04fc247361209269007589ab11e66a4dc0928b09a158","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JPgMQ3vkWJjllPghu6D1xi4MmgxyARjjYu5veEEGEr0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 24f80c\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b8e1 b5ea b4a1 b6df | 130 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n001 2 68cb 6d3c | 61 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n002 5 1b1d 19ea 1049 1070 | 37 1484 (0) 140d (0) 1784 (0) 1686 (0)\n003 3 3980 3938 32ff | 17 3f31 (0) 3c5b (0) 3cab (0) 3b02 (0)\n004 7 2a50 298a 2c80 2c85 | 7 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 26ac 26ab | 2 26ab (0) 26ac (0)\n007 0 | 0\n008 1 244c | 1 244c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","private_key":"bd42db9dab0f618eb6ccbe9be985031a20cc1daa8157a90861ddd93c290047ab","name":"node_24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","services":["bzz","pss"],"enable_msg_events":true,"port":37751},"up":true}},{"node":{"info":{"id":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","name":"node_ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","enode":"enode://1afe1c8bb1a13bc5bc8ab9528f323597de5d3c7322397d611f7cfdee80cabaa6ee95222a551a9bfd627f595472bb227327a045306c75a25b75eb5d6240eb7b54@127.0.0.1:0","enr":"0xf88fb840a2ce29495c237a1d985a2865cbcacf2d5d3e6332f63ebbf01a8beeac0e5e2621504b30da39c19b73bc3cf1135905ab7c6fe71b1e90fc05dfd1fceea7ec3269ff0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021afe1c8bb1a13bc5bc8ab9528f323597de5d3c7322397d611f7cfdee80cabaa6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7JCiL0HuZZ1XWaSXlGrCmRyRbwD+fK7usJCPOvH+YLY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec90a2\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 43d4 68cb 0e80 2e65 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 10 b78f b8e1 bbaf ab3f | 75 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n002 5 ddb8 d408 d700 c9c3 | 27 d959 (0) d9cf (0) dbd4 (0) da36 (0)\n003 9 feb3 fc51 fc39 fa24 | 14 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n004 4 e471 e2d3 e09f e0a0 | 7 e471 (0) e64d (0) e681 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n============ DEPTH: 6 ==========================================\n006 3 eebd eff2 ef99 | 3 eebd (0) eff2 (0) ef99 (0)\n007 1 ed42 | 1 ed42 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","private_key":"89981ff407aefd00840d1b348382e6571fe033d8e0e93bdacff8d74ac1fbb465","name":"node_ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","services":["bzz","pss"],"enable_msg_events":true,"port":42753},"up":true}},{"node":{"info":{"id":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","name":"node_955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","enode":"enode://28ce8e8bd283c85d928eff07eb1fe95320e63ffecaeba76699cc6559b4e724ebab2f08fc20a3569022d9a14c0dc992ce97cb38b8031a6c170594ff80c0360a59@127.0.0.1:0","enr":"0xf88fb840599bae7bc68a1be369da49e6e4fc452277e838db6b140b288b1443accdfc5e7b68e44b4d5cf9c33cdbc1d0c7088b756639d98e9a4c055ee7589c982e720a68a30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10328ce8e8bd283c85d928eff07eb1fe95320e63ffecaeba76699cc6559b4e724eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lV2hXtrlCkxovIxXm5eZ1V9Bt8KmF49kX3nXcuARZmI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 955da1\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2e65 0e80 43d4 6d3c | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 2 c190 ec90 | 55 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n002 4 bbaf b8e1 af02 a8f4 | 37 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n003 4 8e28 8f9a 8d19 8073 | 21 8b43 (0) 8862 (0) 8854 (0) 8ea2 (0)\n004 8 9948 9959 9b8e 9ec8 | 9 9959 (0) 9948 (0) 9b8e (0) 9ec8 (0)\n005 3 9257 93c0 93ea | 3 9257 (0) 93c0 (0) 93ea (0)\n006 1 97da | 1 97da (0)\n007 1 9464 | 1 9464 (0)\n============ DEPTH: 8 ==========================================\n008 1 95c0 | 1 95c0 (0)\n009 1 9518 | 1 9518 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","private_key":"37f0dfbc4bcabf9e11ec2090cd8fd558bd7784630fdac652e65e0e56e11fff47","name":"node_955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","services":["bzz","pss"],"enable_msg_events":true,"port":46557},"up":true}},{"node":{"info":{"id":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","name":"node_a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","enode":"enode://a387b1ae7d38f1e3bb1576e26b97a6f5bf1fc147160a59dd43b8184b0c23dde70d006b3e046f727c0d3d185db250fb1796d0c8c4a63921c8fa4fda6ec1feea1c@127.0.0.1:0","enr":"0xf88fb840f2d8228ae427fc1b5347e72a85e3f6fb50398b45a626c6521c677d449daa7f9f1f0b921ba8b3e600829957e2a3cfc8d98234f8a6d8395d56172c1c0c4c8855ea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a387b1ae7d38f1e3bb1576e26b97a6f5bf1fc147160a59dd43b8184b0c23dde7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qPSehxVv2lUQiXYBaJzpaNdwMhNMUjY0kWuW3hY2b54=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a8f49e\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0e80 1070 43d4 43c9 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 6 f1ed fa24 fc51 fc39 | 55 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n002 6 8d19 8f9a 8ea2 8e28 | 38 8862 (0) 8854 (0) 8b43 (0) 8ea2 (0)\n003 2 bea1 b6df | 14 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n004 6 a2e6 a2a1 a327 a1c8 | 13 a505 (0) a5ac (0) a4ee (0) a616 (0)\n005 2 aeb4 af02 | 3 acee (0) aeb4 (0) af02 (0)\n006 3 aaf0 ab71 ab3f | 3 aaf0 (0) ab71 (0) ab3f (0)\n007 1 a970 | 1 a970 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 a8b5 | 1 a8b5 (0)\n010 0 | 0\n011 0 | 0\n012 1 a8ff | 1 a8ff (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","private_key":"6bb6d8d705a40ba424923e49c1a5f2ea7ef65a8047cd69554f076497ad72abe8","name":"node_a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","services":["bzz","pss"],"enable_msg_events":true,"port":40983},"up":true}},{"node":{"info":{"id":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","name":"node_c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","enode":"enode://624fdcc04a4251fa0a5e452254deb09951e1c0e466046bb34ecfc5762881942842a1ad2ebe95d8a53fc13cf338b164aae811b96d19034914557485104f7cf8a6@127.0.0.1:0","enr":"0xf88fb840f541779d4363d2d110782b9208996593d8124c23e35c0c27c4a598881a445d896199da564f83d98e0d70a24b31b5995b979add943d98a2e3d0ede83d689bc0ad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102624fdcc04a4251fa0a5e452254deb09951e1c0e466046bb34ecfc57628819428","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wZD50Ix47W3/ra7zbnf+aqlgmeRFN1Owz8jsVC+pa50=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c190f9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5814 43d4 6d3c 68cb | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 7 9f7d 9ca1 955d 8073 | 75 8b43 (0) 8854 (0) 8862 (0) 8ea2 (0)\n002 7 f645 f2b4 fa24 feb3 | 28 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n003 3 dad0 ddb8 d700 | 11 d959 (0) d9cf (0) dbd4 (0) da36 (0)\n004 3 cf52 c8ea c9c3 | 8 cc33 (0) cd6c (0) cdb1 (0) cf52 (0)\n005 4 c603 c6a8 c534 c42e | 5 c74d (0) c603 (0) c6a8 (0) c534 (0)\n============ DEPTH: 6 ==========================================\n006 2 c2d0 c272 | 2 c2d0 (0) c272 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","private_key":"8e85cf18cf9dd5c75878ddc75b26b567c6f213cd9cf41387232103a423215444","name":"node_c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","services":["bzz","pss"],"enable_msg_events":true,"port":42929},"up":true}},{"node":{"info":{"id":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","name":"node_80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","enode":"enode://fdcec2678f4772897ed0eb0ec54b7de122c22cbf31b6e501c00adeed3d80cc14351e6a4ca7677d22fc7bbd94db0e3302cf20e7f55c554bd4dbaa0bd4e8a50a7f@127.0.0.1:0","enr":"0xf88fb84005c6d37ffbbfde5c741d546335ecf1ee87f1fb33af5875d0c84b3fb9dc87329f16d6370725423a847f1eebb7bd3a21a8fb3c43b99ef030a6cda4e1e144d69a280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fdcec2678f4772897ed0eb0ec54b7de122c22cbf31b6e501c00adeed3d80cc14","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gHNacocgu6CsCNqszQkzcNZyqPmlCEWteMzWz4aGw58=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 80735a\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 2fd2 5814 5663 43d4 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 2 d700 c190 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 5 a8ff a1c8 a327 a2e6 | 37 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n003 8 93c0 955d 9948 9b8e | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 5 8b43 8f9a 8ea2 8e28 | 9 8854 (0) 8862 (0) 8b43 (0) 8ea2 (0)\n005 2 87a3 86d6 | 4 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n006 3 837f 834f 8358 | 3 834f (0) 8358 (0) 837f (0)\n007 1 81a5 | 1 81a5 (0)\n008 1 80d7 | 1 80d7 (0)\n============ DEPTH: 9 ==========================================\n009 1 8006 | 1 8006 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 8074 | 1 8074 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","private_key":"8623a021033479cd7104a88188d9784ac5edeb95094c010547e615407d7a8973","name":"node_80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","services":["bzz","pss"],"enable_msg_events":true,"port":38855},"up":true}},{"node":{"info":{"id":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","name":"node_b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","enode":"enode://3057525034706ee1eee5958ad026f2f68f4bff18e95bec5db1e27e845df3c6b45b7a3d030786afab82b789cef41f9bc88bbb7c7238eb01ada275e9d294741643@127.0.0.1:0","enr":"0xf88fb84043499166c98cc953ba2a4b899aea5eba91503a235686406a2e5cc6f41156d01b6a9cfdab6cab3104c08d3b2fe340ea9b4504fde582847b46d2c4ebfc55e4639f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033057525034706ee1eee5958ad026f2f68f4bff18e95bec5db1e27e845df3c6b4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tKG2h/vbdU/WieJvCHCn3KtddhkMBvPqLqHhmPiqWrI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b4a1b6\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 68cb 43d4 43c9 0e80 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 4 f1ed f6c0 fc39 d700 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 2 8d19 8073 | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 4 a742 a7a8 a327 a1c8 | 23 a2e6 (0) a2a1 (0) a330 (0) a327 (0)\n004 5 b8e1 bbaf bdc5 bcf8 | 8 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n005 1 b3f9 | 1 b3f9 (0)\n============ DEPTH: 6 ==========================================\n006 3 b78f b659 b6df | 3 b78f (0) b659 (0) b6df (0)\n007 1 b5ea | 1 b5ea (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","private_key":"2db46fccdc01ed22afb3e789ea51e706f96e02424e2883893536ac8941043985","name":"node_b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","services":["bzz","pss"],"enable_msg_events":true,"port":34987},"up":true}},{"node":{"info":{"id":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","name":"node_b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","enode":"enode://83bcb3c68dcde737d01e64be91562e08aa6d62823cce64889fe81f01f05c9678015ec02c8c36bb8f83beee9587374da90118a76a98289f5ebad1436b19035bc4@127.0.0.1:0","enr":"0xf88fb8405bc0154529713773273db32f0ea11698b2fb42edf643c702fa47f05b032ad0b2780c5793a4018e529b014c867bee95c6af034725f784cc7f4742f2b9dc6d87d30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10283bcb3c68dcde737d01e64be91562e08aa6d62823cce64889fe81f01f05c9678","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tt/6xLTrKXTtDtJBeZ+X0uXZvmceMRJmgm0Nz+z8wgk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b6dffa\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 43d4 43c9 68cb 6d3c | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 3 e0a0 fc39 d700 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 2 9ca1 8d19 | 38 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n003 3 a7a8 af02 a8f4 | 23 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n004 5 bcf8 bfc7 bea1 bbaf | 8 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n005 1 b3f9 | 1 b3f9 (0)\n006 2 b5ea b4a1 | 2 b5ea (0) b4a1 (0)\n============ DEPTH: 7 ==========================================\n007 1 b78f | 1 b78f (0)\n008 1 b659 | 1 b659 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","private_key":"e24347072d11928511f53eef3f8e9a9734b3aaf2cb6205e653b42817451769b3","name":"node_b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","services":["bzz","pss"],"enable_msg_events":true,"port":46447},"up":true}},{"node":{"info":{"id":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","name":"node_d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","enode":"enode://410d63c57efb139f46850a8e0c7be2739099ace7e693848bb141c8cc7a9918f0ea1bb23bca1d292d38877c9fcd33d089ec39ba60ecfe1c8f10d5364e31196576@127.0.0.1:0","enr":"0xf88fb8408aa9045d36445a648a2d7468dfe7acea7f555e845341e000f782de3a667360ae2b494625fbc4c7ea45769984f4915b406d9241de31ef82d41bbeff3811d6d98f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102410d63c57efb139f46850a8e0c7be2739099ace7e693848bb141c8cc7a9918f0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1wDZbeEZNFbcC89JLHwRsJUQYpdK8vf0e4yQGxfCMWU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d700d9\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0e80 19ea 2fd2 24f8 | 126 140d (0) 1484 (0) 1784 (0) 1686 (0)\n001 9 9f7d 9ca1 8073 8f9a | 75 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n002 10 e0a0 ef99 ec90 feb3 | 28 e64d (0) e681 (0) e471 (0) e277 (0)\n003 10 c9c3 c8ea cf52 cc33 | 16 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n004 3 ddb8 dad0 d9cf | 6 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n============ DEPTH: 5 ==========================================\n005 3 d209 d3e9 d302 | 3 d209 (0) d3e9 (0) d302 (0)\n006 1 d408 | 1 d408 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","private_key":"44cd8419094d50e78afb097502f16dcd9c28368eb0ac43ce3b6312f58b6a3176","name":"node_d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","services":["bzz","pss"],"enable_msg_events":true,"port":43567},"up":true}},{"node":{"info":{"id":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","name":"node_43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","enode":"enode://7041f32dd06a878b138bbfefc65706d09feb4d20fa70fdaec9b5e107e0b78fb17e7e0e925ac8e1de69e03d8ab6005d250b3988c1c0911dadfd14e07849bd556e@127.0.0.1:0","enr":"0xf88fb840d7d0ed8828dbcb293891f06bd62c1a8f8be6e41e64cdfd8c701332e185ae09782876283f3a7fb0bd32333fddb3890bf3afbbda703a86a9e2189b5d08811c410f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027041f32dd06a878b138bbfefc65706d09feb4d20fa70fdaec9b5e107e0b78fb1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Q8nhVxxGDLn1mfqO153dD5w6If0vpFXgYDEJxVAS92s=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 43c9e1\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 b6df b4a1 a8f4 a1c8 | 130 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n001 2 244c 2fd2 | 65 012b (0) 0111 (0) 0191 (0) 025d (0)\n002 5 79e5 7895 68cb 6dd3 | 26 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n003 7 5ff0 5ac0 5814 50c1 | 16 5d82 (0) 5c7c (0) 5c37 (0) 5ff0 (0)\n004 3 4d38 48de 482e | 10 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n005 2 447c 447a | 4 46bf (0) 44ad (0) 447c (0) 447a (0)\n006 2 4005 402c | 2 4005 (0) 402c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 435d | 1 435d (0)\n009 0 | 0\n010 0 | 0\n011 1 43d4 | 1 43d4 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","private_key":"0be456eea926753ec7862f851dbd4b26ee5559316964d3411e6024e19a752138","name":"node_43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","services":["bzz","pss"],"enable_msg_events":true,"port":46243},"up":true}},{"node":{"info":{"id":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","name":"node_9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","enode":"enode://c9a8f470d438c9326b6d9e1f44bd2df3b9b4db56183efa7e23e2381f7499a94abcf1098ecf26221121fd113ea34eb8df3d183d5a3df359ebb5a93ef693f13923@127.0.0.1:0","enr":"0xf88fb840c1fa2933c23d1743f13988ec4d4c71a6d636eab7df047c52c265ea0086f72f550a1b2fd29579c42d2b4d7d3a9b2898b42b35ef897ebb203d6980bef0063402470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c9a8f470d438c9326b6d9e1f44bd2df3b9b4db56183efa7e23e2381f7499a94a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nKH9XUGXWsuQXzN5l5IoSbQHA2DkeEm7T9jNG53bTXM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ca1fd\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 046c 0942 244c 2fd2 | 126 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n001 5 d700 c190 ec90 f6c0 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 4 b6df a327 a1c8 a7a8 | 37 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n003 3 8073 8f9a 8d19 | 21 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n004 3 93ea 93c0 955d | 8 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n005 3 9959 9948 9b8e | 3 9948 (0) 9959 (0) 9b8e (0)\n006 3 9ec8 9f0e 9f7d | 3 9ec8 (0) 9f0e (0) 9f7d (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 9c21 | 1 9c21 (0)\n009 0 | 0\n010 1 9c8e | 1 9c8e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","private_key":"fbcd62592636cde3b1d26d9fd45dd2a45c8d1dfd4919ef05694e5c3a64330798","name":"node_9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","services":["bzz","pss"],"enable_msg_events":true,"port":39429},"up":true}},{"node":{"info":{"id":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","name":"node_8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","enode":"enode://222e619168c8502ad2677160abc513c09bfff4fc68adc96d2e7f0f7c4930abd567e863fe0472152a657c4ddd856612f5fb1dc02b056d9e8c1c159e098939dfe5@127.0.0.1:0","enr":"0xf88fb840930bf1a5288e587dffc9cebd12f017e5781d33ea16fe79da844003dba818a12e274142748fa13f0293ec802260c571d0052748b2d534197d123a968cfe5b46900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103222e619168c8502ad2677160abc513c09bfff4fc68adc96d2e7f0f7c4930abd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jRkrEVOActt1D3EgTi5q353AUI2cXPHrRX5OmWzZhbw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8d192b\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5814 2fd2 | 126 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n001 4 ec90 f6c0 fc39 d700 | 55 c8c8 (0) c8ea (0) c961 (0) c9c3 (0)\n002 6 a8f4 a1c8 bea1 b8e1 | 37 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n003 6 955d 9b8e 9ec8 9f7d | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 5 87a3 86d6 8358 837f | 12 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n005 3 8854 8862 8b43 | 3 8854 (0) 8862 (0) 8b43 (0)\n============ DEPTH: 6 ==========================================\n006 4 8ea2 8e28 8e7b 8f9a | 4 8ea2 (0) 8e7b (0) 8e28 (0) 8f9a (0)\n007 1 8cc3 | 1 8cc3 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","private_key":"edbbc3a484e366a33c8f6c00e9c02ac566737d8e91db651bc236921021651832","name":"node_8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","services":["bzz","pss"],"enable_msg_events":true,"port":42737},"up":true}},{"node":{"info":{"id":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","name":"node_2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","enode":"enode://d90aedfb65dd9e291e3c4407969177cc0003f7aeefea62a5fda7e78a2f8e57503ea0542d07a9ca08fc77b1c140394f0b96403ee29b9ef7e77220e8349d89d727@127.0.0.1:0","enr":"0xf88fb840fb7cf57abda6762cac6ad86cec07e3614162d910e4bfaac92260335eb590c78248534c6fb3f6579c4d43dda86da3aac0bf57486a520ce42420a4348d33eca50c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d90aedfb65dd9e291e3c4407969177cc0003f7aeefea62a5fda7e78a2f8e5750","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"L9L3fXbMpICsGOmvekYvKX2xaMM3CzvA4sBKoAbE0Dc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2fd2f7\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 d700 c534 c190 fc39 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 7 7895 79e5 7d16 7c46 | 61 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n002 5 046c 0e80 0942 1b1d | 37 08e5 (0) 08f8 (0) 08bd (0) 09b3 (0)\n003 4 3980 3938 3411 32ff | 17 3f31 (0) 3c5b (0) 3cab (0) 3b02 (0)\n004 4 26ab 26ac 24f8 244c | 4 26ab (0) 26ac (0) 24f8 (0) 244c (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n============ DEPTH: 6 ==========================================\n006 3 2ddf 2c85 2c80 | 3 2ddf (0) 2c85 (0) 2c80 (0)\n007 1 2e65 | 1 2e65 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","private_key":"7f01ef5d73b7a1621cf1a50134d0e446cde7c2685c35b818d64476d6cda01227","name":"node_2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","services":["bzz","pss"],"enable_msg_events":true,"port":32949},"up":true}},{"node":{"info":{"id":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","name":"node_f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","enode":"enode://ffc371f4f10ff50bcf4e7340bdc527dfcb0999c56a8ad077681dda0e5af313e62507524e2ff696ece4cb8eb97aac54f27d233260cb7ca5c4154e7afdfbdf96e5@127.0.0.1:0","enr":"0xf88fb84078e3e0d2b74bdd55983a052ed78591ee0915da8578fd5b0a91956d6b269bf3d81d3db48178b5eaee67ea280e6f5f0d246d756fc5abf350ae9397534bf91281da0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ffc371f4f10ff50bcf4e7340bdc527dfcb0999c56a8ad077681dda0e5af313e6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9sAo1qK2QI6QFpFR9FGbVh7Rg72JJe2aFwKAbzl2Zuc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f6c028\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7895 5814 43c9 244c | 126 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n001 4 8d19 9ca1 b4a1 a7a8 | 75 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n002 5 c272 c42e c534 cf52 | 27 c8c8 (0) c8ea (0) c961 (0) c9c3 (0)\n003 5 e2d3 e471 e681 ef99 | 14 e867 (0) eb68 (0) eebd (0) eff2 (0)\n004 4 fa24 fc39 fc51 feb3 | 7 f9de (0) f8ff (0) fa24 (0) ff75 (0)\n005 4 f1ed f215 f2b4 f305 | 4 f1ed (0) f215 (0) f2b4 (0) f305 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f756 | 1 f756 (0)\n008 1 f645 | 1 f645 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","private_key":"c2001db1b7540d6a72ed993e4a136476e6ca041a2240675f06b1a4e86e3424b0","name":"node_f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","services":["bzz","pss"],"enable_msg_events":true,"port":42857},"up":true}},{"node":{"info":{"id":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","name":"node_a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","enode":"enode://5e72e16dc757645afb111309a937a4366004991283411fd3c3d50c52778232ea7e7719d3cd0b1cc369bacf31c031b3a68472fd6fc03614d1986778f4e75140d9@127.0.0.1:0","enr":"0xf88fb840e8f42e427291a54799a4ef9798e106974722cc80a6cfd96431e683e82ca8ec92476544d118c7c93cde8d566d6bf48318fa85a0caa46c9abac29b1444055438090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035e72e16dc757645afb111309a937a4366004991283411fd3c3d50c52778232ea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p6hWpDKTqjAEhIqG8Yfgk0O9YF4ak+hTpva2sQMb1mc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a7a856\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1070 1b1d 244c 43c9 | 126 648a (0) 6758 (0) 67f3 (0) 6795 (0)\n001 3 fc39 f1ed f6c0 | 55 c8c8 (0) c8ea (0) c9c3 (0) c961 (0)\n002 2 9f7d 9ca1 | 38 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n003 6 b659 b6df b4a1 b8e1 | 14 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n004 4 af02 a8b5 a8ff a8f4 | 10 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n005 3 a327 a0c8 a1c8 | 6 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n006 3 a505 a5ac a4ee | 3 a505 (0) a5ac (0) a4ee (0)\n============ DEPTH: 7 ==========================================\n007 2 a616 a606 | 2 a616 (0) a606 (0)\n008 1 a742 | 1 a742 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","private_key":"aaadb3be16a7097261fed25f08f292e5be9b99c1bf3e70cdbb76066aa605151b","name":"node_a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","services":["bzz","pss"],"enable_msg_events":true,"port":43911},"up":true}},{"node":{"info":{"id":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","name":"node_fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","enode":"enode://afc7a62e260657fc0f72b68057c239d562dd553789cb3906dab521c2a0020c4d2e34f72e5c3b4bffc3c6d5a025ec22131d20c572b0667120bb9d6ff131368aa7@127.0.0.1:0","enr":"0xf88fb840b433a55822deba2cb67c49773ac6e9f6f916feeead46453ea70f7b6fb891e1b170b3ddf9a5f427aba0d47f36094e0bd0d8b00b31a2e816c4a06a6983e83e6c310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103afc7a62e260657fc0f72b68057c239d562dd553789cb3906dab521c2a0020c4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/DkROD90qYL2r4q5WmNCa1YRfUXxU7PBRBRZ2Rkdqv8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fc3911\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5814 1b1d 2fd2 244c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 9 8d19 9f7d 9ca1 b6df | 75 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n002 2 c190 d700 | 27 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n003 4 ec90 ef99 e471 e0a0 | 14 e867 (0) eb68 (0) eebd (0) eff2 (0)\n004 6 f1ed f2b4 f215 f305 | 7 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n005 2 f9de fa24 | 3 f8ff (0) f9de (0) fa24 (0)\n============ DEPTH: 6 ==========================================\n006 2 ff75 feb3 | 2 ff75 (0) feb3 (0)\n007 0 | 0\n008 0 | 0\n009 1 fc51 | 1 fc51 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","private_key":"0ab4f963705bd1ecac1ddfc070baf12e433c412c0dd7fda5ec1153e31f06d4c2","name":"node_fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","services":["bzz","pss"],"enable_msg_events":true,"port":33103},"up":true}},{"node":{"info":{"id":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","name":"node_a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","enode":"enode://62b2eb13717066427ba05db84603b330fb3b693d2bd1813d8e9a4c827fd48f746e425420802c437d4d617dacfe21133a47c98445bda61d435b1f1b25d3e430a4@127.0.0.1:0","enr":"0xf88fb8403d5ad691524cfb1b6da3dab6ee3570ad1ade29f4b42fcc3a0603f12596af26e82166d74d480e460f21c4f63ba82529d08d4089ffcb9667ab5f98b7ae05b09c6e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10262b2eb13717066427ba05db84603b330fb3b693d2bd1813d8e9a4c827fd48f74","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oche517bgHoB9M6TAIbJSJGKreMkdSYJsHjCiZHAToY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a1c85e\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 43c9 2fd2 244c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 5 c534 e0a0 f1ed f756 | 55 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n002 6 86d6 8073 8d19 9ca1 | 38 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n003 6 b659 b4a1 ba91 b8e1 | 14 ba91 (0) bbaf (0) b8e1 (0) bdc5 (0)\n004 2 a8b5 a8f4 | 10 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n005 6 a4ee a5ac a616 a606 | 7 a505 (0) a5ac (0) a4ee (0) a616 (0)\n============ DEPTH: 6 ==========================================\n006 4 a2e6 a2a1 a330 a327 | 4 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n007 1 a0c8 | 1 a0c8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","private_key":"2d5200058e0137ed16e823b77f132dec259ba1ba4237b3c7d64b6077dac98f24","name":"node_a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","services":["bzz","pss"],"enable_msg_events":true,"port":46031},"up":true}},{"node":{"info":{"id":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","name":"node_244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","enode":"enode://bc965245672290bb814412e8c14997e91efee12a0980a8ad30a49cafcdc350a149112bb4c07d92fa648bfb87d0e04b0d49dd5876fb503689dc29f894f9afc11c@127.0.0.1:0","enr":"0xf88fb8406db7bfa6b9d5aa889571c5a4bfcdcef571a6e1c7f1b13ae8bd42e882bdcb10f35429b014724321e75ef0725af408123a88b9fefcbf9cc4b8333c556d683067c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bc965245672290bb814412e8c14997e91efee12a0980a8ad30a49cafcdc350a1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JEw8lUrGEuUdSUWrm3fwtKOYMoXordeSF3fgxFob8zg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 244c3c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 cf52 c534 d700 e0a0 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 4 6d3c 7895 43c9 5814 | 61 648a (0) 6758 (0) 67f3 (0) 6790 (0)\n002 5 046c 0942 0e80 0d1c | 37 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n003 4 3938 32ff 30fe 3411 | 17 3f31 (0) 3cab (0) 3c5b (0) 3a62 (0)\n004 6 2a50 2ddf 2c85 2c80 | 7 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 26ac 26ab | 2 26ac (0) 26ab (0)\n007 0 | 0\n008 1 24f8 | 1 24f8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","private_key":"756bc2386944320552b690fdf2118ce4d2ebcec85975547ada771a0683526e39","name":"node_244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","services":["bzz","pss"],"enable_msg_events":true,"port":41177},"up":true}},{"node":{"info":{"id":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","name":"node_5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","enode":"enode://df45993237c885437698b9b42e4207115ff5f58aa44c86dec586013c408bddc56e44ca3c85a503ba4124ea6b825e510ca0c3aff8ffea771c186ddeec9282eaed@127.0.0.1:0","enr":"0xf88fb84046bd2bda155f5a7e7f14f680ffaef48b1222058233bac7457c919b20cd5bef383be59f22ce7613605070fe9bdca1f816c15e80c9c8b7c1c3b0b1928f383314d90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df45993237c885437698b9b42e4207115ff5f58aa44c86dec586013c408bddc5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WBS+E8hVC5pag9COevYCIAKo/ao4umwsML5YCZqfd0Q=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5814be\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 c190 f6c0 fc39 e0a0 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 4 0942 1b1d 1070 244c | 65 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n002 4 68cb 6dd3 6d3c 7895 | 26 648a (0) 6758 (0) 6795 (0) 6790 (0)\n003 3 482e 43d4 43c9 | 19 4cec (0) 4d38 (0) 4d91 (0) 4b79 (0)\n004 4 50c1 5663 56ca 5538 | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 4 5ff0 5d82 5c7c 5c37 | 4 5d82 (0) 5c7c (0) 5c37 (0) 5ff0 (0)\n============ DEPTH: 6 ==========================================\n006 4 5bd8 5a26 5a8b 5ac0 | 4 5bd8 (0) 5a26 (0) 5a8b (0) 5ac0 (0)\n007 1 5987 | 1 5987 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","private_key":"3272db2e0cc941ae4242b75d527d37070acfd72d8565878230b23cdd5ba9aeeb","name":"node_5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","services":["bzz","pss"],"enable_msg_events":true,"port":35259},"up":true}},{"node":{"info":{"id":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","name":"node_bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","enode":"enode://05327ec5fb8fa18f4d157d91b796c4d75a86f76159dd10ba2a14be7924a7fb58d20ea137bfea3f319d779b05c1297ecf50517ee627fc419c0fe82aa9dbab5ebe@127.0.0.1:0","enr":"0xf88fb840a5e1e04d2823e9b4c938872330f7c5e0576dbad0404136ef57aa33a3fbc8b59263359ab46fbf691c6df00e06b7f475636a04c60d62cb7ebb12e72d9f412b0d940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10205327ec5fb8fa18f4d157d91b796c4d75a86f76159dd10ba2a14be7924a7fb58","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vqEIaNXaUGwYAd6EXBSMLwl2GJMROskT/mZnSo9DwXg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bea108\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5663 5814 3411 1b1d | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 2 fc39 e0a0 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 2 8d19 9f7d | 38 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n003 5 af02 a8b5 a8f4 a7a8 | 23 acee (0) aeb4 (0) af02 (0) ab3f (0)\n004 5 b3f9 b5ea b4a1 b6df | 6 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n005 3 b8e1 ba91 bbaf | 3 bbaf (0) ba91 (0) b8e1 (0)\n006 2 bcf8 bdc5 | 2 bdc5 (0) bcf8 (0)\n============ DEPTH: 7 ==========================================\n007 1 bfc7 | 1 bfc7 (0)\n008 1 be68 | 1 be68 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","private_key":"d527efdb2ac85143b0e802a24844dd9c3aecc99bd77e0612baf6acb83decc3cf","name":"node_bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","services":["bzz","pss"],"enable_msg_events":true,"port":38981},"up":true}},{"node":{"info":{"id":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","name":"node_1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","enode":"enode://0b6b4bae7d34ebd01146d2c3912e36c6dc68c3fdcaeefb53789698c96d68142a7dea20ecc04141de176514183530bd52dd602fbb143e003f9629b58c12e5cc33@127.0.0.1:0","enr":"0xf88fb840bf5689088694d9e70533fcb09c6ce37880f92cc12326d6e446217bcc664b09e64f6cda48b1981c6bbc9c862fb2e06fd3946de83f4324bcca41a2650ee23899ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030b6b4bae7d34ebd01146d2c3912e36c6dc68c3fdcaeefb53789698c96d68142a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Gx3D+TEt8UGFXFRd0WruMl+aYJIw7GFlvbuwfQwIYvY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1b1dc3\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fc39 9f7d a7a8 bea1 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 3 7895 5663 5814 | 61 648a (0) 67f3 (0) 6795 (0) 6790 (0)\n002 6 3938 3980 2e65 2fd2 | 28 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n003 4 046c 0d1c 0e80 0942 | 21 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n004 3 1686 1070 1049 | 7 140d (0) 1484 (0) 1784 (0) 1686 (0)\n005 3 1fd0 1dec 1dc0 | 3 1fd0 (0) 1dec (0) 1dc0 (0)\n006 3 18e0 194e 19ea | 3 18e0 (0) 194e (0) 19ea (0)\n============ DEPTH: 7 ==========================================\n007 1 1add | 1 1add (0)\n008 1 1bd5 | 1 1bd5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","private_key":"c3aeeb9b4511f6c9ea3f8db8e4276b10196cc6c2a60e302f5bbb89b9ef64f347","name":"node_1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","services":["bzz","pss"],"enable_msg_events":true,"port":33901},"up":true}},{"node":{"info":{"id":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","name":"node_9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","enode":"enode://d362f99f7e00ec84f6ccd67dced7aa2e96e5dd50cddeaee8905cf072d71c8d723fc4781ace6da7e5e8b9730b793e53d447bf5d2b8fb2b8789fbef10c8068a46e@127.0.0.1:0","enr":"0xf88fb84077e35d00c12dc0bd099fd21289a49989ea8fd68a36842bb056f10263234ce083009f796590e6bbf22e4cc3d1763969b34838da241b9f68d571aa56d33299ee5c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d362f99f7e00ec84f6ccd67dced7aa2e96e5dd50cddeaee8905cf072d71c8d72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"n31yt9mEOHKQS4QeQhmFCCQo+6UBDbJ92HHtdmMKHh0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9f7d72\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7895 5663 3411 1b1d | 126 648a (0) 6758 (0) 67f3 (0) 6795 (0)\n001 4 c190 d700 fc39 e0a0 | 55 cc33 (0) cd6c (0) cdb1 (0) cf52 (0)\n002 7 b659 bbaf bcf8 bea1 | 37 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n003 2 8073 8d19 | 21 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n004 4 93c0 9464 9518 955d | 8 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n005 3 9b8e 9959 9948 | 3 9b8e (0) 9959 (0) 9948 (0)\n006 3 9c21 9c8e 9ca1 | 3 9c21 (0) 9c8e (0) 9ca1 (0)\n============ DEPTH: 7 ==========================================\n007 1 9ec8 | 1 9ec8 (0)\n008 0 | 0\n009 1 9f0e | 1 9f0e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","private_key":"f6395d3f2dfff6a01fa0f1143c3c6ba9b31b776fe6ae409050d911d23a137868","name":"node_9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","services":["bzz","pss"],"enable_msg_events":true,"port":37587},"up":true}},{"node":{"info":{"id":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","name":"node_e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","enode":"enode://422a22e066ae056507308bb1fecc971ca826bab52f6cb3b34b0589a2fc48a0408fdba15209748268cf34fac6bf4c209e24eda88a244a86828d194275ebe46f7f@127.0.0.1:0","enr":"0xf88fb8400775cf65da7c43b86728c2df5afa5e9c4c3f8f090a4adc01b3a5efa7baa889b372ff1fa45e2c44d87865585cd877390cdde993202b72699fc3adaf68ca1760bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103422a22e066ae056507308bb1fecc971ca826bab52f6cb3b34b0589a2fc48a040","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4KC6fn6Jp6+AXiSr3hpaW0iboZdYUFGodV6MI0XD1Xs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e0a0ba\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7895 5663 5814 244c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 4 a1c8 b6df bea1 9f7d | 75 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n002 5 cf52 c42e c190 c272 | 27 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n003 7 f645 f2b4 f215 f1ed | 14 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n004 2 ec90 ef99 | 7 eb68 (0) e867 (0) ed42 (0) ec90 (0)\n005 2 e681 e471 | 3 e64d (0) e681 (0) e471 (0)\n============ DEPTH: 6 ==========================================\n006 2 e277 e2d3 | 2 e277 (0) e2d3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 e09f | 1 e09f (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","private_key":"b0d5109a4802c73c946c7a258870bd410c63771abdb96a9270ef013cf2c988de","name":"node_e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","services":["bzz","pss"],"enable_msg_events":true,"port":43807},"up":true}},{"node":{"info":{"id":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","name":"node_1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","enode":"enode://111c70fb9b2eb78fd08286a0101565ce175084379f0d8449515001d42a158dc1bbaec026062de57a300ef9127fd4aca4cd98f12526ac8ebf4564dc7eb62d2861@127.0.0.1:0","enr":"0xf88fb84027a4b499ed66fe3c260acb1384fd562864ab2ea5be83229701ac73ad6916a91b0d8d1c6e3e112ba9b03b133077d6e109f47ddfa35dbd20d934c9305cafe06b8d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103111c70fb9b2eb78fd08286a0101565ce175084379f0d8449515001d42a158dc1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EHDfXpBOOGUIWwMZqBdh5ZFGSUxonnVn7+dGX8gZros=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1070df\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a742 a7a8 a8f4 c272 | 130 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n001 3 7895 5663 5814 | 61 648a (0) 6758 (0) 67f3 (0) 6795 (0)\n002 5 24f8 2e65 2fd2 3938 | 28 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n003 4 0942 0e80 0d1c 046c | 21 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n004 3 1dc0 1b1d 19ea | 9 1fd0 (0) 1dec (0) 1dc0 (0) 1add (0)\n005 4 140d 1484 1784 1686 | 4 140d (0) 1484 (0) 1784 (0) 1686 (0)\n============ DEPTH: 6 ==========================================\n006 1 138d | 1 138d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1049 | 1 1049 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","private_key":"e257c3e07a2c0a5fb86fd8a37ab0d9ff743e74798f3f353ec68c2035dc86b111","name":"node_1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","services":["bzz","pss"],"enable_msg_events":true,"port":46317},"up":true}},{"node":{"info":{"id":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","name":"node_34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","enode":"enode://9f8abe5231a45fd20487a9b4121d524d3b7a84e8ba84e4172bdba5b9e0fd7c950aeeb9d50e3747eeccfaabb4b97f23b01b5de7db38bb79720461d2e07f6fd21c@127.0.0.1:0","enr":"0xf88fb840db60fc10ad69f264ddc0aa2c696ca00930d8509a5150488041b12ccff8a0f4546a98344daf7ccf1d4cc42b130fbbc59bee03d2c1cd405e2081227557266da9680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029f8abe5231a45fd20487a9b4121d524d3b7a84e8ba84e4172bdba5b9e0fd7c95","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NBGBZoRcGF0Vwoa35UM1Oe6Y7WNLqr1TTVc2n9X3xoE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 341181\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f756 9f7d bea1 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 5 68cb 6d3c 70f6 7895 | 61 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n002 5 046c 0e80 0d1c 0942 | 37 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n003 6 2e65 2fd2 2ddf 2c80 | 11 2a50 (0) 298a (0) 2c85 (0) 2c80 (0)\n004 3 3980 397a 3938 | 8 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n005 4 31e1 3188 30fe 32ff | 6 31e6 (0) 31e1 (0) 3188 (0) 3051 (0)\n============ DEPTH: 6 ==========================================\n006 2 3728 36b9 | 2 3728 (0) 36b9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","private_key":"6aebf51d37cedb0b4d755280a22852af0bac9f6f3d355b43bbc8464947552e34","name":"node_34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","services":["bzz","pss"],"enable_msg_events":true,"port":33159},"up":true}},{"node":{"info":{"id":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","name":"node_56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","enode":"enode://bce79d844c8a5bf30fdabb154e156c9b572e1ae5cde1df2f778557d19f720bc830a47ae4678a962fd7f80d4868fda0658bad614a36a18d0ad2cdff495832699c@127.0.0.1:0","enr":"0xf88fb840e2fb45ac13932cdc0858fd63065cf2542a47b9c76331ea177fd36fa8df7938fc069e18891af924b9717bf4598486f9b4d0cbc8e354fdc0c601f9744bf9fcdad00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bce79d844c8a5bf30fdabb154e156c9b572e1ae5cde1df2f778557d19f720bc8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VmNWmb07x4GTrb246LfCyR2rQUD9qlBv6iMA7obEuoE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 566356\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8073 9f7d bea1 f1ed | 130 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n001 6 046c 0942 1070 1b1d | 65 0e2b (0) 0e3b (0) 0e80 (0) 0cfc (0)\n002 6 6d3c 6dd3 68cb 6790 | 26 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n003 3 482e 43d4 43c9 | 19 4d91 (0) 4d38 (0) 4cec (0) 4b79 (0)\n004 7 5d82 5ff0 5a8b 5ac0 | 10 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n005 2 5144 50c1 | 3 52a8 (0) 5144 (0) 50c1 (0)\n============ DEPTH: 6 ==========================================\n006 1 5538 | 1 5538 (0)\n007 0 | 0\n008 1 56ca | 1 56ca (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","private_key":"98f06aa013ffdc1dc622e6180a8b868dcb22f51d0e11dddc2994bd02016cd2d8","name":"node_56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","services":["bzz","pss"],"enable_msg_events":true,"port":39073},"up":true}},{"node":{"info":{"id":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","name":"node_19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","enode":"enode://25da9f823f6a53ece92ba5f5a8fd5f6e819defef89a1d3dca5ab85ea24f52320c59331446c7863ea2a9161b19c2d37abe3af6a9a6961ba1003d5783b6d35ac27@127.0.0.1:0","enr":"0xf88fb8406cdb82ce95d6e0c4222880a7cd7e50ca502bacad52f5afc7c4b72b8dbda35b466718ed4f8f11f2a4342a3f4e1aafefb6869ce7e77d94e6dc1901344e69a07bf80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10325da9f823f6a53ece92ba5f5a8fd5f6e819defef89a1d3dca5ab85ea24f52320","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GeoKaF/E7dKYtzbceneMnsQ2LeN4h2kREF+puizpAgQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 19ea0a\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d700 c272 f756 f1ed | 130 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n001 5 6d3c 68cb 7c7c 70f6 | 61 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n002 4 2e65 24f8 3938 32ff | 28 298a (0) 2a50 (0) 2c85 (0) 2c80 (0)\n003 4 046c 0d1c 0e80 0942 | 21 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n004 3 1686 1049 1070 | 7 140d (0) 1484 (0) 1784 (0) 1686 (0)\n005 3 1dc0 1dec 1fd0 | 3 1fd0 (0) 1dec (0) 1dc0 (0)\n006 3 1add 1bd5 1b1d | 3 1add (0) 1bd5 (0) 1b1d (0)\n============ DEPTH: 7 ==========================================\n007 1 18e0 | 1 18e0 (0)\n008 1 194e | 1 194e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","private_key":"ac8b9e1b4cfbd81595b636bdadfff8bb5f50cd77c2d6dcb05ae20e8ec4c63c1d","name":"node_19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","services":["bzz","pss"],"enable_msg_events":true,"port":43067},"up":true}},{"node":{"info":{"id":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","name":"node_32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","enode":"enode://dc181c079cf6ec82d82772bc7ae94bffff7d8120914030631b14e2a1e91a2979c02e119f03635cdf5d3e001c2b0370eeb626c2aea142bcd446fcb9671a2503e1@127.0.0.1:0","enr":"0xf88fb84052f9b4ee198b6110c708f59268694515e9488cb46efc9f9be015665e9990c36d04f94605b4f0cabf5462667106ddae15421dc9edfc990e6517c0d59d90555f980183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dc181c079cf6ec82d82772bc7ae94bffff7d8120914030631b14e2a1e91a2979","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Mv8ZadkKqlqO0iYJaKjiusLRyuWXyQb5BJXx3F3n+NM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 32ff19\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b659 c42e cf52 f305 | 130 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n001 3 43d4 5538 7895 | 61 4cec (0) 4d38 (0) 4d91 (0) 4b79 (0)\n002 4 0e80 0942 046c 19ea | 37 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n003 8 2c80 2ddf 2e65 2fd2 | 11 298a (0) 2a50 (0) 2c85 (0) 2c80 (0)\n004 2 3980 3938 | 8 3f31 (0) 3c5b (0) 3cab (0) 3b02 (0)\n005 2 36b9 3411 | 3 3728 (0) 36b9 (0) 3411 (0)\n============ DEPTH: 6 ==========================================\n006 5 30fe 3051 31e1 31e6 | 5 31e1 (0) 31e6 (0) 3188 (0) 3051 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","private_key":"b1c850ed51e29dd00bfd57bfed2e5d99cc9f9631301bd8fd28164014f4d70f33","name":"node_32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","services":["bzz","pss"],"enable_msg_events":true,"port":45657},"up":true}},{"node":{"info":{"id":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","name":"node_7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","enode":"enode://a68c7f6ec8a1dcf423bc83c0b592ee6ceaae76d432cd461b10b26f7450cb6f9f444cc86d3d4c99242f12f40dee10f0afb1e72ebee5e1b366d9b8b5f9655f7113@127.0.0.1:0","enr":"0xf88fb8406b7afa5e6f4769c19841e7d3ba40ddbb85b498bb51aabc56a435c0f46703037f63cd6cb222e5da5d92df503476767da8fe86181a30ff028b09d6f045fa46e58c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a68c7f6ec8a1dcf423bc83c0b592ee6ceaae76d432cd461b10b26f7450cb6f9f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eJWyy5e0c/iJPMcKRCHg+L4cAzsnzXMPoTQ4t6jz/LU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7895b2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 9f7d e0a0 f6c0 f756 | 130 ddb8 (0) da36 (0) dad0 (0) dbd4 (0)\n001 8 1b1d 1070 046c 2fd2 | 65 1784 (0) 1686 (0) 140d (0) 1484 (0)\n002 6 43d4 43c9 5814 50c1 | 35 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n003 3 6790 68cb 6d3c | 13 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n004 2 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 3 7d16 7ce7 7c7c | 5 7e47 (0) 7d16 (0) 7ce7 (0) 7c46 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 7933 79e5 | 2 7933 (0) 79e5 (0)\n008 1 7850 | 1 7850 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","private_key":"4e69a8b973ab817bc7714a637ec947dd608ee56d981c0d77f7c99a6aa5f6ac6c","name":"node_7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","services":["bzz","pss"],"enable_msg_events":true,"port":33345},"up":true}},{"node":{"info":{"id":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","name":"node_046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","enode":"enode://183b5b7be84ebacec7a72dc825fc12441895754ccc15e53f4aec88278bae9da625acc2a8ad692479985552cb9e2afa799a5d8915933fae79bc3c24a525beda63@127.0.0.1:0","enr":"0xf88fb840a134fc16f24fd19fc3b2f61ed683f8c65a6fca5513dd3c7d6aac3a81855ef1484bc3b37e5482fcecbcf469c07477e57fd0af25ae5ee67e1a07f9ba2b40a2f9330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103183b5b7be84ebacec7a72dc825fc12441895754ccc15e53f4aec88278bae9da6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BGylQWXw3U1i/X2O6el8ZV2z019UUqDMsN/8ecBHl4w=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 046ca5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c272 c42e ef99 f756 | 130 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n001 5 5987 50c1 5663 70f6 | 61 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n002 6 2fd2 244c 3938 3411 | 28 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n003 3 1b1d 19ea 1070 | 16 1784 (0) 1686 (0) 1484 (0) 140d (0)\n004 3 0e80 0d1c 0942 | 11 0e2b (0) 0e3b (0) 0e80 (0) 0cfc (0)\n005 5 0191 0111 012b 025d | 6 0191 (0) 0111 (0) 012b (0) 025d (0)\n006 1 07f5 | 1 07f5 (0)\n============ DEPTH: 7 ==========================================\n007 2 0594 0561 | 2 0561 (0) 0594 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","private_key":"bc2961c291d9547bc0a390f7c929583558824d7047195fcd2cb026be0c9e0509","name":"node_046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","services":["bzz","pss"],"enable_msg_events":true,"port":35721},"up":true}},{"node":{"info":{"id":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","name":"node_094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","enode":"enode://34b32e374d0cb1f5f1066e330600cb29a8c74400fa6b4e4cb7115a3ca378f605cba1434fceb05ce465f624ab6b77630026597000caea4bce2d96b3b6fb2508ad@127.0.0.1:0","enr":"0xf88fb84097508e3f96233a8a9233a357aa263237d1c15a1d3b78f6b535adbb51249f097b0ae9437277cdeda5fd8ac5416b37b3e9d769ae8802cf22908fd3ab751ecd035e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10334b32e374d0cb1f5f1066e330600cb29a8c74400fa6b4e4cb7115a3ca378f605","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CUJWgSCExgUqJgQUmqOrojecSDv07CUWL2tDk0lCd1o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 094256\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ca1 b659 | 130 ddb8 (0) da36 (0) dad0 (0) dbd4 (0)\n001 5 70f6 5814 5663 5538 | 61 4cec (0) 4d38 (0) 4d91 (0) 4b79 (0)\n002 5 244c 2fd2 3938 3411 | 28 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n003 3 1070 1b1d 19ea | 16 1784 (0) 1686 (0) 140d (0) 1484 (0)\n004 2 025d 046c | 10 0191 (0) 0111 (0) 012b (0) 035f (0)\n005 3 0d1c 0e3b 0e80 | 5 0e2b (0) 0e3b (0) 0e80 (0) 0cfc (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 08bd 08e5 08f8 | 3 08bd (0) 08e5 (0) 08f8 (0)\n008 1 09b3 | 1 09b3 (0)\n009 0 | 0\n010 1 096a | 1 096a (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","private_key":"c5996d97ff53b644b9c191150d78304a45d9874040fb778ddc5bb65779d86bc8","name":"node_094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","services":["bzz","pss"],"enable_msg_events":true,"port":43233},"up":true}},{"node":{"info":{"id":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","name":"node_b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","enode":"enode://58735e5ecf597295cd19c074c7192858e890ceb98016f0e325cec4778d0218a9389a701caf242f4e40d8a3c9eb6b1f00a3174d7d2937fa28f16a12a8c78f9b18@127.0.0.1:0","enr":"0xf88fb84098020ea2d7d1fa04750b97764d931d2e91a9bd545f4d88bb37ca4bef38b7549a4c442d4f9a38ba4a8330780e9971528497eb7f33360afe06246098af41f622c20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10258735e5ecf597295cd19c074c7192858e890ceb98016f0e325cec4778d0218a9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tllBiIUDKQXqIK1H1wRw5APn5Afg6ev5J3+aLYHsEhw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b65941\npopulation: 22 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 32ff 19ea 0942 | 126 4d38 (0) 4d91 (0) 4cec (0) 482e (0)\n001 4 d700 cf52 e09f f305 | 55 ddb8 (0) da36 (0) dad0 (0) dbd4 (0)\n002 3 8358 9f7d 9c21 | 38 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n003 3 a8b5 a7a8 a1c8 | 23 acee (0) aeb4 (0) af02 (0) ab3f (0)\n004 4 ba91 bea1 bdc5 bcf8 | 8 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n005 1 b3f9 | 1 b3f9 (0)\n006 2 b5ea b4a1 | 2 b5ea (0) b4a1 (0)\n============ DEPTH: 7 ==========================================\n007 1 b78f | 1 b78f (0)\n008 1 b6df | 1 b6df (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","private_key":"6f63b7184c7a59615a5a9236a580d00b48d321b742cf81ae7310b20bc9f46f2f","name":"node_b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","services":["bzz","pss"],"enable_msg_events":true,"port":36979},"up":true}},{"node":{"info":{"id":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","name":"node_f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","enode":"enode://d218f0e8c660ea02f34733c763f5ded66b745176058a141d5c3bedb3485fcdedc87b59cd8d7a48a8fd21db93c553cead53a9ac4aaf2f033a3ab072c3d256c511@127.0.0.1:0","enr":"0xf88fb84016a186737b4c1ca5f0aea03b84f96ec62714e7e5da2d64be6b2440ac1c2748ed6fe3708f82254d114172bda4aa9b90e52648fdf8a4965407adcf8299ba7e616e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d218f0e8c660ea02f34733c763f5ded66b745176058a141d5c3bedb3485fcded","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8wUnOn0I5y9psLFThV6CLyUsu/NKGPMFE07tnR63tYo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f30527\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 19ea 046c 32ff 3938 | 126 4d38 (0) 4d91 (0) 4cec (0) 4b79 (0)\n001 2 9c21 b659 | 75 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n002 4 d700 cf52 c42e c272 | 27 ddb8 (0) d959 (0) d9cf (0) dad0 (0)\n003 4 e471 e2d3 ec90 ef99 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 4 f8ff fa24 ff75 fc39 | 7 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n005 3 f645 f6c0 f756 | 3 f645 (0) f6c0 (0) f756 (0)\n006 1 f1ed | 1 f1ed (0)\n============ DEPTH: 7 ==========================================\n007 2 f2b4 f215 | 2 f2b4 (0) f215 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","private_key":"39d3913d08835ee0310d15c086d9d2b5bdfe93c590ffeb6d94d0a053770a938a","name":"node_f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","services":["bzz","pss"],"enable_msg_events":true,"port":43471},"up":true}},{"node":{"info":{"id":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","name":"node_f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","enode":"enode://f20b87c432491558cc8aebd5ea9ee25b89c6f93f08f1dbfdd8f5ce5b442263099d8f903e2a82b4c31c15c24e3763f335643014c943dac9dba80bb99b2bf7fab7@127.0.0.1:0","enr":"0xf88fb84014f4b222ba6b5de9fd84dbf8714c734b2273549ffd1e5d785589072c106e628a1a8c4cf1ed22b0b33864347ed1d46b4a941e32a0d27b46c3bdb1af2f742acb3b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f20b87c432491558cc8aebd5ea9ee25b89c6f93f08f1dbfdd8f5ce5b44226309","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"91YctnQOF+x8fRcGglGyyVHZVMd4BKpa9gRk6cOWTlc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f7561c\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5c37 5663 7895 046c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 4 a8b5 a1c8 93c0 9c21 | 75 aeb4 (0) af02 (0) acee (0) ab3f (0)\n002 6 d700 c8ea cf52 cdb1 | 27 ddb8 (0) d959 (0) d9cf (0) da36 (0)\n003 6 e471 e277 e09f e867 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 6 f9de f8ff fa24 ff75 | 7 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n005 4 f1ed f2b4 f215 f305 | 4 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 f645 f6c0 | 2 f645 (0) f6c0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","private_key":"ecae59b9fef453fa7d5352f8aa56d8af8ae96d6846b15e9aaff107d1031cdd4c","name":"node_f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","services":["bzz","pss"],"enable_msg_events":true,"port":45253},"up":true}},{"node":{"info":{"id":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","name":"node_9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","enode":"enode://437f633a70046ae9419cb2ddabf116dab0954965e968a6f007e228a7a7be8ce3d03010480c1b6e5d493d696d883920532e1bdb07b996dc70406fde018db10948@127.0.0.1:0","enr":"0xf88fb84021a7f662e426de82de76fe3fb5a9358593b06425d494639aaf2886f7d0cd4c2f09f3b746b5071fccca870524abebba751c338e44dd9c8af378c6f81bfa6b8b090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102437f633a70046ae9419cb2ddabf116dab0954965e968a6f007e228a7a7be8ce3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nCHLPlb4rGankXqboU5Y936ZiscMF4uItQU9msJ3fmA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9c21cb\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 50c1 3938 | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 9 cf52 c272 c42e e2d3 | 55 ddb8 (0) dad0 (0) da36 (0) dbd4 (0)\n002 7 a742 a616 a970 a8f4 | 37 af02 (0) aeb4 (0) acee (0) ab3f (0)\n003 7 8b43 8d19 8ea2 8073 | 21 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n004 3 955d 9257 93c0 | 8 97da (0) 9464 (0) 95c0 (0) 9518 (0)\n005 3 9959 9948 9b8e | 3 9959 (0) 9948 (0) 9b8e (0)\n006 3 9f0e 9f7d 9ec8 | 3 9ec8 (0) 9f0e (0) 9f7d (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 9c8e 9ca1 | 2 9c8e (0) 9ca1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","private_key":"7eef00d143ca4d22aa8920afb1093aeee46b08939a3cfefeab24e6465f3d7523","name":"node_9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","services":["bzz","pss"],"enable_msg_events":true,"port":45091},"up":true}},{"node":{"info":{"id":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","name":"node_f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","enode":"enode://1f605d05b467e52497e1862559e2ea806c76b9b68e4afb936b675a7afa72346881e26390a04e9afcda1a11fbefd20fd50c0762ce93772dac8c8498e6c301da9c@127.0.0.1:0","enr":"0xf88fb84092227639c78910be0212f1396d95453dd49c75961b2d39d43b6dbe94b6be413b25e0d6ae86588ec165a1c7881d660a1621459959cc457247cd1ab90403fbf3730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f605d05b467e52497e1862559e2ea806c76b9b68e4afb936b675a7afa723468","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8e2dRWIv+XSh45bNh4st64njGqXQjadzQj8pKujby7Y=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f1ed9d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 5c37 50c1 5663 7895 | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 6 b4a1 a7a8 a1c8 a327 | 75 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n002 3 c8ea c42e c272 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 7 ef99 eb68 e681 e471 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 4 f9de feb3 ff75 fc39 | 7 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n005 3 f645 f6c0 f756 | 3 f645 (0) f6c0 (0) f756 (0)\n============ DEPTH: 6 ==========================================\n006 3 f2b4 f215 f305 | 3 f2b4 (0) f215 (0) f305 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","private_key":"43438f5d37cc4d101776db9c837b45c0348d0fb3ee2b4d66b66ea68193a67634","name":"node_f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","services":["bzz","pss"],"enable_msg_events":true,"port":42225},"up":true}},{"node":{"info":{"id":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","name":"node_3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","enode":"enode://d65c386d5a9eb699e325a7b173f89ced8caed9f813009e1949ae1c727decbb605d94eecc4f1b8733edb8dbd4c29d3b85d0de50abdab36072250f3de5cd28ac35@127.0.0.1:0","enr":"0xf88fb840eb07d284d45af49b9534f8d95e093e90eb86595cf13b63dab9984c6430a9ba0845a201ee9f0eaea3d91a875fba3a36474eebdebef6154e1227ce0f12d011b6f30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d65c386d5a9eb699e325a7b173f89ced8caed9f813009e1949ae1c727decbb60","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OTjmssCVCE3Jl1o+hkkTNVdJXTSsbfh0xtkpJm4//m8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3938e6\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9c21 bcf8 c42e f305 | 130 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n001 6 70f6 7895 5c37 5987 | 61 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n002 8 1070 138d 1dc0 1b1d | 37 1686 (0) 1784 (0) 1484 (0) 140d (0)\n003 4 2fd2 26ab 24f8 244c | 11 2a50 (0) 298a (0) 2c85 (0) 2c80 (0)\n004 5 36b9 3411 30fe 3051 | 9 3728 (0) 36b9 (0) 3411 (0) 3188 (0)\n005 2 3cab 3c5b | 3 3f31 (0) 3cab (0) 3c5b (0)\n006 2 3b02 3a62 | 2 3b02 (0) 3a62 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 3980 | 1 3980 (0)\n009 1 397a | 1 397a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","private_key":"fbe0ae960205a2db352664d1d04b5bba8f4ba47cd2fe72d6ade101914a4ccaeb","name":"node_3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","services":["bzz","pss"],"enable_msg_events":true,"port":44129},"up":true}},{"node":{"info":{"id":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","name":"node_bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","enode":"enode://e6c340b1a3696a5038e4d658f970cac4bda141f463f92b1b44ee1cb7f7f6868ffdde7757ef00b0ff3b271a9a9ecc8ab2e5875c42cb87e496405bc922e6fa64d0@127.0.0.1:0","enr":"0xf88fb840c9a15fff14a8ea3abbc9aedcba9b73f5e824da4b1a9e08fcf571cab264f32d8e7a24034ff41cfab6ecfd8ac3d535031401c463fdbd7e54919a443452c29c81ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e6c340b1a3696a5038e4d658f970cac4bda141f463f92b1b44ee1cb7f7f6868f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vPhez0Ibhx/KAkenCBGIqOLAh3i4j/rRbbN+8CT+wPw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bcf85e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 50c1 046c 3938 | 126 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n001 3 cf52 c272 ef99 | 55 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n002 8 8ea2 8358 87a3 86d6 | 38 80d7 (0) 8073 (0) 8074 (0) 8006 (0)\n003 4 a970 a8b5 a7a8 a1c8 | 23 acee (0) aeb4 (0) af02 (0) ab3f (0)\n004 4 b3f9 b4a1 b6df b659 | 6 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n005 3 b8e1 bbaf ba91 | 3 b8e1 (0) bbaf (0) ba91 (0)\n============ DEPTH: 6 ==========================================\n006 3 be68 bea1 bfc7 | 3 bfc7 (0) be68 (0) bea1 (0)\n007 1 bdc5 | 1 bdc5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","private_key":"0e3de03ec47c112197b5ce9f4876cc7e0328950172cb9bdcdbf176c7b1e8f4ad","name":"node_bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","services":["bzz","pss"],"enable_msg_events":true,"port":40251},"up":true}},{"node":{"info":{"id":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","name":"node_ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","enode":"enode://a32bf13f4f87b1e4791889257bd457b480d36efd85c79fbdeafa0cd700b80d68203a12c8c8dc06bc7fe6784e017ed5beaf08fa18498f6b4a7014b292c79ad657@127.0.0.1:0","enr":"0xf88fb84090a9fff8d7f284263393a75dbe4c5ffa3baf41b98a66f2556dcceeba191c4f70370008eb731f510bf571448c132df27f82771b519fb3ad204ad2d0689fa0781d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a32bf13f4f87b1e4791889257bd457b480d36efd85c79fbdeafa0cd700b80d68","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"75m2zcBTRaHugiZ4kOPMru8fK9L+euiwK2sguaXvhbs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ef99b6\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 046c 50c1 | 126 298a (0) 2a50 (0) 2c85 (0) 2c80 (0)\n001 4 87a3 86d6 8358 bcf8 | 75 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n002 4 d3e9 d700 c8ea c272 | 27 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n003 8 fa24 fc51 fc39 f1ed | 14 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n004 6 e681 e471 e09f e0a0 | 7 e64d (0) e681 (0) e471 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n006 2 ed42 ec90 | 2 ed42 (0) ec90 (0)\n============ DEPTH: 7 ==========================================\n007 1 eebd | 1 eebd (0)\n008 0 | 0\n009 1 eff2 | 1 eff2 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","private_key":"3831e217095e4b4c3136779fd48aa121431f6a092eb73e195733ff54b1173150","name":"node_ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","services":["bzz","pss"],"enable_msg_events":true,"port":44801},"up":true}},{"node":{"info":{"id":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","name":"node_c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","enode":"enode://58ac0bf5776e7efc0260166f939bfdf2dde78fe6180b3d8aa44837f05cec80d837921c8066f45d495bfbe49ffeeca03fe962b8a7da5ccab5317ea019d665218e@127.0.0.1:0","enr":"0xf88fb840478fb2b3a4ab8e3cd050916898983baa1a6896bd48d38cc281048c9f916b9e493bc8b5aa56c0c2fc28e8aec7f9fcb6b6245cbd205c39861c37f7980d982af09a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10258ac0bf5776e7efc0260166f939bfdf2dde78fe6180b3d8aa44837f05cec80d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wnKxL0Agrlsg49Kc0J3gP6AIjj7rXweqdyiymj6Q5oc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c272b1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1070 19ea 046c 50c1 | 126 140d (0) 1484 (0) 1784 (0) 1686 (0)\n001 3 bcf8 9c21 9ec8 | 75 af02 (0) aeb4 (0) acee (0) aaf0 (0)\n002 7 ff75 f6c0 f756 f305 | 28 f9de (0) f8ff (0) fa24 (0) feb3 (0)\n003 2 d3e9 d700 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 5 c9c3 c8ea cdb1 cc33 | 8 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n005 5 c6a8 c603 c74d c534 | 5 c6a8 (0) c603 (0) c74d (0) c534 (0)\n============ DEPTH: 6 ==========================================\n006 1 c190 | 1 c190 (0)\n007 0 | 0\n008 1 c2d0 | 1 c2d0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","private_key":"5ba984dd53fd38ef7d9f085d4d2f71bf5e57cebbcf57a991cdfc6f90de3bf1e2","name":"node_c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","services":["bzz","pss"],"enable_msg_events":true,"port":36391},"up":true}},{"node":{"info":{"id":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","name":"node_c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","enode":"enode://50c60560f3e788431adda5f3ee4a65d462996a8a36a801d446f2d7d9e5a2d6dbc87d22941f4533589788d323a941f0f70a6c9b3b8c70f9984c1493879b56a3d6@127.0.0.1:0","enr":"0xf88fb840b2c5ef4495d49d374e60fa0e85dc6a8e48f5004aebec4bc746bfae6c2fe8e1180e0ba56367464f0e396f9d98f8e999544031948efb5659f3f33130eee1e8bb230183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10250c60560f3e788431adda5f3ee4a65d462996a8a36a801d446f2d7d9e5a2d6db","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xC5kkoeUOe7s2ZONF/8oP9j18kIGkGylErTapIA7eLQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c42e64\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 08f8 046c 32ff 3938 | 126 140d (0) 1484 (0) 1686 (0) 1784 (0)\n001 2 9c21 9ec8 | 75 a5ac (0) a505 (0) a4ee (0) a742 (0)\n002 8 e2d3 e0a0 ff75 f6c0 | 28 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n003 4 dbd4 da36 d3e9 d700 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 4 c8ea cf52 cc33 cdb1 | 8 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n005 3 c190 c2d0 c272 | 3 c190 (0) c2d0 (0) c272 (0)\n============ DEPTH: 6 ==========================================\n006 3 c74d c6a8 c603 | 3 c74d (0) c6a8 (0) c603 (0)\n007 1 c534 | 1 c534 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","private_key":"49943ef9cb5cfe1f6f01ab1a1f9fa8d6de40a8c49ed24b1ae244aff5459c9da0","name":"node_c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","services":["bzz","pss"],"enable_msg_events":true,"port":36607},"up":true}},{"node":{"info":{"id":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","name":"node_f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","enode":"enode://914631182a42d1219b9b28e6b5da1bd8c08e539575c6a7a85fa1d4222e9dc5c26156834d4dda7260174a844f276747baf4fbb4c75d6497ed9fc55f1300ad99df@127.0.0.1:0","enr":"0xf88fb840799f4f4b2fd08a7f68922afcbc7694953e771f3d0bfb81ee89d9f3c15bd5750b6e7e379849906088a02b409e2c46ef95e0f2169d796e86b7082d85ec6b99114e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103914631182a42d1219b9b28e6b5da1bd8c08e539575c6a7a85fa1d4222e9dc5c2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8hW8CSaOYOu+x290O+vQnX5y1Mvu3AudNBe7Si70KTU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f215bc\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5c37 5538 50c1 | 126 2a50 (0) 298a (0) 2ddf (0) 2c80 (0)\n001 3 ba91 9c21 9ec8 | 75 af02 (0) aeb4 (0) acee (0) ab3f (0)\n002 4 d3e9 cc33 cdb1 c42e | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 9 e867 eb68 ef99 e471 | 14 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n004 3 f9de ff75 fc39 | 7 fa24 (0) f8ff (0) f9de (0) feb3 (0)\n005 3 f645 f6c0 f756 | 3 f645 (0) f6c0 (0) f756 (0)\n006 1 f1ed | 1 f1ed (0)\n============ DEPTH: 7 ==========================================\n007 1 f305 | 1 f305 (0)\n008 1 f2b4 | 1 f2b4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","private_key":"1fed8e5946a97ef10fbabe578590010445e49851e010e422c67c268755300ba7","name":"node_f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","services":["bzz","pss"],"enable_msg_events":true,"port":46479},"up":true}},{"node":{"info":{"id":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","name":"node_50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","enode":"enode://7e0efcde01784575e4464fcd19486068e81004e45914861571c763aab72c40fd7de3be474040f71ccb0daa1d9bbb197140dad13d641b98fed6ffbc50b322e2d4@127.0.0.1:0","enr":"0xf88fb8402fd5df06a939249a9fd0804b4b2f40564565802cf963bde27cbc3f4504997ac970f523add3a785ca408dbf18c0de819dd1f6ae8b65c540fbafe08e578e5673c40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027e0efcde01784575e4464fcd19486068e81004e45914861571c763aab72c40fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UMGoAjv+z/sJRy/cUImPTQUKMUQ9QKbAe2KQkL6w3z0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 50c1a8\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 bcf8 9c21 9ec8 c42e | 130 af02 (0) aeb4 (0) acee (0) aaf0 (0)\n001 4 046c 0942 0d1c 3938 | 65 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n002 3 70f6 7c7c 7895 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 5 46bf 43c9 4a95 48d7 | 19 402c (0) 4005 (0) 435d (0) 43d4 (0)\n004 7 5ff0 5d82 5c37 5c7c | 10 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n005 3 56ca 5663 5538 | 3 56ca (0) 5663 (0) 5538 (0)\n============ DEPTH: 6 ==========================================\n006 1 52a8 | 1 52a8 (0)\n007 1 5144 | 1 5144 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","private_key":"d0239dc44e8e56fc8a14b93a43280c425ab0988a63c4fa8d558b6b61b972ccbc","name":"node_50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","services":["bzz","pss"],"enable_msg_events":true,"port":35321},"up":true}},{"node":{"info":{"id":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","name":"node_cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","enode":"enode://e384773f94b9f4af8300be9d39cc581c8fd208e7fe459b0457b672457797b8c548dd064bb5361fcfc8587bf356c8499f98a5bd8b2271ffe616f070f8fe479178@127.0.0.1:0","enr":"0xf88fb8401939cbdd1ef26b61abcaf49b3902648650033c3decced5af79fdd44e154207b01ba84f8e62658f91e9386318c11267895180beaa28dec6fb4bbcd4355b6e733b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e384773f94b9f4af8300be9d39cc581c8fd208e7fe459b0457b672457797b8c5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"z1Kz/ILsJMPptASI18X3rIr3MdFZoQNhm+6TLsdNXpI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cf52b3\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 244c 32ff 50c1 | 126 298a (0) 2a50 (0) 2ddf (0) 2c80 (0)\n001 4 bcf8 b659 9c21 9ec8 | 75 a4ee (0) a505 (0) a5ac (0) a742 (0)\n002 8 ff75 f305 f6c0 f756 | 28 f9de (0) f8ff (0) fa24 (0) feb3 (0)\n003 4 dbd4 d700 d408 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dad0 (0)\n004 6 c603 c42e c534 c190 | 8 c190 (0) c2d0 (0) c272 (0) c74d (0)\n005 4 c961 c9c3 c8c8 c8ea | 4 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n============ DEPTH: 6 ==========================================\n006 3 cd6c cdb1 cc33 | 3 cc33 (0) cd6c (0) cdb1 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","private_key":"53a2e6b259e67e80a322fb0917b85f97860e8d37711d29f1964170d6b45d30cf","name":"node_cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","services":["bzz","pss"],"enable_msg_events":true,"port":36313},"up":true}},{"node":{"info":{"id":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","name":"node_e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","enode":"enode://a1889a38f3b1e9100f7626ad54d9622d503f7b1a9014ec13cd5215336196fc7bf27333448336381ec7c86db4006d245abb48c0f58940760bbb9deba79ca40c98@127.0.0.1:0","enr":"0xf88fb840aa1a2025c453351a72aae064d06aea3bd2d1804bd65cef80301c79f24934fbf94a35606db5f3a38a983d33c340db4c1f4c573ccf0b492159aa9bea1e78b3c8bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a1889a38f3b1e9100f7626ad54d9622d503f7b1a9014ec13cd5215336196fc7b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4J+YEU2mTnVHs1FjcZD2YhofdVaM+plgmA/Hdhj4hVs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e09f98\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0d1c 5987 5538 | 126 298a (0) 2a50 (0) 2c80 (0) 2c85 (0)\n001 6 a8b5 b659 ba91 93c0 | 75 a4ee (0) a505 (0) a5ac (0) a606 (0)\n002 2 c534 cf52 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 3 f756 f1ed f215 | 14 fa24 (0) f8ff (0) f9de (0) feb3 (0)\n004 5 e867 eb68 ec90 eebd | 7 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n005 3 e64d e681 e471 | 3 e64d (0) e681 (0) e471 (0)\n============ DEPTH: 6 ==========================================\n006 2 e277 e2d3 | 2 e277 (0) e2d3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 e0a0 | 1 e0a0 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","private_key":"0c21558e199ac8f8279ccba752dfce4a160302de5147dcf00d462d131b117293","name":"node_e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","services":["bzz","pss"],"enable_msg_events":true,"port":36519},"up":true}},{"node":{"info":{"id":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","name":"node_e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","enode":"enode://811ff91b658315c4fe2d501370f6e0a5c2a4e87fd7705b110ffd9f5b560a6cbf6a57694806e4a1371ae4ac682b8ef5eb4948f3f8798bde7bae62478ce8b29187@127.0.0.1:0","enr":"0xf88fb840a4ca41dc96fb07375e8655b138b07ef3e43a3cd6824b9b03a1bfbfd5dbffe8514a9522377d1e78474799dd1121831879798540a60453e10b5808f881eb4c12ec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103811ff91b658315c4fe2d501370f6e0a5c2a4e87fd7705b110ffd9f5b560a6cbf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4tNvM12QrWMUjbjjU6eKMNjZwKvhB74s+GhfagHOdLk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e2d36f\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 70f6 50c1 5987 0d1c | 126 2a50 (0) 298a (0) 2ddf (0) 2c80 (0)\n001 3 a8b5 9c21 9ec8 | 75 a5ac (0) a505 (0) a4ee (0) a742 (0)\n002 3 c42e c534 cf52 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 5 ff75 f6c0 f1ed f305 | 14 fa24 (0) f8ff (0) f9de (0) feb3 (0)\n004 4 e867 eb68 ec90 ef99 | 7 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n005 3 e64d e681 e471 | 3 e64d (0) e681 (0) e471 (0)\n============ DEPTH: 6 ==========================================\n006 2 e0a0 e09f | 2 e0a0 (0) e09f (0)\n007 0 | 0\n008 1 e277 | 1 e277 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","private_key":"85e06d183c4f5bd671a46232c0f291076bda62d6d879496e84ae6c378d966174","name":"node_e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","services":["bzz","pss"],"enable_msg_events":true,"port":39311},"up":true}},{"node":{"info":{"id":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","name":"node_9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","enode":"enode://4dd9a25575645b97012af13c2b562b1fdfc4444922998e1d08ac31e94030800ec40d6c48d4f3fd76c25ed0882398d9620390cbad7c72618375520f348552e966@127.0.0.1:0","enr":"0xf88fb8408fa9c2bc6983316b1331a0fbc8cd6fdb72a55deec652bdb9de328b24b60e78c51aca35ac84c776df03949c9a90e376a21a4e15f4b334551da12477a8eb16cd470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024dd9a25575645b97012af13c2b562b1fdfc4444922998e1d08ac31e94030800e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nsgx2XQYkW/ZaVRl4EHK8ngk27Udb/dNa3DzvVYecOY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ec831\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0d1c 70f6 5987 50c1 | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 7 c42e c272 cdb1 cf52 | 55 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n002 3 a1c8 ba91 bcf8 | 37 a5ac (0) a505 (0) a4ee (0) a742 (0)\n003 8 8b43 8ea2 8d19 8358 | 21 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n004 4 955d 9518 9464 93c0 | 8 97da (0) 95c0 (0) 9518 (0) 955d (0)\n005 3 9b8e 9959 9948 | 3 9b8e (0) 9959 (0) 9948 (0)\n006 3 9c8e 9ca1 9c21 | 3 9c8e (0) 9ca1 (0) 9c21 (0)\n============ DEPTH: 7 ==========================================\n007 2 9f7d 9f0e | 2 9f0e (0) 9f7d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","private_key":"1448c304f2af7e48ae443402703fb0a3b1e1f2d2bfef6a6456141daa73c558f6","name":"node_9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","services":["bzz","pss"],"enable_msg_events":true,"port":46859},"up":true}},{"node":{"info":{"id":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","name":"node_553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","enode":"enode://f82e099fec04ce2be67700e463707728eb144ee2a7cf821945ec03d4b8166298749bed9860b4348e5a202bd5bff1957dc60d943fbf065aeed536e8baa6e18492@127.0.0.1:0","enr":"0xf88fb840f8de9483b97759f1daf327a569a475175e424a75efbc3654978adf85d062bc605b9880637ca11a772ac5e122d91c1acf3f95096d0ceea3935048f40ac35b28990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f82e099fec04ce2be67700e463707728eb144ee2a7cf821945ec03d4b8166298","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VTgk73AdPNAZGuOmfeVk7Qz1U+dL1g7Z3jIfkwJzK6Y=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 553824\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f215 e09f 9ec8 | 130 fa24 (0) f9de (0) f8ff (0) fc51 (0)\n001 5 30fe 32ff 3938 0942 | 65 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n002 5 6790 70f6 7895 7ce7 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 7 4a95 48d7 48f1 48b8 | 19 4d38 (0) 4d91 (0) 4cec (0) 4b79 (0)\n004 8 5ff0 5d82 5c37 5c7c | 10 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n005 3 52a8 5144 50c1 | 3 52a8 (0) 5144 (0) 50c1 (0)\n============ DEPTH: 6 ==========================================\n006 2 56ca 5663 | 2 56ca (0) 5663 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","private_key":"cf91bb0fea150fbf8705d939da029fdefebdd1076d1f645864e8d53e99501f66","name":"node_553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","services":["bzz","pss"],"enable_msg_events":true,"port":36171},"up":true}},{"node":{"info":{"id":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","name":"node_0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","enode":"enode://8963c10c3899dce73c253820c99702353f5b64a1fcd1e94e3c60e8fa36a84d51e3155fe96a087599495c893da0da9d41148ab85235b65124f03236d23543e0eb@127.0.0.1:0","enr":"0xf88fb8404dcbbcadbab5ddfd4e10d68ffabb6b5c5038e323a062c9153dcb26b97422e6dc051d2044717c22e8f9279c57776cf04de0184acc5b55f05525303d87739498fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038963c10c3899dce73c253820c99702353f5b64a1fcd1e94e3c60e8fa36a84d51","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DRw1xupIXLM4V7eQ7iYvl0zw1Uz4zjAD+DCKwuh8LCU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d1c35\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 e09f e2d3 c8ea cdb1 | 130 a4ee (0) a5ac (0) a505 (0) a742 (0)\n001 5 7c7c 70f6 5987 50c1 | 61 6e7f (0) 6c01 (0) 6dd3 (0) 6d5e (0)\n002 4 244c 3938 3411 30fe | 28 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n003 6 19ea 1b1d 1dc0 1784 | 16 140d (0) 1484 (0) 1686 (0) 1784 (0)\n004 3 035f 025d 046c | 10 0191 (0) 0111 (0) 012b (0) 025d (0)\n005 4 0942 08bd 08f8 08e5 | 6 08bd (0) 08f8 (0) 08e5 (0) 09b3 (0)\n============ DEPTH: 6 ==========================================\n006 3 0e80 0e2b 0e3b | 3 0e80 (0) 0e2b (0) 0e3b (0)\n007 1 0cfc | 1 0cfc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","private_key":"ef22b9afd09135d969cbfaa3c7f02beacec87dc03fc514f0565a8fdee536fab4","name":"node_0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","services":["bzz","pss"],"enable_msg_events":true,"port":40431},"up":true}},{"node":{"info":{"id":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","name":"node_59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","enode":"enode://7720368c45d12af9a222ed1304cec25526c3f521dc8bdbdad1a966ab1b0bd4169a905fe56bec7845f8be9ddb4a1302c8c13d61273415db4ae840c8662272be45@127.0.0.1:0","enr":"0xf88fb84034abc65244d703a8f51ccf0ea8c8099e02c759dbf7c0b19434d08a4c72e9836629a6c3f2dad2881e6e85fc9aade07106ee0fbd25d2d04233ee4cbe90748a1ef10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037720368c45d12af9a222ed1304cec25526c3f521dc8bdbdad1a966ab1b0bd416","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WYduf/npIkOFba0jEm4dONml3a55dy7Rsr25HzOkpLU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 59876e\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9ec8 e09f e2d3 cdb1 | 130 a4ee (0) a5ac (0) a505 (0) a7a8 (0)\n001 4 30fe 3938 046c 0d1c | 65 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n002 2 7c7c 70f6 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 4 4a95 48b8 48f1 48d7 | 19 46bf (0) 447c (0) 447a (0) 44ad (0)\n004 4 52a8 50c1 5663 5538 | 6 52a8 (0) 5144 (0) 50c1 (0) 56ca (0)\n005 2 5c37 5c7c | 4 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n============ DEPTH: 6 ==========================================\n006 4 5a8b 5ac0 5a26 5bd8 | 4 5a8b (0) 5ac0 (0) 5a26 (0) 5bd8 (0)\n007 1 5814 | 1 5814 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","private_key":"d68e5f6712ad13a5f18afe7ea604194bc75d700d868489882a6d439f62d3319f","name":"node_59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","services":["bzz","pss"],"enable_msg_events":true,"port":43863},"up":true}},{"node":{"info":{"id":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","name":"node_c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","enode":"enode://ed050956c10a60194bdfcc79bc927b7864a5ccd487521a7764441e4146defd9147ba153983e148a136ae5bde225df9eec974f956dcbd4c837b61013ce32a13fb@127.0.0.1:0","enr":"0xf88fb840d1ba87a7f202b2d69d25fe1c48a6386c6e96f4b473922d59cebadff7c92d58b528bf3e59e6f57acb30587ce613e1bb64b9f483d837420b47e669533583256c650183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ed050956c10a60194bdfcc79bc927b7864a5ccd487521a7764441e4146defd91","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xTQX8AjkVQ4cTLmj4pVbOvZAPgWbe0tMM4adntSlgKU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c53417\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 2c85 2c80 2fd2 244c | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 5 a1c8 ba91 8358 87a3 | 75 a4ee (0) a505 (0) a5ac (0) a742 (0)\n002 4 f6c0 e471 e09f e2d3 | 28 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n003 4 da36 ddb8 d700 d3e9 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 3 c8ea cf52 cdb1 | 8 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n005 3 c190 c2d0 c272 | 3 c190 (0) c2d0 (0) c272 (0)\n============ DEPTH: 6 ==========================================\n006 3 c74d c6a8 c603 | 3 c74d (0) c6a8 (0) c603 (0)\n007 1 c42e | 1 c42e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","private_key":"a4ea2b639e280337e8009d2b54e9a11f76f523e1ef1ba9619f03ba35ee15abd8","name":"node_c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","services":["bzz","pss"],"enable_msg_events":true,"port":39971},"up":true}},{"node":{"info":{"id":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","name":"node_cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","enode":"enode://c272080f38dac498765747523f4926457465e2941b3ddc08b62aa1affedc7f8e16f0e038d1a474ff133dfbbfc366fe750e99c2b75a184d40debca8913add7f88@127.0.0.1:0","enr":"0xf88fb840b2235f35efc093f6baac2bfe925b6f021eb803ca0488b4174d2a7ecc21921e124f99929c0f151ebdb9472db8350ab836dba4759f9aa6aad06a78f9c3bed45f7c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c272080f38dac498765747523f4926457465e2941b3ddc08b62aa1affedc7f8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zbE4c6wFiGHylevKXZWL8rt5Pj+eJ0z1pzpjNCWpJ28=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cdb138\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 08f8 0d1c 5987 70f6 | 126 2ddf (0) 2c80 (0) 2c85 (0) 2e65 (0)\n001 5 9ec8 8ea2 8358 ba91 | 75 a5ac (0) a505 (0) a4ee (0) a742 (0)\n002 3 e471 f756 f215 | 28 f8ff (0) f9de (0) fa24 (0) fc51 (0)\n003 3 da36 d3e9 d700 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 4 c2d0 c272 c42e c534 | 8 c190 (0) c2d0 (0) c272 (0) c74d (0)\n005 4 c961 c9c3 c8c8 c8ea | 4 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n006 1 cf52 | 1 cf52 (0)\n============ DEPTH: 7 ==========================================\n007 1 cc33 | 1 cc33 (0)\n008 1 cd6c | 1 cd6c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","private_key":"276e93bd6b53db81cd162f42fb634b4f3910e6d45ec7079c645a69e4bb5afca8","name":"node_cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","services":["bzz","pss"],"enable_msg_events":true,"port":45371},"up":true}},{"node":{"info":{"id":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","name":"node_70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","enode":"enode://8f535591758ee98b2ac41582a7d8642366706bd60b1e98b68f9a4019f653977b5d0973cee6fff3ec29c71ad9699d7e456f0ce29a85517f76f9876fdb6ff30a1d@127.0.0.1:0","enr":"0xf88fb840b1187ebcb96b2d46f5160c07357e2fb4ea69464366c7db75aacaa3b5c296724b5eff7e0985615cc94bf3aa4fe85bfaed822dd031b5d5b00e56937de9f27d922b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038f535591758ee98b2ac41582a7d8642366706bd60b1e98b68f9a4019f653977b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cPaFYnM9pOOxw5SftuEawL3UnqfnMpJfk3+H31r2mNY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 70f685\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9ec8 8ea2 e2d3 e471 | 130 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n001 8 2fd2 3938 3411 30fe | 65 298a (0) 2a50 (0) 2ddf (0) 2c80 (0)\n002 5 48d7 48b8 5538 50c1 | 35 46bf (0) 44ad (0) 447c (0) 447a (0)\n003 6 6790 60c5 6dd3 6d5e | 13 6e7f (0) 6c01 (0) 6dd3 (0) 6d5e (0)\n004 6 7933 79e5 7895 7d16 | 9 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 7660 741a | 2 7660 (0) 741a (0)\n006 0 | 0\n007 0 | 0\n008 1 7049 | 1 7049 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","private_key":"0e58ed0a2b5955aa47fe1c7b185856a83cdf3966967becea9ac671a883a80100","name":"node_70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","services":["bzz","pss"],"enable_msg_events":true,"port":38721},"up":true}},{"node":{"info":{"id":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","name":"node_e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","enode":"enode://a39dec81162f336a51198d012a49706e42117ca42cf3d483d9ac74f65e01eab80f2164489ad2fffb217106e4f1e877d3ff2653643519569aa3f6b44becffccc7@127.0.0.1:0","enr":"0xf88fb8403f1d47db38a57c5f187e93e73913d7d9164793ebf66aa94e6e1eb9bec7be36de323d165610bbdde527989f06ff19902a0d7e342985034c0d1798277c0f9dd2ee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a39dec81162f336a51198d012a49706e42117ca42cf3d483d9ac74f65e01eab8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5HHvvPHe85FbPdotxlqGlFxge+VKM+MeliVUm+ysDjQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e471ef\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 30fe 70f6 | 126 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n001 2 ba91 8ea2 | 75 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n002 7 d3e9 c2d0 c534 cdb1 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 7 feb3 fc39 f756 f6c0 | 14 f9de (0) f8ff (0) fa24 (0) feb3 (0)\n004 4 eb68 e867 ec90 ef99 | 7 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n005 4 e277 e2d3 e0a0 e09f | 4 e0a0 (0) e09f (0) e277 (0) e2d3 (0)\n============ DEPTH: 6 ==========================================\n006 2 e64d e681 | 2 e64d (0) e681 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","private_key":"8e34bf0af71dad627841518807b1d0dd56349eafd2c3b416704905a478f24628","name":"node_e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","services":["bzz","pss"],"enable_msg_events":true,"port":33051},"up":true}},{"node":{"info":{"id":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","name":"node_8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","enode":"enode://7efcc0a5b110a3d47e6b3e9b74e485a18770d757efb293ac544941a244e1764eef9534fb52dd16769014c5d3591266da5d6816885513985fd4d9eb1ff29225b2@127.0.0.1:0","enr":"0xf88fb840af3e7481de1a628caeff3e925e26c7ec284791874d83ca00a34365321e53458a61c6d4e0dd1e3a7e816d3ba5b038820ca851aae32ea491173f4a090486d1a1440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027efcc0a5b110a3d47e6b3e9b74e485a18770d757efb293ac544941a244e1764e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jqLIrMER841bSl7WAlLug/MS0Pg1kmXVuSZtVHNQUv4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8ea2c8\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0d1c 30fe 70f6 7c7c | 126 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n001 3 cdb1 c534 e471 | 55 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n002 6 a8b5 a8f4 a616 bcf8 | 37 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n003 6 93c0 9257 9464 9ec8 | 17 97da (0) 95c0 (0) 955d (0) 9518 (0)\n004 7 84a9 8402 87a3 86d6 | 12 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n005 2 8862 8b43 | 3 8854 (0) 8862 (0) 8b43 (0)\n006 2 8d19 8cc3 | 2 8cc3 (0) 8d19 (0)\n007 1 8f9a | 1 8f9a (0)\n============ DEPTH: 8 ==========================================\n008 2 8e28 8e7b | 2 8e28 (0) 8e7b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","private_key":"c77c425da926ed3f45911d96e5d2ed01784a1e16987bbf8049d8c2b9a37eab26","name":"node_8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","services":["bzz","pss"],"enable_msg_events":true,"port":45075},"up":true}},{"node":{"info":{"id":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","name":"node_8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","enode":"enode://a6221058c98285416177d220a2f3ad4f8fad14bb72b226b6eca678a156da263ca8026a756a1e54ac812e6cf9db5279df4616c839b8d1d1f19a158783fcca1ad4@127.0.0.1:0","enr":"0xf88fb840c04a30337e262366540d7c35ecd07ff64b9083fd1f2b5195c205fda603295a375950c2ab3c8ab2fb2494ed5ca1346133fa181d56577a6918d49941fdaaed2cec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a6221058c98285416177d220a2f3ad4f8fad14bb72b226b6eca678a156da263c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g1inT8jY45zMQLTTohK3pppqj2r8Jc/yyce0S7r57II=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8358a7\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0d1c 1dc0 7c7c | 126 140d (0) 1484 (0) 1686 (0) 1784 (0)\n001 4 ef99 c534 cdb1 c8ea | 55 fa24 (0) f9de (0) f8ff (0) fc51 (0)\n002 4 b659 bcf8 bdc5 a8b5 | 37 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n003 5 9ec8 9c21 9464 9257 | 17 97da (0) 95c0 (0) 955d (0) 9518 (0)\n004 5 8862 8b43 8d19 8e7b | 9 8854 (0) 8862 (0) 8b43 (0) 8cc3 (0)\n005 4 84a9 8402 87a3 86d6 | 4 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n006 5 80d7 8006 8074 8073 | 5 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 837f | 1 837f (0)\n011 1 834f | 1 834f (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","private_key":"39642ed937f1adee6d9034810e644cf755f21dc9f06efda6535d19c78001af83","name":"node_8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","services":["bzz","pss"],"enable_msg_events":true,"port":32777},"up":true}},{"node":{"info":{"id":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","name":"node_a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","enode":"enode://6a681a2c60f7c7e2a832251ea4b54c1e7a75f5299e7a9bd343b3a8e6f147b41eb91a7fe95bd24adb2928b69018edf9eb146c92314b9d42964758449f767fb17a@127.0.0.1:0","enr":"0xf88fb84077f8314567599da083128579bdb43586da96cdd21d570ae4272c4a643ae5ef8d7bcc874624ab16e56b638270bf85aaabe97221c96f69bb9a7c487d9ad3c407880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a681a2c60f7c7e2a832251ea4b54c1e7a75f5299e7a9bd343b3a8e6f147b41e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qLWAE/+RGHHRqmwrvqbC5u+bALh7gKQdwEckrQSI4v8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a8b580\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 138d 1dc0 0d1c 7c7c | 126 1686 (0) 1784 (0) 140d (0) 1484 (0)\n001 5 f756 e2d3 e09f cdb1 | 55 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n002 7 9c21 93c0 9464 8ea2 | 38 97da (0) 95c0 (0) 955d (0) 9518 (0)\n003 5 b659 ba91 bea1 bcf8 | 14 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n004 4 a616 a742 a7a8 a1c8 | 13 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n005 3 acee af02 aeb4 | 3 af02 (0) aeb4 (0) acee (0)\n006 3 ab3f ab71 aaf0 | 3 ab3f (0) ab71 (0) aaf0 (0)\n007 1 a970 | 1 a970 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 a8ff a8f4 | 2 a8ff (0) a8f4 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","private_key":"8e39367b51358d04e71f5883ad1dbd70eee27b4ef493509df2377fbce04ad168","name":"node_a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","services":["bzz","pss"],"enable_msg_events":true,"port":33233},"up":true}},{"node":{"info":{"id":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","name":"node_7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","enode":"enode://57465744f0e2ac055f9d29be31e53d6939f20a6038e2c66834a7967ecc44341d90aa115fb5255fd137271f992d89629cbf514bbbd904c9b935e2068f22852fab@127.0.0.1:0","enr":"0xf88fb840b9d47b0a5d48db8adef386ac49f3dc8c9eb545bdd756d6d1ab18b92b1299e94a295d530c29791eaa0942296992e5b5e2de9b435fd1b0c1b9267fa049259b2a120183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10357465744f0e2ac055f9d29be31e53d6939f20a6038e2c66834a7967ecc44341d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fHylp1IqBPYvK+vWGXoD148lXQF1w9/OtdkraENlsqo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7c7ca5\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c8ea 8ea2 8358 a8b5 | 130 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n001 5 0d1c 19ea 1dc0 2fd2 | 65 1686 (0) 1784 (0) 140d (0) 1484 (0)\n002 4 5bd8 5987 50c1 5538 | 35 402c (0) 4005 (0) 435d (0) 43c9 (0)\n003 5 6d3c 6c01 648a 6795 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 4 7660 741a 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 3 79e5 7850 7895 | 4 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n006 1 7e47 | 1 7e47 (0)\n007 1 7d16 | 1 7d16 (0)\n============ DEPTH: 8 ==========================================\n008 1 7ce7 | 1 7ce7 (0)\n009 0 | 0\n010 1 7c46 | 1 7c46 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","private_key":"06b02c6e2c9d37cd4b50dedfe3e86594cbfd243d764ed379df53eb3392911dda","name":"node_7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","services":["bzz","pss"],"enable_msg_events":true,"port":37295},"up":true}},{"node":{"info":{"id":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","name":"node_c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","enode":"enode://585e9760962e0f911be40a1a465b83c6ad84f45a4e2b2f9e06640352970e28cd99d8e407c455e5e265f9bda6cd4b542223ff8c8bdc4964ea89d72298640b1284@127.0.0.1:0","enr":"0xf88fb840654b3875a2b357e41fb9bacc6e4de76b7aa6d3718a157dcb098ca478b61e9a350c90fb9a21b15df60c21decd1c97d75a9c0bde7641cde5b3736d54ea855f1cae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102585e9760962e0f911be40a1a465b83c6ad84f45a4e2b2f9e06640352970e28cd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yOpBd0IHhZJuCSlwH150x0SSA4bypDuJ2DyCgRBsuV4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8ea41\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 30fe 08f8 0d1c 1dc0 | 126 1686 (0) 1784 (0) 140d (0) 1484 (0)\n001 6 ba91 a8b5 8b43 8358 | 75 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n002 5 ff75 f1ed f756 ef99 | 28 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n003 3 da36 d700 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n004 5 c534 c42e c190 c2d0 | 8 c190 (0) c2d0 (0) c272 (0) c74d (0)\n005 4 cf52 cd6c cdb1 cc33 | 4 cf52 (0) cc33 (0) cd6c (0) cdb1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c961 c9c3 | 2 c961 (0) c9c3 (0)\n008 0 | 0\n009 0 | 0\n010 1 c8c8 | 1 c8c8 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","private_key":"00c912a815d056b04de18334e53d8facff8ea04075ae869401191b0c74503fe2","name":"node_c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","services":["bzz","pss"],"enable_msg_events":true,"port":44523},"up":true}},{"node":{"info":{"id":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","name":"node_87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","enode":"enode://7f46de8585a9766537267742cba2418426c637ca4c1973bac22d320ab3a432ed5e835edc53e2ab828ffd47c66137875d3b05da6577d637ab13bce3866fba58ef@127.0.0.1:0","enr":"0xf88fb840e4762001029c0140b891c3b53ef932dd40e210cccfd3fb490876ce81ae5275d766e2714b415a03bfc54f11d0392862d70f600927e39c35361191a937267f86c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037f46de8585a9766537267742cba2418426c637ca4c1973bac22d320ab3a432ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"h6M3YiRVrmXa86slVc7omF6aoUusJFVF2YUpYGDkqN4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 87a337\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5c7c 30fe | 126 43c9 (0) 43d4 (0) 435d (0) 402c (0)\n001 3 ef99 c534 c8ea | 55 fa24 (0) f8ff (0) f9de (0) fc51 (0)\n002 4 a8b5 bcf8 bdc5 ba91 | 37 a327 (0) a330 (0) a2e6 (0) a2a1 (0)\n003 6 9464 9257 93c0 9c21 | 17 9b8e (0) 9948 (0) 9959 (0) 9ca1 (0)\n004 3 8b43 8d19 8ea2 | 9 8854 (0) 8862 (0) 8b43 (0) 8cc3 (0)\n005 7 837f 8358 81a5 80d7 | 8 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n============ DEPTH: 6 ==========================================\n006 2 84a9 8402 | 2 84a9 (0) 8402 (0)\n007 1 86d6 | 1 86d6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","private_key":"0e812f155b3fec855e829701b7616d3bdc18fe020e679796ff10b79f74fce66a","name":"node_87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","services":["bzz","pss"],"enable_msg_events":true,"port":39229},"up":true}},{"node":{"info":{"id":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","name":"node_30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","enode":"enode://2d755da5dfdc21d6f3961f2beaab5613c412abd44276d5d050ef451b9bafb084a6afd797665c74c3ae6c0a33a52abf6c04504fd80a7fdd34ad91ffc3c671faae@127.0.0.1:0","enr":"0xf88fb8407a7294535524363392f62b42a82b13c5cfdfbc7e9e3710c54300cd606d41411000d4e002440679ca9f24fa5c4d8893f09f513ccde4545fa8b80580d1f46bf9360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022d755da5dfdc21d6f3961f2beaab5613c412abd44276d5d050ef451b9bafb084","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MP7KYx8GBByxTOrThN+qX/+m3DSwzuVCMO++FeVqWIQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 30feca\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c8ea e471 ba91 8ea2 | 130 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n001 8 48d7 5538 5bd8 5987 | 61 435d (0) 43c9 (0) 43d4 (0) 402c (0)\n002 8 046c 012b 025d 035f | 37 07f5 (0) 0561 (0) 0594 (0) 046c (0)\n003 3 2c85 244c 26ab | 11 2a50 (0) 298a (0) 2fd2 (0) 2e65 (0)\n004 4 3c5b 3938 3b02 3a62 | 8 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n005 3 36b9 3728 3411 | 3 36b9 (0) 3728 (0) 3411 (0)\n006 1 32ff | 1 32ff (0)\n============ DEPTH: 7 ==========================================\n007 3 3188 31e6 31e1 | 3 3188 (0) 31e6 (0) 31e1 (0)\n008 1 3051 | 1 3051 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","private_key":"0089202cbcad4ef35d5c4c18ac7f67f68b5c9f00a9ab8d1b7bfd57334bf95d95","name":"node_30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","services":["bzz","pss"],"enable_msg_events":true,"port":35121},"up":true}},{"node":{"info":{"id":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","name":"node_ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","enode":"enode://7a6e6ee730715ba07c013afa4adfa96b44af80ca9127d218d82b85f8f9a0f0d33a8650d3a482ab78523d91c1cf526d88087a2b352298ee29c2b060520436b2a5@127.0.0.1:0","enr":"0xf88fb84097647754d54945eb66061b25a00288c9cc9759b1b244c15785469f43e3cb3a1b0446356d42248da85d3b151c9d6ce61a9a8627dd5b6478e8e196150f8bf2b7ad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037a6e6ee730715ba07c013afa4adfa96b44af80ca9127d218d82b85f8f9a0f0d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"upERddOqP8wmbipaoy+3BiCLiptQIaXzfAuF9UfrN10=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ba9111\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 48f1 4a95 4b79 44ad | 126 435d (0) 43c9 (0) 43d4 (0) 402c (0)\n001 9 f215 e09f e471 d3e9 | 55 f8ff (0) f9de (0) fa24 (0) fc51 (0)\n002 5 9464 9ec8 8ea2 87a3 | 38 9b8e (0) 9948 (0) 9959 (0) 9ca1 (0)\n003 8 acee a970 a8b5 aaf0 | 23 a330 (0) a327 (0) a2a1 (0) a2e6 (0)\n004 3 b3f9 b5ea b659 | 6 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n005 4 bfc7 bea1 bcf8 bdc5 | 5 bfc7 (0) be68 (0) bea1 (0) bcf8 (0)\n============ DEPTH: 6 ==========================================\n006 1 b8e1 | 1 b8e1 (0)\n007 1 bbaf | 1 bbaf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","private_key":"455cfde9eb8d35e128fc05e1b1e697250397c4baa4d0609935427370e67e9567","name":"node_ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","services":["bzz","pss"],"enable_msg_events":true,"port":43089},"up":true}},{"node":{"info":{"id":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","name":"node_86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","enode":"enode://e11ad71a76ca345cb05b4689991a27df0d90136ab34404f7ac6659115281c0caebfb6c47af02b784a8dbd15632906ea81e935e5d68a0d818f86356d4098e2683@127.0.0.1:0","enr":"0xf88fb840ae4e55821d468925a34d498ef69d95cd2812772fc3333ffa4818f050f74bbe6c51618438af3372928bc751bc170fa31238feea5b167507551f583e2a8a15253d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e11ad71a76ca345cb05b4689991a27df0d90136ab34404f7ac6659115281c0ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"htb2jsC44bNAaUN4f5GL7nTdGCeZi9sT7Oj2kNotKWo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 86d6f6\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 1dc0 6790 | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 4 ef99 d3e9 cc33 c8ea | 55 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n002 5 a616 a1c8 a0c8 bcf8 | 37 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n003 4 93c0 9c8e 9c21 9ec8 | 17 9959 (0) 9948 (0) 9b8e (0) 9ca1 (0)\n004 4 8862 8b43 8d19 8ea2 | 9 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n005 8 81a5 80d7 8006 8073 | 8 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n============ DEPTH: 6 ==========================================\n006 2 84a9 8402 | 2 84a9 (0) 8402 (0)\n007 1 87a3 | 1 87a3 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","private_key":"462383c857370af2c4903fae5e5b3380ba12f14ac972e2a57fb03d60d53be99c","name":"node_86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","services":["bzz","pss"],"enable_msg_events":true,"port":34901},"up":true}},{"node":{"info":{"id":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","name":"node_67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","enode":"enode://9062625e5fd25e5b95d2fb131bd9836c17a278d08fd26d556c2ff3e82375b7739963d7dc46cf90a82a3ec3a51610de42e11daa5439de02fce2239d11c5100ca8@127.0.0.1:0","enr":"0xf88fb840a6e4f385ee971a0e10914ccd098a592003d39eb308e35914192339eeb67e99f505f75a47fe66fcd6baf71a8a5d2bb584480b07f6546f35ec5a1d7ef8a7d99f410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029062625e5fd25e5b95d2fb131bd9836c17a278d08fd26d556c2ff3e82375b773","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z5Cb3K7yMw7xIOUkx24eOCtHTzMy2G9lKCAo4FHzTHU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67909b\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c8ea cc33 8b43 86d6 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 3 30fe 035f 1dc0 | 65 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n002 10 4005 44ad 4a95 48d7 | 35 43c9 (0) 43d4 (0) 435d (0) 402c (0)\n003 7 70f6 7049 7660 741a | 13 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n004 2 6b4e 6d5e | 7 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 6758 | 1 6758 (0)\n009 1 67f3 | 1 67f3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 6795 | 1 6795 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","private_key":"e9d719353a6fb5bcae29ae98425718128b81ecc12560e8010bd8f63f2eedd79c","name":"node_67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","services":["bzz","pss"],"enable_msg_events":true,"port":42515},"up":true}},{"node":{"info":{"id":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","name":"node_8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","enode":"enode://6ab1e0f44fc24a1a9f01b103ed29a36d9344168d3760528da384ed0217fea7f37c77f54f1f91f510c0639c5aca4ad1eecba807e7643ac2426f92ac23617de8f0@127.0.0.1:0","enr":"0xf88fb840c6bf13d71510c296358d2e7025b910b959dd7cda4c3ab34d014fa342222ce5842055d0dcd799e79e004c9236268d6a1ed3c28eb4668ffe87b55b7c2f0c5054d60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ab1e0f44fc24a1a9f01b103ed29a36d9344168d3760528da384ed0217fea7f3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"i0MY+GrUeXYyGvl7+/lc0KOwqiJEeusGEe0am/HmpL8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8b4318\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1dc0 7049 6790 | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 4 d3e9 c2d0 c8ea cc33 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 2 a8b5 bdc5 | 37 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n003 7 9c21 9c8e 9ec8 9518 | 17 9959 (0) 9948 (0) 9b8e (0) 9ca1 (0)\n004 8 8358 81a5 80d7 8073 | 12 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n005 6 8d19 8cc3 8f9a 8e28 | 6 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n============ DEPTH: 6 ==========================================\n006 2 8854 8862 | 2 8854 (0) 8862 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","private_key":"5dedb1f9d69c2c6fe7a3aec668fac4e9c9615812829c7387000d87cbcd60aa41","name":"node_8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","services":["bzz","pss"],"enable_msg_events":true,"port":36035},"up":true}},{"node":{"info":{"id":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","name":"node_7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","enode":"enode://e430705ea5c1c11d55e6dc7d7738fc78a6b5e0b4b1833e6bd702d1227e5b8171505eb28c01546a2b0c9cffbc076b31b7bd1ee7f829b422bdae9b868a3d60055d@127.0.0.1:0","enr":"0xf88fb840bb450b66718c989ef173b71454ce6fcd33c94847190c06755cede1b16d7e05c551a88ba5700ef5828f74ded46693aaaf580f31c2249eff900c07824c8531d5a10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e430705ea5c1c11d55e6dc7d7738fc78a6b5e0b4b1833e6bd702d1227e5b8171","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cEnpKjljEfvy9KVbtb0v4/e7PBpj9Bu4jrgA7dRaxuU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7049e9\npopulation: 23 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 cc33 bdc5 8b43 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 2 30fe 1dc0 | 65 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n002 4 48b8 5bd8 5c37 5c7c | 35 435d (0) 43c9 (0) 43d4 (0) 402c (0)\n003 4 6c01 6790 6795 648a | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 7 7933 79e5 7850 7895 | 9 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 741a 7660 | 2 7660 (0) 741a (0)\n006 0 | 0\n007 0 | 0\n008 1 70f6 | 1 70f6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","private_key":"55f5ca8c609ad483be093fad4614abf484adc370763bf034321dc9b5d7bd8896","name":"node_7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","services":["bzz","pss"],"enable_msg_events":true,"port":40911},"up":true}},{"node":{"info":{"id":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","name":"node_1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","enode":"enode://3d69646df064c701b33bd040a7d35477e31bf7a56abb00bc2aead70938ab35f8399aaa1909e3c2bf41afc68a07292224110c8bc18d1eb5eb50df6b572361cd07@127.0.0.1:0","enr":"0xf88fb8408754060a82ff7e9fb41134faaa3a2ed4e6a5c27a819fc9fdd3aaaa0a1e74a1ba5f09b85c3433b0c3a49c7bfd7fdcaaf544be0a8e25ea79f8eeff4401c3fee5310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d69646df064c701b33bd040a7d35477e31bf7a56abb00bc2aead70938ab35f8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HcDvHOaNxoEpgXe96AivUU76UqWtOMnNK9YZaM3xnPs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1dc0ef\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 d3e9 c2d0 c8ea cc33 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 3 6790 7c7c 7049 | 61 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n002 6 26ab 3a62 3938 3c5b | 28 2ddf (0) 2c80 (0) 2c85 (0) 2fd2 (0)\n003 5 035f 025d 012b 08f8 | 21 096a (0) 0942 (0) 09b3 (0) 08bd (0)\n004 5 1784 1484 140d 1070 | 7 1686 (0) 1784 (0) 140d (0) 1484 (0)\n005 5 19ea 18e0 1add 1bd5 | 6 1add (0) 1bd5 (0) 1b1d (0) 18e0 (0)\n============ DEPTH: 6 ==========================================\n006 1 1fd0 | 1 1fd0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1dec | 1 1dec (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","private_key":"067a43a21c4c9595ff81c7c87cc15ed7b5c5e62d85308e2e0b77c52c27a5d30f","name":"node_1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","services":["bzz","pss"],"enable_msg_events":true,"port":42187},"up":true}},{"node":{"info":{"id":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","name":"node_bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","enode":"enode://fa6deb61cc0b3f0d346f0a5f28f03b1deeab9de673b4843fffd14b87704b7d97074be58116c187408d0bca73a025cd911274ff51c3837206884713fcb57b639a@127.0.0.1:0","enr":"0xf88fb8409b31a5f75a714e32770fb9bfb24b2603601041ca8d8b98f953a48f932ec9750404cbec7ff1a44c7e7a9f89af7fbb85bfaa9e92361eecb63512fa33798f3391b20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fa6deb61cc0b3f0d346f0a5f28f03b1deeab9de673b4843fffd14b87704b7d97","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vcXeASdhV6Dz/EOpzDtBssrMhHkRi3WuxLqbK3+obV4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bdc5de\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5bd8 7049 1dc0 | 126 435d (0) 43d4 (0) 43c9 (0) 402c (0)\n001 3 d3e9 c2d0 cc33 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 8 9464 9257 93c0 8358 | 38 9b8e (0) 9948 (0) 9959 (0) 9c8e (0)\n003 7 a0c8 a616 acee aaf0 | 23 acee (0) af02 (0) aeb4 (0) aaf0 (0)\n004 3 b3f9 b659 b4a1 | 6 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n005 3 b8e1 bbaf ba91 | 3 b8e1 (0) bbaf (0) ba91 (0)\n============ DEPTH: 6 ==========================================\n006 3 bfc7 be68 bea1 | 3 bfc7 (0) be68 (0) bea1 (0)\n007 1 bcf8 | 1 bcf8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","private_key":"129a7a69ba65fd74ba294f66ea025ca335d94c7a05e91aaf3c24cf3f9f7e0972","name":"node_bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","services":["bzz","pss"],"enable_msg_events":true,"port":42761},"up":true}},{"node":{"info":{"id":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","name":"node_cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","enode":"enode://3d2a0536cb0fb672ffcc469c8a71d4ff9b33a2b48e749c64d32c8fdf6c704e695b3d6699f04baf4e6299b694f36c309308f9fca69859148ae8c7ef71c20df4f1@127.0.0.1:0","enr":"0xf88fb8404f40bae7e0adcf8abafd249d8dad969a599ccb2f825ac5a56a8ef652452bfc1146f1510ab3db60fed9e49b1332c606423f169adf9c7841aead732652178119c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d2a0536cb0fb672ffcc469c8a71d4ff9b33a2b48e749c64d32c8fdf6c704e69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zDOX6eEfdSc9P4HZH5gPRQR1X4CyehgyEt5WzFCF5Y0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc3397\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 08f8 1dc0 6790 7049 | 126 3b02 (0) 3a62 (0) 3980 (0) 397a (0)\n001 6 93c0 8074 86d6 8b43 | 75 9948 (0) 9959 (0) 9b8e (0) 9ca1 (0)\n002 5 eb68 e471 e681 f215 | 28 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n003 3 da36 d700 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n004 4 c603 c42e c272 c2d0 | 8 c42e (0) c534 (0) c74d (0) c6a8 (0)\n005 3 c961 c9c3 c8ea | 4 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n006 1 cf52 | 1 cf52 (0)\n============ DEPTH: 7 ==========================================\n007 2 cd6c cdb1 | 2 cd6c (0) cdb1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","private_key":"617246021b48922c971765385e8d46d55d22849c49a2b2a58c9e108c53f08b6a","name":"node_cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","services":["bzz","pss"],"enable_msg_events":true,"port":44073},"up":true}},{"node":{"info":{"id":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","name":"node_5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","enode":"enode://81ccd85acd650e9264c02ea67a5c7743051afe4099a4013603c99b81cbc8ce3e18de1601c3e4bbe795262637c94798a502b7b87759c71bc9635c5f5763741ce3@127.0.0.1:0","enr":"0xf88fb84095b8956864f5e16f73f6caacda54957b5e3ab227e77c7b6a4f90d81ee18393e41d774af6765a97f6c71d2455d432959d81eb8a404400829bfacddf9d497112b20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10381ccd85acd650e9264c02ea67a5c7743051afe4099a4013603c99b81cbc8ce3e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W9j6+TvK0HAG6UJrRfXMWZ8ZY6t5HerE/2PWc5zWKhc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5bd8fa\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bdc5 cc33 c2d0 | 130 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n001 4 26ab 3728 30fe 138d | 65 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n002 5 7049 7660 7c7c 7ce7 | 26 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n003 6 4005 447a 44ad 4a95 | 19 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n004 4 50c1 5144 5538 5663 | 6 52a8 (0) 50c1 (0) 5144 (0) 56ca (0)\n005 2 5c7c 5c37 | 4 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n006 2 5814 5987 | 2 5814 (0) 5987 (0)\n============ DEPTH: 7 ==========================================\n007 3 5a8b 5ac0 5a26 | 3 5a8b (0) 5ac0 (0) 5a26 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","private_key":"26ef88a18d2d40a51bfabd66c6d93698f7fb8ae73c0efe4be8504f76081c7f85","name":"node_5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","services":["bzz","pss"],"enable_msg_events":true,"port":45545},"up":true}},{"node":{"info":{"id":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","name":"node_c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","enode":"enode://0d8d82144d964d2235866b8f1ed08a27c362598490e3745a6bbfa3ba90241e098abdaa05715666f02a4ac86fe384307431a69f83d66b3de2dfbe7b1d8f8bf374@127.0.0.1:0","enr":"0xf88fb84080a73499a87c86c9c8f7a3432690866a7941a3001f228e0dd3920b9848aae5f641db07c25860ddcc3124563fa497fa1137ee5f9ea9fa548e8c7b0756275e1fc40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020d8d82144d964d2235866b8f1ed08a27c362598490e3745a6bbfa3ba90241e09","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wtAMfZYBdMCTQSn9zsY1Jb+nKPePtwt8UgNrdy1il60=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c2d00c\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 08f8 1dc0 138d 48b8 | 126 3f31 (0) 3c5b (0) 3cab (0) 3980 (0)\n001 6 a616 b3f9 ba91 bdc5 | 75 acee (0) af02 (0) aeb4 (0) ab3f (0)\n002 4 ff75 eb68 e471 e681 | 28 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n003 3 da36 d700 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n004 4 c8ea cf52 cdb1 cc33 | 8 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n005 5 c534 c42e c74d c6a8 | 5 c534 (0) c42e (0) c74d (0) c6a8 (0)\n============ DEPTH: 6 ==========================================\n006 1 c190 | 1 c190 (0)\n007 0 | 0\n008 1 c272 | 1 c272 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","private_key":"f34329763f790689554fda7332d50df283663d26d6b7934322a4997f28ad4a70","name":"node_c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","services":["bzz","pss"],"enable_msg_events":true,"port":41949},"up":true}},{"node":{"info":{"id":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","name":"node_138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","enode":"enode://df33b1f0c1352c293d74d4b9b031141777ea5ea361a67862b312e14930160bea0489c08aac497214355e3c4702f1b31c1e74034f495d9cd59a19d893ce1d2bb4@127.0.0.1:0","enr":"0xf88fb840284f8900282f63e433dce06ae23eeb10839c72958e31168d974b1e3fad8efeab583f8ebc19fe0305c26f34560b4f16f2f246227220300c31ed1d2df4b58520dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102df33b1f0c1352c293d74d4b9b031141777ea5ea361a67862b312e14930160bea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E428FmLEzpsrMO9QNZFMxwRlZm/hjzEzGOZi0T8JliE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 138dbc\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a8b5 d3e9 c2d0 | 130 acee (0) af02 (0) aeb4 (0) aaf0 (0)\n001 4 7ce7 5c37 5c7c 5bd8 | 61 7660 (0) 741a (0) 70f6 (0) 7049 (0)\n002 7 3938 3b02 30fe 31e6 | 28 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n003 5 035f 0d1c 0e3b 08bd | 21 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n004 4 18e0 1dec 1dc0 1fd0 | 9 1bd5 (0) 1b1d (0) 1add (0) 194e (0)\n005 4 1686 1784 140d 1484 | 4 1686 (0) 1784 (0) 140d (0) 1484 (0)\n============ DEPTH: 6 ==========================================\n006 2 1049 1070 | 2 1049 (0) 1070 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","private_key":"fea6806c3b8e5f07d86ecd3870391f3145d05518f0f2da0b48ba753f8454ad24","name":"node_138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","services":["bzz","pss"],"enable_msg_events":true,"port":43695},"up":true}},{"node":{"info":{"id":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","name":"node_d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","enode":"enode://5c269acede83f81f0a59a02e10764ac1cef987f398a7ae38228c12862ac5a6aadfbc89c7e0a02ba60019ae7a855be61a68e2964a0d36632a798a8410cf28b6bd@127.0.0.1:0","enr":"0xf88fb84076ebf3a52c4ed0e3af7e5f134b50f6537548b5a9781344afa5a5a84989ae3fbb0912b048b5c21e7c318132d7e2fcb35a8cfc00997a6e63dd68dcd4919f7e321a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035c269acede83f81f0a59a02e10764ac1cef987f398a7ae38228c12862ac5a6aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0+kTz0p9q/tWmRMbZeUzpArbRuo34O1M6UM/mQFZhu8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3e913\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5c7c 1dc0 138d | 126 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n001 8 a616 ba91 bdc5 86d6 | 75 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n002 6 f215 ff75 e471 e681 | 28 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n003 9 c603 c42e c534 c272 | 16 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n004 2 d959 da36 | 6 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n005 2 d700 d408 | 2 d700 (0) d408 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 d209 | 1 d209 (0)\n008 1 d302 | 1 d302 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","private_key":"e8cb3c33050ebe9bd3e750e4b8f55fa35e538fd293395b06710db344fa8f480c","name":"node_d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","services":["bzz","pss"],"enable_msg_events":true,"port":45149},"up":true}},{"node":{"info":{"id":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","name":"node_5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","enode":"enode://7a0333ebcda5040e71cb74335af5f9434b53912b7918af8fddf3acbb2341a4091d7cbd9c4839061dd5390b11f0e988c24ac645003bca8092070c6d3f171ae68e@127.0.0.1:0","enr":"0xf88fb840e36636443db94a3278ad7e1c41abe6d90576990dca1c3b85c64f49472b0b4cfd029f18575656b1febfe27c53a79d62d703019939082d6a61fe480be68f9c63660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027a0333ebcda5040e71cb74335af5f9434b53912b7918af8fddf3acbb2341a409","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XHwVeY6G/nlLsgFhTUY2bqltxRCR9bGfFJmV4NQN8KY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5c7c15\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 87a3 d3e9 | 130 b78f (0) b6df (0) b659 (0) b5ea (0)\n001 2 138d 035f | 65 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n002 4 6790 7ce7 741a 7049 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 4005 4b79 4a95 48b8 | 19 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n004 4 52a8 5144 50c1 5538 | 6 52a8 (0) 5144 (0) 50c1 (0) 56ca (0)\n005 6 5814 5987 5ac0 5a8b | 6 5814 (0) 5987 (0) 5ac0 (0) 5a8b (0)\n006 1 5ff0 | 1 5ff0 (0)\n============ DEPTH: 7 ==========================================\n007 1 5d82 | 1 5d82 (0)\n008 0 | 0\n009 1 5c37 | 1 5c37 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","private_key":"bb0921c7331c6ee15280ac5573b08e824e5c7248b1e5539eefb80c55c8702459","name":"node_5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","services":["bzz","pss"],"enable_msg_events":true,"port":38107},"up":true}},{"node":{"info":{"id":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","name":"node_5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","enode":"enode://8f0560f5e755cbf619660e72ba73a02998bca53e860cbdcc69bee129bf16923258b851c65723649d670dbf0e1166f14cfdfe1cb8c8c73eb2906f20e78edcea8e@127.0.0.1:0","enr":"0xf88fb840d2ea5eb11567c49114dd285962beba545d8adecc62156b334bc08bd946887cad22435f4a2b2d944fd7a37cd1f8a7a27bbb6eed794505b3b5000a8f607a7502610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028f0560f5e755cbf619660e72ba73a02998bca53e860cbdcc69bee129bf169232","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XDcwNHcOQT5wCxzQOyA192ns2auOtU0y97JkW+GZH+U=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5c3730\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f1ed f215 f305 f756 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 6 3938 3b02 3a62 3c5b | 65 3f31 (0) 3cab (0) 3c5b (0) 3a62 (0)\n002 3 6790 7ce7 7049 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 8 447a 44ad 4005 4b79 | 19 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n004 4 5538 52a8 50c1 5144 | 6 52a8 (0) 50c1 (0) 5144 (0) 56ca (0)\n005 4 5814 5987 5a26 5bd8 | 6 5814 (0) 5987 (0) 5a8b (0) 5ac0 (0)\n006 1 5ff0 | 1 5ff0 (0)\n============ DEPTH: 7 ==========================================\n007 1 5d82 | 1 5d82 (0)\n008 0 | 0\n009 1 5c7c | 1 5c7c (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","private_key":"0c2c7d021de7510363cf5e2641eaa5f9378a5b212ffebbb2759c636e6eb1f581","name":"node_5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","services":["bzz","pss"],"enable_msg_events":true,"port":39663},"up":true}},{"node":{"info":{"id":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","name":"node_93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","enode":"enode://4fcf131746aae7e3b07348194ea8e617a5d50f3efacae7946f8ee5afc235f8ba437adfd9cd3411470f4cea27041ec717a816e46771aab4b057b191859ed04f79@127.0.0.1:0","enr":"0xf88fb8405f99513aca9b2504c8789a4395c454ad8201930dedfefb376fa80d8edb93790943b526ced56eb76753d377faf7819e9f2fa859c515903bb04604e0ba6d9a04bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034fcf131746aae7e3b07348194ea8e617a5d50f3efacae7946f8ee5afc235f8ba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"k8DhrfI/3xYjNZ64jFF7xSHVomMlVU34kMwEwfoXpd8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 93c0e1\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 035f 48b8 48d7 5c37 | 126 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n001 8 ff75 f756 e09f eb68 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 3 bdc5 a8b5 a616 | 37 b78f (0) b6df (0) b659 (0) b5ea (0)\n003 8 8cc3 8ea2 8b43 87a3 | 21 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n004 5 9c8e 9ca1 9c21 9f7d | 9 9959 (0) 9948 (0) 9b8e (0) 9c21 (0)\n005 4 95c0 9518 955d 9464 | 5 97da (0) 95c0 (0) 955d (0) 9518 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 9257 | 1 9257 (0)\n008 0 | 0\n009 0 | 0\n010 1 93ea | 1 93ea (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","private_key":"e9b9e5f77b823f754cc953b6e8bb3f29875b25f3f07294dc648aad09741eae5d","name":"node_93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","services":["bzz","pss"],"enable_msg_events":true,"port":39455},"up":true}},{"node":{"info":{"id":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","name":"node_035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","enode":"enode://a2ea0d984eb8c2a044d8d57b6b34ac49f7e319cd0ce8c9ad882e352f681e73bf1212f8c9b4155d9413384324db4dc6e0430b23bd9ebe32dc3694d927c34e07ef@127.0.0.1:0","enr":"0xf88fb84021c14a87840a5a62b181c58ce71769ae7998b9182a812551fba5dd2798c30a6228770d3463f5bd7428e5f81dd35ce8f649571ec472eb1f870a82386058e3756a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a2ea0d984eb8c2a044d8d57b6b34ac49f7e319cd0ce8c9ad882e352f681e73bf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A18VSZzbDwebPjWK1UphImgUQqUpPDri/fbFJwBLNtI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 035f15\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a616 8074 93c0 | 130 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n001 4 6790 7ce7 5c7c 5c37 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 2 30fe 26ab | 28 3f31 (0) 3cab (0) 3c5b (0) 3a62 (0)\n003 5 138d 1784 1484 1dc0 | 16 18e0 (0) 194e (0) 19ea (0) 1bd5 (0)\n004 3 08bd 0d1c 0e3b | 11 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n005 3 07f5 0594 046c | 4 07f5 (0) 0561 (0) 0594 (0) 046c (0)\n006 3 0191 012b 0111 | 3 0191 (0) 0111 (0) 012b (0)\n============ DEPTH: 7 ==========================================\n007 1 025d | 1 025d (0)\n008 0 | 0\n009 1 0314 | 1 0314 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","private_key":"595254b7c40bf18ec4d789cf500b58c5850ad2f21460f58230cd8e53b428c0bb","name":"node_035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","services":["bzz","pss"],"enable_msg_events":true,"port":41613},"up":true}},{"node":{"info":{"id":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","name":"node_807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","enode":"enode://4ae810f37f174c8ffe4c90d5590e2bdc3677a1f413738a94776bbe63f1f45b08043188e3f2366b245c0e285f02ac759329e37760bc3c797ba7d70479dd8f9490@127.0.0.1:0","enr":"0xf88fb84006c5b23f700d5d387dc4a8d96c97cb9b9415cce70e955133a5f006e2b37011047da680b267227e5646409503737c6d382fa97364e60c24095320efbca3056ac70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024ae810f37f174c8ffe4c90d5590e2bdc3677a1f413738a94776bbe63f1f45b08","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gHQWzHDwLUgaGIAn95MrSOj3teglj36WI/P24phdj2o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 807416\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 48d7 48b8 7ce7 035f | 126 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n001 3 eb68 cc33 d3e9 | 55 f305 (0) f2b4 (0) f215 (0) f1ed (0)\n002 2 bdc5 a616 | 37 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n003 4 9ec8 9c8e 9257 93c0 | 17 9b8e (0) 9959 (0) 9948 (0) 9c21 (0)\n004 5 8cc3 8e7b 8ea2 8862 | 9 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n005 4 8402 84a9 86d6 87a3 | 4 87a3 (0) 86d6 (0) 84a9 (0) 8402 (0)\n006 3 837f 8358 834f | 3 837f (0) 834f (0) 8358 (0)\n007 1 81a5 | 1 81a5 (0)\n008 1 80d7 | 1 80d7 (0)\n============ DEPTH: 9 ==========================================\n009 1 8006 | 1 8006 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 8073 | 1 8073 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","private_key":"421902540a521af21b446884bc2ff3f606e8e7814ffad298bdb1200502aa73f8","name":"node_807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","services":["bzz","pss"],"enable_msg_events":true,"port":37835},"up":true}},{"node":{"info":{"id":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","name":"node_a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","enode":"enode://51ff87ed33ddf13e429d933fa411ad53dfdaf4f83d2d156ee20fc759f1900fbe70b000ad9891f8a5e79fa93673839682c50273f4012eae003b40c8bef34e0542@127.0.0.1:0","enr":"0xf88fb8402fd3e3ba496c67f81c4704bbedcb048e9985d8e2fa0d26e8aadf582cc5bdab7428098d781ee942ecc983bd6c645ee494759d9fc3aacc50957db0ac276b93ea8c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10251ff87ed33ddf13e429d933fa411ad53dfdaf4f83d2d156ee20fc759f1900fbe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"phZaSwLVi+EWiSmCwO09Sdhv7A6fQ2pRa2GGgzHthT8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a6165a\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 035f 1fd0 48b8 7ce7 | 126 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n001 5 ff75 e681 eb68 d3e9 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 7 9c8e 9c21 9257 93c0 | 38 9b8e (0) 9959 (0) 9948 (0) 9ec8 (0)\n003 4 ba91 bdc5 bfc7 b3f9 | 14 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n004 6 acee aeb4 aaf0 ab71 | 10 af02 (0) aeb4 (0) acee (0) ab3f (0)\n005 4 a2e6 a330 a1c8 a0c8 | 6 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n006 2 a5ac a505 | 3 a4ee (0) a5ac (0) a505 (0)\n============ DEPTH: 7 ==========================================\n007 2 a742 a7a8 | 2 a742 (0) a7a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a606 | 1 a606 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","private_key":"f8b37704a0eba9987c7cbd4d718ee3eba88b7d76957c5043be17f16e8408c442","name":"node_a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","services":["bzz","pss"],"enable_msg_events":true,"port":45387},"up":true}},{"node":{"info":{"id":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","name":"node_7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","enode":"enode://ff883ea700704e0d06c059393d1c9c79298f0ff8bd3a806cf777c1b1643539f79b58a73e57a76b7e4631b6f6d224a263b3da5a4029565cd811d1cfba392b16d0@127.0.0.1:0","enr":"0xf88fb84094a7b14977397bf60c09a538d9206bfbb260df1994b06df0a747d58e5b0d17562803bb201f443f5b17d527f875f5c9185455b13bf3aa0789206b83bb9dfb71c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ff883ea700704e0d06c059393d1c9c79298f0ff8bd3a806cf777c1b1643539f7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fOf+yDOi6MdyD8yX+CDyyirKhTiCEPiHw+/niwIHZuc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7ce7fe\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8074 a616 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 4 26ab 138d 1fd0 035f | 65 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n002 5 5538 5bd8 5c37 5c7c | 35 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n003 4 6c01 648a 6795 6790 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 4 70f6 7049 741a 7660 | 4 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n005 4 79e5 7933 7850 7895 | 4 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n006 1 7e47 | 1 7e47 (0)\n007 1 7d16 | 1 7d16 (0)\n============ DEPTH: 8 ==========================================\n008 2 7c7c 7c46 | 2 7c46 (0) 7c7c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","private_key":"60cd3f72a03ac58379a8c6ba81e19265da277316a0e01fa3876bc4c92ff49df6","name":"node_7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","services":["bzz","pss"],"enable_msg_events":true,"port":41789},"up":true}},{"node":{"info":{"id":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","name":"node_48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","enode":"enode://707261d403a5192568c194162fd61ffccb0cde756d06d2eb7c117b0160f7ad528446db8695b53393c6b20ec9fa5a555d5a341980d106865e9527566d32b9bb54@127.0.0.1:0","enr":"0xf88fb840bb9ab177f3ef6ff14610eb47e7168572b6f01f94f263f707915fc7ea3d9af0f5468fc44ff2210116cbcf0bfbae738979e4a3cfee6ddecd0e4abac50af13eb92c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102707261d403a5192568c194162fd61ffccb0cde756d06d2eb7c117b0160f7ad52","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SNeaxV+N9RKvjn2GiqQKybYUk/pPGwzgt2v22i6zDng=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48d79a\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a970 8074 93c0 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 3 30fe 26ab 1fd0 | 65 3980 (0) 397a (0) 3938 (0) 3a62 (0)\n002 4 6c01 6790 70f6 7ce7 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 5538 50c1 5987 5bd8 | 16 52a8 (0) 50c1 (0) 5144 (0) 56ca (0)\n004 4 402c 4005 46bf 44ad | 9 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n005 2 4cec 4d91 | 3 4cec (0) 4d38 (0) 4d91 (0)\n006 2 4b79 4a95 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 1 48b8 | 1 48b8 (0)\n010 1 48f1 | 1 48f1 (0)\n011 0 | 0\n012 1 48de | 1 48de (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","private_key":"332189f434da38340438c9e98fbf7e82e2cf6bc241b9b8689f12514555c995d7","name":"node_48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","services":["bzz","pss"],"enable_msg_events":true,"port":41935},"up":true}},{"node":{"info":{"id":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","name":"node_48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","enode":"enode://b19c0ae1cb81e68f5f80d6b0ca2e30109c2fd797df00404cd2c70f4b0b22a45a3316d279f68f3d211584bf955fad3326cbf8ccc1c5b4de9f4d34671d033b9aef@127.0.0.1:0","enr":"0xf88fb840cfce87968b891140a7b5398ce7c46c9e55da927db6b676d5150b5d1d5808a0160675b0905f993242da939cc4bd9d3a8ce303209b3442c1a398dbc1c58abe8ede0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b19c0ae1cb81e68f5f80d6b0ca2e30109c2fd797df00404cd2c70f4b0b22a45a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SLhQl0V1ylejzF+aTPWq/YaIyzK5k/aZg+zmMlj/h24=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48b850\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c2d0 e681 eb68 93c0 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 2 1fd0 1784 | 65 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n002 5 6790 7660 741a 70f6 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 5 5538 50c1 5987 5c37 | 16 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n004 4 44ad 447a 46bf 4005 | 9 43c9 (0) 43d4 (0) 435d (0) 402c (0)\n005 3 4d91 4d38 4cec | 3 4d38 (0) 4d91 (0) 4cec (0)\n006 2 4a95 4b79 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 3 48f1 48de 48d7 | 3 48f1 (0) 48de (0) 48d7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","private_key":"dad03259c72bb0ab9ef830e43beb607d0933e8ceab8af57177cdedcccaa94838","name":"node_48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","services":["bzz","pss"],"enable_msg_events":true,"port":34161},"up":true}},{"node":{"info":{"id":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","name":"node_178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","enode":"enode://27897e5bff2021adf7dfc30beeae2d45dee4a331f85ccd2c611ff0df21a46f37373f49a11c7484953162778e229db0f12c587b97e449759086b0d9573e0c1a26@127.0.0.1:0","enr":"0xf88fb840429dfb2ce19f2d10de9df91da52260207acd7bcdb6f38055772e416e732174ee29384cd41078dbe55437ddf28a305fdb26b8fbe9c5f95c36514330d2055b27bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10227897e5bff2021adf7dfc30beeae2d45dee4a331f85ccd2c611ff0df21a46f37","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F4QB7I0BoKT1UdI+iAqOik64d3NWU2OEPVHPUmYLEhE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 178401\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e681 eb68 9257 a970 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 2 741a 48b8 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 4 3c5b 36b9 3728 26ab | 28 3980 (0) 397a (0) 3938 (0) 3b02 (0)\n003 8 012b 035f 025d 0d1c | 21 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n004 4 1add 1dec 1dc0 1fd0 | 9 194e (0) 19ea (0) 18e0 (0) 1bd5 (0)\n005 3 1049 1070 138d | 3 1049 (0) 1070 (0) 138d (0)\n============ DEPTH: 6 ==========================================\n006 2 140d 1484 | 2 140d (0) 1484 (0)\n007 1 1686 | 1 1686 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","private_key":"354ee66c6897d2e2295d1c694b61628074a9697102dde529318baa2cbc0c698c","name":"node_178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","services":["bzz","pss"],"enable_msg_events":true,"port":34553},"up":true}},{"node":{"info":{"id":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","name":"node_1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","enode":"enode://a6d82f53e41ccd91583fbd89ab6dc5ca9ea1e1c8cf32336f3850d7abd7b67c12d26f485949244e17e996848469b10582ae14d19bba53fa22af1a289e2098fa2f@127.0.0.1:0","enr":"0xf88fb840011b8900371589a6bdc15199784c217ccdb148656c9cf6f7aeaaa2e96dc963a93ee8ad5c8509e66f007be32b90ca078bbc6d9e655df8ce0fa1a1ff258d3599cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a6d82f53e41ccd91583fbd89ab6dc5ca9ea1e1c8cf32336f3850d7abd7b67c12","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"H9AZLfH78zdxylda+7TifGVBzOSjz/LfwfLAhef6t54=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1fd019\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e681 eb68 a616 a970 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 4 741a 7ce7 48b8 48d7 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 4 36b9 3728 2c85 26ab | 28 3980 (0) 397a (0) 3938 (0) 3b02 (0)\n003 7 012b 025d 035f 0e3b | 21 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n004 4 138d 140d 1484 1784 | 7 1049 (0) 1070 (0) 138d (0) 140d (0)\n005 5 1add 1b1d 18e0 194e | 6 194e (0) 19ea (0) 18e0 (0) 1bd5 (0)\n============ DEPTH: 6 ==========================================\n006 2 1dec 1dc0 | 2 1dec (0) 1dc0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","private_key":"56799ffc0f8172319a5acee54229b310b2ee9bfcff23054e163d25ebd6b74da6","name":"node_1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","services":["bzz","pss"],"enable_msg_events":true,"port":33911},"up":true}},{"node":{"info":{"id":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","name":"node_26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","enode":"enode://cec920dd405d44d0b1e52e29040cb654a1fe80dc3bf4484ebbc8480cb43d5f0cb060aa4e8ede415db0b1d08a220d5ab4add6b38d42d7aa794db434ff9dda1697@127.0.0.1:0","enr":"0xf88fb840b1a4300c5cadd86b2b219a1044bd3e44834ca1f0053ee7a3e3e45f15100dbe35044cd77a522de4160bbe65b9c8ac4ab26c6a20c7d8a3c037e4e6694d1eb38e6d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103cec920dd405d44d0b1e52e29040cb654a1fe80dc3bf4484ebbc8480cb43d5f0c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JqucgTgi27TxojDNjpnoqygLJCdH3rVf35PRYJBu8zE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26ab9c\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c534 ff75 e681 eb68 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 5 7ce7 741a 5bd8 4a95 | 61 6b4e (0) 68cb (0) 6e7f (0) 6dd3 (0)\n002 11 08bd 08f8 0e3b 012b | 37 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n003 11 3cab 3c5b 3938 3a62 | 17 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n004 6 2a50 298a 2fd2 2e65 | 7 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 24f8 244c | 2 24f8 (0) 244c (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 26ac | 1 26ac (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","private_key":"9d39b98cb0569ba31464e7827579e71e40dae5f366d3dfe5cbb197a9f825dbd4","name":"node_26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","services":["bzz","pss"],"enable_msg_events":true,"port":42047},"up":true}},{"node":{"info":{"id":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","name":"node_a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","enode":"enode://a74db2e9fc46ed2ad19743b773f0021b88e21cac389189ca1350aaecaf010fcd452f1991fb38c3d65a3745547b26e6dc0f655d75fd397cfef0fa286823e10b50@127.0.0.1:0","enr":"0xf88fb84002a5006b493d814889934b13a2e3714a6712f571e88ff5139d96e40cc1bcb6d719aba5a3169f334698e6273dfb9e8c3ed5234b18da0cfd2edf656396d0d92fcb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a74db2e9fc46ed2ad19743b773f0021b88e21cac389189ca1350aaecaf010fcd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qXADCFFsAs+a6ogJAApOBZbWtEdT4QvQko34Pi65uec=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a97003\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 48d7 1784 1fd0 26ab | 126 5663 (0) 56ca (0) 5538 (0) 52a8 (0)\n001 2 eb68 e681 | 55 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n002 6 84a9 8402 9c21 9c8e | 38 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n003 5 b3f9 ba91 bfc7 bcf8 | 14 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n004 2 a0c8 a616 | 13 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n005 3 acee af02 aeb4 | 3 acee (0) af02 (0) aeb4 (0)\n006 3 ab71 ab3f aaf0 | 3 aaf0 (0) ab3f (0) ab71 (0)\n============ DEPTH: 7 ==========================================\n007 3 a8f4 a8ff a8b5 | 3 a8f4 (0) a8ff (0) a8b5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","private_key":"89ebf8f655338d3ee03b70fce8b3206157e3e198a2c1e6511944e7ba76672303","name":"node_a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","services":["bzz","pss"],"enable_msg_events":true,"port":40557},"up":true}}],"conns":[{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_3.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_3.json index 38ce68f3..15ed45bc 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_3.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_3.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","private_key":"e567b7d9c554e5102cdc99b6523bace02dbb8951415c8816d82ba2d2e97fa23b","name":"node01","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","private_key":"c7526db70acd02f36d3b201ef3e1d85e38c52bee6931453213dbc5edec4d0976","name":"node02","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","private_key":"61b5728f59bc43080c3b8eb0458fb30d7723e2747355b6dc980f35f3ed431199","name":"node03","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","other":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","up":true},{"one":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","other":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","enode":"enode://6a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f9757875b6b8d02f88fafe3fd7f20f0349a0060ace7c0be1d65470e736a3319431b5c14@127.0.0.1:0","enr":"0xf88fb84096f5dd9030fc74da3701ef7b06dfe4d44068118f8041a728876904d70fa8c88c20df197c343522c76d75d3a12507c567213c13b46a94ed4800f47474643f4ee70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f975787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/TfkUhDds2+LXs75ydnT+CAbqVI7/WpwKRMzzzuSB+E=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fd37e4\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 1 3594 | 1 3594 (0)\n001 0 | 0\n002 1 cb08 | 1 cb08 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","private_key":"6a02f87b1d13a15ce24bfa58456af8aaabdcf8cb58b9f86c19ab14c721c80f91","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","services":["bzz","pss"],"enable_msg_events":true,"port":39341},"up":true}},{"node":{"info":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","enode":"enode://0972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03397efbad98888f8d740b7cf55c357d1d6d74b5e8cb935f71b19e0e16ceef03f9@127.0.0.1:0","enr":"0xf88fb840d5f39b1ebcd5b616ef67b1c0239ed4501ef45c6a00e5bd8cd3f2ac88870d4c4b6ce4a4af820afab9a714d99a5fef53ec3c042fc3243f403819bcfb3504c2150d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NZRDinSApcPcBkQOKKFgRMDH0okhnaAvnkHaGBCCeAU=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 359443\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 fd37 cb08 | 2 fd37 (0) cb08 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","private_key":"26266470b7f4e9341cbbbb304b1aed116626cb1bea55d639cdbef1a069c18123","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","services":["bzz","pss"],"enable_msg_events":true,"port":33055},"up":true}},{"node":{"info":{"id":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","name":"node_cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","enode":"enode://046f757c2632f0fbdb74f73ce67be9cf181f85a6d2a8ec0d5e8a329a8ede81fe476bb5a1e5896b9ce49201ec4a32561bbbe91ab46eb9f7d99bb9a0002df3a639@127.0.0.1:0","enr":"0xf88fb84022bde12be56af73a7793d7ffe9f22d205a7540d6cc337815697115edeafcc1d461427c8cdee33e602201d3b2dfac034b567a8270e5f0c8b3fe29e10883f4b1e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103046f757c2632f0fbdb74f73ce67be9cf181f85a6d2a8ec0d5e8a329a8ede81fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ywipNV85ulXmoasCQQQCFppjAINUErqkveBJo/oUQ70=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cb08a9\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 1 3594 | 1 3594 (0)\n001 0 | 0\n002 1 fd37 | 1 fd37 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","private_key":"52fd9e67692ef0963c13052f85f88eac3a527cd50137e4c0a75ebc8ad471b8af","name":"node_cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","services":["bzz","pss"],"enable_msg_events":true,"port":38675},"up":true}}],"conns":[{"one":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","other":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","up":true},{"one":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","other":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","up":true},{"one":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","other":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_32.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_32.json index c33cc6e1..05a40b2b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_32.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_32.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","private_key":"294c55925f084f4af87c7e09716c6334a538bac3e6b7157844c0c96a9dd02b4a","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","private_key":"010dbe172f1240848fae9639e029301ebd297b29ad2d6936c67669d23470cee4","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","private_key":"7f974cee5ec96d070bf88898c24035988667ea21242a02822bccbe4ec487d126","name":"node03","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","private_key":"d7e181b51ba95fd1475314470468045205d7ddefb1bbecfda3340267062489d1","name":"node04","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","private_key":"87ed3ffe3111baec0adfd92068b47ed9e1efb642d0ff3115d7d76338f25eea76","name":"node05","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","private_key":"7dbb4fe973c714c4291ce5a8aedce9c3425a25cdecfd5fe0c7f14b55e91d6a03","name":"node06","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","private_key":"6f8900888d42ea5340f13634776acfd4a261837cdb772b9a059b23c7d425da1d","name":"node07","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","private_key":"a94698db3c1a809d255fedabcb4f3314be27cad7be63cda59bb71724d24ca0d9","name":"node08","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","private_key":"37f683b58015f6a7ce73f814fc3860318bb2048052356a215f9eff00aa6ed34b","name":"node09","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","private_key":"b27bdea692559a2a77d497ee567e972e033d4e6e5dfb7c35948a9d231c25b0e0","name":"node10","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","private_key":"0a75e7e7dfabf4ee693bfe127221c97eb9b2f4e19d32f7bc836ba253445358d7","name":"node11","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","private_key":"1557c4754c71e6468fae0c7d0e1b5af2cf70511ed2d5d9b0bc276315a4c8f922","name":"node12","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","private_key":"d2b18f4edef23f629bc5624a36ac1d58f59207bf7de0b19220f90fc3c64b5a61","name":"node13","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","private_key":"48fe56dfc63a454ab004e7a5dc7938e29694377b6bcc27d1c19d8a72349a8c2d","name":"node14","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","private_key":"9155d38d2a2bbe1e5239f9993d96a350182e3840813436e23e1f2a4a9a32b7d9","name":"node15","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","private_key":"e60772916c9d248e3a3819de52aacdd4008412aab20a457e88e764752679b8f8","name":"node16","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","private_key":"e7f27ccf343d2124211ba980dfe8ee7e774a5956268a25522347bb3be99bf38e","name":"node17","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","private_key":"0e9cb88a7d70a04f0780ea51e001aabda0830f504e29e31c69d859acce0a9019","name":"node18","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","private_key":"cf8362e06e18a783f7e20baf956d40e2ea4a204ec868f8d34909802af222e997","name":"node19","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","private_key":"9a63fae9e77f9cfdc30f4747a939ba44e85824560d98b49047bfa8f4156d426c","name":"node20","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","private_key":"748efd85864661c429fd70a74bc32f1d81685bd81927c1499dbd93993dc27cad","name":"node21","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","private_key":"fed7bc6fd67e331e642253e604215ba088daa48a1b84979699ad770c09b909dd","name":"node22","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","private_key":"c61c4e9235825e60f2d8c57169e7d1913f45b057f298ba8fb05d51515e92a902","name":"node23","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","private_key":"53704ffbabad329a9032a58cd7ec012499b0a521bb0300e1d7160d4e5d1220fd","name":"node24","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","private_key":"7098a0386bb10a213728ea65f3ca98fd25a31daf3917190f6a1889d350e09674","name":"node25","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","private_key":"e967b2c9db78764c1ce024423c48e170b68fb6232c313a32133faf4936e2c114","name":"node26","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","private_key":"f8cf717ad5b26578e58a97eddc6074cebb814cdaf3f4144acbafcce51ccbd249","name":"node27","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","private_key":"e6573973825826d193b5093ec610c34368630376e4e13843e5f2203c3ca88fa9","name":"node28","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","private_key":"0ff9df0f439480bc31f8a3ae593af2662bad0f5bd4e0c3e87839af326929de07","name":"node29","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","private_key":"1daf1094602b9234a1651a8ba6013a807d9c0d56339c784d618e2c6705b65e23","name":"node30","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","private_key":"376cc1c769c48c4a04f3f1447fe31112cdbc8d898266a338f6675906511bc9c6","name":"node31","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","private_key":"6a9a93cae21630926926ece339463ca165823f499f47d45632dbe1a49a84257c","name":"node32","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","other":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","up":true},{"one":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","other":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","up":true},{"one":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","other":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","up":true},{"one":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","other":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","up":true},{"one":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","other":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","up":true},{"one":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","other":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","up":true},{"one":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","other":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","up":true},{"one":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","other":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","up":true},{"one":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","other":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","up":true},{"one":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","other":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","up":true},{"one":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","other":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","up":true},{"one":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","other":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","up":true},{"one":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","other":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","up":true},{"one":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","other":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","up":true},{"one":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","other":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","up":true},{"one":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","other":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","up":true},{"one":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","other":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","up":true},{"one":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","other":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","up":true},{"one":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","other":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","up":true},{"one":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","other":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","up":true},{"one":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","other":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","up":true},{"one":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","other":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","up":true},{"one":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","other":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","up":true},{"one":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","other":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","up":true},{"one":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","other":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","up":true},{"one":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","other":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","up":true},{"one":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","other":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","up":true},{"one":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","other":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","up":true},{"one":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","other":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","up":true},{"one":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","other":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","up":true},{"one":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","other":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","up":true},{"one":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","other":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","up":true},{"one":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","other":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","up":true},{"one":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","other":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","up":true},{"one":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","other":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","up":true},{"one":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","other":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","up":true},{"one":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","other":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","up":true},{"one":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","other":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","up":true},{"one":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","other":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","up":true},{"one":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","other":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","up":true},{"one":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","other":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","up":true},{"one":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","other":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","up":true},{"one":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","other":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","up":true},{"one":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","other":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","up":true},{"one":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","other":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","up":true},{"one":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","other":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","up":true},{"one":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","other":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","up":true},{"one":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","other":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","up":true},{"one":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","other":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","up":true},{"one":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","other":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","up":true},{"one":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","other":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","up":true},{"one":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","other":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","up":true},{"one":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","other":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","up":true},{"one":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","other":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","up":true},{"one":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","other":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","up":true},{"one":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","other":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","up":true},{"one":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","other":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","up":true},{"one":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","other":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","up":true},{"one":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","other":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","up":true},{"one":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","other":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","up":true},{"one":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","other":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","up":true},{"one":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","other":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","up":true},{"one":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","other":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","up":true},{"one":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","other":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","up":true},{"one":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","other":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","up":true},{"one":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","other":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","up":true},{"one":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","other":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","up":true},{"one":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","other":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","up":true},{"one":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","other":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","up":true},{"one":"0c14562578ab9796c635d1e5b713bc966341f6e742acd4a8a93a524cadd669eb","other":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","up":true},{"one":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","other":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","up":true},{"one":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","other":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","up":true},{"one":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","other":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","up":true},{"one":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","other":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","up":true},{"one":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","other":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","up":true},{"one":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","other":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","up":true},{"one":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","other":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","up":true},{"one":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","other":"3efb0d9530c931c9e47c6ff622c8ad695cbfad216cd9a2b4268c8c3763ffaff0","up":true},{"one":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","other":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","up":true},{"one":"461dc187c3911fd12829fb3168b68135e3208771d385324434e8ca7ecf72b2e2","other":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","up":true},{"one":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","other":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","up":true},{"one":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"ea5ae8b639fa80db684c774d814b7e9cff0cf9622427dae35239cc84c1b7dabc","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"59b214370ca7c60bcda95a18d2b668519ef8ee53af9e4a677f1981defe79d4a7","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","other":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","up":true},{"one":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","other":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","up":true},{"one":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","other":"9ea072155528aaca8fef7a25af26134898b65aed2464dbaa397235cb96f7cd15","up":true},{"one":"3efa59309f968ab20e053836f01e0d8b4c9e777063a73e871cab86c1fe6a0159","other":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","up":true},{"one":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","other":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","up":true},{"one":"0a5cc796e733b06866b67ec3652e41a03a0c03707fed56b767ca5cbfe3828b35","other":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","up":true},{"one":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"81449fb850a7c2713784bc938da3e1573d92e93dfd88199e8d877746b6c260af","other":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","up":true},{"one":"8b72d2a8665d545aae43b317a20f51af80357b290e826822309d9a1dc67a4470","other":"e9bcffd8355af43dfe4ec4415e77a92f6f6897f9c6bc78f31281346cd460cd34","up":true},{"one":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","other":"46599aa9671556263a5e5818575b8a12e7c755a44f9dac7873c1c48f33c1465e","up":true},{"one":"58ebac47c884e77049a6c9c851ffb1e74622d27be8e30117f1f775391ac27717","other":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","up":true},{"one":"fbe2f731b4bcdbf8490ba7599a011f561ec6a46c95bc9a34effaf29c91085c09","other":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","up":true},{"one":"f1e3713691f9088c72295658b7e887d83058c668495830c63c0241716c9cae80","other":"8939636008ec2eec222bd490ab86b42f9ef1fee7e41a32c70deb676920c3454a","up":true},{"one":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","other":"c3863946fb7d43a75cbe2503fa301a4a20cf65caac1dfcbe5fafa2d873a5c6e5","up":true},{"one":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","other":"c6b69d856ec8ac1822b4a1d54f8d3bc44831bcd20fbb5c8f8c67b68b33541fe9","up":true},{"one":"0b07a13f12316594013fb220a14910c9aec9446274b6e9f89da3bf1f5732624b","other":"3a268a0db7e8b31d4b362ecb598f3e549a2aa59392591b4d2f2ba37e6ceb72b3","up":true},{"one":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","other":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","up":true},{"one":"0688bd16330526285a532b2ee34a92075487d93938e2789e324ccb583af7956a","other":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","up":true},{"one":"211b73ccd445df519b8afabb07b3b590f3594f01715abca8f9cc7fade33f75ba","other":"7f25ae980b4aeac041d8bd17a8a4140f762aca78710cfd2fb41f8d91d713e4df","up":true},{"one":"55b8a5f2d199cc115b9d0978458444983137888591b0e91016cc2f75ce593a41","other":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","up":true},{"one":"175e3bbbfc70b443adf887386485a4c0171df26edaf7b44c32e430fc37b830d3","other":"02f7b6240d3c3990559d296355bb86f40162fee7a45c2e092eb90277266ecbd8","up":true},{"one":"5e883de2318b4355140edb00a60db79ddc16e0dabec47cd34e2a2b175e198711","other":"41de70b44e7b0b0670d42f0ae348bc6501cef8b4174a6c6d9986645cd5e47aaf","up":true},{"one":"de8f114621b53a5a68dfc1870600c60bf9912ad4d36458e52606ab27a6d7c3fa","other":"8564a53752aa3e7edb8e09c3ad61b765ce5abd2ad9c5cb63bfa036930d6de244","up":true},{"one":"dcf5d113ddf39e516a3871a31843da3cd7740daa2a8f4827265a3d9bfaa3b402","other":"cd92d92973dc25f623e4492a165f8a8b043e9dd959ca498aa7c6e82ec8038d54","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","name":"node_2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","enode":"enode://6e710e572097f299c352e4e1b8a2980de9e6d2cba35fc6b05623ed829c722148861d96fef1530c41ea27a53be8894dd32b299189b421f1f8f06f6a706b56433a@127.0.0.1:0","enr":"0xf88fb8409bf3f7dd13b162a205ccbe927f310ddf3b8c4c5f89183331a6317408259f970e7cec513e4ee7bafb3ae3378b24837e035bde558630c0e6b7db93527f043dc0de0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026e710e572097f299c352e4e1b8a2980de9e6d2cba35fc6b05623ed829c722148","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"I0Wt0e19mNuIFqrT/aCCnmsMnBZwhwZ6fsOokL7IrVg=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2345ad\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8ee3 8115 | 13 8115 (0) 8ee3 (0) 9b33 (0) 97b7 (0)\n001 3 7fb9 6e31 4730 | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 3 0518 0d53 0993 | 3 0518 (0) 0d53 (0) 0993 (0)\n============ DEPTH: 3 ==========================================\n003 2 3a42 39fe | 2 39fe (0) 3a42 (0)\n004 0 | 0\n005 1 24cb | 1 24cb (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","private_key":"f020ebea0429ea9f2ed075c50df1841beb61cdb88a0b5a3b864fe27bf214a297","name":"node_2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","services":["bzz","pss"],"enable_msg_events":true,"port":38575},"up":true}},{"node":{"info":{"id":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","name":"node_4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","enode":"enode://e57ffbc9c56f76b56f9005ac74af0db50a8e6f883e392b744080f36b35441ef2031f57e8d5d1899d0343f59545dfdda51cfc3c861bd810e0cb75516e32384676@127.0.0.1:0","enr":"0xf88fb8406472138d3fd8bb33c916d5192587abed17160ddc25b5b725259f95b3b5ab17b92fbb75939667eebdd4a0dab29d5b6a5b0cf3878d40c7c412cd99d22e94ced4e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e57ffbc9c56f76b56f9005ac74af0db50a8e6f883e392b744080f36b35441ef2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RzA2Bnms9jD8iroUx747vBOVPLHqjXpy9aO1dkFw73Y=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 473036\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8115 f3ed | 13 8115 (0) 8ee3 (0) 9b33 (0) 97b7 (0)\n001 3 0518 39fe 2345 | 7 0518 (0) 0d53 (0) 0993 (0) 39fe (0)\n002 4 7df3 78c7 6a64 6e31 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n============ DEPTH: 3 ==========================================\n003 3 541f 579d 5743 | 3 5743 (0) 579d (0) 541f (0)\n004 0 | 0\n005 0 | 0\n006 1 4464 | 1 4464 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","private_key":"99552bc7c5ce5b7ea569a6d3b46502a171a9ae1a3a6bc88f3fa2da99b1b25ef7","name":"node_4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","services":["bzz","pss"],"enable_msg_events":true,"port":41821},"up":true}},{"node":{"info":{"id":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","name":"node_f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","enode":"enode://0dd06e3e445d2cc141af19d7143f57fdb7fd08688718a628230c9e80ee2e700d12b98585be5c983630faa8061cca9dcee5fa267840ab63c7a177ed32c54abac9@127.0.0.1:0","enr":"0xf88fb8400bc5733ce0c6dab1ea57bf24e37a838bc7bfd4d4fa76002760aba33bf2b102b27f84c60b93282a95881f98a45f91c174957d61630a70e6bb91877a0417b99c970183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030dd06e3e445d2cc141af19d7143f57fdb7fd08688718a628230c9e80ee2e700d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8+0awvoZrhK+qr4ifsAz9JUwDwgwqEAUyDn/LmdsmNM=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f3ed1a\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 39fe 3a42 78c7 541f | 19 0518 (0) 0d53 (0) 0993 (0) 39fe (0)\n001 3 97b7 8115 8ee3 | 7 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n002 2 d735 ceeb | 3 ceeb (0) d735 (0) df92 (0)\n============ DEPTH: 3 ==========================================\n003 2 e17a e25a | 2 e17a (0) e25a (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","private_key":"6cd0d2e5beba190a7a871ae45b3bfa123d3c79b4fd171ef22eceedcfa35dd7d6","name":"node_f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","services":["bzz","pss"],"enable_msg_events":true,"port":46325},"up":true}},{"node":{"info":{"id":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","name":"node_541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","enode":"enode://1cf1ddffc042e967618bacdcf1e4aa0e765d65acc9e75c3ba8ed8b40c5f602eaf1cdb0652219fa04c169441b74ad07b014e7b94c54a54d7aefdb2b9e05d8ed48@127.0.0.1:0","enr":"0xf88fb84017719ad2bdcf75e3de4b6bd1d41115306432abcbd8d0ac6ea95bce768f5b06c12b4f507ff59afcb21724688f254f2f177b300c1f22995c184b3466cad698ff280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021cf1ddffc042e967618bacdcf1e4aa0e765d65acc9e75c3ba8ed8b40c5f602ea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VB8Vu+WNnhsr09FYLFz6Yv281DY7z0UZZPjG108XmjQ=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 541f15\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8ee3 f3ed | 13 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n001 2 0518 24cb | 7 0518 (0) 0d53 (0) 0993 (0) 39fe (0)\n002 2 7fb9 6e31 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n003 2 4730 4464 | 2 4464 (0) 4730 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 5743 579d | 2 5743 (0) 579d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","private_key":"92852d378cc44e9e13a49fb6eac32c7808f2415bd4882da6076b5c5c57147a52","name":"node_541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","services":["bzz","pss"],"enable_msg_events":true,"port":35339},"up":true}},{"node":{"info":{"id":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","name":"node_24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","enode":"enode://793fc878556c2704dac445d6dd237d8d4a5ffd6a9ccc7b40315790785062fcc9423df4649fdbeed26a47e3220ac6798c43e8111357e37d8a186382805a2d0f7f@127.0.0.1:0","enr":"0xf88fb8405ec36b34d21bc6414e2a974f21a891aa1ba4f896e1787c7e94b253908b8eb9274cf5b6c102479de1aef263c90c09c275ffdc2c8480007c92034d7073ac56b4de0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103793fc878556c2704dac445d6dd237d8d4a5ffd6a9ccc7b40315790785062fcc9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JMs5GxmEpTgK+C8vpiLxoC6wNeyzQB1TjkGCSWXdzFY=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 24cb39\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e17a 8ee3 bfeb a263 | 13 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n001 2 7fb9 541f | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 3 0993 0d53 0518 | 3 0518 (0) 0d53 (0) 0993 (0)\n============ DEPTH: 3 ==========================================\n003 2 3a42 39fe | 2 39fe (0) 3a42 (0)\n004 0 | 0\n005 1 2345 | 1 2345 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","private_key":"e9e78ca9c5aa6c4d52d7d6f39dc7ef585ac1b3a232beec65a7493e818276c04d","name":"node_24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","services":["bzz","pss"],"enable_msg_events":true,"port":40305},"up":true}},{"node":{"info":{"id":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","name":"node_a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","enode":"enode://0e4cad0aaad50693ff30730b850da74646d6742011b90cbb5ea2e8bd1d5430f553796beed70d373525d4bb7a136a7ff5b3acee77afb21b9c91ba93bab9c1e7c6@127.0.0.1:0","enr":"0xf88fb84093fd09e514cfed721f0cb368859e31ec619cc2d0d8482cd0b216d6d368d761b43c8a0ce93916b46d87f2338a934a1ae706f2070e4cd6599b891ec374c90aa1110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020e4cad0aaad50693ff30730b850da74646d6742011b90cbb5ea2e8bd1d5430f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"omOldpzz8ibbfSzZGu6WogbEawziqAeKbThB3D9MXGY=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a263a5\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5743 78b6 24cb 3a42 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 2 e17a d735 | 6 f3ed (0) e17a (0) e25a (0) ceeb (0)\n002 3 8115 8ee3 97b7 | 4 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n============ DEPTH: 3 ==========================================\n003 1 bfeb | 1 bfeb (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 a3d9 | 1 a3d9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","private_key":"ff1484b5140cd7e811e6ce51bf267644de2b44a4aaac227490a713ed17b998ad","name":"node_a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","services":["bzz","pss"],"enable_msg_events":true,"port":45663},"up":true}},{"node":{"info":{"id":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","name":"node_3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","enode":"enode://6cdb01e6d8e2f2d201ae9593e7234c2f954efe223726481576d9596ecebf45965ce6606620cd8ac5ce8a62dd03ad386319acc6b0b49caef9533b8fb39f928338@127.0.0.1:0","enr":"0xf88fb840d5a5fd5c60a2e5253b01fc73dc69320f4be754df21628a91874bc86ae8e00bc02c432f46859e14dbc35515f1864c6e482e0165490d7a2e9e73a868789e6dc1560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026cdb01e6d8e2f2d201ae9593e7234c2f954efe223726481576d9596ecebf4596","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OkKYvhPDnd7gRvQjeGNSjAWsHjpsnCzEKWNoZdjuShU=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3a4298\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f3ed a263 | 13 f3ed (0) e17a (0) e25a (0) ceeb (0)\n001 3 4464 753a 78b6 | 12 4464 (0) 4730 (0) 541f (0) 5743 (0)\n002 3 0993 0d53 0518 | 3 0518 (0) 0d53 (0) 0993 (0)\n============ DEPTH: 3 ==========================================\n003 2 24cb 2345 | 2 2345 (0) 24cb (0)\n004 0 | 0\n005 0 | 0\n006 1 39fe | 1 39fe (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","private_key":"c3bd98ec585a2bf57984ea44e3df5862d0ac4036367cf8a71530d6e3da5e19cf","name":"node_3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","services":["bzz","pss"],"enable_msg_events":true,"port":33977},"up":true}},{"node":{"info":{"id":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","name":"node_78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","enode":"enode://0020a4e955476d6774ca840c91a6f298f738eb8bc162cdf0bf919d6ff85430dd080d68b2519e7a8806e30bbedd04d9ca0455e9cfea9a9d1f8316b3e02a7739c5@127.0.0.1:0","enr":"0xf88fb840091444d053b7aaddb31d705918bf78a24089d8db087272558babdf3c35e7e1544ab5f6d6d130c38f71153b590cd6c4a8b0538b39505b3bd53caadb499d7efc350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030020a4e955476d6774ca840c91a6f298f738eb8bc162cdf0bf919d6ff85430dd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eLai+zQolUhV+9v5mTjhIUuPGfozQUSYQonR+wO7T3w=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 78b6a2\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 a263 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0518 3a42 | 7 0518 (0) 0d53 (0) 0993 (0) 24cb (0)\n002 2 4464 5743 | 5 4464 (0) 4730 (0) 541f (0) 579d (0)\n003 2 6a64 6e31 | 2 6e31 (0) 6a64 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 7fb9 7df3 | 2 7fb9 (0) 7df3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 78c7 | 1 78c7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","private_key":"5d3e69f521510ed62af7c34c089faa034445e525fae5789a5b2708e3e34a55b7","name":"node_78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","services":["bzz","pss"],"enable_msg_events":true,"port":44923},"up":true}},{"node":{"info":{"id":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","name":"node_5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","enode":"enode://9769d41ff8d1a2220be2c7a9f3f522b197606a2a9b771e70f7115b43e9a3f7f8a2bd1bd4a7eed179a8f5032b122e7a16cc3f38eabf55f2655cb183a12c425f59@127.0.0.1:0","enr":"0xf88fb840406de7323ba3d20449df0acbcba8c0a6104d62495aae6346997f988a71b197a7232ae0db83b24c4b90dc2e9c8192734fd6bae7b1b0d41e80102201920fa864d70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039769d41ff8d1a2220be2c7a9f3f522b197606a2a9b771e70f7115b43e9a3f7f8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V0O8CecT58TVj+8ZUatrYnon5vGjxC24iCehYTvX7z8=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5743bc\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 a263 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0d53 0518 | 7 0518 (0) 0d53 (0) 0993 (0) 24cb (0)\n002 4 6e31 753a 7fb9 78b6 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n003 2 4464 4730 | 2 4464 (0) 4730 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 541f | 1 541f (0)\n007 0 | 0\n008 1 579d | 1 579d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","private_key":"3ec49076ee0972b516c7ac98a7ab569014cf747935fe3dd076c683c1cc7d0509","name":"node_5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","services":["bzz","pss"],"enable_msg_events":true,"port":35273},"up":true}},{"node":{"info":{"id":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","name":"node_579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","enode":"enode://024d47097bb5d264e382a071489167e48e9c4e56ee3d0eb6594603ed7847dbbb141b45523e4b174b7083472630e08dcc15bb2495bb1fccc0506b19d4e14fa297@127.0.0.1:0","enr":"0xf88fb840e1f4b1665503a11d8e8c261ffc24f744272c0d96ebaf17d03c2046f6a0c3161f264ff1c4ddc618cb5da9c35b4dae871aaf7ec77cee48cab46467acc27f7d812b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103024d47097bb5d264e382a071489167e48e9c4e56ee3d0eb6594603ed7847dbbb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V52hcJAe2RG+NEXUQiZkqZfrFCAVidcC4GiPYUaHKZM=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 579da1\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 d735 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0d53 0518 | 7 0518 (0) 0d53 (0) 0993 (0) 24cb (0)\n002 2 6a64 6e31 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n003 2 4730 4464 | 2 4464 (0) 4730 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 541f | 1 541f (0)\n007 0 | 0\n008 1 5743 | 1 5743 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","private_key":"6e50f30bce1310aa06e28011d83829b6432b73e09ffaa327bcb09d0a871e56c5","name":"node_579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","services":["bzz","pss"],"enable_msg_events":true,"port":37161},"up":true}},{"node":{"info":{"id":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","name":"node_d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","enode":"enode://e0063bc92893325b6f3aff3a1cdebe170f3a70c3ed8b6aa55607f96ffa9e199f1f37d6b4f5743adeb91e1aea7baea44fca78010706f2615c27840a341d926a4d@127.0.0.1:0","enr":"0xf88fb8407686b23d8d56528be1d859eb241e4228adbebf46b6664fb1a89141257a7552140a602485685a9256944106c9f9f57828d22cd7ce01c64fa504dd7977294b52cf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e0063bc92893325b6f3aff3a1cdebe170f3a70c3ed8b6aa55607f96ffa9e199f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1zUeR/DHRu0zxlKw8qov7TVMja2Nh1JaS1EVga/2xvo=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d7351e\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0518 7df3 579d | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 2 a3d9 a263 | 7 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n002 2 e25a f3ed | 3 f3ed (0) e25a (0) e17a (0)\n============ DEPTH: 3 ==========================================\n003 1 ceeb | 1 ceeb (0)\n004 1 df92 | 1 df92 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","private_key":"e6ebe5c66707a0c89243e414155374afcdcd0529b7fb63d17696f685fe9554dc","name":"node_d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","services":["bzz","pss"],"enable_msg_events":true,"port":35925},"up":true}},{"node":{"info":{"id":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","name":"node_7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","enode":"enode://f0b310658f442f5bb853496ee598435dd08bdfdceb62499f0aa1583212529fb831b2d1f6db5a2faadc238f91204b7d5a51d7f9259983008bccba2d35d5bd7114@127.0.0.1:0","enr":"0xf88fb84015bb5fcc3a16b896d129418fd6304c5c4a07d2613278e74c38490a515d97e03074fb145cd653fcf028feb6f005d0ca8c83203df0ec9c042635e41c9a685264810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0b310658f442f5bb853496ee598435dd08bdfdceb62499f0aa1583212529fb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ffMHT04RdaIT5XiTmr2cHl/3FUPrXcJO5d7V+ATjuEI=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7df307\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 d735 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0993 0d53 | 7 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n002 2 4730 4464 | 5 4464 (0) 4730 (0) 541f (0) 5743 (0)\n003 2 6a64 6e31 | 2 6e31 (0) 6a64 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 78b6 78c7 | 2 78b6 (0) 78c7 (0)\n006 1 7fb9 | 1 7fb9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","private_key":"2739d262560fd1c32320e01920f26d20fe756d085ea86b3a3c105ee36f6b13c4","name":"node_7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","services":["bzz","pss"],"enable_msg_events":true,"port":34347},"up":true}},{"node":{"info":{"id":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","name":"node_78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","enode":"enode://2852c5c0c2cc4ce9ec1e680b5be7fdc6178bf36e6393d791817042b221a0f787dcb6f00600b95c177940bae3dcad8bb10d7e0601d92d6fee73033dcffe0af98a@127.0.0.1:0","enr":"0xf88fb840250093f9c808805726fa94afee9b1fbe20be7c6bcaf444a93e3073cb2eb4632d1eb840824f9ca949b40b26b9878f7399f4c3c1ee6ac0877c3f52efb88aae18510183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022852c5c0c2cc4ce9ec1e680b5be7fdc6178bf36e6393d791817042b221a0f787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eMcNM9/RMbzBxkJnv3Hm/oHpP4kblAoRFMZXyCZnW9c=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 78c70d\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f3ed a3d9 | 13 f3ed (0) e25a (0) e17a (0) ceeb (0)\n001 2 0993 0d53 | 7 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n002 2 4730 4464 | 5 4464 (0) 4730 (0) 541f (0) 5743 (0)\n003 2 6a64 6e31 | 2 6e31 (0) 6a64 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 7fb9 7df3 | 2 7fb9 (0) 7df3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 78b6 | 1 78b6 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","private_key":"ecb17d33e2878ecc69683c97b16415ef66ea959593d5e15b0a376ab566cccdfb","name":"node_78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","services":["bzz","pss"],"enable_msg_events":true,"port":37163},"up":true}},{"node":{"info":{"id":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","name":"node_a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","enode":"enode://abe44f262b43e0ddcc49d889a93f3f7d43ea44bf504d23937464edf104332b963d3635818c12867c25f4e43c4860e18cbedc28a87dd87ca65bf2b13db23ff93b@127.0.0.1:0","enr":"0xf88fb840c0a357ca865bdcbfbc5f575be6d2ab837c7354069d334c5ab7d618076595a70c5a8a53142161c36f6d759f2f8e196924f722f98635f3fbfbb86fe7a910868ad20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103abe44f262b43e0ddcc49d889a93f3f7d43ea44bf504d23937464edf104332b96","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"o9mHeV4Z+FGOR3D3LJ+AgEuZmjG/ItCc/rBNZEtCm/k=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a3d987\npopulation: 15 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 39fe 579d 5743 753a | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 3 d735 df92 e25a | 6 f3ed (0) e25a (0) e17a (0) ceeb (0)\n002 3 8115 8ee3 9b33 | 4 9b33 (0) 97b7 (0) 8ee3 (0) 8115 (0)\n============ DEPTH: 3 ==========================================\n003 1 bfeb | 1 bfeb (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 a263 | 1 a263 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","private_key":"765bfc005ad4dec671a2f1dee108fa60f9760b185dee1d2a2af53a0d56f53902","name":"node_a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","services":["bzz","pss"],"enable_msg_events":true,"port":35675},"up":true}},{"node":{"info":{"id":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","name":"node_39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","enode":"enode://1a9002726d9442faaa087d3f865c4c5d7f2882a87866a710835cbb8d4dc3da7338b868cd888fd898e4016dd20fd21f98891a212f1b17a5427b5476b5b6f6c317@127.0.0.1:0","enr":"0xf88fb840fa5103638887af121c7fe3afedad54432df30561fc796f03459942a3f17f7cc03ea50cfe59d8af29e82b76f1295a8b5697f48525060ed90d804210a80df804bd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031a9002726d9442faaa087d3f865c4c5d7f2882a87866a710835cbb8d4dc3da73","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Of6nbi5DCRnK20jOKQwRrWay+KZohq4ItZ5Bj6Tq3os=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39fea7\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f3ed e25a a3d9 | 13 f3ed (0) e25a (0) e17a (0) ceeb (0)\n001 3 4730 753a 6a64 | 12 4730 (0) 4464 (0) 541f (0) 5743 (0)\n002 3 0518 0993 0d53 | 3 0d53 (0) 0993 (0) 0518 (0)\n============ DEPTH: 3 ==========================================\n003 2 24cb 2345 | 2 24cb (0) 2345 (0)\n004 0 | 0\n005 0 | 0\n006 1 3a42 | 1 3a42 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","private_key":"bd7dbd51baf88692c24a8d75636af1f00e609fe4eda6444b674b14ab09ecddc5","name":"node_39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","services":["bzz","pss"],"enable_msg_events":true,"port":33437},"up":true}},{"node":{"info":{"id":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","name":"node_6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","enode":"enode://ce647cc2ad911b8cb35aeb74b022bce733ae4cfd609859b6c348e72e4e03cc4284064126b5419e15e7ad1e321469b3fbc3cb30319247c36b0eeba7f5a069a78d@127.0.0.1:0","enr":"0xf88fb840d07202149bb989b7b0bc49a88fab6c8e70082ef55751246005290393cfe8979c72eac475f2a5fe1292b7a48ae288d9fa421806c36447be580061fb5ee11fe5f30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ce647cc2ad911b8cb35aeb74b022bce733ae4cfd609859b6c348e72e4e03cc42","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"amTXZeQP3hGQ/yKLuGCWuEGC1xnm0bcTcm25qu6kN9o=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6a64d7\npopulation: 14 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ceeb 9b33 | 13 ceeb (0) df92 (0) d735 (0) f3ed (0)\n001 3 0993 0d53 39fe | 7 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n002 3 579d 4464 4730 | 5 4730 (0) 4464 (0) 541f (0) 5743 (0)\n============ DEPTH: 3 ==========================================\n003 5 753a 78c7 78b6 7df3 | 5 753a (0) 7fb9 (0) 7df3 (0) 78b6 (0)\n004 0 | 0\n005 1 6e31 | 1 6e31 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","private_key":"2d1258592260e026c71f0e3d8f9b60ff4264cca8acb232abc3715ed0fa49e8cf","name":"node_6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","services":["bzz","pss"],"enable_msg_events":true,"port":37153},"up":true}},{"node":{"info":{"id":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","name":"node_9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","enode":"enode://ddf82056124d428300b2fbe2318d468707657ce7aed15add51629475f3bf3076eb42fd2da9394bef0c22e2fa4615e39e3cec3073587947862b347e7e30e046e6@127.0.0.1:0","enr":"0xf88fb8403df62e843c1aba232b75f4e1ef741cdcb6a1abc2d70c27548171885786d8cf6262354bc32298a1202bb3a1b484b9840592f11470af89955df5c5cff009f3d5470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ddf82056124d428300b2fbe2318d468707657ce7aed15add51629475f3bf3076","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mzNa62m3+9OWrOUYLT/nkw5dl4ZTFZMxC0ioV8K7dp4=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9b335a\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4464 6a64 | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 2 df92 ceeb | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 bfeb a3d9 | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 8ee3 8115 | 2 8ee3 (0) 8115 (0)\n004 1 97b7 | 1 97b7 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","private_key":"f0dcfc2e5fe5cc19ae0e55c17cea621a344848ba6413de2fa1370d0ef5041cc1","name":"node_9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","services":["bzz","pss"],"enable_msg_events":true,"port":36105},"up":true}},{"node":{"info":{"id":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","name":"node_8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","enode":"enode://519322960c41240dfdf0f6eb33cf4dbcd607f9c71552844f4c88b40535ee8e8edc4f81e969ee6418ecaeb731f6627c7553535db148d6af171aa90d3d4b52de5e@127.0.0.1:0","enr":"0xf88fb840beb59d1ae71c8e13e68f38f5dc4d35fd419423aeb66e9bd02825cd51675e195c59bfe74790a11d3660a429f51c7fa533b03f5de75f9c50bd9deb20aad7bdb3aa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102519322960c41240dfdf0f6eb33cf4dbcd607f9c71552844f4c88b40535ee8e8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gRWrzzl0enrz7s5V8SzJ5JCaduQYU7LhJlIhUNvalQc=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8115ab\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 4730 0d53 2345 | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 2 f3ed ceeb | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 a263 a3d9 | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 97b7 9b33 | 2 97b7 (0) 9b33 (0)\n004 1 8ee3 | 1 8ee3 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","private_key":"0cdcfe48b7096864bb66f2d09b7ef45a27b5f26606f6429a841a266fadc2b8de","name":"node_8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","services":["bzz","pss"],"enable_msg_events":true,"port":37937},"up":true}},{"node":{"info":{"id":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","name":"node_8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","enode":"enode://5eb100e652f1a20369cc22355e5ddbb1f3503d45ab5bc343e42d43c1189ac66d99472efb731fbdb43c086a9867494c340a3b93ec0c248313ed44f017b38f0c97@127.0.0.1:0","enr":"0xf88fb8407e0bff7bd1090185526f52a43ecdda7358286cc0468f0eca9f18958d2a3447361acab4fa03a4a0799aa4e50f8e84c306e840f8249a0308b34f82b76afe046eed0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035eb100e652f1a20369cc22355e5ddbb1f3503d45ab5bc343e42d43c1189ac66d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"juOHQ4urcW87bSD0xaEXvOrsYDz6axvWCx0LhLEatDA=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8ee387\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 24cb 2345 541f 7fb9 | 19 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n001 2 ceeb f3ed | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 a263 a3d9 | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 9b33 97b7 | 2 97b7 (0) 9b33 (0)\n004 1 8115 | 1 8115 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","private_key":"105b799734097e8023441f6939805723ac89fcb4ff9ccac50bd62460e87c247c","name":"node_8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","services":["bzz","pss"],"enable_msg_events":true,"port":40859},"up":true}},{"node":{"info":{"id":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","name":"node_7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","enode":"enode://2fb00f3ef77f231e224d908fcbafa19fcc9384a8636a4f616e2bd1d0aaa901ed6e8af6ae1fe98835650624d7d5cd0d357b6716dfed0096c2a4784a303dacf52a@127.0.0.1:0","enr":"0xf88fb840d2aff8f47839e79ba53089410607c84c3a350f6549787298369c6b4aaee001711772c1ebe313391835a231f69078929006c5bc46a7a7a365339a43019105ee6a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022fb00f3ef77f231e224d908fcbafa19fcc9384a8636a4f616e2bd1d0aaa901ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f7lV7jRch+nY48mJvAvMsV5Ejw2ZqI0z+3vmcJL7bxQ=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7fb955\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bfeb 8ee3 | 13 ceeb (0) df92 (0) d735 (0) f3ed (0)\n001 2 2345 24cb | 7 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n002 2 5743 541f | 5 541f (0) 5743 (0) 579d (0) 4730 (0)\n003 2 6a64 6e31 | 2 6a64 (0) 6e31 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 78b6 78c7 | 2 78b6 (0) 78c7 (0)\n006 1 7df3 | 1 7df3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","private_key":"64333ce54c8da8d7e9c33f7be3b251a5ed1e5aa83a11249a82e29a110b1d5b2b","name":"node_7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","services":["bzz","pss"],"enable_msg_events":true,"port":42481},"up":true}},{"node":{"info":{"id":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","name":"node_bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","enode":"enode://c59989c774f7e074cdf34e86b5606f6413731cb002d6e23fb7048b6abb8d4ab175993ac902afe935830d5aaf2323da442f6001f4efb4f744c8e815d7cbebc210@127.0.0.1:0","enr":"0xf88fb840e0f778f02886637fbd7ea40cc496e93293d426c0339594822cebdd56850aa36f407c7f9a63d251f0a2dff02c8462b150d7c771c2dbb09d6f886529e5a354906c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c59989c774f7e074cdf34e86b5606f6413731cb002d6e23fb7048b6abb8d4ab1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"v+tsaf7RbSm6INEc2LI4neInZbYgm7uPGZQBSiCiBOY=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bfeb6c\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0993 24cb 7fb9 | 19 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n001 3 ceeb df92 e17a | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 9b33 97b7 | 4 97b7 (0) 9b33 (0) 8115 (0) 8ee3 (0)\n============ DEPTH: 3 ==========================================\n003 2 a3d9 a263 | 2 a3d9 (0) a263 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","private_key":"1d29cf23c9755015db0f67b0188c2c19bf24987efa6c1682ccf3cc0ad0ec5a23","name":"node_bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","services":["bzz","pss"],"enable_msg_events":true,"port":46455},"up":true}},{"node":{"info":{"id":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","name":"node_e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","enode":"enode://a2dd668460422389d655b5663deec36cd2881ad83de1e61764a4ac0281dc04de5dfe0a1c77aebf15b1507f62433d08f839fdc45ccde68b1372da5fb05edb2626@127.0.0.1:0","enr":"0xf88fb8402cb1df00b6cd3322b435ed7d378f8f55f11e43f478d15b4c2a5944bc802ae37d5d27186bbb89602d74aba656f45abb719f1f24cbc09221a929fe3b9c49e73e4e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a2dd668460422389d655b5663deec36cd2881ad83de1e61764a4ac0281dc04de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4XqGI697L+Ioe5Lgs9kXukTY8pcwGXuuKq4gUDVoqzo=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e17a86\npopulation: 8 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 24cb 6e31 | 19 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n001 2 a263 bfeb | 7 97b7 (0) 9b33 (0) 8115 (0) 8ee3 (0)\n002 2 ceeb df92 | 3 df92 (0) d735 (0) ceeb (0)\n============ DEPTH: 3 ==========================================\n003 1 f3ed | 1 f3ed (0)\n004 0 | 0\n005 0 | 0\n006 1 e25a | 1 e25a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","private_key":"77bd5acdbf27ca1f194007ebaae9a384db0ed52cdf49a440fce50fd8986663d1","name":"node_e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","services":["bzz","pss"],"enable_msg_events":true,"port":38823},"up":true}},{"node":{"info":{"id":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","name":"node_6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","enode":"enode://e8f703980df3e25fe82683b6d2a775262e07309814eaaa60c3d22d64d352431ff3fc485e8bea252e646e60acb14b08c53ac0d6c480e468a018c9940cfbb5995a@127.0.0.1:0","enr":"0xf88fb840808b5d498d23de164013220eb74d54a810a0d63485538a9b2e4d05fb854995732e8be73c9c32da53cc2ef4dc9d554295743188a22c08a5ce3731575770cf250f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8f703980df3e25fe82683b6d2a775262e07309814eaaa60c3d22d64d352431f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bjFW1QN/r9Tk1v+/tQ/ZV7s0qBza0kxluXFZ9vvKgto=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e3156\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ceeb e17a | 13 97b7 (0) 9b33 (0) 8115 (0) 8ee3 (0)\n001 4 2345 0d53 0993 0518 | 7 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n002 4 579d 5743 541f 4730 | 5 5743 (0) 579d (0) 541f (0) 4730 (0)\n============ DEPTH: 3 ==========================================\n003 5 753a 7df3 7fb9 78c7 | 5 7fb9 (0) 7df3 (0) 78b6 (0) 78c7 (0)\n004 0 | 0\n005 1 6a64 | 1 6a64 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","private_key":"a2b5a8fc75c349602ab3f0c732403c34e0dd6d0983bdca9fd6e8e63fa7e625ee","name":"node_6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","services":["bzz","pss"],"enable_msg_events":true,"port":44515},"up":true}},{"node":{"info":{"id":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","name":"node_051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","enode":"enode://f95dcdf6a7b67a12e461b7d620e9e5473ef6630fae5334cc81ee19f7ed5a86af2d898820ee10598f9886270bad22885f33bdd77da3ce1cebc35eab12a851bf29@127.0.0.1:0","enr":"0xf88fb840f83b0db1e290d22c0a001f3850407da61d152aa66b04657db08b30ad9b417d3b20a8c76d1f78787581e182bf5a52a4e4133d916f923ae20b81ea6baccb2500410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f95dcdf6a7b67a12e461b7d620e9e5473ef6630fae5334cc81ee19f7ed5a86af","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BRhyySYhF5f2JaZ1tQyTSrXynLt9FAtsid7EuSSg/0E=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 051872\npopulation: 15 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d735 df92 | 13 df92 (0) d735 (0) ceeb (0) f3ed (0)\n001 7 541f 5743 579d 4730 | 12 5743 (0) 579d (0) 541f (0) 4730 (0)\n002 4 2345 24cb 39fe 3a42 | 4 3a42 (0) 39fe (0) 24cb (0) 2345 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 2 0d53 0993 | 2 0d53 (0) 0993 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","private_key":"15d5b46039f63072fedea8221981c8ea5e41e2f76fb9f68e11af1dc629514ae9","name":"node_051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","services":["bzz","pss"],"enable_msg_events":true,"port":41645},"up":true}},{"node":{"info":{"id":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","name":"node_4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","enode":"enode://0b5fa0bc32971346e7f724db70c7c2debd42aabad0ae08ddafdd9c2a3089b1e39cb62b34e36b3a4902a20bbd0b86e47b0e660eda5fcd203a2bb7ee411397aebb@127.0.0.1:0","enr":"0xf88fb84042ecaa56acb3a73b05756c24e1d9cb90f3941293a34b7e58d19cf3f3974f801b38ddf5de2c5cc06ab8cddc4f1d39d6429e6bcb5d45b3162cd8efb5e62ab2963a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030b5fa0bc32971346e7f724db70c7c2debd42aabad0ae08ddafdd9c2a3089b1e3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RGTTOqr2BvAMIyVHxk1NDD0LwQCAydLO73jwyaUZjmI=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4464d3\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 97b7 9b33 | 13 9b33 (0) 97b7 (0) 8115 (0) 8ee3 (0)\n001 2 3a42 0518 | 7 3a42 (0) 39fe (0) 24cb (0) 2345 (0)\n002 5 6a64 78b6 78c7 7df3 | 7 6a64 (0) 6e31 (0) 7fb9 (0) 7df3 (0)\n============ DEPTH: 3 ==========================================\n003 3 5743 579d 541f | 3 5743 (0) 579d (0) 541f (0)\n004 0 | 0\n005 0 | 0\n006 1 4730 | 1 4730 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","private_key":"2adb4afe6ba823e733df48a3d5d09eb8fa4ed380cb5accf0aae706ef7781f344","name":"node_4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","services":["bzz","pss"],"enable_msg_events":true,"port":42813},"up":true}},{"node":{"info":{"id":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","name":"node_753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","enode":"enode://1352929c4211f4c4cd4a13cbfdce725e4f1bc4ed263b8fb8e5d34ead2f6bf5c0947a7013057d1f5cf04ea9ca1ca19bfe3dcc236e3ce674702dc5e8926b75ba89@127.0.0.1:0","enr":"0xf88fb840b9ab15d6154f9a25168313678352c17719ca962b1c7518185075c93a3f88bf3e224bb5165b657547a61ce6c7d65b28834119ba9de142b3ca096c1bf614cf3ad20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031352929c4211f4c4cd4a13cbfdce725e4f1bc4ed263b8fb8e5d34ead2f6bf5c0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dTqDZ/za+Mrx/myiXtl7I/mYKBFaONYTUkiLw9AqPhc=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 753a83\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 e25a | 13 a3d9 (0) a263 (0) bfeb (0) 8115 (0)\n001 2 39fe 3a42 | 7 3a42 (0) 39fe (0) 24cb (0) 2345 (0)\n002 2 5743 4464 | 5 5743 (0) 579d (0) 541f (0) 4730 (0)\n003 2 6a64 6e31 | 2 6a64 (0) 6e31 (0)\n============ DEPTH: 4 ==========================================\n004 4 78c7 78b6 7df3 7fb9 | 4 7fb9 (0) 7df3 (0) 78c7 (0) 78b6 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","private_key":"168b73a15e60830a02857df2b0829fd5a8763b349b554523b0159f54eb92e3aa","name":"node_753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","services":["bzz","pss"],"enable_msg_events":true,"port":33315},"up":true}},{"node":{"info":{"id":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","name":"node_e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","enode":"enode://5ac2f47e9c71378005c153f9d63851ec5b6548902f310f0e0d1f70adab24930495a39c6e2f861e4f90a7f6115cdad65b3031270b3a622d53adedf1842c4d5b60@127.0.0.1:0","enr":"0xf88fb840850bea04ffb859769c059b511c2c57509fd3a9169027e68054a4da19741eee99346b08613ccbd87611a1731d116f5eb6e857eb89cd51afd1352d2def6921cc6e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025ac2f47e9c71378005c153f9d63851ec5b6548902f310f0e0d1f70adab249304","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4lphH3oGkxQFDo/8oOs4P3KgUFxZQv2fIcDYrE/CJV0=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e25a61\npopulation: 8 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 39fe 753a | 19 39fe (0) 3a42 (0) 24cb (0) 2345 (0)\n001 2 a3d9 97b7 | 7 a3d9 (0) a263 (0) bfeb (0) 8115 (0)\n002 2 d735 df92 | 3 df92 (0) d735 (0) ceeb (0)\n============ DEPTH: 3 ==========================================\n003 1 f3ed | 1 f3ed (0)\n004 0 | 0\n005 0 | 0\n006 1 e17a | 1 e17a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","private_key":"c4c13286dcde737ba9a3fc2e7953732cdab547e3e0b627aa3eb5aa41403370d0","name":"node_e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","services":["bzz","pss"],"enable_msg_events":true,"port":42117},"up":true}},{"node":{"info":{"id":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","name":"node_97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","enode":"enode://2c0df18912e105bbf6f9b8eb475be15fa4b2588774db19e58efa9f9004827b7b7c7ce8c6b85f09ed18d35525894c0fdab9db72bda999b840490a9bf69d4e9483@127.0.0.1:0","enr":"0xf88fb84047867575521a015ed256017d340f51f6b7b89dbf341e7198d2873cdf1643097d57e3353c5b2dedc7ac2f59f228207f23aaf85bd0d5ea22c839cd42093c008c520183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032c0df18912e105bbf6f9b8eb475be15fa4b2588774db19e58efa9f9004827b7b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"l7cDr+AEiTIc6YBXBOjFCWcasOlG0zlZWjIg28+6F9c=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 97b703\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4464 0d53 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 2 f3ed e25a | 6 f3ed (0) e17a (0) e25a (0) ceeb (0)\n002 2 a263 bfeb | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 8ee3 8115 | 2 8115 (0) 8ee3 (0)\n004 1 9b33 | 1 9b33 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","private_key":"459c256ce29dce2b5e51c0ce9519d817687f2ae8d39291bd0bb8c45be3cac239","name":"node_97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","services":["bzz","pss"],"enable_msg_events":true,"port":35847},"up":true}},{"node":{"info":{"id":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","name":"node_0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","enode":"enode://61b38c0b92a4c6ce5d27ea0b6d43d452e1e997c46f8ee202b2e75ea97ced9f4688972acf423e65ef43459bb16e39aebf26088a1f1ff7539524802bc73e3933ae@127.0.0.1:0","enr":"0xf88fb840303205621ea7bf25072f954d0d961007601360547291141945bb0093577673ef019f53965ee35755ee49420db016f5bbeb2033ca540a4697ac74f4a7d44f3f200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261b38c0b92a4c6ce5d27ea0b6d43d452e1e997c46f8ee202b2e75ea97ced9f46","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DVORnD1bCv3DtzjYLLIT+R4F7DsPQqOqRuelBE+MRoQ=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d5391\npopulation: 15 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 df92 8115 97b7 | 13 f3ed (0) e17a (0) e25a (0) ceeb (0)\n001 6 579d 5743 6a64 6e31 | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 4 2345 24cb 3a42 39fe | 4 39fe (0) 3a42 (0) 24cb (0) 2345 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 0518 | 1 0518 (0)\n005 1 0993 | 1 0993 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","private_key":"c45ad9fcca69152984db9fed40d730632c1298936ade555a8cb20d1a817bd670","name":"node_0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","services":["bzz","pss"],"enable_msg_events":true,"port":38753},"up":true}},{"node":{"info":{"id":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","name":"node_df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","enode":"enode://95f793890df976e2116b50757db31f18f9973a271201d253d5e7eb8045e883b2343ce7c251c3cef5a8a47fb2f7ee194a75fd6da2f6c86edc301d1a1c61967aab@127.0.0.1:0","enr":"0xf88fb840d94e3579279121df14a0951495d39187d19e1eaaf27ea43657c534f73f0478c57461adbb638a01bac20370acce51c6a7336966224889eba1a5c7c71ed0ea14210183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10395f793890df976e2116b50757db31f18f9973a271201d253d5e7eb8045e883b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"35JqZsJv2fAxTI+ilNeaiPkS7DjEWk8CZ/ZL7qyqG8U=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: df926a\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0518 0d53 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 3 9b33 a3d9 bfeb | 7 bfeb (0) a3d9 (0) a263 (0) 8115 (0)\n002 2 e25a e17a | 3 f3ed (0) e17a (0) e25a (0)\n============ DEPTH: 3 ==========================================\n003 1 ceeb | 1 ceeb (0)\n004 1 d735 | 1 d735 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","private_key":"eeb3903d4463417af9da2ea27fba13fd5093da36946266a277ec581558b2856c","name":"node_df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","services":["bzz","pss"],"enable_msg_events":true,"port":39343},"up":true}},{"node":{"info":{"id":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","name":"node_ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","enode":"enode://b3e2654630b1d6ebbb09ee959e76c7730ae9c6fc480911ff08fcdd24d7ba4b828729f5a4dfc7200e612a8c1fcf86eaeb7cbb8c21397b46c65f32e1aed42147d9@127.0.0.1:0","enr":"0xf88fb84092f5be44e027ba50e860ca40efdd29bbf06481e026e13a4a5ac92a23fbfc4abd14a3e017a8b06df176479a8d5f2917d4c34c2acef2bcf5759a288681f2ea97400183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b3e2654630b1d6ebbb09ee959e76c7730ae9c6fc480911ff08fcdd24d7ba4b82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zuuCKuMTSaut21Qw6AQz9FM+lClgovUcyEbfldqlqPg=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ceeb82\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6a64 6e31 0993 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 4 bfeb 9b33 8ee3 8115 | 7 bfeb (0) a3d9 (0) a263 (0) 8115 (0)\n002 2 e17a f3ed | 3 f3ed (0) e17a (0) e25a (0)\n============ DEPTH: 3 ==========================================\n003 2 d735 df92 | 2 d735 (0) df92 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","private_key":"b6e0764b9a67a61d0b3d28f015fa324dcd1cf91184ffe3e19d09dd4c2e03eba9","name":"node_ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","services":["bzz","pss"],"enable_msg_events":true,"port":33733},"up":true}},{"node":{"info":{"id":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","name":"node_09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","enode":"enode://7865fabc9290d5908d0b0379da577a803da633ce87eca6a230cd485858f79d8732a353fd06bb730a194d4014ac932231ca83337c8523f7134c7d42d4c478d3a2@127.0.0.1:0","enr":"0xf88fb840d2dbe8ecd544c1c014c8f02cd34a100977754a6db7f5e02016625158c1bdd75c53f231aa89315cd6bf3d705704e49986dc7ed17eedc5540e7991a7f69c0df83b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027865fabc9290d5908d0b0379da577a803da633ce87eca6a230cd485858f79d87","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CZN+J8DlJQHatyFXh3+ZSCorctqKNpDlXFF8D8Pzv/w=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 09937e\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bfeb ceeb | 13 bfeb (0) a3d9 (0) a263 (0) 8115 (0)\n001 4 78c7 7df3 6a64 6e31 | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 4 3a42 39fe 24cb 2345 | 4 39fe (0) 3a42 (0) 24cb (0) 2345 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 0518 | 1 0518 (0)\n005 1 0d53 | 1 0d53 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","private_key":"e412c080f6539c4ed5ecc3cb66b97b85ee903f61b67fc90fa515775522d067ac","name":"node_09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","services":["bzz","pss"],"enable_msg_events":true,"port":34047},"up":true}}],"conns":[{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","other":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_4.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_4.json index a64f3137..9296cad0 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_4.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_4.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","private_key":"e567b7d9c554e5102cdc99b6523bace02dbb8951415c8816d82ba2d2e97fa23b","name":"node01","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","private_key":"c7526db70acd02f36d3b201ef3e1d85e38c52bee6931453213dbc5edec4d0976","name":"node02","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","private_key":"61b5728f59bc43080c3b8eb0458fb30d7723e2747355b6dc980f35f3ed431199","name":"node03","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","private_key":"075b07c29ceac4ffa2a114afd67b21dfc438126bc169bf7c154be6d81d86ed38","name":"node04","services":["bzz","pss"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","other":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","up":true},{"one":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","other":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","up":true},{"one":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","other":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","name":"node_39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","enode":"enode://1adbc1635af8ae835d3041edc8a5c633f40a009111b6a74e0cce501181b7ea3b1f26b193294721540ec8970183ff74a9121899af5bc9425f2bd3506e4a164cd5@127.0.0.1:0","enr":"0xf88fb840dc163ce6d8e977e2d01bde715e6b77a6ae29ee68c87cd245047d2f0afc728e847b4674905af3780f2ef7e65dfdcebd5d5a59aa7ba20985ba5edc2edbacc2aa430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031adbc1635af8ae835d3041edc8a5c633f40a009111b6a74e0cce501181b7ea3b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OWN9hua+axvMNCc4qEo298YgLKbh2jeVJPXI2QGK6ZM=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39637d\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 d9b8 f9ee | 2 d9b8 (0) f9ee (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 1 3eea | 1 3eea (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","private_key":"777c522fea2223bf13c53cc946d4761b29a5f071939160197b8305faff375f5b","name":"node_39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","services":["bzz","pss"],"enable_msg_events":true,"port":45013},"up":true}},{"node":{"info":{"id":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","name":"node_f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","enode":"enode://81d15729673f044e747a296362aceca03a5cec3dbab718bdced562ed52ca46cadcd387403307d69e55793b1bcfd275428d5235492acc0b03d44fc7c320dbb8b8@127.0.0.1:0","enr":"0xf88fb840bcc07b798defeb3fce1c5c15a3a5a1e2ed4f586606b450bf24d63fd0ac43447041869c05e4809d6d7ff1f293d020ef37cd0d9d5ddbbba85db19b26e78cd4276c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10281d15729673f044e747a296362aceca03a5cec3dbab718bdced562ed52ca46ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+e53D2+b3csevlmvzABou1NIZNZs5D2H+yVQOMEqT9U=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f9ee77\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 3eea 3963 | 2 3eea (0) 3963 (0)\n001 0 | 0\n002 1 d9b8 | 1 d9b8 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","private_key":"33058348a654e1f7083b1e151159be731dce92dc63fd6a8218d05a0a79556264","name":"node_f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","services":["bzz","pss"],"enable_msg_events":true,"port":42259},"up":true}},{"node":{"info":{"id":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","name":"node_d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","enode":"enode://45ce3a7edb53c1ba49af48932d23cc431c8093e16363be0c164d7a2d91a9b42292fcab0a19f44961c660670ab35585f06671af76660e1879bac551649eeaf383@127.0.0.1:0","enr":"0xf88fb840e84fc1155908a63c768932ac73515e5badc69a4c9870628174f0ada2b2c51b884cd5023d2c99f9ea91f859daec2b6f1861dfbed2a79d64e2ec7d0d5e10b96a670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10345ce3a7edb53c1ba49af48932d23cc431c8093e16363be0c164d7a2d91a9b422","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2bjt/6M4O2+EZ7ihQyGyRPLrgR/+/oFicF7mHdgxnrg=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d9b8ed\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 3963 3eea | 2 3963 (0) 3eea (0)\n001 0 | 0\n002 1 f9ee | 1 f9ee (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","private_key":"212d7f1311d01b67472c5f08b993f423ae2479ce51b31e223b2d2569b8fe9b2b","name":"node_d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","services":["bzz","pss"],"enable_msg_events":true,"port":42359},"up":true}},{"node":{"info":{"id":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","name":"node_3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","enode":"enode://a858788ee0cfe3e41f87f7f08d6e1f4af3b46aac21c031eb764995c70c13e103dccb92a70cd85004343bd6b52cdfbd448c0692ffb332a328d0655d1e82c67044@127.0.0.1:0","enr":"0xf88fb840e7edbd4abbf61818777dd83a7a33d3ae7965c97845955e1fe850d5826159898f076a7b650aadee767bcf047dbdd7b64e362f458e2dfadc5bf61a70e3bc98e4400183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a858788ee0cfe3e41f87f7f08d6e1f4af3b46aac21c031eb764995c70c13e103","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PuoGR7u2jhDE7X7KZGtlCIJBFE/qQ/OajBtp8CXjqKM=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3eea06\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 f9ee d9b8 | 2 f9ee (0) d9b8 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 1 3963 | 1 3963 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","private_key":"0e14c45740f36d25300cd008dd1e1c1f98d39c519a1fee65fb30e004f1a992df","name":"node_3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","services":["bzz","pss"],"enable_msg_events":true,"port":42157},"up":true}}],"conns":[{"one":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","other":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","up":true},{"one":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","other":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","up":true},{"one":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","other":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","up":true},{"one":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","other":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","up":true},{"one":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","other":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","up":true},{"one":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","other":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_64.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_64.json index d8031614..cd3d5593 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_64.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_64.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","private_key":"8f572fa1cb0643b3413cd0dfceac00a4dac9ec09af0c2d134809b6385dad35d7","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","private_key":"a66e079664952b1fb1028e959dd8a05a21477e2f298ea89592adc522d38e511b","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","private_key":"072e1cf99b52c2f1d40560809048fea86f39ae1db94bec2c9b71b0bfe092910a","name":"node03","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","private_key":"003ec9cb18f157360d7a3eb506b37ec69dbbd141bbeb7b8fae5f470b1a0768db","name":"node04","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","private_key":"fd6fc50368fbc7e848635726291264cf6ad682fb4fe785b724c8b22ea31e1e24","name":"node05","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","private_key":"da156f269cb01e7fbea5efd5f7ab6283ef0994a1ca139768f49c68e027ca76b0","name":"node06","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","private_key":"ae570046bebe22a2cd095ca2b2282cab29b2501c6f217ae3e19d96bace36c199","name":"node07","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","private_key":"dee3b946981d4b7bd055941cd6722b166efc24f28f6b26da9cd52a8f91f3a411","name":"node08","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","private_key":"b7e566b24a7c97f714c9920c4e426dd462ee171bb8fd91a3efee9bd1d28dd060","name":"node09","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","private_key":"070b030d06605c46eafadabb979d38f9d4f48cf55e24a96378f4f0bbe2806887","name":"node10","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","private_key":"4ad1a65bb55e2f6d41cc3383b1de11c79bab13723c02d4f5abaf725d6aaea3e4","name":"node11","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","private_key":"bbe3351a79ad82f8b832dc16567dd1bcc24b1897bc9bfec930f3461a61f7d652","name":"node12","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","private_key":"26e548a577ae1fcc718256e75d48d70ed406dda8798f84c967d7dfe45c6aceb5","name":"node13","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","private_key":"97ca855261319532dfa74bf6194b4302c3d2f971adbd462e3437408df6dcbe47","name":"node14","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","private_key":"a762e1b25bed356f9a9e3aed01c7a38e8f57441b6caa18874712ef1159616b57","name":"node15","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","private_key":"53407f7862d16cdfd7beb23612d5d57dda1963cf729766feb046966e15850b32","name":"node16","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","private_key":"f3ffbcce6a7f7bfe25c3ab3ba95dd0574944bb5a09eabda3da69f187c48ea747","name":"node17","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","private_key":"0fc26e702e6bf4755536ef14b178df72099f9d2e818b53ce85f5b5ff3ea6c9c8","name":"node18","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","private_key":"6f1be181439476148e13cd2c39dd8983588047ef5f966091688ce37a01f78441","name":"node19","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","private_key":"b2732f7493e1101eb17248f6a6d83b5811c49cfc13f1aa41a624d1bb3e85368f","name":"node20","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","private_key":"b573a79bddda3cee3997d5c1210e33810dfce4f43a9a47d3f41ad02352d0515e","name":"node21","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","private_key":"3e8547c0320dad0457a7c6d576c1700ac4af59504cae9178faafcd60c9830e99","name":"node22","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","private_key":"dcee5e2db10836dcd5e3bbe14845a6203eebb791ae82200732e6b21d453e0642","name":"node23","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","private_key":"e895b2d5bfbd538d231463563cec8889c8aef0fbeb77acfd3ab9bb75504d39cd","name":"node24","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","private_key":"199b03688e42fbdcdd00b6230f59bf7a0b6ac22f6088c7d398535121f867b30a","name":"node25","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","private_key":"04a50f62b3bd30de9b6a4ca7c72d0fe81f6c111ab99bbbf4bb9c21b6c8983639","name":"node26","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","private_key":"dee1658338c1840984753b1121833d17232db7a62a8ed1b4fc1268e99138385e","name":"node27","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","private_key":"9fa3a527ec0ce68f936c2dadcc080238cfd5a3a462c20462567976eaf1d52810","name":"node28","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","private_key":"26df6d28e33e4da3390df260d9bbad739c31cc494a632239633485872b1ead29","name":"node29","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","private_key":"d7549640c8223b3b3e55195e3b519a85b7af1f1fc26ebbd56c9117a639544593","name":"node30","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","private_key":"16ea03e396aba3e56e9e2d89e53b68e46e51408b090fe2b99e65591ae6cd02c0","name":"node31","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","private_key":"2f111d17fef6870e109950bfd76e7e6db0913a06d14f8f5a311a39f447e65aea","name":"node32","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","private_key":"b20e729862ae141e3134c9eb2ed703957c0fd006f041df213946d66bfe06a3a7","name":"node33","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","private_key":"d35682e43d6382cb9508e5479fc2d09bec82166746bd406cc249f655715ae986","name":"node34","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","private_key":"9d7b2568317659ec35ed53c64f5c1aa0813dde36f1f492139ffefdd91ae0717e","name":"node35","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","private_key":"1177e7fa4a1e785fc30996682cf9ecd265d86943f65d7e3cf4c25cefcd861479","name":"node36","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","private_key":"29e2a9ddf2c5b8914fcf8d3782d464b0be6252d589b2a7daa1ea6b93b205c4f4","name":"node37","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","private_key":"de7a36b57175c1b9dd9686884f73048ea29215a01fdee9f2cf5068218efdc9d6","name":"node38","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","private_key":"209fa24e0d0a335e74967ae3ca2914ea6fb1ac99b9495820e9680855fab3081f","name":"node39","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","private_key":"225e538725db916b0e7be129cbda4da08e6be4ccaef64cf870551466d2658834","name":"node40","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","private_key":"1cf5c454ae9746fb367557d4f4a4a9d22157508dd1b19223b4640a3fa9c1dce8","name":"node41","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","private_key":"e4f81e7a844611f55194d22f62b681f479dadd58596a292cbbf6ef794df1c99a","name":"node42","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","private_key":"cfea4812067444b8816b5d70ed03fe5491d28ca6012a871bcb8aebbd100f9489","name":"node43","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","private_key":"384043ea1944918b9fac6bbbd88341254533ae49e3b2ce16c1df0941b1118303","name":"node44","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","private_key":"2de5004aa7337bd0819c88121cb0e708bc072c153bf94e274d7e786288996630","name":"node45","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","private_key":"aeb73b9ba035e0d3569e9dd5780dea2994151e2b43cb74e0e297fa285ba3d794","name":"node46","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","private_key":"6f192dda3ba98c5d13e94cc2e64ed95478ee64e97b230f224237977bf04cd724","name":"node47","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","private_key":"5c3a125bd1eca6243b28fcbd20a0811d7e09ce602ca98ba5f253435d76e0e4a9","name":"node48","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","private_key":"e4c7dec3dd327bfaa41b91fb8ccdbb96156d1fe464da973445a35f61e5bc6814","name":"node49","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","private_key":"07853d60907494e01f54f879c85c5f3fec6d4d615f9553d12b3da9ea1ad7a4ec","name":"node50","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","private_key":"6de081218acdb9ac4c4b8fbf1fde5f2be3c601cbf9104c970de43c2512c5e4c3","name":"node51","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","private_key":"7b7cb0ca071a27ee059bda50862b7fed343122d2546f5ac5a49dd5b47910530a","name":"node52","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","private_key":"542108cf09fe9447bb772d25802153811dd504943271556789165c6742636520","name":"node53","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","private_key":"87ab72e1c606a3b799ef3f34d3aa14549953c570f569a7b7952bb8f460b05a56","name":"node54","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","private_key":"a568b1f02f9c9129fd2924f704b8948351325edea81e43132c857be97dc7216d","name":"node55","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","private_key":"885083158aab574e1ab94645ea978b0e98a06605b1cbbfc48450f46522476b22","name":"node56","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","private_key":"5ee85ab61759ce457c89801346b14f68f1f16d6c59b2c034a2aef87242488041","name":"node57","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","private_key":"0bc8227f073c115b1ecd2add3e0ce8f58974528279de040eeaf189abfa6bc506","name":"node58","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","private_key":"a548a32f98cf950d6811b01fd764cd17b51d7012b18e944b3bb90dc660e35817","name":"node59","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","private_key":"55c9fd7b7ce7d50376a51050ac0a0a61b4657f9392ad14509bf432758a02b102","name":"node60","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","private_key":"daa4e758bca88df487bb1bcd41e59643256d23f237f96d654010801c07240435","name":"node61","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","private_key":"0090eced227d4fcb0e639349e4164040aa3c9d858531c2df416023c416753a5d","name":"node62","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","private_key":"96f0c30375428cd6184d43806adfbc9a4600e0180b50afa6ce06bfb1581cf1e0","name":"node63","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","private_key":"4738e28b9e3f0920f9c89ac195862299c670e5b354e5bbd644395336a446166f","name":"node64","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","other":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","up":true},{"one":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","other":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","up":true},{"one":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","other":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","up":true},{"one":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","other":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","up":true},{"one":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","other":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","other":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","up":true},{"one":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","other":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","up":true},{"one":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","other":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","other":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","other":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","other":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","up":true},{"one":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","other":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","up":true},{"one":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","other":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","up":true},{"one":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","other":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","up":true},{"one":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","other":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","up":true},{"one":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","other":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","up":true},{"one":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","other":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","up":true},{"one":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","other":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","up":true},{"one":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","other":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","up":true},{"one":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","other":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","up":true},{"one":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","other":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","up":true},{"one":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","other":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","up":true},{"one":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","other":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","up":true},{"one":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","other":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","up":true},{"one":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","other":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","up":true},{"one":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","other":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","up":true},{"one":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","other":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","up":true},{"one":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","other":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","up":true},{"one":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","other":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","up":true},{"one":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","other":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","up":true},{"one":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","other":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","up":true},{"one":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","other":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","up":true},{"one":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","other":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","up":true},{"one":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","other":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","up":true},{"one":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","other":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","up":true},{"one":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","other":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","up":true},{"one":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","other":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","up":true},{"one":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","other":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","up":true},{"one":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","other":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","other":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","up":true},{"one":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","other":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","up":true},{"one":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","other":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","up":true},{"one":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","other":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","other":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","up":true},{"one":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","other":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","other":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","up":true},{"one":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","other":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","up":true},{"one":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","other":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","up":true},{"one":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","other":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","up":true},{"one":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","other":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","up":true},{"one":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","other":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","up":true},{"one":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","up":true},{"one":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","other":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","up":true},{"one":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","other":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","up":true},{"one":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","other":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","up":true},{"one":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","other":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","up":true},{"one":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","other":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","up":true},{"one":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","up":true},{"one":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","other":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","other":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","up":true},{"one":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","other":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","up":true},{"one":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","other":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","up":true},{"one":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","other":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","up":true},{"one":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","other":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","up":true},{"one":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","other":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","other":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","up":true},{"one":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","other":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","other":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","up":true},{"one":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","other":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","up":true},{"one":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","other":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","up":true},{"one":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","other":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","up":true},{"one":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","other":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","up":true},{"one":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","other":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","up":true},{"one":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","other":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","other":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","up":true},{"one":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","other":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","up":true},{"one":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","other":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","up":true},{"one":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","up":true},{"one":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","other":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","up":true},{"one":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","other":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","other":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","up":true},{"one":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","other":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","up":true},{"one":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","other":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","up":true},{"one":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","other":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","other":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","up":true},{"one":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","other":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","up":true},{"one":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","other":"9bb12f66006f3347790c2c4e74e5463fd6ab651768296ee41de51757b9f40b89","up":true},{"one":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","other":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","other":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","up":true},{"one":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","other":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","up":true},{"one":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","other":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","up":true},{"one":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","other":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","up":true},{"one":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","other":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","other":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","up":true},{"one":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","other":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","up":true},{"one":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","other":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","up":true},{"one":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","up":true},{"one":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","other":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","up":true},{"one":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","other":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","up":true},{"one":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","up":true},{"one":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","other":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","up":true},{"one":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","up":true},{"one":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","other":"74117e299fffce1ef7f323ea1d6fb1c509cd5581f6c53e0f5e9af8d0b83748f2","up":true},{"one":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","other":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","up":true},{"one":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","other":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","up":true},{"one":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","other":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","up":true},{"one":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","other":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","up":true},{"one":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","other":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","up":true},{"one":"7f4198ddcfb55e9f690024cc19ce4f32d5bbc8d56cfb43f806513a74e52dc277","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","other":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","up":true},{"one":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","other":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","up":true},{"one":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","other":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","up":true},{"one":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","other":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"cec77f188351d24d5067de2e0cc57b48a9a5455d78bda6b7632d14a679070c3d","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","up":true},{"one":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","other":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","up":true},{"one":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","other":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","up":true},{"one":"292bb75a5407dda2ad7b642b1b790264e7ce16bbd8cd22e512eeec3d600ea520","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","up":true},{"one":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","other":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","up":true},{"one":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","other":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","up":true},{"one":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","other":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","up":true},{"one":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","other":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","up":true},{"one":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","other":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","up":true},{"one":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","other":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","up":true},{"one":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","other":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","up":true},{"one":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","other":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","up":true},{"one":"b52335dfb9367471204dfba231ba274815b859164e19ee872e20326d0575b88a","other":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","up":true},{"one":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","other":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","up":true},{"one":"0f5c44c74d4cc9b10d283a0099fba5f925c3455f5308d2044c377f8a5181703a","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","up":true},{"one":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","other":"3bc8d405359a665d3f6d64cf9ba194b7e614c2050add0a1205be7f6c3c984e1d","up":true},{"one":"0b45cb8af78fb1af7ab55d022ed00da66393b7eea1b7a3a2f802ffeba4c79dd3","other":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","up":true},{"one":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","other":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","up":true},{"one":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","other":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","up":true},{"one":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","other":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","up":true},{"one":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"ab1c8bbfea9434576e15465cfbd66e8c6565345d83e248d6fcd3748e82806c95","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","up":true},{"one":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","other":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","up":true},{"one":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","other":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","up":true},{"one":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","other":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","up":true},{"one":"8c5f07bdc96c7bbd8fc7bcf5e3ba841cabfc47f910acbf416730f5e67f847b34","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"e75238135f0c071ca541fb0a9569e38036c51af350a16bf4a1526f1752318059","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","up":true},{"one":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","up":true},{"one":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","other":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","up":true},{"one":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","other":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"e0463c87b0b7deefbd521721430e0fd24683aa8b41c65f259d678d9844bd800f","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"cf69e5f8effee000dc16109a7e0d04e4e13aeb2f6c089999e555946a46e548f6","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","up":true},{"one":"9e9451cb84ec10881e16a87d84b0e4e1aa78f5e9bc49ca5244a3da414b5210da","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","up":true},{"one":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","other":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","up":true},{"one":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","other":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"5e64f329525e17129b3f51580b399a5f09d7652a663bbaac83c8173dd9fded41","up":true},{"one":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","other":"39e710327f4176b5ed7ebc921db592a6b9197b237029faab4525a00d18470e8a","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"7fe48790180ab38e7687009847285f7af5e73b21b60cfad9d844ba8b2e7576e4","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"6a5cd611a5a8a94c82d6d3b40912909f326d4111c82983c3f719cfa3f621312f","other":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","up":true},{"one":"cee0b72bcb0a112c9aa33eb80166d279c2cc0216782a19454a086c0147b8126d","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","up":true},{"one":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","other":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","up":true},{"one":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","other":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","up":true},{"one":"1f17c9223987ccf4d9683df0664cd568164c69d2f62bad2a79ef4636623ba87a","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","other":"aa655b48b225d692184a21a2f7162950851a914f89671cc1af3e87a21b37c5e3","up":true},{"one":"5c197e623ab40c0de2c83a4ffd16930cf791e60357f162f5b2a2e865ff0cea73","other":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","up":true},{"one":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","other":"34ad9431b71cdeae0c1941b3ae680387b3cedd815f39d65034892920aa869f38","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"e45d7b4870acb8a984c065cce7bd17acaf79c5ad4d477f810563315aebacd8e3","up":true},{"one":"2597463214ea0faa3db781fa8cb336da59aff43553f045a0f704ab10f5f54cf2","other":"0f988a170fdc7761b8d9814a1a7ac0cc0e98483b91841046b9948783befeed88","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","up":true},{"one":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","other":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","up":true},{"one":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","other":"903561af2459b0e46d8188121e66d8b999ad39341944eb099eff70213244c813","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","up":true},{"one":"6b336cfff0d431edce4cee0cf35ffb1e50b7a5c6e15d3d816fb1bb1cf6488f22","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"9e384d8e6d319016c2807884e0b46da4ce9fcb426efb76224ce41b5d4dae5632","other":"88b4c3d6ae6a1d4c39caef84d56f308b58e2ca0477cc5197f3f5be41c890bd7c","up":true},{"one":"b45f23d6ac8824b480f71f25abf5aa2c9db4c3a904660d391768168430355827","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"647ccb25b23a917f611a46a72b12fd457610f07143155e1f828b41fd2d3e0b58","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","up":true},{"one":"cfc872fe7f213f4ada5ec413037450ae2b141157c83998b9520ac2ddb51707bd","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"e0205da225e77fa15332864eaef1c437be306090b0489faf3f6725cb3c5b4712","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","up":true},{"one":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","other":"461c7f8f8948693dea717679ffc4bbf0eb573f4597543993e3be39d3594fdd47","up":true},{"one":"5a4fa4f4482dbaf7bbe6c3d2ae28c35187fbd0f00d1293be41719aa8e5e4a388","other":"6d29dbed992f0f0008a72978045df08a4ae1753571fdefbb676f52b5ff843433","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"5fd664467fac65594c3dd6f89bf2a5398e28aa95d248c3a3d21abaecfebfde5d","up":true},{"one":"66d586d2f06e0b26d051d3fed949bf8f36ca3ba4c64b8230987ae0c7d29c2dfd","other":"71fe0f225ee23106cb6d6c57cdeb49ecc4ffb2b13441956eca6d94505aa2a72c","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"85d645e3738c441f508671f52cde0aa7ae2032c082c86b7ca6af92598d7174d5","up":true},{"one":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"9045e912dc0acaf9d86ec75d98e93bc90832dbca1119641f8569a98040be940c","other":"80d0a541f041fbab580164228d09af6be9e3beec5301e998398231362298835e","up":true},{"one":"cc708e47196a6435b13b18f213f50bf075f3f97100d52d18d70052efc301c91a","other":"b2a236a2acf5cf675c521a3e87ef847933e1736c220a54cf66db4ba03f369483","up":true},{"one":"bece4d99fafdcebd22f03a4640026c55f7155ff814b295a2aec7a98d3973595a","other":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","up":true},{"one":"b04c7f907691ac51adab6fe657dd4592044ca4222ee60eb86c7851c855057a8e","other":"a416fa852bb425e00b805ffabb525ae45024403685a0e8a67815617fd1d078da","up":true},{"one":"bd5b11dfb3bf903c4cb8ce44756e41fefb5582deb79055ccc65fe7b47b2a1a41","other":"a365bf427dc109429657033f4b7b22575b6a8d955d6eaf44288725e5e47b0a86","up":true},{"one":"f0517f6a1187d0f454aaf98506fdc830e14d31259fbf195f1694078dcaa5582f","other":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","up":true},{"one":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","other":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","up":true},{"one":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","other":"eebe8082b0f6efbade062eb49f2592519524a8c3f22975ba901ed9755a9d0ead","up":true},{"one":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"113d7850e8169761d357e0ad5a262560fe6137fc6a992b3b2cedcebbe5d5f6a2","up":true},{"one":"4ff286f9e1f7d2d0a8e14a5547e03580d67dbedd1e2ca0c88ad01a2e56c0f45c","other":"5205bbd1c298864045f08fe7cc4c2409055db3ee4d790d2587c9ca3366acd977","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"1102d287c72becf1bfa8567cf43cc2051aed16a79196f9109cdedf829a2a5a2d","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"c85b39668486c5eb3ea9f312d9897bda5688c4995318e4e64a0be2ac0cb47692","up":true},{"one":"d79a1e6f3dc0e3382eaccdc1fb0f49cd66f483addcc52d767fc12f4b6754e206","other":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","up":true},{"one":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","other":"2218170def9962d400bf932ced91f3c14595062b50ef86eb4d2f7fd384fc8597","up":true},{"one":"cab41b44229682f11d6aca3d3136597524e9eb4e1640147b87f3f8c7227959f1","other":"f3a57f887ddcf1793207948374ce67da9f6a1227f253e3a90acc5b36a48ee645","up":true},{"one":"df45befed47eec3248ce3b55e9cc56f8d718fc13dcb1a03755cdc0cda89e4dcb","other":"c0d6b4950771888e9770051d341f2071fecdb09e28c289e251668327eb8ccf66","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","name":"node_177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","enode":"enode://b2ecd384df0c1911a363892a8f9f92276afdadbd9766d5367e9426baaf52db54607ef8ed20c6013bcd31216645721a66b33c2afd1f995665b49ef32554fa55c9@127.0.0.1:0","enr":"0xf88fb84084a65eedfefa09006c370680d7af5b4d4600e9775cc2fa0a778a6ca5adf131810dfcdc8b9509da7bbb1a1a865244daf2d32b34b96a9c005080f94eeaf270099f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b2ecd384df0c1911a363892a8f9f92276afdadbd9766d5367e9426baaf52db54","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F34jK9upcPSwAbIor5QC4/ygqvAGgqEbyZhPfbS3/ro=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 177e23\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b73b be2b | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 3 452b 581a 5602 | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 3 255d 3103 3abf | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 3 0acb 0727 0486 | 5 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 154f 1455 | 2 1455 (0) 154f (0)\n007 0 | 0\n008 0 | 0\n009 1 172b | 1 172b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","private_key":"1286e8188fe5e907890aef4a270d2307e0937dd38d9340f4e56829fd23413f31","name":"node_177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","services":["bzz","pss"],"enable_msg_events":true,"port":40837},"up":true}},{"node":{"info":{"id":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","name":"node_be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","enode":"enode://7f0ebae8d5040cd874605d9ec6c3a7cb63c1b7cf90d06f7d0b0c7066569ef465f68eb09c19058d1c9cde1d99ae351e95196c1feb2a9ce64ef17076510dd0cd7d@127.0.0.1:0","enr":"0xf88fb840daad2aad3a4d7ff125994a1b8646db6d4bee82774004dd547373a34e6b456b4b34d740e306f79da7c50ae15a5d4dfb60af9dd435898e901986b0570d184a8c2e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037f0ebae8d5040cd874605d9ec6c3a7cb63c1b7cf90d06f7d0b0c7066569ef465","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vivLj7SzTuaYHmY0uPMpj7vudW9udlZiBKVruGyOwPA=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be2bcb\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 7d69 177e | 30 452b (0) 581a (0) 5f83 (0) 5e36 (0)\n001 3 c0c2 d3c1 f6e5 | 17 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n002 5 8673 856e 8926 8802 | 8 8802 (0) 8926 (0) 821a (0) 856e (0)\n003 3 afb1 ae60 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n004 2 b73b b374 | 2 b374 (0) b73b (0)\n============ DEPTH: 5 ==========================================\n005 2 b8f9 b8f3 | 2 b8f9 (0) b8f3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","private_key":"1bfc88f8747bfe3f0686c0dd06c6994f80bc3109cbce619c87194df9c0af35ec","name":"node_be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","services":["bzz","pss"],"enable_msg_events":true,"port":41679},"up":true}},{"node":{"info":{"id":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","name":"node_7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","enode":"enode://73efd5ce9d1348bb96a73682ab0e0523106c449265974c594f34a445de026e1225f2a1e0cd7d95a391563cdda852cb9ed50a12a5ba174447ac1320743429f15a@127.0.0.1:0","enr":"0xf88fb84027a696cdd03ce902b65824023e0014604a449a0ab2819e417b664ea0f292ea690de64c4fec6dc5b80d5f97fb7c03e0168027a60d77a65ee8845dd7a519d7a7f80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10273efd5ce9d1348bb96a73682ab0e0523106c449265974c594f34a445de026e12","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fWm1cHpLme3ZATF/FVP/FVhqrDUPOODIExjzXWi4Nag=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7d69b5\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ebf2 fb7e 8802 be2b | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 3 255d 3103 154f | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 5 452b 581a 5e36 52fc | 8 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 703d 70d0 | 2 70d0 (0) 703d (0)\n005 0 | 0\n006 1 7f80 | 1 7f80 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","private_key":"138b2b1614eba35db1d63a8b4cad155aae9ffe67aeba89da6b77c32d8085978c","name":"node_7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","services":["bzz","pss"],"enable_msg_events":true,"port":37997},"up":true}},{"node":{"info":{"id":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","name":"node_154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","enode":"enode://5383cc445c43a2ed3afe5922fc466e7ad833fadea40c63e1fd3bf6c1beee0db531a26c526994d14249bf854f9b36b49e7416d55407d49a3a70608f02419bc8b9@127.0.0.1:0","enr":"0xf88fb8403a38e49c1e706672d35d764ebcf564cca19c96df63f8777ef17eff0305791fa14a022147e46d186121c4ff0d52488b51e3929b5ba536dffe4e7fb7957f7909940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035383cc445c43a2ed3afe5922fc466e7ad833fadea40c63e1fd3bf6c1beee0db5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FU/sX6cor5VqFEa9WjXmPXFreagEGXtQ/ZxyWF0ES3c=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 154fec\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a12b b8f3 f6e5 | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 4 581a 5e36 452b 7d69 | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 2 274f 3c40 | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 4 00ba 0257 0486 0727 | 5 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 177e 172b | 2 172b (0) 177e (0)\n007 1 1455 | 1 1455 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","private_key":"ce1506c16008e68cab421b02e7de0e8bf64bd8061e84336dd3ee4e7382078bb5","name":"node_154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","services":["bzz","pss"],"enable_msg_events":true,"port":41399},"up":true}},{"node":{"info":{"id":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","name":"node_3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","enode":"enode://f98b58ce571bd762921cf62c8001f481eb582bf905c42e8d40eab48cfe6394065721413958fe1a1df85e350f6075bda55b7a8745eb329b11e462282dbc1e7012@127.0.0.1:0","enr":"0xf88fb840193b2d1eaa7d147a52bd4c4a65a9d70c37b92c837f74d8f919a893605560b33c4d5a6df29825a8a430f4e250e5e3a6ec8ce78ec940c759c0b3369cb52ea8e3c90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f98b58ce571bd762921cf62c8001f481eb582bf905c42e8d40eab48cfe639406","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PECeW3bpd+4xFaChlUDdZ0XmC4h4/cGlwdmW5+R8qWk=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3c409e\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 821a e6cf c3b2 c461 | 34 821a (0) 856e (0) 87aa (0) 87ac (0)\n001 3 70d0 6123 5602 | 13 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n002 3 0727 0486 154f | 9 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n003 3 274f 255d 248a | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n============ DEPTH: 5 ==========================================\n005 3 38f0 3abf 3b4f | 3 3b4f (0) 3abf (0) 38f0 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","private_key":"4e158a7430c532fe0c5fbd4e063cbce5fbd793a516b0d9b2728daac7741a71b9","name":"node_3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","services":["bzz","pss"],"enable_msg_events":true,"port":33099},"up":true}},{"node":{"info":{"id":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","name":"node_c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","enode":"enode://a8deb108b6c33a1abc50c0ce0041d4c5de23f17171fb3558dc0a4aed942dc887bb56c0917ed3032af073d8b2415e0879e264370a800f64d060f8f8e1c096d04d@127.0.0.1:0","enr":"0xf88fb8409107e601aef81da4e1f9a95006f25aeec3f9d59b329245d0475a4a3347ee4f7e69b4c64a5401e0679d1ab092d618b1d678a77ba22e43159d1d46790338e165e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a8deb108b6c33a1abc50c0ce0041d4c5de23f17171fb3558dc0a4aed942dc887","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xGHkMMiHiUu7/04ze2HuRJzxLMB9D8X+QXhdWA0Wrpg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c461e4\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5f83 52fc 452b 6123 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 5 b374 87aa 856e 821a | 17 821a (0) 856e (0) 87aa (0) 87ac (0)\n002 2 f211 e558 | 11 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n003 2 d904 d3c1 | 2 d3c1 (0) d904 (0)\n004 1 cb8d | 1 cb8d (0)\n============ DEPTH: 5 ==========================================\n005 2 c0c2 c3b2 | 2 c3b2 (0) c0c2 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","private_key":"978cfc6313655f0d829dc91a0545aa1369f3b0baafc201c8cbc641c965f85b77","name":"node_c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","services":["bzz","pss"],"enable_msg_events":true,"port":43525},"up":true}},{"node":{"info":{"id":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","name":"node_e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","enode":"enode://26b5014af36030418be4bbab747a56da3f0a0b96e77a5c732cfdf7f61ca71d565f2b43bbbb44d2d047a3c549971b88655d62a889afdbb724e8fefe656dbe2b5d@127.0.0.1:0","enr":"0xf88fb840015e82c76a09041b22bbd93a7ea12ce2f51fbc04bb6629d1f8055d626456b7215bbec219530291b84fb78db61bbd25983f693c69d221fa1155ee0947690be72b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10326b5014af36030418be4bbab747a56da3f0a0b96e77a5c732cfdf7f61ca71d56","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5VgQXSrrWciW9ftwR1sEbZA070WW6c1fVPFsMWRJJB4=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e55810\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 70d0 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 2 87aa 821a | 17 821a (0) 87aa (0) 87ac (0) 8673 (0)\n002 3 d904 d3c1 c461 | 6 d3c1 (0) d904 (0) cb8d (0) c3b2 (0)\n003 3 fb7e f211 f6e5 | 5 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n004 3 eb30 ebf2 e9fd | 3 ebf2 (0) eb30 (0) e9fd (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e6cf | 1 e6cf (0)\n007 0 | 0\n008 1 e5e1 | 1 e5e1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","private_key":"62f09d35ddecb1f76c961bd8188912d6ea354de35322e5add87d2eca8154ff74","name":"node_e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","services":["bzz","pss"],"enable_msg_events":true,"port":32823},"up":true}},{"node":{"info":{"id":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","name":"node_e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","enode":"enode://44a78245fbc89e776a8d27b4548fe61dc789a02628d3246a364971e9ebb1497b72d487ce9d7a0745d667c8adba7db2bf35aac7e327a49728bad8184be24dc311@127.0.0.1:0","enr":"0xf88fb840126f89ca6d674b29c05eb8517aa48cc039a7f289bc17d7e1bc24485e90fa504a1ab8b4c6df373aff9c75943533a3b5955016e0ef89824e23c4cb1b06b86d41d60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10344a78245fbc89e776a8d27b4548fe61dc789a02628d3246a364971e9ebb1497b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6f1c1/jSjKFyo9Mx2kAemFPTEhkjyBv4J4f3mJAJ5Do=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e9fd5c\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 70d0 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 2 821a 9629 | 17 9629 (0) 821a (0) 87aa (0) 87ac (0)\n002 2 d3c1 d904 | 6 d3c1 (0) d904 (0) cb8d (0) c3b2 (0)\n003 2 fb7e f0e9 | 5 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n004 3 e6cf e5e1 e558 | 3 e6cf (0) e5e1 (0) e558 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 eb30 ebf2 | 2 ebf2 (0) eb30 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","private_key":"e1866d6c66f9cdff0845058b114b9a15a4967274ad9cda558e102be0a746e9dd","name":"node_e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","services":["bzz","pss"],"enable_msg_events":true,"port":36597},"up":true}},{"node":{"info":{"id":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","name":"node_f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","enode":"enode://39fc37e1b4c1d8d2906469ea880448186e5246e849c0b6f79952d9254173f1d88e5e06d9331f14bd5052073d2c2d28106ca84ae08fab04d3217db4233fd750dd@127.0.0.1:0","enr":"0xf88fb84088c04103f60facca986ee3d5509cb1e58a231d8dc712d3df77c917f1aa9c27df5a9b0797512f9d61477075a6b766f14ea88d4ae2311b8ae23274327c0d9ba93c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10339fc37e1b4c1d8d2906469ea880448186e5246e849c0b6f79952d9254173f1d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8OkA7ze6rWoWharxcA6SkOfpwNXTDjJlIE7JQ0RSSLM=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f0e900\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 70d0 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 3 821a 9629 aabc | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 2 d904 d3c1 | 6 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n003 2 e6cf e9fd | 6 e6cf (0) e5e1 (0) e558 (0) ebf2 (0)\n004 1 fb7e | 1 fb7e (0)\n005 1 f6e5 | 1 f6e5 (0)\n============ DEPTH: 6 ==========================================\n006 2 f211 f35a | 2 f211 (0) f35a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","private_key":"d85d087c4d2770c08517c1b719cd6805713af1046aeba2bd6db5e31402388df2","name":"node_f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","services":["bzz","pss"],"enable_msg_events":true,"port":45551},"up":true}},{"node":{"info":{"id":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","name":"node_aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","enode":"enode://df29ae71bd1cab0ab806f7dea6545ae649dc9e0640e8d1bef8f6b518c4a75e822f1ac2a937b117eed3faf5f9a4e718d31899d4a6466c33fd6ee520daae0650f3@127.0.0.1:0","enr":"0xf88fb84046f68bd288eb808ea2aa0bbf41922e0e52f2bf6dbd65f83ce2d9632d94262fcf2af844233c694aec3e77cb82eb24aff844c4aa24be379900ec5323a3218b8c430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df29ae71bd1cab0ab806f7dea6545ae649dc9e0640e8d1bef8f6b518c4a75e82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qrxYfdw7fUk86OhJsV02QmXFfTo6UmEwdqWzGATLdT8=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aabc58\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 172b 6123 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 3 fb7e f6e5 f0e9 | 17 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n002 3 821a 87aa 9629 | 8 9629 (0) 821a (0) 8673 (0) 87aa (0)\n003 2 b73b b374 | 5 b374 (0) b73b (0) be2b (0) b8f9 (0)\n004 1 a12b | 1 a12b (0)\n============ DEPTH: 5 ==========================================\n005 2 afb1 ae60 | 2 afb1 (0) ae60 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","private_key":"2338394db2f3550707f783ab13a9427021f5e6be8b3431444d735c6506fc2b2d","name":"node_aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","services":["bzz","pss"],"enable_msg_events":true,"port":34323},"up":true}},{"node":{"info":{"id":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","name":"node_f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","enode":"enode://f5975ee0b5c78d6bc4a68b9b35744cec5ac5922b8da008a4b68a8e9ceee9a6d3a817b21d8b51f9fe35123317bc22cbd1dd37d18f93c433a8d82d25774bc84f59@127.0.0.1:0","enr":"0xf88fb8406c21f34341248451d882a4655a586feeb202f8cb7d47b0da9bd8a4f5f915128228efd4998dcfb8d43543463364a2937db016284e0bb78cfec37208079bb910020183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f5975ee0b5c78d6bc4a68b9b35744cec5ac5922b8da008a4b68a8e9ceee9a6d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9uUUjSQhrhHooQmFLJ2ne75Jj55u06o2F1Wh/z/Sm3Q=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f6e514\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5508 154f 1455 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 8 8926 b73b b8f9 be2b | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 3 cb8d c3b2 c0c2 | 6 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n003 5 eb30 ebf2 e6cf e558 | 6 e6cf (0) e5e1 (0) e558 (0) ebf2 (0)\n004 1 fb7e | 1 fb7e (0)\n============ DEPTH: 5 ==========================================\n005 3 f0e9 f35a f211 | 3 f211 (0) f35a (0) f0e9 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","private_key":"f6740a5cf46069cee8cdfefdd049e563958cbda7e4c59315d0276a92915efe0a","name":"node_f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","services":["bzz","pss"],"enable_msg_events":true,"port":40421},"up":true}},{"node":{"info":{"id":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","name":"node_1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","enode":"enode://b5e652612f7909a70ecaf98ed27cc962687c895a349dcc80a326794a291a3851a3ba447345a30263a39c29f730276e1b1810813d39975649c50537c0febf67f0@127.0.0.1:0","enr":"0xf88fb8405d344eda0bf71d02e1171dbf8e3b0ae13b7091d138dbc1ed3f568b08dea67f526ec263da507139112160bd3260e7f3582b1fe88aa0501cf52d73650bbdb2d6ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b5e652612f7909a70ecaf98ed27cc962687c895a349dcc80a326794a291a3851","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FFXUcTtRNOkVdRe4SwThUpLPGNPgi5XWnxlkj7njgj4=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1455d4\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a12b f6e5 | 34 9629 (0) 821a (0) 8673 (0) 87aa (0)\n001 4 5f83 6123 703d 7f80 | 13 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n002 3 3103 3abf 38f0 | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 4 0257 00ba 0727 0486 | 5 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 172b 177e | 2 172b (0) 177e (0)\n007 1 154f | 1 154f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","private_key":"50925145323eadd436d028b14956413b9ce4a6e6e12ee61bc6f39b7bdeb607ce","name":"node_1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","services":["bzz","pss"],"enable_msg_events":true,"port":35787},"up":true}},{"node":{"info":{"id":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","name":"node_38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","enode":"enode://48f1b561316fb88b3f6966b6b77793eb73ade705dffda5b5e889665c61f61eb65fc53b12a893affa1626e2c066c218fbf0cacc47ae235f284b99d1ddb70a1b7b@127.0.0.1:0","enr":"0xf88fb840ac0a5221c7f96140e1c2b39e3ce570681198f21499c4ac2d4cf71f13084d1d463ea56145f4bc0ae39e1bcf6f728c0fb8bcb53b6f59ff82ca0c91761364ae2aeb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10348f1b561316fb88b3f6966b6b77793eb73ade705dffda5b5e889665c61f61eb6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OPBa9AzQ3Dl06JbiSqdevaHJbwzn2eP/DqhAYVGGMH0=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 38f05a\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9629 821a 856e | 34 9629 (0) 821a (0) 8673 (0) 87aa (0)\n001 2 6123 5508 | 13 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n002 2 0acb 1455 | 9 00ba (0) 0257 (0) 0486 (0) 0727 (0)\n003 3 274f 255d 248a | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n005 1 3c40 | 1 3c40 (0)\n============ DEPTH: 6 ==========================================\n006 2 3b4f 3abf | 2 3b4f (0) 3abf (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","private_key":"72aaff493375ffe3fdf32b207dec2bf4b6947a83b0be8a39d016a620e5d84166","name":"node_38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","services":["bzz","pss"],"enable_msg_events":true,"port":46291},"up":true}},{"node":{"info":{"id":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","name":"node_0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","enode":"enode://f3639f1bd30e3cf2653b9a4f9d20fab2897ba468020ec336c3eff2d6a4b27c4d3f7f01a6e2cbc6496e8ab4b435a53a518f45a78752b9ecce6ff119cd83eae04c@127.0.0.1:0","enr":"0xf88fb84093cbe4a72d6dc31819c9cd24e75d7178f02135c11b41668880b6c4ce743b2602056aa9103ed6fbdaada4c85913a2f4bf90dd092942db61a1df54c4269cc2f46f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f3639f1bd30e3cf2653b9a4f9d20fab2897ba468020ec336c3eff2d6a4b27c4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CssXM0JTQIp3MgIEHUpnx4c7DnTpTIbjND+0cL3L7YI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0acb17\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b8f3 821a 8926 9629 | 34 9629 (0) 821a (0) 8673 (0) 87aa (0)\n001 5 57d9 6123 70d0 703d | 13 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n002 3 274f 3b4f 38f0 | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 2 177e 172b | 4 172b (0) 177e (0) 154f (0) 1455 (0)\n============ DEPTH: 4 ==========================================\n004 4 0727 0486 0257 00ba | 4 00ba (0) 0257 (0) 0486 (0) 0727 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","private_key":"f732331fdd132dd9b4c64ae5c42247591f96dc911fe6a706b14a10ce3a8ed9d6","name":"node_0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","services":["bzz","pss"],"enable_msg_events":true,"port":44253},"up":true}},{"node":{"info":{"id":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","name":"node_f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","enode":"enode://e745eb6d9e95b82f6b4a6fbd9fb578c5ec53de4bf64bf008a25af4595cf01cd932b1070c197157ebeddcf79d4659acc3a6244177421656d601eb1a108f6c8ab8@127.0.0.1:0","enr":"0xf88fb840fd81f60522c3b56a658b661d599993ff0aca7eaadae4a28bff72103db1ffda910194afe2e3799b9f30d6b7c9134a70f7d05f79b082b70dba836d6ae907720f5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e745eb6d9e95b82f6b4a6fbd9fb578c5ec53de4bf64bf008a25af4595cf01cd9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"81pH4dVqbY5cqtUNiOVcg/87lksnm1ilDV5UT/kYeGQ=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f35a47\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 703d 6123 0acb | 30 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n001 3 9629 821a 856e | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 2 d904 d3c1 | 6 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n003 2 ebf2 e5e1 | 6 ebf2 (0) eb30 (0) e9fd (0) e6cf (0)\n004 1 fb7e | 1 fb7e (0)\n005 1 f6e5 | 1 f6e5 (0)\n============ DEPTH: 6 ==========================================\n006 1 f0e9 | 1 f0e9 (0)\n007 1 f211 | 1 f211 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","private_key":"bc31ff1a3354902df6fdba93d648599c420dc962166cd94ba5c9c88781f7b1ac","name":"node_f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","services":["bzz","pss"],"enable_msg_events":true,"port":40235},"up":true}},{"node":{"info":{"id":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","name":"node_e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","enode":"enode://12f560588c3394b54f4be445fbc804457f104c736613aa7516dcdc935bc1004c7489dbd657445bbcfd5d1b4f85571f2805789d680c6e7bdb08950b548093de42@127.0.0.1:0","enr":"0xf88fb840510aeffd2b76786cd66e778ad5f1c6301affb8c7f1a226cd32e3d61f23da281c79562ae15cbd94ce4a39dff5596492b2716cf58c476ce701e22a641d60a8a4af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212f560588c3394b54f4be445fbc804457f104c736613aa7516dcdc935bc1004c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5eFm+F6p4mT8JXNFI4adm5FvOIAEy0r5lolWzhSnpSI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5e166\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 703d 7f80 | 30 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n001 3 8802 856e b8f3 | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 2 d3c1 d904 | 6 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n003 3 f6e5 f211 f35a | 5 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n004 2 ebf2 e9fd | 3 e9fd (0) ebf2 (0) eb30 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e6cf | 1 e6cf (0)\n007 0 | 0\n008 1 e558 | 1 e558 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","private_key":"25c5ec054b6f8975276f7c37381908b15ba3fdd204996e80188c27a45a120156","name":"node_e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","services":["bzz","pss"],"enable_msg_events":true,"port":42811},"up":true}},{"node":{"info":{"id":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","name":"node_b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","enode":"enode://1eafb72a59e875d1e4c6fcfc48e3b83060dc7edf1745dc4b4d69920b5c498a0aa5028ac463be2a03331b3f50634295010786205311e2dde4214f5375d846be46@127.0.0.1:0","enr":"0xf88fb840f39e6fb0bc59342b1e5379ca1dfe35c07ed85b72975e03d86b5eaacb2845d6013b15e070b59162b9da5f6a9459e9d69522dfd0dd5dc6eab1478e26446d3adf640183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021eafb72a59e875d1e4c6fcfc48e3b83060dc7edf1745dc4b4d69920b5c498a0a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uPNFlAvO2IMbMAef8qJ2q2X77Q3YV1yTo8zYx70byLE=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8f345\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 00ba 0acb 154f | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 2 cb8d e5e1 | 17 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n002 3 821a 8802 9629 | 8 9629 (0) 821a (0) 8673 (0) 87ac (0)\n003 3 afb1 ae60 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n004 2 b73b b374 | 2 b374 (0) b73b (0)\n============ DEPTH: 5 ==========================================\n005 1 be2b | 1 be2b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 b8f9 | 1 b8f9 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","private_key":"f213075c2bb9ce044c3ea7e245d0e841eeb4448cb914bad8b7cc2aaf223494f5","name":"node_b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","services":["bzz","pss"],"enable_msg_events":true,"port":32901},"up":true}},{"node":{"info":{"id":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","name":"node_cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","enode":"enode://b86efbaace42f2f41e4faeb180734ba7b3bcd88ce25a4b671f0522e50bccc0544084a0f72f57d3183269bc433e8522e008fcf70990130bd428e679cd2ef2301e@127.0.0.1:0","enr":"0xf88fb840fd41041292742e2d87cfac656804056de57d38166539d75aa87d8ea4028c8b905a7395663eced2fb92ca0b03214bb0fd07d36096c4fa09e3b51edc25293577d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b86efbaace42f2f41e4faeb180734ba7b3bcd88ce25a4b671f0522e50bccc054","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"y43xg+f+pPgI7VadP6CmwmZw9kUbmp9I6GWYccK5qwI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cb8df1\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 274f 0486 0727 452b | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 5 8673 87ac 87aa b374 | 17 9629 (0) 821a (0) 8673 (0) 87ac (0)\n002 3 ebf2 f6e5 fb7e | 11 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n003 2 d904 d3c1 | 2 d904 (0) d3c1 (0)\n============ DEPTH: 4 ==========================================\n004 3 c461 c3b2 c0c2 | 3 c461 (0) c3b2 (0) c0c2 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","private_key":"492d4a83cd01c80cafe080a10aba2708adad9d57c896ddd20c3f1783fb8c8ae2","name":"node_cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","services":["bzz","pss"],"enable_msg_events":true,"port":37973},"up":true}},{"node":{"info":{"id":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","name":"node_c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","enode":"enode://5307ee476b7d4a7cc8fff3c91a49faff9ef919880ec9f6c2bbf3e57f27bd769f5692a37e70531c902a3d1e519fcbfee9cbd946d008e3653287786ead5083cedd@127.0.0.1:0","enr":"0xf88fb8400e91dade29f3fd1bfebe010d282d7b43d12bdf0bcae8e2e549a2e1ed15785ac4504f8048792eba8a6518ad1ae28b39fd2b21dac0adf4e65609f6da91de0b618f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035307ee476b7d4a7cc8fff3c91a49faff9ef919880ec9f6c2bbf3e57f27bd769f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wMLXOr0rarw7oLCYUgxMw+2mG1/J0atC69BOzCXe0iQ=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c0c2d7\npopulation: 12 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0acb 00ba 0486 | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 2 be2b 8926 | 17 be2b (0) b8f9 (0) b8f3 (0) b374 (0)\n002 2 f211 f6e5 | 11 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n003 2 d3c1 d904 | 2 d904 (0) d3c1 (0)\n004 1 cb8d | 1 cb8d (0)\n============ DEPTH: 5 ==========================================\n005 1 c461 | 1 c461 (0)\n006 1 c3b2 | 1 c3b2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","private_key":"2c6df66c8a1843928d4ff1c1f86261392e9ba859e1d50dbc7e47344968446e7d","name":"node_c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","services":["bzz","pss"],"enable_msg_events":true,"port":46541},"up":true}},{"node":{"info":{"id":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","name":"node_892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","enode":"enode://d2b6d26acb63edf3d8f2e7ba86fce1304441bb3a8c9138e4069412e556fe677e49bf669824144f7f2f752c1ba56d21e1d5b2583b7ce06db6f8e466929bb54fa3@127.0.0.1:0","enr":"0xf88fb84030e09ff37ec6e84f56137ccc06cfe91eec3cfba76fd5f655d4220c8984c2bf74694a268165a67c073623dd0c8ef0879ce3f78eddf5ce61832a0f755c5342a26a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d2b6d26acb63edf3d8f2e7ba86fce1304441bb3a8c9138e4069412e556fe677e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iSYD/GT+FprRVRkGDPsdJ3gK3/YNpg+GpiDyv5p8oeE=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 892603\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 00ba 0acb 57d9 | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 3 f6e5 fb7e c0c2 | 17 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n002 5 b73b be2b afb1 ae60 | 9 b8f9 (0) b8f3 (0) be2b (0) b374 (0)\n003 1 9629 | 1 9629 (0)\n============ DEPTH: 4 ==========================================\n004 5 821a 856e 8673 87aa | 5 821a (0) 8673 (0) 87ac (0) 87aa (0)\n005 0 | 0\n006 0 | 0\n007 1 8802 | 1 8802 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","private_key":"44e05a26b9222f67f884d2093377f119349ef6710b86f7b7edc2f0e61793a1ea","name":"node_892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","services":["bzz","pss"],"enable_msg_events":true,"port":33109},"up":true}},{"node":{"info":{"id":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","name":"node_57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","enode":"enode://0527dc36e6d408034587180c2cadb429ac1ea5e4cf5ffaadf60e8af1bbef30368fc234f75f7ede63d70df8d932f3fae54ba14fdbdb033a18ec2e914b85594f0a@127.0.0.1:0","enr":"0xf88fb840783a349f43c192ad36b674821f63954fd4de02eb076100f9dab68b0fe5eafe8051d208f26c93e9ad609307b169dba4ea5236c4cb557365c16b94e96fc85372eb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020527dc36e6d408034587180c2cadb429ac1ea5e4cf5ffaadf60e8af1bbef3036","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V9kR+GS+epDYgHvD/s1ljFaX1wzz3cwd3g3ZvQ/X+2c=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 57d911\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d3c1 eb30 8926 | 34 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n001 4 0acb 0257 00ba 0486 | 17 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n002 2 70d0 6123 | 5 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n003 1 452b | 1 452b (0)\n004 3 581a 5e36 5f83 | 3 5e36 (0) 5f83 (0) 581a (0)\n005 1 52fc | 1 52fc (0)\n============ DEPTH: 6 ==========================================\n006 1 5508 | 1 5508 (0)\n007 1 5602 | 1 5602 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","private_key":"34c80a58a443bb0e1518a14f812731f34ed2a04d27aad1978a43edfdc46b1219","name":"node_57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","services":["bzz","pss"],"enable_msg_events":true,"port":44125},"up":true}},{"node":{"info":{"id":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","name":"node_eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","enode":"enode://f3a08e5df6a6bcf751846b6ace6f57a31a6d449df1d48df065dea5bfc74586b8933323a5b063ec3e7ae58f7e038d7c218ad2294587029267bb4c092388609234@127.0.0.1:0","enr":"0xf88fb84056d0cb9ccc119c03a9f1d32aedfd19f6e27d6813d9a2ea1813e35ac670286db72f8b2d4481d401b7f7464d2cacd28c10aacbde6fdb7a0b4a83ede973c90042310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f3a08e5df6a6bcf751846b6ace6f57a31a6d449df1d48df065dea5bfc74586b8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6zB6bzM7MOvR47K1G9gJUxHUhwfWyiyBRH0BrUU+JUI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb307a\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3abf 57d9 | 30 177e (0) 172b (0) 154f (0) 1455 (0)\n001 3 8802 b73b a12b | 17 b73b (0) b374 (0) b8f9 (0) b8f3 (0)\n002 2 d3c1 d904 | 6 d904 (0) d3c1 (0) c0c2 (0) c3b2 (0)\n003 2 f6e5 fb7e | 5 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n004 2 e558 e6cf | 3 e6cf (0) e558 (0) e5e1 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e9fd | 1 e9fd (0)\n007 0 | 0\n008 1 ebf2 | 1 ebf2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","private_key":"46e33ba68cfba7f42ff80b2a4e6e42af54661467f574487ae9dd64d58b7f1bff","name":"node_eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","services":["bzz","pss"],"enable_msg_events":true,"port":43461},"up":true}},{"node":{"info":{"id":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","name":"node_3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","enode":"enode://51deaa308d9269c160365fdfcbb25f60a03a82f2efaff308a0eb09a18cf138beda36562ac1c16957da7172ce518f770d922c053efc2c3bce06419cc6e0928014@127.0.0.1:0","enr":"0xf88fb84053019049f1135e4048d6971781321d1f8b972fd8a2a99e110a64833ce5a36834048b662125d1775ff49679add18eb3d76c36c8ec11be8647e6c523b5fe93a8160183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10251deaa308d9269c160365fdfcbb25f60a03a82f2efaff308a0eb09a18cf138be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Or/p9Pao00tTbQJVH0XAOjWYe5T30zs6DcMK00sV+Co=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3abfe9\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b73b eb30 | 34 b73b (0) b374 (0) b8f9 (0) b8f3 (0)\n001 2 452b 7f80 | 13 452b (0) 5f83 (0) 5e36 (0) 581a (0)\n002 2 177e 1455 | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 3 255d 248a 274f | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n005 1 3c40 | 1 3c40 (0)\n============ DEPTH: 6 ==========================================\n006 1 38f0 | 1 38f0 (0)\n007 1 3b4f | 1 3b4f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","private_key":"93982f270ea11ec36ba55e97235856f2ed6fab52aa3d0249bf628e2b9c91d9dd","name":"node_3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","services":["bzz","pss"],"enable_msg_events":true,"port":34193},"up":true}},{"node":{"info":{"id":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","name":"node_7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","enode":"enode://51bcf947a12e8ac505ec8b402224676a504d2c39b71e446006083d741c461c94ab190ab816afaef8a6b24df9b56e6e9f8a30eb2bebd6a7df58e67e31c8c4e405@127.0.0.1:0","enr":"0xf88fb840f65e01347df378f48f5e7ebbb387f2f2cde36dd9aaede48ab5819adf690d1f87361843b84b8b6ab295420b7bf4eb9b12d169c9c53f2ef3d01db492bf9ef0735c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10351bcf947a12e8ac505ec8b402224676a504d2c39b71e446006083d741c461c94","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f4AOWnlwIw9Sc+SZccfuUh3pfmn1bdVU4w3RLW+1x0k=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7f800e\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f0e9 e9fd e5e1 e558 | 34 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n001 4 0acb 1455 3103 3abf | 17 154f (0) 1455 (0) 177e (0) 172b (0)\n002 4 452b 5602 5508 581a | 8 452b (0) 5f83 (0) 5e36 (0) 581a (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 703d 70d0 | 2 703d (0) 70d0 (0)\n005 0 | 0\n006 1 7d69 | 1 7d69 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","private_key":"015cba3c04c983b51b26debe83456fc5ce953a720c5d618632a551198845ce87","name":"node_7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","services":["bzz","pss"],"enable_msg_events":true,"port":37409},"up":true}},{"node":{"info":{"id":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","name":"node_ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","enode":"enode://8d29ea4346f1503c80ef55fdb63d33a2d857bbda499bfd296afd75a9ae9badd16b3328fe1ba73b31a2b3cd6600d7fd33d2bfc6dcd1e61dc369f505b16c9df1d5@127.0.0.1:0","enr":"0xf88fb84025b8f01e1b8f2908011afc21980bd9d8b915e89b8851d351a509936bc3202d886b91cb5b9a1c2ba97ae71a5f776d2075237ee89af24379ed746fcf3e3e8eafe60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038d29ea4346f1503c80ef55fdb63d33a2d857bbda499bfd296afd75a9ae9badd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rmAj1BbIe7Qz652NRPl1MXl9KSd0ME2ZaSOj/meIdHg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ae6023\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 248a 7f80 | 30 154f (0) 1455 (0) 177e (0) 172b (0)\n001 4 e6cf fb7e f6e5 f211 | 17 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n002 2 8926 9629 | 8 9629 (0) 8926 (0) 8802 (0) 821a (0)\n003 3 be2b b8f3 b8f9 | 5 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n004 1 a12b | 1 a12b (0)\n============ DEPTH: 5 ==========================================\n005 1 aabc | 1 aabc (0)\n006 0 | 0\n007 1 afb1 | 1 afb1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","private_key":"22c2fb65420237f8b89643102304e7ec4785bd727e32cf8d324a08c0c83bbcc9","name":"node_ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","services":["bzz","pss"],"enable_msg_events":true,"port":45469},"up":true}},{"node":{"info":{"id":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","name":"node_a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","enode":"enode://89914e07e3f818e5857dcf267822b10d9cf455fa7a2fa5b39ec98ad1f931ca0e8b152354d3514f26c9f1414aa10d95d96089819546a41a6f91a6e3c6d3399463@127.0.0.1:0","enr":"0xf88fb8400dc63a9d8ef5bc6b6aeef2fa584f5336ea901d50124c1606f8b2378173ebc2fd66efbc2bdcea10e1ae4587ac22cda0b5d5808a02865c0519648ccce893f76c9a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10389914e07e3f818e5857dcf267822b10d9cf455fa7a2fa5b39ec98ad1f931ca0e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oSsSCBttSegjeNUjl2W8qMX0MjKzAWO8RpJMw+mOEXc=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a12b12\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1455 154f 3103 | 30 154f (0) 1455 (0) 177e (0) 172b (0)\n001 3 e6cf eb30 f6e5 | 17 f6e5 (0) f0e9 (0) f211 (0) f35a (0)\n002 5 9629 8673 821a 8802 | 8 9629 (0) 8926 (0) 8802 (0) 821a (0)\n003 5 b73b b374 b8f3 b8f9 | 5 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n============ DEPTH: 4 ==========================================\n004 3 aabc afb1 ae60 | 3 aabc (0) afb1 (0) ae60 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","private_key":"d7090c3295beb236fb881805333f666cea56d6dea2f42bf3b4ac5b607c63808d","name":"node_a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","services":["bzz","pss"],"enable_msg_events":true,"port":46387},"up":true}},{"node":{"info":{"id":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","name":"node_3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","enode":"enode://2566b869c3ead5eb369d120bdcfb5915162a7ab2b1ad732e88d9d977100c395a12867c8d6d2ce3be2dfed18ce3fc994523093fc48b01e1f7f6c1b9c6d2d2564e@127.0.0.1:0","enr":"0xf88fb84085e944ff27136b601bf818ec370a678631bb4b993981f6f37d4239904fd4c05c7a7bb06485217f380c84013e3ff57efd5f916325ce8929a2429a12af8a95a2bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022566b869c3ead5eb369d120bdcfb5915162a7ab2b1ad732e88d9d977100c395a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MQPNC3ZU9ZO3Io0XFSCfJ+M5rQFAGalzhBOiDLasY+Q=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3103cd\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 856e a12b | 34 f6e5 (0) f0e9 (0) f35a (0) f211 (0)\n001 3 7f80 7d69 6123 | 13 7f80 (0) 7d69 (0) 703d (0) 70d0 (0)\n002 3 0486 177e 1455 | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 3 274f 255d 248a | 3 274f (0) 255d (0) 248a (0)\n============ DEPTH: 4 ==========================================\n004 4 3b4f 3abf 38f0 3c40 | 4 3c40 (0) 38f0 (0) 3b4f (0) 3abf (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","private_key":"95e6a35c4e714e2f717338757d55e091a179f90a24a9b669a758172f5685ca01","name":"node_3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","services":["bzz","pss"],"enable_msg_events":true,"port":36983},"up":true}},{"node":{"info":{"id":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","name":"node_856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","enode":"enode://bed85f28b7443ca051f8cc01c76cc4b73c1f4d737c273cbb726decbe6e2f3b4b22529e7ae589c40805650784c8d367e53525041825bc8377747743342d1d5ffd@127.0.0.1:0","enr":"0xf88fb84059a5c37cb0e55cbcde717bcf88c22f5c5a45df4aa83358375f04b00efa5e65203ef0371f0755c1afc0d541bf9fab3e7292d4150fbafab8fbb2d627ef6b7605b50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bed85f28b7443ca051f8cc01c76cc4b73c1f4d737c273cbb726decbe6e2f3b4b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hW4nymiamyr0zT7ZWPIWK5xxB0xyaGisehCsL299Ah0=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 856e27\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 38f0 3103 | 30 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n001 3 c461 e5e1 f35a | 17 eb30 (0) ebf2 (0) e9fd (0) e6cf (0)\n002 2 b8f9 be2b | 9 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8926 (0) 8802 (0)\n005 1 821a | 1 821a (0)\n============ DEPTH: 6 ==========================================\n006 3 8673 87aa 87ac | 3 8673 (0) 87ac (0) 87aa (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","private_key":"35fb992eb3f4de7a3ac9e68c81b4f1e62d1f474eedd1bbd0d6b588d4a123faa3","name":"node_856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","services":["bzz","pss"],"enable_msg_events":true,"port":42951},"up":true}},{"node":{"info":{"id":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","name":"node_88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","enode":"enode://e15ed0ea7080c438ee8f5e359fe828ea27f1cd348449b819cf9ec4df58dbac3a08423e6d525f011d5f41cecc440a49c9b12c6dc8ef3380b5bff38cf6b9ce0e11@127.0.0.1:0","enr":"0xf88fb840617403b8f0d402717d1f39440b4cf23b906c9df7c10b4c846599b0a4787e289b29afdd85207fcfe39147c0467347702bc44ce5da6fe7200a0e57dc2baa99433d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e15ed0ea7080c438ee8f5e359fe828ea27f1cd348449b819cf9ec4df58dbac3a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iAJLn2hDRrd1wcHrbpcJA0E1lXq0GOwAJyXxDviRmDc=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 88024b\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7f80 7d69 255d | 30 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n001 3 ebf2 eb30 e5e1 | 17 eb30 (0) ebf2 (0) e9fd (0) e6cf (0)\n002 5 a12b b73b b374 b8f3 | 9 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n003 1 9629 | 1 9629 (0)\n============ DEPTH: 4 ==========================================\n004 5 821a 8673 87aa 87ac | 5 821a (0) 8673 (0) 87ac (0) 87aa (0)\n005 0 | 0\n006 0 | 0\n007 1 8926 | 1 8926 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","private_key":"31dbecd3ca7aa370e3a50aaac4f98bef73f2527b1896da7ed889a43ad771c2e8","name":"node_88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","services":["bzz","pss"],"enable_msg_events":true,"port":40113},"up":true}},{"node":{"info":{"id":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","name":"node_255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","enode":"enode://bb25c5b1634689128e4f6bd8c31f0ac70a9b0dd37e9fbeda681e96ae04a19553f5534314a8e675e517d5ca0013bf79de3893a40c1c2734ef4243d1db4ed08060@127.0.0.1:0","enr":"0xf88fb840a4996422aeb3198fc58ab411a6910daa8a05d960911ef17cc7b14152653cd219771997a20423baa0c51b882a843135d99c31b01eabed91a4818f2cb573ab00660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bb25c5b1634689128e4f6bd8c31f0ac70a9b0dd37e9fbeda681e96ae04a19553","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JV240xGmanRDsV0ECvoGYm1pGcDSCm/Q9a+jTocoFzI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 255db8\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d3c1 d904 821a 8802 | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 3 7d69 5e36 581a | 13 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n002 3 0257 177e 172b | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 5 3b4f 3abf 38f0 3c40 | 5 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 274f | 1 274f (0)\n007 1 248a | 1 248a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","private_key":"2ced13cc7febab95479e76339b80139922095bf66b8d47541c9bc22789123a9f","name":"node_255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","services":["bzz","pss"],"enable_msg_events":true,"port":40487},"up":true}},{"node":{"info":{"id":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","name":"node_581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","enode":"enode://9096985dab960112b5511301c88595af2dc0a90852fc6a98c0970cd20b0b11ada5293e4f8b066fbaf3b0a207d51cf0e3d0a50ada11446814054b39e6265cda7e@127.0.0.1:0","enr":"0xf88fb8402f9d16c72c43c1856f7d778c531ea65e02a0450905075f9bdddc9c2938b042941177b8854391706ee69ca82d23eb5654fb434b767fa732ca8167c32c33f5e00a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029096985dab960112b5511301c88595af2dc0a90852fc6a98c0970cd20b0b11ad","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WBrZLUNHg0hQwW54GYPAm+NAkXUno13ZZQxaPaH8gis=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 581ad9\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9629 d904 cb8d | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 4 177e 154f 0727 255d | 17 154f (0) 1455 (0) 177e (0) 172b (0)\n002 3 703d 7d69 7f80 | 5 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n003 1 452b | 1 452b (0)\n004 4 52fc 5508 57d9 5602 | 4 52fc (0) 5508 (0) 5602 (0) 57d9 (0)\n============ DEPTH: 5 ==========================================\n005 2 5e36 5f83 | 2 5e36 (0) 5f83 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","private_key":"39aed43a62aad671048b07d25383bb957d88b3bd53c0a52a9b73f132241f47bd","name":"node_581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","services":["bzz","pss"],"enable_msg_events":true,"port":38101},"up":true}},{"node":{"info":{"id":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","name":"node_0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","enode":"enode://90b8c983944e79f3081d0e6e7538f2e6fe78ba7a63412aa32fb3b08b02ed6efad44f45d6e2db83d67a03d0242e3ffd8e62703f0e4e6b74e48331c6b3a8c51db1@127.0.0.1:0","enr":"0xf88fb8409af7b76fd8c8b31f077a6f2fd5be9cd7b6f5f7d1c0dcd1d517334d649fc9f8140f432c4c4641c970093b46b75371213bf7e3e21e3b0e486e4160a092d71f53310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10390b8c983944e79f3081d0e6e7538f2e6fe78ba7a63412aa32fb3b08b02ed6efa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ByfX5owxnTpMxaFh3QWyp+cjUME55lwgkMEjLrvtX3g=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0727d7\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d3c1 d904 cb8d | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 2 6123 581a | 13 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n002 2 3c40 274f | 8 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n003 4 172b 177e 1455 154f | 4 154f (0) 1455 (0) 177e (0) 172b (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0257 00ba | 2 00ba (0) 0257 (0)\n006 1 0486 | 1 0486 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","private_key":"312ee0e8a214abbd131a0e03c9c30710cbea185776d03bc7e6319eb1ce1d8c9d","name":"node_0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","services":["bzz","pss"],"enable_msg_events":true,"port":34603},"up":true}},{"node":{"info":{"id":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","name":"node_6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","enode":"enode://9a0af04a8b33cefc1178e827baadd6211134e17e6d17dda345d9a1af47e657e487d46382b137bd50829a3b49663160237c9c4ae9e5aa57249791029026b71ad8@127.0.0.1:0","enr":"0xf88fb8408d49aa1cfaa238a09955f64747940c56d3e4efcb913e43f3f12bc586038ec8a40405758ebe81aeba159213fe543a4c60c4119097c6eec92157eba0659cd944b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029a0af04a8b33cefc1178e827baadd6211134e17e6d17dda345d9a1af47e657e4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YSO3d33jvCWR4wNqmt66H32OyTPQXuT+ABeRCJaSXRs=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6123b7\npopulation: 33 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 aabc ebf2 e9fd e5e1 | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 9 38f0 3b4f 3c40 3103 | 17 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n002 7 452b 5e36 5f83 52fc | 8 452b (0) 5508 (0) 5602 (0) 57d9 (0)\n============ DEPTH: 3 ==========================================\n003 4 703d 70d0 7f80 7d69 | 4 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","private_key":"a32ad9e8eb034068af76013c458a289d8bb4faf6000aa63666404d8be13bf5d6","name":"node_6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","services":["bzz","pss"],"enable_msg_events":true,"port":37555},"up":true}},{"node":{"info":{"id":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","name":"node_04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","enode":"enode://0314da640d0324270183587d5ee38b6d7f82082def277f1fa70f2dff054becdaab3c31aa4921f4bdeb7f4c31adc8a70ad09609868642101b3e63eaab91727d69@127.0.0.1:0","enr":"0xf88fb84082ed1045bb3ffd5e7d12ace534321c835e31ed2db07e7eb5bfc3bb200d7e0fb23f55e4975e73ed36e6de025624ddc499148b4d9d8001734be2cd014a9e84cb8d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030314da640d0324270183587d5ee38b6d7f82082def277f1fa70f2dff054becda","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BIYlUO84+DEIXzeOJTOt3CyQQog5RjEgjEnLM2Fa2js=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 048625\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b374 cb8d c0c2 | 34 be2b (0) b8f9 (0) b8f3 (0) b73b (0)\n001 2 57d9 6123 | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 4 3c40 3103 274f 248a | 8 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n003 4 172b 177e 154f 1455 | 4 154f (0) 1455 (0) 177e (0) 172b (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0257 00ba | 2 00ba (0) 0257 (0)\n006 1 0727 | 1 0727 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","private_key":"dadc2a0436842f90010d95ae0b3d5e1612d72a28854573e679a8a336f5370e21","name":"node_04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","services":["bzz","pss"],"enable_msg_events":true,"port":46049},"up":true}},{"node":{"info":{"id":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","name":"node_248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","enode":"enode://7f0f82c32f25e019be8cba115eba217f82432b010a401a273037351dca0b5c61089825d7b034801b2876318500c566b1991d1efcde1466bdcfee6a128c3bf81a@127.0.0.1:0","enr":"0xf88fb840bfa5193ddceefc65d57437eff8a7a774354003033fd5224a4d2edc41e43b3f5d50f4ea4346ea045e6985ccb53ff48ba17b317e791010248dbfa996b83c429aad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027f0f82c32f25e019be8cba115eba217f82432b010a401a273037351dca0b5c61","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JIouYYCR3urEWPR0FhZAXgvF/9oan5ElMH4yx4FyinU=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 248a2e\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e6cf ae60 | 34 aabc (0) afb1 (0) ae60 (0) a12b (0)\n001 2 5e36 452b | 13 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n002 4 172b 0257 00ba 0486 | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 5 3103 3c40 3b4f 3abf | 5 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 274f | 1 274f (0)\n007 1 255d | 1 255d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","private_key":"5eed72a77466e0457f248c4b926ad580c90bac7ee1e11bca5d5d20a9d2bfab5d","name":"node_248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","services":["bzz","pss"],"enable_msg_events":true,"port":35737},"up":true}},{"node":{"info":{"id":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","name":"node_172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","enode":"enode://a9a9c0be91c80c150ed76c716242763e92cfd34102db458614b97a2fdc1aa9046a873d2e16d6b720a82abef0c3d3afe50c548e82064081f6d3722bfaa8ad5a7a@127.0.0.1:0","enr":"0xf88fb840af989a0c29715008d7c936ddbe8af501a4904339da4b799f99369a5ae9937a805b29f031c54f88d358a298b4ecd360bc06b55108ecaecb17a31f9902f367f44c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a9a9c0be91c80c150ed76c716242763e92cfd34102db458614b97a2fdc1aa904","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Fyu7yqV8N8JDFKhPvQud5F+DpGAWvSOV3Crbqxu5C1w=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 172bbb\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 afb1 aabc fb7e | 34 aabc (0) afb1 (0) ae60 (0) a12b (0)\n001 2 6123 70d0 | 13 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n002 2 255d 248a | 8 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n003 5 0486 0727 0257 00ba | 5 0acb (0) 00ba (0) 0257 (0) 0727 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 1455 154f | 2 1455 (0) 154f (0)\n007 0 | 0\n008 0 | 0\n009 1 177e | 1 177e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","private_key":"2016f3bc79c1f5a91c126a6f548bdd080c149e46cb1165cf1002068c6fcda411","name":"node_172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","services":["bzz","pss"],"enable_msg_events":true,"port":42303},"up":true}},{"node":{"info":{"id":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","name":"node_fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","enode":"enode://f9175ab3d792f133155a959560213cc1c01279ed6e348a68906d8a96a87596baf128933900518e8d6aa1fda56b7139b3dc74dbb690196147ab6480b498c65dd1@127.0.0.1:0","enr":"0xf88fb8400494ee532414babfb684947ef027e954af32abe1255703856100999a37a3b27d4e3e6728f46532dffdb89272cb1948f5bc6df766b40fdd2797bed3c8148074870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f9175ab3d792f133155a959560213cc1c01279ed6e348a68906d8a96a87596ba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+35nFmFKyUG3Thipvz3tY7wAtFMiG0CXb3g2daHAbGM=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fb7e67\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5508 7d69 6123 172b | 30 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n001 5 8926 b73b aabc ae60 | 17 aabc (0) afb1 (0) ae60 (0) a12b (0)\n002 3 c3b2 cb8d d904 | 6 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n003 5 e558 e6cf e9fd eb30 | 6 e6cf (0) e558 (0) e5e1 (0) e9fd (0)\n============ DEPTH: 4 ==========================================\n004 4 f6e5 f0e9 f35a f211 | 4 f6e5 (0) f0e9 (0) f35a (0) f211 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","private_key":"8b2673cf73b2e993026f6a2c87caae15dba45720ad187f9c5f5ddbdc7d1b32a4","name":"node_fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","services":["bzz","pss"],"enable_msg_events":true,"port":40621},"up":true}},{"node":{"info":{"id":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","name":"node_f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","enode":"enode://3595a73fde880c53304b49c39683267c4fa90fa5773dc084a1affc7999314e2dab768ab82091fe068bb824cd54277129cc6f5d0065d9f2dfcf3392c048dcb7c5@127.0.0.1:0","enr":"0xf88fb840e00692e06d4b89b7bdd43adeba6626c5e4bba8988449a048ff3ce2ba802dad3a6f8c07c23a5d3ff37562cec16cff3eae3fb2dfd4e825a8e07ea04a4fa1a054b80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033595a73fde880c53304b49c39683267c4fa90fa5773dc084a1affc7999314e2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8hE3bUbm4JZu6YTPWDeAUkCyulPFrHUxXFbb3/uVemU=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f21137\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6123 3b4f | 30 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n001 2 b73b ae60 | 17 aabc (0) afb1 (0) ae60 (0) a12b (0)\n002 2 c0c2 c461 | 6 c461 (0) c0c2 (0) c3b2 (0) cb8d (0)\n003 3 e5e1 e558 e6cf | 6 e6cf (0) e558 (0) e5e1 (0) e9fd (0)\n004 1 fb7e | 1 fb7e (0)\n005 1 f6e5 | 1 f6e5 (0)\n============ DEPTH: 6 ==========================================\n006 1 f0e9 | 1 f0e9 (0)\n007 1 f35a | 1 f35a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","private_key":"cc85dc8007f84a1a4cef3b3f84345cf6212741fe8451882613368b13b8a21170","name":"node_f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","services":["bzz","pss"],"enable_msg_events":true,"port":33599},"up":true}},{"node":{"info":{"id":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","name":"node_3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","enode":"enode://185474977590e399a3bde82710d24deebb17ec414f3fa17d70550ccc7fd742d881f76c5ad58e5854b3cdc16d27789332ba975d840218a363adf9950251006852@127.0.0.1:0","enr":"0xf88fb84041802a5fbc1bf6e457fed3480b3d38fc2bd3d3fa40ca619ef6a09d58e5c1873958cd6cb13ab6d0709a9ee1172496e623f5c6d1ab202915f54b3f3bff6d1923ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102185474977590e399a3bde82710d24deebb17ec414f3fa17d70550ccc7fd742d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O0+n1ykSkGihKB72hJS2HQVSA96MNqX+J68+tWWDIQg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b4fa7\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 87aa f211 | 34 aabc (0) afb1 (0) ae60 (0) a12b (0)\n001 2 6123 703d | 13 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n002 2 0acb 00ba | 9 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n003 3 255d 248a 274f | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n005 1 3c40 | 1 3c40 (0)\n============ DEPTH: 6 ==========================================\n006 1 38f0 | 1 38f0 (0)\n007 1 3abf | 1 3abf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","private_key":"6ad42cf2ce8ec2d947696df2ab9fd0b464376964980f542777118020ce0e5d7b","name":"node_3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","services":["bzz","pss"],"enable_msg_events":true,"port":33419},"up":true}},{"node":{"info":{"id":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","name":"node_87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","enode":"enode://35b27d332ce1f35bec177a8c636960cbfb79cf58bb3f2d1b874231b382a0cdc590c4e8353decd2fe3b1b4f8542b03f2171425bff56edccbbd15272b3cace9a0e@127.0.0.1:0","enr":"0xf88fb8407dbd42f95e5ae03d53a9da07975ce124ffe18be69ad76c445cd2cb001e85da44048d49dca08d4efae5512882c98113f26c2f540eba64a1fd289c35fafa598c040183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10235b27d332ce1f35bec177a8c636960cbfb79cf58bb3f2d1b874231b382a0cdc5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"h6p33O8ZsMhqPoq2TI8S2acz53p+Eryuw6TNhQTFp3U=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 87aa77\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3b4f 70d0 | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 4 e558 c461 cb8d d904 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 2 afb1 aabc | 9 aabc (0) afb1 (0) ae60 (0) a12b (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8802 (0) 8926 (0)\n005 1 821a | 1 821a (0)\n006 1 856e | 1 856e (0)\n============ DEPTH: 7 ==========================================\n007 1 8673 | 1 8673 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 87ac | 1 87ac (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","private_key":"f61f38cd9320f5d79569492609fbc059d0c28376d87733386c34ed0ee05f9b52","name":"node_87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","services":["bzz","pss"],"enable_msg_events":true,"port":45677},"up":true}},{"node":{"info":{"id":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","name":"node_70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","enode":"enode://75f2fb6caf9b53cf0b82b5c6751b2d06f05decbce5a26d8196d2240fdc8b8cb7cfdac4f123838a8895d81578515dcd5b07ed1ff432667c175ca092bb241e5d81@127.0.0.1:0","enr":"0xf88fb840ca369a7e8bad45d547ba1b43054168da9813f7ebf8143be24488270f9cf1a3373939a5b2c228aa93a6857cc0b50be949c909531bb4269dfce238c9433aca848e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10375f2fb6caf9b53cf0b82b5c6751b2d06f05decbce5a26d8196d2240fdc8b8cb7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cNBxCziU+r8ys0O5tZM594bs45iVx+2l8WLMV1ycglM=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 70d071\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f0e9 e558 e9fd ebf2 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 4 3c40 0acb 00ba 172b | 17 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n002 2 57d9 52fc | 8 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 7d69 7f80 | 2 7d69 (0) 7f80 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 703d | 1 703d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","private_key":"c1017fa00e291b4183d30ab17ef32b438afcfd234be6cecbb9897bdb585a9a86","name":"node_70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","services":["bzz","pss"],"enable_msg_events":true,"port":39215},"up":true}},{"node":{"info":{"id":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","name":"node_52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","enode":"enode://b0a77e6fe1c5bc0275bbb7eca27007740ae80fe424fe6acf055bf84789dc99a14280d8c08d2d3a0cc7c2b996c091a5059ed083a8f289704b6e82234b20815447@127.0.0.1:0","enr":"0xf88fb840b35c45f9ad29f754a3318f771140615e64a3fc523df8dc7d6e4aba4bcafa4642422ae39afe0eba129bf9519377d0026bd546255261f4388dc0a7c89d2752e23c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b0a77e6fe1c5bc0275bbb7eca27007740ae80fe424fe6acf055bf84789dc99a1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UvweIZvFGPuvKJ2jI22Y2xtj3xIn6jJYEilnFHOtw70=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 52fc1e\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c461 cb8d b374 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 2 00ba 0257 | 17 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n002 3 6123 7d69 70d0 | 5 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n003 1 452b | 1 452b (0)\n004 3 581a 5f83 5e36 | 3 581a (0) 5e36 (0) 5f83 (0)\n============ DEPTH: 5 ==========================================\n005 3 5508 57d9 5602 | 3 57d9 (0) 5602 (0) 5508 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","private_key":"5128d9e0c20a65b00ada80037610ab8459cb99a9bc3cbc467f90e3d94868636e","name":"node_52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","services":["bzz","pss"],"enable_msg_events":true,"port":37815},"up":true}},{"node":{"info":{"id":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","name":"node_b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","enode":"enode://bddef211431764890d0c556f02492d623440dadef8220aa3d14cc5a4a176c0c6a3d9c51db26fa8d00e3b2919ae01708c6ccbcfb89300889f763e88e88f1cf62f@127.0.0.1:0","enr":"0xf88fb840fa92fb538dc1f10b99bd1a5ff04542a013336d8c78c82d02689092893de2558d3be1b76e10a87b2976ab77dba021345e4da01bcf57e968f16179262cbb7f7b610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bddef211431764890d0c556f02492d623440dadef8220aa3d14cc5a4a176c0c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s3RM9vGAwuuaHe0Obd1gDV95JoOHuXMzBw+1oYOv/Yk=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b3744c\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0486 274f 52fc | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 3 cb8d c461 c3b2 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 3 9629 8802 8673 | 8 9629 (0) 8802 (0) 8926 (0) 821a (0)\n003 3 a12b afb1 aabc | 4 a12b (0) aabc (0) ae60 (0) afb1 (0)\n============ DEPTH: 4 ==========================================\n004 3 be2b b8f9 b8f3 | 3 be2b (0) b8f3 (0) b8f9 (0)\n005 1 b73b | 1 b73b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","private_key":"f9b4401c90628262d75ec2b1472b181d0ba586f207e512d8c2bff501f6969006","name":"node_b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","services":["bzz","pss"],"enable_msg_events":true,"port":39313},"up":true}},{"node":{"info":{"id":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","name":"node_274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","enode":"enode://cd29948d6981370c284ab296a55d43dbe7203b54193b763b157977ad2952be300cafaad9cb5d51517a90c64254bc6a0e9b50e40f37487d9a824ff9f6a442d543@127.0.0.1:0","enr":"0xf88fb8400df64191c8bf59e9ac7ad80c636ae992d431ba5d833d277a482b3d374ef08eb8697eef5cbddfdf88bb8e260cb007083c6e9333a667d0cb7e4560630ceeb951820183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103cd29948d6981370c284ab296a55d43dbe7203b54193b763b157977ad2952be30","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J0+LdS7wyEpcMJgGawtNHAK4obFzD1ntlAZFNe7aR1Y=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 274f8b\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 cb8d 87ac 821a b8f9 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 4 703d 5508 5e36 5f83 | 13 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n002 4 154f 0acb 0486 0727 | 9 0acb (0) 0486 (0) 0727 (0) 00ba (0)\n003 5 3103 3c40 38f0 3b4f | 5 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 255d 248a | 2 255d (0) 248a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","private_key":"7ff83f61deceac3be4f65ab071b30e2906485aa9b9cf9762915bdab24ad3095d","name":"node_274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","services":["bzz","pss"],"enable_msg_events":true,"port":37995},"up":true}},{"node":{"info":{"id":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","name":"node_5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","enode":"enode://a75b279e617f6db28bac0fc33337d87e284116d2e3e069685fe1f42f46fdea15c51124ed699840d171f47d4778553e545475580f510a2ec4f830fedf460df0d6@127.0.0.1:0","enr":"0xf88fb840ef24e78bea8bf572427a95c9bf7cb2faffec0a4a430715acd4aadcdcdb78125e54a5d26f68b4d1be1551eb00e29157acb4b1692b27e80546b20bfd2dd0cd43a70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a75b279e617f6db28bac0fc33337d87e284116d2e3e069685fe1f42f46fdea15","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"X4MhWM+E4OSKNRiVWHixauJTRn9UZk607BIT/vw/Mnc=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5f8321\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 cb8d c461 c3b2 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 2 1455 274f | 17 1455 (0) 154f (0) 177e (0) 172b (0)\n002 2 6123 703d | 5 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n003 1 452b | 1 452b (0)\n004 4 52fc 5508 5602 57d9 | 4 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n============ DEPTH: 5 ==========================================\n005 1 581a | 1 581a (0)\n006 0 | 0\n007 1 5e36 | 1 5e36 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","private_key":"d19565076e49cecdfa86edf90fdaae204fb957d2aa8d76158101247c371fbecd","name":"node_5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","services":["bzz","pss"],"enable_msg_events":true,"port":45427},"up":true}},{"node":{"info":{"id":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","name":"node_452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","enode":"enode://dea46c610b096ce0543a2ecbed5434bf207a65a42457ddbc6c3132b6809d56a4b3037879121fd53a0c2c0c92fb3736f8373c987c1ba95992e53e2dbf8f35cb79@127.0.0.1:0","enr":"0xf88fb84083953db305d8b6d3f2a3d38e0e8f81c2381c85a3d80ffe54c2a6582a7076e63124e85a302030bc72cf9e748b50ce103fb12c6cd072472f538ff96ccdb08359300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dea46c610b096ce0543a2ecbed5434bf207a65a42457ddbc6c3132b6809d56a4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RSsH1zQz59bCBaUEQZrhAAGaoZIHIwEScrWWYH22aEo=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 452b07\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c461 cb8d 9629 8673 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 5 3abf 248a 177e 154f | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 7d69 7f80 6123 | 5 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n============ DEPTH: 3 ==========================================\n003 7 52fc 5508 57d9 5602 | 7 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","private_key":"92e76eb57823fd78556776b404da0b21c27ef8c4824adef769ea1c5f49ae3db9","name":"node_452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","services":["bzz","pss"],"enable_msg_events":true,"port":33293},"up":true}},{"node":{"info":{"id":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","name":"node_86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","enode":"enode://2733db14205f39cf4a5f52580a937dccc7220e36a80b7c541c95e9f5f1ab651bd96f451fecc2e2cdab225fc0e37fc63b70f3a4e84d99ceb7c2d7f1bf0a0f39f6@127.0.0.1:0","enr":"0xf88fb84044d30c7582fe27aa3b8c55da3f032e7cb56b288e44baf86177cfde6ed4c9149015288e5ba011d1c31348e0f182578ce8e67d5005e9643a93d79062b0b49214570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022733db14205f39cf4a5f52580a937dccc7220e36a80b7c541c95e9f5f1ab651b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hnNaRtp2sxMvcpspO02FAuk57Lp3a42Fs65z76IYS18=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 86735a\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 452b 5e36 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 2 cb8d c3b2 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 4 a12b afb1 be2b b374 | 9 b73b (0) b374 (0) be2b (0) b8f3 (0)\n003 1 9629 | 1 9629 (0)\n004 2 8802 8926 | 2 8926 (0) 8802 (0)\n005 1 821a | 1 821a (0)\n006 1 856e | 1 856e (0)\n============ DEPTH: 7 ==========================================\n007 2 87aa 87ac | 2 87aa (0) 87ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","private_key":"b24570a9ec33187bd0150552ac01cdd88eec842a46287b6ac1b2deb18f33e085","name":"node_86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","services":["bzz","pss"],"enable_msg_events":true,"port":40543},"up":true}},{"node":{"info":{"id":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","name":"node_5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","enode":"enode://6828133036c9b44a750ebe723643ebb654f1e58df2ceeebc03acfb272369884cb2d2d655af0643f45967522375b8ffead57932e55b3b7dcfb52c9f7d82f137b9@127.0.0.1:0","enr":"0xf88fb84028bf1f9f6157f4c3f2d4ef7e1ea62299c768b52e33444503387ea891297151581142a59adab791688ddb3eac52f9b5edfedc501289011d1b817c4cbe2bada5770183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036828133036c9b44a750ebe723643ebb654f1e58df2ceeebc03acfb272369884c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XjZUK7vA1wIxydAHQssw/M8/IG7s8QoPNDMqKYbIb/s=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5e3654\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9629 87ac 8673 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 4 154f 274f 255d 248a | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 6123 7d69 703d | 5 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n003 1 452b | 1 452b (0)\n004 4 52fc 5508 57d9 5602 | 4 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n============ DEPTH: 5 ==========================================\n005 1 581a | 1 581a (0)\n006 0 | 0\n007 1 5f83 | 1 5f83 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","private_key":"89f0ff7aa444ba31932f2d98ccf6dfd9c65ff023efd774671320ecaf9a928885","name":"node_5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","services":["bzz","pss"],"enable_msg_events":true,"port":45057},"up":true}},{"node":{"info":{"id":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","name":"node_87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","enode":"enode://fd65f331dd55b301498b1fd8690370c2150ce0c0cb0eba8fafb9401b873683998d605be7cbf6b1e4653a44decd3ce45eb6666582fb64a1549b8d6f6ea5136ccc@127.0.0.1:0","enr":"0xf88fb84067a97cfc4b4ead1783d6733994223dd4f8e0a4b58e380a6b43e24efb3992b7d765533669304855d20d5c0b1970f6756f7294840f8d7caf98d1292c63a1ae46860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fd65f331dd55b301498b1fd8690370c2150ce0c0cb0eba8fafb9401b87368399","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"h6z2SyLFeXUXGNwJPADIKzn+twI/5TxkhrKIlgrZ4UY=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 87acf6\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 274f 5e36 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 2 cb8d ebf2 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 2 b73b b8f9 | 9 b73b (0) b374 (0) be2b (0) b8f3 (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8802 (0) 8926 (0)\n005 1 821a | 1 821a (0)\n006 1 856e | 1 856e (0)\n============ DEPTH: 7 ==========================================\n007 1 8673 | 1 8673 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 87aa | 1 87aa (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","private_key":"9037526f177112177c3d058d3b13b501be3a83fdd3c1e99b947fc4282b4ea6ec","name":"node_87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","services":["bzz","pss"],"enable_msg_events":true,"port":39033},"up":true}},{"node":{"info":{"id":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","name":"node_ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","enode":"enode://6e0b7fe07cf0a0ef6aff0adebd4fa523361aa0a557c6d363f9e618c229187bba266e046891e4d574f089cb9a13f952a3be1d3484b2917e7a07d8f0504f24e32d@127.0.0.1:0","enr":"0xf88fb840ea01ea00dc23b440bab5e4b3afbb32e20216d4bb47fda6ac71084c371a93e32e5fa1f8064f95b4756488093c95804591ca4cf7045cae8e2d84a75c6f998a6ee10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036e0b7fe07cf0a0ef6aff0adebd4fa523361aa0a557c6d363f9e618c229187bba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6/Jc5CeQUQa3BiXACE3LEXlkpNS5lR9Zd0V9pXQbcWw=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ebf25c\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 7d69 70d0 | 30 6123 (0) 7d69 (0) 7f80 (0) 70d0 (0)\n001 2 8802 87ac | 17 b73b (0) b374 (0) be2b (0) b8f3 (0)\n002 2 cb8d d3c1 | 6 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n003 3 f35a f6e5 fb7e | 5 fb7e (0) f6e5 (0) f0e9 (0) f35a (0)\n004 2 e558 e5e1 | 3 e5e1 (0) e558 (0) e6cf (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e9fd | 1 e9fd (0)\n007 0 | 0\n008 1 eb30 | 1 eb30 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","private_key":"a5091bd57fcc7b35a7f062cffd9498b8ca19657267318836a47b545deb40052a","name":"node_ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","services":["bzz","pss"],"enable_msg_events":true,"port":34261},"up":true}},{"node":{"info":{"id":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","name":"node_d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","enode":"enode://9dbd240d54a8ec88749a933200a7985b59dad0875db66a334b61ddf1a0475851fe15d0a2c521bb9b9c8dd762f98d16fb1606e18aaa7e9be9635a70684f792ce1@127.0.0.1:0","enr":"0xf88fb84081bae7fd011c17a28aec0c170fcf86fce22719550c958b1b76570e8ff83a371f434558ff6b1c828ee71f3809adc8e7e3ff1b17ab1c6a2ea47fa94ffcb9a2f6c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039dbd240d54a8ec88749a933200a7985b59dad0875db66a334b61ddf1a0475851","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"08Ga1MGrya8Dv/wavJcX9Odl1f/3rndiA0OLrJTQGAY=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3c19a\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6123 5602 57d9 255d | 30 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n001 2 b8f9 be2b | 17 b374 (0) b73b (0) be2b (0) b8f3 (0)\n002 8 f35a f0e9 e6cf e558 | 11 fb7e (0) f6e5 (0) f0e9 (0) f35a (0)\n============ DEPTH: 3 ==========================================\n003 4 cb8d c461 c0c2 c3b2 | 4 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n004 1 d904 | 1 d904 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","private_key":"9e4ad8ba562de45511544b4f652f51689e2ad6dcfe4324845b41cab2a1cdb499","name":"node_d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","services":["bzz","pss"],"enable_msg_events":true,"port":42733},"up":true}},{"node":{"info":{"id":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","name":"node_0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","enode":"enode://9a31745dfa11805bdde500a1cfb7d3c0df78681ccd7705384e39e7c6b90278255f7273815bae322e633c7a7e7267f6c310d98ae8b849c34c87f94c40528e54f5@127.0.0.1:0","enr":"0xf88fb840a1f769829999e7af043cecab4b6b39ce1d53fdaf5a02a960165c8eda587bfd0378ad69db24c3f47258aaad5a06acf5dfd842cf65ba503e4cd72580a85176d6290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039a31745dfa11805bdde500a1cfb7d3c0df78681ccd7705384e39e7c6b9027825","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AlftRr1JJxMG/tAScBn9VNtHIoTQAJnxDK3X6DWIpjo=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0257ed\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d904 d3c1 | 34 9629 (0) 8802 (0) 8926 (0) 821a (0)\n001 3 5602 57d9 52fc | 13 52fc (0) 57d9 (0) 5602 (0) 5508 (0)\n002 2 255d 248a | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 3 172b 1455 154f | 4 154f (0) 1455 (0) 172b (0) 177e (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0727 0486 | 2 0486 (0) 0727 (0)\n006 1 00ba | 1 00ba (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","private_key":"93e56d43d2445522babc78fe39d069e01dced5497755d2a0a5690b1b3bc7f5aa","name":"node_0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","services":["bzz","pss"],"enable_msg_events":true,"port":39565},"up":true}},{"node":{"info":{"id":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","name":"node_d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","enode":"enode://a7d3655360abbdb952e9fdf7575d8fb2930309cf2d41bb6a7c8e33f0fb424c1e39c847da1cb0ec0bef9f7569e687f3d71ff62764ed431c2e149f839e060a8d61@127.0.0.1:0","enr":"0xf88fb8404ea64b440fd4d8c1d58f6d37ea7fa76455fb2e1df09a99d151cd5837622939a442f0b9e20b90df55a6c93c013fa1a6e2b6df5ed709823b48d4485e34a03687f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a7d3655360abbdb952e9fdf7575d8fb2930309cf2d41bb6a7c8e33f0fb424c1e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2QT22HkMwjUGP1RmFSHDoZfj6c3Z27zWdl7GzaXY97Q=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d904f6\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 581a 6123 703d 255d | 30 581a (0) 5e36 (0) 5f83 (0) 52fc (0)\n001 2 87aa 821a | 17 8802 (0) 8926 (0) 821a (0) 856e (0)\n002 8 f35a f0e9 fb7e e9fd | 11 fb7e (0) f6e5 (0) f0e9 (0) f35a (0)\n============ DEPTH: 3 ==========================================\n003 4 cb8d c461 c3b2 c0c2 | 4 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n004 1 d3c1 | 1 d3c1 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","private_key":"b53f894c8449d42e7dfbb557649b7fd8816b55d7fd57c3ed65a65c5fdc643478","name":"node_d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","services":["bzz","pss"],"enable_msg_events":true,"port":39481},"up":true}},{"node":{"info":{"id":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","name":"node_703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","enode":"enode://123c89683b99e7d2cb71f5e7d6d6fad3200c8c9129dd11844158320310a15d658bdf8af970f938bbe2e97f72f08405e8c323d49f1c84a7b8cbc8c94bdb1ac762@127.0.0.1:0","enr":"0xf88fb8404488d9cd1ca1b9bdb277610eac83b22a38260188c4604d95f5d9b673feb11b6e262970fefd02bb8685d3be492dd5950f2d3db07395f949562dbcc9c154cc77bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102123c89683b99e7d2cb71f5e7d6d6fad3200c8c9129dd11844158320310a15d65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cD3HasckRXyAWrzB7S4/MhghQJ+0zwGF4vB+vEwYFE8=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 703dc7\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 afb1 e5e1 f35a d904 | 34 8802 (0) 8926 (0) 856e (0) 8673 (0)\n001 4 0acb 1455 274f 3b4f | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 581a 5f83 5e36 | 8 581a (0) 5e36 (0) 5f83 (0) 52fc (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 7d69 7f80 | 2 7f80 (0) 7d69 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 70d0 | 1 70d0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","private_key":"e16c1c8c92402bfd9f8fe2a57e37c01f1898f2f128430398ac33ae7482108ebc","name":"node_703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","services":["bzz","pss"],"enable_msg_events":true,"port":36893},"up":true}},{"node":{"info":{"id":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","name":"node_afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","enode":"enode://50e65aecad41df245ddc2f29869d81db24b988a216918b80b305904ed62647ce8c03cc7fdcee80bbe864ca008714bce3d055bbfb50bec1214ae67ba54b9126bb@127.0.0.1:0","enr":"0xf88fb8401f728d3897ecb9512cf5eb7a662998136041c670409700a9f59b5e9b8a04a81e395e1d3f21b92032fb70f5ab6ffc3b648f6b884268426117ba50407330ee9eef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10350e65aecad41df245ddc2f29869d81db24b988a216918b80b305904ed62647ce","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"r7HQuNGx9qNBOEwfCBj2souF/v5qRaiSVS3k3lN59qU=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: afb1d0\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 172b 00ba 703d | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 3 e6cf fb7e f6e5 | 17 fb7e (0) f6e5 (0) f35a (0) f211 (0)\n002 3 8926 87aa 8673 | 8 8926 (0) 8802 (0) 856e (0) 8673 (0)\n003 5 b73b b374 be2b b8f3 | 5 b374 (0) b73b (0) be2b (0) b8f3 (0)\n004 1 a12b | 1 a12b (0)\n============ DEPTH: 5 ==========================================\n005 1 aabc | 1 aabc (0)\n006 0 | 0\n007 1 ae60 | 1 ae60 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","private_key":"4354e176e57a83691528c333e221af5d016371701e1d7f08607a0a04f5fca409","name":"node_afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","services":["bzz","pss"],"enable_msg_events":true,"port":33425},"up":true}},{"node":{"info":{"id":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","name":"node_00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","enode":"enode://d2088cb0561220a69e8efa4945b89411db2f73bd1432a997f9cf0f4316eda2a7f5962c0b0d5b314fea4cb73dc4df7fedcccc2027eb9d4cedf7fbe996d7f5e0bf@127.0.0.1:0","enr":"0xf88fb84063cbdaf9b29653c80c1532a4963d23258dc89555d21522053f86d7a73b54520d64eee9fa218232119ae212b2c9b0d27e5b8cacf6f3c727bf3dc4cbbf690dd51e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d2088cb0561220a69e8efa4945b89411db2f73bd1432a997f9cf0f4316eda2a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ALpsYbLWSA9T9Iw97zrIVYfZt6kmWNIcI1/Q/dwkaFA=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 00ba6c\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c0c2 8926 9629 b8f3 | 34 fb7e (0) f6e5 (0) f35a (0) f211 (0)\n001 4 70d0 452b 57d9 52fc | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 2 248a 3b4f | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 3 1455 154f 172b | 4 154f (0) 1455 (0) 172b (0) 177e (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0727 0486 | 2 0486 (0) 0727 (0)\n006 1 0257 | 1 0257 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","private_key":"5a24ca759ff05fd20635c180866850474c9548f77adb55e3dd1b4745a871f0b7","name":"node_00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","services":["bzz","pss"],"enable_msg_events":true,"port":43657},"up":true}},{"node":{"info":{"id":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","name":"node_9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","enode":"enode://28248a4e3b947a840d138ec02d99874ec310f8a569c25dc8a34c5e334dc69bbd196f0769f32afad244552e8f321e4ab1b498e10ba875cb6e008146607b4b1748@127.0.0.1:0","enr":"0xf88fb840410401b0463d1535e6372c265c06ccac3b6116261f346d31b2c4da7487baa40b0d04f506d7a30412b7ca365e1283a8c1f6298c2a0fd14448a8b7b9d3d0e6f9f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10228248a4e3b947a840d138ec02d99874ec310f8a569c25dc8a34c5e334dc69bbd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"likyDWSP2jg07drHJjzGyIZR3GB0IGzuABRJGNInYok=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 962932\npopulation: 24 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5e36 581a 452b 38f0 | 30 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n001 5 f35a f0e9 e9fd c461 | 17 fb7e (0) f6e5 (0) f35a (0) f211 (0)\n002 6 a12b ae60 aabc b374 | 9 b73b (0) b374 (0) be2b (0) b8f3 (0)\n============ DEPTH: 3 ==========================================\n003 7 821a 856e 8673 87aa | 7 8926 (0) 8802 (0) 856e (0) 8673 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","private_key":"37f4999bea53d1c97ec6a575c20dd5a83d19dbf990fe54e165401484f46a0ad5","name":"node_9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","services":["bzz","pss"],"enable_msg_events":true,"port":41351},"up":true}},{"node":{"info":{"id":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","name":"node_c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","enode":"enode://6d97076d32b9b9f4b5283863a9e98ae3565c5b76c4d79066a19dcea55b59368e7608ba4756a6ad7c2abcfa2cd8a35687b72abc688594d2e75acf7c06224f070f@127.0.0.1:0","enr":"0xf88fb84051fb637bffdf225590478fd9c8d1191799580989e08e24be868d06fc5bcc1d331b83c265df3b5914dd08cb298f5c664aed93b478f82c2b79044d18b9e6e8e05e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036d97076d32b9b9f4b5283863a9e98ae3565c5b76c4d79066a19dcea55b59368e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"w7LS8McnU+2J/ExYDIH1DGbLAsH5AFRlDhkaAQXEDR0=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c3b2d2\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3c40 5f83 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 3 b374 8673 9629 | 17 a12b (0) afb1 (0) ae60 (0) aabc (0)\n002 3 f6e5 fb7e e6cf | 11 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n003 2 d904 d3c1 | 2 d3c1 (0) d904 (0)\n004 1 cb8d | 1 cb8d (0)\n============ DEPTH: 5 ==========================================\n005 1 c461 | 1 c461 (0)\n006 1 c0c2 | 1 c0c2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","private_key":"3e87a7f0724932c97ccea342e08f9cbab0a16398baa4d83cf262cab27e823a00","name":"node_c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","services":["bzz","pss"],"enable_msg_events":true,"port":33597},"up":true}},{"node":{"info":{"id":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","name":"node_e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","enode":"enode://66956dc6f44f5a14fbd8cacccb4a0392af57212942e8ab9a389056d9577bf347a38cfdd762902a5edcb4eecf9651e855e67968089887e622490e8b69b548f496@127.0.0.1:0","enr":"0xf88fb840736618f919fc2c358b6f142a11f97cfe9676c53077ffac8dc2e6f386275e20054d088ed925aeddf27038b97725b58eb517ada94564ace17c71b2e679b3a0712e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10266956dc6f44f5a14fbd8cacccb4a0392af57212942e8ab9a389056d9577bf347","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5s8zfQ5pXoYeo2hk4qzh9AKdWzJG970Vzk3MIgv+Pkg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e6cf33\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 248a 3c40 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 4 ae60 afb1 a12b 821a | 17 a12b (0) afb1 (0) ae60 (0) aabc (0)\n002 3 d904 d3c1 c3b2 | 6 d3c1 (0) d904 (0) cb8d (0) c461 (0)\n003 4 f6e5 f0e9 f211 fb7e | 5 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n004 2 eb30 e9fd | 3 e9fd (0) eb30 (0) ebf2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 e5e1 e558 | 2 e5e1 (0) e558 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","private_key":"17299832d5703762960e077579ea9a6ffc090a4e52d4b7da5ac8f0a93fe3dc58","name":"node_e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","services":["bzz","pss"],"enable_msg_events":true,"port":42449},"up":true}},{"node":{"info":{"id":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","name":"node_821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","enode":"enode://9076c5a898a4ed3432a2f812f4c221429a92437f6e27430d6606d7e0d8d01467f860d0949c1bf61d8630a2f1cdcac9b59dff894910bb4d5f11793e03ca4812bc@127.0.0.1:0","enr":"0xf88fb840c4b0861f6a4c06646188be8b72ed472c5dce5473d4568b7bbfc15409a2b575fd1ffe9c6597915b5a0d3225f043bc7c42438fc6786f38fa60c9372592fbf0b3720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029076c5a898a4ed3432a2f812f4c221429a92437f6e27430d6606d7e0d8d01467","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ghryXmNmI3zKJWgexjPrqI20ik/4i1kgzckuFGFhQOQ=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 821af2\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0acb 255d 274f 38f0 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 7 c461 d904 f35a f0e9 | 17 d3c1 (0) d904 (0) cb8d (0) c461 (0)\n002 4 a12b aabc b8f3 b8f9 | 9 a12b (0) afb1 (0) ae60 (0) aabc (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8802 (0) 8926 (0)\n============ DEPTH: 5 ==========================================\n005 4 8673 87aa 87ac 856e | 4 856e (0) 8673 (0) 87aa (0) 87ac (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","private_key":"7a3f8c7619489d91c82cd5712ea79f4a09bda58899b9c47305cecaaf474446e9","name":"node_821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","services":["bzz","pss"],"enable_msg_events":true,"port":37855},"up":true}},{"node":{"info":{"id":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","name":"node_b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","enode":"enode://4d06d30c93bb00f7ea04113fb7db1f44cf2d64fa6fa84136844915317a078a5f515d67f2c9531726774eff1e1c55e794444413207a7a33f8efe69c3b9a1ce809@127.0.0.1:0","enr":"0xf88fb840da80dce04c535f4a03e572241364ebfcc260ac172c2f4f8613c30690c319e6916a57ccbc2ba5996f0eb97daa72b5f179ddc8c8402cbf34e3d4e25b6d5de65d560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034d06d30c93bb00f7ea04113fb7db1f44cf2d64fa6fa84136844915317a078a5f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uPmUaxfOpdu6S6HDfNTQCjVxfGn7DjkfJK+SlPkDDC4=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8f994\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 274f 5508 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 2 d3c1 f6e5 | 17 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n002 3 856e 87ac 821a | 8 9629 (0) 8802 (0) 8926 (0) 856e (0)\n003 3 ae60 afb1 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n004 2 b374 b73b | 2 b73b (0) b374 (0)\n============ DEPTH: 5 ==========================================\n005 1 be2b | 1 be2b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 b8f3 | 1 b8f3 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","private_key":"ba7822a917d871b0db8d2f35c273e03d2611d6b1ec22afa5f3904d5912715fe6","name":"node_b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","services":["bzz","pss"],"enable_msg_events":true,"port":46635},"up":true}},{"node":{"info":{"id":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","name":"node_550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","enode":"enode://674d26ce4cfc8f488a5582293dcb0b48dbafe55633179a515be743fd8df0115312862eb9890c52caa8a448b0643237fa1cb52630bbb037f10a4b51c9bb03547c@127.0.0.1:0","enr":"0xf88fb840f50fd3df45a62d984c9335d268586911f8ca0e81aa4bcb0d91ba62cd4c9d788739972464e7736c25bafc230322b8cd066b8336706c3829ba54844c18cc2d1e510183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102674d26ce4cfc8f488a5582293dcb0b48dbafe55633179a515be743fd8df01153","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VQhXusIHh8p/ZJN67boLo9K1hQUtboJP3oQDg4osKtw=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 550857\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f6e5 fb7e b8f9 | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 2 274f 38f0 | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 2 7f80 6123 | 5 6123 (0) 7f80 (0) 7d69 (0) 70d0 (0)\n003 1 452b | 1 452b (0)\n004 3 5f83 5e36 581a | 3 581a (0) 5e36 (0) 5f83 (0)\n005 1 52fc | 1 52fc (0)\n============ DEPTH: 6 ==========================================\n006 2 57d9 5602 | 2 57d9 (0) 5602 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","private_key":"71212a2c0cc74c7f5acae0d49389517fb9f8125452e5ff53a87d9f94d1cdb656","name":"node_550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","services":["bzz","pss"],"enable_msg_events":true,"port":38047},"up":true}},{"node":{"info":{"id":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","name":"node_56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","enode":"enode://6e7531fa1aad96956cb94991feb1de42184d663cf91edeec3ec9c44a40b74669a30ca1b149de068ad02287f4749aaa00baba98cfaf078c9616119971af4d8e41@127.0.0.1:0","enr":"0xf88fb840e9d8fe4011fb432017522b9895b5df21af7f12f9f032d6fe91afd6674259563329ec357a908efcdf03bf0ce90552bec005f8d8e48d4ff8501f5d4a78f5e140a90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036e7531fa1aad96956cb94991feb1de42184d663cf91edeec3ec9c44a40b74669","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VgKekTxY+aEKUcJfvzIq7lToREdssXI8MS8Pi7nCTjk=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 56029e\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d3c1 b73b | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 3 3c40 0257 177e | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 6123 7f80 7d69 | 5 6123 (0) 7f80 (0) 7d69 (0) 70d0 (0)\n003 1 452b | 1 452b (0)\n004 3 581a 5f83 5e36 | 3 581a (0) 5e36 (0) 5f83 (0)\n005 1 52fc | 1 52fc (0)\n============ DEPTH: 6 ==========================================\n006 1 5508 | 1 5508 (0)\n007 1 57d9 | 1 57d9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","private_key":"4e9222727f6b16c6bf0ed7a54aa1b7469e124eba3236c02cdbcc687cd60b72bc","name":"node_56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","services":["bzz","pss"],"enable_msg_events":true,"port":38635},"up":true}},{"node":{"info":{"id":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","name":"node_b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","enode":"enode://ab3e384377a188409c644d5b90e2c6ef1f2684a6f706d706a4648f7de14c6636e1879b40b73c0ae2f50e0a5b310fae9d87dec78077f765ea86d1d1692e7f30e9@127.0.0.1:0","enr":"0xf88fb8402367c86e536923173d2217bd08333ff411134bf6cfd0e621b7979b3e8e5858f46c7490fafa705e3e2039990a49492e9061617d5dc27a275fbb87b2b5af9a1b020183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ab3e384377a188409c644d5b90e2c6ef1f2684a6f706d706a4648f7de14c6636","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tzuapaYmTJoBipiKgTuRJ9m/lwc2R4zw3D7dHCAj9vI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b73b9a\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3abf 177e 5602 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 4 eb30 fb7e f211 f6e5 | 17 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n002 3 87ac 8802 8926 | 8 8802 (0) 8926 (0) 821a (0) 856e (0)\n003 3 aabc afb1 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n============ DEPTH: 4 ==========================================\n004 3 be2b b8f3 b8f9 | 3 b8f9 (0) b8f3 (0) be2b (0)\n005 1 b374 | 1 b374 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","private_key":"7b8ef93d2a057f4d4cd38111d6f670c9ea7480d10fb335de23e95b1e66c6c445","name":"node_b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","services":["bzz","pss"],"enable_msg_events":true,"port":33079},"up":true}}],"conns":[{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","other":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_8.json b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_8.json index 307afe5a..53fe4f96 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_8.json +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/testdata/snapshot_8.json @@ -1 +1 @@ -{"nodes":[{"node":{"config":{"id":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","private_key":"e567b7d9c554e5102cdc99b6523bace02dbb8951415c8816d82ba2d2e97fa23b","name":"node01","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","private_key":"c7526db70acd02f36d3b201ef3e1d85e38c52bee6931453213dbc5edec4d0976","name":"node02","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","private_key":"61b5728f59bc43080c3b8eb0458fb30d7723e2747355b6dc980f35f3ed431199","name":"node03","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","private_key":"075b07c29ceac4ffa2a114afd67b21dfc438126bc169bf7c154be6d81d86ed38","name":"node04","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"05dacbe069e452448fb7bee09b8270a0218089a6d441c461fc45d338d2b59492","private_key":"4882fdd34676c2158f7bfc761bf824fcf693736a8df294cc7e79ef1848c7bae6","name":"node05","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"3451df808a9e122ebbc6306f159ae90ccd34e5ef3e0457c501f54ac08457238a","private_key":"0470652ac57af40a43bc67b1b49699219fc35a805da167244f505d27858334c7","name":"node06","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","private_key":"2cbf6256e92736e1b54279b79addbb830a607a71488cdd3462a44fcaa68c018e","name":"node07","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}},{"node":{"config":{"id":"dfd47d54492eac09708641a7115b1fda328e2dd8f75ced9026212d3699722f94","private_key":"e659774a5ff4f76b021bf4884ad359eadeb8ff33e843a3f76fcf4a38b0d82b35","name":"node08","services":["pss","bzz"],"enable_msg_events":false,"port":0},"up":true}}],"conns":[{"one":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","other":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","up":true},{"one":"05dacbe069e452448fb7bee09b8270a0218089a6d441c461fc45d338d2b59492","other":"3451df808a9e122ebbc6306f159ae90ccd34e5ef3e0457c501f54ac08457238a","up":true},{"one":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","other":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","up":true},{"one":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","other":"dfd47d54492eac09708641a7115b1fda328e2dd8f75ced9026212d3699722f94","up":true},{"one":"dfd47d54492eac09708641a7115b1fda328e2dd8f75ced9026212d3699722f94","other":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","up":true},{"one":"3451df808a9e122ebbc6306f159ae90ccd34e5ef3e0457c501f54ac08457238a","other":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","up":true},{"one":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","other":"05dacbe069e452448fb7bee09b8270a0218089a6d441c461fc45d338d2b59492","up":true},{"one":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","other":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","up":true},{"one":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","other":"3451df808a9e122ebbc6306f159ae90ccd34e5ef3e0457c501f54ac08457238a","up":true},{"one":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","other":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","up":true},{"one":"05dacbe069e452448fb7bee09b8270a0218089a6d441c461fc45d338d2b59492","other":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","up":true},{"one":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","other":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","up":true},{"one":"3451df808a9e122ebbc6306f159ae90ccd34e5ef3e0457c501f54ac08457238a","other":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","up":true},{"one":"dfd47d54492eac09708641a7115b1fda328e2dd8f75ced9026212d3699722f94","other":"d7768334f79d626adb433f44b703a818555e3331056036ef3f8d1282586bf044","up":true},{"one":"8a1eb78ff13df318e7f8116dffee98cd7d9905650fa53f16766b754a63f387ac","other":"dfd47d54492eac09708641a7115b1fda328e2dd8f75ced9026212d3699722f94","up":true},{"one":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","other":"05dacbe069e452448fb7bee09b8270a0218089a6d441c461fc45d338d2b59492","up":true},{"one":"73d6ad4a75069dced660fa4cb98143ee5573df7cb15d9a295acf1655e9683384","other":"05dacbe069e452448fb7bee09b8270a0218089a6d441c461fc45d338d2b59492","up":true},{"one":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","other":"159c0bdb3c1638e66de52ec0c476282eb5a7b1fcf763dc33b938c5381ef5a149","up":true},{"one":"6e8da86abb894ab35044c8c455147225df96cab498da067a118f1fb9a417f9e3","other":"3451df808a9e122ebbc6306f159ae90ccd34e5ef3e0457c501f54ac08457238a","up":true}]} \ No newline at end of file +{"nodes":[{"node":{"info":{"id":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","name":"node_b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","enode":"enode://1fdd80e21167da20c5b50282fff16b9d9ba26b1ba66f4b485f2a280c97d135d2650a0aec63b0c4f05ebc1fd1e26dd701c78c3d26660ae55b1ec443d0858d5fae@127.0.0.1:0","enr":"0xf88fb84089ca9b4322a861dc171283da9cf5f01c2f522abc20fea004cdc9e021133e69a63c392de428728d12dae699dc4db983978a7d49e9f842a2a97e608411c26b0f380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021fdd80e21167da20c5b50282fff16b9d9ba26b1ba66f4b485f2a280c97d135d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sMKCtIQZcFFyJ1Ur32MDhVUaj9cYhM5kyoZbqVGSldI=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b0c282\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 e5c3 d20e | 2 e5c3 (0) d20e (0)\n============ DEPTH: 2 ==========================================\n002 3 9d65 8d78 857f | 3 9d65 (0) 8d78 (0) 857f (0)\n003 1 af5a | 1 af5a (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","private_key":"4abb6d72d23ab230f5903ce4eade3e17621c344793b5b4478adc885ea16ccd5e","name":"node_b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","services":["bzz","pss"],"enable_msg_events":true,"port":38939},"up":true}},{"node":{"info":{"id":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","name":"node_857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","enode":"enode://1253be1d17f585c64b93f4521a8c9a6fc2219941cbd4c0a0f4f9c505ff25faf880745e2fbb7d85bdd43510ef61222a11730770d75060eeb8d2449198ca9d99d9@127.0.0.1:0","enr":"0xf88fb8401ff2d62982fa003d6d8138eddc966e3bb01f0418be800a888246409230f7331b2ae72c81e74b250219b1b53c54eb658716fae5653e2154f8e489d8fd9c556ac90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031253be1d17f585c64b93f4521a8c9a6fc2219941cbd4c0a0f4f9c505ff25faf8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hX/d+AgXh7TdgwRZd44e4oFrIrtq+61imwRUfOgw1MQ=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 857fdd\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 d20e e5c3 | 2 e5c3 (0) d20e (0)\n002 2 af5a b0c2 | 2 af5a (0) b0c2 (0)\n============ DEPTH: 3 ==========================================\n003 1 9d65 | 1 9d65 (0)\n004 1 8d78 | 1 8d78 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","private_key":"9ec93c440894afdab5919df0886cf410fed4c31a7a2a859ca39f7f702c0c68a7","name":"node_857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","services":["bzz","pss"],"enable_msg_events":true,"port":37411},"up":true}},{"node":{"info":{"id":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","name":"node_9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","enode":"enode://f0854e632647b0c6194987efc857de2018a55c3e41fa83d66c1bc7a6b41b6410667343be112125a56d00813a2217a9c7f9de6294f90d1062868195b0209febee@127.0.0.1:0","enr":"0xf88fb84092a5952a80b7c2970b3026cba7242670edc3bfeb88145f517586537cf3c723cf0f843d8e4fd79b03865506c72c4e359828e844d734a156e9433ea8005a84e86e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0854e632647b0c6194987efc857de2018a55c3e41fa83d66c1bc7a6b41b6410","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nWVoU2sk38S+r/qiRApWkBntiFVpU27zrzZtT9fkFVw=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9d6568\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 d20e e5c3 | 2 d20e (0) e5c3 (0)\n002 2 af5a b0c2 | 2 b0c2 (0) af5a (0)\n============ DEPTH: 3 ==========================================\n003 2 8d78 857f | 2 8d78 (0) 857f (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","private_key":"78c3cbec4b5203c57cb07bec48b1f6b483333254270f8c78369f663a67332275","name":"node_9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","services":["bzz","pss"],"enable_msg_events":true,"port":35167},"up":true}},{"node":{"info":{"id":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","name":"node_e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","enode":"enode://b942a7abe4d7bb812c4dd793e10b90bd0a052d02c8fd30a51d4fc7f2c0ba00a69f28d80b694d467a8e0dd3a91d8c002d7cc4b559c0814a3465c88c848ee67c78@127.0.0.1:0","enr":"0xf88fb840e652351f98a74786fc3ef30d88e198485e1d1d2dbcee24527737d3e7ed9f7e1c327b5e0e5222fad7b1b8849a7cf930a11d784b8b5df0a4e83f96bed207be80fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b942a7abe4d7bb812c4dd793e10b90bd0a052d02c8fd30a51d4fc7f2c0ba00a6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5cP6M2xt64ESi9Y8+/Fstk1Kg8bmp6ZdGvUe4B5LiuE=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5c3fa\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n============ DEPTH: 1 ==========================================\n001 5 af5a b0c2 8d78 857f | 5 b0c2 (0) af5a (0) 8d78 (0) 857f (0)\n002 1 d20e | 1 d20e (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","private_key":"e47c725966b157b8d5f82a845e7972a8f46f4afdd7e6936924b091f6903f206a","name":"node_e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","services":["bzz","pss"],"enable_msg_events":true,"port":40723},"up":true}},{"node":{"info":{"id":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","name":"node_4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","enode":"enode://07926b76c1525c50780e9665d8eece3669309dbe11901ecce0fdd4b58cb674d6492eb005708df46901b05fb100b3e0e7d5fa68063b264ece3b89dab0387f75eb@127.0.0.1:0","enr":"0xf88fb8409b7e55bf546e10ed700d31d91c0da7485440884d8765e8690b5a6d36622a9b1d3e701b927e7ec276477e7c249a7c6ed5a3d723e5c2b5343eda892e3b510e7f760183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10307926b76c1525c50780e9665d8eece3669309dbe11901ecce0fdd4b58cb674d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TygdoL/x+v48VU0NTqGumi06FP+7hC3CUaRbHwAWMcU=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4f281d\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 7 9d65 8d78 857f b0c2 | 7 b0c2 (0) af5a (0) 8d78 (0) 857f (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","private_key":"314da8f87c03fe3bea0fc585c33443cd627cf93a51f609e88d0251a248cc8a2b","name":"node_4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","services":["bzz","pss"],"enable_msg_events":true,"port":40771},"up":true}},{"node":{"info":{"id":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","name":"node_af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","enode":"enode://86e63eb120fa323784aab76c4586fc5f96764473b5e5181e5101d05f99b6a2ae42b40d2ada4ff77338a6189c68745b96d1a7535fa1a81211aaf719b7918344f0@127.0.0.1:0","enr":"0xf88fb840ef88957469c48aed8ea2da3a5d910b199f8506a13703fbfc55f28d26199820175dd29361863b9cd50ce0d032412687302fb1b12ad7ca026dab30c5c600e541ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10286e63eb120fa323784aab76c4586fc5f96764473b5e5181e5101d05f99b6a2ae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"r1pDikcZaqKWKUeWZNRU54EEzDyPAENfoU2jB1XrGbg=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: af5a43\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 e5c3 d20e | 2 d20e (0) e5c3 (0)\n============ DEPTH: 2 ==========================================\n002 3 9d65 857f 8d78 | 3 9d65 (0) 857f (0) 8d78 (0)\n003 1 b0c2 | 1 b0c2 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","private_key":"ca50145cbbcbb65bb54caae3f33b2253f05203a2825ad5e77aebe7513ac1f2f6","name":"node_af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","services":["bzz","pss"],"enable_msg_events":true,"port":33411},"up":true}},{"node":{"info":{"id":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","name":"node_8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","enode":"enode://c0fbc89e69cc5371b97f530380e78cac1cd7e3ad87a6bc1597e714ba892d53da030438cfdc1d7f3f1a50f1328733feb1afaabe1bdfdb731d7c134f42637bc570@127.0.0.1:0","enr":"0xf88fb8402e0b00cc0ddeb598d3dd71f1538b77e52afb8b6ee456a56a15d73b850f88480d686962bb60c059abf4080bb090dd6960e00ccc3992a79682f4d0b32d7f1182f40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c0fbc89e69cc5371b97f530380e78cac1cd7e3ad87a6bc1597e714ba892d53da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jXiz9/uGRNeQrUQ058JzVYR1r6O9KQdIBXyKuozLGMI=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8d78b3\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 e5c3 d20e | 2 e5c3 (0) d20e (0)\n002 2 b0c2 af5a | 2 b0c2 (0) af5a (0)\n============ DEPTH: 3 ==========================================\n003 1 9d65 | 1 9d65 (0)\n004 1 857f | 1 857f (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","private_key":"3610f2b1d9031bcf4dd8e44f17d7262c53c302d49aae7068bf58bf63593b168c","name":"node_8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","services":["bzz","pss"],"enable_msg_events":true,"port":46461},"up":true}},{"node":{"info":{"id":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","name":"node_d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","enode":"enode://59a306fa22d2124205f53d5eb905896f7fe818569fc14221c50a3b0ce032b67c275381f7b3ccbc88fb679a42d19dc9b24f699f2f44cc34a9e92c4087f3df3224@127.0.0.1:0","enr":"0xf88fb84010c45aa3fc72b92b0a6c1999ec487c845993f1fe4210e415c1995ec007cf990b62cbe15723436c2b6324564678c3dcf711ec0dd6fea5cd02f59758e5ec8caf660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10259a306fa22d2124205f53d5eb905896f7fe818569fc14221c50a3b0ce032b67c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0g6deWEImIWbj251Q96WEZtzj1WNhzej53b0IfguhtA=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d20e9d\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n============ DEPTH: 1 ==========================================\n001 5 af5a b0c2 9d65 857f | 5 af5a (0) b0c2 (0) 9d65 (0) 857f (0)\n002 1 e5c3 | 1 e5c3 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","private_key":"4f08d74f4aae2cc502689afad5bb760072c6f1931f7872c3d4ca210972736b74","name":"node_d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","services":["bzz","pss"],"enable_msg_events":true,"port":36035},"up":true}}],"conns":[{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true},{"one":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","other":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","up":true},{"one":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","other":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","up":true},{"one":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","other":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","up":true},{"one":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","up":true},{"one":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","other":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true}]} \ No newline at end of file diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/pss/types.go b/vendor/github.com/ethereum/go-ethereum/swarm/pss/types.go index 56c2c51d..2ce1f5cf 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/pss/types.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/pss/types.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/swarm/storage" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) const ( @@ -159,9 +159,39 @@ func (msg *PssMsg) String() string { } // Signature for a message handler function for a PssMsg -// // Implementations of this type are passed to Pss.Register together with a topic, -type Handler func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error +type HandlerFunc func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error + +type handlerCaps struct { + raw bool + prox bool +} + +// Handler defines code to be executed upon reception of content. +type handler struct { + f HandlerFunc + caps *handlerCaps +} + +// NewHandler returns a new message handler +func NewHandler(f HandlerFunc) *handler { + return &handler{ + f: f, + caps: &handlerCaps{}, + } +} + +// WithRaw is a chainable method that allows raw messages to be handled. +func (h *handler) WithRaw() *handler { + h.caps.raw = true + return h +} + +// WithProxBin is a chainable method that allows sending messages with full addresses to neighbourhoods using the kademlia depth as reference +func (h *handler) WithProxBin() *handler { + h.caps.prox = true + return h +} // the stateStore handles saving and loading PSS peers and their corresponding keys // it is currently unimplemented diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/db.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/db.go new file mode 100644 index 00000000..8c11bf48 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/db.go @@ -0,0 +1,320 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package shed provides a simple abstraction components to compose +// more complex operations on storage data organized in fields and indexes. +// +// Only type which holds logical information about swarm storage chunks data +// and metadata is Item. This part is not generalized mostly for +// performance reasons. +package shed + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/syndtr/goleveldb/leveldb/opt" +) + +const ( + openFileLimit = 128 // The limit for LevelDB OpenFilesCacheCapacity. + writePauseWarningThrottler = 1 * time.Minute +) + +// DB provides abstractions over LevelDB in order to +// implement complex structures using fields and ordered indexes. +// It provides a schema functionality to store fields and indexes +// information about naming and types. +type DB struct { + ldb *leveldb.DB + + compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction + compReadMeter metrics.Meter // Meter for measuring the data read during compaction + compWriteMeter metrics.Meter // Meter for measuring the data written during compaction + writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction + writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction + diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read + diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written + + quit chan struct{} // Quit channel to stop the metrics collection before closing the database +} + +// NewDB constructs a new DB and validates the schema +// if it exists in database on the given path. +// metricsPrefix is used for metrics collection for the given DB. +func NewDB(path string, metricsPrefix string) (db *DB, err error) { + ldb, err := leveldb.OpenFile(path, &opt.Options{ + OpenFilesCacheCapacity: openFileLimit, + }) + if err != nil { + return nil, err + } + db = &DB{ + ldb: ldb, + } + + if _, err = db.getSchema(); err != nil { + if err == leveldb.ErrNotFound { + // save schema with initialized default fields + if err = db.putSchema(schema{ + Fields: make(map[string]fieldSpec), + Indexes: make(map[byte]indexSpec), + }); err != nil { + return nil, err + } + } else { + return nil, err + } + } + + // Configure meters for DB + db.configure(metricsPrefix) + + // Create a quit channel for the periodic metrics collector and run it + db.quit = make(chan struct{}) + + go db.meter(10 * time.Second) + + return db, nil +} + +// Put wraps LevelDB Put method to increment metrics counter. +func (db *DB) Put(key []byte, value []byte) (err error) { + err = db.ldb.Put(key, value, nil) + if err != nil { + metrics.GetOrRegisterCounter("DB.putFail", nil).Inc(1) + return err + } + metrics.GetOrRegisterCounter("DB.put", nil).Inc(1) + return nil +} + +// Get wraps LevelDB Get method to increment metrics counter. +func (db *DB) Get(key []byte) (value []byte, err error) { + value, err = db.ldb.Get(key, nil) + if err != nil { + if err == leveldb.ErrNotFound { + metrics.GetOrRegisterCounter("DB.getNotFound", nil).Inc(1) + } else { + metrics.GetOrRegisterCounter("DB.getFail", nil).Inc(1) + } + return nil, err + } + metrics.GetOrRegisterCounter("DB.get", nil).Inc(1) + return value, nil +} + +// Has wraps LevelDB Has method to increment metrics counter. +func (db *DB) Has(key []byte) (yes bool, err error) { + yes, err = db.ldb.Has(key, nil) + if err != nil { + metrics.GetOrRegisterCounter("DB.hasFail", nil).Inc(1) + return false, err + } + metrics.GetOrRegisterCounter("DB.has", nil).Inc(1) + return yes, nil +} + +// Delete wraps LevelDB Delete method to increment metrics counter. +func (db *DB) Delete(key []byte) (err error) { + err = db.ldb.Delete(key, nil) + if err != nil { + metrics.GetOrRegisterCounter("DB.deleteFail", nil).Inc(1) + return err + } + metrics.GetOrRegisterCounter("DB.delete", nil).Inc(1) + return nil +} + +// NewIterator wraps LevelDB NewIterator method to increment metrics counter. +func (db *DB) NewIterator() iterator.Iterator { + metrics.GetOrRegisterCounter("DB.newiterator", nil).Inc(1) + + return db.ldb.NewIterator(nil, nil) +} + +// WriteBatch wraps LevelDB Write method to increment metrics counter. +func (db *DB) WriteBatch(batch *leveldb.Batch) (err error) { + err = db.ldb.Write(batch, nil) + if err != nil { + metrics.GetOrRegisterCounter("DB.writebatchFail", nil).Inc(1) + return err + } + metrics.GetOrRegisterCounter("DB.writebatch", nil).Inc(1) + return nil +} + +// Close closes LevelDB database. +func (db *DB) Close() (err error) { + close(db.quit) + return db.ldb.Close() +} + +// Configure configures the database metrics collectors +func (db *DB) configure(prefix string) { + // Initialize all the metrics collector at the requested prefix + db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil) + db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil) + db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil) + db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil) + db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil) + db.writeDelayMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil) + db.writeDelayNMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", nil) +} + +func (db *DB) meter(refresh time.Duration) { + // Create the counters to store current and previous compaction values + compactions := make([][]float64, 2) + for i := 0; i < 2; i++ { + compactions[i] = make([]float64, 3) + } + // Create storage for iostats. + var iostats [2]float64 + + // Create storage and warning log tracer for write delay. + var ( + delaystats [2]int64 + lastWritePaused time.Time + ) + + // Iterate ad infinitum and collect the stats + for i := 1; true; i++ { + // Retrieve the database stats + stats, err := db.ldb.GetProperty("leveldb.stats") + if err != nil { + log.Error("Failed to read database stats", "err", err) + continue + } + // Find the compaction table, skip the header + lines := strings.Split(stats, "\n") + for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" { + lines = lines[1:] + } + if len(lines) <= 3 { + log.Error("Compaction table not found") + continue + } + lines = lines[3:] + + // Iterate over all the table rows, and accumulate the entries + for j := 0; j < len(compactions[i%2]); j++ { + compactions[i%2][j] = 0 + } + for _, line := range lines { + parts := strings.Split(line, "|") + if len(parts) != 6 { + break + } + for idx, counter := range parts[3:] { + value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64) + if err != nil { + log.Error("Compaction entry parsing failed", "err", err) + continue + } + compactions[i%2][idx] += value + } + } + // Update all the requested meters + if db.compTimeMeter != nil { + db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000)) + } + if db.compReadMeter != nil { + db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024)) + } + if db.compWriteMeter != nil { + db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024)) + } + + // Retrieve the write delay statistic + writedelay, err := db.ldb.GetProperty("leveldb.writedelay") + if err != nil { + log.Error("Failed to read database write delay statistic", "err", err) + continue + } + var ( + delayN int64 + delayDuration string + duration time.Duration + paused bool + ) + if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil { + log.Error("Write delay statistic not found") + continue + } + duration, err = time.ParseDuration(delayDuration) + if err != nil { + log.Error("Failed to parse delay duration", "err", err) + continue + } + if db.writeDelayNMeter != nil { + db.writeDelayNMeter.Mark(delayN - delaystats[0]) + } + if db.writeDelayMeter != nil { + db.writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1]) + } + // If a warning that db is performing compaction has been displayed, any subsequent + // warnings will be withheld for one minute not to overwhelm the user. + if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 && + time.Now().After(lastWritePaused.Add(writePauseWarningThrottler)) { + log.Warn("Database compacting, degraded performance") + lastWritePaused = time.Now() + } + delaystats[0], delaystats[1] = delayN, duration.Nanoseconds() + + // Retrieve the database iostats. + ioStats, err := db.ldb.GetProperty("leveldb.iostats") + if err != nil { + log.Error("Failed to read database iostats", "err", err) + continue + } + var nRead, nWrite float64 + parts := strings.Split(ioStats, " ") + if len(parts) < 2 { + log.Error("Bad syntax of ioStats", "ioStats", ioStats) + continue + } + if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil { + log.Error("Bad syntax of read entry", "entry", parts[0]) + continue + } + if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil { + log.Error("Bad syntax of write entry", "entry", parts[1]) + continue + } + if db.diskReadMeter != nil { + db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024)) + } + if db.diskWriteMeter != nil { + db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024)) + } + iostats[0], iostats[1] = nRead, nWrite + + // Sleep a bit, then repeat the stats collection + select { + case <-db.quit: + // Quit requesting, stop hammering the database + return + case <-time.After(refresh): + // Timeout, gather a new set of stats + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/db_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/db_test.go new file mode 100644 index 00000000..4e8276f7 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/db_test.go @@ -0,0 +1,112 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "io/ioutil" + "os" + "testing" +) + +// TestNewDB constructs a new DB +// and validates if the schema is initialized properly. +func TestNewDB(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + s, err := db.getSchema() + if err != nil { + t.Fatal(err) + } + if s.Fields == nil { + t.Error("schema fields are empty") + } + if len(s.Fields) != 0 { + t.Errorf("got schema fields length %v, want %v", len(s.Fields), 0) + } + if s.Indexes == nil { + t.Error("schema indexes are empty") + } + if len(s.Indexes) != 0 { + t.Errorf("got schema indexes length %v, want %v", len(s.Indexes), 0) + } +} + +// TestDB_persistence creates one DB, saves a field and closes that DB. +// Then, it constructs another DB and trues to retrieve the saved value. +func TestDB_persistence(t *testing.T) { + dir, err := ioutil.TempDir("", "shed-test-persistence") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + db, err := NewDB(dir, "") + if err != nil { + t.Fatal(err) + } + stringField, err := db.NewStringField("preserve-me") + if err != nil { + t.Fatal(err) + } + want := "persistent value" + err = stringField.Put(want) + if err != nil { + t.Fatal(err) + } + err = db.Close() + if err != nil { + t.Fatal(err) + } + + db2, err := NewDB(dir, "") + if err != nil { + t.Fatal(err) + } + stringField2, err := db2.NewStringField("preserve-me") + if err != nil { + t.Fatal(err) + } + got, err := stringField2.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got string %q, want %q", got, want) + } +} + +// newTestDB is a helper function that constructs a +// temporary database and returns a cleanup function that must +// be called to remove the data. +func newTestDB(t *testing.T) (db *DB, cleanupFunc func()) { + t.Helper() + + dir, err := ioutil.TempDir("", "shed-test") + if err != nil { + t.Fatal(err) + } + db, err = NewDB(dir, "") + if err != nil { + os.RemoveAll(dir) + t.Fatal(err) + } + return db, func() { + db.Close() + os.RemoveAll(dir) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/example_store_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/example_store_test.go new file mode 100644 index 00000000..9a83855e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/example_store_test.go @@ -0,0 +1,332 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed_test + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "io/ioutil" + "log" + "os" + "time" + + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/syndtr/goleveldb/leveldb" +) + +// Store holds fields and indexes (including their encoding functions) +// and defines operations on them by composing data from them. +// It implements storage.ChunkStore interface. +// It is just an example without any support for parallel operations +// or real world implementation. +type Store struct { + db *shed.DB + + // fields and indexes + schemaName shed.StringField + sizeCounter shed.Uint64Field + accessCounter shed.Uint64Field + retrievalIndex shed.Index + accessIndex shed.Index + gcIndex shed.Index +} + +// New returns new Store. All fields and indexes are initialized +// and possible conflicts with schema from existing database is checked +// automatically. +func New(path string) (s *Store, err error) { + db, err := shed.NewDB(path, "") + if err != nil { + return nil, err + } + s = &Store{ + db: db, + } + // Identify current storage schema by arbitrary name. + s.schemaName, err = db.NewStringField("schema-name") + if err != nil { + return nil, err + } + // Global ever incrementing index of chunk accesses. + s.accessCounter, err = db.NewUint64Field("access-counter") + if err != nil { + return nil, err + } + // Index storing actual chunk address, data and store timestamp. + s.retrievalIndex, err = db.NewIndex("Address->StoreTimestamp|Data", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + return fields.Address, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.Address = key + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) + value = append(b, fields.Data...) + return value, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) + e.Data = value[8:] + return e, nil + }, + }) + if err != nil { + return nil, err + } + // Index storing access timestamp for a particular address. + // It is needed in order to update gc index keys for iteration order. + s.accessIndex, err = db.NewIndex("Address->AccessTimestamp", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + return fields.Address, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.Address = key + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(fields.AccessTimestamp)) + return b, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + e.AccessTimestamp = int64(binary.BigEndian.Uint64(value)) + return e, nil + }, + }) + if err != nil { + return nil, err + } + // Index with keys ordered by access timestamp for garbage collection prioritization. + s.gcIndex, err = db.NewIndex("AccessTimestamp|StoredTimestamp|Address->nil", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + b := make([]byte, 16, 16+len(fields.Address)) + binary.BigEndian.PutUint64(b[:8], uint64(fields.AccessTimestamp)) + binary.BigEndian.PutUint64(b[8:16], uint64(fields.StoreTimestamp)) + key = append(b, fields.Address...) + return key, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.AccessTimestamp = int64(binary.BigEndian.Uint64(key[:8])) + e.StoreTimestamp = int64(binary.BigEndian.Uint64(key[8:16])) + e.Address = key[16:] + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + return nil, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + return e, nil + }, + }) + if err != nil { + return nil, err + } + return s, nil +} + +// Put stores the chunk and sets it store timestamp. +func (s *Store) Put(_ context.Context, ch storage.Chunk) (err error) { + return s.retrievalIndex.Put(shed.Item{ + Address: ch.Address(), + Data: ch.Data(), + StoreTimestamp: time.Now().UTC().UnixNano(), + }) +} + +// Get retrieves a chunk with the provided address. +// It updates access and gc indexes by removing the previous +// items from them and adding new items as keys of index entries +// are changed. +func (s *Store) Get(_ context.Context, addr storage.Address) (c storage.Chunk, err error) { + batch := new(leveldb.Batch) + + // Get the chunk data and storage timestamp. + item, err := s.retrievalIndex.Get(shed.Item{ + Address: addr, + }) + if err != nil { + if err == leveldb.ErrNotFound { + return nil, storage.ErrChunkNotFound + } + return nil, err + } + + // Get the chunk access timestamp. + accessItem, err := s.accessIndex.Get(shed.Item{ + Address: addr, + }) + switch err { + case nil: + // Remove gc index entry if access timestamp is found. + err = s.gcIndex.DeleteInBatch(batch, shed.Item{ + Address: item.Address, + StoreTimestamp: accessItem.AccessTimestamp, + AccessTimestamp: item.StoreTimestamp, + }) + if err != nil { + return nil, err + } + case leveldb.ErrNotFound: + // Access timestamp is not found. Do not do anything. + // This is the firs get request. + default: + return nil, err + } + + // Specify new access timestamp + accessTimestamp := time.Now().UTC().UnixNano() + + // Put new access timestamp in access index. + err = s.accessIndex.PutInBatch(batch, shed.Item{ + Address: addr, + AccessTimestamp: accessTimestamp, + }) + if err != nil { + return nil, err + } + + // Put new access timestamp in gc index. + err = s.gcIndex.PutInBatch(batch, shed.Item{ + Address: item.Address, + AccessTimestamp: accessTimestamp, + StoreTimestamp: item.StoreTimestamp, + }) + if err != nil { + return nil, err + } + + // Increment access counter. + // Currently this information is not used anywhere. + _, err = s.accessCounter.IncInBatch(batch) + if err != nil { + return nil, err + } + + // Write the batch. + err = s.db.WriteBatch(batch) + if err != nil { + return nil, err + } + + // Return the chunk. + return storage.NewChunk(item.Address, item.Data), nil +} + +// CollectGarbage is an example of index iteration. +// It provides no reliable garbage collection functionality. +func (s *Store) CollectGarbage() (err error) { + const maxTrashSize = 100 + maxRounds := 10 // arbitrary number, needs to be calculated + + // Run a few gc rounds. + for roundCount := 0; roundCount < maxRounds; roundCount++ { + var garbageCount int + // New batch for a new cg round. + trash := new(leveldb.Batch) + // Iterate through all index items and break when needed. + err = s.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { + // Remove the chunk. + err = s.retrievalIndex.DeleteInBatch(trash, item) + if err != nil { + return false, err + } + // Remove the element in gc index. + err = s.gcIndex.DeleteInBatch(trash, item) + if err != nil { + return false, err + } + // Remove the relation in access index. + err = s.accessIndex.DeleteInBatch(trash, item) + if err != nil { + return false, err + } + garbageCount++ + if garbageCount >= maxTrashSize { + return true, nil + } + return false, nil + }, nil) + if err != nil { + return err + } + if garbageCount == 0 { + return nil + } + err = s.db.WriteBatch(trash) + if err != nil { + return err + } + } + return nil +} + +// GetSchema is an example of retrieveing the most simple +// string from a database field. +func (s *Store) GetSchema() (name string, err error) { + name, err = s.schemaName.Get() + if err == leveldb.ErrNotFound { + return "", nil + } + return name, err +} + +// GetSchema is an example of storing the most simple +// string in a database field. +func (s *Store) PutSchema(name string) (err error) { + return s.schemaName.Put(name) +} + +// Close closes the underlying database. +func (s *Store) Close() error { + return s.db.Close() +} + +// Example_store constructs a simple storage implementation using shed package. +func Example_store() { + dir, err := ioutil.TempDir("", "ephemeral") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + s, err := New(dir) + if err != nil { + log.Fatal(err) + } + defer s.Close() + + ch := storage.GenerateRandomChunk(1024) + err = s.Put(context.Background(), ch) + if err != nil { + log.Fatal(err) + } + + got, err := s.Get(context.Background(), ch.Address()) + if err != nil { + log.Fatal(err) + } + + fmt.Println(bytes.Equal(got.Data(), ch.Data())) + + //Output: true +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_string.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_string.go new file mode 100644 index 00000000..a7e8f0c7 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_string.go @@ -0,0 +1,66 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "github.com/syndtr/goleveldb/leveldb" +) + +// StringField is the most simple field implementation +// that stores an arbitrary string under a specific LevelDB key. +type StringField struct { + db *DB + key []byte +} + +// NewStringField retruns a new Instance of StringField. +// It validates its name and type against the database schema. +func (db *DB) NewStringField(name string) (f StringField, err error) { + key, err := db.schemaFieldKey(name, "string") + if err != nil { + return f, err + } + return StringField{ + db: db, + key: key, + }, nil +} + +// Get returns a string value from database. +// If the value is not found, an empty string is returned +// an no error. +func (f StringField) Get() (val string, err error) { + b, err := f.db.Get(f.key) + if err != nil { + if err == leveldb.ErrNotFound { + return "", nil + } + return "", err + } + return string(b), nil +} + +// Put stores a string in the database. +func (f StringField) Put(val string) (err error) { + return f.db.Put(f.key, []byte(val)) +} + +// PutInBatch stores a string in a batch that can be +// saved later in database. +func (f StringField) PutInBatch(batch *leveldb.Batch, val string) { + batch.Put(f.key, []byte(val)) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_string_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_string_test.go new file mode 100644 index 00000000..4215075b --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_string_test.go @@ -0,0 +1,110 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "testing" + + "github.com/syndtr/goleveldb/leveldb" +) + +// TestStringField validates put and get operations +// of the StringField. +func TestStringField(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + simpleString, err := db.NewStringField("simple-string") + if err != nil { + t.Fatal(err) + } + + t.Run("get empty", func(t *testing.T) { + got, err := simpleString.Get() + if err != nil { + t.Fatal(err) + } + want := "" + if got != want { + t.Errorf("got string %q, want %q", got, want) + } + }) + + t.Run("put", func(t *testing.T) { + want := "simple string value" + err = simpleString.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := simpleString.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got string %q, want %q", got, want) + } + + t.Run("overwrite", func(t *testing.T) { + want := "overwritten string value" + err = simpleString.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := simpleString.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got string %q, want %q", got, want) + } + }) + }) + + t.Run("put in batch", func(t *testing.T) { + batch := new(leveldb.Batch) + want := "simple string batch value" + simpleString.PutInBatch(batch, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := simpleString.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got string %q, want %q", got, want) + } + + t.Run("overwrite", func(t *testing.T) { + batch := new(leveldb.Batch) + want := "overwritten string batch value" + simpleString.PutInBatch(batch, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := simpleString.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got string %q, want %q", got, want) + } + }) + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_struct.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_struct.go new file mode 100644 index 00000000..90daee7f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_struct.go @@ -0,0 +1,71 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "github.com/ethereum/go-ethereum/rlp" + "github.com/syndtr/goleveldb/leveldb" +) + +// StructField is a helper to store complex structure by +// encoding it in RLP format. +type StructField struct { + db *DB + key []byte +} + +// NewStructField returns a new StructField. +// It validates its name and type against the database schema. +func (db *DB) NewStructField(name string) (f StructField, err error) { + key, err := db.schemaFieldKey(name, "struct-rlp") + if err != nil { + return f, err + } + return StructField{ + db: db, + key: key, + }, nil +} + +// Get unmarshals data from the database to a provided val. +// If the data is not found leveldb.ErrNotFound is returned. +func (f StructField) Get(val interface{}) (err error) { + b, err := f.db.Get(f.key) + if err != nil { + return err + } + return rlp.DecodeBytes(b, val) +} + +// Put marshals provided val and saves it to the database. +func (f StructField) Put(val interface{}) (err error) { + b, err := rlp.EncodeToBytes(val) + if err != nil { + return err + } + return f.db.Put(f.key, b) +} + +// PutInBatch marshals provided val and puts it into the batch. +func (f StructField) PutInBatch(batch *leveldb.Batch, val interface{}) (err error) { + b, err := rlp.EncodeToBytes(val) + if err != nil { + return err + } + batch.Put(f.key, b) + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_struct_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_struct_test.go new file mode 100644 index 00000000..cc0be018 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_struct_test.go @@ -0,0 +1,127 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "testing" + + "github.com/syndtr/goleveldb/leveldb" +) + +// TestStructField validates put and get operations +// of the StructField. +func TestStructField(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + complexField, err := db.NewStructField("complex-field") + if err != nil { + t.Fatal(err) + } + + type complexStructure struct { + A string + } + + t.Run("get empty", func(t *testing.T) { + var s complexStructure + err := complexField.Get(&s) + if err != leveldb.ErrNotFound { + t.Fatalf("got error %v, want %v", err, leveldb.ErrNotFound) + } + want := "" + if s.A != want { + t.Errorf("got string %q, want %q", s.A, want) + } + }) + + t.Run("put", func(t *testing.T) { + want := complexStructure{ + A: "simple string value", + } + err = complexField.Put(want) + if err != nil { + t.Fatal(err) + } + var got complexStructure + err = complexField.Get(&got) + if err != nil { + t.Fatal(err) + } + if got.A != want.A { + t.Errorf("got string %q, want %q", got.A, want.A) + } + + t.Run("overwrite", func(t *testing.T) { + want := complexStructure{ + A: "overwritten string value", + } + err = complexField.Put(want) + if err != nil { + t.Fatal(err) + } + var got complexStructure + err = complexField.Get(&got) + if err != nil { + t.Fatal(err) + } + if got.A != want.A { + t.Errorf("got string %q, want %q", got.A, want.A) + } + }) + }) + + t.Run("put in batch", func(t *testing.T) { + batch := new(leveldb.Batch) + want := complexStructure{ + A: "simple string batch value", + } + complexField.PutInBatch(batch, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + var got complexStructure + err := complexField.Get(&got) + if err != nil { + t.Fatal(err) + } + if got.A != want.A { + t.Errorf("got string %q, want %q", got, want) + } + + t.Run("overwrite", func(t *testing.T) { + batch := new(leveldb.Batch) + want := complexStructure{ + A: "overwritten string batch value", + } + complexField.PutInBatch(batch, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + var got complexStructure + err := complexField.Get(&got) + if err != nil { + t.Fatal(err) + } + if got.A != want.A { + t.Errorf("got string %q, want %q", got, want) + } + }) + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_uint64.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_uint64.go new file mode 100644 index 00000000..0417583a --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_uint64.go @@ -0,0 +1,146 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "encoding/binary" + + "github.com/syndtr/goleveldb/leveldb" +) + +// Uint64Field provides a way to have a simple counter in the database. +// It transparently encodes uint64 type value to bytes. +type Uint64Field struct { + db *DB + key []byte +} + +// NewUint64Field returns a new Uint64Field. +// It validates its name and type against the database schema. +func (db *DB) NewUint64Field(name string) (f Uint64Field, err error) { + key, err := db.schemaFieldKey(name, "uint64") + if err != nil { + return f, err + } + return Uint64Field{ + db: db, + key: key, + }, nil +} + +// Get retrieves a uint64 value from the database. +// If the value is not found in the database a 0 value +// is returned and no error. +func (f Uint64Field) Get() (val uint64, err error) { + b, err := f.db.Get(f.key) + if err != nil { + if err == leveldb.ErrNotFound { + return 0, nil + } + return 0, err + } + return binary.BigEndian.Uint64(b), nil +} + +// Put encodes uin64 value and stores it in the database. +func (f Uint64Field) Put(val uint64) (err error) { + return f.db.Put(f.key, encodeUint64(val)) +} + +// PutInBatch stores a uint64 value in a batch +// that can be saved later in the database. +func (f Uint64Field) PutInBatch(batch *leveldb.Batch, val uint64) { + batch.Put(f.key, encodeUint64(val)) +} + +// Inc increments a uint64 value in the database. +// This operation is not goroutine save. +func (f Uint64Field) Inc() (val uint64, err error) { + val, err = f.Get() + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + val++ + return val, f.Put(val) +} + +// IncInBatch increments a uint64 value in the batch +// by retreiving a value from the database, not the same batch. +// This operation is not goroutine save. +func (f Uint64Field) IncInBatch(batch *leveldb.Batch) (val uint64, err error) { + val, err = f.Get() + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + val++ + f.PutInBatch(batch, val) + return val, nil +} + +// Dec decrements a uint64 value in the database. +// This operation is not goroutine save. +// The field is protected from overflow to a negative value. +func (f Uint64Field) Dec() (val uint64, err error) { + val, err = f.Get() + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + if val != 0 { + val-- + } + return val, f.Put(val) +} + +// DecInBatch decrements a uint64 value in the batch +// by retreiving a value from the database, not the same batch. +// This operation is not goroutine save. +// The field is protected from overflow to a negative value. +func (f Uint64Field) DecInBatch(batch *leveldb.Batch) (val uint64, err error) { + val, err = f.Get() + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + if val != 0 { + val-- + } + f.PutInBatch(batch, val) + return val, nil +} + +// encode transforms uint64 to 8 byte long +// slice in big endian encoding. +func encodeUint64(val uint64) (b []byte) { + b = make([]byte, 8) + binary.BigEndian.PutUint64(b, val) + return b +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_uint64_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_uint64_test.go new file mode 100644 index 00000000..9462b56d --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/field_uint64_test.go @@ -0,0 +1,300 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "testing" + + "github.com/syndtr/goleveldb/leveldb" +) + +// TestUint64Field validates put and get operations +// of the Uint64Field. +func TestUint64Field(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + counter, err := db.NewUint64Field("counter") + if err != nil { + t.Fatal(err) + } + + t.Run("get empty", func(t *testing.T) { + got, err := counter.Get() + if err != nil { + t.Fatal(err) + } + var want uint64 + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + }) + + t.Run("put", func(t *testing.T) { + var want uint64 = 42 + err = counter.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + t.Run("overwrite", func(t *testing.T) { + var want uint64 = 84 + err = counter.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + }) + }) + + t.Run("put in batch", func(t *testing.T) { + batch := new(leveldb.Batch) + var want uint64 = 42 + counter.PutInBatch(batch, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + t.Run("overwrite", func(t *testing.T) { + batch := new(leveldb.Batch) + var want uint64 = 84 + counter.PutInBatch(batch, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + }) + }) +} + +// TestUint64Field_Inc validates Inc operation +// of the Uint64Field. +func TestUint64Field_Inc(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + counter, err := db.NewUint64Field("counter") + if err != nil { + t.Fatal(err) + } + + var want uint64 = 1 + got, err := counter.Inc() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + want = 2 + got, err = counter.Inc() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } +} + +// TestUint64Field_IncInBatch validates IncInBatch operation +// of the Uint64Field. +func TestUint64Field_IncInBatch(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + counter, err := db.NewUint64Field("counter") + if err != nil { + t.Fatal(err) + } + + batch := new(leveldb.Batch) + var want uint64 = 1 + got, err := counter.IncInBatch(batch) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err = counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + batch2 := new(leveldb.Batch) + want = 2 + got, err = counter.IncInBatch(batch2) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + err = db.WriteBatch(batch2) + if err != nil { + t.Fatal(err) + } + got, err = counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } +} + +// TestUint64Field_Dec validates Dec operation +// of the Uint64Field. +func TestUint64Field_Dec(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + counter, err := db.NewUint64Field("counter") + if err != nil { + t.Fatal(err) + } + + // test overflow protection + var want uint64 + got, err := counter.Dec() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + want = 32 + err = counter.Put(want) + if err != nil { + t.Fatal(err) + } + + want = 31 + got, err = counter.Dec() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } +} + +// TestUint64Field_DecInBatch validates DecInBatch operation +// of the Uint64Field. +func TestUint64Field_DecInBatch(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + counter, err := db.NewUint64Field("counter") + if err != nil { + t.Fatal(err) + } + + batch := new(leveldb.Batch) + var want uint64 + got, err := counter.DecInBatch(batch) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err = counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + batch2 := new(leveldb.Batch) + want = 42 + counter.PutInBatch(batch2, want) + err = db.WriteBatch(batch2) + if err != nil { + t.Fatal(err) + } + got, err = counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + + batch3 := new(leveldb.Batch) + want = 41 + got, err = counter.DecInBatch(batch3) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + err = db.WriteBatch(batch3) + if err != nil { + t.Fatal(err) + } + got, err = counter.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/index.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/index.go new file mode 100644 index 00000000..6be018d2 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/index.go @@ -0,0 +1,392 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "bytes" + + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/iterator" +) + +// Item holds fields relevant to Swarm Chunk data and metadata. +// All information required for swarm storage and operations +// on that storage must be defined here. +// This structure is logically connected to swarm storage, +// the only part of this package that is not generalized, +// mostly for performance reasons. +// +// Item is a type that is used for retrieving, storing and encoding +// chunk data and metadata. It is passed as an argument to Index encoding +// functions, get function and put function. +// But it is also returned with additional data from get function call +// and as the argument in iterator function definition. +type Item struct { + Address []byte + Data []byte + AccessTimestamp int64 + StoreTimestamp int64 + // UseMockStore is a pointer to identify + // an unset state of the field in Join function. + UseMockStore *bool +} + +// Merge is a helper method to construct a new +// Item by filling up fields with default values +// of a particular Item with values from another one. +func (i Item) Merge(i2 Item) (new Item) { + if i.Address == nil { + i.Address = i2.Address + } + if i.Data == nil { + i.Data = i2.Data + } + if i.AccessTimestamp == 0 { + i.AccessTimestamp = i2.AccessTimestamp + } + if i.StoreTimestamp == 0 { + i.StoreTimestamp = i2.StoreTimestamp + } + if i.UseMockStore == nil { + i.UseMockStore = i2.UseMockStore + } + return i +} + +// Index represents a set of LevelDB key value pairs that have common +// prefix. It holds functions for encoding and decoding keys and values +// to provide transparent actions on saved data which inclide: +// - getting a particular Item +// - saving a particular Item +// - iterating over a sorted LevelDB keys +// It implements IndexIteratorInterface interface. +type Index struct { + db *DB + prefix []byte + encodeKeyFunc func(fields Item) (key []byte, err error) + decodeKeyFunc func(key []byte) (e Item, err error) + encodeValueFunc func(fields Item) (value []byte, err error) + decodeValueFunc func(keyFields Item, value []byte) (e Item, err error) +} + +// IndexFuncs structure defines functions for encoding and decoding +// LevelDB keys and values for a specific index. +type IndexFuncs struct { + EncodeKey func(fields Item) (key []byte, err error) + DecodeKey func(key []byte) (e Item, err error) + EncodeValue func(fields Item) (value []byte, err error) + DecodeValue func(keyFields Item, value []byte) (e Item, err error) +} + +// NewIndex returns a new Index instance with defined name and +// encoding functions. The name must be unique and will be validated +// on database schema for a key prefix byte. +func (db *DB) NewIndex(name string, funcs IndexFuncs) (f Index, err error) { + id, err := db.schemaIndexPrefix(name) + if err != nil { + return f, err + } + prefix := []byte{id} + return Index{ + db: db, + prefix: prefix, + // This function adjusts Index LevelDB key + // by appending the provided index id byte. + // This is needed to avoid collisions between keys of different + // indexes as all index ids are unique. + encodeKeyFunc: func(e Item) (key []byte, err error) { + key, err = funcs.EncodeKey(e) + if err != nil { + return nil, err + } + return append(append(make([]byte, 0, len(key)+1), prefix...), key...), nil + }, + // This function reverses the encodeKeyFunc constructed key + // to transparently work with index keys without their index ids. + // It assumes that index keys are prefixed with only one byte. + decodeKeyFunc: func(key []byte) (e Item, err error) { + return funcs.DecodeKey(key[1:]) + }, + encodeValueFunc: funcs.EncodeValue, + decodeValueFunc: funcs.DecodeValue, + }, nil +} + +// Get accepts key fields represented as Item to retrieve a +// value from the index and return maximum available information +// from the index represented as another Item. +func (f Index) Get(keyFields Item) (out Item, err error) { + key, err := f.encodeKeyFunc(keyFields) + if err != nil { + return out, err + } + value, err := f.db.Get(key) + if err != nil { + return out, err + } + out, err = f.decodeValueFunc(keyFields, value) + if err != nil { + return out, err + } + return out.Merge(keyFields), nil +} + +// Has accepts key fields represented as Item to check +// if there this Item's encoded key is stored in +// the index. +func (f Index) Has(keyFields Item) (bool, error) { + key, err := f.encodeKeyFunc(keyFields) + if err != nil { + return false, err + } + return f.db.Has(key) +} + +// Put accepts Item to encode information from it +// and save it to the database. +func (f Index) Put(i Item) (err error) { + key, err := f.encodeKeyFunc(i) + if err != nil { + return err + } + value, err := f.encodeValueFunc(i) + if err != nil { + return err + } + return f.db.Put(key, value) +} + +// PutInBatch is the same as Put method, but it just +// saves the key/value pair to the batch instead +// directly to the database. +func (f Index) PutInBatch(batch *leveldb.Batch, i Item) (err error) { + key, err := f.encodeKeyFunc(i) + if err != nil { + return err + } + value, err := f.encodeValueFunc(i) + if err != nil { + return err + } + batch.Put(key, value) + return nil +} + +// Delete accepts Item to remove a key/value pair +// from the database based on its fields. +func (f Index) Delete(keyFields Item) (err error) { + key, err := f.encodeKeyFunc(keyFields) + if err != nil { + return err + } + return f.db.Delete(key) +} + +// DeleteInBatch is the same as Delete just the operation +// is performed on the batch instead on the database. +func (f Index) DeleteInBatch(batch *leveldb.Batch, keyFields Item) (err error) { + key, err := f.encodeKeyFunc(keyFields) + if err != nil { + return err + } + batch.Delete(key) + return nil +} + +// IndexIterFunc is a callback on every Item that is decoded +// by iterating on an Index keys. +// By returning a true for stop variable, iteration will +// stop, and by returning the error, that error will be +// propagated to the called iterator method on Index. +type IndexIterFunc func(item Item) (stop bool, err error) + +// IterateOptions defines optional parameters for Iterate function. +type IterateOptions struct { + // StartFrom is the Item to start the iteration from. + StartFrom *Item + // If SkipStartFromItem is true, StartFrom item will not + // be iterated on. + SkipStartFromItem bool + // Iterate over items which keys have a common prefix. + Prefix []byte +} + +// Iterate function iterates over keys of the Index. +// If IterateOptions is nil, the iterations is over all keys. +func (f Index) Iterate(fn IndexIterFunc, options *IterateOptions) (err error) { + if options == nil { + options = new(IterateOptions) + } + // construct a prefix with Index prefix and optional common key prefix + prefix := append(f.prefix, options.Prefix...) + // start from the prefix + startKey := prefix + if options.StartFrom != nil { + // start from the provided StartFrom Item key value + startKey, err = f.encodeKeyFunc(*options.StartFrom) + if err != nil { + return err + } + } + it := f.db.NewIterator() + defer it.Release() + + // move the cursor to the start key + ok := it.Seek(startKey) + if !ok { + // stop iterator if seek has failed + return it.Error() + } + if options.SkipStartFromItem && bytes.Equal(startKey, it.Key()) { + // skip the start from Item if it is the first key + // and it is explicitly configured to skip it + ok = it.Next() + } + for ; ok; ok = it.Next() { + item, err := f.itemFromIterator(it, prefix) + if err != nil { + if err == leveldb.ErrNotFound { + break + } + return err + } + stop, err := fn(item) + if err != nil { + return err + } + if stop { + break + } + } + return it.Error() +} + +// First returns the first item in the Index which encoded key starts with a prefix. +// If the prefix is nil, the first element of the whole index is returned. +// If Index has no elements, a leveldb.ErrNotFound error is returned. +func (f Index) First(prefix []byte) (i Item, err error) { + it := f.db.NewIterator() + defer it.Release() + + totalPrefix := append(f.prefix, prefix...) + it.Seek(totalPrefix) + + return f.itemFromIterator(it, totalPrefix) +} + +// itemFromIterator returns the Item from the current iterator position. +// If the complete encoded key does not start with totalPrefix, +// leveldb.ErrNotFound is returned. Value for totalPrefix must start with +// Index prefix. +func (f Index) itemFromIterator(it iterator.Iterator, totalPrefix []byte) (i Item, err error) { + key := it.Key() + if !bytes.HasPrefix(key, totalPrefix) { + return i, leveldb.ErrNotFound + } + // create a copy of key byte slice not to share leveldb underlaying slice array + keyItem, err := f.decodeKeyFunc(append([]byte(nil), key...)) + if err != nil { + return i, err + } + // create a copy of value byte slice not to share leveldb underlaying slice array + valueItem, err := f.decodeValueFunc(keyItem, append([]byte(nil), it.Value()...)) + if err != nil { + return i, err + } + return keyItem.Merge(valueItem), it.Error() +} + +// Last returns the last item in the Index which encoded key starts with a prefix. +// If the prefix is nil, the last element of the whole index is returned. +// If Index has no elements, a leveldb.ErrNotFound error is returned. +func (f Index) Last(prefix []byte) (i Item, err error) { + it := f.db.NewIterator() + defer it.Release() + + // get the next prefix in line + // since leveldb iterator Seek seeks to the + // next key if the key that it seeks to is not found + // and by getting the previous key, the last one for the + // actual prefix is found + nextPrefix := incByteSlice(prefix) + l := len(prefix) + + if l > 0 && nextPrefix != nil { + it.Seek(append(f.prefix, nextPrefix...)) + it.Prev() + } else { + it.Last() + } + + totalPrefix := append(f.prefix, prefix...) + return f.itemFromIterator(it, totalPrefix) +} + +// incByteSlice returns the byte slice of the same size +// of the provided one that is by one incremented in its +// total value. If all bytes in provided slice are equal +// to 255 a nil slice would be returned indicating that +// increment can not happen for the same length. +func incByteSlice(b []byte) (next []byte) { + l := len(b) + next = make([]byte, l) + copy(next, b) + for i := l - 1; i >= 0; i-- { + if b[i] == 255 { + next[i] = 0 + } else { + next[i] = b[i] + 1 + return next + } + } + return nil +} + +// Count returns the number of items in index. +func (f Index) Count() (count int, err error) { + it := f.db.NewIterator() + defer it.Release() + + for ok := it.Seek(f.prefix); ok; ok = it.Next() { + key := it.Key() + if key[0] != f.prefix[0] { + break + } + count++ + } + return count, it.Error() +} + +// CountFrom returns the number of items in index keys +// starting from the key encoded from the provided Item. +func (f Index) CountFrom(start Item) (count int, err error) { + startKey, err := f.encodeKeyFunc(start) + if err != nil { + return 0, err + } + it := f.db.NewIterator() + defer it.Release() + + for ok := it.Seek(startKey); ok; ok = it.Next() { + key := it.Key() + if key[0] != f.prefix[0] { + break + } + count++ + } + return count, it.Error() +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/index_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/index_test.go new file mode 100644 index 00000000..de181fa4 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/index_test.go @@ -0,0 +1,962 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "bytes" + "encoding/binary" + "fmt" + "sort" + "testing" + "time" + + "github.com/syndtr/goleveldb/leveldb" +) + +// Index functions for the index that is used in tests in this file. +var retrievalIndexFuncs = IndexFuncs{ + EncodeKey: func(fields Item) (key []byte, err error) { + return fields.Address, nil + }, + DecodeKey: func(key []byte) (e Item, err error) { + e.Address = key + return e, nil + }, + EncodeValue: func(fields Item) (value []byte, err error) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) + value = append(b, fields.Data...) + return value, nil + }, + DecodeValue: func(keyItem Item, value []byte) (e Item, err error) { + e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) + e.Data = value[8:] + return e, nil + }, +} + +// TestIndex validates put, get, has and delete functions of the Index implementation. +func TestIndex(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + index, err := db.NewIndex("retrieval", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + t.Run("put", func(t *testing.T) { + want := Item{ + Address: []byte("put-hash"), + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + err := index.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + + t.Run("overwrite", func(t *testing.T) { + want := Item{ + Address: []byte("put-hash"), + Data: []byte("New DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + err = index.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + }) + }) + + t.Run("put in batch", func(t *testing.T) { + want := Item{ + Address: []byte("put-in-batch-hash"), + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + batch := new(leveldb.Batch) + index.PutInBatch(batch, want) + err := db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + + t.Run("overwrite", func(t *testing.T) { + want := Item{ + Address: []byte("put-in-batch-hash"), + Data: []byte("New DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + batch := new(leveldb.Batch) + index.PutInBatch(batch, want) + db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + }) + }) + + t.Run("put in batch twice", func(t *testing.T) { + // ensure that the last item of items with the same db keys + // is actually saved + batch := new(leveldb.Batch) + address := []byte("put-in-batch-twice-hash") + + // put the first item + index.PutInBatch(batch, Item{ + Address: address, + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + }) + + want := Item{ + Address: address, + Data: []byte("New DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + // then put the item that will produce the same key + // but different value in the database + index.PutInBatch(batch, want) + db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + }) + + t.Run("has", func(t *testing.T) { + want := Item{ + Address: []byte("has-hash"), + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + dontWant := Item{ + Address: []byte("do-not-has-hash"), + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + err := index.Put(want) + if err != nil { + t.Fatal(err) + } + + has, err := index.Has(want) + if err != nil { + t.Fatal(err) + } + if !has { + t.Error("item is not found") + } + + has, err = index.Has(dontWant) + if err != nil { + t.Fatal(err) + } + if has { + t.Error("unwanted item is found") + } + }) + + t.Run("delete", func(t *testing.T) { + want := Item{ + Address: []byte("delete-hash"), + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + err := index.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + + err = index.Delete(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + + wantErr := leveldb.ErrNotFound + got, err = index.Get(Item{ + Address: want.Address, + }) + if err != wantErr { + t.Fatalf("got error %v, want %v", err, wantErr) + } + }) + + t.Run("delete in batch", func(t *testing.T) { + want := Item{ + Address: []byte("delete-in-batch-hash"), + Data: []byte("DATA"), + StoreTimestamp: time.Now().UTC().UnixNano(), + } + + err := index.Put(want) + if err != nil { + t.Fatal(err) + } + got, err := index.Get(Item{ + Address: want.Address, + }) + if err != nil { + t.Fatal(err) + } + checkItem(t, got, want) + + batch := new(leveldb.Batch) + index.DeleteInBatch(batch, Item{ + Address: want.Address, + }) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + + wantErr := leveldb.ErrNotFound + got, err = index.Get(Item{ + Address: want.Address, + }) + if err != wantErr { + t.Fatalf("got error %v, want %v", err, wantErr) + } + }) +} + +// TestIndex_Iterate validates index Iterate +// functions for correctness. +func TestIndex_Iterate(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + index, err := db.NewIndex("retrieval", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + items := []Item{ + { + Address: []byte("iterate-hash-01"), + Data: []byte("data80"), + }, + { + Address: []byte("iterate-hash-03"), + Data: []byte("data22"), + }, + { + Address: []byte("iterate-hash-05"), + Data: []byte("data41"), + }, + { + Address: []byte("iterate-hash-02"), + Data: []byte("data84"), + }, + { + Address: []byte("iterate-hash-06"), + Data: []byte("data1"), + }, + } + batch := new(leveldb.Batch) + for _, i := range items { + index.PutInBatch(batch, i) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + item04 := Item{ + Address: []byte("iterate-hash-04"), + Data: []byte("data0"), + } + err = index.Put(item04) + if err != nil { + t.Fatal(err) + } + items = append(items, item04) + + sort.SliceStable(items, func(i, j int) bool { + return bytes.Compare(items[i].Address, items[j].Address) < 0 + }) + + t.Run("all", func(t *testing.T) { + var i int + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + return false, nil + }, nil) + if err != nil { + t.Fatal(err) + } + }) + + t.Run("start from", func(t *testing.T) { + startIndex := 2 + i := startIndex + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + return false, nil + }, &IterateOptions{ + StartFrom: &items[startIndex], + }) + if err != nil { + t.Fatal(err) + } + }) + + t.Run("skip start from", func(t *testing.T) { + startIndex := 2 + i := startIndex + 1 + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + return false, nil + }, &IterateOptions{ + StartFrom: &items[startIndex], + SkipStartFromItem: true, + }) + if err != nil { + t.Fatal(err) + } + }) + + t.Run("stop", func(t *testing.T) { + var i int + stopIndex := 3 + var count int + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + count++ + if i == stopIndex { + return true, nil + } + i++ + return false, nil + }, nil) + if err != nil { + t.Fatal(err) + } + wantItemsCount := stopIndex + 1 + if count != wantItemsCount { + t.Errorf("got %v items, expected %v", count, wantItemsCount) + } + }) + + t.Run("no overflow", func(t *testing.T) { + secondIndex, err := db.NewIndex("second-index", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + secondItem := Item{ + Address: []byte("iterate-hash-10"), + Data: []byte("data-second"), + } + err = secondIndex.Put(secondItem) + if err != nil { + t.Fatal(err) + } + + var i int + err = index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + return false, nil + }, nil) + if err != nil { + t.Fatal(err) + } + + i = 0 + err = secondIndex.Iterate(func(item Item) (stop bool, err error) { + if i > 1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + checkItem(t, item, secondItem) + i++ + return false, nil + }, nil) + if err != nil { + t.Fatal(err) + } + }) +} + +// TestIndex_Iterate_withPrefix validates index Iterate +// function for correctness. +func TestIndex_Iterate_withPrefix(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + index, err := db.NewIndex("retrieval", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + allItems := []Item{ + {Address: []byte("want-hash-00"), Data: []byte("data80")}, + {Address: []byte("skip-hash-01"), Data: []byte("data81")}, + {Address: []byte("skip-hash-02"), Data: []byte("data82")}, + {Address: []byte("skip-hash-03"), Data: []byte("data83")}, + {Address: []byte("want-hash-04"), Data: []byte("data84")}, + {Address: []byte("want-hash-05"), Data: []byte("data85")}, + {Address: []byte("want-hash-06"), Data: []byte("data86")}, + {Address: []byte("want-hash-07"), Data: []byte("data87")}, + {Address: []byte("want-hash-08"), Data: []byte("data88")}, + {Address: []byte("want-hash-09"), Data: []byte("data89")}, + {Address: []byte("skip-hash-10"), Data: []byte("data90")}, + } + batch := new(leveldb.Batch) + for _, i := range allItems { + index.PutInBatch(batch, i) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + + prefix := []byte("want") + + items := make([]Item, 0) + for _, item := range allItems { + if bytes.HasPrefix(item.Address, prefix) { + items = append(items, item) + } + } + sort.SliceStable(items, func(i, j int) bool { + return bytes.Compare(items[i].Address, items[j].Address) < 0 + }) + + t.Run("with prefix", func(t *testing.T) { + var i int + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + return false, nil + }, &IterateOptions{ + Prefix: prefix, + }) + if err != nil { + t.Fatal(err) + } + if i != len(items) { + t.Errorf("got %v items, want %v", i, len(items)) + } + }) + + t.Run("with prefix and start from", func(t *testing.T) { + startIndex := 2 + var count int + i := startIndex + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + count++ + return false, nil + }, &IterateOptions{ + StartFrom: &items[startIndex], + Prefix: prefix, + }) + if err != nil { + t.Fatal(err) + } + wantCount := len(items) - startIndex + if count != wantCount { + t.Errorf("got %v items, want %v", count, wantCount) + } + }) + + t.Run("with prefix and skip start from", func(t *testing.T) { + startIndex := 2 + var count int + i := startIndex + 1 + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + count++ + return false, nil + }, &IterateOptions{ + StartFrom: &items[startIndex], + SkipStartFromItem: true, + Prefix: prefix, + }) + if err != nil { + t.Fatal(err) + } + wantCount := len(items) - startIndex - 1 + if count != wantCount { + t.Errorf("got %v items, want %v", count, wantCount) + } + }) + + t.Run("stop", func(t *testing.T) { + var i int + stopIndex := 3 + var count int + err := index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + count++ + if i == stopIndex { + return true, nil + } + i++ + return false, nil + }, &IterateOptions{ + Prefix: prefix, + }) + if err != nil { + t.Fatal(err) + } + wantItemsCount := stopIndex + 1 + if count != wantItemsCount { + t.Errorf("got %v items, expected %v", count, wantItemsCount) + } + }) + + t.Run("no overflow", func(t *testing.T) { + secondIndex, err := db.NewIndex("second-index", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + secondItem := Item{ + Address: []byte("iterate-hash-10"), + Data: []byte("data-second"), + } + err = secondIndex.Put(secondItem) + if err != nil { + t.Fatal(err) + } + + var i int + err = index.Iterate(func(item Item) (stop bool, err error) { + if i > len(items)-1 { + return true, fmt.Errorf("got unexpected index item: %#v", item) + } + want := items[i] + checkItem(t, item, want) + i++ + return false, nil + }, &IterateOptions{ + Prefix: prefix, + }) + if err != nil { + t.Fatal(err) + } + if i != len(items) { + t.Errorf("got %v items, want %v", i, len(items)) + } + }) +} + +// TestIndex_count tests if Index.Count and Index.CountFrom +// returns the correct number of items. +func TestIndex_count(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + index, err := db.NewIndex("retrieval", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + items := []Item{ + { + Address: []byte("iterate-hash-01"), + Data: []byte("data80"), + }, + { + Address: []byte("iterate-hash-02"), + Data: []byte("data84"), + }, + { + Address: []byte("iterate-hash-03"), + Data: []byte("data22"), + }, + { + Address: []byte("iterate-hash-04"), + Data: []byte("data41"), + }, + { + Address: []byte("iterate-hash-05"), + Data: []byte("data1"), + }, + } + batch := new(leveldb.Batch) + for _, i := range items { + index.PutInBatch(batch, i) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + + t.Run("Count", func(t *testing.T) { + got, err := index.Count() + if err != nil { + t.Fatal(err) + } + + want := len(items) + if got != want { + t.Errorf("got %v items count, want %v", got, want) + } + }) + + t.Run("CountFrom", func(t *testing.T) { + got, err := index.CountFrom(Item{ + Address: items[1].Address, + }) + if err != nil { + t.Fatal(err) + } + + want := len(items) - 1 + if got != want { + t.Errorf("got %v items count, want %v", got, want) + } + }) + + // update the index with another item + t.Run("add item", func(t *testing.T) { + item04 := Item{ + Address: []byte("iterate-hash-06"), + Data: []byte("data0"), + } + err = index.Put(item04) + if err != nil { + t.Fatal(err) + } + + count := len(items) + 1 + + t.Run("Count", func(t *testing.T) { + got, err := index.Count() + if err != nil { + t.Fatal(err) + } + + want := count + if got != want { + t.Errorf("got %v items count, want %v", got, want) + } + }) + + t.Run("CountFrom", func(t *testing.T) { + got, err := index.CountFrom(Item{ + Address: items[1].Address, + }) + if err != nil { + t.Fatal(err) + } + + want := count - 1 + if got != want { + t.Errorf("got %v items count, want %v", got, want) + } + }) + }) + + // delete some items + t.Run("delete items", func(t *testing.T) { + deleteCount := 3 + + for _, item := range items[:deleteCount] { + err := index.Delete(item) + if err != nil { + t.Fatal(err) + } + } + + count := len(items) + 1 - deleteCount + + t.Run("Count", func(t *testing.T) { + got, err := index.Count() + if err != nil { + t.Fatal(err) + } + + want := count + if got != want { + t.Errorf("got %v items count, want %v", got, want) + } + }) + + t.Run("CountFrom", func(t *testing.T) { + got, err := index.CountFrom(Item{ + Address: items[deleteCount+1].Address, + }) + if err != nil { + t.Fatal(err) + } + + want := count - 1 + if got != want { + t.Errorf("got %v items count, want %v", got, want) + } + }) + }) +} + +// checkItem is a test helper function that compares if two Index items are the same. +func checkItem(t *testing.T, got, want Item) { + t.Helper() + + if !bytes.Equal(got.Address, want.Address) { + t.Errorf("got hash %q, expected %q", string(got.Address), string(want.Address)) + } + if !bytes.Equal(got.Data, want.Data) { + t.Errorf("got data %q, expected %q", string(got.Data), string(want.Data)) + } + if got.StoreTimestamp != want.StoreTimestamp { + t.Errorf("got store timestamp %v, expected %v", got.StoreTimestamp, want.StoreTimestamp) + } + if got.AccessTimestamp != want.AccessTimestamp { + t.Errorf("got access timestamp %v, expected %v", got.AccessTimestamp, want.AccessTimestamp) + } +} + +// TestIndex_firstAndLast validates that index First and Last methods +// are returning expected results based on the provided prefix. +func TestIndex_firstAndLast(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + index, err := db.NewIndex("retrieval", retrievalIndexFuncs) + if err != nil { + t.Fatal(err) + } + + addrs := [][]byte{ + {0, 0, 0, 0, 0}, + {0, 1}, + {0, 1, 0, 0, 0}, + {0, 1, 0, 0, 1}, + {0, 1, 0, 0, 2}, + {0, 2, 0, 0, 1}, + {0, 4, 0, 0, 0}, + {0, 10, 0, 0, 10}, + {0, 10, 0, 0, 11}, + {0, 10, 0, 0, 20}, + {1, 32, 255, 0, 1}, + {1, 32, 255, 0, 2}, + {1, 32, 255, 0, 3}, + {255, 255, 255, 255, 32}, + {255, 255, 255, 255, 64}, + {255, 255, 255, 255, 255}, + } + + // ensure that the addresses are sorted for + // validation of nil prefix + sort.Slice(addrs, func(i, j int) (less bool) { + return bytes.Compare(addrs[i], addrs[j]) == -1 + }) + + batch := new(leveldb.Batch) + for _, addr := range addrs { + index.PutInBatch(batch, Item{ + Address: addr, + }) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + + for _, tc := range []struct { + prefix []byte + first []byte + last []byte + err error + }{ + { + prefix: nil, + first: addrs[0], + last: addrs[len(addrs)-1], + }, + { + prefix: []byte{0, 0}, + first: []byte{0, 0, 0, 0, 0}, + last: []byte{0, 0, 0, 0, 0}, + }, + { + prefix: []byte{0}, + first: []byte{0, 0, 0, 0, 0}, + last: []byte{0, 10, 0, 0, 20}, + }, + { + prefix: []byte{0, 1}, + first: []byte{0, 1}, + last: []byte{0, 1, 0, 0, 2}, + }, + { + prefix: []byte{0, 10}, + first: []byte{0, 10, 0, 0, 10}, + last: []byte{0, 10, 0, 0, 20}, + }, + { + prefix: []byte{1, 32, 255}, + first: []byte{1, 32, 255, 0, 1}, + last: []byte{1, 32, 255, 0, 3}, + }, + { + prefix: []byte{255}, + first: []byte{255, 255, 255, 255, 32}, + last: []byte{255, 255, 255, 255, 255}, + }, + { + prefix: []byte{255, 255, 255, 255, 255}, + first: []byte{255, 255, 255, 255, 255}, + last: []byte{255, 255, 255, 255, 255}, + }, + { + prefix: []byte{0, 3}, + err: leveldb.ErrNotFound, + }, + { + prefix: []byte{222}, + err: leveldb.ErrNotFound, + }, + } { + got, err := index.Last(tc.prefix) + if tc.err != err { + t.Errorf("got error %v for Last with prefix %v, want %v", err, tc.prefix, tc.err) + } else { + if !bytes.Equal(got.Address, tc.last) { + t.Errorf("got %v for Last with prefix %v, want %v", got.Address, tc.prefix, tc.last) + } + } + + got, err = index.First(tc.prefix) + if tc.err != err { + t.Errorf("got error %v for First with prefix %v, want %v", err, tc.prefix, tc.err) + } else { + if !bytes.Equal(got.Address, tc.first) { + t.Errorf("got %v for First with prefix %v, want %v", got.Address, tc.prefix, tc.first) + } + } + } +} + +// TestIncByteSlice validates returned values of incByteSlice function. +func TestIncByteSlice(t *testing.T) { + for _, tc := range []struct { + b []byte + want []byte + }{ + {b: nil, want: nil}, + {b: []byte{}, want: nil}, + {b: []byte{0}, want: []byte{1}}, + {b: []byte{42}, want: []byte{43}}, + {b: []byte{255}, want: nil}, + {b: []byte{0, 0}, want: []byte{0, 1}}, + {b: []byte{1, 0}, want: []byte{1, 1}}, + {b: []byte{1, 255}, want: []byte{2, 0}}, + {b: []byte{255, 255}, want: nil}, + {b: []byte{32, 0, 255}, want: []byte{32, 1, 0}}, + } { + got := incByteSlice(tc.b) + if !bytes.Equal(got, tc.want) { + t.Errorf("got %v, want %v", got, tc.want) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/schema.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/schema.go new file mode 100644 index 00000000..cfb7c6d6 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/schema.go @@ -0,0 +1,134 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "encoding/json" + "errors" + "fmt" +) + +var ( + // LevelDB key value for storing the schema. + keySchema = []byte{0} + // LevelDB key prefix for all field type. + // LevelDB keys will be constructed by appending name values to this prefix. + keyPrefixFields byte = 1 + // LevelDB key prefix from which indexing keys start. + // Every index has its own key prefix and this value defines the first one. + keyPrefixIndexStart byte = 2 // Q: or maybe a higher number like 7, to have more space for potential specific perfixes +) + +// schema is used to serialize known database structure information. +type schema struct { + Fields map[string]fieldSpec `json:"fields"` // keys are field names + Indexes map[byte]indexSpec `json:"indexes"` // keys are index prefix bytes +} + +// fieldSpec holds information about a particular field. +// It does not need Name field as it is contained in the +// schema.Field map key. +type fieldSpec struct { + Type string `json:"type"` +} + +// indxSpec holds information about a particular index. +// It does not contain index type, as indexes do not have type. +type indexSpec struct { + Name string `json:"name"` +} + +// schemaFieldKey retrives the complete LevelDB key for +// a particular field form the schema definition. +func (db *DB) schemaFieldKey(name, fieldType string) (key []byte, err error) { + if name == "" { + return nil, errors.New("field name can not be blank") + } + if fieldType == "" { + return nil, errors.New("field type can not be blank") + } + s, err := db.getSchema() + if err != nil { + return nil, err + } + var found bool + for n, f := range s.Fields { + if n == name { + if f.Type != fieldType { + return nil, fmt.Errorf("field %q of type %q stored as %q in db", name, fieldType, f.Type) + } + break + } + } + if !found { + s.Fields[name] = fieldSpec{ + Type: fieldType, + } + err := db.putSchema(s) + if err != nil { + return nil, err + } + } + return append([]byte{keyPrefixFields}, []byte(name)...), nil +} + +// schemaIndexID retrieves the complete LevelDB prefix for +// a particular index. +func (db *DB) schemaIndexPrefix(name string) (id byte, err error) { + if name == "" { + return 0, errors.New("index name can not be blank") + } + s, err := db.getSchema() + if err != nil { + return 0, err + } + nextID := keyPrefixIndexStart + for i, f := range s.Indexes { + if i >= nextID { + nextID = i + 1 + } + if f.Name == name { + return i, nil + } + } + id = nextID + s.Indexes[id] = indexSpec{ + Name: name, + } + return id, db.putSchema(s) +} + +// getSchema retrieves the complete schema from +// the database. +func (db *DB) getSchema() (s schema, err error) { + b, err := db.Get(keySchema) + if err != nil { + return s, err + } + err = json.Unmarshal(b, &s) + return s, err +} + +// putSchema stores the complete schema to +// the database. +func (db *DB) putSchema(s schema) (err error) { + b, err := json.Marshal(s) + if err != nil { + return err + } + return db.Put(keySchema, b) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/schema_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/schema_test.go new file mode 100644 index 00000000..a0c1838c --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/schema_test.go @@ -0,0 +1,126 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "bytes" + "testing" +) + +// TestDB_schemaFieldKey validates correctness of schemaFieldKey. +func TestDB_schemaFieldKey(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + t.Run("empty name or type", func(t *testing.T) { + _, err := db.schemaFieldKey("", "") + if err == nil { + t.Errorf("error not returned, but expected") + } + _, err = db.schemaFieldKey("", "type") + if err == nil { + t.Errorf("error not returned, but expected") + } + + _, err = db.schemaFieldKey("test", "") + if err == nil { + t.Errorf("error not returned, but expected") + } + }) + + t.Run("same field", func(t *testing.T) { + key1, err := db.schemaFieldKey("test", "undefined") + if err != nil { + t.Fatal(err) + } + + key2, err := db.schemaFieldKey("test", "undefined") + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(key1, key2) { + t.Errorf("schema keys for the same field name are not the same: %q, %q", string(key1), string(key2)) + } + }) + + t.Run("different fields", func(t *testing.T) { + key1, err := db.schemaFieldKey("test1", "undefined") + if err != nil { + t.Fatal(err) + } + + key2, err := db.schemaFieldKey("test2", "undefined") + if err != nil { + t.Fatal(err) + } + + if bytes.Equal(key1, key2) { + t.Error("schema keys for the same field name are the same, but must not be") + } + }) + + t.Run("same field name different types", func(t *testing.T) { + _, err := db.schemaFieldKey("the-field", "one-type") + if err != nil { + t.Fatal(err) + } + + _, err = db.schemaFieldKey("the-field", "another-type") + if err == nil { + t.Errorf("error not returned, but expected") + } + }) +} + +// TestDB_schemaIndexPrefix validates correctness of schemaIndexPrefix. +func TestDB_schemaIndexPrefix(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + t.Run("same name", func(t *testing.T) { + id1, err := db.schemaIndexPrefix("test") + if err != nil { + t.Fatal(err) + } + + id2, err := db.schemaIndexPrefix("test") + if err != nil { + t.Fatal(err) + } + + if id1 != id2 { + t.Errorf("schema keys for the same field name are not the same: %v, %v", id1, id2) + } + }) + + t.Run("different names", func(t *testing.T) { + id1, err := db.schemaIndexPrefix("test1") + if err != nil { + t.Fatal(err) + } + + id2, err := db.schemaIndexPrefix("test2") + if err != nil { + t.Fatal(err) + } + + if id1 == id2 { + t.Error("schema ids for the same index name are the same, but must not be") + } + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/vector_uint64.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/vector_uint64.go new file mode 100644 index 00000000..0926e64f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/vector_uint64.go @@ -0,0 +1,146 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "encoding/binary" + + "github.com/syndtr/goleveldb/leveldb" +) + +// Uint64Vector provides a way to have multiple counters in the database. +// It transparently encodes uint64 type value to bytes. +type Uint64Vector struct { + db *DB + key []byte +} + +// NewUint64Vector returns a new Uint64Vector. +// It validates its name and type against the database schema. +func (db *DB) NewUint64Vector(name string) (f Uint64Vector, err error) { + key, err := db.schemaFieldKey(name, "vector-uint64") + if err != nil { + return f, err + } + return Uint64Vector{ + db: db, + key: key, + }, nil +} + +// Get retrieves a uint64 value at index i from the database. +// If the value is not found in the database a 0 value +// is returned and no error. +func (f Uint64Vector) Get(i uint64) (val uint64, err error) { + b, err := f.db.Get(f.indexKey(i)) + if err != nil { + if err == leveldb.ErrNotFound { + return 0, nil + } + return 0, err + } + return binary.BigEndian.Uint64(b), nil +} + +// Put encodes uin64 value and stores it in the database. +func (f Uint64Vector) Put(i, val uint64) (err error) { + return f.db.Put(f.indexKey(i), encodeUint64(val)) +} + +// PutInBatch stores a uint64 value at index i in a batch +// that can be saved later in the database. +func (f Uint64Vector) PutInBatch(batch *leveldb.Batch, i, val uint64) { + batch.Put(f.indexKey(i), encodeUint64(val)) +} + +// Inc increments a uint64 value in the database. +// This operation is not goroutine safe. +func (f Uint64Vector) Inc(i uint64) (val uint64, err error) { + val, err = f.Get(i) + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + val++ + return val, f.Put(i, val) +} + +// IncInBatch increments a uint64 value at index i in the batch +// by retreiving a value from the database, not the same batch. +// This operation is not goroutine safe. +func (f Uint64Vector) IncInBatch(batch *leveldb.Batch, i uint64) (val uint64, err error) { + val, err = f.Get(i) + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + val++ + f.PutInBatch(batch, i, val) + return val, nil +} + +// Dec decrements a uint64 value at index i in the database. +// This operation is not goroutine safe. +// The field is protected from overflow to a negative value. +func (f Uint64Vector) Dec(i uint64) (val uint64, err error) { + val, err = f.Get(i) + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + if val != 0 { + val-- + } + return val, f.Put(i, val) +} + +// DecInBatch decrements a uint64 value at index i in the batch +// by retreiving a value from the database, not the same batch. +// This operation is not goroutine safe. +// The field is protected from overflow to a negative value. +func (f Uint64Vector) DecInBatch(batch *leveldb.Batch, i uint64) (val uint64, err error) { + val, err = f.Get(i) + if err != nil { + if err == leveldb.ErrNotFound { + val = 0 + } else { + return 0, err + } + } + if val != 0 { + val-- + } + f.PutInBatch(batch, i, val) + return val, nil +} + +// indexKey concatenates field prefix and vector index +// returning a unique database key for a specific vector element. +func (f Uint64Vector) indexKey(i uint64) (key []byte) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, i) + return append(f.key, b...) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/shed/vector_uint64_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/shed/vector_uint64_test.go new file mode 100644 index 00000000..75aed7d1 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/shed/vector_uint64_test.go @@ -0,0 +1,312 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package shed + +import ( + "testing" + + "github.com/syndtr/goleveldb/leveldb" +) + +// TestUint64Vector validates put and get operations +// of the Uint64Vector. +func TestUint64Vector(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + bins, err := db.NewUint64Vector("bins") + if err != nil { + t.Fatal(err) + } + + t.Run("get empty", func(t *testing.T) { + got, err := bins.Get(0) + if err != nil { + t.Fatal(err) + } + var want uint64 + if got != want { + t.Errorf("got uint64 %v, want %v", got, want) + } + }) + + t.Run("put", func(t *testing.T) { + for _, index := range []uint64{0, 1, 2, 5, 100} { + var want uint64 = 42 + index + err = bins.Put(index, want) + if err != nil { + t.Fatal(err) + } + got, err := bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + t.Run("overwrite", func(t *testing.T) { + var want uint64 = 84 + index + err = bins.Put(index, want) + if err != nil { + t.Fatal(err) + } + got, err := bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + }) + } + }) + + t.Run("put in batch", func(t *testing.T) { + for _, index := range []uint64{0, 1, 2, 3, 5, 10} { + batch := new(leveldb.Batch) + var want uint64 = 43 + index + bins.PutInBatch(batch, index, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + t.Run("overwrite", func(t *testing.T) { + batch := new(leveldb.Batch) + var want uint64 = 85 + index + bins.PutInBatch(batch, index, want) + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err := bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + }) + } + }) +} + +// TestUint64Vector_Inc validates Inc operation +// of the Uint64Vector. +func TestUint64Vector_Inc(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + bins, err := db.NewUint64Vector("bins") + if err != nil { + t.Fatal(err) + } + + for _, index := range []uint64{0, 1, 2, 3, 5, 10} { + var want uint64 = 1 + got, err := bins.Inc(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + want = 2 + got, err = bins.Inc(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + } +} + +// TestUint64Vector_IncInBatch validates IncInBatch operation +// of the Uint64Vector. +func TestUint64Vector_IncInBatch(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + bins, err := db.NewUint64Vector("bins") + if err != nil { + t.Fatal(err) + } + + for _, index := range []uint64{0, 1, 2, 3, 5, 10} { + batch := new(leveldb.Batch) + var want uint64 = 1 + got, err := bins.IncInBatch(batch, index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err = bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + batch2 := new(leveldb.Batch) + want = 2 + got, err = bins.IncInBatch(batch2, index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + err = db.WriteBatch(batch2) + if err != nil { + t.Fatal(err) + } + got, err = bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + } +} + +// TestUint64Vector_Dec validates Dec operation +// of the Uint64Vector. +func TestUint64Vector_Dec(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + bins, err := db.NewUint64Vector("bins") + if err != nil { + t.Fatal(err) + } + + for _, index := range []uint64{0, 1, 2, 3, 5, 10} { + // test overflow protection + var want uint64 + got, err := bins.Dec(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + want = 32 + index + err = bins.Put(index, want) + if err != nil { + t.Fatal(err) + } + + want = 31 + index + got, err = bins.Dec(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + } +} + +// TestUint64Vector_DecInBatch validates DecInBatch operation +// of the Uint64Vector. +func TestUint64Vector_DecInBatch(t *testing.T) { + db, cleanupFunc := newTestDB(t) + defer cleanupFunc() + + bins, err := db.NewUint64Vector("bins") + if err != nil { + t.Fatal(err) + } + + for _, index := range []uint64{0, 1, 2, 3, 5, 10} { + batch := new(leveldb.Batch) + var want uint64 + got, err := bins.DecInBatch(batch, index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + err = db.WriteBatch(batch) + if err != nil { + t.Fatal(err) + } + got, err = bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + batch2 := new(leveldb.Batch) + want = 42 + index + bins.PutInBatch(batch2, index, want) + err = db.WriteBatch(batch2) + if err != nil { + t.Fatal(err) + } + got, err = bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + + batch3 := new(leveldb.Batch) + want = 41 + index + got, err = bins.DecInBatch(batch3, index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + err = db.WriteBatch(batch3) + if err != nil { + t.Fatal(err) + } + got, err = bins.Get(index) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got %v uint64 %v, want %v", index, got, want) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/state/dbstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/state/dbstore.go index b0aa92e2..1b541e78 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/state/dbstore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/state/dbstore.go @@ -22,13 +22,20 @@ import ( "errors" "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/storage" ) // ErrNotFound is returned when no results are returned from the database var ErrNotFound = errors.New("ErrorNotFound") -// ErrInvalidArgument is returned when the argument type does not match the expected type -var ErrInvalidArgument = errors.New("ErrorInvalidArgument") +// Store defines methods required to get, set, delete values for different keys +// and close the underlying resources. +type Store interface { + Get(key string, i interface{}) (err error) + Put(key string, i interface{}) (err error) + Delete(key string) (err error) + Close() error +} // DBStore uses LevelDB to store values. type DBStore struct { @@ -46,6 +53,17 @@ func NewDBStore(path string) (s *DBStore, err error) { }, nil } +// NewInmemoryStore returns a new instance of DBStore. To be used only in tests and simulations. +func NewInmemoryStore() *DBStore { + db, err := leveldb.Open(storage.NewMemStorage(), nil) + if err != nil { + panic(err) + } + return &DBStore{ + db: db, + } +} + // Get retrieves a persisted value for a specific key. If there is no results // ErrNotFound is returned. The provided parameter should be either a byte slice or // a struct that implements the encoding.BinaryUnmarshaler interface @@ -70,18 +88,15 @@ func (s *DBStore) Get(key string, i interface{}) (err error) { // Put stores an object that implements Binary for a specific key. func (s *DBStore) Put(key string, i interface{}) (err error) { var bytes []byte - - marshaler, ok := i.(encoding.BinaryMarshaler) - if !ok { - if bytes, err = json.Marshal(i); err != nil { - return err - } - } else { + if marshaler, ok := i.(encoding.BinaryMarshaler); ok { if bytes, err = marshaler.MarshalBinary(); err != nil { return err } + } else { + if bytes, err = json.Marshal(i); err != nil { + return err + } } - return s.db.Put([]byte(key), bytes, nil) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/state/inmemorystore.go b/vendor/github.com/ethereum/go-ethereum/swarm/state/inmemorystore.go deleted file mode 100644 index 3ba48592..00000000 --- a/vendor/github.com/ethereum/go-ethereum/swarm/state/inmemorystore.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package state - -import ( - "encoding" - "encoding/json" - "sync" -) - -// InmemoryStore is the reference implementation of Store interface that is supposed -// to be used in tests. -type InmemoryStore struct { - db map[string][]byte - mu sync.RWMutex -} - -// NewInmemoryStore returns a new instance of InmemoryStore. -func NewInmemoryStore() *InmemoryStore { - return &InmemoryStore{ - db: make(map[string][]byte), - } -} - -// Get retrieves a value stored for a specific key. If there is no value found, -// ErrNotFound is returned. -func (s *InmemoryStore) Get(key string, i interface{}) (err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - bytes, ok := s.db[key] - if !ok { - return ErrNotFound - } - - unmarshaler, ok := i.(encoding.BinaryUnmarshaler) - if !ok { - return json.Unmarshal(bytes, i) - } - - return unmarshaler.UnmarshalBinary(bytes) -} - -// Put stores a value for a specific key. -func (s *InmemoryStore) Put(key string, i interface{}) (err error) { - s.mu.Lock() - defer s.mu.Unlock() - var bytes []byte - - marshaler, ok := i.(encoding.BinaryMarshaler) - if !ok { - if bytes, err = json.Marshal(i); err != nil { - return err - } - } else { - if bytes, err = marshaler.MarshalBinary(); err != nil { - return err - } - } - - s.db[key] = bytes - return nil -} - -// Delete removes value stored under a specific key. -func (s *InmemoryStore) Delete(key string) (err error) { - s.mu.Lock() - defer s.mu.Unlock() - - if _, ok := s.db[key]; !ok { - return ErrNotFound - } - delete(s.db, key) - return nil -} - -// Close does not do anything. -func (s *InmemoryStore) Close() error { - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker.go index 40292e88..b2f0f563 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker.go @@ -22,9 +22,10 @@ import ( "fmt" "io" "sync" + "time" "github.com/ethereum/go-ethereum/metrics" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/spancontext" opentracing "github.com/opentracing/opentracing-go" @@ -64,10 +65,6 @@ If all is well it is possible to implement this by simply composing readers so t The hashing itself does use extra copies and allocation though, since it does need it. */ -var ( - errAppendOppNotSuported = errors.New("Append operation not supported") -) - type ChunkerParams struct { chunkSize int64 hashSize int64 @@ -98,7 +95,6 @@ type TreeChunker struct { ctx context.Context branches int64 - hashFunc SwarmHasher dataSize int64 data io.Reader // calculated @@ -131,7 +127,7 @@ type TreeChunker struct { func TreeJoin(ctx context.Context, addr Address, getter Getter, depth int) *LazyChunkReader { jp := &JoinerParams{ ChunkerParams: ChunkerParams{ - chunkSize: ch.DefaultSize, + chunkSize: chunk.DefaultSize, hashSize: int64(len(addr)), }, addr: addr, @@ -151,7 +147,7 @@ func TreeSplit(ctx context.Context, data io.Reader, size int64, putter Putter) ( tsp := &TreeSplitterParams{ SplitterParams: SplitterParams{ ChunkerParams: ChunkerParams{ - chunkSize: ch.DefaultSize, + chunkSize: chunk.DefaultSize, hashSize: putter.RefSize(), }, reader: data, @@ -364,10 +360,6 @@ func (tc *TreeChunker) runWorker(ctx context.Context) { }() } -func (tc *TreeChunker) Append() (Address, func(), error) { - return nil, nil, errAppendOppNotSuported -} - // LazyChunkReader implements LazySectionReader type LazyChunkReader struct { ctx context.Context @@ -410,18 +402,16 @@ func (r *LazyChunkReader) Size(ctx context.Context, quitC chan bool) (n int64, e log.Debug("lazychunkreader.size", "addr", r.addr) if r.chunkData == nil { + startTime := time.Now() chunkData, err := r.getter.Get(cctx, Reference(r.addr)) if err != nil { + metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime) return 0, err } + metrics.GetOrRegisterResettingTimer("lcr.getter.get", nil).UpdateSince(startTime) r.chunkData = chunkData - s := r.chunkData.Size() - log.Debug("lazychunkreader.size", "key", r.addr, "size", s) - if s < 0 { - return 0, errors.New("corrupt size") - } - return int64(s), nil } + s := r.chunkData.Size() log.Debug("lazychunkreader.size", "key", r.addr, "size", s) @@ -475,7 +465,7 @@ func (r *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { length *= r.chunkSize } wg.Add(1) - go r.join(b, off, off+length, depth, treeSize/r.branches, r.chunkData, &wg, errC, quitC) + go r.join(cctx, b, off, off+length, depth, treeSize/r.branches, r.chunkData, &wg, errC, quitC) go func() { wg.Wait() close(errC) @@ -495,7 +485,7 @@ func (r *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { return len(b), nil } -func (r *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeSize int64, chunkData ChunkData, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) { +func (r *LazyChunkReader) join(ctx context.Context, b []byte, off int64, eoff int64, depth int, treeSize int64, chunkData ChunkData, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) { defer parentWg.Done() // find appropriate block level for chunkData.Size() < uint64(treeSize) && depth > r.depth { @@ -542,15 +532,17 @@ func (r *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeS wg.Add(1) go func(j int64) { childAddress := chunkData[8+j*r.hashSize : 8+(j+1)*r.hashSize] - chunkData, err := r.getter.Get(r.ctx, Reference(childAddress)) + startTime := time.Now() + chunkData, err := r.getter.Get(ctx, Reference(childAddress)) if err != nil { - log.Debug("lazychunkreader.join", "key", fmt.Sprintf("%x", childAddress), "err", err) + metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime) select { case errC <- fmt.Errorf("chunk %v-%v not found; key: %s", off, off+treeSize, fmt.Sprintf("%x", childAddress)): case <-quitC: } return } + metrics.GetOrRegisterResettingTimer("lcr.getter.get", nil).UpdateSince(startTime) if l := len(chunkData); l < 9 { select { case errC <- fmt.Errorf("chunk %v-%v incomplete; key: %s, data length %v", off, off+treeSize, fmt.Sprintf("%x", childAddress), l): @@ -561,19 +553,19 @@ func (r *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeS if soff < off { soff = off } - r.join(b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/r.branches, chunkData, wg, errC, quitC) + r.join(ctx, b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/r.branches, chunkData, wg, errC, quitC) }(i) } //for } // Read keeps a cursor so cannot be called simulateously, see ReadAt func (r *LazyChunkReader) Read(b []byte) (read int, err error) { - log.Debug("lazychunkreader.read", "key", r.addr) + log.Trace("lazychunkreader.read", "key", r.addr) metrics.GetOrRegisterCounter("lazychunkreader.read", nil).Inc(1) read, err = r.ReadAt(b, r.off) if err != nil && err != io.EOF { - log.Debug("lazychunkreader.readat", "read", read, "err", err) + log.Trace("lazychunkreader.readat", "read", read, "err", err) metrics.GetOrRegisterCounter("lazychunkreader.read.err", nil).Inc(1) } @@ -588,6 +580,11 @@ var errWhence = errors.New("Seek: invalid whence") var errOffset = errors.New("Seek: invalid offset") func (r *LazyChunkReader) Seek(offset int64, whence int) (int64, error) { + cctx, sp := spancontext.StartSpan( + r.ctx, + "lcr.seek") + defer sp.Finish() + log.Debug("lazychunkreader.seek", "key", r.addr, "offset", offset) switch whence { default: @@ -597,8 +594,9 @@ func (r *LazyChunkReader) Seek(offset int64, whence int) (int64, error) { case 1: offset += r.off case 2: + if r.chunkData == nil { //seek from the end requires rootchunk for size. call Size first - _, err := r.Size(context.TODO(), nil) + _, err := r.Size(cctx, nil) if err != nil { return 0, fmt.Errorf("can't get size: %v", err) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker_test.go index 1f847edc..9a125944 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/chunker_test.go @@ -24,8 +24,8 @@ import ( "io" "testing" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/crypto/sha3" ) /* @@ -142,7 +142,7 @@ func TestSha3ForCorrectness(t *testing.T) { io.LimitReader(bytes.NewReader(input[8:]), int64(size)) - rawSha3 := sha3.NewKeccak256() + rawSha3 := sha3.NewLegacyKeccak256() rawSha3.Reset() rawSha3.Write(input) rawSha3Output := rawSha3.Sum(nil) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/common_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/common_test.go index af104a5a..c4d187b6 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/common_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/common_test.go @@ -29,7 +29,7 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" "github.com/mattn/go-colorable" ) @@ -83,7 +83,7 @@ func newLDBStore(t *testing.T) (*LDBStore, func()) { return db, cleanup } -func mputRandomChunks(store ChunkStore, n int, chunksize int64) ([]Chunk, error) { +func mputRandomChunks(store ChunkStore, n int) ([]Chunk, error) { return mput(store, n, GenerateRandomChunk) } @@ -91,10 +91,10 @@ func mput(store ChunkStore, n int, f func(i int64) Chunk) (hs []Chunk, err error // put to localstore and wait for stored channel // does not check delivery error state errc := make(chan error) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) defer cancel() for i := int64(0); i < int64(n); i++ { - chunk := f(ch.DefaultSize) + chunk := f(chunk.DefaultSize) go func() { select { case errc <- store.Put(ctx, chunk): @@ -142,10 +142,11 @@ func mget(store ChunkStore, hs []Address, f func(h Address, chunk Chunk) error) close(errc) }() var err error + timeout := 20 * time.Second select { case err = <-errc: - case <-time.NewTimer(5 * time.Second).C: - err = fmt.Errorf("timed out after 5 seconds") + case <-time.NewTimer(timeout).C: + err = fmt.Errorf("timed out after %v", timeout) } return err } @@ -158,8 +159,8 @@ func (r *brokenLimitedReader) Read(buf []byte) (int, error) { return r.lr.Read(buf) } -func testStoreRandom(m ChunkStore, n int, chunksize int64, t *testing.T) { - chunks, err := mputRandomChunks(m, n, chunksize) +func testStoreRandom(m ChunkStore, n int, t *testing.T) { + chunks, err := mputRandomChunks(m, n) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -169,8 +170,8 @@ func testStoreRandom(m ChunkStore, n int, chunksize int64, t *testing.T) { } } -func testStoreCorrect(m ChunkStore, n int, chunksize int64, t *testing.T) { - chunks, err := mputRandomChunks(m, n, chunksize) +func testStoreCorrect(m ChunkStore, n int, t *testing.T) { + chunks, err := mputRandomChunks(m, n) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -179,8 +180,9 @@ func testStoreCorrect(m ChunkStore, n int, chunksize int64, t *testing.T) { return fmt.Errorf("key does not match retrieved chunk Address") } hasher := MakeHashFunc(DefaultHash)() - hasher.ResetWithLength(chunk.SpanBytes()) - hasher.Write(chunk.Payload()) + data := chunk.Data() + hasher.ResetWithLength(data[:8]) + hasher.Write(data[8:]) exp := hasher.Sum(nil) if !bytes.Equal(h, exp) { return fmt.Errorf("key is not hash of chunk data") @@ -193,7 +195,7 @@ func testStoreCorrect(m ChunkStore, n int, chunksize int64, t *testing.T) { } } -func benchmarkStorePut(store ChunkStore, n int, chunksize int64, b *testing.B) { +func benchmarkStorePut(store ChunkStore, n int, b *testing.B) { chunks := make([]Chunk, n) i := 0 f := func(dataSize int64) Chunk { @@ -220,8 +222,8 @@ func benchmarkStorePut(store ChunkStore, n int, chunksize int64, b *testing.B) { } } -func benchmarkStoreGet(store ChunkStore, n int, chunksize int64, b *testing.B) { - chunks, err := mputRandomChunks(store, n, chunksize) +func benchmarkStoreGet(store ChunkStore, n int, b *testing.B) { + chunks, err := mputRandomChunks(store, n) if err != nil { b.Fatalf("expected no error, got %v", err) } @@ -265,6 +267,15 @@ func (m *MapChunkStore) Get(_ context.Context, ref Address) (Chunk, error) { return chunk, nil } +// Need to implement Has from SyncChunkStore +func (m *MapChunkStore) Has(ctx context.Context, ref Address) bool { + m.mu.RLock() + defer m.mu.RUnlock() + + _, has := m.chunks[ref.Hex()] + return has +} + func (m *MapChunkStore) Close() { } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/database.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/database.go index e25fce31..12367b90 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/database.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/database.go @@ -64,16 +64,6 @@ func (db *LDBDatabase) Delete(key []byte) error { return db.db.Delete(key, nil) } -func (db *LDBDatabase) LastKnownTD() []byte { - data, _ := db.Get([]byte("LTD")) - - if len(data) == 0 { - data = []byte{0x0} - } - - return data -} - func (db *LDBDatabase) NewIterator() iterator.Iterator { metrics.GetOrRegisterCounter("ldbdatabase.newiterator", nil).Inc(1) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/encryption/encryption_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/encryption/encryption_test.go index 0c0d0508..3b4f8a4e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/encryption/encryption_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/encryption/encryption_test.go @@ -22,13 +22,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/crypto/sha3" ) var expectedTransformedHex = "352187af3a843decc63ceca6cb01ea39dbcf77caf0a8f705f5c30d557044ceec9392b94a79376f1e5c10cd0c0f2a98e5353bf22b3ea4fdac6677ee553dec192e3db64e179d0474e96088fb4abd2babd67de123fb398bdf84d818f7bda2c1ab60b3ea0e0569ae54aa969658eb4844e6960d2ff44d7c087ee3aaffa1c0ee5df7e50b615f7ad90190f022934ad5300c7d1809bfe71a11cc04cece5274eb97a5f20350630522c1dbb7cebaf4f97f84e03f5cfd88f2b48880b25d12f4d5e75c150f704ef6b46c72e07db2b705ac3644569dccd22fd8f964f6ef787fda63c46759af334e6f665f70eac775a7017acea49f3c7696151cb1b9434fa4ac27fb803921ffb5ec58dafa168098d7d5b97e384be3384cf5bc235c3d887fef89fe76c0065f9b8d6ad837b442340d9e797b46ef5709ea3358bc415df11e4830de986ef0f1c418ffdcc80e9a3cda9bea0ab5676c0d4240465c43ba527e3b4ea50b4f6255b510e5d25774a75449b0bd71e56c537ade4fcf0f4d63c99ae1dbb5a844971e2c19941b8facfcfc8ee3056e7cb3c7114c5357e845b52f7103cb6e00d2308c37b12baa5b769e1cc7b00fc06f2d16e70cc27a82cb9c1a4e40cb0d43907f73df2c9db44f1b51a6b0bc6d09f77ac3be14041fae3f9df2da42df43ae110904f9ecee278030185254d7c6e918a5512024d047f77a992088cb3190a6587aa54d0c7231c1cd2e455e0d4c07f74bece68e29cd8ba0190c0bcfb26d24634af5d91a81ef5d4dd3d614836ce942ddbf7bb1399317f4c03faa675f325f18324bf9433844bfe5c4cc04130c8d5c329562b7cd66e72f7355de8f5375a72202971613c32bd7f3fcdcd51080758cd1d0a46dbe8f0374381dbc359f5864250c63dde8131cbd7c98ae2b0147d6ea4bf65d1443d511b18e6d608bbb46ac036353b4c51df306a10a6f6939c38629a5c18aaf89cac04bd3ad5156e6b92011c88341cb08551bab0a89e6a46538f5af33b86121dba17e3a434c273f385cd2e8cb90bdd32747d8425d929ccbd9b0815c73325988855549a8489dfd047daf777aaa3099e54cf997175a5d9e1edfe363e3b68c70e02f6bf4fcde6a0f3f7d0e7e98bde1a72ae8b6cd27b32990680cc4a04fc467f41c5adcaddabfc71928a3f6872c360c1d765260690dd28b269864c8e380d9c92ef6b89b0094c8f9bb22608b4156381b19b920e9583c9616ce5693b4d2a6c689f02e6a91584a8e501e107403d2689dd0045269dd9946c0e969fb656a3b39d84a798831f5f9290f163eb2f97d3ae25071324e95e2256d9c1e56eb83c26397855323edc202d56ad05894333b7f0ed3c1e4734782eb8bd5477242fd80d7a89b12866f85cfae476322f032465d6b1253993033fccd4723530630ab97a1566460af9c90c9da843c229406e65f3fa578bd6bf04dee9b6153807ddadb8ceefc5c601a8ab26023c67b1ab1e8e0f29ce94c78c308005a781853e7a2e0e51738939a657c987b5e611f32f47b5ff461c52e63e0ea390515a8e1f5393dae54ea526934b5f310b76e3fa050e40718cb4c8a20e58946d6ee1879f08c52764422fe542b3240e75eccb7aa75b1f8a651e37a3bc56b0932cdae0e985948468db1f98eb4b77b82081ea25d8a762db00f7898864984bd80e2f3f35f236bf57291dec28f550769943bcfb6f884b7687589b673642ef7fe5d7d5a87d3eca5017f83ccb9a3310520474479464cb3f433440e7e2f1e28c0aef700a45848573409e7ab66e0cfd4fe5d2147ace81bc65fd8891f6245cd69246bbf5c27830e5ab882dd1d02aba34ff6ca9af88df00fd602892f02fedbdc65dedec203faf3f8ff4a97314e0ddb58b9ab756a61a562597f4088b445fcc3b28a708ca7b1485dcd791b779fbf2b3ef1ec5c6205f595fbe45a02105034147e5a146089c200a49dae33ae051a08ea5f974a21540aaeffa7f9d9e3d35478016fb27b871036eb27217a5b834b461f535752fb5f1c8dded3ae14ce3a2ef6639e2fe41939e3509e46e347a95d50b2080f1ba42c804b290ddc912c952d1cec3f2661369f738feacc0dbf1ea27429c644e45f9e26f30c341acd34c7519b2a1663e334621691e810767e9918c2c547b2e23cce915f97d26aac8d0d2fcd3edb7986ad4e2b8a852edebad534cb6c0e9f0797d3563e5409d7e068e48356c67ce519246cd9c560e881453df97cbba562018811e6cf8c327f399d1d1253ab47a19f4a0ccc7c6d86a9603e0551da310ea595d71305c4aad96819120a92cdbaf1f77ec8df9cc7c838c0d4de1e8692dd81da38268d1d71324bcffdafbe5122e4b81828e021e936d83ae8021eac592aa52cd296b5ce392c7173d622f8e07d18f59bb1b08ba15211af6703463b09b593af3c37735296816d9f2e7a369354a5374ea3955e14ca8ac56d5bfe4aef7a21bd825d6ae85530bee5d2aaaa4914981b3dfdb2e92ec2a27c83d74b59e84ff5c056f7d8945745f2efc3dcf28f288c6cd8383700fb2312f7001f24dd40015e436ae23e052fe9070ea9535b9c989898a9bda3d5382cf10e432fae6ccf0c825b3e6436edd3a9f8846e5606f8563931b5f29ba407c5236e5730225dda211a8504ec1817bc935e1fd9a532b648c502df302ed2063aed008fd5676131ac9e95998e9447b02bd29d77e38fcfd2959f2de929b31970335eb2a74348cc6918bc35b9bf749eab0fe304c946cd9e1ca284e6853c42646e60b6b39e0d3fb3c260abfc5c1b4ca3c3770f344118ca7c7f5c1ad1f123f8f369cd60afc3cdb3e9e81968c5c9fa7c8b014ffe0508dd4f0a2a976d5d1ca8fc9ad7a237d92cfe7b41413d934d6e142824b252699397e48e4bac4e91ebc10602720684bd0863773c548f9a2f9724245e47b129ecf65afd7252aac48c8a8d6fd3d888af592a01fb02dc71ed7538a700d3d16243e4621e0fcf9f8ed2b4e11c9fa9a95338bb1dac74a7d9bc4eb8cbf900b634a2a56469c00f5994e4f0934bdb947640e6d67e47d0b621aacd632bfd3c800bd7d93bd329f494a90e06ed51535831bd6e07ac1b4b11434ef3918fa9511813a002913f33f836454798b8d1787fea9a4c4743ba091ed192ed92f4d33e43a226bf9503e1a83a16dd340b3cbbf38af6db0d99201da8de529b4225f3d2fa2aad6621afc6c79ef3537720591edfc681ae6d00ede53ed724fc71b23b90d2e9b7158aaee98d626a4fe029107df2cb5f90147e07ebe423b1519d848af18af365c71bfd0665db46be493bbe99b79a188de0cf3594aef2299f0324075bdce9eb0b87bc29d62401ba4fd6ae48b1ba33261b5b845279becf38ee03e3dc5c45303321c5fac96fd02a3ad8c9e3b02127b320501333c9e6360440d1ad5e64a6239501502dde1a49c9abe33b66098458eee3d611bb06ffcd234a1b9aef4af5021cd61f0de6789f822ee116b5078aae8c129e8391d8987500d322b58edd1595dc570b57341f2df221b94a96ab7fbcf32a8ca9684196455694024623d7ed49f7d66e8dd453c0bae50e0d8b34377b22d0ece059e2c385dfc70b9089fcd27577c51f4d870b5738ee2b68c361a67809c105c7848b68860a829f29930857a9f9d40b14fd2384ac43bafdf43c0661103794c4bd07d1cfdd4681b6aeaefad53d4c1473359bcc5a83b09189352e5bb9a7498dd0effb89c35aad26954551f8b0621374b449bf515630bd3974dca982279733470fdd059aa9c3df403d8f22b38c4709c82d8f12b888e22990350490e16179caf406293cc9e65f116bafcbe96af132f679877061107a2f690a82a8cb46eea57a90abd23798c5937c6fe6b17be3f9bfa01ce117d2c268181b9095bf49f395fea07ca03838de0588c5e2db633e836d64488c1421e653ea52d810d096048c092d0da6e02fa6613890219f51a76148c8588c2487b171a28f17b7a299204874af0131725d793481333be5f08e86ca837a226850b0c1060891603bfecf9e55cddd22c0dbb28d495342d9cc3de8409f72e52a0115141cffe755c74f061c1a770428ccb0ae59536ee6fc074fbfc6cacb51a549d327527e20f8407477e60355863f1153f9ce95641198663c968874e7fdb29407bd771d94fdda8180cbb0358f5874738db705924b8cbe0cd5e1484aeb64542fe8f38667b7c34baf818c63b1e18440e9fba575254d063fd49f24ef26432f4eb323f3836972dca87473e3e9bb26dc3be236c3aae6bc8a6da567442309da0e8450e242fc9db836e2964f2c76a3b80a2c677979882dda7d7ebf62c93664018bcf4ec431fe6b403d49b3b36618b9c07c2d0d4569cb8d52223903debc72ec113955b206c34f1ae5300990ccfc0180f47d91afdb542b6312d12aeff7e19c645dc0b9fe6e3288e9539f6d5870f99882df187bfa6d24d179dfd1dac22212c8b5339f7171a3efc15b760fed8f68538bc5cbd845c2d1ab41f3a6c692820653eaef7930c02fbe6061d93805d73decdbb945572a7c44ed0241982a6e4d2d730898f82b3d9877cb7bca41cc6dcee67aa0c3d6db76f0b0a708ace0031113e48429de5d886c10e9200f68f32263a2fbf44a5992c2459fda7b8796ba796e3a0804fc25992ed2c9a5fe0580a6b809200ecde6caa0364b58be11564dcb9a616766dd7906db5636ee708b0204f38d309466d8d4a162965dd727e29f5a6c133e9b4ed5bafe803e479f9b2a7640c942c4a40b14ac7dc9828546052761a070f6404008f1ec3605836339c3da95a00b4fd81b2cabf88b51d2087d5b83e8c5b69bf96d8c72cbd278dad3bbb42b404b436f84ad688a22948adf60a81090f1e904291503c16e9f54b05fc76c881a5f95f0e732949e95d3f1bae2d3652a14fe0dda2d68879604657171856ef72637def2a96ac47d7b3fe86eb3198f5e0e626f06be86232305f2ae79ffcd2725e48208f9d8d63523f81915acc957563ab627cd6bc68c2a37d59fb0ed77a90aa9d085d6914a8ebada22a2c2d471b5163aeddd799d90fbb10ed6851ace2c4af504b7d572686700a59d6db46d5e42bb83f8e0c0ffe1dfa6582cc0b34c921ff6e85e83188d24906d5c08bb90069639e713051b3102b53e6f703e8210017878add5df68e6f2b108de279c5490e9eef5590185c4a1c744d4e00d244e1245a8805bd30407b1bc488db44870ccfd75a8af104df78efa2fb7ba31f048a263efdb3b63271fff4922bece9a71187108f65744a24f4947dc556b7440cb4fa45d296bb7f724588d1f245125b21ea063500029bd49650237f53899daf1312809552c81c5827341263cc807a29fe84746170cdfa1ff3838399a5645319bcaff674bb70efccdd88b3d3bb2f2d98111413585dc5d5bd5168f43b3f55e58972a5b2b9b3733febf02f931bd436648cb617c3794841aab961fe41277ab07812e1d3bc4ff6f4350a3e615bfba08c3b9480ef57904d3a16f7e916345202e3f93d11f7a7305170cb8c4eb9ac88ace8bbd1f377bdd5855d3162d6723d4435e84ce529b8f276a8927915ac759a0d04e5ca4a9d3da6291f0333b475df527e99fe38f7a4082662e8125936640c26dd1d17cf284ce6e2b17777a05aa0574f7793a6a062cc6f7263f7ab126b4528a17becfdec49ac0f7d8705aa1704af97fb861faa8a466161b2b5c08a5bacc79fe8500b913d65c8d3c52d1fd52d2ab2c9f52196e712455619c1cd3e0f391b274487944240e2ed8858dd0823c801094310024ae3fe4dd1cf5a2b6487b42cc5937bbafb193ee331d87e378258963d49b9da90899bbb4b88e79f78e866b0213f4719f67da7bcc2fce073c01e87c62ea3cdbcd589cfc41281f2f4c757c742d6d1e" -var hashFunc = sha3.NewKeccak256 +var hashFunc = sha3.NewLegacyKeccak256 var testKey Key func init() { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/error.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/error.go index 44261c08..1e412e55 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/error.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/error.go @@ -16,30 +16,21 @@ package storage -import ( - "errors" -) +import "github.com/ethereum/go-ethereum/swarm/chunk" const ( ErrInit = iota ErrNotFound - ErrIO ErrUnauthorized ErrInvalidValue ErrDataOverflow ErrNothingToReturn - ErrCorruptData ErrInvalidSignature ErrNotSynced - ErrPeriodDepth - ErrCnt ) +// Errors are the same as the ones in chunk package for backward compatibility. var ( - ErrChunkNotFound = errors.New("chunk not found") - ErrFetching = errors.New("chunk still fetching") - ErrChunkInvalid = errors.New("invalid chunk") - ErrChunkForward = errors.New("cannot forward") - ErrChunkUnavailable = errors.New("chunk unavailable") - ErrChunkTimeout = errors.New("timeout") + ErrChunkNotFound = chunk.ErrChunkNotFound + ErrChunkInvalid = chunk.ErrChunkNotFound ) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler.go index 9e264028..063d3e92 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler.go @@ -23,7 +23,6 @@ import ( "context" "fmt" "sync" - "time" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" @@ -32,12 +31,10 @@ import ( ) type Handler struct { - chunkStore *storage.NetStore - HashSize int - cache map[uint64]*cacheEntry - cacheLock sync.RWMutex - storeTimeout time.Duration - queryMaxPeriods uint32 + chunkStore *storage.NetStore + HashSize int + cache map[uint64]*cacheEntry + cacheLock sync.RWMutex } // HandlerParams pass parameters to the Handler constructor NewHandler @@ -82,9 +79,8 @@ func (h *Handler) SetStore(store *storage.NetStore) { // Validate is a chunk validation method // If it looks like a feed update, the chunk address is checked against the userAddr of the update's signature // It implements the storage.ChunkValidator interface -func (h *Handler) Validate(chunkAddr storage.Address, data []byte) bool { - dataLength := len(data) - if dataLength < minimumSignedUpdateLength { +func (h *Handler) Validate(chunk storage.Chunk) bool { + if len(chunk.Data()) < minimumSignedUpdateLength { return false } @@ -94,8 +90,8 @@ func (h *Handler) Validate(chunkAddr storage.Address, data []byte) bool { // First, deserialize the chunk var r Request - if err := r.fromChunk(chunkAddr, data); err != nil { - log.Debug("Invalid feed update chunk", "addr", chunkAddr.Hex(), "err", err.Error()) + if err := r.fromChunk(chunk); err != nil { + log.Debug("Invalid feed update chunk", "addr", chunk.Address(), "err", err) return false } @@ -198,7 +194,7 @@ func (h *Handler) Lookup(ctx context.Context, query *Query) (*cacheEntry, error) } var request Request - if err := request.fromChunk(chunk.Address(), chunk.Data()); err != nil { + if err := request.fromChunk(chunk); err != nil { return nil, nil } if request.Time <= timeLimit { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler_test.go index fb2ef3a6..2f8a5245 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/handler_test.go @@ -40,7 +40,6 @@ var ( } cleanF func() subtopicName = "føø.bar" - hashfunc = storage.MakeHashFunc(storage.DefaultHash) ) func init() { @@ -366,7 +365,7 @@ func TestValidator(t *testing.T) { if err != nil { t.Fatal(err) } - if !rh.Validate(chunk.Address(), chunk.Data()) { + if !rh.Validate(chunk) { t.Fatal("Chunk validator fail on update chunk") } @@ -375,7 +374,7 @@ func TestValidator(t *testing.T) { address[0] = 11 address[15] = 99 - if rh.Validate(address, chunk.Data()) { + if rh.Validate(storage.NewChunk(address, chunk.Data())) { t.Fatal("Expected Validate to fail with false chunk address") } } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/lookup/lookup_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/lookup/lookup_test.go index d71e81e9..4652feac 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/lookup/lookup_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/lookup/lookup_test.go @@ -346,7 +346,7 @@ type testG struct { } // test cases -var testGetNextLevelCases []testG = []testG{{e: lookup.Epoch{Time: 989875233, Level: 12}, n: 989875233, x: 11}, {e: lookup.Epoch{Time: 995807650, Level: 18}, n: 995598156, x: 19}, {e: lookup.Epoch{Time: 969167082, Level: 0}, n: 968990357, x: 18}, {e: lookup.Epoch{Time: 993087628, Level: 14}, n: 992987044, x: 20}, {e: lookup.Epoch{Time: 963364631, Level: 20}, n: 963364630, x: 19}, {e: lookup.Epoch{Time: 963497510, Level: 16}, n: 963370732, x: 18}, {e: lookup.Epoch{Time: 955421349, Level: 22}, n: 955421348, x: 21}, {e: lookup.Epoch{Time: 968220379, Level: 15}, n: 968220378, x: 14}, {e: lookup.Epoch{Time: 939129014, Level: 6}, n: 939128771, x: 11}, {e: lookup.Epoch{Time: 907847903, Level: 6}, n: 907791833, x: 18}, {e: lookup.Epoch{Time: 910835564, Level: 15}, n: 910835564, x: 14}, {e: lookup.Epoch{Time: 913578333, Level: 22}, n: 881808431, x: 25}, {e: lookup.Epoch{Time: 895818460, Level: 3}, n: 895818132, x: 9}, {e: lookup.Epoch{Time: 903843025, Level: 24}, n: 895609561, x: 23}, {e: lookup.Epoch{Time: 877889433, Level: 13}, n: 877877093, x: 15}, {e: lookup.Epoch{Time: 901450396, Level: 10}, n: 901450058, x: 9}, {e: lookup.Epoch{Time: 925179910, Level: 3}, n: 925168393, x: 16}, {e: lookup.Epoch{Time: 913485477, Level: 21}, n: 913485476, x: 20}, {e: lookup.Epoch{Time: 924462991, Level: 18}, n: 924462990, x: 17}, {e: lookup.Epoch{Time: 941175128, Level: 13}, n: 941175127, x: 12}, {e: lookup.Epoch{Time: 920126583, Level: 3}, n: 920100782, x: 19}, {e: lookup.Epoch{Time: 932403200, Level: 9}, n: 932279891, x: 17}, {e: lookup.Epoch{Time: 948284931, Level: 2}, n: 948284921, x: 9}, {e: lookup.Epoch{Time: 953540997, Level: 7}, n: 950547986, x: 22}, {e: lookup.Epoch{Time: 926639837, Level: 18}, n: 918608882, x: 24}, {e: lookup.Epoch{Time: 954637598, Level: 1}, n: 954578761, x: 17}, {e: lookup.Epoch{Time: 943482981, Level: 10}, n: 942924151, x: 19}, {e: lookup.Epoch{Time: 963580771, Level: 7}, n: 963580771, x: 6}, {e: lookup.Epoch{Time: 993744930, Level: 7}, n: 993690858, x: 16}, {e: lookup.Epoch{Time: 1018890213, Level: 12}, n: 1018890212, x: 11}, {e: lookup.Epoch{Time: 1030309411, Level: 2}, n: 1030309227, x: 9}, {e: lookup.Epoch{Time: 1063204997, Level: 20}, n: 1063204996, x: 19}, {e: lookup.Epoch{Time: 1094340832, Level: 6}, n: 1094340633, x: 7}, {e: lookup.Epoch{Time: 1077880597, Level: 10}, n: 1075914292, x: 20}, {e: lookup.Epoch{Time: 1051114957, Level: 18}, n: 1051114957, x: 17}, {e: lookup.Epoch{Time: 1045649701, Level: 22}, n: 1045649700, x: 21}, {e: lookup.Epoch{Time: 1066198885, Level: 14}, n: 1066198884, x: 13}, {e: lookup.Epoch{Time: 1053231952, Level: 1}, n: 1053210845, x: 16}, {e: lookup.Epoch{Time: 1068763404, Level: 14}, n: 1068675428, x: 18}, {e: lookup.Epoch{Time: 1039042173, Level: 15}, n: 1038973110, x: 17}, {e: lookup.Epoch{Time: 1050747636, Level: 6}, n: 1050747364, x: 9}, {e: lookup.Epoch{Time: 1030034434, Level: 23}, n: 1030034433, x: 22}, {e: lookup.Epoch{Time: 1003783425, Level: 18}, n: 1003783424, x: 17}, {e: lookup.Epoch{Time: 988163976, Level: 15}, n: 988084064, x: 17}, {e: lookup.Epoch{Time: 1007222377, Level: 15}, n: 1007222377, x: 14}, {e: lookup.Epoch{Time: 1001211375, Level: 13}, n: 1001208178, x: 14}, {e: lookup.Epoch{Time: 997623199, Level: 8}, n: 997623198, x: 7}, {e: lookup.Epoch{Time: 1026283830, Level: 10}, n: 1006681704, x: 24}, {e: lookup.Epoch{Time: 1019421907, Level: 20}, n: 1019421906, x: 19}, {e: lookup.Epoch{Time: 1043154306, Level: 16}, n: 1043108343, x: 16}, {e: lookup.Epoch{Time: 1075643767, Level: 17}, n: 1075325898, x: 18}, {e: lookup.Epoch{Time: 1043726309, Level: 20}, n: 1043726308, x: 19}, {e: lookup.Epoch{Time: 1056415324, Level: 17}, n: 1056415324, x: 16}, {e: lookup.Epoch{Time: 1088650219, Level: 13}, n: 1088650218, x: 12}, {e: lookup.Epoch{Time: 1088551662, Level: 7}, n: 1088543355, x: 13}, {e: lookup.Epoch{Time: 1069667265, Level: 6}, n: 1069667075, x: 7}, {e: lookup.Epoch{Time: 1079145970, Level: 18}, n: 1079145969, x: 17}, {e: lookup.Epoch{Time: 1083338876, Level: 7}, n: 1083338875, x: 6}, {e: lookup.Epoch{Time: 1051581086, Level: 4}, n: 1051568869, x: 14}, {e: lookup.Epoch{Time: 1028430882, Level: 4}, n: 1028430864, x: 5}, {e: lookup.Epoch{Time: 1057356462, Level: 1}, n: 1057356417, x: 5}, {e: lookup.Epoch{Time: 1033104266, Level: 0}, n: 1033097479, x: 13}, {e: lookup.Epoch{Time: 1031391367, Level: 11}, n: 1031387304, x: 14}, {e: lookup.Epoch{Time: 1049781164, Level: 15}, n: 1049781163, x: 14}, {e: lookup.Epoch{Time: 1027271628, Level: 12}, n: 1027271627, x: 11}, {e: lookup.Epoch{Time: 1057270560, Level: 23}, n: 1057270560, x: 22}, {e: lookup.Epoch{Time: 1047501317, Level: 15}, n: 1047501317, x: 14}, {e: lookup.Epoch{Time: 1058349035, Level: 11}, n: 1045175573, x: 24}, {e: lookup.Epoch{Time: 1057396147, Level: 20}, n: 1057396147, x: 19}, {e: lookup.Epoch{Time: 1048906375, Level: 18}, n: 1039616919, x: 25}, {e: lookup.Epoch{Time: 1074294831, Level: 20}, n: 1074294831, x: 19}, {e: lookup.Epoch{Time: 1088946052, Level: 1}, n: 1088917364, x: 14}, {e: lookup.Epoch{Time: 1112337595, Level: 17}, n: 1111008110, x: 22}, {e: lookup.Epoch{Time: 1099990284, Level: 5}, n: 1099968370, x: 15}, {e: lookup.Epoch{Time: 1087036441, Level: 16}, n: 1053967855, x: 25}, {e: lookup.Epoch{Time: 1069225185, Level: 8}, n: 1069224660, x: 10}, {e: lookup.Epoch{Time: 1057505479, Level: 9}, n: 1057505170, x: 14}, {e: lookup.Epoch{Time: 1072381377, Level: 12}, n: 1065950959, x: 22}, {e: lookup.Epoch{Time: 1093887139, Level: 8}, n: 1093863305, x: 14}, {e: lookup.Epoch{Time: 1082366510, Level: 24}, n: 1082366510, x: 23}, {e: lookup.Epoch{Time: 1103231132, Level: 14}, n: 1102292201, x: 22}, {e: lookup.Epoch{Time: 1094502355, Level: 3}, n: 1094324652, x: 18}, {e: lookup.Epoch{Time: 1068488344, Level: 12}, n: 1067577330, x: 19}, {e: lookup.Epoch{Time: 1050278233, Level: 12}, n: 1050278232, x: 11}, {e: lookup.Epoch{Time: 1047660768, Level: 5}, n: 1047652137, x: 17}, {e: lookup.Epoch{Time: 1060116167, Level: 11}, n: 1060114091, x: 12}, {e: lookup.Epoch{Time: 1068149392, Level: 21}, n: 1052074801, x: 24}, {e: lookup.Epoch{Time: 1081934120, Level: 6}, n: 1081933847, x: 8}, {e: lookup.Epoch{Time: 1107943693, Level: 16}, n: 1107096139, x: 25}, {e: lookup.Epoch{Time: 1131571649, Level: 9}, n: 1131570428, x: 11}, {e: lookup.Epoch{Time: 1123139367, Level: 0}, n: 1122912198, x: 20}, {e: lookup.Epoch{Time: 1121144423, Level: 6}, n: 1120568289, x: 20}, {e: lookup.Epoch{Time: 1089932411, Level: 17}, n: 1089932410, x: 16}, {e: lookup.Epoch{Time: 1104899012, Level: 22}, n: 1098978789, x: 22}, {e: lookup.Epoch{Time: 1094588059, Level: 21}, n: 1094588059, x: 20}, {e: lookup.Epoch{Time: 1114987438, Level: 24}, n: 1114987437, x: 23}, {e: lookup.Epoch{Time: 1084186305, Level: 7}, n: 1084186241, x: 6}, {e: lookup.Epoch{Time: 1058827111, Level: 8}, n: 1058826504, x: 9}, {e: lookup.Epoch{Time: 1090679810, Level: 12}, n: 1090616539, x: 17}, {e: lookup.Epoch{Time: 1084299475, Level: 23}, n: 1084299475, x: 22}} +var testGetNextLevelCases = []testG{{e: lookup.Epoch{Time: 989875233, Level: 12}, n: 989875233, x: 11}, {e: lookup.Epoch{Time: 995807650, Level: 18}, n: 995598156, x: 19}, {e: lookup.Epoch{Time: 969167082, Level: 0}, n: 968990357, x: 18}, {e: lookup.Epoch{Time: 993087628, Level: 14}, n: 992987044, x: 20}, {e: lookup.Epoch{Time: 963364631, Level: 20}, n: 963364630, x: 19}, {e: lookup.Epoch{Time: 963497510, Level: 16}, n: 963370732, x: 18}, {e: lookup.Epoch{Time: 955421349, Level: 22}, n: 955421348, x: 21}, {e: lookup.Epoch{Time: 968220379, Level: 15}, n: 968220378, x: 14}, {e: lookup.Epoch{Time: 939129014, Level: 6}, n: 939128771, x: 11}, {e: lookup.Epoch{Time: 907847903, Level: 6}, n: 907791833, x: 18}, {e: lookup.Epoch{Time: 910835564, Level: 15}, n: 910835564, x: 14}, {e: lookup.Epoch{Time: 913578333, Level: 22}, n: 881808431, x: 25}, {e: lookup.Epoch{Time: 895818460, Level: 3}, n: 895818132, x: 9}, {e: lookup.Epoch{Time: 903843025, Level: 24}, n: 895609561, x: 23}, {e: lookup.Epoch{Time: 877889433, Level: 13}, n: 877877093, x: 15}, {e: lookup.Epoch{Time: 901450396, Level: 10}, n: 901450058, x: 9}, {e: lookup.Epoch{Time: 925179910, Level: 3}, n: 925168393, x: 16}, {e: lookup.Epoch{Time: 913485477, Level: 21}, n: 913485476, x: 20}, {e: lookup.Epoch{Time: 924462991, Level: 18}, n: 924462990, x: 17}, {e: lookup.Epoch{Time: 941175128, Level: 13}, n: 941175127, x: 12}, {e: lookup.Epoch{Time: 920126583, Level: 3}, n: 920100782, x: 19}, {e: lookup.Epoch{Time: 932403200, Level: 9}, n: 932279891, x: 17}, {e: lookup.Epoch{Time: 948284931, Level: 2}, n: 948284921, x: 9}, {e: lookup.Epoch{Time: 953540997, Level: 7}, n: 950547986, x: 22}, {e: lookup.Epoch{Time: 926639837, Level: 18}, n: 918608882, x: 24}, {e: lookup.Epoch{Time: 954637598, Level: 1}, n: 954578761, x: 17}, {e: lookup.Epoch{Time: 943482981, Level: 10}, n: 942924151, x: 19}, {e: lookup.Epoch{Time: 963580771, Level: 7}, n: 963580771, x: 6}, {e: lookup.Epoch{Time: 993744930, Level: 7}, n: 993690858, x: 16}, {e: lookup.Epoch{Time: 1018890213, Level: 12}, n: 1018890212, x: 11}, {e: lookup.Epoch{Time: 1030309411, Level: 2}, n: 1030309227, x: 9}, {e: lookup.Epoch{Time: 1063204997, Level: 20}, n: 1063204996, x: 19}, {e: lookup.Epoch{Time: 1094340832, Level: 6}, n: 1094340633, x: 7}, {e: lookup.Epoch{Time: 1077880597, Level: 10}, n: 1075914292, x: 20}, {e: lookup.Epoch{Time: 1051114957, Level: 18}, n: 1051114957, x: 17}, {e: lookup.Epoch{Time: 1045649701, Level: 22}, n: 1045649700, x: 21}, {e: lookup.Epoch{Time: 1066198885, Level: 14}, n: 1066198884, x: 13}, {e: lookup.Epoch{Time: 1053231952, Level: 1}, n: 1053210845, x: 16}, {e: lookup.Epoch{Time: 1068763404, Level: 14}, n: 1068675428, x: 18}, {e: lookup.Epoch{Time: 1039042173, Level: 15}, n: 1038973110, x: 17}, {e: lookup.Epoch{Time: 1050747636, Level: 6}, n: 1050747364, x: 9}, {e: lookup.Epoch{Time: 1030034434, Level: 23}, n: 1030034433, x: 22}, {e: lookup.Epoch{Time: 1003783425, Level: 18}, n: 1003783424, x: 17}, {e: lookup.Epoch{Time: 988163976, Level: 15}, n: 988084064, x: 17}, {e: lookup.Epoch{Time: 1007222377, Level: 15}, n: 1007222377, x: 14}, {e: lookup.Epoch{Time: 1001211375, Level: 13}, n: 1001208178, x: 14}, {e: lookup.Epoch{Time: 997623199, Level: 8}, n: 997623198, x: 7}, {e: lookup.Epoch{Time: 1026283830, Level: 10}, n: 1006681704, x: 24}, {e: lookup.Epoch{Time: 1019421907, Level: 20}, n: 1019421906, x: 19}, {e: lookup.Epoch{Time: 1043154306, Level: 16}, n: 1043108343, x: 16}, {e: lookup.Epoch{Time: 1075643767, Level: 17}, n: 1075325898, x: 18}, {e: lookup.Epoch{Time: 1043726309, Level: 20}, n: 1043726308, x: 19}, {e: lookup.Epoch{Time: 1056415324, Level: 17}, n: 1056415324, x: 16}, {e: lookup.Epoch{Time: 1088650219, Level: 13}, n: 1088650218, x: 12}, {e: lookup.Epoch{Time: 1088551662, Level: 7}, n: 1088543355, x: 13}, {e: lookup.Epoch{Time: 1069667265, Level: 6}, n: 1069667075, x: 7}, {e: lookup.Epoch{Time: 1079145970, Level: 18}, n: 1079145969, x: 17}, {e: lookup.Epoch{Time: 1083338876, Level: 7}, n: 1083338875, x: 6}, {e: lookup.Epoch{Time: 1051581086, Level: 4}, n: 1051568869, x: 14}, {e: lookup.Epoch{Time: 1028430882, Level: 4}, n: 1028430864, x: 5}, {e: lookup.Epoch{Time: 1057356462, Level: 1}, n: 1057356417, x: 5}, {e: lookup.Epoch{Time: 1033104266, Level: 0}, n: 1033097479, x: 13}, {e: lookup.Epoch{Time: 1031391367, Level: 11}, n: 1031387304, x: 14}, {e: lookup.Epoch{Time: 1049781164, Level: 15}, n: 1049781163, x: 14}, {e: lookup.Epoch{Time: 1027271628, Level: 12}, n: 1027271627, x: 11}, {e: lookup.Epoch{Time: 1057270560, Level: 23}, n: 1057270560, x: 22}, {e: lookup.Epoch{Time: 1047501317, Level: 15}, n: 1047501317, x: 14}, {e: lookup.Epoch{Time: 1058349035, Level: 11}, n: 1045175573, x: 24}, {e: lookup.Epoch{Time: 1057396147, Level: 20}, n: 1057396147, x: 19}, {e: lookup.Epoch{Time: 1048906375, Level: 18}, n: 1039616919, x: 25}, {e: lookup.Epoch{Time: 1074294831, Level: 20}, n: 1074294831, x: 19}, {e: lookup.Epoch{Time: 1088946052, Level: 1}, n: 1088917364, x: 14}, {e: lookup.Epoch{Time: 1112337595, Level: 17}, n: 1111008110, x: 22}, {e: lookup.Epoch{Time: 1099990284, Level: 5}, n: 1099968370, x: 15}, {e: lookup.Epoch{Time: 1087036441, Level: 16}, n: 1053967855, x: 25}, {e: lookup.Epoch{Time: 1069225185, Level: 8}, n: 1069224660, x: 10}, {e: lookup.Epoch{Time: 1057505479, Level: 9}, n: 1057505170, x: 14}, {e: lookup.Epoch{Time: 1072381377, Level: 12}, n: 1065950959, x: 22}, {e: lookup.Epoch{Time: 1093887139, Level: 8}, n: 1093863305, x: 14}, {e: lookup.Epoch{Time: 1082366510, Level: 24}, n: 1082366510, x: 23}, {e: lookup.Epoch{Time: 1103231132, Level: 14}, n: 1102292201, x: 22}, {e: lookup.Epoch{Time: 1094502355, Level: 3}, n: 1094324652, x: 18}, {e: lookup.Epoch{Time: 1068488344, Level: 12}, n: 1067577330, x: 19}, {e: lookup.Epoch{Time: 1050278233, Level: 12}, n: 1050278232, x: 11}, {e: lookup.Epoch{Time: 1047660768, Level: 5}, n: 1047652137, x: 17}, {e: lookup.Epoch{Time: 1060116167, Level: 11}, n: 1060114091, x: 12}, {e: lookup.Epoch{Time: 1068149392, Level: 21}, n: 1052074801, x: 24}, {e: lookup.Epoch{Time: 1081934120, Level: 6}, n: 1081933847, x: 8}, {e: lookup.Epoch{Time: 1107943693, Level: 16}, n: 1107096139, x: 25}, {e: lookup.Epoch{Time: 1131571649, Level: 9}, n: 1131570428, x: 11}, {e: lookup.Epoch{Time: 1123139367, Level: 0}, n: 1122912198, x: 20}, {e: lookup.Epoch{Time: 1121144423, Level: 6}, n: 1120568289, x: 20}, {e: lookup.Epoch{Time: 1089932411, Level: 17}, n: 1089932410, x: 16}, {e: lookup.Epoch{Time: 1104899012, Level: 22}, n: 1098978789, x: 22}, {e: lookup.Epoch{Time: 1094588059, Level: 21}, n: 1094588059, x: 20}, {e: lookup.Epoch{Time: 1114987438, Level: 24}, n: 1114987437, x: 23}, {e: lookup.Epoch{Time: 1084186305, Level: 7}, n: 1084186241, x: 6}, {e: lookup.Epoch{Time: 1058827111, Level: 8}, n: 1058826504, x: 9}, {e: lookup.Epoch{Time: 1090679810, Level: 12}, n: 1090616539, x: 17}, {e: lookup.Epoch{Time: 1084299475, Level: 23}, n: 1084299475, x: 22}} func TestGetNextLevel(t *testing.T) { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request.go index 6968d8b9..dd91a7cf 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request.go @@ -171,9 +171,11 @@ func (r *Request) toChunk() (storage.Chunk, error) { } // fromChunk populates this structure from chunk data. It does not verify the signature is valid. -func (r *Request) fromChunk(updateAddr storage.Address, chunkdata []byte) error { +func (r *Request) fromChunk(chunk storage.Chunk) error { // for update chunk layout see Request definition + chunkdata := chunk.Data() + //deserialize the feed update portion if err := r.Update.binaryGet(chunkdata[:len(chunkdata)-signatureLength]); err != nil { return err @@ -189,7 +191,7 @@ func (r *Request) fromChunk(updateAddr storage.Address, chunkdata []byte) error } r.Signature = signature - r.idAddr = updateAddr + r.idAddr = chunk.Address() r.binaryData = chunkdata return nil diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request_test.go index f5de32b7..c30158fd 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/request_test.go @@ -197,7 +197,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) { // Test that parseUpdate fails if the chunk is too small var r Request - if err := r.fromChunk(storage.ZeroAddr, make([]byte, minimumUpdateDataLength-1+signatureLength)); err == nil { + if err := r.fromChunk(storage.NewChunk(storage.ZeroAddr, make([]byte, minimumUpdateDataLength-1+signatureLength))); err == nil { t.Fatalf("Expected request.fromChunk to fail when chunkData contains less than %d bytes", minimumUpdateDataLength) } @@ -226,7 +226,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) { compareByteSliceToExpectedHex(t, "chunk", chunk.Data(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019416c206269656e206861636572206a616dc3a173206c652066616c7461207072656d696f5a0ffe0bc27f207cd5b00944c8b9cee93e08b89b5ada777f123ac535189333f174a6a4ca2f43a92c4a477a49d774813c36ce8288552c58e6205b0ac35d0507eb00") var recovered Request - recovered.fromChunk(chunk.Address(), chunk.Data()) + recovered.fromChunk(chunk) if !reflect.DeepEqual(recovered, r) { t.Fatal("Expected recovered feed update request to equal the original one") } @@ -282,7 +282,7 @@ func TestReverse(t *testing.T) { // check that we can recover the owner account from the update chunk's signature var checkUpdate Request - if err := checkUpdate.fromChunk(chunk.Address(), chunk.Data()); err != nil { + if err := checkUpdate.fromChunk(chunk); err != nil { t.Fatal(err) } checkdigest, err := checkUpdate.GetDigest() diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/testutil.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/testutil.go index b513fa1f..caa39d9f 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/testutil.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/testutil.go @@ -40,9 +40,9 @@ func (t *TestHandler) Close() { type mockNetFetcher struct{} -func (m *mockNetFetcher) Request(ctx context.Context, hopCount uint8) { +func (m *mockNetFetcher) Request(hopCount uint8) { } -func (m *mockNetFetcher) Offer(ctx context.Context, source *enode.ID) { +func (m *mockNetFetcher) Offer(source *enode.ID) { } func newFakeNetFetcher(context.Context, storage.Address, *sync.Map) storage.NetFetcher { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/timestampprovider.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/timestampprovider.go index 072dc3a4..fb60cea9 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/timestampprovider.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/feed/timestampprovider.go @@ -17,7 +17,6 @@ package feed import ( - "encoding/binary" "encoding/json" "time" ) @@ -30,32 +29,11 @@ type Timestamp struct { Time uint64 `json:"time"` // Unix epoch timestamp, in seconds } -// 8 bytes uint64 Time -const timestampLength = 8 - // timestampProvider interface describes a source of timestamp information type timestampProvider interface { Now() Timestamp // returns the current timestamp information } -// binaryGet populates the timestamp structure from the given byte slice -func (t *Timestamp) binaryGet(data []byte) error { - if len(data) != timestampLength { - return NewError(ErrCorruptData, "timestamp data has the wrong size") - } - t.Time = binary.LittleEndian.Uint64(data[:8]) - return nil -} - -// binaryPut Serializes a Timestamp to a byte slice -func (t *Timestamp) binaryPut(data []byte) error { - if len(data) != timestampLength { - return NewError(ErrCorruptData, "timestamp data has the wrong size") - } - binary.LittleEndian.PutUint64(data, t.Time) - return nil -} - // UnmarshalJSON implements the json.Unmarshaller interface func (t *Timestamp) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &t.Time) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore.go index 2d8d82d9..0bad944e 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore.go @@ -19,6 +19,8 @@ package storage import ( "context" "io" + "sort" + "sync" ) /* @@ -74,7 +76,7 @@ func NewFileStore(store ChunkStore, params *FileStoreParams) *FileStore { } } -// Public API. Main entry point for document retrieval directly. Used by the +// Retrieve is a public API. Main entry point for document retrieval directly. Used by the // FS-aware API and httpaccess // Chunk retrieval blocks on netStore requests with a timeout so reader will // report error if retrieval of chunks within requested range time out. @@ -86,7 +88,7 @@ func (f *FileStore) Retrieve(ctx context.Context, addr Address) (reader *LazyChu return } -// Public API. Main entry point for document storage directly. Used by the +// Store is a public API. Main entry point for document storage directly. Used by the // FS-aware API and httpaccess func (f *FileStore) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr Address, wait func(context.Context) error, err error) { putter := NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt) @@ -96,3 +98,49 @@ func (f *FileStore) Store(ctx context.Context, data io.Reader, size int64, toEnc func (f *FileStore) HashSize() int { return f.hashFunc().Size() } + +// GetAllReferences is a public API. This endpoint returns all chunk hashes (only) for a given file +func (f *FileStore) GetAllReferences(ctx context.Context, data io.Reader, toEncrypt bool) (addrs AddressCollection, err error) { + // create a special kind of putter, which only will store the references + putter := &hashExplorer{ + hasherStore: NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt), + } + // do the actual splitting anyway, no way around it + _, wait, err := PyramidSplit(ctx, data, putter, putter) + if err != nil { + return nil, err + } + // wait for splitting to be complete and all chunks processed + err = wait(ctx) + if err != nil { + return nil, err + } + // collect all references + addrs = NewAddressCollection(0) + for _, ref := range putter.references { + addrs = append(addrs, Address(ref)) + } + sort.Sort(addrs) + return addrs, nil +} + +// hashExplorer is a special kind of putter which will only store chunk references +type hashExplorer struct { + *hasherStore + references []Reference + lock sync.Mutex +} + +// HashExplorer's Put will add just the chunk hashes to its `References` +func (he *hashExplorer) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { + // Need to do the actual Put, which returns the references + ref, err := he.hasherStore.Put(ctx, chunkData) + if err != nil { + return nil, err + } + // internally store the reference + he.lock.Lock() + he.references = append(he.references, ref) + he.lock.Unlock() + return ref, nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore_test.go index fb0f761a..06c4be1d 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/filestore_test.go @@ -173,3 +173,35 @@ func testFileStoreCapacity(toEncrypt bool, t *testing.T) { t.Fatalf("Comparison error after clearing memStore.") } } + +// TestGetAllReferences only tests that GetAllReferences returns an expected +// number of references for a given file +func TestGetAllReferences(t *testing.T) { + tdb, cleanup, err := newTestDbStore(false, false) + defer cleanup() + if err != nil { + t.Fatalf("init dbStore failed: %v", err) + } + db := tdb.LDBStore + memStore := NewMemStore(NewDefaultStoreParams(), db) + localStore := &LocalStore{ + memStore: memStore, + DbStore: db, + } + fileStore := NewFileStore(localStore, NewFileStoreParams()) + + // testRuns[i] and expectedLen[i] are dataSize and expected length respectively + testRuns := []int{1024, 8192, 16000, 30000, 1000000} + expectedLens := []int{1, 3, 5, 9, 248} + for i, r := range testRuns { + slice := testutil.RandomBytes(1, r) + + addrs, err := fileStore.GetAllReferences(context.Background(), bytes.NewReader(slice), false) + if err != nil { + t.Fatal(err) + } + if len(addrs) != expectedLens[i] { + t.Fatalf("Expected reference array length to be %d, but is %d", expectedLens[i], len(addrs)) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/hasherstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/hasherstore.go index ff18e64c..345ce743 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/hasherstore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/hasherstore.go @@ -21,9 +21,9 @@ import ( "fmt" "sync/atomic" - "github.com/ethereum/go-ethereum/crypto/sha3" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" "github.com/ethereum/go-ethereum/swarm/storage/encryption" + "golang.org/x/crypto/sha3" ) type hasherStore struct { @@ -156,7 +156,7 @@ func (h *hasherStore) createHash(chunkData ChunkData) Address { return hasher.Sum(nil) } -func (h *hasherStore) createChunk(chunkData ChunkData) *chunk { +func (h *hasherStore) createChunk(chunkData ChunkData) Chunk { hash := h.createHash(chunkData) chunk := NewChunk(hash, chunkData) return chunk @@ -189,9 +189,9 @@ func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryp // removing extra bytes which were just added for padding length := ChunkData(decryptedSpan).Size() - for length > ch.DefaultSize { - length = length + (ch.DefaultSize - 1) - length = length / ch.DefaultSize + for length > chunk.DefaultSize { + length = length + (chunk.DefaultSize - 1) + length = length / chunk.DefaultSize length *= uint64(h.refSize) } @@ -232,14 +232,14 @@ func (h *hasherStore) decrypt(chunkData ChunkData, key encryption.Key) ([]byte, } func (h *hasherStore) newSpanEncryption(key encryption.Key) encryption.Encryption { - return encryption.New(key, 0, uint32(ch.DefaultSize/h.refSize), sha3.NewKeccak256) + return encryption.New(key, 0, uint32(chunk.DefaultSize/h.refSize), sha3.NewLegacyKeccak256) } func (h *hasherStore) newDataEncryption(key encryption.Key) encryption.Encryption { - return encryption.New(key, int(ch.DefaultSize), 0, sha3.NewKeccak256) + return encryption.New(key, int(chunk.DefaultSize), 0, sha3.NewLegacyKeccak256) } -func (h *hasherStore) storeChunk(ctx context.Context, chunk *chunk) { +func (h *hasherStore) storeChunk(ctx context.Context, chunk Chunk) { atomic.AddUint64(&h.nrChunks, 1) go func() { select { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore.go index fbae59fa..fd5ec9e3 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore.go @@ -248,10 +248,6 @@ func U64ToBytes(val uint64) []byte { return data } -func (s *LDBStore) updateIndexAccess(index *dpaDBIndex) { - index.Access = s.accessCnt -} - func getIndexKey(hash Address) []byte { hashSize := len(hash) key := make([]byte, hashSize+1) @@ -284,7 +280,7 @@ func getGCIdxValue(index *dpaDBIndex, po uint8, addr Address) []byte { return val } -func parseGCIdxKey(key []byte) (byte, []byte) { +func parseIdxKey(key []byte) (byte, []byte) { return key[0], key[1:] } @@ -316,12 +312,11 @@ func decodeIndex(data []byte, index *dpaDBIndex) error { return dec.Decode(index) } -func decodeData(addr Address, data []byte) (*chunk, error) { +func decodeData(addr Address, data []byte) (Chunk, error) { return NewChunk(addr, data[32:]), nil } func (s *LDBStore) collectGarbage() error { - // prevent duplicate gc from starting when one is already running select { case <-s.gc.runC: @@ -339,7 +334,6 @@ func (s *LDBStore) collectGarbage() error { s.startGC(int(entryCnt)) log.Debug("collectGarbage", "target", s.gc.target, "entryCnt", entryCnt) - var totalDeleted int for s.gc.count < s.gc.target { it := s.db.NewIterator() ok := it.Seek([]byte{keyGCIdx}) @@ -375,15 +369,15 @@ func (s *LDBStore) collectGarbage() error { } s.writeBatch(s.gc.batch, wEntryCnt) + log.Trace("garbage collect batch done", "batch", singleIterationCount, "total", s.gc.count) s.lock.Unlock() it.Release() - log.Trace("garbage collect batch done", "batch", singleIterationCount, "total", s.gc.count) } - s.gc.runC <- struct{}{} + metrics.GetOrRegisterCounter("ldbstore.collectgarbage.delete", nil).Inc(int64(s.gc.count)) log.Debug("garbage collect done", "c", s.gc.count) + s.gc.runC <- struct{}{} - metrics.GetOrRegisterCounter("ldbstore.collectgarbage.delete", nil).Inc(int64(totalDeleted)) return nil } @@ -508,7 +502,7 @@ func (s *LDBStore) Import(in io.Reader) (int64, error) { } // Cleanup iterates over the database and deletes chunks if they pass the `f` condition -func (s *LDBStore) Cleanup(f func(*chunk) bool) { +func (s *LDBStore) Cleanup(f func(Chunk) bool) { var errorsFound, removed, total int it := s.db.NewIterator() @@ -533,8 +527,8 @@ func (s *LDBStore) Cleanup(f func(*chunk) bool) { if err != nil { found := false - // highest possible proximity is 255 - for po = 1; po <= 255; po++ { + // The highest possible proximity is 255, so exit loop upon overflow. + for po = uint8(1); po != 0; po++ { datakey = getDataKey(index.Idx, po) data, err = s.db.Get(datakey) if err == nil { @@ -557,12 +551,14 @@ func (s *LDBStore) Cleanup(f func(*chunk) bool) { continue } - cs := int64(binary.LittleEndian.Uint64(c.sdata[:8])) - log.Trace("chunk", "key", fmt.Sprintf("%x", key), "ck", fmt.Sprintf("%x", ck), "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po, "len data", len(data), "len sdata", len(c.sdata), "size", cs) + sdata := c.Data() + + cs := int64(binary.LittleEndian.Uint64(sdata[:8])) + log.Trace("chunk", "key", fmt.Sprintf("%x", key), "ck", fmt.Sprintf("%x", ck), "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po, "len data", len(data), "len sdata", len(sdata), "size", cs) // if chunk is to be removed if f(c) { - log.Warn("chunk for cleanup", "key", fmt.Sprintf("%x", key), "ck", fmt.Sprintf("%x", ck), "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po, "len data", len(data), "len sdata", len(c.sdata), "size", cs) + log.Warn("chunk for cleanup", "key", fmt.Sprintf("%x", key), "ck", fmt.Sprintf("%x", ck), "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po, "len data", len(data), "len sdata", len(sdata), "size", cs) s.deleteNow(&index, getIndexKey(key[1:]), po) removed++ errorsFound++ @@ -589,7 +585,7 @@ func (s *LDBStore) CleanGCIndex() error { it.Seek([]byte{keyGCIdx}) var gcDeletes int for it.Valid() { - rowType, _ := parseGCIdxKey(it.Key()) + rowType, _ := parseIdxKey(it.Key()) if rowType != keyGCIdx { break } @@ -601,47 +597,113 @@ func (s *LDBStore) CleanGCIndex() error { if err := s.db.Write(&batch); err != nil { return err } - - it.Seek([]byte{keyIndex}) - var idx dpaDBIndex - var poPtrs [256]uint64 - for it.Valid() { - rowType, chunkHash := parseGCIdxKey(it.Key()) - if rowType != keyIndex { - break - } - err := decodeIndex(it.Value(), &idx) - if err != nil { - return fmt.Errorf("corrupt index: %v", err) - } - po := s.po(chunkHash) - - // if we don't find the data key, remove the entry - dataKey := getDataKey(idx.Idx, po) - _, err = s.db.Get(dataKey) - if err != nil { - log.Warn("deleting inconsistent index (missing data)", "key", chunkHash) - batch.Delete(it.Key()) - } else { - gcIdxKey := getGCIdxKey(&idx) - gcIdxData := getGCIdxValue(&idx, po, chunkHash) - batch.Put(gcIdxKey, gcIdxData) - log.Trace("clean ok", "key", chunkHash, "gcKey", gcIdxKey, "gcData", gcIdxData) - okEntryCount++ - if idx.Idx > poPtrs[po] { - poPtrs[po] = idx.Idx - } - } - totalEntryCount++ - it.Next() - } + batch.Reset() it.Release() + + // corrected po index pointer values + var poPtrs [256]uint64 + + // set to true if chunk count not on 4096 iteration boundary + var doneIterating bool + + // last key index in previous iteration + lastIdxKey := []byte{keyIndex} + + // counter for debug output + var cleanBatchCount int + + // go through all key index entries + for !doneIterating { + cleanBatchCount++ + var idxs []dpaDBIndex + var chunkHashes [][]byte + var pos []uint8 + it := s.db.NewIterator() + + it.Seek(lastIdxKey) + + // 4096 is just a nice number, don't look for any hidden meaning here... + var i int + for i = 0; i < 4096; i++ { + + // this really shouldn't happen unless database is empty + // but let's keep it to be safe + if !it.Valid() { + doneIterating = true + break + } + + // if it's not keyindex anymore we're done iterating + rowType, chunkHash := parseIdxKey(it.Key()) + if rowType != keyIndex { + doneIterating = true + break + } + + // decode the retrieved index + var idx dpaDBIndex + err := decodeIndex(it.Value(), &idx) + if err != nil { + return fmt.Errorf("corrupt index: %v", err) + } + po := s.po(chunkHash) + lastIdxKey = it.Key() + + // if we don't find the data key, remove the entry + // if we find it, add to the array of new gc indices to create + dataKey := getDataKey(idx.Idx, po) + _, err = s.db.Get(dataKey) + if err != nil { + log.Warn("deleting inconsistent index (missing data)", "key", chunkHash) + batch.Delete(it.Key()) + } else { + idxs = append(idxs, idx) + chunkHashes = append(chunkHashes, chunkHash) + pos = append(pos, po) + okEntryCount++ + if idx.Idx > poPtrs[po] { + poPtrs[po] = idx.Idx + } + } + totalEntryCount++ + it.Next() + } + it.Release() + + // flush the key index corrections + err := s.db.Write(&batch) + if err != nil { + return err + } + batch.Reset() + + // add correct gc indices + for i, okIdx := range idxs { + gcIdxKey := getGCIdxKey(&okIdx) + gcIdxData := getGCIdxValue(&okIdx, pos[i], chunkHashes[i]) + batch.Put(gcIdxKey, gcIdxData) + log.Trace("clean ok", "key", chunkHashes[i], "gcKey", gcIdxKey, "gcData", gcIdxData) + } + + // flush them + err = s.db.Write(&batch) + if err != nil { + return err + } + batch.Reset() + + log.Debug("clean gc index pass", "batch", cleanBatchCount, "checked", i, "kept", len(idxs)) + } + log.Debug("gc cleanup entries", "ok", okEntryCount, "total", totalEntryCount, "batchlen", batch.Len()) + // lastly add updated entry count var entryCount [8]byte binary.BigEndian.PutUint64(entryCount[:], okEntryCount) batch.Put(keyEntryCnt, entryCount[:]) + + // and add the new po index pointers var poKey [2]byte poKey[0] = keyDistanceCnt for i, poPtr := range poPtrs { @@ -655,6 +717,7 @@ func (s *LDBStore) CleanGCIndex() error { } } + // if you made it this far your harddisk has survived. Congratulations return s.db.Write(&batch) } @@ -710,18 +773,6 @@ func (s *LDBStore) BinIndex(po uint8) uint64 { return s.bucketCnt[po] } -func (s *LDBStore) Size() uint64 { - s.lock.RLock() - defer s.lock.RUnlock() - return s.entryCnt -} - -func (s *LDBStore) CurrentStorageIndex() uint64 { - s.lock.RLock() - defer s.lock.RUnlock() - return s.dataIdx -} - // Put adds a chunk to the database, adding indices and incrementing global counters. // If it already exists, it merely increments the access count of the existing entry. // Is thread safe @@ -743,11 +794,11 @@ func (s *LDBStore) Put(ctx context.Context, chunk Chunk) error { batch := s.batch log.Trace("ldbstore.put: s.db.Get", "key", chunk.Address(), "ikey", fmt.Sprintf("%x", ikey)) - idata, err := s.db.Get(ikey) + _, err := s.db.Get(ikey) if err != nil { s.doPut(chunk, &index, po) } - idata = encodeIndex(&index) + idata := encodeIndex(&index) s.batch.Put(ikey, idata) // add the access-chunkindex index for garbage collection @@ -918,8 +969,20 @@ func (s *LDBStore) Get(_ context.Context, addr Address) (chunk Chunk, err error) return s.get(addr) } +// Has queries the underlying DB if a chunk with the given address is stored +// Returns true if the chunk is found, false if not +func (s *LDBStore) Has(_ context.Context, addr Address) bool { + s.lock.RLock() + defer s.lock.RUnlock() + + ikey := getIndexKey(addr) + _, err := s.db.Get(ikey) + + return err == nil +} + // TODO: To conform with other private methods of this object indices should not be updated -func (s *LDBStore) get(addr Address) (chunk *chunk, err error) { +func (s *LDBStore) get(addr Address) (chunk Chunk, err error) { if s.closed { return nil, ErrDBClosed } @@ -942,7 +1005,10 @@ func (s *LDBStore) get(addr Address) (chunk *chunk, err error) { if err != nil { log.Trace("ldbstore.get chunk found but could not be accessed", "key", addr, "err", err) s.deleteNow(index, getIndexKey(addr), s.po(addr)) - return + if err == leveldb.ErrNotFound { + return nil, ErrChunkNotFound + } + return nil, err } } @@ -986,7 +1052,6 @@ func (s *LDBStore) Close() { s.lock.Unlock() // force writing out current batch s.writeCurrentBatch() - close(s.batchesC) s.db.Close() } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore_test.go index 07557980..d17bd7d0 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/ldbstore_test.go @@ -26,10 +26,9 @@ import ( "strconv" "strings" "testing" - "time" "github.com/ethereum/go-ethereum/common" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" ldberrors "github.com/syndtr/goleveldb/leveldb/errors" @@ -79,30 +78,22 @@ func testPoFunc(k Address) (ret uint8) { return uint8(Proximity(basekey, k[:])) } -func (db *testDbStore) close() { - db.Close() - err := os.RemoveAll(db.dir) - if err != nil { - panic(err) - } -} - -func testDbStoreRandom(n int, chunksize int64, mock bool, t *testing.T) { +func testDbStoreRandom(n int, mock bool, t *testing.T) { db, cleanup, err := newTestDbStore(mock, true) defer cleanup() if err != nil { t.Fatalf("init dbStore failed: %v", err) } - testStoreRandom(db, n, chunksize, t) + testStoreRandom(db, n, t) } -func testDbStoreCorrect(n int, chunksize int64, mock bool, t *testing.T) { +func testDbStoreCorrect(n int, mock bool, t *testing.T) { db, cleanup, err := newTestDbStore(mock, false) defer cleanup() if err != nil { t.Fatalf("init dbStore failed: %v", err) } - testStoreCorrect(db, n, chunksize, t) + testStoreCorrect(db, n, t) } func TestMarkAccessed(t *testing.T) { @@ -112,7 +103,7 @@ func TestMarkAccessed(t *testing.T) { t.Fatalf("init dbStore failed: %v", err) } - h := GenerateRandomChunk(ch.DefaultSize) + h := GenerateRandomChunk(chunk.DefaultSize) db.Put(context.Background(), h) @@ -146,35 +137,35 @@ func TestMarkAccessed(t *testing.T) { } func TestDbStoreRandom_1(t *testing.T) { - testDbStoreRandom(1, 0, false, t) + testDbStoreRandom(1, false, t) } func TestDbStoreCorrect_1(t *testing.T) { - testDbStoreCorrect(1, 4096, false, t) + testDbStoreCorrect(1, false, t) } func TestDbStoreRandom_1k(t *testing.T) { - testDbStoreRandom(1000, 0, false, t) + testDbStoreRandom(1000, false, t) } func TestDbStoreCorrect_1k(t *testing.T) { - testDbStoreCorrect(1000, 4096, false, t) + testDbStoreCorrect(1000, false, t) } func TestMockDbStoreRandom_1(t *testing.T) { - testDbStoreRandom(1, 0, true, t) + testDbStoreRandom(1, true, t) } func TestMockDbStoreCorrect_1(t *testing.T) { - testDbStoreCorrect(1, 4096, true, t) + testDbStoreCorrect(1, true, t) } func TestMockDbStoreRandom_1k(t *testing.T) { - testDbStoreRandom(1000, 0, true, t) + testDbStoreRandom(1000, true, t) } func TestMockDbStoreCorrect_1k(t *testing.T) { - testDbStoreCorrect(1000, 4096, true, t) + testDbStoreCorrect(1000, true, t) } func testDbStoreNotFound(t *testing.T, mock bool) { @@ -198,11 +189,11 @@ func TestMockDbStoreNotFound(t *testing.T) { } func testIterator(t *testing.T, mock bool) { - var chunkcount int = 32 var i int var poc uint + chunkcount := 32 chunkkeys := NewAddressCollection(chunkcount) - chunkkeys_results := NewAddressCollection(chunkcount) + chunkkeysResults := NewAddressCollection(chunkcount) db, cleanup, err := newTestDbStore(mock, false) defer cleanup() @@ -210,7 +201,7 @@ func testIterator(t *testing.T, mock bool) { t.Fatalf("init dbStore failed: %v", err) } - chunks := GenerateRandomChunks(ch.DefaultSize, chunkcount) + chunks := GenerateRandomChunks(chunk.DefaultSize, chunkcount) for i = 0; i < len(chunks); i++ { chunkkeys[i] = chunks[i].Address() @@ -227,7 +218,7 @@ func testIterator(t *testing.T, mock bool) { for poc = 0; poc <= 255; poc++ { err := db.SyncIterator(0, uint64(chunkkeys.Len()), uint8(poc), func(k Address, n uint64) bool { log.Trace(fmt.Sprintf("Got key %v number %d poc %d", k, n, uint8(poc))) - chunkkeys_results[n] = k + chunkkeysResults[n] = k i++ return true }) @@ -237,8 +228,8 @@ func testIterator(t *testing.T, mock bool) { } for i = 0; i < chunkcount; i++ { - if !bytes.Equal(chunkkeys[i], chunkkeys_results[i]) { - t.Fatalf("Chunk put #%d key '%v' does not match iterator's key '%v'", i, chunkkeys[i], chunkkeys_results[i]) + if !bytes.Equal(chunkkeys[i], chunkkeysResults[i]) { + t.Fatalf("Chunk put #%d key '%v' does not match iterator's key '%v'", i, chunkkeys[i], chunkkeysResults[i]) } } @@ -251,54 +242,38 @@ func TestMockIterator(t *testing.T) { testIterator(t, true) } -func benchmarkDbStorePut(n int, processors int, chunksize int64, mock bool, b *testing.B) { +func benchmarkDbStorePut(n int, mock bool, b *testing.B) { db, cleanup, err := newTestDbStore(mock, true) defer cleanup() if err != nil { b.Fatalf("init dbStore failed: %v", err) } - benchmarkStorePut(db, n, chunksize, b) + benchmarkStorePut(db, n, b) } -func benchmarkDbStoreGet(n int, processors int, chunksize int64, mock bool, b *testing.B) { +func benchmarkDbStoreGet(n int, mock bool, b *testing.B) { db, cleanup, err := newTestDbStore(mock, true) defer cleanup() if err != nil { b.Fatalf("init dbStore failed: %v", err) } - benchmarkStoreGet(db, n, chunksize, b) + benchmarkStoreGet(db, n, b) } -func BenchmarkDbStorePut_1_500(b *testing.B) { - benchmarkDbStorePut(500, 1, 4096, false, b) +func BenchmarkDbStorePut_500(b *testing.B) { + benchmarkDbStorePut(500, false, b) } -func BenchmarkDbStorePut_8_500(b *testing.B) { - benchmarkDbStorePut(500, 8, 4096, false, b) +func BenchmarkDbStoreGet_500(b *testing.B) { + benchmarkDbStoreGet(500, false, b) } -func BenchmarkDbStoreGet_1_500(b *testing.B) { - benchmarkDbStoreGet(500, 1, 4096, false, b) +func BenchmarkMockDbStorePut_500(b *testing.B) { + benchmarkDbStorePut(500, true, b) } -func BenchmarkDbStoreGet_8_500(b *testing.B) { - benchmarkDbStoreGet(500, 8, 4096, false, b) -} - -func BenchmarkMockDbStorePut_1_500(b *testing.B) { - benchmarkDbStorePut(500, 1, 4096, true, b) -} - -func BenchmarkMockDbStorePut_8_500(b *testing.B) { - benchmarkDbStorePut(500, 8, 4096, true, b) -} - -func BenchmarkMockDbStoreGet_1_500(b *testing.B) { - benchmarkDbStoreGet(500, 1, 4096, true, b) -} - -func BenchmarkMockDbStoreGet_8_500(b *testing.B) { - benchmarkDbStoreGet(500, 8, 4096, true, b) +func BenchmarkMockDbStoreGet_500(b *testing.B) { + benchmarkDbStoreGet(500, true, b) } // TestLDBStoreWithoutCollectGarbage tests that we can put a number of random chunks in the LevelDB store, and @@ -311,7 +286,7 @@ func TestLDBStoreWithoutCollectGarbage(t *testing.T) { ldb.setCapacity(uint64(capacity)) defer cleanup() - chunks, err := mputRandomChunks(ldb, n, int64(ch.DefaultSize)) + chunks, err := mputRandomChunks(ldb, n) if err != nil { t.Fatal(err.Error()) } @@ -344,17 +319,18 @@ func TestLDBStoreWithoutCollectGarbage(t *testing.T) { func TestLDBStoreCollectGarbage(t *testing.T) { // below max ronud - cap := defaultMaxGCRound / 2 + initialCap := defaultMaxGCRound / 100 + cap := initialCap / 2 t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) // at max round - cap = defaultMaxGCRound + cap = initialCap t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) // more than max around, not on threshold - cap = defaultMaxGCRound * 1.1 + cap = initialCap + 500 t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) @@ -390,16 +366,16 @@ func testLDBStoreCollectGarbage(t *testing.T) { putCount = roundTarget } remaining -= putCount - chunks, err := mputRandomChunks(ldb, putCount, int64(ch.DefaultSize)) + chunks, err := mputRandomChunks(ldb, putCount) if err != nil { t.Fatal(err.Error()) } allChunks = append(allChunks, chunks...) + ldb.lock.RLock() log.Debug("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt, "cap", capacity, "n", n) + ldb.lock.RUnlock() - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - waitGc(ctx, ldb) + waitGc(ldb) } // attempt gets on all put chunks @@ -437,7 +413,7 @@ func TestLDBStoreAddRemove(t *testing.T) { defer cleanup() n := 100 - chunks, err := mputRandomChunks(ldb, n, int64(ch.DefaultSize)) + chunks, err := mputRandomChunks(ldb, n) if err != nil { t.Fatalf(err.Error()) } @@ -452,7 +428,7 @@ func TestLDBStoreAddRemove(t *testing.T) { log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) for i := 0; i < n; i++ { - ret, err := ldb.Get(nil, chunks[i].Address()) + ret, err := ldb.Get(context.TODO(), chunks[i].Address()) if i%2 == 0 { // expect even chunks to be missing @@ -473,6 +449,7 @@ func TestLDBStoreAddRemove(t *testing.T) { } func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { + t.Skip("flaky with -race flag") params := strings.Split(t.Name(), "/") capacity, err := strconv.Atoi(params[2]) @@ -491,7 +468,7 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { // put capacity count number of chunks chunks := make([]Chunk, n) for i := 0; i < n; i++ { - c := GenerateRandomChunk(ch.DefaultSize) + c := GenerateRandomChunk(chunk.DefaultSize) chunks[i] = c log.Trace("generate random chunk", "idx", i, "chunk", c) } @@ -503,9 +480,7 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { } } - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - waitGc(ctx, ldb) + waitGc(ldb) // delete all chunks // (only count the ones actually deleted, the rest will have been gc'd) @@ -544,14 +519,14 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { remaining -= putCount for putCount > 0 { ldb.Put(context.TODO(), chunks[puts]) + ldb.lock.RLock() log.Debug("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt, "cap", capacity, "n", n, "puts", puts, "remaining", remaining, "roundtarget", roundTarget) + ldb.lock.RUnlock() puts++ putCount-- } - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - waitGc(ctx, ldb) + waitGc(ldb) } // expect first surplus chunks to be missing, because they have the smallest access value @@ -578,14 +553,14 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { // TestLDBStoreCollectGarbageAccessUnlikeIndex tests garbage collection where accesscount differs from indexcount func TestLDBStoreCollectGarbageAccessUnlikeIndex(t *testing.T) { - capacity := defaultMaxGCRound * 2 + capacity := defaultMaxGCRound / 100 * 2 n := capacity - 1 ldb, cleanup := newLDBStore(t) ldb.setCapacity(uint64(capacity)) defer cleanup() - chunks, err := mputRandomChunks(ldb, n, int64(ch.DefaultSize)) + chunks, err := mputRandomChunks(ldb, n) if err != nil { t.Fatal(err.Error()) } @@ -598,15 +573,13 @@ func TestLDBStoreCollectGarbageAccessUnlikeIndex(t *testing.T) { t.Fatalf("fail add chunk #%d - %s: %v", i, chunks[i].Address(), err) } } - _, err = mputRandomChunks(ldb, 2, int64(ch.DefaultSize)) + _, err = mputRandomChunks(ldb, 2) if err != nil { t.Fatal(err.Error()) } // wait for garbage collection to kick in on the responsible actor - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - waitGc(ctx, ldb) + waitGc(ldb) var missing int for i, ch := range chunks[2 : capacity/2] { @@ -632,7 +605,7 @@ func TestCleanIndex(t *testing.T) { ldb.setCapacity(uint64(capacity)) defer cleanup() - chunks, err := mputRandomChunks(ldb, n, 4096) + chunks, err := mputRandomChunks(ldb, n) if err != nil { t.Fatal(err) } @@ -761,9 +734,44 @@ func TestCleanIndex(t *testing.T) { t.Fatalf("expected sum of bin indices to be 3, was %d", binTotal) } } + + // check that the iterator quits properly + chunks, err = mputRandomChunks(ldb, 4100) + if err != nil { + t.Fatal(err) + } + + po = ldb.po(chunks[4099].Address()[:]) + dataKey = make([]byte, 10) + dataKey[0] = keyData + dataKey[1] = byte(po) + binary.BigEndian.PutUint64(dataKey[2:], 4099+3) + if _, err := ldb.db.Get(dataKey); err != nil { + t.Fatal(err) + } + if err := ldb.db.Delete(dataKey); err != nil { + t.Fatal(err) + } + + if err := ldb.CleanGCIndex(); err != nil { + t.Fatal(err) + } + + // entrycount should now be one less of added chunks + c, err = ldb.db.Get(keyEntryCnt) + if err != nil { + t.Fatalf("expected gc 2 idx to be present: %v", idxKey) + } + entryCount = binary.BigEndian.Uint64(c) + if entryCount != 4099+2 { + t.Fatalf("expected entrycnt to be 2, was %d", c) + } } -func waitGc(ctx context.Context, ldb *LDBStore) { +// Note: waitGc does not guarantee that we wait 1 GC round; it only +// guarantees that if the GC is running we wait for that run to finish +// ticket: https://github.com/ethersphere/go-ethereum/issues/1151 +func waitGc(ldb *LDBStore) { <-ldb.gc.runC ldb.gc.runC <- struct{}{} } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore.go index fa98848d..a8f6f037 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore.go @@ -92,7 +92,7 @@ func (ls *LocalStore) isValid(chunk Chunk) bool { // ls.Validators contains a list of one validator per chunk type. // if one validator succeeds, then the chunk is valid for _, v := range ls.Validators { - if valid = v.Validate(chunk.Address(), chunk.Data()); valid { + if valid = v.Validate(chunk); valid { break } } @@ -132,6 +132,13 @@ func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error { return err } +// Has queries the underlying DbStore if a chunk with the given address +// is being stored there. +// Returns true if it is stored, false if not +func (ls *LocalStore) Has(ctx context.Context, addr Address) bool { + return ls.DbStore.Has(ctx, addr) +} + // Get(chunk *Chunk) looks up a chunk in the local stores // This method is blocking until the chunk is retrieved // so additional timeout may be needed to wrap this call if @@ -194,7 +201,8 @@ func (ls *LocalStore) Close() { ls.DbStore.Close() } -// Migrate checks the datastore schema vs the runtime schema, and runs migrations if they don't match +// Migrate checks the datastore schema vs the runtime schema and runs +// migrations if they don't match func (ls *LocalStore) Migrate() error { actualDbSchema, err := ls.DbStore.GetSchema() if err != nil { @@ -202,12 +210,12 @@ func (ls *LocalStore) Migrate() error { return err } - log.Debug("running migrations for", "schema", actualDbSchema, "runtime-schema", CurrentDbSchema) - if actualDbSchema == CurrentDbSchema { return nil } + log.Debug("running migrations for", "schema", actualDbSchema, "runtime-schema", CurrentDbSchema) + if actualDbSchema == DbSchemaNone { ls.migrateFromNoneToPurity() actualDbSchema = DbSchemaPurity @@ -233,7 +241,7 @@ func (ls *LocalStore) Migrate() error { func (ls *LocalStore) migrateFromNoneToPurity() { // delete chunks that are not valid, i.e. chunks that do not pass // any of the ls.Validators - ls.DbStore.Cleanup(func(c *chunk) bool { + ls.DbStore.Cleanup(func(c Chunk) bool { return !ls.isValid(c) }) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/doc.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/doc.go new file mode 100644 index 00000000..98f6fc40 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/doc.go @@ -0,0 +1,56 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +/* +Package localstore provides disk storage layer for Swarm Chunk persistence. +It uses swarm/shed abstractions on top of github.com/syndtr/goleveldb LevelDB +implementation. + +The main type is DB which manages the storage by providing methods to +access and add Chunks and to manage their status. + +Modes are abstractions that do specific changes to Chunks. There are three +mode types: + + - ModeGet, for Chunk access + - ModePut, for adding Chunks to the database + - ModeSet, for changing Chunk statuses + +Every mode type has a corresponding type (Getter, Putter and Setter) +that provides adequate method to perform the opperation and that type +should be injected into localstore consumers instead the whole DB. +This provides more clear insight which operations consumer is performing +on the database. + +Getters, Putters and Setters accept different get, put and set modes +to perform different actions. For example, ModeGet has two different +variables ModeGetRequest and ModeGetSync and two different Getters +can be constructed with them that are used when the chunk is requested +or when the chunk is synced as this two events are differently changing +the database. + +Subscription methods are implemented for a specific purpose of +continuous iterations over Chunks that should be provided to +Push and Pull syncing. + +DB implements an internal garbage collector that removes only synced +Chunks from the database based on their most recent access time. + +Internally, DB stores Chunk data and any required information, such as +store and access timestamps in different shed indexes that can be +iterated on by garbage collector or subscriptions. +*/ +package localstore diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/gc.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/gc.go new file mode 100644 index 00000000..84c4f596 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/gc.go @@ -0,0 +1,175 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/syndtr/goleveldb/leveldb" +) + +var ( + // gcTargetRatio defines the target number of items + // in garbage collection index that will not be removed + // on garbage collection. The target number of items + // is calculated by gcTarget function. This value must be + // in range (0,1]. For example, with 0.9 value, + // garbage collection will leave 90% of defined capacity + // in database after its run. This prevents frequent + // garbage collection runs. + gcTargetRatio = 0.9 + // gcBatchSize limits the number of chunks in a single + // leveldb batch on garbage collection. + gcBatchSize uint64 = 1000 +) + +// collectGarbageWorker is a long running function that waits for +// collectGarbageTrigger channel to signal a garbage collection +// run. GC run iterates on gcIndex and removes older items +// form retrieval and other indexes. +func (db *DB) collectGarbageWorker() { + defer close(db.collectGarbageWorkerDone) + + for { + select { + case <-db.collectGarbageTrigger: + // run a single collect garbage run and + // if done is false, gcBatchSize is reached and + // another collect garbage run is needed + collectedCount, done, err := db.collectGarbage() + if err != nil { + log.Error("localstore collect garbage", "err", err) + } + // check if another gc run is needed + if !done { + db.triggerGarbageCollection() + } + + if collectedCount > 0 && testHookCollectGarbage != nil { + testHookCollectGarbage(collectedCount) + } + case <-db.close: + return + } + } +} + +// collectGarbage removes chunks from retrieval and other +// indexes if maximal number of chunks in database is reached. +// This function returns the number of removed chunks. If done +// is false, another call to this function is needed to collect +// the rest of the garbage as the batch size limit is reached. +// This function is called in collectGarbageWorker. +func (db *DB) collectGarbage() (collectedCount uint64, done bool, err error) { + batch := new(leveldb.Batch) + target := db.gcTarget() + + // protect database from changing idexes and gcSize + db.batchMu.Lock() + defer db.batchMu.Unlock() + + gcSize, err := db.gcSize.Get() + if err != nil { + return 0, true, err + } + + done = true + err = db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { + if gcSize-collectedCount <= target { + return true, nil + } + // delete from retrieve, pull, gc + db.retrievalDataIndex.DeleteInBatch(batch, item) + db.retrievalAccessIndex.DeleteInBatch(batch, item) + db.pullIndex.DeleteInBatch(batch, item) + db.gcIndex.DeleteInBatch(batch, item) + collectedCount++ + if collectedCount >= gcBatchSize { + // bach size limit reached, + // another gc run is needed + done = false + return true, nil + } + return false, nil + }, nil) + if err != nil { + return 0, false, err + } + + db.gcSize.PutInBatch(batch, gcSize-collectedCount) + + err = db.shed.WriteBatch(batch) + if err != nil { + return 0, false, err + } + return collectedCount, done, nil +} + +// gcTrigger retruns the absolute value for garbage collection +// target value, calculated from db.capacity and gcTargetRatio. +func (db *DB) gcTarget() (target uint64) { + return uint64(float64(db.capacity) * gcTargetRatio) +} + +// triggerGarbageCollection signals collectGarbageWorker +// to call collectGarbage. +func (db *DB) triggerGarbageCollection() { + select { + case db.collectGarbageTrigger <- struct{}{}: + case <-db.close: + default: + } +} + +// incGCSizeInBatch changes gcSize field value +// by change which can be negative. This function +// must be called under batchMu lock. +func (db *DB) incGCSizeInBatch(batch *leveldb.Batch, change int64) (err error) { + if change == 0 { + return nil + } + gcSize, err := db.gcSize.Get() + if err != nil { + return err + } + + var new uint64 + if change > 0 { + new = gcSize + uint64(change) + } else { + // 'change' is an int64 and is negative + // a conversion is needed with correct sign + c := uint64(-change) + if c > gcSize { + // protect uint64 undeflow + return nil + } + new = gcSize - c + } + db.gcSize.PutInBatch(batch, new) + + // trigger garbage collection if we reached the capacity + if new >= db.capacity { + db.triggerGarbageCollection() + } + return nil +} + +// testHookCollectGarbage is a hook that can provide +// information when a garbage collection run is done +// and how many items it removed. +var testHookCollectGarbage func(collectedCount uint64) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/gc_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/gc_test.go new file mode 100644 index 00000000..081e0af8 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/gc_test.go @@ -0,0 +1,371 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "io/ioutil" + "math/rand" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// TestDB_collectGarbageWorker tests garbage collection runs +// by uploading and syncing a number of chunks. +func TestDB_collectGarbageWorker(t *testing.T) { + testDB_collectGarbageWorker(t) +} + +// TestDB_collectGarbageWorker_multipleBatches tests garbage +// collection runs by uploading and syncing a number of +// chunks by having multiple smaller batches. +func TestDB_collectGarbageWorker_multipleBatches(t *testing.T) { + // lower the maximal number of chunks in a single + // gc batch to ensure multiple batches. + defer func(s uint64) { gcBatchSize = s }(gcBatchSize) + gcBatchSize = 2 + + testDB_collectGarbageWorker(t) +} + +// testDB_collectGarbageWorker is a helper test function to test +// garbage collection runs by uploading and syncing a number of chunks. +func testDB_collectGarbageWorker(t *testing.T) { + t.Helper() + + chunkCount := 150 + + db, cleanupFunc := newTestDB(t, &Options{ + Capacity: 100, + }) + testHookCollectGarbageChan := make(chan uint64) + defer setTestHookCollectGarbage(func(collectedCount uint64) { + select { + case testHookCollectGarbageChan <- collectedCount: + case <-db.close: + } + })() + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + syncer := db.NewSetter(ModeSetSync) + + addrs := make([]chunk.Address, 0) + + // upload random chunks + for i := 0; i < chunkCount; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + err = syncer.Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + addrs = append(addrs, chunk.Address()) + } + + gcTarget := db.gcTarget() + + for { + select { + case <-testHookCollectGarbageChan: + case <-time.After(10 * time.Second): + t.Error("collect garbage timeout") + } + gcSize, err := db.gcSize.Get() + if err != nil { + t.Fatal(err) + } + if gcSize == gcTarget { + break + } + } + + t.Run("pull index count", newItemsCountTest(db.pullIndex, int(gcTarget))) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, int(gcTarget))) + + t.Run("gc size", newIndexGCSizeTest(db)) + + // the first synced chunk should be removed + t.Run("get the first synced chunk", func(t *testing.T) { + _, err := db.NewGetter(ModeGetRequest).Get(addrs[0]) + if err != chunk.ErrChunkNotFound { + t.Errorf("got error %v, want %v", err, chunk.ErrChunkNotFound) + } + }) + + // last synced chunk should not be removed + t.Run("get most recent synced chunk", func(t *testing.T) { + _, err := db.NewGetter(ModeGetRequest).Get(addrs[len(addrs)-1]) + if err != nil { + t.Fatal(err) + } + }) +} + +// TestDB_collectGarbageWorker_withRequests is a helper test function +// to test garbage collection runs by uploading, syncing and +// requesting a number of chunks. +func TestDB_collectGarbageWorker_withRequests(t *testing.T) { + db, cleanupFunc := newTestDB(t, &Options{ + Capacity: 100, + }) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + syncer := db.NewSetter(ModeSetSync) + + testHookCollectGarbageChan := make(chan uint64) + defer setTestHookCollectGarbage(func(collectedCount uint64) { + testHookCollectGarbageChan <- collectedCount + })() + + addrs := make([]chunk.Address, 0) + + // upload random chunks just up to the capacity + for i := 0; i < int(db.capacity)-1; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + err = syncer.Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + addrs = append(addrs, chunk.Address()) + } + + // set update gc test hook to signal when + // update gc goroutine is done by closing + // testHookUpdateGCChan channel + testHookUpdateGCChan := make(chan struct{}) + resetTestHookUpdateGC := setTestHookUpdateGC(func() { + close(testHookUpdateGCChan) + }) + + // request the latest synced chunk + // to prioritize it in the gc index + // not to be collected + _, err := db.NewGetter(ModeGetRequest).Get(addrs[0]) + if err != nil { + t.Fatal(err) + } + + // wait for update gc goroutine to finish for garbage + // collector to be correctly triggered after the last upload + select { + case <-testHookUpdateGCChan: + case <-time.After(10 * time.Second): + t.Fatal("updateGC was not called after getting chunk with ModeGetRequest") + } + + // no need to wait for update gc hook anymore + resetTestHookUpdateGC() + + // upload and sync another chunk to trigger + // garbage collection + ch := generateTestRandomChunk() + err = uploader.Put(ch) + if err != nil { + t.Fatal(err) + } + err = syncer.Set(ch.Address()) + if err != nil { + t.Fatal(err) + } + addrs = append(addrs, ch.Address()) + + // wait for garbage collection + + gcTarget := db.gcTarget() + + var totalCollectedCount uint64 + for { + select { + case c := <-testHookCollectGarbageChan: + totalCollectedCount += c + case <-time.After(10 * time.Second): + t.Error("collect garbage timeout") + } + gcSize, err := db.gcSize.Get() + if err != nil { + t.Fatal(err) + } + if gcSize == gcTarget { + break + } + } + + wantTotalCollectedCount := uint64(len(addrs)) - gcTarget + if totalCollectedCount != wantTotalCollectedCount { + t.Errorf("total collected chunks %v, want %v", totalCollectedCount, wantTotalCollectedCount) + } + + t.Run("pull index count", newItemsCountTest(db.pullIndex, int(gcTarget))) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, int(gcTarget))) + + t.Run("gc size", newIndexGCSizeTest(db)) + + // requested chunk should not be removed + t.Run("get requested chunk", func(t *testing.T) { + _, err := db.NewGetter(ModeGetRequest).Get(addrs[0]) + if err != nil { + t.Fatal(err) + } + }) + + // the second synced chunk should be removed + t.Run("get gc-ed chunk", func(t *testing.T) { + _, err := db.NewGetter(ModeGetRequest).Get(addrs[1]) + if err != chunk.ErrChunkNotFound { + t.Errorf("got error %v, want %v", err, chunk.ErrChunkNotFound) + } + }) + + // last synced chunk should not be removed + t.Run("get most recent synced chunk", func(t *testing.T) { + _, err := db.NewGetter(ModeGetRequest).Get(addrs[len(addrs)-1]) + if err != nil { + t.Fatal(err) + } + }) +} + +// TestDB_gcSize checks if gcSize has a correct value after +// database is initialized with existing data. +func TestDB_gcSize(t *testing.T) { + dir, err := ioutil.TempDir("", "localstore-stored-gc-size") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + baseKey := make([]byte, 32) + if _, err := rand.Read(baseKey); err != nil { + t.Fatal(err) + } + db, err := New(dir, baseKey, nil) + if err != nil { + t.Fatal(err) + } + + uploader := db.NewPutter(ModePutUpload) + syncer := db.NewSetter(ModeSetSync) + + count := 100 + + for i := 0; i < count; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + err = syncer.Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + } + + if err := db.Close(); err != nil { + t.Fatal(err) + } + + db, err = New(dir, baseKey, nil) + if err != nil { + t.Fatal(err) + } + defer db.Close() + + t.Run("gc index size", newIndexGCSizeTest(db)) +} + +// setTestHookCollectGarbage sets testHookCollectGarbage and +// returns a function that will reset it to the +// value before the change. +func setTestHookCollectGarbage(h func(collectedCount uint64)) (reset func()) { + current := testHookCollectGarbage + reset = func() { testHookCollectGarbage = current } + testHookCollectGarbage = h + return reset +} + +// TestSetTestHookCollectGarbage tests if setTestHookCollectGarbage changes +// testHookCollectGarbage function correctly and if its reset function +// resets the original function. +func TestSetTestHookCollectGarbage(t *testing.T) { + // Set the current function after the test finishes. + defer func(h func(collectedCount uint64)) { testHookCollectGarbage = h }(testHookCollectGarbage) + + // expected value for the unchanged function + original := 1 + // expected value for the changed function + changed := 2 + + // this variable will be set with two different functions + var got int + + // define the original (unchanged) functions + testHookCollectGarbage = func(_ uint64) { + got = original + } + + // set got variable + testHookCollectGarbage(0) + + // test if got variable is set correctly + if got != original { + t.Errorf("got hook value %v, want %v", got, original) + } + + // set the new function + reset := setTestHookCollectGarbage(func(_ uint64) { + got = changed + }) + + // set got variable + testHookCollectGarbage(0) + + // test if got variable is set correctly to changed value + if got != changed { + t.Errorf("got hook value %v, want %v", got, changed) + } + + // set the function to the original one + reset() + + // set got variable + testHookCollectGarbage(0) + + // test if got variable is set correctly to original value + if got != original { + t.Errorf("got hook value %v, want %v", got, original) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/index_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/index_test.go new file mode 100644 index 00000000..cf19e4f6 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/index_test.go @@ -0,0 +1,227 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// TestDB_pullIndex validates the ordering of keys in pull index. +// Pull index key contains PO prefix which is calculated from +// DB base key and chunk address. This is not an Item field +// which are checked in Mode tests. +// This test uploads chunks, sorts them in expected order and +// validates that pull index iterator will iterate it the same +// order. +func TestDB_pullIndex(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + chunkCount := 50 + + chunks := make([]testIndexChunk, chunkCount) + + // upload random chunks + for i := 0; i < chunkCount; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + chunks[i] = testIndexChunk{ + Chunk: chunk, + // this timestamp is not the same as in + // the index, but given that uploads + // are sequential and that only ordering + // of events matter, this information is + // sufficient + storeTimestamp: now(), + } + } + + testItemsOrder(t, db.pullIndex, chunks, func(i, j int) (less bool) { + poi := chunk.Proximity(db.baseKey, chunks[i].Address()) + poj := chunk.Proximity(db.baseKey, chunks[j].Address()) + if poi < poj { + return true + } + if poi > poj { + return false + } + if chunks[i].storeTimestamp < chunks[j].storeTimestamp { + return true + } + if chunks[i].storeTimestamp > chunks[j].storeTimestamp { + return false + } + return bytes.Compare(chunks[i].Address(), chunks[j].Address()) == -1 + }) +} + +// TestDB_gcIndex validates garbage collection index by uploading +// a chunk with and performing operations using synced, access and +// request modes. +func TestDB_gcIndex(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + chunkCount := 50 + + chunks := make([]testIndexChunk, chunkCount) + + // upload random chunks + for i := 0; i < chunkCount; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + chunks[i] = testIndexChunk{ + Chunk: chunk, + } + } + + // check if all chunks are stored + newItemsCountTest(db.pullIndex, chunkCount)(t) + + // check that chunks are not collectable for garbage + newItemsCountTest(db.gcIndex, 0)(t) + + // set update gc test hook to signal when + // update gc goroutine is done by sending to + // testHookUpdateGCChan channel, which is + // used to wait for indexes change verifications + testHookUpdateGCChan := make(chan struct{}) + defer setTestHookUpdateGC(func() { + testHookUpdateGCChan <- struct{}{} + })() + + t.Run("request unsynced", func(t *testing.T) { + chunk := chunks[1] + + _, err := db.NewGetter(ModeGetRequest).Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + + // the chunk is not synced + // should not be in the garbace collection index + newItemsCountTest(db.gcIndex, 0)(t) + + newIndexGCSizeTest(db)(t) + }) + + t.Run("sync one chunk", func(t *testing.T) { + chunk := chunks[0] + + err := db.NewSetter(ModeSetSync).Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + // the chunk is synced and should be in gc index + newItemsCountTest(db.gcIndex, 1)(t) + + newIndexGCSizeTest(db)(t) + }) + + t.Run("sync all chunks", func(t *testing.T) { + setter := db.NewSetter(ModeSetSync) + + for i := range chunks { + err := setter.Set(chunks[i].Address()) + if err != nil { + t.Fatal(err) + } + } + + testItemsOrder(t, db.gcIndex, chunks, nil) + + newIndexGCSizeTest(db)(t) + }) + + t.Run("request one chunk", func(t *testing.T) { + i := 6 + + _, err := db.NewGetter(ModeGetRequest).Get(chunks[i].Address()) + if err != nil { + t.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + + // move the chunk to the end of the expected gc + c := chunks[i] + chunks = append(chunks[:i], chunks[i+1:]...) + chunks = append(chunks, c) + + testItemsOrder(t, db.gcIndex, chunks, nil) + + newIndexGCSizeTest(db)(t) + }) + + t.Run("random chunk request", func(t *testing.T) { + requester := db.NewGetter(ModeGetRequest) + + rand.Shuffle(len(chunks), func(i, j int) { + chunks[i], chunks[j] = chunks[j], chunks[i] + }) + + for _, chunk := range chunks { + _, err := requester.Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + } + + testItemsOrder(t, db.gcIndex, chunks, nil) + + newIndexGCSizeTest(db)(t) + }) + + t.Run("remove one chunk", func(t *testing.T) { + i := 3 + + err := db.NewSetter(modeSetRemove).Set(chunks[i].Address()) + if err != nil { + t.Fatal(err) + } + + // remove the chunk from the expected chunks in gc index + chunks = append(chunks[:i], chunks[i+1:]...) + + testItemsOrder(t, db.gcIndex, chunks, nil) + + newIndexGCSizeTest(db)(t) + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/localstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/localstore.go new file mode 100644 index 00000000..98d4c788 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/localstore.go @@ -0,0 +1,360 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "encoding/binary" + "errors" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/ethereum/go-ethereum/swarm/storage/mock" +) + +var ( + // ErrInvalidMode is retuned when an unknown Mode + // is provided to the function. + ErrInvalidMode = errors.New("invalid mode") + // ErrAddressLockTimeout is returned when the same chunk + // is updated in parallel and one of the updates + // takes longer then the configured timeout duration. + ErrAddressLockTimeout = errors.New("address lock timeout") +) + +var ( + // Default value for Capacity DB option. + defaultCapacity uint64 = 5000000 + // Limit the number of goroutines created by Getters + // that call updateGC function. Value 0 sets no limit. + maxParallelUpdateGC = 1000 +) + +// DB is the local store implementation and holds +// database related objects. +type DB struct { + shed *shed.DB + + // schema name of loaded data + schemaName shed.StringField + + // retrieval indexes + retrievalDataIndex shed.Index + retrievalAccessIndex shed.Index + // push syncing index + pushIndex shed.Index + // push syncing subscriptions triggers + pushTriggers []chan struct{} + pushTriggersMu sync.RWMutex + + // pull syncing index + pullIndex shed.Index + // pull syncing subscriptions triggers per bin + pullTriggers map[uint8][]chan struct{} + pullTriggersMu sync.RWMutex + + // garbage collection index + gcIndex shed.Index + + // field that stores number of intems in gc index + gcSize shed.Uint64Field + + // garbage collection is triggered when gcSize exceeds + // the capacity value + capacity uint64 + + // triggers garbage collection event loop + collectGarbageTrigger chan struct{} + + // a buffered channel acting as a semaphore + // to limit the maximal number of goroutines + // created by Getters to call updateGC function + updateGCSem chan struct{} + // a wait group to ensure all updateGC goroutines + // are done before closing the database + updateGCWG sync.WaitGroup + + baseKey []byte + + batchMu sync.Mutex + + // this channel is closed when close function is called + // to terminate other goroutines + close chan struct{} + + // protect Close method from exiting before + // garbage collection and gc size write workers + // are done + collectGarbageWorkerDone chan struct{} +} + +// Options struct holds optional parameters for configuring DB. +type Options struct { + // MockStore is a mock node store that is used to store + // chunk data in a central store. It can be used to reduce + // total storage space requirements in testing large number + // of swarm nodes with chunk data deduplication provided by + // the mock global store. + MockStore *mock.NodeStore + // Capacity is a limit that triggers garbage collection when + // number of items in gcIndex equals or exceeds it. + Capacity uint64 + // MetricsPrefix defines a prefix for metrics names. + MetricsPrefix string +} + +// New returns a new DB. All fields and indexes are initialized +// and possible conflicts with schema from existing database is checked. +// One goroutine for writing batches is created. +func New(path string, baseKey []byte, o *Options) (db *DB, err error) { + if o == nil { + o = new(Options) + } + db = &DB{ + capacity: o.Capacity, + baseKey: baseKey, + // channel collectGarbageTrigger + // needs to be buffered with the size of 1 + // to signal another event if it + // is triggered during already running function + collectGarbageTrigger: make(chan struct{}, 1), + close: make(chan struct{}), + collectGarbageWorkerDone: make(chan struct{}), + } + if db.capacity <= 0 { + db.capacity = defaultCapacity + } + if maxParallelUpdateGC > 0 { + db.updateGCSem = make(chan struct{}, maxParallelUpdateGC) + } + + db.shed, err = shed.NewDB(path, o.MetricsPrefix) + if err != nil { + return nil, err + } + // Identify current storage schema by arbitrary name. + db.schemaName, err = db.shed.NewStringField("schema-name") + if err != nil { + return nil, err + } + // Persist gc size. + db.gcSize, err = db.shed.NewUint64Field("gc-size") + if err != nil { + return nil, err + } + // Functions for retrieval data index. + var ( + encodeValueFunc func(fields shed.Item) (value []byte, err error) + decodeValueFunc func(keyItem shed.Item, value []byte) (e shed.Item, err error) + ) + if o.MockStore != nil { + encodeValueFunc = func(fields shed.Item) (value []byte, err error) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) + err = o.MockStore.Put(fields.Address, fields.Data) + if err != nil { + return nil, err + } + return b, nil + } + decodeValueFunc = func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) + e.Data, err = o.MockStore.Get(keyItem.Address) + return e, err + } + } else { + encodeValueFunc = func(fields shed.Item) (value []byte, err error) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) + value = append(b, fields.Data...) + return value, nil + } + decodeValueFunc = func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) + e.Data = value[8:] + return e, nil + } + } + // Index storing actual chunk address, data and store timestamp. + db.retrievalDataIndex, err = db.shed.NewIndex("Address->StoreTimestamp|Data", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + return fields.Address, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.Address = key + return e, nil + }, + EncodeValue: encodeValueFunc, + DecodeValue: decodeValueFunc, + }) + if err != nil { + return nil, err + } + // Index storing access timestamp for a particular address. + // It is needed in order to update gc index keys for iteration order. + db.retrievalAccessIndex, err = db.shed.NewIndex("Address->AccessTimestamp", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + return fields.Address, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.Address = key + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(fields.AccessTimestamp)) + return b, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + e.AccessTimestamp = int64(binary.BigEndian.Uint64(value)) + return e, nil + }, + }) + if err != nil { + return nil, err + } + // pull index allows history and live syncing per po bin + db.pullIndex, err = db.shed.NewIndex("PO|StoredTimestamp|Hash->nil", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + key = make([]byte, 41) + key[0] = db.po(fields.Address) + binary.BigEndian.PutUint64(key[1:9], uint64(fields.StoreTimestamp)) + copy(key[9:], fields.Address[:]) + return key, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.Address = key[9:] + e.StoreTimestamp = int64(binary.BigEndian.Uint64(key[1:9])) + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + return nil, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + return e, nil + }, + }) + if err != nil { + return nil, err + } + // create a pull syncing triggers used by SubscribePull function + db.pullTriggers = make(map[uint8][]chan struct{}) + // push index contains as yet unsynced chunks + db.pushIndex, err = db.shed.NewIndex("StoredTimestamp|Hash->nil", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + key = make([]byte, 40) + binary.BigEndian.PutUint64(key[:8], uint64(fields.StoreTimestamp)) + copy(key[8:], fields.Address[:]) + return key, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.Address = key[8:] + e.StoreTimestamp = int64(binary.BigEndian.Uint64(key[:8])) + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + return nil, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + return e, nil + }, + }) + if err != nil { + return nil, err + } + // create a push syncing triggers used by SubscribePush function + db.pushTriggers = make([]chan struct{}, 0) + // gc index for removable chunk ordered by ascending last access time + db.gcIndex, err = db.shed.NewIndex("AccessTimestamp|StoredTimestamp|Hash->nil", shed.IndexFuncs{ + EncodeKey: func(fields shed.Item) (key []byte, err error) { + b := make([]byte, 16, 16+len(fields.Address)) + binary.BigEndian.PutUint64(b[:8], uint64(fields.AccessTimestamp)) + binary.BigEndian.PutUint64(b[8:16], uint64(fields.StoreTimestamp)) + key = append(b, fields.Address...) + return key, nil + }, + DecodeKey: func(key []byte) (e shed.Item, err error) { + e.AccessTimestamp = int64(binary.BigEndian.Uint64(key[:8])) + e.StoreTimestamp = int64(binary.BigEndian.Uint64(key[8:16])) + e.Address = key[16:] + return e, nil + }, + EncodeValue: func(fields shed.Item) (value []byte, err error) { + return nil, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + return e, nil + }, + }) + if err != nil { + return nil, err + } + // start garbage collection worker + go db.collectGarbageWorker() + return db, nil +} + +// Close closes the underlying database. +func (db *DB) Close() (err error) { + close(db.close) + db.updateGCWG.Wait() + + // wait for gc worker to + // return before closing the shed + select { + case <-db.collectGarbageWorkerDone: + case <-time.After(5 * time.Second): + log.Error("localstore: collect garbage worker did not return after db close") + } + return db.shed.Close() +} + +// po computes the proximity order between the address +// and database base key. +func (db *DB) po(addr chunk.Address) (bin uint8) { + return uint8(chunk.Proximity(db.baseKey, addr)) +} + +// chunkToItem creates new Item with data provided by the Chunk. +func chunkToItem(ch chunk.Chunk) shed.Item { + return shed.Item{ + Address: ch.Address(), + Data: ch.Data(), + } +} + +// addressToItem creates new Item with a provided address. +func addressToItem(addr chunk.Address) shed.Item { + return shed.Item{ + Address: addr, + } +} + +// now is a helper function that returns a current unix timestamp +// in UTC timezone. +// It is set in the init function for usage in production, and +// optionally overridden in tests for data validation. +var now func() int64 + +func init() { + // set the now function + now = func() (t int64) { + return time.Now().UTC().UnixNano() + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/localstore_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/localstore_test.go new file mode 100644 index 00000000..42e76258 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/localstore_test.go @@ -0,0 +1,454 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "fmt" + "io/ioutil" + "math/rand" + "os" + "runtime" + "sort" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/syndtr/goleveldb/leveldb" +) + +func init() { + // Some of the tests in localstore package rely on the same ordering of + // items uploaded or accessed compared to the ordering of items in indexes + // that contain StoreTimestamp or AccessTimestamp in keys. In tests + // where the same order is required from the database as the order + // in which chunks are put or accessed, if the StoreTimestamp or + // AccessTimestamp are the same for two or more sequential items + // their order in database will be based on the chunk address value, + // in which case the ordering of items/chunks stored in a test slice + // will not be the same. To ensure the same ordering in database on such + // indexes on windows systems, an additional short sleep is added to + // the now function. + if runtime.GOOS == "windows" { + setNow(func() int64 { + time.Sleep(time.Microsecond) + return time.Now().UTC().UnixNano() + }) + } +} + +// TestDB validates if the chunk can be uploaded and +// correctly retrieved. +func TestDB(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + got, err := db.NewGetter(ModeGetRequest).Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(got.Address(), chunk.Address()) { + t.Errorf("got address %x, want %x", got.Address(), chunk.Address()) + } + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Errorf("got data %x, want %x", got.Data(), chunk.Data()) + } +} + +// TestDB_updateGCSem tests maxParallelUpdateGC limit. +// This test temporary sets the limit to a low number, +// makes updateGC function execution time longer by +// setting a custom testHookUpdateGC function with a sleep +// and a count current and maximal number of goroutines. +func TestDB_updateGCSem(t *testing.T) { + updateGCSleep := time.Second + var count int + var max int + var mu sync.Mutex + defer setTestHookUpdateGC(func() { + mu.Lock() + // add to the count of current goroutines + count++ + if count > max { + // set maximal detected numbers of goroutines + max = count + } + mu.Unlock() + + // wait for some time to ensure multiple parallel goroutines + time.Sleep(updateGCSleep) + + mu.Lock() + count-- + mu.Unlock() + })() + + defer func(m int) { maxParallelUpdateGC = m }(maxParallelUpdateGC) + maxParallelUpdateGC = 3 + + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + getter := db.NewGetter(ModeGetRequest) + + // get more chunks then maxParallelUpdateGC + // in time shorter then updateGCSleep + for i := 0; i < 5; i++ { + _, err = getter.Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + } + + if max != maxParallelUpdateGC { + t.Errorf("got max %v, want %v", max, maxParallelUpdateGC) + } +} + +// newTestDB is a helper function that constructs a +// temporary database and returns a cleanup function that must +// be called to remove the data. +func newTestDB(t testing.TB, o *Options) (db *DB, cleanupFunc func()) { + t.Helper() + + dir, err := ioutil.TempDir("", "localstore-test") + if err != nil { + t.Fatal(err) + } + cleanupFunc = func() { os.RemoveAll(dir) } + baseKey := make([]byte, 32) + if _, err := rand.Read(baseKey); err != nil { + t.Fatal(err) + } + db, err = New(dir, baseKey, o) + if err != nil { + cleanupFunc() + t.Fatal(err) + } + cleanupFunc = func() { + err := db.Close() + if err != nil { + t.Error(err) + } + os.RemoveAll(dir) + } + return db, cleanupFunc +} + +func init() { + // needed for generateTestRandomChunk + rand.Seed(time.Now().UnixNano()) +} + +// generateTestRandomChunk generates a Chunk that is not +// valid, but it contains a random key and a random value. +// This function is faster then storage.generateTestRandomChunk +// which generates a valid chunk. +// Some tests in this package do not need valid chunks, just +// random data, and their execution time can be decreased +// using this function. +func generateTestRandomChunk() chunk.Chunk { + data := make([]byte, chunk.DefaultSize) + rand.Read(data) + key := make([]byte, 32) + rand.Read(key) + return chunk.NewChunk(key, data) +} + +// TestGenerateTestRandomChunk validates that +// generateTestRandomChunk returns random data by comparing +// two generated chunks. +func TestGenerateTestRandomChunk(t *testing.T) { + c1 := generateTestRandomChunk() + c2 := generateTestRandomChunk() + addrLen := len(c1.Address()) + if addrLen != 32 { + t.Errorf("first chunk address length %v, want %v", addrLen, 32) + } + dataLen := len(c1.Data()) + if dataLen != chunk.DefaultSize { + t.Errorf("first chunk data length %v, want %v", dataLen, chunk.DefaultSize) + } + addrLen = len(c2.Address()) + if addrLen != 32 { + t.Errorf("second chunk address length %v, want %v", addrLen, 32) + } + dataLen = len(c2.Data()) + if dataLen != chunk.DefaultSize { + t.Errorf("second chunk data length %v, want %v", dataLen, chunk.DefaultSize) + } + if bytes.Equal(c1.Address(), c2.Address()) { + t.Error("fake chunks addresses do not differ") + } + if bytes.Equal(c1.Data(), c2.Data()) { + t.Error("fake chunks data bytes do not differ") + } +} + +// newRetrieveIndexesTest returns a test function that validates if the right +// chunk values are in the retrieval indexes. +func newRetrieveIndexesTest(db *DB, chunk chunk.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) { + return func(t *testing.T) { + item, err := db.retrievalDataIndex.Get(addressToItem(chunk.Address())) + if err != nil { + t.Fatal(err) + } + validateItem(t, item, chunk.Address(), chunk.Data(), storeTimestamp, 0) + + // access index should not be set + wantErr := leveldb.ErrNotFound + item, err = db.retrievalAccessIndex.Get(addressToItem(chunk.Address())) + if err != wantErr { + t.Errorf("got error %v, want %v", err, wantErr) + } + } +} + +// newRetrieveIndexesTestWithAccess returns a test function that validates if the right +// chunk values are in the retrieval indexes when access time must be stored. +func newRetrieveIndexesTestWithAccess(db *DB, chunk chunk.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) { + return func(t *testing.T) { + item, err := db.retrievalDataIndex.Get(addressToItem(chunk.Address())) + if err != nil { + t.Fatal(err) + } + validateItem(t, item, chunk.Address(), chunk.Data(), storeTimestamp, 0) + + if accessTimestamp > 0 { + item, err = db.retrievalAccessIndex.Get(addressToItem(chunk.Address())) + if err != nil { + t.Fatal(err) + } + validateItem(t, item, chunk.Address(), nil, 0, accessTimestamp) + } + } +} + +// newPullIndexTest returns a test function that validates if the right +// chunk values are in the pull index. +func newPullIndexTest(db *DB, chunk chunk.Chunk, storeTimestamp int64, wantError error) func(t *testing.T) { + return func(t *testing.T) { + item, err := db.pullIndex.Get(shed.Item{ + Address: chunk.Address(), + StoreTimestamp: storeTimestamp, + }) + if err != wantError { + t.Errorf("got error %v, want %v", err, wantError) + } + if err == nil { + validateItem(t, item, chunk.Address(), nil, storeTimestamp, 0) + } + } +} + +// newPushIndexTest returns a test function that validates if the right +// chunk values are in the push index. +func newPushIndexTest(db *DB, chunk chunk.Chunk, storeTimestamp int64, wantError error) func(t *testing.T) { + return func(t *testing.T) { + item, err := db.pushIndex.Get(shed.Item{ + Address: chunk.Address(), + StoreTimestamp: storeTimestamp, + }) + if err != wantError { + t.Errorf("got error %v, want %v", err, wantError) + } + if err == nil { + validateItem(t, item, chunk.Address(), nil, storeTimestamp, 0) + } + } +} + +// newGCIndexTest returns a test function that validates if the right +// chunk values are in the push index. +func newGCIndexTest(db *DB, chunk chunk.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) { + return func(t *testing.T) { + item, err := db.gcIndex.Get(shed.Item{ + Address: chunk.Address(), + StoreTimestamp: storeTimestamp, + AccessTimestamp: accessTimestamp, + }) + if err != nil { + t.Fatal(err) + } + validateItem(t, item, chunk.Address(), nil, storeTimestamp, accessTimestamp) + } +} + +// newItemsCountTest returns a test function that validates if +// an index contains expected number of key/value pairs. +func newItemsCountTest(i shed.Index, want int) func(t *testing.T) { + return func(t *testing.T) { + var c int + err := i.Iterate(func(item shed.Item) (stop bool, err error) { + c++ + return + }, nil) + if err != nil { + t.Fatal(err) + } + if c != want { + t.Errorf("got %v items in index, want %v", c, want) + } + } +} + +// newIndexGCSizeTest retruns a test function that validates if DB.gcSize +// value is the same as the number of items in DB.gcIndex. +func newIndexGCSizeTest(db *DB) func(t *testing.T) { + return func(t *testing.T) { + var want uint64 + err := db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { + want++ + return + }, nil) + if err != nil { + t.Fatal(err) + } + got, err := db.gcSize.Get() + if err != nil { + t.Fatal(err) + } + if got != want { + t.Errorf("got gc size %v, want %v", got, want) + } + } +} + +// testIndexChunk embeds storageChunk with additional data that is stored +// in database. It is used for index values validations. +type testIndexChunk struct { + chunk.Chunk + storeTimestamp int64 +} + +// testItemsOrder tests the order of chunks in the index. If sortFunc is not nil, +// chunks will be sorted with it before validation. +func testItemsOrder(t *testing.T, i shed.Index, chunks []testIndexChunk, sortFunc func(i, j int) (less bool)) { + newItemsCountTest(i, len(chunks))(t) + + if sortFunc != nil { + sort.Slice(chunks, sortFunc) + } + + var cursor int + err := i.Iterate(func(item shed.Item) (stop bool, err error) { + want := chunks[cursor].Address() + got := item.Address + if !bytes.Equal(got, want) { + return true, fmt.Errorf("got address %x at position %v, want %x", got, cursor, want) + } + cursor++ + return false, nil + }, nil) + if err != nil { + t.Fatal(err) + } +} + +// validateItem is a helper function that checks Item values. +func validateItem(t *testing.T, item shed.Item, address, data []byte, storeTimestamp, accessTimestamp int64) { + t.Helper() + + if !bytes.Equal(item.Address, address) { + t.Errorf("got item address %x, want %x", item.Address, address) + } + if !bytes.Equal(item.Data, data) { + t.Errorf("got item data %x, want %x", item.Data, data) + } + if item.StoreTimestamp != storeTimestamp { + t.Errorf("got item store timestamp %v, want %v", item.StoreTimestamp, storeTimestamp) + } + if item.AccessTimestamp != accessTimestamp { + t.Errorf("got item access timestamp %v, want %v", item.AccessTimestamp, accessTimestamp) + } +} + +// setNow replaces now function and +// returns a function that will reset it to the +// value before the change. +func setNow(f func() int64) (reset func()) { + current := now + reset = func() { now = current } + now = f + return reset +} + +// TestSetNow tests if setNow function changes now function +// correctly and if its reset function resets the original function. +func TestSetNow(t *testing.T) { + // set the current function after the test finishes + defer func(f func() int64) { now = f }(now) + + // expected value for the unchanged function + var original int64 = 1 + // expected value for the changed function + var changed int64 = 2 + + // define the original (unchanged) functions + now = func() int64 { + return original + } + + // get the time + got := now() + + // test if got variable is set correctly + if got != original { + t.Errorf("got now value %v, want %v", got, original) + } + + // set the new function + reset := setNow(func() int64 { + return changed + }) + + // get the time + got = now() + + // test if got variable is set correctly to changed value + if got != changed { + t.Errorf("got hook value %v, want %v", got, changed) + } + + // set the function to the original one + reset() + + // get the time + got = now() + + // test if got variable is set correctly to original value + if got != original { + t.Errorf("got hook value %v, want %v", got, original) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_get.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_get.go new file mode 100644 index 00000000..a6353e14 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_get.go @@ -0,0 +1,151 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/syndtr/goleveldb/leveldb" +) + +// ModeGet enumerates different Getter modes. +type ModeGet int + +// Getter modes. +const ( + // ModeGetRequest: when accessed for retrieval + ModeGetRequest ModeGet = iota + // ModeGetSync: when accessed for syncing or proof of custody request + ModeGetSync +) + +// Getter provides Get method to retrieve Chunks +// from database. +type Getter struct { + db *DB + mode ModeGet +} + +// NewGetter returns a new Getter on database +// with a specific Mode. +func (db *DB) NewGetter(mode ModeGet) *Getter { + return &Getter{ + mode: mode, + db: db, + } +} + +// Get returns a chunk from the database. If the chunk is +// not found chunk.ErrChunkNotFound will be returned. +// All required indexes will be updated required by the +// Getter Mode. +func (g *Getter) Get(addr chunk.Address) (ch chunk.Chunk, err error) { + out, err := g.db.get(g.mode, addr) + if err != nil { + if err == leveldb.ErrNotFound { + return nil, chunk.ErrChunkNotFound + } + return nil, err + } + return chunk.NewChunk(out.Address, out.Data), nil +} + +// get returns Item from the retrieval index +// and updates other indexes. +func (db *DB) get(mode ModeGet, addr chunk.Address) (out shed.Item, err error) { + item := addressToItem(addr) + + out, err = db.retrievalDataIndex.Get(item) + if err != nil { + return out, err + } + switch mode { + // update the access timestamp and gc index + case ModeGetRequest: + if db.updateGCSem != nil { + // wait before creating new goroutines + // if updateGCSem buffer id full + db.updateGCSem <- struct{}{} + } + db.updateGCWG.Add(1) + go func() { + defer db.updateGCWG.Done() + if db.updateGCSem != nil { + // free a spot in updateGCSem buffer + // for a new goroutine + defer func() { <-db.updateGCSem }() + } + err := db.updateGC(out) + if err != nil { + log.Error("localstore update gc", "err", err) + } + // if gc update hook is defined, call it + if testHookUpdateGC != nil { + testHookUpdateGC() + } + }() + + // no updates to indexes + case ModeGetSync: + default: + return out, ErrInvalidMode + } + return out, nil +} + +// updateGC updates garbage collection index for +// a single item. Provided item is expected to have +// only Address and Data fields with non zero values, +// which is ensured by the get function. +func (db *DB) updateGC(item shed.Item) (err error) { + db.batchMu.Lock() + defer db.batchMu.Unlock() + + batch := new(leveldb.Batch) + + // update accessTimeStamp in retrieve, gc + + i, err := db.retrievalAccessIndex.Get(item) + switch err { + case nil: + item.AccessTimestamp = i.AccessTimestamp + case leveldb.ErrNotFound: + // no chunk accesses + default: + return err + } + if item.AccessTimestamp == 0 { + // chunk is not yet synced + // do not add it to the gc index + return nil + } + // delete current entry from the gc index + db.gcIndex.DeleteInBatch(batch, item) + // update access timestamp + item.AccessTimestamp = now() + // update retrieve access index + db.retrievalAccessIndex.PutInBatch(batch, item) + // add new entry to gc index + db.gcIndex.PutInBatch(batch, item) + + return db.shed.WriteBatch(batch) +} + +// testHookUpdateGC is a hook that can provide +// information when a garbage collection index is updated. +var testHookUpdateGC func() diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_get_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_get_test.go new file mode 100644 index 00000000..28a70ee0 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_get_test.go @@ -0,0 +1,237 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "testing" + "time" +) + +// TestModeGetRequest validates ModeGetRequest index values on the provided DB. +func TestModeGetRequest(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploadTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return uploadTimestamp + })() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + requester := db.NewGetter(ModeGetRequest) + + // set update gc test hook to signal when + // update gc goroutine is done by sending to + // testHookUpdateGCChan channel, which is + // used to wait for garbage colletion index + // changes + testHookUpdateGCChan := make(chan struct{}) + defer setTestHookUpdateGC(func() { + testHookUpdateGCChan <- struct{}{} + })() + + t.Run("get unsynced", func(t *testing.T) { + got, err := requester.Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + + if !bytes.Equal(got.Address(), chunk.Address()) { + t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address()) + } + + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data()) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 0)) + + t.Run("gc size", newIndexGCSizeTest(db)) + }) + + // set chunk to synced state + err = db.NewSetter(ModeSetSync).Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + t.Run("first get", func(t *testing.T) { + got, err := requester.Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + + if !bytes.Equal(got.Address(), chunk.Address()) { + t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address()) + } + + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data()) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, uploadTimestamp)) + + t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, uploadTimestamp)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) + + t.Run("gc size", newIndexGCSizeTest(db)) + }) + + t.Run("second get", func(t *testing.T) { + accessTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return accessTimestamp + })() + + got, err := requester.Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + + if !bytes.Equal(got.Address(), chunk.Address()) { + t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address()) + } + + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data()) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, accessTimestamp)) + + t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, accessTimestamp)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) + + t.Run("gc size", newIndexGCSizeTest(db)) + }) +} + +// TestModeGetSync validates ModeGetSync index values on the provided DB. +func TestModeGetSync(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploadTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return uploadTimestamp + })() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + got, err := db.NewGetter(ModeGetSync).Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(got.Address(), chunk.Address()) { + t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address()) + } + + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data()) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 0)) + + t.Run("gc size", newIndexGCSizeTest(db)) +} + +// setTestHookUpdateGC sets testHookUpdateGC and +// returns a function that will reset it to the +// value before the change. +func setTestHookUpdateGC(h func()) (reset func()) { + current := testHookUpdateGC + reset = func() { testHookUpdateGC = current } + testHookUpdateGC = h + return reset +} + +// TestSetTestHookUpdateGC tests if setTestHookUpdateGC changes +// testHookUpdateGC function correctly and if its reset function +// resets the original function. +func TestSetTestHookUpdateGC(t *testing.T) { + // Set the current function after the test finishes. + defer func(h func()) { testHookUpdateGC = h }(testHookUpdateGC) + + // expected value for the unchanged function + original := 1 + // expected value for the changed function + changed := 2 + + // this variable will be set with two different functions + var got int + + // define the original (unchanged) functions + testHookUpdateGC = func() { + got = original + } + + // set got variable + testHookUpdateGC() + + // test if got variable is set correctly + if got != original { + t.Errorf("got hook value %v, want %v", got, original) + } + + // set the new function + reset := setTestHookUpdateGC(func() { + got = changed + }) + + // set got variable + testHookUpdateGC() + + // test if got variable is set correctly to changed value + if got != changed { + t.Errorf("got hook value %v, want %v", got, changed) + } + + // set the function to the original one + reset() + + // set got variable + testHookUpdateGC() + + // test if got variable is set correctly to original value + if got != original { + t.Errorf("got hook value %v, want %v", got, original) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_has.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_has.go new file mode 100644 index 00000000..90feacee --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_has.go @@ -0,0 +1,39 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// Hasser provides Has method to retrieve Chunks +// from database. +type Hasser struct { + db *DB +} + +// NewHasser returns a new Hasser on database. +func (db *DB) NewHasser() *Hasser { + return &Hasser{ + db: db, + } +} + +// Has returns true if the chunk is stored in database. +func (h *Hasser) Has(addr chunk.Address) (bool, error) { + return h.db.retrievalDataIndex.Has(addressToItem(addr)) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/api/testapi.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_has_test.go similarity index 51% rename from vendor/github.com/ethereum/go-ethereum/swarm/api/testapi.go rename to vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_has_test.go index 4c7d0982..332616ca 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/api/testapi.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_has_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,33 +14,42 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package api +package localstore import ( - "github.com/ethereum/go-ethereum/swarm/network" + "testing" ) -type Control struct { - api *API - hive *network.Hive -} +// TestHas validates that Hasser is returning true for +// the stored chunk and false for one that is not stored. +func TestHas(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() -func NewControl(api *API, hive *network.Hive) *Control { - return &Control{api, hive} -} + chunk := generateTestRandomChunk() -//func (self *Control) BlockNetworkRead(on bool) { -// self.hive.BlockNetworkRead(on) -//} -// -//func (self *Control) SyncEnabled(on bool) { -// self.hive.SyncEnabled(on) -//} -// -//func (self *Control) SwapEnabled(on bool) { -// self.hive.SwapEnabled(on) -//} -// -func (c *Control) Hive() string { - return c.hive.String() + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + hasser := db.NewHasser() + + has, err := hasser.Has(chunk.Address()) + if err != nil { + t.Fatal(err) + } + if !has { + t.Error("chunk not found") + } + + missingChunk := generateTestRandomChunk() + + has, err = hasser.Has(missingChunk.Address()) + if err != nil { + t.Fatal(err) + } + if has { + t.Error("unexpected chunk is found") + } } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_put.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_put.go new file mode 100644 index 00000000..1599ca8e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_put.go @@ -0,0 +1,158 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/syndtr/goleveldb/leveldb" +) + +// ModePut enumerates different Putter modes. +type ModePut int + +// Putter modes. +const ( + // ModePutRequest: when a chunk is received as a result of retrieve request and delivery + ModePutRequest ModePut = iota + // ModePutSync: when a chunk is received via syncing + ModePutSync + // ModePutUpload: when a chunk is created by local upload + ModePutUpload +) + +// Putter provides Put method to store Chunks +// to database. +type Putter struct { + db *DB + mode ModePut +} + +// NewPutter returns a new Putter on database +// with a specific Mode. +func (db *DB) NewPutter(mode ModePut) *Putter { + return &Putter{ + mode: mode, + db: db, + } +} + +// Put stores the Chunk to database and depending +// on the Putter mode, it updates required indexes. +func (p *Putter) Put(ch chunk.Chunk) (err error) { + return p.db.put(p.mode, chunkToItem(ch)) +} + +// put stores Item to database and updates other +// indexes. It acquires lockAddr to protect two calls +// of this function for the same address in parallel. +// Item fields Address and Data must not be +// with their nil values. +func (db *DB) put(mode ModePut, item shed.Item) (err error) { + // protect parallel updates + db.batchMu.Lock() + defer db.batchMu.Unlock() + + batch := new(leveldb.Batch) + + // variables that provide information for operations + // to be done after write batch function successfully executes + var gcSizeChange int64 // number to add or subtract from gcSize + var triggerPullFeed bool // signal pull feed subscriptions to iterate + var triggerPushFeed bool // signal push feed subscriptions to iterate + + switch mode { + case ModePutRequest: + // put to indexes: retrieve, gc; it does not enter the syncpool + + // check if the chunk already is in the database + // as gc index is updated + i, err := db.retrievalAccessIndex.Get(item) + switch err { + case nil: + item.AccessTimestamp = i.AccessTimestamp + case leveldb.ErrNotFound: + // no chunk accesses + default: + return err + } + i, err = db.retrievalDataIndex.Get(item) + switch err { + case nil: + item.StoreTimestamp = i.StoreTimestamp + case leveldb.ErrNotFound: + // no chunk accesses + default: + return err + } + if item.AccessTimestamp != 0 { + // delete current entry from the gc index + db.gcIndex.DeleteInBatch(batch, item) + gcSizeChange-- + } + if item.StoreTimestamp == 0 { + item.StoreTimestamp = now() + } + // update access timestamp + item.AccessTimestamp = now() + // update retrieve access index + db.retrievalAccessIndex.PutInBatch(batch, item) + // add new entry to gc index + db.gcIndex.PutInBatch(batch, item) + gcSizeChange++ + + db.retrievalDataIndex.PutInBatch(batch, item) + + case ModePutUpload: + // put to indexes: retrieve, push, pull + + item.StoreTimestamp = now() + db.retrievalDataIndex.PutInBatch(batch, item) + db.pullIndex.PutInBatch(batch, item) + triggerPullFeed = true + db.pushIndex.PutInBatch(batch, item) + triggerPushFeed = true + + case ModePutSync: + // put to indexes: retrieve, pull + + item.StoreTimestamp = now() + db.retrievalDataIndex.PutInBatch(batch, item) + db.pullIndex.PutInBatch(batch, item) + triggerPullFeed = true + + default: + return ErrInvalidMode + } + + err = db.incGCSizeInBatch(batch, gcSizeChange) + if err != nil { + return err + } + + err = db.shed.WriteBatch(batch) + if err != nil { + return err + } + if triggerPullFeed { + db.triggerPullSubscriptions(db.po(item.Address)) + } + if triggerPushFeed { + db.triggerPushSubscriptions() + } + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_put_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_put_test.go new file mode 100644 index 00000000..8ecae1d2 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_put_test.go @@ -0,0 +1,300 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "fmt" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// TestModePutRequest validates ModePutRequest index values on the provided DB. +func TestModePutRequest(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + putter := db.NewPutter(ModePutRequest) + + chunk := generateTestRandomChunk() + + // keep the record when the chunk is stored + var storeTimestamp int64 + + t.Run("first put", func(t *testing.T) { + wantTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return wantTimestamp + })() + + storeTimestamp = wantTimestamp + + err := putter.Put(chunk) + if err != nil { + t.Fatal(err) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, wantTimestamp, wantTimestamp)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) + + t.Run("gc size", newIndexGCSizeTest(db)) + }) + + t.Run("second put", func(t *testing.T) { + wantTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return wantTimestamp + })() + + err := putter.Put(chunk) + if err != nil { + t.Fatal(err) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, storeTimestamp, wantTimestamp)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) + + t.Run("gc size", newIndexGCSizeTest(db)) + }) +} + +// TestModePutSync validates ModePutSync index values on the provided DB. +func TestModePutSync(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + wantTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return wantTimestamp + })() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutSync).Put(chunk) + if err != nil { + t.Fatal(err) + } + + t.Run("retrieve indexes", newRetrieveIndexesTest(db, chunk, wantTimestamp, 0)) + + t.Run("pull index", newPullIndexTest(db, chunk, wantTimestamp, nil)) +} + +// TestModePutUpload validates ModePutUpload index values on the provided DB. +func TestModePutUpload(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + wantTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return wantTimestamp + })() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + t.Run("retrieve indexes", newRetrieveIndexesTest(db, chunk, wantTimestamp, 0)) + + t.Run("pull index", newPullIndexTest(db, chunk, wantTimestamp, nil)) + + t.Run("push index", newPushIndexTest(db, chunk, wantTimestamp, nil)) +} + +// TestModePutUpload_parallel uploads chunks in parallel +// and validates if all chunks can be retrieved with correct data. +func TestModePutUpload_parallel(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + chunkCount := 1000 + workerCount := 100 + + chunkChan := make(chan chunk.Chunk) + errChan := make(chan error) + doneChan := make(chan struct{}) + defer close(doneChan) + + // start uploader workers + for i := 0; i < workerCount; i++ { + go func(i int) { + uploader := db.NewPutter(ModePutUpload) + for { + select { + case chunk, ok := <-chunkChan: + if !ok { + return + } + err := uploader.Put(chunk) + select { + case errChan <- err: + case <-doneChan: + } + case <-doneChan: + return + } + } + }(i) + } + + chunks := make([]chunk.Chunk, 0) + var chunksMu sync.Mutex + + // send chunks to workers + go func() { + for i := 0; i < chunkCount; i++ { + chunk := generateTestRandomChunk() + select { + case chunkChan <- chunk: + case <-doneChan: + return + } + chunksMu.Lock() + chunks = append(chunks, chunk) + chunksMu.Unlock() + } + + close(chunkChan) + }() + + // validate every error from workers + for i := 0; i < chunkCount; i++ { + err := <-errChan + if err != nil { + t.Fatal(err) + } + } + + // get every chunk and validate its data + getter := db.NewGetter(ModeGetRequest) + + chunksMu.Lock() + defer chunksMu.Unlock() + for _, chunk := range chunks { + got, err := getter.Get(chunk.Address()) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Fatalf("got chunk %s data %x, want %x", chunk.Address().Hex(), got.Data(), chunk.Data()) + } + } +} + +// BenchmarkPutUpload runs a series of benchmarks that upload +// a specific number of chunks in parallel. +// +// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014) +// +// # go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkPutUpload -v +// +// goos: darwin +// goarch: amd64 +// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore +// BenchmarkPutUpload/count_100_parallel_1-8 300 5107704 ns/op 2081461 B/op 2374 allocs/op +// BenchmarkPutUpload/count_100_parallel_2-8 300 5411742 ns/op 2081608 B/op 2364 allocs/op +// BenchmarkPutUpload/count_100_parallel_4-8 500 3704964 ns/op 2081696 B/op 2324 allocs/op +// BenchmarkPutUpload/count_100_parallel_8-8 500 2932663 ns/op 2082594 B/op 2295 allocs/op +// BenchmarkPutUpload/count_100_parallel_16-8 500 3117157 ns/op 2085438 B/op 2282 allocs/op +// BenchmarkPutUpload/count_100_parallel_32-8 500 3449122 ns/op 2089721 B/op 2286 allocs/op +// BenchmarkPutUpload/count_1000_parallel_1-8 20 79784470 ns/op 25211240 B/op 23225 allocs/op +// BenchmarkPutUpload/count_1000_parallel_2-8 20 75422164 ns/op 25210730 B/op 23187 allocs/op +// BenchmarkPutUpload/count_1000_parallel_4-8 20 70698378 ns/op 25206522 B/op 22692 allocs/op +// BenchmarkPutUpload/count_1000_parallel_8-8 20 71285528 ns/op 25213436 B/op 22345 allocs/op +// BenchmarkPutUpload/count_1000_parallel_16-8 20 71301826 ns/op 25205040 B/op 22090 allocs/op +// BenchmarkPutUpload/count_1000_parallel_32-8 30 57713506 ns/op 25219781 B/op 21848 allocs/op +// BenchmarkPutUpload/count_10000_parallel_1-8 2 656719345 ns/op 216792908 B/op 248940 allocs/op +// BenchmarkPutUpload/count_10000_parallel_2-8 2 646301962 ns/op 216730800 B/op 248270 allocs/op +// BenchmarkPutUpload/count_10000_parallel_4-8 2 532784228 ns/op 216667080 B/op 241910 allocs/op +// BenchmarkPutUpload/count_10000_parallel_8-8 3 494290188 ns/op 216297749 B/op 236247 allocs/op +// BenchmarkPutUpload/count_10000_parallel_16-8 3 483485315 ns/op 216060384 B/op 231090 allocs/op +// BenchmarkPutUpload/count_10000_parallel_32-8 3 434461294 ns/op 215371280 B/op 224800 allocs/op +// BenchmarkPutUpload/count_100000_parallel_1-8 1 22767894338 ns/op 2331372088 B/op 4049876 allocs/op +// BenchmarkPutUpload/count_100000_parallel_2-8 1 25347872677 ns/op 2344140160 B/op 4106763 allocs/op +// BenchmarkPutUpload/count_100000_parallel_4-8 1 23580460174 ns/op 2338582576 B/op 4027452 allocs/op +// BenchmarkPutUpload/count_100000_parallel_8-8 1 22197559193 ns/op 2321803496 B/op 3877553 allocs/op +// BenchmarkPutUpload/count_100000_parallel_16-8 1 22527046476 ns/op 2327854800 B/op 3885455 allocs/op +// BenchmarkPutUpload/count_100000_parallel_32-8 1 21332243613 ns/op 2299654568 B/op 3697181 allocs/op +// PASS +func BenchmarkPutUpload(b *testing.B) { + for _, count := range []int{ + 100, + 1000, + 10000, + 100000, + } { + for _, maxParallelUploads := range []int{ + 1, + 2, + 4, + 8, + 16, + 32, + } { + name := fmt.Sprintf("count %v parallel %v", count, maxParallelUploads) + b.Run(name, func(b *testing.B) { + for n := 0; n < b.N; n++ { + benchmarkPutUpload(b, nil, count, maxParallelUploads) + } + }) + } + } +} + +// benchmarkPutUpload runs a benchmark by uploading a specific number +// of chunks with specified max parallel uploads. +func benchmarkPutUpload(b *testing.B, o *Options, count, maxParallelUploads int) { + b.StopTimer() + db, cleanupFunc := newTestDB(b, o) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + chunks := make([]chunk.Chunk, count) + for i := 0; i < count; i++ { + chunks[i] = generateTestRandomChunk() + } + errs := make(chan error) + b.StartTimer() + + go func() { + sem := make(chan struct{}, maxParallelUploads) + for i := 0; i < count; i++ { + sem <- struct{}{} + + go func(i int) { + defer func() { <-sem }() + + errs <- uploader.Put(chunks[i]) + }(i) + } + }() + + for i := 0; i < count; i++ { + err := <-errs + if err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_set.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_set.go new file mode 100644 index 00000000..83fcbea5 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_set.go @@ -0,0 +1,201 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/syndtr/goleveldb/leveldb" +) + +// ModeSet enumerates different Setter modes. +type ModeSet int + +// Setter modes. +const ( + // ModeSetAccess: when an update request is received for a chunk or chunk is retrieved for delivery + ModeSetAccess ModeSet = iota + // ModeSetSync: when push sync receipt is received + ModeSetSync + // modeSetRemove: when GC-d + // unexported as no external packages should remove chunks from database + modeSetRemove +) + +// Setter sets the state of a particular +// Chunk in database by changing indexes. +type Setter struct { + db *DB + mode ModeSet +} + +// NewSetter returns a new Setter on database +// with a specific Mode. +func (db *DB) NewSetter(mode ModeSet) *Setter { + return &Setter{ + mode: mode, + db: db, + } +} + +// Set updates database indexes for a specific +// chunk represented by the address. +func (s *Setter) Set(addr chunk.Address) (err error) { + return s.db.set(s.mode, addr) +} + +// set updates database indexes for a specific +// chunk represented by the address. +// It acquires lockAddr to protect two calls +// of this function for the same address in parallel. +func (db *DB) set(mode ModeSet, addr chunk.Address) (err error) { + // protect parallel updates + db.batchMu.Lock() + defer db.batchMu.Unlock() + + batch := new(leveldb.Batch) + + // variables that provide information for operations + // to be done after write batch function successfully executes + var gcSizeChange int64 // number to add or subtract from gcSize + var triggerPullFeed bool // signal pull feed subscriptions to iterate + + item := addressToItem(addr) + + switch mode { + case ModeSetAccess: + // add to pull, insert to gc + + // need to get access timestamp here as it is not + // provided by the access function, and it is not + // a property of a chunk provided to Accessor.Put. + + i, err := db.retrievalDataIndex.Get(item) + switch err { + case nil: + item.StoreTimestamp = i.StoreTimestamp + case leveldb.ErrNotFound: + db.pushIndex.DeleteInBatch(batch, item) + item.StoreTimestamp = now() + default: + return err + } + + i, err = db.retrievalAccessIndex.Get(item) + switch err { + case nil: + item.AccessTimestamp = i.AccessTimestamp + db.gcIndex.DeleteInBatch(batch, item) + gcSizeChange-- + case leveldb.ErrNotFound: + // the chunk is not accessed before + default: + return err + } + item.AccessTimestamp = now() + db.retrievalAccessIndex.PutInBatch(batch, item) + db.pullIndex.PutInBatch(batch, item) + triggerPullFeed = true + db.gcIndex.PutInBatch(batch, item) + gcSizeChange++ + + case ModeSetSync: + // delete from push, insert to gc + + // need to get access timestamp here as it is not + // provided by the access function, and it is not + // a property of a chunk provided to Accessor.Put. + i, err := db.retrievalDataIndex.Get(item) + if err != nil { + if err == leveldb.ErrNotFound { + // chunk is not found, + // no need to update gc index + // just delete from the push index + // if it is there + db.pushIndex.DeleteInBatch(batch, item) + return nil + } + return err + } + item.StoreTimestamp = i.StoreTimestamp + + i, err = db.retrievalAccessIndex.Get(item) + switch err { + case nil: + item.AccessTimestamp = i.AccessTimestamp + db.gcIndex.DeleteInBatch(batch, item) + gcSizeChange-- + case leveldb.ErrNotFound: + // the chunk is not accessed before + default: + return err + } + item.AccessTimestamp = now() + db.retrievalAccessIndex.PutInBatch(batch, item) + db.pushIndex.DeleteInBatch(batch, item) + db.gcIndex.PutInBatch(batch, item) + gcSizeChange++ + + case modeSetRemove: + // delete from retrieve, pull, gc + + // need to get access timestamp here as it is not + // provided by the access function, and it is not + // a property of a chunk provided to Accessor.Put. + + i, err := db.retrievalAccessIndex.Get(item) + switch err { + case nil: + item.AccessTimestamp = i.AccessTimestamp + case leveldb.ErrNotFound: + default: + return err + } + i, err = db.retrievalDataIndex.Get(item) + if err != nil { + return err + } + item.StoreTimestamp = i.StoreTimestamp + + db.retrievalDataIndex.DeleteInBatch(batch, item) + db.retrievalAccessIndex.DeleteInBatch(batch, item) + db.pullIndex.DeleteInBatch(batch, item) + db.gcIndex.DeleteInBatch(batch, item) + // a check is needed for decrementing gcSize + // as delete is not reporting if the key/value pair + // is deleted or not + if _, err := db.gcIndex.Get(item); err == nil { + gcSizeChange = -1 + } + + default: + return ErrInvalidMode + } + + err = db.incGCSizeInBatch(batch, gcSizeChange) + if err != nil { + return err + } + + err = db.shed.WriteBatch(batch) + if err != nil { + return err + } + if triggerPullFeed { + db.triggerPullSubscriptions(db.po(item.Address)) + } + return nil +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_set_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_set_test.go new file mode 100644 index 00000000..674aaabe --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/mode_set_test.go @@ -0,0 +1,128 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "testing" + "time" + + "github.com/syndtr/goleveldb/leveldb" +) + +// TestModeSetAccess validates ModeSetAccess index values on the provided DB. +func TestModeSetAccess(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + chunk := generateTestRandomChunk() + + wantTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return wantTimestamp + })() + + err := db.NewSetter(ModeSetAccess).Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + t.Run("pull index", newPullIndexTest(db, chunk, wantTimestamp, nil)) + + t.Run("pull index count", newItemsCountTest(db.pullIndex, 1)) + + t.Run("gc index", newGCIndexTest(db, chunk, wantTimestamp, wantTimestamp)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) + + t.Run("gc size", newIndexGCSizeTest(db)) +} + +// TestModeSetSync validates ModeSetSync index values on the provided DB. +func TestModeSetSync(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + chunk := generateTestRandomChunk() + + wantTimestamp := time.Now().UTC().UnixNano() + defer setNow(func() (t int64) { + return wantTimestamp + })() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + err = db.NewSetter(ModeSetSync).Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, wantTimestamp, wantTimestamp)) + + t.Run("push index", newPushIndexTest(db, chunk, wantTimestamp, leveldb.ErrNotFound)) + + t.Run("gc index", newGCIndexTest(db, chunk, wantTimestamp, wantTimestamp)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) + + t.Run("gc size", newIndexGCSizeTest(db)) +} + +// TestModeSetRemove validates ModeSetRemove index values on the provided DB. +func TestModeSetRemove(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + chunk := generateTestRandomChunk() + + err := db.NewPutter(ModePutUpload).Put(chunk) + if err != nil { + t.Fatal(err) + } + + err = db.NewSetter(modeSetRemove).Set(chunk.Address()) + if err != nil { + t.Fatal(err) + } + + t.Run("retrieve indexes", func(t *testing.T) { + wantErr := leveldb.ErrNotFound + _, err := db.retrievalDataIndex.Get(addressToItem(chunk.Address())) + if err != wantErr { + t.Errorf("got error %v, want %v", err, wantErr) + } + t.Run("retrieve data index count", newItemsCountTest(db.retrievalDataIndex, 0)) + + // access index should not be set + _, err = db.retrievalAccessIndex.Get(addressToItem(chunk.Address())) + if err != wantErr { + t.Errorf("got error %v, want %v", err, wantErr) + } + t.Run("retrieve access index count", newItemsCountTest(db.retrievalAccessIndex, 0)) + }) + + t.Run("pull index", newPullIndexTest(db, chunk, 0, leveldb.ErrNotFound)) + + t.Run("pull index count", newItemsCountTest(db.pullIndex, 0)) + + t.Run("gc index count", newItemsCountTest(db.gcIndex, 0)) + + t.Run("gc size", newIndexGCSizeTest(db)) + +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/retrieval_index_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/retrieval_index_test.go new file mode 100644 index 00000000..b0879012 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/retrieval_index_test.go @@ -0,0 +1,150 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "strconv" + "testing" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// BenchmarkRetrievalIndexes uploads a number of chunks in order to measure +// total time of updating their retrieval indexes by setting them +// to synced state and requesting them. +// +// This benchmark takes significant amount of time. +// +// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014) show +// that two separated indexes perform better. +// +// # go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkRetrievalIndexes -v +// goos: darwin +// goarch: amd64 +// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore +// BenchmarkRetrievalIndexes/1000-8 20 75556686 ns/op 19033493 B/op 84500 allocs/op +// BenchmarkRetrievalIndexes/10000-8 1 1079084922 ns/op 382792064 B/op 1429644 allocs/op +// BenchmarkRetrievalIndexes/100000-8 1 16891305737 ns/op 2629165304 B/op 12465019 allocs/op +// PASS +func BenchmarkRetrievalIndexes(b *testing.B) { + for _, count := range []int{ + 1000, + 10000, + 100000, + } { + b.Run(strconv.Itoa(count)+"-split", func(b *testing.B) { + for n := 0; n < b.N; n++ { + benchmarkRetrievalIndexes(b, nil, count) + } + }) + } +} + +// benchmarkRetrievalIndexes is used in BenchmarkRetrievalIndexes +// to do benchmarks with a specific number of chunks and different +// database options. +func benchmarkRetrievalIndexes(b *testing.B, o *Options, count int) { + b.StopTimer() + db, cleanupFunc := newTestDB(b, o) + defer cleanupFunc() + uploader := db.NewPutter(ModePutUpload) + syncer := db.NewSetter(ModeSetSync) + requester := db.NewGetter(ModeGetRequest) + addrs := make([]chunk.Address, count) + for i := 0; i < count; i++ { + chunk := generateTestRandomChunk() + err := uploader.Put(chunk) + if err != nil { + b.Fatal(err) + } + addrs[i] = chunk.Address() + } + // set update gc test hook to signal when + // update gc goroutine is done by sending to + // testHookUpdateGCChan channel, which is + // used to wait for gc index updates to be + // included in the benchmark time + testHookUpdateGCChan := make(chan struct{}) + defer setTestHookUpdateGC(func() { + testHookUpdateGCChan <- struct{}{} + })() + b.StartTimer() + + for i := 0; i < count; i++ { + err := syncer.Set(addrs[i]) + if err != nil { + b.Fatal(err) + } + + _, err = requester.Get(addrs[i]) + if err != nil { + b.Fatal(err) + } + // wait for update gc goroutine to be done + <-testHookUpdateGCChan + } +} + +// BenchmarkUpload compares uploading speed for different +// retrieval indexes and various number of chunks. +// +// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014). +// +// go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkUpload -v +// goos: darwin +// goarch: amd64 +// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore +// BenchmarkUpload/1000-8 20 59437463 ns/op 25205193 B/op 23208 allocs/op +// BenchmarkUpload/10000-8 2 580646362 ns/op 216532932 B/op 248090 allocs/op +// BenchmarkUpload/100000-8 1 22373390892 ns/op 2323055312 B/op 3995903 allocs/op +// PASS +func BenchmarkUpload(b *testing.B) { + for _, count := range []int{ + 1000, + 10000, + 100000, + } { + b.Run(strconv.Itoa(count), func(b *testing.B) { + for n := 0; n < b.N; n++ { + benchmarkUpload(b, nil, count) + } + }) + } +} + +// benchmarkUpload is used in BenchmarkUpload +// to do benchmarks with a specific number of chunks and different +// database options. +func benchmarkUpload(b *testing.B, o *Options, count int) { + b.StopTimer() + db, cleanupFunc := newTestDB(b, o) + defer cleanupFunc() + uploader := db.NewPutter(ModePutUpload) + chunks := make([]chunk.Chunk, count) + for i := 0; i < count; i++ { + chunk := generateTestRandomChunk() + chunks[i] = chunk + } + b.StartTimer() + + for i := 0; i < count; i++ { + err := uploader.Put(chunks[i]) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_pull.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_pull.go new file mode 100644 index 00000000..0b96102e --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_pull.go @@ -0,0 +1,211 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "context" + "errors" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/shed" + "github.com/syndtr/goleveldb/leveldb" +) + +// SubscribePull returns a channel that provides chunk addresses and stored times from pull syncing index. +// Pull syncing index can be only subscribed to a particular proximity order bin. If since +// is not nil, the iteration will start from the first item stored after that timestamp. If until is not nil, +// only chunks stored up to this timestamp will be send to the channel, and the returned channel will be +// closed. The since-until interval is open on the left and closed on the right (since,until]. Returned stop +// function will terminate current and further iterations without errors, and also close the returned channel. +// Make sure that you check the second returned parameter from the channel to stop iteration when its value +// is false. +func (db *DB) SubscribePull(ctx context.Context, bin uint8, since, until *ChunkDescriptor) (c <-chan ChunkDescriptor, stop func()) { + chunkDescriptors := make(chan ChunkDescriptor) + trigger := make(chan struct{}, 1) + + db.pullTriggersMu.Lock() + if _, ok := db.pullTriggers[bin]; !ok { + db.pullTriggers[bin] = make([]chan struct{}, 0) + } + db.pullTriggers[bin] = append(db.pullTriggers[bin], trigger) + db.pullTriggersMu.Unlock() + + // send signal for the initial iteration + trigger <- struct{}{} + + stopChan := make(chan struct{}) + var stopChanOnce sync.Once + + // used to provide information from the iterator to + // stop subscription when until chunk descriptor is reached + var errStopSubscription = errors.New("stop subscription") + + go func() { + // close the returned ChunkDescriptor channel at the end to + // signal that the subscription is done + defer close(chunkDescriptors) + // sinceItem is the Item from which the next iteration + // should start. The first iteration starts from the first Item. + var sinceItem *shed.Item + if since != nil { + sinceItem = &shed.Item{ + Address: since.Address, + StoreTimestamp: since.StoreTimestamp, + } + } + for { + select { + case <-trigger: + // iterate until: + // - last index Item is reached + // - subscription stop is called + // - context is done + err := db.pullIndex.Iterate(func(item shed.Item) (stop bool, err error) { + select { + case chunkDescriptors <- ChunkDescriptor{ + Address: item.Address, + StoreTimestamp: item.StoreTimestamp, + }: + // until chunk descriptor is sent + // break the iteration + if until != nil && + (item.StoreTimestamp >= until.StoreTimestamp || + bytes.Equal(item.Address, until.Address)) { + return true, errStopSubscription + } + // set next iteration start item + // when its chunk is successfully sent to channel + sinceItem = &item + return false, nil + case <-stopChan: + // gracefully stop the iteration + // on stop + return true, nil + case <-db.close: + // gracefully stop the iteration + // on database close + return true, nil + case <-ctx.Done(): + return true, ctx.Err() + } + }, &shed.IterateOptions{ + StartFrom: sinceItem, + // sinceItem was sent as the last Address in the previous + // iterator call, skip it in this one + SkipStartFromItem: true, + Prefix: []byte{bin}, + }) + if err != nil { + if err == errStopSubscription { + // stop subscription without any errors + // if until is reached + return + } + log.Error("localstore pull subscription iteration", "bin", bin, "since", since, "until", until, "err", err) + return + } + case <-stopChan: + // terminate the subscription + // on stop + return + case <-db.close: + // terminate the subscription + // on database close + return + case <-ctx.Done(): + err := ctx.Err() + if err != nil { + log.Error("localstore pull subscription", "bin", bin, "since", since, "until", until, "err", err) + } + return + } + } + }() + + stop = func() { + stopChanOnce.Do(func() { + close(stopChan) + }) + + db.pullTriggersMu.Lock() + defer db.pullTriggersMu.Unlock() + + for i, t := range db.pullTriggers[bin] { + if t == trigger { + db.pullTriggers[bin] = append(db.pullTriggers[bin][:i], db.pullTriggers[bin][i+1:]...) + break + } + } + } + + return chunkDescriptors, stop +} + +// LastPullSubscriptionChunk returns ChunkDescriptor of the latest Chunk +// in pull syncing index for a provided bin. If there are no chunks in +// that bin, chunk.ErrChunkNotFound is returned. +func (db *DB) LastPullSubscriptionChunk(bin uint8) (c *ChunkDescriptor, err error) { + item, err := db.pullIndex.Last([]byte{bin}) + if err != nil { + if err == leveldb.ErrNotFound { + return nil, chunk.ErrChunkNotFound + } + return nil, err + } + return &ChunkDescriptor{ + Address: item.Address, + StoreTimestamp: item.StoreTimestamp, + }, nil +} + +// ChunkDescriptor holds information required for Pull syncing. This struct +// is provided by subscribing to pull index. +type ChunkDescriptor struct { + Address chunk.Address + StoreTimestamp int64 +} + +func (c *ChunkDescriptor) String() string { + if c == nil { + return "none" + } + return fmt.Sprintf("%s stored at %v", c.Address.Hex(), c.StoreTimestamp) +} + +// triggerPullSubscriptions is used internally for starting iterations +// on Pull subscriptions for a particular bin. When new item with address +// that is in particular bin for DB's baseKey is added to pull index +// this function should be called. +func (db *DB) triggerPullSubscriptions(bin uint8) { + db.pullTriggersMu.RLock() + triggers, ok := db.pullTriggers[bin] + db.pullTriggersMu.RUnlock() + if !ok { + return + } + + for _, t := range triggers { + select { + case t <- struct{}{}: + default: + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_pull_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_pull_test.go new file mode 100644 index 00000000..d5ddae02 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_pull_test.go @@ -0,0 +1,559 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "context" + "fmt" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// TestDB_SubscribePull uploads some chunks before and after +// pull syncing subscription is created and validates if +// all addresses are received in the right order +// for expected proximity order bins. +func TestDB_SubscribePull(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make(map[uint8][]chunk.Address) + var addrsMu sync.Mutex + var wantedChunksCount int + + // prepopulate database with some chunks + // before the subscription + uploadRandomChunksBin(t, db, uploader, addrs, &addrsMu, &wantedChunksCount, 10) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { + ch, stop := db.SubscribePull(ctx, bin, nil, nil) + defer stop() + + // receive and validate addresses from the subscription + go readPullSubscriptionBin(ctx, bin, ch, addrs, &addrsMu, errChan) + } + + // upload some chunks just after subscribe + uploadRandomChunksBin(t, db, uploader, addrs, &addrsMu, &wantedChunksCount, 5) + + time.Sleep(200 * time.Millisecond) + + // upload some chunks after some short time + // to ensure that subscription will include them + // in a dynamic environment + uploadRandomChunksBin(t, db, uploader, addrs, &addrsMu, &wantedChunksCount, 3) + + checkErrChan(ctx, t, errChan, wantedChunksCount) +} + +// TestDB_SubscribePull_multiple uploads chunks before and after +// multiple pull syncing subscriptions are created and +// validates if all addresses are received in the right order +// for expected proximity order bins. +func TestDB_SubscribePull_multiple(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make(map[uint8][]chunk.Address) + var addrsMu sync.Mutex + var wantedChunksCount int + + // prepopulate database with some chunks + // before the subscription + uploadRandomChunksBin(t, db, uploader, addrs, &addrsMu, &wantedChunksCount, 10) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + subsCount := 10 + + // start a number of subscriptions + // that all of them will write every address error to errChan + for j := 0; j < subsCount; j++ { + for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { + ch, stop := db.SubscribePull(ctx, bin, nil, nil) + defer stop() + + // receive and validate addresses from the subscription + go readPullSubscriptionBin(ctx, bin, ch, addrs, &addrsMu, errChan) + } + } + + // upload some chunks just after subscribe + uploadRandomChunksBin(t, db, uploader, addrs, &addrsMu, &wantedChunksCount, 5) + + time.Sleep(200 * time.Millisecond) + + // upload some chunks after some short time + // to ensure that subscription will include them + // in a dynamic environment + uploadRandomChunksBin(t, db, uploader, addrs, &addrsMu, &wantedChunksCount, 3) + + checkErrChan(ctx, t, errChan, wantedChunksCount*subsCount) +} + +// TestDB_SubscribePull_since uploads chunks before and after +// pull syncing subscriptions are created with a since argument +// and validates if all expected addresses are received in the +// right order for expected proximity order bins. +func TestDB_SubscribePull_since(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make(map[uint8][]chunk.Address) + var addrsMu sync.Mutex + var wantedChunksCount int + + lastTimestamp := time.Now().UTC().UnixNano() + var lastTimestampMu sync.RWMutex + defer setNow(func() (t int64) { + lastTimestampMu.Lock() + defer lastTimestampMu.Unlock() + lastTimestamp++ + return lastTimestamp + })() + + uploadRandomChunks := func(count int, wanted bool) (last map[uint8]ChunkDescriptor) { + addrsMu.Lock() + defer addrsMu.Unlock() + + last = make(map[uint8]ChunkDescriptor) + for i := 0; i < count; i++ { + ch := generateTestRandomChunk() + + err := uploader.Put(ch) + if err != nil { + t.Fatal(err) + } + + bin := db.po(ch.Address()) + + if _, ok := addrs[bin]; !ok { + addrs[bin] = make([]chunk.Address, 0) + } + if wanted { + addrs[bin] = append(addrs[bin], ch.Address()) + wantedChunksCount++ + } + + lastTimestampMu.RLock() + storeTimestamp := lastTimestamp + lastTimestampMu.RUnlock() + + last[bin] = ChunkDescriptor{ + Address: ch.Address(), + StoreTimestamp: storeTimestamp, + } + } + return last + } + + // prepopulate database with some chunks + // before the subscription + last := uploadRandomChunks(30, false) + + uploadRandomChunks(25, true) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { + var since *ChunkDescriptor + if c, ok := last[bin]; ok { + since = &c + } + ch, stop := db.SubscribePull(ctx, bin, since, nil) + defer stop() + + // receive and validate addresses from the subscription + go readPullSubscriptionBin(ctx, bin, ch, addrs, &addrsMu, errChan) + + } + + // upload some chunks just after subscribe + uploadRandomChunks(15, true) + + checkErrChan(ctx, t, errChan, wantedChunksCount) +} + +// TestDB_SubscribePull_until uploads chunks before and after +// pull syncing subscriptions are created with an until argument +// and validates if all expected addresses are received in the +// right order for expected proximity order bins. +func TestDB_SubscribePull_until(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make(map[uint8][]chunk.Address) + var addrsMu sync.Mutex + var wantedChunksCount int + + lastTimestamp := time.Now().UTC().UnixNano() + var lastTimestampMu sync.RWMutex + defer setNow(func() (t int64) { + lastTimestampMu.Lock() + defer lastTimestampMu.Unlock() + lastTimestamp++ + return lastTimestamp + })() + + uploadRandomChunks := func(count int, wanted bool) (last map[uint8]ChunkDescriptor) { + addrsMu.Lock() + defer addrsMu.Unlock() + + last = make(map[uint8]ChunkDescriptor) + for i := 0; i < count; i++ { + ch := generateTestRandomChunk() + + err := uploader.Put(ch) + if err != nil { + t.Fatal(err) + } + + bin := db.po(ch.Address()) + + if _, ok := addrs[bin]; !ok { + addrs[bin] = make([]chunk.Address, 0) + } + if wanted { + addrs[bin] = append(addrs[bin], ch.Address()) + wantedChunksCount++ + } + + lastTimestampMu.RLock() + storeTimestamp := lastTimestamp + lastTimestampMu.RUnlock() + + last[bin] = ChunkDescriptor{ + Address: ch.Address(), + StoreTimestamp: storeTimestamp, + } + } + return last + } + + // prepopulate database with some chunks + // before the subscription + last := uploadRandomChunks(30, true) + + uploadRandomChunks(25, false) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { + until, ok := last[bin] + if !ok { + continue + } + ch, stop := db.SubscribePull(ctx, bin, nil, &until) + defer stop() + + // receive and validate addresses from the subscription + go readPullSubscriptionBin(ctx, bin, ch, addrs, &addrsMu, errChan) + } + + // upload some chunks just after subscribe + uploadRandomChunks(15, false) + + checkErrChan(ctx, t, errChan, wantedChunksCount) +} + +// TestDB_SubscribePull_sinceAndUntil uploads chunks before and +// after pull syncing subscriptions are created with since +// and until arguments, and validates if all expected addresses +// are received in the right order for expected proximity order bins. +func TestDB_SubscribePull_sinceAndUntil(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make(map[uint8][]chunk.Address) + var addrsMu sync.Mutex + var wantedChunksCount int + + lastTimestamp := time.Now().UTC().UnixNano() + var lastTimestampMu sync.RWMutex + defer setNow(func() (t int64) { + lastTimestampMu.Lock() + defer lastTimestampMu.Unlock() + lastTimestamp++ + return lastTimestamp + })() + + uploadRandomChunks := func(count int, wanted bool) (last map[uint8]ChunkDescriptor) { + addrsMu.Lock() + defer addrsMu.Unlock() + + last = make(map[uint8]ChunkDescriptor) + for i := 0; i < count; i++ { + ch := generateTestRandomChunk() + + err := uploader.Put(ch) + if err != nil { + t.Fatal(err) + } + + bin := db.po(ch.Address()) + + if _, ok := addrs[bin]; !ok { + addrs[bin] = make([]chunk.Address, 0) + } + if wanted { + addrs[bin] = append(addrs[bin], ch.Address()) + wantedChunksCount++ + } + + lastTimestampMu.RLock() + storeTimestamp := lastTimestamp + lastTimestampMu.RUnlock() + + last[bin] = ChunkDescriptor{ + Address: ch.Address(), + StoreTimestamp: storeTimestamp, + } + } + return last + } + + // all chunks from upload1 are not expected + // as upload1 chunk is used as since for subscriptions + upload1 := uploadRandomChunks(100, false) + + // all chunks from upload2 are expected + // as upload2 chunk is used as until for subscriptions + upload2 := uploadRandomChunks(100, true) + + // upload some chunks before subscribe but after + // wanted chunks + uploadRandomChunks(8, false) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { + var since *ChunkDescriptor + if c, ok := upload1[bin]; ok { + since = &c + } + until, ok := upload2[bin] + if !ok { + // no chunks un this bin uploaded in the upload2 + // skip this bin from testing + continue + } + ch, stop := db.SubscribePull(ctx, bin, since, &until) + defer stop() + + // receive and validate addresses from the subscription + go readPullSubscriptionBin(ctx, bin, ch, addrs, &addrsMu, errChan) + } + + // upload some chunks just after subscribe + uploadRandomChunks(15, false) + + checkErrChan(ctx, t, errChan, wantedChunksCount) +} + +// uploadRandomChunksBin uploads random chunks to database and adds them to +// the map of addresses ber bin. +func uploadRandomChunksBin(t *testing.T, db *DB, uploader *Putter, addrs map[uint8][]chunk.Address, addrsMu *sync.Mutex, wantedChunksCount *int, count int) { + addrsMu.Lock() + defer addrsMu.Unlock() + + for i := 0; i < count; i++ { + ch := generateTestRandomChunk() + + err := uploader.Put(ch) + if err != nil { + t.Fatal(err) + } + + bin := db.po(ch.Address()) + if _, ok := addrs[bin]; !ok { + addrs[bin] = make([]chunk.Address, 0) + } + addrs[bin] = append(addrs[bin], ch.Address()) + + *wantedChunksCount++ + } +} + +// readPullSubscriptionBin is a helper function that reads all ChunkDescriptors from a channel and +// sends error to errChan, even if it is nil, to count the number of ChunkDescriptors +// returned by the channel. +func readPullSubscriptionBin(ctx context.Context, bin uint8, ch <-chan ChunkDescriptor, addrs map[uint8][]chunk.Address, addrsMu *sync.Mutex, errChan chan error) { + var i int // address index + for { + select { + case got, ok := <-ch: + if !ok { + return + } + var err error + addrsMu.Lock() + if i+1 > len(addrs[bin]) { + err = fmt.Errorf("got more chunk addresses %v, then expected %v, for bin %v", i+1, len(addrs[bin]), bin) + } else { + want := addrs[bin][i] + if !bytes.Equal(got.Address, want) { + err = fmt.Errorf("got chunk address %v in bin %v %s, want %s", i, bin, got.Address.Hex(), want) + } + } + addrsMu.Unlock() + i++ + // send one and only one error per received address + select { + case errChan <- err: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } +} + +// checkErrChan expects the number of wantedChunksCount errors from errChan +// and calls t.Error for the ones that are not nil. +func checkErrChan(ctx context.Context, t *testing.T, errChan chan error, wantedChunksCount int) { + t.Helper() + + for i := 0; i < wantedChunksCount; i++ { + select { + case err := <-errChan: + if err != nil { + t.Error(err) + } + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + } +} + +// TestDB_LastPullSubscriptionChunk validates that LastPullSubscriptionChunk +// is returning the last chunk descriptor for proximity order bins by +// doing a few rounds of chunk uploads. +func TestDB_LastPullSubscriptionChunk(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make(map[uint8][]chunk.Address) + + lastTimestamp := time.Now().UTC().UnixNano() + var lastTimestampMu sync.RWMutex + defer setNow(func() (t int64) { + lastTimestampMu.Lock() + defer lastTimestampMu.Unlock() + lastTimestamp++ + return lastTimestamp + })() + + last := make(map[uint8]ChunkDescriptor) + + // do a few rounds of uploads and check if + // last pull subscription chunk is correct + for _, count := range []int{1, 3, 10, 11, 100, 120} { + + // upload + for i := 0; i < count; i++ { + ch := generateTestRandomChunk() + + err := uploader.Put(ch) + if err != nil { + t.Fatal(err) + } + + bin := db.po(ch.Address()) + + if _, ok := addrs[bin]; !ok { + addrs[bin] = make([]chunk.Address, 0) + } + addrs[bin] = append(addrs[bin], ch.Address()) + + lastTimestampMu.RLock() + storeTimestamp := lastTimestamp + lastTimestampMu.RUnlock() + + last[bin] = ChunkDescriptor{ + Address: ch.Address(), + StoreTimestamp: storeTimestamp, + } + } + + // check + for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { + want, ok := last[bin] + got, err := db.LastPullSubscriptionChunk(bin) + if ok { + if err != nil { + t.Errorf("got unexpected error value %v", err) + } + if !bytes.Equal(got.Address, want.Address) { + t.Errorf("got last address %s, want %s", got.Address.Hex(), want.Address.Hex()) + } + } else { + if err != chunk.ErrChunkNotFound { + t.Errorf("got unexpected error value %v, want %v", err, chunk.ErrChunkNotFound) + } + } + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_push.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_push.go new file mode 100644 index 00000000..5cbc2eb6 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_push.go @@ -0,0 +1,145 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "context" + "sync" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/shed" +) + +// SubscribePush returns a channel that provides storage chunks with ordering from push syncing index. +// Returned stop function will terminate current and further iterations, and also it will close +// the returned channel without any errors. Make sure that you check the second returned parameter +// from the channel to stop iteration when its value is false. +func (db *DB) SubscribePush(ctx context.Context) (c <-chan chunk.Chunk, stop func()) { + chunks := make(chan chunk.Chunk) + trigger := make(chan struct{}, 1) + + db.pushTriggersMu.Lock() + db.pushTriggers = append(db.pushTriggers, trigger) + db.pushTriggersMu.Unlock() + + // send signal for the initial iteration + trigger <- struct{}{} + + stopChan := make(chan struct{}) + var stopChanOnce sync.Once + + go func() { + // close the returned chunkInfo channel at the end to + // signal that the subscription is done + defer close(chunks) + // sinceItem is the Item from which the next iteration + // should start. The first iteration starts from the first Item. + var sinceItem *shed.Item + for { + select { + case <-trigger: + // iterate until: + // - last index Item is reached + // - subscription stop is called + // - context is done + err := db.pushIndex.Iterate(func(item shed.Item) (stop bool, err error) { + // get chunk data + dataItem, err := db.retrievalDataIndex.Get(item) + if err != nil { + return true, err + } + + select { + case chunks <- chunk.NewChunk(dataItem.Address, dataItem.Data): + // set next iteration start item + // when its chunk is successfully sent to channel + sinceItem = &item + return false, nil + case <-stopChan: + // gracefully stop the iteration + // on stop + return true, nil + case <-db.close: + // gracefully stop the iteration + // on database close + return true, nil + case <-ctx.Done(): + return true, ctx.Err() + } + }, &shed.IterateOptions{ + StartFrom: sinceItem, + // sinceItem was sent as the last Address in the previous + // iterator call, skip it in this one + SkipStartFromItem: true, + }) + if err != nil { + log.Error("localstore push subscription iteration", "err", err) + return + } + case <-stopChan: + // terminate the subscription + // on stop + return + case <-db.close: + // terminate the subscription + // on database close + return + case <-ctx.Done(): + err := ctx.Err() + if err != nil { + log.Error("localstore push subscription", "err", err) + } + return + } + } + }() + + stop = func() { + stopChanOnce.Do(func() { + close(stopChan) + }) + + db.pushTriggersMu.Lock() + defer db.pushTriggersMu.Unlock() + + for i, t := range db.pushTriggers { + if t == trigger { + db.pushTriggers = append(db.pushTriggers[:i], db.pushTriggers[i+1:]...) + break + } + } + } + + return chunks, stop +} + +// triggerPushSubscriptions is used internally for starting iterations +// on Push subscriptions. Whenever new item is added to the push index, +// this function should be called. +func (db *DB) triggerPushSubscriptions() { + db.pushTriggersMu.RLock() + triggers := db.pushTriggers + db.pushTriggersMu.RUnlock() + + for _, t := range triggers { + select { + case t <- struct{}{}: + default: + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_push_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_push_test.go new file mode 100644 index 00000000..30fb98eb --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore/subscription_push_test.go @@ -0,0 +1,210 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package localstore + +import ( + "bytes" + "context" + "fmt" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// TestDB_SubscribePush uploads some chunks before and after +// push syncing subscription is created and validates if +// all addresses are received in the right order. +func TestDB_SubscribePush(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + chunks := make([]chunk.Chunk, 0) + var chunksMu sync.Mutex + + uploadRandomChunks := func(count int) { + chunksMu.Lock() + defer chunksMu.Unlock() + + for i := 0; i < count; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + chunks = append(chunks, chunk) + } + } + + // prepopulate database with some chunks + // before the subscription + uploadRandomChunks(10) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + ch, stop := db.SubscribePush(ctx) + defer stop() + + // receive and validate addresses from the subscription + go func() { + var i int // address index + for { + select { + case got, ok := <-ch: + if !ok { + return + } + chunksMu.Lock() + want := chunks[i] + chunksMu.Unlock() + var err error + if !bytes.Equal(got.Data(), want.Data()) { + err = fmt.Errorf("got chunk %v data %x, want %x", i, got.Data(), want.Data()) + } + if !bytes.Equal(got.Address(), want.Address()) { + err = fmt.Errorf("got chunk %v address %s, want %s", i, got.Address().Hex(), want.Address().Hex()) + } + i++ + // send one and only one error per received address + select { + case errChan <- err: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + + // upload some chunks just after subscribe + uploadRandomChunks(5) + + time.Sleep(200 * time.Millisecond) + + // upload some chunks after some short time + // to ensure that subscription will include them + // in a dynamic environment + uploadRandomChunks(3) + + checkErrChan(ctx, t, errChan, len(chunks)) +} + +// TestDB_SubscribePush_multiple uploads chunks before and after +// multiple push syncing subscriptions are created and +// validates if all addresses are received in the right order. +func TestDB_SubscribePush_multiple(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + uploader := db.NewPutter(ModePutUpload) + + addrs := make([]chunk.Address, 0) + var addrsMu sync.Mutex + + uploadRandomChunks := func(count int) { + addrsMu.Lock() + defer addrsMu.Unlock() + + for i := 0; i < count; i++ { + chunk := generateTestRandomChunk() + + err := uploader.Put(chunk) + if err != nil { + t.Fatal(err) + } + + addrs = append(addrs, chunk.Address()) + } + } + + // prepopulate database with some chunks + // before the subscription + uploadRandomChunks(10) + + // set a timeout on subscription + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // collect all errors from validating addresses, even nil ones + // to validate the number of addresses received by the subscription + errChan := make(chan error) + + subsCount := 10 + + // start a number of subscriptions + // that all of them will write every addresses error to errChan + for j := 0; j < subsCount; j++ { + ch, stop := db.SubscribePush(ctx) + defer stop() + + // receive and validate addresses from the subscription + go func(j int) { + var i int // address index + for { + select { + case got, ok := <-ch: + if !ok { + return + } + addrsMu.Lock() + want := addrs[i] + addrsMu.Unlock() + var err error + if !bytes.Equal(got.Address(), want) { + err = fmt.Errorf("got chunk %v address on subscription %v %s, want %s", i, j, got, want) + } + i++ + // send one and only one error per received address + select { + case errChan <- err: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }(j) + } + + // upload some chunks just after subscribe + uploadRandomChunks(5) + + time.Sleep(200 * time.Millisecond) + + // upload some chunks after some short time + // to ensure that subscription will include them + // in a dynamic environment + uploadRandomChunks(3) + + // number of addresses received by all subscriptions + wantedChunksCount := len(addrs) * subsCount + + checkErrChan(ctx, t, errChan, wantedChunksCount) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore_test.go index 7a07726d..fcadcefa 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/localstore_test.go @@ -23,7 +23,7 @@ import ( "testing" "time" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" ) var ( @@ -65,7 +65,7 @@ func TestValidator(t *testing.T) { // add content address validator and check puts // bad should fail, good should pass store.Validators = append(store.Validators, NewContentAddressValidator(hashfunc)) - chunks = GenerateRandomChunks(ch.DefaultSize, 2) + chunks = GenerateRandomChunks(chunk.DefaultSize, 2) goodChunk = chunks[0] badChunk = chunks[1] copy(badChunk.Data(), goodChunk.Data()) @@ -83,7 +83,7 @@ func TestValidator(t *testing.T) { var negV boolTestValidator store.Validators = append(store.Validators, negV) - chunks = GenerateRandomChunks(ch.DefaultSize, 2) + chunks = GenerateRandomChunks(chunk.DefaultSize, 2) goodChunk = chunks[0] badChunk = chunks[1] copy(badChunk.Data(), goodChunk.Data()) @@ -101,7 +101,7 @@ func TestValidator(t *testing.T) { var posV boolTestValidator = true store.Validators = append(store.Validators, posV) - chunks = GenerateRandomChunks(ch.DefaultSize, 2) + chunks = GenerateRandomChunks(chunk.DefaultSize, 2) goodChunk = chunks[0] badChunk = chunks[1] copy(badChunk.Data(), goodChunk.Data()) @@ -118,7 +118,7 @@ func TestValidator(t *testing.T) { type boolTestValidator bool -func (self boolTestValidator) Validate(addr Address, data []byte) bool { +func (self boolTestValidator) Validate(chunk Chunk) bool { return bool(self) } @@ -138,7 +138,7 @@ func putChunks(store *LocalStore, chunks ...Chunk) []error { func put(store *LocalStore, n int, f func(i int64) Chunk) (hs []Address, errs []error) { for i := int64(0); i < int64(n); i++ { - chunk := f(ch.DefaultSize) + chunk := f(chunk.DefaultSize) err := store.Put(context.TODO(), chunk) errs = append(errs, err) hs = append(hs, chunk.Address()) @@ -158,7 +158,7 @@ func TestGetFrequentlyAccessedChunkWontGetGarbageCollected(t *testing.T) { var chunks []Chunk for i := 0; i < ldbCap; i++ { - chunks = append(chunks, GenerateRandomChunk(ch.DefaultSize)) + chunks = append(chunks, GenerateRandomChunk(chunk.DefaultSize)) } mostAccessed := chunks[0].Address() @@ -209,3 +209,36 @@ func setupLocalStore(t *testing.T, ldbCap int) (ls *LocalStore, cleanup func()) return store, cleanup } + +func TestHas(t *testing.T) { + ldbCap := defaultGCRatio + store, cleanup := setupLocalStore(t, ldbCap) + defer cleanup() + + nonStoredAddr := GenerateRandomChunk(128).Address() + + has := store.Has(context.Background(), nonStoredAddr) + if has { + t.Fatal("Expected Has() to return false, but returned true!") + } + + storeChunks := GenerateRandomChunks(128, 3) + for _, ch := range storeChunks { + err := store.Put(context.Background(), ch) + if err != nil { + t.Fatalf("Expected store to store chunk, but it failed: %v", err) + } + + has := store.Has(context.Background(), ch.Address()) + if !has { + t.Fatal("Expected Has() to return true, but returned false!") + } + } + + //let's be paranoic and test again that the non-existent chunk returns false + has = store.Has(context.Background(), nonStoredAddr) + if has { + t.Fatal("Expected Has() to return false, but returned true!") + } + +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore.go index 36b1e00d..611ac3bc 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore.go @@ -48,6 +48,11 @@ func NewMemStore(params *StoreParams, _ *LDBStore) (m *MemStore) { } } +// Has needed to implement SyncChunkStore +func (m *MemStore) Has(_ context.Context, addr Address) bool { + return m.cache.Contains(addr) +} + func (m *MemStore) Get(_ context.Context, addr Address) (Chunk, error) { if m.disabled { return nil, ErrChunkNotFound @@ -57,7 +62,7 @@ func (m *MemStore) Get(_ context.Context, addr Address) (Chunk, error) { if !ok { return nil, ErrChunkNotFound } - return c.(*chunk), nil + return c.(Chunk), nil } func (m *MemStore) Put(_ context.Context, c Chunk) error { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore_test.go index 6850d2d6..8aaf486a 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/memstore_test.go @@ -28,32 +28,32 @@ func newTestMemStore() *MemStore { return NewMemStore(storeparams, nil) } -func testMemStoreRandom(n int, chunksize int64, t *testing.T) { +func testMemStoreRandom(n int, t *testing.T) { m := newTestMemStore() defer m.Close() - testStoreRandom(m, n, chunksize, t) + testStoreRandom(m, n, t) } -func testMemStoreCorrect(n int, chunksize int64, t *testing.T) { +func testMemStoreCorrect(n int, t *testing.T) { m := newTestMemStore() defer m.Close() - testStoreCorrect(m, n, chunksize, t) + testStoreCorrect(m, n, t) } func TestMemStoreRandom_1(t *testing.T) { - testMemStoreRandom(1, 0, t) + testMemStoreRandom(1, t) } func TestMemStoreCorrect_1(t *testing.T) { - testMemStoreCorrect(1, 4104, t) + testMemStoreCorrect(1, t) } func TestMemStoreRandom_1k(t *testing.T) { - testMemStoreRandom(1000, 0, t) + testMemStoreRandom(1000, t) } func TestMemStoreCorrect_1k(t *testing.T) { - testMemStoreCorrect(100, 4096, t) + testMemStoreCorrect(100, t) } func TestMemStoreNotFound(t *testing.T) { @@ -66,32 +66,24 @@ func TestMemStoreNotFound(t *testing.T) { } } -func benchmarkMemStorePut(n int, processors int, chunksize int64, b *testing.B) { +func benchmarkMemStorePut(n int, b *testing.B) { m := newTestMemStore() defer m.Close() - benchmarkStorePut(m, n, chunksize, b) + benchmarkStorePut(m, n, b) } -func benchmarkMemStoreGet(n int, processors int, chunksize int64, b *testing.B) { +func benchmarkMemStoreGet(n int, b *testing.B) { m := newTestMemStore() defer m.Close() - benchmarkStoreGet(m, n, chunksize, b) + benchmarkStoreGet(m, n, b) } -func BenchmarkMemStorePut_1_500(b *testing.B) { - benchmarkMemStorePut(500, 1, 4096, b) +func BenchmarkMemStorePut_500(b *testing.B) { + benchmarkMemStorePut(500, b) } -func BenchmarkMemStorePut_8_500(b *testing.B) { - benchmarkMemStorePut(500, 8, 4096, b) -} - -func BenchmarkMemStoreGet_1_500(b *testing.B) { - benchmarkMemStoreGet(500, 1, 4096, b) -} - -func BenchmarkMemStoreGet_8_500(b *testing.B) { - benchmarkMemStoreGet(500, 8, 4096, b) +func BenchmarkMemStoreGet_500(b *testing.B) { + benchmarkMemStoreGet(500, b) } func TestMemStoreAndLDBStore(t *testing.T) { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db.go index 43bfa24f..313a61b4 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db.go @@ -21,8 +21,12 @@ import ( "archive/tar" "bytes" "encoding/json" + "errors" + "fmt" "io" "io/ioutil" + "sync" + "time" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" @@ -37,6 +41,10 @@ import ( // release resources used by the database. type GlobalStore struct { db *leveldb.DB + // protects nodes and keys indexes + // in Put and Delete methods + nodesLocks sync.Map + keysLocks sync.Map } // NewGlobalStore creates a new instance of GlobalStore. @@ -64,14 +72,14 @@ func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { // Get returns chunk data if the chunk with key exists for node // on address addr. func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { - has, err := s.db.Has(nodeDBKey(addr, key), nil) + has, err := s.db.Has(indexForHashesPerNode(addr, key), nil) if err != nil { return nil, mock.ErrNotFound } if !has { return nil, mock.ErrNotFound } - data, err = s.db.Get(dataDBKey(key), nil) + data, err = s.db.Get(indexDataKey(key), nil) if err == leveldb.ErrNotFound { err = mock.ErrNotFound } @@ -80,21 +88,165 @@ func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err err // Put saves the chunk data for node with address addr. func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { + unlock, err := s.lock(addr, key) + if err != nil { + return err + } + defer unlock() + batch := new(leveldb.Batch) - batch.Put(nodeDBKey(addr, key), nil) - batch.Put(dataDBKey(key), data) + batch.Put(indexForHashesPerNode(addr, key), nil) + batch.Put(indexForNodesWithHash(key, addr), nil) + batch.Put(indexForNodes(addr), nil) + batch.Put(indexForHashes(key), nil) + batch.Put(indexDataKey(key), data) + return s.db.Write(batch, nil) +} + +// Delete removes the chunk reference to node with address addr. +func (s *GlobalStore) Delete(addr common.Address, key []byte) error { + unlock, err := s.lock(addr, key) + if err != nil { + return err + } + defer unlock() + + batch := new(leveldb.Batch) + batch.Delete(indexForHashesPerNode(addr, key)) + batch.Delete(indexForNodesWithHash(key, addr)) + + // check if this node contains any keys, and if not + // remove it from the + x := indexForHashesPerNodePrefix(addr) + if k, _ := s.db.Get(x, nil); !bytes.HasPrefix(k, x) { + batch.Delete(indexForNodes(addr)) + } + + x = indexForNodesWithHashPrefix(key) + if k, _ := s.db.Get(x, nil); !bytes.HasPrefix(k, x) { + batch.Delete(indexForHashes(key)) + } return s.db.Write(batch, nil) } // HasKey returns whether a node with addr contains the key. func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { - has, err := s.db.Has(nodeDBKey(addr, key), nil) + has, err := s.db.Has(indexForHashesPerNode(addr, key), nil) if err != nil { has = false } return has } +// Keys returns a paginated list of keys on all nodes. +func (s *GlobalStore) Keys(startKey []byte, limit int) (keys mock.Keys, err error) { + return s.keys(nil, startKey, limit) +} + +// Nodes returns a paginated list of all known nodes. +func (s *GlobalStore) Nodes(startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + return s.nodes(nil, startAddr, limit) +} + +// NodeKeys returns a paginated list of keys on a node with provided address. +func (s *GlobalStore) NodeKeys(addr common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { + return s.keys(&addr, startKey, limit) +} + +// KeyNodes returns a paginated list of nodes that contain a particular key. +func (s *GlobalStore) KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + return s.nodes(key, startAddr, limit) +} + +// keys returns a paginated list of keys. If addr is not nil, only keys on that +// node will be returned. +func (s *GlobalStore) keys(addr *common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { + iter := s.db.NewIterator(nil, nil) + defer iter.Release() + + if limit <= 0 { + limit = mock.DefaultLimit + } + + prefix := []byte{indexForHashesPrefix} + if addr != nil { + prefix = indexForHashesPerNodePrefix(*addr) + } + if startKey != nil { + if addr != nil { + startKey = indexForHashesPerNode(*addr, startKey) + } else { + startKey = indexForHashes(startKey) + } + } else { + startKey = prefix + } + + ok := iter.Seek(startKey) + if !ok { + return keys, iter.Error() + } + for ; ok; ok = iter.Next() { + k := iter.Key() + if !bytes.HasPrefix(k, prefix) { + break + } + key := append([]byte(nil), bytes.TrimPrefix(k, prefix)...) + + if len(keys.Keys) >= limit { + keys.Next = key + break + } + + keys.Keys = append(keys.Keys, key) + } + return keys, iter.Error() +} + +// nodes returns a paginated list of node addresses. If key is not nil, +// only nodes that contain that key will be returned. +func (s *GlobalStore) nodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + iter := s.db.NewIterator(nil, nil) + defer iter.Release() + + if limit <= 0 { + limit = mock.DefaultLimit + } + + prefix := []byte{indexForNodesPrefix} + if key != nil { + prefix = indexForNodesWithHashPrefix(key) + } + startKey := prefix + if startAddr != nil { + if key != nil { + startKey = indexForNodesWithHash(key, *startAddr) + } else { + startKey = indexForNodes(*startAddr) + } + } + + ok := iter.Seek(startKey) + if !ok { + return nodes, iter.Error() + } + for ; ok; ok = iter.Next() { + k := iter.Key() + if !bytes.HasPrefix(k, prefix) { + break + } + addr := common.BytesToAddress(append([]byte(nil), bytes.TrimPrefix(k, prefix)...)) + + if len(nodes.Addrs) >= limit { + nodes.Next = &addr + break + } + + nodes.Addrs = append(nodes.Addrs, addr) + } + return nodes, iter.Error() +} + // Import reads tar archive from a reader that contains exported chunk data. // It returns the number of chunks imported and an error. func (s *GlobalStore) Import(r io.Reader) (n int, err error) { @@ -119,12 +271,18 @@ func (s *GlobalStore) Import(r io.Reader) (n int, err error) { return n, err } + key := common.Hex2Bytes(hdr.Name) + batch := new(leveldb.Batch) for _, addr := range c.Addrs { - batch.Put(nodeDBKeyHex(addr, hdr.Name), nil) + batch.Put(indexForHashesPerNode(addr, key), nil) + batch.Put(indexForNodesWithHash(key, addr), nil) + batch.Put(indexForNodes(addr), nil) } - batch.Put(dataDBKey(common.Hex2Bytes(hdr.Name)), c.Data) + batch.Put(indexForHashes(key), nil) + batch.Put(indexDataKey(key), c.Data) + if err = s.db.Write(batch, nil); err != nil { return n, err } @@ -143,18 +301,23 @@ func (s *GlobalStore) Export(w io.Writer) (n int, err error) { buf := bytes.NewBuffer(make([]byte, 0, 1024)) encoder := json.NewEncoder(buf) - iter := s.db.NewIterator(util.BytesPrefix(nodeKeyPrefix), nil) + snap, err := s.db.GetSnapshot() + if err != nil { + return 0, err + } + + iter := snap.NewIterator(util.BytesPrefix([]byte{indexForHashesByNodePrefix}), nil) defer iter.Release() var currentKey string var addrs []common.Address - saveChunk := func(hexKey string) error { - key := common.Hex2Bytes(hexKey) + saveChunk := func() error { + hexKey := currentKey - data, err := s.db.Get(dataDBKey(key), nil) + data, err := snap.Get(indexDataKey(common.Hex2Bytes(hexKey)), nil) if err != nil { - return err + return fmt.Errorf("get data %s: %v", hexKey, err) } buf.Reset() @@ -182,8 +345,8 @@ func (s *GlobalStore) Export(w io.Writer) (n int, err error) { } for iter.Next() { - k := bytes.TrimPrefix(iter.Key(), nodeKeyPrefix) - i := bytes.Index(k, []byte("-")) + k := bytes.TrimPrefix(iter.Key(), []byte{indexForHashesByNodePrefix}) + i := bytes.Index(k, []byte{keyTermByte}) if i < 0 { continue } @@ -194,7 +357,7 @@ func (s *GlobalStore) Export(w io.Writer) (n int, err error) { } if hexKey != currentKey { - if err = saveChunk(currentKey); err != nil { + if err = saveChunk(); err != nil { return n, err } @@ -202,35 +365,112 @@ func (s *GlobalStore) Export(w io.Writer) (n int, err error) { } currentKey = hexKey - addrs = append(addrs, common.BytesToAddress(k[i:])) + addrs = append(addrs, common.BytesToAddress(k[i+1:])) } if len(addrs) > 0 { - if err = saveChunk(currentKey); err != nil { + if err = saveChunk(); err != nil { return n, err } } - return n, err + return n, iter.Error() } var ( - nodeKeyPrefix = []byte("node-") - dataKeyPrefix = []byte("data-") + // maximal time for lock to wait until it returns error + lockTimeout = 3 * time.Second + // duration between two lock checks. + lockCheckDelay = 30 * time.Microsecond + // error returned by lock method when lock timeout is reached + errLockTimeout = errors.New("lock timeout") ) -// nodeDBKey constructs a database key for key/node mappings. -func nodeDBKey(addr common.Address, key []byte) []byte { - return nodeDBKeyHex(addr, common.Bytes2Hex(key)) +// lock protects parallel writes in Put and Delete methods for both +// node with provided address and for data with provided key. +func (s *GlobalStore) lock(addr common.Address, key []byte) (unlock func(), err error) { + start := time.Now() + nodeLockKey := addr.Hex() + for { + _, loaded := s.nodesLocks.LoadOrStore(nodeLockKey, struct{}{}) + if !loaded { + break + } + time.Sleep(lockCheckDelay) + if time.Since(start) > lockTimeout { + return nil, errLockTimeout + } + } + start = time.Now() + keyLockKey := common.Bytes2Hex(key) + for { + _, loaded := s.keysLocks.LoadOrStore(keyLockKey, struct{}{}) + if !loaded { + break + } + time.Sleep(lockCheckDelay) + if time.Since(start) > lockTimeout { + return nil, errLockTimeout + } + } + return func() { + s.nodesLocks.Delete(nodeLockKey) + s.keysLocks.Delete(keyLockKey) + }, nil } -// nodeDBKeyHex constructs a database key for key/node mappings -// using the hexadecimal string representation of the key. -func nodeDBKeyHex(addr common.Address, hexKey string) []byte { - return append(append(nodeKeyPrefix, []byte(hexKey+"-")...), addr[:]...) +const ( + // prefixes for different indexes + indexDataPrefix = 0 + indexForNodesWithHashesPrefix = 1 + indexForHashesByNodePrefix = 2 + indexForNodesPrefix = 3 + indexForHashesPrefix = 4 + + // keyTermByte splits keys and node addresses + // in database keys + keyTermByte = 0xff +) + +// indexForHashesPerNode constructs a database key to store keys used in +// NodeKeys method. +func indexForHashesPerNode(addr common.Address, key []byte) []byte { + return append(indexForHashesPerNodePrefix(addr), key...) } -// dataDBkey constructs a database key for key/data storage. -func dataDBKey(key []byte) []byte { - return append(dataKeyPrefix, key...) +// indexForHashesPerNodePrefix returns a prefix containing a node address used in +// NodeKeys method. Node address is hex encoded to be able to use keyTermByte +// for splitting node address and key. +func indexForHashesPerNodePrefix(addr common.Address) []byte { + return append([]byte{indexForNodesWithHashesPrefix}, append([]byte(addr.Hex()), keyTermByte)...) +} + +// indexForNodesWithHash constructs a database key to store keys used in +// KeyNodes method. +func indexForNodesWithHash(key []byte, addr common.Address) []byte { + return append(indexForNodesWithHashPrefix(key), addr[:]...) +} + +// indexForNodesWithHashPrefix returns a prefix containing a key used in +// KeyNodes method. Key is hex encoded to be able to use keyTermByte +// for splitting key and node address. +func indexForNodesWithHashPrefix(key []byte) []byte { + return append([]byte{indexForHashesByNodePrefix}, append([]byte(common.Bytes2Hex(key)), keyTermByte)...) +} + +// indexForNodes constructs a database key to store keys used in +// Nodes method. +func indexForNodes(addr common.Address) []byte { + return append([]byte{indexForNodesPrefix}, addr[:]...) +} + +// indexForHashes constructs a database key to store keys used in +// Keys method. +func indexForHashes(key []byte) []byte { + return append([]byte{indexForHashesPrefix}, key...) +} + +// indexDataKey constructs a database key for key/data storage. +func indexDataKey(key []byte) []byte { + return append([]byte{indexDataPrefix}, key...) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db_test.go index 782faaf3..efbf942f 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/db/db_test.go @@ -1,5 +1,3 @@ -// +build go1.8 -// // Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // @@ -29,47 +27,49 @@ import ( // TestDBStore is running a test.MockStore tests // using test.MockStore function. func TestDBStore(t *testing.T) { - dir, err := ioutil.TempDir("", "mock_"+t.Name()) - if err != nil { - panic(err) - } - defer os.RemoveAll(dir) - - store, err := NewGlobalStore(dir) - if err != nil { - t.Fatal(err) - } - defer store.Close() + store, cleanup := newTestStore(t) + defer cleanup() test.MockStore(t, store, 100) } +// TestDBStoreListings is running test.MockStoreListings tests. +func TestDBStoreListings(t *testing.T) { + store, cleanup := newTestStore(t) + defer cleanup() + + test.MockStoreListings(t, store, 1000) +} + // TestImportExport is running a test.ImportExport tests // using test.MockStore function. func TestImportExport(t *testing.T) { - dir1, err := ioutil.TempDir("", "mock_"+t.Name()+"_exporter") - if err != nil { - panic(err) - } - defer os.RemoveAll(dir1) + store1, cleanup := newTestStore(t) + defer cleanup() - store1, err := NewGlobalStore(dir1) - if err != nil { - t.Fatal(err) - } - defer store1.Close() - - dir2, err := ioutil.TempDir("", "mock_"+t.Name()+"_importer") - if err != nil { - panic(err) - } - defer os.RemoveAll(dir2) - - store2, err := NewGlobalStore(dir2) - if err != nil { - t.Fatal(err) - } - defer store2.Close() + store2, cleanup := newTestStore(t) + defer cleanup() test.ImportExport(t, store1, store2, 100) } + +// newTestStore creates a temporary GlobalStore +// that will be closed and data deleted when +// calling returned cleanup function. +func newTestStore(t *testing.T) (s *GlobalStore, cleanup func()) { + dir, err := ioutil.TempDir("", "swarm-mock-db-") + if err != nil { + t.Fatal(err) + } + + s, err = NewGlobalStore(dir) + if err != nil { + os.RemoveAll(dir) + t.Fatal(err) + } + + return s, func() { + s.Close() + os.RemoveAll(dir) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/explorer.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/explorer.go new file mode 100644 index 00000000..8fffff8f --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/explorer.go @@ -0,0 +1,257 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package explorer + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + "github.com/rs/cors" +) + +const jsonContentType = "application/json; charset=utf-8" + +// NewHandler constructs an http.Handler with router +// that servers requests required by chunk explorer. +// +// /api/has-key/{node}/{key} +// /api/keys?start={key}&node={node}&limit={int[0..1000]} +// /api/nodes?start={node}&key={key}&limit={int[0..1000]} +// +// Data from global store will be served and appropriate +// CORS headers will be sent if allowed origins are provided. +func NewHandler(store mock.GlobalStorer, corsOrigins []string) (handler http.Handler) { + mux := http.NewServeMux() + mux.Handle("/api/has-key/", newHasKeyHandler(store)) + mux.Handle("/api/keys", newKeysHandler(store)) + mux.Handle("/api/nodes", newNodesHandler(store)) + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + jsonStatusResponse(w, http.StatusNotFound) + }) + handler = noCacheHandler(mux) + if corsOrigins != nil { + handler = cors.New(cors.Options{ + AllowedOrigins: corsOrigins, + AllowedMethods: []string{"GET"}, + MaxAge: 600, + }).Handler(handler) + } + return handler +} + +// newHasKeyHandler returns a new handler that serves +// requests for HasKey global store method. +// Possible responses are StatusResponse with +// status codes 200 or 404 if the chunk is found or not. +func newHasKeyHandler(store mock.GlobalStorer) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + addr, key, ok := parseHasKeyPath(r.URL.Path) + if !ok { + jsonStatusResponse(w, http.StatusNotFound) + return + } + found := store.HasKey(addr, key) + if !found { + jsonStatusResponse(w, http.StatusNotFound) + return + } + jsonStatusResponse(w, http.StatusOK) + } +} + +// KeysResponse is a JSON-encoded response for global store +// Keys and NodeKeys methods. +type KeysResponse struct { + Keys []string `json:"keys"` + Next string `json:"next,omitempty"` +} + +// newKeysHandler returns a new handler that serves +// requests for Key global store method. +// HTTP response body will be JSON-encoded KeysResponse. +func newKeysHandler(store mock.GlobalStorer) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + q := r.URL.Query() + node := q.Get("node") + start, limit := listingPage(q) + + var keys mock.Keys + if node == "" { + var err error + keys, err = store.Keys(common.Hex2Bytes(start), limit) + if err != nil { + log.Error("chunk explorer: keys handler: get keys", "start", start, "err", err) + jsonStatusResponse(w, http.StatusInternalServerError) + return + } + } else { + var err error + keys, err = store.NodeKeys(common.HexToAddress(node), common.Hex2Bytes(start), limit) + if err != nil { + log.Error("chunk explorer: keys handler: get node keys", "node", node, "start", start, "err", err) + jsonStatusResponse(w, http.StatusInternalServerError) + return + } + } + ks := make([]string, len(keys.Keys)) + for i, k := range keys.Keys { + ks[i] = common.Bytes2Hex(k) + } + data, err := json.Marshal(KeysResponse{ + Keys: ks, + Next: common.Bytes2Hex(keys.Next), + }) + if err != nil { + log.Error("chunk explorer: keys handler: json marshal", "err", err) + jsonStatusResponse(w, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", jsonContentType) + _, err = io.Copy(w, bytes.NewReader(data)) + if err != nil { + log.Error("chunk explorer: keys handler: write response", "err", err) + } + } +} + +// NodesResponse is a JSON-encoded response for global store +// Nodes and KeyNodes methods. +type NodesResponse struct { + Nodes []string `json:"nodes"` + Next string `json:"next,omitempty"` +} + +// newNodesHandler returns a new handler that serves +// requests for Nodes global store method. +// HTTP response body will be JSON-encoded NodesResponse. +func newNodesHandler(store mock.GlobalStorer) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + q := r.URL.Query() + key := q.Get("key") + var start *common.Address + queryStart, limit := listingPage(q) + if queryStart != "" { + s := common.HexToAddress(queryStart) + start = &s + } + + var nodes mock.Nodes + if key == "" { + var err error + nodes, err = store.Nodes(start, limit) + if err != nil { + log.Error("chunk explorer: nodes handler: get nodes", "start", queryStart, "err", err) + jsonStatusResponse(w, http.StatusInternalServerError) + return + } + } else { + var err error + nodes, err = store.KeyNodes(common.Hex2Bytes(key), start, limit) + if err != nil { + log.Error("chunk explorer: nodes handler: get key nodes", "key", key, "start", queryStart, "err", err) + jsonStatusResponse(w, http.StatusInternalServerError) + return + } + } + ns := make([]string, len(nodes.Addrs)) + for i, n := range nodes.Addrs { + ns[i] = n.Hex() + } + var next string + if nodes.Next != nil { + next = nodes.Next.Hex() + } + data, err := json.Marshal(NodesResponse{ + Nodes: ns, + Next: next, + }) + if err != nil { + log.Error("chunk explorer: nodes handler", "err", err) + jsonStatusResponse(w, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", jsonContentType) + _, err = io.Copy(w, bytes.NewReader(data)) + if err != nil { + log.Error("chunk explorer: nodes handler: write response", "err", err) + } + } +} + +// parseHasKeyPath extracts address and key from HTTP request +// path for HasKey route: /api/has-key/{node}/{key}. +// If ok is false, the provided path is not matched. +func parseHasKeyPath(p string) (addr common.Address, key []byte, ok bool) { + p = strings.TrimPrefix(p, "/api/has-key/") + parts := strings.SplitN(p, "/", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return addr, nil, false + } + addr = common.HexToAddress(parts[0]) + key = common.Hex2Bytes(parts[1]) + return addr, key, true +} + +// listingPage returns start value and listing limit +// from url query values. +func listingPage(q url.Values) (start string, limit int) { + // if limit is not a valid integer (or blank string), + // ignore the error and use the returned 0 value + limit, _ = strconv.Atoi(q.Get("limit")) + return q.Get("start"), limit +} + +// StatusResponse is a standardized JSON-encoded response +// that contains information about HTTP response code +// for easier status identification. +type StatusResponse struct { + Message string `json:"message"` + Code int `json:"code"` +} + +// jsonStatusResponse writes to the response writer +// JSON-encoded StatusResponse based on the provided status code. +func jsonStatusResponse(w http.ResponseWriter, code int) { + w.Header().Set("Content-Type", jsonContentType) + w.WriteHeader(code) + err := json.NewEncoder(w).Encode(StatusResponse{ + Message: http.StatusText(code), + Code: code, + }) + if err != nil { + log.Error("chunk explorer: json status response", "err", err) + } +} + +// noCacheHandler sets required HTTP headers to prevent +// response caching at the client side. +func noCacheHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Expires", "0") + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/explorer_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/explorer_test.go new file mode 100644 index 00000000..be266842 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/explorer_test.go @@ -0,0 +1,471 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package explorer + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "os" + "sort" + "strconv" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + "github.com/ethereum/go-ethereum/swarm/storage/mock/db" + "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" +) + +// TestHandler_memGlobalStore runs a set of tests +// to validate handler with mem global store. +func TestHandler_memGlobalStore(t *testing.T) { + t.Parallel() + + globalStore := mem.NewGlobalStore() + + testHandler(t, globalStore) +} + +// TestHandler_dbGlobalStore runs a set of tests +// to validate handler with database global store. +func TestHandler_dbGlobalStore(t *testing.T) { + t.Parallel() + + dir, err := ioutil.TempDir("", "swarm-mock-explorer-db-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + globalStore, err := db.NewGlobalStore(dir) + if err != nil { + t.Fatal(err) + } + defer globalStore.Close() + + testHandler(t, globalStore) +} + +// testHandler stores data distributed by node addresses +// and validates if this data is correctly retrievable +// by using the http.Handler returned by NewHandler function. +// This test covers all HTTP routes and various get parameters +// on them to check paginated results. +func testHandler(t *testing.T, globalStore mock.GlobalStorer) { + const ( + nodeCount = 350 + keyCount = 250 + keysOnNodeCount = 150 + ) + + // keys for every node + nodeKeys := make(map[string][]string) + + // a node address that is not present in global store + invalidAddr := "0x7b8b72938c254cf002c4e1e714d27e022be88d93" + + // a key that is not present in global store + invalidKey := "f9824192fb515cfb" + + for i := 1; i <= nodeCount; i++ { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(i)) + addr := common.BytesToAddress(b).Hex() + nodeKeys[addr] = make([]string, 0) + } + + for i := 1; i <= keyCount; i++ { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(i)) + + key := common.Bytes2Hex(b) + + var c int + for addr := range nodeKeys { + nodeKeys[addr] = append(nodeKeys[addr], key) + c++ + if c >= keysOnNodeCount { + break + } + } + } + + // sort keys for every node as they are expected to be + // sorted in HTTP responses + for _, keys := range nodeKeys { + sort.Strings(keys) + } + + // nodes for every key + keyNodes := make(map[string][]string) + + // construct a reverse mapping of nodes for every key + for addr, keys := range nodeKeys { + for _, key := range keys { + keyNodes[key] = append(keyNodes[key], addr) + } + } + + // sort node addresses with case insensitive sort, + // as hex letters in node addresses are in mixed caps + for _, addrs := range keyNodes { + sortCaseInsensitive(addrs) + } + + // find a key that is not stored at the address + var ( + unmatchedAddr string + unmatchedKey string + ) + for addr, keys := range nodeKeys { + for key := range keyNodes { + var found bool + for _, k := range keys { + if k == key { + found = true + break + } + } + if !found { + unmatchedAddr = addr + unmatchedKey = key + } + break + } + if unmatchedAddr != "" { + break + } + } + // check if unmatched key/address pair is found + if unmatchedAddr == "" || unmatchedKey == "" { + t.Fatalf("could not find a key that is not associated with a node") + } + + // store the data + for addr, keys := range nodeKeys { + for _, key := range keys { + err := globalStore.Put(common.HexToAddress(addr), common.Hex2Bytes(key), []byte("data")) + if err != nil { + t.Fatal(err) + } + } + } + + handler := NewHandler(globalStore, nil) + + // this subtest confirms that it has uploaded key and that it does not have invalid keys + t.Run("has key", func(t *testing.T) { + for addr, keys := range nodeKeys { + for _, key := range keys { + testStatusResponse(t, handler, "/api/has-key/"+addr+"/"+key, http.StatusOK) + testStatusResponse(t, handler, "/api/has-key/"+invalidAddr+"/"+key, http.StatusNotFound) + } + testStatusResponse(t, handler, "/api/has-key/"+addr+"/"+invalidKey, http.StatusNotFound) + } + testStatusResponse(t, handler, "/api/has-key/"+invalidAddr+"/"+invalidKey, http.StatusNotFound) + testStatusResponse(t, handler, "/api/has-key/"+unmatchedAddr+"/"+unmatchedKey, http.StatusNotFound) + }) + + // this subtest confirms that all keys are are listed in correct order with expected pagination + t.Run("keys", func(t *testing.T) { + var allKeys []string + for key := range keyNodes { + allKeys = append(allKeys, key) + } + sort.Strings(allKeys) + + t.Run("limit 0", testKeys(handler, allKeys, 0, "")) + t.Run("limit default", testKeys(handler, allKeys, mock.DefaultLimit, "")) + t.Run("limit 2x default", testKeys(handler, allKeys, 2*mock.DefaultLimit, "")) + t.Run("limit 0.5x default", testKeys(handler, allKeys, mock.DefaultLimit/2, "")) + t.Run("limit max", testKeys(handler, allKeys, mock.MaxLimit, "")) + t.Run("limit 2x max", testKeys(handler, allKeys, 2*mock.MaxLimit, "")) + t.Run("limit negative", testKeys(handler, allKeys, -10, "")) + }) + + // this subtest confirms that all keys are are listed for every node in correct order + // and that for one node different pagination options are correct + t.Run("node keys", func(t *testing.T) { + var limitCheckAddr string + + for addr, keys := range nodeKeys { + testKeys(handler, keys, 0, addr)(t) + if limitCheckAddr == "" { + limitCheckAddr = addr + } + } + testKeys(handler, nil, 0, invalidAddr)(t) + + limitCheckKeys := nodeKeys[limitCheckAddr] + t.Run("limit 0", testKeys(handler, limitCheckKeys, 0, limitCheckAddr)) + t.Run("limit default", testKeys(handler, limitCheckKeys, mock.DefaultLimit, limitCheckAddr)) + t.Run("limit 2x default", testKeys(handler, limitCheckKeys, 2*mock.DefaultLimit, limitCheckAddr)) + t.Run("limit 0.5x default", testKeys(handler, limitCheckKeys, mock.DefaultLimit/2, limitCheckAddr)) + t.Run("limit max", testKeys(handler, limitCheckKeys, mock.MaxLimit, limitCheckAddr)) + t.Run("limit 2x max", testKeys(handler, limitCheckKeys, 2*mock.MaxLimit, limitCheckAddr)) + t.Run("limit negative", testKeys(handler, limitCheckKeys, -10, limitCheckAddr)) + }) + + // this subtest confirms that all nodes are are listed in correct order with expected pagination + t.Run("nodes", func(t *testing.T) { + var allNodes []string + for addr := range nodeKeys { + allNodes = append(allNodes, addr) + } + sortCaseInsensitive(allNodes) + + t.Run("limit 0", testNodes(handler, allNodes, 0, "")) + t.Run("limit default", testNodes(handler, allNodes, mock.DefaultLimit, "")) + t.Run("limit 2x default", testNodes(handler, allNodes, 2*mock.DefaultLimit, "")) + t.Run("limit 0.5x default", testNodes(handler, allNodes, mock.DefaultLimit/2, "")) + t.Run("limit max", testNodes(handler, allNodes, mock.MaxLimit, "")) + t.Run("limit 2x max", testNodes(handler, allNodes, 2*mock.MaxLimit, "")) + t.Run("limit negative", testNodes(handler, allNodes, -10, "")) + }) + + // this subtest confirms that all nodes are are listed that contain a a particular key in correct order + // and that for one key different node pagination options are correct + t.Run("key nodes", func(t *testing.T) { + var limitCheckKey string + + for key, addrs := range keyNodes { + testNodes(handler, addrs, 0, key)(t) + if limitCheckKey == "" { + limitCheckKey = key + } + } + testNodes(handler, nil, 0, invalidKey)(t) + + limitCheckKeys := keyNodes[limitCheckKey] + t.Run("limit 0", testNodes(handler, limitCheckKeys, 0, limitCheckKey)) + t.Run("limit default", testNodes(handler, limitCheckKeys, mock.DefaultLimit, limitCheckKey)) + t.Run("limit 2x default", testNodes(handler, limitCheckKeys, 2*mock.DefaultLimit, limitCheckKey)) + t.Run("limit 0.5x default", testNodes(handler, limitCheckKeys, mock.DefaultLimit/2, limitCheckKey)) + t.Run("limit max", testNodes(handler, limitCheckKeys, mock.MaxLimit, limitCheckKey)) + t.Run("limit 2x max", testNodes(handler, limitCheckKeys, 2*mock.MaxLimit, limitCheckKey)) + t.Run("limit negative", testNodes(handler, limitCheckKeys, -10, limitCheckKey)) + }) +} + +// testsKeys returns a test function that validates wantKeys against a series of /api/keys +// HTTP responses with provided limit and node options. +func testKeys(handler http.Handler, wantKeys []string, limit int, node string) func(t *testing.T) { + return func(t *testing.T) { + t.Helper() + + wantLimit := limit + if wantLimit <= 0 { + wantLimit = mock.DefaultLimit + } + if wantLimit > mock.MaxLimit { + wantLimit = mock.MaxLimit + } + wantKeysLen := len(wantKeys) + var i int + var startKey string + for { + var wantNext string + start := i * wantLimit + end := (i + 1) * wantLimit + if end < wantKeysLen { + wantNext = wantKeys[end] + } else { + end = wantKeysLen + } + testKeysResponse(t, handler, node, startKey, limit, KeysResponse{ + Keys: wantKeys[start:end], + Next: wantNext, + }) + if wantNext == "" { + break + } + startKey = wantNext + i++ + } + } +} + +// testNodes returns a test function that validates wantAddrs against a series of /api/nodes +// HTTP responses with provided limit and key options. +func testNodes(handler http.Handler, wantAddrs []string, limit int, key string) func(t *testing.T) { + return func(t *testing.T) { + t.Helper() + + wantLimit := limit + if wantLimit <= 0 { + wantLimit = mock.DefaultLimit + } + if wantLimit > mock.MaxLimit { + wantLimit = mock.MaxLimit + } + wantAddrsLen := len(wantAddrs) + var i int + var startKey string + for { + var wantNext string + start := i * wantLimit + end := (i + 1) * wantLimit + if end < wantAddrsLen { + wantNext = wantAddrs[end] + } else { + end = wantAddrsLen + } + testNodesResponse(t, handler, key, startKey, limit, NodesResponse{ + Nodes: wantAddrs[start:end], + Next: wantNext, + }) + if wantNext == "" { + break + } + startKey = wantNext + i++ + } + } +} + +// testStatusResponse validates a response made on url if it matches +// the expected StatusResponse. +func testStatusResponse(t *testing.T, handler http.Handler, url string, code int) { + t.Helper() + + resp := httpGet(t, handler, url) + + if resp.StatusCode != code { + t.Errorf("got status code %v, want %v", resp.StatusCode, code) + } + if got := resp.Header.Get("Content-Type"); got != jsonContentType { + t.Errorf("got Content-Type header %q, want %q", got, jsonContentType) + } + var r StatusResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + t.Fatal(err) + } + if r.Code != code { + t.Errorf("got response code %v, want %v", r.Code, code) + } + if r.Message != http.StatusText(code) { + t.Errorf("got response message %q, want %q", r.Message, http.StatusText(code)) + } +} + +// testKeysResponse validates response returned from handler on /api/keys +// with node, start and limit options against KeysResponse. +func testKeysResponse(t *testing.T, handler http.Handler, node, start string, limit int, want KeysResponse) { + t.Helper() + + u, err := url.Parse("/api/keys") + if err != nil { + t.Fatal(err) + } + q := u.Query() + if node != "" { + q.Set("node", node) + } + if start != "" { + q.Set("start", start) + } + if limit != 0 { + q.Set("limit", strconv.Itoa(limit)) + } + u.RawQuery = q.Encode() + + resp := httpGet(t, handler, u.String()) + + if resp.StatusCode != http.StatusOK { + t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) + } + if got := resp.Header.Get("Content-Type"); got != jsonContentType { + t.Errorf("got Content-Type header %q, want %q", got, jsonContentType) + } + var r KeysResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + t.Fatal(err) + } + if fmt.Sprint(r.Keys) != fmt.Sprint(want.Keys) { + t.Errorf("got keys %v, want %v", r.Keys, want.Keys) + } + if r.Next != want.Next { + t.Errorf("got next %s, want %s", r.Next, want.Next) + } +} + +// testNodesResponse validates response returned from handler on /api/nodes +// with key, start and limit options against NodesResponse. +func testNodesResponse(t *testing.T, handler http.Handler, key, start string, limit int, want NodesResponse) { + t.Helper() + + u, err := url.Parse("/api/nodes") + if err != nil { + t.Fatal(err) + } + q := u.Query() + if key != "" { + q.Set("key", key) + } + if start != "" { + q.Set("start", start) + } + if limit != 0 { + q.Set("limit", strconv.Itoa(limit)) + } + u.RawQuery = q.Encode() + + resp := httpGet(t, handler, u.String()) + + if resp.StatusCode != http.StatusOK { + t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) + } + if got := resp.Header.Get("Content-Type"); got != jsonContentType { + t.Errorf("got Content-Type header %q, want %q", got, jsonContentType) + } + var r NodesResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + t.Fatal(err) + } + if fmt.Sprint(r.Nodes) != fmt.Sprint(want.Nodes) { + t.Errorf("got nodes %v, want %v", r.Nodes, want.Nodes) + } + if r.Next != want.Next { + t.Errorf("got next %s, want %s", r.Next, want.Next) + } +} + +// httpGet uses httptest recorder to provide a response on handler's url. +func httpGet(t *testing.T, handler http.Handler, url string) (r *http.Response) { + t.Helper() + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + t.Fatal(err) + } + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + return w.Result() +} + +// sortCaseInsensitive performs a case insensitive sort on a string slice. +func sortCaseInsensitive(s []string) { + sort.Slice(s, func(i, j int) bool { + return strings.ToLower(s[i]) < strings.ToLower(s[j]) + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/headers_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/headers_test.go new file mode 100644 index 00000000..5b8e05ff --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/headers_test.go @@ -0,0 +1,163 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package explorer + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" +) + +// TestHandler_CORSOrigin validates that the correct Access-Control-Allow-Origin +// header is served with various allowed origin settings. +func TestHandler_CORSOrigin(t *testing.T) { + notAllowedOrigin := "http://not-allowed-origin.com/" + + for _, tc := range []struct { + name string + origins []string + }{ + { + name: "no origin", + origins: nil, + }, + { + name: "single origin", + origins: []string{"http://localhost/"}, + }, + { + name: "multiple origins", + origins: []string{"http://localhost/", "http://ethereum.org/"}, + }, + } { + t.Run(tc.name, func(t *testing.T) { + handler := NewHandler(mem.NewGlobalStore(), tc.origins) + + origins := tc.origins + if origins == nil { + // handle the "no origin" test case + origins = []string{""} + } + + for _, origin := range origins { + t.Run(fmt.Sprintf("get %q", origin), newTestCORSOrigin(handler, origin, origin)) + t.Run(fmt.Sprintf("preflight %q", origin), newTestCORSPreflight(handler, origin, origin)) + } + + t.Run(fmt.Sprintf("get %q", notAllowedOrigin), newTestCORSOrigin(handler, notAllowedOrigin, "")) + t.Run(fmt.Sprintf("preflight %q", notAllowedOrigin), newTestCORSPreflight(handler, notAllowedOrigin, "")) + }) + } + + t.Run("wildcard", func(t *testing.T) { + handler := NewHandler(mem.NewGlobalStore(), []string{"*"}) + + for _, origin := range []string{ + "http://example.com/", + "http://ethereum.org", + "http://localhost", + } { + t.Run(fmt.Sprintf("get %q", origin), newTestCORSOrigin(handler, origin, origin)) + t.Run(fmt.Sprintf("preflight %q", origin), newTestCORSPreflight(handler, origin, origin)) + } + }) +} + +// newTestCORSOrigin returns a test function that validates if wantOrigin CORS header is +// served by the handler for a GET request. +func newTestCORSOrigin(handler http.Handler, origin, wantOrigin string) func(t *testing.T) { + return func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, "/", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Origin", origin) + + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + resp := w.Result() + + header := resp.Header.Get("Access-Control-Allow-Origin") + if header != wantOrigin { + t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, wantOrigin) + } + } +} + +// newTestCORSPreflight returns a test function that validates if wantOrigin CORS header is +// served by the handler for an OPTIONS CORS preflight request. +func newTestCORSPreflight(handler http.Handler, origin, wantOrigin string) func(t *testing.T) { + return func(t *testing.T) { + req, err := http.NewRequest(http.MethodOptions, "/", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Origin", origin) + req.Header.Set("Access-Control-Request-Method", "GET") + + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + resp := w.Result() + + header := resp.Header.Get("Access-Control-Allow-Origin") + if header != wantOrigin { + t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, wantOrigin) + } + } +} + +// TestHandler_noCacheHeaders validates that no cache headers are server. +func TestHandler_noCacheHeaders(t *testing.T) { + handler := NewHandler(mem.NewGlobalStore(), nil) + + for _, tc := range []struct { + url string + }{ + { + url: "/", + }, + { + url: "/api/nodes", + }, + { + url: "/api/keys", + }, + } { + req, err := http.NewRequest(http.MethodGet, tc.url, nil) + if err != nil { + t.Fatal(err) + } + + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) + resp := w.Result() + + for header, want := range map[string]string{ + "Cache-Control": "no-cache, no-store, must-revalidate", + "Pragma": "no-cache", + "Expires": "0", + } { + got := resp.Header.Get(header) + if got != want { + t.Errorf("got %q header %q for url %q, want %q", header, tc.url, got, want) + } + } + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/swagger.yaml b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/swagger.yaml new file mode 100644 index 00000000..2c014e92 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/explorer/swagger.yaml @@ -0,0 +1,176 @@ +swagger: '2.0' +info: + title: Swarm Global Store API + version: 0.1.0 +tags: + - name: Has Key + description: Checks if a Key is stored on a Node + - name: Keys + description: Lists Keys + - name: Nodes + description: Lists Node addresses + +paths: + '/api/has-key/{node}/{key}': + get: + tags: + - Has Key + summary: Checks if a Key is stored on a Node + operationId: hasKey + produces: + - application/json + + parameters: + - name: node + in: path + required: true + type: string + format: hex-endoded + description: Node address. + + - name: key + in: path + required: true + type: string + format: hex-endoded + description: Key. + + responses: + '200': + description: Key is stored on Node + schema: + $ref: '#/definitions/Status' + '404': + description: Key is not stored on Node + schema: + $ref: '#/definitions/Status' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Status' + + '/api/keys': + get: + tags: + - Keys + summary: Lists Keys + operationId: keys + produces: + - application/json + + parameters: + - name: start + in: query + required: false + type: string + format: hex-encoded Key + description: A Key as the starting point for the returned list. It is usually a value from the returned "next" field in the Keys repsonse. + + - name: limit + in: query + required: false + type: integer + default: 100 + minimum: 1 + maximum: 1000 + description: Limits the number of Keys returned in on response. + + - name: node + in: query + required: false + type: string + format: hex-encoded Node address + description: If this parameter is provided, only Keys that are stored on this Node be returned in the response. If not, all known Keys will be returned. + + responses: + '200': + description: List of Keys + schema: + $ref: '#/definitions/Keys' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Status' + + '/api/nodes': + get: + tags: + - Nodes + summary: Lists Node addresses + operationId: nodes + produces: + - application/json + + parameters: + - name: start + in: query + required: false + type: string + format: hex-encoded Node address + description: A Node address as the starting point for the returned list. It is usually a value from the returned "next" field in the Nodes repsonse. + + - name: limit + in: query + required: false + type: integer + default: 100 + minimum: 1 + maximum: 1000 + description: Limits the number of Node addresses returned in on response. + + - name: key + in: query + required: false + type: string + format: hex-encoded Key + description: If this parameter is provided, only addresses of Nodes that store this Key will be returned in the response. If not, all known Node addresses will be returned. + + responses: + '200': + description: List of Node addresses + schema: + $ref: '#/definitions/Nodes' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Status' + +definitions: + + Status: + type: object + properties: + message: + type: string + description: HTTP Status Code name. + code: + type: integer + description: HTTP Status Code. + + Keys: + type: object + properties: + keys: + type: array + description: A list of Keys. + items: + type: string + format: hex-encoded Key + next: + type: string + format: hex-encoded Key + description: If present, the next Key in listing. Can be passed as "start" query parameter to continue the listing. If not present, the end of the listing is reached. + + Nodes: + type: object + properties: + nodes: + type: array + description: A list of Node addresses. + items: + type: string + format: hex-encoded Node address + next: + type: string + format: hex-encoded Node address + description: If present, the next Node address in listing. Can be passed as "start" query parameter to continue the listing. If not present, the end of the listing is reached. diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem.go index 8878309d..38bf098d 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem.go @@ -25,6 +25,7 @@ import ( "encoding/json" "io" "io/ioutil" + "sort" "sync" "github.com/ethereum/go-ethereum/common" @@ -34,16 +35,27 @@ import ( // GlobalStore stores all chunk data and also keys and node addresses relations. // It implements mock.GlobalStore interface. type GlobalStore struct { - nodes map[string]map[common.Address]struct{} - data map[string][]byte - mu sync.Mutex + // holds a slice of keys per node + nodeKeys map[common.Address][][]byte + // holds which key is stored on which nodes + keyNodes map[string][]common.Address + // all node addresses + nodes []common.Address + // all keys + keys [][]byte + // all keys data + data map[string][]byte + mu sync.RWMutex } // NewGlobalStore creates a new instance of GlobalStore. func NewGlobalStore() *GlobalStore { return &GlobalStore{ - nodes: make(map[string]map[common.Address]struct{}), - data: make(map[string][]byte), + nodeKeys: make(map[common.Address][][]byte), + keyNodes: make(map[string][]common.Address), + nodes: make([]common.Address, 0), + keys: make([][]byte, 0), + data: make(map[string][]byte), } } @@ -56,10 +68,10 @@ func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { // Get returns chunk data if the chunk with key exists for node // on address addr. func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { - s.mu.Lock() - defer s.mu.Unlock() + s.mu.RLock() + defer s.mu.RUnlock() - if _, ok := s.nodes[string(key)][addr]; !ok { + if _, has := s.nodeKeyIndex(addr, key); !has { return nil, mock.ErrNotFound } @@ -75,21 +87,212 @@ func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { s.mu.Lock() defer s.mu.Unlock() - if _, ok := s.nodes[string(key)]; !ok { - s.nodes[string(key)] = make(map[common.Address]struct{}) + if i, found := s.nodeKeyIndex(addr, key); !found { + s.nodeKeys[addr] = append(s.nodeKeys[addr], nil) + copy(s.nodeKeys[addr][i+1:], s.nodeKeys[addr][i:]) + s.nodeKeys[addr][i] = key } - s.nodes[string(key)][addr] = struct{}{} + + if i, found := s.keyNodeIndex(key, addr); !found { + k := string(key) + s.keyNodes[k] = append(s.keyNodes[k], addr) + copy(s.keyNodes[k][i+1:], s.keyNodes[k][i:]) + s.keyNodes[k][i] = addr + } + + if i, found := s.nodeIndex(addr); !found { + s.nodes = append(s.nodes, addr) + copy(s.nodes[i+1:], s.nodes[i:]) + s.nodes[i] = addr + } + + if i, found := s.keyIndex(key); !found { + s.keys = append(s.keys, nil) + copy(s.keys[i+1:], s.keys[i:]) + s.keys[i] = key + } + s.data[string(key)] = data + + return nil +} + +// Delete removes the chunk data for node with address addr. +func (s *GlobalStore) Delete(addr common.Address, key []byte) error { + s.mu.Lock() + defer s.mu.Unlock() + + if i, has := s.nodeKeyIndex(addr, key); has { + s.nodeKeys[addr] = append(s.nodeKeys[addr][:i], s.nodeKeys[addr][i+1:]...) + } + + k := string(key) + if i, on := s.keyNodeIndex(key, addr); on { + s.keyNodes[k] = append(s.keyNodes[k][:i], s.keyNodes[k][i+1:]...) + } + + if len(s.nodeKeys[addr]) == 0 { + if i, found := s.nodeIndex(addr); found { + s.nodes = append(s.nodes[:i], s.nodes[i+1:]...) + } + } + + if len(s.keyNodes[k]) == 0 { + if i, found := s.keyIndex(key); found { + s.keys = append(s.keys[:i], s.keys[i+1:]...) + } + } return nil } // HasKey returns whether a node with addr contains the key. -func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { - s.mu.Lock() - defer s.mu.Unlock() +func (s *GlobalStore) HasKey(addr common.Address, key []byte) (yes bool) { + s.mu.RLock() + defer s.mu.RUnlock() - _, ok := s.nodes[string(key)][addr] - return ok + _, yes = s.nodeKeyIndex(addr, key) + return yes +} + +// keyIndex returns the index of a key in keys slice. +func (s *GlobalStore) keyIndex(key []byte) (index int, found bool) { + l := len(s.keys) + index = sort.Search(l, func(i int) bool { + return bytes.Compare(s.keys[i], key) >= 0 + }) + found = index < l && bytes.Equal(s.keys[index], key) + return index, found +} + +// nodeIndex returns the index of a node address in nodes slice. +func (s *GlobalStore) nodeIndex(addr common.Address) (index int, found bool) { + l := len(s.nodes) + index = sort.Search(l, func(i int) bool { + return bytes.Compare(s.nodes[i][:], addr[:]) >= 0 + }) + found = index < l && bytes.Equal(s.nodes[index][:], addr[:]) + return index, found +} + +// nodeKeyIndex returns the index of a key in nodeKeys slice. +func (s *GlobalStore) nodeKeyIndex(addr common.Address, key []byte) (index int, found bool) { + l := len(s.nodeKeys[addr]) + index = sort.Search(l, func(i int) bool { + return bytes.Compare(s.nodeKeys[addr][i], key) >= 0 + }) + found = index < l && bytes.Equal(s.nodeKeys[addr][index], key) + return index, found +} + +// keyNodeIndex returns the index of a node address in keyNodes slice. +func (s *GlobalStore) keyNodeIndex(key []byte, addr common.Address) (index int, found bool) { + k := string(key) + l := len(s.keyNodes[k]) + index = sort.Search(l, func(i int) bool { + return bytes.Compare(s.keyNodes[k][i][:], addr[:]) >= 0 + }) + found = index < l && s.keyNodes[k][index] == addr + return index, found +} + +// Keys returns a paginated list of keys on all nodes. +func (s *GlobalStore) Keys(startKey []byte, limit int) (keys mock.Keys, err error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var i int + if startKey != nil { + i, _ = s.keyIndex(startKey) + } + total := len(s.keys) + max := maxIndex(i, limit, total) + keys.Keys = make([][]byte, 0, max-i) + for ; i < max; i++ { + keys.Keys = append(keys.Keys, append([]byte(nil), s.keys[i]...)) + } + if total > max { + keys.Next = s.keys[max] + } + return keys, nil +} + +// Nodes returns a paginated list of all known nodes. +func (s *GlobalStore) Nodes(startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var i int + if startAddr != nil { + i, _ = s.nodeIndex(*startAddr) + } + total := len(s.nodes) + max := maxIndex(i, limit, total) + nodes.Addrs = make([]common.Address, 0, max-i) + for ; i < max; i++ { + nodes.Addrs = append(nodes.Addrs, s.nodes[i]) + } + if total > max { + nodes.Next = &s.nodes[max] + } + return nodes, nil +} + +// NodeKeys returns a paginated list of keys on a node with provided address. +func (s *GlobalStore) NodeKeys(addr common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var i int + if startKey != nil { + i, _ = s.nodeKeyIndex(addr, startKey) + } + total := len(s.nodeKeys[addr]) + max := maxIndex(i, limit, total) + keys.Keys = make([][]byte, 0, max-i) + for ; i < max; i++ { + keys.Keys = append(keys.Keys, append([]byte(nil), s.nodeKeys[addr][i]...)) + } + if total > max { + keys.Next = s.nodeKeys[addr][max] + } + return keys, nil +} + +// KeyNodes returns a paginated list of nodes that contain a particular key. +func (s *GlobalStore) KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var i int + if startAddr != nil { + i, _ = s.keyNodeIndex(key, *startAddr) + } + total := len(s.keyNodes[string(key)]) + max := maxIndex(i, limit, total) + nodes.Addrs = make([]common.Address, 0, max-i) + for ; i < max; i++ { + nodes.Addrs = append(nodes.Addrs, s.keyNodes[string(key)][i]) + } + if total > max { + nodes.Next = &s.keyNodes[string(key)][max] + } + return nodes, nil +} + +// maxIndex returns the end index for one page listing +// based on the start index, limit and total number of elements. +func maxIndex(start, limit, total int) (max int) { + if limit <= 0 { + limit = mock.DefaultLimit + } + if limit > mock.MaxLimit { + limit = mock.MaxLimit + } + max = total + if start+limit < max { + max = start + limit + } + return max } // Import reads tar archive from a reader that contains exported chunk data. @@ -119,14 +322,26 @@ func (s *GlobalStore) Import(r io.Reader) (n int, err error) { return n, err } - addrs := make(map[common.Address]struct{}) - for _, a := range c.Addrs { - addrs[a] = struct{}{} + key := common.Hex2Bytes(hdr.Name) + s.keyNodes[string(key)] = c.Addrs + for _, addr := range c.Addrs { + if i, has := s.nodeKeyIndex(addr, key); !has { + s.nodeKeys[addr] = append(s.nodeKeys[addr], nil) + copy(s.nodeKeys[addr][i+1:], s.nodeKeys[addr][i:]) + s.nodeKeys[addr][i] = key + } + if i, found := s.nodeIndex(addr); !found { + s.nodes = append(s.nodes, addr) + copy(s.nodes[i+1:], s.nodes[i:]) + s.nodes[i] = addr + } } - - key := string(common.Hex2Bytes(hdr.Name)) - s.nodes[key] = addrs - s.data[key] = c.Data + if i, found := s.keyIndex(key); !found { + s.keys = append(s.keys, nil) + copy(s.keys[i+1:], s.keys[i:]) + s.keys[i] = key + } + s.data[string(key)] = c.Data n++ } return n, err @@ -135,23 +350,18 @@ func (s *GlobalStore) Import(r io.Reader) (n int, err error) { // Export writes to a writer a tar archive with all chunk data from // the store. It returns the number of chunks exported and an error. func (s *GlobalStore) Export(w io.Writer) (n int, err error) { - s.mu.Lock() - defer s.mu.Unlock() + s.mu.RLock() + defer s.mu.RUnlock() tw := tar.NewWriter(w) defer tw.Close() buf := bytes.NewBuffer(make([]byte, 0, 1024)) encoder := json.NewEncoder(buf) - for key, addrs := range s.nodes { - al := make([]common.Address, 0, len(addrs)) - for a := range addrs { - al = append(al, a) - } - + for key, addrs := range s.keyNodes { buf.Reset() if err = encoder.Encode(mock.ExportedChunk{ - Addrs: al, + Addrs: addrs, Data: s.data[key], }); err != nil { return n, err diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem_test.go index adcefaab..d39aaef4 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mem/mem_test.go @@ -28,6 +28,12 @@ func TestGlobalStore(t *testing.T) { test.MockStore(t, NewGlobalStore(), 100) } +// TestGlobalStoreListings is running test for a GlobalStore +// using test.MockStoreListings function. +func TestGlobalStoreListings(t *testing.T) { + test.MockStoreListings(t, NewGlobalStore(), 1000) +} + // TestImportExport is running tests for importing and // exporting data between two GlobalStores // using test.ImportExport function. diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mock.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mock.go index 81340f92..586112a9 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mock.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/mock.go @@ -39,6 +39,17 @@ import ( "github.com/ethereum/go-ethereum/common" ) +const ( + // DefaultLimit should be used as default limit for + // Keys, Nodes, NodeKeys and KeyNodes GlobarStorer + // methids implementations. + DefaultLimit = 100 + // MaxLimit should be used as the maximal returned number + // of items for Keys, Nodes, NodeKeys and KeyNodes GlobarStorer + // methids implementations, regardless of provided limit. + MaxLimit = 1000 +) + // ErrNotFound indicates that the chunk is not found. var ErrNotFound = errors.New("not found") @@ -70,6 +81,16 @@ func (n *NodeStore) Put(key []byte, data []byte) error { return n.store.Put(n.addr, key, data) } +// Delete removes chunk data for a key for a node that has the address +// provided on NodeStore initialization. +func (n *NodeStore) Delete(key []byte) error { + return n.store.Delete(n.addr, key) +} + +func (n *NodeStore) Keys(startKey []byte, limit int) (keys Keys, err error) { + return n.store.NodeKeys(n.addr, startKey, limit) +} + // GlobalStorer defines methods for mock db store // that stores chunk data for all swarm nodes. // It is used in tests to construct mock NodeStores @@ -77,13 +98,30 @@ func (n *NodeStore) Put(key []byte, data []byte) error { type GlobalStorer interface { Get(addr common.Address, key []byte) (data []byte, err error) Put(addr common.Address, key []byte, data []byte) error + Delete(addr common.Address, key []byte) error HasKey(addr common.Address, key []byte) bool + Keys(startKey []byte, limit int) (keys Keys, err error) + Nodes(startAddr *common.Address, limit int) (nodes Nodes, err error) + NodeKeys(addr common.Address, startKey []byte, limit int) (keys Keys, err error) + KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes Nodes, err error) // NewNodeStore creates an instance of NodeStore // to be used by a single swarm node with // address addr. NewNodeStore(addr common.Address) *NodeStore } +// Keys are returned results by Keys and NodeKeys GlobalStorer methods. +type Keys struct { + Keys [][]byte + Next []byte +} + +// Nodes are returned results by Nodes and KeyNodes GlobalStorer methods. +type Nodes struct { + Addrs []common.Address + Next *common.Address +} + // Importer defines method for importing mock store data // from an exported tar archive. type Importer interface { @@ -96,13 +134,6 @@ type Exporter interface { Export(w io.Writer) (n int, err error) } -// ImportExporter is an interface for importing and exporting -// mock store data to and from a tar archive. -type ImportExporter interface { - Importer - Exporter -} - // ExportedChunk is the structure that is saved in tar archive for // each chunk as JSON-encoded bytes. type ExportedChunk struct { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc.go index 6e735f69..8150ccff 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc.go @@ -73,6 +73,12 @@ func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { return err } +// Delete calls a Delete method to RPC server. +func (s *GlobalStore) Delete(addr common.Address, key []byte) error { + err := s.client.Call(nil, "mockStore_delete", addr, key) + return err +} + // HasKey calls a HasKey method to RPC server. func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { var has bool @@ -82,3 +88,27 @@ func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { } return has } + +// Keys returns a paginated list of keys on all nodes. +func (s *GlobalStore) Keys(startKey []byte, limit int) (keys mock.Keys, err error) { + err = s.client.Call(&keys, "mockStore_keys", startKey, limit) + return keys, err +} + +// Nodes returns a paginated list of all known nodes. +func (s *GlobalStore) Nodes(startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + err = s.client.Call(&nodes, "mockStore_nodes", startAddr, limit) + return nodes, err +} + +// NodeKeys returns a paginated list of keys on a node with provided address. +func (s *GlobalStore) NodeKeys(addr common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { + err = s.client.Call(&keys, "mockStore_nodeKeys", addr, startKey, limit) + return keys, err +} + +// KeyNodes returns a paginated list of nodes that contain a particular key. +func (s *GlobalStore) KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { + err = s.client.Call(&nodes, "mockStore_keyNodes", key, startAddr, limit) + return nodes, err +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc_test.go index 52b634a4..6c465235 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/rpc/rpc_test.go @@ -27,6 +27,27 @@ import ( // TestDBStore is running test for a GlobalStore // using test.MockStore function. func TestRPCStore(t *testing.T) { + store, cleanup := newTestStore(t) + defer cleanup() + + test.MockStore(t, store, 30) +} + +// TestRPCStoreListings is running test for a GlobalStore +// using test.MockStoreListings function. +func TestRPCStoreListings(t *testing.T) { + store, cleanup := newTestStore(t) + defer cleanup() + + test.MockStoreListings(t, store, 1000) +} + +// newTestStore creates a temporary GlobalStore +// that will be closed when returned cleanup function +// is called. +func newTestStore(t *testing.T) (s *GlobalStore, cleanup func()) { + t.Helper() + serverStore := mem.NewGlobalStore() server := rpc.NewServer() @@ -35,7 +56,9 @@ func TestRPCStore(t *testing.T) { } store := NewGlobalStore(rpc.DialInProc(server)) - defer store.Close() - - test.MockStore(t, store, 100) + return store, func() { + if err := store.Close(); err != nil { + t.Error(err) + } + } } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/test/test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/test/test.go index 02da3af5..cc837f0b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/test/test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/mock/test/test.go @@ -20,6 +20,7 @@ package test import ( "bytes" + "encoding/binary" "fmt" "io" "strconv" @@ -72,6 +73,31 @@ func MockStore(t *testing.T, globalStore mock.GlobalStorer, n int) { } } } + t.Run("delete", func(t *testing.T) { + chunkAddr := storage.Address([]byte("1234567890abcd")) + for _, addr := range addrs { + err := globalStore.Put(addr, chunkAddr, []byte("data")) + if err != nil { + t.Fatalf("put data to store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) + } + } + firstNodeAddr := addrs[0] + if err := globalStore.Delete(firstNodeAddr, chunkAddr); err != nil { + t.Fatalf("delete from store %s key %s: %v", firstNodeAddr.Hex(), chunkAddr.Hex(), err) + } + for i, addr := range addrs { + _, err := globalStore.Get(addr, chunkAddr) + if i == 0 { + if err != mock.ErrNotFound { + t.Errorf("get data from store %s key %s: expected mock.ErrNotFound error, got %v", addr.Hex(), chunkAddr.Hex(), err) + } + } else { + if err != nil { + t.Errorf("get data from store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) + } + } + } + }) }) t.Run("NodeStore", func(t *testing.T) { @@ -114,9 +140,154 @@ func MockStore(t *testing.T, globalStore mock.GlobalStorer, n int) { } } } + t.Run("delete", func(t *testing.T) { + chunkAddr := storage.Address([]byte("1234567890abcd")) + var chosenStore *mock.NodeStore + for addr, store := range nodes { + if chosenStore == nil { + chosenStore = store + } + err := store.Put(chunkAddr, []byte("data")) + if err != nil { + t.Fatalf("put data to store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) + } + } + if err := chosenStore.Delete(chunkAddr); err != nil { + t.Fatalf("delete key %s: %v", chunkAddr.Hex(), err) + } + for addr, store := range nodes { + _, err := store.Get(chunkAddr) + if store == chosenStore { + if err != mock.ErrNotFound { + t.Errorf("get data from store %s key %s: expected mock.ErrNotFound error, got %v", addr.Hex(), chunkAddr.Hex(), err) + } + } else { + if err != nil { + t.Errorf("get data from store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) + } + } + } + }) }) } +// MockStoreListings tests global store methods Keys, Nodes, NodeKeys and KeyNodes. +// It uses a provided globalstore to put chunks for n number of node addresses +// and to validate that methods are returning the right responses. +func MockStoreListings(t *testing.T, globalStore mock.GlobalStorer, n int) { + addrs := make([]common.Address, n) + for i := 0; i < n; i++ { + addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) + } + type chunk struct { + key []byte + data []byte + } + const chunksPerNode = 5 + keys := make([][]byte, n*chunksPerNode) + for i := 0; i < n*chunksPerNode; i++ { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(i)) + keys[i] = b + } + + // keep track of keys on every node + nodeKeys := make(map[common.Address][][]byte) + // keep track of nodes that store particular key + keyNodes := make(map[string][]common.Address) + for i := 0; i < chunksPerNode; i++ { + // put chunks for every address + for j := 0; j < n; j++ { + addr := addrs[j] + key := keys[(i*n)+j] + err := globalStore.Put(addr, key, []byte("data")) + if err != nil { + t.Fatal(err) + } + nodeKeys[addr] = append(nodeKeys[addr], key) + keyNodes[string(key)] = append(keyNodes[string(key)], addr) + } + + // test Keys method + var startKey []byte + var gotKeys [][]byte + for { + keys, err := globalStore.Keys(startKey, 0) + if err != nil { + t.Fatal(err) + } + gotKeys = append(gotKeys, keys.Keys...) + if keys.Next == nil { + break + } + startKey = keys.Next + } + wantKeys := keys[:(i+1)*n] + if fmt.Sprint(gotKeys) != fmt.Sprint(wantKeys) { + t.Fatalf("got #%v keys %v, want %v", i+1, gotKeys, wantKeys) + } + + // test Nodes method + var startNode *common.Address + var gotNodes []common.Address + for { + nodes, err := globalStore.Nodes(startNode, 0) + if err != nil { + t.Fatal(err) + } + gotNodes = append(gotNodes, nodes.Addrs...) + if nodes.Next == nil { + break + } + startNode = nodes.Next + } + wantNodes := addrs + if fmt.Sprint(gotNodes) != fmt.Sprint(wantNodes) { + t.Fatalf("got #%v nodes %v, want %v", i+1, gotNodes, wantNodes) + } + + // test NodeKeys method + for addr, wantKeys := range nodeKeys { + var startKey []byte + var gotKeys [][]byte + for { + keys, err := globalStore.NodeKeys(addr, startKey, 0) + if err != nil { + t.Fatal(err) + } + gotKeys = append(gotKeys, keys.Keys...) + if keys.Next == nil { + break + } + startKey = keys.Next + } + if fmt.Sprint(gotKeys) != fmt.Sprint(wantKeys) { + t.Fatalf("got #%v %s node keys %v, want %v", i+1, addr.Hex(), gotKeys, wantKeys) + } + } + + // test KeyNodes method + for key, wantNodes := range keyNodes { + var startNode *common.Address + var gotNodes []common.Address + for { + nodes, err := globalStore.KeyNodes([]byte(key), startNode, 0) + if err != nil { + t.Fatal(err) + } + gotNodes = append(gotNodes, nodes.Addrs...) + if nodes.Next == nil { + break + } + startNode = nodes.Next + } + if fmt.Sprint(gotNodes) != fmt.Sprint(wantNodes) { + t.Fatalf("got #%v %x key nodes %v, want %v", i+1, []byte(key), gotNodes, wantNodes) + } + } + } +} + // ImportExport saves chunks to the outStore, exports them to the tar archive, // imports tar archive to the inStore and checks if all chunks are imported correctly. func ImportExport(t *testing.T, outStore, inStore mock.GlobalStorer, n int) { @@ -143,17 +314,22 @@ func ImportExport(t *testing.T, outStore, inStore mock.GlobalStorer, n int) { r, w := io.Pipe() defer r.Close() + exportErrChan := make(chan error) go func() { defer w.Close() - if _, err := exporter.Export(w); err != nil { - t.Fatalf("export: %v", err) - } + + _, err := exporter.Export(w) + exportErrChan <- err }() if _, err := importer.Import(r); err != nil { t.Fatalf("import: %v", err) } + if err := <-exportErrChan; err != nil { + t.Fatalf("export: %v", err) + } + for i, addr := range addrs { chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...)) data := []byte(strconv.FormatInt(int64(i)+1, 16)) diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore.go index 16bc48a9..7741b8f7 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore.go @@ -26,6 +26,11 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/spancontext" + "github.com/opentracing/opentracing-go" + olog "github.com/opentracing/opentracing-go/log" + "github.com/syndtr/goleveldb/leveldb" + lru "github.com/hashicorp/golang-lru" ) @@ -34,8 +39,8 @@ type ( ) type NetFetcher interface { - Request(ctx context.Context, hopCount uint8) - Offer(ctx context.Context, source *enode.ID) + Request(hopCount uint8) + Offer(source *enode.ID) } // NetStore is an extension of local storage @@ -82,7 +87,9 @@ func (n *NetStore) Put(ctx context.Context, ch Chunk) error { // if chunk is now put in the store, check if there was an active fetcher and call deliver on it // (this delivers the chunk to requestors via the fetcher) + log.Trace("n.getFetcher", "ref", ch.Address()) if f := n.getFetcher(ch.Address()); f != nil { + log.Trace("n.getFetcher deliver", "ref", ch.Address()) f.deliver(ctx, ch) } return nil @@ -98,6 +105,14 @@ func (n *NetStore) Get(rctx context.Context, ref Address) (Chunk, error) { return nil, err } if chunk != nil { + // this is not measuring how long it takes to get the chunk for the localstore, but + // rather just adding a span for clarity when inspecting traces in Jaeger, in order + // to make it easier to reason which is the node that actually delivered a chunk. + _, sp := spancontext.StartSpan( + rctx, + "localstore.get") + defer sp.Finish() + return chunk, nil } return fetch(rctx) @@ -128,7 +143,25 @@ func (n *NetStore) FetchFunc(ctx context.Context, ref Address) func(context.Cont func (n *NetStore) Close() { close(n.closeC) n.store.Close() - // TODO: loop through fetchers to cancel them + + wg := sync.WaitGroup{} + for _, key := range n.fetchers.Keys() { + if f, ok := n.fetchers.Get(key); ok { + if fetch, ok := f.(*fetcher); ok { + wg.Add(1) + go func(fetch *fetcher) { + defer wg.Done() + fetch.cancel() + + select { + case <-fetch.deliveredC: + case <-fetch.cancelledC: + } + }(fetch) + } + } + } + wg.Wait() } // get attempts at retrieving the chunk from LocalStore @@ -145,12 +178,13 @@ func (n *NetStore) get(ctx context.Context, ref Address) (Chunk, func(context.Co chunk, err := n.store.Get(ctx, ref) if err != nil { - if err != ErrChunkNotFound { + // TODO: Fix comparison - we should be comparing against leveldb.ErrNotFound, this error should be wrapped. + if err != ErrChunkNotFound && err != leveldb.ErrNotFound { log.Debug("Received error from LocalStore other than ErrNotFound", "err", err) } // The chunk is not available in the LocalStore, let's get the fetcher for it, or create a new one // if it doesn't exist yet - f := n.getOrCreateFetcher(ref) + f := n.getOrCreateFetcher(ctx, ref) // If the caller needs the chunk, it has to use the returned fetch function to get it return nil, f.Fetch, nil } @@ -158,10 +192,17 @@ func (n *NetStore) get(ctx context.Context, ref Address) (Chunk, func(context.Co return chunk, nil, nil } +// Has is the storage layer entry point to query the underlying +// database to return if it has a chunk or not. +// Called from the DebugAPI +func (n *NetStore) Has(ctx context.Context, ref Address) bool { + return n.store.Has(ctx, ref) +} + // getOrCreateFetcher attempts at retrieving an existing fetchers // if none exists, creates one and saves it in the fetchers cache // caller must hold the lock -func (n *NetStore) getOrCreateFetcher(ref Address) *fetcher { +func (n *NetStore) getOrCreateFetcher(ctx context.Context, ref Address) *fetcher { if f := n.getFetcher(ref); f != nil { return f } @@ -169,7 +210,7 @@ func (n *NetStore) getOrCreateFetcher(ref Address) *fetcher { // no fetcher for the given address, we have to create a new one key := hex.EncodeToString(ref) // create the context during which fetching is kept alive - ctx, cancel := context.WithTimeout(context.Background(), fetcherTimeout) + cctx, cancel := context.WithTimeout(ctx, fetcherTimeout) // destroy is called when all requests finish destroy := func() { // remove fetcher from fetchers @@ -183,7 +224,13 @@ func (n *NetStore) getOrCreateFetcher(ref Address) *fetcher { // the peers which requested the chunk should not be requested to deliver it. peers := &sync.Map{} - fetcher := newFetcher(ref, n.NewNetFetcherFunc(ctx, ref, peers), destroy, peers, n.closeC) + cctx, sp := spancontext.StartSpan( + cctx, + "netstore.fetcher", + ) + + sp.LogFields(olog.String("ref", ref.String())) + fetcher := newFetcher(sp, ref, n.NewNetFetcherFunc(cctx, ref, peers), destroy, peers, n.closeC) n.fetchers.Add(key, fetcher) return fetcher @@ -208,15 +255,16 @@ func (n *NetStore) RequestsCacheLen() int { // One fetcher object is responsible to fetch one chunk for one address, and keep track of all the // peers who have requested it and did not receive it yet. type fetcher struct { - addr Address // address of chunk - chunk Chunk // fetcher can set the chunk on the fetcher - deliveredC chan struct{} // chan signalling chunk delivery to requests - cancelledC chan struct{} // chan signalling the fetcher has been cancelled (removed from fetchers in NetStore) - netFetcher NetFetcher // remote fetch function to be called with a request source taken from the context - cancel func() // cleanup function for the remote fetcher to call when all upstream contexts are called - peers *sync.Map // the peers which asked for the chunk - requestCnt int32 // number of requests on this chunk. If all the requests are done (delivered or context is done) the cancel function is called - deliverOnce *sync.Once // guarantees that we only close deliveredC once + addr Address // address of chunk + chunk Chunk // fetcher can set the chunk on the fetcher + deliveredC chan struct{} // chan signalling chunk delivery to requests + cancelledC chan struct{} // chan signalling the fetcher has been cancelled (removed from fetchers in NetStore) + netFetcher NetFetcher // remote fetch function to be called with a request source taken from the context + cancel func() // cleanup function for the remote fetcher to call when all upstream contexts are called + peers *sync.Map // the peers which asked for the chunk + requestCnt int32 // number of requests on this chunk. If all the requests are done (delivered or context is done) the cancel function is called + deliverOnce *sync.Once // guarantees that we only close deliveredC once + span opentracing.Span // measure retrieve time per chunk } // newFetcher creates a new fetcher object for the fiven addr. fetch is the function which actually @@ -225,7 +273,7 @@ type fetcher struct { // 1. when the chunk has been fetched all peers have been either notified or their context has been done // 2. the chunk has not been fetched but all context from all the requests has been done // The peers map stores all the peers which have requested chunk. -func newFetcher(addr Address, nf NetFetcher, cancel func(), peers *sync.Map, closeC chan struct{}) *fetcher { +func newFetcher(span opentracing.Span, addr Address, nf NetFetcher, cancel func(), peers *sync.Map, closeC chan struct{}) *fetcher { cancelOnce := &sync.Once{} // cancel should only be called once return &fetcher{ addr: addr, @@ -239,6 +287,7 @@ func newFetcher(addr Address, nf NetFetcher, cancel func(), peers *sync.Map, clo }) }, peers: peers, + span: span, } } @@ -251,6 +300,7 @@ func (f *fetcher) Fetch(rctx context.Context) (Chunk, error) { if atomic.AddInt32(&f.requestCnt, -1) == 0 { f.cancel() } + f.span.Finish() }() // The peer asking for the chunk. Store in the shared peers map, but delete after the request @@ -271,9 +321,9 @@ func (f *fetcher) Fetch(rctx context.Context) (Chunk, error) { if err := source.UnmarshalText([]byte(sourceIF.(string))); err != nil { return nil, err } - f.netFetcher.Offer(rctx, &source) + f.netFetcher.Offer(&source) } else { - f.netFetcher.Request(rctx, hopCount) + f.netFetcher.Request(hopCount) } // wait until either the chunk is delivered or the context is done @@ -293,5 +343,6 @@ func (f *fetcher) deliver(ctx context.Context, ch Chunk) { f.chunk = ch // closing the deliveredC channel will terminate ongoing requests close(f.deliveredC) + log.Trace("n.getFetcher close deliveredC", "ref", ch.Address()) }) } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore_test.go index 8a09fa5a..65387762 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/netstore_test.go @@ -20,6 +20,8 @@ import ( "bytes" "context" "crypto/rand" + "errors" + "fmt" "io/ioutil" "sync" "testing" @@ -27,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/p2p/enode" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" ) var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") @@ -41,14 +43,18 @@ type mockNetFetcher struct { quit <-chan struct{} ctx context.Context hopCounts []uint8 + mu sync.Mutex } -func (m *mockNetFetcher) Offer(ctx context.Context, source *enode.ID) { +func (m *mockNetFetcher) Offer(source *enode.ID) { m.offerCalled = true m.sources = append(m.sources, source) } -func (m *mockNetFetcher) Request(ctx context.Context, hopCount uint8) { +func (m *mockNetFetcher) Request(hopCount uint8) { + m.mu.Lock() + defer m.mu.Unlock() + m.requestCalled = true var peers []Address m.peers.Range(func(key interface{}, _ interface{}) bool { @@ -108,25 +114,30 @@ func mustNewNetStoreWithFetcher(t *testing.T) (*NetStore, *mockNetFetcher) { func TestNetStoreGetAndPut(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() c := make(chan struct{}) // this channel ensures that the gouroutine with the Put does not run earlier than the Get + putErrC := make(chan error) go func() { <-c // wait for the Get to be called time.Sleep(200 * time.Millisecond) // and a little more so it is surely called // check if netStore created a fetcher in the Get call for the unavailable chunk if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { - t.Fatal("Expected netStore to use a fetcher for the Get call") + putErrC <- errors.New("Expected netStore to use a fetcher for the Get call") + return } err := netStore.Put(ctx, chunk) if err != nil { - t.Fatalf("Expected no err got %v", err) + putErrC <- fmt.Errorf("Expected no err got %v", err) + return } + + putErrC <- nil }() close(c) @@ -134,6 +145,10 @@ func TestNetStoreGetAndPut(t *testing.T) { if err != nil { t.Fatalf("Expected no err got %v", err) } + + if err := <-putErrC; err != nil { + t.Fatal(err) + } // the retrieved chunk should be the same as what we Put if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { t.Fatalf("Different chunk received than what was put") @@ -159,7 +174,7 @@ func TestNetStoreGetAndPut(t *testing.T) { func TestNetStoreGetAfterPut(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() @@ -194,20 +209,24 @@ func TestNetStoreGetAfterPut(t *testing.T) { func TestNetStoreGetTimeout(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() c := make(chan struct{}) // this channel ensures that the gouroutine does not run earlier than the Get + fetcherErrC := make(chan error) go func() { <-c // wait for the Get to be called time.Sleep(200 * time.Millisecond) // and a little more so it is surely called // check if netStore created a fetcher in the Get call for the unavailable chunk if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { - t.Fatal("Expected netStore to use a fetcher for the Get call") + fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") + return } + + fetcherErrC <- nil }() close(c) @@ -220,6 +239,10 @@ func TestNetStoreGetTimeout(t *testing.T) { t.Fatalf("Expected context.DeadLineExceeded err got %v", err) } + if err := <-fetcherErrC; err != nil { + t.Fatal(err) + } + // A fetcher was created, check if it has been removed after timeout if netStore.fetchers.Len() != 0 { t.Fatal("Expected netStore to remove the fetcher after timeout") @@ -238,25 +261,34 @@ func TestNetStoreGetTimeout(t *testing.T) { func TestNetStoreGetCancel(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) c := make(chan struct{}) // this channel ensures that the gouroutine with the cancel does not run earlier than the Get + fetcherErrC := make(chan error, 1) go func() { <-c // wait for the Get to be called time.Sleep(200 * time.Millisecond) // and a little more so it is surely called // check if netStore created a fetcher in the Get call for the unavailable chunk if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { - t.Fatal("Expected netStore to use a fetcher for the Get call") + fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") + return } + + fetcherErrC <- nil cancel() }() close(c) + // We call Get with an unavailable chunk, so it will create a fetcher and wait for delivery _, err := netStore.Get(ctx, chunk.Address()) + if err := <-fetcherErrC; err != nil { + t.Fatal(err) + } + // After the context is cancelled above Get should return with an error if err != context.Canceled { t.Fatalf("Expected context.Canceled err got %v", err) @@ -281,51 +313,60 @@ func TestNetStoreGetCancel(t *testing.T) { func TestNetStoreMultipleGetAndPut(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() + putErrC := make(chan error) go func() { // sleep to make sure Put is called after all the Get time.Sleep(500 * time.Millisecond) // check if netStore created exactly one fetcher for all Get calls if netStore.fetchers.Len() != 1 { - t.Fatal("Expected netStore to use one fetcher for all Get calls") + putErrC <- errors.New("Expected netStore to use one fetcher for all Get calls") + return } err := netStore.Put(ctx, chunk) if err != nil { - t.Fatalf("Expected no err got %v", err) + putErrC <- fmt.Errorf("Expected no err got %v", err) + return } + putErrC <- nil }() + count := 4 // call Get 4 times for the same unavailable chunk. The calls will be blocked until the Put above. - getWG := sync.WaitGroup{} - for i := 0; i < 4; i++ { - getWG.Add(1) + errC := make(chan error) + for i := 0; i < count; i++ { go func() { - defer getWG.Done() recChunk, err := netStore.Get(ctx, chunk.Address()) if err != nil { - t.Fatalf("Expected no err got %v", err) + errC <- fmt.Errorf("Expected no err got %v", err) } if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { - t.Fatalf("Different chunk received than what was put") + errC <- errors.New("Different chunk received than what was put") } + errC <- nil }() } - finishedC := make(chan struct{}) - go func() { - getWG.Wait() - close(finishedC) - }() + if err := <-putErrC; err != nil { + t.Fatal(err) + } + + timeout := time.After(1 * time.Second) // The Get calls should return after Put, so no timeout expected - select { - case <-finishedC: - case <-time.After(1 * time.Second): - t.Fatalf("Timeout waiting for Get calls to return") + for i := 0; i < count; i++ { + select { + case err := <-errC: + if err != nil { + t.Fatal(err) + } + case <-timeout: + t.Fatalf("Timeout waiting for Get calls to return") + } } // A fetcher was created, check if it has been removed after cancel @@ -346,7 +387,7 @@ func TestNetStoreMultipleGetAndPut(t *testing.T) { func TestNetStoreFetchFuncTimeout(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) defer cancel() @@ -385,7 +426,7 @@ func TestNetStoreFetchFuncTimeout(t *testing.T) { func TestNetStoreFetchFuncAfterPut(t *testing.T) { netStore := mustNewNetStore(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() @@ -412,7 +453,7 @@ func TestNetStoreFetchFuncAfterPut(t *testing.T) { func TestNetStoreGetCallsRequest(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx := context.WithValue(context.Background(), "hopcount", uint8(5)) ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) @@ -440,7 +481,7 @@ func TestNetStoreGetCallsRequest(t *testing.T) { func TestNetStoreGetCallsOffer(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) // If a source peer is added to the context, NetStore will handle it as an offer ctx := context.WithValue(context.Background(), "source", sourcePeerID.String()) @@ -448,7 +489,7 @@ func TestNetStoreGetCallsOffer(t *testing.T) { defer cancel() // We call get for a not available chunk, it will timeout because the chunk is not delivered - chunk, err := netStore.Get(ctx, chunk.Address()) + _, err := netStore.Get(ctx, chunk.Address()) if err != context.DeadlineExceeded { t.Fatalf("Expect error %v got %v", context.DeadlineExceeded, err) @@ -526,7 +567,7 @@ func TestNetStoreFetcherCountPeers(t *testing.T) { func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() @@ -542,16 +583,12 @@ func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { t.Fatalf("Expected netStore to have one fetcher for the requested chunk") } - // Call wait three times parallelly - wg := sync.WaitGroup{} - for i := 0; i < 3; i++ { - wg.Add(1) + // Call wait three times in parallel + count := 3 + errC := make(chan error) + for i := 0; i < count; i++ { go func() { - err := wait(ctx) - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - wg.Done() + errC <- wait(ctx) }() } @@ -570,7 +607,12 @@ func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { } // wait until all wait calls return (because the chunk is delivered) - wg.Wait() + for i := 0; i < count; i++ { + err := <-errC + if err != nil { + t.Fatal(err) + } + } // There should be no more fetchers for the delivered chunk if netStore.fetchers.Len() != 0 { @@ -590,7 +632,7 @@ func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { func TestNetStoreFetcherLifeCycleWithTimeout(t *testing.T) { netStore, fetcher := mustNewNetStoreWithFetcher(t) - chunk := GenerateRandomChunk(ch.DefaultSize) + chunk := GenerateRandomChunk(chunk.DefaultSize) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() @@ -606,23 +648,29 @@ func TestNetStoreFetcherLifeCycleWithTimeout(t *testing.T) { t.Fatalf("Expected netStore to have one fetcher for the requested chunk") } - // Call wait three times parallelly - wg := sync.WaitGroup{} - for i := 0; i < 3; i++ { - wg.Add(1) + // Call wait three times in parallel + count := 3 + errC := make(chan error) + for i := 0; i < count; i++ { go func() { - defer wg.Done() rctx, rcancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer rcancel() err := wait(rctx) if err != context.DeadlineExceeded { - t.Fatalf("Expected err %v got %v", context.DeadlineExceeded, err) + errC <- fmt.Errorf("Expected err %v got %v", context.DeadlineExceeded, err) + return } + errC <- nil }() } // wait until all wait calls timeout - wg.Wait() + for i := 0; i < count; i++ { + err := <-errC + if err != nil { + t.Fatal(err) + } + } // There should be no more fetchers after timeout if netStore.fetchers.Len() != 0 { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/pyramid.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/pyramid.go index f74eef06..281bbe9f 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/pyramid.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/pyramid.go @@ -25,7 +25,7 @@ import ( "sync" "time" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" "github.com/ethereum/go-ethereum/swarm/log" ) @@ -71,11 +71,6 @@ const ( splitTimeout = time.Minute * 5 ) -const ( - DataChunk = 0 - TreeChunk = 1 -) - type PyramidSplitterParams struct { SplitterParams getter Getter @@ -102,11 +97,11 @@ func NewPyramidSplitterParams(addr Address, reader io.Reader, putter Putter, get New chunks to store are store using the putter which the caller provides. */ func PyramidSplit(ctx context.Context, reader io.Reader, putter Putter, getter Getter) (Address, func(context.Context) error, error) { - return NewPyramidSplitter(NewPyramidSplitterParams(nil, reader, putter, getter, ch.DefaultSize)).Split(ctx) + return NewPyramidSplitter(NewPyramidSplitterParams(nil, reader, putter, getter, chunk.DefaultSize)).Split(ctx) } func PyramidAppend(ctx context.Context, addr Address, reader io.Reader, putter Putter, getter Getter) (Address, func(context.Context) error, error) { - return NewPyramidSplitter(NewPyramidSplitterParams(addr, reader, putter, getter, ch.DefaultSize)).Append(ctx) + return NewPyramidSplitter(NewPyramidSplitterParams(addr, reader, putter, getter, chunk.DefaultSize)).Append(ctx) } // Entry to create a tree node @@ -206,8 +201,6 @@ func (pc *PyramidChunker) decrementWorkerCount() { } func (pc *PyramidChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) { - log.Debug("pyramid.chunker: Split()") - pc.wg.Add(1) pc.prepareChunks(ctx, false) @@ -240,7 +233,6 @@ func (pc *PyramidChunker) Split(ctx context.Context) (k Address, wait func(conte } func (pc *PyramidChunker) Append(ctx context.Context) (k Address, wait func(context.Context) error, err error) { - log.Debug("pyramid.chunker: Append()") // Load the right most unfinished tree chunks in every level pc.loadTree(ctx) @@ -288,8 +280,6 @@ func (pc *PyramidChunker) processor(ctx context.Context, id int64) { } func (pc *PyramidChunker) processChunk(ctx context.Context, id int64, job *chunkJob) { - log.Debug("pyramid.chunker: processChunk()", "id", id) - ref, err := pc.putter.Put(ctx, job.chunk) if err != nil { select { @@ -306,7 +296,6 @@ func (pc *PyramidChunker) processChunk(ctx context.Context, id int64, job *chunk } func (pc *PyramidChunker) loadTree(ctx context.Context) error { - log.Debug("pyramid.chunker: loadTree()") // Get the root chunk to get the total size chunkData, err := pc.getter.Get(ctx, Reference(pc.key)) if err != nil { @@ -391,7 +380,6 @@ func (pc *PyramidChunker) loadTree(ctx context.Context) error { } func (pc *PyramidChunker) prepareChunks(ctx context.Context, isAppend bool) { - log.Debug("pyramid.chunker: prepareChunks", "isAppend", isAppend) defer pc.wg.Done() chunkWG := &sync.WaitGroup{} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/storage/types.go b/vendor/github.com/ethereum/go-ethereum/swarm/storage/types.go index 42557766..2f39685b 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/storage/types.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/storage/types.go @@ -22,113 +22,41 @@ import ( "crypto" "crypto/rand" "encoding/binary" - "fmt" - "hash" "io" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/swarm/bmt" - ch "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/chunk" + "golang.org/x/crypto/sha3" ) -const MaxPO = 16 -const AddressLength = 32 +// MaxPO is the same as chunk.MaxPO for backward compatibility. +const MaxPO = chunk.MaxPO + +// AddressLength is the same as chunk.AddressLength for backward compatibility. +const AddressLength = chunk.AddressLength -type Hasher func() hash.Hash type SwarmHasher func() SwarmHash -// Peer is the recorded as Source on the chunk -// should probably not be here? but network should wrap chunk object -type Peer interface{} +// Address is an alias for chunk.Address for backward compatibility. +type Address = chunk.Address -type Address []byte +// Proximity is the same as chunk.Proximity for backward compatibility. +var Proximity = chunk.Proximity -func (a Address) Size() uint { - return uint(len(a)) -} - -func (a Address) isEqual(y Address) bool { - return bytes.Equal(a, y) -} - -func (a Address) bits(i, j uint) uint { - ii := i >> 3 - jj := i & 7 - if ii >= a.Size() { - return 0 - } - - if jj+j <= 8 { - return uint((a[ii] >> jj) & ((1 << j) - 1)) - } - - res := uint(a[ii] >> jj) - jj = 8 - jj - j -= jj - for j != 0 { - ii++ - if j < 8 { - res += uint(a[ii]&((1< len(one) { - b = len(one) - } - m := 8 - for i := 0; i < b; i++ { - oxo := one[i] ^ other[i] - if i == b-1 { - m = MaxPO % 8 - } - for j := 0; j < m; j++ { - if (oxo>>uint8(7-j))&0x01 != 0 { - return i*8 + j - } - } - } - return MaxPO -} - -func IsZeroAddr(addr Address) bool { - return len(addr) == 0 || bytes.Equal(addr, ZeroAddr) -} - -var ZeroAddr = Address(common.Hash{}.Bytes()) +// ZeroAddr is the same as chunk.ZeroAddr for backward compatibility. +var ZeroAddr = chunk.ZeroAddr func MakeHashFunc(hash string) SwarmHasher { switch hash { case "SHA256": return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} } case "SHA3": - return func() SwarmHash { return &HashWithLength{sha3.NewKeccak256()} } + return func() SwarmHash { return &HashWithLength{sha3.NewLegacyKeccak256()} } case "BMT": return func() SwarmHash { - hasher := sha3.NewKeccak256 + hasher := sha3.NewLegacyKeccak256 hasherSize := hasher().Size() - segmentCount := ch.DefaultSize / hasherSize + segmentCount := chunk.DefaultSize / hasherSize pool := bmt.NewTreePool(hasher, segmentCount, bmt.PoolSize) return bmt.New(pool) } @@ -136,33 +64,6 @@ func MakeHashFunc(hash string) SwarmHasher { return nil } -func (a Address) Hex() string { - return fmt.Sprintf("%064x", []byte(a[:])) -} - -func (a Address) Log() string { - if len(a[:]) < 8 { - return fmt.Sprintf("%x", []byte(a[:])) - } - return fmt.Sprintf("%016x", []byte(a[:8])) -} - -func (a Address) String() string { - return fmt.Sprintf("%064x", []byte(a)) -} - -func (a Address) MarshalJSON() (out []byte, err error) { - return []byte(`"` + a.String() + `"`), nil -} - -func (a *Address) UnmarshalJSON(value []byte) error { - s := string(value) - *a = make([]byte, 32) - h := common.Hex2Bytes(s[1 : len(s)-1]) - copy(*a, h) - return nil -} - type AddressCollection []Address func NewAddressCollection(l int) AddressCollection { @@ -181,56 +82,11 @@ func (c AddressCollection) Swap(i, j int) { c[i], c[j] = c[j], c[i] } -// Chunk interface implemented by context.Contexts and data chunks -type Chunk interface { - Address() Address - Payload() []byte - SpanBytes() []byte - Span() int64 - Data() []byte -} +// Chunk is an alias for chunk.Chunk for backward compatibility. +type Chunk = chunk.Chunk -type chunk struct { - addr Address - sdata []byte - span int64 -} - -func NewChunk(addr Address, data []byte) *chunk { - return &chunk{ - addr: addr, - sdata: data, - span: -1, - } -} - -func (c *chunk) Address() Address { - return c.addr -} - -func (c *chunk) SpanBytes() []byte { - return c.sdata[:8] -} - -func (c *chunk) Span() int64 { - if c.span == -1 { - c.span = int64(binary.LittleEndian.Uint64(c.sdata[:8])) - } - return c.span -} - -func (c *chunk) Data() []byte { - return c.sdata -} - -func (c *chunk) Payload() []byte { - return c.sdata[8:] -} - -// String() for pretty printing -func (self *chunk) String() string { - return fmt.Sprintf("Address: %v TreeSize: %v Chunksize: %v", self.addr.Log(), self.span, len(self.sdata)) -} +// NewChunk is the same as chunk.NewChunk for backward compatibility. +var NewChunk = chunk.NewChunk func GenerateRandomChunk(dataSize int64) Chunk { hasher := MakeHashFunc(DefaultHash)() @@ -322,12 +178,8 @@ func (c ChunkData) Size() uint64 { return binary.LittleEndian.Uint64(c[:8]) } -func (c ChunkData) Data() []byte { - return c[8:] -} - type ChunkValidator interface { - Validate(addr Address, data []byte) bool + Validate(chunk Chunk) bool } // Provides method for validation of content address in chunks @@ -344,8 +196,9 @@ func NewContentAddressValidator(hasher SwarmHasher) *ContentAddressValidator { } // Validate that the given key is a valid content address for the given data -func (v *ContentAddressValidator) Validate(addr Address, data []byte) bool { - if l := len(data); l < 9 || l > ch.DefaultSize+8 { +func (v *ContentAddressValidator) Validate(ch Chunk) bool { + data := ch.Data() + if l := len(data); l < 9 || l > chunk.DefaultSize+8 { // log.Error("invalid chunk size", "chunk", addr.Hex(), "size", l) return false } @@ -355,12 +208,13 @@ func (v *ContentAddressValidator) Validate(addr Address, data []byte) bool { hasher.Write(data[8:]) hash := hasher.Sum(nil) - return bytes.Equal(hash, addr[:]) + return bytes.Equal(hash, ch.Address()) } type ChunkStore interface { Put(ctx context.Context, ch Chunk) (err error) Get(rctx context.Context, ref Address) (ch Chunk, err error) + Has(rctx context.Context, ref Address) bool Close() } @@ -383,7 +237,12 @@ func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error { return nil } -// Gut doesn't store anything it is just here to implement ChunkStore +// Has doesn't do anything it is just here to implement ChunkStore +func (f *FakeChunkStore) Has(_ context.Context, ref Address) bool { + panic("FakeChunkStore doesn't support HasChunk") +} + +// Get doesn't store anything it is just here to implement ChunkStore func (f *FakeChunkStore) Get(_ context.Context, ref Address) (Chunk, error) { panic("FakeChunkStore doesn't support Get") } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/swap/swap.go b/vendor/github.com/ethereum/go-ethereum/swarm/swap/swap.go new file mode 100644 index 00000000..5d636dc2 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/swap/swap.go @@ -0,0 +1,98 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package swap + +import ( + "errors" + "fmt" + "strconv" + "sync" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/state" +) + +// SwAP Swarm Accounting Protocol +// a peer to peer micropayment system +// A node maintains an individual balance with every peer +// Only messages which have a price will be accounted for +type Swap struct { + stateStore state.Store //stateStore is needed in order to keep balances across sessions + lock sync.RWMutex //lock the balances + balances map[enode.ID]int64 //map of balances for each peer +} + +// New - swap constructor +func New(stateStore state.Store) (swap *Swap) { + swap = &Swap{ + stateStore: stateStore, + balances: make(map[enode.ID]int64), + } + return +} + +//Swap implements the protocols.Balance interface +//Add is the (sole) accounting function +func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) { + s.lock.Lock() + defer s.lock.Unlock() + + //load existing balances from the state store + err = s.loadState(peer) + if err != nil && err != state.ErrNotFound { + return + } + //adjust the balance + //if amount is negative, it will decrease, otherwise increase + s.balances[peer.ID()] += amount + //save the new balance to the state store + peerBalance := s.balances[peer.ID()] + err = s.stateStore.Put(peer.ID().String(), &peerBalance) + + log.Debug(fmt.Sprintf("balance for peer %s: %s", peer.ID().String(), strconv.FormatInt(peerBalance, 10))) + return err +} + +//GetPeerBalance returns the balance for a given peer +func (swap *Swap) GetPeerBalance(peer enode.ID) (int64, error) { + swap.lock.RLock() + defer swap.lock.RUnlock() + if p, ok := swap.balances[peer]; ok { + return p, nil + } + return 0, errors.New("Peer not found") +} + +//load balances from the state store (persisted) +func (s *Swap) loadState(peer *protocols.Peer) (err error) { + var peerBalance int64 + peerID := peer.ID() + //only load if the current instance doesn't already have this peer's + //balance in memory + if _, ok := s.balances[peerID]; !ok { + err = s.stateStore.Get(peerID.String(), &peerBalance) + s.balances[peerID] = peerBalance + } + return +} + +//Clean up Swap +func (swap *Swap) Close() { + swap.stateStore.Close() +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/swap/swap_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/swap/swap_test.go new file mode 100644 index 00000000..f2e3ba16 --- /dev/null +++ b/vendor/github.com/ethereum/go-ethereum/swarm/swap/swap_test.go @@ -0,0 +1,184 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package swap + +import ( + "flag" + "fmt" + "io/ioutil" + mrand "math/rand" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/state" + colorable "github.com/mattn/go-colorable" +) + +var ( + loglevel = flag.Int("loglevel", 2, "verbosity of logs") +) + +func init() { + flag.Parse() + mrand.Seed(time.Now().UnixNano()) + + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + +//Test getting a peer's balance +func TestGetPeerBalance(t *testing.T) { + //create a test swap account + swap, testDir := createTestSwap(t) + defer os.RemoveAll(testDir) + + //test for correct value + testPeer := newDummyPeer() + swap.balances[testPeer.ID()] = 888 + b, err := swap.GetPeerBalance(testPeer.ID()) + if err != nil { + t.Fatal(err) + } + if b != 888 { + t.Fatalf("Expected peer's balance to be %d, but is %d", 888, b) + } + + //test for inexistent node + id := adapters.RandomNodeConfig().ID + _, err = swap.GetPeerBalance(id) + if err == nil { + t.Fatal("Expected call to fail, but it didn't!") + } + if err.Error() != "Peer not found" { + t.Fatalf("Expected test to fail with %s, but is %s", "Peer not found", err.Error()) + } +} + +//Test that repeated bookings do correct accounting +func TestRepeatedBookings(t *testing.T) { + //create a test swap account + swap, testDir := createTestSwap(t) + defer os.RemoveAll(testDir) + + testPeer := newDummyPeer() + amount := mrand.Intn(100) + cnt := 1 + mrand.Intn(10) + for i := 0; i < cnt; i++ { + swap.Add(int64(amount), testPeer.Peer) + } + expectedBalance := int64(cnt * amount) + realBalance := swap.balances[testPeer.ID()] + if expectedBalance != realBalance { + t.Fatal(fmt.Sprintf("After %d credits of %d, expected balance to be: %d, but is: %d", cnt, amount, expectedBalance, realBalance)) + } + + testPeer2 := newDummyPeer() + amount = mrand.Intn(100) + cnt = 1 + mrand.Intn(10) + for i := 0; i < cnt; i++ { + swap.Add(0-int64(amount), testPeer2.Peer) + } + expectedBalance = int64(0 - (cnt * amount)) + realBalance = swap.balances[testPeer2.ID()] + if expectedBalance != realBalance { + t.Fatal(fmt.Sprintf("After %d debits of %d, expected balance to be: %d, but is: %d", cnt, amount, expectedBalance, realBalance)) + } + + //mixed debits and credits + amount1 := mrand.Intn(100) + amount2 := mrand.Intn(55) + amount3 := mrand.Intn(999) + swap.Add(int64(amount1), testPeer2.Peer) + swap.Add(int64(0-amount2), testPeer2.Peer) + swap.Add(int64(0-amount3), testPeer2.Peer) + + expectedBalance = expectedBalance + int64(amount1-amount2-amount3) + realBalance = swap.balances[testPeer2.ID()] + + if expectedBalance != realBalance { + t.Fatal(fmt.Sprintf("After mixed debits and credits, expected balance to be: %d, but is: %d", expectedBalance, realBalance)) + } +} + +//try restoring a balance from state store +//this is simulated by creating a node, +//assigning it an arbitrary balance, +//then closing the state store. +//Then we re-open the state store and check that +//the balance is still the same +func TestRestoreBalanceFromStateStore(t *testing.T) { + //create a test swap account + swap, testDir := createTestSwap(t) + defer os.RemoveAll(testDir) + + testPeer := newDummyPeer() + swap.balances[testPeer.ID()] = -8888 + + tmpBalance := swap.balances[testPeer.ID()] + swap.stateStore.Put(testPeer.ID().String(), &tmpBalance) + + swap.stateStore.Close() + swap.stateStore = nil + + stateStore, err := state.NewDBStore(testDir) + if err != nil { + t.Fatal(err) + } + + var newBalance int64 + stateStore.Get(testPeer.ID().String(), &newBalance) + + //compare the balances + if tmpBalance != newBalance { + t.Fatal(fmt.Sprintf("Unexpected balance value after sending cheap message test. Expected balance: %d, balance is: %d", + tmpBalance, newBalance)) + } +} + +//create a test swap account +//creates a stateStore for persistence and a Swap account +func createTestSwap(t *testing.T) (*Swap, string) { + dir, err := ioutil.TempDir("", "swap_test_store") + if err != nil { + t.Fatal(err) + } + stateStore, err2 := state.NewDBStore(dir) + if err2 != nil { + t.Fatal(err2) + } + swap := New(stateStore) + return swap, dir +} + +type dummyPeer struct { + *protocols.Peer +} + +//creates a dummy protocols.Peer with dummy MsgReadWriter +func newDummyPeer() *dummyPeer { + id := adapters.RandomNodeConfig().ID + protoPeer := protocols.NewPeer(p2p.NewPeer(id, "testPeer", nil), nil, nil) + dummy := &dummyPeer{ + Peer: protoPeer, + } + return dummy +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/swarm.go b/vendor/github.com/ethereum/go-ethereum/swarm/swarm.go index 1fb5443f..61813e23 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/swarm.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/swarm.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2018 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/protocols" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -51,11 +50,11 @@ import ( "github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage/feed" "github.com/ethereum/go-ethereum/swarm/storage/mock" + "github.com/ethereum/go-ethereum/swarm/swap" "github.com/ethereum/go-ethereum/swarm/tracing" ) var ( - startTime time.Time updateGaugesPeriod = 5 * time.Second startCounter = metrics.NewRegisteredCounter("stack,start", nil) stopCounter = metrics.NewRegisteredCounter("stack,stop", nil) @@ -65,41 +64,30 @@ var ( // the swarm stack type Swarm struct { - config *api.Config // swarm configuration - api *api.API // high level api layer (fs/manifest) - dns api.Resolver // DNS registrar - fileStore *storage.FileStore // distributed preimage archive, the local API to the storage with document level storage/retrieval support - streamer *stream.Registry - bzz *network.Bzz // the logistic manager - backend chequebook.Backend // simple blockchain Backend - privateKey *ecdsa.PrivateKey - corsString string - swapEnabled bool - netStore *storage.NetStore - sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit - ps *pss.Pss + config *api.Config // swarm configuration + api *api.API // high level api layer (fs/manifest) + dns api.Resolver // DNS registrar + fileStore *storage.FileStore // distributed preimage archive, the local API to the storage with document level storage/retrieval support + streamer *stream.Registry + bzz *network.Bzz // the logistic manager + backend chequebook.Backend // simple blockchain Backend + privateKey *ecdsa.PrivateKey + netStore *storage.NetStore + sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit + ps *pss.Pss + swap *swap.Swap + stateStore *state.DBStore + accountingMetrics *protocols.AccountingMetrics + cleanupFuncs []func() error tracerClose io.Closer } -type SwarmAPI struct { - Api *api.API - Backend chequebook.Backend -} - -func (self *Swarm) API() *SwarmAPI { - return &SwarmAPI{ - Api: self.api, - Backend: self.backend, - } -} - -// creates a new swarm service instance +// NewSwarm creates a new swarm service instance // implements node.Service // If mockStore is not nil, it will be used as the storage for chunk data. // MockStore should be used only for testing. func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err error) { - if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroAddr) { return nil, fmt.Errorf("empty public key") } @@ -117,22 +105,24 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e } self = &Swarm{ - config: config, - backend: backend, - privateKey: config.ShiftPrivateKey(), + config: config, + backend: backend, + privateKey: config.ShiftPrivateKey(), + cleanupFuncs: []func() error{}, } log.Debug("Setting up Swarm service components") config.HiveParams.Discovery = true bzzconfig := &network.BzzConfig{ - NetworkID: config.NetworkID, - OverlayAddr: common.FromHex(config.BzzKey), - HiveParams: config.HiveParams, - LightNode: config.LightNodeEnabled, + NetworkID: config.NetworkID, + OverlayAddr: common.FromHex(config.BzzKey), + HiveParams: config.HiveParams, + LightNode: config.LightNodeEnabled, + BootnodeMode: config.BootnodeMode, } - stateStore, err := state.NewDBStore(filepath.Join(config.Path, "state-store.db")) + self.stateStore, err = state.NewDBStore(filepath.Join(config.Path, "state-store.db")) if err != nil { return } @@ -171,11 +161,17 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e delivery := stream.NewDelivery(to, self.netStore) self.netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, config.DeliverySkipCheck).New - var nodeID enode.ID - if err := nodeID.UnmarshalText([]byte(config.NodeID)); err != nil { - return nil, err + if config.SwapEnabled { + balancesStore, err := state.NewDBStore(filepath.Join(config.Path, "balances.db")) + if err != nil { + return nil, err + } + self.swap = swap.New(balancesStore) + self.accountingMetrics = protocols.SetupAccountingMetrics(10*time.Second, filepath.Join(config.Path, "metrics.db")) } + nodeID := config.Enode.ID() + syncing := stream.SyncingAutoSubscribe if !config.SyncEnabled || config.LightNodeEnabled { syncing = stream.SyncingDisabled @@ -193,7 +189,7 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e SyncUpdateDelay: config.SyncUpdateDelay, MaxPeerServers: config.MaxStreamPeerServers, } - self.streamer = stream.NewRegistry(nodeID, delivery, self.netStore, stateStore, registryOptions) + self.streamer = stream.NewRegistry(nodeID, delivery, self.netStore, self.stateStore, registryOptions, self.swap) // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams) @@ -216,7 +212,7 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e log.Debug("Setup local storage") - self.bzz = network.NewBzz(bzzconfig, to, stateStore, stream.Spec, self.streamer.Run) + self.bzz = network.NewBzz(bzzconfig, to, self.stateStore, self.streamer.GetSpec(), self.streamer.Run) // Pss = postal service over swarm (devp2p over bzz) self.ps, err = pss.NewPss(to, config.Pss) @@ -344,49 +340,51 @@ Start is called when the stack is started * TODO: start subservices like sword, swear, swarmdns */ // implements the node.Service interface -func (self *Swarm) Start(srv *p2p.Server) error { - startTime = time.Now() +func (s *Swarm) Start(srv *p2p.Server) error { + startTime := time.Now() - self.tracerClose = tracing.Closer + s.tracerClose = tracing.Closer // update uaddr to correct enode - newaddr := self.bzz.UpdateLocalAddr([]byte(srv.Self().String())) + newaddr := s.bzz.UpdateLocalAddr([]byte(srv.Self().String())) log.Info("Updated bzz local addr", "oaddr", fmt.Sprintf("%x", newaddr.OAddr), "uaddr", fmt.Sprintf("%s", newaddr.UAddr)) // set chequebook - if self.config.SwapEnabled { + //TODO: Currently if swap is enabled and no chequebook (or inexistent) contract is provided, the node would crash. + //Once we integrate back the contracts, this check MUST be revisited + if s.config.SwapEnabled && s.config.SwapAPI != "" { ctx := context.Background() // The initial setup has no deadline. - err := self.SetChequebook(ctx) + err := s.SetChequebook(ctx) if err != nil { return fmt.Errorf("Unable to set chequebook for SWAP: %v", err) } - log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook())) + log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", s.config.Swap.Chequebook())) } else { log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set")) } log.Info("Starting bzz service") - err := self.bzz.Start(srv) + err := s.bzz.Start(srv) if err != nil { log.Error("bzz failed", "err", err) return err } - log.Info("Swarm network started", "bzzaddr", fmt.Sprintf("%x", self.bzz.Hive.BaseAddr())) + log.Info("Swarm network started", "bzzaddr", fmt.Sprintf("%x", s.bzz.Hive.BaseAddr())) - if self.ps != nil { - self.ps.Start(srv) + if s.ps != nil { + s.ps.Start(srv) } // start swarm http proxy server - if self.config.Port != "" { - addr := net.JoinHostPort(self.config.ListenAddr, self.config.Port) - server := httpapi.NewServer(self.api, self.config.Cors) + if s.config.Port != "" { + addr := net.JoinHostPort(s.config.ListenAddr, s.config.Port) + server := httpapi.NewServer(s.api, s.config.Cors) - if self.config.Cors != "" { - log.Debug("Swarm HTTP proxy CORS headers", "allowedOrigins", self.config.Cors) + if s.config.Cors != "" { + log.Debug("Swarm HTTP proxy CORS headers", "allowedOrigins", s.config.Cors) } - log.Debug("Starting Swarm HTTP proxy", "port", self.config.Port) + log.Debug("Starting Swarm HTTP proxy", "port", s.config.Port) go func() { err := server.ListenAndServe(addr) if err != nil { @@ -395,135 +393,161 @@ func (self *Swarm) Start(srv *p2p.Server) error { }() } - self.periodicallyUpdateGauges() + doneC := make(chan struct{}) + + s.cleanupFuncs = append(s.cleanupFuncs, func() error { + close(doneC) + return nil + }) + + go func(time.Time) { + for { + select { + case <-time.After(updateGaugesPeriod): + uptimeGauge.Update(time.Since(startTime).Nanoseconds()) + requestsCacheGauge.Update(int64(s.netStore.RequestsCacheLen())) + case <-doneC: + return + } + } + }(startTime) startCounter.Inc(1) - self.streamer.Start(srv) + s.streamer.Start(srv) return nil } -func (self *Swarm) periodicallyUpdateGauges() { - ticker := time.NewTicker(updateGaugesPeriod) - - go func() { - for range ticker.C { - self.updateGauges() - } - }() -} - -func (self *Swarm) updateGauges() { - uptimeGauge.Update(time.Since(startTime).Nanoseconds()) - requestsCacheGauge.Update(int64(self.netStore.RequestsCacheLen())) -} - // implements the node.Service interface // stops all component services. -func (self *Swarm) Stop() error { - if self.tracerClose != nil { - err := self.tracerClose.Close() +func (s *Swarm) Stop() error { + if s.tracerClose != nil { + err := s.tracerClose.Close() + tracing.FinishSpans() if err != nil { return err } } - if self.ps != nil { - self.ps.Stop() + if s.ps != nil { + s.ps.Stop() } - if ch := self.config.Swap.Chequebook(); ch != nil { + if ch := s.config.Swap.Chequebook(); ch != nil { ch.Stop() ch.Save() } - - if self.netStore != nil { - self.netStore.Close() + if s.swap != nil { + s.swap.Close() } - self.sfs.Stop() + if s.accountingMetrics != nil { + s.accountingMetrics.Close() + } + if s.netStore != nil { + s.netStore.Close() + } + s.sfs.Stop() stopCounter.Inc(1) - self.streamer.Stop() - return self.bzz.Stop() + s.streamer.Stop() + + err := s.bzz.Stop() + if s.stateStore != nil { + s.stateStore.Close() + } + + for _, cleanF := range s.cleanupFuncs { + err = cleanF() + if err != nil { + log.Error("encountered an error while running cleanup function", "err", err) + break + } + } + return err } -// implements the node.Service interface -func (self *Swarm) Protocols() (protos []p2p.Protocol) { - protos = append(protos, self.bzz.Protocols()...) +// Protocols implements the node.Service interface +func (s *Swarm) Protocols() (protos []p2p.Protocol) { + if s.config.BootnodeMode { + protos = append(protos, s.bzz.Protocols()...) + } else { + protos = append(protos, s.bzz.Protocols()...) - if self.ps != nil { - protos = append(protos, self.ps.Protocols()...) + if s.ps != nil { + protos = append(protos, s.ps.Protocols()...) + } } return } -func (self *Swarm) RegisterPssProtocol(spec *protocols.Spec, targetprotocol *p2p.Protocol, options *pss.ProtocolParams) (*pss.Protocol, error) { - if !pss.IsActiveProtocol { - return nil, fmt.Errorf("Pss protocols not available (built with !nopssprotocol tag)") - } - topic := pss.ProtocolTopic(spec) - return pss.RegisterProtocol(self.ps, &topic, spec, targetprotocol, options) -} - // implements node.Service // APIs returns the RPC API descriptors the Swarm implementation offers -func (self *Swarm) APIs() []rpc.API { +func (s *Swarm) APIs() []rpc.API { apis := []rpc.API{ // public APIs { Namespace: "bzz", Version: "3.0", - Service: &Info{self.config, chequebook.ContractParams}, + Service: &Info{s.config, chequebook.ContractParams}, Public: true, }, // admin APIs { Namespace: "bzz", Version: "3.0", - Service: api.NewControl(self.api, self.bzz.Hive), + Service: api.NewInspector(s.api, s.bzz.Hive, s.netStore), Public: false, }, { Namespace: "chequebook", Version: chequebook.Version, - Service: chequebook.NewApi(self.config.Swap.Chequebook), + Service: chequebook.NewAPI(s.config.Swap.Chequebook), Public: false, }, { Namespace: "swarmfs", - Version: fuse.Swarmfs_Version, - Service: self.sfs, + Version: fuse.SwarmFSVersion, + Service: s.sfs, + Public: false, + }, + { + Namespace: "accounting", + Version: protocols.AccountingVersion, + Service: protocols.NewAccountingApi(s.accountingMetrics), Public: false, }, } - apis = append(apis, self.bzz.APIs()...) + apis = append(apis, s.bzz.APIs()...) - if self.ps != nil { - apis = append(apis, self.ps.APIs()...) + apis = append(apis, s.streamer.APIs()...) + + if s.ps != nil { + apis = append(apis, s.ps.APIs()...) } return apis } -func (self *Swarm) Api() *api.API { - return self.api -} - // SetChequebook ensures that the local checquebook is set up on chain. -func (self *Swarm) SetChequebook(ctx context.Context) error { - err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path) +func (s *Swarm) SetChequebook(ctx context.Context) error { + err := s.config.Swap.SetChequebook(ctx, s.backend, s.config.Path) if err != nil { return err } - log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex())) + log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", s.config.Swap.Contract.Hex())) return nil } +// RegisterPssProtocol adds a devp2p protocol to the swarm node's Pss instance +func (s *Swarm) RegisterPssProtocol(topic *pss.Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol, options *pss.ProtocolParams) (*pss.Protocol, error) { + return pss.RegisterProtocol(s.ps, topic, spec, targetprotocol, options) +} + // serialisable info about swarm type Info struct { *api.Config *chequebook.Params } -func (self *Info) Info() *Info { - return self +func (s *Info) Info() *Info { + return s } diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/swarm_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/swarm_test.go index d85eb911..2a5b2851 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/swarm_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/swarm_test.go @@ -170,8 +170,12 @@ func TestNewSwarm(t *testing.T) { if err != nil { t.Fatal(err) } + nodekey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } - config.Init(privkey) + config.Init(privkey, nodekey) if tc.configure != nil { tc.configure(config) @@ -307,8 +311,12 @@ func TestLocalStoreAndRetrieve(t *testing.T) { if err != nil { t.Fatal(err) } + nodekey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } - config.Init(privkey) + config.Init(privkey, nodekey) swarm, err := NewSwarm(config, nil) if err != nil { diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/state/store.go b/vendor/github.com/ethereum/go-ethereum/swarm/testutil/norace.go similarity index 62% rename from vendor/github.com/ethereum/go-ethereum/swarm/state/store.go rename to vendor/github.com/ethereum/go-ethereum/swarm/testutil/norace.go index fb7fe258..bc652184 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/state/store.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/testutil/norace.go @@ -1,4 +1,4 @@ -// Copyright 2018 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,13 +14,13 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package state +// +build !race -// Store defines methods required to get, set, delete values for different keys -// and close the underlying resources. -type Store interface { - Get(key string, i interface{}) (err error) - Put(key string, i interface{}) (err error) - Delete(key string) (err error) - Close() error -} +package testutil + +// RaceEnabled is true when -race flag is provided to the go tool. This const +// might be used in tests to skip some cases as the race detector may increase +// memory usage 5-10x and execution time by 2-20x. That might causes problems +// on Travis. Please, use this flag sparingly and keep your unit tests +// as light on resources as possible. +const RaceEnabled = false diff --git a/vendor/github.com/ethereum/go-ethereum/ethdb/database_js_test.go b/vendor/github.com/ethereum/go-ethereum/swarm/testutil/race.go similarity index 79% rename from vendor/github.com/ethereum/go-ethereum/ethdb/database_js_test.go rename to vendor/github.com/ethereum/go-ethereum/swarm/testutil/race.go index b4c12ae0..08aa279a 100644 --- a/vendor/github.com/ethereum/go-ethereum/ethdb/database_js_test.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/testutil/race.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,12 +14,10 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build js +// +build race -package ethdb_test +package testutil -import ( - "github.com/ethereum/go-ethereum/ethdb" -) - -var _ ethdb.Database = ðdb.LDBDatabase{} +// RaceEnabled is true when -race flag is provided to the go tool. +// See norace.go for more. +const RaceEnabled = true diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/tracing/tracing.go b/vendor/github.com/ethereum/go-ethereum/swarm/tracing/tracing.go index f95fa41b..55875464 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/tracing/tracing.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/tracing/tracing.go @@ -1,21 +1,39 @@ package tracing import ( + "context" "io" "os" "strings" + "sync" "time" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/spancontext" + + opentracing "github.com/opentracing/opentracing-go" jaeger "github.com/uber/jaeger-client-go" jaegercfg "github.com/uber/jaeger-client-go/config" cli "gopkg.in/urfave/cli.v1" ) -var Enabled bool = false +var ( + // Enabled turns tracing on for the current swarm instance + Enabled bool = false + store = spanStore{} +) -// TracingEnabledFlag is the CLI flag name to use to enable trace collections. -const TracingEnabledFlag = "tracing" +const ( + // TracingEnabledFlag is the CLI flag name to use to enable trace collections. + TracingEnabledFlag = "tracing" + + // StoreLabelId is the context value key of the name of the span to be saved + StoreLabelId = "span_save_id" + + // StoreLabelMeta is the context value key that together with StoreLabelId constitutes the retrieval key for saved spans in the span store + // StartSaveSpan and ShiftSpanByKey + StoreLabelMeta = "span_save_meta" +) var ( Closer io.Closer @@ -100,3 +118,56 @@ func initTracer(endpoint, svc string) (closer io.Closer) { return closer } + +// spanStore holds saved spans +type spanStore struct { + spans sync.Map +} + +// StartSaveSpan stores the span specified in the passed context for later retrieval +// The span object but be context value on the key StoreLabelId. +// It will be stored under the the following string key context.Value(StoreLabelId)|.|context.Value(StoreLabelMeta) +func StartSaveSpan(ctx context.Context) context.Context { + if !Enabled { + return ctx + } + traceId := ctx.Value(StoreLabelId) + + if traceId != nil { + traceStr := traceId.(string) + var sp opentracing.Span + ctx, sp = spancontext.StartSpan( + ctx, + traceStr, + ) + traceMeta := ctx.Value(StoreLabelMeta) + if traceMeta != nil { + traceStr = traceStr + "." + traceMeta.(string) + } + store.spans.Store(traceStr, sp) + } + return ctx +} + +// ShiftSpanByKey retrieves the span stored under the key of the string given as argument +// The span is then deleted from the store +func ShiftSpanByKey(k string) opentracing.Span { + if !Enabled { + return nil + } + span, spanOk := store.spans.Load(k) + if !spanOk { + return nil + } + store.spans.Delete(k) + return span.(opentracing.Span) +} + +// FinishSpans calls `Finish()` on all stored spans +// It should be called on instance shutdown +func FinishSpans() { + store.spans.Range(func(_, v interface{}) bool { + v.(opentracing.Span).Finish() + return true + }) +} diff --git a/vendor/github.com/ethereum/go-ethereum/swarm/version/version.go b/vendor/github.com/ethereum/go-ethereum/swarm/version/version.go index 0f5a453d..ff54bdf1 100644 --- a/vendor/github.com/ethereum/go-ethereum/swarm/version/version.go +++ b/vendor/github.com/ethereum/go-ethereum/swarm/version/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 0 // Major version component of the current release - VersionMinor = 3 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 0 // Major version component of the current release + VersionMinor = 3 // Minor version component of the current release + VersionPatch = 12 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. @@ -41,6 +41,9 @@ var VersionWithMeta = func() string { return v }() +// Git SHA1 commit hash of the release, will be set by main.init() function +var GitCommit string + // ArchiveVersion holds the textual version string used for Swarm archives. // e.g. "0.3.0-dea1ce05" for stable releases, or // "0.3.1-unstable-21c059b6" for unstable releases diff --git a/vendor/github.com/ethereum/go-ethereum/tests/block_test_util.go b/vendor/github.com/ethereum/go-ethereum/tests/block_test_util.go index 12cba324..d40a3726 100644 --- a/vendor/github.com/ethereum/go-ethereum/tests/block_test_util.go +++ b/vendor/github.com/ethereum/go-ethereum/tests/block_test_util.go @@ -30,10 +30,10 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -101,7 +101,7 @@ func (t *BlockTest) Run() error { } // import pre accounts & construct test genesis block & state root - db := ethdb.NewMemDatabase() + db := rawdb.NewMemoryDatabase() gblock, err := t.genesis(config).Commit(db) if err != nil { return err @@ -118,7 +118,7 @@ func (t *BlockTest) Run() error { } else { engine = ethash.NewShared() } - chain, err := core.NewBlockChain(db, nil, config, engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil) if err != nil { return err } diff --git a/vendor/github.com/ethereum/go-ethereum/tests/init.go b/vendor/github.com/ethereum/go-ethereum/tests/init.go index f0a4943c..188cdffe 100644 --- a/vendor/github.com/ethereum/go-ethereum/tests/init.go +++ b/vendor/github.com/ethereum/go-ethereum/tests/init.go @@ -62,6 +62,18 @@ var Forks = map[string]*params.ChainConfig{ DAOForkBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(10000000), + }, + "ConstantinopleFix": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), }, "FrontierToHomesteadAt5": { ChainID: big.NewInt(1), @@ -86,6 +98,15 @@ var Forks = map[string]*params.ChainConfig{ EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(5), }, + "ByzantiumToConstantinopleAt5": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(5), + }, } // UnsupportedForkError is returned when a test requests a fork that isn't implemented. diff --git a/vendor/github.com/ethereum/go-ethereum/tests/rlp_test_util.go b/vendor/github.com/ethereum/go-ethereum/tests/rlp_test_util.go index 58ef8a64..9069ec55 100644 --- a/vendor/github.com/ethereum/go-ethereum/tests/rlp_test_util.go +++ b/vendor/github.com/ethereum/go-ethereum/tests/rlp_test_util.go @@ -42,9 +42,22 @@ type RLPTest struct { Out string } +// FromHex returns the bytes represented by the hexadecimal string s. +// s may be prefixed with "0x". +// This is copy-pasted from bytes.go, which does not return the error +func FromHex(s string) ([]byte, error) { + if len(s) > 1 && (s[0:2] == "0x" || s[0:2] == "0X") { + s = s[2:] + } + if len(s)%2 == 1 { + s = "0" + s + } + return hex.DecodeString(s) +} + // Run executes the test. func (t *RLPTest) Run() error { - outb, err := hex.DecodeString(t.Out) + outb, err := FromHex(t.Out) if err != nil { return fmt.Errorf("invalid hex in Out") } diff --git a/vendor/github.com/ethereum/go-ethereum/tests/state_test.go b/vendor/github.com/ethereum/go-ethereum/tests/state_test.go index ad77e4f3..8b69da91 100644 --- a/vendor/github.com/ethereum/go-ethereum/tests/state_test.go +++ b/vendor/github.com/ethereum/go-ethereum/tests/state_test.go @@ -17,11 +17,14 @@ package tests import ( + "bufio" "bytes" + "flag" "fmt" "reflect" "testing" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/core/vm" ) @@ -43,9 +46,12 @@ func TestState(t *testing.T) { st.skipLoad(`^stTransactionTest/OverflowGasRequire\.json`) // gasLimit > 256 bits st.skipLoad(`^stTransactionTest/zeroSigTransa[^/]*\.json`) // EIP-86 is not supported yet // Expected failures: - st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/EIP158`, "bug in test") - st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/Byzantium`, "bug in test") - st.fails(`^stRevertTest/RevertPrecompiledTouch.json/Constantinople`, "bug in test") + st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test") + st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test") + st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test") + st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test") + st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test") + st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test") st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) { for _, subtest := range test.Subtests() { @@ -65,8 +71,17 @@ func TestState(t *testing.T) { // Transactions with gasLimit above this value will not get a VM trace on failure. const traceErrorLimit = 400000 +// The VM config for state tests that accepts --vm.* command line arguments. +var testVMConfig = func() vm.Config { + vmconfig := vm.Config{} + flag.StringVar(&vmconfig.EVMInterpreter, utils.EVMInterpreterFlag.Name, utils.EVMInterpreterFlag.Value, utils.EVMInterpreterFlag.Usage) + flag.StringVar(&vmconfig.EWASMInterpreter, utils.EWASMInterpreterFlag.Name, utils.EWASMInterpreterFlag.Value, utils.EWASMInterpreterFlag.Usage) + flag.Parse() + return vmconfig +}() + func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { - err := test(vm.Config{}) + err := test(testVMConfig) if err == nil { return } @@ -75,18 +90,19 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { t.Log("gas limit too high for EVM trace") return } - tracer := vm.NewStructLogger(nil) + buf := new(bytes.Buffer) + w := bufio.NewWriter(buf) + tracer := vm.NewJSONLogger(&vm.LogConfig{DisableMemory: true}, w) err2 := test(vm.Config{Debug: true, Tracer: tracer}) if !reflect.DeepEqual(err, err2) { t.Errorf("different error for second run: %v", err2) } - buf := new(bytes.Buffer) - vm.WriteTrace(buf, tracer.StructLogs()) + w.Flush() if buf.Len() == 0 { t.Log("no EVM operation logs generated") } else { t.Log("EVM operation log:\n" + buf.String()) } - t.Logf("EVM output: 0x%x", tracer.Output()) - t.Logf("EVM error: %v", tracer.Error()) + //t.Logf("EVM output: 0x%x", tracer.Output()) + //t.Logf("EVM error: %v", tracer.Error()) } diff --git a/vendor/github.com/ethereum/go-ethereum/tests/state_test_util.go b/vendor/github.com/ethereum/go-ethereum/tests/state_test_util.go index 3683aae3..0b78f26e 100644 --- a/vendor/github.com/ethereum/go-ethereum/tests/state_test_util.go +++ b/vendor/github.com/ethereum/go-ethereum/tests/state_test_util.go @@ -27,14 +27,15 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) // StateTest checks transaction processing without block context. @@ -126,7 +127,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD return nil, UnsupportedForkError{subtest.Fork} } block := t.genesis(config).ToBlock(nil) - statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) + statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre) post := t.json.Post[subtest.Fork][subtest.Index] msg, err := t.json.Tx.toMessage(post) @@ -248,7 +249,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { } func rlpHash(x interface{}) (h common.Hash) { - hw := sha3.NewKeccak256() + hw := sha3.NewLegacyKeccak256() rlp.Encode(hw, x) hw.Sum(h[:0]) return h diff --git a/vendor/github.com/ethereum/go-ethereum/tests/vm_test_util.go b/vendor/github.com/ethereum/go-ethereum/tests/vm_test_util.go index cb81c5b9..91566c47 100644 --- a/vendor/github.com/ethereum/go-ethereum/tests/vm_test_util.go +++ b/vendor/github.com/ethereum/go-ethereum/tests/vm_test_util.go @@ -26,10 +26,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -79,7 +79,7 @@ type vmExecMarshaling struct { } func (t *VMTest) Run(vmconfig vm.Config) error { - statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) + statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre) ret, gasRemaining, err := t.exec(statedb, vmconfig) if t.json.GasRemaining == nil { diff --git a/vendor/github.com/ethereum/go-ethereum/trie/database.go b/vendor/github.com/ethereum/go-ethereum/trie/database.go index d0691b63..3bbcb6ad 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/database.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/database.go @@ -17,11 +17,13 @@ package trie import ( + "encoding/binary" "fmt" "io" "sync" "time" + "github.com/allegro/bigcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -30,6 +32,11 @@ import ( ) var ( + memcacheCleanHitMeter = metrics.NewRegisteredMeter("trie/memcache/clean/hit", nil) + memcacheCleanMissMeter = metrics.NewRegisteredMeter("trie/memcache/clean/miss", nil) + memcacheCleanReadMeter = metrics.NewRegisteredMeter("trie/memcache/clean/read", nil) + memcacheCleanWriteMeter = metrics.NewRegisteredMeter("trie/memcache/clean/write", nil) + memcacheFlushTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/flush/time", nil) memcacheFlushNodesMeter = metrics.NewRegisteredMeter("trie/memcache/flush/nodes", nil) memcacheFlushSizeMeter = metrics.NewRegisteredMeter("trie/memcache/flush/size", nil) @@ -49,24 +56,21 @@ var secureKeyPrefix = []byte("secure-key-") // secureKeyLength is the length of the above prefix + 32byte hash. const secureKeyLength = 11 + 32 -// DatabaseReader wraps the Get and Has method of a backing store for the trie. -type DatabaseReader interface { - // Get retrieves the value associated with key from the database. - Get(key []byte) (value []byte, err error) - - // Has retrieves whether a key is present in the database. - Has(key []byte) (bool, error) -} - // Database is an intermediate write layer between the trie data structures and // the disk database. The aim is to accumulate trie writes in-memory and only // periodically flush a couple tries to disk, garbage collecting the remainder. +// +// Note, the trie Database is **not** thread safe in its mutations, but it **is** +// thread safe in providing individual, independent node access. The rationale +// behind this split design is to provide read access to RPC handlers and sync +// servers even while the trie is executing expensive garbage collection. type Database struct { - diskdb ethdb.Database // Persistent storage for matured trie nodes + diskdb ethdb.KeyValueStore // Persistent storage for matured trie nodes - nodes map[common.Hash]*cachedNode // Data and references relationships of a node - oldest common.Hash // Oldest tracked node, flush-list head - newest common.Hash // Newest tracked node, flush-list tail + cleans *bigcache.BigCache // GC friendly memory cache of clean node RLPs + dirties map[common.Hash]*cachedNode // Data and references relationships of dirty nodes + oldest common.Hash // Oldest tracked node, flush-list head + newest common.Hash // Newest tracked node, flush-list tail preimages map[common.Hash][]byte // Preimages of nodes from the secure trie seckeybuf [secureKeyLength]byte // Ephemeral buffer for calculating preimage keys @@ -79,7 +83,7 @@ type Database struct { flushnodes uint64 // Nodes flushed since last commit flushsize common.StorageSize // Data storage flushed since last commit - nodesSize common.StorageSize // Storage size of the nodes cache (exc. flushlist) + dirtiesSize common.StorageSize // Storage size of the dirty node cache (exc. flushlist) preimagesSize common.StorageSize // Storage size of the preimages cache lock sync.RWMutex @@ -134,7 +138,7 @@ type cachedNode struct { node node // Cached collapsed trie node, or raw rlp data size uint16 // Byte size of the useful cached data - parents uint16 // Number of live nodes referencing this one + parents uint32 // Number of live nodes referencing this one children map[common.Hash]uint16 // External children referenced by this node flushPrev common.Hash // Previous node in the flush-list @@ -156,11 +160,11 @@ func (n *cachedNode) rlp() []byte { // obj returns the decoded and expanded trie node, either directly from the cache, // or by regenerating it from the rlp encoded blob. -func (n *cachedNode) obj(hash common.Hash, cachegen uint16) node { +func (n *cachedNode) obj(hash common.Hash) node { if node, ok := n.node.(rawNode); ok { - return mustDecodeNode(hash[:], node, cachegen) + return mustDecodeNode(hash[:], node) } - return expandNode(hash[:], n.node, cachegen) + return expandNode(hash[:], n.node) } // childs returns all the tracked children of this node, both the implicit ones @@ -225,16 +229,15 @@ func simplifyNode(n node) node { // expandNode traverses the node hierarchy of a collapsed storage node and converts // all fields and keys into expanded memory form. -func expandNode(hash hashNode, n node, cachegen uint16) node { +func expandNode(hash hashNode, n node) node { switch n := n.(type) { case *rawShortNode: // Short nodes need key and child expansion return &shortNode{ Key: compactToHex(n.Key), - Val: expandNode(nil, n.Val, cachegen), + Val: expandNode(nil, n.Val), flags: nodeFlag{ hash: hash, - gen: cachegen, }, } @@ -243,12 +246,11 @@ func expandNode(hash hashNode, n node, cachegen uint16) node { node := &fullNode{ flags: nodeFlag{ hash: hash, - gen: cachegen, }, } for i := 0; i < len(node.Children); i++ { if n[i] != nil { - node.Children[i] = expandNode(nil, n[i], cachegen) + node.Children[i] = expandNode(nil, n[i]) } } return node @@ -261,18 +263,51 @@ func expandNode(hash hashNode, n node, cachegen uint16) node { } } +// trienodeHasher is a struct to be used with BigCache, which uses a Hasher to +// determine which shard to place an entry into. It's not a cryptographic hash, +// just to provide a bit of anti-collision (default is FNV64a). +// +// Since trie keys are already hashes, we can just use the key directly to +// map shard id. +type trienodeHasher struct{} + +// Sum64 implements the bigcache.Hasher interface. +func (t trienodeHasher) Sum64(key string) uint64 { + return binary.BigEndian.Uint64([]byte(key)) +} + // NewDatabase creates a new trie database to store ephemeral trie content before -// its written out to disk or garbage collected. -func NewDatabase(diskdb ethdb.Database) *Database { +// its written out to disk or garbage collected. No read cache is created, so all +// data retrievals will hit the underlying disk database. +func NewDatabase(diskdb ethdb.KeyValueStore) *Database { + return NewDatabaseWithCache(diskdb, 0) +} + +// NewDatabaseWithCache creates a new trie database to store ephemeral trie content +// before its written out to disk or garbage collected. It also acts as a read cache +// for nodes loaded from disk. +func NewDatabaseWithCache(diskdb ethdb.KeyValueStore, cache int) *Database { + var cleans *bigcache.BigCache + if cache > 0 { + cleans, _ = bigcache.NewBigCache(bigcache.Config{ + Shards: 1024, + LifeWindow: time.Hour, + MaxEntriesInWindow: cache * 1024, + MaxEntrySize: 512, + HardMaxCacheSize: cache, + Hasher: trienodeHasher{}, + }) + } return &Database{ diskdb: diskdb, - nodes: map[common.Hash]*cachedNode{{}: {}}, + cleans: cleans, + dirties: map[common.Hash]*cachedNode{{}: {}}, preimages: make(map[common.Hash][]byte), } } // DiskDB retrieves the persistent storage backing the trie database. -func (db *Database) DiskDB() DatabaseReader { +func (db *Database) DiskDB() ethdb.Reader { return db.diskdb } @@ -293,7 +328,7 @@ func (db *Database) InsertBlob(hash common.Hash, blob []byte) { // size tracking. func (db *Database) insert(hash common.Hash, blob []byte, node node) { // If the node's already cached, skip - if _, ok := db.nodes[hash]; ok { + if _, ok := db.dirties[hash]; ok { return } // Create the cached entry for this node @@ -303,19 +338,19 @@ func (db *Database) insert(hash common.Hash, blob []byte, node node) { flushPrev: db.newest, } for _, child := range entry.childs() { - if c := db.nodes[child]; c != nil { + if c := db.dirties[child]; c != nil { c.parents++ } } - db.nodes[hash] = entry + db.dirties[hash] = entry // Update the flush-list endpoints if db.oldest == (common.Hash{}) { db.oldest, db.newest = hash, hash } else { - db.nodes[db.newest].flushNext, db.newest = hash, hash + db.dirties[db.newest].flushNext, db.newest = hash, hash } - db.nodesSize += common.StorageSize(common.HashLength + entry.size) + db.dirtiesSize += common.StorageSize(common.HashLength + entry.size) } // insertPreimage writes a new trie node pre-image to the memory database if it's @@ -332,36 +367,65 @@ func (db *Database) insertPreimage(hash common.Hash, preimage []byte) { // node retrieves a cached trie node from memory, or returns nil if none can be // found in the memory cache. -func (db *Database) node(hash common.Hash, cachegen uint16) node { - // Retrieve the node from cache if available +func (db *Database) node(hash common.Hash) node { + // Retrieve the node from the clean cache if available + if db.cleans != nil { + if enc, err := db.cleans.Get(string(hash[:])); err == nil && enc != nil { + memcacheCleanHitMeter.Mark(1) + memcacheCleanReadMeter.Mark(int64(len(enc))) + return mustDecodeNode(hash[:], enc) + } + } + // Retrieve the node from the dirty cache if available db.lock.RLock() - node := db.nodes[hash] + dirty := db.dirties[hash] db.lock.RUnlock() - if node != nil { - return node.obj(hash, cachegen) + if dirty != nil { + return dirty.obj(hash) } // Content unavailable in memory, attempt to retrieve from disk enc, err := db.diskdb.Get(hash[:]) if err != nil || enc == nil { return nil } - return mustDecodeNode(hash[:], enc, cachegen) + if db.cleans != nil { + db.cleans.Set(string(hash[:]), enc) + memcacheCleanMissMeter.Mark(1) + memcacheCleanWriteMeter.Mark(int64(len(enc))) + } + return mustDecodeNode(hash[:], enc) } // Node retrieves an encoded cached trie node from memory. If it cannot be found // cached, the method queries the persistent database for the content. func (db *Database) Node(hash common.Hash) ([]byte, error) { - // Retrieve the node from cache if available + // Retrieve the node from the clean cache if available + if db.cleans != nil { + if enc, err := db.cleans.Get(string(hash[:])); err == nil && enc != nil { + memcacheCleanHitMeter.Mark(1) + memcacheCleanReadMeter.Mark(int64(len(enc))) + return enc, nil + } + } + // Retrieve the node from the dirty cache if available db.lock.RLock() - node := db.nodes[hash] + dirty := db.dirties[hash] db.lock.RUnlock() - if node != nil { - return node.rlp(), nil + if dirty != nil { + return dirty.rlp(), nil } // Content unavailable in memory, attempt to retrieve from disk - return db.diskdb.Get(hash[:]) + enc, err := db.diskdb.Get(hash[:]) + if err == nil && enc != nil { + if db.cleans != nil { + db.cleans.Set(string(hash[:]), enc) + memcacheCleanMissMeter.Mark(1) + memcacheCleanWriteMeter.Mark(int64(len(enc))) + } + } + return enc, err } // preimage retrieves a cached trie node pre-image from memory. If it cannot be @@ -395,8 +459,8 @@ func (db *Database) Nodes() []common.Hash { db.lock.RLock() defer db.lock.RUnlock() - var hashes = make([]common.Hash, 0, len(db.nodes)) - for hash := range db.nodes { + var hashes = make([]common.Hash, 0, len(db.dirties)) + for hash := range db.dirties { if hash != (common.Hash{}) { // Special case for "root" references/nodes hashes = append(hashes, hash) } @@ -406,8 +470,8 @@ func (db *Database) Nodes() []common.Hash { // Reference adds a new reference from a parent node to a child node. func (db *Database) Reference(child common.Hash, parent common.Hash) { - db.lock.RLock() - defer db.lock.RUnlock() + db.lock.Lock() + defer db.lock.Unlock() db.reference(child, parent) } @@ -415,18 +479,18 @@ func (db *Database) Reference(child common.Hash, parent common.Hash) { // reference is the private locked version of Reference. func (db *Database) reference(child common.Hash, parent common.Hash) { // If the node does not exist, it's a node pulled from disk, skip - node, ok := db.nodes[child] + node, ok := db.dirties[child] if !ok { return } // If the reference already exists, only duplicate for roots - if db.nodes[parent].children == nil { - db.nodes[parent].children = make(map[common.Hash]uint16) - } else if _, ok = db.nodes[parent].children[child]; ok && parent != (common.Hash{}) { + if db.dirties[parent].children == nil { + db.dirties[parent].children = make(map[common.Hash]uint16) + } else if _, ok = db.dirties[parent].children[child]; ok && parent != (common.Hash{}) { return } node.parents++ - db.nodes[parent].children[child]++ + db.dirties[parent].children[child]++ } // Dereference removes an existing reference from a root node. @@ -439,25 +503,25 @@ func (db *Database) Dereference(root common.Hash) { db.lock.Lock() defer db.lock.Unlock() - nodes, storage, start := len(db.nodes), db.nodesSize, time.Now() + nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() db.dereference(root, common.Hash{}) - db.gcnodes += uint64(nodes - len(db.nodes)) - db.gcsize += storage - db.nodesSize + db.gcnodes += uint64(nodes - len(db.dirties)) + db.gcsize += storage - db.dirtiesSize db.gctime += time.Since(start) memcacheGCTimeTimer.Update(time.Since(start)) - memcacheGCSizeMeter.Mark(int64(storage - db.nodesSize)) - memcacheGCNodesMeter.Mark(int64(nodes - len(db.nodes))) + memcacheGCSizeMeter.Mark(int64(storage - db.dirtiesSize)) + memcacheGCNodesMeter.Mark(int64(nodes - len(db.dirties))) - log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.nodesSize, "time", time.Since(start), - "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.nodesSize) + log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), + "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) } // dereference is the private locked version of Dereference. func (db *Database) dereference(child common.Hash, parent common.Hash) { // Dereference the parent-child - node := db.nodes[parent] + node := db.dirties[parent] if node.children != nil && node.children[child] > 0 { node.children[child]-- @@ -466,7 +530,7 @@ func (db *Database) dereference(child common.Hash, parent common.Hash) { } } // If the child does not exist, it's a previously committed node. - node, ok := db.nodes[child] + node, ok := db.dirties[child] if !ok { return } @@ -483,39 +547,40 @@ func (db *Database) dereference(child common.Hash, parent common.Hash) { switch child { case db.oldest: db.oldest = node.flushNext - db.nodes[node.flushNext].flushPrev = common.Hash{} + db.dirties[node.flushNext].flushPrev = common.Hash{} case db.newest: db.newest = node.flushPrev - db.nodes[node.flushPrev].flushNext = common.Hash{} + db.dirties[node.flushPrev].flushNext = common.Hash{} default: - db.nodes[node.flushPrev].flushNext = node.flushNext - db.nodes[node.flushNext].flushPrev = node.flushPrev + db.dirties[node.flushPrev].flushNext = node.flushNext + db.dirties[node.flushNext].flushPrev = node.flushPrev } // Dereference all children and delete the node for _, hash := range node.childs() { db.dereference(hash, child) } - delete(db.nodes, child) - db.nodesSize -= common.StorageSize(common.HashLength + int(node.size)) + delete(db.dirties, child) + db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) } } // Cap iteratively flushes old but still referenced trie nodes until the total // memory usage goes below the given threshold. +// +// Note, this method is a non-synchronized mutator. It is unsafe to call this +// concurrently with other mutators. func (db *Database) Cap(limit common.StorageSize) error { // Create a database batch to flush persistent data out. It is important that // outside code doesn't see an inconsistent state (referenced data removed from // memory cache during commit but not yet in persistent storage). This is ensured // by only uncaching existing data when the database write finalizes. - db.lock.RLock() - - nodes, storage, start := len(db.nodes), db.nodesSize, time.Now() + nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() batch := db.diskdb.NewBatch() - // db.nodesSize only contains the useful data in the cache, but when reporting + // db.dirtiesSize only contains the useful data in the cache, but when reporting // the total memory consumption, the maintenance metadata is also needed to be // counted. For every useful node, we track 2 extra hashes as the flushlist. - size := db.nodesSize + common.StorageSize((len(db.nodes)-1)*2*common.HashLength) + size := db.dirtiesSize + common.StorageSize((len(db.dirties)-1)*2*common.HashLength) // If the preimage cache got large enough, push to disk. If it's still small // leave for later to deduplicate writes. @@ -524,12 +589,10 @@ func (db *Database) Cap(limit common.StorageSize) error { for hash, preimage := range db.preimages { if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { log.Error("Failed to commit preimage from trie database", "err", err) - db.lock.RUnlock() return err } if batch.ValueSize() > ethdb.IdealBatchSize { if err := batch.Write(); err != nil { - db.lock.RUnlock() return err } batch.Reset() @@ -540,16 +603,14 @@ func (db *Database) Cap(limit common.StorageSize) error { oldest := db.oldest for size > limit && oldest != (common.Hash{}) { // Fetch the oldest referenced node and push into the batch - node := db.nodes[oldest] + node := db.dirties[oldest] if err := batch.Put(oldest[:], node.rlp()); err != nil { - db.lock.RUnlock() return err } // If we exceeded the ideal batch size, commit and reset if batch.ValueSize() >= ethdb.IdealBatchSize { if err := batch.Write(); err != nil { log.Error("Failed to write flush list to disk", "err", err) - db.lock.RUnlock() return err } batch.Reset() @@ -564,11 +625,8 @@ func (db *Database) Cap(limit common.StorageSize) error { // Flush out any remainder data from the last batch if err := batch.Write(); err != nil { log.Error("Failed to write flush list to disk", "err", err) - db.lock.RUnlock() return err } - db.lock.RUnlock() - // Write successful, clear out the flushed data db.lock.Lock() defer db.lock.Unlock() @@ -578,40 +636,40 @@ func (db *Database) Cap(limit common.StorageSize) error { db.preimagesSize = 0 } for db.oldest != oldest { - node := db.nodes[db.oldest] - delete(db.nodes, db.oldest) + node := db.dirties[db.oldest] + delete(db.dirties, db.oldest) db.oldest = node.flushNext - db.nodesSize -= common.StorageSize(common.HashLength + int(node.size)) + db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) } if db.oldest != (common.Hash{}) { - db.nodes[db.oldest].flushPrev = common.Hash{} + db.dirties[db.oldest].flushPrev = common.Hash{} } - db.flushnodes += uint64(nodes - len(db.nodes)) - db.flushsize += storage - db.nodesSize + db.flushnodes += uint64(nodes - len(db.dirties)) + db.flushsize += storage - db.dirtiesSize db.flushtime += time.Since(start) memcacheFlushTimeTimer.Update(time.Since(start)) - memcacheFlushSizeMeter.Mark(int64(storage - db.nodesSize)) - memcacheFlushNodesMeter.Mark(int64(nodes - len(db.nodes))) + memcacheFlushSizeMeter.Mark(int64(storage - db.dirtiesSize)) + memcacheFlushNodesMeter.Mark(int64(nodes - len(db.dirties))) - log.Debug("Persisted nodes from memory database", "nodes", nodes-len(db.nodes), "size", storage-db.nodesSize, "time", time.Since(start), - "flushnodes", db.flushnodes, "flushsize", db.flushsize, "flushtime", db.flushtime, "livenodes", len(db.nodes), "livesize", db.nodesSize) + log.Debug("Persisted nodes from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), + "flushnodes", db.flushnodes, "flushsize", db.flushsize, "flushtime", db.flushtime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) return nil } // Commit iterates over all the children of a particular node, writes them out -// to disk, forcefully tearing down all references in both directions. +// to disk, forcefully tearing down all references in both directions. As a side +// effect, all pre-images accumulated up to this point are also written. // -// As a side effect, all pre-images accumulated up to this point are also written. +// Note, this method is a non-synchronized mutator. It is unsafe to call this +// concurrently with other mutators. func (db *Database) Commit(node common.Hash, report bool) error { // Create a database batch to flush persistent data out. It is important that // outside code doesn't see an inconsistent state (referenced data removed from // memory cache during commit but not yet in persistent storage). This is ensured // by only uncaching existing data when the database write finalizes. - db.lock.RLock() - start := time.Now() batch := db.diskdb.NewBatch() @@ -619,9 +677,9 @@ func (db *Database) Commit(node common.Hash, report bool) error { for hash, preimage := range db.preimages { if err := batch.Put(db.secureKey(hash[:]), preimage); err != nil { log.Error("Failed to commit preimage from trie database", "err", err) - db.lock.RUnlock() return err } + // If the batch is too large, flush to disk if batch.ValueSize() > ethdb.IdealBatchSize { if err := batch.Write(); err != nil { return err @@ -629,40 +687,47 @@ func (db *Database) Commit(node common.Hash, report bool) error { batch.Reset() } } - // Move the trie itself into the batch, flushing if enough data is accumulated - nodes, storage := len(db.nodes), db.nodesSize - if err := db.commit(node, batch); err != nil { - log.Error("Failed to commit trie from trie database", "err", err) - db.lock.RUnlock() + // Since we're going to replay trie node writes into the clean cache, flush out + // any batched pre-images before continuing. + if err := batch.Write(); err != nil { return err } - // Write batch ready, unlock for readers during persistence + batch.Reset() + + // Move the trie itself into the batch, flushing if enough data is accumulated + nodes, storage := len(db.dirties), db.dirtiesSize + + uncacher := &cleaner{db} + if err := db.commit(node, batch, uncacher); err != nil { + log.Error("Failed to commit trie from trie database", "err", err) + return err + } + // Trie mostly committed to disk, flush any batch leftovers if err := batch.Write(); err != nil { log.Error("Failed to write trie to disk", "err", err) - db.lock.RUnlock() return err } - db.lock.RUnlock() - - // Write successful, clear out the flushed data + // Uncache any leftovers in the last batch db.lock.Lock() defer db.lock.Unlock() + batch.Replay(uncacher) + batch.Reset() + + // Reset the storage counters and bumpd metrics db.preimages = make(map[common.Hash][]byte) db.preimagesSize = 0 - db.uncache(node) - memcacheCommitTimeTimer.Update(time.Since(start)) - memcacheCommitSizeMeter.Mark(int64(storage - db.nodesSize)) - memcacheCommitNodesMeter.Mark(int64(nodes - len(db.nodes))) + memcacheCommitSizeMeter.Mark(int64(storage - db.dirtiesSize)) + memcacheCommitNodesMeter.Mark(int64(nodes - len(db.dirties))) logger := log.Info if !report { logger = log.Debug } - logger("Persisted trie from memory database", "nodes", nodes-len(db.nodes)+int(db.flushnodes), "size", storage-db.nodesSize+db.flushsize, "time", time.Since(start)+db.flushtime, - "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.nodes), "livesize", db.nodesSize) + logger("Persisted trie from memory database", "nodes", nodes-len(db.dirties)+int(db.flushnodes), "size", storage-db.dirtiesSize+db.flushsize, "time", time.Since(start)+db.flushtime, + "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) // Reset the garbage collection statistics db.gcnodes, db.gcsize, db.gctime = 0, 0, 0 @@ -672,14 +737,14 @@ func (db *Database) Commit(node common.Hash, report bool) error { } // commit is the private locked version of Commit. -func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error { +func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleaner) error { // If the node does not exist, it's a previously committed node - node, ok := db.nodes[hash] + node, ok := db.dirties[hash] if !ok { return nil } for _, child := range node.childs() { - if err := db.commit(child, batch); err != nil { + if err := db.commit(child, batch, uncacher); err != nil { return err } } @@ -691,39 +756,58 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error { if err := batch.Write(); err != nil { return err } + db.lock.Lock() + batch.Replay(uncacher) batch.Reset() + db.lock.Unlock() } return nil } -// uncache is the post-processing step of a commit operation where the already -// persisted trie is removed from the cache. The reason behind the two-phase -// commit is to ensure consistent data availability while moving from memory -// to disk. -func (db *Database) uncache(hash common.Hash) { +// cleaner is a database batch replayer that takes a batch of write operations +// and cleans up the trie database from anything written to disk. +type cleaner struct { + db *Database +} + +// Put reacts to database writes and implements dirty data uncaching. This is the +// post-processing step of a commit operation where the already persisted trie is +// removed from the dirty cache and moved into the clean cache. The reason behind +// the two-phase commit is to ensure ensure data availability while moving from +// memory to disk. +func (c *cleaner) Put(key []byte, rlp []byte) error { + hash := common.BytesToHash(key) + // If the node does not exist, we're done on this path - node, ok := db.nodes[hash] + node, ok := c.db.dirties[hash] if !ok { - return + return nil } // Node still exists, remove it from the flush-list switch hash { - case db.oldest: - db.oldest = node.flushNext - db.nodes[node.flushNext].flushPrev = common.Hash{} - case db.newest: - db.newest = node.flushPrev - db.nodes[node.flushPrev].flushNext = common.Hash{} + case c.db.oldest: + c.db.oldest = node.flushNext + c.db.dirties[node.flushNext].flushPrev = common.Hash{} + case c.db.newest: + c.db.newest = node.flushPrev + c.db.dirties[node.flushPrev].flushNext = common.Hash{} default: - db.nodes[node.flushPrev].flushNext = node.flushNext - db.nodes[node.flushNext].flushPrev = node.flushPrev + c.db.dirties[node.flushPrev].flushNext = node.flushNext + c.db.dirties[node.flushNext].flushPrev = node.flushPrev } - // Uncache the node's subtries and remove the node itself too - for _, child := range node.childs() { - db.uncache(child) + // Remove the node from the dirty cache + delete(c.db.dirties, hash) + c.db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) + + // Move the flushed node into the clean cache to prevent insta-reloads + if c.db.cleans != nil { + c.db.cleans.Set(string(hash[:]), rlp) } - delete(db.nodes, hash) - db.nodesSize -= common.StorageSize(common.HashLength + int(node.size)) + return nil +} + +func (c *cleaner) Delete(key []byte) error { + panic("Not implemented") } // Size returns the current storage size of the memory cache in front of the @@ -732,11 +816,11 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) { db.lock.RLock() defer db.lock.RUnlock() - // db.nodesSize only contains the useful data in the cache, but when reporting + // db.dirtiesSize only contains the useful data in the cache, but when reporting // the total memory consumption, the maintenance metadata is also needed to be // counted. For every useful node, we track 2 extra hashes as the flushlist. - var flushlistSize = common.StorageSize((len(db.nodes) - 1) * 2 * common.HashLength) - return db.nodesSize + flushlistSize, db.preimagesSize + var flushlistSize = common.StorageSize((len(db.dirties) - 1) * 2 * common.HashLength) + return db.dirtiesSize + flushlistSize, db.preimagesSize } // verifyIntegrity is a debug method to iterate over the entire trie stored in @@ -749,12 +833,12 @@ func (db *Database) verifyIntegrity() { // Iterate over all the cached nodes and accumulate them into a set reachable := map[common.Hash]struct{}{{}: {}} - for child := range db.nodes[common.Hash{}].children { + for child := range db.dirties[common.Hash{}].children { db.accumulate(child, reachable) } // Find any unreachable but cached nodes - unreachable := []string{} - for hash, node := range db.nodes { + var unreachable []string + for hash, node := range db.dirties { if _, ok := reachable[hash]; !ok { unreachable = append(unreachable, fmt.Sprintf("%x: {Node: %v, Parents: %d, Prev: %x, Next: %x}", hash, node.node, node.parents, node.flushPrev, node.flushNext)) @@ -769,7 +853,7 @@ func (db *Database) verifyIntegrity() { // cached children found in memory. func (db *Database) accumulate(hash common.Hash, reachable map[common.Hash]struct{}) { // Mark the node reachable if present in the memory cache - node, ok := db.nodes[hash] + node, ok := db.dirties[hash] if !ok { return } diff --git a/vendor/github.com/ethereum/go-ethereum/trie/encoding.go b/vendor/github.com/ethereum/go-ethereum/trie/encoding.go index 5f120de6..1955a3e6 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/encoding.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/encoding.go @@ -52,6 +52,9 @@ func hexToCompact(hex []byte) []byte { } func compactToHex(compact []byte) []byte { + if len(compact) == 0 { + return compact + } base := keybytesToHex(compact) // delete terminator flag if base[0] < 2 { diff --git a/vendor/github.com/ethereum/go-ethereum/trie/hasher.go b/vendor/github.com/ethereum/go-ethereum/trie/hasher.go index 7b1d7793..54f6a9de 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/hasher.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/hasher.go @@ -21,16 +21,14 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) type hasher struct { - tmp sliceBuffer - sha keccakState - cachegen uint16 - cachelimit uint16 - onleaf LeafCallback + tmp sliceBuffer + sha keccakState + onleaf LeafCallback } // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports @@ -57,14 +55,14 @@ var hasherPool = sync.Pool{ New: func() interface{} { return &hasher{ tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode. - sha: sha3.NewKeccak256().(keccakState), + sha: sha3.NewLegacyKeccak256().(keccakState), } }, } -func newHasher(cachegen, cachelimit uint16, onleaf LeafCallback) *hasher { +func newHasher(onleaf LeafCallback) *hasher { h := hasherPool.Get().(*hasher) - h.cachegen, h.cachelimit, h.onleaf = cachegen, cachelimit, onleaf + h.onleaf = onleaf return h } @@ -80,14 +78,13 @@ func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { if db == nil { return hash, n, nil } - if n.canUnload(h.cachegen, h.cachelimit) { - // Unload the node from cache. All of its subnodes will have a lower or equal - // cache generation number. - cacheUnloadCounter.Inc(1) - return hash, hash, nil - } if !dirty { - return hash, n, nil + switch n.(type) { + case *fullNode, *shortNode: + return hash, hash, nil + default: + return hash, n, nil + } } } // Trie not processed yet or needs storage, walk the children diff --git a/vendor/github.com/ethereum/go-ethereum/trie/iterator.go b/vendor/github.com/ethereum/go-ethereum/trie/iterator.go index 00b890eb..da93b2fa 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/iterator.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/iterator.go @@ -180,7 +180,9 @@ func (it *nodeIterator) LeafBlob() []byte { func (it *nodeIterator) LeafProof() [][]byte { if len(it.stack) > 0 { if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { - hasher := newHasher(0, 0, nil) + hasher := newHasher(nil) + defer returnHasherToPool(hasher) + proofs := make([][]byte, 0, len(it.stack)) for i, item := range it.stack[:len(it.stack)-1] { diff --git a/vendor/github.com/ethereum/go-ethereum/trie/iterator_test.go b/vendor/github.com/ethereum/go-ethereum/trie/iterator_test.go index 2a510b1c..88b8103f 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/iterator_test.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/iterator_test.go @@ -23,7 +23,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" ) func TestIterator(t *testing.T) { @@ -113,18 +113,21 @@ func TestNodeIteratorCoverage(t *testing.T) { t.Errorf("failed to retrieve reported node %x: %v", hash, err) } } - for hash, obj := range db.nodes { + for hash, obj := range db.dirties { if obj != nil && hash != (common.Hash{}) { if _, ok := hashes[hash]; !ok { t.Errorf("state entry not reported %x", hash) } } } - for _, key := range db.diskdb.(*ethdb.MemDatabase).Keys() { + it := db.diskdb.NewIterator() + for it.Next() { + key := it.Key() if _, ok := hashes[common.BytesToHash(key)]; !ok { t.Errorf("state entry not reported %x", key) } } + it.Release() } type kvs struct{ k, v string } @@ -289,7 +292,7 @@ func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueA func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } func testIteratorContinueAfterError(t *testing.T, memonly bool) { - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) tr, _ := New(common.Hash{}, triedb) @@ -309,7 +312,11 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { if memonly { memKeys = triedb.Nodes() } else { - diskKeys = diskdb.Keys() + it := diskdb.NewIterator() + for it.Next() { + diskKeys = append(diskKeys, it.Key()) + } + it.Release() } for i := 0; i < 20; i++ { // Create trie that will load all nodes from DB. @@ -333,8 +340,8 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { } } if memonly { - robj = triedb.nodes[rkey] - delete(triedb.nodes, rkey) + robj = triedb.dirties[rkey] + delete(triedb.dirties, rkey) } else { rval, _ = diskdb.Get(rkey[:]) diskdb.Delete(rkey[:]) @@ -350,7 +357,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { // Add the node back and continue iteration. if memonly { - triedb.nodes[rkey] = robj + triedb.dirties[rkey] = robj } else { diskdb.Put(rkey[:], rval) } @@ -376,7 +383,7 @@ func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { // Commit test trie to db, then remove the node containing "bars". - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) ctr, _ := New(common.Hash{}, triedb) @@ -393,8 +400,8 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { barNodeObj *cachedNode ) if memonly { - barNodeObj = triedb.nodes[barNodeHash] - delete(triedb.nodes, barNodeHash) + barNodeObj = triedb.dirties[barNodeHash] + delete(triedb.dirties, barNodeHash) } else { barNodeBlob, _ = diskdb.Get(barNodeHash[:]) diskdb.Delete(barNodeHash[:]) @@ -411,7 +418,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { } // Reinsert the missing node. if memonly { - triedb.nodes[barNodeHash] = barNodeObj + triedb.dirties[barNodeHash] = barNodeObj } else { diskdb.Put(barNodeHash[:], barNodeBlob) } diff --git a/vendor/github.com/ethereum/go-ethereum/trie/node.go b/vendor/github.com/ethereum/go-ethereum/trie/node.go index 1fafb7a5..f4055e77 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/node.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/node.go @@ -30,7 +30,6 @@ var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b type node interface { fstring(string) string cache() (hashNode, bool) - canUnload(cachegen, cachelimit uint16) bool } type ( @@ -71,20 +70,9 @@ func (n *shortNode) copy() *shortNode { copy := *n; return © } // nodeFlag contains caching-related metadata about a node. type nodeFlag struct { hash hashNode // cached hash of the node (may be nil) - gen uint16 // cache generation counter dirty bool // whether the node has changes that must be written to the database } -// canUnload tells whether a node can be unloaded. -func (n *nodeFlag) canUnload(cachegen, cachelimit uint16) bool { - return !n.dirty && cachegen-n.gen >= cachelimit -} - -func (n *fullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } -func (n *shortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } -func (n hashNode) canUnload(uint16, uint16) bool { return false } -func (n valueNode) canUnload(uint16, uint16) bool { return false } - func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } func (n hashNode) cache() (hashNode, bool) { return nil, true } @@ -117,8 +105,8 @@ func (n valueNode) fstring(ind string) string { return fmt.Sprintf("%x ", []byte(n)) } -func mustDecodeNode(hash, buf []byte, cachegen uint16) node { - n, err := decodeNode(hash, buf, cachegen) +func mustDecodeNode(hash, buf []byte) node { + n, err := decodeNode(hash, buf) if err != nil { panic(fmt.Sprintf("node %x: %v", hash, err)) } @@ -126,7 +114,7 @@ func mustDecodeNode(hash, buf []byte, cachegen uint16) node { } // decodeNode parses the RLP encoding of a trie node. -func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { +func decodeNode(hash, buf []byte) (node, error) { if len(buf) == 0 { return nil, io.ErrUnexpectedEOF } @@ -136,22 +124,22 @@ func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { } switch c, _ := rlp.CountValues(elems); c { case 2: - n, err := decodeShort(hash, elems, cachegen) + n, err := decodeShort(hash, elems) return n, wrapError(err, "short") case 17: - n, err := decodeFull(hash, elems, cachegen) + n, err := decodeFull(hash, elems) return n, wrapError(err, "full") default: return nil, fmt.Errorf("invalid number of list elements: %v", c) } } -func decodeShort(hash, elems []byte, cachegen uint16) (node, error) { +func decodeShort(hash, elems []byte) (node, error) { kbuf, rest, err := rlp.SplitString(elems) if err != nil { return nil, err } - flag := nodeFlag{hash: hash, gen: cachegen} + flag := nodeFlag{hash: hash} key := compactToHex(kbuf) if hasTerm(key) { // value node @@ -161,17 +149,17 @@ func decodeShort(hash, elems []byte, cachegen uint16) (node, error) { } return &shortNode{key, append(valueNode{}, val...), flag}, nil } - r, _, err := decodeRef(rest, cachegen) + r, _, err := decodeRef(rest) if err != nil { return nil, wrapError(err, "val") } return &shortNode{key, r, flag}, nil } -func decodeFull(hash, elems []byte, cachegen uint16) (*fullNode, error) { - n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen}} +func decodeFull(hash, elems []byte) (*fullNode, error) { + n := &fullNode{flags: nodeFlag{hash: hash}} for i := 0; i < 16; i++ { - cld, rest, err := decodeRef(elems, cachegen) + cld, rest, err := decodeRef(elems) if err != nil { return n, wrapError(err, fmt.Sprintf("[%d]", i)) } @@ -189,7 +177,7 @@ func decodeFull(hash, elems []byte, cachegen uint16) (*fullNode, error) { const hashLen = len(common.Hash{}) -func decodeRef(buf []byte, cachegen uint16) (node, []byte, error) { +func decodeRef(buf []byte) (node, []byte, error) { kind, val, rest, err := rlp.Split(buf) if err != nil { return nil, buf, err @@ -202,7 +190,7 @@ func decodeRef(buf []byte, cachegen uint16) (node, []byte, error) { err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen) return nil, buf, err } - n, err := decodeNode(nil, buf, cachegen) + n, err := decodeNode(nil, buf) return n, rest, err case kind == rlp.String && len(val) == 0: // empty node diff --git a/vendor/github.com/ethereum/go-ethereum/trie/node_test.go b/vendor/github.com/ethereum/go-ethereum/trie/node_test.go deleted file mode 100644 index 7ad1ff9e..00000000 --- a/vendor/github.com/ethereum/go-ethereum/trie/node_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -import "testing" - -func TestCanUnload(t *testing.T) { - tests := []struct { - flag nodeFlag - cachegen, cachelimit uint16 - want bool - }{ - { - flag: nodeFlag{dirty: true, gen: 0}, - want: false, - }, - { - flag: nodeFlag{dirty: false, gen: 0}, - cachegen: 0, cachelimit: 0, - want: true, - }, - { - flag: nodeFlag{dirty: false, gen: 65534}, - cachegen: 65535, cachelimit: 1, - want: true, - }, - { - flag: nodeFlag{dirty: false, gen: 65534}, - cachegen: 0, cachelimit: 1, - want: true, - }, - { - flag: nodeFlag{dirty: false, gen: 1}, - cachegen: 65535, cachelimit: 1, - want: true, - }, - } - - for _, test := range tests { - if got := test.flag.canUnload(test.cachegen, test.cachelimit); got != test.want { - t.Errorf("%+v\n got %t, want %t", test, got, test.want) - } - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/trie/proof.go b/vendor/github.com/ethereum/go-ethereum/trie/proof.go index 6cb8f4d5..26a41ed2 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/proof.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/proof.go @@ -34,10 +34,10 @@ import ( // If the trie does not contain a value for key, the returned proof contains all // nodes of the longest existing prefix of the key (at least the root node), ending // with the node that proves the absence of the key. -func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { +func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Writer) error { // Collect all nodes on the path to key. key = keybytesToHex(key) - nodes := []node{} + var nodes []node tn := t.root for len(key) > 0 && tn != nil { switch n := tn.(type) { @@ -65,7 +65,9 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) } } - hasher := newHasher(0, 0, nil) + hasher := newHasher(nil) + defer returnHasherToPool(hasher) + for i, n := range nodes { // Don't bother checking for errors here since hasher panics // if encoding doesn't work and we're not writing to any database. @@ -95,14 +97,14 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { // If the trie does not contain a value for key, the returned proof contains all // nodes of the longest existing prefix of the key (at least the root node), ending // with the node that proves the absence of the key. -func (t *SecureTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { +func (t *SecureTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Writer) error { return t.trie.Prove(key, fromLevel, proofDb) } // VerifyProof checks merkle proofs. The given proof must contain the value for // key in a trie with the given root hash. VerifyProof returns an error if the // proof contains invalid trie nodes or the wrong value. -func VerifyProof(rootHash common.Hash, key []byte, proofDb DatabaseReader) (value []byte, nodes int, err error) { +func VerifyProof(rootHash common.Hash, key []byte, proofDb ethdb.Reader) (value []byte, nodes int, err error) { key = keybytesToHex(key) wantHash := rootHash for i := 0; ; i++ { @@ -110,7 +112,7 @@ func VerifyProof(rootHash common.Hash, key []byte, proofDb DatabaseReader) (valu if buf == nil { return nil, i, fmt.Errorf("proof node %d (hash %064x) missing", i, wantHash) } - n, err := decodeNode(wantHash[:], buf, 0) + n, err := decodeNode(wantHash[:], buf) if err != nil { return nil, i, fmt.Errorf("bad proof node %d: %v", i, err) } diff --git a/vendor/github.com/ethereum/go-ethereum/trie/proof_test.go b/vendor/github.com/ethereum/go-ethereum/trie/proof_test.go index 996f8747..c488f342 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/proof_test.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/proof_test.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" ) func init() { @@ -34,18 +34,18 @@ func init() { // makeProvers creates Merkle trie provers based on different implementations to // test all variations. -func makeProvers(trie *Trie) []func(key []byte) *ethdb.MemDatabase { - var provers []func(key []byte) *ethdb.MemDatabase +func makeProvers(trie *Trie) []func(key []byte) *memorydb.Database { + var provers []func(key []byte) *memorydb.Database // Create a direct trie based Merkle prover - provers = append(provers, func(key []byte) *ethdb.MemDatabase { - proof := ethdb.NewMemDatabase() + provers = append(provers, func(key []byte) *memorydb.Database { + proof := memorydb.New() trie.Prove(key, 0, proof) return proof }) // Create a leaf iterator based Merkle prover - provers = append(provers, func(key []byte) *ethdb.MemDatabase { - proof := ethdb.NewMemDatabase() + provers = append(provers, func(key []byte) *memorydb.Database { + proof := memorydb.New() if it := NewIterator(trie.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) { for _, p := range it.Prove() { proof.Put(crypto.Keccak256(p), p) @@ -106,9 +106,14 @@ func TestBadProof(t *testing.T) { if proof == nil { t.Fatalf("prover %d: nil proof", i) } - key := proof.Keys()[mrand.Intn(proof.Len())] + it := proof.NewIterator() + for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ { + it.Next() + } + key := it.Key() val, _ := proof.Get(key) proof.Delete(key) + it.Release() mutateByte(val) proof.Put(crypto.Keccak256(val), val) @@ -127,7 +132,7 @@ func TestMissingKeyProof(t *testing.T) { updateString(trie, "k", "v") for i, key := range []string{"a", "j", "l", "z"} { - proof := ethdb.NewMemDatabase() + proof := memorydb.New() trie.Prove([]byte(key), 0, proof) if proof.Len() != 1 { @@ -164,8 +169,8 @@ func BenchmarkProve(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { kv := vals[keys[i%len(keys)]] - proofs := ethdb.NewMemDatabase() - if trie.Prove(kv.k, 0, proofs); len(proofs.Keys()) == 0 { + proofs := memorydb.New() + if trie.Prove(kv.k, 0, proofs); proofs.Len() == 0 { b.Fatalf("zero length proof for %x", kv.k) } } @@ -175,10 +180,10 @@ func BenchmarkVerifyProof(b *testing.B) { trie, vals := randomTrie(100) root := trie.Hash() var keys []string - var proofs []*ethdb.MemDatabase + var proofs []*memorydb.Database for k := range vals { keys = append(keys, k) - proof := ethdb.NewMemDatabase() + proof := memorydb.New() trie.Prove([]byte(k), 0, proof) proofs = append(proofs, proof) } diff --git a/vendor/github.com/ethereum/go-ethereum/trie/secure_trie.go b/vendor/github.com/ethereum/go-ethereum/trie/secure_trie.go index 6a50cfd5..fbc591ed 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/secure_trie.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/secure_trie.go @@ -51,7 +51,7 @@ type SecureTrie struct { // Loaded nodes are kept around until their 'cache generation' expires. // A new cache generation is created by each call to Commit. // cachelimit sets the number of past cache generations to keep. -func NewSecure(root common.Hash, db *Database, cachelimit uint16) (*SecureTrie, error) { +func NewSecure(root common.Hash, db *Database) (*SecureTrie, error) { if db == nil { panic("trie.NewSecure called without a database") } @@ -59,7 +59,6 @@ func NewSecure(root common.Hash, db *Database, cachelimit uint16) (*SecureTrie, if err != nil { return nil, err } - trie.SetCacheLimit(cachelimit) return &SecureTrie{trie: *trie}, nil } @@ -161,12 +160,6 @@ func (t *SecureTrie) Hash() common.Hash { return t.trie.Hash() } -// Root returns the root hash of SecureTrie. -// Deprecated: use Hash instead. -func (t *SecureTrie) Root() []byte { - return t.trie.Root() -} - // Copy returns a copy of SecureTrie. func (t *SecureTrie) Copy() *SecureTrie { cpy := *t @@ -183,7 +176,7 @@ func (t *SecureTrie) NodeIterator(start []byte) NodeIterator { // The caller must not hold onto the return value because it will become // invalid on the next call to hashKey or secKey. func (t *SecureTrie) hashKey(key []byte) []byte { - h := newHasher(0, 0, nil) + h := newHasher(nil) h.sha.Reset() h.sha.Write(key) buf := h.sha.Sum(t.hashKeyBuf[:0]) diff --git a/vendor/github.com/ethereum/go-ethereum/trie/secure_trie_test.go b/vendor/github.com/ethereum/go-ethereum/trie/secure_trie_test.go index d16d9996..fb6c38ee 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/secure_trie_test.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/secure_trie_test.go @@ -24,20 +24,19 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" ) func newEmptySecure() *SecureTrie { - trie, _ := NewSecure(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()), 0) + trie, _ := NewSecure(common.Hash{}, NewDatabase(memorydb.New())) return trie } // makeTestSecureTrie creates a large enough secure trie for testing. func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) { // Create an empty trie - triedb := NewDatabase(ethdb.NewMemDatabase()) - - trie, _ := NewSecure(common.Hash{}, triedb, 0) + triedb := NewDatabase(memorydb.New()) + trie, _ := NewSecure(common.Hash{}, triedb) // Fill it with some arbitrary data content := make(map[string][]byte) diff --git a/vendor/github.com/ethereum/go-ethereum/trie/sync.go b/vendor/github.com/ethereum/go-ethereum/trie/sync.go index 67dff5a8..85f1b0f8 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/sync.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/sync.go @@ -72,14 +72,14 @@ func newSyncMemBatch() *syncMemBatch { // unknown trie hashes to retrieve, accepts node data associated with said hashes // and reconstructs the trie step by step until all is done. type Sync struct { - database DatabaseReader // Persistent database to check for existing entries + database ethdb.Reader // Persistent database to check for existing entries membatch *syncMemBatch // Memory buffer to avoid frequent database writes requests map[common.Hash]*request // Pending requests pertaining to a key hash queue *prque.Prque // Priority queue with the pending requests } // NewSync creates a new trie data download scheduler. -func NewSync(root common.Hash, database DatabaseReader, callback LeafCallback) *Sync { +func NewSync(root common.Hash, database ethdb.Reader, callback LeafCallback) *Sync { ts := &Sync{ database: database, membatch: newSyncMemBatch(), @@ -101,7 +101,7 @@ func (s *Sync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callb } key := root.Bytes() blob, _ := s.database.Get(key) - if local, err := decodeNode(key, blob, 0); local != nil && err == nil { + if local, err := decodeNode(key, blob); local != nil && err == nil { return } // Assemble the new sub-trie sync request @@ -157,7 +157,7 @@ func (s *Sync) AddRawEntry(hash common.Hash, depth int, parent common.Hash) { // Missing retrieves the known missing nodes from the trie for retrieval. func (s *Sync) Missing(max int) []common.Hash { - requests := []common.Hash{} + var requests []common.Hash for !s.queue.Empty() && (max == 0 || len(requests) < max) { requests = append(requests, s.queue.PopItem().(common.Hash)) } @@ -187,7 +187,7 @@ func (s *Sync) Process(results []SyncResult) (bool, int, error) { continue } // Decode the node data content and update the request - node, err := decodeNode(item.Hash[:], item.Data, 0) + node, err := decodeNode(item.Hash[:], item.Data) if err != nil { return committed, i, err } @@ -213,7 +213,7 @@ func (s *Sync) Process(results []SyncResult) (bool, int, error) { // Commit flushes the data stored in the internal membatch out to persistent // storage, returning the number of items written and any occurred error. -func (s *Sync) Commit(dbw ethdb.Putter) (int, error) { +func (s *Sync) Commit(dbw ethdb.Writer) (int, error) { // Dump the membatch into a database dbw for i, key := range s.membatch.order { if err := dbw.Put(key[:], s.membatch.batch[key]); err != nil { @@ -254,7 +254,7 @@ func (s *Sync) children(req *request, object node) ([]*request, error) { node node depth int } - children := []child{} + var children []child switch node := (object).(type) { case *shortNode: diff --git a/vendor/github.com/ethereum/go-ethereum/trie/sync_test.go b/vendor/github.com/ethereum/go-ethereum/trie/sync_test.go index c76779e5..0d8c29cf 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/sync_test.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/sync_test.go @@ -21,13 +21,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" ) // makeTestTrie create a sample test trie to test node-wise reconstruction. func makeTestTrie() (*Database, *Trie, map[string][]byte) { // Create an empty trie - triedb := NewDatabase(ethdb.NewMemDatabase()) + triedb := NewDatabase(memorydb.New()) trie, _ := New(common.Hash{}, triedb) // Fill it with some arbitrary data @@ -88,13 +88,13 @@ func checkTrieConsistency(db *Database, root common.Hash) error { // Tests that an empty trie is not scheduled for syncing. func TestEmptySync(t *testing.T) { - dbA := NewDatabase(ethdb.NewMemDatabase()) - dbB := NewDatabase(ethdb.NewMemDatabase()) + dbA := NewDatabase(memorydb.New()) + dbB := NewDatabase(memorydb.New()) emptyA, _ := New(common.Hash{}, dbA) emptyB, _ := New(emptyRoot, dbB) for i, trie := range []*Trie{emptyA, emptyB} { - if req := NewSync(trie.Hash(), ethdb.NewMemDatabase(), nil).Missing(1); len(req) != 0 { + if req := NewSync(trie.Hash(), memorydb.New(), nil).Missing(1); len(req) != 0 { t.Errorf("test %d: content requested for empty trie: %v", i, req) } } @@ -110,7 +110,7 @@ func testIterativeSync(t *testing.T, batch int) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) @@ -133,7 +133,7 @@ func testIterativeSync(t *testing.T, batch int) { queue = append(queue[:0], sched.Missing(batch)...) } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only @@ -143,7 +143,7 @@ func TestIterativeDelayedSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) @@ -167,7 +167,7 @@ func TestIterativeDelayedSync(t *testing.T) { queue = append(queue[len(results):], sched.Missing(10000)...) } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that given a root hash, a trie can sync iteratively on a single thread, @@ -181,7 +181,7 @@ func testIterativeRandomSync(t *testing.T, batch int) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) @@ -212,7 +212,7 @@ func testIterativeRandomSync(t *testing.T, batch int) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only @@ -222,7 +222,7 @@ func TestIterativeRandomDelayedSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) @@ -259,7 +259,7 @@ func TestIterativeRandomDelayedSync(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that a trie sync will not request nodes multiple times, even if they @@ -269,7 +269,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) @@ -299,7 +299,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) { queue = append(queue[:0], sched.Missing(0)...) } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) } // Tests that at any point in time during a sync, only complete sub-tries are in @@ -309,11 +309,11 @@ func TestIncompleteSync(t *testing.T) { srcDb, srcTrie, _ := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - added := []common.Hash{} + var added []common.Hash queue := append([]common.Hash{}, sched.Missing(1)...) for len(queue) > 0 { // Fetch a batch of trie nodes diff --git a/vendor/github.com/ethereum/go-ethereum/trie/trie.go b/vendor/github.com/ethereum/go-ethereum/trie/trie.go index af424d4a..920e331f 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/trie.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/trie.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" ) var ( @@ -35,25 +34,6 @@ var ( emptyState = crypto.Keccak256Hash(nil) ) -var ( - cacheMissCounter = metrics.NewRegisteredCounter("trie/cachemiss", nil) - cacheUnloadCounter = metrics.NewRegisteredCounter("trie/cacheunload", nil) -) - -// CacheMisses retrieves a global counter measuring the number of cache misses -// the trie had since process startup. This isn't useful for anything apart from -// trie debugging purposes. -func CacheMisses() int64 { - return cacheMissCounter.Count() -} - -// CacheUnloads retrieves a global counter measuring the number of cache unloads -// the trie did since process startup. This isn't useful for anything apart from -// trie debugging purposes. -func CacheUnloads() int64 { - return cacheUnloadCounter.Count() -} - // LeafCallback is a callback type invoked when a trie operation reaches a leaf // node. It's used by state sync and commit to allow handling external references // between account and storage tries. @@ -67,23 +47,11 @@ type LeafCallback func(leaf []byte, parent common.Hash) error type Trie struct { db *Database root node - - // Cache generation values. - // cachegen increases by one with each commit operation. - // new nodes are tagged with the current generation and unloaded - // when their generation is older than than cachegen-cachelimit. - cachegen, cachelimit uint16 -} - -// SetCacheLimit sets the number of 'cache generations' to keep. -// A cache generation is created by a call to Commit. -func (t *Trie) SetCacheLimit(l uint16) { - t.cachelimit = l } // newFlag returns the cache flag value for a newly created node. func (t *Trie) newFlag() nodeFlag { - return nodeFlag{dirty: true, gen: t.cachegen} + return nodeFlag{dirty: true} } // New creates a trie with an existing root node from db. @@ -152,14 +120,12 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode if err == nil && didResolve { n = n.copy() n.Val = newnode - n.flags.gen = t.cachegen } return value, n, didResolve, err case *fullNode: value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1) if err == nil && didResolve { n = n.copy() - n.flags.gen = t.cachegen n.Children[key[pos]] = newnode } return value, n, didResolve, err @@ -428,19 +394,13 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) { } func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { - cacheMissCounter.Inc(1) - hash := common.BytesToHash(n) - if node := t.db.node(hash, t.cachegen); node != nil { + if node := t.db.node(hash); node != nil { return node, nil } return nil, &MissingNodeError{NodeHash: hash, Path: prefix} } -// Root returns the root hash of the trie. -// Deprecated: use Hash instead. -func (t *Trie) Root() []byte { return t.Hash().Bytes() } - // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash { @@ -460,7 +420,6 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) { return common.Hash{}, err } t.root = cached - t.cachegen++ return common.BytesToHash(hash.(hashNode)), nil } @@ -468,7 +427,7 @@ func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (node, node, error) { if t.root == nil { return hashNode(emptyRoot.Bytes()), nil, nil } - h := newHasher(t.cachegen, t.cachelimit, onleaf) + h := newHasher(onleaf) defer returnHasherToPool(h) return h.hash(t.root, db, true) } diff --git a/vendor/github.com/ethereum/go-ethereum/trie/trie_test.go b/vendor/github.com/ethereum/go-ethereum/trie/trie_test.go index f8e5fd12..ea0b3cbd 100644 --- a/vendor/github.com/ethereum/go-ethereum/trie/trie_test.go +++ b/vendor/github.com/ethereum/go-ethereum/trie/trie_test.go @@ -19,7 +19,6 @@ package trie import ( "bytes" "encoding/binary" - "errors" "fmt" "io/ioutil" "math/big" @@ -33,6 +32,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/leveldb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/rlp" ) @@ -43,7 +44,7 @@ func init() { // Used for testing func newEmpty() *Trie { - trie, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) + trie, _ := New(common.Hash{}, NewDatabase(memorydb.New())) return trie } @@ -67,7 +68,7 @@ func TestNull(t *testing.T) { } func TestMissingRoot(t *testing.T) { - trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(ethdb.NewMemDatabase())) + trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(memorydb.New())) if trie != nil { t.Error("New returned non-nil trie for invalid root") } @@ -80,7 +81,7 @@ func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } func testMissingNode(t *testing.T, memonly bool) { - diskdb := ethdb.NewMemDatabase() + diskdb := memorydb.New() triedb := NewDatabase(diskdb) trie, _ := New(common.Hash{}, triedb) @@ -119,7 +120,7 @@ func testMissingNode(t *testing.T, memonly bool) { hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") if memonly { - delete(triedb.nodes, hash) + delete(triedb.dirties, hash) } else { diskdb.Delete(hash[:]) } @@ -317,44 +318,13 @@ func TestLargeValue(t *testing.T) { } type countingDB struct { - ethdb.Database + ethdb.KeyValueStore gets map[string]int } func (db *countingDB) Get(key []byte) ([]byte, error) { db.gets[string(key)]++ - return db.Database.Get(key) -} - -// TestCacheUnload checks that decoded nodes are unloaded after a -// certain number of commit operations. -func TestCacheUnload(t *testing.T) { - // Create test trie with two branches. - trie := newEmpty() - key1 := "---------------------------------" - key2 := "---some other branch" - updateString(trie, key1, "this is the branch of key1.") - updateString(trie, key2, "this is the branch of key2.") - - root, _ := trie.Commit(nil) - trie.db.Commit(root, true) - - // Commit the trie repeatedly and access key1. - // The branch containing it is loaded from DB exactly two times: - // in the 0th and 6th iteration. - db := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)} - trie, _ = New(root, NewDatabase(db)) - trie.SetCacheLimit(5) - for i := 0; i < 12; i++ { - getString(trie, key1) - trie.Commit(nil) - } - // Check that it got loaded two times. - for dbkey, count := range db.gets { - if count != 2 { - t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2) - } - } + return db.KeyValueStore.Get(key) } // randTest performs random trie operations. @@ -376,7 +346,6 @@ const ( opHash opReset opItercheckhash - opCheckCacheInvariant opMax // boundary value, not an actual op ) @@ -411,7 +380,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { } func runRandTest(rt randTest) bool { - triedb := NewDatabase(ethdb.NewMemDatabase()) + triedb := NewDatabase(memorydb.New()) tr, _ := New(common.Hash{}, triedb) values := make(map[string]string) // tracks content of the trie @@ -455,8 +424,6 @@ func runRandTest(rt randTest) bool { if tr.Hash() != checktr.Hash() { rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") } - case opCheckCacheInvariant: - rt[i].err = checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0) } // Abort the test on error. if rt[i].err != nil { @@ -466,40 +433,6 @@ func runRandTest(rt randTest) bool { return true } -func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error { - var children []node - var flag nodeFlag - switch n := n.(type) { - case *shortNode: - flag = n.flags - children = []node{n.Val} - case *fullNode: - flag = n.flags - children = n.Children[:] - default: - return nil - } - - errorf := func(format string, args ...interface{}) error { - msg := fmt.Sprintf(format, args...) - msg += fmt.Sprintf("\nat depth %d node %s", depth, spew.Sdump(n)) - msg += fmt.Sprintf("parent: %s", spew.Sdump(parent)) - return errors.New(msg) - } - if flag.gen > parentCachegen { - return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) - } - if depth > 0 && !parentDirty && flag.dirty { - return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) - } - for _, child := range children { - if err := checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1); err != nil { - return err - } - } - return nil -} - func TestRandom(t *testing.T) { if err := quick.Check(runRandTest, nil); err != nil { if cerr, ok := err.(*quick.CheckError); ok { @@ -539,7 +472,7 @@ func benchGet(b *testing.B, commit bool) { b.StopTimer() if commit { - ldb := trie.db.diskdb.(*ethdb.LDBDatabase) + ldb := trie.db.diskdb.(*leveldb.Database) ldb.Close() os.RemoveAll(ldb.Path()) } @@ -595,7 +528,7 @@ func tempDB() (string, *Database) { if err != nil { panic(fmt.Sprintf("can't create temporary directory: %v", err)) } - diskdb, err := ethdb.NewLDBDatabase(dir, 256, 0) + diskdb, err := leveldb.New(dir, 256, 0, "") if err != nil { panic(fmt.Sprintf("can't create temporary database: %v", err)) } @@ -613,3 +546,16 @@ func updateString(trie *Trie, k, v string) { func deleteString(trie *Trie, k string) { trie.Delete([]byte(k)) } + +func TestDecodeNode(t *testing.T) { + t.Parallel() + var ( + hash = make([]byte, 20) + elems = make([]byte, 20) + ) + for i := 0; i < 5000000; i++ { + rand.Read(hash) + rand.Read(elems) + decodeNode(hash, elems) + } +} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/mailserver/mailserver.go b/vendor/github.com/ethereum/go-ethereum/whisper/mailserver/mailserver.go index af9418d9..d7af4baa 100644 --- a/vendor/github.com/ethereum/go-ethereum/whisper/mailserver/mailserver.go +++ b/vendor/github.com/ethereum/go-ethereum/whisper/mailserver/mailserver.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +// Package mailserver provides a naive, example mailserver implementation package mailserver import ( @@ -26,9 +27,11 @@ import ( "github.com/ethereum/go-ethereum/rlp" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/opt" "github.com/syndtr/goleveldb/leveldb/util" ) +// WMailServer represents the state data of the mailserver. type WMailServer struct { db *leveldb.DB w *whisper.Whisper @@ -42,6 +45,8 @@ type DBKey struct { raw []byte } +// NewDbKey is a helper function that creates a levelDB +// key from a hash and an integer. func NewDbKey(t uint32, h common.Hash) *DBKey { const sz = common.HashLength + 4 var k DBKey @@ -53,6 +58,7 @@ func NewDbKey(t uint32, h common.Hash) *DBKey { return &k } +// Init initializes the mail server. func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) error { var err error if len(path) == 0 { @@ -63,7 +69,7 @@ func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, p return fmt.Errorf("password is not specified") } - s.db, err = leveldb.OpenFile(path, nil) + s.db, err = leveldb.OpenFile(path, &opt.Options{OpenFilesCacheCapacity: 32}) if err != nil { return fmt.Errorf("open DB file: %s", err) } @@ -82,12 +88,14 @@ func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, p return nil } +// Close cleans up before shutdown. func (s *WMailServer) Close() { if s.db != nil { s.db.Close() } } +// Archive stores the func (s *WMailServer) Archive(env *whisper.Envelope) { key := NewDbKey(env.Expiry-env.TTL, env.Hash()) rawEnvelope, err := rlp.EncodeToBytes(env) @@ -101,6 +109,8 @@ func (s *WMailServer) Archive(env *whisper.Envelope) { } } +// DeliverMail responds with saved messages upon request by the +// messages' owner. func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) { if peer == nil { log.Error("Whisper peer is nil") diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/api.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/api.go deleted file mode 100644 index 7d963df8..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/api.go +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "context" - "crypto/ecdsa" - "errors" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/rpc" -) - -var ( - ErrSymAsym = errors.New("specify either a symmetric or an asymmetric key") - ErrInvalidSymmetricKey = errors.New("invalid symmetric key") - ErrInvalidPublicKey = errors.New("invalid public key") - ErrInvalidSigningPubKey = errors.New("invalid signing public key") - ErrTooLowPoW = errors.New("message rejected, PoW too low") - ErrNoTopics = errors.New("missing topic(s)") -) - -// PublicWhisperAPI provides the whisper RPC service that can be -// use publicly without security implications. -type PublicWhisperAPI struct { - w *Whisper - - mu sync.Mutex - lastUsed map[string]time.Time // keeps track when a filter was polled for the last time. -} - -// NewPublicWhisperAPI create a new RPC whisper service. -func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI { - api := &PublicWhisperAPI{ - w: w, - lastUsed: make(map[string]time.Time), - } - return api -} - -// Version returns the Whisper sub-protocol version. -func (api *PublicWhisperAPI) Version(ctx context.Context) string { - return ProtocolVersionStr -} - -// Info contains diagnostic information. -type Info struct { - Memory int `json:"memory"` // Memory size of the floating messages in bytes. - Messages int `json:"messages"` // Number of floating messages. - MinPow float64 `json:"minPow"` // Minimal accepted PoW - MaxMessageSize uint32 `json:"maxMessageSize"` // Maximum accepted message size -} - -// Info returns diagnostic information about the whisper node. -func (api *PublicWhisperAPI) Info(ctx context.Context) Info { - stats := api.w.Stats() - return Info{ - Memory: stats.memoryUsed, - Messages: len(api.w.messageQueue) + len(api.w.p2pMsgQueue), - MinPow: api.w.MinPow(), - MaxMessageSize: api.w.MaxMessageSize(), - } -} - -// SetMaxMessageSize sets the maximum message size that is accepted. -// Upper limit is defined in whisperv5.MaxMessageSize. -func (api *PublicWhisperAPI) SetMaxMessageSize(ctx context.Context, size uint32) (bool, error) { - return true, api.w.SetMaxMessageSize(size) -} - -// SetMinPoW sets the minimum PoW for a message before it is accepted. -func (api *PublicWhisperAPI) SetMinPoW(ctx context.Context, pow float64) (bool, error) { - return true, api.w.SetMinimumPoW(pow) -} - -// MarkTrustedPeer marks a peer trusted. , which will allow it to send historic (expired) messages. -// Note: This function is not adding new nodes, the node needs to exists as a peer. -func (api *PublicWhisperAPI) MarkTrustedPeer(ctx context.Context, url string) (bool, error) { - n, err := enode.ParseV4(url) - if err != nil { - return false, err - } - return true, api.w.AllowP2PMessagesFromPeer(n.ID().Bytes()) -} - -// NewKeyPair generates a new public and private key pair for message decryption and encryption. -// It returns an ID that can be used to refer to the keypair. -func (api *PublicWhisperAPI) NewKeyPair(ctx context.Context) (string, error) { - return api.w.NewKeyPair() -} - -// AddPrivateKey imports the given private key. -func (api *PublicWhisperAPI) AddPrivateKey(ctx context.Context, privateKey hexutil.Bytes) (string, error) { - key, err := crypto.ToECDSA(privateKey) - if err != nil { - return "", err - } - return api.w.AddKeyPair(key) -} - -// DeleteKeyPair removes the key with the given key if it exists. -func (api *PublicWhisperAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) { - if ok := api.w.DeleteKeyPair(key); ok { - return true, nil - } - return false, fmt.Errorf("key pair %s not found", key) -} - -// HasKeyPair returns an indication if the node has a key pair that is associated with the given id. -func (api *PublicWhisperAPI) HasKeyPair(ctx context.Context, id string) bool { - return api.w.HasKeyPair(id) -} - -// GetPublicKey returns the public key associated with the given key. The key is the hex -// encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. -func (api *PublicWhisperAPI) GetPublicKey(ctx context.Context, id string) (hexutil.Bytes, error) { - key, err := api.w.GetPrivateKey(id) - if err != nil { - return hexutil.Bytes{}, err - } - return crypto.FromECDSAPub(&key.PublicKey), nil -} - -// GetPrivateKey returns the private key associated with the given key. The key is the hex -// encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. -func (api *PublicWhisperAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error) { - key, err := api.w.GetPrivateKey(id) - if err != nil { - return hexutil.Bytes{}, err - } - return crypto.FromECDSA(key), nil -} - -// NewSymKey generate a random symmetric key. -// It returns an ID that can be used to refer to the key. -// Can be used encrypting and decrypting messages where the key is known to both parties. -func (api *PublicWhisperAPI) NewSymKey(ctx context.Context) (string, error) { - return api.w.GenerateSymKey() -} - -// AddSymKey import a symmetric key. -// It returns an ID that can be used to refer to the key. -// Can be used encrypting and decrypting messages where the key is known to both parties. -func (api *PublicWhisperAPI) AddSymKey(ctx context.Context, key hexutil.Bytes) (string, error) { - return api.w.AddSymKeyDirect([]byte(key)) -} - -// GenerateSymKeyFromPassword derive a key from the given password, stores it, and returns its ID. -func (api *PublicWhisperAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) { - return api.w.AddSymKeyFromPassword(passwd) -} - -// HasSymKey returns an indication if the node has a symmetric key associated with the given key. -func (api *PublicWhisperAPI) HasSymKey(ctx context.Context, id string) bool { - return api.w.HasSymKey(id) -} - -// GetSymKey returns the symmetric key associated with the given id. -func (api *PublicWhisperAPI) GetSymKey(ctx context.Context, id string) (hexutil.Bytes, error) { - return api.w.GetSymKey(id) -} - -// DeleteSymKey deletes the symmetric key that is associated with the given id. -func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool { - return api.w.DeleteSymKey(id) -} - -//go:generate gencodec -type NewMessage -field-override newMessageOverride -out gen_newmessage_json.go - -// NewMessage represents a new whisper message that is posted through the RPC. -type NewMessage struct { - SymKeyID string `json:"symKeyID"` - PublicKey []byte `json:"pubKey"` - Sig string `json:"sig"` - TTL uint32 `json:"ttl"` - Topic TopicType `json:"topic"` - Payload []byte `json:"payload"` - Padding []byte `json:"padding"` - PowTime uint32 `json:"powTime"` - PowTarget float64 `json:"powTarget"` - TargetPeer string `json:"targetPeer"` -} - -type newMessageOverride struct { - PublicKey hexutil.Bytes - Payload hexutil.Bytes - Padding hexutil.Bytes -} - -// Post a message on the Whisper network. -func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error) { - var ( - symKeyGiven = len(req.SymKeyID) > 0 - pubKeyGiven = len(req.PublicKey) > 0 - err error - ) - - // user must specify either a symmetric or an asymmetric key - if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) { - return false, ErrSymAsym - } - - params := &MessageParams{ - TTL: req.TTL, - Payload: req.Payload, - Padding: req.Padding, - WorkTime: req.PowTime, - PoW: req.PowTarget, - Topic: req.Topic, - } - - // Set key that is used to sign the message - if len(req.Sig) > 0 { - if params.Src, err = api.w.GetPrivateKey(req.Sig); err != nil { - return false, err - } - } - - // Set symmetric key that is used to encrypt the message - if symKeyGiven { - if params.Topic == (TopicType{}) { // topics are mandatory with symmetric encryption - return false, ErrNoTopics - } - if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil { - return false, err - } - if !validateSymmetricKey(params.KeySym) { - return false, ErrInvalidSymmetricKey - } - } - - // Set asymmetric key that is used to encrypt the message - if pubKeyGiven { - if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil { - return false, ErrInvalidPublicKey - } - } - - // encrypt and sent message - whisperMsg, err := NewSentMessage(params) - if err != nil { - return false, err - } - - env, err := whisperMsg.Wrap(params) - if err != nil { - return false, err - } - - // send to specific node (skip PoW check) - if len(req.TargetPeer) > 0 { - n, err := enode.ParseV4(req.TargetPeer) - if err != nil { - return false, fmt.Errorf("failed to parse target peer: %s", err) - } - return true, api.w.SendP2PMessage(n.ID().Bytes(), env) - } - - // ensure that the message PoW meets the node's minimum accepted PoW - if req.PowTarget < api.w.MinPow() { - return false, ErrTooLowPoW - } - - return true, api.w.Send(env) -} - -//go:generate gencodec -type Criteria -field-override criteriaOverride -out gen_criteria_json.go - -// Criteria holds various filter options for inbound messages. -type Criteria struct { - SymKeyID string `json:"symKeyID"` - PrivateKeyID string `json:"privateKeyID"` - Sig []byte `json:"sig"` - MinPow float64 `json:"minPow"` - Topics []TopicType `json:"topics"` - AllowP2P bool `json:"allowP2P"` -} - -type criteriaOverride struct { - Sig hexutil.Bytes -} - -// Messages set up a subscription that fires events when messages arrive that match -// the given set of criteria. -func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.Subscription, error) { - var ( - symKeyGiven = len(crit.SymKeyID) > 0 - pubKeyGiven = len(crit.PrivateKeyID) > 0 - err error - ) - - // ensure that the RPC connection supports subscriptions - notifier, supported := rpc.NotifierFromContext(ctx) - if !supported { - return nil, rpc.ErrNotificationsUnsupported - } - - // user must specify either a symmetric or an asymmetric key - if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) { - return nil, ErrSymAsym - } - - filter := Filter{ - PoW: crit.MinPow, - Messages: make(map[common.Hash]*ReceivedMessage), - AllowP2P: crit.AllowP2P, - } - - if len(crit.Sig) > 0 { - if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil { - return nil, ErrInvalidSigningPubKey - } - } - - for i, bt := range crit.Topics { - if len(bt) == 0 || len(bt) > 4 { - return nil, fmt.Errorf("subscribe: topic %d has wrong size: %d", i, len(bt)) - } - filter.Topics = append(filter.Topics, bt[:]) - } - - // listen for message that are encrypted with the given symmetric key - if symKeyGiven { - if len(filter.Topics) == 0 { - return nil, ErrNoTopics - } - key, err := api.w.GetSymKey(crit.SymKeyID) - if err != nil { - return nil, err - } - if !validateSymmetricKey(key) { - return nil, ErrInvalidSymmetricKey - } - filter.KeySym = key - filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym) - } - - // listen for messages that are encrypted with the given public key - if pubKeyGiven { - filter.KeyAsym, err = api.w.GetPrivateKey(crit.PrivateKeyID) - if err != nil || filter.KeyAsym == nil { - return nil, ErrInvalidPublicKey - } - } - - id, err := api.w.Subscribe(&filter) - if err != nil { - return nil, err - } - - // create subscription and start waiting for message events - rpcSub := notifier.CreateSubscription() - go func() { - // for now poll internally, refactor whisper internal for channel support - ticker := time.NewTicker(250 * time.Millisecond) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - if filter := api.w.GetFilter(id); filter != nil { - for _, rpcMessage := range toMessage(filter.Retrieve()) { - if err := notifier.Notify(rpcSub.ID, rpcMessage); err != nil { - log.Error("Failed to send notification", "err", err) - } - } - } - case <-rpcSub.Err(): - api.w.Unsubscribe(id) - return - case <-notifier.Closed(): - api.w.Unsubscribe(id) - return - } - } - }() - - return rpcSub, nil -} - -//go:generate gencodec -type Message -field-override messageOverride -out gen_message_json.go - -// Message is the RPC representation of a whisper message. -type Message struct { - Sig []byte `json:"sig,omitempty"` - TTL uint32 `json:"ttl"` - Timestamp uint32 `json:"timestamp"` - Topic TopicType `json:"topic"` - Payload []byte `json:"payload"` - Padding []byte `json:"padding"` - PoW float64 `json:"pow"` - Hash []byte `json:"hash"` - Dst []byte `json:"recipientPublicKey,omitempty"` -} - -type messageOverride struct { - Sig hexutil.Bytes - Payload hexutil.Bytes - Padding hexutil.Bytes - Hash hexutil.Bytes - Dst hexutil.Bytes -} - -// ToWhisperMessage converts an internal message into an API version. -func ToWhisperMessage(message *ReceivedMessage) *Message { - msg := Message{ - Payload: message.Payload, - Padding: message.Padding, - Timestamp: message.Sent, - TTL: message.TTL, - PoW: message.PoW, - Hash: message.EnvelopeHash.Bytes(), - Topic: message.Topic, - } - - if message.Dst != nil { - b := crypto.FromECDSAPub(message.Dst) - if b != nil { - msg.Dst = b - } - } - - if isMessageSigned(message.Raw[0]) { - b := crypto.FromECDSAPub(message.SigToPubKey()) - if b != nil { - msg.Sig = b - } - } - - return &msg -} - -// toMessage converts a set of messages to its RPC representation. -func toMessage(messages []*ReceivedMessage) []*Message { - msgs := make([]*Message, len(messages)) - for i, msg := range messages { - msgs[i] = ToWhisperMessage(msg) - } - return msgs -} - -// GetFilterMessages returns the messages that match the filter criteria and -// are received between the last poll and now. -func (api *PublicWhisperAPI) GetFilterMessages(id string) ([]*Message, error) { - api.mu.Lock() - f := api.w.GetFilter(id) - if f == nil { - api.mu.Unlock() - return nil, fmt.Errorf("filter not found") - } - api.lastUsed[id] = time.Now() - api.mu.Unlock() - - receivedMessages := f.Retrieve() - messages := make([]*Message, 0, len(receivedMessages)) - for _, msg := range receivedMessages { - messages = append(messages, ToWhisperMessage(msg)) - } - - return messages, nil -} - -// DeleteMessageFilter deletes a filter. -func (api *PublicWhisperAPI) DeleteMessageFilter(id string) (bool, error) { - api.mu.Lock() - defer api.mu.Unlock() - - delete(api.lastUsed, id) - return true, api.w.Unsubscribe(id) -} - -// NewMessageFilter creates a new filter that can be used to poll for -// (new) messages that satisfy the given criteria. -func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) { - var ( - src *ecdsa.PublicKey - keySym []byte - keyAsym *ecdsa.PrivateKey - topics [][]byte - - symKeyGiven = len(req.SymKeyID) > 0 - asymKeyGiven = len(req.PrivateKeyID) > 0 - - err error - ) - - // user must specify either a symmetric or an asymmetric key - if (symKeyGiven && asymKeyGiven) || (!symKeyGiven && !asymKeyGiven) { - return "", ErrSymAsym - } - - if len(req.Sig) > 0 { - if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil { - return "", ErrInvalidSigningPubKey - } - } - - if symKeyGiven { - if keySym, err = api.w.GetSymKey(req.SymKeyID); err != nil { - return "", err - } - if !validateSymmetricKey(keySym) { - return "", ErrInvalidSymmetricKey - } - } - - if asymKeyGiven { - if keyAsym, err = api.w.GetPrivateKey(req.PrivateKeyID); err != nil { - return "", err - } - } - - if len(req.Topics) > 0 { - topics = make([][]byte, 0, len(req.Topics)) - for _, topic := range req.Topics { - topics = append(topics, topic[:]) - } - } - - f := &Filter{ - Src: src, - KeySym: keySym, - KeyAsym: keyAsym, - PoW: req.MinPow, - AllowP2P: req.AllowP2P, - Topics: topics, - Messages: make(map[common.Hash]*ReceivedMessage), - } - - id, err := api.w.Subscribe(f) - if err != nil { - return "", err - } - - api.mu.Lock() - api.lastUsed[id] = time.Now() - api.mu.Unlock() - - return id, nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/benchmarks_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/benchmarks_test.go deleted file mode 100644 index dcfbcb56..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/benchmarks_test.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "testing" - - "github.com/ethereum/go-ethereum/crypto" -) - -func BenchmarkDeriveKeyMaterial(b *testing.B) { - for i := 0; i < b.N; i++ { - deriveKeyMaterial([]byte("test"), 0) - } -} - -func BenchmarkEncryptionSym(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - for i := 0; i < b.N; i++ { - msg, _ := NewSentMessage(params) - _, err := msg.Wrap(params) - if err != nil { - b.Errorf("failed Wrap with seed %d: %s.", seed, err) - b.Errorf("i = %d, len(msg.Raw) = %d, params.Payload = %d.", i, len(msg.Raw), len(params.Payload)) - return - } - } -} - -func BenchmarkEncryptionAsym(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - key, err := crypto.GenerateKey() - if err != nil { - b.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - params.KeySym = nil - params.Dst = &key.PublicKey - - for i := 0; i < b.N; i++ { - msg, _ := NewSentMessage(params) - _, err := msg.Wrap(params) - if err != nil { - b.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - } -} - -func BenchmarkDecryptionSymValid(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) - if err != nil { - b.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - f := Filter{KeySym: params.KeySym} - - for i := 0; i < b.N; i++ { - msg := env.Open(&f) - if msg == nil { - b.Fatalf("failed to open with seed %d.", seed) - } - } -} - -func BenchmarkDecryptionSymInvalid(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) - if err != nil { - b.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - f := Filter{KeySym: []byte("arbitrary stuff here")} - - for i := 0; i < b.N; i++ { - msg := env.Open(&f) - if msg != nil { - b.Fatalf("opened envelope with invalid key, seed: %d.", seed) - } - } -} - -func BenchmarkDecryptionAsymValid(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - key, err := crypto.GenerateKey() - if err != nil { - b.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - f := Filter{KeyAsym: key} - params.KeySym = nil - params.Dst = &key.PublicKey - msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) - if err != nil { - b.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - for i := 0; i < b.N; i++ { - msg := env.Open(&f) - if msg == nil { - b.Fatalf("fail to open, seed: %d.", seed) - } - } -} - -func BenchmarkDecryptionAsymInvalid(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - key, err := crypto.GenerateKey() - if err != nil { - b.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - params.KeySym = nil - params.Dst = &key.PublicKey - msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) - if err != nil { - b.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - key, err = crypto.GenerateKey() - if err != nil { - b.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - f := Filter{KeyAsym: key} - - for i := 0; i < b.N; i++ { - msg := env.Open(&f) - if msg != nil { - b.Fatalf("opened envelope with invalid key, seed: %d.", seed) - } - } -} - -func increment(x []byte) { - for i := 0; i < len(x); i++ { - x[i]++ - if x[i] != 0 { - break - } - } -} - -func BenchmarkPoW(b *testing.B) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - params.Payload = make([]byte, 32) - params.PoW = 10.0 - params.TTL = 1 - - for i := 0; i < b.N; i++ { - increment(params.Payload) - msg, _ := NewSentMessage(params) - _, err := msg.Wrap(params) - if err != nil { - b.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/doc.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/doc.go deleted file mode 100644 index 8161db8e..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/doc.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -Package whisperv5 implements the Whisper protocol (version 5). - -Whisper combines aspects of both DHTs and datagram messaging systems (e.g. UDP). -As such it may be likened and compared to both, not dissimilar to the -matter/energy duality (apologies to physicists for the blatant abuse of a -fundamental and beautiful natural principle). - -Whisper is a pure identity-based messaging system. Whisper provides a low-level -(non-application-specific) but easily-accessible API without being based upon -or prejudiced by the low-level hardware attributes and characteristics, -particularly the notion of singular endpoints. -*/ -package whisperv5 - -import ( - "fmt" - "time" -) - -const ( - EnvelopeVersion = uint64(0) - ProtocolVersion = uint64(5) - ProtocolVersionStr = "5.0" - ProtocolName = "shh" - - statusCode = 0 // used by whisper protocol - messagesCode = 1 // normal whisper message - p2pCode = 2 // peer-to-peer message (to be consumed by the peer, but not forwarded any further) - p2pRequestCode = 3 // peer-to-peer message, used by Dapp protocol - NumberOfMessageCodes = 64 - - paddingMask = byte(3) - signatureFlag = byte(4) - - TopicLength = 4 - signatureLength = 65 - aesKeyLength = 32 - AESNonceLength = 12 - keyIdSize = 32 - - MaxMessageSize = uint32(10 * 1024 * 1024) // maximum accepted size of a message. - DefaultMaxMessageSize = uint32(1024 * 1024) - DefaultMinimumPoW = 0.2 - - padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol (must not exceed 2^24) - messageQueueLimit = 1024 - - expirationCycle = time.Second - transmissionCycle = 300 * time.Millisecond - - DefaultTTL = 50 // seconds - SynchAllowance = 10 // seconds -) - -type unknownVersionError uint64 - -func (e unknownVersionError) Error() string { - return fmt.Sprintf("invalid envelope version %d", uint64(e)) -} - -// MailServer represents a mail server, capable of -// archiving the old messages for subsequent delivery -// to the peers. Any implementation must ensure that both -// functions are thread-safe. Also, they must return ASAP. -// DeliverMail should use directMessagesCode for delivery, -// in order to bypass the expiry checks. -type MailServer interface { - Archive(env *Envelope) - DeliverMail(whisperPeer *Peer, request *Envelope) -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/envelope.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/envelope.go deleted file mode 100644 index 169cbba9..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/envelope.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Contains the Whisper protocol Envelope element. - -package whisperv5 - -import ( - "crypto/ecdsa" - "encoding/binary" - "fmt" - gmath "math" - "math/big" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/rlp" -) - -// Envelope represents a clear-text data packet to transmit through the Whisper -// network. Its contents may or may not be encrypted and signed. -type Envelope struct { - Version []byte - Expiry uint32 - TTL uint32 - Topic TopicType - AESNonce []byte - Data []byte - EnvNonce uint64 - - pow float64 // Message-specific PoW as described in the Whisper specification. - hash common.Hash // Cached hash of the envelope to avoid rehashing every time. - // Don't access hash directly, use Hash() function instead. -} - -// size returns the size of envelope as it is sent (i.e. public fields only) -func (e *Envelope) size() int { - return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data) -} - -// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. -func (e *Envelope) rlpWithoutNonce() []byte { - res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data}) - return res -} - -// NewEnvelope wraps a Whisper message with expiration and destination data -// included into an envelope for network forwarding. -func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *sentMessage) *Envelope { - env := Envelope{ - Version: make([]byte, 1), - Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), - TTL: ttl, - Topic: topic, - AESNonce: aesNonce, - Data: msg.Raw, - EnvNonce: 0, - } - - if EnvelopeVersion < 256 { - env.Version[0] = byte(EnvelopeVersion) - } else { - panic("please increase the size of Envelope.Version before releasing this version") - } - - return &env -} - -func (e *Envelope) IsSymmetric() bool { - return len(e.AESNonce) > 0 -} - -func (e *Envelope) isAsymmetric() bool { - return !e.IsSymmetric() -} - -func (e *Envelope) Ver() uint64 { - return bytesToUintLittleEndian(e.Version) -} - -// Seal closes the envelope by spending the requested amount of time as a proof -// of work on hashing the data. -func (e *Envelope) Seal(options *MessageParams) error { - var target, bestBit int - if options.PoW == 0 { - // adjust for the duration of Seal() execution only if execution time is predefined unconditionally - e.Expiry += options.WorkTime - } else { - target = e.powToFirstBit(options.PoW) - if target < 1 { - target = 1 - } - } - - buf := make([]byte, 64) - h := crypto.Keccak256(e.rlpWithoutNonce()) - copy(buf[:32], h) - - finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() - for nonce := uint64(0); time.Now().UnixNano() < finish; { - for i := 0; i < 1024; i++ { - binary.BigEndian.PutUint64(buf[56:], nonce) - d := new(big.Int).SetBytes(crypto.Keccak256(buf)) - firstBit := math.FirstBitSet(d) - if firstBit > bestBit { - e.EnvNonce, bestBit = nonce, firstBit - if target > 0 && bestBit >= target { - return nil - } - } - nonce++ - } - } - - if target > 0 && bestBit < target { - return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) - } - - return nil -} - -func (e *Envelope) PoW() float64 { - if e.pow == 0 { - e.calculatePoW(0) - } - return e.pow -} - -func (e *Envelope) calculatePoW(diff uint32) { - buf := make([]byte, 64) - h := crypto.Keccak256(e.rlpWithoutNonce()) - copy(buf[:32], h) - binary.BigEndian.PutUint64(buf[56:], e.EnvNonce) - d := new(big.Int).SetBytes(crypto.Keccak256(buf)) - firstBit := math.FirstBitSet(d) - x := gmath.Pow(2, float64(firstBit)) - x /= float64(e.size()) - x /= float64(e.TTL + diff) - e.pow = x -} - -func (e *Envelope) powToFirstBit(pow float64) int { - x := pow - x *= float64(e.size()) - x *= float64(e.TTL) - bits := gmath.Log2(x) - bits = gmath.Ceil(bits) - return int(bits) -} - -// Hash returns the SHA3 hash of the envelope, calculating it if not yet done. -func (e *Envelope) Hash() common.Hash { - if (e.hash == common.Hash{}) { - encoded, _ := rlp.EncodeToBytes(e) - e.hash = crypto.Keccak256Hash(encoded) - } - return e.hash -} - -// DecodeRLP decodes an Envelope from an RLP data stream. -func (e *Envelope) DecodeRLP(s *rlp.Stream) error { - raw, err := s.Raw() - if err != nil { - return err - } - // The decoding of Envelope uses the struct fields but also needs - // to compute the hash of the whole RLP-encoded envelope. This - // type has the same structure as Envelope but is not an - // rlp.Decoder (does not implement DecodeRLP function). - // Only public members will be encoded. - type rlpenv Envelope - if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { - return err - } - e.hash = crypto.Keccak256Hash(raw) - return nil -} - -// OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key. -func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { - message := &ReceivedMessage{Raw: e.Data} - err := message.decryptAsymmetric(key) - switch err { - case nil: - return message, nil - case ecies.ErrInvalidPublicKey: // addressed to somebody else - return nil, err - default: - return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) - } -} - -// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key. -func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { - msg = &ReceivedMessage{Raw: e.Data} - err = msg.decryptSymmetric(key, e.AESNonce) - if err != nil { - msg = nil - } - return msg, err -} - -// Open tries to decrypt an envelope, and populates the message fields in case of success. -func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { - if e.isAsymmetric() { - msg, _ = e.OpenAsymmetric(watcher.KeyAsym) - if msg != nil { - msg.Dst = &watcher.KeyAsym.PublicKey - } - } else if e.IsSymmetric() { - msg, _ = e.OpenSymmetric(watcher.KeySym) - if msg != nil { - msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) - } - } - - if msg != nil { - ok := msg.Validate() - if !ok { - return nil - } - msg.Topic = e.Topic - msg.PoW = e.PoW() - msg.TTL = e.TTL - msg.Sent = e.Expiry - e.TTL - msg.EnvelopeHash = e.Hash() - msg.EnvelopeVersion = e.Ver() - } - return msg -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/filter.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/filter.go deleted file mode 100644 index 9550a7e3..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/filter.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "crypto/ecdsa" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" -) - -type Filter struct { - Src *ecdsa.PublicKey // Sender of the message - KeyAsym *ecdsa.PrivateKey // Private Key of recipient - KeySym []byte // Key associated with the Topic - Topics [][]byte // Topics to filter messages with - PoW float64 // Proof of work as described in the Whisper spec - AllowP2P bool // Indicates whether this filter is interested in direct peer-to-peer messages - SymKeyHash common.Hash // The Keccak256Hash of the symmetric key, needed for optimization - - Messages map[common.Hash]*ReceivedMessage - mutex sync.RWMutex -} - -type Filters struct { - watchers map[string]*Filter - whisper *Whisper - mutex sync.RWMutex -} - -func NewFilters(w *Whisper) *Filters { - return &Filters{ - watchers: make(map[string]*Filter), - whisper: w, - } -} - -func (fs *Filters) Install(watcher *Filter) (string, error) { - if watcher.Messages == nil { - watcher.Messages = make(map[common.Hash]*ReceivedMessage) - } - - id, err := GenerateRandomID() - if err != nil { - return "", err - } - - fs.mutex.Lock() - defer fs.mutex.Unlock() - - if fs.watchers[id] != nil { - return "", fmt.Errorf("failed to generate unique ID") - } - - if watcher.expectsSymmetricEncryption() { - watcher.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) - } - - fs.watchers[id] = watcher - return id, err -} - -func (fs *Filters) Uninstall(id string) bool { - fs.mutex.Lock() - defer fs.mutex.Unlock() - if fs.watchers[id] != nil { - delete(fs.watchers, id) - return true - } - return false -} - -func (fs *Filters) Get(id string) *Filter { - fs.mutex.RLock() - defer fs.mutex.RUnlock() - return fs.watchers[id] -} - -func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { - var msg *ReceivedMessage - - fs.mutex.RLock() - defer fs.mutex.RUnlock() - - i := -1 // only used for logging info - for _, watcher := range fs.watchers { - i++ - if p2pMessage && !watcher.AllowP2P { - log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), i)) - continue - } - - var match bool - if msg != nil { - match = watcher.MatchMessage(msg) - } else { - match = watcher.MatchEnvelope(env) - if match { - msg = env.Open(watcher) - if msg == nil { - log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", i) - } - } else { - log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", i) - } - } - - if match && msg != nil { - log.Trace("processing message: decrypted", "hash", env.Hash().Hex()) - if watcher.Src == nil || IsPubKeyEqual(msg.Src, watcher.Src) { - watcher.Trigger(msg) - } - } - } -} - -func (f *Filter) processEnvelope(env *Envelope) *ReceivedMessage { - if f.MatchEnvelope(env) { - msg := env.Open(f) - if msg != nil { - return msg - } else { - log.Trace("processing envelope: failed to open", "hash", env.Hash().Hex()) - } - } else { - log.Trace("processing envelope: does not match", "hash", env.Hash().Hex()) - } - return nil -} - -func (f *Filter) expectsAsymmetricEncryption() bool { - return f.KeyAsym != nil -} - -func (f *Filter) expectsSymmetricEncryption() bool { - return f.KeySym != nil -} - -func (f *Filter) Trigger(msg *ReceivedMessage) { - f.mutex.Lock() - defer f.mutex.Unlock() - - if _, exist := f.Messages[msg.EnvelopeHash]; !exist { - f.Messages[msg.EnvelopeHash] = msg - } -} - -func (f *Filter) Retrieve() (all []*ReceivedMessage) { - f.mutex.Lock() - defer f.mutex.Unlock() - - all = make([]*ReceivedMessage, 0, len(f.Messages)) - for _, msg := range f.Messages { - all = append(all, msg) - } - - f.Messages = make(map[common.Hash]*ReceivedMessage) // delete old messages - return all -} - -func (f *Filter) MatchMessage(msg *ReceivedMessage) bool { - if f.PoW > 0 && msg.PoW < f.PoW { - return false - } - - if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() { - return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic) - } else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() { - return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic) - } - return false -} - -func (f *Filter) MatchEnvelope(envelope *Envelope) bool { - if f.PoW > 0 && envelope.pow < f.PoW { - return false - } - - if f.expectsAsymmetricEncryption() && envelope.isAsymmetric() { - return f.MatchTopic(envelope.Topic) - } else if f.expectsSymmetricEncryption() && envelope.IsSymmetric() { - return f.MatchTopic(envelope.Topic) - } - return false -} - -func (f *Filter) MatchTopic(topic TopicType) bool { - if len(f.Topics) == 0 { - // any topic matches - return true - } - - for _, bt := range f.Topics { - if matchSingleTopic(topic, bt) { - return true - } - } - return false -} - -func matchSingleTopic(topic TopicType, bt []byte) bool { - if len(bt) > TopicLength { - bt = bt[:TopicLength] - } - - if len(bt) == 0 { - return false - } - - for j, b := range bt { - if topic[j] != b { - return false - } - } - return true -} - -func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool { - if !ValidatePublicKey(a) { - return false - } else if !ValidatePublicKey(b) { - return false - } - // the curve is always the same, just compare the points - return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0 -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/filter_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/filter_test.go deleted file mode 100644 index 33138fb1..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/filter_test.go +++ /dev/null @@ -1,848 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "math/big" - mrand "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -var seed int64 - -// InitSingleTest should be called in the beginning of every -// test, which uses RNG, in order to make the tests -// reproduciblity independent of their sequence. -func InitSingleTest() { - seed = time.Now().Unix() - mrand.Seed(seed) -} - -func InitDebugTest(i int64) { - seed = i - mrand.Seed(seed) -} - -type FilterTestCase struct { - f *Filter - id string - alive bool - msgCnt int -} - -func generateFilter(t *testing.T, symmetric bool) (*Filter, error) { - var f Filter - f.Messages = make(map[common.Hash]*ReceivedMessage) - - const topicNum = 8 - f.Topics = make([][]byte, topicNum) - for i := 0; i < topicNum; i++ { - f.Topics[i] = make([]byte, 4) - mrand.Read(f.Topics[i]) - f.Topics[i][0] = 0x01 - } - - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("generateFilter 1 failed with seed %d.", seed) - return nil, err - } - f.Src = &key.PublicKey - - if symmetric { - f.KeySym = make([]byte, aesKeyLength) - mrand.Read(f.KeySym) - f.SymKeyHash = crypto.Keccak256Hash(f.KeySym) - } else { - f.KeyAsym, err = crypto.GenerateKey() - if err != nil { - t.Fatalf("generateFilter 2 failed with seed %d.", seed) - return nil, err - } - } - - // AcceptP2P & PoW are not set - return &f, nil -} - -func generateTestCases(t *testing.T, SizeTestFilters int) []FilterTestCase { - cases := make([]FilterTestCase, SizeTestFilters) - for i := 0; i < SizeTestFilters; i++ { - f, _ := generateFilter(t, true) - cases[i].f = f - cases[i].alive = mrand.Int()&int(1) == 0 - } - return cases -} - -func TestInstallFilters(t *testing.T) { - InitSingleTest() - - const SizeTestFilters = 256 - w := New(&Config{}) - filters := NewFilters(w) - tst := generateTestCases(t, SizeTestFilters) - - var err error - var j string - for i := 0; i < SizeTestFilters; i++ { - j, err = filters.Install(tst[i].f) - if err != nil { - t.Fatalf("seed %d: failed to install filter: %s", seed, err) - } - tst[i].id = j - if len(j) != keyIdSize*2 { - t.Fatalf("seed %d: wrong filter id size [%d]", seed, len(j)) - } - } - - for _, testCase := range tst { - if !testCase.alive { - filters.Uninstall(testCase.id) - } - } - - for i, testCase := range tst { - fil := filters.Get(testCase.id) - exist := fil != nil - if exist != testCase.alive { - t.Fatalf("seed %d: failed alive: %d, %v, %v", seed, i, exist, testCase.alive) - } - if exist && fil.PoW != testCase.f.PoW { - t.Fatalf("seed %d: failed Get: %d, %v, %v", seed, i, exist, testCase.alive) - } - } -} - -func TestInstallSymKeyGeneratesHash(t *testing.T) { - InitSingleTest() - - w := New(&Config{}) - filters := NewFilters(w) - filter, _ := generateFilter(t, true) - - // save the current SymKeyHash for comparison - initialSymKeyHash := filter.SymKeyHash - - // ensure the SymKeyHash is invalid, for Install to recreate it - var invalid common.Hash - filter.SymKeyHash = invalid - - _, err := filters.Install(filter) - - if err != nil { - t.Fatalf("Error installing the filter: %s", err) - } - - for i, b := range filter.SymKeyHash { - if b != initialSymKeyHash[i] { - t.Fatalf("The filter's symmetric key hash was not properly generated by Install") - } - } -} - -func TestInstallIdenticalFilters(t *testing.T) { - InitSingleTest() - - w := New(&Config{}) - filters := NewFilters(w) - filter1, _ := generateFilter(t, true) - - // Copy the first filter since some of its fields - // are randomly gnerated. - filter2 := &Filter{ - KeySym: filter1.KeySym, - Topics: filter1.Topics, - PoW: filter1.PoW, - AllowP2P: filter1.AllowP2P, - Messages: make(map[common.Hash]*ReceivedMessage), - } - - _, err := filters.Install(filter1) - - if err != nil { - t.Fatalf("Error installing the first filter with seed %d: %s", seed, err) - } - - _, err = filters.Install(filter2) - - if err != nil { - t.Fatalf("Error installing the second filter with seed %d: %s", seed, err) - } - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("Error generating message parameters with seed %d: %s", seed, err) - } - - params.KeySym = filter1.KeySym - params.Topic = BytesToTopic(filter1.Topics[0]) - - filter1.Src = ¶ms.Src.PublicKey - filter2.Src = ¶ms.Src.PublicKey - - sentMessage, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := sentMessage.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - msg := env.Open(filter1) - if msg == nil { - t.Fatalf("failed to Open with filter1") - } - - if !filter1.MatchEnvelope(env) { - t.Fatalf("failed matching with the first filter") - } - - if !filter2.MatchEnvelope(env) { - t.Fatalf("failed matching with the first filter") - } - - if !filter1.MatchMessage(msg) { - t.Fatalf("failed matching with the second filter") - } - - if !filter2.MatchMessage(msg) { - t.Fatalf("failed matching with the second filter") - } -} - -func TestComparePubKey(t *testing.T) { - InitSingleTest() - - key1, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to generate first key with seed %d: %s.", seed, err) - } - key2, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to generate second key with seed %d: %s.", seed, err) - } - if IsPubKeyEqual(&key1.PublicKey, &key2.PublicKey) { - t.Fatalf("public keys are equal, seed %d.", seed) - } - - // generate key3 == key1 - mrand.Seed(seed) - key3, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to generate third key with seed %d: %s.", seed, err) - } - if IsPubKeyEqual(&key1.PublicKey, &key3.PublicKey) { - t.Fatalf("key1 == key3, seed %d.", seed) - } -} - -func TestMatchEnvelope(t *testing.T) { - InitSingleTest() - - fsym, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) - } - - fasym, err := generateFilter(t, false) - if err != nil { - t.Fatalf("failed generateFilter() with seed %d: %s.", seed, err) - } - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - params.Topic[0] = 0xFF // ensure mismatch - - // mismatch with pseudo-random data - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - match := fsym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope symmetric with seed %d.", seed) - } - match = fasym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope asymmetric with seed %d.", seed) - } - - // encrypt symmetrically - i := mrand.Int() % 4 - fsym.Topics[i] = params.Topic[:] - fasym.Topics[i] = params.Topic[:] - msg, err = NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err = msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap() with seed %d: %s.", seed, err) - } - - // symmetric + matching topic: match - match = fsym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope() symmetric with seed %d.", seed) - } - - // asymmetric + matching topic: mismatch - match = fasym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope() asymmetric with seed %d.", seed) - } - - // symmetric + matching topic + insufficient PoW: mismatch - fsym.PoW = env.PoW() + 1.0 - match = fsym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope(symmetric + matching topic + insufficient PoW) asymmetric with seed %d.", seed) - } - - // symmetric + matching topic + sufficient PoW: match - fsym.PoW = env.PoW() / 2 - match = fsym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope(symmetric + matching topic + sufficient PoW) with seed %d.", seed) - } - - // symmetric + topics are nil (wildcard): match - prevTopics := fsym.Topics - fsym.Topics = nil - match = fsym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope(symmetric + topics are nil) with seed %d.", seed) - } - fsym.Topics = prevTopics - - // encrypt asymmetrically - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - params.KeySym = nil - params.Dst = &key.PublicKey - msg, err = NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err = msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap() with seed %d: %s.", seed, err) - } - - // encryption method mismatch - match = fsym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed) - } - - // asymmetric + mismatching topic: mismatch - match = fasym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope(asymmetric + mismatching topic) with seed %d.", seed) - } - - // asymmetric + matching topic: match - fasym.Topics[i] = fasym.Topics[i+1] - match = fasym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope(asymmetric + matching topic) with seed %d.", seed) - } - - // asymmetric + filter without topic (wildcard): match - fasym.Topics = nil - match = fasym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope(asymmetric + filter without topic) with seed %d.", seed) - } - - // asymmetric + insufficient PoW: mismatch - fasym.PoW = env.PoW() + 1.0 - match = fasym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope(asymmetric + insufficient PoW) with seed %d.", seed) - } - - // asymmetric + sufficient PoW: match - fasym.PoW = env.PoW() / 2 - match = fasym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope(asymmetric + sufficient PoW) with seed %d.", seed) - } - - // filter without topic + envelope without topic: match - env.Topic = TopicType{} - match = fasym.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed) - } - - // filter with topic + envelope without topic: mismatch - fasym.Topics = fsym.Topics - match = fasym.MatchEnvelope(env) - if match { - t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed) - } -} - -func TestMatchMessageSym(t *testing.T) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - f, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) - } - - const index = 1 - params.KeySym = f.KeySym - params.Topic = BytesToTopic(f.Topics[index]) - - sentMessage, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := sentMessage.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - msg := env.Open(f) - if msg == nil { - t.Fatalf("failed Open with seed %d.", seed) - } - - // Src: match - *f.Src.X = *params.Src.PublicKey.X - *f.Src.Y = *params.Src.PublicKey.Y - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(src match) with seed %d.", seed) - } - - // insufficient PoW: mismatch - f.PoW = msg.PoW + 1.0 - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed) - } - - // sufficient PoW: match - f.PoW = msg.PoW / 2 - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed) - } - - // topic mismatch - f.Topics[index][0]++ - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed) - } - f.Topics[index][0]-- - - // key mismatch - f.SymKeyHash[0]++ - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed) - } - f.SymKeyHash[0]-- - - // Src absent: match - f.Src = nil - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed) - } - - // key hash mismatch - h := f.SymKeyHash - f.SymKeyHash = common.Hash{} - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(key hash mismatch) with seed %d.", seed) - } - f.SymKeyHash = h - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(key hash match) with seed %d.", seed) - } - - // encryption method mismatch - f.KeySym = nil - f.KeyAsym, err = crypto.GenerateKey() - if err != nil { - t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed) - } -} - -func TestMatchMessageAsym(t *testing.T) { - InitSingleTest() - - f, err := generateFilter(t, false) - if err != nil { - t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) - } - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - const index = 1 - params.Topic = BytesToTopic(f.Topics[index]) - params.Dst = &f.KeyAsym.PublicKey - keySymOrig := params.KeySym - params.KeySym = nil - - sentMessage, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := sentMessage.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - msg := env.Open(f) - if msg == nil { - t.Fatalf("failed to open with seed %d.", seed) - } - - // Src: match - *f.Src.X = *params.Src.PublicKey.X - *f.Src.Y = *params.Src.PublicKey.Y - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchMessage(src match) with seed %d.", seed) - } - - // insufficient PoW: mismatch - f.PoW = msg.PoW + 1.0 - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed) - } - - // sufficient PoW: match - f.PoW = msg.PoW / 2 - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed) - } - - // topic mismatch - f.Topics[index][0]++ - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed) - } - f.Topics[index][0]-- - - // key mismatch - prev := *f.KeyAsym.PublicKey.X - zero := *big.NewInt(0) - *f.KeyAsym.PublicKey.X = zero - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed) - } - *f.KeyAsym.PublicKey.X = prev - - // Src absent: match - f.Src = nil - if !f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed) - } - - // encryption method mismatch - f.KeySym = keySymOrig - f.KeyAsym = nil - if f.MatchMessage(msg) { - t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed) - } -} - -func cloneFilter(orig *Filter) *Filter { - var clone Filter - clone.Messages = make(map[common.Hash]*ReceivedMessage) - clone.Src = orig.Src - clone.KeyAsym = orig.KeyAsym - clone.KeySym = orig.KeySym - clone.Topics = orig.Topics - clone.PoW = orig.PoW - clone.AllowP2P = orig.AllowP2P - clone.SymKeyHash = orig.SymKeyHash - return &clone -} - -func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope { - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - return nil - } - - params.KeySym = f.KeySym - params.Topic = BytesToTopic(f.Topics[2]) - sentMessage, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := sentMessage.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - return nil - } - return env -} - -func TestWatchers(t *testing.T) { - InitSingleTest() - - const NumFilters = 16 - const NumMessages = 256 - var i int - var j uint32 - var e *Envelope - var x, firstID string - var err error - - w := New(&Config{}) - filters := NewFilters(w) - tst := generateTestCases(t, NumFilters) - for i = 0; i < NumFilters; i++ { - tst[i].f.Src = nil - x, err = filters.Install(tst[i].f) - if err != nil { - t.Fatalf("failed to install filter with seed %d: %s.", seed, err) - } - tst[i].id = x - if len(firstID) == 0 { - firstID = x - } - } - - lastID := x - - var envelopes [NumMessages]*Envelope - for i = 0; i < NumMessages; i++ { - j = mrand.Uint32() % NumFilters - e = generateCompatibeEnvelope(t, tst[j].f) - envelopes[i] = e - tst[j].msgCnt++ - } - - for i = 0; i < NumMessages; i++ { - filters.NotifyWatchers(envelopes[i], false) - } - - var total int - var mail []*ReceivedMessage - var count [NumFilters]int - - for i = 0; i < NumFilters; i++ { - mail = tst[i].f.Retrieve() - count[i] = len(mail) - total += len(mail) - } - - if total != NumMessages { - t.Fatalf("failed with seed %d: total = %d, want: %d.", seed, total, NumMessages) - } - - for i = 0; i < NumFilters; i++ { - mail = tst[i].f.Retrieve() - if len(mail) != 0 { - t.Fatalf("failed with seed %d: i = %d.", seed, i) - } - - if tst[i].msgCnt != count[i] { - t.Fatalf("failed with seed %d: count[%d]: get %d, want %d.", seed, i, tst[i].msgCnt, count[i]) - } - } - - // another round with a cloned filter - - clone := cloneFilter(tst[0].f) - filters.Uninstall(lastID) - total = 0 - last := NumFilters - 1 - tst[last].f = clone - filters.Install(clone) - for i = 0; i < NumFilters; i++ { - tst[i].msgCnt = 0 - count[i] = 0 - } - - // make sure that the first watcher receives at least one message - e = generateCompatibeEnvelope(t, tst[0].f) - envelopes[0] = e - tst[0].msgCnt++ - for i = 1; i < NumMessages; i++ { - j = mrand.Uint32() % NumFilters - e = generateCompatibeEnvelope(t, tst[j].f) - envelopes[i] = e - tst[j].msgCnt++ - } - - for i = 0; i < NumMessages; i++ { - filters.NotifyWatchers(envelopes[i], false) - } - - for i = 0; i < NumFilters; i++ { - mail = tst[i].f.Retrieve() - count[i] = len(mail) - total += len(mail) - } - - combined := tst[0].msgCnt + tst[last].msgCnt - if total != NumMessages+count[0] { - t.Fatalf("failed with seed %d: total = %d, count[0] = %d.", seed, total, count[0]) - } - - if combined != count[0] { - t.Fatalf("failed with seed %d: combined = %d, count[0] = %d.", seed, combined, count[0]) - } - - if combined != count[last] { - t.Fatalf("failed with seed %d: combined = %d, count[last] = %d.", seed, combined, count[last]) - } - - for i = 1; i < NumFilters-1; i++ { - mail = tst[i].f.Retrieve() - if len(mail) != 0 { - t.Fatalf("failed with seed %d: i = %d.", seed, i) - } - - if tst[i].msgCnt != count[i] { - t.Fatalf("failed with seed %d: i = %d, get %d, want %d.", seed, i, tst[i].msgCnt, count[i]) - } - } - - // test AcceptP2P - - total = 0 - filters.NotifyWatchers(envelopes[0], true) - - for i = 0; i < NumFilters; i++ { - mail = tst[i].f.Retrieve() - total += len(mail) - } - - if total != 0 { - t.Fatalf("failed with seed %d: total: got %d, want 0.", seed, total) - } - - f := filters.Get(firstID) - if f == nil { - t.Fatalf("failed to get the filter with seed %d.", seed) - } - f.AllowP2P = true - total = 0 - filters.NotifyWatchers(envelopes[0], true) - - for i = 0; i < NumFilters; i++ { - mail = tst[i].f.Retrieve() - total += len(mail) - } - - if total != 1 { - t.Fatalf("failed with seed %d: total: got %d, want 1.", seed, total) - } -} - -func TestVariableTopics(t *testing.T) { - InitSingleTest() - - const lastTopicByte = 3 - var match bool - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - f, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) - } - - for i := 0; i < 4; i++ { - env.Topic = BytesToTopic(f.Topics[i]) - match = f.MatchEnvelope(env) - if !match { - t.Fatalf("failed MatchEnvelope symmetric with seed %d, step %d.", seed, i) - } - - f.Topics[i][lastTopicByte]++ - match = f.MatchEnvelope(env) - if match { - t.Fatalf("MatchEnvelope symmetric with seed %d, step %d: false positive.", seed, i) - } - } -} - -func TestMatchSingleTopic_ReturnTrue(t *testing.T) { - bt := []byte("test") - topic := BytesToTopic(bt) - - if !matchSingleTopic(topic, bt) { - t.FailNow() - } -} - -func TestMatchSingleTopic_WithTail_ReturnTrue(t *testing.T) { - bt := []byte("test with tail") - topic := BytesToTopic([]byte("test")) - - if !matchSingleTopic(topic, bt) { - t.FailNow() - } -} - -func TestMatchSingleTopic_PartialTopic_ReturnTrue(t *testing.T) { - bt := []byte("tes") - topic := BytesToTopic([]byte("test")) - - if !matchSingleTopic(topic, bt) { - t.FailNow() - } -} - -func TestMatchSingleTopic_NotEquals_ReturnFalse(t *testing.T) { - bt := []byte("test") - topic := BytesToTopic([]byte("not_equal")) - - if matchSingleTopic(topic, bt) { - t.FailNow() - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_criteria_json.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_criteria_json.go deleted file mode 100644 index 1c0e389a..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_criteria_json.go +++ /dev/null @@ -1,64 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package whisperv5 - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -var _ = (*criteriaOverride)(nil) - -func (c Criteria) MarshalJSON() ([]byte, error) { - type Criteria struct { - SymKeyID string `json:"symKeyID"` - PrivateKeyID string `json:"privateKeyID"` - Sig hexutil.Bytes `json:"sig"` - MinPow float64 `json:"minPow"` - Topics []TopicType `json:"topics"` - AllowP2P bool `json:"allowP2P"` - } - var enc Criteria - enc.SymKeyID = c.SymKeyID - enc.PrivateKeyID = c.PrivateKeyID - enc.Sig = c.Sig - enc.MinPow = c.MinPow - enc.Topics = c.Topics - enc.AllowP2P = c.AllowP2P - return json.Marshal(&enc) -} - -func (c *Criteria) UnmarshalJSON(input []byte) error { - type Criteria struct { - SymKeyID *string `json:"symKeyID"` - PrivateKeyID *string `json:"privateKeyID"` - Sig *hexutil.Bytes `json:"sig"` - MinPow *float64 `json:"minPow"` - Topics []TopicType `json:"topics"` - AllowP2P *bool `json:"allowP2P"` - } - var dec Criteria - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.SymKeyID != nil { - c.SymKeyID = *dec.SymKeyID - } - if dec.PrivateKeyID != nil { - c.PrivateKeyID = *dec.PrivateKeyID - } - if dec.Sig != nil { - c.Sig = *dec.Sig - } - if dec.MinPow != nil { - c.MinPow = *dec.MinPow - } - if dec.Topics != nil { - c.Topics = dec.Topics - } - if dec.AllowP2P != nil { - c.AllowP2P = *dec.AllowP2P - } - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_message_json.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_message_json.go deleted file mode 100644 index b4c4274d..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_message_json.go +++ /dev/null @@ -1,82 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package whisperv5 - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -var _ = (*messageOverride)(nil) - -func (m Message) MarshalJSON() ([]byte, error) { - type Message struct { - Sig hexutil.Bytes `json:"sig,omitempty"` - TTL uint32 `json:"ttl"` - Timestamp uint32 `json:"timestamp"` - Topic TopicType `json:"topic"` - Payload hexutil.Bytes `json:"payload"` - Padding hexutil.Bytes `json:"padding"` - PoW float64 `json:"pow"` - Hash hexutil.Bytes `json:"hash"` - Dst hexutil.Bytes `json:"recipientPublicKey,omitempty"` - } - var enc Message - enc.Sig = m.Sig - enc.TTL = m.TTL - enc.Timestamp = m.Timestamp - enc.Topic = m.Topic - enc.Payload = m.Payload - enc.Padding = m.Padding - enc.PoW = m.PoW - enc.Hash = m.Hash - enc.Dst = m.Dst - return json.Marshal(&enc) -} - -func (m *Message) UnmarshalJSON(input []byte) error { - type Message struct { - Sig *hexutil.Bytes `json:"sig,omitempty"` - TTL *uint32 `json:"ttl"` - Timestamp *uint32 `json:"timestamp"` - Topic *TopicType `json:"topic"` - Payload *hexutil.Bytes `json:"payload"` - Padding *hexutil.Bytes `json:"padding"` - PoW *float64 `json:"pow"` - Hash *hexutil.Bytes `json:"hash"` - Dst *hexutil.Bytes `json:"recipientPublicKey,omitempty"` - } - var dec Message - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.Sig != nil { - m.Sig = *dec.Sig - } - if dec.TTL != nil { - m.TTL = *dec.TTL - } - if dec.Timestamp != nil { - m.Timestamp = *dec.Timestamp - } - if dec.Topic != nil { - m.Topic = *dec.Topic - } - if dec.Payload != nil { - m.Payload = *dec.Payload - } - if dec.Padding != nil { - m.Padding = *dec.Padding - } - if dec.PoW != nil { - m.PoW = *dec.PoW - } - if dec.Hash != nil { - m.Hash = *dec.Hash - } - if dec.Dst != nil { - m.Dst = *dec.Dst - } - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_newmessage_json.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_newmessage_json.go deleted file mode 100644 index 97ffb64a..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/gen_newmessage_json.go +++ /dev/null @@ -1,88 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package whisperv5 - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -var _ = (*newMessageOverride)(nil) - -func (n NewMessage) MarshalJSON() ([]byte, error) { - type NewMessage struct { - SymKeyID string `json:"symKeyID"` - PublicKey hexutil.Bytes `json:"pubKey"` - Sig string `json:"sig"` - TTL uint32 `json:"ttl"` - Topic TopicType `json:"topic"` - Payload hexutil.Bytes `json:"payload"` - Padding hexutil.Bytes `json:"padding"` - PowTime uint32 `json:"powTime"` - PowTarget float64 `json:"powTarget"` - TargetPeer string `json:"targetPeer"` - } - var enc NewMessage - enc.SymKeyID = n.SymKeyID - enc.PublicKey = n.PublicKey - enc.Sig = n.Sig - enc.TTL = n.TTL - enc.Topic = n.Topic - enc.Payload = n.Payload - enc.Padding = n.Padding - enc.PowTime = n.PowTime - enc.PowTarget = n.PowTarget - enc.TargetPeer = n.TargetPeer - return json.Marshal(&enc) -} - -func (n *NewMessage) UnmarshalJSON(input []byte) error { - type NewMessage struct { - SymKeyID *string `json:"symKeyID"` - PublicKey *hexutil.Bytes `json:"pubKey"` - Sig *string `json:"sig"` - TTL *uint32 `json:"ttl"` - Topic *TopicType `json:"topic"` - Payload *hexutil.Bytes `json:"payload"` - Padding *hexutil.Bytes `json:"padding"` - PowTime *uint32 `json:"powTime"` - PowTarget *float64 `json:"powTarget"` - TargetPeer *string `json:"targetPeer"` - } - var dec NewMessage - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.SymKeyID != nil { - n.SymKeyID = *dec.SymKeyID - } - if dec.PublicKey != nil { - n.PublicKey = *dec.PublicKey - } - if dec.Sig != nil { - n.Sig = *dec.Sig - } - if dec.TTL != nil { - n.TTL = *dec.TTL - } - if dec.Topic != nil { - n.Topic = *dec.Topic - } - if dec.Payload != nil { - n.Payload = *dec.Payload - } - if dec.Padding != nil { - n.Padding = *dec.Padding - } - if dec.PowTime != nil { - n.PowTime = *dec.PowTime - } - if dec.PowTarget != nil { - n.PowTarget = *dec.PowTarget - } - if dec.TargetPeer != nil { - n.TargetPeer = *dec.TargetPeer - } - return nil -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/message.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/message.go deleted file mode 100644 index 35711d72..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/message.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Contains the Whisper protocol Message element. - -package whisperv5 - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/ecdsa" - crand "crypto/rand" - "encoding/binary" - "errors" - "strconv" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/log" -) - -// MessageParams specifies the exact way a message should be wrapped into an Envelope. -type MessageParams struct { - TTL uint32 - Src *ecdsa.PrivateKey - Dst *ecdsa.PublicKey - KeySym []byte - Topic TopicType - WorkTime uint32 - PoW float64 - Payload []byte - Padding []byte -} - -// SentMessage represents an end-user data packet to transmit through the -// Whisper protocol. These are wrapped into Envelopes that need not be -// understood by intermediate nodes, just forwarded. -type sentMessage struct { - Raw []byte -} - -// ReceivedMessage represents a data packet to be received through the -// Whisper protocol. -type ReceivedMessage struct { - Raw []byte - - Payload []byte - Padding []byte - Signature []byte - - PoW float64 // Proof of work as described in the Whisper spec - Sent uint32 // Time when the message was posted into the network - TTL uint32 // Maximum time to live allowed for the message - Src *ecdsa.PublicKey // Message recipient (identity used to decode the message) - Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message) - Topic TopicType - - SymKeyHash common.Hash // The Keccak256Hash of the key, associated with the Topic - EnvelopeHash common.Hash // Message envelope hash to act as a unique id - EnvelopeVersion uint64 -} - -func isMessageSigned(flags byte) bool { - return (flags & signatureFlag) != 0 -} - -func (msg *ReceivedMessage) isSymmetricEncryption() bool { - return msg.SymKeyHash != common.Hash{} -} - -func (msg *ReceivedMessage) isAsymmetricEncryption() bool { - return msg.Dst != nil -} - -// NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message. -func NewSentMessage(params *MessageParams) (*sentMessage, error) { - msg := sentMessage{} - msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) - msg.Raw[0] = 0 // set all the flags to zero - err := msg.appendPadding(params) - if err != nil { - return nil, err - } - msg.Raw = append(msg.Raw, params.Payload...) - return &msg, nil -} - -// getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes) -func getSizeOfLength(b []byte) (sz int, err error) { - sz = intSize(len(b)) // first iteration - sz = intSize(len(b) + sz) // second iteration - if sz > 3 { - err = errors.New("oversized padding parameter") - } - return sz, err -} - -// sizeOfIntSize returns minimal number of bytes necessary to encode an integer value -func intSize(i int) (s int) { - for s = 1; i >= 256; s++ { - i /= 256 - } - return s -} - -// appendPadding appends the pseudorandom padding bytes and sets the padding flag. -// The last byte contains the size of padding (thus, its size must not exceed 256). -func (msg *sentMessage) appendPadding(params *MessageParams) error { - rawSize := len(params.Payload) + 1 - if params.Src != nil { - rawSize += signatureLength - } - odd := rawSize % padSizeLimit - - if len(params.Padding) != 0 { - padSize := len(params.Padding) - padLengthSize, err := getSizeOfLength(params.Padding) - if err != nil { - return err - } - totalPadSize := padSize + padLengthSize - buf := make([]byte, 8) - binary.LittleEndian.PutUint32(buf, uint32(totalPadSize)) - buf = buf[:padLengthSize] - msg.Raw = append(msg.Raw, buf...) - msg.Raw = append(msg.Raw, params.Padding...) - msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size - } else if odd != 0 { - totalPadSize := padSizeLimit - odd - if totalPadSize > 255 { - // this algorithm is only valid if padSizeLimit < 256. - // if padSizeLimit will ever change, please fix the algorithm - // (please see also ReceivedMessage.extractPadding() function). - panic("please fix the padding algorithm before releasing new version") - } - buf := make([]byte, totalPadSize) - _, err := crand.Read(buf[1:]) - if err != nil { - return err - } - if totalPadSize > 6 && !validateSymmetricKey(buf) { - return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize)) - } - buf[0] = byte(totalPadSize) - msg.Raw = append(msg.Raw, buf...) - msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size - } - return nil -} - -// sign calculates and sets the cryptographic signature for the message, -// also setting the sign flag. -func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { - if isMessageSigned(msg.Raw[0]) { - // this should not happen, but no reason to panic - log.Error("failed to sign the message: already signed") - return nil - } - - msg.Raw[0] |= signatureFlag - hash := crypto.Keccak256(msg.Raw) - signature, err := crypto.Sign(hash, key) - if err != nil { - msg.Raw[0] &= ^signatureFlag // clear the flag - return err - } - msg.Raw = append(msg.Raw, signature...) - return nil -} - -// encryptAsymmetric encrypts a message with a public key. -func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { - if !ValidatePublicKey(key) { - return errors.New("invalid public key provided for asymmetric encryption") - } - encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) - if err == nil { - msg.Raw = encrypted - } - return err -} - -// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256. -// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). -func (msg *sentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) { - if !validateSymmetricKey(key) { - return nil, errors.New("invalid key provided for symmetric encryption") - } - - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - aesgcm, err := cipher.NewGCM(block) - if err != nil { - return nil, err - } - - // never use more than 2^32 random nonces with a given key - nonce = make([]byte, aesgcm.NonceSize()) - _, err = crand.Read(nonce) - if err != nil { - return nil, err - } else if !validateSymmetricKey(nonce) { - return nil, errors.New("crypto/rand failed to generate nonce") - } - - msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil) - return nonce, nil -} - -// Wrap bundles the message into an Envelope to transmit over the network. -func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { - if options.TTL == 0 { - options.TTL = DefaultTTL - } - if options.Src != nil { - if err = msg.sign(options.Src); err != nil { - return nil, err - } - } - var nonce []byte - if options.Dst != nil { - err = msg.encryptAsymmetric(options.Dst) - } else if options.KeySym != nil { - nonce, err = msg.encryptSymmetric(options.KeySym) - } else { - err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") - } - if err != nil { - return nil, err - } - - envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg) - if err = envelope.Seal(options); err != nil { - return nil, err - } - return envelope, nil -} - -// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256. -// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). -func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error { - block, err := aes.NewCipher(key) - if err != nil { - return err - } - aesgcm, err := cipher.NewGCM(block) - if err != nil { - return err - } - if len(nonce) != aesgcm.NonceSize() { - log.Error("decrypting the message", "AES nonce size", len(nonce)) - return errors.New("wrong AES nonce size") - } - decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil) - if err != nil { - return err - } - msg.Raw = decrypted - return nil -} - -// decryptAsymmetric decrypts an encrypted payload with a private key. -func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { - decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) - if err == nil { - msg.Raw = decrypted - } - return err -} - -// Validate checks the validity and extracts the fields in case of success -func (msg *ReceivedMessage) Validate() bool { - end := len(msg.Raw) - if end < 1 { - return false - } - - if isMessageSigned(msg.Raw[0]) { - end -= signatureLength - if end <= 1 { - return false - } - msg.Signature = msg.Raw[end:] - msg.Src = msg.SigToPubKey() - if msg.Src == nil { - return false - } - } - - padSize, ok := msg.extractPadding(end) - if !ok { - return false - } - - msg.Payload = msg.Raw[1+padSize : end] - return true -} - -// extractPadding extracts the padding from raw message. -// although we don't support sending messages with padding size -// exceeding 255 bytes, such messages are perfectly valid, and -// can be successfully decrypted. -func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { - paddingSize := 0 - sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes) - // could be zero -- it means no padding - if sz != 0 { - paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz])) - if paddingSize < sz || paddingSize+1 > end { - return 0, false - } - msg.Padding = msg.Raw[1+sz : 1+paddingSize] - } - return paddingSize, true -} - -// SigToPubKey retrieves the public key of the message signer. -func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { - defer func() { recover() }() // in case of invalid signature - - pub, err := crypto.SigToPub(msg.hash(), msg.Signature) - if err != nil { - log.Error("failed to recover public key from signature", "err", err) - return nil - } - return pub -} - -// hash calculates the SHA3 checksum of the message flags, payload and padding. -func (msg *ReceivedMessage) hash() []byte { - if isMessageSigned(msg.Raw[0]) { - sz := len(msg.Raw) - signatureLength - return crypto.Keccak256(msg.Raw[:sz]) - } - return crypto.Keccak256(msg.Raw) -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/message_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/message_test.go deleted file mode 100644 index 2edf945d..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/message_test.go +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "bytes" - mrand "math/rand" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" -) - -func generateMessageParams() (*MessageParams, error) { - // set all the parameters except p.Dst and p.Padding - - buf := make([]byte, 4) - mrand.Read(buf) - sz := mrand.Intn(400) - - var p MessageParams - p.PoW = 0.01 - p.WorkTime = 1 - p.TTL = uint32(mrand.Intn(1024)) - p.Payload = make([]byte, sz) - p.KeySym = make([]byte, aesKeyLength) - mrand.Read(p.Payload) - mrand.Read(p.KeySym) - p.Topic = BytesToTopic(buf) - - var err error - p.Src, err = crypto.GenerateKey() - if err != nil { - return nil, err - } - - return &p, nil -} - -func singleMessageTest(t *testing.T, symmetric bool) { - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - - if !symmetric { - params.KeySym = nil - params.Dst = &key.PublicKey - } - - text := make([]byte, 0, 512) - text = append(text, params.Payload...) - - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - var decrypted *ReceivedMessage - if symmetric { - decrypted, err = env.OpenSymmetric(params.KeySym) - } else { - decrypted, err = env.OpenAsymmetric(key) - } - - if err != nil { - t.Fatalf("failed to encrypt with seed %d: %s.", seed, err) - } - - if !decrypted.Validate() { - t.Fatalf("failed to validate with seed %d.", seed) - } - - if !bytes.Equal(text, decrypted.Payload) { - t.Fatalf("failed with seed %d: compare payload.", seed) - } - if !isMessageSigned(decrypted.Raw[0]) { - t.Fatalf("failed with seed %d: unsigned.", seed) - } - if len(decrypted.Signature) != signatureLength { - t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature)) - } - if !IsPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) { - t.Fatalf("failed with seed %d: signature mismatch.", seed) - } -} - -func TestMessageEncryption(t *testing.T) { - InitSingleTest() - - var symmetric bool - for i := 0; i < 256; i++ { - singleMessageTest(t, symmetric) - symmetric = !symmetric - } -} - -func TestMessageWrap(t *testing.T) { - seed = int64(1777444222) - mrand.Seed(seed) - target := 128.0 - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - params.TTL = 1 - params.WorkTime = 12 - params.PoW = target - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - pow := env.PoW() - if pow < target { - t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target) - } - - // set PoW target too high, expect error - msg2, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - params.TTL = 1000000 - params.WorkTime = 1 - params.PoW = 10000000.0 - _, err = msg2.Wrap(params) - if err == nil { - t.Fatalf("unexpectedly reached the PoW target with seed %d.", seed) - } -} - -func TestMessageSeal(t *testing.T) { - // this test depends on deterministic choice of seed (1976726903) - seed = int64(1976726903) - mrand.Seed(seed) - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - params.TTL = 1 - aesnonce := make([]byte, 12) - mrand.Read(aesnonce) - - env := NewEnvelope(params.TTL, params.Topic, aesnonce, msg) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - env.Expiry = uint32(seed) // make it deterministic - target := 32.0 - params.WorkTime = 4 - params.PoW = target - env.Seal(params) - - env.calculatePoW(0) - pow := env.PoW() - if pow < target { - t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target) - } - - params.WorkTime = 1 - params.PoW = 1000000000.0 - env.Seal(params) - env.calculatePoW(0) - pow = env.PoW() - if pow < 2*target { - t.Fatalf("failed Wrap with seed %d: pow too small %f.", seed, pow) - } -} - -func TestEnvelopeOpen(t *testing.T) { - InitSingleTest() - - var symmetric bool - for i := 0; i < 256; i++ { - singleEnvelopeOpenTest(t, symmetric) - symmetric = !symmetric - } -} - -func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) - } - - if !symmetric { - params.KeySym = nil - params.Dst = &key.PublicKey - } - - text := make([]byte, 0, 512) - text = append(text, params.Payload...) - - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - f := Filter{KeyAsym: key, KeySym: params.KeySym} - decrypted := env.Open(&f) - if decrypted == nil { - t.Fatalf("failed to open with seed %d.", seed) - } - - if !bytes.Equal(text, decrypted.Payload) { - t.Fatalf("failed with seed %d: compare payload.", seed) - } - if !isMessageSigned(decrypted.Raw[0]) { - t.Fatalf("failed with seed %d: unsigned.", seed) - } - if len(decrypted.Signature) != signatureLength { - t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature)) - } - if !IsPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) { - t.Fatalf("failed with seed %d: signature mismatch.", seed) - } - if decrypted.isAsymmetricEncryption() == symmetric { - t.Fatalf("failed with seed %d: asymmetric %v vs. %v.", seed, decrypted.isAsymmetricEncryption(), symmetric) - } - if decrypted.isSymmetricEncryption() != symmetric { - t.Fatalf("failed with seed %d: symmetric %v vs. %v.", seed, decrypted.isSymmetricEncryption(), symmetric) - } - if !symmetric { - if decrypted.Dst == nil { - t.Fatalf("failed with seed %d: dst is nil.", seed) - } - if !IsPubKeyEqual(decrypted.Dst, &key.PublicKey) { - t.Fatalf("failed with seed %d: Dst.", seed) - } - } -} - -func TestEncryptWithZeroKey(t *testing.T) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - params.KeySym = make([]byte, aesKeyLength) - _, err = msg.Wrap(params) - if err == nil { - t.Fatalf("wrapped with zero key, seed: %d.", seed) - } - - params, err = generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, err = NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - params.KeySym = make([]byte, 0) - _, err = msg.Wrap(params) - if err == nil { - t.Fatalf("wrapped with empty key, seed: %d.", seed) - } - - params, err = generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, err = NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - params.KeySym = nil - _, err = msg.Wrap(params) - if err == nil { - t.Fatalf("wrapped with nil key, seed: %d.", seed) - } -} - -func TestRlpEncode(t *testing.T) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("wrapped with zero key, seed: %d.", seed) - } - - raw, err := rlp.EncodeToBytes(env) - if err != nil { - t.Fatalf("RLP encode failed: %s.", err) - } - - var decoded Envelope - rlp.DecodeBytes(raw, &decoded) - if err != nil { - t.Fatalf("RLP decode failed: %s.", err) - } - - he := env.Hash() - hd := decoded.Hash() - - if he != hd { - t.Fatalf("Hashes are not equal: %x vs. %x", he, hd) - } -} - -func singlePaddingTest(t *testing.T, padSize int) { - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d and sz=%d: %s.", seed, padSize, err) - } - params.Padding = make([]byte, padSize) - params.PoW = 0.0000000001 - pad := make([]byte, padSize) - _, err = mrand.Read(pad) - if err != nil { - t.Fatalf("padding is not generated (seed %d): %s", seed, err) - } - n := copy(params.Padding, pad) - if n != padSize { - t.Fatalf("padding is not copied (seed %d): %s", seed, err) - } - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed to wrap, seed: %d and sz=%d.", seed, padSize) - } - f := Filter{KeySym: params.KeySym} - decrypted := env.Open(&f) - if decrypted == nil { - t.Fatalf("failed to open, seed and sz=%d: %d.", seed, padSize) - } - if !bytes.Equal(pad, decrypted.Padding) { - t.Fatalf("padding is not retireved as expected with seed %d and sz=%d:\n[%x]\n[%x].", seed, padSize, pad, decrypted.Padding) - } -} - -func TestPadding(t *testing.T) { - InitSingleTest() - - for i := 1; i < 260; i++ { - singlePaddingTest(t, i) - } - - lim := 256 * 256 - for i := lim - 5; i < lim+2; i++ { - singlePaddingTest(t, i) - } - - for i := 0; i < 256; i++ { - n := mrand.Intn(256*254) + 256 - singlePaddingTest(t, n) - } - - for i := 0; i < 256; i++ { - n := mrand.Intn(256*1024) + 256*256 - singlePaddingTest(t, n) - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/peer.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/peer.go deleted file mode 100644 index 2bb5677c..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/peer.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "fmt" - "time" - - mapset "github.com/deckarep/golang-set" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" -) - -// Peer represents a whisper protocol peer connection. -type Peer struct { - host *Whisper - peer *p2p.Peer - ws p2p.MsgReadWriter - trusted bool - - known mapset.Set // Messages already known by the peer to avoid wasting bandwidth - - quit chan struct{} -} - -// newPeer creates a new whisper peer object, but does not run the handshake itself. -func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer { - return &Peer{ - host: host, - peer: remote, - ws: rw, - trusted: false, - known: mapset.NewSet(), - quit: make(chan struct{}), - } -} - -// start initiates the peer updater, periodically broadcasting the whisper packets -// into the network. -func (peer *Peer) start() { - go peer.update() - log.Trace("start", "peer", peer.ID()) -} - -// stop terminates the peer updater, stopping message forwarding to it. -func (peer *Peer) stop() { - close(peer.quit) - log.Trace("stop", "peer", peer.ID()) -} - -// handshake sends the protocol initiation status message to the remote peer and -// verifies the remote status too. -func (peer *Peer) handshake() error { - // Send the handshake status message asynchronously - errc := make(chan error, 1) - go func() { - errc <- p2p.Send(peer.ws, statusCode, ProtocolVersion) - }() - // Fetch the remote status packet and verify protocol match - packet, err := peer.ws.ReadMsg() - if err != nil { - return err - } - if packet.Code != statusCode { - return fmt.Errorf("peer [%x] sent packet %x before status packet", peer.ID(), packet.Code) - } - s := rlp.NewStream(packet.Payload, uint64(packet.Size)) - peerVersion, err := s.Uint() - if err != nil { - return fmt.Errorf("peer [%x] sent bad status message: %v", peer.ID(), err) - } - if peerVersion != ProtocolVersion { - return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", peer.ID(), peerVersion, ProtocolVersion) - } - // Wait until out own status is consumed too - if err := <-errc; err != nil { - return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err) - } - return nil -} - -// update executes periodic operations on the peer, including message transmission -// and expiration. -func (peer *Peer) update() { - // Start the tickers for the updates - expire := time.NewTicker(expirationCycle) - transmit := time.NewTicker(transmissionCycle) - - // Loop and transmit until termination is requested - for { - select { - case <-expire.C: - peer.expire() - - case <-transmit.C: - if err := peer.broadcast(); err != nil { - log.Trace("broadcast failed", "reason", err, "peer", peer.ID()) - return - } - - case <-peer.quit: - return - } - } -} - -// mark marks an envelope known to the peer so that it won't be sent back. -func (peer *Peer) mark(envelope *Envelope) { - peer.known.Add(envelope.Hash()) -} - -// marked checks if an envelope is already known to the remote peer. -func (peer *Peer) marked(envelope *Envelope) bool { - return peer.known.Contains(envelope.Hash()) -} - -// expire iterates over all the known envelopes in the host and removes all -// expired (unknown) ones from the known list. -func (peer *Peer) expire() { - unmark := make(map[common.Hash]struct{}) - peer.known.Each(func(v interface{}) bool { - if !peer.host.isEnvelopeCached(v.(common.Hash)) { - unmark[v.(common.Hash)] = struct{}{} - } - return true - }) - // Dump all known but no longer cached - for hash := range unmark { - peer.known.Remove(hash) - } -} - -// broadcast iterates over the collection of envelopes and transmits yet unknown -// ones over the network. -func (peer *Peer) broadcast() error { - var cnt int - envelopes := peer.host.Envelopes() - for _, envelope := range envelopes { - if !peer.marked(envelope) { - err := p2p.Send(peer.ws, messagesCode, envelope) - if err != nil { - return err - } else { - peer.mark(envelope) - cnt++ - } - } - } - if cnt > 0 { - log.Trace("broadcast", "num. messages", cnt) - } - return nil -} - -func (peer *Peer) ID() []byte { - id := peer.peer.ID() - return id[:] -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/peer_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/peer_test.go deleted file mode 100644 index 35616aaa..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/peer_test.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "bytes" - "crypto/ecdsa" - "net" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/nat" -) - -var keys = []string{ - "d49dcf37238dc8a7aac57dc61b9fee68f0a97f062968978b9fafa7d1033d03a9", - "73fd6143c48e80ed3c56ea159fe7494a0b6b393a392227b422f4c3e8f1b54f98", - "119dd32adb1daa7a4c7bf77f847fb28730785aa92947edf42fdd997b54de40dc", - "deeda8709dea935bb772248a3144dea449ffcc13e8e5a1fd4ef20ce4e9c87837", - "5bd208a079633befa349441bdfdc4d85ba9bd56081525008380a63ac38a407cf", - "1d27fb4912002d58a2a42a50c97edb05c1b3dffc665dbaa42df1fe8d3d95c9b5", - "15def52800c9d6b8ca6f3066b7767a76afc7b611786c1276165fbc61636afb68", - "51be6ab4b2dc89f251ff2ace10f3c1cc65d6855f3e083f91f6ff8efdfd28b48c", - "ef1ef7441bf3c6419b162f05da6037474664f198b58db7315a6f4de52414b4a0", - "09bdf6985aabc696dc1fbeb5381aebd7a6421727343872eb2fadfc6d82486fd9", - "15d811bf2e01f99a224cdc91d0cf76cea08e8c67905c16fee9725c9be71185c4", - "2f83e45cf1baaea779789f755b7da72d8857aeebff19362dd9af31d3c9d14620", - "73f04e34ac6532b19c2aae8f8e52f38df1ac8f5cd10369f92325b9b0494b0590", - "1e2e07b69e5025537fb73770f483dc8d64f84ae3403775ef61cd36e3faf162c1", - "8963d9bbb3911aac6d30388c786756b1c423c4fbbc95d1f96ddbddf39809e43a", - "0422da85abc48249270b45d8de38a4cc3c02032ede1fcf0864a51092d58a2f1f", - "8ae5c15b0e8c7cade201fdc149831aa9b11ff626a7ffd27188886cc108ad0fa8", - "acd8f5a71d4aecfcb9ad00d32aa4bcf2a602939b6a9dd071bab443154184f805", - "a285a922125a7481600782ad69debfbcdb0316c1e97c267aff29ef50001ec045", - "28fd4eee78c6cd4bf78f39f8ab30c32c67c24a6223baa40e6f9c9a0e1de7cef5", - "c5cca0c9e6f043b288c6f1aef448ab59132dab3e453671af5d0752961f013fc7", - "46df99b051838cb6f8d1b73f232af516886bd8c4d0ee07af9a0a033c391380fd", - "c6a06a53cbaadbb432884f36155c8f3244e244881b5ee3e92e974cfa166d793f", - "783b90c75c63dc72e2f8d11b6f1b4de54d63825330ec76ee8db34f06b38ea211", - "9450038f10ca2c097a8013e5121b36b422b95b04892232f930a29292d9935611", - "e215e6246ed1cfdcf7310d4d8cdbe370f0d6a8371e4eb1089e2ae05c0e1bc10f", - "487110939ed9d64ebbc1f300adeab358bc58875faf4ca64990fbd7fe03b78f2b", - "824a70ea76ac81366da1d4f4ac39de851c8ac49dca456bb3f0a186ceefa269a5", - "ba8f34fa40945560d1006a328fe70c42e35cc3d1017e72d26864cd0d1b150f15", - "30a5dfcfd144997f428901ea88a43c8d176b19c79dde54cc58eea001aa3d246c", - "de59f7183aca39aa245ce66a05245fecfc7e2c75884184b52b27734a4a58efa2", - "92629e2ff5f0cb4f5f08fffe0f64492024d36f045b901efb271674b801095c5a", - "7184c1701569e3a4c4d2ddce691edd983b81e42e09196d332e1ae2f1e062cff4", -} - -const NumNodes = 16 // must not exceed the number of keys (32) - -type TestData struct { - counter [NumNodes]int - mutex sync.RWMutex -} - -type TestNode struct { - shh *Whisper - id *ecdsa.PrivateKey - server *p2p.Server - filerId string -} - -var result TestData -var nodes [NumNodes]*TestNode -var sharedKey = []byte("some arbitrary data here") -var sharedTopic TopicType = TopicType{0xF, 0x1, 0x2, 0} -var expectedMessage = []byte("per rectum ad astra") - -// This test does the following: -// 1. creates a chain of whisper nodes, -// 2. installs the filters with shared (predefined) parameters, -// 3. each node sends a number of random (undecryptable) messages, -// 4. first node sends one expected (decryptable) message, -// 5. checks if each node have received and decrypted exactly one message. -func TestSimulation(t *testing.T) { - initialize(t) - - for i := 0; i < NumNodes; i++ { - sendMsg(t, false, i) - } - - sendMsg(t, true, 0) - checkPropagation(t) - stopServers() -} - -func initialize(t *testing.T) { - var err error - - for i := 0; i < NumNodes; i++ { - var node TestNode - node.shh = New(&DefaultConfig) - node.shh.SetMinimumPoW(0.00000001) - node.shh.Start(nil) - topics := make([]TopicType, 0) - topics = append(topics, sharedTopic) - f := Filter{KeySym: sharedKey} - f.Topics = [][]byte{topics[0][:]} - node.filerId, err = node.shh.Subscribe(&f) - if err != nil { - t.Fatalf("failed to install the filter: %s.", err) - } - node.id, err = crypto.HexToECDSA(keys[i]) - if err != nil { - t.Fatalf("failed convert the key: %s.", keys[i]) - } - name := common.MakeName("whisper-go", "2.0") - node.server = &p2p.Server{ - Config: p2p.Config{ - PrivateKey: node.id, - MaxPeers: NumNodes/2 + 1, - Name: name, - Protocols: node.shh.Protocols(), - ListenAddr: "127.0.0.1:0", - NAT: nat.Any(), - }, - } - - err = node.server.Start() - if err != nil { - t.Fatalf("failed to start server %d.", i) - } - - for j := 0; j < i; j++ { - peerNodeId := nodes[j].id - address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr) - peerPort := uint16(address.Port) - peer := enode.NewV4(&peerNodeId.PublicKey, address.IP, int(peerPort), int(peerPort)) - node.server.AddPeer(peer) - } - - nodes[i] = &node - } -} - -func stopServers() { - for i := 0; i < NumNodes; i++ { - n := nodes[i] - if n != nil { - n.shh.Unsubscribe(n.filerId) - n.shh.Stop() - n.server.Stop() - } - } -} - -func checkPropagation(t *testing.T) { - if t.Failed() { - return - } - - const cycle = 100 - const iterations = 100 - - for j := 0; j < iterations; j++ { - time.Sleep(cycle * time.Millisecond) - - for i := 0; i < NumNodes; i++ { - f := nodes[i].shh.GetFilter(nodes[i].filerId) - if f == nil { - t.Fatalf("failed to get filterId %s from node %d.", nodes[i].filerId, i) - } - - mail := f.Retrieve() - if !validateMail(t, i, mail) { - return - } - - if isTestComplete() { - return - } - } - } - - t.Fatalf("Test was not complete: timeout %d seconds.", iterations*cycle/1000) -} - -func validateMail(t *testing.T, index int, mail []*ReceivedMessage) bool { - var cnt int - for _, m := range mail { - if bytes.Equal(m.Payload, expectedMessage) { - cnt++ - } - } - - if cnt == 0 { - // no messages received yet: nothing is wrong - return true - } - if cnt > 1 { - t.Fatalf("node %d received %d.", index, cnt) - return false - } - - if cnt > 0 { - result.mutex.Lock() - defer result.mutex.Unlock() - result.counter[index] += cnt - if result.counter[index] > 1 { - t.Fatalf("node %d accumulated %d.", index, result.counter[index]) - } - } - return true -} - -func isTestComplete() bool { - result.mutex.RLock() - defer result.mutex.RUnlock() - - for i := 0; i < NumNodes; i++ { - if result.counter[i] < 1 { - return false - } - } - - for i := 0; i < NumNodes; i++ { - envelopes := nodes[i].shh.Envelopes() - if len(envelopes) < 2 { - return false - } - } - - return true -} - -func sendMsg(t *testing.T, expected bool, id int) { - if t.Failed() { - return - } - - opt := MessageParams{KeySym: sharedKey, Topic: sharedTopic, Payload: expectedMessage, PoW: 0.00000001, WorkTime: 1} - if !expected { - opt.KeySym[0]++ - opt.Topic[0]++ - opt.Payload = opt.Payload[1:] - } - - msg, err := NewSentMessage(&opt) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - envelope, err := msg.Wrap(&opt) - if err != nil { - t.Fatalf("failed to seal message: %s", err) - } - - err = nodes[id].shh.Send(envelope) - if err != nil { - t.Fatalf("failed to send message: %s", err) - } -} - -func TestPeerBasic(t *testing.T) { - InitSingleTest() - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d.", seed) - } - - params.PoW = 0.001 - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d.", seed) - } - - p := newPeer(nil, nil, nil) - p.mark(env) - if !p.marked(env) { - t.Fatalf("failed mark with seed %d.", seed) - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/topic.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/topic.go deleted file mode 100644 index c4eda1db..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/topic.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Contains the Whisper protocol Topic element. - -package whisperv5 - -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -// TopicType represents a cryptographically secure, probabilistic partial -// classifications of a message, determined as the first (left) 4 bytes of the -// SHA3 hash of some arbitrary data given by the original author of the message. -type TopicType [TopicLength]byte - -func BytesToTopic(b []byte) (t TopicType) { - sz := TopicLength - if x := len(b); x < TopicLength { - sz = x - } - for i := 0; i < sz; i++ { - t[i] = b[i] - } - return t -} - -// String converts a topic byte array to a string representation. -func (t *TopicType) String() string { - return common.ToHex(t[:]) -} - -// MarshalText returns the hex representation of t. -func (t TopicType) MarshalText() ([]byte, error) { - return hexutil.Bytes(t[:]).MarshalText() -} - -// UnmarshalText parses a hex representation to a topic. -func (t *TopicType) UnmarshalText(input []byte) error { - return hexutil.UnmarshalFixedText("Topic", input, t[:]) -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/topic_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/topic_test.go deleted file mode 100644 index 54bbeaf8..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/topic_test.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "encoding/json" - "testing" -) - -var topicStringTests = []struct { - topic TopicType - str string -}{ - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, str: "0x00000000"}, - {topic: TopicType{0x00, 0x7f, 0x80, 0xff}, str: "0x007f80ff"}, - {topic: TopicType{0xff, 0x80, 0x7f, 0x00}, str: "0xff807f00"}, - {topic: TopicType{0xf2, 0x6e, 0x77, 0x79}, str: "0xf26e7779"}, -} - -func TestTopicString(t *testing.T) { - for i, tst := range topicStringTests { - s := tst.topic.String() - if s != tst.str { - t.Fatalf("failed test %d: have %s, want %s.", i, s, tst.str) - } - } -} - -var bytesToTopicTests = []struct { - data []byte - topic TopicType -}{ - {topic: TopicType{0x8f, 0x9a, 0x2b, 0x7d}, data: []byte{0x8f, 0x9a, 0x2b, 0x7d}}, - {topic: TopicType{0x00, 0x7f, 0x80, 0xff}, data: []byte{0x00, 0x7f, 0x80, 0xff}}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte{0x00, 0x00, 0x00, 0x00}}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte{0x00, 0x00, 0x00}}, - {topic: TopicType{0x01, 0x00, 0x00, 0x00}, data: []byte{0x01}}, - {topic: TopicType{0x00, 0xfe, 0x00, 0x00}, data: []byte{0x00, 0xfe}}, - {topic: TopicType{0xea, 0x1d, 0x43, 0x00}, data: []byte{0xea, 0x1d, 0x43}}, - {topic: TopicType{0x6f, 0x3c, 0xb0, 0xdd}, data: []byte{0x6f, 0x3c, 0xb0, 0xdd, 0x0f, 0x00, 0x90}}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte{}}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: nil}, -} - -var unmarshalTestsGood = []struct { - topic TopicType - data []byte -}{ - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0x00000000"`)}, - {topic: TopicType{0x00, 0x7f, 0x80, 0xff}, data: []byte(`"0x007f80ff"`)}, - {topic: TopicType{0xff, 0x80, 0x7f, 0x00}, data: []byte(`"0xff807f00"`)}, - {topic: TopicType{0xf2, 0x6e, 0x77, 0x79}, data: []byte(`"0xf26e7779"`)}, -} - -var unmarshalTestsBad = []struct { - topic TopicType - data []byte -}{ - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0x000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0x0000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0x000000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0x0000000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"000000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"0000000000"`)}, - {topic: TopicType{0x00, 0x00, 0x00, 0x00}, data: []byte(`"abcdefg0"`)}, -} - -var unmarshalTestsUgly = []struct { - topic TopicType - data []byte -}{ - {topic: TopicType{0x01, 0x00, 0x00, 0x00}, data: []byte(`"0x00000001"`)}, -} - -func TestBytesToTopic(t *testing.T) { - for i, tst := range bytesToTopicTests { - top := BytesToTopic(tst.data) - if top != tst.topic { - t.Fatalf("failed test %d: have %v, want %v.", i, t, tst.topic) - } - } -} - -func TestUnmarshalTestsGood(t *testing.T) { - for i, tst := range unmarshalTestsGood { - var top TopicType - err := json.Unmarshal(tst.data, &top) - if err != nil { - t.Errorf("failed test %d. input: %v. err: %v", i, tst.data, err) - } else if top != tst.topic { - t.Errorf("failed test %d: have %v, want %v.", i, t, tst.topic) - } - } -} - -func TestUnmarshalTestsBad(t *testing.T) { - // in this test UnmarshalJSON() is supposed to fail - for i, tst := range unmarshalTestsBad { - var top TopicType - err := json.Unmarshal(tst.data, &top) - if err == nil { - t.Fatalf("failed test %d. input: %v.", i, tst.data) - } - } -} - -func TestUnmarshalTestsUgly(t *testing.T) { - // in this test UnmarshalJSON() is NOT supposed to fail, but result should be wrong - for i, tst := range unmarshalTestsUgly { - var top TopicType - err := json.Unmarshal(tst.data, &top) - if err != nil { - t.Errorf("failed test %d. input: %v.", i, tst.data) - } else if top == tst.topic { - t.Errorf("failed test %d: have %v, want %v.", i, top, tst.topic) - } - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/whisper.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/whisper.go deleted file mode 100644 index 46554582..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/whisper.go +++ /dev/null @@ -1,855 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "bytes" - "crypto/ecdsa" - crand "crypto/rand" - "crypto/sha256" - "fmt" - "runtime" - "sync" - "time" - - mapset "github.com/deckarep/golang-set" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rpc" - "github.com/syndtr/goleveldb/leveldb/errors" - "golang.org/x/crypto/pbkdf2" - "golang.org/x/sync/syncmap" -) - -type Statistics struct { - messagesCleared int - memoryCleared int - memoryUsed int - cycles int - totalMessagesCleared int -} - -const ( - minPowIdx = iota // Minimal PoW required by the whisper node - maxMsgSizeIdx = iota // Maximal message length allowed by the whisper node - overflowIdx = iota // Indicator of message queue overflow -) - -// Whisper represents a dark communication interface through the Ethereum -// network, using its very own P2P communication layer. -type Whisper struct { - protocol p2p.Protocol // Protocol description and parameters - filters *Filters // Message filters installed with Subscribe function - - privateKeys map[string]*ecdsa.PrivateKey // Private key storage - symKeys map[string][]byte // Symmetric key storage - keyMu sync.RWMutex // Mutex associated with key storages - - poolMu sync.RWMutex // Mutex to sync the message and expiration pools - envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node - expirations map[uint32]mapset.Set // Message expiration pool - - peerMu sync.RWMutex // Mutex to sync the active peer set - peers map[*Peer]struct{} // Set of currently active peers - - messageQueue chan *Envelope // Message queue for normal whisper messages - p2pMsgQueue chan *Envelope // Message queue for peer-to-peer messages (not to be forwarded any further) - quit chan struct{} // Channel used for graceful exit - - settings syncmap.Map // holds configuration settings that can be dynamically changed - - statsMu sync.Mutex // guard stats - stats Statistics // Statistics of whisper node - - mailServer MailServer // MailServer interface -} - -// New creates a Whisper client ready to communicate through the Ethereum P2P network. -func New(cfg *Config) *Whisper { - if cfg == nil { - cfg = &DefaultConfig - } - - whisper := &Whisper{ - privateKeys: make(map[string]*ecdsa.PrivateKey), - symKeys: make(map[string][]byte), - envelopes: make(map[common.Hash]*Envelope), - expirations: make(map[uint32]mapset.Set), - peers: make(map[*Peer]struct{}), - messageQueue: make(chan *Envelope, messageQueueLimit), - p2pMsgQueue: make(chan *Envelope, messageQueueLimit), - quit: make(chan struct{}), - } - - whisper.filters = NewFilters(whisper) - - whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW) - whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize) - whisper.settings.Store(overflowIdx, false) - - // p2p whisper sub protocol handler - whisper.protocol = p2p.Protocol{ - Name: ProtocolName, - Version: uint(ProtocolVersion), - Length: NumberOfMessageCodes, - Run: whisper.HandlePeer, - NodeInfo: func() interface{} { - return map[string]interface{}{ - "version": ProtocolVersionStr, - "maxMessageSize": whisper.MaxMessageSize(), - "minimumPoW": whisper.MinPow(), - } - }, - } - - return whisper -} - -func (w *Whisper) MinPow() float64 { - val, _ := w.settings.Load(minPowIdx) - return val.(float64) -} - -// MaxMessageSize returns the maximum accepted message size. -func (w *Whisper) MaxMessageSize() uint32 { - val, _ := w.settings.Load(maxMsgSizeIdx) - return val.(uint32) -} - -// Overflow returns an indication if the message queue is full. -func (w *Whisper) Overflow() bool { - val, _ := w.settings.Load(overflowIdx) - return val.(bool) -} - -// APIs returns the RPC descriptors the Whisper implementation offers -func (w *Whisper) APIs() []rpc.API { - return []rpc.API{ - { - Namespace: ProtocolName, - Version: ProtocolVersionStr, - Service: NewPublicWhisperAPI(w), - Public: true, - }, - } -} - -// RegisterServer registers MailServer interface. -// MailServer will process all the incoming messages with p2pRequestCode. -func (w *Whisper) RegisterServer(server MailServer) { - w.mailServer = server -} - -// Protocols returns the whisper sub-protocols ran by this particular client. -func (w *Whisper) Protocols() []p2p.Protocol { - return []p2p.Protocol{w.protocol} -} - -// Version returns the whisper sub-protocols version number. -func (w *Whisper) Version() uint { - return w.protocol.Version -} - -// SetMaxMessageSize sets the maximal message size allowed by this node -func (w *Whisper) SetMaxMessageSize(size uint32) error { - if size > MaxMessageSize { - return fmt.Errorf("message size too large [%d>%d]", size, MaxMessageSize) - } - w.settings.Store(maxMsgSizeIdx, size) - return nil -} - -// SetMinimumPoW sets the minimal PoW required by this node -func (w *Whisper) SetMinimumPoW(val float64) error { - if val <= 0.0 { - return fmt.Errorf("invalid PoW: %f", val) - } - w.settings.Store(minPowIdx, val) - return nil -} - -// getPeer retrieves peer by ID -func (w *Whisper) getPeer(peerID []byte) (*Peer, error) { - w.peerMu.Lock() - defer w.peerMu.Unlock() - for p := range w.peers { - id := p.peer.ID() - if bytes.Equal(peerID, id[:]) { - return p, nil - } - } - return nil, fmt.Errorf("Could not find peer with ID: %x", peerID) -} - -// AllowP2PMessagesFromPeer marks specific peer trusted, -// which will allow it to send historic (expired) messages. -func (w *Whisper) AllowP2PMessagesFromPeer(peerID []byte) error { - p, err := w.getPeer(peerID) - if err != nil { - return err - } - p.trusted = true - return nil -} - -// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer, -// which is known to implement MailServer interface, and is supposed to process this -// request and respond with a number of peer-to-peer messages (possibly expired), -// which are not supposed to be forwarded any further. -// The whisper protocol is agnostic of the format and contents of envelope. -func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) error { - p, err := w.getPeer(peerID) - if err != nil { - return err - } - p.trusted = true - return p2p.Send(p.ws, p2pRequestCode, envelope) -} - -// SendP2PMessage sends a peer-to-peer message to a specific peer. -func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error { - p, err := w.getPeer(peerID) - if err != nil { - return err - } - return w.SendP2PDirect(p, envelope) -} - -// SendP2PDirect sends a peer-to-peer message to a specific peer. -func (w *Whisper) SendP2PDirect(peer *Peer, envelope *Envelope) error { - return p2p.Send(peer.ws, p2pCode, envelope) -} - -// NewKeyPair generates a new cryptographic identity for the client, and injects -// it into the known identities for message decryption. Returns ID of the new key pair. -func (w *Whisper) NewKeyPair() (string, error) { - key, err := crypto.GenerateKey() - if err != nil || !validatePrivateKey(key) { - key, err = crypto.GenerateKey() // retry once - } - if err != nil { - return "", err - } - if !validatePrivateKey(key) { - return "", fmt.Errorf("failed to generate valid key") - } - - id, err := GenerateRandomID() - if err != nil { - return "", fmt.Errorf("failed to generate ID: %s", err) - } - - w.keyMu.Lock() - defer w.keyMu.Unlock() - - if w.privateKeys[id] != nil { - return "", fmt.Errorf("failed to generate unique ID") - } - w.privateKeys[id] = key - return id, nil -} - -// DeleteKeyPair deletes the specified key if it exists. -func (w *Whisper) DeleteKeyPair(key string) bool { - w.keyMu.Lock() - defer w.keyMu.Unlock() - - if w.privateKeys[key] != nil { - delete(w.privateKeys, key) - return true - } - return false -} - -// AddKeyPair imports a asymmetric private key and returns it identifier. -func (w *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) { - id, err := GenerateRandomID() - if err != nil { - return "", fmt.Errorf("failed to generate ID: %s", err) - } - - w.keyMu.Lock() - w.privateKeys[id] = key - w.keyMu.Unlock() - - return id, nil -} - -// HasKeyPair checks if the whisper node is configured with the private key -// of the specified public pair. -func (w *Whisper) HasKeyPair(id string) bool { - w.keyMu.RLock() - defer w.keyMu.RUnlock() - return w.privateKeys[id] != nil -} - -// GetPrivateKey retrieves the private key of the specified identity. -func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) { - w.keyMu.RLock() - defer w.keyMu.RUnlock() - key := w.privateKeys[id] - if key == nil { - return nil, fmt.Errorf("invalid id") - } - return key, nil -} - -// GenerateSymKey generates a random symmetric key and stores it under id, -// which is then returned. Will be used in the future for session key exchange. -func (w *Whisper) GenerateSymKey() (string, error) { - key := make([]byte, aesKeyLength) - _, err := crand.Read(key) - if err != nil { - return "", err - } else if !validateSymmetricKey(key) { - return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data") - } - - id, err := GenerateRandomID() - if err != nil { - return "", fmt.Errorf("failed to generate ID: %s", err) - } - - w.keyMu.Lock() - defer w.keyMu.Unlock() - - if w.symKeys[id] != nil { - return "", fmt.Errorf("failed to generate unique ID") - } - w.symKeys[id] = key - return id, nil -} - -// AddSymKeyDirect stores the key, and returns its id. -func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) { - if len(key) != aesKeyLength { - return "", fmt.Errorf("wrong key size: %d", len(key)) - } - - id, err := GenerateRandomID() - if err != nil { - return "", fmt.Errorf("failed to generate ID: %s", err) - } - - w.keyMu.Lock() - defer w.keyMu.Unlock() - - if w.symKeys[id] != nil { - return "", fmt.Errorf("failed to generate unique ID") - } - w.symKeys[id] = key - return id, nil -} - -// AddSymKeyFromPassword generates the key from password, stores it, and returns its id. -func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) { - id, err := GenerateRandomID() - if err != nil { - return "", fmt.Errorf("failed to generate ID: %s", err) - } - if w.HasSymKey(id) { - return "", fmt.Errorf("failed to generate unique ID") - } - - derived, err := deriveKeyMaterial([]byte(password), EnvelopeVersion) - if err != nil { - return "", err - } - - w.keyMu.Lock() - defer w.keyMu.Unlock() - - // double check is necessary, because deriveKeyMaterial() is very slow - if w.symKeys[id] != nil { - return "", fmt.Errorf("critical error: failed to generate unique ID") - } - w.symKeys[id] = derived - return id, nil -} - -// HasSymKey returns true if there is a key associated with the given id. -// Otherwise returns false. -func (w *Whisper) HasSymKey(id string) bool { - w.keyMu.RLock() - defer w.keyMu.RUnlock() - return w.symKeys[id] != nil -} - -// DeleteSymKey deletes the key associated with the name string if it exists. -func (w *Whisper) DeleteSymKey(id string) bool { - w.keyMu.Lock() - defer w.keyMu.Unlock() - if w.symKeys[id] != nil { - delete(w.symKeys, id) - return true - } - return false -} - -// GetSymKey returns the symmetric key associated with the given id. -func (w *Whisper) GetSymKey(id string) ([]byte, error) { - w.keyMu.RLock() - defer w.keyMu.RUnlock() - if w.symKeys[id] != nil { - return w.symKeys[id], nil - } - return nil, fmt.Errorf("non-existent key ID") -} - -// Subscribe installs a new message handler used for filtering, decrypting -// and subsequent storing of incoming messages. -func (w *Whisper) Subscribe(f *Filter) (string, error) { - return w.filters.Install(f) -} - -// GetFilter returns the filter by id. -func (w *Whisper) GetFilter(id string) *Filter { - return w.filters.Get(id) -} - -// Unsubscribe removes an installed message handler. -func (w *Whisper) Unsubscribe(id string) error { - ok := w.filters.Uninstall(id) - if !ok { - return fmt.Errorf("Unsubscribe: Invalid ID") - } - return nil -} - -// Send injects a message into the whisper send queue, to be distributed in the -// network in the coming cycles. -func (w *Whisper) Send(envelope *Envelope) error { - ok, err := w.add(envelope) - if err != nil { - return err - } - if !ok { - return fmt.Errorf("failed to add envelope") - } - return err -} - -// Start implements node.Service, starting the background data propagation thread -// of the Whisper protocol. -func (w *Whisper) Start(*p2p.Server) error { - log.Info("started whisper v." + ProtocolVersionStr) - go w.update() - - numCPU := runtime.NumCPU() - for i := 0; i < numCPU; i++ { - go w.processQueue() - } - - return nil -} - -// Stop implements node.Service, stopping the background data propagation thread -// of the Whisper protocol. -func (w *Whisper) Stop() error { - close(w.quit) - log.Info("whisper stopped") - return nil -} - -// HandlePeer is called by the underlying P2P layer when the whisper sub-protocol -// connection is negotiated. -func (w *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - // Create the new peer and start tracking it - whisperPeer := newPeer(w, peer, rw) - - w.peerMu.Lock() - w.peers[whisperPeer] = struct{}{} - w.peerMu.Unlock() - - defer func() { - w.peerMu.Lock() - delete(w.peers, whisperPeer) - w.peerMu.Unlock() - }() - - // Run the peer handshake and state updates - if err := whisperPeer.handshake(); err != nil { - return err - } - whisperPeer.start() - defer whisperPeer.stop() - - return w.runMessageLoop(whisperPeer, rw) -} - -// runMessageLoop reads and processes inbound messages directly to merge into client-global state. -func (w *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { - for { - // fetch the next packet - packet, err := rw.ReadMsg() - if err != nil { - log.Info("message loop", "peer", p.peer.ID(), "err", err) - return err - } - if packet.Size > w.MaxMessageSize() { - log.Warn("oversized message received", "peer", p.peer.ID()) - return errors.New("oversized message received") - } - - switch packet.Code { - case statusCode: - // this should not happen, but no need to panic; just ignore this message. - log.Warn("unxepected status message received", "peer", p.peer.ID()) - case messagesCode: - // decode the contained envelopes - var envelope Envelope - if err := packet.Decode(&envelope); err != nil { - log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err) - return errors.New("invalid envelope") - } - cached, err := w.add(&envelope) - if err != nil { - log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err) - return errors.New("invalid envelope") - } - if cached { - p.mark(&envelope) - } - case p2pCode: - // peer-to-peer message, sent directly to peer bypassing PoW checks, etc. - // this message is not supposed to be forwarded to other peers, and - // therefore might not satisfy the PoW, expiry and other requirements. - // these messages are only accepted from the trusted peer. - if p.trusted { - var envelope Envelope - if err := packet.Decode(&envelope); err != nil { - log.Warn("failed to decode direct message, peer will be disconnected", "peer", p.peer.ID(), "err", err) - return errors.New("invalid direct message") - } - w.postEvent(&envelope, true) - } - case p2pRequestCode: - // Must be processed if mail server is implemented. Otherwise ignore. - if w.mailServer != nil { - var request Envelope - if err := packet.Decode(&request); err != nil { - log.Warn("failed to decode p2p request message, peer will be disconnected", "peer", p.peer.ID(), "err", err) - return errors.New("invalid p2p request") - } - w.mailServer.DeliverMail(p, &request) - } - default: - // New message types might be implemented in the future versions of Whisper. - // For forward compatibility, just ignore. - } - - packet.Discard() - } -} - -// add inserts a new envelope into the message pool to be distributed within the -// whisper network. It also inserts the envelope into the expiration pool at the -// appropriate time-stamp. In case of error, connection should be dropped. -func (w *Whisper) add(envelope *Envelope) (bool, error) { - now := uint32(time.Now().Unix()) - sent := envelope.Expiry - envelope.TTL - - if sent > now { - if sent-SynchAllowance > now { - return false, fmt.Errorf("envelope created in the future [%x]", envelope.Hash()) - } - // recalculate PoW, adjusted for the time difference, plus one second for latency - envelope.calculatePoW(sent - now + 1) - } - - if envelope.Expiry < now { - if envelope.Expiry+SynchAllowance*2 < now { - return false, fmt.Errorf("very old message") - } - log.Debug("expired envelope dropped", "hash", envelope.Hash().Hex()) - return false, nil // drop envelope without error - } - - if uint32(envelope.size()) > w.MaxMessageSize() { - return false, fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash()) - } - - if len(envelope.Version) > 4 { - return false, fmt.Errorf("oversized version [%x]", envelope.Hash()) - } - - aesNonceSize := len(envelope.AESNonce) - if aesNonceSize != 0 && aesNonceSize != AESNonceLength { - // the standard AES GCM nonce size is 12 bytes, - // but constant gcmStandardNonceSize cannot be accessed (not exported) - return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash()) - } - - if envelope.PoW() < w.MinPow() { - log.Debug("envelope with low PoW dropped", "PoW", envelope.PoW(), "hash", envelope.Hash().Hex()) - return false, nil // drop envelope without error - } - - hash := envelope.Hash() - - w.poolMu.Lock() - _, alreadyCached := w.envelopes[hash] - if !alreadyCached { - w.envelopes[hash] = envelope - if w.expirations[envelope.Expiry] == nil { - w.expirations[envelope.Expiry] = mapset.NewThreadUnsafeSet() - } - if !w.expirations[envelope.Expiry].Contains(hash) { - w.expirations[envelope.Expiry].Add(hash) - } - } - w.poolMu.Unlock() - - if alreadyCached { - log.Trace("whisper envelope already cached", "hash", envelope.Hash().Hex()) - } else { - log.Trace("cached whisper envelope", "hash", envelope.Hash().Hex()) - w.statsMu.Lock() - w.stats.memoryUsed += envelope.size() - w.statsMu.Unlock() - w.postEvent(envelope, false) // notify the local node about the new message - if w.mailServer != nil { - w.mailServer.Archive(envelope) - } - } - return true, nil -} - -// postEvent queues the message for further processing. -func (w *Whisper) postEvent(envelope *Envelope, isP2P bool) { - // if the version of incoming message is higher than - // currently supported version, we can not decrypt it, - // and therefore just ignore this message - if envelope.Ver() <= EnvelopeVersion { - if isP2P { - w.p2pMsgQueue <- envelope - } else { - w.checkOverflow() - w.messageQueue <- envelope - } - } -} - -// checkOverflow checks if message queue overflow occurs and reports it if necessary. -func (w *Whisper) checkOverflow() { - queueSize := len(w.messageQueue) - - if queueSize == messageQueueLimit { - if !w.Overflow() { - w.settings.Store(overflowIdx, true) - log.Warn("message queue overflow") - } - } else if queueSize <= messageQueueLimit/2 { - if w.Overflow() { - w.settings.Store(overflowIdx, false) - log.Warn("message queue overflow fixed (back to normal)") - } - } -} - -// processQueue delivers the messages to the watchers during the lifetime of the whisper node. -func (w *Whisper) processQueue() { - var e *Envelope - for { - select { - case <-w.quit: - return - - case e = <-w.messageQueue: - w.filters.NotifyWatchers(e, false) - - case e = <-w.p2pMsgQueue: - w.filters.NotifyWatchers(e, true) - } - } -} - -// update loops until the lifetime of the whisper node, updating its internal -// state by expiring stale messages from the pool. -func (w *Whisper) update() { - // Start a ticker to check for expirations - expire := time.NewTicker(expirationCycle) - - // Repeat updates until termination is requested - for { - select { - case <-expire.C: - w.expire() - - case <-w.quit: - return - } - } -} - -// expire iterates over all the expiration timestamps, removing all stale -// messages from the pools. -func (w *Whisper) expire() { - w.poolMu.Lock() - defer w.poolMu.Unlock() - - w.statsMu.Lock() - defer w.statsMu.Unlock() - w.stats.reset() - now := uint32(time.Now().Unix()) - for expiry, hashSet := range w.expirations { - if expiry < now { - // Dump all expired messages and remove timestamp - hashSet.Each(func(v interface{}) bool { - sz := w.envelopes[v.(common.Hash)].size() - delete(w.envelopes, v.(common.Hash)) - w.stats.messagesCleared++ - w.stats.memoryCleared += sz - w.stats.memoryUsed -= sz - return false - }) - w.expirations[expiry].Clear() - delete(w.expirations, expiry) - } - } -} - -// Stats returns the whisper node statistics. -func (w *Whisper) Stats() Statistics { - w.statsMu.Lock() - defer w.statsMu.Unlock() - - return w.stats -} - -// Envelopes retrieves all the messages currently pooled by the node. -func (w *Whisper) Envelopes() []*Envelope { - w.poolMu.RLock() - defer w.poolMu.RUnlock() - - all := make([]*Envelope, 0, len(w.envelopes)) - for _, envelope := range w.envelopes { - all = append(all, envelope) - } - return all -} - -// Messages iterates through all currently floating envelopes -// and retrieves all the messages, that this filter could decrypt. -func (w *Whisper) Messages(id string) []*ReceivedMessage { - result := make([]*ReceivedMessage, 0) - w.poolMu.RLock() - defer w.poolMu.RUnlock() - - if filter := w.filters.Get(id); filter != nil { - for _, env := range w.envelopes { - msg := filter.processEnvelope(env) - if msg != nil { - result = append(result, msg) - } - } - } - return result -} - -// isEnvelopeCached checks if envelope with specific hash has already been received and cached. -func (w *Whisper) isEnvelopeCached(hash common.Hash) bool { - w.poolMu.Lock() - defer w.poolMu.Unlock() - - _, exist := w.envelopes[hash] - return exist -} - -// reset resets the node's statistics after each expiry cycle. -func (s *Statistics) reset() { - s.cycles++ - s.totalMessagesCleared += s.messagesCleared - - s.memoryCleared = 0 - s.messagesCleared = 0 -} - -// ValidatePublicKey checks the format of the given public key. -func ValidatePublicKey(k *ecdsa.PublicKey) bool { - return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0 -} - -// validatePrivateKey checks the format of the given private key. -func validatePrivateKey(k *ecdsa.PrivateKey) bool { - if k == nil || k.D == nil || k.D.Sign() == 0 { - return false - } - return ValidatePublicKey(&k.PublicKey) -} - -// validateSymmetricKey returns false if the key contains all zeros -func validateSymmetricKey(k []byte) bool { - return len(k) > 0 && !containsOnlyZeros(k) -} - -// containsOnlyZeros checks if the data contain only zeros. -func containsOnlyZeros(data []byte) bool { - for _, b := range data { - if b != 0 { - return false - } - } - return true -} - -// bytesToUintLittleEndian converts the slice to 64-bit unsigned integer. -func bytesToUintLittleEndian(b []byte) (res uint64) { - mul := uint64(1) - for i := 0; i < len(b); i++ { - res += uint64(b[i]) * mul - mul *= 256 - } - return res -} - -// BytesToUintBigEndian converts the slice to 64-bit unsigned integer. -func BytesToUintBigEndian(b []byte) (res uint64) { - for i := 0; i < len(b); i++ { - res *= 256 - res += uint64(b[i]) - } - return res -} - -// deriveKeyMaterial derives symmetric key material from the key or password. -// pbkdf2 is used for security, in case people use password instead of randomly generated keys. -func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error) { - if version == 0 { - // kdf should run no less than 0.1 seconds on average compute, - // because it's a once in a session experience - derivedKey := pbkdf2.Key(key, nil, 65356, aesKeyLength, sha256.New) - return derivedKey, nil - } - return nil, unknownVersionError(version) -} - -// GenerateRandomID generates a random string, which is then returned to be used as a key id -func GenerateRandomID() (id string, err error) { - buf := make([]byte, keyIdSize) - _, err = crand.Read(buf) - if err != nil { - return "", err - } - if !validateSymmetricKey(buf) { - return "", fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data") - } - id = common.Bytes2Hex(buf) - return id, err -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/whisper_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/whisper_test.go deleted file mode 100644 index a7bd17e4..00000000 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv5/whisper_test.go +++ /dev/null @@ -1,858 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package whisperv5 - -import ( - "bytes" - "crypto/ecdsa" - mrand "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" -) - -func TestWhisperBasic(t *testing.T) { - w := New(&DefaultConfig) - p := w.Protocols() - shh := p[0] - if shh.Name != ProtocolName { - t.Fatalf("failed Protocol Name: %v.", shh.Name) - } - if uint64(shh.Version) != ProtocolVersion { - t.Fatalf("failed Protocol Version: %v.", shh.Version) - } - if shh.Length != NumberOfMessageCodes { - t.Fatalf("failed Protocol Length: %v.", shh.Length) - } - if shh.Run == nil { - t.Fatalf("failed shh.Run.") - } - if uint64(w.Version()) != ProtocolVersion { - t.Fatalf("failed whisper Version: %v.", shh.Version) - } - if w.GetFilter("non-existent") != nil { - t.Fatalf("failed GetFilter.") - } - - peerID := make([]byte, 64) - mrand.Read(peerID) - peer, _ := w.getPeer(peerID) - if peer != nil { - t.Fatal("found peer for random key.") - } - if err := w.AllowP2PMessagesFromPeer(peerID); err == nil { - t.Fatalf("failed MarkPeerTrusted.") - } - exist := w.HasSymKey("non-existing") - if exist { - t.Fatalf("failed HasSymKey.") - } - key, err := w.GetSymKey("non-existing") - if err == nil { - t.Fatalf("failed GetSymKey(non-existing): false positive.") - } - if key != nil { - t.Fatalf("failed GetSymKey: false positive.") - } - mail := w.Envelopes() - if len(mail) != 0 { - t.Fatalf("failed w.Envelopes().") - } - m := w.Messages("non-existent") - if len(m) != 0 { - t.Fatalf("failed w.Messages.") - } - - var derived []byte - ver := uint64(0xDEADBEEF) - if _, err := deriveKeyMaterial(peerID, ver); err != unknownVersionError(ver) { - t.Fatalf("failed deriveKeyMaterial with param = %v: %s.", peerID, err) - } - derived, err = deriveKeyMaterial(peerID, 0) - if err != nil { - t.Fatalf("failed second deriveKeyMaterial with param = %v: %s.", peerID, err) - } - if !validateSymmetricKey(derived) { - t.Fatalf("failed validateSymmetricKey with param = %v.", derived) - } - if containsOnlyZeros(derived) { - t.Fatalf("failed containsOnlyZeros with param = %v.", derived) - } - - buf := []byte{0xFF, 0xE5, 0x80, 0x2, 0} - le := bytesToUintLittleEndian(buf) - be := BytesToUintBigEndian(buf) - if le != uint64(0x280e5ff) { - t.Fatalf("failed bytesToIntLittleEndian: %d.", le) - } - if be != uint64(0xffe5800200) { - t.Fatalf("failed BytesToIntBigEndian: %d.", be) - } - - id, err := w.NewKeyPair() - if err != nil { - t.Fatalf("failed to generate new key pair: %s.", err) - } - pk, err := w.GetPrivateKey(id) - if err != nil { - t.Fatalf("failed to retrieve new key pair: %s.", err) - } - if !validatePrivateKey(pk) { - t.Fatalf("failed validatePrivateKey: %v.", pk) - } - if !ValidatePublicKey(&pk.PublicKey) { - t.Fatalf("failed ValidatePublicKey: %v.", pk) - } -} - -func TestWhisperAsymmetricKeyImport(t *testing.T) { - var ( - w = New(&DefaultConfig) - privateKeys []*ecdsa.PrivateKey - ) - - for i := 0; i < 50; i++ { - id, err := w.NewKeyPair() - if err != nil { - t.Fatalf("could not generate key: %v", err) - } - - pk, err := w.GetPrivateKey(id) - if err != nil { - t.Fatalf("could not export private key: %v", err) - } - - privateKeys = append(privateKeys, pk) - - if !w.DeleteKeyPair(id) { - t.Fatalf("could not delete private key") - } - } - - for _, pk := range privateKeys { - if _, err := w.AddKeyPair(pk); err != nil { - t.Fatalf("could not import private key: %v", err) - } - } -} - -func TestWhisperIdentityManagement(t *testing.T) { - w := New(&DefaultConfig) - id1, err := w.NewKeyPair() - if err != nil { - t.Fatalf("failed to generate new key pair: %s.", err) - } - id2, err := w.NewKeyPair() - if err != nil { - t.Fatalf("failed to generate new key pair: %s.", err) - } - pk1, err := w.GetPrivateKey(id1) - if err != nil { - t.Fatalf("failed to retrieve the key pair: %s.", err) - } - pk2, err := w.GetPrivateKey(id2) - if err != nil { - t.Fatalf("failed to retrieve the key pair: %s.", err) - } - - if !w.HasKeyPair(id1) { - t.Fatalf("failed HasIdentity(pk1).") - } - if !w.HasKeyPair(id2) { - t.Fatalf("failed HasIdentity(pk2).") - } - if pk1 == nil { - t.Fatalf("failed GetIdentity(pk1).") - } - if pk2 == nil { - t.Fatalf("failed GetIdentity(pk2).") - } - - if !validatePrivateKey(pk1) { - t.Fatalf("pk1 is invalid.") - } - if !validatePrivateKey(pk2) { - t.Fatalf("pk2 is invalid.") - } - - // Delete one identity - done := w.DeleteKeyPair(id1) - if !done { - t.Fatalf("failed to delete id1.") - } - pk1, err = w.GetPrivateKey(id1) - if err == nil { - t.Fatalf("retrieve the key pair: false positive.") - } - pk2, err = w.GetPrivateKey(id2) - if err != nil { - t.Fatalf("failed to retrieve the key pair: %s.", err) - } - if w.HasKeyPair(id1) { - t.Fatalf("failed DeleteIdentity(pub1): still exist.") - } - if !w.HasKeyPair(id2) { - t.Fatalf("failed DeleteIdentity(pub1): pub2 does not exist.") - } - if pk1 != nil { - t.Fatalf("failed DeleteIdentity(pub1): first key still exist.") - } - if pk2 == nil { - t.Fatalf("failed DeleteIdentity(pub1): second key does not exist.") - } - - // Delete again non-existing identity - done = w.DeleteKeyPair(id1) - if done { - t.Fatalf("delete id1: false positive.") - } - pk1, err = w.GetPrivateKey(id1) - if err == nil { - t.Fatalf("retrieve the key pair: false positive.") - } - pk2, err = w.GetPrivateKey(id2) - if err != nil { - t.Fatalf("failed to retrieve the key pair: %s.", err) - } - if w.HasKeyPair(id1) { - t.Fatalf("failed delete non-existing identity: exist.") - } - if !w.HasKeyPair(id2) { - t.Fatalf("failed delete non-existing identity: pub2 does not exist.") - } - if pk1 != nil { - t.Fatalf("failed delete non-existing identity: first key exist.") - } - if pk2 == nil { - t.Fatalf("failed delete non-existing identity: second key does not exist.") - } - - // Delete second identity - done = w.DeleteKeyPair(id2) - if !done { - t.Fatalf("failed to delete id2.") - } - pk1, err = w.GetPrivateKey(id1) - if err == nil { - t.Fatalf("retrieve the key pair: false positive.") - } - pk2, err = w.GetPrivateKey(id2) - if err == nil { - t.Fatalf("retrieve the key pair: false positive.") - } - if w.HasKeyPair(id1) { - t.Fatalf("failed delete second identity: first identity exist.") - } - if w.HasKeyPair(id2) { - t.Fatalf("failed delete second identity: still exist.") - } - if pk1 != nil { - t.Fatalf("failed delete second identity: first key exist.") - } - if pk2 != nil { - t.Fatalf("failed delete second identity: second key exist.") - } -} - -func TestWhisperSymKeyManagement(t *testing.T) { - InitSingleTest() - - var err error - var k1, k2 []byte - w := New(&DefaultConfig) - id1 := string("arbitrary-string-1") - id2 := string("arbitrary-string-2") - - id1, err = w.GenerateSymKey() - if err != nil { - t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err) - } - - k1, err = w.GetSymKey(id1) - if err != nil { - t.Fatalf("failed GetSymKey(id1).") - } - k2, err = w.GetSymKey(id2) - if err == nil { - t.Fatalf("failed GetSymKey(id2): false positive.") - } - if !w.HasSymKey(id1) { - t.Fatalf("failed HasSymKey(id1).") - } - if w.HasSymKey(id2) { - t.Fatalf("failed HasSymKey(id2): false positive.") - } - if k1 == nil { - t.Fatalf("first key does not exist.") - } - if k2 != nil { - t.Fatalf("second key still exist.") - } - - // add existing id, nothing should change - randomKey := make([]byte, aesKeyLength) - mrand.Read(randomKey) - id1, err = w.AddSymKeyDirect(randomKey) - if err != nil { - t.Fatalf("failed AddSymKey with seed %d: %s.", seed, err) - } - - k1, err = w.GetSymKey(id1) - if err != nil { - t.Fatalf("failed w.GetSymKey(id1).") - } - k2, err = w.GetSymKey(id2) - if err == nil { - t.Fatalf("failed w.GetSymKey(id2): false positive.") - } - if !w.HasSymKey(id1) { - t.Fatalf("failed w.HasSymKey(id1).") - } - if w.HasSymKey(id2) { - t.Fatalf("failed w.HasSymKey(id2): false positive.") - } - if k1 == nil { - t.Fatalf("first key does not exist.") - } - if !bytes.Equal(k1, randomKey) { - t.Fatalf("k1 != randomKey.") - } - if k2 != nil { - t.Fatalf("second key already exist.") - } - - id2, err = w.AddSymKeyDirect(randomKey) - if err != nil { - t.Fatalf("failed AddSymKey(id2) with seed %d: %s.", seed, err) - } - k1, err = w.GetSymKey(id1) - if err != nil { - t.Fatalf("failed w.GetSymKey(id1).") - } - k2, err = w.GetSymKey(id2) - if err != nil { - t.Fatalf("failed w.GetSymKey(id2).") - } - if !w.HasSymKey(id1) { - t.Fatalf("HasSymKey(id1) failed.") - } - if !w.HasSymKey(id2) { - t.Fatalf("HasSymKey(id2) failed.") - } - if k1 == nil { - t.Fatalf("k1 does not exist.") - } - if k2 == nil { - t.Fatalf("k2 does not exist.") - } - if !bytes.Equal(k1, k2) { - t.Fatalf("k1 != k2.") - } - if !bytes.Equal(k1, randomKey) { - t.Fatalf("k1 != randomKey.") - } - if len(k1) != aesKeyLength { - t.Fatalf("wrong length of k1.") - } - if len(k2) != aesKeyLength { - t.Fatalf("wrong length of k2.") - } - - w.DeleteSymKey(id1) - k1, err = w.GetSymKey(id1) - if err == nil { - t.Fatalf("failed w.GetSymKey(id1): false positive.") - } - if k1 != nil { - t.Fatalf("failed GetSymKey(id1): false positive.") - } - k2, err = w.GetSymKey(id2) - if err != nil { - t.Fatalf("failed w.GetSymKey(id2).") - } - if w.HasSymKey(id1) { - t.Fatalf("failed to delete first key: still exist.") - } - if !w.HasSymKey(id2) { - t.Fatalf("failed to delete first key: second key does not exist.") - } - if k1 != nil { - t.Fatalf("failed to delete first key.") - } - if k2 == nil { - t.Fatalf("failed to delete first key: second key is nil.") - } - - w.DeleteSymKey(id1) - w.DeleteSymKey(id2) - k1, err = w.GetSymKey(id1) - if err == nil { - t.Fatalf("failed w.GetSymKey(id1): false positive.") - } - k2, err = w.GetSymKey(id2) - if err == nil { - t.Fatalf("failed w.GetSymKey(id2): false positive.") - } - if k1 != nil || k2 != nil { - t.Fatalf("k1 or k2 is not nil") - } - if w.HasSymKey(id1) { - t.Fatalf("failed to delete second key: first key exist.") - } - if w.HasSymKey(id2) { - t.Fatalf("failed to delete second key: still exist.") - } - if k1 != nil { - t.Fatalf("failed to delete second key: first key is not nil.") - } - if k2 != nil { - t.Fatalf("failed to delete second key: second key is not nil.") - } - - randomKey = make([]byte, aesKeyLength+1) - mrand.Read(randomKey) - _, err = w.AddSymKeyDirect(randomKey) - if err == nil { - t.Fatalf("added the key with wrong size, seed %d.", seed) - } - - const password = "arbitrary data here" - id1, err = w.AddSymKeyFromPassword(password) - if err != nil { - t.Fatalf("failed AddSymKeyFromPassword(id1) with seed %d: %s.", seed, err) - } - id2, err = w.AddSymKeyFromPassword(password) - if err != nil { - t.Fatalf("failed AddSymKeyFromPassword(id2) with seed %d: %s.", seed, err) - } - k1, err = w.GetSymKey(id1) - if err != nil { - t.Fatalf("failed w.GetSymKey(id1).") - } - k2, err = w.GetSymKey(id2) - if err != nil { - t.Fatalf("failed w.GetSymKey(id2).") - } - if !w.HasSymKey(id1) { - t.Fatalf("HasSymKey(id1) failed.") - } - if !w.HasSymKey(id2) { - t.Fatalf("HasSymKey(id2) failed.") - } - if k1 == nil { - t.Fatalf("k1 does not exist.") - } - if k2 == nil { - t.Fatalf("k2 does not exist.") - } - if !bytes.Equal(k1, k2) { - t.Fatalf("k1 != k2.") - } - if len(k1) != aesKeyLength { - t.Fatalf("wrong length of k1.") - } - if len(k2) != aesKeyLength { - t.Fatalf("wrong length of k2.") - } - if !validateSymmetricKey(k2) { - t.Fatalf("key validation failed.") - } -} - -func TestExpiry(t *testing.T) { - InitSingleTest() - - w := New(&DefaultConfig) - w.SetMinimumPoW(0.0000001) - defer w.SetMinimumPoW(DefaultMinimumPoW) - w.Start(nil) - defer w.Stop() - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - params.TTL = 1 - - messagesCount := 5 - - // Send a few messages one after another. Due to low PoW and expiration buckets - // with one second resolution, it covers a case when there are multiple items - // in a single expiration bucket. - for i := 0; i < messagesCount; i++ { - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - err = w.Send(env) - if err != nil { - t.Fatalf("failed to send envelope with seed %d: %s.", seed, err) - } - } - - // wait till received or timeout - var received, expired bool - for j := 0; j < 20; j++ { - time.Sleep(100 * time.Millisecond) - if len(w.Envelopes()) == messagesCount { - received = true - break - } - } - - if !received { - t.Fatalf("did not receive the sent envelope, seed: %d.", seed) - } - - // wait till expired or timeout - for j := 0; j < 20; j++ { - time.Sleep(100 * time.Millisecond) - if len(w.Envelopes()) == 0 { - expired = true - break - } - } - - if !expired { - t.Fatalf("expire failed, seed: %d.", seed) - } -} - -func TestCustomization(t *testing.T) { - InitSingleTest() - - w := New(&DefaultConfig) - defer w.SetMinimumPoW(DefaultMinimumPoW) - defer w.SetMaxMessageSize(DefaultMaxMessageSize) - w.Start(nil) - defer w.Stop() - - const smallPoW = 0.00001 - - f, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - params.KeySym = f.KeySym - params.Topic = BytesToTopic(f.Topics[2]) - params.PoW = smallPoW - params.TTL = 3600 * 24 // one day - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - err = w.Send(env) - if err == nil { - t.Fatalf("successfully sent envelope with PoW %.06f, false positive (seed %d).", env.PoW(), seed) - } - - w.SetMinimumPoW(smallPoW / 2) - err = w.Send(env) - if err != nil { - t.Fatalf("failed to send envelope with seed %d: %s.", seed, err) - } - - params.TTL++ - msg, err = NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err = msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - w.SetMaxMessageSize(uint32(env.size() - 1)) - err = w.Send(env) - if err == nil { - t.Fatalf("successfully sent oversized envelope (seed %d): false positive.", seed) - } - - w.SetMaxMessageSize(DefaultMaxMessageSize) - err = w.Send(env) - if err != nil { - t.Fatalf("failed to send second envelope with seed %d: %s.", seed, err) - } - - // wait till received or timeout - var received bool - for j := 0; j < 20; j++ { - time.Sleep(100 * time.Millisecond) - if len(w.Envelopes()) > 1 { - received = true - break - } - } - - if !received { - t.Fatalf("did not receive the sent envelope, seed: %d.", seed) - } - - // check w.messages() - id, err := w.Subscribe(f) - if err != nil { - t.Fatalf("failed subscribe with seed %d: %s.", seed, err) - } - time.Sleep(5 * time.Millisecond) - mail := f.Retrieve() - if len(mail) > 0 { - t.Fatalf("received premature mail") - } - - mail = w.Messages(id) - if len(mail) != 2 { - t.Fatalf("failed to get whisper messages") - } -} - -func TestSymmetricSendCycle(t *testing.T) { - InitSingleTest() - - w := New(&DefaultConfig) - defer w.SetMinimumPoW(DefaultMinimumPoW) - defer w.SetMaxMessageSize(DefaultMaxMessageSize) - w.Start(nil) - defer w.Stop() - - filter1, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - filter1.PoW = DefaultMinimumPoW - - // Copy the first filter since some of its fields - // are randomly gnerated. - filter2 := &Filter{ - KeySym: filter1.KeySym, - Topics: filter1.Topics, - PoW: filter1.PoW, - AllowP2P: filter1.AllowP2P, - Messages: make(map[common.Hash]*ReceivedMessage), - } - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - filter1.Src = ¶ms.Src.PublicKey - filter2.Src = ¶ms.Src.PublicKey - - params.KeySym = filter1.KeySym - params.Topic = BytesToTopic(filter1.Topics[2]) - params.PoW = filter1.PoW - params.WorkTime = 10 - params.TTL = 50 - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - _, err = w.Subscribe(filter1) - if err != nil { - t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err) - } - - _, err = w.Subscribe(filter2) - if err != nil { - t.Fatalf("failed subscribe 2 with seed %d: %s.", seed, err) - } - - err = w.Send(env) - if err != nil { - t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err) - } - - // wait till received or timeout - var received bool - for j := 0; j < 200; j++ { - time.Sleep(10 * time.Millisecond) - if len(w.Envelopes()) > 0 { - received = true - break - } - } - - if !received { - t.Fatalf("did not receive the sent envelope, seed: %d.", seed) - } - - // check w.messages() - time.Sleep(5 * time.Millisecond) - mail1 := filter1.Retrieve() - mail2 := filter2.Retrieve() - if len(mail2) == 0 { - t.Fatalf("did not receive any email for filter 2") - } - if len(mail1) == 0 { - t.Fatalf("did not receive any email for filter 1") - } - -} - -func TestSymmetricSendWithoutAKey(t *testing.T) { - InitSingleTest() - - w := New(&DefaultConfig) - defer w.SetMinimumPoW(DefaultMinimumPoW) - defer w.SetMaxMessageSize(DefaultMaxMessageSize) - w.Start(nil) - defer w.Stop() - - filter, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - filter.PoW = DefaultMinimumPoW - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - filter.Src = nil - - params.KeySym = filter.KeySym - params.Topic = BytesToTopic(filter.Topics[2]) - params.PoW = filter.PoW - params.WorkTime = 10 - params.TTL = 50 - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - _, err = w.Subscribe(filter) - if err != nil { - t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err) - } - - err = w.Send(env) - if err != nil { - t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err) - } - - // wait till received or timeout - var received bool - for j := 0; j < 200; j++ { - time.Sleep(10 * time.Millisecond) - if len(w.Envelopes()) > 0 { - received = true - break - } - } - - if !received { - t.Fatalf("did not receive the sent envelope, seed: %d.", seed) - } - - // check w.messages() - time.Sleep(5 * time.Millisecond) - mail := filter.Retrieve() - if len(mail) == 0 { - t.Fatalf("did not receive message in spite of not setting a public key") - } -} - -func TestSymmetricSendKeyMismatch(t *testing.T) { - InitSingleTest() - - w := New(&DefaultConfig) - defer w.SetMinimumPoW(DefaultMinimumPoW) - defer w.SetMaxMessageSize(DefaultMaxMessageSize) - w.Start(nil) - defer w.Stop() - - filter, err := generateFilter(t, true) - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - filter.PoW = DefaultMinimumPoW - - params, err := generateMessageParams() - if err != nil { - t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) - } - - params.KeySym = filter.KeySym - params.Topic = BytesToTopic(filter.Topics[2]) - params.PoW = filter.PoW - params.WorkTime = 10 - params.TTL = 50 - msg, err := NewSentMessage(params) - if err != nil { - t.Fatalf("failed to create new message with seed %d: %s.", seed, err) - } - env, err := msg.Wrap(params) - if err != nil { - t.Fatalf("failed Wrap with seed %d: %s.", seed, err) - } - - _, err = w.Subscribe(filter) - if err != nil { - t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err) - } - - err = w.Send(env) - if err != nil { - t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err) - } - - // wait till received or timeout - var received bool - for j := 0; j < 200; j++ { - time.Sleep(10 * time.Millisecond) - if len(w.Envelopes()) > 0 { - received = true - break - } - } - - if !received { - t.Fatalf("did not receive the sent envelope, seed: %d.", seed) - } - - // check w.messages() - time.Sleep(5 * time.Millisecond) - mail := filter.Retrieve() - if len(mail) > 0 { - t.Fatalf("received a message when keys weren't matching") - } -} diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/api_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/api_test.go index cdbc7fab..6d7157f5 100644 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/api_test.go +++ b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/api_test.go @@ -18,27 +18,12 @@ package whisperv6 import ( "bytes" - "crypto/ecdsa" "testing" "time" - - mapset "github.com/deckarep/golang-set" - "github.com/ethereum/go-ethereum/common" ) func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) { - w := &Whisper{ - privateKeys: make(map[string]*ecdsa.PrivateKey), - symKeys: make(map[string][]byte), - envelopes: make(map[common.Hash]*Envelope), - expirations: make(map[uint32]mapset.Set), - peers: make(map[*Peer]struct{}), - messageQueue: make(chan *Envelope, messageQueueLimit), - p2pMsgQueue: make(chan *Envelope, messageQueueLimit), - quit: make(chan struct{}), - syncAllowance: DefaultSyncAllowance, - } - w.filters = NewFilters(w) + w := New(nil) keyID, err := w.GenerateSymKey() if err != nil { diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope.go index c42d1fa8..5d9d3508 100644 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope.go +++ b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope.go @@ -27,7 +27,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/rlp" @@ -82,7 +81,7 @@ func (e *Envelope) Seal(options *MessageParams) error { return nil } - var target, bestBit int + var target, bestLeadingZeros int if options.PoW < 0 { // target is not set - the function should run for a period // of time specified in WorkTime param. Since we can predict @@ -101,10 +100,10 @@ func (e *Envelope) Seal(options *MessageParams) error { for i := 0; i < 1024; i++ { binary.BigEndian.PutUint64(buf[56:], nonce) d := new(big.Int).SetBytes(crypto.Keccak256(buf)) - firstBit := math.FirstBitSet(d) - if firstBit > bestBit { - e.Nonce, bestBit = nonce, firstBit - if target > 0 && bestBit >= target { + leadingZeros := 256 - d.BitLen() + if leadingZeros > bestLeadingZeros { + e.Nonce, bestLeadingZeros = nonce, leadingZeros + if target > 0 && bestLeadingZeros >= target { return nil } } @@ -112,7 +111,7 @@ func (e *Envelope) Seal(options *MessageParams) error { } } - if target > 0 && bestBit < target { + if target > 0 && bestLeadingZeros < target { return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) } @@ -130,13 +129,14 @@ func (e *Envelope) PoW() float64 { func (e *Envelope) calculatePoW(diff uint32) { buf := make([]byte, 64) - h := crypto.Keccak256(e.rlpWithoutNonce()) + rlp := e.rlpWithoutNonce() + h := crypto.Keccak256(rlp) copy(buf[:32], h) binary.BigEndian.PutUint64(buf[56:], e.Nonce) - d := new(big.Int).SetBytes(crypto.Keccak256(buf)) - firstBit := math.FirstBitSet(d) - x := gmath.Pow(2, float64(firstBit)) - x /= float64(e.size()) + powHash := new(big.Int).SetBytes(crypto.Keccak256(buf)) + leadingZeroes := 256 - powHash.BitLen() + x := gmath.Pow(2, float64(leadingZeroes)) + x /= float64(len(rlp)) x /= float64(e.TTL + diff) e.pow = x } diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope_test.go index 410b250a..d6e38e68 100644 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope_test.go +++ b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/envelope_test.go @@ -25,6 +25,33 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) +func TestPoWCalculationsWithNoLeadingZeros(t *testing.T) { + e := Envelope{ + TTL: 1, + Data: []byte{0xde, 0xad, 0xbe, 0xef}, + Nonce: 100000, + } + + e.calculatePoW(0) + + if e.pow != 0.07692307692307693 { + t.Fatalf("invalid PoW calculation. Expected 0.07692307692307693, got %v", e.pow) + } +} + +func TestPoWCalculationsWith8LeadingZeros(t *testing.T) { + e := Envelope{ + TTL: 1, + Data: []byte{0xde, 0xad, 0xbe, 0xef}, + Nonce: 48159, + } + e.calculatePoW(0) + + if e.pow != 40329.846153846156 { + t.Fatalf("invalid PoW calculation. Expected 0.07692307692307693, got %v", e.pow) + } +} + func TestEnvelopeOpenAcceptsOnlyOneKeyTypeInFilter(t *testing.T) { symKey := make([]byte, aesKeyLength) mrand.Read(symKey) diff --git a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/peer_test.go b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/peer_test.go index 65e62d96..c5b044e1 100644 --- a/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/peer_test.go +++ b/vendor/github.com/ethereum/go-ethereum/whisper/whisperv6/peer_test.go @@ -232,7 +232,7 @@ func initialize(t *testing.T) { func startServer(t *testing.T, s *p2p.Server) { err := s.Start() if err != nil { - t.Fatalf("failed to start the fisrt server.") + t.Fatalf("failed to start the first server. err: %v", err) } atomic.AddInt64(&result.started, 1) diff --git a/vendor/github.com/go-stack/stack/.travis.yml b/vendor/github.com/go-stack/stack/.travis.yml index e91cc9a0..5c5a2b51 100644 --- a/vendor/github.com/go-stack/stack/.travis.yml +++ b/vendor/github.com/go-stack/stack/.travis.yml @@ -1,9 +1,11 @@ language: go sudo: false go: - - 1.7 - - 1.8 - - 1.9 + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x - tip before_install: diff --git a/vendor/github.com/go-stack/stack/go.mod b/vendor/github.com/go-stack/stack/go.mod new file mode 100644 index 00000000..96a53a10 --- /dev/null +++ b/vendor/github.com/go-stack/stack/go.mod @@ -0,0 +1 @@ +module github.com/go-stack/stack diff --git a/vendor/github.com/go-stack/stack/stack.go b/vendor/github.com/go-stack/stack/stack.go index 1bc6971d..ac3b93b1 100644 --- a/vendor/github.com/go-stack/stack/stack.go +++ b/vendor/github.com/go-stack/stack/stack.go @@ -81,7 +81,9 @@ var ErrNoFunc = errors.New("no call stack information") // // It accepts the '+' and '#' flags for most of the verbs as follows. // -// %+s path of source file relative to the compile time GOPATH +// %+s path of source file relative to the compile time GOPATH, +// or the module path joined to the path of source file relative +// to module root // %#s full path of source file // %+n import path qualified function name // %+k full package path @@ -100,7 +102,7 @@ func (c Call) Format(s fmt.State, verb rune) { case s.Flag('#'): // done case s.Flag('+'): - file = file[pkgIndex(file, c.frame.Function):] + file = pkgFilePath(&c.frame) default: const sep = "/" if i := strings.LastIndex(file, sep); i != -1 { @@ -285,6 +287,80 @@ func pkgIndex(file, funcName string) int { return i + len(sep) } +// pkgFilePath returns the frame's filepath relative to the compile-time GOPATH, +// or its module path joined to its path relative to the module root. +// +// As of Go 1.11 there is no direct way to know the compile time GOPATH or +// module paths at runtime, but we can piece together the desired information +// from available information. We note that runtime.Frame.Function contains the +// function name qualified by the package path, which includes the module path +// but not the GOPATH. We can extract the package path from that and append the +// last segments of the file path to arrive at the desired package qualified +// file path. For example, given: +// +// GOPATH /home/user +// import path pkg/sub +// frame.File /home/user/src/pkg/sub/file.go +// frame.Function pkg/sub.Type.Method +// Desired return pkg/sub/file.go +// +// It appears that we simply need to trim ".Type.Method" from frame.Function and +// append "/" + path.Base(file). +// +// But there are other wrinkles. Although it is idiomatic to do so, the internal +// name of a package is not required to match the last segment of its import +// path. In addition, the introduction of modules in Go 1.11 allows working +// without a GOPATH. So we also must make these work right: +// +// GOPATH /home/user +// import path pkg/go-sub +// package name sub +// frame.File /home/user/src/pkg/go-sub/file.go +// frame.Function pkg/sub.Type.Method +// Desired return pkg/go-sub/file.go +// +// Module path pkg/v2 +// import path pkg/v2/go-sub +// package name sub +// frame.File /home/user/cloned-pkg/go-sub/file.go +// frame.Function pkg/v2/sub.Type.Method +// Desired return pkg/v2/go-sub/file.go +// +// We can handle all of these situations by using the package path extracted +// from frame.Function up to, but not including, the last segment as the prefix +// and the last two segments of frame.File as the suffix of the returned path. +// This preserves the existing behavior when working in a GOPATH without modules +// and a semantically equivalent behavior when used in module aware project. +func pkgFilePath(frame *runtime.Frame) string { + pre := pkgPrefix(frame.Function) + post := pathSuffix(frame.File) + if pre == "" { + return post + } + return pre + "/" + post +} + +// pkgPrefix returns the import path of the function's package with the final +// segment removed. +func pkgPrefix(funcName string) string { + const pathSep = "/" + end := strings.LastIndex(funcName, pathSep) + if end == -1 { + return "" + } + return funcName[:end] +} + +// pathSuffix returns the last two segments of path. +func pathSuffix(path string) string { + const pathSep = "/" + lastSep := strings.LastIndex(path, pathSep) + if lastSep == -1 { + return path + } + return path[strings.LastIndex(path[:lastSep], pathSep)+1:] +} + var runtimePath string func init() { diff --git a/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/bug_report.md b/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..cb9fc37c --- /dev/null +++ b/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**What version of protobuf and what language are you using?** +Version: (e.g., `v1.1.0`, `89a0c16f`, etc) + +**What did you do?** +If possible, provide a recipe for reproducing the error. +A complete runnable program is good with `.proto` and `.go` source code. + +**What did you expect to see?** + +**What did you see instead?** + +Make sure you include information that can help us debug (full error message, exception listing, stack trace, logs). + +**Anything else we should know about your project / environment?** diff --git a/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/feature_request.md b/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..b904f1f8 --- /dev/null +++ b/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/question.md b/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..bfa6ddea --- /dev/null +++ b/vendor/github.com/golang/protobuf/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,7 @@ +--- +name: Question +about: Questions and troubleshooting + +--- + + diff --git a/vendor/github.com/golang/protobuf/.gitignore b/vendor/github.com/golang/protobuf/.gitignore index 8f5b596b..c7dd4058 100644 --- a/vendor/github.com/golang/protobuf/.gitignore +++ b/vendor/github.com/golang/protobuf/.gitignore @@ -12,5 +12,6 @@ core _obj _test _testmain.go -protoc-gen-go/testdata/multi/*.pb.go -_conformance/_conformance + +# Conformance test output and transient files. +conformance/failing_tests.txt diff --git a/vendor/github.com/golang/protobuf/.travis.yml b/vendor/github.com/golang/protobuf/.travis.yml index 93c67805..78949c88 100644 --- a/vendor/github.com/golang/protobuf/.travis.yml +++ b/vendor/github.com/golang/protobuf/.travis.yml @@ -2,17 +2,30 @@ sudo: false language: go go: - 1.6.x -- 1.7.x -- 1.8.x -- 1.9.x +- 1.10.x +- 1.x install: + - go get -v -d google.golang.org/grpc - go get -v -d -t github.com/golang/protobuf/... - - curl -L https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip -o /tmp/protoc.zip - - unzip /tmp/protoc.zip -d $HOME/protoc + - curl -L https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-linux-x86_64.zip -o /tmp/protoc.zip + - unzip /tmp/protoc.zip -d "$HOME"/protoc + - mkdir -p "$HOME"/src && ln -s "$HOME"/protoc "$HOME"/src/protobuf env: - PATH=$HOME/protoc/bin:$PATH script: - - make all test + - make all + - make regenerate + # TODO(tamird): When https://github.com/travis-ci/gimme/pull/130 is + # released, make this look for "1.x". + - if [[ "$TRAVIS_GO_VERSION" == 1.10* ]]; then + if [[ "$(git status --porcelain 2>&1)" != "" ]]; then + git status >&2; + git diff -a >&2; + exit 1; + fi; + echo "git status is clean."; + fi; + - make test diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE index 1b1b1921..0f646931 100644 --- a/vendor/github.com/golang/protobuf/LICENSE +++ b/vendor/github.com/golang/protobuf/LICENSE @@ -1,7 +1,4 @@ -Go support for Protocol Buffers - Google's data interchange format - Copyright 2010 The Go Authors. All rights reserved. -https://github.com/golang/protobuf Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/golang/protobuf/Make.protobuf b/vendor/github.com/golang/protobuf/Make.protobuf deleted file mode 100644 index 15071de1..00000000 --- a/vendor/github.com/golang/protobuf/Make.protobuf +++ /dev/null @@ -1,40 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Includable Makefile to add a rule for generating .pb.go files from .proto files -# (Google protocol buffer descriptions). -# Typical use if myproto.proto is a file in package mypackage in this directory: -# -# include $(GOROOT)/src/pkg/github.com/golang/protobuf/Make.protobuf - -%.pb.go: %.proto - protoc --go_out=. $< - diff --git a/vendor/github.com/golang/protobuf/Makefile b/vendor/github.com/golang/protobuf/Makefile index a1421d8b..7a51c95b 100644 --- a/vendor/github.com/golang/protobuf/Makefile +++ b/vendor/github.com/golang/protobuf/Makefile @@ -29,16 +29,16 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - all: install install: - go install ./proto ./jsonpb ./ptypes - go install ./protoc-gen-go + go install ./proto ./jsonpb ./ptypes ./protoc-gen-go test: - go test ./proto ./jsonpb ./ptypes - make -C protoc-gen-go/testdata test + go test ./... ./protoc-gen-go/testdata + go test -tags purego ./... ./protoc-gen-go/testdata + go build ./protoc-gen-go/testdata/grpc/grpc.pb.go + make -C conformance test clean: go clean ./... @@ -47,9 +47,4 @@ nuke: go clean -i ./... regenerate: - make -C protoc-gen-go/descriptor regenerate - make -C protoc-gen-go/plugin regenerate - make -C protoc-gen-go/testdata regenerate - make -C proto/testdata regenerate - make -C jsonpb/jsonpb_test_proto regenerate - make -C _conformance regenerate + ./regenerate.sh diff --git a/vendor/github.com/golang/protobuf/README.md b/vendor/github.com/golang/protobuf/README.md index 9c4c815c..61820bed 100644 --- a/vendor/github.com/golang/protobuf/README.md +++ b/vendor/github.com/golang/protobuf/README.md @@ -1,4 +1,4 @@ -# Go support for Protocol Buffers +# Go support for Protocol Buffers - Google's data interchange format [![Build Status](https://travis-ci.org/golang/protobuf.svg?branch=master)](https://travis-ci.org/golang/protobuf) [![GoDoc](https://godoc.org/github.com/golang/protobuf?status.svg)](https://godoc.org/github.com/golang/protobuf) @@ -7,7 +7,7 @@ Google's data interchange format. Copyright 2010 The Go Authors. https://github.com/golang/protobuf -This package and the code it generates requires at least Go 1.4. +This package and the code it generates requires at least Go 1.6. This software implements Go bindings for protocol buffers. For information about protocol buffers themselves, see @@ -56,13 +56,53 @@ parameter set to the directory you want to output the Go code to. The generated files will be suffixed .pb.go. See the Test code below for an example using such a file. +## Packages and input paths ## + +The protocol buffer language has a concept of "packages" which does not +correspond well to the Go notion of packages. In generated Go code, +each source `.proto` file is associated with a single Go package. The +name and import path for this package is specified with the `go_package` +proto option: + + option go_package = "github.com/golang/protobuf/ptypes/any"; + +The protocol buffer compiler will attempt to derive a package name and +import path if a `go_package` option is not present, but it is +best to always specify one explicitly. + +There is a one-to-one relationship between source `.proto` files and +generated `.pb.go` files, but any number of `.pb.go` files may be +contained in the same Go package. + +The output name of a generated file is produced by replacing the +`.proto` suffix with `.pb.go` (e.g., `foo.proto` produces `foo.pb.go`). +However, the output directory is selected in one of two ways. Let +us say we have `inputs/x.proto` with a `go_package` option of +`github.com/golang/protobuf/p`. The corresponding output file may +be: + +- Relative to the import path: + +```shell + protoc --go_out=. inputs/x.proto + # writes ./github.com/golang/protobuf/p/x.pb.go +``` + + (This can work well with `--go_out=$GOPATH`.) + +- Relative to the input file: + +```shell +protoc --go_out=paths=source_relative:. inputs/x.proto +# generate ./inputs/x.pb.go +``` + +## Generated code ## The package comment for the proto library contains text describing the interface provided in Go for protocol buffers. Here is an edited version. -========== - The proto package converts data structures to and from the wire format of protocol buffers. It works in concert with the Go source code generated for .proto files by the protocol compiler. @@ -114,16 +154,13 @@ Consider file test.proto, containing ```proto syntax = "proto2"; package example; - + enum FOO { X = 17; }; - + message Test { required string label = 1; optional int32 type = 2 [default=77]; repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } } ``` @@ -140,13 +177,10 @@ To create and play with a Test object from the example package, ) func main() { - test := &example.Test { + test := &example.Test{ Label: proto.String("hello"), Type: proto.Int32(17), Reps: []int64{1, 2, 3}, - Optionalgroup: &example.Test_OptionalGroup { - RequiredField: proto.String("good bye"), - }, } data, err := proto.Marshal(test) if err != nil { @@ -170,22 +204,25 @@ To create and play with a Test object from the example package, To pass extra parameters to the plugin, use a comma-separated parameter list separated from the output directory by a colon: - protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto - -- `import_prefix=xxx` - a prefix that is added onto the beginning of - all imports. Useful for things like generating protos in a - subdirectory, or regenerating vendored protobufs in-place. -- `import_path=foo/bar` - used as the package if no input files - declare `go_package`. If it contains slashes, everything up to the - rightmost slash is ignored. +- `paths=(import | source_relative)` - specifies how the paths of + generated files are structured. See the "Packages and imports paths" + section above. The default is `import`. - `plugins=plugin1+plugin2` - specifies the list of sub-plugins to load. The only plugin in this repo is `grpc`. - `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is associated with Go package quux/shme. This is subject to the import_prefix parameter. +The following parameters are deprecated and should not be used: + +- `import_prefix=xxx` - a prefix that is added onto the beginning of + all imports. +- `import_path=foo/bar` - used as the package if no input files + declare `go_package`. If it contains slashes, everything up to the + rightmost slash is ignored. + ## gRPC Support ## If a proto file specifies RPC services, protoc-gen-go can be instructed to diff --git a/vendor/github.com/golang/protobuf/_conformance/conformance_proto/conformance.pb.go b/vendor/github.com/golang/protobuf/_conformance/conformance_proto/conformance.pb.go deleted file mode 100644 index ec354ead..00000000 --- a/vendor/github.com/golang/protobuf/_conformance/conformance_proto/conformance.pb.go +++ /dev/null @@ -1,1885 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: conformance_proto/conformance.proto - -/* -Package conformance is a generated protocol buffer package. - -It is generated from these files: - conformance_proto/conformance.proto - -It has these top-level messages: - ConformanceRequest - ConformanceResponse - TestAllTypes - ForeignMessage -*/ -package conformance - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/golang/protobuf/ptypes/any" -import google_protobuf1 "github.com/golang/protobuf/ptypes/duration" -import google_protobuf2 "google.golang.org/genproto/protobuf" -import google_protobuf3 "github.com/golang/protobuf/ptypes/struct" -import google_protobuf4 "github.com/golang/protobuf/ptypes/timestamp" -import google_protobuf5 "github.com/golang/protobuf/ptypes/wrappers" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type WireFormat int32 - -const ( - WireFormat_UNSPECIFIED WireFormat = 0 - WireFormat_PROTOBUF WireFormat = 1 - WireFormat_JSON WireFormat = 2 -) - -var WireFormat_name = map[int32]string{ - 0: "UNSPECIFIED", - 1: "PROTOBUF", - 2: "JSON", -} -var WireFormat_value = map[string]int32{ - "UNSPECIFIED": 0, - "PROTOBUF": 1, - "JSON": 2, -} - -func (x WireFormat) String() string { - return proto.EnumName(WireFormat_name, int32(x)) -} -func (WireFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -type ForeignEnum int32 - -const ( - ForeignEnum_FOREIGN_FOO ForeignEnum = 0 - ForeignEnum_FOREIGN_BAR ForeignEnum = 1 - ForeignEnum_FOREIGN_BAZ ForeignEnum = 2 -) - -var ForeignEnum_name = map[int32]string{ - 0: "FOREIGN_FOO", - 1: "FOREIGN_BAR", - 2: "FOREIGN_BAZ", -} -var ForeignEnum_value = map[string]int32{ - "FOREIGN_FOO": 0, - "FOREIGN_BAR": 1, - "FOREIGN_BAZ": 2, -} - -func (x ForeignEnum) String() string { - return proto.EnumName(ForeignEnum_name, int32(x)) -} -func (ForeignEnum) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -type TestAllTypes_NestedEnum int32 - -const ( - TestAllTypes_FOO TestAllTypes_NestedEnum = 0 - TestAllTypes_BAR TestAllTypes_NestedEnum = 1 - TestAllTypes_BAZ TestAllTypes_NestedEnum = 2 - TestAllTypes_NEG TestAllTypes_NestedEnum = -1 -) - -var TestAllTypes_NestedEnum_name = map[int32]string{ - 0: "FOO", - 1: "BAR", - 2: "BAZ", - -1: "NEG", -} -var TestAllTypes_NestedEnum_value = map[string]int32{ - "FOO": 0, - "BAR": 1, - "BAZ": 2, - "NEG": -1, -} - -func (x TestAllTypes_NestedEnum) String() string { - return proto.EnumName(TestAllTypes_NestedEnum_name, int32(x)) -} -func (TestAllTypes_NestedEnum) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} } - -// Represents a single test case's input. The testee should: -// -// 1. parse this proto (which should always succeed) -// 2. parse the protobuf or JSON payload in "payload" (which may fail) -// 3. if the parse succeeded, serialize the message in the requested format. -type ConformanceRequest struct { - // The payload (whether protobuf of JSON) is always for a TestAllTypes proto - // (see below). - // - // Types that are valid to be assigned to Payload: - // *ConformanceRequest_ProtobufPayload - // *ConformanceRequest_JsonPayload - Payload isConformanceRequest_Payload `protobuf_oneof:"payload"` - // Which format should the testee serialize its message to? - RequestedOutputFormat WireFormat `protobuf:"varint,3,opt,name=requested_output_format,json=requestedOutputFormat,enum=conformance.WireFormat" json:"requested_output_format,omitempty"` -} - -func (m *ConformanceRequest) Reset() { *m = ConformanceRequest{} } -func (m *ConformanceRequest) String() string { return proto.CompactTextString(m) } -func (*ConformanceRequest) ProtoMessage() {} -func (*ConformanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -type isConformanceRequest_Payload interface { - isConformanceRequest_Payload() -} - -type ConformanceRequest_ProtobufPayload struct { - ProtobufPayload []byte `protobuf:"bytes,1,opt,name=protobuf_payload,json=protobufPayload,proto3,oneof"` -} -type ConformanceRequest_JsonPayload struct { - JsonPayload string `protobuf:"bytes,2,opt,name=json_payload,json=jsonPayload,oneof"` -} - -func (*ConformanceRequest_ProtobufPayload) isConformanceRequest_Payload() {} -func (*ConformanceRequest_JsonPayload) isConformanceRequest_Payload() {} - -func (m *ConformanceRequest) GetPayload() isConformanceRequest_Payload { - if m != nil { - return m.Payload - } - return nil -} - -func (m *ConformanceRequest) GetProtobufPayload() []byte { - if x, ok := m.GetPayload().(*ConformanceRequest_ProtobufPayload); ok { - return x.ProtobufPayload - } - return nil -} - -func (m *ConformanceRequest) GetJsonPayload() string { - if x, ok := m.GetPayload().(*ConformanceRequest_JsonPayload); ok { - return x.JsonPayload - } - return "" -} - -func (m *ConformanceRequest) GetRequestedOutputFormat() WireFormat { - if m != nil { - return m.RequestedOutputFormat - } - return WireFormat_UNSPECIFIED -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*ConformanceRequest) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _ConformanceRequest_OneofMarshaler, _ConformanceRequest_OneofUnmarshaler, _ConformanceRequest_OneofSizer, []interface{}{ - (*ConformanceRequest_ProtobufPayload)(nil), - (*ConformanceRequest_JsonPayload)(nil), - } -} - -func _ConformanceRequest_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*ConformanceRequest) - // payload - switch x := m.Payload.(type) { - case *ConformanceRequest_ProtobufPayload: - b.EncodeVarint(1<<3 | proto.WireBytes) - b.EncodeRawBytes(x.ProtobufPayload) - case *ConformanceRequest_JsonPayload: - b.EncodeVarint(2<<3 | proto.WireBytes) - b.EncodeStringBytes(x.JsonPayload) - case nil: - default: - return fmt.Errorf("ConformanceRequest.Payload has unexpected type %T", x) - } - return nil -} - -func _ConformanceRequest_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*ConformanceRequest) - switch tag { - case 1: // payload.protobuf_payload - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.Payload = &ConformanceRequest_ProtobufPayload{x} - return true, err - case 2: // payload.json_payload - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Payload = &ConformanceRequest_JsonPayload{x} - return true, err - default: - return false, nil - } -} - -func _ConformanceRequest_OneofSizer(msg proto.Message) (n int) { - m := msg.(*ConformanceRequest) - // payload - switch x := m.Payload.(type) { - case *ConformanceRequest_ProtobufPayload: - n += proto.SizeVarint(1<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.ProtobufPayload))) - n += len(x.ProtobufPayload) - case *ConformanceRequest_JsonPayload: - n += proto.SizeVarint(2<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.JsonPayload))) - n += len(x.JsonPayload) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -// Represents a single test case's output. -type ConformanceResponse struct { - // Types that are valid to be assigned to Result: - // *ConformanceResponse_ParseError - // *ConformanceResponse_SerializeError - // *ConformanceResponse_RuntimeError - // *ConformanceResponse_ProtobufPayload - // *ConformanceResponse_JsonPayload - // *ConformanceResponse_Skipped - Result isConformanceResponse_Result `protobuf_oneof:"result"` -} - -func (m *ConformanceResponse) Reset() { *m = ConformanceResponse{} } -func (m *ConformanceResponse) String() string { return proto.CompactTextString(m) } -func (*ConformanceResponse) ProtoMessage() {} -func (*ConformanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -type isConformanceResponse_Result interface { - isConformanceResponse_Result() -} - -type ConformanceResponse_ParseError struct { - ParseError string `protobuf:"bytes,1,opt,name=parse_error,json=parseError,oneof"` -} -type ConformanceResponse_SerializeError struct { - SerializeError string `protobuf:"bytes,6,opt,name=serialize_error,json=serializeError,oneof"` -} -type ConformanceResponse_RuntimeError struct { - RuntimeError string `protobuf:"bytes,2,opt,name=runtime_error,json=runtimeError,oneof"` -} -type ConformanceResponse_ProtobufPayload struct { - ProtobufPayload []byte `protobuf:"bytes,3,opt,name=protobuf_payload,json=protobufPayload,proto3,oneof"` -} -type ConformanceResponse_JsonPayload struct { - JsonPayload string `protobuf:"bytes,4,opt,name=json_payload,json=jsonPayload,oneof"` -} -type ConformanceResponse_Skipped struct { - Skipped string `protobuf:"bytes,5,opt,name=skipped,oneof"` -} - -func (*ConformanceResponse_ParseError) isConformanceResponse_Result() {} -func (*ConformanceResponse_SerializeError) isConformanceResponse_Result() {} -func (*ConformanceResponse_RuntimeError) isConformanceResponse_Result() {} -func (*ConformanceResponse_ProtobufPayload) isConformanceResponse_Result() {} -func (*ConformanceResponse_JsonPayload) isConformanceResponse_Result() {} -func (*ConformanceResponse_Skipped) isConformanceResponse_Result() {} - -func (m *ConformanceResponse) GetResult() isConformanceResponse_Result { - if m != nil { - return m.Result - } - return nil -} - -func (m *ConformanceResponse) GetParseError() string { - if x, ok := m.GetResult().(*ConformanceResponse_ParseError); ok { - return x.ParseError - } - return "" -} - -func (m *ConformanceResponse) GetSerializeError() string { - if x, ok := m.GetResult().(*ConformanceResponse_SerializeError); ok { - return x.SerializeError - } - return "" -} - -func (m *ConformanceResponse) GetRuntimeError() string { - if x, ok := m.GetResult().(*ConformanceResponse_RuntimeError); ok { - return x.RuntimeError - } - return "" -} - -func (m *ConformanceResponse) GetProtobufPayload() []byte { - if x, ok := m.GetResult().(*ConformanceResponse_ProtobufPayload); ok { - return x.ProtobufPayload - } - return nil -} - -func (m *ConformanceResponse) GetJsonPayload() string { - if x, ok := m.GetResult().(*ConformanceResponse_JsonPayload); ok { - return x.JsonPayload - } - return "" -} - -func (m *ConformanceResponse) GetSkipped() string { - if x, ok := m.GetResult().(*ConformanceResponse_Skipped); ok { - return x.Skipped - } - return "" -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*ConformanceResponse) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _ConformanceResponse_OneofMarshaler, _ConformanceResponse_OneofUnmarshaler, _ConformanceResponse_OneofSizer, []interface{}{ - (*ConformanceResponse_ParseError)(nil), - (*ConformanceResponse_SerializeError)(nil), - (*ConformanceResponse_RuntimeError)(nil), - (*ConformanceResponse_ProtobufPayload)(nil), - (*ConformanceResponse_JsonPayload)(nil), - (*ConformanceResponse_Skipped)(nil), - } -} - -func _ConformanceResponse_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*ConformanceResponse) - // result - switch x := m.Result.(type) { - case *ConformanceResponse_ParseError: - b.EncodeVarint(1<<3 | proto.WireBytes) - b.EncodeStringBytes(x.ParseError) - case *ConformanceResponse_SerializeError: - b.EncodeVarint(6<<3 | proto.WireBytes) - b.EncodeStringBytes(x.SerializeError) - case *ConformanceResponse_RuntimeError: - b.EncodeVarint(2<<3 | proto.WireBytes) - b.EncodeStringBytes(x.RuntimeError) - case *ConformanceResponse_ProtobufPayload: - b.EncodeVarint(3<<3 | proto.WireBytes) - b.EncodeRawBytes(x.ProtobufPayload) - case *ConformanceResponse_JsonPayload: - b.EncodeVarint(4<<3 | proto.WireBytes) - b.EncodeStringBytes(x.JsonPayload) - case *ConformanceResponse_Skipped: - b.EncodeVarint(5<<3 | proto.WireBytes) - b.EncodeStringBytes(x.Skipped) - case nil: - default: - return fmt.Errorf("ConformanceResponse.Result has unexpected type %T", x) - } - return nil -} - -func _ConformanceResponse_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*ConformanceResponse) - switch tag { - case 1: // result.parse_error - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Result = &ConformanceResponse_ParseError{x} - return true, err - case 6: // result.serialize_error - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Result = &ConformanceResponse_SerializeError{x} - return true, err - case 2: // result.runtime_error - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Result = &ConformanceResponse_RuntimeError{x} - return true, err - case 3: // result.protobuf_payload - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.Result = &ConformanceResponse_ProtobufPayload{x} - return true, err - case 4: // result.json_payload - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Result = &ConformanceResponse_JsonPayload{x} - return true, err - case 5: // result.skipped - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Result = &ConformanceResponse_Skipped{x} - return true, err - default: - return false, nil - } -} - -func _ConformanceResponse_OneofSizer(msg proto.Message) (n int) { - m := msg.(*ConformanceResponse) - // result - switch x := m.Result.(type) { - case *ConformanceResponse_ParseError: - n += proto.SizeVarint(1<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.ParseError))) - n += len(x.ParseError) - case *ConformanceResponse_SerializeError: - n += proto.SizeVarint(6<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.SerializeError))) - n += len(x.SerializeError) - case *ConformanceResponse_RuntimeError: - n += proto.SizeVarint(2<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.RuntimeError))) - n += len(x.RuntimeError) - case *ConformanceResponse_ProtobufPayload: - n += proto.SizeVarint(3<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.ProtobufPayload))) - n += len(x.ProtobufPayload) - case *ConformanceResponse_JsonPayload: - n += proto.SizeVarint(4<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.JsonPayload))) - n += len(x.JsonPayload) - case *ConformanceResponse_Skipped: - n += proto.SizeVarint(5<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.Skipped))) - n += len(x.Skipped) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -// This proto includes every type of field in both singular and repeated -// forms. -type TestAllTypes struct { - // Singular - OptionalInt32 int32 `protobuf:"varint,1,opt,name=optional_int32,json=optionalInt32" json:"optional_int32,omitempty"` - OptionalInt64 int64 `protobuf:"varint,2,opt,name=optional_int64,json=optionalInt64" json:"optional_int64,omitempty"` - OptionalUint32 uint32 `protobuf:"varint,3,opt,name=optional_uint32,json=optionalUint32" json:"optional_uint32,omitempty"` - OptionalUint64 uint64 `protobuf:"varint,4,opt,name=optional_uint64,json=optionalUint64" json:"optional_uint64,omitempty"` - OptionalSint32 int32 `protobuf:"zigzag32,5,opt,name=optional_sint32,json=optionalSint32" json:"optional_sint32,omitempty"` - OptionalSint64 int64 `protobuf:"zigzag64,6,opt,name=optional_sint64,json=optionalSint64" json:"optional_sint64,omitempty"` - OptionalFixed32 uint32 `protobuf:"fixed32,7,opt,name=optional_fixed32,json=optionalFixed32" json:"optional_fixed32,omitempty"` - OptionalFixed64 uint64 `protobuf:"fixed64,8,opt,name=optional_fixed64,json=optionalFixed64" json:"optional_fixed64,omitempty"` - OptionalSfixed32 int32 `protobuf:"fixed32,9,opt,name=optional_sfixed32,json=optionalSfixed32" json:"optional_sfixed32,omitempty"` - OptionalSfixed64 int64 `protobuf:"fixed64,10,opt,name=optional_sfixed64,json=optionalSfixed64" json:"optional_sfixed64,omitempty"` - OptionalFloat float32 `protobuf:"fixed32,11,opt,name=optional_float,json=optionalFloat" json:"optional_float,omitempty"` - OptionalDouble float64 `protobuf:"fixed64,12,opt,name=optional_double,json=optionalDouble" json:"optional_double,omitempty"` - OptionalBool bool `protobuf:"varint,13,opt,name=optional_bool,json=optionalBool" json:"optional_bool,omitempty"` - OptionalString string `protobuf:"bytes,14,opt,name=optional_string,json=optionalString" json:"optional_string,omitempty"` - OptionalBytes []byte `protobuf:"bytes,15,opt,name=optional_bytes,json=optionalBytes,proto3" json:"optional_bytes,omitempty"` - OptionalNestedMessage *TestAllTypes_NestedMessage `protobuf:"bytes,18,opt,name=optional_nested_message,json=optionalNestedMessage" json:"optional_nested_message,omitempty"` - OptionalForeignMessage *ForeignMessage `protobuf:"bytes,19,opt,name=optional_foreign_message,json=optionalForeignMessage" json:"optional_foreign_message,omitempty"` - OptionalNestedEnum TestAllTypes_NestedEnum `protobuf:"varint,21,opt,name=optional_nested_enum,json=optionalNestedEnum,enum=conformance.TestAllTypes_NestedEnum" json:"optional_nested_enum,omitempty"` - OptionalForeignEnum ForeignEnum `protobuf:"varint,22,opt,name=optional_foreign_enum,json=optionalForeignEnum,enum=conformance.ForeignEnum" json:"optional_foreign_enum,omitempty"` - OptionalStringPiece string `protobuf:"bytes,24,opt,name=optional_string_piece,json=optionalStringPiece" json:"optional_string_piece,omitempty"` - OptionalCord string `protobuf:"bytes,25,opt,name=optional_cord,json=optionalCord" json:"optional_cord,omitempty"` - RecursiveMessage *TestAllTypes `protobuf:"bytes,27,opt,name=recursive_message,json=recursiveMessage" json:"recursive_message,omitempty"` - // Repeated - RepeatedInt32 []int32 `protobuf:"varint,31,rep,packed,name=repeated_int32,json=repeatedInt32" json:"repeated_int32,omitempty"` - RepeatedInt64 []int64 `protobuf:"varint,32,rep,packed,name=repeated_int64,json=repeatedInt64" json:"repeated_int64,omitempty"` - RepeatedUint32 []uint32 `protobuf:"varint,33,rep,packed,name=repeated_uint32,json=repeatedUint32" json:"repeated_uint32,omitempty"` - RepeatedUint64 []uint64 `protobuf:"varint,34,rep,packed,name=repeated_uint64,json=repeatedUint64" json:"repeated_uint64,omitempty"` - RepeatedSint32 []int32 `protobuf:"zigzag32,35,rep,packed,name=repeated_sint32,json=repeatedSint32" json:"repeated_sint32,omitempty"` - RepeatedSint64 []int64 `protobuf:"zigzag64,36,rep,packed,name=repeated_sint64,json=repeatedSint64" json:"repeated_sint64,omitempty"` - RepeatedFixed32 []uint32 `protobuf:"fixed32,37,rep,packed,name=repeated_fixed32,json=repeatedFixed32" json:"repeated_fixed32,omitempty"` - RepeatedFixed64 []uint64 `protobuf:"fixed64,38,rep,packed,name=repeated_fixed64,json=repeatedFixed64" json:"repeated_fixed64,omitempty"` - RepeatedSfixed32 []int32 `protobuf:"fixed32,39,rep,packed,name=repeated_sfixed32,json=repeatedSfixed32" json:"repeated_sfixed32,omitempty"` - RepeatedSfixed64 []int64 `protobuf:"fixed64,40,rep,packed,name=repeated_sfixed64,json=repeatedSfixed64" json:"repeated_sfixed64,omitempty"` - RepeatedFloat []float32 `protobuf:"fixed32,41,rep,packed,name=repeated_float,json=repeatedFloat" json:"repeated_float,omitempty"` - RepeatedDouble []float64 `protobuf:"fixed64,42,rep,packed,name=repeated_double,json=repeatedDouble" json:"repeated_double,omitempty"` - RepeatedBool []bool `protobuf:"varint,43,rep,packed,name=repeated_bool,json=repeatedBool" json:"repeated_bool,omitempty"` - RepeatedString []string `protobuf:"bytes,44,rep,name=repeated_string,json=repeatedString" json:"repeated_string,omitempty"` - RepeatedBytes [][]byte `protobuf:"bytes,45,rep,name=repeated_bytes,json=repeatedBytes,proto3" json:"repeated_bytes,omitempty"` - RepeatedNestedMessage []*TestAllTypes_NestedMessage `protobuf:"bytes,48,rep,name=repeated_nested_message,json=repeatedNestedMessage" json:"repeated_nested_message,omitempty"` - RepeatedForeignMessage []*ForeignMessage `protobuf:"bytes,49,rep,name=repeated_foreign_message,json=repeatedForeignMessage" json:"repeated_foreign_message,omitempty"` - RepeatedNestedEnum []TestAllTypes_NestedEnum `protobuf:"varint,51,rep,packed,name=repeated_nested_enum,json=repeatedNestedEnum,enum=conformance.TestAllTypes_NestedEnum" json:"repeated_nested_enum,omitempty"` - RepeatedForeignEnum []ForeignEnum `protobuf:"varint,52,rep,packed,name=repeated_foreign_enum,json=repeatedForeignEnum,enum=conformance.ForeignEnum" json:"repeated_foreign_enum,omitempty"` - RepeatedStringPiece []string `protobuf:"bytes,54,rep,name=repeated_string_piece,json=repeatedStringPiece" json:"repeated_string_piece,omitempty"` - RepeatedCord []string `protobuf:"bytes,55,rep,name=repeated_cord,json=repeatedCord" json:"repeated_cord,omitempty"` - // Map - MapInt32Int32 map[int32]int32 `protobuf:"bytes,56,rep,name=map_int32_int32,json=mapInt32Int32" json:"map_int32_int32,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - MapInt64Int64 map[int64]int64 `protobuf:"bytes,57,rep,name=map_int64_int64,json=mapInt64Int64" json:"map_int64_int64,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - MapUint32Uint32 map[uint32]uint32 `protobuf:"bytes,58,rep,name=map_uint32_uint32,json=mapUint32Uint32" json:"map_uint32_uint32,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - MapUint64Uint64 map[uint64]uint64 `protobuf:"bytes,59,rep,name=map_uint64_uint64,json=mapUint64Uint64" json:"map_uint64_uint64,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - MapSint32Sint32 map[int32]int32 `protobuf:"bytes,60,rep,name=map_sint32_sint32,json=mapSint32Sint32" json:"map_sint32_sint32,omitempty" protobuf_key:"zigzag32,1,opt,name=key" protobuf_val:"zigzag32,2,opt,name=value"` - MapSint64Sint64 map[int64]int64 `protobuf:"bytes,61,rep,name=map_sint64_sint64,json=mapSint64Sint64" json:"map_sint64_sint64,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"zigzag64,2,opt,name=value"` - MapFixed32Fixed32 map[uint32]uint32 `protobuf:"bytes,62,rep,name=map_fixed32_fixed32,json=mapFixed32Fixed32" json:"map_fixed32_fixed32,omitempty" protobuf_key:"fixed32,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"` - MapFixed64Fixed64 map[uint64]uint64 `protobuf:"bytes,63,rep,name=map_fixed64_fixed64,json=mapFixed64Fixed64" json:"map_fixed64_fixed64,omitempty" protobuf_key:"fixed64,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"` - MapSfixed32Sfixed32 map[int32]int32 `protobuf:"bytes,64,rep,name=map_sfixed32_sfixed32,json=mapSfixed32Sfixed32" json:"map_sfixed32_sfixed32,omitempty" protobuf_key:"fixed32,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"` - MapSfixed64Sfixed64 map[int64]int64 `protobuf:"bytes,65,rep,name=map_sfixed64_sfixed64,json=mapSfixed64Sfixed64" json:"map_sfixed64_sfixed64,omitempty" protobuf_key:"fixed64,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"` - MapInt32Float map[int32]float32 `protobuf:"bytes,66,rep,name=map_int32_float,json=mapInt32Float" json:"map_int32_float,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"` - MapInt32Double map[int32]float64 `protobuf:"bytes,67,rep,name=map_int32_double,json=mapInt32Double" json:"map_int32_double,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"` - MapBoolBool map[bool]bool `protobuf:"bytes,68,rep,name=map_bool_bool,json=mapBoolBool" json:"map_bool_bool,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - MapStringString map[string]string `protobuf:"bytes,69,rep,name=map_string_string,json=mapStringString" json:"map_string_string,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - MapStringBytes map[string][]byte `protobuf:"bytes,70,rep,name=map_string_bytes,json=mapStringBytes" json:"map_string_bytes,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapStringNestedMessage map[string]*TestAllTypes_NestedMessage `protobuf:"bytes,71,rep,name=map_string_nested_message,json=mapStringNestedMessage" json:"map_string_nested_message,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - MapStringForeignMessage map[string]*ForeignMessage `protobuf:"bytes,72,rep,name=map_string_foreign_message,json=mapStringForeignMessage" json:"map_string_foreign_message,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - MapStringNestedEnum map[string]TestAllTypes_NestedEnum `protobuf:"bytes,73,rep,name=map_string_nested_enum,json=mapStringNestedEnum" json:"map_string_nested_enum,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value,enum=conformance.TestAllTypes_NestedEnum"` - MapStringForeignEnum map[string]ForeignEnum `protobuf:"bytes,74,rep,name=map_string_foreign_enum,json=mapStringForeignEnum" json:"map_string_foreign_enum,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value,enum=conformance.ForeignEnum"` - // Types that are valid to be assigned to OneofField: - // *TestAllTypes_OneofUint32 - // *TestAllTypes_OneofNestedMessage - // *TestAllTypes_OneofString - // *TestAllTypes_OneofBytes - // *TestAllTypes_OneofBool - // *TestAllTypes_OneofUint64 - // *TestAllTypes_OneofFloat - // *TestAllTypes_OneofDouble - // *TestAllTypes_OneofEnum - OneofField isTestAllTypes_OneofField `protobuf_oneof:"oneof_field"` - // Well-known types - OptionalBoolWrapper *google_protobuf5.BoolValue `protobuf:"bytes,201,opt,name=optional_bool_wrapper,json=optionalBoolWrapper" json:"optional_bool_wrapper,omitempty"` - OptionalInt32Wrapper *google_protobuf5.Int32Value `protobuf:"bytes,202,opt,name=optional_int32_wrapper,json=optionalInt32Wrapper" json:"optional_int32_wrapper,omitempty"` - OptionalInt64Wrapper *google_protobuf5.Int64Value `protobuf:"bytes,203,opt,name=optional_int64_wrapper,json=optionalInt64Wrapper" json:"optional_int64_wrapper,omitempty"` - OptionalUint32Wrapper *google_protobuf5.UInt32Value `protobuf:"bytes,204,opt,name=optional_uint32_wrapper,json=optionalUint32Wrapper" json:"optional_uint32_wrapper,omitempty"` - OptionalUint64Wrapper *google_protobuf5.UInt64Value `protobuf:"bytes,205,opt,name=optional_uint64_wrapper,json=optionalUint64Wrapper" json:"optional_uint64_wrapper,omitempty"` - OptionalFloatWrapper *google_protobuf5.FloatValue `protobuf:"bytes,206,opt,name=optional_float_wrapper,json=optionalFloatWrapper" json:"optional_float_wrapper,omitempty"` - OptionalDoubleWrapper *google_protobuf5.DoubleValue `protobuf:"bytes,207,opt,name=optional_double_wrapper,json=optionalDoubleWrapper" json:"optional_double_wrapper,omitempty"` - OptionalStringWrapper *google_protobuf5.StringValue `protobuf:"bytes,208,opt,name=optional_string_wrapper,json=optionalStringWrapper" json:"optional_string_wrapper,omitempty"` - OptionalBytesWrapper *google_protobuf5.BytesValue `protobuf:"bytes,209,opt,name=optional_bytes_wrapper,json=optionalBytesWrapper" json:"optional_bytes_wrapper,omitempty"` - RepeatedBoolWrapper []*google_protobuf5.BoolValue `protobuf:"bytes,211,rep,name=repeated_bool_wrapper,json=repeatedBoolWrapper" json:"repeated_bool_wrapper,omitempty"` - RepeatedInt32Wrapper []*google_protobuf5.Int32Value `protobuf:"bytes,212,rep,name=repeated_int32_wrapper,json=repeatedInt32Wrapper" json:"repeated_int32_wrapper,omitempty"` - RepeatedInt64Wrapper []*google_protobuf5.Int64Value `protobuf:"bytes,213,rep,name=repeated_int64_wrapper,json=repeatedInt64Wrapper" json:"repeated_int64_wrapper,omitempty"` - RepeatedUint32Wrapper []*google_protobuf5.UInt32Value `protobuf:"bytes,214,rep,name=repeated_uint32_wrapper,json=repeatedUint32Wrapper" json:"repeated_uint32_wrapper,omitempty"` - RepeatedUint64Wrapper []*google_protobuf5.UInt64Value `protobuf:"bytes,215,rep,name=repeated_uint64_wrapper,json=repeatedUint64Wrapper" json:"repeated_uint64_wrapper,omitempty"` - RepeatedFloatWrapper []*google_protobuf5.FloatValue `protobuf:"bytes,216,rep,name=repeated_float_wrapper,json=repeatedFloatWrapper" json:"repeated_float_wrapper,omitempty"` - RepeatedDoubleWrapper []*google_protobuf5.DoubleValue `protobuf:"bytes,217,rep,name=repeated_double_wrapper,json=repeatedDoubleWrapper" json:"repeated_double_wrapper,omitempty"` - RepeatedStringWrapper []*google_protobuf5.StringValue `protobuf:"bytes,218,rep,name=repeated_string_wrapper,json=repeatedStringWrapper" json:"repeated_string_wrapper,omitempty"` - RepeatedBytesWrapper []*google_protobuf5.BytesValue `protobuf:"bytes,219,rep,name=repeated_bytes_wrapper,json=repeatedBytesWrapper" json:"repeated_bytes_wrapper,omitempty"` - OptionalDuration *google_protobuf1.Duration `protobuf:"bytes,301,opt,name=optional_duration,json=optionalDuration" json:"optional_duration,omitempty"` - OptionalTimestamp *google_protobuf4.Timestamp `protobuf:"bytes,302,opt,name=optional_timestamp,json=optionalTimestamp" json:"optional_timestamp,omitempty"` - OptionalFieldMask *google_protobuf2.FieldMask `protobuf:"bytes,303,opt,name=optional_field_mask,json=optionalFieldMask" json:"optional_field_mask,omitempty"` - OptionalStruct *google_protobuf3.Struct `protobuf:"bytes,304,opt,name=optional_struct,json=optionalStruct" json:"optional_struct,omitempty"` - OptionalAny *google_protobuf.Any `protobuf:"bytes,305,opt,name=optional_any,json=optionalAny" json:"optional_any,omitempty"` - OptionalValue *google_protobuf3.Value `protobuf:"bytes,306,opt,name=optional_value,json=optionalValue" json:"optional_value,omitempty"` - RepeatedDuration []*google_protobuf1.Duration `protobuf:"bytes,311,rep,name=repeated_duration,json=repeatedDuration" json:"repeated_duration,omitempty"` - RepeatedTimestamp []*google_protobuf4.Timestamp `protobuf:"bytes,312,rep,name=repeated_timestamp,json=repeatedTimestamp" json:"repeated_timestamp,omitempty"` - RepeatedFieldmask []*google_protobuf2.FieldMask `protobuf:"bytes,313,rep,name=repeated_fieldmask,json=repeatedFieldmask" json:"repeated_fieldmask,omitempty"` - RepeatedStruct []*google_protobuf3.Struct `protobuf:"bytes,324,rep,name=repeated_struct,json=repeatedStruct" json:"repeated_struct,omitempty"` - RepeatedAny []*google_protobuf.Any `protobuf:"bytes,315,rep,name=repeated_any,json=repeatedAny" json:"repeated_any,omitempty"` - RepeatedValue []*google_protobuf3.Value `protobuf:"bytes,316,rep,name=repeated_value,json=repeatedValue" json:"repeated_value,omitempty"` - // Test field-name-to-JSON-name convention. - // (protobuf says names can be any valid C/C++ identifier.) - Fieldname1 int32 `protobuf:"varint,401,opt,name=fieldname1" json:"fieldname1,omitempty"` - FieldName2 int32 `protobuf:"varint,402,opt,name=field_name2,json=fieldName2" json:"field_name2,omitempty"` - XFieldName3 int32 `protobuf:"varint,403,opt,name=_field_name3,json=FieldName3" json:"_field_name3,omitempty"` - Field_Name4_ int32 `protobuf:"varint,404,opt,name=field__name4_,json=fieldName4" json:"field__name4_,omitempty"` - Field0Name5 int32 `protobuf:"varint,405,opt,name=field0name5" json:"field0name5,omitempty"` - Field_0Name6 int32 `protobuf:"varint,406,opt,name=field_0_name6,json=field0Name6" json:"field_0_name6,omitempty"` - FieldName7 int32 `protobuf:"varint,407,opt,name=fieldName7" json:"fieldName7,omitempty"` - FieldName8 int32 `protobuf:"varint,408,opt,name=FieldName8" json:"FieldName8,omitempty"` - Field_Name9 int32 `protobuf:"varint,409,opt,name=field_Name9,json=fieldName9" json:"field_Name9,omitempty"` - Field_Name10 int32 `protobuf:"varint,410,opt,name=Field_Name10,json=FieldName10" json:"Field_Name10,omitempty"` - FIELD_NAME11 int32 `protobuf:"varint,411,opt,name=FIELD_NAME11,json=FIELDNAME11" json:"FIELD_NAME11,omitempty"` - FIELDName12 int32 `protobuf:"varint,412,opt,name=FIELD_name12,json=FIELDName12" json:"FIELD_name12,omitempty"` - XFieldName13 int32 `protobuf:"varint,413,opt,name=__field_name13,json=FieldName13" json:"__field_name13,omitempty"` - X_FieldName14 int32 `protobuf:"varint,414,opt,name=__Field_name14,json=FieldName14" json:"__Field_name14,omitempty"` - Field_Name15 int32 `protobuf:"varint,415,opt,name=field__name15,json=fieldName15" json:"field__name15,omitempty"` - Field__Name16 int32 `protobuf:"varint,416,opt,name=field__Name16,json=fieldName16" json:"field__Name16,omitempty"` - FieldName17__ int32 `protobuf:"varint,417,opt,name=field_name17__,json=fieldName17" json:"field_name17__,omitempty"` - FieldName18__ int32 `protobuf:"varint,418,opt,name=Field_name18__,json=FieldName18" json:"Field_name18__,omitempty"` -} - -func (m *TestAllTypes) Reset() { *m = TestAllTypes{} } -func (m *TestAllTypes) String() string { return proto.CompactTextString(m) } -func (*TestAllTypes) ProtoMessage() {} -func (*TestAllTypes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -type isTestAllTypes_OneofField interface { - isTestAllTypes_OneofField() -} - -type TestAllTypes_OneofUint32 struct { - OneofUint32 uint32 `protobuf:"varint,111,opt,name=oneof_uint32,json=oneofUint32,oneof"` -} -type TestAllTypes_OneofNestedMessage struct { - OneofNestedMessage *TestAllTypes_NestedMessage `protobuf:"bytes,112,opt,name=oneof_nested_message,json=oneofNestedMessage,oneof"` -} -type TestAllTypes_OneofString struct { - OneofString string `protobuf:"bytes,113,opt,name=oneof_string,json=oneofString,oneof"` -} -type TestAllTypes_OneofBytes struct { - OneofBytes []byte `protobuf:"bytes,114,opt,name=oneof_bytes,json=oneofBytes,proto3,oneof"` -} -type TestAllTypes_OneofBool struct { - OneofBool bool `protobuf:"varint,115,opt,name=oneof_bool,json=oneofBool,oneof"` -} -type TestAllTypes_OneofUint64 struct { - OneofUint64 uint64 `protobuf:"varint,116,opt,name=oneof_uint64,json=oneofUint64,oneof"` -} -type TestAllTypes_OneofFloat struct { - OneofFloat float32 `protobuf:"fixed32,117,opt,name=oneof_float,json=oneofFloat,oneof"` -} -type TestAllTypes_OneofDouble struct { - OneofDouble float64 `protobuf:"fixed64,118,opt,name=oneof_double,json=oneofDouble,oneof"` -} -type TestAllTypes_OneofEnum struct { - OneofEnum TestAllTypes_NestedEnum `protobuf:"varint,119,opt,name=oneof_enum,json=oneofEnum,enum=conformance.TestAllTypes_NestedEnum,oneof"` -} - -func (*TestAllTypes_OneofUint32) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofNestedMessage) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofString) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofBytes) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofBool) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofUint64) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofFloat) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofDouble) isTestAllTypes_OneofField() {} -func (*TestAllTypes_OneofEnum) isTestAllTypes_OneofField() {} - -func (m *TestAllTypes) GetOneofField() isTestAllTypes_OneofField { - if m != nil { - return m.OneofField - } - return nil -} - -func (m *TestAllTypes) GetOptionalInt32() int32 { - if m != nil { - return m.OptionalInt32 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalInt64() int64 { - if m != nil { - return m.OptionalInt64 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalUint32() uint32 { - if m != nil { - return m.OptionalUint32 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalUint64() uint64 { - if m != nil { - return m.OptionalUint64 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalSint32() int32 { - if m != nil { - return m.OptionalSint32 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalSint64() int64 { - if m != nil { - return m.OptionalSint64 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalFixed32() uint32 { - if m != nil { - return m.OptionalFixed32 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalFixed64() uint64 { - if m != nil { - return m.OptionalFixed64 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalSfixed32() int32 { - if m != nil { - return m.OptionalSfixed32 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalSfixed64() int64 { - if m != nil { - return m.OptionalSfixed64 - } - return 0 -} - -func (m *TestAllTypes) GetOptionalFloat() float32 { - if m != nil { - return m.OptionalFloat - } - return 0 -} - -func (m *TestAllTypes) GetOptionalDouble() float64 { - if m != nil { - return m.OptionalDouble - } - return 0 -} - -func (m *TestAllTypes) GetOptionalBool() bool { - if m != nil { - return m.OptionalBool - } - return false -} - -func (m *TestAllTypes) GetOptionalString() string { - if m != nil { - return m.OptionalString - } - return "" -} - -func (m *TestAllTypes) GetOptionalBytes() []byte { - if m != nil { - return m.OptionalBytes - } - return nil -} - -func (m *TestAllTypes) GetOptionalNestedMessage() *TestAllTypes_NestedMessage { - if m != nil { - return m.OptionalNestedMessage - } - return nil -} - -func (m *TestAllTypes) GetOptionalForeignMessage() *ForeignMessage { - if m != nil { - return m.OptionalForeignMessage - } - return nil -} - -func (m *TestAllTypes) GetOptionalNestedEnum() TestAllTypes_NestedEnum { - if m != nil { - return m.OptionalNestedEnum - } - return TestAllTypes_FOO -} - -func (m *TestAllTypes) GetOptionalForeignEnum() ForeignEnum { - if m != nil { - return m.OptionalForeignEnum - } - return ForeignEnum_FOREIGN_FOO -} - -func (m *TestAllTypes) GetOptionalStringPiece() string { - if m != nil { - return m.OptionalStringPiece - } - return "" -} - -func (m *TestAllTypes) GetOptionalCord() string { - if m != nil { - return m.OptionalCord - } - return "" -} - -func (m *TestAllTypes) GetRecursiveMessage() *TestAllTypes { - if m != nil { - return m.RecursiveMessage - } - return nil -} - -func (m *TestAllTypes) GetRepeatedInt32() []int32 { - if m != nil { - return m.RepeatedInt32 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedInt64() []int64 { - if m != nil { - return m.RepeatedInt64 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedUint32() []uint32 { - if m != nil { - return m.RepeatedUint32 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedUint64() []uint64 { - if m != nil { - return m.RepeatedUint64 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedSint32() []int32 { - if m != nil { - return m.RepeatedSint32 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedSint64() []int64 { - if m != nil { - return m.RepeatedSint64 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedFixed32() []uint32 { - if m != nil { - return m.RepeatedFixed32 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedFixed64() []uint64 { - if m != nil { - return m.RepeatedFixed64 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedSfixed32() []int32 { - if m != nil { - return m.RepeatedSfixed32 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedSfixed64() []int64 { - if m != nil { - return m.RepeatedSfixed64 - } - return nil -} - -func (m *TestAllTypes) GetRepeatedFloat() []float32 { - if m != nil { - return m.RepeatedFloat - } - return nil -} - -func (m *TestAllTypes) GetRepeatedDouble() []float64 { - if m != nil { - return m.RepeatedDouble - } - return nil -} - -func (m *TestAllTypes) GetRepeatedBool() []bool { - if m != nil { - return m.RepeatedBool - } - return nil -} - -func (m *TestAllTypes) GetRepeatedString() []string { - if m != nil { - return m.RepeatedString - } - return nil -} - -func (m *TestAllTypes) GetRepeatedBytes() [][]byte { - if m != nil { - return m.RepeatedBytes - } - return nil -} - -func (m *TestAllTypes) GetRepeatedNestedMessage() []*TestAllTypes_NestedMessage { - if m != nil { - return m.RepeatedNestedMessage - } - return nil -} - -func (m *TestAllTypes) GetRepeatedForeignMessage() []*ForeignMessage { - if m != nil { - return m.RepeatedForeignMessage - } - return nil -} - -func (m *TestAllTypes) GetRepeatedNestedEnum() []TestAllTypes_NestedEnum { - if m != nil { - return m.RepeatedNestedEnum - } - return nil -} - -func (m *TestAllTypes) GetRepeatedForeignEnum() []ForeignEnum { - if m != nil { - return m.RepeatedForeignEnum - } - return nil -} - -func (m *TestAllTypes) GetRepeatedStringPiece() []string { - if m != nil { - return m.RepeatedStringPiece - } - return nil -} - -func (m *TestAllTypes) GetRepeatedCord() []string { - if m != nil { - return m.RepeatedCord - } - return nil -} - -func (m *TestAllTypes) GetMapInt32Int32() map[int32]int32 { - if m != nil { - return m.MapInt32Int32 - } - return nil -} - -func (m *TestAllTypes) GetMapInt64Int64() map[int64]int64 { - if m != nil { - return m.MapInt64Int64 - } - return nil -} - -func (m *TestAllTypes) GetMapUint32Uint32() map[uint32]uint32 { - if m != nil { - return m.MapUint32Uint32 - } - return nil -} - -func (m *TestAllTypes) GetMapUint64Uint64() map[uint64]uint64 { - if m != nil { - return m.MapUint64Uint64 - } - return nil -} - -func (m *TestAllTypes) GetMapSint32Sint32() map[int32]int32 { - if m != nil { - return m.MapSint32Sint32 - } - return nil -} - -func (m *TestAllTypes) GetMapSint64Sint64() map[int64]int64 { - if m != nil { - return m.MapSint64Sint64 - } - return nil -} - -func (m *TestAllTypes) GetMapFixed32Fixed32() map[uint32]uint32 { - if m != nil { - return m.MapFixed32Fixed32 - } - return nil -} - -func (m *TestAllTypes) GetMapFixed64Fixed64() map[uint64]uint64 { - if m != nil { - return m.MapFixed64Fixed64 - } - return nil -} - -func (m *TestAllTypes) GetMapSfixed32Sfixed32() map[int32]int32 { - if m != nil { - return m.MapSfixed32Sfixed32 - } - return nil -} - -func (m *TestAllTypes) GetMapSfixed64Sfixed64() map[int64]int64 { - if m != nil { - return m.MapSfixed64Sfixed64 - } - return nil -} - -func (m *TestAllTypes) GetMapInt32Float() map[int32]float32 { - if m != nil { - return m.MapInt32Float - } - return nil -} - -func (m *TestAllTypes) GetMapInt32Double() map[int32]float64 { - if m != nil { - return m.MapInt32Double - } - return nil -} - -func (m *TestAllTypes) GetMapBoolBool() map[bool]bool { - if m != nil { - return m.MapBoolBool - } - return nil -} - -func (m *TestAllTypes) GetMapStringString() map[string]string { - if m != nil { - return m.MapStringString - } - return nil -} - -func (m *TestAllTypes) GetMapStringBytes() map[string][]byte { - if m != nil { - return m.MapStringBytes - } - return nil -} - -func (m *TestAllTypes) GetMapStringNestedMessage() map[string]*TestAllTypes_NestedMessage { - if m != nil { - return m.MapStringNestedMessage - } - return nil -} - -func (m *TestAllTypes) GetMapStringForeignMessage() map[string]*ForeignMessage { - if m != nil { - return m.MapStringForeignMessage - } - return nil -} - -func (m *TestAllTypes) GetMapStringNestedEnum() map[string]TestAllTypes_NestedEnum { - if m != nil { - return m.MapStringNestedEnum - } - return nil -} - -func (m *TestAllTypes) GetMapStringForeignEnum() map[string]ForeignEnum { - if m != nil { - return m.MapStringForeignEnum - } - return nil -} - -func (m *TestAllTypes) GetOneofUint32() uint32 { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofUint32); ok { - return x.OneofUint32 - } - return 0 -} - -func (m *TestAllTypes) GetOneofNestedMessage() *TestAllTypes_NestedMessage { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofNestedMessage); ok { - return x.OneofNestedMessage - } - return nil -} - -func (m *TestAllTypes) GetOneofString() string { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofString); ok { - return x.OneofString - } - return "" -} - -func (m *TestAllTypes) GetOneofBytes() []byte { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofBytes); ok { - return x.OneofBytes - } - return nil -} - -func (m *TestAllTypes) GetOneofBool() bool { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofBool); ok { - return x.OneofBool - } - return false -} - -func (m *TestAllTypes) GetOneofUint64() uint64 { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofUint64); ok { - return x.OneofUint64 - } - return 0 -} - -func (m *TestAllTypes) GetOneofFloat() float32 { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofFloat); ok { - return x.OneofFloat - } - return 0 -} - -func (m *TestAllTypes) GetOneofDouble() float64 { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofDouble); ok { - return x.OneofDouble - } - return 0 -} - -func (m *TestAllTypes) GetOneofEnum() TestAllTypes_NestedEnum { - if x, ok := m.GetOneofField().(*TestAllTypes_OneofEnum); ok { - return x.OneofEnum - } - return TestAllTypes_FOO -} - -func (m *TestAllTypes) GetOptionalBoolWrapper() *google_protobuf5.BoolValue { - if m != nil { - return m.OptionalBoolWrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalInt32Wrapper() *google_protobuf5.Int32Value { - if m != nil { - return m.OptionalInt32Wrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalInt64Wrapper() *google_protobuf5.Int64Value { - if m != nil { - return m.OptionalInt64Wrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalUint32Wrapper() *google_protobuf5.UInt32Value { - if m != nil { - return m.OptionalUint32Wrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalUint64Wrapper() *google_protobuf5.UInt64Value { - if m != nil { - return m.OptionalUint64Wrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalFloatWrapper() *google_protobuf5.FloatValue { - if m != nil { - return m.OptionalFloatWrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalDoubleWrapper() *google_protobuf5.DoubleValue { - if m != nil { - return m.OptionalDoubleWrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalStringWrapper() *google_protobuf5.StringValue { - if m != nil { - return m.OptionalStringWrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalBytesWrapper() *google_protobuf5.BytesValue { - if m != nil { - return m.OptionalBytesWrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedBoolWrapper() []*google_protobuf5.BoolValue { - if m != nil { - return m.RepeatedBoolWrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedInt32Wrapper() []*google_protobuf5.Int32Value { - if m != nil { - return m.RepeatedInt32Wrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedInt64Wrapper() []*google_protobuf5.Int64Value { - if m != nil { - return m.RepeatedInt64Wrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedUint32Wrapper() []*google_protobuf5.UInt32Value { - if m != nil { - return m.RepeatedUint32Wrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedUint64Wrapper() []*google_protobuf5.UInt64Value { - if m != nil { - return m.RepeatedUint64Wrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedFloatWrapper() []*google_protobuf5.FloatValue { - if m != nil { - return m.RepeatedFloatWrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedDoubleWrapper() []*google_protobuf5.DoubleValue { - if m != nil { - return m.RepeatedDoubleWrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedStringWrapper() []*google_protobuf5.StringValue { - if m != nil { - return m.RepeatedStringWrapper - } - return nil -} - -func (m *TestAllTypes) GetRepeatedBytesWrapper() []*google_protobuf5.BytesValue { - if m != nil { - return m.RepeatedBytesWrapper - } - return nil -} - -func (m *TestAllTypes) GetOptionalDuration() *google_protobuf1.Duration { - if m != nil { - return m.OptionalDuration - } - return nil -} - -func (m *TestAllTypes) GetOptionalTimestamp() *google_protobuf4.Timestamp { - if m != nil { - return m.OptionalTimestamp - } - return nil -} - -func (m *TestAllTypes) GetOptionalFieldMask() *google_protobuf2.FieldMask { - if m != nil { - return m.OptionalFieldMask - } - return nil -} - -func (m *TestAllTypes) GetOptionalStruct() *google_protobuf3.Struct { - if m != nil { - return m.OptionalStruct - } - return nil -} - -func (m *TestAllTypes) GetOptionalAny() *google_protobuf.Any { - if m != nil { - return m.OptionalAny - } - return nil -} - -func (m *TestAllTypes) GetOptionalValue() *google_protobuf3.Value { - if m != nil { - return m.OptionalValue - } - return nil -} - -func (m *TestAllTypes) GetRepeatedDuration() []*google_protobuf1.Duration { - if m != nil { - return m.RepeatedDuration - } - return nil -} - -func (m *TestAllTypes) GetRepeatedTimestamp() []*google_protobuf4.Timestamp { - if m != nil { - return m.RepeatedTimestamp - } - return nil -} - -func (m *TestAllTypes) GetRepeatedFieldmask() []*google_protobuf2.FieldMask { - if m != nil { - return m.RepeatedFieldmask - } - return nil -} - -func (m *TestAllTypes) GetRepeatedStruct() []*google_protobuf3.Struct { - if m != nil { - return m.RepeatedStruct - } - return nil -} - -func (m *TestAllTypes) GetRepeatedAny() []*google_protobuf.Any { - if m != nil { - return m.RepeatedAny - } - return nil -} - -func (m *TestAllTypes) GetRepeatedValue() []*google_protobuf3.Value { - if m != nil { - return m.RepeatedValue - } - return nil -} - -func (m *TestAllTypes) GetFieldname1() int32 { - if m != nil { - return m.Fieldname1 - } - return 0 -} - -func (m *TestAllTypes) GetFieldName2() int32 { - if m != nil { - return m.FieldName2 - } - return 0 -} - -func (m *TestAllTypes) GetXFieldName3() int32 { - if m != nil { - return m.XFieldName3 - } - return 0 -} - -func (m *TestAllTypes) GetField_Name4_() int32 { - if m != nil { - return m.Field_Name4_ - } - return 0 -} - -func (m *TestAllTypes) GetField0Name5() int32 { - if m != nil { - return m.Field0Name5 - } - return 0 -} - -func (m *TestAllTypes) GetField_0Name6() int32 { - if m != nil { - return m.Field_0Name6 - } - return 0 -} - -func (m *TestAllTypes) GetFieldName7() int32 { - if m != nil { - return m.FieldName7 - } - return 0 -} - -func (m *TestAllTypes) GetFieldName8() int32 { - if m != nil { - return m.FieldName8 - } - return 0 -} - -func (m *TestAllTypes) GetField_Name9() int32 { - if m != nil { - return m.Field_Name9 - } - return 0 -} - -func (m *TestAllTypes) GetField_Name10() int32 { - if m != nil { - return m.Field_Name10 - } - return 0 -} - -func (m *TestAllTypes) GetFIELD_NAME11() int32 { - if m != nil { - return m.FIELD_NAME11 - } - return 0 -} - -func (m *TestAllTypes) GetFIELDName12() int32 { - if m != nil { - return m.FIELDName12 - } - return 0 -} - -func (m *TestAllTypes) GetXFieldName13() int32 { - if m != nil { - return m.XFieldName13 - } - return 0 -} - -func (m *TestAllTypes) GetX_FieldName14() int32 { - if m != nil { - return m.X_FieldName14 - } - return 0 -} - -func (m *TestAllTypes) GetField_Name15() int32 { - if m != nil { - return m.Field_Name15 - } - return 0 -} - -func (m *TestAllTypes) GetField__Name16() int32 { - if m != nil { - return m.Field__Name16 - } - return 0 -} - -func (m *TestAllTypes) GetFieldName17__() int32 { - if m != nil { - return m.FieldName17__ - } - return 0 -} - -func (m *TestAllTypes) GetFieldName18__() int32 { - if m != nil { - return m.FieldName18__ - } - return 0 -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*TestAllTypes) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _TestAllTypes_OneofMarshaler, _TestAllTypes_OneofUnmarshaler, _TestAllTypes_OneofSizer, []interface{}{ - (*TestAllTypes_OneofUint32)(nil), - (*TestAllTypes_OneofNestedMessage)(nil), - (*TestAllTypes_OneofString)(nil), - (*TestAllTypes_OneofBytes)(nil), - (*TestAllTypes_OneofBool)(nil), - (*TestAllTypes_OneofUint64)(nil), - (*TestAllTypes_OneofFloat)(nil), - (*TestAllTypes_OneofDouble)(nil), - (*TestAllTypes_OneofEnum)(nil), - } -} - -func _TestAllTypes_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*TestAllTypes) - // oneof_field - switch x := m.OneofField.(type) { - case *TestAllTypes_OneofUint32: - b.EncodeVarint(111<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.OneofUint32)) - case *TestAllTypes_OneofNestedMessage: - b.EncodeVarint(112<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.OneofNestedMessage); err != nil { - return err - } - case *TestAllTypes_OneofString: - b.EncodeVarint(113<<3 | proto.WireBytes) - b.EncodeStringBytes(x.OneofString) - case *TestAllTypes_OneofBytes: - b.EncodeVarint(114<<3 | proto.WireBytes) - b.EncodeRawBytes(x.OneofBytes) - case *TestAllTypes_OneofBool: - t := uint64(0) - if x.OneofBool { - t = 1 - } - b.EncodeVarint(115<<3 | proto.WireVarint) - b.EncodeVarint(t) - case *TestAllTypes_OneofUint64: - b.EncodeVarint(116<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.OneofUint64)) - case *TestAllTypes_OneofFloat: - b.EncodeVarint(117<<3 | proto.WireFixed32) - b.EncodeFixed32(uint64(math.Float32bits(x.OneofFloat))) - case *TestAllTypes_OneofDouble: - b.EncodeVarint(118<<3 | proto.WireFixed64) - b.EncodeFixed64(math.Float64bits(x.OneofDouble)) - case *TestAllTypes_OneofEnum: - b.EncodeVarint(119<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.OneofEnum)) - case nil: - default: - return fmt.Errorf("TestAllTypes.OneofField has unexpected type %T", x) - } - return nil -} - -func _TestAllTypes_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*TestAllTypes) - switch tag { - case 111: // oneof_field.oneof_uint32 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.OneofField = &TestAllTypes_OneofUint32{uint32(x)} - return true, err - case 112: // oneof_field.oneof_nested_message - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(TestAllTypes_NestedMessage) - err := b.DecodeMessage(msg) - m.OneofField = &TestAllTypes_OneofNestedMessage{msg} - return true, err - case 113: // oneof_field.oneof_string - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.OneofField = &TestAllTypes_OneofString{x} - return true, err - case 114: // oneof_field.oneof_bytes - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.OneofField = &TestAllTypes_OneofBytes{x} - return true, err - case 115: // oneof_field.oneof_bool - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.OneofField = &TestAllTypes_OneofBool{x != 0} - return true, err - case 116: // oneof_field.oneof_uint64 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.OneofField = &TestAllTypes_OneofUint64{x} - return true, err - case 117: // oneof_field.oneof_float - if wire != proto.WireFixed32 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed32() - m.OneofField = &TestAllTypes_OneofFloat{math.Float32frombits(uint32(x))} - return true, err - case 118: // oneof_field.oneof_double - if wire != proto.WireFixed64 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed64() - m.OneofField = &TestAllTypes_OneofDouble{math.Float64frombits(x)} - return true, err - case 119: // oneof_field.oneof_enum - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.OneofField = &TestAllTypes_OneofEnum{TestAllTypes_NestedEnum(x)} - return true, err - default: - return false, nil - } -} - -func _TestAllTypes_OneofSizer(msg proto.Message) (n int) { - m := msg.(*TestAllTypes) - // oneof_field - switch x := m.OneofField.(type) { - case *TestAllTypes_OneofUint32: - n += proto.SizeVarint(111<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.OneofUint32)) - case *TestAllTypes_OneofNestedMessage: - s := proto.Size(x.OneofNestedMessage) - n += proto.SizeVarint(112<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *TestAllTypes_OneofString: - n += proto.SizeVarint(113<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.OneofString))) - n += len(x.OneofString) - case *TestAllTypes_OneofBytes: - n += proto.SizeVarint(114<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.OneofBytes))) - n += len(x.OneofBytes) - case *TestAllTypes_OneofBool: - n += proto.SizeVarint(115<<3 | proto.WireVarint) - n += 1 - case *TestAllTypes_OneofUint64: - n += proto.SizeVarint(116<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.OneofUint64)) - case *TestAllTypes_OneofFloat: - n += proto.SizeVarint(117<<3 | proto.WireFixed32) - n += 4 - case *TestAllTypes_OneofDouble: - n += proto.SizeVarint(118<<3 | proto.WireFixed64) - n += 8 - case *TestAllTypes_OneofEnum: - n += proto.SizeVarint(119<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.OneofEnum)) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type TestAllTypes_NestedMessage struct { - A int32 `protobuf:"varint,1,opt,name=a" json:"a,omitempty"` - Corecursive *TestAllTypes `protobuf:"bytes,2,opt,name=corecursive" json:"corecursive,omitempty"` -} - -func (m *TestAllTypes_NestedMessage) Reset() { *m = TestAllTypes_NestedMessage{} } -func (m *TestAllTypes_NestedMessage) String() string { return proto.CompactTextString(m) } -func (*TestAllTypes_NestedMessage) ProtoMessage() {} -func (*TestAllTypes_NestedMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} } - -func (m *TestAllTypes_NestedMessage) GetA() int32 { - if m != nil { - return m.A - } - return 0 -} - -func (m *TestAllTypes_NestedMessage) GetCorecursive() *TestAllTypes { - if m != nil { - return m.Corecursive - } - return nil -} - -type ForeignMessage struct { - C int32 `protobuf:"varint,1,opt,name=c" json:"c,omitempty"` -} - -func (m *ForeignMessage) Reset() { *m = ForeignMessage{} } -func (m *ForeignMessage) String() string { return proto.CompactTextString(m) } -func (*ForeignMessage) ProtoMessage() {} -func (*ForeignMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func (m *ForeignMessage) GetC() int32 { - if m != nil { - return m.C - } - return 0 -} - -func init() { - proto.RegisterType((*ConformanceRequest)(nil), "conformance.ConformanceRequest") - proto.RegisterType((*ConformanceResponse)(nil), "conformance.ConformanceResponse") - proto.RegisterType((*TestAllTypes)(nil), "conformance.TestAllTypes") - proto.RegisterType((*TestAllTypes_NestedMessage)(nil), "conformance.TestAllTypes.NestedMessage") - proto.RegisterType((*ForeignMessage)(nil), "conformance.ForeignMessage") - proto.RegisterEnum("conformance.WireFormat", WireFormat_name, WireFormat_value) - proto.RegisterEnum("conformance.ForeignEnum", ForeignEnum_name, ForeignEnum_value) - proto.RegisterEnum("conformance.TestAllTypes_NestedEnum", TestAllTypes_NestedEnum_name, TestAllTypes_NestedEnum_value) -} - -func init() { proto.RegisterFile("conformance_proto/conformance.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 2737 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x5a, 0xd9, 0x72, 0xdb, 0xc8, - 0xd5, 0x16, 0x08, 0x59, 0x4b, 0x93, 0x92, 0xa8, 0xd6, 0xd6, 0x96, 0x5d, 0x63, 0x58, 0xb2, 0x7f, - 0xd3, 0xf6, 0x8c, 0xac, 0x05, 0x86, 0x65, 0xcf, 0x3f, 0x8e, 0x45, 0x9b, 0xb4, 0xe4, 0x8c, 0x25, - 0x17, 0x64, 0x8d, 0xab, 0x9c, 0x0b, 0x06, 0xa6, 0x20, 0x15, 0xc7, 0x24, 0xc1, 0x01, 0x48, 0x4f, - 0x94, 0xcb, 0xbc, 0x41, 0xf6, 0x7d, 0xbd, 0xcf, 0x7a, 0x93, 0xa4, 0x92, 0xab, 0x54, 0x6e, 0xb2, - 0x27, 0x95, 0x3d, 0x79, 0x85, 0xbc, 0x43, 0x52, 0xbd, 0xa2, 0xbb, 0x01, 0x50, 0xf4, 0x54, 0x0d, - 0x25, 0x1e, 0x7c, 0xfd, 0x9d, 0xd3, 0xe7, 0x1c, 0x7c, 0x2d, 0x1c, 0x18, 0x2c, 0xd7, 0x83, 0xf6, - 0x51, 0x10, 0xb6, 0xbc, 0x76, 0xdd, 0xaf, 0x75, 0xc2, 0xa0, 0x1b, 0xdc, 0x90, 0x2c, 0x2b, 0xc4, - 0x02, 0xf3, 0x92, 0x69, 0xf1, 0xec, 0x71, 0x10, 0x1c, 0x37, 0xfd, 0x1b, 0xe4, 0xd2, 0x8b, 0xde, - 0xd1, 0x0d, 0xaf, 0x7d, 0x42, 0x71, 0x8b, 0x6f, 0xe8, 0x97, 0x0e, 0x7b, 0xa1, 0xd7, 0x6d, 0x04, - 0x6d, 0x76, 0xdd, 0xd2, 0xaf, 0x1f, 0x35, 0xfc, 0xe6, 0x61, 0xad, 0xe5, 0x45, 0x2f, 0x19, 0xe2, - 0xbc, 0x8e, 0x88, 0xba, 0x61, 0xaf, 0xde, 0x65, 0x57, 0x2f, 0xe8, 0x57, 0xbb, 0x8d, 0x96, 0x1f, - 0x75, 0xbd, 0x56, 0x27, 0x2b, 0x80, 0x0f, 0x43, 0xaf, 0xd3, 0xf1, 0xc3, 0x88, 0x5e, 0x5f, 0xfa, - 0x85, 0x01, 0xe0, 0xfd, 0x78, 0x2f, 0xae, 0xff, 0x41, 0xcf, 0x8f, 0xba, 0xf0, 0x3a, 0x28, 0xf2, - 0x15, 0xb5, 0x8e, 0x77, 0xd2, 0x0c, 0xbc, 0x43, 0x64, 0x58, 0x46, 0xa9, 0xb0, 0x3d, 0xe4, 0x4e, - 0xf1, 0x2b, 0x4f, 0xe8, 0x05, 0xb8, 0x0c, 0x0a, 0xef, 0x47, 0x41, 0x5b, 0x00, 0x73, 0x96, 0x51, - 0x1a, 0xdf, 0x1e, 0x72, 0xf3, 0xd8, 0xca, 0x41, 0x7b, 0x60, 0x21, 0xa4, 0xe4, 0xfe, 0x61, 0x2d, - 0xe8, 0x75, 0x3b, 0xbd, 0x6e, 0x8d, 0x78, 0xed, 0x22, 0xd3, 0x32, 0x4a, 0x93, 0xeb, 0x0b, 0x2b, - 0x72, 0x9a, 0x9f, 0x35, 0x42, 0xbf, 0x4a, 0x2e, 0xbb, 0x73, 0x62, 0xdd, 0x1e, 0x59, 0x46, 0xcd, - 0xe5, 0x71, 0x30, 0xca, 0x1c, 0x2e, 0x7d, 0x2a, 0x07, 0x66, 0x94, 0x4d, 0x44, 0x9d, 0xa0, 0x1d, - 0xf9, 0xf0, 0x22, 0xc8, 0x77, 0xbc, 0x30, 0xf2, 0x6b, 0x7e, 0x18, 0x06, 0x21, 0xd9, 0x00, 0x8e, - 0x0b, 0x10, 0x63, 0x05, 0xdb, 0xe0, 0x55, 0x30, 0x15, 0xf9, 0x61, 0xc3, 0x6b, 0x36, 0x3e, 0xc9, - 0x61, 0x23, 0x0c, 0x36, 0x29, 0x2e, 0x50, 0xe8, 0x65, 0x30, 0x11, 0xf6, 0xda, 0x38, 0xc1, 0x0c, - 0xc8, 0xf7, 0x59, 0x60, 0x66, 0x0a, 0x4b, 0x4b, 0x9d, 0x39, 0x68, 0xea, 0x86, 0xd3, 0x52, 0xb7, - 0x08, 0x46, 0xa3, 0x97, 0x8d, 0x4e, 0xc7, 0x3f, 0x44, 0x67, 0xd8, 0x75, 0x6e, 0x28, 0x8f, 0x81, - 0x91, 0xd0, 0x8f, 0x7a, 0xcd, 0xee, 0xd2, 0x7f, 0xaa, 0xa0, 0xf0, 0xd4, 0x8f, 0xba, 0x5b, 0xcd, - 0xe6, 0xd3, 0x93, 0x8e, 0x1f, 0xc1, 0xcb, 0x60, 0x32, 0xe8, 0xe0, 0x5e, 0xf3, 0x9a, 0xb5, 0x46, - 0xbb, 0xbb, 0xb1, 0x4e, 0x12, 0x70, 0xc6, 0x9d, 0xe0, 0xd6, 0x1d, 0x6c, 0xd4, 0x61, 0x8e, 0x4d, - 0xf6, 0x65, 0x2a, 0x30, 0xc7, 0x86, 0x57, 0xc0, 0x94, 0x80, 0xf5, 0x28, 0x1d, 0xde, 0xd5, 0x84, - 0x2b, 0x56, 0x1f, 0x10, 0x6b, 0x02, 0xe8, 0xd8, 0x64, 0x57, 0xc3, 0x2a, 0x50, 0x63, 0x8c, 0x28, - 0x23, 0xde, 0xde, 0x74, 0x0c, 0xdc, 0x4f, 0x32, 0x46, 0x94, 0x11, 0xd7, 0x08, 0xaa, 0x40, 0xc7, - 0x86, 0x57, 0x41, 0x51, 0x00, 0x8f, 0x1a, 0x9f, 0xf0, 0x0f, 0x37, 0xd6, 0xd1, 0xa8, 0x65, 0x94, - 0x46, 0x5d, 0x41, 0x50, 0xa5, 0xe6, 0x24, 0xd4, 0xb1, 0xd1, 0x98, 0x65, 0x94, 0x46, 0x34, 0xa8, - 0x63, 0xc3, 0xeb, 0x60, 0x3a, 0x76, 0xcf, 0x69, 0xc7, 0x2d, 0xa3, 0x34, 0xe5, 0x0a, 0x8e, 0x7d, - 0x66, 0x4f, 0x01, 0x3b, 0x36, 0x02, 0x96, 0x51, 0x2a, 0xea, 0x60, 0xc7, 0x56, 0x52, 0x7f, 0xd4, - 0x0c, 0xbc, 0x2e, 0xca, 0x5b, 0x46, 0x29, 0x17, 0xa7, 0xbe, 0x8a, 0x8d, 0xca, 0xfe, 0x0f, 0x83, - 0xde, 0x8b, 0xa6, 0x8f, 0x0a, 0x96, 0x51, 0x32, 0xe2, 0xfd, 0x3f, 0x20, 0x56, 0xb8, 0x0c, 0xc4, - 0xca, 0xda, 0x8b, 0x20, 0x68, 0xa2, 0x09, 0xcb, 0x28, 0x8d, 0xb9, 0x05, 0x6e, 0x2c, 0x07, 0x41, - 0x53, 0xcd, 0x66, 0x37, 0x6c, 0xb4, 0x8f, 0xd1, 0x24, 0xee, 0x2a, 0x29, 0x9b, 0xc4, 0xaa, 0x44, - 0xf7, 0xe2, 0xa4, 0xeb, 0x47, 0x68, 0x0a, 0xb7, 0x71, 0x1c, 0x5d, 0x19, 0x1b, 0x61, 0x0d, 0x2c, - 0x08, 0x58, 0x9b, 0xde, 0xde, 0x2d, 0x3f, 0x8a, 0xbc, 0x63, 0x1f, 0x41, 0xcb, 0x28, 0xe5, 0xd7, - 0xaf, 0x28, 0x37, 0xb6, 0xdc, 0xa2, 0x2b, 0xbb, 0x04, 0xff, 0x98, 0xc2, 0xdd, 0x39, 0xce, 0xa3, - 0x98, 0xe1, 0x01, 0x40, 0x71, 0x96, 0x82, 0xd0, 0x6f, 0x1c, 0xb7, 0x85, 0x87, 0x19, 0xe2, 0xe1, - 0x9c, 0xe2, 0xa1, 0x4a, 0x31, 0x9c, 0x75, 0x5e, 0x24, 0x53, 0xb1, 0xc3, 0xf7, 0xc0, 0xac, 0x1e, - 0xb7, 0xdf, 0xee, 0xb5, 0xd0, 0x1c, 0x51, 0xa3, 0x4b, 0xa7, 0x05, 0x5d, 0x69, 0xf7, 0x5a, 0x2e, - 0x54, 0x23, 0xc6, 0x36, 0xf8, 0x2e, 0x98, 0x4b, 0x84, 0x4b, 0x88, 0xe7, 0x09, 0x31, 0x4a, 0x8b, - 0x95, 0x90, 0xcd, 0x68, 0x81, 0x12, 0x36, 0x47, 0x62, 0xa3, 0xd5, 0xaa, 0x75, 0x1a, 0x7e, 0xdd, - 0x47, 0x08, 0xd7, 0xac, 0x9c, 0x1b, 0xcb, 0xc5, 0xeb, 0x68, 0xdd, 0x9e, 0xe0, 0xcb, 0xf0, 0x8a, - 0xd4, 0x0a, 0xf5, 0x20, 0x3c, 0x44, 0x67, 0x19, 0xde, 0x88, 0xdb, 0xe1, 0x7e, 0x10, 0x1e, 0xc2, - 0x2a, 0x98, 0x0e, 0xfd, 0x7a, 0x2f, 0x8c, 0x1a, 0xaf, 0x7c, 0x91, 0xd6, 0x73, 0x24, 0xad, 0x67, - 0x33, 0x73, 0xe0, 0x16, 0xc5, 0x1a, 0x9e, 0xce, 0xcb, 0x60, 0x32, 0xf4, 0x3b, 0xbe, 0x87, 0xf3, - 0x48, 0x6f, 0xe6, 0x0b, 0x96, 0x89, 0xd5, 0x86, 0x5b, 0x85, 0xda, 0xc8, 0x30, 0xc7, 0x46, 0x96, - 0x65, 0x62, 0xb5, 0x91, 0x60, 0x54, 0x1b, 0x04, 0x8c, 0xa9, 0xcd, 0x45, 0xcb, 0xc4, 0x6a, 0xc3, - 0xcd, 0xb1, 0xda, 0x28, 0x40, 0xc7, 0x46, 0x4b, 0x96, 0x89, 0xd5, 0x46, 0x06, 0x6a, 0x8c, 0x4c, - 0x6d, 0x96, 0x2d, 0x13, 0xab, 0x0d, 0x37, 0xef, 0x27, 0x19, 0x99, 0xda, 0x5c, 0xb2, 0x4c, 0xac, - 0x36, 0x32, 0x90, 0xaa, 0x8d, 0x00, 0x72, 0x59, 0xb8, 0x6c, 0x99, 0x58, 0x6d, 0xb8, 0x5d, 0x52, - 0x1b, 0x15, 0xea, 0xd8, 0xe8, 0xff, 0x2c, 0x13, 0xab, 0x8d, 0x02, 0xa5, 0x6a, 0x13, 0xbb, 0xe7, - 0xb4, 0x57, 0x2c, 0x13, 0xab, 0x8d, 0x08, 0x40, 0x52, 0x1b, 0x0d, 0xec, 0xd8, 0xa8, 0x64, 0x99, - 0x58, 0x6d, 0x54, 0x30, 0x55, 0x9b, 0x38, 0x08, 0xa2, 0x36, 0x57, 0x2d, 0x13, 0xab, 0x8d, 0x08, - 0x81, 0xab, 0x8d, 0x80, 0x31, 0xb5, 0xb9, 0x66, 0x99, 0x58, 0x6d, 0xb8, 0x39, 0x56, 0x1b, 0x01, - 0x24, 0x6a, 0x73, 0xdd, 0x32, 0xb1, 0xda, 0x70, 0x23, 0x57, 0x9b, 0x38, 0x42, 0xaa, 0x36, 0x6f, - 0x5a, 0x26, 0x56, 0x1b, 0x11, 0x9f, 0x50, 0x9b, 0x98, 0x8d, 0xa8, 0xcd, 0x5b, 0x96, 0x89, 0xd5, - 0x46, 0xd0, 0x71, 0xb5, 0x11, 0x30, 0x4d, 0x6d, 0x56, 0x2d, 0xf3, 0xb5, 0xd4, 0x86, 0xf3, 0x24, - 0xd4, 0x26, 0xce, 0x92, 0xa6, 0x36, 0x6b, 0xc4, 0x43, 0x7f, 0xb5, 0x11, 0xc9, 0x4c, 0xa8, 0x8d, - 0x1e, 0x37, 0x11, 0x85, 0x0d, 0xcb, 0x1c, 0x5c, 0x6d, 0xd4, 0x88, 0xb9, 0xda, 0x24, 0xc2, 0x25, - 0xc4, 0x36, 0x21, 0xee, 0xa3, 0x36, 0x5a, 0xa0, 0x5c, 0x6d, 0xb4, 0x6a, 0x31, 0xb5, 0x71, 0x70, - 0xcd, 0xa8, 0xda, 0xa8, 0x75, 0x13, 0x6a, 0x23, 0xd6, 0x11, 0xb5, 0xb9, 0xc5, 0xf0, 0x46, 0xdc, - 0x0e, 0x44, 0x6d, 0x9e, 0x82, 0xa9, 0x96, 0xd7, 0xa1, 0x02, 0xc1, 0x64, 0x62, 0x93, 0x24, 0xf5, - 0xcd, 0xec, 0x0c, 0x3c, 0xf6, 0x3a, 0x44, 0x3b, 0xc8, 0x47, 0xa5, 0xdd, 0x0d, 0x4f, 0xdc, 0x89, - 0x96, 0x6c, 0x93, 0x58, 0x1d, 0x9b, 0xa9, 0xca, 0xed, 0xc1, 0x58, 0x1d, 0x9b, 0x7c, 0x28, 0xac, - 0xcc, 0x06, 0x9f, 0x83, 0x69, 0xcc, 0x4a, 0xe5, 0x87, 0xab, 0xd0, 0x1d, 0xc2, 0xbb, 0xd2, 0x97, - 0x97, 0x4a, 0x13, 0xfd, 0xa4, 0xcc, 0x38, 0x3c, 0xd9, 0x2a, 0x73, 0x3b, 0x36, 0x17, 0xae, 0xb7, - 0x07, 0xe4, 0x76, 0x6c, 0xfa, 0xa9, 0x72, 0x73, 0x2b, 0xe7, 0xa6, 0x22, 0xc7, 0xb5, 0xee, 0xff, - 0x07, 0xe0, 0xa6, 0x02, 0xb8, 0xaf, 0xc5, 0x2d, 0x5b, 0x65, 0x6e, 0xc7, 0xe6, 0xf2, 0xf8, 0xce, - 0x80, 0xdc, 0x8e, 0xbd, 0xaf, 0xc5, 0x2d, 0x5b, 0xe1, 0xc7, 0xc1, 0x0c, 0xe6, 0x66, 0xda, 0x26, - 0x24, 0xf5, 0x2e, 0x61, 0x5f, 0xed, 0xcb, 0xce, 0x74, 0x96, 0xfd, 0xa0, 0xfc, 0x38, 0x50, 0xd5, - 0xae, 0x78, 0x70, 0x6c, 0xa1, 0xc4, 0x1f, 0x19, 0xd4, 0x83, 0x63, 0xb3, 0x1f, 0x9a, 0x07, 0x61, - 0x87, 0x47, 0x60, 0x8e, 0xe4, 0x87, 0x6f, 0x42, 0x28, 0xf8, 0x3d, 0xe2, 0x63, 0xbd, 0x7f, 0x8e, - 0x18, 0x98, 0xff, 0xa4, 0x5e, 0x70, 0xc8, 0xfa, 0x15, 0xd5, 0x0f, 0xae, 0x04, 0xdf, 0xcb, 0xd6, - 0xc0, 0x7e, 0x1c, 0x9b, 0xff, 0xd4, 0xfd, 0xc4, 0x57, 0xd4, 0xfb, 0x95, 0x1e, 0x1a, 0xe5, 0x41, - 0xef, 0x57, 0x72, 0x9c, 0x68, 0xf7, 0x2b, 0x3d, 0x62, 0x9e, 0x81, 0x62, 0xcc, 0xca, 0xce, 0x98, - 0xfb, 0x84, 0xf6, 0xad, 0xd3, 0x69, 0xe9, 0xe9, 0x43, 0x79, 0x27, 0x5b, 0x8a, 0x11, 0xee, 0x02, - 0xec, 0x89, 0x9c, 0x46, 0xf4, 0x48, 0x7a, 0x40, 0x58, 0xaf, 0xf5, 0x65, 0xc5, 0xe7, 0x14, 0xfe, - 0x9f, 0x52, 0xe6, 0x5b, 0xb1, 0x45, 0xb4, 0x3b, 0x95, 0x42, 0x76, 0x7e, 0x55, 0x06, 0x69, 0x77, - 0x02, 0xa5, 0x9f, 0x52, 0xbb, 0x4b, 0x56, 0x9e, 0x04, 0xc6, 0x4d, 0x8f, 0xbc, 0xea, 0x00, 0x49, - 0xa0, 0xcb, 0xc9, 0x69, 0x18, 0x27, 0x41, 0x32, 0xc2, 0x0e, 0x38, 0x2b, 0x11, 0x6b, 0x87, 0xe4, - 0x43, 0xe2, 0xe1, 0xe6, 0x00, 0x1e, 0x94, 0x63, 0x91, 0x7a, 0x9a, 0x6f, 0xa5, 0x5e, 0x84, 0x11, - 0x58, 0x94, 0x3c, 0xea, 0xa7, 0xe6, 0x36, 0x71, 0xe9, 0x0c, 0xe0, 0x52, 0x3d, 0x33, 0xa9, 0xcf, - 0x85, 0x56, 0xfa, 0x55, 0x78, 0x0c, 0xe6, 0x93, 0xdb, 0x24, 0x47, 0xdf, 0xce, 0x20, 0xf7, 0x80, - 0xb4, 0x0d, 0x7c, 0xf4, 0x49, 0xf7, 0x80, 0x76, 0x05, 0xbe, 0x0f, 0x16, 0x52, 0x76, 0x47, 0x3c, - 0x3d, 0x22, 0x9e, 0x36, 0x06, 0xdf, 0x5a, 0xec, 0x6a, 0xb6, 0x95, 0x72, 0x09, 0x2e, 0x83, 0x42, - 0xd0, 0xf6, 0x83, 0x23, 0x7e, 0xdc, 0x04, 0xf8, 0x11, 0x7b, 0x7b, 0xc8, 0xcd, 0x13, 0x2b, 0x3b, - 0x3c, 0x3e, 0x06, 0x66, 0x29, 0x48, 0xab, 0x6d, 0xe7, 0xb5, 0x1e, 0xb7, 0xb6, 0x87, 0x5c, 0x48, - 0x68, 0xd4, 0x5a, 0x8a, 0x08, 0x58, 0xb7, 0x7f, 0xc0, 0x27, 0x12, 0xc4, 0xca, 0x7a, 0xf7, 0x22, - 0xa0, 0x5f, 0x59, 0xdb, 0x86, 0x6c, 0xbc, 0x01, 0x88, 0x91, 0x76, 0xe1, 0x05, 0x00, 0x18, 0x04, - 0xdf, 0x87, 0x11, 0x7e, 0x10, 0xdd, 0x1e, 0x72, 0xc7, 0x29, 0x02, 0xdf, 0x5b, 0xca, 0x56, 0x1d, - 0x1b, 0x75, 0x2d, 0xa3, 0x34, 0xac, 0x6c, 0xd5, 0xb1, 0x63, 0x47, 0x54, 0x7b, 0x7a, 0xf8, 0xf1, - 0x58, 0x38, 0xa2, 0x62, 0x22, 0x78, 0x98, 0x90, 0xbc, 0xc2, 0x8f, 0xc6, 0x82, 0x87, 0x09, 0x43, - 0x85, 0x47, 0x43, 0xca, 0xf6, 0xe1, 0xe0, 0x8f, 0x78, 0x22, 0x66, 0x52, 0x9e, 0x3d, 0xe9, 0x69, - 0x8c, 0x88, 0x0c, 0x9b, 0xa6, 0xa1, 0x5f, 0x19, 0x24, 0xf7, 0x8b, 0x2b, 0x74, 0xdc, 0xb6, 0xc2, - 0xe7, 0x3c, 0x2b, 0x78, 0xab, 0xef, 0x79, 0xcd, 0x9e, 0x1f, 0x3f, 0xa6, 0x61, 0xd3, 0x33, 0xba, - 0x0e, 0xba, 0x60, 0x5e, 0x9d, 0xd1, 0x08, 0xc6, 0x5f, 0x1b, 0xec, 0xd1, 0x56, 0x67, 0x24, 0x7a, - 0x47, 0x29, 0x67, 0x95, 0x49, 0x4e, 0x06, 0xa7, 0x63, 0x0b, 0xce, 0xdf, 0xf4, 0xe1, 0x74, 0xec, - 0x24, 0xa7, 0x63, 0x73, 0xce, 0x03, 0xe9, 0x21, 0xbf, 0xa7, 0x06, 0xfa, 0x5b, 0x4a, 0x7a, 0x3e, - 0x41, 0x7a, 0x20, 0x45, 0x3a, 0xa7, 0x0e, 0x89, 0xb2, 0x68, 0xa5, 0x58, 0x7f, 0xd7, 0x8f, 0x96, - 0x07, 0x3b, 0xa7, 0x8e, 0x94, 0xd2, 0x32, 0x40, 0x1a, 0x47, 0xb0, 0xfe, 0x3e, 0x2b, 0x03, 0xa4, - 0x97, 0xb4, 0x0c, 0x10, 0x5b, 0x5a, 0xa8, 0xb4, 0xd3, 0x04, 0xe9, 0x1f, 0xb2, 0x42, 0xa5, 0xcd, - 0xa7, 0x85, 0x4a, 0x8d, 0x69, 0xb4, 0x4c, 0x61, 0x38, 0xed, 0x1f, 0xb3, 0x68, 0xe9, 0x4d, 0xa8, - 0xd1, 0x52, 0x63, 0x5a, 0x06, 0xc8, 0x3d, 0x2a, 0x58, 0xff, 0x94, 0x95, 0x01, 0x72, 0xdb, 0x6a, - 0x19, 0x20, 0x36, 0xce, 0xb9, 0x27, 0x3d, 0x1c, 0x28, 0xcd, 0xff, 0x67, 0x83, 0xc8, 0x60, 0xdf, - 0xe6, 0x97, 0x1f, 0x0a, 0xa5, 0x20, 0xd5, 0x91, 0x81, 0x60, 0xfc, 0x8b, 0xc1, 0x9e, 0xb4, 0xfa, - 0x35, 0xbf, 0x32, 0x58, 0xc8, 0xe0, 0x94, 0x1a, 0xea, 0xaf, 0x7d, 0x38, 0x45, 0xf3, 0x2b, 0x53, - 0x08, 0xa9, 0x46, 0xda, 0x30, 0x42, 0x90, 0xfe, 0x8d, 0x92, 0x9e, 0xd2, 0xfc, 0xea, 0xcc, 0x22, - 0x8b, 0x56, 0x8a, 0xf5, 0xef, 0xfd, 0x68, 0x45, 0xf3, 0xab, 0x13, 0x8e, 0xb4, 0x0c, 0xa8, 0xcd, - 0xff, 0x8f, 0xac, 0x0c, 0xc8, 0xcd, 0xaf, 0x0c, 0x03, 0xd2, 0x42, 0xd5, 0x9a, 0xff, 0x9f, 0x59, - 0xa1, 0x2a, 0xcd, 0xaf, 0x8e, 0x0e, 0xd2, 0x68, 0xb5, 0xe6, 0xff, 0x57, 0x16, 0xad, 0xd2, 0xfc, - 0xea, 0xb3, 0x68, 0x5a, 0x06, 0xd4, 0xe6, 0xff, 0x77, 0x56, 0x06, 0xe4, 0xe6, 0x57, 0x06, 0x0e, - 0x9c, 0xf3, 0xa1, 0x34, 0xd7, 0xe5, 0xef, 0x70, 0xd0, 0x77, 0x73, 0x6c, 0x4e, 0x96, 0xd8, 0x3b, - 0x43, 0xc4, 0x33, 0x5f, 0x6e, 0x81, 0x8f, 0x80, 0x18, 0x1a, 0xd6, 0xc4, 0xcb, 0x1a, 0xf4, 0xbd, - 0x5c, 0xc6, 0xf9, 0xf1, 0x94, 0x43, 0x5c, 0xe1, 0x5f, 0x98, 0xe0, 0x47, 0xc1, 0x8c, 0x34, 0xc4, - 0xe6, 0x2f, 0x8e, 0xd0, 0xf7, 0xb3, 0xc8, 0xaa, 0x18, 0xf3, 0xd8, 0x8b, 0x5e, 0xc6, 0x64, 0xc2, - 0x04, 0xb7, 0xd4, 0xb9, 0x70, 0xaf, 0xde, 0x45, 0x3f, 0xa0, 0x44, 0x0b, 0x69, 0x45, 0xe8, 0xd5, - 0xbb, 0xca, 0xc4, 0xb8, 0x57, 0xef, 0xc2, 0x4d, 0x20, 0x66, 0x8b, 0x35, 0xaf, 0x7d, 0x82, 0x7e, - 0x48, 0xd7, 0xcf, 0x26, 0xd6, 0x6f, 0xb5, 0x4f, 0xdc, 0x3c, 0x87, 0x6e, 0xb5, 0x4f, 0xe0, 0x5d, - 0x69, 0xd6, 0xfc, 0x0a, 0x97, 0x01, 0xfd, 0x88, 0xae, 0x9d, 0x4f, 0xac, 0xa5, 0x55, 0x12, 0xd3, - 0x4d, 0xf2, 0x15, 0x97, 0x27, 0x6e, 0x50, 0x5e, 0x9e, 0x1f, 0xe7, 0x48, 0xb5, 0xfb, 0x95, 0x47, - 0xf4, 0xa5, 0x54, 0x1e, 0x41, 0x14, 0x97, 0xe7, 0x27, 0xb9, 0x0c, 0x85, 0x93, 0xca, 0xc3, 0x97, - 0xc5, 0xe5, 0x91, 0xb9, 0x48, 0x79, 0x48, 0x75, 0x7e, 0x9a, 0xc5, 0x25, 0x55, 0x27, 0x1e, 0x0a, - 0xb2, 0x55, 0xb8, 0x3a, 0xf2, 0xad, 0x82, 0xab, 0xf3, 0x4b, 0x4a, 0x94, 0x5d, 0x1d, 0xe9, 0xee, - 0x60, 0xd5, 0x11, 0x14, 0xb8, 0x3a, 0x3f, 0xa3, 0xeb, 0x33, 0xaa, 0xc3, 0xa1, 0xac, 0x3a, 0x62, - 0x25, 0xad, 0xce, 0xcf, 0xe9, 0xda, 0xcc, 0xea, 0x70, 0x38, 0xad, 0xce, 0x05, 0x00, 0xc8, 0xfe, - 0xdb, 0x5e, 0xcb, 0x5f, 0x43, 0x9f, 0x36, 0xc9, 0x6b, 0x28, 0xc9, 0x04, 0x2d, 0x90, 0xa7, 0xfd, - 0x8b, 0xbf, 0xae, 0xa3, 0xcf, 0xc8, 0x88, 0x5d, 0x6c, 0x82, 0x17, 0x41, 0xa1, 0x16, 0x43, 0x36, - 0xd0, 0x67, 0x19, 0xa4, 0xca, 0x21, 0x1b, 0x70, 0x09, 0x4c, 0x50, 0x04, 0x81, 0xd8, 0x35, 0xf4, - 0x39, 0x9d, 0x86, 0xfc, 0x3d, 0x49, 0xbe, 0xad, 0x62, 0xc8, 0x4d, 0xf4, 0x79, 0x8a, 0x90, 0x6d, - 0x70, 0x99, 0xd3, 0xac, 0x12, 0x1e, 0x07, 0x7d, 0x41, 0x01, 0x61, 0x1e, 0x47, 0xec, 0x08, 0x7f, - 0xbb, 0x85, 0xbe, 0xa8, 0x3b, 0xba, 0x85, 0x01, 0x22, 0xb4, 0x4d, 0xf4, 0x25, 0x3d, 0xda, 0xcd, - 0x78, 0xcb, 0xf8, 0xeb, 0x6d, 0xf4, 0x65, 0x9d, 0xe2, 0x36, 0x5c, 0x02, 0x85, 0xaa, 0x40, 0xac, - 0xad, 0xa2, 0xaf, 0xb0, 0x38, 0x04, 0xc9, 0xda, 0x2a, 0xc1, 0xec, 0x54, 0xde, 0x7d, 0x50, 0xdb, - 0xdd, 0x7a, 0x5c, 0x59, 0x5b, 0x43, 0x5f, 0xe5, 0x18, 0x6c, 0xa4, 0xb6, 0x18, 0x43, 0x72, 0xbd, - 0x8e, 0xbe, 0xa6, 0x60, 0x88, 0x0d, 0x5e, 0x02, 0x93, 0x35, 0x29, 0xbf, 0x6b, 0x1b, 0xe8, 0xeb, - 0x09, 0x6f, 0x1b, 0x14, 0x55, 0x8d, 0x51, 0x36, 0xfa, 0x46, 0x02, 0x65, 0xc7, 0x09, 0xa4, 0xa0, - 0x9b, 0xe8, 0x9b, 0x72, 0x02, 0x09, 0x48, 0xca, 0x32, 0xdd, 0x9d, 0x83, 0xbe, 0x95, 0x00, 0x39, - 0xd8, 0x9f, 0x14, 0xd3, 0xad, 0x5a, 0x0d, 0x7d, 0x3b, 0x81, 0xba, 0x85, 0x51, 0x52, 0x4c, 0x9b, - 0xb5, 0x1a, 0xfa, 0x4e, 0x22, 0xaa, 0xcd, 0xc5, 0xe7, 0x60, 0x42, 0x7d, 0xd0, 0x29, 0x00, 0xc3, - 0x63, 0x6f, 0x44, 0x0d, 0x0f, 0xbe, 0x0d, 0xf2, 0xf5, 0x40, 0xbc, 0xd4, 0x40, 0xb9, 0xd3, 0x5e, - 0x80, 0xc8, 0xe8, 0xc5, 0x7b, 0x00, 0x26, 0x87, 0x94, 0xb0, 0x08, 0xcc, 0x97, 0xfe, 0x09, 0x73, - 0x81, 0x7f, 0x85, 0xb3, 0xe0, 0x0c, 0xbd, 0x7d, 0x72, 0xc4, 0x46, 0xbf, 0xdc, 0xc9, 0x6d, 0x1a, - 0x31, 0x83, 0x3c, 0x90, 0x94, 0x19, 0xcc, 0x14, 0x06, 0x53, 0x66, 0x28, 0x83, 0xd9, 0xb4, 0xd1, - 0xa3, 0xcc, 0x31, 0x91, 0xc2, 0x31, 0x91, 0xce, 0xa1, 0x8c, 0x18, 0x65, 0x8e, 0xe1, 0x14, 0x8e, - 0xe1, 0x24, 0x47, 0x62, 0x94, 0x28, 0x73, 0x4c, 0xa7, 0x70, 0x4c, 0xa7, 0x73, 0x28, 0x23, 0x43, - 0x99, 0x03, 0xa6, 0x70, 0x40, 0x99, 0xe3, 0x01, 0x98, 0x4f, 0x1f, 0x0c, 0xca, 0x2c, 0xa3, 0x29, - 0x2c, 0xa3, 0x19, 0x2c, 0xea, 0xf0, 0x4f, 0x66, 0x19, 0x49, 0x61, 0x19, 0x91, 0x59, 0xaa, 0x00, - 0x65, 0x8d, 0xf7, 0x64, 0x9e, 0xa9, 0x14, 0x9e, 0xa9, 0x2c, 0x1e, 0x6d, 0x7c, 0x27, 0xf3, 0x14, - 0x53, 0x78, 0x8a, 0xa9, 0xdd, 0x26, 0x0f, 0xe9, 0x4e, 0xeb, 0xd7, 0x9c, 0xcc, 0xb0, 0x05, 0x66, - 0x52, 0xe6, 0x71, 0xa7, 0x51, 0x18, 0x32, 0xc5, 0x5d, 0x50, 0xd4, 0x87, 0x6f, 0xf2, 0xfa, 0xb1, - 0x94, 0xf5, 0x63, 0x29, 0x4d, 0xa2, 0x0f, 0xda, 0x64, 0x8e, 0xf1, 0x14, 0x8e, 0xf1, 0xe4, 0x36, - 0xf4, 0x89, 0xda, 0x69, 0x14, 0x05, 0x99, 0x22, 0x04, 0xe7, 0xfa, 0x8c, 0xcc, 0x52, 0xa8, 0xde, - 0x91, 0xa9, 0x5e, 0xe3, 0x7d, 0x95, 0xe4, 0xf3, 0x18, 0x9c, 0xef, 0x37, 0x33, 0x4b, 0x71, 0xba, - 0xa6, 0x3a, 0xed, 0xfb, 0x0a, 0x4b, 0x72, 0xd4, 0xa4, 0x0d, 0x97, 0x36, 0x2b, 0x4b, 0x71, 0x72, - 0x47, 0x76, 0x32, 0xe8, 0x4b, 0x2d, 0xc9, 0x9b, 0x07, 0xce, 0x66, 0xce, 0xcb, 0x52, 0xdc, 0xad, - 0xa8, 0xee, 0xb2, 0x5f, 0x75, 0xc5, 0x2e, 0x96, 0x6e, 0x03, 0x20, 0x4d, 0xf6, 0x46, 0x81, 0x59, - 0xdd, 0xdb, 0x2b, 0x0e, 0xe1, 0x5f, 0xca, 0x5b, 0x6e, 0xd1, 0xa0, 0xbf, 0x3c, 0x2f, 0xe6, 0xb0, - 0xbb, 0xdd, 0xca, 0xc3, 0xe2, 0x7f, 0xf9, 0x7f, 0x46, 0x79, 0x42, 0x8c, 0xa2, 0xf0, 0xa9, 0xb2, - 0xf4, 0x06, 0x98, 0xd4, 0x06, 0x92, 0x05, 0x60, 0xd4, 0xf9, 0x81, 0x52, 0xbf, 0x76, 0x13, 0x80, - 0xf8, 0xdf, 0x30, 0xc1, 0x29, 0x90, 0x3f, 0xd8, 0xdd, 0x7f, 0x52, 0xb9, 0xbf, 0x53, 0xdd, 0xa9, - 0x3c, 0x28, 0x0e, 0xc1, 0x02, 0x18, 0x7b, 0xe2, 0xee, 0x3d, 0xdd, 0x2b, 0x1f, 0x54, 0x8b, 0x06, - 0x1c, 0x03, 0xc3, 0x8f, 0xf6, 0xf7, 0x76, 0x8b, 0xb9, 0x6b, 0xf7, 0x40, 0x5e, 0x9e, 0x07, 0x4e, - 0x81, 0x7c, 0x75, 0xcf, 0xad, 0xec, 0x3c, 0xdc, 0xad, 0xd1, 0x48, 0x25, 0x03, 0x8d, 0x58, 0x31, - 0x3c, 0x2f, 0xe6, 0xca, 0x17, 0xc1, 0x85, 0x7a, 0xd0, 0x4a, 0xfc, 0x61, 0x26, 0x25, 0xe7, 0xc5, - 0x08, 0xb1, 0x6e, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x33, 0xc2, 0x0c, 0xb6, 0xeb, 0x26, 0x00, - 0x00, -} diff --git a/vendor/github.com/golang/protobuf/_conformance/Makefile b/vendor/github.com/golang/protobuf/conformance/Makefile similarity index 76% rename from vendor/github.com/golang/protobuf/_conformance/Makefile rename to vendor/github.com/golang/protobuf/conformance/Makefile index 89800e2d..b99e4ed6 100644 --- a/vendor/github.com/golang/protobuf/_conformance/Makefile +++ b/vendor/github.com/golang/protobuf/conformance/Makefile @@ -29,5 +29,21 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -regenerate: - protoc --go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any,Mgoogle/protobuf/duration.proto=github.com/golang/protobuf/ptypes/duration,Mgoogle/protobuf/struct.proto=github.com/golang/protobuf/ptypes/struct,Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,Mgoogle/protobuf/wrappers.proto=github.com/golang/protobuf/ptypes/wrappers,Mgoogle/protobuf/field_mask.proto=google.golang.org/genproto/protobuf:. conformance_proto/conformance.proto +PROTOBUF_ROOT=$(HOME)/src/protobuf + +all: + @echo To run the tests in this directory, acquire the main protobuf + @echo distribution from: + @echo + @echo ' https://github.com/google/protobuf' + @echo + @echo Build the test runner with: + @echo + @echo ' cd conformance && make conformance-test-runner' + @echo + @echo And run the tests in this directory with: + @echo + @echo ' make test PROTOBUF_ROOT=' + +test: + ./test.sh $(PROTOBUF_ROOT) diff --git a/vendor/github.com/golang/protobuf/_conformance/conformance.go b/vendor/github.com/golang/protobuf/conformance/conformance.go similarity index 94% rename from vendor/github.com/golang/protobuf/_conformance/conformance.go rename to vendor/github.com/golang/protobuf/conformance/conformance.go index c54212c8..3029312a 100644 --- a/vendor/github.com/golang/protobuf/_conformance/conformance.go +++ b/vendor/github.com/golang/protobuf/conformance/conformance.go @@ -39,7 +39,7 @@ import ( "io" "os" - pb "github.com/golang/protobuf/_conformance/conformance_proto" + pb "github.com/golang/protobuf/conformance/internal/conformance_proto" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" ) @@ -101,13 +101,6 @@ func handle(req *pb.ConformanceRequest) *pb.ConformanceResponse { err = proto.Unmarshal(p.ProtobufPayload, &msg) case *pb.ConformanceRequest_JsonPayload: err = jsonpb.UnmarshalString(p.JsonPayload, &msg) - if err != nil && err.Error() == "unmarshaling Any not supported yet" { - return &pb.ConformanceResponse{ - Result: &pb.ConformanceResponse_Skipped{ - Skipped: err.Error(), - }, - } - } default: return &pb.ConformanceResponse{ Result: &pb.ConformanceResponse_RuntimeError{ diff --git a/vendor/github.com/golang/protobuf/conformance/conformance.sh b/vendor/github.com/golang/protobuf/conformance/conformance.sh new file mode 100755 index 00000000..8532f571 --- /dev/null +++ b/vendor/github.com/golang/protobuf/conformance/conformance.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd $(dirname $0) +exec go run conformance.go $* diff --git a/vendor/github.com/golang/protobuf/conformance/failure_list_go.txt b/vendor/github.com/golang/protobuf/conformance/failure_list_go.txt new file mode 100644 index 00000000..d3728089 --- /dev/null +++ b/vendor/github.com/golang/protobuf/conformance/failure_list_go.txt @@ -0,0 +1,61 @@ +# This is the list of conformance tests that are known ot fail right now. +# TODO: These should be fixed. + +DurationProtoInputTooLarge.JsonOutput +DurationProtoInputTooSmall.JsonOutput +FieldMaskNumbersDontRoundTrip.JsonOutput +FieldMaskPathsDontRoundTrip.JsonOutput +FieldMaskTooManyUnderscore.JsonOutput +JsonInput.AnyWithFieldMask.JsonOutput +JsonInput.AnyWithFieldMask.ProtobufOutput +JsonInput.DoubleFieldQuotedValue.JsonOutput +JsonInput.DoubleFieldQuotedValue.ProtobufOutput +JsonInput.DurationHas3FractionalDigits.Validator +JsonInput.DurationHas6FractionalDigits.Validator +JsonInput.DurationHas9FractionalDigits.Validator +JsonInput.DurationHasZeroFractionalDigit.Validator +JsonInput.DurationMaxValue.JsonOutput +JsonInput.DurationMaxValue.ProtobufOutput +JsonInput.DurationMinValue.JsonOutput +JsonInput.DurationMinValue.ProtobufOutput +JsonInput.EnumFieldUnknownValue.Validator +JsonInput.FieldMask.JsonOutput +JsonInput.FieldMask.ProtobufOutput +JsonInput.FieldNameInLowerCamelCase.Validator +JsonInput.FieldNameWithMixedCases.JsonOutput +JsonInput.FieldNameWithMixedCases.ProtobufOutput +JsonInput.FieldNameWithMixedCases.Validator +JsonInput.FieldNameWithNumbers.Validator +JsonInput.FloatFieldQuotedValue.JsonOutput +JsonInput.FloatFieldQuotedValue.ProtobufOutput +JsonInput.Int32FieldExponentialFormat.JsonOutput +JsonInput.Int32FieldExponentialFormat.ProtobufOutput +JsonInput.Int32FieldFloatTrailingZero.JsonOutput +JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput +JsonInput.Int32FieldMaxFloatValue.JsonOutput +JsonInput.Int32FieldMaxFloatValue.ProtobufOutput +JsonInput.Int32FieldMinFloatValue.JsonOutput +JsonInput.Int32FieldMinFloatValue.ProtobufOutput +JsonInput.Int32FieldStringValue.JsonOutput +JsonInput.Int32FieldStringValue.ProtobufOutput +JsonInput.Int32FieldStringValueEscaped.JsonOutput +JsonInput.Int32FieldStringValueEscaped.ProtobufOutput +JsonInput.Int64FieldBeString.Validator +JsonInput.MapFieldValueIsNull +JsonInput.OneofFieldDuplicate +JsonInput.RepeatedFieldMessageElementIsNull +JsonInput.RepeatedFieldPrimitiveElementIsNull +JsonInput.StringFieldSurrogateInWrongOrder +JsonInput.StringFieldUnpairedHighSurrogate +JsonInput.StringFieldUnpairedLowSurrogate +JsonInput.TimestampHas3FractionalDigits.Validator +JsonInput.TimestampHas6FractionalDigits.Validator +JsonInput.TimestampHas9FractionalDigits.Validator +JsonInput.TimestampHasZeroFractionalDigit.Validator +JsonInput.TimestampJsonInputTooSmall +JsonInput.TimestampZeroNormalized.Validator +JsonInput.Uint32FieldMaxFloatValue.JsonOutput +JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput +JsonInput.Uint64FieldBeString.Validator +TimestampProtoInputTooLarge.JsonOutput +TimestampProtoInputTooSmall.JsonOutput diff --git a/vendor/github.com/golang/protobuf/conformance/internal/conformance_proto/conformance.pb.go b/vendor/github.com/golang/protobuf/conformance/internal/conformance_proto/conformance.pb.go new file mode 100644 index 00000000..15102e85 --- /dev/null +++ b/vendor/github.com/golang/protobuf/conformance/internal/conformance_proto/conformance.pb.go @@ -0,0 +1,1834 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: conformance.proto + +package conformance + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import any "github.com/golang/protobuf/ptypes/any" +import duration "github.com/golang/protobuf/ptypes/duration" +import _struct "github.com/golang/protobuf/ptypes/struct" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" +import wrappers "github.com/golang/protobuf/ptypes/wrappers" +import field_mask "google.golang.org/genproto/protobuf/field_mask" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type WireFormat int32 + +const ( + WireFormat_UNSPECIFIED WireFormat = 0 + WireFormat_PROTOBUF WireFormat = 1 + WireFormat_JSON WireFormat = 2 +) + +var WireFormat_name = map[int32]string{ + 0: "UNSPECIFIED", + 1: "PROTOBUF", + 2: "JSON", +} +var WireFormat_value = map[string]int32{ + "UNSPECIFIED": 0, + "PROTOBUF": 1, + "JSON": 2, +} + +func (x WireFormat) String() string { + return proto.EnumName(WireFormat_name, int32(x)) +} +func (WireFormat) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{0} +} + +type ForeignEnum int32 + +const ( + ForeignEnum_FOREIGN_FOO ForeignEnum = 0 + ForeignEnum_FOREIGN_BAR ForeignEnum = 1 + ForeignEnum_FOREIGN_BAZ ForeignEnum = 2 +) + +var ForeignEnum_name = map[int32]string{ + 0: "FOREIGN_FOO", + 1: "FOREIGN_BAR", + 2: "FOREIGN_BAZ", +} +var ForeignEnum_value = map[string]int32{ + "FOREIGN_FOO": 0, + "FOREIGN_BAR": 1, + "FOREIGN_BAZ": 2, +} + +func (x ForeignEnum) String() string { + return proto.EnumName(ForeignEnum_name, int32(x)) +} +func (ForeignEnum) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{1} +} + +type TestAllTypes_NestedEnum int32 + +const ( + TestAllTypes_FOO TestAllTypes_NestedEnum = 0 + TestAllTypes_BAR TestAllTypes_NestedEnum = 1 + TestAllTypes_BAZ TestAllTypes_NestedEnum = 2 + TestAllTypes_NEG TestAllTypes_NestedEnum = -1 +) + +var TestAllTypes_NestedEnum_name = map[int32]string{ + 0: "FOO", + 1: "BAR", + 2: "BAZ", + -1: "NEG", +} +var TestAllTypes_NestedEnum_value = map[string]int32{ + "FOO": 0, + "BAR": 1, + "BAZ": 2, + "NEG": -1, +} + +func (x TestAllTypes_NestedEnum) String() string { + return proto.EnumName(TestAllTypes_NestedEnum_name, int32(x)) +} +func (TestAllTypes_NestedEnum) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{2, 0} +} + +// Represents a single test case's input. The testee should: +// +// 1. parse this proto (which should always succeed) +// 2. parse the protobuf or JSON payload in "payload" (which may fail) +// 3. if the parse succeeded, serialize the message in the requested format. +type ConformanceRequest struct { + // The payload (whether protobuf of JSON) is always for a TestAllTypes proto + // (see below). + // + // Types that are valid to be assigned to Payload: + // *ConformanceRequest_ProtobufPayload + // *ConformanceRequest_JsonPayload + Payload isConformanceRequest_Payload `protobuf_oneof:"payload"` + // Which format should the testee serialize its message to? + RequestedOutputFormat WireFormat `protobuf:"varint,3,opt,name=requested_output_format,json=requestedOutputFormat,proto3,enum=conformance.WireFormat" json:"requested_output_format,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConformanceRequest) Reset() { *m = ConformanceRequest{} } +func (m *ConformanceRequest) String() string { return proto.CompactTextString(m) } +func (*ConformanceRequest) ProtoMessage() {} +func (*ConformanceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{0} +} +func (m *ConformanceRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConformanceRequest.Unmarshal(m, b) +} +func (m *ConformanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConformanceRequest.Marshal(b, m, deterministic) +} +func (dst *ConformanceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConformanceRequest.Merge(dst, src) +} +func (m *ConformanceRequest) XXX_Size() int { + return xxx_messageInfo_ConformanceRequest.Size(m) +} +func (m *ConformanceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ConformanceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ConformanceRequest proto.InternalMessageInfo + +type isConformanceRequest_Payload interface { + isConformanceRequest_Payload() +} + +type ConformanceRequest_ProtobufPayload struct { + ProtobufPayload []byte `protobuf:"bytes,1,opt,name=protobuf_payload,json=protobufPayload,proto3,oneof"` +} + +type ConformanceRequest_JsonPayload struct { + JsonPayload string `protobuf:"bytes,2,opt,name=json_payload,json=jsonPayload,proto3,oneof"` +} + +func (*ConformanceRequest_ProtobufPayload) isConformanceRequest_Payload() {} + +func (*ConformanceRequest_JsonPayload) isConformanceRequest_Payload() {} + +func (m *ConformanceRequest) GetPayload() isConformanceRequest_Payload { + if m != nil { + return m.Payload + } + return nil +} + +func (m *ConformanceRequest) GetProtobufPayload() []byte { + if x, ok := m.GetPayload().(*ConformanceRequest_ProtobufPayload); ok { + return x.ProtobufPayload + } + return nil +} + +func (m *ConformanceRequest) GetJsonPayload() string { + if x, ok := m.GetPayload().(*ConformanceRequest_JsonPayload); ok { + return x.JsonPayload + } + return "" +} + +func (m *ConformanceRequest) GetRequestedOutputFormat() WireFormat { + if m != nil { + return m.RequestedOutputFormat + } + return WireFormat_UNSPECIFIED +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ConformanceRequest) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ConformanceRequest_OneofMarshaler, _ConformanceRequest_OneofUnmarshaler, _ConformanceRequest_OneofSizer, []interface{}{ + (*ConformanceRequest_ProtobufPayload)(nil), + (*ConformanceRequest_JsonPayload)(nil), + } +} + +func _ConformanceRequest_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ConformanceRequest) + // payload + switch x := m.Payload.(type) { + case *ConformanceRequest_ProtobufPayload: + b.EncodeVarint(1<<3 | proto.WireBytes) + b.EncodeRawBytes(x.ProtobufPayload) + case *ConformanceRequest_JsonPayload: + b.EncodeVarint(2<<3 | proto.WireBytes) + b.EncodeStringBytes(x.JsonPayload) + case nil: + default: + return fmt.Errorf("ConformanceRequest.Payload has unexpected type %T", x) + } + return nil +} + +func _ConformanceRequest_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ConformanceRequest) + switch tag { + case 1: // payload.protobuf_payload + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeRawBytes(true) + m.Payload = &ConformanceRequest_ProtobufPayload{x} + return true, err + case 2: // payload.json_payload + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Payload = &ConformanceRequest_JsonPayload{x} + return true, err + default: + return false, nil + } +} + +func _ConformanceRequest_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ConformanceRequest) + // payload + switch x := m.Payload.(type) { + case *ConformanceRequest_ProtobufPayload: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.ProtobufPayload))) + n += len(x.ProtobufPayload) + case *ConformanceRequest_JsonPayload: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.JsonPayload))) + n += len(x.JsonPayload) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// Represents a single test case's output. +type ConformanceResponse struct { + // Types that are valid to be assigned to Result: + // *ConformanceResponse_ParseError + // *ConformanceResponse_SerializeError + // *ConformanceResponse_RuntimeError + // *ConformanceResponse_ProtobufPayload + // *ConformanceResponse_JsonPayload + // *ConformanceResponse_Skipped + Result isConformanceResponse_Result `protobuf_oneof:"result"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConformanceResponse) Reset() { *m = ConformanceResponse{} } +func (m *ConformanceResponse) String() string { return proto.CompactTextString(m) } +func (*ConformanceResponse) ProtoMessage() {} +func (*ConformanceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{1} +} +func (m *ConformanceResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConformanceResponse.Unmarshal(m, b) +} +func (m *ConformanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConformanceResponse.Marshal(b, m, deterministic) +} +func (dst *ConformanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConformanceResponse.Merge(dst, src) +} +func (m *ConformanceResponse) XXX_Size() int { + return xxx_messageInfo_ConformanceResponse.Size(m) +} +func (m *ConformanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ConformanceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ConformanceResponse proto.InternalMessageInfo + +type isConformanceResponse_Result interface { + isConformanceResponse_Result() +} + +type ConformanceResponse_ParseError struct { + ParseError string `protobuf:"bytes,1,opt,name=parse_error,json=parseError,proto3,oneof"` +} + +type ConformanceResponse_SerializeError struct { + SerializeError string `protobuf:"bytes,6,opt,name=serialize_error,json=serializeError,proto3,oneof"` +} + +type ConformanceResponse_RuntimeError struct { + RuntimeError string `protobuf:"bytes,2,opt,name=runtime_error,json=runtimeError,proto3,oneof"` +} + +type ConformanceResponse_ProtobufPayload struct { + ProtobufPayload []byte `protobuf:"bytes,3,opt,name=protobuf_payload,json=protobufPayload,proto3,oneof"` +} + +type ConformanceResponse_JsonPayload struct { + JsonPayload string `protobuf:"bytes,4,opt,name=json_payload,json=jsonPayload,proto3,oneof"` +} + +type ConformanceResponse_Skipped struct { + Skipped string `protobuf:"bytes,5,opt,name=skipped,proto3,oneof"` +} + +func (*ConformanceResponse_ParseError) isConformanceResponse_Result() {} + +func (*ConformanceResponse_SerializeError) isConformanceResponse_Result() {} + +func (*ConformanceResponse_RuntimeError) isConformanceResponse_Result() {} + +func (*ConformanceResponse_ProtobufPayload) isConformanceResponse_Result() {} + +func (*ConformanceResponse_JsonPayload) isConformanceResponse_Result() {} + +func (*ConformanceResponse_Skipped) isConformanceResponse_Result() {} + +func (m *ConformanceResponse) GetResult() isConformanceResponse_Result { + if m != nil { + return m.Result + } + return nil +} + +func (m *ConformanceResponse) GetParseError() string { + if x, ok := m.GetResult().(*ConformanceResponse_ParseError); ok { + return x.ParseError + } + return "" +} + +func (m *ConformanceResponse) GetSerializeError() string { + if x, ok := m.GetResult().(*ConformanceResponse_SerializeError); ok { + return x.SerializeError + } + return "" +} + +func (m *ConformanceResponse) GetRuntimeError() string { + if x, ok := m.GetResult().(*ConformanceResponse_RuntimeError); ok { + return x.RuntimeError + } + return "" +} + +func (m *ConformanceResponse) GetProtobufPayload() []byte { + if x, ok := m.GetResult().(*ConformanceResponse_ProtobufPayload); ok { + return x.ProtobufPayload + } + return nil +} + +func (m *ConformanceResponse) GetJsonPayload() string { + if x, ok := m.GetResult().(*ConformanceResponse_JsonPayload); ok { + return x.JsonPayload + } + return "" +} + +func (m *ConformanceResponse) GetSkipped() string { + if x, ok := m.GetResult().(*ConformanceResponse_Skipped); ok { + return x.Skipped + } + return "" +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ConformanceResponse) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ConformanceResponse_OneofMarshaler, _ConformanceResponse_OneofUnmarshaler, _ConformanceResponse_OneofSizer, []interface{}{ + (*ConformanceResponse_ParseError)(nil), + (*ConformanceResponse_SerializeError)(nil), + (*ConformanceResponse_RuntimeError)(nil), + (*ConformanceResponse_ProtobufPayload)(nil), + (*ConformanceResponse_JsonPayload)(nil), + (*ConformanceResponse_Skipped)(nil), + } +} + +func _ConformanceResponse_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ConformanceResponse) + // result + switch x := m.Result.(type) { + case *ConformanceResponse_ParseError: + b.EncodeVarint(1<<3 | proto.WireBytes) + b.EncodeStringBytes(x.ParseError) + case *ConformanceResponse_SerializeError: + b.EncodeVarint(6<<3 | proto.WireBytes) + b.EncodeStringBytes(x.SerializeError) + case *ConformanceResponse_RuntimeError: + b.EncodeVarint(2<<3 | proto.WireBytes) + b.EncodeStringBytes(x.RuntimeError) + case *ConformanceResponse_ProtobufPayload: + b.EncodeVarint(3<<3 | proto.WireBytes) + b.EncodeRawBytes(x.ProtobufPayload) + case *ConformanceResponse_JsonPayload: + b.EncodeVarint(4<<3 | proto.WireBytes) + b.EncodeStringBytes(x.JsonPayload) + case *ConformanceResponse_Skipped: + b.EncodeVarint(5<<3 | proto.WireBytes) + b.EncodeStringBytes(x.Skipped) + case nil: + default: + return fmt.Errorf("ConformanceResponse.Result has unexpected type %T", x) + } + return nil +} + +func _ConformanceResponse_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ConformanceResponse) + switch tag { + case 1: // result.parse_error + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Result = &ConformanceResponse_ParseError{x} + return true, err + case 6: // result.serialize_error + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Result = &ConformanceResponse_SerializeError{x} + return true, err + case 2: // result.runtime_error + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Result = &ConformanceResponse_RuntimeError{x} + return true, err + case 3: // result.protobuf_payload + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeRawBytes(true) + m.Result = &ConformanceResponse_ProtobufPayload{x} + return true, err + case 4: // result.json_payload + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Result = &ConformanceResponse_JsonPayload{x} + return true, err + case 5: // result.skipped + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Result = &ConformanceResponse_Skipped{x} + return true, err + default: + return false, nil + } +} + +func _ConformanceResponse_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ConformanceResponse) + // result + switch x := m.Result.(type) { + case *ConformanceResponse_ParseError: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.ParseError))) + n += len(x.ParseError) + case *ConformanceResponse_SerializeError: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.SerializeError))) + n += len(x.SerializeError) + case *ConformanceResponse_RuntimeError: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.RuntimeError))) + n += len(x.RuntimeError) + case *ConformanceResponse_ProtobufPayload: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.ProtobufPayload))) + n += len(x.ProtobufPayload) + case *ConformanceResponse_JsonPayload: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.JsonPayload))) + n += len(x.JsonPayload) + case *ConformanceResponse_Skipped: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.Skipped))) + n += len(x.Skipped) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// This proto includes every type of field in both singular and repeated +// forms. +type TestAllTypes struct { + // Singular + OptionalInt32 int32 `protobuf:"varint,1,opt,name=optional_int32,json=optionalInt32,proto3" json:"optional_int32,omitempty"` + OptionalInt64 int64 `protobuf:"varint,2,opt,name=optional_int64,json=optionalInt64,proto3" json:"optional_int64,omitempty"` + OptionalUint32 uint32 `protobuf:"varint,3,opt,name=optional_uint32,json=optionalUint32,proto3" json:"optional_uint32,omitempty"` + OptionalUint64 uint64 `protobuf:"varint,4,opt,name=optional_uint64,json=optionalUint64,proto3" json:"optional_uint64,omitempty"` + OptionalSint32 int32 `protobuf:"zigzag32,5,opt,name=optional_sint32,json=optionalSint32,proto3" json:"optional_sint32,omitempty"` + OptionalSint64 int64 `protobuf:"zigzag64,6,opt,name=optional_sint64,json=optionalSint64,proto3" json:"optional_sint64,omitempty"` + OptionalFixed32 uint32 `protobuf:"fixed32,7,opt,name=optional_fixed32,json=optionalFixed32,proto3" json:"optional_fixed32,omitempty"` + OptionalFixed64 uint64 `protobuf:"fixed64,8,opt,name=optional_fixed64,json=optionalFixed64,proto3" json:"optional_fixed64,omitempty"` + OptionalSfixed32 int32 `protobuf:"fixed32,9,opt,name=optional_sfixed32,json=optionalSfixed32,proto3" json:"optional_sfixed32,omitempty"` + OptionalSfixed64 int64 `protobuf:"fixed64,10,opt,name=optional_sfixed64,json=optionalSfixed64,proto3" json:"optional_sfixed64,omitempty"` + OptionalFloat float32 `protobuf:"fixed32,11,opt,name=optional_float,json=optionalFloat,proto3" json:"optional_float,omitempty"` + OptionalDouble float64 `protobuf:"fixed64,12,opt,name=optional_double,json=optionalDouble,proto3" json:"optional_double,omitempty"` + OptionalBool bool `protobuf:"varint,13,opt,name=optional_bool,json=optionalBool,proto3" json:"optional_bool,omitempty"` + OptionalString string `protobuf:"bytes,14,opt,name=optional_string,json=optionalString,proto3" json:"optional_string,omitempty"` + OptionalBytes []byte `protobuf:"bytes,15,opt,name=optional_bytes,json=optionalBytes,proto3" json:"optional_bytes,omitempty"` + OptionalNestedMessage *TestAllTypes_NestedMessage `protobuf:"bytes,18,opt,name=optional_nested_message,json=optionalNestedMessage,proto3" json:"optional_nested_message,omitempty"` + OptionalForeignMessage *ForeignMessage `protobuf:"bytes,19,opt,name=optional_foreign_message,json=optionalForeignMessage,proto3" json:"optional_foreign_message,omitempty"` + OptionalNestedEnum TestAllTypes_NestedEnum `protobuf:"varint,21,opt,name=optional_nested_enum,json=optionalNestedEnum,proto3,enum=conformance.TestAllTypes_NestedEnum" json:"optional_nested_enum,omitempty"` + OptionalForeignEnum ForeignEnum `protobuf:"varint,22,opt,name=optional_foreign_enum,json=optionalForeignEnum,proto3,enum=conformance.ForeignEnum" json:"optional_foreign_enum,omitempty"` + OptionalStringPiece string `protobuf:"bytes,24,opt,name=optional_string_piece,json=optionalStringPiece,proto3" json:"optional_string_piece,omitempty"` + OptionalCord string `protobuf:"bytes,25,opt,name=optional_cord,json=optionalCord,proto3" json:"optional_cord,omitempty"` + RecursiveMessage *TestAllTypes `protobuf:"bytes,27,opt,name=recursive_message,json=recursiveMessage,proto3" json:"recursive_message,omitempty"` + // Repeated + RepeatedInt32 []int32 `protobuf:"varint,31,rep,packed,name=repeated_int32,json=repeatedInt32,proto3" json:"repeated_int32,omitempty"` + RepeatedInt64 []int64 `protobuf:"varint,32,rep,packed,name=repeated_int64,json=repeatedInt64,proto3" json:"repeated_int64,omitempty"` + RepeatedUint32 []uint32 `protobuf:"varint,33,rep,packed,name=repeated_uint32,json=repeatedUint32,proto3" json:"repeated_uint32,omitempty"` + RepeatedUint64 []uint64 `protobuf:"varint,34,rep,packed,name=repeated_uint64,json=repeatedUint64,proto3" json:"repeated_uint64,omitempty"` + RepeatedSint32 []int32 `protobuf:"zigzag32,35,rep,packed,name=repeated_sint32,json=repeatedSint32,proto3" json:"repeated_sint32,omitempty"` + RepeatedSint64 []int64 `protobuf:"zigzag64,36,rep,packed,name=repeated_sint64,json=repeatedSint64,proto3" json:"repeated_sint64,omitempty"` + RepeatedFixed32 []uint32 `protobuf:"fixed32,37,rep,packed,name=repeated_fixed32,json=repeatedFixed32,proto3" json:"repeated_fixed32,omitempty"` + RepeatedFixed64 []uint64 `protobuf:"fixed64,38,rep,packed,name=repeated_fixed64,json=repeatedFixed64,proto3" json:"repeated_fixed64,omitempty"` + RepeatedSfixed32 []int32 `protobuf:"fixed32,39,rep,packed,name=repeated_sfixed32,json=repeatedSfixed32,proto3" json:"repeated_sfixed32,omitempty"` + RepeatedSfixed64 []int64 `protobuf:"fixed64,40,rep,packed,name=repeated_sfixed64,json=repeatedSfixed64,proto3" json:"repeated_sfixed64,omitempty"` + RepeatedFloat []float32 `protobuf:"fixed32,41,rep,packed,name=repeated_float,json=repeatedFloat,proto3" json:"repeated_float,omitempty"` + RepeatedDouble []float64 `protobuf:"fixed64,42,rep,packed,name=repeated_double,json=repeatedDouble,proto3" json:"repeated_double,omitempty"` + RepeatedBool []bool `protobuf:"varint,43,rep,packed,name=repeated_bool,json=repeatedBool,proto3" json:"repeated_bool,omitempty"` + RepeatedString []string `protobuf:"bytes,44,rep,name=repeated_string,json=repeatedString,proto3" json:"repeated_string,omitempty"` + RepeatedBytes [][]byte `protobuf:"bytes,45,rep,name=repeated_bytes,json=repeatedBytes,proto3" json:"repeated_bytes,omitempty"` + RepeatedNestedMessage []*TestAllTypes_NestedMessage `protobuf:"bytes,48,rep,name=repeated_nested_message,json=repeatedNestedMessage,proto3" json:"repeated_nested_message,omitempty"` + RepeatedForeignMessage []*ForeignMessage `protobuf:"bytes,49,rep,name=repeated_foreign_message,json=repeatedForeignMessage,proto3" json:"repeated_foreign_message,omitempty"` + RepeatedNestedEnum []TestAllTypes_NestedEnum `protobuf:"varint,51,rep,packed,name=repeated_nested_enum,json=repeatedNestedEnum,proto3,enum=conformance.TestAllTypes_NestedEnum" json:"repeated_nested_enum,omitempty"` + RepeatedForeignEnum []ForeignEnum `protobuf:"varint,52,rep,packed,name=repeated_foreign_enum,json=repeatedForeignEnum,proto3,enum=conformance.ForeignEnum" json:"repeated_foreign_enum,omitempty"` + RepeatedStringPiece []string `protobuf:"bytes,54,rep,name=repeated_string_piece,json=repeatedStringPiece,proto3" json:"repeated_string_piece,omitempty"` + RepeatedCord []string `protobuf:"bytes,55,rep,name=repeated_cord,json=repeatedCord,proto3" json:"repeated_cord,omitempty"` + // Map + MapInt32Int32 map[int32]int32 `protobuf:"bytes,56,rep,name=map_int32_int32,json=mapInt32Int32,proto3" json:"map_int32_int32,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapInt64Int64 map[int64]int64 `protobuf:"bytes,57,rep,name=map_int64_int64,json=mapInt64Int64,proto3" json:"map_int64_int64,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapUint32Uint32 map[uint32]uint32 `protobuf:"bytes,58,rep,name=map_uint32_uint32,json=mapUint32Uint32,proto3" json:"map_uint32_uint32,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapUint64Uint64 map[uint64]uint64 `protobuf:"bytes,59,rep,name=map_uint64_uint64,json=mapUint64Uint64,proto3" json:"map_uint64_uint64,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapSint32Sint32 map[int32]int32 `protobuf:"bytes,60,rep,name=map_sint32_sint32,json=mapSint32Sint32,proto3" json:"map_sint32_sint32,omitempty" protobuf_key:"zigzag32,1,opt,name=key,proto3" protobuf_val:"zigzag32,2,opt,name=value,proto3"` + MapSint64Sint64 map[int64]int64 `protobuf:"bytes,61,rep,name=map_sint64_sint64,json=mapSint64Sint64,proto3" json:"map_sint64_sint64,omitempty" protobuf_key:"zigzag64,1,opt,name=key,proto3" protobuf_val:"zigzag64,2,opt,name=value,proto3"` + MapFixed32Fixed32 map[uint32]uint32 `protobuf:"bytes,62,rep,name=map_fixed32_fixed32,json=mapFixed32Fixed32,proto3" json:"map_fixed32_fixed32,omitempty" protobuf_key:"fixed32,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` + MapFixed64Fixed64 map[uint64]uint64 `protobuf:"bytes,63,rep,name=map_fixed64_fixed64,json=mapFixed64Fixed64,proto3" json:"map_fixed64_fixed64,omitempty" protobuf_key:"fixed64,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + MapSfixed32Sfixed32 map[int32]int32 `protobuf:"bytes,64,rep,name=map_sfixed32_sfixed32,json=mapSfixed32Sfixed32,proto3" json:"map_sfixed32_sfixed32,omitempty" protobuf_key:"fixed32,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` + MapSfixed64Sfixed64 map[int64]int64 `protobuf:"bytes,65,rep,name=map_sfixed64_sfixed64,json=mapSfixed64Sfixed64,proto3" json:"map_sfixed64_sfixed64,omitempty" protobuf_key:"fixed64,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + MapInt32Float map[int32]float32 `protobuf:"bytes,66,rep,name=map_int32_float,json=mapInt32Float,proto3" json:"map_int32_float,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` + MapInt32Double map[int32]float64 `protobuf:"bytes,67,rep,name=map_int32_double,json=mapInt32Double,proto3" json:"map_int32_double,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + MapBoolBool map[bool]bool `protobuf:"bytes,68,rep,name=map_bool_bool,json=mapBoolBool,proto3" json:"map_bool_bool,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapStringString map[string]string `protobuf:"bytes,69,rep,name=map_string_string,json=mapStringString,proto3" json:"map_string_string,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapStringBytes map[string][]byte `protobuf:"bytes,70,rep,name=map_string_bytes,json=mapStringBytes,proto3" json:"map_string_bytes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapStringNestedMessage map[string]*TestAllTypes_NestedMessage `protobuf:"bytes,71,rep,name=map_string_nested_message,json=mapStringNestedMessage,proto3" json:"map_string_nested_message,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapStringForeignMessage map[string]*ForeignMessage `protobuf:"bytes,72,rep,name=map_string_foreign_message,json=mapStringForeignMessage,proto3" json:"map_string_foreign_message,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapStringNestedEnum map[string]TestAllTypes_NestedEnum `protobuf:"bytes,73,rep,name=map_string_nested_enum,json=mapStringNestedEnum,proto3" json:"map_string_nested_enum,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3,enum=conformance.TestAllTypes_NestedEnum"` + MapStringForeignEnum map[string]ForeignEnum `protobuf:"bytes,74,rep,name=map_string_foreign_enum,json=mapStringForeignEnum,proto3" json:"map_string_foreign_enum,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3,enum=conformance.ForeignEnum"` + // Types that are valid to be assigned to OneofField: + // *TestAllTypes_OneofUint32 + // *TestAllTypes_OneofNestedMessage + // *TestAllTypes_OneofString + // *TestAllTypes_OneofBytes + OneofField isTestAllTypes_OneofField `protobuf_oneof:"oneof_field"` + // Well-known types + OptionalBoolWrapper *wrappers.BoolValue `protobuf:"bytes,201,opt,name=optional_bool_wrapper,json=optionalBoolWrapper,proto3" json:"optional_bool_wrapper,omitempty"` + OptionalInt32Wrapper *wrappers.Int32Value `protobuf:"bytes,202,opt,name=optional_int32_wrapper,json=optionalInt32Wrapper,proto3" json:"optional_int32_wrapper,omitempty"` + OptionalInt64Wrapper *wrappers.Int64Value `protobuf:"bytes,203,opt,name=optional_int64_wrapper,json=optionalInt64Wrapper,proto3" json:"optional_int64_wrapper,omitempty"` + OptionalUint32Wrapper *wrappers.UInt32Value `protobuf:"bytes,204,opt,name=optional_uint32_wrapper,json=optionalUint32Wrapper,proto3" json:"optional_uint32_wrapper,omitempty"` + OptionalUint64Wrapper *wrappers.UInt64Value `protobuf:"bytes,205,opt,name=optional_uint64_wrapper,json=optionalUint64Wrapper,proto3" json:"optional_uint64_wrapper,omitempty"` + OptionalFloatWrapper *wrappers.FloatValue `protobuf:"bytes,206,opt,name=optional_float_wrapper,json=optionalFloatWrapper,proto3" json:"optional_float_wrapper,omitempty"` + OptionalDoubleWrapper *wrappers.DoubleValue `protobuf:"bytes,207,opt,name=optional_double_wrapper,json=optionalDoubleWrapper,proto3" json:"optional_double_wrapper,omitempty"` + OptionalStringWrapper *wrappers.StringValue `protobuf:"bytes,208,opt,name=optional_string_wrapper,json=optionalStringWrapper,proto3" json:"optional_string_wrapper,omitempty"` + OptionalBytesWrapper *wrappers.BytesValue `protobuf:"bytes,209,opt,name=optional_bytes_wrapper,json=optionalBytesWrapper,proto3" json:"optional_bytes_wrapper,omitempty"` + RepeatedBoolWrapper []*wrappers.BoolValue `protobuf:"bytes,211,rep,name=repeated_bool_wrapper,json=repeatedBoolWrapper,proto3" json:"repeated_bool_wrapper,omitempty"` + RepeatedInt32Wrapper []*wrappers.Int32Value `protobuf:"bytes,212,rep,name=repeated_int32_wrapper,json=repeatedInt32Wrapper,proto3" json:"repeated_int32_wrapper,omitempty"` + RepeatedInt64Wrapper []*wrappers.Int64Value `protobuf:"bytes,213,rep,name=repeated_int64_wrapper,json=repeatedInt64Wrapper,proto3" json:"repeated_int64_wrapper,omitempty"` + RepeatedUint32Wrapper []*wrappers.UInt32Value `protobuf:"bytes,214,rep,name=repeated_uint32_wrapper,json=repeatedUint32Wrapper,proto3" json:"repeated_uint32_wrapper,omitempty"` + RepeatedUint64Wrapper []*wrappers.UInt64Value `protobuf:"bytes,215,rep,name=repeated_uint64_wrapper,json=repeatedUint64Wrapper,proto3" json:"repeated_uint64_wrapper,omitempty"` + RepeatedFloatWrapper []*wrappers.FloatValue `protobuf:"bytes,216,rep,name=repeated_float_wrapper,json=repeatedFloatWrapper,proto3" json:"repeated_float_wrapper,omitempty"` + RepeatedDoubleWrapper []*wrappers.DoubleValue `protobuf:"bytes,217,rep,name=repeated_double_wrapper,json=repeatedDoubleWrapper,proto3" json:"repeated_double_wrapper,omitempty"` + RepeatedStringWrapper []*wrappers.StringValue `protobuf:"bytes,218,rep,name=repeated_string_wrapper,json=repeatedStringWrapper,proto3" json:"repeated_string_wrapper,omitempty"` + RepeatedBytesWrapper []*wrappers.BytesValue `protobuf:"bytes,219,rep,name=repeated_bytes_wrapper,json=repeatedBytesWrapper,proto3" json:"repeated_bytes_wrapper,omitempty"` + OptionalDuration *duration.Duration `protobuf:"bytes,301,opt,name=optional_duration,json=optionalDuration,proto3" json:"optional_duration,omitempty"` + OptionalTimestamp *timestamp.Timestamp `protobuf:"bytes,302,opt,name=optional_timestamp,json=optionalTimestamp,proto3" json:"optional_timestamp,omitempty"` + OptionalFieldMask *field_mask.FieldMask `protobuf:"bytes,303,opt,name=optional_field_mask,json=optionalFieldMask,proto3" json:"optional_field_mask,omitempty"` + OptionalStruct *_struct.Struct `protobuf:"bytes,304,opt,name=optional_struct,json=optionalStruct,proto3" json:"optional_struct,omitempty"` + OptionalAny *any.Any `protobuf:"bytes,305,opt,name=optional_any,json=optionalAny,proto3" json:"optional_any,omitempty"` + OptionalValue *_struct.Value `protobuf:"bytes,306,opt,name=optional_value,json=optionalValue,proto3" json:"optional_value,omitempty"` + RepeatedDuration []*duration.Duration `protobuf:"bytes,311,rep,name=repeated_duration,json=repeatedDuration,proto3" json:"repeated_duration,omitempty"` + RepeatedTimestamp []*timestamp.Timestamp `protobuf:"bytes,312,rep,name=repeated_timestamp,json=repeatedTimestamp,proto3" json:"repeated_timestamp,omitempty"` + RepeatedFieldmask []*field_mask.FieldMask `protobuf:"bytes,313,rep,name=repeated_fieldmask,json=repeatedFieldmask,proto3" json:"repeated_fieldmask,omitempty"` + RepeatedStruct []*_struct.Struct `protobuf:"bytes,324,rep,name=repeated_struct,json=repeatedStruct,proto3" json:"repeated_struct,omitempty"` + RepeatedAny []*any.Any `protobuf:"bytes,315,rep,name=repeated_any,json=repeatedAny,proto3" json:"repeated_any,omitempty"` + RepeatedValue []*_struct.Value `protobuf:"bytes,316,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` + // Test field-name-to-JSON-name convention. + Fieldname1 int32 `protobuf:"varint,401,opt,name=fieldname1,proto3" json:"fieldname1,omitempty"` + FieldName2 int32 `protobuf:"varint,402,opt,name=field_name2,json=fieldName2,proto3" json:"field_name2,omitempty"` + XFieldName3 int32 `protobuf:"varint,403,opt,name=_field_name3,json=FieldName3,proto3" json:"_field_name3,omitempty"` + Field_Name4_ int32 `protobuf:"varint,404,opt,name=field__name4_,json=fieldName4,proto3" json:"field__name4_,omitempty"` + Field0Name5 int32 `protobuf:"varint,405,opt,name=field0name5,proto3" json:"field0name5,omitempty"` + Field_0Name6 int32 `protobuf:"varint,406,opt,name=field_0_name6,json=field0Name6,proto3" json:"field_0_name6,omitempty"` + FieldName7 int32 `protobuf:"varint,407,opt,name=fieldName7,proto3" json:"fieldName7,omitempty"` + FieldName8 int32 `protobuf:"varint,408,opt,name=FieldName8,proto3" json:"FieldName8,omitempty"` + Field_Name9 int32 `protobuf:"varint,409,opt,name=field_Name9,json=fieldName9,proto3" json:"field_Name9,omitempty"` + Field_Name10 int32 `protobuf:"varint,410,opt,name=Field_Name10,json=FieldName10,proto3" json:"Field_Name10,omitempty"` + FIELD_NAME11 int32 `protobuf:"varint,411,opt,name=FIELD_NAME11,json=FIELDNAME11,proto3" json:"FIELD_NAME11,omitempty"` + FIELDName12 int32 `protobuf:"varint,412,opt,name=FIELD_name12,json=FIELDName12,proto3" json:"FIELD_name12,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TestAllTypes) Reset() { *m = TestAllTypes{} } +func (m *TestAllTypes) String() string { return proto.CompactTextString(m) } +func (*TestAllTypes) ProtoMessage() {} +func (*TestAllTypes) Descriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{2} +} +func (m *TestAllTypes) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TestAllTypes.Unmarshal(m, b) +} +func (m *TestAllTypes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TestAllTypes.Marshal(b, m, deterministic) +} +func (dst *TestAllTypes) XXX_Merge(src proto.Message) { + xxx_messageInfo_TestAllTypes.Merge(dst, src) +} +func (m *TestAllTypes) XXX_Size() int { + return xxx_messageInfo_TestAllTypes.Size(m) +} +func (m *TestAllTypes) XXX_DiscardUnknown() { + xxx_messageInfo_TestAllTypes.DiscardUnknown(m) +} + +var xxx_messageInfo_TestAllTypes proto.InternalMessageInfo + +func (m *TestAllTypes) GetOptionalInt32() int32 { + if m != nil { + return m.OptionalInt32 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalInt64() int64 { + if m != nil { + return m.OptionalInt64 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalUint32() uint32 { + if m != nil { + return m.OptionalUint32 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalUint64() uint64 { + if m != nil { + return m.OptionalUint64 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalSint32() int32 { + if m != nil { + return m.OptionalSint32 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalSint64() int64 { + if m != nil { + return m.OptionalSint64 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalFixed32() uint32 { + if m != nil { + return m.OptionalFixed32 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalFixed64() uint64 { + if m != nil { + return m.OptionalFixed64 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalSfixed32() int32 { + if m != nil { + return m.OptionalSfixed32 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalSfixed64() int64 { + if m != nil { + return m.OptionalSfixed64 + } + return 0 +} + +func (m *TestAllTypes) GetOptionalFloat() float32 { + if m != nil { + return m.OptionalFloat + } + return 0 +} + +func (m *TestAllTypes) GetOptionalDouble() float64 { + if m != nil { + return m.OptionalDouble + } + return 0 +} + +func (m *TestAllTypes) GetOptionalBool() bool { + if m != nil { + return m.OptionalBool + } + return false +} + +func (m *TestAllTypes) GetOptionalString() string { + if m != nil { + return m.OptionalString + } + return "" +} + +func (m *TestAllTypes) GetOptionalBytes() []byte { + if m != nil { + return m.OptionalBytes + } + return nil +} + +func (m *TestAllTypes) GetOptionalNestedMessage() *TestAllTypes_NestedMessage { + if m != nil { + return m.OptionalNestedMessage + } + return nil +} + +func (m *TestAllTypes) GetOptionalForeignMessage() *ForeignMessage { + if m != nil { + return m.OptionalForeignMessage + } + return nil +} + +func (m *TestAllTypes) GetOptionalNestedEnum() TestAllTypes_NestedEnum { + if m != nil { + return m.OptionalNestedEnum + } + return TestAllTypes_FOO +} + +func (m *TestAllTypes) GetOptionalForeignEnum() ForeignEnum { + if m != nil { + return m.OptionalForeignEnum + } + return ForeignEnum_FOREIGN_FOO +} + +func (m *TestAllTypes) GetOptionalStringPiece() string { + if m != nil { + return m.OptionalStringPiece + } + return "" +} + +func (m *TestAllTypes) GetOptionalCord() string { + if m != nil { + return m.OptionalCord + } + return "" +} + +func (m *TestAllTypes) GetRecursiveMessage() *TestAllTypes { + if m != nil { + return m.RecursiveMessage + } + return nil +} + +func (m *TestAllTypes) GetRepeatedInt32() []int32 { + if m != nil { + return m.RepeatedInt32 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedInt64() []int64 { + if m != nil { + return m.RepeatedInt64 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedUint32() []uint32 { + if m != nil { + return m.RepeatedUint32 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedUint64() []uint64 { + if m != nil { + return m.RepeatedUint64 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedSint32() []int32 { + if m != nil { + return m.RepeatedSint32 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedSint64() []int64 { + if m != nil { + return m.RepeatedSint64 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedFixed32() []uint32 { + if m != nil { + return m.RepeatedFixed32 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedFixed64() []uint64 { + if m != nil { + return m.RepeatedFixed64 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedSfixed32() []int32 { + if m != nil { + return m.RepeatedSfixed32 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedSfixed64() []int64 { + if m != nil { + return m.RepeatedSfixed64 + } + return nil +} + +func (m *TestAllTypes) GetRepeatedFloat() []float32 { + if m != nil { + return m.RepeatedFloat + } + return nil +} + +func (m *TestAllTypes) GetRepeatedDouble() []float64 { + if m != nil { + return m.RepeatedDouble + } + return nil +} + +func (m *TestAllTypes) GetRepeatedBool() []bool { + if m != nil { + return m.RepeatedBool + } + return nil +} + +func (m *TestAllTypes) GetRepeatedString() []string { + if m != nil { + return m.RepeatedString + } + return nil +} + +func (m *TestAllTypes) GetRepeatedBytes() [][]byte { + if m != nil { + return m.RepeatedBytes + } + return nil +} + +func (m *TestAllTypes) GetRepeatedNestedMessage() []*TestAllTypes_NestedMessage { + if m != nil { + return m.RepeatedNestedMessage + } + return nil +} + +func (m *TestAllTypes) GetRepeatedForeignMessage() []*ForeignMessage { + if m != nil { + return m.RepeatedForeignMessage + } + return nil +} + +func (m *TestAllTypes) GetRepeatedNestedEnum() []TestAllTypes_NestedEnum { + if m != nil { + return m.RepeatedNestedEnum + } + return nil +} + +func (m *TestAllTypes) GetRepeatedForeignEnum() []ForeignEnum { + if m != nil { + return m.RepeatedForeignEnum + } + return nil +} + +func (m *TestAllTypes) GetRepeatedStringPiece() []string { + if m != nil { + return m.RepeatedStringPiece + } + return nil +} + +func (m *TestAllTypes) GetRepeatedCord() []string { + if m != nil { + return m.RepeatedCord + } + return nil +} + +func (m *TestAllTypes) GetMapInt32Int32() map[int32]int32 { + if m != nil { + return m.MapInt32Int32 + } + return nil +} + +func (m *TestAllTypes) GetMapInt64Int64() map[int64]int64 { + if m != nil { + return m.MapInt64Int64 + } + return nil +} + +func (m *TestAllTypes) GetMapUint32Uint32() map[uint32]uint32 { + if m != nil { + return m.MapUint32Uint32 + } + return nil +} + +func (m *TestAllTypes) GetMapUint64Uint64() map[uint64]uint64 { + if m != nil { + return m.MapUint64Uint64 + } + return nil +} + +func (m *TestAllTypes) GetMapSint32Sint32() map[int32]int32 { + if m != nil { + return m.MapSint32Sint32 + } + return nil +} + +func (m *TestAllTypes) GetMapSint64Sint64() map[int64]int64 { + if m != nil { + return m.MapSint64Sint64 + } + return nil +} + +func (m *TestAllTypes) GetMapFixed32Fixed32() map[uint32]uint32 { + if m != nil { + return m.MapFixed32Fixed32 + } + return nil +} + +func (m *TestAllTypes) GetMapFixed64Fixed64() map[uint64]uint64 { + if m != nil { + return m.MapFixed64Fixed64 + } + return nil +} + +func (m *TestAllTypes) GetMapSfixed32Sfixed32() map[int32]int32 { + if m != nil { + return m.MapSfixed32Sfixed32 + } + return nil +} + +func (m *TestAllTypes) GetMapSfixed64Sfixed64() map[int64]int64 { + if m != nil { + return m.MapSfixed64Sfixed64 + } + return nil +} + +func (m *TestAllTypes) GetMapInt32Float() map[int32]float32 { + if m != nil { + return m.MapInt32Float + } + return nil +} + +func (m *TestAllTypes) GetMapInt32Double() map[int32]float64 { + if m != nil { + return m.MapInt32Double + } + return nil +} + +func (m *TestAllTypes) GetMapBoolBool() map[bool]bool { + if m != nil { + return m.MapBoolBool + } + return nil +} + +func (m *TestAllTypes) GetMapStringString() map[string]string { + if m != nil { + return m.MapStringString + } + return nil +} + +func (m *TestAllTypes) GetMapStringBytes() map[string][]byte { + if m != nil { + return m.MapStringBytes + } + return nil +} + +func (m *TestAllTypes) GetMapStringNestedMessage() map[string]*TestAllTypes_NestedMessage { + if m != nil { + return m.MapStringNestedMessage + } + return nil +} + +func (m *TestAllTypes) GetMapStringForeignMessage() map[string]*ForeignMessage { + if m != nil { + return m.MapStringForeignMessage + } + return nil +} + +func (m *TestAllTypes) GetMapStringNestedEnum() map[string]TestAllTypes_NestedEnum { + if m != nil { + return m.MapStringNestedEnum + } + return nil +} + +func (m *TestAllTypes) GetMapStringForeignEnum() map[string]ForeignEnum { + if m != nil { + return m.MapStringForeignEnum + } + return nil +} + +type isTestAllTypes_OneofField interface { + isTestAllTypes_OneofField() +} + +type TestAllTypes_OneofUint32 struct { + OneofUint32 uint32 `protobuf:"varint,111,opt,name=oneof_uint32,json=oneofUint32,proto3,oneof"` +} + +type TestAllTypes_OneofNestedMessage struct { + OneofNestedMessage *TestAllTypes_NestedMessage `protobuf:"bytes,112,opt,name=oneof_nested_message,json=oneofNestedMessage,proto3,oneof"` +} + +type TestAllTypes_OneofString struct { + OneofString string `protobuf:"bytes,113,opt,name=oneof_string,json=oneofString,proto3,oneof"` +} + +type TestAllTypes_OneofBytes struct { + OneofBytes []byte `protobuf:"bytes,114,opt,name=oneof_bytes,json=oneofBytes,proto3,oneof"` +} + +func (*TestAllTypes_OneofUint32) isTestAllTypes_OneofField() {} + +func (*TestAllTypes_OneofNestedMessage) isTestAllTypes_OneofField() {} + +func (*TestAllTypes_OneofString) isTestAllTypes_OneofField() {} + +func (*TestAllTypes_OneofBytes) isTestAllTypes_OneofField() {} + +func (m *TestAllTypes) GetOneofField() isTestAllTypes_OneofField { + if m != nil { + return m.OneofField + } + return nil +} + +func (m *TestAllTypes) GetOneofUint32() uint32 { + if x, ok := m.GetOneofField().(*TestAllTypes_OneofUint32); ok { + return x.OneofUint32 + } + return 0 +} + +func (m *TestAllTypes) GetOneofNestedMessage() *TestAllTypes_NestedMessage { + if x, ok := m.GetOneofField().(*TestAllTypes_OneofNestedMessage); ok { + return x.OneofNestedMessage + } + return nil +} + +func (m *TestAllTypes) GetOneofString() string { + if x, ok := m.GetOneofField().(*TestAllTypes_OneofString); ok { + return x.OneofString + } + return "" +} + +func (m *TestAllTypes) GetOneofBytes() []byte { + if x, ok := m.GetOneofField().(*TestAllTypes_OneofBytes); ok { + return x.OneofBytes + } + return nil +} + +func (m *TestAllTypes) GetOptionalBoolWrapper() *wrappers.BoolValue { + if m != nil { + return m.OptionalBoolWrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalInt32Wrapper() *wrappers.Int32Value { + if m != nil { + return m.OptionalInt32Wrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalInt64Wrapper() *wrappers.Int64Value { + if m != nil { + return m.OptionalInt64Wrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalUint32Wrapper() *wrappers.UInt32Value { + if m != nil { + return m.OptionalUint32Wrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalUint64Wrapper() *wrappers.UInt64Value { + if m != nil { + return m.OptionalUint64Wrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalFloatWrapper() *wrappers.FloatValue { + if m != nil { + return m.OptionalFloatWrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalDoubleWrapper() *wrappers.DoubleValue { + if m != nil { + return m.OptionalDoubleWrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalStringWrapper() *wrappers.StringValue { + if m != nil { + return m.OptionalStringWrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalBytesWrapper() *wrappers.BytesValue { + if m != nil { + return m.OptionalBytesWrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedBoolWrapper() []*wrappers.BoolValue { + if m != nil { + return m.RepeatedBoolWrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedInt32Wrapper() []*wrappers.Int32Value { + if m != nil { + return m.RepeatedInt32Wrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedInt64Wrapper() []*wrappers.Int64Value { + if m != nil { + return m.RepeatedInt64Wrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedUint32Wrapper() []*wrappers.UInt32Value { + if m != nil { + return m.RepeatedUint32Wrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedUint64Wrapper() []*wrappers.UInt64Value { + if m != nil { + return m.RepeatedUint64Wrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedFloatWrapper() []*wrappers.FloatValue { + if m != nil { + return m.RepeatedFloatWrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedDoubleWrapper() []*wrappers.DoubleValue { + if m != nil { + return m.RepeatedDoubleWrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedStringWrapper() []*wrappers.StringValue { + if m != nil { + return m.RepeatedStringWrapper + } + return nil +} + +func (m *TestAllTypes) GetRepeatedBytesWrapper() []*wrappers.BytesValue { + if m != nil { + return m.RepeatedBytesWrapper + } + return nil +} + +func (m *TestAllTypes) GetOptionalDuration() *duration.Duration { + if m != nil { + return m.OptionalDuration + } + return nil +} + +func (m *TestAllTypes) GetOptionalTimestamp() *timestamp.Timestamp { + if m != nil { + return m.OptionalTimestamp + } + return nil +} + +func (m *TestAllTypes) GetOptionalFieldMask() *field_mask.FieldMask { + if m != nil { + return m.OptionalFieldMask + } + return nil +} + +func (m *TestAllTypes) GetOptionalStruct() *_struct.Struct { + if m != nil { + return m.OptionalStruct + } + return nil +} + +func (m *TestAllTypes) GetOptionalAny() *any.Any { + if m != nil { + return m.OptionalAny + } + return nil +} + +func (m *TestAllTypes) GetOptionalValue() *_struct.Value { + if m != nil { + return m.OptionalValue + } + return nil +} + +func (m *TestAllTypes) GetRepeatedDuration() []*duration.Duration { + if m != nil { + return m.RepeatedDuration + } + return nil +} + +func (m *TestAllTypes) GetRepeatedTimestamp() []*timestamp.Timestamp { + if m != nil { + return m.RepeatedTimestamp + } + return nil +} + +func (m *TestAllTypes) GetRepeatedFieldmask() []*field_mask.FieldMask { + if m != nil { + return m.RepeatedFieldmask + } + return nil +} + +func (m *TestAllTypes) GetRepeatedStruct() []*_struct.Struct { + if m != nil { + return m.RepeatedStruct + } + return nil +} + +func (m *TestAllTypes) GetRepeatedAny() []*any.Any { + if m != nil { + return m.RepeatedAny + } + return nil +} + +func (m *TestAllTypes) GetRepeatedValue() []*_struct.Value { + if m != nil { + return m.RepeatedValue + } + return nil +} + +func (m *TestAllTypes) GetFieldname1() int32 { + if m != nil { + return m.Fieldname1 + } + return 0 +} + +func (m *TestAllTypes) GetFieldName2() int32 { + if m != nil { + return m.FieldName2 + } + return 0 +} + +func (m *TestAllTypes) GetXFieldName3() int32 { + if m != nil { + return m.XFieldName3 + } + return 0 +} + +func (m *TestAllTypes) GetField_Name4_() int32 { + if m != nil { + return m.Field_Name4_ + } + return 0 +} + +func (m *TestAllTypes) GetField0Name5() int32 { + if m != nil { + return m.Field0Name5 + } + return 0 +} + +func (m *TestAllTypes) GetField_0Name6() int32 { + if m != nil { + return m.Field_0Name6 + } + return 0 +} + +func (m *TestAllTypes) GetFieldName7() int32 { + if m != nil { + return m.FieldName7 + } + return 0 +} + +func (m *TestAllTypes) GetFieldName8() int32 { + if m != nil { + return m.FieldName8 + } + return 0 +} + +func (m *TestAllTypes) GetField_Name9() int32 { + if m != nil { + return m.Field_Name9 + } + return 0 +} + +func (m *TestAllTypes) GetField_Name10() int32 { + if m != nil { + return m.Field_Name10 + } + return 0 +} + +func (m *TestAllTypes) GetFIELD_NAME11() int32 { + if m != nil { + return m.FIELD_NAME11 + } + return 0 +} + +func (m *TestAllTypes) GetFIELDName12() int32 { + if m != nil { + return m.FIELDName12 + } + return 0 +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*TestAllTypes) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _TestAllTypes_OneofMarshaler, _TestAllTypes_OneofUnmarshaler, _TestAllTypes_OneofSizer, []interface{}{ + (*TestAllTypes_OneofUint32)(nil), + (*TestAllTypes_OneofNestedMessage)(nil), + (*TestAllTypes_OneofString)(nil), + (*TestAllTypes_OneofBytes)(nil), + } +} + +func _TestAllTypes_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*TestAllTypes) + // oneof_field + switch x := m.OneofField.(type) { + case *TestAllTypes_OneofUint32: + b.EncodeVarint(111<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.OneofUint32)) + case *TestAllTypes_OneofNestedMessage: + b.EncodeVarint(112<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.OneofNestedMessage); err != nil { + return err + } + case *TestAllTypes_OneofString: + b.EncodeVarint(113<<3 | proto.WireBytes) + b.EncodeStringBytes(x.OneofString) + case *TestAllTypes_OneofBytes: + b.EncodeVarint(114<<3 | proto.WireBytes) + b.EncodeRawBytes(x.OneofBytes) + case nil: + default: + return fmt.Errorf("TestAllTypes.OneofField has unexpected type %T", x) + } + return nil +} + +func _TestAllTypes_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*TestAllTypes) + switch tag { + case 111: // oneof_field.oneof_uint32 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.OneofField = &TestAllTypes_OneofUint32{uint32(x)} + return true, err + case 112: // oneof_field.oneof_nested_message + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(TestAllTypes_NestedMessage) + err := b.DecodeMessage(msg) + m.OneofField = &TestAllTypes_OneofNestedMessage{msg} + return true, err + case 113: // oneof_field.oneof_string + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.OneofField = &TestAllTypes_OneofString{x} + return true, err + case 114: // oneof_field.oneof_bytes + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeRawBytes(true) + m.OneofField = &TestAllTypes_OneofBytes{x} + return true, err + default: + return false, nil + } +} + +func _TestAllTypes_OneofSizer(msg proto.Message) (n int) { + m := msg.(*TestAllTypes) + // oneof_field + switch x := m.OneofField.(type) { + case *TestAllTypes_OneofUint32: + n += 2 // tag and wire + n += proto.SizeVarint(uint64(x.OneofUint32)) + case *TestAllTypes_OneofNestedMessage: + s := proto.Size(x.OneofNestedMessage) + n += 2 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *TestAllTypes_OneofString: + n += 2 // tag and wire + n += proto.SizeVarint(uint64(len(x.OneofString))) + n += len(x.OneofString) + case *TestAllTypes_OneofBytes: + n += 2 // tag and wire + n += proto.SizeVarint(uint64(len(x.OneofBytes))) + n += len(x.OneofBytes) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type TestAllTypes_NestedMessage struct { + A int32 `protobuf:"varint,1,opt,name=a,proto3" json:"a,omitempty"` + Corecursive *TestAllTypes `protobuf:"bytes,2,opt,name=corecursive,proto3" json:"corecursive,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TestAllTypes_NestedMessage) Reset() { *m = TestAllTypes_NestedMessage{} } +func (m *TestAllTypes_NestedMessage) String() string { return proto.CompactTextString(m) } +func (*TestAllTypes_NestedMessage) ProtoMessage() {} +func (*TestAllTypes_NestedMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{2, 0} +} +func (m *TestAllTypes_NestedMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TestAllTypes_NestedMessage.Unmarshal(m, b) +} +func (m *TestAllTypes_NestedMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TestAllTypes_NestedMessage.Marshal(b, m, deterministic) +} +func (dst *TestAllTypes_NestedMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_TestAllTypes_NestedMessage.Merge(dst, src) +} +func (m *TestAllTypes_NestedMessage) XXX_Size() int { + return xxx_messageInfo_TestAllTypes_NestedMessage.Size(m) +} +func (m *TestAllTypes_NestedMessage) XXX_DiscardUnknown() { + xxx_messageInfo_TestAllTypes_NestedMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_TestAllTypes_NestedMessage proto.InternalMessageInfo + +func (m *TestAllTypes_NestedMessage) GetA() int32 { + if m != nil { + return m.A + } + return 0 +} + +func (m *TestAllTypes_NestedMessage) GetCorecursive() *TestAllTypes { + if m != nil { + return m.Corecursive + } + return nil +} + +type ForeignMessage struct { + C int32 `protobuf:"varint,1,opt,name=c,proto3" json:"c,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ForeignMessage) Reset() { *m = ForeignMessage{} } +func (m *ForeignMessage) String() string { return proto.CompactTextString(m) } +func (*ForeignMessage) ProtoMessage() {} +func (*ForeignMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_conformance_48ac832451f5d6c3, []int{3} +} +func (m *ForeignMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ForeignMessage.Unmarshal(m, b) +} +func (m *ForeignMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ForeignMessage.Marshal(b, m, deterministic) +} +func (dst *ForeignMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForeignMessage.Merge(dst, src) +} +func (m *ForeignMessage) XXX_Size() int { + return xxx_messageInfo_ForeignMessage.Size(m) +} +func (m *ForeignMessage) XXX_DiscardUnknown() { + xxx_messageInfo_ForeignMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_ForeignMessage proto.InternalMessageInfo + +func (m *ForeignMessage) GetC() int32 { + if m != nil { + return m.C + } + return 0 +} + +func init() { + proto.RegisterType((*ConformanceRequest)(nil), "conformance.ConformanceRequest") + proto.RegisterType((*ConformanceResponse)(nil), "conformance.ConformanceResponse") + proto.RegisterType((*TestAllTypes)(nil), "conformance.TestAllTypes") + proto.RegisterMapType((map[bool]bool)(nil), "conformance.TestAllTypes.MapBoolBoolEntry") + proto.RegisterMapType((map[uint32]uint32)(nil), "conformance.TestAllTypes.MapFixed32Fixed32Entry") + proto.RegisterMapType((map[uint64]uint64)(nil), "conformance.TestAllTypes.MapFixed64Fixed64Entry") + proto.RegisterMapType((map[int32]float64)(nil), "conformance.TestAllTypes.MapInt32DoubleEntry") + proto.RegisterMapType((map[int32]float32)(nil), "conformance.TestAllTypes.MapInt32FloatEntry") + proto.RegisterMapType((map[int32]int32)(nil), "conformance.TestAllTypes.MapInt32Int32Entry") + proto.RegisterMapType((map[int64]int64)(nil), "conformance.TestAllTypes.MapInt64Int64Entry") + proto.RegisterMapType((map[int32]int32)(nil), "conformance.TestAllTypes.MapSfixed32Sfixed32Entry") + proto.RegisterMapType((map[int64]int64)(nil), "conformance.TestAllTypes.MapSfixed64Sfixed64Entry") + proto.RegisterMapType((map[int32]int32)(nil), "conformance.TestAllTypes.MapSint32Sint32Entry") + proto.RegisterMapType((map[int64]int64)(nil), "conformance.TestAllTypes.MapSint64Sint64Entry") + proto.RegisterMapType((map[string][]byte)(nil), "conformance.TestAllTypes.MapStringBytesEntry") + proto.RegisterMapType((map[string]ForeignEnum)(nil), "conformance.TestAllTypes.MapStringForeignEnumEntry") + proto.RegisterMapType((map[string]*ForeignMessage)(nil), "conformance.TestAllTypes.MapStringForeignMessageEntry") + proto.RegisterMapType((map[string]TestAllTypes_NestedEnum)(nil), "conformance.TestAllTypes.MapStringNestedEnumEntry") + proto.RegisterMapType((map[string]*TestAllTypes_NestedMessage)(nil), "conformance.TestAllTypes.MapStringNestedMessageEntry") + proto.RegisterMapType((map[string]string)(nil), "conformance.TestAllTypes.MapStringStringEntry") + proto.RegisterMapType((map[uint32]uint32)(nil), "conformance.TestAllTypes.MapUint32Uint32Entry") + proto.RegisterMapType((map[uint64]uint64)(nil), "conformance.TestAllTypes.MapUint64Uint64Entry") + proto.RegisterType((*TestAllTypes_NestedMessage)(nil), "conformance.TestAllTypes.NestedMessage") + proto.RegisterType((*ForeignMessage)(nil), "conformance.ForeignMessage") + proto.RegisterEnum("conformance.WireFormat", WireFormat_name, WireFormat_value) + proto.RegisterEnum("conformance.ForeignEnum", ForeignEnum_name, ForeignEnum_value) + proto.RegisterEnum("conformance.TestAllTypes_NestedEnum", TestAllTypes_NestedEnum_name, TestAllTypes_NestedEnum_value) +} + +func init() { proto.RegisterFile("conformance.proto", fileDescriptor_conformance_48ac832451f5d6c3) } + +var fileDescriptor_conformance_48ac832451f5d6c3 = []byte{ + // 2600 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x5a, 0x5b, 0x73, 0x13, 0xc9, + 0x15, 0xf6, 0x68, 0xc0, 0x36, 0x2d, 0xd9, 0x96, 0xdb, 0xb7, 0xc6, 0x50, 0xcb, 0x60, 0x96, 0x20, + 0x60, 0xd7, 0xeb, 0xcb, 0x30, 0x5c, 0x36, 0x4b, 0xb0, 0xc0, 0x02, 0x93, 0xc5, 0xa2, 0xc6, 0x78, + 0xa9, 0x22, 0x0f, 0xca, 0x20, 0x8f, 0x5d, 0x5a, 0x24, 0x8d, 0x76, 0x66, 0xb4, 0x89, 0xf3, 0x98, + 0x7f, 0x90, 0xfb, 0xf5, 0x2f, 0xe4, 0x5a, 0x95, 0x4a, 0x52, 0xc9, 0x53, 0x2a, 0x2f, 0xb9, 0x27, + 0x95, 0x7b, 0xf2, 0x63, 0x92, 0xea, 0xeb, 0x74, 0xb7, 0x7a, 0x64, 0xb1, 0x55, 0x2b, 0x5b, 0xa7, + 0xbf, 0xfe, 0xce, 0xe9, 0xd3, 0x67, 0xbe, 0x76, 0x9f, 0x01, 0xcc, 0x36, 0xa3, 0xee, 0x61, 0x14, + 0x77, 0x82, 0x6e, 0x33, 0x5c, 0xed, 0xc5, 0x51, 0x1a, 0xc1, 0xa2, 0x64, 0x5a, 0x3e, 0x7b, 0x14, + 0x45, 0x47, 0xed, 0xf0, 0x1d, 0x32, 0xf4, 0xb2, 0x7f, 0xf8, 0x4e, 0xd0, 0x3d, 0xa6, 0xb8, 0xe5, + 0x37, 0xf4, 0xa1, 0x83, 0x7e, 0x1c, 0xa4, 0xad, 0xa8, 0xcb, 0xc6, 0x1d, 0x7d, 0xfc, 0xb0, 0x15, + 0xb6, 0x0f, 0x1a, 0x9d, 0x20, 0x79, 0xc5, 0x10, 0xe7, 0x75, 0x44, 0x92, 0xc6, 0xfd, 0x66, 0xca, + 0x46, 0x2f, 0xe8, 0xa3, 0x69, 0xab, 0x13, 0x26, 0x69, 0xd0, 0xe9, 0xe5, 0x05, 0xf0, 0xb9, 0x38, + 0xe8, 0xf5, 0xc2, 0x38, 0xa1, 0xe3, 0x2b, 0xbf, 0xb2, 0x00, 0xbc, 0x9f, 0xad, 0xc5, 0x0f, 0x3f, + 0xea, 0x87, 0x49, 0x0a, 0xaf, 0x83, 0x32, 0x9f, 0xd1, 0xe8, 0x05, 0xc7, 0xed, 0x28, 0x38, 0x40, + 0x96, 0x63, 0x55, 0x4a, 0x8f, 0xc6, 0xfc, 0x19, 0x3e, 0xf2, 0x94, 0x0e, 0xc0, 0x4b, 0xa0, 0xf4, + 0x61, 0x12, 0x75, 0x05, 0xb0, 0xe0, 0x58, 0x95, 0x33, 0x8f, 0xc6, 0xfc, 0x22, 0xb6, 0x72, 0x50, + 0x1d, 0x2c, 0xc5, 0x94, 0x3c, 0x3c, 0x68, 0x44, 0xfd, 0xb4, 0xd7, 0x4f, 0x1b, 0xc4, 0x6b, 0x8a, + 0x6c, 0xc7, 0xaa, 0x4c, 0x6f, 0x2c, 0xad, 0xca, 0x69, 0x7e, 0xde, 0x8a, 0xc3, 0x1a, 0x19, 0xf6, + 0x17, 0xc4, 0xbc, 0x3a, 0x99, 0x46, 0xcd, 0xd5, 0x33, 0x60, 0x82, 0x39, 0x5c, 0xf9, 0x62, 0x01, + 0xcc, 0x29, 0x8b, 0x48, 0x7a, 0x51, 0x37, 0x09, 0xe1, 0x45, 0x50, 0xec, 0x05, 0x71, 0x12, 0x36, + 0xc2, 0x38, 0x8e, 0x62, 0xb2, 0x00, 0x1c, 0x17, 0x20, 0xc6, 0x6d, 0x6c, 0x83, 0x57, 0xc1, 0x4c, + 0x12, 0xc6, 0xad, 0xa0, 0xdd, 0xfa, 0x02, 0x87, 0x8d, 0x33, 0xd8, 0xb4, 0x18, 0xa0, 0xd0, 0xcb, + 0x60, 0x2a, 0xee, 0x77, 0x71, 0x82, 0x19, 0x90, 0xaf, 0xb3, 0xc4, 0xcc, 0x14, 0x66, 0x4a, 0x9d, + 0x3d, 0x6a, 0xea, 0x4e, 0x99, 0x52, 0xb7, 0x0c, 0x26, 0x92, 0x57, 0xad, 0x5e, 0x2f, 0x3c, 0x40, + 0xa7, 0xd9, 0x38, 0x37, 0x54, 0x27, 0xc1, 0x78, 0x1c, 0x26, 0xfd, 0x76, 0xba, 0xf2, 0x93, 0xfb, + 0xa0, 0xf4, 0x2c, 0x4c, 0xd2, 0xad, 0x76, 0xfb, 0xd9, 0x71, 0x2f, 0x4c, 0xe0, 0x65, 0x30, 0x1d, + 0xf5, 0x70, 0xad, 0x05, 0xed, 0x46, 0xab, 0x9b, 0x6e, 0x6e, 0x90, 0x04, 0x9c, 0xf6, 0xa7, 0xb8, + 0x75, 0x07, 0x1b, 0x75, 0x98, 0xe7, 0x92, 0x75, 0xd9, 0x0a, 0xcc, 0x73, 0xe1, 0x15, 0x30, 0x23, + 0x60, 0x7d, 0x4a, 0x87, 0x57, 0x35, 0xe5, 0x8b, 0xd9, 0xfb, 0xc4, 0x3a, 0x00, 0xf4, 0x5c, 0xb2, + 0xaa, 0x53, 0x2a, 0x50, 0x63, 0x4c, 0x28, 0x23, 0x5e, 0xde, 0x6c, 0x06, 0xdc, 0x1b, 0x64, 0x4c, + 0x28, 0x23, 0xde, 0x23, 0xa8, 0x02, 0x3d, 0x17, 0x5e, 0x05, 0x65, 0x01, 0x3c, 0x6c, 0x7d, 0x3e, + 0x3c, 0xd8, 0xdc, 0x40, 0x13, 0x8e, 0x55, 0x99, 0xf0, 0x05, 0x41, 0x8d, 0x9a, 0x07, 0xa1, 0x9e, + 0x8b, 0x26, 0x1d, 0xab, 0x32, 0xae, 0x41, 0x3d, 0x17, 0x5e, 0x07, 0xb3, 0x99, 0x7b, 0x4e, 0x7b, + 0xc6, 0xb1, 0x2a, 0x33, 0xbe, 0xe0, 0xd8, 0x63, 0x76, 0x03, 0xd8, 0x73, 0x11, 0x70, 0xac, 0x4a, + 0x59, 0x07, 0x7b, 0xae, 0x92, 0xfa, 0xc3, 0x76, 0x14, 0xa4, 0xa8, 0xe8, 0x58, 0x95, 0x42, 0x96, + 0xfa, 0x1a, 0x36, 0x2a, 0xeb, 0x3f, 0x88, 0xfa, 0x2f, 0xdb, 0x21, 0x2a, 0x39, 0x56, 0xc5, 0xca, + 0xd6, 0xff, 0x80, 0x58, 0xe1, 0x25, 0x20, 0x66, 0x36, 0x5e, 0x46, 0x51, 0x1b, 0x4d, 0x39, 0x56, + 0x65, 0xd2, 0x2f, 0x71, 0x63, 0x35, 0x8a, 0xda, 0x6a, 0x36, 0xd3, 0xb8, 0xd5, 0x3d, 0x42, 0xd3, + 0xb8, 0xaa, 0xa4, 0x6c, 0x12, 0xab, 0x12, 0xdd, 0xcb, 0xe3, 0x34, 0x4c, 0xd0, 0x0c, 0x2e, 0xe3, + 0x2c, 0xba, 0x2a, 0x36, 0xc2, 0x06, 0x58, 0x12, 0xb0, 0x2e, 0x7d, 0xbc, 0x3b, 0x61, 0x92, 0x04, + 0x47, 0x21, 0x82, 0x8e, 0x55, 0x29, 0x6e, 0x5c, 0x51, 0x1e, 0x6c, 0xb9, 0x44, 0x57, 0x77, 0x09, + 0xfe, 0x09, 0x85, 0xfb, 0x0b, 0x9c, 0x47, 0x31, 0xc3, 0x7d, 0x80, 0xb2, 0x2c, 0x45, 0x71, 0xd8, + 0x3a, 0xea, 0x0a, 0x0f, 0x73, 0xc4, 0xc3, 0x39, 0xc5, 0x43, 0x8d, 0x62, 0x38, 0xeb, 0xa2, 0x48, + 0xa6, 0x62, 0x87, 0x1f, 0x80, 0x79, 0x3d, 0xee, 0xb0, 0xdb, 0xef, 0xa0, 0x05, 0xa2, 0x46, 0x6f, + 0x9e, 0x14, 0xf4, 0x76, 0xb7, 0xdf, 0xf1, 0xa1, 0x1a, 0x31, 0xb6, 0xc1, 0xf7, 0xc1, 0xc2, 0x40, + 0xb8, 0x84, 0x78, 0x91, 0x10, 0x23, 0x53, 0xac, 0x84, 0x6c, 0x4e, 0x0b, 0x94, 0xb0, 0x79, 0x12, + 0x1b, 0xdd, 0xad, 0x46, 0xaf, 0x15, 0x36, 0x43, 0x84, 0xf0, 0x9e, 0x55, 0x0b, 0x93, 0x85, 0x6c, + 0x1e, 0xdd, 0xb7, 0xa7, 0x78, 0x18, 0x5e, 0x91, 0x4a, 0xa1, 0x19, 0xc5, 0x07, 0xe8, 0x2c, 0xc3, + 0x5b, 0x59, 0x39, 0xdc, 0x8f, 0xe2, 0x03, 0x58, 0x03, 0xb3, 0x71, 0xd8, 0xec, 0xc7, 0x49, 0xeb, + 0xe3, 0x50, 0xa4, 0xf5, 0x1c, 0x49, 0xeb, 0xd9, 0xdc, 0x1c, 0xf8, 0x65, 0x31, 0x87, 0xa7, 0xf3, + 0x32, 0x98, 0x8e, 0xc3, 0x5e, 0x18, 0xe0, 0x3c, 0xd2, 0x87, 0xf9, 0x82, 0x63, 0x63, 0xb5, 0xe1, + 0x56, 0xa1, 0x36, 0x32, 0xcc, 0x73, 0x91, 0xe3, 0xd8, 0x58, 0x6d, 0x24, 0x18, 0xd5, 0x06, 0x01, + 0x63, 0x6a, 0x73, 0xd1, 0xb1, 0xb1, 0xda, 0x70, 0x73, 0xa6, 0x36, 0x0a, 0xd0, 0x73, 0xd1, 0x8a, + 0x63, 0x63, 0xb5, 0x91, 0x81, 0x1a, 0x23, 0x53, 0x9b, 0x4b, 0x8e, 0x8d, 0xd5, 0x86, 0x9b, 0xf7, + 0x06, 0x19, 0x99, 0xda, 0xbc, 0xe9, 0xd8, 0x58, 0x6d, 0x64, 0x20, 0x55, 0x1b, 0x01, 0xe4, 0xb2, + 0x70, 0xd9, 0xb1, 0xb1, 0xda, 0x70, 0xbb, 0xa4, 0x36, 0x2a, 0xd4, 0x73, 0xd1, 0x27, 0x1c, 0x1b, + 0xab, 0x8d, 0x02, 0xa5, 0x6a, 0x93, 0xb9, 0xe7, 0xb4, 0x57, 0x1c, 0x1b, 0xab, 0x8d, 0x08, 0x40, + 0x52, 0x1b, 0x0d, 0xec, 0xb9, 0xa8, 0xe2, 0xd8, 0x58, 0x6d, 0x54, 0x30, 0x55, 0x9b, 0x2c, 0x08, + 0xa2, 0x36, 0x57, 0x1d, 0x1b, 0xab, 0x8d, 0x08, 0x81, 0xab, 0x8d, 0x80, 0x31, 0xb5, 0xb9, 0xe6, + 0xd8, 0x58, 0x6d, 0xb8, 0x39, 0x53, 0x1b, 0x01, 0x24, 0x6a, 0x73, 0xdd, 0xb1, 0xb1, 0xda, 0x70, + 0x23, 0x57, 0x9b, 0x2c, 0x42, 0xaa, 0x36, 0x6f, 0x39, 0x36, 0x56, 0x1b, 0x11, 0x9f, 0x50, 0x9b, + 0x8c, 0x8d, 0xa8, 0xcd, 0xdb, 0x8e, 0x8d, 0xd5, 0x46, 0xd0, 0x71, 0xb5, 0x11, 0x30, 0x4d, 0x6d, + 0xd6, 0x1c, 0xfb, 0xb5, 0xd4, 0x86, 0xf3, 0x0c, 0xa8, 0x4d, 0x96, 0x25, 0x4d, 0x6d, 0xd6, 0x89, + 0x87, 0xe1, 0x6a, 0x23, 0x92, 0x39, 0xa0, 0x36, 0x7a, 0xdc, 0x44, 0x14, 0x36, 0x1d, 0x7b, 0x74, + 0xb5, 0x51, 0x23, 0xe6, 0x6a, 0x33, 0x10, 0x2e, 0x21, 0x76, 0x09, 0xf1, 0x10, 0xb5, 0xd1, 0x02, + 0xe5, 0x6a, 0xa3, 0xed, 0x16, 0x53, 0x1b, 0x0f, 0xef, 0x19, 0x55, 0x1b, 0x75, 0xdf, 0x84, 0xda, + 0x88, 0x79, 0x44, 0x6d, 0x6e, 0x32, 0xbc, 0x95, 0x95, 0x03, 0x51, 0x9b, 0x67, 0x60, 0xa6, 0x13, + 0xf4, 0xa8, 0x40, 0x30, 0x99, 0xb8, 0x45, 0x92, 0xfa, 0x56, 0x7e, 0x06, 0x9e, 0x04, 0x3d, 0xa2, + 0x1d, 0xe4, 0x63, 0xbb, 0x9b, 0xc6, 0xc7, 0xfe, 0x54, 0x47, 0xb6, 0x49, 0xac, 0x9e, 0xcb, 0x54, + 0xe5, 0xf6, 0x68, 0xac, 0x9e, 0x4b, 0x3e, 0x14, 0x56, 0x66, 0x83, 0x2f, 0xc0, 0x2c, 0x66, 0xa5, + 0xf2, 0xc3, 0x55, 0xe8, 0x0e, 0xe1, 0x5d, 0x1d, 0xca, 0x4b, 0xa5, 0x89, 0x7e, 0x52, 0x66, 0x1c, + 0x9e, 0x6c, 0x95, 0xb9, 0x3d, 0x97, 0x0b, 0xd7, 0xbb, 0x23, 0x72, 0x7b, 0x2e, 0xfd, 0x54, 0xb9, + 0xb9, 0x95, 0x73, 0x53, 0x91, 0xe3, 0x5a, 0xf7, 0xc9, 0x11, 0xb8, 0xa9, 0x00, 0xee, 0x69, 0x71, + 0xcb, 0x56, 0x99, 0xdb, 0x73, 0xb9, 0x3c, 0xbe, 0x37, 0x22, 0xb7, 0xe7, 0xee, 0x69, 0x71, 0xcb, + 0x56, 0xf8, 0x59, 0x30, 0x87, 0xb9, 0x99, 0xb6, 0x09, 0x49, 0xbd, 0x4b, 0xd8, 0xd7, 0x86, 0xb2, + 0x33, 0x9d, 0x65, 0x3f, 0x28, 0x3f, 0x0e, 0x54, 0xb5, 0x2b, 0x1e, 0x3c, 0x57, 0x28, 0xf1, 0xa7, + 0x46, 0xf5, 0xe0, 0xb9, 0xec, 0x87, 0xe6, 0x41, 0xd8, 0xe1, 0x21, 0x58, 0x20, 0xf9, 0xe1, 0x8b, + 0x10, 0x0a, 0x7e, 0x8f, 0xf8, 0xd8, 0x18, 0x9e, 0x23, 0x06, 0xe6, 0x3f, 0xa9, 0x17, 0x1c, 0xb2, + 0x3e, 0xa2, 0xfa, 0xc1, 0x3b, 0xc1, 0xd7, 0xb2, 0x35, 0xb2, 0x1f, 0xcf, 0xe5, 0x3f, 0x75, 0x3f, + 0xd9, 0x88, 0xfa, 0xbc, 0xd2, 0x43, 0xa3, 0x3a, 0xea, 0xf3, 0x4a, 0x8e, 0x13, 0xed, 0x79, 0xa5, + 0x47, 0xcc, 0x73, 0x50, 0xce, 0x58, 0xd9, 0x19, 0x73, 0x9f, 0xd0, 0xbe, 0x7d, 0x32, 0x2d, 0x3d, + 0x7d, 0x28, 0xef, 0x74, 0x47, 0x31, 0xc2, 0x5d, 0x80, 0x3d, 0x91, 0xd3, 0x88, 0x1e, 0x49, 0x0f, + 0x08, 0xeb, 0xb5, 0xa1, 0xac, 0xf8, 0x9c, 0xc2, 0xff, 0x53, 0xca, 0x62, 0x27, 0xb3, 0x88, 0x72, + 0xa7, 0x52, 0xc8, 0xce, 0xaf, 0xed, 0x51, 0xca, 0x9d, 0x40, 0xe9, 0xa7, 0x54, 0xee, 0x92, 0x95, + 0x27, 0x81, 0x71, 0xd3, 0x23, 0xaf, 0x36, 0x42, 0x12, 0xe8, 0x74, 0x72, 0x1a, 0x66, 0x49, 0x90, + 0x8c, 0xb0, 0x07, 0xce, 0x4a, 0xc4, 0xda, 0x21, 0xf9, 0x90, 0x78, 0xb8, 0x31, 0x82, 0x07, 0xe5, + 0x58, 0xa4, 0x9e, 0x16, 0x3b, 0xc6, 0x41, 0x98, 0x80, 0x65, 0xc9, 0xa3, 0x7e, 0x6a, 0x3e, 0x22, + 0x2e, 0xbd, 0x11, 0x5c, 0xaa, 0x67, 0x26, 0xf5, 0xb9, 0xd4, 0x31, 0x8f, 0xc2, 0x23, 0xb0, 0x38, + 0xb8, 0x4c, 0x72, 0xf4, 0xed, 0x8c, 0xf2, 0x0c, 0x48, 0xcb, 0xc0, 0x47, 0x9f, 0xf4, 0x0c, 0x68, + 0x23, 0xf0, 0x43, 0xb0, 0x64, 0x58, 0x1d, 0xf1, 0xf4, 0x98, 0x78, 0xda, 0x1c, 0x7d, 0x69, 0x99, + 0xab, 0xf9, 0x8e, 0x61, 0x08, 0x5e, 0x02, 0xa5, 0xa8, 0x1b, 0x46, 0x87, 0xfc, 0xb8, 0x89, 0xf0, + 0x15, 0xfb, 0xd1, 0x98, 0x5f, 0x24, 0x56, 0x76, 0x78, 0x7c, 0x06, 0xcc, 0x53, 0x90, 0xb6, 0xb7, + 0xbd, 0xd7, 0xba, 0x6e, 0x3d, 0x1a, 0xf3, 0x21, 0xa1, 0x51, 0xf7, 0x52, 0x44, 0xc0, 0xaa, 0xfd, + 0x23, 0xde, 0x91, 0x20, 0x56, 0x56, 0xbb, 0x17, 0x01, 0xfd, 0xca, 0xca, 0x36, 0x66, 0xed, 0x0d, + 0x40, 0x8c, 0xb4, 0x0a, 0xeb, 0xd2, 0xc5, 0x85, 0x3c, 0x8f, 0xac, 0xf1, 0x84, 0x7e, 0x63, 0x91, + 0x30, 0x97, 0x57, 0x69, 0x67, 0x6a, 0x95, 0xb7, 0x44, 0x56, 0xf1, 0x13, 0xf7, 0x41, 0xd0, 0xee, + 0x87, 0xd9, 0x8d, 0x06, 0x9b, 0x9e, 0xd3, 0x79, 0xd0, 0x07, 0x8b, 0x6a, 0x3b, 0x43, 0x30, 0xfe, + 0xd6, 0x62, 0xb7, 0x40, 0x9d, 0x91, 0x48, 0x03, 0xa5, 0x9c, 0x57, 0x9a, 0x1e, 0x39, 0x9c, 0x9e, + 0x2b, 0x38, 0x7f, 0x37, 0x84, 0xd3, 0x73, 0x07, 0x39, 0x3d, 0x97, 0x73, 0xee, 0x4b, 0xf7, 0xe1, + 0xbe, 0x1a, 0xe8, 0xef, 0x29, 0xe9, 0xf9, 0x01, 0xd2, 0x7d, 0x29, 0xd2, 0x05, 0xb5, 0x9f, 0x92, + 0x47, 0x2b, 0xc5, 0xfa, 0x87, 0x61, 0xb4, 0x3c, 0xd8, 0x05, 0xb5, 0xfb, 0x62, 0xca, 0x00, 0xd1, + 0x77, 0xc1, 0xfa, 0xc7, 0xbc, 0x0c, 0x10, 0x0d, 0xd7, 0x32, 0x40, 0x6c, 0xa6, 0x50, 0xa9, 0xba, + 0x0b, 0xd2, 0x3f, 0xe5, 0x85, 0x4a, 0x05, 0x5c, 0x0b, 0x95, 0x1a, 0x4d, 0xb4, 0xec, 0x61, 0xe4, + 0xb4, 0x7f, 0xce, 0xa3, 0xa5, 0xf5, 0xaa, 0xd1, 0x52, 0xa3, 0x29, 0x03, 0xa4, 0x9c, 0x05, 0xeb, + 0x5f, 0xf2, 0x32, 0x40, 0x2a, 0x5c, 0xcb, 0x00, 0xb1, 0x71, 0xce, 0xba, 0xf4, 0x77, 0xb4, 0x52, + 0xfc, 0x7f, 0xb5, 0x88, 0x62, 0x0c, 0x2d, 0x7e, 0xf9, 0xfe, 0x24, 0x05, 0xa9, 0xde, 0xae, 0x05, + 0xe3, 0xdf, 0x2c, 0x76, 0x29, 0x19, 0x56, 0xfc, 0xca, 0x1d, 0x3c, 0x87, 0x53, 0x2a, 0xa8, 0xbf, + 0x0f, 0xe1, 0x14, 0xc5, 0xaf, 0x5c, 0xd8, 0xa5, 0x3d, 0xd2, 0xee, 0xed, 0x82, 0xf4, 0x1f, 0x94, + 0xf4, 0x84, 0xe2, 0x57, 0xaf, 0xf7, 0x79, 0xb4, 0x52, 0xac, 0xff, 0x1c, 0x46, 0x2b, 0x8a, 0x5f, + 0x6d, 0x06, 0x98, 0x32, 0xa0, 0x16, 0xff, 0xbf, 0xf2, 0x32, 0x20, 0x17, 0xbf, 0x72, 0x6f, 0x36, + 0x85, 0xaa, 0x15, 0xff, 0xbf, 0xf3, 0x42, 0x55, 0x8a, 0x5f, 0xbd, 0x65, 0x9b, 0x68, 0xb5, 0xe2, + 0xff, 0x4f, 0x1e, 0xad, 0x52, 0xfc, 0xea, 0xb5, 0xcd, 0x94, 0x01, 0xb5, 0xf8, 0xff, 0x9b, 0x97, + 0x01, 0xb9, 0xf8, 0x95, 0xbb, 0x39, 0xe7, 0x7c, 0x28, 0xb5, 0x40, 0xf9, 0xeb, 0x0e, 0xf4, 0xbd, + 0x02, 0x6b, 0x29, 0x0d, 0xac, 0x9d, 0x21, 0xb2, 0xf6, 0x28, 0xb7, 0xc0, 0xc7, 0x40, 0xf4, 0xd7, + 0x1a, 0xe2, 0xbd, 0x06, 0xfa, 0x7e, 0x21, 0xe7, 0xfc, 0x78, 0xc6, 0x21, 0xbe, 0xf0, 0x2f, 0x4c, + 0xf0, 0xd3, 0x60, 0x4e, 0xea, 0xf7, 0xf2, 0x77, 0x2c, 0xe8, 0x07, 0x79, 0x64, 0x35, 0x8c, 0x79, + 0x12, 0x24, 0xaf, 0x32, 0x32, 0x61, 0x82, 0x5b, 0x6a, 0x0b, 0xb5, 0xdf, 0x4c, 0xd1, 0x0f, 0x29, + 0xd1, 0x92, 0x69, 0x13, 0xfa, 0xcd, 0x54, 0x69, 0xae, 0xf6, 0x9b, 0x29, 0xbc, 0x05, 0x44, 0x1b, + 0xae, 0x11, 0x74, 0x8f, 0xd1, 0x8f, 0xe8, 0xfc, 0xf9, 0x81, 0xf9, 0x5b, 0xdd, 0x63, 0xbf, 0xc8, + 0xa1, 0x5b, 0xdd, 0x63, 0x78, 0x57, 0x6a, 0xcb, 0x7e, 0x8c, 0xb7, 0x01, 0xfd, 0x98, 0xce, 0x5d, + 0x1c, 0x98, 0x4b, 0x77, 0x49, 0x34, 0x02, 0xc9, 0x57, 0xbc, 0x3d, 0x59, 0x81, 0xf2, 0xed, 0xf9, + 0x69, 0x81, 0xec, 0xf6, 0xb0, 0xed, 0x11, 0x75, 0x29, 0x6d, 0x8f, 0x20, 0xca, 0xb6, 0xe7, 0x67, + 0x85, 0x1c, 0x85, 0x93, 0xb6, 0x87, 0x4f, 0xcb, 0xb6, 0x47, 0xe6, 0x22, 0xdb, 0x43, 0x76, 0xe7, + 0xe7, 0x79, 0x5c, 0xd2, 0xee, 0x64, 0xfd, 0x33, 0x36, 0x0b, 0xef, 0x8e, 0xfc, 0xa8, 0xe0, 0xdd, + 0xf9, 0x35, 0x25, 0xca, 0xdf, 0x1d, 0xe9, 0xe9, 0x60, 0xbb, 0x23, 0x28, 0xf0, 0xee, 0xfc, 0x82, + 0xce, 0xcf, 0xd9, 0x1d, 0x0e, 0x65, 0xbb, 0x23, 0x66, 0xd2, 0xdd, 0xf9, 0x25, 0x9d, 0x9b, 0xbb, + 0x3b, 0x1c, 0x4e, 0x77, 0xe7, 0x02, 0x00, 0x64, 0xfd, 0xdd, 0xa0, 0x13, 0xae, 0xa3, 0x2f, 0xd9, + 0xe4, 0x8d, 0x8d, 0x64, 0x82, 0x0e, 0x28, 0xd2, 0xfa, 0xc5, 0x5f, 0x37, 0xd0, 0x97, 0x65, 0xc4, + 0x2e, 0x36, 0xc1, 0x8b, 0xa0, 0xd4, 0xc8, 0x20, 0x9b, 0xe8, 0x2b, 0x0c, 0x52, 0xe3, 0x90, 0x4d, + 0xb8, 0x02, 0xa6, 0x28, 0x82, 0x40, 0xdc, 0x06, 0xfa, 0xaa, 0x4e, 0xe3, 0xe2, 0xbf, 0xf1, 0xc8, + 0xb7, 0x35, 0x0c, 0xb9, 0x81, 0xbe, 0x46, 0x11, 0xb2, 0x0d, 0x5e, 0xe2, 0x34, 0x6b, 0x84, 0xc7, + 0x43, 0x5f, 0x57, 0x40, 0x98, 0xc7, 0x13, 0x2b, 0xc2, 0xdf, 0x6e, 0xa2, 0x6f, 0xe8, 0x8e, 0x6e, + 0x62, 0x80, 0x08, 0xed, 0x16, 0xfa, 0xa6, 0x1e, 0xed, 0xad, 0x6c, 0xc9, 0xf8, 0xeb, 0x6d, 0xf4, + 0x2d, 0x9d, 0xe2, 0x36, 0x5c, 0x01, 0xa5, 0x9a, 0x40, 0xac, 0xaf, 0xa1, 0x6f, 0xb3, 0x38, 0x04, + 0xc9, 0xfa, 0x1a, 0xc1, 0xec, 0x6c, 0xbf, 0xff, 0xa0, 0xb1, 0xbb, 0xf5, 0x64, 0x7b, 0x7d, 0x1d, + 0x7d, 0x87, 0x63, 0xb0, 0x91, 0xda, 0x32, 0x0c, 0xc9, 0xf5, 0x06, 0xfa, 0xae, 0x82, 0x21, 0xb6, + 0xe5, 0x17, 0x60, 0x4a, 0xfd, 0x8b, 0xb9, 0x04, 0xac, 0x80, 0xbd, 0x5a, 0xb3, 0x02, 0xf8, 0x2e, + 0x28, 0x36, 0x23, 0xd1, 0x1d, 0x47, 0x85, 0x93, 0x3a, 0xe9, 0x32, 0x7a, 0xf9, 0x1e, 0x80, 0x83, + 0xdd, 0x2e, 0x58, 0x06, 0xf6, 0xab, 0xf0, 0x98, 0xb9, 0xc0, 0xbf, 0xc2, 0x79, 0x70, 0x9a, 0x16, + 0x57, 0x81, 0xd8, 0xe8, 0x97, 0x3b, 0x85, 0x5b, 0x56, 0xc6, 0x20, 0x77, 0xb6, 0x64, 0x06, 0xdb, + 0xc0, 0x60, 0xcb, 0x0c, 0x55, 0x30, 0x6f, 0xea, 0x61, 0xc9, 0x1c, 0x53, 0x06, 0x8e, 0x29, 0x33, + 0x87, 0xd2, 0xab, 0x92, 0x39, 0x4e, 0x19, 0x38, 0x4e, 0x0d, 0x72, 0x0c, 0xf4, 0xa4, 0x64, 0x8e, + 0x59, 0x03, 0xc7, 0xac, 0x99, 0x43, 0xe9, 0x3d, 0xc9, 0x1c, 0xd0, 0xc0, 0x01, 0x65, 0x8e, 0x07, + 0x60, 0xd1, 0xdc, 0x61, 0x92, 0x59, 0x26, 0x0c, 0x2c, 0x13, 0x39, 0x2c, 0x6a, 0x17, 0x49, 0x66, + 0x19, 0x37, 0xb0, 0x8c, 0xcb, 0x2c, 0x35, 0x80, 0xf2, 0xfa, 0x44, 0x32, 0xcf, 0x8c, 0x81, 0x67, + 0x26, 0x8f, 0x47, 0xeb, 0x03, 0xc9, 0x3c, 0x65, 0x03, 0x4f, 0xd9, 0x58, 0x6d, 0x72, 0xb7, 0xe7, + 0xa4, 0x7a, 0x2d, 0xc8, 0x0c, 0x5b, 0x60, 0xce, 0xd0, 0xd8, 0x39, 0x89, 0xc2, 0x92, 0x29, 0xee, + 0x82, 0xb2, 0xde, 0xc5, 0x91, 0xe7, 0x4f, 0x1a, 0xe6, 0x4f, 0x1a, 0x8a, 0x44, 0xef, 0xd8, 0xc8, + 0x1c, 0x67, 0x0c, 0x1c, 0x67, 0x06, 0x97, 0xa1, 0xb7, 0x66, 0x4e, 0xa2, 0x28, 0xc9, 0x14, 0x31, + 0x38, 0x37, 0xa4, 0xf7, 0x62, 0xa0, 0x7a, 0x4f, 0xa6, 0x7a, 0x8d, 0x17, 0x1f, 0x92, 0xcf, 0x23, + 0x70, 0x7e, 0x58, 0xf3, 0xc5, 0xe0, 0x74, 0x5d, 0x75, 0x3a, 0xf4, 0x5d, 0x88, 0xe4, 0xa8, 0x4d, + 0x0b, 0xce, 0xd4, 0x74, 0x31, 0x38, 0xb9, 0x23, 0x3b, 0x19, 0xf5, 0xed, 0x88, 0xe4, 0x2d, 0x00, + 0x67, 0x73, 0x1b, 0x2f, 0x06, 0x77, 0xab, 0xaa, 0xbb, 0xfc, 0x77, 0x26, 0x99, 0x8b, 0x95, 0xdb, + 0x00, 0x48, 0x2d, 0xa2, 0x09, 0x60, 0xd7, 0xea, 0xf5, 0xf2, 0x18, 0xfe, 0xa5, 0xba, 0xe5, 0x97, + 0x2d, 0xfa, 0xcb, 0x8b, 0x72, 0x01, 0xbb, 0xdb, 0xdd, 0x7e, 0x58, 0xfe, 0x1f, 0xff, 0xcf, 0xaa, + 0x4e, 0xf1, 0xe6, 0x09, 0x39, 0xc0, 0x56, 0xde, 0x00, 0xd3, 0x5a, 0x67, 0xab, 0x04, 0xac, 0x26, + 0x3f, 0x50, 0x9a, 0xd7, 0x6e, 0x00, 0x90, 0xfd, 0x63, 0x18, 0x38, 0x03, 0x8a, 0xfb, 0xbb, 0x7b, + 0x4f, 0xb7, 0xef, 0xef, 0xd4, 0x76, 0xb6, 0x1f, 0x94, 0xc7, 0x60, 0x09, 0x4c, 0x3e, 0xf5, 0xeb, + 0xcf, 0xea, 0xd5, 0xfd, 0x5a, 0xd9, 0x82, 0x93, 0xe0, 0xd4, 0xe3, 0xbd, 0xfa, 0x6e, 0xb9, 0x70, + 0xed, 0x1e, 0x28, 0xca, 0x8d, 0xa5, 0x19, 0x50, 0xac, 0xd5, 0xfd, 0xed, 0x9d, 0x87, 0xbb, 0x0d, + 0x1a, 0xa9, 0x64, 0xa0, 0x11, 0x2b, 0x86, 0x17, 0xe5, 0x42, 0xf5, 0x22, 0xb8, 0xd0, 0x8c, 0x3a, + 0x03, 0x7f, 0xb6, 0x48, 0xc9, 0x79, 0x39, 0x4e, 0xac, 0x9b, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, + 0x29, 0x30, 0x51, 0x54, 0x22, 0x25, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/_conformance/conformance_proto/conformance.proto b/vendor/github.com/golang/protobuf/conformance/internal/conformance_proto/conformance.proto similarity index 96% rename from vendor/github.com/golang/protobuf/_conformance/conformance_proto/conformance.proto rename to vendor/github.com/golang/protobuf/conformance/internal/conformance_proto/conformance.proto index 95a8fd13..fc96074a 100644 --- a/vendor/github.com/golang/protobuf/_conformance/conformance_proto/conformance.proto +++ b/vendor/github.com/golang/protobuf/conformance/internal/conformance_proto/conformance.proto @@ -210,11 +210,6 @@ message TestAllTypes { NestedMessage oneof_nested_message = 112; string oneof_string = 113; bytes oneof_bytes = 114; - bool oneof_bool = 115; - uint64 oneof_uint64 = 116; - float oneof_float = 117; - double oneof_double = 118; - NestedEnum oneof_enum = 119; } // Well-known types @@ -253,7 +248,6 @@ message TestAllTypes { repeated google.protobuf.Value repeated_value = 316; // Test field-name-to-JSON-name convention. - // (protobuf says names can be any valid C/C++ identifier.) int32 fieldname1 = 401; int32 field_name2 = 402; int32 _field_name3 = 403; @@ -266,12 +260,6 @@ message TestAllTypes { int32 Field_Name10 = 410; int32 FIELD_NAME11 = 411; int32 FIELD_name12 = 412; - int32 __field_name13 = 413; - int32 __Field_name14 = 414; - int32 field__name15 = 415; - int32 field__Name16 = 416; - int32 field_name17__ = 417; - int32 Field_name18__ = 418; } message ForeignMessage { diff --git a/vendor/github.com/golang/protobuf/conformance/test.sh b/vendor/github.com/golang/protobuf/conformance/test.sh new file mode 100755 index 00000000..e6de29b9 --- /dev/null +++ b/vendor/github.com/golang/protobuf/conformance/test.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +PROTOBUF_ROOT=$1 +CONFORMANCE_ROOT=$1/conformance +CONFORMANCE_TEST_RUNNER=$CONFORMANCE_ROOT/conformance-test-runner + +cd $(dirname $0) + +if [[ $PROTOBUF_ROOT == "" ]]; then + echo "usage: test.sh " >/dev/stderr + exit 1 +fi + +if [[ ! -x $CONFORMANCE_TEST_RUNNER ]]; then + echo "SKIP: conformance test runner not installed" >/dev/stderr + exit 0 +fi + +a=$CONFORMANCE_ROOT/conformance.proto +b=internal/conformance_proto/conformance.proto +if [[ $(diff $a $b) != "" ]]; then + cp $a $b + echo "WARNING: conformance.proto is out of date" >/dev/stderr +fi + +$CONFORMANCE_TEST_RUNNER --failure_list failure_list_go.txt ./conformance.sh diff --git a/vendor/github.com/golang/protobuf/descriptor/descriptor_test.go b/vendor/github.com/golang/protobuf/descriptor/descriptor_test.go index 27b0729c..bf5174d3 100644 --- a/vendor/github.com/golang/protobuf/descriptor/descriptor_test.go +++ b/vendor/github.com/golang/protobuf/descriptor/descriptor_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/golang/protobuf/descriptor" - tpb "github.com/golang/protobuf/proto/testdata" + tpb "github.com/golang/protobuf/proto/test_proto" protobuf "github.com/golang/protobuf/protoc-gen-go/descriptor" ) @@ -20,7 +20,7 @@ func TestMessage(t *testing.T) { } } -func Example_Options() { +func Example_options() { var msg *tpb.MyMessageSet _, md := descriptor.ForMessage(msg) if md.GetOptions().GetMessageSetWireFormat() { diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go index dfdfc5b3..ada2b78e 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go @@ -56,6 +56,8 @@ import ( stpb "github.com/golang/protobuf/ptypes/struct" ) +const secondInNanos = int64(time.Second / time.Nanosecond) + // Marshaler is a configurable object for converting between // protocol buffer objects and a JSON representation for them. type Marshaler struct { @@ -104,6 +106,9 @@ func defaultResolveAny(typeUrl string) (proto.Message, error) { // way they are marshaled to JSON. Messages that implement this should // also implement JSONPBUnmarshaler so that the custom format can be // parsed. +// +// The JSON marshaling must follow the proto to JSON specification: +// https://developers.google.com/protocol-buffers/docs/proto3#json type JSONPBMarshaler interface { MarshalJSONPB(*Marshaler) ([]byte, error) } @@ -112,12 +117,23 @@ type JSONPBMarshaler interface { // the way they are unmarshaled from JSON. Messages that implement this // should also implement JSONPBMarshaler so that the custom format can be // produced. +// +// The JSON unmarshaling must follow the JSON to proto specification: +// https://developers.google.com/protocol-buffers/docs/proto3#json type JSONPBUnmarshaler interface { UnmarshalJSONPB(*Unmarshaler, []byte) error } // Marshal marshals a protocol buffer into JSON. func (m *Marshaler) Marshal(out io.Writer, pb proto.Message) error { + v := reflect.ValueOf(pb) + if pb == nil || (v.Kind() == reflect.Ptr && v.IsNil()) { + return errors.New("Marshal called with nil") + } + // Check for unset required fields first. + if err := checkRequiredFields(pb); err != nil { + return err + } writer := &errWriter{writer: out} return m.marshalObject(writer, pb, "", "") } @@ -190,12 +206,22 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU // Any is a bit more involved. return m.marshalAny(out, v, indent) case "Duration": - // "Generated output always contains 3, 6, or 9 fractional digits, + // "Generated output always contains 0, 3, 6, or 9 fractional digits, // depending on required precision." s, ns := s.Field(0).Int(), s.Field(1).Int() + if ns <= -secondInNanos || ns >= secondInNanos { + return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos) + } + if (s > 0 && ns < 0) || (s < 0 && ns > 0) { + return errors.New("signs of seconds and nanos do not match") + } + if s < 0 { + ns = -ns + } x := fmt.Sprintf("%d.%09d", s, ns) x = strings.TrimSuffix(x, "000") x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") out.write(`"`) out.write(x) out.write(`s"`) @@ -206,13 +232,17 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU return m.marshalValue(out, &proto.Properties{}, s.Field(0), indent) case "Timestamp": // "RFC 3339, where generated output will always be Z-normalized - // and uses 3, 6 or 9 fractional digits." + // and uses 0, 3, 6 or 9 fractional digits." s, ns := s.Field(0).Int(), s.Field(1).Int() + if ns < 0 || ns >= secondInNanos { + return fmt.Errorf("ns out of range [0, %v)", secondInNanos) + } t := time.Unix(s, ns).UTC() // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits). x := t.Format("2006-01-02T15:04:05.000000000") x = strings.TrimSuffix(x, "000") x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") out.write(`"`) out.write(x) out.write(`Z"`) @@ -541,6 +571,7 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle out.write(m.Indent) } + // TODO handle map key prop properly b, err := json.Marshal(k.Interface()) if err != nil { return err @@ -562,7 +593,11 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle out.write(` `) } - if err := m.marshalValue(out, prop, v.MapIndex(k), indent+m.Indent); err != nil { + vprop := prop + if prop != nil && prop.MapValProp != nil { + vprop = prop.MapValProp + } + if err := m.marshalValue(out, vprop, v.MapIndex(k), indent+m.Indent); err != nil { return err } } @@ -631,7 +666,10 @@ func (u *Unmarshaler) UnmarshalNext(dec *json.Decoder, pb proto.Message) error { if err := dec.Decode(&inputValue); err != nil { return err } - return u.unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue, nil) + if err := u.unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue, nil); err != nil { + return err + } + return checkRequiredFields(pb) } // Unmarshal unmarshals a JSON object stream into a protocol @@ -751,7 +789,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe return nil case "Duration": - unq, err := strconv.Unquote(string(inputValue)) + unq, err := unquote(string(inputValue)) if err != nil { return err } @@ -768,7 +806,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe target.Field(1).SetInt(ns) return nil case "Timestamp": - unq, err := strconv.Unquote(string(inputValue)) + unq, err := unquote(string(inputValue)) if err != nil { return err } @@ -802,7 +840,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe return fmt.Errorf("bad ListValue: %v", err) } - target.Field(0).Set(reflect.ValueOf(make([]*stpb.Value, len(s), len(s)))) + target.Field(0).Set(reflect.ValueOf(make([]*stpb.Value, len(s)))) for i, sv := range s { if err := u.unmarshalValue(target.Field(0).Index(i), sv, prop); err != nil { return err @@ -815,7 +853,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe target.Field(0).Set(reflect.ValueOf(&stpb.Value_NullValue{})) } else if v, err := strconv.ParseFloat(ivStr, 0); err == nil { target.Field(0).Set(reflect.ValueOf(&stpb.Value_NumberValue{v})) - } else if v, err := strconv.Unquote(ivStr); err == nil { + } else if v, err := unquote(ivStr); err == nil { target.Field(0).Set(reflect.ValueOf(&stpb.Value_StringValue{v})) } else if v, err := strconv.ParseBool(ivStr); err == nil { target.Field(0).Set(reflect.ValueOf(&stpb.Value_BoolValue{v})) @@ -851,6 +889,9 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe target.Set(reflect.New(targetType.Elem())) target = target.Elem() } + if targetType.Kind() != reflect.Int32 { + return fmt.Errorf("invalid target %q for enum %s", targetType.Kind(), prop.Enum) + } target.SetInt(int64(n)) return nil } @@ -972,13 +1013,6 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe } if mp != nil { target.Set(reflect.MakeMap(targetType)) - var keyprop, valprop *proto.Properties - if prop != nil { - // These could still be nil if the protobuf metadata is broken somehow. - // TODO: This won't work because the fields are unexported. - // We should probably just reparse them. - //keyprop, valprop = prop.mkeyprop, prop.mvalprop - } for ks, raw := range mp { // Unmarshal map key. The core json library already decoded the key into a // string, so we handle that specially. Other types were quoted post-serialization. @@ -987,14 +1021,22 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe k = reflect.ValueOf(ks) } else { k = reflect.New(targetType.Key()).Elem() - if err := u.unmarshalValue(k, json.RawMessage(ks), keyprop); err != nil { + var kprop *proto.Properties + if prop != nil && prop.MapKeyProp != nil { + kprop = prop.MapKeyProp + } + if err := u.unmarshalValue(k, json.RawMessage(ks), kprop); err != nil { return err } } // Unmarshal map value. v := reflect.New(targetType.Elem()).Elem() - if err := u.unmarshalValue(v, raw, valprop); err != nil { + var vprop *proto.Properties + if prop != nil && prop.MapValProp != nil { + vprop = prop.MapValProp + } + if err := u.unmarshalValue(v, raw, vprop); err != nil { return err } target.SetMapIndex(k, v) @@ -1003,13 +1045,6 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe return nil } - // 64-bit integers can be encoded as strings. In this case we drop - // the quotes and proceed as normal. - isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64 - if isNum && strings.HasPrefix(string(inputValue), `"`) { - inputValue = inputValue[1 : len(inputValue)-1] - } - // Non-finite numbers can be encoded as strings. isFloat := targetType.Kind() == reflect.Float32 || targetType.Kind() == reflect.Float64 if isFloat { @@ -1019,10 +1054,25 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe } } + // integers & floats can be encoded as strings. In this case we drop + // the quotes and proceed as normal. + isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64 || + targetType.Kind() == reflect.Int32 || targetType.Kind() == reflect.Uint32 || + targetType.Kind() == reflect.Float32 || targetType.Kind() == reflect.Float64 + if isNum && strings.HasPrefix(string(inputValue), `"`) { + inputValue = inputValue[1 : len(inputValue)-1] + } + // Use the encoding/json for parsing other value types. return json.Unmarshal(inputValue, target.Addr().Interface()) } +func unquote(s string) (string, error) { + var ret string + err := json.Unmarshal([]byte(s), &ret) + return ret, err +} + // jsonProperties returns parsed proto.Properties for the field and corrects JSONName attribute. func jsonProperties(f reflect.StructField, origName bool) *proto.Properties { var prop proto.Properties @@ -1072,6 +1122,8 @@ func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s mapKeys) Less(i, j int) bool { if k := s[i].Kind(); k == s[j].Kind() { switch k { + case reflect.String: + return s[i].String() < s[j].String() case reflect.Int32, reflect.Int64: return s[i].Int() < s[j].Int() case reflect.Uint32, reflect.Uint64: @@ -1080,3 +1132,140 @@ func (s mapKeys) Less(i, j int) bool { } return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface()) } + +// checkRequiredFields returns an error if any required field in the given proto message is not set. +// This function is used by both Marshal and Unmarshal. While required fields only exist in a +// proto2 message, a proto3 message can contain proto2 message(s). +func checkRequiredFields(pb proto.Message) error { + // Most well-known type messages do not contain required fields. The "Any" type may contain + // a message that has required fields. + // + // When an Any message is being marshaled, the code will invoked proto.Unmarshal on Any.Value + // field in order to transform that into JSON, and that should have returned an error if a + // required field is not set in the embedded message. + // + // When an Any message is being unmarshaled, the code will have invoked proto.Marshal on the + // embedded message to store the serialized message in Any.Value field, and that should have + // returned an error if a required field is not set. + if _, ok := pb.(wkt); ok { + return nil + } + + v := reflect.ValueOf(pb) + // Skip message if it is not a struct pointer. + if v.Kind() != reflect.Ptr { + return nil + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return nil + } + + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + sfield := v.Type().Field(i) + + if sfield.PkgPath != "" { + // blank PkgPath means the field is exported; skip if not exported + continue + } + + if strings.HasPrefix(sfield.Name, "XXX_") { + continue + } + + // Oneof field is an interface implemented by wrapper structs containing the actual oneof + // field, i.e. an interface containing &T{real_value}. + if sfield.Tag.Get("protobuf_oneof") != "" { + if field.Kind() != reflect.Interface { + continue + } + v := field.Elem() + if v.Kind() != reflect.Ptr || v.IsNil() { + continue + } + v = v.Elem() + if v.Kind() != reflect.Struct || v.NumField() < 1 { + continue + } + field = v.Field(0) + sfield = v.Type().Field(0) + } + + protoTag := sfield.Tag.Get("protobuf") + if protoTag == "" { + continue + } + var prop proto.Properties + prop.Init(sfield.Type, sfield.Name, protoTag, &sfield) + + switch field.Kind() { + case reflect.Map: + if field.IsNil() { + continue + } + // Check each map value. + keys := field.MapKeys() + for _, k := range keys { + v := field.MapIndex(k) + if err := checkRequiredFieldsInValue(v); err != nil { + return err + } + } + case reflect.Slice: + // Handle non-repeated type, e.g. bytes. + if !prop.Repeated { + if prop.Required && field.IsNil() { + return fmt.Errorf("required field %q is not set", prop.Name) + } + continue + } + + // Handle repeated type. + if field.IsNil() { + continue + } + // Check each slice item. + for i := 0; i < field.Len(); i++ { + v := field.Index(i) + if err := checkRequiredFieldsInValue(v); err != nil { + return err + } + } + case reflect.Ptr: + if field.IsNil() { + if prop.Required { + return fmt.Errorf("required field %q is not set", prop.Name) + } + continue + } + if err := checkRequiredFieldsInValue(field); err != nil { + return err + } + } + } + + // Handle proto2 extensions. + for _, ext := range proto.RegisteredExtensions(pb) { + if !proto.HasExtension(pb, ext) { + continue + } + ep, err := proto.GetExtension(pb, ext) + if err != nil { + return err + } + err = checkRequiredFieldsInValue(reflect.ValueOf(ep)) + if err != nil { + return err + } + } + + return nil +} + +func checkRequiredFieldsInValue(v reflect.Value) error { + if pm, ok := v.Interface().(proto.Message); ok { + return checkRequiredFields(pm) + } + return nil +} diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go index 4fdbde15..45a13d45 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go @@ -60,43 +60,111 @@ var ( } simpleObject = &pb.Simple{ - OInt32: proto.Int32(-32), - OInt64: proto.Int64(-6400000000), - OUint32: proto.Uint32(32), - OUint64: proto.Uint64(6400000000), - OSint32: proto.Int32(-13), - OSint64: proto.Int64(-2600000000), - OFloat: proto.Float32(3.14), - ODouble: proto.Float64(6.02214179e23), - OBool: proto.Bool(true), - OString: proto.String("hello \"there\""), - OBytes: []byte("beep boop"), + OInt32: proto.Int32(-32), + OInt32Str: proto.Int32(-32), + OInt64: proto.Int64(-6400000000), + OInt64Str: proto.Int64(-6400000000), + OUint32: proto.Uint32(32), + OUint32Str: proto.Uint32(32), + OUint64: proto.Uint64(6400000000), + OUint64Str: proto.Uint64(6400000000), + OSint32: proto.Int32(-13), + OSint32Str: proto.Int32(-13), + OSint64: proto.Int64(-2600000000), + OSint64Str: proto.Int64(-2600000000), + OFloat: proto.Float32(3.14), + OFloatStr: proto.Float32(3.14), + ODouble: proto.Float64(6.02214179e23), + ODoubleStr: proto.Float64(6.02214179e23), + OBool: proto.Bool(true), + OString: proto.String("hello \"there\""), + OBytes: []byte("beep boop"), } - simpleObjectJSON = `{` + + simpleObjectInputJSON = `{` + `"oBool":true,` + `"oInt32":-32,` + - `"oInt64":"-6400000000",` + + `"oInt32Str":"-32",` + + `"oInt64":-6400000000,` + + `"oInt64Str":"-6400000000",` + `"oUint32":32,` + - `"oUint64":"6400000000",` + + `"oUint32Str":"32",` + + `"oUint64":6400000000,` + + `"oUint64Str":"6400000000",` + `"oSint32":-13,` + - `"oSint64":"-2600000000",` + + `"oSint32Str":"-13",` + + `"oSint64":-2600000000,` + + `"oSint64Str":"-2600000000",` + `"oFloat":3.14,` + + `"oFloatStr":"3.14",` + `"oDouble":6.02214179e+23,` + + `"oDoubleStr":"6.02214179e+23",` + `"oString":"hello \"there\"",` + `"oBytes":"YmVlcCBib29w"` + `}` - simpleObjectPrettyJSON = `{ + simpleObjectOutputJSON = `{` + + `"oBool":true,` + + `"oInt32":-32,` + + `"oInt32Str":-32,` + + `"oInt64":"-6400000000",` + + `"oInt64Str":"-6400000000",` + + `"oUint32":32,` + + `"oUint32Str":32,` + + `"oUint64":"6400000000",` + + `"oUint64Str":"6400000000",` + + `"oSint32":-13,` + + `"oSint32Str":-13,` + + `"oSint64":"-2600000000",` + + `"oSint64Str":"-2600000000",` + + `"oFloat":3.14,` + + `"oFloatStr":3.14,` + + `"oDouble":6.02214179e+23,` + + `"oDoubleStr":6.02214179e+23,` + + `"oString":"hello \"there\"",` + + `"oBytes":"YmVlcCBib29w"` + + `}` + + simpleObjectInputPrettyJSON = `{ "oBool": true, "oInt32": -32, - "oInt64": "-6400000000", + "oInt32Str": "-32", + "oInt64": -6400000000, + "oInt64Str": "-6400000000", "oUint32": 32, - "oUint64": "6400000000", + "oUint32Str": "32", + "oUint64": 6400000000, + "oUint64Str": "6400000000", "oSint32": -13, - "oSint64": "-2600000000", + "oSint32Str": "-13", + "oSint64": -2600000000, + "oSint64Str": "-2600000000", "oFloat": 3.14, + "oFloatStr": "3.14", "oDouble": 6.02214179e+23, + "oDoubleStr": "6.02214179e+23", + "oString": "hello \"there\"", + "oBytes": "YmVlcCBib29w" +}` + + simpleObjectOutputPrettyJSON = `{ + "oBool": true, + "oInt32": -32, + "oInt32Str": -32, + "oInt64": "-6400000000", + "oInt64Str": "-6400000000", + "oUint32": 32, + "oUint32Str": 32, + "oUint64": "6400000000", + "oUint64Str": "6400000000", + "oSint32": -13, + "oSint32Str": -13, + "oSint64": "-2600000000", + "oSint64Str": "-2600000000", + "oFloat": 3.14, + "oFloatStr": 3.14, + "oDouble": 6.02214179e+23, + "oDoubleStr": 6.02214179e+23, "oString": "hello \"there\"", "oBytes": "YmVlcCBib29w" }` @@ -343,8 +411,8 @@ var marshalingTests = []struct { pb proto.Message json string }{ - {"simple flat object", marshaler, simpleObject, simpleObjectJSON}, - {"simple pretty object", marshalerAllOptions, simpleObject, simpleObjectPrettyJSON}, + {"simple flat object", marshaler, simpleObject, simpleObjectOutputJSON}, + {"simple pretty object", marshalerAllOptions, simpleObject, simpleObjectOutputPrettyJSON}, {"non-finite floats fields object", marshaler, nonFinites, nonFinitesJSON}, {"repeated fields flat object", marshaler, repeatsObject, repeatsObjectJSON}, {"repeated fields pretty object", marshalerAllOptions, repeatsObject, repeatsObjectPrettyJSON}, @@ -385,8 +453,7 @@ var marshalingTests = []struct { {"map", marshaler, &pb.Mappy{Buggy: map[int64]string{1234: "yup"}}, `{"buggy":{"1234":"yup"}}`}, {"map", marshaler, &pb.Mappy{Booly: map[bool]bool{false: true}}, `{"booly":{"false":true}}`}, - // TODO: This is broken. - //{"map", marshaler, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":"ROMAN"}`}, + {"map", marshaler, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":"ROMAN"}}`}, {"map", Marshaler{EnumsAsInts: true}, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":2}}`}, {"map", marshaler, &pb.Mappy{S32Booly: map[int32]bool{1: true, 3: false, 10: true, 12: false}}, `{"s32booly":{"1":true,"3":false,"10":true,"12":false}}`}, {"map", marshaler, &pb.Mappy{S64Booly: map[int64]bool{1: true, 3: false, 10: true, 12: false}}, `{"s64booly":{"1":true,"3":false,"10":true,"12":false}}`}, @@ -406,8 +473,10 @@ var marshalingTests = []struct { {"Any with message and indent", marshalerAllOptions, anySimple, anySimplePrettyJSON}, {"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON}, {"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON}, - {"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}, `{"dur":"3.000s"}`}, - {"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 100000000, Nanos: 1}}, `{"dur":"100000000.000000001s"}`}, + {"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}, `{"dur":"3s"}`}, + {"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3, Nanos: 1e6}}, `{"dur":"3.001s"}`}, + {"Duration beyond float64 precision", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 100000000, Nanos: 1}}, `{"dur":"100000000.000000001s"}`}, + {"negative Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: -123, Nanos: -456}}, `{"dur":"-123.000000456s"}`}, {"Struct", marshaler, &pb.KnownTypes{St: &stpb.Struct{ Fields: map[string]*stpb.Value{ "one": {Kind: &stpb.Value_StringValue{"loneliest number"}}, @@ -422,6 +491,7 @@ var marshalingTests = []struct { {Kind: &stpb.Value_BoolValue{true}}, }}}, `{"lv":["x",null,3,true]}`}, {"Timestamp", marshaler, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 21e6}}, `{"ts":"2014-05-13T16:53:20.021Z"}`}, + {"Timestamp", marshaler, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 0}}, `{"ts":"2014-05-13T16:53:20Z"}`}, {"number Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NumberValue{1}}}, `{"val":1}`}, {"null Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}}}, `{"val":null}`}, {"string number value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"9223372036854775807"}}}, `{"val":"9223372036854775807"}`}, @@ -450,6 +520,9 @@ var marshalingTests = []struct { {"BoolValue", marshaler, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}, `{"bool":true}`}, {"StringValue", marshaler, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}, `{"str":"plush"}`}, {"BytesValue", marshaler, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`}, + + {"required", marshaler, &pb.MsgWithRequired{Str: proto.String("hello")}, `{"str":"hello"}`}, + {"required bytes", marshaler, &pb.MsgWithRequiredBytes{Byts: []byte{}}, `{"byts":""}`}, } func TestMarshaling(t *testing.T) { @@ -463,9 +536,43 @@ func TestMarshaling(t *testing.T) { } } +func TestMarshalingNil(t *testing.T) { + var msg *pb.Simple + m := &Marshaler{} + if _, err := m.MarshalToString(msg); err == nil { + t.Errorf("mashaling nil returned no error") + } +} + +func TestMarshalIllegalTime(t *testing.T) { + tests := []struct { + pb proto.Message + fail bool + }{ + {&pb.KnownTypes{Dur: &durpb.Duration{Seconds: 1, Nanos: 0}}, false}, + {&pb.KnownTypes{Dur: &durpb.Duration{Seconds: -1, Nanos: 0}}, false}, + {&pb.KnownTypes{Dur: &durpb.Duration{Seconds: 1, Nanos: -1}}, true}, + {&pb.KnownTypes{Dur: &durpb.Duration{Seconds: -1, Nanos: 1}}, true}, + {&pb.KnownTypes{Dur: &durpb.Duration{Seconds: 1, Nanos: 1000000000}}, true}, + {&pb.KnownTypes{Dur: &durpb.Duration{Seconds: -1, Nanos: -1000000000}}, true}, + {&pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 1, Nanos: 1}}, false}, + {&pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 1, Nanos: -1}}, true}, + {&pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 1, Nanos: 1000000000}}, true}, + } + for _, tt := range tests { + _, err := marshaler.MarshalToString(tt.pb) + if err == nil && tt.fail { + t.Errorf("marshaler.MarshalToString(%v) = _, ; want _, ", tt.pb) + } + if err != nil && !tt.fail { + t.Errorf("marshaler.MarshalToString(%v) = _, %v; want _, ", tt.pb, err) + } + } +} + func TestMarshalJSONPBMarshaler(t *testing.T) { rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }` - msg := dynamicMessage{rawJson: rawJson} + msg := dynamicMessage{RawJson: rawJson} str, err := new(Marshaler).MarshalToString(&msg) if err != nil { t.Errorf("an unexpected error occurred when marshalling JSONPBMarshaler: %v", err) @@ -476,7 +583,7 @@ func TestMarshalJSONPBMarshaler(t *testing.T) { } func TestMarshalAnyJSONPBMarshaler(t *testing.T) { - msg := dynamicMessage{rawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`} + msg := dynamicMessage{RawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`} a, err := ptypes.MarshalAny(&msg) if err != nil { t.Errorf("an unexpected error occurred when marshalling to Any: %v", err) @@ -493,14 +600,112 @@ func TestMarshalAnyJSONPBMarshaler(t *testing.T) { } } +func TestMarshalWithCustomValidation(t *testing.T) { + msg := dynamicMessage{RawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`, Dummy: &dynamicMessage{}} + + js, err := new(Marshaler).MarshalToString(&msg) + if err != nil { + t.Errorf("an unexpected error occurred when marshalling to json: %v", err) + } + err = Unmarshal(strings.NewReader(js), &msg) + if err != nil { + t.Errorf("an unexpected error occurred when unmarshalling from json: %v", err) + } +} + +// Test marshaling message containing unset required fields should produce error. +func TestMarshalUnsetRequiredFields(t *testing.T) { + msgExt := &pb.Real{} + proto.SetExtension(msgExt, pb.E_Extm, &pb.MsgWithRequired{}) + + tests := []struct { + desc string + marshaler *Marshaler + pb proto.Message + }{ + { + desc: "direct required field", + marshaler: &Marshaler{}, + pb: &pb.MsgWithRequired{}, + }, + { + desc: "direct required field + emit defaults", + marshaler: &Marshaler{EmitDefaults: true}, + pb: &pb.MsgWithRequired{}, + }, + { + desc: "indirect required field", + marshaler: &Marshaler{}, + pb: &pb.MsgWithIndirectRequired{Subm: &pb.MsgWithRequired{}}, + }, + { + desc: "indirect required field + emit defaults", + marshaler: &Marshaler{EmitDefaults: true}, + pb: &pb.MsgWithIndirectRequired{Subm: &pb.MsgWithRequired{}}, + }, + { + desc: "direct required wkt field", + marshaler: &Marshaler{}, + pb: &pb.MsgWithRequiredWKT{}, + }, + { + desc: "direct required wkt field + emit defaults", + marshaler: &Marshaler{EmitDefaults: true}, + pb: &pb.MsgWithRequiredWKT{}, + }, + { + desc: "direct required bytes field", + marshaler: &Marshaler{}, + pb: &pb.MsgWithRequiredBytes{}, + }, + { + desc: "required in map value", + marshaler: &Marshaler{}, + pb: &pb.MsgWithIndirectRequired{ + MapField: map[string]*pb.MsgWithRequired{ + "key": {}, + }, + }, + }, + { + desc: "required in repeated item", + marshaler: &Marshaler{}, + pb: &pb.MsgWithIndirectRequired{ + SliceField: []*pb.MsgWithRequired{ + {Str: proto.String("hello")}, + {}, + }, + }, + }, + { + desc: "required inside oneof", + marshaler: &Marshaler{}, + pb: &pb.MsgWithOneof{ + Union: &pb.MsgWithOneof_MsgWithRequired{&pb.MsgWithRequired{}}, + }, + }, + { + desc: "required inside extension", + marshaler: &Marshaler{}, + pb: msgExt, + }, + } + + for _, tc := range tests { + if _, err := tc.marshaler.MarshalToString(tc.pb); err == nil { + t.Errorf("%s: expecting error in marshaling with unset required fields %+v", tc.desc, tc.pb) + } + } +} + var unmarshalingTests = []struct { desc string unmarshaler Unmarshaler json string pb proto.Message }{ - {"simple flat object", Unmarshaler{}, simpleObjectJSON, simpleObject}, - {"simple pretty object", Unmarshaler{}, simpleObjectPrettyJSON, simpleObject}, + {"simple flat object", Unmarshaler{}, simpleObjectInputJSON, simpleObject}, + {"simple pretty object", Unmarshaler{}, simpleObjectInputPrettyJSON, simpleObject}, {"repeated fields flat object", Unmarshaler{}, repeatsObjectJSON, repeatsObject}, {"repeated fields pretty object", Unmarshaler{}, repeatsObjectPrettyJSON, repeatsObject}, {"nested message/enum flat object", Unmarshaler{}, complexObjectJSON, complexObject}, @@ -542,8 +747,7 @@ var unmarshalingTests = []struct { {"Any with message and indent", Unmarshaler{}, anySimplePrettyJSON, anySimple}, {"Any with WKT", Unmarshaler{}, anyWellKnownJSON, anyWellKnown}, {"Any with WKT and indent", Unmarshaler{}, anyWellKnownPrettyJSON, anyWellKnown}, - // TODO: This is broken. - //{"map", Unmarshaler{}, `{"enumy":{"XIV":"ROMAN"}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}}, + {"map", Unmarshaler{}, `{"enumy":{"XIV":"ROMAN"}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}}, {"map", Unmarshaler{}, `{"enumy":{"XIV":2}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}}, {"oneof", Unmarshaler{}, `{"salary":31000}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Salary{31000}}}, {"oneof spec name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{"Australia"}}}, @@ -554,8 +758,12 @@ var unmarshalingTests = []struct { {"camelName input", Unmarshaler{}, `{"oBool":true}`, &pb.Simple{OBool: proto.Bool(true)}}, {"Duration", Unmarshaler{}, `{"dur":"3.000s"}`, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}}, + {"Duration", Unmarshaler{}, `{"dur":"4s"}`, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 4}}}, + {"Duration with unicode", Unmarshaler{}, `{"dur": "3\u0073"}`, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}}, {"null Duration", Unmarshaler{}, `{"dur":null}`, &pb.KnownTypes{Dur: nil}}, {"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20.021Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 21e6}}}, + {"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 0}}}, + {"Timestamp with unicode", Unmarshaler{}, `{"ts": "2014-05-13T16:53:20\u005a"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 0}}}, {"PreEpochTimestamp", Unmarshaler{}, `{"ts":"1969-12-31T23:59:58.999999995Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: -2, Nanos: 999999995}}}, {"ZeroTimeTimestamp", Unmarshaler{}, `{"ts":"0001-01-01T00:00:00Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: -62135596800, Nanos: 0}}}, {"null Timestamp", Unmarshaler{}, `{"ts":null}`, &pb.KnownTypes{Ts: nil}}, @@ -612,6 +820,14 @@ var unmarshalingTests = []struct { {"UInt32Value", Unmarshaler{}, `{"u32":4}`, &pb.KnownTypes{U32: &wpb.UInt32Value{Value: 4}}}, {"BoolValue", Unmarshaler{}, `{"bool":true}`, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}}, {"StringValue", Unmarshaler{}, `{"str":"plush"}`, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}}, + {"StringValue containing escaped character", Unmarshaler{}, `{"str":"a\/b"}`, &pb.KnownTypes{Str: &wpb.StringValue{Value: "a/b"}}}, + {"StructValue containing StringValue's", Unmarshaler{}, `{"escaped": "a\/b", "unicode": "\u00004E16\u0000754C"}`, + &stpb.Struct{ + Fields: map[string]*stpb.Value{ + "escaped": {Kind: &stpb.Value_StringValue{"a/b"}}, + "unicode": {Kind: &stpb.Value_StringValue{"\u00004E16\u0000754C"}}, + }, + }}, {"BytesValue", Unmarshaler{}, `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}}, // Ensure that `null` as a value ends up with a nil pointer instead of a [type]Value struct. @@ -624,6 +840,9 @@ var unmarshalingTests = []struct { {"null BoolValue", Unmarshaler{}, `{"bool":null}`, &pb.KnownTypes{Bool: nil}}, {"null StringValue", Unmarshaler{}, `{"str":null}`, &pb.KnownTypes{Str: nil}}, {"null BytesValue", Unmarshaler{}, `{"bytes":null}`, &pb.KnownTypes{Bytes: nil}}, + + {"required", Unmarshaler{}, `{"str":"hello"}`, &pb.MsgWithRequired{Str: proto.String("hello")}}, + {"required bytes", Unmarshaler{}, `{"byts": []}`, &pb.MsgWithRequiredBytes{Byts: []byte{}}}, } func TestUnmarshaling(t *testing.T) { @@ -633,7 +852,7 @@ func TestUnmarshaling(t *testing.T) { err := tt.unmarshaler.Unmarshal(strings.NewReader(tt.json), p) if err != nil { - t.Errorf("%s: %v", tt.desc, err) + t.Errorf("unmarshalling %s: %v", tt.desc, err) continue } @@ -711,6 +930,11 @@ var unmarshalingShouldError = []struct { {"gibberish", "{adskja123;l23=-=", new(pb.Simple)}, {"unknown field", `{"unknown": "foo"}`, new(pb.Simple)}, {"unknown enum name", `{"hilarity":"DAVE"}`, new(proto3pb.Message)}, + {"Duration containing invalid character", `{"dur": "3\U0073"}`, &pb.KnownTypes{}}, + {"Timestamp containing invalid character", `{"ts": "2014-05-13T16:53:20\U005a"}`, &pb.KnownTypes{}}, + {"StringValue containing invalid character", `{"str": "\U00004E16\U0000754C"}`, &pb.KnownTypes{}}, + {"StructValue containing invalid character", `{"str": "\U00004E16\U0000754C"}`, &stpb.Struct{}}, + {"repeated proto3 enum with non array input", `{"rFunny":"PUNS"}`, &proto3pb.Message{RFunny: []proto3pb.Message_Humour{}}}, } func TestUnmarshalingBadInput(t *testing.T) { @@ -787,8 +1011,8 @@ func TestUnmarshalJSONPBUnmarshaler(t *testing.T) { if err := Unmarshal(strings.NewReader(rawJson), &msg); err != nil { t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err) } - if msg.rawJson != rawJson { - t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.rawJson, rawJson) + if msg.RawJson != rawJson { + t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.RawJson, rawJson) } } @@ -812,7 +1036,7 @@ func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) { t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err) } - dm := &dynamicMessage{rawJson: `{"baz":[0,1,2,3],"foo":"bar"}`} + dm := &dynamicMessage{RawJson: `{"baz":[0,1,2,3],"foo":"bar"}`} var want anypb.Any if b, err := proto.Marshal(dm); err != nil { t.Errorf("an unexpected error occurred when marshaling message: %v", err) @@ -822,7 +1046,7 @@ func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) { } if !proto.Equal(&got, &want) { - t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", got, want) + t.Errorf("message contents not set correctly after unmarshalling JSON: got %v, wanted %v", got, want) } } @@ -873,25 +1097,135 @@ func (s *stringField) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error { // dynamicMessage implements protobuf.Message but is not a normal generated message type. // It provides implementations of JSONPBMarshaler and JSONPBUnmarshaler for JSON support. type dynamicMessage struct { - rawJson string `protobuf:"bytes,1,opt,name=rawJson"` + RawJson string `protobuf:"bytes,1,opt,name=rawJson"` + + // an unexported nested message is present just to ensure that it + // won't result in a panic (see issue #509) + Dummy *dynamicMessage `protobuf:"bytes,2,opt,name=dummy"` } func (m *dynamicMessage) Reset() { - m.rawJson = "{}" + m.RawJson = "{}" } func (m *dynamicMessage) String() string { - return m.rawJson + return m.RawJson } func (m *dynamicMessage) ProtoMessage() { } func (m *dynamicMessage) MarshalJSONPB(jm *Marshaler) ([]byte, error) { - return []byte(m.rawJson), nil + return []byte(m.RawJson), nil } func (m *dynamicMessage) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error { - m.rawJson = string(js) + m.RawJson = string(js) return nil } + +// Test unmarshaling message containing unset required fields should produce error. +func TestUnmarshalUnsetRequiredFields(t *testing.T) { + tests := []struct { + desc string + pb proto.Message + json string + }{ + { + desc: "direct required field missing", + pb: &pb.MsgWithRequired{}, + json: `{}`, + }, + { + desc: "direct required field set to null", + pb: &pb.MsgWithRequired{}, + json: `{"str": null}`, + }, + { + desc: "indirect required field missing", + pb: &pb.MsgWithIndirectRequired{}, + json: `{"subm": {}}`, + }, + { + desc: "indirect required field set to null", + pb: &pb.MsgWithIndirectRequired{}, + json: `{"subm": {"str": null}}`, + }, + { + desc: "direct required bytes field missing", + pb: &pb.MsgWithRequiredBytes{}, + json: `{}`, + }, + { + desc: "direct required bytes field set to null", + pb: &pb.MsgWithRequiredBytes{}, + json: `{"byts": null}`, + }, + { + desc: "direct required wkt field missing", + pb: &pb.MsgWithRequiredWKT{}, + json: `{}`, + }, + { + desc: "direct required wkt field set to null", + pb: &pb.MsgWithRequiredWKT{}, + json: `{"str": null}`, + }, + { + desc: "any containing message with required field set to null", + pb: &pb.KnownTypes{}, + json: `{"an": {"@type": "example.com/jsonpb.MsgWithRequired", "str": null}}`, + }, + { + desc: "any containing message with missing required field", + pb: &pb.KnownTypes{}, + json: `{"an": {"@type": "example.com/jsonpb.MsgWithRequired"}}`, + }, + { + desc: "missing required in map value", + pb: &pb.MsgWithIndirectRequired{}, + json: `{"map_field": {"a": {}, "b": {"str": "hi"}}}`, + }, + { + desc: "required in map value set to null", + pb: &pb.MsgWithIndirectRequired{}, + json: `{"map_field": {"a": {"str": "hello"}, "b": {"str": null}}}`, + }, + { + desc: "missing required in slice item", + pb: &pb.MsgWithIndirectRequired{}, + json: `{"slice_field": [{}, {"str": "hi"}]}`, + }, + { + desc: "required in slice item set to null", + pb: &pb.MsgWithIndirectRequired{}, + json: `{"slice_field": [{"str": "hello"}, {"str": null}]}`, + }, + { + desc: "required inside oneof missing", + pb: &pb.MsgWithOneof{}, + json: `{"msgWithRequired": {}}`, + }, + { + desc: "required inside oneof set to null", + pb: &pb.MsgWithOneof{}, + json: `{"msgWithRequired": {"str": null}}`, + }, + { + desc: "required field in extension missing", + pb: &pb.Real{}, + json: `{"[jsonpb.extm]":{}}`, + }, + { + desc: "required field in extension set to null", + pb: &pb.Real{}, + json: `{"[jsonpb.extm]":{"str": null}}`, + }, + } + + for _, tc := range tests { + if err := UnmarshalString(tc.json, tc.pb); err == nil { + t.Errorf("%s: expecting error in unmarshaling with unset required fields %s", tc.desc, tc.json) + } + } +} diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/Makefile b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/Makefile deleted file mode 100644 index eeda8ae5..00000000 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2015 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -regenerate: - protoc --go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any,Mgoogle/protobuf/duration.proto=github.com/golang/protobuf/ptypes/duration,Mgoogle/protobuf/struct.proto=github.com/golang/protobuf/ptypes/struct,Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,Mgoogle/protobuf/wrappers.proto=github.com/golang/protobuf/ptypes/wrappers:. *.proto diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/more_test_objects.pb.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/more_test_objects.pb.go index ebb180e8..0555e44f 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/more_test_objects.pb.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/more_test_objects.pb.go @@ -1,29 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: more_test_objects.proto -/* -Package jsonpb is a generated protocol buffer package. - -It is generated from these files: - more_test_objects.proto - test_objects.proto - -It has these top-level messages: - Simple3 - SimpleSlice3 - SimpleMap3 - SimpleNull3 - Mappy - Simple - NonFinites - Repeats - Widget - Maps - MsgWithOneof - Real - Complex - KnownTypes -*/ package jsonpb import proto "github.com/golang/protobuf/proto" @@ -63,16 +40,40 @@ var Numeral_value = map[string]int32{ func (x Numeral) String() string { return proto.EnumName(Numeral_name, int32(x)) } -func (Numeral) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -type Simple3 struct { - Dub float64 `protobuf:"fixed64,1,opt,name=dub" json:"dub,omitempty"` +func (Numeral) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_more_test_objects_bef0d79b901f4c4a, []int{0} } -func (m *Simple3) Reset() { *m = Simple3{} } -func (m *Simple3) String() string { return proto.CompactTextString(m) } -func (*Simple3) ProtoMessage() {} -func (*Simple3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +type Simple3 struct { + Dub float64 `protobuf:"fixed64,1,opt,name=dub,proto3" json:"dub,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Simple3) Reset() { *m = Simple3{} } +func (m *Simple3) String() string { return proto.CompactTextString(m) } +func (*Simple3) ProtoMessage() {} +func (*Simple3) Descriptor() ([]byte, []int) { + return fileDescriptor_more_test_objects_bef0d79b901f4c4a, []int{0} +} +func (m *Simple3) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Simple3.Unmarshal(m, b) +} +func (m *Simple3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Simple3.Marshal(b, m, deterministic) +} +func (dst *Simple3) XXX_Merge(src proto.Message) { + xxx_messageInfo_Simple3.Merge(dst, src) +} +func (m *Simple3) XXX_Size() int { + return xxx_messageInfo_Simple3.Size(m) +} +func (m *Simple3) XXX_DiscardUnknown() { + xxx_messageInfo_Simple3.DiscardUnknown(m) +} + +var xxx_messageInfo_Simple3 proto.InternalMessageInfo func (m *Simple3) GetDub() float64 { if m != nil { @@ -82,13 +83,35 @@ func (m *Simple3) GetDub() float64 { } type SimpleSlice3 struct { - Slices []string `protobuf:"bytes,1,rep,name=slices" json:"slices,omitempty"` + Slices []string `protobuf:"bytes,1,rep,name=slices,proto3" json:"slices,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SimpleSlice3) Reset() { *m = SimpleSlice3{} } -func (m *SimpleSlice3) String() string { return proto.CompactTextString(m) } -func (*SimpleSlice3) ProtoMessage() {} -func (*SimpleSlice3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *SimpleSlice3) Reset() { *m = SimpleSlice3{} } +func (m *SimpleSlice3) String() string { return proto.CompactTextString(m) } +func (*SimpleSlice3) ProtoMessage() {} +func (*SimpleSlice3) Descriptor() ([]byte, []int) { + return fileDescriptor_more_test_objects_bef0d79b901f4c4a, []int{1} +} +func (m *SimpleSlice3) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SimpleSlice3.Unmarshal(m, b) +} +func (m *SimpleSlice3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SimpleSlice3.Marshal(b, m, deterministic) +} +func (dst *SimpleSlice3) XXX_Merge(src proto.Message) { + xxx_messageInfo_SimpleSlice3.Merge(dst, src) +} +func (m *SimpleSlice3) XXX_Size() int { + return xxx_messageInfo_SimpleSlice3.Size(m) +} +func (m *SimpleSlice3) XXX_DiscardUnknown() { + xxx_messageInfo_SimpleSlice3.DiscardUnknown(m) +} + +var xxx_messageInfo_SimpleSlice3 proto.InternalMessageInfo func (m *SimpleSlice3) GetSlices() []string { if m != nil { @@ -98,13 +121,35 @@ func (m *SimpleSlice3) GetSlices() []string { } type SimpleMap3 struct { - Stringy map[string]string `protobuf:"bytes,1,rep,name=stringy" json:"stringy,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Stringy map[string]string `protobuf:"bytes,1,rep,name=stringy,proto3" json:"stringy,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SimpleMap3) Reset() { *m = SimpleMap3{} } -func (m *SimpleMap3) String() string { return proto.CompactTextString(m) } -func (*SimpleMap3) ProtoMessage() {} -func (*SimpleMap3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *SimpleMap3) Reset() { *m = SimpleMap3{} } +func (m *SimpleMap3) String() string { return proto.CompactTextString(m) } +func (*SimpleMap3) ProtoMessage() {} +func (*SimpleMap3) Descriptor() ([]byte, []int) { + return fileDescriptor_more_test_objects_bef0d79b901f4c4a, []int{2} +} +func (m *SimpleMap3) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SimpleMap3.Unmarshal(m, b) +} +func (m *SimpleMap3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SimpleMap3.Marshal(b, m, deterministic) +} +func (dst *SimpleMap3) XXX_Merge(src proto.Message) { + xxx_messageInfo_SimpleMap3.Merge(dst, src) +} +func (m *SimpleMap3) XXX_Size() int { + return xxx_messageInfo_SimpleMap3.Size(m) +} +func (m *SimpleMap3) XXX_DiscardUnknown() { + xxx_messageInfo_SimpleMap3.DiscardUnknown(m) +} + +var xxx_messageInfo_SimpleMap3 proto.InternalMessageInfo func (m *SimpleMap3) GetStringy() map[string]string { if m != nil { @@ -114,13 +159,35 @@ func (m *SimpleMap3) GetStringy() map[string]string { } type SimpleNull3 struct { - Simple *Simple3 `protobuf:"bytes,1,opt,name=simple" json:"simple,omitempty"` + Simple *Simple3 `protobuf:"bytes,1,opt,name=simple,proto3" json:"simple,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SimpleNull3) Reset() { *m = SimpleNull3{} } -func (m *SimpleNull3) String() string { return proto.CompactTextString(m) } -func (*SimpleNull3) ProtoMessage() {} -func (*SimpleNull3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (m *SimpleNull3) Reset() { *m = SimpleNull3{} } +func (m *SimpleNull3) String() string { return proto.CompactTextString(m) } +func (*SimpleNull3) ProtoMessage() {} +func (*SimpleNull3) Descriptor() ([]byte, []int) { + return fileDescriptor_more_test_objects_bef0d79b901f4c4a, []int{3} +} +func (m *SimpleNull3) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SimpleNull3.Unmarshal(m, b) +} +func (m *SimpleNull3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SimpleNull3.Marshal(b, m, deterministic) +} +func (dst *SimpleNull3) XXX_Merge(src proto.Message) { + xxx_messageInfo_SimpleNull3.Merge(dst, src) +} +func (m *SimpleNull3) XXX_Size() int { + return xxx_messageInfo_SimpleNull3.Size(m) +} +func (m *SimpleNull3) XXX_DiscardUnknown() { + xxx_messageInfo_SimpleNull3.DiscardUnknown(m) +} + +var xxx_messageInfo_SimpleNull3 proto.InternalMessageInfo func (m *SimpleNull3) GetSimple() *Simple3 { if m != nil { @@ -130,22 +197,44 @@ func (m *SimpleNull3) GetSimple() *Simple3 { } type Mappy struct { - Nummy map[int64]int32 `protobuf:"bytes,1,rep,name=nummy" json:"nummy,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - Strry map[string]string `protobuf:"bytes,2,rep,name=strry" json:"strry,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Objjy map[int32]*Simple3 `protobuf:"bytes,3,rep,name=objjy" json:"objjy,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Buggy map[int64]string `protobuf:"bytes,4,rep,name=buggy" json:"buggy,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Booly map[bool]bool `protobuf:"bytes,5,rep,name=booly" json:"booly,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - Enumy map[string]Numeral `protobuf:"bytes,6,rep,name=enumy" json:"enumy,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value,enum=jsonpb.Numeral"` - S32Booly map[int32]bool `protobuf:"bytes,7,rep,name=s32booly" json:"s32booly,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - S64Booly map[int64]bool `protobuf:"bytes,8,rep,name=s64booly" json:"s64booly,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - U32Booly map[uint32]bool `protobuf:"bytes,9,rep,name=u32booly" json:"u32booly,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` - U64Booly map[uint64]bool `protobuf:"bytes,10,rep,name=u64booly" json:"u64booly,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + Nummy map[int64]int32 `protobuf:"bytes,1,rep,name=nummy,proto3" json:"nummy,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + Strry map[string]string `protobuf:"bytes,2,rep,name=strry,proto3" json:"strry,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Objjy map[int32]*Simple3 `protobuf:"bytes,3,rep,name=objjy,proto3" json:"objjy,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Buggy map[int64]string `protobuf:"bytes,4,rep,name=buggy,proto3" json:"buggy,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Booly map[bool]bool `protobuf:"bytes,5,rep,name=booly,proto3" json:"booly,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + Enumy map[string]Numeral `protobuf:"bytes,6,rep,name=enumy,proto3" json:"enumy,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3,enum=jsonpb.Numeral"` + S32Booly map[int32]bool `protobuf:"bytes,7,rep,name=s32booly,proto3" json:"s32booly,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + S64Booly map[int64]bool `protobuf:"bytes,8,rep,name=s64booly,proto3" json:"s64booly,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + U32Booly map[uint32]bool `protobuf:"bytes,9,rep,name=u32booly,proto3" json:"u32booly,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + U64Booly map[uint64]bool `protobuf:"bytes,10,rep,name=u64booly,proto3" json:"u64booly,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Mappy) Reset() { *m = Mappy{} } -func (m *Mappy) String() string { return proto.CompactTextString(m) } -func (*Mappy) ProtoMessage() {} -func (*Mappy) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } +func (m *Mappy) Reset() { *m = Mappy{} } +func (m *Mappy) String() string { return proto.CompactTextString(m) } +func (*Mappy) ProtoMessage() {} +func (*Mappy) Descriptor() ([]byte, []int) { + return fileDescriptor_more_test_objects_bef0d79b901f4c4a, []int{4} +} +func (m *Mappy) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Mappy.Unmarshal(m, b) +} +func (m *Mappy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Mappy.Marshal(b, m, deterministic) +} +func (dst *Mappy) XXX_Merge(src proto.Message) { + xxx_messageInfo_Mappy.Merge(dst, src) +} +func (m *Mappy) XXX_Size() int { + return xxx_messageInfo_Mappy.Size(m) +} +func (m *Mappy) XXX_DiscardUnknown() { + xxx_messageInfo_Mappy.DiscardUnknown(m) +} + +var xxx_messageInfo_Mappy proto.InternalMessageInfo func (m *Mappy) GetNummy() map[int64]int32 { if m != nil { @@ -221,14 +310,27 @@ func init() { proto.RegisterType((*Simple3)(nil), "jsonpb.Simple3") proto.RegisterType((*SimpleSlice3)(nil), "jsonpb.SimpleSlice3") proto.RegisterType((*SimpleMap3)(nil), "jsonpb.SimpleMap3") + proto.RegisterMapType((map[string]string)(nil), "jsonpb.SimpleMap3.StringyEntry") proto.RegisterType((*SimpleNull3)(nil), "jsonpb.SimpleNull3") proto.RegisterType((*Mappy)(nil), "jsonpb.Mappy") + proto.RegisterMapType((map[bool]bool)(nil), "jsonpb.Mappy.BoolyEntry") + proto.RegisterMapType((map[int64]string)(nil), "jsonpb.Mappy.BuggyEntry") + proto.RegisterMapType((map[string]Numeral)(nil), "jsonpb.Mappy.EnumyEntry") + proto.RegisterMapType((map[int64]int32)(nil), "jsonpb.Mappy.NummyEntry") + proto.RegisterMapType((map[int32]*Simple3)(nil), "jsonpb.Mappy.ObjjyEntry") + proto.RegisterMapType((map[int32]bool)(nil), "jsonpb.Mappy.S32boolyEntry") + proto.RegisterMapType((map[int64]bool)(nil), "jsonpb.Mappy.S64boolyEntry") + proto.RegisterMapType((map[string]string)(nil), "jsonpb.Mappy.StrryEntry") + proto.RegisterMapType((map[uint32]bool)(nil), "jsonpb.Mappy.U32boolyEntry") + proto.RegisterMapType((map[uint64]bool)(nil), "jsonpb.Mappy.U64boolyEntry") proto.RegisterEnum("jsonpb.Numeral", Numeral_name, Numeral_value) } -func init() { proto.RegisterFile("more_test_objects.proto", fileDescriptor0) } +func init() { + proto.RegisterFile("more_test_objects.proto", fileDescriptor_more_test_objects_bef0d79b901f4c4a) +} -var fileDescriptor0 = []byte{ +var fileDescriptor_more_test_objects_bef0d79b901f4c4a = []byte{ // 526 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdd, 0x6b, 0xdb, 0x3c, 0x14, 0x87, 0x5f, 0x27, 0xf5, 0xd7, 0x49, 0xfb, 0x2e, 0x88, 0xb1, 0x99, 0xf4, 0x62, 0xc5, 0xb0, diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.pb.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.pb.go index d413d740..ab7b53f7 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.pb.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.pb.go @@ -6,17 +6,23 @@ package jsonpb import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" -import google_protobuf "github.com/golang/protobuf/ptypes/any" -import google_protobuf1 "github.com/golang/protobuf/ptypes/duration" -import google_protobuf2 "github.com/golang/protobuf/ptypes/struct" -import google_protobuf3 "github.com/golang/protobuf/ptypes/timestamp" -import google_protobuf4 "github.com/golang/protobuf/ptypes/wrappers" +import any "github.com/golang/protobuf/ptypes/any" +import duration "github.com/golang/protobuf/ptypes/duration" +import _struct "github.com/golang/protobuf/ptypes/struct" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" +import wrappers "github.com/golang/protobuf/ptypes/wrappers" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + type Widget_Color int32 const ( @@ -52,28 +58,59 @@ func (x *Widget_Color) UnmarshalJSON(data []byte) error { *x = Widget_Color(value) return nil } -func (Widget_Color) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{3, 0} } +func (Widget_Color) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{3, 0} +} // Test message for holding primitive types. type Simple struct { - OBool *bool `protobuf:"varint,1,opt,name=o_bool,json=oBool" json:"o_bool,omitempty"` - OInt32 *int32 `protobuf:"varint,2,opt,name=o_int32,json=oInt32" json:"o_int32,omitempty"` - OInt64 *int64 `protobuf:"varint,3,opt,name=o_int64,json=oInt64" json:"o_int64,omitempty"` - OUint32 *uint32 `protobuf:"varint,4,opt,name=o_uint32,json=oUint32" json:"o_uint32,omitempty"` - OUint64 *uint64 `protobuf:"varint,5,opt,name=o_uint64,json=oUint64" json:"o_uint64,omitempty"` - OSint32 *int32 `protobuf:"zigzag32,6,opt,name=o_sint32,json=oSint32" json:"o_sint32,omitempty"` - OSint64 *int64 `protobuf:"zigzag64,7,opt,name=o_sint64,json=oSint64" json:"o_sint64,omitempty"` - OFloat *float32 `protobuf:"fixed32,8,opt,name=o_float,json=oFloat" json:"o_float,omitempty"` - ODouble *float64 `protobuf:"fixed64,9,opt,name=o_double,json=oDouble" json:"o_double,omitempty"` - OString *string `protobuf:"bytes,10,opt,name=o_string,json=oString" json:"o_string,omitempty"` - OBytes []byte `protobuf:"bytes,11,opt,name=o_bytes,json=oBytes" json:"o_bytes,omitempty"` - XXX_unrecognized []byte `json:"-"` + OBool *bool `protobuf:"varint,1,opt,name=o_bool,json=oBool" json:"o_bool,omitempty"` + OInt32 *int32 `protobuf:"varint,2,opt,name=o_int32,json=oInt32" json:"o_int32,omitempty"` + OInt32Str *int32 `protobuf:"varint,3,opt,name=o_int32_str,json=oInt32Str" json:"o_int32_str,omitempty"` + OInt64 *int64 `protobuf:"varint,4,opt,name=o_int64,json=oInt64" json:"o_int64,omitempty"` + OInt64Str *int64 `protobuf:"varint,5,opt,name=o_int64_str,json=oInt64Str" json:"o_int64_str,omitempty"` + OUint32 *uint32 `protobuf:"varint,6,opt,name=o_uint32,json=oUint32" json:"o_uint32,omitempty"` + OUint32Str *uint32 `protobuf:"varint,7,opt,name=o_uint32_str,json=oUint32Str" json:"o_uint32_str,omitempty"` + OUint64 *uint64 `protobuf:"varint,8,opt,name=o_uint64,json=oUint64" json:"o_uint64,omitempty"` + OUint64Str *uint64 `protobuf:"varint,9,opt,name=o_uint64_str,json=oUint64Str" json:"o_uint64_str,omitempty"` + OSint32 *int32 `protobuf:"zigzag32,10,opt,name=o_sint32,json=oSint32" json:"o_sint32,omitempty"` + OSint32Str *int32 `protobuf:"zigzag32,11,opt,name=o_sint32_str,json=oSint32Str" json:"o_sint32_str,omitempty"` + OSint64 *int64 `protobuf:"zigzag64,12,opt,name=o_sint64,json=oSint64" json:"o_sint64,omitempty"` + OSint64Str *int64 `protobuf:"zigzag64,13,opt,name=o_sint64_str,json=oSint64Str" json:"o_sint64_str,omitempty"` + OFloat *float32 `protobuf:"fixed32,14,opt,name=o_float,json=oFloat" json:"o_float,omitempty"` + OFloatStr *float32 `protobuf:"fixed32,15,opt,name=o_float_str,json=oFloatStr" json:"o_float_str,omitempty"` + ODouble *float64 `protobuf:"fixed64,16,opt,name=o_double,json=oDouble" json:"o_double,omitempty"` + ODoubleStr *float64 `protobuf:"fixed64,17,opt,name=o_double_str,json=oDoubleStr" json:"o_double_str,omitempty"` + OString *string `protobuf:"bytes,18,opt,name=o_string,json=oString" json:"o_string,omitempty"` + OBytes []byte `protobuf:"bytes,19,opt,name=o_bytes,json=oBytes" json:"o_bytes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Simple) Reset() { *m = Simple{} } -func (m *Simple) String() string { return proto.CompactTextString(m) } -func (*Simple) ProtoMessage() {} -func (*Simple) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } +func (m *Simple) Reset() { *m = Simple{} } +func (m *Simple) String() string { return proto.CompactTextString(m) } +func (*Simple) ProtoMessage() {} +func (*Simple) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{0} +} +func (m *Simple) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Simple.Unmarshal(m, b) +} +func (m *Simple) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Simple.Marshal(b, m, deterministic) +} +func (dst *Simple) XXX_Merge(src proto.Message) { + xxx_messageInfo_Simple.Merge(dst, src) +} +func (m *Simple) XXX_Size() int { + return xxx_messageInfo_Simple.Size(m) +} +func (m *Simple) XXX_DiscardUnknown() { + xxx_messageInfo_Simple.DiscardUnknown(m) +} + +var xxx_messageInfo_Simple proto.InternalMessageInfo func (m *Simple) GetOBool() bool { if m != nil && m.OBool != nil { @@ -89,6 +126,13 @@ func (m *Simple) GetOInt32() int32 { return 0 } +func (m *Simple) GetOInt32Str() int32 { + if m != nil && m.OInt32Str != nil { + return *m.OInt32Str + } + return 0 +} + func (m *Simple) GetOInt64() int64 { if m != nil && m.OInt64 != nil { return *m.OInt64 @@ -96,6 +140,13 @@ func (m *Simple) GetOInt64() int64 { return 0 } +func (m *Simple) GetOInt64Str() int64 { + if m != nil && m.OInt64Str != nil { + return *m.OInt64Str + } + return 0 +} + func (m *Simple) GetOUint32() uint32 { if m != nil && m.OUint32 != nil { return *m.OUint32 @@ -103,6 +154,13 @@ func (m *Simple) GetOUint32() uint32 { return 0 } +func (m *Simple) GetOUint32Str() uint32 { + if m != nil && m.OUint32Str != nil { + return *m.OUint32Str + } + return 0 +} + func (m *Simple) GetOUint64() uint64 { if m != nil && m.OUint64 != nil { return *m.OUint64 @@ -110,6 +168,13 @@ func (m *Simple) GetOUint64() uint64 { return 0 } +func (m *Simple) GetOUint64Str() uint64 { + if m != nil && m.OUint64Str != nil { + return *m.OUint64Str + } + return 0 +} + func (m *Simple) GetOSint32() int32 { if m != nil && m.OSint32 != nil { return *m.OSint32 @@ -117,6 +182,13 @@ func (m *Simple) GetOSint32() int32 { return 0 } +func (m *Simple) GetOSint32Str() int32 { + if m != nil && m.OSint32Str != nil { + return *m.OSint32Str + } + return 0 +} + func (m *Simple) GetOSint64() int64 { if m != nil && m.OSint64 != nil { return *m.OSint64 @@ -124,6 +196,13 @@ func (m *Simple) GetOSint64() int64 { return 0 } +func (m *Simple) GetOSint64Str() int64 { + if m != nil && m.OSint64Str != nil { + return *m.OSint64Str + } + return 0 +} + func (m *Simple) GetOFloat() float32 { if m != nil && m.OFloat != nil { return *m.OFloat @@ -131,6 +210,13 @@ func (m *Simple) GetOFloat() float32 { return 0 } +func (m *Simple) GetOFloatStr() float32 { + if m != nil && m.OFloatStr != nil { + return *m.OFloatStr + } + return 0 +} + func (m *Simple) GetODouble() float64 { if m != nil && m.ODouble != nil { return *m.ODouble @@ -138,6 +224,13 @@ func (m *Simple) GetODouble() float64 { return 0 } +func (m *Simple) GetODoubleStr() float64 { + if m != nil && m.ODoubleStr != nil { + return *m.ODoubleStr + } + return 0 +} + func (m *Simple) GetOString() string { if m != nil && m.OString != nil { return *m.OString @@ -154,19 +247,40 @@ func (m *Simple) GetOBytes() []byte { // Test message for holding special non-finites primitives. type NonFinites struct { - FNan *float32 `protobuf:"fixed32,1,opt,name=f_nan,json=fNan" json:"f_nan,omitempty"` - FPinf *float32 `protobuf:"fixed32,2,opt,name=f_pinf,json=fPinf" json:"f_pinf,omitempty"` - FNinf *float32 `protobuf:"fixed32,3,opt,name=f_ninf,json=fNinf" json:"f_ninf,omitempty"` - DNan *float64 `protobuf:"fixed64,4,opt,name=d_nan,json=dNan" json:"d_nan,omitempty"` - DPinf *float64 `protobuf:"fixed64,5,opt,name=d_pinf,json=dPinf" json:"d_pinf,omitempty"` - DNinf *float64 `protobuf:"fixed64,6,opt,name=d_ninf,json=dNinf" json:"d_ninf,omitempty"` - XXX_unrecognized []byte `json:"-"` + FNan *float32 `protobuf:"fixed32,1,opt,name=f_nan,json=fNan" json:"f_nan,omitempty"` + FPinf *float32 `protobuf:"fixed32,2,opt,name=f_pinf,json=fPinf" json:"f_pinf,omitempty"` + FNinf *float32 `protobuf:"fixed32,3,opt,name=f_ninf,json=fNinf" json:"f_ninf,omitempty"` + DNan *float64 `protobuf:"fixed64,4,opt,name=d_nan,json=dNan" json:"d_nan,omitempty"` + DPinf *float64 `protobuf:"fixed64,5,opt,name=d_pinf,json=dPinf" json:"d_pinf,omitempty"` + DNinf *float64 `protobuf:"fixed64,6,opt,name=d_ninf,json=dNinf" json:"d_ninf,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *NonFinites) Reset() { *m = NonFinites{} } -func (m *NonFinites) String() string { return proto.CompactTextString(m) } -func (*NonFinites) ProtoMessage() {} -func (*NonFinites) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } +func (m *NonFinites) Reset() { *m = NonFinites{} } +func (m *NonFinites) String() string { return proto.CompactTextString(m) } +func (*NonFinites) ProtoMessage() {} +func (*NonFinites) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{1} +} +func (m *NonFinites) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NonFinites.Unmarshal(m, b) +} +func (m *NonFinites) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NonFinites.Marshal(b, m, deterministic) +} +func (dst *NonFinites) XXX_Merge(src proto.Message) { + xxx_messageInfo_NonFinites.Merge(dst, src) +} +func (m *NonFinites) XXX_Size() int { + return xxx_messageInfo_NonFinites.Size(m) +} +func (m *NonFinites) XXX_DiscardUnknown() { + xxx_messageInfo_NonFinites.DiscardUnknown(m) +} + +var xxx_messageInfo_NonFinites proto.InternalMessageInfo func (m *NonFinites) GetFNan() float32 { if m != nil && m.FNan != nil { @@ -212,24 +326,45 @@ func (m *NonFinites) GetDNinf() float64 { // Test message for holding repeated primitives. type Repeats struct { - RBool []bool `protobuf:"varint,1,rep,name=r_bool,json=rBool" json:"r_bool,omitempty"` - RInt32 []int32 `protobuf:"varint,2,rep,name=r_int32,json=rInt32" json:"r_int32,omitempty"` - RInt64 []int64 `protobuf:"varint,3,rep,name=r_int64,json=rInt64" json:"r_int64,omitempty"` - RUint32 []uint32 `protobuf:"varint,4,rep,name=r_uint32,json=rUint32" json:"r_uint32,omitempty"` - RUint64 []uint64 `protobuf:"varint,5,rep,name=r_uint64,json=rUint64" json:"r_uint64,omitempty"` - RSint32 []int32 `protobuf:"zigzag32,6,rep,name=r_sint32,json=rSint32" json:"r_sint32,omitempty"` - RSint64 []int64 `protobuf:"zigzag64,7,rep,name=r_sint64,json=rSint64" json:"r_sint64,omitempty"` - RFloat []float32 `protobuf:"fixed32,8,rep,name=r_float,json=rFloat" json:"r_float,omitempty"` - RDouble []float64 `protobuf:"fixed64,9,rep,name=r_double,json=rDouble" json:"r_double,omitempty"` - RString []string `protobuf:"bytes,10,rep,name=r_string,json=rString" json:"r_string,omitempty"` - RBytes [][]byte `protobuf:"bytes,11,rep,name=r_bytes,json=rBytes" json:"r_bytes,omitempty"` - XXX_unrecognized []byte `json:"-"` + RBool []bool `protobuf:"varint,1,rep,name=r_bool,json=rBool" json:"r_bool,omitempty"` + RInt32 []int32 `protobuf:"varint,2,rep,name=r_int32,json=rInt32" json:"r_int32,omitempty"` + RInt64 []int64 `protobuf:"varint,3,rep,name=r_int64,json=rInt64" json:"r_int64,omitempty"` + RUint32 []uint32 `protobuf:"varint,4,rep,name=r_uint32,json=rUint32" json:"r_uint32,omitempty"` + RUint64 []uint64 `protobuf:"varint,5,rep,name=r_uint64,json=rUint64" json:"r_uint64,omitempty"` + RSint32 []int32 `protobuf:"zigzag32,6,rep,name=r_sint32,json=rSint32" json:"r_sint32,omitempty"` + RSint64 []int64 `protobuf:"zigzag64,7,rep,name=r_sint64,json=rSint64" json:"r_sint64,omitempty"` + RFloat []float32 `protobuf:"fixed32,8,rep,name=r_float,json=rFloat" json:"r_float,omitempty"` + RDouble []float64 `protobuf:"fixed64,9,rep,name=r_double,json=rDouble" json:"r_double,omitempty"` + RString []string `protobuf:"bytes,10,rep,name=r_string,json=rString" json:"r_string,omitempty"` + RBytes [][]byte `protobuf:"bytes,11,rep,name=r_bytes,json=rBytes" json:"r_bytes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Repeats) Reset() { *m = Repeats{} } -func (m *Repeats) String() string { return proto.CompactTextString(m) } -func (*Repeats) ProtoMessage() {} -func (*Repeats) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } +func (m *Repeats) Reset() { *m = Repeats{} } +func (m *Repeats) String() string { return proto.CompactTextString(m) } +func (*Repeats) ProtoMessage() {} +func (*Repeats) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{2} +} +func (m *Repeats) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Repeats.Unmarshal(m, b) +} +func (m *Repeats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Repeats.Marshal(b, m, deterministic) +} +func (dst *Repeats) XXX_Merge(src proto.Message) { + xxx_messageInfo_Repeats.Merge(dst, src) +} +func (m *Repeats) XXX_Size() int { + return xxx_messageInfo_Repeats.Size(m) +} +func (m *Repeats) XXX_DiscardUnknown() { + xxx_messageInfo_Repeats.DiscardUnknown(m) +} + +var xxx_messageInfo_Repeats proto.InternalMessageInfo func (m *Repeats) GetRBool() []bool { if m != nil { @@ -310,19 +445,40 @@ func (m *Repeats) GetRBytes() [][]byte { // Test message for holding enums and nested messages. type Widget struct { - Color *Widget_Color `protobuf:"varint,1,opt,name=color,enum=jsonpb.Widget_Color" json:"color,omitempty"` - RColor []Widget_Color `protobuf:"varint,2,rep,name=r_color,json=rColor,enum=jsonpb.Widget_Color" json:"r_color,omitempty"` - Simple *Simple `protobuf:"bytes,10,opt,name=simple" json:"simple,omitempty"` - RSimple []*Simple `protobuf:"bytes,11,rep,name=r_simple,json=rSimple" json:"r_simple,omitempty"` - Repeats *Repeats `protobuf:"bytes,20,opt,name=repeats" json:"repeats,omitempty"` - RRepeats []*Repeats `protobuf:"bytes,21,rep,name=r_repeats,json=rRepeats" json:"r_repeats,omitempty"` - XXX_unrecognized []byte `json:"-"` + Color *Widget_Color `protobuf:"varint,1,opt,name=color,enum=jsonpb.Widget_Color" json:"color,omitempty"` + RColor []Widget_Color `protobuf:"varint,2,rep,name=r_color,json=rColor,enum=jsonpb.Widget_Color" json:"r_color,omitempty"` + Simple *Simple `protobuf:"bytes,10,opt,name=simple" json:"simple,omitempty"` + RSimple []*Simple `protobuf:"bytes,11,rep,name=r_simple,json=rSimple" json:"r_simple,omitempty"` + Repeats *Repeats `protobuf:"bytes,20,opt,name=repeats" json:"repeats,omitempty"` + RRepeats []*Repeats `protobuf:"bytes,21,rep,name=r_repeats,json=rRepeats" json:"r_repeats,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Widget) Reset() { *m = Widget{} } -func (m *Widget) String() string { return proto.CompactTextString(m) } -func (*Widget) ProtoMessage() {} -func (*Widget) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } +func (m *Widget) Reset() { *m = Widget{} } +func (m *Widget) String() string { return proto.CompactTextString(m) } +func (*Widget) ProtoMessage() {} +func (*Widget) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{3} +} +func (m *Widget) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Widget.Unmarshal(m, b) +} +func (m *Widget) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Widget.Marshal(b, m, deterministic) +} +func (dst *Widget) XXX_Merge(src proto.Message) { + xxx_messageInfo_Widget.Merge(dst, src) +} +func (m *Widget) XXX_Size() int { + return xxx_messageInfo_Widget.Size(m) +} +func (m *Widget) XXX_DiscardUnknown() { + xxx_messageInfo_Widget.DiscardUnknown(m) +} + +var xxx_messageInfo_Widget proto.InternalMessageInfo func (m *Widget) GetColor() Widget_Color { if m != nil && m.Color != nil { @@ -367,15 +523,36 @@ func (m *Widget) GetRRepeats() []*Repeats { } type Maps struct { - MInt64Str map[int64]string `protobuf:"bytes,1,rep,name=m_int64_str,json=mInt64Str" json:"m_int64_str,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - MBoolSimple map[bool]*Simple `protobuf:"bytes,2,rep,name=m_bool_simple,json=mBoolSimple" json:"m_bool_simple,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - XXX_unrecognized []byte `json:"-"` + MInt64Str map[int64]string `protobuf:"bytes,1,rep,name=m_int64_str,json=mInt64Str" json:"m_int64_str,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + MBoolSimple map[bool]*Simple `protobuf:"bytes,2,rep,name=m_bool_simple,json=mBoolSimple" json:"m_bool_simple,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Maps) Reset() { *m = Maps{} } -func (m *Maps) String() string { return proto.CompactTextString(m) } -func (*Maps) ProtoMessage() {} -func (*Maps) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} } +func (m *Maps) Reset() { *m = Maps{} } +func (m *Maps) String() string { return proto.CompactTextString(m) } +func (*Maps) ProtoMessage() {} +func (*Maps) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{4} +} +func (m *Maps) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Maps.Unmarshal(m, b) +} +func (m *Maps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Maps.Marshal(b, m, deterministic) +} +func (dst *Maps) XXX_Merge(src proto.Message) { + xxx_messageInfo_Maps.Merge(dst, src) +} +func (m *Maps) XXX_Size() int { + return xxx_messageInfo_Maps.Size(m) +} +func (m *Maps) XXX_DiscardUnknown() { + xxx_messageInfo_Maps.DiscardUnknown(m) +} + +var xxx_messageInfo_Maps proto.InternalMessageInfo func (m *Maps) GetMInt64Str() map[int64]string { if m != nil { @@ -397,14 +574,36 @@ type MsgWithOneof struct { // *MsgWithOneof_Salary // *MsgWithOneof_Country // *MsgWithOneof_HomeAddress - Union isMsgWithOneof_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` + // *MsgWithOneof_MsgWithRequired + Union isMsgWithOneof_Union `protobuf_oneof:"union"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MsgWithOneof) Reset() { *m = MsgWithOneof{} } -func (m *MsgWithOneof) String() string { return proto.CompactTextString(m) } -func (*MsgWithOneof) ProtoMessage() {} -func (*MsgWithOneof) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{5} } +func (m *MsgWithOneof) Reset() { *m = MsgWithOneof{} } +func (m *MsgWithOneof) String() string { return proto.CompactTextString(m) } +func (*MsgWithOneof) ProtoMessage() {} +func (*MsgWithOneof) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{5} +} +func (m *MsgWithOneof) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgWithOneof.Unmarshal(m, b) +} +func (m *MsgWithOneof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgWithOneof.Marshal(b, m, deterministic) +} +func (dst *MsgWithOneof) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithOneof.Merge(dst, src) +} +func (m *MsgWithOneof) XXX_Size() int { + return xxx_messageInfo_MsgWithOneof.Size(m) +} +func (m *MsgWithOneof) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithOneof.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithOneof proto.InternalMessageInfo type isMsgWithOneof_Union interface { isMsgWithOneof_Union() @@ -413,21 +612,33 @@ type isMsgWithOneof_Union interface { type MsgWithOneof_Title struct { Title string `protobuf:"bytes,1,opt,name=title,oneof"` } + type MsgWithOneof_Salary struct { Salary int64 `protobuf:"varint,2,opt,name=salary,oneof"` } + type MsgWithOneof_Country struct { Country string `protobuf:"bytes,3,opt,name=Country,oneof"` } + type MsgWithOneof_HomeAddress struct { HomeAddress string `protobuf:"bytes,4,opt,name=home_address,json=homeAddress,oneof"` } -func (*MsgWithOneof_Title) isMsgWithOneof_Union() {} -func (*MsgWithOneof_Salary) isMsgWithOneof_Union() {} -func (*MsgWithOneof_Country) isMsgWithOneof_Union() {} +type MsgWithOneof_MsgWithRequired struct { + MsgWithRequired *MsgWithRequired `protobuf:"bytes,5,opt,name=msg_with_required,json=msgWithRequired,oneof"` +} + +func (*MsgWithOneof_Title) isMsgWithOneof_Union() {} + +func (*MsgWithOneof_Salary) isMsgWithOneof_Union() {} + +func (*MsgWithOneof_Country) isMsgWithOneof_Union() {} + func (*MsgWithOneof_HomeAddress) isMsgWithOneof_Union() {} +func (*MsgWithOneof_MsgWithRequired) isMsgWithOneof_Union() {} + func (m *MsgWithOneof) GetUnion() isMsgWithOneof_Union { if m != nil { return m.Union @@ -463,6 +674,13 @@ func (m *MsgWithOneof) GetHomeAddress() string { return "" } +func (m *MsgWithOneof) GetMsgWithRequired() *MsgWithRequired { + if x, ok := m.GetUnion().(*MsgWithOneof_MsgWithRequired); ok { + return x.MsgWithRequired + } + return nil +} + // XXX_OneofFuncs is for the internal use of the proto package. func (*MsgWithOneof) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { return _MsgWithOneof_OneofMarshaler, _MsgWithOneof_OneofUnmarshaler, _MsgWithOneof_OneofSizer, []interface{}{ @@ -470,6 +688,7 @@ func (*MsgWithOneof) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) (*MsgWithOneof_Salary)(nil), (*MsgWithOneof_Country)(nil), (*MsgWithOneof_HomeAddress)(nil), + (*MsgWithOneof_MsgWithRequired)(nil), } } @@ -489,6 +708,11 @@ func _MsgWithOneof_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { case *MsgWithOneof_HomeAddress: b.EncodeVarint(4<<3 | proto.WireBytes) b.EncodeStringBytes(x.HomeAddress) + case *MsgWithOneof_MsgWithRequired: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.MsgWithRequired); err != nil { + return err + } case nil: default: return fmt.Errorf("MsgWithOneof.Union has unexpected type %T", x) @@ -527,6 +751,14 @@ func _MsgWithOneof_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.B x, err := b.DecodeStringBytes() m.Union = &MsgWithOneof_HomeAddress{x} return true, err + case 5: // union.msg_with_required + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(MsgWithRequired) + err := b.DecodeMessage(msg) + m.Union = &MsgWithOneof_MsgWithRequired{msg} + return true, err default: return false, nil } @@ -537,20 +769,25 @@ func _MsgWithOneof_OneofSizer(msg proto.Message) (n int) { // union switch x := m.Union.(type) { case *MsgWithOneof_Title: - n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(len(x.Title))) n += len(x.Title) case *MsgWithOneof_Salary: - n += proto.SizeVarint(2<<3 | proto.WireVarint) + n += 1 // tag and wire n += proto.SizeVarint(uint64(x.Salary)) case *MsgWithOneof_Country: - n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(len(x.Country))) n += len(x.Country) case *MsgWithOneof_HomeAddress: - n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(len(x.HomeAddress))) n += len(x.HomeAddress) + case *MsgWithOneof_MsgWithRequired: + s := proto.Size(x.MsgWithRequired) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s case nil: default: panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) @@ -560,22 +797,43 @@ func _MsgWithOneof_OneofSizer(msg proto.Message) (n int) { type Real struct { Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Real) Reset() { *m = Real{} } -func (m *Real) String() string { return proto.CompactTextString(m) } -func (*Real) ProtoMessage() {} -func (*Real) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{6} } +func (m *Real) Reset() { *m = Real{} } +func (m *Real) String() string { return proto.CompactTextString(m) } +func (*Real) ProtoMessage() {} +func (*Real) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{6} +} var extRange_Real = []proto.ExtensionRange{ - {100, 536870911}, + {Start: 100, End: 536870911}, } func (*Real) ExtensionRangeArray() []proto.ExtensionRange { return extRange_Real } +func (m *Real) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Real.Unmarshal(m, b) +} +func (m *Real) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Real.Marshal(b, m, deterministic) +} +func (dst *Real) XXX_Merge(src proto.Message) { + xxx_messageInfo_Real.Merge(dst, src) +} +func (m *Real) XXX_Size() int { + return xxx_messageInfo_Real.Size(m) +} +func (m *Real) XXX_DiscardUnknown() { + xxx_messageInfo_Real.DiscardUnknown(m) +} + +var xxx_messageInfo_Real proto.InternalMessageInfo func (m *Real) GetValue() float64 { if m != nil && m.Value != nil { @@ -586,22 +844,43 @@ func (m *Real) GetValue() float64 { type Complex struct { Imaginary *float64 `protobuf:"fixed64,1,opt,name=imaginary" json:"imaginary,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Complex) Reset() { *m = Complex{} } -func (m *Complex) String() string { return proto.CompactTextString(m) } -func (*Complex) ProtoMessage() {} -func (*Complex) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{7} } +func (m *Complex) Reset() { *m = Complex{} } +func (m *Complex) String() string { return proto.CompactTextString(m) } +func (*Complex) ProtoMessage() {} +func (*Complex) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{7} +} var extRange_Complex = []proto.ExtensionRange{ - {100, 536870911}, + {Start: 100, End: 536870911}, } func (*Complex) ExtensionRangeArray() []proto.ExtensionRange { return extRange_Complex } +func (m *Complex) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Complex.Unmarshal(m, b) +} +func (m *Complex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Complex.Marshal(b, m, deterministic) +} +func (dst *Complex) XXX_Merge(src proto.Message) { + xxx_messageInfo_Complex.Merge(dst, src) +} +func (m *Complex) XXX_Size() int { + return xxx_messageInfo_Complex.Size(m) +} +func (m *Complex) XXX_DiscardUnknown() { + xxx_messageInfo_Complex.DiscardUnknown(m) +} + +var xxx_messageInfo_Complex proto.InternalMessageInfo func (m *Complex) GetImaginary() float64 { if m != nil && m.Imaginary != nil { @@ -620,134 +899,324 @@ var E_Complex_RealExtension = &proto.ExtensionDesc{ } type KnownTypes struct { - An *google_protobuf.Any `protobuf:"bytes,14,opt,name=an" json:"an,omitempty"` - Dur *google_protobuf1.Duration `protobuf:"bytes,1,opt,name=dur" json:"dur,omitempty"` - St *google_protobuf2.Struct `protobuf:"bytes,12,opt,name=st" json:"st,omitempty"` - Ts *google_protobuf3.Timestamp `protobuf:"bytes,2,opt,name=ts" json:"ts,omitempty"` - Lv *google_protobuf2.ListValue `protobuf:"bytes,15,opt,name=lv" json:"lv,omitempty"` - Val *google_protobuf2.Value `protobuf:"bytes,16,opt,name=val" json:"val,omitempty"` - Dbl *google_protobuf4.DoubleValue `protobuf:"bytes,3,opt,name=dbl" json:"dbl,omitempty"` - Flt *google_protobuf4.FloatValue `protobuf:"bytes,4,opt,name=flt" json:"flt,omitempty"` - I64 *google_protobuf4.Int64Value `protobuf:"bytes,5,opt,name=i64" json:"i64,omitempty"` - U64 *google_protobuf4.UInt64Value `protobuf:"bytes,6,opt,name=u64" json:"u64,omitempty"` - I32 *google_protobuf4.Int32Value `protobuf:"bytes,7,opt,name=i32" json:"i32,omitempty"` - U32 *google_protobuf4.UInt32Value `protobuf:"bytes,8,opt,name=u32" json:"u32,omitempty"` - Bool *google_protobuf4.BoolValue `protobuf:"bytes,9,opt,name=bool" json:"bool,omitempty"` - Str *google_protobuf4.StringValue `protobuf:"bytes,10,opt,name=str" json:"str,omitempty"` - Bytes *google_protobuf4.BytesValue `protobuf:"bytes,11,opt,name=bytes" json:"bytes,omitempty"` - XXX_unrecognized []byte `json:"-"` + An *any.Any `protobuf:"bytes,14,opt,name=an" json:"an,omitempty"` + Dur *duration.Duration `protobuf:"bytes,1,opt,name=dur" json:"dur,omitempty"` + St *_struct.Struct `protobuf:"bytes,12,opt,name=st" json:"st,omitempty"` + Ts *timestamp.Timestamp `protobuf:"bytes,2,opt,name=ts" json:"ts,omitempty"` + Lv *_struct.ListValue `protobuf:"bytes,15,opt,name=lv" json:"lv,omitempty"` + Val *_struct.Value `protobuf:"bytes,16,opt,name=val" json:"val,omitempty"` + Dbl *wrappers.DoubleValue `protobuf:"bytes,3,opt,name=dbl" json:"dbl,omitempty"` + Flt *wrappers.FloatValue `protobuf:"bytes,4,opt,name=flt" json:"flt,omitempty"` + I64 *wrappers.Int64Value `protobuf:"bytes,5,opt,name=i64" json:"i64,omitempty"` + U64 *wrappers.UInt64Value `protobuf:"bytes,6,opt,name=u64" json:"u64,omitempty"` + I32 *wrappers.Int32Value `protobuf:"bytes,7,opt,name=i32" json:"i32,omitempty"` + U32 *wrappers.UInt32Value `protobuf:"bytes,8,opt,name=u32" json:"u32,omitempty"` + Bool *wrappers.BoolValue `protobuf:"bytes,9,opt,name=bool" json:"bool,omitempty"` + Str *wrappers.StringValue `protobuf:"bytes,10,opt,name=str" json:"str,omitempty"` + Bytes *wrappers.BytesValue `protobuf:"bytes,11,opt,name=bytes" json:"bytes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *KnownTypes) Reset() { *m = KnownTypes{} } -func (m *KnownTypes) String() string { return proto.CompactTextString(m) } -func (*KnownTypes) ProtoMessage() {} -func (*KnownTypes) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{8} } +func (m *KnownTypes) Reset() { *m = KnownTypes{} } +func (m *KnownTypes) String() string { return proto.CompactTextString(m) } +func (*KnownTypes) ProtoMessage() {} +func (*KnownTypes) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{8} +} +func (m *KnownTypes) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KnownTypes.Unmarshal(m, b) +} +func (m *KnownTypes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KnownTypes.Marshal(b, m, deterministic) +} +func (dst *KnownTypes) XXX_Merge(src proto.Message) { + xxx_messageInfo_KnownTypes.Merge(dst, src) +} +func (m *KnownTypes) XXX_Size() int { + return xxx_messageInfo_KnownTypes.Size(m) +} +func (m *KnownTypes) XXX_DiscardUnknown() { + xxx_messageInfo_KnownTypes.DiscardUnknown(m) +} -func (m *KnownTypes) GetAn() *google_protobuf.Any { +var xxx_messageInfo_KnownTypes proto.InternalMessageInfo + +func (m *KnownTypes) GetAn() *any.Any { if m != nil { return m.An } return nil } -func (m *KnownTypes) GetDur() *google_protobuf1.Duration { +func (m *KnownTypes) GetDur() *duration.Duration { if m != nil { return m.Dur } return nil } -func (m *KnownTypes) GetSt() *google_protobuf2.Struct { +func (m *KnownTypes) GetSt() *_struct.Struct { if m != nil { return m.St } return nil } -func (m *KnownTypes) GetTs() *google_protobuf3.Timestamp { +func (m *KnownTypes) GetTs() *timestamp.Timestamp { if m != nil { return m.Ts } return nil } -func (m *KnownTypes) GetLv() *google_protobuf2.ListValue { +func (m *KnownTypes) GetLv() *_struct.ListValue { if m != nil { return m.Lv } return nil } -func (m *KnownTypes) GetVal() *google_protobuf2.Value { +func (m *KnownTypes) GetVal() *_struct.Value { if m != nil { return m.Val } return nil } -func (m *KnownTypes) GetDbl() *google_protobuf4.DoubleValue { +func (m *KnownTypes) GetDbl() *wrappers.DoubleValue { if m != nil { return m.Dbl } return nil } -func (m *KnownTypes) GetFlt() *google_protobuf4.FloatValue { +func (m *KnownTypes) GetFlt() *wrappers.FloatValue { if m != nil { return m.Flt } return nil } -func (m *KnownTypes) GetI64() *google_protobuf4.Int64Value { +func (m *KnownTypes) GetI64() *wrappers.Int64Value { if m != nil { return m.I64 } return nil } -func (m *KnownTypes) GetU64() *google_protobuf4.UInt64Value { +func (m *KnownTypes) GetU64() *wrappers.UInt64Value { if m != nil { return m.U64 } return nil } -func (m *KnownTypes) GetI32() *google_protobuf4.Int32Value { +func (m *KnownTypes) GetI32() *wrappers.Int32Value { if m != nil { return m.I32 } return nil } -func (m *KnownTypes) GetU32() *google_protobuf4.UInt32Value { +func (m *KnownTypes) GetU32() *wrappers.UInt32Value { if m != nil { return m.U32 } return nil } -func (m *KnownTypes) GetBool() *google_protobuf4.BoolValue { +func (m *KnownTypes) GetBool() *wrappers.BoolValue { if m != nil { return m.Bool } return nil } -func (m *KnownTypes) GetStr() *google_protobuf4.StringValue { +func (m *KnownTypes) GetStr() *wrappers.StringValue { if m != nil { return m.Str } return nil } -func (m *KnownTypes) GetBytes() *google_protobuf4.BytesValue { +func (m *KnownTypes) GetBytes() *wrappers.BytesValue { if m != nil { return m.Bytes } return nil } +// Test messages for marshaling/unmarshaling required fields. +type MsgWithRequired struct { + Str *string `protobuf:"bytes,1,req,name=str" json:"str,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgWithRequired) Reset() { *m = MsgWithRequired{} } +func (m *MsgWithRequired) String() string { return proto.CompactTextString(m) } +func (*MsgWithRequired) ProtoMessage() {} +func (*MsgWithRequired) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{9} +} +func (m *MsgWithRequired) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgWithRequired.Unmarshal(m, b) +} +func (m *MsgWithRequired) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgWithRequired.Marshal(b, m, deterministic) +} +func (dst *MsgWithRequired) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithRequired.Merge(dst, src) +} +func (m *MsgWithRequired) XXX_Size() int { + return xxx_messageInfo_MsgWithRequired.Size(m) +} +func (m *MsgWithRequired) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithRequired.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithRequired proto.InternalMessageInfo + +func (m *MsgWithRequired) GetStr() string { + if m != nil && m.Str != nil { + return *m.Str + } + return "" +} + +type MsgWithIndirectRequired struct { + Subm *MsgWithRequired `protobuf:"bytes,1,opt,name=subm" json:"subm,omitempty"` + MapField map[string]*MsgWithRequired `protobuf:"bytes,2,rep,name=map_field,json=mapField" json:"map_field,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + SliceField []*MsgWithRequired `protobuf:"bytes,3,rep,name=slice_field,json=sliceField" json:"slice_field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgWithIndirectRequired) Reset() { *m = MsgWithIndirectRequired{} } +func (m *MsgWithIndirectRequired) String() string { return proto.CompactTextString(m) } +func (*MsgWithIndirectRequired) ProtoMessage() {} +func (*MsgWithIndirectRequired) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{10} +} +func (m *MsgWithIndirectRequired) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgWithIndirectRequired.Unmarshal(m, b) +} +func (m *MsgWithIndirectRequired) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgWithIndirectRequired.Marshal(b, m, deterministic) +} +func (dst *MsgWithIndirectRequired) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithIndirectRequired.Merge(dst, src) +} +func (m *MsgWithIndirectRequired) XXX_Size() int { + return xxx_messageInfo_MsgWithIndirectRequired.Size(m) +} +func (m *MsgWithIndirectRequired) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithIndirectRequired.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithIndirectRequired proto.InternalMessageInfo + +func (m *MsgWithIndirectRequired) GetSubm() *MsgWithRequired { + if m != nil { + return m.Subm + } + return nil +} + +func (m *MsgWithIndirectRequired) GetMapField() map[string]*MsgWithRequired { + if m != nil { + return m.MapField + } + return nil +} + +func (m *MsgWithIndirectRequired) GetSliceField() []*MsgWithRequired { + if m != nil { + return m.SliceField + } + return nil +} + +type MsgWithRequiredBytes struct { + Byts []byte `protobuf:"bytes,1,req,name=byts" json:"byts,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgWithRequiredBytes) Reset() { *m = MsgWithRequiredBytes{} } +func (m *MsgWithRequiredBytes) String() string { return proto.CompactTextString(m) } +func (*MsgWithRequiredBytes) ProtoMessage() {} +func (*MsgWithRequiredBytes) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{11} +} +func (m *MsgWithRequiredBytes) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgWithRequiredBytes.Unmarshal(m, b) +} +func (m *MsgWithRequiredBytes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgWithRequiredBytes.Marshal(b, m, deterministic) +} +func (dst *MsgWithRequiredBytes) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithRequiredBytes.Merge(dst, src) +} +func (m *MsgWithRequiredBytes) XXX_Size() int { + return xxx_messageInfo_MsgWithRequiredBytes.Size(m) +} +func (m *MsgWithRequiredBytes) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithRequiredBytes.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithRequiredBytes proto.InternalMessageInfo + +func (m *MsgWithRequiredBytes) GetByts() []byte { + if m != nil { + return m.Byts + } + return nil +} + +type MsgWithRequiredWKT struct { + Str *wrappers.StringValue `protobuf:"bytes,1,req,name=str" json:"str,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgWithRequiredWKT) Reset() { *m = MsgWithRequiredWKT{} } +func (m *MsgWithRequiredWKT) String() string { return proto.CompactTextString(m) } +func (*MsgWithRequiredWKT) ProtoMessage() {} +func (*MsgWithRequiredWKT) Descriptor() ([]byte, []int) { + return fileDescriptor_test_objects_a4d3e593ea3c686f, []int{12} +} +func (m *MsgWithRequiredWKT) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgWithRequiredWKT.Unmarshal(m, b) +} +func (m *MsgWithRequiredWKT) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgWithRequiredWKT.Marshal(b, m, deterministic) +} +func (dst *MsgWithRequiredWKT) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithRequiredWKT.Merge(dst, src) +} +func (m *MsgWithRequiredWKT) XXX_Size() int { + return xxx_messageInfo_MsgWithRequiredWKT.Size(m) +} +func (m *MsgWithRequiredWKT) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithRequiredWKT.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithRequiredWKT proto.InternalMessageInfo + +func (m *MsgWithRequiredWKT) GetStr() *wrappers.StringValue { + if m != nil { + return m.Str + } + return nil +} + var E_Name = &proto.ExtensionDesc{ ExtendedType: (*Real)(nil), ExtensionType: (*string)(nil), @@ -757,96 +1226,132 @@ var E_Name = &proto.ExtensionDesc{ Filename: "test_objects.proto", } +var E_Extm = &proto.ExtensionDesc{ + ExtendedType: (*Real)(nil), + ExtensionType: (*MsgWithRequired)(nil), + Field: 125, + Name: "jsonpb.extm", + Tag: "bytes,125,opt,name=extm", + Filename: "test_objects.proto", +} + func init() { proto.RegisterType((*Simple)(nil), "jsonpb.Simple") proto.RegisterType((*NonFinites)(nil), "jsonpb.NonFinites") proto.RegisterType((*Repeats)(nil), "jsonpb.Repeats") proto.RegisterType((*Widget)(nil), "jsonpb.Widget") proto.RegisterType((*Maps)(nil), "jsonpb.Maps") + proto.RegisterMapType((map[bool]*Simple)(nil), "jsonpb.Maps.MBoolSimpleEntry") + proto.RegisterMapType((map[int64]string)(nil), "jsonpb.Maps.MInt64StrEntry") proto.RegisterType((*MsgWithOneof)(nil), "jsonpb.MsgWithOneof") proto.RegisterType((*Real)(nil), "jsonpb.Real") proto.RegisterType((*Complex)(nil), "jsonpb.Complex") proto.RegisterType((*KnownTypes)(nil), "jsonpb.KnownTypes") + proto.RegisterType((*MsgWithRequired)(nil), "jsonpb.MsgWithRequired") + proto.RegisterType((*MsgWithIndirectRequired)(nil), "jsonpb.MsgWithIndirectRequired") + proto.RegisterMapType((map[string]*MsgWithRequired)(nil), "jsonpb.MsgWithIndirectRequired.MapFieldEntry") + proto.RegisterType((*MsgWithRequiredBytes)(nil), "jsonpb.MsgWithRequiredBytes") + proto.RegisterType((*MsgWithRequiredWKT)(nil), "jsonpb.MsgWithRequiredWKT") proto.RegisterEnum("jsonpb.Widget_Color", Widget_Color_name, Widget_Color_value) proto.RegisterExtension(E_Complex_RealExtension) proto.RegisterExtension(E_Name) + proto.RegisterExtension(E_Extm) } -func init() { proto.RegisterFile("test_objects.proto", fileDescriptor1) } +func init() { proto.RegisterFile("test_objects.proto", fileDescriptor_test_objects_a4d3e593ea3c686f) } -var fileDescriptor1 = []byte{ - // 1160 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x95, 0x41, 0x73, 0xdb, 0x44, - 0x14, 0xc7, 0x23, 0xc9, 0x92, 0xed, 0x75, 0x92, 0x9a, 0x6d, 0xda, 0x2a, 0x26, 0x80, 0xc6, 0x94, - 0x22, 0x0a, 0x75, 0x07, 0xc7, 0xe3, 0x61, 0x0a, 0x97, 0xa4, 0x71, 0x29, 0x43, 0x13, 0x98, 0x4d, - 0x43, 0x8f, 0x1e, 0x39, 0x5a, 0xbb, 0x2a, 0xf2, 0xae, 0x67, 0x77, 0x95, 0xd4, 0x03, 0x87, 0x9c, - 0x39, 0x32, 0x7c, 0x05, 0xf8, 0x08, 0x1c, 0xf8, 0x74, 0xcc, 0xdb, 0x95, 0xac, 0xc4, 0x8e, 0x4f, - 0xf1, 0x7b, 0xef, 0xff, 0xfe, 0x59, 0xed, 0x6f, 0x77, 0x1f, 0xc2, 0x8a, 0x4a, 0x35, 0xe4, 0xa3, - 0x77, 0xf4, 0x5c, 0xc9, 0xce, 0x4c, 0x70, 0xc5, 0xb1, 0xf7, 0x4e, 0x72, 0x36, 0x1b, 0xb5, 0x76, - 0x27, 0x9c, 0x4f, 0x52, 0xfa, 0x54, 0x67, 0x47, 0xd9, 0xf8, 0x69, 0xc4, 0xe6, 0x46, 0xd2, 0xfa, - 0x78, 0xb9, 0x14, 0x67, 0x22, 0x52, 0x09, 0x67, 0x79, 0x7d, 0x6f, 0xb9, 0x2e, 0x95, 0xc8, 0xce, - 0x55, 0x5e, 0xfd, 0x64, 0xb9, 0xaa, 0x92, 0x29, 0x95, 0x2a, 0x9a, 0xce, 0xd6, 0xd9, 0x5f, 0x8a, - 0x68, 0x36, 0xa3, 0x22, 0x5f, 0x61, 0xfb, 0x6f, 0x1b, 0x79, 0xa7, 0xc9, 0x74, 0x96, 0x52, 0x7c, - 0x0f, 0x79, 0x7c, 0x38, 0xe2, 0x3c, 0xf5, 0xad, 0xc0, 0x0a, 0x6b, 0xc4, 0xe5, 0x87, 0x9c, 0xa7, - 0xf8, 0x01, 0xaa, 0xf2, 0x61, 0xc2, 0xd4, 0x7e, 0xd7, 0xb7, 0x03, 0x2b, 0x74, 0x89, 0xc7, 0x7f, - 0x80, 0x68, 0x51, 0xe8, 0xf7, 0x7c, 0x27, 0xb0, 0x42, 0xc7, 0x14, 0xfa, 0x3d, 0xbc, 0x8b, 0x6a, - 0x7c, 0x98, 0x99, 0x96, 0x4a, 0x60, 0x85, 0x5b, 0xa4, 0xca, 0xcf, 0x74, 0x58, 0x96, 0xfa, 0x3d, - 0xdf, 0x0d, 0xac, 0xb0, 0x92, 0x97, 0x8a, 0x2e, 0x69, 0xba, 0xbc, 0xc0, 0x0a, 0x3f, 0x20, 0x55, - 0x7e, 0x7a, 0xad, 0x4b, 0x9a, 0xae, 0x6a, 0x60, 0x85, 0x38, 0x2f, 0xf5, 0x7b, 0x66, 0x11, 0xe3, - 0x94, 0x47, 0xca, 0xaf, 0x05, 0x56, 0x68, 0x13, 0x8f, 0xbf, 0x80, 0xc8, 0xf4, 0xc4, 0x3c, 0x1b, - 0xa5, 0xd4, 0xaf, 0x07, 0x56, 0x68, 0x91, 0x2a, 0x3f, 0xd2, 0x61, 0x6e, 0xa7, 0x44, 0xc2, 0x26, - 0x3e, 0x0a, 0xac, 0xb0, 0x0e, 0x76, 0x3a, 0x34, 0x76, 0xa3, 0xb9, 0xa2, 0xd2, 0x6f, 0x04, 0x56, - 0xb8, 0x49, 0x3c, 0x7e, 0x08, 0x51, 0xfb, 0x4f, 0x0b, 0xa1, 0x13, 0xce, 0x5e, 0x24, 0x2c, 0x51, - 0x54, 0xe2, 0xbb, 0xc8, 0x1d, 0x0f, 0x59, 0xc4, 0xf4, 0x56, 0xd9, 0xa4, 0x32, 0x3e, 0x89, 0x18, - 0x6c, 0xe0, 0x78, 0x38, 0x4b, 0xd8, 0x58, 0x6f, 0x94, 0x4d, 0xdc, 0xf1, 0xcf, 0x09, 0x1b, 0x9b, - 0x34, 0x83, 0xb4, 0x93, 0xa7, 0x4f, 0x20, 0x7d, 0x17, 0xb9, 0xb1, 0xb6, 0xa8, 0xe8, 0xd5, 0x55, - 0xe2, 0xdc, 0x22, 0x36, 0x16, 0xae, 0xce, 0xba, 0x71, 0x61, 0x11, 0x1b, 0x0b, 0x2f, 0x4f, 0x83, - 0x45, 0xfb, 0x1f, 0x1b, 0x55, 0x09, 0x9d, 0xd1, 0x48, 0x49, 0x90, 0x88, 0x82, 0x9e, 0x03, 0xf4, - 0x44, 0x41, 0x4f, 0x2c, 0xe8, 0x39, 0x40, 0x4f, 0x2c, 0xe8, 0x89, 0x05, 0x3d, 0x07, 0xe8, 0x89, - 0x05, 0x3d, 0x51, 0xd2, 0x73, 0x80, 0x9e, 0x28, 0xe9, 0x89, 0x92, 0x9e, 0x03, 0xf4, 0x44, 0x49, - 0x4f, 0x94, 0xf4, 0x1c, 0xa0, 0x27, 0x4e, 0xaf, 0x75, 0x2d, 0xe8, 0x39, 0x40, 0x4f, 0x94, 0xf4, - 0xc4, 0x82, 0x9e, 0x03, 0xf4, 0xc4, 0x82, 0x9e, 0x28, 0xe9, 0x39, 0x40, 0x4f, 0x94, 0xf4, 0x44, - 0x49, 0xcf, 0x01, 0x7a, 0xa2, 0xa4, 0x27, 0x16, 0xf4, 0x1c, 0xa0, 0x27, 0x0c, 0xbd, 0x7f, 0x6d, - 0xe4, 0xbd, 0x49, 0xe2, 0x09, 0x55, 0xf8, 0x31, 0x72, 0xcf, 0x79, 0xca, 0x85, 0x26, 0xb7, 0xdd, - 0xdd, 0xe9, 0x98, 0x2b, 0xda, 0x31, 0xe5, 0xce, 0x73, 0xa8, 0x11, 0x23, 0xc1, 0x4f, 0xc0, 0xcf, - 0xa8, 0x61, 0xf3, 0xd6, 0xa9, 0x3d, 0xa1, 0xff, 0xe2, 0x47, 0xc8, 0x93, 0xfa, 0x2a, 0xe9, 0x53, - 0xd5, 0xe8, 0x6e, 0x17, 0x6a, 0x73, 0xc1, 0x48, 0x5e, 0xc5, 0x5f, 0x98, 0x0d, 0xd1, 0x4a, 0x58, - 0xe7, 0xaa, 0x12, 0x36, 0x28, 0x97, 0x56, 0x85, 0x01, 0xec, 0xef, 0x68, 0xcf, 0x3b, 0x85, 0x32, - 0xe7, 0x4e, 0x8a, 0x3a, 0xfe, 0x0a, 0xd5, 0xc5, 0xb0, 0x10, 0xdf, 0xd3, 0xb6, 0x2b, 0xe2, 0x9a, - 0xc8, 0x7f, 0xb5, 0x3f, 0x43, 0xae, 0x59, 0x74, 0x15, 0x39, 0x64, 0x70, 0xd4, 0xdc, 0xc0, 0x75, - 0xe4, 0x7e, 0x4f, 0x06, 0x83, 0x93, 0xa6, 0x85, 0x6b, 0xa8, 0x72, 0xf8, 0xea, 0x6c, 0xd0, 0xb4, - 0xdb, 0x7f, 0xd9, 0xa8, 0x72, 0x1c, 0xcd, 0x24, 0xfe, 0x16, 0x35, 0xa6, 0xe6, 0xb8, 0xc0, 0xde, - 0xeb, 0x33, 0xd6, 0xe8, 0x7e, 0x58, 0xf8, 0x83, 0xa4, 0x73, 0xac, 0xcf, 0xcf, 0xa9, 0x12, 0x03, - 0xa6, 0xc4, 0x9c, 0xd4, 0xa7, 0x45, 0x8c, 0x0f, 0xd0, 0xd6, 0x54, 0x9f, 0xcd, 0xe2, 0xab, 0x6d, - 0xdd, 0xfe, 0xd1, 0xcd, 0x76, 0x38, 0xaf, 0xe6, 0xb3, 0x8d, 0x41, 0x63, 0x5a, 0x66, 0x5a, 0xdf, - 0xa1, 0xed, 0x9b, 0xfe, 0xb8, 0x89, 0x9c, 0x5f, 0xe9, 0x5c, 0x63, 0x74, 0x08, 0xfc, 0xc4, 0x3b, - 0xc8, 0xbd, 0x88, 0xd2, 0x8c, 0xea, 0xeb, 0x57, 0x27, 0x26, 0x78, 0x66, 0x7f, 0x63, 0xb5, 0x4e, - 0x50, 0x73, 0xd9, 0xfe, 0x7a, 0x7f, 0xcd, 0xf4, 0x3f, 0xbc, 0xde, 0xbf, 0x0a, 0xa5, 0xf4, 0x6b, - 0xff, 0x61, 0xa1, 0xcd, 0x63, 0x39, 0x79, 0x93, 0xa8, 0xb7, 0x3f, 0x31, 0xca, 0xc7, 0xf8, 0x3e, - 0x72, 0x55, 0xa2, 0x52, 0xaa, 0xed, 0xea, 0x2f, 0x37, 0x88, 0x09, 0xb1, 0x8f, 0x3c, 0x19, 0xa5, - 0x91, 0x98, 0x6b, 0x4f, 0xe7, 0xe5, 0x06, 0xc9, 0x63, 0xdc, 0x42, 0xd5, 0xe7, 0x3c, 0x83, 0x95, - 0xe8, 0x67, 0x01, 0x7a, 0x8a, 0x04, 0xfe, 0x14, 0x6d, 0xbe, 0xe5, 0x53, 0x3a, 0x8c, 0xe2, 0x58, - 0x50, 0x29, 0xf5, 0x0b, 0x01, 0x82, 0x06, 0x64, 0x0f, 0x4c, 0xf2, 0xb0, 0x8a, 0xdc, 0x8c, 0x25, - 0x9c, 0xb5, 0x1f, 0xa1, 0x0a, 0xa1, 0x51, 0x5a, 0x7e, 0xbe, 0x65, 0xde, 0x08, 0x1d, 0x3c, 0xae, - 0xd5, 0xe2, 0xe6, 0xd5, 0xd5, 0xd5, 0x95, 0xdd, 0xbe, 0x84, 0xff, 0x08, 0x5f, 0xf2, 0x1e, 0xef, - 0xa1, 0x7a, 0x32, 0x8d, 0x26, 0x09, 0x83, 0x95, 0x19, 0x79, 0x99, 0x28, 0x5b, 0xba, 0x47, 0x68, - 0x5b, 0xd0, 0x28, 0x1d, 0xd2, 0xf7, 0x8a, 0x32, 0x99, 0x70, 0x86, 0x37, 0xcb, 0x23, 0x15, 0xa5, - 0xfe, 0x6f, 0x37, 0xcf, 0x64, 0x6e, 0x4f, 0xb6, 0xa0, 0x69, 0x50, 0xf4, 0xb4, 0xff, 0x73, 0x11, - 0xfa, 0x91, 0xf1, 0x4b, 0xf6, 0x7a, 0x3e, 0xa3, 0x12, 0x3f, 0x44, 0x76, 0xc4, 0xfc, 0x6d, 0xdd, - 0xba, 0xd3, 0x31, 0xf3, 0xa9, 0x53, 0xcc, 0xa7, 0xce, 0x01, 0x9b, 0x13, 0x3b, 0x62, 0xf8, 0x4b, - 0xe4, 0xc4, 0x99, 0xb9, 0xa5, 0x8d, 0xee, 0xee, 0x8a, 0xec, 0x28, 0x9f, 0x92, 0x04, 0x54, 0xf8, - 0x73, 0x64, 0x4b, 0xe5, 0x6f, 0x6a, 0xed, 0x83, 0x15, 0xed, 0xa9, 0x9e, 0x98, 0xc4, 0x96, 0x70, - 0xfb, 0x6d, 0x25, 0x73, 0xbe, 0xad, 0x15, 0xe1, 0xeb, 0x62, 0x78, 0x12, 0x5b, 0x49, 0xd0, 0xa6, - 0x17, 0xfe, 0x9d, 0x35, 0xda, 0x57, 0x89, 0x54, 0xbf, 0xc0, 0x0e, 0x13, 0x3b, 0xbd, 0xc0, 0x21, - 0x72, 0x2e, 0xa2, 0xd4, 0x6f, 0x6a, 0xf1, 0xfd, 0x15, 0xb1, 0x11, 0x82, 0x04, 0x77, 0x90, 0x13, - 0x8f, 0x52, 0xcd, 0xbc, 0xd1, 0xdd, 0x5b, 0xfd, 0x2e, 0xfd, 0xc8, 0xe5, 0xfa, 0x78, 0x94, 0xe2, - 0x27, 0xc8, 0x19, 0xa7, 0x4a, 0x1f, 0x01, 0xb8, 0x70, 0xcb, 0x7a, 0xfd, 0x5c, 0xe6, 0xf2, 0x71, - 0xaa, 0x40, 0x9e, 0xe4, 0xb3, 0xf5, 0x36, 0xb9, 0xbe, 0x42, 0xb9, 0x3c, 0xe9, 0xf7, 0x60, 0x35, - 0x59, 0xbf, 0xa7, 0xa7, 0xca, 0x6d, 0xab, 0x39, 0xbb, 0xae, 0xcf, 0xfa, 0x3d, 0x6d, 0xbf, 0xdf, - 0xd5, 0x43, 0x78, 0x8d, 0xfd, 0x7e, 0xb7, 0xb0, 0xdf, 0xef, 0x6a, 0xfb, 0xfd, 0xae, 0x9e, 0xcc, - 0xeb, 0xec, 0x17, 0xfa, 0x4c, 0xeb, 0x2b, 0x7a, 0x84, 0xd5, 0xd7, 0x6c, 0x3a, 0xdc, 0x61, 0x23, - 0xd7, 0x3a, 0xf0, 0x87, 0xd7, 0x08, 0xad, 0xf1, 0x37, 0x63, 0x21, 0xf7, 0x97, 0x4a, 0xe0, 0xaf, - 0x91, 0x5b, 0x0e, 0xf7, 0xdb, 0x3e, 0x40, 0x8f, 0x0b, 0xd3, 0x60, 0x94, 0xcf, 0x02, 0x54, 0x61, - 0xd1, 0x94, 0x2e, 0x1d, 0xfc, 0xdf, 0xf5, 0x0b, 0xa3, 0x2b, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, - 0xd5, 0x39, 0x32, 0x09, 0xf9, 0x09, 0x00, 0x00, +var fileDescriptor_test_objects_a4d3e593ea3c686f = []byte{ + // 1460 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xdd, 0x72, 0xdb, 0x44, + 0x14, 0x8e, 0x24, 0xcb, 0xb6, 0x8e, 0xf3, 0xd7, 0x6d, 0xda, 0x2a, 0xa1, 0x14, 0x8d, 0x5b, 0x8a, + 0x69, 0x89, 0x3b, 0x38, 0x1e, 0x4f, 0x29, 0xdc, 0x34, 0x4d, 0x4a, 0x4b, 0xdb, 0xc0, 0x6c, 0x52, + 0x7a, 0xe9, 0x91, 0x23, 0x39, 0x55, 0x91, 0xb4, 0x66, 0x77, 0x9d, 0xd4, 0x03, 0xcc, 0xe4, 0x19, + 0x18, 0x9e, 0x80, 0x0b, 0x6e, 0xb9, 0xe3, 0x82, 0xb7, 0xe0, 0x8d, 0x98, 0x3d, 0xbb, 0xf2, 0x5f, + 0xe2, 0x81, 0x2b, 0x7b, 0xf7, 0xfb, 0xd9, 0xd5, 0x9e, 0x4f, 0x67, 0x05, 0x44, 0xc6, 0x42, 0x76, + 0x59, 0xef, 0x5d, 0x7c, 0x2c, 0x45, 0x73, 0xc0, 0x99, 0x64, 0xa4, 0xfc, 0x4e, 0xb0, 0x7c, 0xd0, + 0xdb, 0xda, 0x3c, 0x61, 0xec, 0x24, 0x8d, 0x1f, 0xe0, 0x6c, 0x6f, 0xd8, 0x7f, 0x10, 0xe6, 0x23, + 0x4d, 0xd9, 0xba, 0x35, 0x0f, 0x45, 0x43, 0x1e, 0xca, 0x84, 0xe5, 0x06, 0xbf, 0x39, 0x8f, 0x0b, + 0xc9, 0x87, 0xc7, 0xd2, 0xa0, 0x1f, 0xcd, 0xa3, 0x32, 0xc9, 0x62, 0x21, 0xc3, 0x6c, 0xb0, 0xc8, + 0xfe, 0x8c, 0x87, 0x83, 0x41, 0xcc, 0xcd, 0x0e, 0xeb, 0x7f, 0x96, 0xa0, 0x7c, 0x98, 0x64, 0x83, + 0x34, 0x26, 0xd7, 0xa0, 0xcc, 0xba, 0x3d, 0xc6, 0x52, 0xdf, 0x0a, 0xac, 0x46, 0x95, 0xba, 0x6c, + 0x97, 0xb1, 0x94, 0xdc, 0x80, 0x0a, 0xeb, 0x26, 0xb9, 0xdc, 0x69, 0xf9, 0x76, 0x60, 0x35, 0x5c, + 0x5a, 0x66, 0xcf, 0xd5, 0x88, 0xdc, 0x82, 0x9a, 0x01, 0xba, 0x42, 0x72, 0xdf, 0x41, 0xd0, 0xd3, + 0xe0, 0xa1, 0xe4, 0x63, 0x61, 0xa7, 0xed, 0x97, 0x02, 0xab, 0xe1, 0x68, 0x61, 0xa7, 0x3d, 0x16, + 0x76, 0xda, 0x28, 0x74, 0x11, 0xf4, 0x34, 0xa8, 0x84, 0x9b, 0x50, 0x65, 0xdd, 0xa1, 0x5e, 0xb2, + 0x1c, 0x58, 0x8d, 0x15, 0x5a, 0x61, 0xaf, 0x71, 0x48, 0x02, 0x58, 0x2e, 0x20, 0xd4, 0x56, 0x10, + 0x06, 0x03, 0xcf, 0x88, 0x3b, 0x6d, 0xbf, 0x1a, 0x58, 0x8d, 0x92, 0x11, 0x77, 0xda, 0x13, 0xb1, + 0x59, 0xd8, 0x43, 0x18, 0x0c, 0x3c, 0x16, 0x0b, 0xbd, 0x32, 0x04, 0x56, 0xe3, 0x0a, 0xad, 0xb0, + 0xc3, 0xa9, 0x95, 0xc5, 0x64, 0xe5, 0x1a, 0xc2, 0x60, 0xe0, 0x19, 0x71, 0xa7, 0xed, 0x2f, 0x07, + 0x56, 0x83, 0x18, 0x71, 0xb1, 0xb2, 0x98, 0xac, 0xbc, 0x82, 0x30, 0x18, 0x78, 0x7c, 0x58, 0xfd, + 0x94, 0x85, 0xd2, 0x5f, 0x0d, 0xac, 0x86, 0x4d, 0xcb, 0xec, 0xa9, 0x1a, 0xe9, 0xc3, 0x42, 0x00, + 0x95, 0x6b, 0x08, 0x7a, 0x1a, 0x1c, 0xaf, 0x1a, 0xb1, 0x61, 0x2f, 0x8d, 0xfd, 0xf5, 0xc0, 0x6a, + 0x58, 0xb4, 0xc2, 0xf6, 0x70, 0xa8, 0x57, 0xd5, 0x10, 0x6a, 0xaf, 0x20, 0x0c, 0x06, 0x9e, 0x6c, + 0x59, 0xf2, 0x24, 0x3f, 0xf1, 0x49, 0x60, 0x35, 0x3c, 0xb5, 0x65, 0x1c, 0xea, 0x0d, 0xf5, 0x46, + 0x32, 0x16, 0xfe, 0xd5, 0xc0, 0x6a, 0x2c, 0xd3, 0x32, 0xdb, 0x55, 0xa3, 0xfa, 0xaf, 0x16, 0xc0, + 0x01, 0xcb, 0x9f, 0x26, 0x79, 0x22, 0x63, 0x41, 0xae, 0x82, 0xdb, 0xef, 0xe6, 0x61, 0x8e, 0xa1, + 0xb1, 0x69, 0xa9, 0x7f, 0x10, 0xe6, 0x2a, 0x4a, 0xfd, 0xee, 0x20, 0xc9, 0xfb, 0x18, 0x19, 0x9b, + 0xba, 0xfd, 0xef, 0x92, 0xbc, 0xaf, 0xa7, 0x73, 0x35, 0xed, 0x98, 0xe9, 0x03, 0x35, 0x7d, 0x15, + 0xdc, 0x08, 0x2d, 0x4a, 0xb8, 0xc1, 0x52, 0x64, 0x2c, 0x22, 0x6d, 0xe1, 0xe2, 0xac, 0x1b, 0x15, + 0x16, 0x91, 0xb6, 0x28, 0x9b, 0x69, 0x65, 0x51, 0xff, 0xc3, 0x86, 0x0a, 0x8d, 0x07, 0x71, 0x28, + 0x85, 0xa2, 0xf0, 0x22, 0xc7, 0x8e, 0xca, 0x31, 0x2f, 0x72, 0xcc, 0xc7, 0x39, 0x76, 0x54, 0x8e, + 0xb9, 0xce, 0x71, 0x01, 0x74, 0xda, 0xbe, 0x13, 0x38, 0x2a, 0xa7, 0x5c, 0xe7, 0x74, 0x13, 0xaa, + 0xbc, 0xc8, 0x61, 0x29, 0x70, 0x54, 0x0e, 0xb9, 0xc9, 0xe1, 0x18, 0xea, 0xb4, 0x7d, 0x37, 0x70, + 0x54, 0xca, 0xb8, 0x49, 0x19, 0x42, 0xa2, 0x48, 0xaf, 0xa3, 0x32, 0xc4, 0x0f, 0xa7, 0x54, 0x26, + 0x21, 0x95, 0xc0, 0x51, 0x09, 0xe1, 0x26, 0x21, 0xb8, 0x09, 0x5d, 0xff, 0x6a, 0xe0, 0xa8, 0xfa, + 0x73, 0x5d, 0x7f, 0xd4, 0x98, 0xfa, 0x7a, 0x81, 0xa3, 0xea, 0xcb, 0x4d, 0x7d, 0xb5, 0x9d, 0xae, + 0x1e, 0x04, 0x8e, 0xaa, 0x1e, 0x9f, 0x54, 0x8f, 0x9b, 0xea, 0xd5, 0x02, 0x47, 0x55, 0x8f, 0xeb, + 0xea, 0xfd, 0x65, 0x43, 0xf9, 0x4d, 0x12, 0x9d, 0xc4, 0x92, 0xdc, 0x03, 0xf7, 0x98, 0xa5, 0x8c, + 0x63, 0xe5, 0x56, 0x5b, 0x1b, 0x4d, 0xdd, 0xac, 0x9a, 0x1a, 0x6e, 0x3e, 0x51, 0x18, 0xd5, 0x14, + 0xb2, 0xad, 0xfc, 0x34, 0x5b, 0x1d, 0xde, 0x22, 0x76, 0x99, 0xe3, 0x2f, 0xb9, 0x0b, 0x65, 0x81, + 0x4d, 0x05, 0xdf, 0xa2, 0x5a, 0x6b, 0xb5, 0x60, 0xeb, 0x56, 0x43, 0x0d, 0x4a, 0x3e, 0xd5, 0x07, + 0x82, 0x4c, 0xb5, 0xcf, 0x8b, 0x4c, 0x75, 0x40, 0x86, 0x5a, 0xe1, 0xba, 0xc0, 0xfe, 0x06, 0x7a, + 0xae, 0x15, 0x4c, 0x53, 0x77, 0x5a, 0xe0, 0xe4, 0x33, 0xf0, 0x78, 0xb7, 0x20, 0x5f, 0x43, 0xdb, + 0x0b, 0xe4, 0x2a, 0x37, 0xff, 0xea, 0x1f, 0x83, 0xab, 0x37, 0x5d, 0x01, 0x87, 0xee, 0xef, 0xad, + 0x2f, 0x11, 0x0f, 0xdc, 0xaf, 0xe9, 0xfe, 0xfe, 0xc1, 0xba, 0x45, 0xaa, 0x50, 0xda, 0x7d, 0xf9, + 0x7a, 0x7f, 0xdd, 0xae, 0xff, 0x66, 0x43, 0xe9, 0x55, 0x38, 0x10, 0xe4, 0x4b, 0xa8, 0x65, 0x53, + 0xdd, 0xcb, 0x42, 0xff, 0x0f, 0x0a, 0x7f, 0x45, 0x69, 0xbe, 0x2a, 0x5a, 0xd9, 0x7e, 0x2e, 0xf9, + 0x88, 0x7a, 0xd9, 0xb8, 0xb5, 0x3d, 0x86, 0x95, 0x0c, 0xb3, 0x59, 0x3c, 0xb5, 0x8d, 0xf2, 0x0f, + 0x67, 0xe5, 0x2a, 0xaf, 0xfa, 0xb1, 0xb5, 0x41, 0x2d, 0x9b, 0xcc, 0x6c, 0x7d, 0x05, 0xab, 0xb3, + 0xfe, 0x64, 0x1d, 0x9c, 0x1f, 0xe2, 0x11, 0x96, 0xd1, 0xa1, 0xea, 0x2f, 0xd9, 0x00, 0xf7, 0x34, + 0x4c, 0x87, 0x31, 0xbe, 0x7e, 0x1e, 0xd5, 0x83, 0x47, 0xf6, 0x43, 0x6b, 0xeb, 0x00, 0xd6, 0xe7, + 0xed, 0xa7, 0xf5, 0x55, 0xad, 0xbf, 0x33, 0xad, 0xbf, 0x58, 0x94, 0x89, 0x5f, 0xfd, 0x1f, 0x0b, + 0x96, 0x5f, 0x89, 0x93, 0x37, 0x89, 0x7c, 0xfb, 0x6d, 0x1e, 0xb3, 0x3e, 0xb9, 0x0e, 0xae, 0x4c, + 0x64, 0x1a, 0xa3, 0x9d, 0xf7, 0x6c, 0x89, 0xea, 0x21, 0xf1, 0xa1, 0x2c, 0xc2, 0x34, 0xe4, 0x23, + 0xf4, 0x74, 0x9e, 0x2d, 0x51, 0x33, 0x26, 0x5b, 0x50, 0x79, 0xc2, 0x86, 0x6a, 0x27, 0xd8, 0x16, + 0x94, 0xa6, 0x98, 0x20, 0xb7, 0x61, 0xf9, 0x2d, 0xcb, 0xe2, 0x6e, 0x18, 0x45, 0x3c, 0x16, 0x02, + 0x3b, 0x84, 0x22, 0xd4, 0xd4, 0xec, 0x63, 0x3d, 0x49, 0xf6, 0xe1, 0x4a, 0x26, 0x4e, 0xba, 0x67, + 0x89, 0x7c, 0xdb, 0xe5, 0xf1, 0x8f, 0xc3, 0x84, 0xc7, 0x11, 0x76, 0x8d, 0x5a, 0xeb, 0xc6, 0xf8, + 0x60, 0xf5, 0x1e, 0xa9, 0x81, 0x9f, 0x2d, 0xd1, 0xb5, 0x6c, 0x76, 0x6a, 0xb7, 0x02, 0xee, 0x30, + 0x4f, 0x58, 0x5e, 0xbf, 0x0b, 0x25, 0x1a, 0x87, 0xe9, 0xe4, 0x14, 0x2d, 0xdd, 0x6a, 0x70, 0x70, + 0xaf, 0x5a, 0x8d, 0xd6, 0xcf, 0xcf, 0xcf, 0xcf, 0xed, 0xfa, 0x99, 0xda, 0xb8, 0x3a, 0x90, 0xf7, + 0xe4, 0x26, 0x78, 0x49, 0x16, 0x9e, 0x24, 0xb9, 0x7a, 0x40, 0x4d, 0x9f, 0x4c, 0x4c, 0x24, 0xad, + 0x3d, 0x58, 0xe5, 0x71, 0x98, 0x76, 0xe3, 0xf7, 0x32, 0xce, 0x45, 0xc2, 0x72, 0xb2, 0x3c, 0x49, + 0x66, 0x98, 0xfa, 0x3f, 0xcd, 0x46, 0xdb, 0xd8, 0xd3, 0x15, 0x25, 0xda, 0x2f, 0x34, 0xf5, 0xbf, + 0x5d, 0x80, 0x17, 0x39, 0x3b, 0xcb, 0x8f, 0x46, 0x83, 0x58, 0x90, 0x3b, 0x60, 0x87, 0x39, 0x5e, + 0x1b, 0xb5, 0xd6, 0x46, 0x53, 0x5f, 0xf8, 0xcd, 0xe2, 0xc2, 0x6f, 0x3e, 0xce, 0x47, 0xd4, 0x0e, + 0x73, 0x72, 0x1f, 0x9c, 0x68, 0xa8, 0x5f, 0xf6, 0x5a, 0x6b, 0xf3, 0x02, 0x6d, 0xcf, 0x7c, 0x76, + 0x50, 0xc5, 0x22, 0x9f, 0x80, 0x2d, 0x24, 0xde, 0x62, 0xea, 0x0c, 0xe7, 0xb9, 0x87, 0xf8, 0x09, + 0x42, 0x6d, 0xa1, 0x9a, 0x88, 0x2d, 0x85, 0x89, 0xc9, 0xd6, 0x05, 0xe2, 0x51, 0xf1, 0x35, 0x42, + 0x6d, 0x29, 0x14, 0x37, 0x3d, 0xc5, 0x1b, 0xec, 0x32, 0xee, 0xcb, 0x44, 0xc8, 0xef, 0xd5, 0x09, + 0x53, 0x3b, 0x3d, 0x25, 0x0d, 0x70, 0x4e, 0xc3, 0x14, 0x6f, 0xb4, 0x5a, 0xeb, 0xfa, 0x05, 0xb2, + 0x26, 0x2a, 0x0a, 0x69, 0x82, 0x13, 0xf5, 0x52, 0x8c, 0x4e, 0xad, 0x75, 0xf3, 0xe2, 0x73, 0x61, + 0xaf, 0x34, 0xfc, 0xa8, 0x97, 0x92, 0x6d, 0x70, 0xfa, 0xa9, 0xc4, 0x24, 0xa9, 0xf7, 0x76, 0x9e, + 0x8f, 0x5d, 0xd7, 0xd0, 0xfb, 0xa9, 0x54, 0xf4, 0x04, 0x9b, 0xfc, 0xe5, 0x74, 0x7c, 0x13, 0x0d, + 0x3d, 0xe9, 0xb4, 0xd5, 0x6e, 0x86, 0x9d, 0x36, 0x5e, 0x4e, 0x97, 0xed, 0xe6, 0xf5, 0x34, 0x7f, + 0xd8, 0x69, 0xa3, 0xfd, 0x4e, 0x0b, 0xbf, 0x63, 0x16, 0xd8, 0xef, 0xb4, 0x0a, 0xfb, 0x9d, 0x16, + 0xda, 0xef, 0xb4, 0xf0, 0xc3, 0x66, 0x91, 0xfd, 0x98, 0x3f, 0x44, 0x7e, 0x09, 0x6f, 0x42, 0x6f, + 0xc1, 0xa1, 0xab, 0x56, 0xa0, 0xe9, 0xc8, 0x53, 0xfe, 0xaa, 0xa9, 0xc1, 0x02, 0x7f, 0x7d, 0xbb, + 0x18, 0x7f, 0x21, 0x39, 0xf9, 0x1c, 0xdc, 0xe2, 0x96, 0xb9, 0xfc, 0x01, 0xf0, 0xd6, 0xd1, 0x02, + 0xcd, 0xac, 0xdf, 0x86, 0xb5, 0xb9, 0x97, 0x51, 0x35, 0x20, 0xdd, 0x4a, 0xed, 0x86, 0x87, 0xbe, + 0xf5, 0xdf, 0x6d, 0xb8, 0x61, 0x58, 0xcf, 0xf3, 0x28, 0xe1, 0xf1, 0xb1, 0x1c, 0xb3, 0xef, 0x43, + 0x49, 0x0c, 0x7b, 0x99, 0x49, 0xf2, 0xa2, 0x37, 0x9c, 0x22, 0x89, 0x7c, 0x03, 0x5e, 0x16, 0x0e, + 0xba, 0xfd, 0x24, 0x4e, 0x23, 0xd3, 0x6c, 0xb7, 0xe7, 0x14, 0xf3, 0x0b, 0xa8, 0x26, 0xfc, 0x54, + 0xf1, 0x75, 0xf3, 0xad, 0x66, 0x66, 0x48, 0x1e, 0x42, 0x4d, 0xa4, 0xc9, 0x71, 0x6c, 0xdc, 0x1c, + 0x74, 0x5b, 0xb8, 0x3e, 0x20, 0x17, 0x95, 0x5b, 0x47, 0xb0, 0x32, 0x63, 0x3a, 0xdd, 0x72, 0x3d, + 0xdd, 0x72, 0xb7, 0x67, 0x5b, 0xee, 0x42, 0xdb, 0xa9, 0xde, 0x7b, 0x0f, 0x36, 0xe6, 0x50, 0x3c, + 0x6d, 0x42, 0xa0, 0xd4, 0x1b, 0x49, 0x81, 0xe7, 0xb9, 0x4c, 0xf1, 0x7f, 0x7d, 0x0f, 0xc8, 0x1c, + 0xf7, 0xcd, 0x8b, 0xa3, 0xa2, 0xdc, 0x8a, 0xf8, 0x7f, 0xca, 0xfd, 0x28, 0x80, 0x52, 0x1e, 0x66, + 0xf1, 0x5c, 0xd3, 0xfa, 0x19, 0x9f, 0x02, 0x91, 0x47, 0x5f, 0x40, 0x29, 0x7e, 0x2f, 0xb3, 0x39, + 0xc6, 0x2f, 0xff, 0x51, 0x2a, 0x25, 0xf9, 0x37, 0x00, 0x00, 0xff, 0xff, 0xe9, 0xd4, 0xfd, 0x2f, + 0x41, 0x0d, 0x00, 0x00, } diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.proto b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.proto index 0d2fc1fa..e01386e7 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.proto +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test_proto/test_objects.proto @@ -43,15 +43,23 @@ package jsonpb; message Simple { optional bool o_bool = 1; optional int32 o_int32 = 2; - optional int64 o_int64 = 3; - optional uint32 o_uint32 = 4; - optional uint64 o_uint64 = 5; - optional sint32 o_sint32 = 6; - optional sint64 o_sint64 = 7; - optional float o_float = 8; - optional double o_double = 9; - optional string o_string = 10; - optional bytes o_bytes = 11; + optional int32 o_int32_str = 3; + optional int64 o_int64 = 4; + optional int64 o_int64_str = 5; + optional uint32 o_uint32 = 6; + optional uint32 o_uint32_str = 7; + optional uint64 o_uint64 = 8; + optional uint64 o_uint64_str = 9; + optional sint32 o_sint32 = 10; + optional sint32 o_sint32_str = 11; + optional sint64 o_sint64 = 12; + optional sint64 o_sint64_str = 13; + optional float o_float = 14; + optional float o_float_str = 15; + optional double o_double = 16; + optional double o_double_str = 17; + optional string o_string = 18; + optional bytes o_bytes = 19; } // Test message for holding special non-finites primitives. @@ -107,6 +115,7 @@ message MsgWithOneof { int64 salary = 2; string Country = 3; string home_address = 4; + MsgWithRequired msg_with_required = 5; } } @@ -145,3 +154,26 @@ message KnownTypes { optional google.protobuf.StringValue str = 10; optional google.protobuf.BytesValue bytes = 11; } + +// Test messages for marshaling/unmarshaling required fields. +message MsgWithRequired { + required string str = 1; +} + +message MsgWithIndirectRequired { + optional MsgWithRequired subm = 1; + map map_field = 2; + repeated MsgWithRequired slice_field = 3; +} + +message MsgWithRequiredBytes { + required bytes byts = 1; +} + +message MsgWithRequiredWKT { + required google.protobuf.StringValue str = 1; +} + +extend Real { + optional MsgWithRequired extm = 125; +} diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile deleted file mode 100644 index e2e0651a..00000000 --- a/vendor/github.com/golang/protobuf/proto/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -install: - go install - -test: install generate-test-pbs - go test - - -generate-test-pbs: - make install - make -C testdata - protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto - make diff --git a/vendor/github.com/golang/protobuf/proto/all_test.go b/vendor/github.com/golang/protobuf/proto/all_test.go index 41451a40..1bea4b6e 100644 --- a/vendor/github.com/golang/protobuf/proto/all_test.go +++ b/vendor/github.com/golang/protobuf/proto/all_test.go @@ -41,11 +41,13 @@ import ( "reflect" "runtime/debug" "strings" + "sync" "testing" "time" . "github.com/golang/protobuf/proto" - . "github.com/golang/protobuf/proto/testdata" + pb3 "github.com/golang/protobuf/proto/proto3_proto" + . "github.com/golang/protobuf/proto/test_proto" ) var globalO *Buffer @@ -114,6 +116,8 @@ func initGoTest(setdefaults bool) *GoTest { pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) + pb.F_Sfixed32Defaulted = Int32(Default_GoTest_F_Sfixed32Defaulted) + pb.F_Sfixed64Defaulted = Int64(Default_GoTest_F_Sfixed64Defaulted) } pb.Kind = GoTest_TIME.Enum() @@ -131,135 +135,13 @@ func initGoTest(setdefaults bool) *GoTest { pb.F_BytesRequired = []byte("bytes") pb.F_Sint32Required = Int32(-32) pb.F_Sint64Required = Int64(-64) + pb.F_Sfixed32Required = Int32(-32) + pb.F_Sfixed64Required = Int64(-64) pb.Requiredgroup = initGoTest_RequiredGroup() return pb } -func fail(msg string, b *bytes.Buffer, s string, t *testing.T) { - data := b.Bytes() - ld := len(data) - ls := len(s) / 2 - - fmt.Printf("fail %s ld=%d ls=%d\n", msg, ld, ls) - - // find the interesting spot - n - n := ls - if ld < ls { - n = ld - } - j := 0 - for i := 0; i < n; i++ { - bs := hex(s[j])*16 + hex(s[j+1]) - j += 2 - if data[i] == bs { - continue - } - n = i - break - } - l := n - 10 - if l < 0 { - l = 0 - } - h := n + 10 - - // find the interesting spot - n - fmt.Printf("is[%d]:", l) - for i := l; i < h; i++ { - if i >= ld { - fmt.Printf(" --") - continue - } - fmt.Printf(" %.2x", data[i]) - } - fmt.Printf("\n") - - fmt.Printf("sb[%d]:", l) - for i := l; i < h; i++ { - if i >= ls { - fmt.Printf(" --") - continue - } - bs := hex(s[j])*16 + hex(s[j+1]) - j += 2 - fmt.Printf(" %.2x", bs) - } - fmt.Printf("\n") - - t.Fail() - - // t.Errorf("%s: \ngood: %s\nbad: %x", msg, s, b.Bytes()) - // Print the output in a partially-decoded format; can - // be helpful when updating the test. It produces the output - // that is pasted, with minor edits, into the argument to verify(). - // data := b.Bytes() - // nesting := 0 - // for b.Len() > 0 { - // start := len(data) - b.Len() - // var u uint64 - // u, err := DecodeVarint(b) - // if err != nil { - // fmt.Printf("decode error on varint:", err) - // return - // } - // wire := u & 0x7 - // tag := u >> 3 - // switch wire { - // case WireVarint: - // v, err := DecodeVarint(b) - // if err != nil { - // fmt.Printf("decode error on varint:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", - // data[start:len(data)-b.Len()], tag, wire, v) - // case WireFixed32: - // v, err := DecodeFixed32(b) - // if err != nil { - // fmt.Printf("decode error on fixed32:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", - // data[start:len(data)-b.Len()], tag, wire, v) - // case WireFixed64: - // v, err := DecodeFixed64(b) - // if err != nil { - // fmt.Printf("decode error on fixed64:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", - // data[start:len(data)-b.Len()], tag, wire, v) - // case WireBytes: - // nb, err := DecodeVarint(b) - // if err != nil { - // fmt.Printf("decode error on bytes:", err) - // return - // } - // after_tag := len(data) - b.Len() - // str := make([]byte, nb) - // _, err = b.Read(str) - // if err != nil { - // fmt.Printf("decode error on bytes:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" \"%x\" // field %d, encoding %d (FIELD)\n", - // data[start:after_tag], str, tag, wire) - // case WireStartGroup: - // nesting++ - // fmt.Printf("\t\t\"%x\"\t\t// start group field %d level %d\n", - // data[start:len(data)-b.Len()], tag, nesting) - // case WireEndGroup: - // fmt.Printf("\t\t\"%x\"\t\t// end group field %d level %d\n", - // data[start:len(data)-b.Len()], tag, nesting) - // nesting-- - // default: - // fmt.Printf("unrecognized wire type %d\n", wire) - // return - // } - // } -} - func hex(c uint8) uint8 { if '0' <= c && c <= '9' { return c - '0' @@ -482,6 +364,48 @@ func TestMarshalerEncoding(t *testing.T) { } } +// Ensure that Buffer.Marshal uses O(N) memory for N messages +func TestBufferMarshalAllocs(t *testing.T) { + value := &OtherMessage{Key: Int64(1)} + msg := &MyMessage{Count: Int32(1), Others: []*OtherMessage{value}} + + reallocSize := func(t *testing.T, items int, prealloc int) (int64, int64) { + var b Buffer + b.SetBuf(make([]byte, 0, prealloc)) + + var allocSpace int64 + prevCap := cap(b.Bytes()) + for i := 0; i < items; i++ { + err := b.Marshal(msg) + if err != nil { + t.Errorf("Marshal err = %q", err) + break + } + if c := cap(b.Bytes()); prevCap != c { + allocSpace += int64(c) + prevCap = c + } + } + needSpace := int64(len(b.Bytes())) + return allocSpace, needSpace + } + + for _, prealloc := range []int{0, 100, 10000} { + for _, items := range []int{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000} { + runtimeSpace, need := reallocSize(t, items, prealloc) + totalSpace := int64(prealloc) + runtimeSpace + + runtimeRatio := float64(runtimeSpace) / float64(need) + totalRatio := float64(totalSpace) / float64(need) + + if totalRatio < 1 || runtimeRatio > 4 { + t.Errorf("needed %dB, allocated %dB total (ratio %.1f), allocated %dB at runtime (ratio %.1f)", + need, totalSpace, totalRatio, runtimeSpace, runtimeRatio) + } + } + } +} + // Simple tests for bytes func TestBytesPrimitives(t *testing.T) { o := old() @@ -519,7 +443,7 @@ func TestRequiredBit(t *testing.T) { err := o.Marshal(pb) if err == nil { t.Error("did not catch missing required fields") - } else if strings.Index(err.Error(), "Kind") < 0 { + } else if !strings.Contains(err.Error(), "Kind") { t.Error("wrong error type:", err) } } @@ -612,7 +536,9 @@ func TestEncodeDecode1(t *testing.T) { "b404"+ // field 70, encoding 4, end group "aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f") // field 103, encoding 0, 0x7f zigzag64 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff") // field 105, encoding 1, -64 fixed64 } // All required fields set, defaults provided. @@ -647,9 +573,13 @@ func TestEncodeDecode2(t *testing.T) { "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 } @@ -669,6 +599,8 @@ func TestEncodeDecode3(t *testing.T) { pb.F_BytesDefaulted = []byte("Bignose") pb.F_Sint32Defaulted = Int32(-32) pb.F_Sint64Defaulted = Int64(-64) + pb.F_Sfixed32Defaulted = Int32(-32) + pb.F_Sfixed64Defaulted = Int64(-64) overify(t, pb, "0807"+ // field 1, encoding 0, value 7 @@ -699,9 +631,13 @@ func TestEncodeDecode3(t *testing.T) { "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 } @@ -724,6 +660,8 @@ func TestEncodeDecode4(t *testing.T) { pb.F_BytesOptional = []byte("Bignose") pb.F_Sint32Optional = Int32(-32) pb.F_Sint64Optional = Int64(-64) + pb.F_Sfixed32Optional = Int32(-32) + pb.F_Sfixed64Optional = Int64(-64) pb.Optionalgroup = initGoTest_OptionalGroup() overify(t, pb, @@ -771,12 +709,18 @@ func TestEncodeDecode4(t *testing.T) { "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 "ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose" "f0123f"+ // field 302, encoding 0, value 63 "f8127f"+ // field 303, encoding 0, value 127 + "8513e0ffffff"+ // field 304, encoding 5, -32 fixed32 + "8913c0ffffffffffffff"+ // field 305, encoding 1, -64 fixed64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 } @@ -797,6 +741,8 @@ func TestEncodeDecode5(t *testing.T) { pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")} pb.F_Sint32Repeated = []int32{32, -32} pb.F_Sint64Repeated = []int64{64, -64} + pb.F_Sfixed32Repeated = []int32{32, -32} + pb.F_Sfixed64Repeated = []int64{64, -64} pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()} overify(t, pb, @@ -856,15 +802,23 @@ func TestEncodeDecode5(t *testing.T) { "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 "ca0c03"+"626967"+ // field 201, encoding 2, string "big" "ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose" "d00c40"+ // field 202, encoding 0, value 32 "d00c3f"+ // field 202, encoding 0, value -32 "d80c8001"+ // field 203, encoding 0, value 64 "d80c7f"+ // field 203, encoding 0, value -64 + "e50c20000000"+ // field 204, encoding 5, 32 fixed32 + "e50ce0ffffff"+ // field 204, encoding 5, -32 fixed32 + "e90c4000000000000000"+ // field 205, encoding 1, 64 fixed64 + "e90cc0ffffffffffffff"+ // field 205, encoding 1, -64 fixed64 "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 } @@ -882,6 +836,8 @@ func TestEncodeDecode6(t *testing.T) { pb.F_DoubleRepeatedPacked = []float64{64., 65.} pb.F_Sint32RepeatedPacked = []int32{32, -32} pb.F_Sint64RepeatedPacked = []int64{64, -64} + pb.F_Sfixed32RepeatedPacked = []int32{32, -32} + pb.F_Sfixed64RepeatedPacked = []int64{64, -64} overify(t, pb, "0807"+ // field 1, encoding 0, value 7 @@ -917,10 +873,17 @@ func TestEncodeDecode6(t *testing.T) { "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 "b21f02"+ // field 502, encoding 2, 2 bytes "403f"+ // value 32, value -32 "ba1f03"+ // field 503, encoding 2, 3 bytes - "80017f") // value 64, value -64 + "80017f"+ // value 64, value -64 + "c21f08"+ // field 504, encoding 2, 8 bytes + "20000000e0ffffff"+ // value 32, value -32 + "ca1f10"+ // field 505, encoding 2, 16 bytes + "4000000000000000c0ffffffffffffff") // value 64, value -64 + } // Test that we can encode empty bytes fields. @@ -1167,13 +1130,10 @@ func TestBigRepeated(t *testing.T) { if pbd.Repeatedgroup[i] == nil { // TODO: more checking? t.Error("pbd.Repeatedgroup bad") } - var x uint64 - x = uint64(pbd.F_Sint64Repeated[i]) - if x != i { + if x := uint64(pbd.F_Sint64Repeated[i]); x != i { t.Error("pbd.F_Sint64Repeated bad", x, i) } - x = uint64(pbd.F_Sint32Repeated[i]) - if x != i { + if x := uint64(pbd.F_Sint32Repeated[i]); x != i { t.Error("pbd.F_Sint32Repeated bad", x, i) } s := fmt.Sprint(i) @@ -1181,39 +1141,31 @@ func TestBigRepeated(t *testing.T) { if pbd.F_StringRepeated[i] != s { t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i) } - x = uint64(pbd.F_DoubleRepeated[i]) - if x != i { + if x := uint64(pbd.F_DoubleRepeated[i]); x != i { t.Error("pbd.F_DoubleRepeated bad", x, i) } - x = uint64(pbd.F_FloatRepeated[i]) - if x != i { + if x := uint64(pbd.F_FloatRepeated[i]); x != i { t.Error("pbd.F_FloatRepeated bad", x, i) } - x = pbd.F_Uint64Repeated[i] - if x != i { + if x := pbd.F_Uint64Repeated[i]; x != i { t.Error("pbd.F_Uint64Repeated bad", x, i) } - x = uint64(pbd.F_Uint32Repeated[i]) - if x != i { + if x := uint64(pbd.F_Uint32Repeated[i]); x != i { t.Error("pbd.F_Uint32Repeated bad", x, i) } - x = pbd.F_Fixed64Repeated[i] - if x != i { + if x := pbd.F_Fixed64Repeated[i]; x != i { t.Error("pbd.F_Fixed64Repeated bad", x, i) } - x = uint64(pbd.F_Fixed32Repeated[i]) - if x != i { + if x := uint64(pbd.F_Fixed32Repeated[i]); x != i { t.Error("pbd.F_Fixed32Repeated bad", x, i) } - x = uint64(pbd.F_Int64Repeated[i]) - if x != i { + if x := uint64(pbd.F_Int64Repeated[i]); x != i { t.Error("pbd.F_Int64Repeated bad", x, i) } - x = uint64(pbd.F_Int32Repeated[i]) - if x != i { + if x := uint64(pbd.F_Int32Repeated[i]); x != i { t.Error("pbd.F_Int32Repeated bad", x, i) } - if pbd.F_BoolRepeated[i] != (i%2 == 0) { + if x := pbd.F_BoolRepeated[i]; x != (i%2 == 0) { t.Error("pbd.F_BoolRepeated bad", x, i) } if pbd.RepeatedField[i] == nil { // TODO: more checking? @@ -1222,21 +1174,25 @@ func TestBigRepeated(t *testing.T) { } } -// Verify we give a useful message when decoding to the wrong structure type. -func TestTypeMismatch(t *testing.T) { - pb1 := initGoTest(true) +func TestBadWireTypeUnknown(t *testing.T) { + var b []byte + fmt.Sscanf("0a01780d00000000080b101612036161611521000000202c220362626225370000002203636363214200000000000000584d5a036464645900000000000056405d63000000", "%x", &b) - // Marshal - o := old() - o.Marshal(pb1) + m := new(MyMessage) + if err := Unmarshal(b, m); err != nil { + t.Errorf("unexpected Unmarshal error: %v", err) + } - // Now Unmarshal it to the wrong type. - pb2 := initGoTestField() - err := o.Unmarshal(pb2) - if err == nil { - t.Error("expected error, got no error") - } else if !strings.Contains(err.Error(), "bad wiretype") { - t.Error("expected bad wiretype error, got", err) + var unknown []byte + fmt.Sscanf("0a01780d0000000010161521000000202c2537000000214200000000000000584d5a036464645d63000000", "%x", &unknown) + if !bytes.Equal(m.XXX_unrecognized, unknown) { + t.Errorf("unknown bytes mismatch:\ngot %x\nwant %x", m.XXX_unrecognized, unknown) + } + DiscardUnknown(m) + + want := &MyMessage{Count: Int32(11), Name: String("aaa"), Pet: []string{"bbb", "ccc"}, Bigfloat: Float64(88)} + if !Equal(m, want) { + t.Errorf("message mismatch:\ngot %v\nwant %v", m, want) } } @@ -1331,7 +1287,8 @@ func TestRequiredFieldEnforcement(t *testing.T) { err = Unmarshal(buf, pb) if err == nil { t.Error("unmarshal: expected error, got nil") - } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "{Unknown}") { + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Type") && !strings.Contains(err.Error(), "{Unknown}") { + // TODO: remove unknown cases once we commit to the new unmarshaler. t.Errorf("unmarshal: bad error type: %v", err) } } @@ -1348,7 +1305,7 @@ func TestRequiredFieldEnforcementGroups(t *testing.T) { buf := []byte{11, 12} if err := Unmarshal(buf, pb); err == nil { t.Error("unmarshal: expected error, got nil") - } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.{Unknown}") { + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.Field") && !strings.Contains(err.Error(), "Group.{Unknown}") { t.Errorf("unmarshal: bad error type: %v", err) } } @@ -1385,18 +1342,7 @@ func (*NNIMessage) Reset() {} func (*NNIMessage) String() string { return "" } func (*NNIMessage) ProtoMessage() {} -// A type that implements the Marshaler interface and is nillable. -type nillableMessage struct { - x uint64 -} - -func (nm *nillableMessage) Marshal() ([]byte, error) { - return EncodeVarint(nm.x), nil -} - -type NMMessage struct { - nm *nillableMessage -} +type NMMessage struct{} func (*NMMessage) Reset() {} func (*NMMessage) String() string { return "" } @@ -1595,6 +1541,14 @@ func TestVarintOverflow(t *testing.T) { } } +func TestBytesWithInvalidLengthInGroup(t *testing.T) { + // Overflowing a 64-bit length should not be allowed. + b := []byte{0xbb, 0x30, 0xb2, 0x30, 0xb0, 0xb2, 0x83, 0xf1, 0xb0, 0xb2, 0xef, 0xbf, 0xbd, 0x01} + if err := Unmarshal(b, new(MyMessage)); err == nil { + t.Fatalf("Overflowed uint64 length without error") + } +} + func TestUnmarshalFuzz(t *testing.T) { const N = 1000 seed := time.Now().UnixNano() @@ -1668,6 +1622,28 @@ func TestExtensionMarshalOrder(t *testing.T) { } } +func TestExtensionMapFieldMarshalDeterministic(t *testing.T) { + m := &MyMessage{Count: Int(123)} + if err := SetExtension(m, E_Ext_More, &Ext{MapField: map[int32]int32{1: 1, 2: 2, 3: 3, 4: 4}}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + marshal := func(m Message) []byte { + var b Buffer + b.SetDeterministic(true) + if err := b.Marshal(m); err != nil { + t.Fatalf("Marshal failed: %v", err) + } + return b.Bytes() + } + + want := marshal(m) + for i := 0; i < 100; i++ { + if got := marshal(m); !bytes.Equal(got, want) { + t.Errorf("Marshal produced inconsistent output with determinism enabled (pass %d).\n got %v\nwant %v", i, got, want) + } + } +} + // Many extensions, because small maps might not iterate differently on each iteration. var exts = []*ExtensionDesc{ E_X201, @@ -1802,6 +1778,43 @@ func TestUnmarshalMergesMessages(t *testing.T) { } } +func TestUnmarshalMergesGroups(t *testing.T) { + // If a nested group occurs twice in the input, + // the fields should be merged when decoding. + a := &GroupNew{ + G: &GroupNew_G{ + X: Int32(7), + Y: Int32(8), + }, + } + aData, err := Marshal(a) + if err != nil { + t.Fatalf("Marshal(a): %v", err) + } + b := &GroupNew{ + G: &GroupNew_G{ + X: Int32(9), + }, + } + bData, err := Marshal(b) + if err != nil { + t.Fatalf("Marshal(b): %v", err) + } + want := &GroupNew{ + G: &GroupNew_G{ + X: Int32(9), + Y: Int32(8), + }, + } + got := new(GroupNew) + if err := Unmarshal(append(aData, bData...), got); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + func TestEncodingSizes(t *testing.T) { tests := []struct { m Message @@ -1845,7 +1858,9 @@ func TestRequiredNotSetError(t *testing.T) { "b404" + // field 70, encoding 4, end group "aa0605" + "6279746573" + // field 101, encoding 2, string "bytes" "b0063f" + // field 102, encoding 0, 0x3f zigzag32 - "b8067f" // field 103, encoding 0, 0x7f zigzag64 + "b8067f" + // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff" + // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff" // field 105, encoding 1, -64 fixed64 o := old() bytes, err := Marshal(pb) @@ -1854,7 +1869,7 @@ func TestRequiredNotSetError(t *testing.T) { o.DebugPrint("", bytes) t.Fatalf("expected = %s", expected) } - if strings.Index(err.Error(), "RequiredField.Label") < 0 { + if !strings.Contains(err.Error(), "RequiredField.Label") { t.Errorf("marshal-1 wrong err msg: %v", err) } if !equal(bytes, expected, t) { @@ -1870,7 +1885,7 @@ func TestRequiredNotSetError(t *testing.T) { o.DebugPrint("", bytes) t.Fatalf("string = %s", expected) } - if strings.Index(err.Error(), "RequiredField.{Unknown}") < 0 { + if !strings.Contains(err.Error(), "RequiredField.Label") && !strings.Contains(err.Error(), "RequiredField.{Unknown}") { t.Errorf("unmarshal wrong err msg: %v", err) } bytes, err = Marshal(pbd) @@ -1879,7 +1894,7 @@ func TestRequiredNotSetError(t *testing.T) { o.DebugPrint("", bytes) t.Fatalf("string = %s", expected) } - if strings.Index(err.Error(), "RequiredField.Label") < 0 { + if !strings.Contains(err.Error(), "RequiredField.Label") { t.Errorf("marshal-2 wrong err msg: %v", err) } if !equal(bytes, expected, t) { @@ -1888,6 +1903,25 @@ func TestRequiredNotSetError(t *testing.T) { } } +func TestRequiredNotSetErrorWithBadWireTypes(t *testing.T) { + // Required field expects a varint, and properly found a varint. + if err := Unmarshal([]byte{0x08, 0x00}, new(GoEnum)); err != nil { + t.Errorf("Unmarshal = %v, want nil", err) + } + // Required field expects a varint, but found a fixed32 instead. + if err := Unmarshal([]byte{0x0d, 0x00, 0x00, 0x00, 0x00}, new(GoEnum)); err == nil { + t.Errorf("Unmarshal = nil, want RequiredNotSetError") + } + // Required field expects a varint, and found both a varint and fixed32 (ignored). + m := new(GoEnum) + if err := Unmarshal([]byte{0x08, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00}, m); err != nil { + t.Errorf("Unmarshal = %v, want nil", err) + } + if !bytes.Equal(m.XXX_unrecognized, []byte{0x0d, 0x00, 0x00, 0x00, 0x00}) { + t.Errorf("expected fixed32 to appear as unknown bytes: %x", m.XXX_unrecognized) + } +} + func fuzzUnmarshal(t *testing.T, data []byte) { defer func() { if e := recover(); e != nil { @@ -1946,6 +1980,32 @@ func TestMapFieldMarshal(t *testing.T) { (new(Buffer)).DebugPrint("Dump of b", b) } +func TestMapFieldDeterministicMarshal(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + } + + marshal := func(m Message) []byte { + var b Buffer + b.SetDeterministic(true) + if err := b.Marshal(m); err != nil { + t.Fatalf("Marshal failed: %v", err) + } + return b.Bytes() + } + + want := marshal(m) + for i := 0; i < 10; i++ { + if got := marshal(m); !bytes.Equal(got, want) { + t.Errorf("Marshal produced inconsistent output with determinism enabled (pass %d).\n got %v\nwant %v", i, got, want) + } + } +} + func TestMapFieldRoundTrips(t *testing.T) { m := &MessageWithMap{ NameMapping: map[int32]string{ @@ -1954,7 +2014,7 @@ func TestMapFieldRoundTrips(t *testing.T) { 8: "Dave", }, MsgMapping: map[int64]*FloatingPoint{ - 0x7001: &FloatingPoint{F: Float64(2.0)}, + 0x7001: {F: Float64(2.0)}, }, ByteMapping: map[bool][]byte{ false: []byte("that's not right!"), @@ -1970,14 +2030,8 @@ func TestMapFieldRoundTrips(t *testing.T) { if err := Unmarshal(b, m2); err != nil { t.Fatalf("Unmarshal: %v", err) } - for _, pair := range [][2]interface{}{ - {m.NameMapping, m2.NameMapping}, - {m.MsgMapping, m2.MsgMapping}, - {m.ByteMapping, m2.ByteMapping}, - } { - if !reflect.DeepEqual(pair[0], pair[1]) { - t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", pair[0], pair[1]) - } + if !Equal(m, m2) { + t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", m, m2) } } @@ -2005,7 +2059,7 @@ func TestMapFieldWithNil(t *testing.T) { func TestMapFieldWithNilBytes(t *testing.T) { m1 := &MessageWithMap{ ByteMapping: map[bool][]byte{ - false: []byte{}, + false: {}, true: nil, }, } @@ -2119,6 +2173,22 @@ func TestOneof(t *testing.T) { } } +func TestOneofNilBytes(t *testing.T) { + // A oneof with nil byte slice should marshal to tag + 0 (size), with no error. + m := &Communique{Union: &Communique_Data{Data: nil}} + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + want := []byte{ + 7<<3 | 2, // tag 7, wire type 2 + 0, // size + } + if !bytes.Equal(b, want) { + t.Errorf("Wrong result of Marshal: got %x, want %x", b, want) + } +} + func TestInefficientPackedBool(t *testing.T) { // https://github.com/golang/protobuf/issues/76 inp := []byte{ @@ -2132,6 +2202,150 @@ func TestInefficientPackedBool(t *testing.T) { } } +// Make sure pure-reflect-based implementation handles +// []int32-[]enum conversion correctly. +func TestRepeatedEnum2(t *testing.T) { + pb := &RepeatedEnum{ + Color: []RepeatedEnum_Color{RepeatedEnum_RED}, + } + b, err := Marshal(pb) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + x := new(RepeatedEnum) + err = Unmarshal(b, x) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + if !Equal(pb, x) { + t.Errorf("Incorrect result: want: %v got: %v", pb, x) + } +} + +// TestConcurrentMarshal makes sure that it is safe to marshal +// same message in multiple goroutines concurrently. +func TestConcurrentMarshal(t *testing.T) { + pb := initGoTest(true) + const N = 100 + b := make([][]byte, N) + + var wg sync.WaitGroup + for i := 0; i < N; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + var err error + b[i], err = Marshal(pb) + if err != nil { + t.Errorf("marshal error: %v", err) + } + }(i) + } + + wg.Wait() + for i := 1; i < N; i++ { + if !bytes.Equal(b[0], b[i]) { + t.Errorf("concurrent marshal result not same: b[0] = %v, b[%d] = %v", b[0], i, b[i]) + } + } +} + +func TestInvalidUTF8(t *testing.T) { + const invalidUTF8 = "\xde\xad\xbe\xef\x80\x00\xff" + tests := []struct { + label string + proto2 Message + proto3 Message + want []byte + }{{ + label: "Scalar", + proto2: &TestUTF8{Scalar: String(invalidUTF8)}, + proto3: &pb3.TestUTF8{Scalar: invalidUTF8}, + want: []byte{0x0a, 0x07, 0xde, 0xad, 0xbe, 0xef, 0x80, 0x00, 0xff}, + }, { + label: "Vector", + proto2: &TestUTF8{Vector: []string{invalidUTF8}}, + proto3: &pb3.TestUTF8{Vector: []string{invalidUTF8}}, + want: []byte{0x12, 0x07, 0xde, 0xad, 0xbe, 0xef, 0x80, 0x00, 0xff}, + }, { + label: "Oneof", + proto2: &TestUTF8{Oneof: &TestUTF8_Field{invalidUTF8}}, + proto3: &pb3.TestUTF8{Oneof: &pb3.TestUTF8_Field{invalidUTF8}}, + want: []byte{0x1a, 0x07, 0xde, 0xad, 0xbe, 0xef, 0x80, 0x00, 0xff}, + }, { + label: "MapKey", + proto2: &TestUTF8{MapKey: map[string]int64{invalidUTF8: 0}}, + proto3: &pb3.TestUTF8{MapKey: map[string]int64{invalidUTF8: 0}}, + want: []byte{0x22, 0x0b, 0x0a, 0x07, 0xde, 0xad, 0xbe, 0xef, 0x80, 0x00, 0xff, 0x10, 0x00}, + }, { + label: "MapValue", + proto2: &TestUTF8{MapValue: map[int64]string{0: invalidUTF8}}, + proto3: &pb3.TestUTF8{MapValue: map[int64]string{0: invalidUTF8}}, + want: []byte{0x2a, 0x0b, 0x08, 0x00, 0x12, 0x07, 0xde, 0xad, 0xbe, 0xef, 0x80, 0x00, 0xff}, + }} + + for _, tt := range tests { + // Proto2 should not validate UTF-8. + b, err := Marshal(tt.proto2) + if err != nil { + t.Errorf("Marshal(proto2.%s) = %v, want nil", tt.label, err) + } + if !bytes.Equal(b, tt.want) { + t.Errorf("Marshal(proto2.%s) = %x, want %x", tt.label, b, tt.want) + } + + m := Clone(tt.proto2) + m.Reset() + if err = Unmarshal(tt.want, m); err != nil { + t.Errorf("Unmarshal(proto2.%s) = %v, want nil", tt.label, err) + } + if !Equal(m, tt.proto2) { + t.Errorf("proto2.%s: output mismatch:\ngot %v\nwant %v", tt.label, m, tt.proto2) + } + + // Proto3 should validate UTF-8. + b, err = Marshal(tt.proto3) + if err == nil { + t.Errorf("Marshal(proto3.%s) = %v, want non-nil", tt.label, err) + } + if !bytes.Equal(b, tt.want) { + t.Errorf("Marshal(proto3.%s) = %x, want %x", tt.label, b, tt.want) + } + + m = Clone(tt.proto3) + m.Reset() + err = Unmarshal(tt.want, m) + if err == nil { + t.Errorf("Unmarshal(proto3.%s) = %v, want non-nil", tt.label, err) + } + if !Equal(m, tt.proto3) { + t.Errorf("proto3.%s: output mismatch:\ngot %v\nwant %v", tt.label, m, tt.proto2) + } + } +} + +func TestRequired(t *testing.T) { + // The F_BoolRequired field appears after all of the required fields. + // It should still be handled even after multiple required field violations. + m := &GoTest{F_BoolRequired: Bool(true)} + got, err := Marshal(m) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Errorf("Marshal() = %v, want RequiredNotSetError error", err) + } + if want := []byte{0x50, 0x01}; !bytes.Equal(got, want) { + t.Errorf("Marshal() = %x, want %x", got, want) + } + + m = new(GoTest) + err = Unmarshal(got, m) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Errorf("Marshal() = %v, want RequiredNotSetError error", err) + } + if !m.GetF_BoolRequired() { + t.Error("m.F_BoolRequired = false, want true") + } +} + // Benchmarks func testMsg() *GoTest { diff --git a/vendor/github.com/golang/protobuf/proto/any_test.go b/vendor/github.com/golang/protobuf/proto/any_test.go index 1a3c22ed..56fc97c1 100644 --- a/vendor/github.com/golang/protobuf/proto/any_test.go +++ b/vendor/github.com/golang/protobuf/proto/any_test.go @@ -38,7 +38,7 @@ import ( "github.com/golang/protobuf/proto" pb "github.com/golang/protobuf/proto/proto3_proto" - testpb "github.com/golang/protobuf/proto/testdata" + testpb "github.com/golang/protobuf/proto/test_proto" anypb "github.com/golang/protobuf/ptypes/any" ) @@ -166,33 +166,33 @@ anything: < name: "David" result_count: 47 anything: < - [type.googleapis.com/testdata.MyMessage]: < + [type.googleapis.com/test_proto.MyMessage]: < count: 47 name: "David" - [testdata.Ext.more]: < + [test_proto.Ext.more]: < data: "foo" > - [testdata.Ext.text]: "bar" + [test_proto.Ext.text]: "bar" > > many_things: < - [type.googleapis.com/testdata.MyMessage]: < + [type.googleapis.com/test_proto.MyMessage]: < count: 42 bikeshed: GREEN rep_bytes: "roboto" - [testdata.Ext.more]: < + [test_proto.Ext.more]: < data: "baz" > > > many_things: < - [type.googleapis.com/testdata.MyMessage]: < + [type.googleapis.com/test_proto.MyMessage]: < count: 47 name: "David" - [testdata.Ext.more]: < + [test_proto.Ext.more]: < data: "foo" > - [testdata.Ext.text]: "bar" + [test_proto.Ext.text]: "bar" > > ` diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go index e392575b..3cd3249f 100644 --- a/vendor/github.com/golang/protobuf/proto/clone.go +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -35,22 +35,39 @@ package proto import ( + "fmt" "log" "reflect" "strings" ) // Clone returns a deep copy of a protocol buffer. -func Clone(pb Message) Message { - in := reflect.ValueOf(pb) +func Clone(src Message) Message { + in := reflect.ValueOf(src) if in.IsNil() { - return pb + return src } - out := reflect.New(in.Type().Elem()) - // out is empty so a merge is a deep copy. - mergeStruct(out.Elem(), in.Elem()) - return out.Interface().(Message) + dst := out.Interface().(Message) + Merge(dst, src) + return dst +} + +// Merger is the interface representing objects that can merge messages of the same type. +type Merger interface { + // Merge merges src into this message. + // Required and optional fields that are set in src will be set to that value in dst. + // Elements of repeated fields will be appended. + // + // Merge may panic if called with a different argument type than the receiver. + Merge(src Message) +} + +// generatedMerger is the custom merge method that generated protos will have. +// We must add this method since a generate Merge method will conflict with +// many existing protos that have a Merge data field already defined. +type generatedMerger interface { + XXX_Merge(src Message) } // Merge merges src into dst. @@ -58,17 +75,24 @@ func Clone(pb Message) Message { // Elements of repeated fields will be appended. // Merge panics if src and dst are not the same type, or if dst is nil. func Merge(dst, src Message) { + if m, ok := dst.(Merger); ok { + m.Merge(src) + return + } + in := reflect.ValueOf(src) out := reflect.ValueOf(dst) if out.IsNil() { panic("proto: nil destination") } if in.Type() != out.Type() { - // Explicit test prior to mergeStruct so that mistyped nils will fail - panic("proto: type mismatch") + panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) } if in.IsNil() { - // Merging nil into non-nil is a quiet no-op + return // Merge from nil src is a noop + } + if m, ok := dst.(generatedMerger); ok { + m.XXX_Merge(src) return } mergeStruct(out.Elem(), in.Elem()) @@ -84,7 +108,7 @@ func mergeStruct(out, in reflect.Value) { mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } - if emIn, ok := extendable(in.Addr().Interface()); ok { + if emIn, err := extendable(in.Addr().Interface()); err == nil { emOut, _ := extendable(out.Addr().Interface()) mIn, muIn := emIn.extensionsRead() if mIn != nil { diff --git a/vendor/github.com/golang/protobuf/proto/clone_test.go b/vendor/github.com/golang/protobuf/proto/clone_test.go index f607ff49..0d3b1273 100644 --- a/vendor/github.com/golang/protobuf/proto/clone_test.go +++ b/vendor/github.com/golang/protobuf/proto/clone_test.go @@ -37,7 +37,7 @@ import ( "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" + pb "github.com/golang/protobuf/proto/test_proto" ) var cloneTestMessage = &pb.MyMessage{ @@ -72,7 +72,7 @@ func init() { func TestClone(t *testing.T) { m := proto.Clone(cloneTestMessage).(*pb.MyMessage) if !proto.Equal(m, cloneTestMessage) { - t.Errorf("Clone(%v) = %v", cloneTestMessage, m) + t.Fatalf("Clone(%v) = %v", cloneTestMessage, m) } // Verify it was a deep copy. @@ -244,27 +244,45 @@ var mergeTests = []struct { Data: []byte("texas!"), }, }, - // Oneof fields should merge by assignment. - { - src: &pb.Communique{ - Union: &pb.Communique_Number{41}, - }, - dst: &pb.Communique{ - Union: &pb.Communique_Name{"Bobby Tables"}, - }, - want: &pb.Communique{ - Union: &pb.Communique_Number{41}, - }, + { // Oneof fields should merge by assignment. + src: &pb.Communique{Union: &pb.Communique_Number{41}}, + dst: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}}, + want: &pb.Communique{Union: &pb.Communique_Number{41}}, + }, + { // Oneof nil is the same as not set. + src: &pb.Communique{}, + dst: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}}, + want: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}}, }, - // Oneof nil is the same as not set. { - src: &pb.Communique{}, - dst: &pb.Communique{ - Union: &pb.Communique_Name{"Bobby Tables"}, - }, - want: &pb.Communique{ - Union: &pb.Communique_Name{"Bobby Tables"}, - }, + src: &pb.Communique{Union: &pb.Communique_Number{1337}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Number{1337}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Col{pb.MyMessage_RED}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Col{pb.MyMessage_RED}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Data{[]byte("hello")}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Data{[]byte("hello")}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Msg{}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Msg{}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123")}}}, + dst: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}}, + want: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123"), BytesField: []byte{1, 2, 3}}}}, }, { src: &proto3pb.Message{ @@ -287,14 +305,86 @@ var mergeTests = []struct { }, }, }, + { + src: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + dst: &pb.GoTest{}, + want: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + }, + { + src: &pb.GoTest{}, + dst: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + want: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + }, + { + src: &pb.GoTest{ + F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}}, + }, + dst: &pb.GoTest{}, + want: &pb.GoTest{ + F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}}, + }, + }, + { + src: &pb.MyMessage{ + Others: []*pb.OtherMessage{}, + }, + dst: &pb.MyMessage{}, + want: &pb.MyMessage{ + Others: []*pb.OtherMessage{}, + }, + }, } func TestMerge(t *testing.T) { for _, m := range mergeTests { got := proto.Clone(m.dst) + if !proto.Equal(got, m.dst) { + t.Errorf("Clone()\ngot %v\nwant %v", got, m.dst) + continue + } proto.Merge(got, m.src) if !proto.Equal(got, m.want) { - t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want) + t.Errorf("Merge(%v, %v)\ngot %v\nwant %v", m.dst, m.src, got, m.want) } } } diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go index aa207298..d9aa3c42 100644 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -39,8 +39,6 @@ import ( "errors" "fmt" "io" - "os" - "reflect" ) // errOverflow is returned when an integer is too large to be represented. @@ -50,10 +48,6 @@ var errOverflow = errors.New("proto: integer overflow") // wire type is encountered. It does not get returned to user code. var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") -// The fundamental decoders that interpret bytes on the wire. -// Those that take integer types all return uint64 and are -// therefore of type valueDecoder. - // DecodeVarint reads a varint-encoded integer from the slice. // It returns the integer and the number of bytes consumed, or // zero if there is not enough. @@ -267,9 +261,6 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) { return } -// These are not ValueDecoders: they produce an array of bytes or a string. -// bytes, embedded messages - // DecodeRawBytes reads a count-delimited byte buffer from the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. @@ -311,81 +302,29 @@ func (p *Buffer) DecodeStringBytes() (s string, err error) { return string(buf), nil } -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -// If the protocol buffer has extensions, and the field matches, add it as an extension. -// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. -func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { - oi := o.index - - err := o.skip(t, tag, wire) - if err != nil { - return err - } - - if !unrecField.IsValid() { - return nil - } - - ptr := structPointer_Bytes(base, unrecField) - - // Add the skipped field to struct field - obuf := o.buf - - o.buf = *ptr - o.EncodeVarint(uint64(tag<<3 | wire)) - *ptr = append(o.buf, obuf[oi:o.index]...) - - o.buf = obuf - - return nil -} - -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -func (o *Buffer) skip(t reflect.Type, tag, wire int) error { - - var u uint64 - var err error - - switch wire { - case WireVarint: - _, err = o.DecodeVarint() - case WireFixed64: - _, err = o.DecodeFixed64() - case WireBytes: - _, err = o.DecodeRawBytes(false) - case WireFixed32: - _, err = o.DecodeFixed32() - case WireStartGroup: - for { - u, err = o.DecodeVarint() - if err != nil { - break - } - fwire := int(u & 0x7) - if fwire == WireEndGroup { - break - } - ftag := int(u >> 3) - err = o.skip(t, ftag, fwire) - if err != nil { - break - } - } - default: - err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) - } - return err -} - // Unmarshaler is the interface representing objects that can -// unmarshal themselves. The method should reset the receiver before -// decoding starts. The argument points to data that may be +// unmarshal themselves. The argument points to data that may be // overwritten, so implementations should not keep references to the // buffer. +// Unmarshal implementations should not clear the receiver. +// Any unmarshaled data should be merged into the receiver. +// Callers of Unmarshal that do not want to retain existing data +// should Reset the receiver before calling Unmarshal. type Unmarshaler interface { Unmarshal([]byte) error } +// newUnmarshaler is the interface representing objects that can +// unmarshal themselves. The semantics are identical to Unmarshaler. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newUnmarshaler interface { + XXX_Unmarshal([]byte) error +} + // Unmarshal parses the protocol buffer representation in buf and places the // decoded result in pb. If the struct underlying pb does not match // the data in buf, the results can be unpredictable. @@ -395,7 +334,13 @@ type Unmarshaler interface { // to preserve and append to existing data. func Unmarshal(buf []byte, pb Message) error { pb.Reset() - return UnmarshalMerge(buf, pb) + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) } // UnmarshalMerge parses the protocol buffer representation in buf and @@ -405,8 +350,16 @@ func Unmarshal(buf []byte, pb Message) error { // UnmarshalMerge merges into existing data in pb. // Most code should use Unmarshal instead. func UnmarshalMerge(buf []byte, pb Message) error { - // If the object can unmarshal itself, let it. + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 return u.Unmarshal(buf) } return NewBuffer(buf).Unmarshal(pb) @@ -422,12 +375,17 @@ func (p *Buffer) DecodeMessage(pb Message) error { } // DecodeGroup reads a tag-delimited group from the Buffer. +// StartGroup tag is already consumed. This function consumes +// EndGroup tag. func (p *Buffer) DecodeGroup(pb Message) error { - typ, base, err := getbase(pb) - if err != nil { - return err + b := p.buf[p.index:] + x, y := findEndGroup(b) + if x < 0 { + return io.ErrUnexpectedEOF } - return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) + err := Unmarshal(b[:x], pb) + p.index += y + return err } // Unmarshal parses the protocol buffer representation in the @@ -438,533 +396,33 @@ func (p *Buffer) DecodeGroup(pb Message) error { // Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. func (p *Buffer) Unmarshal(pb Message) error { // If the object can unmarshal itself, let it. + if u, ok := pb.(newUnmarshaler); ok { + err := u.XXX_Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 err := u.Unmarshal(p.buf[p.index:]) p.index = len(p.buf) return err } - typ, base, err := getbase(pb) - if err != nil { - return err - } - - err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) - - if collectStats { - stats.Decode++ - } - - return err -} - -// unmarshalType does the work of unmarshaling a structure. -func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { - var state errorState - required, reqFields := prop.reqCount, uint64(0) - - var err error - for err == nil && o.index < len(o.buf) { - oi := o.index - var u uint64 - u, err = o.DecodeVarint() - if err != nil { - break - } - wire := int(u & 0x7) - if wire == WireEndGroup { - if is_group { - if required > 0 { - // Not enough information to determine the exact field. - // (See below.) - return &RequiredNotSetError{"{Unknown}"} - } - return nil // input is satisfied - } - return fmt.Errorf("proto: %s: wiretype end group for non-group", st) - } - tag := int(u >> 3) - if tag <= 0 { - return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) - } - fieldnum, ok := prop.decoderTags.get(tag) - if !ok { - // Maybe it's an extension? - if prop.extendable { - if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { - if err = o.skip(st, tag, wire); err == nil { - extmap := e.extensionsWrite() - ext := extmap[int32(tag)] // may be missing - ext.enc = append(ext.enc, o.buf[oi:o.index]...) - extmap[int32(tag)] = ext - } - continue - } - } - // Maybe it's a oneof? - if prop.oneofUnmarshaler != nil { - m := structPointer_Interface(base, st).(Message) - // First return value indicates whether tag is a oneof field. - ok, err = prop.oneofUnmarshaler(m, tag, wire, o) - if err == ErrInternalBadWireType { - // Map the error to something more descriptive. - // Do the formatting here to save generated code space. - err = fmt.Errorf("bad wiretype for oneof field in %T", m) - } - if ok { - continue - } - } - err = o.skipAndSave(st, tag, wire, base, prop.unrecField) - continue - } - p := prop.Prop[fieldnum] - - if p.dec == nil { - fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) - continue - } - dec := p.dec - if wire != WireStartGroup && wire != p.WireType { - if wire == WireBytes && p.packedDec != nil { - // a packable field - dec = p.packedDec - } else { - err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) - continue - } - } - decErr := dec(o, p, base) - if decErr != nil && !state.shouldContinue(decErr, p) { - err = decErr - } - if err == nil && p.Required { - // Successfully decoded a required field. - if tag <= 64 { - // use bitmap for fields 1-64 to catch field reuse. - var mask uint64 = 1 << uint64(tag-1) - if reqFields&mask == 0 { - // new required field - reqFields |= mask - required-- - } - } else { - // This is imprecise. It can be fooled by a required field - // with a tag > 64 that is encoded twice; that's very rare. - // A fully correct implementation would require allocating - // a data structure, which we would like to avoid. - required-- - } - } - } - if err == nil { - if is_group { - return io.ErrUnexpectedEOF - } - if state.err != nil { - return state.err - } - if required > 0 { - // Not enough information to determine the exact field. If we use extra - // CPU, we could determine the field only if the missing required field - // has a tag <= 64 and we check reqFields. - return &RequiredNotSetError{"{Unknown}"} - } - } - return err -} - -// Individual type decoders -// For each, -// u is the decoded value, -// v is a pointer to the field (pointer) in the struct - -// Sizes of the pools to allocate inside the Buffer. -// The goal is modest amortization and allocation -// on at least 16-byte boundaries. -const ( - boolPoolSize = 16 - uint32PoolSize = 8 - uint64PoolSize = 4 -) - -// Decode a bool. -func (o *Buffer) dec_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - if len(o.bools) == 0 { - o.bools = make([]bool, boolPoolSize) - } - o.bools[0] = u != 0 - *structPointer_Bool(base, p.field) = &o.bools[0] - o.bools = o.bools[1:] - return nil -} - -func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - *structPointer_BoolVal(base, p.field) = u != 0 - return nil -} - -// Decode an int32. -func (o *Buffer) dec_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) - return nil -} - -func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) - return nil -} - -// Decode an int64. -func (o *Buffer) dec_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64_Set(structPointer_Word64(base, p.field), o, u) - return nil -} - -func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64Val_Set(structPointer_Word64Val(base, p.field), o, u) - return nil -} - -// Decode a string. -func (o *Buffer) dec_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_String(base, p.field) = &s - return nil -} - -func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_StringVal(base, p.field) = s - return nil -} - -// Decode a slice of bytes ([]byte). -func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - *structPointer_Bytes(base, p.field) = b - return nil -} - -// Decode a slice of bools ([]bool). -func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - v := structPointer_BoolSlice(base, p.field) - *v = append(*v, u != 0) - return nil -} - -// Decode a slice of bools ([]bool) in packed format. -func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { - v := structPointer_BoolSlice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded bools - fin := o.index + nb - if fin < o.index { - return errOverflow - } - - y := *v - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - y = append(y, u != 0) - } - - *v = y - return nil -} - -// Decode a slice of int32s ([]int32). -func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - structPointer_Word32Slice(base, p.field).Append(uint32(u)) - return nil -} - -// Decode a slice of int32s ([]int32) in packed format. -func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int32s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(uint32(u)) - } - return nil -} - -// Decode a slice of int64s ([]int64). -func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - - structPointer_Word64Slice(base, p.field).Append(u) - return nil -} - -// Decode a slice of int64s ([]int64) in packed format. -func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int64s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(u) - } - return nil -} - -// Decode a slice of strings ([]string). -func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - v := structPointer_StringSlice(base, p.field) - *v = append(*v, s) - return nil -} - -// Decode a slice of slice of bytes ([][]byte). -func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - v := structPointer_BytesSlice(base, p.field) - *v = append(*v, b) - return nil -} - -// Decode a map field. -func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - oi := o.index // index at the end of this map entry - o.index -= len(raw) // move buffer back to start of map entry - - mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V - if mptr.Elem().IsNil() { - mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) - } - v := mptr.Elem() // map[K]V - - // Prepare addressable doubly-indirect placeholders for the key and value types. - // See enc_new_map for why. - keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K - keybase := toStructPointer(keyptr.Addr()) // **K - - var valbase structPointer - var valptr reflect.Value - switch p.mtype.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valptr = reflect.ValueOf(&dummy) // *[]byte - valbase = toStructPointer(valptr) // *[]byte - case reflect.Ptr: - // message; valptr is **Msg; need to allocate the intermediate pointer - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valptr.Set(reflect.New(valptr.Type().Elem())) - valbase = toStructPointer(valptr) - default: - // everything else - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valbase = toStructPointer(valptr.Addr()) // **V - } - - // Decode. - // This parses a restricted wire format, namely the encoding of a message - // with two fields. See enc_new_map for the format. - for o.index < oi { - // tagcode for key and value properties are always a single byte - // because they have tags 1 and 2. - tagcode := o.buf[o.index] - o.index++ - switch tagcode { - case p.mkeyprop.tagcode[0]: - if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { - return err - } - case p.mvalprop.tagcode[0]: - if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { - return err - } - default: - // TODO: Should we silently skip this instead? - return fmt.Errorf("proto: bad map data tag %d", raw[0]) - } - } - keyelem, valelem := keyptr.Elem(), valptr.Elem() - if !keyelem.IsValid() { - keyelem = reflect.Zero(p.mtype.Key()) - } - if !valelem.IsValid() { - valelem = reflect.Zero(p.mtype.Elem()) - } - - v.SetMapIndex(keyelem, valelem) - return nil -} - -// Decode a group. -func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - return o.unmarshalType(p.stype, p.sprop, true, bas) -} - -// Decode an embedded message. -func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { - raw, e := o.DecodeRawBytes(false) - if e != nil { - return e - } - - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := structPointer_Interface(bas, p.stype) - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, false, bas) - o.buf = obuf - o.index = oi - - return err -} - -// Decode a slice of embedded messages. -func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, false, base) -} - -// Decode a slice of embedded groups. -func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, true, base) -} - -// Decode a slice of structs ([]*struct). -func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { - v := reflect.New(p.stype) - bas := toStructPointer(v) - structPointer_StructPointerSlice(base, p.field).Append(bas) - - if is_group { - err := o.unmarshalType(p.stype, p.sprop, is_group, bas) - return err - } - - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := v.Interface() - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, is_group, bas) - - o.buf = obuf - o.index = oi - + // Slow workaround for messages that aren't Unmarshalers. + // This includes some hand-coded .pb.go files and + // bootstrap protos. + // TODO: fix all of those and then add Unmarshal to + // the Message interface. Then: + // The cast above and code below can be deleted. + // The old unmarshaler can be deleted. + // Clients can call Unmarshal directly (can already do that, actually). + var info InternalMessageInfo + err := info.Unmarshal(pb, p.buf[p.index:]) + p.index = len(p.buf) return err } diff --git a/vendor/github.com/golang/protobuf/proto/decode_test.go b/vendor/github.com/golang/protobuf/proto/decode_test.go index 2c4c31d1..949be3ab 100644 --- a/vendor/github.com/golang/protobuf/proto/decode_test.go +++ b/vendor/github.com/golang/protobuf/proto/decode_test.go @@ -41,10 +41,7 @@ import ( tpb "github.com/golang/protobuf/proto/proto3_proto" ) -var ( - bytesBlackhole []byte - msgBlackhole = new(tpb.Message) -) +var msgBlackhole = new(tpb.Message) // BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and // 2 bytes long). diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go new file mode 100644 index 00000000..dea2617c --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/discard.go @@ -0,0 +1,350 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +type generatedDiscarder interface { + XXX_DiscardUnknown() +} + +// DiscardUnknown recursively discards all unknown fields from this message +// and all embedded messages. +// +// When unmarshaling a message with unrecognized fields, the tags and values +// of such fields are preserved in the Message. This allows a later call to +// marshal to be able to produce a message that continues to have those +// unrecognized fields. To avoid this, DiscardUnknown is used to +// explicitly clear the unknown fields after unmarshaling. +// +// For proto2 messages, the unknown fields of message extensions are only +// discarded from messages that have been accessed via GetExtension. +func DiscardUnknown(m Message) { + if m, ok := m.(generatedDiscarder); ok { + m.XXX_DiscardUnknown() + return + } + // TODO: Dynamically populate a InternalMessageInfo for legacy messages, + // but the master branch has no implementation for InternalMessageInfo, + // so it would be more work to replicate that approach. + discardLegacy(m) +} + +// DiscardUnknown recursively discards all unknown fields. +func (a *InternalMessageInfo) DiscardUnknown(m Message) { + di := atomicLoadDiscardInfo(&a.discard) + if di == nil { + di = getDiscardInfo(reflect.TypeOf(m).Elem()) + atomicStoreDiscardInfo(&a.discard, di) + } + di.discard(toPointer(&m)) +} + +type discardInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []discardFieldInfo + unrecognized field +} + +type discardFieldInfo struct { + field field // Offset of field, guaranteed to be valid + discard func(src pointer) +} + +var ( + discardInfoMap = map[reflect.Type]*discardInfo{} + discardInfoLock sync.Mutex +) + +func getDiscardInfo(t reflect.Type) *discardInfo { + discardInfoLock.Lock() + defer discardInfoLock.Unlock() + di := discardInfoMap[t] + if di == nil { + di = &discardInfo{typ: t} + discardInfoMap[t] = di + } + return di +} + +func (di *discardInfo) discard(src pointer) { + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&di.initialized) == 0 { + di.computeDiscardInfo() + } + + for _, fi := range di.fields { + sfp := src.offset(fi.field) + fi.discard(sfp) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { + // Ignore lock since DiscardUnknown is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + DiscardUnknown(m) + } + } + } + + if di.unrecognized.IsValid() { + *src.offset(di.unrecognized).toBytes() = nil + } +} + +func (di *discardInfo) computeDiscardInfo() { + di.lock.Lock() + defer di.lock.Unlock() + if di.initialized != 0 { + return + } + t := di.typ + n := t.NumField() + + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + dfi := discardFieldInfo{field: toField(&f)} + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) + case isSlice: // E.g., []*pb.T + di := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sps := src.getPointerSlice() + for _, sp := range sps { + if !sp.isNil() { + di.discard(sp) + } + } + } + default: // E.g., *pb.T + di := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sp := src.getPointer() + if !sp.isNil() { + di.discard(sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) + default: // E.g., map[K]V + if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) + dfi.discard = func(src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + DiscardUnknown(val.Interface().(Message)) + } + } + } else { + dfi.discard = func(pointer) {} // Noop + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) + default: // E.g., interface{} + // TODO: Make this faster? + dfi.discard = func(src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + DiscardUnknown(sv.Interface().(Message)) + } + } + } + } + default: + continue + } + di.fields = append(di.fields, dfi) + } + + di.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + di.unrecognized = toField(&f) + } + + atomic.StoreInt32(&di.initialized, 1) +} + +func discardLegacy(m Message) { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return + } + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + vf := v.Field(i) + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) + case isSlice: // E.g., []*pb.T + for j := 0; j < vf.Len(); j++ { + discardLegacy(vf.Index(j).Interface().(Message)) + } + default: // E.g., *pb.T + discardLegacy(vf.Interface().(Message)) + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) + default: // E.g., map[K]V + tv := vf.Type().Elem() + if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) + for _, key := range vf.MapKeys() { + val := vf.MapIndex(key) + discardLegacy(val.Interface().(Message)) + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) + default: // E.g., test_proto.isCommunique_Union interface + if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { + vf = vf.Elem() // E.g., *test_proto.Communique_Msg + if !vf.IsNil() { + vf = vf.Elem() // E.g., test_proto.Communique_Msg + vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value + if vf.Kind() == reflect.Ptr { + discardLegacy(vf.Interface().(Message)) + } + } + } + } + } + } + + if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { + if vf.Type() != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + vf.Set(reflect.ValueOf([]byte(nil))) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(m); err == nil { + // Ignore lock since discardLegacy is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + discardLegacy(m) + } + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/discard_test.go b/vendor/github.com/golang/protobuf/proto/discard_test.go new file mode 100644 index 00000000..a2ff5509 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/discard_test.go @@ -0,0 +1,170 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/golang/protobuf/proto" + + proto3pb "github.com/golang/protobuf/proto/proto3_proto" + pb "github.com/golang/protobuf/proto/test_proto" +) + +func TestDiscardUnknown(t *testing.T) { + tests := []struct { + desc string + in, want proto.Message + }{{ + desc: "Nil", + in: nil, want: nil, // Should not panic + }, { + desc: "NilPtr", + in: (*proto3pb.Message)(nil), want: (*proto3pb.Message)(nil), // Should not panic + }, { + desc: "Nested", + in: &proto3pb.Message{ + Name: "Aaron", + Nested: &proto3pb.Nested{Cute: true, XXX_unrecognized: []byte("blah")}, + XXX_unrecognized: []byte("blah"), + }, + want: &proto3pb.Message{ + Name: "Aaron", + Nested: &proto3pb.Nested{Cute: true}, + }, + }, { + desc: "Slice", + in: &proto3pb.Message{ + Name: "Aaron", + Children: []*proto3pb.Message{ + {Name: "Sarah", XXX_unrecognized: []byte("blah")}, + {Name: "Abraham", XXX_unrecognized: []byte("blah")}, + }, + XXX_unrecognized: []byte("blah"), + }, + want: &proto3pb.Message{ + Name: "Aaron", + Children: []*proto3pb.Message{ + {Name: "Sarah"}, + {Name: "Abraham"}, + }, + }, + }, { + desc: "OneOf", + in: &pb.Communique{ + Union: &pb.Communique_Msg{&pb.Strings{ + StringField: proto.String("123"), + XXX_unrecognized: []byte("blah"), + }}, + XXX_unrecognized: []byte("blah"), + }, + want: &pb.Communique{ + Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123")}}, + }, + }, { + desc: "Map", + in: &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4002: &pb.FloatingPoint{ + Exact: proto.Bool(true), + XXX_unrecognized: []byte("blah"), + }, + }}, + want: &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4002: &pb.FloatingPoint{Exact: proto.Bool(true)}, + }}, + }, { + desc: "Extension", + in: func() proto.Message { + m := &pb.MyMessage{ + Count: proto.Int32(42), + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + XXX_unrecognized: []byte("blah"), + }, + XXX_unrecognized: []byte("blah"), + } + proto.SetExtension(m, pb.E_Ext_More, &pb.Ext{ + Data: proto.String("extension"), + XXX_unrecognized: []byte("blah"), + }) + return m + }(), + want: func() proto.Message { + m := &pb.MyMessage{ + Count: proto.Int32(42), + Somegroup: &pb.MyMessage_SomeGroup{GroupField: proto.Int32(6)}, + } + proto.SetExtension(m, pb.E_Ext_More, &pb.Ext{Data: proto.String("extension")}) + return m + }(), + }} + + // Test the legacy code path. + for _, tt := range tests { + // Clone the input so that we don't alter the original. + in := tt.in + if in != nil { + in = proto.Clone(tt.in) + } + + var m LegacyMessage + m.Message, _ = in.(*proto3pb.Message) + m.Communique, _ = in.(*pb.Communique) + m.MessageWithMap, _ = in.(*pb.MessageWithMap) + m.MyMessage, _ = in.(*pb.MyMessage) + proto.DiscardUnknown(&m) + if !proto.Equal(in, tt.want) { + t.Errorf("test %s/Legacy, expected unknown fields to be discarded\ngot %v\nwant %v", tt.desc, in, tt.want) + } + } + + for _, tt := range tests { + proto.DiscardUnknown(tt.in) + if !proto.Equal(tt.in, tt.want) { + t.Errorf("test %s, expected unknown fields to be discarded\ngot %v\nwant %v", tt.desc, tt.in, tt.want) + } + } +} + +// LegacyMessage is a proto.Message that has several nested messages. +// This does not have the XXX_DiscardUnknown method and so forces DiscardUnknown +// to use the legacy fallback logic. +type LegacyMessage struct { + Message *proto3pb.Message + Communique *pb.Communique + MessageWithMap *pb.MessageWithMap + MyMessage *pb.MyMessage +} + +func (m *LegacyMessage) Reset() { *m = LegacyMessage{} } +func (m *LegacyMessage) String() string { return proto.CompactTextString(m) } +func (*LegacyMessage) ProtoMessage() {} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go index 8b84d1b2..3abfed2c 100644 --- a/vendor/github.com/golang/protobuf/proto/encode.go +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -37,28 +37,9 @@ package proto import ( "errors" - "fmt" "reflect" - "sort" ) -// RequiredNotSetError is the error returned if Marshal is called with -// a protocol buffer struct whose required fields have not -// all been initialized. It is also the error returned if Unmarshal is -// called with an encoded protocol buffer that does not include all the -// required fields. -// -// When printed, RequiredNotSetError reports the first unset required field in a -// message. If the field cannot be precisely determined, it is reported as -// "{Unknown}". -type RequiredNotSetError struct { - field string -} - -func (e *RequiredNotSetError) Error() string { - return fmt.Sprintf("proto: required field %q not set", e.field) -} - var ( // errRepeatedHasNil is the error returned if Marshal is called with // a struct with a repeated field containing a nil element. @@ -82,10 +63,6 @@ var ( const maxVarintBytes = 10 // maximum length of a varint -// maxMarshalSize is the largest allowed size of an encoded protobuf, -// since C++ and Java use signed int32s for the size. -const maxMarshalSize = 1<<31 - 1 - // EncodeVarint returns the varint encoding of x. // This is the format for the // int32, int64, uint32, uint64, bool, and enum @@ -119,18 +96,27 @@ func (p *Buffer) EncodeVarint(x uint64) error { // SizeVarint returns the varint encoding size of an integer. func SizeVarint(x uint64) int { - return sizeVarint(x) -} - -func sizeVarint(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } + switch { + case x < 1<<7: + return 1 + case x < 1<<14: + return 2 + case x < 1<<21: + return 3 + case x < 1<<28: + return 4 + case x < 1<<35: + return 5 + case x < 1<<42: + return 6 + case x < 1<<49: + return 7 + case x < 1<<56: + return 8 + case x < 1<<63: + return 9 } - return n + return 10 } // EncodeFixed64 writes a 64-bit integer to the Buffer. @@ -149,10 +135,6 @@ func (p *Buffer) EncodeFixed64(x uint64) error { return nil } -func sizeFixed64(x uint64) int { - return 8 -} - // EncodeFixed32 writes a 32-bit integer to the Buffer. // This is the format for the // fixed32, sfixed32, and float protocol buffer types. @@ -165,20 +147,12 @@ func (p *Buffer) EncodeFixed32(x uint64) error { return nil } -func sizeFixed32(x uint64) int { - return 4 -} - // EncodeZigzag64 writes a zigzag-encoded 64-bit integer // to the Buffer. // This is the format used for the sint64 protocol buffer type. func (p *Buffer) EncodeZigzag64(x uint64) error { // use signed number to get arithmetic right shift. - return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) -} - -func sizeZigzag64(x uint64) int { - return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } // EncodeZigzag32 writes a zigzag-encoded 32-bit integer @@ -189,10 +163,6 @@ func (p *Buffer) EncodeZigzag32(x uint64) error { return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) } -func sizeZigzag32(x uint64) int { - return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. @@ -202,11 +172,6 @@ func (p *Buffer) EncodeRawBytes(b []byte) error { return nil } -func sizeRawBytes(b []byte) int { - return sizeVarint(uint64(len(b))) + - len(b) -} - // EncodeStringBytes writes an encoded string to the Buffer. // This is the format used for the proto2 string type. func (p *Buffer) EncodeStringBytes(s string) error { @@ -215,319 +180,17 @@ func (p *Buffer) EncodeStringBytes(s string) error { return nil } -func sizeStringBytes(s string) int { - return sizeVarint(uint64(len(s))) + - len(s) -} - // Marshaler is the interface representing objects that can marshal themselves. type Marshaler interface { Marshal() ([]byte, error) } -// Marshal takes the protocol buffer -// and encodes it into the wire format, returning the data. -func Marshal(pb Message) ([]byte, error) { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - return m.Marshal() - } - p := NewBuffer(nil) - err := p.Marshal(pb) - if p.buf == nil && err == nil { - // Return a non-nil slice on success. - return []byte{}, nil - } - return p.buf, err -} - // EncodeMessage writes the protocol buffer to the Buffer, // prefixed by a varint-encoded length. func (p *Buffer) EncodeMessage(pb Message) error { - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - var state errorState - err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) - } - return err -} - -// Marshal takes the protocol buffer -// and encodes it into the wire format, writing the result to the -// Buffer. -func (p *Buffer) Marshal(pb Message) error { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - data, err := m.Marshal() - p.buf = append(p.buf, data...) - return err - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - err = p.enc_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - (stats).Encode++ // Parens are to work around a goimports bug. - } - - if len(p.buf) > maxMarshalSize { - return ErrTooLarge - } - return err -} - -// Size returns the encoded size of a protocol buffer. -func Size(pb Message) (n int) { - // Can the object marshal itself? If so, Size is slow. - // TODO: add Size to Marshaler, or add a Sizer interface. - if m, ok := pb.(Marshaler); ok { - b, _ := m.Marshal() - return len(b) - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return 0 - } - if err == nil { - n = size_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - (stats).Size++ // Parens are to work around a goimports bug. - } - - return -} - -// Individual type encoders. - -// Encode a bool. -func (o *Buffer) enc_bool(p *Properties, base structPointer) error { - v := *structPointer_Bool(base, p.field) - if v == nil { - return ErrNil - } - x := 0 - if *v { - x = 1 - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { - v := *structPointer_BoolVal(base, p.field) - if !v { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, 1) - return nil -} - -func size_bool(p *Properties, base structPointer) int { - v := *structPointer_Bool(base, p.field) - if v == nil { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -func size_proto3_bool(p *Properties, base structPointer) int { - v := *structPointer_BoolVal(base, p.field) - if !v && !p.oneof { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -// Encode an int32. -func (o *Buffer) enc_int32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode a uint32. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := word32_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := word32_Get(v) - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode an int64. -func (o *Buffer) enc_int64(p *Properties, base structPointer) error { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return ErrNil - } - x := word64_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func size_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return 0 - } - x := word64_Get(v) - n += len(p.tagcode) - n += p.valSize(x) - return -} - -func size_proto3_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(x) - return -} - -// Encode a string. -func (o *Buffer) enc_string(p *Properties, base structPointer) error { - v := *structPointer_String(base, p.field) - if v == nil { - return ErrNil - } - x := *v - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(x) - return nil -} - -func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { - v := *structPointer_StringVal(base, p.field) - if v == "" { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(v) - return nil -} - -func size_string(p *Properties, base structPointer) (n int) { - v := *structPointer_String(base, p.field) - if v == nil { - return 0 - } - x := *v - n += len(p.tagcode) - n += sizeStringBytes(x) - return -} - -func size_proto3_string(p *Properties, base structPointer) (n int) { - v := *structPointer_StringVal(base, p.field) - if v == "" && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeStringBytes(v) - return + siz := Size(pb) + p.EncodeVarint(uint64(siz)) + return p.Marshal(pb) } // All protocol buffer fields are nillable, but be careful. @@ -538,825 +201,3 @@ func isNil(v reflect.Value) bool { } return false } - -// Encode a message struct. -func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { - var state errorState - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return ErrNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - return state.err - } - - o.buf = append(o.buf, p.tagcode...) - return o.enc_len_struct(p.sprop, structp, &state) -} - -func size_struct_message(p *Properties, base structPointer) int { - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return 0 - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n0 := len(p.tagcode) - n1 := sizeRawBytes(data) - return n0 + n1 - } - - n0 := len(p.tagcode) - n1 := size_struct(p.sprop, structp) - n2 := sizeVarint(uint64(n1)) // size of encoded length - return n0 + n1 + n2 -} - -// Encode a group struct. -func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { - var state errorState - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return ErrNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - err := o.enc_struct(p.sprop, b) - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return state.err -} - -func size_struct_group(p *Properties, base structPointer) (n int) { - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return 0 - } - - n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) - n += size_struct(p.sprop, b) - n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return -} - -// Encode a slice of bools ([]bool). -func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - for _, x := range s { - o.buf = append(o.buf, p.tagcode...) - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_bool(p *Properties, base structPointer) int { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - return l * (len(p.tagcode) + 1) // each bool takes exactly one byte -} - -// Encode a slice of bools ([]bool) in packed format. -func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(l)) // each bool takes exactly one byte - for _, x := range s { - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_packed_bool(p *Properties, base structPointer) (n int) { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - n += len(p.tagcode) - n += sizeVarint(uint64(l)) - n += l // each bool takes exactly one byte - return -} - -// Encode a slice of bytes ([]byte). -func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if s == nil { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func size_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if s == nil && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -// Encode a slice of int32s ([]int32). -func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of int32s ([]int32) in packed format. -func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(buf, uint64(x)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - bufSize += p.valSize(uint64(x)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of uint32s ([]uint32). -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := s.Index(i) - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := s.Index(i) - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of uint32s ([]uint32) in packed format. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, uint64(s.Index(i))) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(uint64(s.Index(i))) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of int64s ([]int64). -func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, s.Index(i)) - } - return nil -} - -func size_slice_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - n += p.valSize(s.Index(i)) - } - return -} - -// Encode a slice of int64s ([]int64) in packed format. -func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, s.Index(i)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(s.Index(i)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of slice of bytes ([][]byte). -func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(ss[i]) - } - return nil -} - -func size_slice_slice_byte(p *Properties, base structPointer) (n int) { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return 0 - } - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeRawBytes(ss[i]) - } - return -} - -// Encode a slice of strings ([]string). -func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(ss[i]) - } - return nil -} - -func size_slice_string(p *Properties, base structPointer) (n int) { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeStringBytes(ss[i]) - } - return -} - -// Encode a slice of message structs ([]*struct). -func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return errRepeatedHasNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - continue - } - - o.buf = append(o.buf, p.tagcode...) - err := o.enc_len_struct(p.sprop, structp, &state) - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - } - return state.err -} - -func size_slice_struct_message(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return // return the size up to this point - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n += sizeRawBytes(data) - continue - } - - n0 := size_struct(p.sprop, structp) - n1 := sizeVarint(uint64(n0)) // size of encoded length - n += n0 + n1 - } - return -} - -// Encode a slice of group structs ([]*struct). -func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return errRepeatedHasNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - - err := o.enc_struct(p.sprop, b) - - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - } - return state.err -} - -func size_slice_struct_group(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) - n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return // return size up to this point - } - - n += size_struct(p.sprop, b) - } - return -} - -// Encode an extension map. -func (o *Buffer) enc_map(p *Properties, base structPointer) error { - exts := structPointer_ExtMap(base, p.field) - if err := encodeExtensionsMap(*exts); err != nil { - return err - } - - return o.enc_map_body(*exts) -} - -func (o *Buffer) enc_exts(p *Properties, base structPointer) error { - exts := structPointer_Extensions(base, p.field) - - v, mu := exts.extensionsRead() - if v == nil { - return nil - } - - mu.Lock() - defer mu.Unlock() - if err := encodeExtensionsMap(v); err != nil { - return err - } - - return o.enc_map_body(v) -} - -func (o *Buffer) enc_map_body(v map[int32]Extension) error { - // Fast-path for common cases: zero or one extensions. - if len(v) <= 1 { - for _, e := range v { - o.buf = append(o.buf, e.enc...) - } - return nil - } - - // Sort keys to provide a deterministic encoding. - keys := make([]int, 0, len(v)) - for k := range v { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, k := range keys { - o.buf = append(o.buf, v[int32(k)].enc...) - } - return nil -} - -func size_map(p *Properties, base structPointer) int { - v := structPointer_ExtMap(base, p.field) - return extensionsMapSize(*v) -} - -func size_exts(p *Properties, base structPointer) int { - v := structPointer_Extensions(base, p.field) - return extensionsSize(v) -} - -// Encode a map field. -func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { - var state errorState // XXX: or do we need to plumb this through? - - /* - A map defined as - map map_field = N; - is encoded in the same way as - message MapFieldEntry { - key_type key = 1; - value_type value = 2; - } - repeated MapFieldEntry map_field = N; - */ - - v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V - if v.Len() == 0 { - return nil - } - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - enc := func() error { - if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { - return err - } - if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { - return err - } - return nil - } - - // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - - keycopy.Set(key) - valcopy.Set(val) - - o.buf = append(o.buf, p.tagcode...) - if err := o.enc_len_thing(enc, &state); err != nil { - return err - } - } - return nil -} - -func size_new_map(p *Properties, base structPointer) int { - v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - n := 0 - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - keycopy.Set(key) - valcopy.Set(val) - - // Tag codes for key and val are the responsibility of the sub-sizer. - keysize := p.mkeyprop.size(p.mkeyprop, keybase) - valsize := p.mvalprop.size(p.mvalprop, valbase) - entry := keysize + valsize - // Add on tag code and length of map entry itself. - n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry - } - return n -} - -// mapEncodeScratch returns a new reflect.Value matching the map's value type, -// and a structPointer suitable for passing to an encoder or sizer. -func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { - // Prepare addressable doubly-indirect placeholders for the key and value types. - // This is needed because the element-type encoders expect **T, but the map iteration produces T. - - keycopy = reflect.New(mapType.Key()).Elem() // addressable K - keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K - keyptr.Set(keycopy.Addr()) // - keybase = toStructPointer(keyptr.Addr()) // **K - - // Value types are more varied and require special handling. - switch mapType.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte - valbase = toStructPointer(valcopy.Addr()) - case reflect.Ptr: - // message; the generated field type is map[K]*Msg (so V is *Msg), - // so we only need one level of indirection. - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valbase = toStructPointer(valcopy.Addr()) - default: - // everything else - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V - valptr.Set(valcopy.Addr()) // - valbase = toStructPointer(valptr.Addr()) // **V - } - return -} - -// Encode a struct. -func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { - var state errorState - // Encode fields in tag order so that decoders may use optimizations - // that depend on the ordering. - // https://developers.google.com/protocol-buffers/docs/encoding#order - for _, i := range prop.order { - p := prop.Prop[i] - if p.enc != nil { - err := p.enc(o, p, base) - if err != nil { - if err == ErrNil { - if p.Required && state.err == nil { - state.err = &RequiredNotSetError{p.Name} - } - } else if err == errRepeatedHasNil { - // Give more context to nil values in repeated fields. - return errors.New("repeated field " + p.OrigName + " has nil element") - } else if !state.shouldContinue(err, p) { - return err - } - } - if len(o.buf) > maxMarshalSize { - return ErrTooLarge - } - } - } - - // Do oneof fields. - if prop.oneofMarshaler != nil { - m := structPointer_Interface(base, prop.stype).(Message) - if err := prop.oneofMarshaler(m, o); err == ErrNil { - return errOneofHasNil - } else if err != nil { - return err - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - if len(o.buf)+len(v) > maxMarshalSize { - return ErrTooLarge - } - if len(v) > 0 { - o.buf = append(o.buf, v...) - } - } - - return state.err -} - -func size_struct(prop *StructProperties, base structPointer) (n int) { - for _, i := range prop.order { - p := prop.Prop[i] - if p.size != nil { - n += p.size(p, base) - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - n += len(v) - } - - // Factor in any oneof fields. - if prop.oneofSizer != nil { - m := structPointer_Interface(base, prop.stype).(Message) - n += prop.oneofSizer(m) - } - - return -} - -var zeroes [20]byte // longer than any conceivable sizeVarint - -// Encode a struct, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { - return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) -} - -// Encode something, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { - iLen := len(o.buf) - o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length - iMsg := len(o.buf) - err := enc() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - lMsg := len(o.buf) - iMsg - lLen := sizeVarint(uint64(lMsg)) - switch x := lLen - (iMsg - iLen); { - case x > 0: // actual length is x bytes larger than the space we reserved - // Move msg x bytes right. - o.buf = append(o.buf, zeroes[:x]...) - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - case x < 0: // actual length is x bytes smaller than the space we reserved - // Move msg x bytes left. - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - o.buf = o.buf[:len(o.buf)+x] // x is negative - } - // Encode the length in the reserved space. - o.buf = o.buf[:iLen] - o.EncodeVarint(uint64(lMsg)) - o.buf = o.buf[:len(o.buf)+lMsg] - return state.err -} - -// errorState maintains the first error that occurs and updates that error -// with additional context. -type errorState struct { - err error -} - -// shouldContinue reports whether encoding should continue upon encountering the -// given error. If the error is RequiredNotSetError, shouldContinue returns true -// and, if this is the first appearance of that error, remembers it for future -// reporting. -// -// If prop is not nil, it may update any error with additional context about the -// field with the error. -func (s *errorState) shouldContinue(err error, prop *Properties) bool { - // Ignore unset required fields. - reqNotSet, ok := err.(*RequiredNotSetError) - if !ok { - return false - } - if s.err == nil { - if prop != nil { - err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} - } - s.err = err - } - return true -} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go index 2ed1cf59..d4db5a1c 100644 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -109,15 +109,6 @@ func equalStruct(v1, v2 reflect.Value) bool { // set/unset mismatch return false } - b1, ok := f1.Interface().(raw) - if ok { - b2 := f2.Interface().(raw) - // RawMessage - if !bytes.Equal(b1.Bytes(), b2.Bytes()) { - return false - } - continue - } f1, f2 = f1.Elem(), f2.Elem() } if !equalAny(f1, f2, sprop.Prop[i]) { @@ -146,11 +137,7 @@ func equalStruct(v1, v2 reflect.Value) bool { u1 := uf.Bytes() u2 := v2.FieldByName("XXX_unrecognized").Bytes() - if !bytes.Equal(u1, u2) { - return false - } - - return true + return bytes.Equal(u1, u2) } // v1 and v2 are known to have the same type. @@ -261,6 +248,15 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { m1, m2 := e1.value, e2.value + if m1 == nil && m2 == nil { + // Both have only encoded form. + if bytes.Equal(e1.enc, e2.enc) { + continue + } + // The bytes are different, but the extensions might still be + // equal. We need to decode them to compare. + } + if m1 != nil && m2 != nil { // Both are unencoded. if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { @@ -276,8 +272,12 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { desc = m[extNum] } if desc == nil { + // If both have only encoded form and the bytes are the same, + // it is handled above. We get here when the bytes are different. + // We don't know how to decode it, so just compare them as byte + // slices. log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) - continue + return false } var err error if m1 == nil { diff --git a/vendor/github.com/golang/protobuf/proto/equal_test.go b/vendor/github.com/golang/protobuf/proto/equal_test.go index a2febb39..93ff88f3 100644 --- a/vendor/github.com/golang/protobuf/proto/equal_test.go +++ b/vendor/github.com/golang/protobuf/proto/equal_test.go @@ -36,7 +36,7 @@ import ( . "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" + pb "github.com/golang/protobuf/proto/test_proto" ) // Four identical base messages. @@ -45,6 +45,9 @@ var messageWithoutExtension = &pb.MyMessage{Count: Int32(7)} var messageWithExtension1a = &pb.MyMessage{Count: Int32(7)} var messageWithExtension1b = &pb.MyMessage{Count: Int32(7)} var messageWithExtension2 = &pb.MyMessage{Count: Int32(7)} +var messageWithExtension3a = &pb.MyMessage{Count: Int32(7)} +var messageWithExtension3b = &pb.MyMessage{Count: Int32(7)} +var messageWithExtension3c = &pb.MyMessage{Count: Int32(7)} // Two messages with non-message extensions. var messageWithInt32Extension1 = &pb.MyMessage{Count: Int32(8)} @@ -83,6 +86,20 @@ func init() { if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(24)); err != nil { panic("SetExtension on Int32-2 failed: " + err.Error()) } + + // messageWithExtension3{a,b,c} has unregistered extension. + if RegisteredExtensions(messageWithExtension3a)[200] != nil { + panic("expect extension 200 unregistered") + } + bytes := []byte{ + 0xc0, 0x0c, 0x01, // id=200, wiretype=0 (varint), data=1 + } + bytes2 := []byte{ + 0xc0, 0x0c, 0x02, // id=200, wiretype=0 (varint), data=2 + } + SetRawExtension(messageWithExtension3a, 200, bytes) + SetRawExtension(messageWithExtension3b, 200, bytes) + SetRawExtension(messageWithExtension3c, 200, bytes2) } var EqualTests = []struct { @@ -142,6 +159,9 @@ var EqualTests = []struct { {"int32 extension vs. itself", messageWithInt32Extension1, messageWithInt32Extension1, true}, {"int32 extension vs. a different int32", messageWithInt32Extension1, messageWithInt32Extension2, false}, + {"unregistered extension same", messageWithExtension3a, messageWithExtension3b, true}, + {"unregistered extension different", messageWithExtension3a, messageWithExtension3c, false}, + { "message with group", &pb.MyMessage{ diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go index eaad2183..816a3b9d 100644 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -38,6 +38,7 @@ package proto import ( "errors" "fmt" + "io" "reflect" "strconv" "sync" @@ -91,14 +92,29 @@ func (n notLocker) Unlock() {} // extendable returns the extendableProto interface for the given generated proto message. // If the proto message has the old extension format, it returns a wrapper that implements // the extendableProto interface. -func extendable(p interface{}) (extendableProto, bool) { - if ep, ok := p.(extendableProto); ok { - return ep, ok +func extendable(p interface{}) (extendableProto, error) { + switch p := p.(type) { + case extendableProto: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return p, nil + case extendableProtoV1: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return extensionAdapter{p}, nil } - if ep, ok := p.(extendableProtoV1); ok { - return extensionAdapter{ep}, ok - } - return nil, false + // Don't allocate a specific error containing %T: + // this is the hot path for Clone and MarshalText. + return nil, errNotExtendable +} + +var errNotExtendable = errors.New("proto: not an extendable proto.Message") + +func isNilPtr(x interface{}) bool { + v := reflect.ValueOf(x) + return v.Kind() == reflect.Ptr && v.IsNil() } // XXX_InternalExtensions is an internal representation of proto extensions. @@ -143,9 +159,6 @@ func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Loc return e.p.extensionMap, &e.p.mu } -var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() -var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() - // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. type ExtensionDesc struct { @@ -179,8 +192,8 @@ type Extension struct { // SetRawExtension is for testing only. func SetRawExtension(base Message, id int32, b []byte) { - epb, ok := extendable(base) - if !ok { + epb, err := extendable(base) + if err != nil { return } extmap := epb.extensionsWrite() @@ -205,7 +218,7 @@ func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { pbi = ea.extendableProtoV1 } if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { - return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) } // Check the range. if !isExtensionField(pb, extension.Field) { @@ -250,85 +263,11 @@ func extensionProperties(ed *ExtensionDesc) *Properties { return prop } -// encode encodes any unmarshaled (unencoded) extensions in e. -func encodeExtensions(e *XXX_InternalExtensions) error { - m, mu := e.extensionsRead() - if m == nil { - return nil // fast path - } - mu.Lock() - defer mu.Unlock() - return encodeExtensionsMap(m) -} - -// encode encodes any unmarshaled (unencoded) extensions in e. -func encodeExtensionsMap(m map[int32]Extension) error { - for k, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - p := NewBuffer(nil) - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - if err := props.enc(p, props, toStructPointer(x)); err != nil { - return err - } - e.enc = p.buf - m[k] = e - } - return nil -} - -func extensionsSize(e *XXX_InternalExtensions) (n int) { - m, mu := e.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - defer mu.Unlock() - return extensionsMapSize(m) -} - -func extensionsMapSize(m map[int32]Extension) (n int) { - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - n += props.size(props, toStructPointer(x)) - } - return -} - // HasExtension returns whether the given extension is present in pb. func HasExtension(pb Message, extension *ExtensionDesc) bool { // TODO: Check types, field numbers, etc.? - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return false } extmap, mu := epb.extensionsRead() @@ -336,15 +275,15 @@ func HasExtension(pb Message, extension *ExtensionDesc) bool { return false } mu.Lock() - _, ok = extmap[extension.Field] + _, ok := extmap[extension.Field] mu.Unlock() return ok } // ClearExtension removes the given extension from pb. func ClearExtension(pb Message, extension *ExtensionDesc) { - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return } // TODO: Check types, field numbers, etc.? @@ -352,16 +291,26 @@ func ClearExtension(pb Message, extension *ExtensionDesc) { delete(extmap, extension.Field) } -// GetExtension parses and returns the given extension of pb. -// If the extension is not present and has no default value it returns ErrMissingExtension. +// GetExtension retrieves a proto2 extended field from pb. +// +// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), +// then GetExtension parses the encoded field and returns a Go value of the specified type. +// If the field is not present, then the default value is returned (if one is specified), +// otherwise ErrMissingExtension is reported. +// +// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), +// then GetExtension returns the raw encoded bytes of the field extension. func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { - epb, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return nil, err } - if err := checkExtensionTypes(epb, extension); err != nil { - return nil, err + if extension.ExtendedType != nil { + // can only check type if this is a complete descriptor + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } } emap, mu := epb.extensionsRead() @@ -388,6 +337,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { return e.value, nil } + if extension.ExtensionType == nil { + // incomplete descriptor + return e.enc, nil + } + v, err := decodeExtension(e.enc, extension) if err != nil { return nil, err @@ -405,6 +359,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { // defaultExtensionValue returns the default value for extension. // If no default for an extension is defined ErrMissingExtension is returned. func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + if extension.ExtensionType == nil { + // incomplete descriptor, so no default + return nil, ErrMissingExtension + } + t := reflect.TypeOf(extension.ExtensionType) props := extensionProperties(extension) @@ -439,31 +398,28 @@ func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { // decodeExtension decodes an extension encoded in b. func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { - o := NewBuffer(b) - t := reflect.TypeOf(extension.ExtensionType) - - props := extensionProperties(extension) + unmarshal := typeUnmarshaler(t, extension.Tag) // t is a pointer to a struct, pointer to basic type or a slice. - // Allocate a "field" to store the pointer/slice itself; the - // pointer/slice will be stored here. We pass - // the address of this field to props.dec. - // This passes a zero field and a *t and lets props.dec - // interpret it as a *struct{ x t }. + // Allocate space to store the pointer/slice. value := reflect.New(t).Elem() + var err error for { - // Discard wire type and field number varint. It isn't needed. - if _, err := o.DecodeVarint(); err != nil { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + wire := int(x) & 7 + + b, err = unmarshal(b, valToPointer(value.Addr()), wire) + if err != nil { return nil, err } - if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { - return nil, err - } - - if o.index >= len(o.buf) { + if len(b) == 0 { break } } @@ -473,9 +429,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return nil, err } extensions = make([]interface{}, len(es)) for i, e := range es { @@ -494,9 +450,9 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e // For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing // just the Field field, which defines the extension's field number. func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { - epb, ok := extendable(pb) - if !ok { - return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + epb, err := extendable(pb) + if err != nil { + return nil, err } registeredExtensions := RegisteredExtensions(pb) @@ -523,9 +479,9 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { // SetExtension sets the specified extension of pb to the specified value. func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { - epb, ok := extendable(pb) - if !ok { - return errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return err } if err := checkExtensionTypes(epb, extension); err != nil { return err @@ -550,8 +506,8 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error // ClearAllExtensions clears all extensions from pb. func ClearAllExtensions(pb Message) { - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return } m := epb.extensionsWrite() diff --git a/vendor/github.com/golang/protobuf/proto/extensions_test.go b/vendor/github.com/golang/protobuf/proto/extensions_test.go index b6d9114c..dc69fe97 100644 --- a/vendor/github.com/golang/protobuf/proto/extensions_test.go +++ b/vendor/github.com/golang/protobuf/proto/extensions_test.go @@ -34,12 +34,14 @@ package proto_test import ( "bytes" "fmt" + "io" "reflect" "sort" + "strings" "testing" "github.com/golang/protobuf/proto" - pb "github.com/golang/protobuf/proto/testdata" + pb "github.com/golang/protobuf/proto/test_proto" "golang.org/x/sync/errgroup" ) @@ -64,7 +66,107 @@ func TestGetExtensionsWithMissingExtensions(t *testing.T) { } } -func TestExtensionDescsWithMissingExtensions(t *testing.T) { +func TestGetExtensionWithEmptyBuffer(t *testing.T) { + // Make sure that GetExtension returns an error if its + // undecoded buffer is empty. + msg := &pb.MyMessage{} + proto.SetRawExtension(msg, pb.E_Ext_More.Field, []byte{}) + _, err := proto.GetExtension(msg, pb.E_Ext_More) + if want := io.ErrUnexpectedEOF; err != want { + t.Errorf("unexpected error in GetExtension from empty buffer: got %v, want %v", err, want) + } +} + +func TestGetExtensionForIncompleteDesc(t *testing.T) { + msg := &pb.MyMessage{Count: proto.Int32(0)} + extdesc1 := &proto.ExtensionDesc{ + ExtendedType: (*pb.MyMessage)(nil), + ExtensionType: (*bool)(nil), + Field: 123456789, + Name: "a.b", + Tag: "varint,123456789,opt", + } + ext1 := proto.Bool(true) + if err := proto.SetExtension(msg, extdesc1, ext1); err != nil { + t.Fatalf("Could not set ext1: %s", err) + } + extdesc2 := &proto.ExtensionDesc{ + ExtendedType: (*pb.MyMessage)(nil), + ExtensionType: ([]byte)(nil), + Field: 123456790, + Name: "a.c", + Tag: "bytes,123456790,opt", + } + ext2 := []byte{0, 1, 2, 3, 4, 5, 6, 7} + if err := proto.SetExtension(msg, extdesc2, ext2); err != nil { + t.Fatalf("Could not set ext2: %s", err) + } + extdesc3 := &proto.ExtensionDesc{ + ExtendedType: (*pb.MyMessage)(nil), + ExtensionType: (*pb.Ext)(nil), + Field: 123456791, + Name: "a.d", + Tag: "bytes,123456791,opt", + } + ext3 := &pb.Ext{Data: proto.String("foo")} + if err := proto.SetExtension(msg, extdesc3, ext3); err != nil { + t.Fatalf("Could not set ext3: %s", err) + } + + b, err := proto.Marshal(msg) + if err != nil { + t.Fatalf("Could not marshal msg: %v", err) + } + if err := proto.Unmarshal(b, msg); err != nil { + t.Fatalf("Could not unmarshal into msg: %v", err) + } + + var expected proto.Buffer + if err := expected.EncodeVarint(uint64((extdesc1.Field << 3) | proto.WireVarint)); err != nil { + t.Fatalf("failed to compute expected prefix for ext1: %s", err) + } + if err := expected.EncodeVarint(1 /* bool true */); err != nil { + t.Fatalf("failed to compute expected value for ext1: %s", err) + } + + if b, err := proto.GetExtension(msg, &proto.ExtensionDesc{Field: extdesc1.Field}); err != nil { + t.Fatalf("Failed to get raw value for ext1: %s", err) + } else if !reflect.DeepEqual(b, expected.Bytes()) { + t.Fatalf("Raw value for ext1: got %v, want %v", b, expected.Bytes()) + } + + expected = proto.Buffer{} // reset + if err := expected.EncodeVarint(uint64((extdesc2.Field << 3) | proto.WireBytes)); err != nil { + t.Fatalf("failed to compute expected prefix for ext2: %s", err) + } + if err := expected.EncodeRawBytes(ext2); err != nil { + t.Fatalf("failed to compute expected value for ext2: %s", err) + } + + if b, err := proto.GetExtension(msg, &proto.ExtensionDesc{Field: extdesc2.Field}); err != nil { + t.Fatalf("Failed to get raw value for ext2: %s", err) + } else if !reflect.DeepEqual(b, expected.Bytes()) { + t.Fatalf("Raw value for ext2: got %v, want %v", b, expected.Bytes()) + } + + expected = proto.Buffer{} // reset + if err := expected.EncodeVarint(uint64((extdesc3.Field << 3) | proto.WireBytes)); err != nil { + t.Fatalf("failed to compute expected prefix for ext3: %s", err) + } + if b, err := proto.Marshal(ext3); err != nil { + t.Fatalf("failed to compute expected value for ext3: %s", err) + } else if err := expected.EncodeRawBytes(b); err != nil { + t.Fatalf("failed to compute expected value for ext3: %s", err) + } + + if b, err := proto.GetExtension(msg, &proto.ExtensionDesc{Field: extdesc3.Field}); err != nil { + t.Fatalf("Failed to get raw value for ext3: %s", err) + } else if !reflect.DeepEqual(b, expected.Bytes()) { + t.Fatalf("Raw value for ext3: got %v, want %v", b, expected.Bytes()) + } +} + +func TestExtensionDescsWithUnregisteredExtensions(t *testing.T) { msg := &pb.MyMessage{Count: proto.Int32(0)} extdesc1 := pb.E_Ext_More if descs, err := proto.ExtensionDescs(msg); len(descs) != 0 || err != nil { @@ -100,7 +202,7 @@ func TestExtensionDescsWithMissingExtensions(t *testing.T) { t.Fatalf("proto.ExtensionDescs: got error %v", err) } sortExtDescs(descs) - wantDescs := []*proto.ExtensionDesc{extdesc1, &proto.ExtensionDesc{Field: extdesc2.Field}} + wantDescs := []*proto.ExtensionDesc{extdesc1, {Field: extdesc2.Field}} if !reflect.DeepEqual(descs, wantDescs) { t.Errorf("proto.ExtensionDescs(msg) sorted extension ids: got %+v, want %+v", descs, wantDescs) } @@ -200,7 +302,7 @@ func TestGetExtensionDefaults(t *testing.T) { {pb.E_DefaultSfixed64, setInt64, int64(51)}, {pb.E_DefaultBool, setBool, true}, {pb.E_DefaultBool, setBool2, true}, - {pb.E_DefaultString, setString, "Hello, string"}, + {pb.E_DefaultString, setString, "Hello, string,def=foo"}, {pb.E_DefaultBytes, setBytes, []byte("Hello, bytes")}, {pb.E_DefaultEnum, setEnum, pb.DefaultsMessage_ONE}, } @@ -287,6 +389,44 @@ func TestGetExtensionDefaults(t *testing.T) { } } +func TestNilMessage(t *testing.T) { + name := "nil interface" + if got, err := proto.GetExtension(nil, pb.E_Ext_More); err == nil { + t.Errorf("%s: got %T %v, expected to fail", name, got, got) + } else if !strings.Contains(err.Error(), "extendable") { + t.Errorf("%s: got error %v, expected not-extendable error", name, err) + } + + // Regression tests: all functions of the Extension API + // used to panic when passed (*M)(nil), where M is a concrete message + // type. Now they handle this gracefully as a no-op or reported error. + var nilMsg *pb.MyMessage + desc := pb.E_Ext_More + + isNotExtendable := func(err error) bool { + return strings.Contains(fmt.Sprint(err), "not extendable") + } + + if proto.HasExtension(nilMsg, desc) { + t.Error("HasExtension(nil) = true") + } + + if _, err := proto.GetExtensions(nilMsg, []*proto.ExtensionDesc{desc}); !isNotExtendable(err) { + t.Errorf("GetExtensions(nil) = %q (wrong error)", err) + } + + if _, err := proto.ExtensionDescs(nilMsg); !isNotExtendable(err) { + t.Errorf("ExtensionDescs(nil) = %q (wrong error)", err) + } + + if err := proto.SetExtension(nilMsg, desc, nil); !isNotExtendable(err) { + t.Errorf("SetExtension(nil) = %q (wrong error)", err) + } + + proto.ClearExtension(nilMsg, desc) // no-op + proto.ClearAllExtensions(nilMsg) // no-op +} + func TestExtensionsRoundTrip(t *testing.T) { msg := &pb.MyMessage{} ext1 := &pb.Ext{ @@ -311,7 +451,7 @@ func TestExtensionsRoundTrip(t *testing.T) { } x, ok := e.(*pb.Ext) if !ok { - t.Errorf("e has type %T, expected testdata.Ext", e) + t.Errorf("e has type %T, expected test_proto.Ext", e) } else if *x.Data != "there" { t.Errorf("SetExtension failed to overwrite, got %+v, not 'there'", x) } @@ -339,7 +479,7 @@ func TestNilExtension(t *testing.T) { } if err := proto.SetExtension(msg, pb.E_Ext_More, (*pb.Ext)(nil)); err == nil { t.Error("expected SetExtension to fail due to a nil extension") - } else if want := "proto: SetExtension called with nil value of type *testdata.Ext"; err.Error() != want { + } else if want := fmt.Sprintf("proto: SetExtension called with nil value of type %T", new(pb.Ext)); err.Error() != want { t.Errorf("expected error %v, got %v", want, err) } // Note: if the behavior of Marshal is ever changed to ignore nil extensions, update @@ -402,8 +542,13 @@ func TestMarshalUnmarshalRepeatedExtension(t *testing.T) { if ext == nil { t.Fatalf("[%s] Invalid extension", test.name) } - if !reflect.DeepEqual(ext, test.ext) { - t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, test.ext) + if len(ext) != len(test.ext) { + t.Errorf("[%s] Wrong length of ComplexExtension: got: %v want: %v\n", test.name, len(ext), len(test.ext)) + } + for i := range test.ext { + if !proto.Equal(ext[i], test.ext[i]) { + t.Errorf("[%s] Wrong value for ComplexExtension[%d]: got: %v want: %v\n", test.name, i, ext[i], test.ext[i]) + } } } } @@ -477,8 +622,8 @@ func TestUnmarshalRepeatingNonRepeatedExtension(t *testing.T) { if ext == nil { t.Fatalf("[%s] Invalid extension", test.name) } - if !reflect.DeepEqual(*ext, want) { - t.Errorf("[%s] Wrong value for ComplexExtension: got: %s want: %s\n", test.name, ext, want) + if !proto.Equal(ext, &want) { + t.Errorf("[%s] Wrong value for ComplexExtension: got: %s want: %s\n", test.name, ext, &want) } } } @@ -509,19 +654,22 @@ func TestClearAllExtensions(t *testing.T) { } func TestMarshalRace(t *testing.T) { - // unregistered extension - desc := &proto.ExtensionDesc{ - ExtendedType: (*pb.MyMessage)(nil), - ExtensionType: (*bool)(nil), - Field: 101010100, - Name: "emptyextension", - Tag: "varint,0,opt", + ext := &pb.Ext{} + m := &pb.MyMessage{Count: proto.Int32(4)} + if err := proto.SetExtension(m, pb.E_Ext_More, ext); err != nil { + t.Fatalf("proto.SetExtension(m, desc, true): got error %q, want nil", err) } - m := &pb.MyMessage{Count: proto.Int32(4)} - if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { - t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) + b, err := proto.Marshal(m) + if err != nil { + t.Fatalf("Could not marshal message: %v", err) } + if err := proto.Unmarshal(b, m); err != nil { + t.Fatalf("Could not unmarshal message: %v", err) + } + // after Unmarshal, the extension is in undecoded form. + // GetExtension will decode it lazily. Make sure this does + // not race against Marshal. var g errgroup.Group for n := 3; n > 0; n-- { @@ -529,6 +677,10 @@ func TestMarshalRace(t *testing.T) { _, err := proto.Marshal(m) return err }) + g.Go(func() error { + _, err := proto.GetExtension(m, pb.E_Ext_More) + return err + }) } if err := g.Wait(); err != nil { t.Fatal(err) diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go index 1c225504..75565cc6 100644 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -273,6 +273,67 @@ import ( "sync" ) +// RequiredNotSetError is an error type returned by either Marshal or Unmarshal. +// Marshal reports this when a required field is not initialized. +// Unmarshal reports this when a required field is missing from the wire data. +type RequiredNotSetError struct{ field string } + +func (e *RequiredNotSetError) Error() string { + if e.field == "" { + return fmt.Sprintf("proto: required field not set") + } + return fmt.Sprintf("proto: required field %q not set", e.field) +} +func (e *RequiredNotSetError) RequiredNotSet() bool { + return true +} + +type invalidUTF8Error struct{ field string } + +func (e *invalidUTF8Error) Error() string { + if e.field == "" { + return "proto: invalid UTF-8 detected" + } + return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) +} +func (e *invalidUTF8Error) InvalidUTF8() bool { + return true +} + +// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. +// This error should not be exposed to the external API as such errors should +// be recreated with the field information. +var errInvalidUTF8 = &invalidUTF8Error{} + +// isNonFatal reports whether the error is either a RequiredNotSet error +// or a InvalidUTF8 error. +func isNonFatal(err error) bool { + if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { + return true + } + if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { + return true + } + return false +} + +type nonFatal struct{ E error } + +// Merge merges err into nf and reports whether it was successful. +// Otherwise it returns false for any fatal non-nil errors. +func (nf *nonFatal) Merge(err error) (ok bool) { + if err == nil { + return true // not an error + } + if !isNonFatal(err) { + return false // fatal error + } + if nf.E == nil { + nf.E = err // store first instance of non-fatal error + } + return true +} + // Message is implemented by generated protocol buffer messages. type Message interface { Reset() @@ -309,16 +370,7 @@ type Buffer struct { buf []byte // encode/decode byte stream index int // read point - // pools of basic types to amortize allocation. - bools []bool - uint32s []uint32 - uint64s []uint64 - - // extra pools, only used with pointer_reflect.go - int32s []int32 - int64s []int64 - float32s []float32 - float64s []float64 + deterministic bool } // NewBuffer allocates a new Buffer and initializes its internal data to @@ -343,6 +395,30 @@ func (p *Buffer) SetBuf(s []byte) { // Bytes returns the contents of the Buffer. func (p *Buffer) Bytes() []byte { return p.buf } +// SetDeterministic sets whether to use deterministic serialization. +// +// Deterministic serialization guarantees that for a given binary, equal +// messages will always be serialized to the same bytes. This implies: +// +// - Repeated serialization of a message will return the same bytes. +// - Different processes of the same binary (which may be executing on +// different machines) will serialize equal messages to the same bytes. +// +// Note that the deterministic serialization is NOT canonical across +// languages. It is not guaranteed to remain stable over time. It is unstable +// across different builds with schema changes due to unknown fields. +// Users who need canonical serialization (e.g., persistent storage in a +// canonical form, fingerprinting, etc.) should define their own +// canonicalization specification and implement their own serializer rather +// than relying on this API. +// +// If deterministic serialization is requested, map entries will be sorted +// by keys in lexographical order. This is an implementation detail and +// subject to change. +func (p *Buffer) SetDeterministic(deterministic bool) { + p.deterministic = deterministic +} + /* * Helper routines for simplifying the creation of optional fields of basic type. */ @@ -831,22 +907,12 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes return sf, false, nil } +// mapKeys returns a sort.Interface to be used for sorting the map keys. // Map fields may have key types of non-float scalars, strings and enums. -// The easiest way to sort them in some deterministic order is to use fmt. -// If this turns out to be inefficient we can always consider other options, -// such as doing a Schwartzian transform. - func mapKeys(vs []reflect.Value) sort.Interface { - s := mapKeySorter{ - vs: vs, - // default Less function: textual comparison - less: func(a, b reflect.Value) bool { - return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) - }, - } + s := mapKeySorter{vs: vs} - // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; - // numeric keys are sorted numerically. + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. if len(vs) == 0 { return s } @@ -855,6 +921,12 @@ func mapKeys(vs []reflect.Value) sort.Interface { s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } case reflect.Uint32, reflect.Uint64: s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + case reflect.Bool: + s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true + case reflect.String: + s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } + default: + panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) } return s @@ -895,3 +967,13 @@ const ProtoPackageIsVersion2 = true // ProtoPackageIsVersion1 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. const ProtoPackageIsVersion1 = true + +// InternalMessageInfo is a type used internally by generated .pb.go files. +// This type is not intended to be used by non-generated code. +// This type is not subject to any compatibility guarantee. +type InternalMessageInfo struct { + marshal *marshalInfo + unmarshal *unmarshalInfo + merge *mergeInfo + discard *discardInfo +} diff --git a/vendor/github.com/golang/protobuf/proto/map_test.go b/vendor/github.com/golang/protobuf/proto/map_test.go index 313e8792..b1e1529e 100644 --- a/vendor/github.com/golang/protobuf/proto/map_test.go +++ b/vendor/github.com/golang/protobuf/proto/map_test.go @@ -2,12 +2,36 @@ package proto_test import ( "fmt" + "reflect" "testing" "github.com/golang/protobuf/proto" ppb "github.com/golang/protobuf/proto/proto3_proto" ) +func TestMap(t *testing.T) { + var b []byte + fmt.Sscanf("a2010c0a044b657931120456616c31a201130a044b657932120556616c3261120456616c32a201240a044b6579330d05000000120556616c33621a0556616c3361120456616c331505000000a20100a201260a044b657934130a07536f6d6555524c1209536f6d655469746c651a08536e69707065743114", "%x", &b) + + var m ppb.Message + if err := proto.Unmarshal(b, &m); err != nil { + t.Fatalf("proto.Unmarshal error: %v", err) + } + + got := m.StringMap + want := map[string]string{ + "": "", + "Key1": "Val1", + "Key2": "Val2", + "Key3": "Val3", + "Key4": "", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("maps differ:\ngot %#v\nwant %#v", got, want) + } +} + func marshalled() []byte { m := &ppb.IntMaps{} for i := 0; i < 1000; i++ { diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go index fd982dec..3b6ca41d 100644 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -42,6 +42,7 @@ import ( "fmt" "reflect" "sort" + "sync" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. @@ -94,10 +95,7 @@ func (ms *messageSet) find(pb Message) *_MessageSet_Item { } func (ms *messageSet) Has(pb Message) bool { - if ms.find(pb) != nil { - return true - } - return false + return ms.find(pb) != nil } func (ms *messageSet) Unmarshal(pb Message) error { @@ -150,46 +148,42 @@ func skipVarint(buf []byte) []byte { // MarshalMessageSet encodes the extension map represented by m in the message set wire format. // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. func MarshalMessageSet(exts interface{}) ([]byte, error) { - var m map[int32]Extension + return marshalMessageSet(exts, false) +} + +// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal. +func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) { switch exts := exts.(type) { case *XXX_InternalExtensions: - if err := encodeExtensions(exts); err != nil { - return nil, err - } - m, _ = exts.extensionsRead() + var u marshalInfo + siz := u.sizeMessageSet(exts) + b := make([]byte, 0, siz) + return u.appendMessageSet(b, exts, deterministic) + case map[int32]Extension: - if err := encodeExtensionsMap(exts); err != nil { - return nil, err + // This is an old-style extension map. + // Wrap it in a new-style XXX_InternalExtensions. + ie := XXX_InternalExtensions{ + p: &struct { + mu sync.Mutex + extensionMap map[int32]Extension + }{ + extensionMap: exts, + }, } - m = exts + + var u marshalInfo + siz := u.sizeMessageSet(&ie) + b := make([]byte, 0, siz) + return u.appendMessageSet(b, &ie, deterministic) + default: return nil, errors.New("proto: not an extension map") } - - // Sort extension IDs to provide a deterministic encoding. - // See also enc_map in encode.go. - ids := make([]int, 0, len(m)) - for id := range m { - ids = append(ids, int(id)) - } - sort.Ints(ids) - - ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} - for _, id := range ids { - e := m[int32(id)] - // Remove the wire type and field number varint, as well as the length varint. - msg := skipVarint(skipVarint(e.enc)) - - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: Int32(int32(id)), - Message: msg, - }) - } - return Marshal(ms) } // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. -// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. func UnmarshalMessageSet(buf []byte, exts interface{}) error { var m map[int32]Extension switch exts := exts.(type) { @@ -235,7 +229,15 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: - m, _ = exts.extensionsRead() + var mu sync.Locker + m, mu = exts.extensionsRead() + if m != nil { + // Keep the extensions map locked until we're done marshaling to prevent + // races between marshaling and unmarshaling the lazily-{en,de}coded + // values. + mu.Lock() + defer mu.Unlock() + } case map[int32]Extension: m = exts default: @@ -253,15 +255,16 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { for i, id := range ids { ext := m[id] - if i > 0 { - b.WriteByte(',') - } - msd, ok := messageSetMap[id] if !ok { // Unknown type; we can't render it, so skip it. continue } + + if i > 0 && b.Len() > 1 { + b.WriteByte(',') + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) x := ext.value diff --git a/vendor/github.com/golang/protobuf/proto/message_set_test.go b/vendor/github.com/golang/protobuf/proto/message_set_test.go index 353a3ea7..2c170c5f 100644 --- a/vendor/github.com/golang/protobuf/proto/message_set_test.go +++ b/vendor/github.com/golang/protobuf/proto/message_set_test.go @@ -64,3 +64,14 @@ func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { t.Errorf("Combined extension is %q, want %q", got, want) } } + +func TestMarshalMessageSetJSON_UnknownType(t *testing.T) { + extMap := map[int32]Extension{12345: Extension{}} + got, err := MarshalMessageSetJSON(extMap) + if err != nil { + t.Fatalf("MarshalMessageSetJSON: %v", err) + } + if want := []byte("{}"); !bytes.Equal(got, want) { + t.Errorf("MarshalMessageSetJSON(%v) = %q, want %q", extMap, got, want) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go index fb512e2e..b6cad908 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build appengine js +// +build purego appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can @@ -38,32 +38,13 @@ package proto import ( - "math" "reflect" + "sync" ) -// A structPointer is a pointer to a struct. -type structPointer struct { - v reflect.Value -} +const unsafeAllowed = false -// toStructPointer returns a structPointer equivalent to the given reflect value. -// The reflect value must itself be a pointer to a struct. -func toStructPointer(v reflect.Value) structPointer { - return structPointer{v} -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p.v.IsNil() -} - -// Interface returns the struct pointer as an interface value. -func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { - return p.v.Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. +// A field identifies a field in a struct, accessible from a pointer. // In this implementation, a field is identified by the sequence of field indices // passed to reflect's FieldByIndex. type field []int @@ -76,409 +57,301 @@ func toField(f *reflect.StructField) field { // invalidField is an invalid field identifier. var invalidField = field(nil) +// zeroField is a noop when calling pointer.offset. +var zeroField = field([]int{}) + // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { return f != nil } -// field returns the given field in the struct as a reflect value. -func structPointer_field(p structPointer, f field) reflect.Value { - // Special case: an extension map entry with a value of type T - // passes a *T to the struct-handling code with a zero field, - // expecting that it will be treated as equivalent to *struct{ X T }, - // which has the same memory layout. We have to handle that case - // specially, because reflect will panic if we call FieldByIndex on a - // non-struct. - if f == nil { - return p.v.Elem() - } - - return p.v.Elem().FieldByIndex(f) -} - -// ifield returns the given field in the struct as an interface value. -func structPointer_ifield(p structPointer, f field) interface{} { - return structPointer_field(p, f).Addr().Interface() -} - -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return structPointer_ifield(p, f).(*[]byte) -} - -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return structPointer_ifield(p, f).(*[][]byte) -} - -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return structPointer_ifield(p, f).(**bool) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return structPointer_ifield(p, f).(*bool) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return structPointer_ifield(p, f).(*[]bool) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return structPointer_ifield(p, f).(**string) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return structPointer_ifield(p, f).(*string) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return structPointer_ifield(p, f).(*[]string) -} - -// Extensions returns the address of an extension map field in the struct. -func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { - return structPointer_ifield(p, f).(*XXX_InternalExtensions) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return structPointer_ifield(p, f).(*map[int32]Extension) -} - -// NewAt returns the reflect.Value for a pointer to a field in the struct. -func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { - return structPointer_field(p, f).Addr() -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - structPointer_field(p, f).Set(q.v) -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return structPointer{structPointer_field(p, f)} -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { - return structPointerSlice{structPointer_field(p, f)} -} - -// A structPointerSlice represents the address of a slice of pointers to structs -// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. -type structPointerSlice struct { +// The pointer type is for the table-driven decoder. +// The implementation here uses a reflect.Value of pointer type to +// create a generic pointer. In pointer_unsafe.go we use unsafe +// instead of reflect to implement the same (but faster) interface. +type pointer struct { v reflect.Value } -func (p structPointerSlice) Len() int { return p.v.Len() } -func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } -func (p structPointerSlice) Append(q structPointer) { - p.v.Set(reflect.Append(p.v, q.v)) +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + return pointer{v: reflect.ValueOf(*i)} } -var ( - int32Type = reflect.TypeOf(int32(0)) - uint32Type = reflect.TypeOf(uint32(0)) - float32Type = reflect.TypeOf(float32(0)) - int64Type = reflect.TypeOf(int64(0)) - uint64Type = reflect.TypeOf(uint64(0)) - float64Type = reflect.TypeOf(float64(0)) -) - -// A word32 represents a field of type *int32, *uint32, *float32, or *enum. -// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. -type word32 struct { - v reflect.Value +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr bool) pointer { + v := reflect.ValueOf(*i) + u := reflect.New(v.Type()) + u.Elem().Set(v) + return pointer{v: u} } -// IsNil reports whether p is nil. -func word32_IsNil(p word32) bool { +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{v: v} +} + +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} +} + +func (p pointer) isNil() bool { return p.v.IsNil() } -// Set sets p to point at a newly allocated word with bits set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - t := p.v.Type().Elem() - switch t { - case int32Type: - if len(o.int32s) == 0 { - o.int32s = make([]int32, uint32PoolSize) - } - o.int32s[0] = int32(x) - p.v.Set(reflect.ValueOf(&o.int32s[0])) - o.int32s = o.int32s[1:] - return - case uint32Type: - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) - } - o.uint32s[0] = x - p.v.Set(reflect.ValueOf(&o.uint32s[0])) - o.uint32s = o.uint32s[1:] - return - case float32Type: - if len(o.float32s) == 0 { - o.float32s = make([]float32, uint32PoolSize) - } - o.float32s[0] = math.Float32frombits(x) - p.v.Set(reflect.ValueOf(&o.float32s[0])) - o.float32s = o.float32s[1:] - return - } - - // must be enum - p.v.Set(reflect.New(t)) - p.v.Elem().SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32_Get(p word32) uint32 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32{structPointer_field(p, f)} -} - -// A word32Val represents a field of type int32, uint32, float32, or enum. -// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. -type word32Val struct { - v reflect.Value -} - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - switch p.v.Type() { - case int32Type: - p.v.SetInt(int64(x)) - return - case uint32Type: - p.v.SetUint(uint64(x)) - return - case float32Type: - p.v.SetFloat(float64(math.Float32frombits(x))) - return - } - - // must be enum - p.v.SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32Val_Get(p word32Val) uint32 { - elem := p.v - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val{structPointer_field(p, f)} -} - -// A word32Slice is a slice of 32-bit values. -// That is, v.Type() is []int32, []uint32, []float32, or []enum. -type word32Slice struct { - v reflect.Value -} - -func (p word32Slice) Append(x uint32) { - n, m := p.v.Len(), p.v.Cap() +// grow updates the slice s in place to make it one element longer. +// s must be addressable. +// Returns the (addressable) new element. +func grow(s reflect.Value) reflect.Value { + n, m := s.Len(), s.Cap() if n < m { - p.v.SetLen(n + 1) + s.SetLen(n + 1) } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int32: - elem.SetInt(int64(int32(x))) - case reflect.Uint32: - elem.SetUint(uint64(x)) - case reflect.Float32: - elem.SetFloat(float64(math.Float32frombits(x))) + return s.Index(n) +} + +func (p pointer) toInt64() *int64 { + return p.v.Interface().(*int64) +} +func (p pointer) toInt64Ptr() **int64 { + return p.v.Interface().(**int64) +} +func (p pointer) toInt64Slice() *[]int64 { + return p.v.Interface().(*[]int64) +} + +var int32ptr = reflect.TypeOf((*int32)(nil)) + +func (p pointer) toInt32() *int32 { + return p.v.Convert(int32ptr).Interface().(*int32) +} + +// The toInt32Ptr/Slice methods don't work because of enums. +// Instead, we must use set/get methods for the int32ptr/slice case. +/* + func (p pointer) toInt32Ptr() **int32 { + return p.v.Interface().(**int32) +} + func (p pointer) toInt32Slice() *[]int32 { + return p.v.Interface().(*[]int32) +} +*/ +func (p pointer) getInt32Ptr() *int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().(*int32) } + // an enum + return p.v.Elem().Convert(int32PtrType).Interface().(*int32) +} +func (p pointer) setInt32Ptr(v int32) { + // Allocate value in a *int32. Possibly convert that to a *enum. + // Then assign it to a **int32 or **enum. + // Note: we can convert *int32 to *enum, but we can't convert + // **int32 to **enum! + p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) } -func (p word32Slice) Len() int { - return p.v.Len() -} - -func (p word32Slice) Index(i int) uint32 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) +// getInt32Slice copies []int32 from p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getInt32Slice() []int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().([]int32) } - panic("unreachable") + // an enum + // Allocate a []int32, then assign []enum's values into it. + // Note: we can't convert []enum to []int32. + slice := p.v.Elem() + s := make([]int32, slice.Len()) + for i := 0; i < slice.Len(); i++ { + s[i] = int32(slice.Index(i).Int()) + } + return s } -// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) word32Slice { - return word32Slice{structPointer_field(p, f)} -} - -// word64 is like word32 but for 64-bit values. -type word64 struct { - v reflect.Value -} - -func word64_Set(p word64, o *Buffer, x uint64) { - t := p.v.Type().Elem() - switch t { - case int64Type: - if len(o.int64s) == 0 { - o.int64s = make([]int64, uint64PoolSize) - } - o.int64s[0] = int64(x) - p.v.Set(reflect.ValueOf(&o.int64s[0])) - o.int64s = o.int64s[1:] - return - case uint64Type: - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) - } - o.uint64s[0] = x - p.v.Set(reflect.ValueOf(&o.uint64s[0])) - o.uint64s = o.uint64s[1:] - return - case float64Type: - if len(o.float64s) == 0 { - o.float64s = make([]float64, uint64PoolSize) - } - o.float64s[0] = math.Float64frombits(x) - p.v.Set(reflect.ValueOf(&o.float64s[0])) - o.float64s = o.float64s[1:] +// setInt32Slice copies []int32 into p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setInt32Slice(v []int32) { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + p.v.Elem().Set(reflect.ValueOf(v)) return } - panic("unreachable") -} - -func word64_IsNil(p word64) bool { - return p.v.IsNil() -} - -func word64_Get(p word64) uint64 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) + // an enum + // Allocate a []enum, then assign []int32's values into it. + // Note: we can't convert []enum to []int32. + slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) + for i, x := range v { + slice.Index(i).SetInt(int64(x)) } - panic("unreachable") + p.v.Elem().Set(slice) +} +func (p pointer) appendInt32Slice(v int32) { + grow(p.v.Elem()).SetInt(int64(v)) } -func structPointer_Word64(p structPointer, f field) word64 { - return word64{structPointer_field(p, f)} +func (p pointer) toUint64() *uint64 { + return p.v.Interface().(*uint64) +} +func (p pointer) toUint64Ptr() **uint64 { + return p.v.Interface().(**uint64) +} +func (p pointer) toUint64Slice() *[]uint64 { + return p.v.Interface().(*[]uint64) +} +func (p pointer) toUint32() *uint32 { + return p.v.Interface().(*uint32) +} +func (p pointer) toUint32Ptr() **uint32 { + return p.v.Interface().(**uint32) +} +func (p pointer) toUint32Slice() *[]uint32 { + return p.v.Interface().(*[]uint32) +} +func (p pointer) toBool() *bool { + return p.v.Interface().(*bool) +} +func (p pointer) toBoolPtr() **bool { + return p.v.Interface().(**bool) +} +func (p pointer) toBoolSlice() *[]bool { + return p.v.Interface().(*[]bool) +} +func (p pointer) toFloat64() *float64 { + return p.v.Interface().(*float64) +} +func (p pointer) toFloat64Ptr() **float64 { + return p.v.Interface().(**float64) +} +func (p pointer) toFloat64Slice() *[]float64 { + return p.v.Interface().(*[]float64) +} +func (p pointer) toFloat32() *float32 { + return p.v.Interface().(*float32) +} +func (p pointer) toFloat32Ptr() **float32 { + return p.v.Interface().(**float32) +} +func (p pointer) toFloat32Slice() *[]float32 { + return p.v.Interface().(*[]float32) +} +func (p pointer) toString() *string { + return p.v.Interface().(*string) +} +func (p pointer) toStringPtr() **string { + return p.v.Interface().(**string) +} +func (p pointer) toStringSlice() *[]string { + return p.v.Interface().(*[]string) +} +func (p pointer) toBytes() *[]byte { + return p.v.Interface().(*[]byte) +} +func (p pointer) toBytesSlice() *[][]byte { + return p.v.Interface().(*[][]byte) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return p.v.Interface().(*XXX_InternalExtensions) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return p.v.Interface().(*map[int32]Extension) +} +func (p pointer) getPointer() pointer { + return pointer{v: p.v.Elem()} +} +func (p pointer) setPointer(q pointer) { + p.v.Elem().Set(q.v) +} +func (p pointer) appendPointer(q pointer) { + grow(p.v.Elem()).Set(q.v) } -// word64Val is like word32Val but for 64-bit values. -type word64Val struct { - v reflect.Value +// getPointerSlice copies []*T from p as a new []pointer. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getPointerSlice() []pointer { + if p.v.IsNil() { + return nil + } + n := p.v.Elem().Len() + s := make([]pointer, n) + for i := 0; i < n; i++ { + s[i] = pointer{v: p.v.Elem().Index(i)} + } + return s } -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - switch p.v.Type() { - case int64Type: - p.v.SetInt(int64(x)) - return - case uint64Type: - p.v.SetUint(x) - return - case float64Type: - p.v.SetFloat(math.Float64frombits(x)) +// setPointerSlice copies []pointer into p as a new []*T. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setPointerSlice(v []pointer) { + if v == nil { + p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) return } - panic("unreachable") -} - -func word64Val_Get(p word64Val) uint64 { - elem := p.v - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) + s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) + for _, p := range v { + s = reflect.Append(s, p.v) } - panic("unreachable") + p.v.Elem().Set(s) } -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val{structPointer_field(p, f)} -} - -type word64Slice struct { - v reflect.Value -} - -func (p word64Slice) Append(x uint64) { - n, m := p.v.Len(), p.v.Cap() - if n < m { - p.v.SetLen(n + 1) - } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) - } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int64: - elem.SetInt(int64(int64(x))) - case reflect.Uint64: - elem.SetUint(uint64(x)) - case reflect.Float64: - elem.SetFloat(float64(math.Float64frombits(x))) +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + if p.v.Elem().IsNil() { + return pointer{v: p.v.Elem()} } + return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct } -func (p word64Slice) Len() int { - return p.v.Len() +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + // TODO: check that p.v.Type().Elem() == t? + return p.v } -func (p word64Slice) Index(i int) uint64 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return uint64(elem.Uint()) - case reflect.Float64: - return math.Float64bits(float64(elem.Float())) - } - panic("unreachable") +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v } -func structPointer_Word64Slice(p structPointer, f field) word64Slice { - return word64Slice{structPointer_field(p, f)} -} +var atomicLock sync.Mutex diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go index 6b5567d4..d55a335d 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build !appengine,!js +// +build !purego,!appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. @@ -37,38 +37,13 @@ package proto import ( "reflect" + "sync/atomic" "unsafe" ) -// NOTE: These type_Foo functions would more idiomatically be methods, -// but Go does not allow methods on pointer types, and we must preserve -// some pointer type for the garbage collector. We use these -// funcs with clunky names as our poor approximation to methods. -// -// An alternative would be -// type structPointer struct { p unsafe.Pointer } -// but that does not registerize as well. +const unsafeAllowed = true -// A structPointer is a pointer to a struct. -type structPointer unsafe.Pointer - -// toStructPointer returns a structPointer equivalent to the given reflect value. -func toStructPointer(v reflect.Value) structPointer { - return structPointer(unsafe.Pointer(v.Pointer())) -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p == nil -} - -// Interface returns the struct pointer, assumed to have element type t, -// as an interface value. -func structPointer_Interface(p structPointer, t reflect.Type) interface{} { - return reflect.NewAt(t, unsafe.Pointer(p)).Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. +// A field identifies a field in a struct, accessible from a pointer. // In this implementation, a field is identified by its byte offset from the start of the struct. type field uintptr @@ -80,191 +55,254 @@ func toField(f *reflect.StructField) field { // invalidField is an invalid field identifier. const invalidField = ^field(0) +// zeroField is a noop when calling pointer.offset. +const zeroField = field(0) + // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { - return f != ^field(0) + return f != invalidField } -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +// The pointer type below is for the new table-driven encoder/decoder. +// The implementation here uses unsafe.Pointer to create a generic pointer. +// In pointer_reflect.go we use reflect instead of unsafe to implement +// the same (but slower) interface. +type pointer struct { + p unsafe.Pointer } -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +// size of pointer +var ptrSize = unsafe.Sizeof(uintptr(0)) + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + // Super-tricky - read pointer out of data word of interface value. + // Saves ~25ns over the equivalent: + // return valToPointer(reflect.ValueOf(*i)) + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { - return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// NewAt returns the reflect.Value for a pointer to a field in the struct. -func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { - return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { - return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). -type structPointerSlice []structPointer - -func (v *structPointerSlice) Len() int { return len(*v) } -func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } -func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } - -// A word32 is the address of a "pointer to 32-bit value" field. -type word32 **uint32 - -// IsNil reports whether *v is nil. -func word32_IsNil(p word32) bool { - return *p == nil -} - -// Set sets *v to point at a newly allocated word set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr bool) pointer { + // Super-tricky - read or get the address of data word of interface value. + if isptr { + // The interface is of pointer type, thus it is a direct interface. + // The data word is the pointer data itself. We take its address. + return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} } - o.uint32s[0] = x - *p = &o.uint32s[0] - o.uint32s = o.uint32s[1:] + // The interface is not of pointer type. The data word is the pointer + // to the data. + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } -// Get gets the value pointed at by *v. -func word32_Get(p word32) uint32 { - return **p +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{p: unsafe.Pointer(v.Pointer())} } -// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + // For safety, we should panic if !f.IsValid, however calling panic causes + // this to no longer be inlineable, which is a serious performance cost. + /* + if !f.IsValid() { + panic("invalid field") + } + */ + return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} } -// A word32Val is the address of a 32-bit value field. -type word32Val *uint32 - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - *p = x +func (p pointer) isNil() bool { + return p.p == nil } -// Get gets the value pointed at by p. -func word32Val_Get(p word32Val) uint32 { - return *p +func (p pointer) toInt64() *int64 { + return (*int64)(p.p) +} +func (p pointer) toInt64Ptr() **int64 { + return (**int64)(p.p) +} +func (p pointer) toInt64Slice() *[]int64 { + return (*[]int64)(p.p) +} +func (p pointer) toInt32() *int32 { + return (*int32)(p.p) } -// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Slice is a slice of 32-bit values. -type word32Slice []uint32 - -func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } -func (v *word32Slice) Len() int { return len(*v) } -func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } - -// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) *word32Slice { - return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// word64 is like word32 but for 64-bit values. -type word64 **uint64 - -func word64_Set(p word64, o *Buffer, x uint64) { - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) +// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. +/* + func (p pointer) toInt32Ptr() **int32 { + return (**int32)(p.p) } - o.uint64s[0] = x - *p = &o.uint64s[0] - o.uint64s = o.uint64s[1:] + func (p pointer) toInt32Slice() *[]int32 { + return (*[]int32)(p.p) + } +*/ +func (p pointer) getInt32Ptr() *int32 { + return *(**int32)(p.p) +} +func (p pointer) setInt32Ptr(v int32) { + *(**int32)(p.p) = &v } -func word64_IsNil(p word64) bool { - return *p == nil +// getInt32Slice loads a []int32 from p. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getInt32Slice() []int32 { + return *(*[]int32)(p.p) } -func word64_Get(p word64) uint64 { - return **p +// setInt32Slice stores a []int32 to p. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setInt32Slice(v []int32) { + *(*[]int32)(p.p) = v } -func structPointer_Word64(p structPointer, f field) word64 { - return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? +func (p pointer) appendInt32Slice(v int32) { + s := (*[]int32)(p.p) + *s = append(*s, v) } -// word64Val is like word32Val but for 64-bit values. -type word64Val *uint64 - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - *p = x +func (p pointer) toUint64() *uint64 { + return (*uint64)(p.p) +} +func (p pointer) toUint64Ptr() **uint64 { + return (**uint64)(p.p) +} +func (p pointer) toUint64Slice() *[]uint64 { + return (*[]uint64)(p.p) +} +func (p pointer) toUint32() *uint32 { + return (*uint32)(p.p) +} +func (p pointer) toUint32Ptr() **uint32 { + return (**uint32)(p.p) +} +func (p pointer) toUint32Slice() *[]uint32 { + return (*[]uint32)(p.p) +} +func (p pointer) toBool() *bool { + return (*bool)(p.p) +} +func (p pointer) toBoolPtr() **bool { + return (**bool)(p.p) +} +func (p pointer) toBoolSlice() *[]bool { + return (*[]bool)(p.p) +} +func (p pointer) toFloat64() *float64 { + return (*float64)(p.p) +} +func (p pointer) toFloat64Ptr() **float64 { + return (**float64)(p.p) +} +func (p pointer) toFloat64Slice() *[]float64 { + return (*[]float64)(p.p) +} +func (p pointer) toFloat32() *float32 { + return (*float32)(p.p) +} +func (p pointer) toFloat32Ptr() **float32 { + return (**float32)(p.p) +} +func (p pointer) toFloat32Slice() *[]float32 { + return (*[]float32)(p.p) +} +func (p pointer) toString() *string { + return (*string)(p.p) +} +func (p pointer) toStringPtr() **string { + return (**string)(p.p) +} +func (p pointer) toStringSlice() *[]string { + return (*[]string)(p.p) +} +func (p pointer) toBytes() *[]byte { + return (*[]byte)(p.p) +} +func (p pointer) toBytesSlice() *[][]byte { + return (*[][]byte)(p.p) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(p.p) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return (*map[int32]Extension)(p.p) } -func word64Val_Get(p word64Val) uint64 { - return *p +// getPointerSlice loads []*T from p as a []pointer. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getPointerSlice() []pointer { + // Super-tricky - p should point to a []*T where T is a + // message type. We load it as []pointer. + return *(*[]pointer)(p.p) } -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +// setPointerSlice stores []pointer into p as a []*T. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setPointerSlice(v []pointer) { + // Super-tricky - p should point to a []*T where T is a + // message type. We store it as []pointer. + *(*[]pointer)(p.p) = v } -// word64Slice is like word32Slice but for 64-bit values. -type word64Slice []uint64 - -func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } -func (v *word64Slice) Len() int { return len(*v) } -func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } - -func structPointer_Word64Slice(p structPointer, f field) *word64Slice { - return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +// getPointer loads the pointer at p and returns it. +func (p pointer) getPointer() pointer { + return pointer{p: *(*unsafe.Pointer)(p.p)} +} + +// setPointer stores the pointer q at p. +func (p pointer) setPointer(q pointer) { + *(*unsafe.Pointer)(p.p) = q.p +} + +// append q to the slice pointed to by p. +func (p pointer) appendPointer(q pointer) { + s := (*[]unsafe.Pointer)(p.p) + *s = append(*s, q.p) +} + +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + // Super-tricky - read pointer out of data word of interface value. + return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} +} + +// asPointerTo returns a reflect.Value that is a pointer to an +// object of type t stored at p. +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + return reflect.NewAt(t, p.p) +} + +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) } diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go index ec2289c0..50b99b83 100644 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -58,42 +58,6 @@ const ( WireFixed32 = 5 ) -const startSize = 10 // initial slice/string sizes - -// Encoders are defined in encode.go -// An encoder outputs the full representation of a field, including its -// tag and encoder type. -type encoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueEncoder encodes a single integer in a particular encoding. -type valueEncoder func(o *Buffer, x uint64) error - -// Sizers are defined in encode.go -// A sizer returns the encoded size of a field, including its tag and encoder -// type. -type sizer func(prop *Properties, base structPointer) int - -// A valueSizer returns the encoded size of a single integer in a particular -// encoding. -type valueSizer func(x uint64) int - -// Decoders are defined in decode.go -// A decoder creates a value from its wire representation. -// Unrecognized subelements are saved in unrec. -type decoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueDecoder decodes a single integer in a particular encoding. -type valueDecoder func(o *Buffer) (x uint64, err error) - -// A oneofMarshaler does the marshaling for all oneof fields in a message. -type oneofMarshaler func(Message, *Buffer) error - -// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. -type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) - -// A oneofSizer does the sizing for all oneof fields in a message. -type oneofSizer func(Message) int - // tagMap is an optimization over map[int]int for typical protocol buffer // use-cases. Encoded protocol buffers are often in tag order with small tag // numbers. @@ -140,13 +104,6 @@ type StructProperties struct { decoderTags tagMap // map from proto tag to struct field number decoderOrigNames map[string]int // map from original name to struct field number order []int // list of struct field numbers in tag order - unrecField field // field id of the XXX_unrecognized []byte field - extendable bool // is this an extendable proto - - oneofMarshaler oneofMarshaler - oneofUnmarshaler oneofUnmarshaler - oneofSizer oneofSizer - stype reflect.Type // OneofTypes contains information about the oneof fields in this message. // It is keyed by the original name of a field. @@ -182,41 +139,24 @@ type Properties struct { Repeated bool Packed bool // relevant for repeated primitives only Enum string // set for enum types only - proto3 bool // whether this is known to be a proto3 field; set for []byte only + proto3 bool // whether this is known to be a proto3 field oneof bool // whether this is a oneof field Default string // default value HasDefault bool // whether an explicit default was provided - def_uint64 uint64 - enc encoder - valEnc valueEncoder // set for bool and numeric types only - field field - tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) - tagbuf [8]byte - stype reflect.Type // set for struct types only - sprop *StructProperties // set for struct types only - isMarshaler bool - isUnmarshaler bool + stype reflect.Type // set for struct types only + sprop *StructProperties // set for struct types only - mtype reflect.Type // set for map types only - mkeyprop *Properties // set for map types only - mvalprop *Properties // set for map types only - - size sizer - valSize valueSizer // set for bool and numeric types only - - dec decoder - valDec valueDecoder // set for bool and numeric types only - - // If this is a packable field, this will be the decoder for the packed version of the field. - packedDec decoder + mtype reflect.Type // set for map types only + MapKeyProp *Properties // set for map types only + MapValProp *Properties // set for map types only } // String formats the properties in the protobuf struct field tag style. func (p *Properties) String() string { s := p.Wire - s = "," + s += "," s += strconv.Itoa(p.Tag) if p.Required { s += ",req" @@ -262,29 +202,14 @@ func (p *Properties) Parse(s string) { switch p.Wire { case "varint": p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeVarint - p.valDec = (*Buffer).DecodeVarint - p.valSize = sizeVarint case "fixed32": p.WireType = WireFixed32 - p.valEnc = (*Buffer).EncodeFixed32 - p.valDec = (*Buffer).DecodeFixed32 - p.valSize = sizeFixed32 case "fixed64": p.WireType = WireFixed64 - p.valEnc = (*Buffer).EncodeFixed64 - p.valDec = (*Buffer).DecodeFixed64 - p.valSize = sizeFixed64 case "zigzag32": p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag32 - p.valDec = (*Buffer).DecodeZigzag32 - p.valSize = sizeZigzag32 case "zigzag64": p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag64 - p.valDec = (*Buffer).DecodeZigzag64 - p.valSize = sizeZigzag64 case "bytes", "group": p.WireType = WireBytes // no numeric converter for non-numeric types @@ -299,6 +224,7 @@ func (p *Properties) Parse(s string) { return } +outer: for i := 2; i < len(fields); i++ { f := fields[i] switch { @@ -326,256 +252,41 @@ func (p *Properties) Parse(s string) { if i+1 < len(fields) { // Commas aren't escaped, and def is always last. p.Default += "," + strings.Join(fields[i+1:], ",") - break + break outer } } } } -func logNoSliceEnc(t1, t2 reflect.Type) { - fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) -} - var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() -// Initialize the fields for encoding and decoding. -func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { - p.enc = nil - p.dec = nil - p.size = nil - +// setFieldProps initializes the field properties for submessages and maps. +func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { switch t1 := typ; t1.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) - - // proto3 scalar types - - case reflect.Bool: - p.enc = (*Buffer).enc_proto3_bool - p.dec = (*Buffer).dec_proto3_bool - p.size = size_proto3_bool - case reflect.Int32: - p.enc = (*Buffer).enc_proto3_int32 - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_proto3_uint32 - p.dec = (*Buffer).dec_proto3_int32 // can reuse - p.size = size_proto3_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_proto3_int64 - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.String: - p.enc = (*Buffer).enc_proto3_string - p.dec = (*Buffer).dec_proto3_string - p.size = size_proto3_string - case reflect.Ptr: - switch t2 := t1.Elem(); t2.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) - break - case reflect.Bool: - p.enc = (*Buffer).enc_bool - p.dec = (*Buffer).dec_bool - p.size = size_bool - case reflect.Int32: - p.enc = (*Buffer).enc_int32 - p.dec = (*Buffer).dec_int32 - p.size = size_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_uint32 - p.dec = (*Buffer).dec_int32 // can reuse - p.size = size_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_int64 - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_int32 - p.size = size_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_int64 // can just treat them as bits - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.String: - p.enc = (*Buffer).enc_string - p.dec = (*Buffer).dec_string - p.size = size_string - case reflect.Struct: + if t1.Elem().Kind() == reflect.Struct { p.stype = t1.Elem() - p.isMarshaler = isMarshaler(t1) - p.isUnmarshaler = isUnmarshaler(t1) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_struct_message - p.dec = (*Buffer).dec_struct_message - p.size = size_struct_message - } else { - p.enc = (*Buffer).enc_struct_group - p.dec = (*Buffer).dec_struct_group - p.size = size_struct_group - } } case reflect.Slice: - switch t2 := t1.Elem(); t2.Kind() { - default: - logNoSliceEnc(t1, t2) - break - case reflect.Bool: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_bool - p.size = size_slice_packed_bool - } else { - p.enc = (*Buffer).enc_slice_bool - p.size = size_slice_bool - } - p.dec = (*Buffer).dec_slice_bool - p.packedDec = (*Buffer).dec_slice_packed_bool - case reflect.Int32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int32 - p.size = size_slice_packed_int32 - } else { - p.enc = (*Buffer).enc_slice_int32 - p.size = size_slice_int32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Uint32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Int64, reflect.Uint64: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - case reflect.Uint8: - p.dec = (*Buffer).dec_slice_byte - if p.proto3 { - p.enc = (*Buffer).enc_proto3_slice_byte - p.size = size_proto3_slice_byte - } else { - p.enc = (*Buffer).enc_slice_byte - p.size = size_slice_byte - } - case reflect.Float32, reflect.Float64: - switch t2.Bits() { - case 32: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case 64: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - default: - logNoSliceEnc(t1, t2) - break - } - case reflect.String: - p.enc = (*Buffer).enc_slice_string - p.dec = (*Buffer).dec_slice_string - p.size = size_slice_string - case reflect.Ptr: - switch t3 := t2.Elem(); t3.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) - break - case reflect.Struct: - p.stype = t2.Elem() - p.isMarshaler = isMarshaler(t2) - p.isUnmarshaler = isUnmarshaler(t2) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_slice_struct_message - p.dec = (*Buffer).dec_slice_struct_message - p.size = size_slice_struct_message - } else { - p.enc = (*Buffer).enc_slice_struct_group - p.dec = (*Buffer).dec_slice_struct_group - p.size = size_slice_struct_group - } - } - case reflect.Slice: - switch t2.Elem().Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) - break - case reflect.Uint8: - p.enc = (*Buffer).enc_slice_slice_byte - p.dec = (*Buffer).dec_slice_slice_byte - p.size = size_slice_slice_byte - } + if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { + p.stype = t2.Elem() } case reflect.Map: - p.enc = (*Buffer).enc_new_map - p.dec = (*Buffer).dec_new_map - p.size = size_new_map - p.mtype = t1 - p.mkeyprop = &Properties{} - p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) - p.mvalprop = &Properties{} + p.MapKeyProp = &Properties{} + p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.MapValProp = &Properties{} vtype := p.mtype.Elem() if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { // The value type is not a message (*T) or bytes ([]byte), // so we need encoders for the pointer to this type. vtype = reflect.PtrTo(vtype) } - p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) } - // precalculate tag code - wire := p.WireType - if p.Packed { - wire = WireBytes - } - x := uint32(p.Tag)<<3 | uint32(wire) - i := 0 - for i = 0; x > 127; i++ { - p.tagbuf[i] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - p.tagbuf[i] = uint8(x) - p.tagcode = p.tagbuf[0 : i+1] - if p.stype != nil { if lockGetProp { p.sprop = GetProperties(p.stype) @@ -586,32 +297,9 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock } var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() ) -// isMarshaler reports whether type t implements Marshaler. -func isMarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isMarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isMarshaler") - } - return t.Implements(marshalerType) -} - -// isUnmarshaler reports whether type t implements Unmarshaler. -func isUnmarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isUnmarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isUnmarshaler") - } - return t.Implements(unmarshalerType) -} - // Init populates the properties from a protocol buffer struct tag. func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { p.init(typ, name, tag, f, true) @@ -621,14 +309,11 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF // "bytes,49,opt,def=hello!" p.Name = name p.OrigName = name - if f != nil { - p.field = toField(f) - } if tag == "" { return } p.Parse(tag) - p.setEncAndDec(typ, f, lockGetProp) + p.setFieldProps(typ, f, lockGetProp) } var ( @@ -678,9 +363,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { propertiesMap[t] = prop // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || - reflect.PtrTo(t).Implements(extendableProtoV1Type) - prop.unrecField = invalidField prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) @@ -690,17 +372,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { name := f.Name p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - if f.Name == "XXX_InternalExtensions" { // special case - p.enc = (*Buffer).enc_exts - p.dec = nil // not needed - p.size = size_exts - } else if f.Name == "XXX_extensions" { // special case - p.enc = (*Buffer).enc_map - p.dec = nil // not needed - p.size = size_map - } else if f.Name == "XXX_unrecognized" { // special case - prop.unrecField = toField(&f) - } oneof := f.Tag.Get("protobuf_oneof") // special case if oneof != "" { // Oneof fields don't use the traditional protobuf tag. @@ -715,9 +386,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } print("\n") } - if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { - fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") - } } // Re-order prop.order. @@ -728,8 +396,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { var oots []interface{} - prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() - prop.stype = t + _, _, _, oots = om.XXX_OneofFuncs() // Interpret oneof metadata. prop.OneofTypes = make(map[string]*OneofProperties) @@ -779,30 +446,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { return prop } -// Return the Properties object for the x[0]'th field of the structure. -func propByIndex(t reflect.Type, x []int) *Properties { - if len(x) != 1 { - fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) - return nil - } - prop := GetProperties(t) - return prop.Prop[x[0]] -} - -// Get the address and type of a pointer to a struct from an interface. -func getbase(pb Message) (t reflect.Type, b structPointer, err error) { - if pb == nil { - err = ErrNil - return - } - // get the reflect type of the pointer to the struct. - t = reflect.TypeOf(pb) - // get the address of the struct. - value := reflect.ValueOf(pb) - b = toStructPointer(value) - return -} - // A global registry of enum types. // The generated code will register the generated maps by calling RegisterEnum. @@ -826,20 +469,42 @@ func EnumValueMap(enumType string) map[string]int32 { // A registry of all linked message types. // The string is a fully-qualified proto name ("pkg.Message"). var ( - protoTypes = make(map[string]reflect.Type) - revProtoTypes = make(map[reflect.Type]string) + protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers + protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types + revProtoTypes = make(map[reflect.Type]string) ) // RegisterType is called from generated code and maps from the fully qualified // proto name to the type (pointer to struct) of the protocol buffer. func RegisterType(x Message, name string) { - if _, ok := protoTypes[name]; ok { + if _, ok := protoTypedNils[name]; ok { // TODO: Some day, make this a panic. log.Printf("proto: duplicate proto type registered: %s", name) return } t := reflect.TypeOf(x) - protoTypes[name] = t + if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { + // Generated code always calls RegisterType with nil x. + // This check is just for extra safety. + protoTypedNils[name] = x + } else { + protoTypedNils[name] = reflect.Zero(t).Interface().(Message) + } + revProtoTypes[t] = name +} + +// RegisterMapType is called from generated code and maps from the fully qualified +// proto name to the native map type of the proto map definition. +func RegisterMapType(x interface{}, name string) { + if reflect.TypeOf(x).Kind() != reflect.Map { + panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) + } + if _, ok := protoMapTypes[name]; ok { + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoMapTypes[name] = t revProtoTypes[t] = name } @@ -855,7 +520,14 @@ func MessageName(x Message) string { } // MessageType returns the message type (pointer to struct) for a named message. -func MessageType(name string) reflect.Type { return protoTypes[name] } +// The type is not guaranteed to implement proto.Message if the name refers to a +// map entry. +func MessageType(name string) reflect.Type { + if t, ok := protoTypedNils[name]; ok { + return reflect.TypeOf(t) + } + return protoMapTypes[name] +} // A registry of all linked proto files. var ( diff --git a/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.pb.go b/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.pb.go index cc4d0489..2bd39923 100644 --- a/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.pb.go +++ b/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.pb.go @@ -1,27 +1,13 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: proto3_proto/proto3.proto -// DO NOT EDIT! -/* -Package proto3_proto is a generated protocol buffer package. - -It is generated from these files: - proto3_proto/proto3.proto - -It has these top-level messages: - Message - Nested - MessageWithMap - IntMap - IntMaps -*/ package proto3_proto import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" -import google_protobuf "github.com/golang/protobuf/ptypes/any" -import testdata "github.com/golang/protobuf/proto/testdata" +import test_proto "github.com/golang/protobuf/proto/test_proto" +import any "github.com/golang/protobuf/ptypes/any" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -59,33 +45,58 @@ var Message_Humour_value = map[string]int32{ func (x Message_Humour) String() string { return proto.EnumName(Message_Humour_name, int32(x)) } -func (Message_Humour) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } - -type Message struct { - Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Hilarity Message_Humour `protobuf:"varint,2,opt,name=hilarity,enum=proto3_proto.Message_Humour" json:"hilarity,omitempty"` - HeightInCm uint32 `protobuf:"varint,3,opt,name=height_in_cm,json=heightInCm" json:"height_in_cm,omitempty"` - Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` - ResultCount int64 `protobuf:"varint,7,opt,name=result_count,json=resultCount" json:"result_count,omitempty"` - TrueScotsman bool `protobuf:"varint,8,opt,name=true_scotsman,json=trueScotsman" json:"true_scotsman,omitempty"` - Score float32 `protobuf:"fixed32,9,opt,name=score" json:"score,omitempty"` - Key []uint64 `protobuf:"varint,5,rep,packed,name=key" json:"key,omitempty"` - ShortKey []int32 `protobuf:"varint,19,rep,packed,name=short_key,json=shortKey" json:"short_key,omitempty"` - Nested *Nested `protobuf:"bytes,6,opt,name=nested" json:"nested,omitempty"` - RFunny []Message_Humour `protobuf:"varint,16,rep,packed,name=r_funny,json=rFunny,enum=proto3_proto.Message_Humour" json:"r_funny,omitempty"` - Terrain map[string]*Nested `protobuf:"bytes,10,rep,name=terrain" json:"terrain,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Proto2Field *testdata.SubDefaults `protobuf:"bytes,11,opt,name=proto2_field,json=proto2Field" json:"proto2_field,omitempty"` - Proto2Value map[string]*testdata.SubDefaults `protobuf:"bytes,13,rep,name=proto2_value,json=proto2Value" json:"proto2_value,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Anything *google_protobuf.Any `protobuf:"bytes,14,opt,name=anything" json:"anything,omitempty"` - ManyThings []*google_protobuf.Any `protobuf:"bytes,15,rep,name=many_things,json=manyThings" json:"many_things,omitempty"` - Submessage *Message `protobuf:"bytes,17,opt,name=submessage" json:"submessage,omitempty"` - Children []*Message `protobuf:"bytes,18,rep,name=children" json:"children,omitempty"` +func (Message_Humour) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{0, 0} } -func (m *Message) Reset() { *m = Message{} } -func (m *Message) String() string { return proto.CompactTextString(m) } -func (*Message) ProtoMessage() {} -func (*Message) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +type Message struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Hilarity Message_Humour `protobuf:"varint,2,opt,name=hilarity,proto3,enum=proto3_proto.Message_Humour" json:"hilarity,omitempty"` + HeightInCm uint32 `protobuf:"varint,3,opt,name=height_in_cm,json=heightInCm,proto3" json:"height_in_cm,omitempty"` + Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` + ResultCount int64 `protobuf:"varint,7,opt,name=result_count,json=resultCount,proto3" json:"result_count,omitempty"` + TrueScotsman bool `protobuf:"varint,8,opt,name=true_scotsman,json=trueScotsman,proto3" json:"true_scotsman,omitempty"` + Score float32 `protobuf:"fixed32,9,opt,name=score,proto3" json:"score,omitempty"` + Key []uint64 `protobuf:"varint,5,rep,packed,name=key,proto3" json:"key,omitempty"` + ShortKey []int32 `protobuf:"varint,19,rep,packed,name=short_key,json=shortKey,proto3" json:"short_key,omitempty"` + Nested *Nested `protobuf:"bytes,6,opt,name=nested,proto3" json:"nested,omitempty"` + RFunny []Message_Humour `protobuf:"varint,16,rep,packed,name=r_funny,json=rFunny,proto3,enum=proto3_proto.Message_Humour" json:"r_funny,omitempty"` + Terrain map[string]*Nested `protobuf:"bytes,10,rep,name=terrain,proto3" json:"terrain,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Proto2Field *test_proto.SubDefaults `protobuf:"bytes,11,opt,name=proto2_field,json=proto2Field,proto3" json:"proto2_field,omitempty"` + Proto2Value map[string]*test_proto.SubDefaults `protobuf:"bytes,13,rep,name=proto2_value,json=proto2Value,proto3" json:"proto2_value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Anything *any.Any `protobuf:"bytes,14,opt,name=anything,proto3" json:"anything,omitempty"` + ManyThings []*any.Any `protobuf:"bytes,15,rep,name=many_things,json=manyThings,proto3" json:"many_things,omitempty"` + Submessage *Message `protobuf:"bytes,17,opt,name=submessage,proto3" json:"submessage,omitempty"` + Children []*Message `protobuf:"bytes,18,rep,name=children,proto3" json:"children,omitempty"` + StringMap map[string]string `protobuf:"bytes,20,rep,name=string_map,json=stringMap,proto3" json:"string_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{0} +} +func (m *Message) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Message.Unmarshal(m, b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Message.Marshal(b, m, deterministic) +} +func (dst *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(dst, src) +} +func (m *Message) XXX_Size() int { + return xxx_messageInfo_Message.Size(m) +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo func (m *Message) GetName() string { if m != nil { @@ -171,28 +182,28 @@ func (m *Message) GetTerrain() map[string]*Nested { return nil } -func (m *Message) GetProto2Field() *testdata.SubDefaults { +func (m *Message) GetProto2Field() *test_proto.SubDefaults { if m != nil { return m.Proto2Field } return nil } -func (m *Message) GetProto2Value() map[string]*testdata.SubDefaults { +func (m *Message) GetProto2Value() map[string]*test_proto.SubDefaults { if m != nil { return m.Proto2Value } return nil } -func (m *Message) GetAnything() *google_protobuf.Any { +func (m *Message) GetAnything() *any.Any { if m != nil { return m.Anything } return nil } -func (m *Message) GetManyThings() []*google_protobuf.Any { +func (m *Message) GetManyThings() []*any.Any { if m != nil { return m.ManyThings } @@ -213,15 +224,44 @@ func (m *Message) GetChildren() []*Message { return nil } -type Nested struct { - Bunny string `protobuf:"bytes,1,opt,name=bunny" json:"bunny,omitempty"` - Cute bool `protobuf:"varint,2,opt,name=cute" json:"cute,omitempty"` +func (m *Message) GetStringMap() map[string]string { + if m != nil { + return m.StringMap + } + return nil } -func (m *Nested) Reset() { *m = Nested{} } -func (m *Nested) String() string { return proto.CompactTextString(m) } -func (*Nested) ProtoMessage() {} -func (*Nested) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +type Nested struct { + Bunny string `protobuf:"bytes,1,opt,name=bunny,proto3" json:"bunny,omitempty"` + Cute bool `protobuf:"varint,2,opt,name=cute,proto3" json:"cute,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Nested) Reset() { *m = Nested{} } +func (m *Nested) String() string { return proto.CompactTextString(m) } +func (*Nested) ProtoMessage() {} +func (*Nested) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{1} +} +func (m *Nested) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Nested.Unmarshal(m, b) +} +func (m *Nested) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Nested.Marshal(b, m, deterministic) +} +func (dst *Nested) XXX_Merge(src proto.Message) { + xxx_messageInfo_Nested.Merge(dst, src) +} +func (m *Nested) XXX_Size() int { + return xxx_messageInfo_Nested.Size(m) +} +func (m *Nested) XXX_DiscardUnknown() { + xxx_messageInfo_Nested.DiscardUnknown(m) +} + +var xxx_messageInfo_Nested proto.InternalMessageInfo func (m *Nested) GetBunny() string { if m != nil { @@ -238,13 +278,35 @@ func (m *Nested) GetCute() bool { } type MessageWithMap struct { - ByteMapping map[bool][]byte `protobuf:"bytes,1,rep,name=byte_mapping,json=byteMapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"` + ByteMapping map[bool][]byte `protobuf:"bytes,1,rep,name=byte_mapping,json=byteMapping,proto3" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MessageWithMap) Reset() { *m = MessageWithMap{} } -func (m *MessageWithMap) String() string { return proto.CompactTextString(m) } -func (*MessageWithMap) ProtoMessage() {} -func (*MessageWithMap) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *MessageWithMap) Reset() { *m = MessageWithMap{} } +func (m *MessageWithMap) String() string { return proto.CompactTextString(m) } +func (*MessageWithMap) ProtoMessage() {} +func (*MessageWithMap) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{2} +} +func (m *MessageWithMap) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MessageWithMap.Unmarshal(m, b) +} +func (m *MessageWithMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MessageWithMap.Marshal(b, m, deterministic) +} +func (dst *MessageWithMap) XXX_Merge(src proto.Message) { + xxx_messageInfo_MessageWithMap.Merge(dst, src) +} +func (m *MessageWithMap) XXX_Size() int { + return xxx_messageInfo_MessageWithMap.Size(m) +} +func (m *MessageWithMap) XXX_DiscardUnknown() { + xxx_messageInfo_MessageWithMap.DiscardUnknown(m) +} + +var xxx_messageInfo_MessageWithMap proto.InternalMessageInfo func (m *MessageWithMap) GetByteMapping() map[bool][]byte { if m != nil { @@ -254,13 +316,35 @@ func (m *MessageWithMap) GetByteMapping() map[bool][]byte { } type IntMap struct { - Rtt map[int32]int32 `protobuf:"bytes,1,rep,name=rtt" json:"rtt,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + Rtt map[int32]int32 `protobuf:"bytes,1,rep,name=rtt,proto3" json:"rtt,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *IntMap) Reset() { *m = IntMap{} } -func (m *IntMap) String() string { return proto.CompactTextString(m) } -func (*IntMap) ProtoMessage() {} -func (*IntMap) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (m *IntMap) Reset() { *m = IntMap{} } +func (m *IntMap) String() string { return proto.CompactTextString(m) } +func (*IntMap) ProtoMessage() {} +func (*IntMap) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{3} +} +func (m *IntMap) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IntMap.Unmarshal(m, b) +} +func (m *IntMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IntMap.Marshal(b, m, deterministic) +} +func (dst *IntMap) XXX_Merge(src proto.Message) { + xxx_messageInfo_IntMap.Merge(dst, src) +} +func (m *IntMap) XXX_Size() int { + return xxx_messageInfo_IntMap.Size(m) +} +func (m *IntMap) XXX_DiscardUnknown() { + xxx_messageInfo_IntMap.DiscardUnknown(m) +} + +var xxx_messageInfo_IntMap proto.InternalMessageInfo func (m *IntMap) GetRtt() map[int32]int32 { if m != nil { @@ -270,13 +354,35 @@ func (m *IntMap) GetRtt() map[int32]int32 { } type IntMaps struct { - Maps []*IntMap `protobuf:"bytes,1,rep,name=maps" json:"maps,omitempty"` + Maps []*IntMap `protobuf:"bytes,1,rep,name=maps,proto3" json:"maps,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *IntMaps) Reset() { *m = IntMaps{} } -func (m *IntMaps) String() string { return proto.CompactTextString(m) } -func (*IntMaps) ProtoMessage() {} -func (*IntMaps) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } +func (m *IntMaps) Reset() { *m = IntMaps{} } +func (m *IntMaps) String() string { return proto.CompactTextString(m) } +func (*IntMaps) ProtoMessage() {} +func (*IntMaps) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{4} +} +func (m *IntMaps) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IntMaps.Unmarshal(m, b) +} +func (m *IntMaps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IntMaps.Marshal(b, m, deterministic) +} +func (dst *IntMaps) XXX_Merge(src proto.Message) { + xxx_messageInfo_IntMaps.Merge(dst, src) +} +func (m *IntMaps) XXX_Size() int { + return xxx_messageInfo_IntMaps.Size(m) +} +func (m *IntMaps) XXX_DiscardUnknown() { + xxx_messageInfo_IntMaps.DiscardUnknown(m) +} + +var xxx_messageInfo_IntMaps proto.InternalMessageInfo func (m *IntMaps) GetMaps() []*IntMap { if m != nil { @@ -285,63 +391,221 @@ func (m *IntMaps) GetMaps() []*IntMap { return nil } +type TestUTF8 struct { + Scalar string `protobuf:"bytes,1,opt,name=scalar,proto3" json:"scalar,omitempty"` + Vector []string `protobuf:"bytes,2,rep,name=vector,proto3" json:"vector,omitempty"` + // Types that are valid to be assigned to Oneof: + // *TestUTF8_Field + Oneof isTestUTF8_Oneof `protobuf_oneof:"oneof"` + MapKey map[string]int64 `protobuf:"bytes,4,rep,name=map_key,json=mapKey,proto3" json:"map_key,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue map[int64]string `protobuf:"bytes,5,rep,name=map_value,json=mapValue,proto3" json:"map_value,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TestUTF8) Reset() { *m = TestUTF8{} } +func (m *TestUTF8) String() string { return proto.CompactTextString(m) } +func (*TestUTF8) ProtoMessage() {} +func (*TestUTF8) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_78ae00cd7e6e5e35, []int{5} +} +func (m *TestUTF8) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TestUTF8.Unmarshal(m, b) +} +func (m *TestUTF8) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TestUTF8.Marshal(b, m, deterministic) +} +func (dst *TestUTF8) XXX_Merge(src proto.Message) { + xxx_messageInfo_TestUTF8.Merge(dst, src) +} +func (m *TestUTF8) XXX_Size() int { + return xxx_messageInfo_TestUTF8.Size(m) +} +func (m *TestUTF8) XXX_DiscardUnknown() { + xxx_messageInfo_TestUTF8.DiscardUnknown(m) +} + +var xxx_messageInfo_TestUTF8 proto.InternalMessageInfo + +func (m *TestUTF8) GetScalar() string { + if m != nil { + return m.Scalar + } + return "" +} + +func (m *TestUTF8) GetVector() []string { + if m != nil { + return m.Vector + } + return nil +} + +type isTestUTF8_Oneof interface { + isTestUTF8_Oneof() +} + +type TestUTF8_Field struct { + Field string `protobuf:"bytes,3,opt,name=field,proto3,oneof"` +} + +func (*TestUTF8_Field) isTestUTF8_Oneof() {} + +func (m *TestUTF8) GetOneof() isTestUTF8_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *TestUTF8) GetField() string { + if x, ok := m.GetOneof().(*TestUTF8_Field); ok { + return x.Field + } + return "" +} + +func (m *TestUTF8) GetMapKey() map[string]int64 { + if m != nil { + return m.MapKey + } + return nil +} + +func (m *TestUTF8) GetMapValue() map[int64]string { + if m != nil { + return m.MapValue + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*TestUTF8) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _TestUTF8_OneofMarshaler, _TestUTF8_OneofUnmarshaler, _TestUTF8_OneofSizer, []interface{}{ + (*TestUTF8_Field)(nil), + } +} + +func _TestUTF8_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*TestUTF8) + // oneof + switch x := m.Oneof.(type) { + case *TestUTF8_Field: + b.EncodeVarint(3<<3 | proto.WireBytes) + b.EncodeStringBytes(x.Field) + case nil: + default: + return fmt.Errorf("TestUTF8.Oneof has unexpected type %T", x) + } + return nil +} + +func _TestUTF8_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*TestUTF8) + switch tag { + case 3: // oneof.field + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Oneof = &TestUTF8_Field{x} + return true, err + default: + return false, nil + } +} + +func _TestUTF8_OneofSizer(msg proto.Message) (n int) { + m := msg.(*TestUTF8) + // oneof + switch x := m.Oneof.(type) { + case *TestUTF8_Field: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.Field))) + n += len(x.Field) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + func init() { proto.RegisterType((*Message)(nil), "proto3_proto.Message") + proto.RegisterMapType((map[string]*test_proto.SubDefaults)(nil), "proto3_proto.Message.Proto2ValueEntry") + proto.RegisterMapType((map[string]string)(nil), "proto3_proto.Message.StringMapEntry") + proto.RegisterMapType((map[string]*Nested)(nil), "proto3_proto.Message.TerrainEntry") proto.RegisterType((*Nested)(nil), "proto3_proto.Nested") proto.RegisterType((*MessageWithMap)(nil), "proto3_proto.MessageWithMap") + proto.RegisterMapType((map[bool][]byte)(nil), "proto3_proto.MessageWithMap.ByteMappingEntry") proto.RegisterType((*IntMap)(nil), "proto3_proto.IntMap") + proto.RegisterMapType((map[int32]int32)(nil), "proto3_proto.IntMap.RttEntry") proto.RegisterType((*IntMaps)(nil), "proto3_proto.IntMaps") + proto.RegisterType((*TestUTF8)(nil), "proto3_proto.TestUTF8") + proto.RegisterMapType((map[string]int64)(nil), "proto3_proto.TestUTF8.MapKeyEntry") + proto.RegisterMapType((map[int64]string)(nil), "proto3_proto.TestUTF8.MapValueEntry") proto.RegisterEnum("proto3_proto.Message_Humour", Message_Humour_name, Message_Humour_value) } -func init() { proto.RegisterFile("proto3_proto/proto3.proto", fileDescriptor0) } +func init() { proto.RegisterFile("proto3_proto/proto3.proto", fileDescriptor_proto3_78ae00cd7e6e5e35) } -var fileDescriptor0 = []byte{ - // 733 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x53, 0x6d, 0x6f, 0xf3, 0x34, - 0x14, 0x25, 0x4d, 0x5f, 0xd2, 0x9b, 0x74, 0x0b, 0x5e, 0x91, 0xbc, 0x02, 0x52, 0x28, 0x12, 0x8a, - 0x78, 0x49, 0xa1, 0xd3, 0xd0, 0x84, 0x10, 0x68, 0x1b, 0x9b, 0xa8, 0xd6, 0x95, 0xca, 0xdd, 0x98, - 0xf8, 0x14, 0xa5, 0xad, 0xdb, 0x46, 0x34, 0x4e, 0x49, 0x1c, 0xa4, 0xfc, 0x1d, 0xfe, 0x28, 0x8f, - 0x6c, 0xa7, 0x5d, 0x36, 0x65, 0xcf, 0xf3, 0x29, 0xf6, 0xf1, 0xb9, 0xf7, 0x9c, 0x1c, 0x5f, 0xc3, - 0xe9, 0x2e, 0x89, 0x79, 0x7c, 0xe6, 0xcb, 0xcf, 0x40, 0x6d, 0x3c, 0xf9, 0x41, 0x56, 0xf9, 0xa8, - 0x77, 0xba, 0x8e, 0xe3, 0xf5, 0x96, 0x2a, 0xca, 0x3c, 0x5b, 0x0d, 0x02, 0x96, 0x2b, 0x62, 0xef, - 0x84, 0xd3, 0x94, 0x2f, 0x03, 0x1e, 0x0c, 0xc4, 0x42, 0x81, 0xfd, 0xff, 0x5b, 0xd0, 0xba, 0xa7, - 0x69, 0x1a, 0xac, 0x29, 0x42, 0x50, 0x67, 0x41, 0x44, 0xb1, 0xe6, 0x68, 0x6e, 0x9b, 0xc8, 0x35, - 0xba, 0x00, 0x63, 0x13, 0x6e, 0x83, 0x24, 0xe4, 0x39, 0xae, 0x39, 0x9a, 0x7b, 0x34, 0xfc, 0xcc, - 0x2b, 0x0b, 0x7a, 0x45, 0xb1, 0xf7, 0x7b, 0x16, 0xc5, 0x59, 0x42, 0x0e, 0x6c, 0xe4, 0x80, 0xb5, - 0xa1, 0xe1, 0x7a, 0xc3, 0xfd, 0x90, 0xf9, 0x8b, 0x08, 0xeb, 0x8e, 0xe6, 0x76, 0x08, 0x28, 0x6c, - 0xc4, 0xae, 0x23, 0xa1, 0x27, 0xec, 0xe0, 0xba, 0xa3, 0xb9, 0x16, 0x91, 0x6b, 0xf4, 0x05, 0x58, - 0x09, 0x4d, 0xb3, 0x2d, 0xf7, 0x17, 0x71, 0xc6, 0x38, 0x6e, 0x39, 0x9a, 0xab, 0x13, 0x53, 0x61, - 0xd7, 0x02, 0x42, 0x5f, 0x42, 0x87, 0x27, 0x19, 0xf5, 0xd3, 0x45, 0xcc, 0xd3, 0x28, 0x60, 0xd8, - 0x70, 0x34, 0xd7, 0x20, 0x96, 0x00, 0x67, 0x05, 0x86, 0xba, 0xd0, 0x48, 0x17, 0x71, 0x42, 0x71, - 0xdb, 0xd1, 0xdc, 0x1a, 0x51, 0x1b, 0x64, 0x83, 0xfe, 0x37, 0xcd, 0x71, 0xc3, 0xd1, 0xdd, 0x3a, - 0x11, 0x4b, 0xf4, 0x29, 0xb4, 0xd3, 0x4d, 0x9c, 0x70, 0x5f, 0xe0, 0x27, 0x8e, 0xee, 0x36, 0x88, - 0x21, 0x81, 0x3b, 0x9a, 0xa3, 0x6f, 0xa1, 0xc9, 0x68, 0xca, 0xe9, 0x12, 0x37, 0x1d, 0xcd, 0x35, - 0x87, 0xdd, 0x97, 0xbf, 0x3e, 0x91, 0x67, 0xa4, 0xe0, 0xa0, 0x73, 0x68, 0x25, 0xfe, 0x2a, 0x63, - 0x2c, 0xc7, 0xb6, 0xa3, 0x7f, 0x30, 0xa9, 0x66, 0x72, 0x2b, 0xb8, 0xe8, 0x67, 0x68, 0x71, 0x9a, - 0x24, 0x41, 0xc8, 0x30, 0x38, 0xba, 0x6b, 0x0e, 0xfb, 0xd5, 0x65, 0x0f, 0x8a, 0x74, 0xc3, 0x78, - 0x92, 0x93, 0x7d, 0x09, 0xba, 0x00, 0x75, 0xff, 0x43, 0x7f, 0x15, 0xd2, 0xed, 0x12, 0x9b, 0xd2, - 0xe8, 0x27, 0xde, 0xfe, 0xae, 0xbd, 0x59, 0x36, 0xff, 0x8d, 0xae, 0x82, 0x6c, 0xcb, 0x53, 0x62, - 0x2a, 0xea, 0xad, 0x60, 0xa2, 0xd1, 0xa1, 0xf2, 0xdf, 0x60, 0x9b, 0x51, 0xdc, 0x91, 0xe2, 0x5f, - 0x55, 0x8b, 0x4f, 0x25, 0xf3, 0x4f, 0x41, 0x54, 0x06, 0x8a, 0x56, 0x12, 0x41, 0xdf, 0x83, 0x11, - 0xb0, 0x9c, 0x6f, 0x42, 0xb6, 0xc6, 0x47, 0x45, 0x52, 0x6a, 0x0e, 0xbd, 0xfd, 0x1c, 0x7a, 0x97, - 0x2c, 0x27, 0x07, 0x16, 0x3a, 0x07, 0x33, 0x0a, 0x58, 0xee, 0xcb, 0x5d, 0x8a, 0x8f, 0xa5, 0x76, - 0x75, 0x11, 0x08, 0xe2, 0x83, 0xe4, 0xa1, 0x73, 0x80, 0x34, 0x9b, 0x47, 0xca, 0x14, 0xfe, 0xb8, - 0xf8, 0xd7, 0x2a, 0xc7, 0xa4, 0x44, 0x44, 0x3f, 0x80, 0xb1, 0xd8, 0x84, 0xdb, 0x65, 0x42, 0x19, - 0x46, 0x52, 0xea, 0x8d, 0xa2, 0x03, 0xad, 0x37, 0x05, 0xab, 0x1c, 0xf8, 0x7e, 0x72, 0xd4, 0xd3, - 0x90, 0x93, 0xf3, 0x35, 0x34, 0x54, 0x70, 0xb5, 0xf7, 0xcc, 0x86, 0xa2, 0xfc, 0x54, 0xbb, 0xd0, - 0x7a, 0x8f, 0x60, 0xbf, 0x4e, 0xb1, 0xa2, 0xeb, 0x37, 0x2f, 0xbb, 0xbe, 0x71, 0x91, 0xcf, 0x6d, - 0xfb, 0xbf, 0x42, 0x53, 0x0d, 0x14, 0x32, 0xa1, 0xf5, 0x38, 0xb9, 0x9b, 0xfc, 0xf1, 0x34, 0xb1, - 0x3f, 0x42, 0x06, 0xd4, 0xa7, 0x8f, 0x93, 0x99, 0xad, 0xa1, 0x0e, 0xb4, 0x67, 0xe3, 0xcb, 0xe9, - 0xec, 0x61, 0x74, 0x7d, 0x67, 0xd7, 0xd0, 0x31, 0x98, 0x57, 0xa3, 0xf1, 0xd8, 0xbf, 0xba, 0x1c, - 0x8d, 0x6f, 0xfe, 0xb2, 0xf5, 0xfe, 0x10, 0x9a, 0xca, 0xac, 0x78, 0x33, 0x73, 0x39, 0xbe, 0xca, - 0x8f, 0xda, 0x88, 0x57, 0xba, 0xc8, 0xb8, 0x32, 0x64, 0x10, 0xb9, 0xee, 0xff, 0xa7, 0xc1, 0x51, - 0x91, 0xd9, 0x53, 0xc8, 0x37, 0xf7, 0xc1, 0x0e, 0x4d, 0xc1, 0x9a, 0xe7, 0x9c, 0xfa, 0x51, 0xb0, - 0xdb, 0x89, 0x39, 0xd0, 0x64, 0xce, 0xdf, 0x55, 0xe6, 0x5c, 0xd4, 0x78, 0x57, 0x39, 0xa7, 0xf7, - 0x8a, 0x5f, 0x4c, 0xd5, 0xfc, 0x19, 0xe9, 0xfd, 0x02, 0xf6, 0x6b, 0x42, 0x39, 0x30, 0x43, 0x05, - 0xd6, 0x2d, 0x07, 0x66, 0x95, 0x93, 0xf9, 0x07, 0x9a, 0x23, 0xc6, 0x85, 0xb7, 0x01, 0xe8, 0x09, - 0xe7, 0x85, 0xa5, 0xcf, 0x5f, 0x5a, 0x52, 0x14, 0x8f, 0x70, 0xae, 0x2c, 0x08, 0x66, 0xef, 0x47, - 0x30, 0xf6, 0x40, 0x59, 0xb2, 0x51, 0x21, 0xd9, 0x28, 0x4b, 0x9e, 0x41, 0x4b, 0xf5, 0x4b, 0x91, - 0x0b, 0xf5, 0x28, 0xd8, 0xa5, 0x85, 0x68, 0xb7, 0x4a, 0x94, 0x48, 0xc6, 0xbc, 0xa9, 0x8e, 0xde, - 0x05, 0x00, 0x00, 0xff, 0xff, 0x75, 0x38, 0xad, 0x84, 0xe4, 0x05, 0x00, 0x00, +var fileDescriptor_proto3_78ae00cd7e6e5e35 = []byte{ + // 896 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0x6f, 0x6f, 0xdb, 0xb6, + 0x13, 0xae, 0x2c, 0xff, 0x91, 0xcf, 0x76, 0xea, 0x1f, 0x7f, 0x6e, 0xc7, 0x7a, 0x1b, 0xa0, 0x79, + 0xc3, 0x20, 0x0c, 0xab, 0xb2, 0xb9, 0xc8, 0x90, 0xb5, 0xc5, 0x86, 0x24, 0x6b, 0x50, 0x23, 0xb1, + 0x67, 0xd0, 0xce, 0x82, 0xbd, 0x12, 0x68, 0x87, 0xb6, 0x85, 0x59, 0x94, 0x27, 0x52, 0x05, 0xf4, + 0x05, 0xf6, 0x41, 0xf6, 0x95, 0xf6, 0x85, 0x06, 0x92, 0x72, 0x2a, 0x17, 0xea, 0xf2, 0x4a, 0xbc, + 0x47, 0xcf, 0xdd, 0x73, 0xbc, 0x3b, 0x1e, 0x3c, 0xdb, 0x25, 0xb1, 0x8c, 0x5f, 0x04, 0xfa, 0x73, + 0x6c, 0x0c, 0x5f, 0x7f, 0x50, 0xbb, 0xf8, 0xab, 0xff, 0x6c, 0x1d, 0xc7, 0xeb, 0x2d, 0x33, 0x94, + 0x45, 0xba, 0x3a, 0xa6, 0x3c, 0x33, 0xc4, 0xfe, 0x13, 0xc9, 0x84, 0xcc, 0x23, 0xa8, 0xa3, 0x81, + 0x07, 0x7f, 0x35, 0xa1, 0x31, 0x66, 0x42, 0xd0, 0x35, 0x43, 0x08, 0xaa, 0x9c, 0x46, 0x0c, 0x5b, + 0xae, 0xe5, 0x35, 0x89, 0x3e, 0xa3, 0x53, 0x70, 0x36, 0xe1, 0x96, 0x26, 0xa1, 0xcc, 0x70, 0xc5, + 0xb5, 0xbc, 0xa3, 0xe1, 0x67, 0x7e, 0x51, 0xd2, 0xcf, 0x9d, 0xfd, 0xb7, 0x69, 0x14, 0xa7, 0x09, + 0xb9, 0x67, 0x23, 0x17, 0xda, 0x1b, 0x16, 0xae, 0x37, 0x32, 0x08, 0x79, 0xb0, 0x8c, 0xb0, 0xed, + 0x5a, 0x5e, 0x87, 0x80, 0xc1, 0x46, 0xfc, 0x22, 0x52, 0x7a, 0x77, 0x54, 0x52, 0x5c, 0x75, 0x2d, + 0xaf, 0x4d, 0xf4, 0x19, 0x7d, 0x01, 0xed, 0x84, 0x89, 0x74, 0x2b, 0x83, 0x65, 0x9c, 0x72, 0x89, + 0x1b, 0xae, 0xe5, 0xd9, 0xa4, 0x65, 0xb0, 0x0b, 0x05, 0xa1, 0x2f, 0xa1, 0x23, 0x93, 0x94, 0x05, + 0x62, 0x19, 0x4b, 0x11, 0x51, 0x8e, 0x1d, 0xd7, 0xf2, 0x1c, 0xd2, 0x56, 0xe0, 0x2c, 0xc7, 0x50, + 0x0f, 0x6a, 0x62, 0x19, 0x27, 0x0c, 0x37, 0x5d, 0xcb, 0xab, 0x10, 0x63, 0xa0, 0x2e, 0xd8, 0x7f, + 0xb0, 0x0c, 0xd7, 0x5c, 0xdb, 0xab, 0x12, 0x75, 0x44, 0x9f, 0x42, 0x53, 0x6c, 0xe2, 0x44, 0x06, + 0x0a, 0xff, 0xbf, 0x6b, 0x7b, 0x35, 0xe2, 0x68, 0xe0, 0x8a, 0x65, 0xe8, 0x5b, 0xa8, 0x73, 0x26, + 0x24, 0xbb, 0xc3, 0x75, 0xd7, 0xf2, 0x5a, 0xc3, 0xde, 0xe1, 0xd5, 0x27, 0xfa, 0x1f, 0xc9, 0x39, + 0xe8, 0x04, 0x1a, 0x49, 0xb0, 0x4a, 0x39, 0xcf, 0x70, 0xd7, 0xb5, 0x1f, 0xac, 0x54, 0x3d, 0xb9, + 0x54, 0x5c, 0xf4, 0x1a, 0x1a, 0x92, 0x25, 0x09, 0x0d, 0x39, 0x06, 0xd7, 0xf6, 0x5a, 0xc3, 0x41, + 0xb9, 0xdb, 0xdc, 0x90, 0xde, 0x70, 0x99, 0x64, 0x64, 0xef, 0x82, 0x5e, 0x82, 0x99, 0x80, 0x61, + 0xb0, 0x0a, 0xd9, 0xf6, 0x0e, 0xb7, 0x74, 0xa2, 0x9f, 0xf8, 0xef, 0xbb, 0xed, 0xcf, 0xd2, 0xc5, + 0x2f, 0x6c, 0x45, 0xd3, 0xad, 0x14, 0xa4, 0x65, 0xc8, 0x97, 0x8a, 0x8b, 0x46, 0xf7, 0xbe, 0xef, + 0xe8, 0x36, 0x65, 0xb8, 0xa3, 0xe5, 0xbf, 0x2e, 0x97, 0x9f, 0x6a, 0xe6, 0x6f, 0x8a, 0x68, 0x52, + 0xc8, 0x43, 0x69, 0x04, 0x7d, 0x07, 0x0e, 0xe5, 0x99, 0xdc, 0x84, 0x7c, 0x8d, 0x8f, 0xf2, 0x5a, + 0x99, 0x59, 0xf4, 0xf7, 0xb3, 0xe8, 0x9f, 0xf1, 0x8c, 0xdc, 0xb3, 0xd0, 0x09, 0xb4, 0x22, 0xca, + 0xb3, 0x40, 0x5b, 0x02, 0x3f, 0xd6, 0xda, 0xe5, 0x4e, 0xa0, 0x88, 0x73, 0xcd, 0x43, 0x27, 0x00, + 0x22, 0x5d, 0x44, 0x26, 0x29, 0xfc, 0x3f, 0x2d, 0xf5, 0xa4, 0x34, 0x63, 0x52, 0x20, 0xa2, 0xef, + 0xc1, 0x59, 0x6e, 0xc2, 0xed, 0x5d, 0xc2, 0x38, 0x46, 0x5a, 0xea, 0x23, 0x4e, 0xf7, 0x34, 0x74, + 0x01, 0x20, 0x64, 0x12, 0xf2, 0x75, 0x10, 0xd1, 0x1d, 0xee, 0x69, 0xa7, 0xaf, 0xca, 0x6b, 0x33, + 0xd3, 0xbc, 0x31, 0xdd, 0x99, 0xca, 0x34, 0xc5, 0xde, 0xee, 0x4f, 0xa1, 0x5d, 0xec, 0xdb, 0x7e, + 0x00, 0xcd, 0x0b, 0xd3, 0x03, 0xf8, 0x0d, 0xd4, 0x4c, 0xf5, 0x2b, 0xff, 0x31, 0x62, 0x86, 0xf2, + 0xb2, 0x72, 0x6a, 0xf5, 0x6f, 0xa1, 0xfb, 0x61, 0x2b, 0x4a, 0xa2, 0x3e, 0x3f, 0x8c, 0xfa, 0xd1, + 0x79, 0x28, 0x04, 0x7e, 0x0d, 0x47, 0x87, 0xf7, 0x28, 0x09, 0xdb, 0x2b, 0x86, 0x6d, 0x16, 0xbc, + 0x07, 0x3f, 0x43, 0xdd, 0xcc, 0x35, 0x6a, 0x41, 0xe3, 0x66, 0x72, 0x35, 0xf9, 0xf5, 0x76, 0xd2, + 0x7d, 0x84, 0x1c, 0xa8, 0x4e, 0x6f, 0x26, 0xb3, 0xae, 0x85, 0x3a, 0xd0, 0x9c, 0x5d, 0x9f, 0x4d, + 0x67, 0xf3, 0xd1, 0xc5, 0x55, 0xb7, 0x82, 0x1e, 0x43, 0xeb, 0x7c, 0x74, 0x7d, 0x1d, 0x9c, 0x9f, + 0x8d, 0xae, 0xdf, 0xfc, 0xde, 0xb5, 0x07, 0x43, 0xa8, 0x9b, 0xcb, 0x2a, 0x91, 0x85, 0x7e, 0x45, + 0x46, 0xd8, 0x18, 0x6a, 0x59, 0x2c, 0x53, 0x69, 0x94, 0x1d, 0xa2, 0xcf, 0x83, 0xbf, 0x2d, 0x38, + 0xca, 0x7b, 0x70, 0x1b, 0xca, 0xcd, 0x98, 0xee, 0xd0, 0x14, 0xda, 0x8b, 0x4c, 0x32, 0xd5, 0xb3, + 0x9d, 0x1a, 0x46, 0x4b, 0xf7, 0xed, 0x79, 0x69, 0xdf, 0x72, 0x1f, 0xff, 0x3c, 0x93, 0x6c, 0x6c, + 0xf8, 0xf9, 0x68, 0x2f, 0xde, 0x23, 0xfd, 0x9f, 0xa0, 0xfb, 0x21, 0xa1, 0x58, 0x19, 0xa7, 0xa4, + 0x32, 0xed, 0x62, 0x65, 0xfe, 0x84, 0xfa, 0x88, 0x4b, 0x95, 0xdb, 0x31, 0xd8, 0x89, 0x94, 0x79, + 0x4a, 0x9f, 0x1f, 0xa6, 0x64, 0x28, 0x3e, 0x91, 0xd2, 0xa4, 0xa0, 0x98, 0xfd, 0x1f, 0xc0, 0xd9, + 0x03, 0x45, 0xc9, 0x5a, 0x89, 0x64, 0xad, 0x28, 0xf9, 0x02, 0x1a, 0x26, 0x9e, 0x40, 0x1e, 0x54, + 0x23, 0xba, 0x13, 0xb9, 0x68, 0xaf, 0x4c, 0x94, 0x68, 0xc6, 0xe0, 0x9f, 0x0a, 0x38, 0x73, 0x26, + 0xe4, 0xcd, 0xfc, 0xf2, 0x14, 0x3d, 0x85, 0xba, 0x58, 0xd2, 0x2d, 0x4d, 0xf2, 0x26, 0xe4, 0x96, + 0xc2, 0xdf, 0xb1, 0xa5, 0x8c, 0x13, 0x5c, 0x71, 0x6d, 0x85, 0x1b, 0x0b, 0x3d, 0x85, 0x9a, 0xd9, + 0x3f, 0x6a, 0xcb, 0x37, 0xdf, 0x3e, 0x22, 0xc6, 0x44, 0xaf, 0xa0, 0x11, 0xd1, 0x9d, 0x5e, 0xae, + 0xd5, 0xb2, 0xe5, 0xb6, 0x17, 0xf4, 0xc7, 0x74, 0x77, 0xc5, 0x32, 0x73, 0xf7, 0x7a, 0xa4, 0x0d, + 0x74, 0x06, 0x4d, 0xe5, 0x6c, 0x2e, 0x59, 0x2b, 0x7b, 0x80, 0x45, 0xf7, 0xc2, 0x6a, 0x72, 0xa2, + 0xdc, 0xec, 0xff, 0x08, 0xad, 0x42, 0xe4, 0x87, 0x26, 0xda, 0x2e, 0xbe, 0x87, 0x57, 0xd0, 0x39, + 0x88, 0x5a, 0x74, 0xb6, 0x1f, 0x78, 0x0e, 0xe7, 0x0d, 0xa8, 0xc5, 0x9c, 0xc5, 0xab, 0x45, 0xdd, + 0xe4, 0xfb, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x74, 0x17, 0x7f, 0xc3, 0x07, 0x00, 0x00, } diff --git a/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.proto b/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.proto index 20486557..6adea22f 100644 --- a/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.proto +++ b/vendor/github.com/golang/protobuf/proto/proto3_proto/proto3.proto @@ -32,7 +32,7 @@ syntax = "proto3"; import "google/protobuf/any.proto"; -import "testdata/test.proto"; +import "test_proto/test.proto"; package proto3_proto; @@ -58,14 +58,16 @@ message Message { repeated Humour r_funny = 16; map terrain = 10; - testdata.SubDefaults proto2_field = 11; - map proto2_value = 13; + test_proto.SubDefaults proto2_field = 11; + map proto2_value = 13; google.protobuf.Any anything = 14; repeated google.protobuf.Any many_things = 15; Message submessage = 17; repeated Message children = 18; + + map string_map = 20; } message Nested { @@ -85,3 +87,11 @@ message IntMap { message IntMaps { repeated IntMap maps = 1; } + +message TestUTF8 { + string scalar = 1; + repeated string vector = 2; + oneof oneof { string field = 3; } + map map_key = 4; + map map_value = 5; +} diff --git a/vendor/github.com/golang/protobuf/proto/proto3_test.go b/vendor/github.com/golang/protobuf/proto/proto3_test.go index 735837f2..73eed6c0 100644 --- a/vendor/github.com/golang/protobuf/proto/proto3_test.go +++ b/vendor/github.com/golang/protobuf/proto/proto3_test.go @@ -32,11 +32,12 @@ package proto_test import ( + "bytes" "testing" "github.com/golang/protobuf/proto" pb "github.com/golang/protobuf/proto/proto3_proto" - tpb "github.com/golang/protobuf/proto/testdata" + tpb "github.com/golang/protobuf/proto/test_proto" ) func TestProto3ZeroValues(t *testing.T) { @@ -133,3 +134,18 @@ func TestProto3SetDefaults(t *testing.T) { t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) } } + +func TestUnknownFieldPreservation(t *testing.T) { + b1 := "\x0a\x05David" // Known tag 1 + b2 := "\xc2\x0c\x06Google" // Unknown tag 200 + b := []byte(b1 + b2) + + m := new(pb.Message) + if err := proto.Unmarshal(b, m); err != nil { + t.Fatalf("proto.Unmarshal: %v", err) + } + + if !bytes.Equal(m.XXX_unrecognized, []byte(b2)) { + t.Fatalf("mismatching unknown fields:\ngot %q\nwant %q", m.XXX_unrecognized, b2) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/size2_test.go b/vendor/github.com/golang/protobuf/proto/size2_test.go index a2729c39..7846b061 100644 --- a/vendor/github.com/golang/protobuf/proto/size2_test.go +++ b/vendor/github.com/golang/protobuf/proto/size2_test.go @@ -55,7 +55,7 @@ func TestVarintSize(t *testing.T) { {1 << 63, 10}, } for _, tc := range testCases { - size := sizeVarint(tc.n) + size := SizeVarint(tc.n) if size != tc.size { t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) } diff --git a/vendor/github.com/golang/protobuf/proto/size_test.go b/vendor/github.com/golang/protobuf/proto/size_test.go index af1034dc..3abac418 100644 --- a/vendor/github.com/golang/protobuf/proto/size_test.go +++ b/vendor/github.com/golang/protobuf/proto/size_test.go @@ -38,7 +38,7 @@ import ( . "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" + pb "github.com/golang/protobuf/proto/test_proto" ) var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} @@ -59,6 +59,30 @@ func init() { } +// non-pointer custom message +type nonptrMessage struct{} + +func (m nonptrMessage) ProtoMessage() {} +func (m nonptrMessage) Reset() {} +func (m nonptrMessage) String() string { return "" } + +func (m nonptrMessage) Marshal() ([]byte, error) { + return []byte{42}, nil +} + +// custom message embedding a proto.Message +type messageWithEmbedding struct { + *pb.OtherMessage +} + +func (m *messageWithEmbedding) ProtoMessage() {} +func (m *messageWithEmbedding) Reset() {} +func (m *messageWithEmbedding) String() string { return "" } + +func (m *messageWithEmbedding) Marshal() ([]byte, error) { + return []byte{42}, nil +} + var SizeTests = []struct { desc string pb Message @@ -146,6 +170,9 @@ var SizeTests = []struct { {"oneof group", &pb.Oneof{Union: &pb.Oneof_FGroup{&pb.Oneof_F_Group{X: Int32(52)}}}}, {"oneof largest tag", &pb.Oneof{Union: &pb.Oneof_F_Largest_Tag{1}}}, {"multiple oneofs", &pb.Oneof{Union: &pb.Oneof_F_Int32{1}, Tormato: &pb.Oneof_Value{2}}}, + + {"non-pointer message", nonptrMessage{}}, + {"custom message with embedding", &messageWithEmbedding{&pb.OtherMessage{}}}, } func TestSize(t *testing.T) { diff --git a/vendor/github.com/golang/protobuf/proto/table_marshal.go b/vendor/github.com/golang/protobuf/proto/table_marshal.go new file mode 100644 index 00000000..b1679449 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_marshal.go @@ -0,0 +1,2767 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "errors" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// a sizer takes a pointer to a field and the size of its tag, computes the size of +// the encoded data. +type sizer func(pointer, int) int + +// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format), +// marshals the field to the end of the slice, returns the slice and error (if any). +type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) + +// marshalInfo is the information used for marshaling a message. +type marshalInfo struct { + typ reflect.Type + fields []*marshalFieldInfo + unrecognized field // offset of XXX_unrecognized + extensions field // offset of XXX_InternalExtensions + v1extensions field // offset of XXX_extensions + sizecache field // offset of XXX_sizecache + initialized int32 // 0 -- only typ is set, 1 -- fully initialized + messageset bool // uses message set wire format + hasmarshaler bool // has custom marshaler + sync.RWMutex // protect extElems map, also for initialization + extElems map[int32]*marshalElemInfo // info of extension elements +} + +// marshalFieldInfo is the information used for marshaling a field of a message. +type marshalFieldInfo struct { + field field + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isPointer bool + required bool // field is required + name string // name of the field, for error reporting + oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements +} + +// marshalElemInfo is the information used for marshaling an extension or oneof element. +type marshalElemInfo struct { + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) +} + +var ( + marshalInfoMap = map[reflect.Type]*marshalInfo{} + marshalInfoLock sync.Mutex +) + +// getMarshalInfo returns the information to marshal a given type of message. +// The info it returns may not necessarily initialized. +// t is the type of the message (NOT the pointer to it). +func getMarshalInfo(t reflect.Type) *marshalInfo { + marshalInfoLock.Lock() + u, ok := marshalInfoMap[t] + if !ok { + u = &marshalInfo{typ: t} + marshalInfoMap[t] = u + } + marshalInfoLock.Unlock() + return u +} + +// Size is the entry point from generated code, +// and should be ONLY called by generated code. +// It computes the size of encoded data of msg. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Size(msg Message) int { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return 0 + } + return u.size(ptr) +} + +// Marshal is the entry point from generated code, +// and should be ONLY called by generated code. +// It marshals msg to the end of b. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return b, ErrNil + } + return u.marshal(b, ptr, deterministic) +} + +func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo { + // u := a.marshal, but atomically. + // We use an atomic here to ensure memory consistency. + u := atomicLoadMarshalInfo(&a.marshal) + if u == nil { + // Get marshal information from type of message. + t := reflect.ValueOf(msg).Type() + if t.Kind() != reflect.Ptr { + panic(fmt.Sprintf("cannot handle non-pointer message type %v", t)) + } + u = getMarshalInfo(t.Elem()) + // Store it in the cache for later users. + // a.marshal = u, but atomically. + atomicStoreMarshalInfo(&a.marshal, u) + } + return u +} + +// size is the main function to compute the size of the encoded data of a message. +// ptr is the pointer to the message. +func (u *marshalInfo) size(ptr pointer) int { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b, _ := m.Marshal() + return len(b) + } + + n := 0 + for _, f := range u.fields { + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + n += f.sizer(ptr.offset(f.field), f.tagsize) + } + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + n += u.sizeMessageSet(e) + } else { + n += u.sizeExtensions(e) + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + n += u.sizeV1Extensions(m) + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + n += len(s) + } + // cache the result for use in marshal + if u.sizecache.IsValid() { + atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n)) + } + return n +} + +// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated), +// fall back to compute the size. +func (u *marshalInfo) cachedsize(ptr pointer) int { + if u.sizecache.IsValid() { + return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32())) + } + return u.size(ptr) +} + +// marshal is the main function to marshal a message. It takes a byte slice and appends +// the encoded data to the end of the slice, returns the slice and error (if any). +// ptr is the pointer to the message. +// If deterministic is true, map is marshaled in deterministic order. +func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b1, err := m.Marshal() + b = append(b, b1...) + return b, err + } + + var err, errLater error + // The old marshaler encodes extensions at beginning. + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + b, err = u.appendMessageSet(b, e, deterministic) + } else { + b, err = u.appendExtensions(b, e, deterministic) + } + if err != nil { + return b, err + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + b, err = u.appendV1Extensions(b, m, deterministic) + if err != nil { + return b, err + } + } + for _, f := range u.fields { + if f.required { + if ptr.offset(f.field).getPointer().isNil() { + // Required field is not set. + // We record the error but keep going, to give a complete marshaling. + if errLater == nil { + errLater = &RequiredNotSetError{f.name} + } + continue + } + } + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic) + if err != nil { + if err1, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errLater == nil { + errLater = &RequiredNotSetError{f.name + "." + err1.field} + } + continue + } + if err == errRepeatedHasNil { + err = errors.New("proto: repeated field " + f.name + " has nil element") + } + if err == errInvalidUTF8 { + if errLater == nil { + fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name + errLater = &invalidUTF8Error{fullName} + } + continue + } + return b, err + } + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + b = append(b, s...) + } + return b, errLater +} + +// computeMarshalInfo initializes the marshal info. +func (u *marshalInfo) computeMarshalInfo() { + u.Lock() + defer u.Unlock() + if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock + return + } + + t := u.typ + u.unrecognized = invalidField + u.extensions = invalidField + u.v1extensions = invalidField + u.sizecache = invalidField + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if reflect.PtrTo(t).Implements(marshalerType) { + u.hasmarshaler = true + atomic.StoreInt32(&u.initialized, 1) + return + } + + // get oneof implementers + var oneofImplementers []interface{} + if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + } + + n := t.NumField() + + // deal with XXX fields first + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if !strings.HasPrefix(f.Name, "XXX_") { + continue + } + switch f.Name { + case "XXX_sizecache": + u.sizecache = toField(&f) + case "XXX_unrecognized": + u.unrecognized = toField(&f) + case "XXX_InternalExtensions": + u.extensions = toField(&f) + u.messageset = f.Tag.Get("protobuf_messageset") == "1" + case "XXX_extensions": + u.v1extensions = toField(&f) + case "XXX_NoUnkeyedLiteral": + // nothing to do + default: + panic("unknown XXX field: " + f.Name) + } + n-- + } + + // normal fields + fields := make([]marshalFieldInfo, n) // batch allocation + u.fields = make([]*marshalFieldInfo, 0, n) + for i, j := 0, 0; i < t.NumField(); i++ { + f := t.Field(i) + + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + field := &fields[j] + j++ + field.name = f.Name + u.fields = append(u.fields, field) + if f.Tag.Get("protobuf_oneof") != "" { + field.computeOneofFieldInfo(&f, oneofImplementers) + continue + } + if f.Tag.Get("protobuf") == "" { + // field has no tag (not in generated message), ignore it + u.fields = u.fields[:len(u.fields)-1] + j-- + continue + } + field.computeMarshalFieldInfo(&f) + } + + // fields are marshaled in tag order on the wire. + sort.Sort(byTag(u.fields)) + + atomic.StoreInt32(&u.initialized, 1) +} + +// helper for sorting fields by tag +type byTag []*marshalFieldInfo + +func (a byTag) Len() int { return len(a) } +func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag } + +// getExtElemInfo returns the information to marshal an extension element. +// The info it returns is initialized. +func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { + // get from cache first + u.RLock() + e, ok := u.extElems[desc.Field] + u.RUnlock() + if ok { + return e + } + + t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct + tags := strings.Split(desc.Tag, ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizer, marshaler := typeMarshaler(t, tags, false, false) + e = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizer, + marshaler: marshaler, + isptr: t.Kind() == reflect.Ptr, + } + + // update cache + u.Lock() + if u.extElems == nil { + u.extElems = make(map[int32]*marshalElemInfo) + } + u.extElems[desc.Field] = e + u.Unlock() + return e +} + +// computeMarshalFieldInfo fills up the information to marshal a field. +func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { + // parse protobuf tag of the field. + // tag has format of "bytes,49,opt,name=foo,def=hello!" + tags := strings.Split(f.Tag.Get("protobuf"), ",") + if tags[0] == "" { + return + } + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + if tags[2] == "req" { + fi.required = true + } + fi.setTag(f, tag, wt) + fi.setMarshaler(f, tags) +} + +func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { + fi.field = toField(f) + fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. + fi.isPointer = true + fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) + fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) + + ityp := f.Type // interface type + for _, o := range oneofImplementers { + t := reflect.TypeOf(o) + if !t.Implements(ityp) { + continue + } + sf := t.Elem().Field(0) // oneof implementer is a struct with a single field + tags := strings.Split(sf.Tag.Get("protobuf"), ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizer, marshaler := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value + fi.oneofElems[t.Elem()] = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizer, + marshaler: marshaler, + } + } +} + +type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) +} + +// wiretype returns the wire encoding of the type. +func wiretype(encoding string) uint64 { + switch encoding { + case "fixed32": + return WireFixed32 + case "fixed64": + return WireFixed64 + case "varint", "zigzag32", "zigzag64": + return WireVarint + case "bytes": + return WireBytes + case "group": + return WireStartGroup + } + panic("unknown wire type " + encoding) +} + +// setTag fills up the tag (in wire format) and its size in the info of a field. +func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) { + fi.field = toField(f) + fi.wiretag = uint64(tag)<<3 | wt + fi.tagsize = SizeVarint(uint64(tag) << 3) +} + +// setMarshaler fills up the sizer and marshaler in the info of a field. +func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) { + switch f.Type.Kind() { + case reflect.Map: + // map field + fi.isPointer = true + fi.sizer, fi.marshaler = makeMapMarshaler(f) + return + case reflect.Ptr, reflect.Slice: + fi.isPointer = true + } + fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false) +} + +// typeMarshaler returns the sizer and marshaler of a given field. +// t is the type of the field. +// tags is the generated "protobuf" tag of the field. +// If nozero is true, zero value is not marshaled to the wire. +// If oneof is true, it is a oneof field. +func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) { + encoding := tags[0] + + pointer := false + slice := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + packed := false + proto3 := false + validateUTF8 := true + for i := 2; i < len(tags); i++ { + if tags[i] == "packed" { + packed = true + } + if tags[i] == "proto3" { + proto3 = true + } + } + validateUTF8 = validateUTF8 && proto3 + + switch t.Kind() { + case reflect.Bool: + if pointer { + return sizeBoolPtr, appendBoolPtr + } + if slice { + if packed { + return sizeBoolPackedSlice, appendBoolPackedSlice + } + return sizeBoolSlice, appendBoolSlice + } + if nozero { + return sizeBoolValueNoZero, appendBoolValueNoZero + } + return sizeBoolValue, appendBoolValue + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixed32Ptr, appendFixed32Ptr + } + if slice { + if packed { + return sizeFixed32PackedSlice, appendFixed32PackedSlice + } + return sizeFixed32Slice, appendFixed32Slice + } + if nozero { + return sizeFixed32ValueNoZero, appendFixed32ValueNoZero + } + return sizeFixed32Value, appendFixed32Value + case "varint": + if pointer { + return sizeVarint32Ptr, appendVarint32Ptr + } + if slice { + if packed { + return sizeVarint32PackedSlice, appendVarint32PackedSlice + } + return sizeVarint32Slice, appendVarint32Slice + } + if nozero { + return sizeVarint32ValueNoZero, appendVarint32ValueNoZero + } + return sizeVarint32Value, appendVarint32Value + } + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixedS32Ptr, appendFixedS32Ptr + } + if slice { + if packed { + return sizeFixedS32PackedSlice, appendFixedS32PackedSlice + } + return sizeFixedS32Slice, appendFixedS32Slice + } + if nozero { + return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero + } + return sizeFixedS32Value, appendFixedS32Value + case "varint": + if pointer { + return sizeVarintS32Ptr, appendVarintS32Ptr + } + if slice { + if packed { + return sizeVarintS32PackedSlice, appendVarintS32PackedSlice + } + return sizeVarintS32Slice, appendVarintS32Slice + } + if nozero { + return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero + } + return sizeVarintS32Value, appendVarintS32Value + case "zigzag32": + if pointer { + return sizeZigzag32Ptr, appendZigzag32Ptr + } + if slice { + if packed { + return sizeZigzag32PackedSlice, appendZigzag32PackedSlice + } + return sizeZigzag32Slice, appendZigzag32Slice + } + if nozero { + return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero + } + return sizeZigzag32Value, appendZigzag32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixed64Ptr, appendFixed64Ptr + } + if slice { + if packed { + return sizeFixed64PackedSlice, appendFixed64PackedSlice + } + return sizeFixed64Slice, appendFixed64Slice + } + if nozero { + return sizeFixed64ValueNoZero, appendFixed64ValueNoZero + } + return sizeFixed64Value, appendFixed64Value + case "varint": + if pointer { + return sizeVarint64Ptr, appendVarint64Ptr + } + if slice { + if packed { + return sizeVarint64PackedSlice, appendVarint64PackedSlice + } + return sizeVarint64Slice, appendVarint64Slice + } + if nozero { + return sizeVarint64ValueNoZero, appendVarint64ValueNoZero + } + return sizeVarint64Value, appendVarint64Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixedS64Ptr, appendFixedS64Ptr + } + if slice { + if packed { + return sizeFixedS64PackedSlice, appendFixedS64PackedSlice + } + return sizeFixedS64Slice, appendFixedS64Slice + } + if nozero { + return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero + } + return sizeFixedS64Value, appendFixedS64Value + case "varint": + if pointer { + return sizeVarintS64Ptr, appendVarintS64Ptr + } + if slice { + if packed { + return sizeVarintS64PackedSlice, appendVarintS64PackedSlice + } + return sizeVarintS64Slice, appendVarintS64Slice + } + if nozero { + return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero + } + return sizeVarintS64Value, appendVarintS64Value + case "zigzag64": + if pointer { + return sizeZigzag64Ptr, appendZigzag64Ptr + } + if slice { + if packed { + return sizeZigzag64PackedSlice, appendZigzag64PackedSlice + } + return sizeZigzag64Slice, appendZigzag64Slice + } + if nozero { + return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero + } + return sizeZigzag64Value, appendZigzag64Value + } + case reflect.Float32: + if pointer { + return sizeFloat32Ptr, appendFloat32Ptr + } + if slice { + if packed { + return sizeFloat32PackedSlice, appendFloat32PackedSlice + } + return sizeFloat32Slice, appendFloat32Slice + } + if nozero { + return sizeFloat32ValueNoZero, appendFloat32ValueNoZero + } + return sizeFloat32Value, appendFloat32Value + case reflect.Float64: + if pointer { + return sizeFloat64Ptr, appendFloat64Ptr + } + if slice { + if packed { + return sizeFloat64PackedSlice, appendFloat64PackedSlice + } + return sizeFloat64Slice, appendFloat64Slice + } + if nozero { + return sizeFloat64ValueNoZero, appendFloat64ValueNoZero + } + return sizeFloat64Value, appendFloat64Value + case reflect.String: + if validateUTF8 { + if pointer { + return sizeStringPtr, appendUTF8StringPtr + } + if slice { + return sizeStringSlice, appendUTF8StringSlice + } + if nozero { + return sizeStringValueNoZero, appendUTF8StringValueNoZero + } + return sizeStringValue, appendUTF8StringValue + } + if pointer { + return sizeStringPtr, appendStringPtr + } + if slice { + return sizeStringSlice, appendStringSlice + } + if nozero { + return sizeStringValueNoZero, appendStringValueNoZero + } + return sizeStringValue, appendStringValue + case reflect.Slice: + if slice { + return sizeBytesSlice, appendBytesSlice + } + if oneof { + // Oneof bytes field may also have "proto3" tag. + // We want to marshal it as a oneof field. Do this + // check before the proto3 check. + return sizeBytesOneof, appendBytesOneof + } + if proto3 { + return sizeBytes3, appendBytes3 + } + return sizeBytes, appendBytes + case reflect.Struct: + switch encoding { + case "group": + if slice { + return makeGroupSliceMarshaler(getMarshalInfo(t)) + } + return makeGroupMarshaler(getMarshalInfo(t)) + case "bytes": + if slice { + return makeMessageSliceMarshaler(getMarshalInfo(t)) + } + return makeMessageMarshaler(getMarshalInfo(t)) + } + } + panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding)) +} + +// Below are functions to size/marshal a specific type of a field. +// They are stored in the field's info, and called by function pointers. +// They have type sizer or marshaler. + +func sizeFixed32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixed32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixedS32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFloat32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + return (4 + tagsize) * len(s) +} +func sizeFloat32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixed64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixed64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFixedS64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFloat64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + return (8 + tagsize) * len(s) +} +func sizeFloat64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeVarint32Value(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarint32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarint32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarint64Value(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + return SizeVarint(v) + tagsize +} +func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return SizeVarint(v) + tagsize +} +func sizeVarint64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return SizeVarint(*p) + tagsize +} +func sizeVarint64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(v) + tagsize + } + return n +} +func sizeVarint64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize + } + return n +} +func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize + } + return n +} +func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeBoolValue(_ pointer, tagsize int) int { + return 1 + tagsize +} +func sizeBoolValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toBool() + if !v { + return 0 + } + return 1 + tagsize +} +func sizeBoolPtr(ptr pointer, tagsize int) int { + p := *ptr.toBoolPtr() + if p == nil { + return 0 + } + return 1 + tagsize +} +func sizeBoolSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + return (1 + tagsize) * len(s) +} +func sizeBoolPackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return 0 + } + return len(s) + SizeVarint(uint64(len(s))) + tagsize +} +func sizeStringValue(ptr pointer, tagsize int) int { + v := *ptr.toString() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toString() + if v == "" { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringPtr(ptr pointer, tagsize int) int { + p := *ptr.toStringPtr() + if p == nil { + return 0 + } + v := *p + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringSlice(ptr pointer, tagsize int) int { + s := *ptr.toStringSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} +func sizeBytes(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if v == nil { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytes3(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if len(v) == 0 { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesOneof(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesSlice(ptr pointer, tagsize int) int { + s := *ptr.toBytesSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} + +// appendFixed32 appends an encoded fixed32 to b. +func appendFixed32(b []byte, v uint32) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24)) + return b +} + +// appendFixed64 appends an encoded fixed64 to b. +func appendFixed64(b []byte, v uint64) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56)) + return b +} + +// appendVarint appends an encoded varint to b. +func appendVarint(b []byte, v uint64) []byte { + // TODO: make 1-byte (maybe 2-byte) case inline-able, once we + // have non-leaf inliner. + switch { + case v < 1<<7: + b = append(b, byte(v)) + case v < 1<<14: + b = append(b, + byte(v&0x7f|0x80), + byte(v>>7)) + case v < 1<<21: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte(v>>14)) + case v < 1<<28: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte(v>>21)) + case v < 1<<35: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte(v>>28)) + case v < 1<<42: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte(v>>35)) + case v < 1<<49: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte(v>>42)) + case v < 1<<56: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte(v>>49)) + case v < 1<<63: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte(v>>56)) + default: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte((v>>56)&0x7f|0x80), + 1) + } + return b +} + +func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, *p) + return b, nil +} +func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(*p)) + return b, nil +} +func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(*p)) + return b, nil +} +func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, *p) + return b, nil +} +func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(*p)) + return b, nil +} +func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(*p)) + return b, nil +} +func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, *p) + return b, nil +} +func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + } + return b, nil +} +func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, v) + } + return b, nil +} +func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + if !v { + return b, nil + } + b = appendVarint(b, wiretag) + b = append(b, 1) + return b, nil +} + +func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toBoolPtr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + if *p { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(len(s))) + for _, v := range s { + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + if v == "" { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toStringSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} +func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + v := *ptr.toString() + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + v := *ptr.toString() + if v == "" { + return b, nil + } + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + s := *ptr.toStringSlice() + for _, v := range s { + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if v == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if len(v) == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBytesSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} + +// makeGroupMarshaler returns the sizer and marshaler for a group. +// u is the marshal info of the underlying message. +func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + return u.size(p) + 2*tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + var err error + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, p, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + return b, err + } +} + +// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice. +// u is the marshal info of the underlying message. +func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + n += u.size(v) + 2*tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err error + var nerr nonFatal + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, v, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + if !nerr.Merge(err) { + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, nerr.E + } +} + +// makeMessageMarshaler returns the sizer and marshaler for a message field. +// u is the marshal info of the message. +func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.size(p) + return siz + SizeVarint(uint64(siz)) + tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(p) + b = appendVarint(b, uint64(siz)) + return u.marshal(b, p, deterministic) + } +} + +// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice. +// u is the marshal info of the message. +func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + siz := u.size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err error + var nerr nonFatal + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(v) + b = appendVarint(b, uint64(siz)) + b, err = u.marshal(b, v, deterministic) + + if !nerr.Merge(err) { + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, nerr.E + } +} + +// makeMapMarshaler returns the sizer and marshaler for a map field. +// f is the pointer to the reflect data structure of the field. +func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { + // figure out key and value type + t := f.Type + keyType := t.Key() + valType := t.Elem() + keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",") + valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") + keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map + valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map + keyWireTag := 1<<3 | wiretype(keyTags[0]) + valWireTag := 2<<3 | wiretype(valTags[0]) + + // We create an interface to get the addresses of the map key and value. + // If value is pointer-typed, the interface is a direct interface, the + // idata itself is the value. Otherwise, the idata is the pointer to the + // value. + // Key cannot be pointer-typed. + valIsPtr := valType.Kind() == reflect.Ptr + + // If value is a message with nested maps, calling + // valSizer in marshal may be quadratic. We should use + // cached version in marshal (but not in size). + // If value is not message type, we don't have size cache, + // but it cannot be nested either. Just use valSizer. + valCachedSizer := valSizer + if valIsPtr && valType.Elem().Kind() == reflect.Struct { + u := getMarshalInfo(valType.Elem()) + valCachedSizer = func(ptr pointer, tagsize int) int { + // Same as message sizer, but use cache. + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.cachedsize(p) + return siz + SizeVarint(uint64(siz)) + tagsize + } + } + return func(ptr pointer, tagsize int) int { + m := ptr.asPointerTo(t).Elem() // the map + n := 0 + for _, k := range m.MapKeys() { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) { + m := ptr.asPointerTo(t).Elem() // the map + var err error + keys := m.MapKeys() + if len(keys) > 1 && deterministic { + sort.Sort(mapKeys(keys)) + } + + var nerr nonFatal + for _, k := range keys { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + b = appendVarint(b, tag) + siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + b = appendVarint(b, uint64(siz)) + b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) + if !nerr.Merge(err) { + return b, err + } + b, err = valMarshaler(b, vaddr, valWireTag, deterministic) + if err != ErrNil && !nerr.Merge(err) { // allow nil value in map + return b, err + } + } + return b, nerr.E + } +} + +// makeOneOfMarshaler returns the sizer and marshaler for a oneof field. +// fi is the marshal info of the field. +// f is the pointer to the reflect data structure of the field. +func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) { + // Oneof field is an interface. We need to get the actual data type on the fly. + t := f.Type + return func(ptr pointer, _ int) int { + p := ptr.getInterfacePointer() + if p.isNil() { + return 0 + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + e := fi.oneofElems[telem] + return e.sizer(p, e.tagsize) + }, + func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) { + p := ptr.getInterfacePointer() + if p.isNil() { + return b, nil + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() { + return b, errOneofHasNil + } + e := fi.oneofElems[telem] + return e.marshaler(b, p, e.wiretag, deterministic) + } +} + +// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field. +func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, ei.tagsize) + } + mu.Unlock() + return n +} + +// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b. +func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + var nerr nonFatal + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E + } + + // Sort the keys to provide a deterministic encoding. + // Not sure this is required, but the old code does it. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// message set format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } + +// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field +// in message set format (above). +func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for id, e := range m { + n += 2 // start group, end group. tag = 1 (size=1) + n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + siz := len(msgWithLen) + n += siz + 1 // message, tag = 3 (size=1) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, 1) // message, tag = 3 (size=1) + } + mu.Unlock() + return n +} + +// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above) +// to the end of byte slice b. +func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + var nerr nonFatal + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for id, e := range m { + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + if !nerr.Merge(err) { + return b, err + } + b = append(b, 1<<3|WireEndGroup) + } + return b, nerr.E + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, id := range keys { + e := m[int32(id)] + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + b = append(b, 1<<3|WireEndGroup) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// sizeV1Extensions computes the size of encoded data for a V1-API extension field. +func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { + if m == nil { + return 0 + } + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, ei.tagsize) + } + return n +} + +// appendV1Extensions marshals a V1-API extension field to the end of byte slice b. +func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) { + if m == nil { + return b, nil + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + var err error + var nerr nonFatal + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// newMarshaler is the interface representing objects that can marshal themselves. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newMarshaler interface { + XXX_Size() int + XXX_Marshal(b []byte, deterministic bool) ([]byte, error) +} + +// Size returns the encoded size of a protocol buffer message. +// This is the main entry point. +func Size(pb Message) int { + if m, ok := pb.(newMarshaler); ok { + return m.XXX_Size() + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, _ := m.Marshal() + return len(b) + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return 0 + } + var info InternalMessageInfo + return info.Size(pb) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, returning the data. +// This is the main entry point. +func Marshal(pb Message) ([]byte, error) { + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + b := make([]byte, 0, siz) + return m.XXX_Marshal(b, false) + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + return m.Marshal() + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return nil, ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + b := make([]byte, 0, siz) + return info.Marshal(b, pb, false) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, writing the result to the +// Buffer. +// This is an alternative entry point. It is not necessary to use +// a Buffer for most applications. +func (p *Buffer) Marshal(pb Message) error { + var err error + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + p.grow(siz) // make sure buf has enough capacity + p.buf, err = m.XXX_Marshal(p.buf, p.deterministic) + return err + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, err := m.Marshal() + p.buf = append(p.buf, b...) + return err + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + p.grow(siz) // make sure buf has enough capacity + p.buf, err = info.Marshal(p.buf, pb, p.deterministic) + return err +} + +// grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After grow(n), at least n bytes can be written to the +// buffer without another allocation. +func (p *Buffer) grow(n int) { + need := len(p.buf) + n + if need <= cap(p.buf) { + return + } + newCap := len(p.buf) * 2 + if newCap < need { + newCap = need + } + p.buf = append(make([]byte, 0, newCap), p.buf...) +} diff --git a/vendor/github.com/golang/protobuf/proto/table_merge.go b/vendor/github.com/golang/protobuf/proto/table_merge.go new file mode 100644 index 00000000..5525def6 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_merge.go @@ -0,0 +1,654 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +// Merge merges the src message into dst. +// This assumes that dst and src of the same type and are non-nil. +func (a *InternalMessageInfo) Merge(dst, src Message) { + mi := atomicLoadMergeInfo(&a.merge) + if mi == nil { + mi = getMergeInfo(reflect.TypeOf(dst).Elem()) + atomicStoreMergeInfo(&a.merge, mi) + } + mi.merge(toPointer(&dst), toPointer(&src)) +} + +type mergeInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []mergeFieldInfo + unrecognized field // Offset of XXX_unrecognized +} + +type mergeFieldInfo struct { + field field // Offset of field, guaranteed to be valid + + // isPointer reports whether the value in the field is a pointer. + // This is true for the following situations: + // * Pointer to struct + // * Pointer to basic type (proto2 only) + // * Slice (first value in slice header is a pointer) + // * String (first value in string header is a pointer) + isPointer bool + + // basicWidth reports the width of the field assuming that it is directly + // embedded in the struct (as is the case for basic types in proto3). + // The possible values are: + // 0: invalid + // 1: bool + // 4: int32, uint32, float32 + // 8: int64, uint64, float64 + basicWidth int + + // Where dst and src are pointers to the types being merged. + merge func(dst, src pointer) +} + +var ( + mergeInfoMap = map[reflect.Type]*mergeInfo{} + mergeInfoLock sync.Mutex +) + +func getMergeInfo(t reflect.Type) *mergeInfo { + mergeInfoLock.Lock() + defer mergeInfoLock.Unlock() + mi := mergeInfoMap[t] + if mi == nil { + mi = &mergeInfo{typ: t} + mergeInfoMap[t] = mi + } + return mi +} + +// merge merges src into dst assuming they are both of type *mi.typ. +func (mi *mergeInfo) merge(dst, src pointer) { + if dst.isNil() { + panic("proto: nil destination") + } + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&mi.initialized) == 0 { + mi.computeMergeInfo() + } + + for _, fi := range mi.fields { + sfp := src.offset(fi.field) + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string + continue + } + if fi.basicWidth > 0 { + switch { + case fi.basicWidth == 1 && !*sfp.toBool(): + continue + case fi.basicWidth == 4 && *sfp.toUint32() == 0: + continue + case fi.basicWidth == 8 && *sfp.toUint64() == 0: + continue + } + } + } + + dfp := dst.offset(fi.field) + fi.merge(dfp, sfp) + } + + // TODO: Make this faster? + out := dst.asPointerTo(mi.typ).Elem() + in := src.asPointerTo(mi.typ).Elem() + if emIn, err := extendable(in.Addr().Interface()); err == nil { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + if mi.unrecognized.IsValid() { + if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { + *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) + } + } +} + +func (mi *mergeInfo) computeMergeInfo() { + mi.lock.Lock() + defer mi.lock.Unlock() + if mi.initialized != 0 { + return + } + t := mi.typ + n := t.NumField() + + props := GetProperties(t) + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + mfi := mergeFieldInfo{field: toField(&f)} + tf := f.Type + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + switch tf.Kind() { + case reflect.Ptr, reflect.Slice, reflect.String: + // As a special case, we assume slices and strings are pointers + // since we know that the first field in the SliceSlice or + // StringHeader is a data pointer. + mfi.isPointer = true + case reflect.Bool: + mfi.basicWidth = 1 + case reflect.Int32, reflect.Uint32, reflect.Float32: + mfi.basicWidth = 4 + case reflect.Int64, reflect.Uint64, reflect.Float64: + mfi.basicWidth = 8 + } + } + + // Unwrap tf to get at its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + tf.Name()) + } + + switch tf.Kind() { + case reflect.Int32: + switch { + case isSlice: // E.g., []int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Slice is not defined (see pointer_reflect.go). + /* + sfsp := src.toInt32Slice() + if *sfsp != nil { + dfsp := dst.toInt32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + */ + sfs := src.getInt32Slice() + if sfs != nil { + dfs := dst.getInt32Slice() + dfs = append(dfs, sfs...) + if dfs == nil { + dfs = []int32{} + } + dst.setInt32Slice(dfs) + } + } + case isPointer: // E.g., *int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Ptr is not defined (see pointer_reflect.go). + /* + sfpp := src.toInt32Ptr() + if *sfpp != nil { + dfpp := dst.toInt32Ptr() + if *dfpp == nil { + *dfpp = Int32(**sfpp) + } else { + **dfpp = **sfpp + } + } + */ + sfp := src.getInt32Ptr() + if sfp != nil { + dfp := dst.getInt32Ptr() + if dfp == nil { + dst.setInt32Ptr(*sfp) + } else { + *dfp = *sfp + } + } + } + default: // E.g., int32 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt32(); v != 0 { + *dst.toInt32() = v + } + } + } + case reflect.Int64: + switch { + case isSlice: // E.g., []int64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toInt64Slice() + if *sfsp != nil { + dfsp := dst.toInt64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + } + case isPointer: // E.g., *int64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toInt64Ptr() + if *sfpp != nil { + dfpp := dst.toInt64Ptr() + if *dfpp == nil { + *dfpp = Int64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., int64 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt64(); v != 0 { + *dst.toInt64() = v + } + } + } + case reflect.Uint32: + switch { + case isSlice: // E.g., []uint32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint32Slice() + if *sfsp != nil { + dfsp := dst.toUint32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint32{} + } + } + } + case isPointer: // E.g., *uint32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint32Ptr() + if *sfpp != nil { + dfpp := dst.toUint32Ptr() + if *dfpp == nil { + *dfpp = Uint32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint32 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint32(); v != 0 { + *dst.toUint32() = v + } + } + } + case reflect.Uint64: + switch { + case isSlice: // E.g., []uint64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint64Slice() + if *sfsp != nil { + dfsp := dst.toUint64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint64{} + } + } + } + case isPointer: // E.g., *uint64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint64Ptr() + if *sfpp != nil { + dfpp := dst.toUint64Ptr() + if *dfpp == nil { + *dfpp = Uint64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint64 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint64(); v != 0 { + *dst.toUint64() = v + } + } + } + case reflect.Float32: + switch { + case isSlice: // E.g., []float32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat32Slice() + if *sfsp != nil { + dfsp := dst.toFloat32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float32{} + } + } + } + case isPointer: // E.g., *float32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat32Ptr() + if *sfpp != nil { + dfpp := dst.toFloat32Ptr() + if *dfpp == nil { + *dfpp = Float32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float32 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat32(); v != 0 { + *dst.toFloat32() = v + } + } + } + case reflect.Float64: + switch { + case isSlice: // E.g., []float64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat64Slice() + if *sfsp != nil { + dfsp := dst.toFloat64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float64{} + } + } + } + case isPointer: // E.g., *float64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat64Ptr() + if *sfpp != nil { + dfpp := dst.toFloat64Ptr() + if *dfpp == nil { + *dfpp = Float64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float64 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat64(); v != 0 { + *dst.toFloat64() = v + } + } + } + case reflect.Bool: + switch { + case isSlice: // E.g., []bool + mfi.merge = func(dst, src pointer) { + sfsp := src.toBoolSlice() + if *sfsp != nil { + dfsp := dst.toBoolSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []bool{} + } + } + } + case isPointer: // E.g., *bool + mfi.merge = func(dst, src pointer) { + sfpp := src.toBoolPtr() + if *sfpp != nil { + dfpp := dst.toBoolPtr() + if *dfpp == nil { + *dfpp = Bool(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., bool + mfi.merge = func(dst, src pointer) { + if v := *src.toBool(); v { + *dst.toBool() = v + } + } + } + case reflect.String: + switch { + case isSlice: // E.g., []string + mfi.merge = func(dst, src pointer) { + sfsp := src.toStringSlice() + if *sfsp != nil { + dfsp := dst.toStringSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []string{} + } + } + } + case isPointer: // E.g., *string + mfi.merge = func(dst, src pointer) { + sfpp := src.toStringPtr() + if *sfpp != nil { + dfpp := dst.toStringPtr() + if *dfpp == nil { + *dfpp = String(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., string + mfi.merge = func(dst, src pointer) { + if v := *src.toString(); v != "" { + *dst.toString() = v + } + } + } + case reflect.Slice: + isProto3 := props.Prop[i].proto3 + switch { + case isPointer: + panic("bad pointer in byte slice case in " + tf.Name()) + case tf.Elem().Kind() != reflect.Uint8: + panic("bad element kind in byte slice case in " + tf.Name()) + case isSlice: // E.g., [][]byte + mfi.merge = func(dst, src pointer) { + sbsp := src.toBytesSlice() + if *sbsp != nil { + dbsp := dst.toBytesSlice() + for _, sb := range *sbsp { + if sb == nil { + *dbsp = append(*dbsp, nil) + } else { + *dbsp = append(*dbsp, append([]byte{}, sb...)) + } + } + if *dbsp == nil { + *dbsp = [][]byte{} + } + } + } + default: // E.g., []byte + mfi.merge = func(dst, src pointer) { + sbp := src.toBytes() + if *sbp != nil { + dbp := dst.toBytes() + if !isProto3 || len(*sbp) > 0 { + *dbp = append([]byte{}, *sbp...) + } + } + } + } + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("message field %s without pointer", tf)) + case isSlice: // E.g., []*pb.T + mi := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sps := src.getPointerSlice() + if sps != nil { + dps := dst.getPointerSlice() + for _, sp := range sps { + var dp pointer + if !sp.isNil() { + dp = valToPointer(reflect.New(tf)) + mi.merge(dp, sp) + } + dps = append(dps, dp) + } + if dps == nil { + dps = []pointer{} + } + dst.setPointerSlice(dps) + } + } + default: // E.g., *pb.T + mi := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sp := src.getPointer() + if !sp.isNil() { + dp := dst.getPointer() + if dp.isNil() { + dp = valToPointer(reflect.New(tf)) + dst.setPointer(dp) + } + mi.merge(dp, sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic("bad pointer or slice in map case in " + tf.Name()) + default: // E.g., map[K]V + mfi.merge = func(dst, src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + dm := dst.asPointerTo(tf).Elem() + if dm.IsNil() { + dm.Set(reflect.MakeMap(tf)) + } + + switch tf.Elem().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(Clone(val.Interface().(Message))) + dm.SetMapIndex(key, val) + } + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + dm.SetMapIndex(key, val) + } + default: // Basic type (e.g., string) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + dm.SetMapIndex(key, val) + } + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic("bad pointer or slice in interface case in " + tf.Name()) + default: // E.g., interface{} + // TODO: Make this faster? + mfi.merge = func(dst, src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + du := dst.asPointerTo(tf).Elem() + typ := su.Elem().Type() + if du.IsNil() || du.Elem().Type() != typ { + du.Set(reflect.New(typ.Elem())) // Initialize interface if empty + } + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + dv := du.Elem().Elem().Field(0) + if dv.Kind() == reflect.Ptr && dv.IsNil() { + dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + Merge(dv.Interface().(Message), sv.Interface().(Message)) + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) + default: // Basic type (e.g., string) + dv.Set(sv) + } + } + } + } + default: + panic(fmt.Sprintf("merger not found for type:%s", tf)) + } + mi.fields = append(mi.fields, mfi) + } + + mi.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + mi.unrecognized = toField(&f) + } + + atomic.StoreInt32(&mi.initialized, 1) +} diff --git a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go new file mode 100644 index 00000000..ebf1caa5 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go @@ -0,0 +1,2051 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "errors" + "fmt" + "io" + "math" + "reflect" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// Unmarshal is the entry point from the generated .pb.go files. +// This function is not intended to be used by non-generated code. +// This function is not subject to any compatibility guarantee. +// msg contains a pointer to a protocol buffer struct. +// b is the data to be unmarshaled into the protocol buffer. +// a is a pointer to a place to store cached unmarshal information. +func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error { + // Load the unmarshal information for this message type. + // The atomic load ensures memory consistency. + u := atomicLoadUnmarshalInfo(&a.unmarshal) + if u == nil { + // Slow path: find unmarshal info for msg, update a with it. + u = getUnmarshalInfo(reflect.TypeOf(msg).Elem()) + atomicStoreUnmarshalInfo(&a.unmarshal, u) + } + // Then do the unmarshaling. + err := u.unmarshal(toPointer(&msg), b) + return err +} + +type unmarshalInfo struct { + typ reflect.Type // type of the protobuf struct + + // 0 = only typ field is initialized + // 1 = completely initialized + initialized int32 + lock sync.Mutex // prevents double initialization + dense []unmarshalFieldInfo // fields indexed by tag # + sparse map[uint64]unmarshalFieldInfo // fields indexed by tag # + reqFields []string // names of required fields + reqMask uint64 // 1< 0 { + // Read tag and wire type. + // Special case 1 and 2 byte varints. + var x uint64 + if b[0] < 128 { + x = uint64(b[0]) + b = b[1:] + } else if len(b) >= 2 && b[1] < 128 { + x = uint64(b[0]&0x7f) + uint64(b[1])<<7 + b = b[2:] + } else { + var n int + x, n = decodeVarint(b) + if n == 0 { + return io.ErrUnexpectedEOF + } + b = b[n:] + } + tag := x >> 3 + wire := int(x) & 7 + + // Dispatch on the tag to one of the unmarshal* functions below. + var f unmarshalFieldInfo + if tag < uint64(len(u.dense)) { + f = u.dense[tag] + } else { + f = u.sparse[tag] + } + if fn := f.unmarshal; fn != nil { + var err error + b, err = fn(b, m.offset(f.field), wire) + if err == nil { + reqMask |= f.reqMask + continue + } + if r, ok := err.(*RequiredNotSetError); ok { + // Remember this error, but keep parsing. We need to produce + // a full parse even if a required field is missing. + if errLater == nil { + errLater = r + } + reqMask |= f.reqMask + continue + } + if err != errInternalBadWireType { + if err == errInvalidUTF8 { + if errLater == nil { + fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name + errLater = &invalidUTF8Error{fullName} + } + continue + } + return err + } + // Fragments with bad wire type are treated as unknown fields. + } + + // Unknown tag. + if !u.unrecognized.IsValid() { + // Don't keep unrecognized data; just skip it. + var err error + b, err = skipField(b, wire) + if err != nil { + return err + } + continue + } + // Keep unrecognized data around. + // maybe in extensions, maybe in the unrecognized field. + z := m.offset(u.unrecognized).toBytes() + var emap map[int32]Extension + var e Extension + for _, r := range u.extensionRanges { + if uint64(r.Start) <= tag && tag <= uint64(r.End) { + if u.extensions.IsValid() { + mp := m.offset(u.extensions).toExtensions() + emap = mp.extensionsWrite() + e = emap[int32(tag)] + z = &e.enc + break + } + if u.oldExtensions.IsValid() { + p := m.offset(u.oldExtensions).toOldExtensions() + emap = *p + if emap == nil { + emap = map[int32]Extension{} + *p = emap + } + e = emap[int32(tag)] + z = &e.enc + break + } + panic("no extensions field available") + } + } + + // Use wire type to skip data. + var err error + b0 := b + b, err = skipField(b, wire) + if err != nil { + return err + } + *z = encodeVarint(*z, tag<<3|uint64(wire)) + *z = append(*z, b0[:len(b0)-len(b)]...) + + if emap != nil { + emap[int32(tag)] = e + } + } + if reqMask != u.reqMask && errLater == nil { + // A required field of this message is missing. + for _, n := range u.reqFields { + if reqMask&1 == 0 { + errLater = &RequiredNotSetError{n} + } + reqMask >>= 1 + } + } + return errLater +} + +// computeUnmarshalInfo fills in u with information for use +// in unmarshaling protocol buffers of type u.typ. +func (u *unmarshalInfo) computeUnmarshalInfo() { + u.lock.Lock() + defer u.lock.Unlock() + if u.initialized != 0 { + return + } + t := u.typ + n := t.NumField() + + // Set up the "not found" value for the unrecognized byte buffer. + // This is the default for proto3. + u.unrecognized = invalidField + u.extensions = invalidField + u.oldExtensions = invalidField + + // List of the generated type and offset for each oneof field. + type oneofField struct { + ityp reflect.Type // interface type of oneof field + field field // offset in containing message + } + var oneofFields []oneofField + + for i := 0; i < n; i++ { + f := t.Field(i) + if f.Name == "XXX_unrecognized" { + // The byte slice used to hold unrecognized input is special. + if f.Type != reflect.TypeOf(([]byte)(nil)) { + panic("bad type for XXX_unrecognized field: " + f.Type.Name()) + } + u.unrecognized = toField(&f) + continue + } + if f.Name == "XXX_InternalExtensions" { + // Ditto here. + if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) { + panic("bad type for XXX_InternalExtensions field: " + f.Type.Name()) + } + u.extensions = toField(&f) + if f.Tag.Get("protobuf_messageset") == "1" { + u.isMessageSet = true + } + continue + } + if f.Name == "XXX_extensions" { + // An older form of the extensions field. + if f.Type != reflect.TypeOf((map[int32]Extension)(nil)) { + panic("bad type for XXX_extensions field: " + f.Type.Name()) + } + u.oldExtensions = toField(&f) + continue + } + if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" { + continue + } + + oneof := f.Tag.Get("protobuf_oneof") + if oneof != "" { + oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)}) + // The rest of oneof processing happens below. + continue + } + + tags := f.Tag.Get("protobuf") + tagArray := strings.Split(tags, ",") + if len(tagArray) < 2 { + panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags) + } + tag, err := strconv.Atoi(tagArray[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tagArray[1]) + } + + name := "" + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + } + + // Extract unmarshaling function from the field (its type and tags). + unmarshal := fieldUnmarshaler(&f) + + // Required field? + var reqMask uint64 + if tagArray[2] == "req" { + bit := len(u.reqFields) + u.reqFields = append(u.reqFields, name) + reqMask = uint64(1) << uint(bit) + // TODO: if we have more than 64 required fields, we end up + // not verifying that all required fields are present. + // Fix this, perhaps using a count of required fields? + } + + // Store the info in the correct slot in the message. + u.setTag(tag, toField(&f), unmarshal, reqMask, name) + } + + // Find any types associated with oneof fields. + // TODO: XXX_OneofFuncs returns more info than we need. Get rid of some of it? + fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("XXX_OneofFuncs") + if fn.IsValid() { + res := fn.Call(nil)[3] // last return value from XXX_OneofFuncs: []interface{} + for i := res.Len() - 1; i >= 0; i-- { + v := res.Index(i) // interface{} + tptr := reflect.ValueOf(v.Interface()).Type() // *Msg_X + typ := tptr.Elem() // Msg_X + + f := typ.Field(0) // oneof implementers have one field + baseUnmarshal := fieldUnmarshaler(&f) + tags := strings.Split(f.Tag.Get("protobuf"), ",") + fieldNum, err := strconv.Atoi(tags[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tags[1]) + } + var name string + for _, tag := range tags { + if strings.HasPrefix(tag, "name=") { + name = strings.TrimPrefix(tag, "name=") + break + } + } + + // Find the oneof field that this struct implements. + // Might take O(n^2) to process all of the oneofs, but who cares. + for _, of := range oneofFields { + if tptr.Implements(of.ityp) { + // We have found the corresponding interface for this struct. + // That lets us know where this struct should be stored + // when we encounter it during unmarshaling. + unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) + u.setTag(fieldNum, of.field, unmarshal, 0, name) + } + } + } + } + + // Get extension ranges, if any. + fn = reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") + if fn.IsValid() { + if !u.extensions.IsValid() && !u.oldExtensions.IsValid() { + panic("a message with extensions, but no extensions field in " + t.Name()) + } + u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange) + } + + // Explicitly disallow tag 0. This will ensure we flag an error + // when decoding a buffer of all zeros. Without this code, we + // would decode and skip an all-zero buffer of even length. + // [0 0] is [tag=0/wiretype=varint varint-encoded-0]. + u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) { + return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w) + }, 0, "") + + // Set mask for required field check. + u.reqMask = uint64(1)<= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here? + for len(u.dense) <= tag { + u.dense = append(u.dense, unmarshalFieldInfo{}) + } + u.dense[tag] = i + return + } + if u.sparse == nil { + u.sparse = map[uint64]unmarshalFieldInfo{} + } + u.sparse[uint64(tag)] = i +} + +// fieldUnmarshaler returns an unmarshaler for the given field. +func fieldUnmarshaler(f *reflect.StructField) unmarshaler { + if f.Type.Kind() == reflect.Map { + return makeUnmarshalMap(f) + } + return typeUnmarshaler(f.Type, f.Tag.Get("protobuf")) +} + +// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair. +func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { + tagArray := strings.Split(tags, ",") + encoding := tagArray[0] + name := "unknown" + proto3 := false + validateUTF8 := true + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + if tag == "proto3" { + proto3 = true + } + } + validateUTF8 = validateUTF8 && proto3 + + // Figure out packaging (pointer, slice, or both) + slice := false + pointer := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + // We'll never have both pointer and slice for basic types. + if pointer && slice && t.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + t.Name()) + } + + switch t.Kind() { + case reflect.Bool: + if pointer { + return unmarshalBoolPtr + } + if slice { + return unmarshalBoolSlice + } + return unmarshalBoolValue + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixedS32Ptr + } + if slice { + return unmarshalFixedS32Slice + } + return unmarshalFixedS32Value + case "varint": + // this could be int32 or enum + if pointer { + return unmarshalInt32Ptr + } + if slice { + return unmarshalInt32Slice + } + return unmarshalInt32Value + case "zigzag32": + if pointer { + return unmarshalSint32Ptr + } + if slice { + return unmarshalSint32Slice + } + return unmarshalSint32Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixedS64Ptr + } + if slice { + return unmarshalFixedS64Slice + } + return unmarshalFixedS64Value + case "varint": + if pointer { + return unmarshalInt64Ptr + } + if slice { + return unmarshalInt64Slice + } + return unmarshalInt64Value + case "zigzag64": + if pointer { + return unmarshalSint64Ptr + } + if slice { + return unmarshalSint64Slice + } + return unmarshalSint64Value + } + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixed32Ptr + } + if slice { + return unmarshalFixed32Slice + } + return unmarshalFixed32Value + case "varint": + if pointer { + return unmarshalUint32Ptr + } + if slice { + return unmarshalUint32Slice + } + return unmarshalUint32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixed64Ptr + } + if slice { + return unmarshalFixed64Slice + } + return unmarshalFixed64Value + case "varint": + if pointer { + return unmarshalUint64Ptr + } + if slice { + return unmarshalUint64Slice + } + return unmarshalUint64Value + } + case reflect.Float32: + if pointer { + return unmarshalFloat32Ptr + } + if slice { + return unmarshalFloat32Slice + } + return unmarshalFloat32Value + case reflect.Float64: + if pointer { + return unmarshalFloat64Ptr + } + if slice { + return unmarshalFloat64Slice + } + return unmarshalFloat64Value + case reflect.Map: + panic("map type in typeUnmarshaler in " + t.Name()) + case reflect.Slice: + if pointer { + panic("bad pointer in slice case in " + t.Name()) + } + if slice { + return unmarshalBytesSlice + } + return unmarshalBytesValue + case reflect.String: + if validateUTF8 { + if pointer { + return unmarshalUTF8StringPtr + } + if slice { + return unmarshalUTF8StringSlice + } + return unmarshalUTF8StringValue + } + if pointer { + return unmarshalStringPtr + } + if slice { + return unmarshalStringSlice + } + return unmarshalStringValue + case reflect.Struct: + // message or group field + if !pointer { + panic(fmt.Sprintf("message/group field %s:%s without pointer", t, encoding)) + } + switch encoding { + case "bytes": + if slice { + return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name) + case "group": + if slice { + return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name) + } + } + panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding)) +} + +// Below are all the unmarshalers for individual fields of various types. + +func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64() = v + return b, nil +} + +func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64() = v + return b, nil +} + +func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64() = v + return b, nil +} + +func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64Ptr() = &v + return b, nil +} + +func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + *f.toInt32() = v + return b, nil +} + +func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + *f.toInt32() = v + return b, nil +} + +func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32() = v + return b, nil +} + +func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32Ptr() = &v + return b, nil +} + +func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64() = v + return b[8:], nil +} + +func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64() = v + return b[8:], nil +} + +func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32() = v + return b[4:], nil +} + +func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32Ptr() = &v + return b[4:], nil +} + +func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + *f.toInt32() = v + return b[4:], nil +} + +func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.setInt32Ptr(v) + return b[4:], nil +} + +func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + return b[4:], nil +} + +func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + // Note: any length varint is allowed, even though any sane + // encoder will use one byte. + // See https://github.com/golang/protobuf/issues/76 + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + // TODO: check if x>1? Tests seem to indicate no. + v := x != 0 + *f.toBool() = v + return b[n:], nil +} + +func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + *f.toBoolPtr() = &v + return b[n:], nil +} + +func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + b = b[n:] + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + return b[n:], nil +} + +func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64() = v + return b[8:], nil +} + +func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64Ptr() = &v + return b[8:], nil +} + +func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32() = v + return b[4:], nil +} + +func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32Ptr() = &v + return b[4:], nil +} + +func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toString() = v + return b[x:], nil +} + +func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toStringPtr() = &v + return b[x:], nil +} + +func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + s := f.toStringSlice() + *s = append(*s, v) + return b[x:], nil +} + +func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toString() = v + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toStringPtr() = &v + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + s := f.toStringSlice() + *s = append(*s, v) + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +var emptyBuf [0]byte + +func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // The use of append here is a trick which avoids the zeroing + // that would be required if we used a make/copy pair. + // We append to emptyBuf instead of nil because we want + // a non-nil result even when the length is 0. + v := append(emptyBuf[:], b[:x]...) + *f.toBytes() = v + return b[x:], nil +} + +func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := append(emptyBuf[:], b[:x]...) + s := f.toBytesSlice() + *s = append(*s, v) + return b[x:], nil +} + +func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // First read the message field to see if something is there. + // The semantics of multiple submessages are weird. Instead of + // the last one winning (as it is for all other fields), multiple + // submessages are merged. + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[x:], err + } +} + +func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[x:], err + } +} + +func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[y:], err + } +} + +func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[y:], err + } +} + +func makeUnmarshalMap(f *reflect.StructField) unmarshaler { + t := f.Type + kt := t.Key() + vt := t.Elem() + unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key")) + unmarshalVal := typeUnmarshaler(vt, f.Tag.Get("protobuf_val")) + return func(b []byte, f pointer, w int) ([]byte, error) { + // The map entry is a submessage. Figure out how big it is. + if w != WireBytes { + return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes) + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + r := b[x:] // unused data to return + b = b[:x] // data for map entry + + // Note: we could use #keys * #values ~= 200 functions + // to do map decoding without reflection. Probably not worth it. + // Maps will be somewhat slow. Oh well. + + // Read key and value from data. + var nerr nonFatal + k := reflect.New(kt) + v := reflect.New(vt) + for len(b) > 0 { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + wire := int(x) & 7 + b = b[n:] + + var err error + switch x >> 3 { + case 1: + b, err = unmarshalKey(b, valToPointer(k), wire) + case 2: + b, err = unmarshalVal(b, valToPointer(v), wire) + default: + err = errInternalBadWireType // skip unknown tag + } + + if nerr.Merge(err) { + continue + } + if err != errInternalBadWireType { + return nil, err + } + + // Skip past unknown fields. + b, err = skipField(b, wire) + if err != nil { + return nil, err + } + } + + // Get map, allocate if needed. + m := f.asPointerTo(t).Elem() // an addressable map[K]T + if m.IsNil() { + m.Set(reflect.MakeMap(t)) + } + + // Insert into map. + m.SetMapIndex(k.Elem(), v.Elem()) + + return r, nerr.E + } +} + +// makeUnmarshalOneof makes an unmarshaler for oneof fields. +// for: +// message Msg { +// oneof F { +// int64 X = 1; +// float64 Y = 2; +// } +// } +// typ is the type of the concrete entry for a oneof case (e.g. Msg_X). +// ityp is the interface type of the oneof field (e.g. isMsg_F). +// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). +// Note that this function will be called once for each case in the oneof. +func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler { + sf := typ.Field(0) + field0 := toField(&sf) + return func(b []byte, f pointer, w int) ([]byte, error) { + // Allocate holder for value. + v := reflect.New(typ) + + // Unmarshal data into holder. + // We unmarshal into the first field of the holder object. + var err error + var nerr nonFatal + b, err = unmarshal(b, valToPointer(v).offset(field0), w) + if !nerr.Merge(err) { + return nil, err + } + + // Write pointer to holder into target field. + f.asPointerTo(ityp).Elem().Set(v) + + return b, nerr.E + } +} + +// Error used by decode internally. +var errInternalBadWireType = errors.New("proto: internal error: bad wiretype") + +// skipField skips past a field of type wire and returns the remaining bytes. +func skipField(b []byte, wire int) ([]byte, error) { + switch wire { + case WireVarint: + _, k := decodeVarint(b) + if k == 0 { + return b, io.ErrUnexpectedEOF + } + b = b[k:] + case WireFixed32: + if len(b) < 4 { + return b, io.ErrUnexpectedEOF + } + b = b[4:] + case WireFixed64: + if len(b) < 8 { + return b, io.ErrUnexpectedEOF + } + b = b[8:] + case WireBytes: + m, k := decodeVarint(b) + if k == 0 || uint64(len(b)-k) < m { + return b, io.ErrUnexpectedEOF + } + b = b[uint64(k)+m:] + case WireStartGroup: + _, i := findEndGroup(b) + if i == -1 { + return b, io.ErrUnexpectedEOF + } + b = b[i:] + default: + return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire) + } + return b, nil +} + +// findEndGroup finds the index of the next EndGroup tag. +// Groups may be nested, so the "next" EndGroup tag is the first +// unpaired EndGroup. +// findEndGroup returns the indexes of the start and end of the EndGroup tag. +// Returns (-1,-1) if it can't find one. +func findEndGroup(b []byte) (int, int) { + depth := 1 + i := 0 + for { + x, n := decodeVarint(b[i:]) + if n == 0 { + return -1, -1 + } + j := i + i += n + switch x & 7 { + case WireVarint: + _, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + case WireFixed32: + if len(b)-4 < i { + return -1, -1 + } + i += 4 + case WireFixed64: + if len(b)-8 < i { + return -1, -1 + } + i += 8 + case WireBytes: + m, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + if uint64(len(b)-i) < m { + return -1, -1 + } + i += int(m) + case WireStartGroup: + depth++ + case WireEndGroup: + depth-- + if depth == 0 { + return j, i + } + default: + return -1, -1 + } + } +} + +// encodeVarint appends a varint-encoded integer to b and returns the result. +func encodeVarint(b []byte, x uint64) []byte { + for x >= 1<<7 { + b = append(b, byte(x&0x7f|0x80)) + x >>= 7 + } + return append(b, byte(x)) +} + +// decodeVarint reads a varint-encoded integer from b. +// Returns the decoded integer and the number of bytes read. +// If there is an error, it returns 0,0. +func decodeVarint(b []byte) (uint64, int) { + var x, y uint64 + if len(b) <= 0 { + goto bad + } + x = uint64(b[0]) + if x < 0x80 { + return x, 1 + } + x -= 0x80 + + if len(b) <= 1 { + goto bad + } + y = uint64(b[1]) + x += y << 7 + if y < 0x80 { + return x, 2 + } + x -= 0x80 << 7 + + if len(b) <= 2 { + goto bad + } + y = uint64(b[2]) + x += y << 14 + if y < 0x80 { + return x, 3 + } + x -= 0x80 << 14 + + if len(b) <= 3 { + goto bad + } + y = uint64(b[3]) + x += y << 21 + if y < 0x80 { + return x, 4 + } + x -= 0x80 << 21 + + if len(b) <= 4 { + goto bad + } + y = uint64(b[4]) + x += y << 28 + if y < 0x80 { + return x, 5 + } + x -= 0x80 << 28 + + if len(b) <= 5 { + goto bad + } + y = uint64(b[5]) + x += y << 35 + if y < 0x80 { + return x, 6 + } + x -= 0x80 << 35 + + if len(b) <= 6 { + goto bad + } + y = uint64(b[6]) + x += y << 42 + if y < 0x80 { + return x, 7 + } + x -= 0x80 << 42 + + if len(b) <= 7 { + goto bad + } + y = uint64(b[7]) + x += y << 49 + if y < 0x80 { + return x, 8 + } + x -= 0x80 << 49 + + if len(b) <= 8 { + goto bad + } + y = uint64(b[8]) + x += y << 56 + if y < 0x80 { + return x, 9 + } + x -= 0x80 << 56 + + if len(b) <= 9 { + goto bad + } + y = uint64(b[9]) + x += y << 63 + if y < 2 { + return x, 10 + } + +bad: + return 0, 0 +} diff --git a/vendor/github.com/golang/protobuf/proto/test_proto/test.pb.go b/vendor/github.com/golang/protobuf/proto/test_proto/test.pb.go new file mode 100644 index 00000000..dc3ef673 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/test_proto/test.pb.go @@ -0,0 +1,5314 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: test_proto/test.proto + +package test_proto // import "github.com/golang/protobuf/proto/test_proto" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type FOO int32 + +const ( + FOO_FOO1 FOO = 1 +) + +var FOO_name = map[int32]string{ + 1: "FOO1", +} +var FOO_value = map[string]int32{ + "FOO1": 1, +} + +func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p +} +func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) +} +func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO") + if err != nil { + return err + } + *x = FOO(value) + return nil +} +func (FOO) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{0} +} + +// An enum, for completeness. +type GoTest_KIND int32 + +const ( + GoTest_VOID GoTest_KIND = 0 + // Basic types + GoTest_BOOL GoTest_KIND = 1 + GoTest_BYTES GoTest_KIND = 2 + GoTest_FINGERPRINT GoTest_KIND = 3 + GoTest_FLOAT GoTest_KIND = 4 + GoTest_INT GoTest_KIND = 5 + GoTest_STRING GoTest_KIND = 6 + GoTest_TIME GoTest_KIND = 7 + // Groupings + GoTest_TUPLE GoTest_KIND = 8 + GoTest_ARRAY GoTest_KIND = 9 + GoTest_MAP GoTest_KIND = 10 + // Table types + GoTest_TABLE GoTest_KIND = 11 + // Functions + GoTest_FUNCTION GoTest_KIND = 12 +) + +var GoTest_KIND_name = map[int32]string{ + 0: "VOID", + 1: "BOOL", + 2: "BYTES", + 3: "FINGERPRINT", + 4: "FLOAT", + 5: "INT", + 6: "STRING", + 7: "TIME", + 8: "TUPLE", + 9: "ARRAY", + 10: "MAP", + 11: "TABLE", + 12: "FUNCTION", +} +var GoTest_KIND_value = map[string]int32{ + "VOID": 0, + "BOOL": 1, + "BYTES": 2, + "FINGERPRINT": 3, + "FLOAT": 4, + "INT": 5, + "STRING": 6, + "TIME": 7, + "TUPLE": 8, + "ARRAY": 9, + "MAP": 10, + "TABLE": 11, + "FUNCTION": 12, +} + +func (x GoTest_KIND) Enum() *GoTest_KIND { + p := new(GoTest_KIND) + *p = x + return p +} +func (x GoTest_KIND) String() string { + return proto.EnumName(GoTest_KIND_name, int32(x)) +} +func (x *GoTest_KIND) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(GoTest_KIND_value, data, "GoTest_KIND") + if err != nil { + return err + } + *x = GoTest_KIND(value) + return nil +} +func (GoTest_KIND) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{2, 0} +} + +type MyMessage_Color int32 + +const ( + MyMessage_RED MyMessage_Color = 0 + MyMessage_GREEN MyMessage_Color = 1 + MyMessage_BLUE MyMessage_Color = 2 +) + +var MyMessage_Color_name = map[int32]string{ + 0: "RED", + 1: "GREEN", + 2: "BLUE", +} +var MyMessage_Color_value = map[string]int32{ + "RED": 0, + "GREEN": 1, + "BLUE": 2, +} + +func (x MyMessage_Color) Enum() *MyMessage_Color { + p := new(MyMessage_Color) + *p = x + return p +} +func (x MyMessage_Color) String() string { + return proto.EnumName(MyMessage_Color_name, int32(x)) +} +func (x *MyMessage_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(MyMessage_Color_value, data, "MyMessage_Color") + if err != nil { + return err + } + *x = MyMessage_Color(value) + return nil +} +func (MyMessage_Color) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{13, 0} +} + +type DefaultsMessage_DefaultsEnum int32 + +const ( + DefaultsMessage_ZERO DefaultsMessage_DefaultsEnum = 0 + DefaultsMessage_ONE DefaultsMessage_DefaultsEnum = 1 + DefaultsMessage_TWO DefaultsMessage_DefaultsEnum = 2 +) + +var DefaultsMessage_DefaultsEnum_name = map[int32]string{ + 0: "ZERO", + 1: "ONE", + 2: "TWO", +} +var DefaultsMessage_DefaultsEnum_value = map[string]int32{ + "ZERO": 0, + "ONE": 1, + "TWO": 2, +} + +func (x DefaultsMessage_DefaultsEnum) Enum() *DefaultsMessage_DefaultsEnum { + p := new(DefaultsMessage_DefaultsEnum) + *p = x + return p +} +func (x DefaultsMessage_DefaultsEnum) String() string { + return proto.EnumName(DefaultsMessage_DefaultsEnum_name, int32(x)) +} +func (x *DefaultsMessage_DefaultsEnum) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(DefaultsMessage_DefaultsEnum_value, data, "DefaultsMessage_DefaultsEnum") + if err != nil { + return err + } + *x = DefaultsMessage_DefaultsEnum(value) + return nil +} +func (DefaultsMessage_DefaultsEnum) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{16, 0} +} + +type Defaults_Color int32 + +const ( + Defaults_RED Defaults_Color = 0 + Defaults_GREEN Defaults_Color = 1 + Defaults_BLUE Defaults_Color = 2 +) + +var Defaults_Color_name = map[int32]string{ + 0: "RED", + 1: "GREEN", + 2: "BLUE", +} +var Defaults_Color_value = map[string]int32{ + "RED": 0, + "GREEN": 1, + "BLUE": 2, +} + +func (x Defaults_Color) Enum() *Defaults_Color { + p := new(Defaults_Color) + *p = x + return p +} +func (x Defaults_Color) String() string { + return proto.EnumName(Defaults_Color_name, int32(x)) +} +func (x *Defaults_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Defaults_Color_value, data, "Defaults_Color") + if err != nil { + return err + } + *x = Defaults_Color(value) + return nil +} +func (Defaults_Color) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{21, 0} +} + +type RepeatedEnum_Color int32 + +const ( + RepeatedEnum_RED RepeatedEnum_Color = 1 +) + +var RepeatedEnum_Color_name = map[int32]string{ + 1: "RED", +} +var RepeatedEnum_Color_value = map[string]int32{ + "RED": 1, +} + +func (x RepeatedEnum_Color) Enum() *RepeatedEnum_Color { + p := new(RepeatedEnum_Color) + *p = x + return p +} +func (x RepeatedEnum_Color) String() string { + return proto.EnumName(RepeatedEnum_Color_name, int32(x)) +} +func (x *RepeatedEnum_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(RepeatedEnum_Color_value, data, "RepeatedEnum_Color") + if err != nil { + return err + } + *x = RepeatedEnum_Color(value) + return nil +} +func (RepeatedEnum_Color) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{23, 0} +} + +type GoEnum struct { + Foo *FOO `protobuf:"varint,1,req,name=foo,enum=test_proto.FOO" json:"foo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoEnum) Reset() { *m = GoEnum{} } +func (m *GoEnum) String() string { return proto.CompactTextString(m) } +func (*GoEnum) ProtoMessage() {} +func (*GoEnum) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{0} +} +func (m *GoEnum) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoEnum.Unmarshal(m, b) +} +func (m *GoEnum) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoEnum.Marshal(b, m, deterministic) +} +func (dst *GoEnum) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoEnum.Merge(dst, src) +} +func (m *GoEnum) XXX_Size() int { + return xxx_messageInfo_GoEnum.Size(m) +} +func (m *GoEnum) XXX_DiscardUnknown() { + xxx_messageInfo_GoEnum.DiscardUnknown(m) +} + +var xxx_messageInfo_GoEnum proto.InternalMessageInfo + +func (m *GoEnum) GetFoo() FOO { + if m != nil && m.Foo != nil { + return *m.Foo + } + return FOO_FOO1 +} + +type GoTestField struct { + Label *string `protobuf:"bytes,1,req,name=Label" json:"Label,omitempty"` + Type *string `protobuf:"bytes,2,req,name=Type" json:"Type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTestField) Reset() { *m = GoTestField{} } +func (m *GoTestField) String() string { return proto.CompactTextString(m) } +func (*GoTestField) ProtoMessage() {} +func (*GoTestField) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{1} +} +func (m *GoTestField) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTestField.Unmarshal(m, b) +} +func (m *GoTestField) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTestField.Marshal(b, m, deterministic) +} +func (dst *GoTestField) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTestField.Merge(dst, src) +} +func (m *GoTestField) XXX_Size() int { + return xxx_messageInfo_GoTestField.Size(m) +} +func (m *GoTestField) XXX_DiscardUnknown() { + xxx_messageInfo_GoTestField.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTestField proto.InternalMessageInfo + +func (m *GoTestField) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *GoTestField) GetType() string { + if m != nil && m.Type != nil { + return *m.Type + } + return "" +} + +type GoTest struct { + // Some typical parameters + Kind *GoTest_KIND `protobuf:"varint,1,req,name=Kind,enum=test_proto.GoTest_KIND" json:"Kind,omitempty"` + Table *string `protobuf:"bytes,2,opt,name=Table" json:"Table,omitempty"` + Param *int32 `protobuf:"varint,3,opt,name=Param" json:"Param,omitempty"` + // Required, repeated and optional foreign fields. + RequiredField *GoTestField `protobuf:"bytes,4,req,name=RequiredField" json:"RequiredField,omitempty"` + RepeatedField []*GoTestField `protobuf:"bytes,5,rep,name=RepeatedField" json:"RepeatedField,omitempty"` + OptionalField *GoTestField `protobuf:"bytes,6,opt,name=OptionalField" json:"OptionalField,omitempty"` + // Required fields of all basic types + F_BoolRequired *bool `protobuf:"varint,10,req,name=F_Bool_required,json=FBoolRequired" json:"F_Bool_required,omitempty"` + F_Int32Required *int32 `protobuf:"varint,11,req,name=F_Int32_required,json=FInt32Required" json:"F_Int32_required,omitempty"` + F_Int64Required *int64 `protobuf:"varint,12,req,name=F_Int64_required,json=FInt64Required" json:"F_Int64_required,omitempty"` + F_Fixed32Required *uint32 `protobuf:"fixed32,13,req,name=F_Fixed32_required,json=FFixed32Required" json:"F_Fixed32_required,omitempty"` + F_Fixed64Required *uint64 `protobuf:"fixed64,14,req,name=F_Fixed64_required,json=FFixed64Required" json:"F_Fixed64_required,omitempty"` + F_Uint32Required *uint32 `protobuf:"varint,15,req,name=F_Uint32_required,json=FUint32Required" json:"F_Uint32_required,omitempty"` + F_Uint64Required *uint64 `protobuf:"varint,16,req,name=F_Uint64_required,json=FUint64Required" json:"F_Uint64_required,omitempty"` + F_FloatRequired *float32 `protobuf:"fixed32,17,req,name=F_Float_required,json=FFloatRequired" json:"F_Float_required,omitempty"` + F_DoubleRequired *float64 `protobuf:"fixed64,18,req,name=F_Double_required,json=FDoubleRequired" json:"F_Double_required,omitempty"` + F_StringRequired *string `protobuf:"bytes,19,req,name=F_String_required,json=FStringRequired" json:"F_String_required,omitempty"` + F_BytesRequired []byte `protobuf:"bytes,101,req,name=F_Bytes_required,json=FBytesRequired" json:"F_Bytes_required,omitempty"` + F_Sint32Required *int32 `protobuf:"zigzag32,102,req,name=F_Sint32_required,json=FSint32Required" json:"F_Sint32_required,omitempty"` + F_Sint64Required *int64 `protobuf:"zigzag64,103,req,name=F_Sint64_required,json=FSint64Required" json:"F_Sint64_required,omitempty"` + F_Sfixed32Required *int32 `protobuf:"fixed32,104,req,name=F_Sfixed32_required,json=FSfixed32Required" json:"F_Sfixed32_required,omitempty"` + F_Sfixed64Required *int64 `protobuf:"fixed64,105,req,name=F_Sfixed64_required,json=FSfixed64Required" json:"F_Sfixed64_required,omitempty"` + // Repeated fields of all basic types + F_BoolRepeated []bool `protobuf:"varint,20,rep,name=F_Bool_repeated,json=FBoolRepeated" json:"F_Bool_repeated,omitempty"` + F_Int32Repeated []int32 `protobuf:"varint,21,rep,name=F_Int32_repeated,json=FInt32Repeated" json:"F_Int32_repeated,omitempty"` + F_Int64Repeated []int64 `protobuf:"varint,22,rep,name=F_Int64_repeated,json=FInt64Repeated" json:"F_Int64_repeated,omitempty"` + F_Fixed32Repeated []uint32 `protobuf:"fixed32,23,rep,name=F_Fixed32_repeated,json=FFixed32Repeated" json:"F_Fixed32_repeated,omitempty"` + F_Fixed64Repeated []uint64 `protobuf:"fixed64,24,rep,name=F_Fixed64_repeated,json=FFixed64Repeated" json:"F_Fixed64_repeated,omitempty"` + F_Uint32Repeated []uint32 `protobuf:"varint,25,rep,name=F_Uint32_repeated,json=FUint32Repeated" json:"F_Uint32_repeated,omitempty"` + F_Uint64Repeated []uint64 `protobuf:"varint,26,rep,name=F_Uint64_repeated,json=FUint64Repeated" json:"F_Uint64_repeated,omitempty"` + F_FloatRepeated []float32 `protobuf:"fixed32,27,rep,name=F_Float_repeated,json=FFloatRepeated" json:"F_Float_repeated,omitempty"` + F_DoubleRepeated []float64 `protobuf:"fixed64,28,rep,name=F_Double_repeated,json=FDoubleRepeated" json:"F_Double_repeated,omitempty"` + F_StringRepeated []string `protobuf:"bytes,29,rep,name=F_String_repeated,json=FStringRepeated" json:"F_String_repeated,omitempty"` + F_BytesRepeated [][]byte `protobuf:"bytes,201,rep,name=F_Bytes_repeated,json=FBytesRepeated" json:"F_Bytes_repeated,omitempty"` + F_Sint32Repeated []int32 `protobuf:"zigzag32,202,rep,name=F_Sint32_repeated,json=FSint32Repeated" json:"F_Sint32_repeated,omitempty"` + F_Sint64Repeated []int64 `protobuf:"zigzag64,203,rep,name=F_Sint64_repeated,json=FSint64Repeated" json:"F_Sint64_repeated,omitempty"` + F_Sfixed32Repeated []int32 `protobuf:"fixed32,204,rep,name=F_Sfixed32_repeated,json=FSfixed32Repeated" json:"F_Sfixed32_repeated,omitempty"` + F_Sfixed64Repeated []int64 `protobuf:"fixed64,205,rep,name=F_Sfixed64_repeated,json=FSfixed64Repeated" json:"F_Sfixed64_repeated,omitempty"` + // Optional fields of all basic types + F_BoolOptional *bool `protobuf:"varint,30,opt,name=F_Bool_optional,json=FBoolOptional" json:"F_Bool_optional,omitempty"` + F_Int32Optional *int32 `protobuf:"varint,31,opt,name=F_Int32_optional,json=FInt32Optional" json:"F_Int32_optional,omitempty"` + F_Int64Optional *int64 `protobuf:"varint,32,opt,name=F_Int64_optional,json=FInt64Optional" json:"F_Int64_optional,omitempty"` + F_Fixed32Optional *uint32 `protobuf:"fixed32,33,opt,name=F_Fixed32_optional,json=FFixed32Optional" json:"F_Fixed32_optional,omitempty"` + F_Fixed64Optional *uint64 `protobuf:"fixed64,34,opt,name=F_Fixed64_optional,json=FFixed64Optional" json:"F_Fixed64_optional,omitempty"` + F_Uint32Optional *uint32 `protobuf:"varint,35,opt,name=F_Uint32_optional,json=FUint32Optional" json:"F_Uint32_optional,omitempty"` + F_Uint64Optional *uint64 `protobuf:"varint,36,opt,name=F_Uint64_optional,json=FUint64Optional" json:"F_Uint64_optional,omitempty"` + F_FloatOptional *float32 `protobuf:"fixed32,37,opt,name=F_Float_optional,json=FFloatOptional" json:"F_Float_optional,omitempty"` + F_DoubleOptional *float64 `protobuf:"fixed64,38,opt,name=F_Double_optional,json=FDoubleOptional" json:"F_Double_optional,omitempty"` + F_StringOptional *string `protobuf:"bytes,39,opt,name=F_String_optional,json=FStringOptional" json:"F_String_optional,omitempty"` + F_BytesOptional []byte `protobuf:"bytes,301,opt,name=F_Bytes_optional,json=FBytesOptional" json:"F_Bytes_optional,omitempty"` + F_Sint32Optional *int32 `protobuf:"zigzag32,302,opt,name=F_Sint32_optional,json=FSint32Optional" json:"F_Sint32_optional,omitempty"` + F_Sint64Optional *int64 `protobuf:"zigzag64,303,opt,name=F_Sint64_optional,json=FSint64Optional" json:"F_Sint64_optional,omitempty"` + F_Sfixed32Optional *int32 `protobuf:"fixed32,304,opt,name=F_Sfixed32_optional,json=FSfixed32Optional" json:"F_Sfixed32_optional,omitempty"` + F_Sfixed64Optional *int64 `protobuf:"fixed64,305,opt,name=F_Sfixed64_optional,json=FSfixed64Optional" json:"F_Sfixed64_optional,omitempty"` + // Default-valued fields of all basic types + F_BoolDefaulted *bool `protobuf:"varint,40,opt,name=F_Bool_defaulted,json=FBoolDefaulted,def=1" json:"F_Bool_defaulted,omitempty"` + F_Int32Defaulted *int32 `protobuf:"varint,41,opt,name=F_Int32_defaulted,json=FInt32Defaulted,def=32" json:"F_Int32_defaulted,omitempty"` + F_Int64Defaulted *int64 `protobuf:"varint,42,opt,name=F_Int64_defaulted,json=FInt64Defaulted,def=64" json:"F_Int64_defaulted,omitempty"` + F_Fixed32Defaulted *uint32 `protobuf:"fixed32,43,opt,name=F_Fixed32_defaulted,json=FFixed32Defaulted,def=320" json:"F_Fixed32_defaulted,omitempty"` + F_Fixed64Defaulted *uint64 `protobuf:"fixed64,44,opt,name=F_Fixed64_defaulted,json=FFixed64Defaulted,def=640" json:"F_Fixed64_defaulted,omitempty"` + F_Uint32Defaulted *uint32 `protobuf:"varint,45,opt,name=F_Uint32_defaulted,json=FUint32Defaulted,def=3200" json:"F_Uint32_defaulted,omitempty"` + F_Uint64Defaulted *uint64 `protobuf:"varint,46,opt,name=F_Uint64_defaulted,json=FUint64Defaulted,def=6400" json:"F_Uint64_defaulted,omitempty"` + F_FloatDefaulted *float32 `protobuf:"fixed32,47,opt,name=F_Float_defaulted,json=FFloatDefaulted,def=314159" json:"F_Float_defaulted,omitempty"` + F_DoubleDefaulted *float64 `protobuf:"fixed64,48,opt,name=F_Double_defaulted,json=FDoubleDefaulted,def=271828" json:"F_Double_defaulted,omitempty"` + F_StringDefaulted *string `protobuf:"bytes,49,opt,name=F_String_defaulted,json=FStringDefaulted,def=hello, \"world!\"\n" json:"F_String_defaulted,omitempty"` + F_BytesDefaulted []byte `protobuf:"bytes,401,opt,name=F_Bytes_defaulted,json=FBytesDefaulted,def=Bignose" json:"F_Bytes_defaulted,omitempty"` + F_Sint32Defaulted *int32 `protobuf:"zigzag32,402,opt,name=F_Sint32_defaulted,json=FSint32Defaulted,def=-32" json:"F_Sint32_defaulted,omitempty"` + F_Sint64Defaulted *int64 `protobuf:"zigzag64,403,opt,name=F_Sint64_defaulted,json=FSint64Defaulted,def=-64" json:"F_Sint64_defaulted,omitempty"` + F_Sfixed32Defaulted *int32 `protobuf:"fixed32,404,opt,name=F_Sfixed32_defaulted,json=FSfixed32Defaulted,def=-32" json:"F_Sfixed32_defaulted,omitempty"` + F_Sfixed64Defaulted *int64 `protobuf:"fixed64,405,opt,name=F_Sfixed64_defaulted,json=FSfixed64Defaulted,def=-64" json:"F_Sfixed64_defaulted,omitempty"` + // Packed repeated fields (no string or bytes). + F_BoolRepeatedPacked []bool `protobuf:"varint,50,rep,packed,name=F_Bool_repeated_packed,json=FBoolRepeatedPacked" json:"F_Bool_repeated_packed,omitempty"` + F_Int32RepeatedPacked []int32 `protobuf:"varint,51,rep,packed,name=F_Int32_repeated_packed,json=FInt32RepeatedPacked" json:"F_Int32_repeated_packed,omitempty"` + F_Int64RepeatedPacked []int64 `protobuf:"varint,52,rep,packed,name=F_Int64_repeated_packed,json=FInt64RepeatedPacked" json:"F_Int64_repeated_packed,omitempty"` + F_Fixed32RepeatedPacked []uint32 `protobuf:"fixed32,53,rep,packed,name=F_Fixed32_repeated_packed,json=FFixed32RepeatedPacked" json:"F_Fixed32_repeated_packed,omitempty"` + F_Fixed64RepeatedPacked []uint64 `protobuf:"fixed64,54,rep,packed,name=F_Fixed64_repeated_packed,json=FFixed64RepeatedPacked" json:"F_Fixed64_repeated_packed,omitempty"` + F_Uint32RepeatedPacked []uint32 `protobuf:"varint,55,rep,packed,name=F_Uint32_repeated_packed,json=FUint32RepeatedPacked" json:"F_Uint32_repeated_packed,omitempty"` + F_Uint64RepeatedPacked []uint64 `protobuf:"varint,56,rep,packed,name=F_Uint64_repeated_packed,json=FUint64RepeatedPacked" json:"F_Uint64_repeated_packed,omitempty"` + F_FloatRepeatedPacked []float32 `protobuf:"fixed32,57,rep,packed,name=F_Float_repeated_packed,json=FFloatRepeatedPacked" json:"F_Float_repeated_packed,omitempty"` + F_DoubleRepeatedPacked []float64 `protobuf:"fixed64,58,rep,packed,name=F_Double_repeated_packed,json=FDoubleRepeatedPacked" json:"F_Double_repeated_packed,omitempty"` + F_Sint32RepeatedPacked []int32 `protobuf:"zigzag32,502,rep,packed,name=F_Sint32_repeated_packed,json=FSint32RepeatedPacked" json:"F_Sint32_repeated_packed,omitempty"` + F_Sint64RepeatedPacked []int64 `protobuf:"zigzag64,503,rep,packed,name=F_Sint64_repeated_packed,json=FSint64RepeatedPacked" json:"F_Sint64_repeated_packed,omitempty"` + F_Sfixed32RepeatedPacked []int32 `protobuf:"fixed32,504,rep,packed,name=F_Sfixed32_repeated_packed,json=FSfixed32RepeatedPacked" json:"F_Sfixed32_repeated_packed,omitempty"` + F_Sfixed64RepeatedPacked []int64 `protobuf:"fixed64,505,rep,packed,name=F_Sfixed64_repeated_packed,json=FSfixed64RepeatedPacked" json:"F_Sfixed64_repeated_packed,omitempty"` + Requiredgroup *GoTest_RequiredGroup `protobuf:"group,70,req,name=RequiredGroup,json=requiredgroup" json:"requiredgroup,omitempty"` + Repeatedgroup []*GoTest_RepeatedGroup `protobuf:"group,80,rep,name=RepeatedGroup,json=repeatedgroup" json:"repeatedgroup,omitempty"` + Optionalgroup *GoTest_OptionalGroup `protobuf:"group,90,opt,name=OptionalGroup,json=optionalgroup" json:"optionalgroup,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTest) Reset() { *m = GoTest{} } +func (m *GoTest) String() string { return proto.CompactTextString(m) } +func (*GoTest) ProtoMessage() {} +func (*GoTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{2} +} +func (m *GoTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTest.Unmarshal(m, b) +} +func (m *GoTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTest.Marshal(b, m, deterministic) +} +func (dst *GoTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTest.Merge(dst, src) +} +func (m *GoTest) XXX_Size() int { + return xxx_messageInfo_GoTest.Size(m) +} +func (m *GoTest) XXX_DiscardUnknown() { + xxx_messageInfo_GoTest.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTest proto.InternalMessageInfo + +const Default_GoTest_F_BoolDefaulted bool = true +const Default_GoTest_F_Int32Defaulted int32 = 32 +const Default_GoTest_F_Int64Defaulted int64 = 64 +const Default_GoTest_F_Fixed32Defaulted uint32 = 320 +const Default_GoTest_F_Fixed64Defaulted uint64 = 640 +const Default_GoTest_F_Uint32Defaulted uint32 = 3200 +const Default_GoTest_F_Uint64Defaulted uint64 = 6400 +const Default_GoTest_F_FloatDefaulted float32 = 314159 +const Default_GoTest_F_DoubleDefaulted float64 = 271828 +const Default_GoTest_F_StringDefaulted string = "hello, \"world!\"\n" + +var Default_GoTest_F_BytesDefaulted []byte = []byte("Bignose") + +const Default_GoTest_F_Sint32Defaulted int32 = -32 +const Default_GoTest_F_Sint64Defaulted int64 = -64 +const Default_GoTest_F_Sfixed32Defaulted int32 = -32 +const Default_GoTest_F_Sfixed64Defaulted int64 = -64 + +func (m *GoTest) GetKind() GoTest_KIND { + if m != nil && m.Kind != nil { + return *m.Kind + } + return GoTest_VOID +} + +func (m *GoTest) GetTable() string { + if m != nil && m.Table != nil { + return *m.Table + } + return "" +} + +func (m *GoTest) GetParam() int32 { + if m != nil && m.Param != nil { + return *m.Param + } + return 0 +} + +func (m *GoTest) GetRequiredField() *GoTestField { + if m != nil { + return m.RequiredField + } + return nil +} + +func (m *GoTest) GetRepeatedField() []*GoTestField { + if m != nil { + return m.RepeatedField + } + return nil +} + +func (m *GoTest) GetOptionalField() *GoTestField { + if m != nil { + return m.OptionalField + } + return nil +} + +func (m *GoTest) GetF_BoolRequired() bool { + if m != nil && m.F_BoolRequired != nil { + return *m.F_BoolRequired + } + return false +} + +func (m *GoTest) GetF_Int32Required() int32 { + if m != nil && m.F_Int32Required != nil { + return *m.F_Int32Required + } + return 0 +} + +func (m *GoTest) GetF_Int64Required() int64 { + if m != nil && m.F_Int64Required != nil { + return *m.F_Int64Required + } + return 0 +} + +func (m *GoTest) GetF_Fixed32Required() uint32 { + if m != nil && m.F_Fixed32Required != nil { + return *m.F_Fixed32Required + } + return 0 +} + +func (m *GoTest) GetF_Fixed64Required() uint64 { + if m != nil && m.F_Fixed64Required != nil { + return *m.F_Fixed64Required + } + return 0 +} + +func (m *GoTest) GetF_Uint32Required() uint32 { + if m != nil && m.F_Uint32Required != nil { + return *m.F_Uint32Required + } + return 0 +} + +func (m *GoTest) GetF_Uint64Required() uint64 { + if m != nil && m.F_Uint64Required != nil { + return *m.F_Uint64Required + } + return 0 +} + +func (m *GoTest) GetF_FloatRequired() float32 { + if m != nil && m.F_FloatRequired != nil { + return *m.F_FloatRequired + } + return 0 +} + +func (m *GoTest) GetF_DoubleRequired() float64 { + if m != nil && m.F_DoubleRequired != nil { + return *m.F_DoubleRequired + } + return 0 +} + +func (m *GoTest) GetF_StringRequired() string { + if m != nil && m.F_StringRequired != nil { + return *m.F_StringRequired + } + return "" +} + +func (m *GoTest) GetF_BytesRequired() []byte { + if m != nil { + return m.F_BytesRequired + } + return nil +} + +func (m *GoTest) GetF_Sint32Required() int32 { + if m != nil && m.F_Sint32Required != nil { + return *m.F_Sint32Required + } + return 0 +} + +func (m *GoTest) GetF_Sint64Required() int64 { + if m != nil && m.F_Sint64Required != nil { + return *m.F_Sint64Required + } + return 0 +} + +func (m *GoTest) GetF_Sfixed32Required() int32 { + if m != nil && m.F_Sfixed32Required != nil { + return *m.F_Sfixed32Required + } + return 0 +} + +func (m *GoTest) GetF_Sfixed64Required() int64 { + if m != nil && m.F_Sfixed64Required != nil { + return *m.F_Sfixed64Required + } + return 0 +} + +func (m *GoTest) GetF_BoolRepeated() []bool { + if m != nil { + return m.F_BoolRepeated + } + return nil +} + +func (m *GoTest) GetF_Int32Repeated() []int32 { + if m != nil { + return m.F_Int32Repeated + } + return nil +} + +func (m *GoTest) GetF_Int64Repeated() []int64 { + if m != nil { + return m.F_Int64Repeated + } + return nil +} + +func (m *GoTest) GetF_Fixed32Repeated() []uint32 { + if m != nil { + return m.F_Fixed32Repeated + } + return nil +} + +func (m *GoTest) GetF_Fixed64Repeated() []uint64 { + if m != nil { + return m.F_Fixed64Repeated + } + return nil +} + +func (m *GoTest) GetF_Uint32Repeated() []uint32 { + if m != nil { + return m.F_Uint32Repeated + } + return nil +} + +func (m *GoTest) GetF_Uint64Repeated() []uint64 { + if m != nil { + return m.F_Uint64Repeated + } + return nil +} + +func (m *GoTest) GetF_FloatRepeated() []float32 { + if m != nil { + return m.F_FloatRepeated + } + return nil +} + +func (m *GoTest) GetF_DoubleRepeated() []float64 { + if m != nil { + return m.F_DoubleRepeated + } + return nil +} + +func (m *GoTest) GetF_StringRepeated() []string { + if m != nil { + return m.F_StringRepeated + } + return nil +} + +func (m *GoTest) GetF_BytesRepeated() [][]byte { + if m != nil { + return m.F_BytesRepeated + } + return nil +} + +func (m *GoTest) GetF_Sint32Repeated() []int32 { + if m != nil { + return m.F_Sint32Repeated + } + return nil +} + +func (m *GoTest) GetF_Sint64Repeated() []int64 { + if m != nil { + return m.F_Sint64Repeated + } + return nil +} + +func (m *GoTest) GetF_Sfixed32Repeated() []int32 { + if m != nil { + return m.F_Sfixed32Repeated + } + return nil +} + +func (m *GoTest) GetF_Sfixed64Repeated() []int64 { + if m != nil { + return m.F_Sfixed64Repeated + } + return nil +} + +func (m *GoTest) GetF_BoolOptional() bool { + if m != nil && m.F_BoolOptional != nil { + return *m.F_BoolOptional + } + return false +} + +func (m *GoTest) GetF_Int32Optional() int32 { + if m != nil && m.F_Int32Optional != nil { + return *m.F_Int32Optional + } + return 0 +} + +func (m *GoTest) GetF_Int64Optional() int64 { + if m != nil && m.F_Int64Optional != nil { + return *m.F_Int64Optional + } + return 0 +} + +func (m *GoTest) GetF_Fixed32Optional() uint32 { + if m != nil && m.F_Fixed32Optional != nil { + return *m.F_Fixed32Optional + } + return 0 +} + +func (m *GoTest) GetF_Fixed64Optional() uint64 { + if m != nil && m.F_Fixed64Optional != nil { + return *m.F_Fixed64Optional + } + return 0 +} + +func (m *GoTest) GetF_Uint32Optional() uint32 { + if m != nil && m.F_Uint32Optional != nil { + return *m.F_Uint32Optional + } + return 0 +} + +func (m *GoTest) GetF_Uint64Optional() uint64 { + if m != nil && m.F_Uint64Optional != nil { + return *m.F_Uint64Optional + } + return 0 +} + +func (m *GoTest) GetF_FloatOptional() float32 { + if m != nil && m.F_FloatOptional != nil { + return *m.F_FloatOptional + } + return 0 +} + +func (m *GoTest) GetF_DoubleOptional() float64 { + if m != nil && m.F_DoubleOptional != nil { + return *m.F_DoubleOptional + } + return 0 +} + +func (m *GoTest) GetF_StringOptional() string { + if m != nil && m.F_StringOptional != nil { + return *m.F_StringOptional + } + return "" +} + +func (m *GoTest) GetF_BytesOptional() []byte { + if m != nil { + return m.F_BytesOptional + } + return nil +} + +func (m *GoTest) GetF_Sint32Optional() int32 { + if m != nil && m.F_Sint32Optional != nil { + return *m.F_Sint32Optional + } + return 0 +} + +func (m *GoTest) GetF_Sint64Optional() int64 { + if m != nil && m.F_Sint64Optional != nil { + return *m.F_Sint64Optional + } + return 0 +} + +func (m *GoTest) GetF_Sfixed32Optional() int32 { + if m != nil && m.F_Sfixed32Optional != nil { + return *m.F_Sfixed32Optional + } + return 0 +} + +func (m *GoTest) GetF_Sfixed64Optional() int64 { + if m != nil && m.F_Sfixed64Optional != nil { + return *m.F_Sfixed64Optional + } + return 0 +} + +func (m *GoTest) GetF_BoolDefaulted() bool { + if m != nil && m.F_BoolDefaulted != nil { + return *m.F_BoolDefaulted + } + return Default_GoTest_F_BoolDefaulted +} + +func (m *GoTest) GetF_Int32Defaulted() int32 { + if m != nil && m.F_Int32Defaulted != nil { + return *m.F_Int32Defaulted + } + return Default_GoTest_F_Int32Defaulted +} + +func (m *GoTest) GetF_Int64Defaulted() int64 { + if m != nil && m.F_Int64Defaulted != nil { + return *m.F_Int64Defaulted + } + return Default_GoTest_F_Int64Defaulted +} + +func (m *GoTest) GetF_Fixed32Defaulted() uint32 { + if m != nil && m.F_Fixed32Defaulted != nil { + return *m.F_Fixed32Defaulted + } + return Default_GoTest_F_Fixed32Defaulted +} + +func (m *GoTest) GetF_Fixed64Defaulted() uint64 { + if m != nil && m.F_Fixed64Defaulted != nil { + return *m.F_Fixed64Defaulted + } + return Default_GoTest_F_Fixed64Defaulted +} + +func (m *GoTest) GetF_Uint32Defaulted() uint32 { + if m != nil && m.F_Uint32Defaulted != nil { + return *m.F_Uint32Defaulted + } + return Default_GoTest_F_Uint32Defaulted +} + +func (m *GoTest) GetF_Uint64Defaulted() uint64 { + if m != nil && m.F_Uint64Defaulted != nil { + return *m.F_Uint64Defaulted + } + return Default_GoTest_F_Uint64Defaulted +} + +func (m *GoTest) GetF_FloatDefaulted() float32 { + if m != nil && m.F_FloatDefaulted != nil { + return *m.F_FloatDefaulted + } + return Default_GoTest_F_FloatDefaulted +} + +func (m *GoTest) GetF_DoubleDefaulted() float64 { + if m != nil && m.F_DoubleDefaulted != nil { + return *m.F_DoubleDefaulted + } + return Default_GoTest_F_DoubleDefaulted +} + +func (m *GoTest) GetF_StringDefaulted() string { + if m != nil && m.F_StringDefaulted != nil { + return *m.F_StringDefaulted + } + return Default_GoTest_F_StringDefaulted +} + +func (m *GoTest) GetF_BytesDefaulted() []byte { + if m != nil && m.F_BytesDefaulted != nil { + return m.F_BytesDefaulted + } + return append([]byte(nil), Default_GoTest_F_BytesDefaulted...) +} + +func (m *GoTest) GetF_Sint32Defaulted() int32 { + if m != nil && m.F_Sint32Defaulted != nil { + return *m.F_Sint32Defaulted + } + return Default_GoTest_F_Sint32Defaulted +} + +func (m *GoTest) GetF_Sint64Defaulted() int64 { + if m != nil && m.F_Sint64Defaulted != nil { + return *m.F_Sint64Defaulted + } + return Default_GoTest_F_Sint64Defaulted +} + +func (m *GoTest) GetF_Sfixed32Defaulted() int32 { + if m != nil && m.F_Sfixed32Defaulted != nil { + return *m.F_Sfixed32Defaulted + } + return Default_GoTest_F_Sfixed32Defaulted +} + +func (m *GoTest) GetF_Sfixed64Defaulted() int64 { + if m != nil && m.F_Sfixed64Defaulted != nil { + return *m.F_Sfixed64Defaulted + } + return Default_GoTest_F_Sfixed64Defaulted +} + +func (m *GoTest) GetF_BoolRepeatedPacked() []bool { + if m != nil { + return m.F_BoolRepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Int32RepeatedPacked() []int32 { + if m != nil { + return m.F_Int32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Int64RepeatedPacked() []int64 { + if m != nil { + return m.F_Int64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Fixed32RepeatedPacked() []uint32 { + if m != nil { + return m.F_Fixed32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Fixed64RepeatedPacked() []uint64 { + if m != nil { + return m.F_Fixed64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Uint32RepeatedPacked() []uint32 { + if m != nil { + return m.F_Uint32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Uint64RepeatedPacked() []uint64 { + if m != nil { + return m.F_Uint64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_FloatRepeatedPacked() []float32 { + if m != nil { + return m.F_FloatRepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_DoubleRepeatedPacked() []float64 { + if m != nil { + return m.F_DoubleRepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Sint32RepeatedPacked() []int32 { + if m != nil { + return m.F_Sint32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Sint64RepeatedPacked() []int64 { + if m != nil { + return m.F_Sint64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Sfixed32RepeatedPacked() []int32 { + if m != nil { + return m.F_Sfixed32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Sfixed64RepeatedPacked() []int64 { + if m != nil { + return m.F_Sfixed64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetRequiredgroup() *GoTest_RequiredGroup { + if m != nil { + return m.Requiredgroup + } + return nil +} + +func (m *GoTest) GetRepeatedgroup() []*GoTest_RepeatedGroup { + if m != nil { + return m.Repeatedgroup + } + return nil +} + +func (m *GoTest) GetOptionalgroup() *GoTest_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil +} + +// Required, repeated, and optional groups. +type GoTest_RequiredGroup struct { + RequiredField *string `protobuf:"bytes,71,req,name=RequiredField" json:"RequiredField,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTest_RequiredGroup) Reset() { *m = GoTest_RequiredGroup{} } +func (m *GoTest_RequiredGroup) String() string { return proto.CompactTextString(m) } +func (*GoTest_RequiredGroup) ProtoMessage() {} +func (*GoTest_RequiredGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{2, 0} +} +func (m *GoTest_RequiredGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTest_RequiredGroup.Unmarshal(m, b) +} +func (m *GoTest_RequiredGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTest_RequiredGroup.Marshal(b, m, deterministic) +} +func (dst *GoTest_RequiredGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTest_RequiredGroup.Merge(dst, src) +} +func (m *GoTest_RequiredGroup) XXX_Size() int { + return xxx_messageInfo_GoTest_RequiredGroup.Size(m) +} +func (m *GoTest_RequiredGroup) XXX_DiscardUnknown() { + xxx_messageInfo_GoTest_RequiredGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTest_RequiredGroup proto.InternalMessageInfo + +func (m *GoTest_RequiredGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" +} + +type GoTest_RepeatedGroup struct { + RequiredField *string `protobuf:"bytes,81,req,name=RequiredField" json:"RequiredField,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTest_RepeatedGroup) Reset() { *m = GoTest_RepeatedGroup{} } +func (m *GoTest_RepeatedGroup) String() string { return proto.CompactTextString(m) } +func (*GoTest_RepeatedGroup) ProtoMessage() {} +func (*GoTest_RepeatedGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{2, 1} +} +func (m *GoTest_RepeatedGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTest_RepeatedGroup.Unmarshal(m, b) +} +func (m *GoTest_RepeatedGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTest_RepeatedGroup.Marshal(b, m, deterministic) +} +func (dst *GoTest_RepeatedGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTest_RepeatedGroup.Merge(dst, src) +} +func (m *GoTest_RepeatedGroup) XXX_Size() int { + return xxx_messageInfo_GoTest_RepeatedGroup.Size(m) +} +func (m *GoTest_RepeatedGroup) XXX_DiscardUnknown() { + xxx_messageInfo_GoTest_RepeatedGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTest_RepeatedGroup proto.InternalMessageInfo + +func (m *GoTest_RepeatedGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" +} + +type GoTest_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,91,req,name=RequiredField" json:"RequiredField,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTest_OptionalGroup) Reset() { *m = GoTest_OptionalGroup{} } +func (m *GoTest_OptionalGroup) String() string { return proto.CompactTextString(m) } +func (*GoTest_OptionalGroup) ProtoMessage() {} +func (*GoTest_OptionalGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{2, 2} +} +func (m *GoTest_OptionalGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTest_OptionalGroup.Unmarshal(m, b) +} +func (m *GoTest_OptionalGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTest_OptionalGroup.Marshal(b, m, deterministic) +} +func (dst *GoTest_OptionalGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTest_OptionalGroup.Merge(dst, src) +} +func (m *GoTest_OptionalGroup) XXX_Size() int { + return xxx_messageInfo_GoTest_OptionalGroup.Size(m) +} +func (m *GoTest_OptionalGroup) XXX_DiscardUnknown() { + xxx_messageInfo_GoTest_OptionalGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTest_OptionalGroup proto.InternalMessageInfo + +func (m *GoTest_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" +} + +// For testing a group containing a required field. +type GoTestRequiredGroupField struct { + Group *GoTestRequiredGroupField_Group `protobuf:"group,1,req,name=Group,json=group" json:"group,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTestRequiredGroupField) Reset() { *m = GoTestRequiredGroupField{} } +func (m *GoTestRequiredGroupField) String() string { return proto.CompactTextString(m) } +func (*GoTestRequiredGroupField) ProtoMessage() {} +func (*GoTestRequiredGroupField) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{3} +} +func (m *GoTestRequiredGroupField) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTestRequiredGroupField.Unmarshal(m, b) +} +func (m *GoTestRequiredGroupField) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTestRequiredGroupField.Marshal(b, m, deterministic) +} +func (dst *GoTestRequiredGroupField) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTestRequiredGroupField.Merge(dst, src) +} +func (m *GoTestRequiredGroupField) XXX_Size() int { + return xxx_messageInfo_GoTestRequiredGroupField.Size(m) +} +func (m *GoTestRequiredGroupField) XXX_DiscardUnknown() { + xxx_messageInfo_GoTestRequiredGroupField.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTestRequiredGroupField proto.InternalMessageInfo + +func (m *GoTestRequiredGroupField) GetGroup() *GoTestRequiredGroupField_Group { + if m != nil { + return m.Group + } + return nil +} + +type GoTestRequiredGroupField_Group struct { + Field *int32 `protobuf:"varint,2,req,name=Field" json:"Field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoTestRequiredGroupField_Group) Reset() { *m = GoTestRequiredGroupField_Group{} } +func (m *GoTestRequiredGroupField_Group) String() string { return proto.CompactTextString(m) } +func (*GoTestRequiredGroupField_Group) ProtoMessage() {} +func (*GoTestRequiredGroupField_Group) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{3, 0} +} +func (m *GoTestRequiredGroupField_Group) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoTestRequiredGroupField_Group.Unmarshal(m, b) +} +func (m *GoTestRequiredGroupField_Group) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoTestRequiredGroupField_Group.Marshal(b, m, deterministic) +} +func (dst *GoTestRequiredGroupField_Group) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoTestRequiredGroupField_Group.Merge(dst, src) +} +func (m *GoTestRequiredGroupField_Group) XXX_Size() int { + return xxx_messageInfo_GoTestRequiredGroupField_Group.Size(m) +} +func (m *GoTestRequiredGroupField_Group) XXX_DiscardUnknown() { + xxx_messageInfo_GoTestRequiredGroupField_Group.DiscardUnknown(m) +} + +var xxx_messageInfo_GoTestRequiredGroupField_Group proto.InternalMessageInfo + +func (m *GoTestRequiredGroupField_Group) GetField() int32 { + if m != nil && m.Field != nil { + return *m.Field + } + return 0 +} + +// For testing skipping of unrecognized fields. +// Numbers are all big, larger than tag numbers in GoTestField, +// the message used in the corresponding test. +type GoSkipTest struct { + SkipInt32 *int32 `protobuf:"varint,11,req,name=skip_int32,json=skipInt32" json:"skip_int32,omitempty"` + SkipFixed32 *uint32 `protobuf:"fixed32,12,req,name=skip_fixed32,json=skipFixed32" json:"skip_fixed32,omitempty"` + SkipFixed64 *uint64 `protobuf:"fixed64,13,req,name=skip_fixed64,json=skipFixed64" json:"skip_fixed64,omitempty"` + SkipString *string `protobuf:"bytes,14,req,name=skip_string,json=skipString" json:"skip_string,omitempty"` + Skipgroup *GoSkipTest_SkipGroup `protobuf:"group,15,req,name=SkipGroup,json=skipgroup" json:"skipgroup,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoSkipTest) Reset() { *m = GoSkipTest{} } +func (m *GoSkipTest) String() string { return proto.CompactTextString(m) } +func (*GoSkipTest) ProtoMessage() {} +func (*GoSkipTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{4} +} +func (m *GoSkipTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoSkipTest.Unmarshal(m, b) +} +func (m *GoSkipTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoSkipTest.Marshal(b, m, deterministic) +} +func (dst *GoSkipTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoSkipTest.Merge(dst, src) +} +func (m *GoSkipTest) XXX_Size() int { + return xxx_messageInfo_GoSkipTest.Size(m) +} +func (m *GoSkipTest) XXX_DiscardUnknown() { + xxx_messageInfo_GoSkipTest.DiscardUnknown(m) +} + +var xxx_messageInfo_GoSkipTest proto.InternalMessageInfo + +func (m *GoSkipTest) GetSkipInt32() int32 { + if m != nil && m.SkipInt32 != nil { + return *m.SkipInt32 + } + return 0 +} + +func (m *GoSkipTest) GetSkipFixed32() uint32 { + if m != nil && m.SkipFixed32 != nil { + return *m.SkipFixed32 + } + return 0 +} + +func (m *GoSkipTest) GetSkipFixed64() uint64 { + if m != nil && m.SkipFixed64 != nil { + return *m.SkipFixed64 + } + return 0 +} + +func (m *GoSkipTest) GetSkipString() string { + if m != nil && m.SkipString != nil { + return *m.SkipString + } + return "" +} + +func (m *GoSkipTest) GetSkipgroup() *GoSkipTest_SkipGroup { + if m != nil { + return m.Skipgroup + } + return nil +} + +type GoSkipTest_SkipGroup struct { + GroupInt32 *int32 `protobuf:"varint,16,req,name=group_int32,json=groupInt32" json:"group_int32,omitempty"` + GroupString *string `protobuf:"bytes,17,req,name=group_string,json=groupString" json:"group_string,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GoSkipTest_SkipGroup) Reset() { *m = GoSkipTest_SkipGroup{} } +func (m *GoSkipTest_SkipGroup) String() string { return proto.CompactTextString(m) } +func (*GoSkipTest_SkipGroup) ProtoMessage() {} +func (*GoSkipTest_SkipGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{4, 0} +} +func (m *GoSkipTest_SkipGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GoSkipTest_SkipGroup.Unmarshal(m, b) +} +func (m *GoSkipTest_SkipGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GoSkipTest_SkipGroup.Marshal(b, m, deterministic) +} +func (dst *GoSkipTest_SkipGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_GoSkipTest_SkipGroup.Merge(dst, src) +} +func (m *GoSkipTest_SkipGroup) XXX_Size() int { + return xxx_messageInfo_GoSkipTest_SkipGroup.Size(m) +} +func (m *GoSkipTest_SkipGroup) XXX_DiscardUnknown() { + xxx_messageInfo_GoSkipTest_SkipGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_GoSkipTest_SkipGroup proto.InternalMessageInfo + +func (m *GoSkipTest_SkipGroup) GetGroupInt32() int32 { + if m != nil && m.GroupInt32 != nil { + return *m.GroupInt32 + } + return 0 +} + +func (m *GoSkipTest_SkipGroup) GetGroupString() string { + if m != nil && m.GroupString != nil { + return *m.GroupString + } + return "" +} + +// For testing packed/non-packed decoder switching. +// A serialized instance of one should be deserializable as the other. +type NonPackedTest struct { + A []int32 `protobuf:"varint,1,rep,name=a" json:"a,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NonPackedTest) Reset() { *m = NonPackedTest{} } +func (m *NonPackedTest) String() string { return proto.CompactTextString(m) } +func (*NonPackedTest) ProtoMessage() {} +func (*NonPackedTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{5} +} +func (m *NonPackedTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NonPackedTest.Unmarshal(m, b) +} +func (m *NonPackedTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NonPackedTest.Marshal(b, m, deterministic) +} +func (dst *NonPackedTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_NonPackedTest.Merge(dst, src) +} +func (m *NonPackedTest) XXX_Size() int { + return xxx_messageInfo_NonPackedTest.Size(m) +} +func (m *NonPackedTest) XXX_DiscardUnknown() { + xxx_messageInfo_NonPackedTest.DiscardUnknown(m) +} + +var xxx_messageInfo_NonPackedTest proto.InternalMessageInfo + +func (m *NonPackedTest) GetA() []int32 { + if m != nil { + return m.A + } + return nil +} + +type PackedTest struct { + B []int32 `protobuf:"varint,1,rep,packed,name=b" json:"b,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PackedTest) Reset() { *m = PackedTest{} } +func (m *PackedTest) String() string { return proto.CompactTextString(m) } +func (*PackedTest) ProtoMessage() {} +func (*PackedTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{6} +} +func (m *PackedTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PackedTest.Unmarshal(m, b) +} +func (m *PackedTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PackedTest.Marshal(b, m, deterministic) +} +func (dst *PackedTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PackedTest.Merge(dst, src) +} +func (m *PackedTest) XXX_Size() int { + return xxx_messageInfo_PackedTest.Size(m) +} +func (m *PackedTest) XXX_DiscardUnknown() { + xxx_messageInfo_PackedTest.DiscardUnknown(m) +} + +var xxx_messageInfo_PackedTest proto.InternalMessageInfo + +func (m *PackedTest) GetB() []int32 { + if m != nil { + return m.B + } + return nil +} + +type MaxTag struct { + // Maximum possible tag number. + LastField *string `protobuf:"bytes,536870911,opt,name=last_field,json=lastField" json:"last_field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MaxTag) Reset() { *m = MaxTag{} } +func (m *MaxTag) String() string { return proto.CompactTextString(m) } +func (*MaxTag) ProtoMessage() {} +func (*MaxTag) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{7} +} +func (m *MaxTag) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MaxTag.Unmarshal(m, b) +} +func (m *MaxTag) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MaxTag.Marshal(b, m, deterministic) +} +func (dst *MaxTag) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaxTag.Merge(dst, src) +} +func (m *MaxTag) XXX_Size() int { + return xxx_messageInfo_MaxTag.Size(m) +} +func (m *MaxTag) XXX_DiscardUnknown() { + xxx_messageInfo_MaxTag.DiscardUnknown(m) +} + +var xxx_messageInfo_MaxTag proto.InternalMessageInfo + +func (m *MaxTag) GetLastField() string { + if m != nil && m.LastField != nil { + return *m.LastField + } + return "" +} + +type OldMessage struct { + Nested *OldMessage_Nested `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` + Num *int32 `protobuf:"varint,2,opt,name=num" json:"num,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OldMessage) Reset() { *m = OldMessage{} } +func (m *OldMessage) String() string { return proto.CompactTextString(m) } +func (*OldMessage) ProtoMessage() {} +func (*OldMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{8} +} +func (m *OldMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OldMessage.Unmarshal(m, b) +} +func (m *OldMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OldMessage.Marshal(b, m, deterministic) +} +func (dst *OldMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_OldMessage.Merge(dst, src) +} +func (m *OldMessage) XXX_Size() int { + return xxx_messageInfo_OldMessage.Size(m) +} +func (m *OldMessage) XXX_DiscardUnknown() { + xxx_messageInfo_OldMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_OldMessage proto.InternalMessageInfo + +func (m *OldMessage) GetNested() *OldMessage_Nested { + if m != nil { + return m.Nested + } + return nil +} + +func (m *OldMessage) GetNum() int32 { + if m != nil && m.Num != nil { + return *m.Num + } + return 0 +} + +type OldMessage_Nested struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OldMessage_Nested) Reset() { *m = OldMessage_Nested{} } +func (m *OldMessage_Nested) String() string { return proto.CompactTextString(m) } +func (*OldMessage_Nested) ProtoMessage() {} +func (*OldMessage_Nested) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{8, 0} +} +func (m *OldMessage_Nested) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OldMessage_Nested.Unmarshal(m, b) +} +func (m *OldMessage_Nested) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OldMessage_Nested.Marshal(b, m, deterministic) +} +func (dst *OldMessage_Nested) XXX_Merge(src proto.Message) { + xxx_messageInfo_OldMessage_Nested.Merge(dst, src) +} +func (m *OldMessage_Nested) XXX_Size() int { + return xxx_messageInfo_OldMessage_Nested.Size(m) +} +func (m *OldMessage_Nested) XXX_DiscardUnknown() { + xxx_messageInfo_OldMessage_Nested.DiscardUnknown(m) +} + +var xxx_messageInfo_OldMessage_Nested proto.InternalMessageInfo + +func (m *OldMessage_Nested) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +// NewMessage is wire compatible with OldMessage; +// imagine it as a future version. +type NewMessage struct { + Nested *NewMessage_Nested `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` + // This is an int32 in OldMessage. + Num *int64 `protobuf:"varint,2,opt,name=num" json:"num,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NewMessage) Reset() { *m = NewMessage{} } +func (m *NewMessage) String() string { return proto.CompactTextString(m) } +func (*NewMessage) ProtoMessage() {} +func (*NewMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{9} +} +func (m *NewMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NewMessage.Unmarshal(m, b) +} +func (m *NewMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NewMessage.Marshal(b, m, deterministic) +} +func (dst *NewMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_NewMessage.Merge(dst, src) +} +func (m *NewMessage) XXX_Size() int { + return xxx_messageInfo_NewMessage.Size(m) +} +func (m *NewMessage) XXX_DiscardUnknown() { + xxx_messageInfo_NewMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_NewMessage proto.InternalMessageInfo + +func (m *NewMessage) GetNested() *NewMessage_Nested { + if m != nil { + return m.Nested + } + return nil +} + +func (m *NewMessage) GetNum() int64 { + if m != nil && m.Num != nil { + return *m.Num + } + return 0 +} + +type NewMessage_Nested struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + FoodGroup *string `protobuf:"bytes,2,opt,name=food_group,json=foodGroup" json:"food_group,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NewMessage_Nested) Reset() { *m = NewMessage_Nested{} } +func (m *NewMessage_Nested) String() string { return proto.CompactTextString(m) } +func (*NewMessage_Nested) ProtoMessage() {} +func (*NewMessage_Nested) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{9, 0} +} +func (m *NewMessage_Nested) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NewMessage_Nested.Unmarshal(m, b) +} +func (m *NewMessage_Nested) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NewMessage_Nested.Marshal(b, m, deterministic) +} +func (dst *NewMessage_Nested) XXX_Merge(src proto.Message) { + xxx_messageInfo_NewMessage_Nested.Merge(dst, src) +} +func (m *NewMessage_Nested) XXX_Size() int { + return xxx_messageInfo_NewMessage_Nested.Size(m) +} +func (m *NewMessage_Nested) XXX_DiscardUnknown() { + xxx_messageInfo_NewMessage_Nested.DiscardUnknown(m) +} + +var xxx_messageInfo_NewMessage_Nested proto.InternalMessageInfo + +func (m *NewMessage_Nested) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *NewMessage_Nested) GetFoodGroup() string { + if m != nil && m.FoodGroup != nil { + return *m.FoodGroup + } + return "" +} + +type InnerMessage struct { + Host *string `protobuf:"bytes,1,req,name=host" json:"host,omitempty"` + Port *int32 `protobuf:"varint,2,opt,name=port,def=4000" json:"port,omitempty"` + Connected *bool `protobuf:"varint,3,opt,name=connected" json:"connected,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InnerMessage) Reset() { *m = InnerMessage{} } +func (m *InnerMessage) String() string { return proto.CompactTextString(m) } +func (*InnerMessage) ProtoMessage() {} +func (*InnerMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{10} +} +func (m *InnerMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InnerMessage.Unmarshal(m, b) +} +func (m *InnerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InnerMessage.Marshal(b, m, deterministic) +} +func (dst *InnerMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_InnerMessage.Merge(dst, src) +} +func (m *InnerMessage) XXX_Size() int { + return xxx_messageInfo_InnerMessage.Size(m) +} +func (m *InnerMessage) XXX_DiscardUnknown() { + xxx_messageInfo_InnerMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_InnerMessage proto.InternalMessageInfo + +const Default_InnerMessage_Port int32 = 4000 + +func (m *InnerMessage) GetHost() string { + if m != nil && m.Host != nil { + return *m.Host + } + return "" +} + +func (m *InnerMessage) GetPort() int32 { + if m != nil && m.Port != nil { + return *m.Port + } + return Default_InnerMessage_Port +} + +func (m *InnerMessage) GetConnected() bool { + if m != nil && m.Connected != nil { + return *m.Connected + } + return false +} + +type OtherMessage struct { + Key *int64 `protobuf:"varint,1,opt,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` + Weight *float32 `protobuf:"fixed32,3,opt,name=weight" json:"weight,omitempty"` + Inner *InnerMessage `protobuf:"bytes,4,opt,name=inner" json:"inner,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OtherMessage) Reset() { *m = OtherMessage{} } +func (m *OtherMessage) String() string { return proto.CompactTextString(m) } +func (*OtherMessage) ProtoMessage() {} +func (*OtherMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{11} +} + +var extRange_OtherMessage = []proto.ExtensionRange{ + {Start: 100, End: 536870911}, +} + +func (*OtherMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_OtherMessage +} +func (m *OtherMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OtherMessage.Unmarshal(m, b) +} +func (m *OtherMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OtherMessage.Marshal(b, m, deterministic) +} +func (dst *OtherMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_OtherMessage.Merge(dst, src) +} +func (m *OtherMessage) XXX_Size() int { + return xxx_messageInfo_OtherMessage.Size(m) +} +func (m *OtherMessage) XXX_DiscardUnknown() { + xxx_messageInfo_OtherMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_OtherMessage proto.InternalMessageInfo + +func (m *OtherMessage) GetKey() int64 { + if m != nil && m.Key != nil { + return *m.Key + } + return 0 +} + +func (m *OtherMessage) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *OtherMessage) GetWeight() float32 { + if m != nil && m.Weight != nil { + return *m.Weight + } + return 0 +} + +func (m *OtherMessage) GetInner() *InnerMessage { + if m != nil { + return m.Inner + } + return nil +} + +type RequiredInnerMessage struct { + LeoFinallyWonAnOscar *InnerMessage `protobuf:"bytes,1,req,name=leo_finally_won_an_oscar,json=leoFinallyWonAnOscar" json:"leo_finally_won_an_oscar,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RequiredInnerMessage) Reset() { *m = RequiredInnerMessage{} } +func (m *RequiredInnerMessage) String() string { return proto.CompactTextString(m) } +func (*RequiredInnerMessage) ProtoMessage() {} +func (*RequiredInnerMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{12} +} +func (m *RequiredInnerMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RequiredInnerMessage.Unmarshal(m, b) +} +func (m *RequiredInnerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RequiredInnerMessage.Marshal(b, m, deterministic) +} +func (dst *RequiredInnerMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequiredInnerMessage.Merge(dst, src) +} +func (m *RequiredInnerMessage) XXX_Size() int { + return xxx_messageInfo_RequiredInnerMessage.Size(m) +} +func (m *RequiredInnerMessage) XXX_DiscardUnknown() { + xxx_messageInfo_RequiredInnerMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_RequiredInnerMessage proto.InternalMessageInfo + +func (m *RequiredInnerMessage) GetLeoFinallyWonAnOscar() *InnerMessage { + if m != nil { + return m.LeoFinallyWonAnOscar + } + return nil +} + +type MyMessage struct { + Count *int32 `protobuf:"varint,1,req,name=count" json:"count,omitempty"` + Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Quote *string `protobuf:"bytes,3,opt,name=quote" json:"quote,omitempty"` + Pet []string `protobuf:"bytes,4,rep,name=pet" json:"pet,omitempty"` + Inner *InnerMessage `protobuf:"bytes,5,opt,name=inner" json:"inner,omitempty"` + Others []*OtherMessage `protobuf:"bytes,6,rep,name=others" json:"others,omitempty"` + WeMustGoDeeper *RequiredInnerMessage `protobuf:"bytes,13,opt,name=we_must_go_deeper,json=weMustGoDeeper" json:"we_must_go_deeper,omitempty"` + RepInner []*InnerMessage `protobuf:"bytes,12,rep,name=rep_inner,json=repInner" json:"rep_inner,omitempty"` + Bikeshed *MyMessage_Color `protobuf:"varint,7,opt,name=bikeshed,enum=test_proto.MyMessage_Color" json:"bikeshed,omitempty"` + Somegroup *MyMessage_SomeGroup `protobuf:"group,8,opt,name=SomeGroup,json=somegroup" json:"somegroup,omitempty"` + // This field becomes [][]byte in the generated code. + RepBytes [][]byte `protobuf:"bytes,10,rep,name=rep_bytes,json=repBytes" json:"rep_bytes,omitempty"` + Bigfloat *float64 `protobuf:"fixed64,11,opt,name=bigfloat" json:"bigfloat,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MyMessage) Reset() { *m = MyMessage{} } +func (m *MyMessage) String() string { return proto.CompactTextString(m) } +func (*MyMessage) ProtoMessage() {} +func (*MyMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{13} +} + +var extRange_MyMessage = []proto.ExtensionRange{ + {Start: 100, End: 536870911}, +} + +func (*MyMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_MyMessage +} +func (m *MyMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MyMessage.Unmarshal(m, b) +} +func (m *MyMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MyMessage.Marshal(b, m, deterministic) +} +func (dst *MyMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_MyMessage.Merge(dst, src) +} +func (m *MyMessage) XXX_Size() int { + return xxx_messageInfo_MyMessage.Size(m) +} +func (m *MyMessage) XXX_DiscardUnknown() { + xxx_messageInfo_MyMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_MyMessage proto.InternalMessageInfo + +func (m *MyMessage) GetCount() int32 { + if m != nil && m.Count != nil { + return *m.Count + } + return 0 +} + +func (m *MyMessage) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *MyMessage) GetQuote() string { + if m != nil && m.Quote != nil { + return *m.Quote + } + return "" +} + +func (m *MyMessage) GetPet() []string { + if m != nil { + return m.Pet + } + return nil +} + +func (m *MyMessage) GetInner() *InnerMessage { + if m != nil { + return m.Inner + } + return nil +} + +func (m *MyMessage) GetOthers() []*OtherMessage { + if m != nil { + return m.Others + } + return nil +} + +func (m *MyMessage) GetWeMustGoDeeper() *RequiredInnerMessage { + if m != nil { + return m.WeMustGoDeeper + } + return nil +} + +func (m *MyMessage) GetRepInner() []*InnerMessage { + if m != nil { + return m.RepInner + } + return nil +} + +func (m *MyMessage) GetBikeshed() MyMessage_Color { + if m != nil && m.Bikeshed != nil { + return *m.Bikeshed + } + return MyMessage_RED +} + +func (m *MyMessage) GetSomegroup() *MyMessage_SomeGroup { + if m != nil { + return m.Somegroup + } + return nil +} + +func (m *MyMessage) GetRepBytes() [][]byte { + if m != nil { + return m.RepBytes + } + return nil +} + +func (m *MyMessage) GetBigfloat() float64 { + if m != nil && m.Bigfloat != nil { + return *m.Bigfloat + } + return 0 +} + +type MyMessage_SomeGroup struct { + GroupField *int32 `protobuf:"varint,9,opt,name=group_field,json=groupField" json:"group_field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MyMessage_SomeGroup) Reset() { *m = MyMessage_SomeGroup{} } +func (m *MyMessage_SomeGroup) String() string { return proto.CompactTextString(m) } +func (*MyMessage_SomeGroup) ProtoMessage() {} +func (*MyMessage_SomeGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{13, 0} +} +func (m *MyMessage_SomeGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MyMessage_SomeGroup.Unmarshal(m, b) +} +func (m *MyMessage_SomeGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MyMessage_SomeGroup.Marshal(b, m, deterministic) +} +func (dst *MyMessage_SomeGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_MyMessage_SomeGroup.Merge(dst, src) +} +func (m *MyMessage_SomeGroup) XXX_Size() int { + return xxx_messageInfo_MyMessage_SomeGroup.Size(m) +} +func (m *MyMessage_SomeGroup) XXX_DiscardUnknown() { + xxx_messageInfo_MyMessage_SomeGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_MyMessage_SomeGroup proto.InternalMessageInfo + +func (m *MyMessage_SomeGroup) GetGroupField() int32 { + if m != nil && m.GroupField != nil { + return *m.GroupField + } + return 0 +} + +type Ext struct { + Data *string `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` + MapField map[int32]int32 `protobuf:"bytes,2,rep,name=map_field,json=mapField" json:"map_field,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Ext) Reset() { *m = Ext{} } +func (m *Ext) String() string { return proto.CompactTextString(m) } +func (*Ext) ProtoMessage() {} +func (*Ext) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{14} +} +func (m *Ext) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Ext.Unmarshal(m, b) +} +func (m *Ext) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Ext.Marshal(b, m, deterministic) +} +func (dst *Ext) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ext.Merge(dst, src) +} +func (m *Ext) XXX_Size() int { + return xxx_messageInfo_Ext.Size(m) +} +func (m *Ext) XXX_DiscardUnknown() { + xxx_messageInfo_Ext.DiscardUnknown(m) +} + +var xxx_messageInfo_Ext proto.InternalMessageInfo + +func (m *Ext) GetData() string { + if m != nil && m.Data != nil { + return *m.Data + } + return "" +} + +func (m *Ext) GetMapField() map[int32]int32 { + if m != nil { + return m.MapField + } + return nil +} + +var E_Ext_More = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: (*Ext)(nil), + Field: 103, + Name: "test_proto.Ext.more", + Tag: "bytes,103,opt,name=more", + Filename: "test_proto/test.proto", +} + +var E_Ext_Text = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: (*string)(nil), + Field: 104, + Name: "test_proto.Ext.text", + Tag: "bytes,104,opt,name=text", + Filename: "test_proto/test.proto", +} + +var E_Ext_Number = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 105, + Name: "test_proto.Ext.number", + Tag: "varint,105,opt,name=number", + Filename: "test_proto/test.proto", +} + +type ComplexExtension struct { + First *int32 `protobuf:"varint,1,opt,name=first" json:"first,omitempty"` + Second *int32 `protobuf:"varint,2,opt,name=second" json:"second,omitempty"` + Third []int32 `protobuf:"varint,3,rep,name=third" json:"third,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ComplexExtension) Reset() { *m = ComplexExtension{} } +func (m *ComplexExtension) String() string { return proto.CompactTextString(m) } +func (*ComplexExtension) ProtoMessage() {} +func (*ComplexExtension) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{15} +} +func (m *ComplexExtension) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ComplexExtension.Unmarshal(m, b) +} +func (m *ComplexExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ComplexExtension.Marshal(b, m, deterministic) +} +func (dst *ComplexExtension) XXX_Merge(src proto.Message) { + xxx_messageInfo_ComplexExtension.Merge(dst, src) +} +func (m *ComplexExtension) XXX_Size() int { + return xxx_messageInfo_ComplexExtension.Size(m) +} +func (m *ComplexExtension) XXX_DiscardUnknown() { + xxx_messageInfo_ComplexExtension.DiscardUnknown(m) +} + +var xxx_messageInfo_ComplexExtension proto.InternalMessageInfo + +func (m *ComplexExtension) GetFirst() int32 { + if m != nil && m.First != nil { + return *m.First + } + return 0 +} + +func (m *ComplexExtension) GetSecond() int32 { + if m != nil && m.Second != nil { + return *m.Second + } + return 0 +} + +func (m *ComplexExtension) GetThird() []int32 { + if m != nil { + return m.Third + } + return nil +} + +type DefaultsMessage struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DefaultsMessage) Reset() { *m = DefaultsMessage{} } +func (m *DefaultsMessage) String() string { return proto.CompactTextString(m) } +func (*DefaultsMessage) ProtoMessage() {} +func (*DefaultsMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{16} +} + +var extRange_DefaultsMessage = []proto.ExtensionRange{ + {Start: 100, End: 536870911}, +} + +func (*DefaultsMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_DefaultsMessage +} +func (m *DefaultsMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DefaultsMessage.Unmarshal(m, b) +} +func (m *DefaultsMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DefaultsMessage.Marshal(b, m, deterministic) +} +func (dst *DefaultsMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_DefaultsMessage.Merge(dst, src) +} +func (m *DefaultsMessage) XXX_Size() int { + return xxx_messageInfo_DefaultsMessage.Size(m) +} +func (m *DefaultsMessage) XXX_DiscardUnknown() { + xxx_messageInfo_DefaultsMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_DefaultsMessage proto.InternalMessageInfo + +type MyMessageSet struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `protobuf_messageset:"1" json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MyMessageSet) Reset() { *m = MyMessageSet{} } +func (m *MyMessageSet) String() string { return proto.CompactTextString(m) } +func (*MyMessageSet) ProtoMessage() {} +func (*MyMessageSet) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{17} +} + +func (m *MyMessageSet) MarshalJSON() ([]byte, error) { + return proto.MarshalMessageSetJSON(&m.XXX_InternalExtensions) +} +func (m *MyMessageSet) UnmarshalJSON(buf []byte) error { + return proto.UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions) +} + +var extRange_MyMessageSet = []proto.ExtensionRange{ + {Start: 100, End: 2147483646}, +} + +func (*MyMessageSet) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_MyMessageSet +} +func (m *MyMessageSet) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MyMessageSet.Unmarshal(m, b) +} +func (m *MyMessageSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MyMessageSet.Marshal(b, m, deterministic) +} +func (dst *MyMessageSet) XXX_Merge(src proto.Message) { + xxx_messageInfo_MyMessageSet.Merge(dst, src) +} +func (m *MyMessageSet) XXX_Size() int { + return xxx_messageInfo_MyMessageSet.Size(m) +} +func (m *MyMessageSet) XXX_DiscardUnknown() { + xxx_messageInfo_MyMessageSet.DiscardUnknown(m) +} + +var xxx_messageInfo_MyMessageSet proto.InternalMessageInfo + +type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{18} +} +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (dst *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(dst, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo + +type MessageList struct { + Message []*MessageList_Message `protobuf:"group,1,rep,name=Message,json=message" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MessageList) Reset() { *m = MessageList{} } +func (m *MessageList) String() string { return proto.CompactTextString(m) } +func (*MessageList) ProtoMessage() {} +func (*MessageList) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{19} +} +func (m *MessageList) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MessageList.Unmarshal(m, b) +} +func (m *MessageList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MessageList.Marshal(b, m, deterministic) +} +func (dst *MessageList) XXX_Merge(src proto.Message) { + xxx_messageInfo_MessageList.Merge(dst, src) +} +func (m *MessageList) XXX_Size() int { + return xxx_messageInfo_MessageList.Size(m) +} +func (m *MessageList) XXX_DiscardUnknown() { + xxx_messageInfo_MessageList.DiscardUnknown(m) +} + +var xxx_messageInfo_MessageList proto.InternalMessageInfo + +func (m *MessageList) GetMessage() []*MessageList_Message { + if m != nil { + return m.Message + } + return nil +} + +type MessageList_Message struct { + Name *string `protobuf:"bytes,2,req,name=name" json:"name,omitempty"` + Count *int32 `protobuf:"varint,3,req,name=count" json:"count,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MessageList_Message) Reset() { *m = MessageList_Message{} } +func (m *MessageList_Message) String() string { return proto.CompactTextString(m) } +func (*MessageList_Message) ProtoMessage() {} +func (*MessageList_Message) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{19, 0} +} +func (m *MessageList_Message) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MessageList_Message.Unmarshal(m, b) +} +func (m *MessageList_Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MessageList_Message.Marshal(b, m, deterministic) +} +func (dst *MessageList_Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_MessageList_Message.Merge(dst, src) +} +func (m *MessageList_Message) XXX_Size() int { + return xxx_messageInfo_MessageList_Message.Size(m) +} +func (m *MessageList_Message) XXX_DiscardUnknown() { + xxx_messageInfo_MessageList_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_MessageList_Message proto.InternalMessageInfo + +func (m *MessageList_Message) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *MessageList_Message) GetCount() int32 { + if m != nil && m.Count != nil { + return *m.Count + } + return 0 +} + +type Strings struct { + StringField *string `protobuf:"bytes,1,opt,name=string_field,json=stringField" json:"string_field,omitempty"` + BytesField []byte `protobuf:"bytes,2,opt,name=bytes_field,json=bytesField" json:"bytes_field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Strings) Reset() { *m = Strings{} } +func (m *Strings) String() string { return proto.CompactTextString(m) } +func (*Strings) ProtoMessage() {} +func (*Strings) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{20} +} +func (m *Strings) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Strings.Unmarshal(m, b) +} +func (m *Strings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Strings.Marshal(b, m, deterministic) +} +func (dst *Strings) XXX_Merge(src proto.Message) { + xxx_messageInfo_Strings.Merge(dst, src) +} +func (m *Strings) XXX_Size() int { + return xxx_messageInfo_Strings.Size(m) +} +func (m *Strings) XXX_DiscardUnknown() { + xxx_messageInfo_Strings.DiscardUnknown(m) +} + +var xxx_messageInfo_Strings proto.InternalMessageInfo + +func (m *Strings) GetStringField() string { + if m != nil && m.StringField != nil { + return *m.StringField + } + return "" +} + +func (m *Strings) GetBytesField() []byte { + if m != nil { + return m.BytesField + } + return nil +} + +type Defaults struct { + // Default-valued fields of all basic types. + // Same as GoTest, but copied here to make testing easier. + F_Bool *bool `protobuf:"varint,1,opt,name=F_Bool,json=FBool,def=1" json:"F_Bool,omitempty"` + F_Int32 *int32 `protobuf:"varint,2,opt,name=F_Int32,json=FInt32,def=32" json:"F_Int32,omitempty"` + F_Int64 *int64 `protobuf:"varint,3,opt,name=F_Int64,json=FInt64,def=64" json:"F_Int64,omitempty"` + F_Fixed32 *uint32 `protobuf:"fixed32,4,opt,name=F_Fixed32,json=FFixed32,def=320" json:"F_Fixed32,omitempty"` + F_Fixed64 *uint64 `protobuf:"fixed64,5,opt,name=F_Fixed64,json=FFixed64,def=640" json:"F_Fixed64,omitempty"` + F_Uint32 *uint32 `protobuf:"varint,6,opt,name=F_Uint32,json=FUint32,def=3200" json:"F_Uint32,omitempty"` + F_Uint64 *uint64 `protobuf:"varint,7,opt,name=F_Uint64,json=FUint64,def=6400" json:"F_Uint64,omitempty"` + F_Float *float32 `protobuf:"fixed32,8,opt,name=F_Float,json=FFloat,def=314159" json:"F_Float,omitempty"` + F_Double *float64 `protobuf:"fixed64,9,opt,name=F_Double,json=FDouble,def=271828" json:"F_Double,omitempty"` + F_String *string `protobuf:"bytes,10,opt,name=F_String,json=FString,def=hello, \"world!\"\n" json:"F_String,omitempty"` + F_Bytes []byte `protobuf:"bytes,11,opt,name=F_Bytes,json=FBytes,def=Bignose" json:"F_Bytes,omitempty"` + F_Sint32 *int32 `protobuf:"zigzag32,12,opt,name=F_Sint32,json=FSint32,def=-32" json:"F_Sint32,omitempty"` + F_Sint64 *int64 `protobuf:"zigzag64,13,opt,name=F_Sint64,json=FSint64,def=-64" json:"F_Sint64,omitempty"` + F_Enum *Defaults_Color `protobuf:"varint,14,opt,name=F_Enum,json=FEnum,enum=test_proto.Defaults_Color,def=1" json:"F_Enum,omitempty"` + // More fields with crazy defaults. + F_Pinf *float32 `protobuf:"fixed32,15,opt,name=F_Pinf,json=FPinf,def=inf" json:"F_Pinf,omitempty"` + F_Ninf *float32 `protobuf:"fixed32,16,opt,name=F_Ninf,json=FNinf,def=-inf" json:"F_Ninf,omitempty"` + F_Nan *float32 `protobuf:"fixed32,17,opt,name=F_Nan,json=FNan,def=nan" json:"F_Nan,omitempty"` + // Sub-message. + Sub *SubDefaults `protobuf:"bytes,18,opt,name=sub" json:"sub,omitempty"` + // Redundant but explicit defaults. + StrZero *string `protobuf:"bytes,19,opt,name=str_zero,json=strZero,def=" json:"str_zero,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Defaults) Reset() { *m = Defaults{} } +func (m *Defaults) String() string { return proto.CompactTextString(m) } +func (*Defaults) ProtoMessage() {} +func (*Defaults) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{21} +} +func (m *Defaults) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Defaults.Unmarshal(m, b) +} +func (m *Defaults) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Defaults.Marshal(b, m, deterministic) +} +func (dst *Defaults) XXX_Merge(src proto.Message) { + xxx_messageInfo_Defaults.Merge(dst, src) +} +func (m *Defaults) XXX_Size() int { + return xxx_messageInfo_Defaults.Size(m) +} +func (m *Defaults) XXX_DiscardUnknown() { + xxx_messageInfo_Defaults.DiscardUnknown(m) +} + +var xxx_messageInfo_Defaults proto.InternalMessageInfo + +const Default_Defaults_F_Bool bool = true +const Default_Defaults_F_Int32 int32 = 32 +const Default_Defaults_F_Int64 int64 = 64 +const Default_Defaults_F_Fixed32 uint32 = 320 +const Default_Defaults_F_Fixed64 uint64 = 640 +const Default_Defaults_F_Uint32 uint32 = 3200 +const Default_Defaults_F_Uint64 uint64 = 6400 +const Default_Defaults_F_Float float32 = 314159 +const Default_Defaults_F_Double float64 = 271828 +const Default_Defaults_F_String string = "hello, \"world!\"\n" + +var Default_Defaults_F_Bytes []byte = []byte("Bignose") + +const Default_Defaults_F_Sint32 int32 = -32 +const Default_Defaults_F_Sint64 int64 = -64 +const Default_Defaults_F_Enum Defaults_Color = Defaults_GREEN + +var Default_Defaults_F_Pinf float32 = float32(math.Inf(1)) +var Default_Defaults_F_Ninf float32 = float32(math.Inf(-1)) +var Default_Defaults_F_Nan float32 = float32(math.NaN()) + +func (m *Defaults) GetF_Bool() bool { + if m != nil && m.F_Bool != nil { + return *m.F_Bool + } + return Default_Defaults_F_Bool +} + +func (m *Defaults) GetF_Int32() int32 { + if m != nil && m.F_Int32 != nil { + return *m.F_Int32 + } + return Default_Defaults_F_Int32 +} + +func (m *Defaults) GetF_Int64() int64 { + if m != nil && m.F_Int64 != nil { + return *m.F_Int64 + } + return Default_Defaults_F_Int64 +} + +func (m *Defaults) GetF_Fixed32() uint32 { + if m != nil && m.F_Fixed32 != nil { + return *m.F_Fixed32 + } + return Default_Defaults_F_Fixed32 +} + +func (m *Defaults) GetF_Fixed64() uint64 { + if m != nil && m.F_Fixed64 != nil { + return *m.F_Fixed64 + } + return Default_Defaults_F_Fixed64 +} + +func (m *Defaults) GetF_Uint32() uint32 { + if m != nil && m.F_Uint32 != nil { + return *m.F_Uint32 + } + return Default_Defaults_F_Uint32 +} + +func (m *Defaults) GetF_Uint64() uint64 { + if m != nil && m.F_Uint64 != nil { + return *m.F_Uint64 + } + return Default_Defaults_F_Uint64 +} + +func (m *Defaults) GetF_Float() float32 { + if m != nil && m.F_Float != nil { + return *m.F_Float + } + return Default_Defaults_F_Float +} + +func (m *Defaults) GetF_Double() float64 { + if m != nil && m.F_Double != nil { + return *m.F_Double + } + return Default_Defaults_F_Double +} + +func (m *Defaults) GetF_String() string { + if m != nil && m.F_String != nil { + return *m.F_String + } + return Default_Defaults_F_String +} + +func (m *Defaults) GetF_Bytes() []byte { + if m != nil && m.F_Bytes != nil { + return m.F_Bytes + } + return append([]byte(nil), Default_Defaults_F_Bytes...) +} + +func (m *Defaults) GetF_Sint32() int32 { + if m != nil && m.F_Sint32 != nil { + return *m.F_Sint32 + } + return Default_Defaults_F_Sint32 +} + +func (m *Defaults) GetF_Sint64() int64 { + if m != nil && m.F_Sint64 != nil { + return *m.F_Sint64 + } + return Default_Defaults_F_Sint64 +} + +func (m *Defaults) GetF_Enum() Defaults_Color { + if m != nil && m.F_Enum != nil { + return *m.F_Enum + } + return Default_Defaults_F_Enum +} + +func (m *Defaults) GetF_Pinf() float32 { + if m != nil && m.F_Pinf != nil { + return *m.F_Pinf + } + return Default_Defaults_F_Pinf +} + +func (m *Defaults) GetF_Ninf() float32 { + if m != nil && m.F_Ninf != nil { + return *m.F_Ninf + } + return Default_Defaults_F_Ninf +} + +func (m *Defaults) GetF_Nan() float32 { + if m != nil && m.F_Nan != nil { + return *m.F_Nan + } + return Default_Defaults_F_Nan +} + +func (m *Defaults) GetSub() *SubDefaults { + if m != nil { + return m.Sub + } + return nil +} + +func (m *Defaults) GetStrZero() string { + if m != nil && m.StrZero != nil { + return *m.StrZero + } + return "" +} + +type SubDefaults struct { + N *int64 `protobuf:"varint,1,opt,name=n,def=7" json:"n,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SubDefaults) Reset() { *m = SubDefaults{} } +func (m *SubDefaults) String() string { return proto.CompactTextString(m) } +func (*SubDefaults) ProtoMessage() {} +func (*SubDefaults) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{22} +} +func (m *SubDefaults) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SubDefaults.Unmarshal(m, b) +} +func (m *SubDefaults) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SubDefaults.Marshal(b, m, deterministic) +} +func (dst *SubDefaults) XXX_Merge(src proto.Message) { + xxx_messageInfo_SubDefaults.Merge(dst, src) +} +func (m *SubDefaults) XXX_Size() int { + return xxx_messageInfo_SubDefaults.Size(m) +} +func (m *SubDefaults) XXX_DiscardUnknown() { + xxx_messageInfo_SubDefaults.DiscardUnknown(m) +} + +var xxx_messageInfo_SubDefaults proto.InternalMessageInfo + +const Default_SubDefaults_N int64 = 7 + +func (m *SubDefaults) GetN() int64 { + if m != nil && m.N != nil { + return *m.N + } + return Default_SubDefaults_N +} + +type RepeatedEnum struct { + Color []RepeatedEnum_Color `protobuf:"varint,1,rep,name=color,enum=test_proto.RepeatedEnum_Color" json:"color,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RepeatedEnum) Reset() { *m = RepeatedEnum{} } +func (m *RepeatedEnum) String() string { return proto.CompactTextString(m) } +func (*RepeatedEnum) ProtoMessage() {} +func (*RepeatedEnum) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{23} +} +func (m *RepeatedEnum) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RepeatedEnum.Unmarshal(m, b) +} +func (m *RepeatedEnum) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RepeatedEnum.Marshal(b, m, deterministic) +} +func (dst *RepeatedEnum) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepeatedEnum.Merge(dst, src) +} +func (m *RepeatedEnum) XXX_Size() int { + return xxx_messageInfo_RepeatedEnum.Size(m) +} +func (m *RepeatedEnum) XXX_DiscardUnknown() { + xxx_messageInfo_RepeatedEnum.DiscardUnknown(m) +} + +var xxx_messageInfo_RepeatedEnum proto.InternalMessageInfo + +func (m *RepeatedEnum) GetColor() []RepeatedEnum_Color { + if m != nil { + return m.Color + } + return nil +} + +type MoreRepeated struct { + Bools []bool `protobuf:"varint,1,rep,name=bools" json:"bools,omitempty"` + BoolsPacked []bool `protobuf:"varint,2,rep,packed,name=bools_packed,json=boolsPacked" json:"bools_packed,omitempty"` + Ints []int32 `protobuf:"varint,3,rep,name=ints" json:"ints,omitempty"` + IntsPacked []int32 `protobuf:"varint,4,rep,packed,name=ints_packed,json=intsPacked" json:"ints_packed,omitempty"` + Int64SPacked []int64 `protobuf:"varint,7,rep,packed,name=int64s_packed,json=int64sPacked" json:"int64s_packed,omitempty"` + Strings []string `protobuf:"bytes,5,rep,name=strings" json:"strings,omitempty"` + Fixeds []uint32 `protobuf:"fixed32,6,rep,name=fixeds" json:"fixeds,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MoreRepeated) Reset() { *m = MoreRepeated{} } +func (m *MoreRepeated) String() string { return proto.CompactTextString(m) } +func (*MoreRepeated) ProtoMessage() {} +func (*MoreRepeated) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{24} +} +func (m *MoreRepeated) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MoreRepeated.Unmarshal(m, b) +} +func (m *MoreRepeated) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MoreRepeated.Marshal(b, m, deterministic) +} +func (dst *MoreRepeated) XXX_Merge(src proto.Message) { + xxx_messageInfo_MoreRepeated.Merge(dst, src) +} +func (m *MoreRepeated) XXX_Size() int { + return xxx_messageInfo_MoreRepeated.Size(m) +} +func (m *MoreRepeated) XXX_DiscardUnknown() { + xxx_messageInfo_MoreRepeated.DiscardUnknown(m) +} + +var xxx_messageInfo_MoreRepeated proto.InternalMessageInfo + +func (m *MoreRepeated) GetBools() []bool { + if m != nil { + return m.Bools + } + return nil +} + +func (m *MoreRepeated) GetBoolsPacked() []bool { + if m != nil { + return m.BoolsPacked + } + return nil +} + +func (m *MoreRepeated) GetInts() []int32 { + if m != nil { + return m.Ints + } + return nil +} + +func (m *MoreRepeated) GetIntsPacked() []int32 { + if m != nil { + return m.IntsPacked + } + return nil +} + +func (m *MoreRepeated) GetInt64SPacked() []int64 { + if m != nil { + return m.Int64SPacked + } + return nil +} + +func (m *MoreRepeated) GetStrings() []string { + if m != nil { + return m.Strings + } + return nil +} + +func (m *MoreRepeated) GetFixeds() []uint32 { + if m != nil { + return m.Fixeds + } + return nil +} + +type GroupOld struct { + G *GroupOld_G `protobuf:"group,101,opt,name=G,json=g" json:"g,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupOld) Reset() { *m = GroupOld{} } +func (m *GroupOld) String() string { return proto.CompactTextString(m) } +func (*GroupOld) ProtoMessage() {} +func (*GroupOld) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{25} +} +func (m *GroupOld) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupOld.Unmarshal(m, b) +} +func (m *GroupOld) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupOld.Marshal(b, m, deterministic) +} +func (dst *GroupOld) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupOld.Merge(dst, src) +} +func (m *GroupOld) XXX_Size() int { + return xxx_messageInfo_GroupOld.Size(m) +} +func (m *GroupOld) XXX_DiscardUnknown() { + xxx_messageInfo_GroupOld.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupOld proto.InternalMessageInfo + +func (m *GroupOld) GetG() *GroupOld_G { + if m != nil { + return m.G + } + return nil +} + +type GroupOld_G struct { + X *int32 `protobuf:"varint,2,opt,name=x" json:"x,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupOld_G) Reset() { *m = GroupOld_G{} } +func (m *GroupOld_G) String() string { return proto.CompactTextString(m) } +func (*GroupOld_G) ProtoMessage() {} +func (*GroupOld_G) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{25, 0} +} +func (m *GroupOld_G) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupOld_G.Unmarshal(m, b) +} +func (m *GroupOld_G) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupOld_G.Marshal(b, m, deterministic) +} +func (dst *GroupOld_G) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupOld_G.Merge(dst, src) +} +func (m *GroupOld_G) XXX_Size() int { + return xxx_messageInfo_GroupOld_G.Size(m) +} +func (m *GroupOld_G) XXX_DiscardUnknown() { + xxx_messageInfo_GroupOld_G.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupOld_G proto.InternalMessageInfo + +func (m *GroupOld_G) GetX() int32 { + if m != nil && m.X != nil { + return *m.X + } + return 0 +} + +type GroupNew struct { + G *GroupNew_G `protobuf:"group,101,opt,name=G,json=g" json:"g,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupNew) Reset() { *m = GroupNew{} } +func (m *GroupNew) String() string { return proto.CompactTextString(m) } +func (*GroupNew) ProtoMessage() {} +func (*GroupNew) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{26} +} +func (m *GroupNew) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupNew.Unmarshal(m, b) +} +func (m *GroupNew) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupNew.Marshal(b, m, deterministic) +} +func (dst *GroupNew) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupNew.Merge(dst, src) +} +func (m *GroupNew) XXX_Size() int { + return xxx_messageInfo_GroupNew.Size(m) +} +func (m *GroupNew) XXX_DiscardUnknown() { + xxx_messageInfo_GroupNew.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupNew proto.InternalMessageInfo + +func (m *GroupNew) GetG() *GroupNew_G { + if m != nil { + return m.G + } + return nil +} + +type GroupNew_G struct { + X *int32 `protobuf:"varint,2,opt,name=x" json:"x,omitempty"` + Y *int32 `protobuf:"varint,3,opt,name=y" json:"y,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupNew_G) Reset() { *m = GroupNew_G{} } +func (m *GroupNew_G) String() string { return proto.CompactTextString(m) } +func (*GroupNew_G) ProtoMessage() {} +func (*GroupNew_G) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{26, 0} +} +func (m *GroupNew_G) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupNew_G.Unmarshal(m, b) +} +func (m *GroupNew_G) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupNew_G.Marshal(b, m, deterministic) +} +func (dst *GroupNew_G) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupNew_G.Merge(dst, src) +} +func (m *GroupNew_G) XXX_Size() int { + return xxx_messageInfo_GroupNew_G.Size(m) +} +func (m *GroupNew_G) XXX_DiscardUnknown() { + xxx_messageInfo_GroupNew_G.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupNew_G proto.InternalMessageInfo + +func (m *GroupNew_G) GetX() int32 { + if m != nil && m.X != nil { + return *m.X + } + return 0 +} + +func (m *GroupNew_G) GetY() int32 { + if m != nil && m.Y != nil { + return *m.Y + } + return 0 +} + +type FloatingPoint struct { + F *float64 `protobuf:"fixed64,1,req,name=f" json:"f,omitempty"` + Exact *bool `protobuf:"varint,2,opt,name=exact" json:"exact,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FloatingPoint) Reset() { *m = FloatingPoint{} } +func (m *FloatingPoint) String() string { return proto.CompactTextString(m) } +func (*FloatingPoint) ProtoMessage() {} +func (*FloatingPoint) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{27} +} +func (m *FloatingPoint) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FloatingPoint.Unmarshal(m, b) +} +func (m *FloatingPoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FloatingPoint.Marshal(b, m, deterministic) +} +func (dst *FloatingPoint) XXX_Merge(src proto.Message) { + xxx_messageInfo_FloatingPoint.Merge(dst, src) +} +func (m *FloatingPoint) XXX_Size() int { + return xxx_messageInfo_FloatingPoint.Size(m) +} +func (m *FloatingPoint) XXX_DiscardUnknown() { + xxx_messageInfo_FloatingPoint.DiscardUnknown(m) +} + +var xxx_messageInfo_FloatingPoint proto.InternalMessageInfo + +func (m *FloatingPoint) GetF() float64 { + if m != nil && m.F != nil { + return *m.F + } + return 0 +} + +func (m *FloatingPoint) GetExact() bool { + if m != nil && m.Exact != nil { + return *m.Exact + } + return false +} + +type MessageWithMap struct { + NameMapping map[int32]string `protobuf:"bytes,1,rep,name=name_mapping,json=nameMapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + MsgMapping map[int64]*FloatingPoint `protobuf:"bytes,2,rep,name=msg_mapping,json=msgMapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + ByteMapping map[bool][]byte `protobuf:"bytes,3,rep,name=byte_mapping,json=byteMapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + StrToStr map[string]string `protobuf:"bytes,4,rep,name=str_to_str,json=strToStr" json:"str_to_str,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MessageWithMap) Reset() { *m = MessageWithMap{} } +func (m *MessageWithMap) String() string { return proto.CompactTextString(m) } +func (*MessageWithMap) ProtoMessage() {} +func (*MessageWithMap) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{28} +} +func (m *MessageWithMap) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MessageWithMap.Unmarshal(m, b) +} +func (m *MessageWithMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MessageWithMap.Marshal(b, m, deterministic) +} +func (dst *MessageWithMap) XXX_Merge(src proto.Message) { + xxx_messageInfo_MessageWithMap.Merge(dst, src) +} +func (m *MessageWithMap) XXX_Size() int { + return xxx_messageInfo_MessageWithMap.Size(m) +} +func (m *MessageWithMap) XXX_DiscardUnknown() { + xxx_messageInfo_MessageWithMap.DiscardUnknown(m) +} + +var xxx_messageInfo_MessageWithMap proto.InternalMessageInfo + +func (m *MessageWithMap) GetNameMapping() map[int32]string { + if m != nil { + return m.NameMapping + } + return nil +} + +func (m *MessageWithMap) GetMsgMapping() map[int64]*FloatingPoint { + if m != nil { + return m.MsgMapping + } + return nil +} + +func (m *MessageWithMap) GetByteMapping() map[bool][]byte { + if m != nil { + return m.ByteMapping + } + return nil +} + +func (m *MessageWithMap) GetStrToStr() map[string]string { + if m != nil { + return m.StrToStr + } + return nil +} + +type Oneof struct { + // Types that are valid to be assigned to Union: + // *Oneof_F_Bool + // *Oneof_F_Int32 + // *Oneof_F_Int64 + // *Oneof_F_Fixed32 + // *Oneof_F_Fixed64 + // *Oneof_F_Uint32 + // *Oneof_F_Uint64 + // *Oneof_F_Float + // *Oneof_F_Double + // *Oneof_F_String + // *Oneof_F_Bytes + // *Oneof_F_Sint32 + // *Oneof_F_Sint64 + // *Oneof_F_Enum + // *Oneof_F_Message + // *Oneof_FGroup + // *Oneof_F_Largest_Tag + Union isOneof_Union `protobuf_oneof:"union"` + // Types that are valid to be assigned to Tormato: + // *Oneof_Value + Tormato isOneof_Tormato `protobuf_oneof:"tormato"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Oneof) Reset() { *m = Oneof{} } +func (m *Oneof) String() string { return proto.CompactTextString(m) } +func (*Oneof) ProtoMessage() {} +func (*Oneof) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{29} +} +func (m *Oneof) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Oneof.Unmarshal(m, b) +} +func (m *Oneof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Oneof.Marshal(b, m, deterministic) +} +func (dst *Oneof) XXX_Merge(src proto.Message) { + xxx_messageInfo_Oneof.Merge(dst, src) +} +func (m *Oneof) XXX_Size() int { + return xxx_messageInfo_Oneof.Size(m) +} +func (m *Oneof) XXX_DiscardUnknown() { + xxx_messageInfo_Oneof.DiscardUnknown(m) +} + +var xxx_messageInfo_Oneof proto.InternalMessageInfo + +type isOneof_Union interface { + isOneof_Union() +} + +type Oneof_F_Bool struct { + F_Bool bool `protobuf:"varint,1,opt,name=F_Bool,json=FBool,oneof"` +} + +type Oneof_F_Int32 struct { + F_Int32 int32 `protobuf:"varint,2,opt,name=F_Int32,json=FInt32,oneof"` +} + +type Oneof_F_Int64 struct { + F_Int64 int64 `protobuf:"varint,3,opt,name=F_Int64,json=FInt64,oneof"` +} + +type Oneof_F_Fixed32 struct { + F_Fixed32 uint32 `protobuf:"fixed32,4,opt,name=F_Fixed32,json=FFixed32,oneof"` +} + +type Oneof_F_Fixed64 struct { + F_Fixed64 uint64 `protobuf:"fixed64,5,opt,name=F_Fixed64,json=FFixed64,oneof"` +} + +type Oneof_F_Uint32 struct { + F_Uint32 uint32 `protobuf:"varint,6,opt,name=F_Uint32,json=FUint32,oneof"` +} + +type Oneof_F_Uint64 struct { + F_Uint64 uint64 `protobuf:"varint,7,opt,name=F_Uint64,json=FUint64,oneof"` +} + +type Oneof_F_Float struct { + F_Float float32 `protobuf:"fixed32,8,opt,name=F_Float,json=FFloat,oneof"` +} + +type Oneof_F_Double struct { + F_Double float64 `protobuf:"fixed64,9,opt,name=F_Double,json=FDouble,oneof"` +} + +type Oneof_F_String struct { + F_String string `protobuf:"bytes,10,opt,name=F_String,json=FString,oneof"` +} + +type Oneof_F_Bytes struct { + F_Bytes []byte `protobuf:"bytes,11,opt,name=F_Bytes,json=FBytes,oneof"` +} + +type Oneof_F_Sint32 struct { + F_Sint32 int32 `protobuf:"zigzag32,12,opt,name=F_Sint32,json=FSint32,oneof"` +} + +type Oneof_F_Sint64 struct { + F_Sint64 int64 `protobuf:"zigzag64,13,opt,name=F_Sint64,json=FSint64,oneof"` +} + +type Oneof_F_Enum struct { + F_Enum MyMessage_Color `protobuf:"varint,14,opt,name=F_Enum,json=FEnum,enum=test_proto.MyMessage_Color,oneof"` +} + +type Oneof_F_Message struct { + F_Message *GoTestField `protobuf:"bytes,15,opt,name=F_Message,json=FMessage,oneof"` +} + +type Oneof_FGroup struct { + FGroup *Oneof_F_Group `protobuf:"group,16,opt,name=F_Group,json=fGroup,oneof"` +} + +type Oneof_F_Largest_Tag struct { + F_Largest_Tag int32 `protobuf:"varint,536870911,opt,name=F_Largest_Tag,json=FLargestTag,oneof"` +} + +func (*Oneof_F_Bool) isOneof_Union() {} + +func (*Oneof_F_Int32) isOneof_Union() {} + +func (*Oneof_F_Int64) isOneof_Union() {} + +func (*Oneof_F_Fixed32) isOneof_Union() {} + +func (*Oneof_F_Fixed64) isOneof_Union() {} + +func (*Oneof_F_Uint32) isOneof_Union() {} + +func (*Oneof_F_Uint64) isOneof_Union() {} + +func (*Oneof_F_Float) isOneof_Union() {} + +func (*Oneof_F_Double) isOneof_Union() {} + +func (*Oneof_F_String) isOneof_Union() {} + +func (*Oneof_F_Bytes) isOneof_Union() {} + +func (*Oneof_F_Sint32) isOneof_Union() {} + +func (*Oneof_F_Sint64) isOneof_Union() {} + +func (*Oneof_F_Enum) isOneof_Union() {} + +func (*Oneof_F_Message) isOneof_Union() {} + +func (*Oneof_FGroup) isOneof_Union() {} + +func (*Oneof_F_Largest_Tag) isOneof_Union() {} + +func (m *Oneof) GetUnion() isOneof_Union { + if m != nil { + return m.Union + } + return nil +} + +func (m *Oneof) GetF_Bool() bool { + if x, ok := m.GetUnion().(*Oneof_F_Bool); ok { + return x.F_Bool + } + return false +} + +func (m *Oneof) GetF_Int32() int32 { + if x, ok := m.GetUnion().(*Oneof_F_Int32); ok { + return x.F_Int32 + } + return 0 +} + +func (m *Oneof) GetF_Int64() int64 { + if x, ok := m.GetUnion().(*Oneof_F_Int64); ok { + return x.F_Int64 + } + return 0 +} + +func (m *Oneof) GetF_Fixed32() uint32 { + if x, ok := m.GetUnion().(*Oneof_F_Fixed32); ok { + return x.F_Fixed32 + } + return 0 +} + +func (m *Oneof) GetF_Fixed64() uint64 { + if x, ok := m.GetUnion().(*Oneof_F_Fixed64); ok { + return x.F_Fixed64 + } + return 0 +} + +func (m *Oneof) GetF_Uint32() uint32 { + if x, ok := m.GetUnion().(*Oneof_F_Uint32); ok { + return x.F_Uint32 + } + return 0 +} + +func (m *Oneof) GetF_Uint64() uint64 { + if x, ok := m.GetUnion().(*Oneof_F_Uint64); ok { + return x.F_Uint64 + } + return 0 +} + +func (m *Oneof) GetF_Float() float32 { + if x, ok := m.GetUnion().(*Oneof_F_Float); ok { + return x.F_Float + } + return 0 +} + +func (m *Oneof) GetF_Double() float64 { + if x, ok := m.GetUnion().(*Oneof_F_Double); ok { + return x.F_Double + } + return 0 +} + +func (m *Oneof) GetF_String() string { + if x, ok := m.GetUnion().(*Oneof_F_String); ok { + return x.F_String + } + return "" +} + +func (m *Oneof) GetF_Bytes() []byte { + if x, ok := m.GetUnion().(*Oneof_F_Bytes); ok { + return x.F_Bytes + } + return nil +} + +func (m *Oneof) GetF_Sint32() int32 { + if x, ok := m.GetUnion().(*Oneof_F_Sint32); ok { + return x.F_Sint32 + } + return 0 +} + +func (m *Oneof) GetF_Sint64() int64 { + if x, ok := m.GetUnion().(*Oneof_F_Sint64); ok { + return x.F_Sint64 + } + return 0 +} + +func (m *Oneof) GetF_Enum() MyMessage_Color { + if x, ok := m.GetUnion().(*Oneof_F_Enum); ok { + return x.F_Enum + } + return MyMessage_RED +} + +func (m *Oneof) GetF_Message() *GoTestField { + if x, ok := m.GetUnion().(*Oneof_F_Message); ok { + return x.F_Message + } + return nil +} + +func (m *Oneof) GetFGroup() *Oneof_F_Group { + if x, ok := m.GetUnion().(*Oneof_FGroup); ok { + return x.FGroup + } + return nil +} + +func (m *Oneof) GetF_Largest_Tag() int32 { + if x, ok := m.GetUnion().(*Oneof_F_Largest_Tag); ok { + return x.F_Largest_Tag + } + return 0 +} + +type isOneof_Tormato interface { + isOneof_Tormato() +} + +type Oneof_Value struct { + Value int32 `protobuf:"varint,100,opt,name=value,oneof"` +} + +func (*Oneof_Value) isOneof_Tormato() {} + +func (m *Oneof) GetTormato() isOneof_Tormato { + if m != nil { + return m.Tormato + } + return nil +} + +func (m *Oneof) GetValue() int32 { + if x, ok := m.GetTormato().(*Oneof_Value); ok { + return x.Value + } + return 0 +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Oneof) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Oneof_OneofMarshaler, _Oneof_OneofUnmarshaler, _Oneof_OneofSizer, []interface{}{ + (*Oneof_F_Bool)(nil), + (*Oneof_F_Int32)(nil), + (*Oneof_F_Int64)(nil), + (*Oneof_F_Fixed32)(nil), + (*Oneof_F_Fixed64)(nil), + (*Oneof_F_Uint32)(nil), + (*Oneof_F_Uint64)(nil), + (*Oneof_F_Float)(nil), + (*Oneof_F_Double)(nil), + (*Oneof_F_String)(nil), + (*Oneof_F_Bytes)(nil), + (*Oneof_F_Sint32)(nil), + (*Oneof_F_Sint64)(nil), + (*Oneof_F_Enum)(nil), + (*Oneof_F_Message)(nil), + (*Oneof_FGroup)(nil), + (*Oneof_F_Largest_Tag)(nil), + (*Oneof_Value)(nil), + } +} + +func _Oneof_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Oneof) + // union + switch x := m.Union.(type) { + case *Oneof_F_Bool: + t := uint64(0) + if x.F_Bool { + t = 1 + } + b.EncodeVarint(1<<3 | proto.WireVarint) + b.EncodeVarint(t) + case *Oneof_F_Int32: + b.EncodeVarint(2<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.F_Int32)) + case *Oneof_F_Int64: + b.EncodeVarint(3<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.F_Int64)) + case *Oneof_F_Fixed32: + b.EncodeVarint(4<<3 | proto.WireFixed32) + b.EncodeFixed32(uint64(x.F_Fixed32)) + case *Oneof_F_Fixed64: + b.EncodeVarint(5<<3 | proto.WireFixed64) + b.EncodeFixed64(uint64(x.F_Fixed64)) + case *Oneof_F_Uint32: + b.EncodeVarint(6<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.F_Uint32)) + case *Oneof_F_Uint64: + b.EncodeVarint(7<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.F_Uint64)) + case *Oneof_F_Float: + b.EncodeVarint(8<<3 | proto.WireFixed32) + b.EncodeFixed32(uint64(math.Float32bits(x.F_Float))) + case *Oneof_F_Double: + b.EncodeVarint(9<<3 | proto.WireFixed64) + b.EncodeFixed64(math.Float64bits(x.F_Double)) + case *Oneof_F_String: + b.EncodeVarint(10<<3 | proto.WireBytes) + b.EncodeStringBytes(x.F_String) + case *Oneof_F_Bytes: + b.EncodeVarint(11<<3 | proto.WireBytes) + b.EncodeRawBytes(x.F_Bytes) + case *Oneof_F_Sint32: + b.EncodeVarint(12<<3 | proto.WireVarint) + b.EncodeZigzag32(uint64(x.F_Sint32)) + case *Oneof_F_Sint64: + b.EncodeVarint(13<<3 | proto.WireVarint) + b.EncodeZigzag64(uint64(x.F_Sint64)) + case *Oneof_F_Enum: + b.EncodeVarint(14<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.F_Enum)) + case *Oneof_F_Message: + b.EncodeVarint(15<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.F_Message); err != nil { + return err + } + case *Oneof_FGroup: + b.EncodeVarint(16<<3 | proto.WireStartGroup) + if err := b.Marshal(x.FGroup); err != nil { + return err + } + b.EncodeVarint(16<<3 | proto.WireEndGroup) + case *Oneof_F_Largest_Tag: + b.EncodeVarint(536870911<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.F_Largest_Tag)) + case nil: + default: + return fmt.Errorf("Oneof.Union has unexpected type %T", x) + } + // tormato + switch x := m.Tormato.(type) { + case *Oneof_Value: + b.EncodeVarint(100<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Value)) + case nil: + default: + return fmt.Errorf("Oneof.Tormato has unexpected type %T", x) + } + return nil +} + +func _Oneof_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Oneof) + switch tag { + case 1: // union.F_Bool + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Bool{x != 0} + return true, err + case 2: // union.F_Int32 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Int32{int32(x)} + return true, err + case 3: // union.F_Int64 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Int64{int64(x)} + return true, err + case 4: // union.F_Fixed32 + if wire != proto.WireFixed32 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed32() + m.Union = &Oneof_F_Fixed32{uint32(x)} + return true, err + case 5: // union.F_Fixed64 + if wire != proto.WireFixed64 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed64() + m.Union = &Oneof_F_Fixed64{x} + return true, err + case 6: // union.F_Uint32 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Uint32{uint32(x)} + return true, err + case 7: // union.F_Uint64 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Uint64{x} + return true, err + case 8: // union.F_Float + if wire != proto.WireFixed32 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed32() + m.Union = &Oneof_F_Float{math.Float32frombits(uint32(x))} + return true, err + case 9: // union.F_Double + if wire != proto.WireFixed64 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed64() + m.Union = &Oneof_F_Double{math.Float64frombits(x)} + return true, err + case 10: // union.F_String + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Union = &Oneof_F_String{x} + return true, err + case 11: // union.F_Bytes + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeRawBytes(true) + m.Union = &Oneof_F_Bytes{x} + return true, err + case 12: // union.F_Sint32 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeZigzag32() + m.Union = &Oneof_F_Sint32{int32(x)} + return true, err + case 13: // union.F_Sint64 + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeZigzag64() + m.Union = &Oneof_F_Sint64{int64(x)} + return true, err + case 14: // union.F_Enum + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Enum{MyMessage_Color(x)} + return true, err + case 15: // union.F_Message + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(GoTestField) + err := b.DecodeMessage(msg) + m.Union = &Oneof_F_Message{msg} + return true, err + case 16: // union.f_group + if wire != proto.WireStartGroup { + return true, proto.ErrInternalBadWireType + } + msg := new(Oneof_F_Group) + err := b.DecodeGroup(msg) + m.Union = &Oneof_FGroup{msg} + return true, err + case 536870911: // union.F_Largest_Tag + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Oneof_F_Largest_Tag{int32(x)} + return true, err + case 100: // tormato.value + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Tormato = &Oneof_Value{int32(x)} + return true, err + default: + return false, nil + } +} + +func _Oneof_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Oneof) + // union + switch x := m.Union.(type) { + case *Oneof_F_Bool: + n += 1 // tag and wire + n += 1 + case *Oneof_F_Int32: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.F_Int32)) + case *Oneof_F_Int64: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.F_Int64)) + case *Oneof_F_Fixed32: + n += 1 // tag and wire + n += 4 + case *Oneof_F_Fixed64: + n += 1 // tag and wire + n += 8 + case *Oneof_F_Uint32: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.F_Uint32)) + case *Oneof_F_Uint64: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.F_Uint64)) + case *Oneof_F_Float: + n += 1 // tag and wire + n += 4 + case *Oneof_F_Double: + n += 1 // tag and wire + n += 8 + case *Oneof_F_String: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.F_String))) + n += len(x.F_String) + case *Oneof_F_Bytes: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.F_Bytes))) + n += len(x.F_Bytes) + case *Oneof_F_Sint32: + n += 1 // tag and wire + n += proto.SizeVarint(uint64((uint32(x.F_Sint32) << 1) ^ uint32((int32(x.F_Sint32) >> 31)))) + case *Oneof_F_Sint64: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(uint64(x.F_Sint64<<1) ^ uint64((int64(x.F_Sint64) >> 63)))) + case *Oneof_F_Enum: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.F_Enum)) + case *Oneof_F_Message: + s := proto.Size(x.F_Message) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Oneof_FGroup: + n += 2 // tag and wire + n += proto.Size(x.FGroup) + n += 2 // tag and wire + case *Oneof_F_Largest_Tag: + n += 5 // tag and wire + n += proto.SizeVarint(uint64(x.F_Largest_Tag)) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + // tormato + switch x := m.Tormato.(type) { + case *Oneof_Value: + n += 2 // tag and wire + n += proto.SizeVarint(uint64(x.Value)) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type Oneof_F_Group struct { + X *int32 `protobuf:"varint,17,opt,name=x" json:"x,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Oneof_F_Group) Reset() { *m = Oneof_F_Group{} } +func (m *Oneof_F_Group) String() string { return proto.CompactTextString(m) } +func (*Oneof_F_Group) ProtoMessage() {} +func (*Oneof_F_Group) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{29, 0} +} +func (m *Oneof_F_Group) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Oneof_F_Group.Unmarshal(m, b) +} +func (m *Oneof_F_Group) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Oneof_F_Group.Marshal(b, m, deterministic) +} +func (dst *Oneof_F_Group) XXX_Merge(src proto.Message) { + xxx_messageInfo_Oneof_F_Group.Merge(dst, src) +} +func (m *Oneof_F_Group) XXX_Size() int { + return xxx_messageInfo_Oneof_F_Group.Size(m) +} +func (m *Oneof_F_Group) XXX_DiscardUnknown() { + xxx_messageInfo_Oneof_F_Group.DiscardUnknown(m) +} + +var xxx_messageInfo_Oneof_F_Group proto.InternalMessageInfo + +func (m *Oneof_F_Group) GetX() int32 { + if m != nil && m.X != nil { + return *m.X + } + return 0 +} + +type Communique struct { + MakeMeCry *bool `protobuf:"varint,1,opt,name=make_me_cry,json=makeMeCry" json:"make_me_cry,omitempty"` + // This is a oneof, called "union". + // + // Types that are valid to be assigned to Union: + // *Communique_Number + // *Communique_Name + // *Communique_Data + // *Communique_TempC + // *Communique_Col + // *Communique_Msg + Union isCommunique_Union `protobuf_oneof:"union"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Communique) Reset() { *m = Communique{} } +func (m *Communique) String() string { return proto.CompactTextString(m) } +func (*Communique) ProtoMessage() {} +func (*Communique) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{30} +} +func (m *Communique) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Communique.Unmarshal(m, b) +} +func (m *Communique) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Communique.Marshal(b, m, deterministic) +} +func (dst *Communique) XXX_Merge(src proto.Message) { + xxx_messageInfo_Communique.Merge(dst, src) +} +func (m *Communique) XXX_Size() int { + return xxx_messageInfo_Communique.Size(m) +} +func (m *Communique) XXX_DiscardUnknown() { + xxx_messageInfo_Communique.DiscardUnknown(m) +} + +var xxx_messageInfo_Communique proto.InternalMessageInfo + +func (m *Communique) GetMakeMeCry() bool { + if m != nil && m.MakeMeCry != nil { + return *m.MakeMeCry + } + return false +} + +type isCommunique_Union interface { + isCommunique_Union() +} + +type Communique_Number struct { + Number int32 `protobuf:"varint,5,opt,name=number,oneof"` +} + +type Communique_Name struct { + Name string `protobuf:"bytes,6,opt,name=name,oneof"` +} + +type Communique_Data struct { + Data []byte `protobuf:"bytes,7,opt,name=data,oneof"` +} + +type Communique_TempC struct { + TempC float64 `protobuf:"fixed64,8,opt,name=temp_c,json=tempC,oneof"` +} + +type Communique_Col struct { + Col MyMessage_Color `protobuf:"varint,9,opt,name=col,enum=test_proto.MyMessage_Color,oneof"` +} + +type Communique_Msg struct { + Msg *Strings `protobuf:"bytes,10,opt,name=msg,oneof"` +} + +func (*Communique_Number) isCommunique_Union() {} + +func (*Communique_Name) isCommunique_Union() {} + +func (*Communique_Data) isCommunique_Union() {} + +func (*Communique_TempC) isCommunique_Union() {} + +func (*Communique_Col) isCommunique_Union() {} + +func (*Communique_Msg) isCommunique_Union() {} + +func (m *Communique) GetUnion() isCommunique_Union { + if m != nil { + return m.Union + } + return nil +} + +func (m *Communique) GetNumber() int32 { + if x, ok := m.GetUnion().(*Communique_Number); ok { + return x.Number + } + return 0 +} + +func (m *Communique) GetName() string { + if x, ok := m.GetUnion().(*Communique_Name); ok { + return x.Name + } + return "" +} + +func (m *Communique) GetData() []byte { + if x, ok := m.GetUnion().(*Communique_Data); ok { + return x.Data + } + return nil +} + +func (m *Communique) GetTempC() float64 { + if x, ok := m.GetUnion().(*Communique_TempC); ok { + return x.TempC + } + return 0 +} + +func (m *Communique) GetCol() MyMessage_Color { + if x, ok := m.GetUnion().(*Communique_Col); ok { + return x.Col + } + return MyMessage_RED +} + +func (m *Communique) GetMsg() *Strings { + if x, ok := m.GetUnion().(*Communique_Msg); ok { + return x.Msg + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Communique) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Communique_OneofMarshaler, _Communique_OneofUnmarshaler, _Communique_OneofSizer, []interface{}{ + (*Communique_Number)(nil), + (*Communique_Name)(nil), + (*Communique_Data)(nil), + (*Communique_TempC)(nil), + (*Communique_Col)(nil), + (*Communique_Msg)(nil), + } +} + +func _Communique_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Communique) + // union + switch x := m.Union.(type) { + case *Communique_Number: + b.EncodeVarint(5<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Number)) + case *Communique_Name: + b.EncodeVarint(6<<3 | proto.WireBytes) + b.EncodeStringBytes(x.Name) + case *Communique_Data: + b.EncodeVarint(7<<3 | proto.WireBytes) + b.EncodeRawBytes(x.Data) + case *Communique_TempC: + b.EncodeVarint(8<<3 | proto.WireFixed64) + b.EncodeFixed64(math.Float64bits(x.TempC)) + case *Communique_Col: + b.EncodeVarint(9<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Col)) + case *Communique_Msg: + b.EncodeVarint(10<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Msg); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Communique.Union has unexpected type %T", x) + } + return nil +} + +func _Communique_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Communique) + switch tag { + case 5: // union.number + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Communique_Number{int32(x)} + return true, err + case 6: // union.name + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Union = &Communique_Name{x} + return true, err + case 7: // union.data + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeRawBytes(true) + m.Union = &Communique_Data{x} + return true, err + case 8: // union.temp_c + if wire != proto.WireFixed64 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed64() + m.Union = &Communique_TempC{math.Float64frombits(x)} + return true, err + case 9: // union.col + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Union = &Communique_Col{MyMessage_Color(x)} + return true, err + case 10: // union.msg + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Strings) + err := b.DecodeMessage(msg) + m.Union = &Communique_Msg{msg} + return true, err + default: + return false, nil + } +} + +func _Communique_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Communique) + // union + switch x := m.Union.(type) { + case *Communique_Number: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.Number)) + case *Communique_Name: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.Name))) + n += len(x.Name) + case *Communique_Data: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.Data))) + n += len(x.Data) + case *Communique_TempC: + n += 1 // tag and wire + n += 8 + case *Communique_Col: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.Col)) + case *Communique_Msg: + s := proto.Size(x.Msg) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type TestUTF8 struct { + Scalar *string `protobuf:"bytes,1,opt,name=scalar" json:"scalar,omitempty"` + Vector []string `protobuf:"bytes,2,rep,name=vector" json:"vector,omitempty"` + // Types that are valid to be assigned to Oneof: + // *TestUTF8_Field + Oneof isTestUTF8_Oneof `protobuf_oneof:"oneof"` + MapKey map[string]int64 `protobuf:"bytes,4,rep,name=map_key,json=mapKey" json:"map_key,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + MapValue map[int64]string `protobuf:"bytes,5,rep,name=map_value,json=mapValue" json:"map_value,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TestUTF8) Reset() { *m = TestUTF8{} } +func (m *TestUTF8) String() string { return proto.CompactTextString(m) } +func (*TestUTF8) ProtoMessage() {} +func (*TestUTF8) Descriptor() ([]byte, []int) { + return fileDescriptor_test_ee9f66cbbebc227c, []int{31} +} +func (m *TestUTF8) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TestUTF8.Unmarshal(m, b) +} +func (m *TestUTF8) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TestUTF8.Marshal(b, m, deterministic) +} +func (dst *TestUTF8) XXX_Merge(src proto.Message) { + xxx_messageInfo_TestUTF8.Merge(dst, src) +} +func (m *TestUTF8) XXX_Size() int { + return xxx_messageInfo_TestUTF8.Size(m) +} +func (m *TestUTF8) XXX_DiscardUnknown() { + xxx_messageInfo_TestUTF8.DiscardUnknown(m) +} + +var xxx_messageInfo_TestUTF8 proto.InternalMessageInfo + +func (m *TestUTF8) GetScalar() string { + if m != nil && m.Scalar != nil { + return *m.Scalar + } + return "" +} + +func (m *TestUTF8) GetVector() []string { + if m != nil { + return m.Vector + } + return nil +} + +type isTestUTF8_Oneof interface { + isTestUTF8_Oneof() +} + +type TestUTF8_Field struct { + Field string `protobuf:"bytes,3,opt,name=field,oneof"` +} + +func (*TestUTF8_Field) isTestUTF8_Oneof() {} + +func (m *TestUTF8) GetOneof() isTestUTF8_Oneof { + if m != nil { + return m.Oneof + } + return nil +} + +func (m *TestUTF8) GetField() string { + if x, ok := m.GetOneof().(*TestUTF8_Field); ok { + return x.Field + } + return "" +} + +func (m *TestUTF8) GetMapKey() map[string]int64 { + if m != nil { + return m.MapKey + } + return nil +} + +func (m *TestUTF8) GetMapValue() map[int64]string { + if m != nil { + return m.MapValue + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*TestUTF8) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _TestUTF8_OneofMarshaler, _TestUTF8_OneofUnmarshaler, _TestUTF8_OneofSizer, []interface{}{ + (*TestUTF8_Field)(nil), + } +} + +func _TestUTF8_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*TestUTF8) + // oneof + switch x := m.Oneof.(type) { + case *TestUTF8_Field: + b.EncodeVarint(3<<3 | proto.WireBytes) + b.EncodeStringBytes(x.Field) + case nil: + default: + return fmt.Errorf("TestUTF8.Oneof has unexpected type %T", x) + } + return nil +} + +func _TestUTF8_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*TestUTF8) + switch tag { + case 3: // oneof.field + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Oneof = &TestUTF8_Field{x} + return true, err + default: + return false, nil + } +} + +func _TestUTF8_OneofSizer(msg proto.Message) (n int) { + m := msg.(*TestUTF8) + // oneof + switch x := m.Oneof.(type) { + case *TestUTF8_Field: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.Field))) + n += len(x.Field) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +var E_Greeting = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: ([]string)(nil), + Field: 106, + Name: "test_proto.greeting", + Tag: "bytes,106,rep,name=greeting", + Filename: "test_proto/test.proto", +} + +var E_Complex = &proto.ExtensionDesc{ + ExtendedType: (*OtherMessage)(nil), + ExtensionType: (*ComplexExtension)(nil), + Field: 200, + Name: "test_proto.complex", + Tag: "bytes,200,opt,name=complex", + Filename: "test_proto/test.proto", +} + +var E_RComplex = &proto.ExtensionDesc{ + ExtendedType: (*OtherMessage)(nil), + ExtensionType: ([]*ComplexExtension)(nil), + Field: 201, + Name: "test_proto.r_complex", + Tag: "bytes,201,rep,name=r_complex,json=rComplex", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultDouble = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*float64)(nil), + Field: 101, + Name: "test_proto.no_default_double", + Tag: "fixed64,101,opt,name=no_default_double,json=noDefaultDouble", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultFloat = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*float32)(nil), + Field: 102, + Name: "test_proto.no_default_float", + Tag: "fixed32,102,opt,name=no_default_float,json=noDefaultFloat", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultInt32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 103, + Name: "test_proto.no_default_int32", + Tag: "varint,103,opt,name=no_default_int32,json=noDefaultInt32", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultInt64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 104, + Name: "test_proto.no_default_int64", + Tag: "varint,104,opt,name=no_default_int64,json=noDefaultInt64", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultUint32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint32)(nil), + Field: 105, + Name: "test_proto.no_default_uint32", + Tag: "varint,105,opt,name=no_default_uint32,json=noDefaultUint32", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultUint64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint64)(nil), + Field: 106, + Name: "test_proto.no_default_uint64", + Tag: "varint,106,opt,name=no_default_uint64,json=noDefaultUint64", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultSint32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 107, + Name: "test_proto.no_default_sint32", + Tag: "zigzag32,107,opt,name=no_default_sint32,json=noDefaultSint32", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultSint64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 108, + Name: "test_proto.no_default_sint64", + Tag: "zigzag64,108,opt,name=no_default_sint64,json=noDefaultSint64", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultFixed32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint32)(nil), + Field: 109, + Name: "test_proto.no_default_fixed32", + Tag: "fixed32,109,opt,name=no_default_fixed32,json=noDefaultFixed32", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultFixed64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint64)(nil), + Field: 110, + Name: "test_proto.no_default_fixed64", + Tag: "fixed64,110,opt,name=no_default_fixed64,json=noDefaultFixed64", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultSfixed32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 111, + Name: "test_proto.no_default_sfixed32", + Tag: "fixed32,111,opt,name=no_default_sfixed32,json=noDefaultSfixed32", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultSfixed64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 112, + Name: "test_proto.no_default_sfixed64", + Tag: "fixed64,112,opt,name=no_default_sfixed64,json=noDefaultSfixed64", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultBool = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*bool)(nil), + Field: 113, + Name: "test_proto.no_default_bool", + Tag: "varint,113,opt,name=no_default_bool,json=noDefaultBool", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultString = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*string)(nil), + Field: 114, + Name: "test_proto.no_default_string", + Tag: "bytes,114,opt,name=no_default_string,json=noDefaultString", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultBytes = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: ([]byte)(nil), + Field: 115, + Name: "test_proto.no_default_bytes", + Tag: "bytes,115,opt,name=no_default_bytes,json=noDefaultBytes", + Filename: "test_proto/test.proto", +} + +var E_NoDefaultEnum = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*DefaultsMessage_DefaultsEnum)(nil), + Field: 116, + Name: "test_proto.no_default_enum", + Tag: "varint,116,opt,name=no_default_enum,json=noDefaultEnum,enum=test_proto.DefaultsMessage_DefaultsEnum", + Filename: "test_proto/test.proto", +} + +var E_DefaultDouble = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*float64)(nil), + Field: 201, + Name: "test_proto.default_double", + Tag: "fixed64,201,opt,name=default_double,json=defaultDouble,def=3.1415", + Filename: "test_proto/test.proto", +} + +var E_DefaultFloat = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*float32)(nil), + Field: 202, + Name: "test_proto.default_float", + Tag: "fixed32,202,opt,name=default_float,json=defaultFloat,def=3.14", + Filename: "test_proto/test.proto", +} + +var E_DefaultInt32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 203, + Name: "test_proto.default_int32", + Tag: "varint,203,opt,name=default_int32,json=defaultInt32,def=42", + Filename: "test_proto/test.proto", +} + +var E_DefaultInt64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 204, + Name: "test_proto.default_int64", + Tag: "varint,204,opt,name=default_int64,json=defaultInt64,def=43", + Filename: "test_proto/test.proto", +} + +var E_DefaultUint32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint32)(nil), + Field: 205, + Name: "test_proto.default_uint32", + Tag: "varint,205,opt,name=default_uint32,json=defaultUint32,def=44", + Filename: "test_proto/test.proto", +} + +var E_DefaultUint64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint64)(nil), + Field: 206, + Name: "test_proto.default_uint64", + Tag: "varint,206,opt,name=default_uint64,json=defaultUint64,def=45", + Filename: "test_proto/test.proto", +} + +var E_DefaultSint32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 207, + Name: "test_proto.default_sint32", + Tag: "zigzag32,207,opt,name=default_sint32,json=defaultSint32,def=46", + Filename: "test_proto/test.proto", +} + +var E_DefaultSint64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 208, + Name: "test_proto.default_sint64", + Tag: "zigzag64,208,opt,name=default_sint64,json=defaultSint64,def=47", + Filename: "test_proto/test.proto", +} + +var E_DefaultFixed32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint32)(nil), + Field: 209, + Name: "test_proto.default_fixed32", + Tag: "fixed32,209,opt,name=default_fixed32,json=defaultFixed32,def=48", + Filename: "test_proto/test.proto", +} + +var E_DefaultFixed64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*uint64)(nil), + Field: 210, + Name: "test_proto.default_fixed64", + Tag: "fixed64,210,opt,name=default_fixed64,json=defaultFixed64,def=49", + Filename: "test_proto/test.proto", +} + +var E_DefaultSfixed32 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 211, + Name: "test_proto.default_sfixed32", + Tag: "fixed32,211,opt,name=default_sfixed32,json=defaultSfixed32,def=50", + Filename: "test_proto/test.proto", +} + +var E_DefaultSfixed64 = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 212, + Name: "test_proto.default_sfixed64", + Tag: "fixed64,212,opt,name=default_sfixed64,json=defaultSfixed64,def=51", + Filename: "test_proto/test.proto", +} + +var E_DefaultBool = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*bool)(nil), + Field: 213, + Name: "test_proto.default_bool", + Tag: "varint,213,opt,name=default_bool,json=defaultBool,def=1", + Filename: "test_proto/test.proto", +} + +var E_DefaultString = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*string)(nil), + Field: 214, + Name: "test_proto.default_string", + Tag: "bytes,214,opt,name=default_string,json=defaultString,def=Hello, string,def=foo", + Filename: "test_proto/test.proto", +} + +var E_DefaultBytes = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: ([]byte)(nil), + Field: 215, + Name: "test_proto.default_bytes", + Tag: "bytes,215,opt,name=default_bytes,json=defaultBytes,def=Hello, bytes", + Filename: "test_proto/test.proto", +} + +var E_DefaultEnum = &proto.ExtensionDesc{ + ExtendedType: (*DefaultsMessage)(nil), + ExtensionType: (*DefaultsMessage_DefaultsEnum)(nil), + Field: 216, + Name: "test_proto.default_enum", + Tag: "varint,216,opt,name=default_enum,json=defaultEnum,enum=test_proto.DefaultsMessage_DefaultsEnum,def=1", + Filename: "test_proto/test.proto", +} + +var E_X201 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 201, + Name: "test_proto.x201", + Tag: "bytes,201,opt,name=x201", + Filename: "test_proto/test.proto", +} + +var E_X202 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 202, + Name: "test_proto.x202", + Tag: "bytes,202,opt,name=x202", + Filename: "test_proto/test.proto", +} + +var E_X203 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 203, + Name: "test_proto.x203", + Tag: "bytes,203,opt,name=x203", + Filename: "test_proto/test.proto", +} + +var E_X204 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 204, + Name: "test_proto.x204", + Tag: "bytes,204,opt,name=x204", + Filename: "test_proto/test.proto", +} + +var E_X205 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 205, + Name: "test_proto.x205", + Tag: "bytes,205,opt,name=x205", + Filename: "test_proto/test.proto", +} + +var E_X206 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 206, + Name: "test_proto.x206", + Tag: "bytes,206,opt,name=x206", + Filename: "test_proto/test.proto", +} + +var E_X207 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 207, + Name: "test_proto.x207", + Tag: "bytes,207,opt,name=x207", + Filename: "test_proto/test.proto", +} + +var E_X208 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 208, + Name: "test_proto.x208", + Tag: "bytes,208,opt,name=x208", + Filename: "test_proto/test.proto", +} + +var E_X209 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 209, + Name: "test_proto.x209", + Tag: "bytes,209,opt,name=x209", + Filename: "test_proto/test.proto", +} + +var E_X210 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 210, + Name: "test_proto.x210", + Tag: "bytes,210,opt,name=x210", + Filename: "test_proto/test.proto", +} + +var E_X211 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 211, + Name: "test_proto.x211", + Tag: "bytes,211,opt,name=x211", + Filename: "test_proto/test.proto", +} + +var E_X212 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 212, + Name: "test_proto.x212", + Tag: "bytes,212,opt,name=x212", + Filename: "test_proto/test.proto", +} + +var E_X213 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 213, + Name: "test_proto.x213", + Tag: "bytes,213,opt,name=x213", + Filename: "test_proto/test.proto", +} + +var E_X214 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 214, + Name: "test_proto.x214", + Tag: "bytes,214,opt,name=x214", + Filename: "test_proto/test.proto", +} + +var E_X215 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 215, + Name: "test_proto.x215", + Tag: "bytes,215,opt,name=x215", + Filename: "test_proto/test.proto", +} + +var E_X216 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 216, + Name: "test_proto.x216", + Tag: "bytes,216,opt,name=x216", + Filename: "test_proto/test.proto", +} + +var E_X217 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 217, + Name: "test_proto.x217", + Tag: "bytes,217,opt,name=x217", + Filename: "test_proto/test.proto", +} + +var E_X218 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 218, + Name: "test_proto.x218", + Tag: "bytes,218,opt,name=x218", + Filename: "test_proto/test.proto", +} + +var E_X219 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 219, + Name: "test_proto.x219", + Tag: "bytes,219,opt,name=x219", + Filename: "test_proto/test.proto", +} + +var E_X220 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 220, + Name: "test_proto.x220", + Tag: "bytes,220,opt,name=x220", + Filename: "test_proto/test.proto", +} + +var E_X221 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 221, + Name: "test_proto.x221", + Tag: "bytes,221,opt,name=x221", + Filename: "test_proto/test.proto", +} + +var E_X222 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 222, + Name: "test_proto.x222", + Tag: "bytes,222,opt,name=x222", + Filename: "test_proto/test.proto", +} + +var E_X223 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 223, + Name: "test_proto.x223", + Tag: "bytes,223,opt,name=x223", + Filename: "test_proto/test.proto", +} + +var E_X224 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 224, + Name: "test_proto.x224", + Tag: "bytes,224,opt,name=x224", + Filename: "test_proto/test.proto", +} + +var E_X225 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 225, + Name: "test_proto.x225", + Tag: "bytes,225,opt,name=x225", + Filename: "test_proto/test.proto", +} + +var E_X226 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 226, + Name: "test_proto.x226", + Tag: "bytes,226,opt,name=x226", + Filename: "test_proto/test.proto", +} + +var E_X227 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 227, + Name: "test_proto.x227", + Tag: "bytes,227,opt,name=x227", + Filename: "test_proto/test.proto", +} + +var E_X228 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 228, + Name: "test_proto.x228", + Tag: "bytes,228,opt,name=x228", + Filename: "test_proto/test.proto", +} + +var E_X229 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 229, + Name: "test_proto.x229", + Tag: "bytes,229,opt,name=x229", + Filename: "test_proto/test.proto", +} + +var E_X230 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 230, + Name: "test_proto.x230", + Tag: "bytes,230,opt,name=x230", + Filename: "test_proto/test.proto", +} + +var E_X231 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 231, + Name: "test_proto.x231", + Tag: "bytes,231,opt,name=x231", + Filename: "test_proto/test.proto", +} + +var E_X232 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 232, + Name: "test_proto.x232", + Tag: "bytes,232,opt,name=x232", + Filename: "test_proto/test.proto", +} + +var E_X233 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 233, + Name: "test_proto.x233", + Tag: "bytes,233,opt,name=x233", + Filename: "test_proto/test.proto", +} + +var E_X234 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 234, + Name: "test_proto.x234", + Tag: "bytes,234,opt,name=x234", + Filename: "test_proto/test.proto", +} + +var E_X235 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 235, + Name: "test_proto.x235", + Tag: "bytes,235,opt,name=x235", + Filename: "test_proto/test.proto", +} + +var E_X236 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 236, + Name: "test_proto.x236", + Tag: "bytes,236,opt,name=x236", + Filename: "test_proto/test.proto", +} + +var E_X237 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 237, + Name: "test_proto.x237", + Tag: "bytes,237,opt,name=x237", + Filename: "test_proto/test.proto", +} + +var E_X238 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 238, + Name: "test_proto.x238", + Tag: "bytes,238,opt,name=x238", + Filename: "test_proto/test.proto", +} + +var E_X239 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 239, + Name: "test_proto.x239", + Tag: "bytes,239,opt,name=x239", + Filename: "test_proto/test.proto", +} + +var E_X240 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 240, + Name: "test_proto.x240", + Tag: "bytes,240,opt,name=x240", + Filename: "test_proto/test.proto", +} + +var E_X241 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 241, + Name: "test_proto.x241", + Tag: "bytes,241,opt,name=x241", + Filename: "test_proto/test.proto", +} + +var E_X242 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 242, + Name: "test_proto.x242", + Tag: "bytes,242,opt,name=x242", + Filename: "test_proto/test.proto", +} + +var E_X243 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 243, + Name: "test_proto.x243", + Tag: "bytes,243,opt,name=x243", + Filename: "test_proto/test.proto", +} + +var E_X244 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 244, + Name: "test_proto.x244", + Tag: "bytes,244,opt,name=x244", + Filename: "test_proto/test.proto", +} + +var E_X245 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 245, + Name: "test_proto.x245", + Tag: "bytes,245,opt,name=x245", + Filename: "test_proto/test.proto", +} + +var E_X246 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 246, + Name: "test_proto.x246", + Tag: "bytes,246,opt,name=x246", + Filename: "test_proto/test.proto", +} + +var E_X247 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 247, + Name: "test_proto.x247", + Tag: "bytes,247,opt,name=x247", + Filename: "test_proto/test.proto", +} + +var E_X248 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 248, + Name: "test_proto.x248", + Tag: "bytes,248,opt,name=x248", + Filename: "test_proto/test.proto", +} + +var E_X249 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 249, + Name: "test_proto.x249", + Tag: "bytes,249,opt,name=x249", + Filename: "test_proto/test.proto", +} + +var E_X250 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 250, + Name: "test_proto.x250", + Tag: "bytes,250,opt,name=x250", + Filename: "test_proto/test.proto", +} + +func init() { + proto.RegisterType((*GoEnum)(nil), "test_proto.GoEnum") + proto.RegisterType((*GoTestField)(nil), "test_proto.GoTestField") + proto.RegisterType((*GoTest)(nil), "test_proto.GoTest") + proto.RegisterType((*GoTest_RequiredGroup)(nil), "test_proto.GoTest.RequiredGroup") + proto.RegisterType((*GoTest_RepeatedGroup)(nil), "test_proto.GoTest.RepeatedGroup") + proto.RegisterType((*GoTest_OptionalGroup)(nil), "test_proto.GoTest.OptionalGroup") + proto.RegisterType((*GoTestRequiredGroupField)(nil), "test_proto.GoTestRequiredGroupField") + proto.RegisterType((*GoTestRequiredGroupField_Group)(nil), "test_proto.GoTestRequiredGroupField.Group") + proto.RegisterType((*GoSkipTest)(nil), "test_proto.GoSkipTest") + proto.RegisterType((*GoSkipTest_SkipGroup)(nil), "test_proto.GoSkipTest.SkipGroup") + proto.RegisterType((*NonPackedTest)(nil), "test_proto.NonPackedTest") + proto.RegisterType((*PackedTest)(nil), "test_proto.PackedTest") + proto.RegisterType((*MaxTag)(nil), "test_proto.MaxTag") + proto.RegisterType((*OldMessage)(nil), "test_proto.OldMessage") + proto.RegisterType((*OldMessage_Nested)(nil), "test_proto.OldMessage.Nested") + proto.RegisterType((*NewMessage)(nil), "test_proto.NewMessage") + proto.RegisterType((*NewMessage_Nested)(nil), "test_proto.NewMessage.Nested") + proto.RegisterType((*InnerMessage)(nil), "test_proto.InnerMessage") + proto.RegisterType((*OtherMessage)(nil), "test_proto.OtherMessage") + proto.RegisterType((*RequiredInnerMessage)(nil), "test_proto.RequiredInnerMessage") + proto.RegisterType((*MyMessage)(nil), "test_proto.MyMessage") + proto.RegisterType((*MyMessage_SomeGroup)(nil), "test_proto.MyMessage.SomeGroup") + proto.RegisterType((*Ext)(nil), "test_proto.Ext") + proto.RegisterMapType((map[int32]int32)(nil), "test_proto.Ext.MapFieldEntry") + proto.RegisterType((*ComplexExtension)(nil), "test_proto.ComplexExtension") + proto.RegisterType((*DefaultsMessage)(nil), "test_proto.DefaultsMessage") + proto.RegisterType((*MyMessageSet)(nil), "test_proto.MyMessageSet") + proto.RegisterType((*Empty)(nil), "test_proto.Empty") + proto.RegisterType((*MessageList)(nil), "test_proto.MessageList") + proto.RegisterType((*MessageList_Message)(nil), "test_proto.MessageList.Message") + proto.RegisterType((*Strings)(nil), "test_proto.Strings") + proto.RegisterType((*Defaults)(nil), "test_proto.Defaults") + proto.RegisterType((*SubDefaults)(nil), "test_proto.SubDefaults") + proto.RegisterType((*RepeatedEnum)(nil), "test_proto.RepeatedEnum") + proto.RegisterType((*MoreRepeated)(nil), "test_proto.MoreRepeated") + proto.RegisterType((*GroupOld)(nil), "test_proto.GroupOld") + proto.RegisterType((*GroupOld_G)(nil), "test_proto.GroupOld.G") + proto.RegisterType((*GroupNew)(nil), "test_proto.GroupNew") + proto.RegisterType((*GroupNew_G)(nil), "test_proto.GroupNew.G") + proto.RegisterType((*FloatingPoint)(nil), "test_proto.FloatingPoint") + proto.RegisterType((*MessageWithMap)(nil), "test_proto.MessageWithMap") + proto.RegisterMapType((map[bool][]byte)(nil), "test_proto.MessageWithMap.ByteMappingEntry") + proto.RegisterMapType((map[int64]*FloatingPoint)(nil), "test_proto.MessageWithMap.MsgMappingEntry") + proto.RegisterMapType((map[int32]string)(nil), "test_proto.MessageWithMap.NameMappingEntry") + proto.RegisterMapType((map[string]string)(nil), "test_proto.MessageWithMap.StrToStrEntry") + proto.RegisterType((*Oneof)(nil), "test_proto.Oneof") + proto.RegisterType((*Oneof_F_Group)(nil), "test_proto.Oneof.F_Group") + proto.RegisterType((*Communique)(nil), "test_proto.Communique") + proto.RegisterType((*TestUTF8)(nil), "test_proto.TestUTF8") + proto.RegisterMapType((map[string]int64)(nil), "test_proto.TestUTF8.MapKeyEntry") + proto.RegisterMapType((map[int64]string)(nil), "test_proto.TestUTF8.MapValueEntry") + proto.RegisterEnum("test_proto.FOO", FOO_name, FOO_value) + proto.RegisterEnum("test_proto.GoTest_KIND", GoTest_KIND_name, GoTest_KIND_value) + proto.RegisterEnum("test_proto.MyMessage_Color", MyMessage_Color_name, MyMessage_Color_value) + proto.RegisterEnum("test_proto.DefaultsMessage_DefaultsEnum", DefaultsMessage_DefaultsEnum_name, DefaultsMessage_DefaultsEnum_value) + proto.RegisterEnum("test_proto.Defaults_Color", Defaults_Color_name, Defaults_Color_value) + proto.RegisterEnum("test_proto.RepeatedEnum_Color", RepeatedEnum_Color_name, RepeatedEnum_Color_value) + proto.RegisterExtension(E_Ext_More) + proto.RegisterExtension(E_Ext_Text) + proto.RegisterExtension(E_Ext_Number) + proto.RegisterExtension(E_Greeting) + proto.RegisterExtension(E_Complex) + proto.RegisterExtension(E_RComplex) + proto.RegisterExtension(E_NoDefaultDouble) + proto.RegisterExtension(E_NoDefaultFloat) + proto.RegisterExtension(E_NoDefaultInt32) + proto.RegisterExtension(E_NoDefaultInt64) + proto.RegisterExtension(E_NoDefaultUint32) + proto.RegisterExtension(E_NoDefaultUint64) + proto.RegisterExtension(E_NoDefaultSint32) + proto.RegisterExtension(E_NoDefaultSint64) + proto.RegisterExtension(E_NoDefaultFixed32) + proto.RegisterExtension(E_NoDefaultFixed64) + proto.RegisterExtension(E_NoDefaultSfixed32) + proto.RegisterExtension(E_NoDefaultSfixed64) + proto.RegisterExtension(E_NoDefaultBool) + proto.RegisterExtension(E_NoDefaultString) + proto.RegisterExtension(E_NoDefaultBytes) + proto.RegisterExtension(E_NoDefaultEnum) + proto.RegisterExtension(E_DefaultDouble) + proto.RegisterExtension(E_DefaultFloat) + proto.RegisterExtension(E_DefaultInt32) + proto.RegisterExtension(E_DefaultInt64) + proto.RegisterExtension(E_DefaultUint32) + proto.RegisterExtension(E_DefaultUint64) + proto.RegisterExtension(E_DefaultSint32) + proto.RegisterExtension(E_DefaultSint64) + proto.RegisterExtension(E_DefaultFixed32) + proto.RegisterExtension(E_DefaultFixed64) + proto.RegisterExtension(E_DefaultSfixed32) + proto.RegisterExtension(E_DefaultSfixed64) + proto.RegisterExtension(E_DefaultBool) + proto.RegisterExtension(E_DefaultString) + proto.RegisterExtension(E_DefaultBytes) + proto.RegisterExtension(E_DefaultEnum) + proto.RegisterExtension(E_X201) + proto.RegisterExtension(E_X202) + proto.RegisterExtension(E_X203) + proto.RegisterExtension(E_X204) + proto.RegisterExtension(E_X205) + proto.RegisterExtension(E_X206) + proto.RegisterExtension(E_X207) + proto.RegisterExtension(E_X208) + proto.RegisterExtension(E_X209) + proto.RegisterExtension(E_X210) + proto.RegisterExtension(E_X211) + proto.RegisterExtension(E_X212) + proto.RegisterExtension(E_X213) + proto.RegisterExtension(E_X214) + proto.RegisterExtension(E_X215) + proto.RegisterExtension(E_X216) + proto.RegisterExtension(E_X217) + proto.RegisterExtension(E_X218) + proto.RegisterExtension(E_X219) + proto.RegisterExtension(E_X220) + proto.RegisterExtension(E_X221) + proto.RegisterExtension(E_X222) + proto.RegisterExtension(E_X223) + proto.RegisterExtension(E_X224) + proto.RegisterExtension(E_X225) + proto.RegisterExtension(E_X226) + proto.RegisterExtension(E_X227) + proto.RegisterExtension(E_X228) + proto.RegisterExtension(E_X229) + proto.RegisterExtension(E_X230) + proto.RegisterExtension(E_X231) + proto.RegisterExtension(E_X232) + proto.RegisterExtension(E_X233) + proto.RegisterExtension(E_X234) + proto.RegisterExtension(E_X235) + proto.RegisterExtension(E_X236) + proto.RegisterExtension(E_X237) + proto.RegisterExtension(E_X238) + proto.RegisterExtension(E_X239) + proto.RegisterExtension(E_X240) + proto.RegisterExtension(E_X241) + proto.RegisterExtension(E_X242) + proto.RegisterExtension(E_X243) + proto.RegisterExtension(E_X244) + proto.RegisterExtension(E_X245) + proto.RegisterExtension(E_X246) + proto.RegisterExtension(E_X247) + proto.RegisterExtension(E_X248) + proto.RegisterExtension(E_X249) + proto.RegisterExtension(E_X250) +} + +func init() { proto.RegisterFile("test_proto/test.proto", fileDescriptor_test_ee9f66cbbebc227c) } + +var fileDescriptor_test_ee9f66cbbebc227c = []byte{ + // 4795 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x5b, 0xd9, 0x73, 0x1b, 0x47, + 0x7a, 0xd7, 0x0c, 0xee, 0x0f, 0x20, 0x31, 0x6c, 0xc9, 0x12, 0x44, 0x59, 0xd2, 0x08, 0x6b, 0xaf, + 0x61, 0xc9, 0xa2, 0x48, 0x60, 0x08, 0x49, 0x70, 0xec, 0x58, 0x07, 0x41, 0xb3, 0x24, 0x12, 0xf2, + 0x90, 0xb6, 0xb3, 0xca, 0x03, 0x0a, 0x24, 0x06, 0x20, 0x56, 0xc0, 0x0c, 0x0c, 0x0c, 0x56, 0x64, + 0x52, 0xa9, 0xf2, 0x63, 0xaa, 0xf2, 0x94, 0x4d, 0x52, 0x95, 0xf7, 0xbc, 0xe4, 0x25, 0xd7, 0x43, + 0xf2, 0x37, 0xc4, 0xd7, 0x7a, 0x77, 0xbd, 0x57, 0x92, 0x4d, 0x36, 0xf7, 0x9d, 0xcd, 0xbd, 0x47, + 0x5e, 0x9c, 0xea, 0xaf, 0x7b, 0x66, 0x7a, 0x06, 0x50, 0x93, 0x7c, 0xe2, 0x74, 0xf7, 0xef, 0xfb, + 0xf5, 0xf5, 0x9b, 0xef, 0xfb, 0xba, 0x31, 0x84, 0xe7, 0x5c, 0x6b, 0xec, 0x36, 0x87, 0x23, 0xc7, + 0x75, 0x6e, 0xd0, 0xc7, 0x25, 0x7c, 0x24, 0x10, 0x54, 0x17, 0xaf, 0x41, 0x72, 0xdd, 0x59, 0xb3, + 0x27, 0x03, 0x72, 0x05, 0x62, 0x1d, 0xc7, 0x29, 0x28, 0xba, 0x5a, 0x9a, 0x2f, 0xe7, 0x97, 0x02, + 0xcc, 0x52, 0xbd, 0xd1, 0x30, 0x69, 0x5b, 0xf1, 0x26, 0x64, 0xd7, 0x9d, 0x1d, 0x6b, 0xec, 0xd6, + 0x7b, 0x56, 0xbf, 0x4d, 0xce, 0x40, 0xe2, 0x61, 0x6b, 0xd7, 0xea, 0xa3, 0x4d, 0xc6, 0x64, 0x05, + 0x42, 0x20, 0xbe, 0x73, 0x38, 0xb4, 0x0a, 0x2a, 0x56, 0xe2, 0x73, 0xf1, 0x0f, 0x8b, 0xb4, 0x1b, + 0x6a, 0x49, 0xae, 0x41, 0xfc, 0x41, 0xcf, 0x6e, 0xf3, 0x7e, 0xce, 0x89, 0xfd, 0x30, 0xc4, 0xd2, + 0x83, 0x8d, 0xad, 0xfb, 0x26, 0x82, 0x68, 0x0f, 0x3b, 0xad, 0xdd, 0x3e, 0x25, 0x53, 0x68, 0x0f, + 0x58, 0xa0, 0xb5, 0x8f, 0x5a, 0xa3, 0xd6, 0xa0, 0x10, 0xd3, 0x95, 0x52, 0xc2, 0x64, 0x05, 0xf2, + 0x1a, 0xcc, 0x99, 0xd6, 0x7b, 0x93, 0xde, 0xc8, 0x6a, 0xe3, 0xf0, 0x0a, 0x71, 0x5d, 0x2d, 0x65, + 0x67, 0xf5, 0x80, 0xcd, 0x66, 0x18, 0xcd, 0xcc, 0x87, 0x56, 0xcb, 0xf5, 0xcc, 0x13, 0x7a, 0xec, + 0x08, 0x73, 0x01, 0x4d, 0xcd, 0x1b, 0x43, 0xb7, 0xe7, 0xd8, 0xad, 0x3e, 0x33, 0x4f, 0xea, 0x8a, + 0xd4, 0x3c, 0x84, 0x26, 0x5f, 0x84, 0x7c, 0xbd, 0x79, 0xd7, 0x71, 0xfa, 0xcd, 0x11, 0x1f, 0x55, + 0x01, 0x74, 0xb5, 0x94, 0x36, 0xe7, 0xea, 0xb4, 0xd6, 0x1b, 0x2a, 0x29, 0x81, 0x56, 0x6f, 0x6e, + 0xd8, 0x6e, 0xa5, 0x1c, 0x00, 0xb3, 0xba, 0x5a, 0x4a, 0x98, 0xf3, 0x75, 0xac, 0x9e, 0x42, 0x56, + 0x8d, 0x00, 0x99, 0xd3, 0xd5, 0x52, 0x8c, 0x21, 0xab, 0x86, 0x8f, 0x7c, 0x05, 0x48, 0xbd, 0x59, + 0xef, 0x1d, 0x58, 0x6d, 0x91, 0x75, 0x4e, 0x57, 0x4b, 0x29, 0x53, 0xab, 0xf3, 0x86, 0x19, 0x68, + 0x91, 0x79, 0x5e, 0x57, 0x4b, 0x49, 0x0f, 0x2d, 0x70, 0x5f, 0x85, 0x85, 0x7a, 0xf3, 0xed, 0x5e, + 0x78, 0xc0, 0x79, 0x5d, 0x2d, 0xcd, 0x99, 0xf9, 0x3a, 0xab, 0x9f, 0xc6, 0x8a, 0xc4, 0x9a, 0xae, + 0x96, 0xe2, 0x1c, 0x2b, 0xf0, 0xe2, 0xec, 0xea, 0x7d, 0xa7, 0xe5, 0x06, 0xd0, 0x05, 0x5d, 0x2d, + 0xa9, 0xe6, 0x7c, 0x1d, 0xab, 0xc3, 0xac, 0xf7, 0x9d, 0xc9, 0x6e, 0xdf, 0x0a, 0xa0, 0x44, 0x57, + 0x4b, 0x8a, 0x99, 0xaf, 0xb3, 0xfa, 0x30, 0x76, 0xdb, 0x1d, 0xf5, 0xec, 0x6e, 0x80, 0x3d, 0x8d, + 0x3a, 0xce, 0xd7, 0x59, 0x7d, 0x78, 0x04, 0x77, 0x0f, 0x5d, 0x6b, 0x1c, 0x40, 0x2d, 0x5d, 0x2d, + 0xe5, 0xcc, 0xf9, 0x3a, 0x56, 0x47, 0x58, 0x23, 0x6b, 0xd0, 0xd1, 0xd5, 0xd2, 0x02, 0x65, 0x9d, + 0xb1, 0x06, 0xdb, 0x91, 0x35, 0xe8, 0xea, 0x6a, 0x89, 0x70, 0xac, 0xb0, 0x06, 0x4b, 0x70, 0xba, + 0xde, 0xdc, 0xee, 0x44, 0x37, 0x6e, 0x5f, 0x57, 0x4b, 0x79, 0x73, 0xa1, 0xee, 0xb5, 0xcc, 0xc2, + 0x8b, 0xec, 0x3d, 0x5d, 0x2d, 0x69, 0x3e, 0x5e, 0xe0, 0x17, 0x35, 0xc9, 0xa4, 0x5e, 0x38, 0xa3, + 0xc7, 0x04, 0x4d, 0xb2, 0xca, 0xb0, 0x26, 0x39, 0xf0, 0x39, 0x3d, 0x26, 0x6a, 0x32, 0x82, 0xc4, + 0xee, 0x39, 0xf2, 0xac, 0x1e, 0x13, 0x35, 0xc9, 0x91, 0x11, 0x4d, 0x72, 0xec, 0x39, 0x3d, 0x16, + 0xd6, 0xe4, 0x14, 0x5a, 0x64, 0x2e, 0xe8, 0xb1, 0xb0, 0x26, 0x39, 0x3a, 0xac, 0x49, 0x0e, 0x3e, + 0xaf, 0xc7, 0x42, 0x9a, 0x8c, 0x62, 0x45, 0xe2, 0x45, 0x3d, 0x16, 0xd2, 0xa4, 0x38, 0x3b, 0x4f, + 0x93, 0x1c, 0x7a, 0x41, 0x8f, 0x89, 0x9a, 0x14, 0x59, 0x7d, 0x4d, 0x72, 0xe8, 0xf3, 0x7a, 0x2c, + 0xa4, 0x49, 0x11, 0xeb, 0x6b, 0x92, 0x63, 0x2f, 0xea, 0xb1, 0x90, 0x26, 0x39, 0xf6, 0x65, 0x51, + 0x93, 0x1c, 0xfa, 0x81, 0xa2, 0xc7, 0x44, 0x51, 0x72, 0xe8, 0xb5, 0x90, 0x28, 0x39, 0xf6, 0x43, + 0x8a, 0x15, 0x55, 0x19, 0x05, 0x8b, 0xab, 0xf0, 0x11, 0x05, 0x8b, 0xb2, 0xe4, 0xe0, 0x1b, 0x11, + 0x59, 0x72, 0xf8, 0xc7, 0x14, 0x1e, 0xd6, 0xe5, 0xb4, 0x81, 0xc8, 0xff, 0x09, 0x35, 0x08, 0x0b, + 0x93, 0x1b, 0x04, 0xc2, 0x74, 0xb8, 0x13, 0x2d, 0x5c, 0xd2, 0x15, 0x5f, 0x98, 0x9e, 0x67, 0x15, + 0x85, 0xe9, 0x03, 0x2f, 0x63, 0xc8, 0xe0, 0xc2, 0x9c, 0x42, 0x56, 0x8d, 0x00, 0xa9, 0xeb, 0x4a, + 0x20, 0x4c, 0x1f, 0x19, 0x12, 0xa6, 0x8f, 0xbd, 0xa2, 0x2b, 0xa2, 0x30, 0x67, 0xa0, 0x45, 0xe6, + 0xa2, 0xae, 0x88, 0xc2, 0xf4, 0xd1, 0xa2, 0x30, 0x7d, 0xf0, 0x17, 0x74, 0x45, 0x10, 0xe6, 0x34, + 0x56, 0x24, 0x7e, 0x41, 0x57, 0x04, 0x61, 0x86, 0x67, 0xc7, 0x84, 0xe9, 0x43, 0x5f, 0xd4, 0x95, + 0x40, 0x98, 0x61, 0x56, 0x2e, 0x4c, 0x1f, 0xfa, 0x45, 0x5d, 0x11, 0x84, 0x19, 0xc6, 0x72, 0x61, + 0xfa, 0xd8, 0x97, 0x30, 0x4e, 0x7b, 0xc2, 0xf4, 0xb1, 0x82, 0x30, 0x7d, 0xe8, 0xef, 0xd0, 0x98, + 0xee, 0x0b, 0xd3, 0x87, 0x8a, 0xc2, 0xf4, 0xb1, 0xbf, 0x4b, 0xb1, 0x81, 0x30, 0xa7, 0xc1, 0xe2, + 0x2a, 0xfc, 0x1e, 0x05, 0x07, 0xc2, 0xf4, 0xc1, 0x61, 0x61, 0xfa, 0xf0, 0xdf, 0xa7, 0x70, 0x51, + 0x98, 0xb3, 0x0c, 0x44, 0xfe, 0x3f, 0xa0, 0x06, 0xa2, 0x30, 0x7d, 0x83, 0x25, 0x9c, 0x26, 0x15, + 0x66, 0xdb, 0xea, 0xb4, 0x26, 0x7d, 0x2a, 0xe3, 0x12, 0x55, 0x66, 0x2d, 0xee, 0x8e, 0x26, 0x16, + 0x9d, 0xab, 0xe3, 0xf4, 0xef, 0x7b, 0x6d, 0x64, 0x89, 0x0e, 0x9f, 0x09, 0x34, 0x30, 0x78, 0x99, + 0x2a, 0xb4, 0xa6, 0x56, 0xca, 0x66, 0x9e, 0xa9, 0x74, 0x1a, 0x5f, 0x35, 0x04, 0xfc, 0x55, 0xaa, + 0xd3, 0x9a, 0x5a, 0x35, 0x18, 0xbe, 0x6a, 0x04, 0xf8, 0x0a, 0x9d, 0x80, 0x27, 0xd6, 0xc0, 0xe2, + 0x1a, 0x55, 0x6b, 0x2d, 0x56, 0x29, 0x2f, 0x9b, 0x0b, 0x9e, 0x64, 0x67, 0x19, 0x85, 0xba, 0x79, + 0x85, 0x8a, 0xb6, 0x16, 0xab, 0x1a, 0xbe, 0x91, 0xd8, 0x53, 0x99, 0x0a, 0x9d, 0x4b, 0x37, 0xb0, + 0xb9, 0x4e, 0xb5, 0x5b, 0x8b, 0x57, 0xca, 0xcb, 0xcb, 0xa6, 0xc6, 0x15, 0x3c, 0xc3, 0x26, 0xd4, + 0xcf, 0x12, 0xd5, 0x70, 0x2d, 0x5e, 0x35, 0x7c, 0x9b, 0x70, 0x3f, 0x0b, 0x9e, 0x94, 0x03, 0x93, + 0x1b, 0x54, 0xcb, 0xb5, 0x64, 0x65, 0xc5, 0x58, 0x59, 0xbd, 0x6d, 0xe6, 0x99, 0xa6, 0x03, 0x1b, + 0x83, 0xf6, 0xc3, 0x45, 0x1d, 0x18, 0x2d, 0x53, 0x55, 0xd7, 0x92, 0xe5, 0x9b, 0x2b, 0xb7, 0xca, + 0xb7, 0x4c, 0x8d, 0xab, 0x3b, 0xb0, 0x7a, 0x9d, 0x5a, 0x71, 0x79, 0x07, 0x56, 0x2b, 0x54, 0xdf, + 0x35, 0x6d, 0xdf, 0xea, 0xf7, 0x9d, 0x57, 0xf4, 0xe2, 0x53, 0x67, 0xd4, 0x6f, 0x5f, 0x29, 0x82, + 0xa9, 0x71, 0xc5, 0x8b, 0xbd, 0x2e, 0x78, 0x92, 0x0f, 0xcc, 0x7f, 0x95, 0x66, 0xac, 0xb9, 0x5a, + 0xea, 0x6e, 0xaf, 0x6b, 0x3b, 0x63, 0xcb, 0xcc, 0x33, 0xf1, 0x47, 0xd6, 0x64, 0x3b, 0xba, 0x8e, + 0x5f, 0xa5, 0x66, 0x0b, 0xb5, 0xd8, 0xf5, 0x4a, 0x99, 0xf6, 0x34, 0x6b, 0x1d, 0xb7, 0xa3, 0xeb, + 0xf8, 0x6b, 0xd4, 0x86, 0xd4, 0x62, 0xd7, 0xab, 0x06, 0xb7, 0x11, 0xd7, 0xb1, 0x0a, 0x67, 0x84, + 0x77, 0x21, 0xb0, 0xfa, 0x75, 0x6a, 0x95, 0x67, 0x3d, 0x11, 0xff, 0x8d, 0x98, 0x69, 0x17, 0xea, + 0xed, 0x37, 0xa8, 0x9d, 0xc6, 0x7a, 0x23, 0xfe, 0x8b, 0x11, 0xd8, 0xdd, 0x84, 0xb3, 0x91, 0x5c, + 0xa2, 0x39, 0x6c, 0xed, 0x3d, 0xb1, 0xda, 0x85, 0x32, 0x4d, 0x29, 0xee, 0xaa, 0x9a, 0x62, 0x9e, + 0x0e, 0xa5, 0x15, 0x8f, 0xb0, 0x99, 0xdc, 0x86, 0x73, 0xd1, 0xe4, 0xc2, 0xb3, 0xac, 0xd0, 0x1c, + 0x03, 0x2d, 0xcf, 0x84, 0xf3, 0x8c, 0x88, 0xa9, 0x10, 0x54, 0x3c, 0x53, 0x83, 0x26, 0x1d, 0x81, + 0x69, 0x10, 0x5b, 0xb8, 0xe9, 0x6b, 0x70, 0x7e, 0x3a, 0xfd, 0xf0, 0x8c, 0x57, 0x69, 0x16, 0x82, + 0xc6, 0x67, 0xa3, 0x99, 0xc8, 0x94, 0xf9, 0x8c, 0xbe, 0xab, 0x34, 0x2d, 0x11, 0xcd, 0xa7, 0x7a, + 0x7f, 0x15, 0x0a, 0x53, 0x09, 0x8a, 0x67, 0x7d, 0x93, 0xe6, 0x29, 0x68, 0xfd, 0x5c, 0x24, 0x57, + 0x89, 0x1a, 0xcf, 0xe8, 0xfa, 0x16, 0x4d, 0x5c, 0x04, 0xe3, 0xa9, 0x9e, 0x71, 0xc9, 0xc2, 0x29, + 0x8c, 0x67, 0x7b, 0x9b, 0x66, 0x32, 0x7c, 0xc9, 0x42, 0xd9, 0x8c, 0xd8, 0x6f, 0x24, 0xa7, 0xf1, + 0x6c, 0x6b, 0x34, 0xb5, 0xe1, 0xfd, 0x86, 0xd3, 0x1b, 0x6e, 0xfc, 0x33, 0xd4, 0x78, 0x7b, 0xf6, + 0x8c, 0x7f, 0x14, 0xa3, 0x49, 0x09, 0xb7, 0xde, 0x9e, 0x35, 0x65, 0xdf, 0x7a, 0xc6, 0x94, 0x7f, + 0x4c, 0xad, 0x89, 0x60, 0x3d, 0x35, 0xe7, 0x37, 0x60, 0x71, 0x46, 0xbe, 0xe2, 0xd9, 0xff, 0x84, + 0xda, 0xe7, 0xd1, 0xfe, 0xdc, 0x54, 0xea, 0x32, 0xcd, 0x30, 0x63, 0x04, 0x3f, 0xa5, 0x0c, 0x5a, + 0x88, 0x61, 0x6a, 0x0c, 0x75, 0x98, 0xf3, 0xf2, 0xf1, 0xee, 0xc8, 0x99, 0x0c, 0x0b, 0x75, 0x5d, + 0x2d, 0x41, 0x59, 0x9f, 0x71, 0x3a, 0xf6, 0xd2, 0xf3, 0x75, 0x8a, 0x33, 0xc3, 0x66, 0x8c, 0x87, + 0x31, 0x33, 0x9e, 0x47, 0x7a, 0xec, 0x99, 0x3c, 0x0c, 0xe7, 0xf3, 0x08, 0x66, 0x94, 0xc7, 0x0b, + 0x77, 0x8c, 0xe7, 0xb1, 0xae, 0x3c, 0x83, 0xc7, 0x0b, 0x7e, 0x9c, 0x27, 0x64, 0xb6, 0xb8, 0x1a, + 0x9c, 0xc9, 0xb1, 0x9d, 0xbc, 0x10, 0x3d, 0xa4, 0xaf, 0xe3, 0xe9, 0x2a, 0x5c, 0xc9, 0xcc, 0x84, + 0xe1, 0x4d, 0x9b, 0xbd, 0xf5, 0x0c, 0xb3, 0xd0, 0x68, 0xa6, 0xcd, 0x7e, 0x7e, 0x86, 0x59, 0xf1, + 0x37, 0x15, 0x88, 0x3f, 0xd8, 0xd8, 0xba, 0x4f, 0xd2, 0x10, 0x7f, 0xa7, 0xb1, 0x71, 0x5f, 0x3b, + 0x45, 0x9f, 0xee, 0x36, 0x1a, 0x0f, 0x35, 0x85, 0x64, 0x20, 0x71, 0xf7, 0x4b, 0x3b, 0x6b, 0xdb, + 0x9a, 0x4a, 0xf2, 0x90, 0xad, 0x6f, 0x6c, 0xad, 0xaf, 0x99, 0x8f, 0xcc, 0x8d, 0xad, 0x1d, 0x2d, + 0x46, 0xdb, 0xea, 0x0f, 0x1b, 0x77, 0x76, 0xb4, 0x38, 0x49, 0x41, 0x8c, 0xd6, 0x25, 0x08, 0x40, + 0x72, 0x7b, 0xc7, 0xdc, 0xd8, 0x5a, 0xd7, 0x92, 0x94, 0x65, 0x67, 0x63, 0x73, 0x4d, 0x4b, 0x51, + 0xe4, 0xce, 0xdb, 0x8f, 0x1e, 0xae, 0x69, 0x69, 0xfa, 0x78, 0xc7, 0x34, 0xef, 0x7c, 0x49, 0xcb, + 0x50, 0xa3, 0xcd, 0x3b, 0x8f, 0x34, 0xc0, 0xe6, 0x3b, 0x77, 0x1f, 0xae, 0x69, 0x59, 0x92, 0x83, + 0x74, 0xfd, 0xed, 0xad, 0x7b, 0x3b, 0x1b, 0x8d, 0x2d, 0x2d, 0x57, 0xfc, 0x45, 0x28, 0xb0, 0x65, + 0x0e, 0xad, 0x22, 0xbb, 0x32, 0x78, 0x03, 0x12, 0x6c, 0x6f, 0x14, 0xd4, 0xca, 0xd5, 0xe9, 0xbd, + 0x99, 0x36, 0x5a, 0x62, 0xbb, 0xc4, 0x0c, 0x17, 0x2f, 0x42, 0x82, 0xad, 0xd3, 0x19, 0x48, 0xb0, + 0xf5, 0x51, 0xf1, 0x2a, 0x81, 0x15, 0x8a, 0xbf, 0xa5, 0x02, 0xac, 0x3b, 0xdb, 0x4f, 0x7a, 0x43, + 0xbc, 0xb8, 0xb9, 0x08, 0x30, 0x7e, 0xd2, 0x1b, 0x36, 0xf1, 0x0d, 0xe4, 0x97, 0x0e, 0x19, 0x5a, + 0x83, 0xbe, 0x97, 0x5c, 0x81, 0x1c, 0x36, 0xf3, 0x57, 0x04, 0xef, 0x1a, 0x52, 0x66, 0x96, 0xd6, + 0x71, 0x27, 0x19, 0x86, 0x54, 0x0d, 0xbc, 0x62, 0x48, 0x0a, 0x90, 0xaa, 0x41, 0x2e, 0x03, 0x16, + 0x9b, 0x63, 0x8c, 0xa6, 0x78, 0xad, 0x90, 0x31, 0xb1, 0x5f, 0x16, 0x5f, 0xc9, 0xeb, 0x80, 0x7d, + 0xb2, 0x99, 0xe7, 0x67, 0xbd, 0x25, 0xde, 0x80, 0x97, 0xe8, 0x03, 0x9b, 0x6f, 0x60, 0xb2, 0xd8, + 0x80, 0x8c, 0x5f, 0x4f, 0x7b, 0xc3, 0x5a, 0x3e, 0x27, 0x0d, 0xe7, 0x04, 0x58, 0xe5, 0x4f, 0x8a, + 0x01, 0xf8, 0x78, 0x16, 0x70, 0x3c, 0xcc, 0x88, 0x0d, 0xa8, 0x78, 0x11, 0xe6, 0xb6, 0x1c, 0x9b, + 0xbd, 0xc7, 0xb8, 0x4e, 0x39, 0x50, 0x5a, 0x05, 0x05, 0xcf, 0xbf, 0x4a, 0xab, 0x78, 0x09, 0x40, + 0x68, 0xd3, 0x40, 0xd9, 0x65, 0x6d, 0xe8, 0x0f, 0x94, 0xdd, 0xe2, 0x35, 0x48, 0x6e, 0xb6, 0x0e, + 0x76, 0x5a, 0x5d, 0x72, 0x05, 0xa0, 0xdf, 0x1a, 0xbb, 0xcd, 0x0e, 0xee, 0xc4, 0xe7, 0x9f, 0x7f, + 0xfe, 0xb9, 0x82, 0xc9, 0x74, 0x86, 0xd6, 0xb2, 0x1d, 0x19, 0x03, 0x34, 0xfa, 0xed, 0x4d, 0x6b, + 0x3c, 0x6e, 0x75, 0x2d, 0xb2, 0x0a, 0x49, 0xdb, 0x1a, 0xd3, 0xe8, 0xab, 0xe0, 0x5d, 0xd3, 0x45, + 0x71, 0x1d, 0x02, 0xdc, 0xd2, 0x16, 0x82, 0x4c, 0x0e, 0x26, 0x1a, 0xc4, 0xec, 0xc9, 0x00, 0x6f, + 0xd4, 0x12, 0x26, 0x7d, 0x5c, 0x7c, 0x1e, 0x92, 0x0c, 0x43, 0x08, 0xc4, 0xed, 0xd6, 0xc0, 0x2a, + 0xb0, 0x9e, 0xf1, 0xb9, 0xf8, 0x55, 0x05, 0x60, 0xcb, 0x7a, 0x7a, 0xac, 0x5e, 0x03, 0x9c, 0xa4, + 0xd7, 0x18, 0xeb, 0xf5, 0x55, 0x59, 0xaf, 0x54, 0x6d, 0x1d, 0xc7, 0x69, 0x37, 0xd9, 0x46, 0xb3, + 0xeb, 0xbf, 0x0c, 0xad, 0xc1, 0x9d, 0x2b, 0x3e, 0x86, 0xdc, 0x86, 0x6d, 0x5b, 0x23, 0x6f, 0x54, + 0x04, 0xe2, 0xfb, 0xce, 0xd8, 0xe5, 0x37, 0x91, 0xf8, 0x4c, 0x0a, 0x10, 0x1f, 0x3a, 0x23, 0x97, + 0xcd, 0xb4, 0x16, 0x37, 0x96, 0x97, 0x97, 0x4d, 0xac, 0x21, 0xcf, 0x43, 0x66, 0xcf, 0xb1, 0x6d, + 0x6b, 0x8f, 0x4e, 0x23, 0x86, 0x47, 0xc7, 0xa0, 0xa2, 0xf8, 0xcb, 0x0a, 0xe4, 0x1a, 0xee, 0x7e, + 0x40, 0xae, 0x41, 0xec, 0x89, 0x75, 0x88, 0xc3, 0x8b, 0x99, 0xf4, 0x91, 0xbe, 0x30, 0x5f, 0x69, + 0xf5, 0x27, 0xec, 0x5e, 0x32, 0x67, 0xb2, 0x02, 0x39, 0x0b, 0xc9, 0xa7, 0x56, 0xaf, 0xbb, 0xef, + 0x22, 0xa7, 0x6a, 0xf2, 0x12, 0x59, 0x82, 0x44, 0x8f, 0x0e, 0xb6, 0x10, 0xc7, 0x15, 0x2b, 0x88, + 0x2b, 0x26, 0xce, 0xc2, 0x64, 0xb0, 0xab, 0xe9, 0x74, 0x5b, 0x7b, 0xff, 0xfd, 0xf7, 0xdf, 0x57, + 0x8b, 0xfb, 0x70, 0xc6, 0x7b, 0x89, 0x43, 0xd3, 0x7d, 0x04, 0x85, 0xbe, 0xe5, 0x34, 0x3b, 0x3d, + 0xbb, 0xd5, 0xef, 0x1f, 0x36, 0x9f, 0x3a, 0x76, 0xb3, 0x65, 0x37, 0x9d, 0xf1, 0x5e, 0x6b, 0x84, + 0x4b, 0x20, 0xeb, 0xe4, 0x4c, 0xdf, 0x72, 0xea, 0xcc, 0xf0, 0x5d, 0xc7, 0xbe, 0x63, 0x37, 0xa8, + 0x55, 0xf1, 0xb3, 0x38, 0x64, 0x36, 0x0f, 0x3d, 0xfe, 0x33, 0x90, 0xd8, 0x73, 0x26, 0x36, 0x5b, + 0xcf, 0x84, 0xc9, 0x0a, 0xfe, 0x3e, 0xa9, 0xc2, 0x3e, 0x9d, 0x81, 0xc4, 0x7b, 0x13, 0xc7, 0xb5, + 0x70, 0xca, 0x19, 0x93, 0x15, 0xe8, 0x8a, 0x0d, 0x2d, 0xb7, 0x10, 0xc7, 0x6b, 0x0a, 0xfa, 0x18, + 0xac, 0x41, 0xe2, 0x58, 0x6b, 0x40, 0x96, 0x21, 0xe9, 0xd0, 0x3d, 0x18, 0x17, 0x92, 0x78, 0x0f, + 0x1b, 0x32, 0x10, 0x77, 0xc7, 0xe4, 0x38, 0xf2, 0x00, 0x16, 0x9e, 0x5a, 0xcd, 0xc1, 0x64, 0xec, + 0x36, 0xbb, 0x4e, 0xb3, 0x6d, 0x59, 0x43, 0x6b, 0x54, 0x98, 0xc3, 0xde, 0x42, 0x1e, 0x62, 0xd6, + 0x82, 0x9a, 0xf3, 0x4f, 0xad, 0xcd, 0xc9, 0xd8, 0x5d, 0x77, 0xee, 0xa3, 0x1d, 0x59, 0x85, 0xcc, + 0xc8, 0xa2, 0x7e, 0x81, 0x0e, 0x39, 0x37, 0x3d, 0x82, 0x90, 0x71, 0x7a, 0x64, 0x0d, 0xb1, 0x82, + 0xdc, 0x84, 0xf4, 0x6e, 0xef, 0x89, 0x35, 0xde, 0xb7, 0xda, 0x85, 0x94, 0xae, 0x94, 0xe6, 0xcb, + 0x17, 0x44, 0x2b, 0x7f, 0x81, 0x97, 0xee, 0x39, 0x7d, 0x67, 0x64, 0xfa, 0x60, 0xf2, 0x1a, 0x64, + 0xc6, 0xce, 0xc0, 0x62, 0x6a, 0x4f, 0x63, 0xb0, 0xbd, 0x3c, 0xdb, 0x72, 0xdb, 0x19, 0x58, 0x9e, + 0x57, 0xf3, 0x2c, 0xc8, 0x05, 0x36, 0xdc, 0x5d, 0x7a, 0x98, 0x28, 0x00, 0x5e, 0xf8, 0xd0, 0x41, + 0xe1, 0xe1, 0x82, 0x2c, 0xd2, 0x41, 0x75, 0x3b, 0x34, 0x67, 0x2b, 0x64, 0xf1, 0x2c, 0xef, 0x97, + 0x17, 0x5f, 0x81, 0x8c, 0x4f, 0x18, 0xb8, 0x43, 0xe6, 0x82, 0x32, 0xe8, 0x21, 0x98, 0x3b, 0x64, + 0xfe, 0xe7, 0x45, 0x48, 0xe0, 0xc0, 0x69, 0xe4, 0x32, 0xd7, 0x68, 0xa0, 0xcc, 0x40, 0x62, 0xdd, + 0x5c, 0x5b, 0xdb, 0xd2, 0x14, 0x8c, 0x99, 0x0f, 0xdf, 0x5e, 0xd3, 0x54, 0x41, 0xbf, 0xbf, 0xad, + 0x42, 0x6c, 0xed, 0x00, 0x95, 0xd3, 0x6e, 0xb9, 0x2d, 0xef, 0x0d, 0xa7, 0xcf, 0xa4, 0x06, 0x99, + 0x41, 0xcb, 0xeb, 0x4b, 0xc5, 0x25, 0x0e, 0xf9, 0x92, 0xb5, 0x03, 0x77, 0x69, 0xb3, 0xc5, 0x7a, + 0x5e, 0xb3, 0xdd, 0xd1, 0xa1, 0x99, 0x1e, 0xf0, 0xe2, 0xe2, 0xab, 0x30, 0x17, 0x6a, 0x12, 0x5f, + 0xd1, 0xc4, 0x8c, 0x57, 0x34, 0xc1, 0x5f, 0xd1, 0x9a, 0x7a, 0x4b, 0x29, 0xd7, 0x20, 0x3e, 0x70, + 0x46, 0x16, 0x79, 0x6e, 0xe6, 0x02, 0x17, 0xba, 0x28, 0x99, 0x7c, 0x64, 0x28, 0x26, 0xda, 0x94, + 0x5f, 0x86, 0xb8, 0x6b, 0x1d, 0xb8, 0xcf, 0xb2, 0xdd, 0x67, 0xf3, 0xa3, 0x90, 0xf2, 0x75, 0x48, + 0xda, 0x93, 0xc1, 0xae, 0x35, 0x7a, 0x16, 0xb8, 0x87, 0x03, 0xe3, 0xa0, 0xe2, 0x3b, 0xa0, 0xdd, + 0x73, 0x06, 0xc3, 0xbe, 0x75, 0xb0, 0x76, 0xe0, 0x5a, 0xf6, 0xb8, 0xe7, 0xd8, 0x74, 0x0e, 0x9d, + 0xde, 0x08, 0xdd, 0x1a, 0xce, 0x01, 0x0b, 0xd4, 0xcd, 0x8c, 0xad, 0x3d, 0xc7, 0x6e, 0xf3, 0xa9, + 0xf1, 0x12, 0x45, 0xbb, 0xfb, 0xbd, 0x11, 0xf5, 0x68, 0x34, 0xf8, 0xb0, 0x42, 0x71, 0x1d, 0xf2, + 0xfc, 0x18, 0x36, 0xe6, 0x1d, 0x17, 0xaf, 0x42, 0xce, 0xab, 0xc2, 0x5f, 0x7e, 0xd2, 0x10, 0x7f, + 0xbc, 0x66, 0x36, 0xb4, 0x53, 0x74, 0x5f, 0x1b, 0x5b, 0x6b, 0x9a, 0x42, 0x1f, 0x76, 0xde, 0x6d, + 0x84, 0xf6, 0xf2, 0x79, 0xc8, 0xf9, 0x63, 0xdf, 0xb6, 0x5c, 0x6c, 0xa1, 0x51, 0x2a, 0x55, 0x53, + 0xd3, 0x4a, 0x31, 0x05, 0x89, 0xb5, 0xc1, 0xd0, 0x3d, 0x2c, 0xfe, 0x12, 0x64, 0x39, 0xe8, 0x61, + 0x6f, 0xec, 0x92, 0xdb, 0x90, 0x1a, 0xf0, 0xf9, 0x2a, 0x98, 0x8b, 0x86, 0x65, 0x1d, 0x20, 0xbd, + 0x67, 0xd3, 0xc3, 0x2f, 0x56, 0x20, 0x25, 0xb8, 0x77, 0xee, 0x79, 0x54, 0xd1, 0xf3, 0x30, 0x1f, + 0x15, 0x13, 0x7c, 0x54, 0x71, 0x13, 0x52, 0x2c, 0x30, 0x8f, 0x31, 0xdd, 0x60, 0xe7, 0x77, 0xa6, + 0x31, 0x26, 0xbe, 0x2c, 0xab, 0x63, 0x39, 0xd4, 0x65, 0xc8, 0xe2, 0x3b, 0xe3, 0xab, 0x90, 0x7a, + 0x73, 0xc0, 0x2a, 0xa6, 0xf8, 0x3f, 0x4a, 0x40, 0xda, 0x5b, 0x2b, 0x72, 0x01, 0x92, 0xec, 0x10, + 0x8b, 0x54, 0xde, 0xa5, 0x4e, 0x02, 0x8f, 0xad, 0xe4, 0x02, 0xa4, 0xf8, 0x41, 0x95, 0x07, 0x1c, + 0xb5, 0x52, 0x36, 0x93, 0xec, 0x60, 0xea, 0x37, 0x56, 0x0d, 0xf4, 0x93, 0xec, 0xba, 0x26, 0xc9, + 0x8e, 0x9e, 0x44, 0x87, 0x8c, 0x7f, 0xd8, 0xc4, 0x10, 0xc1, 0xef, 0x66, 0xd2, 0xde, 0xe9, 0x52, + 0x40, 0x54, 0x0d, 0x74, 0xa0, 0xfc, 0x22, 0x26, 0x5d, 0x0f, 0xf2, 0xa6, 0xb4, 0x77, 0x64, 0xc4, + 0x5f, 0x9e, 0xbc, 0x5b, 0x97, 0x14, 0x3f, 0x24, 0x06, 0x80, 0xaa, 0x81, 0x9e, 0xc9, 0xbb, 0x62, + 0x49, 0xf1, 0x83, 0x20, 0xb9, 0x4c, 0x87, 0x88, 0x07, 0x3b, 0xf4, 0x3f, 0xc1, 0x7d, 0x4a, 0x92, + 0x1d, 0xf7, 0xc8, 0x15, 0xca, 0xc0, 0x4e, 0x6f, 0xe8, 0x1a, 0x82, 0xcb, 0x93, 0x14, 0x3f, 0xd4, + 0x91, 0x6b, 0x14, 0xc2, 0x96, 0xbf, 0x00, 0xcf, 0xb8, 0x29, 0x49, 0xf1, 0x9b, 0x12, 0xa2, 0xd3, + 0x0e, 0xd1, 0x43, 0xa1, 0x57, 0x12, 0x6e, 0x45, 0x92, 0xec, 0x56, 0x84, 0x5c, 0x42, 0x3a, 0x36, + 0xa9, 0x5c, 0x70, 0x03, 0x92, 0xe2, 0xa7, 0xc0, 0xa0, 0x1d, 0x73, 0x49, 0xff, 0xb6, 0x23, 0xc5, + 0xcf, 0x79, 0xe4, 0x16, 0xdd, 0x2f, 0xaa, 0xf0, 0xc2, 0x3c, 0xfa, 0xe2, 0x45, 0x51, 0x7a, 0xde, + 0xae, 0x32, 0x57, 0x5c, 0x63, 0x6e, 0xcc, 0x4c, 0xd4, 0xf1, 0x8d, 0x58, 0xa4, 0x96, 0x8f, 0x7a, + 0x76, 0xa7, 0x90, 0xc7, 0xb5, 0x88, 0xf5, 0xec, 0x8e, 0x99, 0xa8, 0xd3, 0x1a, 0xa6, 0x82, 0x2d, + 0xda, 0xa6, 0x61, 0x5b, 0xfc, 0x3a, 0x6b, 0xa4, 0x55, 0xa4, 0x00, 0x89, 0x7a, 0x73, 0xab, 0x65, + 0x17, 0x16, 0x98, 0x9d, 0xdd, 0xb2, 0xcd, 0x78, 0x7d, 0xab, 0x65, 0x93, 0x97, 0x21, 0x36, 0x9e, + 0xec, 0x16, 0xc8, 0xf4, 0xcf, 0x82, 0xdb, 0x93, 0x5d, 0x6f, 0x30, 0x26, 0xc5, 0x90, 0x0b, 0x90, + 0x1e, 0xbb, 0xa3, 0xe6, 0x2f, 0x58, 0x23, 0xa7, 0x70, 0x1a, 0x97, 0xf1, 0x94, 0x99, 0x1a, 0xbb, + 0xa3, 0xc7, 0xd6, 0xc8, 0x39, 0xa6, 0x0f, 0x2e, 0x5e, 0x82, 0xac, 0xc0, 0x4b, 0xf2, 0xa0, 0xd8, + 0x2c, 0x81, 0xa9, 0x29, 0x37, 0x4d, 0xc5, 0x2e, 0xbe, 0x03, 0x39, 0xef, 0x88, 0x85, 0x33, 0x36, + 0xe8, 0xdb, 0xd4, 0x77, 0x46, 0xf8, 0x96, 0xce, 0x97, 0x2f, 0x85, 0x23, 0x66, 0x00, 0xe4, 0x91, + 0x8b, 0x81, 0x8b, 0x5a, 0x64, 0x30, 0x4a, 0xf1, 0x07, 0x0a, 0xe4, 0x36, 0x9d, 0x51, 0xf0, 0xfb, + 0xc5, 0x19, 0x48, 0xec, 0x3a, 0x4e, 0x7f, 0x8c, 0xc4, 0x69, 0x93, 0x15, 0xc8, 0x8b, 0x90, 0xc3, + 0x07, 0xef, 0x90, 0xac, 0xfa, 0xb7, 0x40, 0x59, 0xac, 0xe7, 0xe7, 0x62, 0x02, 0xf1, 0x9e, 0xed, + 0x8e, 0xb9, 0x47, 0xc3, 0x67, 0xf2, 0x05, 0xc8, 0xd2, 0xbf, 0x9e, 0x65, 0xdc, 0xcf, 0xa6, 0x81, + 0x56, 0x73, 0xc3, 0x97, 0x60, 0x0e, 0x35, 0xe0, 0xc3, 0x52, 0xfe, 0x8d, 0x4f, 0x8e, 0x35, 0x70, + 0x60, 0x01, 0x52, 0xcc, 0x21, 0x8c, 0xf1, 0x07, 0xdf, 0x8c, 0xe9, 0x15, 0xa9, 0x9b, 0xc5, 0x83, + 0x0a, 0xcb, 0x40, 0x52, 0x26, 0x2f, 0x15, 0xef, 0x41, 0x1a, 0xc3, 0x65, 0xa3, 0xdf, 0x26, 0x2f, + 0x80, 0xd2, 0x2d, 0x58, 0x18, 0xae, 0xcf, 0x86, 0x4e, 0x21, 0x1c, 0xb0, 0xb4, 0x6e, 0x2a, 0xdd, + 0xc5, 0x05, 0x50, 0xd6, 0xe9, 0xb1, 0xe0, 0x80, 0x3b, 0x6c, 0xe5, 0xa0, 0xf8, 0x16, 0x27, 0xd9, + 0xb2, 0x9e, 0xca, 0x49, 0xb6, 0xac, 0xa7, 0x8c, 0xe4, 0xf2, 0x14, 0x09, 0x2d, 0x1d, 0xf2, 0xdf, + 0xc0, 0x95, 0xc3, 0x62, 0x05, 0xe6, 0xf0, 0x45, 0xed, 0xd9, 0xdd, 0x47, 0x4e, 0xcf, 0xc6, 0x83, + 0x48, 0x07, 0x13, 0x38, 0xc5, 0x54, 0x3a, 0x74, 0x1f, 0xac, 0x83, 0xd6, 0x1e, 0x4b, 0x87, 0xd3, + 0x26, 0x2b, 0x14, 0xbf, 0x1f, 0x87, 0x79, 0xee, 0x64, 0xdf, 0xed, 0xb9, 0xfb, 0x9b, 0xad, 0x21, + 0xd9, 0x82, 0x1c, 0xf5, 0xaf, 0xcd, 0x41, 0x6b, 0x38, 0xa4, 0x2f, 0xb2, 0x82, 0xa1, 0xf9, 0xda, + 0x0c, 0xb7, 0xcd, 0x2d, 0x96, 0xb6, 0x5a, 0x03, 0x6b, 0x93, 0xa1, 0x59, 0xa0, 0xce, 0xda, 0x41, + 0x0d, 0x79, 0x00, 0xd9, 0xc1, 0xb8, 0xeb, 0xd3, 0xb1, 0x48, 0x7f, 0x55, 0x42, 0xb7, 0x39, 0xee, + 0x86, 0xd8, 0x60, 0xe0, 0x57, 0xd0, 0xc1, 0x51, 0xef, 0xec, 0xb3, 0xc5, 0x8e, 0x1c, 0x1c, 0x75, + 0x25, 0xe1, 0xc1, 0xed, 0x06, 0x35, 0xa4, 0x0e, 0x40, 0x5f, 0x35, 0xd7, 0xa1, 0x27, 0x3c, 0xd4, + 0x52, 0xb6, 0x5c, 0x92, 0xb0, 0x6d, 0xbb, 0xa3, 0x1d, 0x67, 0xdb, 0x1d, 0xf1, 0x84, 0x64, 0xcc, + 0x8b, 0x8b, 0xaf, 0x83, 0x16, 0x5d, 0x85, 0xa3, 0x72, 0x92, 0x8c, 0x90, 0x93, 0x2c, 0xfe, 0x1c, + 0xe4, 0x23, 0xd3, 0x16, 0xcd, 0x09, 0x33, 0xbf, 0x21, 0x9a, 0x67, 0xcb, 0xe7, 0x43, 0xdf, 0x68, + 0x88, 0x5b, 0x2f, 0x32, 0xbf, 0x0e, 0x5a, 0x74, 0x09, 0x44, 0xea, 0xb4, 0xe4, 0x40, 0x83, 0xf6, + 0xaf, 0xc2, 0x5c, 0x68, 0xd2, 0xa2, 0x71, 0xe6, 0x88, 0x69, 0x15, 0x7f, 0x25, 0x01, 0x89, 0x86, + 0x6d, 0x39, 0x1d, 0x72, 0x2e, 0x1c, 0x3b, 0xdf, 0x3c, 0xe5, 0xc5, 0xcd, 0xf3, 0x91, 0xb8, 0xf9, + 0xe6, 0x29, 0x3f, 0x6a, 0x9e, 0x8f, 0x44, 0x4d, 0xaf, 0xa9, 0x6a, 0x90, 0x8b, 0x53, 0x31, 0xf3, + 0xcd, 0x53, 0x42, 0xc0, 0xbc, 0x38, 0x15, 0x30, 0x83, 0xe6, 0xaa, 0x41, 0x1d, 0x6c, 0x38, 0x5a, + 0xbe, 0x79, 0x2a, 0x88, 0x94, 0x17, 0xa2, 0x91, 0xd2, 0x6f, 0xac, 0x1a, 0x6c, 0x48, 0x42, 0x94, + 0xc4, 0x21, 0xb1, 0xf8, 0x78, 0x21, 0x1a, 0x1f, 0xd1, 0x8e, 0x47, 0xc6, 0x0b, 0xd1, 0xc8, 0x88, + 0x8d, 0x3c, 0x12, 0x9e, 0x8f, 0x44, 0x42, 0x24, 0x65, 0x21, 0xf0, 0x42, 0x34, 0x04, 0x32, 0x3b, + 0x61, 0xa4, 0x62, 0xfc, 0xf3, 0x1b, 0xab, 0x06, 0x31, 0x22, 0xc1, 0x4f, 0x76, 0x10, 0xc1, 0xdd, + 0xc0, 0x30, 0x50, 0xa5, 0x0b, 0xe7, 0x25, 0xa8, 0x79, 0xe9, 0x27, 0x2c, 0xb8, 0xa2, 0x5e, 0x82, + 0x66, 0x40, 0xaa, 0xc3, 0xcf, 0xea, 0x1a, 0x7a, 0xb2, 0x90, 0x38, 0x51, 0x02, 0x4b, 0xf5, 0x26, + 0x7a, 0x34, 0x3a, 0xbb, 0x0e, 0x3b, 0x70, 0x94, 0x60, 0xae, 0xde, 0x7c, 0xd8, 0x1a, 0x75, 0x29, + 0x74, 0xa7, 0xd5, 0xf5, 0x6f, 0x3d, 0xa8, 0x0a, 0xb2, 0x75, 0xde, 0xb2, 0xd3, 0xea, 0x92, 0xb3, + 0x9e, 0xc4, 0xda, 0xd8, 0xaa, 0x70, 0x91, 0x2d, 0x9e, 0xa3, 0x4b, 0xc7, 0xc8, 0xd0, 0x37, 0x2e, + 0x70, 0xdf, 0x78, 0x37, 0x05, 0x89, 0x89, 0xdd, 0x73, 0xec, 0xbb, 0x19, 0x48, 0xb9, 0xce, 0x68, + 0xd0, 0x72, 0x9d, 0xe2, 0x0f, 0x15, 0x80, 0x7b, 0xce, 0x60, 0x30, 0xb1, 0x7b, 0xef, 0x4d, 0x2c, + 0x72, 0x09, 0xb2, 0x83, 0xd6, 0x13, 0xab, 0x39, 0xb0, 0x9a, 0x7b, 0x23, 0xef, 0x6d, 0xc8, 0xd0, + 0xaa, 0x4d, 0xeb, 0xde, 0xe8, 0x90, 0x14, 0xbc, 0x04, 0x1e, 0x15, 0x84, 0xc2, 0xe4, 0x09, 0xfd, + 0x19, 0x9e, 0x8e, 0x26, 0xf9, 0x4e, 0x7a, 0x09, 0x29, 0x3b, 0xe4, 0xa4, 0xf8, 0x1e, 0xb2, 0x63, + 0xce, 0x39, 0x48, 0xba, 0xd6, 0x60, 0xd8, 0xdc, 0x43, 0xc1, 0x50, 0x51, 0x24, 0x68, 0xf9, 0x1e, + 0xb9, 0x01, 0xb1, 0x3d, 0xa7, 0x8f, 0x52, 0x39, 0x72, 0x77, 0x28, 0x92, 0xbc, 0x04, 0xb1, 0xc1, + 0x98, 0xc9, 0x27, 0x5b, 0x3e, 0x1d, 0xca, 0x20, 0x58, 0xc8, 0xa2, 0xc0, 0xc1, 0xb8, 0xeb, 0xcf, + 0xbd, 0xf8, 0xa9, 0x0a, 0x69, 0xba, 0x5f, 0x6f, 0xef, 0xd4, 0x6f, 0xe1, 0xb1, 0x61, 0xaf, 0xd5, + 0xc7, 0x1b, 0x02, 0xfa, 0x9a, 0xf2, 0x12, 0xad, 0xff, 0x8a, 0xb5, 0xe7, 0x3a, 0x23, 0x74, 0xcd, + 0x19, 0x93, 0x97, 0xe8, 0x92, 0xb3, 0xac, 0x38, 0xc6, 0x67, 0xc9, 0x8a, 0x98, 0xd1, 0xb7, 0x86, + 0x4d, 0xea, 0x03, 0x98, 0xbf, 0x0c, 0x9d, 0xae, 0xbd, 0xee, 0xe8, 0xd1, 0xed, 0x81, 0x75, 0xc8, + 0xfc, 0x64, 0x72, 0x80, 0x05, 0xf2, 0xb3, 0xec, 0xc8, 0xc7, 0x76, 0x92, 0x7d, 0x5f, 0x55, 0x7c, + 0x96, 0xf1, 0x3b, 0x14, 0x14, 0x9c, 0xfb, 0xb0, 0xb8, 0x78, 0x1b, 0xb2, 0x02, 0xef, 0x51, 0xae, + 0x28, 0x16, 0xf1, 0x63, 0x21, 0xd6, 0xa3, 0x6e, 0x75, 0x44, 0x3f, 0x46, 0x57, 0xd4, 0xa1, 0x1a, + 0xbe, 0x9a, 0x87, 0x58, 0xbd, 0xd1, 0xa0, 0x79, 0x56, 0xbd, 0xd1, 0x58, 0xd1, 0x94, 0xda, 0x0a, + 0xa4, 0xbb, 0x23, 0xcb, 0xa2, 0xae, 0xf7, 0x59, 0xe7, 0xbc, 0x2f, 0xe3, 0xb2, 0xfa, 0xb0, 0xda, + 0x5b, 0x90, 0xda, 0x63, 0x27, 0x3d, 0xf2, 0xcc, 0x5b, 0x8d, 0xc2, 0x1f, 0xb3, 0xdb, 0xb5, 0xe7, + 0x45, 0x40, 0xf4, 0x7c, 0x68, 0x7a, 0x3c, 0xb5, 0x1d, 0xc8, 0x8c, 0x9a, 0x47, 0x93, 0x7e, 0xc0, + 0x62, 0xb9, 0x9c, 0x34, 0x3d, 0xe2, 0x55, 0xb5, 0x75, 0x58, 0xb0, 0x1d, 0xef, 0x47, 0xbe, 0x66, + 0x9b, 0x7b, 0xb2, 0x59, 0x49, 0xb4, 0xd7, 0x81, 0xc5, 0x3e, 0x15, 0xb0, 0x1d, 0xde, 0xc0, 0xbc, + 0x5f, 0x6d, 0x0d, 0x34, 0x81, 0xa8, 0xc3, 0xdc, 0xa5, 0x8c, 0xa7, 0xc3, 0xbe, 0x4e, 0xf0, 0x79, + 0xd0, 0xc3, 0x46, 0x68, 0xb8, 0x0f, 0x94, 0xd1, 0x74, 0xd9, 0xc7, 0x1e, 0x3e, 0x0d, 0x86, 0x95, + 0x69, 0x1a, 0x1a, 0x11, 0x64, 0x34, 0xfb, 0xec, 0x4b, 0x10, 0x91, 0xa6, 0x6a, 0x44, 0x56, 0x67, + 0x72, 0x8c, 0xe1, 0xf4, 0xd8, 0xa7, 0x1c, 0x3e, 0x0f, 0x0b, 0x38, 0x33, 0x88, 0x8e, 0x1a, 0xd0, + 0x97, 0xd9, 0x77, 0x1e, 0x21, 0xa2, 0xa9, 0x11, 0x8d, 0x8f, 0x31, 0xa2, 0x27, 0xec, 0xb3, 0x0a, + 0x9f, 0x68, 0x7b, 0xd6, 0x88, 0xc6, 0xc7, 0x18, 0x51, 0x9f, 0x7d, 0x72, 0x11, 0x22, 0xaa, 0x1a, + 0xb5, 0x0d, 0x20, 0xe2, 0xc6, 0xf3, 0xe8, 0x2c, 0x65, 0x1a, 0xb0, 0x4f, 0x69, 0x82, 0xad, 0x67, + 0x46, 0xb3, 0xa8, 0x8e, 0x1a, 0x94, 0xcd, 0xbe, 0xb3, 0x09, 0x53, 0x55, 0x8d, 0xda, 0x03, 0x38, + 0x2d, 0x4e, 0xef, 0x58, 0xc3, 0x72, 0xd8, 0x47, 0x22, 0xc1, 0x04, 0xb9, 0xd5, 0x4c, 0xb2, 0xa3, + 0x06, 0x36, 0x64, 0x1f, 0x90, 0x44, 0xc8, 0xaa, 0x46, 0xed, 0x1e, 0xe4, 0x05, 0xb2, 0x5d, 0xbc, + 0x57, 0x90, 0x11, 0xbd, 0xc7, 0x3e, 0x7b, 0xf2, 0x89, 0x68, 0x46, 0x15, 0xdd, 0x3d, 0x96, 0x63, + 0x48, 0x69, 0x46, 0xec, 0xab, 0x9d, 0x60, 0x3c, 0x68, 0x13, 0x79, 0x51, 0x76, 0x59, 0x42, 0x22, + 0xe3, 0x19, 0xb3, 0x2f, 0x7a, 0x82, 0xe1, 0x50, 0x93, 0xda, 0x20, 0x34, 0x29, 0x8b, 0xa6, 0x19, + 0x52, 0x16, 0x17, 0x23, 0x62, 0x49, 0x02, 0x59, 0x12, 0xaf, 0xaf, 0x84, 0xe9, 0xd3, 0x62, 0xed, + 0x01, 0xcc, 0x9f, 0xc4, 0x65, 0x7d, 0xa0, 0xb0, 0xbb, 0x8c, 0xca, 0xd2, 0x8a, 0xb1, 0xb2, 0x6a, + 0xce, 0xb5, 0x43, 0x9e, 0x6b, 0x1d, 0xe6, 0x4e, 0xe0, 0xb6, 0x3e, 0x54, 0xd8, 0x8d, 0x00, 0xe5, + 0x32, 0x73, 0xed, 0xb0, 0xef, 0x9a, 0x3b, 0x81, 0xe3, 0xfa, 0x48, 0x61, 0x57, 0x48, 0x46, 0xd9, + 0xa7, 0xf1, 0x7c, 0xd7, 0xdc, 0x09, 0x1c, 0xd7, 0xc7, 0xec, 0xc4, 0xaf, 0x1a, 0x15, 0x91, 0x06, + 0x3d, 0xc5, 0xfc, 0x49, 0x1c, 0xd7, 0x27, 0x0a, 0x5e, 0x29, 0xa9, 0x86, 0xe1, 0xaf, 0x8f, 0xef, + 0xbb, 0xe6, 0x4f, 0xe2, 0xb8, 0xbe, 0xa6, 0xe0, 0xd5, 0x93, 0x6a, 0xac, 0x86, 0x88, 0xc2, 0x23, + 0x3a, 0x8e, 0xe3, 0xfa, 0x54, 0xc1, 0xfb, 0x20, 0xd5, 0xa8, 0xfa, 0x44, 0xdb, 0x53, 0x23, 0x3a, + 0x8e, 0xe3, 0xfa, 0x3a, 0x9e, 0xaf, 0x6a, 0xaa, 0x71, 0x33, 0x44, 0x84, 0xbe, 0x2b, 0x7f, 0x22, + 0xc7, 0xf5, 0x0d, 0x05, 0xaf, 0xee, 0x54, 0xe3, 0x96, 0xe9, 0x8d, 0x20, 0xf0, 0x5d, 0xf9, 0x13, + 0x39, 0xae, 0x6f, 0x2a, 0x78, 0xc7, 0xa7, 0x1a, 0xb7, 0xc3, 0x54, 0xe8, 0xbb, 0xb4, 0x93, 0x39, + 0xae, 0xcf, 0x14, 0xfc, 0xa2, 0x47, 0x5d, 0x5d, 0x36, 0xbd, 0x41, 0x08, 0xbe, 0x4b, 0x3b, 0x99, + 0xe3, 0xfa, 0x96, 0x82, 0x9f, 0xf9, 0xa8, 0xab, 0x2b, 0x11, 0xb2, 0xaa, 0x51, 0x5b, 0x83, 0xdc, + 0xf1, 0x1d, 0xd7, 0xb7, 0xc5, 0x1b, 0xd4, 0x6c, 0x5b, 0xf0, 0x5e, 0x8f, 0x85, 0xfd, 0x3b, 0x86, + 0xeb, 0xfa, 0x0e, 0x26, 0x7f, 0xb5, 0xe7, 0xde, 0x64, 0xf7, 0x8c, 0xcc, 0xe4, 0x95, 0xb6, 0xd5, + 0x79, 0xad, 0xe3, 0x38, 0xc1, 0x96, 0x32, 0x87, 0xd6, 0x08, 0xde, 0x9e, 0x63, 0x78, 0xb3, 0xef, + 0x2a, 0x78, 0x2d, 0x99, 0xe3, 0xd4, 0x68, 0xe1, 0xbf, 0x47, 0xcc, 0xb5, 0xd9, 0xc1, 0x9c, 0x8f, + 0xf6, 0x6b, 0xdf, 0x53, 0x4e, 0xe6, 0xd8, 0x6a, 0xb1, 0xc6, 0xd6, 0x9a, 0xbf, 0x38, 0x58, 0xf3, + 0x06, 0xc4, 0x0f, 0xca, 0xcb, 0x2b, 0xe1, 0x14, 0x4f, 0xbc, 0x95, 0x67, 0xee, 0x2c, 0x5b, 0x5e, + 0x08, 0xfd, 0x7c, 0x31, 0x18, 0xba, 0x87, 0x26, 0x5a, 0x72, 0x86, 0xb2, 0x84, 0xe1, 0x43, 0x29, + 0x43, 0x99, 0x33, 0x54, 0x24, 0x0c, 0x1f, 0x49, 0x19, 0x2a, 0x9c, 0xc1, 0x90, 0x30, 0x7c, 0x2c, + 0x65, 0x30, 0x38, 0xc3, 0xaa, 0x84, 0xe1, 0x13, 0x29, 0xc3, 0x2a, 0x67, 0xa8, 0x4a, 0x18, 0xbe, + 0x26, 0x65, 0xa8, 0x72, 0x86, 0x9b, 0x12, 0x86, 0x4f, 0xa5, 0x0c, 0x37, 0x39, 0xc3, 0x2d, 0x09, + 0xc3, 0xd7, 0xa5, 0x0c, 0xb7, 0x38, 0xc3, 0x6d, 0x09, 0xc3, 0x37, 0xa4, 0x0c, 0xb7, 0x19, 0xc3, + 0xca, 0xb2, 0x84, 0xe1, 0x9b, 0x32, 0x86, 0x95, 0x65, 0xce, 0x20, 0xd3, 0xe4, 0x67, 0x52, 0x06, + 0xae, 0xc9, 0x15, 0x99, 0x26, 0xbf, 0x25, 0x65, 0xe0, 0x9a, 0x5c, 0x91, 0x69, 0xf2, 0xdb, 0x52, + 0x06, 0xae, 0xc9, 0x15, 0x99, 0x26, 0xbf, 0x23, 0x65, 0xe0, 0x9a, 0x5c, 0x91, 0x69, 0xf2, 0xbb, + 0x52, 0x06, 0xae, 0xc9, 0x15, 0x99, 0x26, 0xbf, 0x27, 0x65, 0xe0, 0x9a, 0x5c, 0x91, 0x69, 0xf2, + 0x4f, 0xa4, 0x0c, 0x5c, 0x93, 0x2b, 0x32, 0x4d, 0xfe, 0xa9, 0x94, 0x81, 0x6b, 0x72, 0x45, 0xa6, + 0xc9, 0x3f, 0x93, 0x32, 0x70, 0x4d, 0x96, 0x65, 0x9a, 0xfc, 0xbe, 0x8c, 0xa1, 0xcc, 0x35, 0x59, + 0x96, 0x69, 0xf2, 0xcf, 0xa5, 0x0c, 0x5c, 0x93, 0x65, 0x99, 0x26, 0xff, 0x42, 0xca, 0xc0, 0x35, + 0x59, 0x96, 0x69, 0xf2, 0x07, 0x52, 0x06, 0xae, 0xc9, 0xb2, 0x4c, 0x93, 0x7f, 0x29, 0x65, 0xe0, + 0x9a, 0x2c, 0xcb, 0x34, 0xf9, 0x57, 0x52, 0x06, 0xae, 0xc9, 0xb2, 0x4c, 0x93, 0x7f, 0x2d, 0x65, + 0xe0, 0x9a, 0x2c, 0xcb, 0x34, 0xf9, 0x37, 0x52, 0x06, 0xae, 0xc9, 0xb2, 0x4c, 0x93, 0x7f, 0x2b, + 0x65, 0xe0, 0x9a, 0x2c, 0xcb, 0x34, 0xf9, 0x77, 0x52, 0x06, 0xae, 0xc9, 0x8a, 0x4c, 0x93, 0x7f, + 0x2f, 0x63, 0xa8, 0x70, 0x4d, 0x56, 0x64, 0x9a, 0xfc, 0x07, 0x29, 0x03, 0xd7, 0x64, 0x45, 0xa6, + 0xc9, 0x7f, 0x94, 0x32, 0x70, 0x4d, 0x56, 0x64, 0x9a, 0xfc, 0x27, 0x29, 0x03, 0xd7, 0x64, 0x45, + 0xa6, 0xc9, 0x7f, 0x96, 0x32, 0x70, 0x4d, 0x56, 0x64, 0x9a, 0xfc, 0x17, 0x29, 0x03, 0xd7, 0x64, + 0x45, 0xa6, 0xc9, 0x7f, 0x95, 0x32, 0x70, 0x4d, 0x56, 0x64, 0x9a, 0xfc, 0x37, 0x29, 0x03, 0xd7, + 0x64, 0x45, 0xa6, 0xc9, 0x1f, 0x4a, 0x19, 0xb8, 0x26, 0x2b, 0x32, 0x4d, 0xfe, 0xbb, 0x94, 0x81, + 0x6b, 0xd2, 0x90, 0x69, 0xf2, 0x3f, 0x64, 0x0c, 0x06, 0xd7, 0xa4, 0x21, 0xd3, 0xe4, 0x7f, 0x4a, + 0x19, 0xb8, 0x26, 0x0d, 0x99, 0x26, 0xff, 0x4b, 0xca, 0xc0, 0x35, 0x69, 0xc8, 0x34, 0xf9, 0xdf, + 0x52, 0x06, 0xae, 0x49, 0x43, 0xa6, 0xc9, 0xff, 0x91, 0x32, 0x70, 0x4d, 0x1a, 0x32, 0x4d, 0xfe, + 0xaf, 0x94, 0x81, 0x6b, 0xd2, 0x90, 0x69, 0xf2, 0x47, 0x52, 0x06, 0xae, 0x49, 0x43, 0xa6, 0xc9, + 0x1f, 0x4b, 0x19, 0xb8, 0x26, 0x0d, 0x99, 0x26, 0x7f, 0x22, 0x65, 0xe0, 0x9a, 0x34, 0x64, 0x9a, + 0xfc, 0xa9, 0x94, 0x81, 0x6b, 0x72, 0x55, 0xa6, 0xc9, 0xff, 0x93, 0x31, 0xac, 0x2e, 0xdf, 0xbd, + 0xfe, 0xf8, 0x5a, 0xb7, 0xe7, 0xee, 0x4f, 0x76, 0x97, 0xf6, 0x9c, 0xc1, 0x8d, 0xae, 0xd3, 0x6f, + 0xd9, 0xdd, 0x1b, 0x08, 0xdb, 0x9d, 0x74, 0x6e, 0x04, 0xff, 0xcc, 0xce, 0x4c, 0xff, 0x3f, 0x00, + 0x00, 0xff, 0xff, 0x8e, 0xb4, 0x0c, 0xbd, 0xe4, 0x3e, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/proto/testdata/test.proto b/vendor/github.com/golang/protobuf/proto/test_proto/test.proto similarity index 94% rename from vendor/github.com/golang/protobuf/proto/testdata/test.proto rename to vendor/github.com/golang/protobuf/proto/test_proto/test.proto index 70e3cfcd..f339e05c 100644 --- a/vendor/github.com/golang/protobuf/proto/testdata/test.proto +++ b/vendor/github.com/golang/protobuf/proto/test_proto/test.proto @@ -33,7 +33,9 @@ syntax = "proto2"; -package testdata; +option go_package = "github.com/golang/protobuf/proto/test_proto"; + +package test_proto; enum FOO { FOO1 = 1; }; @@ -96,6 +98,8 @@ message GoTest { required bytes F_Bytes_required = 101; required sint32 F_Sint32_required = 102; required sint64 F_Sint64_required = 103; + required sfixed32 F_Sfixed32_required = 104; + required sfixed64 F_Sfixed64_required = 105; // Repeated fields of all basic types repeated bool F_Bool_repeated = 20; @@ -111,6 +115,8 @@ message GoTest { repeated bytes F_Bytes_repeated = 201; repeated sint32 F_Sint32_repeated = 202; repeated sint64 F_Sint64_repeated = 203; + repeated sfixed32 F_Sfixed32_repeated = 204; + repeated sfixed64 F_Sfixed64_repeated = 205; // Optional fields of all basic types optional bool F_Bool_optional = 30; @@ -126,6 +132,8 @@ message GoTest { optional bytes F_Bytes_optional = 301; optional sint32 F_Sint32_optional = 302; optional sint64 F_Sint64_optional = 303; + optional sfixed32 F_Sfixed32_optional = 304; + optional sfixed64 F_Sfixed64_optional = 305; // Default-valued fields of all basic types optional bool F_Bool_defaulted = 40 [default=true]; @@ -141,6 +149,8 @@ message GoTest { optional bytes F_Bytes_defaulted = 401 [default="Bignose"]; optional sint32 F_Sint32_defaulted = 402 [default = -32]; optional sint64 F_Sint64_defaulted = 403 [default = -64]; + optional sfixed32 F_Sfixed32_defaulted = 404 [default = -32]; + optional sfixed64 F_Sfixed64_defaulted = 405 [default = -64]; // Packed repeated fields (no string or bytes). repeated bool F_Bool_repeated_packed = 50 [packed=true]; @@ -154,6 +164,8 @@ message GoTest { repeated double F_Double_repeated_packed = 58 [packed=true]; repeated sint32 F_Sint32_repeated_packed = 502 [packed=true]; repeated sint64 F_Sint64_repeated_packed = 503 [packed=true]; + repeated sfixed32 F_Sfixed32_repeated_packed = 504 [packed=true]; + repeated sfixed64 F_Sfixed64_repeated_packed = 505 [packed=true]; // Required, repeated, and optional groups. required group RequiredGroup = 70 { @@ -285,10 +297,12 @@ message Ext { } optional string data = 1; + map map_field = 2; } extend MyMessage { repeated string greeting = 106; + // leave field 200 unregistered for testing } message ComplexExtension { @@ -342,7 +356,7 @@ extend DefaultsMessage { optional sfixed32 default_sfixed32 = 211 [default = 50]; optional sfixed64 default_sfixed64 = 212 [default = 51]; optional bool default_bool = 213 [default = true]; - optional string default_string = 214 [default = "Hello, string"]; + optional string default_string = 214 [default = "Hello, string,def=foo"]; optional bytes default_bytes = 215 [default = "Hello, bytes"]; optional DefaultsMessage.DefaultsEnum default_enum = 216 [default = ONE]; } @@ -546,3 +560,11 @@ message Communique { Strings msg = 10; } } + +message TestUTF8 { + optional string scalar = 1; + repeated string vector = 2; + oneof oneof { string field = 3; } + map map_key = 4; + map map_value = 5; +} diff --git a/vendor/github.com/golang/protobuf/proto/testdata/Makefile b/vendor/github.com/golang/protobuf/proto/testdata/Makefile deleted file mode 100644 index fc288628..00000000 --- a/vendor/github.com/golang/protobuf/proto/testdata/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -include ../../Make.protobuf - -all: regenerate - -regenerate: - rm -f test.pb.go - make test.pb.go - -# The following rules are just aids to development. Not needed for typical testing. - -diff: regenerate - git diff test.pb.go - -restore: - cp test.pb.go.golden test.pb.go - -preserve: - cp test.pb.go test.pb.go.golden diff --git a/vendor/github.com/golang/protobuf/proto/testdata/test.pb.go b/vendor/github.com/golang/protobuf/proto/testdata/test.pb.go deleted file mode 100644 index e980d1a0..00000000 --- a/vendor/github.com/golang/protobuf/proto/testdata/test.pb.go +++ /dev/null @@ -1,4147 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: test.proto - -/* -Package testdata is a generated protocol buffer package. - -It is generated from these files: - test.proto - -It has these top-level messages: - GoEnum - GoTestField - GoTest - GoTestRequiredGroupField - GoSkipTest - NonPackedTest - PackedTest - MaxTag - OldMessage - NewMessage - InnerMessage - OtherMessage - RequiredInnerMessage - MyMessage - Ext - ComplexExtension - DefaultsMessage - MyMessageSet - Empty - MessageList - Strings - Defaults - SubDefaults - RepeatedEnum - MoreRepeated - GroupOld - GroupNew - FloatingPoint - MessageWithMap - Oneof - Communique -*/ -package testdata - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type FOO int32 - -const ( - FOO_FOO1 FOO = 1 -) - -var FOO_name = map[int32]string{ - 1: "FOO1", -} -var FOO_value = map[string]int32{ - "FOO1": 1, -} - -func (x FOO) Enum() *FOO { - p := new(FOO) - *p = x - return p -} -func (x FOO) String() string { - return proto.EnumName(FOO_name, int32(x)) -} -func (x *FOO) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO") - if err != nil { - return err - } - *x = FOO(value) - return nil -} -func (FOO) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -// An enum, for completeness. -type GoTest_KIND int32 - -const ( - GoTest_VOID GoTest_KIND = 0 - // Basic types - GoTest_BOOL GoTest_KIND = 1 - GoTest_BYTES GoTest_KIND = 2 - GoTest_FINGERPRINT GoTest_KIND = 3 - GoTest_FLOAT GoTest_KIND = 4 - GoTest_INT GoTest_KIND = 5 - GoTest_STRING GoTest_KIND = 6 - GoTest_TIME GoTest_KIND = 7 - // Groupings - GoTest_TUPLE GoTest_KIND = 8 - GoTest_ARRAY GoTest_KIND = 9 - GoTest_MAP GoTest_KIND = 10 - // Table types - GoTest_TABLE GoTest_KIND = 11 - // Functions - GoTest_FUNCTION GoTest_KIND = 12 -) - -var GoTest_KIND_name = map[int32]string{ - 0: "VOID", - 1: "BOOL", - 2: "BYTES", - 3: "FINGERPRINT", - 4: "FLOAT", - 5: "INT", - 6: "STRING", - 7: "TIME", - 8: "TUPLE", - 9: "ARRAY", - 10: "MAP", - 11: "TABLE", - 12: "FUNCTION", -} -var GoTest_KIND_value = map[string]int32{ - "VOID": 0, - "BOOL": 1, - "BYTES": 2, - "FINGERPRINT": 3, - "FLOAT": 4, - "INT": 5, - "STRING": 6, - "TIME": 7, - "TUPLE": 8, - "ARRAY": 9, - "MAP": 10, - "TABLE": 11, - "FUNCTION": 12, -} - -func (x GoTest_KIND) Enum() *GoTest_KIND { - p := new(GoTest_KIND) - *p = x - return p -} -func (x GoTest_KIND) String() string { - return proto.EnumName(GoTest_KIND_name, int32(x)) -} -func (x *GoTest_KIND) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(GoTest_KIND_value, data, "GoTest_KIND") - if err != nil { - return err - } - *x = GoTest_KIND(value) - return nil -} -func (GoTest_KIND) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} } - -type MyMessage_Color int32 - -const ( - MyMessage_RED MyMessage_Color = 0 - MyMessage_GREEN MyMessage_Color = 1 - MyMessage_BLUE MyMessage_Color = 2 -) - -var MyMessage_Color_name = map[int32]string{ - 0: "RED", - 1: "GREEN", - 2: "BLUE", -} -var MyMessage_Color_value = map[string]int32{ - "RED": 0, - "GREEN": 1, - "BLUE": 2, -} - -func (x MyMessage_Color) Enum() *MyMessage_Color { - p := new(MyMessage_Color) - *p = x - return p -} -func (x MyMessage_Color) String() string { - return proto.EnumName(MyMessage_Color_name, int32(x)) -} -func (x *MyMessage_Color) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(MyMessage_Color_value, data, "MyMessage_Color") - if err != nil { - return err - } - *x = MyMessage_Color(value) - return nil -} -func (MyMessage_Color) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{13, 0} } - -type DefaultsMessage_DefaultsEnum int32 - -const ( - DefaultsMessage_ZERO DefaultsMessage_DefaultsEnum = 0 - DefaultsMessage_ONE DefaultsMessage_DefaultsEnum = 1 - DefaultsMessage_TWO DefaultsMessage_DefaultsEnum = 2 -) - -var DefaultsMessage_DefaultsEnum_name = map[int32]string{ - 0: "ZERO", - 1: "ONE", - 2: "TWO", -} -var DefaultsMessage_DefaultsEnum_value = map[string]int32{ - "ZERO": 0, - "ONE": 1, - "TWO": 2, -} - -func (x DefaultsMessage_DefaultsEnum) Enum() *DefaultsMessage_DefaultsEnum { - p := new(DefaultsMessage_DefaultsEnum) - *p = x - return p -} -func (x DefaultsMessage_DefaultsEnum) String() string { - return proto.EnumName(DefaultsMessage_DefaultsEnum_name, int32(x)) -} -func (x *DefaultsMessage_DefaultsEnum) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(DefaultsMessage_DefaultsEnum_value, data, "DefaultsMessage_DefaultsEnum") - if err != nil { - return err - } - *x = DefaultsMessage_DefaultsEnum(value) - return nil -} -func (DefaultsMessage_DefaultsEnum) EnumDescriptor() ([]byte, []int) { - return fileDescriptor0, []int{16, 0} -} - -type Defaults_Color int32 - -const ( - Defaults_RED Defaults_Color = 0 - Defaults_GREEN Defaults_Color = 1 - Defaults_BLUE Defaults_Color = 2 -) - -var Defaults_Color_name = map[int32]string{ - 0: "RED", - 1: "GREEN", - 2: "BLUE", -} -var Defaults_Color_value = map[string]int32{ - "RED": 0, - "GREEN": 1, - "BLUE": 2, -} - -func (x Defaults_Color) Enum() *Defaults_Color { - p := new(Defaults_Color) - *p = x - return p -} -func (x Defaults_Color) String() string { - return proto.EnumName(Defaults_Color_name, int32(x)) -} -func (x *Defaults_Color) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Defaults_Color_value, data, "Defaults_Color") - if err != nil { - return err - } - *x = Defaults_Color(value) - return nil -} -func (Defaults_Color) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{21, 0} } - -type RepeatedEnum_Color int32 - -const ( - RepeatedEnum_RED RepeatedEnum_Color = 1 -) - -var RepeatedEnum_Color_name = map[int32]string{ - 1: "RED", -} -var RepeatedEnum_Color_value = map[string]int32{ - "RED": 1, -} - -func (x RepeatedEnum_Color) Enum() *RepeatedEnum_Color { - p := new(RepeatedEnum_Color) - *p = x - return p -} -func (x RepeatedEnum_Color) String() string { - return proto.EnumName(RepeatedEnum_Color_name, int32(x)) -} -func (x *RepeatedEnum_Color) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(RepeatedEnum_Color_value, data, "RepeatedEnum_Color") - if err != nil { - return err - } - *x = RepeatedEnum_Color(value) - return nil -} -func (RepeatedEnum_Color) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{23, 0} } - -type GoEnum struct { - Foo *FOO `protobuf:"varint,1,req,name=foo,enum=testdata.FOO" json:"foo,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoEnum) Reset() { *m = GoEnum{} } -func (m *GoEnum) String() string { return proto.CompactTextString(m) } -func (*GoEnum) ProtoMessage() {} -func (*GoEnum) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *GoEnum) GetFoo() FOO { - if m != nil && m.Foo != nil { - return *m.Foo - } - return FOO_FOO1 -} - -type GoTestField struct { - Label *string `protobuf:"bytes,1,req,name=Label" json:"Label,omitempty"` - Type *string `protobuf:"bytes,2,req,name=Type" json:"Type,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTestField) Reset() { *m = GoTestField{} } -func (m *GoTestField) String() string { return proto.CompactTextString(m) } -func (*GoTestField) ProtoMessage() {} -func (*GoTestField) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *GoTestField) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" -} - -func (m *GoTestField) GetType() string { - if m != nil && m.Type != nil { - return *m.Type - } - return "" -} - -type GoTest struct { - // Some typical parameters - Kind *GoTest_KIND `protobuf:"varint,1,req,name=Kind,enum=testdata.GoTest_KIND" json:"Kind,omitempty"` - Table *string `protobuf:"bytes,2,opt,name=Table" json:"Table,omitempty"` - Param *int32 `protobuf:"varint,3,opt,name=Param" json:"Param,omitempty"` - // Required, repeated and optional foreign fields. - RequiredField *GoTestField `protobuf:"bytes,4,req,name=RequiredField" json:"RequiredField,omitempty"` - RepeatedField []*GoTestField `protobuf:"bytes,5,rep,name=RepeatedField" json:"RepeatedField,omitempty"` - OptionalField *GoTestField `protobuf:"bytes,6,opt,name=OptionalField" json:"OptionalField,omitempty"` - // Required fields of all basic types - F_BoolRequired *bool `protobuf:"varint,10,req,name=F_Bool_required,json=FBoolRequired" json:"F_Bool_required,omitempty"` - F_Int32Required *int32 `protobuf:"varint,11,req,name=F_Int32_required,json=FInt32Required" json:"F_Int32_required,omitempty"` - F_Int64Required *int64 `protobuf:"varint,12,req,name=F_Int64_required,json=FInt64Required" json:"F_Int64_required,omitempty"` - F_Fixed32Required *uint32 `protobuf:"fixed32,13,req,name=F_Fixed32_required,json=FFixed32Required" json:"F_Fixed32_required,omitempty"` - F_Fixed64Required *uint64 `protobuf:"fixed64,14,req,name=F_Fixed64_required,json=FFixed64Required" json:"F_Fixed64_required,omitempty"` - F_Uint32Required *uint32 `protobuf:"varint,15,req,name=F_Uint32_required,json=FUint32Required" json:"F_Uint32_required,omitempty"` - F_Uint64Required *uint64 `protobuf:"varint,16,req,name=F_Uint64_required,json=FUint64Required" json:"F_Uint64_required,omitempty"` - F_FloatRequired *float32 `protobuf:"fixed32,17,req,name=F_Float_required,json=FFloatRequired" json:"F_Float_required,omitempty"` - F_DoubleRequired *float64 `protobuf:"fixed64,18,req,name=F_Double_required,json=FDoubleRequired" json:"F_Double_required,omitempty"` - F_StringRequired *string `protobuf:"bytes,19,req,name=F_String_required,json=FStringRequired" json:"F_String_required,omitempty"` - F_BytesRequired []byte `protobuf:"bytes,101,req,name=F_Bytes_required,json=FBytesRequired" json:"F_Bytes_required,omitempty"` - F_Sint32Required *int32 `protobuf:"zigzag32,102,req,name=F_Sint32_required,json=FSint32Required" json:"F_Sint32_required,omitempty"` - F_Sint64Required *int64 `protobuf:"zigzag64,103,req,name=F_Sint64_required,json=FSint64Required" json:"F_Sint64_required,omitempty"` - // Repeated fields of all basic types - F_BoolRepeated []bool `protobuf:"varint,20,rep,name=F_Bool_repeated,json=FBoolRepeated" json:"F_Bool_repeated,omitempty"` - F_Int32Repeated []int32 `protobuf:"varint,21,rep,name=F_Int32_repeated,json=FInt32Repeated" json:"F_Int32_repeated,omitempty"` - F_Int64Repeated []int64 `protobuf:"varint,22,rep,name=F_Int64_repeated,json=FInt64Repeated" json:"F_Int64_repeated,omitempty"` - F_Fixed32Repeated []uint32 `protobuf:"fixed32,23,rep,name=F_Fixed32_repeated,json=FFixed32Repeated" json:"F_Fixed32_repeated,omitempty"` - F_Fixed64Repeated []uint64 `protobuf:"fixed64,24,rep,name=F_Fixed64_repeated,json=FFixed64Repeated" json:"F_Fixed64_repeated,omitempty"` - F_Uint32Repeated []uint32 `protobuf:"varint,25,rep,name=F_Uint32_repeated,json=FUint32Repeated" json:"F_Uint32_repeated,omitempty"` - F_Uint64Repeated []uint64 `protobuf:"varint,26,rep,name=F_Uint64_repeated,json=FUint64Repeated" json:"F_Uint64_repeated,omitempty"` - F_FloatRepeated []float32 `protobuf:"fixed32,27,rep,name=F_Float_repeated,json=FFloatRepeated" json:"F_Float_repeated,omitempty"` - F_DoubleRepeated []float64 `protobuf:"fixed64,28,rep,name=F_Double_repeated,json=FDoubleRepeated" json:"F_Double_repeated,omitempty"` - F_StringRepeated []string `protobuf:"bytes,29,rep,name=F_String_repeated,json=FStringRepeated" json:"F_String_repeated,omitempty"` - F_BytesRepeated [][]byte `protobuf:"bytes,201,rep,name=F_Bytes_repeated,json=FBytesRepeated" json:"F_Bytes_repeated,omitempty"` - F_Sint32Repeated []int32 `protobuf:"zigzag32,202,rep,name=F_Sint32_repeated,json=FSint32Repeated" json:"F_Sint32_repeated,omitempty"` - F_Sint64Repeated []int64 `protobuf:"zigzag64,203,rep,name=F_Sint64_repeated,json=FSint64Repeated" json:"F_Sint64_repeated,omitempty"` - // Optional fields of all basic types - F_BoolOptional *bool `protobuf:"varint,30,opt,name=F_Bool_optional,json=FBoolOptional" json:"F_Bool_optional,omitempty"` - F_Int32Optional *int32 `protobuf:"varint,31,opt,name=F_Int32_optional,json=FInt32Optional" json:"F_Int32_optional,omitempty"` - F_Int64Optional *int64 `protobuf:"varint,32,opt,name=F_Int64_optional,json=FInt64Optional" json:"F_Int64_optional,omitempty"` - F_Fixed32Optional *uint32 `protobuf:"fixed32,33,opt,name=F_Fixed32_optional,json=FFixed32Optional" json:"F_Fixed32_optional,omitempty"` - F_Fixed64Optional *uint64 `protobuf:"fixed64,34,opt,name=F_Fixed64_optional,json=FFixed64Optional" json:"F_Fixed64_optional,omitempty"` - F_Uint32Optional *uint32 `protobuf:"varint,35,opt,name=F_Uint32_optional,json=FUint32Optional" json:"F_Uint32_optional,omitempty"` - F_Uint64Optional *uint64 `protobuf:"varint,36,opt,name=F_Uint64_optional,json=FUint64Optional" json:"F_Uint64_optional,omitempty"` - F_FloatOptional *float32 `protobuf:"fixed32,37,opt,name=F_Float_optional,json=FFloatOptional" json:"F_Float_optional,omitempty"` - F_DoubleOptional *float64 `protobuf:"fixed64,38,opt,name=F_Double_optional,json=FDoubleOptional" json:"F_Double_optional,omitempty"` - F_StringOptional *string `protobuf:"bytes,39,opt,name=F_String_optional,json=FStringOptional" json:"F_String_optional,omitempty"` - F_BytesOptional []byte `protobuf:"bytes,301,opt,name=F_Bytes_optional,json=FBytesOptional" json:"F_Bytes_optional,omitempty"` - F_Sint32Optional *int32 `protobuf:"zigzag32,302,opt,name=F_Sint32_optional,json=FSint32Optional" json:"F_Sint32_optional,omitempty"` - F_Sint64Optional *int64 `protobuf:"zigzag64,303,opt,name=F_Sint64_optional,json=FSint64Optional" json:"F_Sint64_optional,omitempty"` - // Default-valued fields of all basic types - F_BoolDefaulted *bool `protobuf:"varint,40,opt,name=F_Bool_defaulted,json=FBoolDefaulted,def=1" json:"F_Bool_defaulted,omitempty"` - F_Int32Defaulted *int32 `protobuf:"varint,41,opt,name=F_Int32_defaulted,json=FInt32Defaulted,def=32" json:"F_Int32_defaulted,omitempty"` - F_Int64Defaulted *int64 `protobuf:"varint,42,opt,name=F_Int64_defaulted,json=FInt64Defaulted,def=64" json:"F_Int64_defaulted,omitempty"` - F_Fixed32Defaulted *uint32 `protobuf:"fixed32,43,opt,name=F_Fixed32_defaulted,json=FFixed32Defaulted,def=320" json:"F_Fixed32_defaulted,omitempty"` - F_Fixed64Defaulted *uint64 `protobuf:"fixed64,44,opt,name=F_Fixed64_defaulted,json=FFixed64Defaulted,def=640" json:"F_Fixed64_defaulted,omitempty"` - F_Uint32Defaulted *uint32 `protobuf:"varint,45,opt,name=F_Uint32_defaulted,json=FUint32Defaulted,def=3200" json:"F_Uint32_defaulted,omitempty"` - F_Uint64Defaulted *uint64 `protobuf:"varint,46,opt,name=F_Uint64_defaulted,json=FUint64Defaulted,def=6400" json:"F_Uint64_defaulted,omitempty"` - F_FloatDefaulted *float32 `protobuf:"fixed32,47,opt,name=F_Float_defaulted,json=FFloatDefaulted,def=314159" json:"F_Float_defaulted,omitempty"` - F_DoubleDefaulted *float64 `protobuf:"fixed64,48,opt,name=F_Double_defaulted,json=FDoubleDefaulted,def=271828" json:"F_Double_defaulted,omitempty"` - F_StringDefaulted *string `protobuf:"bytes,49,opt,name=F_String_defaulted,json=FStringDefaulted,def=hello, \"world!\"\n" json:"F_String_defaulted,omitempty"` - F_BytesDefaulted []byte `protobuf:"bytes,401,opt,name=F_Bytes_defaulted,json=FBytesDefaulted,def=Bignose" json:"F_Bytes_defaulted,omitempty"` - F_Sint32Defaulted *int32 `protobuf:"zigzag32,402,opt,name=F_Sint32_defaulted,json=FSint32Defaulted,def=-32" json:"F_Sint32_defaulted,omitempty"` - F_Sint64Defaulted *int64 `protobuf:"zigzag64,403,opt,name=F_Sint64_defaulted,json=FSint64Defaulted,def=-64" json:"F_Sint64_defaulted,omitempty"` - // Packed repeated fields (no string or bytes). - F_BoolRepeatedPacked []bool `protobuf:"varint,50,rep,packed,name=F_Bool_repeated_packed,json=FBoolRepeatedPacked" json:"F_Bool_repeated_packed,omitempty"` - F_Int32RepeatedPacked []int32 `protobuf:"varint,51,rep,packed,name=F_Int32_repeated_packed,json=FInt32RepeatedPacked" json:"F_Int32_repeated_packed,omitempty"` - F_Int64RepeatedPacked []int64 `protobuf:"varint,52,rep,packed,name=F_Int64_repeated_packed,json=FInt64RepeatedPacked" json:"F_Int64_repeated_packed,omitempty"` - F_Fixed32RepeatedPacked []uint32 `protobuf:"fixed32,53,rep,packed,name=F_Fixed32_repeated_packed,json=FFixed32RepeatedPacked" json:"F_Fixed32_repeated_packed,omitempty"` - F_Fixed64RepeatedPacked []uint64 `protobuf:"fixed64,54,rep,packed,name=F_Fixed64_repeated_packed,json=FFixed64RepeatedPacked" json:"F_Fixed64_repeated_packed,omitempty"` - F_Uint32RepeatedPacked []uint32 `protobuf:"varint,55,rep,packed,name=F_Uint32_repeated_packed,json=FUint32RepeatedPacked" json:"F_Uint32_repeated_packed,omitempty"` - F_Uint64RepeatedPacked []uint64 `protobuf:"varint,56,rep,packed,name=F_Uint64_repeated_packed,json=FUint64RepeatedPacked" json:"F_Uint64_repeated_packed,omitempty"` - F_FloatRepeatedPacked []float32 `protobuf:"fixed32,57,rep,packed,name=F_Float_repeated_packed,json=FFloatRepeatedPacked" json:"F_Float_repeated_packed,omitempty"` - F_DoubleRepeatedPacked []float64 `protobuf:"fixed64,58,rep,packed,name=F_Double_repeated_packed,json=FDoubleRepeatedPacked" json:"F_Double_repeated_packed,omitempty"` - F_Sint32RepeatedPacked []int32 `protobuf:"zigzag32,502,rep,packed,name=F_Sint32_repeated_packed,json=FSint32RepeatedPacked" json:"F_Sint32_repeated_packed,omitempty"` - F_Sint64RepeatedPacked []int64 `protobuf:"zigzag64,503,rep,packed,name=F_Sint64_repeated_packed,json=FSint64RepeatedPacked" json:"F_Sint64_repeated_packed,omitempty"` - Requiredgroup *GoTest_RequiredGroup `protobuf:"group,70,req,name=RequiredGroup,json=requiredgroup" json:"requiredgroup,omitempty"` - Repeatedgroup []*GoTest_RepeatedGroup `protobuf:"group,80,rep,name=RepeatedGroup,json=repeatedgroup" json:"repeatedgroup,omitempty"` - Optionalgroup *GoTest_OptionalGroup `protobuf:"group,90,opt,name=OptionalGroup,json=optionalgroup" json:"optionalgroup,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTest) Reset() { *m = GoTest{} } -func (m *GoTest) String() string { return proto.CompactTextString(m) } -func (*GoTest) ProtoMessage() {} -func (*GoTest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -const Default_GoTest_F_BoolDefaulted bool = true -const Default_GoTest_F_Int32Defaulted int32 = 32 -const Default_GoTest_F_Int64Defaulted int64 = 64 -const Default_GoTest_F_Fixed32Defaulted uint32 = 320 -const Default_GoTest_F_Fixed64Defaulted uint64 = 640 -const Default_GoTest_F_Uint32Defaulted uint32 = 3200 -const Default_GoTest_F_Uint64Defaulted uint64 = 6400 -const Default_GoTest_F_FloatDefaulted float32 = 314159 -const Default_GoTest_F_DoubleDefaulted float64 = 271828 -const Default_GoTest_F_StringDefaulted string = "hello, \"world!\"\n" - -var Default_GoTest_F_BytesDefaulted []byte = []byte("Bignose") - -const Default_GoTest_F_Sint32Defaulted int32 = -32 -const Default_GoTest_F_Sint64Defaulted int64 = -64 - -func (m *GoTest) GetKind() GoTest_KIND { - if m != nil && m.Kind != nil { - return *m.Kind - } - return GoTest_VOID -} - -func (m *GoTest) GetTable() string { - if m != nil && m.Table != nil { - return *m.Table - } - return "" -} - -func (m *GoTest) GetParam() int32 { - if m != nil && m.Param != nil { - return *m.Param - } - return 0 -} - -func (m *GoTest) GetRequiredField() *GoTestField { - if m != nil { - return m.RequiredField - } - return nil -} - -func (m *GoTest) GetRepeatedField() []*GoTestField { - if m != nil { - return m.RepeatedField - } - return nil -} - -func (m *GoTest) GetOptionalField() *GoTestField { - if m != nil { - return m.OptionalField - } - return nil -} - -func (m *GoTest) GetF_BoolRequired() bool { - if m != nil && m.F_BoolRequired != nil { - return *m.F_BoolRequired - } - return false -} - -func (m *GoTest) GetF_Int32Required() int32 { - if m != nil && m.F_Int32Required != nil { - return *m.F_Int32Required - } - return 0 -} - -func (m *GoTest) GetF_Int64Required() int64 { - if m != nil && m.F_Int64Required != nil { - return *m.F_Int64Required - } - return 0 -} - -func (m *GoTest) GetF_Fixed32Required() uint32 { - if m != nil && m.F_Fixed32Required != nil { - return *m.F_Fixed32Required - } - return 0 -} - -func (m *GoTest) GetF_Fixed64Required() uint64 { - if m != nil && m.F_Fixed64Required != nil { - return *m.F_Fixed64Required - } - return 0 -} - -func (m *GoTest) GetF_Uint32Required() uint32 { - if m != nil && m.F_Uint32Required != nil { - return *m.F_Uint32Required - } - return 0 -} - -func (m *GoTest) GetF_Uint64Required() uint64 { - if m != nil && m.F_Uint64Required != nil { - return *m.F_Uint64Required - } - return 0 -} - -func (m *GoTest) GetF_FloatRequired() float32 { - if m != nil && m.F_FloatRequired != nil { - return *m.F_FloatRequired - } - return 0 -} - -func (m *GoTest) GetF_DoubleRequired() float64 { - if m != nil && m.F_DoubleRequired != nil { - return *m.F_DoubleRequired - } - return 0 -} - -func (m *GoTest) GetF_StringRequired() string { - if m != nil && m.F_StringRequired != nil { - return *m.F_StringRequired - } - return "" -} - -func (m *GoTest) GetF_BytesRequired() []byte { - if m != nil { - return m.F_BytesRequired - } - return nil -} - -func (m *GoTest) GetF_Sint32Required() int32 { - if m != nil && m.F_Sint32Required != nil { - return *m.F_Sint32Required - } - return 0 -} - -func (m *GoTest) GetF_Sint64Required() int64 { - if m != nil && m.F_Sint64Required != nil { - return *m.F_Sint64Required - } - return 0 -} - -func (m *GoTest) GetF_BoolRepeated() []bool { - if m != nil { - return m.F_BoolRepeated - } - return nil -} - -func (m *GoTest) GetF_Int32Repeated() []int32 { - if m != nil { - return m.F_Int32Repeated - } - return nil -} - -func (m *GoTest) GetF_Int64Repeated() []int64 { - if m != nil { - return m.F_Int64Repeated - } - return nil -} - -func (m *GoTest) GetF_Fixed32Repeated() []uint32 { - if m != nil { - return m.F_Fixed32Repeated - } - return nil -} - -func (m *GoTest) GetF_Fixed64Repeated() []uint64 { - if m != nil { - return m.F_Fixed64Repeated - } - return nil -} - -func (m *GoTest) GetF_Uint32Repeated() []uint32 { - if m != nil { - return m.F_Uint32Repeated - } - return nil -} - -func (m *GoTest) GetF_Uint64Repeated() []uint64 { - if m != nil { - return m.F_Uint64Repeated - } - return nil -} - -func (m *GoTest) GetF_FloatRepeated() []float32 { - if m != nil { - return m.F_FloatRepeated - } - return nil -} - -func (m *GoTest) GetF_DoubleRepeated() []float64 { - if m != nil { - return m.F_DoubleRepeated - } - return nil -} - -func (m *GoTest) GetF_StringRepeated() []string { - if m != nil { - return m.F_StringRepeated - } - return nil -} - -func (m *GoTest) GetF_BytesRepeated() [][]byte { - if m != nil { - return m.F_BytesRepeated - } - return nil -} - -func (m *GoTest) GetF_Sint32Repeated() []int32 { - if m != nil { - return m.F_Sint32Repeated - } - return nil -} - -func (m *GoTest) GetF_Sint64Repeated() []int64 { - if m != nil { - return m.F_Sint64Repeated - } - return nil -} - -func (m *GoTest) GetF_BoolOptional() bool { - if m != nil && m.F_BoolOptional != nil { - return *m.F_BoolOptional - } - return false -} - -func (m *GoTest) GetF_Int32Optional() int32 { - if m != nil && m.F_Int32Optional != nil { - return *m.F_Int32Optional - } - return 0 -} - -func (m *GoTest) GetF_Int64Optional() int64 { - if m != nil && m.F_Int64Optional != nil { - return *m.F_Int64Optional - } - return 0 -} - -func (m *GoTest) GetF_Fixed32Optional() uint32 { - if m != nil && m.F_Fixed32Optional != nil { - return *m.F_Fixed32Optional - } - return 0 -} - -func (m *GoTest) GetF_Fixed64Optional() uint64 { - if m != nil && m.F_Fixed64Optional != nil { - return *m.F_Fixed64Optional - } - return 0 -} - -func (m *GoTest) GetF_Uint32Optional() uint32 { - if m != nil && m.F_Uint32Optional != nil { - return *m.F_Uint32Optional - } - return 0 -} - -func (m *GoTest) GetF_Uint64Optional() uint64 { - if m != nil && m.F_Uint64Optional != nil { - return *m.F_Uint64Optional - } - return 0 -} - -func (m *GoTest) GetF_FloatOptional() float32 { - if m != nil && m.F_FloatOptional != nil { - return *m.F_FloatOptional - } - return 0 -} - -func (m *GoTest) GetF_DoubleOptional() float64 { - if m != nil && m.F_DoubleOptional != nil { - return *m.F_DoubleOptional - } - return 0 -} - -func (m *GoTest) GetF_StringOptional() string { - if m != nil && m.F_StringOptional != nil { - return *m.F_StringOptional - } - return "" -} - -func (m *GoTest) GetF_BytesOptional() []byte { - if m != nil { - return m.F_BytesOptional - } - return nil -} - -func (m *GoTest) GetF_Sint32Optional() int32 { - if m != nil && m.F_Sint32Optional != nil { - return *m.F_Sint32Optional - } - return 0 -} - -func (m *GoTest) GetF_Sint64Optional() int64 { - if m != nil && m.F_Sint64Optional != nil { - return *m.F_Sint64Optional - } - return 0 -} - -func (m *GoTest) GetF_BoolDefaulted() bool { - if m != nil && m.F_BoolDefaulted != nil { - return *m.F_BoolDefaulted - } - return Default_GoTest_F_BoolDefaulted -} - -func (m *GoTest) GetF_Int32Defaulted() int32 { - if m != nil && m.F_Int32Defaulted != nil { - return *m.F_Int32Defaulted - } - return Default_GoTest_F_Int32Defaulted -} - -func (m *GoTest) GetF_Int64Defaulted() int64 { - if m != nil && m.F_Int64Defaulted != nil { - return *m.F_Int64Defaulted - } - return Default_GoTest_F_Int64Defaulted -} - -func (m *GoTest) GetF_Fixed32Defaulted() uint32 { - if m != nil && m.F_Fixed32Defaulted != nil { - return *m.F_Fixed32Defaulted - } - return Default_GoTest_F_Fixed32Defaulted -} - -func (m *GoTest) GetF_Fixed64Defaulted() uint64 { - if m != nil && m.F_Fixed64Defaulted != nil { - return *m.F_Fixed64Defaulted - } - return Default_GoTest_F_Fixed64Defaulted -} - -func (m *GoTest) GetF_Uint32Defaulted() uint32 { - if m != nil && m.F_Uint32Defaulted != nil { - return *m.F_Uint32Defaulted - } - return Default_GoTest_F_Uint32Defaulted -} - -func (m *GoTest) GetF_Uint64Defaulted() uint64 { - if m != nil && m.F_Uint64Defaulted != nil { - return *m.F_Uint64Defaulted - } - return Default_GoTest_F_Uint64Defaulted -} - -func (m *GoTest) GetF_FloatDefaulted() float32 { - if m != nil && m.F_FloatDefaulted != nil { - return *m.F_FloatDefaulted - } - return Default_GoTest_F_FloatDefaulted -} - -func (m *GoTest) GetF_DoubleDefaulted() float64 { - if m != nil && m.F_DoubleDefaulted != nil { - return *m.F_DoubleDefaulted - } - return Default_GoTest_F_DoubleDefaulted -} - -func (m *GoTest) GetF_StringDefaulted() string { - if m != nil && m.F_StringDefaulted != nil { - return *m.F_StringDefaulted - } - return Default_GoTest_F_StringDefaulted -} - -func (m *GoTest) GetF_BytesDefaulted() []byte { - if m != nil && m.F_BytesDefaulted != nil { - return m.F_BytesDefaulted - } - return append([]byte(nil), Default_GoTest_F_BytesDefaulted...) -} - -func (m *GoTest) GetF_Sint32Defaulted() int32 { - if m != nil && m.F_Sint32Defaulted != nil { - return *m.F_Sint32Defaulted - } - return Default_GoTest_F_Sint32Defaulted -} - -func (m *GoTest) GetF_Sint64Defaulted() int64 { - if m != nil && m.F_Sint64Defaulted != nil { - return *m.F_Sint64Defaulted - } - return Default_GoTest_F_Sint64Defaulted -} - -func (m *GoTest) GetF_BoolRepeatedPacked() []bool { - if m != nil { - return m.F_BoolRepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Int32RepeatedPacked() []int32 { - if m != nil { - return m.F_Int32RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Int64RepeatedPacked() []int64 { - if m != nil { - return m.F_Int64RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Fixed32RepeatedPacked() []uint32 { - if m != nil { - return m.F_Fixed32RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Fixed64RepeatedPacked() []uint64 { - if m != nil { - return m.F_Fixed64RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Uint32RepeatedPacked() []uint32 { - if m != nil { - return m.F_Uint32RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Uint64RepeatedPacked() []uint64 { - if m != nil { - return m.F_Uint64RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_FloatRepeatedPacked() []float32 { - if m != nil { - return m.F_FloatRepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_DoubleRepeatedPacked() []float64 { - if m != nil { - return m.F_DoubleRepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Sint32RepeatedPacked() []int32 { - if m != nil { - return m.F_Sint32RepeatedPacked - } - return nil -} - -func (m *GoTest) GetF_Sint64RepeatedPacked() []int64 { - if m != nil { - return m.F_Sint64RepeatedPacked - } - return nil -} - -func (m *GoTest) GetRequiredgroup() *GoTest_RequiredGroup { - if m != nil { - return m.Requiredgroup - } - return nil -} - -func (m *GoTest) GetRepeatedgroup() []*GoTest_RepeatedGroup { - if m != nil { - return m.Repeatedgroup - } - return nil -} - -func (m *GoTest) GetOptionalgroup() *GoTest_OptionalGroup { - if m != nil { - return m.Optionalgroup - } - return nil -} - -// Required, repeated, and optional groups. -type GoTest_RequiredGroup struct { - RequiredField *string `protobuf:"bytes,71,req,name=RequiredField" json:"RequiredField,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTest_RequiredGroup) Reset() { *m = GoTest_RequiredGroup{} } -func (m *GoTest_RequiredGroup) String() string { return proto.CompactTextString(m) } -func (*GoTest_RequiredGroup) ProtoMessage() {} -func (*GoTest_RequiredGroup) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} } - -func (m *GoTest_RequiredGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" -} - -type GoTest_RepeatedGroup struct { - RequiredField *string `protobuf:"bytes,81,req,name=RequiredField" json:"RequiredField,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTest_RepeatedGroup) Reset() { *m = GoTest_RepeatedGroup{} } -func (m *GoTest_RepeatedGroup) String() string { return proto.CompactTextString(m) } -func (*GoTest_RepeatedGroup) ProtoMessage() {} -func (*GoTest_RepeatedGroup) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 1} } - -func (m *GoTest_RepeatedGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" -} - -type GoTest_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,91,req,name=RequiredField" json:"RequiredField,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTest_OptionalGroup) Reset() { *m = GoTest_OptionalGroup{} } -func (m *GoTest_OptionalGroup) String() string { return proto.CompactTextString(m) } -func (*GoTest_OptionalGroup) ProtoMessage() {} -func (*GoTest_OptionalGroup) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 2} } - -func (m *GoTest_OptionalGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" -} - -// For testing a group containing a required field. -type GoTestRequiredGroupField struct { - Group *GoTestRequiredGroupField_Group `protobuf:"group,1,req,name=Group,json=group" json:"group,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTestRequiredGroupField) Reset() { *m = GoTestRequiredGroupField{} } -func (m *GoTestRequiredGroupField) String() string { return proto.CompactTextString(m) } -func (*GoTestRequiredGroupField) ProtoMessage() {} -func (*GoTestRequiredGroupField) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func (m *GoTestRequiredGroupField) GetGroup() *GoTestRequiredGroupField_Group { - if m != nil { - return m.Group - } - return nil -} - -type GoTestRequiredGroupField_Group struct { - Field *int32 `protobuf:"varint,2,req,name=Field" json:"Field,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoTestRequiredGroupField_Group) Reset() { *m = GoTestRequiredGroupField_Group{} } -func (m *GoTestRequiredGroupField_Group) String() string { return proto.CompactTextString(m) } -func (*GoTestRequiredGroupField_Group) ProtoMessage() {} -func (*GoTestRequiredGroupField_Group) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{3, 0} -} - -func (m *GoTestRequiredGroupField_Group) GetField() int32 { - if m != nil && m.Field != nil { - return *m.Field - } - return 0 -} - -// For testing skipping of unrecognized fields. -// Numbers are all big, larger than tag numbers in GoTestField, -// the message used in the corresponding test. -type GoSkipTest struct { - SkipInt32 *int32 `protobuf:"varint,11,req,name=skip_int32,json=skipInt32" json:"skip_int32,omitempty"` - SkipFixed32 *uint32 `protobuf:"fixed32,12,req,name=skip_fixed32,json=skipFixed32" json:"skip_fixed32,omitempty"` - SkipFixed64 *uint64 `protobuf:"fixed64,13,req,name=skip_fixed64,json=skipFixed64" json:"skip_fixed64,omitempty"` - SkipString *string `protobuf:"bytes,14,req,name=skip_string,json=skipString" json:"skip_string,omitempty"` - Skipgroup *GoSkipTest_SkipGroup `protobuf:"group,15,req,name=SkipGroup,json=skipgroup" json:"skipgroup,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoSkipTest) Reset() { *m = GoSkipTest{} } -func (m *GoSkipTest) String() string { return proto.CompactTextString(m) } -func (*GoSkipTest) ProtoMessage() {} -func (*GoSkipTest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } - -func (m *GoSkipTest) GetSkipInt32() int32 { - if m != nil && m.SkipInt32 != nil { - return *m.SkipInt32 - } - return 0 -} - -func (m *GoSkipTest) GetSkipFixed32() uint32 { - if m != nil && m.SkipFixed32 != nil { - return *m.SkipFixed32 - } - return 0 -} - -func (m *GoSkipTest) GetSkipFixed64() uint64 { - if m != nil && m.SkipFixed64 != nil { - return *m.SkipFixed64 - } - return 0 -} - -func (m *GoSkipTest) GetSkipString() string { - if m != nil && m.SkipString != nil { - return *m.SkipString - } - return "" -} - -func (m *GoSkipTest) GetSkipgroup() *GoSkipTest_SkipGroup { - if m != nil { - return m.Skipgroup - } - return nil -} - -type GoSkipTest_SkipGroup struct { - GroupInt32 *int32 `protobuf:"varint,16,req,name=group_int32,json=groupInt32" json:"group_int32,omitempty"` - GroupString *string `protobuf:"bytes,17,req,name=group_string,json=groupString" json:"group_string,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GoSkipTest_SkipGroup) Reset() { *m = GoSkipTest_SkipGroup{} } -func (m *GoSkipTest_SkipGroup) String() string { return proto.CompactTextString(m) } -func (*GoSkipTest_SkipGroup) ProtoMessage() {} -func (*GoSkipTest_SkipGroup) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4, 0} } - -func (m *GoSkipTest_SkipGroup) GetGroupInt32() int32 { - if m != nil && m.GroupInt32 != nil { - return *m.GroupInt32 - } - return 0 -} - -func (m *GoSkipTest_SkipGroup) GetGroupString() string { - if m != nil && m.GroupString != nil { - return *m.GroupString - } - return "" -} - -// For testing packed/non-packed decoder switching. -// A serialized instance of one should be deserializable as the other. -type NonPackedTest struct { - A []int32 `protobuf:"varint,1,rep,name=a" json:"a,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *NonPackedTest) Reset() { *m = NonPackedTest{} } -func (m *NonPackedTest) String() string { return proto.CompactTextString(m) } -func (*NonPackedTest) ProtoMessage() {} -func (*NonPackedTest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } - -func (m *NonPackedTest) GetA() []int32 { - if m != nil { - return m.A - } - return nil -} - -type PackedTest struct { - B []int32 `protobuf:"varint,1,rep,packed,name=b" json:"b,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PackedTest) Reset() { *m = PackedTest{} } -func (m *PackedTest) String() string { return proto.CompactTextString(m) } -func (*PackedTest) ProtoMessage() {} -func (*PackedTest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } - -func (m *PackedTest) GetB() []int32 { - if m != nil { - return m.B - } - return nil -} - -type MaxTag struct { - // Maximum possible tag number. - LastField *string `protobuf:"bytes,536870911,opt,name=last_field,json=lastField" json:"last_field,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MaxTag) Reset() { *m = MaxTag{} } -func (m *MaxTag) String() string { return proto.CompactTextString(m) } -func (*MaxTag) ProtoMessage() {} -func (*MaxTag) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } - -func (m *MaxTag) GetLastField() string { - if m != nil && m.LastField != nil { - return *m.LastField - } - return "" -} - -type OldMessage struct { - Nested *OldMessage_Nested `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` - Num *int32 `protobuf:"varint,2,opt,name=num" json:"num,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *OldMessage) Reset() { *m = OldMessage{} } -func (m *OldMessage) String() string { return proto.CompactTextString(m) } -func (*OldMessage) ProtoMessage() {} -func (*OldMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } - -func (m *OldMessage) GetNested() *OldMessage_Nested { - if m != nil { - return m.Nested - } - return nil -} - -func (m *OldMessage) GetNum() int32 { - if m != nil && m.Num != nil { - return *m.Num - } - return 0 -} - -type OldMessage_Nested struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *OldMessage_Nested) Reset() { *m = OldMessage_Nested{} } -func (m *OldMessage_Nested) String() string { return proto.CompactTextString(m) } -func (*OldMessage_Nested) ProtoMessage() {} -func (*OldMessage_Nested) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8, 0} } - -func (m *OldMessage_Nested) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -// NewMessage is wire compatible with OldMessage; -// imagine it as a future version. -type NewMessage struct { - Nested *NewMessage_Nested `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` - // This is an int32 in OldMessage. - Num *int64 `protobuf:"varint,2,opt,name=num" json:"num,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *NewMessage) Reset() { *m = NewMessage{} } -func (m *NewMessage) String() string { return proto.CompactTextString(m) } -func (*NewMessage) ProtoMessage() {} -func (*NewMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } - -func (m *NewMessage) GetNested() *NewMessage_Nested { - if m != nil { - return m.Nested - } - return nil -} - -func (m *NewMessage) GetNum() int64 { - if m != nil && m.Num != nil { - return *m.Num - } - return 0 -} - -type NewMessage_Nested struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - FoodGroup *string `protobuf:"bytes,2,opt,name=food_group,json=foodGroup" json:"food_group,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *NewMessage_Nested) Reset() { *m = NewMessage_Nested{} } -func (m *NewMessage_Nested) String() string { return proto.CompactTextString(m) } -func (*NewMessage_Nested) ProtoMessage() {} -func (*NewMessage_Nested) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9, 0} } - -func (m *NewMessage_Nested) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *NewMessage_Nested) GetFoodGroup() string { - if m != nil && m.FoodGroup != nil { - return *m.FoodGroup - } - return "" -} - -type InnerMessage struct { - Host *string `protobuf:"bytes,1,req,name=host" json:"host,omitempty"` - Port *int32 `protobuf:"varint,2,opt,name=port,def=4000" json:"port,omitempty"` - Connected *bool `protobuf:"varint,3,opt,name=connected" json:"connected,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *InnerMessage) Reset() { *m = InnerMessage{} } -func (m *InnerMessage) String() string { return proto.CompactTextString(m) } -func (*InnerMessage) ProtoMessage() {} -func (*InnerMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } - -const Default_InnerMessage_Port int32 = 4000 - -func (m *InnerMessage) GetHost() string { - if m != nil && m.Host != nil { - return *m.Host - } - return "" -} - -func (m *InnerMessage) GetPort() int32 { - if m != nil && m.Port != nil { - return *m.Port - } - return Default_InnerMessage_Port -} - -func (m *InnerMessage) GetConnected() bool { - if m != nil && m.Connected != nil { - return *m.Connected - } - return false -} - -type OtherMessage struct { - Key *int64 `protobuf:"varint,1,opt,name=key" json:"key,omitempty"` - Value []byte `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` - Weight *float32 `protobuf:"fixed32,3,opt,name=weight" json:"weight,omitempty"` - Inner *InnerMessage `protobuf:"bytes,4,opt,name=inner" json:"inner,omitempty"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *OtherMessage) Reset() { *m = OtherMessage{} } -func (m *OtherMessage) String() string { return proto.CompactTextString(m) } -func (*OtherMessage) ProtoMessage() {} -func (*OtherMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } - -var extRange_OtherMessage = []proto.ExtensionRange{ - {100, 536870911}, -} - -func (*OtherMessage) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_OtherMessage -} - -func (m *OtherMessage) GetKey() int64 { - if m != nil && m.Key != nil { - return *m.Key - } - return 0 -} - -func (m *OtherMessage) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -func (m *OtherMessage) GetWeight() float32 { - if m != nil && m.Weight != nil { - return *m.Weight - } - return 0 -} - -func (m *OtherMessage) GetInner() *InnerMessage { - if m != nil { - return m.Inner - } - return nil -} - -type RequiredInnerMessage struct { - LeoFinallyWonAnOscar *InnerMessage `protobuf:"bytes,1,req,name=leo_finally_won_an_oscar,json=leoFinallyWonAnOscar" json:"leo_finally_won_an_oscar,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *RequiredInnerMessage) Reset() { *m = RequiredInnerMessage{} } -func (m *RequiredInnerMessage) String() string { return proto.CompactTextString(m) } -func (*RequiredInnerMessage) ProtoMessage() {} -func (*RequiredInnerMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } - -func (m *RequiredInnerMessage) GetLeoFinallyWonAnOscar() *InnerMessage { - if m != nil { - return m.LeoFinallyWonAnOscar - } - return nil -} - -type MyMessage struct { - Count *int32 `protobuf:"varint,1,req,name=count" json:"count,omitempty"` - Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - Quote *string `protobuf:"bytes,3,opt,name=quote" json:"quote,omitempty"` - Pet []string `protobuf:"bytes,4,rep,name=pet" json:"pet,omitempty"` - Inner *InnerMessage `protobuf:"bytes,5,opt,name=inner" json:"inner,omitempty"` - Others []*OtherMessage `protobuf:"bytes,6,rep,name=others" json:"others,omitempty"` - WeMustGoDeeper *RequiredInnerMessage `protobuf:"bytes,13,opt,name=we_must_go_deeper,json=weMustGoDeeper" json:"we_must_go_deeper,omitempty"` - RepInner []*InnerMessage `protobuf:"bytes,12,rep,name=rep_inner,json=repInner" json:"rep_inner,omitempty"` - Bikeshed *MyMessage_Color `protobuf:"varint,7,opt,name=bikeshed,enum=testdata.MyMessage_Color" json:"bikeshed,omitempty"` - Somegroup *MyMessage_SomeGroup `protobuf:"group,8,opt,name=SomeGroup,json=somegroup" json:"somegroup,omitempty"` - // This field becomes [][]byte in the generated code. - RepBytes [][]byte `protobuf:"bytes,10,rep,name=rep_bytes,json=repBytes" json:"rep_bytes,omitempty"` - Bigfloat *float64 `protobuf:"fixed64,11,opt,name=bigfloat" json:"bigfloat,omitempty"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MyMessage) Reset() { *m = MyMessage{} } -func (m *MyMessage) String() string { return proto.CompactTextString(m) } -func (*MyMessage) ProtoMessage() {} -func (*MyMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } - -var extRange_MyMessage = []proto.ExtensionRange{ - {100, 536870911}, -} - -func (*MyMessage) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_MyMessage -} - -func (m *MyMessage) GetCount() int32 { - if m != nil && m.Count != nil { - return *m.Count - } - return 0 -} - -func (m *MyMessage) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *MyMessage) GetQuote() string { - if m != nil && m.Quote != nil { - return *m.Quote - } - return "" -} - -func (m *MyMessage) GetPet() []string { - if m != nil { - return m.Pet - } - return nil -} - -func (m *MyMessage) GetInner() *InnerMessage { - if m != nil { - return m.Inner - } - return nil -} - -func (m *MyMessage) GetOthers() []*OtherMessage { - if m != nil { - return m.Others - } - return nil -} - -func (m *MyMessage) GetWeMustGoDeeper() *RequiredInnerMessage { - if m != nil { - return m.WeMustGoDeeper - } - return nil -} - -func (m *MyMessage) GetRepInner() []*InnerMessage { - if m != nil { - return m.RepInner - } - return nil -} - -func (m *MyMessage) GetBikeshed() MyMessage_Color { - if m != nil && m.Bikeshed != nil { - return *m.Bikeshed - } - return MyMessage_RED -} - -func (m *MyMessage) GetSomegroup() *MyMessage_SomeGroup { - if m != nil { - return m.Somegroup - } - return nil -} - -func (m *MyMessage) GetRepBytes() [][]byte { - if m != nil { - return m.RepBytes - } - return nil -} - -func (m *MyMessage) GetBigfloat() float64 { - if m != nil && m.Bigfloat != nil { - return *m.Bigfloat - } - return 0 -} - -type MyMessage_SomeGroup struct { - GroupField *int32 `protobuf:"varint,9,opt,name=group_field,json=groupField" json:"group_field,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MyMessage_SomeGroup) Reset() { *m = MyMessage_SomeGroup{} } -func (m *MyMessage_SomeGroup) String() string { return proto.CompactTextString(m) } -func (*MyMessage_SomeGroup) ProtoMessage() {} -func (*MyMessage_SomeGroup) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13, 0} } - -func (m *MyMessage_SomeGroup) GetGroupField() int32 { - if m != nil && m.GroupField != nil { - return *m.GroupField - } - return 0 -} - -type Ext struct { - Data *string `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Ext) Reset() { *m = Ext{} } -func (m *Ext) String() string { return proto.CompactTextString(m) } -func (*Ext) ProtoMessage() {} -func (*Ext) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } - -func (m *Ext) GetData() string { - if m != nil && m.Data != nil { - return *m.Data - } - return "" -} - -var E_Ext_More = &proto.ExtensionDesc{ - ExtendedType: (*MyMessage)(nil), - ExtensionType: (*Ext)(nil), - Field: 103, - Name: "testdata.Ext.more", - Tag: "bytes,103,opt,name=more", - Filename: "test.proto", -} - -var E_Ext_Text = &proto.ExtensionDesc{ - ExtendedType: (*MyMessage)(nil), - ExtensionType: (*string)(nil), - Field: 104, - Name: "testdata.Ext.text", - Tag: "bytes,104,opt,name=text", - Filename: "test.proto", -} - -var E_Ext_Number = &proto.ExtensionDesc{ - ExtendedType: (*MyMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 105, - Name: "testdata.Ext.number", - Tag: "varint,105,opt,name=number", - Filename: "test.proto", -} - -type ComplexExtension struct { - First *int32 `protobuf:"varint,1,opt,name=first" json:"first,omitempty"` - Second *int32 `protobuf:"varint,2,opt,name=second" json:"second,omitempty"` - Third []int32 `protobuf:"varint,3,rep,name=third" json:"third,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ComplexExtension) Reset() { *m = ComplexExtension{} } -func (m *ComplexExtension) String() string { return proto.CompactTextString(m) } -func (*ComplexExtension) ProtoMessage() {} -func (*ComplexExtension) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } - -func (m *ComplexExtension) GetFirst() int32 { - if m != nil && m.First != nil { - return *m.First - } - return 0 -} - -func (m *ComplexExtension) GetSecond() int32 { - if m != nil && m.Second != nil { - return *m.Second - } - return 0 -} - -func (m *ComplexExtension) GetThird() []int32 { - if m != nil { - return m.Third - } - return nil -} - -type DefaultsMessage struct { - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DefaultsMessage) Reset() { *m = DefaultsMessage{} } -func (m *DefaultsMessage) String() string { return proto.CompactTextString(m) } -func (*DefaultsMessage) ProtoMessage() {} -func (*DefaultsMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } - -var extRange_DefaultsMessage = []proto.ExtensionRange{ - {100, 536870911}, -} - -func (*DefaultsMessage) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_DefaultsMessage -} - -type MyMessageSet struct { - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MyMessageSet) Reset() { *m = MyMessageSet{} } -func (m *MyMessageSet) String() string { return proto.CompactTextString(m) } -func (*MyMessageSet) ProtoMessage() {} -func (*MyMessageSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } - -func (m *MyMessageSet) Marshal() ([]byte, error) { - return proto.MarshalMessageSet(&m.XXX_InternalExtensions) -} -func (m *MyMessageSet) Unmarshal(buf []byte) error { - return proto.UnmarshalMessageSet(buf, &m.XXX_InternalExtensions) -} -func (m *MyMessageSet) MarshalJSON() ([]byte, error) { - return proto.MarshalMessageSetJSON(&m.XXX_InternalExtensions) -} -func (m *MyMessageSet) UnmarshalJSON(buf []byte) error { - return proto.UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions) -} - -// ensure MyMessageSet satisfies proto.Marshaler and proto.Unmarshaler -var _ proto.Marshaler = (*MyMessageSet)(nil) -var _ proto.Unmarshaler = (*MyMessageSet)(nil) - -var extRange_MyMessageSet = []proto.ExtensionRange{ - {100, 2147483646}, -} - -func (*MyMessageSet) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_MyMessageSet -} - -type Empty struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *Empty) Reset() { *m = Empty{} } -func (m *Empty) String() string { return proto.CompactTextString(m) } -func (*Empty) ProtoMessage() {} -func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } - -type MessageList struct { - Message []*MessageList_Message `protobuf:"group,1,rep,name=Message,json=message" json:"message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MessageList) Reset() { *m = MessageList{} } -func (m *MessageList) String() string { return proto.CompactTextString(m) } -func (*MessageList) ProtoMessage() {} -func (*MessageList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } - -func (m *MessageList) GetMessage() []*MessageList_Message { - if m != nil { - return m.Message - } - return nil -} - -type MessageList_Message struct { - Name *string `protobuf:"bytes,2,req,name=name" json:"name,omitempty"` - Count *int32 `protobuf:"varint,3,req,name=count" json:"count,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MessageList_Message) Reset() { *m = MessageList_Message{} } -func (m *MessageList_Message) String() string { return proto.CompactTextString(m) } -func (*MessageList_Message) ProtoMessage() {} -func (*MessageList_Message) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19, 0} } - -func (m *MessageList_Message) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *MessageList_Message) GetCount() int32 { - if m != nil && m.Count != nil { - return *m.Count - } - return 0 -} - -type Strings struct { - StringField *string `protobuf:"bytes,1,opt,name=string_field,json=stringField" json:"string_field,omitempty"` - BytesField []byte `protobuf:"bytes,2,opt,name=bytes_field,json=bytesField" json:"bytes_field,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Strings) Reset() { *m = Strings{} } -func (m *Strings) String() string { return proto.CompactTextString(m) } -func (*Strings) ProtoMessage() {} -func (*Strings) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } - -func (m *Strings) GetStringField() string { - if m != nil && m.StringField != nil { - return *m.StringField - } - return "" -} - -func (m *Strings) GetBytesField() []byte { - if m != nil { - return m.BytesField - } - return nil -} - -type Defaults struct { - // Default-valued fields of all basic types. - // Same as GoTest, but copied here to make testing easier. - F_Bool *bool `protobuf:"varint,1,opt,name=F_Bool,json=FBool,def=1" json:"F_Bool,omitempty"` - F_Int32 *int32 `protobuf:"varint,2,opt,name=F_Int32,json=FInt32,def=32" json:"F_Int32,omitempty"` - F_Int64 *int64 `protobuf:"varint,3,opt,name=F_Int64,json=FInt64,def=64" json:"F_Int64,omitempty"` - F_Fixed32 *uint32 `protobuf:"fixed32,4,opt,name=F_Fixed32,json=FFixed32,def=320" json:"F_Fixed32,omitempty"` - F_Fixed64 *uint64 `protobuf:"fixed64,5,opt,name=F_Fixed64,json=FFixed64,def=640" json:"F_Fixed64,omitempty"` - F_Uint32 *uint32 `protobuf:"varint,6,opt,name=F_Uint32,json=FUint32,def=3200" json:"F_Uint32,omitempty"` - F_Uint64 *uint64 `protobuf:"varint,7,opt,name=F_Uint64,json=FUint64,def=6400" json:"F_Uint64,omitempty"` - F_Float *float32 `protobuf:"fixed32,8,opt,name=F_Float,json=FFloat,def=314159" json:"F_Float,omitempty"` - F_Double *float64 `protobuf:"fixed64,9,opt,name=F_Double,json=FDouble,def=271828" json:"F_Double,omitempty"` - F_String *string `protobuf:"bytes,10,opt,name=F_String,json=FString,def=hello, \"world!\"\n" json:"F_String,omitempty"` - F_Bytes []byte `protobuf:"bytes,11,opt,name=F_Bytes,json=FBytes,def=Bignose" json:"F_Bytes,omitempty"` - F_Sint32 *int32 `protobuf:"zigzag32,12,opt,name=F_Sint32,json=FSint32,def=-32" json:"F_Sint32,omitempty"` - F_Sint64 *int64 `protobuf:"zigzag64,13,opt,name=F_Sint64,json=FSint64,def=-64" json:"F_Sint64,omitempty"` - F_Enum *Defaults_Color `protobuf:"varint,14,opt,name=F_Enum,json=FEnum,enum=testdata.Defaults_Color,def=1" json:"F_Enum,omitempty"` - // More fields with crazy defaults. - F_Pinf *float32 `protobuf:"fixed32,15,opt,name=F_Pinf,json=FPinf,def=inf" json:"F_Pinf,omitempty"` - F_Ninf *float32 `protobuf:"fixed32,16,opt,name=F_Ninf,json=FNinf,def=-inf" json:"F_Ninf,omitempty"` - F_Nan *float32 `protobuf:"fixed32,17,opt,name=F_Nan,json=FNan,def=nan" json:"F_Nan,omitempty"` - // Sub-message. - Sub *SubDefaults `protobuf:"bytes,18,opt,name=sub" json:"sub,omitempty"` - // Redundant but explicit defaults. - StrZero *string `protobuf:"bytes,19,opt,name=str_zero,json=strZero,def=" json:"str_zero,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Defaults) Reset() { *m = Defaults{} } -func (m *Defaults) String() string { return proto.CompactTextString(m) } -func (*Defaults) ProtoMessage() {} -func (*Defaults) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } - -const Default_Defaults_F_Bool bool = true -const Default_Defaults_F_Int32 int32 = 32 -const Default_Defaults_F_Int64 int64 = 64 -const Default_Defaults_F_Fixed32 uint32 = 320 -const Default_Defaults_F_Fixed64 uint64 = 640 -const Default_Defaults_F_Uint32 uint32 = 3200 -const Default_Defaults_F_Uint64 uint64 = 6400 -const Default_Defaults_F_Float float32 = 314159 -const Default_Defaults_F_Double float64 = 271828 -const Default_Defaults_F_String string = "hello, \"world!\"\n" - -var Default_Defaults_F_Bytes []byte = []byte("Bignose") - -const Default_Defaults_F_Sint32 int32 = -32 -const Default_Defaults_F_Sint64 int64 = -64 -const Default_Defaults_F_Enum Defaults_Color = Defaults_GREEN - -var Default_Defaults_F_Pinf float32 = float32(math.Inf(1)) -var Default_Defaults_F_Ninf float32 = float32(math.Inf(-1)) -var Default_Defaults_F_Nan float32 = float32(math.NaN()) - -func (m *Defaults) GetF_Bool() bool { - if m != nil && m.F_Bool != nil { - return *m.F_Bool - } - return Default_Defaults_F_Bool -} - -func (m *Defaults) GetF_Int32() int32 { - if m != nil && m.F_Int32 != nil { - return *m.F_Int32 - } - return Default_Defaults_F_Int32 -} - -func (m *Defaults) GetF_Int64() int64 { - if m != nil && m.F_Int64 != nil { - return *m.F_Int64 - } - return Default_Defaults_F_Int64 -} - -func (m *Defaults) GetF_Fixed32() uint32 { - if m != nil && m.F_Fixed32 != nil { - return *m.F_Fixed32 - } - return Default_Defaults_F_Fixed32 -} - -func (m *Defaults) GetF_Fixed64() uint64 { - if m != nil && m.F_Fixed64 != nil { - return *m.F_Fixed64 - } - return Default_Defaults_F_Fixed64 -} - -func (m *Defaults) GetF_Uint32() uint32 { - if m != nil && m.F_Uint32 != nil { - return *m.F_Uint32 - } - return Default_Defaults_F_Uint32 -} - -func (m *Defaults) GetF_Uint64() uint64 { - if m != nil && m.F_Uint64 != nil { - return *m.F_Uint64 - } - return Default_Defaults_F_Uint64 -} - -func (m *Defaults) GetF_Float() float32 { - if m != nil && m.F_Float != nil { - return *m.F_Float - } - return Default_Defaults_F_Float -} - -func (m *Defaults) GetF_Double() float64 { - if m != nil && m.F_Double != nil { - return *m.F_Double - } - return Default_Defaults_F_Double -} - -func (m *Defaults) GetF_String() string { - if m != nil && m.F_String != nil { - return *m.F_String - } - return Default_Defaults_F_String -} - -func (m *Defaults) GetF_Bytes() []byte { - if m != nil && m.F_Bytes != nil { - return m.F_Bytes - } - return append([]byte(nil), Default_Defaults_F_Bytes...) -} - -func (m *Defaults) GetF_Sint32() int32 { - if m != nil && m.F_Sint32 != nil { - return *m.F_Sint32 - } - return Default_Defaults_F_Sint32 -} - -func (m *Defaults) GetF_Sint64() int64 { - if m != nil && m.F_Sint64 != nil { - return *m.F_Sint64 - } - return Default_Defaults_F_Sint64 -} - -func (m *Defaults) GetF_Enum() Defaults_Color { - if m != nil && m.F_Enum != nil { - return *m.F_Enum - } - return Default_Defaults_F_Enum -} - -func (m *Defaults) GetF_Pinf() float32 { - if m != nil && m.F_Pinf != nil { - return *m.F_Pinf - } - return Default_Defaults_F_Pinf -} - -func (m *Defaults) GetF_Ninf() float32 { - if m != nil && m.F_Ninf != nil { - return *m.F_Ninf - } - return Default_Defaults_F_Ninf -} - -func (m *Defaults) GetF_Nan() float32 { - if m != nil && m.F_Nan != nil { - return *m.F_Nan - } - return Default_Defaults_F_Nan -} - -func (m *Defaults) GetSub() *SubDefaults { - if m != nil { - return m.Sub - } - return nil -} - -func (m *Defaults) GetStrZero() string { - if m != nil && m.StrZero != nil { - return *m.StrZero - } - return "" -} - -type SubDefaults struct { - N *int64 `protobuf:"varint,1,opt,name=n,def=7" json:"n,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SubDefaults) Reset() { *m = SubDefaults{} } -func (m *SubDefaults) String() string { return proto.CompactTextString(m) } -func (*SubDefaults) ProtoMessage() {} -func (*SubDefaults) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } - -const Default_SubDefaults_N int64 = 7 - -func (m *SubDefaults) GetN() int64 { - if m != nil && m.N != nil { - return *m.N - } - return Default_SubDefaults_N -} - -type RepeatedEnum struct { - Color []RepeatedEnum_Color `protobuf:"varint,1,rep,name=color,enum=testdata.RepeatedEnum_Color" json:"color,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *RepeatedEnum) Reset() { *m = RepeatedEnum{} } -func (m *RepeatedEnum) String() string { return proto.CompactTextString(m) } -func (*RepeatedEnum) ProtoMessage() {} -func (*RepeatedEnum) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } - -func (m *RepeatedEnum) GetColor() []RepeatedEnum_Color { - if m != nil { - return m.Color - } - return nil -} - -type MoreRepeated struct { - Bools []bool `protobuf:"varint,1,rep,name=bools" json:"bools,omitempty"` - BoolsPacked []bool `protobuf:"varint,2,rep,packed,name=bools_packed,json=boolsPacked" json:"bools_packed,omitempty"` - Ints []int32 `protobuf:"varint,3,rep,name=ints" json:"ints,omitempty"` - IntsPacked []int32 `protobuf:"varint,4,rep,packed,name=ints_packed,json=intsPacked" json:"ints_packed,omitempty"` - Int64SPacked []int64 `protobuf:"varint,7,rep,packed,name=int64s_packed,json=int64sPacked" json:"int64s_packed,omitempty"` - Strings []string `protobuf:"bytes,5,rep,name=strings" json:"strings,omitempty"` - Fixeds []uint32 `protobuf:"fixed32,6,rep,name=fixeds" json:"fixeds,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MoreRepeated) Reset() { *m = MoreRepeated{} } -func (m *MoreRepeated) String() string { return proto.CompactTextString(m) } -func (*MoreRepeated) ProtoMessage() {} -func (*MoreRepeated) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } - -func (m *MoreRepeated) GetBools() []bool { - if m != nil { - return m.Bools - } - return nil -} - -func (m *MoreRepeated) GetBoolsPacked() []bool { - if m != nil { - return m.BoolsPacked - } - return nil -} - -func (m *MoreRepeated) GetInts() []int32 { - if m != nil { - return m.Ints - } - return nil -} - -func (m *MoreRepeated) GetIntsPacked() []int32 { - if m != nil { - return m.IntsPacked - } - return nil -} - -func (m *MoreRepeated) GetInt64SPacked() []int64 { - if m != nil { - return m.Int64SPacked - } - return nil -} - -func (m *MoreRepeated) GetStrings() []string { - if m != nil { - return m.Strings - } - return nil -} - -func (m *MoreRepeated) GetFixeds() []uint32 { - if m != nil { - return m.Fixeds - } - return nil -} - -type GroupOld struct { - G *GroupOld_G `protobuf:"group,101,opt,name=G,json=g" json:"g,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GroupOld) Reset() { *m = GroupOld{} } -func (m *GroupOld) String() string { return proto.CompactTextString(m) } -func (*GroupOld) ProtoMessage() {} -func (*GroupOld) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } - -func (m *GroupOld) GetG() *GroupOld_G { - if m != nil { - return m.G - } - return nil -} - -type GroupOld_G struct { - X *int32 `protobuf:"varint,2,opt,name=x" json:"x,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GroupOld_G) Reset() { *m = GroupOld_G{} } -func (m *GroupOld_G) String() string { return proto.CompactTextString(m) } -func (*GroupOld_G) ProtoMessage() {} -func (*GroupOld_G) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25, 0} } - -func (m *GroupOld_G) GetX() int32 { - if m != nil && m.X != nil { - return *m.X - } - return 0 -} - -type GroupNew struct { - G *GroupNew_G `protobuf:"group,101,opt,name=G,json=g" json:"g,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GroupNew) Reset() { *m = GroupNew{} } -func (m *GroupNew) String() string { return proto.CompactTextString(m) } -func (*GroupNew) ProtoMessage() {} -func (*GroupNew) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } - -func (m *GroupNew) GetG() *GroupNew_G { - if m != nil { - return m.G - } - return nil -} - -type GroupNew_G struct { - X *int32 `protobuf:"varint,2,opt,name=x" json:"x,omitempty"` - Y *int32 `protobuf:"varint,3,opt,name=y" json:"y,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GroupNew_G) Reset() { *m = GroupNew_G{} } -func (m *GroupNew_G) String() string { return proto.CompactTextString(m) } -func (*GroupNew_G) ProtoMessage() {} -func (*GroupNew_G) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26, 0} } - -func (m *GroupNew_G) GetX() int32 { - if m != nil && m.X != nil { - return *m.X - } - return 0 -} - -func (m *GroupNew_G) GetY() int32 { - if m != nil && m.Y != nil { - return *m.Y - } - return 0 -} - -type FloatingPoint struct { - F *float64 `protobuf:"fixed64,1,req,name=f" json:"f,omitempty"` - Exact *bool `protobuf:"varint,2,opt,name=exact" json:"exact,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *FloatingPoint) Reset() { *m = FloatingPoint{} } -func (m *FloatingPoint) String() string { return proto.CompactTextString(m) } -func (*FloatingPoint) ProtoMessage() {} -func (*FloatingPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } - -func (m *FloatingPoint) GetF() float64 { - if m != nil && m.F != nil { - return *m.F - } - return 0 -} - -func (m *FloatingPoint) GetExact() bool { - if m != nil && m.Exact != nil { - return *m.Exact - } - return false -} - -type MessageWithMap struct { - NameMapping map[int32]string `protobuf:"bytes,1,rep,name=name_mapping,json=nameMapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - MsgMapping map[int64]*FloatingPoint `protobuf:"bytes,2,rep,name=msg_mapping,json=msgMapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - ByteMapping map[bool][]byte `protobuf:"bytes,3,rep,name=byte_mapping,json=byteMapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - StrToStr map[string]string `protobuf:"bytes,4,rep,name=str_to_str,json=strToStr" json:"str_to_str,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MessageWithMap) Reset() { *m = MessageWithMap{} } -func (m *MessageWithMap) String() string { return proto.CompactTextString(m) } -func (*MessageWithMap) ProtoMessage() {} -func (*MessageWithMap) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } - -func (m *MessageWithMap) GetNameMapping() map[int32]string { - if m != nil { - return m.NameMapping - } - return nil -} - -func (m *MessageWithMap) GetMsgMapping() map[int64]*FloatingPoint { - if m != nil { - return m.MsgMapping - } - return nil -} - -func (m *MessageWithMap) GetByteMapping() map[bool][]byte { - if m != nil { - return m.ByteMapping - } - return nil -} - -func (m *MessageWithMap) GetStrToStr() map[string]string { - if m != nil { - return m.StrToStr - } - return nil -} - -type Oneof struct { - // Types that are valid to be assigned to Union: - // *Oneof_F_Bool - // *Oneof_F_Int32 - // *Oneof_F_Int64 - // *Oneof_F_Fixed32 - // *Oneof_F_Fixed64 - // *Oneof_F_Uint32 - // *Oneof_F_Uint64 - // *Oneof_F_Float - // *Oneof_F_Double - // *Oneof_F_String - // *Oneof_F_Bytes - // *Oneof_F_Sint32 - // *Oneof_F_Sint64 - // *Oneof_F_Enum - // *Oneof_F_Message - // *Oneof_FGroup - // *Oneof_F_Largest_Tag - Union isOneof_Union `protobuf_oneof:"union"` - // Types that are valid to be assigned to Tormato: - // *Oneof_Value - Tormato isOneof_Tormato `protobuf_oneof:"tormato"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Oneof) Reset() { *m = Oneof{} } -func (m *Oneof) String() string { return proto.CompactTextString(m) } -func (*Oneof) ProtoMessage() {} -func (*Oneof) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } - -type isOneof_Union interface { - isOneof_Union() -} -type isOneof_Tormato interface { - isOneof_Tormato() -} - -type Oneof_F_Bool struct { - F_Bool bool `protobuf:"varint,1,opt,name=F_Bool,json=FBool,oneof"` -} -type Oneof_F_Int32 struct { - F_Int32 int32 `protobuf:"varint,2,opt,name=F_Int32,json=FInt32,oneof"` -} -type Oneof_F_Int64 struct { - F_Int64 int64 `protobuf:"varint,3,opt,name=F_Int64,json=FInt64,oneof"` -} -type Oneof_F_Fixed32 struct { - F_Fixed32 uint32 `protobuf:"fixed32,4,opt,name=F_Fixed32,json=FFixed32,oneof"` -} -type Oneof_F_Fixed64 struct { - F_Fixed64 uint64 `protobuf:"fixed64,5,opt,name=F_Fixed64,json=FFixed64,oneof"` -} -type Oneof_F_Uint32 struct { - F_Uint32 uint32 `protobuf:"varint,6,opt,name=F_Uint32,json=FUint32,oneof"` -} -type Oneof_F_Uint64 struct { - F_Uint64 uint64 `protobuf:"varint,7,opt,name=F_Uint64,json=FUint64,oneof"` -} -type Oneof_F_Float struct { - F_Float float32 `protobuf:"fixed32,8,opt,name=F_Float,json=FFloat,oneof"` -} -type Oneof_F_Double struct { - F_Double float64 `protobuf:"fixed64,9,opt,name=F_Double,json=FDouble,oneof"` -} -type Oneof_F_String struct { - F_String string `protobuf:"bytes,10,opt,name=F_String,json=FString,oneof"` -} -type Oneof_F_Bytes struct { - F_Bytes []byte `protobuf:"bytes,11,opt,name=F_Bytes,json=FBytes,oneof"` -} -type Oneof_F_Sint32 struct { - F_Sint32 int32 `protobuf:"zigzag32,12,opt,name=F_Sint32,json=FSint32,oneof"` -} -type Oneof_F_Sint64 struct { - F_Sint64 int64 `protobuf:"zigzag64,13,opt,name=F_Sint64,json=FSint64,oneof"` -} -type Oneof_F_Enum struct { - F_Enum MyMessage_Color `protobuf:"varint,14,opt,name=F_Enum,json=FEnum,enum=testdata.MyMessage_Color,oneof"` -} -type Oneof_F_Message struct { - F_Message *GoTestField `protobuf:"bytes,15,opt,name=F_Message,json=FMessage,oneof"` -} -type Oneof_FGroup struct { - FGroup *Oneof_F_Group `protobuf:"group,16,opt,name=F_Group,json=fGroup,oneof"` -} -type Oneof_F_Largest_Tag struct { - F_Largest_Tag int32 `protobuf:"varint,536870911,opt,name=F_Largest_Tag,json=FLargestTag,oneof"` -} -type Oneof_Value struct { - Value int32 `protobuf:"varint,100,opt,name=value,oneof"` -} - -func (*Oneof_F_Bool) isOneof_Union() {} -func (*Oneof_F_Int32) isOneof_Union() {} -func (*Oneof_F_Int64) isOneof_Union() {} -func (*Oneof_F_Fixed32) isOneof_Union() {} -func (*Oneof_F_Fixed64) isOneof_Union() {} -func (*Oneof_F_Uint32) isOneof_Union() {} -func (*Oneof_F_Uint64) isOneof_Union() {} -func (*Oneof_F_Float) isOneof_Union() {} -func (*Oneof_F_Double) isOneof_Union() {} -func (*Oneof_F_String) isOneof_Union() {} -func (*Oneof_F_Bytes) isOneof_Union() {} -func (*Oneof_F_Sint32) isOneof_Union() {} -func (*Oneof_F_Sint64) isOneof_Union() {} -func (*Oneof_F_Enum) isOneof_Union() {} -func (*Oneof_F_Message) isOneof_Union() {} -func (*Oneof_FGroup) isOneof_Union() {} -func (*Oneof_F_Largest_Tag) isOneof_Union() {} -func (*Oneof_Value) isOneof_Tormato() {} - -func (m *Oneof) GetUnion() isOneof_Union { - if m != nil { - return m.Union - } - return nil -} -func (m *Oneof) GetTormato() isOneof_Tormato { - if m != nil { - return m.Tormato - } - return nil -} - -func (m *Oneof) GetF_Bool() bool { - if x, ok := m.GetUnion().(*Oneof_F_Bool); ok { - return x.F_Bool - } - return false -} - -func (m *Oneof) GetF_Int32() int32 { - if x, ok := m.GetUnion().(*Oneof_F_Int32); ok { - return x.F_Int32 - } - return 0 -} - -func (m *Oneof) GetF_Int64() int64 { - if x, ok := m.GetUnion().(*Oneof_F_Int64); ok { - return x.F_Int64 - } - return 0 -} - -func (m *Oneof) GetF_Fixed32() uint32 { - if x, ok := m.GetUnion().(*Oneof_F_Fixed32); ok { - return x.F_Fixed32 - } - return 0 -} - -func (m *Oneof) GetF_Fixed64() uint64 { - if x, ok := m.GetUnion().(*Oneof_F_Fixed64); ok { - return x.F_Fixed64 - } - return 0 -} - -func (m *Oneof) GetF_Uint32() uint32 { - if x, ok := m.GetUnion().(*Oneof_F_Uint32); ok { - return x.F_Uint32 - } - return 0 -} - -func (m *Oneof) GetF_Uint64() uint64 { - if x, ok := m.GetUnion().(*Oneof_F_Uint64); ok { - return x.F_Uint64 - } - return 0 -} - -func (m *Oneof) GetF_Float() float32 { - if x, ok := m.GetUnion().(*Oneof_F_Float); ok { - return x.F_Float - } - return 0 -} - -func (m *Oneof) GetF_Double() float64 { - if x, ok := m.GetUnion().(*Oneof_F_Double); ok { - return x.F_Double - } - return 0 -} - -func (m *Oneof) GetF_String() string { - if x, ok := m.GetUnion().(*Oneof_F_String); ok { - return x.F_String - } - return "" -} - -func (m *Oneof) GetF_Bytes() []byte { - if x, ok := m.GetUnion().(*Oneof_F_Bytes); ok { - return x.F_Bytes - } - return nil -} - -func (m *Oneof) GetF_Sint32() int32 { - if x, ok := m.GetUnion().(*Oneof_F_Sint32); ok { - return x.F_Sint32 - } - return 0 -} - -func (m *Oneof) GetF_Sint64() int64 { - if x, ok := m.GetUnion().(*Oneof_F_Sint64); ok { - return x.F_Sint64 - } - return 0 -} - -func (m *Oneof) GetF_Enum() MyMessage_Color { - if x, ok := m.GetUnion().(*Oneof_F_Enum); ok { - return x.F_Enum - } - return MyMessage_RED -} - -func (m *Oneof) GetF_Message() *GoTestField { - if x, ok := m.GetUnion().(*Oneof_F_Message); ok { - return x.F_Message - } - return nil -} - -func (m *Oneof) GetFGroup() *Oneof_F_Group { - if x, ok := m.GetUnion().(*Oneof_FGroup); ok { - return x.FGroup - } - return nil -} - -func (m *Oneof) GetF_Largest_Tag() int32 { - if x, ok := m.GetUnion().(*Oneof_F_Largest_Tag); ok { - return x.F_Largest_Tag - } - return 0 -} - -func (m *Oneof) GetValue() int32 { - if x, ok := m.GetTormato().(*Oneof_Value); ok { - return x.Value - } - return 0 -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*Oneof) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _Oneof_OneofMarshaler, _Oneof_OneofUnmarshaler, _Oneof_OneofSizer, []interface{}{ - (*Oneof_F_Bool)(nil), - (*Oneof_F_Int32)(nil), - (*Oneof_F_Int64)(nil), - (*Oneof_F_Fixed32)(nil), - (*Oneof_F_Fixed64)(nil), - (*Oneof_F_Uint32)(nil), - (*Oneof_F_Uint64)(nil), - (*Oneof_F_Float)(nil), - (*Oneof_F_Double)(nil), - (*Oneof_F_String)(nil), - (*Oneof_F_Bytes)(nil), - (*Oneof_F_Sint32)(nil), - (*Oneof_F_Sint64)(nil), - (*Oneof_F_Enum)(nil), - (*Oneof_F_Message)(nil), - (*Oneof_FGroup)(nil), - (*Oneof_F_Largest_Tag)(nil), - (*Oneof_Value)(nil), - } -} - -func _Oneof_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*Oneof) - // union - switch x := m.Union.(type) { - case *Oneof_F_Bool: - t := uint64(0) - if x.F_Bool { - t = 1 - } - b.EncodeVarint(1<<3 | proto.WireVarint) - b.EncodeVarint(t) - case *Oneof_F_Int32: - b.EncodeVarint(2<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.F_Int32)) - case *Oneof_F_Int64: - b.EncodeVarint(3<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.F_Int64)) - case *Oneof_F_Fixed32: - b.EncodeVarint(4<<3 | proto.WireFixed32) - b.EncodeFixed32(uint64(x.F_Fixed32)) - case *Oneof_F_Fixed64: - b.EncodeVarint(5<<3 | proto.WireFixed64) - b.EncodeFixed64(uint64(x.F_Fixed64)) - case *Oneof_F_Uint32: - b.EncodeVarint(6<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.F_Uint32)) - case *Oneof_F_Uint64: - b.EncodeVarint(7<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.F_Uint64)) - case *Oneof_F_Float: - b.EncodeVarint(8<<3 | proto.WireFixed32) - b.EncodeFixed32(uint64(math.Float32bits(x.F_Float))) - case *Oneof_F_Double: - b.EncodeVarint(9<<3 | proto.WireFixed64) - b.EncodeFixed64(math.Float64bits(x.F_Double)) - case *Oneof_F_String: - b.EncodeVarint(10<<3 | proto.WireBytes) - b.EncodeStringBytes(x.F_String) - case *Oneof_F_Bytes: - b.EncodeVarint(11<<3 | proto.WireBytes) - b.EncodeRawBytes(x.F_Bytes) - case *Oneof_F_Sint32: - b.EncodeVarint(12<<3 | proto.WireVarint) - b.EncodeZigzag32(uint64(x.F_Sint32)) - case *Oneof_F_Sint64: - b.EncodeVarint(13<<3 | proto.WireVarint) - b.EncodeZigzag64(uint64(x.F_Sint64)) - case *Oneof_F_Enum: - b.EncodeVarint(14<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.F_Enum)) - case *Oneof_F_Message: - b.EncodeVarint(15<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.F_Message); err != nil { - return err - } - case *Oneof_FGroup: - b.EncodeVarint(16<<3 | proto.WireStartGroup) - if err := b.Marshal(x.FGroup); err != nil { - return err - } - b.EncodeVarint(16<<3 | proto.WireEndGroup) - case *Oneof_F_Largest_Tag: - b.EncodeVarint(536870911<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.F_Largest_Tag)) - case nil: - default: - return fmt.Errorf("Oneof.Union has unexpected type %T", x) - } - // tormato - switch x := m.Tormato.(type) { - case *Oneof_Value: - b.EncodeVarint(100<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Value)) - case nil: - default: - return fmt.Errorf("Oneof.Tormato has unexpected type %T", x) - } - return nil -} - -func _Oneof_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*Oneof) - switch tag { - case 1: // union.F_Bool - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Bool{x != 0} - return true, err - case 2: // union.F_Int32 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Int32{int32(x)} - return true, err - case 3: // union.F_Int64 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Int64{int64(x)} - return true, err - case 4: // union.F_Fixed32 - if wire != proto.WireFixed32 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed32() - m.Union = &Oneof_F_Fixed32{uint32(x)} - return true, err - case 5: // union.F_Fixed64 - if wire != proto.WireFixed64 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed64() - m.Union = &Oneof_F_Fixed64{x} - return true, err - case 6: // union.F_Uint32 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Uint32{uint32(x)} - return true, err - case 7: // union.F_Uint64 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Uint64{x} - return true, err - case 8: // union.F_Float - if wire != proto.WireFixed32 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed32() - m.Union = &Oneof_F_Float{math.Float32frombits(uint32(x))} - return true, err - case 9: // union.F_Double - if wire != proto.WireFixed64 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed64() - m.Union = &Oneof_F_Double{math.Float64frombits(x)} - return true, err - case 10: // union.F_String - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Union = &Oneof_F_String{x} - return true, err - case 11: // union.F_Bytes - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.Union = &Oneof_F_Bytes{x} - return true, err - case 12: // union.F_Sint32 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeZigzag32() - m.Union = &Oneof_F_Sint32{int32(x)} - return true, err - case 13: // union.F_Sint64 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeZigzag64() - m.Union = &Oneof_F_Sint64{int64(x)} - return true, err - case 14: // union.F_Enum - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Enum{MyMessage_Color(x)} - return true, err - case 15: // union.F_Message - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(GoTestField) - err := b.DecodeMessage(msg) - m.Union = &Oneof_F_Message{msg} - return true, err - case 16: // union.f_group - if wire != proto.WireStartGroup { - return true, proto.ErrInternalBadWireType - } - msg := new(Oneof_F_Group) - err := b.DecodeGroup(msg) - m.Union = &Oneof_FGroup{msg} - return true, err - case 536870911: // union.F_Largest_Tag - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Oneof_F_Largest_Tag{int32(x)} - return true, err - case 100: // tormato.value - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Tormato = &Oneof_Value{int32(x)} - return true, err - default: - return false, nil - } -} - -func _Oneof_OneofSizer(msg proto.Message) (n int) { - m := msg.(*Oneof) - // union - switch x := m.Union.(type) { - case *Oneof_F_Bool: - n += proto.SizeVarint(1<<3 | proto.WireVarint) - n += 1 - case *Oneof_F_Int32: - n += proto.SizeVarint(2<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.F_Int32)) - case *Oneof_F_Int64: - n += proto.SizeVarint(3<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.F_Int64)) - case *Oneof_F_Fixed32: - n += proto.SizeVarint(4<<3 | proto.WireFixed32) - n += 4 - case *Oneof_F_Fixed64: - n += proto.SizeVarint(5<<3 | proto.WireFixed64) - n += 8 - case *Oneof_F_Uint32: - n += proto.SizeVarint(6<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.F_Uint32)) - case *Oneof_F_Uint64: - n += proto.SizeVarint(7<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.F_Uint64)) - case *Oneof_F_Float: - n += proto.SizeVarint(8<<3 | proto.WireFixed32) - n += 4 - case *Oneof_F_Double: - n += proto.SizeVarint(9<<3 | proto.WireFixed64) - n += 8 - case *Oneof_F_String: - n += proto.SizeVarint(10<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.F_String))) - n += len(x.F_String) - case *Oneof_F_Bytes: - n += proto.SizeVarint(11<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.F_Bytes))) - n += len(x.F_Bytes) - case *Oneof_F_Sint32: - n += proto.SizeVarint(12<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64((uint32(x.F_Sint32) << 1) ^ uint32((int32(x.F_Sint32) >> 31)))) - case *Oneof_F_Sint64: - n += proto.SizeVarint(13<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(uint64(x.F_Sint64<<1) ^ uint64((int64(x.F_Sint64) >> 63)))) - case *Oneof_F_Enum: - n += proto.SizeVarint(14<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.F_Enum)) - case *Oneof_F_Message: - s := proto.Size(x.F_Message) - n += proto.SizeVarint(15<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Oneof_FGroup: - n += proto.SizeVarint(16<<3 | proto.WireStartGroup) - n += proto.Size(x.FGroup) - n += proto.SizeVarint(16<<3 | proto.WireEndGroup) - case *Oneof_F_Largest_Tag: - n += proto.SizeVarint(536870911<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.F_Largest_Tag)) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - // tormato - switch x := m.Tormato.(type) { - case *Oneof_Value: - n += proto.SizeVarint(100<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Value)) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type Oneof_F_Group struct { - X *int32 `protobuf:"varint,17,opt,name=x" json:"x,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Oneof_F_Group) Reset() { *m = Oneof_F_Group{} } -func (m *Oneof_F_Group) String() string { return proto.CompactTextString(m) } -func (*Oneof_F_Group) ProtoMessage() {} -func (*Oneof_F_Group) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29, 0} } - -func (m *Oneof_F_Group) GetX() int32 { - if m != nil && m.X != nil { - return *m.X - } - return 0 -} - -type Communique struct { - MakeMeCry *bool `protobuf:"varint,1,opt,name=make_me_cry,json=makeMeCry" json:"make_me_cry,omitempty"` - // This is a oneof, called "union". - // - // Types that are valid to be assigned to Union: - // *Communique_Number - // *Communique_Name - // *Communique_Data - // *Communique_TempC - // *Communique_Col - // *Communique_Msg - Union isCommunique_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Communique) Reset() { *m = Communique{} } -func (m *Communique) String() string { return proto.CompactTextString(m) } -func (*Communique) ProtoMessage() {} -func (*Communique) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } - -type isCommunique_Union interface { - isCommunique_Union() -} - -type Communique_Number struct { - Number int32 `protobuf:"varint,5,opt,name=number,oneof"` -} -type Communique_Name struct { - Name string `protobuf:"bytes,6,opt,name=name,oneof"` -} -type Communique_Data struct { - Data []byte `protobuf:"bytes,7,opt,name=data,oneof"` -} -type Communique_TempC struct { - TempC float64 `protobuf:"fixed64,8,opt,name=temp_c,json=tempC,oneof"` -} -type Communique_Col struct { - Col MyMessage_Color `protobuf:"varint,9,opt,name=col,enum=testdata.MyMessage_Color,oneof"` -} -type Communique_Msg struct { - Msg *Strings `protobuf:"bytes,10,opt,name=msg,oneof"` -} - -func (*Communique_Number) isCommunique_Union() {} -func (*Communique_Name) isCommunique_Union() {} -func (*Communique_Data) isCommunique_Union() {} -func (*Communique_TempC) isCommunique_Union() {} -func (*Communique_Col) isCommunique_Union() {} -func (*Communique_Msg) isCommunique_Union() {} - -func (m *Communique) GetUnion() isCommunique_Union { - if m != nil { - return m.Union - } - return nil -} - -func (m *Communique) GetMakeMeCry() bool { - if m != nil && m.MakeMeCry != nil { - return *m.MakeMeCry - } - return false -} - -func (m *Communique) GetNumber() int32 { - if x, ok := m.GetUnion().(*Communique_Number); ok { - return x.Number - } - return 0 -} - -func (m *Communique) GetName() string { - if x, ok := m.GetUnion().(*Communique_Name); ok { - return x.Name - } - return "" -} - -func (m *Communique) GetData() []byte { - if x, ok := m.GetUnion().(*Communique_Data); ok { - return x.Data - } - return nil -} - -func (m *Communique) GetTempC() float64 { - if x, ok := m.GetUnion().(*Communique_TempC); ok { - return x.TempC - } - return 0 -} - -func (m *Communique) GetCol() MyMessage_Color { - if x, ok := m.GetUnion().(*Communique_Col); ok { - return x.Col - } - return MyMessage_RED -} - -func (m *Communique) GetMsg() *Strings { - if x, ok := m.GetUnion().(*Communique_Msg); ok { - return x.Msg - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*Communique) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _Communique_OneofMarshaler, _Communique_OneofUnmarshaler, _Communique_OneofSizer, []interface{}{ - (*Communique_Number)(nil), - (*Communique_Name)(nil), - (*Communique_Data)(nil), - (*Communique_TempC)(nil), - (*Communique_Col)(nil), - (*Communique_Msg)(nil), - } -} - -func _Communique_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*Communique) - // union - switch x := m.Union.(type) { - case *Communique_Number: - b.EncodeVarint(5<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Number)) - case *Communique_Name: - b.EncodeVarint(6<<3 | proto.WireBytes) - b.EncodeStringBytes(x.Name) - case *Communique_Data: - b.EncodeVarint(7<<3 | proto.WireBytes) - b.EncodeRawBytes(x.Data) - case *Communique_TempC: - b.EncodeVarint(8<<3 | proto.WireFixed64) - b.EncodeFixed64(math.Float64bits(x.TempC)) - case *Communique_Col: - b.EncodeVarint(9<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Col)) - case *Communique_Msg: - b.EncodeVarint(10<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Msg); err != nil { - return err - } - case nil: - default: - return fmt.Errorf("Communique.Union has unexpected type %T", x) - } - return nil -} - -func _Communique_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*Communique) - switch tag { - case 5: // union.number - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Communique_Number{int32(x)} - return true, err - case 6: // union.name - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Union = &Communique_Name{x} - return true, err - case 7: // union.data - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.Union = &Communique_Data{x} - return true, err - case 8: // union.temp_c - if wire != proto.WireFixed64 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed64() - m.Union = &Communique_TempC{math.Float64frombits(x)} - return true, err - case 9: // union.col - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Communique_Col{MyMessage_Color(x)} - return true, err - case 10: // union.msg - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Strings) - err := b.DecodeMessage(msg) - m.Union = &Communique_Msg{msg} - return true, err - default: - return false, nil - } -} - -func _Communique_OneofSizer(msg proto.Message) (n int) { - m := msg.(*Communique) - // union - switch x := m.Union.(type) { - case *Communique_Number: - n += proto.SizeVarint(5<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Number)) - case *Communique_Name: - n += proto.SizeVarint(6<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.Name))) - n += len(x.Name) - case *Communique_Data: - n += proto.SizeVarint(7<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.Data))) - n += len(x.Data) - case *Communique_TempC: - n += proto.SizeVarint(8<<3 | proto.WireFixed64) - n += 8 - case *Communique_Col: - n += proto.SizeVarint(9<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Col)) - case *Communique_Msg: - s := proto.Size(x.Msg) - n += proto.SizeVarint(10<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -var E_Greeting = &proto.ExtensionDesc{ - ExtendedType: (*MyMessage)(nil), - ExtensionType: ([]string)(nil), - Field: 106, - Name: "testdata.greeting", - Tag: "bytes,106,rep,name=greeting", - Filename: "test.proto", -} - -var E_Complex = &proto.ExtensionDesc{ - ExtendedType: (*OtherMessage)(nil), - ExtensionType: (*ComplexExtension)(nil), - Field: 200, - Name: "testdata.complex", - Tag: "bytes,200,opt,name=complex", - Filename: "test.proto", -} - -var E_RComplex = &proto.ExtensionDesc{ - ExtendedType: (*OtherMessage)(nil), - ExtensionType: ([]*ComplexExtension)(nil), - Field: 201, - Name: "testdata.r_complex", - Tag: "bytes,201,rep,name=r_complex,json=rComplex", - Filename: "test.proto", -} - -var E_NoDefaultDouble = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*float64)(nil), - Field: 101, - Name: "testdata.no_default_double", - Tag: "fixed64,101,opt,name=no_default_double,json=noDefaultDouble", - Filename: "test.proto", -} - -var E_NoDefaultFloat = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*float32)(nil), - Field: 102, - Name: "testdata.no_default_float", - Tag: "fixed32,102,opt,name=no_default_float,json=noDefaultFloat", - Filename: "test.proto", -} - -var E_NoDefaultInt32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 103, - Name: "testdata.no_default_int32", - Tag: "varint,103,opt,name=no_default_int32,json=noDefaultInt32", - Filename: "test.proto", -} - -var E_NoDefaultInt64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int64)(nil), - Field: 104, - Name: "testdata.no_default_int64", - Tag: "varint,104,opt,name=no_default_int64,json=noDefaultInt64", - Filename: "test.proto", -} - -var E_NoDefaultUint32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint32)(nil), - Field: 105, - Name: "testdata.no_default_uint32", - Tag: "varint,105,opt,name=no_default_uint32,json=noDefaultUint32", - Filename: "test.proto", -} - -var E_NoDefaultUint64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint64)(nil), - Field: 106, - Name: "testdata.no_default_uint64", - Tag: "varint,106,opt,name=no_default_uint64,json=noDefaultUint64", - Filename: "test.proto", -} - -var E_NoDefaultSint32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 107, - Name: "testdata.no_default_sint32", - Tag: "zigzag32,107,opt,name=no_default_sint32,json=noDefaultSint32", - Filename: "test.proto", -} - -var E_NoDefaultSint64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int64)(nil), - Field: 108, - Name: "testdata.no_default_sint64", - Tag: "zigzag64,108,opt,name=no_default_sint64,json=noDefaultSint64", - Filename: "test.proto", -} - -var E_NoDefaultFixed32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint32)(nil), - Field: 109, - Name: "testdata.no_default_fixed32", - Tag: "fixed32,109,opt,name=no_default_fixed32,json=noDefaultFixed32", - Filename: "test.proto", -} - -var E_NoDefaultFixed64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint64)(nil), - Field: 110, - Name: "testdata.no_default_fixed64", - Tag: "fixed64,110,opt,name=no_default_fixed64,json=noDefaultFixed64", - Filename: "test.proto", -} - -var E_NoDefaultSfixed32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 111, - Name: "testdata.no_default_sfixed32", - Tag: "fixed32,111,opt,name=no_default_sfixed32,json=noDefaultSfixed32", - Filename: "test.proto", -} - -var E_NoDefaultSfixed64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int64)(nil), - Field: 112, - Name: "testdata.no_default_sfixed64", - Tag: "fixed64,112,opt,name=no_default_sfixed64,json=noDefaultSfixed64", - Filename: "test.proto", -} - -var E_NoDefaultBool = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*bool)(nil), - Field: 113, - Name: "testdata.no_default_bool", - Tag: "varint,113,opt,name=no_default_bool,json=noDefaultBool", - Filename: "test.proto", -} - -var E_NoDefaultString = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*string)(nil), - Field: 114, - Name: "testdata.no_default_string", - Tag: "bytes,114,opt,name=no_default_string,json=noDefaultString", - Filename: "test.proto", -} - -var E_NoDefaultBytes = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: ([]byte)(nil), - Field: 115, - Name: "testdata.no_default_bytes", - Tag: "bytes,115,opt,name=no_default_bytes,json=noDefaultBytes", - Filename: "test.proto", -} - -var E_NoDefaultEnum = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*DefaultsMessage_DefaultsEnum)(nil), - Field: 116, - Name: "testdata.no_default_enum", - Tag: "varint,116,opt,name=no_default_enum,json=noDefaultEnum,enum=testdata.DefaultsMessage_DefaultsEnum", - Filename: "test.proto", -} - -var E_DefaultDouble = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*float64)(nil), - Field: 201, - Name: "testdata.default_double", - Tag: "fixed64,201,opt,name=default_double,json=defaultDouble,def=3.1415", - Filename: "test.proto", -} - -var E_DefaultFloat = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*float32)(nil), - Field: 202, - Name: "testdata.default_float", - Tag: "fixed32,202,opt,name=default_float,json=defaultFloat,def=3.14", - Filename: "test.proto", -} - -var E_DefaultInt32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 203, - Name: "testdata.default_int32", - Tag: "varint,203,opt,name=default_int32,json=defaultInt32,def=42", - Filename: "test.proto", -} - -var E_DefaultInt64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int64)(nil), - Field: 204, - Name: "testdata.default_int64", - Tag: "varint,204,opt,name=default_int64,json=defaultInt64,def=43", - Filename: "test.proto", -} - -var E_DefaultUint32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint32)(nil), - Field: 205, - Name: "testdata.default_uint32", - Tag: "varint,205,opt,name=default_uint32,json=defaultUint32,def=44", - Filename: "test.proto", -} - -var E_DefaultUint64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint64)(nil), - Field: 206, - Name: "testdata.default_uint64", - Tag: "varint,206,opt,name=default_uint64,json=defaultUint64,def=45", - Filename: "test.proto", -} - -var E_DefaultSint32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 207, - Name: "testdata.default_sint32", - Tag: "zigzag32,207,opt,name=default_sint32,json=defaultSint32,def=46", - Filename: "test.proto", -} - -var E_DefaultSint64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int64)(nil), - Field: 208, - Name: "testdata.default_sint64", - Tag: "zigzag64,208,opt,name=default_sint64,json=defaultSint64,def=47", - Filename: "test.proto", -} - -var E_DefaultFixed32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint32)(nil), - Field: 209, - Name: "testdata.default_fixed32", - Tag: "fixed32,209,opt,name=default_fixed32,json=defaultFixed32,def=48", - Filename: "test.proto", -} - -var E_DefaultFixed64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*uint64)(nil), - Field: 210, - Name: "testdata.default_fixed64", - Tag: "fixed64,210,opt,name=default_fixed64,json=defaultFixed64,def=49", - Filename: "test.proto", -} - -var E_DefaultSfixed32 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int32)(nil), - Field: 211, - Name: "testdata.default_sfixed32", - Tag: "fixed32,211,opt,name=default_sfixed32,json=defaultSfixed32,def=50", - Filename: "test.proto", -} - -var E_DefaultSfixed64 = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*int64)(nil), - Field: 212, - Name: "testdata.default_sfixed64", - Tag: "fixed64,212,opt,name=default_sfixed64,json=defaultSfixed64,def=51", - Filename: "test.proto", -} - -var E_DefaultBool = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*bool)(nil), - Field: 213, - Name: "testdata.default_bool", - Tag: "varint,213,opt,name=default_bool,json=defaultBool,def=1", - Filename: "test.proto", -} - -var E_DefaultString = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*string)(nil), - Field: 214, - Name: "testdata.default_string", - Tag: "bytes,214,opt,name=default_string,json=defaultString,def=Hello, string", - Filename: "test.proto", -} - -var E_DefaultBytes = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: ([]byte)(nil), - Field: 215, - Name: "testdata.default_bytes", - Tag: "bytes,215,opt,name=default_bytes,json=defaultBytes,def=Hello, bytes", - Filename: "test.proto", -} - -var E_DefaultEnum = &proto.ExtensionDesc{ - ExtendedType: (*DefaultsMessage)(nil), - ExtensionType: (*DefaultsMessage_DefaultsEnum)(nil), - Field: 216, - Name: "testdata.default_enum", - Tag: "varint,216,opt,name=default_enum,json=defaultEnum,enum=testdata.DefaultsMessage_DefaultsEnum,def=1", - Filename: "test.proto", -} - -var E_X201 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 201, - Name: "testdata.x201", - Tag: "bytes,201,opt,name=x201", - Filename: "test.proto", -} - -var E_X202 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 202, - Name: "testdata.x202", - Tag: "bytes,202,opt,name=x202", - Filename: "test.proto", -} - -var E_X203 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 203, - Name: "testdata.x203", - Tag: "bytes,203,opt,name=x203", - Filename: "test.proto", -} - -var E_X204 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 204, - Name: "testdata.x204", - Tag: "bytes,204,opt,name=x204", - Filename: "test.proto", -} - -var E_X205 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 205, - Name: "testdata.x205", - Tag: "bytes,205,opt,name=x205", - Filename: "test.proto", -} - -var E_X206 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 206, - Name: "testdata.x206", - Tag: "bytes,206,opt,name=x206", - Filename: "test.proto", -} - -var E_X207 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 207, - Name: "testdata.x207", - Tag: "bytes,207,opt,name=x207", - Filename: "test.proto", -} - -var E_X208 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 208, - Name: "testdata.x208", - Tag: "bytes,208,opt,name=x208", - Filename: "test.proto", -} - -var E_X209 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 209, - Name: "testdata.x209", - Tag: "bytes,209,opt,name=x209", - Filename: "test.proto", -} - -var E_X210 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 210, - Name: "testdata.x210", - Tag: "bytes,210,opt,name=x210", - Filename: "test.proto", -} - -var E_X211 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 211, - Name: "testdata.x211", - Tag: "bytes,211,opt,name=x211", - Filename: "test.proto", -} - -var E_X212 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 212, - Name: "testdata.x212", - Tag: "bytes,212,opt,name=x212", - Filename: "test.proto", -} - -var E_X213 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 213, - Name: "testdata.x213", - Tag: "bytes,213,opt,name=x213", - Filename: "test.proto", -} - -var E_X214 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 214, - Name: "testdata.x214", - Tag: "bytes,214,opt,name=x214", - Filename: "test.proto", -} - -var E_X215 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 215, - Name: "testdata.x215", - Tag: "bytes,215,opt,name=x215", - Filename: "test.proto", -} - -var E_X216 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 216, - Name: "testdata.x216", - Tag: "bytes,216,opt,name=x216", - Filename: "test.proto", -} - -var E_X217 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 217, - Name: "testdata.x217", - Tag: "bytes,217,opt,name=x217", - Filename: "test.proto", -} - -var E_X218 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 218, - Name: "testdata.x218", - Tag: "bytes,218,opt,name=x218", - Filename: "test.proto", -} - -var E_X219 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 219, - Name: "testdata.x219", - Tag: "bytes,219,opt,name=x219", - Filename: "test.proto", -} - -var E_X220 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 220, - Name: "testdata.x220", - Tag: "bytes,220,opt,name=x220", - Filename: "test.proto", -} - -var E_X221 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 221, - Name: "testdata.x221", - Tag: "bytes,221,opt,name=x221", - Filename: "test.proto", -} - -var E_X222 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 222, - Name: "testdata.x222", - Tag: "bytes,222,opt,name=x222", - Filename: "test.proto", -} - -var E_X223 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 223, - Name: "testdata.x223", - Tag: "bytes,223,opt,name=x223", - Filename: "test.proto", -} - -var E_X224 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 224, - Name: "testdata.x224", - Tag: "bytes,224,opt,name=x224", - Filename: "test.proto", -} - -var E_X225 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 225, - Name: "testdata.x225", - Tag: "bytes,225,opt,name=x225", - Filename: "test.proto", -} - -var E_X226 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 226, - Name: "testdata.x226", - Tag: "bytes,226,opt,name=x226", - Filename: "test.proto", -} - -var E_X227 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 227, - Name: "testdata.x227", - Tag: "bytes,227,opt,name=x227", - Filename: "test.proto", -} - -var E_X228 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 228, - Name: "testdata.x228", - Tag: "bytes,228,opt,name=x228", - Filename: "test.proto", -} - -var E_X229 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 229, - Name: "testdata.x229", - Tag: "bytes,229,opt,name=x229", - Filename: "test.proto", -} - -var E_X230 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 230, - Name: "testdata.x230", - Tag: "bytes,230,opt,name=x230", - Filename: "test.proto", -} - -var E_X231 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 231, - Name: "testdata.x231", - Tag: "bytes,231,opt,name=x231", - Filename: "test.proto", -} - -var E_X232 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 232, - Name: "testdata.x232", - Tag: "bytes,232,opt,name=x232", - Filename: "test.proto", -} - -var E_X233 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 233, - Name: "testdata.x233", - Tag: "bytes,233,opt,name=x233", - Filename: "test.proto", -} - -var E_X234 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 234, - Name: "testdata.x234", - Tag: "bytes,234,opt,name=x234", - Filename: "test.proto", -} - -var E_X235 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 235, - Name: "testdata.x235", - Tag: "bytes,235,opt,name=x235", - Filename: "test.proto", -} - -var E_X236 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 236, - Name: "testdata.x236", - Tag: "bytes,236,opt,name=x236", - Filename: "test.proto", -} - -var E_X237 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 237, - Name: "testdata.x237", - Tag: "bytes,237,opt,name=x237", - Filename: "test.proto", -} - -var E_X238 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 238, - Name: "testdata.x238", - Tag: "bytes,238,opt,name=x238", - Filename: "test.proto", -} - -var E_X239 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 239, - Name: "testdata.x239", - Tag: "bytes,239,opt,name=x239", - Filename: "test.proto", -} - -var E_X240 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 240, - Name: "testdata.x240", - Tag: "bytes,240,opt,name=x240", - Filename: "test.proto", -} - -var E_X241 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 241, - Name: "testdata.x241", - Tag: "bytes,241,opt,name=x241", - Filename: "test.proto", -} - -var E_X242 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 242, - Name: "testdata.x242", - Tag: "bytes,242,opt,name=x242", - Filename: "test.proto", -} - -var E_X243 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 243, - Name: "testdata.x243", - Tag: "bytes,243,opt,name=x243", - Filename: "test.proto", -} - -var E_X244 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 244, - Name: "testdata.x244", - Tag: "bytes,244,opt,name=x244", - Filename: "test.proto", -} - -var E_X245 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 245, - Name: "testdata.x245", - Tag: "bytes,245,opt,name=x245", - Filename: "test.proto", -} - -var E_X246 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 246, - Name: "testdata.x246", - Tag: "bytes,246,opt,name=x246", - Filename: "test.proto", -} - -var E_X247 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 247, - Name: "testdata.x247", - Tag: "bytes,247,opt,name=x247", - Filename: "test.proto", -} - -var E_X248 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 248, - Name: "testdata.x248", - Tag: "bytes,248,opt,name=x248", - Filename: "test.proto", -} - -var E_X249 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 249, - Name: "testdata.x249", - Tag: "bytes,249,opt,name=x249", - Filename: "test.proto", -} - -var E_X250 = &proto.ExtensionDesc{ - ExtendedType: (*MyMessageSet)(nil), - ExtensionType: (*Empty)(nil), - Field: 250, - Name: "testdata.x250", - Tag: "bytes,250,opt,name=x250", - Filename: "test.proto", -} - -func init() { - proto.RegisterType((*GoEnum)(nil), "testdata.GoEnum") - proto.RegisterType((*GoTestField)(nil), "testdata.GoTestField") - proto.RegisterType((*GoTest)(nil), "testdata.GoTest") - proto.RegisterType((*GoTest_RequiredGroup)(nil), "testdata.GoTest.RequiredGroup") - proto.RegisterType((*GoTest_RepeatedGroup)(nil), "testdata.GoTest.RepeatedGroup") - proto.RegisterType((*GoTest_OptionalGroup)(nil), "testdata.GoTest.OptionalGroup") - proto.RegisterType((*GoTestRequiredGroupField)(nil), "testdata.GoTestRequiredGroupField") - proto.RegisterType((*GoTestRequiredGroupField_Group)(nil), "testdata.GoTestRequiredGroupField.Group") - proto.RegisterType((*GoSkipTest)(nil), "testdata.GoSkipTest") - proto.RegisterType((*GoSkipTest_SkipGroup)(nil), "testdata.GoSkipTest.SkipGroup") - proto.RegisterType((*NonPackedTest)(nil), "testdata.NonPackedTest") - proto.RegisterType((*PackedTest)(nil), "testdata.PackedTest") - proto.RegisterType((*MaxTag)(nil), "testdata.MaxTag") - proto.RegisterType((*OldMessage)(nil), "testdata.OldMessage") - proto.RegisterType((*OldMessage_Nested)(nil), "testdata.OldMessage.Nested") - proto.RegisterType((*NewMessage)(nil), "testdata.NewMessage") - proto.RegisterType((*NewMessage_Nested)(nil), "testdata.NewMessage.Nested") - proto.RegisterType((*InnerMessage)(nil), "testdata.InnerMessage") - proto.RegisterType((*OtherMessage)(nil), "testdata.OtherMessage") - proto.RegisterType((*RequiredInnerMessage)(nil), "testdata.RequiredInnerMessage") - proto.RegisterType((*MyMessage)(nil), "testdata.MyMessage") - proto.RegisterType((*MyMessage_SomeGroup)(nil), "testdata.MyMessage.SomeGroup") - proto.RegisterType((*Ext)(nil), "testdata.Ext") - proto.RegisterType((*ComplexExtension)(nil), "testdata.ComplexExtension") - proto.RegisterType((*DefaultsMessage)(nil), "testdata.DefaultsMessage") - proto.RegisterType((*MyMessageSet)(nil), "testdata.MyMessageSet") - proto.RegisterType((*Empty)(nil), "testdata.Empty") - proto.RegisterType((*MessageList)(nil), "testdata.MessageList") - proto.RegisterType((*MessageList_Message)(nil), "testdata.MessageList.Message") - proto.RegisterType((*Strings)(nil), "testdata.Strings") - proto.RegisterType((*Defaults)(nil), "testdata.Defaults") - proto.RegisterType((*SubDefaults)(nil), "testdata.SubDefaults") - proto.RegisterType((*RepeatedEnum)(nil), "testdata.RepeatedEnum") - proto.RegisterType((*MoreRepeated)(nil), "testdata.MoreRepeated") - proto.RegisterType((*GroupOld)(nil), "testdata.GroupOld") - proto.RegisterType((*GroupOld_G)(nil), "testdata.GroupOld.G") - proto.RegisterType((*GroupNew)(nil), "testdata.GroupNew") - proto.RegisterType((*GroupNew_G)(nil), "testdata.GroupNew.G") - proto.RegisterType((*FloatingPoint)(nil), "testdata.FloatingPoint") - proto.RegisterType((*MessageWithMap)(nil), "testdata.MessageWithMap") - proto.RegisterType((*Oneof)(nil), "testdata.Oneof") - proto.RegisterType((*Oneof_F_Group)(nil), "testdata.Oneof.F_Group") - proto.RegisterType((*Communique)(nil), "testdata.Communique") - proto.RegisterEnum("testdata.FOO", FOO_name, FOO_value) - proto.RegisterEnum("testdata.GoTest_KIND", GoTest_KIND_name, GoTest_KIND_value) - proto.RegisterEnum("testdata.MyMessage_Color", MyMessage_Color_name, MyMessage_Color_value) - proto.RegisterEnum("testdata.DefaultsMessage_DefaultsEnum", DefaultsMessage_DefaultsEnum_name, DefaultsMessage_DefaultsEnum_value) - proto.RegisterEnum("testdata.Defaults_Color", Defaults_Color_name, Defaults_Color_value) - proto.RegisterEnum("testdata.RepeatedEnum_Color", RepeatedEnum_Color_name, RepeatedEnum_Color_value) - proto.RegisterExtension(E_Ext_More) - proto.RegisterExtension(E_Ext_Text) - proto.RegisterExtension(E_Ext_Number) - proto.RegisterExtension(E_Greeting) - proto.RegisterExtension(E_Complex) - proto.RegisterExtension(E_RComplex) - proto.RegisterExtension(E_NoDefaultDouble) - proto.RegisterExtension(E_NoDefaultFloat) - proto.RegisterExtension(E_NoDefaultInt32) - proto.RegisterExtension(E_NoDefaultInt64) - proto.RegisterExtension(E_NoDefaultUint32) - proto.RegisterExtension(E_NoDefaultUint64) - proto.RegisterExtension(E_NoDefaultSint32) - proto.RegisterExtension(E_NoDefaultSint64) - proto.RegisterExtension(E_NoDefaultFixed32) - proto.RegisterExtension(E_NoDefaultFixed64) - proto.RegisterExtension(E_NoDefaultSfixed32) - proto.RegisterExtension(E_NoDefaultSfixed64) - proto.RegisterExtension(E_NoDefaultBool) - proto.RegisterExtension(E_NoDefaultString) - proto.RegisterExtension(E_NoDefaultBytes) - proto.RegisterExtension(E_NoDefaultEnum) - proto.RegisterExtension(E_DefaultDouble) - proto.RegisterExtension(E_DefaultFloat) - proto.RegisterExtension(E_DefaultInt32) - proto.RegisterExtension(E_DefaultInt64) - proto.RegisterExtension(E_DefaultUint32) - proto.RegisterExtension(E_DefaultUint64) - proto.RegisterExtension(E_DefaultSint32) - proto.RegisterExtension(E_DefaultSint64) - proto.RegisterExtension(E_DefaultFixed32) - proto.RegisterExtension(E_DefaultFixed64) - proto.RegisterExtension(E_DefaultSfixed32) - proto.RegisterExtension(E_DefaultSfixed64) - proto.RegisterExtension(E_DefaultBool) - proto.RegisterExtension(E_DefaultString) - proto.RegisterExtension(E_DefaultBytes) - proto.RegisterExtension(E_DefaultEnum) - proto.RegisterExtension(E_X201) - proto.RegisterExtension(E_X202) - proto.RegisterExtension(E_X203) - proto.RegisterExtension(E_X204) - proto.RegisterExtension(E_X205) - proto.RegisterExtension(E_X206) - proto.RegisterExtension(E_X207) - proto.RegisterExtension(E_X208) - proto.RegisterExtension(E_X209) - proto.RegisterExtension(E_X210) - proto.RegisterExtension(E_X211) - proto.RegisterExtension(E_X212) - proto.RegisterExtension(E_X213) - proto.RegisterExtension(E_X214) - proto.RegisterExtension(E_X215) - proto.RegisterExtension(E_X216) - proto.RegisterExtension(E_X217) - proto.RegisterExtension(E_X218) - proto.RegisterExtension(E_X219) - proto.RegisterExtension(E_X220) - proto.RegisterExtension(E_X221) - proto.RegisterExtension(E_X222) - proto.RegisterExtension(E_X223) - proto.RegisterExtension(E_X224) - proto.RegisterExtension(E_X225) - proto.RegisterExtension(E_X226) - proto.RegisterExtension(E_X227) - proto.RegisterExtension(E_X228) - proto.RegisterExtension(E_X229) - proto.RegisterExtension(E_X230) - proto.RegisterExtension(E_X231) - proto.RegisterExtension(E_X232) - proto.RegisterExtension(E_X233) - proto.RegisterExtension(E_X234) - proto.RegisterExtension(E_X235) - proto.RegisterExtension(E_X236) - proto.RegisterExtension(E_X237) - proto.RegisterExtension(E_X238) - proto.RegisterExtension(E_X239) - proto.RegisterExtension(E_X240) - proto.RegisterExtension(E_X241) - proto.RegisterExtension(E_X242) - proto.RegisterExtension(E_X243) - proto.RegisterExtension(E_X244) - proto.RegisterExtension(E_X245) - proto.RegisterExtension(E_X246) - proto.RegisterExtension(E_X247) - proto.RegisterExtension(E_X248) - proto.RegisterExtension(E_X249) - proto.RegisterExtension(E_X250) -} - -func init() { proto.RegisterFile("test.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 4453 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x5a, 0xc9, 0x77, 0xdb, 0x48, - 0x7a, 0x37, 0xc0, 0xfd, 0x23, 0x25, 0x42, 0x65, 0xb5, 0x9b, 0x96, 0xbc, 0xc0, 0x9c, 0xe9, 0x6e, - 0x7a, 0xd3, 0x48, 0x20, 0x44, 0xdb, 0x74, 0xa7, 0xdf, 0xf3, 0x42, 0xca, 0x7a, 0x63, 0x89, 0x0a, - 0xa4, 0xee, 0x7e, 0xd3, 0x39, 0xf0, 0x51, 0x22, 0x44, 0xb3, 0x4d, 0x02, 0x34, 0x09, 0xc5, 0x52, - 0x72, 0xe9, 0x4b, 0x72, 0xcd, 0x76, 0xc9, 0x35, 0xa7, 0x9c, 0x92, 0xbc, 0x97, 0x7f, 0x22, 0xe9, - 0xee, 0x59, 0x7b, 0xd6, 0xac, 0x93, 0x7d, 0x99, 0xec, 0xdb, 0x4c, 0x92, 0x4b, 0xcf, 0xab, 0xaf, - 0x0a, 0x40, 0x01, 0x24, 0x20, 0xf9, 0x24, 0x56, 0xd5, 0xef, 0xf7, 0xd5, 0xf6, 0xab, 0xef, 0xab, - 0xaf, 0x20, 0x00, 0xc7, 0x9c, 0x38, 0x2b, 0xa3, 0xb1, 0xed, 0xd8, 0x24, 0x4b, 0x7f, 0x77, 0x3b, - 0x4e, 0xa7, 0x7c, 0x1d, 0xd2, 0x1b, 0x76, 0xc3, 0x3a, 0x1a, 0x92, 0xab, 0x90, 0x38, 0xb4, 0xed, - 0x92, 0xa4, 0xca, 0x95, 0x79, 0x6d, 0x6e, 0xc5, 0x45, 0xac, 0x34, 0x5b, 0x2d, 0x83, 0xb6, 0x94, - 0xef, 0x40, 0x7e, 0xc3, 0xde, 0x33, 0x27, 0x4e, 0xb3, 0x6f, 0x0e, 0xba, 0x64, 0x11, 0x52, 0x4f, - 0x3b, 0xfb, 0xe6, 0x00, 0x19, 0x39, 0x83, 0x15, 0x08, 0x81, 0xe4, 0xde, 0xc9, 0xc8, 0x2c, 0xc9, - 0x58, 0x89, 0xbf, 0xcb, 0xbf, 0x72, 0x85, 0x76, 0x42, 0x99, 0xe4, 0x3a, 0x24, 0xbf, 0xdc, 0xb7, - 0xba, 0xbc, 0x97, 0xd7, 0xfc, 0x5e, 0x58, 0xfb, 0xca, 0x97, 0x37, 0xb7, 0x1f, 0x1b, 0x08, 0xa1, - 0xf6, 0xf7, 0x3a, 0xfb, 0x03, 0x6a, 0x4a, 0xa2, 0xf6, 0xb1, 0x40, 0x6b, 0x77, 0x3a, 0xe3, 0xce, - 0xb0, 0x94, 0x50, 0xa5, 0x4a, 0xca, 0x60, 0x05, 0x72, 0x1f, 0xe6, 0x0c, 0xf3, 0xc5, 0x51, 0x7f, - 0x6c, 0x76, 0x71, 0x70, 0xa5, 0xa4, 0x2a, 0x57, 0xf2, 0xd3, 0xf6, 0xb1, 0xd1, 0x08, 0x62, 0x19, - 0x79, 0x64, 0x76, 0x1c, 0x97, 0x9c, 0x52, 0x13, 0xb1, 0x64, 0x01, 0x4b, 0xc9, 0xad, 0x91, 0xd3, - 0xb7, 0xad, 0xce, 0x80, 0x91, 0xd3, 0xaa, 0x14, 0x43, 0x0e, 0x60, 0xc9, 0x9b, 0x50, 0x6c, 0xb6, - 0x1f, 0xda, 0xf6, 0xa0, 0x3d, 0xe6, 0x23, 0x2a, 0x81, 0x2a, 0x57, 0xb2, 0xc6, 0x5c, 0x93, 0xd6, - 0xba, 0xc3, 0x24, 0x15, 0x50, 0x9a, 0xed, 0x4d, 0xcb, 0xa9, 0x6a, 0x3e, 0x30, 0xaf, 0xca, 0x95, - 0x94, 0x31, 0xdf, 0xc4, 0xea, 0x29, 0x64, 0x4d, 0xf7, 0x91, 0x05, 0x55, 0xae, 0x24, 0x18, 0xb2, - 0xa6, 0x7b, 0xc8, 0x5b, 0x40, 0x9a, 0xed, 0x66, 0xff, 0xd8, 0xec, 0x8a, 0x56, 0xe7, 0x54, 0xb9, - 0x92, 0x31, 0x94, 0x26, 0x6f, 0x98, 0x81, 0x16, 0x2d, 0xcf, 0xab, 0x72, 0x25, 0xed, 0xa2, 0x05, - 0xdb, 0x37, 0x60, 0xa1, 0xd9, 0x7e, 0xb7, 0x1f, 0x1c, 0x70, 0x51, 0x95, 0x2b, 0x73, 0x46, 0xb1, - 0xc9, 0xea, 0xa7, 0xb1, 0xa2, 0x61, 0x45, 0x95, 0x2b, 0x49, 0x8e, 0x15, 0xec, 0xe2, 0xec, 0x9a, - 0x03, 0xbb, 0xe3, 0xf8, 0xd0, 0x05, 0x55, 0xae, 0xc8, 0xc6, 0x7c, 0x13, 0xab, 0x83, 0x56, 0x1f, - 0xdb, 0x47, 0xfb, 0x03, 0xd3, 0x87, 0x12, 0x55, 0xae, 0x48, 0x46, 0xb1, 0xc9, 0xea, 0x83, 0xd8, - 0x5d, 0x67, 0xdc, 0xb7, 0x7a, 0x3e, 0xf6, 0x3c, 0xea, 0xb7, 0xd8, 0x64, 0xf5, 0xc1, 0x11, 0x3c, - 0x3c, 0x71, 0xcc, 0x89, 0x0f, 0x35, 0x55, 0xb9, 0x52, 0x30, 0xe6, 0x9b, 0x58, 0x1d, 0xb2, 0x1a, - 0x5a, 0x83, 0x43, 0x55, 0xae, 0x2c, 0x50, 0xab, 0x33, 0xd6, 0x60, 0x37, 0xb4, 0x06, 0x3d, 0x55, - 0xae, 0x10, 0x8e, 0x15, 0xd6, 0x40, 0xd4, 0x0c, 0x13, 0x62, 0x69, 0x51, 0x4d, 0x08, 0x9a, 0x61, - 0x95, 0x41, 0xcd, 0x70, 0xe0, 0x6b, 0x6a, 0x42, 0xd4, 0x4c, 0x08, 0x89, 0x9d, 0x73, 0xe4, 0x05, - 0x35, 0x21, 0x6a, 0x86, 0x23, 0x43, 0x9a, 0xe1, 0xd8, 0xd7, 0xd5, 0x44, 0x50, 0x33, 0x53, 0x68, - 0xd1, 0x72, 0x49, 0x4d, 0x04, 0x35, 0xc3, 0xd1, 0x41, 0xcd, 0x70, 0xf0, 0x45, 0x35, 0x11, 0xd0, - 0x4c, 0x18, 0x2b, 0x1a, 0x5e, 0x52, 0x13, 0x01, 0xcd, 0x88, 0xb3, 0x73, 0x35, 0xc3, 0xa1, 0xcb, - 0x6a, 0x42, 0xd4, 0x8c, 0x68, 0xd5, 0xd3, 0x0c, 0x87, 0x5e, 0x52, 0x13, 0x01, 0xcd, 0x88, 0x58, - 0x4f, 0x33, 0x1c, 0x7b, 0x59, 0x4d, 0x04, 0x34, 0xc3, 0xb1, 0xd7, 0x45, 0xcd, 0x70, 0xe8, 0xc7, - 0x92, 0x9a, 0x10, 0x45, 0xc3, 0xa1, 0x37, 0x03, 0xa2, 0xe1, 0xd8, 0x4f, 0x28, 0x56, 0x54, 0x4d, - 0x18, 0x2c, 0xae, 0xc2, 0xa7, 0x14, 0x2c, 0xca, 0x86, 0x83, 0x7d, 0xd9, 0xd8, 0xdc, 0x05, 0x95, - 0xae, 0xa8, 0x92, 0x27, 0x1b, 0xd7, 0x2f, 0x89, 0xb2, 0xf1, 0x80, 0x57, 0xd1, 0xd5, 0x72, 0xd9, - 0x4c, 0x21, 0x6b, 0xba, 0x8f, 0x54, 0x55, 0xc9, 0x97, 0x8d, 0x87, 0x0c, 0xc8, 0xc6, 0xc3, 0x5e, - 0x53, 0x25, 0x51, 0x36, 0x33, 0xd0, 0xa2, 0xe5, 0xb2, 0x2a, 0x89, 0xb2, 0xf1, 0xd0, 0xa2, 0x6c, - 0x3c, 0xf0, 0x17, 0x54, 0x49, 0x90, 0xcd, 0x34, 0x56, 0x34, 0xfc, 0x45, 0x55, 0x12, 0x64, 0x13, - 0x9c, 0x1d, 0x93, 0x8d, 0x07, 0x7d, 0x43, 0x95, 0x7c, 0xd9, 0x04, 0xad, 0x72, 0xd9, 0x78, 0xd0, - 0x37, 0x55, 0x49, 0x90, 0x4d, 0x10, 0xcb, 0x65, 0xe3, 0x61, 0xdf, 0xc2, 0xf8, 0xe6, 0xca, 0xc6, - 0xc3, 0x0a, 0xb2, 0xf1, 0xa0, 0xbf, 0x43, 0x63, 0xa1, 0x27, 0x1b, 0x0f, 0x2a, 0xca, 0xc6, 0xc3, - 0xfe, 0x2e, 0xc5, 0xfa, 0xb2, 0x99, 0x06, 0x8b, 0xab, 0xf0, 0x7b, 0x14, 0xec, 0xcb, 0xc6, 0x03, - 0xaf, 0xe0, 0x20, 0xa8, 0x6c, 0xba, 0xe6, 0x61, 0xe7, 0x68, 0x40, 0x25, 0x56, 0xa1, 0xba, 0xa9, - 0x27, 0x9d, 0xf1, 0x91, 0x49, 0x47, 0x62, 0xdb, 0x83, 0xc7, 0x6e, 0x1b, 0x59, 0xa1, 0xc6, 0x99, - 0x7c, 0x7c, 0xc2, 0x75, 0xaa, 0x9f, 0xba, 0x5c, 0xd5, 0x8c, 0x22, 0xd3, 0xd0, 0x34, 0xbe, 0xa6, - 0x0b, 0xf8, 0x1b, 0x54, 0x45, 0x75, 0xb9, 0xa6, 0x33, 0x7c, 0x4d, 0xf7, 0xf1, 0x55, 0x38, 0xef, - 0x4b, 0xc9, 0x67, 0xdc, 0xa4, 0x5a, 0xaa, 0x27, 0xaa, 0xda, 0xaa, 0xb1, 0xe0, 0x0a, 0x6a, 0x16, - 0x29, 0xd0, 0xcd, 0x2d, 0x2a, 0xa9, 0x7a, 0xa2, 0xa6, 0x7b, 0x24, 0xb1, 0x27, 0x8d, 0xca, 0x90, - 0x0b, 0xcb, 0xe7, 0xdc, 0xa6, 0xca, 0xaa, 0x27, 0xab, 0xda, 0xea, 0xaa, 0xa1, 0x70, 0x7d, 0xcd, - 0xe0, 0x04, 0xfa, 0x59, 0xa1, 0x0a, 0xab, 0x27, 0x6b, 0xba, 0xc7, 0x09, 0xf6, 0xb3, 0xe0, 0x0a, - 0xcd, 0xa7, 0x7c, 0x89, 0x2a, 0xad, 0x9e, 0xae, 0xae, 0xe9, 0x6b, 0xeb, 0xf7, 0x8c, 0x22, 0x53, - 0x9c, 0xcf, 0xd1, 0x69, 0x3f, 0x5c, 0x72, 0x3e, 0x69, 0x95, 0x6a, 0xae, 0x9e, 0xd6, 0xee, 0xac, - 0xdd, 0xd5, 0xee, 0x1a, 0x0a, 0xd7, 0x9e, 0xcf, 0x7a, 0x87, 0xb2, 0xb8, 0xf8, 0x7c, 0xd6, 0x1a, - 0x55, 0x5f, 0x5d, 0x79, 0x66, 0x0e, 0x06, 0xf6, 0x2d, 0xb5, 0xfc, 0xd2, 0x1e, 0x0f, 0xba, 0xd7, - 0xca, 0x60, 0x28, 0x5c, 0x8f, 0x62, 0xaf, 0x0b, 0xae, 0x20, 0x7d, 0xfa, 0xaf, 0xd1, 0x7b, 0x58, - 0xa1, 0x9e, 0x79, 0xd8, 0xef, 0x59, 0xf6, 0xc4, 0x34, 0x8a, 0x4c, 0x9a, 0xa1, 0x35, 0xd9, 0x0d, - 0xaf, 0xe3, 0xaf, 0x53, 0xda, 0x42, 0x3d, 0x71, 0xbb, 0xaa, 0xd1, 0x9e, 0x66, 0xad, 0xe3, 0x6e, - 0x78, 0x1d, 0x7f, 0x83, 0x72, 0x48, 0x3d, 0x71, 0xbb, 0xa6, 0x73, 0x8e, 0xb8, 0x8e, 0x77, 0xe0, - 0x42, 0x28, 0x2e, 0xb6, 0x47, 0x9d, 0x83, 0xe7, 0x66, 0xb7, 0xa4, 0xd1, 0xf0, 0xf8, 0x50, 0x56, - 0x24, 0xe3, 0x7c, 0x20, 0x44, 0xee, 0x60, 0x33, 0xb9, 0x07, 0xaf, 0x87, 0x03, 0xa5, 0xcb, 0xac, - 0xd2, 0x78, 0x89, 0xcc, 0xc5, 0x60, 0xcc, 0x0c, 0x51, 0x05, 0x07, 0xec, 0x52, 0x75, 0x1a, 0x40, - 0x7d, 0xaa, 0xef, 0x89, 0x39, 0xf5, 0x67, 0xe0, 0xe2, 0x74, 0x28, 0x75, 0xc9, 0xeb, 0x34, 0xa2, - 0x22, 0xf9, 0x42, 0x38, 0xaa, 0x4e, 0xd1, 0x67, 0xf4, 0x5d, 0xa3, 0x21, 0x56, 0xa4, 0x4f, 0xf5, - 0x7e, 0x1f, 0x4a, 0x53, 0xc1, 0xd6, 0x65, 0xdf, 0xa1, 0x31, 0x17, 0xd9, 0xaf, 0x85, 0xe2, 0x6e, - 0x98, 0x3c, 0xa3, 0xeb, 0xbb, 0x34, 0x08, 0x0b, 0xe4, 0xa9, 0x9e, 0x71, 0xc9, 0x82, 0xe1, 0xd8, - 0xe5, 0xde, 0xa3, 0x51, 0x99, 0x2f, 0x59, 0x20, 0x32, 0x8b, 0xfd, 0x86, 0xe2, 0xb3, 0xcb, 0xad, - 0xd3, 0x30, 0xcd, 0xfb, 0x0d, 0x86, 0x6a, 0x4e, 0x7e, 0x9b, 0x92, 0x77, 0x67, 0xcf, 0xf8, 0xc7, - 0x09, 0x1a, 0x60, 0x39, 0x7b, 0x77, 0xd6, 0x94, 0x3d, 0xf6, 0x8c, 0x29, 0xff, 0x84, 0xb2, 0x89, - 0xc0, 0x9e, 0x9a, 0xf3, 0x63, 0x98, 0x73, 0x6f, 0x75, 0xbd, 0xb1, 0x7d, 0x34, 0x2a, 0x35, 0x55, - 0xb9, 0x02, 0xda, 0x95, 0xa9, 0xec, 0xc7, 0xbd, 0xe4, 0x6d, 0x50, 0x94, 0x11, 0x24, 0x31, 0x2b, - 0xcc, 0x2e, 0xb3, 0xb2, 0xa3, 0x26, 0x22, 0xac, 0x30, 0x94, 0x67, 0x45, 0x20, 0x51, 0x2b, 0xae, - 0xd3, 0x67, 0x56, 0x3e, 0x50, 0xa5, 0x99, 0x56, 0xdc, 0x10, 0xc0, 0xad, 0x04, 0x48, 0x4b, 0xeb, - 0x7e, 0xbe, 0x85, 0xed, 0xe4, 0x8b, 0xe1, 0x04, 0x6c, 0x03, 0xef, 0xcf, 0xc1, 0x4a, 0x46, 0x13, - 0x06, 0x37, 0x4d, 0xfb, 0xd9, 0x08, 0x5a, 0x60, 0x34, 0xd3, 0xb4, 0x9f, 0x9b, 0x41, 0x2b, 0xff, - 0xa6, 0x04, 0x49, 0x9a, 0x4f, 0x92, 0x2c, 0x24, 0xdf, 0x6b, 0x6d, 0x3e, 0x56, 0xce, 0xd1, 0x5f, - 0x0f, 0x5b, 0xad, 0xa7, 0x8a, 0x44, 0x72, 0x90, 0x7a, 0xf8, 0x95, 0xbd, 0xc6, 0xae, 0x22, 0x93, - 0x22, 0xe4, 0x9b, 0x9b, 0xdb, 0x1b, 0x0d, 0x63, 0xc7, 0xd8, 0xdc, 0xde, 0x53, 0x12, 0xb4, 0xad, - 0xf9, 0xb4, 0xf5, 0x60, 0x4f, 0x49, 0x92, 0x0c, 0x24, 0x68, 0x5d, 0x8a, 0x00, 0xa4, 0x77, 0xf7, - 0x8c, 0xcd, 0xed, 0x0d, 0x25, 0x4d, 0xad, 0xec, 0x6d, 0x6e, 0x35, 0x94, 0x0c, 0x45, 0xee, 0xbd, - 0xbb, 0xf3, 0xb4, 0xa1, 0x64, 0xe9, 0xcf, 0x07, 0x86, 0xf1, 0xe0, 0x2b, 0x4a, 0x8e, 0x92, 0xb6, - 0x1e, 0xec, 0x28, 0x80, 0xcd, 0x0f, 0x1e, 0x3e, 0x6d, 0x28, 0x79, 0x52, 0x80, 0x6c, 0xf3, 0xdd, - 0xed, 0x47, 0x7b, 0x9b, 0xad, 0x6d, 0xa5, 0x50, 0x3e, 0x81, 0x12, 0x5b, 0xe6, 0xc0, 0x2a, 0xb2, - 0xa4, 0xf0, 0x1d, 0x48, 0xb1, 0x9d, 0x91, 0x50, 0x25, 0x95, 0xf0, 0xce, 0x4c, 0x53, 0x56, 0xd8, - 0x1e, 0x31, 0xda, 0xd2, 0x65, 0x48, 0xb1, 0x55, 0x5a, 0x84, 0x14, 0x5b, 0x1d, 0x19, 0x53, 0x45, - 0x56, 0x28, 0xff, 0x96, 0x0c, 0xb0, 0x61, 0xef, 0x3e, 0xef, 0x8f, 0x30, 0x21, 0xbf, 0x0c, 0x30, - 0x79, 0xde, 0x1f, 0xb5, 0x51, 0xf5, 0x3c, 0xa9, 0xcc, 0xd1, 0x1a, 0xf4, 0x77, 0xe4, 0x1a, 0x14, - 0xb0, 0xf9, 0x90, 0x79, 0x21, 0xcc, 0x25, 0x33, 0x46, 0x9e, 0xd6, 0x71, 0xc7, 0x14, 0x84, 0xd4, - 0x74, 0x4c, 0x21, 0xd3, 0x02, 0xa4, 0xa6, 0x93, 0xab, 0x80, 0xc5, 0xf6, 0x04, 0x23, 0x0a, 0xa6, - 0x8d, 0x39, 0x03, 0xfb, 0x65, 0x31, 0x86, 0xbc, 0x0d, 0xd8, 0x27, 0x9b, 0x77, 0x71, 0xfa, 0x74, - 0xb8, 0xc3, 0x5d, 0xa1, 0x3f, 0xd8, 0x6c, 0x7d, 0xc2, 0x52, 0x0b, 0x72, 0x5e, 0x3d, 0xed, 0x0b, - 0x6b, 0xf9, 0x8c, 0x14, 0x9c, 0x11, 0x60, 0x95, 0x37, 0x25, 0x06, 0xe0, 0xa3, 0x59, 0xc0, 0xd1, - 0x30, 0x12, 0x1b, 0x4e, 0xf9, 0x32, 0xcc, 0x6d, 0xdb, 0x16, 0x3b, 0xbd, 0xb8, 0x4a, 0x05, 0x90, - 0x3a, 0x25, 0x09, 0xb3, 0x27, 0xa9, 0x53, 0xbe, 0x02, 0x20, 0xb4, 0x29, 0x20, 0xed, 0xb3, 0x36, - 0xf4, 0x01, 0xd2, 0x7e, 0xf9, 0x26, 0xa4, 0xb7, 0x3a, 0xc7, 0x7b, 0x9d, 0x1e, 0xb9, 0x06, 0x30, - 0xe8, 0x4c, 0x9c, 0xf6, 0x21, 0xee, 0xc3, 0xe7, 0x9f, 0x7f, 0xfe, 0xb9, 0x84, 0x97, 0xbd, 0x1c, - 0xad, 0x65, 0xfb, 0xf1, 0x02, 0xa0, 0x35, 0xe8, 0x6e, 0x99, 0x93, 0x49, 0xa7, 0x67, 0x92, 0x2a, - 0xa4, 0x2d, 0x73, 0x42, 0xa3, 0x9d, 0x84, 0xef, 0x08, 0xcb, 0xfe, 0x2a, 0xf8, 0xa8, 0x95, 0x6d, - 0x84, 0x18, 0x1c, 0x4a, 0x14, 0x48, 0x58, 0x47, 0x43, 0x7c, 0x27, 0x49, 0x19, 0xf4, 0xe7, 0xd2, - 0x25, 0x48, 0x33, 0x0c, 0x21, 0x90, 0xb4, 0x3a, 0x43, 0xb3, 0xc4, 0xfa, 0xc5, 0xdf, 0xe5, 0x5f, - 0x95, 0x00, 0xb6, 0xcd, 0x97, 0x67, 0xe8, 0xd3, 0x47, 0xc5, 0xf4, 0x99, 0x60, 0x7d, 0xde, 0x8f, - 0xeb, 0x93, 0xea, 0xec, 0xd0, 0xb6, 0xbb, 0x6d, 0xb6, 0xc5, 0xec, 0x49, 0x27, 0x47, 0x6b, 0x70, - 0xd7, 0xca, 0x1f, 0x40, 0x61, 0xd3, 0xb2, 0xcc, 0xb1, 0x3b, 0x26, 0x02, 0xc9, 0x67, 0xf6, 0xc4, - 0xe1, 0x6f, 0x4b, 0xf8, 0x9b, 0x94, 0x20, 0x39, 0xb2, 0xc7, 0x0e, 0x9b, 0x67, 0x3d, 0xa9, 0xaf, - 0xae, 0xae, 0x1a, 0x58, 0x43, 0x2e, 0x41, 0xee, 0xc0, 0xb6, 0x2c, 0xf3, 0x80, 0x4e, 0x22, 0x81, - 0x69, 0x8d, 0x5f, 0x51, 0xfe, 0x65, 0x09, 0x0a, 0x2d, 0xe7, 0x99, 0x6f, 0x5c, 0x81, 0xc4, 0x73, - 0xf3, 0x04, 0x87, 0x97, 0x30, 0xe8, 0x4f, 0x7a, 0x54, 0x7e, 0xbe, 0x33, 0x38, 0x62, 0x6f, 0x4d, - 0x05, 0x83, 0x15, 0xc8, 0x05, 0x48, 0xbf, 0x34, 0xfb, 0xbd, 0x67, 0x0e, 0xda, 0x94, 0x0d, 0x5e, - 0x22, 0xb7, 0x20, 0xd5, 0xa7, 0x83, 0x2d, 0x25, 0x71, 0xbd, 0x2e, 0xf8, 0xeb, 0x25, 0xce, 0xc1, - 0x60, 0xa0, 0x1b, 0xd9, 0x6c, 0x57, 0xf9, 0xe8, 0xa3, 0x8f, 0x3e, 0x92, 0xcb, 0x87, 0xb0, 0xe8, - 0x1e, 0xde, 0xc0, 0x64, 0xb7, 0xa1, 0x34, 0x30, 0xed, 0xf6, 0x61, 0xdf, 0xea, 0x0c, 0x06, 0x27, - 0xed, 0x97, 0xb6, 0xd5, 0xee, 0x58, 0x6d, 0x7b, 0x72, 0xd0, 0x19, 0xe3, 0x02, 0x44, 0x77, 0xb1, - 0x38, 0x30, 0xed, 0x26, 0xa3, 0xbd, 0x6f, 0x5b, 0x0f, 0xac, 0x16, 0xe5, 0x94, 0xff, 0x20, 0x09, - 0xb9, 0xad, 0x13, 0xd7, 0xfa, 0x22, 0xa4, 0x0e, 0xec, 0x23, 0x8b, 0xad, 0x65, 0xca, 0x60, 0x05, - 0x6f, 0x8f, 0x64, 0x61, 0x8f, 0x16, 0x21, 0xf5, 0xe2, 0xc8, 0x76, 0x4c, 0x9c, 0x6e, 0xce, 0x60, - 0x05, 0xba, 0x5a, 0x23, 0xd3, 0x29, 0x25, 0x31, 0xb9, 0xa5, 0x3f, 0xfd, 0xf9, 0xa7, 0xce, 0x30, - 0x7f, 0xb2, 0x02, 0x69, 0x9b, 0xae, 0xfe, 0xa4, 0x94, 0xc6, 0x77, 0x35, 0x01, 0x2e, 0xee, 0x8a, - 0xc1, 0x51, 0x64, 0x13, 0x16, 0x5e, 0x9a, 0xed, 0xe1, 0xd1, 0xc4, 0x69, 0xf7, 0xec, 0x76, 0xd7, - 0x34, 0x47, 0xe6, 0xb8, 0x34, 0x87, 0x3d, 0x09, 0x3e, 0x61, 0xd6, 0x42, 0x1a, 0xf3, 0x2f, 0xcd, - 0xad, 0xa3, 0x89, 0xb3, 0x61, 0x3f, 0x46, 0x16, 0xa9, 0x42, 0x6e, 0x6c, 0x52, 0x4f, 0x40, 0x07, - 0x5b, 0x08, 0xf7, 0x1e, 0xa0, 0x66, 0xc7, 0xe6, 0x08, 0x2b, 0xc8, 0x3a, 0x64, 0xf7, 0xfb, 0xcf, - 0xcd, 0xc9, 0x33, 0xb3, 0x5b, 0xca, 0xa8, 0x52, 0x65, 0x5e, 0xbb, 0xe8, 0x73, 0xbc, 0x65, 0x5d, - 0x79, 0x64, 0x0f, 0xec, 0xb1, 0xe1, 0x41, 0xc9, 0x7d, 0xc8, 0x4d, 0xec, 0xa1, 0xc9, 0xf4, 0x9d, - 0xc5, 0xa0, 0x7a, 0x79, 0x16, 0x6f, 0xd7, 0x1e, 0x9a, 0xae, 0x07, 0x73, 0xf1, 0x64, 0x99, 0x0d, - 0x74, 0x9f, 0x5e, 0x9d, 0x4b, 0x80, 0x4f, 0x03, 0x74, 0x40, 0x78, 0x95, 0x26, 0x4b, 0x74, 0x40, - 0xbd, 0x43, 0x7a, 0x23, 0x2a, 0xe5, 0x31, 0xaf, 0xf4, 0xca, 0x4b, 0xb7, 0x20, 0xe7, 0x19, 0xf4, - 0x5d, 0x1f, 0x73, 0x37, 0x39, 0xf4, 0x07, 0xcc, 0xf5, 0x31, 0x5f, 0xf3, 0x06, 0xa4, 0x70, 0xd8, - 0x34, 0x42, 0x19, 0x0d, 0x1a, 0x10, 0x73, 0x90, 0xda, 0x30, 0x1a, 0x8d, 0x6d, 0x45, 0xc2, 0xd8, - 0xf8, 0xf4, 0xdd, 0x86, 0x22, 0x0b, 0x8a, 0xfd, 0x6d, 0x09, 0x12, 0x8d, 0x63, 0x54, 0x0b, 0x9d, - 0x86, 0x7b, 0xa2, 0xe9, 0x6f, 0xad, 0x06, 0xc9, 0xa1, 0x3d, 0x36, 0xc9, 0xf9, 0x19, 0xb3, 0x2c, - 0xf5, 0x70, 0xbf, 0x84, 0x57, 0xe4, 0xc6, 0xb1, 0x63, 0x20, 0x5e, 0x7b, 0x0b, 0x92, 0x8e, 0x79, - 0xec, 0xcc, 0xe6, 0x3d, 0x63, 0x1d, 0x50, 0x80, 0x76, 0x13, 0xd2, 0xd6, 0xd1, 0x70, 0xdf, 0x1c, - 0xcf, 0x86, 0xf6, 0x71, 0x7a, 0x1c, 0x52, 0x7e, 0x0f, 0x94, 0x47, 0xf6, 0x70, 0x34, 0x30, 0x8f, - 0x1b, 0xc7, 0x8e, 0x69, 0x4d, 0xfa, 0xb6, 0x45, 0xf5, 0x7c, 0xd8, 0x1f, 0xa3, 0x17, 0xc1, 0xb7, - 0x62, 0x2c, 0xd0, 0x53, 0x3d, 0x31, 0x0f, 0x6c, 0xab, 0xcb, 0x1d, 0x26, 0x2f, 0x51, 0xb4, 0xf3, - 0xac, 0x3f, 0xa6, 0x0e, 0x84, 0xfa, 0x79, 0x56, 0x28, 0x6f, 0x40, 0x91, 0xe7, 0x18, 0x13, 0xde, - 0x71, 0xf9, 0x06, 0x14, 0xdc, 0x2a, 0x7c, 0x38, 0xcf, 0x42, 0xf2, 0x83, 0x86, 0xd1, 0x52, 0xce, - 0xd1, 0x65, 0x6d, 0x6d, 0x37, 0x14, 0x89, 0xfe, 0xd8, 0x7b, 0xbf, 0x15, 0x58, 0xca, 0x4b, 0x50, - 0xf0, 0xc6, 0xbe, 0x6b, 0x3a, 0xd8, 0x42, 0x03, 0x42, 0xa6, 0x2e, 0x67, 0xa5, 0x72, 0x06, 0x52, - 0x8d, 0xe1, 0xc8, 0x39, 0x29, 0xff, 0x22, 0xe4, 0x39, 0xe8, 0x69, 0x7f, 0xe2, 0x90, 0x3b, 0x90, - 0x19, 0xf2, 0xf9, 0x4a, 0x78, 0xdd, 0x13, 0x35, 0xe5, 0xe3, 0xdc, 0xdf, 0x86, 0x8b, 0x5e, 0xaa, - 0x42, 0x46, 0xf0, 0xa5, 0xfc, 0xa8, 0xcb, 0xe2, 0x51, 0x67, 0x4e, 0x21, 0x21, 0x38, 0x85, 0xf2, - 0x16, 0x64, 0x58, 0x04, 0x9c, 0x60, 0x54, 0x67, 0xa9, 0x22, 0x13, 0x13, 0xdb, 0xf9, 0x3c, 0xab, - 0x63, 0x17, 0x95, 0xab, 0x90, 0x47, 0xc1, 0x72, 0x04, 0x73, 0x9d, 0x80, 0x55, 0x4c, 0x6e, 0xbf, - 0x9f, 0x82, 0xac, 0xbb, 0x52, 0x64, 0x19, 0xd2, 0x2c, 0x3f, 0x43, 0x53, 0xee, 0xfb, 0x41, 0x0a, - 0x33, 0x32, 0xb2, 0x0c, 0x19, 0x9e, 0x83, 0x71, 0xef, 0x2e, 0x57, 0x35, 0x23, 0xcd, 0x72, 0x2e, - 0xaf, 0xb1, 0xa6, 0xa3, 0x63, 0x62, 0x2f, 0x03, 0x69, 0x96, 0x55, 0x11, 0x15, 0x72, 0x5e, 0x1e, - 0x85, 0xfe, 0x98, 0x3f, 0x03, 0x64, 0xdd, 0xc4, 0x49, 0x40, 0xd4, 0x74, 0xf4, 0x58, 0x3c, 0xe7, - 0xcf, 0x36, 0xfd, 0xeb, 0x49, 0xd6, 0xcd, 0x86, 0xf0, 0xf9, 0xde, 0x4d, 0xf0, 0x33, 0x3c, 0xff, - 0xf1, 0x01, 0x35, 0x1d, 0x5d, 0x82, 0x9b, 0xcd, 0x67, 0x78, 0x8e, 0x43, 0xae, 0xd2, 0x21, 0x62, - 0xce, 0x82, 0x47, 0xdf, 0x4f, 0xdd, 0xd3, 0x2c, 0x93, 0x21, 0xd7, 0xa8, 0x05, 0x96, 0x98, 0xe0, - 0xb9, 0xf4, 0xf3, 0xf4, 0x0c, 0xcf, 0x57, 0xc8, 0x4d, 0x0a, 0x61, 0xcb, 0x5f, 0x82, 0x88, 0xa4, - 0x3c, 0xc3, 0x93, 0x72, 0xa2, 0xd2, 0x0e, 0xd1, 0x3d, 0xa0, 0x4b, 0x10, 0x12, 0xf0, 0x34, 0x4b, - 0xc0, 0xc9, 0x15, 0x34, 0xc7, 0x26, 0x55, 0xf0, 0x93, 0xed, 0x0c, 0x4f, 0x70, 0xfc, 0x76, 0xbc, - 0xb2, 0x79, 0x89, 0x75, 0x86, 0xa7, 0x30, 0xa4, 0x46, 0xf7, 0x8b, 0xea, 0xbb, 0x34, 0x8f, 0x4e, - 0xb0, 0xe4, 0x0b, 0xcf, 0xdd, 0x53, 0xe6, 0x03, 0xeb, 0xcc, 0x83, 0x18, 0xa9, 0x26, 0x9e, 0x86, - 0x25, 0xca, 0xdb, 0xe9, 0x5b, 0x87, 0xa5, 0x22, 0xae, 0x44, 0xa2, 0x6f, 0x1d, 0x1a, 0xa9, 0x26, - 0xad, 0x61, 0x1a, 0xd8, 0xa6, 0x6d, 0x0a, 0xb6, 0x25, 0x6f, 0xb3, 0x46, 0x5a, 0x45, 0x4a, 0x90, - 0x6a, 0xb6, 0xb7, 0x3b, 0x56, 0x69, 0x81, 0xf1, 0xac, 0x8e, 0x65, 0x24, 0x9b, 0xdb, 0x1d, 0x8b, - 0xbc, 0x05, 0x89, 0xc9, 0xd1, 0x7e, 0x89, 0x84, 0xbf, 0xac, 0xec, 0x1e, 0xed, 0xbb, 0x43, 0x31, - 0x28, 0x82, 0x2c, 0x43, 0x76, 0xe2, 0x8c, 0xdb, 0xbf, 0x60, 0x8e, 0xed, 0xd2, 0x79, 0x5c, 0xc2, - 0x73, 0x46, 0x66, 0xe2, 0x8c, 0x3f, 0x30, 0xc7, 0xf6, 0x19, 0x9d, 0x5f, 0xf9, 0x0a, 0xe4, 0x05, - 0xbb, 0xa4, 0x08, 0x92, 0xc5, 0x6e, 0x0a, 0x75, 0xe9, 0x8e, 0x21, 0x59, 0xe5, 0x3d, 0x28, 0xb8, - 0x39, 0x0c, 0xce, 0x57, 0xa3, 0x27, 0x69, 0x60, 0x8f, 0xf1, 0x7c, 0xce, 0x6b, 0x97, 0xc4, 0x10, - 0xe5, 0xc3, 0x78, 0xb8, 0x60, 0xd0, 0xb2, 0x12, 0x1a, 0x8a, 0x54, 0xfe, 0xa1, 0x04, 0x85, 0x2d, - 0x7b, 0xec, 0x3f, 0x30, 0x2f, 0x42, 0x6a, 0xdf, 0xb6, 0x07, 0x13, 0x34, 0x9b, 0x35, 0x58, 0x81, - 0xbc, 0x01, 0x05, 0xfc, 0xe1, 0xe6, 0x9e, 0xb2, 0xf7, 0xb4, 0x91, 0xc7, 0x7a, 0x9e, 0x70, 0x12, - 0x48, 0xf6, 0x2d, 0x67, 0xc2, 0x3d, 0x19, 0xfe, 0x26, 0x5f, 0x80, 0x3c, 0xfd, 0xeb, 0x32, 0x93, - 0xde, 0x85, 0x15, 0x68, 0x35, 0x27, 0xbe, 0x05, 0x73, 0xb8, 0xfb, 0x1e, 0x2c, 0xe3, 0x3d, 0x63, - 0x14, 0x58, 0x03, 0x07, 0x96, 0x20, 0xc3, 0x5c, 0xc1, 0x04, 0xbf, 0x96, 0xe5, 0x0c, 0xb7, 0x48, - 0xdd, 0x2b, 0x66, 0x02, 0x2c, 0xdc, 0x67, 0x0c, 0x5e, 0x2a, 0x3f, 0x80, 0x2c, 0x46, 0xa9, 0xd6, - 0xa0, 0x4b, 0xca, 0x20, 0xf5, 0x4a, 0x26, 0xc6, 0xc8, 0x45, 0xe1, 0x9a, 0xcf, 0x9b, 0x57, 0x36, - 0x0c, 0xa9, 0xb7, 0xb4, 0x00, 0xd2, 0x06, 0xbd, 0x77, 0x1f, 0x73, 0x37, 0x2d, 0x1d, 0x97, 0x5b, - 0xdc, 0xc4, 0xb6, 0xf9, 0x32, 0xce, 0xc4, 0xb6, 0xf9, 0x92, 0x99, 0xb8, 0x3a, 0x65, 0x82, 0x96, - 0x4e, 0xf8, 0xa7, 0x43, 0xe9, 0xa4, 0x5c, 0x85, 0x39, 0x3c, 0x9e, 0x7d, 0xab, 0xb7, 0x63, 0xf7, - 0x2d, 0xbc, 0xe7, 0x1f, 0xe2, 0x3d, 0x49, 0x32, 0xa4, 0x43, 0xba, 0x07, 0xe6, 0x71, 0xe7, 0x80, - 0xdd, 0x38, 0xb3, 0x06, 0x2b, 0x94, 0x3f, 0x4b, 0xc2, 0x3c, 0x77, 0xad, 0xef, 0xf7, 0x9d, 0x67, - 0x5b, 0x9d, 0x11, 0x79, 0x0a, 0x05, 0xea, 0x55, 0xdb, 0xc3, 0xce, 0x68, 0x44, 0x8f, 0xaf, 0x84, - 0x57, 0x8d, 0xeb, 0x53, 0xae, 0x9a, 0xe3, 0x57, 0xb6, 0x3b, 0x43, 0x73, 0x8b, 0x61, 0x1b, 0x96, - 0x33, 0x3e, 0x31, 0xf2, 0x96, 0x5f, 0x43, 0x36, 0x21, 0x3f, 0x9c, 0xf4, 0x3c, 0x63, 0x32, 0x1a, - 0xab, 0x44, 0x1a, 0xdb, 0x9a, 0xf4, 0x02, 0xb6, 0x60, 0xe8, 0x55, 0xd0, 0x81, 0x51, 0x7f, 0xec, - 0xd9, 0x4a, 0x9c, 0x32, 0x30, 0xea, 0x3a, 0x82, 0x03, 0xdb, 0xf7, 0x6b, 0xc8, 0x63, 0x00, 0x7a, - 0xbc, 0x1c, 0x9b, 0xa6, 0x4e, 0xa8, 0xa0, 0xbc, 0xf6, 0x66, 0xa4, 0xad, 0x5d, 0x67, 0xbc, 0x67, - 0xef, 0x3a, 0x63, 0x66, 0x88, 0x1e, 0x4c, 0x2c, 0x2e, 0xbd, 0x03, 0x4a, 0x78, 0xfe, 0xe2, 0x8d, - 0x3c, 0x35, 0xe3, 0x46, 0x9e, 0xe3, 0x37, 0xf2, 0xba, 0x7c, 0x57, 0x5a, 0x7a, 0x0f, 0x8a, 0xa1, - 0x29, 0x8b, 0x74, 0xc2, 0xe8, 0xb7, 0x45, 0x7a, 0x5e, 0x7b, 0x5d, 0xf8, 0x9c, 0x2d, 0x6e, 0xb8, - 0x68, 0xf7, 0x1d, 0x50, 0xc2, 0xd3, 0x17, 0x0d, 0x67, 0x63, 0x32, 0x05, 0xe4, 0xdf, 0x87, 0xb9, - 0xc0, 0x94, 0x45, 0x72, 0xee, 0x94, 0x49, 0x95, 0x7f, 0x29, 0x05, 0xa9, 0x96, 0x65, 0xda, 0x87, - 0xe4, 0xf5, 0x60, 0x9c, 0x7c, 0x72, 0xce, 0x8d, 0x91, 0x17, 0x43, 0x31, 0xf2, 0xc9, 0x39, 0x2f, - 0x42, 0x5e, 0x0c, 0x45, 0x48, 0xb7, 0xa9, 0xa6, 0x93, 0xcb, 0x53, 0xf1, 0xf1, 0xc9, 0x39, 0x21, - 0x38, 0x5e, 0x9e, 0x0a, 0x8e, 0x7e, 0x73, 0x4d, 0xa7, 0x0e, 0x35, 0x18, 0x19, 0x9f, 0x9c, 0xf3, - 0xa3, 0xe2, 0x72, 0x38, 0x2a, 0x7a, 0x8d, 0x35, 0x9d, 0x0d, 0x49, 0x88, 0x88, 0x38, 0x24, 0x16, - 0x0b, 0x97, 0xc3, 0xb1, 0x10, 0x79, 0x3c, 0x0a, 0x2e, 0x87, 0xa3, 0x20, 0x36, 0xf2, 0xa8, 0x77, - 0x31, 0x14, 0xf5, 0xd0, 0x28, 0x0b, 0x77, 0xcb, 0xe1, 0x70, 0xc7, 0x78, 0xc2, 0x48, 0xc5, 0x58, - 0xe7, 0x35, 0xd6, 0x74, 0xa2, 0x85, 0x02, 0x5d, 0xf4, 0x6d, 0x1f, 0xf7, 0x02, 0x9d, 0xbe, 0x4e, - 0x97, 0xcd, 0xbd, 0x88, 0x16, 0x63, 0xbe, 0xf8, 0xe3, 0x6a, 0xba, 0x17, 0x31, 0x0d, 0x32, 0x87, - 0x3c, 0x01, 0x56, 0xd0, 0x73, 0x09, 0xb2, 0xc4, 0xcd, 0x5f, 0x69, 0xb6, 0xd1, 0x83, 0xd1, 0x79, - 0x1d, 0xb2, 0x3b, 0x7d, 0x05, 0xe6, 0x9a, 0xed, 0xa7, 0x9d, 0x71, 0xcf, 0x9c, 0x38, 0xed, 0xbd, - 0x4e, 0xcf, 0x7b, 0x44, 0xa0, 0xfb, 0x9f, 0x6f, 0xf2, 0x96, 0xbd, 0x4e, 0x8f, 0x5c, 0x70, 0xc5, - 0xd5, 0xc5, 0x56, 0x89, 0xcb, 0x6b, 0xe9, 0x75, 0xba, 0x68, 0xcc, 0x18, 0xfa, 0xc2, 0x05, 0xee, - 0x0b, 0x1f, 0x66, 0x20, 0x75, 0x64, 0xf5, 0x6d, 0xeb, 0x61, 0x0e, 0x32, 0x8e, 0x3d, 0x1e, 0x76, - 0x1c, 0xbb, 0xfc, 0x23, 0x09, 0xe0, 0x91, 0x3d, 0x1c, 0x1e, 0x59, 0xfd, 0x17, 0x47, 0x26, 0xb9, - 0x02, 0xf9, 0x61, 0xe7, 0xb9, 0xd9, 0x1e, 0x9a, 0xed, 0x83, 0xb1, 0x7b, 0x0e, 0x72, 0xb4, 0x6a, - 0xcb, 0x7c, 0x34, 0x3e, 0x21, 0x25, 0xf7, 0x8a, 0x8e, 0xda, 0x41, 0x49, 0xf2, 0x2b, 0xfb, 0x22, - 0xbf, 0x74, 0xa6, 0xf9, 0x1e, 0xba, 0xd7, 0x4e, 0x96, 0x47, 0x64, 0xf8, 0xee, 0x61, 0x89, 0x4a, - 0xde, 0x31, 0x87, 0xa3, 0xf6, 0x01, 0x4a, 0x85, 0xca, 0x21, 0x45, 0xcb, 0x8f, 0xc8, 0x6d, 0x48, - 0x1c, 0xd8, 0x03, 0x14, 0xc9, 0x29, 0xfb, 0x42, 0x71, 0xe4, 0x0d, 0x48, 0x0c, 0x27, 0x4c, 0x36, - 0x79, 0x6d, 0x41, 0xb8, 0x27, 0xb0, 0xd0, 0x44, 0x61, 0xc3, 0x49, 0xcf, 0x9b, 0xf7, 0x8d, 0x22, - 0x24, 0x9a, 0xad, 0x16, 0x8d, 0xfd, 0xcd, 0x56, 0x6b, 0x4d, 0x91, 0xea, 0x5f, 0x82, 0x6c, 0x6f, - 0x6c, 0x9a, 0xd4, 0x3d, 0xcc, 0xce, 0x39, 0x3e, 0xc4, 0x58, 0xe7, 0x81, 0xea, 0x5b, 0x90, 0x39, - 0x60, 0x59, 0x07, 0x89, 0x48, 0x6b, 0x4b, 0x7f, 0xc8, 0x1e, 0x55, 0x96, 0xfc, 0xe6, 0x70, 0x9e, - 0x62, 0xb8, 0x36, 0xea, 0x3b, 0x90, 0x1b, 0xb7, 0x4f, 0x33, 0xf8, 0x31, 0x8b, 0x2e, 0x71, 0x06, - 0xb3, 0x63, 0x5e, 0x55, 0x6f, 0xc0, 0x82, 0x65, 0xbb, 0xdf, 0x50, 0xda, 0x5d, 0x76, 0xc6, 0x2e, - 0x4e, 0x5f, 0xe5, 0x5c, 0xe3, 0x26, 0xfb, 0x6e, 0x69, 0xd9, 0xbc, 0x81, 0x9d, 0xca, 0xfa, 0x23, - 0x50, 0x04, 0x33, 0x98, 0x7a, 0xc6, 0x59, 0x39, 0x64, 0x1f, 0x4a, 0x3d, 0x2b, 0x78, 0xee, 0x43, - 0x46, 0xd8, 0xc9, 0x8c, 0x31, 0xd2, 0x63, 0x5f, 0x9d, 0x3d, 0x23, 0xe8, 0xea, 0xa6, 0x8d, 0x50, - 0x5f, 0x13, 0x6d, 0xe4, 0x19, 0xfb, 0x20, 0x2d, 0x1a, 0xa9, 0xe9, 0xa1, 0x55, 0x39, 0x3a, 0x75, - 0x28, 0x7d, 0xf6, 0x3d, 0xd9, 0xb3, 0xc2, 0x1c, 0xe0, 0x0c, 0x33, 0xf1, 0x83, 0xf9, 0x90, 0x7d, - 0x6a, 0x0e, 0x98, 0x99, 0x1a, 0xcd, 0xe4, 0xd4, 0xd1, 0x3c, 0x67, 0xdf, 0x75, 0x3d, 0x33, 0xbb, - 0xb3, 0x46, 0x33, 0x39, 0x75, 0x34, 0x03, 0xf6, 0xc5, 0x37, 0x60, 0xa6, 0xa6, 0xd7, 0x37, 0x80, - 0x88, 0x5b, 0xcd, 0xe3, 0x44, 0x8c, 0x9d, 0x21, 0xfb, 0x8e, 0xef, 0x6f, 0x36, 0xa3, 0xcc, 0x32, - 0x14, 0x3f, 0x20, 0x8b, 0x7d, 0xe2, 0x0f, 0x1a, 0xaa, 0xe9, 0xf5, 0x4d, 0x38, 0x2f, 0x4e, 0xec, - 0x0c, 0x43, 0xb2, 0x55, 0xa9, 0x52, 0x34, 0x16, 0xfc, 0xa9, 0x71, 0xce, 0x4c, 0x53, 0xf1, 0x83, - 0x1a, 0xa9, 0x52, 0x45, 0x99, 0x32, 0x55, 0xd3, 0xeb, 0x0f, 0xa0, 0x28, 0x98, 0xda, 0xc7, 0x08, - 0x1d, 0x6d, 0xe6, 0x05, 0xfb, 0x5f, 0x0b, 0xcf, 0x0c, 0x8d, 0xe8, 0xe1, 0x1d, 0xe3, 0x31, 0x2e, - 0xda, 0xc8, 0x98, 0xfd, 0xa3, 0x80, 0x3f, 0x16, 0x64, 0x84, 0x8e, 0x04, 0xe6, 0xdf, 0x71, 0x56, - 0x26, 0xec, 0x5f, 0x08, 0xfc, 0xa1, 0x50, 0x42, 0xbd, 0x1f, 0x98, 0x8e, 0x49, 0x83, 0x5c, 0x8c, - 0x0d, 0x07, 0x3d, 0xf2, 0x9b, 0x91, 0x80, 0x15, 0xf1, 0x81, 0x44, 0x98, 0x36, 0x2d, 0xd6, 0x37, - 0x61, 0xfe, 0xec, 0x0e, 0xe9, 0x63, 0x89, 0x65, 0xcb, 0xd5, 0x15, 0x9a, 0x50, 0x1b, 0x73, 0xdd, - 0x80, 0x5f, 0x6a, 0xc0, 0xdc, 0x99, 0x9d, 0xd2, 0x27, 0x12, 0xcb, 0x39, 0xa9, 0x25, 0xa3, 0xd0, - 0x0d, 0x7a, 0xa6, 0xb9, 0x33, 0xbb, 0xa5, 0x4f, 0x25, 0xf6, 0x40, 0xa1, 0x6b, 0x9e, 0x11, 0xd7, - 0x33, 0xcd, 0x9d, 0xd9, 0x2d, 0x7d, 0x95, 0x65, 0x94, 0xb2, 0x5e, 0x15, 0x8d, 0xa0, 0x2f, 0x98, - 0x3f, 0xbb, 0x5b, 0xfa, 0x9a, 0x84, 0x8f, 0x15, 0xb2, 0xae, 0x7b, 0xeb, 0xe2, 0x79, 0xa6, 0xf9, - 0xb3, 0xbb, 0xa5, 0xaf, 0x4b, 0xf8, 0xa4, 0x21, 0xeb, 0xeb, 0x01, 0x33, 0xc1, 0xd1, 0x9c, 0xee, - 0x96, 0xbe, 0x21, 0xe1, 0x2b, 0x83, 0xac, 0xd7, 0x3c, 0x33, 0xbb, 0x53, 0xa3, 0x39, 0xdd, 0x2d, - 0x7d, 0x13, 0x6f, 0xf1, 0x75, 0x59, 0xbf, 0x13, 0x30, 0x83, 0x9e, 0xa9, 0xf8, 0x0a, 0x6e, 0xe9, - 0x5b, 0x12, 0x3e, 0x06, 0xc9, 0xfa, 0x5d, 0xc3, 0xed, 0xdd, 0xf7, 0x4c, 0xc5, 0x57, 0x70, 0x4b, - 0x9f, 0x49, 0xf8, 0x66, 0x24, 0xeb, 0xf7, 0x82, 0x86, 0xd0, 0x33, 0x29, 0xaf, 0xe2, 0x96, 0xbe, - 0x4d, 0x2d, 0x15, 0xeb, 0xf2, 0xfa, 0xaa, 0xe1, 0x0e, 0x40, 0xf0, 0x4c, 0xca, 0xab, 0xb8, 0xa5, - 0xef, 0x50, 0x53, 0x4a, 0x5d, 0x5e, 0x5f, 0x0b, 0x99, 0xaa, 0xe9, 0xf5, 0x47, 0x50, 0x38, 0xab, - 0x5b, 0xfa, 0xae, 0xf8, 0x16, 0x97, 0xef, 0x0a, 0xbe, 0x69, 0x47, 0xd8, 0xb3, 0x53, 0x1d, 0xd3, - 0xf7, 0x30, 0xc7, 0xa9, 0xcf, 0x3d, 0x61, 0xef, 0x55, 0x8c, 0xe0, 0x6f, 0x1f, 0x73, 0x53, 0x5b, - 0xfe, 0xf9, 0x38, 0xd5, 0x47, 0x7d, 0x5f, 0xc2, 0x47, 0xad, 0x02, 0x37, 0x88, 0x78, 0xef, 0xa4, - 0x30, 0x87, 0xf5, 0xa1, 0x3f, 0xcb, 0xd3, 0xbc, 0xd5, 0x0f, 0xa4, 0x57, 0x71, 0x57, 0xf5, 0x44, - 0x6b, 0xbb, 0xe1, 0x2d, 0x06, 0xd6, 0xbc, 0x0d, 0xc9, 0x63, 0x6d, 0x75, 0x4d, 0xbc, 0x92, 0x89, - 0x6f, 0xb9, 0xcc, 0x49, 0xe5, 0xb5, 0xa2, 0xf0, 0xdc, 0x3d, 0x1c, 0x39, 0x27, 0x06, 0xb2, 0x38, - 0x5b, 0x8b, 0x64, 0x7f, 0x12, 0xc3, 0xd6, 0x38, 0xbb, 0x1a, 0xc9, 0xfe, 0x34, 0x86, 0x5d, 0xe5, - 0x6c, 0x3d, 0x92, 0xfd, 0xd5, 0x18, 0xb6, 0xce, 0xd9, 0xeb, 0x91, 0xec, 0xaf, 0xc5, 0xb0, 0xd7, - 0x39, 0xbb, 0x16, 0xc9, 0xfe, 0x7a, 0x0c, 0xbb, 0xc6, 0xd9, 0x77, 0x22, 0xd9, 0xdf, 0x88, 0x61, - 0xdf, 0xe1, 0xec, 0xbb, 0x91, 0xec, 0x6f, 0xc6, 0xb0, 0xef, 0x72, 0xf6, 0xbd, 0x48, 0xf6, 0xb7, - 0x62, 0xd8, 0xf7, 0x18, 0x7b, 0x6d, 0x35, 0x92, 0xfd, 0x59, 0x34, 0x7b, 0x6d, 0x95, 0xb3, 0xa3, - 0xb5, 0xf6, 0xed, 0x18, 0x36, 0xd7, 0xda, 0x5a, 0xb4, 0xd6, 0xbe, 0x13, 0xc3, 0xe6, 0x5a, 0x5b, - 0x8b, 0xd6, 0xda, 0x77, 0x63, 0xd8, 0x5c, 0x6b, 0x6b, 0xd1, 0x5a, 0xfb, 0x5e, 0x0c, 0x9b, 0x6b, - 0x6d, 0x2d, 0x5a, 0x6b, 0xdf, 0x8f, 0x61, 0x73, 0xad, 0xad, 0x45, 0x6b, 0xed, 0x07, 0x31, 0x6c, - 0xae, 0xb5, 0xb5, 0x68, 0xad, 0xfd, 0x51, 0x0c, 0x9b, 0x6b, 0x6d, 0x2d, 0x5a, 0x6b, 0x7f, 0x1c, - 0xc3, 0xe6, 0x5a, 0x5b, 0x8b, 0xd6, 0xda, 0x9f, 0xc4, 0xb0, 0xb9, 0xd6, 0xb4, 0x68, 0xad, 0xfd, - 0x69, 0x34, 0x5b, 0xe3, 0x5a, 0xd3, 0xa2, 0xb5, 0xf6, 0x67, 0x31, 0x6c, 0xae, 0x35, 0x2d, 0x5a, - 0x6b, 0x7f, 0x1e, 0xc3, 0xe6, 0x5a, 0xd3, 0xa2, 0xb5, 0xf6, 0xc3, 0x18, 0x36, 0xd7, 0x9a, 0x16, - 0xad, 0xb5, 0xbf, 0x88, 0x61, 0x73, 0xad, 0x69, 0xd1, 0x5a, 0xfb, 0xcb, 0x18, 0x36, 0xd7, 0x9a, - 0x16, 0xad, 0xb5, 0xbf, 0x8a, 0x61, 0x73, 0xad, 0x69, 0xd1, 0x5a, 0xfb, 0xeb, 0x18, 0x36, 0xd7, - 0x9a, 0x16, 0xad, 0xb5, 0xbf, 0x89, 0x61, 0x73, 0xad, 0x69, 0xd1, 0x5a, 0xfb, 0xdb, 0x18, 0x36, - 0xd7, 0x5a, 0x35, 0x5a, 0x6b, 0x7f, 0x17, 0xcd, 0xae, 0x72, 0xad, 0x55, 0xa3, 0xb5, 0xf6, 0xf7, - 0x31, 0x6c, 0xae, 0xb5, 0x6a, 0xb4, 0xd6, 0xfe, 0x21, 0x86, 0xcd, 0xb5, 0x56, 0x8d, 0xd6, 0xda, - 0x3f, 0xc6, 0xb0, 0xb9, 0xd6, 0xaa, 0xd1, 0x5a, 0xfb, 0x51, 0x0c, 0x9b, 0x6b, 0xad, 0x1a, 0xad, - 0xb5, 0x7f, 0x8a, 0x61, 0x73, 0xad, 0x55, 0xa3, 0xb5, 0xf6, 0xcf, 0x31, 0x6c, 0xae, 0xb5, 0x6a, - 0xb4, 0xd6, 0xfe, 0x25, 0x86, 0xcd, 0xb5, 0x56, 0x8d, 0xd6, 0xda, 0xbf, 0xc6, 0xb0, 0xb9, 0xd6, - 0xaa, 0xd1, 0x5a, 0xfb, 0xb7, 0x18, 0x36, 0xd7, 0x9a, 0x1e, 0xad, 0xb5, 0x7f, 0x8f, 0x66, 0xeb, - 0x5c, 0x6b, 0x7a, 0xb4, 0xd6, 0xfe, 0x23, 0x86, 0xcd, 0xb5, 0xa6, 0x47, 0x6b, 0xed, 0x3f, 0x63, - 0xd8, 0x5c, 0x6b, 0x7a, 0xb4, 0xd6, 0xfe, 0x2b, 0x86, 0xcd, 0xb5, 0xa6, 0x47, 0x6b, 0xed, 0xbf, - 0x63, 0xd8, 0x5c, 0x6b, 0x7a, 0xb4, 0xd6, 0xfe, 0x27, 0x86, 0xcd, 0xb5, 0xa6, 0x47, 0x6b, 0xed, - 0xc7, 0x31, 0x6c, 0xae, 0x35, 0x3d, 0x5a, 0x6b, 0x3f, 0x89, 0x61, 0x73, 0xad, 0xe9, 0xd1, 0x5a, - 0xfb, 0xdf, 0x18, 0x36, 0xd7, 0x9a, 0x1e, 0xad, 0xb5, 0xff, 0x8b, 0x61, 0x73, 0xad, 0xad, 0x47, - 0x6b, 0xed, 0xff, 0xa3, 0xd9, 0xeb, 0xab, 0x3f, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x00, 0xcd, - 0x32, 0x57, 0x39, 0x00, 0x00, -} diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go index 965876bf..1aaee725 100644 --- a/vendor/github.com/golang/protobuf/proto/text.go +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -50,7 +50,6 @@ import ( var ( newline = []byte("\n") spaces = []byte(" ") - gtNewline = []byte(">\n") endBraceNewline = []byte("}\n") backslashN = []byte{'\\', 'n'} backslashR = []byte{'\\', 'r'} @@ -170,11 +169,6 @@ func writeName(w *textWriter, props *Properties) error { return nil } -// raw is the interface satisfied by RawMessage. -type raw interface { - Bytes() []byte -} - func requiresQuotes(u string) bool { // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. for _, ch := range u { @@ -269,6 +263,10 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { props := sprops.Prop[i] name := st.Field(i).Name + if name == "XXX_NoUnkeyedLiteral" { + continue + } + if strings.HasPrefix(name, "XXX_") { // There are two XXX_ fields: // XXX_unrecognized []byte @@ -355,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { return err } if err := w.WriteByte('\n'); err != nil { @@ -372,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if err := tm.writeAny(w, val, props.mvalprop); err != nil { + if err := tm.writeAny(w, val, props.MapValProp); err != nil { return err } if err := w.WriteByte('\n'); err != nil { @@ -436,12 +434,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if b, ok := fv.Interface().(raw); ok { - if err := writeRaw(w, b.Bytes()); err != nil { - return err - } - continue - } // Enums have a String method, so writeAny will work fine. if err := tm.writeAny(w, fv, props); err != nil { @@ -455,7 +447,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { // Extensions (the XXX_extensions field). pv := sv.Addr() - if _, ok := extendable(pv.Interface()); ok { + if _, err := extendable(pv.Interface()); err == nil { if err := tm.writeExtensions(w, pv); err != nil { return err } @@ -464,27 +456,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return nil } -// writeRaw writes an uninterpreted raw message. -func writeRaw(w *textWriter, b []byte) error { - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if err := writeUnknownStruct(w, b); err != nil { - return err - } - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - return nil -} - // writeAny writes an arbitrary field. func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { v = reflect.Indirect(v) @@ -535,6 +506,19 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert } } w.indent() + if v.CanAddr() { + // Calling v.Interface on a struct causes the reflect package to + // copy the entire struct. This is racy with the new Marshaler + // since we atomically update the XXX_sizecache. + // + // Thus, we retrieve a pointer to the struct if possible to avoid + // a race since v.Interface on the pointer doesn't copy the struct. + // + // If v is not addressable, then we are not worried about a race + // since it implies that the binary Marshaler cannot possibly be + // mutating this value. + v = v.Addr() + } if etm, ok := v.Interface().(encoding.TextMarshaler); ok { text, err := etm.MarshalText() if err != nil { @@ -543,8 +527,13 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert if _, err = w.Write(text); err != nil { return err } - } else if err := tm.writeStruct(w, v); err != nil { - return err + } else { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if err := tm.writeStruct(w, v); err != nil { + return err + } } w.unindent() if err := w.WriteByte(ket); err != nil { diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go index 5e14513f..bb55a3af 100644 --- a/vendor/github.com/golang/protobuf/proto/text_parser.go +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -206,7 +206,6 @@ func (p *textParser) advance() { var ( errBadUTF8 = errors.New("proto: bad UTF-8") - errBadHex = errors.New("proto: bad hexadecimal") ) func unquoteC(s string, quote rune) (string, error) { @@ -277,60 +276,47 @@ func unescape(s string) (ch string, tail string, err error) { return "?", s, nil // trigraph workaround case '\'', '"', '\\': return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + case '0', '1', '2', '3', '4', '5', '6', '7': if len(s) < 2 { return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) } - base := 8 - ss := s[:2] + ss := string(r) + s[:2] s = s[2:] - if r == 'x' || r == 'X' { - base = 16 - } else { - ss = string(r) + ss - } - i, err := strconv.ParseUint(ss, base, 8) + i, err := strconv.ParseUint(ss, 8, 8) if err != nil { - return "", "", err + return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) } return string([]byte{byte(i)}), s, nil - case 'u', 'U': - n := 4 - if r == 'U' { + case 'x', 'X', 'u', 'U': + var n int + switch r { + case 'x', 'X': + n = 2 + case 'u': + n = 4 + case 'U': n = 8 } if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) - } - - bs := make([]byte, n/2) - for i := 0; i < n; i += 2 { - a, ok1 := unhex(s[i]) - b, ok2 := unhex(s[i+1]) - if !ok1 || !ok2 { - return "", "", errBadHex - } - bs[i/2] = a<<4 | b + return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) } + ss := s[:n] s = s[n:] - return string(bs), s, nil + i, err := strconv.ParseUint(ss, 16, 64) + if err != nil { + return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) + } + if r == 'x' || r == 'X' { + return string([]byte{byte(i)}), s, nil + } + if i > utf8.MaxRune { + return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) + } + return string(i), s, nil } return "", "", fmt.Errorf(`unknown escape \%c`, r) } -// Adapted from src/pkg/strconv/quote.go. -func unhex(b byte) (v byte, ok bool) { - switch { - case '0' <= b && b <= '9': - return b - '0', true - case 'a' <= b && b <= 'f': - return b - 'a' + 10, true - case 'A' <= b && b <= 'F': - return b - 'A' + 10, true - } - return 0, false -} - // Back off the parser by one token. Can only be done between calls to next(). // It makes the next advance() a no-op. func (p *textParser) back() { p.backed = true } @@ -644,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { if err := p.consumeToken(":"); err != nil { return err } - if err := p.readAny(key, props.mkeyprop); err != nil { + if err := p.readAny(key, props.MapKeyProp); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { return err } case "value": - if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { return err } - if err := p.readAny(val, props.mvalprop); err != nil { + if err := p.readAny(val, props.MapValProp); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { @@ -728,6 +714,9 @@ func (p *textParser) consumeExtName() (string, error) { if tok.err != nil { return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) } + if p.done && tok.value != "]" { + return "", p.errorf("unclosed type_url or extension name") + } } return strings.Join(parts, ""), nil } @@ -865,7 +854,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { return p.readStruct(fv, terminator) case reflect.Uint32: if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(x) + fv.SetUint(uint64(x)) return nil } case reflect.Uint64: @@ -883,13 +872,9 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { // UnmarshalText returns *RequiredNotSetError. func UnmarshalText(s string, pb Message) error { if um, ok := pb.(encoding.TextUnmarshaler); ok { - err := um.UnmarshalText([]byte(s)) - return err + return um.UnmarshalText([]byte(s)) } pb.Reset() v := reflect.ValueOf(pb) - if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { - return pe - } - return nil + return newTextParser(s).readStruct(v.Elem(), "") } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser_test.go b/vendor/github.com/golang/protobuf/proto/text_parser_test.go index 8f7cb4d2..a8198087 100644 --- a/vendor/github.com/golang/protobuf/proto/text_parser_test.go +++ b/vendor/github.com/golang/protobuf/proto/text_parser_test.go @@ -32,13 +32,13 @@ package proto_test import ( + "fmt" "math" - "reflect" "testing" . "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" - . "github.com/golang/protobuf/proto/testdata" + . "github.com/golang/protobuf/proto/test_proto" ) type UnmarshalTextTest struct { @@ -167,10 +167,19 @@ var unMarshalTextTests = []UnmarshalTextTest{ // Quoted string with UTF-8 bytes. { - in: "count:42 name: '\303\277\302\201\xAB'", + in: "count:42 name: '\303\277\302\201\x00\xAB\xCD\xEF'", out: &MyMessage{ Count: Int32(42), - Name: String("\303\277\302\201\xAB"), + Name: String("\303\277\302\201\x00\xAB\xCD\xEF"), + }, + }, + + // Quoted string with unicode escapes. + { + in: `count: 42 name: "\u0047\U00000047\uffff\U0010ffff"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("GG\uffff\U0010ffff"), }, }, @@ -180,6 +189,24 @@ var unMarshalTextTests = []UnmarshalTextTest{ err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`, }, + // Bad \u escape + { + in: `count: 42 name: "\u000"`, + err: `line 1.16: invalid quoted string "\u000": \u requires 4 following digits`, + }, + + // Bad \U escape + { + in: `count: 42 name: "\U0000000"`, + err: `line 1.16: invalid quoted string "\U0000000": \U requires 8 following digits`, + }, + + // Bad \U escape + { + in: `count: 42 name: "\xxx"`, + err: `line 1.16: invalid quoted string "\xxx": \xxx contains non-hexadecimal digits`, + }, + // Number too large for int64 { in: "count: 1 others { key: 123456789012345678901 }", @@ -263,6 +290,12 @@ var unMarshalTextTests = []UnmarshalTextTest{ err: `line 1.17: invalid float32: "17.4"`, }, + // unclosed bracket doesn't cause infinite loop + { + in: `[`, + err: `line 1.0: unclosed type_url or extension name`, + }, + // Enum { in: `count:42 bikeshed: BLUE`, @@ -330,7 +363,7 @@ var unMarshalTextTests = []UnmarshalTextTest{ // Missing required field { in: `name: "Pawel"`, - err: `proto: required field "testdata.MyMessage.count" not set`, + err: fmt.Sprintf(`proto: required field "%T.count" not set`, MyMessage{}), out: &MyMessage{ Name: String("Pawel"), }, @@ -339,7 +372,7 @@ var unMarshalTextTests = []UnmarshalTextTest{ // Missing required field in a required submessage { in: `count: 42 we_must_go_deeper < leo_finally_won_an_oscar <> >`, - err: `proto: required field "testdata.InnerMessage.host" not set`, + err: fmt.Sprintf(`proto: required field "%T.host" not set`, InnerMessage{}), out: &MyMessage{ Count: Int32(42), WeMustGoDeeper: &RequiredInnerMessage{LeoFinallyWonAnOscar: &InnerMessage{}}, @@ -470,10 +503,10 @@ var unMarshalTextTests = []UnmarshalTextTest{ }, // Extension - buildExtStructTest(`count: 42 [testdata.Ext.more]:`), - buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`), - buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`), - buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`), + buildExtStructTest(`count: 42 [test_proto.Ext.more]:`), + buildExtStructTest(`count: 42 [test_proto.Ext.more] {data:"Hello, world!"}`), + buildExtDataTest(`count: 42 [test_proto.Ext.text]:"Hello, world!" [test_proto.Ext.number]:1729`), + buildExtRepStringTest(`count: 42 [test_proto.greeting]:"bula" [test_proto.greeting]:"hola"`), // Big all-in-one { @@ -534,7 +567,7 @@ func TestUnmarshalText(t *testing.T) { // We don't expect failure. if err != nil { t.Errorf("Test %d: Unexpected error: %v", i, err) - } else if !reflect.DeepEqual(pb, test.out) { + } else if !Equal(pb, test.out) { t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", i, pb, test.out) } @@ -545,7 +578,7 @@ func TestUnmarshalText(t *testing.T) { } else if err.Error() != test.err { t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", i, err.Error(), test.err) - } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) { + } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !Equal(pb, test.out) { t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", i, pb, test.out) } diff --git a/vendor/github.com/golang/protobuf/proto/text_test.go b/vendor/github.com/golang/protobuf/proto/text_test.go index 3eabacac..3c8b033c 100644 --- a/vendor/github.com/golang/protobuf/proto/text_test.go +++ b/vendor/github.com/golang/protobuf/proto/text_test.go @@ -37,12 +37,14 @@ import ( "io/ioutil" "math" "strings" + "sync" "testing" "github.com/golang/protobuf/proto" proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" + pb "github.com/golang/protobuf/proto/test_proto" + anypb "github.com/golang/protobuf/ptypes/any" ) // textMessage implements the methods that allow it to marshal and unmarshal @@ -151,12 +153,12 @@ SomeGroup { } /* 2 unknown bytes */ 13: 4 -[testdata.Ext.more]: < +[test_proto.Ext.more]: < data: "Big gobs for big rats" > -[testdata.greeting]: "adg" -[testdata.greeting]: "easy" -[testdata.greeting]: "cow" +[test_proto.greeting]: "adg" +[test_proto.greeting]: "easy" +[test_proto.greeting]: "cow" /* 13 unknown bytes */ 201: "\t3G skiing" /* 3 unknown bytes */ @@ -472,3 +474,45 @@ func TestProto3Text(t *testing.T) { } } } + +func TestRacyMarshal(t *testing.T) { + // This test should be run with the race detector. + + any := &pb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")} + proto.SetExtension(any, pb.E_Ext_Text, proto.String("bar")) + b, err := proto.Marshal(any) + if err != nil { + panic(err) + } + m := &proto3pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any), Value: b}, + } + + wantText := proto.MarshalTextString(m) + wantBytes, err := proto.Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal error: %v", err) + } + + var wg sync.WaitGroup + defer wg.Wait() + wg.Add(20) + for i := 0; i < 10; i++ { + go func() { + defer wg.Done() + got := proto.MarshalTextString(m) + if got != wantText { + t.Errorf("proto.MarshalTextString = %q, want %q", got, wantText) + } + }() + go func() { + defer wg.Done() + got, err := proto.Marshal(m) + if !bytes.Equal(got, wantBytes) || err != nil { + t.Errorf("proto.Marshal = (%x, %v), want (%x, nil)", got, err, wantBytes) + } + }() + } +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/Makefile deleted file mode 100644 index a42cc371..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -test: - cd testdata && make test diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile deleted file mode 100644 index f706871a..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Not stored here, but descriptor.proto is in https://github.com/google/protobuf/ -# at src/google/protobuf/descriptor.proto -regenerate: - @echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION - cp $(HOME)/src/protobuf/include/google/protobuf/descriptor.proto . - protoc --go_out=../../../../.. -I$(HOME)/src/protobuf/include $(HOME)/src/protobuf/include/google/protobuf/descriptor.proto diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go index c6a91bca..e855b1f5 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go @@ -1,36 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/descriptor.proto -/* -Package descriptor is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/descriptor.proto - -It has these top-level messages: - FileDescriptorSet - FileDescriptorProto - DescriptorProto - ExtensionRangeOptions - FieldDescriptorProto - OneofDescriptorProto - EnumDescriptorProto - EnumValueDescriptorProto - ServiceDescriptorProto - MethodDescriptorProto - FileOptions - MessageOptions - FieldOptions - OneofOptions - EnumOptions - EnumValueOptions - ServiceOptions - MethodOptions - UninterpretedOption - SourceCodeInfo - GeneratedCodeInfo -*/ -package descriptor +package descriptor // import "github.com/golang/protobuf/protoc-gen-go/descriptor" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -138,7 +109,9 @@ func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error { *x = FieldDescriptorProto_Type(value) return nil } -func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{4, 0} } +func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{4, 0} +} type FieldDescriptorProto_Label int32 @@ -177,7 +150,7 @@ func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error { return nil } func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) { - return fileDescriptor0, []int{4, 1} + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{4, 1} } // Generated classes can be optimized for speed or code size. @@ -217,7 +190,9 @@ func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error { *x = FileOptions_OptimizeMode(value) return nil } -func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{10, 0} } +func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{10, 0} +} type FieldOptions_CType int32 @@ -255,7 +230,9 @@ func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error { *x = FieldOptions_CType(value) return nil } -func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{12, 0} } +func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{12, 0} +} type FieldOptions_JSType int32 @@ -295,7 +272,9 @@ func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error { *x = FieldOptions_JSType(value) return nil } -func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{12, 1} } +func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{12, 1} +} // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, // or neither? HTTP based RPC implementation may choose GET verb for safe @@ -336,20 +315,41 @@ func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error { return nil } func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) { - return fileDescriptor0, []int{17, 0} + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{17, 0} } // The protocol compiler can output a FileDescriptorSet containing the .proto // files it parses. type FileDescriptorSet struct { - File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"` - XXX_unrecognized []byte `json:"-"` + File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} } -func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) } -func (*FileDescriptorSet) ProtoMessage() {} -func (*FileDescriptorSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} } +func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) } +func (*FileDescriptorSet) ProtoMessage() {} +func (*FileDescriptorSet) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{0} +} +func (m *FileDescriptorSet) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileDescriptorSet.Unmarshal(m, b) +} +func (m *FileDescriptorSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileDescriptorSet.Marshal(b, m, deterministic) +} +func (dst *FileDescriptorSet) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileDescriptorSet.Merge(dst, src) +} +func (m *FileDescriptorSet) XXX_Size() int { + return xxx_messageInfo_FileDescriptorSet.Size(m) +} +func (m *FileDescriptorSet) XXX_DiscardUnknown() { + xxx_messageInfo_FileDescriptorSet.DiscardUnknown(m) +} + +var xxx_messageInfo_FileDescriptorSet proto.InternalMessageInfo func (m *FileDescriptorSet) GetFile() []*FileDescriptorProto { if m != nil { @@ -382,14 +382,35 @@ type FileDescriptorProto struct { SourceCodeInfo *SourceCodeInfo `protobuf:"bytes,9,opt,name=source_code_info,json=sourceCodeInfo" json:"source_code_info,omitempty"` // The syntax of the proto file. // The supported values are "proto2" and "proto3". - Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"` - XXX_unrecognized []byte `json:"-"` + Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} } -func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*FileDescriptorProto) ProtoMessage() {} -func (*FileDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} } +func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*FileDescriptorProto) ProtoMessage() {} +func (*FileDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{1} +} +func (m *FileDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileDescriptorProto.Unmarshal(m, b) +} +func (m *FileDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *FileDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileDescriptorProto.Merge(dst, src) +} +func (m *FileDescriptorProto) XXX_Size() int { + return xxx_messageInfo_FileDescriptorProto.Size(m) +} +func (m *FileDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_FileDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_FileDescriptorProto proto.InternalMessageInfo func (m *FileDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -488,14 +509,35 @@ type DescriptorProto struct { ReservedRange []*DescriptorProto_ReservedRange `protobuf:"bytes,9,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` // Reserved field names, which may not be used by fields in the same message. // A given name may only be reserved once. - ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` - XXX_unrecognized []byte `json:"-"` + ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *DescriptorProto) Reset() { *m = DescriptorProto{} } -func (m *DescriptorProto) String() string { return proto.CompactTextString(m) } -func (*DescriptorProto) ProtoMessage() {} -func (*DescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *DescriptorProto) Reset() { *m = DescriptorProto{} } +func (m *DescriptorProto) String() string { return proto.CompactTextString(m) } +func (*DescriptorProto) ProtoMessage() {} +func (*DescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{2} +} +func (m *DescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DescriptorProto.Unmarshal(m, b) +} +func (m *DescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DescriptorProto.Marshal(b, m, deterministic) +} +func (dst *DescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_DescriptorProto.Merge(dst, src) +} +func (m *DescriptorProto) XXX_Size() int { + return xxx_messageInfo_DescriptorProto.Size(m) +} +func (m *DescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_DescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_DescriptorProto proto.InternalMessageInfo func (m *DescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -568,18 +610,37 @@ func (m *DescriptorProto) GetReservedName() []string { } type DescriptorProto_ExtensionRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - Options *ExtensionRangeOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + Options *ExtensionRangeOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} } func (m *DescriptorProto_ExtensionRange) String() string { return proto.CompactTextString(m) } func (*DescriptorProto_ExtensionRange) ProtoMessage() {} func (*DescriptorProto_ExtensionRange) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{2, 0} + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{2, 0} } +func (m *DescriptorProto_ExtensionRange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DescriptorProto_ExtensionRange.Unmarshal(m, b) +} +func (m *DescriptorProto_ExtensionRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DescriptorProto_ExtensionRange.Marshal(b, m, deterministic) +} +func (dst *DescriptorProto_ExtensionRange) XXX_Merge(src proto.Message) { + xxx_messageInfo_DescriptorProto_ExtensionRange.Merge(dst, src) +} +func (m *DescriptorProto_ExtensionRange) XXX_Size() int { + return xxx_messageInfo_DescriptorProto_ExtensionRange.Size(m) +} +func (m *DescriptorProto_ExtensionRange) XXX_DiscardUnknown() { + xxx_messageInfo_DescriptorProto_ExtensionRange.DiscardUnknown(m) +} + +var xxx_messageInfo_DescriptorProto_ExtensionRange proto.InternalMessageInfo func (m *DescriptorProto_ExtensionRange) GetStart() int32 { if m != nil && m.Start != nil { @@ -606,17 +667,36 @@ func (m *DescriptorProto_ExtensionRange) GetOptions() *ExtensionRangeOptions { // fields or extension ranges in the same message. Reserved ranges may // not overlap. type DescriptorProto_ReservedRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - XXX_unrecognized []byte `json:"-"` + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *DescriptorProto_ReservedRange) Reset() { *m = DescriptorProto_ReservedRange{} } func (m *DescriptorProto_ReservedRange) String() string { return proto.CompactTextString(m) } func (*DescriptorProto_ReservedRange) ProtoMessage() {} func (*DescriptorProto_ReservedRange) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{2, 1} + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{2, 1} } +func (m *DescriptorProto_ReservedRange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DescriptorProto_ReservedRange.Unmarshal(m, b) +} +func (m *DescriptorProto_ReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DescriptorProto_ReservedRange.Marshal(b, m, deterministic) +} +func (dst *DescriptorProto_ReservedRange) XXX_Merge(src proto.Message) { + xxx_messageInfo_DescriptorProto_ReservedRange.Merge(dst, src) +} +func (m *DescriptorProto_ReservedRange) XXX_Size() int { + return xxx_messageInfo_DescriptorProto_ReservedRange.Size(m) +} +func (m *DescriptorProto_ReservedRange) XXX_DiscardUnknown() { + xxx_messageInfo_DescriptorProto_ReservedRange.DiscardUnknown(m) +} + +var xxx_messageInfo_DescriptorProto_ReservedRange proto.InternalMessageInfo func (m *DescriptorProto_ReservedRange) GetStart() int32 { if m != nil && m.Start != nil { @@ -635,22 +715,43 @@ func (m *DescriptorProto_ReservedRange) GetEnd() int32 { type ExtensionRangeOptions struct { // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ExtensionRangeOptions) Reset() { *m = ExtensionRangeOptions{} } -func (m *ExtensionRangeOptions) String() string { return proto.CompactTextString(m) } -func (*ExtensionRangeOptions) ProtoMessage() {} -func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (m *ExtensionRangeOptions) Reset() { *m = ExtensionRangeOptions{} } +func (m *ExtensionRangeOptions) String() string { return proto.CompactTextString(m) } +func (*ExtensionRangeOptions) ProtoMessage() {} +func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{3} +} var extRange_ExtensionRangeOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*ExtensionRangeOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_ExtensionRangeOptions } +func (m *ExtensionRangeOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExtensionRangeOptions.Unmarshal(m, b) +} +func (m *ExtensionRangeOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExtensionRangeOptions.Marshal(b, m, deterministic) +} +func (dst *ExtensionRangeOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtensionRangeOptions.Merge(dst, src) +} +func (m *ExtensionRangeOptions) XXX_Size() int { + return xxx_messageInfo_ExtensionRangeOptions.Size(m) +} +func (m *ExtensionRangeOptions) XXX_DiscardUnknown() { + xxx_messageInfo_ExtensionRangeOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtensionRangeOptions proto.InternalMessageInfo func (m *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption { if m != nil { @@ -689,15 +790,36 @@ type FieldDescriptorProto struct { // user has set a "json_name" option on this field, that option's value // will be used. Otherwise, it's deduced from the field's name by converting // it to camelCase. - JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` - Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` + Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } -func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*FieldDescriptorProto) ProtoMessage() {} -func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } +func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } +func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*FieldDescriptorProto) ProtoMessage() {} +func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{4} +} +func (m *FieldDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FieldDescriptorProto.Unmarshal(m, b) +} +func (m *FieldDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FieldDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *FieldDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_FieldDescriptorProto.Merge(dst, src) +} +func (m *FieldDescriptorProto) XXX_Size() int { + return xxx_messageInfo_FieldDescriptorProto.Size(m) +} +func (m *FieldDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_FieldDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_FieldDescriptorProto proto.InternalMessageInfo func (m *FieldDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -771,15 +893,36 @@ func (m *FieldDescriptorProto) GetOptions() *FieldOptions { // Describes a oneof. type OneofDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } -func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*OneofDescriptorProto) ProtoMessage() {} -func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } +func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } +func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*OneofDescriptorProto) ProtoMessage() {} +func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{5} +} +func (m *OneofDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OneofDescriptorProto.Unmarshal(m, b) +} +func (m *OneofDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OneofDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *OneofDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_OneofDescriptorProto.Merge(dst, src) +} +func (m *OneofDescriptorProto) XXX_Size() int { + return xxx_messageInfo_OneofDescriptorProto.Size(m) +} +func (m *OneofDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_OneofDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_OneofDescriptorProto proto.InternalMessageInfo func (m *OneofDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -797,16 +940,44 @@ func (m *OneofDescriptorProto) GetOptions() *OneofOptions { // Describes an enum type. type EnumDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` - Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` + Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + ReservedRange []*EnumDescriptorProto_EnumReservedRange `protobuf:"bytes,4,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + ReservedName []string `protobuf:"bytes,5,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } -func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*EnumDescriptorProto) ProtoMessage() {} -func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } +func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } +func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*EnumDescriptorProto) ProtoMessage() {} +func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{6} +} +func (m *EnumDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumDescriptorProto.Unmarshal(m, b) +} +func (m *EnumDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *EnumDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumDescriptorProto.Merge(dst, src) +} +func (m *EnumDescriptorProto) XXX_Size() int { + return xxx_messageInfo_EnumDescriptorProto.Size(m) +} +func (m *EnumDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_EnumDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumDescriptorProto proto.InternalMessageInfo func (m *EnumDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -829,18 +1000,105 @@ func (m *EnumDescriptorProto) GetOptions() *EnumOptions { return nil } -// Describes a value within an enum. -type EnumValueDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` - Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` +func (m *EnumDescriptorProto) GetReservedRange() []*EnumDescriptorProto_EnumReservedRange { + if m != nil { + return m.ReservedRange + } + return nil } -func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } -func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*EnumValueDescriptorProto) ProtoMessage() {} -func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } +func (m *EnumDescriptorProto) GetReservedName() []string { + if m != nil { + return m.ReservedName + } + return nil +} + +// Range of reserved numeric values. Reserved values may not be used by +// entries in the same enum. Reserved ranges may not overlap. +// +// Note that this is distinct from DescriptorProto.ReservedRange in that it +// is inclusive such that it can appropriately represent the entire int32 +// domain. +type EnumDescriptorProto_EnumReservedRange struct { + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EnumDescriptorProto_EnumReservedRange) Reset() { *m = EnumDescriptorProto_EnumReservedRange{} } +func (m *EnumDescriptorProto_EnumReservedRange) String() string { return proto.CompactTextString(m) } +func (*EnumDescriptorProto_EnumReservedRange) ProtoMessage() {} +func (*EnumDescriptorProto_EnumReservedRange) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{6, 0} +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Unmarshal(m, b) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Marshal(b, m, deterministic) +} +func (dst *EnumDescriptorProto_EnumReservedRange) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Merge(dst, src) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Size() int { + return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Size(m) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_DiscardUnknown() { + xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumDescriptorProto_EnumReservedRange proto.InternalMessageInfo + +func (m *EnumDescriptorProto_EnumReservedRange) GetStart() int32 { + if m != nil && m.Start != nil { + return *m.Start + } + return 0 +} + +func (m *EnumDescriptorProto_EnumReservedRange) GetEnd() int32 { + if m != nil && m.End != nil { + return *m.End + } + return 0 +} + +// Describes a value within an enum. +type EnumValueDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` + Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } +func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*EnumValueDescriptorProto) ProtoMessage() {} +func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{7} +} +func (m *EnumValueDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumValueDescriptorProto.Unmarshal(m, b) +} +func (m *EnumValueDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumValueDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *EnumValueDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumValueDescriptorProto.Merge(dst, src) +} +func (m *EnumValueDescriptorProto) XXX_Size() int { + return xxx_messageInfo_EnumValueDescriptorProto.Size(m) +} +func (m *EnumValueDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_EnumValueDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumValueDescriptorProto proto.InternalMessageInfo func (m *EnumValueDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -865,16 +1123,37 @@ func (m *EnumValueDescriptorProto) GetOptions() *EnumValueOptions { // Describes a service. type ServiceDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"` - Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"` + Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } -func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*ServiceDescriptorProto) ProtoMessage() {} -func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } +func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } +func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*ServiceDescriptorProto) ProtoMessage() {} +func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{8} +} +func (m *ServiceDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ServiceDescriptorProto.Unmarshal(m, b) +} +func (m *ServiceDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ServiceDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *ServiceDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceDescriptorProto.Merge(dst, src) +} +func (m *ServiceDescriptorProto) XXX_Size() int { + return xxx_messageInfo_ServiceDescriptorProto.Size(m) +} +func (m *ServiceDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceDescriptorProto proto.InternalMessageInfo func (m *ServiceDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -908,14 +1187,35 @@ type MethodDescriptorProto struct { // Identifies if client streams multiple client messages ClientStreaming *bool `protobuf:"varint,5,opt,name=client_streaming,json=clientStreaming,def=0" json:"client_streaming,omitempty"` // Identifies if server streams multiple server messages - ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"` - XXX_unrecognized []byte `json:"-"` + ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } -func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*MethodDescriptorProto) ProtoMessage() {} -func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } +func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } +func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*MethodDescriptorProto) ProtoMessage() {} +func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{9} +} +func (m *MethodDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MethodDescriptorProto.Unmarshal(m, b) +} +func (m *MethodDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MethodDescriptorProto.Marshal(b, m, deterministic) +} +func (dst *MethodDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_MethodDescriptorProto.Merge(dst, src) +} +func (m *MethodDescriptorProto) XXX_Size() int { + return xxx_messageInfo_MethodDescriptorProto.Size(m) +} +func (m *MethodDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_MethodDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_MethodDescriptorProto proto.InternalMessageInfo const Default_MethodDescriptorProto_ClientStreaming bool = false const Default_MethodDescriptorProto_ServerStreaming bool = false @@ -982,7 +1282,7 @@ type FileOptions struct { // top-level extensions defined in the file. JavaMultipleFiles *bool `protobuf:"varint,10,opt,name=java_multiple_files,json=javaMultipleFiles,def=0" json:"java_multiple_files,omitempty"` // This option does nothing. - JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` + JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` // Deprecated: Do not use. // If set true, then the Java2 code generator will generate code that // throws an exception whenever an attempt is made to assign a non-UTF-8 // byte sequence to a string field. @@ -1036,24 +1336,46 @@ type FileOptions struct { // is empty. When this option is empty, the package name will be used for // determining the namespace. PhpNamespace *string `protobuf:"bytes,41,opt,name=php_namespace,json=phpNamespace" json:"php_namespace,omitempty"` - // The parser stores options it doesn't recognize here. See above. + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FileOptions) Reset() { *m = FileOptions{} } -func (m *FileOptions) String() string { return proto.CompactTextString(m) } -func (*FileOptions) ProtoMessage() {} -func (*FileOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } +func (m *FileOptions) Reset() { *m = FileOptions{} } +func (m *FileOptions) String() string { return proto.CompactTextString(m) } +func (*FileOptions) ProtoMessage() {} +func (*FileOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{10} +} var extRange_FileOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*FileOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_FileOptions } +func (m *FileOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileOptions.Unmarshal(m, b) +} +func (m *FileOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileOptions.Marshal(b, m, deterministic) +} +func (dst *FileOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileOptions.Merge(dst, src) +} +func (m *FileOptions) XXX_Size() int { + return xxx_messageInfo_FileOptions.Size(m) +} +func (m *FileOptions) XXX_DiscardUnknown() { + xxx_messageInfo_FileOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_FileOptions proto.InternalMessageInfo const Default_FileOptions_JavaMultipleFiles bool = false const Default_FileOptions_JavaStringCheckUtf8 bool = false @@ -1086,6 +1408,7 @@ func (m *FileOptions) GetJavaMultipleFiles() bool { return Default_FileOptions_JavaMultipleFiles } +// Deprecated: Do not use. func (m *FileOptions) GetJavaGenerateEqualsAndHash() bool { if m != nil && m.JavaGenerateEqualsAndHash != nil { return *m.JavaGenerateEqualsAndHash @@ -1251,22 +1574,43 @@ type MessageOptions struct { MapEntry *bool `protobuf:"varint,7,opt,name=map_entry,json=mapEntry" json:"map_entry,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MessageOptions) Reset() { *m = MessageOptions{} } -func (m *MessageOptions) String() string { return proto.CompactTextString(m) } -func (*MessageOptions) ProtoMessage() {} -func (*MessageOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } +func (m *MessageOptions) Reset() { *m = MessageOptions{} } +func (m *MessageOptions) String() string { return proto.CompactTextString(m) } +func (*MessageOptions) ProtoMessage() {} +func (*MessageOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{11} +} var extRange_MessageOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*MessageOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_MessageOptions } +func (m *MessageOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MessageOptions.Unmarshal(m, b) +} +func (m *MessageOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MessageOptions.Marshal(b, m, deterministic) +} +func (dst *MessageOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_MessageOptions.Merge(dst, src) +} +func (m *MessageOptions) XXX_Size() int { + return xxx_messageInfo_MessageOptions.Size(m) +} +func (m *MessageOptions) XXX_DiscardUnknown() { + xxx_messageInfo_MessageOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_MessageOptions proto.InternalMessageInfo const Default_MessageOptions_MessageSetWireFormat bool = false const Default_MessageOptions_NoStandardDescriptorAccessor bool = false @@ -1369,22 +1713,43 @@ type FieldOptions struct { Weak *bool `protobuf:"varint,10,opt,name=weak,def=0" json:"weak,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FieldOptions) Reset() { *m = FieldOptions{} } -func (m *FieldOptions) String() string { return proto.CompactTextString(m) } -func (*FieldOptions) ProtoMessage() {} -func (*FieldOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } +func (m *FieldOptions) Reset() { *m = FieldOptions{} } +func (m *FieldOptions) String() string { return proto.CompactTextString(m) } +func (*FieldOptions) ProtoMessage() {} +func (*FieldOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{12} +} var extRange_FieldOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*FieldOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_FieldOptions } +func (m *FieldOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FieldOptions.Unmarshal(m, b) +} +func (m *FieldOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FieldOptions.Marshal(b, m, deterministic) +} +func (dst *FieldOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_FieldOptions.Merge(dst, src) +} +func (m *FieldOptions) XXX_Size() int { + return xxx_messageInfo_FieldOptions.Size(m) +} +func (m *FieldOptions) XXX_DiscardUnknown() { + xxx_messageInfo_FieldOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_FieldOptions proto.InternalMessageInfo const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING const Default_FieldOptions_Jstype FieldOptions_JSType = FieldOptions_JS_NORMAL @@ -1444,22 +1809,43 @@ func (m *FieldOptions) GetUninterpretedOption() []*UninterpretedOption { type OneofOptions struct { // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *OneofOptions) Reset() { *m = OneofOptions{} } -func (m *OneofOptions) String() string { return proto.CompactTextString(m) } -func (*OneofOptions) ProtoMessage() {} -func (*OneofOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } +func (m *OneofOptions) Reset() { *m = OneofOptions{} } +func (m *OneofOptions) String() string { return proto.CompactTextString(m) } +func (*OneofOptions) ProtoMessage() {} +func (*OneofOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{13} +} var extRange_OneofOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*OneofOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_OneofOptions } +func (m *OneofOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OneofOptions.Unmarshal(m, b) +} +func (m *OneofOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OneofOptions.Marshal(b, m, deterministic) +} +func (dst *OneofOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_OneofOptions.Merge(dst, src) +} +func (m *OneofOptions) XXX_Size() int { + return xxx_messageInfo_OneofOptions.Size(m) +} +func (m *OneofOptions) XXX_DiscardUnknown() { + xxx_messageInfo_OneofOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_OneofOptions proto.InternalMessageInfo func (m *OneofOptions) GetUninterpretedOption() []*UninterpretedOption { if m != nil { @@ -1479,22 +1865,43 @@ type EnumOptions struct { Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *EnumOptions) Reset() { *m = EnumOptions{} } -func (m *EnumOptions) String() string { return proto.CompactTextString(m) } -func (*EnumOptions) ProtoMessage() {} -func (*EnumOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } +func (m *EnumOptions) Reset() { *m = EnumOptions{} } +func (m *EnumOptions) String() string { return proto.CompactTextString(m) } +func (*EnumOptions) ProtoMessage() {} +func (*EnumOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{14} +} var extRange_EnumOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*EnumOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_EnumOptions } +func (m *EnumOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumOptions.Unmarshal(m, b) +} +func (m *EnumOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumOptions.Marshal(b, m, deterministic) +} +func (dst *EnumOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumOptions.Merge(dst, src) +} +func (m *EnumOptions) XXX_Size() int { + return xxx_messageInfo_EnumOptions.Size(m) +} +func (m *EnumOptions) XXX_DiscardUnknown() { + xxx_messageInfo_EnumOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumOptions proto.InternalMessageInfo const Default_EnumOptions_Deprecated bool = false @@ -1527,22 +1934,43 @@ type EnumValueOptions struct { Deprecated *bool `protobuf:"varint,1,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } -func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } -func (*EnumValueOptions) ProtoMessage() {} -func (*EnumValueOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } +func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } +func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } +func (*EnumValueOptions) ProtoMessage() {} +func (*EnumValueOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{15} +} var extRange_EnumValueOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*EnumValueOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_EnumValueOptions } +func (m *EnumValueOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumValueOptions.Unmarshal(m, b) +} +func (m *EnumValueOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumValueOptions.Marshal(b, m, deterministic) +} +func (dst *EnumValueOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumValueOptions.Merge(dst, src) +} +func (m *EnumValueOptions) XXX_Size() int { + return xxx_messageInfo_EnumValueOptions.Size(m) +} +func (m *EnumValueOptions) XXX_DiscardUnknown() { + xxx_messageInfo_EnumValueOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumValueOptions proto.InternalMessageInfo const Default_EnumValueOptions_Deprecated bool = false @@ -1568,22 +1996,43 @@ type ServiceOptions struct { Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } -func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } -func (*ServiceOptions) ProtoMessage() {} -func (*ServiceOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } +func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } +func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } +func (*ServiceOptions) ProtoMessage() {} +func (*ServiceOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{16} +} var extRange_ServiceOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*ServiceOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_ServiceOptions } +func (m *ServiceOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ServiceOptions.Unmarshal(m, b) +} +func (m *ServiceOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ServiceOptions.Marshal(b, m, deterministic) +} +func (dst *ServiceOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceOptions.Merge(dst, src) +} +func (m *ServiceOptions) XXX_Size() int { + return xxx_messageInfo_ServiceOptions.Size(m) +} +func (m *ServiceOptions) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceOptions proto.InternalMessageInfo const Default_ServiceOptions_Deprecated bool = false @@ -1610,22 +2059,43 @@ type MethodOptions struct { IdempotencyLevel *MethodOptions_IdempotencyLevel `protobuf:"varint,34,opt,name=idempotency_level,json=idempotencyLevel,enum=google.protobuf.MethodOptions_IdempotencyLevel,def=0" json:"idempotency_level,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MethodOptions) Reset() { *m = MethodOptions{} } -func (m *MethodOptions) String() string { return proto.CompactTextString(m) } -func (*MethodOptions) ProtoMessage() {} -func (*MethodOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } +func (m *MethodOptions) Reset() { *m = MethodOptions{} } +func (m *MethodOptions) String() string { return proto.CompactTextString(m) } +func (*MethodOptions) ProtoMessage() {} +func (*MethodOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{17} +} var extRange_MethodOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*MethodOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_MethodOptions } +func (m *MethodOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MethodOptions.Unmarshal(m, b) +} +func (m *MethodOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MethodOptions.Marshal(b, m, deterministic) +} +func (dst *MethodOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_MethodOptions.Merge(dst, src) +} +func (m *MethodOptions) XXX_Size() int { + return xxx_messageInfo_MethodOptions.Size(m) +} +func (m *MethodOptions) XXX_DiscardUnknown() { + xxx_messageInfo_MethodOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_MethodOptions proto.InternalMessageInfo const Default_MethodOptions_Deprecated bool = false const Default_MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel = MethodOptions_IDEMPOTENCY_UNKNOWN @@ -1661,19 +2131,40 @@ type UninterpretedOption struct { Name []*UninterpretedOption_NamePart `protobuf:"bytes,2,rep,name=name" json:"name,omitempty"` // The value of the uninterpreted option, in whatever type the tokenizer // identified it as during parsing. Exactly one of these should be set. - IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"` - PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"` - NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"` - DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` - StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` - AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"` - XXX_unrecognized []byte `json:"-"` + IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"` + PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"` + NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"` + DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` + StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` + AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } -func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } -func (*UninterpretedOption) ProtoMessage() {} -func (*UninterpretedOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } +func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } +func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } +func (*UninterpretedOption) ProtoMessage() {} +func (*UninterpretedOption) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{18} +} +func (m *UninterpretedOption) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UninterpretedOption.Unmarshal(m, b) +} +func (m *UninterpretedOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UninterpretedOption.Marshal(b, m, deterministic) +} +func (dst *UninterpretedOption) XXX_Merge(src proto.Message) { + xxx_messageInfo_UninterpretedOption.Merge(dst, src) +} +func (m *UninterpretedOption) XXX_Size() int { + return xxx_messageInfo_UninterpretedOption.Size(m) +} +func (m *UninterpretedOption) XXX_DiscardUnknown() { + xxx_messageInfo_UninterpretedOption.DiscardUnknown(m) +} + +var xxx_messageInfo_UninterpretedOption proto.InternalMessageInfo func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart { if m != nil { @@ -1730,17 +2221,36 @@ func (m *UninterpretedOption) GetAggregateValue() string { // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents // "foo.(bar.baz).qux". type UninterpretedOption_NamePart struct { - NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"` - IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"` - XXX_unrecognized []byte `json:"-"` + NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"` + IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *UninterpretedOption_NamePart) Reset() { *m = UninterpretedOption_NamePart{} } func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) } func (*UninterpretedOption_NamePart) ProtoMessage() {} func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{18, 0} + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{18, 0} } +func (m *UninterpretedOption_NamePart) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UninterpretedOption_NamePart.Unmarshal(m, b) +} +func (m *UninterpretedOption_NamePart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UninterpretedOption_NamePart.Marshal(b, m, deterministic) +} +func (dst *UninterpretedOption_NamePart) XXX_Merge(src proto.Message) { + xxx_messageInfo_UninterpretedOption_NamePart.Merge(dst, src) +} +func (m *UninterpretedOption_NamePart) XXX_Size() int { + return xxx_messageInfo_UninterpretedOption_NamePart.Size(m) +} +func (m *UninterpretedOption_NamePart) XXX_DiscardUnknown() { + xxx_messageInfo_UninterpretedOption_NamePart.DiscardUnknown(m) +} + +var xxx_messageInfo_UninterpretedOption_NamePart proto.InternalMessageInfo func (m *UninterpretedOption_NamePart) GetNamePart() string { if m != nil && m.NamePart != nil { @@ -1802,14 +2312,35 @@ type SourceCodeInfo struct { // - Code which tries to interpret locations should probably be designed to // ignore those that it doesn't understand, as more types of locations could // be recorded in the future. - Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` - XXX_unrecognized []byte `json:"-"` + Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } -func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } -func (*SourceCodeInfo) ProtoMessage() {} -func (*SourceCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } +func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } +func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } +func (*SourceCodeInfo) ProtoMessage() {} +func (*SourceCodeInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{19} +} +func (m *SourceCodeInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SourceCodeInfo.Unmarshal(m, b) +} +func (m *SourceCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SourceCodeInfo.Marshal(b, m, deterministic) +} +func (dst *SourceCodeInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_SourceCodeInfo.Merge(dst, src) +} +func (m *SourceCodeInfo) XXX_Size() int { + return xxx_messageInfo_SourceCodeInfo.Size(m) +} +func (m *SourceCodeInfo) XXX_DiscardUnknown() { + xxx_messageInfo_SourceCodeInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_SourceCodeInfo proto.InternalMessageInfo func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location { if m != nil { @@ -1899,13 +2430,34 @@ type SourceCodeInfo_Location struct { LeadingComments *string `protobuf:"bytes,3,opt,name=leading_comments,json=leadingComments" json:"leading_comments,omitempty"` TrailingComments *string `protobuf:"bytes,4,opt,name=trailing_comments,json=trailingComments" json:"trailing_comments,omitempty"` LeadingDetachedComments []string `protobuf:"bytes,6,rep,name=leading_detached_comments,json=leadingDetachedComments" json:"leading_detached_comments,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } -func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } -func (*SourceCodeInfo_Location) ProtoMessage() {} -func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19, 0} } +func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } +func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } +func (*SourceCodeInfo_Location) ProtoMessage() {} +func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{19, 0} +} +func (m *SourceCodeInfo_Location) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SourceCodeInfo_Location.Unmarshal(m, b) +} +func (m *SourceCodeInfo_Location) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SourceCodeInfo_Location.Marshal(b, m, deterministic) +} +func (dst *SourceCodeInfo_Location) XXX_Merge(src proto.Message) { + xxx_messageInfo_SourceCodeInfo_Location.Merge(dst, src) +} +func (m *SourceCodeInfo_Location) XXX_Size() int { + return xxx_messageInfo_SourceCodeInfo_Location.Size(m) +} +func (m *SourceCodeInfo_Location) XXX_DiscardUnknown() { + xxx_messageInfo_SourceCodeInfo_Location.DiscardUnknown(m) +} + +var xxx_messageInfo_SourceCodeInfo_Location proto.InternalMessageInfo func (m *SourceCodeInfo_Location) GetPath() []int32 { if m != nil { @@ -1948,14 +2500,35 @@ func (m *SourceCodeInfo_Location) GetLeadingDetachedComments() []string { type GeneratedCodeInfo struct { // An Annotation connects some span of text in generated code to an element // of its generating .proto file. - Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"` - XXX_unrecognized []byte `json:"-"` + Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } -func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } -func (*GeneratedCodeInfo) ProtoMessage() {} -func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } +func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } +func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } +func (*GeneratedCodeInfo) ProtoMessage() {} +func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{20} +} +func (m *GeneratedCodeInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GeneratedCodeInfo.Unmarshal(m, b) +} +func (m *GeneratedCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GeneratedCodeInfo.Marshal(b, m, deterministic) +} +func (dst *GeneratedCodeInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeneratedCodeInfo.Merge(dst, src) +} +func (m *GeneratedCodeInfo) XXX_Size() int { + return xxx_messageInfo_GeneratedCodeInfo.Size(m) +} +func (m *GeneratedCodeInfo) XXX_DiscardUnknown() { + xxx_messageInfo_GeneratedCodeInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_GeneratedCodeInfo proto.InternalMessageInfo func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation { if m != nil { @@ -1976,16 +2549,35 @@ type GeneratedCodeInfo_Annotation struct { // Identifies the ending offset in bytes in the generated code that // relates to the identified offset. The end offset should be one past // the last relevant byte (so the length of the text = end - begin). - End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"` - XXX_unrecognized []byte `json:"-"` + End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *GeneratedCodeInfo_Annotation) Reset() { *m = GeneratedCodeInfo_Annotation{} } func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) } func (*GeneratedCodeInfo_Annotation) ProtoMessage() {} func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{20, 0} + return fileDescriptor_descriptor_4df4cb5f42392df6, []int{20, 0} } +func (m *GeneratedCodeInfo_Annotation) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GeneratedCodeInfo_Annotation.Unmarshal(m, b) +} +func (m *GeneratedCodeInfo_Annotation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GeneratedCodeInfo_Annotation.Marshal(b, m, deterministic) +} +func (dst *GeneratedCodeInfo_Annotation) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeneratedCodeInfo_Annotation.Merge(dst, src) +} +func (m *GeneratedCodeInfo_Annotation) XXX_Size() int { + return xxx_messageInfo_GeneratedCodeInfo_Annotation.Size(m) +} +func (m *GeneratedCodeInfo_Annotation) XXX_DiscardUnknown() { + xxx_messageInfo_GeneratedCodeInfo_Annotation.DiscardUnknown(m) +} + +var xxx_messageInfo_GeneratedCodeInfo_Annotation proto.InternalMessageInfo func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 { if m != nil { @@ -2025,6 +2617,7 @@ func init() { proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto") proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto") proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto") + proto.RegisterType((*EnumDescriptorProto_EnumReservedRange)(nil), "google.protobuf.EnumDescriptorProto.EnumReservedRange") proto.RegisterType((*EnumValueDescriptorProto)(nil), "google.protobuf.EnumValueDescriptorProto") proto.RegisterType((*ServiceDescriptorProto)(nil), "google.protobuf.ServiceDescriptorProto") proto.RegisterType((*MethodDescriptorProto)(nil), "google.protobuf.MethodDescriptorProto") @@ -2050,166 +2643,170 @@ func init() { proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value) } -func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 2519 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x6e, 0x1b, 0xc7, - 0x15, 0x0e, 0x7f, 0x45, 0x1e, 0x52, 0xd4, 0x68, 0xa4, 0xd8, 0x6b, 0xe5, 0xc7, 0x32, 0xf3, 0x63, - 0xd9, 0x69, 0xa8, 0x40, 0xb1, 0x1d, 0x47, 0x29, 0xd2, 0x52, 0xe4, 0x5a, 0xa1, 0x4a, 0x91, 0xec, - 0x92, 0x6a, 0x7e, 0x6e, 0x16, 0xa3, 0xdd, 0x21, 0xb9, 0xf6, 0x72, 0x77, 0xb3, 0xbb, 0xb4, 0xad, - 0xa0, 0x17, 0x06, 0x7a, 0x55, 0xa0, 0x0f, 0x50, 0x14, 0x45, 0x2f, 0x72, 0x13, 0xa0, 0x0f, 0x50, - 0x20, 0x77, 0x7d, 0x82, 0x02, 0x79, 0x83, 0xa2, 0x28, 0xd0, 0x3e, 0x46, 0x31, 0x33, 0xbb, 0xcb, - 0x5d, 0xfe, 0xc4, 0x6a, 0x80, 0x38, 0x57, 0xe4, 0x7c, 0xe7, 0x3b, 0x67, 0xce, 0x9c, 0x39, 0x33, - 0x73, 0x66, 0x16, 0x76, 0x47, 0xb6, 0x3d, 0x32, 0xe9, 0xbe, 0xe3, 0xda, 0xbe, 0x7d, 0x3e, 0x1d, - 0xee, 0xeb, 0xd4, 0xd3, 0x5c, 0xc3, 0xf1, 0x6d, 0xb7, 0xc6, 0x31, 0xbc, 0x21, 0x18, 0xb5, 0x90, - 0x51, 0x3d, 0x85, 0xcd, 0x07, 0x86, 0x49, 0x9b, 0x11, 0xb1, 0x4f, 0x7d, 0x7c, 0x1f, 0xb2, 0x43, - 0xc3, 0xa4, 0x52, 0x6a, 0x37, 0xb3, 0x57, 0x3a, 0x78, 0xb3, 0x36, 0xa7, 0x54, 0x4b, 0x6a, 0xf4, - 0x18, 0xac, 0x70, 0x8d, 0xea, 0xbf, 0xb3, 0xb0, 0xb5, 0x44, 0x8a, 0x31, 0x64, 0x2d, 0x32, 0x61, - 0x16, 0x53, 0x7b, 0x45, 0x85, 0xff, 0xc7, 0x12, 0xac, 0x39, 0x44, 0x7b, 0x44, 0x46, 0x54, 0x4a, - 0x73, 0x38, 0x6c, 0xe2, 0xd7, 0x01, 0x74, 0xea, 0x50, 0x4b, 0xa7, 0x96, 0x76, 0x21, 0x65, 0x76, - 0x33, 0x7b, 0x45, 0x25, 0x86, 0xe0, 0x77, 0x60, 0xd3, 0x99, 0x9e, 0x9b, 0x86, 0xa6, 0xc6, 0x68, - 0xb0, 0x9b, 0xd9, 0xcb, 0x29, 0x48, 0x08, 0x9a, 0x33, 0xf2, 0x4d, 0xd8, 0x78, 0x42, 0xc9, 0xa3, - 0x38, 0xb5, 0xc4, 0xa9, 0x15, 0x06, 0xc7, 0x88, 0x0d, 0x28, 0x4f, 0xa8, 0xe7, 0x91, 0x11, 0x55, - 0xfd, 0x0b, 0x87, 0x4a, 0x59, 0x3e, 0xfa, 0xdd, 0x85, 0xd1, 0xcf, 0x8f, 0xbc, 0x14, 0x68, 0x0d, - 0x2e, 0x1c, 0x8a, 0xeb, 0x50, 0xa4, 0xd6, 0x74, 0x22, 0x2c, 0xe4, 0x56, 0xc4, 0x4f, 0xb6, 0xa6, - 0x93, 0x79, 0x2b, 0x05, 0xa6, 0x16, 0x98, 0x58, 0xf3, 0xa8, 0xfb, 0xd8, 0xd0, 0xa8, 0x94, 0xe7, - 0x06, 0x6e, 0x2e, 0x18, 0xe8, 0x0b, 0xf9, 0xbc, 0x8d, 0x50, 0x0f, 0x37, 0xa0, 0x48, 0x9f, 0xfa, - 0xd4, 0xf2, 0x0c, 0xdb, 0x92, 0xd6, 0xb8, 0x91, 0xb7, 0x96, 0xcc, 0x22, 0x35, 0xf5, 0x79, 0x13, - 0x33, 0x3d, 0x7c, 0x0f, 0xd6, 0x6c, 0xc7, 0x37, 0x6c, 0xcb, 0x93, 0x0a, 0xbb, 0xa9, 0xbd, 0xd2, - 0xc1, 0xab, 0x4b, 0x13, 0xa1, 0x2b, 0x38, 0x4a, 0x48, 0xc6, 0x2d, 0x40, 0x9e, 0x3d, 0x75, 0x35, - 0xaa, 0x6a, 0xb6, 0x4e, 0x55, 0xc3, 0x1a, 0xda, 0x52, 0x91, 0x1b, 0xb8, 0xbe, 0x38, 0x10, 0x4e, - 0x6c, 0xd8, 0x3a, 0x6d, 0x59, 0x43, 0x5b, 0xa9, 0x78, 0x89, 0x36, 0xbe, 0x02, 0x79, 0xef, 0xc2, - 0xf2, 0xc9, 0x53, 0xa9, 0xcc, 0x33, 0x24, 0x68, 0x55, 0xbf, 0xcd, 0xc3, 0xc6, 0x65, 0x52, 0xec, - 0x23, 0xc8, 0x0d, 0xd9, 0x28, 0xa5, 0xf4, 0xff, 0x13, 0x03, 0xa1, 0x93, 0x0c, 0x62, 0xfe, 0x07, - 0x06, 0xb1, 0x0e, 0x25, 0x8b, 0x7a, 0x3e, 0xd5, 0x45, 0x46, 0x64, 0x2e, 0x99, 0x53, 0x20, 0x94, - 0x16, 0x53, 0x2a, 0xfb, 0x83, 0x52, 0xea, 0x33, 0xd8, 0x88, 0x5c, 0x52, 0x5d, 0x62, 0x8d, 0xc2, - 0xdc, 0xdc, 0x7f, 0x9e, 0x27, 0x35, 0x39, 0xd4, 0x53, 0x98, 0x9a, 0x52, 0xa1, 0x89, 0x36, 0x6e, - 0x02, 0xd8, 0x16, 0xb5, 0x87, 0xaa, 0x4e, 0x35, 0x53, 0x2a, 0xac, 0x88, 0x52, 0x97, 0x51, 0x16, - 0xa2, 0x64, 0x0b, 0x54, 0x33, 0xf1, 0x87, 0xb3, 0x54, 0x5b, 0x5b, 0x91, 0x29, 0xa7, 0x62, 0x91, - 0x2d, 0x64, 0xdb, 0x19, 0x54, 0x5c, 0xca, 0xf2, 0x9e, 0xea, 0xc1, 0xc8, 0x8a, 0xdc, 0x89, 0xda, - 0x73, 0x47, 0xa6, 0x04, 0x6a, 0x62, 0x60, 0xeb, 0x6e, 0xbc, 0x89, 0xdf, 0x80, 0x08, 0x50, 0x79, - 0x5a, 0x01, 0xdf, 0x85, 0xca, 0x21, 0xd8, 0x21, 0x13, 0xba, 0xf3, 0x15, 0x54, 0x92, 0xe1, 0xc1, - 0xdb, 0x90, 0xf3, 0x7c, 0xe2, 0xfa, 0x3c, 0x0b, 0x73, 0x8a, 0x68, 0x60, 0x04, 0x19, 0x6a, 0xe9, - 0x7c, 0x97, 0xcb, 0x29, 0xec, 0x2f, 0xfe, 0xe5, 0x6c, 0xc0, 0x19, 0x3e, 0xe0, 0xb7, 0x17, 0x67, - 0x34, 0x61, 0x79, 0x7e, 0xdc, 0x3b, 0x1f, 0xc0, 0x7a, 0x62, 0x00, 0x97, 0xed, 0xba, 0xfa, 0x5b, - 0x78, 0x79, 0xa9, 0x69, 0xfc, 0x19, 0x6c, 0x4f, 0x2d, 0xc3, 0xf2, 0xa9, 0xeb, 0xb8, 0x94, 0x65, - 0xac, 0xe8, 0x4a, 0xfa, 0xcf, 0xda, 0x8a, 0x9c, 0x3b, 0x8b, 0xb3, 0x85, 0x15, 0x65, 0x6b, 0xba, - 0x08, 0xde, 0x2e, 0x16, 0xfe, 0xbb, 0x86, 0x9e, 0x3d, 0x7b, 0xf6, 0x2c, 0x5d, 0xfd, 0x63, 0x1e, - 0xb6, 0x97, 0xad, 0x99, 0xa5, 0xcb, 0xf7, 0x0a, 0xe4, 0xad, 0xe9, 0xe4, 0x9c, 0xba, 0x3c, 0x48, - 0x39, 0x25, 0x68, 0xe1, 0x3a, 0xe4, 0x4c, 0x72, 0x4e, 0x4d, 0x29, 0xbb, 0x9b, 0xda, 0xab, 0x1c, - 0xbc, 0x73, 0xa9, 0x55, 0x59, 0x6b, 0x33, 0x15, 0x45, 0x68, 0xe2, 0x8f, 0x21, 0x1b, 0x6c, 0xd1, - 0xcc, 0xc2, 0xed, 0xcb, 0x59, 0x60, 0x6b, 0x49, 0xe1, 0x7a, 0xf8, 0x15, 0x28, 0xb2, 0x5f, 0x91, - 0x1b, 0x79, 0xee, 0x73, 0x81, 0x01, 0x2c, 0x2f, 0xf0, 0x0e, 0x14, 0xf8, 0x32, 0xd1, 0x69, 0x78, - 0xb4, 0x45, 0x6d, 0x96, 0x58, 0x3a, 0x1d, 0x92, 0xa9, 0xe9, 0xab, 0x8f, 0x89, 0x39, 0xa5, 0x3c, - 0xe1, 0x8b, 0x4a, 0x39, 0x00, 0x7f, 0xc3, 0x30, 0x7c, 0x1d, 0x4a, 0x62, 0x55, 0x19, 0x96, 0x4e, - 0x9f, 0xf2, 0xdd, 0x33, 0xa7, 0x88, 0x85, 0xd6, 0x62, 0x08, 0xeb, 0xfe, 0xa1, 0x67, 0x5b, 0x61, - 0x6a, 0xf2, 0x2e, 0x18, 0xc0, 0xbb, 0xff, 0x60, 0x7e, 0xe3, 0x7e, 0x6d, 0xf9, 0xf0, 0xe6, 0x73, - 0xaa, 0xfa, 0xb7, 0x34, 0x64, 0xf9, 0x7e, 0xb1, 0x01, 0xa5, 0xc1, 0xe7, 0x3d, 0x59, 0x6d, 0x76, - 0xcf, 0x8e, 0xda, 0x32, 0x4a, 0xe1, 0x0a, 0x00, 0x07, 0x1e, 0xb4, 0xbb, 0xf5, 0x01, 0x4a, 0x47, - 0xed, 0x56, 0x67, 0x70, 0xef, 0x0e, 0xca, 0x44, 0x0a, 0x67, 0x02, 0xc8, 0xc6, 0x09, 0xef, 0x1f, - 0xa0, 0x1c, 0x46, 0x50, 0x16, 0x06, 0x5a, 0x9f, 0xc9, 0xcd, 0x7b, 0x77, 0x50, 0x3e, 0x89, 0xbc, - 0x7f, 0x80, 0xd6, 0xf0, 0x3a, 0x14, 0x39, 0x72, 0xd4, 0xed, 0xb6, 0x51, 0x21, 0xb2, 0xd9, 0x1f, - 0x28, 0xad, 0xce, 0x31, 0x2a, 0x46, 0x36, 0x8f, 0x95, 0xee, 0x59, 0x0f, 0x41, 0x64, 0xe1, 0x54, - 0xee, 0xf7, 0xeb, 0xc7, 0x32, 0x2a, 0x45, 0x8c, 0xa3, 0xcf, 0x07, 0x72, 0x1f, 0x95, 0x13, 0x6e, - 0xbd, 0x7f, 0x80, 0xd6, 0xa3, 0x2e, 0xe4, 0xce, 0xd9, 0x29, 0xaa, 0xe0, 0x4d, 0x58, 0x17, 0x5d, - 0x84, 0x4e, 0x6c, 0xcc, 0x41, 0xf7, 0xee, 0x20, 0x34, 0x73, 0x44, 0x58, 0xd9, 0x4c, 0x00, 0xf7, - 0xee, 0x20, 0x5c, 0x6d, 0x40, 0x8e, 0x67, 0x17, 0xc6, 0x50, 0x69, 0xd7, 0x8f, 0xe4, 0xb6, 0xda, - 0xed, 0x0d, 0x5a, 0xdd, 0x4e, 0xbd, 0x8d, 0x52, 0x33, 0x4c, 0x91, 0x7f, 0x7d, 0xd6, 0x52, 0xe4, - 0x26, 0x4a, 0xc7, 0xb1, 0x9e, 0x5c, 0x1f, 0xc8, 0x4d, 0x94, 0xa9, 0x6a, 0xb0, 0xbd, 0x6c, 0x9f, - 0x5c, 0xba, 0x32, 0x62, 0x53, 0x9c, 0x5e, 0x31, 0xc5, 0xdc, 0xd6, 0xc2, 0x14, 0x7f, 0x9d, 0x82, - 0xad, 0x25, 0x67, 0xc5, 0xd2, 0x4e, 0x7e, 0x01, 0x39, 0x91, 0xa2, 0xe2, 0xf4, 0xbc, 0xb5, 0xf4, - 0xd0, 0xe1, 0x09, 0xbb, 0x70, 0x82, 0x72, 0xbd, 0x78, 0x05, 0x91, 0x59, 0x51, 0x41, 0x30, 0x13, - 0x0b, 0x4e, 0xfe, 0x2e, 0x05, 0xd2, 0x2a, 0xdb, 0xcf, 0xd9, 0x28, 0xd2, 0x89, 0x8d, 0xe2, 0xa3, - 0x79, 0x07, 0x6e, 0xac, 0x1e, 0xc3, 0x82, 0x17, 0xdf, 0xa4, 0xe0, 0xca, 0xf2, 0x42, 0x6b, 0xa9, - 0x0f, 0x1f, 0x43, 0x7e, 0x42, 0xfd, 0xb1, 0x1d, 0x16, 0x1b, 0x6f, 0x2f, 0x39, 0xc2, 0x98, 0x78, - 0x3e, 0x56, 0x81, 0x56, 0xfc, 0x0c, 0xcc, 0xac, 0xaa, 0x96, 0x84, 0x37, 0x0b, 0x9e, 0xfe, 0x3e, - 0x0d, 0x2f, 0x2f, 0x35, 0xbe, 0xd4, 0xd1, 0xd7, 0x00, 0x0c, 0xcb, 0x99, 0xfa, 0xa2, 0xa0, 0x10, - 0xfb, 0x53, 0x91, 0x23, 0x7c, 0xed, 0xb3, 0xbd, 0x67, 0xea, 0x47, 0xf2, 0x0c, 0x97, 0x83, 0x80, - 0x38, 0xe1, 0xfe, 0xcc, 0xd1, 0x2c, 0x77, 0xf4, 0xf5, 0x15, 0x23, 0x5d, 0x38, 0xab, 0xdf, 0x03, - 0xa4, 0x99, 0x06, 0xb5, 0x7c, 0xd5, 0xf3, 0x5d, 0x4a, 0x26, 0x86, 0x35, 0xe2, 0x1b, 0x70, 0xe1, - 0x30, 0x37, 0x24, 0xa6, 0x47, 0x95, 0x0d, 0x21, 0xee, 0x87, 0x52, 0xa6, 0xc1, 0xcf, 0x38, 0x37, - 0xa6, 0x91, 0x4f, 0x68, 0x08, 0x71, 0xa4, 0x51, 0xfd, 0xb6, 0x00, 0xa5, 0x58, 0x59, 0x8a, 0x6f, - 0x40, 0xf9, 0x21, 0x79, 0x4c, 0xd4, 0xf0, 0xaa, 0x21, 0x22, 0x51, 0x62, 0x58, 0x2f, 0xb8, 0x6e, - 0xbc, 0x07, 0xdb, 0x9c, 0x62, 0x4f, 0x7d, 0xea, 0xaa, 0x9a, 0x49, 0x3c, 0x8f, 0x07, 0xad, 0xc0, - 0xa9, 0x98, 0xc9, 0xba, 0x4c, 0xd4, 0x08, 0x25, 0xf8, 0x2e, 0x6c, 0x71, 0x8d, 0xc9, 0xd4, 0xf4, - 0x0d, 0xc7, 0xa4, 0x2a, 0xbb, 0xfc, 0x78, 0x7c, 0x23, 0x8e, 0x3c, 0xdb, 0x64, 0x8c, 0xd3, 0x80, - 0xc0, 0x3c, 0xf2, 0x70, 0x13, 0x5e, 0xe3, 0x6a, 0x23, 0x6a, 0x51, 0x97, 0xf8, 0x54, 0xa5, 0x5f, - 0x4e, 0x89, 0xe9, 0xa9, 0xc4, 0xd2, 0xd5, 0x31, 0xf1, 0xc6, 0xd2, 0x36, 0x33, 0x70, 0x94, 0x96, - 0x52, 0xca, 0x35, 0x46, 0x3c, 0x0e, 0x78, 0x32, 0xa7, 0xd5, 0x2d, 0xfd, 0x13, 0xe2, 0x8d, 0xf1, - 0x21, 0x5c, 0xe1, 0x56, 0x3c, 0xdf, 0x35, 0xac, 0x91, 0xaa, 0x8d, 0xa9, 0xf6, 0x48, 0x9d, 0xfa, - 0xc3, 0xfb, 0xd2, 0x2b, 0xf1, 0xfe, 0xb9, 0x87, 0x7d, 0xce, 0x69, 0x30, 0xca, 0x99, 0x3f, 0xbc, - 0x8f, 0xfb, 0x50, 0x66, 0x93, 0x31, 0x31, 0xbe, 0xa2, 0xea, 0xd0, 0x76, 0xf9, 0xc9, 0x52, 0x59, - 0xb2, 0xb2, 0x63, 0x11, 0xac, 0x75, 0x03, 0x85, 0x53, 0x5b, 0xa7, 0x87, 0xb9, 0x7e, 0x4f, 0x96, - 0x9b, 0x4a, 0x29, 0xb4, 0xf2, 0xc0, 0x76, 0x59, 0x42, 0x8d, 0xec, 0x28, 0xc0, 0x25, 0x91, 0x50, - 0x23, 0x3b, 0x0c, 0xef, 0x5d, 0xd8, 0xd2, 0x34, 0x31, 0x66, 0x43, 0x53, 0x83, 0x2b, 0x8a, 0x27, - 0xa1, 0x44, 0xb0, 0x34, 0xed, 0x58, 0x10, 0x82, 0x1c, 0xf7, 0xf0, 0x87, 0xf0, 0xf2, 0x2c, 0x58, - 0x71, 0xc5, 0xcd, 0x85, 0x51, 0xce, 0xab, 0xde, 0x85, 0x2d, 0xe7, 0x62, 0x51, 0x11, 0x27, 0x7a, - 0x74, 0x2e, 0xe6, 0xd5, 0x3e, 0x80, 0x6d, 0x67, 0xec, 0x2c, 0xea, 0xdd, 0x8e, 0xeb, 0x61, 0x67, - 0xec, 0xcc, 0x2b, 0xbe, 0xc5, 0xef, 0xab, 0x2e, 0xd5, 0x88, 0x4f, 0x75, 0xe9, 0x6a, 0x9c, 0x1e, - 0x13, 0xe0, 0x7d, 0x40, 0x9a, 0xa6, 0x52, 0x8b, 0x9c, 0x9b, 0x54, 0x25, 0x2e, 0xb5, 0x88, 0x27, - 0x5d, 0x8f, 0x93, 0x2b, 0x9a, 0x26, 0x73, 0x69, 0x9d, 0x0b, 0xf1, 0x6d, 0xd8, 0xb4, 0xcf, 0x1f, - 0x6a, 0x22, 0x25, 0x55, 0xc7, 0xa5, 0x43, 0xe3, 0xa9, 0xf4, 0x26, 0x8f, 0xef, 0x06, 0x13, 0xf0, - 0x84, 0xec, 0x71, 0x18, 0xdf, 0x02, 0xa4, 0x79, 0x63, 0xe2, 0x3a, 0xbc, 0x26, 0xf0, 0x1c, 0xa2, - 0x51, 0xe9, 0x2d, 0x41, 0x15, 0x78, 0x27, 0x84, 0xd9, 0x92, 0xf0, 0x9e, 0x18, 0x43, 0x3f, 0xb4, - 0x78, 0x53, 0x2c, 0x09, 0x8e, 0x05, 0xd6, 0xf6, 0x00, 0xb1, 0x50, 0x24, 0x3a, 0xde, 0xe3, 0xb4, - 0x8a, 0x33, 0x76, 0xe2, 0xfd, 0xbe, 0x01, 0xeb, 0x8c, 0x39, 0xeb, 0xf4, 0x96, 0xa8, 0x67, 0x9c, - 0x71, 0xac, 0xc7, 0x1f, 0xad, 0xb4, 0xac, 0x1e, 0x42, 0x39, 0x9e, 0x9f, 0xb8, 0x08, 0x22, 0x43, - 0x51, 0x8a, 0x9d, 0xf5, 0x8d, 0x6e, 0x93, 0x9d, 0xd2, 0x5f, 0xc8, 0x28, 0xcd, 0xaa, 0x85, 0x76, - 0x6b, 0x20, 0xab, 0xca, 0x59, 0x67, 0xd0, 0x3a, 0x95, 0x51, 0x26, 0x56, 0x96, 0x9e, 0x64, 0x0b, - 0x6f, 0xa3, 0x9b, 0xd5, 0xef, 0xd2, 0x50, 0x49, 0xde, 0x33, 0xf0, 0xcf, 0xe1, 0x6a, 0xf8, 0x28, - 0xe0, 0x51, 0x5f, 0x7d, 0x62, 0xb8, 0x7c, 0xe1, 0x4c, 0x88, 0xa8, 0xb3, 0xa3, 0xa9, 0xdb, 0x0e, - 0x58, 0x7d, 0xea, 0x7f, 0x6a, 0xb8, 0x6c, 0x59, 0x4c, 0x88, 0x8f, 0xdb, 0x70, 0xdd, 0xb2, 0x55, - 0xcf, 0x27, 0x96, 0x4e, 0x5c, 0x5d, 0x9d, 0x3d, 0xc7, 0xa8, 0x44, 0xd3, 0xa8, 0xe7, 0xd9, 0xe2, - 0xc0, 0x8a, 0xac, 0xbc, 0x6a, 0xd9, 0xfd, 0x80, 0x3c, 0xdb, 0xc9, 0xeb, 0x01, 0x75, 0x2e, 0xcd, - 0x32, 0xab, 0xd2, 0xec, 0x15, 0x28, 0x4e, 0x88, 0xa3, 0x52, 0xcb, 0x77, 0x2f, 0x78, 0x75, 0x59, - 0x50, 0x0a, 0x13, 0xe2, 0xc8, 0xac, 0xfd, 0x42, 0x8a, 0xfc, 0x93, 0x6c, 0xa1, 0x80, 0x8a, 0x27, - 0xd9, 0x42, 0x11, 0x41, 0xf5, 0x5f, 0x19, 0x28, 0xc7, 0xab, 0x4d, 0x56, 0xbc, 0x6b, 0xfc, 0x64, - 0x49, 0xf1, 0xbd, 0xe7, 0x8d, 0xef, 0xad, 0x4d, 0x6b, 0x0d, 0x76, 0xe4, 0x1c, 0xe6, 0x45, 0x0d, - 0xa8, 0x08, 0x4d, 0x76, 0xdc, 0xb3, 0xdd, 0x86, 0x8a, 0x7b, 0x4d, 0x41, 0x09, 0x5a, 0xf8, 0x18, - 0xf2, 0x0f, 0x3d, 0x6e, 0x3b, 0xcf, 0x6d, 0xbf, 0xf9, 0xfd, 0xb6, 0x4f, 0xfa, 0xdc, 0x78, 0xf1, - 0xa4, 0xaf, 0x76, 0xba, 0xca, 0x69, 0xbd, 0xad, 0x04, 0xea, 0xf8, 0x1a, 0x64, 0x4d, 0xf2, 0xd5, - 0x45, 0xf2, 0x70, 0xe2, 0xd0, 0x65, 0x27, 0xe1, 0x1a, 0x64, 0x9f, 0x50, 0xf2, 0x28, 0x79, 0x24, - 0x70, 0xe8, 0x47, 0x5c, 0x0c, 0xfb, 0x90, 0xe3, 0xf1, 0xc2, 0x00, 0x41, 0xc4, 0xd0, 0x4b, 0xb8, - 0x00, 0xd9, 0x46, 0x57, 0x61, 0x0b, 0x02, 0x41, 0x59, 0xa0, 0x6a, 0xaf, 0x25, 0x37, 0x64, 0x94, - 0xae, 0xde, 0x85, 0xbc, 0x08, 0x02, 0x5b, 0x2c, 0x51, 0x18, 0xd0, 0x4b, 0x41, 0x33, 0xb0, 0x91, - 0x0a, 0xa5, 0x67, 0xa7, 0x47, 0xb2, 0x82, 0xd2, 0xc9, 0xa9, 0xce, 0xa2, 0x5c, 0xd5, 0x83, 0x72, - 0xbc, 0xdc, 0x7c, 0x31, 0x57, 0xc9, 0xbf, 0xa7, 0xa0, 0x14, 0x2b, 0x1f, 0x59, 0xe1, 0x42, 0x4c, - 0xd3, 0x7e, 0xa2, 0x12, 0xd3, 0x20, 0x5e, 0x90, 0x1a, 0xc0, 0xa1, 0x3a, 0x43, 0x2e, 0x3b, 0x75, - 0x2f, 0x68, 0x89, 0xe4, 0x50, 0xbe, 0xfa, 0x97, 0x14, 0xa0, 0xf9, 0x02, 0x74, 0xce, 0xcd, 0xd4, - 0x4f, 0xe9, 0x66, 0xf5, 0xcf, 0x29, 0xa8, 0x24, 0xab, 0xce, 0x39, 0xf7, 0x6e, 0xfc, 0xa4, 0xee, - 0xfd, 0x33, 0x0d, 0xeb, 0x89, 0x5a, 0xf3, 0xb2, 0xde, 0x7d, 0x09, 0x9b, 0x86, 0x4e, 0x27, 0x8e, - 0xed, 0x53, 0x4b, 0xbb, 0x50, 0x4d, 0xfa, 0x98, 0x9a, 0x52, 0x95, 0x6f, 0x1a, 0xfb, 0xdf, 0x5f, - 0xcd, 0xd6, 0x5a, 0x33, 0xbd, 0x36, 0x53, 0x3b, 0xdc, 0x6a, 0x35, 0xe5, 0xd3, 0x5e, 0x77, 0x20, - 0x77, 0x1a, 0x9f, 0xab, 0x67, 0x9d, 0x5f, 0x75, 0xba, 0x9f, 0x76, 0x14, 0x64, 0xcc, 0xd1, 0x7e, - 0xc4, 0x65, 0xdf, 0x03, 0x34, 0xef, 0x14, 0xbe, 0x0a, 0xcb, 0xdc, 0x42, 0x2f, 0xe1, 0x2d, 0xd8, - 0xe8, 0x74, 0xd5, 0x7e, 0xab, 0x29, 0xab, 0xf2, 0x83, 0x07, 0x72, 0x63, 0xd0, 0x17, 0xd7, 0xfb, - 0x88, 0x3d, 0x48, 0x2c, 0xf0, 0xea, 0x9f, 0x32, 0xb0, 0xb5, 0xc4, 0x13, 0x5c, 0x0f, 0x6e, 0x16, - 0xe2, 0xb2, 0xf3, 0xee, 0x65, 0xbc, 0xaf, 0xb1, 0x82, 0xa0, 0x47, 0x5c, 0x3f, 0xb8, 0x88, 0xdc, - 0x02, 0x16, 0x25, 0xcb, 0x37, 0x86, 0x06, 0x75, 0x83, 0xd7, 0x10, 0x71, 0xdd, 0xd8, 0x98, 0xe1, - 0xe2, 0x41, 0xe4, 0x67, 0x80, 0x1d, 0xdb, 0x33, 0x7c, 0xe3, 0x31, 0x55, 0x0d, 0x2b, 0x7c, 0x3a, - 0x61, 0xd7, 0x8f, 0xac, 0x82, 0x42, 0x49, 0xcb, 0xf2, 0x23, 0xb6, 0x45, 0x47, 0x64, 0x8e, 0xcd, - 0x36, 0xf3, 0x8c, 0x82, 0x42, 0x49, 0xc4, 0xbe, 0x01, 0x65, 0xdd, 0x9e, 0xb2, 0x9a, 0x4c, 0xf0, - 0xd8, 0xd9, 0x91, 0x52, 0x4a, 0x02, 0x8b, 0x28, 0x41, 0xb5, 0x3d, 0x7b, 0xb3, 0x29, 0x2b, 0x25, - 0x81, 0x09, 0xca, 0x4d, 0xd8, 0x20, 0xa3, 0x91, 0xcb, 0x8c, 0x87, 0x86, 0xc4, 0xfd, 0xa1, 0x12, - 0xc1, 0x9c, 0xb8, 0x73, 0x02, 0x85, 0x30, 0x0e, 0xec, 0xa8, 0x66, 0x91, 0x50, 0x1d, 0xf1, 0x6e, - 0x97, 0xde, 0x2b, 0x2a, 0x05, 0x2b, 0x14, 0xde, 0x80, 0xb2, 0xe1, 0xa9, 0xb3, 0x27, 0xe8, 0xf4, - 0x6e, 0x7a, 0xaf, 0xa0, 0x94, 0x0c, 0x2f, 0x7a, 0xbe, 0xab, 0x7e, 0x93, 0x86, 0x4a, 0xf2, 0x09, - 0x1d, 0x37, 0xa1, 0x60, 0xda, 0x1a, 0xe1, 0xa9, 0x25, 0xbe, 0xdf, 0xec, 0x3d, 0xe7, 0xd5, 0xbd, - 0xd6, 0x0e, 0xf8, 0x4a, 0xa4, 0xb9, 0xf3, 0x8f, 0x14, 0x14, 0x42, 0x18, 0x5f, 0x81, 0xac, 0x43, - 0xfc, 0x31, 0x37, 0x97, 0x3b, 0x4a, 0xa3, 0x94, 0xc2, 0xdb, 0x0c, 0xf7, 0x1c, 0x62, 0xf1, 0x14, - 0x08, 0x70, 0xd6, 0x66, 0xf3, 0x6a, 0x52, 0xa2, 0xf3, 0xcb, 0x89, 0x3d, 0x99, 0x50, 0xcb, 0xf7, - 0xc2, 0x79, 0x0d, 0xf0, 0x46, 0x00, 0xe3, 0x77, 0x60, 0xd3, 0x77, 0x89, 0x61, 0x26, 0xb8, 0x59, - 0xce, 0x45, 0xa1, 0x20, 0x22, 0x1f, 0xc2, 0xb5, 0xd0, 0xae, 0x4e, 0x7d, 0xa2, 0x8d, 0xa9, 0x3e, - 0x53, 0xca, 0xf3, 0xf7, 0xd9, 0xab, 0x01, 0xa1, 0x19, 0xc8, 0x43, 0xdd, 0xea, 0x77, 0x29, 0xd8, - 0x0c, 0xaf, 0x53, 0x7a, 0x14, 0xac, 0x53, 0x00, 0x62, 0x59, 0xb6, 0x1f, 0x0f, 0xd7, 0x62, 0x2a, - 0x2f, 0xe8, 0xd5, 0xea, 0x91, 0x92, 0x12, 0x33, 0xb0, 0x33, 0x01, 0x98, 0x49, 0x56, 0x86, 0xed, - 0x3a, 0x94, 0x82, 0xef, 0x23, 0xfc, 0x23, 0x9b, 0xb8, 0x80, 0x83, 0x80, 0xd8, 0xbd, 0x0b, 0x6f, - 0x43, 0xee, 0x9c, 0x8e, 0x0c, 0x2b, 0x78, 0xf5, 0x14, 0x8d, 0xf0, 0x25, 0x37, 0x1b, 0xbd, 0xe4, - 0x1e, 0xfd, 0x21, 0x05, 0x5b, 0x9a, 0x3d, 0x99, 0xf7, 0xf7, 0x08, 0xcd, 0xbd, 0x02, 0x78, 0x9f, - 0xa4, 0xbe, 0xf8, 0x78, 0x64, 0xf8, 0xe3, 0xe9, 0x79, 0x4d, 0xb3, 0x27, 0xfb, 0x23, 0xdb, 0x24, - 0xd6, 0x68, 0xf6, 0x95, 0x90, 0xff, 0xd1, 0xde, 0x1d, 0x51, 0xeb, 0xdd, 0x91, 0x1d, 0xfb, 0x66, - 0xf8, 0xd1, 0xec, 0xef, 0xd7, 0xe9, 0xcc, 0x71, 0xef, 0xe8, 0xaf, 0xe9, 0x9d, 0x63, 0xd1, 0x57, - 0x2f, 0x8c, 0x8d, 0x42, 0x87, 0x26, 0xd5, 0xd8, 0x78, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x0c, - 0xab, 0xb6, 0x37, 0x7e, 0x1c, 0x00, 0x00, +func init() { + proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor_descriptor_4df4cb5f42392df6) +} + +var fileDescriptor_descriptor_4df4cb5f42392df6 = []byte{ + // 2555 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x6e, 0x1b, 0xc7, + 0xf5, 0xcf, 0xf2, 0x4b, 0xe4, 0x21, 0x45, 0x8d, 0x46, 0x8a, 0xbd, 0x56, 0x3e, 0x2c, 0x33, 0x1f, + 0x96, 0x9d, 0x7f, 0xa8, 0xc0, 0xb1, 0x1d, 0x47, 0xfe, 0x23, 0x2d, 0x45, 0xae, 0x15, 0xaa, 0x12, + 0xc9, 0x2e, 0xa9, 0xe6, 0x03, 0x28, 0x16, 0xa3, 0xdd, 0x21, 0xb9, 0xf6, 0x72, 0x77, 0xb3, 0xbb, + 0xb4, 0xad, 0xa0, 0x17, 0x06, 0x7a, 0xd5, 0xab, 0xde, 0x16, 0x45, 0xd1, 0x8b, 0xde, 0x04, 0xe8, + 0x03, 0x14, 0xc8, 0x5d, 0x9f, 0xa0, 0x40, 0xde, 0xa0, 0x68, 0x0b, 0xb4, 0x8f, 0xd0, 0xcb, 0x62, + 0x66, 0x76, 0x97, 0xbb, 0x24, 0x15, 0x2b, 0x01, 0xe2, 0x5c, 0x91, 0xf3, 0x9b, 0xdf, 0x39, 0x73, + 0xe6, 0xcc, 0x99, 0x33, 0x67, 0x66, 0x61, 0x7b, 0xe4, 0x38, 0x23, 0x8b, 0xee, 0xba, 0x9e, 0x13, + 0x38, 0xa7, 0xd3, 0xe1, 0xae, 0x41, 0x7d, 0xdd, 0x33, 0xdd, 0xc0, 0xf1, 0xea, 0x1c, 0xc3, 0x6b, + 0x82, 0x51, 0x8f, 0x18, 0xb5, 0x63, 0x58, 0x7f, 0x60, 0x5a, 0xb4, 0x15, 0x13, 0xfb, 0x34, 0xc0, + 0xf7, 0x20, 0x37, 0x34, 0x2d, 0x2a, 0x4b, 0xdb, 0xd9, 0x9d, 0xf2, 0xad, 0x37, 0xeb, 0x73, 0x42, + 0xf5, 0xb4, 0x44, 0x8f, 0xc1, 0x2a, 0x97, 0xa8, 0xfd, 0x2b, 0x07, 0x1b, 0x4b, 0x7a, 0x31, 0x86, + 0x9c, 0x4d, 0x26, 0x4c, 0xa3, 0xb4, 0x53, 0x52, 0xf9, 0x7f, 0x2c, 0xc3, 0x8a, 0x4b, 0xf4, 0x47, + 0x64, 0x44, 0xe5, 0x0c, 0x87, 0xa3, 0x26, 0x7e, 0x1d, 0xc0, 0xa0, 0x2e, 0xb5, 0x0d, 0x6a, 0xeb, + 0x67, 0x72, 0x76, 0x3b, 0xbb, 0x53, 0x52, 0x13, 0x08, 0x7e, 0x07, 0xd6, 0xdd, 0xe9, 0xa9, 0x65, + 0xea, 0x5a, 0x82, 0x06, 0xdb, 0xd9, 0x9d, 0xbc, 0x8a, 0x44, 0x47, 0x6b, 0x46, 0xbe, 0x0e, 0x6b, + 0x4f, 0x28, 0x79, 0x94, 0xa4, 0x96, 0x39, 0xb5, 0xca, 0xe0, 0x04, 0xb1, 0x09, 0x95, 0x09, 0xf5, + 0x7d, 0x32, 0xa2, 0x5a, 0x70, 0xe6, 0x52, 0x39, 0xc7, 0x67, 0xbf, 0xbd, 0x30, 0xfb, 0xf9, 0x99, + 0x97, 0x43, 0xa9, 0xc1, 0x99, 0x4b, 0x71, 0x03, 0x4a, 0xd4, 0x9e, 0x4e, 0x84, 0x86, 0xfc, 0x39, + 0xfe, 0x53, 0xec, 0xe9, 0x64, 0x5e, 0x4b, 0x91, 0x89, 0x85, 0x2a, 0x56, 0x7c, 0xea, 0x3d, 0x36, + 0x75, 0x2a, 0x17, 0xb8, 0x82, 0xeb, 0x0b, 0x0a, 0xfa, 0xa2, 0x7f, 0x5e, 0x47, 0x24, 0x87, 0x9b, + 0x50, 0xa2, 0x4f, 0x03, 0x6a, 0xfb, 0xa6, 0x63, 0xcb, 0x2b, 0x5c, 0xc9, 0x5b, 0x4b, 0x56, 0x91, + 0x5a, 0xc6, 0xbc, 0x8a, 0x99, 0x1c, 0xbe, 0x0b, 0x2b, 0x8e, 0x1b, 0x98, 0x8e, 0xed, 0xcb, 0xc5, + 0x6d, 0x69, 0xa7, 0x7c, 0xeb, 0xd5, 0xa5, 0x81, 0xd0, 0x15, 0x1c, 0x35, 0x22, 0xe3, 0x36, 0x20, + 0xdf, 0x99, 0x7a, 0x3a, 0xd5, 0x74, 0xc7, 0xa0, 0x9a, 0x69, 0x0f, 0x1d, 0xb9, 0xc4, 0x15, 0x5c, + 0x5d, 0x9c, 0x08, 0x27, 0x36, 0x1d, 0x83, 0xb6, 0xed, 0xa1, 0xa3, 0x56, 0xfd, 0x54, 0x1b, 0x5f, + 0x82, 0x82, 0x7f, 0x66, 0x07, 0xe4, 0xa9, 0x5c, 0xe1, 0x11, 0x12, 0xb6, 0x6a, 0x5f, 0x17, 0x60, + 0xed, 0x22, 0x21, 0x76, 0x1f, 0xf2, 0x43, 0x36, 0x4b, 0x39, 0xf3, 0x5d, 0x7c, 0x20, 0x64, 0xd2, + 0x4e, 0x2c, 0x7c, 0x4f, 0x27, 0x36, 0xa0, 0x6c, 0x53, 0x3f, 0xa0, 0x86, 0x88, 0x88, 0xec, 0x05, + 0x63, 0x0a, 0x84, 0xd0, 0x62, 0x48, 0xe5, 0xbe, 0x57, 0x48, 0x7d, 0x0a, 0x6b, 0xb1, 0x49, 0x9a, + 0x47, 0xec, 0x51, 0x14, 0x9b, 0xbb, 0xcf, 0xb3, 0xa4, 0xae, 0x44, 0x72, 0x2a, 0x13, 0x53, 0xab, + 0x34, 0xd5, 0xc6, 0x2d, 0x00, 0xc7, 0xa6, 0xce, 0x50, 0x33, 0xa8, 0x6e, 0xc9, 0xc5, 0x73, 0xbc, + 0xd4, 0x65, 0x94, 0x05, 0x2f, 0x39, 0x02, 0xd5, 0x2d, 0xfc, 0xe1, 0x2c, 0xd4, 0x56, 0xce, 0x89, + 0x94, 0x63, 0xb1, 0xc9, 0x16, 0xa2, 0xed, 0x04, 0xaa, 0x1e, 0x65, 0x71, 0x4f, 0x8d, 0x70, 0x66, + 0x25, 0x6e, 0x44, 0xfd, 0xb9, 0x33, 0x53, 0x43, 0x31, 0x31, 0xb1, 0x55, 0x2f, 0xd9, 0xc4, 0x6f, + 0x40, 0x0c, 0x68, 0x3c, 0xac, 0x80, 0x67, 0xa1, 0x4a, 0x04, 0x76, 0xc8, 0x84, 0x6e, 0x7d, 0x09, + 0xd5, 0xb4, 0x7b, 0xf0, 0x26, 0xe4, 0xfd, 0x80, 0x78, 0x01, 0x8f, 0xc2, 0xbc, 0x2a, 0x1a, 0x18, + 0x41, 0x96, 0xda, 0x06, 0xcf, 0x72, 0x79, 0x95, 0xfd, 0xc5, 0x3f, 0x9d, 0x4d, 0x38, 0xcb, 0x27, + 0xfc, 0xf6, 0xe2, 0x8a, 0xa6, 0x34, 0xcf, 0xcf, 0x7b, 0xeb, 0x03, 0x58, 0x4d, 0x4d, 0xe0, 0xa2, + 0x43, 0xd7, 0x7e, 0x05, 0x2f, 0x2f, 0x55, 0x8d, 0x3f, 0x85, 0xcd, 0xa9, 0x6d, 0xda, 0x01, 0xf5, + 0x5c, 0x8f, 0xb2, 0x88, 0x15, 0x43, 0xc9, 0xff, 0x5e, 0x39, 0x27, 0xe6, 0x4e, 0x92, 0x6c, 0xa1, + 0x45, 0xdd, 0x98, 0x2e, 0x82, 0x37, 0x4b, 0xc5, 0xff, 0xac, 0xa0, 0x67, 0xcf, 0x9e, 0x3d, 0xcb, + 0xd4, 0x7e, 0x57, 0x80, 0xcd, 0x65, 0x7b, 0x66, 0xe9, 0xf6, 0xbd, 0x04, 0x05, 0x7b, 0x3a, 0x39, + 0xa5, 0x1e, 0x77, 0x52, 0x5e, 0x0d, 0x5b, 0xb8, 0x01, 0x79, 0x8b, 0x9c, 0x52, 0x4b, 0xce, 0x6d, + 0x4b, 0x3b, 0xd5, 0x5b, 0xef, 0x5c, 0x68, 0x57, 0xd6, 0x8f, 0x98, 0x88, 0x2a, 0x24, 0xf1, 0x47, + 0x90, 0x0b, 0x53, 0x34, 0xd3, 0x70, 0xf3, 0x62, 0x1a, 0xd8, 0x5e, 0x52, 0xb9, 0x1c, 0x7e, 0x05, + 0x4a, 0xec, 0x57, 0xc4, 0x46, 0x81, 0xdb, 0x5c, 0x64, 0x00, 0x8b, 0x0b, 0xbc, 0x05, 0x45, 0xbe, + 0x4d, 0x0c, 0x1a, 0x1d, 0x6d, 0x71, 0x9b, 0x05, 0x96, 0x41, 0x87, 0x64, 0x6a, 0x05, 0xda, 0x63, + 0x62, 0x4d, 0x29, 0x0f, 0xf8, 0x92, 0x5a, 0x09, 0xc1, 0x5f, 0x30, 0x0c, 0x5f, 0x85, 0xb2, 0xd8, + 0x55, 0xa6, 0x6d, 0xd0, 0xa7, 0x3c, 0x7b, 0xe6, 0x55, 0xb1, 0xd1, 0xda, 0x0c, 0x61, 0xc3, 0x3f, + 0xf4, 0x1d, 0x3b, 0x0a, 0x4d, 0x3e, 0x04, 0x03, 0xf8, 0xf0, 0x1f, 0xcc, 0x27, 0xee, 0xd7, 0x96, + 0x4f, 0x6f, 0x3e, 0xa6, 0x6a, 0x7f, 0xc9, 0x40, 0x8e, 0xe7, 0x8b, 0x35, 0x28, 0x0f, 0x3e, 0xeb, + 0x29, 0x5a, 0xab, 0x7b, 0xb2, 0x7f, 0xa4, 0x20, 0x09, 0x57, 0x01, 0x38, 0xf0, 0xe0, 0xa8, 0xdb, + 0x18, 0xa0, 0x4c, 0xdc, 0x6e, 0x77, 0x06, 0x77, 0x6f, 0xa3, 0x6c, 0x2c, 0x70, 0x22, 0x80, 0x5c, + 0x92, 0xf0, 0xfe, 0x2d, 0x94, 0xc7, 0x08, 0x2a, 0x42, 0x41, 0xfb, 0x53, 0xa5, 0x75, 0xf7, 0x36, + 0x2a, 0xa4, 0x91, 0xf7, 0x6f, 0xa1, 0x15, 0xbc, 0x0a, 0x25, 0x8e, 0xec, 0x77, 0xbb, 0x47, 0xa8, + 0x18, 0xeb, 0xec, 0x0f, 0xd4, 0x76, 0xe7, 0x00, 0x95, 0x62, 0x9d, 0x07, 0x6a, 0xf7, 0xa4, 0x87, + 0x20, 0xd6, 0x70, 0xac, 0xf4, 0xfb, 0x8d, 0x03, 0x05, 0x95, 0x63, 0xc6, 0xfe, 0x67, 0x03, 0xa5, + 0x8f, 0x2a, 0x29, 0xb3, 0xde, 0xbf, 0x85, 0x56, 0xe3, 0x21, 0x94, 0xce, 0xc9, 0x31, 0xaa, 0xe2, + 0x75, 0x58, 0x15, 0x43, 0x44, 0x46, 0xac, 0xcd, 0x41, 0x77, 0x6f, 0x23, 0x34, 0x33, 0x44, 0x68, + 0x59, 0x4f, 0x01, 0x77, 0x6f, 0x23, 0x5c, 0x6b, 0x42, 0x9e, 0x47, 0x17, 0xc6, 0x50, 0x3d, 0x6a, + 0xec, 0x2b, 0x47, 0x5a, 0xb7, 0x37, 0x68, 0x77, 0x3b, 0x8d, 0x23, 0x24, 0xcd, 0x30, 0x55, 0xf9, + 0xf9, 0x49, 0x5b, 0x55, 0x5a, 0x28, 0x93, 0xc4, 0x7a, 0x4a, 0x63, 0xa0, 0xb4, 0x50, 0xb6, 0xa6, + 0xc3, 0xe6, 0xb2, 0x3c, 0xb9, 0x74, 0x67, 0x24, 0x96, 0x38, 0x73, 0xce, 0x12, 0x73, 0x5d, 0x0b, + 0x4b, 0xfc, 0xcf, 0x0c, 0x6c, 0x2c, 0x39, 0x2b, 0x96, 0x0e, 0xf2, 0x13, 0xc8, 0x8b, 0x10, 0x15, + 0xa7, 0xe7, 0x8d, 0xa5, 0x87, 0x0e, 0x0f, 0xd8, 0x85, 0x13, 0x94, 0xcb, 0x25, 0x2b, 0x88, 0xec, + 0x39, 0x15, 0x04, 0x53, 0xb1, 0x90, 0xd3, 0x7f, 0xb9, 0x90, 0xd3, 0xc5, 0xb1, 0x77, 0xf7, 0x22, + 0xc7, 0x1e, 0xc7, 0xbe, 0x5b, 0x6e, 0xcf, 0x2f, 0xc9, 0xed, 0xf7, 0x61, 0x7d, 0x41, 0xd1, 0x85, + 0x73, 0xec, 0xaf, 0x25, 0x90, 0xcf, 0x73, 0xce, 0x73, 0x32, 0x5d, 0x26, 0x95, 0xe9, 0xee, 0xcf, + 0x7b, 0xf0, 0xda, 0xf9, 0x8b, 0xb0, 0xb0, 0xd6, 0x5f, 0x49, 0x70, 0x69, 0x79, 0xa5, 0xb8, 0xd4, + 0x86, 0x8f, 0xa0, 0x30, 0xa1, 0xc1, 0xd8, 0x89, 0xaa, 0xa5, 0xb7, 0x97, 0x9c, 0xc1, 0xac, 0x7b, + 0x7e, 0xb1, 0x43, 0xa9, 0xe4, 0x21, 0x9e, 0x3d, 0xaf, 0xdc, 0x13, 0xd6, 0x2c, 0x58, 0xfa, 0x9b, + 0x0c, 0xbc, 0xbc, 0x54, 0xf9, 0x52, 0x43, 0x5f, 0x03, 0x30, 0x6d, 0x77, 0x1a, 0x88, 0x8a, 0x48, + 0x24, 0xd8, 0x12, 0x47, 0x78, 0xf2, 0x62, 0xc9, 0x73, 0x1a, 0xc4, 0xfd, 0x59, 0xde, 0x0f, 0x02, + 0xe2, 0x84, 0x7b, 0x33, 0x43, 0x73, 0xdc, 0xd0, 0xd7, 0xcf, 0x99, 0xe9, 0x42, 0x60, 0xbe, 0x07, + 0x48, 0xb7, 0x4c, 0x6a, 0x07, 0x9a, 0x1f, 0x78, 0x94, 0x4c, 0x4c, 0x7b, 0xc4, 0x4f, 0x90, 0xe2, + 0x5e, 0x7e, 0x48, 0x2c, 0x9f, 0xaa, 0x6b, 0xa2, 0xbb, 0x1f, 0xf5, 0x32, 0x09, 0x1e, 0x40, 0x5e, + 0x42, 0xa2, 0x90, 0x92, 0x10, 0xdd, 0xb1, 0x44, 0xed, 0xeb, 0x22, 0x94, 0x13, 0x75, 0x35, 0xbe, + 0x06, 0x95, 0x87, 0xe4, 0x31, 0xd1, 0xa2, 0xbb, 0x92, 0xf0, 0x44, 0x99, 0x61, 0xbd, 0xf0, 0xbe, + 0xf4, 0x1e, 0x6c, 0x72, 0x8a, 0x33, 0x0d, 0xa8, 0xa7, 0xe9, 0x16, 0xf1, 0x7d, 0xee, 0xb4, 0x22, + 0xa7, 0x62, 0xd6, 0xd7, 0x65, 0x5d, 0xcd, 0xa8, 0x07, 0xdf, 0x81, 0x0d, 0x2e, 0x31, 0x99, 0x5a, + 0x81, 0xe9, 0x5a, 0x54, 0x63, 0xb7, 0x37, 0x9f, 0x9f, 0x24, 0xb1, 0x65, 0xeb, 0x8c, 0x71, 0x1c, + 0x12, 0x98, 0x45, 0x3e, 0x6e, 0xc1, 0x6b, 0x5c, 0x6c, 0x44, 0x6d, 0xea, 0x91, 0x80, 0x6a, 0xf4, + 0x8b, 0x29, 0xb1, 0x7c, 0x8d, 0xd8, 0x86, 0x36, 0x26, 0xfe, 0x58, 0xde, 0x64, 0x0a, 0xf6, 0x33, + 0xb2, 0xa4, 0x5e, 0x61, 0xc4, 0x83, 0x90, 0xa7, 0x70, 0x5a, 0xc3, 0x36, 0x3e, 0x26, 0xfe, 0x18, + 0xef, 0xc1, 0x25, 0xae, 0xc5, 0x0f, 0x3c, 0xd3, 0x1e, 0x69, 0xfa, 0x98, 0xea, 0x8f, 0xb4, 0x69, + 0x30, 0xbc, 0x27, 0xbf, 0x92, 0x1c, 0x9f, 0x5b, 0xd8, 0xe7, 0x9c, 0x26, 0xa3, 0x9c, 0x04, 0xc3, + 0x7b, 0xb8, 0x0f, 0x15, 0xb6, 0x18, 0x13, 0xf3, 0x4b, 0xaa, 0x0d, 0x1d, 0x8f, 0x1f, 0x8d, 0xd5, + 0x25, 0xa9, 0x29, 0xe1, 0xc1, 0x7a, 0x37, 0x14, 0x38, 0x76, 0x0c, 0xba, 0x97, 0xef, 0xf7, 0x14, + 0xa5, 0xa5, 0x96, 0x23, 0x2d, 0x0f, 0x1c, 0x8f, 0x05, 0xd4, 0xc8, 0x89, 0x1d, 0x5c, 0x16, 0x01, + 0x35, 0x72, 0x22, 0xf7, 0xde, 0x81, 0x0d, 0x5d, 0x17, 0x73, 0x36, 0x75, 0x2d, 0xbc, 0x63, 0xf9, + 0x32, 0x4a, 0x39, 0x4b, 0xd7, 0x0f, 0x04, 0x21, 0x8c, 0x71, 0x1f, 0x7f, 0x08, 0x2f, 0xcf, 0x9c, + 0x95, 0x14, 0x5c, 0x5f, 0x98, 0xe5, 0xbc, 0xe8, 0x1d, 0xd8, 0x70, 0xcf, 0x16, 0x05, 0x71, 0x6a, + 0x44, 0xf7, 0x6c, 0x5e, 0xec, 0x03, 0xd8, 0x74, 0xc7, 0xee, 0xa2, 0xdc, 0xcd, 0xa4, 0x1c, 0x76, + 0xc7, 0xee, 0xbc, 0xe0, 0x5b, 0xfc, 0xc2, 0xed, 0x51, 0x9d, 0x04, 0xd4, 0x90, 0x2f, 0x27, 0xe9, + 0x89, 0x0e, 0xbc, 0x0b, 0x48, 0xd7, 0x35, 0x6a, 0x93, 0x53, 0x8b, 0x6a, 0xc4, 0xa3, 0x36, 0xf1, + 0xe5, 0xab, 0x49, 0x72, 0x55, 0xd7, 0x15, 0xde, 0xdb, 0xe0, 0x9d, 0xf8, 0x26, 0xac, 0x3b, 0xa7, + 0x0f, 0x75, 0x11, 0x92, 0x9a, 0xeb, 0xd1, 0xa1, 0xf9, 0x54, 0x7e, 0x93, 0xfb, 0x77, 0x8d, 0x75, + 0xf0, 0x80, 0xec, 0x71, 0x18, 0xdf, 0x00, 0xa4, 0xfb, 0x63, 0xe2, 0xb9, 0x3c, 0x27, 0xfb, 0x2e, + 0xd1, 0xa9, 0xfc, 0x96, 0xa0, 0x0a, 0xbc, 0x13, 0xc1, 0x6c, 0x4b, 0xf8, 0x4f, 0xcc, 0x61, 0x10, + 0x69, 0xbc, 0x2e, 0xb6, 0x04, 0xc7, 0x42, 0x6d, 0x3b, 0x80, 0x98, 0x2b, 0x52, 0x03, 0xef, 0x70, + 0x5a, 0xd5, 0x1d, 0xbb, 0xc9, 0x71, 0xdf, 0x80, 0x55, 0xc6, 0x9c, 0x0d, 0x7a, 0x43, 0x14, 0x64, + 0xee, 0x38, 0x31, 0xe2, 0x0f, 0x56, 0x1b, 0xd7, 0xf6, 0xa0, 0x92, 0x8c, 0x4f, 0x5c, 0x02, 0x11, + 0xa1, 0x48, 0x62, 0xc5, 0x4a, 0xb3, 0xdb, 0x62, 0x65, 0xc6, 0xe7, 0x0a, 0xca, 0xb0, 0x72, 0xe7, + 0xa8, 0x3d, 0x50, 0x34, 0xf5, 0xa4, 0x33, 0x68, 0x1f, 0x2b, 0x28, 0x9b, 0xa8, 0xab, 0x0f, 0x73, + 0xc5, 0xb7, 0xd1, 0xf5, 0xda, 0x37, 0x19, 0xa8, 0xa6, 0x2f, 0x4a, 0xf8, 0xff, 0xe1, 0x72, 0xf4, + 0xaa, 0xe1, 0xd3, 0x40, 0x7b, 0x62, 0x7a, 0x7c, 0xe3, 0x4c, 0x88, 0x38, 0xc4, 0xe2, 0xa5, 0xdb, + 0x0c, 0x59, 0x7d, 0x1a, 0x7c, 0x62, 0x7a, 0x6c, 0x5b, 0x4c, 0x48, 0x80, 0x8f, 0xe0, 0xaa, 0xed, + 0x68, 0x7e, 0x40, 0x6c, 0x83, 0x78, 0x86, 0x36, 0x7b, 0x4f, 0xd2, 0x88, 0xae, 0x53, 0xdf, 0x77, + 0xc4, 0x81, 0x15, 0x6b, 0x79, 0xd5, 0x76, 0xfa, 0x21, 0x79, 0x96, 0xc9, 0x1b, 0x21, 0x75, 0x2e, + 0xcc, 0xb2, 0xe7, 0x85, 0xd9, 0x2b, 0x50, 0x9a, 0x10, 0x57, 0xa3, 0x76, 0xe0, 0x9d, 0xf1, 0xf2, + 0xb8, 0xa8, 0x16, 0x27, 0xc4, 0x55, 0x58, 0xfb, 0x85, 0xdc, 0x52, 0x0e, 0x73, 0xc5, 0x22, 0x2a, + 0x1d, 0xe6, 0x8a, 0x25, 0x04, 0xb5, 0x7f, 0x64, 0xa1, 0x92, 0x2c, 0x97, 0xd9, 0xed, 0x43, 0xe7, + 0x27, 0x8b, 0xc4, 0x73, 0xcf, 0x1b, 0xdf, 0x5a, 0x5c, 0xd7, 0x9b, 0xec, 0xc8, 0xd9, 0x2b, 0x88, + 0x22, 0x56, 0x15, 0x92, 0xec, 0xb8, 0x67, 0xd9, 0x86, 0x8a, 0xa2, 0xa1, 0xa8, 0x86, 0x2d, 0x7c, + 0x00, 0x85, 0x87, 0x3e, 0xd7, 0x5d, 0xe0, 0xba, 0xdf, 0xfc, 0x76, 0xdd, 0x87, 0x7d, 0xae, 0xbc, + 0x74, 0xd8, 0xd7, 0x3a, 0x5d, 0xf5, 0xb8, 0x71, 0xa4, 0x86, 0xe2, 0xf8, 0x0a, 0xe4, 0x2c, 0xf2, + 0xe5, 0x59, 0xfa, 0x70, 0xe2, 0xd0, 0x45, 0x17, 0xe1, 0x0a, 0xe4, 0x9e, 0x50, 0xf2, 0x28, 0x7d, + 0x24, 0x70, 0xe8, 0x07, 0xdc, 0x0c, 0xbb, 0x90, 0xe7, 0xfe, 0xc2, 0x00, 0xa1, 0xc7, 0xd0, 0x4b, + 0xb8, 0x08, 0xb9, 0x66, 0x57, 0x65, 0x1b, 0x02, 0x41, 0x45, 0xa0, 0x5a, 0xaf, 0xad, 0x34, 0x15, + 0x94, 0xa9, 0xdd, 0x81, 0x82, 0x70, 0x02, 0xdb, 0x2c, 0xb1, 0x1b, 0xd0, 0x4b, 0x61, 0x33, 0xd4, + 0x21, 0x45, 0xbd, 0x27, 0xc7, 0xfb, 0x8a, 0x8a, 0x32, 0xe9, 0xa5, 0xce, 0xa1, 0x7c, 0xcd, 0x87, + 0x4a, 0xb2, 0x5e, 0x7e, 0x31, 0x77, 0xe1, 0xbf, 0x4a, 0x50, 0x4e, 0xd4, 0xbf, 0xac, 0x70, 0x21, + 0x96, 0xe5, 0x3c, 0xd1, 0x88, 0x65, 0x12, 0x3f, 0x0c, 0x0d, 0xe0, 0x50, 0x83, 0x21, 0x17, 0x5d, + 0xba, 0x17, 0xb4, 0x45, 0xf2, 0xa8, 0x50, 0xfb, 0xa3, 0x04, 0x68, 0xbe, 0x00, 0x9d, 0x33, 0x53, + 0xfa, 0x31, 0xcd, 0xac, 0xfd, 0x41, 0x82, 0x6a, 0xba, 0xea, 0x9c, 0x33, 0xef, 0xda, 0x8f, 0x6a, + 0xde, 0xdf, 0x33, 0xb0, 0x9a, 0xaa, 0x35, 0x2f, 0x6a, 0xdd, 0x17, 0xb0, 0x6e, 0x1a, 0x74, 0xe2, + 0x3a, 0x01, 0xb5, 0xf5, 0x33, 0xcd, 0xa2, 0x8f, 0xa9, 0x25, 0xd7, 0x78, 0xd2, 0xd8, 0xfd, 0xf6, + 0x6a, 0xb6, 0xde, 0x9e, 0xc9, 0x1d, 0x31, 0xb1, 0xbd, 0x8d, 0x76, 0x4b, 0x39, 0xee, 0x75, 0x07, + 0x4a, 0xa7, 0xf9, 0x99, 0x76, 0xd2, 0xf9, 0x59, 0xa7, 0xfb, 0x49, 0x47, 0x45, 0xe6, 0x1c, 0xed, + 0x07, 0xdc, 0xf6, 0x3d, 0x40, 0xf3, 0x46, 0xe1, 0xcb, 0xb0, 0xcc, 0x2c, 0xf4, 0x12, 0xde, 0x80, + 0xb5, 0x4e, 0x57, 0xeb, 0xb7, 0x5b, 0x8a, 0xa6, 0x3c, 0x78, 0xa0, 0x34, 0x07, 0x7d, 0xf1, 0x3e, + 0x11, 0xb3, 0x07, 0xa9, 0x0d, 0x5e, 0xfb, 0x7d, 0x16, 0x36, 0x96, 0x58, 0x82, 0x1b, 0xe1, 0xcd, + 0x42, 0x5c, 0x76, 0xde, 0xbd, 0x88, 0xf5, 0x75, 0x56, 0x10, 0xf4, 0x88, 0x17, 0x84, 0x17, 0x91, + 0x1b, 0xc0, 0xbc, 0x64, 0x07, 0xe6, 0xd0, 0xa4, 0x5e, 0xf8, 0x9c, 0x23, 0xae, 0x1b, 0x6b, 0x33, + 0x5c, 0xbc, 0xe8, 0xfc, 0x1f, 0x60, 0xd7, 0xf1, 0xcd, 0xc0, 0x7c, 0x4c, 0x35, 0xd3, 0x8e, 0xde, + 0x7e, 0xd8, 0xf5, 0x23, 0xa7, 0xa2, 0xa8, 0xa7, 0x6d, 0x07, 0x31, 0xdb, 0xa6, 0x23, 0x32, 0xc7, + 0x66, 0xc9, 0x3c, 0xab, 0xa2, 0xa8, 0x27, 0x66, 0x5f, 0x83, 0x8a, 0xe1, 0x4c, 0x59, 0x4d, 0x26, + 0x78, 0xec, 0xec, 0x90, 0xd4, 0xb2, 0xc0, 0x62, 0x4a, 0x58, 0x6d, 0xcf, 0x1e, 0x9d, 0x2a, 0x6a, + 0x59, 0x60, 0x82, 0x72, 0x1d, 0xd6, 0xc8, 0x68, 0xe4, 0x31, 0xe5, 0x91, 0x22, 0x71, 0x7f, 0xa8, + 0xc6, 0x30, 0x27, 0x6e, 0x1d, 0x42, 0x31, 0xf2, 0x03, 0x3b, 0xaa, 0x99, 0x27, 0x34, 0x57, 0x5c, + 0x8a, 0x33, 0x3b, 0x25, 0xb5, 0x68, 0x47, 0x9d, 0xd7, 0xa0, 0x62, 0xfa, 0xda, 0xec, 0x0d, 0x3d, + 0xb3, 0x9d, 0xd9, 0x29, 0xaa, 0x65, 0xd3, 0x8f, 0xdf, 0x1f, 0x6b, 0x5f, 0x65, 0xa0, 0x9a, 0xfe, + 0x06, 0x80, 0x5b, 0x50, 0xb4, 0x1c, 0x9d, 0xf0, 0xd0, 0x12, 0x1f, 0xa0, 0x76, 0x9e, 0xf3, 0xd9, + 0xa0, 0x7e, 0x14, 0xf2, 0xd5, 0x58, 0x72, 0xeb, 0x6f, 0x12, 0x14, 0x23, 0x18, 0x5f, 0x82, 0x9c, + 0x4b, 0x82, 0x31, 0x57, 0x97, 0xdf, 0xcf, 0x20, 0x49, 0xe5, 0x6d, 0x86, 0xfb, 0x2e, 0xb1, 0x79, + 0x08, 0x84, 0x38, 0x6b, 0xb3, 0x75, 0xb5, 0x28, 0x31, 0xf8, 0xe5, 0xc4, 0x99, 0x4c, 0xa8, 0x1d, + 0xf8, 0xd1, 0xba, 0x86, 0x78, 0x33, 0x84, 0xf1, 0x3b, 0xb0, 0x1e, 0x78, 0xc4, 0xb4, 0x52, 0xdc, + 0x1c, 0xe7, 0xa2, 0xa8, 0x23, 0x26, 0xef, 0xc1, 0x95, 0x48, 0xaf, 0x41, 0x03, 0xa2, 0x8f, 0xa9, + 0x31, 0x13, 0x2a, 0xf0, 0x47, 0x88, 0xcb, 0x21, 0xa1, 0x15, 0xf6, 0x47, 0xb2, 0xb5, 0x6f, 0x24, + 0x58, 0x8f, 0xae, 0x53, 0x46, 0xec, 0xac, 0x63, 0x00, 0x62, 0xdb, 0x4e, 0x90, 0x74, 0xd7, 0x62, + 0x28, 0x2f, 0xc8, 0xd5, 0x1b, 0xb1, 0x90, 0x9a, 0x50, 0xb0, 0x35, 0x01, 0x98, 0xf5, 0x9c, 0xeb, + 0xb6, 0xab, 0x50, 0x0e, 0x3f, 0xf0, 0xf0, 0xaf, 0x84, 0xe2, 0x02, 0x0e, 0x02, 0x62, 0xf7, 0x2e, + 0xbc, 0x09, 0xf9, 0x53, 0x3a, 0x32, 0xed, 0xf0, 0xd9, 0x56, 0x34, 0xa2, 0x67, 0x92, 0x5c, 0xfc, + 0x4c, 0xb2, 0xff, 0x5b, 0x09, 0x36, 0x74, 0x67, 0x32, 0x6f, 0xef, 0x3e, 0x9a, 0x7b, 0x05, 0xf0, + 0x3f, 0x96, 0x3e, 0xff, 0x68, 0x64, 0x06, 0xe3, 0xe9, 0x69, 0x5d, 0x77, 0x26, 0xbb, 0x23, 0xc7, + 0x22, 0xf6, 0x68, 0xf6, 0x99, 0x93, 0xff, 0xd1, 0xdf, 0x1d, 0x51, 0xfb, 0xdd, 0x91, 0x93, 0xf8, + 0xe8, 0x79, 0x7f, 0xf6, 0xf7, 0xbf, 0x92, 0xf4, 0xa7, 0x4c, 0xf6, 0xa0, 0xb7, 0xff, 0xe7, 0xcc, + 0xd6, 0x81, 0x18, 0xae, 0x17, 0xb9, 0x47, 0xa5, 0x43, 0x8b, 0xea, 0x6c, 0xca, 0xff, 0x0b, 0x00, + 0x00, 0xff, 0xff, 0x1a, 0x28, 0x25, 0x79, 0x42, 0x1d, 0x00, 0x00, } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto index 4d4fb378..8697a50d 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto @@ -45,6 +45,7 @@ option java_package = "com.google.protobuf"; option java_outer_classname = "DescriptorProtos"; option csharp_namespace = "Google.Protobuf.Reflection"; option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; // descriptor.proto must be optimized for speed because reflection-based // algorithms don't work during bootstrapping. @@ -225,6 +226,26 @@ message EnumDescriptorProto { repeated EnumValueDescriptorProto value = 2; optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; } // Describes a value within an enum. @@ -396,10 +417,12 @@ message FileOptions { // determining the namespace. optional string php_namespace = 41; - // The parser stores options it doesn't recognize here. See above. + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. repeated UninterpretedOption uninterpreted_option = 999; - // Clients can define custom options in extensions of this message. See above. + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. extensions 1000 to max; reserved 38; diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/Makefile deleted file mode 100644 index b5715c35..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -include $(GOROOT)/src/Make.inc - -TARG=github.com/golang/protobuf/compiler/generator -GOFILES=\ - generator.go\ - -DEPS=../descriptor ../plugin ../../proto - -include $(GOROOT)/src/Make.pkg diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/generator.go b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/generator.go index 60d52464..c13a9f1e 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/generator.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/generator.go @@ -40,19 +40,24 @@ import ( "bufio" "bytes" "compress/gzip" + "crypto/sha256" + "encoding/hex" "fmt" + "go/build" "go/parser" "go/printer" "go/token" "log" "os" "path" + "sort" "strconv" "strings" "unicode" "unicode/utf8" "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/protoc-gen-go/generator/internal/remap" "github.com/golang/protobuf/protoc-gen-go/descriptor" plugin "github.com/golang/protobuf/protoc-gen-go/plugin" @@ -88,6 +93,14 @@ func RegisterPlugin(p Plugin) { plugins = append(plugins, p) } +// A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf". +type GoImportPath string + +func (p GoImportPath) String() string { return strconv.Quote(string(p)) } + +// A GoPackageName is the name of a Go package. e.g., "protobuf". +type GoPackageName string + // Each type we import as a protocol buffer (other than FileDescriptorProto) needs // a pointer to the FileDescriptorProto that represents it. These types achieve that // wrapping by placing each Proto inside a struct with the pointer to its File. The @@ -96,19 +109,21 @@ func RegisterPlugin(p Plugin) { // The file and package name method are common to messages and enums. type common struct { - file *descriptor.FileDescriptorProto // File this object comes from. + file *FileDescriptor // File this object comes from. } -// PackageName is name in the package clause in the generated file. -func (c *common) PackageName() string { return uniquePackageOf(c.file) } +// GoImportPath is the import path of the Go package containing the type. +func (c *common) GoImportPath() GoImportPath { + return c.file.importPath +} -func (c *common) File() *descriptor.FileDescriptorProto { return c.file } +func (c *common) File() *FileDescriptor { return c.file } func fileIsProto3(file *descriptor.FileDescriptorProto) bool { return file.GetSyntax() == "proto3" } -func (c *common) proto3() bool { return fileIsProto3(c.file) } +func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) } // Descriptor represents a protocol buffer message. type Descriptor struct { @@ -134,7 +149,7 @@ func (d *Descriptor) TypeName() []string { for parent := d; parent != nil; parent = parent.parent { n++ } - s := make([]string, n, n) + s := make([]string, n) for parent := d; parent != nil; parent = parent.parent { n-- s[n] = parent.GetName() @@ -256,77 +271,61 @@ type FileDescriptor struct { // This is used for supporting public imports. exported map[Object][]symbol - index int // The index of this file in the list of files to generate code for + fingerprint string // Fingerprint of this file's contents. + importPath GoImportPath // Import path of this file's package. + packageName GoPackageName // Name of this file's Go package. proto3 bool // whether to generate proto3 code for this file } -// PackageName is the package name we'll use in the generated code to refer to this file. -func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDescriptorProto) } - // VarName is the variable name we'll use in the generated code to refer // to the compressed bytes of this descriptor. It is not exported, so // it is only valid inside the generated package. -func (d *FileDescriptor) VarName() string { return fmt.Sprintf("fileDescriptor%d", d.index) } +func (d *FileDescriptor) VarName() string { + name := strings.Map(badToUnderscore, baseName(d.GetName())) + return fmt.Sprintf("fileDescriptor_%s_%s", name, d.fingerprint) +} // goPackageOption interprets the file's go_package option. // If there is no go_package, it returns ("", "", false). // If there's a simple name, it returns ("", pkg, true). // If the option implies an import path, it returns (impPath, pkg, true). -func (d *FileDescriptor) goPackageOption() (impPath, pkg string, ok bool) { - pkg = d.GetOptions().GetGoPackage() - if pkg == "" { - return +func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageName, ok bool) { + opt := d.GetOptions().GetGoPackage() + if opt == "" { + return "", "", false + } + // A semicolon-delimited suffix delimits the import path and package name. + sc := strings.Index(opt, ";") + if sc >= 0 { + return GoImportPath(opt[:sc]), cleanPackageName(opt[sc+1:]), true } - ok = true // The presence of a slash implies there's an import path. - slash := strings.LastIndex(pkg, "/") - if slash < 0 { - return + slash := strings.LastIndex(opt, "/") + if slash >= 0 { + return GoImportPath(opt), cleanPackageName(opt[slash+1:]), true } - impPath, pkg = pkg, pkg[slash+1:] - // A semicolon-delimited suffix overrides the package name. - sc := strings.IndexByte(impPath, ';') - if sc < 0 { - return - } - impPath, pkg = impPath[:sc], impPath[sc+1:] - return -} - -// goPackageName returns the Go package name to use in the -// generated Go file. The result explicit reports whether the name -// came from an option go_package statement. If explicit is false, -// the name was derived from the protocol buffer's package statement -// or the input file name. -func (d *FileDescriptor) goPackageName() (name string, explicit bool) { - // Does the file have a "go_package" option? - if _, pkg, ok := d.goPackageOption(); ok { - return pkg, true - } - - // Does the file have a package clause? - if pkg := d.GetPackage(); pkg != "" { - return pkg, false - } - // Use the file base name. - return baseName(d.GetName()), false + return "", cleanPackageName(opt), true } // goFileName returns the output name for the generated Go file. -func (d *FileDescriptor) goFileName() string { +func (d *FileDescriptor) goFileName(pathType pathType) string { name := *d.Name if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" { name = name[:len(name)-len(ext)] } name += ".pb.go" + if pathType == pathTypeSourceRelative { + return name + } + // Does the file have a "go_package" option? // If it does, it may override the filename. if impPath, _, ok := d.goPackageOption(); ok && impPath != "" { // Replace the existing dirname with the declared import path. _, name = path.Split(name) - name = path.Join(impPath, name) + name = path.Join(string(impPath), name) return name } @@ -341,14 +340,13 @@ func (d *FileDescriptor) addExport(obj Object, sym symbol) { type symbol interface { // GenerateAlias should generate an appropriate alias // for the symbol from the named package. - GenerateAlias(g *Generator, pkg string) + GenerateAlias(g *Generator, pkg GoPackageName) } type messageSymbol struct { sym string hasExtensions, isMessageSet bool - hasOneof bool - getters []getterSymbol + oneofTypes []string } type getterSymbol struct { @@ -358,144 +356,11 @@ type getterSymbol struct { genType bool // whether typ contains a generated type (message/group/enum) } -func (ms *messageSymbol) GenerateAlias(g *Generator, pkg string) { - remoteSym := pkg + "." + ms.sym - - g.P("type ", ms.sym, " ", remoteSym) - g.P("func (m *", ms.sym, ") Reset() { (*", remoteSym, ")(m).Reset() }") - g.P("func (m *", ms.sym, ") String() string { return (*", remoteSym, ")(m).String() }") - g.P("func (*", ms.sym, ") ProtoMessage() {}") - if ms.hasExtensions { - g.P("func (*", ms.sym, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange ", - "{ return (*", remoteSym, ")(nil).ExtensionRangeArray() }") - if ms.isMessageSet { - g.P("func (m *", ms.sym, ") Marshal() ([]byte, error) ", - "{ return (*", remoteSym, ")(m).Marshal() }") - g.P("func (m *", ms.sym, ") Unmarshal(buf []byte) error ", - "{ return (*", remoteSym, ")(m).Unmarshal(buf) }") - } +func (ms *messageSymbol) GenerateAlias(g *Generator, pkg GoPackageName) { + g.P("type ", ms.sym, " = ", pkg, ".", ms.sym) + for _, name := range ms.oneofTypes { + g.P("type ", name, " = ", pkg, ".", name) } - if ms.hasOneof { - // Oneofs and public imports do not mix well. - // We can make them work okay for the binary format, - // but they're going to break weirdly for text/JSON. - enc := "_" + ms.sym + "_OneofMarshaler" - dec := "_" + ms.sym + "_OneofUnmarshaler" - size := "_" + ms.sym + "_OneofSizer" - encSig := "(msg " + g.Pkg["proto"] + ".Message, b *" + g.Pkg["proto"] + ".Buffer) error" - decSig := "(msg " + g.Pkg["proto"] + ".Message, tag, wire int, b *" + g.Pkg["proto"] + ".Buffer) (bool, error)" - sizeSig := "(msg " + g.Pkg["proto"] + ".Message) int" - g.P("func (m *", ms.sym, ") XXX_OneofFuncs() (func", encSig, ", func", decSig, ", func", sizeSig, ", []interface{}) {") - g.P("return ", enc, ", ", dec, ", ", size, ", nil") - g.P("}") - - g.P("func ", enc, encSig, " {") - g.P("m := msg.(*", ms.sym, ")") - g.P("m0 := (*", remoteSym, ")(m)") - g.P("enc, _, _, _ := m0.XXX_OneofFuncs()") - g.P("return enc(m0, b)") - g.P("}") - - g.P("func ", dec, decSig, " {") - g.P("m := msg.(*", ms.sym, ")") - g.P("m0 := (*", remoteSym, ")(m)") - g.P("_, dec, _, _ := m0.XXX_OneofFuncs()") - g.P("return dec(m0, tag, wire, b)") - g.P("}") - - g.P("func ", size, sizeSig, " {") - g.P("m := msg.(*", ms.sym, ")") - g.P("m0 := (*", remoteSym, ")(m)") - g.P("_, _, size, _ := m0.XXX_OneofFuncs()") - g.P("return size(m0)") - g.P("}") - } - for _, get := range ms.getters { - - if get.typeName != "" { - g.RecordTypeUse(get.typeName) - } - typ := get.typ - val := "(*" + remoteSym + ")(m)." + get.name + "()" - if get.genType { - // typ will be "*pkg.T" (message/group) or "pkg.T" (enum) - // or "map[t]*pkg.T" (map to message/enum). - // The first two of those might have a "[]" prefix if it is repeated. - // Drop any package qualifier since we have hoisted the type into this package. - rep := strings.HasPrefix(typ, "[]") - if rep { - typ = typ[2:] - } - isMap := strings.HasPrefix(typ, "map[") - star := typ[0] == '*' - if !isMap { // map types handled lower down - typ = typ[strings.Index(typ, ".")+1:] - } - if star { - typ = "*" + typ - } - if rep { - // Go does not permit conversion between slice types where both - // element types are named. That means we need to generate a bit - // of code in this situation. - // typ is the element type. - // val is the expression to get the slice from the imported type. - - ctyp := typ // conversion type expression; "Foo" or "(*Foo)" - if star { - ctyp = "(" + typ + ")" - } - - g.P("func (m *", ms.sym, ") ", get.name, "() []", typ, " {") - g.In() - g.P("o := ", val) - g.P("if o == nil {") - g.In() - g.P("return nil") - g.Out() - g.P("}") - g.P("s := make([]", typ, ", len(o))") - g.P("for i, x := range o {") - g.In() - g.P("s[i] = ", ctyp, "(x)") - g.Out() - g.P("}") - g.P("return s") - g.Out() - g.P("}") - continue - } - if isMap { - // Split map[keyTyp]valTyp. - bra, ket := strings.Index(typ, "["), strings.Index(typ, "]") - keyTyp, valTyp := typ[bra+1:ket], typ[ket+1:] - // Drop any package qualifier. - // Only the value type may be foreign. - star := valTyp[0] == '*' - valTyp = valTyp[strings.Index(valTyp, ".")+1:] - if star { - valTyp = "*" + valTyp - } - - typ := "map[" + keyTyp + "]" + valTyp - g.P("func (m *", ms.sym, ") ", get.name, "() ", typ, " {") - g.P("o := ", val) - g.P("if o == nil { return nil }") - g.P("s := make(", typ, ", len(o))") - g.P("for k, v := range o {") - g.P("s[k] = (", valTyp, ")(v)") - g.P("}") - g.P("return s") - g.P("}") - continue - } - // Convert imported type into the forwarding type. - val = "(" + typ + ")(" + val + ")" - } - - g.P("func (m *", ms.sym, ") ", get.name, "() ", typ, " { return ", val, " }") - } - } type enumSymbol struct { @@ -503,16 +368,11 @@ type enumSymbol struct { proto3 bool // Whether this came from a proto3 file. } -func (es enumSymbol) GenerateAlias(g *Generator, pkg string) { +func (es enumSymbol) GenerateAlias(g *Generator, pkg GoPackageName) { s := es.name - g.P("type ", s, " ", pkg, ".", s) + g.P("type ", s, " = ", pkg, ".", s) g.P("var ", s, "_name = ", pkg, ".", s, "_name") g.P("var ", s, "_value = ", pkg, ".", s, "_value") - g.P("func (x ", s, ") String() string { return (", pkg, ".", s, ")(x).String() }") - if !es.proto3 { - g.P("func (x ", s, ") Enum() *", s, "{ return (*", s, ")((", pkg, ".", s, ")(x).Enum()) }") - g.P("func (x *", s, ") UnmarshalJSON(data []byte) error { return (*", pkg, ".", s, ")(x).UnmarshalJSON(data) }") - } } type constOrVarSymbol struct { @@ -521,8 +381,8 @@ type constOrVarSymbol struct { cast string // if non-empty, a type cast is required (used for enums) } -func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) { - v := pkg + "." + cs.sym +func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg GoPackageName) { + v := string(pkg) + "." + cs.sym if cs.cast != "" { v = cs.cast + "(" + v + ")" } @@ -531,21 +391,9 @@ func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) { // Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects. type Object interface { - PackageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness. + GoImportPath() GoImportPath TypeName() []string - File() *descriptor.FileDescriptorProto -} - -// Each package name we generate must be unique. The package we're generating -// gets its own name but every other package must have a unique name that does -// not conflict in the code we generate. These names are chosen globally (although -// they don't have to be, it simplifies things to do them globally). -func uniquePackageOf(fd *descriptor.FileDescriptorProto) string { - s, ok := uniquePackageName[fd] - if !ok { - log.Fatal("internal error: no package name defined for " + fd.GetName()) - } - return s + File() *FileDescriptor } // Generator is the type whose methods generate the output, stored in the associated response structure. @@ -562,18 +410,30 @@ type Generator struct { Pkg map[string]string // The names under which we import support packages - packageName string // What we're calling ourselves. - allFiles []*FileDescriptor // All files in the tree - allFilesByName map[string]*FileDescriptor // All files by filename. - genFiles []*FileDescriptor // Those files we will generate output for. - file *FileDescriptor // The file we are compiling now. - usedPackages map[string]bool // Names of packages used in current file. - typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax. - init []string // Lines to emit in the init function. + outputImportPath GoImportPath // Package we're generating code for. + allFiles []*FileDescriptor // All files in the tree + allFilesByName map[string]*FileDescriptor // All files by filename. + genFiles []*FileDescriptor // Those files we will generate output for. + file *FileDescriptor // The file we are compiling now. + packageNames map[GoImportPath]GoPackageName // Imported package names in the current file. + usedPackages map[GoImportPath]bool // Packages used in current file. + usedPackageNames map[GoPackageName]bool // Package names used in the current file. + typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax. + init []string // Lines to emit in the init function. indent string + pathType pathType // How to generate output filenames. writeOutput bool + annotateCode bool // whether to store annotations + annotations []*descriptor.GeneratedCodeInfo_Annotation // annotations to store } +type pathType int + +const ( + pathTypeImport pathType = iota + pathTypeSourceRelative +) + // New creates a new generator and allocates the request and response protobufs. func New() *Generator { g := new(Generator) @@ -618,8 +478,21 @@ func (g *Generator) CommandLineParameters(parameter string) { g.ImportPrefix = v case "import_path": g.PackageImportPath = v + case "paths": + switch v { + case "import": + g.pathType = pathTypeImport + case "source_relative": + g.pathType = pathTypeSourceRelative + default: + g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v)) + } case "plugins": pluginList = v + case "annotate_code": + if v == "true" { + g.annotateCode = true + } default: if len(k) > 0 && k[0] == 'M' { g.ImportMap[k[1:]] = v @@ -646,37 +519,42 @@ func (g *Generator) CommandLineParameters(parameter string) { // If its file is in a different package, it returns the package name we're using for this file, plus ".". // Otherwise it returns the empty string. func (g *Generator) DefaultPackageName(obj Object) string { - pkg := obj.PackageName() - if pkg == g.packageName { + importPath := obj.GoImportPath() + if importPath == g.outputImportPath { return "" } - return pkg + "." + return string(g.GoPackageName(importPath)) + "." } -// For each input file, the unique package name to use, underscored. -var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string) +// GoPackageName returns the name used for a package. +func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName { + if name, ok := g.packageNames[importPath]; ok { + return name + } + name := cleanPackageName(baseName(string(importPath))) + for i, orig := 1, name; g.usedPackageNames[name]; i++ { + name = orig + GoPackageName(strconv.Itoa(i)) + } + g.packageNames[importPath] = name + g.usedPackageNames[name] = true + return name +} -// Package names already registered. Key is the name from the .proto file; -// value is the name that appears in the generated code. -var pkgNamesInUse = make(map[string]bool) +var globalPackageNames = map[GoPackageName]bool{ + "fmt": true, + "math": true, + "proto": true, +} -// Create and remember a guaranteed unique package name for this file descriptor. -// Pkg is the candidate name. If f is nil, it's a builtin package like "proto" and -// has no file descriptor. +// Create and remember a guaranteed unique package name. Pkg is the candidate name. +// The FileDescriptor parameter is unused. func RegisterUniquePackageName(pkg string, f *FileDescriptor) string { - // Convert dots to underscores before finding a unique alias. - pkg = strings.Map(badToUnderscore, pkg) - - for i, orig := 1, pkg; pkgNamesInUse[pkg]; i++ { - // It's a duplicate; must rename. - pkg = orig + strconv.Itoa(i) + name := cleanPackageName(pkg) + for i, orig := 1, name; globalPackageNames[name]; i++ { + name = orig + GoPackageName(strconv.Itoa(i)) } - // Install it. - pkgNamesInUse[pkg] = true - if f != nil { - uniquePackageName[f.FileDescriptorProto] = pkg - } - return pkg + globalPackageNames[name] = true + return string(name) } var isGoKeyword = map[string]bool{ @@ -707,97 +585,83 @@ var isGoKeyword = map[string]bool{ "var": true, } +func cleanPackageName(name string) GoPackageName { + name = strings.Map(badToUnderscore, name) + // Identifier must not be keyword: insert _. + if isGoKeyword[name] { + name = "_" + name + } + // Identifier must not begin with digit: insert _. + if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) { + name = "_" + name + } + return GoPackageName(name) +} + // defaultGoPackage returns the package name to use, // derived from the import path of the package we're building code for. -func (g *Generator) defaultGoPackage() string { +func (g *Generator) defaultGoPackage() GoPackageName { p := g.PackageImportPath if i := strings.LastIndex(p, "/"); i >= 0 { p = p[i+1:] } - if p == "" { - return "" - } - - p = strings.Map(badToUnderscore, p) - // Identifier must not be keyword: insert _. - if isGoKeyword[p] { - p = "_" + p - } - // Identifier must not begin with digit: insert _. - if r, _ := utf8.DecodeRuneInString(p); unicode.IsDigit(r) { - p = "_" + p - } - return p + return cleanPackageName(p) } // SetPackageNames sets the package name for this run. // The package name must agree across all files being generated. // It also defines unique package names for all imported files. func (g *Generator) SetPackageNames() { - // Register the name for this package. It will be the first name - // registered so is guaranteed to be unmodified. - pkg, explicit := g.genFiles[0].goPackageName() + g.outputImportPath = g.genFiles[0].importPath - // Check all files for an explicit go_package option. + defaultPackageNames := make(map[GoImportPath]GoPackageName) for _, f := range g.genFiles { - thisPkg, thisExplicit := f.goPackageName() - if thisExplicit { - if !explicit { - // Let this file's go_package option serve for all input files. - pkg, explicit = thisPkg, true - } else if thisPkg != pkg { - g.Fail("inconsistent package names:", thisPkg, pkg) - } + if _, p, ok := f.goPackageOption(); ok { + defaultPackageNames[f.importPath] = p + } + } + for _, f := range g.genFiles { + if _, p, ok := f.goPackageOption(); ok { + // Source file: option go_package = "quux/bar"; + f.packageName = p + } else if p, ok := defaultPackageNames[f.importPath]; ok { + // A go_package option in another file in the same package. + // + // This is a poor choice in general, since every source file should + // contain a go_package option. Supported mainly for historical + // compatibility. + f.packageName = p + } else if p := g.defaultGoPackage(); p != "" { + // Command-line: import_path=quux/bar. + // + // The import_path flag sets a package name for files which don't + // contain a go_package option. + f.packageName = p + } else if p := f.GetPackage(); p != "" { + // Source file: package quux.bar; + f.packageName = cleanPackageName(p) + } else { + // Source filename. + f.packageName = cleanPackageName(baseName(f.GetName())) } } - // If we don't have an explicit go_package option but we have an - // import path, use that. - if !explicit { - p := g.defaultGoPackage() - if p != "" { - pkg, explicit = p, true + // Check that all files have a consistent package name and import path. + for _, f := range g.genFiles[1:] { + if a, b := g.genFiles[0].importPath, f.importPath; a != b { + g.Fail(fmt.Sprintf("inconsistent package import paths: %v, %v", a, b)) + } + if a, b := g.genFiles[0].packageName, f.packageName; a != b { + g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b)) } } - // If there was no go_package and no import path to use, - // double-check that all the inputs have the same implicit - // Go package name. - if !explicit { - for _, f := range g.genFiles { - thisPkg, _ := f.goPackageName() - if thisPkg != pkg { - g.Fail("inconsistent package names:", thisPkg, pkg) - } - } - } - - g.packageName = RegisterUniquePackageName(pkg, g.genFiles[0]) - - // Register the support package names. They might collide with the - // name of a package we import. + // Names of support packages. These never vary (if there are conflicts, + // we rename the conflicting package), so this could be removed someday. g.Pkg = map[string]string{ - "fmt": RegisterUniquePackageName("fmt", nil), - "math": RegisterUniquePackageName("math", nil), - "proto": RegisterUniquePackageName("proto", nil), - } - -AllFiles: - for _, f := range g.allFiles { - for _, genf := range g.genFiles { - if f == genf { - // In this package already. - uniquePackageName[f.FileDescriptorProto] = g.packageName - continue AllFiles - } - } - // The file is a dependency, so we want to ignore its go_package option - // because that is only relevant for its specific generated output. - pkg := f.GetPackage() - if pkg == "" { - pkg = baseName(*f.Name) - } - RegisterUniquePackageName(pkg, f) + "fmt": "fmt", + "math": "math", + "proto": "proto", } } @@ -807,27 +671,51 @@ AllFiles: func (g *Generator) WrapTypes() { g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile)) g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles)) + genFileNames := make(map[string]bool) + for _, n := range g.Request.FileToGenerate { + genFileNames[n] = true + } for _, f := range g.Request.ProtoFile { - // We must wrap the descriptors before we wrap the enums - descs := wrapDescriptors(f) - g.buildNestedDescriptors(descs) - enums := wrapEnumDescriptors(f, descs) - g.buildNestedEnums(descs, enums) - exts := wrapExtensions(f) fd := &FileDescriptor{ FileDescriptorProto: f, - desc: descs, - enum: enums, - ext: exts, exported: make(map[Object][]symbol), proto3: fileIsProto3(f), } + // The import path may be set in a number of ways. + if substitution, ok := g.ImportMap[f.GetName()]; ok { + // Command-line: M=foo.proto=quux/bar. + // + // Explicit mapping of source file to import path. + fd.importPath = GoImportPath(substitution) + } else if genFileNames[f.GetName()] && g.PackageImportPath != "" { + // Command-line: import_path=quux/bar. + // + // The import_path flag sets the import path for every file that + // we generate code for. + fd.importPath = GoImportPath(g.PackageImportPath) + } else if p, _, _ := fd.goPackageOption(); p != "" { + // Source file: option go_package = "quux/bar"; + // + // The go_package option sets the import path. Most users should use this. + fd.importPath = p + } else { + // Source filename. + // + // Last resort when nothing else is available. + fd.importPath = GoImportPath(path.Dir(f.GetName())) + } + // We must wrap the descriptors before we wrap the enums + fd.desc = wrapDescriptors(fd) + g.buildNestedDescriptors(fd.desc) + fd.enum = wrapEnumDescriptors(fd, fd.desc) + g.buildNestedEnums(fd.desc, fd.enum) + fd.ext = wrapExtensions(fd) extractComments(fd) g.allFiles = append(g.allFiles, fd) g.allFilesByName[f.GetName()] = fd } for _, fd := range g.allFiles { - fd.imp = wrapImported(fd.FileDescriptorProto, g) + fd.imp = wrapImported(fd, g) } g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate)) @@ -836,11 +724,27 @@ func (g *Generator) WrapTypes() { if fd == nil { g.Fail("could not find file named", fileName) } - fd.index = len(g.genFiles) + fingerprint, err := fingerprintProto(fd.FileDescriptorProto) + if err != nil { + g.Error(err) + } + fd.fingerprint = fingerprint g.genFiles = append(g.genFiles, fd) } } +// fingerprintProto returns a fingerprint for a message. +// The fingerprint is intended to prevent conflicts between generated fileds, +// not to provide cryptographic security. +func fingerprintProto(m proto.Message) (string, error) { + b, err := proto.Marshal(m) + if err != nil { + return "", err + } + h := sha256.Sum256(b) + return hex.EncodeToString(h[:8]), nil +} + // Scan the descriptors in this file. For each one, build the slice of nested descriptors func (g *Generator) buildNestedDescriptors(descs []*Descriptor) { for _, desc := range descs { @@ -873,7 +777,7 @@ func (g *Generator) buildNestedEnums(descs []*Descriptor, enums []*EnumDescripto } // Construct the Descriptor -func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) *Descriptor { +func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor { d := &Descriptor{ common: common{file}, DescriptorProto: desc, @@ -910,7 +814,7 @@ func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *d } // Return a slice of all the Descriptors defined within this file -func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor { +func wrapDescriptors(file *FileDescriptor) []*Descriptor { sl := make([]*Descriptor, 0, len(file.MessageType)+10) for i, desc := range file.MessageType { sl = wrapThisDescriptor(sl, desc, nil, file, i) @@ -919,7 +823,7 @@ func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor { } // Wrap this Descriptor, recursively -func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) []*Descriptor { +func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor { sl = append(sl, newDescriptor(desc, parent, file, index)) me := sl[len(sl)-1] for i, nested := range desc.NestedType { @@ -929,7 +833,7 @@ func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, pare } // Construct the EnumDescriptor -func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) *EnumDescriptor { +func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor { ed := &EnumDescriptor{ common: common{file}, EnumDescriptorProto: desc, @@ -945,7 +849,7 @@ func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, } // Return a slice of all the EnumDescriptors defined within this file -func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor { +func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor { sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10) // Top-level enums. for i, enum := range file.EnumType { @@ -961,7 +865,7 @@ func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descript } // Return a slice of all the top-level ExtensionDescriptors defined within this file. -func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor { +func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor { var sl []*ExtensionDescriptor for _, field := range file.Extension { sl = append(sl, &ExtensionDescriptor{common{file}, field, nil}) @@ -970,7 +874,7 @@ func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor } // Return a slice of all the types that are publicly imported into this file. -func wrapImported(file *descriptor.FileDescriptorProto, g *Generator) (sl []*ImportedDescriptor) { +func wrapImported(file *FileDescriptor, g *Generator) (sl []*ImportedDescriptor) { for _, index := range file.PublicDependency { df := g.fileByName(file.Dependency[index]) for _, d := range df.desc { @@ -1070,35 +974,84 @@ func (g *Generator) ObjectNamed(typeName string) Object { return o } +// AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated. +type AnnotatedAtoms struct { + source string + path string + atoms []interface{} +} + +// Annotate records the file name and proto AST path of a list of atoms +// so that a later call to P can emit a link from each atom to its origin. +func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms { + return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms} +} + +// printAtom prints the (atomic, non-annotation) argument to the generated output. +func (g *Generator) printAtom(v interface{}) { + switch v := v.(type) { + case string: + g.WriteString(v) + case *string: + g.WriteString(*v) + case bool: + fmt.Fprint(g, v) + case *bool: + fmt.Fprint(g, *v) + case int: + fmt.Fprint(g, v) + case *int32: + fmt.Fprint(g, *v) + case *int64: + fmt.Fprint(g, *v) + case float64: + fmt.Fprint(g, v) + case *float64: + fmt.Fprint(g, *v) + case GoPackageName: + g.WriteString(string(v)) + case GoImportPath: + g.WriteString(strconv.Quote(string(v))) + default: + g.Fail(fmt.Sprintf("unknown type in printer: %T", v)) + } +} + // P prints the arguments to the generated output. It handles strings and int32s, plus -// handling indirections because they may be *string, etc. +// handling indirections because they may be *string, etc. Any inputs of type AnnotatedAtoms may emit +// annotations in a .meta file in addition to outputting the atoms themselves (if g.annotateCode +// is true). func (g *Generator) P(str ...interface{}) { if !g.writeOutput { return } g.WriteString(g.indent) for _, v := range str { - switch s := v.(type) { - case string: - g.WriteString(s) - case *string: - g.WriteString(*s) - case bool: - fmt.Fprintf(g, "%t", s) - case *bool: - fmt.Fprintf(g, "%t", *s) - case int: - fmt.Fprintf(g, "%d", s) - case *int32: - fmt.Fprintf(g, "%d", *s) - case *int64: - fmt.Fprintf(g, "%d", *s) - case float64: - fmt.Fprintf(g, "%g", s) - case *float64: - fmt.Fprintf(g, "%g", *s) + switch v := v.(type) { + case *AnnotatedAtoms: + begin := int32(g.Len()) + for _, v := range v.atoms { + g.printAtom(v) + } + if g.annotateCode { + end := int32(g.Len()) + var path []int32 + for _, token := range strings.Split(v.path, ",") { + val, err := strconv.ParseInt(token, 10, 32) + if err != nil { + g.Fail("could not parse proto AST path: ", err.Error()) + } + path = append(path, int32(val)) + } + g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{ + Path: path, + SourceFile: &v.source, + Begin: &begin, + End: &end, + }) + } default: - g.Fail(fmt.Sprintf("unknown type in printer: %T", v)) + g.printAtom(v) } } g.WriteByte('\n') @@ -1135,15 +1088,25 @@ func (g *Generator) GenerateAllFiles() { } for _, file := range g.allFiles { g.Reset() + g.annotations = nil g.writeOutput = genFileMap[file] g.generate(file) if !g.writeOutput { continue } + fname := file.goFileName(g.pathType) g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{ - Name: proto.String(file.goFileName()), + Name: proto.String(fname), Content: proto.String(g.String()), }) + if g.annotateCode { + // Store the generated code annotations in text, as the protoc plugin protocol requires that + // strings contain valid UTF-8. + g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{ + Name: proto.String(file.goFileName(g.pathType) + ".meta"), + Content: proto.String(proto.CompactTextString(&descriptor.GeneratedCodeInfo{Annotation: g.annotations})), + }) + } } } @@ -1154,32 +1117,24 @@ func (g *Generator) runPlugins(file *FileDescriptor) { } } -// FileOf return the FileDescriptor for this FileDescriptorProto. -func (g *Generator) FileOf(fd *descriptor.FileDescriptorProto) *FileDescriptor { - for _, file := range g.allFiles { - if file.FileDescriptorProto == fd { - return file - } - } - g.Fail("could not find file in table:", fd.GetName()) - return nil -} - // Fill the response protocol buffer with the generated output for all the files we're // supposed to generate. func (g *Generator) generate(file *FileDescriptor) { - g.file = g.FileOf(file.FileDescriptorProto) - g.usedPackages = make(map[string]bool) - - if g.file.index == 0 { - // For one file in the package, assert version compatibility. - g.P("// This is a compile-time assertion to ensure that this generated file") - g.P("// is compatible with the proto package it is being compiled against.") - g.P("// A compilation error at this line likely means your copy of the") - g.P("// proto package needs to be updated.") - g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package") - g.P() + g.file = file + g.usedPackages = make(map[GoImportPath]bool) + g.packageNames = make(map[GoImportPath]GoPackageName) + g.usedPackageNames = make(map[GoPackageName]bool) + for name := range globalPackageNames { + g.usedPackageNames[name] = true } + + g.P("// This is a compile-time assertion to ensure that this generated file") + g.P("// is compatible with the proto package it is being compiled against.") + g.P("// A compilation error at this line likely means your copy of the") + g.P("// proto package needs to be updated.") + g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package") + g.P() + for _, td := range g.file.imp { g.generateImported(td) } @@ -1205,24 +1160,36 @@ func (g *Generator) generate(file *FileDescriptor) { // Generate header and imports last, though they appear first in the output. rem := g.Buffer + remAnno := g.annotations g.Buffer = new(bytes.Buffer) + g.annotations = nil g.generateHeader() g.generateImports() if !g.writeOutput { return } + // Adjust the offsets for annotations displaced by the header and imports. + for _, anno := range remAnno { + *anno.Begin += int32(g.Len()) + *anno.End += int32(g.Len()) + g.annotations = append(g.annotations, anno) + } g.Write(rem.Bytes()) - // Reformat generated code. + // Reformat generated code and patch annotation locations. fset := token.NewFileSet() - raw := g.Bytes() - ast, err := parser.ParseFile(fset, "", g, parser.ParseComments) + original := g.Bytes() + if g.annotateCode { + // make a copy independent of g; we'll need it after Reset. + original = append([]byte(nil), original...) + } + ast, err := parser.ParseFile(fset, "", original, parser.ParseComments) if err != nil { // Print out the bad code with line numbers. // This should never happen in practice, but it can while changing generated code, // so consider this a debugging aid. var src bytes.Buffer - s := bufio.NewScanner(bytes.NewReader(raw)) + s := bufio.NewScanner(bytes.NewReader(original)) for line := 1; s.Scan(); line++ { fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes()) } @@ -1233,55 +1200,59 @@ func (g *Generator) generate(file *FileDescriptor) { if err != nil { g.Fail("generated Go source code could not be reformatted:", err.Error()) } + if g.annotateCode { + m, err := remap.Compute(original, g.Bytes()) + if err != nil { + g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error()) + } + for _, anno := range g.annotations { + new, ok := m.Find(int(*anno.Begin), int(*anno.End)) + if !ok { + g.Fail("span in formatted generated Go source code could not be mapped back to the original code") + } + *anno.Begin = int32(new.Pos) + *anno.End = int32(new.End) + } + } } // Generate the header, including package definition func (g *Generator) generateHeader() { g.P("// Code generated by protoc-gen-go. DO NOT EDIT.") - g.P("// source: ", g.file.Name) + if g.file.GetOptions().GetDeprecated() { + g.P("// ", g.file.Name, " is a deprecated file.") + } else { + g.P("// source: ", g.file.Name) + } g.P() - name := g.file.PackageName() + importPath, _, _ := g.file.goPackageOption() + if importPath == "" { + g.P("package ", g.file.packageName) + } else { + g.P("package ", g.file.packageName, " // import ", GoImportPath(g.ImportPrefix)+importPath) + } + g.P() - if g.file.index == 0 { - // Generate package docs for the first file in the package. + if loc, ok := g.file.comments[strconv.Itoa(packagePath)]; ok { g.P("/*") - g.P("Package ", name, " is a generated protocol buffer package.") - g.P() - if loc, ok := g.file.comments[strconv.Itoa(packagePath)]; ok { - // not using g.PrintComments because this is a /* */ comment block. - text := strings.TrimSuffix(loc.GetLeadingComments(), "\n") - for _, line := range strings.Split(text, "\n") { - line = strings.TrimPrefix(line, " ") - // ensure we don't escape from the block comment - line = strings.Replace(line, "*/", "* /", -1) - g.P(line) - } - g.P() - } - var topMsgs []string - g.P("It is generated from these files:") - for _, f := range g.genFiles { - g.P("\t", f.Name) - for _, msg := range f.desc { - if msg.parent != nil { - continue - } - topMsgs = append(topMsgs, CamelCaseSlice(msg.TypeName())) - } - } - g.P() - g.P("It has these top-level messages:") - for _, msg := range topMsgs { - g.P("\t", msg) + // not using g.PrintComments because this is a /* */ comment block. + text := strings.TrimSuffix(loc.GetLeadingComments(), "\n") + for _, line := range strings.Split(text, "\n") { + line = strings.TrimPrefix(line, " ") + // ensure we don't escape from the block comment + line = strings.Replace(line, "*/", "* /", -1) + g.P(line) } g.P("*/") + g.P() } - - g.P("package ", name) - g.P() } +// deprecationComment is the standard comment added to deprecated +// messages, fields, enums, and enum values. +var deprecationComment = "// Deprecated: Do not use." + // PrintComments prints any comments from the source .proto file. // The path is a comma-separated list of integers. // It returns an indication of whether any comments were printed. @@ -1290,16 +1261,28 @@ func (g *Generator) PrintComments(path string) bool { if !g.writeOutput { return false } - if loc, ok := g.file.comments[path]; ok { - text := strings.TrimSuffix(loc.GetLeadingComments(), "\n") - for _, line := range strings.Split(text, "\n") { - g.P("// ", strings.TrimPrefix(line, " ")) - } + if c, ok := g.makeComments(path); ok { + g.P(c) return true } return false } +// makeComments generates the comment string for the field, no "\n" at the end +func (g *Generator) makeComments(path string) (string, bool) { + loc, ok := g.file.comments[path] + if !ok { + return "", false + } + w := new(bytes.Buffer) + nl := "" + for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") { + fmt.Fprintf(w, "%s// %s", nl, strings.TrimPrefix(line, " ")) + nl = "\n" + } + return w.String(), true +} + func (g *Generator) fileByName(filename string) *FileDescriptor { return g.allFilesByName[filename] } @@ -1319,35 +1302,46 @@ func (g *Generator) generateImports() { // We almost always need a proto import. Rather than computing when we // do, which is tricky when there's a plugin, just import it and // reference it later. The same argument applies to the fmt and math packages. - g.P("import " + g.Pkg["proto"] + " " + strconv.Quote(g.ImportPrefix+"github.com/golang/protobuf/proto")) + g.P("import "+g.Pkg["proto"]+" ", GoImportPath(g.ImportPrefix)+"github.com/golang/protobuf/proto") g.P("import " + g.Pkg["fmt"] + ` "fmt"`) g.P("import " + g.Pkg["math"] + ` "math"`) + var ( + imports = make(map[GoImportPath]bool) + strongImports = make(map[GoImportPath]bool) + importPaths []string + ) for i, s := range g.file.Dependency { fd := g.fileByName(s) + importPath := fd.importPath // Do not import our own package. - if fd.PackageName() == g.packageName { + if importPath == g.file.importPath { continue } - filename := fd.goFileName() - // By default, import path is the dirname of the Go filename. - importPath := path.Dir(filename) - if substitution, ok := g.ImportMap[s]; ok { - importPath = substitution + if !imports[importPath] { + importPaths = append(importPaths, string(importPath)) } - importPath = g.ImportPrefix + importPath + imports[importPath] = true + if !g.weak(int32(i)) { + strongImports[importPath] = true + } + } + sort.Strings(importPaths) + for i := range importPaths { + importPath := GoImportPath(importPaths[i]) + packageName := g.GoPackageName(importPath) + fullPath := GoImportPath(g.ImportPrefix) + importPath // Skip weak imports. - if g.weak(int32(i)) { - g.P("// skipping weak import ", fd.PackageName(), " ", strconv.Quote(importPath)) + if !strongImports[importPath] { + g.P("// skipping weak import ", packageName, " ", fullPath) continue } // We need to import all the dependencies, even if we don't reference them, // because other code and tools depend on having the full transitive closure // of protocol buffer types in the binary. - pname := fd.PackageName() - if _, ok := g.usedPackages[pname]; !ok { - pname = "_" + if _, ok := g.usedPackages[importPath]; !ok { + packageName = "_" } - g.P("import ", pname, " ", strconv.Quote(importPath)) + g.P("import ", packageName, " ", fullPath) } g.P() // TODO: may need to worry about uniqueness across plugins @@ -1363,26 +1357,24 @@ func (g *Generator) generateImports() { } func (g *Generator) generateImported(id *ImportedDescriptor) { - // Don't generate public import symbols for files that we are generating - // code for, since those symbols will already be in this package. - // We can't simply avoid creating the ImportedDescriptor objects, - // because g.genFiles isn't populated at that stage. tn := id.TypeName() sn := tn[len(tn)-1] - df := g.FileOf(id.o.File()) + df := id.o.File() filename := *df.Name - for _, fd := range g.genFiles { - if *fd.Name == filename { - g.P("// Ignoring public import of ", sn, " from ", filename) - g.P() - return - } + if df.importPath == g.file.importPath { + // Don't generate type aliases for files in the same Go package as this one. + g.P("// Ignoring public import of ", sn, " from ", filename) + g.P() + return + } + if !supportTypeAliases { + g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename)) } g.P("// ", sn, " from public import ", filename) - g.usedPackages[df.PackageName()] = true + g.usedPackages[df.importPath] = true for _, sym := range df.exported[id.o] { - sym.GenerateAlias(g, df.PackageName()) + sym.GenerateAlias(g, g.GoPackageName(df.importPath)) } g.P() @@ -1396,22 +1388,29 @@ func (g *Generator) generateEnum(enum *EnumDescriptor) { ccTypeName := CamelCaseSlice(typeName) ccPrefix := enum.prefix() + deprecatedEnum := "" + if enum.GetOptions().GetDeprecated() { + deprecatedEnum = deprecationComment + } g.PrintComments(enum.path) - g.P("type ", ccTypeName, " int32") + g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum) g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()}) g.P("const (") - g.In() for i, e := range enum.Value { - g.PrintComments(fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i)) + etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i) + g.PrintComments(etorPath) + + deprecatedValue := "" + if e.GetOptions().GetDeprecated() { + deprecatedValue = deprecationComment + } name := ccPrefix + *e.Name - g.P(name, " ", ccTypeName, " = ", e.Number) + g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue) g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName}) } - g.Out() g.P(")") g.P("var ", ccTypeName, "_name = map[int32]string{") - g.In() generated := make(map[int32]bool) // avoid duplicate values for _, e := range enum.Value { duplicate := "" @@ -1421,44 +1420,33 @@ func (g *Generator) generateEnum(enum *EnumDescriptor) { g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",") generated[*e.Number] = true } - g.Out() g.P("}") g.P("var ", ccTypeName, "_value = map[string]int32{") - g.In() for _, e := range enum.Value { g.P(strconv.Quote(*e.Name), ": ", e.Number, ",") } - g.Out() g.P("}") if !enum.proto3() { g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {") - g.In() g.P("p := new(", ccTypeName, ")") g.P("*p = x") g.P("return p") - g.Out() g.P("}") } g.P("func (x ", ccTypeName, ") String() string {") - g.In() g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))") - g.Out() g.P("}") if !enum.proto3() { g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {") - g.In() g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`) g.P("if err != nil {") - g.In() g.P("return err") - g.Out() g.P("}") g.P("*x = ", ccTypeName, "(value)") g.P("return nil") - g.Out() g.P("}") } @@ -1468,7 +1456,9 @@ func (g *Generator) generateEnum(enum *EnumDescriptor) { indexes = append([]string{strconv.Itoa(m.index)}, indexes...) } indexes = append(indexes, strconv.Itoa(enum.index)) - g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) { return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "} }") + g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {") + g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") + g.P("}") if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" { g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`) } @@ -1535,7 +1525,7 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor } enum := "" if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { - // We avoid using obj.PackageName(), because we want to use the + // We avoid using obj.GoPackageName(), because we want to use the // original (proto-world) package name. obj := g.ObjectNamed(field.GetTypeName()) if id, ok := obj.(*ImportedDescriptor); ok { @@ -1574,12 +1564,7 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor } name = ",name=" + name if message.proto3() { - // We only need the extra tag for []byte fields; - // no need to add noise for the others. - if *field.Type == descriptor.FieldDescriptorProto_TYPE_BYTES { - name += ",proto3" - } - + name += ",proto3" } oneof := "" if field.OneofIndex != nil { @@ -1617,12 +1602,6 @@ func (g *Generator) TypeName(obj Object) string { return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName()) } -// TypeNameWithPackage is like TypeName, but always includes the package -// name even if the object is in our own package. -func (g *Generator) TypeNameWithPackage(obj Object) string { - return obj.PackageName() + CamelCaseSlice(obj.TypeName()) -} - // GoType returns a string representing the type name, and the wire type func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) { // TODO: Options. @@ -1682,10 +1661,10 @@ func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescripto } func (g *Generator) RecordTypeUse(t string) { - if obj, ok := g.typeNameToObject[t]; ok { + if _, ok := g.typeNameToObject[t]; ok { // Call ObjectNamed to get the true object to record the use. - obj = g.ObjectNamed(t) - g.usedPackages[obj.PackageName()] = true + obj := g.ObjectNamed(t) + g.usedPackages[obj.GoImportPath()] = true } } @@ -1725,30 +1704,763 @@ var wellKnownTypes = map[string]bool{ "BytesValue": true, } -// Generate the type and default constant definitions for this Descriptor. +// getterDefault finds the default value for the field to return from a getter, +// regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName" +func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType string) string { + if isRepeated(field) { + return "nil" + } + if def := field.GetDefaultValue(); def != "" { + defaultConstant := g.defaultConstantName(goMessageType, field.GetName()) + if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES { + return defaultConstant + } + return "append([]byte(nil), " + defaultConstant + "...)" + } + switch *field.Type { + case descriptor.FieldDescriptorProto_TYPE_BOOL: + return "false" + case descriptor.FieldDescriptorProto_TYPE_STRING: + return `""` + case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_BYTES: + return "nil" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + obj := g.ObjectNamed(field.GetTypeName()) + var enum *EnumDescriptor + if id, ok := obj.(*ImportedDescriptor); ok { + // The enum type has been publicly imported. + enum, _ = id.o.(*EnumDescriptor) + } else { + enum, _ = obj.(*EnumDescriptor) + } + if enum == nil { + log.Printf("don't know how to generate getter for %s", field.GetName()) + return "nil" + } + if len(enum.Value) == 0 { + return "0 // empty enum" + } + first := enum.Value[0].GetName() + return g.DefaultPackageName(obj) + enum.prefix() + first + default: + return "0" + } +} + +// defaultConstantName builds the name of the default constant from the message +// type name and the untouched field name, e.g. "Default_MessageType_FieldName" +func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string { + return "Default_" + goMessageType + "_" + CamelCase(protoFieldName) +} + +// The different types of fields in a message and how to actually print them +// Most of the logic for generateMessage is in the methods of these types. +// +// Note that the content of the field is irrelevant, a simpleField can contain +// anything from a scalar to a group (which is just a message). +// +// Extension fields (and message sets) are however handled separately. +// +// simpleField - a field that is neiter weak nor oneof, possibly repeated +// oneofField - field containing list of subfields: +// - oneofSubField - a field within the oneof + +// msgCtx contais the context for the generator functions. +type msgCtx struct { + goName string // Go struct name of the message, e.g. MessageName + message *Descriptor // The descriptor for the message +} + +// fieldCommon contains data common to all types of fields. +type fieldCommon struct { + goName string // Go name of field, e.g. "FieldName" or "Descriptor_" + protoName string // Name of field in proto language, e.g. "field_name" or "descriptor" + getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_" + goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage" + tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"` + fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0" +} + +// getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor". +func (f *fieldCommon) getProtoName() string { + return f.protoName +} + +// getGoType returns the go type of the field as a string, e.g. "*int32". +func (f *fieldCommon) getGoType() string { + return f.goType +} + +// simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated. +type simpleField struct { + fieldCommon + protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" + protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 + deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use." + getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" + protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" + comment string // The full comment for the field, e.g. "// Useful information" +} + +// decl prints the declaration of the field in the struct (if any). +func (f *simpleField) decl(g *Generator, mc *msgCtx) { + g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated) +} + +// getter prints the getter for the field. +func (f *simpleField) getter(g *Generator, mc *msgCtx) { + star := "" + tname := f.goType + if needsStar(f.protoType) && tname[0] == '*' { + tname = tname[1:] + star = "*" + } + if f.deprecated != "" { + g.P(f.deprecated) + } + g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() "+tname+" {") + if f.getterDef == "nil" { // Simpler getter + g.P("if m != nil {") + g.P("return m." + f.goName) + g.P("}") + g.P("return nil") + g.P("}") + g.P() + return + } + if mc.message.proto3() { + g.P("if m != nil {") + } else { + g.P("if m != nil && m." + f.goName + " != nil {") + } + g.P("return " + star + "m." + f.goName) + g.P("}") + g.P("return ", f.getterDef) + g.P("}") + g.P() +} + +// setter prints the setter method of the field. +func (f *simpleField) setter(g *Generator, mc *msgCtx) { + // No setter for regular fields yet +} + +// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". +func (f *simpleField) getProtoDef() string { + return f.protoDef +} + +// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". +func (f *simpleField) getProtoTypeName() string { + return f.protoTypeName +} + +// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. +func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type { + return f.protoType +} + +// oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message. +type oneofSubField struct { + fieldCommon + protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" + protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 + oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName" + fieldNumber int // Actual field number, as defined in proto, e.g. 12 + getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" + protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" +} + +// wireTypeName returns a textual wire type, needed for oneof sub fields in generated code. +func (f *oneofSubField) wireTypeName() string { + switch f.protoType { + case descriptor.FieldDescriptorProto_TYPE_FIXED64, + descriptor.FieldDescriptorProto_TYPE_SFIXED64, + descriptor.FieldDescriptorProto_TYPE_DOUBLE: + return "WireFixed64" + case descriptor.FieldDescriptorProto_TYPE_FIXED32, + descriptor.FieldDescriptorProto_TYPE_SFIXED32, + descriptor.FieldDescriptorProto_TYPE_FLOAT: + return "WireFixed32" + case descriptor.FieldDescriptorProto_TYPE_GROUP: + return "WireStartGroup" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE, + descriptor.FieldDescriptorProto_TYPE_STRING, + descriptor.FieldDescriptorProto_TYPE_BYTES: + return "WireBytes" + default: // All others are Varints + return "WireVarint" + } +} + +// typedNil prints a nil casted to the pointer to this field. +// - for XXX_OneofFuncs +func (f *oneofSubField) typedNil(g *Generator) { + g.P("(*", f.oneofTypeName, ")(nil),") +} + +// marshalCase prints the case matching this oneof subfield in the marshalling code. +func (f *oneofSubField) marshalCase(g *Generator) { + g.P("case *", f.oneofTypeName, ":") + wire := f.wireTypeName() + var pre, post string + val := "x." + f.goName // overridden for TYPE_BOOL + switch f.protoType { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + pre = "b.EncodeFixed64(" + g.Pkg["math"] + ".Float64bits(" + post = "))" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + pre = "b.EncodeFixed32(uint64(" + g.Pkg["math"] + ".Float32bits(" + post = ")))" + case descriptor.FieldDescriptorProto_TYPE_INT64, descriptor.FieldDescriptorProto_TYPE_UINT64: + pre, post = "b.EncodeVarint(uint64(", "))" + case descriptor.FieldDescriptorProto_TYPE_INT32, descriptor.FieldDescriptorProto_TYPE_UINT32, descriptor.FieldDescriptorProto_TYPE_ENUM: + pre, post = "b.EncodeVarint(uint64(", "))" + case descriptor.FieldDescriptorProto_TYPE_FIXED64, descriptor.FieldDescriptorProto_TYPE_SFIXED64: + pre, post = "b.EncodeFixed64(uint64(", "))" + case descriptor.FieldDescriptorProto_TYPE_FIXED32, descriptor.FieldDescriptorProto_TYPE_SFIXED32: + pre, post = "b.EncodeFixed32(uint64(", "))" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + g.P("t := uint64(0)") + g.P("if ", val, " { t = 1 }") + val = "t" + pre, post = "b.EncodeVarint(", ")" + case descriptor.FieldDescriptorProto_TYPE_STRING: + pre, post = "b.EncodeStringBytes(", ")" + case descriptor.FieldDescriptorProto_TYPE_GROUP: + pre, post = "b.Marshal(", ")" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + pre, post = "b.EncodeMessage(", ")" + case descriptor.FieldDescriptorProto_TYPE_BYTES: + pre, post = "b.EncodeRawBytes(", ")" + case descriptor.FieldDescriptorProto_TYPE_SINT32: + pre, post = "b.EncodeZigzag32(uint64(", "))" + case descriptor.FieldDescriptorProto_TYPE_SINT64: + pre, post = "b.EncodeZigzag64(uint64(", "))" + default: + g.Fail("unhandled oneof field type ", f.protoType.String()) + } + g.P("b.EncodeVarint(", f.fieldNumber, "<<3|", g.Pkg["proto"], ".", wire, ")") + if t := f.protoType; t != descriptor.FieldDescriptorProto_TYPE_GROUP && t != descriptor.FieldDescriptorProto_TYPE_MESSAGE { + g.P(pre, val, post) + } else { + g.P("if err := ", pre, val, post, "; err != nil {") + g.P("return err") + g.P("}") + } + if f.protoType == descriptor.FieldDescriptorProto_TYPE_GROUP { + g.P("b.EncodeVarint(", f.fieldNumber, "<<3|", g.Pkg["proto"], ".WireEndGroup)") + } +} + +// unmarshalCase prints the case matching this oneof subfield in the unmarshalling code. +func (f *oneofSubField) unmarshalCase(g *Generator, origOneofName string, oneofName string) { + g.P("case ", f.fieldNumber, ": // ", origOneofName, ".", f.getProtoName()) + g.P("if wire != ", g.Pkg["proto"], ".", f.wireTypeName(), " {") + g.P("return true, ", g.Pkg["proto"], ".ErrInternalBadWireType") + g.P("}") + lhs := "x, err" // overridden for TYPE_MESSAGE and TYPE_GROUP + var dec, cast, cast2 string + switch f.protoType { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + dec, cast = "b.DecodeFixed64()", g.Pkg["math"]+".Float64frombits" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + dec, cast, cast2 = "b.DecodeFixed32()", "uint32", g.Pkg["math"]+".Float32frombits" + case descriptor.FieldDescriptorProto_TYPE_INT64: + dec, cast = "b.DecodeVarint()", "int64" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + dec = "b.DecodeVarint()" + case descriptor.FieldDescriptorProto_TYPE_INT32: + dec, cast = "b.DecodeVarint()", "int32" + case descriptor.FieldDescriptorProto_TYPE_FIXED64: + dec = "b.DecodeFixed64()" + case descriptor.FieldDescriptorProto_TYPE_FIXED32: + dec, cast = "b.DecodeFixed32()", "uint32" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + dec = "b.DecodeVarint()" + // handled specially below + case descriptor.FieldDescriptorProto_TYPE_STRING: + dec = "b.DecodeStringBytes()" + case descriptor.FieldDescriptorProto_TYPE_GROUP: + g.P("msg := new(", f.goType[1:], ")") // drop star + lhs = "err" + dec = "b.DecodeGroup(msg)" + // handled specially below + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + g.P("msg := new(", f.goType[1:], ")") // drop star + lhs = "err" + dec = "b.DecodeMessage(msg)" + // handled specially below + case descriptor.FieldDescriptorProto_TYPE_BYTES: + dec = "b.DecodeRawBytes(true)" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + dec, cast = "b.DecodeVarint()", "uint32" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + dec, cast = "b.DecodeVarint()", f.goType + case descriptor.FieldDescriptorProto_TYPE_SFIXED32: + dec, cast = "b.DecodeFixed32()", "int32" + case descriptor.FieldDescriptorProto_TYPE_SFIXED64: + dec, cast = "b.DecodeFixed64()", "int64" + case descriptor.FieldDescriptorProto_TYPE_SINT32: + dec, cast = "b.DecodeZigzag32()", "int32" + case descriptor.FieldDescriptorProto_TYPE_SINT64: + dec, cast = "b.DecodeZigzag64()", "int64" + default: + g.Fail("unhandled oneof field type ", f.protoType.String()) + } + g.P(lhs, " := ", dec) + val := "x" + if cast != "" { + val = cast + "(" + val + ")" + } + if cast2 != "" { + val = cast2 + "(" + val + ")" + } + switch f.protoType { + case descriptor.FieldDescriptorProto_TYPE_BOOL: + val += " != 0" + case descriptor.FieldDescriptorProto_TYPE_GROUP, + descriptor.FieldDescriptorProto_TYPE_MESSAGE: + val = "msg" + } + g.P("m.", oneofName, " = &", f.oneofTypeName, "{", val, "}") + g.P("return true, err") +} + +// sizerCase prints the case matching this oneof subfield in the sizer code. +func (f *oneofSubField) sizerCase(g *Generator) { + g.P("case *", f.oneofTypeName, ":") + val := "x." + f.goName + var varint, fixed string + switch f.protoType { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + fixed = "8" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + fixed = "4" + case descriptor.FieldDescriptorProto_TYPE_INT64, descriptor.FieldDescriptorProto_TYPE_UINT64, descriptor.FieldDescriptorProto_TYPE_INT32, descriptor.FieldDescriptorProto_TYPE_UINT32, descriptor.FieldDescriptorProto_TYPE_ENUM: + varint = val + case descriptor.FieldDescriptorProto_TYPE_FIXED64, descriptor.FieldDescriptorProto_TYPE_SFIXED64: + fixed = "8" + case descriptor.FieldDescriptorProto_TYPE_FIXED32, descriptor.FieldDescriptorProto_TYPE_SFIXED32: + fixed = "4" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + fixed = "1" + case descriptor.FieldDescriptorProto_TYPE_STRING: + fixed = "len(" + val + ")" + varint = fixed + case descriptor.FieldDescriptorProto_TYPE_GROUP: + fixed = g.Pkg["proto"] + ".Size(" + val + ")" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + g.P("s := ", g.Pkg["proto"], ".Size(", val, ")") + fixed = "s" + varint = fixed + case descriptor.FieldDescriptorProto_TYPE_BYTES: + fixed = "len(" + val + ")" + varint = fixed + case descriptor.FieldDescriptorProto_TYPE_SINT32: + varint = "(uint32(" + val + ") << 1) ^ uint32((int32(" + val + ") >> 31))" + case descriptor.FieldDescriptorProto_TYPE_SINT64: + varint = "uint64(" + val + " << 1) ^ uint64((int64(" + val + ") >> 63))" + default: + g.Fail("unhandled oneof field type ", f.protoType.String()) + } + // Tag and wire varint is known statically, + // so don't generate code for that part of the size computation. + tagAndWireSize := proto.SizeVarint(uint64(f.fieldNumber << 3)) // wire doesn't affect varint size + g.P("n += ", tagAndWireSize, " // tag and wire") + if varint != "" { + g.P("n += ", g.Pkg["proto"], ".SizeVarint(uint64(", varint, "))") + } + if fixed != "" { + g.P("n += ", fixed) + } + if f.protoType == descriptor.FieldDescriptorProto_TYPE_GROUP { + g.P("n += ", tagAndWireSize, " // tag and wire") + } +} + +// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". +func (f *oneofSubField) getProtoDef() string { + return f.protoDef +} + +// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". +func (f *oneofSubField) getProtoTypeName() string { + return f.protoTypeName +} + +// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. +func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type { + return f.protoType +} + +// oneofField represents the oneof on top level. +// The alternative fields within the oneof are represented by oneofSubField. +type oneofField struct { + fieldCommon + subFields []*oneofSubField // All the possible oneof fields + comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\" +} + +// decl prints the declaration of the field in the struct (if any). +func (f *oneofField) decl(g *Generator, mc *msgCtx) { + comment := f.comment + for _, sf := range f.subFields { + comment += "//\t*" + sf.oneofTypeName + "\n" + } + g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`") +} + +// getter for a oneof field will print additional discriminators and interfaces for the oneof, +// also it prints all the getters for the sub fields. +func (f *oneofField) getter(g *Generator, mc *msgCtx) { + // The discriminator type + g.P("type ", f.goType, " interface {") + g.P(f.goType, "()") + g.P("}") + g.P() + // The subField types, fulfilling the discriminator type contract + for _, sf := range f.subFields { + g.P("type ", Annotate(mc.message.file, sf.fullPath, sf.oneofTypeName), " struct {") + g.P(Annotate(mc.message.file, sf.fullPath, sf.goName), " ", sf.goType, " `", sf.tags, "`") + g.P("}") + g.P() + } + for _, sf := range f.subFields { + g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}") + g.P() + } + // Getter for the oneof field + g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() ", f.goType, " {") + g.P("if m != nil { return m.", f.goName, " }") + g.P("return nil") + g.P("}") + g.P() + // Getters for each oneof + for _, sf := range f.subFields { + g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, sf.fullPath, sf.getterName), "() "+sf.goType+" {") + g.P("if x, ok := m.", f.getterName, "().(*", sf.oneofTypeName, "); ok {") + g.P("return x.", sf.goName) + g.P("}") + g.P("return ", sf.getterDef) + g.P("}") + g.P() + } +} + +// setter prints the setter method of the field. +func (f *oneofField) setter(g *Generator, mc *msgCtx) { + // No setters for oneof yet +} + +// topLevelField interface implemented by all types of fields on the top level (not oneofSubField). +type topLevelField interface { + decl(g *Generator, mc *msgCtx) // print declaration within the struct + getter(g *Generator, mc *msgCtx) // print getter + setter(g *Generator, mc *msgCtx) // print setter if applicable +} + +// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField). +type defField interface { + getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5" + getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor" + getGoType() string // go type of the field as a string, e.g. "*int32" + getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration" + getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 +} + +// generateDefaultConstants adds constants for default values if needed, which is only if the default value is. +// explicit in the proto. +func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) { + // Collect fields that can have defaults + dFields := []defField{} + for _, pf := range topLevelFields { + if f, ok := pf.(*oneofField); ok { + for _, osf := range f.subFields { + dFields = append(dFields, osf) + } + continue + } + dFields = append(dFields, pf.(defField)) + } + for _, df := range dFields { + def := df.getProtoDef() + if def == "" { + continue + } + fieldname := g.defaultConstantName(mc.goName, df.getProtoName()) + typename := df.getGoType() + if typename[0] == '*' { + typename = typename[1:] + } + kind := "const " + switch { + case typename == "bool": + case typename == "string": + def = strconv.Quote(def) + case typename == "[]byte": + def = "[]byte(" + strconv.Quote(unescape(def)) + ")" + kind = "var " + case def == "inf", def == "-inf", def == "nan": + // These names are known to, and defined by, the protocol language. + switch def { + case "inf": + def = "math.Inf(1)" + case "-inf": + def = "math.Inf(-1)" + case "nan": + def = "math.NaN()" + } + if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT { + def = "float32(" + def + ")" + } + kind = "var " + case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM: + // Must be an enum. Need to construct the prefixed name. + obj := g.ObjectNamed(df.getProtoTypeName()) + var enum *EnumDescriptor + if id, ok := obj.(*ImportedDescriptor); ok { + // The enum type has been publicly imported. + enum, _ = id.o.(*EnumDescriptor) + } else { + enum, _ = obj.(*EnumDescriptor) + } + if enum == nil { + log.Printf("don't know how to generate constant for %s", fieldname) + continue + } + def = g.DefaultPackageName(obj) + enum.prefix() + def + } + g.P(kind, fieldname, " ", typename, " = ", def) + g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""}) + } + g.P() +} + +// generateInternalStructFields just adds the XXX_ fields to the message struct. +func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) { + g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals + if len(mc.message.ExtensionRange) > 0 { + messageset := "" + if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { + messageset = "protobuf_messageset:\"1\" " + } + g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`") + } + g.P("XXX_unrecognized\t[]byte `json:\"-\"`") + g.P("XXX_sizecache\tint32 `json:\"-\"`") + +} + +// generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer. +func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) { + ofields := []*oneofField{} + for _, f := range topLevelFields { + if o, ok := f.(*oneofField); ok { + ofields = append(ofields, o) + } + } + if len(ofields) == 0 { + return + } + enc := "_" + mc.goName + "_OneofMarshaler" + dec := "_" + mc.goName + "_OneofUnmarshaler" + size := "_" + mc.goName + "_OneofSizer" + encSig := "(msg " + g.Pkg["proto"] + ".Message, b *" + g.Pkg["proto"] + ".Buffer) error" + decSig := "(msg " + g.Pkg["proto"] + ".Message, tag, wire int, b *" + g.Pkg["proto"] + ".Buffer) (bool, error)" + sizeSig := "(msg " + g.Pkg["proto"] + ".Message) (n int)" + + // OneofFuncs + g.P("// XXX_OneofFuncs is for the internal use of the proto package.") + g.P("func (*", mc.goName, ") XXX_OneofFuncs() (func", encSig, ", func", decSig, ", func", sizeSig, ", []interface{}) {") + g.P("return ", enc, ", ", dec, ", ", size, ", []interface{}{") + for _, of := range ofields { + for _, sf := range of.subFields { + sf.typedNil(g) + } + } + g.P("}") + g.P("}") + g.P() + + // marshaler + g.P("func ", enc, encSig, " {") + g.P("m := msg.(*", mc.goName, ")") + for _, of := range ofields { + g.P("// ", of.getProtoName()) + g.P("switch x := m.", of.goName, ".(type) {") + for _, sf := range of.subFields { + // also fills in field.wire + sf.marshalCase(g) + } + g.P("case nil:") + g.P("default:") + g.P(" return ", g.Pkg["fmt"], `.Errorf("`, mc.goName, ".", of.goName, ` has unexpected type %T", x)`) + g.P("}") + } + g.P("return nil") + g.P("}") + g.P() + + // unmarshaler + g.P("func ", dec, decSig, " {") + g.P("m := msg.(*", mc.goName, ")") + g.P("switch tag {") + for _, of := range ofields { + for _, sf := range of.subFields { + sf.unmarshalCase(g, of.getProtoName(), of.goName) + } + } + g.P("default:") + g.P("return false, nil") + g.P("}") + g.P("}") + g.P() + + // sizer + g.P("func ", size, sizeSig, " {") + g.P("m := msg.(*", mc.goName, ")") + for _, of := range ofields { + g.P("// ", of.getProtoName()) + g.P("switch x := m.", of.goName, ".(type) {") + for _, sf := range of.subFields { + // also fills in field.wire + sf.sizerCase(g) + } + g.P("case nil:") + g.P("default:") + g.P("panic(", g.Pkg["fmt"], ".Sprintf(\"proto: unexpected type %T in oneof\", x))") + g.P("}") + } + g.P("return n") + g.P("}") + g.P() +} + +// generateMessageStruct adds the actual struct with it's members (but not methods) to the output. +func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) { + comments := g.PrintComments(mc.message.path) + + // Guarantee deprecation comments appear after user-provided comments. + if mc.message.GetOptions().GetDeprecated() { + if comments { + // Convention: Separate deprecation comments from original + // comments with an empty line. + g.P("//") + } + g.P(deprecationComment) + } + + g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {") + for _, pf := range topLevelFields { + pf.decl(g, mc) + } + g.generateInternalStructFields(mc, topLevelFields) + g.P("}") +} + +// generateGetters adds getters for all fields, including oneofs and weak fields when applicable. +func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) { + for _, pf := range topLevelFields { + pf.getter(g, mc) + } +} + +// generateSetters add setters for all fields, including oneofs and weak fields when applicable. +func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) { + for _, pf := range topLevelFields { + pf.setter(g, mc) + } +} + +// generateCommonMethods adds methods to the message that are not on a per field basis. +func (g *Generator) generateCommonMethods(mc *msgCtx) { + // Reset, String and ProtoMessage methods. + g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }") + g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }") + g.P("func (*", mc.goName, ") ProtoMessage() {}") + var indexes []string + for m := mc.message; m != nil; m = m.parent { + indexes = append([]string{strconv.Itoa(m.index)}, indexes...) + } + g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {") + g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") + g.P("}") + // TODO: Revisit the decision to use a XXX_WellKnownType method + // if we change proto.MessageName to work with multiple equivalents. + if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] { + g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`) + } + + // Extension support methods + if len(mc.message.ExtensionRange) > 0 { + // message_set_wire_format only makes sense when extensions are defined. + if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { + g.P() + g.P("func (m *", mc.goName, ") MarshalJSON() ([]byte, error) {") + g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(&m.XXX_InternalExtensions)") + g.P("}") + g.P("func (m *", mc.goName, ") UnmarshalJSON(buf []byte) error {") + g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions)") + g.P("}") + } + + g.P() + g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{") + for _, r := range mc.message.ExtensionRange { + end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends + g.P("{Start: ", r.Start, ", End: ", end, "},") + } + g.P("}") + g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {") + g.P("return extRange_", mc.goName) + g.P("}") + } + + // TODO: It does not scale to keep adding another method for every + // operation on protos that we want to switch over to using the + // table-driven approach. Instead, we should only add a single method + // that allows getting access to the *InternalMessageInfo struct and then + // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that. + + // Wrapper for table-driven marshaling and unmarshaling. + g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {") + g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)") + g.P("}") + + g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {") + g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") + g.P("}") + + g.P("func (dst *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {") + g.P("xxx_messageInfo_", mc.goName, ".Merge(dst, src)") + g.P("}") + + g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message + g.P("return xxx_messageInfo_", mc.goName, ".Size(m)") + g.P("}") + + g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {") + g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)") + g.P("}") + + g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo") + g.P() +} + +// Generate the type, methods and default constant definitions for this Descriptor. func (g *Generator) generateMessage(message *Descriptor) { + topLevelFields := []topLevelField{} + oFields := make(map[int32]*oneofField) // The full type name typeName := message.TypeName() // The full type name, CamelCased. - ccTypeName := CamelCaseSlice(typeName) + goTypeName := CamelCaseSlice(typeName) usedNames := make(map[string]bool) for _, n := range methodNames { usedNames[n] = true } - fieldNames := make(map[*descriptor.FieldDescriptorProto]string) - fieldGetterNames := make(map[*descriptor.FieldDescriptorProto]string) - fieldTypes := make(map[*descriptor.FieldDescriptorProto]string) - mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) - - oneofFieldName := make(map[int32]string) // indexed by oneof_index field of FieldDescriptorProto - oneofDisc := make(map[int32]string) // name of discriminator method - oneofTypeName := make(map[*descriptor.FieldDescriptorProto]string) // without star - oneofInsertPoints := make(map[int32]int) // oneof_index => offset of g.Buffer - - g.PrintComments(message.path) - g.P("type ", ccTypeName, " struct {") - g.In() // allocNames finds a conflict-free variation of the given strings, // consistently mutating their suffixes. @@ -1771,6 +2483,9 @@ func (g *Generator) generateMessage(message *Descriptor) { } } + mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later + + // Build a structure more suitable for generating the text in one pass for i, field := range message.Field { // Allocate the getter and the field at the same time so name // collisions create field/method consistent names. @@ -1784,30 +2499,39 @@ func (g *Generator) generateMessage(message *Descriptor) { jsonName := *field.Name tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty") - fieldNames[field] = fieldName - fieldGetterNames[field] = fieldGetterName - oneof := field.OneofIndex != nil - if oneof && oneofFieldName[*field.OneofIndex] == "" { + if oneof && oFields[*field.OneofIndex] == nil { odp := message.OneofDecl[int(*field.OneofIndex)] - fname := allocNames(CamelCase(odp.GetName()))[0] + base := CamelCase(odp.GetName()) + names := allocNames(base, "Get"+base) + fname, gname := names[0], names[1] // This is the first field of a oneof we haven't seen before. // Generate the union field. - com := g.PrintComments(fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex)) - if com { - g.P("//") + oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex) + c, ok := g.makeComments(oneofFullPath) + if ok { + c += "\n//\n" } - g.P("// Types that are valid to be assigned to ", fname, ":") + c += "// Types that are valid to be assigned to " + fname + ":\n" // Generate the rest of this comment later, // when we've computed any disambiguation. - oneofInsertPoints[*field.OneofIndex] = g.Buffer.Len() - dname := "is" + ccTypeName + "_" + fname - oneofFieldName[*field.OneofIndex] = fname - oneofDisc[*field.OneofIndex] = dname + dname := "is" + goTypeName + "_" + fname tag := `protobuf_oneof:"` + odp.GetName() + `"` - g.P(fname, " ", dname, " `", tag, "`") + of := oneofField{ + fieldCommon: fieldCommon{ + goName: fname, + getterName: gname, + goType: dname, + tags: tag, + protoName: odp.GetName(), + fullPath: oneofFullPath, + }, + comment: c, + } + topLevelFields = append(topLevelFields, &of) + oFields[*field.OneofIndex] = &of } if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { @@ -1840,10 +2564,9 @@ func (g *Generator) generateMessage(message *Descriptor) { } } - fieldTypes[field] = typename - + dvalue := g.getterDefault(field, goTypeName) if oneof { - tname := ccTypeName + "_" + fieldName + tname := goTypeName + "_" + fieldName // It is possible for this to collide with a message or enum // nested in this message. Check for collisions. for { @@ -1867,635 +2590,100 @@ func (g *Generator) generateMessage(message *Descriptor) { break } - oneofTypeName[field] = tname + oneofField := oFields[*field.OneofIndex] + tag := "protobuf:" + g.goTag(message, field, wiretype) + sf := oneofSubField{ + fieldCommon: fieldCommon{ + goName: fieldName, + getterName: fieldGetterName, + goType: typename, + tags: tag, + protoName: field.GetName(), + fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i), + }, + protoTypeName: field.GetTypeName(), + fieldNumber: int(*field.Number), + protoType: *field.Type, + getterDef: dvalue, + protoDef: field.GetDefaultValue(), + oneofTypeName: tname, + } + oneofField.subFields = append(oneofField.subFields, &sf) + g.RecordTypeUse(field.GetTypeName()) continue } - g.PrintComments(fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i)) - g.P(fieldName, "\t", typename, "\t`", tag, "`") + fieldDeprecated := "" + if field.GetOptions().GetDeprecated() { + fieldDeprecated = deprecationComment + } + + fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i) + c, ok := g.makeComments(fieldFullPath) + if ok { + c += "\n" + } + rf := simpleField{ + fieldCommon: fieldCommon{ + goName: fieldName, + getterName: fieldGetterName, + goType: typename, + tags: tag, + protoName: field.GetName(), + fullPath: fieldFullPath, + }, + protoTypeName: field.GetTypeName(), + protoType: *field.Type, + deprecated: fieldDeprecated, + getterDef: dvalue, + protoDef: field.GetDefaultValue(), + comment: c, + } + var pf topLevelField = &rf + + topLevelFields = append(topLevelFields, pf) g.RecordTypeUse(field.GetTypeName()) } - if len(message.ExtensionRange) > 0 { - g.P(g.Pkg["proto"], ".XXX_InternalExtensions `json:\"-\"`") - } - if !message.proto3() { - g.P("XXX_unrecognized\t[]byte `json:\"-\"`") - } - g.Out() - g.P("}") - // Update g.Buffer to list valid oneof types. - // We do this down here, after we've disambiguated the oneof type names. - // We go in reverse order of insertion point to avoid invalidating offsets. - for oi := int32(len(message.OneofDecl)); oi >= 0; oi-- { - ip := oneofInsertPoints[oi] - all := g.Buffer.Bytes() - rem := all[ip:] - g.Buffer = bytes.NewBuffer(all[:ip:ip]) // set cap so we don't scribble on rem - for _, field := range message.Field { - if field.OneofIndex == nil || *field.OneofIndex != oi { - continue - } - g.P("//\t*", oneofTypeName[field]) - } - g.Buffer.Write(rem) + mc := &msgCtx{ + goName: goTypeName, + message: message, } - // Reset, String and ProtoMessage methods. - g.P("func (m *", ccTypeName, ") Reset() { *m = ", ccTypeName, "{} }") - g.P("func (m *", ccTypeName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }") - g.P("func (*", ccTypeName, ") ProtoMessage() {}") - var indexes []string - for m := message; m != nil; m = m.parent { - indexes = append([]string{strconv.Itoa(m.index)}, indexes...) - } - g.P("func (*", ccTypeName, ") Descriptor() ([]byte, []int) { return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "} }") - // TODO: Revisit the decision to use a XXX_WellKnownType method - // if we change proto.MessageName to work with multiple equivalents. - if message.file.GetPackage() == "google.protobuf" && wellKnownTypes[message.GetName()] { - g.P("func (*", ccTypeName, `) XXX_WellKnownType() string { return "`, message.GetName(), `" }`) - } - - // Extension support methods - var hasExtensions, isMessageSet bool - if len(message.ExtensionRange) > 0 { - hasExtensions = true - // message_set_wire_format only makes sense when extensions are defined. - if opts := message.Options; opts != nil && opts.GetMessageSetWireFormat() { - isMessageSet = true - g.P() - g.P("func (m *", ccTypeName, ") Marshal() ([]byte, error) {") - g.In() - g.P("return ", g.Pkg["proto"], ".MarshalMessageSet(&m.XXX_InternalExtensions)") - g.Out() - g.P("}") - g.P("func (m *", ccTypeName, ") Unmarshal(buf []byte) error {") - g.In() - g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSet(buf, &m.XXX_InternalExtensions)") - g.Out() - g.P("}") - g.P("func (m *", ccTypeName, ") MarshalJSON() ([]byte, error) {") - g.In() - g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(&m.XXX_InternalExtensions)") - g.Out() - g.P("}") - g.P("func (m *", ccTypeName, ") UnmarshalJSON(buf []byte) error {") - g.In() - g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions)") - g.Out() - g.P("}") - g.P("// ensure ", ccTypeName, " satisfies proto.Marshaler and proto.Unmarshaler") - g.P("var _ ", g.Pkg["proto"], ".Marshaler = (*", ccTypeName, ")(nil)") - g.P("var _ ", g.Pkg["proto"], ".Unmarshaler = (*", ccTypeName, ")(nil)") - } - - g.P() - g.P("var extRange_", ccTypeName, " = []", g.Pkg["proto"], ".ExtensionRange{") - g.In() - for _, r := range message.ExtensionRange { - end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends - g.P("{", r.Start, ", ", end, "},") - } - g.Out() - g.P("}") - g.P("func (*", ccTypeName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {") - g.In() - g.P("return extRange_", ccTypeName) - g.Out() - g.P("}") - } - - // Default constants - defNames := make(map[*descriptor.FieldDescriptorProto]string) - for _, field := range message.Field { - def := field.GetDefaultValue() - if def == "" { - continue - } - fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name) - defNames[field] = fieldname - typename, _ := g.GoType(message, field) - if typename[0] == '*' { - typename = typename[1:] - } - kind := "const " - switch { - case typename == "bool": - case typename == "string": - def = strconv.Quote(def) - case typename == "[]byte": - def = "[]byte(" + strconv.Quote(unescape(def)) + ")" - kind = "var " - case def == "inf", def == "-inf", def == "nan": - // These names are known to, and defined by, the protocol language. - switch def { - case "inf": - def = "math.Inf(1)" - case "-inf": - def = "math.Inf(-1)" - case "nan": - def = "math.NaN()" - } - if *field.Type == descriptor.FieldDescriptorProto_TYPE_FLOAT { - def = "float32(" + def + ")" - } - kind = "var " - case *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM: - // Must be an enum. Need to construct the prefixed name. - obj := g.ObjectNamed(field.GetTypeName()) - var enum *EnumDescriptor - if id, ok := obj.(*ImportedDescriptor); ok { - // The enum type has been publicly imported. - enum, _ = id.o.(*EnumDescriptor) - } else { - enum, _ = obj.(*EnumDescriptor) - } - if enum == nil { - log.Printf("don't know how to generate constant for %s", fieldname) - continue - } - def = g.DefaultPackageName(obj) + enum.prefix() + def - } - g.P(kind, fieldname, " ", typename, " = ", def) - g.file.addExport(message, constOrVarSymbol{fieldname, kind, ""}) - } + g.generateMessageStruct(mc, topLevelFields) g.P() - - // Oneof per-field types, discriminants and getters. - // - // Generate unexported named types for the discriminant interfaces. - // We shouldn't have to do this, but there was (~19 Aug 2015) a compiler/linker bug - // that was triggered by using anonymous interfaces here. - // TODO: Revisit this and consider reverting back to anonymous interfaces. - for oi := range message.OneofDecl { - dname := oneofDisc[int32(oi)] - g.P("type ", dname, " interface { ", dname, "() }") - } + g.generateCommonMethods(mc) g.P() - for _, field := range message.Field { - if field.OneofIndex == nil { - continue - } - _, wiretype := g.GoType(message, field) - tag := "protobuf:" + g.goTag(message, field, wiretype) - g.P("type ", oneofTypeName[field], " struct{ ", fieldNames[field], " ", fieldTypes[field], " `", tag, "` }") - g.RecordTypeUse(field.GetTypeName()) - } + g.generateDefaultConstants(mc, topLevelFields) g.P() - for _, field := range message.Field { - if field.OneofIndex == nil { - continue - } - g.P("func (*", oneofTypeName[field], ") ", oneofDisc[*field.OneofIndex], "() {}") - } + g.generateGetters(mc, topLevelFields) g.P() - for oi := range message.OneofDecl { - fname := oneofFieldName[int32(oi)] - g.P("func (m *", ccTypeName, ") Get", fname, "() ", oneofDisc[int32(oi)], " {") - g.P("if m != nil { return m.", fname, " }") - g.P("return nil") - g.P("}") - } + g.generateSetters(mc, topLevelFields) + g.P() + g.generateOneofFuncs(mc, topLevelFields) g.P() - - // Field getters - var getters []getterSymbol - for _, field := range message.Field { - oneof := field.OneofIndex != nil - - fname := fieldNames[field] - typename, _ := g.GoType(message, field) - if t, ok := mapFieldTypes[field]; ok { - typename = t - } - mname := fieldGetterNames[field] - star := "" - if needsStar(*field.Type) && typename[0] == '*' { - typename = typename[1:] - star = "*" - } - - // Only export getter symbols for basic types, - // and for messages and enums in the same package. - // Groups are not exported. - // Foreign types can't be hoisted through a public import because - // the importer may not already be importing the defining .proto. - // As an example, imagine we have an import tree like this: - // A.proto -> B.proto -> C.proto - // If A publicly imports B, we need to generate the getters from B in A's output, - // but if one such getter returns something from C then we cannot do that - // because A is not importing C already. - var getter, genType bool - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_GROUP: - getter = false - case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_ENUM: - // Only export getter if its return type is in this package. - getter = g.ObjectNamed(field.GetTypeName()).PackageName() == message.PackageName() - genType = true - default: - getter = true - } - if getter { - getters = append(getters, getterSymbol{ - name: mname, - typ: typename, - typeName: field.GetTypeName(), - genType: genType, - }) - } - - g.P("func (m *", ccTypeName, ") "+mname+"() "+typename+" {") - g.In() - def, hasDef := defNames[field] - typeDefaultIsNil := false // whether this field type's default value is a literal nil unless specified - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_BYTES: - typeDefaultIsNil = !hasDef - case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE: - typeDefaultIsNil = true - } - if isRepeated(field) { - typeDefaultIsNil = true - } - if typeDefaultIsNil && !oneof { - // A bytes field with no explicit default needs less generated code, - // as does a message or group field, or a repeated field. - g.P("if m != nil {") - g.In() - g.P("return m." + fname) - g.Out() - g.P("}") - g.P("return nil") - g.Out() - g.P("}") - g.P() - continue - } - if !oneof { - if message.proto3() { - g.P("if m != nil {") - } else { - g.P("if m != nil && m." + fname + " != nil {") - } - g.In() - g.P("return " + star + "m." + fname) - g.Out() - g.P("}") - } else { - uname := oneofFieldName[*field.OneofIndex] - tname := oneofTypeName[field] - g.P("if x, ok := m.Get", uname, "().(*", tname, "); ok {") - g.P("return x.", fname) - g.P("}") - } - if hasDef { - if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES { - g.P("return " + def) - } else { - // The default is a []byte var. - // Make a copy when returning it to be safe. - g.P("return append([]byte(nil), ", def, "...)") - } - } else { - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_BOOL: - g.P("return false") - case descriptor.FieldDescriptorProto_TYPE_STRING: - g.P(`return ""`) - case descriptor.FieldDescriptorProto_TYPE_GROUP, - descriptor.FieldDescriptorProto_TYPE_MESSAGE, - descriptor.FieldDescriptorProto_TYPE_BYTES: - // This is only possible for oneof fields. - g.P("return nil") - case descriptor.FieldDescriptorProto_TYPE_ENUM: - // The default default for an enum is the first value in the enum, - // not zero. - obj := g.ObjectNamed(field.GetTypeName()) - var enum *EnumDescriptor - if id, ok := obj.(*ImportedDescriptor); ok { - // The enum type has been publicly imported. - enum, _ = id.o.(*EnumDescriptor) - } else { - enum, _ = obj.(*EnumDescriptor) - } - if enum == nil { - log.Printf("don't know how to generate getter for %s", field.GetName()) - continue - } - if len(enum.Value) == 0 { - g.P("return 0 // empty enum") - } else { - first := enum.Value[0].GetName() - g.P("return ", g.DefaultPackageName(obj)+enum.prefix()+first) - } - default: - g.P("return 0") - } - } - g.Out() - g.P("}") - g.P() - } if !message.group { + + var oneofTypes []string + for _, f := range topLevelFields { + if of, ok := f.(*oneofField); ok { + for _, osf := range of.subFields { + oneofTypes = append(oneofTypes, osf.oneofTypeName) + } + } + } + + opts := message.Options ms := &messageSymbol{ - sym: ccTypeName, - hasExtensions: hasExtensions, - isMessageSet: isMessageSet, - hasOneof: len(message.OneofDecl) > 0, - getters: getters, + sym: goTypeName, + hasExtensions: len(message.ExtensionRange) > 0, + isMessageSet: opts != nil && opts.GetMessageSetWireFormat(), + oneofTypes: oneofTypes, } g.file.addExport(message, ms) } - // Oneof functions - if len(message.OneofDecl) > 0 { - fieldWire := make(map[*descriptor.FieldDescriptorProto]string) - - // method - enc := "_" + ccTypeName + "_OneofMarshaler" - dec := "_" + ccTypeName + "_OneofUnmarshaler" - size := "_" + ccTypeName + "_OneofSizer" - encSig := "(msg " + g.Pkg["proto"] + ".Message, b *" + g.Pkg["proto"] + ".Buffer) error" - decSig := "(msg " + g.Pkg["proto"] + ".Message, tag, wire int, b *" + g.Pkg["proto"] + ".Buffer) (bool, error)" - sizeSig := "(msg " + g.Pkg["proto"] + ".Message) (n int)" - - g.P("// XXX_OneofFuncs is for the internal use of the proto package.") - g.P("func (*", ccTypeName, ") XXX_OneofFuncs() (func", encSig, ", func", decSig, ", func", sizeSig, ", []interface{}) {") - g.P("return ", enc, ", ", dec, ", ", size, ", []interface{}{") - for _, field := range message.Field { - if field.OneofIndex == nil { - continue - } - g.P("(*", oneofTypeName[field], ")(nil),") - } - g.P("}") - g.P("}") - g.P() - - // marshaler - g.P("func ", enc, encSig, " {") - g.P("m := msg.(*", ccTypeName, ")") - for oi, odp := range message.OneofDecl { - g.P("// ", odp.GetName()) - fname := oneofFieldName[int32(oi)] - g.P("switch x := m.", fname, ".(type) {") - for _, field := range message.Field { - if field.OneofIndex == nil || int(*field.OneofIndex) != oi { - continue - } - g.P("case *", oneofTypeName[field], ":") - var wire, pre, post string - val := "x." + fieldNames[field] // overridden for TYPE_BOOL - canFail := false // only TYPE_MESSAGE and TYPE_GROUP can fail - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_DOUBLE: - wire = "WireFixed64" - pre = "b.EncodeFixed64(" + g.Pkg["math"] + ".Float64bits(" - post = "))" - case descriptor.FieldDescriptorProto_TYPE_FLOAT: - wire = "WireFixed32" - pre = "b.EncodeFixed32(uint64(" + g.Pkg["math"] + ".Float32bits(" - post = ")))" - case descriptor.FieldDescriptorProto_TYPE_INT64, - descriptor.FieldDescriptorProto_TYPE_UINT64: - wire = "WireVarint" - pre, post = "b.EncodeVarint(uint64(", "))" - case descriptor.FieldDescriptorProto_TYPE_INT32, - descriptor.FieldDescriptorProto_TYPE_UINT32, - descriptor.FieldDescriptorProto_TYPE_ENUM: - wire = "WireVarint" - pre, post = "b.EncodeVarint(uint64(", "))" - case descriptor.FieldDescriptorProto_TYPE_FIXED64, - descriptor.FieldDescriptorProto_TYPE_SFIXED64: - wire = "WireFixed64" - pre, post = "b.EncodeFixed64(uint64(", "))" - case descriptor.FieldDescriptorProto_TYPE_FIXED32, - descriptor.FieldDescriptorProto_TYPE_SFIXED32: - wire = "WireFixed32" - pre, post = "b.EncodeFixed32(uint64(", "))" - case descriptor.FieldDescriptorProto_TYPE_BOOL: - // bool needs special handling. - g.P("t := uint64(0)") - g.P("if ", val, " { t = 1 }") - val = "t" - wire = "WireVarint" - pre, post = "b.EncodeVarint(", ")" - case descriptor.FieldDescriptorProto_TYPE_STRING: - wire = "WireBytes" - pre, post = "b.EncodeStringBytes(", ")" - case descriptor.FieldDescriptorProto_TYPE_GROUP: - wire = "WireStartGroup" - pre, post = "b.Marshal(", ")" - canFail = true - case descriptor.FieldDescriptorProto_TYPE_MESSAGE: - wire = "WireBytes" - pre, post = "b.EncodeMessage(", ")" - canFail = true - case descriptor.FieldDescriptorProto_TYPE_BYTES: - wire = "WireBytes" - pre, post = "b.EncodeRawBytes(", ")" - case descriptor.FieldDescriptorProto_TYPE_SINT32: - wire = "WireVarint" - pre, post = "b.EncodeZigzag32(uint64(", "))" - case descriptor.FieldDescriptorProto_TYPE_SINT64: - wire = "WireVarint" - pre, post = "b.EncodeZigzag64(uint64(", "))" - default: - g.Fail("unhandled oneof field type ", field.Type.String()) - } - fieldWire[field] = wire - g.P("b.EncodeVarint(", field.Number, "<<3|", g.Pkg["proto"], ".", wire, ")") - if !canFail { - g.P(pre, val, post) - } else { - g.P("if err := ", pre, val, post, "; err != nil {") - g.P("return err") - g.P("}") - } - if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP { - g.P("b.EncodeVarint(", field.Number, "<<3|", g.Pkg["proto"], ".WireEndGroup)") - } - } - g.P("case nil:") - g.P("default: return ", g.Pkg["fmt"], `.Errorf("`, ccTypeName, ".", fname, ` has unexpected type %T", x)`) - g.P("}") - } - g.P("return nil") - g.P("}") - g.P() - - // unmarshaler - g.P("func ", dec, decSig, " {") - g.P("m := msg.(*", ccTypeName, ")") - g.P("switch tag {") - for _, field := range message.Field { - if field.OneofIndex == nil { - continue - } - odp := message.OneofDecl[int(*field.OneofIndex)] - g.P("case ", field.Number, ": // ", odp.GetName(), ".", *field.Name) - g.P("if wire != ", g.Pkg["proto"], ".", fieldWire[field], " {") - g.P("return true, ", g.Pkg["proto"], ".ErrInternalBadWireType") - g.P("}") - lhs := "x, err" // overridden for TYPE_MESSAGE and TYPE_GROUP - var dec, cast, cast2 string - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_DOUBLE: - dec, cast = "b.DecodeFixed64()", g.Pkg["math"]+".Float64frombits" - case descriptor.FieldDescriptorProto_TYPE_FLOAT: - dec, cast, cast2 = "b.DecodeFixed32()", "uint32", g.Pkg["math"]+".Float32frombits" - case descriptor.FieldDescriptorProto_TYPE_INT64: - dec, cast = "b.DecodeVarint()", "int64" - case descriptor.FieldDescriptorProto_TYPE_UINT64: - dec = "b.DecodeVarint()" - case descriptor.FieldDescriptorProto_TYPE_INT32: - dec, cast = "b.DecodeVarint()", "int32" - case descriptor.FieldDescriptorProto_TYPE_FIXED64: - dec = "b.DecodeFixed64()" - case descriptor.FieldDescriptorProto_TYPE_FIXED32: - dec, cast = "b.DecodeFixed32()", "uint32" - case descriptor.FieldDescriptorProto_TYPE_BOOL: - dec = "b.DecodeVarint()" - // handled specially below - case descriptor.FieldDescriptorProto_TYPE_STRING: - dec = "b.DecodeStringBytes()" - case descriptor.FieldDescriptorProto_TYPE_GROUP: - g.P("msg := new(", fieldTypes[field][1:], ")") // drop star - lhs = "err" - dec = "b.DecodeGroup(msg)" - // handled specially below - case descriptor.FieldDescriptorProto_TYPE_MESSAGE: - g.P("msg := new(", fieldTypes[field][1:], ")") // drop star - lhs = "err" - dec = "b.DecodeMessage(msg)" - // handled specially below - case descriptor.FieldDescriptorProto_TYPE_BYTES: - dec = "b.DecodeRawBytes(true)" - case descriptor.FieldDescriptorProto_TYPE_UINT32: - dec, cast = "b.DecodeVarint()", "uint32" - case descriptor.FieldDescriptorProto_TYPE_ENUM: - dec, cast = "b.DecodeVarint()", fieldTypes[field] - case descriptor.FieldDescriptorProto_TYPE_SFIXED32: - dec, cast = "b.DecodeFixed32()", "int32" - case descriptor.FieldDescriptorProto_TYPE_SFIXED64: - dec, cast = "b.DecodeFixed64()", "int64" - case descriptor.FieldDescriptorProto_TYPE_SINT32: - dec, cast = "b.DecodeZigzag32()", "int32" - case descriptor.FieldDescriptorProto_TYPE_SINT64: - dec, cast = "b.DecodeZigzag64()", "int64" - default: - g.Fail("unhandled oneof field type ", field.Type.String()) - } - g.P(lhs, " := ", dec) - val := "x" - if cast != "" { - val = cast + "(" + val + ")" - } - if cast2 != "" { - val = cast2 + "(" + val + ")" - } - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_BOOL: - val += " != 0" - case descriptor.FieldDescriptorProto_TYPE_GROUP, - descriptor.FieldDescriptorProto_TYPE_MESSAGE: - val = "msg" - } - g.P("m.", oneofFieldName[*field.OneofIndex], " = &", oneofTypeName[field], "{", val, "}") - g.P("return true, err") - } - g.P("default: return false, nil") - g.P("}") - g.P("}") - g.P() - - // sizer - g.P("func ", size, sizeSig, " {") - g.P("m := msg.(*", ccTypeName, ")") - for oi, odp := range message.OneofDecl { - g.P("// ", odp.GetName()) - fname := oneofFieldName[int32(oi)] - g.P("switch x := m.", fname, ".(type) {") - for _, field := range message.Field { - if field.OneofIndex == nil || int(*field.OneofIndex) != oi { - continue - } - g.P("case *", oneofTypeName[field], ":") - val := "x." + fieldNames[field] - var wire, varint, fixed string - switch *field.Type { - case descriptor.FieldDescriptorProto_TYPE_DOUBLE: - wire = "WireFixed64" - fixed = "8" - case descriptor.FieldDescriptorProto_TYPE_FLOAT: - wire = "WireFixed32" - fixed = "4" - case descriptor.FieldDescriptorProto_TYPE_INT64, - descriptor.FieldDescriptorProto_TYPE_UINT64, - descriptor.FieldDescriptorProto_TYPE_INT32, - descriptor.FieldDescriptorProto_TYPE_UINT32, - descriptor.FieldDescriptorProto_TYPE_ENUM: - wire = "WireVarint" - varint = val - case descriptor.FieldDescriptorProto_TYPE_FIXED64, - descriptor.FieldDescriptorProto_TYPE_SFIXED64: - wire = "WireFixed64" - fixed = "8" - case descriptor.FieldDescriptorProto_TYPE_FIXED32, - descriptor.FieldDescriptorProto_TYPE_SFIXED32: - wire = "WireFixed32" - fixed = "4" - case descriptor.FieldDescriptorProto_TYPE_BOOL: - wire = "WireVarint" - fixed = "1" - case descriptor.FieldDescriptorProto_TYPE_STRING: - wire = "WireBytes" - fixed = "len(" + val + ")" - varint = fixed - case descriptor.FieldDescriptorProto_TYPE_GROUP: - wire = "WireStartGroup" - fixed = g.Pkg["proto"] + ".Size(" + val + ")" - case descriptor.FieldDescriptorProto_TYPE_MESSAGE: - wire = "WireBytes" - g.P("s := ", g.Pkg["proto"], ".Size(", val, ")") - fixed = "s" - varint = fixed - case descriptor.FieldDescriptorProto_TYPE_BYTES: - wire = "WireBytes" - fixed = "len(" + val + ")" - varint = fixed - case descriptor.FieldDescriptorProto_TYPE_SINT32: - wire = "WireVarint" - varint = "(uint32(" + val + ") << 1) ^ uint32((int32(" + val + ") >> 31))" - case descriptor.FieldDescriptorProto_TYPE_SINT64: - wire = "WireVarint" - varint = "uint64(" + val + " << 1) ^ uint64((int64(" + val + ") >> 63))" - default: - g.Fail("unhandled oneof field type ", field.Type.String()) - } - g.P("n += ", g.Pkg["proto"], ".SizeVarint(", field.Number, "<<3|", g.Pkg["proto"], ".", wire, ")") - if varint != "" { - g.P("n += ", g.Pkg["proto"], ".SizeVarint(uint64(", varint, "))") - } - if fixed != "" { - g.P("n += ", fixed) - } - if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP { - g.P("n += ", g.Pkg["proto"], ".SizeVarint(", field.Number, "<<3|", g.Pkg["proto"], ".WireEndGroup)") - } - } - g.P("case nil:") - g.P("default:") - g.P("panic(", g.Pkg["fmt"], ".Sprintf(\"proto: unexpected type %T in oneof\", x))") - g.P("}") - } - g.P("return n") - g.P("}") - g.P() - } - for _, ext := range message.ext { g.generateExtension(ext) } @@ -2505,7 +2693,29 @@ func (g *Generator) generateMessage(message *Descriptor) { fullName = *g.file.Package + "." + fullName } - g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], ccTypeName, fullName) + g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName) + // Register types for native map types. + for _, k := range mapFieldKeys(mapFieldTypes) { + fullName := strings.TrimPrefix(*k.TypeName, ".") + g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName) + } + +} + +type byTypeName []*descriptor.FieldDescriptorProto + +func (a byTypeName) Len() int { return len(a) } +func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName } + +// mapFieldKeys returns the keys of m in a consistent order. +func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto { + keys := make([]*descriptor.FieldDescriptorProto, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Sort(byTypeName(keys)) + return keys } var escapeChars = [256]byte{ @@ -2594,10 +2804,15 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) { typeName := ext.TypeName() // Special case for proto2 message sets: If this extension is extending - // proto2_bridge.MessageSet, and its final name component is "message_set_extension", + // proto2.bridge.MessageSet, and its final name component is "message_set_extension", // then drop that last component. + // + // TODO: This should be implemented in the text formatter rather than the generator. + // In addition, the situation for when to apply this special case is implemented + // differently in other languages: + // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560 mset := false - if extendedType == "*proto2_bridge.MessageSet" && typeName[len(typeName)-1] == "message_set_extension" { + if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" { typeName = typeName[:len(typeName)-1] mset = true } @@ -2610,7 +2825,6 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) { } g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{") - g.In() g.P("ExtendedType: (", extendedType, ")(nil),") g.P("ExtensionType: (", fieldType, ")(nil),") g.P("Field: ", field.Number, ",") @@ -2618,7 +2832,6 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) { g.P("Tag: ", tag, ",") g.P(`Filename: "`, g.file.GetName(), `",`) - g.Out() g.P("}") g.P() @@ -2646,11 +2859,9 @@ func (g *Generator) generateInitFunction() { return } g.P("func init() {") - g.In() for _, l := range g.init { g.P(l) } - g.Out() g.P("}") g.init = nil } @@ -2676,7 +2887,6 @@ func (g *Generator) generateFileDescriptor(file *FileDescriptor) { g.P() g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }") g.P("var ", v, " = []byte{") - g.In() g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto") for len(b) > 0 { n := 16 @@ -2692,7 +2902,6 @@ func (g *Generator) generateFileDescriptor(file *FileDescriptor) { b = b[n:] } - g.Out() g.P("}") } @@ -2864,3 +3073,14 @@ const ( // tag numbers in EnumDescriptorProto enumValuePath = 2 // value ) + +var supportTypeAliases bool + +func init() { + for _, tag := range build.Default.ReleaseTags { + if tag == "go1.9" { + supportTypeAliases = true + return + } + } +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap.go b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap.go new file mode 100644 index 00000000..a9b61036 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap.go @@ -0,0 +1,117 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* +Package remap handles tracking the locations of Go tokens in a source text +across a rewrite by the Go formatter. +*/ +package remap + +import ( + "fmt" + "go/scanner" + "go/token" +) + +// A Location represents a span of byte offsets in the source text. +type Location struct { + Pos, End int // End is exclusive +} + +// A Map represents a mapping between token locations in an input source text +// and locations in the correspnding output text. +type Map map[Location]Location + +// Find reports whether the specified span is recorded by m, and if so returns +// the new location it was mapped to. If the input span was not found, the +// returned location is the same as the input. +func (m Map) Find(pos, end int) (Location, bool) { + key := Location{ + Pos: pos, + End: end, + } + if loc, ok := m[key]; ok { + return loc, true + } + return key, false +} + +func (m Map) add(opos, oend, npos, nend int) { + m[Location{Pos: opos, End: oend}] = Location{Pos: npos, End: nend} +} + +// Compute constructs a location mapping from input to output. An error is +// reported if any of the tokens of output cannot be mapped. +func Compute(input, output []byte) (Map, error) { + itok := tokenize(input) + otok := tokenize(output) + if len(itok) != len(otok) { + return nil, fmt.Errorf("wrong number of tokens, %d ≠ %d", len(itok), len(otok)) + } + m := make(Map) + for i, ti := range itok { + to := otok[i] + if ti.Token != to.Token { + return nil, fmt.Errorf("token %d type mismatch: %s ≠ %s", i+1, ti, to) + } + m.add(ti.pos, ti.end, to.pos, to.end) + } + return m, nil +} + +// tokinfo records the span and type of a source token. +type tokinfo struct { + pos, end int + token.Token +} + +func tokenize(src []byte) []tokinfo { + fs := token.NewFileSet() + var s scanner.Scanner + s.Init(fs.AddFile("src", fs.Base(), len(src)), src, nil, scanner.ScanComments) + var info []tokinfo + for { + pos, next, lit := s.Scan() + switch next { + case token.SEMICOLON: + continue + } + info = append(info, tokinfo{ + pos: int(pos - 1), + end: int(pos + token.Pos(len(lit)) - 1), + Token: next, + }) + if next == token.EOF { + break + } + } + return info +} diff --git a/vendor/github.com/golang/protobuf/proto/testdata/golden_test.go b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap_test.go similarity index 57% rename from vendor/github.com/golang/protobuf/proto/testdata/golden_test.go rename to vendor/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap_test.go index 7172d0e9..ccc7fca0 100644 --- a/vendor/github.com/golang/protobuf/proto/testdata/golden_test.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap_test.go @@ -1,6 +1,6 @@ // Go support for Protocol Buffers - Google's data interchange format // -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2017 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without @@ -29,58 +29,54 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Verify that the compiler output for test.proto is unchanged. - -package testdata +package remap import ( - "crypto/sha1" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" + "go/format" "testing" ) -// sum returns in string form (for easy comparison) the SHA-1 hash of the named file. -func sum(t *testing.T, name string) string { - data, err := ioutil.ReadFile(name) - if err != nil { - t.Fatal(err) +func TestErrors(t *testing.T) { + tests := []struct { + in, out string + }{ + {"", "x"}, + {"x", ""}, + {"var x int = 5\n", "var x = 5\n"}, + {"these are \"one\" thing", "those are 'another' thing"}, } - t.Logf("sum(%q): length is %d", name, len(data)) - hash := sha1.New() - _, err = hash.Write(data) - if err != nil { - t.Fatal(err) - } - return fmt.Sprintf("% x", hash.Sum(nil)) -} - -func run(t *testing.T, name string, args ...string) { - cmd := exec.Command(name, args...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - if err != nil { - t.Fatal(err) + for _, test := range tests { + m, err := Compute([]byte(test.in), []byte(test.out)) + if err != nil { + t.Logf("Got expected error: %v", err) + continue + } + t.Errorf("Compute(%q, %q): got %+v, wanted error", test.in, test.out, m) } } -func TestGolden(t *testing.T) { - // Compute the original checksum. - goldenSum := sum(t, "test.pb.go") - // Run the proto compiler. - run(t, "protoc", "--go_out="+os.TempDir(), "test.proto") - newFile := filepath.Join(os.TempDir(), "test.pb.go") - defer os.Remove(newFile) - // Compute the new checksum. - newSum := sum(t, newFile) - // Verify - if newSum != goldenSum { - run(t, "diff", "-u", "test.pb.go", newFile) - t.Fatal("Code generated by protoc-gen-go has changed; update test.pb.go") +func TestMatching(t *testing.T) { + // The input is a source text that will be rearranged by the formatter. + const input = `package foo +var s int +func main(){} +` + + output, err := format.Source([]byte(input)) + if err != nil { + t.Fatalf("Formatting failed: %v", err) + } + m, err := Compute([]byte(input), output) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // Verify that the mapped locations have the same text. + for key, val := range m { + want := input[key.Pos:key.End] + got := string(output[val.Pos:val.End]) + if got != want { + t.Errorf("Token at %d:%d: got %q, want %q", key.Pos, key.End, got, want) + } } } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/name_test.go b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/name_test.go index 76808f3b..571147cf 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/generator/name_test.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/generator/name_test.go @@ -59,9 +59,10 @@ func TestCamelCase(t *testing.T) { func TestGoPackageOption(t *testing.T) { tests := []struct { - in string - impPath, pkg string - ok bool + in string + impPath GoImportPath + pkg GoPackageName + ok bool }{ {"", "", "", false}, {"foo", "", "foo", true}, @@ -86,8 +87,8 @@ func TestGoPackageOption(t *testing.T) { func TestUnescape(t *testing.T) { tests := []struct { - in string - out string + in string + out string }{ // successful cases, including all kinds of escapes {"", ""}, diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/golden_test.go b/vendor/github.com/golang/protobuf/protoc-gen-go/golden_test.go new file mode 100644 index 00000000..2630de68 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/golden_test.go @@ -0,0 +1,422 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "go/build" + "go/parser" + "go/token" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strings" + "testing" +) + +// Set --regenerate to regenerate the golden files. +var regenerate = flag.Bool("regenerate", false, "regenerate golden files") + +// When the environment variable RUN_AS_PROTOC_GEN_GO is set, we skip running +// tests and instead act as protoc-gen-go. This allows the test binary to +// pass itself to protoc. +func init() { + if os.Getenv("RUN_AS_PROTOC_GEN_GO") != "" { + main() + os.Exit(0) + } +} + +func TestGolden(t *testing.T) { + workdir, err := ioutil.TempDir("", "proto-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(workdir) + + // Find all the proto files we need to compile. We assume that each directory + // contains the files for a single package. + supportTypeAliases := hasReleaseTag("go1.9") + packages := map[string][]string{} + err = filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error { + if filepath.Base(path) == "import_public" && !supportTypeAliases { + // Public imports require type alias support. + return filepath.SkipDir + } + if !strings.HasSuffix(path, ".proto") { + return nil + } + dir := filepath.Dir(path) + packages[dir] = append(packages[dir], path) + return nil + }) + if err != nil { + t.Fatal(err) + } + + // Compile each package, using this binary as protoc-gen-go. + for _, sources := range packages { + args := []string{"-Itestdata", "--go_out=plugins=grpc,paths=source_relative:" + workdir} + args = append(args, sources...) + protoc(t, args) + } + + // Compare each generated file to the golden version. + filepath.Walk(workdir, func(genPath string, info os.FileInfo, _ error) error { + if info.IsDir() { + return nil + } + + // For each generated file, figure out the path to the corresponding + // golden file in the testdata directory. + relPath, err := filepath.Rel(workdir, genPath) + if err != nil { + t.Errorf("filepath.Rel(%q, %q): %v", workdir, genPath, err) + return nil + } + if filepath.SplitList(relPath)[0] == ".." { + t.Errorf("generated file %q is not relative to %q", genPath, workdir) + } + goldenPath := filepath.Join("testdata", relPath) + + got, err := ioutil.ReadFile(genPath) + if err != nil { + t.Error(err) + return nil + } + if *regenerate { + // If --regenerate set, just rewrite the golden files. + err := ioutil.WriteFile(goldenPath, got, 0666) + if err != nil { + t.Error(err) + } + return nil + } + + want, err := ioutil.ReadFile(goldenPath) + if err != nil { + t.Error(err) + return nil + } + + want = fdescRE.ReplaceAll(want, nil) + got = fdescRE.ReplaceAll(got, nil) + if bytes.Equal(got, want) { + return nil + } + + cmd := exec.Command("diff", "-u", goldenPath, genPath) + out, _ := cmd.CombinedOutput() + t.Errorf("golden file differs: %v\n%v", relPath, string(out)) + return nil + }) +} + +var fdescRE = regexp.MustCompile(`(?ms)^var fileDescriptor.*}`) + +// Source files used by TestParameters. +const ( + aProto = ` +syntax = "proto3"; +package test.alpha; +option go_package = "package/alpha"; +import "beta/b.proto"; +message M { test.beta.M field = 1; }` + + bProto = ` +syntax = "proto3"; +package test.beta; +// no go_package option +message M {}` +) + +func TestParameters(t *testing.T) { + for _, test := range []struct { + parameters string + wantFiles map[string]bool + wantImportsA map[string]bool + wantPackageA string + wantPackageB string + }{{ + parameters: "", + wantFiles: map[string]bool{ + "package/alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + wantPackageA: "alpha", + wantPackageB: "test_beta", + wantImportsA: map[string]bool{ + "github.com/golang/protobuf/proto": true, + "beta": true, + }, + }, { + parameters: "import_prefix=prefix", + wantFiles: map[string]bool{ + "package/alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + wantPackageA: "alpha", + wantPackageB: "test_beta", + wantImportsA: map[string]bool{ + // This really doesn't seem like useful behavior. + "prefixgithub.com/golang/protobuf/proto": true, + "prefixbeta": true, + }, + }, { + // import_path only affects the 'package' line. + parameters: "import_path=import/path/of/pkg", + wantPackageA: "alpha", + wantPackageB: "pkg", + wantFiles: map[string]bool{ + "package/alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + }, { + parameters: "Mbeta/b.proto=package/gamma", + wantFiles: map[string]bool{ + "package/alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + wantPackageA: "alpha", + wantPackageB: "test_beta", + wantImportsA: map[string]bool{ + "github.com/golang/protobuf/proto": true, + // Rewritten by the M parameter. + "package/gamma": true, + }, + }, { + parameters: "import_prefix=prefix,Mbeta/b.proto=package/gamma", + wantFiles: map[string]bool{ + "package/alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + wantPackageA: "alpha", + wantPackageB: "test_beta", + wantImportsA: map[string]bool{ + // import_prefix applies after M. + "prefixpackage/gamma": true, + }, + }, { + parameters: "paths=source_relative", + wantFiles: map[string]bool{ + "alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + wantPackageA: "alpha", + wantPackageB: "test_beta", + }, { + parameters: "paths=source_relative,import_prefix=prefix", + wantFiles: map[string]bool{ + // import_prefix doesn't affect filenames. + "alpha/a.pb.go": true, + "beta/b.pb.go": true, + }, + wantPackageA: "alpha", + wantPackageB: "test_beta", + }} { + name := test.parameters + if name == "" { + name = "defaults" + } + // TODO: Switch to t.Run when we no longer support Go 1.6. + t.Logf("TEST: %v", name) + workdir, err := ioutil.TempDir("", "proto-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(workdir) + + for _, dir := range []string{"alpha", "beta", "out"} { + if err := os.MkdirAll(filepath.Join(workdir, dir), 0777); err != nil { + t.Fatal(err) + } + } + + if err := ioutil.WriteFile(filepath.Join(workdir, "alpha", "a.proto"), []byte(aProto), 0666); err != nil { + t.Fatal(err) + } + + if err := ioutil.WriteFile(filepath.Join(workdir, "beta", "b.proto"), []byte(bProto), 0666); err != nil { + t.Fatal(err) + } + + protoc(t, []string{ + "-I" + workdir, + "--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"), + filepath.Join(workdir, "alpha", "a.proto"), + }) + protoc(t, []string{ + "-I" + workdir, + "--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"), + filepath.Join(workdir, "beta", "b.proto"), + }) + + contents := make(map[string]string) + gotFiles := make(map[string]bool) + outdir := filepath.Join(workdir, "out") + filepath.Walk(outdir, func(p string, info os.FileInfo, _ error) error { + if info.IsDir() { + return nil + } + base := filepath.Base(p) + if base == "a.pb.go" || base == "b.pb.go" { + b, err := ioutil.ReadFile(p) + if err != nil { + t.Fatal(err) + } + contents[base] = string(b) + } + relPath, _ := filepath.Rel(outdir, p) + gotFiles[relPath] = true + return nil + }) + for got := range gotFiles { + if runtime.GOOS == "windows" { + got = filepath.ToSlash(got) + } + if !test.wantFiles[got] { + t.Errorf("unexpected output file: %v", got) + } + } + for want := range test.wantFiles { + if runtime.GOOS == "windows" { + want = filepath.FromSlash(want) + } + if !gotFiles[want] { + t.Errorf("missing output file: %v", want) + } + } + gotPackageA, gotImports, err := parseFile(contents["a.pb.go"]) + if err != nil { + t.Fatal(err) + } + gotPackageB, _, err := parseFile(contents["b.pb.go"]) + if err != nil { + t.Fatal(err) + } + if got, want := gotPackageA, test.wantPackageA; want != got { + t.Errorf("output file a.pb.go is package %q, want %q", got, want) + } + if got, want := gotPackageB, test.wantPackageB; want != got { + t.Errorf("output file b.pb.go is package %q, want %q", got, want) + } + missingImport := false + WantImport: + for want := range test.wantImportsA { + for _, imp := range gotImports { + if `"`+want+`"` == imp { + continue WantImport + } + } + t.Errorf("output file a.pb.go does not contain expected import %q", want) + missingImport = true + } + if missingImport { + t.Error("got imports:") + for _, imp := range gotImports { + t.Errorf(" %v", imp) + } + } + } +} + +func TestPackageComment(t *testing.T) { + workdir, err := ioutil.TempDir("", "proto-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(workdir) + + var packageRE = regexp.MustCompile(`(?m)^package .*`) + + for i, test := range []struct { + goPackageOption string + wantPackage string + }{{ + goPackageOption: ``, + wantPackage: `package proto_package`, + }, { + goPackageOption: `option go_package = "go_package";`, + wantPackage: `package go_package`, + }, { + goPackageOption: `option go_package = "import/path/of/go_package";`, + wantPackage: `package go_package // import "import/path/of/go_package"`, + }, { + goPackageOption: `option go_package = "import/path/of/something;go_package";`, + wantPackage: `package go_package // import "import/path/of/something"`, + }, { + goPackageOption: `option go_package = "import_path;go_package";`, + wantPackage: `package go_package // import "import_path"`, + }} { + srcName := filepath.Join(workdir, fmt.Sprintf("%d.proto", i)) + tgtName := filepath.Join(workdir, fmt.Sprintf("%d.pb.go", i)) + + buf := &bytes.Buffer{} + fmt.Fprintln(buf, `syntax = "proto3";`) + fmt.Fprintln(buf, `package proto_package;`) + fmt.Fprintln(buf, test.goPackageOption) + if err := ioutil.WriteFile(srcName, buf.Bytes(), 0666); err != nil { + t.Fatal(err) + } + + protoc(t, []string{"-I" + workdir, "--go_out=paths=source_relative:" + workdir, srcName}) + + out, err := ioutil.ReadFile(tgtName) + if err != nil { + t.Fatal(err) + } + + pkg := packageRE.Find(out) + if pkg == nil { + t.Errorf("generated .pb.go contains no package line\n\nsource:\n%v\n\noutput:\n%v", buf.String(), string(out)) + continue + } + + if got, want := string(pkg), test.wantPackage; got != want { + t.Errorf("unexpected package statement with go_package = %q\n got: %v\nwant: %v", test.goPackageOption, got, want) + } + } +} + +// parseFile returns a file's package name and a list of all packages it imports. +func parseFile(source string) (packageName string, imports []string, err error) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "", source, parser.ImportsOnly) + if err != nil { + return "", nil, err + } + for _, imp := range f.Imports { + imports = append(imports, imp.Path.Value) + } + return f.Name.Name, imports, nil +} + +func protoc(t *testing.T, args []string) { + cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0]) + cmd.Args = append(cmd.Args, args...) + // We set the RUN_AS_PROTOC_GEN_GO environment variable to indicate that + // the subprocess should act as a proto compiler rather than a test. + cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_GEN_GO=1") + out, err := cmd.CombinedOutput() + if len(out) > 0 || err != nil { + t.Log("RUNNING: ", strings.Join(cmd.Args, " ")) + } + if len(out) > 0 { + t.Log(string(out)) + } + if err != nil { + t.Fatalf("protoc: %v", err) + } +} + +func hasReleaseTag(want string) bool { + for _, tag := range build.Default.ReleaseTags { + if tag == want { + return true + } + } + return false +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/grpc/grpc.go b/vendor/github.com/golang/protobuf/protoc-gen-go/grpc/grpc.go index 2660e47a..faef1abb 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/grpc/grpc.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/grpc/grpc.go @@ -130,19 +130,23 @@ func (g *grpc) GenerateImports(file *generator.FileDescriptor) { return } g.P("import (") - g.P(contextPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, contextPkgPath))) - g.P(grpcPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, grpcPkgPath))) + g.P(contextPkg, " ", generator.GoImportPath(path.Join(string(g.gen.ImportPrefix), contextPkgPath))) + g.P(grpcPkg, " ", generator.GoImportPath(path.Join(string(g.gen.ImportPrefix), grpcPkgPath))) g.P(")") g.P() } // reservedClientName records whether a client name is reserved on the client side. var reservedClientName = map[string]bool{ -// TODO: do we need any in gRPC? + // TODO: do we need any in gRPC? } func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] } +// deprecationComment is the standard comment added to deprecated +// messages, fields, enums, and enum values. +var deprecationComment = "// Deprecated: Do not use." + // generateService generates all the code for the named service. func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) { path := fmt.Sprintf("6,%d", index) // 6 means service. @@ -153,12 +157,18 @@ func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.Servi fullServName = pkg + "." + fullServName } servName := generator.CamelCase(origServName) + deprecated := service.GetOptions().GetDeprecated() g.P() - g.P("// Client API for ", servName, " service") - g.P() + g.P(fmt.Sprintf(`// %sClient is the client API for %s service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.`, servName, servName)) // Client interface. + if deprecated { + g.P("//") + g.P(deprecationComment) + } g.P("type ", servName, "Client interface {") for i, method := range service.Method { g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service. @@ -174,6 +184,9 @@ func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.Servi g.P() // NewClient factory. + if deprecated { + g.P(deprecationComment) + } g.P("func New", servName, "Client (cc *", grpcPkg, ".ClientConn) ", servName, "Client {") g.P("return &", unexport(servName), "Client{cc}") g.P("}") @@ -196,11 +209,13 @@ func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.Servi g.generateClientMethod(servName, fullServName, serviceDescVar, method, descExpr) } - g.P("// Server API for ", servName, " service") - g.P() - // Server interface. serverType := servName + "Server" + g.P("// ", serverType, " is the server API for ", servName, " service.") + if deprecated { + g.P("//") + g.P(deprecationComment) + } g.P("type ", serverType, " interface {") for i, method := range service.Method { g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service. @@ -210,6 +225,9 @@ func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.Servi g.P() // Server registration. + if deprecated { + g.P(deprecationComment) + } g.P("func Register", servName, "Server(s *", grpcPkg, ".Server, srv ", serverType, ") {") g.P("s.RegisterService(&", serviceDescVar, `, srv)`) g.P("}") @@ -283,11 +301,14 @@ func (g *grpc) generateClientMethod(servName, fullServName, serviceDescVar strin inType := g.typeName(method.GetInputType()) outType := g.typeName(method.GetOutputType()) + if method.GetOptions().GetDeprecated() { + g.P(deprecationComment) + } g.P("func (c *", unexport(servName), "Client) ", g.generateClientSignature(servName, method), "{") if !method.GetServerStreaming() && !method.GetClientStreaming() { g.P("out := new(", outType, ")") // TODO: Pass descExpr to Invoke. - g.P("err := ", grpcPkg, `.Invoke(ctx, "`, sname, `", in, out, c.cc, opts...)`) + g.P(`err := c.cc.Invoke(ctx, "`, sname, `", in, out, opts...)`) g.P("if err != nil { return nil, err }") g.P("return out, nil") g.P("}") @@ -295,7 +316,7 @@ func (g *grpc) generateClientMethod(servName, fullServName, serviceDescVar strin return } streamType := unexport(servName) + methName + "Client" - g.P("stream, err := ", grpcPkg, ".NewClientStream(ctx, ", descExpr, `, c.cc, "`, sname, `", opts...)`) + g.P("stream, err := c.cc.NewStream(ctx, ", descExpr, `, "`, sname, `", opts...)`) g.P("if err != nil { return nil, err }") g.P("x := &", streamType, "{stream}") if !method.GetClientStreaming() { diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/Makefile deleted file mode 100644 index bc0463d5..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Not stored here, but plugin.proto is in https://github.com/google/protobuf/ -# at src/google/protobuf/compiler/plugin.proto -# Also we need to fix an import. -regenerate: - @echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION - cp $(HOME)/src/protobuf/include/google/protobuf/compiler/plugin.proto . - protoc --go_out=Mgoogle/protobuf/descriptor.proto=github.com/golang/protobuf/protoc-gen-go/descriptor:../../../../.. \ - -I$(HOME)/src/protobuf/include $(HOME)/src/protobuf/include/google/protobuf/compiler/plugin.proto - -restore: - cp plugin.pb.golden plugin.pb.go - -preserve: - cp plugin.pb.go plugin.pb.golden diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/plugin.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/plugin.pb.go index c608a248..61bfc10e 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/plugin.pb.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/plugin/plugin.pb.go @@ -37,14 +37,33 @@ type Version struct { Patch *int32 `protobuf:"varint,3,opt,name=patch" json:"patch,omitempty"` // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should // be empty for mainline stable releases. - Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` - XXX_unrecognized []byte `json:"-"` + Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Version) Reset() { *m = Version{} } func (m *Version) String() string { return proto.CompactTextString(m) } func (*Version) ProtoMessage() {} func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (m *Version) Unmarshal(b []byte) error { + return xxx_messageInfo_Version.Unmarshal(m, b) +} +func (m *Version) Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Version.Marshal(b, m, deterministic) +} +func (dst *Version) XXX_Merge(src proto.Message) { + xxx_messageInfo_Version.Merge(dst, src) +} +func (m *Version) XXX_Size() int { + return xxx_messageInfo_Version.Size(m) +} +func (m *Version) XXX_DiscardUnknown() { + xxx_messageInfo_Version.DiscardUnknown(m) +} + +var xxx_messageInfo_Version proto.InternalMessageInfo func (m *Version) GetMajor() int32 { if m != nil && m.Major != nil { @@ -98,14 +117,33 @@ type CodeGeneratorRequest struct { // fully qualified. ProtoFile []*google_protobuf.FileDescriptorProto `protobuf:"bytes,15,rep,name=proto_file,json=protoFile" json:"proto_file,omitempty"` // The version number of protocol compiler. - CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion" json:"compiler_version,omitempty"` - XXX_unrecognized []byte `json:"-"` + CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion" json:"compiler_version,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CodeGeneratorRequest) Reset() { *m = CodeGeneratorRequest{} } func (m *CodeGeneratorRequest) String() string { return proto.CompactTextString(m) } func (*CodeGeneratorRequest) ProtoMessage() {} func (*CodeGeneratorRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *CodeGeneratorRequest) Unmarshal(b []byte) error { + return xxx_messageInfo_CodeGeneratorRequest.Unmarshal(m, b) +} +func (m *CodeGeneratorRequest) Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CodeGeneratorRequest.Marshal(b, m, deterministic) +} +func (dst *CodeGeneratorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CodeGeneratorRequest.Merge(dst, src) +} +func (m *CodeGeneratorRequest) XXX_Size() int { + return xxx_messageInfo_CodeGeneratorRequest.Size(m) +} +func (m *CodeGeneratorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CodeGeneratorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CodeGeneratorRequest proto.InternalMessageInfo func (m *CodeGeneratorRequest) GetFileToGenerate() []string { if m != nil { @@ -145,15 +183,34 @@ type CodeGeneratorResponse struct { // problem in protoc itself -- such as the input CodeGeneratorRequest being // unparseable -- should be reported by writing a message to stderr and // exiting with a non-zero status code. - Error *string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` - File []*CodeGeneratorResponse_File `protobuf:"bytes,15,rep,name=file" json:"file,omitempty"` - XXX_unrecognized []byte `json:"-"` + Error *string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` + File []*CodeGeneratorResponse_File `protobuf:"bytes,15,rep,name=file" json:"file,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CodeGeneratorResponse) Reset() { *m = CodeGeneratorResponse{} } func (m *CodeGeneratorResponse) String() string { return proto.CompactTextString(m) } func (*CodeGeneratorResponse) ProtoMessage() {} func (*CodeGeneratorResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *CodeGeneratorResponse) Unmarshal(b []byte) error { + return xxx_messageInfo_CodeGeneratorResponse.Unmarshal(m, b) +} +func (m *CodeGeneratorResponse) Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CodeGeneratorResponse.Marshal(b, m, deterministic) +} +func (dst *CodeGeneratorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CodeGeneratorResponse.Merge(dst, src) +} +func (m *CodeGeneratorResponse) XXX_Size() int { + return xxx_messageInfo_CodeGeneratorResponse.Size(m) +} +func (m *CodeGeneratorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CodeGeneratorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CodeGeneratorResponse proto.InternalMessageInfo func (m *CodeGeneratorResponse) GetError() string { if m != nil && m.Error != nil { @@ -222,14 +279,33 @@ type CodeGeneratorResponse_File struct { // If |insertion_point| is present, |name| must also be present. InsertionPoint *string `protobuf:"bytes,2,opt,name=insertion_point,json=insertionPoint" json:"insertion_point,omitempty"` // The file contents. - Content *string `protobuf:"bytes,15,opt,name=content" json:"content,omitempty"` - XXX_unrecognized []byte `json:"-"` + Content *string `protobuf:"bytes,15,opt,name=content" json:"content,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CodeGeneratorResponse_File) Reset() { *m = CodeGeneratorResponse_File{} } func (m *CodeGeneratorResponse_File) String() string { return proto.CompactTextString(m) } func (*CodeGeneratorResponse_File) ProtoMessage() {} func (*CodeGeneratorResponse_File) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} } +func (m *CodeGeneratorResponse_File) Unmarshal(b []byte) error { + return xxx_messageInfo_CodeGeneratorResponse_File.Unmarshal(m, b) +} +func (m *CodeGeneratorResponse_File) Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CodeGeneratorResponse_File.Marshal(b, m, deterministic) +} +func (dst *CodeGeneratorResponse_File) XXX_Merge(src proto.Message) { + xxx_messageInfo_CodeGeneratorResponse_File.Merge(dst, src) +} +func (m *CodeGeneratorResponse_File) XXX_Size() int { + return xxx_messageInfo_CodeGeneratorResponse_File.Size(m) +} +func (m *CodeGeneratorResponse_File) XXX_DiscardUnknown() { + xxx_messageInfo_CodeGeneratorResponse_File.DiscardUnknown(m) +} + +var xxx_messageInfo_CodeGeneratorResponse_File proto.InternalMessageInfo func (m *CodeGeneratorResponse_File) GetName() string { if m != nil && m.Name != nil { diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/Makefile deleted file mode 100644 index a0bf9fef..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/Makefile +++ /dev/null @@ -1,73 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -all: - @echo run make test - -include ../../Make.protobuf - -test: golden testbuild - -#test: golden testbuild extension_test -# ./extension_test -# @echo PASS - -my_test/test.pb.go: my_test/test.proto - protoc --go_out=Mmulti/multi1.proto=github.com/golang/protobuf/protoc-gen-go/testdata/multi:. $< - -golden: - make -B my_test/test.pb.go - sed -i -e '/return.*fileDescriptor/d' my_test/test.pb.go - sed -i -e '/^var fileDescriptor/,/^}/d' my_test/test.pb.go - sed -i -e '/proto.RegisterFile.*fileDescriptor/d' my_test/test.pb.go - gofmt -w my_test/test.pb.go - diff -w my_test/test.pb.go my_test/test.pb.go.golden - -nuke: clean - -testbuild: regenerate - go test - -regenerate: - # Invoke protoc once to generate three independent .pb.go files in the same package. - protoc --go_out=. multi/multi1.proto multi/multi2.proto multi/multi3.proto - -#extension_test: extension_test.$O -# $(LD) -L. -o $@ $< - -#multi.a: multi3.pb.$O multi2.pb.$O multi1.pb.$O -# rm -f multi.a -# $(QUOTED_GOBIN)/gopack grc $@ $< - -#test.pb.go: imp.pb.go -#multi1.pb.go: multi2.pb.go multi3.pb.go -#main.$O: imp.pb.$O test.pb.$O multi.a -#extension_test.$O: extension_base.pb.$O extension_extra.pb.$O extension_user.pb.$O diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/deprecated/deprecated.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/deprecated/deprecated.pb.go new file mode 100644 index 00000000..63e4e137 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/deprecated/deprecated.pb.go @@ -0,0 +1,234 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// deprecated/deprecated.proto is a deprecated file. + +package deprecated // import "github.com/golang/protobuf/protoc-gen-go/testdata/deprecated" + +/* +package deprecated contains only deprecated messages and services. +*/ + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// DeprecatedEnum contains deprecated values. +type DeprecatedEnum int32 // Deprecated: Do not use. +const ( + // DEPRECATED is the iota value of this enum. + DeprecatedEnum_DEPRECATED DeprecatedEnum = 0 // Deprecated: Do not use. +) + +var DeprecatedEnum_name = map[int32]string{ + 0: "DEPRECATED", +} +var DeprecatedEnum_value = map[string]int32{ + "DEPRECATED": 0, +} + +func (x DeprecatedEnum) String() string { + return proto.EnumName(DeprecatedEnum_name, int32(x)) +} +func (DeprecatedEnum) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_deprecated_9e1889ba21817fad, []int{0} +} + +// DeprecatedRequest is a request to DeprecatedCall. +// +// Deprecated: Do not use. +type DeprecatedRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeprecatedRequest) Reset() { *m = DeprecatedRequest{} } +func (m *DeprecatedRequest) String() string { return proto.CompactTextString(m) } +func (*DeprecatedRequest) ProtoMessage() {} +func (*DeprecatedRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_deprecated_9e1889ba21817fad, []int{0} +} +func (m *DeprecatedRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeprecatedRequest.Unmarshal(m, b) +} +func (m *DeprecatedRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeprecatedRequest.Marshal(b, m, deterministic) +} +func (dst *DeprecatedRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeprecatedRequest.Merge(dst, src) +} +func (m *DeprecatedRequest) XXX_Size() int { + return xxx_messageInfo_DeprecatedRequest.Size(m) +} +func (m *DeprecatedRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeprecatedRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeprecatedRequest proto.InternalMessageInfo + +// Deprecated: Do not use. +type DeprecatedResponse struct { + // DeprecatedField contains a DeprecatedEnum. + DeprecatedField DeprecatedEnum `protobuf:"varint,1,opt,name=deprecated_field,json=deprecatedField,proto3,enum=deprecated.DeprecatedEnum" json:"deprecated_field,omitempty"` // Deprecated: Do not use. + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeprecatedResponse) Reset() { *m = DeprecatedResponse{} } +func (m *DeprecatedResponse) String() string { return proto.CompactTextString(m) } +func (*DeprecatedResponse) ProtoMessage() {} +func (*DeprecatedResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_deprecated_9e1889ba21817fad, []int{1} +} +func (m *DeprecatedResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeprecatedResponse.Unmarshal(m, b) +} +func (m *DeprecatedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeprecatedResponse.Marshal(b, m, deterministic) +} +func (dst *DeprecatedResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeprecatedResponse.Merge(dst, src) +} +func (m *DeprecatedResponse) XXX_Size() int { + return xxx_messageInfo_DeprecatedResponse.Size(m) +} +func (m *DeprecatedResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeprecatedResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DeprecatedResponse proto.InternalMessageInfo + +// Deprecated: Do not use. +func (m *DeprecatedResponse) GetDeprecatedField() DeprecatedEnum { + if m != nil { + return m.DeprecatedField + } + return DeprecatedEnum_DEPRECATED +} + +func init() { + proto.RegisterType((*DeprecatedRequest)(nil), "deprecated.DeprecatedRequest") + proto.RegisterType((*DeprecatedResponse)(nil), "deprecated.DeprecatedResponse") + proto.RegisterEnum("deprecated.DeprecatedEnum", DeprecatedEnum_name, DeprecatedEnum_value) +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DeprecatedServiceClient is the client API for DeprecatedService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +// +// Deprecated: Do not use. +type DeprecatedServiceClient interface { + // DeprecatedCall takes a DeprecatedRequest and returns a DeprecatedResponse. + DeprecatedCall(ctx context.Context, in *DeprecatedRequest, opts ...grpc.CallOption) (*DeprecatedResponse, error) +} + +type deprecatedServiceClient struct { + cc *grpc.ClientConn +} + +// Deprecated: Do not use. +func NewDeprecatedServiceClient(cc *grpc.ClientConn) DeprecatedServiceClient { + return &deprecatedServiceClient{cc} +} + +// Deprecated: Do not use. +func (c *deprecatedServiceClient) DeprecatedCall(ctx context.Context, in *DeprecatedRequest, opts ...grpc.CallOption) (*DeprecatedResponse, error) { + out := new(DeprecatedResponse) + err := c.cc.Invoke(ctx, "/deprecated.DeprecatedService/DeprecatedCall", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DeprecatedServiceServer is the server API for DeprecatedService service. +// +// Deprecated: Do not use. +type DeprecatedServiceServer interface { + // DeprecatedCall takes a DeprecatedRequest and returns a DeprecatedResponse. + DeprecatedCall(context.Context, *DeprecatedRequest) (*DeprecatedResponse, error) +} + +// Deprecated: Do not use. +func RegisterDeprecatedServiceServer(s *grpc.Server, srv DeprecatedServiceServer) { + s.RegisterService(&_DeprecatedService_serviceDesc, srv) +} + +func _DeprecatedService_DeprecatedCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeprecatedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeprecatedServiceServer).DeprecatedCall(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/deprecated.DeprecatedService/DeprecatedCall", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeprecatedServiceServer).DeprecatedCall(ctx, req.(*DeprecatedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _DeprecatedService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "deprecated.DeprecatedService", + HandlerType: (*DeprecatedServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DeprecatedCall", + Handler: _DeprecatedService_DeprecatedCall_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "deprecated/deprecated.proto", +} + +func init() { + proto.RegisterFile("deprecated/deprecated.proto", fileDescriptor_deprecated_9e1889ba21817fad) +} + +var fileDescriptor_deprecated_9e1889ba21817fad = []byte{ + // 248 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0x49, 0x2d, 0x28, + 0x4a, 0x4d, 0x4e, 0x2c, 0x49, 0x4d, 0xd1, 0x47, 0x30, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, + 0xb8, 0x10, 0x22, 0x4a, 0xe2, 0x5c, 0x82, 0x2e, 0x70, 0x5e, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, + 0x89, 0x15, 0x93, 0x04, 0xa3, 0x52, 0x32, 0x97, 0x10, 0xb2, 0x44, 0x71, 0x41, 0x7e, 0x5e, 0x71, + 0xaa, 0x90, 0x27, 0x97, 0x00, 0x42, 0x73, 0x7c, 0x5a, 0x66, 0x6a, 0x4e, 0x8a, 0x04, 0xa3, 0x02, + 0xa3, 0x06, 0x9f, 0x91, 0x94, 0x1e, 0x92, 0x3d, 0x08, 0x9d, 0xae, 0x79, 0xa5, 0xb9, 0x4e, 0x4c, + 0x12, 0x8c, 0x41, 0xfc, 0x08, 0x69, 0x37, 0x90, 0x36, 0x90, 0x25, 0x5a, 0x1a, 0x5c, 0x7c, 0xa8, + 0x4a, 0x85, 0x84, 0xb8, 0xb8, 0x5c, 0x5c, 0x03, 0x82, 0x5c, 0x9d, 0x1d, 0x43, 0x5c, 0x5d, 0x04, + 0x18, 0xa4, 0x98, 0x38, 0x18, 0xa5, 0x98, 0x24, 0x18, 0x8d, 0xf2, 0x90, 0xdd, 0x19, 0x9c, 0x5a, + 0x54, 0x96, 0x99, 0x9c, 0x2a, 0x14, 0x82, 0xac, 0xdd, 0x39, 0x31, 0x27, 0x47, 0x48, 0x16, 0xbb, + 0x2b, 0xa0, 0x1e, 0x93, 0x92, 0xc3, 0x25, 0x0d, 0xf1, 0x9e, 0x12, 0x73, 0x07, 0x13, 0xa3, 0x14, + 0x88, 0x70, 0x72, 0x8c, 0xb2, 0x49, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, + 0x4f, 0xcf, 0xcf, 0x49, 0xcc, 0x4b, 0xd7, 0x07, 0x07, 0x5f, 0x52, 0x69, 0x1a, 0x84, 0x91, 0xac, + 0x9b, 0x9e, 0x9a, 0xa7, 0x9b, 0x9e, 0xaf, 0x5f, 0x92, 0x5a, 0x5c, 0x92, 0x92, 0x58, 0x92, 0x88, + 0x14, 0xd2, 0x3b, 0x18, 0x19, 0x93, 0xd8, 0xc0, 0xaa, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x0e, 0xf5, 0x6c, 0x87, 0x8c, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/deprecated/deprecated.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/deprecated/deprecated.proto new file mode 100644 index 00000000..b314166d --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/deprecated/deprecated.proto @@ -0,0 +1,69 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +// package deprecated contains only deprecated messages and services. +package deprecated; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/deprecated"; + +option deprecated = true; // file-level deprecation + +// DeprecatedRequest is a request to DeprecatedCall. +message DeprecatedRequest { + option deprecated = true; +} + +message DeprecatedResponse { + // comment for DeprecatedResponse is omitted to guarantee deprecation + // message doesn't append unnecessary comments. + option deprecated = true; + // DeprecatedField contains a DeprecatedEnum. + DeprecatedEnum deprecated_field = 1 [deprecated=true]; +} + +// DeprecatedEnum contains deprecated values. +enum DeprecatedEnum { + option deprecated = true; + // DEPRECATED is the iota value of this enum. + DEPRECATED = 0 [deprecated=true]; +} + +// DeprecatedService is for making DeprecatedCalls +service DeprecatedService { + option deprecated = true; + + // DeprecatedCall takes a DeprecatedRequest and returns a DeprecatedResponse. + rpc DeprecatedCall(DeprecatedRequest) returns (DeprecatedResponse) { + option deprecated = true; + } +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base/extension_base.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base/extension_base.pb.go new file mode 100644 index 00000000..a08e8eda --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base/extension_base.pb.go @@ -0,0 +1,139 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: extension_base/extension_base.proto + +package extension_base // import "github.com/golang/protobuf/protoc-gen-go/testdata/extension_base" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type BaseMessage struct { + Height *int32 `protobuf:"varint,1,opt,name=height" json:"height,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BaseMessage) Reset() { *m = BaseMessage{} } +func (m *BaseMessage) String() string { return proto.CompactTextString(m) } +func (*BaseMessage) ProtoMessage() {} +func (*BaseMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_base_41d3c712c9fc37fc, []int{0} +} + +var extRange_BaseMessage = []proto.ExtensionRange{ + {Start: 4, End: 9}, + {Start: 16, End: 536870911}, +} + +func (*BaseMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_BaseMessage +} +func (m *BaseMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BaseMessage.Unmarshal(m, b) +} +func (m *BaseMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BaseMessage.Marshal(b, m, deterministic) +} +func (dst *BaseMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_BaseMessage.Merge(dst, src) +} +func (m *BaseMessage) XXX_Size() int { + return xxx_messageInfo_BaseMessage.Size(m) +} +func (m *BaseMessage) XXX_DiscardUnknown() { + xxx_messageInfo_BaseMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_BaseMessage proto.InternalMessageInfo + +func (m *BaseMessage) GetHeight() int32 { + if m != nil && m.Height != nil { + return *m.Height + } + return 0 +} + +// Another message that may be extended, using message_set_wire_format. +type OldStyleMessage struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `protobuf_messageset:"1" json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OldStyleMessage) Reset() { *m = OldStyleMessage{} } +func (m *OldStyleMessage) String() string { return proto.CompactTextString(m) } +func (*OldStyleMessage) ProtoMessage() {} +func (*OldStyleMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_base_41d3c712c9fc37fc, []int{1} +} + +func (m *OldStyleMessage) MarshalJSON() ([]byte, error) { + return proto.MarshalMessageSetJSON(&m.XXX_InternalExtensions) +} +func (m *OldStyleMessage) UnmarshalJSON(buf []byte) error { + return proto.UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions) +} + +var extRange_OldStyleMessage = []proto.ExtensionRange{ + {Start: 100, End: 2147483646}, +} + +func (*OldStyleMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_OldStyleMessage +} +func (m *OldStyleMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OldStyleMessage.Unmarshal(m, b) +} +func (m *OldStyleMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OldStyleMessage.Marshal(b, m, deterministic) +} +func (dst *OldStyleMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_OldStyleMessage.Merge(dst, src) +} +func (m *OldStyleMessage) XXX_Size() int { + return xxx_messageInfo_OldStyleMessage.Size(m) +} +func (m *OldStyleMessage) XXX_DiscardUnknown() { + xxx_messageInfo_OldStyleMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_OldStyleMessage proto.InternalMessageInfo + +func init() { + proto.RegisterType((*BaseMessage)(nil), "extension_base.BaseMessage") + proto.RegisterType((*OldStyleMessage)(nil), "extension_base.OldStyleMessage") +} + +func init() { + proto.RegisterFile("extension_base/extension_base.proto", fileDescriptor_extension_base_41d3c712c9fc37fc) +} + +var fileDescriptor_extension_base_41d3c712c9fc37fc = []byte{ + // 179 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4e, 0xad, 0x28, 0x49, + 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0x8b, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x47, 0xe5, 0xea, 0x15, 0x14, + 0xe5, 0x97, 0xe4, 0x0b, 0xf1, 0xa1, 0x8a, 0x2a, 0x99, 0x72, 0x71, 0x3b, 0x25, 0x16, 0xa7, 0xfa, + 0xa6, 0x16, 0x17, 0x27, 0xa6, 0xa7, 0x0a, 0x89, 0x71, 0xb1, 0x65, 0xa4, 0x66, 0xa6, 0x67, 0x94, + 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x06, 0x41, 0x79, 0x5a, 0x2c, 0x1c, 0x2c, 0x02, 0x5c, 0x5a, + 0x1c, 0x1c, 0x02, 0x02, 0x0d, 0x0d, 0x0d, 0x0d, 0x4c, 0x4a, 0xf2, 0x5c, 0xfc, 0xfe, 0x39, 0x29, + 0xc1, 0x25, 0x95, 0x39, 0x30, 0xad, 0x5a, 0x1c, 0x1c, 0x29, 0x02, 0xff, 0xff, 0xff, 0xff, 0xcf, + 0x6e, 0xc5, 0xc4, 0xc1, 0xe8, 0xe4, 0x14, 0xe5, 0x90, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, + 0x9c, 0x9f, 0xab, 0x9f, 0x9e, 0x9f, 0x93, 0x98, 0x97, 0xae, 0x0f, 0x76, 0x42, 0x52, 0x69, 0x1a, + 0x84, 0x91, 0xac, 0x9b, 0x9e, 0x9a, 0xa7, 0x9b, 0x9e, 0xaf, 0x5f, 0x92, 0x5a, 0x5c, 0x92, 0x92, + 0x58, 0x92, 0x88, 0xe6, 0x62, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x7f, 0xb7, 0x2a, 0xd1, + 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base/extension_base.proto similarity index 95% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base/extension_base.proto index 94acfc1b..0ba74def 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_base/extension_base.proto @@ -33,6 +33,8 @@ syntax = "proto2"; package extension_base; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/extension_base"; + message BaseMessage { optional int32 height = 1; extensions 4 to 9; diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra/extension_extra.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra/extension_extra.pb.go new file mode 100644 index 00000000..b3732169 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra/extension_extra.pb.go @@ -0,0 +1,78 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: extension_extra/extension_extra.proto + +package extension_extra // import "github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type ExtraMessage struct { + Width *int32 `protobuf:"varint,1,opt,name=width" json:"width,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExtraMessage) Reset() { *m = ExtraMessage{} } +func (m *ExtraMessage) String() string { return proto.CompactTextString(m) } +func (*ExtraMessage) ProtoMessage() {} +func (*ExtraMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_extra_83adf2410f49f816, []int{0} +} +func (m *ExtraMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExtraMessage.Unmarshal(m, b) +} +func (m *ExtraMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExtraMessage.Marshal(b, m, deterministic) +} +func (dst *ExtraMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtraMessage.Merge(dst, src) +} +func (m *ExtraMessage) XXX_Size() int { + return xxx_messageInfo_ExtraMessage.Size(m) +} +func (m *ExtraMessage) XXX_DiscardUnknown() { + xxx_messageInfo_ExtraMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtraMessage proto.InternalMessageInfo + +func (m *ExtraMessage) GetWidth() int32 { + if m != nil && m.Width != nil { + return *m.Width + } + return 0 +} + +func init() { + proto.RegisterType((*ExtraMessage)(nil), "extension_extra.ExtraMessage") +} + +func init() { + proto.RegisterFile("extension_extra/extension_extra.proto", fileDescriptor_extension_extra_83adf2410f49f816) +} + +var fileDescriptor_extension_extra_83adf2410f49f816 = []byte{ + // 133 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4d, 0xad, 0x28, 0x49, + 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0x8b, 0x4f, 0xad, 0x28, 0x29, 0x4a, 0xd4, 0x47, 0xe3, 0xeb, 0x15, + 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0xf1, 0xa3, 0x09, 0x2b, 0xa9, 0x70, 0xf1, 0xb8, 0x82, 0x18, 0xbe, + 0xa9, 0xc5, 0xc5, 0x89, 0xe9, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0xe5, 0x99, 0x29, 0x25, 0x19, 0x12, + 0x8c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x93, 0x73, 0x94, 0x63, 0x7a, 0x66, 0x49, 0x46, + 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e, 0xba, 0x3e, 0xd8, 0xc4, + 0xa4, 0xd2, 0x34, 0x08, 0x23, 0x59, 0x37, 0x3d, 0x35, 0x4f, 0x37, 0x3d, 0x5f, 0xbf, 0x24, 0xb5, + 0xb8, 0x24, 0x25, 0xb1, 0x04, 0xc3, 0x05, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf1, 0xec, 0xe3, + 0xb7, 0xa3, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra/extension_extra.proto similarity index 95% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra/extension_extra.proto index fca7f600..1dd03e70 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra/extension_extra.proto @@ -33,6 +33,8 @@ syntax = "proto2"; package extension_extra; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra"; + message ExtraMessage { optional int32 width = 1; } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_test.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_test.go index 86e9c118..05247299 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_test.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_test.go @@ -33,16 +33,14 @@ package testdata -/* - import ( "bytes" "regexp" "testing" "github.com/golang/protobuf/proto" - base "extension_base.pb" - user "extension_user.pb" + base "github.com/golang/protobuf/protoc-gen-go/testdata/extension_base" + user "github.com/golang/protobuf/protoc-gen-go/testdata/extension_user" ) func TestSingleFieldExtension(t *testing.T) { @@ -206,5 +204,3 @@ func main() { []testing.InternalBenchmark{}, []testing.InternalExample{}) } - -*/ diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user/extension_user.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user/extension_user.pb.go new file mode 100644 index 00000000..c7187921 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user/extension_user.pb.go @@ -0,0 +1,401 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: extension_user/extension_user.proto + +package extension_user // import "github.com/golang/protobuf/protoc-gen-go/testdata/extension_user" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import extension_base "github.com/golang/protobuf/protoc-gen-go/testdata/extension_base" +import extension_extra "github.com/golang/protobuf/protoc-gen-go/testdata/extension_extra" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type UserMessage struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Rank *string `protobuf:"bytes,2,opt,name=rank" json:"rank,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserMessage) Reset() { *m = UserMessage{} } +func (m *UserMessage) String() string { return proto.CompactTextString(m) } +func (*UserMessage) ProtoMessage() {} +func (*UserMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_user_af41b5e0bdfb7846, []int{0} +} +func (m *UserMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserMessage.Unmarshal(m, b) +} +func (m *UserMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserMessage.Marshal(b, m, deterministic) +} +func (dst *UserMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserMessage.Merge(dst, src) +} +func (m *UserMessage) XXX_Size() int { + return xxx_messageInfo_UserMessage.Size(m) +} +func (m *UserMessage) XXX_DiscardUnknown() { + xxx_messageInfo_UserMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_UserMessage proto.InternalMessageInfo + +func (m *UserMessage) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *UserMessage) GetRank() string { + if m != nil && m.Rank != nil { + return *m.Rank + } + return "" +} + +// Extend inside the scope of another type +type LoudMessage struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LoudMessage) Reset() { *m = LoudMessage{} } +func (m *LoudMessage) String() string { return proto.CompactTextString(m) } +func (*LoudMessage) ProtoMessage() {} +func (*LoudMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_user_af41b5e0bdfb7846, []int{1} +} + +var extRange_LoudMessage = []proto.ExtensionRange{ + {Start: 100, End: 536870911}, +} + +func (*LoudMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_LoudMessage +} +func (m *LoudMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LoudMessage.Unmarshal(m, b) +} +func (m *LoudMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LoudMessage.Marshal(b, m, deterministic) +} +func (dst *LoudMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_LoudMessage.Merge(dst, src) +} +func (m *LoudMessage) XXX_Size() int { + return xxx_messageInfo_LoudMessage.Size(m) +} +func (m *LoudMessage) XXX_DiscardUnknown() { + xxx_messageInfo_LoudMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_LoudMessage proto.InternalMessageInfo + +var E_LoudMessage_Volume = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: (*uint32)(nil), + Field: 8, + Name: "extension_user.LoudMessage.volume", + Tag: "varint,8,opt,name=volume", + Filename: "extension_user/extension_user.proto", +} + +// Extend inside the scope of another type, using a message. +type LoginMessage struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LoginMessage) Reset() { *m = LoginMessage{} } +func (m *LoginMessage) String() string { return proto.CompactTextString(m) } +func (*LoginMessage) ProtoMessage() {} +func (*LoginMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_user_af41b5e0bdfb7846, []int{2} +} +func (m *LoginMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LoginMessage.Unmarshal(m, b) +} +func (m *LoginMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LoginMessage.Marshal(b, m, deterministic) +} +func (dst *LoginMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_LoginMessage.Merge(dst, src) +} +func (m *LoginMessage) XXX_Size() int { + return xxx_messageInfo_LoginMessage.Size(m) +} +func (m *LoginMessage) XXX_DiscardUnknown() { + xxx_messageInfo_LoginMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_LoginMessage proto.InternalMessageInfo + +var E_LoginMessage_UserMessage = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: (*UserMessage)(nil), + Field: 16, + Name: "extension_user.LoginMessage.user_message", + Tag: "bytes,16,opt,name=user_message,json=userMessage", + Filename: "extension_user/extension_user.proto", +} + +type Detail struct { + Color *string `protobuf:"bytes,1,opt,name=color" json:"color,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Detail) Reset() { *m = Detail{} } +func (m *Detail) String() string { return proto.CompactTextString(m) } +func (*Detail) ProtoMessage() {} +func (*Detail) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_user_af41b5e0bdfb7846, []int{3} +} +func (m *Detail) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Detail.Unmarshal(m, b) +} +func (m *Detail) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Detail.Marshal(b, m, deterministic) +} +func (dst *Detail) XXX_Merge(src proto.Message) { + xxx_messageInfo_Detail.Merge(dst, src) +} +func (m *Detail) XXX_Size() int { + return xxx_messageInfo_Detail.Size(m) +} +func (m *Detail) XXX_DiscardUnknown() { + xxx_messageInfo_Detail.DiscardUnknown(m) +} + +var xxx_messageInfo_Detail proto.InternalMessageInfo + +func (m *Detail) GetColor() string { + if m != nil && m.Color != nil { + return *m.Color + } + return "" +} + +// An extension of an extension +type Announcement struct { + Words *string `protobuf:"bytes,1,opt,name=words" json:"words,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Announcement) Reset() { *m = Announcement{} } +func (m *Announcement) String() string { return proto.CompactTextString(m) } +func (*Announcement) ProtoMessage() {} +func (*Announcement) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_user_af41b5e0bdfb7846, []int{4} +} +func (m *Announcement) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Announcement.Unmarshal(m, b) +} +func (m *Announcement) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Announcement.Marshal(b, m, deterministic) +} +func (dst *Announcement) XXX_Merge(src proto.Message) { + xxx_messageInfo_Announcement.Merge(dst, src) +} +func (m *Announcement) XXX_Size() int { + return xxx_messageInfo_Announcement.Size(m) +} +func (m *Announcement) XXX_DiscardUnknown() { + xxx_messageInfo_Announcement.DiscardUnknown(m) +} + +var xxx_messageInfo_Announcement proto.InternalMessageInfo + +func (m *Announcement) GetWords() string { + if m != nil && m.Words != nil { + return *m.Words + } + return "" +} + +var E_Announcement_LoudExt = &proto.ExtensionDesc{ + ExtendedType: (*LoudMessage)(nil), + ExtensionType: (*Announcement)(nil), + Field: 100, + Name: "extension_user.Announcement.loud_ext", + Tag: "bytes,100,opt,name=loud_ext,json=loudExt", + Filename: "extension_user/extension_user.proto", +} + +// Something that can be put in a message set. +type OldStyleParcel struct { + Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` + Height *int32 `protobuf:"varint,2,opt,name=height" json:"height,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OldStyleParcel) Reset() { *m = OldStyleParcel{} } +func (m *OldStyleParcel) String() string { return proto.CompactTextString(m) } +func (*OldStyleParcel) ProtoMessage() {} +func (*OldStyleParcel) Descriptor() ([]byte, []int) { + return fileDescriptor_extension_user_af41b5e0bdfb7846, []int{5} +} +func (m *OldStyleParcel) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OldStyleParcel.Unmarshal(m, b) +} +func (m *OldStyleParcel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OldStyleParcel.Marshal(b, m, deterministic) +} +func (dst *OldStyleParcel) XXX_Merge(src proto.Message) { + xxx_messageInfo_OldStyleParcel.Merge(dst, src) +} +func (m *OldStyleParcel) XXX_Size() int { + return xxx_messageInfo_OldStyleParcel.Size(m) +} +func (m *OldStyleParcel) XXX_DiscardUnknown() { + xxx_messageInfo_OldStyleParcel.DiscardUnknown(m) +} + +var xxx_messageInfo_OldStyleParcel proto.InternalMessageInfo + +func (m *OldStyleParcel) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *OldStyleParcel) GetHeight() int32 { + if m != nil && m.Height != nil { + return *m.Height + } + return 0 +} + +var E_OldStyleParcel_MessageSetExtension = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.OldStyleMessage)(nil), + ExtensionType: (*OldStyleParcel)(nil), + Field: 2001, + Name: "extension_user.OldStyleParcel", + Tag: "bytes,2001,opt,name=message_set_extension,json=messageSetExtension", + Filename: "extension_user/extension_user.proto", +} + +var E_UserMessage = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: (*UserMessage)(nil), + Field: 5, + Name: "extension_user.user_message", + Tag: "bytes,5,opt,name=user_message,json=userMessage", + Filename: "extension_user/extension_user.proto", +} + +var E_ExtraMessage = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: (*extension_extra.ExtraMessage)(nil), + Field: 9, + Name: "extension_user.extra_message", + Tag: "bytes,9,opt,name=extra_message,json=extraMessage", + Filename: "extension_user/extension_user.proto", +} + +var E_Width = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 6, + Name: "extension_user.width", + Tag: "varint,6,opt,name=width", + Filename: "extension_user/extension_user.proto", +} + +var E_Area = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: (*int64)(nil), + Field: 7, + Name: "extension_user.area", + Tag: "varint,7,opt,name=area", + Filename: "extension_user/extension_user.proto", +} + +var E_Detail = &proto.ExtensionDesc{ + ExtendedType: (*extension_base.BaseMessage)(nil), + ExtensionType: ([]*Detail)(nil), + Field: 17, + Name: "extension_user.detail", + Tag: "bytes,17,rep,name=detail", + Filename: "extension_user/extension_user.proto", +} + +func init() { + proto.RegisterType((*UserMessage)(nil), "extension_user.UserMessage") + proto.RegisterType((*LoudMessage)(nil), "extension_user.LoudMessage") + proto.RegisterType((*LoginMessage)(nil), "extension_user.LoginMessage") + proto.RegisterType((*Detail)(nil), "extension_user.Detail") + proto.RegisterType((*Announcement)(nil), "extension_user.Announcement") + proto.RegisterMessageSetType((*OldStyleParcel)(nil), 2001, "extension_user.OldStyleParcel") + proto.RegisterType((*OldStyleParcel)(nil), "extension_user.OldStyleParcel") + proto.RegisterExtension(E_LoudMessage_Volume) + proto.RegisterExtension(E_LoginMessage_UserMessage) + proto.RegisterExtension(E_Announcement_LoudExt) + proto.RegisterExtension(E_OldStyleParcel_MessageSetExtension) + proto.RegisterExtension(E_UserMessage) + proto.RegisterExtension(E_ExtraMessage) + proto.RegisterExtension(E_Width) + proto.RegisterExtension(E_Area) + proto.RegisterExtension(E_Detail) +} + +func init() { + proto.RegisterFile("extension_user/extension_user.proto", fileDescriptor_extension_user_af41b5e0bdfb7846) +} + +var fileDescriptor_extension_user_af41b5e0bdfb7846 = []byte{ + // 492 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x51, 0x6f, 0x94, 0x40, + 0x10, 0x0e, 0x6d, 0x8f, 0x5e, 0x87, 0x6b, 0xad, 0xa8, 0xcd, 0xa5, 0x6a, 0x25, 0x18, 0x13, 0x62, + 0xd2, 0x23, 0x62, 0x7c, 0xe1, 0x49, 0x2f, 0xde, 0x93, 0x67, 0x34, 0x54, 0x5f, 0xf4, 0x81, 0xec, + 0xc1, 0xc8, 0x91, 0xc2, 0xae, 0xd9, 0x5d, 0xec, 0xe9, 0xd3, 0xfd, 0x26, 0xff, 0x89, 0xff, 0xc8, + 0xb0, 0x2c, 0x2d, 0x87, 0xc9, 0xc5, 0xbe, 0x90, 0xfd, 0x86, 0x6f, 0xbe, 0x99, 0xfd, 0x66, 0x00, + 0x9e, 0xe2, 0x4a, 0x22, 0x15, 0x39, 0xa3, 0x71, 0x25, 0x90, 0xfb, 0x9b, 0x70, 0xf2, 0x9d, 0x33, + 0xc9, 0xec, 0xa3, 0xcd, 0xe8, 0x69, 0x27, 0x69, 0x41, 0x04, 0xfa, 0x9b, 0xb0, 0x49, 0x3a, 0x7d, + 0x76, 0x13, 0xc5, 0x95, 0xe4, 0xc4, 0xef, 0xe1, 0x86, 0xe6, 0xbe, 0x02, 0xeb, 0xb3, 0x40, 0xfe, + 0x1e, 0x85, 0x20, 0x19, 0xda, 0x36, 0xec, 0x51, 0x52, 0xe2, 0xd8, 0x70, 0x0c, 0xef, 0x20, 0x52, + 0xe7, 0x3a, 0xc6, 0x09, 0xbd, 0x1c, 0xef, 0x34, 0xb1, 0xfa, 0xec, 0xce, 0xc1, 0x9a, 0xb3, 0x2a, + 0xd5, 0x69, 0xcf, 0x87, 0xc3, 0xf4, 0x78, 0xbd, 0x5e, 0xaf, 0x77, 0x82, 0x97, 0x60, 0xfe, 0x60, + 0x45, 0x55, 0xa2, 0xfd, 0x70, 0xd2, 0xeb, 0x6b, 0x4a, 0x04, 0xea, 0x84, 0xf1, 0xd0, 0x31, 0xbc, + 0xc3, 0x48, 0x53, 0xdd, 0x4b, 0x18, 0xcd, 0x59, 0x96, 0x53, 0xfd, 0x36, 0xf8, 0x0a, 0xa3, 0xfa, + 0xa2, 0x71, 0xa9, 0xbb, 0xda, 0x2a, 0x75, 0xec, 0x18, 0x9e, 0x15, 0x74, 0x29, 0xca, 0xba, 0xce, + 0xad, 0x22, 0xab, 0xba, 0x01, 0xee, 0x19, 0x98, 0x6f, 0x51, 0x92, 0xbc, 0xb0, 0xef, 0xc3, 0x20, + 0x61, 0x05, 0xe3, 0xfa, 0xb6, 0x0d, 0x70, 0x7f, 0xc1, 0xe8, 0x0d, 0xa5, 0xac, 0xa2, 0x09, 0x96, + 0x48, 0x65, 0xcd, 0xba, 0x62, 0x3c, 0x15, 0x2d, 0x4b, 0x81, 0xe0, 0x13, 0x0c, 0x0b, 0x56, 0xa5, + 0xb5, 0x97, 0xf6, 0x3f, 0xb5, 0x3b, 0xd6, 0x8c, 0x53, 0xd5, 0xde, 0xa3, 0x3e, 0xa5, 0x5b, 0x22, + 0xda, 0xaf, 0xa5, 0x66, 0x2b, 0xe9, 0xfe, 0x36, 0xe0, 0xe8, 0x43, 0x91, 0x5e, 0xc8, 0x9f, 0x05, + 0x7e, 0x24, 0x3c, 0xc1, 0xa2, 0x33, 0x91, 0x9d, 0xeb, 0x89, 0x9c, 0x80, 0xb9, 0xc4, 0x3c, 0x5b, + 0x4a, 0x35, 0x93, 0x41, 0xa4, 0x51, 0x20, 0xe1, 0x81, 0xb6, 0x2c, 0x16, 0x28, 0xe3, 0xeb, 0x92, + 0xf6, 0x93, 0xbe, 0x81, 0x6d, 0x91, 0xb6, 0xcb, 0x3f, 0x77, 0x54, 0x9b, 0x67, 0xfd, 0x36, 0x37, + 0x9b, 0x89, 0xee, 0x69, 0xf9, 0x0b, 0x94, 0xb3, 0x96, 0x18, 0xde, 0x6a, 0x5a, 0x83, 0xdb, 0x4d, + 0x2b, 0x8c, 0xe1, 0x50, 0xad, 0xeb, 0xff, 0xa9, 0x1f, 0x28, 0xf5, 0xc7, 0x93, 0xfe, 0xae, 0xcf, + 0xea, 0x67, 0xab, 0x3f, 0xc2, 0x0e, 0x0a, 0x5f, 0xc0, 0xe0, 0x2a, 0x4f, 0xe5, 0x72, 0xbb, 0xb0, + 0xa9, 0x7c, 0x6e, 0x98, 0xa1, 0x0f, 0x7b, 0x84, 0x23, 0xd9, 0x9e, 0xb1, 0xef, 0x18, 0xde, 0x6e, + 0xa4, 0x88, 0xe1, 0x3b, 0x30, 0xd3, 0x66, 0xe5, 0xb6, 0xa6, 0xdc, 0x75, 0x76, 0x3d, 0x2b, 0x38, + 0xe9, 0x7b, 0xd3, 0x6c, 0x6b, 0xa4, 0x25, 0xa6, 0xd3, 0x2f, 0xaf, 0xb3, 0x5c, 0x2e, 0xab, 0xc5, + 0x24, 0x61, 0xa5, 0x9f, 0xb1, 0x82, 0xd0, 0xcc, 0x57, 0x1f, 0xf3, 0xa2, 0xfa, 0xd6, 0x1c, 0x92, + 0xf3, 0x0c, 0xe9, 0x79, 0xc6, 0x7c, 0x89, 0x42, 0xa6, 0x44, 0x92, 0xde, 0x7f, 0xe5, 0x6f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xdf, 0x18, 0x64, 0x15, 0x77, 0x04, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user/extension_user.proto similarity index 94% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user/extension_user.proto index ff65873d..033c186c 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/extension_user/extension_user.proto @@ -31,11 +31,13 @@ syntax = "proto2"; -import "extension_base.proto"; -import "extension_extra.proto"; +import "extension_base/extension_base.proto"; +import "extension_extra/extension_extra.proto"; package extension_user; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/extension_user"; + message UserMessage { optional string name = 1; optional string rank = 2; diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc/grpc.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc/grpc.pb.go new file mode 100644 index 00000000..1bc0283f --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc/grpc.pb.go @@ -0,0 +1,444 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: grpc/grpc.proto + +package testing // import "github.com/golang/protobuf/protoc-gen-go/testdata/grpc" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type SimpleRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SimpleRequest) Reset() { *m = SimpleRequest{} } +func (m *SimpleRequest) String() string { return proto.CompactTextString(m) } +func (*SimpleRequest) ProtoMessage() {} +func (*SimpleRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_grpc_65bf3902e49ee873, []int{0} +} +func (m *SimpleRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SimpleRequest.Unmarshal(m, b) +} +func (m *SimpleRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SimpleRequest.Marshal(b, m, deterministic) +} +func (dst *SimpleRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SimpleRequest.Merge(dst, src) +} +func (m *SimpleRequest) XXX_Size() int { + return xxx_messageInfo_SimpleRequest.Size(m) +} +func (m *SimpleRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SimpleRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SimpleRequest proto.InternalMessageInfo + +type SimpleResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SimpleResponse) Reset() { *m = SimpleResponse{} } +func (m *SimpleResponse) String() string { return proto.CompactTextString(m) } +func (*SimpleResponse) ProtoMessage() {} +func (*SimpleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_grpc_65bf3902e49ee873, []int{1} +} +func (m *SimpleResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SimpleResponse.Unmarshal(m, b) +} +func (m *SimpleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SimpleResponse.Marshal(b, m, deterministic) +} +func (dst *SimpleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SimpleResponse.Merge(dst, src) +} +func (m *SimpleResponse) XXX_Size() int { + return xxx_messageInfo_SimpleResponse.Size(m) +} +func (m *SimpleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_SimpleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_SimpleResponse proto.InternalMessageInfo + +type StreamMsg struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamMsg) Reset() { *m = StreamMsg{} } +func (m *StreamMsg) String() string { return proto.CompactTextString(m) } +func (*StreamMsg) ProtoMessage() {} +func (*StreamMsg) Descriptor() ([]byte, []int) { + return fileDescriptor_grpc_65bf3902e49ee873, []int{2} +} +func (m *StreamMsg) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamMsg.Unmarshal(m, b) +} +func (m *StreamMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamMsg.Marshal(b, m, deterministic) +} +func (dst *StreamMsg) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamMsg.Merge(dst, src) +} +func (m *StreamMsg) XXX_Size() int { + return xxx_messageInfo_StreamMsg.Size(m) +} +func (m *StreamMsg) XXX_DiscardUnknown() { + xxx_messageInfo_StreamMsg.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamMsg proto.InternalMessageInfo + +type StreamMsg2 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StreamMsg2) Reset() { *m = StreamMsg2{} } +func (m *StreamMsg2) String() string { return proto.CompactTextString(m) } +func (*StreamMsg2) ProtoMessage() {} +func (*StreamMsg2) Descriptor() ([]byte, []int) { + return fileDescriptor_grpc_65bf3902e49ee873, []int{3} +} +func (m *StreamMsg2) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StreamMsg2.Unmarshal(m, b) +} +func (m *StreamMsg2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StreamMsg2.Marshal(b, m, deterministic) +} +func (dst *StreamMsg2) XXX_Merge(src proto.Message) { + xxx_messageInfo_StreamMsg2.Merge(dst, src) +} +func (m *StreamMsg2) XXX_Size() int { + return xxx_messageInfo_StreamMsg2.Size(m) +} +func (m *StreamMsg2) XXX_DiscardUnknown() { + xxx_messageInfo_StreamMsg2.DiscardUnknown(m) +} + +var xxx_messageInfo_StreamMsg2 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*SimpleRequest)(nil), "grpc.testing.SimpleRequest") + proto.RegisterType((*SimpleResponse)(nil), "grpc.testing.SimpleResponse") + proto.RegisterType((*StreamMsg)(nil), "grpc.testing.StreamMsg") + proto.RegisterType((*StreamMsg2)(nil), "grpc.testing.StreamMsg2") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// TestClient is the client API for Test service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type TestClient interface { + UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error) + // This RPC streams from the server only. + Downstream(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (Test_DownstreamClient, error) + // This RPC streams from the client. + Upstream(ctx context.Context, opts ...grpc.CallOption) (Test_UpstreamClient, error) + // This one streams in both directions. + Bidi(ctx context.Context, opts ...grpc.CallOption) (Test_BidiClient, error) +} + +type testClient struct { + cc *grpc.ClientConn +} + +func NewTestClient(cc *grpc.ClientConn) TestClient { + return &testClient{cc} +} + +func (c *testClient) UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error) { + out := new(SimpleResponse) + err := c.cc.Invoke(ctx, "/grpc.testing.Test/UnaryCall", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *testClient) Downstream(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (Test_DownstreamClient, error) { + stream, err := c.cc.NewStream(ctx, &_Test_serviceDesc.Streams[0], "/grpc.testing.Test/Downstream", opts...) + if err != nil { + return nil, err + } + x := &testDownstreamClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Test_DownstreamClient interface { + Recv() (*StreamMsg, error) + grpc.ClientStream +} + +type testDownstreamClient struct { + grpc.ClientStream +} + +func (x *testDownstreamClient) Recv() (*StreamMsg, error) { + m := new(StreamMsg) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *testClient) Upstream(ctx context.Context, opts ...grpc.CallOption) (Test_UpstreamClient, error) { + stream, err := c.cc.NewStream(ctx, &_Test_serviceDesc.Streams[1], "/grpc.testing.Test/Upstream", opts...) + if err != nil { + return nil, err + } + x := &testUpstreamClient{stream} + return x, nil +} + +type Test_UpstreamClient interface { + Send(*StreamMsg) error + CloseAndRecv() (*SimpleResponse, error) + grpc.ClientStream +} + +type testUpstreamClient struct { + grpc.ClientStream +} + +func (x *testUpstreamClient) Send(m *StreamMsg) error { + return x.ClientStream.SendMsg(m) +} + +func (x *testUpstreamClient) CloseAndRecv() (*SimpleResponse, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(SimpleResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *testClient) Bidi(ctx context.Context, opts ...grpc.CallOption) (Test_BidiClient, error) { + stream, err := c.cc.NewStream(ctx, &_Test_serviceDesc.Streams[2], "/grpc.testing.Test/Bidi", opts...) + if err != nil { + return nil, err + } + x := &testBidiClient{stream} + return x, nil +} + +type Test_BidiClient interface { + Send(*StreamMsg) error + Recv() (*StreamMsg2, error) + grpc.ClientStream +} + +type testBidiClient struct { + grpc.ClientStream +} + +func (x *testBidiClient) Send(m *StreamMsg) error { + return x.ClientStream.SendMsg(m) +} + +func (x *testBidiClient) Recv() (*StreamMsg2, error) { + m := new(StreamMsg2) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// TestServer is the server API for Test service. +type TestServer interface { + UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error) + // This RPC streams from the server only. + Downstream(*SimpleRequest, Test_DownstreamServer) error + // This RPC streams from the client. + Upstream(Test_UpstreamServer) error + // This one streams in both directions. + Bidi(Test_BidiServer) error +} + +func RegisterTestServer(s *grpc.Server, srv TestServer) { + s.RegisterService(&_Test_serviceDesc, srv) +} + +func _Test_UnaryCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TestServer).UnaryCall(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.testing.Test/UnaryCall", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TestServer).UnaryCall(ctx, req.(*SimpleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Test_Downstream_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(SimpleRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(TestServer).Downstream(m, &testDownstreamServer{stream}) +} + +type Test_DownstreamServer interface { + Send(*StreamMsg) error + grpc.ServerStream +} + +type testDownstreamServer struct { + grpc.ServerStream +} + +func (x *testDownstreamServer) Send(m *StreamMsg) error { + return x.ServerStream.SendMsg(m) +} + +func _Test_Upstream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(TestServer).Upstream(&testUpstreamServer{stream}) +} + +type Test_UpstreamServer interface { + SendAndClose(*SimpleResponse) error + Recv() (*StreamMsg, error) + grpc.ServerStream +} + +type testUpstreamServer struct { + grpc.ServerStream +} + +func (x *testUpstreamServer) SendAndClose(m *SimpleResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *testUpstreamServer) Recv() (*StreamMsg, error) { + m := new(StreamMsg) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Test_Bidi_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(TestServer).Bidi(&testBidiServer{stream}) +} + +type Test_BidiServer interface { + Send(*StreamMsg2) error + Recv() (*StreamMsg, error) + grpc.ServerStream +} + +type testBidiServer struct { + grpc.ServerStream +} + +func (x *testBidiServer) Send(m *StreamMsg2) error { + return x.ServerStream.SendMsg(m) +} + +func (x *testBidiServer) Recv() (*StreamMsg, error) { + m := new(StreamMsg) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _Test_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.testing.Test", + HandlerType: (*TestServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UnaryCall", + Handler: _Test_UnaryCall_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Downstream", + Handler: _Test_Downstream_Handler, + ServerStreams: true, + }, + { + StreamName: "Upstream", + Handler: _Test_Upstream_Handler, + ClientStreams: true, + }, + { + StreamName: "Bidi", + Handler: _Test_Bidi_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "grpc/grpc.proto", +} + +func init() { proto.RegisterFile("grpc/grpc.proto", fileDescriptor_grpc_65bf3902e49ee873) } + +var fileDescriptor_grpc_65bf3902e49ee873 = []byte{ + // 244 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4f, 0x2f, 0x2a, 0x48, + 0xd6, 0x07, 0x11, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x3c, 0x60, 0x76, 0x49, 0x6a, 0x71, + 0x49, 0x66, 0x5e, 0xba, 0x12, 0x3f, 0x17, 0x6f, 0x70, 0x66, 0x6e, 0x41, 0x4e, 0x6a, 0x50, 0x6a, + 0x61, 0x69, 0x6a, 0x71, 0x89, 0x92, 0x00, 0x17, 0x1f, 0x4c, 0xa0, 0xb8, 0x20, 0x3f, 0xaf, 0x38, + 0x55, 0x89, 0x9b, 0x8b, 0x33, 0xb8, 0xa4, 0x28, 0x35, 0x31, 0xd7, 0xb7, 0x38, 0x5d, 0x89, 0x87, + 0x8b, 0x0b, 0xce, 0x31, 0x32, 0x9a, 0xc1, 0xc4, 0xc5, 0x12, 0x92, 0x5a, 0x5c, 0x22, 0xe4, 0xc6, + 0xc5, 0x19, 0x9a, 0x97, 0x58, 0x54, 0xe9, 0x9c, 0x98, 0x93, 0x23, 0x24, 0xad, 0x87, 0x6c, 0x85, + 0x1e, 0x8a, 0xf9, 0x52, 0x32, 0xd8, 0x25, 0x21, 0x76, 0x09, 0xb9, 0x70, 0x71, 0xb9, 0xe4, 0x97, + 0xe7, 0x15, 0x83, 0xad, 0xc0, 0x6f, 0x90, 0x38, 0x9a, 0x24, 0xcc, 0x55, 0x06, 0x8c, 0x42, 0xce, + 0x5c, 0x1c, 0xa1, 0x05, 0x50, 0x33, 0x70, 0x29, 0xc3, 0xef, 0x10, 0x0d, 0x46, 0x21, 0x5b, 0x2e, + 0x16, 0xa7, 0xcc, 0x94, 0x4c, 0xdc, 0x06, 0x48, 0xe0, 0x90, 0x30, 0xd2, 0x60, 0x34, 0x60, 0x74, + 0x72, 0x88, 0xb2, 0x4b, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, + 0xcf, 0x49, 0xcc, 0x4b, 0xd7, 0x07, 0xc7, 0x40, 0x52, 0x69, 0x1a, 0x84, 0x91, 0xac, 0x9b, 0x9e, + 0x9a, 0xa7, 0x9b, 0x9e, 0xaf, 0x0f, 0x32, 0x22, 0x25, 0xb1, 0x24, 0x11, 0x1c, 0x4d, 0xd6, 0x50, + 0x03, 0x93, 0xd8, 0xc0, 0x8a, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x90, 0xb9, 0x95, 0x42, + 0xc2, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc/grpc.proto similarity index 96% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc/grpc.proto index b8bc41ac..0e5c64a9 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/grpc/grpc.proto @@ -33,6 +33,8 @@ syntax = "proto3"; package grpc.testing; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/grpc;testing"; + message SimpleRequest { } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp.pb.go.golden b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp.pb.go.golden deleted file mode 100644 index 784a4f86..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp.pb.go.golden +++ /dev/null @@ -1,113 +0,0 @@ -// Code generated by protoc-gen-go. -// source: imp.proto -// DO NOT EDIT! - -package imp - -import proto "github.com/golang/protobuf/proto" -import "math" -import "os" -import imp1 "imp2.pb" - -// Reference proto & math imports to suppress error if they are not otherwise used. -var _ = proto.GetString -var _ = math.Inf - -// Types from public import imp2.proto -type PubliclyImportedMessage imp1.PubliclyImportedMessage - -func (this *PubliclyImportedMessage) Reset() { (*imp1.PubliclyImportedMessage)(this).Reset() } -func (this *PubliclyImportedMessage) String() string { - return (*imp1.PubliclyImportedMessage)(this).String() -} - -// PubliclyImportedMessage from public import imp.proto - -type ImportedMessage_Owner int32 - -const ( - ImportedMessage_DAVE ImportedMessage_Owner = 1 - ImportedMessage_MIKE ImportedMessage_Owner = 2 -) - -var ImportedMessage_Owner_name = map[int32]string{ - 1: "DAVE", - 2: "MIKE", -} -var ImportedMessage_Owner_value = map[string]int32{ - "DAVE": 1, - "MIKE": 2, -} - -// NewImportedMessage_Owner is deprecated. Use x.Enum() instead. -func NewImportedMessage_Owner(x ImportedMessage_Owner) *ImportedMessage_Owner { - e := ImportedMessage_Owner(x) - return &e -} -func (x ImportedMessage_Owner) Enum() *ImportedMessage_Owner { - p := new(ImportedMessage_Owner) - *p = x - return p -} -func (x ImportedMessage_Owner) String() string { - return proto.EnumName(ImportedMessage_Owner_name, int32(x)) -} - -type ImportedMessage struct { - Field *int64 `protobuf:"varint,1,req,name=field" json:"field,omitempty"` - XXX_extensions map[int32][]byte `json:",omitempty"` - XXX_unrecognized []byte `json:",omitempty"` -} - -func (this *ImportedMessage) Reset() { *this = ImportedMessage{} } -func (this *ImportedMessage) String() string { return proto.CompactTextString(this) } - -var extRange_ImportedMessage = []proto.ExtensionRange{ - proto.ExtensionRange{90, 100}, -} - -func (*ImportedMessage) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_ImportedMessage -} -func (this *ImportedMessage) ExtensionMap() map[int32][]byte { - if this.XXX_extensions == nil { - this.XXX_extensions = make(map[int32][]byte) - } - return this.XXX_extensions -} - -type ImportedExtendable struct { - XXX_extensions map[int32][]byte `json:",omitempty"` - XXX_unrecognized []byte `json:",omitempty"` -} - -func (this *ImportedExtendable) Reset() { *this = ImportedExtendable{} } -func (this *ImportedExtendable) String() string { return proto.CompactTextString(this) } - -func (this *ImportedExtendable) Marshal() ([]byte, error) { - return proto.MarshalMessageSet(this.ExtensionMap()) -} -func (this *ImportedExtendable) Unmarshal(buf []byte) error { - return proto.UnmarshalMessageSet(buf, this.ExtensionMap()) -} -// ensure ImportedExtendable satisfies proto.Marshaler and proto.Unmarshaler -var _ proto.Marshaler = (*ImportedExtendable)(nil) -var _ proto.Unmarshaler = (*ImportedExtendable)(nil) - -var extRange_ImportedExtendable = []proto.ExtensionRange{ - proto.ExtensionRange{100, 536870911}, -} - -func (*ImportedExtendable) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_ImportedExtendable -} -func (this *ImportedExtendable) ExtensionMap() map[int32][]byte { - if this.XXX_extensions == nil { - this.XXX_extensions = make(map[int32][]byte) - } - return this.XXX_extensions -} - -func init() { - proto.RegisterEnum("imp.ImportedMessage_Owner", ImportedMessage_Owner_name, ImportedMessage_Owner_value) -} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/a.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/a.pb.go new file mode 100644 index 00000000..d67ada6d --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/a.pb.go @@ -0,0 +1,110 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: import_public/a.proto + +package import_public // import "github.com/golang/protobuf/protoc-gen-go/testdata/import_public" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sub "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// M from public import import_public/sub/a.proto +type M = sub.M + +// E from public import import_public/sub/a.proto +type E = sub.E + +var E_name = sub.E_name +var E_value = sub.E_value + +const E_ZERO = E(sub.E_ZERO) + +// Ignoring public import of Local from import_public/b.proto + +type Public struct { + M *sub.M `protobuf:"bytes,1,opt,name=m,proto3" json:"m,omitempty"` + E sub.E `protobuf:"varint,2,opt,name=e,proto3,enum=goproto.test.import_public.sub.E" json:"e,omitempty"` + Local *Local `protobuf:"bytes,3,opt,name=local,proto3" json:"local,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Public) Reset() { *m = Public{} } +func (m *Public) String() string { return proto.CompactTextString(m) } +func (*Public) ProtoMessage() {} +func (*Public) Descriptor() ([]byte, []int) { + return fileDescriptor_a_c0314c022b7c17d8, []int{0} +} +func (m *Public) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Public.Unmarshal(m, b) +} +func (m *Public) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Public.Marshal(b, m, deterministic) +} +func (dst *Public) XXX_Merge(src proto.Message) { + xxx_messageInfo_Public.Merge(dst, src) +} +func (m *Public) XXX_Size() int { + return xxx_messageInfo_Public.Size(m) +} +func (m *Public) XXX_DiscardUnknown() { + xxx_messageInfo_Public.DiscardUnknown(m) +} + +var xxx_messageInfo_Public proto.InternalMessageInfo + +func (m *Public) GetM() *sub.M { + if m != nil { + return m.M + } + return nil +} + +func (m *Public) GetE() sub.E { + if m != nil { + return m.E + } + return sub.E_ZERO +} + +func (m *Public) GetLocal() *Local { + if m != nil { + return m.Local + } + return nil +} + +func init() { + proto.RegisterType((*Public)(nil), "goproto.test.import_public.Public") +} + +func init() { proto.RegisterFile("import_public/a.proto", fileDescriptor_a_c0314c022b7c17d8) } + +var fileDescriptor_a_c0314c022b7c17d8 = []byte{ + // 200 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcd, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x89, 0x2f, 0x28, 0x4d, 0xca, 0xc9, 0x4c, 0xd6, 0x4f, 0xd4, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x92, 0x4a, 0xcf, 0x07, 0x33, 0xf4, 0x4a, 0x52, 0x8b, 0x4b, 0xf4, 0x50, 0xd4, 0x48, + 0x49, 0xa2, 0x6a, 0x29, 0x2e, 0x4d, 0x82, 0x69, 0x93, 0x42, 0x33, 0x2d, 0x09, 0x22, 0xac, 0xb4, + 0x98, 0x91, 0x8b, 0x2d, 0x00, 0x2c, 0x24, 0xa4, 0xcf, 0xc5, 0x98, 0x2b, 0xc1, 0xa8, 0xc0, 0xa8, + 0xc1, 0x6d, 0xa4, 0xa8, 0x87, 0xdb, 0x12, 0xbd, 0xe2, 0xd2, 0x24, 0x3d, 0xdf, 0x20, 0xc6, 0x5c, + 0x90, 0x86, 0x54, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x3e, 0xc2, 0x1a, 0x5c, 0x83, 0x18, 0x53, 0x85, + 0xcc, 0xb9, 0x58, 0x73, 0xf2, 0x93, 0x13, 0x73, 0x24, 0x98, 0x09, 0xdb, 0xe2, 0x03, 0x52, 0x18, + 0x04, 0x51, 0xef, 0xe4, 0x18, 0x65, 0x9f, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, + 0xab, 0x9f, 0x9e, 0x9f, 0x93, 0x98, 0x97, 0xae, 0x0f, 0xd6, 0x9a, 0x54, 0x9a, 0x06, 0x61, 0x24, + 0xeb, 0xa6, 0xa7, 0xe6, 0xe9, 0xa6, 0xe7, 0xeb, 0x83, 0xcc, 0x4a, 0x49, 0x2c, 0x49, 0xd4, 0x47, + 0x31, 0x2f, 0x80, 0x21, 0x80, 0x31, 0x89, 0x0d, 0xac, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, + 0x70, 0xc5, 0xc3, 0x79, 0x5a, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/a.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/a.proto new file mode 100644 index 00000000..957ad897 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/a.proto @@ -0,0 +1,45 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package goproto.test.import_public; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/import_public"; + +import public "import_public/sub/a.proto"; // Different Go package. +import public "import_public/b.proto"; // Same Go package. + +message Public { + goproto.test.import_public.sub.M m = 1; + goproto.test.import_public.sub.E e = 2; + Local local = 3; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/b.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/b.pb.go new file mode 100644 index 00000000..24569abf --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/b.pb.go @@ -0,0 +1,87 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: import_public/b.proto + +package import_public // import "github.com/golang/protobuf/protoc-gen-go/testdata/import_public" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sub "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Local struct { + M *sub.M `protobuf:"bytes,1,opt,name=m,proto3" json:"m,omitempty"` + E sub.E `protobuf:"varint,2,opt,name=e,proto3,enum=goproto.test.import_public.sub.E" json:"e,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Local) Reset() { *m = Local{} } +func (m *Local) String() string { return proto.CompactTextString(m) } +func (*Local) ProtoMessage() {} +func (*Local) Descriptor() ([]byte, []int) { + return fileDescriptor_b_7f20a805fad67bd0, []int{0} +} +func (m *Local) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Local.Unmarshal(m, b) +} +func (m *Local) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Local.Marshal(b, m, deterministic) +} +func (dst *Local) XXX_Merge(src proto.Message) { + xxx_messageInfo_Local.Merge(dst, src) +} +func (m *Local) XXX_Size() int { + return xxx_messageInfo_Local.Size(m) +} +func (m *Local) XXX_DiscardUnknown() { + xxx_messageInfo_Local.DiscardUnknown(m) +} + +var xxx_messageInfo_Local proto.InternalMessageInfo + +func (m *Local) GetM() *sub.M { + if m != nil { + return m.M + } + return nil +} + +func (m *Local) GetE() sub.E { + if m != nil { + return m.E + } + return sub.E_ZERO +} + +func init() { + proto.RegisterType((*Local)(nil), "goproto.test.import_public.Local") +} + +func init() { proto.RegisterFile("import_public/b.proto", fileDescriptor_b_7f20a805fad67bd0) } + +var fileDescriptor_b_7f20a805fad67bd0 = []byte{ + // 174 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcd, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x89, 0x2f, 0x28, 0x4d, 0xca, 0xc9, 0x4c, 0xd6, 0x4f, 0xd2, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x92, 0x4a, 0xcf, 0x07, 0x33, 0xf4, 0x4a, 0x52, 0x8b, 0x4b, 0xf4, 0x50, 0xd4, 0x48, + 0x49, 0xa2, 0x6a, 0x29, 0x2e, 0x4d, 0xd2, 0x4f, 0x84, 0x68, 0x53, 0xca, 0xe4, 0x62, 0xf5, 0xc9, + 0x4f, 0x4e, 0xcc, 0x11, 0xd2, 0xe7, 0x62, 0xcc, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x36, 0x52, + 0xd4, 0xc3, 0x6d, 0x96, 0x5e, 0x71, 0x69, 0x92, 0x9e, 0x6f, 0x10, 0x63, 0x2e, 0x48, 0x43, 0xaa, + 0x04, 0x93, 0x02, 0xa3, 0x06, 0x1f, 0x61, 0x0d, 0xae, 0x41, 0x8c, 0xa9, 0x4e, 0x8e, 0x51, 0xf6, + 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89, 0x79, + 0xe9, 0xfa, 0x60, 0x6d, 0x49, 0xa5, 0x69, 0x10, 0x46, 0xb2, 0x6e, 0x7a, 0x6a, 0x9e, 0x6e, 0x7a, + 0xbe, 0x3e, 0xc8, 0x9c, 0x94, 0xc4, 0x92, 0x44, 0x7d, 0x14, 0xb3, 0x92, 0xd8, 0xc0, 0xaa, 0x8c, + 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x2b, 0x5f, 0x8e, 0x04, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/b.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/b.proto new file mode 100644 index 00000000..1dbca3e4 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/b.proto @@ -0,0 +1,43 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package goproto.test.import_public; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/import_public"; + +import "import_public/sub/a.proto"; + +message Local { + goproto.test.import_public.sub.M m = 1; + goproto.test.import_public.sub.E e = 2; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/a.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/a.pb.go new file mode 100644 index 00000000..be667c93 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/a.pb.go @@ -0,0 +1,100 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: import_public/sub/a.proto + +package sub // import "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type E int32 + +const ( + E_ZERO E = 0 +) + +var E_name = map[int32]string{ + 0: "ZERO", +} +var E_value = map[string]int32{ + "ZERO": 0, +} + +func (x E) String() string { + return proto.EnumName(E_name, int32(x)) +} +func (E) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_a_91ca0264a534463a, []int{0} +} + +type M struct { + // Field using a type in the same Go package, but a different source file. + M2 *M2 `protobuf:"bytes,1,opt,name=m2,proto3" json:"m2,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M) Reset() { *m = M{} } +func (m *M) String() string { return proto.CompactTextString(m) } +func (*M) ProtoMessage() {} +func (*M) Descriptor() ([]byte, []int) { + return fileDescriptor_a_91ca0264a534463a, []int{0} +} +func (m *M) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M.Unmarshal(m, b) +} +func (m *M) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M.Marshal(b, m, deterministic) +} +func (dst *M) XXX_Merge(src proto.Message) { + xxx_messageInfo_M.Merge(dst, src) +} +func (m *M) XXX_Size() int { + return xxx_messageInfo_M.Size(m) +} +func (m *M) XXX_DiscardUnknown() { + xxx_messageInfo_M.DiscardUnknown(m) +} + +var xxx_messageInfo_M proto.InternalMessageInfo + +func (m *M) GetM2() *M2 { + if m != nil { + return m.M2 + } + return nil +} + +func init() { + proto.RegisterType((*M)(nil), "goproto.test.import_public.sub.M") + proto.RegisterEnum("goproto.test.import_public.sub.E", E_name, E_value) +} + +func init() { proto.RegisterFile("import_public/sub/a.proto", fileDescriptor_a_91ca0264a534463a) } + +var fileDescriptor_a_91ca0264a534463a = []byte{ + // 172 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x89, 0x2f, 0x28, 0x4d, 0xca, 0xc9, 0x4c, 0xd6, 0x2f, 0x2e, 0x4d, 0xd2, 0x4f, 0xd4, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x4b, 0xcf, 0x07, 0x33, 0xf4, 0x4a, 0x52, 0x8b, 0x4b, + 0xf4, 0x50, 0xd4, 0xe9, 0x15, 0x97, 0x26, 0x49, 0x61, 0xd1, 0x9a, 0x04, 0xd1, 0xaa, 0x64, 0xce, + 0xc5, 0xe8, 0x2b, 0x64, 0xc4, 0xc5, 0x94, 0x6b, 0x24, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0xa4, + 0xa4, 0x87, 0xdf, 0x30, 0x3d, 0x5f, 0xa3, 0x20, 0xa6, 0x5c, 0x23, 0x2d, 0x5e, 0x2e, 0x46, 0x57, + 0x21, 0x0e, 0x2e, 0x96, 0x28, 0xd7, 0x20, 0x7f, 0x01, 0x06, 0x27, 0xd7, 0x28, 0xe7, 0xf4, 0xcc, + 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xf4, 0xfc, 0x9c, 0xc4, 0xbc, 0x74, 0x7d, + 0xb0, 0x39, 0x49, 0xa5, 0x69, 0x10, 0x46, 0xb2, 0x6e, 0x7a, 0x6a, 0x9e, 0x6e, 0x7a, 0xbe, 0x3e, + 0xc8, 0xe0, 0x94, 0xc4, 0x92, 0x44, 0x7d, 0x0c, 0x67, 0x25, 0xb1, 0x81, 0x55, 0x1a, 0x03, 0x02, + 0x00, 0x00, 0xff, 0xff, 0x81, 0xcc, 0x07, 0x7d, 0xed, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/a.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/a.proto new file mode 100644 index 00000000..4494c818 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/a.proto @@ -0,0 +1,47 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package goproto.test.import_public.sub; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub"; + +import "import_public/sub/b.proto"; + +message M { + // Field using a type in the same Go package, but a different source file. + M2 m2 = 1; +} + +enum E { + ZERO = 0; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/b.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/b.pb.go new file mode 100644 index 00000000..d57a3bb9 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/b.pb.go @@ -0,0 +1,67 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: import_public/sub/b.proto + +package sub // import "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M2 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M2) Reset() { *m = M2{} } +func (m *M2) String() string { return proto.CompactTextString(m) } +func (*M2) ProtoMessage() {} +func (*M2) Descriptor() ([]byte, []int) { + return fileDescriptor_b_eba25180453d86b4, []int{0} +} +func (m *M2) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M2.Unmarshal(m, b) +} +func (m *M2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M2.Marshal(b, m, deterministic) +} +func (dst *M2) XXX_Merge(src proto.Message) { + xxx_messageInfo_M2.Merge(dst, src) +} +func (m *M2) XXX_Size() int { + return xxx_messageInfo_M2.Size(m) +} +func (m *M2) XXX_DiscardUnknown() { + xxx_messageInfo_M2.DiscardUnknown(m) +} + +var xxx_messageInfo_M2 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M2)(nil), "goproto.test.import_public.sub.M2") +} + +func init() { proto.RegisterFile("import_public/sub/b.proto", fileDescriptor_b_eba25180453d86b4) } + +var fileDescriptor_b_eba25180453d86b4 = []byte{ + // 127 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x89, 0x2f, 0x28, 0x4d, 0xca, 0xc9, 0x4c, 0xd6, 0x2f, 0x2e, 0x4d, 0xd2, 0x4f, 0xd2, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x4b, 0xcf, 0x07, 0x33, 0xf4, 0x4a, 0x52, 0x8b, 0x4b, + 0xf4, 0x50, 0xd4, 0xe9, 0x15, 0x97, 0x26, 0x29, 0xb1, 0x70, 0x31, 0xf9, 0x1a, 0x39, 0xb9, 0x46, + 0x39, 0xa7, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xe7, 0x24, + 0xe6, 0xa5, 0xeb, 0x83, 0xf5, 0x25, 0x95, 0xa6, 0x41, 0x18, 0xc9, 0xba, 0xe9, 0xa9, 0x79, 0xba, + 0xe9, 0xf9, 0xfa, 0x20, 0x83, 0x52, 0x12, 0x4b, 0x12, 0xf5, 0x31, 0x2c, 0x4d, 0x62, 0x03, 0xab, + 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x64, 0x42, 0xe4, 0xa8, 0x90, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/b.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/b.proto new file mode 100644 index 00000000..c7299e0f --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub/b.proto @@ -0,0 +1,39 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package goproto.test.import_public.sub; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub"; + +message M2 { +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public_test.go similarity index 69% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public_test.go index 156e078d..7ef776bf 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/import_public_test.go @@ -29,42 +29,38 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -syntax = "proto2"; +// +build go1.9 -package imp; +package testdata -import "imp2.proto"; -import "imp3.proto"; +import ( + "testing" -message ImportedMessage { - required int64 field = 1; + mainpb "github.com/golang/protobuf/protoc-gen-go/testdata/import_public" + subpb "github.com/golang/protobuf/protoc-gen-go/testdata/import_public/sub" +) - // The forwarded getters for these fields are fiddly to get right. - optional ImportedMessage2 local_msg = 2; - optional ForeignImportedMessage foreign_msg = 3; // in imp3.proto - optional Owner enum_field = 4; - oneof union { - int32 state = 9; - } - - repeated string name = 5; - repeated Owner boss = 6; - repeated ImportedMessage2 memo = 7; - - map msg_map = 8; - - enum Owner { - DAVE = 1; - MIKE = 2; - } - - extensions 90 to 100; -} - -message ImportedMessage2 { -} - -message ImportedExtendable { - option message_set_wire_format = true; - extensions 100 to max; +func TestImportPublicLink(t *testing.T) { + // mainpb.[ME] should be interchangable with subpb.[ME]. + var _ mainpb.M = subpb.M{} + var _ mainpb.E = subpb.E(0) + _ = &mainpb.Public{ + M: &mainpb.M{}, + E: mainpb.E_ZERO, + Local: &mainpb.Local{ + M: &mainpb.M{}, + E: mainpb.E_ZERO, + }, + } + _ = &mainpb.Public{ + M: &subpb.M{}, + E: subpb.E_ZERO, + Local: &mainpb.Local{ + M: &subpb.M{}, + E: subpb.E_ZERO, + }, + } + _ = &mainpb.M{ + M2: &subpb.M2{}, + } } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt/m.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt/m.pb.go new file mode 100644 index 00000000..ca312d6c --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt/m.pb.go @@ -0,0 +1,66 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/fmt/m.proto + +package fmt // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M) Reset() { *m = M{} } +func (m *M) String() string { return proto.CompactTextString(m) } +func (*M) ProtoMessage() {} +func (*M) Descriptor() ([]byte, []int) { + return fileDescriptor_m_867dd34c461422b8, []int{0} +} +func (m *M) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M.Unmarshal(m, b) +} +func (m *M) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M.Marshal(b, m, deterministic) +} +func (dst *M) XXX_Merge(src proto.Message) { + xxx_messageInfo_M.Merge(dst, src) +} +func (m *M) XXX_Size() int { + return xxx_messageInfo_M.Size(m) +} +func (m *M) XXX_DiscardUnknown() { + xxx_messageInfo_M.DiscardUnknown(m) +} + +var xxx_messageInfo_M proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M)(nil), "fmt.M") +} + +func init() { proto.RegisterFile("imports/fmt/m.proto", fileDescriptor_m_867dd34c461422b8) } + +var fileDescriptor_m_867dd34c461422b8 = []byte{ + // 109 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xce, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x4f, 0xcb, 0x2d, 0xd1, 0xcf, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, + 0x62, 0x4e, 0xcb, 0x2d, 0x51, 0x62, 0xe6, 0x62, 0xf4, 0x75, 0xb2, 0x8f, 0xb2, 0x4d, 0xcf, 0x2c, + 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, 0x4b, 0xd7, 0x07, + 0x2b, 0x4a, 0x2a, 0x4d, 0x83, 0x30, 0x92, 0x75, 0xd3, 0x53, 0xf3, 0x74, 0xd3, 0xf3, 0xf5, 0x4b, + 0x52, 0x8b, 0x4b, 0x52, 0x12, 0x4b, 0x12, 0xf5, 0x91, 0x8c, 0x4c, 0x62, 0x03, 0xab, 0x31, 0x06, + 0x04, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xc9, 0xee, 0xbe, 0x68, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp3.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt/m.proto similarity index 89% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp3.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt/m.proto index 58fc7598..142d8cfa 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp3.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt/m.proto @@ -1,6 +1,6 @@ // Go support for Protocol Buffers - Google's data interchange format // -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2018 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without @@ -29,10 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -syntax = "proto2"; - -package imp; - -message ForeignImportedMessage { - optional string tuber = 1; -} +syntax = "proto3"; +package fmt; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt"; +message M {} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go new file mode 100644 index 00000000..963f7c72 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go @@ -0,0 +1,130 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_a_1/m1.proto + +package test_a_1 // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type E1 int32 + +const ( + E1_E1_ZERO E1 = 0 +) + +var E1_name = map[int32]string{ + 0: "E1_ZERO", +} +var E1_value = map[string]int32{ + "E1_ZERO": 0, +} + +func (x E1) String() string { + return proto.EnumName(E1_name, int32(x)) +} +func (E1) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_m1_56a2598431d21e61, []int{0} +} + +type M1 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M1) Reset() { *m = M1{} } +func (m *M1) String() string { return proto.CompactTextString(m) } +func (*M1) ProtoMessage() {} +func (*M1) Descriptor() ([]byte, []int) { + return fileDescriptor_m1_56a2598431d21e61, []int{0} +} +func (m *M1) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M1.Unmarshal(m, b) +} +func (m *M1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M1.Marshal(b, m, deterministic) +} +func (dst *M1) XXX_Merge(src proto.Message) { + xxx_messageInfo_M1.Merge(dst, src) +} +func (m *M1) XXX_Size() int { + return xxx_messageInfo_M1.Size(m) +} +func (m *M1) XXX_DiscardUnknown() { + xxx_messageInfo_M1.DiscardUnknown(m) +} + +var xxx_messageInfo_M1 proto.InternalMessageInfo + +type M1_1 struct { + M1 *M1 `protobuf:"bytes,1,opt,name=m1,proto3" json:"m1,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M1_1) Reset() { *m = M1_1{} } +func (m *M1_1) String() string { return proto.CompactTextString(m) } +func (*M1_1) ProtoMessage() {} +func (*M1_1) Descriptor() ([]byte, []int) { + return fileDescriptor_m1_56a2598431d21e61, []int{1} +} +func (m *M1_1) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M1_1.Unmarshal(m, b) +} +func (m *M1_1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M1_1.Marshal(b, m, deterministic) +} +func (dst *M1_1) XXX_Merge(src proto.Message) { + xxx_messageInfo_M1_1.Merge(dst, src) +} +func (m *M1_1) XXX_Size() int { + return xxx_messageInfo_M1_1.Size(m) +} +func (m *M1_1) XXX_DiscardUnknown() { + xxx_messageInfo_M1_1.DiscardUnknown(m) +} + +var xxx_messageInfo_M1_1 proto.InternalMessageInfo + +func (m *M1_1) GetM1() *M1 { + if m != nil { + return m.M1 + } + return nil +} + +func init() { + proto.RegisterType((*M1)(nil), "test.a.M1") + proto.RegisterType((*M1_1)(nil), "test.a.M1_1") + proto.RegisterEnum("test.a.E1", E1_name, E1_value) +} + +func init() { proto.RegisterFile("imports/test_a_1/m1.proto", fileDescriptor_m1_56a2598431d21e61) } + +var fileDescriptor_m1_56a2598431d21e61 = []byte{ + // 165 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x4f, 0x8c, 0x37, 0xd4, 0xcf, 0x35, 0xd4, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0x09, 0xe9, 0x25, 0x2a, 0xb1, 0x70, 0x31, 0xf9, + 0x1a, 0x2a, 0x29, 0x71, 0xb1, 0xf8, 0x1a, 0xc6, 0x1b, 0x0a, 0x49, 0x71, 0x31, 0xe5, 0x1a, 0x4a, + 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x71, 0xe9, 0x41, 0x94, 0xe8, 0xf9, 0x1a, 0x06, 0x31, 0xe5, + 0x1a, 0x6a, 0x09, 0x72, 0x31, 0xb9, 0x1a, 0x0a, 0x71, 0x73, 0xb1, 0xbb, 0x1a, 0xc6, 0x47, 0xb9, + 0x06, 0xf9, 0x0b, 0x30, 0x38, 0xb9, 0x44, 0x39, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, + 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, 0xeb, 0x83, 0xcd, 0x4f, 0x2a, 0x4d, 0x83, + 0x30, 0x92, 0x75, 0xd3, 0x53, 0xf3, 0x74, 0xd3, 0xf3, 0xc1, 0x4e, 0x48, 0x49, 0x2c, 0x49, 0xd4, + 0x47, 0x77, 0x53, 0x12, 0x1b, 0x58, 0xa1, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xae, 0xc9, + 0xcd, 0xae, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m1.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m1.proto new file mode 100644 index 00000000..da54c1ee --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m1.proto @@ -0,0 +1,44 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; +package test.a; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1"; + +message M1 {} + +message M1_1 { + M1 m1 = 1; +} + +enum E1 { + E1_ZERO = 0; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go new file mode 100644 index 00000000..1b629bf3 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go @@ -0,0 +1,67 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_a_1/m2.proto + +package test_a_1 // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M2 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M2) Reset() { *m = M2{} } +func (m *M2) String() string { return proto.CompactTextString(m) } +func (*M2) ProtoMessage() {} +func (*M2) Descriptor() ([]byte, []int) { + return fileDescriptor_m2_ccd6356c045a9ac3, []int{0} +} +func (m *M2) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M2.Unmarshal(m, b) +} +func (m *M2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M2.Marshal(b, m, deterministic) +} +func (dst *M2) XXX_Merge(src proto.Message) { + xxx_messageInfo_M2.Merge(dst, src) +} +func (m *M2) XXX_Size() int { + return xxx_messageInfo_M2.Size(m) +} +func (m *M2) XXX_DiscardUnknown() { + xxx_messageInfo_M2.DiscardUnknown(m) +} + +var xxx_messageInfo_M2 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M2)(nil), "test.a.M2") +} + +func init() { proto.RegisterFile("imports/test_a_1/m2.proto", fileDescriptor_m2_ccd6356c045a9ac3) } + +var fileDescriptor_m2_ccd6356c045a9ac3 = []byte{ + // 114 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x4f, 0x8c, 0x37, 0xd4, 0xcf, 0x35, 0xd2, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0x09, 0xe9, 0x25, 0x2a, 0xb1, 0x70, 0x31, 0xf9, + 0x1a, 0x39, 0xb9, 0x44, 0x39, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, + 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, 0xeb, 0x83, 0x15, 0x26, 0x95, 0xa6, 0x41, 0x18, 0xc9, 0xba, + 0xe9, 0xa9, 0x79, 0xba, 0xe9, 0xf9, 0x60, 0xb3, 0x52, 0x12, 0x4b, 0x12, 0xf5, 0xd1, 0x0d, 0x4f, + 0x62, 0x03, 0x2b, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xe0, 0x7e, 0xc0, 0x77, 0x00, + 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp2.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m2.proto similarity index 88% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp2.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m2.proto index 3bb0632b..49499dc9 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imp2.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1/m2.proto @@ -1,6 +1,6 @@ // Go support for Protocol Buffers - Google's data interchange format // -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2018 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without @@ -29,15 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -syntax = "proto2"; - -package imp; - -message PubliclyImportedMessage { - optional int64 field = 1; -} - -enum PubliclyImportedEnum { - GLASSES = 1; - HAIR = 2; -} +syntax = "proto3"; +package test.a; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1"; +message M2 {} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go new file mode 100644 index 00000000..e3895d2b --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go @@ -0,0 +1,67 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_a_2/m3.proto + +package test_a_2 // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M3 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M3) Reset() { *m = M3{} } +func (m *M3) String() string { return proto.CompactTextString(m) } +func (*M3) ProtoMessage() {} +func (*M3) Descriptor() ([]byte, []int) { + return fileDescriptor_m3_de310e87d08d4216, []int{0} +} +func (m *M3) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M3.Unmarshal(m, b) +} +func (m *M3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M3.Marshal(b, m, deterministic) +} +func (dst *M3) XXX_Merge(src proto.Message) { + xxx_messageInfo_M3.Merge(dst, src) +} +func (m *M3) XXX_Size() int { + return xxx_messageInfo_M3.Size(m) +} +func (m *M3) XXX_DiscardUnknown() { + xxx_messageInfo_M3.DiscardUnknown(m) +} + +var xxx_messageInfo_M3 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M3)(nil), "test.a.M3") +} + +func init() { proto.RegisterFile("imports/test_a_2/m3.proto", fileDescriptor_m3_de310e87d08d4216) } + +var fileDescriptor_m3_de310e87d08d4216 = []byte{ + // 114 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x4f, 0x8c, 0x37, 0xd2, 0xcf, 0x35, 0xd6, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0x09, 0xe9, 0x25, 0x2a, 0xb1, 0x70, 0x31, 0xf9, + 0x1a, 0x3b, 0xb9, 0x44, 0x39, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, + 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, 0xeb, 0x83, 0x15, 0x26, 0x95, 0xa6, 0x41, 0x18, 0xc9, 0xba, + 0xe9, 0xa9, 0x79, 0xba, 0xe9, 0xf9, 0x60, 0xb3, 0x52, 0x12, 0x4b, 0x12, 0xf5, 0xd1, 0x0d, 0x4f, + 0x62, 0x03, 0x2b, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x23, 0x86, 0x27, 0x47, 0x77, 0x00, + 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m3.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m3.proto new file mode 100644 index 00000000..5e811ef8 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m3.proto @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; +package test.a; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2"; +message M3 {} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go new file mode 100644 index 00000000..65a3bad2 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go @@ -0,0 +1,67 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_a_2/m4.proto + +package test_a_2 // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M4 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M4) Reset() { *m = M4{} } +func (m *M4) String() string { return proto.CompactTextString(m) } +func (*M4) ProtoMessage() {} +func (*M4) Descriptor() ([]byte, []int) { + return fileDescriptor_m4_da12b386229f3791, []int{0} +} +func (m *M4) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M4.Unmarshal(m, b) +} +func (m *M4) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M4.Marshal(b, m, deterministic) +} +func (dst *M4) XXX_Merge(src proto.Message) { + xxx_messageInfo_M4.Merge(dst, src) +} +func (m *M4) XXX_Size() int { + return xxx_messageInfo_M4.Size(m) +} +func (m *M4) XXX_DiscardUnknown() { + xxx_messageInfo_M4.DiscardUnknown(m) +} + +var xxx_messageInfo_M4 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M4)(nil), "test.a.M4") +} + +func init() { proto.RegisterFile("imports/test_a_2/m4.proto", fileDescriptor_m4_da12b386229f3791) } + +var fileDescriptor_m4_da12b386229f3791 = []byte{ + // 114 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x4f, 0x8c, 0x37, 0xd2, 0xcf, 0x35, 0xd1, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0x09, 0xe9, 0x25, 0x2a, 0xb1, 0x70, 0x31, 0xf9, + 0x9a, 0x38, 0xb9, 0x44, 0x39, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, + 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, 0xeb, 0x83, 0x15, 0x26, 0x95, 0xa6, 0x41, 0x18, 0xc9, 0xba, + 0xe9, 0xa9, 0x79, 0xba, 0xe9, 0xf9, 0x60, 0xb3, 0x52, 0x12, 0x4b, 0x12, 0xf5, 0xd1, 0x0d, 0x4f, + 0x62, 0x03, 0x2b, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x58, 0xcb, 0x10, 0xc8, 0x77, 0x00, + 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m4.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m4.proto new file mode 100644 index 00000000..8f8fe3e1 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2/m4.proto @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; +package test.a; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2"; +message M4 {} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go new file mode 100644 index 00000000..831f4149 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go @@ -0,0 +1,67 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_b_1/m1.proto + +package beta // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M1 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M1) Reset() { *m = M1{} } +func (m *M1) String() string { return proto.CompactTextString(m) } +func (*M1) ProtoMessage() {} +func (*M1) Descriptor() ([]byte, []int) { + return fileDescriptor_m1_aff127b054aec649, []int{0} +} +func (m *M1) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M1.Unmarshal(m, b) +} +func (m *M1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M1.Marshal(b, m, deterministic) +} +func (dst *M1) XXX_Merge(src proto.Message) { + xxx_messageInfo_M1.Merge(dst, src) +} +func (m *M1) XXX_Size() int { + return xxx_messageInfo_M1.Size(m) +} +func (m *M1) XXX_DiscardUnknown() { + xxx_messageInfo_M1.DiscardUnknown(m) +} + +var xxx_messageInfo_M1 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M1)(nil), "test.b.part1.M1") +} + +func init() { proto.RegisterFile("imports/test_b_1/m1.proto", fileDescriptor_m1_aff127b054aec649) } + +var fileDescriptor_m1_aff127b054aec649 = []byte{ + // 125 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x4f, 0x8a, 0x37, 0xd4, 0xcf, 0x35, 0xd4, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x01, 0x09, 0xe9, 0x25, 0xe9, 0x15, 0x24, 0x16, 0x95, + 0x18, 0x2a, 0xb1, 0x70, 0x31, 0xf9, 0x1a, 0x3a, 0x79, 0x46, 0xb9, 0xa7, 0x67, 0x96, 0x64, 0x94, + 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, 0xeb, 0x83, 0x95, 0x27, + 0x95, 0xa6, 0x41, 0x18, 0xc9, 0xba, 0xe9, 0xa9, 0x79, 0xba, 0xe9, 0xf9, 0x60, 0x13, 0x53, 0x12, + 0x4b, 0x12, 0xf5, 0xd1, 0xad, 0xb0, 0x4e, 0x4a, 0x2d, 0x49, 0x4c, 0x62, 0x03, 0xab, 0x36, 0x06, + 0x04, 0x00, 0x00, 0xff, 0xff, 0x4a, 0xf1, 0x3b, 0x7f, 0x82, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m1.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m1.proto new file mode 100644 index 00000000..2c35ec4a --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m1.proto @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; +package test.b.part1; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1;beta"; +message M1 {} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go new file mode 100644 index 00000000..bc741056 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go @@ -0,0 +1,67 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_b_1/m2.proto + +package beta // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type M2 struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *M2) Reset() { *m = M2{} } +func (m *M2) String() string { return proto.CompactTextString(m) } +func (*M2) ProtoMessage() {} +func (*M2) Descriptor() ([]byte, []int) { + return fileDescriptor_m2_0c59cab35ba1b0d8, []int{0} +} +func (m *M2) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_M2.Unmarshal(m, b) +} +func (m *M2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_M2.Marshal(b, m, deterministic) +} +func (dst *M2) XXX_Merge(src proto.Message) { + xxx_messageInfo_M2.Merge(dst, src) +} +func (m *M2) XXX_Size() int { + return xxx_messageInfo_M2.Size(m) +} +func (m *M2) XXX_DiscardUnknown() { + xxx_messageInfo_M2.DiscardUnknown(m) +} + +var xxx_messageInfo_M2 proto.InternalMessageInfo + +func init() { + proto.RegisterType((*M2)(nil), "test.b.part2.M2") +} + +func init() { proto.RegisterFile("imports/test_b_1/m2.proto", fileDescriptor_m2_0c59cab35ba1b0d8) } + +var fileDescriptor_m2_0c59cab35ba1b0d8 = []byte{ + // 125 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x4f, 0x8a, 0x37, 0xd4, 0xcf, 0x35, 0xd2, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x01, 0x09, 0xe9, 0x25, 0xe9, 0x15, 0x24, 0x16, 0x95, + 0x18, 0x29, 0xb1, 0x70, 0x31, 0xf9, 0x1a, 0x39, 0x79, 0x46, 0xb9, 0xa7, 0x67, 0x96, 0x64, 0x94, + 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, 0xeb, 0x83, 0x95, 0x27, + 0x95, 0xa6, 0x41, 0x18, 0xc9, 0xba, 0xe9, 0xa9, 0x79, 0xba, 0xe9, 0xf9, 0x60, 0x13, 0x53, 0x12, + 0x4b, 0x12, 0xf5, 0xd1, 0xad, 0xb0, 0x4e, 0x4a, 0x2d, 0x49, 0x4c, 0x62, 0x03, 0xab, 0x36, 0x06, + 0x04, 0x00, 0x00, 0xff, 0xff, 0x44, 0x29, 0xbe, 0x6d, 0x82, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m2.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m2.proto new file mode 100644 index 00000000..13723be4 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1/m2.proto @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; +package test.b.part2; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1;beta"; +message M2 {} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go new file mode 100644 index 00000000..4f79694c --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go @@ -0,0 +1,80 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_import_a1m1.proto + +package imports // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import test_a_1 "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type A1M1 struct { + F *test_a_1.M1 `protobuf:"bytes,1,opt,name=f,proto3" json:"f,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *A1M1) Reset() { *m = A1M1{} } +func (m *A1M1) String() string { return proto.CompactTextString(m) } +func (*A1M1) ProtoMessage() {} +func (*A1M1) Descriptor() ([]byte, []int) { + return fileDescriptor_test_import_a1m1_d7f2b5c638a69f6e, []int{0} +} +func (m *A1M1) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_A1M1.Unmarshal(m, b) +} +func (m *A1M1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_A1M1.Marshal(b, m, deterministic) +} +func (dst *A1M1) XXX_Merge(src proto.Message) { + xxx_messageInfo_A1M1.Merge(dst, src) +} +func (m *A1M1) XXX_Size() int { + return xxx_messageInfo_A1M1.Size(m) +} +func (m *A1M1) XXX_DiscardUnknown() { + xxx_messageInfo_A1M1.DiscardUnknown(m) +} + +var xxx_messageInfo_A1M1 proto.InternalMessageInfo + +func (m *A1M1) GetF() *test_a_1.M1 { + if m != nil { + return m.F + } + return nil +} + +func init() { + proto.RegisterType((*A1M1)(nil), "test.A1M1") +} + +func init() { + proto.RegisterFile("imports/test_import_a1m1.proto", fileDescriptor_test_import_a1m1_d7f2b5c638a69f6e) +} + +var fileDescriptor_test_import_a1m1_d7f2b5c638a69f6e = []byte{ + // 149 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcb, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x87, 0x70, 0xe2, 0x13, 0x0d, 0x73, 0x0d, + 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x58, 0x40, 0xe2, 0x52, 0x92, 0x28, 0xaa, 0x12, 0xe3, + 0x0d, 0xf5, 0x61, 0x0a, 0x94, 0x14, 0xb8, 0x58, 0x1c, 0x0d, 0x7d, 0x0d, 0x85, 0x24, 0xb8, 0x18, + 0xd3, 0x24, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0xb8, 0xf4, 0x40, 0xca, 0xf4, 0x12, 0xf5, 0x7c, + 0x0d, 0x83, 0x18, 0xd3, 0x9c, 0xac, 0xa3, 0x2c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, + 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0x73, 0x12, 0xf3, 0xd2, 0xf5, 0xc1, 0x9a, 0x93, 0x4a, 0xd3, 0x20, + 0x8c, 0x64, 0xdd, 0xf4, 0xd4, 0x3c, 0xdd, 0xf4, 0x7c, 0xb0, 0xf9, 0x29, 0x89, 0x25, 0x89, 0xfa, + 0x50, 0x0b, 0x93, 0xd8, 0xc0, 0xf2, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x2f, 0x18, + 0x23, 0xa8, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m1.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m1.proto new file mode 100644 index 00000000..abf07f2a --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m1.proto @@ -0,0 +1,42 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package test; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports"; + +import "imports/test_a_1/m1.proto"; + +message A1M1 { + test.a.M1 f = 1; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go new file mode 100644 index 00000000..f5aa2e82 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go @@ -0,0 +1,80 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_import_a1m2.proto + +package imports // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import test_a_1 "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type A1M2 struct { + F *test_a_1.M2 `protobuf:"bytes,1,opt,name=f,proto3" json:"f,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *A1M2) Reset() { *m = A1M2{} } +func (m *A1M2) String() string { return proto.CompactTextString(m) } +func (*A1M2) ProtoMessage() {} +func (*A1M2) Descriptor() ([]byte, []int) { + return fileDescriptor_test_import_a1m2_9a3281ce9464e116, []int{0} +} +func (m *A1M2) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_A1M2.Unmarshal(m, b) +} +func (m *A1M2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_A1M2.Marshal(b, m, deterministic) +} +func (dst *A1M2) XXX_Merge(src proto.Message) { + xxx_messageInfo_A1M2.Merge(dst, src) +} +func (m *A1M2) XXX_Size() int { + return xxx_messageInfo_A1M2.Size(m) +} +func (m *A1M2) XXX_DiscardUnknown() { + xxx_messageInfo_A1M2.DiscardUnknown(m) +} + +var xxx_messageInfo_A1M2 proto.InternalMessageInfo + +func (m *A1M2) GetF() *test_a_1.M2 { + if m != nil { + return m.F + } + return nil +} + +func init() { + proto.RegisterType((*A1M2)(nil), "test.A1M2") +} + +func init() { + proto.RegisterFile("imports/test_import_a1m2.proto", fileDescriptor_test_import_a1m2_9a3281ce9464e116) +} + +var fileDescriptor_test_import_a1m2_9a3281ce9464e116 = []byte{ + // 149 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcb, 0xcc, 0x2d, 0xc8, + 0x2f, 0x2a, 0x29, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x89, 0x87, 0x70, 0xe2, 0x13, 0x0d, 0x73, 0x8d, + 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x58, 0x40, 0xe2, 0x52, 0x92, 0x28, 0xaa, 0x12, 0xe3, + 0x0d, 0xf5, 0x61, 0x0a, 0x94, 0x14, 0xb8, 0x58, 0x1c, 0x0d, 0x7d, 0x8d, 0x84, 0x24, 0xb8, 0x18, + 0xd3, 0x24, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0xb8, 0xf4, 0x40, 0xca, 0xf4, 0x12, 0xf5, 0x7c, + 0x8d, 0x82, 0x18, 0xd3, 0x9c, 0xac, 0xa3, 0x2c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, + 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0x73, 0x12, 0xf3, 0xd2, 0xf5, 0xc1, 0x9a, 0x93, 0x4a, 0xd3, 0x20, + 0x8c, 0x64, 0xdd, 0xf4, 0xd4, 0x3c, 0xdd, 0xf4, 0x7c, 0xb0, 0xf9, 0x29, 0x89, 0x25, 0x89, 0xfa, + 0x50, 0x0b, 0x93, 0xd8, 0xc0, 0xf2, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x88, 0xfb, + 0xea, 0xa8, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m2.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m2.proto new file mode 100644 index 00000000..5c53950d --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_a1m2.proto @@ -0,0 +1,42 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package test; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports"; + +import "imports/test_a_1/m2.proto"; + +message A1M2 { + test.a.M2 f = 1; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_all.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_all.pb.go new file mode 100644 index 00000000..4f9fd046 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_all.pb.go @@ -0,0 +1,138 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: imports/test_import_all.proto + +package imports // import "github.com/golang/protobuf/protoc-gen-go/testdata/imports" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import fmt1 "github.com/golang/protobuf/protoc-gen-go/testdata/imports/fmt" +import test_a_1 "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_1" +import test_a_2 "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_a_2" +import test_b_1 "github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_b_1" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type All struct { + Am1 *test_a_1.M1 `protobuf:"bytes,1,opt,name=am1,proto3" json:"am1,omitempty"` + Am2 *test_a_1.M2 `protobuf:"bytes,2,opt,name=am2,proto3" json:"am2,omitempty"` + Am3 *test_a_2.M3 `protobuf:"bytes,3,opt,name=am3,proto3" json:"am3,omitempty"` + Am4 *test_a_2.M4 `protobuf:"bytes,4,opt,name=am4,proto3" json:"am4,omitempty"` + Bm1 *test_b_1.M1 `protobuf:"bytes,5,opt,name=bm1,proto3" json:"bm1,omitempty"` + Bm2 *test_b_1.M2 `protobuf:"bytes,6,opt,name=bm2,proto3" json:"bm2,omitempty"` + Fmt *fmt1.M `protobuf:"bytes,7,opt,name=fmt,proto3" json:"fmt,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *All) Reset() { *m = All{} } +func (m *All) String() string { return proto.CompactTextString(m) } +func (*All) ProtoMessage() {} +func (*All) Descriptor() ([]byte, []int) { + return fileDescriptor_test_import_all_b41dc4592e4a4f3b, []int{0} +} +func (m *All) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_All.Unmarshal(m, b) +} +func (m *All) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_All.Marshal(b, m, deterministic) +} +func (dst *All) XXX_Merge(src proto.Message) { + xxx_messageInfo_All.Merge(dst, src) +} +func (m *All) XXX_Size() int { + return xxx_messageInfo_All.Size(m) +} +func (m *All) XXX_DiscardUnknown() { + xxx_messageInfo_All.DiscardUnknown(m) +} + +var xxx_messageInfo_All proto.InternalMessageInfo + +func (m *All) GetAm1() *test_a_1.M1 { + if m != nil { + return m.Am1 + } + return nil +} + +func (m *All) GetAm2() *test_a_1.M2 { + if m != nil { + return m.Am2 + } + return nil +} + +func (m *All) GetAm3() *test_a_2.M3 { + if m != nil { + return m.Am3 + } + return nil +} + +func (m *All) GetAm4() *test_a_2.M4 { + if m != nil { + return m.Am4 + } + return nil +} + +func (m *All) GetBm1() *test_b_1.M1 { + if m != nil { + return m.Bm1 + } + return nil +} + +func (m *All) GetBm2() *test_b_1.M2 { + if m != nil { + return m.Bm2 + } + return nil +} + +func (m *All) GetFmt() *fmt1.M { + if m != nil { + return m.Fmt + } + return nil +} + +func init() { + proto.RegisterType((*All)(nil), "test.All") +} + +func init() { + proto.RegisterFile("imports/test_import_all.proto", fileDescriptor_test_import_all_b41dc4592e4a4f3b) +} + +var fileDescriptor_test_import_all_b41dc4592e4a4f3b = []byte{ + // 258 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0xd0, 0xb1, 0x4e, 0xc3, 0x30, + 0x10, 0x06, 0x60, 0x15, 0x97, 0x20, 0x99, 0x05, 0x85, 0xc5, 0x20, 0x90, 0x50, 0x27, 0x96, 0xda, + 0xb2, 0x9d, 0x05, 0x31, 0xc1, 0xde, 0xa5, 0x23, 0x4b, 0x64, 0x97, 0xc6, 0x54, 0xf2, 0xd5, 0x51, + 0x7a, 0x7d, 0x5e, 0x5e, 0x05, 0xd9, 0x07, 0x12, 0x84, 0x66, 0x4b, 0xfe, 0xef, 0xb7, 0xce, 0x3e, + 0x7e, 0xbf, 0x83, 0x3e, 0x0d, 0x78, 0x50, 0xb8, 0x3d, 0x60, 0x4b, 0x3f, 0xad, 0x8b, 0x51, 0xf6, + 0x43, 0xc2, 0x54, 0xcf, 0x73, 0x7c, 0x7b, 0xf3, 0xa7, 0xe4, 0x5a, 0xad, 0x40, 0x53, 0xe1, 0x14, + 0x99, 0x09, 0x32, 0x0a, 0xec, 0x34, 0x35, 0x27, 0xc9, 0x4f, 0xcf, 0xf2, 0xbf, 0x67, 0x5d, 0xff, + 0x50, 0x07, 0xa8, 0x80, 0xc2, 0xc5, 0xe7, 0x8c, 0xb3, 0x97, 0x18, 0xeb, 0x3b, 0xce, 0x1c, 0x68, + 0x31, 0x7b, 0x98, 0x3d, 0x5e, 0x1a, 0x2e, 0xf3, 0x69, 0xe9, 0xe4, 0x4a, 0xaf, 0x73, 0x4c, 0x6a, + 0xc4, 0xd9, 0x48, 0x4d, 0x56, 0x43, 0x6a, 0x05, 0x1b, 0xa9, 0xcd, 0x6a, 0x49, 0x1b, 0x31, 0x1f, + 0x69, 0x93, 0xb5, 0xa9, 0x17, 0x9c, 0x79, 0xd0, 0xe2, 0xbc, 0xe8, 0x15, 0xa9, 0x97, 0xbd, 0x1b, + 0x50, 0x97, 0xe9, 0x1e, 0x34, 0x75, 0x8c, 0xa8, 0xfe, 0x77, 0x4c, 0xb9, 0x83, 0x07, 0x53, 0x0b, + 0xce, 0x3a, 0x40, 0x71, 0x51, 0x3a, 0x95, 0xec, 0x00, 0xe5, 0x6a, 0x9d, 0xa3, 0xd7, 0xe7, 0xb7, + 0xa7, 0xb0, 0xc3, 0x8f, 0xa3, 0x97, 0x9b, 0x04, 0x2a, 0xa4, 0xe8, 0xf6, 0x41, 0x95, 0xc7, 0xfb, + 0x63, 0x47, 0x1f, 0x9b, 0x65, 0xd8, 0xee, 0x97, 0x21, 0x95, 0xa5, 0xbd, 0x3b, 0x74, 0xea, 0x7b, + 0x55, 0xbe, 0x2a, 0x6e, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x95, 0x39, 0xa3, 0x82, 0x03, 0x02, + 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_all.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_all.proto new file mode 100644 index 00000000..582d722e --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/imports/test_import_all.proto @@ -0,0 +1,58 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package test; + +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/imports"; + +// test_a_1/m*.proto are in the same Go package and proto package. +// test_a_*/*.proto are in different Go packages, but the same proto package. +// test_b_1/*.proto are in the same Go package, but different proto packages. +// fmt/m.proto has a package name which conflicts with "fmt". +import "imports/test_a_1/m1.proto"; +import "imports/test_a_1/m2.proto"; +import "imports/test_a_2/m3.proto"; +import "imports/test_a_2/m4.proto"; +import "imports/test_b_1/m1.proto"; +import "imports/test_b_1/m2.proto"; +import "imports/fmt/m.proto"; + +message All { + test.a.M1 am1 = 1; + test.a.M2 am2 = 2; + test.a.M3 am3 = 3; + test.a.M4 am4 = 4; + test.b.part1.M1 bm1 = 5; + test.b.part2.M2 bm2 = 6; + fmt.M fmt = 7; +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/main_test.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/main_test.go index f9b5ccf2..7ec1f2db 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/main_test.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/main_test.go @@ -36,11 +36,13 @@ package testdata import ( "testing" - mytestpb "./my_test" + importspb "github.com/golang/protobuf/protoc-gen-go/testdata/imports" multipb "github.com/golang/protobuf/protoc-gen-go/testdata/multi" + mytestpb "github.com/golang/protobuf/protoc-gen-go/testdata/my_test" ) func TestLink(t *testing.T) { _ = &multipb.Multi1{} _ = &mytestpb.Request{} + _ = &importspb.All{} } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.pb.go new file mode 100644 index 00000000..da0fdf8f --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.pb.go @@ -0,0 +1,96 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: multi/multi1.proto + +package multitest // import "github.com/golang/protobuf/protoc-gen-go/testdata/multi" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Multi1 struct { + Multi2 *Multi2 `protobuf:"bytes,1,req,name=multi2" json:"multi2,omitempty"` + Color *Multi2_Color `protobuf:"varint,2,opt,name=color,enum=multitest.Multi2_Color" json:"color,omitempty"` + HatType *Multi3_HatType `protobuf:"varint,3,opt,name=hat_type,json=hatType,enum=multitest.Multi3_HatType" json:"hat_type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Multi1) Reset() { *m = Multi1{} } +func (m *Multi1) String() string { return proto.CompactTextString(m) } +func (*Multi1) ProtoMessage() {} +func (*Multi1) Descriptor() ([]byte, []int) { + return fileDescriptor_multi1_08e50c6822e808b8, []int{0} +} +func (m *Multi1) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Multi1.Unmarshal(m, b) +} +func (m *Multi1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Multi1.Marshal(b, m, deterministic) +} +func (dst *Multi1) XXX_Merge(src proto.Message) { + xxx_messageInfo_Multi1.Merge(dst, src) +} +func (m *Multi1) XXX_Size() int { + return xxx_messageInfo_Multi1.Size(m) +} +func (m *Multi1) XXX_DiscardUnknown() { + xxx_messageInfo_Multi1.DiscardUnknown(m) +} + +var xxx_messageInfo_Multi1 proto.InternalMessageInfo + +func (m *Multi1) GetMulti2() *Multi2 { + if m != nil { + return m.Multi2 + } + return nil +} + +func (m *Multi1) GetColor() Multi2_Color { + if m != nil && m.Color != nil { + return *m.Color + } + return Multi2_BLUE +} + +func (m *Multi1) GetHatType() Multi3_HatType { + if m != nil && m.HatType != nil { + return *m.HatType + } + return Multi3_FEDORA +} + +func init() { + proto.RegisterType((*Multi1)(nil), "multitest.Multi1") +} + +func init() { proto.RegisterFile("multi/multi1.proto", fileDescriptor_multi1_08e50c6822e808b8) } + +var fileDescriptor_multi1_08e50c6822e808b8 = []byte{ + // 200 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xca, 0x2d, 0xcd, 0x29, + 0xc9, 0xd4, 0x07, 0x93, 0x86, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x9c, 0x60, 0x5e, 0x49, + 0x6a, 0x71, 0x89, 0x14, 0xb2, 0xb4, 0x11, 0x44, 0x1a, 0x45, 0xcc, 0x18, 0x22, 0xa6, 0x34, 0x83, + 0x91, 0x8b, 0xcd, 0x17, 0x6c, 0x86, 0x90, 0x26, 0x17, 0x1b, 0x44, 0xb9, 0x04, 0xa3, 0x02, 0x93, + 0x06, 0xb7, 0x91, 0xa0, 0x1e, 0xdc, 0x38, 0x3d, 0xb0, 0x12, 0xa3, 0x20, 0xa8, 0x02, 0x21, 0x5d, + 0x2e, 0xd6, 0xe4, 0xfc, 0x9c, 0xfc, 0x22, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x3e, 0x23, 0x71, 0x0c, + 0x95, 0x7a, 0xce, 0x20, 0xe9, 0x20, 0x88, 0x2a, 0x21, 0x13, 0x2e, 0x8e, 0x8c, 0xc4, 0x92, 0xf8, + 0x92, 0xca, 0x82, 0x54, 0x09, 0x66, 0xb0, 0x0e, 0x49, 0x74, 0x1d, 0xc6, 0x7a, 0x1e, 0x89, 0x25, + 0x21, 0x95, 0x05, 0xa9, 0x41, 0xec, 0x19, 0x10, 0x86, 0x93, 0x73, 0x94, 0x63, 0x7a, 0x66, 0x49, + 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e, 0xba, 0x3e, 0xd8, + 0xd5, 0x49, 0xa5, 0x69, 0x10, 0x46, 0xb2, 0x6e, 0x7a, 0x6a, 0x9e, 0x6e, 0x7a, 0xbe, 0x3e, 0xc8, + 0xa0, 0x94, 0xc4, 0x92, 0x44, 0x88, 0xe7, 0xac, 0xe1, 0x86, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, + 0x60, 0x7d, 0xfc, 0x9f, 0x27, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.proto index 0da6e0af..d3a32041 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi1.proto @@ -36,6 +36,8 @@ import "multi/multi3.proto"; package multitest; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/multi;multitest"; + message Multi1 { required Multi2 multi2 = 1; optional Multi2.Color color = 2; diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.pb.go new file mode 100644 index 00000000..b66ce793 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.pb.go @@ -0,0 +1,128 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: multi/multi2.proto + +package multitest // import "github.com/golang/protobuf/protoc-gen-go/testdata/multi" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Multi2_Color int32 + +const ( + Multi2_BLUE Multi2_Color = 1 + Multi2_GREEN Multi2_Color = 2 + Multi2_RED Multi2_Color = 3 +) + +var Multi2_Color_name = map[int32]string{ + 1: "BLUE", + 2: "GREEN", + 3: "RED", +} +var Multi2_Color_value = map[string]int32{ + "BLUE": 1, + "GREEN": 2, + "RED": 3, +} + +func (x Multi2_Color) Enum() *Multi2_Color { + p := new(Multi2_Color) + *p = x + return p +} +func (x Multi2_Color) String() string { + return proto.EnumName(Multi2_Color_name, int32(x)) +} +func (x *Multi2_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Multi2_Color_value, data, "Multi2_Color") + if err != nil { + return err + } + *x = Multi2_Color(value) + return nil +} +func (Multi2_Color) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_multi2_c47490ad66d93e67, []int{0, 0} +} + +type Multi2 struct { + RequiredValue *int32 `protobuf:"varint,1,req,name=required_value,json=requiredValue" json:"required_value,omitempty"` + Color *Multi2_Color `protobuf:"varint,2,opt,name=color,enum=multitest.Multi2_Color" json:"color,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Multi2) Reset() { *m = Multi2{} } +func (m *Multi2) String() string { return proto.CompactTextString(m) } +func (*Multi2) ProtoMessage() {} +func (*Multi2) Descriptor() ([]byte, []int) { + return fileDescriptor_multi2_c47490ad66d93e67, []int{0} +} +func (m *Multi2) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Multi2.Unmarshal(m, b) +} +func (m *Multi2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Multi2.Marshal(b, m, deterministic) +} +func (dst *Multi2) XXX_Merge(src proto.Message) { + xxx_messageInfo_Multi2.Merge(dst, src) +} +func (m *Multi2) XXX_Size() int { + return xxx_messageInfo_Multi2.Size(m) +} +func (m *Multi2) XXX_DiscardUnknown() { + xxx_messageInfo_Multi2.DiscardUnknown(m) +} + +var xxx_messageInfo_Multi2 proto.InternalMessageInfo + +func (m *Multi2) GetRequiredValue() int32 { + if m != nil && m.RequiredValue != nil { + return *m.RequiredValue + } + return 0 +} + +func (m *Multi2) GetColor() Multi2_Color { + if m != nil && m.Color != nil { + return *m.Color + } + return Multi2_BLUE +} + +func init() { + proto.RegisterType((*Multi2)(nil), "multitest.Multi2") + proto.RegisterEnum("multitest.Multi2_Color", Multi2_Color_name, Multi2_Color_value) +} + +func init() { proto.RegisterFile("multi/multi2.proto", fileDescriptor_multi2_c47490ad66d93e67) } + +var fileDescriptor_multi2_c47490ad66d93e67 = []byte{ + // 202 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xca, 0x2d, 0xcd, 0x29, + 0xc9, 0xd4, 0x07, 0x93, 0x46, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x9c, 0x60, 0x5e, 0x49, + 0x6a, 0x71, 0x89, 0x52, 0x2b, 0x23, 0x17, 0x9b, 0x2f, 0x58, 0x4e, 0x48, 0x95, 0x8b, 0xaf, 0x28, + 0xb5, 0xb0, 0x34, 0xb3, 0x28, 0x35, 0x25, 0xbe, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x82, 0x51, 0x81, + 0x49, 0x83, 0x35, 0x88, 0x17, 0x26, 0x1a, 0x06, 0x12, 0x14, 0xd2, 0xe5, 0x62, 0x4d, 0xce, 0xcf, + 0xc9, 0x2f, 0x92, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x33, 0x12, 0xd7, 0x83, 0x1b, 0xa6, 0x07, 0x31, + 0x48, 0xcf, 0x19, 0x24, 0x1d, 0x04, 0x51, 0xa5, 0xa4, 0xca, 0xc5, 0x0a, 0xe6, 0x0b, 0x71, 0x70, + 0xb1, 0x38, 0xf9, 0x84, 0xba, 0x0a, 0x30, 0x0a, 0x71, 0x72, 0xb1, 0xba, 0x07, 0xb9, 0xba, 0xfa, + 0x09, 0x30, 0x09, 0xb1, 0x73, 0x31, 0x07, 0xb9, 0xba, 0x08, 0x30, 0x3b, 0x39, 0x47, 0x39, 0xa6, + 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, + 0xeb, 0x83, 0x5d, 0x9b, 0x54, 0x9a, 0x06, 0x61, 0x24, 0xeb, 0xa6, 0xa7, 0xe6, 0xe9, 0xa6, 0xe7, + 0xeb, 0x83, 0xec, 0x4a, 0x49, 0x2c, 0x49, 0x84, 0x78, 0xca, 0x1a, 0x6e, 0x3f, 0x20, 0x00, 0x00, + 0xff, 0xff, 0x49, 0x3b, 0x52, 0x44, 0xec, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.proto index e6bfc71b..ec5b431e 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi2.proto @@ -33,6 +33,8 @@ syntax = "proto2"; package multitest; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/multi;multitest"; + message Multi2 { required int32 required_value = 1; diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.pb.go new file mode 100644 index 00000000..f03c350a --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.pb.go @@ -0,0 +1,115 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: multi/multi3.proto + +package multitest // import "github.com/golang/protobuf/protoc-gen-go/testdata/multi" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Multi3_HatType int32 + +const ( + Multi3_FEDORA Multi3_HatType = 1 + Multi3_FEZ Multi3_HatType = 2 +) + +var Multi3_HatType_name = map[int32]string{ + 1: "FEDORA", + 2: "FEZ", +} +var Multi3_HatType_value = map[string]int32{ + "FEDORA": 1, + "FEZ": 2, +} + +func (x Multi3_HatType) Enum() *Multi3_HatType { + p := new(Multi3_HatType) + *p = x + return p +} +func (x Multi3_HatType) String() string { + return proto.EnumName(Multi3_HatType_name, int32(x)) +} +func (x *Multi3_HatType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Multi3_HatType_value, data, "Multi3_HatType") + if err != nil { + return err + } + *x = Multi3_HatType(value) + return nil +} +func (Multi3_HatType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_multi3_d55a72b4628b7875, []int{0, 0} +} + +type Multi3 struct { + HatType *Multi3_HatType `protobuf:"varint,1,opt,name=hat_type,json=hatType,enum=multitest.Multi3_HatType" json:"hat_type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Multi3) Reset() { *m = Multi3{} } +func (m *Multi3) String() string { return proto.CompactTextString(m) } +func (*Multi3) ProtoMessage() {} +func (*Multi3) Descriptor() ([]byte, []int) { + return fileDescriptor_multi3_d55a72b4628b7875, []int{0} +} +func (m *Multi3) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Multi3.Unmarshal(m, b) +} +func (m *Multi3) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Multi3.Marshal(b, m, deterministic) +} +func (dst *Multi3) XXX_Merge(src proto.Message) { + xxx_messageInfo_Multi3.Merge(dst, src) +} +func (m *Multi3) XXX_Size() int { + return xxx_messageInfo_Multi3.Size(m) +} +func (m *Multi3) XXX_DiscardUnknown() { + xxx_messageInfo_Multi3.DiscardUnknown(m) +} + +var xxx_messageInfo_Multi3 proto.InternalMessageInfo + +func (m *Multi3) GetHatType() Multi3_HatType { + if m != nil && m.HatType != nil { + return *m.HatType + } + return Multi3_FEDORA +} + +func init() { + proto.RegisterType((*Multi3)(nil), "multitest.Multi3") + proto.RegisterEnum("multitest.Multi3_HatType", Multi3_HatType_name, Multi3_HatType_value) +} + +func init() { proto.RegisterFile("multi/multi3.proto", fileDescriptor_multi3_d55a72b4628b7875) } + +var fileDescriptor_multi3_d55a72b4628b7875 = []byte{ + // 170 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xca, 0x2d, 0xcd, 0x29, + 0xc9, 0xd4, 0x07, 0x93, 0xc6, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x9c, 0x60, 0x5e, 0x49, + 0x6a, 0x71, 0x89, 0x52, 0x1c, 0x17, 0x9b, 0x2f, 0x58, 0x4a, 0xc8, 0x84, 0x8b, 0x23, 0x23, 0xb1, + 0x24, 0xbe, 0xa4, 0xb2, 0x20, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0xcf, 0x48, 0x52, 0x0f, 0xae, + 0x4e, 0x0f, 0xa2, 0x48, 0xcf, 0x23, 0xb1, 0x24, 0xa4, 0xb2, 0x20, 0x35, 0x88, 0x3d, 0x03, 0xc2, + 0x50, 0x92, 0xe3, 0x62, 0x87, 0x8a, 0x09, 0x71, 0x71, 0xb1, 0xb9, 0xb9, 0xba, 0xf8, 0x07, 0x39, + 0x0a, 0x30, 0x0a, 0xb1, 0x73, 0x31, 0xbb, 0xb9, 0x46, 0x09, 0x30, 0x39, 0x39, 0x47, 0x39, 0xa6, + 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xa7, 0xe7, 0xe7, 0x24, 0xe6, 0xa5, + 0xeb, 0x83, 0x5d, 0x91, 0x54, 0x9a, 0x06, 0x61, 0x24, 0xeb, 0xa6, 0xa7, 0xe6, 0xe9, 0xa6, 0xe7, + 0xeb, 0x83, 0x2c, 0x4a, 0x49, 0x2c, 0x49, 0x84, 0x38, 0xd6, 0x1a, 0x6e, 0x39, 0x20, 0x00, 0x00, + 0xff, 0xff, 0xd5, 0xa4, 0x1a, 0x0e, 0xc4, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.proto index 146c255b..8690b881 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/multi/multi3.proto @@ -33,6 +33,8 @@ syntax = "proto2"; package multitest; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/multi;multitest"; + message Multi3 { enum HatType { FEDORA = 1; diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go index 1954e3fb..a033f8b0 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go @@ -1,24 +1,11 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: my_test/test.proto +package test // import "github.com/golang/protobuf/protoc-gen-go/testdata/my_test" + /* -Package my_test is a generated protocol buffer package. - This package holds interesting messages. - -It is generated from these files: - my_test/test.proto - -It has these top-level messages: - Request - Reply - OtherBase - ReplyExtensions - OtherReplyExtensions - OldReply - Communique */ -package my_test import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -69,6 +56,9 @@ func (x *HatType) UnmarshalJSON(data []byte) error { *x = HatType(value) return nil } +func (HatType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{0} +} // This enum represents days of the week. type Days int32 @@ -106,6 +96,9 @@ func (x *Days) UnmarshalJSON(data []byte) error { *x = Days(value) return nil } +func (Days) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{1} +} type Request_Color int32 @@ -142,6 +135,9 @@ func (x *Request_Color) UnmarshalJSON(data []byte) error { *x = Request_Color(value) return nil } +func (Request_Color) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{0, 0} +} type Reply_Entry_Game int32 @@ -175,6 +171,9 @@ func (x *Reply_Entry_Game) UnmarshalJSON(data []byte) error { *x = Reply_Entry_Game(value) return nil } +func (Reply_Entry_Game) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{1, 0, 0} +} // This is a message that might be sent somewhere. type Request struct { @@ -191,13 +190,35 @@ type Request struct { MsgMapping map[int64]*Reply `protobuf:"bytes,15,rep,name=msg_mapping,json=msgMapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` Reset_ *int32 `protobuf:"varint,12,opt,name=reset" json:"reset,omitempty"` // This field should not conflict with any getters. - GetKey_ *string `protobuf:"bytes,16,opt,name=get_key,json=getKey" json:"get_key,omitempty"` - XXX_unrecognized []byte `json:"-"` + GetKey_ *string `protobuf:"bytes,16,opt,name=get_key,json=getKey" json:"get_key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Request) Reset() { *m = Request{} } func (m *Request) String() string { return proto.CompactTextString(m) } func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{0} +} +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) +} +func (dst *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(dst, src) +} +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo const Default_Request_Hat HatType = HatType_FEDORA @@ -267,13 +288,35 @@ func (m *Request) GetGetKey_() string { } type Request_SomeGroup struct { - GroupField *int32 `protobuf:"varint,9,opt,name=group_field,json=groupField" json:"group_field,omitempty"` - XXX_unrecognized []byte `json:"-"` + GroupField *int32 `protobuf:"varint,9,opt,name=group_field,json=groupField" json:"group_field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Request_SomeGroup) Reset() { *m = Request_SomeGroup{} } func (m *Request_SomeGroup) String() string { return proto.CompactTextString(m) } func (*Request_SomeGroup) ProtoMessage() {} +func (*Request_SomeGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{0, 0} +} +func (m *Request_SomeGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request_SomeGroup.Unmarshal(m, b) +} +func (m *Request_SomeGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request_SomeGroup.Marshal(b, m, deterministic) +} +func (dst *Request_SomeGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request_SomeGroup.Merge(dst, src) +} +func (m *Request_SomeGroup) XXX_Size() int { + return xxx_messageInfo_Request_SomeGroup.Size(m) +} +func (m *Request_SomeGroup) XXX_DiscardUnknown() { + xxx_messageInfo_Request_SomeGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_Request_SomeGroup proto.InternalMessageInfo func (m *Request_SomeGroup) GetGroupField() int32 { if m != nil && m.GroupField != nil { @@ -285,21 +328,43 @@ func (m *Request_SomeGroup) GetGroupField() int32 { type Reply struct { Found []*Reply_Entry `protobuf:"bytes,1,rep,name=found" json:"found,omitempty"` CompactKeys []int32 `protobuf:"varint,2,rep,packed,name=compact_keys,json=compactKeys" json:"compact_keys,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Reply) Reset() { *m = Reply{} } func (m *Reply) String() string { return proto.CompactTextString(m) } func (*Reply) ProtoMessage() {} +func (*Reply) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{1} +} var extRange_Reply = []proto.ExtensionRange{ - {100, 536870911}, + {Start: 100, End: 536870911}, } func (*Reply) ExtensionRangeArray() []proto.ExtensionRange { return extRange_Reply } +func (m *Reply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Reply.Unmarshal(m, b) +} +func (m *Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Reply.Marshal(b, m, deterministic) +} +func (dst *Reply) XXX_Merge(src proto.Message) { + xxx_messageInfo_Reply.Merge(dst, src) +} +func (m *Reply) XXX_Size() int { + return xxx_messageInfo_Reply.Size(m) +} +func (m *Reply) XXX_DiscardUnknown() { + xxx_messageInfo_Reply.DiscardUnknown(m) +} + +var xxx_messageInfo_Reply proto.InternalMessageInfo func (m *Reply) GetFound() []*Reply_Entry { if m != nil { @@ -316,15 +381,37 @@ func (m *Reply) GetCompactKeys() []int32 { } type Reply_Entry struct { - KeyThatNeeds_1234Camel_CasIng *int64 `protobuf:"varint,1,req,name=key_that_needs_1234camel_CasIng,json=keyThatNeeds1234camelCasIng" json:"key_that_needs_1234camel_CasIng,omitempty"` - Value *int64 `protobuf:"varint,2,opt,name=value,def=7" json:"value,omitempty"` - XMyFieldName_2 *int64 `protobuf:"varint,3,opt,name=_my_field_name_2,json=MyFieldName2" json:"_my_field_name_2,omitempty"` - XXX_unrecognized []byte `json:"-"` + KeyThatNeeds_1234Camel_CasIng *int64 `protobuf:"varint,1,req,name=key_that_needs_1234camel_CasIng,json=keyThatNeeds1234camelCasIng" json:"key_that_needs_1234camel_CasIng,omitempty"` + Value *int64 `protobuf:"varint,2,opt,name=value,def=7" json:"value,omitempty"` + XMyFieldName_2 *int64 `protobuf:"varint,3,opt,name=_my_field_name_2,json=MyFieldName2" json:"_my_field_name_2,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Reply_Entry) Reset() { *m = Reply_Entry{} } func (m *Reply_Entry) String() string { return proto.CompactTextString(m) } func (*Reply_Entry) ProtoMessage() {} +func (*Reply_Entry) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{1, 0} +} +func (m *Reply_Entry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Reply_Entry.Unmarshal(m, b) +} +func (m *Reply_Entry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Reply_Entry.Marshal(b, m, deterministic) +} +func (dst *Reply_Entry) XXX_Merge(src proto.Message) { + xxx_messageInfo_Reply_Entry.Merge(dst, src) +} +func (m *Reply_Entry) XXX_Size() int { + return xxx_messageInfo_Reply_Entry.Size(m) +} +func (m *Reply_Entry) XXX_DiscardUnknown() { + xxx_messageInfo_Reply_Entry.DiscardUnknown(m) +} + +var xxx_messageInfo_Reply_Entry proto.InternalMessageInfo const Default_Reply_Entry_Value int64 = 7 @@ -350,22 +437,44 @@ func (m *Reply_Entry) GetXMyFieldName_2() int64 { } type OtherBase struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *OtherBase) Reset() { *m = OtherBase{} } func (m *OtherBase) String() string { return proto.CompactTextString(m) } func (*OtherBase) ProtoMessage() {} +func (*OtherBase) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{2} +} var extRange_OtherBase = []proto.ExtensionRange{ - {100, 536870911}, + {Start: 100, End: 536870911}, } func (*OtherBase) ExtensionRangeArray() []proto.ExtensionRange { return extRange_OtherBase } +func (m *OtherBase) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OtherBase.Unmarshal(m, b) +} +func (m *OtherBase) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OtherBase.Marshal(b, m, deterministic) +} +func (dst *OtherBase) XXX_Merge(src proto.Message) { + xxx_messageInfo_OtherBase.Merge(dst, src) +} +func (m *OtherBase) XXX_Size() int { + return xxx_messageInfo_OtherBase.Size(m) +} +func (m *OtherBase) XXX_DiscardUnknown() { + xxx_messageInfo_OtherBase.DiscardUnknown(m) +} + +var xxx_messageInfo_OtherBase proto.InternalMessageInfo func (m *OtherBase) GetName() string { if m != nil && m.Name != nil { @@ -375,12 +484,34 @@ func (m *OtherBase) GetName() string { } type ReplyExtensions struct { - XXX_unrecognized []byte `json:"-"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *ReplyExtensions) Reset() { *m = ReplyExtensions{} } func (m *ReplyExtensions) String() string { return proto.CompactTextString(m) } func (*ReplyExtensions) ProtoMessage() {} +func (*ReplyExtensions) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{3} +} +func (m *ReplyExtensions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ReplyExtensions.Unmarshal(m, b) +} +func (m *ReplyExtensions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ReplyExtensions.Marshal(b, m, deterministic) +} +func (dst *ReplyExtensions) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReplyExtensions.Merge(dst, src) +} +func (m *ReplyExtensions) XXX_Size() int { + return xxx_messageInfo_ReplyExtensions.Size(m) +} +func (m *ReplyExtensions) XXX_DiscardUnknown() { + xxx_messageInfo_ReplyExtensions.DiscardUnknown(m) +} + +var xxx_messageInfo_ReplyExtensions proto.InternalMessageInfo var E_ReplyExtensions_Time = &proto.ExtensionDesc{ ExtendedType: (*Reply)(nil), @@ -410,13 +541,35 @@ var E_ReplyExtensions_Donut = &proto.ExtensionDesc{ } type OtherReplyExtensions struct { - Key *int32 `protobuf:"varint,1,opt,name=key" json:"key,omitempty"` - XXX_unrecognized []byte `json:"-"` + Key *int32 `protobuf:"varint,1,opt,name=key" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *OtherReplyExtensions) Reset() { *m = OtherReplyExtensions{} } func (m *OtherReplyExtensions) String() string { return proto.CompactTextString(m) } func (*OtherReplyExtensions) ProtoMessage() {} +func (*OtherReplyExtensions) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{4} +} +func (m *OtherReplyExtensions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OtherReplyExtensions.Unmarshal(m, b) +} +func (m *OtherReplyExtensions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OtherReplyExtensions.Marshal(b, m, deterministic) +} +func (dst *OtherReplyExtensions) XXX_Merge(src proto.Message) { + xxx_messageInfo_OtherReplyExtensions.Merge(dst, src) +} +func (m *OtherReplyExtensions) XXX_Size() int { + return xxx_messageInfo_OtherReplyExtensions.Size(m) +} +func (m *OtherReplyExtensions) XXX_DiscardUnknown() { + xxx_messageInfo_OtherReplyExtensions.DiscardUnknown(m) +} + +var xxx_messageInfo_OtherReplyExtensions proto.InternalMessageInfo func (m *OtherReplyExtensions) GetKey() int32 { if m != nil && m.Key != nil { @@ -426,20 +579,19 @@ func (m *OtherReplyExtensions) GetKey() int32 { } type OldReply struct { - proto.XXX_InternalExtensions `json:"-"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `protobuf_messageset:"1" json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *OldReply) Reset() { *m = OldReply{} } func (m *OldReply) String() string { return proto.CompactTextString(m) } func (*OldReply) ProtoMessage() {} +func (*OldReply) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{5} +} -func (m *OldReply) Marshal() ([]byte, error) { - return proto.MarshalMessageSet(&m.XXX_InternalExtensions) -} -func (m *OldReply) Unmarshal(buf []byte) error { - return proto.UnmarshalMessageSet(buf, &m.XXX_InternalExtensions) -} func (m *OldReply) MarshalJSON() ([]byte, error) { return proto.MarshalMessageSetJSON(&m.XXX_InternalExtensions) } @@ -447,17 +599,30 @@ func (m *OldReply) UnmarshalJSON(buf []byte) error { return proto.UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions) } -// ensure OldReply satisfies proto.Marshaler and proto.Unmarshaler -var _ proto.Marshaler = (*OldReply)(nil) -var _ proto.Unmarshaler = (*OldReply)(nil) - var extRange_OldReply = []proto.ExtensionRange{ - {100, 2147483646}, + {Start: 100, End: 2147483646}, } func (*OldReply) ExtensionRangeArray() []proto.ExtensionRange { return extRange_OldReply } +func (m *OldReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OldReply.Unmarshal(m, b) +} +func (m *OldReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OldReply.Marshal(b, m, deterministic) +} +func (dst *OldReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_OldReply.Merge(dst, src) +} +func (m *OldReply) XXX_Size() int { + return xxx_messageInfo_OldReply.Size(m) +} +func (m *OldReply) XXX_DiscardUnknown() { + xxx_messageInfo_OldReply.DiscardUnknown(m) +} + +var xxx_messageInfo_OldReply proto.InternalMessageInfo type Communique struct { MakeMeCry *bool `protobuf:"varint,1,opt,name=make_me_cry,json=makeMeCry" json:"make_me_cry,omitempty"` @@ -474,13 +639,42 @@ type Communique struct { // *Communique_Delta_ // *Communique_Msg // *Communique_Somegroup - Union isCommunique_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` + Union isCommunique_Union `protobuf_oneof:"union"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Communique) Reset() { *m = Communique{} } func (m *Communique) String() string { return proto.CompactTextString(m) } func (*Communique) ProtoMessage() {} +func (*Communique) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{6} +} +func (m *Communique) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Communique.Unmarshal(m, b) +} +func (m *Communique) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Communique.Marshal(b, m, deterministic) +} +func (dst *Communique) XXX_Merge(src proto.Message) { + xxx_messageInfo_Communique.Merge(dst, src) +} +func (m *Communique) XXX_Size() int { + return xxx_messageInfo_Communique.Size(m) +} +func (m *Communique) XXX_DiscardUnknown() { + xxx_messageInfo_Communique.DiscardUnknown(m) +} + +var xxx_messageInfo_Communique proto.InternalMessageInfo + +func (m *Communique) GetMakeMeCry() bool { + if m != nil && m.MakeMeCry != nil { + return *m.MakeMeCry + } + return false +} type isCommunique_Union interface { isCommunique_Union() @@ -489,43 +683,61 @@ type isCommunique_Union interface { type Communique_Number struct { Number int32 `protobuf:"varint,5,opt,name=number,oneof"` } + type Communique_Name struct { Name string `protobuf:"bytes,6,opt,name=name,oneof"` } + type Communique_Data struct { Data []byte `protobuf:"bytes,7,opt,name=data,oneof"` } + type Communique_TempC struct { TempC float64 `protobuf:"fixed64,8,opt,name=temp_c,json=tempC,oneof"` } + type Communique_Height struct { Height float32 `protobuf:"fixed32,9,opt,name=height,oneof"` } + type Communique_Today struct { Today Days `protobuf:"varint,10,opt,name=today,enum=my.test.Days,oneof"` } + type Communique_Maybe struct { Maybe bool `protobuf:"varint,11,opt,name=maybe,oneof"` } + type Communique_Delta_ struct { Delta int32 `protobuf:"zigzag32,12,opt,name=delta,oneof"` } + type Communique_Msg struct { - Msg *Reply `protobuf:"bytes,13,opt,name=msg,oneof"` + Msg *Reply `protobuf:"bytes,16,opt,name=msg,oneof"` } + type Communique_Somegroup struct { Somegroup *Communique_SomeGroup `protobuf:"group,14,opt,name=SomeGroup,json=somegroup,oneof"` } -func (*Communique_Number) isCommunique_Union() {} -func (*Communique_Name) isCommunique_Union() {} -func (*Communique_Data) isCommunique_Union() {} -func (*Communique_TempC) isCommunique_Union() {} -func (*Communique_Height) isCommunique_Union() {} -func (*Communique_Today) isCommunique_Union() {} -func (*Communique_Maybe) isCommunique_Union() {} -func (*Communique_Delta_) isCommunique_Union() {} -func (*Communique_Msg) isCommunique_Union() {} +func (*Communique_Number) isCommunique_Union() {} + +func (*Communique_Name) isCommunique_Union() {} + +func (*Communique_Data) isCommunique_Union() {} + +func (*Communique_TempC) isCommunique_Union() {} + +func (*Communique_Height) isCommunique_Union() {} + +func (*Communique_Today) isCommunique_Union() {} + +func (*Communique_Maybe) isCommunique_Union() {} + +func (*Communique_Delta_) isCommunique_Union() {} + +func (*Communique_Msg) isCommunique_Union() {} + func (*Communique_Somegroup) isCommunique_Union() {} func (m *Communique) GetUnion() isCommunique_Union { @@ -535,13 +747,6 @@ func (m *Communique) GetUnion() isCommunique_Union { return nil } -func (m *Communique) GetMakeMeCry() bool { - if m != nil && m.MakeMeCry != nil { - return *m.MakeMeCry - } - return false -} - func (m *Communique) GetNumber() int32 { if x, ok := m.GetUnion().(*Communique_Number); ok { return x.Number @@ -661,7 +866,7 @@ func _Communique_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { b.EncodeVarint(12<<3 | proto.WireVarint) b.EncodeZigzag32(uint64(x.Delta)) case *Communique_Msg: - b.EncodeVarint(13<<3 | proto.WireBytes) + b.EncodeVarint(16<<3 | proto.WireBytes) if err := b.EncodeMessage(x.Msg); err != nil { return err } @@ -737,7 +942,7 @@ func _Communique_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buf x, err := b.DecodeZigzag32() m.Union = &Communique_Delta_{int32(x)} return true, err - case 13: // union.msg + case 16: // union.msg if wire != proto.WireBytes { return true, proto.ErrInternalBadWireType } @@ -763,40 +968,40 @@ func _Communique_OneofSizer(msg proto.Message) (n int) { // union switch x := m.Union.(type) { case *Communique_Number: - n += proto.SizeVarint(5<<3 | proto.WireVarint) + n += 1 // tag and wire n += proto.SizeVarint(uint64(x.Number)) case *Communique_Name: - n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(len(x.Name))) n += len(x.Name) case *Communique_Data: - n += proto.SizeVarint(7<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(len(x.Data))) n += len(x.Data) case *Communique_TempC: - n += proto.SizeVarint(8<<3 | proto.WireFixed64) + n += 1 // tag and wire n += 8 case *Communique_Height: - n += proto.SizeVarint(9<<3 | proto.WireFixed32) + n += 1 // tag and wire n += 4 case *Communique_Today: - n += proto.SizeVarint(10<<3 | proto.WireVarint) + n += 1 // tag and wire n += proto.SizeVarint(uint64(x.Today)) case *Communique_Maybe: - n += proto.SizeVarint(11<<3 | proto.WireVarint) + n += 1 // tag and wire n += 1 case *Communique_Delta_: - n += proto.SizeVarint(12<<3 | proto.WireVarint) + n += 1 // tag and wire n += proto.SizeVarint(uint64((uint32(x.Delta) << 1) ^ uint32((int32(x.Delta) >> 31)))) case *Communique_Msg: s := proto.Size(x.Msg) - n += proto.SizeVarint(13<<3 | proto.WireBytes) + n += 2 // tag and wire n += proto.SizeVarint(uint64(s)) n += s case *Communique_Somegroup: - n += proto.SizeVarint(14<<3 | proto.WireStartGroup) + n += 1 // tag and wire n += proto.Size(x.Somegroup) - n += proto.SizeVarint(14<<3 | proto.WireEndGroup) + n += 1 // tag and wire case nil: default: panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) @@ -805,13 +1010,35 @@ func _Communique_OneofSizer(msg proto.Message) (n int) { } type Communique_SomeGroup struct { - Member *string `protobuf:"bytes,15,opt,name=member" json:"member,omitempty"` - XXX_unrecognized []byte `json:"-"` + Member *string `protobuf:"bytes,15,opt,name=member" json:"member,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Communique_SomeGroup) Reset() { *m = Communique_SomeGroup{} } func (m *Communique_SomeGroup) String() string { return proto.CompactTextString(m) } func (*Communique_SomeGroup) ProtoMessage() {} +func (*Communique_SomeGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{6, 0} +} +func (m *Communique_SomeGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Communique_SomeGroup.Unmarshal(m, b) +} +func (m *Communique_SomeGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Communique_SomeGroup.Marshal(b, m, deterministic) +} +func (dst *Communique_SomeGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_Communique_SomeGroup.Merge(dst, src) +} +func (m *Communique_SomeGroup) XXX_Size() int { + return xxx_messageInfo_Communique_SomeGroup.Size(m) +} +func (m *Communique_SomeGroup) XXX_DiscardUnknown() { + xxx_messageInfo_Communique_SomeGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_Communique_SomeGroup proto.InternalMessageInfo func (m *Communique_SomeGroup) GetMember() string { if m != nil && m.Member != nil { @@ -821,12 +1048,34 @@ func (m *Communique_SomeGroup) GetMember() string { } type Communique_Delta struct { - XXX_unrecognized []byte `json:"-"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Communique_Delta) Reset() { *m = Communique_Delta{} } func (m *Communique_Delta) String() string { return proto.CompactTextString(m) } func (*Communique_Delta) ProtoMessage() {} +func (*Communique_Delta) Descriptor() ([]byte, []int) { + return fileDescriptor_test_2309d445eee26af7, []int{6, 1} +} +func (m *Communique_Delta) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Communique_Delta.Unmarshal(m, b) +} +func (m *Communique_Delta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Communique_Delta.Marshal(b, m, deterministic) +} +func (dst *Communique_Delta) XXX_Merge(src proto.Message) { + xxx_messageInfo_Communique_Delta.Merge(dst, src) +} +func (m *Communique_Delta) XXX_Size() int { + return xxx_messageInfo_Communique_Delta.Size(m) +} +func (m *Communique_Delta) XXX_DiscardUnknown() { + xxx_messageInfo_Communique_Delta.DiscardUnknown(m) +} + +var xxx_messageInfo_Communique_Delta proto.InternalMessageInfo var E_Tag = &proto.ExtensionDesc{ ExtendedType: (*Reply)(nil), @@ -848,6 +1097,8 @@ var E_Donut = &proto.ExtensionDesc{ func init() { proto.RegisterType((*Request)(nil), "my.test.Request") + proto.RegisterMapType((map[int64]*Reply)(nil), "my.test.Request.MsgMappingEntry") + proto.RegisterMapType((map[int32]string)(nil), "my.test.Request.NameMappingEntry") proto.RegisterType((*Request_SomeGroup)(nil), "my.test.Request.SomeGroup") proto.RegisterType((*Reply)(nil), "my.test.Reply") proto.RegisterType((*Reply_Entry)(nil), "my.test.Reply.Entry") @@ -868,3 +1119,74 @@ func init() { proto.RegisterExtension(E_Tag) proto.RegisterExtension(E_Donut) } + +func init() { proto.RegisterFile("my_test/test.proto", fileDescriptor_test_2309d445eee26af7) } + +var fileDescriptor_test_2309d445eee26af7 = []byte{ + // 1033 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0xdd, 0x6e, 0xe3, 0x44, + 0x14, 0xce, 0xd8, 0x71, 0x7e, 0x4e, 0x42, 0x6b, 0x46, 0x55, 0x6b, 0x05, 0xed, 0xd6, 0x04, 0x8a, + 0x4c, 0xc5, 0xa6, 0xda, 0x80, 0xc4, 0x2a, 0x88, 0xd5, 0x36, 0x3f, 0x6d, 0xaa, 0x6d, 0x12, 0x69, + 0xda, 0x5e, 0xb0, 0x37, 0xd6, 0x34, 0x9e, 0x3a, 0xa6, 0x19, 0x3b, 0x6b, 0x8f, 0x11, 0xbe, 0xeb, + 0x53, 0xc0, 0x6b, 0x70, 0xcf, 0x0b, 0xf1, 0x16, 0x45, 0x33, 0x0e, 0x49, 0xda, 0xa0, 0xbd, 0xb1, + 0x7c, 0xce, 0xf9, 0xce, 0xe7, 0x39, 0x3f, 0xfe, 0x06, 0x30, 0xcf, 0x5c, 0xc1, 0x12, 0x71, 0x22, + 0x1f, 0xad, 0x45, 0x1c, 0x89, 0x08, 0x97, 0x79, 0xd6, 0x92, 0x66, 0x03, 0xf3, 0x74, 0x2e, 0x82, + 0x13, 0xf5, 0x7c, 0x9d, 0x07, 0x9b, 0xff, 0x14, 0xa1, 0x4c, 0xd8, 0xc7, 0x94, 0x25, 0x02, 0x9b, + 0xa0, 0xdf, 0xb3, 0xcc, 0x42, 0xb6, 0xee, 0xe8, 0x44, 0xbe, 0x62, 0x07, 0xf4, 0x59, 0xca, 0x2c, + 0xdd, 0x46, 0xce, 0x4e, 0x7b, 0xbf, 0xb5, 0x24, 0x6a, 0x2d, 0x13, 0x5a, 0xbd, 0x68, 0x1e, 0xc5, + 0x44, 0x42, 0xf0, 0x31, 0xe8, 0x33, 0x2a, 0xac, 0xa2, 0x42, 0x9a, 0x2b, 0xe4, 0x90, 0x8a, 0xeb, + 0x6c, 0xc1, 0x3a, 0xa5, 0xb3, 0x41, 0x7f, 0x42, 0x4e, 0x89, 0x04, 0xe1, 0x43, 0xa8, 0x78, 0x8c, + 0x7a, 0xf3, 0x20, 0x64, 0x56, 0xd9, 0x46, 0x8e, 0xd6, 0xd1, 0x83, 0xf0, 0x8e, 0xac, 0x9c, 0xf8, + 0x0d, 0x54, 0x93, 0x88, 0x33, 0x3f, 0x8e, 0xd2, 0x85, 0x55, 0xb1, 0x91, 0x03, 0xed, 0xc6, 0xd6, + 0xc7, 0xaf, 0x22, 0xce, 0xce, 0x25, 0x82, 0xac, 0xc1, 0xb8, 0x0f, 0xf5, 0x90, 0x72, 0xe6, 0x72, + 0xba, 0x58, 0x04, 0xa1, 0x6f, 0xed, 0xd8, 0xba, 0x53, 0x6b, 0x7f, 0xb9, 0x95, 0x3c, 0xa6, 0x9c, + 0x8d, 0x72, 0xcc, 0x20, 0x14, 0x71, 0x46, 0x6a, 0xe1, 0xda, 0x83, 0x4f, 0xa1, 0xc6, 0x13, 0x7f, + 0x45, 0xb2, 0xab, 0x48, 0xec, 0x2d, 0x92, 0x51, 0xe2, 0x3f, 0xe1, 0x00, 0xbe, 0x72, 0xe0, 0x3d, + 0x30, 0x62, 0x96, 0x30, 0x61, 0xd5, 0x6d, 0xe4, 0x18, 0x24, 0x37, 0xf0, 0x01, 0x94, 0x7d, 0x26, + 0x5c, 0xd9, 0x65, 0xd3, 0x46, 0x4e, 0x95, 0x94, 0x7c, 0x26, 0xde, 0xb3, 0xac, 0xf1, 0x1d, 0x54, + 0x57, 0xf5, 0xe0, 0x43, 0xa8, 0xa9, 0x6a, 0xdc, 0xbb, 0x80, 0xcd, 0x3d, 0xab, 0xaa, 0x18, 0x40, + 0xb9, 0xce, 0xa4, 0xa7, 0xf1, 0x16, 0xcc, 0xe7, 0x05, 0xac, 0x87, 0x27, 0xc1, 0x6a, 0x78, 0x7b, + 0x60, 0xfc, 0x46, 0xe7, 0x29, 0xb3, 0x34, 0xf5, 0xa9, 0xdc, 0xe8, 0x68, 0x6f, 0x50, 0x63, 0x04, + 0xbb, 0xcf, 0xce, 0xbe, 0x99, 0x8e, 0xf3, 0xf4, 0xaf, 0x37, 0xd3, 0x6b, 0xed, 0x9d, 0x8d, 0xf2, + 0x17, 0xf3, 0x6c, 0x83, 0xae, 0x79, 0x04, 0x86, 0xda, 0x04, 0x5c, 0x06, 0x9d, 0x0c, 0xfa, 0x66, + 0x01, 0x57, 0xc1, 0x38, 0x27, 0x83, 0xc1, 0xd8, 0x44, 0xb8, 0x02, 0xc5, 0xee, 0xe5, 0xcd, 0xc0, + 0xd4, 0x9a, 0x7f, 0x6a, 0x60, 0xa8, 0x5c, 0x7c, 0x0c, 0xc6, 0x5d, 0x94, 0x86, 0x9e, 0x5a, 0xb5, + 0x5a, 0x7b, 0xef, 0x29, 0x75, 0x2b, 0xef, 0x66, 0x0e, 0xc1, 0x47, 0x50, 0x9f, 0x46, 0x7c, 0x41, + 0xa7, 0xaa, 0x6d, 0x89, 0xa5, 0xd9, 0xba, 0x63, 0x74, 0x35, 0x13, 0x91, 0xda, 0xd2, 0xff, 0x9e, + 0x65, 0x49, 0xe3, 0x2f, 0x04, 0x46, 0x5e, 0x49, 0x1f, 0x0e, 0xef, 0x59, 0xe6, 0x8a, 0x19, 0x15, + 0x6e, 0xc8, 0x98, 0x97, 0xb8, 0xaf, 0xdb, 0xdf, 0xff, 0x30, 0xa5, 0x9c, 0xcd, 0xdd, 0x1e, 0x4d, + 0x2e, 0x42, 0xdf, 0x42, 0xb6, 0xe6, 0xe8, 0xe4, 0x8b, 0x7b, 0x96, 0x5d, 0xcf, 0xa8, 0x18, 0x4b, + 0xd0, 0x0a, 0x93, 0x43, 0xf0, 0xc1, 0x66, 0xf5, 0x7a, 0x07, 0xfd, 0xb8, 0x2c, 0x18, 0x7f, 0x03, + 0xa6, 0xcb, 0xb3, 0x7c, 0x34, 0xae, 0xda, 0xb5, 0xb6, 0xfa, 0x3f, 0x74, 0x52, 0x1f, 0x65, 0x6a, + 0x3c, 0x72, 0x34, 0xed, 0xa6, 0x0d, 0xc5, 0x73, 0xca, 0x19, 0xae, 0x43, 0xe5, 0x6c, 0x32, 0xb9, + 0xee, 0x9e, 0x5e, 0x5e, 0x9a, 0x08, 0x03, 0x94, 0xae, 0x07, 0xe3, 0xf1, 0xc5, 0x95, 0xa9, 0x1d, + 0x57, 0x2a, 0x9e, 0xf9, 0xf0, 0xf0, 0xf0, 0xa0, 0x35, 0xbf, 0x85, 0xea, 0x44, 0xcc, 0x58, 0xdc, + 0xa5, 0x09, 0xc3, 0x18, 0x8a, 0x92, 0x56, 0x8d, 0xa2, 0x4a, 0xd4, 0xfb, 0x06, 0xf4, 0x6f, 0x04, + 0xbb, 0xaa, 0x4b, 0x83, 0xdf, 0x05, 0x0b, 0x93, 0x20, 0x0a, 0x93, 0x76, 0x13, 0x8a, 0x22, 0xe0, + 0x0c, 0x3f, 0x1b, 0x91, 0xc5, 0x6c, 0xe4, 0x20, 0xa2, 0x62, 0xed, 0x77, 0x50, 0x9a, 0xd2, 0x38, + 0x8e, 0xc4, 0x16, 0x2a, 0x50, 0xe3, 0xb5, 0x9e, 0x7a, 0xd7, 0xec, 0x64, 0x99, 0xd7, 0xee, 0x82, + 0xe1, 0x45, 0x61, 0x2a, 0x30, 0x5e, 0x41, 0x57, 0x87, 0x56, 0x9f, 0xfa, 0x14, 0x49, 0x9e, 0xda, + 0x74, 0x60, 0x4f, 0xe5, 0x3c, 0x0b, 0x6f, 0x2f, 0x6f, 0xd3, 0x82, 0xca, 0x64, 0xee, 0x29, 0x9c, + 0xaa, 0xfe, 0xf1, 0xf1, 0xf1, 0xb1, 0xdc, 0xd1, 0x2a, 0xa8, 0xf9, 0x87, 0x0e, 0xd0, 0x8b, 0x38, + 0x4f, 0xc3, 0xe0, 0x63, 0xca, 0xf0, 0x4b, 0xa8, 0x71, 0x7a, 0xcf, 0x5c, 0xce, 0xdc, 0x69, 0x9c, + 0x53, 0x54, 0x48, 0x55, 0xba, 0x46, 0xac, 0x17, 0x67, 0xd8, 0x82, 0x52, 0x98, 0xf2, 0x5b, 0x16, + 0x5b, 0x86, 0x64, 0x1f, 0x16, 0xc8, 0xd2, 0xc6, 0x7b, 0xcb, 0x46, 0x97, 0x64, 0xa3, 0x87, 0x85, + 0xbc, 0xd5, 0xd2, 0xeb, 0x51, 0x41, 0x95, 0x30, 0xd5, 0xa5, 0x57, 0x5a, 0xf8, 0x00, 0x4a, 0x82, + 0xf1, 0x85, 0x3b, 0x55, 0x72, 0x84, 0x86, 0x05, 0x62, 0x48, 0xbb, 0x27, 0xe9, 0x67, 0x2c, 0xf0, + 0x67, 0x42, 0xfd, 0xa6, 0x9a, 0xa4, 0xcf, 0x6d, 0x7c, 0x04, 0x86, 0x88, 0x3c, 0x9a, 0x59, 0xa0, + 0x34, 0xf1, 0xb3, 0x55, 0x6f, 0xfa, 0x34, 0x4b, 0x14, 0x81, 0x8c, 0xe2, 0x7d, 0x30, 0x38, 0xcd, + 0x6e, 0x99, 0x55, 0x93, 0x27, 0x97, 0x7e, 0x65, 0x4a, 0xbf, 0xc7, 0xe6, 0x82, 0x2a, 0x01, 0xf9, + 0x5c, 0xfa, 0x95, 0x89, 0x9b, 0xa0, 0xf3, 0xc4, 0x57, 0xf2, 0xb1, 0xf5, 0x53, 0x0e, 0x0b, 0x44, + 0x06, 0xf1, 0xcf, 0x9b, 0xfa, 0xb9, 0xa3, 0xf4, 0xf3, 0xc5, 0x0a, 0xb9, 0xee, 0xdd, 0x5a, 0x42, + 0x87, 0x85, 0x0d, 0x11, 0x6d, 0x7c, 0xb5, 0x29, 0x46, 0xfb, 0x50, 0xe2, 0x4c, 0xf5, 0x6f, 0x37, + 0x57, 0xac, 0xdc, 0x6a, 0x94, 0xc1, 0xe8, 0xcb, 0x03, 0x75, 0xcb, 0x60, 0xa4, 0x61, 0x10, 0x85, + 0xc7, 0x2f, 0xa1, 0xbc, 0x94, 0x7b, 0xb9, 0xe6, 0xb9, 0xe0, 0x9b, 0x48, 0x8a, 0xc2, 0xd9, 0xe0, + 0x83, 0xa9, 0x1d, 0xb7, 0xa0, 0x28, 0x4b, 0x97, 0xc1, 0xd1, 0x64, 0xdc, 0x3f, 0xfd, 0xc5, 0x44, + 0xb8, 0x06, 0xe5, 0xeb, 0x9b, 0xc1, 0x95, 0x34, 0x34, 0xa9, 0x1a, 0x97, 0x37, 0xe3, 0xfe, 0x85, + 0x89, 0x1a, 0x9a, 0x89, 0x3a, 0x36, 0xe8, 0x82, 0xfa, 0x5b, 0xfb, 0xea, 0xab, 0x63, 0xc8, 0x50, + 0xa7, 0xf7, 0xdf, 0x4a, 0x3e, 0xc7, 0xfc, 0xaa, 0xba, 0xf3, 0xe2, 0xe9, 0xa2, 0xfe, 0xff, 0x4e, + 0x76, 0xdf, 0x7d, 0x78, 0xeb, 0x07, 0x62, 0x96, 0xde, 0xb6, 0xa6, 0x11, 0x3f, 0xf1, 0xa3, 0x39, + 0x0d, 0xfd, 0x13, 0x75, 0x39, 0xde, 0xa6, 0x77, 0xf9, 0xcb, 0xf4, 0x95, 0xcf, 0xc2, 0x57, 0x7e, + 0xa4, 0x6e, 0x55, 0xb9, 0x0f, 0x27, 0xcb, 0x6b, 0xf6, 0x27, 0xf9, 0xf8, 0x37, 0x00, 0x00, 0xff, + 0xff, 0x12, 0xd5, 0x46, 0x00, 0x75, 0x07, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go.golden b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go.golden deleted file mode 100644 index 1954e3fb..00000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.pb.go.golden +++ /dev/null @@ -1,870 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: my_test/test.proto - -/* -Package my_test is a generated protocol buffer package. - -This package holds interesting messages. - -It is generated from these files: - my_test/test.proto - -It has these top-level messages: - Request - Reply - OtherBase - ReplyExtensions - OtherReplyExtensions - OldReply - Communique -*/ -package my_test - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import _ "github.com/golang/protobuf/protoc-gen-go/testdata/multi" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type HatType int32 - -const ( - // deliberately skipping 0 - HatType_FEDORA HatType = 1 - HatType_FEZ HatType = 2 -) - -var HatType_name = map[int32]string{ - 1: "FEDORA", - 2: "FEZ", -} -var HatType_value = map[string]int32{ - "FEDORA": 1, - "FEZ": 2, -} - -func (x HatType) Enum() *HatType { - p := new(HatType) - *p = x - return p -} -func (x HatType) String() string { - return proto.EnumName(HatType_name, int32(x)) -} -func (x *HatType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(HatType_value, data, "HatType") - if err != nil { - return err - } - *x = HatType(value) - return nil -} - -// This enum represents days of the week. -type Days int32 - -const ( - Days_MONDAY Days = 1 - Days_TUESDAY Days = 2 - Days_LUNDI Days = 1 -) - -var Days_name = map[int32]string{ - 1: "MONDAY", - 2: "TUESDAY", - // Duplicate value: 1: "LUNDI", -} -var Days_value = map[string]int32{ - "MONDAY": 1, - "TUESDAY": 2, - "LUNDI": 1, -} - -func (x Days) Enum() *Days { - p := new(Days) - *p = x - return p -} -func (x Days) String() string { - return proto.EnumName(Days_name, int32(x)) -} -func (x *Days) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Days_value, data, "Days") - if err != nil { - return err - } - *x = Days(value) - return nil -} - -type Request_Color int32 - -const ( - Request_RED Request_Color = 0 - Request_GREEN Request_Color = 1 - Request_BLUE Request_Color = 2 -) - -var Request_Color_name = map[int32]string{ - 0: "RED", - 1: "GREEN", - 2: "BLUE", -} -var Request_Color_value = map[string]int32{ - "RED": 0, - "GREEN": 1, - "BLUE": 2, -} - -func (x Request_Color) Enum() *Request_Color { - p := new(Request_Color) - *p = x - return p -} -func (x Request_Color) String() string { - return proto.EnumName(Request_Color_name, int32(x)) -} -func (x *Request_Color) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Request_Color_value, data, "Request_Color") - if err != nil { - return err - } - *x = Request_Color(value) - return nil -} - -type Reply_Entry_Game int32 - -const ( - Reply_Entry_FOOTBALL Reply_Entry_Game = 1 - Reply_Entry_TENNIS Reply_Entry_Game = 2 -) - -var Reply_Entry_Game_name = map[int32]string{ - 1: "FOOTBALL", - 2: "TENNIS", -} -var Reply_Entry_Game_value = map[string]int32{ - "FOOTBALL": 1, - "TENNIS": 2, -} - -func (x Reply_Entry_Game) Enum() *Reply_Entry_Game { - p := new(Reply_Entry_Game) - *p = x - return p -} -func (x Reply_Entry_Game) String() string { - return proto.EnumName(Reply_Entry_Game_name, int32(x)) -} -func (x *Reply_Entry_Game) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Reply_Entry_Game_value, data, "Reply_Entry_Game") - if err != nil { - return err - } - *x = Reply_Entry_Game(value) - return nil -} - -// This is a message that might be sent somewhere. -type Request struct { - Key []int64 `protobuf:"varint,1,rep,name=key" json:"key,omitempty"` - // optional imp.ImportedMessage imported_message = 2; - Hue *Request_Color `protobuf:"varint,3,opt,name=hue,enum=my.test.Request_Color" json:"hue,omitempty"` - Hat *HatType `protobuf:"varint,4,opt,name=hat,enum=my.test.HatType,def=1" json:"hat,omitempty"` - // optional imp.ImportedMessage.Owner owner = 6; - Deadline *float32 `protobuf:"fixed32,7,opt,name=deadline,def=inf" json:"deadline,omitempty"` - Somegroup *Request_SomeGroup `protobuf:"group,8,opt,name=SomeGroup,json=somegroup" json:"somegroup,omitempty"` - // This is a map field. It will generate map[int32]string. - NameMapping map[int32]string `protobuf:"bytes,14,rep,name=name_mapping,json=nameMapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - // This is a map field whose value type is a message. - MsgMapping map[int64]*Reply `protobuf:"bytes,15,rep,name=msg_mapping,json=msgMapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Reset_ *int32 `protobuf:"varint,12,opt,name=reset" json:"reset,omitempty"` - // This field should not conflict with any getters. - GetKey_ *string `protobuf:"bytes,16,opt,name=get_key,json=getKey" json:"get_key,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Request) Reset() { *m = Request{} } -func (m *Request) String() string { return proto.CompactTextString(m) } -func (*Request) ProtoMessage() {} - -const Default_Request_Hat HatType = HatType_FEDORA - -var Default_Request_Deadline float32 = float32(math.Inf(1)) - -func (m *Request) GetKey() []int64 { - if m != nil { - return m.Key - } - return nil -} - -func (m *Request) GetHue() Request_Color { - if m != nil && m.Hue != nil { - return *m.Hue - } - return Request_RED -} - -func (m *Request) GetHat() HatType { - if m != nil && m.Hat != nil { - return *m.Hat - } - return Default_Request_Hat -} - -func (m *Request) GetDeadline() float32 { - if m != nil && m.Deadline != nil { - return *m.Deadline - } - return Default_Request_Deadline -} - -func (m *Request) GetSomegroup() *Request_SomeGroup { - if m != nil { - return m.Somegroup - } - return nil -} - -func (m *Request) GetNameMapping() map[int32]string { - if m != nil { - return m.NameMapping - } - return nil -} - -func (m *Request) GetMsgMapping() map[int64]*Reply { - if m != nil { - return m.MsgMapping - } - return nil -} - -func (m *Request) GetReset_() int32 { - if m != nil && m.Reset_ != nil { - return *m.Reset_ - } - return 0 -} - -func (m *Request) GetGetKey_() string { - if m != nil && m.GetKey_ != nil { - return *m.GetKey_ - } - return "" -} - -type Request_SomeGroup struct { - GroupField *int32 `protobuf:"varint,9,opt,name=group_field,json=groupField" json:"group_field,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Request_SomeGroup) Reset() { *m = Request_SomeGroup{} } -func (m *Request_SomeGroup) String() string { return proto.CompactTextString(m) } -func (*Request_SomeGroup) ProtoMessage() {} - -func (m *Request_SomeGroup) GetGroupField() int32 { - if m != nil && m.GroupField != nil { - return *m.GroupField - } - return 0 -} - -type Reply struct { - Found []*Reply_Entry `protobuf:"bytes,1,rep,name=found" json:"found,omitempty"` - CompactKeys []int32 `protobuf:"varint,2,rep,packed,name=compact_keys,json=compactKeys" json:"compact_keys,omitempty"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Reply) Reset() { *m = Reply{} } -func (m *Reply) String() string { return proto.CompactTextString(m) } -func (*Reply) ProtoMessage() {} - -var extRange_Reply = []proto.ExtensionRange{ - {100, 536870911}, -} - -func (*Reply) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_Reply -} - -func (m *Reply) GetFound() []*Reply_Entry { - if m != nil { - return m.Found - } - return nil -} - -func (m *Reply) GetCompactKeys() []int32 { - if m != nil { - return m.CompactKeys - } - return nil -} - -type Reply_Entry struct { - KeyThatNeeds_1234Camel_CasIng *int64 `protobuf:"varint,1,req,name=key_that_needs_1234camel_CasIng,json=keyThatNeeds1234camelCasIng" json:"key_that_needs_1234camel_CasIng,omitempty"` - Value *int64 `protobuf:"varint,2,opt,name=value,def=7" json:"value,omitempty"` - XMyFieldName_2 *int64 `protobuf:"varint,3,opt,name=_my_field_name_2,json=MyFieldName2" json:"_my_field_name_2,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Reply_Entry) Reset() { *m = Reply_Entry{} } -func (m *Reply_Entry) String() string { return proto.CompactTextString(m) } -func (*Reply_Entry) ProtoMessage() {} - -const Default_Reply_Entry_Value int64 = 7 - -func (m *Reply_Entry) GetKeyThatNeeds_1234Camel_CasIng() int64 { - if m != nil && m.KeyThatNeeds_1234Camel_CasIng != nil { - return *m.KeyThatNeeds_1234Camel_CasIng - } - return 0 -} - -func (m *Reply_Entry) GetValue() int64 { - if m != nil && m.Value != nil { - return *m.Value - } - return Default_Reply_Entry_Value -} - -func (m *Reply_Entry) GetXMyFieldName_2() int64 { - if m != nil && m.XMyFieldName_2 != nil { - return *m.XMyFieldName_2 - } - return 0 -} - -type OtherBase struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *OtherBase) Reset() { *m = OtherBase{} } -func (m *OtherBase) String() string { return proto.CompactTextString(m) } -func (*OtherBase) ProtoMessage() {} - -var extRange_OtherBase = []proto.ExtensionRange{ - {100, 536870911}, -} - -func (*OtherBase) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_OtherBase -} - -func (m *OtherBase) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -type ReplyExtensions struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *ReplyExtensions) Reset() { *m = ReplyExtensions{} } -func (m *ReplyExtensions) String() string { return proto.CompactTextString(m) } -func (*ReplyExtensions) ProtoMessage() {} - -var E_ReplyExtensions_Time = &proto.ExtensionDesc{ - ExtendedType: (*Reply)(nil), - ExtensionType: (*float64)(nil), - Field: 101, - Name: "my.test.ReplyExtensions.time", - Tag: "fixed64,101,opt,name=time", - Filename: "my_test/test.proto", -} - -var E_ReplyExtensions_Carrot = &proto.ExtensionDesc{ - ExtendedType: (*Reply)(nil), - ExtensionType: (*ReplyExtensions)(nil), - Field: 105, - Name: "my.test.ReplyExtensions.carrot", - Tag: "bytes,105,opt,name=carrot", - Filename: "my_test/test.proto", -} - -var E_ReplyExtensions_Donut = &proto.ExtensionDesc{ - ExtendedType: (*OtherBase)(nil), - ExtensionType: (*ReplyExtensions)(nil), - Field: 101, - Name: "my.test.ReplyExtensions.donut", - Tag: "bytes,101,opt,name=donut", - Filename: "my_test/test.proto", -} - -type OtherReplyExtensions struct { - Key *int32 `protobuf:"varint,1,opt,name=key" json:"key,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *OtherReplyExtensions) Reset() { *m = OtherReplyExtensions{} } -func (m *OtherReplyExtensions) String() string { return proto.CompactTextString(m) } -func (*OtherReplyExtensions) ProtoMessage() {} - -func (m *OtherReplyExtensions) GetKey() int32 { - if m != nil && m.Key != nil { - return *m.Key - } - return 0 -} - -type OldReply struct { - proto.XXX_InternalExtensions `json:"-"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *OldReply) Reset() { *m = OldReply{} } -func (m *OldReply) String() string { return proto.CompactTextString(m) } -func (*OldReply) ProtoMessage() {} - -func (m *OldReply) Marshal() ([]byte, error) { - return proto.MarshalMessageSet(&m.XXX_InternalExtensions) -} -func (m *OldReply) Unmarshal(buf []byte) error { - return proto.UnmarshalMessageSet(buf, &m.XXX_InternalExtensions) -} -func (m *OldReply) MarshalJSON() ([]byte, error) { - return proto.MarshalMessageSetJSON(&m.XXX_InternalExtensions) -} -func (m *OldReply) UnmarshalJSON(buf []byte) error { - return proto.UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions) -} - -// ensure OldReply satisfies proto.Marshaler and proto.Unmarshaler -var _ proto.Marshaler = (*OldReply)(nil) -var _ proto.Unmarshaler = (*OldReply)(nil) - -var extRange_OldReply = []proto.ExtensionRange{ - {100, 2147483646}, -} - -func (*OldReply) ExtensionRangeArray() []proto.ExtensionRange { - return extRange_OldReply -} - -type Communique struct { - MakeMeCry *bool `protobuf:"varint,1,opt,name=make_me_cry,json=makeMeCry" json:"make_me_cry,omitempty"` - // This is a oneof, called "union". - // - // Types that are valid to be assigned to Union: - // *Communique_Number - // *Communique_Name - // *Communique_Data - // *Communique_TempC - // *Communique_Height - // *Communique_Today - // *Communique_Maybe - // *Communique_Delta_ - // *Communique_Msg - // *Communique_Somegroup - Union isCommunique_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Communique) Reset() { *m = Communique{} } -func (m *Communique) String() string { return proto.CompactTextString(m) } -func (*Communique) ProtoMessage() {} - -type isCommunique_Union interface { - isCommunique_Union() -} - -type Communique_Number struct { - Number int32 `protobuf:"varint,5,opt,name=number,oneof"` -} -type Communique_Name struct { - Name string `protobuf:"bytes,6,opt,name=name,oneof"` -} -type Communique_Data struct { - Data []byte `protobuf:"bytes,7,opt,name=data,oneof"` -} -type Communique_TempC struct { - TempC float64 `protobuf:"fixed64,8,opt,name=temp_c,json=tempC,oneof"` -} -type Communique_Height struct { - Height float32 `protobuf:"fixed32,9,opt,name=height,oneof"` -} -type Communique_Today struct { - Today Days `protobuf:"varint,10,opt,name=today,enum=my.test.Days,oneof"` -} -type Communique_Maybe struct { - Maybe bool `protobuf:"varint,11,opt,name=maybe,oneof"` -} -type Communique_Delta_ struct { - Delta int32 `protobuf:"zigzag32,12,opt,name=delta,oneof"` -} -type Communique_Msg struct { - Msg *Reply `protobuf:"bytes,13,opt,name=msg,oneof"` -} -type Communique_Somegroup struct { - Somegroup *Communique_SomeGroup `protobuf:"group,14,opt,name=SomeGroup,json=somegroup,oneof"` -} - -func (*Communique_Number) isCommunique_Union() {} -func (*Communique_Name) isCommunique_Union() {} -func (*Communique_Data) isCommunique_Union() {} -func (*Communique_TempC) isCommunique_Union() {} -func (*Communique_Height) isCommunique_Union() {} -func (*Communique_Today) isCommunique_Union() {} -func (*Communique_Maybe) isCommunique_Union() {} -func (*Communique_Delta_) isCommunique_Union() {} -func (*Communique_Msg) isCommunique_Union() {} -func (*Communique_Somegroup) isCommunique_Union() {} - -func (m *Communique) GetUnion() isCommunique_Union { - if m != nil { - return m.Union - } - return nil -} - -func (m *Communique) GetMakeMeCry() bool { - if m != nil && m.MakeMeCry != nil { - return *m.MakeMeCry - } - return false -} - -func (m *Communique) GetNumber() int32 { - if x, ok := m.GetUnion().(*Communique_Number); ok { - return x.Number - } - return 0 -} - -func (m *Communique) GetName() string { - if x, ok := m.GetUnion().(*Communique_Name); ok { - return x.Name - } - return "" -} - -func (m *Communique) GetData() []byte { - if x, ok := m.GetUnion().(*Communique_Data); ok { - return x.Data - } - return nil -} - -func (m *Communique) GetTempC() float64 { - if x, ok := m.GetUnion().(*Communique_TempC); ok { - return x.TempC - } - return 0 -} - -func (m *Communique) GetHeight() float32 { - if x, ok := m.GetUnion().(*Communique_Height); ok { - return x.Height - } - return 0 -} - -func (m *Communique) GetToday() Days { - if x, ok := m.GetUnion().(*Communique_Today); ok { - return x.Today - } - return Days_MONDAY -} - -func (m *Communique) GetMaybe() bool { - if x, ok := m.GetUnion().(*Communique_Maybe); ok { - return x.Maybe - } - return false -} - -func (m *Communique) GetDelta() int32 { - if x, ok := m.GetUnion().(*Communique_Delta_); ok { - return x.Delta - } - return 0 -} - -func (m *Communique) GetMsg() *Reply { - if x, ok := m.GetUnion().(*Communique_Msg); ok { - return x.Msg - } - return nil -} - -func (m *Communique) GetSomegroup() *Communique_SomeGroup { - if x, ok := m.GetUnion().(*Communique_Somegroup); ok { - return x.Somegroup - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*Communique) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _Communique_OneofMarshaler, _Communique_OneofUnmarshaler, _Communique_OneofSizer, []interface{}{ - (*Communique_Number)(nil), - (*Communique_Name)(nil), - (*Communique_Data)(nil), - (*Communique_TempC)(nil), - (*Communique_Height)(nil), - (*Communique_Today)(nil), - (*Communique_Maybe)(nil), - (*Communique_Delta_)(nil), - (*Communique_Msg)(nil), - (*Communique_Somegroup)(nil), - } -} - -func _Communique_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*Communique) - // union - switch x := m.Union.(type) { - case *Communique_Number: - b.EncodeVarint(5<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Number)) - case *Communique_Name: - b.EncodeVarint(6<<3 | proto.WireBytes) - b.EncodeStringBytes(x.Name) - case *Communique_Data: - b.EncodeVarint(7<<3 | proto.WireBytes) - b.EncodeRawBytes(x.Data) - case *Communique_TempC: - b.EncodeVarint(8<<3 | proto.WireFixed64) - b.EncodeFixed64(math.Float64bits(x.TempC)) - case *Communique_Height: - b.EncodeVarint(9<<3 | proto.WireFixed32) - b.EncodeFixed32(uint64(math.Float32bits(x.Height))) - case *Communique_Today: - b.EncodeVarint(10<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Today)) - case *Communique_Maybe: - t := uint64(0) - if x.Maybe { - t = 1 - } - b.EncodeVarint(11<<3 | proto.WireVarint) - b.EncodeVarint(t) - case *Communique_Delta_: - b.EncodeVarint(12<<3 | proto.WireVarint) - b.EncodeZigzag32(uint64(x.Delta)) - case *Communique_Msg: - b.EncodeVarint(13<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Msg); err != nil { - return err - } - case *Communique_Somegroup: - b.EncodeVarint(14<<3 | proto.WireStartGroup) - if err := b.Marshal(x.Somegroup); err != nil { - return err - } - b.EncodeVarint(14<<3 | proto.WireEndGroup) - case nil: - default: - return fmt.Errorf("Communique.Union has unexpected type %T", x) - } - return nil -} - -func _Communique_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*Communique) - switch tag { - case 5: // union.number - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Communique_Number{int32(x)} - return true, err - case 6: // union.name - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Union = &Communique_Name{x} - return true, err - case 7: // union.data - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.Union = &Communique_Data{x} - return true, err - case 8: // union.temp_c - if wire != proto.WireFixed64 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed64() - m.Union = &Communique_TempC{math.Float64frombits(x)} - return true, err - case 9: // union.height - if wire != proto.WireFixed32 { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeFixed32() - m.Union = &Communique_Height{math.Float32frombits(uint32(x))} - return true, err - case 10: // union.today - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Communique_Today{Days(x)} - return true, err - case 11: // union.maybe - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Union = &Communique_Maybe{x != 0} - return true, err - case 12: // union.delta - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeZigzag32() - m.Union = &Communique_Delta_{int32(x)} - return true, err - case 13: // union.msg - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Reply) - err := b.DecodeMessage(msg) - m.Union = &Communique_Msg{msg} - return true, err - case 14: // union.somegroup - if wire != proto.WireStartGroup { - return true, proto.ErrInternalBadWireType - } - msg := new(Communique_SomeGroup) - err := b.DecodeGroup(msg) - m.Union = &Communique_Somegroup{msg} - return true, err - default: - return false, nil - } -} - -func _Communique_OneofSizer(msg proto.Message) (n int) { - m := msg.(*Communique) - // union - switch x := m.Union.(type) { - case *Communique_Number: - n += proto.SizeVarint(5<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Number)) - case *Communique_Name: - n += proto.SizeVarint(6<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.Name))) - n += len(x.Name) - case *Communique_Data: - n += proto.SizeVarint(7<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.Data))) - n += len(x.Data) - case *Communique_TempC: - n += proto.SizeVarint(8<<3 | proto.WireFixed64) - n += 8 - case *Communique_Height: - n += proto.SizeVarint(9<<3 | proto.WireFixed32) - n += 4 - case *Communique_Today: - n += proto.SizeVarint(10<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Today)) - case *Communique_Maybe: - n += proto.SizeVarint(11<<3 | proto.WireVarint) - n += 1 - case *Communique_Delta_: - n += proto.SizeVarint(12<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64((uint32(x.Delta) << 1) ^ uint32((int32(x.Delta) >> 31)))) - case *Communique_Msg: - s := proto.Size(x.Msg) - n += proto.SizeVarint(13<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Communique_Somegroup: - n += proto.SizeVarint(14<<3 | proto.WireStartGroup) - n += proto.Size(x.Somegroup) - n += proto.SizeVarint(14<<3 | proto.WireEndGroup) - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type Communique_SomeGroup struct { - Member *string `protobuf:"bytes,15,opt,name=member" json:"member,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Communique_SomeGroup) Reset() { *m = Communique_SomeGroup{} } -func (m *Communique_SomeGroup) String() string { return proto.CompactTextString(m) } -func (*Communique_SomeGroup) ProtoMessage() {} - -func (m *Communique_SomeGroup) GetMember() string { - if m != nil && m.Member != nil { - return *m.Member - } - return "" -} - -type Communique_Delta struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *Communique_Delta) Reset() { *m = Communique_Delta{} } -func (m *Communique_Delta) String() string { return proto.CompactTextString(m) } -func (*Communique_Delta) ProtoMessage() {} - -var E_Tag = &proto.ExtensionDesc{ - ExtendedType: (*Reply)(nil), - ExtensionType: (*string)(nil), - Field: 103, - Name: "my.test.tag", - Tag: "bytes,103,opt,name=tag", - Filename: "my_test/test.proto", -} - -var E_Donut = &proto.ExtensionDesc{ - ExtendedType: (*Reply)(nil), - ExtensionType: (*OtherReplyExtensions)(nil), - Field: 106, - Name: "my.test.donut", - Tag: "bytes,106,opt,name=donut", - Filename: "my_test/test.proto", -} - -func init() { - proto.RegisterType((*Request)(nil), "my.test.Request") - proto.RegisterType((*Request_SomeGroup)(nil), "my.test.Request.SomeGroup") - proto.RegisterType((*Reply)(nil), "my.test.Reply") - proto.RegisterType((*Reply_Entry)(nil), "my.test.Reply.Entry") - proto.RegisterType((*OtherBase)(nil), "my.test.OtherBase") - proto.RegisterType((*ReplyExtensions)(nil), "my.test.ReplyExtensions") - proto.RegisterType((*OtherReplyExtensions)(nil), "my.test.OtherReplyExtensions") - proto.RegisterType((*OldReply)(nil), "my.test.OldReply") - proto.RegisterType((*Communique)(nil), "my.test.Communique") - proto.RegisterType((*Communique_SomeGroup)(nil), "my.test.Communique.SomeGroup") - proto.RegisterType((*Communique_Delta)(nil), "my.test.Communique.Delta") - proto.RegisterEnum("my.test.HatType", HatType_name, HatType_value) - proto.RegisterEnum("my.test.Days", Days_name, Days_value) - proto.RegisterEnum("my.test.Request_Color", Request_Color_name, Request_Color_value) - proto.RegisterEnum("my.test.Reply_Entry_Game", Reply_Entry_Game_name, Reply_Entry_Game_value) - proto.RegisterExtension(E_ReplyExtensions_Time) - proto.RegisterExtension(E_ReplyExtensions_Carrot) - proto.RegisterExtension(E_ReplyExtensions_Donut) - proto.RegisterExtension(E_Tag) - proto.RegisterExtension(E_Donut) -} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.proto index 8e709463..1ef3fd02 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/my_test/test.proto @@ -34,6 +34,8 @@ syntax = "proto2"; // This package holds interesting messages. package my.test; // dotted package name +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/my_test;test"; + //import "imp.proto"; import "multi/multi1.proto"; // unused import @@ -145,7 +147,7 @@ message Communique { Days today = 10; bool maybe = 11; sint32 delta = 12; // name will conflict with Delta below - Reply msg = 13; + Reply msg = 16; // requires two bytes to encode field tag group SomeGroup = 14 { optional string member = 15; } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3/proto3.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3/proto3.pb.go new file mode 100644 index 00000000..1ad010a1 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3/proto3.pb.go @@ -0,0 +1,196 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: proto3/proto3.proto + +package proto3 // import "github.com/golang/protobuf/protoc-gen-go/testdata/proto3" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Request_Flavour int32 + +const ( + Request_SWEET Request_Flavour = 0 + Request_SOUR Request_Flavour = 1 + Request_UMAMI Request_Flavour = 2 + Request_GOPHERLICIOUS Request_Flavour = 3 +) + +var Request_Flavour_name = map[int32]string{ + 0: "SWEET", + 1: "SOUR", + 2: "UMAMI", + 3: "GOPHERLICIOUS", +} +var Request_Flavour_value = map[string]int32{ + "SWEET": 0, + "SOUR": 1, + "UMAMI": 2, + "GOPHERLICIOUS": 3, +} + +func (x Request_Flavour) String() string { + return proto.EnumName(Request_Flavour_name, int32(x)) +} +func (Request_Flavour) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_proto3_a752e09251f17e01, []int{0, 0} +} + +type Request struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Key []int64 `protobuf:"varint,2,rep,packed,name=key,proto3" json:"key,omitempty"` + Taste Request_Flavour `protobuf:"varint,3,opt,name=taste,proto3,enum=proto3.Request_Flavour" json:"taste,omitempty"` + Book *Book `protobuf:"bytes,4,opt,name=book,proto3" json:"book,omitempty"` + Unpacked []int64 `protobuf:"varint,5,rep,name=unpacked,proto3" json:"unpacked,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_a752e09251f17e01, []int{0} +} +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) +} +func (dst *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(dst, src) +} +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo + +func (m *Request) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Request) GetKey() []int64 { + if m != nil { + return m.Key + } + return nil +} + +func (m *Request) GetTaste() Request_Flavour { + if m != nil { + return m.Taste + } + return Request_SWEET +} + +func (m *Request) GetBook() *Book { + if m != nil { + return m.Book + } + return nil +} + +func (m *Request) GetUnpacked() []int64 { + if m != nil { + return m.Unpacked + } + return nil +} + +type Book struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + RawData []byte `protobuf:"bytes,2,opt,name=raw_data,json=rawData,proto3" json:"raw_data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Book) Reset() { *m = Book{} } +func (m *Book) String() string { return proto.CompactTextString(m) } +func (*Book) ProtoMessage() {} +func (*Book) Descriptor() ([]byte, []int) { + return fileDescriptor_proto3_a752e09251f17e01, []int{1} +} +func (m *Book) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Book.Unmarshal(m, b) +} +func (m *Book) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Book.Marshal(b, m, deterministic) +} +func (dst *Book) XXX_Merge(src proto.Message) { + xxx_messageInfo_Book.Merge(dst, src) +} +func (m *Book) XXX_Size() int { + return xxx_messageInfo_Book.Size(m) +} +func (m *Book) XXX_DiscardUnknown() { + xxx_messageInfo_Book.DiscardUnknown(m) +} + +var xxx_messageInfo_Book proto.InternalMessageInfo + +func (m *Book) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *Book) GetRawData() []byte { + if m != nil { + return m.RawData + } + return nil +} + +func init() { + proto.RegisterType((*Request)(nil), "proto3.Request") + proto.RegisterType((*Book)(nil), "proto3.Book") + proto.RegisterEnum("proto3.Request_Flavour", Request_Flavour_name, Request_Flavour_value) +} + +func init() { proto.RegisterFile("proto3/proto3.proto", fileDescriptor_proto3_a752e09251f17e01) } + +var fileDescriptor_proto3_a752e09251f17e01 = []byte{ + // 306 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0xcf, 0x4e, 0xf2, 0x40, + 0x14, 0xc5, 0x99, 0xfe, 0xf9, 0x80, 0xfb, 0xa1, 0x19, 0xaf, 0x26, 0x8e, 0x1b, 0x33, 0x61, 0xd5, + 0x0d, 0x25, 0xc1, 0x85, 0xc6, 0xb8, 0x11, 0x45, 0x25, 0x91, 0x60, 0x06, 0x89, 0x89, 0x1b, 0x33, + 0x85, 0xb1, 0x92, 0x42, 0x07, 0xcb, 0x54, 0xe2, 0xcb, 0xfa, 0x2c, 0xa6, 0x9d, 0xe2, 0xea, 0x9e, + 0x7b, 0xe7, 0xe4, 0x77, 0x32, 0x07, 0x0e, 0xd7, 0x99, 0x36, 0xfa, 0xac, 0x6b, 0x47, 0x58, 0x0e, + 0xfc, 0x67, 0xb7, 0xf6, 0x0f, 0x81, 0xba, 0x50, 0x9f, 0xb9, 0xda, 0x18, 0x44, 0xf0, 0x52, 0xb9, + 0x52, 0x8c, 0x70, 0x12, 0x34, 0x45, 0xa9, 0x91, 0x82, 0x9b, 0xa8, 0x6f, 0xe6, 0x70, 0x37, 0x70, + 0x45, 0x21, 0xb1, 0x03, 0xbe, 0x91, 0x1b, 0xa3, 0x98, 0xcb, 0x49, 0xb0, 0xdf, 0x3b, 0x0e, 0x2b, + 0x6e, 0x45, 0x09, 0xef, 0x96, 0xf2, 0x4b, 0xe7, 0x99, 0xb0, 0x2e, 0xe4, 0xe0, 0x45, 0x5a, 0x27, + 0xcc, 0xe3, 0x24, 0xf8, 0xdf, 0x6b, 0xed, 0xdc, 0x7d, 0xad, 0x13, 0x51, 0xbe, 0xe0, 0x29, 0x34, + 0xf2, 0x74, 0x2d, 0x67, 0x89, 0x9a, 0x33, 0xbf, 0xc8, 0xe9, 0x3b, 0xb4, 0x26, 0xfe, 0x6e, 0xed, + 0x2b, 0xa8, 0x57, 0x4c, 0x6c, 0x82, 0x3f, 0x79, 0x19, 0x0c, 0x9e, 0x69, 0x0d, 0x1b, 0xe0, 0x4d, + 0xc6, 0x53, 0x41, 0x49, 0x71, 0x9c, 0x8e, 0xae, 0x47, 0x43, 0xea, 0xe0, 0x01, 0xec, 0xdd, 0x8f, + 0x9f, 0x1e, 0x06, 0xe2, 0x71, 0x78, 0x33, 0x1c, 0x4f, 0x27, 0xd4, 0x6d, 0x9f, 0x83, 0x57, 0x64, + 0xe1, 0x11, 0xf8, 0x66, 0x61, 0x96, 0xbb, 0xdf, 0xd9, 0x05, 0x4f, 0xa0, 0x91, 0xc9, 0xed, 0xdb, + 0x5c, 0x1a, 0xc9, 0x1c, 0x4e, 0x82, 0x96, 0xa8, 0x67, 0x72, 0x7b, 0x2b, 0x8d, 0xec, 0x5f, 0xbe, + 0x5e, 0xc4, 0x0b, 0xf3, 0x91, 0x47, 0xe1, 0x4c, 0xaf, 0xba, 0xb1, 0x5e, 0xca, 0x34, 0xb6, 0x1d, + 0x46, 0xf9, 0xbb, 0x15, 0xb3, 0x4e, 0xac, 0xd2, 0x4e, 0xac, 0xbb, 0x46, 0x6d, 0x4c, 0xc1, 0xa8, + 0x3a, 0x8e, 0xaa, 0x76, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xec, 0x71, 0xee, 0xdb, 0x7b, 0x01, + 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3/proto3.proto similarity index 96% rename from vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3.proto rename to vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3/proto3.proto index 869b9af5..79954e4e 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3.proto +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/testdata/proto3/proto3.proto @@ -33,6 +33,8 @@ syntax = "proto3"; package proto3; +option go_package = "github.com/golang/protobuf/protoc-gen-go/testdata/proto3"; + message Request { enum Flavour { SWEET = 0; diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go index b2af97f4..70276e8f 100644 --- a/vendor/github.com/golang/protobuf/ptypes/any.go +++ b/vendor/github.com/golang/protobuf/ptypes/any.go @@ -130,10 +130,12 @@ func UnmarshalAny(any *any.Any, pb proto.Message) error { // Is returns true if any value contains a given message type. func Is(any *any.Any, pb proto.Message) bool { - aname, err := AnyMessageName(any) - if err != nil { + // The following is equivalent to AnyMessageName(any) == proto.MessageName(pb), + // but it avoids scanning TypeUrl for the slash. + if any == nil { return false } - - return aname == proto.MessageName(pb) + name := proto.MessageName(pb) + prefix := len(any.TypeUrl) - len(name) + return prefix >= 1 && any.TypeUrl[prefix-1] == '/' && any.TypeUrl[prefix:] == name } diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go index f3460172..e3c56d3f 100644 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go @@ -1,16 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/any.proto -/* -Package any is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/any.proto - -It has these top-level messages: - Any -*/ -package any +package any // import "github.com/golang/protobuf/ptypes/any" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -130,16 +121,38 @@ type Any struct { // Schemes other than `http`, `https` (or the empty scheme) might be // used with implementation specific semantics. // - TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"` + TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"` // Must be a valid serialized protocol buffer of the above specified type. - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Any) Reset() { *m = Any{} } -func (m *Any) String() string { return proto.CompactTextString(m) } -func (*Any) ProtoMessage() {} -func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (*Any) XXX_WellKnownType() string { return "Any" } +func (m *Any) Reset() { *m = Any{} } +func (m *Any) String() string { return proto.CompactTextString(m) } +func (*Any) ProtoMessage() {} +func (*Any) Descriptor() ([]byte, []int) { + return fileDescriptor_any_744b9ca530f228db, []int{0} +} +func (*Any) XXX_WellKnownType() string { return "Any" } +func (m *Any) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Any.Unmarshal(m, b) +} +func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Any.Marshal(b, m, deterministic) +} +func (dst *Any) XXX_Merge(src proto.Message) { + xxx_messageInfo_Any.Merge(dst, src) +} +func (m *Any) XXX_Size() int { + return xxx_messageInfo_Any.Size(m) +} +func (m *Any) XXX_DiscardUnknown() { + xxx_messageInfo_Any.DiscardUnknown(m) +} + +var xxx_messageInfo_Any proto.InternalMessageInfo func (m *Any) GetTypeUrl() string { if m != nil { @@ -159,9 +172,9 @@ func init() { proto.RegisterType((*Any)(nil), "google.protobuf.Any") } -func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor0) } +func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) } -var fileDescriptor0 = []byte{ +var fileDescriptor_any_744b9ca530f228db = []byte{ // 185 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, diff --git a/vendor/github.com/golang/protobuf/ptypes/any_test.go b/vendor/github.com/golang/protobuf/ptypes/any_test.go index ed675b48..871c6de1 100644 --- a/vendor/github.com/golang/protobuf/ptypes/any_test.go +++ b/vendor/github.com/golang/protobuf/ptypes/any_test.go @@ -60,8 +60,13 @@ func TestIs(t *testing.T) { t.Fatal(err) } if Is(a, &pb.DescriptorProto{}) { + // No spurious match for message names of different length. t.Error("FileDescriptorProto is not a DescriptorProto, but Is says it is") } + if Is(a, &pb.EnumDescriptorProto{}) { + // No spurious match for message names of equal length. + t.Error("FileDescriptorProto is not an EnumDescriptorProto, but Is says it is") + } if !Is(a, &pb.FileDescriptorProto{}) { t.Error("FileDescriptorProto is indeed a FileDescriptorProto, but Is says it is not") } @@ -75,6 +80,21 @@ func TestIsDifferentUrlPrefixes(t *testing.T) { } } +func TestIsCornerCases(t *testing.T) { + m := &pb.FileDescriptorProto{} + if Is(nil, m) { + t.Errorf("message with nil type url incorrectly claimed to be %q", proto.MessageName(m)) + } + noPrefix := &any.Any{TypeUrl: proto.MessageName(m)} + if Is(noPrefix, m) { + t.Errorf("message with type url %q incorrectly claimed to be %q", noPrefix.TypeUrl, proto.MessageName(m)) + } + shortPrefix := &any.Any{TypeUrl: "/" + proto.MessageName(m)} + if !Is(shortPrefix, m) { + t.Errorf("message with type url %q didn't satisfy Is for type %q", shortPrefix.TypeUrl, proto.MessageName(m)) + } +} + func TestUnmarshalDynamic(t *testing.T) { want := &pb.FileDescriptorProto{Name: proto.String("foo")} a, err := MarshalAny(want) @@ -111,3 +131,24 @@ func TestEmpty(t *testing.T) { t.Errorf("got no error for an attempt to create a message of type %q, which shouldn't be linked in", a.TypeUrl) } } + +func TestEmptyCornerCases(t *testing.T) { + _, err := Empty(nil) + if err == nil { + t.Error("expected Empty for nil to fail") + } + want := &pb.FileDescriptorProto{} + noPrefix := &any.Any{TypeUrl: proto.MessageName(want)} + _, err = Empty(noPrefix) + if err == nil { + t.Errorf("expected Empty for any type %q to fail", noPrefix.TypeUrl) + } + shortPrefix := &any.Any{TypeUrl: "/" + proto.MessageName(want)} + got, err := Empty(shortPrefix) + if err != nil { + t.Errorf("Empty for any type %q failed: %s", shortPrefix.TypeUrl, err) + } + if !proto.Equal(got, want) { + t.Errorf("Empty for any type %q differs, got %q, want %q", shortPrefix.TypeUrl, got, want) + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go index b2410a09..a7beb2c4 100644 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go @@ -1,16 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/duration.proto -/* -Package duration is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/duration.proto - -It has these top-level messages: - Duration -*/ -package duration +package duration // import "github.com/golang/protobuf/ptypes/duration" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -91,21 +82,43 @@ type Duration struct { // Signed seconds of the span of time. Must be from -315,576,000,000 // to +315,576,000,000 inclusive. Note: these bounds are computed from: // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` // Signed fractions of a second at nanosecond resolution of the span // of time. Durations less than one second are represented with a 0 // `seconds` field and a positive or negative `nanos` field. For durations // of one second or more, a non-zero value for the `nanos` field must be // of the same sign as the `seconds` field. Must be from -999,999,999 // to +999,999,999 inclusive. - Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Duration) Reset() { *m = Duration{} } -func (m *Duration) String() string { return proto.CompactTextString(m) } -func (*Duration) ProtoMessage() {} -func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (*Duration) XXX_WellKnownType() string { return "Duration" } +func (m *Duration) Reset() { *m = Duration{} } +func (m *Duration) String() string { return proto.CompactTextString(m) } +func (*Duration) ProtoMessage() {} +func (*Duration) Descriptor() ([]byte, []int) { + return fileDescriptor_duration_e7d612259e3f0613, []int{0} +} +func (*Duration) XXX_WellKnownType() string { return "Duration" } +func (m *Duration) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Duration.Unmarshal(m, b) +} +func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Duration.Marshal(b, m, deterministic) +} +func (dst *Duration) XXX_Merge(src proto.Message) { + xxx_messageInfo_Duration.Merge(dst, src) +} +func (m *Duration) XXX_Size() int { + return xxx_messageInfo_Duration.Size(m) +} +func (m *Duration) XXX_DiscardUnknown() { + xxx_messageInfo_Duration.DiscardUnknown(m) +} + +var xxx_messageInfo_Duration proto.InternalMessageInfo func (m *Duration) GetSeconds() int64 { if m != nil { @@ -125,9 +138,11 @@ func init() { proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") } -func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor0) } +func init() { + proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613) +} -var fileDescriptor0 = []byte{ +var fileDescriptor_duration_e7d612259e3f0613 = []byte{ // 190 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a, diff --git a/vendor/github.com/golang/protobuf/ptypes/empty/empty.pb.go b/vendor/github.com/golang/protobuf/ptypes/empty/empty.pb.go index e877b72c..a69b403c 100644 --- a/vendor/github.com/golang/protobuf/ptypes/empty/empty.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/empty/empty.pb.go @@ -1,16 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/empty.proto -/* -Package empty is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/empty.proto - -It has these top-level messages: - Empty -*/ -package empty +package empty // import "github.com/golang/protobuf/ptypes/empty" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -37,21 +28,43 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package // // The JSON representation for `Empty` is empty JSON object `{}`. type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Empty) Reset() { *m = Empty{} } -func (m *Empty) String() string { return proto.CompactTextString(m) } -func (*Empty) ProtoMessage() {} -func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (*Empty) XXX_WellKnownType() string { return "Empty" } +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_empty_39e6d6db0632e5b2, []int{0} +} +func (*Empty) XXX_WellKnownType() string { return "Empty" } +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (dst *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(dst, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo func init() { proto.RegisterType((*Empty)(nil), "google.protobuf.Empty") } -func init() { proto.RegisterFile("google/protobuf/empty.proto", fileDescriptor0) } +func init() { proto.RegisterFile("google/protobuf/empty.proto", fileDescriptor_empty_39e6d6db0632e5b2) } -var fileDescriptor0 = []byte{ +var fileDescriptor_empty_39e6d6db0632e5b2 = []byte{ // 148 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcd, 0x2d, 0x28, diff --git a/vendor/github.com/golang/protobuf/ptypes/regen.sh b/vendor/github.com/golang/protobuf/ptypes/regen.sh deleted file mode 100755 index b50a9414..00000000 --- a/vendor/github.com/golang/protobuf/ptypes/regen.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -e -# -# This script fetches and rebuilds the "well-known types" protocol buffers. -# To run this you will need protoc and goprotobuf installed; -# see https://github.com/golang/protobuf for instructions. -# You also need Go and Git installed. - -PKG=github.com/golang/protobuf/ptypes -UPSTREAM=https://github.com/google/protobuf -UPSTREAM_SUBDIR=src/google/protobuf -PROTO_FILES=(any duration empty struct timestamp wrappers) - -function die() { - echo 1>&2 $* - exit 1 -} - -# Sanity check that the right tools are accessible. -for tool in go git protoc protoc-gen-go; do - q=$(which $tool) || die "didn't find $tool" - echo 1>&2 "$tool: $q" -done - -tmpdir=$(mktemp -d -t regen-wkt.XXXXXX) -trap 'rm -rf $tmpdir' EXIT - -echo -n 1>&2 "finding package dir... " -pkgdir=$(go list -f '{{.Dir}}' $PKG) -echo 1>&2 $pkgdir -base=$(echo $pkgdir | sed "s,/$PKG\$,,") -echo 1>&2 "base: $base" -cd "$base" - -echo 1>&2 "fetching latest protos... " -git clone -q $UPSTREAM $tmpdir - -for file in ${PROTO_FILES[@]}; do - echo 1>&2 "* $file" - protoc --go_out=. -I$tmpdir/src $tmpdir/src/google/protobuf/$file.proto || die - cp $tmpdir/src/google/protobuf/$file.proto $PKG/$file -done - -echo 1>&2 "All OK" diff --git a/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go b/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go index 4cfe6081..ee6382e1 100644 --- a/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go @@ -1,18 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/struct.proto -/* -Package structpb is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/struct.proto - -It has these top-level messages: - Struct - Value - ListValue -*/ -package structpb +package structpb // import "github.com/golang/protobuf/ptypes/struct" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -50,8 +39,10 @@ var NullValue_value = map[string]int32{ func (x NullValue) String() string { return proto.EnumName(NullValue_name, int32(x)) } -func (NullValue) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (NullValue) XXX_WellKnownType() string { return "NullValue" } +func (NullValue) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_struct_3a5a94e0c7801b27, []int{0} +} +func (NullValue) XXX_WellKnownType() string { return "NullValue" } // `Struct` represents a structured data value, consisting of fields // which map to dynamically typed values. In some languages, `Struct` @@ -63,14 +54,36 @@ func (NullValue) XXX_WellKnownType() string { return "NullValue" } // The JSON representation for `Struct` is JSON object. type Struct struct { // Unordered map of dynamically typed values. - Fields map[string]*Value `protobuf:"bytes,1,rep,name=fields" json:"fields,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Fields map[string]*Value `protobuf:"bytes,1,rep,name=fields,proto3" json:"fields,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Struct) Reset() { *m = Struct{} } -func (m *Struct) String() string { return proto.CompactTextString(m) } -func (*Struct) ProtoMessage() {} -func (*Struct) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (*Struct) XXX_WellKnownType() string { return "Struct" } +func (m *Struct) Reset() { *m = Struct{} } +func (m *Struct) String() string { return proto.CompactTextString(m) } +func (*Struct) ProtoMessage() {} +func (*Struct) Descriptor() ([]byte, []int) { + return fileDescriptor_struct_3a5a94e0c7801b27, []int{0} +} +func (*Struct) XXX_WellKnownType() string { return "Struct" } +func (m *Struct) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Struct.Unmarshal(m, b) +} +func (m *Struct) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Struct.Marshal(b, m, deterministic) +} +func (dst *Struct) XXX_Merge(src proto.Message) { + xxx_messageInfo_Struct.Merge(dst, src) +} +func (m *Struct) XXX_Size() int { + return xxx_messageInfo_Struct.Size(m) +} +func (m *Struct) XXX_DiscardUnknown() { + xxx_messageInfo_Struct.DiscardUnknown(m) +} + +var xxx_messageInfo_Struct proto.InternalMessageInfo func (m *Struct) GetFields() map[string]*Value { if m != nil { @@ -95,44 +108,76 @@ type Value struct { // *Value_BoolValue // *Value_StructValue // *Value_ListValue - Kind isValue_Kind `protobuf_oneof:"kind"` + Kind isValue_Kind `protobuf_oneof:"kind"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Value) Reset() { *m = Value{} } -func (m *Value) String() string { return proto.CompactTextString(m) } -func (*Value) ProtoMessage() {} -func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } -func (*Value) XXX_WellKnownType() string { return "Value" } +func (m *Value) Reset() { *m = Value{} } +func (m *Value) String() string { return proto.CompactTextString(m) } +func (*Value) ProtoMessage() {} +func (*Value) Descriptor() ([]byte, []int) { + return fileDescriptor_struct_3a5a94e0c7801b27, []int{1} +} +func (*Value) XXX_WellKnownType() string { return "Value" } +func (m *Value) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Value.Unmarshal(m, b) +} +func (m *Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Value.Marshal(b, m, deterministic) +} +func (dst *Value) XXX_Merge(src proto.Message) { + xxx_messageInfo_Value.Merge(dst, src) +} +func (m *Value) XXX_Size() int { + return xxx_messageInfo_Value.Size(m) +} +func (m *Value) XXX_DiscardUnknown() { + xxx_messageInfo_Value.DiscardUnknown(m) +} + +var xxx_messageInfo_Value proto.InternalMessageInfo type isValue_Kind interface { isValue_Kind() } type Value_NullValue struct { - NullValue NullValue `protobuf:"varint,1,opt,name=null_value,json=nullValue,enum=google.protobuf.NullValue,oneof"` -} -type Value_NumberValue struct { - NumberValue float64 `protobuf:"fixed64,2,opt,name=number_value,json=numberValue,oneof"` -} -type Value_StringValue struct { - StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,oneof"` -} -type Value_BoolValue struct { - BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,oneof"` -} -type Value_StructValue struct { - StructValue *Struct `protobuf:"bytes,5,opt,name=struct_value,json=structValue,oneof"` -} -type Value_ListValue struct { - ListValue *ListValue `protobuf:"bytes,6,opt,name=list_value,json=listValue,oneof"` + NullValue NullValue `protobuf:"varint,1,opt,name=null_value,json=nullValue,proto3,enum=google.protobuf.NullValue,oneof"` } -func (*Value_NullValue) isValue_Kind() {} +type Value_NumberValue struct { + NumberValue float64 `protobuf:"fixed64,2,opt,name=number_value,json=numberValue,proto3,oneof"` +} + +type Value_StringValue struct { + StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"` +} + +type Value_BoolValue struct { + BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"` +} + +type Value_StructValue struct { + StructValue *Struct `protobuf:"bytes,5,opt,name=struct_value,json=structValue,proto3,oneof"` +} + +type Value_ListValue struct { + ListValue *ListValue `protobuf:"bytes,6,opt,name=list_value,json=listValue,proto3,oneof"` +} + +func (*Value_NullValue) isValue_Kind() {} + func (*Value_NumberValue) isValue_Kind() {} + func (*Value_StringValue) isValue_Kind() {} -func (*Value_BoolValue) isValue_Kind() {} + +func (*Value_BoolValue) isValue_Kind() {} + func (*Value_StructValue) isValue_Kind() {} -func (*Value_ListValue) isValue_Kind() {} + +func (*Value_ListValue) isValue_Kind() {} func (m *Value) GetKind() isValue_Kind { if m != nil { @@ -289,26 +334,26 @@ func _Value_OneofSizer(msg proto.Message) (n int) { // kind switch x := m.Kind.(type) { case *Value_NullValue: - n += proto.SizeVarint(1<<3 | proto.WireVarint) + n += 1 // tag and wire n += proto.SizeVarint(uint64(x.NullValue)) case *Value_NumberValue: - n += proto.SizeVarint(2<<3 | proto.WireFixed64) + n += 1 // tag and wire n += 8 case *Value_StringValue: - n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(len(x.StringValue))) n += len(x.StringValue) case *Value_BoolValue: - n += proto.SizeVarint(4<<3 | proto.WireVarint) + n += 1 // tag and wire n += 1 case *Value_StructValue: s := proto.Size(x.StructValue) - n += proto.SizeVarint(5<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(s)) n += s case *Value_ListValue: s := proto.Size(x.ListValue) - n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += 1 // tag and wire n += proto.SizeVarint(uint64(s)) n += s case nil: @@ -323,14 +368,36 @@ func _Value_OneofSizer(msg proto.Message) (n int) { // The JSON representation for `ListValue` is JSON array. type ListValue struct { // Repeated field of dynamically typed values. - Values []*Value `protobuf:"bytes,1,rep,name=values" json:"values,omitempty"` + Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ListValue) Reset() { *m = ListValue{} } -func (m *ListValue) String() string { return proto.CompactTextString(m) } -func (*ListValue) ProtoMessage() {} -func (*ListValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } -func (*ListValue) XXX_WellKnownType() string { return "ListValue" } +func (m *ListValue) Reset() { *m = ListValue{} } +func (m *ListValue) String() string { return proto.CompactTextString(m) } +func (*ListValue) ProtoMessage() {} +func (*ListValue) Descriptor() ([]byte, []int) { + return fileDescriptor_struct_3a5a94e0c7801b27, []int{2} +} +func (*ListValue) XXX_WellKnownType() string { return "ListValue" } +func (m *ListValue) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListValue.Unmarshal(m, b) +} +func (m *ListValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListValue.Marshal(b, m, deterministic) +} +func (dst *ListValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListValue.Merge(dst, src) +} +func (m *ListValue) XXX_Size() int { + return xxx_messageInfo_ListValue.Size(m) +} +func (m *ListValue) XXX_DiscardUnknown() { + xxx_messageInfo_ListValue.DiscardUnknown(m) +} + +var xxx_messageInfo_ListValue proto.InternalMessageInfo func (m *ListValue) GetValues() []*Value { if m != nil { @@ -341,14 +408,17 @@ func (m *ListValue) GetValues() []*Value { func init() { proto.RegisterType((*Struct)(nil), "google.protobuf.Struct") + proto.RegisterMapType((map[string]*Value)(nil), "google.protobuf.Struct.FieldsEntry") proto.RegisterType((*Value)(nil), "google.protobuf.Value") proto.RegisterType((*ListValue)(nil), "google.protobuf.ListValue") proto.RegisterEnum("google.protobuf.NullValue", NullValue_name, NullValue_value) } -func init() { proto.RegisterFile("google/protobuf/struct.proto", fileDescriptor0) } +func init() { + proto.RegisterFile("google/protobuf/struct.proto", fileDescriptor_struct_3a5a94e0c7801b27) +} -var fileDescriptor0 = []byte{ +var fileDescriptor_struct_3a5a94e0c7801b27 = []byte{ // 417 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x41, 0x8b, 0xd3, 0x40, 0x14, 0xc7, 0x3b, 0xc9, 0x36, 0x98, 0x17, 0x59, 0x97, 0x11, 0xb4, 0xac, 0xa2, 0xa1, 0x7b, 0x09, diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go index e23e4a25..8e76ae97 100644 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go @@ -1,16 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/timestamp.proto -/* -Package timestamp is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/timestamp.proto - -It has these top-level messages: - Timestamp -*/ -package timestamp +package timestamp // import "github.com/golang/protobuf/ptypes/timestamp" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -101,7 +92,7 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package // to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) // with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one // can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()) +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--) // to obtain a formatter capable of generating timestamps in this format. // // @@ -109,19 +100,41 @@ type Timestamp struct { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to // 9999-12-31T23:59:59Z inclusive. - Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` // Non-negative fractions of a second at nanosecond resolution. Negative // second values with fractions must still have non-negative nanos values // that count forward in time. Must be from 0 to 999,999,999 // inclusive. - Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Timestamp) Reset() { *m = Timestamp{} } -func (m *Timestamp) String() string { return proto.CompactTextString(m) } -func (*Timestamp) ProtoMessage() {} -func (*Timestamp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } +func (m *Timestamp) Reset() { *m = Timestamp{} } +func (m *Timestamp) String() string { return proto.CompactTextString(m) } +func (*Timestamp) ProtoMessage() {} +func (*Timestamp) Descriptor() ([]byte, []int) { + return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0} +} +func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } +func (m *Timestamp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Timestamp.Unmarshal(m, b) +} +func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic) +} +func (dst *Timestamp) XXX_Merge(src proto.Message) { + xxx_messageInfo_Timestamp.Merge(dst, src) +} +func (m *Timestamp) XXX_Size() int { + return xxx_messageInfo_Timestamp.Size(m) +} +func (m *Timestamp) XXX_DiscardUnknown() { + xxx_messageInfo_Timestamp.DiscardUnknown(m) +} + +var xxx_messageInfo_Timestamp proto.InternalMessageInfo func (m *Timestamp) GetSeconds() int64 { if m != nil { @@ -141,9 +154,11 @@ func init() { proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") } -func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor0) } +func init() { + proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8) +} -var fileDescriptor0 = []byte{ +var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{ // 191 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d, diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto index b7cbd175..06750ab1 100644 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto @@ -114,7 +114,7 @@ option objc_class_prefix = "GPB"; // to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) // with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one // can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()) +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--) // to obtain a formatter capable of generating timestamps in this format. // // diff --git a/vendor/github.com/golang/protobuf/ptypes/wrappers/wrappers.pb.go b/vendor/github.com/golang/protobuf/ptypes/wrappers/wrappers.pb.go index 0ed59bf1..0f0fa837 100644 --- a/vendor/github.com/golang/protobuf/ptypes/wrappers/wrappers.pb.go +++ b/vendor/github.com/golang/protobuf/ptypes/wrappers/wrappers.pb.go @@ -1,24 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/wrappers.proto -/* -Package wrappers is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/wrappers.proto - -It has these top-level messages: - DoubleValue - FloatValue - Int64Value - UInt64Value - Int32Value - UInt32Value - BoolValue - StringValue - BytesValue -*/ -package wrappers +package wrappers // import "github.com/golang/protobuf/ptypes/wrappers" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -40,14 +23,36 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package // The JSON representation for `DoubleValue` is JSON number. type DoubleValue struct { // The double value. - Value float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` + Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *DoubleValue) Reset() { *m = DoubleValue{} } -func (m *DoubleValue) String() string { return proto.CompactTextString(m) } -func (*DoubleValue) ProtoMessage() {} -func (*DoubleValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (*DoubleValue) XXX_WellKnownType() string { return "DoubleValue" } +func (m *DoubleValue) Reset() { *m = DoubleValue{} } +func (m *DoubleValue) String() string { return proto.CompactTextString(m) } +func (*DoubleValue) ProtoMessage() {} +func (*DoubleValue) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{0} +} +func (*DoubleValue) XXX_WellKnownType() string { return "DoubleValue" } +func (m *DoubleValue) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DoubleValue.Unmarshal(m, b) +} +func (m *DoubleValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DoubleValue.Marshal(b, m, deterministic) +} +func (dst *DoubleValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_DoubleValue.Merge(dst, src) +} +func (m *DoubleValue) XXX_Size() int { + return xxx_messageInfo_DoubleValue.Size(m) +} +func (m *DoubleValue) XXX_DiscardUnknown() { + xxx_messageInfo_DoubleValue.DiscardUnknown(m) +} + +var xxx_messageInfo_DoubleValue proto.InternalMessageInfo func (m *DoubleValue) GetValue() float64 { if m != nil { @@ -61,14 +66,36 @@ func (m *DoubleValue) GetValue() float64 { // The JSON representation for `FloatValue` is JSON number. type FloatValue struct { // The float value. - Value float32 `protobuf:"fixed32,1,opt,name=value" json:"value,omitempty"` + Value float32 `protobuf:"fixed32,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FloatValue) Reset() { *m = FloatValue{} } -func (m *FloatValue) String() string { return proto.CompactTextString(m) } -func (*FloatValue) ProtoMessage() {} -func (*FloatValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } -func (*FloatValue) XXX_WellKnownType() string { return "FloatValue" } +func (m *FloatValue) Reset() { *m = FloatValue{} } +func (m *FloatValue) String() string { return proto.CompactTextString(m) } +func (*FloatValue) ProtoMessage() {} +func (*FloatValue) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{1} +} +func (*FloatValue) XXX_WellKnownType() string { return "FloatValue" } +func (m *FloatValue) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FloatValue.Unmarshal(m, b) +} +func (m *FloatValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FloatValue.Marshal(b, m, deterministic) +} +func (dst *FloatValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_FloatValue.Merge(dst, src) +} +func (m *FloatValue) XXX_Size() int { + return xxx_messageInfo_FloatValue.Size(m) +} +func (m *FloatValue) XXX_DiscardUnknown() { + xxx_messageInfo_FloatValue.DiscardUnknown(m) +} + +var xxx_messageInfo_FloatValue proto.InternalMessageInfo func (m *FloatValue) GetValue() float32 { if m != nil { @@ -82,14 +109,36 @@ func (m *FloatValue) GetValue() float32 { // The JSON representation for `Int64Value` is JSON string. type Int64Value struct { // The int64 value. - Value int64 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Int64Value) Reset() { *m = Int64Value{} } -func (m *Int64Value) String() string { return proto.CompactTextString(m) } -func (*Int64Value) ProtoMessage() {} -func (*Int64Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } -func (*Int64Value) XXX_WellKnownType() string { return "Int64Value" } +func (m *Int64Value) Reset() { *m = Int64Value{} } +func (m *Int64Value) String() string { return proto.CompactTextString(m) } +func (*Int64Value) ProtoMessage() {} +func (*Int64Value) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{2} +} +func (*Int64Value) XXX_WellKnownType() string { return "Int64Value" } +func (m *Int64Value) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Int64Value.Unmarshal(m, b) +} +func (m *Int64Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Int64Value.Marshal(b, m, deterministic) +} +func (dst *Int64Value) XXX_Merge(src proto.Message) { + xxx_messageInfo_Int64Value.Merge(dst, src) +} +func (m *Int64Value) XXX_Size() int { + return xxx_messageInfo_Int64Value.Size(m) +} +func (m *Int64Value) XXX_DiscardUnknown() { + xxx_messageInfo_Int64Value.DiscardUnknown(m) +} + +var xxx_messageInfo_Int64Value proto.InternalMessageInfo func (m *Int64Value) GetValue() int64 { if m != nil { @@ -103,14 +152,36 @@ func (m *Int64Value) GetValue() int64 { // The JSON representation for `UInt64Value` is JSON string. type UInt64Value struct { // The uint64 value. - Value uint64 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *UInt64Value) Reset() { *m = UInt64Value{} } -func (m *UInt64Value) String() string { return proto.CompactTextString(m) } -func (*UInt64Value) ProtoMessage() {} -func (*UInt64Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } -func (*UInt64Value) XXX_WellKnownType() string { return "UInt64Value" } +func (m *UInt64Value) Reset() { *m = UInt64Value{} } +func (m *UInt64Value) String() string { return proto.CompactTextString(m) } +func (*UInt64Value) ProtoMessage() {} +func (*UInt64Value) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{3} +} +func (*UInt64Value) XXX_WellKnownType() string { return "UInt64Value" } +func (m *UInt64Value) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UInt64Value.Unmarshal(m, b) +} +func (m *UInt64Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UInt64Value.Marshal(b, m, deterministic) +} +func (dst *UInt64Value) XXX_Merge(src proto.Message) { + xxx_messageInfo_UInt64Value.Merge(dst, src) +} +func (m *UInt64Value) XXX_Size() int { + return xxx_messageInfo_UInt64Value.Size(m) +} +func (m *UInt64Value) XXX_DiscardUnknown() { + xxx_messageInfo_UInt64Value.DiscardUnknown(m) +} + +var xxx_messageInfo_UInt64Value proto.InternalMessageInfo func (m *UInt64Value) GetValue() uint64 { if m != nil { @@ -124,14 +195,36 @@ func (m *UInt64Value) GetValue() uint64 { // The JSON representation for `Int32Value` is JSON number. type Int32Value struct { // The int32 value. - Value int32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Value int32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Int32Value) Reset() { *m = Int32Value{} } -func (m *Int32Value) String() string { return proto.CompactTextString(m) } -func (*Int32Value) ProtoMessage() {} -func (*Int32Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } -func (*Int32Value) XXX_WellKnownType() string { return "Int32Value" } +func (m *Int32Value) Reset() { *m = Int32Value{} } +func (m *Int32Value) String() string { return proto.CompactTextString(m) } +func (*Int32Value) ProtoMessage() {} +func (*Int32Value) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{4} +} +func (*Int32Value) XXX_WellKnownType() string { return "Int32Value" } +func (m *Int32Value) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Int32Value.Unmarshal(m, b) +} +func (m *Int32Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Int32Value.Marshal(b, m, deterministic) +} +func (dst *Int32Value) XXX_Merge(src proto.Message) { + xxx_messageInfo_Int32Value.Merge(dst, src) +} +func (m *Int32Value) XXX_Size() int { + return xxx_messageInfo_Int32Value.Size(m) +} +func (m *Int32Value) XXX_DiscardUnknown() { + xxx_messageInfo_Int32Value.DiscardUnknown(m) +} + +var xxx_messageInfo_Int32Value proto.InternalMessageInfo func (m *Int32Value) GetValue() int32 { if m != nil { @@ -145,14 +238,36 @@ func (m *Int32Value) GetValue() int32 { // The JSON representation for `UInt32Value` is JSON number. type UInt32Value struct { // The uint32 value. - Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *UInt32Value) Reset() { *m = UInt32Value{} } -func (m *UInt32Value) String() string { return proto.CompactTextString(m) } -func (*UInt32Value) ProtoMessage() {} -func (*UInt32Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } -func (*UInt32Value) XXX_WellKnownType() string { return "UInt32Value" } +func (m *UInt32Value) Reset() { *m = UInt32Value{} } +func (m *UInt32Value) String() string { return proto.CompactTextString(m) } +func (*UInt32Value) ProtoMessage() {} +func (*UInt32Value) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{5} +} +func (*UInt32Value) XXX_WellKnownType() string { return "UInt32Value" } +func (m *UInt32Value) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UInt32Value.Unmarshal(m, b) +} +func (m *UInt32Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UInt32Value.Marshal(b, m, deterministic) +} +func (dst *UInt32Value) XXX_Merge(src proto.Message) { + xxx_messageInfo_UInt32Value.Merge(dst, src) +} +func (m *UInt32Value) XXX_Size() int { + return xxx_messageInfo_UInt32Value.Size(m) +} +func (m *UInt32Value) XXX_DiscardUnknown() { + xxx_messageInfo_UInt32Value.DiscardUnknown(m) +} + +var xxx_messageInfo_UInt32Value proto.InternalMessageInfo func (m *UInt32Value) GetValue() uint32 { if m != nil { @@ -166,14 +281,36 @@ func (m *UInt32Value) GetValue() uint32 { // The JSON representation for `BoolValue` is JSON `true` and `false`. type BoolValue struct { // The bool value. - Value bool `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Value bool `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *BoolValue) Reset() { *m = BoolValue{} } -func (m *BoolValue) String() string { return proto.CompactTextString(m) } -func (*BoolValue) ProtoMessage() {} -func (*BoolValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } -func (*BoolValue) XXX_WellKnownType() string { return "BoolValue" } +func (m *BoolValue) Reset() { *m = BoolValue{} } +func (m *BoolValue) String() string { return proto.CompactTextString(m) } +func (*BoolValue) ProtoMessage() {} +func (*BoolValue) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{6} +} +func (*BoolValue) XXX_WellKnownType() string { return "BoolValue" } +func (m *BoolValue) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BoolValue.Unmarshal(m, b) +} +func (m *BoolValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BoolValue.Marshal(b, m, deterministic) +} +func (dst *BoolValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_BoolValue.Merge(dst, src) +} +func (m *BoolValue) XXX_Size() int { + return xxx_messageInfo_BoolValue.Size(m) +} +func (m *BoolValue) XXX_DiscardUnknown() { + xxx_messageInfo_BoolValue.DiscardUnknown(m) +} + +var xxx_messageInfo_BoolValue proto.InternalMessageInfo func (m *BoolValue) GetValue() bool { if m != nil { @@ -187,14 +324,36 @@ func (m *BoolValue) GetValue() bool { // The JSON representation for `StringValue` is JSON string. type StringValue struct { // The string value. - Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *StringValue) Reset() { *m = StringValue{} } -func (m *StringValue) String() string { return proto.CompactTextString(m) } -func (*StringValue) ProtoMessage() {} -func (*StringValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } -func (*StringValue) XXX_WellKnownType() string { return "StringValue" } +func (m *StringValue) Reset() { *m = StringValue{} } +func (m *StringValue) String() string { return proto.CompactTextString(m) } +func (*StringValue) ProtoMessage() {} +func (*StringValue) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{7} +} +func (*StringValue) XXX_WellKnownType() string { return "StringValue" } +func (m *StringValue) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StringValue.Unmarshal(m, b) +} +func (m *StringValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StringValue.Marshal(b, m, deterministic) +} +func (dst *StringValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_StringValue.Merge(dst, src) +} +func (m *StringValue) XXX_Size() int { + return xxx_messageInfo_StringValue.Size(m) +} +func (m *StringValue) XXX_DiscardUnknown() { + xxx_messageInfo_StringValue.DiscardUnknown(m) +} + +var xxx_messageInfo_StringValue proto.InternalMessageInfo func (m *StringValue) GetValue() string { if m != nil { @@ -208,14 +367,36 @@ func (m *StringValue) GetValue() string { // The JSON representation for `BytesValue` is JSON string. type BytesValue struct { // The bytes value. - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *BytesValue) Reset() { *m = BytesValue{} } -func (m *BytesValue) String() string { return proto.CompactTextString(m) } -func (*BytesValue) ProtoMessage() {} -func (*BytesValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } -func (*BytesValue) XXX_WellKnownType() string { return "BytesValue" } +func (m *BytesValue) Reset() { *m = BytesValue{} } +func (m *BytesValue) String() string { return proto.CompactTextString(m) } +func (*BytesValue) ProtoMessage() {} +func (*BytesValue) Descriptor() ([]byte, []int) { + return fileDescriptor_wrappers_16c7c35c009f3253, []int{8} +} +func (*BytesValue) XXX_WellKnownType() string { return "BytesValue" } +func (m *BytesValue) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BytesValue.Unmarshal(m, b) +} +func (m *BytesValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BytesValue.Marshal(b, m, deterministic) +} +func (dst *BytesValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_BytesValue.Merge(dst, src) +} +func (m *BytesValue) XXX_Size() int { + return xxx_messageInfo_BytesValue.Size(m) +} +func (m *BytesValue) XXX_DiscardUnknown() { + xxx_messageInfo_BytesValue.DiscardUnknown(m) +} + +var xxx_messageInfo_BytesValue proto.InternalMessageInfo func (m *BytesValue) GetValue() []byte { if m != nil { @@ -236,9 +417,11 @@ func init() { proto.RegisterType((*BytesValue)(nil), "google.protobuf.BytesValue") } -func init() { proto.RegisterFile("google/protobuf/wrappers.proto", fileDescriptor0) } +func init() { + proto.RegisterFile("google/protobuf/wrappers.proto", fileDescriptor_wrappers_16c7c35c009f3253) +} -var fileDescriptor0 = []byte{ +var fileDescriptor_wrappers_16c7c35c009f3253 = []byte{ // 259 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0x2f, 0x4a, 0x2c, diff --git a/vendor/github.com/golang/protobuf/regenerate.sh b/vendor/github.com/golang/protobuf/regenerate.sh new file mode 100755 index 00000000..dc7e2d1f --- /dev/null +++ b/vendor/github.com/golang/protobuf/regenerate.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -e + +# Install the working tree's protoc-gen-gen in a tempdir. +tmpdir=$(mktemp -d -t regen-wkt.XXXXXX) +trap 'rm -rf $tmpdir' EXIT +mkdir -p $tmpdir/bin +PATH=$tmpdir/bin:$PATH +GOBIN=$tmpdir/bin go install ./protoc-gen-go + +# Public imports require at least Go 1.9. +supportTypeAliases="" +if go list -f '{{context.ReleaseTags}}' runtime | grep -q go1.9; then + supportTypeAliases=1 +fi + +# Generate various test protos. +PROTO_DIRS=( + conformance/internal/conformance_proto + jsonpb/jsonpb_test_proto + proto + protoc-gen-go/testdata +) +for dir in ${PROTO_DIRS[@]}; do + for p in `find $dir -name "*.proto"`; do + if [[ $p == */import_public/* && ! $supportTypeAliases ]]; then + echo "# $p (skipped)" + continue; + fi + echo "# $p" + protoc -I$dir --go_out=plugins=grpc,paths=source_relative:$dir $p + done +done + +# Deriving the location of the source protos from the path to the +# protoc binary may be a bit odd, but this is what protoc itself does. +PROTO_INCLUDE=$(dirname $(dirname $(which protoc)))/include + +# Well-known types. +WKT_PROTOS=(any duration empty struct timestamp wrappers) +for p in ${WKT_PROTOS[@]}; do + echo "# google/protobuf/$p.proto" + protoc --go_out=paths=source_relative:$tmpdir google/protobuf/$p.proto + cp $tmpdir/google/protobuf/$p.pb.go ptypes/$p + cp $PROTO_INCLUDE/google/protobuf/$p.proto ptypes/$p +done + +# descriptor.proto. +echo "# google/protobuf/descriptor.proto" +protoc --go_out=paths=source_relative:$tmpdir google/protobuf/descriptor.proto +cp $tmpdir/google/protobuf/descriptor.pb.go protoc-gen-go/descriptor +cp $PROTO_INCLUDE/google/protobuf/descriptor.proto protoc-gen-go/descriptor diff --git a/vendor/github.com/golang/snappy/cmd/snappytool/main.go b/vendor/github.com/golang/snappy/cmd/snappytool/main.go new file mode 100644 index 00000000..b0f44c3f --- /dev/null +++ b/vendor/github.com/golang/snappy/cmd/snappytool/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "errors" + "flag" + "io/ioutil" + "os" + + "github.com/golang/snappy" +) + +var ( + decode = flag.Bool("d", false, "decode") + encode = flag.Bool("e", false, "encode") +) + +func run() error { + flag.Parse() + if *decode == *encode { + return errors.New("exactly one of -d or -e must be given") + } + + in, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return err + } + + out := []byte(nil) + if *decode { + out, err = snappy.Decode(nil, in) + if err != nil { + return err + } + } else { + out = snappy.Encode(nil, in) + } + _, err = os.Stdout.Write(out) + return err +} + +func main() { + if err := run(); err != nil { + os.Stderr.WriteString(err.Error() + "\n") + os.Exit(1) + } +} diff --git a/vendor/github.com/golang/snappy/cmd/snappytool/main.cpp b/vendor/github.com/golang/snappy/misc/main.cpp similarity index 97% rename from vendor/github.com/golang/snappy/cmd/snappytool/main.cpp rename to vendor/github.com/golang/snappy/misc/main.cpp index fc31f517..24a3d9a9 100644 --- a/vendor/github.com/golang/snappy/cmd/snappytool/main.cpp +++ b/vendor/github.com/golang/snappy/misc/main.cpp @@ -1,4 +1,6 @@ /* +This is a C version of the cmd/snappytool Go program. + To build the snappytool binary: g++ main.cpp /usr/lib/libsnappy.a -o snappytool or, if you have built the C++ snappy library from source: diff --git a/vendor/github.com/golang/snappy/snappy.go b/vendor/github.com/golang/snappy/snappy.go index 0cf5e379..ece692ea 100644 --- a/vendor/github.com/golang/snappy/snappy.go +++ b/vendor/github.com/golang/snappy/snappy.go @@ -2,10 +2,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package snappy implements the snappy block-based compression format. -// It aims for very high speeds and reasonable compression. +// Package snappy implements the Snappy compression format. It aims for very +// high speeds and reasonable compression. // -// The C++ snappy implementation is at https://github.com/google/snappy +// There are actually two Snappy formats: block and stream. They are related, +// but different: trying to decompress block-compressed data as a Snappy stream +// will fail, and vice versa. The block format is the Decode and Encode +// functions and the stream format is the Reader and Writer types. +// +// The block format, the more common case, is used when the complete size (the +// number of bytes) of the original data is known upfront, at the time +// compression starts. The stream format, also known as the framing format, is +// for when that isn't always true. +// +// The canonical, C++ implementation is at https://github.com/google/snappy and +// it only implements the block format. package snappy // import "github.com/golang/snappy" import ( diff --git a/vendor/github.com/google/uuid/go.mod b/vendor/github.com/google/uuid/go.mod deleted file mode 100644 index fc84cd79..00000000 --- a/vendor/github.com/google/uuid/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/google/uuid diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index 524404cc..7f3643fe 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All rights reserved. +// Copyright 2016 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -35,43 +35,20 @@ const ( var rander = rand.Reader // random function -// Parse decodes s into a UUID or returns an error. Both the standard UUID -// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the -// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex -// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +// Parse decodes s into a UUID or returns an error. Both the UUID form of +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. func Parse(s string) (UUID, error) { var uuid UUID - switch len(s) { - // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36: - - // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: + if len(s) != 36 { + if len(s) != 36+9 { + return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) + } if strings.ToLower(s[:9]) != "urn:uuid:" { return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) } s = s[9:] - - // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - case 36 + 2: - s = s[1:] - - // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - case 32: - var ok bool - for i := range uuid { - uuid[i], ok = xtob(s[i*2], s[i*2+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { return uuid, errors.New("invalid UUID format") } @@ -93,29 +70,15 @@ func Parse(s string) (UUID, error) { // ParseBytes is like Parse, except it parses a byte slice instead of a string. func ParseBytes(b []byte) (UUID, error) { var uuid UUID - switch len(b) { - case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if len(b) != 36 { + if len(b) != 36+9 { + return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) + } if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) } b = b[9:] - case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - b = b[1:] - case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - var ok bool - for i := 0; i < 32; i += 2 { - uuid[i/2], ok = xtob(b[i], b[i+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { return uuid, errors.New("invalid UUID format") } @@ -134,16 +97,6 @@ func ParseBytes(b []byte) (UUID, error) { return uuid, nil } -// MustParse is like Parse but panics if the string cannot be parsed. -// It simplifies safe initialization of global variables holding compiled UUIDs. -func MustParse(s string) UUID { - uuid, err := Parse(s) - if err != nil { - panic(`uuid: Parse(` + s + `): ` + err.Error()) - } - return uuid -} - // FromBytes creates a new UUID from a byte slice. Returns an error if the slice // does not have a length of 16. The bytes are copied from the slice. func FromBytes(b []byte) (uuid UUID, err error) { @@ -177,7 +130,7 @@ func (uuid UUID) URN() string { } func encodeHex(dst []byte, uuid UUID) { - hex.Encode(dst, uuid[:4]) + hex.Encode(dst[:], uuid[:4]) dst[8] = '-' hex.Encode(dst[9:13], uuid[4:6]) dst[13] = '-' diff --git a/vendor/github.com/google/uuid/uuid_test.go b/vendor/github.com/google/uuid/uuid_test.go index e7876f15..c0a89f41 100644 --- a/vendor/github.com/google/uuid/uuid_test.go +++ b/vendor/github.com/google/uuid/uuid_test.go @@ -59,22 +59,12 @@ var tests = []test{ {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, - {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, - - - {"{f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, RFC4122, true}, - {"{f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, Invalid, false}, - {"f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, Invalid, false}, - - {"f47ac10b58cc037285670e02b2c3d479", 0, RFC4122, true}, - {"f47ac10b58cc037285670e02b2c3d4790", 0, Invalid, false}, - {"f47ac10b58cc037285670e02b2c3d47", 0, Invalid, false}, } var constants = []struct { diff --git a/vendor/github.com/hashicorp/hcl/go.mod b/vendor/github.com/hashicorp/hcl/go.mod new file mode 100644 index 00000000..4debbbe3 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/go.mod @@ -0,0 +1,3 @@ +module github.com/hashicorp/hcl + +require github.com/davecgh/go-spew v1.1.1 diff --git a/vendor/github.com/hashicorp/hcl/go.sum b/vendor/github.com/hashicorp/hcl/go.sum new file mode 100644 index 00000000..b5e2922e --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/go.sum @@ -0,0 +1,2 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/ast_test.go b/vendor/github.com/hashicorp/hcl/hcl/ast/ast_test.go index 942256ca..d4364a10 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/ast/ast_test.go +++ b/vendor/github.com/hashicorp/hcl/hcl/ast/ast_test.go @@ -137,7 +137,7 @@ func TestWalkEquality(t *testing.T) { } if len(newNode.Items) != 2 { - t.Error("expected newNode length 2, got: %d", len(newNode.Items)) + t.Errorf("expected newNode length 2, got: %d", len(newNode.Items)) } expected := []string{ @@ -147,7 +147,7 @@ func TestWalkEquality(t *testing.T) { for i, item := range newNode.Items { if len(item.Keys) != 1 { - t.Error("expected keys newNode length 1, got: %d", len(item.Keys)) + t.Errorf("expected keys newNode length 1, got: %d", len(item.Keys)) } if item.Keys[0].Token.Text != expected[i] { diff --git a/vendor/github.com/hashicorp/hcl/hcl/fmtcmd/fmtcmd_test.go b/vendor/github.com/hashicorp/hcl/hcl/fmtcmd/fmtcmd_test.go index b952d76d..66bed581 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/fmtcmd/fmtcmd_test.go +++ b/vendor/github.com/hashicorp/hcl/hcl/fmtcmd/fmtcmd_test.go @@ -46,7 +46,7 @@ func TestIsValidFile(t *testing.T) { } if res := isValidFile(file, fixtureExtensions); res != tc.Expected { - t.Errorf("want: %b, got: %b", tc.Expected, res) + t.Errorf("want: %t, got: %t", tc.Expected, res) } } } @@ -86,7 +86,7 @@ func TestRunMultiplePaths(t *testing.T) { t.Errorf("unexpected error: %s", err) } if stdout.String() != expectedOut.String() { - t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut, stdout) + t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String()) } } @@ -132,7 +132,7 @@ func TestRunSubDirectories(t *testing.T) { t.Errorf("unexpected error: %s", err) } if stdout.String() != expectedOut.String() { - t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut, stdout) + t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String()) } } @@ -161,7 +161,7 @@ func TestRunStdin(t *testing.T) { t.Errorf("unexpected error: %s", err) } if !bytes.Equal(stdout.Bytes(), expectedOut.Bytes()) { - t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut, stdout) + t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String()) } } @@ -242,7 +242,7 @@ func TestRunNoOptions(t *testing.T) { t.Errorf("unexpected error: %s", err) } if stdout.String() != expectedOut.String() { - t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut, stdout) + t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String()) } } @@ -274,7 +274,7 @@ func TestRunList(t *testing.T) { t.Errorf("unexpected error: %s", err) } if stdout.String() != expectedOut.String() { - t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut, stdout) + t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String()) } } diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go index 098e1bc4..64c83bcf 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go +++ b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go @@ -205,6 +205,12 @@ func (p *Parser) objectItem() (*ast.ObjectItem, error) { } } + // key=#comment + // val + if p.lineComment != nil { + o.LineComment, p.lineComment = p.lineComment, nil + } + // do a look-ahead for line comment p.scan() if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go b/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go index c896d584..7c038d12 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go @@ -252,6 +252,14 @@ func (p *printer) objectItem(o *ast.ObjectItem) []byte { } } + // If key and val are on different lines, treat line comments like lead comments. + if o.LineComment != nil && o.Val.Pos().Line != o.Keys[0].Pos().Line { + for _, comment := range o.LineComment.List { + buf.WriteString(comment.Text) + buf.WriteByte(newline) + } + } + for i, k := range o.Keys { buf.WriteString(k.Token.Text) buf.WriteByte(blank) @@ -265,7 +273,7 @@ func (p *printer) objectItem(o *ast.ObjectItem) []byte { buf.Write(p.output(o.Val)) - if o.Val.Pos().Line == o.Keys[0].Pos().Line && o.LineComment != nil { + if o.LineComment != nil && o.Val.Pos().Line == o.Keys[0].Pos().Line { buf.WriteByte(blank) for _, comment := range o.LineComment.List { buf.WriteString(comment.Text) @@ -509,8 +517,13 @@ func (p *printer) alignedItems(items []*ast.ObjectItem) []byte { // list returns the printable HCL form of an list type. func (p *printer) list(l *ast.ListType) []byte { + if p.isSingleLineList(l) { + return p.singleLineList(l) + } + var buf bytes.Buffer buf.WriteString("[") + buf.WriteByte(newline) var longestLine int for _, item := range l.List { @@ -523,115 +536,112 @@ func (p *printer) list(l *ast.ListType) []byte { } } - insertSpaceBeforeItem := false - lastHadLeadComment := false + haveEmptyLine := false for i, item := range l.List { - // Keep track of whether this item is a heredoc since that has - // unique behavior. - heredoc := false + // If we have a lead comment, then we want to write that first + leadComment := false + if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil { + leadComment = true + + // Ensure an empty line before every element with a + // lead comment (except the first item in a list). + if !haveEmptyLine && i != 0 { + buf.WriteByte(newline) + } + + for _, comment := range lit.LeadComment.List { + buf.Write(p.indent([]byte(comment.Text))) + buf.WriteByte(newline) + } + } + + // also indent each line + val := p.output(item) + curLen := len(val) + buf.Write(p.indent(val)) + + // if this item is a heredoc, then we output the comma on + // the next line. This is the only case this happens. + comma := []byte{','} if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC { - heredoc = true - } - - if item.Pos().Line != l.Lbrack.Line { - // multiline list, add newline before we add each item buf.WriteByte(newline) - insertSpaceBeforeItem = false + comma = p.indent(comma) + } - // If we have a lead comment, then we want to write that first - leadComment := false - if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil { - leadComment = true + buf.Write(comma) - // If this isn't the first item and the previous element - // didn't have a lead comment, then we need to add an extra - // newline to properly space things out. If it did have a - // lead comment previously then this would be done - // automatically. - if i > 0 && !lastHadLeadComment { - buf.WriteByte(newline) - } - - for _, comment := range lit.LeadComment.List { - buf.Write(p.indent([]byte(comment.Text))) - buf.WriteByte(newline) - } - } - - // also indent each line - val := p.output(item) - curLen := len(val) - buf.Write(p.indent(val)) - - // if this item is a heredoc, then we output the comma on - // the next line. This is the only case this happens. - comma := []byte{','} - if heredoc { - buf.WriteByte(newline) - comma = p.indent(comma) - } - - buf.Write(comma) - - if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil { - // if the next item doesn't have any comments, do not align - buf.WriteByte(blank) // align one space - for i := 0; i < longestLine-curLen; i++ { - buf.WriteByte(blank) - } - - for _, comment := range lit.LineComment.List { - buf.WriteString(comment.Text) - } - } - - lastItem := i == len(l.List)-1 - if lastItem { - buf.WriteByte(newline) - } - - if leadComment && !lastItem { - buf.WriteByte(newline) - } - - lastHadLeadComment = leadComment - } else { - if insertSpaceBeforeItem { + if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil { + // if the next item doesn't have any comments, do not align + buf.WriteByte(blank) // align one space + for i := 0; i < longestLine-curLen; i++ { buf.WriteByte(blank) - insertSpaceBeforeItem = false } - // Output the item itself - // also indent each line - val := p.output(item) - curLen := len(val) - buf.Write(val) - - // If this is a heredoc item we always have to output a newline - // so that it parses properly. - if heredoc { - buf.WriteByte(newline) - } - - // If this isn't the last element, write a comma. - if i != len(l.List)-1 { - buf.WriteString(",") - insertSpaceBeforeItem = true - } - - if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil { - // if the next item doesn't have any comments, do not align - buf.WriteByte(blank) // align one space - for i := 0; i < longestLine-curLen; i++ { - buf.WriteByte(blank) - } - - for _, comment := range lit.LineComment.List { - buf.WriteString(comment.Text) - } + for _, comment := range lit.LineComment.List { + buf.WriteString(comment.Text) } } + buf.WriteByte(newline) + + // Ensure an empty line after every element with a + // lead comment (except the first item in a list). + haveEmptyLine = leadComment && i != len(l.List)-1 + if haveEmptyLine { + buf.WriteByte(newline) + } + } + + buf.WriteString("]") + return buf.Bytes() +} + +// isSingleLineList returns true if: +// * they were previously formatted entirely on one line +// * they consist entirely of literals +// * there are either no heredoc strings or the list has exactly one element +// * there are no line comments +func (printer) isSingleLineList(l *ast.ListType) bool { + for _, item := range l.List { + if item.Pos().Line != l.Lbrack.Line { + return false + } + + lit, ok := item.(*ast.LiteralType) + if !ok { + return false + } + + if lit.Token.Type == token.HEREDOC && len(l.List) != 1 { + return false + } + + if lit.LineComment != nil { + return false + } + } + + return true +} + +// singleLineList prints a simple single line list. +// For a definition of "simple", see isSingleLineList above. +func (p *printer) singleLineList(l *ast.ListType) []byte { + buf := &bytes.Buffer{} + + buf.WriteString("[") + for i, item := range l.List { + if i != 0 { + buf.WriteString(", ") + } + + // Output the item itself + buf.Write(p.output(item)) + + // The heredoc marker needs to be at the end of line. + if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC { + buf.WriteByte(newline) + } } buf.WriteString("]") diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/printer_test.go b/vendor/github.com/hashicorp/hcl/hcl/printer/printer_test.go index 5248259b..8ae747ab 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/printer_test.go +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/printer_test.go @@ -147,3 +147,30 @@ func lineAt(text []byte, offs int) []byte { } return text[offs:i] } + +// TestFormatParsable ensures that the output of Format() is can be parsed again. +func TestFormatValidOutput(t *testing.T) { + cases := []string{ + "#\x00", + "#\ue123t", + "x=//\n0y=<<_\n_\n", + "y=[1,//\n]", + "Y=<<4\n4/\n\n\n/4/@=4/\n\n\n/4000000004\r\r\n00004\n", + "x=<<_\n_\r\r\n_\n", + "X=<<-\n\r\r\n", + } + + for _, c := range cases { + f, err := Format([]byte(c)) + if err != nil { + // ignore these failures, not all inputs are valid HCL. + t.Logf("Format(%q) = %v", c, err) + continue + } + + if _, err := parser.Parse(f); err != nil { + t.Errorf("Format(%q) = %q; Parse(%q) = %v", c, f, f, err) + continue + } + } +} diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.golden b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.golden index 9d4b072a..192c26aa 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.golden +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.golden @@ -34,3 +34,6 @@ variable = { foo { bar = "fatih" // line comment 2 } // line comment 3 + +// comment +multiline = "assignment" diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.input b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.input index 57c37ac1..c4b29de7 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.input +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment.input @@ -35,3 +35,5 @@ foo { bar = "fatih" // line comment 2 } // line comment 3 +multiline = // comment +"assignment" diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment_crlf.input b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment_crlf.input index 5d272067..49550864 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment_crlf.input +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/comment_crlf.input @@ -35,3 +35,5 @@ foo { bar = "fatih" // line comment 2 } // line comment 3 +multiline = // comment +"assignment" diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list.golden b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list.golden index 14c37ac0..6894b444 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list.golden +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list.golden @@ -2,11 +2,14 @@ foo = ["fatih", "arslan"] foo = ["bar", "qaz"] -foo = ["zeynep", +foo = [ + "zeynep", "arslan", ] -foo = ["fatih", "zeynep", +foo = [ + "fatih", + "zeynep", "arslan", ] diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.golden b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.golden index e5753c91..35a848f1 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.golden +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.golden @@ -1,7 +1,13 @@ -foo = [1, # Hello +foo = [ + 1, # Hello 2, ] -foo = [1, # Hello +foo = [ + 1, # Hello 2, # World ] + +foo = [ + 1, # Hello +] diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.input b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.input index 1d636c88..c56aef21 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.input +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/list_comment.input @@ -4,3 +4,6 @@ foo = [1, # Hello foo = [1, # Hello 2, # World ] + +foo = [1, # Hello +] diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/object_with_heredoc.golden b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/object_with_heredoc.golden index 7e92243f..a271d289 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/object_with_heredoc.golden +++ b/vendor/github.com/hashicorp/hcl/hcl/printer/testdata/object_with_heredoc.golden @@ -1,6 +1,7 @@ obj { foo = [< 0 { + if ch == '\x00' { s.err("unexpected null character (0x00)") return eof } + if ch == '\uE123' { + s.err("unicode code point U+E123 reserved for internal use") + return utf8.RuneError + } + // debug // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) return ch @@ -432,16 +433,16 @@ func (s *Scanner) scanHeredoc() { // Read the identifier identBytes := s.src[offs : s.srcPos.Offset-s.lastCharLen] - if len(identBytes) == 0 { + if len(identBytes) == 0 || (len(identBytes) == 1 && identBytes[0] == '-') { s.err("zero-length heredoc anchor") return } var identRegexp *regexp.Regexp if identBytes[0] == '-' { - identRegexp = regexp.MustCompile(fmt.Sprintf(`[[:space:]]*%s\z`, identBytes[1:])) + identRegexp = regexp.MustCompile(fmt.Sprintf(`^[[:space:]]*%s\r*\z`, identBytes[1:])) } else { - identRegexp = regexp.MustCompile(fmt.Sprintf(`[[:space:]]*%s\z`, identBytes)) + identRegexp = regexp.MustCompile(fmt.Sprintf(`^[[:space:]]*%s\r*\z`, identBytes)) } // Read the actual string value @@ -551,7 +552,7 @@ func (s *Scanner) scanDigits(ch rune, base, n int) rune { s.err("illegal char escape") } - if n != start { + if n != start && ch != eof { // we scanned all digits, put the last non digit char back, // only if we read anything at all s.unread() diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner_test.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner_test.go index 4f2c9cbe..58d68f5c 100644 --- a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner_test.go +++ b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner_test.go @@ -509,9 +509,12 @@ func TestScan_crlf(t *testing.T) { func TestError(t *testing.T) { testError(t, "\x80", "1:1", "illegal UTF-8 encoding", token.ILLEGAL) testError(t, "\xff", "1:1", "illegal UTF-8 encoding", token.ILLEGAL) + testError(t, "\uE123", "1:1", "unicode code point U+E123 reserved for internal use", token.ILLEGAL) testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", token.IDENT) testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", token.IDENT) + testError(t, "ab\x00", "1:3", "unexpected null character (0x00)", token.IDENT) + testError(t, "ab\x00\n", "1:3", "unexpected null character (0x00)", token.IDENT) testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", token.STRING) testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", token.STRING) @@ -528,6 +531,9 @@ func TestError(t *testing.T) { testError(t, `"${abc`+"\n", "2:1", "literal not terminated", token.STRING) testError(t, `/*/`, "1:4", "comment not terminated", token.COMMENT) testError(t, `/foo`, "1:1", "expected '/' for comment", token.COMMENT) + + testError(t, "<<\nfoo\n\n", "1:3", "zero-length heredoc anchor", token.HEREDOC) + testError(t, "<<-\nfoo\n\n", "1:4", "zero-length heredoc anchor", token.HEREDOC) } func testError(t *testing.T, src, pos, msg string, tok token.Type) { @@ -589,3 +595,48 @@ func countNewlines(s string) int { } return n } + +func TestScanDigitsUnread(t *testing.T) { + cases := []string{ + "M=0\"\\00", + "M=\"\\00", + "\"\\00", + "M=[\"\\00", + "U{\"\\00", + "\"\n{}#\n\"\\00", + "M=[[\"\\00", + "U{d=0\"\\U00", + "#\n\"\\x00", + "m=[[[\"\\00", + } + + for _, c := range cases { + s := New([]byte(c)) + + for { + tok := s.Scan() + if tok.Type == token.EOF { + break + } + t.Logf("s.Scan() = %s", tok) + } + } +} + +func TestScanHeredocRegexpCompile(t *testing.T) { + cases := []string{ + "0\xe1\n<<ȸ\nhello\nworld\nȸ", + } + + for _, c := range cases { + s := New([]byte(c)) + + for { + tok := s.Scan() + if tok.Type == token.EOF { + break + } + t.Logf("s.Scan() = %s", tok) + } + } +} diff --git a/vendor/github.com/hpcloud/tail/.gitignore b/vendor/github.com/hpcloud/tail/.gitignore new file mode 100644 index 00000000..6d9953c3 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/.gitignore @@ -0,0 +1,3 @@ +.test +.go + diff --git a/vendor/github.com/hpcloud/tail/.travis.yml b/vendor/github.com/hpcloud/tail/.travis.yml new file mode 100644 index 00000000..9cf8bb7f --- /dev/null +++ b/vendor/github.com/hpcloud/tail/.travis.yml @@ -0,0 +1,18 @@ +language: go + +script: + - go test -race -v ./... + +go: + - 1.4 + - 1.5 + - 1.6 + - tip + +matrix: + allow_failures: + - go: tip + +install: + - go get gopkg.in/fsnotify.v1 + - go get gopkg.in/tomb.v1 diff --git a/vendor/github.com/hpcloud/tail/CHANGES.md b/vendor/github.com/hpcloud/tail/CHANGES.md new file mode 100644 index 00000000..422790c0 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/CHANGES.md @@ -0,0 +1,63 @@ +# API v1 (gopkg.in/hpcloud/tail.v1) + +## April, 2016 + +* Migrated to godep, as depman is not longer supported +* Introduced golang vendoring feature +* Fixed issue [#57](https://github.com/hpcloud/tail/issues/57) related to reopen deleted file + +## July, 2015 + +* Fix inotify watcher leak; remove `Cleanup` (#51) + +# API v0 (gopkg.in/hpcloud/tail.v0) + +## June, 2015 + +* Don't return partial lines (PR #40) +* Use stable version of fsnotify (#46) + +## July, 2014 + +* Fix tail for Windows (PR #36) + +## May, 2014 + +* Improved rate limiting using leaky bucket (PR #29) +* Fix odd line splitting (PR #30) + +## Apr, 2014 + +* LimitRate now discards read buffer (PR #28) +* allow reading of longer lines if MaxLineSize is unset (PR #24) +* updated deps.json to latest fsnotify (441bbc86b1) + +## Feb, 2014 + +* added `Config.Logger` to suppress library logging + +## Nov, 2013 + +* add Cleanup to remove leaky inotify watches (PR #20) + +## Aug, 2013 + +* redesigned Location field (PR #12) +* add tail.Tell (PR #14) + +## July, 2013 + +* Rate limiting (PR #10) + +## May, 2013 + +* Detect file deletions/renames in polling file watcher (PR #1) +* Detect file truncation +* Fix potential race condition when reopening the file (issue 5) +* Fix potential blocking of `tail.Stop` (issue 4) +* Fix uncleaned up ChangeEvents goroutines after calling tail.Stop +* Support Follow=false + +## Feb, 2013 + +* Initial open source release diff --git a/vendor/github.com/hpcloud/tail/Dockerfile b/vendor/github.com/hpcloud/tail/Dockerfile new file mode 100644 index 00000000..cd297b94 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/Dockerfile @@ -0,0 +1,19 @@ +FROM golang + +RUN mkdir -p $GOPATH/src/github.com/hpcloud/tail/ +ADD . $GOPATH/src/github.com/hpcloud/tail/ + +# expecting to fetch dependencies successfully. +RUN go get -v github.com/hpcloud/tail + +# expecting to run the test successfully. +RUN go test -v github.com/hpcloud/tail + +# expecting to install successfully +RUN go install -v github.com/hpcloud/tail +RUN go install -v github.com/hpcloud/tail/cmd/gotail + +RUN $GOPATH/bin/gotail -h || true + +ENV PATH $GOPATH/bin:$PATH +CMD ["gotail"] diff --git a/vendor/github.com/hpcloud/tail/Godeps/Godeps.json b/vendor/github.com/hpcloud/tail/Godeps/Godeps.json new file mode 100644 index 00000000..904ea805 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/Godeps/Godeps.json @@ -0,0 +1,15 @@ +{ + "ImportPath": "github.com/hpcloud/tail", + "GoVersion": "go1.5.1", + "Deps": [ + { + "ImportPath": "gopkg.in/fsnotify.v1", + "Comment": "v1.2.1", + "Rev": "7be54206639f256967dd82fa767397ba5f8f48f5" + }, + { + "ImportPath": "gopkg.in/tomb.v1", + "Rev": "c131134a1947e9afd9cecfe11f4c6dff0732ae58" + } + ] +} diff --git a/vendor/github.com/hpcloud/tail/Godeps/Readme b/vendor/github.com/hpcloud/tail/Godeps/Readme new file mode 100644 index 00000000..4cdaa53d --- /dev/null +++ b/vendor/github.com/hpcloud/tail/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/vendor/github.com/hpcloud/tail/LICENSE.txt b/vendor/github.com/hpcloud/tail/LICENSE.txt new file mode 100644 index 00000000..818d802a --- /dev/null +++ b/vendor/github.com/hpcloud/tail/LICENSE.txt @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +# © Copyright 2015 Hewlett Packard Enterprise Development LP +Copyright (c) 2014 ActiveState + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/hpcloud/tail/Makefile b/vendor/github.com/hpcloud/tail/Makefile new file mode 100644 index 00000000..6591b24f --- /dev/null +++ b/vendor/github.com/hpcloud/tail/Makefile @@ -0,0 +1,11 @@ +default: test + +test: *.go + go test -v -race ./... + +fmt: + gofmt -w . + +# Run the test in an isolated environment. +fulltest: + docker build -t hpcloud/tail . diff --git a/vendor/github.com/hpcloud/tail/README.md b/vendor/github.com/hpcloud/tail/README.md new file mode 100644 index 00000000..fb7fbc26 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/README.md @@ -0,0 +1,28 @@ +[![Build Status](https://travis-ci.org/hpcloud/tail.svg)](https://travis-ci.org/hpcloud/tail) +[![Build status](https://ci.appveyor.com/api/projects/status/kohpsf3rvhjhrox6?svg=true)](https://ci.appveyor.com/project/HelionCloudFoundry/tail) + +# Go package for tail-ing files + +A Go package striving to emulate the features of the BSD `tail` program. + +```Go +t, err := tail.TailFile("/var/log/nginx.log", tail.Config{Follow: true}) +for line := range t.Lines { + fmt.Println(line.Text) +} +``` + +See [API documentation](http://godoc.org/github.com/hpcloud/tail). + +## Log rotation + +Tail comes with full support for truncation/move detection as it is +designed to work with log rotation tools. + +## Installing + + go get github.com/hpcloud/tail/... + +## Windows support + +This package [needs assistance](https://github.com/hpcloud/tail/labels/Windows) for full Windows support. diff --git a/vendor/github.com/hpcloud/tail/appveyor.yml b/vendor/github.com/hpcloud/tail/appveyor.yml new file mode 100644 index 00000000..d370055b --- /dev/null +++ b/vendor/github.com/hpcloud/tail/appveyor.yml @@ -0,0 +1,11 @@ +version: 0.{build} +skip_tags: true +cache: C:\Users\appveyor\AppData\Local\NuGet\Cache +build_script: +- SET GOPATH=c:\workspace +- go test -v -race ./... +test: off +clone_folder: c:\workspace\src\github.com\hpcloud\tail +branches: + only: + - master diff --git a/vendor/github.com/hpcloud/tail/cmd/gotail/.gitignore b/vendor/github.com/hpcloud/tail/cmd/gotail/.gitignore new file mode 100644 index 00000000..6249af5f --- /dev/null +++ b/vendor/github.com/hpcloud/tail/cmd/gotail/.gitignore @@ -0,0 +1 @@ +gotail diff --git a/vendor/github.com/hpcloud/tail/cmd/gotail/Makefile b/vendor/github.com/hpcloud/tail/cmd/gotail/Makefile new file mode 100644 index 00000000..6b5a2d95 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/cmd/gotail/Makefile @@ -0,0 +1,4 @@ +default: gotail + +gotail: *.go ../../*.go + go build diff --git a/vendor/github.com/hpcloud/tail/cmd/gotail/gotail.go b/vendor/github.com/hpcloud/tail/cmd/gotail/gotail.go new file mode 100644 index 00000000..3da55f23 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/cmd/gotail/gotail.go @@ -0,0 +1,66 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/hpcloud/tail" +) + +func args2config() (tail.Config, int64) { + config := tail.Config{Follow: true} + n := int64(0) + maxlinesize := int(0) + flag.Int64Var(&n, "n", 0, "tail from the last Nth location") + flag.IntVar(&maxlinesize, "max", 0, "max line size") + flag.BoolVar(&config.Follow, "f", false, "wait for additional data to be appended to the file") + flag.BoolVar(&config.ReOpen, "F", false, "follow, and track file rename/rotation") + flag.BoolVar(&config.Poll, "p", false, "use polling, instead of inotify") + flag.Parse() + if config.ReOpen { + config.Follow = true + } + config.MaxLineSize = maxlinesize + return config, n +} + +func main() { + config, n := args2config() + if flag.NFlag() < 1 { + fmt.Println("need one or more files as arguments") + os.Exit(1) + } + + if n != 0 { + config.Location = &tail.SeekInfo{-n, os.SEEK_END} + } + + done := make(chan bool) + for _, filename := range flag.Args() { + go tailFile(filename, config, done) + } + + for _, _ = range flag.Args() { + <-done + } +} + +func tailFile(filename string, config tail.Config, done chan bool) { + defer func() { done <- true }() + t, err := tail.TailFile(filename, config) + if err != nil { + fmt.Println(err) + return + } + for line := range t.Lines { + fmt.Println(line.Text) + } + err = t.Wait() + if err != nil { + fmt.Println(err) + } +} diff --git a/vendor/github.com/hpcloud/tail/ratelimiter/Licence b/vendor/github.com/hpcloud/tail/ratelimiter/Licence new file mode 100644 index 00000000..434aab19 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/ratelimiter/Licence @@ -0,0 +1,7 @@ +Copyright (C) 2013 99designs + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/hpcloud/tail/ratelimiter/leakybucket.go b/vendor/github.com/hpcloud/tail/ratelimiter/leakybucket.go new file mode 100644 index 00000000..358b69e7 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/ratelimiter/leakybucket.go @@ -0,0 +1,97 @@ +// Package ratelimiter implements the Leaky Bucket ratelimiting algorithm with memcached and in-memory backends. +package ratelimiter + +import ( + "time" +) + +type LeakyBucket struct { + Size uint16 + Fill float64 + LeakInterval time.Duration // time.Duration for 1 unit of size to leak + Lastupdate time.Time + Now func() time.Time +} + +func NewLeakyBucket(size uint16, leakInterval time.Duration) *LeakyBucket { + bucket := LeakyBucket{ + Size: size, + Fill: 0, + LeakInterval: leakInterval, + Now: time.Now, + Lastupdate: time.Now(), + } + + return &bucket +} + +func (b *LeakyBucket) updateFill() { + now := b.Now() + if b.Fill > 0 { + elapsed := now.Sub(b.Lastupdate) + + b.Fill -= float64(elapsed) / float64(b.LeakInterval) + if b.Fill < 0 { + b.Fill = 0 + } + } + b.Lastupdate = now +} + +func (b *LeakyBucket) Pour(amount uint16) bool { + b.updateFill() + + var newfill float64 = b.Fill + float64(amount) + + if newfill > float64(b.Size) { + return false + } + + b.Fill = newfill + + return true +} + +// The time at which this bucket will be completely drained +func (b *LeakyBucket) DrainedAt() time.Time { + return b.Lastupdate.Add(time.Duration(b.Fill * float64(b.LeakInterval))) +} + +// The duration until this bucket is completely drained +func (b *LeakyBucket) TimeToDrain() time.Duration { + return b.DrainedAt().Sub(b.Now()) +} + +func (b *LeakyBucket) TimeSinceLastUpdate() time.Duration { + return b.Now().Sub(b.Lastupdate) +} + +type LeakyBucketSer struct { + Size uint16 + Fill float64 + LeakInterval time.Duration // time.Duration for 1 unit of size to leak + Lastupdate time.Time +} + +func (b *LeakyBucket) Serialise() *LeakyBucketSer { + bucket := LeakyBucketSer{ + Size: b.Size, + Fill: b.Fill, + LeakInterval: b.LeakInterval, + Lastupdate: b.Lastupdate, + } + + return &bucket +} + +func (b *LeakyBucketSer) DeSerialise() *LeakyBucket { + bucket := LeakyBucket{ + Size: b.Size, + Fill: b.Fill, + LeakInterval: b.LeakInterval, + Lastupdate: b.Lastupdate, + Now: time.Now, + } + + return &bucket +} diff --git a/vendor/github.com/hpcloud/tail/ratelimiter/leakybucket_test.go b/vendor/github.com/hpcloud/tail/ratelimiter/leakybucket_test.go new file mode 100644 index 00000000..b43dddb0 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/ratelimiter/leakybucket_test.go @@ -0,0 +1,73 @@ +package ratelimiter + +import ( + "testing" + "time" +) + +func TestPour(t *testing.T) { + bucket := NewLeakyBucket(60, time.Second) + bucket.Lastupdate = time.Unix(0, 0) + + bucket.Now = func() time.Time { return time.Unix(1, 0) } + + if bucket.Pour(61) { + t.Error("Expected false") + } + + if !bucket.Pour(10) { + t.Error("Expected true") + } + + if !bucket.Pour(49) { + t.Error("Expected true") + } + + if bucket.Pour(2) { + t.Error("Expected false") + } + + bucket.Now = func() time.Time { return time.Unix(61, 0) } + if !bucket.Pour(60) { + t.Error("Expected true") + } + + if bucket.Pour(1) { + t.Error("Expected false") + } + + bucket.Now = func() time.Time { return time.Unix(70, 0) } + + if !bucket.Pour(1) { + t.Error("Expected true") + } + +} + +func TestTimeSinceLastUpdate(t *testing.T) { + bucket := NewLeakyBucket(60, time.Second) + bucket.Now = func() time.Time { return time.Unix(1, 0) } + bucket.Pour(1) + bucket.Now = func() time.Time { return time.Unix(2, 0) } + + sinceLast := bucket.TimeSinceLastUpdate() + if sinceLast != time.Second*1 { + t.Errorf("Expected time since last update to be less than 1 second, got %d", sinceLast) + } +} + +func TestTimeToDrain(t *testing.T) { + bucket := NewLeakyBucket(60, time.Second) + bucket.Now = func() time.Time { return time.Unix(1, 0) } + bucket.Pour(10) + + if bucket.TimeToDrain() != time.Second*10 { + t.Error("Time to drain should be 10 seconds") + } + + bucket.Now = func() time.Time { return time.Unix(2, 0) } + + if bucket.TimeToDrain() != time.Second*9 { + t.Error("Time to drain should be 9 seconds") + } +} diff --git a/vendor/github.com/hpcloud/tail/ratelimiter/memory.go b/vendor/github.com/hpcloud/tail/ratelimiter/memory.go new file mode 100644 index 00000000..8f6a5784 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/ratelimiter/memory.go @@ -0,0 +1,58 @@ +package ratelimiter + +import ( + "errors" + "time" +) + +const GC_SIZE int = 100 + +type Memory struct { + store map[string]LeakyBucket + lastGCCollected time.Time +} + +func NewMemory() *Memory { + m := new(Memory) + m.store = make(map[string]LeakyBucket) + m.lastGCCollected = time.Now() + return m +} + +func (m *Memory) GetBucketFor(key string) (*LeakyBucket, error) { + + bucket, ok := m.store[key] + if !ok { + return nil, errors.New("miss") + } + + return &bucket, nil +} + +func (m *Memory) SetBucketFor(key string, bucket LeakyBucket) error { + + if len(m.store) > GC_SIZE { + m.GarbageCollect() + } + + m.store[key] = bucket + + return nil +} + +func (m *Memory) GarbageCollect() { + now := time.Now() + + // rate limit GC to once per minute + if now.Add(60*time.Second).Unix() > m.lastGCCollected.Unix() { + + for key, bucket := range m.store { + // if the bucket is drained, then GC + if bucket.DrainedAt().Unix() > now.Unix() { + delete(m.store, key) + } + } + + m.lastGCCollected = now + } +} diff --git a/vendor/github.com/hpcloud/tail/ratelimiter/storage.go b/vendor/github.com/hpcloud/tail/ratelimiter/storage.go new file mode 100644 index 00000000..89b2fe882 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/ratelimiter/storage.go @@ -0,0 +1,6 @@ +package ratelimiter + +type Storage interface { + GetBucketFor(string) (*LeakyBucket, error) + SetBucketFor(string, LeakyBucket) error +} diff --git a/vendor/github.com/hpcloud/tail/tail.go b/vendor/github.com/hpcloud/tail/tail.go new file mode 100644 index 00000000..2d252d60 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/tail.go @@ -0,0 +1,438 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package tail + +import ( + "bufio" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "strings" + "sync" + "time" + + "github.com/hpcloud/tail/ratelimiter" + "github.com/hpcloud/tail/util" + "github.com/hpcloud/tail/watch" + "gopkg.in/tomb.v1" +) + +var ( + ErrStop = fmt.Errorf("tail should now stop") +) + +type Line struct { + Text string + Time time.Time + Err error // Error from tail +} + +// NewLine returns a Line with present time. +func NewLine(text string) *Line { + return &Line{text, time.Now(), nil} +} + +// SeekInfo represents arguments to `os.Seek` +type SeekInfo struct { + Offset int64 + Whence int // os.SEEK_* +} + +type logger interface { + Fatal(v ...interface{}) + Fatalf(format string, v ...interface{}) + Fatalln(v ...interface{}) + Panic(v ...interface{}) + Panicf(format string, v ...interface{}) + Panicln(v ...interface{}) + Print(v ...interface{}) + Printf(format string, v ...interface{}) + Println(v ...interface{}) +} + +// Config is used to specify how a file must be tailed. +type Config struct { + // File-specifc + Location *SeekInfo // Seek to this location before tailing + ReOpen bool // Reopen recreated files (tail -F) + MustExist bool // Fail early if the file does not exist + Poll bool // Poll for file changes instead of using inotify + Pipe bool // Is a named pipe (mkfifo) + RateLimiter *ratelimiter.LeakyBucket + + // Generic IO + Follow bool // Continue looking for new lines (tail -f) + MaxLineSize int // If non-zero, split longer lines into multiple lines + + // Logger, when nil, is set to tail.DefaultLogger + // To disable logging: set field to tail.DiscardingLogger + Logger logger +} + +type Tail struct { + Filename string + Lines chan *Line + Config + + file *os.File + reader *bufio.Reader + + watcher watch.FileWatcher + changes *watch.FileChanges + + tomb.Tomb // provides: Done, Kill, Dying + + lk sync.Mutex +} + +var ( + // DefaultLogger is used when Config.Logger == nil + DefaultLogger = log.New(os.Stderr, "", log.LstdFlags) + // DiscardingLogger can be used to disable logging output + DiscardingLogger = log.New(ioutil.Discard, "", 0) +) + +// TailFile begins tailing the file. Output stream is made available +// via the `Tail.Lines` channel. To handle errors during tailing, +// invoke the `Wait` or `Err` method after finishing reading from the +// `Lines` channel. +func TailFile(filename string, config Config) (*Tail, error) { + if config.ReOpen && !config.Follow { + util.Fatal("cannot set ReOpen without Follow.") + } + + t := &Tail{ + Filename: filename, + Lines: make(chan *Line), + Config: config, + } + + // when Logger was not specified in config, use default logger + if t.Logger == nil { + t.Logger = log.New(os.Stderr, "", log.LstdFlags) + } + + if t.Poll { + t.watcher = watch.NewPollingFileWatcher(filename) + } else { + t.watcher = watch.NewInotifyFileWatcher(filename) + } + + if t.MustExist { + var err error + t.file, err = OpenFile(t.Filename) + if err != nil { + return nil, err + } + } + + go t.tailFileSync() + + return t, nil +} + +// Return the file's current position, like stdio's ftell(). +// But this value is not very accurate. +// it may readed one line in the chan(tail.Lines), +// so it may lost one line. +func (tail *Tail) Tell() (offset int64, err error) { + if tail.file == nil { + return + } + offset, err = tail.file.Seek(0, os.SEEK_CUR) + if err != nil { + return + } + + tail.lk.Lock() + defer tail.lk.Unlock() + if tail.reader == nil { + return + } + + offset -= int64(tail.reader.Buffered()) + return +} + +// Stop stops the tailing activity. +func (tail *Tail) Stop() error { + tail.Kill(nil) + return tail.Wait() +} + +// StopAtEOF stops tailing as soon as the end of the file is reached. +func (tail *Tail) StopAtEOF() error { + tail.Kill(errStopAtEOF) + return tail.Wait() +} + +var errStopAtEOF = errors.New("tail: stop at eof") + +func (tail *Tail) close() { + close(tail.Lines) + tail.closeFile() +} + +func (tail *Tail) closeFile() { + if tail.file != nil { + tail.file.Close() + tail.file = nil + } +} + +func (tail *Tail) reopen() error { + tail.closeFile() + for { + var err error + tail.file, err = OpenFile(tail.Filename) + if err != nil { + if os.IsNotExist(err) { + tail.Logger.Printf("Waiting for %s to appear...", tail.Filename) + if err := tail.watcher.BlockUntilExists(&tail.Tomb); err != nil { + if err == tomb.ErrDying { + return err + } + return fmt.Errorf("Failed to detect creation of %s: %s", tail.Filename, err) + } + continue + } + return fmt.Errorf("Unable to open file %s: %s", tail.Filename, err) + } + break + } + return nil +} + +func (tail *Tail) readLine() (string, error) { + tail.lk.Lock() + line, err := tail.reader.ReadString('\n') + tail.lk.Unlock() + if err != nil { + // Note ReadString "returns the data read before the error" in + // case of an error, including EOF, so we return it as is. The + // caller is expected to process it if err is EOF. + return line, err + } + + line = strings.TrimRight(line, "\n") + + return line, err +} + +func (tail *Tail) tailFileSync() { + defer tail.Done() + defer tail.close() + + if !tail.MustExist { + // deferred first open. + err := tail.reopen() + if err != nil { + if err != tomb.ErrDying { + tail.Kill(err) + } + return + } + } + + // Seek to requested location on first open of the file. + if tail.Location != nil { + _, err := tail.file.Seek(tail.Location.Offset, tail.Location.Whence) + tail.Logger.Printf("Seeked %s - %+v\n", tail.Filename, tail.Location) + if err != nil { + tail.Killf("Seek error on %s: %s", tail.Filename, err) + return + } + } + + tail.openReader() + + var offset int64 = 0 + var err error + + // Read line by line. + for { + // do not seek in named pipes + if !tail.Pipe { + // grab the position in case we need to back up in the event of a half-line + offset, err = tail.Tell() + if err != nil { + tail.Kill(err) + return + } + } + + line, err := tail.readLine() + + // Process `line` even if err is EOF. + if err == nil { + cooloff := !tail.sendLine(line) + if cooloff { + // Wait a second before seeking till the end of + // file when rate limit is reached. + msg := fmt.Sprintf( + "Too much log activity; waiting a second " + + "before resuming tailing") + tail.Lines <- &Line{msg, time.Now(), fmt.Errorf(msg)} + select { + case <-time.After(time.Second): + case <-tail.Dying(): + return + } + if err := tail.seekEnd(); err != nil { + tail.Kill(err) + return + } + } + } else if err == io.EOF { + if !tail.Follow { + if line != "" { + tail.sendLine(line) + } + return + } + + if tail.Follow && line != "" { + // this has the potential to never return the last line if + // it's not followed by a newline; seems a fair trade here + err := tail.seekTo(SeekInfo{Offset: offset, Whence: 0}) + if err != nil { + tail.Kill(err) + return + } + } + + // When EOF is reached, wait for more data to become + // available. Wait strategy is based on the `tail.watcher` + // implementation (inotify or polling). + err := tail.waitForChanges() + if err != nil { + if err != ErrStop { + tail.Kill(err) + } + return + } + } else { + // non-EOF error + tail.Killf("Error reading %s: %s", tail.Filename, err) + return + } + + select { + case <-tail.Dying(): + if tail.Err() == errStopAtEOF { + continue + } + return + default: + } + } +} + +// waitForChanges waits until the file has been appended, deleted, +// moved or truncated. When moved or deleted - the file will be +// reopened if ReOpen is true. Truncated files are always reopened. +func (tail *Tail) waitForChanges() error { + if tail.changes == nil { + pos, err := tail.file.Seek(0, os.SEEK_CUR) + if err != nil { + return err + } + tail.changes, err = tail.watcher.ChangeEvents(&tail.Tomb, pos) + if err != nil { + return err + } + } + + select { + case <-tail.changes.Modified: + return nil + case <-tail.changes.Deleted: + tail.changes = nil + if tail.ReOpen { + // XXX: we must not log from a library. + tail.Logger.Printf("Re-opening moved/deleted file %s ...", tail.Filename) + if err := tail.reopen(); err != nil { + return err + } + tail.Logger.Printf("Successfully reopened %s", tail.Filename) + tail.openReader() + return nil + } else { + tail.Logger.Printf("Stopping tail as file no longer exists: %s", tail.Filename) + return ErrStop + } + case <-tail.changes.Truncated: + // Always reopen truncated files (Follow is true) + tail.Logger.Printf("Re-opening truncated file %s ...", tail.Filename) + if err := tail.reopen(); err != nil { + return err + } + tail.Logger.Printf("Successfully reopened truncated %s", tail.Filename) + tail.openReader() + return nil + case <-tail.Dying(): + return ErrStop + } + panic("unreachable") +} + +func (tail *Tail) openReader() { + if tail.MaxLineSize > 0 { + // add 2 to account for newline characters + tail.reader = bufio.NewReaderSize(tail.file, tail.MaxLineSize+2) + } else { + tail.reader = bufio.NewReader(tail.file) + } +} + +func (tail *Tail) seekEnd() error { + return tail.seekTo(SeekInfo{Offset: 0, Whence: os.SEEK_END}) +} + +func (tail *Tail) seekTo(pos SeekInfo) error { + _, err := tail.file.Seek(pos.Offset, pos.Whence) + if err != nil { + return fmt.Errorf("Seek error on %s: %s", tail.Filename, err) + } + // Reset the read buffer whenever the file is re-seek'ed + tail.reader.Reset(tail.file) + return nil +} + +// sendLine sends the line(s) to Lines channel, splitting longer lines +// if necessary. Return false if rate limit is reached. +func (tail *Tail) sendLine(line string) bool { + now := time.Now() + lines := []string{line} + + // Split longer lines + if tail.MaxLineSize > 0 && len(line) > tail.MaxLineSize { + lines = util.PartitionString(line, tail.MaxLineSize) + } + + for _, line := range lines { + tail.Lines <- &Line{line, now, nil} + } + + if tail.Config.RateLimiter != nil { + ok := tail.Config.RateLimiter.Pour(uint16(len(lines))) + if !ok { + tail.Logger.Printf("Leaky bucket full (%v); entering 1s cooloff period.\n", + tail.Filename) + return false + } + } + + return true +} + +// Cleanup removes inotify watches added by the tail package. This function is +// meant to be invoked from a process's exit handler. Linux kernel may not +// automatically remove inotify watches after the process exits. +func (tail *Tail) Cleanup() { + watch.Cleanup(tail.Filename) +} diff --git a/vendor/github.com/hpcloud/tail/tail_posix.go b/vendor/github.com/hpcloud/tail/tail_posix.go new file mode 100644 index 00000000..bc4dc335 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/tail_posix.go @@ -0,0 +1,11 @@ +// +build linux darwin freebsd netbsd openbsd + +package tail + +import ( + "os" +) + +func OpenFile(name string) (file *os.File, err error) { + return os.Open(name) +} diff --git a/vendor/github.com/hpcloud/tail/tail_test.go b/vendor/github.com/hpcloud/tail/tail_test.go new file mode 100644 index 00000000..8dcc02c2 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/tail_test.go @@ -0,0 +1,521 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +// TODO: +// * repeat all the tests with Poll:true + +package tail + +import ( + _ "fmt" + "io/ioutil" + "os" + "strings" + "testing" + "time" + + "github.com/hpcloud/tail/ratelimiter" + "github.com/hpcloud/tail/watch" +) + +func init() { + // Clear the temporary test directory + err := os.RemoveAll(".test") + if err != nil { + panic(err) + } +} + +func TestMain(m *testing.M) { + // Use a smaller poll duration for faster test runs. Keep it below + // 100ms (which value is used as common delays for tests) + watch.POLL_DURATION = 5 * time.Millisecond + os.Exit(m.Run()) +} + +func TestMustExist(t *testing.T) { + tail, err := TailFile("/no/such/file", Config{Follow: true, MustExist: true}) + if err == nil { + t.Error("MustExist:true is violated") + tail.Stop() + } + tail, err = TailFile("/no/such/file", Config{Follow: true, MustExist: false}) + if err != nil { + t.Error("MustExist:false is violated") + } + tail.Stop() + _, err = TailFile("README.md", Config{Follow: true, MustExist: true}) + if err != nil { + t.Error("MustExist:true on an existing file is violated") + } + tail.Cleanup() +} + +func TestWaitsForFileToExist(t *testing.T) { + tailTest := NewTailTest("waits-for-file-to-exist", t) + tail := tailTest.StartTail("test.txt", Config{}) + go tailTest.VerifyTailOutput(tail, []string{"hello", "world"}, false) + + <-time.After(100 * time.Millisecond) + tailTest.CreateFile("test.txt", "hello\nworld\n") + tailTest.Cleanup(tail, true) +} + +func TestWaitsForFileToExistRelativePath(t *testing.T) { + tailTest := NewTailTest("waits-for-file-to-exist-relative", t) + + oldWD, err := os.Getwd() + if err != nil { + tailTest.Fatal(err) + } + os.Chdir(tailTest.path) + defer os.Chdir(oldWD) + + tail, err := TailFile("test.txt", Config{}) + if err != nil { + tailTest.Fatal(err) + } + + go tailTest.VerifyTailOutput(tail, []string{"hello", "world"}, false) + + <-time.After(100 * time.Millisecond) + if err := ioutil.WriteFile("test.txt", []byte("hello\nworld\n"), 0600); err != nil { + tailTest.Fatal(err) + } + tailTest.Cleanup(tail, true) +} + +func TestStop(t *testing.T) { + tail, err := TailFile("_no_such_file", Config{Follow: true, MustExist: false}) + if err != nil { + t.Error("MustExist:false is violated") + } + if tail.Stop() != nil { + t.Error("Should be stoped successfully") + } + tail.Cleanup() +} + +func TestStopAtEOF(t *testing.T) { + tailTest := NewTailTest("maxlinesize", t) + tailTest.CreateFile("test.txt", "hello\nthere\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: true, Location: nil}) + + // read "hello" + line := <-tail.Lines + if line.Text != "hello" { + t.Errorf("Expected to get 'hello', got '%s' instead", line.Text) + } + + tailTest.VerifyTailOutput(tail, []string{"there", "world"}, false) + tail.StopAtEOF() + tailTest.Cleanup(tail, true) +} + +func TestMaxLineSizeFollow(t *testing.T) { + // As last file line does not end with newline, it will not be present in tail's output + maxLineSize(t, true, "hello\nworld\nfin\nhe", []string{"hel", "lo", "wor", "ld", "fin"}) +} + +func TestMaxLineSizeNoFollow(t *testing.T) { + maxLineSize(t, false, "hello\nworld\nfin\nhe", []string{"hel", "lo", "wor", "ld", "fin", "he"}) +} + +func TestOver4096ByteLine(t *testing.T) { + tailTest := NewTailTest("Over4096ByteLine", t) + testString := strings.Repeat("a", 4097) + tailTest.CreateFile("test.txt", "test\n"+testString+"\nhello\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: true, Location: nil}) + go tailTest.VerifyTailOutput(tail, []string{"test", testString, "hello", "world"}, false) + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + tailTest.Cleanup(tail, true) +} +func TestOver4096ByteLineWithSetMaxLineSize(t *testing.T) { + tailTest := NewTailTest("Over4096ByteLineMaxLineSize", t) + testString := strings.Repeat("a", 4097) + tailTest.CreateFile("test.txt", "test\n"+testString+"\nhello\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: true, Location: nil, MaxLineSize: 4097}) + go tailTest.VerifyTailOutput(tail, []string{"test", testString, "hello", "world"}, false) + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + tailTest.Cleanup(tail, true) +} + +func TestLocationFull(t *testing.T) { + tailTest := NewTailTest("location-full", t) + tailTest.CreateFile("test.txt", "hello\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: true, Location: nil}) + go tailTest.VerifyTailOutput(tail, []string{"hello", "world"}, false) + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + tailTest.Cleanup(tail, true) +} + +func TestLocationFullDontFollow(t *testing.T) { + tailTest := NewTailTest("location-full-dontfollow", t) + tailTest.CreateFile("test.txt", "hello\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: false, Location: nil}) + go tailTest.VerifyTailOutput(tail, []string{"hello", "world"}, false) + + // Add more data only after reasonable delay. + <-time.After(100 * time.Millisecond) + tailTest.AppendFile("test.txt", "more\ndata\n") + <-time.After(100 * time.Millisecond) + + tailTest.Cleanup(tail, true) +} + +func TestLocationEnd(t *testing.T) { + tailTest := NewTailTest("location-end", t) + tailTest.CreateFile("test.txt", "hello\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: true, Location: &SeekInfo{0, os.SEEK_END}}) + go tailTest.VerifyTailOutput(tail, []string{"more", "data"}, false) + + <-time.After(100 * time.Millisecond) + tailTest.AppendFile("test.txt", "more\ndata\n") + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + tailTest.Cleanup(tail, true) +} + +func TestLocationMiddle(t *testing.T) { + // Test reading from middle. + tailTest := NewTailTest("location-middle", t) + tailTest.CreateFile("test.txt", "hello\nworld\n") + tail := tailTest.StartTail("test.txt", Config{Follow: true, Location: &SeekInfo{-6, os.SEEK_END}}) + go tailTest.VerifyTailOutput(tail, []string{"world", "more", "data"}, false) + + <-time.After(100 * time.Millisecond) + tailTest.AppendFile("test.txt", "more\ndata\n") + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + tailTest.Cleanup(tail, true) +} + +// The use of polling file watcher could affect file rotation +// (detected via renames), so test these explicitly. + +func TestReOpenInotify(t *testing.T) { + reOpen(t, false) +} + +func TestReOpenPolling(t *testing.T) { + reOpen(t, true) +} + +// The use of polling file watcher could affect file rotation +// (detected via renames), so test these explicitly. + +func TestReSeekInotify(t *testing.T) { + reSeek(t, false) +} + +func TestReSeekPolling(t *testing.T) { + reSeek(t, true) +} + +func TestRateLimiting(t *testing.T) { + tailTest := NewTailTest("rate-limiting", t) + tailTest.CreateFile("test.txt", "hello\nworld\nagain\nextra\n") + config := Config{ + Follow: true, + RateLimiter: ratelimiter.NewLeakyBucket(2, time.Second)} + leakybucketFull := "Too much log activity; waiting a second before resuming tailing" + tail := tailTest.StartTail("test.txt", config) + + // TODO: also verify that tail resumes after the cooloff period. + go tailTest.VerifyTailOutput(tail, []string{ + "hello", "world", "again", + leakybucketFull, + "more", "data", + leakybucketFull}, false) + + // Add more data only after reasonable delay. + <-time.After(1200 * time.Millisecond) + tailTest.AppendFile("test.txt", "more\ndata\n") + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + + tailTest.Cleanup(tail, true) +} + +func TestTell(t *testing.T) { + tailTest := NewTailTest("tell-position", t) + tailTest.CreateFile("test.txt", "hello\nworld\nagain\nmore\n") + config := Config{ + Follow: false, + Location: &SeekInfo{0, os.SEEK_SET}} + tail := tailTest.StartTail("test.txt", config) + // read noe line + <-tail.Lines + offset, err := tail.Tell() + if err != nil { + tailTest.Errorf("Tell return error: %s", err.Error()) + } + tail.Done() + // tail.close() + + config = Config{ + Follow: false, + Location: &SeekInfo{offset, os.SEEK_SET}} + tail = tailTest.StartTail("test.txt", config) + for l := range tail.Lines { + // it may readed one line in the chan(tail.Lines), + // so it may lost one line. + if l.Text != "world" && l.Text != "again" { + tailTest.Fatalf("mismatch; expected world or again, but got %s", + l.Text) + } + break + } + tailTest.RemoveFile("test.txt") + tail.Done() + tail.Cleanup() +} + +func TestBlockUntilExists(t *testing.T) { + tailTest := NewTailTest("block-until-file-exists", t) + config := Config{ + Follow: true, + } + tail := tailTest.StartTail("test.txt", config) + go func() { + time.Sleep(100 * time.Millisecond) + tailTest.CreateFile("test.txt", "hello world\n") + }() + for l := range tail.Lines { + if l.Text != "hello world" { + tailTest.Fatalf("mismatch; expected hello world, but got %s", + l.Text) + } + break + } + tailTest.RemoveFile("test.txt") + tail.Stop() + tail.Cleanup() +} + +func maxLineSize(t *testing.T, follow bool, fileContent string, expected []string) { + tailTest := NewTailTest("maxlinesize", t) + tailTest.CreateFile("test.txt", fileContent) + tail := tailTest.StartTail("test.txt", Config{Follow: follow, Location: nil, MaxLineSize: 3}) + go tailTest.VerifyTailOutput(tail, expected, false) + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + tailTest.Cleanup(tail, true) +} + +func reOpen(t *testing.T, poll bool) { + var name string + var delay time.Duration + if poll { + name = "reopen-polling" + delay = 300 * time.Millisecond // account for POLL_DURATION + } else { + name = "reopen-inotify" + delay = 100 * time.Millisecond + } + tailTest := NewTailTest(name, t) + tailTest.CreateFile("test.txt", "hello\nworld\n") + tail := tailTest.StartTail( + "test.txt", + Config{Follow: true, ReOpen: true, Poll: poll}) + content := []string{"hello", "world", "more", "data", "endofworld"} + go tailTest.ReadLines(tail, content) + + // deletion must trigger reopen + <-time.After(delay) + tailTest.RemoveFile("test.txt") + <-time.After(delay) + tailTest.CreateFile("test.txt", "more\ndata\n") + + // rename must trigger reopen + <-time.After(delay) + tailTest.RenameFile("test.txt", "test.txt.rotated") + <-time.After(delay) + tailTest.CreateFile("test.txt", "endofworld\n") + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(delay) + tailTest.RemoveFile("test.txt") + <-time.After(delay) + + // Do not bother with stopping as it could kill the tomb during + // the reading of data written above. Timings can vary based on + // test environment. + tail.Cleanup() +} + +func reSeek(t *testing.T, poll bool) { + var name string + if poll { + name = "reseek-polling" + } else { + name = "reseek-inotify" + } + tailTest := NewTailTest(name, t) + tailTest.CreateFile("test.txt", "a really long string goes here\nhello\nworld\n") + tail := tailTest.StartTail( + "test.txt", + Config{Follow: true, ReOpen: false, Poll: poll}) + + go tailTest.VerifyTailOutput(tail, []string{ + "a really long string goes here", "hello", "world", "h311o", "w0r1d", "endofworld"}, false) + + // truncate now + <-time.After(100 * time.Millisecond) + tailTest.TruncateFile("test.txt", "h311o\nw0r1d\nendofworld\n") + + // Delete after a reasonable delay, to give tail sufficient time + // to read all lines. + <-time.After(100 * time.Millisecond) + tailTest.RemoveFile("test.txt") + + // Do not bother with stopping as it could kill the tomb during + // the reading of data written above. Timings can vary based on + // test environment. + tailTest.Cleanup(tail, false) +} + +// Test library + +type TailTest struct { + Name string + path string + done chan struct{} + *testing.T +} + +func NewTailTest(name string, t *testing.T) TailTest { + tt := TailTest{name, ".test/" + name, make(chan struct{}), t} + err := os.MkdirAll(tt.path, os.ModeTemporary|0700) + if err != nil { + tt.Fatal(err) + } + + return tt +} + +func (t TailTest) CreateFile(name string, contents string) { + err := ioutil.WriteFile(t.path+"/"+name, []byte(contents), 0600) + if err != nil { + t.Fatal(err) + } +} + +func (t TailTest) RemoveFile(name string) { + err := os.Remove(t.path + "/" + name) + if err != nil { + t.Fatal(err) + } +} + +func (t TailTest) RenameFile(oldname string, newname string) { + oldname = t.path + "/" + oldname + newname = t.path + "/" + newname + err := os.Rename(oldname, newname) + if err != nil { + t.Fatal(err) + } +} + +func (t TailTest) AppendFile(name string, contents string) { + f, err := os.OpenFile(t.path+"/"+name, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + t.Fatal(err) + } + defer f.Close() + _, err = f.WriteString(contents) + if err != nil { + t.Fatal(err) + } +} + +func (t TailTest) TruncateFile(name string, contents string) { + f, err := os.OpenFile(t.path+"/"+name, os.O_TRUNC|os.O_WRONLY, 0600) + if err != nil { + t.Fatal(err) + } + defer f.Close() + _, err = f.WriteString(contents) + if err != nil { + t.Fatal(err) + } +} + +func (t TailTest) StartTail(name string, config Config) *Tail { + tail, err := TailFile(t.path+"/"+name, config) + if err != nil { + t.Fatal(err) + } + return tail +} + +func (t TailTest) VerifyTailOutput(tail *Tail, lines []string, expectEOF bool) { + defer close(t.done) + t.ReadLines(tail, lines) + // It is important to do this if only EOF is expected + // otherwise we could block on <-tail.Lines + if expectEOF { + line, ok := <-tail.Lines + if ok { + t.Fatalf("more content from tail: %+v", line) + } + } +} + +func (t TailTest) ReadLines(tail *Tail, lines []string) { + for idx, line := range lines { + tailedLine, ok := <-tail.Lines + if !ok { + // tail.Lines is closed and empty. + err := tail.Err() + if err != nil { + t.Fatalf("tail ended with error: %v", err) + } + t.Fatalf("tail ended early; expecting more: %v", lines[idx:]) + } + if tailedLine == nil { + t.Fatalf("tail.Lines returned nil; not possible") + } + // Note: not checking .Err as the `lines` argument is designed + // to match error strings as well. + if tailedLine.Text != line { + t.Fatalf( + "unexpected line/err from tail: "+ + "expecting <<%s>>>, but got <<<%s>>>", + line, tailedLine.Text) + } + } +} + +func (t TailTest) Cleanup(tail *Tail, stop bool) { + <-t.done + if stop { + tail.Stop() + } + tail.Cleanup() +} diff --git a/vendor/github.com/hpcloud/tail/tail_windows.go b/vendor/github.com/hpcloud/tail/tail_windows.go new file mode 100644 index 00000000..ef2cfca1 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/tail_windows.go @@ -0,0 +1,12 @@ +// +build windows + +package tail + +import ( + "github.com/hpcloud/tail/winfile" + "os" +) + +func OpenFile(name string) (file *os.File, err error) { + return winfile.OpenFile(name, os.O_RDONLY, 0) +} diff --git a/vendor/github.com/hpcloud/tail/util/util.go b/vendor/github.com/hpcloud/tail/util/util.go new file mode 100644 index 00000000..54151fe3 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/util/util.go @@ -0,0 +1,48 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package util + +import ( + "fmt" + "log" + "os" + "runtime/debug" +) + +type Logger struct { + *log.Logger +} + +var LOGGER = &Logger{log.New(os.Stderr, "", log.LstdFlags)} + +// fatal is like panic except it displays only the current goroutine's stack. +func Fatal(format string, v ...interface{}) { + // https://github.com/hpcloud/log/blob/master/log.go#L45 + LOGGER.Output(2, fmt.Sprintf("FATAL -- "+format, v...)+"\n"+string(debug.Stack())) + os.Exit(1) +} + +// partitionString partitions the string into chunks of given size, +// with the last chunk of variable size. +func PartitionString(s string, chunkSize int) []string { + if chunkSize <= 0 { + panic("invalid chunkSize") + } + length := len(s) + chunks := 1 + length/chunkSize + start := 0 + end := chunkSize + parts := make([]string, 0, chunks) + for { + if end > length { + end = length + } + parts = append(parts, s[start:end]) + if end == length { + break + } + start, end = end, end+chunkSize + } + return parts +} diff --git a/vendor/github.com/hpcloud/tail/watch/filechanges.go b/vendor/github.com/hpcloud/tail/watch/filechanges.go new file mode 100644 index 00000000..3ce5dcec --- /dev/null +++ b/vendor/github.com/hpcloud/tail/watch/filechanges.go @@ -0,0 +1,36 @@ +package watch + +type FileChanges struct { + Modified chan bool // Channel to get notified of modifications + Truncated chan bool // Channel to get notified of truncations + Deleted chan bool // Channel to get notified of deletions/renames +} + +func NewFileChanges() *FileChanges { + return &FileChanges{ + make(chan bool), make(chan bool), make(chan bool)} +} + +func (fc *FileChanges) NotifyModified() { + sendOnlyIfEmpty(fc.Modified) +} + +func (fc *FileChanges) NotifyTruncated() { + sendOnlyIfEmpty(fc.Truncated) +} + +func (fc *FileChanges) NotifyDeleted() { + sendOnlyIfEmpty(fc.Deleted) +} + +// sendOnlyIfEmpty sends on a bool channel only if the channel has no +// backlog to be read by other goroutines. This concurrency pattern +// can be used to notify other goroutines if and only if they are +// looking for it (i.e., subsequent notifications can be compressed +// into one). +func sendOnlyIfEmpty(ch chan bool) { + select { + case ch <- true: + default: + } +} diff --git a/vendor/github.com/hpcloud/tail/watch/inotify.go b/vendor/github.com/hpcloud/tail/watch/inotify.go new file mode 100644 index 00000000..4478f1e1 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/watch/inotify.go @@ -0,0 +1,128 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package watch + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/hpcloud/tail/util" + + "gopkg.in/fsnotify.v1" + "gopkg.in/tomb.v1" +) + +// InotifyFileWatcher uses inotify to monitor file changes. +type InotifyFileWatcher struct { + Filename string + Size int64 +} + +func NewInotifyFileWatcher(filename string) *InotifyFileWatcher { + fw := &InotifyFileWatcher{filepath.Clean(filename), 0} + return fw +} + +func (fw *InotifyFileWatcher) BlockUntilExists(t *tomb.Tomb) error { + err := WatchCreate(fw.Filename) + if err != nil { + return err + } + defer RemoveWatchCreate(fw.Filename) + + // Do a real check now as the file might have been created before + // calling `WatchFlags` above. + if _, err = os.Stat(fw.Filename); !os.IsNotExist(err) { + // file exists, or stat returned an error. + return err + } + + events := Events(fw.Filename) + + for { + select { + case evt, ok := <-events: + if !ok { + return fmt.Errorf("inotify watcher has been closed") + } + evtName, err := filepath.Abs(evt.Name) + if err != nil { + return err + } + fwFilename, err := filepath.Abs(fw.Filename) + if err != nil { + return err + } + if evtName == fwFilename { + return nil + } + case <-t.Dying(): + return tomb.ErrDying + } + } + panic("unreachable") +} + +func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChanges, error) { + err := Watch(fw.Filename) + if err != nil { + return nil, err + } + + changes := NewFileChanges() + fw.Size = pos + + go func() { + defer RemoveWatch(fw.Filename) + + events := Events(fw.Filename) + + for { + prevSize := fw.Size + + var evt fsnotify.Event + var ok bool + + select { + case evt, ok = <-events: + if !ok { + return + } + case <-t.Dying(): + return + } + + switch { + case evt.Op&fsnotify.Remove == fsnotify.Remove: + fallthrough + + case evt.Op&fsnotify.Rename == fsnotify.Rename: + changes.NotifyDeleted() + return + + case evt.Op&fsnotify.Write == fsnotify.Write: + fi, err := os.Stat(fw.Filename) + if err != nil { + if os.IsNotExist(err) { + changes.NotifyDeleted() + return + } + // XXX: report this error back to the user + util.Fatal("Failed to stat file %v: %v", fw.Filename, err) + } + fw.Size = fi.Size() + + if prevSize > 0 && prevSize > fw.Size { + changes.NotifyTruncated() + } else { + changes.NotifyModified() + } + prevSize = fw.Size + } + } + }() + + return changes, nil +} diff --git a/vendor/github.com/hpcloud/tail/watch/inotify_tracker.go b/vendor/github.com/hpcloud/tail/watch/inotify_tracker.go new file mode 100644 index 00000000..03be4275 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/watch/inotify_tracker.go @@ -0,0 +1,260 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package watch + +import ( + "log" + "os" + "path/filepath" + "sync" + "syscall" + + "github.com/hpcloud/tail/util" + + "gopkg.in/fsnotify.v1" +) + +type InotifyTracker struct { + mux sync.Mutex + watcher *fsnotify.Watcher + chans map[string]chan fsnotify.Event + done map[string]chan bool + watchNums map[string]int + watch chan *watchInfo + remove chan *watchInfo + error chan error +} + +type watchInfo struct { + op fsnotify.Op + fname string +} + +func (this *watchInfo) isCreate() bool { + return this.op == fsnotify.Create +} + +var ( + // globally shared InotifyTracker; ensures only one fsnotify.Watcher is used + shared *InotifyTracker + + // these are used to ensure the shared InotifyTracker is run exactly once + once = sync.Once{} + goRun = func() { + shared = &InotifyTracker{ + mux: sync.Mutex{}, + chans: make(map[string]chan fsnotify.Event), + done: make(map[string]chan bool), + watchNums: make(map[string]int), + watch: make(chan *watchInfo), + remove: make(chan *watchInfo), + error: make(chan error), + } + go shared.run() + } + + logger = log.New(os.Stderr, "", log.LstdFlags) +) + +// Watch signals the run goroutine to begin watching the input filename +func Watch(fname string) error { + return watch(&watchInfo{ + fname: fname, + }) +} + +// Watch create signals the run goroutine to begin watching the input filename +// if call the WatchCreate function, don't call the Cleanup, call the RemoveWatchCreate +func WatchCreate(fname string) error { + return watch(&watchInfo{ + op: fsnotify.Create, + fname: fname, + }) +} + +func watch(winfo *watchInfo) error { + // start running the shared InotifyTracker if not already running + once.Do(goRun) + + winfo.fname = filepath.Clean(winfo.fname) + shared.watch <- winfo + return <-shared.error +} + +// RemoveWatch signals the run goroutine to remove the watch for the input filename +func RemoveWatch(fname string) { + remove(&watchInfo{ + fname: fname, + }) +} + +// RemoveWatch create signals the run goroutine to remove the watch for the input filename +func RemoveWatchCreate(fname string) { + remove(&watchInfo{ + op: fsnotify.Create, + fname: fname, + }) +} + +func remove(winfo *watchInfo) { + // start running the shared InotifyTracker if not already running + once.Do(goRun) + + winfo.fname = filepath.Clean(winfo.fname) + shared.mux.Lock() + done := shared.done[winfo.fname] + if done != nil { + delete(shared.done, winfo.fname) + close(done) + } + + fname := winfo.fname + if winfo.isCreate() { + // Watch for new files to be created in the parent directory. + fname = filepath.Dir(fname) + } + shared.watchNums[fname]-- + watchNum := shared.watchNums[fname] + if watchNum == 0 { + delete(shared.watchNums, fname) + } + shared.mux.Unlock() + + // If we were the last ones to watch this file, unsubscribe from inotify. + // This needs to happen after releasing the lock because fsnotify waits + // synchronously for the kernel to acknowledge the removal of the watch + // for this file, which causes us to deadlock if we still held the lock. + if watchNum == 0 { + shared.watcher.Remove(fname) + } + shared.remove <- winfo +} + +// Events returns a channel to which FileEvents corresponding to the input filename +// will be sent. This channel will be closed when removeWatch is called on this +// filename. +func Events(fname string) <-chan fsnotify.Event { + shared.mux.Lock() + defer shared.mux.Unlock() + + return shared.chans[fname] +} + +// Cleanup removes the watch for the input filename if necessary. +func Cleanup(fname string) { + RemoveWatch(fname) +} + +// watchFlags calls fsnotify.WatchFlags for the input filename and flags, creating +// a new Watcher if the previous Watcher was closed. +func (shared *InotifyTracker) addWatch(winfo *watchInfo) error { + shared.mux.Lock() + defer shared.mux.Unlock() + + if shared.chans[winfo.fname] == nil { + shared.chans[winfo.fname] = make(chan fsnotify.Event) + shared.done[winfo.fname] = make(chan bool) + } + + fname := winfo.fname + if winfo.isCreate() { + // Watch for new files to be created in the parent directory. + fname = filepath.Dir(fname) + } + + // already in inotify watch + if shared.watchNums[fname] > 0 { + shared.watchNums[fname]++ + if winfo.isCreate() { + shared.watchNums[winfo.fname]++ + } + return nil + } + + err := shared.watcher.Add(fname) + if err == nil { + shared.watchNums[fname]++ + if winfo.isCreate() { + shared.watchNums[winfo.fname]++ + } + } + return err +} + +// removeWatch calls fsnotify.RemoveWatch for the input filename and closes the +// corresponding events channel. +func (shared *InotifyTracker) removeWatch(winfo *watchInfo) { + shared.mux.Lock() + defer shared.mux.Unlock() + + ch := shared.chans[winfo.fname] + if ch == nil { + return + } + + delete(shared.chans, winfo.fname) + close(ch) + + if !winfo.isCreate() { + return + } + + shared.watchNums[winfo.fname]-- + if shared.watchNums[winfo.fname] == 0 { + delete(shared.watchNums, winfo.fname) + } +} + +// sendEvent sends the input event to the appropriate Tail. +func (shared *InotifyTracker) sendEvent(event fsnotify.Event) { + name := filepath.Clean(event.Name) + + shared.mux.Lock() + ch := shared.chans[name] + done := shared.done[name] + shared.mux.Unlock() + + if ch != nil && done != nil { + select { + case ch <- event: + case <-done: + } + } +} + +// run starts the goroutine in which the shared struct reads events from its +// Watcher's Event channel and sends the events to the appropriate Tail. +func (shared *InotifyTracker) run() { + watcher, err := fsnotify.NewWatcher() + if err != nil { + util.Fatal("failed to create Watcher") + } + shared.watcher = watcher + + for { + select { + case winfo := <-shared.watch: + shared.error <- shared.addWatch(winfo) + + case winfo := <-shared.remove: + shared.removeWatch(winfo) + + case event, open := <-shared.watcher.Events: + if !open { + return + } + shared.sendEvent(event) + + case err, open := <-shared.watcher.Errors: + if !open { + return + } else if err != nil { + sysErr, ok := err.(*os.SyscallError) + if !ok || sysErr.Err != syscall.EINTR { + logger.Printf("Error in Watcher Error channel: %s", err) + } + } + } + } +} diff --git a/vendor/github.com/hpcloud/tail/watch/polling.go b/vendor/github.com/hpcloud/tail/watch/polling.go new file mode 100644 index 00000000..49491f21 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/watch/polling.go @@ -0,0 +1,118 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package watch + +import ( + "os" + "runtime" + "time" + + "github.com/hpcloud/tail/util" + "gopkg.in/tomb.v1" +) + +// PollingFileWatcher polls the file for changes. +type PollingFileWatcher struct { + Filename string + Size int64 +} + +func NewPollingFileWatcher(filename string) *PollingFileWatcher { + fw := &PollingFileWatcher{filename, 0} + return fw +} + +var POLL_DURATION time.Duration + +func (fw *PollingFileWatcher) BlockUntilExists(t *tomb.Tomb) error { + for { + if _, err := os.Stat(fw.Filename); err == nil { + return nil + } else if !os.IsNotExist(err) { + return err + } + select { + case <-time.After(POLL_DURATION): + continue + case <-t.Dying(): + return tomb.ErrDying + } + } + panic("unreachable") +} + +func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChanges, error) { + origFi, err := os.Stat(fw.Filename) + if err != nil { + return nil, err + } + + changes := NewFileChanges() + var prevModTime time.Time + + // XXX: use tomb.Tomb to cleanly manage these goroutines. replace + // the fatal (below) with tomb's Kill. + + fw.Size = pos + + go func() { + prevSize := fw.Size + for { + select { + case <-t.Dying(): + return + default: + } + + time.Sleep(POLL_DURATION) + fi, err := os.Stat(fw.Filename) + if err != nil { + // Windows cannot delete a file if a handle is still open (tail keeps one open) + // so it gives access denied to anything trying to read it until all handles are released. + if os.IsNotExist(err) || (runtime.GOOS == "windows" && os.IsPermission(err)) { + // File does not exist (has been deleted). + changes.NotifyDeleted() + return + } + + // XXX: report this error back to the user + util.Fatal("Failed to stat file %v: %v", fw.Filename, err) + } + + // File got moved/renamed? + if !os.SameFile(origFi, fi) { + changes.NotifyDeleted() + return + } + + // File got truncated? + fw.Size = fi.Size() + if prevSize > 0 && prevSize > fw.Size { + changes.NotifyTruncated() + prevSize = fw.Size + continue + } + // File got bigger? + if prevSize > 0 && prevSize < fw.Size { + changes.NotifyModified() + prevSize = fw.Size + continue + } + prevSize = fw.Size + + // File was appended to (changed)? + modTime := fi.ModTime() + if modTime != prevModTime { + prevModTime = modTime + changes.NotifyModified() + } + } + }() + + return changes, nil +} + +func init() { + POLL_DURATION = 250 * time.Millisecond +} diff --git a/vendor/github.com/hpcloud/tail/watch/watch.go b/vendor/github.com/hpcloud/tail/watch/watch.go new file mode 100644 index 00000000..2e1783ef --- /dev/null +++ b/vendor/github.com/hpcloud/tail/watch/watch.go @@ -0,0 +1,20 @@ +// Copyright (c) 2015 HPE Software Inc. All rights reserved. +// Copyright (c) 2013 ActiveState Software Inc. All rights reserved. + +package watch + +import "gopkg.in/tomb.v1" + +// FileWatcher monitors file-level events. +type FileWatcher interface { + // BlockUntilExists blocks until the file comes into existence. + BlockUntilExists(*tomb.Tomb) error + + // ChangeEvents reports on changes to a file, be it modification, + // deletion, renames or truncations. Returned FileChanges group of + // channels will be closed, thus become unusable, after a deletion + // or truncation event. + // In order to properly report truncations, ChangeEvents requires + // the caller to pass their current offset in the file. + ChangeEvents(*tomb.Tomb, int64) (*FileChanges, error) +} diff --git a/vendor/github.com/hpcloud/tail/winfile/winfile.go b/vendor/github.com/hpcloud/tail/winfile/winfile.go new file mode 100644 index 00000000..aa7e7bc5 --- /dev/null +++ b/vendor/github.com/hpcloud/tail/winfile/winfile.go @@ -0,0 +1,92 @@ +// +build windows + +package winfile + +import ( + "os" + "syscall" + "unsafe" +) + +// issue also described here +//https://codereview.appspot.com/8203043/ + +// https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L218 +func Open(path string, mode int, perm uint32) (fd syscall.Handle, err error) { + if len(path) == 0 { + return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND + } + pathp, err := syscall.UTF16PtrFromString(path) + if err != nil { + return syscall.InvalidHandle, err + } + var access uint32 + switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) { + case syscall.O_RDONLY: + access = syscall.GENERIC_READ + case syscall.O_WRONLY: + access = syscall.GENERIC_WRITE + case syscall.O_RDWR: + access = syscall.GENERIC_READ | syscall.GENERIC_WRITE + } + if mode&syscall.O_CREAT != 0 { + access |= syscall.GENERIC_WRITE + } + if mode&syscall.O_APPEND != 0 { + access &^= syscall.GENERIC_WRITE + access |= syscall.FILE_APPEND_DATA + } + sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE) + var sa *syscall.SecurityAttributes + if mode&syscall.O_CLOEXEC == 0 { + sa = makeInheritSa() + } + var createmode uint32 + switch { + case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL): + createmode = syscall.CREATE_NEW + case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC): + createmode = syscall.CREATE_ALWAYS + case mode&syscall.O_CREAT == syscall.O_CREAT: + createmode = syscall.OPEN_ALWAYS + case mode&syscall.O_TRUNC == syscall.O_TRUNC: + createmode = syscall.TRUNCATE_EXISTING + default: + createmode = syscall.OPEN_EXISTING + } + h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0) + return h, e +} + +// https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L211 +func makeInheritSa() *syscall.SecurityAttributes { + var sa syscall.SecurityAttributes + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + return &sa +} + +// https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_windows.go#L133 +func OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error) { + r, e := Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) + if e != nil { + return nil, e + } + return os.NewFile(uintptr(r), name), nil +} + +// https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_posix.go#L61 +func syscallMode(i os.FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&os.ModeSetuid != 0 { + o |= syscall.S_ISUID + } + if i&os.ModeSetgid != 0 { + o |= syscall.S_ISGID + } + if i&os.ModeSticky != 0 { + o |= syscall.S_ISVTX + } + // No mapping for Go's ModeTemporary (plan9 only). + return +} diff --git a/vendor/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go b/vendor/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go index 29e8adc8..633fb70f 100644 --- a/vendor/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go +++ b/vendor/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go @@ -23,7 +23,7 @@ func main() { dev := &c.ServiceClient.RootDevice.Device srv := c.ServiceClient.Service fmt.Println(dev.FriendlyName, " :: ", srv.String()) - scpd, err := srv.RequestSCDP() + scpd, err := srv.RequestSCPD() if err != nil { fmt.Printf(" Error requesting service SCPD: %v\n", err) } else { diff --git a/vendor/github.com/huin/goupnp/device.go b/vendor/github.com/huin/goupnp/device.go index e5b658b2..567ab4cf 100644 --- a/vendor/github.com/huin/goupnp/device.go +++ b/vendor/github.com/huin/goupnp/device.go @@ -147,9 +147,9 @@ func (srv *Service) String() string { return fmt.Sprintf("Service ID %s : %s", srv.ServiceId, srv.ServiceType) } -// RequestSCDP requests the SCPD (soap actions and state variables description) +// RequestSCPD requests the SCPD (soap actions and state variables description) // for the service. -func (srv *Service) RequestSCDP() (*scpd.SCPD, error) { +func (srv *Service) RequestSCPD() (*scpd.SCPD, error) { if !srv.SCPDURL.Ok { return nil, errors.New("bad/missing SCPD URL, or no URLBase has been set") } @@ -160,6 +160,12 @@ func (srv *Service) RequestSCDP() (*scpd.SCPD, error) { return s, nil } +// RequestSCDP is for compatibility only, prefer RequestSCPD. This was a +// misspelling of RequestSCDP. +func (srv *Service) RequestSCDP() (*scpd.SCPD, error) { + return srv.RequestSCPD() +} + func (srv *Service) NewSOAPClient() *soap.SOAPClient { return soap.NewSOAPClient(srv.ControlURL.URL) } diff --git a/vendor/github.com/huin/goupnp/httpu/httpu.go b/vendor/github.com/huin/goupnp/httpu/httpu.go index 919589cc..44b0c583 100644 --- a/vendor/github.com/huin/goupnp/httpu/httpu.go +++ b/vendor/github.com/huin/goupnp/httpu/httpu.go @@ -128,5 +128,7 @@ func (httpu *HTTPUClient) Do(req *http.Request, timeout time.Duration, numSends responses = append(responses, response) } - return responses, err + + // Timeout reached - return discovered responses. + return responses, nil } diff --git a/vendor/github.com/huin/goupnp/soap/types.go b/vendor/github.com/huin/goupnp/soap/types.go index 813a2e02..3e73d99d 100644 --- a/vendor/github.com/huin/goupnp/soap/types.go +++ b/vendor/github.com/huin/goupnp/soap/types.go @@ -334,7 +334,7 @@ func UnmarshalTimeOfDay(s string) (TimeOfDay, error) { if err != nil { return TimeOfDay{}, err } else if t.HasOffset { - return TimeOfDay{}, fmt.Errorf("soap time: value %q contains unexpected timezone") + return TimeOfDay{}, fmt.Errorf("soap time: value %q contains unexpected timezone", s) } return t, nil } diff --git a/vendor/github.com/huin/goupnp/ssdp/ssdp.go b/vendor/github.com/huin/goupnp/ssdp/ssdp.go index eb61bdbd..4c03b255 100644 --- a/vendor/github.com/huin/goupnp/ssdp/ssdp.go +++ b/vendor/github.com/huin/goupnp/ssdp/ssdp.go @@ -20,6 +20,11 @@ const ( ssdpSearchPort = 1900 methodSearch = "M-SEARCH" methodNotify = "NOTIFY" + + // SSDPAll is a value for searchTarget that searches for all devices and services. + SSDPAll = "ssdp:all" + // UPNPRootDevice is a value for searchTarget that searches for all root devices. + UPNPRootDevice = "upnp:rootdevice" ) // SSDPRawSearch performs a fairly raw SSDP search request, and returns the @@ -54,12 +59,15 @@ func SSDPRawSearch(httpu *httpu.HTTPUClient, searchTarget string, maxWaitSeconds if err != nil { return nil, err } + + isExactSearch := searchTarget != SSDPAll && searchTarget != UPNPRootDevice + for _, response := range allResponses { if response.StatusCode != 200 { log.Printf("ssdp: got response status code %q in search response", response.Status) continue } - if st := response.Header.Get("ST"); st != searchTarget { + if st := response.Header.Get("ST"); isExactSearch && st != searchTarget { continue } location, err := response.Location() diff --git a/vendor/github.com/jmoiron/sqlx/.travis.yml b/vendor/github.com/jmoiron/sqlx/.travis.yml new file mode 100644 index 00000000..6bc68d67 --- /dev/null +++ b/vendor/github.com/jmoiron/sqlx/.travis.yml @@ -0,0 +1,27 @@ +# vim: ft=yaml sw=2 ts=2 + +language: go + +# enable database services +services: + - mysql + - postgresql + +# create test database +before_install: + - mysql -e 'CREATE DATABASE IF NOT EXISTS sqlxtest;' + - psql -c 'create database sqlxtest;' -U postgres + - go get github.com/mattn/goveralls + - export SQLX_MYSQL_DSN="travis:@/sqlxtest?parseTime=true" + - export SQLX_POSTGRES_DSN="postgres://postgres:@localhost/sqlxtest?sslmode=disable" + - export SQLX_SQLITE_DSN="$HOME/sqlxtest.db" + +# go versions to test +go: + - "1.8" + - "1.9" + - "1.10.x" + +# run tests w/ coverage +script: + - travis_retry $GOPATH/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/jmoiron/sqlx/README.md b/vendor/github.com/jmoiron/sqlx/README.md index d2d12589..c0db7f78 100644 --- a/vendor/github.com/jmoiron/sqlx/README.md +++ b/vendor/github.com/jmoiron/sqlx/README.md @@ -1,6 +1,6 @@ # sqlx -[![Build Status](https://drone.io/github.com/jmoiron/sqlx/status.png)](https://drone.io/github.com/jmoiron/sqlx/latest) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/jmoiron/sqlx) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE) +[![Build Status](https://travis-ci.org/jmoiron/sqlx.svg?branch=master)](https://travis-ci.org/jmoiron/sqlx) [![Coverage Status](https://coveralls.io/repos/github/jmoiron/sqlx/badge.svg?branch=master)](https://coveralls.io/github/jmoiron/sqlx?branch=master) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/jmoiron/sqlx) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE) sqlx is a library which provides a set of extensions on go's standard `database/sql` library. The sqlx versions of `sql.DB`, `sql.TX`, `sql.Stmt`, diff --git a/vendor/github.com/jmoiron/sqlx/bind.go b/vendor/github.com/jmoiron/sqlx/bind.go index 10f7bdf8..0fdc4435 100644 --- a/vendor/github.com/jmoiron/sqlx/bind.go +++ b/vendor/github.com/jmoiron/sqlx/bind.go @@ -21,7 +21,7 @@ const ( // BindType returns the bindtype for a given database given a drivername. func BindType(driverName string) int { switch driverName { - case "postgres", "pgx": + case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres": return DOLLAR case "mysql": return QUESTION @@ -113,7 +113,8 @@ func In(query string, args ...interface{}) (string, []interface{}, error) { v := reflect.ValueOf(arg) t := reflectx.Deref(v.Type()) - if t.Kind() == reflect.Slice { + // []byte is a driver.Value type so it should not be expanded + if t.Kind() == reflect.Slice && t != reflect.TypeOf([]byte{}) { meta[i].length = v.Len() meta[i].v = v diff --git a/vendor/github.com/jmoiron/sqlx/named.go b/vendor/github.com/jmoiron/sqlx/named.go index dd899d35..69eb9549 100644 --- a/vendor/github.com/jmoiron/sqlx/named.go +++ b/vendor/github.com/jmoiron/sqlx/named.go @@ -163,16 +163,18 @@ func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{ v = v.Elem() } - fields := m.TraversalsByName(v.Type(), names) - for i, t := range fields { + err := m.TraversalsByNameFunc(v.Type(), names, func(i int, t []int) error { if len(t) == 0 { - return arglist, fmt.Errorf("could not find name %s in %#v", names[i], arg) + return fmt.Errorf("could not find name %s in %#v", names[i], arg) } + val := reflectx.FieldByIndexesReadOnly(v, t) arglist = append(arglist, val.Interface()) - } - return arglist, nil + return nil + }) + + return arglist, err } // like bindArgs, but for maps. diff --git a/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go b/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go index f2802b80..73c21eb3 100644 --- a/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go +++ b/vendor/github.com/jmoiron/sqlx/reflectx/reflect.go @@ -166,20 +166,39 @@ func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value { // traversals for each mapped name. Panics if t is not a struct or Indirectable // to a struct. Returns empty int slice for each name not found. func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int { + r := make([][]int, 0, len(names)) + m.TraversalsByNameFunc(t, names, func(_ int, i []int) error { + if i == nil { + r = append(r, []int{}) + } else { + r = append(r, i) + } + + return nil + }) + return r +} + +// TraversalsByNameFunc traverses the mapped names and calls fn with the index of +// each name and the struct traversal represented by that name. Panics if t is not +// a struct or Indirectable to a struct. Returns the first error returned by fn or nil. +func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int) error) error { t = Deref(t) mustBe(t, reflect.Struct) tm := m.TypeMap(t) - - r := make([][]int, 0, len(names)) - for _, name := range names { + for i, name := range names { fi, ok := tm.Names[name] if !ok { - r = append(r, []int{}) + if err := fn(i, nil); err != nil { + return err + } } else { - r = append(r, fi.Index) + if err := fn(i, fi.Index); err != nil { + return err + } } } - return r + return nil } // FieldByIndexes returns a value for the field given by the struct traversal diff --git a/vendor/github.com/jmoiron/sqlx/reflectx/reflect_test.go b/vendor/github.com/jmoiron/sqlx/reflectx/reflect_test.go index b702f9cd..22f57fd2 100644 --- a/vendor/github.com/jmoiron/sqlx/reflectx/reflect_test.go +++ b/vendor/github.com/jmoiron/sqlx/reflectx/reflect_test.go @@ -903,3 +903,72 @@ func BenchmarkFieldByIndexL4(b *testing.B) { } } } + +func BenchmarkTraversalsByName(b *testing.B) { + type A struct { + Value int + } + + type B struct { + A A + } + + type C struct { + B B + } + + type D struct { + C C + } + + m := NewMapper("") + t := reflect.TypeOf(D{}) + names := []string{"C", "B", "A", "Value"} + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if l := len(m.TraversalsByName(t, names)); l != len(names) { + b.Errorf("expected %d values, got %d", len(names), l) + } + } +} + +func BenchmarkTraversalsByNameFunc(b *testing.B) { + type A struct { + Z int + } + + type B struct { + A A + } + + type C struct { + B B + } + + type D struct { + C C + } + + m := NewMapper("") + t := reflect.TypeOf(D{}) + names := []string{"C", "B", "A", "Z", "Y"} + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + var l int + + if err := m.TraversalsByNameFunc(t, names, func(_ int, _ []int) error { + l++ + return nil + }); err != nil { + b.Errorf("unexpected error %s", err) + } + + if l != len(names) { + b.Errorf("expected %d values, got %d", len(names), l) + } + } +} diff --git a/vendor/github.com/jmoiron/sqlx/sqlx.go b/vendor/github.com/jmoiron/sqlx/sqlx.go index e95f23ff..4385c3fa 100644 --- a/vendor/github.com/jmoiron/sqlx/sqlx.go +++ b/vendor/github.com/jmoiron/sqlx/sqlx.go @@ -228,6 +228,14 @@ func (r *Row) Columns() ([]string, error) { return r.rows.Columns() } +// ColumnTypes returns the underlying sql.Rows.ColumnTypes(), or the deferred error +func (r *Row) ColumnTypes() ([]*sql.ColumnType, error) { + if r.err != nil { + return []*sql.ColumnType{}, r.err + } + return r.rows.ColumnTypes() +} + // Err returns the error encountered while scanning. func (r *Row) Err() error { return r.err @@ -593,7 +601,7 @@ func (r *Rows) StructScan(dest interface{}) error { return errors.New("must pass a pointer, not a value, to StructScan destination") } - v = reflect.Indirect(v) + v = v.Elem() if !r.started { columns, err := r.Columns() diff --git a/vendor/github.com/jmoiron/sqlx/sqlx_context.go b/vendor/github.com/jmoiron/sqlx/sqlx_context.go index 0b171451..d58ff337 100644 --- a/vendor/github.com/jmoiron/sqlx/sqlx_context.go +++ b/vendor/github.com/jmoiron/sqlx/sqlx_context.go @@ -237,6 +237,19 @@ func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt } } +// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt. +// +// The provided context is used for the preparation of the statement, not for +// the execution of the statement. +func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) { + return PreparexContext(ctx, tx, query) +} + +// PrepareNamedContext returns an sqlx.NamedStmt +func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) { + return prepareNamedContext(ctx, tx, query) +} + // MustExecContext runs MustExecContext within a transaction. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { diff --git a/vendor/github.com/jmoiron/sqlx/sqlx_test.go b/vendor/github.com/jmoiron/sqlx/sqlx_test.go index 9502c13e..e26c9807 100644 --- a/vendor/github.com/jmoiron/sqlx/sqlx_test.go +++ b/vendor/github.com/jmoiron/sqlx/sqlx_test.go @@ -1387,13 +1387,17 @@ func (p PropertyMap) Value() (driver.Value, error) { func (p PropertyMap) Scan(src interface{}) error { v := reflect.ValueOf(src) - if !v.IsValid() || v.IsNil() { + if !v.IsValid() || v.CanAddr() && v.IsNil() { return nil } - if data, ok := src.([]byte); ok { - return json.Unmarshal(data, &p) + switch ts := src.(type) { + case []byte: + return json.Unmarshal(ts, &p) + case string: + return json.Unmarshal([]byte(ts), &p) + default: + return fmt.Errorf("Could not not decode type %T -> %T", src, p) } - return fmt.Errorf("Could not not decode type %T -> %T", src, p) } func TestEmbeddedMaps(t *testing.T) { @@ -1493,6 +1497,9 @@ func TestIn(t *testing.T) { {"SELECT * FROM foo WHERE x in (?)", []interface{}{[]int{1, 2, 3, 4, 5, 6, 7, 8}}, 8}, + {"SELECT * FROM foo WHERE x = ? AND y in (?)", + []interface{}{[]byte("foo"), []int{0, 5, 3}}, + 4}, } for _, test := range tests { q, a, err := In(test.q, test.args...) diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE new file mode 100644 index 00000000..14127cd8 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE @@ -0,0 +1,9 @@ +(The MIT License) + +Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md new file mode 100644 index 00000000..949b77e3 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md @@ -0,0 +1,40 @@ +# Windows Terminal Sequences + +This library allow for enabling Windows terminal color support for Go. + +See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details. + +## Usage + +```go +import ( + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func main() { + sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true) +} + +``` + +## Authors + +The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de). + +We thank all the authors who provided code to this library: + +* Felix Kollmann + +## License + +(The MIT License) + +Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod new file mode 100644 index 00000000..716c6131 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod @@ -0,0 +1 @@ +module github.com/konsorten/go-windows-terminal-sequences diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go new file mode 100644 index 00000000..ef18d8f9 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go @@ -0,0 +1,36 @@ +// +build windows + +package sequences + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll") + setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode") +) + +func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { + const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4 + + var mode uint32 + err := syscall.GetConsoleMode(syscall.Stdout, &mode) + if err != nil { + return err + } + + if enable { + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } else { + mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } + + ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode)) + if ret == 0 { + return err + } + + return nil +} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go new file mode 100644 index 00000000..aad41c5c --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go @@ -0,0 +1,48 @@ +// +build windows + +package sequences + +import ( + "fmt" + "os" + "syscall" + "testing" +) + +func TestStdoutSequencesOn(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stdout, true) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + defer EnableVirtualTerminalProcessing(syscall.Stdout, false) + + fmt.Fprintf(os.Stdout, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} + +func TestStdoutSequencesOff(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stdout, false) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + + fmt.Fprintf(os.Stdout, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} + +func TestStderrSequencesOn(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stderr, true) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + defer EnableVirtualTerminalProcessing(syscall.Stderr, false) + + fmt.Fprintf(os.Stderr, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} + +func TestStderrSequencesOff(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stderr, false) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + + fmt.Fprintf(os.Stderr, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} diff --git a/vendor/github.com/lib/pq/.travis.sh b/vendor/github.com/lib/pq/.travis.sh index ead01df7..a297dc45 100755 --- a/vendor/github.com/lib/pq/.travis.sh +++ b/vendor/github.com/lib/pq/.travis.sh @@ -71,12 +71,6 @@ postgresql_uninstall() { } megacheck_install() { - # Megacheck is Go 1.6+, so skip if Go 1.5. - if [[ "$(go version)" =~ "go1.5" ]] - then - echo "megacheck not supported, skipping installation" - return 0 - fi # Lock megacheck version at $MEGACHECK_VERSION to prevent spontaneous # new error messages in old code. go get -d honnef.co/go/tools/... @@ -86,12 +80,6 @@ megacheck_install() { } golint_install() { - # Golint is Go 1.6+, so skip if Go 1.5. - if [[ "$(go version)" =~ "go1.5" ]] - then - echo "golint not supported, skipping installation" - return 0 - fi go get github.com/golang/lint/golint } diff --git a/vendor/github.com/lib/pq/.travis.yml b/vendor/github.com/lib/pq/.travis.yml index 4e34e885..18556e08 100644 --- a/vendor/github.com/lib/pq/.travis.yml +++ b/vendor/github.com/lib/pq/.travis.yml @@ -1,11 +1,9 @@ language: go go: - - 1.5.x - - 1.6.x - - 1.7.x - 1.8.x - 1.9.x + - 1.10.x - master sudo: true @@ -16,7 +14,7 @@ env: - PQGOSSLTESTS=1 - PQSSLCERTTEST_PATH=$PWD/certs - PGHOST=127.0.0.1 - - MEGACHECK_VERSION=2017.2.1 + - MEGACHECK_VERSION=2017.2.2 matrix: - PGVERSION=10 - PGVERSION=9.6 @@ -46,13 +44,7 @@ script: - > goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }' - go vet ./... - # For compatibility with Go 1.5, launch only if megacheck is present. - - > - which megacheck > /dev/null && megacheck -go 1.5 ./... - || echo 'megacheck is not supported, skipping check' - # For compatibility with Go 1.5, launch only if golint is present. - - > - which golint > /dev/null && golint ./... - || echo 'golint is not supported, skipping check' + - megacheck -go 1.8 ./... + - golint ./... - PQTEST_BINARY_PARAMETERS=no go test -race -v ./... - PQTEST_BINARY_PARAMETERS=yes go test -race -v ./... diff --git a/vendor/github.com/lib/pq/README.md b/vendor/github.com/lib/pq/README.md index 781c89ee..d71f3c2c 100644 --- a/vendor/github.com/lib/pq/README.md +++ b/vendor/github.com/lib/pq/README.md @@ -14,18 +14,7 @@ documentation at . ## Tests -`go test` is used for testing. A running PostgreSQL server is -required, with the ability to log in. The default database to connect -to test with is "pqgotest," but it can be overridden using environment -variables. - -Example: - - PGHOST=/run/postgresql go test github.com/lib/pq - -Optionally, a benchmark suite can be run as part of the tests: - - PGHOST=/run/postgresql go test -bench . +`go test` is used for testing. See [TESTS.md](TESTS.md) for more details. ## Features diff --git a/vendor/github.com/lib/pq/TESTS.md b/vendor/github.com/lib/pq/TESTS.md new file mode 100644 index 00000000..f0502111 --- /dev/null +++ b/vendor/github.com/lib/pq/TESTS.md @@ -0,0 +1,33 @@ +# Tests + +## Running Tests + +`go test` is used for testing. A running PostgreSQL +server is required, with the ability to log in. The +database to connect to test with is "pqgotest," on +"localhost" but these can be overridden using [environment +variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html). + +Example: + + PGHOST=/run/postgresql go test + +## Benchmarks + +A benchmark suite can be run as part of the tests: + + go test -bench . + +## Example setup (Docker) + +Run a postgres container: + +``` +docker run --expose 5432:5432 postgres +``` + +Run tests: + +``` +PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test +``` diff --git a/vendor/github.com/lib/pq/bench_test.go b/vendor/github.com/lib/pq/bench_test.go index e71f41d0..33d7a02f 100644 --- a/vendor/github.com/lib/pq/bench_test.go +++ b/vendor/github.com/lib/pq/bench_test.go @@ -5,6 +5,7 @@ package pq import ( "bufio" "bytes" + "context" "database/sql" "database/sql/driver" "io" @@ -156,7 +157,7 @@ func benchMockQuery(b *testing.B, c *conn, query string) { b.Fatal(err) } defer stmt.Close() - rows, err := stmt.Query(nil) + rows, err := stmt.(driver.StmtQueryContext).QueryContext(context.Background(), nil) if err != nil { b.Fatal(err) } @@ -266,7 +267,7 @@ func BenchmarkMockPreparedSelectSeries(b *testing.B) { } func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) { - rows, err := stmt.Query(nil) + rows, err := stmt.(driver.StmtQueryContext).QueryContext(context.Background(), nil) if err != nil { b.Fatal(err) } diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go index fadb88e5..43c8df29 100644 --- a/vendor/github.com/lib/pq/conn.go +++ b/vendor/github.com/lib/pq/conn.go @@ -339,7 +339,20 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { if err != nil { return nil, err } - cn.ssl(o) + + err = cn.ssl(o) + if err != nil { + return nil, err + } + + // cn.startup panics on error. Make sure we don't leak cn.c. + panicking := true + defer func() { + if panicking { + cn.c.Close() + } + }() + cn.buf = bufio.NewReader(cn.c) cn.startup(o) @@ -347,6 +360,7 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { err = cn.c.SetDeadline(time.Time{}) } + panicking = false return cn, err } @@ -1019,30 +1033,35 @@ func (cn *conn) recv1() (t byte, r *readBuf) { return t, r } -func (cn *conn) ssl(o values) { - upgrade := ssl(o) +func (cn *conn) ssl(o values) error { + upgrade, err := ssl(o) + if err != nil { + return err + } + if upgrade == nil { // Nothing to do - return + return nil } w := cn.writeBuf(0) w.int32(80877103) - if err := cn.sendStartupPacket(w); err != nil { - panic(err) + if err = cn.sendStartupPacket(w); err != nil { + return err } b := cn.scratch[:1] - _, err := io.ReadFull(cn.c, b) + _, err = io.ReadFull(cn.c, b) if err != nil { - panic(err) + return err } if b[0] != 'S' { - panic(ErrSSLNotSupported) + return ErrSSLNotSupported } - cn.c = upgrade(cn.c) + cn.c, err = upgrade(cn.c) + return err } // isDriverSetting returns true iff a setting is purely for configuring the diff --git a/vendor/github.com/lib/pq/conn_go18.go b/vendor/github.com/lib/pq/conn_go18.go index ab97a104..a5254f2b 100644 --- a/vendor/github.com/lib/pq/conn_go18.go +++ b/vendor/github.com/lib/pq/conn_go18.go @@ -108,7 +108,10 @@ func (cn *conn) cancel() error { can := conn{ c: c, } - can.ssl(cn.opts) + err = can.ssl(cn.opts) + if err != nil { + return err + } w := can.writeBuf(0) w.int32(80877102) // cancel request code diff --git a/vendor/github.com/lib/pq/conn_test.go b/vendor/github.com/lib/pq/conn_test.go index 030a798c..e654b85b 100644 --- a/vendor/github.com/lib/pq/conn_test.go +++ b/vendor/github.com/lib/pq/conn_test.go @@ -1,6 +1,7 @@ package pq import ( + "context" "database/sql" "database/sql/driver" "fmt" @@ -28,7 +29,7 @@ func forceBinaryParameters() bool { } } -func openTestConnConninfo(conninfo string) (*sql.DB, error) { +func testConninfo(conninfo string) string { defaultTo := func(envvar string, value string) { if os.Getenv(envvar) == "" { os.Setenv(envvar, value) @@ -43,8 +44,11 @@ func openTestConnConninfo(conninfo string) (*sql.DB, error) { !strings.HasPrefix(conninfo, "postgresql://") { conninfo = conninfo + " binary_parameters=yes" } + return conninfo +} - return sql.Open("postgres", conninfo) +func openTestConnConninfo(conninfo string) (*sql.DB, error) { + return sql.Open("postgres", testConninfo(conninfo)) } func openTestConn(t Fatalistic) *sql.DB { @@ -637,6 +641,57 @@ func TestErrorDuringStartup(t *testing.T) { } } +type testConn struct { + closed bool + net.Conn +} + +func (c *testConn) Close() error { + c.closed = true + return c.Conn.Close() +} + +type testDialer struct { + conns []*testConn +} + +func (d *testDialer) Dial(ntw, addr string) (net.Conn, error) { + c, err := net.Dial(ntw, addr) + if err != nil { + return nil, err + } + tc := &testConn{Conn: c} + d.conns = append(d.conns, tc) + return tc, nil +} + +func (d *testDialer) DialTimeout(ntw, addr string, timeout time.Duration) (net.Conn, error) { + c, err := net.DialTimeout(ntw, addr, timeout) + if err != nil { + return nil, err + } + tc := &testConn{Conn: c} + d.conns = append(d.conns, tc) + return tc, nil +} + +func TestErrorDuringStartupClosesConn(t *testing.T) { + // Don't use the normal connection setup, this is intended to + // blow up in the startup packet from a non-existent user. + var d testDialer + c, err := DialOpen(&d, testConninfo("user=thisuserreallydoesntexist")) + if err == nil { + c.Close() + t.Fatal("expected dial error") + } + if len(d.conns) != 1 { + t.Fatalf("got len(d.conns) = %d, want = %d", len(d.conns), 1) + } + if !d.conns[0].closed { + t.Error("connection leaked") + } +} + func TestBadConn(t *testing.T) { var err error @@ -1209,8 +1264,8 @@ func TestParseComplete(t *testing.T) { // Test interface conformance. var ( - _ driver.Execer = (*conn)(nil) - _ driver.Queryer = (*conn)(nil) + _ driver.ExecerContext = (*conn)(nil) + _ driver.QueryerContext = (*conn)(nil) ) func TestNullAfterNonNull(t *testing.T) { @@ -1555,10 +1610,10 @@ func TestRowsResultTag(t *testing.T) { t.Fatal(err) } defer conn.Close() - q := conn.(driver.Queryer) + q := conn.(driver.QueryerContext) for _, test := range tests { - if rows, err := q.Query(test.query, nil); err != nil { + if rows, err := q.QueryContext(context.Background(), test.query, nil); err != nil { t.Fatalf("%s: %s", test.query, err) } else { r := rows.(ResultTag) diff --git a/vendor/github.com/lib/pq/connector.go b/vendor/github.com/lib/pq/connector.go new file mode 100644 index 00000000..9e66eb5d --- /dev/null +++ b/vendor/github.com/lib/pq/connector.go @@ -0,0 +1,43 @@ +// +build go1.10 + +package pq + +import ( + "context" + "database/sql/driver" +) + +// Connector represents a fixed configuration for the pq driver with a given +// name. Connector satisfies the database/sql/driver Connector interface and +// can be used to create any number of DB Conn's via the database/sql OpenDB +// function. +// +// See https://golang.org/pkg/database/sql/driver/#Connector. +// See https://golang.org/pkg/database/sql/#OpenDB. +type connector struct { + name string +} + +// Connect returns a connection to the database using the fixed configuration +// of this Connector. Context is not used. +func (c *connector) Connect(_ context.Context) (driver.Conn, error) { + return (&Driver{}).Open(c.name) +} + +// Driver returnst the underlying driver of this Connector. +func (c *connector) Driver() driver.Driver { + return &Driver{} +} + +var _ driver.Connector = &connector{} + +// NewConnector returns a connector for the pq driver in a fixed configuration +// with the given name. The returned connector can be used to create any number +// of equivalent Conn's. The returned connector is intended to be used with +// database/sql.OpenDB. +// +// See https://golang.org/pkg/database/sql/driver/#Connector. +// See https://golang.org/pkg/database/sql/#OpenDB. +func NewConnector(name string) (driver.Connector, error) { + return &connector{name: name}, nil +} diff --git a/vendor/github.com/lib/pq/connector_example_test.go b/vendor/github.com/lib/pq/connector_example_test.go new file mode 100644 index 00000000..5b66cf4b --- /dev/null +++ b/vendor/github.com/lib/pq/connector_example_test.go @@ -0,0 +1,33 @@ +// +build go1.10 + +package pq_test + +import ( + "database/sql" + "fmt" + + "github.com/lib/pq" +) + +func ExampleNewConnector() { + name := "" + connector, err := pq.NewConnector(name) + if err != nil { + fmt.Println(err) + return + } + db := sql.OpenDB(connector) + if err != nil { + fmt.Println(err) + return + } + defer db.Close() + + // Use the DB + txn, err := db.Begin() + if err != nil { + fmt.Println(err) + return + } + txn.Rollback() +} diff --git a/vendor/github.com/lib/pq/connector_test.go b/vendor/github.com/lib/pq/connector_test.go new file mode 100644 index 00000000..3d2c67b0 --- /dev/null +++ b/vendor/github.com/lib/pq/connector_test.go @@ -0,0 +1,67 @@ +// +build go1.10 + +package pq + +import ( + "context" + "database/sql" + "database/sql/driver" + "testing" +) + +func TestNewConnector_WorksWithOpenDB(t *testing.T) { + name := "" + c, err := NewConnector(name) + if err != nil { + t.Fatal(err) + } + db := sql.OpenDB(c) + defer db.Close() + // database/sql might not call our Open at all unless we do something with + // the connection + txn, err := db.Begin() + if err != nil { + t.Fatal(err) + } + txn.Rollback() +} + +func TestNewConnector_Connect(t *testing.T) { + name := "" + c, err := NewConnector(name) + if err != nil { + t.Fatal(err) + } + db, err := c.Connect(context.Background()) + if err != nil { + t.Fatal(err) + } + defer db.Close() + // database/sql might not call our Open at all unless we do something with + // the connection + txn, err := db.(driver.ConnBeginTx).BeginTx(context.Background(), driver.TxOptions{}) + if err != nil { + t.Fatal(err) + } + txn.Rollback() +} + +func TestNewConnector_Driver(t *testing.T) { + name := "" + c, err := NewConnector(name) + if err != nil { + t.Fatal(err) + } + db, err := c.Driver().Open(name) + if err != nil { + t.Fatal(err) + } + defer db.Close() + // database/sql might not call our Open at all unless we do something with + // the connection + txn, err := db.(driver.ConnBeginTx).BeginTx(context.Background(), driver.TxOptions{}) + if err != nil { + t.Fatal(err) + } + txn.Rollback() +} diff --git a/vendor/github.com/lib/pq/copy_test.go b/vendor/github.com/lib/pq/copy_test.go index c1a3cd7f..a888a894 100644 --- a/vendor/github.com/lib/pq/copy_test.go +++ b/vendor/github.com/lib/pq/copy_test.go @@ -4,6 +4,7 @@ import ( "bytes" "database/sql" "database/sql/driver" + "net" "strings" "testing" ) @@ -400,15 +401,19 @@ func TestCopyRespLoopConnectionError(t *testing.T) { if err == nil { t.Fatalf("expected error") } - pge, ok := err.(*Error) - if !ok { + switch pge := err.(type) { + case *Error: + if pge.Code.Name() != "admin_shutdown" { + t.Fatalf("expected admin_shutdown, got %s", pge.Code.Name()) + } + case *net.OpError: + // ignore + default: if err == driver.ErrBadConn { // likely an EPIPE } else { - t.Fatalf("expected *pq.Error or driver.ErrBadConn, got %+#v", err) + t.Fatalf("unexpected error, got %+#v", err) } - } else if pge.Code.Name() != "admin_shutdown" { - t.Fatalf("expected admin_shutdown, got %s", pge.Code.Name()) } _ = stmt.Close() diff --git a/vendor/github.com/lib/pq/encode_test.go b/vendor/github.com/lib/pq/encode_test.go index 634a05c6..d58798a4 100644 --- a/vendor/github.com/lib/pq/encode_test.go +++ b/vendor/github.com/lib/pq/encode_test.go @@ -4,7 +4,7 @@ import ( "bytes" "database/sql" "fmt" - "strings" + "regexp" "testing" "time" @@ -304,24 +304,27 @@ func TestInfinityTimestamp(t *testing.T) { var err error var resultT time.Time - expectedErrorStrPrefix := `sql: Scan error on column index 0: unsupported` + expectedErrorStrRegexp := regexp.MustCompile( + `^sql: Scan error on column index 0(, name "timestamp(tz)?"|): unsupported`) + type testCases []struct { - Query string - Param string - ExpectedErrStrPrefix string - ExpectedVal interface{} + Query string + Param string + ExpectedErrorStrRegexp *regexp.Regexp + ExpectedVal interface{} } tc := testCases{ - {"SELECT $1::timestamp", "-infinity", expectedErrorStrPrefix, "-infinity"}, - {"SELECT $1::timestamptz", "-infinity", expectedErrorStrPrefix, "-infinity"}, - {"SELECT $1::timestamp", "infinity", expectedErrorStrPrefix, "infinity"}, - {"SELECT $1::timestamptz", "infinity", expectedErrorStrPrefix, "infinity"}, + {"SELECT $1::timestamp", "-infinity", expectedErrorStrRegexp, "-infinity"}, + {"SELECT $1::timestamptz", "-infinity", expectedErrorStrRegexp, "-infinity"}, + {"SELECT $1::timestamp", "infinity", expectedErrorStrRegexp, "infinity"}, + {"SELECT $1::timestamptz", "infinity", expectedErrorStrRegexp, "infinity"}, } // try to assert []byte to time.Time for _, q := range tc { err = db.QueryRow(q.Query, q.Param).Scan(&resultT) - if !strings.HasPrefix(err.Error(), q.ExpectedErrStrPrefix) { - t.Errorf("Scanning -/+infinity, expected error to have prefix %q, got %q", q.ExpectedErrStrPrefix, err) + if !q.ExpectedErrorStrRegexp.MatchString(err.Error()) { + t.Errorf("Scanning -/+infinity, expected error to match regexp %q, got %q", + q.ExpectedErrorStrRegexp, err) } } // yield []byte diff --git a/vendor/github.com/lib/pq/error.go b/vendor/github.com/lib/pq/error.go index b4bb44ce..96aae29c 100644 --- a/vendor/github.com/lib/pq/error.go +++ b/vendor/github.com/lib/pq/error.go @@ -153,6 +153,7 @@ var errorCodeNames = map[ErrorCode]string{ "22004": "null_value_not_allowed", "22002": "null_value_no_indicator_parameter", "22003": "numeric_value_out_of_range", + "2200H": "sequence_generator_limit_exceeded", "22026": "string_data_length_mismatch", "22001": "string_data_right_truncation", "22011": "substring_error", @@ -459,6 +460,11 @@ func errorf(s string, args ...interface{}) { panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) } +// TODO(ainar-g) Rename to errorf after removing panics. +func fmterrorf(s string, args ...interface{}) error { + return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)) +} + func errRecoverNoErrBadConn(err *error) { e := recover() if e == nil { @@ -487,7 +493,8 @@ func (c *conn) errRecover(err *error) { *err = v } case *net.OpError: - *err = driver.ErrBadConn + c.bad = true + *err = v case error: if v == io.EOF || v.(error).Error() == "remote error: handshake failure" { *err = driver.ErrBadConn diff --git a/vendor/github.com/lib/pq/go.mod b/vendor/github.com/lib/pq/go.mod new file mode 100644 index 00000000..edf0b343 --- /dev/null +++ b/vendor/github.com/lib/pq/go.mod @@ -0,0 +1 @@ +module github.com/lib/pq diff --git a/vendor/github.com/lib/pq/go18_test.go b/vendor/github.com/lib/pq/go18_test.go index 4bf6391e..1a88a5b4 100644 --- a/vendor/github.com/lib/pq/go18_test.go +++ b/vendor/github.com/lib/pq/go18_test.go @@ -228,7 +228,9 @@ func TestContextCancelBegin(t *testing.T) { cancel() if err != nil { t.Fatal(err) - } else if err := tx.Rollback(); err != nil && err != sql.ErrTxDone { + } else if err := tx.Rollback(); err != nil && + err.Error() != "pq: canceling statement due to user request" && + err != sql.ErrTxDone { t.Fatal(err) } }() diff --git a/vendor/github.com/lib/pq/notify.go b/vendor/github.com/lib/pq/notify.go index 412c6ac1..850bb904 100644 --- a/vendor/github.com/lib/pq/notify.go +++ b/vendor/github.com/lib/pq/notify.go @@ -637,7 +637,7 @@ func (l *Listener) disconnectCleanup() error { // after the connection has been established. func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error { doneChan := make(chan error) - go func() { + go func(notificationChan <-chan *Notification) { for channel := range l.channels { // If we got a response, return that error to our caller as it's // going to be more descriptive than cn.Err(). @@ -658,7 +658,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio } } doneChan <- nil - }() + }(notificationChan) // Ignore notifications while synchronization is going on to avoid // deadlocks. We have to send a nil notification over Notify anyway as @@ -725,6 +725,9 @@ func (l *Listener) Close() error { } l.isClosed = true + // Unblock calls to Listen() + l.reconnectCond.Broadcast() + return nil } @@ -784,7 +787,7 @@ func (l *Listener) listenerConnLoop() { } l.emitEvent(ListenerEventDisconnected, err) - time.Sleep(nextReconnect.Sub(time.Now())) + time.Sleep(time.Until(nextReconnect)) } } diff --git a/vendor/github.com/lib/pq/ssl.go b/vendor/github.com/lib/pq/ssl.go index 7deb3043..e1a326a0 100644 --- a/vendor/github.com/lib/pq/ssl.go +++ b/vendor/github.com/lib/pq/ssl.go @@ -12,7 +12,7 @@ import ( // ssl generates a function to upgrade a net.Conn based on the "sslmode" and // related settings. The function is nil when no upgrade should take place. -func ssl(o values) func(net.Conn) net.Conn { +func ssl(o values) (func(net.Conn) (net.Conn, error), error) { verifyCaOnly := false tlsConf := tls.Config{} switch mode := o["sslmode"]; mode { @@ -45,29 +45,38 @@ func ssl(o values) func(net.Conn) net.Conn { case "verify-full": tlsConf.ServerName = o["host"] case "disable": - return nil + return nil, nil default: - errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) + return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) } - sslClientCertificates(&tlsConf, o) - sslCertificateAuthority(&tlsConf, o) + err := sslClientCertificates(&tlsConf, o) + if err != nil { + return nil, err + } + err = sslCertificateAuthority(&tlsConf, o) + if err != nil { + return nil, err + } sslRenegotiation(&tlsConf) - return func(conn net.Conn) net.Conn { + return func(conn net.Conn) (net.Conn, error) { client := tls.Client(conn, &tlsConf) if verifyCaOnly { - sslVerifyCertificateAuthority(client, &tlsConf) + err := sslVerifyCertificateAuthority(client, &tlsConf) + if err != nil { + return nil, err + } } - return client - } + return client, nil + }, nil } // sslClientCertificates adds the certificate specified in the "sslcert" and // "sslkey" settings, or if they aren't set, from the .postgresql directory // in the user's home directory. The configured files must exist and have // the correct permissions. -func sslClientCertificates(tlsConf *tls.Config, o values) { +func sslClientCertificates(tlsConf *tls.Config, o values) error { // user.Current() might fail when cross-compiling. We have to ignore the // error and continue without home directory defaults, since we wouldn't // know from where to load them. @@ -82,13 +91,13 @@ func sslClientCertificates(tlsConf *tls.Config, o values) { } // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045 if len(sslcert) == 0 { - return + return nil } // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054 if _, err := os.Stat(sslcert); os.IsNotExist(err) { - return + return nil } else if err != nil { - panic(err) + return err } // In libpq, the ssl key is only loaded if the setting is not blank. @@ -101,19 +110,21 @@ func sslClientCertificates(tlsConf *tls.Config, o values) { if len(sslkey) > 0 { if err := sslKeyPermissions(sslkey); err != nil { - panic(err) + return err } } cert, err := tls.LoadX509KeyPair(sslcert, sslkey) if err != nil { - panic(err) + return err } + tlsConf.Certificates = []tls.Certificate{cert} + return nil } // sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting. -func sslCertificateAuthority(tlsConf *tls.Config, o values) { +func sslCertificateAuthority(tlsConf *tls.Config, o values) error { // In libpq, the root certificate is only loaded if the setting is not blank. // // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951 @@ -122,22 +133,24 @@ func sslCertificateAuthority(tlsConf *tls.Config, o values) { cert, err := ioutil.ReadFile(sslrootcert) if err != nil { - panic(err) + return err } if !tlsConf.RootCAs.AppendCertsFromPEM(cert) { - errorf("couldn't parse pem in sslrootcert") + return fmterrorf("couldn't parse pem in sslrootcert") } } + + return nil } // sslVerifyCertificateAuthority carries out a TLS handshake to the server and // verifies the presented certificate against the CA, i.e. the one specified in // sslrootcert or the system CA if sslrootcert was not specified. -func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) { +func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error { err := client.Handshake() if err != nil { - panic(err) + return err } certs := client.ConnectionState().PeerCertificates opts := x509.VerifyOptions{ @@ -152,7 +165,5 @@ func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) { opts.Intermediates.AddCert(cert) } _, err = certs[0].Verify(opts) - if err != nil { - panic(err) - } + return err } diff --git a/vendor/github.com/magiconair/properties/.travis.yml b/vendor/github.com/magiconair/properties/.travis.yml index ab980390..3e7c3d2c 100644 --- a/vendor/github.com/magiconair/properties/.travis.yml +++ b/vendor/github.com/magiconair/properties/.travis.yml @@ -6,4 +6,5 @@ go: - 1.7.x - 1.8.x - 1.9.x + - "1.10.x" - tip diff --git a/vendor/github.com/magiconair/properties/CHANGELOG.md b/vendor/github.com/magiconair/properties/CHANGELOG.md index 7abd3926..f83adc20 100644 --- a/vendor/github.com/magiconair/properties/CHANGELOG.md +++ b/vendor/github.com/magiconair/properties/CHANGELOG.md @@ -1,63 +1,92 @@ ## Changelog -### [1.7.4](https://github.com/magiconair/properties/tags/v1.7.4) - 31 Oct 2017 +### [1.8](https://github.com/magiconair/properties/tree/v1.8) - 15 May 2018 + + * [PR #26](https://github.com/magiconair/properties/pull/26): Disable expansion during loading + + This adds the option to disable property expansion during loading. + + Thanks to [@kmala](https://github.com/kmala) for the patch. + +### [1.7.6](https://github.com/magiconair/properties/tree/v1.7.6) - 14 Feb 2018 + + * [PR #29](https://github.com/magiconair/properties/pull/29): Reworked expansion logic to handle more complex cases. + + See PR for an example. + + Thanks to [@yobert](https://github.com/yobert) for the fix. + +### [1.7.5](https://github.com/magiconair/properties/tree/v1.7.5) - 13 Feb 2018 + + * [PR #28](https://github.com/magiconair/properties/pull/28): Support duplicate expansions in the same value + + Values which expand the same key multiple times (e.g. `key=${a} ${a}`) will no longer fail + with a `circular reference error`. + + Thanks to [@yobert](https://github.com/yobert) for the fix. + +### [1.7.4](https://github.com/magiconair/properties/tree/v1.7.4) - 31 Oct 2017 * [Issue #23](https://github.com/magiconair/properties/issues/23): Ignore blank lines with whitespaces - * [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled - Thanks to @mgurov for the fix. -### [1.7.3](https://github.com/magiconair/properties/tags/v1.7.3) - 10 Jul 2017 + * [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled + + Thanks to [@mgurov](https://github.com/mgurov) for the fix. + +### [1.7.3](https://github.com/magiconair/properties/tree/v1.7.3) - 10 Jul 2017 * [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically * [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map -### [1.7.2](https://github.com/magiconair/properties/tags/v1.7.2) - 20 Mar 2017 +### [1.7.2](https://github.com/magiconair/properties/tree/v1.7.2) - 20 Mar 2017 * [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency * [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc) -### [1.7.1](https://github.com/magiconair/properties/tags/v1.7.1) - 13 Jan 2017 +### [1.7.1](https://github.com/magiconair/properties/tree/v1.7.1) - 13 Jan 2017 + * [Issue #14](https://github.com/magiconair/properties/issues/14): Decouple TestLoadExpandedFile from `$USER` + * [PR #12](https://github.com/magiconair/properties/pull/12): Load from files and URLs * [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy * [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function -### [1.7.0](https://github.com/magiconair/properties/tags/v1.7.0) - 20 Mar 2016 +### [1.7.0](https://github.com/magiconair/properties/tree/v1.7.0) - 20 Mar 2016 * [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL. * [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string. * [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe) -### [1.6.0](https://github.com/magiconair/properties/tags/v1.6.0) - 11 Dec 2015 +### [1.6.0](https://github.com/magiconair/properties/tree/v1.6.0) - 11 Dec 2015 * Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags. -### [1.5.6](https://github.com/magiconair/properties/tags/v1.5.6) - 18 Oct 2015 +### [1.5.6](https://github.com/magiconair/properties/tree/v1.5.6) - 18 Oct 2015 * Vendored in gopkg.in/check.v1 -### [1.5.5](https://github.com/magiconair/properties/tags/v1.5.5) - 31 Jul 2015 +### [1.5.5](https://github.com/magiconair/properties/tree/v1.5.5) - 31 Jul 2015 * [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs) -### [1.5.4](https://github.com/magiconair/properties/tags/v1.5.4) - 23 Jun 2015 +### [1.5.4](https://github.com/magiconair/properties/tree/v1.5.4) - 23 Jun 2015 * [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references. -### [1.5.3](https://github.com/magiconair/properties/tags/v1.5.3) - 02 Jun 2015 +### [1.5.3](https://github.com/magiconair/properties/tree/v1.5.3) - 02 Jun 2015 * [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) -### [1.5.2](https://github.com/magiconair/properties/tags/v1.5.2) - 10 Apr 2015 +### [1.5.2](https://github.com/magiconair/properties/tree/v1.5.2) - 10 Apr 2015 * [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty * Add clickable links to README -### [1.5.1](https://github.com/magiconair/properties/tags/v1.5.1) - 08 Dec 2014 +### [1.5.1](https://github.com/magiconair/properties/tree/v1.5.1) - 08 Dec 2014 * Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with [time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration). -### [1.5.0](https://github.com/magiconair/properties/tags/v1.5.0) - 18 Nov 2014 +### [1.5.0](https://github.com/magiconair/properties/tree/v1.5.0) - 18 Nov 2014 * Added support for single and multi-line comments (reading, writing and updating) * The order of keys is now preserved @@ -65,31 +94,31 @@ * Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method * Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1) -### [1.4.2](https://github.com/magiconair/properties/tags/v1.4.2) - 15 Nov 2014 +### [1.4.2](https://github.com/magiconair/properties/tree/v1.4.2) - 15 Nov 2014 * [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one -### [1.4.1](https://github.com/magiconair/properties/tags/v1.4.1) - 13 Nov 2014 +### [1.4.1](https://github.com/magiconair/properties/tree/v1.4.1) - 13 Nov 2014 * [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string -### [1.4.0](https://github.com/magiconair/properties/tags/v1.4.0) - 23 Sep 2014 +### [1.4.0](https://github.com/magiconair/properties/tree/v1.4.0) - 23 Sep 2014 * Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys * Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties -### [1.3.0](https://github.com/magiconair/properties/tags/v1.3.0) - 18 Mar 2014 +### [1.3.0](https://github.com/magiconair/properties/tree/v1.3.0) - 18 Mar 2014 * Added support for time.Duration -* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tags/vior configurable (log.Fatal, panic) - custom) +* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tree/vior configurable (log.Fatal, panic) - custom) * Changed default of MustXXX() failure from panic to log.Fatal -### [1.2.0](https://github.com/magiconair/properties/tags/v1.2.0) - 05 Mar 2014 +### [1.2.0](https://github.com/magiconair/properties/tree/v1.2.0) - 05 Mar 2014 * Added MustGet... functions * Added support for int and uint with range checks on 32 bit platforms -### [1.1.0](https://github.com/magiconair/properties/tags/v1.1.0) - 20 Jan 2014 +### [1.1.0](https://github.com/magiconair/properties/tree/v1.1.0) - 20 Jan 2014 * Renamed from goproperties to properties * Added support for expansion of environment vars in @@ -97,6 +126,6 @@ * Fixed bug where value expressions were not at the start of the string -### [1.0.0](https://github.com/magiconair/properties/tags/v1.0.0) - 7 Jan 2014 +### [1.0.0](https://github.com/magiconair/properties/tree/v1.0.0) - 7 Jan 2014 * Initial release diff --git a/vendor/github.com/magiconair/properties/LICENSE b/vendor/github.com/magiconair/properties/LICENSE index 7eab43b6..b387087c 100644 --- a/vendor/github.com/magiconair/properties/LICENSE +++ b/vendor/github.com/magiconair/properties/LICENSE @@ -1,6 +1,6 @@ goproperties - properties file decoder for Go -Copyright (c) 2013-2014 - Frank Schroeder +Copyright (c) 2013-2018 - Frank Schroeder All rights reserved. diff --git a/vendor/github.com/magiconair/properties/README.md b/vendor/github.com/magiconair/properties/README.md index 258fbb2b..2c05f290 100644 --- a/vendor/github.com/magiconair/properties/README.md +++ b/vendor/github.com/magiconair/properties/README.md @@ -1,7 +1,12 @@ -Overview [![Build Status](https://travis-ci.org/magiconair/properties.svg?branch=master)](https://travis-ci.org/magiconair/properties) -======== +[![](https://img.shields.io/github/tag/magiconair/properties.svg?style=flat-square&label=release)](https://github.com/magiconair/properties/releases) +[![Travis CI Status](https://img.shields.io/travis/magiconair/properties.svg?branch=master&style=flat-square&label=travis)](https://travis-ci.org/magiconair/properties) +[![Codeship CI Status](https://img.shields.io/codeship/16aaf660-f615-0135-b8f0-7e33b70920c0/master.svg?label=codeship&style=flat-square)](https://app.codeship.com/projects/274177") +[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg?style=flat-square)](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE) +[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties) -#### Current version: 1.7.4 +# Overview + +#### Please run `git pull --tags` to update the tags. See [below](#updated-git-tags) why. properties is a Go library for reading and writing properties files. @@ -27,8 +32,7 @@ details. Read the full documentation on [GoDoc](https://godoc.org/github.com/magiconair/properties) [![GoDoc](https://godoc.org/github.com/magiconair/properties?status.png)](https://godoc.org/github.com/magiconair/properties) -Getting Started ---------------- +## Getting Started ```go import ( @@ -83,18 +87,43 @@ func main() { ``` -Installation and Upgrade ------------------------- +## Installation and Upgrade ``` $ go get -u github.com/magiconair/properties ``` -License -------- +## License 2 clause BSD license. See [LICENSE](https://github.com/magiconair/properties/blob/master/LICENSE) file for details. -ToDo ----- +## ToDo + * Dump contents with passwords and secrets obscured + +## Updated Git tags + +#### 13 Feb 2018 + +I realized that all of the git tags I had pushed before v1.7.5 were lightweight tags +and I've only recently learned that this doesn't play well with `git describe` 😞 + +I have replaced all lightweight tags with signed tags using this script which should +retain the commit date, name and email address. Please run `git pull --tags` to update them. + +Worst case you have to reclone the repo. + +```shell +#!/bin/bash +tag=$1 +echo "Updating $tag" +date=$(git show ${tag}^0 --format=%aD | head -1) +email=$(git show ${tag}^0 --format=%aE | head -1) +name=$(git show ${tag}^0 --format=%aN | head -1) +GIT_COMMITTER_DATE="$date" GIT_COMMITTER_NAME="$name" GIT_COMMITTER_EMAIL="$email" git tag -s -f ${tag} ${tag}^0 -m ${tag} +``` + +I apologize for the inconvenience. + +Frank + diff --git a/vendor/github.com/magiconair/properties/assert/assert.go b/vendor/github.com/magiconair/properties/assert/assert.go index cb1097ba..d0f27046 100644 --- a/vendor/github.com/magiconair/properties/assert/assert.go +++ b/vendor/github.com/magiconair/properties/assert/assert.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/assert/assert_test.go b/vendor/github.com/magiconair/properties/assert/assert_test.go index dcef73df..ddb6bf04 100644 --- a/vendor/github.com/magiconair/properties/assert/assert_test.go +++ b/vendor/github.com/magiconair/properties/assert/assert_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/decode.go b/vendor/github.com/magiconair/properties/decode.go index 0a961bb0..3ebf8049 100644 --- a/vendor/github.com/magiconair/properties/decode.go +++ b/vendor/github.com/magiconair/properties/decode.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/decode_test.go b/vendor/github.com/magiconair/properties/decode_test.go index c8293148..9431b832 100644 --- a/vendor/github.com/magiconair/properties/decode_test.go +++ b/vendor/github.com/magiconair/properties/decode_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/doc.go b/vendor/github.com/magiconair/properties/doc.go index 36c83680..f8822da2 100644 --- a/vendor/github.com/magiconair/properties/doc.go +++ b/vendor/github.com/magiconair/properties/doc.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -73,7 +73,7 @@ // # refers to the users' home dir // home = ${HOME} // -// # local key takes precendence over env var: u = foo +// # local key takes precedence over env var: u = foo // USER = foo // u = ${USER} // @@ -102,7 +102,7 @@ // v = p.GetString("key", "def") // v = p.GetDuration("key", 999) // -// As an alterantive properties may be applied with the standard +// As an alternative properties may be applied with the standard // library's flag implementation at any time. // // # Standard configuration diff --git a/vendor/github.com/magiconair/properties/example_test.go b/vendor/github.com/magiconair/properties/example_test.go index 6f21dfbd..4d0bbea7 100644 --- a/vendor/github.com/magiconair/properties/example_test.go +++ b/vendor/github.com/magiconair/properties/example_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/integrate.go b/vendor/github.com/magiconair/properties/integrate.go index 0d775e03..74d38dc6 100644 --- a/vendor/github.com/magiconair/properties/integrate.go +++ b/vendor/github.com/magiconair/properties/integrate.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/integrate_test.go b/vendor/github.com/magiconair/properties/integrate_test.go index cbee181f..5ed74e24 100644 --- a/vendor/github.com/magiconair/properties/integrate_test.go +++ b/vendor/github.com/magiconair/properties/integrate_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -52,7 +52,7 @@ func TestFlagOverride(t *testing.T) { t.Errorf("Got customized b=%d, want %d", *gotB, want) } if want := 4; *gotC != want { - t.Errorf("Got overriden c=%d, want %d", *gotC, want) + t.Errorf("Got overridden c=%d, want %d", *gotC, want) } } diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go index c63fcc60..367166d5 100644 --- a/vendor/github.com/magiconair/properties/lex.go +++ b/vendor/github.com/magiconair/properties/lex.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // diff --git a/vendor/github.com/magiconair/properties/load.go b/vendor/github.com/magiconair/properties/load.go index 278cc2ea..c8e1b580 100644 --- a/vendor/github.com/magiconair/properties/load.go +++ b/vendor/github.com/magiconair/properties/load.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -16,21 +16,157 @@ import ( type Encoding uint const ( + // utf8Default is a private placeholder for the zero value of Encoding to + // ensure that it has the correct meaning. UTF8 is the default encoding but + // was assigned a non-zero value which cannot be changed without breaking + // existing code. Clients should continue to use the public constants. + utf8Default Encoding = iota + // UTF8 interprets the input data as UTF-8. - UTF8 Encoding = 1 << iota + UTF8 // ISO_8859_1 interprets the input data as ISO-8859-1. ISO_8859_1 ) +type Loader struct { + // Encoding determines how the data from files and byte buffers + // is interpreted. For URLs the Content-Type header is used + // to determine the encoding of the data. + Encoding Encoding + + // DisableExpansion configures the property expansion of the + // returned property object. When set to true, the property values + // will not be expanded and the Property object will not be checked + // for invalid expansion expressions. + DisableExpansion bool + + // IgnoreMissing configures whether missing files or URLs which return + // 404 are reported as errors. When set to true, missing files and 404 + // status codes are not reported as errors. + IgnoreMissing bool +} + +// Load reads a buffer into a Properties struct. +func (l *Loader) LoadBytes(buf []byte) (*Properties, error) { + return l.loadBytes(buf, l.Encoding) +} + +// LoadAll reads the content of multiple URLs or files in the given order into +// a Properties struct. If IgnoreMissing is true then a 404 status code or +// missing file will not be reported as error. Encoding sets the encoding for +// files. For the URLs see LoadURL for the Content-Type header and the +// encoding. +func (l *Loader) LoadAll(names []string) (*Properties, error) { + all := NewProperties() + for _, name := range names { + n, err := expandName(name) + if err != nil { + return nil, err + } + + var p *Properties + switch { + case strings.HasPrefix(n, "http://"): + p, err = l.LoadURL(n) + case strings.HasPrefix(n, "https://"): + p, err = l.LoadURL(n) + default: + p, err = l.LoadFile(n) + } + if err != nil { + return nil, err + } + all.Merge(p) + } + + all.DisableExpansion = l.DisableExpansion + if all.DisableExpansion { + return all, nil + } + return all, all.check() +} + +// LoadFile reads a file into a Properties struct. +// If IgnoreMissing is true then a missing file will not be +// reported as error. +func (l *Loader) LoadFile(filename string) (*Properties, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + if l.IgnoreMissing && os.IsNotExist(err) { + LogPrintf("properties: %s not found. skipping", filename) + return NewProperties(), nil + } + return nil, err + } + return l.loadBytes(data, l.Encoding) +} + +// LoadURL reads the content of the URL into a Properties struct. +// +// The encoding is determined via the Content-Type header which +// should be set to 'text/plain'. If the 'charset' parameter is +// missing, 'iso-8859-1' or 'latin1' the encoding is set to +// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the +// encoding is set to UTF-8. A missing content type header is +// interpreted as 'text/plain; charset=utf-8'. +func (l *Loader) LoadURL(url string) (*Properties, error) { + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) + } + + if resp.StatusCode == 404 && l.IgnoreMissing { + LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode) + return NewProperties(), nil + } + + if resp.StatusCode != 200 { + return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) + } + defer resp.Body.Close() + + ct := resp.Header.Get("Content-Type") + var enc Encoding + switch strings.ToLower(ct) { + case "text/plain", "text/plain; charset=iso-8859-1", "text/plain; charset=latin1": + enc = ISO_8859_1 + case "", "text/plain; charset=utf-8": + enc = UTF8 + default: + return nil, fmt.Errorf("properties: invalid content type %s", ct) + } + + return l.loadBytes(body, enc) +} + +func (l *Loader) loadBytes(buf []byte, enc Encoding) (*Properties, error) { + p, err := parse(convert(buf, enc)) + if err != nil { + return nil, err + } + p.DisableExpansion = l.DisableExpansion + if p.DisableExpansion { + return p, nil + } + return p, p.check() +} + // Load reads a buffer into a Properties struct. func Load(buf []byte, enc Encoding) (*Properties, error) { - return loadBuf(buf, enc) + l := &Loader{Encoding: enc} + return l.LoadBytes(buf) } // LoadString reads an UTF8 string into a properties struct. func LoadString(s string) (*Properties, error) { - return loadBuf([]byte(s), UTF8) + l := &Loader{Encoding: UTF8} + return l.LoadBytes([]byte(s)) } // LoadMap creates a new Properties struct from a string map. @@ -44,34 +180,32 @@ func LoadMap(m map[string]string) *Properties { // LoadFile reads a file into a Properties struct. func LoadFile(filename string, enc Encoding) (*Properties, error) { - return loadAll([]string{filename}, enc, false) + l := &Loader{Encoding: enc} + return l.LoadAll([]string{filename}) } // LoadFiles reads multiple files in the given order into // a Properties struct. If 'ignoreMissing' is true then // non-existent files will not be reported as error. func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - return loadAll(filenames, enc, ignoreMissing) + l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing} + return l.LoadAll(filenames) } // LoadURL reads the content of the URL into a Properties struct. -// -// The encoding is determined via the Content-Type header which -// should be set to 'text/plain'. If the 'charset' parameter is -// missing, 'iso-8859-1' or 'latin1' the encoding is set to -// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the -// encoding is set to UTF-8. A missing content type header is -// interpreted as 'text/plain; charset=utf-8'. +// See Loader#LoadURL for details. func LoadURL(url string) (*Properties, error) { - return loadAll([]string{url}, UTF8, false) + l := &Loader{Encoding: UTF8} + return l.LoadAll([]string{url}) } // LoadURLs reads the content of multiple URLs in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code will -// not be reported as error. See LoadURL for the Content-Type header +// Properties struct. If IgnoreMissing is true then a 404 status code will +// not be reported as error. See Loader#LoadURL for the Content-Type header // and the encoding. func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) { - return loadAll(urls, UTF8, ignoreMissing) + l := &Loader{Encoding: UTF8, IgnoreMissing: ignoreMissing} + return l.LoadAll(urls) } // LoadAll reads the content of multiple URLs or files in the given order into a @@ -79,7 +213,8 @@ func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) { // not be reported as error. Encoding sets the encoding for files. For the URLs please see // LoadURL for the Content-Type header and the encoding. func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - return loadAll(names, enc, ignoreMissing) + l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing} + return l.LoadAll(names) } // MustLoadString reads an UTF8 string into a Properties struct and @@ -122,90 +257,6 @@ func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties { return must(LoadAll(names, enc, ignoreMissing)) } -func loadBuf(buf []byte, enc Encoding) (*Properties, error) { - p, err := parse(convert(buf, enc)) - if err != nil { - return nil, err - } - return p, p.check() -} - -func loadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - result := NewProperties() - for _, name := range names { - n, err := expandName(name) - if err != nil { - return nil, err - } - var p *Properties - if strings.HasPrefix(n, "http://") || strings.HasPrefix(n, "https://") { - p, err = loadURL(n, ignoreMissing) - } else { - p, err = loadFile(n, enc, ignoreMissing) - } - if err != nil { - return nil, err - } - result.Merge(p) - - } - return result, result.check() -} - -func loadFile(filename string, enc Encoding, ignoreMissing bool) (*Properties, error) { - data, err := ioutil.ReadFile(filename) - if err != nil { - if ignoreMissing && os.IsNotExist(err) { - LogPrintf("properties: %s not found. skipping", filename) - return NewProperties(), nil - } - return nil, err - } - p, err := parse(convert(data, enc)) - if err != nil { - return nil, err - } - return p, nil -} - -func loadURL(url string, ignoreMissing bool) (*Properties, error) { - resp, err := http.Get(url) - if err != nil { - return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) - } - if resp.StatusCode == 404 && ignoreMissing { - LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode) - return NewProperties(), nil - } - if resp.StatusCode != 200 { - return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode) - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - if err = resp.Body.Close(); err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - - ct := resp.Header.Get("Content-Type") - var enc Encoding - switch strings.ToLower(ct) { - case "text/plain", "text/plain; charset=iso-8859-1", "text/plain; charset=latin1": - enc = ISO_8859_1 - case "", "text/plain; charset=utf-8": - enc = UTF8 - default: - return nil, fmt.Errorf("properties: invalid content type %s", ct) - } - - p, err := parse(convert(body, enc)) - if err != nil { - return nil, err - } - return p, nil -} - func must(p *Properties, err error) *Properties { if err != nil { ErrorHandler(err) @@ -218,7 +269,7 @@ func must(p *Properties, err error) *Properties { // with an empty string. Malformed expressions like "${ENV_VAR" will // be reported as error. func expandName(name string) (string, error) { - return expand(name, make(map[string]bool), "${", "}", make(map[string]string)) + return expand(name, []string{}, "${", "}", make(map[string]string)) } // Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string. @@ -226,7 +277,7 @@ func expandName(name string) (string, error) { // first 256 unicode code points cover ISO-8859-1. func convert(buf []byte, enc Encoding) string { switch enc { - case UTF8: + case utf8Default, UTF8: return string(buf) case ISO_8859_1: runes := make([]rune, len(buf)) diff --git a/vendor/github.com/magiconair/properties/load_test.go b/vendor/github.com/magiconair/properties/load_test.go index d8770c8a..db28b993 100644 --- a/vendor/github.com/magiconair/properties/load_test.go +++ b/vendor/github.com/magiconair/properties/load_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -16,6 +16,18 @@ import ( "github.com/magiconair/properties/assert" ) +func TestEncoding(t *testing.T) { + if got, want := utf8Default, Encoding(0); got != want { + t.Fatalf("got encoding %d want %d", got, want) + } + if got, want := UTF8, Encoding(1); got != want { + t.Fatalf("got encoding %d want %d", got, want) + } + if got, want := ISO_8859_1, Encoding(2); got != want { + t.Fatalf("got encoding %d want %d", got, want) + } +} + func TestLoadFailsWithNotExistingFile(t *testing.T) { _, err := LoadFile("doesnotexist.properties", ISO_8859_1) assert.Equal(t, err != nil, true, "") diff --git a/vendor/github.com/magiconair/properties/parser.go b/vendor/github.com/magiconair/properties/parser.go index 90f555cb..cdc4a803 100644 --- a/vendor/github.com/magiconair/properties/parser.go +++ b/vendor/github.com/magiconair/properties/parser.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go index 85bb1861..cb3d1a33 100644 --- a/vendor/github.com/magiconair/properties/properties.go +++ b/vendor/github.com/magiconair/properties/properties.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -19,6 +19,8 @@ import ( "unicode/utf8" ) +const maxExpansionDepth = 64 + // ErrorHandlerFunc defines the type of function which handles failures // of the MustXXX() functions. An error handler function must exit // the application after handling the error. @@ -81,6 +83,17 @@ func NewProperties() *Properties { } } +// Load reads a buffer into the given Properties struct. +func (p *Properties) Load(buf []byte, enc Encoding) error { + l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion} + newProperties, err := l.LoadBytes(buf) + if err != nil { + return err + } + p.Merge(newProperties) + return nil +} + // Get returns the expanded value for the given key if exists. // Otherwise, ok is false. func (p *Properties) Get(key string) (value string, ok bool) { @@ -92,7 +105,7 @@ func (p *Properties) Get(key string) (value string, ok bool) { return "", false } - expanded, err := p.expand(v) + expanded, err := p.expand(key, v) // we guarantee that the expanded value is free of // circular references and malformed expressions @@ -525,7 +538,7 @@ func (p *Properties) Set(key, value string) (prev string, ok bool, err error) { p.m[key] = value // now check for a circular reference - _, err = p.expand(value) + _, err = p.expand(key, value) if err != nil { // revert to the previous state @@ -696,56 +709,65 @@ outer: // check expands all values and returns an error if a circular reference or // a malformed expression was found. func (p *Properties) check() error { - for _, value := range p.m { - if _, err := p.expand(value); err != nil { + for key, value := range p.m { + if _, err := p.expand(key, value); err != nil { return err } } return nil } -func (p *Properties) expand(input string) (string, error) { +func (p *Properties) expand(key, input string) (string, error) { // no pre/postfix -> nothing to expand if p.Prefix == "" && p.Postfix == "" { return input, nil } - return expand(input, make(map[string]bool), p.Prefix, p.Postfix, p.m) + return expand(input, []string{key}, p.Prefix, p.Postfix, p.m) } // expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values. // The function keeps track of the keys that were already expanded and stops if it // detects a circular reference or a malformed expression of the form '(prefix)key'. -func expand(s string, keys map[string]bool, prefix, postfix string, values map[string]string) (string, error) { - start := strings.Index(s, prefix) - if start == -1 { - return s, nil +func expand(s string, keys []string, prefix, postfix string, values map[string]string) (string, error) { + if len(keys) > maxExpansionDepth { + return "", fmt.Errorf("expansion too deep") } - keyStart := start + len(prefix) - keyLen := strings.Index(s[keyStart:], postfix) - if keyLen == -1 { - return "", fmt.Errorf("malformed expression") + for { + start := strings.Index(s, prefix) + if start == -1 { + return s, nil + } + + keyStart := start + len(prefix) + keyLen := strings.Index(s[keyStart:], postfix) + if keyLen == -1 { + return "", fmt.Errorf("malformed expression") + } + + end := keyStart + keyLen + len(postfix) - 1 + key := s[keyStart : keyStart+keyLen] + + // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key) + + for _, k := range keys { + if key == k { + return "", fmt.Errorf("circular reference") + } + } + + val, ok := values[key] + if !ok { + val = os.Getenv(key) + } + new_val, err := expand(val, append(keys, key), prefix, postfix, values) + if err != nil { + return "", err + } + s = s[:start] + new_val + s[end+1:] } - - end := keyStart + keyLen + len(postfix) - 1 - key := s[keyStart : keyStart+keyLen] - - // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key) - - if _, ok := keys[key]; ok { - return "", fmt.Errorf("circular reference") - } - - val, ok := values[key] - if !ok { - val = os.Getenv(key) - } - - // remember that we've seen the key - keys[key] = true - - return expand(s[:start]+val+s[end+1:], keys, prefix, postfix, values) + return s, nil } // encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters. diff --git a/vendor/github.com/magiconair/properties/properties_test.go b/vendor/github.com/magiconair/properties/properties_test.go index a22f48df..5db64c3e 100644 --- a/vendor/github.com/magiconair/properties/properties_test.go +++ b/vendor/github.com/magiconair/properties/properties_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -90,6 +90,10 @@ var complexTests = [][]string{ {"key=value\nkey2=${key}bb", "key", "value", "key2", "valuebb"}, {"key=value\nkey2=aa${key}bb", "key", "value", "key2", "aavaluebb"}, {"key=value\nkey2=${key}\nkey3=${key2}", "key", "value", "key2", "value", "key3", "value"}, + {"key=value\nkey2=${key}${key}", "key", "value", "key2", "valuevalue"}, + {"key=value\nkey2=${key}${key}${key}${key}", "key", "value", "key2", "valuevaluevaluevalue"}, + {"key=value\nkey2=${key}${key3}\nkey3=${key}", "key", "value", "key2", "valuevalue", "key3", "value"}, + {"key=value\nkey2=${key3}${key}${key4}\nkey3=${key}\nkey4=${key}", "key", "value", "key2", "valuevaluevalue", "key3", "value", "key4", "value"}, {"key=${USER}", "key", os.Getenv("USER")}, {"key=${USER}\nUSER=value", "key", "value", "USER", "value"}, } @@ -446,6 +450,30 @@ func TestErrors(t *testing.T) { } } +func TestVeryDeep(t *testing.T) { + input := "key0=value\n" + prefix := "${" + postfix := "}" + i := 0 + for i = 0; i < maxExpansionDepth-1; i++ { + input += fmt.Sprintf("key%d=%skey%d%s\n", i+1, prefix, i, postfix) + } + + p, err := Load([]byte(input), ISO_8859_1) + assert.Equal(t, err, nil) + p.Prefix = prefix + p.Postfix = postfix + + assert.Equal(t, p.MustGet(fmt.Sprintf("key%d", i)), "value") + + // Nudge input over the edge + input += fmt.Sprintf("key%d=%skey%d%s\n", i+1, prefix, i, postfix) + + _, err = Load([]byte(input), ISO_8859_1) + assert.Equal(t, err != nil, true, "want error") + assert.Equal(t, strings.Contains(err.Error(), "expansion too deep"), true) +} + func TestDisableExpansion(t *testing.T) { input := "key=value\nkey2=${key}" p := mustParse(t, input) @@ -875,6 +903,14 @@ func TestFilterFunc(t *testing.T) { assert.Equal(t, pp.Map(), m) } +func TestLoad(t *testing.T) { + x := "key=${value}\nvalue=${key}" + p := NewProperties() + p.DisableExpansion = true + err := p.Load([]byte(x), UTF8) + assert.Equal(t, err, nil) +} + // ---------------------------------------------------------------------------- // tests all combinations of delimiters, leading and/or trailing whitespace and newlines. diff --git a/vendor/github.com/magiconair/properties/rangecheck.go b/vendor/github.com/magiconair/properties/rangecheck.go index 2e907d54..b013a2e5 100644 --- a/vendor/github.com/magiconair/properties/rangecheck.go +++ b/vendor/github.com/magiconair/properties/rangecheck.go @@ -1,4 +1,4 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. +// Copyright 2018 Frank Schroeder. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/vendor/github.com/mitchellh/go-homedir/go.mod b/vendor/github.com/mitchellh/go-homedir/go.mod new file mode 100644 index 00000000..7efa09a0 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/go.mod @@ -0,0 +1 @@ +module github.com/mitchellh/go-homedir diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go index 47e1f9ef..fb87bef9 100644 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go @@ -77,33 +77,51 @@ func Expand(path string) (string, error) { } func dirUnix() (string, error) { + homeEnv := "HOME" + if runtime.GOOS == "plan9" { + // On plan9, env vars are lowercase. + homeEnv = "home" + } + // First prefer the HOME environmental variable - if home := os.Getenv("HOME"); home != "" { + if home := os.Getenv(homeEnv); home != "" { return home, nil } - // If that fails, try getent var stdout bytes.Buffer - cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - // If the error is ErrNotFound, we ignore it. Otherwise, return it. - if err != exec.ErrNotFound { - return "", err + + // If that fails, try OS specific commands + if runtime.GOOS == "darwin" { + cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + result := strings.TrimSpace(stdout.String()) + if result != "" { + return result, nil + } } } else { - if passwd := strings.TrimSpace(stdout.String()); passwd != "" { - // username:password:uid:gid:gecos:home:shell - passwdParts := strings.SplitN(passwd, ":", 7) - if len(passwdParts) > 5 { - return passwdParts[5], nil + cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + // If the error is ErrNotFound, we ignore it. Otherwise, return it. + if err != exec.ErrNotFound { + return "", err + } + } else { + if passwd := strings.TrimSpace(stdout.String()); passwd != "" { + // username:password:uid:gid:gecos:home:shell + passwdParts := strings.SplitN(passwd, ":", 7) + if len(passwdParts) > 5 { + return passwdParts[5], nil + } } } } // If all else fails, try the shell stdout.Reset() - cmd = exec.Command("sh", "-c", "cd && pwd") + cmd := exec.Command("sh", "-c", "cd && pwd") cmd.Stdout = &stdout if err := cmd.Run(); err != nil { return "", err @@ -123,14 +141,16 @@ func dirWindows() (string, error) { return home, nil } + // Prefer standard environment variable USERPROFILE + if home := os.Getenv("USERPROFILE"); home != "" { + return home, nil + } + drive := os.Getenv("HOMEDRIVE") path := os.Getenv("HOMEPATH") home := drive + path if drive == "" || path == "" { - home = os.Getenv("USERPROFILE") - } - if home == "" { - return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") + return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") } return home, nil diff --git a/vendor/github.com/mitchellh/go-homedir/homedir_test.go b/vendor/github.com/mitchellh/go-homedir/homedir_test.go index e4054e72..cd52127d 100644 --- a/vendor/github.com/mitchellh/go-homedir/homedir_test.go +++ b/vendor/github.com/mitchellh/go-homedir/homedir_test.go @@ -13,7 +13,12 @@ func patchEnv(key, value string) func() { os.Setenv(key, bck) } - os.Setenv(key, value) + if value != "" { + os.Setenv(key, value) + } else { + os.Unsetenv(key) + } + return deferFunc } @@ -43,6 +48,18 @@ func TestDir(t *testing.T) { if u.HomeDir != dir { t.Fatalf("%#v != %#v", u.HomeDir, dir) } + + DisableCache = true + defer func() { DisableCache = false }() + defer patchEnv("HOME", "")() + dir, err = Dir() + if err != nil { + t.Fatalf("err: %s", err) + } + + if u.HomeDir != dir { + t.Fatalf("%#v != %#v", u.HomeDir, dir) + } } func TestExpand(t *testing.T) { diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md index 7ecc785e..0018dc7d 100644 --- a/vendor/github.com/mitchellh/mapstructure/README.md +++ b/vendor/github.com/mitchellh/mapstructure/README.md @@ -1,4 +1,4 @@ -# mapstructure [![Godoc](https://godoc.org/github.com/mitchell/mapstructure?status.svg)](https://godoc.org/github.com/mitchell/mapstructure) +# mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure) mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling. diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go index afcfd5ee..2a727575 100644 --- a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go +++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go @@ -115,6 +115,25 @@ func StringToTimeDurationHookFunc() DecodeHookFunc { } } +// StringToTimeHookFunc returns a DecodeHookFunc that converts +// strings to time.Time. +func StringToTimeHookFunc(layout string) DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Time{}) { + return data, nil + } + + // Convert it by parsing + return time.Parse(layout, data.(string)) + } +} + // WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to // the decoder. // diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go index 53289afc..a81728e7 100644 --- a/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go +++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks_test.go @@ -153,6 +153,36 @@ func TestStringToTimeDurationHookFunc(t *testing.T) { } } +func TestStringToTimeHookFunc(t *testing.T) { + strType := reflect.TypeOf("") + timeType := reflect.TypeOf(time.Time{}) + cases := []struct { + f, t reflect.Type + layout string + data interface{} + result interface{} + err bool + }{ + {strType, timeType, time.RFC3339, "2006-01-02T15:04:05Z", + time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false}, + {strType, timeType, time.RFC3339, "5", time.Time{}, true}, + {strType, strType, time.RFC3339, "5", "5", false}, + } + + for i, tc := range cases { + f := StringToTimeHookFunc(tc.layout) + actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) + if tc.err != (err != nil) { + t.Fatalf("case %d: expected err %#v", i, tc.err) + } + if !reflect.DeepEqual(actual, tc.result) { + t.Fatalf( + "case %d: expected %#v, got %#v", + i, tc.result, actual) + } + } +} + func TestWeaklyTypedHook(t *testing.T) { var f DecodeHookFunc = WeaklyTypedHook diff --git a/vendor/github.com/mitchellh/mapstructure/go.mod b/vendor/github.com/mitchellh/mapstructure/go.mod new file mode 100644 index 00000000..d2a71256 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/go.mod @@ -0,0 +1 @@ +module github.com/mitchellh/mapstructure diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go index 39ec1e94..d3222b8f 100644 --- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go @@ -114,12 +114,12 @@ type Metadata struct { Unused []string } -// Decode takes a map and uses reflection to convert it into the -// given Go native structure. val must be a pointer to a struct. -func Decode(m interface{}, rawVal interface{}) error { +// Decode takes an input structure and uses reflection to translate it to +// the output structure. output must be a pointer to a map or struct. +func Decode(input interface{}, output interface{}) error { config := &DecoderConfig{ Metadata: nil, - Result: rawVal, + Result: output, } decoder, err := NewDecoder(config) @@ -127,7 +127,7 @@ func Decode(m interface{}, rawVal interface{}) error { return err } - return decoder.Decode(m) + return decoder.Decode(input) } // WeakDecode is the same as Decode but is shorthand to enable @@ -147,6 +147,40 @@ func WeakDecode(input, output interface{}) error { return decoder.Decode(input) } +// DecodeMetadata is the same as Decode, but is shorthand to +// enable metadata collection. See DecoderConfig for more info. +func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { + config := &DecoderConfig{ + Metadata: metadata, + Result: output, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// WeakDecodeMetadata is the same as Decode, but is shorthand to +// enable both WeaklyTypedInput and metadata collection. See +// DecoderConfig for more info. +func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { + config := &DecoderConfig{ + Metadata: metadata, + Result: output, + WeaklyTypedInput: true, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + // NewDecoder returns a new decoder for the given configuration. Once // a decoder has been returned, the same configuration must not be used // again. @@ -184,70 +218,81 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { // Decode decodes the given raw interface to the target pointer specified // by the configuration. -func (d *Decoder) Decode(raw interface{}) error { - return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem()) +func (d *Decoder) Decode(input interface{}) error { + return d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) } // Decodes an unknown data type into a specific reflection value. -func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error { - if data == nil { - // If the data is nil, then we don't set anything. +func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { + if input == nil { + // If the data is nil, then we don't set anything, unless ZeroFields is set + // to true. + if d.config.ZeroFields { + outVal.Set(reflect.Zero(outVal.Type())) + + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + } return nil } - dataVal := reflect.ValueOf(data) - if !dataVal.IsValid() { - // If the data value is invalid, then we just set the value + inputVal := reflect.ValueOf(input) + if !inputVal.IsValid() { + // If the input value is invalid, then we just set the value // to be the zero value. - val.Set(reflect.Zero(val.Type())) + outVal.Set(reflect.Zero(outVal.Type())) + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } return nil } if d.config.DecodeHook != nil { - // We have a DecodeHook, so let's pre-process the data. + // We have a DecodeHook, so let's pre-process the input. var err error - data, err = DecodeHookExec( + input, err = DecodeHookExec( d.config.DecodeHook, - dataVal.Type(), val.Type(), data) + inputVal.Type(), outVal.Type(), input) if err != nil { return fmt.Errorf("error decoding '%s': %s", name, err) } } var err error - dataKind := getKind(val) - switch dataKind { + inputKind := getKind(outVal) + switch inputKind { case reflect.Bool: - err = d.decodeBool(name, data, val) + err = d.decodeBool(name, input, outVal) case reflect.Interface: - err = d.decodeBasic(name, data, val) + err = d.decodeBasic(name, input, outVal) case reflect.String: - err = d.decodeString(name, data, val) + err = d.decodeString(name, input, outVal) case reflect.Int: - err = d.decodeInt(name, data, val) + err = d.decodeInt(name, input, outVal) case reflect.Uint: - err = d.decodeUint(name, data, val) + err = d.decodeUint(name, input, outVal) case reflect.Float32: - err = d.decodeFloat(name, data, val) + err = d.decodeFloat(name, input, outVal) case reflect.Struct: - err = d.decodeStruct(name, data, val) + err = d.decodeStruct(name, input, outVal) case reflect.Map: - err = d.decodeMap(name, data, val) + err = d.decodeMap(name, input, outVal) case reflect.Ptr: - err = d.decodePtr(name, data, val) + err = d.decodePtr(name, input, outVal) case reflect.Slice: - err = d.decodeSlice(name, data, val) + err = d.decodeSlice(name, input, outVal) case reflect.Array: - err = d.decodeArray(name, data, val) + err = d.decodeArray(name, input, outVal) case reflect.Func: - err = d.decodeFunc(name, data, val) + err = d.decodeFunc(name, input, outVal) default: // If we reached this point then we weren't able to decode it - return fmt.Errorf("%s: unsupported type: %s", name, dataKind) + return fmt.Errorf("%s: unsupported type: %s", name, inputKind) } // If we reached here, then we successfully decoded SOMETHING, so - // mark the key as used if we're tracking metadata. + // mark the key as used if we're tracking metainput. if d.config.Metadata != nil && name != "" { d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) } @@ -258,6 +303,9 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error // This decodes a basic type (bool, int, string, etc.) and sets the // value to "data" of that type. func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { + if val.IsValid() && val.Elem().IsValid() { + return d.decode(name, data, val.Elem()) + } dataVal := reflect.ValueOf(data) if !dataVal.IsValid() { dataVal = reflect.Zero(val.Type()) @@ -499,34 +547,50 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er valMap = reflect.MakeMap(mapType) } - // Check input type + // Check input type and based on the input type jump to the proper func dataVal := reflect.Indirect(reflect.ValueOf(data)) - if dataVal.Kind() != reflect.Map { - // In weak mode, we accept a slice of maps as an input... + switch dataVal.Kind() { + case reflect.Map: + return d.decodeMapFromMap(name, dataVal, val, valMap) + + case reflect.Struct: + return d.decodeMapFromStruct(name, dataVal, val, valMap) + + case reflect.Array, reflect.Slice: if d.config.WeaklyTypedInput { - switch dataVal.Kind() { - case reflect.Array, reflect.Slice: - // Special case for BC reasons (covered by tests) - if dataVal.Len() == 0 { - val.Set(valMap) - return nil - } - - for i := 0; i < dataVal.Len(); i++ { - err := d.decode( - fmt.Sprintf("%s[%d]", name, i), - dataVal.Index(i).Interface(), val) - if err != nil { - return err - } - } - - return nil - } + return d.decodeMapFromSlice(name, dataVal, val, valMap) } + fallthrough + + default: return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) } +} + +func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + // Special case for BC reasons (covered by tests) + if dataVal.Len() == 0 { + val.Set(valMap) + return nil + } + + for i := 0; i < dataVal.Len(); i++ { + err := d.decode( + fmt.Sprintf("%s[%d]", name, i), + dataVal.Index(i).Interface(), val) + if err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + valType := val.Type() + valKeyType := valType.Key() + valElemType := valType.Elem() // Accumulate errors errors := make([]string, 0) @@ -563,22 +627,106 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er return nil } +func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + typ := dataVal.Type() + for i := 0; i < typ.NumField(); i++ { + // Get the StructField first since this is a cheap operation. If the + // field is unexported, then ignore it. + f := typ.Field(i) + if f.PkgPath != "" { + continue + } + + // Next get the actual value of this field and verify it is assignable + // to the map value. + v := dataVal.Field(i) + if !v.Type().AssignableTo(valMap.Type().Elem()) { + return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) + } + + tagValue := f.Tag.Get(d.config.TagName) + tagParts := strings.Split(tagValue, ",") + + // Determine the name of the key in the map + keyName := f.Name + if tagParts[0] != "" { + if tagParts[0] == "-" { + continue + } + keyName = tagParts[0] + } + + // If "squash" is specified in the tag, we squash the field down. + squash := false + for _, tag := range tagParts[1:] { + if tag == "squash" { + squash = true + break + } + } + if squash && v.Kind() != reflect.Struct { + return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) + } + + switch v.Kind() { + // this is an embedded struct, so handle it differently + case reflect.Struct: + x := reflect.New(v.Type()) + x.Elem().Set(v) + + vType := valMap.Type() + vKeyType := vType.Key() + vElemType := vType.Elem() + mType := reflect.MapOf(vKeyType, vElemType) + vMap := reflect.MakeMap(mType) + + err := d.decode(keyName, x.Interface(), vMap) + if err != nil { + return err + } + + if squash { + for _, k := range vMap.MapKeys() { + valMap.SetMapIndex(k, vMap.MapIndex(k)) + } + } else { + valMap.SetMapIndex(reflect.ValueOf(keyName), vMap) + } + + default: + valMap.SetMapIndex(reflect.ValueOf(keyName), v) + } + } + + if val.CanAddr() { + val.Set(valMap) + } + + return nil +} + func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. valType := val.Type() valElemType := valType.Elem() - realVal := val - if realVal.IsNil() || d.config.ZeroFields { - realVal = reflect.New(valElemType) - } + if val.CanSet() { + realVal := val + if realVal.IsNil() || d.config.ZeroFields { + realVal = reflect.New(valElemType) + } - if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { - return err - } + if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { + return err + } - val.Set(realVal) + val.Set(realVal) + } else { + if err := d.decode(name, data, reflect.Indirect(val)); err != nil { + return err + } + } return nil } @@ -614,7 +762,11 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) val.Set(reflect.MakeSlice(sliceType, 0, 0)) return nil } + // Create slice of maps of other sizes + return d.decodeSlice(name, []interface{}{data}, val) + case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: + return d.decodeSlice(name, []byte(dataVal.String()), val) // All other types we try to convert to the slice type // and "lift" it into it. i.e. a string becomes a string slice. default: @@ -622,7 +774,6 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) return d.decodeSlice(name, []interface{}{data}, val) } } - return fmt.Errorf( "'%s': source data must be an array or slice, got %s", name, dataValKind) diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go b/vendor/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go index ecfb7698..1319da56 100644 --- a/vendor/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go @@ -1,48 +1,142 @@ package mapstructure -import "testing" +import ( + "reflect" + "testing" +) -// GH-1 +// GH-1, GH-10, GH-96 func TestDecode_NilValue(t *testing.T) { - input := map[string]interface{}{ - "vfoo": nil, - "vother": nil, + t.Parallel() + + tests := []struct { + name string + in interface{} + target interface{} + out interface{} + metaKeys []string + metaUnused []string + }{ + { + "all nil", + &map[string]interface{}{ + "vfoo": nil, + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "", Vother: nil}, + []string{"Vfoo", "Vother"}, + []string{}, + }, + { + "partial nil", + &map[string]interface{}{ + "vfoo": "baz", + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "baz", Vother: nil}, + []string{"Vfoo", "Vother"}, + []string{}, + }, + { + "partial decode", + &map[string]interface{}{ + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "foo", Vother: nil}, + []string{"Vother"}, + []string{}, + }, + { + "unused values", + &map[string]interface{}{ + "vbar": "bar", + "vfoo": nil, + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "", Vother: nil}, + []string{"Vfoo", "Vother"}, + []string{"vbar"}, + }, + { + "map interface all nil", + &map[interface{}]interface{}{ + "vfoo": nil, + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "", Vother: nil}, + []string{"Vfoo", "Vother"}, + []string{}, + }, + { + "map interface partial nil", + &map[interface{}]interface{}{ + "vfoo": "baz", + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "baz", Vother: nil}, + []string{"Vfoo", "Vother"}, + []string{}, + }, + { + "map interface partial decode", + &map[interface{}]interface{}{ + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "foo", Vother: nil}, + []string{"Vother"}, + []string{}, + }, + { + "map interface unused values", + &map[interface{}]interface{}{ + "vbar": "bar", + "vfoo": nil, + "vother": nil, + }, + &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}}, + &Map{Vfoo: "", Vother: nil}, + []string{"Vfoo", "Vother"}, + []string{"vbar"}, + }, } - var result Map - err := Decode(input, &result) - if err != nil { - t.Fatalf("should not error: %s", err) - } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + config := &DecoderConfig{ + Metadata: new(Metadata), + Result: tc.target, + ZeroFields: true, + } - if result.Vfoo != "" { - t.Fatalf("value should be default: %s", result.Vfoo) - } + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("should not error: %s", err) + } - if result.Vother != nil { - t.Fatalf("Vother should be nil: %s", result.Vother) - } -} + err = decoder.Decode(tc.in) + if err != nil { + t.Fatalf("should not error: %s", err) + } -// GH-10 -func TestDecode_mapInterfaceInterface(t *testing.T) { - input := map[interface{}]interface{}{ - "vfoo": nil, - "vother": nil, - } + if !reflect.DeepEqual(tc.out, tc.target) { + t.Fatalf("%q: TestDecode_NilValue() expected: %#v, got: %#v", tc.name, tc.out, tc.target) + } - var result Map - err := Decode(input, &result) - if err != nil { - t.Fatalf("should not error: %s", err) - } + if !reflect.DeepEqual(tc.metaKeys, config.Metadata.Keys) { + t.Fatalf("%q: Metadata.Keys mismatch expected: %#v, got: %#v", tc.name, tc.metaKeys, config.Metadata.Keys) + } - if result.Vfoo != "" { - t.Fatalf("value should be default: %s", result.Vfoo) - } - - if result.Vother != nil { - t.Fatalf("Vother should be nil: %s", result.Vother) + if !reflect.DeepEqual(tc.metaUnused, config.Metadata.Unused) { + t.Fatalf("%q: Metadata.Unused mismatch expected: %#v, got: %#v", tc.name, tc.metaUnused, config.Metadata.Unused) + } + }) } } diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go b/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go index 89861edd..344ffa35 100644 --- a/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure_test.go @@ -128,6 +128,7 @@ type TypeConversionResult struct { FloatToBool bool FloatToString string SliceUint8ToString string + StringToSliceUint8 []byte ArrayUint8ToString string StringToInt int StringToUint uint @@ -248,6 +249,32 @@ func TestBasic_Merge(t *testing.T) { } } +// Test for issue #46. +func TestBasic_Struct(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vdata": map[string]interface{}{ + "vstring": "foo", + }, + } + + var result, inner Basic + result.Vdata = &inner + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err) + } + expected := Basic{ + Vdata: &Basic{ + Vstring: "foo", + }, + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("bad: %#v", result) + } +} + func TestDecode_BasicSquash(t *testing.T) { t.Parallel() @@ -266,6 +293,36 @@ func TestDecode_BasicSquash(t *testing.T) { } } +func TestDecodeFrom_BasicSquash(t *testing.T) { + t.Parallel() + + var v interface{} + var ok bool + + input := BasicSquash{ + Test: Basic{ + Vstring: "foo", + }, + } + + var result map[string]interface{} + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if _, ok = result["Test"]; ok { + t.Error("test should not be present in map") + } + + v, ok = result["Vstring"] + if !ok { + t.Error("vstring should be present in map") + } else if !reflect.DeepEqual(v, "foo") { + t.Errorf("vstring value should be 'foo': %#v", v) + } +} + func TestDecode_Embedded(t *testing.T) { t.Parallel() @@ -389,6 +446,44 @@ func TestDecode_EmbeddedSquash(t *testing.T) { } } +func TestDecodeFrom_EmbeddedSquash(t *testing.T) { + t.Parallel() + + var v interface{} + var ok bool + + input := EmbeddedSquash{ + Basic: Basic{ + Vstring: "foo", + }, + Vunique: "bar", + } + + var result map[string]interface{} + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if _, ok = result["Basic"]; ok { + t.Error("basic should not be present in map") + } + + v, ok = result["Vstring"] + if !ok { + t.Error("vstring should be present in map") + } else if !reflect.DeepEqual(v, "foo") { + t.Errorf("vstring value should be 'foo': %#v", v) + } + + v, ok = result["Vunique"] + if !ok { + t.Error("vunique should be present in map") + } else if !reflect.DeepEqual(v, "bar") { + t.Errorf("vunique value should be 'bar': %#v", v) + } +} + func TestDecode_SquashOnNonStructType(t *testing.T) { t.Parallel() @@ -626,6 +721,7 @@ func TestDecode_TypeConversion(t *testing.T) { "FloatToBool": 42.42, "FloatToString": 42.42, "SliceUint8ToString": []uint8("foo"), + "StringToSliceUint8": "foo", "ArrayUint8ToString": [3]uint8{'f', 'o', 'o'}, "StringToInt": "42", "StringToUint": "42", @@ -671,6 +767,7 @@ func TestDecode_TypeConversion(t *testing.T) { FloatToBool: true, FloatToString: "42.42", SliceUint8ToString: "foo", + StringToSliceUint8: []byte("foo"), ArrayUint8ToString: "foo", StringToInt: 42, StringToUint: 42, @@ -926,6 +1023,56 @@ func TestNestedTypePointer(t *testing.T) { } } +// Test for issue #46. +func TestNestedTypeInterface(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": &map[string]interface{}{ + "vstring": "foo", + "vint": 42, + "vbool": true, + + "vdata": map[string]interface{}{ + "vstring": "bar", + }, + }, + } + + var result NestedPointer + result.Vbar = new(Basic) + result.Vbar.Vdata = new(Basic) + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + if result.Vbar.Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) + } + + if result.Vbar.Vint != 42 { + t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) + } + + if result.Vbar.Vbool != true { + t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) + } + + if result.Vbar.Vextra != "" { + t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) + } + + if result.Vbar.Vdata.(*Basic).Vstring != "bar" { + t.Errorf("vstring value should be 'bar': %#v", result.Vbar.Vdata.(*Basic).Vstring) + } +} + func TestSlice(t *testing.T) { t.Parallel() @@ -992,6 +1139,37 @@ func TestSliceOfStruct(t *testing.T) { } } +func TestSliceCornerCases(t *testing.T) { + t.Parallel() + + // Input with a map with zero values + input := map[string]interface{}{} + var resultWeak []Basic + + err := WeakDecode(input, &resultWeak) + if err != nil { + t.Fatalf("got unexpected error: %s", err) + } + + if len(resultWeak) != 0 { + t.Errorf("length should be 0") + } + // Input with more values + input = map[string]interface{}{ + "Vstring": "foo", + } + + resultWeak = nil + err = WeakDecode(input, &resultWeak) + if err != nil { + t.Fatalf("got unexpected error: %s", err) + } + + if resultWeak[0].Vstring != "foo" { + t.Errorf("value does not match") + } +} + func TestSliceToMap(t *testing.T) { t.Parallel() @@ -1112,6 +1290,197 @@ func TestArrayToMap(t *testing.T) { } } +func TestMapOutputForStructuredInputs(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + in interface{} + target interface{} + out interface{} + wantErr bool + }{ + { + "basic struct input", + &Basic{ + Vstring: "vstring", + Vint: 2, + Vuint: 3, + Vbool: true, + Vfloat: 4.56, + Vextra: "vextra", + vsilent: true, + Vdata: []byte("data"), + }, + &map[string]interface{}{}, + &map[string]interface{}{ + "Vstring": "vstring", + "Vint": 2, + "Vuint": uint(3), + "Vbool": true, + "Vfloat": 4.56, + "Vextra": "vextra", + "Vdata": []byte("data"), + "VjsonInt": 0, + "VjsonFloat": 0.0, + "VjsonNumber": json.Number(""), + }, + false, + }, + { + "embedded struct input", + &Embedded{ + Vunique: "vunique", + Basic: Basic{ + Vstring: "vstring", + Vint: 2, + Vuint: 3, + Vbool: true, + Vfloat: 4.56, + Vextra: "vextra", + vsilent: true, + Vdata: []byte("data"), + }, + }, + &map[string]interface{}{}, + &map[string]interface{}{ + "Vunique": "vunique", + "Basic": map[string]interface{}{ + "Vstring": "vstring", + "Vint": 2, + "Vuint": uint(3), + "Vbool": true, + "Vfloat": 4.56, + "Vextra": "vextra", + "Vdata": []byte("data"), + "VjsonInt": 0, + "VjsonFloat": 0.0, + "VjsonNumber": json.Number(""), + }, + }, + false, + }, + { + "slice input - should error", + []string{"foo", "bar"}, + &map[string]interface{}{}, + &map[string]interface{}{}, + true, + }, + { + "struct with slice property", + &Slice{ + Vfoo: "vfoo", + Vbar: []string{"foo", "bar"}, + }, + &map[string]interface{}{}, + &map[string]interface{}{ + "Vfoo": "vfoo", + "Vbar": []string{"foo", "bar"}, + }, + false, + }, + { + "struct with slice of struct property", + &SliceOfStruct{ + Value: []Basic{ + Basic{ + Vstring: "vstring", + Vint: 2, + Vuint: 3, + Vbool: true, + Vfloat: 4.56, + Vextra: "vextra", + vsilent: true, + Vdata: []byte("data"), + }, + }, + }, + &map[string]interface{}{}, + &map[string]interface{}{ + "Value": []Basic{ + Basic{ + Vstring: "vstring", + Vint: 2, + Vuint: 3, + Vbool: true, + Vfloat: 4.56, + Vextra: "vextra", + vsilent: true, + Vdata: []byte("data"), + }, + }, + }, + false, + }, + { + "struct with map property", + &Map{ + Vfoo: "vfoo", + Vother: map[string]string{"vother": "vother"}, + }, + &map[string]interface{}{}, + &map[string]interface{}{ + "Vfoo": "vfoo", + "Vother": map[string]string{ + "vother": "vother", + }}, + false, + }, + { + "tagged struct", + &Tagged{ + Extra: "extra", + Value: "value", + }, + &map[string]string{}, + &map[string]string{ + "bar": "extra", + "foo": "value", + }, + false, + }, + { + "omit tag struct", + &struct { + Value string `mapstructure:"value"` + Omit string `mapstructure:"-"` + }{ + Value: "value", + Omit: "omit", + }, + &map[string]string{}, + &map[string]string{ + "value": "value", + }, + false, + }, + { + "decode to wrong map type", + &struct { + Value string + }{ + Value: "string", + }, + &map[string]int{}, + &map[string]int{}, + true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Decode(tt.in, tt.target); (err != nil) != tt.wantErr { + t.Fatalf("%q: TestMapOutputForStructuredInputs() unexpected error: %s", tt.name, err) + } + + if !reflect.DeepEqual(tt.out, tt.target) { + t.Fatalf("%q: TestMapOutputForStructuredInputs() expected: %#v, got: %#v", tt.name, tt.out, tt.target) + } + }) + } +} + func TestInvalidType(t *testing.T) { t.Parallel() @@ -1171,6 +1540,39 @@ func TestInvalidType(t *testing.T) { } } +func TestDecodeMetadata(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": map[string]interface{}{ + "vstring": "foo", + "Vuint": 42, + "foo": "bar", + }, + "bar": "nil", + } + + var md Metadata + var result Nested + + err := DecodeMetadata(input, &result, &md) + if err != nil { + t.Fatalf("err: %s", err.Error()) + } + + expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} + sort.Strings(md.Keys) + if !reflect.DeepEqual(md.Keys, expectedKeys) { + t.Fatalf("bad keys: %#v", md.Keys) + } + + expectedUnused := []string{"Vbar.foo", "bar"} + if !reflect.DeepEqual(md.Unused, expectedUnused) { + t.Fatalf("bad unused: %#v", md.Unused) + } +} + func TestMetadata(t *testing.T) { t.Parallel() @@ -1311,6 +1713,43 @@ func TestWeakDecode(t *testing.T) { } } +func TestWeakDecodeMetadata(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "foo": "4", + "bar": "value", + "unused": "value", + } + + var md Metadata + var result struct { + Foo int + Bar string + } + + if err := WeakDecodeMetadata(input, &result, &md); err != nil { + t.Fatalf("err: %s", err) + } + if result.Foo != 4 { + t.Fatalf("bad: %#v", result) + } + if result.Bar != "value" { + t.Fatalf("bad: %#v", result) + } + + expectedKeys := []string{"Bar", "Foo"} + sort.Strings(md.Keys) + if !reflect.DeepEqual(md.Keys, expectedKeys) { + t.Fatalf("bad keys: %#v", md.Keys) + } + + expectedUnused := []string{"unused"} + if !reflect.DeepEqual(md.Unused, expectedUnused) { + t.Fatalf("bad unused: %#v", md.Unused) + } +} + func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) { var result Slice err := Decode(input, &result) diff --git a/vendor/github.com/onsi/ginkgo/.gitignore b/vendor/github.com/onsi/ginkgo/.gitignore index 34f02dcc..18793c24 100644 --- a/vendor/github.com/onsi/ginkgo/.gitignore +++ b/vendor/github.com/onsi/ginkgo/.gitignore @@ -2,4 +2,6 @@ TODO tmp/**/* *.coverprofile -.vscode \ No newline at end of file +.vscode +.idea/ +*.log \ No newline at end of file diff --git a/vendor/github.com/onsi/ginkgo/.travis.yml b/vendor/github.com/onsi/ginkgo/.travis.yml index f50fc023..7ad39b78 100644 --- a/vendor/github.com/onsi/ginkgo/.travis.yml +++ b/vendor/github.com/onsi/ginkgo/.travis.yml @@ -1,9 +1,10 @@ language: go go: - - 1.5.x - 1.6.x - 1.7.x - 1.8.x + - 1.9.x + - 1.10.x install: - go get -v -t ./... @@ -12,4 +13,4 @@ install: - go install github.com/onsi/ginkgo/ginkgo - export PATH=$PATH:$HOME/gopath/bin -script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace +script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace && go vet diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md index b00b52ff..32370206 100644 --- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md +++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md @@ -1,3 +1,49 @@ +## 1.6.0 + +### New Features +- add --debug flag to emit node output to files (#499) [39febac] + +### Fixes +- fix: for `go vet` to pass [69338ec] +- docs: fix for contributing instructions [7004cb1] +- consolidate and streamline contribution docs (#494) [d848015] +- Make generated Junit file compatable with "Maven Surefire" (#488) [e51bee6] +- all: gofmt [000d317] +- Increase eventually timeout to 30s [c73579c] +- Clarify asynchronous test behaviour [294d8f4] +- Travis badge should only show master [26d2143] + +## 1.5.0 5/10/2018 + +### New Features +- Supports go v1.10 (#443, #446, #451) [e873237, 468e89e, e37dbfe, a37f4c0, c0b857d, bca5260, 4177ca8] +- Add a When() synonym for Context() (#386) [747514b, 7484dad, 7354a07, dd826c8] +- Re-add noisySkippings flag [652e15c] +- Allow coverage to be displayed for focused specs (#367) [11459a8] +- Handle -outputdir flag (#364) [228e3a8] +- Handle -coverprofile flag (#355) [43392d5] + +### Fixes +- When using custom reporters register the custom reporters *before* the default reporter. This allows users to see the output of any print statements in their customer reporters. (#365) [8382b23] +- When running a test and calculating the coverage using the `-coverprofile` and `-outputdir` flags, Ginkgo fails with an error if the directory does not exist. This is due to an [issue in go 1.10](https://github.com/golang/go/issues/24588) (#446) [b36a6e0] +- `unfocus` command ignores vendor folder (#459) [e5e551c, c556e43, a3b6351, 9a820dd] +- Ignore packages whose tests are all ignored by go (#456) [7430ca7, 6d8be98] +- Increase the threshold when checking time measuments (#455) [2f714bf, 68f622c] +- Fix race condition in coverage tests (#423) [a5a8ff7, ab9c08b] +- Add an extra new line after reporting spec run completion for test2json [874520d] +- added name name field to junit reported testsuite [ae61c63] +- Do not set the run time of a spec when the dryRun flag is used (#438) [457e2d9, ba8e856] +- Process FWhen and FSpecify when unfocusing (#434) [9008c7b, ee65bd, df87dfe] +- Synchronise the access to the state of specs to avoid race conditions (#430) [7d481bc, ae6829d] +- Added Duration on GinkgoTestDescription (#383) [5f49dad, 528417e, 0747408, 329d7ed] +- Fix Ginkgo stack trace on failure for Specify (#415) [b977ede, 65ca40e, 6c46eb8] +- Update README with Go 1.6+, Golang -> Go (#409) [17f6b97, bc14b66, 20d1598] +- Use fmt.Errorf instead of errors.New(fmt.Sprintf (#401) [a299f56, 44e2eaa] +- Imports in generated code should follow conventions (#398) [0bec0b0, e8536d8] +- Prevent data race error when Recording a benchmark value from multiple go routines (#390) [c0c4881, 7a241e9] +- Replace GOPATH in Environment [4b883f0] + + ## 1.4.0 7/16/2017 - `ginkgo` now provides a hint if you accidentally forget to run `ginkgo bootstrap` to generate a `*_suite_test.go` file that actually invokes the Ginkgo test runner. [#345](https://github.com/onsi/ginkgo/pull/345) diff --git a/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md b/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md index bc0c54fe..908b95c2 100644 --- a/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md +++ b/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md @@ -1,12 +1,33 @@ # Contributing to Ginkgo -Your contributions to Ginkgo are essential for its long-term maintenance and improvement. To make a contribution: +Your contributions to Ginkgo are essential for its long-term maintenance and improvement. - Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code! - Ensure adequate test coverage: - - If you're adding functionality to the Ginkgo library, make sure to add appropriate unit and/or integration tests (under the `integration` folder). - - If you're adding functionality to the Ginkgo CLI note that there are very few unit tests. Please add an integration test. - - Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR -- Update the documentation. In addition to standard `godoc` comments Ginkgo has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR. + - When adding to the Ginkgo library, add unit and/or integration tests (under the `integration` folder). + - When adding to the Ginkgo CLI, note that there are very few unit tests. Please add an integration test. +- Update the documentation. Ginko uses `godoc` comments and documentation on the `gh-pages` branch. + If relevant, please submit a docs PR to that branch alongside your code PR. -Thanks for supporting Ginkgo! \ No newline at end of file +Thanks for supporting Ginkgo! + +## Setup + +Fork the repo, then: + +``` +go get github.com/onsi/ginkgo +go get github.com/onsi/gomega/... +cd $GOPATH/src/github.com/onsi/ginkgo +git remote add fork git@github.com:/ginkgo.git + +ginkgo -r -p # ensure tests are green +go vet ./... # ensure linter is happy +``` + +## Making the PR + - go to a new branch `git checkout -b my-feature` + - make your changes + - run tests and linter again (see above) + - `git push fork` + - open PR 🎉 diff --git a/vendor/github.com/onsi/ginkgo/README.md b/vendor/github.com/onsi/ginkgo/README.md index d3097989..cdf8d054 100644 --- a/vendor/github.com/onsi/ginkgo/README.md +++ b/vendor/github.com/onsi/ginkgo/README.md @@ -1,6 +1,6 @@ -![Ginkgo: A Golang BDD Testing Framework](http://onsi.github.io/ginkgo/images/ginkgo.png) +![Ginkgo: A Go BDD Testing Framework](http://onsi.github.io/ginkgo/images/ginkgo.png) -[![Build Status](https://travis-ci.org/onsi/ginkgo.svg)](https://travis-ci.org/onsi/ginkgo) +[![Build Status](https://travis-ci.org/onsi/ginkgo.svg?branch=master)](https://travis-ci.org/onsi/ginkgo) Jump to the [docs](http://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)! @@ -11,9 +11,9 @@ If you have a question, comment, bug report, feature request, etc. please open a - Ginkgo uses Go's `testing` package and can live alongside your existing `testing` tests. It's easy to [bootstrap](http://onsi.github.io/ginkgo/#bootstrapping-a-suite) and start writing your [first tests](http://onsi.github.io/ginkgo/#adding-specs-to-a-suite) - Structure your BDD-style tests expressively: - - Nestable [`Describe` and `Context` container blocks](http://onsi.github.io/ginkgo/#organizing-specs-with-containers-describe-and-context) + - Nestable [`Describe`, `Context` and `When` container blocks](http://onsi.github.io/ginkgo/#organizing-specs-with-containers-describe-and-context) - [`BeforeEach` and `AfterEach` blocks](http://onsi.github.io/ginkgo/#extracting-common-setup-beforeeach) for setup and teardown - - [`It` blocks](http://onsi.github.io/ginkgo/#individual-specs-) that hold your assertions + - [`It` and `Specify` blocks](http://onsi.github.io/ginkgo/#individual-specs-) that hold your assertions - [`JustBeforeEach` blocks](http://onsi.github.io/ginkgo/#separating-creation-and-configuration-justbeforeeach) that separate creation from configuration (also known as the subject action pattern). - [`BeforeSuite` and `AfterSuite` blocks](http://onsi.github.io/ginkgo/#global-setup-and-teardown-beforesuite-and-aftersuite) to prep for and cleanup after a suite. @@ -25,7 +25,7 @@ If you have a question, comment, bug report, feature request, etc. please open a - `ginkgo`: a command line interface with plenty of handy command line arguments for [running your tests](http://onsi.github.io/ginkgo/#running-tests) and [generating](http://onsi.github.io/ginkgo/#generators) test files. Here are a few choice examples: - `ginkgo -nodes=N` runs your tests in `N` parallel processes and print out coherent output in realtime - - `ginkgo -cover` runs your tests using Golang's code coverage tool + - `ginkgo -cover` runs your tests using Go's code coverage tool - `ginkgo convert` converts an XUnit-style `testing` package to a Ginkgo-style package - `ginkgo -focus="REGEXP"` and `ginkgo -skip="REGEXP"` allow you to specify a subset of tests to run via regular expression - `ginkgo -r` runs all tests suites under the current directory @@ -55,18 +55,18 @@ If you have a question, comment, bug report, feature request, etc. please open a Ginkgo is best paired with Gomega. Learn more about Gomega [here](http://onsi.github.io/gomega/) -## [Agouti](http://github.com/sclevine/agouti): A Golang Acceptance Testing Framework +## [Agouti](http://github.com/sclevine/agouti): A Go Acceptance Testing Framework Agouti allows you run WebDriver integration tests. Learn more about Agouti [here](http://agouti.org) ## Set Me Up! -You'll need Golang v1.3+ (Ubuntu users: you probably have Golang v1.0 -- you'll need to upgrade!) +You'll need the Go command-line tools. Ginkgo is tested with Go 1.6+, but preferably you should get the latest. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed. ```bash -go get github.com/onsi/ginkgo/ginkgo # installs the ginkgo CLI -go get github.com/onsi/gomega # fetches the matcher library +go get -u github.com/onsi/ginkgo/ginkgo # installs the ginkgo CLI +go get -u github.com/onsi/gomega/... # fetches the matcher library cd path/to/package/you/want/to/test @@ -85,11 +85,11 @@ Of course, I heartily recommend [Ginkgo](https://github.com/onsi/ginkgo) and [Go With that said, it's great to know what your options are :) -### What Golang gives you out of the box +### What Go gives you out of the box -Testing is a first class citizen in Golang, however Go's built-in testing primitives are somewhat limited: The [testing](http://golang.org/pkg/testing) package provides basic XUnit style tests and no assertion library. +Testing is a first class citizen in Go, however Go's built-in testing primitives are somewhat limited: The [testing](http://golang.org/pkg/testing) package provides basic XUnit style tests and no assertion library. -### Matcher libraries for Golang's XUnit style tests +### Matcher libraries for Go's XUnit style tests A number of matcher libraries have been written to augment Go's built-in XUnit style tests. Here are two that have gained traction: @@ -100,7 +100,7 @@ You can also use Ginkgo's matcher library [Gomega](https://github.com/onsi/gomeg ### BDD style testing frameworks -There are a handful of BDD-style testing frameworks written for Golang. Here are a few: +There are a handful of BDD-style testing frameworks written for Go. Here are a few: - [Ginkgo](https://github.com/onsi/ginkgo) ;) - [GoConvey](https://github.com/smartystreets/goconvey) @@ -108,10 +108,14 @@ There are a handful of BDD-style testing frameworks written for Golang. Here ar - [Mao](https://github.com/azer/mao) - [Zen](https://github.com/pranavraja/zen) -Finally, @shageman has [put together](https://github.com/shageman/gotestit) a comprehensive comparison of golang testing libraries. +Finally, @shageman has [put together](https://github.com/shageman/gotestit) a comprehensive comparison of Go testing libraries. Go explore! ## License Ginkgo is MIT-Licensed + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/vendor/github.com/onsi/ginkgo/RELEASING.md b/vendor/github.com/onsi/ginkgo/RELEASING.md new file mode 100644 index 00000000..1e298c2d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/RELEASING.md @@ -0,0 +1,14 @@ +A Ginkgo release is a tagged git sha and a GitHub release. To cut a release: + +1. Ensure CHANGELOG.md is up to date. + - Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release + - Categorize the changes into + - Breaking Changes (requires a major version) + - New Features (minor version) + - Fixes (fix version) + - Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact) +1. Update `VERSION` in `config/config.go` +1. Create a commit with the version number as the commit message (e.g. `v1.3.0`) +1. Tag the commit with the version number as the tag name (e.g. `v1.3.0`) +1. Push the commit and tag to GitHub +1. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes. diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go index 60d5ea22..d4ed1fa5 100644 --- a/vendor/github.com/onsi/ginkgo/config/config.go +++ b/vendor/github.com/onsi/ginkgo/config/config.go @@ -20,7 +20,7 @@ import ( "fmt" ) -const VERSION = "1.4.0" +const VERSION = "1.6.0" type GinkgoConfigType struct { RandomSeed int64 @@ -34,6 +34,7 @@ type GinkgoConfigType struct { FlakeAttempts int EmitSpecProgress bool DryRun bool + DebugParallel bool ParallelNode int ParallelTotal int @@ -47,6 +48,7 @@ type DefaultReporterConfigType struct { NoColor bool SlowSpecThreshold float64 NoisyPendings bool + NoisySkippings bool Succinct bool Verbose bool FullTrace bool @@ -64,7 +66,7 @@ func processPrefix(prefix string) string { func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) { prefix = processPrefix(prefix) flagSet.Int64Var(&(GinkgoConfig.RandomSeed), prefix+"seed", time.Now().Unix(), "The seed used to randomize the spec suite.") - flagSet.BoolVar(&(GinkgoConfig.RandomizeAllSpecs), prefix+"randomizeAllSpecs", false, "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe/Context groups.") + flagSet.BoolVar(&(GinkgoConfig.RandomizeAllSpecs), prefix+"randomizeAllSpecs", false, "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe, Context and When groups.") flagSet.BoolVar(&(GinkgoConfig.SkipMeasurements), prefix+"skipMeasurements", false, "If set, ginkgo will skip any measurement specs.") flagSet.BoolVar(&(GinkgoConfig.FailOnPending), prefix+"failOnPending", false, "If set, ginkgo will mark the test suite as failed if any specs are pending.") flagSet.BoolVar(&(GinkgoConfig.FailFast), prefix+"failFast", false, "If set, ginkgo will stop running a test suite after a failure occurs.") @@ -80,6 +82,8 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) { flagSet.BoolVar(&(GinkgoConfig.EmitSpecProgress), prefix+"progress", false, "If set, ginkgo will emit progress information as each spec runs to the GinkgoWriter.") + flagSet.BoolVar(&(GinkgoConfig.DebugParallel), prefix+"debug", false, "If set, ginkgo will emit node output to files when running in parallel.") + if includeParallelFlags { flagSet.IntVar(&(GinkgoConfig.ParallelNode), prefix+"parallel.node", 1, "This worker node's (one-indexed) node number. For running specs in parallel.") flagSet.IntVar(&(GinkgoConfig.ParallelTotal), prefix+"parallel.total", 1, "The total number of worker nodes. For running specs in parallel.") @@ -90,6 +94,7 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) { flagSet.BoolVar(&(DefaultReporterConfig.NoColor), prefix+"noColor", false, "If set, suppress color output in default reporter.") flagSet.Float64Var(&(DefaultReporterConfig.SlowSpecThreshold), prefix+"slowSpecThreshold", 5.0, "(in seconds) Specs that take longer to run than this threshold are flagged as slow by the default reporter.") flagSet.BoolVar(&(DefaultReporterConfig.NoisyPendings), prefix+"noisyPendings", true, "If set, default reporter will shout about pending tests.") + flagSet.BoolVar(&(DefaultReporterConfig.NoisySkippings), prefix+"noisySkippings", true, "If set, default reporter will shout about skipping tests.") flagSet.BoolVar(&(DefaultReporterConfig.Verbose), prefix+"v", false, "If set, default reporter print out all specs as they begin.") flagSet.BoolVar(&(DefaultReporterConfig.Succinct), prefix+"succinct", false, "If set, default reporter prints out a very succinct report") flagSet.BoolVar(&(DefaultReporterConfig.FullTrace), prefix+"trace", false, "If set, default reporter prints out the full stack trace when a failure occurs") @@ -139,6 +144,10 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor result = append(result, fmt.Sprintf("--%sprogress", prefix)) } + if ginkgo.DebugParallel { + result = append(result, fmt.Sprintf("--%sdebug", prefix)) + } + if ginkgo.ParallelNode != 0 { result = append(result, fmt.Sprintf("--%sparallel.node=%d", prefix, ginkgo.ParallelNode)) } @@ -171,6 +180,10 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor result = append(result, fmt.Sprintf("--%snoisyPendings=false", prefix)) } + if !reporter.NoisySkippings { + result = append(result, fmt.Sprintf("--%snoisySkippings=false", prefix)) + } + if reporter.Verbose { result = append(result, fmt.Sprintf("--%sv", prefix)) } diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go index 1e209e4f..fea4d4d4 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/bootstrap_command.go @@ -43,10 +43,10 @@ func BuildBootstrapCommand() *Command { var bootstrapText = `package {{.Package}} import ( + "testing" + {{.GinkgoImport}} {{.GomegaImport}} - - "testing" ) func Test{{.FormattedName}}(t *testing.T) { @@ -58,11 +58,11 @@ func Test{{.FormattedName}}(t *testing.T) { var agoutiBootstrapText = `package {{.Package}} import ( + "testing" + {{.GinkgoImport}} {{.GomegaImport}} "github.com/sclevine/agouti" - - "testing" ) func Test{{.FormattedName}}(t *testing.T) { diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/convert_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/convert_command.go index 89e60d39..5944ed85 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/convert_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/convert_command.go @@ -3,8 +3,9 @@ package main import ( "flag" "fmt" - "github.com/onsi/ginkgo/ginkgo/convert" "os" + + "github.com/onsi/ginkgo/ginkgo/convert" ) func BuildConvertCommand() *Command { diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/generate_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/generate_command.go index 3b9405aa..019fd233 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/generate_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/generate_command.go @@ -34,10 +34,10 @@ func BuildGenerateCommand() *Command { var specText = `package {{.Package}} import ( - {{if .DotImportPackage}}. "{{.PackageImportPath}}"{{end}} - {{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}} {{if .IncludeImports}}. "github.com/onsi/gomega"{{end}} + + {{if .DotImportPackage}}. "{{.PackageImportPath}}"{{end}} ) var _ = Describe("{{.Subject}}", func() { @@ -45,15 +45,15 @@ var _ = Describe("{{.Subject}}", func() { }) ` -var agoutiSpecText = `package {{.Package}}_test +var agoutiSpecText = `package {{.Package}} import ( - {{if .DotImportPackage}}. "{{.PackageImportPath}}"{{end}} - {{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}} {{if .IncludeImports}}. "github.com/onsi/gomega"{{end}} - . "github.com/sclevine/agouti/matchers" "github.com/sclevine/agouti" + . "github.com/sclevine/agouti/matchers" + + {{if .DotImportPackage}}. "{{.PackageImportPath}}"{{end}} ) var _ = Describe("{{.Subject}}", func() { diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot_test.go b/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot_test.go index 37260a89..1470b747 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot_test.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot_test.go @@ -1,8 +1,9 @@ package nodot_test import ( - . "github.com/onsi/ginkgo/ginkgo/nodot" "strings" + + . "github.com/onsi/ginkgo/ginkgo/nodot" ) var _ = Describe("ApplyNoDot", func() { diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/nodot_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/nodot_command.go index 212235ba..39b88b5d 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/nodot_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/nodot_command.go @@ -3,11 +3,12 @@ package main import ( "bufio" "flag" - "github.com/onsi/ginkgo/ginkgo/nodot" "io/ioutil" "os" "path/filepath" "regexp" + + "github.com/onsi/ginkgo/ginkgo/nodot" ) func BuildNodotCommand() *Command { diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go index d1483f60..569b6a29 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/run_command.go @@ -5,8 +5,12 @@ import ( "fmt" "math/rand" "os" + "strings" "time" + "io/ioutil" + "path/filepath" + "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/ginkgo/interrupthandler" "github.com/onsi/ginkgo/ginkgo/testrunner" @@ -104,10 +108,25 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { runner.CleanUp() } + if r.isInCoverageMode() { + if r.getOutputDir() != "" { + // If coverprofile is set, combine coverages + if r.getCoverprofile() != "" { + if err := r.combineCoverprofiles(runners); err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + } else { + // Just move them + r.moveCoverprofiles(runners) + } + } + } + fmt.Printf("\nGinkgo ran %d %s in %s\n", numSuites, pluralizedWord("suite", "suites", numSuites), time.Since(t)) if runResult.Passed { - if runResult.HasProgrammaticFocus { + if runResult.HasProgrammaticFocus && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { fmt.Printf("Test Suite Passed\n") fmt.Printf("Detected Programmatic Focus - setting exit status to %d\n", types.GINKGO_FOCUS_EXIT_CODE) os.Exit(types.GINKGO_FOCUS_EXIT_CODE) @@ -121,6 +140,70 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { } } +// Moves all generated profiles to specified directory +func (r *SpecRunner) moveCoverprofiles(runners []*testrunner.TestRunner) { + for _, runner := range runners { + _, filename := filepath.Split(runner.CoverageFile) + err := os.Rename(runner.CoverageFile, filepath.Join(r.getOutputDir(), filename)) + + if err != nil { + fmt.Printf("Unable to move coverprofile %s, %v\n", runner.CoverageFile, err) + return + } + } +} + +// Combines all generated profiles in the specified directory +func (r *SpecRunner) combineCoverprofiles(runners []*testrunner.TestRunner) error { + + path, _ := filepath.Abs(r.getOutputDir()) + if !fileExists(path) { + return fmt.Errorf("Unable to create combined profile, outputdir does not exist: %s", r.getOutputDir()) + } + + fmt.Println("path is " + path) + + combined, err := os.OpenFile(filepath.Join(path, r.getCoverprofile()), + os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666) + + if err != nil { + fmt.Printf("Unable to create combined profile, %v\n", err) + return nil // non-fatal error + } + + for _, runner := range runners { + contents, err := ioutil.ReadFile(runner.CoverageFile) + + if err != nil { + fmt.Printf("Unable to read coverage file %s to combine, %v\n", runner.CoverageFile, err) + return nil // non-fatal error + } + + _, err = combined.Write(contents) + + if err != nil { + fmt.Printf("Unable to append to coverprofile, %v\n", err) + return nil // non-fatal error + } + } + + fmt.Println("All profiles combined") + return nil +} + +func (r *SpecRunner) isInCoverageMode() bool { + opts := r.commandFlags.GoOpts + return *opts["cover"].(*bool) || *opts["coverpkg"].(*string) != "" || *opts["covermode"].(*string) != "" +} + +func (r *SpecRunner) getCoverprofile() string { + return *r.commandFlags.GoOpts["coverprofile"].(*string) +} + +func (r *SpecRunner) getOutputDir() string { + return *r.commandFlags.GoOpts["outputdir"].(*string) +} + func (r *SpecRunner) ComputeSuccinctMode(numSuites int) { if config.DefaultReporterConfig.Verbose { config.DefaultReporterConfig.Succinct = false diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go b/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go index f0a591b9..97a83145 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/testrunner/test_runner.go @@ -17,6 +17,7 @@ import ( "github.com/onsi/ginkgo/ginkgo/testsuite" "github.com/onsi/ginkgo/internal/remote" "github.com/onsi/ginkgo/reporters/stenographer" + colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" "github.com/onsi/ginkgo/types" ) @@ -32,6 +33,8 @@ type TestRunner struct { goOpts map[string]interface{} additionalArgs []string stderr *bytes.Buffer + + CoverageFile string } func New(suite testsuite.TestSuite, numCPU int, parallelStream bool, timeout time.Duration, goOpts map[string]interface{}, additionalArgs []string) *TestRunner { @@ -63,10 +66,10 @@ func (t *TestRunner) Compile() error { func (t *TestRunner) BuildArgs(path string) []string { args := []string{"test", "-c", "-i", "-o", path, t.Suite.Path} - if *t.goOpts["covermode"].(*string) != "" { - args = append(args, "-cover", fmt.Sprintf("-covermode=%s", *t.goOpts["covermode"].(*string))) + if t.getCoverMode() != "" { + args = append(args, "-cover", fmt.Sprintf("-covermode=%s", t.getCoverMode())) } else { - if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" { + if t.shouldCover() || t.getCoverPackage() != "" { args = append(args, "-cover", "-covermode=atomic") } } @@ -298,7 +301,7 @@ func (t *TestRunner) runAndStreamParallelGinkgoSuite() RunResult { os.Stdout.Sync() - if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" { + if t.shouldCombineCoverprofiles() { t.combineCoverprofiles() } @@ -311,7 +314,7 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult { writers := make([]*logWriter, t.numCPU) reports := make([]*bytes.Buffer, t.numCPU) - stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1) + stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1, colorable.NewColorableStdout()) aggregator := remote.NewAggregator(t.numCPU, result, config.DefaultReporterConfig, stenographer) server, err := remote.NewServer(t.numCPU) @@ -364,9 +367,8 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult { | | | Ginkgo timed out waiting for all parallel nodes to report back! | | | - ------------------------------------------------------------------- -`) - fmt.Println(t.Suite.PackageName, "timed out. path:", t.Suite.Path) + -------------------------------------------------------------------`) + fmt.Println("\n", t.Suite.PackageName, "timed out. path:", t.Suite.Path) os.Stdout.Sync() for _, writer := range writers { @@ -380,21 +382,40 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult { os.Stdout.Sync() } - if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" { + if t.shouldCombineCoverprofiles() { t.combineCoverprofiles() } return res } +const CoverProfileSuffix = ".coverprofile" + func (t *TestRunner) cmd(ginkgoArgs []string, stream io.Writer, node int) *exec.Cmd { args := []string{"--test.timeout=" + t.timeout.String()} - if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" { - coverprofile := "--test.coverprofile=" + t.Suite.PackageName + ".coverprofile" - if t.numCPU > 1 { - coverprofile = fmt.Sprintf("%s.%d", coverprofile, node) + + coverProfile := t.getCoverProfile() + + if t.shouldCombineCoverprofiles() { + + testCoverProfile := "--test.coverprofile=" + + coverageFile := "" + // Set default name for coverage results + if coverProfile == "" { + coverageFile = t.Suite.PackageName + CoverProfileSuffix + } else { + coverageFile = coverProfile } - args = append(args, coverprofile) + + testCoverProfile += coverageFile + + t.CoverageFile = filepath.Join(t.Suite.Path, coverageFile) + + if t.numCPU > 1 { + testCoverProfile = fmt.Sprintf("%s.%d", testCoverProfile, node) + } + args = append(args, testCoverProfile) } args = append(args, ginkgoArgs...) @@ -414,6 +435,30 @@ func (t *TestRunner) cmd(ginkgoArgs []string, stream io.Writer, node int) *exec. return cmd } +func (t *TestRunner) shouldCover() bool { + return *t.goOpts["cover"].(*bool) +} + +func (t *TestRunner) shouldRequireSuite() bool { + return *t.goOpts["requireSuite"].(*bool) +} + +func (t *TestRunner) getCoverProfile() string { + return *t.goOpts["coverprofile"].(*string) +} + +func (t *TestRunner) getCoverPackage() string { + return *t.goOpts["coverpkg"].(*string) +} + +func (t *TestRunner) getCoverMode() string { + return *t.goOpts["covermode"].(*string) +} + +func (t *TestRunner) shouldCombineCoverprofiles() bool { + return t.shouldCover() || t.getCoverPackage() != "" || t.getCoverMode() != "" +} + func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult { var res RunResult @@ -436,7 +481,7 @@ func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult { res.HasProgrammaticFocus = (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) if strings.Contains(t.stderr.String(), "warning: no tests to run") { - if *t.goOpts["requireSuite"].(*bool) { + if t.shouldRequireSuite() { res.Passed = false } fmt.Fprintf(os.Stderr, `Found no test suites, did you forget to run "ginkgo bootstrap"?`) @@ -447,8 +492,17 @@ func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult { func (t *TestRunner) combineCoverprofiles() { profiles := []string{} + + coverProfile := t.getCoverProfile() + for cpu := 1; cpu <= t.numCPU; cpu++ { - coverFile := fmt.Sprintf("%s.coverprofile.%d", t.Suite.PackageName, cpu) + var coverFile string + if coverProfile == "" { + coverFile = fmt.Sprintf("%s%s.%d", t.Suite.PackageName, CoverProfileSuffix, cpu) + } else { + coverFile = fmt.Sprintf("%s.%d", coverProfile, cpu) + } + coverFile = filepath.Join(t.Suite.Path, coverFile) coverProfile, err := ioutil.ReadFile(coverFile) os.Remove(coverFile) @@ -484,5 +538,17 @@ func (t *TestRunner) combineCoverprofiles() { output = append(output, fmt.Sprintf("%s %d", line, lines[line])) } finalOutput := strings.Join(output, "\n") - ioutil.WriteFile(filepath.Join(t.Suite.Path, fmt.Sprintf("%s.coverprofile", t.Suite.PackageName)), []byte(finalOutput), 0666) + + finalFilename := "" + + if coverProfile != "" { + finalFilename = coverProfile + } else { + finalFilename = fmt.Sprintf("%s%s", t.Suite.PackageName, CoverProfileSuffix) + } + + coverageFilepath := filepath.Join(t.Suite.Path, finalFilename) + ioutil.WriteFile(coverageFilepath, []byte(finalOutput), 0666) + + t.CoverageFile = coverageFilepath } diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/test_suite.go b/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/test_suite.go index 09b16015..9de8c2bb 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/test_suite.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/test_suite.go @@ -53,7 +53,7 @@ func SuitesInDir(dir string, recurse bool) []TestSuite { } files, _ := ioutil.ReadDir(dir) - re := regexp.MustCompile(`_test\.go$`) + re := regexp.MustCompile(`^[^._].*_test\.go$`) for _, file := range files { if !file.IsDir() && re.Match([]byte(file.Name())) { suites = append(suites, New(dir, files)) diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/testsuite_test.go b/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/testsuite_test.go index 7f89f18a..7a0753bf 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/testsuite_test.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/testsuite/testsuite_test.go @@ -51,6 +51,10 @@ var _ = Describe("TestSuite", func() { //non-go files in a nested directory writeFile("/redherring", "big_test.jpg", "package ginkgo", 0666) + //ginkgo tests in ignored go files + writeFile("/ignored", ".ignore_dot_test.go", `import "github.com/onsi/ginkgo"`, 0666) + writeFile("/ignored", "_ignore_underscore_test.go", `import "github.com/onsi/ginkgo"`, 0666) + //non-ginkgo tests in a nested directory writeFile("/professorplum", "professorplum_test.go", `import "testing"`, 0666) @@ -140,6 +144,13 @@ var _ = Describe("TestSuite", func() { }) }) + Context("when there are ginkgo tests that are ignored by go in the specified directory ", func() { + It("should come up empty", func() { + suites := SuitesInDir(filepath.Join(tmpDir, "ignored"), false) + Ω(suites).Should(BeEmpty()) + }) + }) + Context("when there are non-ginkgo tests in the specified directory", func() { It("should return an appropriately configured suite", func() { suites := SuitesInDir(filepath.Join(tmpDir, "professorplum"), false) diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/unfocus_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/unfocus_command.go index 683c3a99..cedc2b59 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/unfocus_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/unfocus_command.go @@ -3,7 +3,9 @@ package main import ( "flag" "fmt" + "io/ioutil" "os/exec" + "strings" ) func BuildUnfocusCommand() *Command { @@ -26,13 +28,34 @@ func unfocusSpecs([]string, []string) { unfocus("Measure") unfocus("DescribeTable") unfocus("Entry") + unfocus("Specify") + unfocus("When") } func unfocus(component string) { fmt.Printf("Removing F%s...\n", component) - cmd := exec.Command("gofmt", fmt.Sprintf("-r=F%s -> %s", component, component), "-w", ".") - out, _ := cmd.CombinedOutput() - if string(out) != "" { - println(string(out)) + files, err := ioutil.ReadDir(".") + if err != nil { + fmt.Println(err.Error()) + return + } + for _, f := range files { + // Exclude "vendor" directory + if f.IsDir() && f.Name() == "vendor" { + continue + } + // Exclude non-go files in the current directory + if !f.IsDir() && !strings.HasSuffix(f.Name(), ".go") { + continue + } + // Recursively run `gofmt` otherwise + cmd := exec.Command("gofmt", fmt.Sprintf("-r=F%s -> %s", component, component), "-w", f.Name()) + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Println(err.Error()) + } + if string(out) != "" { + fmt.Println(string(out)) + } } } diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/version_command.go b/vendor/github.com/onsi/ginkgo/ginkgo/version_command.go index cdca3a34..f586908e 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo/version_command.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo/version_command.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "github.com/onsi/ginkgo/config" ) diff --git a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go index 8fe0b70a..158acdd5 100644 --- a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go +++ b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go @@ -29,6 +29,7 @@ import ( "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/reporters/stenographer" + colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" "github.com/onsi/ginkgo/types" ) @@ -149,7 +150,8 @@ type GinkgoTestDescription struct { FileName string LineNumber int - Failed bool + Failed bool + Duration time.Duration } //CurrentGinkgoTestDescripton returns information about the current running test. @@ -169,6 +171,7 @@ func CurrentGinkgoTestDescription() GinkgoTestDescription { FileName: subjectCodeLocation.FileName, LineNumber: subjectCodeLocation.LineNumber, Failed: summary.HasFailureState(), + Duration: summary.RunTime, } } @@ -202,7 +205,7 @@ func RunSpecs(t GinkgoTestingT, description string) bool { //To run your tests with Ginkgo's default reporter and your custom reporter(s), replace //RunSpecs() with this method. func RunSpecsWithDefaultAndCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool { - specReporters = append([]Reporter{buildDefaultReporter()}, specReporters...) + specReporters = append(specReporters, buildDefaultReporter()) return RunSpecsWithCustomReporters(t, description, specReporters) } @@ -216,7 +219,7 @@ func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specRepor reporters[i] = reporter } passed, hasFocusedTests := globalSuite.Run(t, description, reporters, writer, config.GinkgoConfig) - if passed && hasFocusedTests { + if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { fmt.Println("PASS | FOCUSED") os.Exit(types.GINKGO_FOCUS_EXIT_CODE) } @@ -226,14 +229,18 @@ func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specRepor func buildDefaultReporter() Reporter { remoteReportingServer := config.GinkgoConfig.StreamHost if remoteReportingServer == "" { - stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1) + stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1, colorable.NewColorableStdout()) return reporters.NewDefaultReporter(config.DefaultReporterConfig, stenographer) } else { - return remote.NewForwardingReporter(remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor()) + debugFile := "" + if config.GinkgoConfig.DebugParallel { + debugFile = fmt.Sprintf("ginkgo-node-%d.log", config.GinkgoConfig.ParallelNode) + } + return remote.NewForwardingReporter(config.DefaultReporterConfig, remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor(), GinkgoWriter.(*writer.Writer), debugFile) } } -//Skip notifies Ginkgo that the current spec should be skipped. +//Skip notifies Ginkgo that the current spec was skipped. func Skip(message string, callerSkip ...int) { skip := 0 if len(callerSkip) > 0 { @@ -275,9 +282,9 @@ func GinkgoRecover() { //Describe blocks allow you to organize your specs. A Describe block can contain any number of //BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks. // -//In addition you can nest Describe and Context blocks. Describe and Context blocks are functionally +//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally //equivalent. The difference is purely semantic -- you typical Describe the behavior of an object -//or method and, within that Describe, outline a number of Contexts. +//or method and, within that Describe, outline a number of Contexts and Whens. func Describe(text string, body func()) bool { globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1)) return true @@ -304,9 +311,9 @@ func XDescribe(text string, body func()) bool { //Context blocks allow you to organize your specs. A Context block can contain any number of //BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks. // -//In addition you can nest Describe and Context blocks. Describe and Context blocks are functionally +//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally //equivalent. The difference is purely semantic -- you typical Describe the behavior of an object -//or method and, within that Describe, outline a number of Contexts. +//or method and, within that Describe, outline a number of Contexts and Whens. func Context(text string, body func()) bool { globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1)) return true @@ -330,6 +337,35 @@ func XContext(text string, body func()) bool { return true } +//When blocks allow you to organize your specs. A When block can contain any number of +//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks. +// +//In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally +//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object +//or method and, within that Describe, outline a number of Contexts and Whens. +func When(text string, body func()) bool { + globalSuite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1)) + return true +} + +//You can focus the tests within a describe block using FWhen +func FWhen(text string, body func()) bool { + globalSuite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1)) + return true +} + +//You can mark the tests within a describe block as pending using PWhen +func PWhen(text string, body func()) bool { + globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1)) + return true +} + +//You can mark the tests within a describe block as pending using XWhen +func XWhen(text string, body func()) bool { + globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1)) + return true +} + //It blocks contain your test code and assertions. You cannot nest any other Ginkgo blocks //within an It block. // @@ -362,22 +398,26 @@ func XIt(text string, _ ...interface{}) bool { //which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks //which apply to It blocks. func Specify(text string, body interface{}, timeout ...float64) bool { - return It(text, body, timeout...) + globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...)) + return true } //You can focus individual Specifys using FSpecify func FSpecify(text string, body interface{}, timeout ...float64) bool { - return FIt(text, body, timeout...) + globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...)) + return true } //You can mark Specifys as pending using PSpecify func PSpecify(text string, is ...interface{}) bool { - return PIt(text, is...) + globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0) + return true } //You can mark Specifys as pending using XSpecify func XSpecify(text string, is ...interface{}) bool { - return XIt(text, is...) + globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0) + return true } //By allows you to better document large Its. diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage.go new file mode 100644 index 00000000..10c1c1bd --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage.go @@ -0,0 +1,21 @@ +package first_package + +func A() string { + return "A" +} + +func B() string { + return "B" +} + +func C() string { + return "C" +} + +func D() string { + return "D" +} + +func E() string { + return "untested" +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_suite_test.go new file mode 100644 index 00000000..4e0976cd --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_suite_test.go @@ -0,0 +1,13 @@ +package first_package_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCoverageFixture(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "CombinedFixture First Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_test.go new file mode 100644 index 00000000..dfe3e112 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_test.go @@ -0,0 +1,31 @@ +package first_package_test + +import ( + . "github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package" + . "github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/external_coverage_fixture" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("CoverageFixture", func() { + It("should test A", func() { + Ω(A()).Should(Equal("A")) + }) + + It("should test B", func() { + Ω(B()).Should(Equal("B")) + }) + + It("should test C", func() { + Ω(C()).Should(Equal("C")) + }) + + It("should test D", func() { + Ω(D()).Should(Equal("D")) + }) + + It("should test external package", func() { + Ω(Tested()).Should(Equal("tested")) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/external_coverage_fixture/external_coverage.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/external_coverage_fixture/external_coverage.go new file mode 100644 index 00000000..5280d4dd --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/external_coverage_fixture/external_coverage.go @@ -0,0 +1,9 @@ +package external_coverage + +func Tested() string { + return "tested" +} + +func Untested() string { + return "untested" +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage.go new file mode 100644 index 00000000..52160989 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage.go @@ -0,0 +1,21 @@ +package second_package + +func A() string { + return "A" +} + +func B() string { + return "B" +} + +func C() string { + return "C" +} + +func D() string { + return "D" +} + +func E() string { + return "E" +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage_fixture_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage_fixture_suite_test.go new file mode 100644 index 00000000..583a0af2 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage_fixture_suite_test.go @@ -0,0 +1,13 @@ +package second_package_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCoverageFixture(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "CombinedFixture Second Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage_fixture_test.go new file mode 100644 index 00000000..2692bec9 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package/coverage_fixture_test.go @@ -0,0 +1,29 @@ +package second_package_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package" + . "github.com/onsi/gomega" +) + +var _ = Describe("CoverageFixture", func() { + It("should test A", func() { + Ω(A()).Should(Equal("A")) + }) + + It("should test B", func() { + Ω(B()).Should(Equal("B")) + }) + + It("should test C", func() { + Ω(C()).Should(Equal("C")) + }) + + It("should test D", func() { + Ω(D()).Should(Equal("D")) + }) + + It("should test E", func() { + Ω(E()).Should(Equal("E")) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/nested_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/nested_suite_test.go index d3d35e81..721d0f2c 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/nested_suite_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/nested_suite_test.go @@ -1,10 +1,10 @@ package nested_test import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - - "testing" ) func TestNested(t *testing.T) { diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/suite_test.go index fd69d333..9ea22913 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/suite_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/convert_goldmasters/suite_test.go @@ -1,10 +1,10 @@ package tmp_test import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - - "testing" ) func TestConvertFixtures(t *testing.T) { diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/coverage.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/coverage.go index 436e21d1..e4d7e43b 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/coverage.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/coverage.go @@ -1,5 +1,9 @@ package coverage_fixture +import ( + _ "github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture" +) + func A() string { return "A" } diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_suite_test.go new file mode 100644 index 00000000..429aebc5 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_suite_test.go @@ -0,0 +1,13 @@ +package debug_parallel_fixture_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestDebugParallelFixture(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "DebugParallelFixture Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_test.go new file mode 100644 index 00000000..b609a8bc --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_test.go @@ -0,0 +1,18 @@ +package debug_parallel_fixture_test + +import ( + "fmt" + "time" + + . "github.com/onsi/ginkgo" +) + +var _ = Describe("DebugParallelFixture", func() { + It("emits output to a file", func() { + for i := 0; i < 10; i += 1 { + fmt.Printf("StdOut %d\n", i) + GinkgoWriter.Write([]byte(fmt.Sprintf("GinkgoWriter %d\n", i))) + } + time.Sleep(time.Second) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/fail_fixture/fail_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/fail_fixture/fail_fixture_test.go index 801acf13..ea6f71ca 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/fail_fixture/fail_fixture_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/fail_fixture/fail_fixture_test.go @@ -97,3 +97,7 @@ var _ = Describe("Excercising different failure modes", func() { println("NEVER SEE THIS") }, 1) }) + +var _ = Specify("a top level specify", func() { + Fail("fail the test") +}) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/flags_tests/flags_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/flags_tests/flags_test.go index 5cd9b72f..27dadf19 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/flags_tests/flags_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/flags_tests/flags_test.go @@ -3,11 +3,13 @@ package flags_test import ( "flag" "fmt" + remapped "math" + _ "math/cmplx" + "time" + . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/flags_tests" . "github.com/onsi/gomega" - "time" - remapped "math" ) var customFlag string diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/README.md b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/README.md new file mode 100644 index 00000000..2b501a25 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/README.md @@ -0,0 +1 @@ +This file should remain the same, regardless the fact that contains FIt, FDescribe, or FWhen. diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/focused_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/focused_fixture_test.go index 16ad16de..ea500eaf 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/focused_fixture_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture/focused_fixture_test.go @@ -18,10 +18,20 @@ var _ = Describe("FocusedFixture", func() { }) }) + FWhen("focused", func() { + It("focused", func() { + + }) + }) + FIt("focused", func() { }) + FSpecify("focused", func() { + + }) + FMeasure("focused", func(b Benchmarker) { }, 2) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_suite_test.go new file mode 100644 index 00000000..92d0c6e4 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_suite_test.go @@ -0,0 +1,13 @@ +package focused_fixture_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestFocused_fixture(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Focused_fixture Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_test.go new file mode 100644 index 00000000..ea500eaf --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_test.go @@ -0,0 +1,73 @@ +package focused_fixture_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" +) + +var _ = Describe("FocusedFixture", func() { + FDescribe("focused", func() { + It("focused", func() { + + }) + }) + + FContext("focused", func() { + It("focused", func() { + + }) + }) + + FWhen("focused", func() { + It("focused", func() { + + }) + }) + + FIt("focused", func() { + + }) + + FSpecify("focused", func() { + + }) + + FMeasure("focused", func(b Benchmarker) { + + }, 2) + + FDescribeTable("focused", + func() {}, + Entry("focused"), + ) + + DescribeTable("focused", + func() {}, + FEntry("focused"), + ) + + Describe("not focused", func() { + It("not focused", func() { + + }) + }) + + Context("not focused", func() { + It("not focused", func() { + + }) + }) + + It("not focused", func() { + + }) + + Measure("not focused", func(b Benchmarker) { + + }, 2) + + DescribeTable("not focused", + func() {}, + Entry("not focused"), + ) +}) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/hanging_suite/hanging_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/hanging_suite/hanging_suite_test.go index 1728dcbe..6a5a070e 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/hanging_suite/hanging_suite_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/hanging_suite/hanging_suite_test.go @@ -3,6 +3,7 @@ package hanging_suite_test import ( "fmt" "time" + . "github.com/onsi/ginkgo" ) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/progress_fixture/progress_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/progress_fixture/progress_fixture_test.go index 1e0aa795..b7f26c25 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/progress_fixture/progress_fixture_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/progress_fixture/progress_fixture_test.go @@ -32,8 +32,18 @@ var _ = Describe("ProgressFixture", func() { fmt.Fprintln(GinkgoWriter, ">inner after<") }) - It("should emit progress as it goes", func() { - fmt.Fprintln(GinkgoWriter, ">it<") + When("Inner When", func() { + BeforeEach(func() { + fmt.Fprintln(GinkgoWriter, ">inner before<") + }) + + It("should emit progress as it goes", func() { + fmt.Fprintln(GinkgoWriter, ">it<") + }) }) }) + + Specify("should emit progress as it goes", func() { + fmt.Fprintln(GinkgoWriter, ">specify<") + }) }) diff --git a/vendor/github.com/onsi/ginkgo/integration/_fixtures/skip_fixture/skip_fixture_test.go b/vendor/github.com/onsi/ginkgo/integration/_fixtures/skip_fixture/skip_fixture_test.go index 72aeb8f4..e406aeb4 100644 --- a/vendor/github.com/onsi/ginkgo/integration/_fixtures/skip_fixture/skip_fixture_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/_fixtures/skip_fixture/skip_fixture_test.go @@ -48,7 +48,6 @@ var _ = Describe("Excercising different skip modes", func() { }, 1) }) - var _ = Describe("SKIP in a BeforeEach", func() { BeforeEach(func() { Skip("a BeforeEach SKIP") @@ -69,4 +68,4 @@ var _ = Describe("SKIP in an AfterEach", func() { It("a SKIP AfterEach", func() { Expect(true).To(BeTrue()) }) -}) \ No newline at end of file +}) diff --git a/vendor/github.com/onsi/ginkgo/integration/coverage_test.go b/vendor/github.com/onsi/ginkgo/integration/coverage_test.go index 6b987a3b..a1d24bfe 100644 --- a/vendor/github.com/onsi/ginkgo/integration/coverage_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/coverage_test.go @@ -1,53 +1,147 @@ package integration_test import ( - "os" "os/exec" + "fmt" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("Coverage Specs", func() { - AfterEach(func() { - os.RemoveAll("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") + Context("when it runs coverage analysis in series and in parallel", func() { + AfterEach(func() { + removeSuccessfully("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") + }) + It("works", func() { + session := startGinkgo("./_fixtures/coverage_fixture", "-cover") + Eventually(session).Should(gexec.Exit(0)) + + Ω(session.Out).Should(gbytes.Say(("coverage: 80.0% of statements"))) + + coverFile := "./_fixtures/coverage_fixture/coverage_fixture.coverprofile" + serialCoverProfileOutput, err := exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() + Ω(err).ShouldNot(HaveOccurred()) + + removeSuccessfully(coverFile) + + Eventually(startGinkgo("./_fixtures/coverage_fixture", "-cover", "-nodes=4")).Should(gexec.Exit(0)) + + parallelCoverProfileOutput, err := exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() + Ω(err).ShouldNot(HaveOccurred()) + + Ω(parallelCoverProfileOutput).Should(Equal(serialCoverProfileOutput)) + + By("handling external packages", func() { + session = startGinkgo("./_fixtures/coverage_fixture", "-coverpkg=github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture,github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture") + Eventually(session).Should(gexec.Exit(0)) + + Ω(session.Out).Should(gbytes.Say("coverage: 71.4% of statements in github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture, github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture")) + + serialCoverProfileOutput, err = exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() + Ω(err).ShouldNot(HaveOccurred()) + + removeSuccessfully("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") + + Eventually(startGinkgo("./_fixtures/coverage_fixture", "-coverpkg=github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture,github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture", "-nodes=4")).Should(gexec.Exit(0)) + + parallelCoverProfileOutput, err = exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() + Ω(err).ShouldNot(HaveOccurred()) + + Ω(parallelCoverProfileOutput).Should(Equal(serialCoverProfileOutput)) + }) + }) }) - It("runs coverage analysis in series and in parallel", func() { - session := startGinkgo("./_fixtures/coverage_fixture", "-cover") - Eventually(session).Should(gexec.Exit(0)) + Context("when a custom profile name is specified", func() { + AfterEach(func() { + removeSuccessfully("./_fixtures/coverage_fixture/coverage.txt") + }) + + It("generates cover profiles with the specified name", func() { + session := startGinkgo("./_fixtures/coverage_fixture", "-cover", "-coverprofile=coverage.txt") + Eventually(session).Should(gexec.Exit(0)) + + Ω("./_fixtures/coverage_fixture/coverage.txt").Should(BeARegularFile()) + }) + }) + + Context("when run in recursive mode", func() { + AfterEach(func() { + removeSuccessfully("./_fixtures/combined_coverage_fixture/coverage-recursive.txt") + removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package/coverage-recursive.txt") + removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package/coverage-recursive.txt") + }) + + It("generates a coverage file per package", func() { + session := startGinkgo("./_fixtures/combined_coverage_fixture", "-r", "-cover", "-coverprofile=coverage-recursive.txt") + Eventually(session).Should(gexec.Exit(0)) + + Ω("./_fixtures/combined_coverage_fixture/first_package/coverage-recursive.txt").Should(BeARegularFile()) + Ω("./_fixtures/combined_coverage_fixture/second_package/coverage-recursive.txt").Should(BeARegularFile()) + }) + }) + + Context("when run in parallel mode", func() { + AfterEach(func() { + removeSuccessfully("./_fixtures/coverage_fixture/coverage-parallel.txt") + }) + + It("works", func() { + session := startGinkgo("./_fixtures/coverage_fixture", "-p", "-cover", "-coverprofile=coverage-parallel.txt") + + Eventually(session).Should(gexec.Exit(0)) + + Ω("./_fixtures/coverage_fixture/coverage-parallel.txt").Should(BeARegularFile()) + }) + }) + + Context("when run in recursive mode specifying a coverprofile", func() { + AfterEach(func() { + removeSuccessfully("./_fixtures/combined_coverage_fixture/coverprofile-recursive.txt") + removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package/coverprofile-recursive.txt") + removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package/coverprofile-recursive.txt") + }) + + It("combines the coverages", func() { + session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./", "-r", "-cover", "-coverprofile=coverprofile-recursive.txt") + Eventually(session).Should(gexec.Exit(0)) + + By("generating a combined coverage file", func() { + Ω("./_fixtures/combined_coverage_fixture/coverprofile-recursive.txt").Should(BeARegularFile()) + }) + + By("also generating the single package coverage files", func() { + Ω("./_fixtures/combined_coverage_fixture/first_package/coverprofile-recursive.txt").Should(BeARegularFile()) + Ω("./_fixtures/combined_coverage_fixture/second_package/coverprofile-recursive.txt").Should(BeARegularFile()) + }) + }) + }) + + It("Fails with an error if output dir and coverprofile were set, but the output dir did not exist", func() { + session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./all/profiles/here", "-r", "-cover", "-coverprofile=coverage.txt") + + Eventually(session).Should(gexec.Exit(1)) output := session.Out.Contents() - Ω(output).Should(ContainSubstring("coverage: 80.0% of statements")) + Ω(string(output)).Should(ContainSubstring("Unable to create combined profile, outputdir does not exist: ./all/profiles/here")) + }) - serialCoverProfileOutput, err := exec.Command("go", "tool", "cover", "-func=./_fixtures/coverage_fixture/coverage_fixture.coverprofile").CombinedOutput() - Ω(err).ShouldNot(HaveOccurred()) + Context("when only output dir was set", func() { + AfterEach(func() { + removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package.coverprofile") + removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package/coverage.txt") + removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package.coverprofile") + removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package/coverage.txt") + }) + It("moves coverages", func() { + session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./", "-r", "-cover") + Eventually(session).Should(gexec.Exit(0)) - os.RemoveAll("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") - - Eventually(startGinkgo("./_fixtures/coverage_fixture", "-cover", "-nodes=4")).Should(gexec.Exit(0)) - - parallelCoverProfileOutput, err := exec.Command("go", "tool", "cover", "-func=./_fixtures/coverage_fixture/coverage_fixture.coverprofile").CombinedOutput() - Ω(err).ShouldNot(HaveOccurred()) - - Ω(parallelCoverProfileOutput).Should(Equal(serialCoverProfileOutput)) - - By("handling external packages") - session = startGinkgo("./_fixtures/coverage_fixture", "-coverpkg=github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture,github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture") - Eventually(session).Should(gexec.Exit(0)) - output = session.Out.Contents() - Ω(output).Should(ContainSubstring("coverage: 71.4% of statements in github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture, github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture")) - - serialCoverProfileOutput, err = exec.Command("go", "tool", "cover", "-func=./_fixtures/coverage_fixture/coverage_fixture.coverprofile").CombinedOutput() - Ω(err).ShouldNot(HaveOccurred()) - - os.RemoveAll("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") - - Eventually(startGinkgo("./_fixtures/coverage_fixture", "-coverpkg=github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture,github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture", "-nodes=4")).Should(gexec.Exit(0)) - - parallelCoverProfileOutput, err = exec.Command("go", "tool", "cover", "-func=./_fixtures/coverage_fixture/coverage_fixture.coverprofile").CombinedOutput() - Ω(err).ShouldNot(HaveOccurred()) - - Ω(parallelCoverProfileOutput).Should(Equal(serialCoverProfileOutput)) + Ω("./_fixtures/combined_coverage_fixture/first_package.coverprofile").Should(BeARegularFile()) + Ω("./_fixtures/combined_coverage_fixture/second_package.coverprofile").Should(BeARegularFile()) + }) }) }) diff --git a/vendor/github.com/onsi/ginkgo/integration/fail_test.go b/vendor/github.com/onsi/ginkgo/integration/fail_test.go index 8dcf5e4a..53b2a67b 100644 --- a/vendor/github.com/onsi/ginkgo/integration/fail_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/fail_test.go @@ -11,7 +11,7 @@ var _ = Describe("Failing Specs", func() { BeforeEach(func() { pathToTest = tmpPath("failing") - copyIn("fail_fixture", pathToTest) + copyIn(fixturePath("fail_fixture"), pathToTest, false) }) It("should fail in all the possible ways", func() { @@ -43,6 +43,13 @@ var _ = Describe("Failing Specs", func() { Ω(output).Should(ContainSubstring("a measure FAIL failure")) Ω(output).Should(MatchRegexp(`Test Panicked\n\s+a measure panic`)) - Ω(output).Should(ContainSubstring("0 Passed | 16 Failed")) + Ω(output).Should(ContainSubstring("a top level specify")) + Ω(output).ShouldNot(ContainSubstring("ginkgo_dsl.go")) + // depending on the go version this could be the first line of the Specify + // block (>= go1.9) or the last line of the Specify block (< go1.9) + Ω(output).Should(Or(ContainSubstring("fail_fixture_test.go:101"), ContainSubstring("fail_fixture_test.go:103"))) + Ω(output).Should(ContainSubstring("fail_fixture_test.go:102")) + + Ω(output).Should(ContainSubstring("0 Passed | 17 Failed")) }) }) diff --git a/vendor/github.com/onsi/ginkgo/integration/flags_test.go b/vendor/github.com/onsi/ginkgo/integration/flags_test.go index e34102d9..d84eb46c 100644 --- a/vendor/github.com/onsi/ginkgo/integration/flags_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/flags_test.go @@ -17,7 +17,7 @@ var _ = Describe("Flags Specs", func() { BeforeEach(func() { pathToTest = tmpPath("flags") - copyIn("flags_tests", pathToTest) + copyIn(fixturePath("flags_tests"), pathToTest, false) }) getRandomOrders := func(output string) []int { @@ -158,13 +158,13 @@ var _ = Describe("Flags Specs", func() { It("should fail fast when told to", func() { pathToTest = tmpPath("fail") - copyIn("fail_fixture", pathToTest) + copyIn(fixturePath("fail_fixture"), pathToTest, false) session := startGinkgo(pathToTest, "--failFast") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("1 Failed")) - Ω(output).Should(ContainSubstring("15 Skipped")) + Ω(output).Should(ContainSubstring("16 Skipped")) }) Context("with a flaky test", func() { @@ -181,20 +181,20 @@ var _ = Describe("Flags Specs", func() { It("should perform a dry run when told to", func() { pathToTest = tmpPath("fail") - copyIn("fail_fixture", pathToTest) + copyIn(fixturePath("fail_fixture"), pathToTest, false) session := startGinkgo(pathToTest, "--dryRun", "-v") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("synchronous failures")) - Ω(output).Should(ContainSubstring("16 Specs")) + Ω(output).Should(ContainSubstring("17 Specs")) Ω(output).Should(ContainSubstring("0 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) }) regextest := func(regexOption string, skipOrFocus string) string { pathToTest = tmpPath("passing") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) session := startGinkgo(pathToTest, regexOption, "--dryRun", "-v", skipOrFocus) Eventually(session).Should(gexec.Exit(0)) return string(session.Out.Contents()) @@ -213,6 +213,7 @@ var _ = Describe("Flags Specs", func() { output = regextest("-regexScansFilePath=false", "-focus=/passing/") // nothing gets focused (nothing runs) Ω(output).Should(ContainSubstring("0 of 4 Specs")) }) + It("should honor compiler flags", func() { session := startGinkgo(pathToTest, "-gcflags=-importmap 'math=math/cmplx'") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) diff --git a/vendor/github.com/onsi/ginkgo/integration/integration_suite_test.go b/vendor/github.com/onsi/ginkgo/integration/integration_suite_test.go index 5cf9546d..32ec741c 100644 --- a/vendor/github.com/onsi/ginkgo/integration/integration_suite_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/integration_suite_test.go @@ -19,7 +19,7 @@ var tmpDir string var pathToGinkgo string func TestIntegration(t *testing.T) { - SetDefaultEventuallyTimeout(15 * time.Second) + SetDefaultEventuallyTimeout(30 * time.Second) RegisterFailHandler(Fail) RunSpecs(t, "Integration Suite") } @@ -51,29 +51,62 @@ func tmpPath(destination string) string { return filepath.Join(tmpDir, destination) } -func copyIn(fixture string, destination string) { - err := os.MkdirAll(destination, 0777) - Ω(err).ShouldNot(HaveOccurred()) +func fixturePath(name string) string { + return filepath.Join("_fixtures", name) +} - filepath.Walk(filepath.Join("_fixtures", fixture), func(path string, info os.FileInfo, err error) error { - if info.IsDir() { - return nil +func copyIn(sourcePath, destinationPath string, recursive bool) { + err := os.MkdirAll(destinationPath, 0777) + Expect(err).NotTo(HaveOccurred()) + + files, err := ioutil.ReadDir(sourcePath) + Expect(err).NotTo(HaveOccurred()) + for _, f := range files { + srcPath := filepath.Join(sourcePath, f.Name()) + dstPath := filepath.Join(destinationPath, f.Name()) + if f.IsDir() { + if recursive { + copyIn(srcPath, dstPath, recursive) + } + continue } - base := filepath.Base(path) + src, err := os.Open(srcPath) - src, err := os.Open(path) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).NotTo(HaveOccurred()) defer src.Close() - dst, err := os.Create(filepath.Join(destination, base)) - Ω(err).ShouldNot(HaveOccurred()) + dst, err := os.Create(dstPath) + Expect(err).NotTo(HaveOccurred()) defer dst.Close() _, err = io.Copy(dst, src) - Ω(err).ShouldNot(HaveOccurred()) - return nil - }) + Expect(err).NotTo(HaveOccurred()) + } +} + +func sameFile(filePath, otherFilePath string) bool { + content, readErr := ioutil.ReadFile(filePath) + Expect(readErr).NotTo(HaveOccurred()) + otherContent, readErr := ioutil.ReadFile(otherFilePath) + Expect(readErr).NotTo(HaveOccurred()) + Expect(string(content)).To(Equal(string(otherContent))) + return true +} + +func sameFolder(sourcePath, destinationPath string) bool { + files, err := ioutil.ReadDir(sourcePath) + Expect(err).NotTo(HaveOccurred()) + for _, f := range files { + srcPath := filepath.Join(sourcePath, f.Name()) + dstPath := filepath.Join(destinationPath, f.Name()) + if f.IsDir() { + sameFolder(srcPath, dstPath) + continue + } + Expect(sameFile(srcPath, dstPath)).To(BeTrue()) + } + return true } func ginkgoCommand(dir string, args ...string) *exec.Cmd { @@ -89,3 +122,8 @@ func startGinkgo(dir string, args ...string) *gexec.Session { Ω(err).ShouldNot(HaveOccurred()) return session } + +func removeSuccessfully(path string) { + err := os.RemoveAll(path) + Expect(err).NotTo(HaveOccurred()) +} diff --git a/vendor/github.com/onsi/ginkgo/integration/interrupt_test.go b/vendor/github.com/onsi/ginkgo/integration/interrupt_test.go index dc3bf284..d4158b80 100644 --- a/vendor/github.com/onsi/ginkgo/integration/interrupt_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/interrupt_test.go @@ -13,7 +13,7 @@ var _ = Describe("Interrupt", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("hanging") - copyIn("hanging_suite", pathToTest) + copyIn(fixturePath("hanging_suite"), pathToTest, false) }) Context("when interrupting a suite", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/precompiled_test.go b/vendor/github.com/onsi/ginkgo/integration/precompiled_test.go index d9b78e0b..55724a9b 100644 --- a/vendor/github.com/onsi/ginkgo/integration/precompiled_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/precompiled_test.go @@ -16,7 +16,7 @@ var _ = Describe("ginkgo build", func() { BeforeEach(func() { pathToTest = tmpPath("passing_ginkgo_tests") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) session := startGinkgo(pathToTest, "build") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) diff --git a/vendor/github.com/onsi/ginkgo/integration/progress_test.go b/vendor/github.com/onsi/ginkgo/integration/progress_test.go index 8589c338..cda86b6e 100644 --- a/vendor/github.com/onsi/ginkgo/integration/progress_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/progress_test.go @@ -15,7 +15,7 @@ var _ = Describe("Emitting progress", func() { BeforeEach(func() { args = []string{"--noColor"} pathToTest = tmpPath("progress") - copyIn("progress_fixture", pathToTest) + copyIn(fixturePath("progress_fixture"), pathToTest, false) }) JustBeforeEach(func() { @@ -50,12 +50,17 @@ var _ = Describe("Emitting progress", func() { }) It("should emit progress (by writing to the GinkgoWriter)", func() { + // First spec + Ω(session).Should(gbytes.Say(`\[BeforeEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer before<`)) Ω(session).Should(gbytes.Say(`\[BeforeEach\] Inner Context`)) Ω(session).Should(gbytes.Say(`>inner before<`)) + Ω(session).Should(gbytes.Say(`\[BeforeEach\] when Inner When`)) + Ω(session).Should(gbytes.Say(`>inner before<`)) + Ω(session).Should(gbytes.Say(`\[JustBeforeEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer just before<`)) @@ -70,6 +75,20 @@ var _ = Describe("Emitting progress", func() { Ω(session).Should(gbytes.Say(`\[AfterEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer after<`)) + + // Second spec + + Ω(session).Should(gbytes.Say(`\[BeforeEach\] ProgressFixture`)) + Ω(session).Should(gbytes.Say(`>outer before<`)) + + Ω(session).Should(gbytes.Say(`\[JustBeforeEach\] ProgressFixture`)) + Ω(session).Should(gbytes.Say(`>outer just before<`)) + + Ω(session).Should(gbytes.Say(`\[It\] should emit progress as it goes`)) + Ω(session).Should(gbytes.Say(`>specify<`)) + + Ω(session).Should(gbytes.Say(`\[AfterEach\] ProgressFixture`)) + Ω(session).Should(gbytes.Say(`>outer after<`)) }) }) }) diff --git a/vendor/github.com/onsi/ginkgo/integration/run_test.go b/vendor/github.com/onsi/ginkgo/integration/run_test.go index 7f320bd5..6c270b61 100644 --- a/vendor/github.com/onsi/ginkgo/integration/run_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/run_test.go @@ -2,6 +2,8 @@ package integration_test import ( "fmt" + "io/ioutil" + "os" "regexp" "runtime" "strings" @@ -26,7 +28,7 @@ var _ = Describe("Running Specs", func() { Context("when pointed at the current directory", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should run the tests in the working directory", func() { @@ -44,7 +46,7 @@ var _ = Describe("Running Specs", func() { Context("when passed an explicit package to run", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should run the ginkgo style tests", func() { @@ -63,8 +65,8 @@ var _ = Describe("Running Specs", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") - copyIn("passing_ginkgo_tests", pathToTest) - copyIn("more_ginkgo_tests", otherPathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) + copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) }) It("should run the ginkgo style tests", func() { @@ -83,9 +85,9 @@ var _ = Describe("Running Specs", func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") focusedPathToTest := tmpPath("focused") - copyIn("passing_ginkgo_tests", pathToTest) - copyIn("more_ginkgo_tests", otherPathToTest) - copyIn("focused_fixture", focusedPathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) + copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) + copyIn(fixturePath("focused_fixture"), focusedPathToTest, false) }) It("should exit with a status code of 2 and explain why", func() { @@ -98,6 +100,24 @@ var _ = Describe("Running Specs", func() { Ω(output).Should(ContainSubstring("Test Suite Passed")) Ω(output).Should(ContainSubstring("Detected Programmatic Focus - setting exit status to %d", types.GINKGO_FOCUS_EXIT_CODE)) }) + + Context("when the GINKGO_EDITOR_INTEGRATION environment variable is set", func() { + BeforeEach(func() { + os.Setenv("GINKGO_EDITOR_INTEGRATION", "true") + }) + AfterEach(func() { + os.Setenv("GINKGO_EDITOR_INTEGRATION", "") + }) + It("should exit with a status code of 0 to allow a coverage file to be generated", func() { + session := startGinkgo(tmpDir, "--noColor", "--succinct=false", "-r") + Eventually(session).Should(gexec.Exit(0)) + output := string(session.Out.Contents()) + + Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) + Ω(output).Should(ContainSubstring("Running Suite: More_ginkgo_tests Suite")) + Ω(output).Should(ContainSubstring("Test Suite Passed")) + }) + }) }) Context("when told to skipPackages", func() { @@ -105,9 +125,9 @@ var _ = Describe("Running Specs", func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") focusedPathToTest := tmpPath("focused") - copyIn("passing_ginkgo_tests", pathToTest) - copyIn("more_ginkgo_tests", otherPathToTest) - copyIn("focused_fixture", focusedPathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) + copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) + copyIn(fixturePath("focused_fixture"), focusedPathToTest, false) }) It("should skip packages that match the list", func() { @@ -149,7 +169,7 @@ var _ = Describe("Running Specs", func() { Context("when there are test files but `go test` reports there are no tests to run", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("no_test_fn", pathToTest) + copyIn(fixturePath("no_test_fn"), pathToTest, false) }) It("suggests running ginkgo bootstrap", func() { @@ -173,8 +193,8 @@ var _ = Describe("Running Specs", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") - copyIn("passing_ginkgo_tests", pathToTest) - copyIn("more_ginkgo_tests", otherPathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) + copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) }) It("should skip packages that match the regexp", func() { @@ -195,7 +215,7 @@ var _ = Describe("Running Specs", func() { Context("when pointed at a package with xunit style tests", func() { BeforeEach(func() { pathToTest = tmpPath("xunit") - copyIn("xunit_tests", pathToTest) + copyIn(fixturePath("xunit_tests"), pathToTest, false) }) It("should run the xunit style tests", func() { @@ -211,7 +231,7 @@ var _ = Describe("Running Specs", func() { Context("when pointed at a package with no tests", func() { BeforeEach(func() { pathToTest = tmpPath("no_tests") - copyIn("no_tests", pathToTest) + copyIn(fixturePath("no_tests"), pathToTest, false) }) It("should fail", func() { @@ -225,7 +245,7 @@ var _ = Describe("Running Specs", func() { Context("when pointed at a package that fails to compile", func() { BeforeEach(func() { pathToTest = tmpPath("does_not_compile") - copyIn("does_not_compile", pathToTest) + copyIn(fixturePath("does_not_compile"), pathToTest, false) }) It("should fail", func() { @@ -240,7 +260,7 @@ var _ = Describe("Running Specs", func() { Context("when running in parallel", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) Context("with a specific number of -nodes", func() { @@ -273,10 +293,51 @@ var _ = Describe("Running Specs", func() { }) }) + Context("when running in parallel with -debug", func() { + BeforeEach(func() { + pathToTest = tmpPath("ginkgo") + copyIn(fixturePath("debug_parallel_fixture"), pathToTest, false) + }) + + Context("without -v", func() { + It("should emit node output to files on disk", func() { + session := startGinkgo(pathToTest, "--nodes=2", "--debug") + Eventually(session).Should(gexec.Exit(0)) + + f0, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-1.log") + Ω(err).ShouldNot(HaveOccurred()) + f1, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-2.log") + Ω(err).ShouldNot(HaveOccurred()) + content := string(append(f0, f1...)) + + for i := 0; i < 10; i += 1 { + Ω(content).Should(ContainSubstring("StdOut %d\n", i)) + Ω(content).Should(ContainSubstring("GinkgoWriter %d\n", i)) + } + }) + }) + + Context("without -v", func() { + It("should emit node output to files on disk, without duplicating the GinkgoWriter output", func() { + session := startGinkgo(pathToTest, "--nodes=2", "--debug", "-v") + Eventually(session).Should(gexec.Exit(0)) + + f0, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-1.log") + Ω(err).ShouldNot(HaveOccurred()) + f1, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-2.log") + Ω(err).ShouldNot(HaveOccurred()) + content := string(append(f0, f1...)) + + out := strings.Split(content, "GinkgoWriter 2") + Ω(out).Should(HaveLen(2)) + }) + }) + }) + Context("when streaming in parallel", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should print output in realtime", func() { @@ -296,8 +357,8 @@ var _ = Describe("Running Specs", func() { BeforeEach(func() { passingTest := tmpPath("A") otherPassingTest := tmpPath("E") - copyIn("passing_ginkgo_tests", passingTest) - copyIn("more_ginkgo_tests", otherPassingTest) + copyIn(fixturePath("passing_ginkgo_tests"), passingTest, false) + copyIn(fixturePath("more_ginkgo_tests"), otherPassingTest, false) }) Context("when all the tests pass", func() { @@ -330,7 +391,7 @@ var _ = Describe("Running Specs", func() { Context("when one of the packages has a failing tests", func() { BeforeEach(func() { failingTest := tmpPath("C") - copyIn("failing_ginkgo_tests", failingTest) + copyIn(fixturePath("failing_ginkgo_tests"), failingTest, false) }) It("should fail and stop running tests", func() { @@ -353,7 +414,7 @@ var _ = Describe("Running Specs", func() { Context("when one of the packages fails to compile", func() { BeforeEach(func() { doesNotCompileTest := tmpPath("C") - copyIn("does_not_compile", doesNotCompileTest) + copyIn(fixturePath("does_not_compile"), doesNotCompileTest, false) }) It("should fail and stop running tests", func() { @@ -372,10 +433,10 @@ var _ = Describe("Running Specs", func() { Context("when either is the case, but the keepGoing flag is set", func() { BeforeEach(func() { doesNotCompileTest := tmpPath("B") - copyIn("does_not_compile", doesNotCompileTest) + copyIn(fixturePath("does_not_compile"), doesNotCompileTest, false) failingTest := tmpPath("C") - copyIn("failing_ginkgo_tests", failingTest) + copyIn(fixturePath("failing_ginkgo_tests"), failingTest, false) }) It("should soldier on", func() { @@ -396,7 +457,7 @@ var _ = Describe("Running Specs", func() { Context("when told to keep going --untilItFails", func() { BeforeEach(func() { - copyIn("eventually_failing", tmpDir) + copyIn(fixturePath("eventually_failing"), tmpDir, false) }) It("should keep rerunning the tests, until a failure occurs", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/skip_test.go b/vendor/github.com/onsi/ginkgo/integration/skip_test.go index 59a12ee6..f0fc9d5e 100644 --- a/vendor/github.com/onsi/ginkgo/integration/skip_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/skip_test.go @@ -11,7 +11,7 @@ var _ = Describe("Skipping Specs", func() { BeforeEach(func() { pathToTest = tmpPath("skipping") - copyIn("skip_fixture", pathToTest) + copyIn(fixturePath("skip_fixture"), pathToTest, false) }) It("should skip in all the possible ways", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/subcommand_test.go b/vendor/github.com/onsi/ginkgo/integration/subcommand_test.go index 6a1913ad..fec197f5 100644 --- a/vendor/github.com/onsi/ginkgo/integration/subcommand_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/subcommand_test.go @@ -348,23 +348,47 @@ var _ = Describe("Subcommand", func() { Describe("ginkgo blur", func() { It("should unfocus tests", func() { pathToTest := tmpPath("focused") - copyIn("focused_fixture", pathToTest) + fixture := fixturePath("focused_fixture") + copyIn(fixture, pathToTest, false) session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := session.Out.Contents() - Ω(output).Should(ContainSubstring("6 Passed")) - Ω(output).Should(ContainSubstring("5 Skipped")) + Ω(string(output)).Should(ContainSubstring("8 Passed")) + Ω(string(output)).Should(ContainSubstring("5 Skipped")) session = startGinkgo(pathToTest, "blur") Eventually(session).Should(gexec.Exit(0)) + output = session.Out.Contents() + Ω(string(output)).ShouldNot(ContainSubstring("expected 'package'")) session = startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output = session.Out.Contents() - Ω(output).Should(ContainSubstring("11 Passed")) - Ω(output).Should(ContainSubstring("0 Skipped")) + Ω(string(output)).Should(ContainSubstring("13 Passed")) + Ω(string(output)).Should(ContainSubstring("0 Skipped")) + + Expect(sameFile(filepath.Join(pathToTest, "README.md"), filepath.Join(fixture, "README.md"))).To(BeTrue()) + }) + + It("should ignore the 'vendor' folder", func() { + pathToTest := tmpPath("focused_fixture_with_vendor") + copyIn(fixturePath("focused_fixture_with_vendor"), pathToTest, true) + + session := startGinkgo(pathToTest, "blur") + Eventually(session).Should(gexec.Exit(0)) + + session = startGinkgo(pathToTest, "--noColor") + Eventually(session).Should(gexec.Exit(0)) + output := session.Out.Contents() + Expect(string(output)).To(ContainSubstring("13 Passed")) + Expect(string(output)).To(ContainSubstring("0 Skipped")) + + vendorPath := fixturePath("focused_fixture_with_vendor/vendor") + otherVendorPath := filepath.Join(pathToTest, "vendor") + + Expect(sameFolder(vendorPath, otherVendorPath)).To(BeTrue()) }) }) diff --git a/vendor/github.com/onsi/ginkgo/integration/suite_command_test.go b/vendor/github.com/onsi/ginkgo/integration/suite_command_test.go index 4bd46f01..4aec1bc4 100644 --- a/vendor/github.com/onsi/ginkgo/integration/suite_command_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/suite_command_test.go @@ -11,7 +11,7 @@ var _ = Describe("Suite Command Specs", func() { BeforeEach(func() { pathToTest = tmpPath("suite_command") - copyIn("suite_command_tests", pathToTest) + copyIn(fixturePath("suite_command_tests"), pathToTest, false) }) It("Runs command after suite echoing out suite data, properly reporting suite name and passing status in successful command output", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/suite_setup_test.go b/vendor/github.com/onsi/ginkgo/integration/suite_setup_test.go index b9313db5..33ff5b98 100644 --- a/vendor/github.com/onsi/ginkgo/integration/suite_setup_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/suite_setup_test.go @@ -14,7 +14,7 @@ var _ = Describe("SuiteSetup", func() { Context("when the BeforeSuite and AfterSuite pass", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") - copyIn("passing_suite_setup", pathToTest) + copyIn(fixturePath("passing_suite_setup"), pathToTest, false) }) It("should run the BeforeSuite once, then run all the tests", func() { @@ -39,7 +39,7 @@ var _ = Describe("SuiteSetup", func() { Context("when the BeforeSuite fails", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") - copyIn("failing_before_suite", pathToTest) + copyIn(fixturePath("failing_before_suite"), pathToTest, false) }) It("should run the BeforeSuite once, none of the tests, but it should run the AfterSuite", func() { @@ -68,7 +68,7 @@ var _ = Describe("SuiteSetup", func() { Context("when the AfterSuite fails", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") - copyIn("failing_after_suite", pathToTest) + copyIn(fixturePath("failing_after_suite"), pathToTest, false) }) It("should run the BeforeSuite once, none of the tests, but it should run the AfterSuite", func() { @@ -97,7 +97,7 @@ var _ = Describe("SuiteSetup", func() { Context("With passing synchronized before and after suites", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") - copyIn("synchronized_setup_tests", pathToTest) + copyIn(fixturePath("synchronized_setup_tests"), pathToTest, false) }) Context("when run with one node", func() { @@ -163,7 +163,7 @@ var _ = Describe("SuiteSetup", func() { Context("With a failing synchronized before suite", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") - copyIn("exiting_synchronized_setup_tests", pathToTest) + copyIn(fixturePath("exiting_synchronized_setup_tests"), pathToTest, false) }) It("should fail and let the user know that node 1 disappeared prematurely", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/tags_test.go b/vendor/github.com/onsi/ginkgo/integration/tags_test.go index 626635bf..fc2ff5e5 100644 --- a/vendor/github.com/onsi/ginkgo/integration/tags_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/tags_test.go @@ -10,7 +10,7 @@ var _ = Describe("Tags", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("tags") - copyIn("tags_tests", pathToTest) + copyIn(fixturePath("tags_tests"), pathToTest, false) }) It("should honor the passed in -tags flag", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/test_description_test.go b/vendor/github.com/onsi/ginkgo/integration/test_description_test.go index 70a8f04e..6739871f 100644 --- a/vendor/github.com/onsi/ginkgo/integration/test_description_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/test_description_test.go @@ -12,7 +12,7 @@ var _ = Describe("TestDescription", func() { BeforeEach(func() { pathToTest = tmpPath("test_description") - copyIn("test_description", pathToTest) + copyIn(fixturePath("test_description"), pathToTest, false) }) It("should capture and emit information about the current test", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/verbose_and_succinct_test.go b/vendor/github.com/onsi/ginkgo/integration/verbose_and_succinct_test.go index aba9a6b0..8238762d 100644 --- a/vendor/github.com/onsi/ginkgo/integration/verbose_and_succinct_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/verbose_and_succinct_test.go @@ -23,7 +23,7 @@ var _ = Describe("Verbose And Succinct Mode", func() { Context("when running one package", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should default to non-succinct mode", func() { @@ -38,9 +38,9 @@ var _ = Describe("Verbose And Succinct Mode", func() { Context("when running more than one package", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") - copyIn("passing_ginkgo_tests", pathToTest) + copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) otherPathToTest = tmpPath("more_ginkgo") - copyIn("more_ginkgo_tests", otherPathToTest) + copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) }) Context("with no flags set", func() { diff --git a/vendor/github.com/onsi/ginkgo/integration/watch_test.go b/vendor/github.com/onsi/ginkgo/integration/watch_test.go index c18e8f87..1d65702a 100644 --- a/vendor/github.com/onsi/ginkgo/integration/watch_test.go +++ b/vendor/github.com/onsi/ginkgo/integration/watch_test.go @@ -34,14 +34,14 @@ var _ = Describe("Watch", func() { err = os.MkdirAll(pathC, 0700) Ω(err).ShouldNot(HaveOccurred()) - copyIn(filepath.Join("watch_fixtures", "A"), pathA) - copyIn(filepath.Join("watch_fixtures", "B"), pathB) - copyIn(filepath.Join("watch_fixtures", "C"), pathC) + copyIn(fixturePath(filepath.Join("watch_fixtures", "A")), pathA, false) + copyIn(fixturePath(filepath.Join("watch_fixtures", "B")), pathB, false) + copyIn(fixturePath(filepath.Join("watch_fixtures", "C")), pathC, false) }) startGinkgoWithGopath := func(args ...string) *gexec.Session { cmd := ginkgoCommand(rootPath, args...) - cmd.Env = append([]string{"GOPATH=" + rootPath + ":" + os.Getenv("GOPATH")}, os.Environ()...) + os.Setenv("GOPATH", rootPath+":"+os.Getenv("GOPATH")) session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) return session @@ -254,7 +254,7 @@ var _ = Describe("Watch", func() { err := os.MkdirAll(pathD, 0700) Ω(err).ShouldNot(HaveOccurred()) - copyIn(filepath.Join("watch_fixtures", "D"), pathD) + copyIn(fixturePath(filepath.Join("watch_fixtures", "D")), pathD, false) Eventually(session).Should(gbytes.Say("Detected 1 new suite")) Eventually(session).Should(gbytes.Say(`D \[1 dependency\]`)) diff --git a/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go index 55a9e9d0..cca75a44 100644 --- a/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go @@ -1,11 +1,12 @@ package codelocation_test import ( + "runtime" + . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" - "runtime" ) var _ = Describe("CodeLocation", func() { diff --git a/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go b/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go index b8d61b13..11ac9b70 100644 --- a/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go @@ -1,9 +1,10 @@ package containernode_test import ( - "github.com/onsi/ginkgo/internal/leafnodes" "math/rand" + "github.com/onsi/ginkgo/internal/leafnodes" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go index 9c3eed2b..d6d54234 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go @@ -35,15 +35,15 @@ func (b *benchmarker) Time(name string, body func(), info ...interface{}) (elaps } func (b *benchmarker) RecordValue(name string, value float64, info ...interface{}) { - measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", "", 3, info...) b.mu.Lock() + measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", "", 3, info...) defer b.mu.Unlock() measurement.Results = append(measurement.Results, value) } func (b *benchmarker) RecordValueWithPrecision(name string, value float64, units string, precision int, info ...interface{}) { - measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", units, precision, info...) b.mu.Lock() + measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", units, precision, info...) defer b.mu.Unlock() measurement.Results = append(measurement.Results, value) } diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go index c76fe3a4..6eded7b7 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go @@ -1,9 +1,10 @@ package leafnodes import ( + "time" + "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "time" ) type ItNode struct { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go index efc3348c..3ab9a6d5 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go @@ -1,9 +1,10 @@ package leafnodes import ( + "reflect" + "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "reflect" ) type MeasureNode struct { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go index 252065b8..1cd13336 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go @@ -5,10 +5,11 @@ import ( . "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/gomega" + "time" + "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "time" ) var _ = Describe("Measure Nodes", func() { @@ -119,13 +120,13 @@ var _ = Describe("Measure Nodes", func() { BeforeEach(func() { measure = NewMeasureNode("the measurement", func(b Benchmarker) { b.Time("foo", func() { - time.Sleep(100 * time.Millisecond) + time.Sleep(200 * time.Millisecond) }, "info!") b.Time("foo", func() { - time.Sleep(200 * time.Millisecond) + time.Sleep(300 * time.Millisecond) }) b.Time("foo", func() { - time.Sleep(170 * time.Millisecond) + time.Sleep(250 * time.Millisecond) }) }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) @@ -141,13 +142,13 @@ var _ = Describe("Measure Nodes", func() { Ω(report["foo"].AverageLabel).Should(Equal("Average Time")) Ω(report["foo"].Units).Should(Equal("s")) Ω(report["foo"].Results).Should(HaveLen(3)) - Ω(report["foo"].Results[0]).Should(BeNumerically("~", 0.1, 0.01)) - Ω(report["foo"].Results[1]).Should(BeNumerically("~", 0.2, 0.01)) - Ω(report["foo"].Results[2]).Should(BeNumerically("~", 0.17, 0.01)) - Ω(report["foo"].Smallest).Should(BeNumerically("~", 0.1, 0.01)) - Ω(report["foo"].Largest).Should(BeNumerically("~", 0.2, 0.01)) - Ω(report["foo"].Average).Should(BeNumerically("~", 0.16, 0.01)) - Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 0.04, 0.01)) + Ω(report["foo"].Results[0]).Should(BeNumerically("~", 0.2, 0.06)) + Ω(report["foo"].Results[1]).Should(BeNumerically("~", 0.3, 0.06)) + Ω(report["foo"].Results[2]).Should(BeNumerically("~", 0.25, 0.06)) + Ω(report["foo"].Smallest).Should(BeNumerically("~", 0.2, 0.06)) + Ω(report["foo"].Largest).Should(BeNumerically("~", 0.3, 0.06)) + Ω(report["foo"].Average).Should(BeNumerically("~", 0.25, 0.06)) + Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 0.07, 0.04)) }) }) }) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go index 870ad826..16cb66c3 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go @@ -2,11 +2,12 @@ package leafnodes import ( "fmt" + "reflect" + "time" + "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "reflect" - "time" ) type runner struct { @@ -86,6 +87,9 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure) finished = true }() + // If this goroutine gets no CPU time before the select block, + // the <-done case may complete even if the test took longer than the timeoutThreshold. + // This can cause flaky behaviour, but we haven't seen it in the wild. select { case <-done: case <-time.After(r.timeoutThreshold): diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go index 6b725a63..b4654cd2 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go @@ -1,9 +1,10 @@ package leafnodes import ( + "time" + "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "time" ) type SetupNode struct { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go index fcccef48..0897836c 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go @@ -179,8 +179,8 @@ func AsynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time didRun = true failer.Fail("bam", innerCodeLocation) time.Sleep(20 * time.Millisecond) + defer close(done) panic("doesn't matter") - close(done) }, 10*time.Millisecond, failer, componentCodeLocation).Run() }) @@ -199,21 +199,18 @@ func AsynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time }) }) - Context("when the function times out", func() { + Context("when the function doesn't close the done channel in time", func() { var guard chan struct{} BeforeEach(func() { guard = make(chan struct{}) outcome, failure = build(func(done Done) { didRun = true - time.Sleep(20 * time.Millisecond) close(guard) - panic("doesn't matter") - close(done) }, 10*time.Millisecond, failer, componentCodeLocation).Run() }) - It("should return the timeout", func() { + It("should return a timeout", func() { <-guard Ω(didRun).Should(BeTrue()) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go index 2ccc7dc0..80f16ed7 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go @@ -1,9 +1,10 @@ package leafnodes import ( + "time" + "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "time" ) type SuiteNode interface { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go index e7030d91..a721d0cf 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go @@ -2,11 +2,12 @@ package leafnodes import ( "encoding/json" - "github.com/onsi/ginkgo/internal/failer" - "github.com/onsi/ginkgo/types" "io/ioutil" "net/http" "time" + + "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/types" ) type synchronizedAfterSuiteNode struct { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go index 4266a4bc..edbdf6ae 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go @@ -1,18 +1,21 @@ package leafnodes_test import ( + "sync" + . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" - "sync" + + "net/http" "github.com/onsi/gomega/ghttp" - "net/http" + + "time" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" - "time" ) var _ = Describe("SynchronizedAfterSuiteNode", func() { @@ -132,19 +135,19 @@ var _ = Describe("SynchronizedAfterSuiteNode", func() { func(writer http.ResponseWriter, request *http.Request) { ranThing("Request1") }, - ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{false}), + ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), func(writer http.ResponseWriter, request *http.Request) { ranThing("Request2") }, - ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{false}), + ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), func(writer http.ResponseWriter, request *http.Request) { ranThing("Request3") }, - ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{true}), + ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: true}), )) node = newNode(func() { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go index 76a96798..d5c88931 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go @@ -3,12 +3,13 @@ package leafnodes import ( "bytes" "encoding/json" - "github.com/onsi/ginkgo/internal/failer" - "github.com/onsi/ginkgo/types" "io/ioutil" "net/http" "reflect" "time" + + "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/types" ) type synchronizedBeforeSuiteNode struct { @@ -109,8 +110,6 @@ func (node *synchronizedBeforeSuiteNode) waitForA(syncHost string) (types.SpecSt time.Sleep(50 * time.Millisecond) } - - return types.SpecStateFailed, failure("Shouldn't get here!") } func (node *synchronizedBeforeSuiteNode) Passed() bool { diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go index dbf24267..46c3e276 100644 --- a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go @@ -5,13 +5,15 @@ import ( . "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/gomega" - "github.com/onsi/gomega/ghttp" "net/http" + "github.com/onsi/gomega/ghttp" + + "time" + "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" - "time" ) var _ = Describe("SynchronizedBeforeSuiteNode", func() { @@ -176,7 +178,7 @@ var _ = Describe("SynchronizedBeforeSuiteNode", func() { Context("when A succeeds", func() { BeforeEach(func() { - expectedState = types.RemoteBeforeSuiteData{[]byte("my data"), types.RemoteBeforeSuiteStatePassed} + expectedState = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed} node = newNode(func() []byte { return []byte("my data") @@ -200,11 +202,10 @@ var _ = Describe("SynchronizedBeforeSuiteNode", func() { Context("when A fails", func() { BeforeEach(func() { - expectedState = types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStateFailed} + expectedState = types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateFailed} node = newNode(func() []byte { panic("BAM") - return []byte("my data") }, func([]byte) { ranB = true }) @@ -238,10 +239,10 @@ var _ = Describe("SynchronizedBeforeSuiteNode", func() { server.AppendHandlers(ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/BeforeSuiteState"), - ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending}).ToJSON())), + ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/BeforeSuiteState"), - ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending}).ToJSON())), + ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/BeforeSuiteState"), ghttp.RespondWithJSONEncodedPtr(&statusCode, &response), @@ -259,7 +260,7 @@ var _ = Describe("SynchronizedBeforeSuiteNode", func() { Context("when A on node1 succeeds", func() { BeforeEach(func() { - response = types.RemoteBeforeSuiteData{[]byte("my data"), types.RemoteBeforeSuiteStatePassed} + response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed} outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) @@ -283,7 +284,7 @@ var _ = Describe("SynchronizedBeforeSuiteNode", func() { Context("when A on node1 fails", func() { BeforeEach(func() { - response = types.RemoteBeforeSuiteData{[]byte("my data"), types.RemoteBeforeSuiteStateFailed} + response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateFailed} outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) @@ -315,7 +316,7 @@ var _ = Describe("SynchronizedBeforeSuiteNode", func() { Context("when node1 disappears", func() { BeforeEach(func() { - response = types.RemoteBeforeSuiteData{[]byte("my data"), types.RemoteBeforeSuiteStateDisappeared} + response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateDisappeared} outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go b/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go index 522d44e3..6b54afe0 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go @@ -207,7 +207,7 @@ func (aggregator *Aggregator) announceSpec(specSummary *types.SpecSummary) { case types.SpecStatePending: aggregator.stenographer.AnnouncePendingSpec(specSummary, aggregator.config.NoisyPendings && !aggregator.config.Succinct) case types.SpecStateSkipped: - aggregator.stenographer.AnnounceSkippedSpec(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace) + aggregator.stenographer.AnnounceSkippedSpec(specSummary, aggregator.config.Succinct || !aggregator.config.NoisySkippings, aggregator.config.FullTrace) case types.SpecStateTimedOut: aggregator.stenographer.AnnounceSpecTimedOut(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace) case types.SpecStatePanicked: diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go index a928f93d..ef54862e 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go @@ -1,5 +1,7 @@ package remote_test +import "os" + type fakeOutputInterceptor struct { DidStartInterceptingOutput bool DidStopInterceptingOutput bool @@ -15,3 +17,6 @@ func (interceptor *fakeOutputInterceptor) StopInterceptingAndReturnOutput() (str interceptor.DidStopInterceptingOutput = true return interceptor.InterceptedOutput, nil } + +func (interceptor *fakeOutputInterceptor) StreamTo(*os.File) { +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter.go b/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter.go index 025eb506..284bc62e 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter.go @@ -3,8 +3,14 @@ package remote import ( "bytes" "encoding/json" + "fmt" "io" "net/http" + "os" + + "github.com/onsi/ginkgo/internal/writer" + "github.com/onsi/ginkgo/reporters" + "github.com/onsi/ginkgo/reporters/stenographer" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/types" @@ -30,14 +36,41 @@ type ForwardingReporter struct { serverHost string poster Poster outputInterceptor OutputInterceptor + debugMode bool + debugFile *os.File + nestedReporter *reporters.DefaultReporter } -func NewForwardingReporter(serverHost string, poster Poster, outputInterceptor OutputInterceptor) *ForwardingReporter { - return &ForwardingReporter{ +func NewForwardingReporter(config config.DefaultReporterConfigType, serverHost string, poster Poster, outputInterceptor OutputInterceptor, ginkgoWriter *writer.Writer, debugFile string) *ForwardingReporter { + reporter := &ForwardingReporter{ serverHost: serverHost, poster: poster, outputInterceptor: outputInterceptor, } + + if debugFile != "" { + var err error + reporter.debugMode = true + reporter.debugFile, err = os.Create(debugFile) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + if !config.Verbose { + //if verbose is true then the GinkgoWriter emits to stdout. Don't _also_ redirect GinkgoWriter output as that will result in duplication. + ginkgoWriter.AndRedirectTo(reporter.debugFile) + } + outputInterceptor.StreamTo(reporter.debugFile) //This is not working + + stenographer := stenographer.New(false, true, reporter.debugFile) + config.Succinct = false + config.Verbose = true + config.FullTrace = true + reporter.nestedReporter = reporters.NewDefaultReporter(config, stenographer) + } + + return reporter } func (reporter *ForwardingReporter) post(path string, data interface{}) { @@ -56,6 +89,10 @@ func (reporter *ForwardingReporter) SpecSuiteWillBegin(conf config.GinkgoConfigT } reporter.outputInterceptor.StartInterceptingOutput() + if reporter.debugMode { + reporter.nestedReporter.SpecSuiteWillBegin(conf, summary) + reporter.debugFile.Sync() + } reporter.post("/SpecSuiteWillBegin", data) } @@ -63,10 +100,18 @@ func (reporter *ForwardingReporter) BeforeSuiteDidRun(setupSummary *types.SetupS output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput() reporter.outputInterceptor.StartInterceptingOutput() setupSummary.CapturedOutput = output + if reporter.debugMode { + reporter.nestedReporter.BeforeSuiteDidRun(setupSummary) + reporter.debugFile.Sync() + } reporter.post("/BeforeSuiteDidRun", setupSummary) } func (reporter *ForwardingReporter) SpecWillRun(specSummary *types.SpecSummary) { + if reporter.debugMode { + reporter.nestedReporter.SpecWillRun(specSummary) + reporter.debugFile.Sync() + } reporter.post("/SpecWillRun", specSummary) } @@ -74,6 +119,10 @@ func (reporter *ForwardingReporter) SpecDidComplete(specSummary *types.SpecSumma output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput() reporter.outputInterceptor.StartInterceptingOutput() specSummary.CapturedOutput = output + if reporter.debugMode { + reporter.nestedReporter.SpecDidComplete(specSummary) + reporter.debugFile.Sync() + } reporter.post("/SpecDidComplete", specSummary) } @@ -81,10 +130,18 @@ func (reporter *ForwardingReporter) AfterSuiteDidRun(setupSummary *types.SetupSu output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput() reporter.outputInterceptor.StartInterceptingOutput() setupSummary.CapturedOutput = output + if reporter.debugMode { + reporter.nestedReporter.AfterSuiteDidRun(setupSummary) + reporter.debugFile.Sync() + } reporter.post("/AfterSuiteDidRun", setupSummary) } func (reporter *ForwardingReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { reporter.outputInterceptor.StopInterceptingAndReturnOutput() + if reporter.debugMode { + reporter.nestedReporter.SpecSuiteDidEnd(summary) + reporter.debugFile.Sync() + } reporter.post("/SpecSuiteDidEnd", summary) } diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go index e5f3b1e3..0d7e4769 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go @@ -2,6 +2,7 @@ package remote_test import ( "encoding/json" + . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/config" . "github.com/onsi/ginkgo/internal/remote" @@ -29,7 +30,7 @@ var _ = Describe("ForwardingReporter", func() { InterceptedOutput: "The intercepted output!", } - reporter = NewForwardingReporter(serverHost, poster, interceptor) + reporter = NewForwardingReporter(config.DefaultReporterConfigType{}, serverHost, poster, interceptor, nil, "") suiteSummary = &types.SuiteSummary{ SuiteDescription: "My Test Suite", diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor.go index 093f4513..5154abe8 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor.go @@ -1,5 +1,7 @@ package remote +import "os" + /* The OutputInterceptor is used by the ForwardingReporter to intercept and capture all stdin and stderr output during a test run. @@ -7,4 +9,5 @@ intercept and capture all stdin and stderr output during a test run. type OutputInterceptor interface { StartInterceptingOutput() error StopInterceptingAndReturnOutput() (string, error) + StreamTo(*os.File) } diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go index 980065da..ab6622a2 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go @@ -6,6 +6,8 @@ import ( "errors" "io/ioutil" "os" + + "github.com/hpcloud/tail" ) func NewOutputInterceptor() OutputInterceptor { @@ -14,7 +16,10 @@ func NewOutputInterceptor() OutputInterceptor { type outputInterceptor struct { redirectFile *os.File + streamTarget *os.File intercepting bool + tailer *tail.Tail + doneTailing chan bool } func (interceptor *outputInterceptor) StartInterceptingOutput() error { @@ -37,6 +42,18 @@ func (interceptor *outputInterceptor) StartInterceptingOutput() error { syscallDup(int(interceptor.redirectFile.Fd()), 1) syscallDup(int(interceptor.redirectFile.Fd()), 2) + if interceptor.streamTarget != nil { + interceptor.tailer, _ = tail.TailFile(interceptor.redirectFile.Name(), tail.Config{Follow: true}) + interceptor.doneTailing = make(chan bool) + + go func() { + for line := range interceptor.tailer.Lines { + interceptor.streamTarget.Write([]byte(line.Text + "\n")) + } + close(interceptor.doneTailing) + }() + } + return nil } @@ -51,5 +68,16 @@ func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string, interceptor.intercepting = false + if interceptor.streamTarget != nil { + interceptor.tailer.Stop() + interceptor.tailer.Cleanup() + <-interceptor.doneTailing + interceptor.streamTarget.Sync() + } + return string(output), err } + +func (interceptor *outputInterceptor) StreamTo(out *os.File) { + interceptor.streamTarget = out +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_win.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_win.go index c8f97d97..40c79033 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_win.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_win.go @@ -4,6 +4,7 @@ package remote import ( "errors" + "os" ) func NewOutputInterceptor() OutputInterceptor { @@ -31,3 +32,5 @@ func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string, return "", nil } + +func (interceptor *outputInterceptor) StreamTo(*os.File) {} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/server.go b/vendor/github.com/onsi/ginkgo/internal/remote/server.go index 297af2eb..367c54da 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/server.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/server.go @@ -45,7 +45,7 @@ func NewServer(parallelTotal int) (*Server, error) { listener: listener, lock: &sync.Mutex{}, alives: make([]func() bool, parallelTotal), - beforeSuiteData: types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending}, + beforeSuiteData: types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}, parallelTotal: parallelTotal, }, nil } diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go index eb2eefeb..36bd0035 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go @@ -47,7 +47,7 @@ var _ = Describe("Server", func() { server.RegisterReporters(reporterA, reporterB) - forwardingReporter = NewForwardingReporter(server.Address(), &http.Client{}, &fakeOutputInterceptor{}) + forwardingReporter = NewForwardingReporter(config.DefaultReporterConfigType{}, server.Address(), &http.Client{}, &fakeOutputInterceptor{}, nil, "") suiteSummary = &types.SuiteSummary{ SuiteDescription: "My Test Suite", @@ -146,10 +146,10 @@ var _ = Describe("Server", func() { Context("when the first node's Alive has not been registered yet", func() { It("should return pending", func() { state := getBeforeSuite() - Ω(state).Should(Equal(types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending})) + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) state = getBeforeSuite() - Ω(state).Should(Equal(types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending})) + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) }) }) @@ -162,10 +162,10 @@ var _ = Describe("Server", func() { It("should return pending", func() { state := getBeforeSuite() - Ω(state).Should(Equal(types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending})) + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) state = getBeforeSuite() - Ω(state).Should(Equal(types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStatePending})) + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) }) }) @@ -198,10 +198,10 @@ var _ = Describe("Server", func() { It("should return disappeared", func() { state := getBeforeSuite() - Ω(state).Should(Equal(types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStateDisappeared})) + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateDisappeared})) state = getBeforeSuite() - Ω(state).Should(Equal(types.RemoteBeforeSuiteData{nil, types.RemoteBeforeSuiteStateDisappeared})) + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateDisappeared})) }) }) }) diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_linux_arm64.go b/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_linux_arm64.go index 5c59728e..9550d37b 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_linux_arm64.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_linux_arm64.go @@ -8,4 +8,4 @@ import "syscall" // use the nearly identical syscall.Dup3 instead func syscallDup(oldfd int, newfd int) (err error) { return syscall.Dup3(oldfd, newfd, 0) -} \ No newline at end of file +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_solaris.go b/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_solaris.go index ecf9cafb..75ef7fb7 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_solaris.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_solaris.go @@ -6,4 +6,4 @@ import "golang.org/x/sys/unix" func syscallDup(oldfd int, newfd int) (err error) { return unix.Dup2(oldfd, newfd) -} \ No newline at end of file +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_unix.go b/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_unix.go index cacdd0e6..ef625596 100644 --- a/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_unix.go +++ b/vendor/github.com/onsi/ginkgo/internal/remote/syscall_dup_unix.go @@ -8,4 +8,4 @@ import "syscall" func syscallDup(oldfd int, newfd int) (err error) { return syscall.Dup2(oldfd, newfd) -} \ No newline at end of file +} diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/spec.go b/vendor/github.com/onsi/ginkgo/internal/spec/spec.go index d32dec69..77b23a4c 100644 --- a/vendor/github.com/onsi/ginkgo/internal/spec/spec.go +++ b/vendor/github.com/onsi/ginkgo/internal/spec/spec.go @@ -5,6 +5,8 @@ import ( "io" "time" + "sync" + "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" @@ -19,8 +21,11 @@ type Spec struct { state types.SpecState runTime time.Duration + startTime time.Time failure types.SpecFailure previousFailures bool + + stateMutex *sync.Mutex } func New(subject leafnodes.SubjectNode, containers []*containernode.ContainerNode, announceProgress bool) *Spec { @@ -29,6 +34,7 @@ func New(subject leafnodes.SubjectNode, containers []*containernode.ContainerNod containers: containers, focused: subject.Flag() == types.FlagTypeFocused, announceProgress: announceProgress, + stateMutex: &sync.Mutex{}, } spec.processFlag(subject.Flag()) @@ -43,32 +49,32 @@ func (spec *Spec) processFlag(flag types.FlagType) { if flag == types.FlagTypeFocused { spec.focused = true } else if flag == types.FlagTypePending { - spec.state = types.SpecStatePending + spec.setState(types.SpecStatePending) } } func (spec *Spec) Skip() { - spec.state = types.SpecStateSkipped + spec.setState(types.SpecStateSkipped) } func (spec *Spec) Failed() bool { - return spec.state == types.SpecStateFailed || spec.state == types.SpecStatePanicked || spec.state == types.SpecStateTimedOut + return spec.getState() == types.SpecStateFailed || spec.getState() == types.SpecStatePanicked || spec.getState() == types.SpecStateTimedOut } func (spec *Spec) Passed() bool { - return spec.state == types.SpecStatePassed + return spec.getState() == types.SpecStatePassed } func (spec *Spec) Flaked() bool { - return spec.state == types.SpecStatePassed && spec.previousFailures + return spec.getState() == types.SpecStatePassed && spec.previousFailures } func (spec *Spec) Pending() bool { - return spec.state == types.SpecStatePending + return spec.getState() == types.SpecStatePending } func (spec *Spec) Skipped() bool { - return spec.state == types.SpecStateSkipped + return spec.getState() == types.SpecStateSkipped } func (spec *Spec) Focused() bool { @@ -91,13 +97,18 @@ func (spec *Spec) Summary(suiteID string) *types.SpecSummary { componentTexts[len(spec.containers)] = spec.subject.Text() componentCodeLocations[len(spec.containers)] = spec.subject.CodeLocation() + runTime := spec.runTime + if runTime == 0 && !spec.startTime.IsZero() { + runTime = time.Since(spec.startTime) + } + return &types.SpecSummary{ IsMeasurement: spec.IsMeasurement(), NumberOfSamples: spec.subject.Samples(), ComponentTexts: componentTexts, ComponentCodeLocations: componentCodeLocations, - State: spec.state, - RunTime: spec.runTime, + State: spec.getState(), + RunTime: runTime, Failure: spec.failure, Measurements: spec.measurementsReport(), SuiteID: suiteID, @@ -114,26 +125,38 @@ func (spec *Spec) ConcatenatedString() string { } func (spec *Spec) Run(writer io.Writer) { - if spec.state == types.SpecStateFailed { + if spec.getState() == types.SpecStateFailed { spec.previousFailures = true } - startTime := time.Now() + spec.startTime = time.Now() defer func() { - spec.runTime = time.Since(startTime) + spec.runTime = time.Since(spec.startTime) }() for sample := 0; sample < spec.subject.Samples(); sample++ { spec.runSample(sample, writer) - if spec.state != types.SpecStatePassed { + if spec.getState() != types.SpecStatePassed { return } } } +func (spec *Spec) getState() types.SpecState { + spec.stateMutex.Lock() + defer spec.stateMutex.Unlock() + return spec.state +} + +func (spec *Spec) setState(state types.SpecState) { + spec.stateMutex.Lock() + defer spec.stateMutex.Unlock() + spec.state = state +} + func (spec *Spec) runSample(sample int, writer io.Writer) { - spec.state = types.SpecStatePassed + spec.setState(types.SpecStatePassed) spec.failure = types.SpecFailure{} innerMostContainerIndexToUnwind := -1 @@ -143,8 +166,8 @@ func (spec *Spec) runSample(sample int, writer io.Writer) { for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) { spec.announceSetupNode(writer, "AfterEach", container, afterEach) afterEachState, afterEachFailure := afterEach.Run() - if afterEachState != types.SpecStatePassed && spec.state == types.SpecStatePassed { - spec.state = afterEachState + if afterEachState != types.SpecStatePassed && spec.getState() == types.SpecStatePassed { + spec.setState(afterEachState) spec.failure = afterEachFailure } } @@ -155,8 +178,10 @@ func (spec *Spec) runSample(sample int, writer io.Writer) { innerMostContainerIndexToUnwind = i for _, beforeEach := range container.SetupNodesOfType(types.SpecComponentTypeBeforeEach) { spec.announceSetupNode(writer, "BeforeEach", container, beforeEach) - spec.state, spec.failure = beforeEach.Run() - if spec.state != types.SpecStatePassed { + s, f := beforeEach.Run() + spec.failure = f + spec.setState(s) + if spec.getState() != types.SpecStatePassed { return } } @@ -165,15 +190,19 @@ func (spec *Spec) runSample(sample int, writer io.Writer) { for _, container := range spec.containers { for _, justBeforeEach := range container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach) { spec.announceSetupNode(writer, "JustBeforeEach", container, justBeforeEach) - spec.state, spec.failure = justBeforeEach.Run() - if spec.state != types.SpecStatePassed { + s, f := justBeforeEach.Run() + spec.failure = f + spec.setState(s) + if spec.getState() != types.SpecStatePassed { return } } } spec.announceSubject(writer, spec.subject) - spec.state, spec.failure = spec.subject.Run() + s, f := spec.subject.Run() + spec.failure = f + spec.setState(s) } func (spec *Spec) announceSetupNode(writer io.Writer, nodeType string, container *containernode.ContainerNode, setupNode leafnodes.BasicNode) { diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go b/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go index 3bab8887..7011a42e 100644 --- a/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go @@ -569,6 +569,13 @@ var _ = Describe("Spec", func() { Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) }) + It("should have a runtime which remains consistent after spec run", func() { + totalRunTime := summary.RunTime + Ω(totalRunTime).Should(BeNumerically(">=", 10*time.Millisecond)) + + Consistently(func() time.Duration { return spec.Summary("suite id").RunTime }).Should(Equal(totalRunTime)) + }) + It("should not be a measurement, or have a measurement summary", func() { Ω(summary.IsMeasurement).Should(BeFalse()) Ω(summary.Measurements).Should(BeEmpty()) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator.go index 54e61ecb..99f548bc 100644 --- a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator.go +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator.go @@ -2,7 +2,6 @@ package spec_iterator import ( "encoding/json" - "errors" "fmt" "net/http" @@ -31,7 +30,7 @@ func (s *ParallelIterator) Next() (*spec.Spec, error) { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, errors.New(fmt.Sprintf("unexpected status code %d", resp.StatusCode)) + return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } var counter Counter diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go index d8e05a2d..c5a762fd 100644 --- a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go @@ -64,10 +64,10 @@ var _ = Describe("ParallelSpecIterator", func() { Describe("when the server returns well-formed responses", func() { BeforeEach(func() { server.AppendHandlers( - ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{0}), - ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{1}), - ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{3}), - ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{4}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 0}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 1}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 3}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 4}), ) }) diff --git a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go index d4dd909e..2c683cb8 100644 --- a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go +++ b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go @@ -56,7 +56,9 @@ func (runner *SpecRunner) Run() bool { } runner.reportSuiteWillBegin() - go runner.registerForInterrupts() + signalRegistered := make(chan struct{}) + go runner.registerForInterrupts(signalRegistered) + <-signalRegistered suitePassed := runner.runBeforeSuite() @@ -213,9 +215,10 @@ func (runner *SpecRunner) CurrentSpecSummary() (*types.SpecSummary, bool) { return runner.runningSpec.Summary(runner.suiteID), true } -func (runner *SpecRunner) registerForInterrupts() { +func (runner *SpecRunner) registerForInterrupts(signalRegistered chan struct{}) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) + close(signalRegistered) <-c signal.Stop(c) diff --git a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go index 77272e8b..a4143792 100644 --- a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go @@ -18,7 +18,6 @@ import ( ) var noneFlag = types.FlagTypeNone -var focusedFlag = types.FlagTypeFocused var pendingFlag = types.FlagTypePending var _ = Describe("Spec Runner", func() { @@ -236,6 +235,13 @@ var _ = Describe("Spec Runner", func() { Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(0)) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) }) + + It("should not report a slow test", func() { + summaries := reporter1.SpecSummaries + for _, s := range summaries { + Expect(s.RunTime).To(BeZero()) + } + }) }) }) diff --git a/vendor/github.com/onsi/ginkgo/internal/suite/suite.go b/vendor/github.com/onsi/ginkgo/internal/suite/suite.go index 698a6e56..f311e9a0 100644 --- a/vendor/github.com/onsi/ginkgo/internal/suite/suite.go +++ b/vendor/github.com/onsi/ginkgo/internal/suite/suite.go @@ -149,35 +149,35 @@ func (suite *Suite) PushContainerNode(text string, body func(), flag types.FlagT func (suite *Suite) PushItNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { - suite.failer.Fail("You may only call It from within a Describe or Context", codeLocation) + suite.failer.Fail("You may only call It from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSubjectNode(leafnodes.NewItNode(text, body, flag, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushMeasureNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, samples int) { if suite.running { - suite.failer.Fail("You may only call Measure from within a Describe or Context", codeLocation) + suite.failer.Fail("You may only call Measure from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSubjectNode(leafnodes.NewMeasureNode(text, body, flag, codeLocation, samples, suite.failer, suite.containerIndex)) } func (suite *Suite) PushBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { - suite.failer.Fail("You may only call BeforeEach from within a Describe or Context", codeLocation) + suite.failer.Fail("You may only call BeforeEach from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { - suite.failer.Fail("You may only call JustBeforeEach from within a Describe or Context", codeLocation) + suite.failer.Fail("You may only call JustBeforeEach from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewJustBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { - suite.failer.Fail("You may only call AfterEach from within a Describe or Context", codeLocation) + suite.failer.Fail("You may only call AfterEach from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } diff --git a/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go b/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go index b7bcdbd2..fd2d11dc 100644 --- a/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go +++ b/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go @@ -121,6 +121,7 @@ var _ = Describe("Suite", func() { Ω(description.LineNumber).Should(BeNumerically(">", 50)) Ω(description.LineNumber).Should(BeNumerically("<", 150)) Ω(description.Failed).Should(BeFalse()) + Ω(description.Duration).Should(BeNumerically(">", 0)) }) Measure("should run measurements", func(b Benchmarker) { @@ -152,6 +153,19 @@ var _ = Describe("Suite", func() { "AfterSuite", })) }) + Context("when in an AfterEach block", func() { + AfterEach(func() { + description := CurrentGinkgoTestDescription() + Ω(description.IsMeasurement).Should(BeFalse()) + Ω(description.FileName).Should(ContainSubstring("suite_test.go")) + Ω(description.Failed).Should(BeFalse()) + Ω(description.Duration).Should(BeNumerically(">", 0)) + }) + + It("still provides information about the current test", func() { + Ω(true).To(BeTrue()) + }) + }) Context("when told to randomize all specs", func() { BeforeEach(func() { diff --git a/vendor/github.com/onsi/ginkgo/internal/writer/writer.go b/vendor/github.com/onsi/ginkgo/internal/writer/writer.go index 6b23b1a6..98eca3bd 100644 --- a/vendor/github.com/onsi/ginkgo/internal/writer/writer.go +++ b/vendor/github.com/onsi/ginkgo/internal/writer/writer.go @@ -16,10 +16,11 @@ type WriterInterface interface { } type Writer struct { - buffer *bytes.Buffer - outWriter io.Writer - lock *sync.Mutex - stream bool + buffer *bytes.Buffer + outWriter io.Writer + lock *sync.Mutex + stream bool + redirector io.Writer } func New(outWriter io.Writer) *Writer { @@ -31,6 +32,10 @@ func New(outWriter io.Writer) *Writer { } } +func (w *Writer) AndRedirectTo(writer io.Writer) { + w.redirector = writer +} + func (w *Writer) SetStream(stream bool) { w.lock.Lock() defer w.lock.Unlock() @@ -42,6 +47,9 @@ func (w *Writer) Write(b []byte) (n int, err error) { defer w.lock.Unlock() n, err = w.buffer.Write(b) + if w.redirector != nil { + w.redirector.Write(b) + } if w.stream { return w.outWriter.Write(b) } diff --git a/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go index fb82f70a..ac58dd5f 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go +++ b/vendor/github.com/onsi/ginkgo/reporters/default_reporter.go @@ -66,7 +66,7 @@ func (reporter *DefaultReporter) SpecDidComplete(specSummary *types.SpecSummary) case types.SpecStatePending: reporter.stenographer.AnnouncePendingSpec(specSummary, reporter.config.NoisyPendings && !reporter.config.Succinct) case types.SpecStateSkipped: - reporter.stenographer.AnnounceSkippedSpec(specSummary, reporter.config.Succinct, reporter.config.FullTrace) + reporter.stenographer.AnnounceSkippedSpec(specSummary, reporter.config.Succinct || !reporter.config.NoisySkippings, reporter.config.FullTrace) case types.SpecStateTimedOut: reporter.stenographer.AnnounceSpecTimedOut(specSummary, reporter.config.Succinct, reporter.config.FullTrace) case types.SpecStatePanicked: diff --git a/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go b/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go index 01528448..2dcf276d 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go +++ b/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go @@ -28,6 +28,7 @@ var _ = Describe("DefaultReporter", func() { NoColor: false, SlowSpecThreshold: 0.1, NoisyPendings: false, + NoisySkippings: false, Verbose: true, FullTrace: true, } @@ -258,8 +259,8 @@ var _ = Describe("DefaultReporter", func() { spec.State = types.SpecStateSkipped }) - It("should announce the skipped spec", func() { - Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, false, true))) + It("should announce the skipped spec, succinctly", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, true, true))) }) }) @@ -311,6 +312,24 @@ var _ = Describe("DefaultReporter", func() { }) }) + Context("in noisy skippings mode", func() { + BeforeEach(func() { + reporterConfig.Succinct = false + reporterConfig.NoisySkippings = true + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + }) + + Context("When the spec is skipped", func() { + BeforeEach(func() { + spec.State = types.SpecStateSkipped + }) + + It("should announce the skipped spec, noisily", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, false, true))) + }) + }) + }) + Context("in succinct mode", func() { BeforeEach(func() { reporterConfig.Succinct = true diff --git a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go index 89b03513..65b8964e 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go +++ b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go @@ -11,6 +11,7 @@ package reporters import ( "encoding/xml" "fmt" + "math" "os" "strings" @@ -21,8 +22,10 @@ import ( type JUnitTestSuite struct { XMLName xml.Name `xml:"testsuite"` TestCases []JUnitTestCase `xml:"testcase"` + Name string `xml:"name,attr"` Tests int `xml:"tests,attr"` Failures int `xml:"failures,attr"` + Errors int `xml:"errors,attr"` Time float64 `xml:"time,attr"` } @@ -59,6 +62,7 @@ func NewJUnitReporter(filename string) *JUnitReporter { func (reporter *JUnitReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { reporter.suite = JUnitTestSuite{ + Name: summary.SuiteDescription, TestCases: []JUnitTestCase{}, } reporter.testSuiteName = summary.SuiteDescription @@ -117,8 +121,9 @@ func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) { func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun - reporter.suite.Time = summary.RunTime.Seconds() + reporter.suite.Time = math.Trunc(summary.RunTime.Seconds() * 1000 / 1000) reporter.suite.Failures = summary.NumberOfFailedSpecs + reporter.suite.Errors = 0 file, err := os.Create(reporter.filename) if err != nil { fmt.Printf("Failed to create JUnit report file: %s\n\t%s", reporter.filename, err.Error()) diff --git a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go index 37a6daab..605169cb 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go +++ b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go @@ -19,6 +19,7 @@ var _ = Describe("JUnit Reporter", func() { outputFile string reporter Reporter ) + testSuiteTime := 12345 * time.Millisecond readOutputFile := func() reporters.JUnitTestSuite { bytes, err := ioutil.ReadFile(outputFile) @@ -70,15 +71,17 @@ var _ = Describe("JUnit Reporter", func() { reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, - RunTime: 10 * time.Second, + RunTime: testSuiteTime, }) }) It("should record the test as passing", func() { output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) Ω(output.Tests).Should(Equal(1)) Ω(output.Failures).Should(Equal(0)) - Ω(output.Time).Should(Equal(10.0)) + Ω(output.Time).Should(Equal(12.0)) + Ω(output.Errors).Should(Equal(0)) Ω(output.TestCases).Should(HaveLen(1)) Ω(output.TestCases[0].Name).Should(Equal("A B C")) Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) @@ -106,15 +109,17 @@ var _ = Describe("JUnit Reporter", func() { reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, - RunTime: 10 * time.Second, + RunTime: testSuiteTime, }) }) It("should record the test as having failed", func() { output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) Ω(output.Tests).Should(Equal(1)) Ω(output.Failures).Should(Equal(1)) - Ω(output.Time).Should(Equal(10.0)) + Ω(output.Time).Should(Equal(12.0)) + Ω(output.Errors).Should(Equal(0)) Ω(output.TestCases[0].Name).Should(Equal("BeforeSuite")) Ω(output.TestCases[0].Time).Should(Equal(3.0)) Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) @@ -144,15 +149,17 @@ var _ = Describe("JUnit Reporter", func() { reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, - RunTime: 10 * time.Second, + RunTime: testSuiteTime, }) }) It("should record the test as having failed", func() { output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) Ω(output.Tests).Should(Equal(1)) Ω(output.Failures).Should(Equal(1)) - Ω(output.Time).Should(Equal(10.0)) + Ω(output.Time).Should(Equal(12.0)) + Ω(output.Errors).Should(Equal(0)) Ω(output.TestCases[0].Name).Should(Equal("AfterSuite")) Ω(output.TestCases[0].Time).Should(Equal(3.0)) Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) @@ -194,15 +201,17 @@ var _ = Describe("JUnit Reporter", func() { reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, - RunTime: 10 * time.Second, + RunTime: testSuiteTime, }) }) It("should record test as failing", func() { output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) Ω(output.Tests).Should(Equal(1)) Ω(output.Failures).Should(Equal(1)) - Ω(output.Time).Should(Equal(10.0)) + Ω(output.Time).Should(Equal(12.0)) + Ω(output.Errors).Should(Equal(0)) Ω(output.TestCases[0].Name).Should(Equal("A B C")) Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) Ω(output.TestCases[0].FailureMessage.Type).Should(Equal(specStateCase.message)) @@ -230,7 +239,7 @@ var _ = Describe("JUnit Reporter", func() { reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, - RunTime: 10 * time.Second, + RunTime: testSuiteTime, }) }) @@ -238,7 +247,8 @@ var _ = Describe("JUnit Reporter", func() { output := readOutputFile() Ω(output.Tests).Should(Equal(1)) Ω(output.Failures).Should(Equal(0)) - Ω(output.Time).Should(Equal(10.0)) + Ω(output.Time).Should(Equal(12.0)) + Ω(output.Errors).Should(Equal(0)) Ω(output.TestCases[0].Name).Should(Equal("A B C")) Ω(output.TestCases[0].Skipped).ShouldNot(BeNil()) }) diff --git a/vendor/github.com/onsi/ginkgo/reporters/stenographer/stenographer.go b/vendor/github.com/onsi/ginkgo/reporters/stenographer/stenographer.go index fefd3e18..601c74d6 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/stenographer/stenographer.go +++ b/vendor/github.com/onsi/ginkgo/reporters/stenographer/stenographer.go @@ -12,7 +12,6 @@ import ( "runtime" "strings" - "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" "github.com/onsi/ginkgo/types" ) @@ -62,7 +61,7 @@ type Stenographer interface { SummarizeFailures(summaries []*types.SpecSummary) } -func New(color bool, enableFlakes bool) Stenographer { +func New(color bool, enableFlakes bool, writer io.Writer) Stenographer { denoter := "•" if runtime.GOOS == "windows" { denoter = "+" @@ -72,7 +71,7 @@ func New(color bool, enableFlakes bool) Stenographer { denoter: denoter, cursorState: cursorStateTop, enableFlakes: enableFlakes, - w: colorable.NewColorableStdout(), + w: writer, } } @@ -178,7 +177,7 @@ func (s *consoleStenographer) AnnounceSpecRunCompletion(summary *types.SuiteSumm } s.print(0, - "%s -- %s | %s | %s | %s ", + "%s -- %s | %s | %s | %s\n", status, s.colorize(greenColor+boldStyle, "%d Passed", summary.NumberOfPassedSpecs), s.colorize(redColor+boldStyle, "%d Failed", summary.NumberOfFailedSpecs)+flakes, diff --git a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go index 657dfe72..36ee2a60 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go +++ b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter.go @@ -10,10 +10,11 @@ package reporters import ( "fmt" - "github.com/onsi/ginkgo/config" - "github.com/onsi/ginkgo/types" "io" "strings" + + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/types" ) const ( diff --git a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go index de877321..b45d5db0 100644 --- a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go +++ b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go @@ -3,13 +3,14 @@ package reporters_test import ( "bytes" "fmt" + "time" + . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" - "time" ) var _ = Describe("TeamCity Reporter", func() { diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml index 61d0f41f..783fb3b4 100644 --- a/vendor/github.com/onsi/gomega/.travis.yml +++ b/vendor/github.com/onsi/gomega/.travis.yml @@ -1,12 +1,16 @@ language: go go: - - 1.6 - - 1.7 - - 1.8 + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x install: - - go get -v ./... + - env GO111MODULE=on go get -v ./... + - env GO111MODULE=on go build ./... - go get github.com/onsi/ginkgo - go install github.com/onsi/ginkgo/ginkgo -script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --failOnPending --randomizeSuites --race +script: env GO111MODULE=on $HOME/gopath/bin/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race && env GO111MODULE=on go vet diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md index a3e8ee44..f2aaea4e 100644 --- a/vendor/github.com/onsi/gomega/CHANGELOG.md +++ b/vendor/github.com/onsi/gomega/CHANGELOG.md @@ -1,4 +1,48 @@ -## HEAD +## 1.4.2 + +### Fixes: + +- Add go.mod and go.sum files to define the gomega go module [f3de367, a085d30] +- Work around go vet issue with Go v1.11 (#300) [40dd6ad] +- Better output when using with go XUnit-style tests, fixes #255 (#297) [29a4b97] +- Fix MatchJSON fail to parse json.RawMessage (#298) [ae19f1b] +- show threshold in failure message of BeNumericallyMatcher (#293) [4bbecc8] + +## 1.4.1 + +### Fixes: + +- Update documentation formatting and examples (#289) [9be8410] +- allow 'Receive' matcher to be used with concrete types (#286) [41673fd] +- Fix data race in ghttp server (#283) [7ac6b01] +- Travis badge should only show master [cc102ab] + +## 1.4.0 + +### Features +- Make string pretty diff user configurable (#273) [eb112ce, 649b44d] + +### Fixes +- Use httputil.DumpRequest to pretty-print unhandled requests (#278) [a4ff0fc, b7d1a52] +- fix typo floa32 > float32 (#272) [041ae3b, 6e33911] +- Fix link to documentation on adding your own matchers (#270) [bb2c830, fcebc62] +- Use setters and getters to avoid race condition (#262) [13057c3, a9c79f1] +- Avoid sending a signal if the process is not alive (#259) [b8043e5, 4fc1762] +- Improve message from AssignableToTypeOf when expected value is nil (#281) [9c1fb20] + +## 1.3.0 + +Improvements: + +- The `Equal` matcher matches byte slices more performantly. +- Improved how `MatchError` matches error strings. +- `MatchXML` ignores the order of xml node attributes. +- Improve support for XUnit style golang tests. ([#254](https://github.com/onsi/gomega/issues/254)) + +Bug Fixes: + +- Diff generation now handles multi-byte sequences correctly. +- Multiple goroutines can now call `gexec.Build` concurrently. ## 1.2.0 diff --git a/vendor/github.com/onsi/gomega/CONTRIBUTING.md b/vendor/github.com/onsi/gomega/CONTRIBUTING.md index 73d4020e..0d7a0992 100644 --- a/vendor/github.com/onsi/gomega/CONTRIBUTING.md +++ b/vendor/github.com/onsi/gomega/CONTRIBUTING.md @@ -6,6 +6,9 @@ Your contributions to Gomega are essential for its long-term maintenance and imp - Ensure adequate test coverage: - Make sure to add appropriate unit tests - Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR + - Please run following linter locally `go vet ./...` and make sure output does not contain any warnings - Update the documentation. In addition to standard `godoc` comments Gomega has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR. -Thanks for supporting Gomega! \ No newline at end of file +If you're a committer, check out RELEASING.md to learn how to cut a release. + +Thanks for supporting Gomega! diff --git a/vendor/github.com/onsi/gomega/README.md b/vendor/github.com/onsi/gomega/README.md index 159be359..76aa6b55 100644 --- a/vendor/github.com/onsi/gomega/README.md +++ b/vendor/github.com/onsi/gomega/README.md @@ -1,6 +1,6 @@ ![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png) -[![Build Status](https://travis-ci.org/onsi/gomega.svg)](https://travis-ci.org/onsi/gomega) +[![Build Status](https://travis-ci.org/onsi/gomega.svg?branch=master)](https://travis-ci.org/onsi/gomega) Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers). diff --git a/vendor/github.com/onsi/gomega/RELEASING.md b/vendor/github.com/onsi/gomega/RELEASING.md new file mode 100644 index 00000000..998d64ee --- /dev/null +++ b/vendor/github.com/onsi/gomega/RELEASING.md @@ -0,0 +1,12 @@ +A Gomega release is a tagged sha and a GitHub release. To cut a release: + +1. Ensure CHANGELOG.md is up to date. + - Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release + - Categorize the changes into + - Breaking Changes (requires a major version) + - New Features (minor version) + - Fixes (fix version) + - Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact) +2. Update GOMEGA_VERSION in `gomega_dsl.go` +3. Push a commit with the version number as the commit message (e.g. `v1.3.0`) +4. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes. diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go index e206ee59..6559525f 100644 --- a/vendor/github.com/onsi/gomega/format/format.go +++ b/vendor/github.com/onsi/gomega/format/format.go @@ -30,6 +30,9 @@ Set PrintContextObjects = true to enable printing of the context internals. */ var PrintContextObjects = false +// TruncatedDiff choose if we should display a truncated pretty diff or not +var TruncatedDiff = true + // Ctx interface defined here to keep backwards compatability with go < 1.7 // It matches the context.Context interface type Ctx interface { @@ -82,7 +85,7 @@ to equal | */ func MessageWithDiff(actual, message, expected string) string { - if len(actual) >= truncateThreshold && len(expected) >= truncateThreshold { + if TruncatedDiff && len(actual) >= truncateThreshold && len(expected) >= truncateThreshold { diffPoint := findFirstMismatch(actual, expected) formattedActual := truncateAndFormat(actual, diffPoint) formattedExpected := truncateAndFormat(expected, diffPoint) @@ -123,7 +126,7 @@ func findFirstMismatch(a, b string) int { bSlice := strings.Split(b, "") for index, str := range aSlice { - if index > len(b) - 1 { + if index > len(bSlice)-1 { return index } if str != bSlice[index] { diff --git a/vendor/github.com/onsi/gomega/format/format_test.go b/vendor/github.com/onsi/gomega/format/format_test.go index a1a90316..9ea78137 100644 --- a/vendor/github.com/onsi/gomega/format/format_test.go +++ b/vendor/github.com/onsi/gomega/format/format_test.go @@ -119,13 +119,13 @@ var _ = Describe("Format", func() { Describe("Message", func() { Context("with only an actual value", func() { It("should print out an indented formatted representation of the value and the message", func() { - Ω(Message(3, "to be three.")).Should(Equal("Expected\n : 3\nto be three.")) + Expect(Message(3, "to be three.")).Should(Equal("Expected\n : 3\nto be three.")) }) }) Context("with an actual and an expected value", func() { It("should print out an indented formatted representatino of both values, and the message", func() { - Ω(Message(3, "to equal", 4)).Should(Equal("Expected\n : 3\nto equal\n : 4")) + Expect(Message(3, "to equal", 4)).Should(Equal("Expected\n : 3\nto equal\n : 4")) }) }) }) @@ -135,63 +135,87 @@ var _ = Describe("Format", func() { stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedLongStringFailureMessage)) + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedLongStringFailureMessage)) }) It("truncates the start of long strings that differ only at their end", func() { stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab" stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz" - Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedStartStringFailureMessage)) + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedStartStringFailureMessage)) }) It("truncates the start of long strings that differ only in length", func() { smallString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" largeString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - Ω(MessageWithDiff(largeString, "to equal", smallString)).Should(Equal(expectedTruncatedStartSizeFailureMessage)) - Ω(MessageWithDiff(smallString, "to equal", largeString)).Should(Equal(expectedTruncatedStartSizeSwappedFailureMessage)) + Expect(MessageWithDiff(largeString, "to equal", smallString)).Should(Equal(expectedTruncatedStartSizeFailureMessage)) + Expect(MessageWithDiff(smallString, "to equal", largeString)).Should(Equal(expectedTruncatedStartSizeSwappedFailureMessage)) }) It("truncates the end of long strings that differ only at their start", func() { stringWithB := "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" stringWithZ := "zaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedEndStringFailureMessage)) + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedEndStringFailureMessage)) + }) + + It("handles multi-byte sequences correctly", func() { + stringA := "• abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1" + stringB := "• abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + + Expect(MessageWithDiff(stringA, "to equal", stringB)).Should(Equal(expectedTruncatedMultiByteFailureMessage)) + }) + + Context("With truncated diff disabled", func() { + BeforeEach(func() { + TruncatedDiff = false + }) + + AfterEach(func() { + TruncatedDiff = true + }) + + It("should show the full diff", func() { + stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedFullFailureDiff)) + }) }) }) Describe("IndentString", func() { It("should indent the string", func() { - Ω(IndentString("foo\n bar\nbaz", 2)).Should(Equal(" foo\n bar\n baz")) + Expect(IndentString("foo\n bar\nbaz", 2)).Should(Equal(" foo\n bar\n baz")) }) }) Describe("Object", func() { Describe("formatting boolean values", func() { It("should give the type and format values correctly", func() { - Ω(Object(true, 1)).Should(match("bool", "true")) - Ω(Object(false, 1)).Should(match("bool", "false")) + Expect(Object(true, 1)).Should(match("bool", "true")) + Expect(Object(false, 1)).Should(match("bool", "false")) }) }) Describe("formatting numbers", func() { It("should give the type and format values correctly", func() { - Ω(Object(int(3), 1)).Should(match("int", "3")) - Ω(Object(int8(3), 1)).Should(match("int8", "3")) - Ω(Object(int16(3), 1)).Should(match("int16", "3")) - Ω(Object(int32(3), 1)).Should(match("int32", "3")) - Ω(Object(int64(3), 1)).Should(match("int64", "3")) + Expect(Object(int(3), 1)).Should(match("int", "3")) + Expect(Object(int8(3), 1)).Should(match("int8", "3")) + Expect(Object(int16(3), 1)).Should(match("int16", "3")) + Expect(Object(int32(3), 1)).Should(match("int32", "3")) + Expect(Object(int64(3), 1)).Should(match("int64", "3")) - Ω(Object(uint(3), 1)).Should(match("uint", "3")) - Ω(Object(uint8(3), 1)).Should(match("uint8", "3")) - Ω(Object(uint16(3), 1)).Should(match("uint16", "3")) - Ω(Object(uint32(3), 1)).Should(match("uint32", "3")) - Ω(Object(uint64(3), 1)).Should(match("uint64", "3")) + Expect(Object(uint(3), 1)).Should(match("uint", "3")) + Expect(Object(uint8(3), 1)).Should(match("uint8", "3")) + Expect(Object(uint16(3), 1)).Should(match("uint16", "3")) + Expect(Object(uint32(3), 1)).Should(match("uint32", "3")) + Expect(Object(uint64(3), 1)).Should(match("uint64", "3")) }) It("should handle uintptr differently", func() { - Ω(Object(uintptr(3), 1)).Should(match("uintptr", "0x3")) + Expect(Object(uintptr(3), 1)).Should(match("uintptr", "0x3")) }) }) @@ -200,14 +224,14 @@ var _ = Describe("Format", func() { c := make(chan<- bool, 3) c <- true c <- false - Ω(Object(c, 1)).Should(match("chan<- bool | len:2, cap:3", "%v", c)) + Expect(Object(c, 1)).Should(match("chan<- bool | len:2, cap:3", "%v", c)) }) }) Describe("formatting strings", func() { It("should give the type and format values correctly", func() { s := "a\nb\nc" - Ω(Object(s, 1)).Should(match("string", `a + Expect(Object(s, 1)).Should(match("string", `a b c`)) }) @@ -217,13 +241,13 @@ var _ = Describe("Format", func() { Context("when the slice is made of printable bytes", func() { It("should present it as string", func() { b := []byte("a b c") - Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`)) + Expect(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`)) }) }) Context("when the slice contains non-printable bytes", func() { It("should present it as slice", func() { b := []byte("a b c\n\x01\x02\x03\xff\x1bH") - Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`)) + Expect(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`)) }) }) }) @@ -233,14 +257,14 @@ var _ = Describe("Format", func() { f := func(a string, b []int) ([]byte, error) { return []byte("abc"), nil } - Ω(Object(f, 1)).Should(match("func(string, []int) ([]uint8, error)", "%v", f)) + Expect(Object(f, 1)).Should(match("func(string, []int) ([]uint8, error)", "%v", f)) }) }) Describe("formatting pointers", func() { It("should give the type and dereference the value to format it correctly", func() { a := 3 - Ω(Object(&a, 1)).Should(match(fmt.Sprintf("*int | %p", &a), "3")) + Expect(Object(&a, 1)).Should(match(fmt.Sprintf("*int | %p", &a), "3")) }) Context("when there are pointers to pointers...", func() { @@ -253,14 +277,14 @@ var _ = Describe("Format", func() { c = &b d = &c - Ω(Object(d, 1)).Should(match(fmt.Sprintf("***int | %p", d), "3")) + Expect(Object(d, 1)).Should(match(fmt.Sprintf("***int | %p", d), "3")) }) }) Context("when the pointer points to nil", func() { It("should say nil and not explode", func() { var a *AStruct - Ω(Object(a, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) + Expect(Object(a, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) }) }) }) @@ -268,13 +292,13 @@ var _ = Describe("Format", func() { Describe("formatting arrays", func() { It("should give the type and format values correctly", func() { w := [3]string{"Jed Bartlet", "Toby Ziegler", "CJ Cregg"} - Ω(Object(w, 1)).Should(match("[3]string", `["Jed Bartlet", "Toby Ziegler", "CJ Cregg"]`)) + Expect(Object(w, 1)).Should(match("[3]string", `["Jed Bartlet", "Toby Ziegler", "CJ Cregg"]`)) }) Context("with byte arrays", func() { It("should give the type and format values correctly", func() { w := [3]byte{17, 28, 19} - Ω(Object(w, 1)).Should(match("[3]uint8", `[17, 28, 19]`)) + Expect(Object(w, 1)).Should(match("[3]uint8", `[17, 28, 19]`)) }) }) }) @@ -282,7 +306,7 @@ var _ = Describe("Format", func() { Describe("formatting slices", func() { It("should include the length and capacity in the type information", func() { s := make([]bool, 3, 4) - Ω(Object(s, 1)).Should(match("[]bool | len:3, cap:4", "[false, false, false]")) + Expect(Object(s, 1)).Should(match("[]bool | len:3, cap:4", "[false, false, false]")) }) Context("when the slice contains long entries", func() { @@ -293,7 +317,7 @@ var _ = Describe("Format", func() { "Toby Ziegler", "CJ Cregg", ]` - Ω(Object(w, 1)).Should(match("[]string | len:3, cap:3", expected)) + Expect(Object(w, 1)).Should(match("[]string | len:3, cap:3", expected)) }) }) }) @@ -303,7 +327,7 @@ var _ = Describe("Format", func() { m := make(map[int]bool, 5) m[3] = true m[4] = false - Ω(Object(m, 1)).Should(matchRegexp(`map\[int\]bool \| len:2`, hashMatchingRegexp("3: true", "4: false"))) + Expect(Object(m, 1)).Should(matchRegexp(`map\[int\]bool \| len:2`, hashMatchingRegexp("3: true", "4: false"))) }) Context("when the slice contains long entries", func() { @@ -317,7 +341,7 @@ var _ = Describe("Format", func() { ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), }` - Ω(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected)) + Expect(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected)) }) }) }) @@ -332,7 +356,7 @@ var _ = Describe("Format", func() { secret: 1983, } - Ω(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`)) + Expect(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`)) }) Context("when the struct contains long entries", func() { @@ -345,7 +369,7 @@ var _ = Describe("Format", func() { secret: 3, } - Ω(Object(s, 1)).Should(match(fmt.Sprintf("*format_test.SimpleStruct | %p", s), `{ + Expect(Object(s, 1)).Should(match(fmt.Sprintf("*format_test.SimpleStruct | %p", s), `{ Name: "Mithrandir Gandalf Greyhame", Enumeration: 2021, Veritas: true, @@ -358,23 +382,23 @@ var _ = Describe("Format", func() { Describe("formatting nil values", func() { It("should print out nil", func() { - Ω(Object(nil, 1)).Should(match("nil", "nil")) + Expect(Object(nil, 1)).Should(match("nil", "nil")) var typedNil *AStruct - Ω(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) + Expect(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) var c chan<- bool - Ω(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil")) + Expect(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil")) var s []string - Ω(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil")) + Expect(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil")) var m map[string]bool - Ω(Object(m, 1)).Should(match("map[string]bool | len:0", "nil")) + Expect(Object(m, 1)).Should(match("map[string]bool | len:0", "nil")) }) }) Describe("formatting aliased types", func() { It("should print out the correct alias type", func() { - Ω(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`)) - Ω(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`)) - Ω(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3")) + Expect(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`)) + Expect(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`)) + Expect(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3")) }) }) @@ -408,14 +432,14 @@ var _ = Describe("Format", func() { (17: "some substantially longer chunks of data"|1138: "that should make things wrap"), }, }` - Ω(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected)) + Expect(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected)) }) }) Describe("formatting times", func() { It("should format time as RFC3339", func() { t := time.Date(2016, 10, 31, 9, 57, 23, 12345, time.UTC) - Ω(Object(t, 1)).Should(match("time.Time", `2016-10-31T09:57:23.000012345Z`)) + Expect(Object(t, 1)).Should(match("time.Time", `2016-10-31T09:57:23.000012345Z`)) }) }) }) @@ -463,7 +487,7 @@ var _ = Describe("Format", func() { interfaceValue: {"a key": 17}, }`, s.chanValue, s.funcValue, hashMatchingRegexp(`"a key": 20`, `"b key": 30`)) - Ω(Object(s, 1)).Should(matchRegexp(`format_test\.SecretiveStruct`, expected)) + Expect(Object(s, 1)).Should(matchRegexp(`format_test\.SecretiveStruct`, expected)) }) }) @@ -477,7 +501,7 @@ var _ = Describe("Format", func() { outerHash["map"] = innerHash expected := hashMatchingRegexp(`"integer": 2`, `"map": {"inner": 3}`) - Ω(Object(outerHash, 1)).Should(matchRegexp(`map\[string\]interface {} \| len:2`, expected)) + Expect(Object(outerHash, 1)).Should(matchRegexp(`map\[string\]interface {} \| len:2`, expected)) }) }) @@ -486,7 +510,7 @@ var _ = Describe("Format", func() { m := map[string]interface{}{} m["integer"] = 2 m["map"] = m - Ω(Object(m, 1)).Should(ContainSubstring("...")) + Expect(Object(m, 1)).Should(ContainSubstring("...")) }) It("really should not go crazy...", func() { @@ -498,7 +522,7 @@ var _ = Describe("Format", func() { complexObject.Value = make(map[interface{}]int) complexObject.Value[&complexObject] = 2 - Ω(Object(complexObject, 1)).Should(ContainSubstring("...")) + Expect(Object(complexObject, 1)).Should(ContainSubstring("...")) }) }) @@ -513,13 +537,13 @@ var _ = Describe("Format", func() { Context("when passed a GoStringer", func() { It("should use what GoString() returns", func() { - Ω(Object(GoStringer{}, 1)).Should(ContainSubstring(": go-string")) + Expect(Object(GoStringer{}, 1)).Should(ContainSubstring(": go-string")) }) }) Context("when passed a stringer", func() { It("should use what String() returns", func() { - Ω(Object(Stringer{}, 1)).Should(ContainSubstring(": string")) + Expect(Object(Stringer{}, 1)).Should(ContainSubstring(": string")) }) }) }) @@ -535,11 +559,11 @@ var _ = Describe("Format", func() { objWithContext := structWithContext{Value: "some-value", Context: &context} It("Suppresses the content by default", func() { - Ω(Object(objWithContext, 1)).Should(ContainSubstring("")) + Expect(Object(objWithContext, 1)).Should(ContainSubstring("")) }) It("Doesn't supress the context if it's the object being printed", func() { - Ω(Object(context, 1)).ShouldNot(MatchRegexp("^.*$")) + Expect(Object(context, 1)).ShouldNot(MatchRegexp("^.*$")) }) Context("PrintContextObjects is set", func() { @@ -552,7 +576,7 @@ var _ = Describe("Format", func() { }) It("Prints the context", func() { - Ω(Object(objWithContext, 1)).ShouldNot(ContainSubstring("")) + Expect(Object(objWithContext, 1)).ShouldNot(ContainSubstring("")) }) }) }) @@ -588,3 +612,16 @@ Expected to equal | : "...aaaaa" `) +var expectedTruncatedMultiByteFailureMessage = strings.TrimSpace(` +Expected + : "...tuvwxyz1" +to equal | + : "...tuvwxyz" +`) + +var expectedFullFailureDiff = strings.TrimSpace(` +Expected + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +to equal + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +`) diff --git a/vendor/github.com/onsi/gomega/gbytes/buffer_test.go b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go index 655a3474..9d4e8279 100644 --- a/vendor/github.com/onsi/gomega/gbytes/buffer_test.go +++ b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go @@ -33,20 +33,20 @@ var _ = Describe("Buffer", func() { It("should return everything that's been written", func() { buffer.Write([]byte("abc")) buffer.Write([]byte("def")) - Ω(buffer.Contents()).Should(Equal([]byte("abcdef"))) + Expect(buffer.Contents()).Should(Equal([]byte("abcdef"))) - Ω(buffer).Should(Say("bcd")) - Ω(buffer.Contents()).Should(Equal([]byte("abcdef"))) + Expect(buffer).Should(Say("bcd")) + Expect(buffer.Contents()).Should(Equal([]byte("abcdef"))) }) }) Describe("creating a buffer with bytes", func() { It("should create the buffer with the cursor set to the beginning", func() { buffer := BufferWithBytes([]byte("abcdef")) - Ω(buffer.Contents()).Should(Equal([]byte("abcdef"))) - Ω(buffer).Should(Say("abc")) - Ω(buffer).ShouldNot(Say("abc")) - Ω(buffer).Should(Say("def")) + Expect(buffer.Contents()).Should(Equal([]byte("abcdef"))) + Expect(buffer).Should(Say("abc")) + Expect(buffer).ShouldNot(Say("abc")) + Expect(buffer).Should(Say("def")) }) }) @@ -56,7 +56,7 @@ var _ = Describe("Buffer", func() { reader := bytes.NewBuffer([]byte("abcdef")) buffer := BufferReader(reader) Eventually(buffer).Should(Say("abc")) - Ω(buffer).ShouldNot(Say("abc")) + Expect(buffer).ShouldNot(Say("abc")) Eventually(buffer).Should(Say("def")) Eventually(buffer.Closed).Should(BeTrue()) }) @@ -72,7 +72,7 @@ var _ = Describe("Buffer", func() { failures := InterceptGomegaFailures(func() { Eventually(buffer, 100*time.Millisecond).Should(Say("abc")) }) - Ω(failures).ShouldNot(BeEmpty()) + Expect(failures).ShouldNot(BeEmpty()) fastReader := SlowReader{ R: bytes.NewBuffer([]byte("abcdef")), @@ -91,19 +91,19 @@ var _ = Describe("Buffer", func() { dest := make([]byte, 3) n, err := buffer.Read(dest) - Ω(err).ShouldNot(HaveOccurred()) - Ω(n).Should(Equal(3)) - Ω(string(dest)).Should(Equal("abc")) + Expect(err).ShouldNot(HaveOccurred()) + Expect(n).Should(Equal(3)) + Expect(string(dest)).Should(Equal("abc")) dest = make([]byte, 3) n, err = buffer.Read(dest) - Ω(err).ShouldNot(HaveOccurred()) - Ω(n).Should(Equal(2)) - Ω(string(dest[:n])).Should(Equal("de")) + Expect(err).ShouldNot(HaveOccurred()) + Expect(n).Should(Equal(2)) + Expect(string(dest[:n])).Should(Equal("de")) n, err = buffer.Read(dest) - Ω(err).Should(Equal(io.EOF)) - Ω(n).Should(Equal(0)) + Expect(err).Should(Equal(io.EOF)) + Expect(n).Should(Equal(0)) }) Context("after the buffer has been closed", func() { @@ -114,8 +114,8 @@ var _ = Describe("Buffer", func() { dest := make([]byte, 3) n, err := buffer.Read(dest) - Ω(err).Should(HaveOccurred()) - Ω(n).Should(Equal(0)) + Expect(err).Should(HaveOccurred()) + Expect(n).Should(Equal(0)) }) }) }) @@ -137,7 +137,7 @@ var _ = Describe("Buffer", func() { Fail("should not have gotten here") } - Ω(gotIt).Should(BeTrue()) + Expect(gotIt).Should(BeTrue()) Eventually(A).Should(BeClosed()) buffer.Write([]byte("f")) @@ -150,8 +150,8 @@ var _ = Describe("Buffer", func() { It("should fast-forward the buffer upon detection", func(done Done) { buffer.Write([]byte("abcde")) <-buffer.Detect("abc") - Ω(buffer).ShouldNot(Say("abc")) - Ω(buffer).Should(Say("de")) + Expect(buffer).ShouldNot(Say("abc")) + Expect(buffer).Should(Say("de")) close(done) }) @@ -159,10 +159,10 @@ var _ = Describe("Buffer", func() { buffer.Write([]byte("abcde")) A := buffer.Detect("abc") time.Sleep(20 * time.Millisecond) //give the goroutine a chance to detect and write to the channel - Ω(buffer).Should(Say("abcd")) + Expect(buffer).Should(Say("abcd")) <-A - Ω(buffer).ShouldNot(Say("d")) - Ω(buffer).Should(Say("e")) + Expect(buffer).ShouldNot(Say("d")) + Expect(buffer).Should(Say("e")) Eventually(A).Should(BeClosed()) close(done) }) @@ -175,7 +175,7 @@ var _ = Describe("Buffer", func() { Eventually(A).Should(BeClosed()) Eventually(B).Should(BeClosed()) - Ω(buffer).Should(Say("bcde")) + Expect(buffer).Should(Say("bcde")) <-buffer.Detect("f") close(done) }) @@ -184,22 +184,22 @@ var _ = Describe("Buffer", func() { Describe("closing the buffer", func() { It("should error when further write attempts are made", func() { _, err := buffer.Write([]byte("abc")) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) buffer.Close() _, err = buffer.Write([]byte("def")) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) - Ω(buffer.Contents()).Should(Equal([]byte("abc"))) + Expect(buffer.Contents()).Should(Equal([]byte("abc"))) }) It("should be closed", func() { - Ω(buffer.Closed()).Should(BeFalse()) + Expect(buffer.Closed()).Should(BeFalse()) buffer.Close() - Ω(buffer.Closed()).Should(BeTrue()) + Expect(buffer.Closed()).Should(BeTrue()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go b/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go index 2c74545d..3da97349 100644 --- a/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go +++ b/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go @@ -68,7 +68,7 @@ var _ = Describe("Io Wrappers", func() { }) It("returns with no error", func() { - Ω(timeoutCloser.Close()).Should(Succeed()) + Expect(timeoutCloser.Close()).Should(Succeed()) }) }) @@ -78,7 +78,7 @@ var _ = Describe("Io Wrappers", func() { }) It("returns the error", func() { - Ω(timeoutCloser.Close()).Should(MatchError("boom")) + Expect(timeoutCloser.Close()).Should(MatchError("boom")) }) }) @@ -91,7 +91,7 @@ var _ = Describe("Io Wrappers", func() { }) It("returns ErrTimeout", func() { - Ω(timeoutCloser.Close()).Should(MatchError(ErrTimeout)) + Expect(timeoutCloser.Close()).Should(MatchError(ErrTimeout)) }) }) }) @@ -112,9 +112,9 @@ var _ = Describe("Io Wrappers", func() { It("returns with no error", func() { p := make([]byte, 5) n, err := timeoutReader.Read(p) - Ω(n).Should(Equal(5)) - Ω(err).ShouldNot(HaveOccurred()) - Ω(p).Should(Equal([]byte("aaaaa"))) + Expect(n).Should(Equal(5)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(p).Should(Equal([]byte("aaaaa"))) }) }) @@ -126,7 +126,7 @@ var _ = Describe("Io Wrappers", func() { It("returns the error", func() { p := make([]byte, 5) _, err := timeoutReader.Read(p) - Ω(err).Should(MatchError("boom")) + Expect(err).Should(MatchError("boom")) }) }) @@ -138,7 +138,7 @@ var _ = Describe("Io Wrappers", func() { It("returns ErrTimeout", func() { p := make([]byte, 5) _, err := timeoutReader.Read(p) - Ω(err).Should(MatchError(ErrTimeout)) + Expect(err).Should(MatchError(ErrTimeout)) }) }) }) @@ -158,8 +158,8 @@ var _ = Describe("Io Wrappers", func() { It("returns with no error", func() { n, err := timeoutWriter.Write([]byte("aaaaa")) - Ω(n).Should(Equal(5)) - Ω(err).ShouldNot(HaveOccurred()) + Expect(n).Should(Equal(5)) + Expect(err).ShouldNot(HaveOccurred()) }) }) @@ -170,7 +170,7 @@ var _ = Describe("Io Wrappers", func() { It("returns the error", func() { _, err := timeoutWriter.Write([]byte("aaaaa")) - Ω(err).Should(MatchError("boom")) + Expect(err).Should(MatchError("boom")) }) }) @@ -181,7 +181,7 @@ var _ = Describe("Io Wrappers", func() { It("returns ErrTimeout", func() { _, err := timeoutWriter.Write([]byte("aaaaa")) - Ω(err).Should(MatchError(ErrTimeout)) + Expect(err).Should(MatchError(ErrTimeout)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go index cbc266c5..14317182 100644 --- a/vendor/github.com/onsi/gomega/gbytes/say_matcher.go +++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go @@ -15,7 +15,7 @@ type BufferProvider interface { /* Say is a Gomega matcher that operates on gbytes.Buffers: - Ω(buffer).Should(Say("something")) + Expect(buffer).Should(Say("something")) will succeed if the unread portion of the buffer matches the regular expression "something". @@ -36,12 +36,11 @@ In such cases, Say simply operates on the *gbytes.Buffer returned by Buffer() If the buffer is closed, the Say matcher will tell Eventually to abort. */ func Say(expected string, args ...interface{}) *sayMatcher { - formattedRegexp := expected if len(args) > 0 { - formattedRegexp = fmt.Sprintf(expected, args...) + expected = fmt.Sprintf(expected, args...) } return &sayMatcher{ - re: regexp.MustCompile(formattedRegexp), + re: regexp.MustCompile(expected), } } diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go index 63fb3b3b..0055d4a1 100644 --- a/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go +++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go @@ -1,9 +1,10 @@ package gbytes_test import ( - . "github.com/onsi/gomega/gbytes" "time" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -27,36 +28,41 @@ var _ = Describe("SayMatcher", func() { Context("when actual is not a gexec Buffer, or a BufferProvider", func() { It("should error", func() { failures := InterceptGomegaFailures(func() { - Ω("foo").Should(Say("foo")) + Expect("foo").Should(Say("foo")) }) - Ω(failures[0]).Should(ContainSubstring("*gbytes.Buffer")) + Expect(failures[0]).Should(ContainSubstring("*gbytes.Buffer")) }) }) Context("when a match is found", func() { It("should succeed", func() { - Ω(buffer).Should(Say("abc")) + Expect(buffer).Should(Say("abc")) }) It("should support printf-like formatting", func() { - Ω(buffer).Should(Say("a%sc", "b")) + Expect(buffer).Should(Say("a%sc", "b")) + }) + + It("should match literal %", func() { + buffer.Write([]byte("%")) + Expect(buffer).Should(Say("abc%")) }) It("should use a regular expression", func() { - Ω(buffer).Should(Say("a.c")) + Expect(buffer).Should(Say("a.c")) }) It("should fastforward the buffer", func() { buffer.Write([]byte("def")) - Ω(buffer).Should(Say("abcd")) - Ω(buffer).Should(Say("ef")) - Ω(buffer).ShouldNot(Say("[a-z]")) + Expect(buffer).Should(Say("abcd")) + Expect(buffer).Should(Say("ef")) + Expect(buffer).ShouldNot(Say("[a-z]")) }) }) Context("when no match is found", func() { It("should not error", func() { - Ω(buffer).ShouldNot(Say("def")) + Expect(buffer).ShouldNot(Say("def")) }) Context("when the buffer is closed", func() { @@ -70,65 +76,65 @@ var _ = Describe("SayMatcher", func() { Eventually(buffer).Should(Say("def")) }) Eventually(buffer).ShouldNot(Say("def")) - Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) t = time.Now() Eventually(buffer).Should(Say("abc")) - Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) }) It("should abort a consistently", func() { t := time.Now() Consistently(buffer, 2.0).ShouldNot(Say("def")) - Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) }) It("should not error with a synchronous matcher", func() { - Ω(buffer).ShouldNot(Say("def")) - Ω(buffer).Should(Say("abc")) + Expect(buffer).ShouldNot(Say("def")) + Expect(buffer).Should(Say("abc")) }) }) }) Context("when a positive match fails", func() { It("should report where it got stuck", func() { - Ω(buffer).Should(Say("abc")) + Expect(buffer).Should(Say("abc")) buffer.Write([]byte("def")) failures := InterceptGomegaFailures(func() { - Ω(buffer).Should(Say("abc")) + Expect(buffer).Should(Say("abc")) }) - Ω(failures[0]).Should(ContainSubstring("Got stuck at:")) - Ω(failures[0]).Should(ContainSubstring("def")) + Expect(failures[0]).Should(ContainSubstring("Got stuck at:")) + Expect(failures[0]).Should(ContainSubstring("def")) }) }) Context("when a negative match fails", func() { It("should report where it got stuck", func() { failures := InterceptGomegaFailures(func() { - Ω(buffer).ShouldNot(Say("abc")) + Expect(buffer).ShouldNot(Say("abc")) }) - Ω(failures[0]).Should(ContainSubstring("Saw:")) - Ω(failures[0]).Should(ContainSubstring("Which matches the unexpected:")) - Ω(failures[0]).Should(ContainSubstring("abc")) + Expect(failures[0]).Should(ContainSubstring("Saw:")) + Expect(failures[0]).Should(ContainSubstring("Which matches the unexpected:")) + Expect(failures[0]).Should(ContainSubstring("abc")) }) }) Context("when a match is not found", func() { It("should not fastforward the buffer", func() { - Ω(buffer).ShouldNot(Say("def")) - Ω(buffer).Should(Say("abc")) + Expect(buffer).ShouldNot(Say("def")) + Expect(buffer).Should(Say("abc")) }) }) Context("a nice real-life example", func() { It("should behave well", func() { - Ω(buffer).Should(Say("abc")) + Expect(buffer).Should(Say("abc")) go func() { time.Sleep(10 * time.Millisecond) buffer.Write([]byte("def")) }() - Ω(buffer).ShouldNot(Say("def")) + Expect(buffer).ShouldNot(Say("def")) Eventually(buffer).Should(Say("def")) }) }) @@ -139,10 +145,10 @@ var _ = Describe("SayMatcher", func() { buffer: NewBuffer(), } - Ω(s).ShouldNot(Say("abc")) + Expect(s).ShouldNot(Say("abc")) s.Buffer().Write([]byte("abc")) - Ω(s).Should(Say("abc")) + Expect(s).Should(Say("abc")) }) It("should abort an eventually", func() { @@ -156,8 +162,8 @@ var _ = Describe("SayMatcher", func() { failures := InterceptGomegaFailures(func() { Eventually(s).Should(Say("def")) }) - Ω(failures).Should(HaveLen(1)) - Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/gexec/build.go b/vendor/github.com/onsi/gomega/gexec/build.go index d11b2fd8..869c1ead 100644 --- a/vendor/github.com/onsi/gomega/gexec/build.go +++ b/vendor/github.com/onsi/gomega/gexec/build.go @@ -3,12 +3,14 @@ package gexec import ( "errors" "fmt" + "go/build" "io/ioutil" "os" "os/exec" "path" "path/filepath" "runtime" + "strings" "sync" ) @@ -21,17 +23,18 @@ var ( Build uses go build to compile the package at packagePath. The resulting binary is saved off in a temporary directory. A path pointing to this binary is returned. -Build uses the $GOPATH set in your environment. It passes the variadic args on to `go build`. +Build uses the $GOPATH set in your environment. If $GOPATH is not set and you are using Go 1.8+, +it will use the default GOPATH instead. It passes the variadic args on to `go build`. */ func Build(packagePath string, args ...string) (compiledPath string, err error) { - return doBuild(os.Getenv("GOPATH"), packagePath, nil, args...) + return doBuild(build.Default.GOPATH, packagePath, nil, args...) } /* BuildWithEnvironment is identical to Build but allows you to specify env vars to be set at build time. */ func BuildWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) { - return doBuild(os.Getenv("GOPATH"), packagePath, env, args...) + return doBuild(build.Default.GOPATH, packagePath, env, args...) } /* @@ -41,6 +44,16 @@ func BuildIn(gopath string, packagePath string, args ...string) (compiledPath st return doBuild(gopath, packagePath, nil, args...) } +func replaceGoPath(environ []string, newGoPath string) []string { + newEnviron := []string{} + for _, v := range environ { + if !strings.HasPrefix(v, "GOPATH=") { + newEnviron = append(newEnviron, v) + } + } + return append(newEnviron, "GOPATH="+newGoPath) +} + func doBuild(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) { tmpDir, err := temporaryDirectory() if err != nil { @@ -60,7 +73,7 @@ func doBuild(gopath, packagePath string, env []string, args ...string) (compiled cmdArgs = append(cmdArgs, "-o", executable, packagePath) build := exec.Command("go", cmdArgs...) - build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...) + build.Env = replaceGoPath(os.Environ(), gopath) build.Env = append(build.Env, env...) output, err := build.CombinedOutput() diff --git a/vendor/github.com/onsi/gomega/gexec/build_test.go b/vendor/github.com/onsi/gomega/gexec/build_test.go index 8df0790c..295dac8b 100644 --- a/vendor/github.com/onsi/gomega/gexec/build_test.go +++ b/vendor/github.com/onsi/gomega/gexec/build_test.go @@ -1,7 +1,10 @@ package gexec_test import ( + "fmt" + "io/ioutil" "os" + "path/filepath" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -14,13 +17,13 @@ var _ = Describe(".Build", func() { Context("when there have been previous calls to Build", func() { BeforeEach(func() { _, err := gexec.Build(packagePath) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("compiles the specified package", func() { compiledPath, err := gexec.Build(packagePath) - Ω(err).ShouldNot(HaveOccurred()) - Ω(compiledPath).Should(BeAnExistingFile()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) }) Context("and CleanupBuildArtifacts has been called", func() { @@ -31,8 +34,8 @@ var _ = Describe(".Build", func() { It("compiles the specified package", func() { var err error fireflyPath, err = gexec.Build(packagePath) - Ω(err).ShouldNot(HaveOccurred()) - Ω(fireflyPath).Should(BeAnExistingFile()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(fireflyPath).Should(BeAnExistingFile()) }) }) }) @@ -47,13 +50,63 @@ var _ = Describe(".BuildWithEnvironment", func() { It("compiles the specified package with the specified env vars", func() { compiledPath, err := gexec.BuildWithEnvironment(packagePath, env) - Ω(err).ShouldNot(HaveOccurred()) - Ω(compiledPath).Should(BeAnExistingFile()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) }) It("returns the environment to a good state", func() { _, err = gexec.BuildWithEnvironment(packagePath, env) - Ω(err).ShouldNot(HaveOccurred()) - Ω(os.Environ()).ShouldNot(ContainElement("GOOS=linux")) + Expect(err).ShouldNot(HaveOccurred()) + Expect(os.Environ()).ShouldNot(ContainElement("GOOS=linux")) }) }) + +var _ = Describe(".BuildIn", func() { + const ( + target = "github.com/onsi/gomega/gexec/_fixture/firefly/" + ) + + var ( + original string + gopath string + ) + + BeforeEach(func() { + var err error + original = os.Getenv("GOPATH") + gopath, err = ioutil.TempDir("", "") + Expect(err).NotTo(HaveOccurred()) + copyFile(filepath.Join("_fixture", "firefly", "main.go"), filepath.Join(gopath, "src", target), "main.go") + Expect(os.Setenv("GOPATH", filepath.Join(os.TempDir(), "emptyFakeGopath"))).To(Succeed()) + Expect(os.Environ()).To(ContainElement(fmt.Sprintf("GOPATH=%s", filepath.Join(os.TempDir(), "emptyFakeGopath")))) + }) + + AfterEach(func() { + if original == "" { + Expect(os.Unsetenv("GOPATH")).To(Succeed()) + } else { + Expect(os.Setenv("GOPATH", original)).To(Succeed()) + } + if gopath != "" { + os.RemoveAll(gopath) + } + }) + + It("appends the gopath env var", func() { + _, err := gexec.BuildIn(gopath, target) + Expect(err).NotTo(HaveOccurred()) + }) + + It("resets GOPATH to its original value", func() { + _, err := gexec.BuildIn(gopath, target) + Expect(err).NotTo(HaveOccurred()) + Expect(os.Getenv("GOPATH")).To(Equal(filepath.Join(os.TempDir(), "emptyFakeGopath"))) + }) +}) + +func copyFile(source, directory, basename string) { + Expect(os.MkdirAll(directory, 0755)).To(Succeed()) + content, err := ioutil.ReadFile(source) + Expect(err).NotTo(HaveOccurred()) + Expect(ioutil.WriteFile(filepath.Join(directory, basename), content, 0644)).To(Succeed()) +} diff --git a/vendor/github.com/onsi/gomega/gexec/exit_matcher.go b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go index d872ec8f..98a35493 100644 --- a/vendor/github.com/onsi/gomega/gexec/exit_matcher.go +++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go @@ -9,7 +9,7 @@ import ( /* The Exit matcher operates on a session: - Ω(session).Should(Exit()) + Expect(session).Should(Exit()) Exit passes if the session has already exited. diff --git a/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go b/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go index 79615ddf..9abc3226 100644 --- a/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go +++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go @@ -1,10 +1,11 @@ package gexec_test import ( - . "github.com/onsi/gomega/gexec" "os/exec" "time" + . "github.com/onsi/gomega/gexec" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -23,79 +24,79 @@ var _ = Describe("ExitMatcher", func() { var err error command = exec.Command(fireflyPath, "0") session, err = Start(command, nil, nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) Describe("when passed something that is an Exiter", func() { It("should act normally", func() { failures := InterceptGomegaFailures(func() { - Ω(NeverExits{}).Should(Exit()) + Expect(NeverExits{}).Should(Exit()) }) - Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) + Expect(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) }) }) Describe("when passed something that is not an Exiter", func() { It("should error", func() { failures := InterceptGomegaFailures(func() { - Ω("aardvark").Should(Exit()) + Expect("aardvark").Should(Exit()) }) - Ω(failures[0]).Should(ContainSubstring("Exit must be passed a gexec.Exiter")) + Expect(failures[0]).Should(ContainSubstring("Exit must be passed a gexec.Exiter")) }) }) Context("with no exit code", func() { It("should say the right things when it fails", func() { - Ω(session).ShouldNot(Exit()) + Expect(session).ShouldNot(Exit()) failures := InterceptGomegaFailures(func() { - Ω(session).Should(Exit()) + Expect(session).Should(Exit()) }) - Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) + Expect(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) Eventually(session).Should(Exit()) - Ω(session).Should(Exit()) + Expect(session).Should(Exit()) failures = InterceptGomegaFailures(func() { - Ω(session).ShouldNot(Exit()) + Expect(session).ShouldNot(Exit()) }) - Ω(failures[0]).Should(ContainSubstring("Expected process not to exit. It did.")) + Expect(failures[0]).Should(ContainSubstring("Expected process not to exit. It did.")) }) }) Context("with an exit code", func() { It("should say the right things when it fails", func() { - Ω(session).ShouldNot(Exit(0)) - Ω(session).ShouldNot(Exit(1)) + Expect(session).ShouldNot(Exit(0)) + Expect(session).ShouldNot(Exit(1)) failures := InterceptGomegaFailures(func() { - Ω(session).Should(Exit(0)) + Expect(session).Should(Exit(0)) }) - Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) + Expect(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) Eventually(session).Should(Exit(0)) - Ω(session).Should(Exit(0)) + Expect(session).Should(Exit(0)) failures = InterceptGomegaFailures(func() { - Ω(session).Should(Exit(1)) + Expect(session).Should(Exit(1)) }) - Ω(failures[0]).Should(ContainSubstring("to match exit code:")) + Expect(failures[0]).Should(ContainSubstring("to match exit code:")) - Ω(session).ShouldNot(Exit(1)) + Expect(session).ShouldNot(Exit(1)) failures = InterceptGomegaFailures(func() { - Ω(session).ShouldNot(Exit(0)) + Expect(session).ShouldNot(Exit(0)) }) - Ω(failures[0]).Should(ContainSubstring("not to match exit code:")) + Expect(failures[0]).Should(ContainSubstring("not to match exit code:")) }) }) @@ -106,8 +107,8 @@ var _ = Describe("ExitMatcher", func() { failures := InterceptGomegaFailures(func() { Eventually(session).Should(Exit(1)) }) - Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go b/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go index 87672aaf..dc8e1f40 100644 --- a/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go +++ b/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go @@ -14,7 +14,7 @@ func TestGexec(t *testing.T) { BeforeSuite(func() { var err error fireflyPath, err = gexec.Build("./_fixture/firefly") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) AfterSuite(func() { diff --git a/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go b/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go index 8657d0c9..e847b150 100644 --- a/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go +++ b/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go @@ -28,7 +28,7 @@ var _ = Describe("PrefixedWriter", func() { writer.Write([]byte("\ntuv\nwx")) writer.Write([]byte("yz\n\n")) - Ω(buffer.String()).Should(Equal(`[p]abcdef + Expect(buffer.String()).Should(Equal(`[p]abcdef [p]hij [p] [p] diff --git a/vendor/github.com/onsi/gomega/gexec/session.go b/vendor/github.com/onsi/gomega/gexec/session.go index 387a72cd..5cb00ca6 100644 --- a/vendor/github.com/onsi/gomega/gexec/session.go +++ b/vendor/github.com/onsi/gomega/gexec/session.go @@ -7,7 +7,6 @@ import ( "io" "os" "os/exec" - "reflect" "sync" "syscall" @@ -40,12 +39,12 @@ Start starts the passed-in *exec.Cmd command. It wraps the command in a *gexec. The session pipes the command's stdout and stderr to two *gbytes.Buffers available as properties on the session: session.Out and session.Err. These buffers can be used with the gbytes.Say matcher to match against unread output: - Ω(session.Out).Should(gbytes.Say("foo-out")) - Ω(session.Err).Should(gbytes.Say("foo-err")) + Expect(session.Out).Should(gbytes.Say("foo-out")) + Expect(session.Err).Should(gbytes.Say("foo-err")) In addition, Session satisfies the gbytes.BufferProvider interface and provides the stdout *gbytes.Buffer. This allows you to replace the first line, above, with: - Ω(session).Should(gbytes.Say("foo-out")) + Expect(session).Should(gbytes.Say("foo-out")) When outWriter and/or errWriter are non-nil, the session will pipe stdout and/or stderr output both into the session *gybtes.Buffers and to the passed-in outWriter/errWriter. This is useful for capturing the process's output or logging it to screen. In particular, when using Ginkgo it can be convenient to direct output to the GinkgoWriter: @@ -57,7 +56,7 @@ This will log output when running tests in verbose mode, but - otherwise - will The session wrapper is responsible for waiting on the *exec.Cmd command. You *should not* call command.Wait() yourself. Instead, to assert that the command has exited you can use the gexec.Exit matcher: - Ω(session).Should(gexec.Exit()) + Expect(session).Should(gexec.Exit()) When the session exits it closes the stdout and stderr gbytes buffers. This will short circuit any Eventuallys waiting for the buffers to Say something. @@ -78,11 +77,11 @@ func Start(command *exec.Cmd, outWriter io.Writer, errWriter io.Writer) (*Sessio commandOut, commandErr = session.Out, session.Err - if outWriter != nil && !reflect.ValueOf(outWriter).IsNil() { + if outWriter != nil { commandOut = io.MultiWriter(commandOut, outWriter) } - if errWriter != nil && !reflect.ValueOf(errWriter).IsNil() { + if errWriter != nil { commandErr = io.MultiWriter(commandErr, errWriter) } @@ -152,11 +151,7 @@ If the command has already exited, Kill returns silently. The session is returned to enable chaining. */ func (s *Session) Kill() *Session { - if s.ExitCode() != -1 { - return s - } - s.Command.Process.Kill() - return s + return s.Signal(syscall.SIGKILL) } /* @@ -189,10 +184,9 @@ If the command has already exited, Signal returns silently. The session is returned to enable chaining. */ func (s *Session) Signal(signal os.Signal) *Session { - if s.ExitCode() != -1 { - return s + if s.processIsAlive() { + s.Command.Process.Signal(signal) } - s.Command.Process.Signal(signal) return s } @@ -216,6 +210,10 @@ func (s *Session) monitorForExit(exited chan<- struct{}) { close(exited) } +func (s *Session) processIsAlive() bool { + return s.ExitCode() == -1 && s.Command.Process != nil +} + var trackedSessions = []*Session{} var trackedSessionsMutex = &sync.Mutex{} diff --git a/vendor/github.com/onsi/gomega/gexec/session_test.go b/vendor/github.com/onsi/gomega/gexec/session_test.go index b7841a09..6fdf22d2 100644 --- a/vendor/github.com/onsi/gomega/gexec/session_test.go +++ b/vendor/github.com/onsi/gomega/gexec/session_test.go @@ -1,6 +1,8 @@ package gexec_test import ( + "io" + "io/ioutil" "os/exec" "syscall" "time" @@ -16,7 +18,7 @@ var _ = Describe("Session", func() { var command *exec.Cmd var session *Session - var outWriter, errWriter *Buffer + var outWriter, errWriter io.Writer BeforeEach(func() { outWriter = nil @@ -27,12 +29,12 @@ var _ = Describe("Session", func() { command = exec.Command(fireflyPath) var err error session, err = Start(command, outWriter, errWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) Context("running a command", func() { It("should start the process", func() { - Ω(command.Process).ShouldNot(BeNil()) + Expect(command.Process).ShouldNot(BeNil()) }) It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) { @@ -60,36 +62,35 @@ var _ = Describe("Session", func() { Describe("providing the exit code", func() { It("should provide the app's exit code", func() { - Ω(session.ExitCode()).Should(Equal(-1)) + Expect(session.ExitCode()).Should(Equal(-1)) Eventually(session).Should(Exit()) - Ω(session.ExitCode()).Should(BeNumerically(">=", 0)) - Ω(session.ExitCode()).Should(BeNumerically("<", 3)) + Expect(session.ExitCode()).Should(BeNumerically(">=", 0)) + Expect(session.ExitCode()).Should(BeNumerically("<", 3)) }) }) Describe("wait", func() { It("should wait till the command exits", func() { - Ω(session.ExitCode()).Should(Equal(-1)) - Ω(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) - Ω(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) + Expect(session.ExitCode()).Should(Equal(-1)) + Expect(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) + Expect(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) }) }) Describe("exited", func() { It("should close when the command exits", func() { Eventually(session.Exited).Should(BeClosed()) - Ω(session.ExitCode()).ShouldNot(Equal(-1)) + Expect(session.ExitCode()).ShouldNot(Equal(-1)) }) }) Describe("kill", func() { - It("should kill the command and don't wait for it to exit", func() { + It("should kill the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session.Kill() - Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 9)) }) }) @@ -97,10 +98,9 @@ var _ = Describe("Session", func() { Describe("interrupt", func() { It("should interrupt the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session.Interrupt() - Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 2)) }) }) @@ -108,10 +108,9 @@ var _ = Describe("Session", func() { Describe("terminate", func() { It("should terminate the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session.Terminate() - Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 15)) }) }) @@ -119,12 +118,18 @@ var _ = Describe("Session", func() { Describe("signal", func() { It("should send the signal to the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session.Signal(syscall.SIGABRT) - Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 6)) }) + + It("should ignore sending a signal if the command did not start", func() { + session, err := Start(exec.Command("notexisting"), GinkgoWriter, GinkgoWriter) + Expect(err).To(HaveOccurred()) + + Expect(func() { session.Signal(syscall.SIGUSR1) }).NotTo(Panic()) + }) }) Context("tracking sessions", func() { @@ -135,13 +140,13 @@ var _ = Describe("Session", func() { Describe("kill", func() { It("should kill all the started sessions", func() { session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) Kill() @@ -150,25 +155,15 @@ var _ = Describe("Session", func() { Eventually(session3).Should(Exit(128 + 9)) }) - It("should not wait for exit", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) - - Kill() - Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") - - Eventually(session1).Should(Exit(128 + 9)) - }) - It("should not track unstarted sessions", func() { _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) Kill() @@ -181,31 +176,31 @@ var _ = Describe("Session", func() { Describe("killAndWait", func() { It("should kill all the started sessions and wait for them to finish", func() { session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) KillAndWait() - Ω(session1).Should(Exit(128+9), "Should have exited") - Ω(session2).Should(Exit(128+9), "Should have exited") - Ω(session3).Should(Exit(128+9), "Should have exited") + Expect(session1).Should(Exit(128+9), "Should have exited") + Expect(session2).Should(Exit(128+9), "Should have exited") + Expect(session3).Should(Exit(128+9), "Should have exited") }) }) Describe("terminate", func() { It("should terminate all the started sessions", func() { session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) Terminate() @@ -213,46 +208,37 @@ var _ = Describe("Session", func() { Eventually(session2).Should(Exit(128 + 15)) Eventually(session3).Should(Exit(128 + 15)) }) - - It("should not wait for exit", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) - - Terminate() - - Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") - }) }) Describe("terminateAndWait", func() { It("should terminate all the started sessions, and wait for them to exit", func() { session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) TerminateAndWait() - Ω(session1).Should(Exit(128+15), "Should have exited") - Ω(session2).Should(Exit(128+15), "Should have exited") - Ω(session3).Should(Exit(128+15), "Should have exited") + Expect(session1).Should(Exit(128+15), "Should have exited") + Expect(session2).Should(Exit(128+15), "Should have exited") + Expect(session3).Should(Exit(128+15), "Should have exited") }) }) Describe("signal", func() { It("should signal all the started sessions", func() { session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) Signal(syscall.SIGABRT) @@ -260,27 +246,18 @@ var _ = Describe("Session", func() { Eventually(session2).Should(Exit(128 + 6)) Eventually(session3).Should(Exit(128 + 6)) }) - - It("should not wait", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) - - Signal(syscall.SIGABRT) - - Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") - }) }) Describe("interrupt", func() { It("should interrupt all the started sessions, and not wait", func() { session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) Interrupt() @@ -288,15 +265,6 @@ var _ = Describe("Session", func() { Eventually(session2).Should(Exit(128 + 2)) Eventually(session3).Should(Exit(128 + 2)) }) - - It("should not wait", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Ω(err).ShouldNot(HaveOccurred()) - - Interrupt() - - Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") - }) }) }) @@ -304,10 +272,10 @@ var _ = Describe("Session", func() { It("should close the buffers", func() { Eventually(session).Should(Exit()) - Ω(session.Out.Closed()).Should(BeTrue()) - Ω(session.Err.Closed()).Should(BeTrue()) + Expect(session.Out.Closed()).Should(BeTrue()) + Expect(session.Err.Closed()).Should(BeTrue()) - Ω(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) + Expect(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) }) var So = It @@ -317,35 +285,52 @@ var _ = Describe("Session", func() { failures := InterceptGomegaFailures(func() { Eventually(session).Should(Say("blah blah blah blah blah")) }) - Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) }) }) Context("when wrapping out and err", func() { + var ( + outWriterBuffer, errWriterBuffer *Buffer + ) + BeforeEach(func() { - outWriter = NewBuffer() - errWriter = NewBuffer() + outWriterBuffer = NewBuffer() + outWriter = outWriterBuffer + errWriterBuffer = NewBuffer() + errWriter = errWriterBuffer }) It("should route to both the provided writers and the gbytes buffers", func() { Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) - Ω(outWriter.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) - Ω(errWriter.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) + Expect(outWriterBuffer.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) + Expect(errWriterBuffer.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) Eventually(session).Should(Exit()) - Ω(outWriter.Contents()).Should(Equal(session.Out.Contents())) - Ω(errWriter.Contents()).Should(Equal(session.Err.Contents())) + Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents())) + Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents())) + }) + + Context("when discarding the output of the command", func() { + BeforeEach(func() { + outWriter = ioutil.Discard + errWriter = ioutil.Discard + }) + + It("executes succesfuly", func() { + Eventually(session).Should(Exit()) + }) }) }) Describe("when the command fails to start", func() { It("should return an error", func() { _, err := Start(exec.Command("agklsjdfas"), nil, nil) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/ghttp/handlers.go b/vendor/github.com/onsi/gomega/ghttp/handlers.go index 63ff6919..82bc1412 100644 --- a/vendor/github.com/onsi/gomega/ghttp/handlers.go +++ b/vendor/github.com/onsi/gomega/ghttp/handlers.go @@ -31,18 +31,18 @@ func CombineHandlers(handlers ...http.HandlerFunc) http.HandlerFunc { //Alternatively you can pass in a matcher (ContainSubstring("/foo") and MatchRegexp("/foo/[a-f0-9]+") for example) func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - Ω(req.Method).Should(Equal(method), "Method mismatch") + Expect(req.Method).Should(Equal(method), "Method mismatch") switch p := path.(type) { case types.GomegaMatcher: - Ω(req.URL.Path).Should(p, "Path mismatch") + Expect(req.URL.Path).Should(p, "Path mismatch") default: - Ω(req.URL.Path).Should(Equal(path), "Path mismatch") + Expect(req.URL.Path).Should(Equal(path), "Path mismatch") } if len(rawQuery) > 0 { values, err := url.ParseQuery(rawQuery[0]) - Ω(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed") + Expect(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed") - Ω(req.URL.Query()).Should(Equal(values), "RawQuery mismatch") + Expect(req.URL.Query()).Should(Equal(values), "RawQuery mismatch") } } } @@ -51,7 +51,7 @@ func VerifyRequest(method string, path interface{}, rawQuery ...string) http.Han //specified value func VerifyContentType(contentType string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - Ω(req.Header.Get("Content-Type")).Should(Equal(contentType)) + Expect(req.Header.Get("Content-Type")).Should(Equal(contentType)) } } @@ -60,12 +60,12 @@ func VerifyContentType(contentType string) http.HandlerFunc { func VerifyBasicAuth(username string, password string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { auth := req.Header.Get("Authorization") - Ω(auth).ShouldNot(Equal(""), "Authorization header must be specified") + Expect(auth).ShouldNot(Equal(""), "Authorization header must be specified") decoded, err := base64.StdEncoding.DecodeString(auth[6:]) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch") + Expect(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch") } } @@ -78,7 +78,7 @@ func VerifyHeader(header http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { for key, values := range header { key = http.CanonicalHeaderKey(key) - Ω(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key) + Expect(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key) } } } @@ -97,8 +97,8 @@ func VerifyBody(expectedBody []byte) http.HandlerFunc { func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) req.Body.Close() - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(Equal(expectedBody), "Body Mismatch") + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(Equal(expectedBody), "Body Mismatch") }, ) } @@ -113,8 +113,8 @@ func VerifyJSON(expectedJSON string) http.HandlerFunc { func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) req.Body.Close() - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(MatchJSON(expectedJSON), "JSON Mismatch") + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(MatchJSON(expectedJSON), "JSON Mismatch") }, ) } @@ -124,7 +124,7 @@ func VerifyJSON(expectedJSON string) http.HandlerFunc { //that matches the object func VerifyJSONRepresenting(object interface{}) http.HandlerFunc { data, err := json.Marshal(object) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) return CombineHandlers( VerifyContentType("application/json"), VerifyJSON(string(data)), @@ -138,9 +138,9 @@ func VerifyJSONRepresenting(object interface{}) http.HandlerFunc { func VerifyForm(values url.Values) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) for key, vals := range values { - Ω(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key) + Expect(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key) } } } @@ -161,19 +161,19 @@ func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc { VerifyContentType("application/x-protobuf"), func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Body.Close() expectedType := reflect.TypeOf(expected) actualValuePtr := reflect.New(expectedType.Elem()) actual, ok := actualValuePtr.Interface().(proto.Message) - Ω(ok).Should(BeTrue(), "Message value is not a proto.Message") + Expect(ok).Should(BeTrue(), "Message value is not a proto.Message") err = proto.Unmarshal(body, actual) - Ω(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf") + Expect(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf") - Ω(actual).Should(Equal(expected), "ProtoBuf Mismatch") + Expect(actual).Should(Equal(expected), "ProtoBuf Mismatch") }, ) } @@ -203,7 +203,7 @@ func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header case []byte: w.Write(x) default: - Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.") + Expect(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.") } } } @@ -230,7 +230,7 @@ func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.He case *[]byte: w.Write(*x) default: - Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.") + Expect(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.") } } } @@ -244,7 +244,7 @@ Also, RespondWithJSONEncoded can be given an optional http.Header. The headers */ func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc { data, err := json.Marshal(object) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) var headers http.Header if len(optionalHeader) == 1 { @@ -271,7 +271,7 @@ Since the http.Header can be mutated after the fact you don't need to pass in a func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { data, err := json.Marshal(object) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) var headers http.Header if len(optionalHeader) == 1 { headers = optionalHeader[0] @@ -294,7 +294,7 @@ func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHead func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { data, err := proto.Marshal(message) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) var headers http.Header if len(optionalHeader) == 1 { diff --git a/vendor/github.com/onsi/gomega/ghttp/test_server.go b/vendor/github.com/onsi/gomega/ghttp/test_server.go index 40d92dea..77535f30 100644 --- a/vendor/github.com/onsi/gomega/ghttp/test_server.go +++ b/vendor/github.com/onsi/gomega/ghttp/test_server.go @@ -47,7 +47,7 @@ A more comprehensive example is available at https://onsi.github.io/gomega/#_tes }) It("should return the returned sprockets", func() { - Ω(client.Sprockets()).Should(Equal(sprockets)) + Expect(client.Sprockets()).Should(Equal(sprockets)) }) }) @@ -57,7 +57,7 @@ A more comprehensive example is available at https://onsi.github.io/gomega/#_tes }) It("should return an empty list of sprockets", func() { - Ω(client.Sprockets()).Should(BeEmpty()) + Expect(client.Sprockets()).Should(BeEmpty()) }) }) @@ -68,8 +68,8 @@ A more comprehensive example is available at https://onsi.github.io/gomega/#_tes It("should return an AuthenticationError error", func() { sprockets, err := client.Sprockets() - Ω(sprockets).Should(BeEmpty()) - Ω(err).Should(MatchError(AuthenticationError)) + Expect(sprockets).Should(BeEmpty()) + Expect(err).Should(MatchError(AuthenticationError)) }) }) @@ -80,8 +80,8 @@ A more comprehensive example is available at https://onsi.github.io/gomega/#_tes It("should return an InternalError error", func() { sprockets, err := client.Sprockets() - Ω(sprockets).Should(BeEmpty()) - Ω(err).Should(MatchError(InternalError)) + Expect(sprockets).Should(BeEmpty()) + Expect(err).Should(MatchError(InternalError)) }) }) }) @@ -97,7 +97,7 @@ A more comprehensive example is available at https://onsi.github.io/gomega/#_tes }) It("should make the request with a filter", func() { - Ω(client.Sprockets("food")).Should(Equal(sprockets)) + Expect(client.Sprockets("food")).Should(Equal(sprockets)) }) }) }) @@ -111,6 +111,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "net/http/httputil" "reflect" "regexp" "strings" @@ -123,7 +124,7 @@ func new() *Server { return &Server{ AllowUnhandledRequests: false, UnhandledRequestStatusCode: http.StatusInternalServerError, - writeLock: &sync.Mutex{}, + rwMutex: &sync.RWMutex{}, } } @@ -160,11 +161,13 @@ type Server struct { HTTPTestServer *httptest.Server //Defaults to false. If set to true, the Server will allow more requests than there are registered handlers. + //Direct use of this property is deprecated and is likely to be removed, use GetAllowUnhandledRequests and SetAllowUnhandledRequests instead. AllowUnhandledRequests bool //The status code returned when receiving an unhandled request. //Defaults to http.StatusInternalServerError. //Only applies if AllowUnhandledRequests is true + //Direct use of this property is deprecated and is likely to be removed, use GetUnhandledRequestStatusCode and SetUnhandledRequestStatusCode instead. UnhandledRequestStatusCode int //If provided, ghttp will log about each request received to the provided io.Writer @@ -176,8 +179,8 @@ type Server struct { requestHandlers []http.HandlerFunc routedHandlers []routedHandler - writeLock *sync.Mutex - calls int + rwMutex *sync.RWMutex + calls int } //Start() starts an unstarted ghttp server. It is a catastrophic error to call Start more than once (thanks, httptest). @@ -187,20 +190,24 @@ func (s *Server) Start() { //URL() returns a url that will hit the server func (s *Server) URL() string { + s.rwMutex.RLock() + defer s.rwMutex.RUnlock() return s.HTTPTestServer.URL } //Addr() returns the address on which the server is listening. func (s *Server) Addr() string { + s.rwMutex.RLock() + defer s.rwMutex.RUnlock() return s.HTTPTestServer.Listener.Addr().String() } //Close() should be called at the end of each test. It spins down and cleans up the test server. func (s *Server) Close() { - s.writeLock.Lock() + s.rwMutex.Lock() server := s.HTTPTestServer s.HTTPTestServer = nil - s.writeLock.Unlock() + s.rwMutex.Unlock() if server != nil { server.Close() @@ -213,10 +220,10 @@ func (s *Server) Close() { //1. If the request matches a handler registered with RouteToHandler, that handler is called. //2. Otherwise, if there are handlers registered via AppendHandlers, those handlers are called in order. //3. If all registered handlers have been called then: -// a) If AllowUnhandledRequests is true, the request will be handled with response code of UnhandledRequestStatusCode +// a) If AllowUnhandledRequests is set to true, the request will be handled with response code of UnhandledRequestStatusCode // b) If AllowUnhandledRequests is false, the request will not be handled and the current test will be marked as failed. func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s.writeLock.Lock() + s.rwMutex.Lock() defer func() { e := recover() if e != nil { @@ -240,7 +247,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { defer func() { recover() }() - Ω(e).Should(BeNil(), "Handler Panicked") + Expect(e).Should(BeNil(), "Handler Panicked") }() if s.Writer != nil { @@ -249,29 +256,31 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { s.receivedRequests = append(s.receivedRequests, req) if routedHandler, ok := s.handlerForRoute(req.Method, req.URL.Path); ok { - s.writeLock.Unlock() + s.rwMutex.Unlock() routedHandler(w, req) } else if s.calls < len(s.requestHandlers) { h := s.requestHandlers[s.calls] s.calls++ - s.writeLock.Unlock() + s.rwMutex.Unlock() h(w, req) } else { - s.writeLock.Unlock() - if s.AllowUnhandledRequests { + s.rwMutex.Unlock() + if s.GetAllowUnhandledRequests() { ioutil.ReadAll(req.Body) req.Body.Close() - w.WriteHeader(s.UnhandledRequestStatusCode) + w.WriteHeader(s.GetUnhandledRequestStatusCode()) } else { - Ω(req).Should(BeNil(), "Received Unhandled Request") + formatted, err := httputil.DumpRequest(req, true) + Expect(err).NotTo(HaveOccurred(), "Encountered error while dumping HTTP request") + Expect(string(formatted)).Should(BeNil(), "Received Unhandled Request") } } } //ReceivedRequests is an array containing all requests received by the server (both handled and unhandled requests) func (s *Server) ReceivedRequests() []*http.Request { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.RLock() + defer s.rwMutex.RUnlock() return s.receivedRequests } @@ -281,8 +290,8 @@ func (s *Server) ReceivedRequests() []*http.Request { // //The path may be either a string object or a *regexp.Regexp. func (s *Server) RouteToHandler(method string, path interface{}, handler http.HandlerFunc) { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.Lock() + defer s.rwMutex.Unlock() rh := routedHandler{ method: method, @@ -327,8 +336,8 @@ func (s *Server) handlerForRoute(method string, path string) (http.HandlerFunc, //AppendHandlers will appends http.HandlerFuncs to the server's list of registered handlers. The first incoming request is handled by the first handler, the second by the second, etc... func (s *Server) AppendHandlers(handlers ...http.HandlerFunc) { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.Lock() + defer s.rwMutex.Unlock() s.requestHandlers = append(s.requestHandlers, handlers...) } @@ -337,23 +346,23 @@ func (s *Server) AppendHandlers(handlers ...http.HandlerFunc) { //This is useful, for example, when a server has been set up in a shared context, but must be tweaked //for a particular test. func (s *Server) SetHandler(index int, handler http.HandlerFunc) { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.Lock() + defer s.rwMutex.Unlock() s.requestHandlers[index] = handler } //GetHandler returns the handler registered at the passed in index. func (s *Server) GetHandler(index int) http.HandlerFunc { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.RLock() + defer s.rwMutex.RUnlock() return s.requestHandlers[index] } func (s *Server) Reset() { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.Lock() + defer s.rwMutex.Unlock() s.HTTPTestServer.CloseClientConnections() s.calls = 0 @@ -374,8 +383,40 @@ func (s *Server) WrapHandler(index int, handler http.HandlerFunc) { } func (s *Server) CloseClientConnections() { - s.writeLock.Lock() - defer s.writeLock.Unlock() + s.rwMutex.Lock() + defer s.rwMutex.Unlock() s.HTTPTestServer.CloseClientConnections() } + +//SetAllowUnhandledRequests enables the server to accept unhandled requests. +func (s *Server) SetAllowUnhandledRequests(allowUnhandledRequests bool) { + s.rwMutex.Lock() + defer s.rwMutex.Unlock() + + s.AllowUnhandledRequests = allowUnhandledRequests +} + +//GetAllowUnhandledRequests returns true if the server accepts unhandled requests. +func (s *Server) GetAllowUnhandledRequests() bool { + s.rwMutex.RLock() + defer s.rwMutex.RUnlock() + + return s.AllowUnhandledRequests +} + +//SetUnhandledRequestStatusCode status code to be returned when the server receives unhandled requests +func (s *Server) SetUnhandledRequestStatusCode(statusCode int) { + s.rwMutex.Lock() + defer s.rwMutex.Unlock() + + s.UnhandledRequestStatusCode = statusCode +} + +//GetUnhandledRequestStatusCode returns the current status code being returned for unhandled requests +func (s *Server) GetUnhandledRequestStatusCode() int { + s.rwMutex.RLock() + defer s.rwMutex.RUnlock() + + return s.UnhandledRequestStatusCode +} diff --git a/vendor/github.com/onsi/gomega/ghttp/test_server_test.go b/vendor/github.com/onsi/gomega/ghttp/test_server_test.go index 88b32465..ac6a269a 100644 --- a/vendor/github.com/onsi/gomega/ghttp/test_server_test.go +++ b/vendor/github.com/onsi/gomega/ghttp/test_server_test.go @@ -38,13 +38,13 @@ var _ = Describe("TestServer", func() { s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) http.Get(s.URL() + "/") - Ω(s.ReceivedRequests()).Should(HaveLen(1)) + Expect(s.ReceivedRequests()).Should(HaveLen(1)) }) It("clears all handlers and call counts", func() { s.Reset() - Ω(s.ReceivedRequests()).Should(HaveLen(0)) - Ω(func() { s.GetHandler(0) }).Should(Panic()) + Expect(s.ReceivedRequests()).Should(HaveLen(0)) + Expect(func() { s.GetHandler(0) }).Should(Panic()) }) }) @@ -57,55 +57,59 @@ var _ = Describe("TestServer", func() { ) client := http.Client{Transport: &http.Transport{DisableKeepAlives: true}} resp, err := client.Get(s.URL()) - Ω(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(200)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).Should(Equal(200)) body, err := ioutil.ReadAll(resp.Body) resp.Body.Close() - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) s.CloseClientConnections() resp, err = client.Get(s.URL()) - Ω(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(200)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).Should(Equal(200)) body2, err := ioutil.ReadAll(resp.Body) resp.Body.Close() - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(body2).ShouldNot(Equal(body)) + Expect(body2).ShouldNot(Equal(body)) }) }) Describe("closing server mulitple times", func() { It("should not fail", func() { s.Close() - Ω(s.Close).ShouldNot(Panic()) + Expect(s.Close).ShouldNot(Panic()) }) }) Describe("allowing unhandled requests", func() { + It("is not permitted by default", func() { + Expect(s.GetAllowUnhandledRequests()).To(BeFalse()) + }) + Context("when true", func() { BeforeEach(func() { - s.AllowUnhandledRequests = true - s.UnhandledRequestStatusCode = http.StatusForbidden + s.SetAllowUnhandledRequests(true) + s.SetUnhandledRequestStatusCode(http.StatusForbidden) resp, err = http.Get(s.URL() + "/foo") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should allow unhandled requests and respond with the passed in status code", func() { - Ω(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusForbidden)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).Should(Equal(http.StatusForbidden)) data, err := ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(data).Should(BeEmpty()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(data).Should(BeEmpty()) }) It("should record the requests", func() { - Ω(s.ReceivedRequests()).Should(HaveLen(1)) - Ω(s.ReceivedRequests()[0].URL.Path).Should(Equal("/foo")) + Expect(s.ReceivedRequests()).Should(HaveLen(1)) + Expect(s.ReceivedRequests()[0].URL.Path).Should(Equal("/foo")) }) }) @@ -115,7 +119,7 @@ var _ = Describe("TestServer", func() { http.Get(s.URL() + "/foo") }) - Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) + Expect(failures[0]).Should(ContainSubstring("Received Unhandled Request")) }) }) }) @@ -152,12 +156,12 @@ var _ = Describe("TestServer", func() { http.Post(s.URL()+"/routed", "application/json", nil) }) - Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) - Ω(failures).Should(HaveLen(4)) + Expect(failures[0]).Should(ContainSubstring("Received Unhandled Request")) + Expect(failures).Should(HaveLen(4)) http.Post(s.URL()+"/routed3", "application/json", nil) - Ω(called).Should(Equal([]string{"r1", "r2", "A", "r1", "r2", "B", "r2"})) + Expect(called).Should(Equal([]string{"r1", "r2", "A", "r1", "r2", "B", "r2"})) }) It("should override routed handlers when reregistered", func() { @@ -171,21 +175,21 @@ var _ = Describe("TestServer", func() { http.Get(s.URL() + "/routed") http.Post(s.URL()+"/routed7", "application/json", nil) - Ω(called).Should(Equal([]string{"r3", "r4"})) + Expect(called).Should(Equal([]string{"r3", "r4"})) }) It("should call the appended handlers, in order, as requests come in", func() { http.Get(s.URL() + "/foo") - Ω(called).Should(Equal([]string{"A"})) + Expect(called).Should(Equal([]string{"A"})) http.Get(s.URL() + "/foo") - Ω(called).Should(Equal([]string{"A", "B"})) + Expect(called).Should(Equal([]string{"A", "B"})) failures := InterceptGomegaFailures(func() { http.Get(s.URL() + "/foo") }) - Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) + Expect(failures[0]).Should(ContainSubstring("Received Unhandled Request")) }) Describe("Overwriting an existing handler", func() { @@ -198,14 +202,14 @@ var _ = Describe("TestServer", func() { It("should override the specified handler", func() { http.Get(s.URL() + "/foo") http.Get(s.URL() + "/foo") - Ω(called).Should(Equal([]string{"C", "B"})) + Expect(called).Should(Equal([]string{"C", "B"})) }) }) Describe("Getting an existing handler", func() { It("should return the handler func", func() { s.GetHandler(1)(nil, nil) - Ω(called).Should(Equal([]string{"B"})) + Expect(called).Should(Equal([]string{"B"})) }) }) @@ -219,14 +223,14 @@ var _ = Describe("TestServer", func() { It("should wrap the existing handler in a new handler", func() { http.Get(s.URL() + "/foo") http.Get(s.URL() + "/foo") - Ω(called).Should(Equal([]string{"A", "C", "B"})) + Expect(called).Should(Equal([]string{"A", "C", "B"})) }) }) }) Describe("When a handler fails", func() { BeforeEach(func() { - s.UnhandledRequestStatusCode = http.StatusForbidden //just to be clear that 500s aren't coming from unhandled requests + s.SetUnhandledRequestStatusCode(http.StatusForbidden) //just to be clear that 500s aren't coming from unhandled requests }) Context("because the handler has panicked", func() { @@ -244,16 +248,16 @@ var _ = Describe("TestServer", func() { resp, err = http.Get(s.URL()) }) - Ω(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) - Ω(failures).Should(ConsistOf(ContainSubstring("Handler Panicked"))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) + Expect(failures).Should(ConsistOf(ContainSubstring("Handler Panicked"))) }) }) Context("because an assertion has failed", func() { BeforeEach(func() { s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { - // Ω(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way + // Expect(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way By("We're cheating a bit here -- we're throwing a GINKGO_PANIC which simulates a failed assertion") panic(GINKGO_PANIC) @@ -263,8 +267,8 @@ var _ = Describe("TestServer", func() { It("should respond with a 500 and *not* make a failing assertion, instead relying on Ginkgo to have already been notified of the error", func() { resp, err := http.Get(s.URL()) - Ω(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) }) }) }) @@ -280,10 +284,10 @@ var _ = Describe("TestServer", func() { It("should write to the buffer when a request comes in", func() { http.Get(s.URL() + "/foo") - Ω(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n")) + Expect(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n")) http.Post(s.URL()+"/bar", "", nil) - Ω(buf).Should(gbytes.Say("GHTTP Received Request: POST - /bar\n")) + Expect(buf).Should(gbytes.Say("GHTTP Received Request: POST - /bar\n")) }) }) @@ -295,28 +299,28 @@ var _ = Describe("TestServer", func() { It("should verify the method, path", func() { resp, err = http.Get(s.URL() + "/foo?baz=bar") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the method, path", func() { failures := InterceptGomegaFailures(func() { http.Get(s.URL() + "/foo2") }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) It("should verify the method, path", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/json", nil) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) Context("when passed a rawQuery", func() { It("should also be possible to verify the rawQuery", func() { s.SetHandler(0, VerifyRequest("GET", "/foo", "baz=bar")) resp, err = http.Get(s.URL() + "/foo?baz=bar") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should match irregardless of query parameter ordering", func() { @@ -328,7 +332,7 @@ var _ = Describe("TestServer", func() { }.Encode() resp, err = http.Get(u.String()) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) }) @@ -336,7 +340,7 @@ var _ = Describe("TestServer", func() { It("should apply the matcher", func() { s.SetHandler(0, VerifyRequest("GET", MatchRegexp(`/foo/[a-f]*/3`))) resp, err = http.Get(s.URL() + "/foo/abcdefa/3") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) }) }) @@ -351,22 +355,22 @@ var _ = Describe("TestServer", func() { It("should verify the content type", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Header.Set("Content-Type", "application/octet-stream") resp, err = http.DefaultClient.Do(req) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the content type", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Header.Set("Content-Type", "application/json") failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -380,32 +384,32 @@ var _ = Describe("TestServer", func() { It("should verify basic auth", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.SetBasicAuth("bob", "password") resp, err = http.DefaultClient.Do(req) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify basic auth", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.SetBasicAuth("bob", "bassword") failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) It("should require basic auth header", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) - Ω(failures).Should(ContainElement(ContainSubstring("Authorization header must be specified"))) + Expect(failures).Should(ContainElement(ContainSubstring("Authorization header must be specified"))) }) }) @@ -423,19 +427,19 @@ var _ = Describe("TestServer", func() { It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Header.Add("Accept", "jpeg") req.Header.Add("Accept", "png") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") resp, err = http.DefaultClient.Do(req) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Header.Add("Schmaccept", "jpeg") req.Header.Add("Schmaccept", "png") req.Header.Add("Cache-Control", "omicron") @@ -444,7 +448,7 @@ var _ = Describe("TestServer", func() { failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -460,19 +464,19 @@ var _ = Describe("TestServer", func() { It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Header.Add("Accept", "jpeg") req.Header.Add("Accept", "png") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") resp, err = http.DefaultClient.Do(req) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) req.Header.Add("Accept", "jpeg") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") @@ -480,7 +484,7 @@ var _ = Describe("TestServer", func() { failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -494,14 +498,14 @@ var _ = Describe("TestServer", func() { It("should verify the body", func() { resp, err = http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("some body"))) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the body", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("wrong body"))) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -515,21 +519,21 @@ var _ = Describe("TestServer", func() { It("should verify the json body and the content type", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":3}`))) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the json body and the content type", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":4}`))) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) It("should verify the json body and the content type", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/not-json", bytes.NewReader([]byte(`{"b":2, "a":3}`))) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -543,14 +547,14 @@ var _ = Describe("TestServer", func() { It("should verify the json body and the content type", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3,5]`))) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the json body and the content type", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3]`))) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -577,13 +581,13 @@ var _ = Describe("TestServer", func() { It("should verify form values", func() { resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should ignore extra values", func() { formValues.Add("extra", "value") resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("fail on missing values", func() { @@ -591,7 +595,7 @@ var _ = Describe("TestServer", func() { failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) It("fail on incorrect values", func() { @@ -599,7 +603,7 @@ var _ = Describe("TestServer", func() { failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -616,13 +620,13 @@ var _ = Describe("TestServer", func() { It("should verify form values", func() { resp, err = http.PostForm(s.URL()+"/foo", formValues) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should ignore extra values", func() { formValues.Add("extra", "value") resp, err = http.PostForm(s.URL()+"/foo", formValues) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("fail on missing values", func() { @@ -630,7 +634,7 @@ var _ = Describe("TestServer", func() { failures := InterceptGomegaFailures(func() { resp, err = http.PostForm(s.URL()+"/foo", formValues) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) It("fail on incorrect values", func() { @@ -638,7 +642,7 @@ var _ = Describe("TestServer", func() { failures := InterceptGomegaFailures(func() { resp, err = http.PostForm(s.URL()+"/foo", formValues) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) }) @@ -654,14 +658,14 @@ var _ = Describe("TestServer", func() { It("verifies the form value", func() { resp, err = http.Get(s.URL() + "/foo?users=user1&users=user2") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("verifies the form value", func() { failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL() + "/foo?users=user1") }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -675,14 +679,14 @@ var _ = Describe("TestServer", func() { It("verifies the form value", func() { resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1", "user2"}}) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("verifies the form value", func() { failures := InterceptGomegaFailures(func() { resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1"}}) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) }) @@ -703,10 +707,10 @@ var _ = Describe("TestServer", func() { It("verifies the proto body and the content type", func() { serialized, err := proto.Marshal(message) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized)) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should verify the proto body and the content type", func() { @@ -715,22 +719,22 @@ var _ = Describe("TestServer", func() { Id: proto.Int32(0), Metadata: proto.String("some metadata"), }) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized)) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) It("should verify the proto body and the content type", func() { serialized, err := proto.Marshal(message) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/proto", "application/not-x-protobuf", bytes.NewReader(serialized)) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -748,22 +752,22 @@ var _ = Describe("TestServer", func() { It("should return the response", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(Equal([]byte("sweet"))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(Equal([]byte("sweet"))) resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusOK)) + Expect(resp.StatusCode).Should(Equal(http.StatusOK)) body, err = ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(Equal([]byte("sour"))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(Equal([]byte("sour"))) }) }) @@ -777,11 +781,11 @@ var _ = Describe("TestServer", func() { It("should return the headers too", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) - Ω(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet"))) - Ω(resp.Header.Get("X-Custom-Header")).Should(Equal("my header")) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet"))) + Expect(resp.Header.Get("X-Custom-Header")).Should(Equal("my header")) }) }) }) @@ -810,22 +814,22 @@ var _ = Describe("TestServer", func() { stringBody = "treat" resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(Equal([]byte("tasty"))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(Equal([]byte("tasty"))) resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err = ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(Equal([]byte("treat"))) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(Equal([]byte("treat"))) }) Context("when passed a nil body", func() { @@ -839,13 +843,13 @@ var _ = Describe("TestServer", func() { It("should return an empty body and not explode", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusOK)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).Should(Equal(http.StatusOK)) body, err := ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(BeEmpty()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(BeEmpty()) - Ω(s.ReceivedRequests()).Should(HaveLen(1)) + Expect(s.ReceivedRequests()).Should(HaveLen(1)) }) }) }) @@ -861,20 +865,20 @@ var _ = Describe("TestServer", func() { It("should return the response", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(MatchJSON("[1,2,3]")) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(MatchJSON("[1,2,3]")) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) }) @@ -893,16 +897,16 @@ var _ = Describe("TestServer", func() { It("should preserve those headers", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) + Expect(resp.Header["Stuff"]).Should(Equal([]string{"things"})) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) Context("when setting the Content-Type explicitly", func() { @@ -912,9 +916,9 @@ var _ = Describe("TestServer", func() { It("should use the Content-Type header that was explicitly set", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) }) }) }) @@ -946,20 +950,20 @@ var _ = Describe("TestServer", func() { Value: "Codes", } resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) - Ω(err).ShouldNot(HaveOccurred()) - Ω(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`)) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) }) @@ -980,16 +984,16 @@ var _ = Describe("TestServer", func() { It("should preserve those headers", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) + Expect(resp.Header["Stuff"]).Should(Equal([]string{"things"})) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) Context("when setting the Content-Type explicitly", func() { @@ -999,9 +1003,9 @@ var _ = Describe("TestServer", func() { It("should use the Content-Type header that was explicitly set", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) }) }) }) @@ -1026,21 +1030,21 @@ var _ = Describe("TestServer", func() { It("should return the response", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) + Expect(resp.StatusCode).Should(Equal(http.StatusCreated)) var received protobuf.SimpleMessage body, err := ioutil.ReadAll(resp.Body) err = proto.Unmarshal(body, &received) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) It("should set the Content-Type header to application/x-protobuf", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) }) }) @@ -1059,16 +1063,16 @@ var _ = Describe("TestServer", func() { It("should preserve those headers", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) + Expect(resp.Header["Stuff"]).Should(Equal([]string{"things"})) }) It("should set the Content-Type header to application/x-protobuf", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) }) Context("when setting the Content-Type explicitly", func() { @@ -1078,9 +1082,9 @@ var _ = Describe("TestServer", func() { It("should use the Content-Type header that was explicitly set", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"})) + Expect(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"})) }) }) }) diff --git a/vendor/github.com/onsi/gomega/go.mod b/vendor/github.com/onsi/gomega/go.mod new file mode 100644 index 00000000..65eedf69 --- /dev/null +++ b/vendor/github.com/onsi/gomega/go.mod @@ -0,0 +1,15 @@ +module github.com/onsi/gomega + +require ( + github.com/fsnotify/fsnotify v1.4.7 // indirect + github.com/golang/protobuf v1.2.0 + github.com/hpcloud/tail v1.0.0 // indirect + github.com/onsi/ginkgo v1.6.0 + golang.org/x/net v0.0.0-20180906233101-161cd47e91fd + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect + golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect + golang.org/x/text v0.3.0 // indirect + gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.2.1 +) diff --git a/vendor/github.com/onsi/gomega/go.sum b/vendor/github.com/onsi/gomega/go.sum new file mode 100644 index 00000000..b23f6ef0 --- /dev/null +++ b/vendor/github.com/onsi/gomega/go.sum @@ -0,0 +1,24 @@ +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go index 0d0f563a..51d7872f 100644 --- a/vendor/github.com/onsi/gomega/gomega_dsl.go +++ b/vendor/github.com/onsi/gomega/gomega_dsl.go @@ -24,14 +24,15 @@ import ( "github.com/onsi/gomega/types" ) -const GOMEGA_VERSION = "1.2.0" +const GOMEGA_VERSION = "1.4.2" const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil. If you're using Ginkgo then you probably forgot to put your assertion in an It(). Alternatively, you may have forgotten to register a fail handler with RegisterFailHandler() or RegisterTestingT(). +Depending on your vendoring solution you may be inadvertently importing gomega and subpackages (e.g. ghhtp, gexec,...) from different locations. ` -var globalFailHandler types.GomegaFailHandler +var globalFailWrapper *types.GomegaFailWrapper var defaultEventuallyTimeout = time.Second var defaultEventuallyPollingInterval = 10 * time.Millisecond @@ -41,26 +42,39 @@ var defaultConsistentlyPollingInterval = 10 * time.Millisecond //RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails //the fail handler passed into RegisterFailHandler is called. func RegisterFailHandler(handler types.GomegaFailHandler) { - globalFailHandler = handler + if handler == nil { + globalFailWrapper = nil + return + } + globalFailWrapper = &types.GomegaFailWrapper{ + Fail: handler, + TWithHelper: testingtsupport.EmptyTWithHelper{}, + } } //RegisterTestingT connects Gomega to Golang's XUnit style -//Testing.T tests. You'll need to call this at the top of each XUnit style test: +//Testing.T tests. It is now deprecated and you should use NewGomegaWithT() instead. // -// func TestFarmHasCow(t *testing.T) { -// RegisterTestingT(t) +//Legacy Documentation: // -// f := farm.New([]string{"Cow", "Horse"}) -// Expect(f.HasCow()).To(BeTrue(), "Farm should have cow") -// } +//You'll need to call this at the top of each XUnit style test: +// +// func TestFarmHasCow(t *testing.T) { +// RegisterTestingT(t) +// +// f := farm.New([]string{"Cow", "Horse"}) +// Expect(f.HasCow()).To(BeTrue(), "Farm should have cow") +// } // // Note that this *testing.T is registered *globally* by Gomega (this is why you don't have to // pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests // in parallel as the global fail handler cannot point to more than one testing.T at a time. // +// NewGomegaWithT() does not have this limitation +// // (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*). func RegisterTestingT(t types.GomegaTestingT) { - RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailHandler(t)) + RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail) } //InterceptGomegaHandlers runs a given callback and returns an array of @@ -73,7 +87,7 @@ func RegisterTestingT(t types.GomegaTestingT) { //This is most useful when testing custom matchers, but can also be used to check //on a value using a Gomega assertion without causing a test failure. func InterceptGomegaFailures(f func()) []string { - originalHandler := globalFailHandler + originalHandler := globalFailWrapper.Fail failures := []string{} RegisterFailHandler(func(message string, callerSkip ...int) { failures = append(failures, message) @@ -84,7 +98,7 @@ func InterceptGomegaFailures(f func()) []string { } //Ω wraps an actual value allowing assertions to be made on it: -// Ω("foo").Should(Equal("foo")) +// Ω("foo").Should(Equal("foo")) // //If Ω is passed more than one argument it will pass the *first* argument to the matcher. //All subsequent arguments will be required to be nil/zero. @@ -105,7 +119,7 @@ func Ω(actual interface{}, extra ...interface{}) GomegaAssertion { } //Expect wraps an actual value allowing assertions to be made on it: -// Expect("foo").To(Equal("foo")) +// Expect("foo").To(Equal("foo")) // //If Expect is passed more than one argument it will pass the *first* argument to the matcher. //All subsequent arguments will be required to be nil/zero. @@ -135,10 +149,10 @@ func Expect(actual interface{}, extra ...interface{}) GomegaAssertion { //error message to refer to the calling line in the test (as opposed to the line in the helper function) //set the first argument of `ExpectWithOffset` appropriately. func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) GomegaAssertion { - if globalFailHandler == nil { + if globalFailWrapper == nil { panic(nilFailHandlerPanic) } - return assertion.New(actual, globalFailHandler, offset, extra...) + return assertion.New(actual, globalFailWrapper, offset, extra...) } //Eventually wraps an actual value allowing assertions to be made on it. @@ -185,7 +199,7 @@ func Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAsserti //initial argument to indicate an offset in the call stack. This is useful when building helper //functions that contain matchers. To learn more, read about `ExpectWithOffset`. func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { - if globalFailHandler == nil { + if globalFailWrapper == nil { panic(nilFailHandlerPanic) } timeoutInterval := defaultEventuallyTimeout @@ -196,7 +210,7 @@ func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface if len(intervals) > 1 { pollingInterval = toDuration(intervals[1]) } - return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailHandler, timeoutInterval, pollingInterval, offset) + return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset) } //Consistently wraps an actual value allowing assertions to be made on it. @@ -230,7 +244,7 @@ func Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAsser //initial argument to indicate an offset in the call stack. This is useful when building helper //functions that contain matchers. To learn more, read about `ExpectWithOffset`. func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { - if globalFailHandler == nil { + if globalFailWrapper == nil { panic(nilFailHandlerPanic) } timeoutInterval := defaultConsistentlyDuration @@ -241,7 +255,7 @@ func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interfa if len(intervals) > 1 { pollingInterval = toDuration(intervals[1]) } - return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailHandler, timeoutInterval, pollingInterval, offset) + return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset) } //Set the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses. @@ -308,6 +322,60 @@ type GomegaAssertion interface { //OmegaMatcher is deprecated in favor of the better-named and better-organized types.GomegaMatcher but sticks around to support existing code that uses it type OmegaMatcher types.GomegaMatcher +//GomegaWithT wraps a *testing.T and provides `Expect`, `Eventually`, and `Consistently` methods. This allows you to leverage +//Gomega's rich ecosystem of matchers in standard `testing` test suites. +// +//Use `NewGomegaWithT` to instantiate a `GomegaWithT` +type GomegaWithT struct { + t types.GomegaTestingT +} + +//NewGomegaWithT takes a *testing.T and returngs a `GomegaWithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with +//Gomega's rich ecosystem of matchers in standard `testing` test suits. +// +// func TestFarmHasCow(t *testing.T) { +// g := GomegaWithT(t) +// +// f := farm.New([]string{"Cow", "Horse"}) +// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow") +// } +func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT { + return &GomegaWithT{ + t: t, + } +} + +//See documentation for Expect +func (g *GomegaWithT) Expect(actual interface{}, extra ...interface{}) GomegaAssertion { + return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...) +} + +//See documentation for Eventually +func (g *GomegaWithT) Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { + timeoutInterval := defaultEventuallyTimeout + pollingInterval := defaultEventuallyPollingInterval + if len(intervals) > 0 { + timeoutInterval = toDuration(intervals[0]) + } + if len(intervals) > 1 { + pollingInterval = toDuration(intervals[1]) + } + return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0) +} + +//See documentation for Consistently +func (g *GomegaWithT) Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { + timeoutInterval := defaultConsistentlyDuration + pollingInterval := defaultConsistentlyPollingInterval + if len(intervals) > 0 { + timeoutInterval = toDuration(intervals[0]) + } + if len(intervals) > 1 { + pollingInterval = toDuration(intervals[1]) + } + return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0) +} + func toDuration(input interface{}) time.Duration { duration, ok := input.(time.Duration) if ok { diff --git a/vendor/github.com/onsi/gomega/gstruct/elements.go b/vendor/github.com/onsi/gomega/gstruct/elements.go index a315fa13..13bf5b89 100644 --- a/vendor/github.com/onsi/gomega/gstruct/elements.go +++ b/vendor/github.com/onsi/gomega/gstruct/elements.go @@ -13,10 +13,14 @@ import ( //MatchAllElements succeeds if every element of a slice matches the element matcher it maps to //through the id function, and every element matcher is matched. -// Expect([]string{"a", "b"}).To(MatchAllElements(idFn, matchers.Elements{ -// "a": BeEqual("a"), -// "b": BeEqual("b"), -// }) +// idFn := func(element interface{}) string { +// return fmt.Sprintf("%v", element) +// } +// +// Expect([]string{"a", "b"}).To(MatchAllElements(idFn, Elements{ +// "a": Equal("a"), +// "b": Equal("b"), +// })) func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatcher { return &ElementsMatcher{ Identifier: identifier, @@ -26,10 +30,20 @@ func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatc //MatchElements succeeds if each element of a slice matches the element matcher it maps to //through the id function. It can ignore extra elements and/or missing elements. -// Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing|IgnoreExtra, matchers.Elements{ -// "a": BeEqual("a") -// "b": BeEqual("b"), -// }) +// idFn := func(element interface{}) string { +// return fmt.Sprintf("%v", element) +// } +// +// Expect([]string{"a", "b", "c"}).To(MatchElements(idFn, IgnoreExtras, Elements{ +// "a": Equal("a"), +// "b": Equal("b"), +// })) +// Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing, Elements{ +// "a": Equal("a"), +// "b": Equal("b"), +// "c": Equal("c"), +// "d": Equal("d"), +// })) func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher { return &ElementsMatcher{ Identifier: identifier, diff --git a/vendor/github.com/onsi/gomega/gstruct/elements_test.go b/vendor/github.com/onsi/gomega/gstruct/elements_test.go index 8ba78cb9..355d463e 100644 --- a/vendor/github.com/onsi/gomega/gstruct/elements_test.go +++ b/vendor/github.com/onsi/gomega/gstruct/elements_test.go @@ -19,22 +19,22 @@ var _ = Describe("Slice", func() { "b": Equal("b"), "a": Equal("a"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(missingElements).ShouldNot(m, "should fail with missing elements") - Ω(extraElements).ShouldNot(m, "should fail with extra elements") - Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") - Ω(nils).ShouldNot(m, "should fail with an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(missingElements).ShouldNot(m, "should fail with missing elements") + Expect(extraElements).ShouldNot(m, "should fail with extra elements") + Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements") + Expect(nils).ShouldNot(m, "should fail with an uninitialized slice") m = MatchAllElements(id, Elements{ "a": Equal("a"), "b": Equal("fail"), }) - Ω(allElements).ShouldNot(m, "should run nested matchers") + Expect(allElements).ShouldNot(m, "should run nested matchers") m = MatchAllElements(id, Elements{}) - Ω(empty).Should(m, "should handle empty slices") - Ω(allElements).ShouldNot(m, "should handle only empty slices") - Ω(nils).Should(m, "should handle nil slices") + Expect(empty).Should(m, "should handle empty slices") + Expect(allElements).ShouldNot(m, "should handle only empty slices") + Expect(nils).Should(m, "should handle nil slices") }) It("should ignore extra elements", func() { @@ -42,11 +42,11 @@ var _ = Describe("Slice", func() { "b": Equal("b"), "a": Equal("a"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(missingElements).ShouldNot(m, "should fail with missing elements") - Ω(extraElements).Should(m, "should ignore extra elements") - Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") - Ω(nils).ShouldNot(m, "should fail with an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(missingElements).ShouldNot(m, "should fail with missing elements") + Expect(extraElements).Should(m, "should ignore extra elements") + Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements") + Expect(nils).ShouldNot(m, "should fail with an uninitialized slice") }) It("should ignore missing elements", func() { @@ -54,11 +54,11 @@ var _ = Describe("Slice", func() { "a": Equal("a"), "b": Equal("b"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(missingElements).Should(m, "should ignore missing elements") - Ω(extraElements).ShouldNot(m, "should fail with extra elements") - Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") - Ω(nils).Should(m, "should ignore an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(missingElements).Should(m, "should ignore missing elements") + Expect(extraElements).ShouldNot(m, "should fail with extra elements") + Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements") + Expect(nils).Should(m, "should ignore an uninitialized slice") }) It("should ignore missing and extra elements", func() { @@ -66,17 +66,17 @@ var _ = Describe("Slice", func() { "a": Equal("a"), "b": Equal("b"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(missingElements).Should(m, "should ignore missing elements") - Ω(extraElements).Should(m, "should ignore extra elements") - Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") - Ω(nils).Should(m, "should ignore an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(missingElements).Should(m, "should ignore missing elements") + Expect(extraElements).Should(m, "should ignore extra elements") + Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements") + Expect(nils).Should(m, "should ignore an uninitialized slice") m = MatchElements(id, IgnoreExtras|IgnoreMissing, Elements{ "a": Equal("a"), "b": Equal("fail"), }) - Ω(allElements).ShouldNot(m, "should run nested matchers") + Expect(allElements).ShouldNot(m, "should run nested matchers") }) Context("with elements that share a key", func() { @@ -94,11 +94,11 @@ var _ = Describe("Slice", func() { "a": ContainSubstring("1"), "b": ContainSubstring("1"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") - Ω(extraElements).ShouldNot(m, "should reject with extra keys") - Ω(missingElements).ShouldNot(m, "should reject with missing keys") - Ω(nils).ShouldNot(m, "should fail with an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") + Expect(extraElements).ShouldNot(m, "should reject with extra keys") + Expect(missingElements).ShouldNot(m, "should reject with missing keys") + Expect(nils).ShouldNot(m, "should fail with an uninitialized slice") }) It("should ignore missing", func() { @@ -106,11 +106,11 @@ var _ = Describe("Slice", func() { "a": ContainSubstring("1"), "b": ContainSubstring("1"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") - Ω(extraElements).ShouldNot(m, "should reject with extra keys") - Ω(missingElements).Should(m, "should allow missing keys") - Ω(nils).Should(m, "should allow an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") + Expect(extraElements).ShouldNot(m, "should reject with extra keys") + Expect(missingElements).Should(m, "should allow missing keys") + Expect(nils).Should(m, "should allow an uninitialized slice") }) It("should ignore extras", func() { @@ -118,11 +118,11 @@ var _ = Describe("Slice", func() { "a": ContainSubstring("1"), "b": ContainSubstring("1"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") - Ω(extraElements).Should(m, "should allow extra keys") - Ω(missingElements).ShouldNot(m, "should reject missing keys") - Ω(nils).ShouldNot(m, "should reject an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") + Expect(extraElements).Should(m, "should allow extra keys") + Expect(missingElements).ShouldNot(m, "should reject missing keys") + Expect(nils).ShouldNot(m, "should reject an uninitialized slice") }) It("should ignore missing and extras", func() { @@ -130,11 +130,11 @@ var _ = Describe("Slice", func() { "a": ContainSubstring("1"), "b": ContainSubstring("1"), }) - Ω(allElements).Should(m, "should match all elements") - Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") - Ω(extraElements).Should(m, "should allow extra keys") - Ω(missingElements).Should(m, "should allow missing keys") - Ω(nils).Should(m, "should allow an uninitialized slice") + Expect(allElements).Should(m, "should match all elements") + Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher") + Expect(extraElements).Should(m, "should allow extra keys") + Expect(missingElements).Should(m, "should allow missing keys") + Expect(nils).Should(m, "should allow an uninitialized slice") }) }) }) diff --git a/vendor/github.com/onsi/gomega/gstruct/fields.go b/vendor/github.com/onsi/gomega/gstruct/fields.go index 0020b873..2eb2d088 100644 --- a/vendor/github.com/onsi/gomega/gstruct/fields.go +++ b/vendor/github.com/onsi/gomega/gstruct/fields.go @@ -14,10 +14,21 @@ import ( //MatchAllFields succeeds if every field of a struct matches the field matcher associated with //it, and every element matcher is matched. -// Expect([]string{"a", "b"}).To(MatchAllFields(gstruct.Fields{ -// "a": BeEqual("a"), -// "b": BeEqual("b"), -// }) +// actual := struct{ +// A int +// B []bool +// C string +// }{ +// A: 5, +// B: []bool{true, false}, +// C: "foo", +// } +// +// Expect(actual).To(MatchAllFields(Fields{ +// "A": Equal(5), +// "B": ConsistOf(true, false), +// "C": Equal("foo"), +// })) func MatchAllFields(fields Fields) types.GomegaMatcher { return &FieldsMatcher{ Fields: fields, @@ -26,10 +37,26 @@ func MatchAllFields(fields Fields) types.GomegaMatcher { //MatchFields succeeds if each element of a struct matches the field matcher associated with //it. It can ignore extra fields and/or missing fields. -// Expect([]string{"a", "c"}).To(MatchFields(IgnoreMissing|IgnoreExtra, gstruct.Fields{ -// "a": BeEqual("a") -// "b": BeEqual("b"), -// }) +// actual := struct{ +// A int +// B []bool +// C string +// }{ +// A: 5, +// B: []bool{true, false}, +// C: "foo", +// } +// +// Expect(actual).To(MatchFields(IgnoreExtras, Fields{ +// "A": Equal(5), +// "B": ConsistOf(true, false), +// })) +// Expect(actual).To(MatchFields(IgnoreMissing, Fields{ +// "A": Equal(5), +// "B": ConsistOf(true, false), +// "C": Equal("foo"), +// "D": Equal("extra"), +// })) func MatchFields(options Options, fields Fields) types.GomegaMatcher { return &FieldsMatcher{ Fields: fields, diff --git a/vendor/github.com/onsi/gomega/gstruct/fields_test.go b/vendor/github.com/onsi/gomega/gstruct/fields_test.go index 61f4afc4..e4e039e2 100644 --- a/vendor/github.com/onsi/gomega/gstruct/fields_test.go +++ b/vendor/github.com/onsi/gomega/gstruct/fields_test.go @@ -17,22 +17,22 @@ var _ = Describe("Struct", func() { "B": Equal("b"), "A": Equal("a"), }) - Ω(allFields).Should(m, "should match all fields") - Ω(missingFields).ShouldNot(m, "should fail with missing fields") - Ω(extraFields).ShouldNot(m, "should fail with extra fields") - Ω(emptyFields).ShouldNot(m, "should fail with empty fields") + Expect(allFields).Should(m, "should match all fields") + Expect(missingFields).ShouldNot(m, "should fail with missing fields") + Expect(extraFields).ShouldNot(m, "should fail with extra fields") + Expect(emptyFields).ShouldNot(m, "should fail with empty fields") m = MatchAllFields(Fields{ "A": Equal("a"), "B": Equal("fail"), }) - Ω(allFields).ShouldNot(m, "should run nested matchers") + Expect(allFields).ShouldNot(m, "should run nested matchers") }) It("should handle empty structs", func() { m := MatchAllFields(Fields{}) - Ω(struct{}{}).Should(m, "should handle empty structs") - Ω(allFields).ShouldNot(m, "should fail with extra fields") + Expect(struct{}{}).Should(m, "should handle empty structs") + Expect(allFields).ShouldNot(m, "should fail with extra fields") }) It("should ignore missing fields", func() { @@ -40,10 +40,10 @@ var _ = Describe("Struct", func() { "B": Equal("b"), "A": Equal("a"), }) - Ω(allFields).Should(m, "should match all fields") - Ω(missingFields).Should(m, "should ignore missing fields") - Ω(extraFields).ShouldNot(m, "should fail with extra fields") - Ω(emptyFields).ShouldNot(m, "should fail with empty fields") + Expect(allFields).Should(m, "should match all fields") + Expect(missingFields).Should(m, "should ignore missing fields") + Expect(extraFields).ShouldNot(m, "should fail with extra fields") + Expect(emptyFields).ShouldNot(m, "should fail with empty fields") }) It("should ignore extra fields", func() { @@ -51,10 +51,10 @@ var _ = Describe("Struct", func() { "B": Equal("b"), "A": Equal("a"), }) - Ω(allFields).Should(m, "should match all fields") - Ω(missingFields).ShouldNot(m, "should fail with missing fields") - Ω(extraFields).Should(m, "should ignore extra fields") - Ω(emptyFields).ShouldNot(m, "should fail with empty fields") + Expect(allFields).Should(m, "should match all fields") + Expect(missingFields).ShouldNot(m, "should fail with missing fields") + Expect(extraFields).Should(m, "should ignore extra fields") + Expect(emptyFields).ShouldNot(m, "should fail with empty fields") }) It("should ignore missing and extra fields", func() { @@ -62,15 +62,15 @@ var _ = Describe("Struct", func() { "B": Equal("b"), "A": Equal("a"), }) - Ω(allFields).Should(m, "should match all fields") - Ω(missingFields).Should(m, "should ignore missing fields") - Ω(extraFields).Should(m, "should ignore extra fields") - Ω(emptyFields).ShouldNot(m, "should fail with empty fields") + Expect(allFields).Should(m, "should match all fields") + Expect(missingFields).Should(m, "should ignore missing fields") + Expect(extraFields).Should(m, "should ignore extra fields") + Expect(emptyFields).ShouldNot(m, "should fail with empty fields") m = MatchFields(IgnoreMissing|IgnoreExtras, Fields{ "A": Equal("a"), "B": Equal("fail"), }) - Ω(allFields).ShouldNot(m, "should run nested matchers") + Expect(allFields).ShouldNot(m, "should run nested matchers") }) }) diff --git a/vendor/github.com/onsi/gomega/gstruct/ignore_test.go b/vendor/github.com/onsi/gomega/gstruct/ignore_test.go index 70e1d400..07775e74 100644 --- a/vendor/github.com/onsi/gomega/gstruct/ignore_test.go +++ b/vendor/github.com/onsi/gomega/gstruct/ignore_test.go @@ -8,16 +8,16 @@ import ( var _ = Describe("Ignore", func() { It("should always succeed", func() { - Ω(nil).Should(Ignore()) - Ω(struct{}{}).Should(Ignore()) - Ω(0).Should(Ignore()) - Ω(false).Should(Ignore()) + Expect(nil).Should(Ignore()) + Expect(struct{}{}).Should(Ignore()) + Expect(0).Should(Ignore()) + Expect(false).Should(Ignore()) }) It("should always fail", func() { - Ω(nil).ShouldNot(Reject()) - Ω(struct{}{}).ShouldNot(Reject()) - Ω(1).ShouldNot(Reject()) - Ω(true).ShouldNot(Reject()) + Expect(nil).ShouldNot(Reject()) + Expect(struct{}{}).ShouldNot(Reject()) + Expect(1).ShouldNot(Reject()) + Expect(true).ShouldNot(Reject()) }) }) diff --git a/vendor/github.com/onsi/gomega/gstruct/pointer_test.go b/vendor/github.com/onsi/gomega/gstruct/pointer_test.go index b02081c4..805a92ab 100644 --- a/vendor/github.com/onsi/gomega/gstruct/pointer_test.go +++ b/vendor/github.com/onsi/gomega/gstruct/pointer_test.go @@ -9,25 +9,25 @@ import ( var _ = Describe("PointTo", func() { It("should fail when passed nil", func() { var p *struct{} - Ω(p).Should(BeNil()) + Expect(p).Should(BeNil()) }) It("should succeed when passed non-nil pointer", func() { var s struct{} - Ω(&s).Should(PointTo(Ignore())) + Expect(&s).Should(PointTo(Ignore())) }) It("should unwrap the pointee value", func() { i := 1 - Ω(&i).Should(PointTo(Equal(1))) - Ω(&i).ShouldNot(PointTo(Equal(2))) + Expect(&i).Should(PointTo(Equal(1))) + Expect(&i).ShouldNot(PointTo(Equal(2))) }) It("should work with nested pointers", func() { i := 1 ip := &i ipp := &ip - Ω(ipp).Should(PointTo(PointTo(Equal(1)))) - Ω(ipp).ShouldNot(PointTo(PointTo(Equal(2)))) + Expect(ipp).Should(PointTo(PointTo(Equal(1)))) + Expect(ipp).ShouldNot(PointTo(PointTo(Equal(2)))) }) }) diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion.go index b73673f2..00197b67 100644 --- a/vendor/github.com/onsi/gomega/internal/assertion/assertion.go +++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion.go @@ -9,37 +9,42 @@ import ( type Assertion struct { actualInput interface{} - fail types.GomegaFailHandler + failWrapper *types.GomegaFailWrapper offset int extra []interface{} } -func New(actualInput interface{}, fail types.GomegaFailHandler, offset int, extra ...interface{}) *Assertion { +func New(actualInput interface{}, failWrapper *types.GomegaFailWrapper, offset int, extra ...interface{}) *Assertion { return &Assertion{ actualInput: actualInput, - fail: fail, + failWrapper: failWrapper, offset: offset, extra: extra, } } func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) } func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) } func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) } func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) } func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) } @@ -55,8 +60,9 @@ func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool { matches, err := matcher.Match(assertion.actualInput) description := assertion.buildDescription(optionalDescription...) + assertion.failWrapper.TWithHelper.Helper() if err != nil { - assertion.fail(description+err.Error(), 2+assertion.offset) + assertion.failWrapper.Fail(description+err.Error(), 2+assertion.offset) return false } if matches != desiredMatch { @@ -66,7 +72,7 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool } else { message = matcher.NegatedFailureMessage(assertion.actualInput) } - assertion.fail(description+message, 2+assertion.offset) + assertion.failWrapper.Fail(description+message, 2+assertion.offset) return false } @@ -80,7 +86,8 @@ func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool { } description := assertion.buildDescription(optionalDescription...) - assertion.fail(description+message, 2+assertion.offset) + assertion.failWrapper.TWithHelper.Helper() + assertion.failWrapper.Fail(description+message, 2+assertion.offset) return false } diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go index c03b7a32..cac0d24c 100644 --- a/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go +++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go @@ -3,10 +3,13 @@ package assertion_test import ( "errors" + "github.com/onsi/gomega/internal/testingtsupport" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/internal/assertion" "github.com/onsi/gomega/internal/fakematcher" + "github.com/onsi/gomega/types" ) var _ = Describe("Assertion", func() { @@ -19,45 +22,48 @@ var _ = Describe("Assertion", func() { input := "The thing I'm testing" - var fakeFailHandler = func(message string, callerSkip ...int) { - failureMessage = message - if len(callerSkip) == 1 { - failureCallerSkip = callerSkip[0] - } + var fakeFailWrapper = &types.GomegaFailWrapper{ + Fail: func(message string, callerSkip ...int) { + failureMessage = message + if len(callerSkip) == 1 { + failureCallerSkip = callerSkip[0] + } + }, + TWithHelper: testingtsupport.EmptyTWithHelper{}, } BeforeEach(func() { matcher = &fakematcher.FakeMatcher{} failureMessage = "" failureCallerSkip = 0 - a = New(input, fakeFailHandler, 1) + a = New(input, fakeFailWrapper, 1) }) Context("when called", func() { It("should pass the provided input value to the matcher", func() { a.Should(matcher) - Ω(matcher.ReceivedActual).Should(Equal(input)) + Expect(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.ShouldNot(matcher) - Ω(matcher.ReceivedActual).Should(Equal(input)) + Expect(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.To(matcher) - Ω(matcher.ReceivedActual).Should(Equal(input)) + Expect(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.ToNot(matcher) - Ω(matcher.ReceivedActual).Should(Equal(input)) + Expect(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.NotTo(matcher) - Ω(matcher.ReceivedActual).Should(Equal(input)) + Expect(matcher.ReceivedActual).Should(Equal(input)) }) }) @@ -70,23 +76,23 @@ var _ = Describe("Assertion", func() { Context("and a positive assertion is being made", func() { It("should not call the failure callback", func() { a.Should(matcher) - Ω(failureMessage).Should(Equal("")) + Expect(failureMessage).Should(Equal("")) }) It("should be true", func() { - Ω(a.Should(matcher)).Should(BeTrue()) + Expect(a.Should(matcher)).Should(BeTrue()) }) }) Context("and a negative assertion is being made", func() { It("should call the failure callback", func() { a.ShouldNot(matcher) - Ω(failureMessage).Should(Equal("negative: The thing I'm testing")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(failureMessage).Should(Equal("negative: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) }) It("should be false", func() { - Ω(a.ShouldNot(matcher)).Should(BeFalse()) + Expect(a.ShouldNot(matcher)).Should(BeFalse()) }) }) }) @@ -100,23 +106,23 @@ var _ = Describe("Assertion", func() { Context("and a positive assertion is being made", func() { It("should call the failure callback", func() { a.Should(matcher) - Ω(failureMessage).Should(Equal("positive: The thing I'm testing")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(failureMessage).Should(Equal("positive: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) }) It("should be false", func() { - Ω(a.Should(matcher)).Should(BeFalse()) + Expect(a.Should(matcher)).Should(BeFalse()) }) }) Context("and a negative assertion is being made", func() { It("should not call the failure callback", func() { a.ShouldNot(matcher) - Ω(failureMessage).Should(Equal("")) + Expect(failureMessage).Should(Equal("")) }) It("should be true", func() { - Ω(a.ShouldNot(matcher)).Should(BeTrue()) + Expect(a.ShouldNot(matcher)).Should(BeTrue()) }) }) }) @@ -130,16 +136,16 @@ var _ = Describe("Assertion", func() { Context("and there is an optional description", func() { It("should append the description to the failure message", func() { a.Should(matcher, "A description") - Ω(failureMessage).Should(Equal("A description\npositive: The thing I'm testing")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(failureMessage).Should(Equal("A description\npositive: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) }) }) Context("and there are multiple arguments to the optional description", func() { It("should append the formatted description to the failure message", func() { a.Should(matcher, "A description of [%d]", 3) - Ω(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) }) }) }) @@ -153,8 +159,8 @@ var _ = Describe("Assertion", func() { It("should call the failure callback", func() { matcher.MatchesToReturn = true a.Should(matcher) - Ω(failureMessage).Should(Equal("Kaboom!")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(failureMessage).Should(Equal("Kaboom!")) + Expect(failureCallerSkip).Should(Equal(3)) }) }) @@ -162,20 +168,20 @@ var _ = Describe("Assertion", func() { It("should call the failure callback", func() { matcher.MatchesToReturn = false a.ShouldNot(matcher) - Ω(failureMessage).Should(Equal("Kaboom!")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(failureMessage).Should(Equal("Kaboom!")) + Expect(failureCallerSkip).Should(Equal(3)) }) }) It("should always be false", func() { - Ω(a.Should(matcher)).Should(BeFalse()) - Ω(a.ShouldNot(matcher)).Should(BeFalse()) + Expect(a.Should(matcher)).Should(BeFalse()) + Expect(a.ShouldNot(matcher)).Should(BeFalse()) }) }) Context("when there are extra parameters", func() { It("(a simple example)", func() { - Ω(func() (string, int, error) { + Expect(func() (string, int, error) { return "foo", 0, nil }()).Should(Equal("foo")) }) @@ -186,13 +192,13 @@ var _ = Describe("Assertion", func() { matcher.ErrToReturn = nil var typedNil []string - a = New(input, fakeFailHandler, 1, 0, nil, typedNil) + a = New(input, fakeFailWrapper, 1, 0, nil, typedNil) result := a.Should(matcher) - Ω(result).Should(BeTrue()) - Ω(matcher.ReceivedActual).Should(Equal(input)) + Expect(result).Should(BeTrue()) + Expect(matcher.ReceivedActual).Should(Equal(input)) - Ω(failureMessage).Should(BeZero()) + Expect(failureMessage).Should(BeZero()) }) }) @@ -201,36 +207,36 @@ var _ = Describe("Assertion", func() { matcher.MatchesToReturn = false matcher.ErrToReturn = nil - a = New(input, fakeFailHandler, 1, errors.New("foo")) + a = New(input, fakeFailWrapper, 1, errors.New("foo")) result := a.Should(matcher) - Ω(result).Should(BeFalse()) - Ω(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called") - Ω(failureMessage).Should(ContainSubstring("foo")) + Expect(result).Should(BeFalse()) + Expect(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called") + Expect(failureMessage).Should(ContainSubstring("foo")) failureMessage = "" - a = New(input, fakeFailHandler, 1, nil, 1) + a = New(input, fakeFailWrapper, 1, nil, 1) result = a.ShouldNot(matcher) - Ω(result).Should(BeFalse()) - Ω(failureMessage).Should(ContainSubstring("1")) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("1")) failureMessage = "" - a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) + a = New(input, fakeFailWrapper, 1, nil, 0, []string{"foo"}) result = a.To(matcher) - Ω(result).Should(BeFalse()) - Ω(failureMessage).Should(ContainSubstring("foo")) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("foo")) failureMessage = "" - a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) + a = New(input, fakeFailWrapper, 1, nil, 0, []string{"foo"}) result = a.ToNot(matcher) - Ω(result).Should(BeFalse()) - Ω(failureMessage).Should(ContainSubstring("foo")) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("foo")) failureMessage = "" - a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) + a = New(input, fakeFailWrapper, 1, nil, 0, []string{"foo"}) result = a.NotTo(matcher) - Ω(result).Should(BeFalse()) - Ω(failureMessage).Should(ContainSubstring("foo")) - Ω(failureCallerSkip).Should(Equal(3)) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("foo")) + Expect(failureCallerSkip).Should(Equal(3)) }) }) }) @@ -246,7 +252,7 @@ var _ = Describe("Assertion", func() { }() RegisterFailHandler(nil) - Ω(true).Should(BeTrue()) + Expect(true).Should(BeTrue()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go index bce08530..cdab233e 100644 --- a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go +++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go @@ -22,11 +22,11 @@ type AsyncAssertion struct { actualInput interface{} timeoutInterval time.Duration pollingInterval time.Duration - fail types.GomegaFailHandler + failWrapper *types.GomegaFailWrapper offset int } -func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.GomegaFailHandler, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion { +func New(asyncType AsyncAssertionType, actualInput interface{}, failWrapper *types.GomegaFailWrapper, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion { actualType := reflect.TypeOf(actualInput) if actualType.Kind() == reflect.Func { if actualType.NumIn() != 0 || actualType.NumOut() == 0 { @@ -37,7 +37,7 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg return &AsyncAssertion{ asyncType: asyncType, actualInput: actualInput, - fail: fail, + failWrapper: failWrapper, timeoutInterval: timeoutInterval, pollingInterval: pollingInterval, offset: offset, @@ -45,10 +45,12 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg } func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.match(matcher, true, optionalDescription...) } func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { + assertion.failWrapper.TWithHelper.Helper() return assertion.match(matcher, false, optionalDescription...) } @@ -110,6 +112,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch matches, err = matcher.Match(value) } + assertion.failWrapper.TWithHelper.Helper() + fail := func(preamble string) { errMsg := "" message := "" @@ -122,7 +126,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch message = matcher.NegatedFailureMessage(value) } } - assertion.fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset) + assertion.failWrapper.TWithHelper.Helper() + assertion.failWrapper.Fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset) } if assertion.asyncType == AsyncAssertionTypeEventually { diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go index 3d7e3489..afd61a7c 100644 --- a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go +++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go @@ -4,9 +4,12 @@ import ( "errors" "time" + "github.com/onsi/gomega/internal/testingtsupport" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/internal/asyncassertion" + "github.com/onsi/gomega/types" ) var _ = Describe("Async Assertion", func() { @@ -15,9 +18,12 @@ var _ = Describe("Async Assertion", func() { callerSkip int ) - var fakeFailHandler = func(message string, skip ...int) { - failureMessage = message - callerSkip = skip[0] + var fakeFailWrapper = &types.GomegaFailWrapper{ + Fail: func(message string, skip ...int) { + failureMessage = message + callerSkip = skip[0] + }, + TWithHelper: testingtsupport.EmptyTWithHelper{}, } BeforeEach(func() { @@ -32,10 +38,10 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeEventually, func() int { counter++ return counter - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically("==", 5)) - Ω(failureMessage).Should(BeZero()) + Expect(failureMessage).Should(BeZero()) }) It("should continue when the matcher errors", func() { @@ -46,13 +52,13 @@ var _ = Describe("Async Assertion", func() { return "not-a-number" //this should cause the matcher to error } return counter - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically("==", 5), "My description %d", 2) - Ω(failureMessage).Should(ContainSubstring("Timed out after")) - Ω(failureMessage).Should(ContainSubstring("My description 2")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) }) It("should be able to timeout", func() { @@ -60,16 +66,16 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeEventually, func() int { counter++ return counter - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically(">", 100), "My description %d", 2) - Ω(counter).Should(BeNumerically(">", 8)) - Ω(counter).Should(BeNumerically("<=", 10)) - Ω(failureMessage).Should(ContainSubstring("Timed out after")) - Ω(failureMessage).Should(MatchRegexp(`\: \d`), "Should pass the correct value to the matcher message formatter.") - Ω(failureMessage).Should(ContainSubstring("My description 2")) - Ω(callerSkip).Should(Equal(4)) + Expect(counter).Should(BeNumerically(">", 8)) + Expect(counter).Should(BeNumerically("<=", 10)) + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(MatchRegexp(`\: \d`), "Should pass the correct value to the matcher message formatter.") + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) }) }) @@ -79,38 +85,38 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeEventually, func() int { counter += 1 return counter - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(BeNumerically("<", 3)) - Ω(counter).Should(Equal(3)) - Ω(failureMessage).Should(BeZero()) + Expect(counter).Should(Equal(3)) + Expect(failureMessage).Should(BeZero()) }) It("should timeout when the matcher errors", func() { a := New(AsyncAssertionTypeEventually, func() interface{} { return 0 //this should cause the matcher to error - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(HaveLen(0), "My description %d", 2) - Ω(failureMessage).Should(ContainSubstring("Timed out after")) - Ω(failureMessage).Should(ContainSubstring("Error:")) - Ω(failureMessage).Should(ContainSubstring("My description 2")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring("Error:")) + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) }) It("should be able to timeout", func() { a := New(AsyncAssertionTypeEventually, func() int { return 0 - }, fakeFailHandler, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(Equal(0), "My description %d", 2) - Ω(failureMessage).Should(ContainSubstring("Timed out after")) - Ω(failureMessage).Should(ContainSubstring(": 0"), "Should pass the correct value to the matcher message formatter.") - Ω(failureMessage).Should(ContainSubstring("My description 2")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring(": 0"), "Should pass the correct value to the matcher message formatter.") + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) }) }) @@ -128,13 +134,13 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeEventually, func() (int, error) { i++ return i, errors.New("bam") - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(Equal(2)) - Ω(failureMessage).Should(ContainSubstring("Timed out after")) - Ω(failureMessage).Should(ContainSubstring("Error:")) - Ω(failureMessage).Should(ContainSubstring("bam")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring("Error:")) + Expect(failureMessage).Should(ContainSubstring("bam")) + Expect(callerSkip).Should(Equal(4)) }) }) @@ -164,12 +170,12 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeConsistently, func() string { calls++ return "foo" - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(Equal("foo")) - Ω(calls).Should(BeNumerically(">", 8)) - Ω(calls).Should(BeNumerically("<=", 10)) - Ω(failureMessage).Should(BeZero()) + Expect(calls).Should(BeNumerically(">", 8)) + Expect(calls).Should(BeNumerically("<=", 10)) + Expect(failureMessage).Should(BeZero()) }) }) @@ -182,11 +188,11 @@ var _ = Describe("Async Assertion", func() { return "bar" } return "foo" - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(Equal("foo")) - Ω(failureMessage).Should(ContainSubstring("to equal")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("to equal")) + Expect(callerSkip).Should(Equal(4)) }) }) @@ -199,11 +205,11 @@ var _ = Describe("Async Assertion", func() { return 3 } return []int{1, 2, 3} - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(HaveLen(3)) - Ω(failureMessage).Should(ContainSubstring("HaveLen matcher expects")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("HaveLen matcher expects")) + Expect(callerSkip).Should(Equal(4)) }) }) }) @@ -212,10 +218,10 @@ var _ = Describe("Async Assertion", func() { Context("when the matcher consistently passes for the duration", func() { It("should pass", func() { c := make(chan bool) - a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + a := New(AsyncAssertionTypeConsistently, c, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(Receive()) - Ω(failureMessage).Should(BeZero()) + Expect(failureMessage).Should(BeZero()) }) }) @@ -227,10 +233,10 @@ var _ = Describe("Async Assertion", func() { c <- true }() - a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + a := New(AsyncAssertionTypeConsistently, c, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(Receive()) - Ω(failureMessage).Should(ContainSubstring("not to receive anything")) + Expect(failureMessage).Should(ContainSubstring("not to receive anything")) }) }) @@ -240,11 +246,11 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeConsistently, func() interface{} { calls++ return calls - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(BeNumerically(">", 5)) - Ω(failureMessage).Should(ContainSubstring("not to be >")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("not to be >")) + Expect(callerSkip).Should(Equal(4)) }) }) }) @@ -263,12 +269,12 @@ var _ = Describe("Async Assertion", func() { a := New(AsyncAssertionTypeEventually, func() (int, error) { i++ return i, errors.New("bam") - }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically(">=", 2)) - Ω(failureMessage).Should(ContainSubstring("Error:")) - Ω(failureMessage).Should(ContainSubstring("bam")) - Ω(callerSkip).Should(Equal(4)) + Expect(failureMessage).Should(ContainSubstring("Error:")) + Expect(failureMessage).Should(ContainSubstring("bam")) + Expect(callerSkip).Should(Equal(4)) }) }) @@ -291,20 +297,20 @@ var _ = Describe("Async Assertion", func() { Context("when passed a function with the wrong # or arguments & returns", func() { It("should panic", func() { - Ω(func() { - New(AsyncAssertionTypeEventually, func() {}, fakeFailHandler, 0, 0, 1) + Expect(func() { + New(AsyncAssertionTypeEventually, func() {}, fakeFailWrapper, 0, 0, 1) }).Should(Panic()) - Ω(func() { - New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailHandler, 0, 0, 1) + Expect(func() { + New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailWrapper, 0, 0, 1) }).Should(Panic()) - Ω(func() { - New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailHandler, 0, 0, 1) + Expect(func() { + New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailWrapper, 0, 0, 1) }).ShouldNot(Panic()) - Ω(func() { - New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailHandler, 0, 0, 1) + Expect(func() { + New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailWrapper, 0, 0, 1) }).ShouldNot(Panic()) }) }) @@ -319,9 +325,9 @@ var _ = Describe("Async Assertion", func() { failures := InterceptGomegaFailures(func() { Eventually(c, 0.1).Should(Receive()) }) - Ω(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond)) + Expect(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) @@ -336,9 +342,9 @@ var _ = Describe("Async Assertion", func() { return c }, 0.1).Should(Receive()) }) - Ω(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond)) + Expect(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go index ac891252..bb27032f 100644 --- a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go +++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go @@ -8,30 +8,50 @@ import ( "github.com/onsi/gomega/types" ) +var StackTracePruneRE = regexp.MustCompile(`\/gomega\/|\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) + +type EmptyTWithHelper struct{} + +func (e EmptyTWithHelper) Helper() {} + type gomegaTestingT interface { Fatalf(format string, args ...interface{}) } -func BuildTestingTGomegaFailHandler(t gomegaTestingT) types.GomegaFailHandler { - return func(message string, callerSkip ...int) { - skip := 1 - if len(callerSkip) > 0 { - skip = callerSkip[0] +func BuildTestingTGomegaFailWrapper(t gomegaTestingT) *types.GomegaFailWrapper { + tWithHelper, hasHelper := t.(types.TWithHelper) + if !hasHelper { + tWithHelper = EmptyTWithHelper{} + } + + fail := func(message string, callerSkip ...int) { + if hasHelper { + tWithHelper.Helper() + t.Fatalf("\n%s", message) + } else { + skip := 2 + if len(callerSkip) > 0 { + skip += callerSkip[0] + } + stackTrace := pruneStack(string(debug.Stack()), skip) + t.Fatalf("\n%s\n%s\n", stackTrace, message) } - stackTrace := pruneStack(string(debug.Stack()), skip) - t.Fatalf("\n%s\n%s", stackTrace, message) + } + + return &types.GomegaFailWrapper{ + Fail: fail, + TWithHelper: tWithHelper, } } func pruneStack(fullStackTrace string, skip int) string { - stack := strings.Split(fullStackTrace, "\n") - if len(stack) > 2*(skip+1) { - stack = stack[2*(skip+1):] + stack := strings.Split(fullStackTrace, "\n")[1:] + if len(stack) > 2*skip { + stack = stack[2*skip:] } prunedStack := []string{} - re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) for i := 0; i < len(stack)/2; i++ { - if !re.Match([]byte(stack[i*2])) { + if !StackTracePruneRE.Match([]byte(stack[i*2])) { prunedStack = append(prunedStack, stack[i*2]) prunedStack = append(prunedStack, stack[i*2+1]) } diff --git a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go index b9fbd6c6..8fd8f0a6 100644 --- a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go +++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go @@ -1,8 +1,14 @@ package testingtsupport_test import ( + "regexp" + "time" + + "github.com/onsi/gomega/internal/testingtsupport" + . "github.com/onsi/gomega" + "fmt" "testing" ) @@ -10,3 +16,77 @@ func TestTestingT(t *testing.T) { RegisterTestingT(t) Ω(true).Should(BeTrue()) } + +type FakeTWithHelper struct { + LastFatal string +} + +func (f *FakeTWithHelper) Fatalf(format string, args ...interface{}) { + f.LastFatal = fmt.Sprintf(format, args...) +} + +func TestGomegaWithTWithoutHelper(t *testing.T) { + g := NewGomegaWithT(t) + + testingtsupport.StackTracePruneRE = regexp.MustCompile(`\/ginkgo\/`) + + f := &FakeTWithHelper{} + testG := NewGomegaWithT(f) + + testG.Expect("foo").To(Equal("foo")) + g.Expect(f.LastFatal).To(BeZero()) + + testG.Expect("foo").To(Equal("bar")) + g.Expect(f.LastFatal).To(ContainSubstring(": foo")) + g.Expect(f.LastFatal).To(ContainSubstring("testingtsupport_test"), "It should include a stacktrace") + + testG.Eventually("foo2", time.Millisecond).Should(Equal("bar")) + g.Expect(f.LastFatal).To(ContainSubstring(": foo2")) + + testG.Consistently("foo3", time.Millisecond).Should(Equal("bar")) + g.Expect(f.LastFatal).To(ContainSubstring(": foo3")) +} + +type FakeTWithoutHelper struct { + LastFatal string + HelperCount int +} + +func (f *FakeTWithoutHelper) Fatalf(format string, args ...interface{}) { + f.LastFatal = fmt.Sprintf(format, args...) +} + +func (f *FakeTWithoutHelper) Helper() { + f.HelperCount += 1 +} + +func (f *FakeTWithoutHelper) ResetHelper() { + f.HelperCount = 0 +} + +func TestGomegaWithTWithHelper(t *testing.T) { + g := NewGomegaWithT(t) + + f := &FakeTWithoutHelper{} + testG := NewGomegaWithT(f) + + testG.Expect("foo").To(Equal("foo")) + g.Expect(f.LastFatal).To(BeZero()) + g.Expect(f.HelperCount).To(BeNumerically(">", 0)) + f.ResetHelper() + + testG.Expect("foo").To(Equal("bar")) + g.Expect(f.LastFatal).To(ContainSubstring(": foo")) + g.Expect(f.LastFatal).NotTo(ContainSubstring("testingtsupport_test"), "It should _not_ include a stacktrace") + g.Expect(f.HelperCount).To(BeNumerically(">", 0)) + f.ResetHelper() + + testG.Eventually("foo2", time.Millisecond).Should(Equal("bar")) + g.Expect(f.LastFatal).To(ContainSubstring(": foo2")) + g.Expect(f.HelperCount).To(BeNumerically(">", 0)) + f.ResetHelper() + + testG.Consistently("foo3", time.Millisecond).Should(Equal("bar")) + g.Expect(f.LastFatal).To(ContainSubstring(": foo3")) + g.Expect(f.HelperCount).To(BeNumerically(">", 0)) +} diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go index e6e85d07..c3a326dd 100644 --- a/vendor/github.com/onsi/gomega/matchers.go +++ b/vendor/github.com/onsi/gomega/matchers.go @@ -53,7 +53,7 @@ func BeFalse() types.GomegaMatcher { //HaveOccurred succeeds if actual is a non-nil error //The typical Go error checking pattern looks like: // err := SomethingThatMightFail() -// Ω(err).ShouldNot(HaveOccurred()) +// Expect(err).ShouldNot(HaveOccurred()) func HaveOccurred() types.GomegaMatcher { return &matchers.HaveOccurredMatcher{} } @@ -61,10 +61,10 @@ func HaveOccurred() types.GomegaMatcher { //Succeed passes if actual is a nil error //Succeed is intended to be used with functions that return a single error value. Instead of // err := SomethingThatMightFail() -// Ω(err).ShouldNot(HaveOccurred()) +// Expect(err).ShouldNot(HaveOccurred()) // //You can write: -// Ω(SomethingThatMightFail()).Should(Succeed()) +// Expect(SomethingThatMightFail()).Should(Succeed()) // //It is a mistake to use Succeed with a function that has multiple return values. Gomega's Ω and Expect //functions automatically trigger failure if any return values after the first return value are non-zero/non-nil. @@ -76,8 +76,8 @@ func Succeed() types.GomegaMatcher { //MatchError succeeds if actual is a non-nil error that matches the passed in string/error. // //These are valid use-cases: -// Ω(err).Should(MatchError("an error")) //asserts that err.Error() == "an error" -// Ω(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual) +// Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error" +// Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual) // //It is an error for err to be nil or an object that does not implement the Error interface func MatchError(expected interface{}) types.GomegaMatcher { @@ -106,11 +106,11 @@ func BeClosed() types.GomegaMatcher { // //Receive returns immediately and never blocks: // -//- If there is nothing on the channel `c` then Ω(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass. +//- If there is nothing on the channel `c` then Expect(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass. // -//- If the channel `c` is closed then Ω(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass. +//- If the channel `c` is closed then Expect(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass. // -//- If there is something on the channel `c` ready to be read, then Ω(c).Should(Receive()) will pass and Ω(c).ShouldNot(Receive()) will fail. +//- If there is something on the channel `c` ready to be read, then Expect(c).Should(Receive()) will pass and Ω(c).ShouldNot(Receive()) will fail. // //If you have a go-routine running in the background that will write to channel `c` you can: // Eventually(c).Should(Receive()) @@ -121,7 +121,7 @@ func BeClosed() types.GomegaMatcher { // Consistently(c).ShouldNot(Receive()) // //You can pass `Receive` a matcher. If you do so, it will match the received object against the matcher. For example: -// Ω(c).Should(Receive(Equal("foo"))) +// Expect(c).Should(Receive(Equal("foo"))) // //When given a matcher, `Receive` will always fail if there is nothing to be received on the channel. // @@ -134,8 +134,8 @@ func BeClosed() types.GomegaMatcher { //Finally, if you want to have a reference to the value *sent* to the channel you can pass the `Receive` matcher a pointer to a variable of the appropriate type: // var myThing thing // Eventually(thingChan).Should(Receive(&myThing)) -// Ω(myThing.Sprocket).Should(Equal("foo")) -// Ω(myThing.IsValid()).Should(BeTrue()) +// Expect(myThing.Sprocket).Should(Equal("foo")) +// Expect(myThing.IsValid()).Should(BeTrue()) func Receive(args ...interface{}) types.GomegaMatcher { var arg interface{} if len(args) > 0 { @@ -153,9 +153,9 @@ func Receive(args ...interface{}) types.GomegaMatcher { // //BeSent never blocks: // -//- If the channel `c` is not ready to receive then Ω(c).Should(BeSent("foo")) will fail immediately +//- If the channel `c` is not ready to receive then Expect(c).Should(BeSent("foo")) will fail immediately //- If the channel `c` is eventually ready to receive then Eventually(c).Should(BeSent("foo")) will succeed.. presuming the channel becomes ready to receive before Eventually's timeout -//- If the channel `c` is closed then Ω(c).Should(BeSent("foo")) and Ω(c).ShouldNot(BeSent("foo")) will both fail immediately +//- If the channel `c` is closed then Expect(c).Should(BeSent("foo")) and Ω(c).ShouldNot(BeSent("foo")) will both fail immediately // //Of course, the value is actually sent to the channel. The point of `BeSent` is less to make an assertion about the availability of the channel (which is typically an implementation detail that your test should not be concerned with). //Rather, the point of `BeSent` is to make it possible to easily and expressively write tests that can timeout on blocked channel sends. @@ -259,7 +259,7 @@ func BeZero() types.GomegaMatcher { //ContainElement succeeds if actual contains the passed in element. //By default ContainElement() uses Equal() to perform the match, however a //matcher can be passed in instead: -// Ω([]string{"Foo", "FooBar"}).Should(ContainElement(ContainSubstring("Bar"))) +// Expect([]string{"Foo", "FooBar"}).Should(ContainElement(ContainSubstring("Bar"))) // //Actual must be an array, slice or map. //For maps, ContainElement searches through the map's values. @@ -269,19 +269,19 @@ func ContainElement(element interface{}) types.GomegaMatcher { } } -//ConsistOf succeeds if actual contains preciely the elements passed into the matcher. The ordering of the elements does not matter. +//ConsistOf succeeds if actual contains precisely the elements passed into the matcher. The ordering of the elements does not matter. //By default ConsistOf() uses Equal() to match the elements, however custom matchers can be passed in instead. Here are some examples: // -// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf("FooBar", "Foo")) -// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Bar"), "Foo")) -// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Foo"), ContainSubstring("Foo"))) +// Expect([]string{"Foo", "FooBar"}).Should(ConsistOf("FooBar", "Foo")) +// Expect([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Bar"), "Foo")) +// Expect([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Foo"), ContainSubstring("Foo"))) // //Actual must be an array, slice or map. For maps, ConsistOf matches against the map's values. // //You typically pass variadic arguments to ConsistOf (as in the examples above). However, if you need to pass in a slice you can provided that it //is the only element passed in to ConsistOf: // -// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf([]string{"FooBar", "Foo"})) +// Expect([]string{"Foo", "FooBar"}).Should(ConsistOf([]string{"FooBar", "Foo"})) // //Note that Go's type system does not allow you to write this as ConsistOf([]string{"FooBar", "Foo"}...) as []string and []interface{} are different types - hence the need for this special rule. func ConsistOf(elements ...interface{}) types.GomegaMatcher { @@ -293,7 +293,7 @@ func ConsistOf(elements ...interface{}) types.GomegaMatcher { //HaveKey succeeds if actual is a map with the passed in key. //By default HaveKey uses Equal() to perform the match, however a //matcher can be passed in instead: -// Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKey(MatchRegexp(`.+Foo$`))) +// Expect(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKey(MatchRegexp(`.+Foo$`))) func HaveKey(key interface{}) types.GomegaMatcher { return &matchers.HaveKeyMatcher{ Key: key, @@ -303,8 +303,8 @@ func HaveKey(key interface{}) types.GomegaMatcher { //HaveKeyWithValue succeeds if actual is a map with the passed in key and value. //By default HaveKeyWithValue uses Equal() to perform the match, however a //matcher can be passed in instead: -// Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue("Foo", "Bar")) -// Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue(MatchRegexp(`.+Foo$`), "Bar")) +// Expect(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue("Foo", "Bar")) +// Expect(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue(MatchRegexp(`.+Foo$`), "Bar")) func HaveKeyWithValue(key interface{}, value interface{}) types.GomegaMatcher { return &matchers.HaveKeyWithValueMatcher{ Key: key, @@ -314,15 +314,15 @@ func HaveKeyWithValue(key interface{}, value interface{}) types.GomegaMatcher { //BeNumerically performs numerical assertions in a type-agnostic way. //Actual and expected should be numbers, though the specific type of -//number is irrelevant (floa32, float64, uint8, etc...). +//number is irrelevant (float32, float64, uint8, etc...). // //There are six, self-explanatory, supported comparators: -// Ω(1.0).Should(BeNumerically("==", 1)) -// Ω(1.0).Should(BeNumerically("~", 0.999, 0.01)) -// Ω(1.0).Should(BeNumerically(">", 0.9)) -// Ω(1.0).Should(BeNumerically(">=", 1.0)) -// Ω(1.0).Should(BeNumerically("<", 3)) -// Ω(1.0).Should(BeNumerically("<=", 1.0)) +// Expect(1.0).Should(BeNumerically("==", 1)) +// Expect(1.0).Should(BeNumerically("~", 0.999, 0.01)) +// Expect(1.0).Should(BeNumerically(">", 0.9)) +// Expect(1.0).Should(BeNumerically(">=", 1.0)) +// Expect(1.0).Should(BeNumerically("<", 3)) +// Expect(1.0).Should(BeNumerically("<=", 1.0)) func BeNumerically(comparator string, compareTo ...interface{}) types.GomegaMatcher { return &matchers.BeNumericallyMatcher{ Comparator: comparator, @@ -332,8 +332,8 @@ func BeNumerically(comparator string, compareTo ...interface{}) types.GomegaMatc //BeTemporally compares time.Time's like BeNumerically //Actual and expected must be time.Time. The comparators are the same as for BeNumerically -// Ω(time.Now()).Should(BeTemporally(">", time.Time{})) -// Ω(time.Now()).Should(BeTemporally("~", time.Now(), time.Second)) +// Expect(time.Now()).Should(BeTemporally(">", time.Time{})) +// Expect(time.Now()).Should(BeTemporally("~", time.Now(), time.Second)) func BeTemporally(comparator string, compareTo time.Time, threshold ...time.Duration) types.GomegaMatcher { return &matchers.BeTemporallyMatcher{ Comparator: comparator, @@ -344,10 +344,10 @@ func BeTemporally(comparator string, compareTo time.Time, threshold ...time.Dura //BeAssignableToTypeOf succeeds if actual is assignable to the type of expected. //It will return an error when one of the values is nil. -// Ω(0).Should(BeAssignableToTypeOf(0)) // Same values -// Ω(5).Should(BeAssignableToTypeOf(-1)) // different values same type -// Ω("foo").Should(BeAssignableToTypeOf("bar")) // different values same type -// Ω(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) +// Expect(0).Should(BeAssignableToTypeOf(0)) // Same values +// Expect(5).Should(BeAssignableToTypeOf(-1)) // different values same type +// Expect("foo").Should(BeAssignableToTypeOf("bar")) // different values same type +// Expect(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) func BeAssignableToTypeOf(expected interface{}) types.GomegaMatcher { return &matchers.AssignableToTypeOfMatcher{ Expected: expected, @@ -366,13 +366,13 @@ func BeAnExistingFile() types.GomegaMatcher { return &matchers.BeAnExistingFileMatcher{} } -//BeARegularFile succeeds iff a file exists and is a regular file. +//BeARegularFile succeeds if a file exists and is a regular file. //Actual must be a string representing the abs path to the file being checked. func BeARegularFile() types.GomegaMatcher { return &matchers.BeARegularFileMatcher{} } -//BeADirectory succeeds iff a file exists and is a directory. +//BeADirectory succeeds if a file exists and is a directory. //Actual must be a string representing the abs path to the file being checked. func BeADirectory() types.GomegaMatcher { return &matchers.BeADirectoryMatcher{} @@ -388,7 +388,7 @@ func And(ms ...types.GomegaMatcher) types.GomegaMatcher { } //SatisfyAll is an alias for And(). -// Ω("hi").Should(SatisfyAll(HaveLen(2), Equal("hi"))) +// Expect("hi").Should(SatisfyAll(HaveLen(2), Equal("hi"))) func SatisfyAll(matchers ...types.GomegaMatcher) types.GomegaMatcher { return And(matchers...) } diff --git a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go index 89a1fc21..51f8be6a 100644 --- a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go @@ -12,8 +12,12 @@ type AssignableToTypeOfMatcher struct { } func (matcher *AssignableToTypeOfMatcher) Match(actual interface{}) (success bool, err error) { - if actual == nil || matcher.Expected == nil { + if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") + } else if matcher.Expected == nil { + return false, fmt.Errorf("Refusing to compare type to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") + } else if actual == nil { + return false, nil } actualType := reflect.TypeOf(actual) diff --git a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go index d2280e05..471a46d9 100644 --- a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go @@ -9,22 +9,38 @@ import ( var _ = Describe("AssignableToTypeOf", func() { Context("When asserting assignability between types", func() { It("should do the right thing", func() { - Ω(0).Should(BeAssignableToTypeOf(0)) - Ω(5).Should(BeAssignableToTypeOf(-1)) - Ω("foo").Should(BeAssignableToTypeOf("bar")) - Ω(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) + Expect(0).Should(BeAssignableToTypeOf(0)) + Expect(5).Should(BeAssignableToTypeOf(-1)) + Expect("foo").Should(BeAssignableToTypeOf("bar")) + Expect(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) - Ω(0).ShouldNot(BeAssignableToTypeOf("bar")) - Ω(5).ShouldNot(BeAssignableToTypeOf(struct{ Foo string }{})) - Ω("foo").ShouldNot(BeAssignableToTypeOf(42)) + Expect(0).ShouldNot(BeAssignableToTypeOf("bar")) + Expect(5).ShouldNot(BeAssignableToTypeOf(struct{ Foo string }{})) + Expect("foo").ShouldNot(BeAssignableToTypeOf(42)) }) }) Context("When asserting nil values", func() { It("should error", func() { success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + + Context("When actual is nil and expected is not nil", func() { + It("should return false without error", func() { + success, err := (&AssignableToTypeOfMatcher{Expected: 17}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + + Context("When actual is not nil and expected is nil", func() { + It("should error", func() { + success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(17) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/attributes_slice.go b/vendor/github.com/onsi/gomega/matchers/attributes_slice.go new file mode 100644 index 00000000..355b362f --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/attributes_slice.go @@ -0,0 +1,14 @@ +package matchers + +import ( + "encoding/xml" + "strings" +) + +type attributesSlice []xml.Attr + +func (attrs attributesSlice) Len() int { return len(attrs) } +func (attrs attributesSlice) Less(i, j int) bool { + return strings.Compare(attrs[i].Name.Local, attrs[j].Name.Local) == -1 +} +func (attrs attributesSlice) Swap(i, j int) { attrs[i], attrs[j] = attrs[j], attrs[i] } diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go b/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go index e59d7699..bc874276 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go @@ -12,29 +12,29 @@ import ( var _ = Describe("BeADirectoryMatcher", func() { Context("when passed a string", func() { It("should do the right thing", func() { - Ω("/dne/test").ShouldNot(BeADirectory()) + Expect("/dne/test").ShouldNot(BeADirectory()) tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpFile.Name()) - Ω(tmpFile.Name()).ShouldNot(BeADirectory()) + Expect(tmpFile.Name()).ShouldNot(BeADirectory()) tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpDir) - Ω(tmpDir).Should(BeADirectory()) + Expect(tmpDir).Should(BeADirectory()) }) }) Context("when passed something else", func() { It("should error", func() { success, err := (&BeADirectoryMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeADirectoryMatcher{}).Match(true) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go index 951e750d..eae06a03 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go @@ -12,29 +12,29 @@ import ( var _ = Describe("BeARegularFileMatcher", func() { Context("when passed a string", func() { It("should do the right thing", func() { - Ω("/dne/test").ShouldNot(BeARegularFile()) + Expect("/dne/test").ShouldNot(BeARegularFile()) tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpFile.Name()) - Ω(tmpFile.Name()).Should(BeARegularFile()) + Expect(tmpFile.Name()).Should(BeARegularFile()) tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpDir) - Ω(tmpDir).ShouldNot(BeARegularFile()) + Expect(tmpDir).ShouldNot(BeARegularFile()) }) }) Context("when passed something else", func() { It("should error", func() { success, err := (&BeARegularFileMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeARegularFileMatcher{}).Match(true) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go index 775f7b6a..e28bd0d6 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go @@ -12,29 +12,29 @@ import ( var _ = Describe("BeAnExistingFileMatcher", func() { Context("when passed a string", func() { It("should do the right thing", func() { - Ω("/dne/test").ShouldNot(BeAnExistingFile()) + Expect("/dne/test").ShouldNot(BeAnExistingFile()) tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpFile.Name()) - Ω(tmpFile.Name()).Should(BeAnExistingFile()) + Expect(tmpFile.Name()).Should(BeAnExistingFile()) tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpDir) - Ω(tmpDir).Should(BeAnExistingFile()) + Expect(tmpDir).Should(BeAnExistingFile()) }) }) Context("when passed something else", func() { It("should error", func() { success, err := (&BeAnExistingFileMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeAnExistingFileMatcher{}).Match(true) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go index c1b49959..ed6f6928 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "reflect" + + "github.com/onsi/gomega/format" ) type BeClosedMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go index b2c40c91..c2e49ab5 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go @@ -10,20 +10,20 @@ var _ = Describe("BeClosedMatcher", func() { Context("when passed a channel", func() { It("should do the right thing", func() { openChannel := make(chan bool) - Ω(openChannel).ShouldNot(BeClosed()) + Expect(openChannel).ShouldNot(BeClosed()) var openReaderChannel <-chan bool openReaderChannel = openChannel - Ω(openReaderChannel).ShouldNot(BeClosed()) + Expect(openReaderChannel).ShouldNot(BeClosed()) closedChannel := make(chan bool) close(closedChannel) - Ω(closedChannel).Should(BeClosed()) + Expect(closedChannel).Should(BeClosed()) var closedReaderChannel <-chan bool closedReaderChannel = closedChannel - Ω(closedReaderChannel).Should(BeClosed()) + Expect(closedReaderChannel).Should(BeClosed()) }) }) @@ -34,8 +34,8 @@ var _ = Describe("BeClosedMatcher", func() { openWriterChannel = openChannel success, err := (&BeClosedMatcher{}).Match(openWriterChannel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) closedChannel := make(chan bool) close(closedChannel) @@ -44,8 +44,8 @@ var _ = Describe("BeClosedMatcher", func() { closedWriterChannel = closedChannel success, err = (&BeClosedMatcher{}).Match(closedWriterChannel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) @@ -55,16 +55,16 @@ var _ = Describe("BeClosedMatcher", func() { var nilChannel chan bool success, err := (&BeClosedMatcher{}).Match(nilChannel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeClosedMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeClosedMatcher{}).Match(7) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go index 55bdd7d1..8b00311b 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go @@ -2,6 +2,7 @@ package matchers import ( "fmt" + "github.com/onsi/gomega/format" ) diff --git a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go index 541c1b95..132480cf 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go @@ -9,44 +9,44 @@ import ( var _ = Describe("BeEmpty", func() { Context("when passed a supported type", func() { It("should do the right thing", func() { - Ω("").Should(BeEmpty()) - Ω(" ").ShouldNot(BeEmpty()) + Expect("").Should(BeEmpty()) + Expect(" ").ShouldNot(BeEmpty()) - Ω([0]int{}).Should(BeEmpty()) - Ω([1]int{1}).ShouldNot(BeEmpty()) + Expect([0]int{}).Should(BeEmpty()) + Expect([1]int{1}).ShouldNot(BeEmpty()) - Ω([]int{}).Should(BeEmpty()) - Ω([]int{1}).ShouldNot(BeEmpty()) + Expect([]int{}).Should(BeEmpty()) + Expect([]int{1}).ShouldNot(BeEmpty()) - Ω(map[string]int{}).Should(BeEmpty()) - Ω(map[string]int{"a": 1}).ShouldNot(BeEmpty()) + Expect(map[string]int{}).Should(BeEmpty()) + Expect(map[string]int{"a": 1}).ShouldNot(BeEmpty()) c := make(chan bool, 1) - Ω(c).Should(BeEmpty()) + Expect(c).Should(BeEmpty()) c <- true - Ω(c).ShouldNot(BeEmpty()) + Expect(c).ShouldNot(BeEmpty()) }) }) Context("when passed a correctly typed nil", func() { It("should be true", func() { var nilSlice []int - Ω(nilSlice).Should(BeEmpty()) + Expect(nilSlice).Should(BeEmpty()) var nilMap map[int]string - Ω(nilMap).Should(BeEmpty()) + Expect(nilMap).Should(BeEmpty()) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&BeEmptyMatcher{}).Match(0) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeEmptyMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go index 32a0c310..97ab20a4 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "reflect" + + "github.com/onsi/gomega/format" ) type BeEquivalentToMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go index def5104f..4d9d11d2 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go @@ -11,40 +11,40 @@ var _ = Describe("BeEquivalentTo", func() { It("should error", func() { success, err := (&BeEquivalentToMatcher{Expected: nil}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("When asserting on nil", func() { It("should do the right thing", func() { - Ω("foo").ShouldNot(BeEquivalentTo(nil)) - Ω(nil).ShouldNot(BeEquivalentTo(3)) - Ω([]int{1, 2}).ShouldNot(BeEquivalentTo(nil)) + Expect("foo").ShouldNot(BeEquivalentTo(nil)) + Expect(nil).ShouldNot(BeEquivalentTo(3)) + Expect([]int{1, 2}).ShouldNot(BeEquivalentTo(nil)) }) }) Context("When asserting on type aliases", func() { It("should the right thing", func() { - Ω(StringAlias("foo")).Should(BeEquivalentTo("foo")) - Ω("foo").Should(BeEquivalentTo(StringAlias("foo"))) - Ω(StringAlias("foo")).ShouldNot(BeEquivalentTo("bar")) - Ω("foo").ShouldNot(BeEquivalentTo(StringAlias("bar"))) + Expect(StringAlias("foo")).Should(BeEquivalentTo("foo")) + Expect("foo").Should(BeEquivalentTo(StringAlias("foo"))) + Expect(StringAlias("foo")).ShouldNot(BeEquivalentTo("bar")) + Expect("foo").ShouldNot(BeEquivalentTo(StringAlias("bar"))) }) }) Context("When asserting on numbers", func() { It("should convert actual to expected and do the right thing", func() { - Ω(5).Should(BeEquivalentTo(5)) - Ω(5.0).Should(BeEquivalentTo(5.0)) - Ω(5).Should(BeEquivalentTo(5.0)) + Expect(5).Should(BeEquivalentTo(5)) + Expect(5.0).Should(BeEquivalentTo(5.0)) + Expect(5).Should(BeEquivalentTo(5.0)) - Ω(5).ShouldNot(BeEquivalentTo("5")) - Ω(5).ShouldNot(BeEquivalentTo(3)) + Expect(5).ShouldNot(BeEquivalentTo("5")) + Expect(5).ShouldNot(BeEquivalentTo(3)) //Here be dragons! - Ω(5.1).Should(BeEquivalentTo(5)) - Ω(5).ShouldNot(BeEquivalentTo(5.1)) + Expect(5.1).Should(BeEquivalentTo(5)) + Expect(5).ShouldNot(BeEquivalentTo(5.1)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go index 0b224cbb..91d3b779 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go @@ -2,6 +2,7 @@ package matchers import ( "fmt" + "github.com/onsi/gomega/format" ) diff --git a/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go index 3965a2c5..25e70633 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go @@ -8,13 +8,13 @@ import ( var _ = Describe("BeFalse", func() { It("should handle true and false correctly", func() { - Ω(true).ShouldNot(BeFalse()) - Ω(false).Should(BeFalse()) + Expect(true).ShouldNot(BeFalse()) + Expect(false).Should(BeFalse()) }) It("should only support booleans", func() { success, err := (&BeFalseMatcher{}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go b/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go index 8b90a1a6..7fdd56ee 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go @@ -13,49 +13,49 @@ var _ = Describe("BeIdenticalTo", func() { It("should error", func() { success, err := (&BeIdenticalToMatcher{Expected: nil}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) It("should treat the same pointer to a struct as identical", func() { mySpecialStruct := myCustomType{} - Ω(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct)) - Ω(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct)) + Expect(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct)) + Expect(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct)) }) It("should be strict about types", func() { - Ω(5).ShouldNot(BeIdenticalTo("5")) - Ω(5).ShouldNot(BeIdenticalTo(5.0)) - Ω(5).ShouldNot(BeIdenticalTo(3)) + Expect(5).ShouldNot(BeIdenticalTo("5")) + Expect(5).ShouldNot(BeIdenticalTo(5.0)) + Expect(5).ShouldNot(BeIdenticalTo(3)) }) It("should treat primtives as identical", func() { - Ω("5").Should(BeIdenticalTo("5")) - Ω("5").ShouldNot(BeIdenticalTo("55")) + Expect("5").Should(BeIdenticalTo("5")) + Expect("5").ShouldNot(BeIdenticalTo("55")) - Ω(5.55).Should(BeIdenticalTo(5.55)) - Ω(5.55).ShouldNot(BeIdenticalTo(6.66)) + Expect(5.55).Should(BeIdenticalTo(5.55)) + Expect(5.55).ShouldNot(BeIdenticalTo(6.66)) - Ω(5).Should(BeIdenticalTo(5)) - Ω(5).ShouldNot(BeIdenticalTo(55)) + Expect(5).Should(BeIdenticalTo(5)) + Expect(5).ShouldNot(BeIdenticalTo(55)) }) It("should treat the same pointers to a slice as identical", func() { mySlice := []int{1, 2} - Ω(&mySlice).Should(BeIdenticalTo(&mySlice)) - Ω(&mySlice).ShouldNot(BeIdenticalTo(&[]int{1, 2})) + Expect(&mySlice).Should(BeIdenticalTo(&mySlice)) + Expect(&mySlice).ShouldNot(BeIdenticalTo(&[]int{1, 2})) }) It("should treat the same pointers to a map as identical", func() { myMap := map[string]string{"a": "b", "c": "d"} - Ω(&myMap).Should(BeIdenticalTo(&myMap)) - Ω(myMap).ShouldNot(BeIdenticalTo(map[string]string{"a": "b", "c": "d"})) + Expect(&myMap).Should(BeIdenticalTo(&myMap)) + Expect(myMap).ShouldNot(BeIdenticalTo(map[string]string{"a": "b", "c": "d"})) }) It("should treat the same pointers to an error as identical", func() { myError := errors.New("foo") - Ω(&myError).Should(BeIdenticalTo(&myError)) - Ω(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar"))) + Expect(&myError).Should(BeIdenticalTo(&myError)) + Expect(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar"))) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go index 75332536..c35aa3d7 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go @@ -7,22 +7,22 @@ import ( var _ = Describe("BeNil", func() { It("should succeed when passed nil", func() { - Ω(nil).Should(BeNil()) + Expect(nil).Should(BeNil()) }) It("should succeed when passed a typed nil", func() { var a []int - Ω(a).Should(BeNil()) + Expect(a).Should(BeNil()) }) It("should succeed when passing nil pointer", func() { var f *struct{} - Ω(f).Should(BeNil()) + Expect(f).Should(BeNil()) }) It("should not succeed when not passed nil", func() { - Ω(0).ShouldNot(BeNil()) - Ω(false).ShouldNot(BeNil()) - Ω("").ShouldNot(BeNil()) + Expect(0).ShouldNot(BeNil()) + Expect(false).ShouldNot(BeNil()) + Expect("").ShouldNot(BeNil()) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go index 0c157f61..9f4f77ee 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go @@ -13,11 +13,23 @@ type BeNumericallyMatcher struct { } func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) { - return format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo[0]) + return matcher.FormatFailureMessage(actual, false) } func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) { - return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo[0]) + return matcher.FormatFailureMessage(actual, true) +} + +func (matcher *BeNumericallyMatcher) FormatFailureMessage(actual interface{}, negated bool) (message string) { + if len(matcher.CompareTo) == 1 { + message = fmt.Sprintf("to be %s", matcher.Comparator) + } else { + message = fmt.Sprintf("to be within %v of %s", matcher.CompareTo[1], matcher.Comparator) + } + if negated { + message = "not " + message + } + return format.Message(actual, message, matcher.CompareTo[0]) } func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) { diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go index 43fdb1fe..c7d7c3f7 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go @@ -9,79 +9,103 @@ import ( var _ = Describe("BeNumerically", func() { Context("when passed a number", func() { It("should support ==", func() { - Ω(uint32(5)).Should(BeNumerically("==", 5)) - Ω(float64(5.0)).Should(BeNumerically("==", 5)) - Ω(int8(5)).Should(BeNumerically("==", 5)) + Expect(uint32(5)).Should(BeNumerically("==", 5)) + Expect(float64(5.0)).Should(BeNumerically("==", 5)) + Expect(int8(5)).Should(BeNumerically("==", 5)) }) It("should not have false positives", func() { - Ω(5.1).ShouldNot(BeNumerically("==", 5)) - Ω(5).ShouldNot(BeNumerically("==", 5.1)) + Expect(5.1).ShouldNot(BeNumerically("==", 5)) + Expect(5).ShouldNot(BeNumerically("==", 5.1)) }) It("should support >", func() { - Ω(uint32(5)).Should(BeNumerically(">", 4)) - Ω(float64(5.0)).Should(BeNumerically(">", 4.9)) - Ω(int8(5)).Should(BeNumerically(">", 4)) + Expect(uint32(5)).Should(BeNumerically(">", 4)) + Expect(float64(5.0)).Should(BeNumerically(">", 4.9)) + Expect(int8(5)).Should(BeNumerically(">", 4)) - Ω(uint32(5)).ShouldNot(BeNumerically(">", 5)) - Ω(float64(5.0)).ShouldNot(BeNumerically(">", 5.0)) - Ω(int8(5)).ShouldNot(BeNumerically(">", 5)) + Expect(uint32(5)).ShouldNot(BeNumerically(">", 5)) + Expect(float64(5.0)).ShouldNot(BeNumerically(">", 5.0)) + Expect(int8(5)).ShouldNot(BeNumerically(">", 5)) }) It("should support <", func() { - Ω(uint32(5)).Should(BeNumerically("<", 6)) - Ω(float64(5.0)).Should(BeNumerically("<", 5.1)) - Ω(int8(5)).Should(BeNumerically("<", 6)) + Expect(uint32(5)).Should(BeNumerically("<", 6)) + Expect(float64(5.0)).Should(BeNumerically("<", 5.1)) + Expect(int8(5)).Should(BeNumerically("<", 6)) - Ω(uint32(5)).ShouldNot(BeNumerically("<", 5)) - Ω(float64(5.0)).ShouldNot(BeNumerically("<", 5.0)) - Ω(int8(5)).ShouldNot(BeNumerically("<", 5)) + Expect(uint32(5)).ShouldNot(BeNumerically("<", 5)) + Expect(float64(5.0)).ShouldNot(BeNumerically("<", 5.0)) + Expect(int8(5)).ShouldNot(BeNumerically("<", 5)) }) It("should support >=", func() { - Ω(uint32(5)).Should(BeNumerically(">=", 4)) - Ω(float64(5.0)).Should(BeNumerically(">=", 4.9)) - Ω(int8(5)).Should(BeNumerically(">=", 4)) + Expect(uint32(5)).Should(BeNumerically(">=", 4)) + Expect(float64(5.0)).Should(BeNumerically(">=", 4.9)) + Expect(int8(5)).Should(BeNumerically(">=", 4)) - Ω(uint32(5)).Should(BeNumerically(">=", 5)) - Ω(float64(5.0)).Should(BeNumerically(">=", 5.0)) - Ω(int8(5)).Should(BeNumerically(">=", 5)) + Expect(uint32(5)).Should(BeNumerically(">=", 5)) + Expect(float64(5.0)).Should(BeNumerically(">=", 5.0)) + Expect(int8(5)).Should(BeNumerically(">=", 5)) - Ω(uint32(5)).ShouldNot(BeNumerically(">=", 6)) - Ω(float64(5.0)).ShouldNot(BeNumerically(">=", 5.1)) - Ω(int8(5)).ShouldNot(BeNumerically(">=", 6)) + Expect(uint32(5)).ShouldNot(BeNumerically(">=", 6)) + Expect(float64(5.0)).ShouldNot(BeNumerically(">=", 5.1)) + Expect(int8(5)).ShouldNot(BeNumerically(">=", 6)) }) It("should support <=", func() { - Ω(uint32(5)).Should(BeNumerically("<=", 6)) - Ω(float64(5.0)).Should(BeNumerically("<=", 5.1)) - Ω(int8(5)).Should(BeNumerically("<=", 6)) + Expect(uint32(5)).Should(BeNumerically("<=", 6)) + Expect(float64(5.0)).Should(BeNumerically("<=", 5.1)) + Expect(int8(5)).Should(BeNumerically("<=", 6)) - Ω(uint32(5)).Should(BeNumerically("<=", 5)) - Ω(float64(5.0)).Should(BeNumerically("<=", 5.0)) - Ω(int8(5)).Should(BeNumerically("<=", 5)) + Expect(uint32(5)).Should(BeNumerically("<=", 5)) + Expect(float64(5.0)).Should(BeNumerically("<=", 5.0)) + Expect(int8(5)).Should(BeNumerically("<=", 5)) - Ω(uint32(5)).ShouldNot(BeNumerically("<=", 4)) - Ω(float64(5.0)).ShouldNot(BeNumerically("<=", 4.9)) - Ω(int8(5)).Should(BeNumerically("<=", 5)) + Expect(uint32(5)).ShouldNot(BeNumerically("<=", 4)) + Expect(float64(5.0)).ShouldNot(BeNumerically("<=", 4.9)) + Expect(int8(5)).Should(BeNumerically("<=", 5)) }) Context("when passed ~", func() { Context("when passed a float", func() { Context("and there is no precision parameter", func() { It("should default to 1e-8", func() { - Ω(5.00000001).Should(BeNumerically("~", 5.00000002)) - Ω(5.00000001).ShouldNot(BeNumerically("~", 5.0000001)) + Expect(5.00000001).Should(BeNumerically("~", 5.00000002)) + Expect(5.00000001).ShouldNot(BeNumerically("~", 5.0000001)) + }) + + It("should show failure message", func(){ + actual := BeNumerically("~", 4.98).FailureMessage(123) + expected := "Expected\n : 123\nto be ~\n : 4.98" + Expect(actual).To(Equal(expected)) + }) + + It("should show negated failure message", func(){ + actual := BeNumerically("~", 4.98).NegatedFailureMessage(123) + expected := "Expected\n : 123\nnot to be ~\n : 4.98" + Expect(actual).To(Equal(expected)) }) }) Context("and there is a precision parameter", func() { It("should use the precision parameter", func() { - Ω(5.1).Should(BeNumerically("~", 5.19, 0.1)) - Ω(5.1).Should(BeNumerically("~", 5.01, 0.1)) - Ω(5.1).ShouldNot(BeNumerically("~", 5.22, 0.1)) - Ω(5.1).ShouldNot(BeNumerically("~", 4.98, 0.1)) + Expect(5.1).Should(BeNumerically("~", 5.19, 0.1)) + Expect(5.1).Should(BeNumerically("~", 5.01, 0.1)) + Expect(5.1).ShouldNot(BeNumerically("~", 5.22, 0.1)) + Expect(5.1).ShouldNot(BeNumerically("~", 4.98, 0.1)) + }) + + It("should show precision in failure message", func(){ + actual := BeNumerically("~", 4.98, 0.1).FailureMessage(123) + expected := "Expected\n : 123\nto be within 0.1 of ~\n : 4.98" + Expect(actual).To(Equal(expected)) + }) + + It("should show precision in negated failure message", func(){ + actual := BeNumerically("~", 4.98, 0.1).NegatedFailureMessage(123) + expected := "Expected\n : 123\nnot to be within 0.1 of ~\n : 4.98" + Expect(actual).To(Equal(expected)) }) }) }) @@ -89,17 +113,17 @@ var _ = Describe("BeNumerically", func() { Context("when passed an int/uint", func() { Context("and there is no precision parameter", func() { It("should just do strict equality", func() { - Ω(5).Should(BeNumerically("~", 5)) - Ω(5).ShouldNot(BeNumerically("~", 6)) - Ω(uint(5)).ShouldNot(BeNumerically("~", 6)) + Expect(5).Should(BeNumerically("~", 5)) + Expect(5).ShouldNot(BeNumerically("~", 6)) + Expect(uint(5)).ShouldNot(BeNumerically("~", 6)) }) }) Context("and there is a precision parameter", func() { It("should use precision paramter", func() { - Ω(5).Should(BeNumerically("~", 6, 2)) - Ω(5).ShouldNot(BeNumerically("~", 8, 2)) - Ω(uint(5)).Should(BeNumerically("~", 6, 1)) + Expect(5).Should(BeNumerically("~", 6, 2)) + Expect(5).ShouldNot(BeNumerically("~", 8, 2)) + Expect(uint(5)).Should(BeNumerically("~", 6, 1)) }) }) }) @@ -109,40 +133,40 @@ var _ = Describe("BeNumerically", func() { Context("when passed a non-number", func() { It("should error", func() { success, err := (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{5}}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "=="}).Match(5) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "~", CompareTo: []interface{}{3.0, "foo"}}).Match(5.0) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match(5) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{nil}}).Match(0) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{0}}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when passed an unsupported comparator", func() { It("should error", func() { success, err := (&BeNumericallyMatcher{Comparator: "!=", CompareTo: []interface{}{5}}).Match(4) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go index 205d71f4..68ec7287 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go @@ -1,9 +1,10 @@ package matchers_test import ( - . "github.com/onsi/gomega/matchers" "time" + . "github.com/onsi/gomega/matchers" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -21,21 +22,21 @@ var _ = Describe("BeSent", func() { time.Sleep(10 * time.Millisecond) - Ω(c).Should(BeSent("foo")) + Expect(c).Should(BeSent("foo")) Eventually(d).Should(Receive(Equal("foo"))) }) It("should succeed (with a buffered channel)", func() { c := make(chan string, 1) - Ω(c).Should(BeSent("foo")) - Ω(<-c).Should(Equal("foo")) + Expect(c).Should(BeSent("foo")) + Expect(<-c).Should(Equal("foo")) }) }) Context("when the channel is not ready to receive", func() { It("should fail and not send down the channel", func() { c := make(chan string) - Ω(c).ShouldNot(BeSent("foo")) + Expect(c).ShouldNot(BeSent("foo")) Consistently(c).ShouldNot(Receive()) }) }) @@ -60,8 +61,8 @@ var _ = Describe("BeSent", func() { c := make(chan string) close(c) success, err := (&BeSentMatcher{Arg: "foo"}).Match(c) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) It("should short-circuit Eventually", func() { @@ -72,8 +73,8 @@ var _ = Describe("BeSent", func() { failures := InterceptGomegaFailures(func() { Eventually(c, 10.0).Should(BeSent("foo")) }) - Ω(failures).Should(HaveLen(1)) - Ω(time.Since(t)).Should(BeNumerically("<", time.Second)) + Expect(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", time.Second)) }) }) }) @@ -81,8 +82,8 @@ var _ = Describe("BeSent", func() { Context("when passed a channel and a non-matching type", func() { It("should error", func() { success, err := (&BeSentMatcher{Arg: "foo"}).Match(make(chan int, 1)) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) @@ -91,16 +92,16 @@ var _ = Describe("BeSent", func() { var c <-chan string c = make(chan string, 1) success, err := (&BeSentMatcher{Arg: "foo"}).Match(c) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when passed a nonchannel", func() { It("should error", func() { success, err := (&BeSentMatcher{Arg: "foo"}).Match("bar") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go index abda4eb1..cb7c038e 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "time" + + "github.com/onsi/gomega/format" ) type BeTemporallyMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go index feb33e5d..95a3a103 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go @@ -1,10 +1,11 @@ package matchers_test import ( + "time" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" - "time" ) var _ = Describe("BeTemporally", func() { @@ -19,34 +20,34 @@ var _ = Describe("BeTemporally", func() { Context("When comparing times", func() { It("should support ==", func() { - Ω(t0).Should(BeTemporally("==", t0)) - Ω(t1).ShouldNot(BeTemporally("==", t0)) - Ω(t0).ShouldNot(BeTemporally("==", t1)) - Ω(t0).ShouldNot(BeTemporally("==", time.Time{})) + Expect(t0).Should(BeTemporally("==", t0)) + Expect(t1).ShouldNot(BeTemporally("==", t0)) + Expect(t0).ShouldNot(BeTemporally("==", t1)) + Expect(t0).ShouldNot(BeTemporally("==", time.Time{})) }) It("should support >", func() { - Ω(t0).Should(BeTemporally(">", t2)) - Ω(t0).ShouldNot(BeTemporally(">", t0)) - Ω(t2).ShouldNot(BeTemporally(">", t0)) + Expect(t0).Should(BeTemporally(">", t2)) + Expect(t0).ShouldNot(BeTemporally(">", t0)) + Expect(t2).ShouldNot(BeTemporally(">", t0)) }) It("should support <", func() { - Ω(t0).Should(BeTemporally("<", t1)) - Ω(t0).ShouldNot(BeTemporally("<", t0)) - Ω(t1).ShouldNot(BeTemporally("<", t0)) + Expect(t0).Should(BeTemporally("<", t1)) + Expect(t0).ShouldNot(BeTemporally("<", t0)) + Expect(t1).ShouldNot(BeTemporally("<", t0)) }) It("should support >=", func() { - Ω(t0).Should(BeTemporally(">=", t2)) - Ω(t0).Should(BeTemporally(">=", t0)) - Ω(t0).ShouldNot(BeTemporally(">=", t1)) + Expect(t0).Should(BeTemporally(">=", t2)) + Expect(t0).Should(BeTemporally(">=", t0)) + Expect(t0).ShouldNot(BeTemporally(">=", t1)) }) It("should support <=", func() { - Ω(t0).Should(BeTemporally("<=", t1)) - Ω(t0).Should(BeTemporally("<=", t0)) - Ω(t0).ShouldNot(BeTemporally("<=", t2)) + Expect(t0).Should(BeTemporally("<=", t1)) + Expect(t0).Should(BeTemporally("<=", t0)) + Expect(t0).ShouldNot(BeTemporally("<=", t2)) }) Context("when passed ~", func() { @@ -56,9 +57,9 @@ var _ = Describe("BeTemporally", func() { t2 = t0.Add(-2 * time.Millisecond) }) It("should approximate", func() { - Ω(t0).Should(BeTemporally("~", t0)) - Ω(t0).Should(BeTemporally("~", t1)) - Ω(t0).ShouldNot(BeTemporally("~", t2)) + Expect(t0).Should(BeTemporally("~", t0)) + Expect(t0).Should(BeTemporally("~", t1)) + Expect(t0).ShouldNot(BeTemporally("~", t2)) }) }) @@ -68,9 +69,9 @@ var _ = Describe("BeTemporally", func() { }) It("should use precision paramter", func() { d := 2 * time.Second - Ω(t0).Should(BeTemporally("~", t0, d)) - Ω(t0).Should(BeTemporally("~", t1, d)) - Ω(t0).ShouldNot(BeTemporally("~", t2, d)) + Expect(t0).Should(BeTemporally("~", t0, d)) + Expect(t0).Should(BeTemporally("~", t1, d)) + Expect(t0).ShouldNot(BeTemporally("~", t2, d)) }) }) }) @@ -79,20 +80,20 @@ var _ = Describe("BeTemporally", func() { Context("when passed a non-time", func() { It("should error", func() { success, err := (&BeTemporallyMatcher{Comparator: "==", CompareTo: t0}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&BeTemporallyMatcher{Comparator: "=="}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when passed an unsupported comparator", func() { It("should error", func() { success, err := (&BeTemporallyMatcher{Comparator: "!=", CompareTo: t0}).Match(t2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go index 1275e5fc..ec57c5db 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go @@ -2,6 +2,7 @@ package matchers import ( "fmt" + "github.com/onsi/gomega/format" ) diff --git a/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go index ca32e56b..9eda62c3 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go @@ -8,13 +8,13 @@ import ( var _ = Describe("BeTrue", func() { It("should handle true and false correctly", func() { - Ω(true).Should(BeTrue()) - Ω(false).ShouldNot(BeTrue()) + Expect(true).Should(BeTrue()) + Expect(false).ShouldNot(BeTrue()) }) It("should only support booleans", func() { success, err := (&BeTrueMatcher{}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go index b39c9144..26196f16 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go @@ -1,8 +1,9 @@ package matchers import ( - "github.com/onsi/gomega/format" "reflect" + + "github.com/onsi/gomega/format" ) type BeZeroMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go index 8ec3643c..015d87d1 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go @@ -7,24 +7,24 @@ import ( var _ = Describe("BeZero", func() { It("should succeed if the passed in object is the zero value for its type", func() { - Ω(nil).Should(BeZero()) + Expect(nil).Should(BeZero()) - Ω("").Should(BeZero()) - Ω(" ").ShouldNot(BeZero()) + Expect("").Should(BeZero()) + Expect(" ").ShouldNot(BeZero()) - Ω(0).Should(BeZero()) - Ω(1).ShouldNot(BeZero()) + Expect(0).Should(BeZero()) + Expect(1).ShouldNot(BeZero()) - Ω(0.0).Should(BeZero()) - Ω(0.1).ShouldNot(BeZero()) + Expect(0.0).Should(BeZero()) + Expect(0.1).ShouldNot(BeZero()) - // Ω([]int{}).Should(BeZero()) - Ω([]int{1}).ShouldNot(BeZero()) + // Expect([]int{}).Should(BeZero()) + Expect([]int{1}).ShouldNot(BeZero()) - // Ω(map[string]int{}).Should(BeZero()) - Ω(map[string]int{"a": 1}).ShouldNot(BeZero()) + // Expect(map[string]int{}).Should(BeZero()) + Expect(map[string]int{"a": 1}).ShouldNot(BeZero()) - Ω(myCustomType{}).Should(BeZero()) - Ω(myCustomType{s: "a"}).ShouldNot(BeZero()) + Expect(myCustomType{}).Should(BeZero()) + Expect(myCustomType{s: "a"}).ShouldNot(BeZero()) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of_test.go b/vendor/github.com/onsi/gomega/matchers/consist_of_test.go index dcd1afe9..081830f5 100644 --- a/vendor/github.com/onsi/gomega/matchers/consist_of_test.go +++ b/vendor/github.com/onsi/gomega/matchers/consist_of_test.go @@ -8,29 +8,29 @@ import ( var _ = Describe("ConsistOf", func() { Context("with a slice", func() { It("should do the right thing", func() { - Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) - Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) - Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) - Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) - Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) }) }) Context("with an array", func() { It("should do the right thing", func() { - Ω([3]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) - Ω([3]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) - Ω([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) - Ω([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) + Expect([3]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect([3]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) + Expect([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) + Expect([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) }) }) Context("with a map", func() { It("should apply to the values", func() { - Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("foo", "bar", "baz")) - Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("baz", "bar", "foo")) - Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) - Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "foo")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("baz", "bar", "foo")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "foo")) }) }) @@ -38,38 +38,38 @@ var _ = Describe("ConsistOf", func() { Context("with anything else", func() { It("should error", func() { failures := InterceptGomegaFailures(func() { - Ω("foo").Should(ConsistOf("f", "o", "o")) + Expect("foo").Should(ConsistOf("f", "o", "o")) }) - Ω(failures).Should(HaveLen(1)) + Expect(failures).Should(HaveLen(1)) }) }) Context("when passed matchers", func() { It("should pass if the matchers pass", func() { - Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), "baz")) - Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"))) - Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("foo"))) - Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("^ba"))) - Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("turducken"))) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), "baz")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"))) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("foo"))) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("^ba"))) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("turducken"))) }) It("should not depend on the order of the matchers", func() { - Ω([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(1), ContainElement(2))) - Ω([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(2), ContainElement(1))) + Expect([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(1), ContainElement(2))) + Expect([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(2), ContainElement(1))) }) Context("when a matcher errors", func() { It("should soldier on", func() { - Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf(BeFalse(), "foo", "bar")) - Ω([]interface{}{"foo", "bar", false}).Should(ConsistOf(BeFalse(), ContainSubstring("foo"), "bar")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf(BeFalse(), "foo", "bar")) + Expect([]interface{}{"foo", "bar", false}).Should(ConsistOf(BeFalse(), ContainSubstring("foo"), "bar")) }) }) }) Context("when passed exactly one argument, and that argument is a slice", func() { It("should match against the elements of that argument", func() { - Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf([]string{"foo", "bar", "baz"})) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf([]string{"foo", "bar", "baz"})) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go index 38ee518f..60fb55e9 100644 --- a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go @@ -10,40 +10,40 @@ var _ = Describe("ContainElement", func() { Context("when passed a supported type", func() { Context("and expecting a non-matcher", func() { It("should do the right thing", func() { - Ω([2]int{1, 2}).Should(ContainElement(2)) - Ω([2]int{1, 2}).ShouldNot(ContainElement(3)) + Expect([2]int{1, 2}).Should(ContainElement(2)) + Expect([2]int{1, 2}).ShouldNot(ContainElement(3)) - Ω([]int{1, 2}).Should(ContainElement(2)) - Ω([]int{1, 2}).ShouldNot(ContainElement(3)) + Expect([]int{1, 2}).Should(ContainElement(2)) + Expect([]int{1, 2}).ShouldNot(ContainElement(3)) - Ω(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(2)) - Ω(map[int]int{3: 1, 4: 2}).ShouldNot(ContainElement(3)) + Expect(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(2)) + Expect(map[int]int{3: 1, 4: 2}).ShouldNot(ContainElement(3)) arr := make([]myCustomType, 2) arr[0] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}} arr[1] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "c"}} - Ω(arr).Should(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) - Ω(arr).ShouldNot(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"b", "c"}})) + Expect(arr).Should(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) + Expect(arr).ShouldNot(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"b", "c"}})) }) }) Context("and expecting a matcher", func() { It("should pass each element through the matcher", func() { - Ω([]int{1, 2, 3}).Should(ContainElement(BeNumerically(">=", 3))) - Ω([]int{1, 2, 3}).ShouldNot(ContainElement(BeNumerically(">", 3))) - Ω(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(BeNumerically(">=", 2))) - Ω(map[string]int{"foo": 1, "bar": 2}).ShouldNot(ContainElement(BeNumerically(">", 2))) + Expect([]int{1, 2, 3}).Should(ContainElement(BeNumerically(">=", 3))) + Expect([]int{1, 2, 3}).ShouldNot(ContainElement(BeNumerically(">", 3))) + Expect(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(BeNumerically(">=", 2))) + Expect(map[string]int{"foo": 1, "bar": 2}).ShouldNot(ContainElement(BeNumerically(">", 2))) }) It("should power through even if the matcher ever fails", func() { - Ω([]interface{}{1, 2, "3", 4}).Should(ContainElement(BeNumerically(">=", 3))) + Expect([]interface{}{1, 2, "3", 4}).Should(ContainElement(BeNumerically(">=", 3))) }) It("should fail if the matcher fails", func() { actual := []interface{}{1, 2, "3", "4"} success, err := (&ContainElementMatcher{Element: BeNumerically(">=", 3)}).Match(actual) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) @@ -51,26 +51,26 @@ var _ = Describe("ContainElement", func() { Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilSlice []int - Ω(nilSlice).ShouldNot(ContainElement(1)) + Expect(nilSlice).ShouldNot(ContainElement(1)) var nilMap map[int]string - Ω(nilMap).ShouldNot(ContainElement("foo")) + Expect(nilMap).ShouldNot(ContainElement("foo")) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&ContainElementMatcher{Element: 0}).Match(0) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&ContainElementMatcher{Element: 0}).Match("abc") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&ContainElementMatcher{Element: 0}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go index 2e760892..f8dc41e7 100644 --- a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "strings" + + "github.com/onsi/gomega/format" ) type ContainSubstringMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go index 6935168e..efffb473 100644 --- a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go @@ -9,28 +9,28 @@ import ( var _ = Describe("ContainSubstringMatcher", func() { Context("when actual is a string", func() { It("should match against the string", func() { - Ω("Marvelous").Should(ContainSubstring("rve")) - Ω("Marvelous").ShouldNot(ContainSubstring("boo")) + Expect("Marvelous").Should(ContainSubstring("rve")) + Expect("Marvelous").ShouldNot(ContainSubstring("boo")) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { - Ω("Marvelous3").Should(ContainSubstring("velous%d", 3)) + Expect("Marvelous3").Should(ContainSubstring("velous%d", 3)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match agains the returned string", func() { - Ω(&myStringer{a: "Abc3"}).Should(ContainSubstring("bc3")) + Expect(&myStringer{a: "Abc3"}).Should(ContainSubstring("bc3")) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&ContainSubstringMatcher{Substr: "2"}).Match(2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/equal_matcher.go b/vendor/github.com/onsi/gomega/matchers/equal_matcher.go index 874e6a62..befb7bdf 100644 --- a/vendor/github.com/onsi/gomega/matchers/equal_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher.go @@ -1,6 +1,7 @@ package matchers import ( + "bytes" "fmt" "reflect" @@ -15,6 +16,14 @@ func (matcher *EqualMatcher) Match(actual interface{}) (success bool, err error) if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") } + // Shortcut for byte slices. + // Comparing long byte slices with reflect.DeepEqual is very slow, + // so use bytes.Equal if actual and expected are both byte slices. + if actualByteSlice, ok := actual.([]byte); ok { + if expectedByteSlice, ok := matcher.Expected.([]byte); ok { + return bytes.Equal(actualByteSlice, expectedByteSlice), nil + } + } return reflect.DeepEqual(actual, matcher.Expected), nil } diff --git a/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go index 2add0b74..3ab991e4 100644 --- a/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go @@ -14,33 +14,35 @@ var _ = Describe("Equal", func() { It("should error", func() { success, err := (&EqualMatcher{Expected: nil}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("When asserting equality between objects", func() { It("should do the right thing", func() { - Ω(5).Should(Equal(5)) - Ω(5.0).Should(Equal(5.0)) + Expect(5).Should(Equal(5)) + Expect(5.0).Should(Equal(5.0)) - Ω(5).ShouldNot(Equal("5")) - Ω(5).ShouldNot(Equal(5.0)) - Ω(5).ShouldNot(Equal(3)) + Expect(5).ShouldNot(Equal("5")) + Expect(5).ShouldNot(Equal(5.0)) + Expect(5).ShouldNot(Equal(3)) - Ω("5").Should(Equal("5")) - Ω([]int{1, 2}).Should(Equal([]int{1, 2})) - Ω([]int{1, 2}).ShouldNot(Equal([]int{2, 1})) - Ω(map[string]string{"a": "b", "c": "d"}).Should(Equal(map[string]string{"a": "b", "c": "d"})) - Ω(map[string]string{"a": "b", "c": "d"}).ShouldNot(Equal(map[string]string{"a": "b", "c": "e"})) - Ω(errors.New("foo")).Should(Equal(errors.New("foo"))) - Ω(errors.New("foo")).ShouldNot(Equal(errors.New("bar"))) + Expect("5").Should(Equal("5")) + Expect([]int{1, 2}).Should(Equal([]int{1, 2})) + Expect([]int{1, 2}).ShouldNot(Equal([]int{2, 1})) + Expect([]byte{'f', 'o', 'o'}).Should(Equal([]byte{'f', 'o', 'o'})) + Expect([]byte{'f', 'o', 'o'}).ShouldNot(Equal([]byte{'b', 'a', 'r'})) + Expect(map[string]string{"a": "b", "c": "d"}).Should(Equal(map[string]string{"a": "b", "c": "d"})) + Expect(map[string]string{"a": "b", "c": "d"}).ShouldNot(Equal(map[string]string{"a": "b", "c": "e"})) + Expect(errors.New("foo")).Should(Equal(errors.New("foo"))) + Expect(errors.New("foo")).ShouldNot(Equal(errors.New("bar"))) - Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) - Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}})) - Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}})) - Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}})) - Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}})) }) }) @@ -49,7 +51,7 @@ var _ = Describe("Equal", func() { subject := EqualMatcher{Expected: "eric"} failureMessage := subject.FailureMessage("tim") - Ω(failureMessage).To(BeEquivalentTo(expectedShortStringFailureMessage)) + Expect(failureMessage).To(BeEquivalentTo(expectedShortStringFailureMessage)) }) It("shows the exact point where two long strings differ", func() { @@ -59,7 +61,7 @@ var _ = Describe("Equal", func() { subject := EqualMatcher{Expected: stringWithZ} failureMessage := subject.FailureMessage(stringWithB) - Ω(failureMessage).To(BeEquivalentTo(expectedLongStringFailureMessage)) + Expect(failureMessage).To(BeEquivalentTo(expectedLongStringFailureMessage)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go index a92a177b..8a61f2e2 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go @@ -9,42 +9,42 @@ import ( var _ = Describe("HaveCap", func() { Context("when passed a supported type", func() { It("should do the right thing", func() { - Ω([0]int{}).Should(HaveCap(0)) - Ω([2]int{1}).Should(HaveCap(2)) + Expect([0]int{}).Should(HaveCap(0)) + Expect([2]int{1}).Should(HaveCap(2)) - Ω([]int{}).Should(HaveCap(0)) - Ω([]int{1, 2, 3, 4, 5}[:2]).Should(HaveCap(5)) - Ω(make([]int, 0, 5)).Should(HaveCap(5)) + Expect([]int{}).Should(HaveCap(0)) + Expect([]int{1, 2, 3, 4, 5}[:2]).Should(HaveCap(5)) + Expect(make([]int, 0, 5)).Should(HaveCap(5)) c := make(chan bool, 3) - Ω(c).Should(HaveCap(3)) + Expect(c).Should(HaveCap(3)) c <- true c <- true - Ω(c).Should(HaveCap(3)) + Expect(c).Should(HaveCap(3)) - Ω(make(chan bool)).Should(HaveCap(0)) + Expect(make(chan bool)).Should(HaveCap(0)) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilSlice []int - Ω(nilSlice).Should(HaveCap(0)) + Expect(nilSlice).Should(HaveCap(0)) var nilChan chan int - Ω(nilChan).Should(HaveCap(0)) + Expect(nilChan).Should(HaveCap(0)) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&HaveCapMatcher{Count: 0}).Match(0) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&HaveCapMatcher{Count: 0}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go index 5701ba6e..ea5b9233 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "reflect" + + "github.com/onsi/gomega/format" ) type HaveKeyMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go index c663e302..0f1561b7 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go @@ -26,48 +26,48 @@ var _ = Describe("HaveKey", func() { Context("when passed a map", func() { It("should do the right thing", func() { - Ω(stringKeys).Should(HaveKey("foo")) - Ω(stringKeys).ShouldNot(HaveKey("baz")) + Expect(stringKeys).Should(HaveKey("foo")) + Expect(stringKeys).ShouldNot(HaveKey("baz")) - Ω(intKeys).Should(HaveKey(2)) - Ω(intKeys).ShouldNot(HaveKey(4)) + Expect(intKeys).Should(HaveKey(2)) + Expect(intKeys).ShouldNot(HaveKey(4)) - Ω(objKeys).Should(HaveKey(customA)) - Ω(objKeys).Should(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}})) - Ω(objKeys).ShouldNot(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}})) + Expect(objKeys).Should(HaveKey(customA)) + Expect(objKeys).Should(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}})) + Expect(objKeys).ShouldNot(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}})) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilMap map[int]string - Ω(nilMap).ShouldNot(HaveKey("foo")) + Expect(nilMap).ShouldNot(HaveKey("foo")) }) }) Context("when the passed in key is actually a matcher", func() { It("should pass each element through the matcher", func() { - Ω(stringKeys).Should(HaveKey(ContainSubstring("oo"))) - Ω(stringKeys).ShouldNot(HaveKey(ContainSubstring("foobar"))) + Expect(stringKeys).Should(HaveKey(ContainSubstring("oo"))) + Expect(stringKeys).ShouldNot(HaveKey(ContainSubstring("foobar"))) }) It("should fail if the matcher ever fails", func() { actual := map[int]string{1: "a", 3: "b", 2: "c"} success, err := (&HaveKeyMatcher{Key: ContainSubstring("ar")}).Match(actual) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when passed something that is not a map", func() { It("should error", func() { success, err := (&HaveKeyMatcher{Key: "foo"}).Match([]string{"foo"}) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&HaveKeyMatcher{Key: "foo"}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go index 464ac187..06355b1e 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "reflect" + + "github.com/onsi/gomega/format" ) type HaveKeyWithValueMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go index 06a2242a..0a49ec99 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go @@ -26,57 +26,57 @@ var _ = Describe("HaveKeyWithValue", func() { Context("when passed a map", func() { It("should do the right thing", func() { - Ω(stringKeys).Should(HaveKeyWithValue("foo", 2)) - Ω(stringKeys).ShouldNot(HaveKeyWithValue("foo", 1)) - Ω(stringKeys).ShouldNot(HaveKeyWithValue("baz", 2)) - Ω(stringKeys).ShouldNot(HaveKeyWithValue("baz", 1)) + Expect(stringKeys).Should(HaveKeyWithValue("foo", 2)) + Expect(stringKeys).ShouldNot(HaveKeyWithValue("foo", 1)) + Expect(stringKeys).ShouldNot(HaveKeyWithValue("baz", 2)) + Expect(stringKeys).ShouldNot(HaveKeyWithValue("baz", 1)) - Ω(intKeys).Should(HaveKeyWithValue(2, "foo")) - Ω(intKeys).ShouldNot(HaveKeyWithValue(4, "foo")) - Ω(intKeys).ShouldNot(HaveKeyWithValue(2, "baz")) + Expect(intKeys).Should(HaveKeyWithValue(2, "foo")) + Expect(intKeys).ShouldNot(HaveKeyWithValue(4, "foo")) + Expect(intKeys).ShouldNot(HaveKeyWithValue(2, "baz")) - Ω(objKeys).Should(HaveKeyWithValue(customA, customA)) - Ω(objKeys).Should(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}, &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}})) - Ω(objKeys).ShouldNot(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}}, customA)) + Expect(objKeys).Should(HaveKeyWithValue(customA, customA)) + Expect(objKeys).Should(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}, &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}})) + Expect(objKeys).ShouldNot(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}}, customA)) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilMap map[int]string - Ω(nilMap).ShouldNot(HaveKeyWithValue("foo", "bar")) + Expect(nilMap).ShouldNot(HaveKeyWithValue("foo", "bar")) }) }) Context("when the passed in key or value is actually a matcher", func() { It("should pass each element through the matcher", func() { - Ω(stringKeys).Should(HaveKeyWithValue(ContainSubstring("oo"), 2)) - Ω(intKeys).Should(HaveKeyWithValue(2, ContainSubstring("oo"))) - Ω(stringKeys).ShouldNot(HaveKeyWithValue(ContainSubstring("foobar"), 2)) + Expect(stringKeys).Should(HaveKeyWithValue(ContainSubstring("oo"), 2)) + Expect(intKeys).Should(HaveKeyWithValue(2, ContainSubstring("oo"))) + Expect(stringKeys).ShouldNot(HaveKeyWithValue(ContainSubstring("foobar"), 2)) }) It("should fail if the matcher ever fails", func() { actual := map[int]string{1: "a", 3: "b", 2: "c"} success, err := (&HaveKeyWithValueMatcher{Key: ContainSubstring("ar"), Value: 2}).Match(actual) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) otherActual := map[string]int{"a": 1, "b": 2, "c": 3} success, err = (&HaveKeyWithValueMatcher{Key: "a", Value: ContainSubstring("1")}).Match(otherActual) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when passed something that is not a map", func() { It("should error", func() { success, err := (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match([]string{"foo"}) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go index a1837755..ee427618 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go @@ -2,6 +2,7 @@ package matchers import ( "fmt" + "github.com/onsi/gomega/format" ) diff --git a/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go index 1e6aa69d..c60f6388 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go @@ -9,45 +9,45 @@ import ( var _ = Describe("HaveLen", func() { Context("when passed a supported type", func() { It("should do the right thing", func() { - Ω("").Should(HaveLen(0)) - Ω("AA").Should(HaveLen(2)) + Expect("").Should(HaveLen(0)) + Expect("AA").Should(HaveLen(2)) - Ω([0]int{}).Should(HaveLen(0)) - Ω([2]int{1, 2}).Should(HaveLen(2)) + Expect([0]int{}).Should(HaveLen(0)) + Expect([2]int{1, 2}).Should(HaveLen(2)) - Ω([]int{}).Should(HaveLen(0)) - Ω([]int{1, 2, 3}).Should(HaveLen(3)) + Expect([]int{}).Should(HaveLen(0)) + Expect([]int{1, 2, 3}).Should(HaveLen(3)) - Ω(map[string]int{}).Should(HaveLen(0)) - Ω(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).Should(HaveLen(4)) + Expect(map[string]int{}).Should(HaveLen(0)) + Expect(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).Should(HaveLen(4)) c := make(chan bool, 3) - Ω(c).Should(HaveLen(0)) + Expect(c).Should(HaveLen(0)) c <- true c <- true - Ω(c).Should(HaveLen(2)) + Expect(c).Should(HaveLen(2)) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilSlice []int - Ω(nilSlice).Should(HaveLen(0)) + Expect(nilSlice).Should(HaveLen(0)) var nilMap map[int]string - Ω(nilMap).Should(HaveLen(0)) + Expect(nilMap).Should(HaveLen(0)) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&HaveLenMatcher{Count: 0}).Match(0) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&HaveLenMatcher{Count: 0}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go index 009e23e5..0ad632ec 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go @@ -2,6 +2,7 @@ package matchers_test import ( "errors" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" @@ -17,42 +18,42 @@ func (e *CustomErr) Error() string { var _ = Describe("HaveOccurred", func() { It("should succeed if matching an error", func() { - Ω(errors.New("Foo")).Should(HaveOccurred()) + Expect(errors.New("Foo")).Should(HaveOccurred()) }) It("should not succeed with nil", func() { - Ω(nil).ShouldNot(HaveOccurred()) + Expect(nil).ShouldNot(HaveOccurred()) }) It("should only support errors and nil", func() { success, err := (&HaveOccurredMatcher{}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&HaveOccurredMatcher{}).Match("") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) It("doesn't support non-error type", func() { success, err := (&HaveOccurredMatcher{}).Match(AnyType{}) - Ω(success).Should(BeFalse()) - Ω(err).Should(MatchError("Expected an error-type. Got:\n : {}")) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError("Expected an error-type. Got:\n : {}")) }) It("doesn't support non-error pointer type", func() { success, err := (&HaveOccurredMatcher{}).Match(&AnyType{}) - Ω(success).Should(BeFalse()) - Ω(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) }) It("should succeed with pointer types that conform to error interface", func() { err := &CustomErr{"ohai"} - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) }) It("should not succeed with nil pointers to types that conform to error interface", func() { var err *CustomErr = nil - Ω(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go index 8b63a899..1d8e8027 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go @@ -2,6 +2,7 @@ package matchers import ( "fmt" + "github.com/onsi/gomega/format" ) diff --git a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go index bec3f975..fe29b7b5 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go @@ -9,28 +9,28 @@ import ( var _ = Describe("HavePrefixMatcher", func() { Context("when actual is a string", func() { It("should match a string prefix", func() { - Ω("Ab").Should(HavePrefix("A")) - Ω("A").ShouldNot(HavePrefix("Ab")) + Expect("Ab").Should(HavePrefix("A")) + Expect("A").ShouldNot(HavePrefix("Ab")) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { - Ω("C3PO").Should(HavePrefix("C%dP", 3)) + Expect("C3PO").Should(HavePrefix("C%dP", 3)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match against the returned string", func() { - Ω(&myStringer{a: "Ab"}).Should(HavePrefix("A")) + Expect(&myStringer{a: "Ab"}).Should(HavePrefix("A")) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&HavePrefixMatcher{Prefix: "2"}).Match(2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go index afc78fc9..40a3526e 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go @@ -2,6 +2,7 @@ package matchers import ( "fmt" + "github.com/onsi/gomega/format" ) diff --git a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go index 72e8975b..2ae29821 100644 --- a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go @@ -9,28 +9,28 @@ import ( var _ = Describe("HaveSuffixMatcher", func() { Context("when actual is a string", func() { It("should match a string suffix", func() { - Ω("Ab").Should(HaveSuffix("b")) - Ω("A").ShouldNot(HaveSuffix("Ab")) + Expect("Ab").Should(HaveSuffix("b")) + Expect("A").ShouldNot(HaveSuffix("Ab")) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { - Ω("C3PO").Should(HaveSuffix("%dPO", 3)) + Expect("C3PO").Should(HaveSuffix("%dPO", 3)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match against the returned string", func() { - Ω(&myStringer{a: "Ab"}).Should(HaveSuffix("b")) + Expect(&myStringer{a: "Ab"}).Should(HaveSuffix("b")) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&HaveSuffixMatcher{Suffix: "2"}).Match(2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go index 03cdf045..07499ac9 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "reflect" + + "github.com/onsi/gomega/format" ) type MatchErrorMatcher struct { @@ -21,14 +22,14 @@ func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err e actualErr := actual.(error) - if isString(matcher.Expected) { - return reflect.DeepEqual(actualErr.Error(), matcher.Expected), nil - } - if isError(matcher.Expected) { return reflect.DeepEqual(actualErr, matcher.Expected), nil } + if isString(matcher.Expected) { + return actualErr.Error() == matcher.Expected, nil + } + var subMatcher omegaMatcher var hasSubMatcher bool if matcher.Expected != nil { diff --git a/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go index 338b5129..9bf89fc4 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go @@ -3,6 +3,7 @@ package matchers_test import ( "errors" "fmt" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" @@ -22,11 +23,11 @@ var _ = Describe("MatchErrorMatcher", func() { fmtErr := fmt.Errorf("an error") customErr := CustomError{} - Ω(err).Should(MatchError(errors.New("an error"))) - Ω(err).ShouldNot(MatchError(errors.New("another error"))) + Expect(err).Should(MatchError(errors.New("an error"))) + Expect(err).ShouldNot(MatchError(errors.New("another error"))) - Ω(fmtErr).Should(MatchError(errors.New("an error"))) - Ω(customErr).Should(MatchError(CustomError{})) + Expect(fmtErr).Should(MatchError(errors.New("an error"))) + Expect(customErr).Should(MatchError(CustomError{})) }) It("should succeed when matching with a string", func() { @@ -34,23 +35,23 @@ var _ = Describe("MatchErrorMatcher", func() { fmtErr := fmt.Errorf("an error") customErr := CustomError{} - Ω(err).Should(MatchError("an error")) - Ω(err).ShouldNot(MatchError("another error")) + Expect(err).Should(MatchError("an error")) + Expect(err).ShouldNot(MatchError("another error")) - Ω(fmtErr).Should(MatchError("an error")) - Ω(customErr).Should(MatchError("an error")) + Expect(fmtErr).Should(MatchError("an error")) + Expect(customErr).Should(MatchError("an error")) }) Context("when passed a matcher", func() { It("should pass if the matcher passes against the error string", func() { err := errors.New("error 123 abc") - Ω(err).Should(MatchError(MatchRegexp(`\d{3}`))) + Expect(err).Should(MatchError(MatchRegexp(`\d{3}`))) }) It("should fail if the matcher fails against the error string", func() { err := errors.New("no digits") - Ω(err).ShouldNot(MatchError(MatchRegexp(`\d`))) + Expect(err).ShouldNot(MatchError(MatchRegexp(`\d`))) }) }) @@ -59,12 +60,12 @@ var _ = Describe("MatchErrorMatcher", func() { _, err := (&MatchErrorMatcher{ Expected: []byte("an error"), }).Match(actualErr) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) _, err = (&MatchErrorMatcher{ Expected: 3, }).Match(actualErr) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) }) }) @@ -73,7 +74,7 @@ var _ = Describe("MatchErrorMatcher", func() { _, err := (&MatchErrorMatcher{ Expected: "an error", }).Match(nil) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) }) }) @@ -82,12 +83,25 @@ var _ = Describe("MatchErrorMatcher", func() { _, err := (&MatchErrorMatcher{ Expected: "an error", }).Match("an error") - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) _, err = (&MatchErrorMatcher{ Expected: "an error", }).Match(3) - Ω(err).Should(HaveOccurred()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed an error that is also a string", func() { + It("should use it as an error", func() { + var e mockErr = "mockErr" + + // this fails if the matcher casts e to a string before comparison + Expect(e).Should(MatchError(e)) }) }) }) + +type mockErr string + +func (m mockErr) Error() string { return string(m) } diff --git a/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go index 499bb583..f962f139 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go @@ -4,8 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "reflect" - "strings" "github.com/onsi/gomega/format" ) @@ -42,32 +40,6 @@ func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (mess return formattedMessage(format.Message(actualString, "not to match JSON of", expectedString), matcher.firstFailurePath) } -func formattedMessage(comparisonMessage string, failurePath []interface{}) string { - var diffMessage string - if len(failurePath) == 0 { - diffMessage = "" - } else { - diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath)) - } - return fmt.Sprintf("%s%s", comparisonMessage, diffMessage) -} - -func formattedFailurePath(failurePath []interface{}) string { - formattedPaths := []string{} - for i := len(failurePath) - 1; i >= 0; i-- { - switch p := failurePath[i].(type) { - case int: - formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p)) - default: - if i != len(failurePath)-1 { - formattedPaths = append(formattedPaths, ".") - } - formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p)) - } - } - return strings.Join(formattedPaths, "") -} - func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatted, expectedFormatted string, err error) { actualString, ok := toString(actual) if !ok { @@ -91,45 +63,3 @@ func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatte return abuf.String(), ebuf.String(), nil } - -func deepEqual(a interface{}, b interface{}) (bool, []interface{}) { - var errorPath []interface{} - if reflect.TypeOf(a) != reflect.TypeOf(b) { - return false, errorPath - } - - switch a.(type) { - case []interface{}: - if len(a.([]interface{})) != len(b.([]interface{})) { - return false, errorPath - } - - for i, v := range a.([]interface{}) { - elementEqual, keyPath := deepEqual(v, b.([]interface{})[i]) - if !elementEqual { - return false, append(keyPath, i) - } - } - return true, errorPath - - case map[string]interface{}: - if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) { - return false, errorPath - } - - for k, v1 := range a.(map[string]interface{}) { - v2, ok := b.(map[string]interface{})[k] - if !ok { - return false, errorPath - } - elementEqual, keyPath := deepEqual(v1, v2) - if !elementEqual { - return false, append(keyPath, k) - } - } - return true, errorPath - - default: - return a == b, errorPath - } -} diff --git a/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go index 45944839..4a1a9db2 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go @@ -1,6 +1,8 @@ package matchers_test import ( + "encoding/json" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" @@ -9,25 +11,29 @@ import ( var _ = Describe("MatchJSONMatcher", func() { Context("When passed stringifiables", func() { It("should succeed if the JSON matches", func() { - Ω("{}").Should(MatchJSON("{}")) - Ω(`{"a":1}`).Should(MatchJSON(`{"a":1}`)) - Ω(`{ + Expect("{}").Should(MatchJSON("{}")) + Expect(`{"a":1}`).Should(MatchJSON(`{"a":1}`)) + Expect(`{ "a":1 }`).Should(MatchJSON(`{"a":1}`)) - Ω(`{"a":1, "b":2}`).Should(MatchJSON(`{"b":2, "a":1}`)) - Ω(`{"a":1}`).ShouldNot(MatchJSON(`{"b":2, "a":1}`)) + Expect(`{"a":1, "b":2}`).Should(MatchJSON(`{"b":2, "a":1}`)) + Expect(`{"a":1}`).ShouldNot(MatchJSON(`{"b":2, "a":1}`)) - Ω(`{"a":"a", "b":"b"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b", "c":"c"}`)) - Ω(`{"a":"a", "b":"b", "c":"c"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b"}`)) + Expect(`{"a":"a", "b":"b"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b", "c":"c"}`)) + Expect(`{"a":"a", "b":"b", "c":"c"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b"}`)) - Ω(`{"a":null, "b":null}`).ShouldNot(MatchJSON(`{"c":"c", "d":"d"}`)) - Ω(`{"a":null, "b":null, "c":null}`).ShouldNot(MatchJSON(`{"a":null, "b":null, "d":null}`)) + Expect(`{"a":null, "b":null}`).ShouldNot(MatchJSON(`{"c":"c", "d":"d"}`)) + Expect(`{"a":null, "b":null, "c":null}`).ShouldNot(MatchJSON(`{"a":null, "b":null, "d":null}`)) }) It("should work with byte arrays", func() { - Ω([]byte("{}")).Should(MatchJSON([]byte("{}"))) - Ω("{}").Should(MatchJSON([]byte("{}"))) - Ω([]byte("{}")).Should(MatchJSON("{}")) + Expect([]byte("{}")).Should(MatchJSON([]byte("{}"))) + Expect("{}").Should(MatchJSON([]byte("{}"))) + Expect([]byte("{}")).Should(MatchJSON("{}")) + }) + + It("should work with json.RawMessage", func() { + Expect([]byte(`{"a": 1}`)).Should(MatchJSON(json.RawMessage(`{"a": 1}`))) }) }) @@ -38,60 +44,60 @@ var _ = Describe("MatchJSONMatcher", func() { subject.Match(actual) failureMessage := subject.FailureMessage(`7`) - Ω(failureMessage).ToNot(ContainSubstring("first mismatched key")) + Expect(failureMessage).ToNot(ContainSubstring("first mismatched key")) subject = MatchJSONMatcher{JSONToMatch: `{"a": 1, "b.g": {"c": 2, "1": ["hello", "see ya"]}}`} actual = `{"a": 1, "b.g": {"c": 2, "1": ["hello", "goodbye"]}}` subject.Match(actual) failureMessage = subject.FailureMessage(actual) - Ω(failureMessage).To(ContainSubstring(`first mismatched key: "b.g"."1"[1]`)) + Expect(failureMessage).To(ContainSubstring(`first mismatched key: "b.g"."1"[1]`)) }) }) Context("when the expected is not valid JSON", func() { It("should error and explain why", func() { success, err := (&MatchJSONMatcher{JSONToMatch: `{}`}).Match(`oops`) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid JSON")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid JSON")) }) }) Context("when the actual is not valid JSON", func() { It("should error and explain why", func() { success, err := (&MatchJSONMatcher{JSONToMatch: `oops`}).Match(`{}`) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid JSON")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid JSON")) }) }) Context("when the expected is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchJSONMatcher{JSONToMatch: 2}).Match("{}") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) success, err = (&MatchJSONMatcher{JSONToMatch: nil}).Match("{}") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) }) }) Context("when the actual is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) success, err = (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go index 7ca79a15..adac5db6 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go @@ -2,8 +2,9 @@ package matchers import ( "fmt" - "github.com/onsi/gomega/format" "regexp" + + "github.com/onsi/gomega/format" ) type MatchRegexpMatcher struct { diff --git a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go index bb521cce..ac2538bb 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go @@ -9,36 +9,36 @@ import ( var _ = Describe("MatchRegexp", func() { Context("when actual is a string", func() { It("should match against the string", func() { - Ω(" a2!bla").Should(MatchRegexp(`\d!`)) - Ω(" a2!bla").ShouldNot(MatchRegexp(`[A-Z]`)) + Expect(" a2!bla").Should(MatchRegexp(`\d!`)) + Expect(" a2!bla").ShouldNot(MatchRegexp(`[A-Z]`)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match agains the returned string", func() { - Ω(&myStringer{a: "Abc3"}).Should(MatchRegexp(`[A-Z][a-z]+\d`)) + Expect(&myStringer{a: "Abc3"}).Should(MatchRegexp(`[A-Z][a-z]+\d`)) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { - Ω(" a23!bla").Should(MatchRegexp(`\d%d!`, 3)) + Expect(" a23!bla").Should(MatchRegexp(`\d%d!`, 3)) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&MatchRegexpMatcher{Regexp: `\d`}).Match(2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when the passed in regexp fails to compile", func() { It("should error", func() { success, err := (&MatchRegexpMatcher{Regexp: "("}).Match("Foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go index da265629..3b412ce8 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "reflect" + "sort" "strings" "github.com/onsi/gomega/format" @@ -82,6 +83,8 @@ func parseXmlContent(content string) (*xmlNode, error) { switch tok := tok.(type) { case xml.StartElement: + attrs := attributesSlice(tok.Attr) + sort.Sort(attrs) allNodes = append(allNodes, &xmlNode{XMLName: tok.Name, XMLAttr: tok.Attr}) case xml.EndElement: if len(allNodes) > 1 { diff --git a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go index 16c19224..0b559b22 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go @@ -23,68 +23,75 @@ var _ = Describe("MatchXMLMatcher", func() { ) Context("When passed stringifiables", func() { + It("matches documents regardless of the attribute order", func() { + a := `` + b := `` + Expect(b).Should(MatchXML(a)) + Expect(a).Should(MatchXML(b)) + }) + It("should succeed if the XML matches", func() { - Ω(sample_01).Should(MatchXML(sample_01)) // same XML - Ω(sample_01).Should(MatchXML(sample_02)) // same XML with blank lines - Ω(sample_01).Should(MatchXML(sample_03)) // same XML with different formatting - Ω(sample_01).ShouldNot(MatchXML(sample_04)) // same structures with different values - Ω(sample_01).ShouldNot(MatchXML(sample_05)) // different structures - Ω(sample_06).ShouldNot(MatchXML(sample_07)) // same xml names with different namespaces - Ω(sample_07).ShouldNot(MatchXML(sample_08)) // same structures with different values - Ω(sample_09).ShouldNot(MatchXML(sample_10)) // same structures with different attribute values - Ω(sample_11).Should(MatchXML(sample_11)) // with non UTF-8 encoding + Expect(sample_01).Should(MatchXML(sample_01)) // same XML + Expect(sample_01).Should(MatchXML(sample_02)) // same XML with blank lines + Expect(sample_01).Should(MatchXML(sample_03)) // same XML with different formatting + Expect(sample_01).ShouldNot(MatchXML(sample_04)) // same structures with different values + Expect(sample_01).ShouldNot(MatchXML(sample_05)) // different structures + Expect(sample_06).ShouldNot(MatchXML(sample_07)) // same xml names with different namespaces + Expect(sample_07).ShouldNot(MatchXML(sample_08)) // same structures with different values + Expect(sample_09).ShouldNot(MatchXML(sample_10)) // same structures with different attribute values + Expect(sample_11).Should(MatchXML(sample_11)) // with non UTF-8 encoding }) It("should work with byte arrays", func() { - Ω([]byte(sample_01)).Should(MatchXML([]byte(sample_01))) - Ω([]byte(sample_01)).Should(MatchXML(sample_01)) - Ω(sample_01).Should(MatchXML([]byte(sample_01))) + Expect([]byte(sample_01)).Should(MatchXML([]byte(sample_01))) + Expect([]byte(sample_01)).Should(MatchXML(sample_01)) + Expect(sample_01).Should(MatchXML([]byte(sample_01))) }) }) Context("when the expected is not valid XML", func() { It("should error and explain why", func() { success, err := (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(`oops`) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid XML")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid XML")) }) }) Context("when the actual is not valid XML", func() { It("should error and explain why", func() { success, err := (&MatchXMLMatcher{XMLToMatch: `oops`}).Match(sample_01) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid XML")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid XML")) }) }) Context("when the expected is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchXMLMatcher{XMLToMatch: 2}).Match(sample_01) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) success, err = (&MatchXMLMatcher{XMLToMatch: nil}).Match(sample_01) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) }) }) Context("when the actual is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(2) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) success, err = (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) - Ω(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go index 69fb51a8..070d6026 100644 --- a/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go @@ -2,7 +2,6 @@ package matchers import ( "fmt" - "reflect" "strings" "github.com/onsi/gomega/format" @@ -10,7 +9,8 @@ import ( ) type MatchYAMLMatcher struct { - YAMLToMatch interface{} + YAMLToMatch interface{} + firstFailurePath []interface{} } func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) { @@ -29,17 +29,19 @@ func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err er return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err) } - return reflect.DeepEqual(aval, eval), nil + var equal bool + equal, matcher.firstFailurePath = deepEqual(aval, eval) + return equal, nil } func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) { actualString, expectedString, _ := matcher.toNormalisedStrings(actual) - return format.Message(actualString, "to match YAML of", expectedString) + return formattedMessage(format.Message(actualString, "to match YAML of", expectedString), matcher.firstFailurePath) } func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) { actualString, expectedString, _ := matcher.toNormalisedStrings(actual) - return format.Message(actualString, "not to match YAML of", expectedString) + return formattedMessage(format.Message(actualString, "not to match YAML of", expectedString), matcher.firstFailurePath) } func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) { diff --git a/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go index 6b859a7e..96270d5a 100644 --- a/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go @@ -10,36 +10,36 @@ var _ = Describe("Panic", func() { Context("when passed something that's not a function that takes zero arguments and returns nothing", func() { It("should error", func() { success, err := (&PanicMatcher{}).Match("foo") - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&PanicMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&PanicMatcher{}).Match(func(foo string) {}) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&PanicMatcher{}).Match(func() string { return "bar" }) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) Context("when passed a function of the correct type", func() { It("should call the function and pass if the function panics", func() { - Ω(func() { panic("ack!") }).Should(Panic()) - Ω(func() {}).ShouldNot(Panic()) + Expect(func() { panic("ack!") }).Should(Panic()) + Expect(func() {}).ShouldNot(Panic()) }) }) Context("when assertion fails", func() { It("should print the object passed to Panic", func() { failuresMessages := InterceptGomegaFailures(func() { - Ω(func() { panic("ack!") }).ShouldNot(Panic()) + Expect(func() { panic("ack!") }).ShouldNot(Panic()) }) - Ω(failuresMessages).Should(ConsistOf(MatchRegexp("not to panic, but panicked with\\s*: ack!"))) + Expect(failuresMessages).Should(ConsistOf(MatchRegexp("not to panic, but panicked with\\s*: ack!"))) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go index 74e9e7eb..fc179916 100644 --- a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go @@ -35,11 +35,6 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro if argType.Kind() != reflect.Ptr { return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1)) } - - assignable := channelType.Elem().AssignableTo(argType.Elem()) - if !assignable { - return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(matcher.Arg, 1)) - } } } @@ -71,7 +66,18 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro if didReceive { if matcher.Arg != nil { outValue := reflect.ValueOf(matcher.Arg) - reflect.Indirect(outValue).Set(value) + + if value.Type().AssignableTo(outValue.Elem().Type()) { + outValue.Elem().Set(value) + return true, nil + } + if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) { + outValue.Elem().Set(value.Elem()) + return true, nil + } else { + return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(matcher.Arg, 1)) + } + } return true, nil diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go index 938c078e..cf04e85d 100644 --- a/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go @@ -20,17 +20,21 @@ func (j *jackie) DrunkenMaster() bool { return true } +type someError struct{ s string } + +func (e *someError) Error() string { return e.s } + var _ = Describe("ReceiveMatcher", func() { Context("with no argument", func() { Context("for a buffered channel", func() { It("should succeed", func() { channel := make(chan bool, 1) - Ω(channel).ShouldNot(Receive()) + Expect(channel).ShouldNot(Receive()) channel <- true - Ω(channel).Should(Receive()) + Expect(channel).Should(Receive()) }) }) @@ -38,7 +42,7 @@ var _ = Describe("ReceiveMatcher", func() { It("should succeed (eventually)", func() { channel := make(chan bool) - Ω(channel).ShouldNot(Receive()) + Expect(channel).ShouldNot(Receive()) go func() { time.Sleep(10 * time.Millisecond) @@ -51,19 +55,37 @@ var _ = Describe("ReceiveMatcher", func() { }) Context("with a pointer argument", func() { + Context("of the correct type", func() { + Context("when the channel has an interface type", func() { + It("should write the value received on the channel to the pointer", func() { + channel := make(chan error, 1) + + var value *someError + + Ω(channel).ShouldNot(Receive(&value)) + Ω(value).Should(BeZero()) + + channel <- &someError{"boooom!"} + + Ω(channel).Should(Receive(&value)) + Ω(value).Should(MatchError("boooom!")) + }) + }) + }) + Context("of the correct type", func() { It("should write the value received on the channel to the pointer", func() { channel := make(chan int, 1) var value int - Ω(channel).ShouldNot(Receive(&value)) - Ω(value).Should(BeZero()) + Expect(channel).ShouldNot(Receive(&value)) + Expect(value).Should(BeZero()) channel <- 17 - Ω(channel).Should(Receive(&value)) - Ω(value).Should(Equal(17)) + Expect(channel).Should(Receive(&value)) + Expect(value).Should(Equal(17)) }) }) @@ -74,16 +96,16 @@ var _ = Describe("ReceiveMatcher", func() { stringChan <- "foo" var s string - Ω(stringChan).Should(Receive(&s)) - Ω(s).Should(Equal("foo")) + Expect(stringChan).Should(Receive(&s)) + Expect(s).Should(Equal("foo")) //channels of slices sliceChan := make(chan []bool, 1) sliceChan <- []bool{true, true, false} var sl []bool - Ω(sliceChan).Should(Receive(&sl)) - Ω(sl).Should(Equal([]bool{true, true, false})) + Expect(sliceChan).Should(Receive(&sl)) + Expect(sl).Should(Equal([]bool{true, true, false})) //channels of channels chanChan := make(chan chan bool, 1) @@ -91,8 +113,8 @@ var _ = Describe("ReceiveMatcher", func() { chanChan <- c var receivedC chan bool - Ω(chanChan).Should(Receive(&receivedC)) - Ω(receivedC).Should(Equal(c)) + Expect(chanChan).Should(Receive(&receivedC)) + Expect(receivedC).Should(Equal(c)) //channels of interfaces jackieChan := make(chan kungFuActor, 1) @@ -100,24 +122,26 @@ var _ = Describe("ReceiveMatcher", func() { jackieChan <- aJackie var theJackie kungFuActor - Ω(jackieChan).Should(Receive(&theJackie)) - Ω(theJackie).Should(Equal(aJackie)) + Expect(jackieChan).Should(Receive(&theJackie)) + Expect(theJackie).Should(Equal(aJackie)) }) }) Context("of the wrong type", func() { It("should error", func() { - channel := make(chan int) + channel := make(chan int, 1) + channel <- 10 + var incorrectType bool success, err := (&ReceiveMatcher{Arg: &incorrectType}).Match(channel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) var notAPointer int success, err = (&ReceiveMatcher{Arg: notAPointer}).Match(channel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) }) @@ -126,17 +150,17 @@ var _ = Describe("ReceiveMatcher", func() { It("should defer to the underlying matcher", func() { intChannel := make(chan int, 1) intChannel <- 3 - Ω(intChannel).Should(Receive(Equal(3))) + Expect(intChannel).Should(Receive(Equal(3))) intChannel <- 2 - Ω(intChannel).ShouldNot(Receive(Equal(3))) + Expect(intChannel).ShouldNot(Receive(Equal(3))) stringChannel := make(chan []string, 1) stringChannel <- []string{"foo", "bar", "baz"} - Ω(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo")))) + Expect(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo")))) stringChannel <- []string{"foo", "bar", "baz"} - Ω(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago")))) + Expect(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago")))) }) It("should defer to the underlying matcher for the message", func() { @@ -144,11 +168,11 @@ var _ = Describe("ReceiveMatcher", func() { channel := make(chan int, 1) channel <- 2 matcher.Match(channel) - Ω(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 2\s+to equal\s+: 3`)) + Expect(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 2\s+to equal\s+: 3`)) channel <- 3 matcher.Match(channel) - Ω(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 3\s+not to equal\s+: 3`)) + Expect(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 3\s+not to equal\s+: 3`)) }) It("should work just fine with Eventually", func() { @@ -169,8 +193,8 @@ var _ = Describe("ReceiveMatcher", func() { channel := make(chan int, 1) channel <- 3 success, err := (&ReceiveMatcher{Arg: ContainSubstring("three")}).Match(channel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) @@ -178,8 +202,8 @@ var _ = Describe("ReceiveMatcher", func() { It("should fail", func() { channel := make(chan int, 1) success, err := (&ReceiveMatcher{Arg: Equal(1)}).Match(channel) - Ω(success).Should(BeFalse()) - Ω(err).ShouldNot(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).ShouldNot(HaveOccurred()) }) }) }) @@ -192,8 +216,8 @@ var _ = Describe("ReceiveMatcher", func() { close(channel) - Ω(channel).Should(Receive()) - Ω(channel).ShouldNot(Receive()) + Expect(channel).Should(Receive()) + Expect(channel).ShouldNot(Receive()) }) }) @@ -202,7 +226,7 @@ var _ = Describe("ReceiveMatcher", func() { channel := make(chan bool) close(channel) - Ω(channel).ShouldNot(Receive()) + Expect(channel).ShouldNot(Receive()) }) }) }) @@ -215,8 +239,8 @@ var _ = Describe("ReceiveMatcher", func() { writerChannel = channel success, err := (&ReceiveMatcher{}).Match(writerChannel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) @@ -225,16 +249,16 @@ var _ = Describe("ReceiveMatcher", func() { var nilChannel chan bool success, err := (&ReceiveMatcher{}).Match(nilChannel) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&ReceiveMatcher{}).Match(nil) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) success, err = (&ReceiveMatcher{}).Match(3) - Ω(success).Should(BeFalse()) - Ω(err).Should(HaveOccurred()) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) }) @@ -244,14 +268,14 @@ var _ = Describe("ReceiveMatcher", func() { c := make(chan string, 0) Eventually(c, 0.01).Should(Receive(Equal("hello"))) }) - Ω(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something.")) + Expect(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something.")) failures = InterceptGomegaFailures(func() { c := make(chan string, 1) c <- "hi" Eventually(c, 0.01).Should(Receive(Equal("hello"))) }) - Ω(failures[0]).Should(ContainSubstring(": hello")) + Expect(failures[0]).Should(ContainSubstring(": hello")) }) }) @@ -264,8 +288,8 @@ var _ = Describe("ReceiveMatcher", func() { failures := InterceptGomegaFailures(func() { Eventually(c).Should(Receive()) }) - Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) }) It("should bail early when passed a non-channel", func() { @@ -273,8 +297,8 @@ var _ = Describe("ReceiveMatcher", func() { failures := InterceptGomegaFailures(func() { Eventually(3).Should(Receive()) }) - Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) - Ω(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) }) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go b/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go new file mode 100644 index 00000000..63929568 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go @@ -0,0 +1,92 @@ +package matchers + +import ( + "fmt" + "reflect" + "strings" +) + +func formattedMessage(comparisonMessage string, failurePath []interface{}) string { + var diffMessage string + if len(failurePath) == 0 { + diffMessage = "" + } else { + diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath)) + } + return fmt.Sprintf("%s%s", comparisonMessage, diffMessage) +} + +func formattedFailurePath(failurePath []interface{}) string { + formattedPaths := []string{} + for i := len(failurePath) - 1; i >= 0; i-- { + switch p := failurePath[i].(type) { + case int: + formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p)) + default: + if i != len(failurePath)-1 { + formattedPaths = append(formattedPaths, ".") + } + formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p)) + } + } + return strings.Join(formattedPaths, "") +} + +func deepEqual(a interface{}, b interface{}) (bool, []interface{}) { + var errorPath []interface{} + if reflect.TypeOf(a) != reflect.TypeOf(b) { + return false, errorPath + } + + switch a.(type) { + case []interface{}: + if len(a.([]interface{})) != len(b.([]interface{})) { + return false, errorPath + } + + for i, v := range a.([]interface{}) { + elementEqual, keyPath := deepEqual(v, b.([]interface{})[i]) + if !elementEqual { + return false, append(keyPath, i) + } + } + return true, errorPath + + case map[interface{}]interface{}: + if len(a.(map[interface{}]interface{})) != len(b.(map[interface{}]interface{})) { + return false, errorPath + } + + for k, v1 := range a.(map[interface{}]interface{}) { + v2, ok := b.(map[interface{}]interface{})[k] + if !ok { + return false, errorPath + } + elementEqual, keyPath := deepEqual(v1, v2) + if !elementEqual { + return false, append(keyPath, k) + } + } + return true, errorPath + + case map[string]interface{}: + if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) { + return false, errorPath + } + + for k, v1 := range a.(map[string]interface{}) { + v2, ok := b.(map[string]interface{})[k] + if !ok { + return false, errorPath + } + elementEqual, keyPath := deepEqual(v1, v2) + if !elementEqual { + return false, append(keyPath, k) + } + } + return true, errorPath + + default: + return a == b, errorPath + } +} diff --git a/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go index 6b62c8bb..21ea64c8 100644 --- a/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go +++ b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go @@ -24,39 +24,39 @@ func Invalid() *AnyType { var _ = Describe("Succeed", func() { It("should succeed if the function succeeds", func() { - Ω(NotErroring()).Should(Succeed()) + Expect(NotErroring()).Should(Succeed()) }) It("should succeed (in the negated) if the function errored", func() { - Ω(Erroring()).ShouldNot(Succeed()) + Expect(Erroring()).ShouldNot(Succeed()) }) It("should not if passed a non-error", func() { success, err := (&SucceedMatcher{}).Match(Invalid()) - Ω(success).Should(BeFalse()) - Ω(err).Should(MatchError("Expected an error-type. Got:\n <*matchers_test.AnyType | 0x0>: nil")) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError("Expected an error-type. Got:\n <*matchers_test.AnyType | 0x0>: nil")) }) It("doesn't support non-error type", func() { success, err := (&SucceedMatcher{}).Match(AnyType{}) - Ω(success).Should(BeFalse()) - Ω(err).Should(MatchError("Expected an error-type. Got:\n : {}")) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError("Expected an error-type. Got:\n : {}")) }) It("doesn't support non-error pointer type", func() { success, err := (&SucceedMatcher{}).Match(&AnyType{}) - Ω(success).Should(BeFalse()) - Ω(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) }) It("should not succeed with pointer types that conform to error interface", func() { err := &CustomErr{"ohai"} - Ω(err).ShouldNot(Succeed()) + Expect(err).ShouldNot(Succeed()) }) It("should succeed with nil pointers to types that conform to error interface", func() { var err *CustomErr = nil - Ω(err).Should(Succeed()) + Expect(err).Should(Succeed()) }) }) diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go index 119d21ef..81b37711 100644 --- a/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go +++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go @@ -15,12 +15,12 @@ type BipartiteGraph struct { func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(interface{}, interface{}) (bool, error)) (*BipartiteGraph, error) { left := NodeOrderedSet{} for i, _ := range leftValues { - left = append(left, Node{i}) + left = append(left, Node{Id: i}) } right := NodeOrderedSet{} for j, _ := range rightValues { - right = append(right, Node{j + len(left)}) + right = append(right, Node{Id: j + len(left)}) } edges := EdgeSet{} @@ -32,7 +32,7 @@ func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(in } if neighbours { - edges = append(edges, Edge{left[i], right[j]}) + edges = append(edges, Edge{Node1: left[i], Node2: right[j]}) } } } diff --git a/vendor/github.com/onsi/gomega/matchers/type_support.go b/vendor/github.com/onsi/gomega/matchers/type_support.go index b05a5e75..75afcd84 100644 --- a/vendor/github.com/onsi/gomega/matchers/type_support.go +++ b/vendor/github.com/onsi/gomega/matchers/type_support.go @@ -9,6 +9,7 @@ http://onsi.github.io/gomega/ package matchers import ( + "encoding/json" "fmt" "reflect" ) @@ -133,6 +134,11 @@ func toString(a interface{}) (string, bool) { return aStringer.String(), true } + aJSONRawMessage, isJSONRawMessage := a.(json.RawMessage) + if isJSONRawMessage { + return string(aJSONRawMessage), true + } + return "", false } diff --git a/vendor/github.com/onsi/gomega/types/types.go b/vendor/github.com/onsi/gomega/types/types.go index a83b4011..ac59a3a5 100644 --- a/vendor/github.com/onsi/gomega/types/types.go +++ b/vendor/github.com/onsi/gomega/types/types.go @@ -1,7 +1,16 @@ package types +type TWithHelper interface { + Helper() +} + type GomegaFailHandler func(message string, callerSkip ...int) +type GomegaFailWrapper struct { + Fail GomegaFailHandler + TWithHelper TWithHelper +} + //A simple *testing.T interface wrapper type GomegaTestingT interface { Fatalf(format string, args ...interface{}) @@ -9,7 +18,7 @@ type GomegaTestingT interface { //All Gomega matchers must implement the GomegaMatcher interface // -//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding_your_own_matchers +//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding-your-own-matchers type GomegaMatcher interface { Match(actual interface{}) (success bool, err error) FailureMessage(actual interface{}) (message string) diff --git a/vendor/github.com/pelletier/go-toml/.travis.yml b/vendor/github.com/pelletier/go-toml/.travis.yml index ab2775d7..c9fbf304 100644 --- a/vendor/github.com/pelletier/go-toml/.travis.yml +++ b/vendor/github.com/pelletier/go-toml/.travis.yml @@ -1,8 +1,9 @@ sudo: false language: go go: - - 1.8.5 - - 1.9.2 + - 1.8.x + - 1.9.x + - 1.10.x - tip matrix: allow_failures: diff --git a/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go b/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go index b2d6fc67..322315b5 100644 --- a/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go +++ b/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go @@ -17,13 +17,12 @@ import ( func main() { flag.Usage = func() { - fmt.Fprintln(os.Stderr, `tomljson can be used in two ways: -Writing to STDIN and reading from STDOUT: - cat file.toml | tomljson > file.json - -Reading from a file name: - tomljson file.toml -`) + fmt.Fprintln(os.Stderr, "tomljson can be used in two ways:") + fmt.Fprintln(os.Stderr, "Writing to STDIN and reading from STDOUT:") + fmt.Fprintln(os.Stderr, " cat file.toml | tomljson > file.json") + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, "Reading from a file name:") + fmt.Fprintln(os.Stderr, " tomljson file.toml") } flag.Parse() os.Exit(processMain(flag.Args(), os.Stdin, os.Stdout, os.Stderr)) diff --git a/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go b/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go index 36c7e375..93ab0c96 100644 --- a/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go +++ b/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go @@ -17,15 +17,14 @@ import ( func main() { flag.Usage = func() { - fmt.Fprintln(os.Stderr, `tomll can be used in two ways: -Writing to STDIN and reading from STDOUT: - cat file.toml | tomll > file.toml - -Reading and updating a list of files: - tomll a.toml b.toml c.toml - -When given a list of files, tomll will modify all files in place without asking. -`) + fmt.Fprintln(os.Stderr, "tomll can be used in two ways:") + fmt.Fprintln(os.Stderr, "Writing to STDIN and reading from STDOUT:") + fmt.Fprintln(os.Stderr, " cat file.toml | tomll > file.toml") + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, "Reading and updating a list of files:") + fmt.Fprintln(os.Stderr, " tomll a.toml b.toml c.toml") + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, "When given a list of files, tomll will modify all files in place without asking.") } flag.Parse() // read from stdin and print to stdout diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go index b5a24150..671da556 100644 --- a/vendor/github.com/pelletier/go-toml/marshal.go +++ b/vendor/github.com/pelletier/go-toml/marshal.go @@ -11,10 +11,13 @@ import ( "time" ) +const tagKeyMultiline = "multiline" + type tomlOpts struct { name string comment string commented bool + multiline bool include bool omitempty bool } @@ -187,7 +190,7 @@ func (e *Encoder) QuoteMapKeys(v bool) *Encoder { // A = [ // 1, // 2, -// 3 +// 3, // ] func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder { e.arraysOneElementPerLine = v @@ -230,7 +233,12 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er if err != nil { return nil, err } - tval.SetWithComment(opts.name, opts.comment, opts.commented, val) + + tval.SetWithOptions(opts.name, SetOptions{ + Comment: opts.comment, + Commented: opts.commented, + Multiline: opts.multiline, + }, val) } } case reflect.Map: @@ -559,7 +567,8 @@ func tomlOptions(vf reflect.StructField) tomlOpts { comment = c } commented, _ := strconv.ParseBool(vf.Tag.Get("commented")) - result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false} + multiline, _ := strconv.ParseBool(vf.Tag.Get(tagKeyMultiline)) + result := tomlOpts{name: vf.Name, comment: comment, commented: commented, multiline: multiline, include: true, omitempty: false} if parse[0] != "" { if parse[0] == "-" && len(parse) == 1 { result.include = false diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.go b/vendor/github.com/pelletier/go-toml/marshal_test.go index 291a80d2..00cbbf31 100644 --- a/vendor/github.com/pelletier/go-toml/marshal_test.go +++ b/vendor/github.com/pelletier/go-toml/marshal_test.go @@ -775,7 +775,7 @@ func TestMarshalArrayOnePerLine(t *testing.T) { B = [ 1, 2, - 3 + 3, ] C = [1] `) diff --git a/vendor/github.com/pelletier/go-toml/query/parser_test.go b/vendor/github.com/pelletier/go-toml/query/parser_test.go index 473896a0..312f51ab 100644 --- a/vendor/github.com/pelletier/go-toml/query/parser_test.go +++ b/vendor/github.com/pelletier/go-toml/query/parser_test.go @@ -2,12 +2,13 @@ package query import ( "fmt" - "github.com/pelletier/go-toml" "io/ioutil" "sort" "strings" "testing" "time" + + "github.com/pelletier/go-toml" ) type queryTestNode struct { @@ -406,8 +407,7 @@ func TestQueryFilterFn(t *testing.T) { assertQueryPositions(t, string(buff), "$..[?(float)]", - []interface{}{ - // no float values in document + []interface{}{ // no float values in document }) tv, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") diff --git a/vendor/github.com/pelletier/go-toml/test.sh b/vendor/github.com/pelletier/go-toml/test.sh index a70a8b02..ba6adf3f 100755 --- a/vendor/github.com/pelletier/go-toml/test.sh +++ b/vendor/github.com/pelletier/go-toml/test.sh @@ -23,9 +23,6 @@ function git_clone() { # Remove potential previous runs rm -rf src test_program_bin toml-test -# Run go vet -go vet ./... - go get github.com/pelletier/go-buffruneio go get github.com/davecgh/go-spew/spew go get gopkg.in/yaml.v2 diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go index 05493a44..98c185ad 100644 --- a/vendor/github.com/pelletier/go-toml/toml.go +++ b/vendor/github.com/pelletier/go-toml/toml.go @@ -14,6 +14,7 @@ type tomlValue struct { value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list comment string commented bool + multiline bool position Position } @@ -175,6 +176,63 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} { return val } +// SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour. +// The default values within the struct are valid default options. +type SetOptions struct { + Comment string + Commented bool + Multiline bool +} + +// SetWithOptions is the same as Set, but allows you to provide formatting +// instructions to the key, that will be used by Marshal(). +func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) { + t.SetPathWithOptions(strings.Split(key, "."), opts, value) +} + +// SetPathWithOptions is the same as SetPath, but allows you to provide +// formatting instructions to the key, that will be reused by Marshal(). +func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) { + subtree := t + for _, intermediateKey := range keys[:len(keys)-1] { + nextTree, exists := subtree.values[intermediateKey] + if !exists { + nextTree = newTree() + subtree.values[intermediateKey] = nextTree // add new element here + } + switch node := nextTree.(type) { + case *Tree: + subtree = node + case []*Tree: + // go to most recent element + if len(node) == 0 { + // create element if it does not exist + subtree.values[intermediateKey] = append(node, newTree()) + } + subtree = node[len(node)-1] + } + } + + var toInsert interface{} + + switch value.(type) { + case *Tree: + tt := value.(*Tree) + tt.comment = opts.Comment + toInsert = value + case []*Tree: + toInsert = value + case *tomlValue: + tt := value.(*tomlValue) + tt.comment = opts.Comment + toInsert = tt + default: + toInsert = &tomlValue{value: value, comment: opts.Comment, commented: opts.Commented, multiline: opts.Multiline} + } + + subtree.values[keys[len(keys)-1]] = toInsert +} + // Set an element in the tree. // Key is a dot-separated path (e.g. a.b.c). // Creates all necessary intermediate trees, if needed. diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go index d322a976..e4049e29 100644 --- a/vendor/github.com/pelletier/go-toml/tomltree_write.go +++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go @@ -12,7 +12,41 @@ import ( "time" ) -// encodes a string to a TOML-compliant string value +// Encodes a string to a TOML-compliant multi-line string value +// This function is a clone of the existing encodeTomlString function, except that whitespace characters +// are preserved. Quotation marks and backslashes are also not escaped. +func encodeMultilineTomlString(value string) string { + var b bytes.Buffer + + for _, rr := range value { + switch rr { + case '\b': + b.WriteString(`\b`) + case '\t': + b.WriteString("\t") + case '\n': + b.WriteString("\n") + case '\f': + b.WriteString(`\f`) + case '\r': + b.WriteString("\r") + case '"': + b.WriteString(`"`) + case '\\': + b.WriteString(`\`) + default: + intRr := uint16(rr) + if intRr < 0x001F { + b.WriteString(fmt.Sprintf("\\u%0.4X", intRr)) + } else { + b.WriteRune(rr) + } + } + } + return b.String() +} + +// Encodes a string to a TOML-compliant string value func encodeTomlString(value string) string { var b bytes.Buffer @@ -45,6 +79,15 @@ func encodeTomlString(value string) string { } func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) { + // this interface check is added to dereference the change made in the writeTo function. + // That change was made to allow this function to see formatting options. + tv, ok := v.(*tomlValue) + if ok { + v = tv.value + } else { + tv = &tomlValue{} + } + switch value := v.(type) { case uint64: return strconv.FormatUint(value, 10), nil @@ -58,6 +101,9 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen } return strings.ToLower(strconv.FormatFloat(value, 'f', -1, 32)), nil case string: + if tv.multiline { + return "\"\"\"\n" + encodeMultilineTomlString(value) + "\"\"\"", nil + } return "\"" + encodeTomlString(value) + "\"", nil case []byte: b, _ := v.([]byte) @@ -91,12 +137,10 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen stringBuffer.WriteString("[\n") - for i, value := range values { + for _, value := range values { stringBuffer.WriteString(valueIndent) stringBuffer.WriteString(value) - if i != len(values)-1 { - stringBuffer.WriteString(`,`) - } + stringBuffer.WriteString(`,`) stringBuffer.WriteString("\n") } @@ -132,7 +176,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, a return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k]) } - repr, err := tomlValueStringRepresentation(v.value, indent, arraysOneElementPerLine) + repr, err := tomlValueStringRepresentation(v, indent, arraysOneElementPerLine) if err != nil { return bytesCount, err } diff --git a/vendor/github.com/rjeczalik/notify/go.mod b/vendor/github.com/rjeczalik/notify/go.mod deleted file mode 100644 index 2bbfbf3b..00000000 --- a/vendor/github.com/rjeczalik/notify/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/rjeczalik/notify - -require golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7 diff --git a/vendor/github.com/rs/cors/.travis.yml b/vendor/github.com/rs/cors/.travis.yml index 3baa3649..17e5e50d 100644 --- a/vendor/github.com/rs/cors/.travis.yml +++ b/vendor/github.com/rs/cors/.travis.yml @@ -1,6 +1,7 @@ language: go go: -- 1.8 +- 1.9 +- "1.10" - tip matrix: allow_failures: diff --git a/vendor/github.com/rs/cors/README.md b/vendor/github.com/rs/cors/README.md index 9e749021..87413cca 100644 --- a/vendor/github.com/rs/cors/README.md +++ b/vendor/github.com/rs/cors/README.md @@ -49,6 +49,14 @@ The server now runs on `localhost:8080`: {"hello": "world"} +### Allow * With Credentials Security Protection + +This library has been modified to avoid a well known security issue when configured with `AllowedOrigins` to `*` and `AllowCredentials` to `true`. Such setup used to make the library reflects the request `Origin` header value, working around a security protection embedded into the standard that makes clients to refuse such configuration. This behavior has been removed with [#55](https://github.com/rs/cors/issues/55) and [#57](https://github.com/rs/cors/issues/57). + +If you depend on this behavior and understand the implications, you can restore it using the `AllowOriginFunc` with `func(origin string) {return true}`. + +Please refer to [#55](https://github.com/rs/cors/issues/55) for more information about the security implications. + ### More Examples * `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go) @@ -57,6 +65,9 @@ The server now runs on `localhost:8080`: * [Negroni](https://github.com/codegangsta/negroni): [examples/negroni/server.go](https://github.com/rs/cors/blob/master/examples/negroni/server.go) * [Alice](https://github.com/justinas/alice): [examples/alice/server.go](https://github.com/rs/cors/blob/master/examples/alice/server.go) * [HttpRouter](https://github.com/julienschmidt/httprouter): [examples/httprouter/server.go](https://github.com/rs/cors/blob/master/examples/httprouter/server.go) +* [Gorilla](http://www.gorillatoolkit.org/pkg/mux): [examples/gorilla/server.go](https://github.com/rs/cors/blob/master/examples/gorilla/server.go) +* [Buffalo](https://gobuffalo.io): [examples/buffalo/server.go](https://github.com/rs/cors/blob/master/examples/buffalo/server.go) +* [Gin](https://gin-gonic.github.io/gin): [examples/gin/server.go](https://github.com/rs/cors/blob/master/examples/gin/server.go) ## Parameters @@ -64,8 +75,10 @@ Parameters are passed to the middleware thru the `cors.New` method as follow: ```go c := cors.New(cors.Options{ - AllowedOrigins: []string{"http://foo.com"}, + AllowedOrigins: []string{"http://foo.com", "http://foo.com:8080"}, AllowCredentials: true, + // Enable Debugging for testing, consider disabling in production + Debug: true, }) // Insert the middleware diff --git a/vendor/github.com/rs/cors/cors.go b/vendor/github.com/rs/cors/cors.go index 8179c616..15181089 100644 --- a/vendor/github.com/rs/cors/cors.go +++ b/vendor/github.com/rs/cors/cors.go @@ -42,7 +42,7 @@ type Options struct { // set, the content of AllowedOrigins is ignored. AllowOriginFunc func(origin string) bool // AllowedMethods is a list of methods the client is allowed to use with - // cross-domain requests. Default value is simple methods (GET and POST) + // cross-domain requests. Default value is simple methods (HEAD, GET and POST). AllowedMethods []string // AllowedHeaders is list of non simple headers the client is allowed to use with // cross-domain requests. @@ -52,12 +52,12 @@ type Options struct { // ExposedHeaders indicates which headers are safe to expose to the API of a CORS // API specification ExposedHeaders []string - // AllowCredentials indicates whether the request can include user credentials like - // cookies, HTTP authentication or client side SSL certificates. - AllowCredentials bool // MaxAge indicates how long (in seconds) the results of a preflight request // can be cached MaxAge int + // AllowCredentials indicates whether the request can include user credentials like + // cookies, HTTP authentication or client side SSL certificates. + AllowCredentials bool // OptionsPassthrough instructs preflight to let other potential next handlers to // process the OPTIONS method. Turn this on if your application handles OPTIONS. OptionsPassthrough bool @@ -69,24 +69,24 @@ type Options struct { type Cors struct { // Debug logger Log *log.Logger - // Set to true when allowed origins contains a "*" - allowedOriginsAll bool // Normalized list of plain allowed origins allowedOrigins []string // List of allowed origins containing wildcards allowedWOrigins []wildcard // Optional origin validator function allowOriginFunc func(origin string) bool - // Set to true when allowed headers contains a "*" - allowedHeadersAll bool // Normalized list of allowed headers allowedHeaders []string // Normalized list of allowed methods allowedMethods []string // Normalized list of exposed headers - exposedHeaders []string + exposedHeaders []string + maxAge int + // Set to true when allowed origins contains a "*" + allowedOriginsAll bool + // Set to true when allowed headers contains a "*" + allowedHeadersAll bool allowCredentials bool - maxAge int optionPassthrough bool } @@ -127,7 +127,7 @@ func New(options Options) *Cors { break } else if i := strings.IndexByte(origin, '*'); i >= 0 { // Split the origin in two: start and end string without the * - w := wildcard{origin[0:i], origin[i+1 : len(origin)]} + w := wildcard{origin[0:i], origin[i+1:]} c.allowedWOrigins = append(c.allowedWOrigins, w) } else { c.allowedOrigins = append(c.allowedOrigins, origin) @@ -138,7 +138,7 @@ func New(options Options) *Cors { // Allowed Headers if len(options.AllowedHeaders) == 0 { // Use sensible defaults - c.allowedHeaders = []string{"Origin", "Accept", "Content-Type"} + c.allowedHeaders = []string{"Origin", "Accept", "Content-Type", "X-Requested-With"} } else { // Origin is always appended as some browsers will always request for this header at preflight c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey) @@ -154,7 +154,7 @@ func New(options Options) *Cors { // Allowed Methods if len(options.AllowedMethods) == 0 { // Default is spec's "simple" methods - c.allowedMethods = []string{"GET", "POST"} + c.allowedMethods = []string{"GET", "POST", "HEAD"} } else { c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper) } @@ -174,7 +174,7 @@ func AllowAll() *Cors { AllowedOrigins: []string{"*"}, AllowedMethods: []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"}, AllowedHeaders: []string{"*"}, - AllowCredentials: true, + AllowCredentials: false, }) } @@ -182,7 +182,7 @@ func AllowAll() *Cors { // as necessary. func (c *Cors) Handler(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == "OPTIONS" && r.Header.Get("Access-Control-Request-Method") != "" { + if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("Handler: Preflight request") c.handlePreflight(w, r) // Preflight requests are standalone and should stop the chain as some other @@ -204,7 +204,7 @@ func (c *Cors) Handler(h http.Handler) http.Handler { // HandlerFunc provides Martini compatible handler func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) { - if r.Method == "OPTIONS" && r.Header.Get("Access-Control-Request-Method") != "" { + if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("HandlerFunc: Preflight request") c.handlePreflight(w, r) } else { @@ -215,7 +215,7 @@ func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) { // Negroni compatible interface func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - if r.Method == "OPTIONS" && r.Header.Get("Access-Control-Request-Method") != "" { + if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("ServeHTTP: Preflight request") c.handlePreflight(w, r) // Preflight requests are standalone and should stop the chain as some other @@ -239,7 +239,7 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { headers := w.Header() origin := r.Header.Get("Origin") - if r.Method != "OPTIONS" { + if r.Method != http.MethodOptions { c.logf(" Preflight aborted: %s!=OPTIONS", r.Method) return } @@ -269,7 +269,7 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders) return } - if c.allowedOriginsAll && !c.allowCredentials { + if c.allowedOriginsAll { headers.Set("Access-Control-Allow-Origin", "*") } else { headers.Set("Access-Control-Allow-Origin", origin) @@ -297,7 +297,7 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { headers := w.Header() origin := r.Header.Get("Origin") - if r.Method == "OPTIONS" { + if r.Method == http.MethodOptions { c.logf(" Actual request no headers added: method == %s", r.Method) return } @@ -321,7 +321,7 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { return } - if c.allowedOriginsAll && !c.allowCredentials { + if c.allowedOriginsAll { headers.Set("Access-Control-Allow-Origin", "*") } else { headers.Set("Access-Control-Allow-Origin", origin) @@ -373,7 +373,7 @@ func (c *Cors) isMethodAllowed(method string) bool { return false } method = strings.ToUpper(method) - if method == "OPTIONS" { + if method == http.MethodOptions { // Always allow preflight requests return true } diff --git a/vendor/github.com/rs/cors/cors_test.go b/vendor/github.com/rs/cors/cors_test.go index 916c101c..d3dbcba9 100644 --- a/vendor/github.com/rs/cors/cors_test.go +++ b/vendor/github.com/rs/cors/cors_test.go @@ -83,7 +83,7 @@ func TestSpec(t *testing.T) { }, map[string]string{ "Vary": "Origin", - "Access-Control-Allow-Origin": "http://foobar.com", + "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true", }, }, @@ -242,6 +242,25 @@ func TestSpec(t *testing.T) { "Access-Control-Allow-Headers": "X-Header-2, X-Header-1", }, }, + { + "DefaultAllowedHeaders", + Options{ + AllowedOrigins: []string{"http://foobar.com"}, + AllowedHeaders: []string{}, + }, + "OPTIONS", + map[string]string{ + "Origin": "http://foobar.com", + "Access-Control-Request-Method": "GET", + "Access-Control-Request-Headers": "X-Requested-With", + }, + map[string]string{ + "Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers", + "Access-Control-Allow-Origin": "http://foobar.com", + "Access-Control-Allow-Methods": "GET", + "Access-Control-Allow-Headers": "X-Requested-With", + }, + }, { "AllowedWildcardHeader", Options{ @@ -411,7 +430,7 @@ func TestDefault(t *testing.T) { } } -func TestHandlePreflightInvlaidOriginAbortion(t *testing.T) { +func TestHandlePreflightInvalidOriginAbortion(t *testing.T) { s := New(Options{ AllowedOrigins: []string{"http://foo.com"}, }) @@ -451,7 +470,7 @@ func TestHandleActualRequestAbortsOptionsMethod(t *testing.T) { assertHeaders(t, res.Header(), map[string]string{}) } -func TestHandleActualRequestInvlaidOriginAbortion(t *testing.T) { +func TestHandleActualRequestInvalidOriginAbortion(t *testing.T) { s := New(Options{ AllowedOrigins: []string{"http://foo.com"}, }) @@ -466,7 +485,7 @@ func TestHandleActualRequestInvlaidOriginAbortion(t *testing.T) { }) } -func TestHandleActualRequestInvlaidMethodAbortion(t *testing.T) { +func TestHandleActualRequestInvalidMethodAbortion(t *testing.T) { s := New(Options{ AllowedMethods: []string{"POST"}, AllowCredentials: true, diff --git a/vendor/github.com/rs/cors/examples/buffalo/server.go b/vendor/github.com/rs/cors/examples/buffalo/server.go new file mode 100644 index 00000000..57a24452 --- /dev/null +++ b/vendor/github.com/rs/cors/examples/buffalo/server.go @@ -0,0 +1,36 @@ +package main + +import ( + "log" + + "github.com/gobuffalo/buffalo" + "github.com/gobuffalo/buffalo/render" + "github.com/rs/cors" +) + +var r *render.Engine + +func init() { + r = render.New(render.Options{}) +} + +func main() { + app := App() + if err := app.Serve(); err != nil { + log.Fatal(err) + } +} + +func App() *buffalo.App { + app := buffalo.New(buffalo.Options{ + PreWares: []buffalo.PreWare{cors.Default().Handler}, + }) + + app.GET("/", HomeHandler) + + return app +} + +func HomeHandler(c buffalo.Context) error { + return c.Render(200, r.JSON(map[string]string{"message": "Welcome to Buffalo!"})) +} diff --git a/vendor/github.com/rs/cors/examples/gin/server.go b/vendor/github.com/rs/cors/examples/gin/server.go new file mode 100644 index 00000000..a9d898e4 --- /dev/null +++ b/vendor/github.com/rs/cors/examples/gin/server.go @@ -0,0 +1,19 @@ +package main + +import ( + "net/http" + + "github.com/gin-gonic/gin" + cors "github.com/rs/cors/wrapper/gin" +) + +func main() { + router := gin.Default() + + router.Use(cors.Default()) + router.GET("/", func(context *gin.Context) { + context.JSON(http.StatusOK, gin.H{"hello": "world"}) + }) + + router.Run(":8080") +} diff --git a/vendor/github.com/rs/cors/go.mod b/vendor/github.com/rs/cors/go.mod new file mode 100644 index 00000000..0a4c6521 --- /dev/null +++ b/vendor/github.com/rs/cors/go.mod @@ -0,0 +1 @@ +module github.com/rs/cors diff --git a/vendor/github.com/rs/cors/wrapper/gin/gin.go b/vendor/github.com/rs/cors/wrapper/gin/gin.go new file mode 100644 index 00000000..2c775416 --- /dev/null +++ b/vendor/github.com/rs/cors/wrapper/gin/gin.go @@ -0,0 +1,50 @@ +// Package cors/wrapper/gin provides gin.HandlerFunc to handle CORS related +// requests as a wrapper of github.com/rs/cors handler. +package gin + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/rs/cors" +) + +// Options is a configuration container to setup the CORS middleware. +type Options = cors.Options + +// corsWrapper is a wrapper of cors.Cors handler which preserves information +// about configured 'optionPassthrough' option. +type corsWrapper struct { + *cors.Cors + optionPassthrough bool +} + +// build transforms wrapped cors.Cors handler into Gin middleware. +func (c corsWrapper) build() gin.HandlerFunc { + return func(ctx *gin.Context) { + c.HandlerFunc(ctx.Writer, ctx.Request) + if !c.optionPassthrough && + ctx.Request.Method == http.MethodOptions && + ctx.GetHeader("Access-Control-Request-Method") != "" { + // Abort processing next Gin middlewares. + ctx.AbortWithStatus(http.StatusOK) + } + } +} + +// AllowAll creates a new CORS Gin middleware with permissive configuration +// allowing all origins with all standard methods with any header and +// credentials. +func AllowAll() gin.HandlerFunc { + return corsWrapper{Cors: cors.AllowAll()}.build() +} + +// Default creates a new CORS Gin middleware with default options. +func Default() gin.HandlerFunc { + return corsWrapper{Cors: cors.Default()}.build() +} + +// New creates a new CORS Gin middleware with the provided options. +func New(options Options) gin.HandlerFunc { + return corsWrapper{cors.New(options), options.OptionsPassthrough}.build() +} diff --git a/vendor/github.com/rs/cors/wrapper/gin/gin_test.go b/vendor/github.com/rs/cors/wrapper/gin/gin_test.go new file mode 100644 index 00000000..e9f8f751 --- /dev/null +++ b/vendor/github.com/rs/cors/wrapper/gin/gin_test.go @@ -0,0 +1,76 @@ +package gin + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/rs/cors" +) + +func init() { + gin.SetMode(gin.ReleaseMode) +} + +func TestAllowAllNotNil(t *testing.T) { + handler := AllowAll() + if handler == nil { + t.Error("Should not return nil Gin handler") + } +} + +func TestDefaultNotNil(t *testing.T) { + handler := Default() + if handler == nil { + t.Error("Should not return nil Gin handler") + } +} + +func TestNewNotNil(t *testing.T) { + handler := New(Options{}) + if handler == nil { + t.Error("Should not return nil Gin handler") + } +} + +func TestCorsWrapper_buildAbortsWhenPreflight(t *testing.T) { + res := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(res) + ctx.Request, _ = http.NewRequest("OPTIONS", "http://example.com/foo", nil) + ctx.Request.Header.Add("Origin", "http://example.com/") + ctx.Request.Header.Add("Access-Control-Request-Method", "POST") + ctx.Status(http.StatusAccepted) + res.Code = http.StatusAccepted + + handler := corsWrapper{Cors: cors.New(Options{ + // Intentionally left blank. + })}.build() + + handler(ctx) + + if !ctx.IsAborted() { + t.Error("Should abort on preflight requests") + } + if res.Code != http.StatusOK { + t.Error("Should abort with 200 OK status") + } +} + +func TestCorsWrapper_buildNotAbortsWhenPassthrough(t *testing.T) { + res := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(res) + ctx.Request, _ = http.NewRequest("OPTIONS", "http://example.com/foo", nil) + ctx.Request.Header.Add("Origin", "http://example.com/") + ctx.Request.Header.Add("Access-Control-Request-Method", "POST") + + handler := corsWrapper{cors.New(Options{ + OptionsPassthrough: true, + }), true}.build() + + handler(ctx) + + if ctx.IsAborted() { + t.Error("Should not abort when OPTIONS passthrough enabled") + } +} diff --git a/vendor/github.com/sirupsen/logrus/.gitignore b/vendor/github.com/sirupsen/logrus/.gitignore new file mode 100644 index 00000000..6b7d7d1e --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.gitignore @@ -0,0 +1,2 @@ +logrus +vendor diff --git a/vendor/github.com/sirupsen/logrus/.travis.yml b/vendor/github.com/sirupsen/logrus/.travis.yml new file mode 100644 index 00000000..1f953beb --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.travis.yml @@ -0,0 +1,51 @@ +language: go +env: + - GOMAXPROCS=4 GORACE=halt_on_error=1 +matrix: + include: + - go: 1.10.x + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v ./... + - go: 1.11.x + env: GO111MODULE=on + install: + - go mod download + script: + - go test -race -v ./... + - go: 1.11.x + env: GO111MODULE=off + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v ./... + - go: 1.10.x + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v -tags appengine ./... + - go: 1.11.x + env: GO111MODULE=on + install: + - go mod download + script: + - go test -race -v -tags appengine ./... + - go: 1.11.x + env: GO111MODULE=off + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v -tags appengine ./... diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md new file mode 100644 index 00000000..cb85d9f9 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md @@ -0,0 +1,165 @@ +# 1.2.0 +This new release introduces: + * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued + * A new trace level named `Trace` whose level is below `Debug` + * A configurable exit function to be called upon a Fatal trace + * The `Level` object now implements `encoding.TextUnmarshaler` interface + +# 1.1.1 +This is a bug fix release. + * fix the build break on Solaris + * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized + +# 1.1.0 +This new release introduces: + * several fixes: + * a fix for a race condition on entry formatting + * proper cleanup of previously used entries before putting them back in the pool + * the extra new line at the end of message in text formatter has been removed + * a new global public API to check if a level is activated: IsLevelEnabled + * the following methods have been added to the Logger object + * IsLevelEnabled + * SetFormatter + * SetOutput + * ReplaceHooks + * introduction of go module + * an indent configuration for the json formatter + * output colour support for windows + * the field sort function is now configurable for text formatter + * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater + +# 1.0.6 + +This new release introduces: + * a new api WithTime which allows to easily force the time of the log entry + which is mostly useful for logger wrapper + * a fix reverting the immutability of the entry given as parameter to the hooks + a new configuration field of the json formatter in order to put all the fields + in a nested dictionnary + * a new SetOutput method in the Logger + * a new configuration of the textformatter to configure the name of the default keys + * a new configuration of the text formatter to disable the level truncation + +# 1.0.5 + +* Fix hooks race (#707) +* Fix panic deadlock (#695) + +# 1.0.4 + +* Fix race when adding hooks (#612) +* Fix terminal check in AppEngine (#635) + +# 1.0.3 + +* Replace example files with testable examples + +# 1.0.2 + +* bug: quote non-string values in text formatter (#583) +* Make (*Logger) SetLevel a public method + +# 1.0.1 + +* bug: fix escaping in text formatter (#575) + +# 1.0.0 + +* Officially changed name to lower-case +* bug: colors on Windows 10 (#541) +* bug: fix race in accessing level (#512) + +# 0.11.5 + +* feature: add writer and writerlevel to entry (#372) + +# 0.11.4 + +* bug: fix undefined variable on solaris (#493) + +# 0.11.3 + +* formatter: configure quoting of empty values (#484) +* formatter: configure quoting character (default is `"`) (#484) +* bug: fix not importing io correctly in non-linux environments (#481) + +# 0.11.2 + +* bug: fix windows terminal detection (#476) + +# 0.11.1 + +* bug: fix tty detection with custom out (#471) + +# 0.11.0 + +* performance: Use bufferpool to allocate (#370) +* terminal: terminal detection for app-engine (#343) +* feature: exit handler (#375) + +# 0.10.0 + +* feature: Add a test hook (#180) +* feature: `ParseLevel` is now case-insensitive (#326) +* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) +* performance: avoid re-allocations on `WithFields` (#335) + +# 0.9.0 + +* logrus/text_formatter: don't emit empty msg +* logrus/hooks/airbrake: move out of main repository +* logrus/hooks/sentry: move out of main repository +* logrus/hooks/papertrail: move out of main repository +* logrus/hooks/bugsnag: move out of main repository +* logrus/core: run tests with `-race` +* logrus/core: detect TTY based on `stderr` +* logrus/core: support `WithError` on logger +* logrus/core: Solaris support + +# 0.8.7 + +* logrus/core: fix possible race (#216) +* logrus/doc: small typo fixes and doc improvements + + +# 0.8.6 + +* hooks/raven: allow passing an initialized client + +# 0.8.5 + +* logrus/core: revert #208 + +# 0.8.4 + +* formatter/text: fix data race (#218) + +# 0.8.3 + +* logrus/core: fix entry log level (#208) +* logrus/core: improve performance of text formatter by 40% +* logrus/core: expose `LevelHooks` type +* logrus/core: add support for DragonflyBSD and NetBSD +* formatter/text: print structs more verbosely + +# 0.8.2 + +* logrus: fix more Fatal family functions + +# 0.8.1 + +* logrus: fix not exiting on `Fatalf` and `Fatalln` + +# 0.8.0 + +* logrus: defaults to stderr instead of stdout +* hooks/sentry: add special field for `*http.Request` +* formatter/text: ignore Windows for colors + +# 0.7.3 + +* formatter/\*: allow configuration of timestamp layout + +# 0.7.2 + +* formatter/text: Add configuration option for time format (#158) diff --git a/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/sirupsen/logrus/LICENSE new file mode 100644 index 00000000..f090cb42 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md new file mode 100644 index 00000000..093bb13f --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/README.md @@ -0,0 +1,493 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. + +**Seeing weird case-sensitive problems?** It's in the past been possible to +import Logrus as both upper- and lower-case. Due to the Go package environment, +this caused issues in the community and we needed a standard. Some environments +experienced problems with the upper-case variant, so the lower-case was decided. +Everything using `logrus` will need to use the lower-case: +`github.com/sirupsen/logrus`. Any package that isn't, should be changed. + +To fix Glide, see [these +comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). +For an in-depth explanation of the casing issue, see [this +comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). + +**Are you interested in assisting in maintaining Logrus?** Currently I have a +lot of obligations, and I am unable to provide Logrus with the maintainership it +needs. If you'd like to help, please reach out to me at `simon at author's +username dot com`. + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +``` +To ensure this behaviour even if a TTY is attached, set your formatter as follows: + +```go + log.SetFormatter(&log.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) +``` + +#### Logging Method Name + +If you wish to add the calling method as a field, instruct the logger via: +```go +log.SetReportCaller(true) +``` +This adds the caller as 'method' like so: + +```json +{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", +"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} +``` + +```text +time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin +``` +Note that this does add measurable overhead - the cost will depend on the version of Go, but is +between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your +environment via benchmarks: +``` +go test -bench=.*CallerTracing +``` + + +#### Case-sensitivity + +The organization's name was changed to lower-case--and this will not be changed +back. If you are getting import conflicts due to case sensitivity, please use +the lower-case import: `github.com/sirupsen/logrus`. + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/sirupsen/logrus" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "os" + "github.com/sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stdout + + // You could set this to any `io.Writer` such as a file + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging through logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Default Fields + +Often it's helpful to have fields _always_ attached to log statements in an +application or parts of one. For example, you may want to always log the +`request_id` and `user_ip` in the context of a request. Instead of writing +`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +every line, you can create a `logrus.Entry` to pass around instead: + +```go +requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger.Warn("something not great happened") +``` + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/sirupsen/logrus" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook(123, "xyz", "production")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` +Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). + +A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) + + +#### Level logging + +Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Trace("Something very low level.") +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true`. For Windows, see + [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). + * When colors are enabled, levels are truncated to 4 characters by default. To disable + truncation set the `DisableLevelTruncation` field to `true`. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). +* `logrus.JSONFormatter`. Logs fields as JSON. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + +Third party logging formatters: + +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. +* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. +* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. +* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +This means that we can override the standard library logger easily: + +```go +logger := logrus.New() +logger.Formatter = &logrus.JSONFormatter{} + +// Use logrus for standard log output +// Note that `log` here references stdlib's log +// Not logrus imported under the name `log`. +log.SetOutput(logger.Writer()) +``` + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + +#### Tools + +| Tool | Description | +| ---- | ----------- | +|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| +|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | + +#### Testing + +Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: + +* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook +* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): + +```go +import( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSomething(t*testing.T){ + logger, hook := test.NewNullLogger() + logger.Error("Helloerror") + + assert.Equal(t, 1, len(hook.Entries)) + assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal(t, "Helloerror", hook.LastEntry().Message) + + hook.Reset() + assert.Nil(t, hook.LastEntry()) +} +``` + +#### Fatal handlers + +Logrus can register one or more functions that will be called when any `fatal` +level message is logged. The registered handlers will be executed before +logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need +to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. + +``` +... +handler := func() { + // gracefully shutdown something... +} +logrus.RegisterExitHandler(handler) +... +``` + +#### Thread safety + +By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. +If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. + +Situation when locking is not needed includes: + +* You have no hooks registered, or hooks calling is already thread-safe. + +* Writing to logger.Out is already thread-safe, for example: + + 1) logger.Out is protected by locks. + + 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) + + (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go new file mode 100644 index 00000000..8af90637 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/alt_exit.go @@ -0,0 +1,64 @@ +package logrus + +// The following code was sourced and modified from the +// https://github.com/tebeka/atexit package governed by the following license: +// +// Copyright (c) 2012 Miki Tebeka . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import ( + "fmt" + "os" +) + +var handlers = []func(){} + +func runHandler(handler func()) { + defer func() { + if err := recover(); err != nil { + fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) + } + }() + + handler() +} + +func runHandlers() { + for _, handler := range handlers { + runHandler(handler) + } +} + +// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) +func Exit(code int) { + runHandlers() + os.Exit(code) +} + +// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke +// all handlers. The handlers will also be invoked when any Fatal log entry is +// made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func RegisterExitHandler(handler func()) { + handlers = append(handlers, handler) +} diff --git a/vendor/github.com/sirupsen/logrus/alt_exit_test.go b/vendor/github.com/sirupsen/logrus/alt_exit_test.go new file mode 100644 index 00000000..0a2ff565 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/alt_exit_test.go @@ -0,0 +1,99 @@ +package logrus + +import ( + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "time" +) + +func TestRegister(t *testing.T) { + current := len(handlers) + RegisterExitHandler(func() {}) + if len(handlers) != current+1 { + t.Fatalf("expected %d handlers, got %d", current+1, len(handlers)) + } +} + +func TestHandler(t *testing.T) { + testprog := testprogleader + testprog = append(testprog, getPackage()...) + testprog = append(testprog, testprogtrailer...) + tempDir, err := ioutil.TempDir("", "test_handler") + if err != nil { + log.Fatalf("can't create temp dir. %q", err) + } + defer os.RemoveAll(tempDir) + + gofile := filepath.Join(tempDir, "gofile.go") + if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil { + t.Fatalf("can't create go file. %q", err) + } + + outfile := filepath.Join(tempDir, "outfile.out") + arg := time.Now().UTC().String() + err = exec.Command("go", "run", gofile, outfile, arg).Run() + if err == nil { + t.Fatalf("completed normally, should have failed") + } + + data, err := ioutil.ReadFile(outfile) + if err != nil { + t.Fatalf("can't read output file %s. %q", outfile, err) + } + + if string(data) != arg { + t.Fatalf("bad data. Expected %q, got %q", data, arg) + } +} + +// getPackage returns the name of the current package, which makes running this +// test in a fork simpler +func getPackage() []byte { + pc, _, _, _ := runtime.Caller(0) + fullFuncName := runtime.FuncForPC(pc).Name() + idx := strings.LastIndex(fullFuncName, ".") + return []byte(fullFuncName[:idx]) // trim off function details +} + +var testprogleader = []byte(` +// Test program for atexit, gets output file and data as arguments and writes +// data to output file in atexit handler. +package main + +import ( + "`) +var testprogtrailer = []byte( + `" + "flag" + "fmt" + "io/ioutil" +) + +var outfile = "" +var data = "" + +func handler() { + ioutil.WriteFile(outfile, []byte(data), 0666) +} + +func badHandler() { + n := 0 + fmt.Println(1/n) +} + +func main() { + flag.Parse() + outfile = flag.Arg(0) + data = flag.Arg(1) + + logrus.RegisterExitHandler(handler) + logrus.RegisterExitHandler(badHandler) + logrus.Fatal("Bye bye") +} +`) diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml new file mode 100644 index 00000000..96c2ce15 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/appveyor.yml @@ -0,0 +1,14 @@ +version: "{build}" +platform: x64 +clone_folder: c:\gopath\src\github.com\sirupsen\logrus +environment: + GOPATH: c:\gopath +branches: + only: + - master +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - go version +build_script: + - go get -t + - go test diff --git a/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go new file mode 100644 index 00000000..da67aba0 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/doc.go @@ -0,0 +1,26 @@ +/* +Package logrus is a structured logger for Go, completely API compatible with the standard library logger. + + +The simplest way to use Logrus is simply the package-level exported logger: + + package main + + import ( + log "github.com/sirupsen/logrus" + ) + + func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "number": 1, + "size": 10, + }).Info("A walrus appears") + } + +Output: + time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 + +For a full guide visit https://github.com/sirupsen/logrus +*/ +package logrus diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go new file mode 100644 index 00000000..cc85d3aa --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -0,0 +1,408 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "reflect" + "runtime" + "strings" + "sync" + "time" +) + +var ( + bufferPool *sync.Pool + + // qualified package name, cached at first use + logrusPackage string + + // Positions in the call stack when tracing to report the calling method + minimumCallerDepth int + + // Used for caller information initialisation + callerInitOnce sync.Once +) + +const ( + maximumCallerDepth int = 25 + knownLogrusFrames int = 4 +) + +func init() { + bufferPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + } + + // start at the bottom of the stack before the package-name cache is primed + minimumCallerDepth = 1 +} + +// Defines the key when adding errors using WithError. +var ErrorKey = "error" + +// An entry is the final or intermediate Logrus logging entry. It contains all +// the fields passed with WithField{,s}. It's finally logged when Trace, Debug, +// Info, Warn, Error, Fatal or Panic is called on it. These objects can be +// reused and passed around as much as you wish to avoid field duplication. +type Entry struct { + Logger *Logger + + // Contains all the fields set by the user. + Data Fields + + // Time at which the log entry was created + Time time.Time + + // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic + // This field will be set on entry firing and the value will be equal to the one in Logger struct field. + Level Level + + // Calling method, with package name + Caller *runtime.Frame + + // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic + Message string + + // When formatter is called in entry.log(), a Buffer may be set to entry + Buffer *bytes.Buffer + + // err may contain a field formatting error + err string +} + +func NewEntry(logger *Logger) *Entry { + return &Entry{ + Logger: logger, + // Default is three fields, plus one optional. Give a little extra room. + Data: make(Fields, 6), + } +} + +// Returns the string representation from the reader and ultimately the +// formatter. +func (entry *Entry) String() (string, error) { + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + return "", err + } + str := string(serialized) + return str, nil +} + +// Add an error as single field (using the key defined in ErrorKey) to the Entry. +func (entry *Entry) WithError(err error) *Entry { + return entry.WithField(ErrorKey, err) +} + +// Add a single field to the Entry. +func (entry *Entry) WithField(key string, value interface{}) *Entry { + return entry.WithFields(Fields{key: value}) +} + +// Add a map of fields to the Entry. +func (entry *Entry) WithFields(fields Fields) *Entry { + data := make(Fields, len(entry.Data)+len(fields)) + for k, v := range entry.Data { + data[k] = v + } + var field_err string + for k, v := range fields { + if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Func { + field_err = fmt.Sprintf("can not add field %q", k) + if entry.err != "" { + field_err = entry.err + ", " + field_err + } + } else { + data[k] = v + } + } + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err} +} + +// Overrides the time of the Entry. +func (entry *Entry) WithTime(t time.Time) *Entry { + return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t} +} + +// getPackageName reduces a fully qualified function name to the package name +// There really ought to be to be a better way... +func getPackageName(f string) string { + for { + lastPeriod := strings.LastIndex(f, ".") + lastSlash := strings.LastIndex(f, "/") + if lastPeriod > lastSlash { + f = f[:lastPeriod] + } else { + break + } + } + + return f +} + +// getCaller retrieves the name of the first non-logrus calling function +func getCaller() *runtime.Frame { + // Restrict the lookback frames to avoid runaway lookups + pcs := make([]uintptr, maximumCallerDepth) + depth := runtime.Callers(minimumCallerDepth, pcs) + frames := runtime.CallersFrames(pcs[:depth]) + + // cache this package's fully-qualified name + callerInitOnce.Do(func() { + logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name()) + + // now that we have the cache, we can skip a minimum count of known-logrus functions + // XXX this is dubious, the number of frames may vary store an entry in a logger interface + minimumCallerDepth = knownLogrusFrames + }) + + for f, again := frames.Next(); again; f, again = frames.Next() { + pkg := getPackageName(f.Function) + + // If the caller isn't part of this package, we're done + if pkg != logrusPackage { + return &f + } + } + + // if we got here, we failed to find the caller's context + return nil +} + +func (entry Entry) HasCaller() (has bool) { + return entry.Logger != nil && + entry.Logger.ReportCaller && + entry.Caller != nil +} + +// This function is not declared with a pointer value because otherwise +// race conditions will occur when using multiple goroutines +func (entry Entry) log(level Level, msg string) { + var buffer *bytes.Buffer + + // Default to now, but allow users to override if they want. + // + // We don't have to worry about polluting future calls to Entry#log() + // with this assignment because this function is declared with a + // non-pointer receiver. + if entry.Time.IsZero() { + entry.Time = time.Now() + } + + entry.Level = level + entry.Message = msg + if entry.Logger.ReportCaller { + entry.Caller = getCaller() + } + + entry.fireHooks() + + buffer = bufferPool.Get().(*bytes.Buffer) + buffer.Reset() + defer bufferPool.Put(buffer) + entry.Buffer = buffer + + entry.write() + + entry.Buffer = nil + + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) + } +} + +func (entry *Entry) fireHooks() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + err := entry.Logger.Hooks.Fire(entry.Level, entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + } +} + +func (entry *Entry) write() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + } else { + _, err = entry.Logger.Out.Write(serialized) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + } +} + +func (entry *Entry) Trace(args ...interface{}) { + if entry.Logger.IsLevelEnabled(TraceLevel) { + entry.log(TraceLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Debug(args ...interface{}) { + if entry.Logger.IsLevelEnabled(DebugLevel) { + entry.log(DebugLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Print(args ...interface{}) { + entry.Info(args...) +} + +func (entry *Entry) Info(args ...interface{}) { + if entry.Logger.IsLevelEnabled(InfoLevel) { + entry.log(InfoLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Warn(args ...interface{}) { + if entry.Logger.IsLevelEnabled(WarnLevel) { + entry.log(WarnLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Warning(args ...interface{}) { + entry.Warn(args...) +} + +func (entry *Entry) Error(args ...interface{}) { + if entry.Logger.IsLevelEnabled(ErrorLevel) { + entry.log(ErrorLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Fatal(args ...interface{}) { + if entry.Logger.IsLevelEnabled(FatalLevel) { + entry.log(FatalLevel, fmt.Sprint(args...)) + } + entry.Logger.Exit(1) +} + +func (entry *Entry) Panic(args ...interface{}) { + if entry.Logger.IsLevelEnabled(PanicLevel) { + entry.log(PanicLevel, fmt.Sprint(args...)) + } + panic(fmt.Sprint(args...)) +} + +// Entry Printf family functions + +func (entry *Entry) Tracef(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(TraceLevel) { + entry.Trace(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Debugf(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(DebugLevel) { + entry.Debug(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Infof(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(InfoLevel) { + entry.Info(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Printf(format string, args ...interface{}) { + entry.Infof(format, args...) +} + +func (entry *Entry) Warnf(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(WarnLevel) { + entry.Warn(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Warningf(format string, args ...interface{}) { + entry.Warnf(format, args...) +} + +func (entry *Entry) Errorf(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(ErrorLevel) { + entry.Error(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Fatalf(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(FatalLevel) { + entry.Fatal(fmt.Sprintf(format, args...)) + } + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicf(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(PanicLevel) { + entry.Panic(fmt.Sprintf(format, args...)) + } +} + +// Entry Println family functions + +func (entry *Entry) Traceln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(TraceLevel) { + entry.Trace(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Debugln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(DebugLevel) { + entry.Debug(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Infoln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(InfoLevel) { + entry.Info(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Println(args ...interface{}) { + entry.Infoln(args...) +} + +func (entry *Entry) Warnln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(WarnLevel) { + entry.Warn(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Warningln(args ...interface{}) { + entry.Warnln(args...) +} + +func (entry *Entry) Errorln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(ErrorLevel) { + entry.Error(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Fatalln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(FatalLevel) { + entry.Fatal(entry.sprintlnn(args...)) + } + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(PanicLevel) { + entry.Panic(entry.sprintlnn(args...)) + } +} + +// Sprintlnn => Sprint no newline. This is to get the behavior of how +// fmt.Sprintln where spaces are always added between operands, regardless of +// their type. Instead of vendoring the Sprintln implementation to spare a +// string allocation, we do the simplest thing. +func (entry *Entry) sprintlnn(args ...interface{}) string { + msg := fmt.Sprintln(args...) + return msg[:len(msg)-1] +} diff --git a/vendor/github.com/sirupsen/logrus/entry_test.go b/vendor/github.com/sirupsen/logrus/entry_test.go new file mode 100644 index 00000000..a81e2b38 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/entry_test.go @@ -0,0 +1,115 @@ +package logrus + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEntryWithError(t *testing.T) { + + assert := assert.New(t) + + defer func() { + ErrorKey = "error" + }() + + err := fmt.Errorf("kaboom at layer %d", 4711) + + assert.Equal(err, WithError(err).Data["error"]) + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + + assert.Equal(err, entry.WithError(err).Data["error"]) + + ErrorKey = "err" + + assert.Equal(err, entry.WithError(err).Data["err"]) + +} + +func TestEntryPanicln(t *testing.T) { + errBoom := fmt.Errorf("boom time") + + defer func() { + p := recover() + assert.NotNil(t, p) + + switch pVal := p.(type) { + case *Entry: + assert.Equal(t, "kaboom", pVal.Message) + assert.Equal(t, errBoom, pVal.Data["err"]) + default: + t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) + } + }() + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + entry.WithField("err", errBoom).Panicln("kaboom") +} + +func TestEntryPanicf(t *testing.T) { + errBoom := fmt.Errorf("boom again") + + defer func() { + p := recover() + assert.NotNil(t, p) + + switch pVal := p.(type) { + case *Entry: + assert.Equal(t, "kaboom true", pVal.Message) + assert.Equal(t, errBoom, pVal.Data["err"]) + default: + t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) + } + }() + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + entry.WithField("err", errBoom).Panicf("kaboom %v", true) +} + +const ( + badMessage = "this is going to panic" + panicMessage = "this is broken" +) + +type panickyHook struct{} + +func (p *panickyHook) Levels() []Level { + return []Level{InfoLevel} +} + +func (p *panickyHook) Fire(entry *Entry) error { + if entry.Message == badMessage { + panic(panicMessage) + } + + return nil +} + +func TestEntryHooksPanic(t *testing.T) { + logger := New() + logger.Out = &bytes.Buffer{} + logger.Level = InfoLevel + logger.Hooks.Add(&panickyHook{}) + + defer func() { + p := recover() + assert.NotNil(t, p) + assert.Equal(t, panicMessage, p) + + entry := NewEntry(logger) + entry.Info("another message") + }() + + entry := NewEntry(logger) + entry.Info(badMessage) +} diff --git a/vendor/github.com/sirupsen/logrus/example_basic_test.go b/vendor/github.com/sirupsen/logrus/example_basic_test.go new file mode 100644 index 00000000..9ff56555 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/example_basic_test.go @@ -0,0 +1,77 @@ +package logrus_test + +import ( + "os" + + "github.com/sirupsen/logrus" +) + +func Example_basic() { + var log = logrus.New() + log.Formatter = new(logrus.JSONFormatter) + log.Formatter = new(logrus.TextFormatter) //default + log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors + log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output + log.Level = logrus.TraceLevel + log.Out = os.Stdout + + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + defer func() { + err := recover() + if err != nil { + entry := err.(*logrus.Entry) + log.WithFields(logrus.Fields{ + "omg": true, + "err_animal": entry.Data["animal"], + "err_size": entry.Data["size"], + "err_level": entry.Level, + "err_message": entry.Message, + "number": 100, + }).Error("The ice breaks!") // or use Fatal() to force the process to exit with a nonzero code + } + }() + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "number": 0, + }).Trace("Went to the beach") + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "number": 8, + }).Debug("Started observing beach") + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(logrus.Fields{ + "temperature": -4, + }).Debug("Temperature changes") + + log.WithFields(logrus.Fields{ + "animal": "orca", + "size": 9009, + }).Panic("It's over 9000!") + + // Output: + // level=trace msg="Went to the beach" animal=walrus number=0 + // level=debug msg="Started observing beach" animal=walrus number=8 + // level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 + // level=warning msg="The group's number increased tremendously!" number=122 omg=true + // level=debug msg="Temperature changes" temperature=-4 + // level=panic msg="It's over 9000!" animal=orca size=9009 + // level=error msg="The ice breaks!" err_animal=orca err_level=panic err_message="It's over 9000!" err_size=9009 number=100 omg=true +} diff --git a/vendor/github.com/sirupsen/logrus/example_global_hook_test.go b/vendor/github.com/sirupsen/logrus/example_global_hook_test.go new file mode 100644 index 00000000..c81e448c --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/example_global_hook_test.go @@ -0,0 +1,36 @@ +package logrus_test + +import ( + "github.com/sirupsen/logrus" + "os" +) + +var ( + mystring string +) + +type GlobalHook struct { +} + +func (h *GlobalHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h *GlobalHook) Fire(e *logrus.Entry) error { + e.Data["mystring"] = mystring + return nil +} + +func Example() { + l := logrus.New() + l.Out = os.Stdout + l.Formatter = &logrus.TextFormatter{DisableTimestamp: true, DisableColors: true} + l.AddHook(&GlobalHook{}) + mystring = "first value" + l.Info("first log") + mystring = "another value" + l.Info("second log") + // Output: + // level=info msg="first log" mystring="first value" + // level=info msg="second log" mystring="another value" +} diff --git a/vendor/github.com/sirupsen/logrus/example_hook_test.go b/vendor/github.com/sirupsen/logrus/example_hook_test.go new file mode 100644 index 00000000..15118d26 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/example_hook_test.go @@ -0,0 +1,43 @@ +// +build !windows + +package logrus_test + +import ( + "log/syslog" + "os" + + "github.com/sirupsen/logrus" + slhooks "github.com/sirupsen/logrus/hooks/syslog" +) + +// An example on how to use a hook +func Example_hook() { + var log = logrus.New() + log.Formatter = new(logrus.TextFormatter) // default + log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors + log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output + if sl, err := slhooks.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""); err != nil { + log.Hooks.Add(sl) + } + log.Out = os.Stdout + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 100, + }).Error("The ice breaks!") + + // Output: + // level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 + // level=warning msg="The group's number increased tremendously!" number=122 omg=true + // level=error msg="The ice breaks!" number=100 omg=true +} diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go new file mode 100644 index 00000000..7342613c --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -0,0 +1,219 @@ +package logrus + +import ( + "io" + "time" +) + +var ( + // std is the name of the standard logger in stdlib `log` + std = New() +) + +func StandardLogger() *Logger { + return std +} + +// SetOutput sets the standard logger output. +func SetOutput(out io.Writer) { + std.SetOutput(out) +} + +// SetFormatter sets the standard logger formatter. +func SetFormatter(formatter Formatter) { + std.SetFormatter(formatter) +} + +// SetReportCaller sets whether the standard logger will include the calling +// method as a field. +func SetReportCaller(include bool) { + std.SetReportCaller(include) +} + +// SetLevel sets the standard logger level. +func SetLevel(level Level) { + std.SetLevel(level) +} + +// GetLevel returns the standard logger level. +func GetLevel() Level { + return std.GetLevel() +} + +// IsLevelEnabled checks if the log level of the standard logger is greater than the level param +func IsLevelEnabled(level Level) bool { + return std.IsLevelEnabled(level) +} + +// AddHook adds a hook to the standard logger hooks. +func AddHook(hook Hook) { + std.AddHook(hook) +} + +// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. +func WithError(err error) *Entry { + return std.WithField(ErrorKey, err) +} + +// WithField creates an entry from the standard logger and adds a field to +// it. If you want multiple fields, use `WithFields`. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithField(key string, value interface{}) *Entry { + return std.WithField(key, value) +} + +// WithFields creates an entry from the standard logger and adds multiple +// fields to it. This is simply a helper for `WithField`, invoking it +// once for each field. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithFields(fields Fields) *Entry { + return std.WithFields(fields) +} + +// WithTime creats an entry from the standard logger and overrides the time of +// logs generated with it. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithTime(t time.Time) *Entry { + return std.WithTime(t) +} + +// Trace logs a message at level Trace on the standard logger. +func Trace(args ...interface{}) { + std.Trace(args...) +} + +// Debug logs a message at level Debug on the standard logger. +func Debug(args ...interface{}) { + std.Debug(args...) +} + +// Print logs a message at level Info on the standard logger. +func Print(args ...interface{}) { + std.Print(args...) +} + +// Info logs a message at level Info on the standard logger. +func Info(args ...interface{}) { + std.Info(args...) +} + +// Warn logs a message at level Warn on the standard logger. +func Warn(args ...interface{}) { + std.Warn(args...) +} + +// Warning logs a message at level Warn on the standard logger. +func Warning(args ...interface{}) { + std.Warning(args...) +} + +// Error logs a message at level Error on the standard logger. +func Error(args ...interface{}) { + std.Error(args...) +} + +// Panic logs a message at level Panic on the standard logger. +func Panic(args ...interface{}) { + std.Panic(args...) +} + +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatal(args ...interface{}) { + std.Fatal(args...) +} + +// Tracef logs a message at level Trace on the standard logger. +func Tracef(format string, args ...interface{}) { + std.Tracef(format, args...) +} + +// Debugf logs a message at level Debug on the standard logger. +func Debugf(format string, args ...interface{}) { + std.Debugf(format, args...) +} + +// Printf logs a message at level Info on the standard logger. +func Printf(format string, args ...interface{}) { + std.Printf(format, args...) +} + +// Infof logs a message at level Info on the standard logger. +func Infof(format string, args ...interface{}) { + std.Infof(format, args...) +} + +// Warnf logs a message at level Warn on the standard logger. +func Warnf(format string, args ...interface{}) { + std.Warnf(format, args...) +} + +// Warningf logs a message at level Warn on the standard logger. +func Warningf(format string, args ...interface{}) { + std.Warningf(format, args...) +} + +// Errorf logs a message at level Error on the standard logger. +func Errorf(format string, args ...interface{}) { + std.Errorf(format, args...) +} + +// Panicf logs a message at level Panic on the standard logger. +func Panicf(format string, args ...interface{}) { + std.Panicf(format, args...) +} + +// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalf(format string, args ...interface{}) { + std.Fatalf(format, args...) +} + +// Traceln logs a message at level Trace on the standard logger. +func Traceln(args ...interface{}) { + std.Traceln(args...) +} + +// Debugln logs a message at level Debug on the standard logger. +func Debugln(args ...interface{}) { + std.Debugln(args...) +} + +// Println logs a message at level Info on the standard logger. +func Println(args ...interface{}) { + std.Println(args...) +} + +// Infoln logs a message at level Info on the standard logger. +func Infoln(args ...interface{}) { + std.Infoln(args...) +} + +// Warnln logs a message at level Warn on the standard logger. +func Warnln(args ...interface{}) { + std.Warnln(args...) +} + +// Warningln logs a message at level Warn on the standard logger. +func Warningln(args ...interface{}) { + std.Warningln(args...) +} + +// Errorln logs a message at level Error on the standard logger. +func Errorln(args ...interface{}) { + std.Errorln(args...) +} + +// Panicln logs a message at level Panic on the standard logger. +func Panicln(args ...interface{}) { + std.Panicln(args...) +} + +// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalln(args ...interface{}) { + std.Fatalln(args...) +} diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go new file mode 100644 index 00000000..40888377 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -0,0 +1,78 @@ +package logrus + +import "time" + +// Default key names for the default fields +const ( + defaultTimestampFormat = time.RFC3339 + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" + FieldKeyLogrusError = "logrus_error" + FieldKeyFunc = "func" + FieldKeyFile = "file" +) + +// The Formatter interface is used to implement a custom Formatter. It takes an +// `Entry`. It exposes all the fields, including the default ones: +// +// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. +// * `entry.Data["time"]`. The timestamp. +// * `entry.Data["level"]. The level the entry was logged at. +// +// Any additional fields added with `WithField` or `WithFields` are also in +// `entry.Data`. Format is expected to return an array of bytes which are then +// logged to `logger.Out`. +type Formatter interface { + Format(*Entry) ([]byte, error) +} + +// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when +// dumping it. If this code wasn't there doing: +// +// logrus.WithField("level", 1).Info("hello") +// +// Would just silently drop the user provided level. Instead with this code +// it'll logged as: +// +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// +// It's not exported because it's still using Data in an opinionated way. It's to +// avoid code duplication between the two default formatters. +func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { + timeKey := fieldMap.resolve(FieldKeyTime) + if t, ok := data[timeKey]; ok { + data["fields."+timeKey] = t + delete(data, timeKey) + } + + msgKey := fieldMap.resolve(FieldKeyMsg) + if m, ok := data[msgKey]; ok { + data["fields."+msgKey] = m + delete(data, msgKey) + } + + levelKey := fieldMap.resolve(FieldKeyLevel) + if l, ok := data[levelKey]; ok { + data["fields."+levelKey] = l + delete(data, levelKey) + } + + logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) + if l, ok := data[logrusErrKey]; ok { + data["fields."+logrusErrKey] = l + delete(data, logrusErrKey) + } + + // If reportCaller is not set, 'func' will not conflict. + if reportCaller { + funcKey := fieldMap.resolve(FieldKeyFunc) + if l, ok := data[funcKey]; ok { + data["fields."+funcKey] = l + } + fileKey := fieldMap.resolve(FieldKeyFile) + if l, ok := data[fileKey]; ok { + data["fields."+fileKey] = l + } + } +} diff --git a/vendor/github.com/sirupsen/logrus/formatter_bench_test.go b/vendor/github.com/sirupsen/logrus/formatter_bench_test.go new file mode 100644 index 00000000..d9481589 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/formatter_bench_test.go @@ -0,0 +1,101 @@ +package logrus + +import ( + "fmt" + "testing" + "time" +) + +// smallFields is a small size data set for benchmarking +var smallFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", +} + +// largeFields is a large size data set for benchmarking +var largeFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", + "five": "six", + "seven": "eight", + "nine": "ten", + "eleven": "twelve", + "thirteen": "fourteen", + "fifteen": "sixteen", + "seventeen": "eighteen", + "nineteen": "twenty", + "a": "b", + "c": "d", + "e": "f", + "g": "h", + "i": "j", + "k": "l", + "m": "n", + "o": "p", + "q": "r", + "s": "t", + "u": "v", + "w": "x", + "y": "z", + "this": "will", + "make": "thirty", + "entries": "yeah", +} + +var errorFields = Fields{ + "foo": fmt.Errorf("bar"), + "baz": fmt.Errorf("qux"), +} + +func BenchmarkErrorTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields) +} + +func BenchmarkSmallTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) +} + +func BenchmarkLargeTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) +} + +func BenchmarkSmallColoredTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) +} + +func BenchmarkLargeColoredTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) +} + +func BenchmarkSmallJSONFormatter(b *testing.B) { + doBenchmark(b, &JSONFormatter{}, smallFields) +} + +func BenchmarkLargeJSONFormatter(b *testing.B) { + doBenchmark(b, &JSONFormatter{}, largeFields) +} + +func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { + logger := New() + + entry := &Entry{ + Time: time.Time{}, + Level: InfoLevel, + Message: "message", + Data: fields, + Logger: logger, + } + var d []byte + var err error + for i := 0; i < b.N; i++ { + d, err = formatter.Format(entry) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(d))) + } +} diff --git a/vendor/github.com/sirupsen/logrus/go.mod b/vendor/github.com/sirupsen/logrus/go.mod new file mode 100644 index 00000000..94574cc6 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/go.mod @@ -0,0 +1,11 @@ +module github.com/sirupsen/logrus + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.1 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.2.2 + golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 + golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 +) diff --git a/vendor/github.com/sirupsen/logrus/go.sum b/vendor/github.com/sirupsen/logrus/go.sum new file mode 100644 index 00000000..133d34ae --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/sirupsen/logrus/hook_test.go b/vendor/github.com/sirupsen/logrus/hook_test.go new file mode 100644 index 00000000..b9675935 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hook_test.go @@ -0,0 +1,192 @@ +package logrus_test + +import ( + "bytes" + "encoding/json" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/sirupsen/logrus" + . "github.com/sirupsen/logrus/internal/testutils" +) + +type TestHook struct { + Fired bool +} + +func (hook *TestHook) Fire(entry *Entry) error { + hook.Fired = true + return nil +} + +func (hook *TestHook) Levels() []Level { + return []Level{ + TraceLevel, + DebugLevel, + InfoLevel, + WarnLevel, + ErrorLevel, + FatalLevel, + PanicLevel, + } +} + +func TestHookFires(t *testing.T) { + hook := new(TestHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + assert.Equal(t, hook.Fired, false) + + log.Print("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, true) + }) +} + +type ModifyHook struct { +} + +func (hook *ModifyHook) Fire(entry *Entry) error { + entry.Data["wow"] = "whale" + return nil +} + +func (hook *ModifyHook) Levels() []Level { + return []Level{ + TraceLevel, + DebugLevel, + InfoLevel, + WarnLevel, + ErrorLevel, + FatalLevel, + PanicLevel, + } +} + +func TestHookCanModifyEntry(t *testing.T) { + hook := new(ModifyHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.WithField("wow", "elephant").Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["wow"], "whale") + }) +} + +func TestCanFireMultipleHooks(t *testing.T) { + hook1 := new(ModifyHook) + hook2 := new(TestHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook1) + log.Hooks.Add(hook2) + + log.WithField("wow", "elephant").Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["wow"], "whale") + assert.Equal(t, hook2.Fired, true) + }) +} + +type SingleLevelModifyHook struct { + ModifyHook +} + +func (h *SingleLevelModifyHook) Levels() []Level { + return []Level{InfoLevel} +} + +func TestHookEntryIsPristine(t *testing.T) { + l := New() + b := &bytes.Buffer{} + l.Formatter = &JSONFormatter{} + l.Out = b + l.AddHook(&SingleLevelModifyHook{}) + + l.Error("error message") + data := map[string]string{} + err := json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok := data["wow"] + require.False(t, ok) + b.Reset() + + l.Info("error message") + data = map[string]string{} + err = json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok = data["wow"] + require.True(t, ok) + b.Reset() + + l.Error("error message") + data = map[string]string{} + err = json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok = data["wow"] + require.False(t, ok) + b.Reset() +} + +type ErrorHook struct { + Fired bool +} + +func (hook *ErrorHook) Fire(entry *Entry) error { + hook.Fired = true + return nil +} + +func (hook *ErrorHook) Levels() []Level { + return []Level{ + ErrorLevel, + } +} + +func TestErrorHookShouldntFireOnInfo(t *testing.T) { + hook := new(ErrorHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.Info("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, false) + }) +} + +func TestErrorHookShouldFireOnError(t *testing.T) { + hook := new(ErrorHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.Error("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, true) + }) +} + +func TestAddHookRace(t *testing.T) { + var wg sync.WaitGroup + wg.Add(2) + hook := new(ErrorHook) + LogAndAssertJSON(t, func(log *Logger) { + go func() { + defer wg.Done() + log.AddHook(hook) + }() + go func() { + defer wg.Done() + log.Error("test") + }() + wg.Wait() + }, func(fields Fields) { + // the line may have been logged + // before the hook was added, so we can't + // actually assert on the hook + }) +} diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go new file mode 100644 index 00000000..3f151cdc --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks.go @@ -0,0 +1,34 @@ +package logrus + +// A hook to be fired when logging on the logging levels returned from +// `Levels()` on your implementation of the interface. Note that this is not +// fired in a goroutine or a channel with workers, you should handle such +// functionality yourself if your call is non-blocking and you don't wish for +// the logging calls for levels returned from `Levels()` to block. +type Hook interface { + Levels() []Level + Fire(*Entry) error +} + +// Internal type for storing the hooks on a logger instance. +type LevelHooks map[Level][]Hook + +// Add a hook to an instance of logger. This is called with +// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. +func (hooks LevelHooks) Add(hook Hook) { + for _, level := range hook.Levels() { + hooks[level] = append(hooks[level], hook) + } +} + +// Fire all the hooks for the passed level. Used by `entry.log` to fire +// appropriate hooks for a log entry. +func (hooks LevelHooks) Fire(level Level, entry *Entry) error { + for _, hook := range hooks[level] { + if err := hook.Fire(entry); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/README.md b/vendor/github.com/sirupsen/logrus/hooks/syslog/README.md new file mode 100644 index 00000000..1bbc0f72 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/README.md @@ -0,0 +1,39 @@ +# Syslog Hooks for Logrus :walrus: + +## Usage + +```go +import ( + "log/syslog" + "github.com/sirupsen/logrus" + lSyslog "github.com/sirupsen/logrus/hooks/syslog" +) + +func main() { + log := logrus.New() + hook, err := lSyslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + + if err == nil { + log.Hooks.Add(hook) + } +} +``` + +If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following. + +```go +import ( + "log/syslog" + "github.com/sirupsen/logrus" + lSyslog "github.com/sirupsen/logrus/hooks/syslog" +) + +func main() { + log := logrus.New() + hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "") + + if err == nil { + log.Hooks.Add(hook) + } +} +``` diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go new file mode 100644 index 00000000..02b8df38 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go @@ -0,0 +1,55 @@ +// +build !windows,!nacl,!plan9 + +package syslog + +import ( + "fmt" + "log/syslog" + "os" + + "github.com/sirupsen/logrus" +) + +// SyslogHook to send logs via syslog. +type SyslogHook struct { + Writer *syslog.Writer + SyslogNetwork string + SyslogRaddr string +} + +// Creates a hook to be added to an instance of logger. This is called with +// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` +// `if err == nil { log.Hooks.Add(hook) }` +func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { + w, err := syslog.Dial(network, raddr, priority, tag) + return &SyslogHook{w, network, raddr}, err +} + +func (hook *SyslogHook) Fire(entry *logrus.Entry) error { + line, err := entry.String() + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) + return err + } + + switch entry.Level { + case logrus.PanicLevel: + return hook.Writer.Crit(line) + case logrus.FatalLevel: + return hook.Writer.Crit(line) + case logrus.ErrorLevel: + return hook.Writer.Err(line) + case logrus.WarnLevel: + return hook.Writer.Warning(line) + case logrus.InfoLevel: + return hook.Writer.Info(line) + case logrus.DebugLevel, logrus.TraceLevel: + return hook.Writer.Debug(line) + default: + return nil + } +} + +func (hook *SyslogHook) Levels() []logrus.Level { + return logrus.AllLevels +} diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go new file mode 100644 index 00000000..bec6efd5 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go @@ -0,0 +1,29 @@ +// +build !windows,!nacl,!plan9 + +package syslog + +import ( + "log/syslog" + "testing" + + "github.com/sirupsen/logrus" +) + +func TestLocalhostAddAndPrint(t *testing.T) { + log := logrus.New() + hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + + if err != nil { + t.Errorf("Unable to connect to local syslog.") + } + + log.Hooks.Add(hook) + + for _, level := range hook.Levels() { + if len(log.Hooks[level]) != 1 { + t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level])) + } + } + + log.Info("Congratulations!") +} diff --git a/vendor/github.com/sirupsen/logrus/hooks/test/test.go b/vendor/github.com/sirupsen/logrus/hooks/test/test.go new file mode 100644 index 00000000..234a17df --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/test/test.go @@ -0,0 +1,92 @@ +// The Test package is used for testing logrus. It is here for backwards +// compatibility from when logrus' organization was upper-case. Please use +// lower-case logrus and the `null` package instead of this one. +package test + +import ( + "io/ioutil" + "sync" + + "github.com/sirupsen/logrus" +) + +// Hook is a hook designed for dealing with logs in test scenarios. +type Hook struct { + // Entries is an array of all entries that have been received by this hook. + // For safe access, use the AllEntries() method, rather than reading this + // value directly. + Entries []logrus.Entry + mu sync.RWMutex +} + +// NewGlobal installs a test hook for the global logger. +func NewGlobal() *Hook { + + hook := new(Hook) + logrus.AddHook(hook) + + return hook + +} + +// NewLocal installs a test hook for a given local logger. +func NewLocal(logger *logrus.Logger) *Hook { + + hook := new(Hook) + logger.Hooks.Add(hook) + + return hook + +} + +// NewNullLogger creates a discarding logger and installs the test hook. +func NewNullLogger() (*logrus.Logger, *Hook) { + + logger := logrus.New() + logger.Out = ioutil.Discard + + return logger, NewLocal(logger) + +} + +func (t *Hook) Fire(e *logrus.Entry) error { + t.mu.Lock() + defer t.mu.Unlock() + t.Entries = append(t.Entries, *e) + return nil +} + +func (t *Hook) Levels() []logrus.Level { + return logrus.AllLevels +} + +// LastEntry returns the last entry that was logged or nil. +func (t *Hook) LastEntry() *logrus.Entry { + t.mu.RLock() + defer t.mu.RUnlock() + i := len(t.Entries) - 1 + if i < 0 { + return nil + } + return &t.Entries[i] +} + +// AllEntries returns all entries that were logged. +func (t *Hook) AllEntries() []*logrus.Entry { + t.mu.RLock() + defer t.mu.RUnlock() + // Make a copy so the returned value won't race with future log requests + entries := make([]*logrus.Entry, len(t.Entries)) + for i := 0; i < len(t.Entries); i++ { + // Make a copy, for safety + entries[i] = &t.Entries[i] + } + return entries +} + +// Reset removes all Entries from this test hook. +func (t *Hook) Reset() { + t.mu.Lock() + defer t.mu.Unlock() + t.Entries = make([]logrus.Entry, 0) +} diff --git a/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go b/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go new file mode 100644 index 00000000..636bad51 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go @@ -0,0 +1,85 @@ +package test + +import ( + "math/rand" + "sync" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestAllHooks(t *testing.T) { + assert := assert.New(t) + + logger, hook := NewNullLogger() + assert.Nil(hook.LastEntry()) + assert.Equal(0, len(hook.Entries)) + + logger.Error("Hello error") + assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal("Hello error", hook.LastEntry().Message) + assert.Equal(1, len(hook.Entries)) + + logger.Warn("Hello warning") + assert.Equal(logrus.WarnLevel, hook.LastEntry().Level) + assert.Equal("Hello warning", hook.LastEntry().Message) + assert.Equal(2, len(hook.Entries)) + + hook.Reset() + assert.Nil(hook.LastEntry()) + assert.Equal(0, len(hook.Entries)) + + hook = NewGlobal() + + logrus.Error("Hello error") + assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal("Hello error", hook.LastEntry().Message) + assert.Equal(1, len(hook.Entries)) +} + +func TestLoggingWithHooksRace(t *testing.T) { + + rand.Seed(time.Now().Unix()) + unlocker := rand.Int() % 100 + + assert := assert.New(t) + logger, hook := NewNullLogger() + + var wgOne, wgAll sync.WaitGroup + wgOne.Add(1) + wgAll.Add(100) + + for i := 0; i < 100; i++ { + go func(i int) { + logger.Info("info") + wgAll.Done() + if i == unlocker { + wgOne.Done() + } + }(i) + } + + wgOne.Wait() + + assert.Equal(logrus.InfoLevel, hook.LastEntry().Level) + assert.Equal("info", hook.LastEntry().Message) + + wgAll.Wait() + + entries := hook.AllEntries() + assert.Equal(100, len(entries)) +} + +func TestFatalWithAlternateExit(t *testing.T) { + assert := assert.New(t) + + logger, hook := NewNullLogger() + logger.ExitFunc = func(code int) {} + + logger.Fatal("something went very wrong") + assert.Equal(logrus.FatalLevel, hook.LastEntry().Level) + assert.Equal("something went very wrong", hook.LastEntry().Message) + assert.Equal(1, len(hook.Entries)) +} diff --git a/vendor/github.com/sirupsen/logrus/internal/testutils/testutils.go b/vendor/github.com/sirupsen/logrus/internal/testutils/testutils.go new file mode 100644 index 00000000..20bc3c3b --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/internal/testutils/testutils.go @@ -0,0 +1,58 @@ +package testutils + +import ( + "bytes" + "encoding/json" + "strconv" + "strings" + "testing" + + . "github.com/sirupsen/logrus" + + "github.com/stretchr/testify/require" +) + +func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + log(logger) + + err := json.Unmarshal(buffer.Bytes(), &fields) + require.Nil(t, err) + + assertions(fields) +} + +func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) { + var buffer bytes.Buffer + + logger := New() + logger.Out = &buffer + logger.Formatter = &TextFormatter{ + DisableColors: true, + } + + log(logger) + + fields := make(map[string]string) + for _, kv := range strings.Split(buffer.String(), " ") { + if !strings.Contains(kv, "=") { + continue + } + kvArr := strings.Split(kv, "=") + key := strings.TrimSpace(kvArr[0]) + val := kvArr[1] + if kvArr[1][0] == '"' { + var err error + val, err = strconv.Unquote(val) + require.NoError(t, err) + } + fields[key] = val + } + assertions(fields) +} diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go new file mode 100644 index 00000000..26057535 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -0,0 +1,105 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type fieldKey string + +// FieldMap allows customization of the key names for default fields. +type FieldMap map[fieldKey]string + +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + +// JSONFormatter formats logs into parsable json +type JSONFormatter struct { + // TimestampFormat sets the format used for marshaling timestamps. + TimestampFormat string + + // DisableTimestamp allows disabling automatic timestamps in output + DisableTimestamp bool + + // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. + DataKey string + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message", + // FieldKeyFunc: "@caller", + // }, + // } + FieldMap FieldMap + + // PrettyPrint will indent all json logs + PrettyPrint bool +} + +// Format renders a single log entry +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields, len(entry.Data)+4) + for k, v := range entry.Data { + switch v := v.(type) { + case error: + // Otherwise errors are ignored by `encoding/json` + // https://github.com/sirupsen/logrus/issues/137 + data[k] = v.Error() + default: + data[k] = v + } + } + + if f.DataKey != "" { + newData := make(Fields, 4) + newData[f.DataKey] = data + data = newData + } + + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + + if entry.err != "" { + data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err + } + if !f.DisableTimestamp { + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + } + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() + if entry.HasCaller() { + data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function + data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + encoder := json.NewEncoder(b) + if f.PrettyPrint { + encoder.SetIndent("", " ") + } + if err := encoder.Encode(data); err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + + return b.Bytes(), nil +} diff --git a/vendor/github.com/sirupsen/logrus/json_formatter_test.go b/vendor/github.com/sirupsen/logrus/json_formatter_test.go new file mode 100644 index 00000000..695c36e5 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/json_formatter_test.go @@ -0,0 +1,346 @@ +package logrus + +import ( + "encoding/json" + "errors" + "fmt" + "runtime" + "strings" + "testing" +) + +func TestErrorNotLost(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("error", errors.New("wild walrus"))) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["error"] != "wild walrus" { + t.Fatal("Error field not set") + } +} + +func TestErrorNotLostOnFieldNotNamedError(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("omg", errors.New("wild walrus"))) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["omg"] != "wild walrus" { + t.Fatal("Error field not set") + } +} + +func TestFieldClashWithTime(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("time", "right now!")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.time"] != "right now!" { + t.Fatal("fields.time not set to original time field") + } + + if entry["time"] != "0001-01-01T00:00:00Z" { + t.Fatal("time field not set to current time, was: ", entry["time"]) + } +} + +func TestFieldClashWithMsg(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("msg", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.msg"] != "something" { + t.Fatal("fields.msg not set to original msg field") + } +} + +func TestFieldClashWithLevel(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.level"] != "something" { + t.Fatal("fields.level not set to original level field") + } +} + +func TestFieldClashWithRemappedFields(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyTime: "@timestamp", + FieldKeyLevel: "@level", + FieldKeyMsg: "@message", + }, + } + + b, err := formatter.Format(WithFields(Fields{ + "@timestamp": "@timestamp", + "@level": "@level", + "@message": "@message", + "timestamp": "timestamp", + "level": "level", + "msg": "msg", + })) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + for _, field := range []string{"timestamp", "level", "msg"} { + if entry[field] != field { + t.Errorf("Expected field %v to be untouched; got %v", field, entry[field]) + } + + remappedKey := fmt.Sprintf("fields.%s", field) + if remapped, ok := entry[remappedKey]; ok { + t.Errorf("Expected %s to be empty; got %v", remappedKey, remapped) + } + } + + for _, field := range []string{"@timestamp", "@level", "@message"} { + if entry[field] == field { + t.Errorf("Expected field %v to be mapped to an Entry value", field) + } + + remappedKey := fmt.Sprintf("fields.%s", field) + if remapped, ok := entry[remappedKey]; ok { + if remapped != field { + t.Errorf("Expected field %v to be copied to %s; got %v", field, remappedKey, remapped) + } + } else { + t.Errorf("Expected field %v to be copied to %s; was absent", field, remappedKey) + } + } +} + +func TestFieldsInNestedDictionary(t *testing.T) { + formatter := &JSONFormatter{ + DataKey: "args", + } + + logEntry := WithFields(Fields{ + "level": "level", + "test": "test", + }) + logEntry.Level = InfoLevel + + b, err := formatter.Format(logEntry) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + args := entry["args"].(map[string]interface{}) + + for _, field := range []string{"test", "level"} { + if value, present := args[field]; !present || value != field { + t.Errorf("Expected field %v to be present under 'args'; untouched", field) + } + } + + for _, field := range []string{"test", "fields.level"} { + if _, present := entry[field]; present { + t.Errorf("Expected field %v not to be present at top level", field) + } + } + + // with nested object, "level" shouldn't clash + if entry["level"] != "info" { + t.Errorf("Expected 'level' field to contain 'info'") + } +} + +func TestJSONEntryEndsWithNewline(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + if b[len(b)-1] != '\n' { + t.Fatal("Expected JSON log entry to end with a newline") + } +} + +func TestJSONMessageKey(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyMsg: "message", + }, + } + + b, err := formatter.Format(&Entry{Message: "oh hai"}) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) { + t.Fatal("Expected JSON to format message key") + } +} + +func TestJSONLevelKey(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyLevel: "somelevel", + }, + } + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, "somelevel") { + t.Fatal("Expected JSON to format level key") + } +} + +func TestJSONTimeKey(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyTime: "timeywimey", + }, + } + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, "timeywimey") { + t.Fatal("Expected JSON to format time key") + } +} + +func TestFieldDoesNotClashWithCaller(t *testing.T) { + SetReportCaller(false) + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("func", "howdy pardner")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["func"] != "howdy pardner" { + t.Fatal("func field replaced when ReportCaller=false") + } +} + +func TestFieldClashWithCaller(t *testing.T) { + SetReportCaller(true) + formatter := &JSONFormatter{} + e := WithField("func", "howdy pardner") + e.Caller = &runtime.Frame{Function: "somefunc"} + b, err := formatter.Format(e) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.func"] != "howdy pardner" { + t.Fatalf("fields.func not set to original func field when ReportCaller=true (got '%s')", + entry["fields.func"]) + } + + if entry["func"] != "somefunc" { + t.Fatalf("func not set as expected when ReportCaller=true (got '%s')", + entry["func"]) + } + + SetReportCaller(false) // return to default value +} + +func TestJSONDisableTimestamp(t *testing.T) { + formatter := &JSONFormatter{ + DisableTimestamp: true, + } + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if strings.Contains(s, FieldKeyTime) { + t.Error("Did not prevent timestamp", s) + } +} + +func TestJSONEnableTimestamp(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, FieldKeyTime) { + t.Error("Timestamp not present", s) + } +} diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go new file mode 100644 index 00000000..5ceca0ea --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -0,0 +1,415 @@ +package logrus + +import ( + "io" + "os" + "sync" + "sync/atomic" + "time" +) + +type Logger struct { + // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a + // file, or leave it default which is `os.Stderr`. You can also set this to + // something more adventurous, such as logging to Kafka. + Out io.Writer + // Hooks for the logger instance. These allow firing events based on logging + // levels and log entries. For example, to send errors to an error tracking + // service, log to StatsD or dump the core on fatal errors. + Hooks LevelHooks + // All log entries pass through the formatter before logged to Out. The + // included formatters are `TextFormatter` and `JSONFormatter` for which + // TextFormatter is the default. In development (when a TTY is attached) it + // logs with colors, but to a file it wouldn't. You can easily implement your + // own that implements the `Formatter` interface, see the `README` or included + // formatters for examples. + Formatter Formatter + + // Flag for whether to log caller info (off by default) + ReportCaller bool + + // The logging level the logger should log at. This is typically (and defaults + // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be + // logged. + Level Level + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap + // Reusable empty entry + entryPool sync.Pool + // Function to exit the application, defaults to `os.Exit()` + ExitFunc exitFunc +} + +type exitFunc func(int) + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true +} + +// Creates a new logger. Configuration should be set by changing `Formatter`, +// `Out` and `Hooks` directly on the default logger instance. You can also just +// instantiate your own: +// +// var log = &Logger{ +// Out: os.Stderr, +// Formatter: new(JSONFormatter), +// Hooks: make(LevelHooks), +// Level: logrus.DebugLevel, +// } +// +// It's recommended to make this a global instance called `log`. +func New() *Logger { + return &Logger{ + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, + ExitFunc: os.Exit, + ReportCaller: false, + } +} + +func (logger *Logger) newEntry() *Entry { + entry, ok := logger.entryPool.Get().(*Entry) + if ok { + return entry + } + return NewEntry(logger) +} + +func (logger *Logger) releaseEntry(entry *Entry) { + entry.Data = map[string]interface{}{} + logger.entryPool.Put(entry) +} + +// Adds a field to the log entry, note that it doesn't log until you call +// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. +// If you want multiple fields, use `WithFields`. +func (logger *Logger) WithField(key string, value interface{}) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithField(key, value) +} + +// Adds a struct of fields to the log entry. All it does is call `WithField` for +// each `Field`. +func (logger *Logger) WithFields(fields Fields) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithFields(fields) +} + +// Add an error as single field to the log entry. All it does is call +// `WithError` for the given `error`. +func (logger *Logger) WithError(err error) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithError(err) +} + +// Overrides the time of the log entry. +func (logger *Logger) WithTime(t time.Time) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithTime(t) +} + +func (logger *Logger) Tracef(format string, args ...interface{}) { + if logger.IsLevelEnabled(TraceLevel) { + entry := logger.newEntry() + entry.Tracef(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Debugf(format string, args ...interface{}) { + if logger.IsLevelEnabled(DebugLevel) { + entry := logger.newEntry() + entry.Debugf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Infof(format string, args ...interface{}) { + if logger.IsLevelEnabled(InfoLevel) { + entry := logger.newEntry() + entry.Infof(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Printf(format string, args ...interface{}) { + entry := logger.newEntry() + entry.Printf(format, args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnf(format string, args ...interface{}) { + if logger.IsLevelEnabled(WarnLevel) { + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Warningf(format string, args ...interface{}) { + if logger.IsLevelEnabled(WarnLevel) { + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Errorf(format string, args ...interface{}) { + if logger.IsLevelEnabled(ErrorLevel) { + entry := logger.newEntry() + entry.Errorf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Fatalf(format string, args ...interface{}) { + if logger.IsLevelEnabled(FatalLevel) { + entry := logger.newEntry() + entry.Fatalf(format, args...) + logger.releaseEntry(entry) + } + logger.Exit(1) +} + +func (logger *Logger) Panicf(format string, args ...interface{}) { + if logger.IsLevelEnabled(PanicLevel) { + entry := logger.newEntry() + entry.Panicf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Trace(args ...interface{}) { + if logger.IsLevelEnabled(TraceLevel) { + entry := logger.newEntry() + entry.Trace(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Debug(args ...interface{}) { + if logger.IsLevelEnabled(DebugLevel) { + entry := logger.newEntry() + entry.Debug(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Info(args ...interface{}) { + if logger.IsLevelEnabled(InfoLevel) { + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Print(args ...interface{}) { + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warn(args ...interface{}) { + if logger.IsLevelEnabled(WarnLevel) { + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Warning(args ...interface{}) { + if logger.IsLevelEnabled(WarnLevel) { + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Error(args ...interface{}) { + if logger.IsLevelEnabled(ErrorLevel) { + entry := logger.newEntry() + entry.Error(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Fatal(args ...interface{}) { + if logger.IsLevelEnabled(FatalLevel) { + entry := logger.newEntry() + entry.Fatal(args...) + logger.releaseEntry(entry) + } + logger.Exit(1) +} + +func (logger *Logger) Panic(args ...interface{}) { + if logger.IsLevelEnabled(PanicLevel) { + entry := logger.newEntry() + entry.Panic(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Traceln(args ...interface{}) { + if logger.IsLevelEnabled(TraceLevel) { + entry := logger.newEntry() + entry.Traceln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Debugln(args ...interface{}) { + if logger.IsLevelEnabled(DebugLevel) { + entry := logger.newEntry() + entry.Debugln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Infoln(args ...interface{}) { + if logger.IsLevelEnabled(InfoLevel) { + entry := logger.newEntry() + entry.Infoln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Println(args ...interface{}) { + entry := logger.newEntry() + entry.Println(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnln(args ...interface{}) { + if logger.IsLevelEnabled(WarnLevel) { + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Warningln(args ...interface{}) { + if logger.IsLevelEnabled(WarnLevel) { + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Errorln(args ...interface{}) { + if logger.IsLevelEnabled(ErrorLevel) { + entry := logger.newEntry() + entry.Errorln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Fatalln(args ...interface{}) { + if logger.IsLevelEnabled(FatalLevel) { + entry := logger.newEntry() + entry.Fatalln(args...) + logger.releaseEntry(entry) + } + logger.Exit(1) +} + +func (logger *Logger) Panicln(args ...interface{}) { + if logger.IsLevelEnabled(PanicLevel) { + entry := logger.newEntry() + entry.Panicln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Exit(code int) { + runHandlers() + if logger.ExitFunc == nil { + logger.ExitFunc = os.Exit + } + logger.ExitFunc(code) +} + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} + +func (logger *Logger) level() Level { + return Level(atomic.LoadUint32((*uint32)(&logger.Level))) +} + +// SetLevel sets the logger level. +func (logger *Logger) SetLevel(level Level) { + atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) +} + +// GetLevel returns the logger level. +func (logger *Logger) GetLevel() Level { + return logger.level() +} + +// AddHook adds a hook to the logger hooks. +func (logger *Logger) AddHook(hook Hook) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Hooks.Add(hook) +} + +// IsLevelEnabled checks if the log level of the logger is greater than the level param +func (logger *Logger) IsLevelEnabled(level Level) bool { + return logger.level() >= level +} + +// SetFormatter sets the logger formatter. +func (logger *Logger) SetFormatter(formatter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Formatter = formatter +} + +// SetOutput sets the logger output. +func (logger *Logger) SetOutput(output io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = output +} + +func (logger *Logger) SetReportCaller(reportCaller bool) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.ReportCaller = reportCaller +} + +// ReplaceHooks replaces the logger hooks and returns the old ones +func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { + logger.mu.Lock() + oldHooks := logger.Hooks + logger.Hooks = hooks + logger.mu.Unlock() + return oldHooks +} diff --git a/vendor/github.com/sirupsen/logrus/logger_bench_test.go b/vendor/github.com/sirupsen/logrus/logger_bench_test.go new file mode 100644 index 00000000..f0a76843 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logger_bench_test.go @@ -0,0 +1,85 @@ +package logrus + +import ( + "io/ioutil" + "os" + "testing" +) + +// smallFields is a small size data set for benchmarking +var loggerFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", +} + +func BenchmarkDummyLogger(b *testing.B) { + nullf, err := os.OpenFile("/dev/null", os.O_WRONLY, 0666) + if err != nil { + b.Fatalf("%v", err) + } + defer nullf.Close() + doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields) +} + +func BenchmarkDummyLoggerNoLock(b *testing.B) { + nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + b.Fatalf("%v", err) + } + defer nullf.Close() + doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields) +} + +func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) { + logger := Logger{ + Out: out, + Level: InfoLevel, + Formatter: formatter, + } + entry := logger.WithFields(fields) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + entry.Info("aaa") + } + }) +} + +func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) { + logger := Logger{ + Out: out, + Level: InfoLevel, + Formatter: formatter, + } + logger.SetNoLock() + entry := logger.WithFields(fields) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + entry.Info("aaa") + } + }) +} + +func BenchmarkLoggerJSONFormatter(b *testing.B) { + doLoggerBenchmarkWithFormatter(b, &JSONFormatter{}) +} + +func BenchmarkLoggerTextFormatter(b *testing.B) { + doLoggerBenchmarkWithFormatter(b, &TextFormatter{}) +} + +func doLoggerBenchmarkWithFormatter(b *testing.B, f Formatter) { + b.SetParallelism(100) + log := New() + log.Formatter = f + log.Out = ioutil.Discard + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + log. + WithField("foo1", "bar1"). + WithField("foo2", "bar2"). + Info("this is a dummy log") + } + }) +} diff --git a/vendor/github.com/sirupsen/logrus/logger_test.go b/vendor/github.com/sirupsen/logrus/logger_test.go new file mode 100644 index 00000000..73ba4506 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logger_test.go @@ -0,0 +1,42 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFieldValueError(t *testing.T) { + buf := &bytes.Buffer{} + l := &Logger{ + Out: buf, + Formatter: new(JSONFormatter), + Hooks: make(LevelHooks), + Level: DebugLevel, + } + l.WithField("func", func() {}).Info("test") + fmt.Println(buf.String()) + var data map[string]interface{} + json.Unmarshal(buf.Bytes(), &data) + _, ok := data[FieldKeyLogrusError] + require.True(t, ok) +} + +func TestNoFieldValueError(t *testing.T) { + buf := &bytes.Buffer{} + l := &Logger{ + Out: buf, + Formatter: new(JSONFormatter), + Hooks: make(LevelHooks), + Level: DebugLevel, + } + l.WithField("str", "str").Info("test") + fmt.Println(buf.String()) + var data map[string]interface{} + json.Unmarshal(buf.Bytes(), &data) + _, ok := data[FieldKeyLogrusError] + require.False(t, ok) +} diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go new file mode 100644 index 00000000..4ef45186 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -0,0 +1,178 @@ +package logrus + +import ( + "fmt" + "log" + "strings" +) + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Level type +type Level uint32 + +// Convert the Level to a string. E.g. PanicLevel becomes "panic". +func (level Level) String() string { + switch level { + case TraceLevel: + return "trace" + case DebugLevel: + return "debug" + case InfoLevel: + return "info" + case WarnLevel: + return "warning" + case ErrorLevel: + return "error" + case FatalLevel: + return "fatal" + case PanicLevel: + return "panic" + } + + return "unknown" +} + +// ParseLevel takes a string level and returns the Logrus log level constant. +func ParseLevel(lvl string) (Level, error) { + switch strings.ToLower(lvl) { + case "panic": + return PanicLevel, nil + case "fatal": + return FatalLevel, nil + case "error": + return ErrorLevel, nil + case "warn", "warning": + return WarnLevel, nil + case "info": + return InfoLevel, nil + case "debug": + return DebugLevel, nil + case "trace": + return TraceLevel, nil + } + + var l Level + return l, fmt.Errorf("not a valid logrus Level: %q", lvl) +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (level *Level) UnmarshalText(text []byte) error { + l, err := ParseLevel(string(text)) + if err != nil { + return err + } + + *level = Level(l) + + return nil +} + +// A constant exposing all logging levels +var AllLevels = []Level{ + PanicLevel, + FatalLevel, + ErrorLevel, + WarnLevel, + InfoLevel, + DebugLevel, + TraceLevel, +} + +// These are the different logging levels. You can set the logging level to log +// on your instance of logger, obtained with `logrus.New()`. +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel Level = iota + // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel + // TraceLevel level. Designates finer-grained informational events than the Debug. + TraceLevel +) + +// Won't compile if StdLogger can't be realized by a log.Logger +var ( + _ StdLogger = &log.Logger{} + _ StdLogger = &Entry{} + _ StdLogger = &Logger{} +) + +// StdLogger is what your logrus-enabled library should take, that way +// it'll accept a stdlib logger and a logrus logger. There's no standard +// interface, this is the closest we get, unfortunately. +type StdLogger interface { + Print(...interface{}) + Printf(string, ...interface{}) + Println(...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + Fatalln(...interface{}) + + Panic(...interface{}) + Panicf(string, ...interface{}) + Panicln(...interface{}) +} + +// The FieldLogger interface generalizes the Entry and Logger types +type FieldLogger interface { + WithField(key string, value interface{}) *Entry + WithFields(fields Fields) *Entry + WithError(err error) *Entry + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Printf(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Warningf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) + Panicf(format string, args ...interface{}) + + Debug(args ...interface{}) + Info(args ...interface{}) + Print(args ...interface{}) + Warn(args ...interface{}) + Warning(args ...interface{}) + Error(args ...interface{}) + Fatal(args ...interface{}) + Panic(args ...interface{}) + + Debugln(args ...interface{}) + Infoln(args ...interface{}) + Println(args ...interface{}) + Warnln(args ...interface{}) + Warningln(args ...interface{}) + Errorln(args ...interface{}) + Fatalln(args ...interface{}) + Panicln(args ...interface{}) + + // IsDebugEnabled() bool + // IsInfoEnabled() bool + // IsWarnEnabled() bool + // IsErrorEnabled() bool + // IsFatalEnabled() bool + // IsPanicEnabled() bool +} + +// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is +// here for consistancy. Do not use. Use Logger or Entry instead. +type Ext1FieldLogger interface { + FieldLogger + Tracef(format string, args ...interface{}) + Trace(args ...interface{}) + Traceln(args ...interface{}) +} diff --git a/vendor/github.com/sirupsen/logrus/logrus_test.go b/vendor/github.com/sirupsen/logrus/logrus_test.go new file mode 100644 index 00000000..b12d71c8 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logrus_test.go @@ -0,0 +1,716 @@ +package logrus_test + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/sirupsen/logrus" + . "github.com/sirupsen/logrus/internal/testutils" +) + +// TestReportCaller verifies that when ReportCaller is set, the 'func' field +// is added, and when it is unset it is not set or modified +// Verify that functions within the Logrus package aren't considered when +// discovering the caller. +func TestReportCallerWhenConfigured(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.ReportCaller = false + log.Print("testNoCaller") + }, func(fields Fields) { + assert.Equal(t, "testNoCaller", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Equal(t, nil, fields["func"]) + }) + + LogAndAssertJSON(t, func(log *Logger) { + log.ReportCaller = true + log.Print("testWithCaller") + }, func(fields Fields) { + assert.Equal(t, "testWithCaller", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Equal(t, + "github.com/sirupsen/logrus_test.TestReportCallerWhenConfigured.func3", fields["func"]) + }) +} + +func logSomething(t *testing.T, message string) Fields { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + logger.ReportCaller = true + + entry := logger.WithFields(Fields{ + "foo": "bar", + }) + + entry.Info(message) + + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + return fields +} + +// TestReportCallerHelperDirect - verify reference when logging from a regular function +func TestReportCallerHelperDirect(t *testing.T) { + fields := logSomething(t, "direct") + + assert.Equal(t, "direct", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"]) +} + +// TestReportCallerHelperDirect - verify reference when logging from a function called via pointer +func TestReportCallerHelperViaPointer(t *testing.T) { + fptr := logSomething + fields := fptr(t, "via pointer") + + assert.Equal(t, "via pointer", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"]) +} + +func TestPrint(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Print("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + }) +} + +func TestInfo(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + }) +} + +func TestWarn(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Warn("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "warning", fields["level"]) + }) +} + +func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln("test", "test") + }, func(fields Fields) { + assert.Equal(t, "test test", fields["msg"]) + }) +} + +func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln("test", 10) + }, func(fields Fields) { + assert.Equal(t, "test 10", fields["msg"]) + }) +} + +func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln(10, 10) + }, func(fields Fields) { + assert.Equal(t, "10 10", fields["msg"]) + }) +} + +func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln(10, 10) + }, func(fields Fields) { + assert.Equal(t, "10 10", fields["msg"]) + }) +} + +func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test", 10) + }, func(fields Fields) { + assert.Equal(t, "test10", fields["msg"]) + }) +} + +func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test", "test") + }, func(fields Fields) { + assert.Equal(t, "testtest", fields["msg"]) + }) +} + +func TestWithFieldsShouldAllowAssignments(t *testing.T) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + localLog := logger.WithFields(Fields{ + "key1": "value1", + }) + + localLog.WithField("key2", "value2").Info("test") + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + assert.Equal(t, "value2", fields["key2"]) + assert.Equal(t, "value1", fields["key1"]) + + buffer = bytes.Buffer{} + fields = Fields{} + localLog.Info("test") + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + _, ok := fields["key2"] + assert.Equal(t, false, ok) + assert.Equal(t, "value1", fields["key1"]) +} + +func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("msg", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + }) +} + +func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("msg", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "hello", fields["fields.msg"]) + }) +} + +func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("time", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, "hello", fields["fields.time"]) + }) +} + +func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("level", 1).Info("test") + }, func(fields Fields) { + assert.Equal(t, "info", fields["level"]) + assert.Equal(t, 1.0, fields["fields.level"]) // JSON has floats only + }) +} + +func TestDefaultFieldsAreNotPrefixed(t *testing.T) { + LogAndAssertText(t, func(log *Logger) { + ll := log.WithField("herp", "derp") + ll.Info("hello") + ll.Info("bye") + }, func(fields map[string]string) { + for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} { + if _, ok := fields[fieldName]; ok { + t.Fatalf("should not have prefixed %q: %v", fieldName, fields) + } + } + }) +} + +func TestWithTimeShouldOverrideTime(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithTime(now).Info("foobar") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(time.RFC3339)) + }) +} + +func TestWithTimeShouldNotOverrideFields(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("herp", "derp").WithTime(now).Info("blah") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(time.RFC3339)) + assert.Equal(t, fields["herp"], "derp") + }) +} + +func TestWithFieldShouldNotOverrideTime(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithTime(now).WithField("herp", "derp").Info("blah") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(time.RFC3339)) + assert.Equal(t, fields["herp"], "derp") + }) +} + +func TestTimeOverrideMultipleLogs(t *testing.T) { + var buffer bytes.Buffer + var firstFields, secondFields Fields + + logger := New() + logger.Out = &buffer + formatter := new(JSONFormatter) + formatter.TimestampFormat = time.StampMilli + logger.Formatter = formatter + + llog := logger.WithField("herp", "derp") + llog.Info("foo") + + err := json.Unmarshal(buffer.Bytes(), &firstFields) + assert.NoError(t, err, "should have decoded first message") + + buffer.Reset() + + time.Sleep(10 * time.Millisecond) + llog.Info("bar") + + err = json.Unmarshal(buffer.Bytes(), &secondFields) + assert.NoError(t, err, "should have decoded second message") + + assert.NotEqual(t, firstFields["time"], secondFields["time"], "timestamps should not be equal") +} + +func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { + + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + llog := logger.WithField("context", "eating raw fish") + + llog.Info("looks delicious") + + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded first message") + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") + assert.Equal(t, fields["msg"], "looks delicious") + assert.Equal(t, fields["context"], "eating raw fish") + + buffer.Reset() + + llog.Warn("omg it is!") + + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded second message") + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") + assert.Equal(t, "omg it is!", fields["msg"]) + assert.Equal(t, "eating raw fish", fields["context"]) + assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") + +} + +func TestNestedLoggingReportsCorrectCaller(t *testing.T) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + logger.ReportCaller = true + + llog := logger.WithField("context", "eating raw fish") + + llog.Info("looks delicious") + + err := json.Unmarshal(buffer.Bytes(), &fields) + require.NoError(t, err, "should have decoded first message") + assert.Equal(t, 6, len(fields), "should have msg/time/level/func/context fields") + assert.Equal(t, "looks delicious", fields["msg"]) + assert.Equal(t, "eating raw fish", fields["context"]) + assert.Equal(t, + "github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"]) + cwd, err := os.Getwd() + require.NoError(t, err) + assert.Equal(t, filepath.ToSlash(cwd+"/logrus_test.go:340"), filepath.ToSlash(fields["file"].(string))) + + buffer.Reset() + + logger.WithFields(Fields{ + "Clyde": "Stubblefield", + }).WithFields(Fields{ + "Jab'o": "Starks", + }).WithFields(Fields{ + "uri": "https://www.youtube.com/watch?v=V5DTznu-9v0", + }).WithFields(Fields{ + "func": "y drummer", + }).WithFields(Fields{ + "James": "Brown", + }).Print("The hardest workin' man in show business") + + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded second message") + assert.Equal(t, 11, len(fields), "should have all builtin fields plus foo,bar,baz,...") + assert.Equal(t, "Stubblefield", fields["Clyde"]) + assert.Equal(t, "Starks", fields["Jab'o"]) + assert.Equal(t, "https://www.youtube.com/watch?v=V5DTznu-9v0", fields["uri"]) + assert.Equal(t, "y drummer", fields["fields.func"]) + assert.Equal(t, "Brown", fields["James"]) + assert.Equal(t, "The hardest workin' man in show business", fields["msg"]) + assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") + assert.Equal(t, + "github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"]) + require.NoError(t, err) + assert.Equal(t, filepath.ToSlash(cwd+"/logrus_test.go:365"), filepath.ToSlash(fields["file"].(string))) + + logger.ReportCaller = false // return to default value +} + +func logLoop(iterations int, reportCaller bool) { + var buffer bytes.Buffer + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + logger.ReportCaller = reportCaller + + for i := 0; i < iterations; i++ { + logger.Infof("round %d of %d", i, iterations) + } +} + +// Assertions for upper bounds to reporting overhead +func TestCallerReportingOverhead(t *testing.T) { + iterations := 5000 + before := time.Now() + logLoop(iterations, false) + during := time.Now() + logLoop(iterations, true) + after := time.Now() + + elapsedNotReporting := during.Sub(before).Nanoseconds() + elapsedReporting := after.Sub(during).Nanoseconds() + + maxDelta := 1 * time.Second + assert.WithinDuration(t, during, before, maxDelta, + "%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)", + iterations, maxDelta.Seconds(), elapsedNotReporting) + assert.WithinDuration(t, after, during, maxDelta, + "%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)", + iterations, maxDelta.Seconds(), elapsedReporting) +} + +// benchmarks for both with and without caller-function reporting +func BenchmarkWithoutCallerTracing(b *testing.B) { + for i := 0; i < b.N; i++ { + logLoop(1000, false) + } +} + +func BenchmarkWithCallerTracing(b *testing.B) { + for i := 0; i < b.N; i++ { + logLoop(1000, true) + } +} + +func TestConvertLevelToString(t *testing.T) { + assert.Equal(t, "trace", TraceLevel.String()) + assert.Equal(t, "debug", DebugLevel.String()) + assert.Equal(t, "info", InfoLevel.String()) + assert.Equal(t, "warning", WarnLevel.String()) + assert.Equal(t, "error", ErrorLevel.String()) + assert.Equal(t, "fatal", FatalLevel.String()) + assert.Equal(t, "panic", PanicLevel.String()) +} + +func TestParseLevel(t *testing.T) { + l, err := ParseLevel("panic") + assert.Nil(t, err) + assert.Equal(t, PanicLevel, l) + + l, err = ParseLevel("PANIC") + assert.Nil(t, err) + assert.Equal(t, PanicLevel, l) + + l, err = ParseLevel("fatal") + assert.Nil(t, err) + assert.Equal(t, FatalLevel, l) + + l, err = ParseLevel("FATAL") + assert.Nil(t, err) + assert.Equal(t, FatalLevel, l) + + l, err = ParseLevel("error") + assert.Nil(t, err) + assert.Equal(t, ErrorLevel, l) + + l, err = ParseLevel("ERROR") + assert.Nil(t, err) + assert.Equal(t, ErrorLevel, l) + + l, err = ParseLevel("warn") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("WARN") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("warning") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("WARNING") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("info") + assert.Nil(t, err) + assert.Equal(t, InfoLevel, l) + + l, err = ParseLevel("INFO") + assert.Nil(t, err) + assert.Equal(t, InfoLevel, l) + + l, err = ParseLevel("debug") + assert.Nil(t, err) + assert.Equal(t, DebugLevel, l) + + l, err = ParseLevel("DEBUG") + assert.Nil(t, err) + assert.Equal(t, DebugLevel, l) + + l, err = ParseLevel("trace") + assert.Nil(t, err) + assert.Equal(t, TraceLevel, l) + + l, err = ParseLevel("TRACE") + assert.Nil(t, err) + assert.Equal(t, TraceLevel, l) + + l, err = ParseLevel("invalid") + assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) +} + +func TestUnmarshalText(t *testing.T) { + var u Level + for _, level := range AllLevels { + t.Run(level.String(), func(t *testing.T) { + assert.NoError(t, u.UnmarshalText([]byte(level.String()))) + assert.Equal(t, level, u) + }) + } + t.Run("invalid", func(t *testing.T) { + assert.Error(t, u.UnmarshalText([]byte("invalid"))) + }) +} + +func TestGetSetLevelRace(t *testing.T) { + wg := sync.WaitGroup{} + for i := 0; i < 100; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + if i%2 == 0 { + SetLevel(InfoLevel) + } else { + GetLevel() + } + }(i) + + } + wg.Wait() +} + +func TestLoggingRace(t *testing.T) { + logger := New() + + var wg sync.WaitGroup + wg.Add(100) + + for i := 0; i < 100; i++ { + go func() { + logger.Info("info") + wg.Done() + }() + } + wg.Wait() +} + +func TestLoggingRaceWithHooksOnEntry(t *testing.T) { + logger := New() + hook := new(ModifyHook) + logger.AddHook(hook) + entry := logger.WithField("context", "clue") + + var wg sync.WaitGroup + wg.Add(100) + + for i := 0; i < 100; i++ { + go func() { + entry.Info("info") + wg.Done() + }() + } + wg.Wait() +} + +func TestReplaceHooks(t *testing.T) { + old, cur := &TestHook{}, &TestHook{} + + logger := New() + logger.SetOutput(ioutil.Discard) + logger.AddHook(old) + + hooks := make(LevelHooks) + hooks.Add(cur) + replaced := logger.ReplaceHooks(hooks) + + logger.Info("test") + + assert.Equal(t, old.Fired, false) + assert.Equal(t, cur.Fired, true) + + logger.ReplaceHooks(replaced) + logger.Info("test") + assert.Equal(t, old.Fired, true) +} + +// Compile test +func TestLogrusInterfaces(t *testing.T) { + var buffer bytes.Buffer + // This verifies FieldLogger and Ext1FieldLogger work as designed. + // Please don't use them. Use Logger and Entry directly. + fn := func(xl Ext1FieldLogger) { + var l FieldLogger = xl + b := l.WithField("key", "value") + b.Debug("Test") + } + // test logger + logger := New() + logger.Out = &buffer + fn(logger) + + // test Entry + e := logger.WithField("another", "value") + fn(e) +} + +// Implements io.Writer using channels for synchronization, so we can wait on +// the Entry.Writer goroutine to write in a non-racey way. This does assume that +// there is a single call to Logger.Out for each message. +type channelWriter chan []byte + +func (cw channelWriter) Write(p []byte) (int, error) { + cw <- p + return len(p), nil +} + +func TestEntryWriter(t *testing.T) { + cw := channelWriter(make(chan []byte, 1)) + log := New() + log.Out = cw + log.Formatter = new(JSONFormatter) + log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n")) + + bs := <-cw + var fields Fields + err := json.Unmarshal(bs, &fields) + assert.Nil(t, err) + assert.Equal(t, fields["foo"], "bar") + assert.Equal(t, fields["level"], "warning") +} + +func TestLogLevelEnabled(t *testing.T) { + log := New() + log.SetLevel(PanicLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, false, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(FatalLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(ErrorLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(WarnLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(InfoLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(DebugLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(TraceLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, true, log.IsLevelEnabled(TraceLevel)) +} + +func TestReportCallerOnTextFormatter(t *testing.T) { + l := New() + + l.Formatter.(*TextFormatter).ForceColors = true + l.Formatter.(*TextFormatter).DisableColors = false + l.WithFields(Fields{"func": "func", "file": "file"}).Info("test") + + l.Formatter.(*TextFormatter).ForceColors = false + l.Formatter.(*TextFormatter).DisableColors = true + l.WithFields(Fields{"func": "func", "file": "file"}).Info("test") +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go new file mode 100644 index 00000000..2403de98 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go @@ -0,0 +1,11 @@ +// +build appengine + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return true +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go new file mode 100644 index 00000000..0c209750 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_js.go @@ -0,0 +1,11 @@ +// +build js + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go new file mode 100644 index 00000000..cf309d6f --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go @@ -0,0 +1,19 @@ +// +build !appengine,!js,!windows + +package logrus + +import ( + "io" + "os" + + "golang.org/x/crypto/ssh/terminal" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return terminal.IsTerminal(int(v.Fd())) + default: + return false + } +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go new file mode 100644 index 00000000..3b9d2864 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go @@ -0,0 +1,20 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + var mode uint32 + err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) + return err == nil + default: + return false + } +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/sirupsen/logrus/terminal_notwindows.go new file mode 100644 index 00000000..3dbd2372 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_notwindows.go @@ -0,0 +1,8 @@ +// +build !windows + +package logrus + +import "io" + +func initTerminal(w io.Writer) { +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_windows.go b/vendor/github.com/sirupsen/logrus/terminal_windows.go new file mode 100644 index 00000000..b4ef5286 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_windows.go @@ -0,0 +1,18 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func initTerminal(w io.Writer) { + switch v := w.(type) { + case *os.File: + sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) + } +} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go new file mode 100644 index 00000000..49ec92f1 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -0,0 +1,269 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "sort" + "strings" + "sync" + "time" +) + +const ( + nocolor = 0 + red = 31 + green = 32 + yellow = 33 + blue = 36 + gray = 37 +) + +var ( + baseTimestamp time.Time + emptyFieldMap FieldMap +) + +func init() { + baseTimestamp = time.Now() +} + +// TextFormatter formats logs into text +type TextFormatter struct { + // Set to true to bypass checking for a TTY before outputting colors. + ForceColors bool + + // Force disabling colors. + DisableColors bool + + // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ + EnvironmentOverrideColors bool + + // Disable timestamp logging. useful when output is redirected to logging + // system that already adds timestamps. + DisableTimestamp bool + + // Enable logging the full timestamp when a TTY is attached instead of just + // the time passed since beginning of execution. + FullTimestamp bool + + // TimestampFormat to use for display when a full timestamp is printed + TimestampFormat string + + // The fields are sorted by default for a consistent output. For applications + // that log extremely frequently and don't use the JSON formatter this may not + // be desired. + DisableSorting bool + + // The keys sorting function, when uninitialized it uses sort.Strings. + SortingFunc func([]string) + + // Disables the truncation of the level text to 4 characters. + DisableLevelTruncation bool + + // QuoteEmptyFields will wrap empty fields in quotes if true + QuoteEmptyFields bool + + // Whether the logger's out is to a terminal + isTerminal bool + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &TextFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message"}} + FieldMap FieldMap + + terminalInitOnce sync.Once +} + +func (f *TextFormatter) init(entry *Entry) { + if entry.Logger != nil { + f.isTerminal = checkIfTerminal(entry.Logger.Out) + + if f.isTerminal { + initTerminal(entry.Logger.Out) + } + } +} + +func (f *TextFormatter) isColored() bool { + isColored := f.ForceColors || f.isTerminal + + if f.EnvironmentOverrideColors { + if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { + isColored = true + } else if ok && force == "0" { + isColored = false + } else if os.Getenv("CLICOLOR") == "0" { + isColored = false + } + } + + return isColored && !f.DisableColors +} + +// Format renders a single log entry +func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { + prefixFieldClashes(entry.Data, f.FieldMap, entry.HasCaller()) + + keys := make([]string, 0, len(entry.Data)) + for k := range entry.Data { + keys = append(keys, k) + } + + fixedKeys := make([]string, 0, 4+len(entry.Data)) + if !f.DisableTimestamp { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) + } + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) + if entry.Message != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) + } + if entry.err != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) + } + if entry.HasCaller() { + fixedKeys = append(fixedKeys, + f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile)) + } + + if !f.DisableSorting { + if f.SortingFunc == nil { + sort.Strings(keys) + fixedKeys = append(fixedKeys, keys...) + } else { + if !f.isColored() { + fixedKeys = append(fixedKeys, keys...) + f.SortingFunc(fixedKeys) + } else { + f.SortingFunc(keys) + } + } + } else { + fixedKeys = append(fixedKeys, keys...) + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + f.terminalInitOnce.Do(func() { f.init(entry) }) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + if f.isColored() { + f.printColored(b, entry, keys, timestampFormat) + } else { + for _, key := range fixedKeys { + var value interface{} + switch { + case key == f.FieldMap.resolve(FieldKeyTime): + value = entry.Time.Format(timestampFormat) + case key == f.FieldMap.resolve(FieldKeyLevel): + value = entry.Level.String() + case key == f.FieldMap.resolve(FieldKeyMsg): + value = entry.Message + case key == f.FieldMap.resolve(FieldKeyLogrusError): + value = entry.err + case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): + value = entry.Caller.Function + case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): + value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + default: + value = entry.Data[key] + } + f.appendKeyValue(b, key, value) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { + var levelColor int + switch entry.Level { + case DebugLevel, TraceLevel: + levelColor = gray + case WarnLevel: + levelColor = yellow + case ErrorLevel, FatalLevel, PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String()) + if !f.DisableLevelTruncation { + levelText = levelText[0:4] + } + + // Remove a single newline if it already exists in the message to keep + // the behavior of logrus text_formatter the same as the stdlib log package + entry.Message = strings.TrimSuffix(entry.Message, "\n") + + caller := "" + + if entry.HasCaller() { + caller = fmt.Sprintf("%s:%d %s()", + entry.Caller.File, entry.Caller.Line, entry.Caller.Function) + } + + if f.DisableTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) + } else if !f.FullTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) + } else { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) + } + for _, k := range keys { + v := entry.Data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) + } +} + +func (f *TextFormatter) needsQuoting(text string) bool { + if f.QuoteEmptyFields && len(text) == 0 { + return true + } + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { + return true + } + } + return false +} + +func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + if b.Len() > 0 { + b.WriteByte(' ') + } + b.WriteString(key) + b.WriteByte('=') + f.appendValue(b, value) +} + +func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { + stringVal, ok := value.(string) + if !ok { + stringVal = fmt.Sprint(value) + } + + if !f.needsQuoting(stringVal) { + b.WriteString(stringVal) + } else { + b.WriteString(fmt.Sprintf("%q", stringVal)) + } +} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter_test.go b/vendor/github.com/sirupsen/logrus/text_formatter_test.go new file mode 100644 index 00000000..b0d3a916 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/text_formatter_test.go @@ -0,0 +1,480 @@ +package logrus + +import ( + "bytes" + "errors" + "fmt" + "os" + "sort" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFormatting(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + testCases := []struct { + value string + expected string + }{ + {`foo`, "time=\"0001-01-01T00:00:00Z\" level=panic test=foo\n"}, + } + + for _, tc := range testCases { + b, _ := tf.Format(WithField("test", tc.value)) + + if string(b) != tc.expected { + t.Errorf("formatting expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) + } + } +} + +func TestQuoting(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + checkQuoting := func(q bool, value interface{}) { + b, _ := tf.Format(WithField("test", value)) + idx := bytes.Index(b, ([]byte)("test=")) + cont := bytes.Contains(b[idx+5:], []byte("\"")) + if cont != q { + if q { + t.Errorf("quoting expected for: %#v", value) + } else { + t.Errorf("quoting not expected for: %#v", value) + } + } + } + + checkQuoting(false, "") + checkQuoting(false, "abcd") + checkQuoting(false, "v1.0") + checkQuoting(false, "1234567890") + checkQuoting(false, "/foobar") + checkQuoting(false, "foo_bar") + checkQuoting(false, "foo@bar") + checkQuoting(false, "foobar^") + checkQuoting(false, "+/-_^@f.oobar") + checkQuoting(true, "foobar$") + checkQuoting(true, "&foobar") + checkQuoting(true, "x y") + checkQuoting(true, "x,y") + checkQuoting(false, errors.New("invalid")) + checkQuoting(true, errors.New("invalid argument")) + + // Test for quoting empty fields. + tf.QuoteEmptyFields = true + checkQuoting(true, "") + checkQuoting(false, "abcd") + checkQuoting(true, errors.New("invalid argument")) +} + +func TestEscaping(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + testCases := []struct { + value string + expected string + }{ + {`ba"r`, `ba\"r`}, + {`ba'r`, `ba'r`}, + } + + for _, tc := range testCases { + b, _ := tf.Format(WithField("test", tc.value)) + if !bytes.Contains(b, []byte(tc.expected)) { + t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) + } + } +} + +func TestEscaping_Interface(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + ts := time.Now() + + testCases := []struct { + value interface{} + expected string + }{ + {ts, fmt.Sprintf("\"%s\"", ts.String())}, + {errors.New("error: something went wrong"), "\"error: something went wrong\""}, + } + + for _, tc := range testCases { + b, _ := tf.Format(WithField("test", tc.value)) + if !bytes.Contains(b, []byte(tc.expected)) { + t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) + } + } +} + +func TestTimestampFormat(t *testing.T) { + checkTimeStr := func(format string) { + customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format} + customStr, _ := customFormatter.Format(WithField("test", "test")) + timeStart := bytes.Index(customStr, ([]byte)("time=")) + timeEnd := bytes.Index(customStr, ([]byte)("level=")) + timeStr := customStr[timeStart+5+len("\"") : timeEnd-1-len("\"")] + if format == "" { + format = time.RFC3339 + } + _, e := time.Parse(format, (string)(timeStr)) + if e != nil { + t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e) + } + } + + checkTimeStr("2006-01-02T15:04:05.000000000Z07:00") + checkTimeStr("Mon Jan _2 15:04:05 2006") + checkTimeStr("") +} + +func TestDisableLevelTruncation(t *testing.T) { + entry := &Entry{ + Time: time.Now(), + Message: "testing", + } + keys := []string{} + timestampFormat := "Mon Jan 2 15:04:05 -0700 MST 2006" + checkDisableTruncation := func(disabled bool, level Level) { + tf := &TextFormatter{DisableLevelTruncation: disabled} + var b bytes.Buffer + entry.Level = level + tf.printColored(&b, entry, keys, timestampFormat) + logLine := (&b).String() + if disabled { + expected := strings.ToUpper(level.String()) + if !strings.Contains(logLine, expected) { + t.Errorf("level string expected to be %s when truncation disabled", expected) + } + } else { + expected := strings.ToUpper(level.String()) + if len(level.String()) > 4 { + if strings.Contains(logLine, expected) { + t.Errorf("level string %s expected to be truncated to %s when truncation is enabled", expected, expected[0:4]) + } + } else { + if !strings.Contains(logLine, expected) { + t.Errorf("level string expected to be %s when truncation is enabled and level string is below truncation threshold", expected) + } + } + } + } + + checkDisableTruncation(true, DebugLevel) + checkDisableTruncation(true, InfoLevel) + checkDisableTruncation(false, ErrorLevel) + checkDisableTruncation(false, InfoLevel) +} + +func TestDisableTimestampWithColoredOutput(t *testing.T) { + tf := &TextFormatter{DisableTimestamp: true, ForceColors: true} + + b, _ := tf.Format(WithField("test", "test")) + if strings.Contains(string(b), "[0000]") { + t.Error("timestamp not expected when DisableTimestamp is true") + } +} + +func TestNewlineBehavior(t *testing.T) { + tf := &TextFormatter{ForceColors: true} + + // Ensure a single new line is removed as per stdlib log + e := NewEntry(StandardLogger()) + e.Message = "test message\n" + b, _ := tf.Format(e) + if bytes.Contains(b, []byte("test message\n")) { + t.Error("first newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected newline to be removed.") + } + + // Ensure a double new line is reduced to a single new line + e = NewEntry(StandardLogger()) + e.Message = "test message\n\n" + b, _ = tf.Format(e) + if bytes.Contains(b, []byte("test message\n\n")) { + t.Error("Double newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected single newline") + } + if !bytes.Contains(b, []byte("test message\n")) { + t.Error("Double newline at end of Entry.Message did not result in a single newline after formatting") + } +} + +func TestTextFormatterFieldMap(t *testing.T) { + formatter := &TextFormatter{ + DisableColors: true, + FieldMap: FieldMap{ + FieldKeyMsg: "message", + FieldKeyLevel: "somelevel", + FieldKeyTime: "timeywimey", + }, + } + + entry := &Entry{ + Message: "oh hi", + Level: WarnLevel, + Time: time.Date(1981, time.February, 24, 4, 28, 3, 100, time.UTC), + Data: Fields{ + "field1": "f1", + "message": "messagefield", + "somelevel": "levelfield", + "timeywimey": "timeywimeyfield", + }, + } + + b, err := formatter.Format(entry) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + assert.Equal(t, + `timeywimey="1981-02-24T04:28:03Z" `+ + `somelevel=warning `+ + `message="oh hi" `+ + `field1=f1 `+ + `fields.message=messagefield `+ + `fields.somelevel=levelfield `+ + `fields.timeywimey=timeywimeyfield`+"\n", + string(b), + "Formatted output doesn't respect FieldMap") +} + +func TestTextFormatterIsColored(t *testing.T) { + params := []struct { + name string + expectedResult bool + isTerminal bool + disableColor bool + forceColor bool + envColor bool + clicolorIsSet bool + clicolorForceIsSet bool + clicolorVal string + clicolorForceVal string + }{ + // Default values + { + name: "testcase1", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal + { + name: "testcase2", + expectedResult: true, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal with color disabled + { + name: "testcase3", + expectedResult: false, + isTerminal: true, + disableColor: true, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output not on terminal with color disabled + { + name: "testcase4", + expectedResult: false, + isTerminal: false, + disableColor: true, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output not on terminal with color forced + { + name: "testcase5", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal with clicolor set to "0" + { + name: "testcase6", + expectedResult: false, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output on terminal with clicolor set to "1" + { + name: "testcase7", + expectedResult: true, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "0" + { + name: "testcase8", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output not on terminal with clicolor set to "1" + { + name: "testcase9", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "1" and force color + { + name: "testcase10", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "0" and force color + { + name: "testcase11", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output not on terminal with clicolor_force set to "1" + { + name: "testcase12", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "1", + }, + // Output not on terminal with clicolor_force set to "0" + { + name: "testcase13", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "0", + }, + // Output on terminal with clicolor_force set to "0" + { + name: "testcase14", + expectedResult: false, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "0", + }, + } + + cleanenv := func() { + os.Unsetenv("CLICOLOR") + os.Unsetenv("CLICOLOR_FORCE") + } + + defer cleanenv() + + for _, val := range params { + t.Run("textformatter_"+val.name, func(subT *testing.T) { + tf := TextFormatter{ + isTerminal: val.isTerminal, + DisableColors: val.disableColor, + ForceColors: val.forceColor, + EnvironmentOverrideColors: val.envColor, + } + cleanenv() + if val.clicolorIsSet { + os.Setenv("CLICOLOR", val.clicolorVal) + } + if val.clicolorForceIsSet { + os.Setenv("CLICOLOR_FORCE", val.clicolorForceVal) + } + res := tf.isColored() + assert.Equal(subT, val.expectedResult, res) + }) + } +} + +func TestCustomSorting(t *testing.T) { + formatter := &TextFormatter{ + DisableColors: true, + SortingFunc: func(keys []string) { + sort.Slice(keys, func(i, j int) bool { + if keys[j] == "prefix" { + return false + } + if keys[i] == "prefix" { + return true + } + return strings.Compare(keys[i], keys[j]) == -1 + }) + }, + } + + entry := &Entry{ + Message: "Testing custom sort function", + Time: time.Now(), + Level: InfoLevel, + Data: Fields{ + "test": "testvalue", + "prefix": "the application prefix", + "blablabla": "blablabla", + }, + } + b, err := formatter.Format(entry) + require.NoError(t, err) + require.True(t, strings.HasPrefix(string(b), "prefix="), "format output is %q", string(b)) +} diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go new file mode 100644 index 00000000..9e1f7513 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/writer.go @@ -0,0 +1,64 @@ +package logrus + +import ( + "bufio" + "io" + "runtime" +) + +func (logger *Logger) Writer() *io.PipeWriter { + return logger.WriterLevel(InfoLevel) +} + +func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { + return NewEntry(logger).WriterLevel(level) +} + +func (entry *Entry) Writer() *io.PipeWriter { + return entry.WriterLevel(InfoLevel) +} + +func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { + reader, writer := io.Pipe() + + var printFunc func(args ...interface{}) + + switch level { + case TraceLevel: + printFunc = entry.Trace + case DebugLevel: + printFunc = entry.Debug + case InfoLevel: + printFunc = entry.Info + case WarnLevel: + printFunc = entry.Warn + case ErrorLevel: + printFunc = entry.Error + case FatalLevel: + printFunc = entry.Fatal + case PanicLevel: + printFunc = entry.Panic + default: + printFunc = entry.Print + } + + go entry.writerScanner(reader, printFunc) + runtime.SetFinalizer(writer, writerFinalizer) + + return writer +} + +func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + printFunc(scanner.Text()) + } + if err := scanner.Err(); err != nil { + entry.Errorf("Error while reading from Writer: %s", err) + } + reader.Close() +} + +func writerFinalizer(writer *io.PipeWriter) { + writer.Close() +} diff --git a/vendor/github.com/spf13/afero/.travis.yml b/vendor/github.com/spf13/afero/.travis.yml index 618159a4..0637db72 100644 --- a/vendor/github.com/spf13/afero/.travis.yml +++ b/vendor/github.com/spf13/afero/.travis.yml @@ -2,8 +2,8 @@ sudo: false language: go go: - - 1.7.5 - - 1.8 + - 1.9 + - "1.10" - tip os: diff --git a/vendor/github.com/spf13/afero/afero_test.go b/vendor/github.com/spf13/afero/afero_test.go index 526afa97..e2c13624 100644 --- a/vendor/github.com/spf13/afero/afero_test.go +++ b/vendor/github.com/spf13/afero/afero_test.go @@ -570,6 +570,25 @@ func TestReaddir(t *testing.T) { } } +// https://github.com/spf13/afero/issues/169 +func TestReaddirRegularFile(t *testing.T) { + defer removeAllTestFiles(t) + for _, fs := range Fss { + f := tmpFile(fs) + defer f.Close() + + _, err := f.Readdirnames(-1) + if err == nil { + t.Fatal("Expected error") + } + + _, err = f.Readdir(-1) + if err == nil { + t.Fatal("Expected error") + } + } +} + type myFileInfo []os.FileInfo func (m myFileInfo) String() string { diff --git a/vendor/github.com/spf13/afero/basepath.go b/vendor/github.com/spf13/afero/basepath.go index 5e4fc2ec..616ff8ff 100644 --- a/vendor/github.com/spf13/afero/basepath.go +++ b/vendor/github.com/spf13/afero/basepath.go @@ -1,7 +1,6 @@ package afero import ( - "errors" "os" "path/filepath" "runtime" @@ -9,6 +8,8 @@ import ( "time" ) +var _ Lstater = (*BasePathFs)(nil) + // The BasePathFs restricts all operations to a given path within an Fs. // The given file name to the operations on this Fs will be prepended with // the base path before calling the base Fs. @@ -22,6 +23,16 @@ type BasePathFs struct { path string } +type BasePathFile struct { + File + path string +} + +func (f *BasePathFile) Name() string { + sourcename := f.File.Name() + return strings.TrimPrefix(sourcename, filepath.Clean(f.path)) +} + func NewBasePathFs(source Fs, path string) Fs { return &BasePathFs{source: source, path: path} } @@ -30,7 +41,7 @@ func NewBasePathFs(source Fs, path string) Fs { // else the given file with the base path prepended func (b *BasePathFs) RealPath(name string) (path string, err error) { if err := validateBasePathName(name); err != nil { - return "", err + return name, err } bpath := filepath.Clean(b.path) @@ -52,7 +63,7 @@ func validateBasePathName(name string) error { // On Windows a common mistake would be to provide an absolute OS path // We could strip out the base part, but that would not be very portable. if filepath.IsAbs(name) { - return &os.PathError{Op: "realPath", Path: name, Err: errors.New("got a real OS path instead of a virtual")} + return os.ErrNotExist } return nil @@ -111,14 +122,22 @@ func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File, if name, err = b.RealPath(name); err != nil { return nil, &os.PathError{Op: "openfile", Path: name, Err: err} } - return b.source.OpenFile(name, flag, mode) + sourcef, err := b.source.OpenFile(name, flag, mode) + if err != nil { + return nil, err + } + return &BasePathFile{sourcef, b.path}, nil } func (b *BasePathFs) Open(name string) (f File, err error) { if name, err = b.RealPath(name); err != nil { return nil, &os.PathError{Op: "open", Path: name, Err: err} } - return b.source.Open(name) + sourcef, err := b.source.Open(name) + if err != nil { + return nil, err + } + return &BasePathFile{File: sourcef, path: b.path}, nil } func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) { @@ -139,7 +158,23 @@ func (b *BasePathFs) Create(name string) (f File, err error) { if name, err = b.RealPath(name); err != nil { return nil, &os.PathError{Op: "create", Path: name, Err: err} } - return b.source.Create(name) + sourcef, err := b.source.Create(name) + if err != nil { + return nil, err + } + return &BasePathFile{File: sourcef, path: b.path}, nil +} + +func (b *BasePathFs) LstatIfPossible(name string) (os.FileInfo, bool, error) { + name, err := b.RealPath(name) + if err != nil { + return nil, false, &os.PathError{Op: "lstat", Path: name, Err: err} + } + if lstater, ok := b.source.(Lstater); ok { + return lstater.LstatIfPossible(name) + } + fi, err := b.source.Stat(name) + return fi, false, err } // vim: ts=4 sw=4 noexpandtab nolist syn=go diff --git a/vendor/github.com/spf13/afero/basepath_test.go b/vendor/github.com/spf13/afero/basepath_test.go index abc22b9f..77aa7dfc 100644 --- a/vendor/github.com/spf13/afero/basepath_test.go +++ b/vendor/github.com/spf13/afero/basepath_test.go @@ -68,8 +68,8 @@ func TestRealPath(t *testing.T) { if runtime.GOOS == "windows" { _, err = bp.RealPath(anotherDir) - if err == nil { - t.Errorf("Expected error") + if err != os.ErrNotExist { + t.Errorf("Expected os.ErrNotExist") } } else { @@ -140,3 +140,51 @@ func TestNestedBasePaths(t *testing.T) { } } } + +func TestBasePathOpenFile(t *testing.T) { + baseFs := &MemMapFs{} + baseFs.MkdirAll("/base/path/tmp", 0777) + bp := NewBasePathFs(baseFs, "/base/path") + f, err := bp.OpenFile("/tmp/file.txt", os.O_CREATE, 0600) + if err != nil { + t.Fatalf("failed to open file: %v", err) + } + if filepath.Dir(f.Name()) != filepath.Clean("/tmp") { + t.Fatalf("realpath leaked: %s", f.Name()) + } +} + +func TestBasePathCreate(t *testing.T) { + baseFs := &MemMapFs{} + baseFs.MkdirAll("/base/path/tmp", 0777) + bp := NewBasePathFs(baseFs, "/base/path") + f, err := bp.Create("/tmp/file.txt") + if err != nil { + t.Fatalf("failed to create file: %v", err) + } + if filepath.Dir(f.Name()) != filepath.Clean("/tmp") { + t.Fatalf("realpath leaked: %s", f.Name()) + } +} + +func TestBasePathTempFile(t *testing.T) { + baseFs := &MemMapFs{} + baseFs.MkdirAll("/base/path/tmp", 0777) + bp := NewBasePathFs(baseFs, "/base/path") + + tDir, err := TempDir(bp, "/tmp", "") + if err != nil { + t.Fatalf("Failed to TempDir: %v", err) + } + if filepath.Dir(tDir) != filepath.Clean("/tmp") { + t.Fatalf("Tempdir realpath leaked: %s", tDir) + } + tempFile, err := TempFile(bp, tDir, "") + if err != nil { + t.Fatalf("Failed to TempFile: %v", err) + } + defer tempFile.Close() + if expected, actual := tDir, filepath.Dir(tempFile.Name()); expected != actual { + t.Fatalf("TempFile realpath leaked: expected %s, got %s", expected, actual) + } +} diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go index b026e0de..29a26c67 100644 --- a/vendor/github.com/spf13/afero/cacheOnReadFs.go +++ b/vendor/github.com/spf13/afero/cacheOnReadFs.go @@ -205,7 +205,7 @@ func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File, bfi.Close() // oops, what if O_TRUNC was set and file opening in the layer failed...? return nil, err } - return &UnionFile{base: bfi, layer: lfi}, nil + return &UnionFile{Base: bfi, Layer: lfi}, nil } return u.layer.OpenFile(name, flag, perm) } @@ -251,7 +251,7 @@ func (u *CacheOnReadFs) Open(name string) (File, error) { if err != nil && bfile == nil { return nil, err } - return &UnionFile{base: bfile, layer: lfile}, nil + return &UnionFile{Base: bfile, Layer: lfile}, nil } func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error { @@ -286,5 +286,5 @@ func (u *CacheOnReadFs) Create(name string) (File, error) { bfh.Close() return nil, err } - return &UnionFile{base: bfh, layer: lfh}, nil + return &UnionFile{Base: bfh, Layer: lfh}, nil } diff --git a/vendor/github.com/spf13/afero/composite_test.go b/vendor/github.com/spf13/afero/composite_test.go index 8e44611d..2a20440e 100644 --- a/vendor/github.com/spf13/afero/composite_test.go +++ b/vendor/github.com/spf13/afero/composite_test.go @@ -51,7 +51,6 @@ func CleanupTempDirs(t *testing.T) { func TestUnionCreateExisting(t *testing.T) { base := &MemMapFs{} roBase := &ReadOnlyFs{source: base} - ufs := NewCopyOnWriteFs(roBase, &MemMapFs{}) base.MkdirAll("/home/test", 0777) diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs.go b/vendor/github.com/spf13/afero/copyOnWriteFs.go index f2ebcd22..9aef3979 100644 --- a/vendor/github.com/spf13/afero/copyOnWriteFs.go +++ b/vendor/github.com/spf13/afero/copyOnWriteFs.go @@ -8,6 +8,8 @@ import ( "time" ) +var _ Lstater = (*CopyOnWriteFs)(nil) + // The CopyOnWriteFs is a union filesystem: a read only base file system with // a possibly writeable layer on top. Changes to the file system will only // be made in the overlay: Changing an existing file in the base layer which @@ -76,18 +78,55 @@ func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error { func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) { fi, err := u.layer.Stat(name) if err != nil { - origErr := err - if e, ok := err.(*os.PathError); ok { - err = e.Err - } - if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR { + isNotExist := u.isNotExist(err) + if isNotExist { return u.base.Stat(name) } - return nil, origErr + return nil, err } return fi, nil } +func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) { + llayer, ok1 := u.layer.(Lstater) + lbase, ok2 := u.base.(Lstater) + + if ok1 { + fi, b, err := llayer.LstatIfPossible(name) + if err == nil { + return fi, b, nil + } + + if !u.isNotExist(err) { + return nil, b, err + } + } + + if ok2 { + fi, b, err := lbase.LstatIfPossible(name) + if err == nil { + return fi, b, nil + } + if !u.isNotExist(err) { + return nil, b, err + } + } + + fi, err := u.Stat(name) + + return fi, false, err +} + +func (u *CopyOnWriteFs) isNotExist(err error) bool { + if e, ok := err.(*os.PathError); ok { + err = e.Err + } + if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR { + return true + } + return false +} + // Renaming files present only in the base layer is not permitted func (u *CopyOnWriteFs) Rename(oldname, newname string) error { b, err := u.isBaseFile(oldname) @@ -219,7 +258,7 @@ func (u *CopyOnWriteFs) Open(name string) (File, error) { return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr) } - return &UnionFile{base: bfile, layer: lfile}, nil + return &UnionFile{Base: bfile, Layer: lfile}, nil } func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error { diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs_test.go b/vendor/github.com/spf13/afero/copyOnWriteFs_test.go index c6f2c6d6..0f199dce 100644 --- a/vendor/github.com/spf13/afero/copyOnWriteFs_test.go +++ b/vendor/github.com/spf13/afero/copyOnWriteFs_test.go @@ -8,6 +8,7 @@ func TestCopyOnWrite(t *testing.T) { base := NewOsFs() roBase := NewReadOnlyFs(base) ufs := NewCopyOnWriteFs(roBase, NewMemMapFs()) + fs = ufs err = fs.MkdirAll("nonexistent/directory/", 0744) if err != nil { diff --git a/vendor/github.com/spf13/afero/go.mod b/vendor/github.com/spf13/afero/go.mod new file mode 100644 index 00000000..9eff4fed --- /dev/null +++ b/vendor/github.com/spf13/afero/go.mod @@ -0,0 +1 @@ +module github.com/spf13/afero diff --git a/vendor/github.com/spf13/afero/lstater.go b/vendor/github.com/spf13/afero/lstater.go new file mode 100644 index 00000000..89c1bfc0 --- /dev/null +++ b/vendor/github.com/spf13/afero/lstater.go @@ -0,0 +1,27 @@ +// Copyright © 2018 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package afero + +import ( + "os" +) + +// Lstater is an optional interface in Afero. It is only implemented by the +// filesystems saying so. +// It will call Lstat if the filesystem iself is, or it delegates to, the os filesystem. +// Else it will call Stat. +// In addtion to the FileInfo, it will return a boolean telling whether Lstat was called or not. +type Lstater interface { + LstatIfPossible(name string) (os.FileInfo, bool, error) +} diff --git a/vendor/github.com/spf13/afero/lstater_test.go b/vendor/github.com/spf13/afero/lstater_test.go new file mode 100644 index 00000000..477924f6 --- /dev/null +++ b/vendor/github.com/spf13/afero/lstater_test.go @@ -0,0 +1,102 @@ +// Copyright ©2018 Steve Francia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package afero + +import ( + "os" + "path/filepath" + "testing" +) + +func TestLstatIfPossible(t *testing.T) { + wd, _ := os.Getwd() + defer func() { + os.Chdir(wd) + }() + + osFs := &OsFs{} + + workDir, err := TempDir(osFs, "", "afero-lstate") + if err != nil { + t.Fatal(err) + } + + defer func() { + osFs.RemoveAll(workDir) + }() + + memWorkDir := "/lstate" + + memFs := NewMemMapFs() + overlayFs1 := &CopyOnWriteFs{base: osFs, layer: memFs} + overlayFs2 := &CopyOnWriteFs{base: memFs, layer: osFs} + overlayFsMemOnly := &CopyOnWriteFs{base: memFs, layer: NewMemMapFs()} + basePathFs := &BasePathFs{source: osFs, path: workDir} + basePathFsMem := &BasePathFs{source: memFs, path: memWorkDir} + roFs := &ReadOnlyFs{source: osFs} + roFsMem := &ReadOnlyFs{source: memFs} + + pathFileMem := filepath.Join(memWorkDir, "aferom.txt") + + WriteFile(osFs, filepath.Join(workDir, "afero.txt"), []byte("Hi, Afero!"), 0777) + WriteFile(memFs, filepath.Join(pathFileMem), []byte("Hi, Afero!"), 0777) + + os.Chdir(workDir) + if err := os.Symlink("afero.txt", "symafero.txt"); err != nil { + t.Fatal(err) + } + + pathFile := filepath.Join(workDir, "afero.txt") + pathSymlink := filepath.Join(workDir, "symafero.txt") + + checkLstat := func(l Lstater, name string, shouldLstat bool) os.FileInfo { + statFile, isLstat, err := l.LstatIfPossible(name) + if err != nil { + t.Fatalf("Lstat check failed: %s", err) + } + if isLstat != shouldLstat { + t.Fatalf("Lstat status was %t for %s", isLstat, name) + } + return statFile + } + + testLstat := func(l Lstater, pathFile, pathSymlink string) { + shouldLstat := pathSymlink != "" + statRegular := checkLstat(l, pathFile, shouldLstat) + statSymlink := checkLstat(l, pathSymlink, shouldLstat) + if statRegular == nil || statSymlink == nil { + t.Fatal("got nil FileInfo") + } + + symSym := statSymlink.Mode()&os.ModeSymlink == os.ModeSymlink + if symSym == (pathSymlink == "") { + t.Fatal("expected the FileInfo to describe the symlink") + } + + _, _, err := l.LstatIfPossible("this-should-not-exist.txt") + if err == nil || !os.IsNotExist(err) { + t.Fatalf("expected file to not exist, got %s", err) + } + } + + testLstat(osFs, pathFile, pathSymlink) + testLstat(overlayFs1, pathFile, pathSymlink) + testLstat(overlayFs2, pathFile, pathSymlink) + testLstat(basePathFs, "afero.txt", "symafero.txt") + testLstat(overlayFsMemOnly, pathFileMem, "") + testLstat(basePathFsMem, "aferom.txt", "") + testLstat(roFs, pathFile, pathSymlink) + testLstat(roFsMem, pathFileMem, "") +} diff --git a/vendor/github.com/spf13/afero/match.go b/vendor/github.com/spf13/afero/match.go index 08b3b7e0..c18a87fb 100644 --- a/vendor/github.com/spf13/afero/match.go +++ b/vendor/github.com/spf13/afero/match.go @@ -33,8 +33,8 @@ import ( // built-ins from that package. func Glob(fs Fs, pattern string) (matches []string, err error) { if !hasMeta(pattern) { - // afero does not support Lstat directly. - if _, err = lstatIfOs(fs, pattern); err != nil { + // Lstat not supported by a ll filesystems. + if _, err = lstatIfPossible(fs, pattern); err != nil { return nil, nil } return []string{pattern}, nil diff --git a/vendor/github.com/spf13/afero/mem/file.go b/vendor/github.com/spf13/afero/mem/file.go index 885e5542..7af2fb56 100644 --- a/vendor/github.com/spf13/afero/mem/file.go +++ b/vendor/github.com/spf13/afero/mem/file.go @@ -131,6 +131,9 @@ func (f *File) Sync() error { } func (f *File) Readdir(count int) (res []os.FileInfo, err error) { + if !f.fileData.dir { + return nil, &os.PathError{Op: "readdir", Path: f.fileData.name, Err: errors.New("not a dir")} + } var outLength int64 f.fileData.Lock() diff --git a/vendor/github.com/spf13/afero/os.go b/vendor/github.com/spf13/afero/os.go index 6b8bce1c..13cc1b84 100644 --- a/vendor/github.com/spf13/afero/os.go +++ b/vendor/github.com/spf13/afero/os.go @@ -19,6 +19,8 @@ import ( "time" ) +var _ Lstater = (*OsFs)(nil) + // OsFs is a Fs implementation that uses functions provided by the os package. // // For details in any method, check the documentation of the os package @@ -92,3 +94,8 @@ func (OsFs) Chmod(name string, mode os.FileMode) error { func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error { return os.Chtimes(name, atime, mtime) } + +func (OsFs) LstatIfPossible(name string) (os.FileInfo, bool, error) { + fi, err := os.Lstat(name) + return fi, true, err +} diff --git a/vendor/github.com/spf13/afero/path.go b/vendor/github.com/spf13/afero/path.go index 1d90e46d..18f60a0f 100644 --- a/vendor/github.com/spf13/afero/path.go +++ b/vendor/github.com/spf13/afero/path.go @@ -60,7 +60,7 @@ func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error for _, name := range names { filename := filepath.Join(path, name) - fileInfo, err := lstatIfOs(fs, filename) + fileInfo, err := lstatIfPossible(fs, filename) if err != nil { if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { return err @@ -77,15 +77,13 @@ func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error return nil } -// if the filesystem is OsFs use Lstat, else use fs.Stat -func lstatIfOs(fs Fs, path string) (info os.FileInfo, err error) { - _, ok := fs.(*OsFs) - if ok { - info, err = os.Lstat(path) - } else { - info, err = fs.Stat(path) +// if the filesystem supports it, use Lstat, else use fs.Stat +func lstatIfPossible(fs Fs, path string) (os.FileInfo, error) { + if lfs, ok := fs.(Lstater); ok { + fi, _, err := lfs.LstatIfPossible(path) + return fi, err } - return + return fs.Stat(path) } // Walk walks the file tree rooted at root, calling walkFn for each file or @@ -100,7 +98,7 @@ func (a Afero) Walk(root string, walkFn filepath.WalkFunc) error { } func Walk(fs Fs, root string, walkFn filepath.WalkFunc) error { - info, err := lstatIfOs(fs, root) + info, err := lstatIfPossible(fs, root) if err != nil { return walkFn(root, nil, err) } diff --git a/vendor/github.com/spf13/afero/readonlyfs.go b/vendor/github.com/spf13/afero/readonlyfs.go index f1fa55bc..c6376ec3 100644 --- a/vendor/github.com/spf13/afero/readonlyfs.go +++ b/vendor/github.com/spf13/afero/readonlyfs.go @@ -6,6 +6,8 @@ import ( "time" ) +var _ Lstater = (*ReadOnlyFs)(nil) + type ReadOnlyFs struct { source Fs } @@ -34,6 +36,14 @@ func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) { return r.source.Stat(name) } +func (r *ReadOnlyFs) LstatIfPossible(name string) (os.FileInfo, bool, error) { + if lsf, ok := r.source.(Lstater); ok { + return lsf.LstatIfPossible(name) + } + fi, err := r.Stat(name) + return fi, false, err +} + func (r *ReadOnlyFs) Rename(o, n string) error { return syscall.EPERM } diff --git a/vendor/github.com/spf13/afero/unionFile.go b/vendor/github.com/spf13/afero/unionFile.go index 99f9e5db..1e78f7d1 100644 --- a/vendor/github.com/spf13/afero/unionFile.go +++ b/vendor/github.com/spf13/afero/unionFile.go @@ -21,32 +21,33 @@ import ( // successful read in the overlay will move the cursor position in the base layer // by the number of bytes read. type UnionFile struct { - base File - layer File - off int - files []os.FileInfo + Base File + Layer File + Merger DirsMerger + off int + files []os.FileInfo } func (f *UnionFile) Close() error { // first close base, so we have a newer timestamp in the overlay. If we'd close // the overlay first, we'd get a cacheStale the next time we access this file // -> cache would be useless ;-) - if f.base != nil { - f.base.Close() + if f.Base != nil { + f.Base.Close() } - if f.layer != nil { - return f.layer.Close() + if f.Layer != nil { + return f.Layer.Close() } return BADFD } func (f *UnionFile) Read(s []byte) (int, error) { - if f.layer != nil { - n, err := f.layer.Read(s) - if (err == nil || err == io.EOF) && f.base != nil { + if f.Layer != nil { + n, err := f.Layer.Read(s) + if (err == nil || err == io.EOF) && f.Base != nil { // advance the file position also in the base file, the next // call may be a write at this position (or a seek with SEEK_CUR) - if _, seekErr := f.base.Seek(int64(n), os.SEEK_CUR); seekErr != nil { + if _, seekErr := f.Base.Seek(int64(n), os.SEEK_CUR); seekErr != nil { // only overwrite err in case the seek fails: we need to // report an eventual io.EOF to the caller err = seekErr @@ -54,105 +55,135 @@ func (f *UnionFile) Read(s []byte) (int, error) { } return n, err } - if f.base != nil { - return f.base.Read(s) + if f.Base != nil { + return f.Base.Read(s) } return 0, BADFD } func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) { - if f.layer != nil { - n, err := f.layer.ReadAt(s, o) - if (err == nil || err == io.EOF) && f.base != nil { - _, err = f.base.Seek(o+int64(n), os.SEEK_SET) + if f.Layer != nil { + n, err := f.Layer.ReadAt(s, o) + if (err == nil || err == io.EOF) && f.Base != nil { + _, err = f.Base.Seek(o+int64(n), os.SEEK_SET) } return n, err } - if f.base != nil { - return f.base.ReadAt(s, o) + if f.Base != nil { + return f.Base.ReadAt(s, o) } return 0, BADFD } func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) { - if f.layer != nil { - pos, err = f.layer.Seek(o, w) - if (err == nil || err == io.EOF) && f.base != nil { - _, err = f.base.Seek(o, w) + if f.Layer != nil { + pos, err = f.Layer.Seek(o, w) + if (err == nil || err == io.EOF) && f.Base != nil { + _, err = f.Base.Seek(o, w) } return pos, err } - if f.base != nil { - return f.base.Seek(o, w) + if f.Base != nil { + return f.Base.Seek(o, w) } return 0, BADFD } func (f *UnionFile) Write(s []byte) (n int, err error) { - if f.layer != nil { - n, err = f.layer.Write(s) - if err == nil && f.base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark? - _, err = f.base.Write(s) + if f.Layer != nil { + n, err = f.Layer.Write(s) + if err == nil && f.Base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark? + _, err = f.Base.Write(s) } return n, err } - if f.base != nil { - return f.base.Write(s) + if f.Base != nil { + return f.Base.Write(s) } return 0, BADFD } func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) { - if f.layer != nil { - n, err = f.layer.WriteAt(s, o) - if err == nil && f.base != nil { - _, err = f.base.WriteAt(s, o) + if f.Layer != nil { + n, err = f.Layer.WriteAt(s, o) + if err == nil && f.Base != nil { + _, err = f.Base.WriteAt(s, o) } return n, err } - if f.base != nil { - return f.base.WriteAt(s, o) + if f.Base != nil { + return f.Base.WriteAt(s, o) } return 0, BADFD } func (f *UnionFile) Name() string { - if f.layer != nil { - return f.layer.Name() + if f.Layer != nil { + return f.Layer.Name() } - return f.base.Name() + return f.Base.Name() +} + +// DirsMerger is how UnionFile weaves two directories together. +// It takes the FileInfo slices from the layer and the base and returns a +// single view. +type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) + +var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) { + var files = make(map[string]os.FileInfo) + + for _, fi := range lofi { + files[fi.Name()] = fi + } + + for _, fi := range bofi { + if _, exists := files[fi.Name()]; !exists { + files[fi.Name()] = fi + } + } + + rfi := make([]os.FileInfo, len(files)) + + i := 0 + for _, fi := range files { + rfi[i] = fi + i++ + } + + return rfi, nil + } // Readdir will weave the two directories together and // return a single view of the overlayed directories func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) { + var merge DirsMerger = f.Merger + if merge == nil { + merge = defaultUnionMergeDirsFn + } + if f.off == 0 { - var files = make(map[string]os.FileInfo) - var rfi []os.FileInfo - if f.layer != nil { - rfi, err = f.layer.Readdir(-1) + var lfi []os.FileInfo + if f.Layer != nil { + lfi, err = f.Layer.Readdir(-1) if err != nil { return nil, err } - for _, fi := range rfi { - files[fi.Name()] = fi - } } - if f.base != nil { - rfi, err = f.base.Readdir(-1) + var bfi []os.FileInfo + if f.Base != nil { + bfi, err = f.Base.Readdir(-1) if err != nil { return nil, err } - for _, fi := range rfi { - if _, exists := files[fi.Name()]; !exists { - files[fi.Name()] = fi - } - } + } - for _, fi := range files { - f.files = append(f.files, fi) + merged, err := merge(lfi, bfi) + if err != nil { + return nil, err } + f.files = append(f.files, merged...) } if c == -1 { return f.files[f.off:], nil @@ -174,53 +205,53 @@ func (f *UnionFile) Readdirnames(c int) ([]string, error) { } func (f *UnionFile) Stat() (os.FileInfo, error) { - if f.layer != nil { - return f.layer.Stat() + if f.Layer != nil { + return f.Layer.Stat() } - if f.base != nil { - return f.base.Stat() + if f.Base != nil { + return f.Base.Stat() } return nil, BADFD } func (f *UnionFile) Sync() (err error) { - if f.layer != nil { - err = f.layer.Sync() - if err == nil && f.base != nil { - err = f.base.Sync() + if f.Layer != nil { + err = f.Layer.Sync() + if err == nil && f.Base != nil { + err = f.Base.Sync() } return err } - if f.base != nil { - return f.base.Sync() + if f.Base != nil { + return f.Base.Sync() } return BADFD } func (f *UnionFile) Truncate(s int64) (err error) { - if f.layer != nil { - err = f.layer.Truncate(s) - if err == nil && f.base != nil { - err = f.base.Truncate(s) + if f.Layer != nil { + err = f.Layer.Truncate(s) + if err == nil && f.Base != nil { + err = f.Base.Truncate(s) } return err } - if f.base != nil { - return f.base.Truncate(s) + if f.Base != nil { + return f.Base.Truncate(s) } return BADFD } func (f *UnionFile) WriteString(s string) (n int, err error) { - if f.layer != nil { - n, err = f.layer.WriteString(s) - if err == nil && f.base != nil { - _, err = f.base.WriteString(s) + if f.Layer != nil { + n, err = f.Layer.WriteString(s) + if err == nil && f.Base != nil { + _, err = f.Base.WriteString(s) } return n, err } - if f.base != nil { - return f.base.WriteString(s) + if f.Base != nil { + return f.Base.WriteString(s) } return 0, BADFD } diff --git a/vendor/github.com/spf13/cast/cast_test.go b/vendor/github.com/spf13/cast/cast_test.go index 404fe768..d9b0b013 100644 --- a/vendor/github.com/spf13/cast/cast_test.go +++ b/vendor/github.com/spf13/cast/cast_test.go @@ -697,6 +697,10 @@ func TestStringMapStringSliceE(t *testing.T) { var stringMapInterface1 = map[string]interface{}{"key 1": []string{"value 1"}, "key 2": []string{"value 2"}} var stringMapInterfaceResult1 = map[string][]string{"key 1": {"value 1"}, "key 2": {"value 2"}} + var jsonStringMapString = `{"key 1": "value 1", "key 2": "value 2"}` + var jsonStringMapStringArray = `{"key 1": ["value 1"], "key 2": ["value 2", "value 3"]}` + var jsonStringMapStringArrayResult = map[string][]string{"key 1": {"value 1"}, "key 2": {"value 2", "value 3"}} + type Key struct { k string } @@ -718,11 +722,15 @@ func TestStringMapStringSliceE(t *testing.T) { {interfaceMapInterfaceSlice, stringMapStringSlice, false}, {interfaceMapString, stringMapStringSingleSliceFieldsResult, false}, {interfaceMapInterface, stringMapStringSingleSliceFieldsResult, false}, + {jsonStringMapStringArray, jsonStringMapStringArrayResult, false}, + // errors {nil, nil, true}, {testing.T{}, nil, true}, {map[interface{}]interface{}{"foo": testing.T{}}, nil, true}, {map[interface{}]interface{}{Key{"foo"}: "bar"}, nil, true}, // ToStringE(Key{"foo"}) should fail + {jsonStringMapString, nil, true}, + {"", nil, true}, } for i, test := range tests { @@ -751,9 +759,13 @@ func TestToStringMapE(t *testing.T) { }{ {map[interface{}]interface{}{"tag": "tags", "group": "groups"}, map[string]interface{}{"tag": "tags", "group": "groups"}, false}, {map[string]interface{}{"tag": "tags", "group": "groups"}, map[string]interface{}{"tag": "tags", "group": "groups"}, false}, + {`{"tag": "tags", "group": "groups"}`, map[string]interface{}{"tag": "tags", "group": "groups"}, false}, + {`{"tag": "tags", "group": true}`, map[string]interface{}{"tag": "tags", "group": true}, false}, + // errors {nil, nil, true}, {testing.T{}, nil, true}, + {"", nil, true}, } for i, test := range tests { @@ -783,9 +795,12 @@ func TestToStringMapBoolE(t *testing.T) { {map[interface{}]interface{}{"v1": true, "v2": false}, map[string]bool{"v1": true, "v2": false}, false}, {map[string]interface{}{"v1": true, "v2": false}, map[string]bool{"v1": true, "v2": false}, false}, {map[string]bool{"v1": true, "v2": false}, map[string]bool{"v1": true, "v2": false}, false}, + {`{"v1": true, "v2": false}`, map[string]bool{"v1": true, "v2": false}, false}, + // errors {nil, nil, true}, {testing.T{}, nil, true}, + {"", nil, true}, } for i, test := range tests { @@ -811,6 +826,9 @@ func TestToStringMapStringE(t *testing.T) { var stringMapInterface = map[string]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"} var interfaceMapString = map[interface{}]string{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"} var interfaceMapInterface = map[interface{}]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"} + var jsonString = `{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}` + var invalidJsonString = `{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"` + var emptyString = "" tests := []struct { input interface{} @@ -821,9 +839,13 @@ func TestToStringMapStringE(t *testing.T) { {stringMapInterface, stringMapString, false}, {interfaceMapString, stringMapString, false}, {interfaceMapInterface, stringMapString, false}, + {jsonString, stringMapString, false}, + // errors {nil, nil, true}, {testing.T{}, nil, true}, + {invalidJsonString, nil, true}, + {emptyString, nil, true}, } for i, test := range tests { @@ -984,9 +1006,12 @@ func TestToDurationSliceE(t *testing.T) { {[]string{"1s", "1m"}, []time.Duration{time.Second, time.Minute}, false}, {[]int{1, 2}, []time.Duration{1, 2}, false}, {[]interface{}{1, 3}, []time.Duration{1, 3}, false}, + {[]time.Duration{1, 3}, []time.Duration{1, 3}, false}, + // errors {nil, nil, true}, {testing.T{}, nil, true}, + {[]string{"invalid"}, nil, true}, } for i, test := range tests { diff --git a/vendor/github.com/spf13/cast/caste.go b/vendor/github.com/spf13/cast/caste.go index 81511fe5..4fe19289 100644 --- a/vendor/github.com/spf13/cast/caste.go +++ b/vendor/github.com/spf13/cast/caste.go @@ -6,6 +6,7 @@ package cast import ( + "encoding/json" "errors" "fmt" "html/template" @@ -872,6 +873,9 @@ func ToStringMapStringE(i interface{}) (map[string]string, error) { m[ToString(k)] = ToString(val) } return m, nil + case string: + err := jsonStringToObject(v, &m) + return m, err default: return m, fmt.Errorf("unable to cast %#v of type %T to map[string]string", i, i) } @@ -932,6 +936,9 @@ func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) { } m[key] = value } + case string: + err := jsonStringToObject(v, &m) + return m, err default: return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) } @@ -955,6 +962,9 @@ func ToStringMapBoolE(i interface{}) (map[string]bool, error) { return m, nil case map[string]bool: return v, nil + case string: + err := jsonStringToObject(v, &m) + return m, err default: return m, fmt.Errorf("unable to cast %#v of type %T to map[string]bool", i, i) } @@ -972,6 +982,9 @@ func ToStringMapE(i interface{}) (map[string]interface{}, error) { return m, nil case map[string]interface{}: return v, nil + case string: + err := jsonStringToObject(v, &m) + return m, err default: return m, fmt.Errorf("unable to cast %#v of type %T to map[string]interface{}", i, i) } @@ -1144,3 +1157,10 @@ func parseDateWith(s string, dates []string) (d time.Time, e error) { } return d, fmt.Errorf("unable to parse date: %s", s) } + +// jsonStringToObject attempts to unmarshall a string as JSON into +// the object passed as pointer. +func jsonStringToObject(s string, v interface{}) error { + data := []byte(s) + return json.Unmarshal(data, v) +} diff --git a/vendor/github.com/spf13/cobra/.circleci/config.yml b/vendor/github.com/spf13/cobra/.circleci/config.yml new file mode 100644 index 00000000..066df225 --- /dev/null +++ b/vendor/github.com/spf13/cobra/.circleci/config.yml @@ -0,0 +1,38 @@ +workflows: + version: 2 + main: + jobs: + - go-current + - go-previous + - go-latest +base: &base + working_directory: /go/src/github.com/spf13/cobra + steps: + - checkout + - run: + name: "All Commands" + command: | + mkdir -p bin + curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.6/shellcheck + chmod +x bin/shellcheck + go get -t -v ./... + PATH=$PATH:$PWD/bin go test -v ./... + go build + diff -u <(echo -n) <(gofmt -d -s .) + if [ -z $NOVET ]; then + diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); + fi +version: 2 +jobs: + go-current: + docker: + - image: circleci/golang:1.10.0 + <<: *base + go-previous: + docker: + - image: circleci/golang:1.9.4 + <<: *base + go-latest: + docker: + - image: circleci/golang:latest + <<: *base diff --git a/vendor/github.com/spf13/cobra/.travis.yml b/vendor/github.com/spf13/cobra/.travis.yml index 68efa136..5afcb209 100644 --- a/vendor/github.com/spf13/cobra/.travis.yml +++ b/vendor/github.com/spf13/cobra/.travis.yml @@ -2,8 +2,8 @@ language: go matrix: include: - - go: 1.7.6 - - go: 1.8.3 + - go: 1.9.4 + - go: 1.10.0 - go: tip allow_failures: - go: tip diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 373a056b..851fcc08 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -20,6 +20,7 @@ Many of the most widely used Go projects are built using Cobra including: * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) * [rclone](http://rclone.org/) * [nehm](https://github.com/bogem/nehm) +* [Pouch](https://github.com/alibaba/pouch) [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) [![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) @@ -158,10 +159,7 @@ import ( ) func main() { - if err := cmd.RootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } + cmd.Execute() } ``` @@ -174,7 +172,7 @@ commands you want. It's the easiest way to incorporate Cobra into your applicati ## Using the Cobra Library -To manually implement Cobra you need to create a bare main.go file and a RootCmd file. +To manually implement Cobra you need to create a bare main.go file and a rootCmd file. You will optionally provide additional commands as you see fit. ### Create rootCmd @@ -184,7 +182,7 @@ Cobra doesn't require any special constructors. Simply create your commands. Ideally you place this in app/cmd/root.go: ```go -var RootCmd = &cobra.Command{ +var rootCmd = &cobra.Command{ Use: "hugo", Short: "Hugo is a very fast static site generator", Long: `A Fast and Flexible Static Site Generator built with @@ -194,6 +192,13 @@ var RootCmd = &cobra.Command{ // Do Stuff Here }, } + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} ``` You will additionally define flags and handle configuration in your init() function. @@ -212,22 +217,18 @@ import ( func init() { cobra.OnInitialize(initConfig) - RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") - RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") - RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") - RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") - RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") - viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) - viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) - viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") + rootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") + rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") + rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") + rootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") + viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) + viper.BindPFlag("projectbase", rootCmd.PersistentFlags().Lookup("projectbase")) + viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) viper.SetDefault("author", "NAME HERE ") viper.SetDefault("license", "apache") } -func Execute() { - RootCmd.Execute() -} - func initConfig() { // Don't forget to read config either from cfgFile or from home directory! if cfgFile != "" { @@ -271,10 +272,7 @@ import ( ) func main() { - if err := cmd.RootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } + cmd.Execute() } ``` @@ -290,12 +288,13 @@ populate it with the following: package cmd import ( - "github.com/spf13/cobra" "fmt" + + "github.com/spf13/cobra" ) func init() { - RootCmd.AddCommand(versionCmd) + rootCmd.AddCommand(versionCmd) } var versionCmd = &cobra.Command{ @@ -332,7 +331,7 @@ command it's assigned to as well as every command under that command. For global flags, assign a flag as a persistent flag on the root. ```go -RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") ``` ### Local Flags @@ -340,13 +339,13 @@ RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out A flag can also be assigned locally which will only apply to that specific command. ```go -RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") ``` ### Local Flag on Parent Commands -By default Cobra only parses local flags on the target command, any local flags on -parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will +By default Cobra only parses local flags on the target command, any local flags on +parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will parse local flags on each command before executing the target command. ```go @@ -363,8 +362,8 @@ You can also bind your flags with [viper](https://github.com/spf13/viper): var author string func init() { - RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") - viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) + rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") + viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) } ``` @@ -374,6 +373,15 @@ when the `--author` flag is not provided by user. More in [viper documentation](https://github.com/spf13/viper#working-with-flags). +### Required flags + +Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required: +```go +rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") +rootCmd.MarkFlagRequired("region") +``` + ## Positional and Custom Arguments Validation of positional arguments can be specified using the `Args` field @@ -522,7 +530,7 @@ around it. In fact, you can provide your own if you want. ### Defining your own help You can provide your own Help command or your own template for the default command to use -with followind functions: +with following functions: ```go cmd.SetHelpCommand(cmd *Command) @@ -569,6 +577,13 @@ cmd.SetUsageFunc(f func(*Command) error) cmd.SetUsageTemplate(s string) ``` +## Version Flag + +Cobra adds a top-level '--version' flag if the Version field is set on the root command. +Running an application with the '--version' flag will print the version to stdout using +the version template. The template can be customized using the +`cmd.SetVersionTemplate(s string)` function. + ## PreRun and PostRun Hooks It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go index 94a6ca27..a5d8a927 100644 --- a/vendor/github.com/spf13/cobra/args.go +++ b/vendor/github.com/spf13/cobra/args.go @@ -16,14 +16,14 @@ func legacyArgs(cmd *Command, args []string) error { return nil } - // root command with subcommands, do subcommand checking + // root command with subcommands, do subcommand checking. if !cmd.HasParent() && len(args) > 0 { return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) } return nil } -// NoArgs returns an error if any args are included +// NoArgs returns an error if any args are included. func NoArgs(cmd *Command, args []string) error { if len(args) > 0 { return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) @@ -31,7 +31,7 @@ func NoArgs(cmd *Command, args []string) error { return nil } -// OnlyValidArgs returns an error if any args are not in the list of ValidArgs +// OnlyValidArgs returns an error if any args are not in the list of ValidArgs. func OnlyValidArgs(cmd *Command, args []string) error { if len(cmd.ValidArgs) > 0 { for _, v := range args { @@ -43,21 +43,12 @@ func OnlyValidArgs(cmd *Command, args []string) error { return nil } -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - -// ArbitraryArgs never returns an error +// ArbitraryArgs never returns an error. func ArbitraryArgs(cmd *Command, args []string) error { return nil } -// MinimumNArgs returns an error if there is not at least N args +// MinimumNArgs returns an error if there is not at least N args. func MinimumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < n { @@ -67,7 +58,7 @@ func MinimumNArgs(n int) PositionalArgs { } } -// MaximumNArgs returns an error if there are more than N args +// MaximumNArgs returns an error if there are more than N args. func MaximumNArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) > n { @@ -77,7 +68,7 @@ func MaximumNArgs(n int) PositionalArgs { } } -// ExactArgs returns an error if there are not exactly n args +// ExactArgs returns an error if there are not exactly n args. func ExactArgs(n int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) != n { @@ -87,7 +78,7 @@ func ExactArgs(n int) PositionalArgs { } } -// RangeArgs returns an error if the number of args is not within the expected range +// RangeArgs returns an error if the number of args is not within the expected range. func RangeArgs(min int, max int) PositionalArgs { return func(cmd *Command, args []string) error { if len(args) < min || len(args) > max { diff --git a/vendor/github.com/spf13/cobra/args_test.go b/vendor/github.com/spf13/cobra/args_test.go new file mode 100644 index 00000000..d797b6f5 --- /dev/null +++ b/vendor/github.com/spf13/cobra/args_test.go @@ -0,0 +1,241 @@ +package cobra + +import ( + "strings" + "testing" +) + +func TestNoArgs(t *testing.T) { + c := &Command{Use: "c", Args: NoArgs, Run: emptyRun} + + output, err := executeCommand(c) + if output != "" { + t.Errorf("Unexpected string: %v", output) + } + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestNoArgsWithArgs(t *testing.T) { + c := &Command{Use: "c", Args: NoArgs, Run: emptyRun} + + _, err := executeCommand(c, "illegal") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `unknown command "illegal" for "c"` + if got != expected { + t.Errorf("Expected: %q, got: %q", expected, got) + } +} + +func TestOnlyValidArgs(t *testing.T) { + c := &Command{ + Use: "c", + Args: OnlyValidArgs, + ValidArgs: []string{"one", "two"}, + Run: emptyRun, + } + + output, err := executeCommand(c, "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestOnlyValidArgsWithInvalidArgs(t *testing.T) { + c := &Command{ + Use: "c", + Args: OnlyValidArgs, + ValidArgs: []string{"one", "two"}, + Run: emptyRun, + } + + _, err := executeCommand(c, "three") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `invalid argument "three" for "c"` + if got != expected { + t.Errorf("Expected: %q, got: %q", expected, got) + } +} + +func TestArbitraryArgs(t *testing.T) { + c := &Command{Use: "c", Args: ArbitraryArgs, Run: emptyRun} + output, err := executeCommand(c, "a", "b") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestMinimumNArgs(t *testing.T) { + c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun} + output, err := executeCommand(c, "a", "b", "c") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestMinimumNArgsWithLessArgs(t *testing.T) { + c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun} + _, err := executeCommand(c, "a") + + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := "requires at least 2 arg(s), only received 1" + if got != expected { + t.Fatalf("Expected %q, got %q", expected, got) + } +} + +func TestMaximumNArgs(t *testing.T) { + c := &Command{Use: "c", Args: MaximumNArgs(3), Run: emptyRun} + output, err := executeCommand(c, "a", "b") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestMaximumNArgsWithMoreArgs(t *testing.T) { + c := &Command{Use: "c", Args: MaximumNArgs(2), Run: emptyRun} + _, err := executeCommand(c, "a", "b", "c") + + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := "accepts at most 2 arg(s), received 3" + if got != expected { + t.Fatalf("Expected %q, got %q", expected, got) + } +} + +func TestExactArgs(t *testing.T) { + c := &Command{Use: "c", Args: ExactArgs(3), Run: emptyRun} + output, err := executeCommand(c, "a", "b", "c") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestExactArgsWithInvalidCount(t *testing.T) { + c := &Command{Use: "c", Args: ExactArgs(2), Run: emptyRun} + _, err := executeCommand(c, "a", "b", "c") + + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := "accepts 2 arg(s), received 3" + if got != expected { + t.Fatalf("Expected %q, got %q", expected, got) + } +} + +func TestRangeArgs(t *testing.T) { + c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun} + output, err := executeCommand(c, "a", "b", "c") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestRangeArgsWithInvalidCount(t *testing.T) { + c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun} + _, err := executeCommand(c, "a") + + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := "accepts between 2 and 4 arg(s), received 1" + if got != expected { + t.Fatalf("Expected %q, got %q", expected, got) + } +} + +func TestRootTakesNoArgs(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + _, err := executeCommand(rootCmd, "illegal", "args") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `unknown command "illegal" for "root"` + if !strings.Contains(got, expected) { + t.Errorf("expected %q, got %q", expected, got) + } +} + +func TestRootTakesArgs(t *testing.T) { + rootCmd := &Command{Use: "root", Args: ArbitraryArgs, Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + _, err := executeCommand(rootCmd, "legal", "args") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestChildTakesNoArgs(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Args: NoArgs, Run: emptyRun} + rootCmd.AddCommand(childCmd) + + _, err := executeCommand(rootCmd, "child", "illegal", "args") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `unknown command "illegal" for "root child"` + if !strings.Contains(got, expected) { + t.Errorf("expected %q, got %q", expected, got) + } +} + +func TestChildTakesArgs(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Args: ArbitraryArgs, Run: emptyRun} + rootCmd.AddCommand(childCmd) + + _, err := executeCommand(rootCmd, "child", "legal", "args") + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index c19fe7a0..8fa8f486 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -21,8 +21,8 @@ const ( func writePreamble(buf *bytes.Buffer, name string) { buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) - buf.WriteString(` -__debug() + buf.WriteString(fmt.Sprintf(` +__%[1]s_debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" @@ -31,13 +31,13 @@ __debug() # Homebrew on Macs have version 1.3 of bash-completion which doesn't include # _init_completion. This is a very minimal version of that function. -__my_init_completion() +__%[1]s_init_completion() { COMPREPLY=() _get_comp_words_by_ref "$@" cur prev words cword } -__index_of_word() +__%[1]s_index_of_word() { local w word=$1 shift @@ -49,7 +49,7 @@ __index_of_word() index=-1 } -__contains_word() +__%[1]s_contains_word() { local w word=$1; shift for w in "$@"; do @@ -58,9 +58,9 @@ __contains_word() return 1 } -__handle_reply() +__%[1]s_handle_reply() { - __debug "${FUNCNAME[0]}" + __%[1]s_debug "${FUNCNAME[0]}" case $cur in -*) if [[ $(type -t compopt) = "builtin" ]]; then @@ -85,7 +85,7 @@ __handle_reply() local index flag flag="${cur%%=*}" - __index_of_word "${flag}" "${flags_with_completion[@]}" + __%[1]s_index_of_word "${flag}" "${flags_with_completion[@]}" COMPREPLY=() if [[ ${index} -ge 0 ]]; then PREFIX="" @@ -103,7 +103,7 @@ __handle_reply() # check if we are handling a flag with special work handling local index - __index_of_word "${prev}" "${flags_with_completion[@]}" + __%[1]s_index_of_word "${prev}" "${flags_with_completion[@]}" if [[ ${index} -ge 0 ]]; then ${flags_completion[${index}]} return @@ -136,24 +136,30 @@ __handle_reply() if declare -F __ltrim_colon_completions >/dev/null; then __ltrim_colon_completions "$cur" fi + + # If there is only 1 completion and it is a flag with an = it will be completed + # but we don't want a space after the = + if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then + compopt -o nospace + fi } # The arguments should be in the form "ext1|ext2|extn" -__handle_filename_extension_flag() +__%[1]s_handle_filename_extension_flag() { local ext="$1" _filedir "@(${ext})" } -__handle_subdirs_in_dir_flag() +__%[1]s_handle_subdirs_in_dir_flag() { local dir="$1" pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 } -__handle_flag() +__%[1]s_handle_flag() { - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" # if a command required a flag, and we found it, unset must_have_one_flag() local flagname=${words[c]} @@ -164,27 +170,30 @@ __handle_flag() flagname=${flagname%%=*} # strip everything after the = flagname="${flagname}=" # but put the = back fi - __debug "${FUNCNAME[0]}: looking for ${flagname}" - if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then + __%[1]s_debug "${FUNCNAME[0]}: looking for ${flagname}" + if __%[1]s_contains_word "${flagname}" "${must_have_one_flag[@]}"; then must_have_one_flag=() fi # if you set a flag which only applies to this command, don't show subcommands - if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + if __%[1]s_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then commands=() fi # keep flag value with flagname as flaghash - if [ -n "${flagvalue}" ] ; then - flaghash[${flagname}]=${flagvalue} - elif [ -n "${words[ $((c+1)) ]}" ] ; then - flaghash[${flagname}]=${words[ $((c+1)) ]} - else - flaghash[${flagname}]="true" # pad "true" for bool flag + # flaghash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi fi # skip the argument to a two word flag - if __contains_word "${words[c]}" "${two_word_flags[@]}"; then + if __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then c=$((c+1)) # if we are looking for a flags value, don't show commands if [[ $c -eq $cword ]]; then @@ -196,13 +205,13 @@ __handle_flag() } -__handle_noun() +__%[1]s_handle_noun() { - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + if __%[1]s_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then must_have_one_noun=() - elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then + elif __%[1]s_contains_word "${words[c]}" "${noun_aliases[@]}"; then must_have_one_noun=() fi @@ -210,45 +219,53 @@ __handle_noun() c=$((c+1)) } -__handle_command() +__%[1]s_handle_command() { - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" local next_command if [[ -n ${last_command} ]]; then next_command="_${last_command}_${words[c]//:/__}" else if [[ $c -eq 0 ]]; then - next_command="_$(basename "${words[c]//:/__}")" + next_command="_%[1]s_root_command" else next_command="_${words[c]//:/__}" fi fi c=$((c+1)) - __debug "${FUNCNAME[0]}: looking for ${next_command}" + __%[1]s_debug "${FUNCNAME[0]}: looking for ${next_command}" declare -F "$next_command" >/dev/null && $next_command } -__handle_word() +__%[1]s_handle_word() { if [[ $c -ge $cword ]]; then - __handle_reply + __%[1]s_handle_reply return fi - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" if [[ "${words[c]}" == -* ]]; then - __handle_flag - elif __contains_word "${words[c]}" "${commands[@]}"; then - __handle_command - elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then - __handle_command + __%[1]s_handle_flag + elif __%[1]s_contains_word "${words[c]}" "${commands[@]}"; then + __%[1]s_handle_command + elif [[ $c -eq 0 ]]; then + __%[1]s_handle_command + elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then + # aliashash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + words[c]=${aliashash[${words[c]}]} + __%[1]s_handle_command + else + __%[1]s_handle_noun + fi else - __handle_noun + __%[1]s_handle_noun fi - __handle_word + __%[1]s_handle_word } -`) +`, name)) } func writePostscript(buf *bytes.Buffer, name string) { @@ -257,10 +274,11 @@ func writePostscript(buf *bytes.Buffer, name string) { buf.WriteString(fmt.Sprintf(`{ local cur prev words cword declare -A flaghash 2>/dev/null || : + declare -A aliashash 2>/dev/null || : if declare -F _init_completion >/dev/null 2>&1; then _init_completion -s || return else - __my_init_completion -n "=" || return + __%[1]s_init_completion -n "=" || return fi local c=0 @@ -269,13 +287,13 @@ func writePostscript(buf *bytes.Buffer, name string) { local local_nonpersistent_flags=() local flags_with_completion=() local flags_completion=() - local commands=("%s") + local commands=("%[1]s") local must_have_one_flag=() local must_have_one_noun=() local last_command local nouns=() - __handle_word + __%[1]s_handle_word } `, name)) @@ -296,11 +314,12 @@ func writeCommands(buf *bytes.Buffer, cmd *Command) { continue } buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) + writeCmdAliases(buf, c) } buf.WriteString("\n") } -func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string) { +func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string, cmd *Command) { for key, value := range annotations { switch key { case BashCompFilenameExt: @@ -308,7 +327,7 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s var ext string if len(value) > 0 { - ext = "__handle_filename_extension_flag " + strings.Join(value, "|") + ext = fmt.Sprintf("__%s_handle_filename_extension_flag ", cmd.Root().Name()) + strings.Join(value, "|") } else { ext = "_filedir" } @@ -326,7 +345,7 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s var ext string if len(value) == 1 { - ext = "__handle_subdirs_in_dir_flag " + value[0] + ext = fmt.Sprintf("__%s_handle_subdirs_in_dir_flag ", cmd.Root().Name()) + value[0] } else { ext = "_filedir -d" } @@ -335,7 +354,7 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s } } -func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) { +func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) { name := flag.Shorthand format := " " if len(flag.NoOptDefVal) == 0 { @@ -343,10 +362,10 @@ func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) { } format += "flags+=(\"-%s\")\n" buf.WriteString(fmt.Sprintf(format, name)) - writeFlagHandler(buf, "-"+name, flag.Annotations) + writeFlagHandler(buf, "-"+name, flag.Annotations, cmd) } -func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) { +func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) { name := flag.Name format := " flags+=(\"--%s" if len(flag.NoOptDefVal) == 0 { @@ -354,7 +373,7 @@ func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) { } format += "\")\n" buf.WriteString(fmt.Sprintf(format, name)) - writeFlagHandler(buf, "--"+name, flag.Annotations) + writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) } func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { @@ -380,9 +399,9 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) { if nonCompletableFlag(flag) { return } - writeFlag(buf, flag) + writeFlag(buf, flag, cmd) if len(flag.Shorthand) > 0 { - writeShortFlag(buf, flag) + writeShortFlag(buf, flag, cmd) } if localNonPersistentFlags.Lookup(flag.Name) != nil { writeLocalNonPersistentFlag(buf, flag) @@ -392,9 +411,9 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) { if nonCompletableFlag(flag) { return } - writeFlag(buf, flag) + writeFlag(buf, flag, cmd) if len(flag.Shorthand) > 0 { - writeShortFlag(buf, flag) + writeShortFlag(buf, flag, cmd) } }) @@ -434,6 +453,21 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { } } +func writeCmdAliases(buf *bytes.Buffer, cmd *Command) { + if len(cmd.Aliases) == 0 { + return + } + + sort.Sort(sort.StringSlice(cmd.Aliases)) + + buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n")) + for _, value := range cmd.Aliases { + buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value)) + buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) + } + buf.WriteString(` fi`) + buf.WriteString("\n") +} func writeArgAliases(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" noun_aliases=()\n") sort.Sort(sort.StringSlice(cmd.ArgAliases)) @@ -452,8 +486,18 @@ func gen(buf *bytes.Buffer, cmd *Command) { commandName := cmd.CommandPath() commandName = strings.Replace(commandName, " ", "_", -1) commandName = strings.Replace(commandName, ":", "__", -1) - buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) + + if cmd.Root() == cmd { + buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName)) + } else { + buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) + } + buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) + buf.WriteString("\n") + buf.WriteString(" command_aliases=()\n") + buf.WriteString("\n") + writeCommands(buf, cmd) writeFlags(buf, cmd) writeRequiredFlag(buf, cmd) @@ -491,17 +535,20 @@ func (c *Command) GenBashCompletionFile(filename string) error { return c.GenBashCompletion(outFile) } -// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, +// and causes your command to report an error if invoked without the flag. func (c *Command) MarkFlagRequired(name string) error { return MarkFlagRequired(c.Flags(), name) } -// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. +// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists, +// and causes your command to report an error if invoked without the flag. func (c *Command) MarkPersistentFlagRequired(name string) error { return MarkFlagRequired(c.PersistentFlags(), name) } -// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, +// and causes your command to report an error if invoked without the flag. func MarkFlagRequired(flags *pflag.FlagSet, name string) error { return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) } diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md index 52bd39dd..e79d4769 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -6,15 +6,16 @@ Generating bash completions from a cobra command is incredibly easy. An actual p package main import ( - "io/ioutil" - "os" + "io/ioutil" + "os" - "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd" + "k8s.io/kubernetes/pkg/kubectl/cmd" + "k8s.io/kubernetes/pkg/kubectl/cmd/util" ) func main() { - kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard) - kubectl.GenBashCompletionFile("out.sh") + kubectl := cmd.NewKubectlCommand(util.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) + kubectl.GenBashCompletionFile("out.sh") } ``` @@ -173,14 +174,14 @@ hello.yml test.json So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. -# Specifiy custom flag completion +# Specify custom flag completion -Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy +Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specify a custom flag completion function with cobra.BashCompCustom: ```go annotation := make(map[string][]string) - annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"} + annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} flag := &pflag.Flag{ Name: "namespace", @@ -204,3 +205,17 @@ __kubectl_get_namespaces() fi } ``` +# Using bash aliases for commands + +You can also configure the `bash aliases` for the commands and they will also support completions. + +```bash +alias aliasname=origcommand +complete -o default -F __start_origcommand aliasname + +# and now when you run `aliasname` completion will make +# suggestions as it did for `origcommand`. + +$) aliasname +completion firstcommand secondcommand +``` diff --git a/vendor/github.com/spf13/cobra/bash_completions_test.go b/vendor/github.com/spf13/cobra/bash_completions_test.go index a3b13a32..02a4f15b 100644 --- a/vendor/github.com/spf13/cobra/bash_completions_test.go +++ b/vendor/github.com/spf13/cobra/bash_completions_test.go @@ -2,21 +2,33 @@ package cobra import ( "bytes" + "fmt" "os" "os/exec" + "regexp" "strings" "testing" ) func checkOmit(t *testing.T, found, unexpected string) { if strings.Contains(found, unexpected) { - t.Errorf("Unexpected response.\nGot: %q\nBut should not have!\n", unexpected) + t.Errorf("Got: %q\nBut should not have!\n", unexpected) } } func check(t *testing.T, found, expected string) { if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + t.Errorf("Expecting to contain: \n %q\nGot:\n %q\n", expected, found) + } +} + +func checkRegex(t *testing.T, found, pattern string) { + matched, err := regexp.MatchString(pattern, found) + if err != nil { + t.Errorf("Error thrown performing MatchString: \n %s\n", err) + } + if !matched { + t.Errorf("Expecting to match: \n %q\nGot:\n %q\n", pattern, found) } } @@ -33,162 +45,173 @@ func runShellCheck(s string) error { return err } go func() { - defer stdin.Close() stdin.Write([]byte(s)) + stdin.Close() }() return cmd.Run() } // World worst custom function, just keep telling you to enter hello! -const ( - bashCompletionFunc = `__custom_func() { -COMPREPLY=( "hello" ) +const bashCompletionFunc = `__custom_func() { + COMPREPLY=( "hello" ) } ` -) func TestBashCompletions(t *testing.T) { - c := initializeWithRootCmd() - cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon) + rootCmd := &Command{ + Use: "root", + ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}, + ValidArgs: []string{"pod", "node", "service", "replicationcontroller"}, + BashCompletionFunction: bashCompletionFunc, + Run: emptyRun, + } + rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") + rootCmd.MarkFlagRequired("introot") - // custom completion function - c.BashCompletionFunction = bashCompletionFunc + // Filename. + rootCmd.Flags().String("filename", "", "Enter a filename") + rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml") - // required flag - c.MarkFlagRequired("introot") + // Persistent filename. + rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename") + rootCmd.MarkPersistentFlagFilename("persistent-filename") + rootCmd.MarkPersistentFlagRequired("persistent-filename") - // valid nouns - validArgs := []string{"pod", "node", "service", "replicationcontroller"} - c.ValidArgs = validArgs + // Filename extensions. + rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)") + rootCmd.MarkFlagFilename("filename-ext") + rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)") + rootCmd.MarkFlagCustom("custom", "__complete_custom") - // noun aliases - argAliases := []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"} - c.ArgAliases = argAliases + // Subdirectories in a given directory. + rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") + rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) - // filename - var flagval string - c.Flags().StringVar(&flagval, "filename", "", "Enter a filename") - c.MarkFlagFilename("filename", "json", "yaml", "yml") + echoCmd := &Command{ + Use: "echo [string to echo]", + Aliases: []string{"say"}, + Short: "Echo anything to the screen", + Long: "an utterly useless command for testing.", + Example: "Just run cobra-test echo", + Run: emptyRun, + } - // persistent filename - var flagvalPersistent string - c.PersistentFlags().StringVar(&flagvalPersistent, "persistent-filename", "", "Enter a filename") - c.MarkPersistentFlagFilename("persistent-filename") - c.MarkPersistentFlagRequired("persistent-filename") + echoCmd.Flags().String("filename", "", "Enter a filename") + echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml") + echoCmd.Flags().String("config", "", "config to use (located in /config/PROFILE/)") + echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"}) - // filename extensions - var flagvalExt string - c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)") - c.MarkFlagFilename("filename-ext") + printCmd := &Command{ + Use: "print [string to print]", + Args: MinimumNArgs(1), + Short: "Print anything to the screen", + Long: "an absolutely utterly useless command for testing.", + Run: emptyRun, + } - // filename extensions - var flagvalCustom string - c.Flags().StringVar(&flagvalCustom, "custom", "", "Enter a filename (extension limited)") - c.MarkFlagCustom("custom", "__complete_custom") + deprecatedCmd := &Command{ + Use: "deprecated [can't do anything here]", + Args: NoArgs, + Short: "A command which is deprecated", + Long: "an absolutely utterly useless command for testing deprecation!.", + Deprecated: "Please use echo instead", + Run: emptyRun, + } - // subdirectories in a given directory - var flagvalTheme string - c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)") - c.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) + colonCmd := &Command{ + Use: "cmd:colon", + Run: emptyRun, + } - out := new(bytes.Buffer) - c.GenBashCompletion(out) - str := out.String() + timesCmd := &Command{ + Use: "times [# times] [string to echo]", + SuggestFor: []string{"counts"}, + Args: OnlyValidArgs, + ValidArgs: []string{"one", "two", "three", "four"}, + Short: "Echo anything to the screen more times", + Long: "a slightly useless command for testing.", + Run: emptyRun, + } - check(t, str, "_cobra-test") - check(t, str, "_cobra-test_echo") - check(t, str, "_cobra-test_echo_times") - check(t, str, "_cobra-test_print") - check(t, str, "_cobra-test_cmd__colon") + echoCmd.AddCommand(timesCmd) + rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd) + + buf := new(bytes.Buffer) + rootCmd.GenBashCompletion(buf) + output := buf.String() + + check(t, output, "_root") + check(t, output, "_root_echo") + check(t, output, "_root_echo_times") + check(t, output, "_root_print") + check(t, output, "_root_cmd__colon") // check for required flags - check(t, str, `must_have_one_flag+=("--introot=")`) - check(t, str, `must_have_one_flag+=("--persistent-filename=")`) + check(t, output, `must_have_one_flag+=("--introot=")`) + check(t, output, `must_have_one_flag+=("--persistent-filename=")`) // check for custom completion function - check(t, str, `COMPREPLY=( "hello" )`) + check(t, output, `COMPREPLY=( "hello" )`) // check for required nouns - check(t, str, `must_have_one_noun+=("pod")`) + check(t, output, `must_have_one_noun+=("pod")`) // check for noun aliases - check(t, str, `noun_aliases+=("pods")`) - check(t, str, `noun_aliases+=("rc")`) - checkOmit(t, str, `must_have_one_noun+=("pods")`) + check(t, output, `noun_aliases+=("pods")`) + check(t, output, `noun_aliases+=("rc")`) + checkOmit(t, output, `must_have_one_noun+=("pods")`) // check for filename extension flags - check(t, str, `flags_completion+=("_filedir")`) + check(t, output, `flags_completion+=("_filedir")`) // check for filename extension flags - check(t, str, `must_have_one_noun+=("three")`) + check(t, output, `must_have_one_noun+=("three")`) // check for filename extension flags - check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`) + check(t, output, fmt.Sprintf(`flags_completion+=("__%s_handle_filename_extension_flag json|yaml|yml")`, rootCmd.Name())) + // check for filename extension flags in a subcommand + checkRegex(t, output, fmt.Sprintf(`_root_echo\(\)\n{[^}]*flags_completion\+=\("__%s_handle_filename_extension_flag json\|yaml\|yml"\)`, rootCmd.Name())) // check for custom flags - check(t, str, `flags_completion+=("__complete_custom")`) + check(t, output, `flags_completion+=("__complete_custom")`) // check for subdirs_in_dir flags - check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`) + check(t, output, fmt.Sprintf(`flags_completion+=("__%s_handle_subdirs_in_dir_flag themes")`, rootCmd.Name())) + // check for subdirs_in_dir flags in a subcommand + checkRegex(t, output, fmt.Sprintf(`_root_echo\(\)\n{[^}]*flags_completion\+=\("__%s_handle_subdirs_in_dir_flag config"\)`, rootCmd.Name())) - checkOmit(t, str, cmdDeprecated.Name()) + checkOmit(t, output, deprecatedCmd.Name()) - // if available, run shellcheck against the script + // If available, run shellcheck against the script. if err := exec.Command("which", "shellcheck").Run(); err != nil { return } - err := runShellCheck(str) - if err != nil { + if err := runShellCheck(output); err != nil { t.Fatalf("shellcheck failed: %v", err) } } func TestBashCompletionHiddenFlag(t *testing.T) { - var cmdTrue = &Command{ - Use: "does nothing", - Run: func(cmd *Command, args []string) {}, - } + c := &Command{Use: "c", Run: emptyRun} - const flagName = "hidden-foo-bar-baz" + const flagName = "hiddenFlag" + c.Flags().Bool(flagName, false, "") + c.Flags().MarkHidden(flagName) - var flagValue bool - cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag") - cmdTrue.Flags().MarkHidden(flagName) + buf := new(bytes.Buffer) + c.GenBashCompletion(buf) + output := buf.String() - out := new(bytes.Buffer) - cmdTrue.GenBashCompletion(out) - bashCompletion := out.String() - if strings.Contains(bashCompletion, flagName) { - t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion) + if strings.Contains(output, flagName) { + t.Errorf("Expected completion to not include %q flag: Got %v", flagName, output) } } func TestBashCompletionDeprecatedFlag(t *testing.T) { - var cmdTrue = &Command{ - Use: "does nothing", - Run: func(cmd *Command, args []string) {}, - } + c := &Command{Use: "c", Run: emptyRun} - const flagName = "deprecated-foo-bar-baz" - - var flagValue bool - cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag") - cmdTrue.Flags().MarkDeprecated(flagName, "use --does-not-exist instead") - - out := new(bytes.Buffer) - cmdTrue.GenBashCompletion(out) - bashCompletion := out.String() - if strings.Contains(bashCompletion, flagName) { - t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion) - } -} - -func BenchmarkBashCompletion(b *testing.B) { - c := initializeWithRootCmd() - cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon) + const flagName = "deprecated-flag" + c.Flags().Bool(flagName, false, "") + c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead") buf := new(bytes.Buffer) + c.GenBashCompletion(buf) + output := buf.String() - b.ResetTimer() - for i := 0; i < b.N; i++ { - buf.Reset() - if err := c.GenBashCompletion(buf); err != nil { - b.Fatal(err) - } + if strings.Contains(output, flagName) { + t.Errorf("expected completion to not include %q flag: Got %v", flagName, output) } } diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index 8928cefc..7010fd15 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -70,7 +70,8 @@ func AddTemplateFuncs(tmplFuncs template.FuncMap) { } } -// OnInitialize takes a series of func() arguments and appends them to a slice of func(). +// OnInitialize sets the passed functions to be run when each command's +// Execute method is called. func OnInitialize(y ...func()) { initializers = append(initializers, y...) } @@ -188,3 +189,12 @@ func ld(s, t string, ignoreCase bool) int { } return d[len(s)][len(t)] } + +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/add.go b/vendor/github.com/spf13/cobra/cobra/cmd/add.go index 993ae16f..fb22096a 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/add.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/add.go @@ -24,7 +24,7 @@ import ( func init() { addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") - addCmd.Flags().StringVarP(&parentName, "parent", "p", "RootCmd", "variable name of parent command for this command") + addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") } var packageName, parentName string @@ -35,7 +35,7 @@ var addCmd = &cobra.Command{ Short: "Add a command to a Cobra Application", Long: `Add (cobra add) will create a new command, with a license and the appropriate structure for a Cobra-based CLI application, -and register it to its parent (default RootCmd). +and register it to its parent (default rootCmd). If you want your command to be public, pass in the command name with an initial uppercase letter. diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go b/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go index e5b37ec7..cd94b3e3 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go @@ -24,7 +24,6 @@ import ( "text/template" ) -var cmdDirs = [...]string{"cmd", "cmds", "command", "commands"} var srcPaths []string func init() { @@ -128,8 +127,6 @@ func writeStringToFile(path string, s string) error { // writeToFile writes r to file with path only // if file/directory on given path doesn't exist. -// If file/directory exists on given path, then -// it terminates app and prints an appropriate error. func writeToFile(path string, r io.Reader) error { if exists(path) { return fmt.Errorf("%v already exists", path) diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/init.go b/vendor/github.com/spf13/cobra/cobra/cmd/init.go index 149aabe1..d65e6c8c 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/init.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/init.go @@ -65,7 +65,7 @@ Init will not use an existing directory with contents.`, initializeProject(project) fmt.Fprintln(cmd.OutOrStdout(), `Your Cobra application is ready at -`+project.AbsPath()+`. +`+project.AbsPath()+` Give it a try by going there and running `+"`go run main.go`."+` Add commands to it by running `+"`cobra add [cmdname]`.") @@ -150,8 +150,8 @@ import ( var cfgFile string{{end}} -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ Use: "{{.appName}}", Short: "A brief description of your application", Long: ` + "`" + `A longer description that spans multiple lines and likely contains @@ -168,24 +168,24 @@ to quickly create a Cobra application.` + "`" + `, // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - if err := RootCmd.Execute(); err != nil { + if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } -func init() { {{if .viper}} +func init() { {{- if .viper}} cobra.OnInitialize(initConfig) {{end}} // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application.{{ if .viper }} - RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ else }} - // RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ end }} + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ else }} + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ end }} // Cobra also supports local flags, which will only run // when this action is called directly. - RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") }{{ if .viper }} // initConfig reads in config file and ENV variables if set. diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/project.go b/vendor/github.com/spf13/cobra/cobra/cmd/project.go index de1168a1..7ddb8258 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/project.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/project.go @@ -17,10 +17,9 @@ type Project struct { } // NewProject returns Project with specified project name. -// If projectName is blank string, it returns nil. func NewProject(projectName string) *Project { if projectName == "" { - return nil + er("can't create project with blank name") } p := new(Project) @@ -54,8 +53,6 @@ func NewProject(projectName string) *Project { } // findPackage returns full path to existing go package in GOPATHs. -// findPackage returns "", if it can't find path. -// If packageName is "", findPackage returns "". func findPackage(packageName string) string { if packageName == "" { return "" @@ -73,16 +70,29 @@ func findPackage(packageName string) string { // NewProjectFromPath returns Project with specified absolute path to // package. -// If absPath is blank string or if absPath is not actually absolute, -// it returns nil. func NewProjectFromPath(absPath string) *Project { - if absPath == "" || !filepath.IsAbs(absPath) { - return nil + if absPath == "" { + er("can't create project: absPath can't be blank") + } + if !filepath.IsAbs(absPath) { + er("can't create project: absPath is not absolute") + } + + // If absPath is symlink, use its destination. + fi, err := os.Lstat(absPath) + if err != nil { + er("can't read path info: " + err.Error()) + } + if fi.Mode()&os.ModeSymlink != 0 { + path, err := os.Readlink(absPath) + if err != nil { + er("can't read the destination of symlink: " + err.Error()) + } + absPath = path } p := new(Project) - p.absPath = absPath - p.absPath = strings.TrimSuffix(p.absPath, findCmdDir(p.absPath)) + p.absPath = strings.TrimSuffix(absPath, findCmdDir(absPath)) p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath())) return p } @@ -91,7 +101,7 @@ func NewProjectFromPath(absPath string) *Project { func trimSrcPath(absPath, srcPath string) string { relPath, err := filepath.Rel(srcPath, absPath) if err != nil { - er("Cobra supports project only within $GOPATH: " + err.Error()) + er(err) } return relPath } @@ -101,7 +111,6 @@ func (p *Project) License() License { if p.license.Text == "" && p.license.Name != "None" { p.license = getLicense() } - return p.license } @@ -111,8 +120,6 @@ func (p Project) Name() string { } // CmdPath returns absolute path to directory, where all commands are located. -// -// CmdPath returns blank string, only if p.AbsPath() is a blank string. func (p *Project) CmdPath() string { if p.absPath == "" { return "" @@ -125,8 +132,6 @@ func (p *Project) CmdPath() string { // findCmdDir checks if base of absPath is cmd dir and returns it or // looks for existing cmd dir in absPath. -// If the cmd dir doesn't exist, empty, or cannot be found, -// it returns "cmd". func findCmdDir(absPath string) string { if !exists(absPath) || isEmpty(absPath) { return "cmd" @@ -149,7 +154,7 @@ func findCmdDir(absPath string) string { // isCmdDir checks if base of name is one of cmdDir. func isCmdDir(name string) bool { name = filepath.Base(name) - for _, cmdDir := range cmdDirs { + for _, cmdDir := range []string{"cmd", "cmds", "command", "commands"} { if name == cmdDir { return true } diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden index 8eeeae89..d74f4cd4 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden +++ b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden @@ -25,8 +25,8 @@ import ( var cfgFile string -// RootCmd represents the base command when called without any subcommands -var RootCmd = &cobra.Command{ +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ Use: "testproject", Short: "A brief description of your application", Long: `A longer description that spans multiple lines and likely contains @@ -43,23 +43,23 @@ to quickly create a Cobra application.`, // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - if err := RootCmd.Execute(); err != nil { + if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } -func init() { +func init() { cobra.OnInitialize(initConfig) // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. - RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.testproject.yaml)") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.testproject.yaml)") // Cobra also supports local flags, which will only run // when this action is called directly. - RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } // initConfig reads in config file and ENV variables if set. diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden index 58405680..ed644275 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden +++ b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden @@ -36,7 +36,7 @@ to quickly create a Cobra application.`, } func init() { - RootCmd.AddCommand(testCmd) + rootCmd.AddCommand(testCmd) // Here you will define your flags and configuration settings. diff --git a/vendor/github.com/spf13/cobra/cobra_test.go b/vendor/github.com/spf13/cobra/cobra_test.go index 8192b526..0d1755bd 100644 --- a/vendor/github.com/spf13/cobra/cobra_test.go +++ b/vendor/github.com/spf13/cobra/cobra_test.go @@ -1,1270 +1,10 @@ package cobra import ( - "bytes" - "fmt" - "os" - "reflect" - "runtime" - "strings" "testing" "text/template" - - "github.com/spf13/pflag" ) -var tp, te, tt, tr []string -var rootPersPre, echoPre, echoPersPre, timesPersPre []string -var flagb1, flagb2, flagb3, flagbr, flagbp bool -var flags1, flags2a, flags2b, flags3, outs string -var flagi1, flagi2, flagi3, flagi4, flagir int -var rootcalled bool -var versionUsed int - -const strtwoParentHelp = "help message for parent flag strtwo" -const strtwoChildHelp = "help message for child flag strtwo" - -var cmdHidden = &Command{ - Use: "hide [secret string to print]", - Short: "Print anything to screen (if command is known)", - Long: `an absolutely utterly useless command for testing.`, - Run: func(cmd *Command, args []string) { - outs = "hidden" - }, - Hidden: true, -} - -var cmdPrint = &Command{ - Use: "print [string to print]", - Args: MinimumNArgs(1), - Short: "Print anything to the screen", - Long: `an absolutely utterly useless command for testing.`, - Run: func(cmd *Command, args []string) { - tp = args - }, -} - -var cmdEcho = &Command{ - Use: "echo [string to echo]", - Aliases: []string{"say"}, - Short: "Echo anything to the screen", - Long: `an utterly useless command for testing.`, - Example: "Just run cobra-test echo", - PersistentPreRun: func(cmd *Command, args []string) { - echoPersPre = args - }, - PreRun: func(cmd *Command, args []string) { - echoPre = args - }, - Run: func(cmd *Command, args []string) { - te = args - }, -} - -var cmdEchoSub = &Command{ - Use: "echosub [string to print]", - Short: "second sub command for echo", - Long: `an absolutely utterly useless command for testing gendocs!.`, - Run: func(cmd *Command, args []string) { - }, -} - -var cmdDeprecated = &Command{ - Use: "deprecated [can't do anything here]", - Short: "A command which is deprecated", - Long: `an absolutely utterly useless command for testing deprecation!.`, - Deprecated: "Please use echo instead", - Run: func(cmd *Command, args []string) { - }, - Args: NoArgs, -} - -var cmdTimes = &Command{ - Use: "times [# times] [string to echo]", - SuggestFor: []string{"counts"}, - Short: "Echo anything to the screen more times", - Long: `a slightly useless command for testing.`, - PersistentPreRun: func(cmd *Command, args []string) { - timesPersPre = args - }, - Run: func(cmd *Command, args []string) { - tt = args - }, - Args: OnlyValidArgs, - ValidArgs: []string{"one", "two", "three", "four"}, -} - -var cmdRootNoRun = &Command{ - Use: "cobra-test", - Short: "The root can run its own function", - Long: "The root description for help", - PersistentPreRun: func(cmd *Command, args []string) { - rootPersPre = args - }, -} - -var cmdRootSameName = &Command{ - Use: "print", - Short: "Root with the same name as a subcommand", - Long: "The root description for help", -} - -var cmdRootTakesArgs = &Command{ - Use: "root-with-args [random args]", - Short: "The root can run it's own function and takes args!", - Long: "The root description for help, and some args", - Run: func(cmd *Command, args []string) { - tr = args - }, - Args: ArbitraryArgs, -} - -var cmdRootWithRun = &Command{ - Use: "cobra-test", - Short: "The root can run its own function", - Long: "The root description for help", - Run: func(cmd *Command, args []string) { - tr = args - rootcalled = true - }, -} - -var cmdSubNoRun = &Command{ - Use: "subnorun", - Short: "A subcommand without a Run function", - Long: "A long output about a subcommand without a Run function", -} - -var cmdCustomFlags = &Command{ - Use: "customflags [flags] -- REMOTE_COMMAND", - Short: "A command that expects flags in a custom location", - Long: "A long output about a command that expects flags in a custom location", - Run: func(cmd *Command, args []string) { - }, -} - -var cmdVersion1 = &Command{ - Use: "version", - Short: "Print the version number", - Long: `First version of the version command`, - Run: func(cmd *Command, args []string) { - versionUsed = 1 - }, -} - -var cmdVersion2 = &Command{ - Use: "version", - Short: "Print the version number", - Long: `Second version of the version command`, - Run: func(cmd *Command, args []string) { - versionUsed = 2 - }, -} - -var cmdColon = &Command{ - Use: "cmd:colon", - Run: func(cmd *Command, args []string) { - }, -} - -func flagInit() { - cmdEcho.ResetFlags() - cmdPrint.ResetFlags() - cmdTimes.ResetFlags() - cmdRootNoRun.ResetFlags() - cmdRootSameName.ResetFlags() - cmdRootWithRun.ResetFlags() - cmdSubNoRun.ResetFlags() - cmdCustomFlags.ResetFlags() - cmdVersion1.ResetFlags() - cmdVersion2.ResetFlags() - - cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp) - cmdCustomFlags.Flags().IntVar(&flagi4, "intfour", 456, "help message for flag intfour") - cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone") - cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone") - cmdEcho.PersistentFlags().BoolVarP(&flagbp, "persistentbool", "p", false, "help message for flag persistentbool") - cmdEcho.PersistentFlags().StringVarP(&flags1, "strone", "s", "one", "help message for flag strone") - cmdPrint.Flags().IntVarP(&flagi3, "intthree", "i", 345, "help message for flag intthree") - cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo") - cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo") - cmdTimes.Flags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp) - cmdTimes.PersistentFlags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp) - cmdTimes.LocalFlags() // populate lflags before parent is set - cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree") - cmdPrint.PersistentFlags().StringVarP(&flags3, "strthree", "s", "three", "help message for flag strthree") -} - -func commandInit() { - cmdEcho.ResetCommands() - cmdPrint.ResetCommands() - cmdTimes.ResetCommands() - cmdRootNoRun.ResetCommands() - cmdRootSameName.ResetCommands() - cmdRootWithRun.ResetCommands() - cmdSubNoRun.ResetCommands() - cmdCustomFlags.ResetCommands() -} - -func initialize() *Command { - tt, tp, te = nil, nil, nil - rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil - - var c = cmdRootNoRun - commandInit() - flagInit() - return c -} - -func initializeWithSameName() *Command { - tt, tp, te = nil, nil, nil - rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil - var c = cmdRootSameName - commandInit() - flagInit() - return c -} - -func initializeWithRootCmd() *Command { - cmdRootWithRun.ResetCommands() - tt, tp, te, tr, rootcalled = nil, nil, nil, nil, false - flagInit() - cmdRootWithRun.Flags().BoolVarP(&flagbr, "boolroot", "b", false, "help message for flag boolroot") - cmdRootWithRun.Flags().IntVarP(&flagir, "introot", "i", 321, "help message for flag introot") - commandInit() - return cmdRootWithRun -} - -type resulter struct { - Error error - Output string - Command *Command -} - -func fullSetupTest(args ...string) resulter { - c := initializeWithRootCmd() - - return fullTester(c, args...) -} - -func noRRSetupTestSilenced(args ...string) resulter { - c := initialize() - c.SilenceErrors = true - c.SilenceUsage = true - return fullTester(c, args...) -} - -func noRRSetupTest(args ...string) resulter { - c := initialize() - - return fullTester(c, args...) -} - -func rootOnlySetupTest(args ...string) resulter { - c := initializeWithRootCmd() - - return simpleTester(c, args...) -} - -func simpleTester(c *Command, args ...string) resulter { - buf := new(bytes.Buffer) - // Testing flag with invalid input - c.SetOutput(buf) - c.SetArgs(args) - - err := c.Execute() - output := buf.String() - - return resulter{err, output, c} -} - -func simpleTesterC(c *Command, args ...string) resulter { - buf := new(bytes.Buffer) - // Testing flag with invalid input - c.SetOutput(buf) - c.SetArgs(args) - - cmd, err := c.ExecuteC() - output := buf.String() - - return resulter{err, output, cmd} -} - -func fullTester(c *Command, args ...string) resulter { - buf := new(bytes.Buffer) - // Testing flag with invalid input - c.SetOutput(buf) - cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun, cmdCustomFlags, cmdDeprecated) - c.SetArgs(args) - - err := c.Execute() - output := buf.String() - - return resulter{err, output, c} -} - -func logErr(t *testing.T, found, expected string) { - out := new(bytes.Buffer) - - _, _, line, ok := runtime.Caller(2) - if ok { - fmt.Fprintf(out, "Line: %d ", line) - } - fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - t.Errorf(out.String()) -} - -func checkStringContains(t *testing.T, found, expected string) { - if !strings.Contains(found, expected) { - logErr(t, found, expected) - } -} - -func checkResultContains(t *testing.T, x resulter, check string) { - checkStringContains(t, x.Output, check) -} - -func checkStringOmits(t *testing.T, found, expected string) { - if strings.Contains(found, expected) { - logErr(t, found, expected) - } -} - -func checkResultOmits(t *testing.T, x resulter, check string) { - checkStringOmits(t, x.Output, check) -} - -func checkOutputContains(t *testing.T, c *Command, check string) { - buf := new(bytes.Buffer) - c.SetOutput(buf) - c.Execute() - - if !strings.Contains(buf.String(), check) { - logErr(t, buf.String(), check) - } -} - -func TestSingleCommand(t *testing.T) { - noRRSetupTest("print", "one", "two") - - if te != nil || tt != nil { - t.Error("Wrong command called") - } - if tp == nil { - t.Error("Wrong command called") - } - if strings.Join(tp, " ") != "one two" { - t.Error("Command didn't parse correctly") - } -} - -func TestChildCommand(t *testing.T) { - noRRSetupTest("echo", "times", "one", "two") - - if te != nil || tp != nil { - t.Error("Wrong command called") - } - if tt == nil { - t.Error("Wrong command called") - } - if strings.Join(tt, " ") != "one two" { - t.Error("Command didn't parse correctly") - } -} - -func TestCommandAlias(t *testing.T) { - noRRSetupTest("say", "times", "one", "two") - - if te != nil || tp != nil { - t.Error("Wrong command called") - } - if tt == nil { - t.Error("Wrong command called") - } - if strings.Join(tt, " ") != "one two" { - t.Error("Command didn't parse correctly") - } -} - -func TestPrefixMatching(t *testing.T) { - EnablePrefixMatching = true - noRRSetupTest("ech", "times", "one", "two") - - if te != nil || tp != nil { - t.Error("Wrong command called") - } - if tt == nil { - t.Error("Wrong command called") - } - if strings.Join(tt, " ") != "one two" { - t.Error("Command didn't parse correctly") - } - - EnablePrefixMatching = false -} - -func TestNoPrefixMatching(t *testing.T) { - EnablePrefixMatching = false - - noRRSetupTest("ech", "times", "one", "two") - - if !(tt == nil && te == nil && tp == nil) { - t.Error("Wrong command called") - } -} - -func TestAliasPrefixMatching(t *testing.T) { - EnablePrefixMatching = true - noRRSetupTest("sa", "times", "one", "two") - - if te != nil || tp != nil { - t.Error("Wrong command called") - } - if tt == nil { - t.Error("Wrong command called") - } - if strings.Join(tt, " ") != "one two" { - t.Error("Command didn't parse correctly") - } - EnablePrefixMatching = false -} - -func TestChildSameName(t *testing.T) { - c := initializeWithSameName() - c.AddCommand(cmdPrint, cmdEcho) - c.SetArgs([]string{"print", "one", "two"}) - c.Execute() - - if te != nil || tt != nil { - t.Error("Wrong command called") - } - if tp == nil { - t.Error("Wrong command called") - } - if strings.Join(tp, " ") != "one two" { - t.Error("Command didn't parse correctly") - } -} - -func TestGrandChildSameName(t *testing.T) { - c := initializeWithSameName() - cmdTimes.AddCommand(cmdPrint) - c.AddCommand(cmdTimes) - c.SetArgs([]string{"times", "print", "one", "two"}) - c.Execute() - - if te != nil || tt != nil { - t.Error("Wrong command called") - } - if tp == nil { - t.Error("Wrong command called") - } - if strings.Join(tp, " ") != "one two" { - t.Error("Command didn't parse correctly") - } -} - -func TestUsage(t *testing.T) { - x := fullSetupTest("help") - checkResultContains(t, x, cmdRootWithRun.Use+" [flags]") - x = fullSetupTest("help", "customflags") - checkResultContains(t, x, cmdCustomFlags.Use) - checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]") -} - -func TestRootTakesNoArgs(t *testing.T) { - c := initializeWithSameName() - c.AddCommand(cmdPrint, cmdEcho) - result := simpleTester(c, "illegal") - - if result.Error == nil { - t.Fatal("Expected an error") - } - - expectedError := `unknown command "illegal" for "print"` - if !strings.Contains(result.Error.Error(), expectedError) { - t.Errorf("exptected %v, got %v", expectedError, result.Error.Error()) - } -} - -func TestRootTakesArgs(t *testing.T) { - c := cmdRootTakesArgs - result := simpleTester(c, "legal") - - if result.Error != nil { - t.Errorf("expected no error, but got %v", result.Error) - } -} - -func TestSubCmdTakesNoArgs(t *testing.T) { - result := fullSetupTest("deprecated", "illegal") - - if result.Error == nil { - t.Fatal("Expected an error") - } - - expectedError := `unknown command "illegal" for "cobra-test deprecated"` - if !strings.Contains(result.Error.Error(), expectedError) { - t.Errorf("expected %v, got %v", expectedError, result.Error.Error()) - } -} - -func TestSubCmdTakesArgs(t *testing.T) { - noRRSetupTest("echo", "times", "one", "two") - if strings.Join(tt, " ") != "one two" { - t.Error("Command didn't parse correctly") - } -} - -func TestCmdOnlyValidArgs(t *testing.T) { - result := noRRSetupTest("echo", "times", "one", "two", "five") - - if result.Error == nil { - t.Fatal("Expected an error") - } - - expectedError := `invalid argument "five"` - if !strings.Contains(result.Error.Error(), expectedError) { - t.Errorf("expected %v, got %v", expectedError, result.Error.Error()) - } -} - -func TestFlagLong(t *testing.T) { - noRRSetupTest("echo", "--intone=13", "something", "--", "here") - - if cmdEcho.ArgsLenAtDash() != 1 { - t.Errorf("expected argsLenAtDash: %d but got %d", 1, cmdRootNoRun.ArgsLenAtDash()) - } - if strings.Join(te, " ") != "something here" { - t.Errorf("flags didn't leave proper args remaining..%s given", te) - } - if flagi1 != 13 { - t.Errorf("int flag didn't get correct value, had %d", flagi1) - } - if flagi2 != 234 { - t.Errorf("default flag value changed, 234 expected, %d given", flagi2) - } -} - -func TestFlagShort(t *testing.T) { - noRRSetupTest("echo", "-i13", "--", "something", "here") - - if cmdEcho.ArgsLenAtDash() != 0 { - t.Errorf("expected argsLenAtDash: %d but got %d", 0, cmdRootNoRun.ArgsLenAtDash()) - } - if strings.Join(te, " ") != "something here" { - t.Errorf("flags didn't leave proper args remaining..%s given", te) - } - if flagi1 != 13 { - t.Errorf("int flag didn't get correct value, had %d", flagi1) - } - if flagi2 != 234 { - t.Errorf("default flag value changed, 234 expected, %d given", flagi2) - } - - noRRSetupTest("echo", "-i", "13", "something", "here") - - if strings.Join(te, " ") != "something here" { - t.Errorf("flags didn't leave proper args remaining..%s given", te) - } - if flagi1 != 13 { - t.Errorf("int flag didn't get correct value, had %d", flagi1) - } - if flagi2 != 234 { - t.Errorf("default flag value changed, 234 expected, %d given", flagi2) - } - - noRRSetupTest("print", "-i99", "one", "two") - - if strings.Join(tp, " ") != "one two" { - t.Errorf("flags didn't leave proper args remaining..%s given", tp) - } - if flagi3 != 99 { - t.Errorf("int flag didn't get correct value, had %d", flagi3) - } - if flagi1 != 123 { - t.Errorf("default flag value changed on different command with same shortname, 234 expected, %d given", flagi2) - } -} - -func TestChildCommandFlags(t *testing.T) { - noRRSetupTest("echo", "times", "-j", "99", "one", "two") - - if strings.Join(tt, " ") != "one two" { - t.Errorf("flags didn't leave proper args remaining..%s given", tt) - } - - // Testing with flag that shouldn't be persistent - r := noRRSetupTest("echo", "times", "-j", "99", "-i77", "one", "two") - - if r.Error == nil { - t.Errorf("invalid flag should generate error") - } - - if !strings.Contains(r.Error.Error(), "unknown shorthand") { - t.Errorf("Wrong error message displayed, \n %s", r.Error) - } - - if flagi2 != 99 { - t.Errorf("flag value should be 99, %d given", flagi2) - } - - if flagi1 != 123 { - t.Errorf("unset flag should have default value, expecting 123, given %d", flagi1) - } - - // Testing with flag only existing on child - r = noRRSetupTest("echo", "-j", "99", "-i77", "one", "two") - - if r.Error == nil { - t.Errorf("invalid flag should generate error") - } - if !strings.Contains(r.Error.Error(), "unknown shorthand flag") { - t.Errorf("Wrong error message displayed, \n %s", r.Error) - } - - // Testing with persistent flag overwritten by child - noRRSetupTest("echo", "times", "--strtwo=child", "one", "two") - - if flags2b != "child" { - t.Errorf("flag value should be child, %s given", flags2b) - } - - if flags2a != "two" { - t.Errorf("unset flag should have default value, expecting two, given %s", flags2a) - } - - // Testing flag with invalid input - r = noRRSetupTest("echo", "-i10E") - - if r.Error == nil { - t.Errorf("invalid input should generate error") - } - if !strings.Contains(r.Error.Error(), "invalid syntax") { - t.Errorf("Wrong error message displayed, \n %s", r.Error) - } -} - -func TestTrailingCommandFlags(t *testing.T) { - x := fullSetupTest("echo", "two", "-x") - - if x.Error == nil { - t.Errorf("invalid flag should generate error") - } -} - -func TestInvalidSubcommandFlags(t *testing.T) { - cmd := initializeWithRootCmd() - cmd.AddCommand(cmdTimes) - - result := simpleTester(cmd, "times", "--inttwo=2", "--badflag=bar") - // given that we are not checking here result.Error we check for - // stock usage message - checkResultContains(t, result, "cobra-test times [# times]") - if strings.Contains(result.Error.Error(), "unknown flag: --inttwo") { - t.Errorf("invalid --badflag flag shouldn't fail on 'unknown' --inttwo flag") - } - -} - -func TestSubcommandExecuteC(t *testing.T) { - cmd := initializeWithRootCmd() - double := &Command{ - Use: "double message", - Run: func(c *Command, args []string) { - msg := strings.Join(args, " ") - c.Println(msg, msg) - }, - } - - echo := &Command{ - Use: "echo message", - Run: func(c *Command, args []string) { - msg := strings.Join(args, " ") - c.Println(msg) - }, - } - - cmd.AddCommand(double, echo) - - result := simpleTesterC(cmd, "double", "hello", "world") - checkResultContains(t, result, "hello world hello world") - - if result.Command.Name() != "double" { - t.Errorf("invalid cmd returned from ExecuteC: should be 'double' but got %s", result.Command.Name()) - } - - result = simpleTesterC(cmd, "echo", "msg", "to", "be", "echoed") - checkResultContains(t, result, "msg to be echoed") - - if result.Command.Name() != "echo" { - t.Errorf("invalid cmd returned from ExecuteC: should be 'echo' but got %s", result.Command.Name()) - } -} - -func TestSubcommandArgEvaluation(t *testing.T) { - cmd := initializeWithRootCmd() - - first := &Command{ - Use: "first", - Run: func(cmd *Command, args []string) { - }, - } - cmd.AddCommand(first) - - second := &Command{ - Use: "second", - Run: func(cmd *Command, args []string) { - fmt.Fprintf(cmd.OutOrStdout(), "%v", args) - }, - } - first.AddCommand(second) - - result := simpleTester(cmd, "first", "second", "first", "third") - - expectedOutput := fmt.Sprint([]string{"first third"}) - if result.Output != expectedOutput { - t.Errorf("exptected %v, got %v", expectedOutput, result.Output) - } -} - -func TestPersistentFlags(t *testing.T) { - fullSetupTest("echo", "-s", "something", "-p", "more", "here") - - // persistentFlag should act like normal flag on its own command - if strings.Join(te, " ") != "more here" { - t.Errorf("flags didn't leave proper args remaining..%s given", te) - } - if flags1 != "something" { - t.Errorf("string flag didn't get correct value, had %v", flags1) - } - if !flagbp { - t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp) - } - - // persistentFlag should act like normal flag on its own command - fullSetupTest("echo", "times", "-s", "again", "-c", "-p", "one", "two") - - if strings.Join(tt, " ") != "one two" { - t.Errorf("flags didn't leave proper args remaining. %s given", tt) - } - - if flags1 != "again" { - t.Errorf("string flag didn't get correct value, had %v", flags1) - } - - if !flagb2 { - t.Errorf("local flag not parsed correctly. Expected true, had %v", flagb2) - } - if !flagbp { - t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp) - } -} - -func TestHelpCommand(t *testing.T) { - x := fullSetupTest("help") - checkResultContains(t, x, cmdRootWithRun.Long) - - x = fullSetupTest("help", "echo") - checkResultContains(t, x, cmdEcho.Long) - - x = fullSetupTest("help", "echo", "times") - checkResultContains(t, x, cmdTimes.Long) -} - -func TestChildCommandHelp(t *testing.T) { - c := noRRSetupTest("print", "--help") - checkResultContains(t, c, strtwoParentHelp) - r := noRRSetupTest("echo", "times", "--help") - checkResultContains(t, r, strtwoChildHelp) -} - -func TestNonRunChildHelp(t *testing.T) { - x := noRRSetupTest("subnorun") - checkResultContains(t, x, cmdSubNoRun.Long) -} - -func TestRunnableRootCommand(t *testing.T) { - x := fullSetupTest("") - - if !rootcalled { - t.Errorf("Root Function was not called\n out:%v", x.Error) - } -} - -func TestVisitParents(t *testing.T) { - c := &Command{Use: "app"} - sub := &Command{Use: "sub"} - dsub := &Command{Use: "dsub"} - sub.AddCommand(dsub) - c.AddCommand(sub) - total := 0 - add := func(x *Command) { - total++ - } - sub.VisitParents(add) - if total != 1 { - t.Errorf("Should have visited 1 parent but visited %d", total) - } - - total = 0 - dsub.VisitParents(add) - if total != 2 { - t.Errorf("Should have visited 2 parent but visited %d", total) - } - - total = 0 - c.VisitParents(add) - if total != 0 { - t.Errorf("Should have not visited any parent but visited %d", total) - } -} - -func TestRunnableRootCommandNilInput(t *testing.T) { - c := initializeWithRootCmd() - - buf := new(bytes.Buffer) - // Testing flag with invalid input - c.SetOutput(buf) - cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdPrint, cmdEcho) - c.SetArgs([]string{}) - - err := c.Execute() - if err != nil { - t.Errorf("Execute() failed with %v", err) - } - - if !rootcalled { - t.Errorf("Root Function was not called") - } -} - -func TestRunnableRootCommandEmptyInput(t *testing.T) { - args := []string{"", "--introot=12", ""} - c := initializeWithRootCmd() - - buf := new(bytes.Buffer) - // Testing flag with invalid input - c.SetOutput(buf) - cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdPrint, cmdEcho) - c.SetArgs(args) - - c.Execute() - - if !rootcalled { - t.Errorf("Root Function was not called.\nOutput was:\n%s\n", buf) - } -} - -func TestInvalidSubcommandWhenArgsAllowed(t *testing.T) { - fullSetupTest("echo", "invalid-sub") - - if te[0] != "invalid-sub" { - t.Errorf("Subcommand didn't work...") - } -} - -func TestRootFlags(t *testing.T) { - fullSetupTest("-i", "17", "-b") - - if !flagbr { - t.Errorf("flag value should be true, %v given", flagbr) - } - - if flagir != 17 { - t.Errorf("flag value should be 17, %d given", flagir) - } -} - -func TestRootHelp(t *testing.T) { - x := fullSetupTest("--help") - - checkResultContains(t, x, "Available Commands:") - checkResultContains(t, x, "for more information about a command") - - if strings.Contains(x.Output, "unknown flag: --help") { - t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) - } - - if strings.Contains(x.Output, cmdEcho.Use) { - t.Errorf("--help shouldn't display subcommand's usage, Got: \n %s", x.Output) - } - - x = fullSetupTest("echo", "--help") - - if strings.Contains(x.Output, cmdTimes.Use) { - t.Errorf("--help shouldn't display subsubcommand's usage, Got: \n %s", x.Output) - } - - checkResultContains(t, x, "Available Commands:") - checkResultContains(t, x, "for more information about a command") - - if strings.Contains(x.Output, "unknown flag: --help") { - t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) - } - -} - -func TestFlagAccess(t *testing.T) { - initialize() - - cmdEcho.AddCommand(cmdTimes) - local := cmdTimes.LocalFlags() - inherited := cmdTimes.InheritedFlags() - - for _, f := range []string{"inttwo", "strtwo", "booltwo"} { - if local.Lookup(f) == nil { - t.Errorf("LocalFlags expected to contain %s, Got: nil", f) - } - } - if inherited.Lookup("strone") == nil { - t.Errorf("InheritedFlags expected to contain strone, Got: nil") - } - if inherited.Lookup("strtwo") != nil { - t.Errorf("InheritedFlags shouldn not contain overwritten flag strtwo") - } -} - -func TestNoNRunnableRootCommandNilInput(t *testing.T) { - c := initialize() - - buf := new(bytes.Buffer) - // Testing flag with invalid input - c.SetOutput(buf) - cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdPrint, cmdEcho) - c.SetArgs([]string{}) - - c.Execute() - - if !strings.Contains(buf.String(), cmdRootNoRun.Long) { - t.Errorf("Expected to get help output, Got: \n %s", buf) - } -} - -func TestRootNoCommandHelp(t *testing.T) { - x := rootOnlySetupTest("--help") - - checkResultOmits(t, x, "Available Commands:") - checkResultOmits(t, x, "for more information about a command") - - if strings.Contains(x.Output, "unknown flag: --help") { - t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) - } - - x = rootOnlySetupTest("echo", "--help") - - checkResultOmits(t, x, "Available Commands:") - checkResultOmits(t, x, "for more information about a command") - - if strings.Contains(x.Output, "unknown flag: --help") { - t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) - } -} - -func TestRootUnknownCommand(t *testing.T) { - r := noRRSetupTest("bogus") - s := "Error: unknown command \"bogus\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n" - - if r.Output != s { - t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output) - } - - r = noRRSetupTest("--strtwo=a", "bogus") - if r.Output != s { - t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output) - } -} - -func TestRootUnknownCommandSilenced(t *testing.T) { - r := noRRSetupTestSilenced("bogus") - - if r.Output != "" { - t.Errorf("Unexpected response.\nExpecting to be: \n\"\"\n Got:\n %q\n", r.Output) - } - - r = noRRSetupTestSilenced("--strtwo=a", "bogus") - if r.Output != "" { - t.Errorf("Unexpected response.\nExpecting to be:\n\"\"\nGot:\n %q\n", r.Output) - } -} - -func TestRootSuggestions(t *testing.T) { - outputWithSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\n\nDid you mean this?\n\t%s\n\nRun 'cobra-test --help' for usage.\n" - outputWithoutSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n" - - cmd := initializeWithRootCmd() - cmd.AddCommand(cmdTimes) - - tests := map[string]string{ - "time": "times", - "tiems": "times", - "tims": "times", - "timeS": "times", - "rimes": "times", - "ti": "times", - "t": "times", - "timely": "times", - "ri": "", - "timezone": "", - "foo": "", - "counts": "times", - } - - for typo, suggestion := range tests { - for _, suggestionsDisabled := range []bool{false, true} { - cmd.DisableSuggestions = suggestionsDisabled - result := simpleTester(cmd, typo) - expected := "" - if len(suggestion) == 0 || suggestionsDisabled { - expected = fmt.Sprintf(outputWithoutSuggestions, typo) - } else { - expected = fmt.Sprintf(outputWithSuggestions, typo, suggestion) - } - if result.Output != expected { - t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output) - } - } - } -} - -func TestFlagsBeforeCommand(t *testing.T) { - // short without space - x := fullSetupTest("-i10", "echo") - if x.Error != nil { - t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) - } - - x = noRRSetupTest("echo", "-i=10") - if x.Error != nil { - t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error) - } - - // long with equals - x = noRRSetupTest("--intone=123", "echo", "one", "two") - if x.Error != nil { - t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error) - } - - // With parsing error properly reported - x = fullSetupTest("-i10E", "echo") - if !strings.Contains(x.Error.Error(), "invalid syntax") { - t.Errorf("Wrong error message displayed, \n %s", x.Error) - } -} - -func TestRemoveCommand(t *testing.T) { - versionUsed = 0 - c := initializeWithRootCmd() - c.AddCommand(cmdVersion1) - c.RemoveCommand(cmdVersion1) - x := fullTester(c, "version") - if x.Error == nil { - t.Errorf("Removed command should not have been called\n") - return - } -} - -func TestCommandWithoutSubcommands(t *testing.T) { - c := initializeWithRootCmd() - - x := simpleTester(c, "") - if x.Error != nil { - t.Errorf("Calling command without subcommands should not have error: %v", x.Error) - return - } -} - -func TestCommandWithoutSubcommandsWithArg(t *testing.T) { - c := initializeWithRootCmd() - expectedArgs := []string{"arg"} - - x := simpleTester(c, "arg") - if x.Error != nil { - t.Errorf("Calling command without subcommands but with arg should not have error: %v", x.Error) - return - } - if !reflect.DeepEqual(expectedArgs, tr) { - t.Errorf("Calling command without subcommands but with arg has wrong args: expected: %v, actual: %v", expectedArgs, tr) - return - } -} - -func TestReplaceCommandWithRemove(t *testing.T) { - versionUsed = 0 - c := initializeWithRootCmd() - c.AddCommand(cmdVersion1) - c.RemoveCommand(cmdVersion1) - c.AddCommand(cmdVersion2) - x := fullTester(c, "version") - if x.Error != nil { - t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) - return - } - if versionUsed == 1 { - t.Errorf("Removed command shouldn't be called\n") - } - if versionUsed != 2 { - t.Errorf("Replacing command should have been called but didn't\n") - } -} - -func TestDeprecatedSub(t *testing.T) { - c := fullSetupTest("deprecated") - - checkResultContains(t, c, cmdDeprecated.Deprecated) -} - -func TestPreRun(t *testing.T) { - noRRSetupTest("echo", "one", "two") - if echoPre == nil || echoPersPre == nil { - t.Error("PreRun or PersistentPreRun not called") - } - if rootPersPre != nil || timesPersPre != nil { - t.Error("Wrong *Pre functions called!") - } - - noRRSetupTest("echo", "times", "one", "two") - if timesPersPre == nil { - t.Error("PreRun or PersistentPreRun not called") - } - if echoPre != nil || echoPersPre != nil || rootPersPre != nil { - t.Error("Wrong *Pre functions called!") - } - - noRRSetupTest("print", "one", "two") - if rootPersPre == nil { - t.Error("Parent PersistentPreRun not called but should not have been") - } - if echoPre != nil || echoPersPre != nil || timesPersPre != nil { - t.Error("Wrong *Pre functions called!") - } -} - -// Check if cmdEchoSub gets PersistentPreRun from rootCmd even if is added last -func TestPeristentPreRunPropagation(t *testing.T) { - rootCmd := initialize() - - // First add the cmdEchoSub to cmdPrint - cmdPrint.AddCommand(cmdEchoSub) - // Now add cmdPrint to rootCmd - rootCmd.AddCommand(cmdPrint) - - rootCmd.SetArgs([]string{"print", "echosub", "lala"}) - rootCmd.Execute() - - if len(rootPersPre) == 0 || rootPersPre[0] != "lala" { - t.Error("RootCmd PersistentPreRun not called but should have been") - } -} - -func TestGlobalNormFuncPropagation(t *testing.T) { - normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName { - return pflag.NormalizedName(name) - } - - rootCmd := initialize() - rootCmd.AddCommand(cmdEcho) - - rootCmd.SetGlobalNormalizationFunc(normFunc) - if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { - t.Error("rootCmd seems to have a wrong normalization function") - } - - // Also check it propagates retroactively - if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(cmdEcho.GlobalNormalizationFunc()).Pointer() { - t.Error("cmdEcho should have had the normalization function of rootCmd") - } - - // First add the cmdEchoSub to cmdPrint - cmdPrint.AddCommand(cmdEchoSub) - if cmdPrint.GlobalNormalizationFunc() != nil && cmdEchoSub.GlobalNormalizationFunc() != nil { - t.Error("cmdPrint and cmdEchoSub should had no normalization functions") - } - - // Now add cmdPrint to rootCmd - rootCmd.AddCommand(cmdPrint) - if reflect.ValueOf(cmdPrint.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() || - reflect.ValueOf(cmdEchoSub.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { - t.Error("cmdPrint and cmdEchoSub should had the normalization function of rootCmd") - } -} - -func TestNormPassedOnLocal(t *testing.T) { - n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { - return pflag.NormalizedName(strings.ToUpper(name)) - } - - cmd := &Command{} - flagVal := false - - cmd.Flags().BoolVar(&flagVal, "flagname", true, "this is a dummy flag") - cmd.SetGlobalNormalizationFunc(n) - if cmd.LocalFlags().Lookup("flagname") != cmd.LocalFlags().Lookup("FLAGNAME") { - t.Error("Normalization function should be passed on to Local flag set") - } -} - -func TestNormPassedOnInherited(t *testing.T) { - n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { - return pflag.NormalizedName(strings.ToUpper(name)) - } - - cmd, childBefore, childAfter := &Command{}, &Command{}, &Command{} - flagVal := false - cmd.AddCommand(childBefore) - - cmd.PersistentFlags().BoolVar(&flagVal, "flagname", true, "this is a dummy flag") - cmd.SetGlobalNormalizationFunc(n) - - cmd.AddCommand(childAfter) - - if f := childBefore.InheritedFlags(); f.Lookup("flagname") == nil || f.Lookup("flagname") != f.Lookup("FLAGNAME") { - t.Error("Normalization function should be passed on to inherited flag set in command added before flag") - } - if f := childAfter.InheritedFlags(); f.Lookup("flagname") == nil || f.Lookup("flagname") != f.Lookup("FLAGNAME") { - t.Error("Normalization function should be passed on to inherited flag set in command added after flag") - } -} - -// Related to https://github.com/spf13/cobra/issues/521. -func TestNormConsistent(t *testing.T) { - n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { - return pflag.NormalizedName(strings.ToUpper(name)) - } - id := func(f *pflag.FlagSet, name string) pflag.NormalizedName { - return pflag.NormalizedName(name) - } - - cmd := &Command{} - flagVal := false - - cmd.Flags().BoolVar(&flagVal, "flagname", true, "this is a dummy flag") - // Build local flag set - cmd.LocalFlags() - - cmd.SetGlobalNormalizationFunc(n) - cmd.SetGlobalNormalizationFunc(id) - - if cmd.LocalFlags().Lookup("flagname") == cmd.LocalFlags().Lookup("FLAGNAME") { - t.Error("Normalizing flag names should not result in duplicate flags") - } -} - -func TestFlagOnPflagCommandLine(t *testing.T) { - flagName := "flagOnCommandLine" - pflag.String(flagName, "", "about my flag") - r := fullSetupTest("--help") - - checkResultContains(t, r, flagName) - - // Reset pflag.CommandLine flagset. - pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) -} - func TestAddTemplateFunctions(t *testing.T) { AddTemplateFunc("t", func() bool { return true }) AddTemplateFuncs(template.FuncMap{ @@ -1272,43 +12,11 @@ func TestAddTemplateFunctions(t *testing.T) { "h": func() string { return "Hello," }, "w": func() string { return "world." }}) - const usage = "Hello, world." - c := &Command{} c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`) - if us := c.UsageString(); us != usage { - t.Errorf("c.UsageString() != \"%s\", is \"%s\"", usage, us) - } -} - -func TestUsageIsNotPrintedTwice(t *testing.T) { - var cmd = &Command{Use: "root"} - var sub = &Command{Use: "sub"} - cmd.AddCommand(sub) - - r := simpleTester(cmd, "") - if strings.Count(r.Output, "Usage:") != 1 { - t.Error("Usage output is not printed exactly once") - } -} - -func BenchmarkInheritedFlags(b *testing.B) { - initialize() - cmdEcho.AddCommand(cmdTimes) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - cmdTimes.InheritedFlags() - } -} - -func BenchmarkLocalFlags(b *testing.B) { - initialize() - cmdEcho.AddCommand(cmdTimes) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - cmdTimes.LocalFlags() + const expected = "Hello, world." + if got := c.UsageString(); got != expected { + t.Errorf("Expected UsageString: %v\nGot: %v", expected, got) } } diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 58e6ceb0..34d1bf36 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -27,6 +27,9 @@ import ( flag "github.com/spf13/pflag" ) +// FParseErrWhitelist configures Flag parse errors to be ignored +type FParseErrWhitelist flag.ParseErrorsWhitelist + // Command is just that, a command for your application. // E.g. 'go run ...' - 'run' is the command. Cobra requires // you to define the usage and description as part of your command @@ -75,6 +78,11 @@ type Command struct { // group commands. Annotations map[string]string + // Version defines the version for this command. If this value is non-empty and the command does not + // define a "version" flag, a "version" boolean flag will be added to the command and, if specified, + // will print content of the "Version" variable. + Version string + // The *Run functions are executed in the following order: // * PersistentPreRun() // * PreRun() @@ -118,6 +126,10 @@ type Command struct { // will be printed by generating docs for this command. DisableAutoGenTag bool + // DisableFlagsInUseLine will disable the addition of [flags] to the usage + // line of a command when printing help or generating docs + DisableFlagsInUseLine bool + // DisableSuggestions disables the suggestions based on Levenshtein distance // that go along with 'unknown command' messages. DisableSuggestions bool @@ -128,6 +140,9 @@ type Command struct { // TraverseChildren parses flags on all parents before executing child command. TraverseChildren bool + //FParseErrWhitelist flag parse errors to be ignored + FParseErrWhitelist FParseErrWhitelist + // commands is the list of commands supported by this program. commands []*Command // parent is a parent command for this command. @@ -138,6 +153,11 @@ type Command struct { commandsMaxNameLen int // commandsAreSorted defines, if command slice are sorted or not. commandsAreSorted bool + // commandCalledAs is the name or alias value used to call this command. + commandCalledAs struct { + name string + called bool + } // args is actual args parsed from flags. args []string @@ -173,6 +193,8 @@ type Command struct { // helpCommand is command with usage 'help'. If it's not defined by user, // cobra uses default help command. helpCommand *Command + // versionTemplate is the version template defined by user. + versionTemplate string } // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden @@ -218,6 +240,11 @@ func (c *Command) SetHelpTemplate(s string) { c.helpTemplate = s } +// SetVersionTemplate sets version template to be used. Application can use it to set custom template. +func (c *Command) SetVersionTemplate(s string) { + c.versionTemplate = s +} + // SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. // The user should not have a cyclic dependency on commands. func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { @@ -407,6 +434,19 @@ func (c *Command) HelpTemplate() string { {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` } +// VersionTemplate return version template for the command. +func (c *Command) VersionTemplate() string { + if c.versionTemplate != "" { + return c.versionTemplate + } + + if c.HasParent() { + return c.parent.VersionTemplate() + } + return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} +` +} + func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { flag := fs.Lookup(name) if flag == nil { @@ -441,6 +481,9 @@ Loop: s := args[0] args = args[1:] switch { + case s == "--": + // "--" terminates the flags + break Loop case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): // If '--flag arg' then // delete arg from args. @@ -528,6 +571,7 @@ func (c *Command) findNext(next string) *Command { matches := make([]*Command, 0) for _, cmd := range c.commands { if cmd.Name() == next || cmd.HasAlias(next) { + cmd.commandCalledAs.name = next return cmd } if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { @@ -538,6 +582,7 @@ func (c *Command) findNext(next string) *Command { if len(matches) == 1 { return matches[0] } + return nil } @@ -621,10 +666,8 @@ func (c *Command) Root() *Command { return c } -// ArgsLenAtDash will return the length of f.Args at the moment when a -- was -// found during arg parsing. This allows your program to know which args were -// before the -- and which came after. (Description from -// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash). +// ArgsLenAtDash will return the length of c.Flags().Args at the moment +// when a -- was found during args parsing. func (c *Command) ArgsLenAtDash() int { return c.Flags().ArgsLenAtDash() } @@ -638,9 +681,10 @@ func (c *Command) execute(a []string) (err error) { c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) } - // initialize help flag as the last point possible to allow for user + // initialize help and version flag at the last point possible to allow for user // overriding c.InitDefaultHelpFlag() + c.InitDefaultVersionFlag() err = c.ParseFlags(a) if err != nil { @@ -657,7 +701,27 @@ func (c *Command) execute(a []string) (err error) { return err } - if helpVal || !c.Runnable() { + if helpVal { + return flag.ErrHelp + } + + // for back-compat, only add version flag behavior if version is defined + if c.Version != "" { + versionVal, err := c.Flags().GetBool("version") + if err != nil { + c.Println("\"version\" flag declared as non-bool. Please correct your code") + return err + } + if versionVal { + err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) + if err != nil { + c.Println(err) + } + return err + } + } + + if !c.Runnable() { return flag.ErrHelp } @@ -780,6 +844,11 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { return c, err } + cmd.commandCalledAs.called = true + if cmd.commandCalledAs.name == "" { + cmd.commandCalledAs.name = cmd.Name() + } + err = cmd.execute(flags) if err != nil { // Always show help if requested, even if SilenceErrors is in @@ -825,7 +894,7 @@ func (c *Command) validateRequiredFlags() error { }) if len(missingFlagNames) > 0 { - return fmt.Errorf(`Required flag(s) "%s" have/has not been set`, strings.Join(missingFlagNames, `", "`)) + return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`)) } return nil } @@ -846,6 +915,27 @@ func (c *Command) InitDefaultHelpFlag() { } } +// InitDefaultVersionFlag adds default version flag to c. +// It is called automatically by executing the c. +// If c already has a version flag, it will do nothing. +// If c.Version is empty, it will do nothing. +func (c *Command) InitDefaultVersionFlag() { + if c.Version == "" { + return + } + + c.mergePersistentFlags() + if c.Flags().Lookup("version") == nil { + usage := "version for " + if c.Name() == "" { + usage += "this command" + } else { + usage += c.Name() + } + c.Flags().Bool("version", false, usage) + } +} + // InitDefaultHelpCmd adds default help command to c. // It is called automatically by executing the c or by calling help and usage. // If c already has help command or c has no subcommands, it will do nothing. @@ -877,7 +967,7 @@ Simply type ` + c.Name() + ` help [path to command] for full details.`, c.AddCommand(c.helpCommand) } -// ResetCommands used for testing. +// ResetCommands delete parent, subcommand and help command from c. func (c *Command) ResetCommands() { c.parent = nil c.commands = nil @@ -996,6 +1086,9 @@ func (c *Command) UseLine() string { } else { useline = c.Use } + if c.DisableFlagsInUseLine { + return useline + } if c.HasAvailableFlags() && !strings.Contains(useline, "[flags]") { useline += " [flags]" } @@ -1063,14 +1156,25 @@ func (c *Command) HasAlias(s string) bool { return false } +// CalledAs returns the command name or alias that was used to invoke +// this command or an empty string if the command has not been called. +func (c *Command) CalledAs() string { + if c.commandCalledAs.called { + return c.commandCalledAs.name + } + return "" +} + // hasNameOrAliasPrefix returns true if the Name or any of aliases start // with prefix func (c *Command) hasNameOrAliasPrefix(prefix string) bool { if strings.HasPrefix(c.Name(), prefix) { + c.commandCalledAs.name = c.Name() return true } for _, alias := range c.Aliases { if strings.HasPrefix(alias, prefix) { + c.commandCalledAs.name = alias return true } } @@ -1163,7 +1267,7 @@ func (c *Command) HasAvailableSubCommands() bool { } } - // the command either has no sub comamnds, or no available (non deprecated/help/hidden) + // the command either has no sub commands, or no available (non deprecated/help/hidden) // sub commands return false } @@ -1173,7 +1277,7 @@ func (c *Command) HasParent() bool { return c.parent != nil } -// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. +// GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist. func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { return c.globNormFunc } @@ -1273,7 +1377,7 @@ func (c *Command) PersistentFlags() *flag.FlagSet { return c.pflags } -// ResetFlags is used in testing. +// ResetFlags deletes all flags from command. func (c *Command) ResetFlags() { c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf.Reset() @@ -1365,6 +1469,10 @@ func (c *Command) ParseFlags(args []string) error { } beforeErrorBufLen := c.flagErrorBuf.Len() c.mergePersistentFlags() + + //do it here after merging all flags and just before parse + c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) + err := c.Flags().Parse(args) // Print warnings if they occurred (e.g. deprecated flag messages). if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { diff --git a/vendor/github.com/spf13/cobra/command_test.go b/vendor/github.com/spf13/cobra/command_test.go index dda355f3..ccee031d 100644 --- a/vendor/github.com/spf13/cobra/command_test.go +++ b/vendor/github.com/spf13/cobra/command_test.go @@ -11,27 +11,450 @@ import ( "github.com/spf13/pflag" ) -// test to ensure hidden commands run as intended -func TestHiddenCommandExecutes(t *testing.T) { +func emptyRun(*Command, []string) {} - // ensure that outs does not already equal what the command will be setting it - // to, if it did this test would not actually be testing anything... - if outs == "hidden" { - t.Errorf("outs should NOT EQUAL hidden") - } +func executeCommand(root *Command, args ...string) (output string, err error) { + _, output, err = executeCommandC(root, args...) + return output, err +} - cmdHidden.Execute() +func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) { + buf := new(bytes.Buffer) + root.SetOutput(buf) + root.SetArgs(args) - // upon running the command, the value of outs should now be 'hidden' - if outs != "hidden" { - t.Errorf("Hidden command failed to run!") + c, err = root.ExecuteC() + + return c, buf.String(), err +} + +func resetCommandLineFlagSet() { + pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) +} + +func checkStringContains(t *testing.T, got, expected string) { + if !strings.Contains(got, expected) { + t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got) } } -// test to ensure hidden commands do not show up in usage/help text -func TestHiddenCommandIsHidden(t *testing.T) { - if cmdHidden.IsAvailableCommand() { - t.Errorf("Hidden command found!") +func checkStringOmits(t *testing.T, got, expected string) { + if strings.Contains(got, expected) { + t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) + } +} + +func TestSingleCommand(t *testing.T) { + var rootCmdArgs []string + rootCmd := &Command{ + Use: "root", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { rootCmdArgs = args }, + } + aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun} + bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun} + rootCmd.AddCommand(aCmd, bCmd) + + output, err := executeCommand(rootCmd, "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(rootCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got) + } +} + +func TestChildCommand(t *testing.T) { + var child1CmdArgs []string + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + child1Cmd := &Command{ + Use: "child1", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { child1CmdArgs = args }, + } + child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun} + rootCmd.AddCommand(child1Cmd, child2Cmd) + + output, err := executeCommand(rootCmd, "child1", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(child1CmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got) + } +} + +func TestCallCommandWithoutSubcommands(t *testing.T) { + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + _, err := executeCommand(rootCmd) + if err != nil { + t.Errorf("Calling command without subcommands should not have error: %v", err) + } +} + +func TestRootExecuteUnknownCommand(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) + + output, _ := executeCommand(rootCmd, "unknown") + + expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n" + + if output != expected { + t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output) + } +} + +func TestSubcommandExecuteC(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + c, output, err := executeCommandC(rootCmd, "child") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if c.Name() != "child" { + t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name()) + } +} + +func TestRootUnknownCommandSilenced(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + rootCmd.SilenceErrors = true + rootCmd.SilenceUsage = true + rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) + + output, _ := executeCommand(rootCmd, "unknown") + if output != "" { + t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output) + } +} + +func TestCommandAlias(t *testing.T) { + var timesCmdArgs []string + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + echoCmd := &Command{ + Use: "echo", + Aliases: []string{"say", "tell"}, + Args: NoArgs, + Run: emptyRun, + } + timesCmd := &Command{ + Use: "times", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { timesCmdArgs = args }, + } + echoCmd.AddCommand(timesCmd) + rootCmd.AddCommand(echoCmd) + + output, err := executeCommand(rootCmd, "tell", "times", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(timesCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) + } +} + +func TestEnablePrefixMatching(t *testing.T) { + EnablePrefixMatching = true + + var aCmdArgs []string + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + aCmd := &Command{ + Use: "aCmd", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { aCmdArgs = args }, + } + bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun} + rootCmd.AddCommand(aCmd, bCmd) + + output, err := executeCommand(rootCmd, "a", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(aCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("aCmdArgs expected: %q, got: %q", expected, got) + } + + EnablePrefixMatching = false +} + +func TestAliasPrefixMatching(t *testing.T) { + EnablePrefixMatching = true + + var timesCmdArgs []string + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + echoCmd := &Command{ + Use: "echo", + Aliases: []string{"say", "tell"}, + Args: NoArgs, + Run: emptyRun, + } + timesCmd := &Command{ + Use: "times", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { timesCmdArgs = args }, + } + echoCmd.AddCommand(timesCmd) + rootCmd.AddCommand(echoCmd) + + output, err := executeCommand(rootCmd, "sa", "times", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(timesCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) + } + + EnablePrefixMatching = false +} + +// TestChildSameName checks the correct behaviour of cobra in cases, +// when an application with name "foo" and with subcommand "foo" +// is executed with args "foo foo". +func TestChildSameName(t *testing.T) { + var fooCmdArgs []string + rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} + fooCmd := &Command{ + Use: "foo", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { fooCmdArgs = args }, + } + barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} + rootCmd.AddCommand(fooCmd, barCmd) + + output, err := executeCommand(rootCmd, "foo", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(fooCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) + } +} + +// TestGrandChildSameName checks the correct behaviour of cobra in cases, +// when user has a root command and a grand child +// with the same name. +func TestGrandChildSameName(t *testing.T) { + var fooCmdArgs []string + rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun} + barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun} + fooCmd := &Command{ + Use: "foo", + Args: ExactArgs(2), + Run: func(_ *Command, args []string) { fooCmdArgs = args }, + } + barCmd.AddCommand(fooCmd) + rootCmd.AddCommand(barCmd) + + output, err := executeCommand(rootCmd, "bar", "foo", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(fooCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) + } +} + +func TestFlagLong(t *testing.T) { + var cArgs []string + c := &Command{ + Use: "c", + Args: ArbitraryArgs, + Run: func(_ *Command, args []string) { cArgs = args }, + } + + var intFlagValue int + var stringFlagValue string + c.Flags().IntVar(&intFlagValue, "intf", -1, "") + c.Flags().StringVar(&stringFlagValue, "sf", "", "") + + output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two") + if output != "" { + t.Errorf("Unexpected output: %v", err) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if c.ArgsLenAtDash() != 1 { + t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash()) + } + if intFlagValue != 7 { + t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue) + } + if stringFlagValue != "abc" { + t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) + } + + got := strings.Join(cArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("Expected arguments: %q, got %q", expected, got) + } +} + +func TestFlagShort(t *testing.T) { + var cArgs []string + c := &Command{ + Use: "c", + Args: ArbitraryArgs, + Run: func(_ *Command, args []string) { cArgs = args }, + } + + var intFlagValue int + var stringFlagValue string + c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") + c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "") + + output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", err) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if intFlagValue != 7 { + t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) + } + if stringFlagValue != "abc" { + t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue) + } + + got := strings.Join(cArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("Expected arguments: %q, got %q", expected, got) + } +} + +func TestChildFlag(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + var intFlagValue int + childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") + + output, err := executeCommand(rootCmd, "child", "-i7") + if output != "" { + t.Errorf("Unexpected output: %v", err) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if intFlagValue != 7 { + t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) + } +} + +func TestChildFlagWithParentLocalFlag(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + var intFlagValue int + rootCmd.Flags().StringP("sf", "s", "", "") + childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "") + + _, err := executeCommand(rootCmd, "child", "-i7", "-sabc") + if err == nil { + t.Errorf("Invalid flag should generate error") + } + + checkStringContains(t, err.Error(), "unknown shorthand") + + if intFlagValue != 7 { + t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue) + } +} + +func TestFlagInvalidInput(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + rootCmd.Flags().IntP("intf", "i", -1, "") + + _, err := executeCommand(rootCmd, "-iabc") + if err == nil { + t.Errorf("Invalid flag value should generate error") + } + + checkStringContains(t, err.Error(), "invalid syntax") +} + +func TestFlagBeforeCommand(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + var flagValue int + childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "") + + // With short flag. + _, err := executeCommand(rootCmd, "-i7", "child") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if flagValue != 7 { + t.Errorf("Expected flag value: %v, got %v", 7, flagValue) + } + + // With long flag. + _, err = executeCommand(rootCmd, "--intf=8", "child") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if flagValue != 8 { + t.Errorf("Expected flag value: %v, got %v", 9, flagValue) } } @@ -45,11 +468,11 @@ func TestStripFlags(t *testing.T) { []string{"foo", "bar"}, }, { - []string{"foo", "--bar", "-b"}, + []string{"foo", "--str", "-s"}, []string{"foo"}, }, { - []string{"-b", "foo", "--bar", "bar"}, + []string{"-s", "foo", "--str", "bar"}, []string{}, }, { @@ -65,7 +488,7 @@ func TestStripFlags(t *testing.T) { []string{"echo"}, }, { - []string{"-ib", "echo", "-bfoo", "baz"}, + []string{"-ib", "echo", "-sfoo", "baz"}, []string{"echo", "baz"}, }, { @@ -73,15 +496,15 @@ func TestStripFlags(t *testing.T) { []string{"bar", "blah"}, }, { - []string{"--int=baz", "-bbar", "-i", "foo", "blah"}, + []string{"--int=baz", "-sbar", "-i", "foo", "blah"}, []string{"blah"}, }, { - []string{"--cat", "bar", "-i", "foo", "blah"}, + []string{"--bool", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { - []string{"-c", "bar", "-i", "foo", "blah"}, + []string{"-b", "bar", "-i", "foo", "blah"}, []string{"bar", "blah"}, }, { @@ -94,61 +517,814 @@ func TestStripFlags(t *testing.T) { }, } - cmdPrint := &Command{ - Use: "print [string to print]", - Short: "Print anything to the screen", - Long: `an utterly useless command for testing.`, - Run: func(cmd *Command, args []string) { - tp = args - }, - } + c := &Command{Use: "c", Run: emptyRun} + c.PersistentFlags().BoolP("persist", "p", false, "") + c.Flags().IntP("int", "i", -1, "") + c.Flags().StringP("str", "s", "", "") + c.Flags().BoolP("bool", "b", false, "") - var flagi int - var flagstr string - var flagbool bool - cmdPrint.PersistentFlags().BoolVarP(&flagbool, "persist", "p", false, "help for persistent one") - cmdPrint.Flags().IntVarP(&flagi, "int", "i", 345, "help message for flag int") - cmdPrint.Flags().StringVarP(&flagstr, "bar", "b", "bar", "help message for flag string") - cmdPrint.Flags().BoolVarP(&flagbool, "cat", "c", false, "help message for flag bool") - - for _, test := range tests { - output := stripFlags(test.input, cmdPrint) - if !reflect.DeepEqual(test.output, output) { - t.Errorf("expected: %v, got: %v", test.output, output) + for i, test := range tests { + got := stripFlags(test.input, c) + if !reflect.DeepEqual(test.output, got) { + t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got) } } } func TestDisableFlagParsing(t *testing.T) { - targs := []string{} - cmdPrint := &Command{ + var cArgs []string + c := &Command{ + Use: "c", DisableFlagParsing: true, - Run: func(cmd *Command, args []string) { - targs = args + Run: func(_ *Command, args []string) { + cArgs = args }, } + args := []string{"cmd", "-v", "-race", "-file", "foo.go"} - cmdPrint.SetArgs(args) - err := cmdPrint.Execute() - if err != nil { - t.Error(err) + output, err := executeCommand(c, args...) + if output != "" { + t.Errorf("Unexpected output: %v", output) } - if !reflect.DeepEqual(args, targs) { - t.Errorf("expected: %v, got: %v", args, targs) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(args, cArgs) { + t.Errorf("Expected: %v, got: %v", args, cArgs) + } +} + +func TestPersistentFlagsOnSameCommand(t *testing.T) { + var rootCmdArgs []string + rootCmd := &Command{ + Use: "root", + Args: ArbitraryArgs, + Run: func(_ *Command, args []string) { rootCmdArgs = args }, + } + + var flagValue int + rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "") + + output, err := executeCommand(rootCmd, "-i7", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(rootCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("rootCmdArgs expected: %q, got %q", expected, got) + } + if flagValue != 7 { + t.Errorf("flagValue expected: %v, got %v", 7, flagValue) + } +} + +// TestEmptyInputs checks, +// if flags correctly parsed with blank strings in args. +func TestEmptyInputs(t *testing.T) { + c := &Command{Use: "c", Run: emptyRun} + + var flagValue int + c.Flags().IntVarP(&flagValue, "intf", "i", -1, "") + + output, err := executeCommand(c, "", "-i7", "") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if flagValue != 7 { + t.Errorf("flagValue expected: %v, got %v", 7, flagValue) + } +} + +func TestOverwrittenFlag(t *testing.T) { + // TODO: This test fails, but should work. + t.Skip() + + parent := &Command{Use: "parent", Run: emptyRun} + child := &Command{Use: "child", Run: emptyRun} + + parent.PersistentFlags().Bool("boolf", false, "") + parent.PersistentFlags().Int("intf", -1, "") + child.Flags().String("strf", "", "") + child.Flags().Int("intf", -1, "") + + parent.AddCommand(child) + + childInherited := child.InheritedFlags() + childLocal := child.LocalFlags() + + if childLocal.Lookup("strf") == nil { + t.Error(`LocalFlags expected to contain "strf", got "nil"`) + } + if childInherited.Lookup("boolf") == nil { + t.Error(`InheritedFlags expected to contain "boolf", got "nil"`) + } + + if childInherited.Lookup("intf") != nil { + t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`) + } + if childLocal.Lookup("intf") == nil { + t.Error(`LocalFlags expected to contain "intf", got "nil"`) + } +} + +func TestPersistentFlagsOnChild(t *testing.T) { + var childCmdArgs []string + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{ + Use: "child", + Args: ArbitraryArgs, + Run: func(_ *Command, args []string) { childCmdArgs = args }, + } + rootCmd.AddCommand(childCmd) + + var parentFlagValue int + var childFlagValue int + rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "") + childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "") + + output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + got := strings.Join(childCmdArgs, " ") + expected := "one two" + if got != expected { + t.Errorf("childCmdArgs expected: %q, got %q", expected, got) + } + if parentFlagValue != 8 { + t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue) + } + if childFlagValue != 7 { + t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue) + } +} + +func TestRequiredFlags(t *testing.T) { + c := &Command{Use: "c", Run: emptyRun} + c.Flags().String("foo1", "", "") + c.MarkFlagRequired("foo1") + c.Flags().String("foo2", "", "") + c.MarkFlagRequired("foo2") + c.Flags().String("bar", "", "") + + expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2") + + _, err := executeCommand(c) + got := err.Error() + + if got != expected { + t.Errorf("Expected error: %q, got: %q", expected, got) + } +} + +func TestPersistentRequiredFlags(t *testing.T) { + parent := &Command{Use: "parent", Run: emptyRun} + parent.PersistentFlags().String("foo1", "", "") + parent.MarkPersistentFlagRequired("foo1") + parent.PersistentFlags().String("foo2", "", "") + parent.MarkPersistentFlagRequired("foo2") + parent.Flags().String("foo3", "", "") + + child := &Command{Use: "child", Run: emptyRun} + child.Flags().String("bar1", "", "") + child.MarkFlagRequired("bar1") + child.Flags().String("bar2", "", "") + child.MarkFlagRequired("bar2") + child.Flags().String("bar3", "", "") + + parent.AddCommand(child) + + expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2") + + _, err := executeCommand(parent, "child") + if err.Error() != expected { + t.Errorf("Expected %q, got %q", expected, err.Error()) } } func TestInitHelpFlagMergesFlags(t *testing.T) { usage := "custom flag" - baseCmd := Command{Use: "testcmd"} - baseCmd.PersistentFlags().Bool("help", false, usage) - cmd := Command{Use: "do"} - baseCmd.AddCommand(&cmd) + rootCmd := &Command{Use: "root"} + rootCmd.PersistentFlags().Bool("help", false, "custom flag") + childCmd := &Command{Use: "child"} + rootCmd.AddCommand(childCmd) - cmd.InitDefaultHelpFlag() - actual := cmd.Flags().Lookup("help").Usage - if actual != usage { - t.Fatalf("Expected the help flag from the base command with usage '%s', but got the default with usage '%s'", usage, actual) + childCmd.InitDefaultHelpFlag() + got := childCmd.Flags().Lookup("help").Usage + if got != usage { + t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got) + } +} + +func TestHelpCommandExecuted(t *testing.T) { + rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} + rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun}) + + output, err := executeCommand(rootCmd, "help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, rootCmd.Long) +} + +func TestHelpCommandExecutedOnChild(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + output, err := executeCommand(rootCmd, "help", "child") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, childCmd.Long) +} + +func TestSetHelpCommand(t *testing.T) { + c := &Command{Use: "c", Run: emptyRun} + c.AddCommand(&Command{Use: "empty", Run: emptyRun}) + + expected := "WORKS" + c.SetHelpCommand(&Command{ + Use: "help [command]", + Short: "Help about any command", + Long: `Help provides help for any command in the application. + Simply type ` + c.Name() + ` help [path to command] for full details.`, + Run: func(c *Command, _ []string) { c.Print(expected) }, + }) + + got, err := executeCommand(c, "help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if got != expected { + t.Errorf("Expected to contain %q, got %q", expected, got) + } +} + +func TestHelpFlagExecuted(t *testing.T) { + rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun} + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, rootCmd.Long) +} + +func TestHelpFlagExecutedOnChild(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + output, err := executeCommand(rootCmd, "child", "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, childCmd.Long) +} + +// TestHelpFlagInHelp checks, +// if '--help' flag is shown in help for child (executing `parent help child`), +// that has no other flags. +// Related to https://github.com/spf13/cobra/issues/302. +func TestHelpFlagInHelp(t *testing.T) { + parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}} + + childCmd := &Command{Use: "child", Run: func(*Command, []string) {}} + parentCmd.AddCommand(childCmd) + + output, err := executeCommand(parentCmd, "help", "child") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "[flags]") +} + +func TestFlagsInUsage(t *testing.T) { + rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}} + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "[flags]") +} + +func TestHelpExecutedOnNonRunnableChild(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Long: "Long description"} + rootCmd.AddCommand(childCmd) + + output, err := executeCommand(rootCmd, "child") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, childCmd.Long) +} + +func TestVersionFlagExecuted(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + + output, err := executeCommand(rootCmd, "--version", "arg1") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "root version 1.0.0") +} + +func TestVersionTemplate(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) + + output, err := executeCommand(rootCmd, "--version", "arg1") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "customized version: 1.0.0") +} + +func TestVersionFlagExecutedOnSubcommand(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0"} + rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) + + output, err := executeCommand(rootCmd, "--version", "sub") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "root version 1.0.0") +} + +func TestVersionFlagOnlyAddedToRoot(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) + + _, err := executeCommand(rootCmd, "sub", "--version") + if err == nil { + t.Errorf("Expected error") + } + + checkStringContains(t, err.Error(), "unknown flag: --version") +} + +func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + + _, err := executeCommand(rootCmd, "--version") + if err == nil { + t.Errorf("Expected error") + } + checkStringContains(t, err.Error(), "unknown flag: --version") +} + +func TestUsageIsNotPrintedTwice(t *testing.T) { + var cmd = &Command{Use: "root"} + var sub = &Command{Use: "sub"} + cmd.AddCommand(sub) + + output, _ := executeCommand(cmd, "") + if strings.Count(output, "Usage:") != 1 { + t.Error("Usage output is not printed exactly once") + } +} + +func TestVisitParents(t *testing.T) { + c := &Command{Use: "app"} + sub := &Command{Use: "sub"} + dsub := &Command{Use: "dsub"} + sub.AddCommand(dsub) + c.AddCommand(sub) + + total := 0 + add := func(x *Command) { + total++ + } + sub.VisitParents(add) + if total != 1 { + t.Errorf("Should have visited 1 parent but visited %d", total) + } + + total = 0 + dsub.VisitParents(add) + if total != 2 { + t.Errorf("Should have visited 2 parents but visited %d", total) + } + + total = 0 + c.VisitParents(add) + if total != 0 { + t.Errorf("Should have visited no parents but visited %d", total) + } +} + +func TestSuggestions(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + timesCmd := &Command{ + Use: "times", + SuggestFor: []string{"counts"}, + Run: emptyRun, + } + rootCmd.AddCommand(timesCmd) + + templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n" + templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n" + + tests := map[string]string{ + "time": "times", + "tiems": "times", + "tims": "times", + "timeS": "times", + "rimes": "times", + "ti": "times", + "t": "times", + "timely": "times", + "ri": "", + "timezone": "", + "foo": "", + "counts": "times", + } + + for typo, suggestion := range tests { + for _, suggestionsDisabled := range []bool{true, false} { + rootCmd.DisableSuggestions = suggestionsDisabled + + var expected string + output, _ := executeCommand(rootCmd, typo) + + if suggestion == "" || suggestionsDisabled { + expected = fmt.Sprintf(templateWithoutSuggestions, typo) + } else { + expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion) + } + + if output != expected { + t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output) + } + } + } +} + +func TestRemoveCommand(t *testing.T) { + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + rootCmd.RemoveCommand(childCmd) + + _, err := executeCommand(rootCmd, "child") + if err == nil { + t.Error("Expected error on calling removed command. Got nil.") + } +} + +func TestReplaceCommandWithRemove(t *testing.T) { + childUsed := 0 + rootCmd := &Command{Use: "root", Run: emptyRun} + child1Cmd := &Command{ + Use: "child", + Run: func(*Command, []string) { childUsed = 1 }, + } + child2Cmd := &Command{ + Use: "child", + Run: func(*Command, []string) { childUsed = 2 }, + } + rootCmd.AddCommand(child1Cmd) + rootCmd.RemoveCommand(child1Cmd) + rootCmd.AddCommand(child2Cmd) + + output, err := executeCommand(rootCmd, "child") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if childUsed == 1 { + t.Error("Removed command shouldn't be called") + } + if childUsed != 2 { + t.Error("Replacing command should have been called but didn't") + } +} + +func TestDeprecatedCommand(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + deprecatedCmd := &Command{ + Use: "deprecated", + Deprecated: "This command is deprecated", + Run: emptyRun, + } + rootCmd.AddCommand(deprecatedCmd) + + output, err := executeCommand(rootCmd, "deprecated") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, deprecatedCmd.Deprecated) +} + +func TestHooks(t *testing.T) { + var ( + persPreArgs string + preArgs string + runArgs string + postArgs string + persPostArgs string + ) + + c := &Command{ + Use: "c", + PersistentPreRun: func(_ *Command, args []string) { + persPreArgs = strings.Join(args, " ") + }, + PreRun: func(_ *Command, args []string) { + preArgs = strings.Join(args, " ") + }, + Run: func(_ *Command, args []string) { + runArgs = strings.Join(args, " ") + }, + PostRun: func(_ *Command, args []string) { + postArgs = strings.Join(args, " ") + }, + PersistentPostRun: func(_ *Command, args []string) { + persPostArgs = strings.Join(args, " ") + }, + } + + output, err := executeCommand(c, "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if persPreArgs != "one two" { + t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs) + } + if preArgs != "one two" { + t.Errorf("Expected preArgs %q, got %q", "one two", preArgs) + } + if runArgs != "one two" { + t.Errorf("Expected runArgs %q, got %q", "one two", runArgs) + } + if postArgs != "one two" { + t.Errorf("Expected postArgs %q, got %q", "one two", postArgs) + } + if persPostArgs != "one two" { + t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs) + } +} + +func TestPersistentHooks(t *testing.T) { + var ( + parentPersPreArgs string + parentPreArgs string + parentRunArgs string + parentPostArgs string + parentPersPostArgs string + ) + + var ( + childPersPreArgs string + childPreArgs string + childRunArgs string + childPostArgs string + childPersPostArgs string + ) + + parentCmd := &Command{ + Use: "parent", + PersistentPreRun: func(_ *Command, args []string) { + parentPersPreArgs = strings.Join(args, " ") + }, + PreRun: func(_ *Command, args []string) { + parentPreArgs = strings.Join(args, " ") + }, + Run: func(_ *Command, args []string) { + parentRunArgs = strings.Join(args, " ") + }, + PostRun: func(_ *Command, args []string) { + parentPostArgs = strings.Join(args, " ") + }, + PersistentPostRun: func(_ *Command, args []string) { + parentPersPostArgs = strings.Join(args, " ") + }, + } + + childCmd := &Command{ + Use: "child", + PersistentPreRun: func(_ *Command, args []string) { + childPersPreArgs = strings.Join(args, " ") + }, + PreRun: func(_ *Command, args []string) { + childPreArgs = strings.Join(args, " ") + }, + Run: func(_ *Command, args []string) { + childRunArgs = strings.Join(args, " ") + }, + PostRun: func(_ *Command, args []string) { + childPostArgs = strings.Join(args, " ") + }, + PersistentPostRun: func(_ *Command, args []string) { + childPersPostArgs = strings.Join(args, " ") + }, + } + parentCmd.AddCommand(childCmd) + + output, err := executeCommand(parentCmd, "child", "one", "two") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // TODO: This test fails, but should not. + // Related to https://github.com/spf13/cobra/issues/252. + // + // if parentPersPreArgs != "one two" { + // t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs) + // } + if parentPreArgs != "" { + t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs) + } + if parentRunArgs != "" { + t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs) + } + if parentPostArgs != "" { + t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs) + } + // TODO: This test fails, but should not. + // Related to https://github.com/spf13/cobra/issues/252. + // + // if parentPersPostArgs != "one two" { + // t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs) + // } + + if childPersPreArgs != "one two" { + t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs) + } + if childPreArgs != "one two" { + t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs) + } + if childRunArgs != "one two" { + t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs) + } + if childPostArgs != "one two" { + t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs) + } + if childPersPostArgs != "one two" { + t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs) + } +} + +// Related to https://github.com/spf13/cobra/issues/521. +func TestGlobalNormFuncPropagation(t *testing.T) { + normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName { + return pflag.NormalizedName(name) + } + + rootCmd := &Command{Use: "root", Run: emptyRun} + childCmd := &Command{Use: "child", Run: emptyRun} + rootCmd.AddCommand(childCmd) + + rootCmd.SetGlobalNormalizationFunc(normFunc) + if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { + t.Error("rootCmd seems to have a wrong normalization function") + } + + if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() { + t.Error("childCmd should have had the normalization function of rootCmd") + } +} + +// Related to https://github.com/spf13/cobra/issues/521. +func TestNormPassedOnLocal(t *testing.T) { + toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { + return pflag.NormalizedName(strings.ToUpper(name)) + } + + c := &Command{} + c.Flags().Bool("flagname", true, "this is a dummy flag") + c.SetGlobalNormalizationFunc(toUpper) + if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") { + t.Error("Normalization function should be passed on to Local flag set") + } +} + +// Related to https://github.com/spf13/cobra/issues/521. +func TestNormPassedOnInherited(t *testing.T) { + toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { + return pflag.NormalizedName(strings.ToUpper(name)) + } + + c := &Command{} + c.SetGlobalNormalizationFunc(toUpper) + + child1 := &Command{} + c.AddCommand(child1) + + c.PersistentFlags().Bool("flagname", true, "") + + child2 := &Command{} + c.AddCommand(child2) + + inherited := child1.InheritedFlags() + if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { + t.Error("Normalization function should be passed on to inherited flag set in command added before flag") + } + + inherited = child2.InheritedFlags() + if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") { + t.Error("Normalization function should be passed on to inherited flag set in command added after flag") + } +} + +// Related to https://github.com/spf13/cobra/issues/521. +func TestConsistentNormalizedName(t *testing.T) { + toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName { + return pflag.NormalizedName(strings.ToUpper(name)) + } + n := func(f *pflag.FlagSet, name string) pflag.NormalizedName { + return pflag.NormalizedName(name) + } + + c := &Command{} + c.Flags().Bool("flagname", true, "") + c.SetGlobalNormalizationFunc(toUpper) + c.SetGlobalNormalizationFunc(n) + + if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") { + t.Error("Normalizing flag names should not result in duplicate flags") + } +} + +func TestFlagOnPflagCommandLine(t *testing.T) { + flagName := "flagOnCommandLine" + pflag.String(flagName, "", "about my flag") + + c := &Command{Use: "c", Run: emptyRun} + c.AddCommand(&Command{Use: "child", Run: emptyRun}) + + output, _ := executeCommand(c, "--help") + checkStringContains(t, output, flagName) + + resetCommandLineFlagSet() +} + +// TestHiddenCommandExecutes checks, +// if hidden commands run as intended. +func TestHiddenCommandExecutes(t *testing.T) { + executed := false + c := &Command{ + Use: "c", + Hidden: true, + Run: func(*Command, []string) { executed = true }, + } + + output, err := executeCommand(c) + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !executed { + t.Error("Hidden command should have been executed") + } +} + +// test to ensure hidden commands do not show up in usage/help text +func TestHiddenCommandIsHidden(t *testing.T) { + c := &Command{Use: "c", Hidden: true, Run: emptyRun} + if c.IsAvailableCommand() { + t.Errorf("Hidden command should be unavailable") } } @@ -158,15 +1334,16 @@ func TestCommandsAreSorted(t *testing.T) { originalNames := []string{"middle", "zlast", "afirst"} expectedNames := []string{"afirst", "middle", "zlast"} - var tmpCommand = &Command{Use: "tmp"} + var rootCmd = &Command{Use: "root"} for _, name := range originalNames { - tmpCommand.AddCommand(&Command{Use: name}) + rootCmd.AddCommand(&Command{Use: name}) } - for i, c := range tmpCommand.Commands() { - if expectedNames[i] != c.Name() { - t.Errorf("expected: %s, got: %s", expectedNames[i], c.Name()) + for i, c := range rootCmd.Commands() { + got := c.Name() + if expectedNames[i] != got { + t.Errorf("Expected: %s, got: %s", expectedNames[i], got) } } @@ -178,15 +1355,16 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) { originalNames := []string{"middle", "zlast", "afirst"} - var tmpCommand = &Command{Use: "tmp"} + var rootCmd = &Command{Use: "root"} for _, name := range originalNames { - tmpCommand.AddCommand(&Command{Use: name}) + rootCmd.AddCommand(&Command{Use: name}) } - for i, c := range tmpCommand.Commands() { - if originalNames[i] != c.Name() { - t.Errorf("expected: %s, got: %s", originalNames[i], c.Name()) + for i, c := range rootCmd.Commands() { + got := c.Name() + if originalNames[i] != got { + t.Errorf("expected: %s, got: %s", originalNames[i], got) } } @@ -194,33 +1372,27 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) { } func TestSetOutput(t *testing.T) { - cmd := &Command{} - cmd.SetOutput(nil) - if out := cmd.OutOrStdout(); out != os.Stdout { - t.Fatalf("expected setting output to nil to revert back to stdout, got %v", out) + c := &Command{} + c.SetOutput(nil) + if out := c.OutOrStdout(); out != os.Stdout { + t.Errorf("Expected setting output to nil to revert back to stdout") } } func TestFlagErrorFunc(t *testing.T) { - cmd := &Command{ - Use: "print", - RunE: func(cmd *Command, args []string) error { - return nil - }, - } - expectedFmt := "This is expected: %s" + c := &Command{Use: "c", Run: emptyRun} - cmd.SetFlagErrorFunc(func(c *Command, err error) error { + expectedFmt := "This is expected: %v" + c.SetFlagErrorFunc(func(_ *Command, err error) error { return fmt.Errorf(expectedFmt, err) }) - cmd.SetArgs([]string{"--bogus-flag"}) - cmd.SetOutput(new(bytes.Buffer)) - err := cmd.Execute() + _, err := executeCommand(c, "--unknown-flag") - expected := fmt.Sprintf(expectedFmt, "unknown flag: --bogus-flag") - if err.Error() != expected { - t.Errorf("expected %v, got %v", expected, err.Error()) + got := err.Error() + expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag") + if got != expected { + t.Errorf("Expected %v, got %v", expected, got) } } @@ -228,19 +1400,19 @@ func TestFlagErrorFunc(t *testing.T) { // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false. // Related to https://github.com/spf13/cobra/issues/404. func TestSortedFlags(t *testing.T) { - cmd := &Command{} - cmd.Flags().SortFlags = false + c := &Command{} + c.Flags().SortFlags = false names := []string{"C", "B", "A", "D"} for _, name := range names { - cmd.Flags().Bool(name, false, "") + c.Flags().Bool(name, false, "") } i := 0 - cmd.LocalFlags().VisitAll(func(f *pflag.Flag) { + c.LocalFlags().VisitAll(func(f *pflag.Flag) { if i == len(names) { return } - if isStringInStringSlice(f.Name, names) { + if stringInSlice(f.Name, names) { if names[i] != f.Name { t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) } @@ -249,267 +1421,134 @@ func TestSortedFlags(t *testing.T) { }) } -// contains checks, if s is in ss. -func isStringInStringSlice(s string, ss []string) bool { - for _, v := range ss { - if v == s { - return true - } - } - return false -} - -// TestHelpFlagInHelp checks, -// if '--help' flag is shown in help for child (executing `parent help child`), -// that has no other flags. -// Related to https://github.com/spf13/cobra/issues/302. -func TestHelpFlagInHelp(t *testing.T) { - output := new(bytes.Buffer) - parent := &Command{Use: "parent", Run: func(*Command, []string) {}} - parent.SetOutput(output) - - child := &Command{Use: "child", Run: func(*Command, []string) {}} - parent.AddCommand(child) - - parent.SetArgs([]string{"help", "child"}) - err := parent.Execute() - if err != nil { - t.Fatal(err) - } - - if !strings.Contains(output.String(), "[flags]") { - t.Errorf("\nExpecting to contain: %v\nGot: %v", "[flags]", output.String()) - } -} - // TestMergeCommandLineToFlags checks, // if pflag.CommandLine is correctly merged to c.Flags() after first call // of c.mergePersistentFlags. // Related to https://github.com/spf13/cobra/issues/443. func TestMergeCommandLineToFlags(t *testing.T) { pflag.Bool("boolflag", false, "") - c := &Command{Use: "c", Run: func(*Command, []string) {}} + c := &Command{Use: "c", Run: emptyRun} c.mergePersistentFlags() if c.Flags().Lookup("boolflag") == nil { t.Fatal("Expecting to have flag from CommandLine in c.Flags()") } - // Reset pflag.CommandLine flagset. - pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) + resetCommandLineFlagSet() } // TestUseDeprecatedFlags checks, // if cobra.Execute() prints a message, if a deprecated flag is used. // Related to https://github.com/spf13/cobra/issues/463. func TestUseDeprecatedFlags(t *testing.T) { - c := &Command{Use: "c", Run: func(*Command, []string) {}} - output := new(bytes.Buffer) - c.SetOutput(output) + c := &Command{Use: "c", Run: emptyRun} c.Flags().BoolP("deprecated", "d", false, "deprecated flag") c.Flags().MarkDeprecated("deprecated", "This flag is deprecated") - c.SetArgs([]string{"c", "-d"}) - if err := c.Execute(); err != nil { + output, err := executeCommand(c, "c", "-d") + if err != nil { t.Error("Unexpected error:", err) } - if !strings.Contains(output.String(), "This flag is deprecated") { - t.Errorf("Expected to contain deprecated message, but got %q", output.String()) - } -} - -// TestSetHelpCommand checks, if SetHelpCommand works correctly. -func TestSetHelpCommand(t *testing.T) { - c := &Command{Use: "c", Run: func(*Command, []string) {}} - output := new(bytes.Buffer) - c.SetOutput(output) - c.SetArgs([]string{"help"}) - - // Help will not be shown, if c has no subcommands. - c.AddCommand(&Command{ - Use: "empty", - Run: func(cmd *Command, args []string) {}, - }) - - correctMessage := "WORKS" - c.SetHelpCommand(&Command{ - Use: "help [command]", - Short: "Help about any command", - Long: `Help provides help for any command in the application. - Simply type ` + c.Name() + ` help [path to command] for full details.`, - Run: func(c *Command, args []string) { c.Print(correctMessage) }, - }) - - if err := c.Execute(); err != nil { - t.Error("Unexpected error:", err) - } - - if output.String() != correctMessage { - t.Errorf("Expected to contain %q message, but got %q", correctMessage, output.String()) - } + checkStringContains(t, output, "This flag is deprecated") } func TestTraverseWithParentFlags(t *testing.T) { - cmd := &Command{ - Use: "do", - TraverseChildren: true, - } - cmd.Flags().String("foo", "", "foo things") - cmd.Flags().BoolP("goo", "g", false, "foo things") + rootCmd := &Command{Use: "root", TraverseChildren: true} + rootCmd.Flags().String("str", "", "") + rootCmd.Flags().BoolP("bool", "b", false, "") - sub := &Command{Use: "next"} - sub.Flags().String("add", "", "add things") - cmd.AddCommand(sub) + childCmd := &Command{Use: "child"} + childCmd.Flags().Int("int", -1, "") - c, args, err := cmd.Traverse([]string{"-g", "--foo", "ok", "next", "--add"}) + rootCmd.AddCommand(childCmd) + + c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"}) if err != nil { - t.Fatalf("Expected no error: %s", err) + t.Errorf("Unexpected error: %v", err) } if len(args) != 1 && args[0] != "--add" { - t.Fatalf("wrong args %s", args) + t.Errorf("Wrong args: %v", args) } - if c.Name() != sub.Name() { - t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name()) + if c.Name() != childCmd.Name() { + t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseNoParentFlags(t *testing.T) { - cmd := &Command{ - Use: "do", - TraverseChildren: true, - } - cmd.Flags().String("foo", "", "foo things") + rootCmd := &Command{Use: "root", TraverseChildren: true} + rootCmd.Flags().String("foo", "", "foo things") - sub := &Command{Use: "next"} - sub.Flags().String("add", "", "add things") - cmd.AddCommand(sub) + childCmd := &Command{Use: "child"} + childCmd.Flags().String("str", "", "") + rootCmd.AddCommand(childCmd) - c, args, err := cmd.Traverse([]string{"next"}) + c, args, err := rootCmd.Traverse([]string{"child"}) if err != nil { - t.Fatalf("Expected no error: %s", err) + t.Errorf("Unexpected error: %v", err) } if len(args) != 0 { - t.Fatalf("wrong args %s", args) + t.Errorf("Wrong args %v", args) } - if c.Name() != sub.Name() { - t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name()) + if c.Name() != childCmd.Name() { + t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseWithBadParentFlags(t *testing.T) { - cmd := &Command{ - Use: "do", - TraverseChildren: true, - } - sub := &Command{Use: "next"} - sub.Flags().String("add", "", "add things") - cmd.AddCommand(sub) + rootCmd := &Command{Use: "root", TraverseChildren: true} - expected := "got unknown flag: --add" + childCmd := &Command{Use: "child"} + childCmd.Flags().String("str", "", "") + rootCmd.AddCommand(childCmd) - c, _, err := cmd.Traverse([]string{"--add", "ok", "next"}) - if err == nil || strings.Contains(err.Error(), expected) { - t.Fatalf("Expected error %s got %s", expected, err) + expected := "unknown flag: --str" + + c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"}) + if err == nil || !strings.Contains(err.Error(), expected) { + t.Errorf("Expected error, %q, got %q", expected, err) } if c != nil { - t.Fatalf("Expected nil command") + t.Errorf("Expected nil command") } } func TestTraverseWithBadChildFlag(t *testing.T) { - cmd := &Command{ - Use: "do", - TraverseChildren: true, - } - cmd.Flags().String("foo", "", "foo things") + rootCmd := &Command{Use: "root", TraverseChildren: true} + rootCmd.Flags().String("str", "", "") - sub := &Command{Use: "next"} - cmd.AddCommand(sub) + childCmd := &Command{Use: "child"} + rootCmd.AddCommand(childCmd) // Expect no error because the last commands args shouldn't be parsed in - // Traverse - c, args, err := cmd.Traverse([]string{"next", "--add"}) + // Traverse. + c, args, err := rootCmd.Traverse([]string{"child", "--str"}) if err != nil { - t.Fatalf("Expected no error: %s", err) + t.Errorf("Unexpected error: %v", err) } - if len(args) != 1 && args[0] != "--add" { - t.Fatalf("wrong args %s", args) + if len(args) != 1 && args[0] != "--str" { + t.Errorf("Wrong args: %v", args) } - if c.Name() != sub.Name() { - t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name()) + if c.Name() != childCmd.Name() { + t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name()) } } func TestTraverseWithTwoSubcommands(t *testing.T) { - cmd := &Command{ - Use: "do", - TraverseChildren: true, - } + rootCmd := &Command{Use: "root", TraverseChildren: true} - sub := &Command{ - Use: "sub", - TraverseChildren: true, - } - cmd.AddCommand(sub) + subCmd := &Command{Use: "sub", TraverseChildren: true} + rootCmd.AddCommand(subCmd) - subsub := &Command{ + subsubCmd := &Command{ Use: "subsub", } - sub.AddCommand(subsub) + subCmd.AddCommand(subsubCmd) - c, _, err := cmd.Traverse([]string{"sub", "subsub"}) + c, _, err := rootCmd.Traverse([]string{"sub", "subsub"}) if err != nil { - t.Fatalf("Expected no error: %s", err) + t.Fatalf("Unexpected error: %v", err) } - if c.Name() != subsub.Name() { - t.Fatalf("wrong command %q expected %q", c.Name(), subsub.Name()) - } -} - -func TestRequiredFlags(t *testing.T) { - c := &Command{Use: "c", Run: func(*Command, []string) {}} - output := new(bytes.Buffer) - c.SetOutput(output) - c.Flags().String("foo1", "", "required foo1") - c.MarkFlagRequired("foo1") - c.Flags().String("foo2", "", "required foo2") - c.MarkFlagRequired("foo2") - c.Flags().String("bar", "", "optional bar") - - expected := fmt.Sprintf("Required flag(s) %q, %q have/has not been set", "foo1", "foo2") - - if err := c.Execute(); err != nil { - if err.Error() != expected { - t.Errorf("expected %v, got %v", expected, err.Error()) - } - } -} - -func TestPersistentRequiredFlags(t *testing.T) { - parent := &Command{Use: "parent", Run: func(*Command, []string) {}} - output := new(bytes.Buffer) - parent.SetOutput(output) - parent.PersistentFlags().String("foo1", "", "required foo1") - parent.MarkPersistentFlagRequired("foo1") - parent.PersistentFlags().String("foo2", "", "required foo2") - parent.MarkPersistentFlagRequired("foo2") - parent.Flags().String("foo3", "", "optional foo3") - - child := &Command{Use: "child", Run: func(*Command, []string) {}} - child.Flags().String("bar1", "", "required bar1") - child.MarkFlagRequired("bar1") - child.Flags().String("bar2", "", "required bar2") - child.MarkFlagRequired("bar2") - child.Flags().String("bar3", "", "optional bar3") - - parent.AddCommand(child) - parent.SetArgs([]string{"child"}) - - expected := fmt.Sprintf("Required flag(s) %q, %q, %q, %q have/has not been set", "bar1", "bar2", "foo1", "foo2") - - if err := parent.Execute(); err != nil { - if err.Error() != expected { - t.Errorf("expected %v, got %v", expected, err.Error()) - } + if c.Name() != subsubCmd.Name() { + t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name()) } } @@ -524,3 +1563,171 @@ func TestUpdateName(t *testing.T) { t.Error("c.Name() should be updated on changed c.Use") } } + +type calledAsTestcase struct { + args []string + call string + want string + epm bool + tc bool +} + +func (tc *calledAsTestcase) test(t *testing.T) { + defer func(ov bool) { EnablePrefixMatching = ov }(EnablePrefixMatching) + EnablePrefixMatching = tc.epm + + var called *Command + run := func(c *Command, _ []string) { t.Logf("called: %q", c.Name()); called = c } + + parent := &Command{Use: "parent", Run: run} + child1 := &Command{Use: "child1", Run: run, Aliases: []string{"this"}} + child2 := &Command{Use: "child2", Run: run, Aliases: []string{"that"}} + + parent.AddCommand(child1) + parent.AddCommand(child2) + parent.SetArgs(tc.args) + + output := new(bytes.Buffer) + parent.SetOutput(output) + + parent.Execute() + + if called == nil { + if tc.call != "" { + t.Errorf("missing expected call to command: %s", tc.call) + } + return + } + + if called.Name() != tc.call { + t.Errorf("called command == %q; Wanted %q", called.Name(), tc.call) + } else if got := called.CalledAs(); got != tc.want { + t.Errorf("%s.CalledAs() == %q; Wanted: %q", tc.call, got, tc.want) + } +} + +func TestCalledAs(t *testing.T) { + tests := map[string]calledAsTestcase{ + "find/no-args": {nil, "parent", "parent", false, false}, + "find/real-name": {[]string{"child1"}, "child1", "child1", false, false}, + "find/full-alias": {[]string{"that"}, "child2", "that", false, false}, + "find/part-no-prefix": {[]string{"thi"}, "", "", false, false}, + "find/part-alias": {[]string{"thi"}, "child1", "this", true, false}, + "find/conflict": {[]string{"th"}, "", "", true, false}, + "traverse/no-args": {nil, "parent", "parent", false, true}, + "traverse/real-name": {[]string{"child1"}, "child1", "child1", false, true}, + "traverse/full-alias": {[]string{"that"}, "child2", "that", false, true}, + "traverse/part-no-prefix": {[]string{"thi"}, "", "", false, true}, + "traverse/part-alias": {[]string{"thi"}, "child1", "this", true, true}, + "traverse/conflict": {[]string{"th"}, "", "", true, true}, + } + + for name, tc := range tests { + t.Run(name, tc.test) + } +} + +func TestFParseErrWhitelistBackwardCompatibility(t *testing.T) { + c := &Command{Use: "c", Run: emptyRun} + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + output, err := executeCommand(c, "c", "-a", "--unknown", "flag") + if err == nil { + t.Error("expected unknown flag error") + } + checkStringContains(t, output, "unknown flag: --unknown") +} + +func TestFParseErrWhitelistSameCommand(t *testing.T) { + c := &Command{ + Use: "c", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + _, err := executeCommand(c, "c", "-a", "--unknown", "flag") + if err != nil { + t.Error("unexpected error: ", err) + } +} + +func TestFParseErrWhitelistParentCommand(t *testing.T) { + root := &Command{ + Use: "root", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + + c := &Command{ + Use: "child", + Run: emptyRun, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + root.AddCommand(c) + + output, err := executeCommand(root, "child", "-a", "--unknown", "flag") + if err == nil { + t.Error("expected unknown flag error") + } + checkStringContains(t, output, "unknown flag: --unknown") +} + +func TestFParseErrWhitelistChildCommand(t *testing.T) { + root := &Command{ + Use: "root", + Run: emptyRun, + } + + c := &Command{ + Use: "child", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + root.AddCommand(c) + + _, err := executeCommand(root, "child", "-a", "--unknown", "flag") + if err != nil { + t.Error("unexpected error: ", err.Error()) + } +} + +func TestFParseErrWhitelistSiblingCommand(t *testing.T) { + root := &Command{ + Use: "root", + Run: emptyRun, + } + + c := &Command{ + Use: "child", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + s := &Command{ + Use: "sibling", + Run: emptyRun, + } + s.Flags().BoolP("boolb", "b", false, "a boolean flag") + + root.AddCommand(c) + root.AddCommand(s) + + output, err := executeCommand(root, "sibling", "-b", "--unknown", "flag") + if err == nil { + t.Error("expected unknown flag error") + } + checkStringContains(t, output, "unknown flag: --unknown") +} diff --git a/vendor/github.com/spf13/cobra/doc/cmd_test.go b/vendor/github.com/spf13/cobra/doc/cmd_test.go index a4b5568f..d29c577d 100644 --- a/vendor/github.com/spf13/cobra/doc/cmd_test.go +++ b/vendor/github.com/spf13/cobra/doc/cmd_test.go @@ -1,145 +1,86 @@ package doc import ( - "bytes" - "fmt" - "runtime" "strings" "testing" "github.com/spf13/cobra" ) -var flagb1, flagb2, flagb3, flagbr, flagbp bool -var flags1, flags2a, flags2b, flags3 string -var flagi1, flagi2, flagi3, flagir int +func emptyRun(*cobra.Command, []string) {} -const strtwoParentHelp = "help message for parent flag strtwo" -const strtwoChildHelp = "help message for child flag strtwo" +func init() { + rootCmd.PersistentFlags().StringP("rootflag", "r", "two", "") + rootCmd.PersistentFlags().StringP("strtwo", "t", "two", "help message for parent flag strtwo") -var cmdEcho = &cobra.Command{ + echoCmd.PersistentFlags().StringP("strone", "s", "one", "help message for flag strone") + echoCmd.PersistentFlags().BoolP("persistentbool", "p", false, "help message for flag persistentbool") + echoCmd.Flags().IntP("intone", "i", 123, "help message for flag intone") + echoCmd.Flags().BoolP("boolone", "b", true, "help message for flag boolone") + + timesCmd.PersistentFlags().StringP("strtwo", "t", "2", "help message for child flag strtwo") + timesCmd.Flags().IntP("inttwo", "j", 234, "help message for flag inttwo") + timesCmd.Flags().BoolP("booltwo", "c", false, "help message for flag booltwo") + + printCmd.PersistentFlags().StringP("strthree", "s", "three", "help message for flag strthree") + printCmd.Flags().IntP("intthree", "i", 345, "help message for flag intthree") + printCmd.Flags().BoolP("boolthree", "b", true, "help message for flag boolthree") + + echoCmd.AddCommand(timesCmd, echoSubCmd, deprecatedCmd) + rootCmd.AddCommand(printCmd, echoCmd) +} + +var rootCmd = &cobra.Command{ + Use: "root", + Short: "Root short description", + Long: "Root long description", + Run: emptyRun, +} + +var echoCmd = &cobra.Command{ Use: "echo [string to echo]", Aliases: []string{"say"}, Short: "Echo anything to the screen", - Long: `an utterly useless command for testing.`, + Long: "an utterly useless command for testing", Example: "Just run cobra-test echo", } -var cmdEchoSub = &cobra.Command{ +var echoSubCmd = &cobra.Command{ Use: "echosub [string to print]", Short: "second sub command for echo", - Long: `an absolutely utterly useless command for testing gendocs!.`, - Run: func(cmd *cobra.Command, args []string) {}, + Long: "an absolutely utterly useless command for testing gendocs!.", + Run: emptyRun, } -var cmdDeprecated = &cobra.Command{ +var timesCmd = &cobra.Command{ + Use: "times [# times] [string to echo]", + SuggestFor: []string{"counts"}, + Short: "Echo anything to the screen more times", + Long: `a slightly useless command for testing.`, + Run: emptyRun, +} + +var deprecatedCmd = &cobra.Command{ Use: "deprecated [can't do anything here]", Short: "A command which is deprecated", Long: `an absolutely utterly useless command for testing deprecation!.`, Deprecated: "Please use echo instead", } -var cmdTimes = &cobra.Command{ - Use: "times [# times] [string to echo]", - SuggestFor: []string{"counts"}, - Short: "Echo anything to the screen more times", - Long: `a slightly useless command for testing.`, - PersistentPreRun: func(cmd *cobra.Command, args []string) {}, - Run: func(cmd *cobra.Command, args []string) {}, -} - -var cmdPrint = &cobra.Command{ +var printCmd = &cobra.Command{ Use: "print [string to print]", Short: "Print anything to the screen", Long: `an absolutely utterly useless command for testing.`, } -var cmdRootNoRun = &cobra.Command{ - Use: "cobra-test", - Short: "The root can run its own function", - Long: "The root description for help", -} - -var cmdRootSameName = &cobra.Command{ - Use: "print", - Short: "Root with the same name as a subcommand", - Long: "The root description for help", -} - -var cmdRootWithRun = &cobra.Command{ - Use: "cobra-test", - Short: "The root can run its own function", - Long: "The root description for help", -} - -var cmdSubNoRun = &cobra.Command{ - Use: "subnorun", - Short: "A subcommand without a Run function", - Long: "A long output about a subcommand without a Run function", -} - -var cmdVersion1 = &cobra.Command{ - Use: "version", - Short: "Print the version number", - Long: `First version of the version command`, -} - -var cmdVersion2 = &cobra.Command{ - Use: "version", - Short: "Print the version number", - Long: `Second version of the version command`, -} - -func flagInit() { - cmdEcho.ResetFlags() - cmdPrint.ResetFlags() - cmdTimes.ResetFlags() - cmdRootNoRun.ResetFlags() - cmdRootSameName.ResetFlags() - cmdRootWithRun.ResetFlags() - cmdSubNoRun.ResetFlags() - cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp) - cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone") - cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo") - cmdPrint.Flags().IntVarP(&flagi3, "intthree", "i", 345, "help message for flag intthree") - cmdEcho.PersistentFlags().StringVarP(&flags1, "strone", "s", "one", "help message for flag strone") - cmdEcho.PersistentFlags().BoolVarP(&flagbp, "persistentbool", "p", false, "help message for flag persistentbool") - cmdTimes.PersistentFlags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp) - cmdPrint.PersistentFlags().StringVarP(&flags3, "strthree", "s", "three", "help message for flag strthree") - cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone") - cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo") - cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree") - cmdVersion1.ResetFlags() - cmdVersion2.ResetFlags() -} - -func initializeWithRootCmd() *cobra.Command { - cmdRootWithRun.ResetCommands() - flagInit() - cmdRootWithRun.Flags().BoolVarP(&flagbr, "boolroot", "b", false, "help message for flag boolroot") - cmdRootWithRun.Flags().IntVarP(&flagir, "introot", "i", 321, "help message for flag introot") - return cmdRootWithRun -} - -func checkStringContains(t *testing.T, found, expected string) { - if !strings.Contains(found, expected) { - logErr(t, found, expected) +func checkStringContains(t *testing.T, got, expected string) { + if !strings.Contains(got, expected) { + t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got) } } -func checkStringOmits(t *testing.T, found, expected string) { - if strings.Contains(found, expected) { - logErr(t, found, expected) +func checkStringOmits(t *testing.T, got, expected string) { + if strings.Contains(got, expected) { + t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) } } - -func logErr(t *testing.T, found, expected string) { - out := new(bytes.Buffer) - - _, _, line, ok := runtime.Caller(2) - if ok { - fmt.Fprintf(out, "Line: %d ", line) - } - fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - t.Errorf(out.String()) -} diff --git a/vendor/github.com/spf13/cobra/doc/man_docs.go b/vendor/github.com/spf13/cobra/doc/man_docs.go index ce92332d..baa48118 100644 --- a/vendor/github.com/spf13/cobra/doc/man_docs.go +++ b/vendor/github.com/spf13/cobra/doc/man_docs.go @@ -176,13 +176,13 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) { func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) { flags := command.NonInheritedFlags() - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("# OPTIONS\n") manPrintFlags(buf, flags) buf.WriteString("\n") } flags = command.InheritedFlags() - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n") manPrintFlags(buf, flags) buf.WriteString("\n") diff --git a/vendor/github.com/spf13/cobra/doc/man_docs_test.go b/vendor/github.com/spf13/cobra/doc/man_docs_test.go index 87991063..2c400f5d 100644 --- a/vendor/github.com/spf13/cobra/doc/man_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/man_docs_test.go @@ -18,135 +18,133 @@ func translate(in string) string { } func TestGenManDoc(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - - out := new(bytes.Buffer) - header := &GenManHeader{ Title: "Project", Section: "2", } + // We generate on a subcommand so we have both subcommands and parents - if err := GenMan(cmdEcho, header, out); err != nil { + buf := new(bytes.Buffer) + if err := GenMan(echoCmd, header, buf); err != nil { t.Fatal(err) } - found := out.String() + output := buf.String() // Make sure parent has - in CommandPath() in SEE ALSO: - parentPath := cmdEcho.Parent().CommandPath() + parentPath := echoCmd.Parent().CommandPath() dashParentPath := strings.Replace(parentPath, " ", "-", -1) expected := translate(dashParentPath) expected = expected + "(" + header.Section + ")" - checkStringContains(t, found, expected) + checkStringContains(t, output, expected) - // Our description - expected = translate(cmdEcho.Name()) - checkStringContains(t, found, expected) + checkStringContains(t, output, translate(echoCmd.Name())) + checkStringContains(t, output, translate(echoCmd.Name())) + checkStringContains(t, output, "boolone") + checkStringContains(t, output, "rootflag") + checkStringContains(t, output, translate(rootCmd.Name())) + checkStringContains(t, output, translate(echoSubCmd.Name())) + checkStringOmits(t, output, translate(deprecatedCmd.Name())) + checkStringContains(t, output, translate("Auto generated")) +} - // Better have our example - expected = translate(cmdEcho.Name()) - checkStringContains(t, found, expected) +func TestGenManNoHiddenParents(t *testing.T) { + header := &GenManHeader{ + Title: "Project", + Section: "2", + } - // A local flag - expected = "boolone" - checkStringContains(t, found, expected) + // We generate on a subcommand so we have both subcommands and parents + for _, name := range []string{"rootflag", "strtwo"} { + f := rootCmd.PersistentFlags().Lookup(name) + f.Hidden = true + defer func() { f.Hidden = false }() + } + buf := new(bytes.Buffer) + if err := GenMan(echoCmd, header, buf); err != nil { + t.Fatal(err) + } + output := buf.String() - // persistent flag on parent - expected = "rootflag" - checkStringContains(t, found, expected) + // Make sure parent has - in CommandPath() in SEE ALSO: + parentPath := echoCmd.Parent().CommandPath() + dashParentPath := strings.Replace(parentPath, " ", "-", -1) + expected := translate(dashParentPath) + expected = expected + "(" + header.Section + ")" + checkStringContains(t, output, expected) - // We better output info about our parent - expected = translate(cmdRootWithRun.Name()) - checkStringContains(t, found, expected) - - // And about subcommands - expected = translate(cmdEchoSub.Name()) - checkStringContains(t, found, expected) - - unexpected := translate(cmdDeprecated.Name()) - checkStringOmits(t, found, unexpected) - - // auto generated - expected = translate("Auto generated") - checkStringContains(t, found, expected) + checkStringContains(t, output, translate(echoCmd.Name())) + checkStringContains(t, output, translate(echoCmd.Name())) + checkStringContains(t, output, "boolone") + checkStringOmits(t, output, "rootflag") + checkStringContains(t, output, translate(rootCmd.Name())) + checkStringContains(t, output, translate(echoSubCmd.Name())) + checkStringOmits(t, output, translate(deprecatedCmd.Name())) + checkStringContains(t, output, translate("Auto generated")) + checkStringOmits(t, output, "OPTIONS INHERITED FROM PARENT COMMANDS") } func TestGenManNoGenTag(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - cmdEcho.DisableAutoGenTag = true - out := new(bytes.Buffer) + echoCmd.DisableAutoGenTag = true + defer func() { echoCmd.DisableAutoGenTag = false }() header := &GenManHeader{ Title: "Project", Section: "2", } + // We generate on a subcommand so we have both subcommands and parents - if err := GenMan(cmdEcho, header, out); err != nil { + buf := new(bytes.Buffer) + if err := GenMan(echoCmd, header, buf); err != nil { t.Fatal(err) } - found := out.String() + output := buf.String() unexpected := translate("#HISTORY") - checkStringOmits(t, found, unexpected) + checkStringOmits(t, output, unexpected) } func TestGenManSeeAlso(t *testing.T) { - noop := func(cmd *cobra.Command, args []string) {} + rootCmd := &cobra.Command{Use: "root", Run: emptyRun} + aCmd := &cobra.Command{Use: "aaa", Run: emptyRun, Hidden: true} // #229 + bCmd := &cobra.Command{Use: "bbb", Run: emptyRun} + cCmd := &cobra.Command{Use: "ccc", Run: emptyRun} + rootCmd.AddCommand(aCmd, bCmd, cCmd) - top := &cobra.Command{Use: "top", Run: noop} - aaa := &cobra.Command{Use: "aaa", Run: noop, Hidden: true} // #229 - bbb := &cobra.Command{Use: "bbb", Run: noop} - ccc := &cobra.Command{Use: "ccc", Run: noop} - top.AddCommand(aaa, bbb, ccc) - - out := new(bytes.Buffer) + buf := new(bytes.Buffer) header := &GenManHeader{} - if err := GenMan(top, header, out); err != nil { + if err := GenMan(rootCmd, header, buf); err != nil { t.Fatal(err) } + scanner := bufio.NewScanner(buf) - scanner := bufio.NewScanner(out) - - if err := AssertLineFound(scanner, ".SH SEE ALSO"); err != nil { - t.Fatal(fmt.Errorf("Couldn't find SEE ALSO section header: %s", err.Error())) + if err := assertLineFound(scanner, ".SH SEE ALSO"); err != nil { + t.Fatalf("Couldn't find SEE ALSO section header: %v", err) } - - if err := AssertNextLineEquals(scanner, ".PP"); err != nil { - t.Fatal(fmt.Errorf("First line after SEE ALSO wasn't break-indent: %s", err.Error())) + if err := assertNextLineEquals(scanner, ".PP"); err != nil { + t.Fatalf("First line after SEE ALSO wasn't break-indent: %v", err) } - - if err := AssertNextLineEquals(scanner, `\fBtop\-bbb(1)\fP, \fBtop\-ccc(1)\fP`); err != nil { - t.Fatal(fmt.Errorf("Second line after SEE ALSO wasn't correct: %s", err.Error())) + if err := assertNextLineEquals(scanner, `\fBroot\-bbb(1)\fP, \fBroot\-ccc(1)\fP`); err != nil { + t.Fatalf("Second line after SEE ALSO wasn't correct: %v", err) } } func TestManPrintFlagsHidesShortDeperecated(t *testing.T) { - cmd := &cobra.Command{} - flags := cmd.Flags() - flags.StringP("foo", "f", "default", "Foo flag") - flags.MarkShorthandDeprecated("foo", "don't use it no more") + c := &cobra.Command{} + c.Flags().StringP("foo", "f", "default", "Foo flag") + c.Flags().MarkShorthandDeprecated("foo", "don't use it no more") - out := new(bytes.Buffer) - manPrintFlags(out, flags) + buf := new(bytes.Buffer) + manPrintFlags(buf, c.Flags()) + got := buf.String() expected := "**--foo**=\"default\"\n\tFoo flag\n\n" - if out.String() != expected { - t.Fatalf("Expected %s, but got %s", expected, out.String()) + if got != expected { + t.Errorf("Expected %v, got %v", expected, got) } } func TestGenManTree(t *testing.T) { - cmd := &cobra.Command{ - Use: "do [OPTIONS] arg1 arg2", - } + c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} header := &GenManHeader{Section: "2"} tmpdir, err := ioutil.TempDir("", "test-gen-man-tree") if err != nil { @@ -154,7 +152,7 @@ func TestGenManTree(t *testing.T) { } defer os.RemoveAll(tmpdir) - if err := GenManTree(cmd, header, tmpdir); err != nil { + if err := GenManTree(c, header, tmpdir); err != nil { t.Fatalf("GenManTree failed: %s", err.Error()) } @@ -167,7 +165,7 @@ func TestGenManTree(t *testing.T) { } } -func AssertLineFound(scanner *bufio.Scanner, expectedLine string) error { +func assertLineFound(scanner *bufio.Scanner, expectedLine string) error { for scanner.Scan() { line := scanner.Text() if line == expectedLine { @@ -176,30 +174,29 @@ func AssertLineFound(scanner *bufio.Scanner, expectedLine string) error { } if err := scanner.Err(); err != nil { - return fmt.Errorf("AssertLineFound: scan failed: %s", err.Error()) + return fmt.Errorf("scan failed: %s", err) } - return fmt.Errorf("AssertLineFound: hit EOF before finding %#v", expectedLine) + return fmt.Errorf("hit EOF before finding %v", expectedLine) } -func AssertNextLineEquals(scanner *bufio.Scanner, expectedLine string) error { +func assertNextLineEquals(scanner *bufio.Scanner, expectedLine string) error { if scanner.Scan() { line := scanner.Text() if line == expectedLine { return nil } - return fmt.Errorf("AssertNextLineEquals: got %#v, not %#v", line, expectedLine) + return fmt.Errorf("got %v, not %v", line, expectedLine) } if err := scanner.Err(); err != nil { - return fmt.Errorf("AssertNextLineEquals: scan failed: %s", err.Error()) + return fmt.Errorf("scan failed: %v", err) } - return fmt.Errorf("AssertNextLineEquals: hit EOF before finding %#v", expectedLine) + return fmt.Errorf("hit EOF before finding %v", expectedLine) } func BenchmarkGenManToFile(b *testing.B) { - c := initializeWithRootCmd() file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) @@ -209,7 +206,7 @@ func BenchmarkGenManToFile(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - if err := GenMan(c, nil, file); err != nil { + if err := GenMan(rootCmd, nil, file); err != nil { b.Fatal(err) } } diff --git a/vendor/github.com/spf13/cobra/doc/md_docs.go b/vendor/github.com/spf13/cobra/doc/md_docs.go index 68cf5bf6..d76f6d5e 100644 --- a/vendor/github.com/spf13/cobra/doc/md_docs.go +++ b/vendor/github.com/spf13/cobra/doc/md_docs.go @@ -29,7 +29,7 @@ import ( func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() flags.SetOutput(buf) - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("### Options\n\n```\n") flags.PrintDefaults() buf.WriteString("```\n\n") @@ -37,7 +37,7 @@ func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { parentFlags := cmd.InheritedFlags() parentFlags.SetOutput(buf) - if parentFlags.HasFlags() { + if parentFlags.HasAvailableFlags() { buf.WriteString("### Options inherited from parent commands\n\n```\n") parentFlags.PrintDefaults() buf.WriteString("```\n\n") @@ -67,7 +67,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) buf.WriteString("## " + name + "\n\n") buf.WriteString(short + "\n\n") buf.WriteString("### Synopsis\n\n") - buf.WriteString("\n" + long + "\n\n") + buf.WriteString(long + "\n\n") if cmd.Runnable() { buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine())) @@ -82,7 +82,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) return err } if hasSeeAlso(cmd) { - buf.WriteString("### SEE ALSO\n") + buf.WriteString("### SEE ALSO\n\n") if cmd.HasParent() { parent := cmd.Parent() pname := parent.CommandPath() diff --git a/vendor/github.com/spf13/cobra/doc/md_docs_test.go b/vendor/github.com/spf13/cobra/doc/md_docs_test.go index ba6b9a46..c060f32f 100644 --- a/vendor/github.com/spf13/cobra/doc/md_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/md_docs_test.go @@ -5,100 +5,75 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "testing" "github.com/spf13/cobra" ) func TestGenMdDoc(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - - out := new(bytes.Buffer) - - // We generate on s subcommand so we have both subcommands and parents - if err := GenMarkdown(cmdEcho, out); err != nil { + // We generate on subcommand so we have both subcommands and parents. + buf := new(bytes.Buffer) + if err := GenMarkdown(echoCmd, buf); err != nil { t.Fatal(err) } - found := out.String() + output := buf.String() - // Our description - expected := cmdEcho.Long - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringContains(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) + checkStringOmits(t, output, deprecatedCmd.Short) + checkStringContains(t, output, "Options inherited from parent commands") +} - // Better have our example - expected = cmdEcho.Example - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) +func TestGenMdNoHiddenParents(t *testing.T) { + // We generate on subcommand so we have both subcommands and parents. + for _, name := range []string{"rootflag", "strtwo"} { + f := rootCmd.PersistentFlags().Lookup(name) + f.Hidden = true + defer func() { f.Hidden = false }() } + buf := new(bytes.Buffer) + if err := GenMarkdown(echoCmd, buf); err != nil { + t.Fatal(err) + } + output := buf.String() - // A local flag - expected = "boolone" - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // persistent flag on parent - expected = "rootflag" - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // We better output info about our parent - expected = cmdRootWithRun.Short - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // And about subcommands - expected = cmdEchoSub.Short - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - unexpected := cmdDeprecated.Short - if strings.Contains(found, unexpected) { - t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected) - } + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringOmits(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) + checkStringOmits(t, output, deprecatedCmd.Short) + checkStringOmits(t, output, "Options inherited from parent commands") } func TestGenMdNoTag(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - c.DisableAutoGenTag = true - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - out := new(bytes.Buffer) + rootCmd.DisableAutoGenTag = true + defer func() { rootCmd.DisableAutoGenTag = false }() - if err := GenMarkdown(c, out); err != nil { + buf := new(bytes.Buffer) + if err := GenMarkdown(rootCmd, buf); err != nil { t.Fatal(err) } - found := out.String() - - unexpected := "Auto generated" - checkStringOmits(t, found, unexpected) + output := buf.String() + checkStringOmits(t, output, "Auto generated") } func TestGenMdTree(t *testing.T) { - cmd := &cobra.Command{ - Use: "do [OPTIONS] arg1 arg2", - } + c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} tmpdir, err := ioutil.TempDir("", "test-gen-md-tree") if err != nil { - t.Fatalf("Failed to create tmpdir: %s", err.Error()) + t.Fatalf("Failed to create tmpdir: %v", err) } defer os.RemoveAll(tmpdir) - if err := GenMarkdownTree(cmd, tmpdir); err != nil { - t.Fatalf("GenMarkdownTree failed: %s", err.Error()) + if err := GenMarkdownTree(c, tmpdir); err != nil { + t.Fatalf("GenMarkdownTree failed: %v", err) } if _, err := os.Stat(filepath.Join(tmpdir, "do.md")); err != nil { @@ -107,7 +82,6 @@ func TestGenMdTree(t *testing.T) { } func BenchmarkGenMarkdownToFile(b *testing.B) { - c := initializeWithRootCmd() file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) @@ -117,7 +91,7 @@ func BenchmarkGenMarkdownToFile(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - if err := GenMarkdown(c, file); err != nil { + if err := GenMarkdown(rootCmd, file); err != nil { b.Fatal(err) } } diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs.go b/vendor/github.com/spf13/cobra/doc/rest_docs.go index 4913e3ee..051d8dc8 100644 --- a/vendor/github.com/spf13/cobra/doc/rest_docs.go +++ b/vendor/github.com/spf13/cobra/doc/rest_docs.go @@ -29,7 +29,7 @@ import ( func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() flags.SetOutput(buf) - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("Options\n") buf.WriteString("~~~~~~~\n\n::\n\n") flags.PrintDefaults() @@ -38,7 +38,7 @@ func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error parentFlags := cmd.InheritedFlags() parentFlags.SetOutput(buf) - if parentFlags.HasFlags() { + if parentFlags.HasAvailableFlags() { buf.WriteString("Options inherited from parent commands\n") buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n") parentFlags.PrintDefaults() diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs_test.go b/vendor/github.com/spf13/cobra/doc/rest_docs_test.go index d5e1dfad..330a2e5e 100644 --- a/vendor/github.com/spf13/cobra/doc/rest_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/rest_docs_test.go @@ -5,99 +5,75 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "testing" "github.com/spf13/cobra" ) func TestGenRSTDoc(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - - out := new(bytes.Buffer) - - // We generate on s subcommand so we have both subcommands and parents - if err := GenReST(cmdEcho, out); err != nil { + // We generate on a subcommand so we have both subcommands and parents + buf := new(bytes.Buffer) + if err := GenReST(echoCmd, buf); err != nil { t.Fatal(err) } - found := out.String() + output := buf.String() - // Our description - expected := cmdEcho.Long - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringContains(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) + checkStringOmits(t, output, deprecatedCmd.Short) +} - // Better have our example - expected = cmdEcho.Example - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) +func TestGenRSTNoHiddenParents(t *testing.T) { + // We generate on a subcommand so we have both subcommands and parents + for _, name := range []string{"rootflag", "strtwo"} { + f := rootCmd.PersistentFlags().Lookup(name) + f.Hidden = true + defer func() { f.Hidden = false }() } + buf := new(bytes.Buffer) + if err := GenReST(echoCmd, buf); err != nil { + t.Fatal(err) + } + output := buf.String() - // A local flag - expected = "boolone" - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // persistent flag on parent - expected = "rootflag" - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // We better output info about our parent - expected = cmdRootWithRun.Short - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // And about subcommands - expected = cmdEchoSub.Short - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - unexpected := cmdDeprecated.Short - if strings.Contains(found, unexpected) { - t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected) - } + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringOmits(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) + checkStringOmits(t, output, deprecatedCmd.Short) + checkStringOmits(t, output, "Options inherited from parent commands") } func TestGenRSTNoTag(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - c.DisableAutoGenTag = true - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - out := new(bytes.Buffer) + rootCmd.DisableAutoGenTag = true + defer func() { rootCmd.DisableAutoGenTag = false }() - if err := GenReST(c, out); err != nil { + buf := new(bytes.Buffer) + if err := GenReST(rootCmd, buf); err != nil { t.Fatal(err) } - found := out.String() + output := buf.String() unexpected := "Auto generated" - checkStringOmits(t, found, unexpected) - + checkStringOmits(t, output, unexpected) } func TestGenRSTTree(t *testing.T) { - cmd := &cobra.Command{ - Use: "do [OPTIONS] arg1 arg2", - } + c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} + tmpdir, err := ioutil.TempDir("", "test-gen-rst-tree") if err != nil { t.Fatalf("Failed to create tmpdir: %s", err.Error()) } defer os.RemoveAll(tmpdir) - if err := GenReSTTree(cmd, tmpdir); err != nil { + if err := GenReSTTree(c, tmpdir); err != nil { t.Fatalf("GenReSTTree failed: %s", err.Error()) } @@ -107,7 +83,6 @@ func TestGenRSTTree(t *testing.T) { } func BenchmarkGenReSTToFile(b *testing.B) { - c := initializeWithRootCmd() file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) @@ -117,7 +92,7 @@ func BenchmarkGenReSTToFile(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - if err := GenReST(c, file); err != nil { + if err := GenReST(rootCmd, file); err != nil { b.Fatal(err) } } diff --git a/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go b/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go index 29e985e4..c5a63594 100644 --- a/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go @@ -5,92 +5,42 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "testing" "github.com/spf13/cobra" ) func TestGenYamlDoc(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - - out := new(bytes.Buffer) - // We generate on s subcommand so we have both subcommands and parents - if err := GenYaml(cmdEcho, out); err != nil { + buf := new(bytes.Buffer) + if err := GenYaml(echoCmd, buf); err != nil { t.Fatal(err) } - found := out.String() + output := buf.String() - // Our description - expected := cmdEcho.Long - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // Better have our example - expected = cmdEcho.Example - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // A local flag - expected = "boolone" - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // persistent flag on parent - expected = "rootflag" - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // We better output info about our parent - expected = cmdRootWithRun.Short - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - // And about subcommands - expected = cmdEchoSub.Short - if !strings.Contains(found, expected) { - t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) - } - - unexpected := cmdDeprecated.Short - if strings.Contains(found, unexpected) { - t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected) - } + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringContains(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) } func TestGenYamlNoTag(t *testing.T) { - c := initializeWithRootCmd() - // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) - c.AddCommand(cmdPrint, cmdEcho) - c.DisableAutoGenTag = true - cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) - out := new(bytes.Buffer) + rootCmd.DisableAutoGenTag = true + defer func() { rootCmd.DisableAutoGenTag = false }() - if err := GenYaml(c, out); err != nil { + buf := new(bytes.Buffer) + if err := GenYaml(rootCmd, buf); err != nil { t.Fatal(err) } - found := out.String() - - unexpected := "Auto generated" - checkStringOmits(t, found, unexpected) + output := buf.String() + checkStringOmits(t, output, "Auto generated") } func TestGenYamlTree(t *testing.T) { - cmd := &cobra.Command{ - Use: "do [OPTIONS] arg1 arg2", - } + c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} tmpdir, err := ioutil.TempDir("", "test-gen-yaml-tree") if err != nil { @@ -98,7 +48,7 @@ func TestGenYamlTree(t *testing.T) { } defer os.RemoveAll(tmpdir) - if err := GenYamlTree(cmd, tmpdir); err != nil { + if err := GenYamlTree(c, tmpdir); err != nil { t.Fatalf("GenYamlTree failed: %s", err.Error()) } @@ -108,7 +58,6 @@ func TestGenYamlTree(t *testing.T) { } func BenchmarkGenYamlToFile(b *testing.B) { - c := initializeWithRootCmd() file, err := ioutil.TempFile("", "") if err != nil { b.Fatal(err) @@ -118,7 +67,7 @@ func BenchmarkGenYamlToFile(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - if err := GenYaml(c, file); err != nil { + if err := GenYaml(rootCmd, file); err != nil { b.Fatal(err) } } diff --git a/vendor/github.com/spf13/cobra/zsh_completions_test.go b/vendor/github.com/spf13/cobra/zsh_completions_test.go index 08b85159..34e69496 100644 --- a/vendor/github.com/spf13/cobra/zsh_completions_test.go +++ b/vendor/github.com/spf13/cobra/zsh_completions_test.go @@ -77,10 +77,11 @@ func TestZshCompletion(t *testing.T) { t.Run(tc.name, func(t *testing.T) { buf := new(bytes.Buffer) tc.root.GenZshCompletion(buf) - completion := buf.String() + output := buf.String() + for _, expectedExpression := range tc.expectedExpressions { - if !strings.Contains(completion, expectedExpression) { - t.Errorf("expected completion to contain '%v' somewhere; got '%v'", expectedExpression, completion) + if !strings.Contains(output, expectedExpression) { + t.Errorf("Expected completion to contain %q somewhere; got %q", expectedExpression, output) } } }) diff --git a/vendor/github.com/spf13/jwalterweatherman/README.md b/vendor/github.com/spf13/jwalterweatherman/README.md index d8cfd27a..932a23fc 100644 --- a/vendor/github.com/spf13/jwalterweatherman/README.md +++ b/vendor/github.com/spf13/jwalterweatherman/README.md @@ -18,7 +18,7 @@ provides a few advantages over using the standard log library alone. I really wanted a very straightforward library that could seamlessly do the following things. -1. Replace all the println, printf, etc statements thought my code with +1. Replace all the println, printf, etc statements thoughout my code with something more useful 2. Allow the user to easily control what levels are printed to stdout 3. Allow the user to easily control what levels are logged diff --git a/vendor/github.com/spf13/jwalterweatherman/go.mod b/vendor/github.com/spf13/jwalterweatherman/go.mod new file mode 100644 index 00000000..bce549c0 --- /dev/null +++ b/vendor/github.com/spf13/jwalterweatherman/go.mod @@ -0,0 +1 @@ +module github.com/spf13/jwalterweatherman diff --git a/vendor/github.com/spf13/pflag/bytes.go b/vendor/github.com/spf13/pflag/bytes.go new file mode 100644 index 00000000..67d53045 --- /dev/null +++ b/vendor/github.com/spf13/pflag/bytes.go @@ -0,0 +1,209 @@ +package pflag + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strings" +) + +// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded +type bytesHexValue []byte + +// String implements pflag.Value.String. +func (bytesHex bytesHexValue) String() string { + return fmt.Sprintf("%X", []byte(bytesHex)) +} + +// Set implements pflag.Value.Set. +func (bytesHex *bytesHexValue) Set(value string) error { + bin, err := hex.DecodeString(strings.TrimSpace(value)) + + if err != nil { + return err + } + + *bytesHex = bin + + return nil +} + +// Type implements pflag.Value.Type. +func (*bytesHexValue) Type() string { + return "bytesHex" +} + +func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue { + *p = val + return (*bytesHexValue)(p) +} + +func bytesHexConv(sval string) (interface{}, error) { + + bin, err := hex.DecodeString(sval) + + if err == nil { + return bin, nil + } + + return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err) +} + +// GetBytesHex return the []byte value of a flag with the given name +func (f *FlagSet) GetBytesHex(name string) ([]byte, error) { + val, err := f.getFlagType(name, "bytesHex", bytesHexConv) + + if err != nil { + return []byte{}, err + } + + return val.([]byte), nil +} + +// BytesHexVar defines an []byte flag with specified name, default value, and usage string. +// The argument p points to an []byte variable in which to store the value of the flag. +func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) { + f.VarP(newBytesHexValue(value, p), name, "", usage) +} + +// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) { + f.VarP(newBytesHexValue(value, p), name, shorthand, usage) +} + +// BytesHexVar defines an []byte flag with specified name, default value, and usage string. +// The argument p points to an []byte variable in which to store the value of the flag. +func BytesHexVar(p *[]byte, name string, value []byte, usage string) { + CommandLine.VarP(newBytesHexValue(value, p), name, "", usage) +} + +// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash. +func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) { + CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage) +} + +// BytesHex defines an []byte flag with specified name, default value, and usage string. +// The return value is the address of an []byte variable that stores the value of the flag. +func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte { + p := new([]byte) + f.BytesHexVarP(p, name, "", value, usage) + return p +} + +// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte { + p := new([]byte) + f.BytesHexVarP(p, name, shorthand, value, usage) + return p +} + +// BytesHex defines an []byte flag with specified name, default value, and usage string. +// The return value is the address of an []byte variable that stores the value of the flag. +func BytesHex(name string, value []byte, usage string) *[]byte { + return CommandLine.BytesHexP(name, "", value, usage) +} + +// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash. +func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte { + return CommandLine.BytesHexP(name, shorthand, value, usage) +} + +// BytesBase64 adapts []byte for use as a flag. Value of flag is Base64 encoded +type bytesBase64Value []byte + +// String implements pflag.Value.String. +func (bytesBase64 bytesBase64Value) String() string { + return base64.StdEncoding.EncodeToString([]byte(bytesBase64)) +} + +// Set implements pflag.Value.Set. +func (bytesBase64 *bytesBase64Value) Set(value string) error { + bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value)) + + if err != nil { + return err + } + + *bytesBase64 = bin + + return nil +} + +// Type implements pflag.Value.Type. +func (*bytesBase64Value) Type() string { + return "bytesBase64" +} + +func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value { + *p = val + return (*bytesBase64Value)(p) +} + +func bytesBase64ValueConv(sval string) (interface{}, error) { + + bin, err := base64.StdEncoding.DecodeString(sval) + if err == nil { + return bin, nil + } + + return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err) +} + +// GetBytesBase64 return the []byte value of a flag with the given name +func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) { + val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv) + + if err != nil { + return []byte{}, err + } + + return val.([]byte), nil +} + +// BytesBase64Var defines an []byte flag with specified name, default value, and usage string. +// The argument p points to an []byte variable in which to store the value of the flag. +func (f *FlagSet) BytesBase64Var(p *[]byte, name string, value []byte, usage string) { + f.VarP(newBytesBase64Value(value, p), name, "", usage) +} + +// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) { + f.VarP(newBytesBase64Value(value, p), name, shorthand, usage) +} + +// BytesBase64Var defines an []byte flag with specified name, default value, and usage string. +// The argument p points to an []byte variable in which to store the value of the flag. +func BytesBase64Var(p *[]byte, name string, value []byte, usage string) { + CommandLine.VarP(newBytesBase64Value(value, p), name, "", usage) +} + +// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash. +func BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) { + CommandLine.VarP(newBytesBase64Value(value, p), name, shorthand, usage) +} + +// BytesBase64 defines an []byte flag with specified name, default value, and usage string. +// The return value is the address of an []byte variable that stores the value of the flag. +func (f *FlagSet) BytesBase64(name string, value []byte, usage string) *[]byte { + p := new([]byte) + f.BytesBase64VarP(p, name, "", value, usage) + return p +} + +// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte { + p := new([]byte) + f.BytesBase64VarP(p, name, shorthand, value, usage) + return p +} + +// BytesBase64 defines an []byte flag with specified name, default value, and usage string. +// The return value is the address of an []byte variable that stores the value of the flag. +func BytesBase64(name string, value []byte, usage string) *[]byte { + return CommandLine.BytesBase64P(name, "", value, usage) +} + +// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash. +func BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte { + return CommandLine.BytesBase64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/bytes_test.go b/vendor/github.com/spf13/pflag/bytes_test.go new file mode 100644 index 00000000..5251f347 --- /dev/null +++ b/vendor/github.com/spf13/pflag/bytes_test.go @@ -0,0 +1,134 @@ +package pflag + +import ( + "encoding/base64" + "fmt" + "os" + "testing" +) + +func setUpBytesHex(bytesHex *[]byte) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.BytesHexVar(bytesHex, "bytes", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in HEX") + f.BytesHexVarP(bytesHex, "bytes2", "B", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in HEX") + return f +} + +func TestBytesHex(t *testing.T) { + testCases := []struct { + input string + success bool + expected string + }{ + /// Positive cases + {"", true, ""}, // Is empty string OK ? + {"01", true, "01"}, + {"0101", true, "0101"}, + {"1234567890abcdef", true, "1234567890ABCDEF"}, + {"1234567890ABCDEF", true, "1234567890ABCDEF"}, + + // Negative cases + {"0", false, ""}, // Short string + {"000", false, ""}, /// Odd-length string + {"qq", false, ""}, /// non-hex character + } + + devnull, _ := os.Open(os.DevNull) + os.Stderr = devnull + + for i := range testCases { + var bytesHex []byte + f := setUpBytesHex(&bytesHex) + + tc := &testCases[i] + + // --bytes + args := []string{ + fmt.Sprintf("--bytes=%s", tc.input), + fmt.Sprintf("-B %s", tc.input), + fmt.Sprintf("--bytes2=%s", tc.input), + } + + for _, arg := range args { + err := f.Parse([]string{arg}) + + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + // bytesHex, err := f.GetBytesHex("bytes") + t.Errorf("expected failure while processing %q", tc.input) + continue + } else if tc.success { + bytesHex, err := f.GetBytesHex("bytes") + if err != nil { + t.Errorf("Got error trying to fetch the 'bytes' flag: %v", err) + } + if fmt.Sprintf("%X", bytesHex) != tc.expected { + t.Errorf("expected %q, got '%X'", tc.expected, bytesHex) + } + } + } + } +} + +func setUpBytesBase64(bytesBase64 *[]byte) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.BytesBase64Var(bytesBase64, "bytes", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in Base64") + f.BytesBase64VarP(bytesBase64, "bytes2", "B", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in Base64") + return f +} + +func TestBytesBase64(t *testing.T) { + testCases := []struct { + input string + success bool + expected string + }{ + /// Positive cases + {"", true, ""}, // Is empty string OK ? + {"AQ==", true, "AQ=="}, + + // Negative cases + {"AQ", false, ""}, // Padding removed + {"ï", false, ""}, // non-base64 characters + } + + devnull, _ := os.Open(os.DevNull) + os.Stderr = devnull + + for i := range testCases { + var bytesBase64 []byte + f := setUpBytesBase64(&bytesBase64) + + tc := &testCases[i] + + // --bytes + args := []string{ + fmt.Sprintf("--bytes=%s", tc.input), + fmt.Sprintf("-B %s", tc.input), + fmt.Sprintf("--bytes2=%s", tc.input), + } + + for _, arg := range args { + err := f.Parse([]string{arg}) + + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + // bytesBase64, err := f.GetBytesBase64("bytes") + t.Errorf("expected failure while processing %q", tc.input) + continue + } else if tc.success { + bytesBase64, err := f.GetBytesBase64("bytes") + if err != nil { + t.Errorf("Got error trying to fetch the 'bytes' flag: %v", err) + } + if base64.StdEncoding.EncodeToString(bytesBase64) != tc.expected { + t.Errorf("expected %q, got '%X'", tc.expected, bytesBase64) + } + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go index 250a4381..aa126e44 100644 --- a/vendor/github.com/spf13/pflag/count.go +++ b/vendor/github.com/spf13/pflag/count.go @@ -11,13 +11,13 @@ func newCountValue(val int, p *int) *countValue { } func (i *countValue) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - // -1 means that no specific value was passed, so increment - if v == -1 { + // "+1" means that no specific value was passed, so increment + if s == "+1" { *i = countValue(*i + 1) - } else { - *i = countValue(v) + return nil } + v, err := strconv.ParseInt(s, 0, 0) + *i = countValue(v) return err } @@ -54,7 +54,7 @@ func (f *FlagSet) CountVar(p *int, name string, usage string) { // CountVarP is like CountVar only take a shorthand for the flag name. func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) - flag.NoOptDefVal = "-1" + flag.NoOptDefVal = "+1" } // CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set diff --git a/vendor/github.com/spf13/pflag/count_test.go b/vendor/github.com/spf13/pflag/count_test.go index 460d96a6..3785d375 100644 --- a/vendor/github.com/spf13/pflag/count_test.go +++ b/vendor/github.com/spf13/pflag/count_test.go @@ -17,10 +17,14 @@ func TestCount(t *testing.T) { success bool expected int }{ + {[]string{}, true, 0}, + {[]string{"-v"}, true, 1}, {[]string{"-vvv"}, true, 3}, {[]string{"-v", "-v", "-v"}, true, 3}, {[]string{"-v", "--verbose", "-v"}, true, 3}, {[]string{"-v=3", "-v"}, true, 4}, + {[]string{"--verbose=0"}, true, 0}, + {[]string{"-v=0"}, true, 0}, {[]string{"-v=a"}, false, 0}, } @@ -45,7 +49,7 @@ func TestCount(t *testing.T) { t.Errorf("Got error trying to fetch the counter flag") } if c != tc.expected { - t.Errorf("expected %q, got %q", tc.expected, c) + t.Errorf("expected %d, got %d", tc.expected, c) } } } diff --git a/vendor/github.com/spf13/pflag/duration_slice.go b/vendor/github.com/spf13/pflag/duration_slice.go new file mode 100644 index 00000000..52c6b6dc --- /dev/null +++ b/vendor/github.com/spf13/pflag/duration_slice.go @@ -0,0 +1,128 @@ +package pflag + +import ( + "fmt" + "strings" + "time" +) + +// -- durationSlice Value +type durationSliceValue struct { + value *[]time.Duration + changed bool +} + +func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue { + dsv := new(durationSliceValue) + dsv.value = p + *dsv.value = val + return dsv +} + +func (s *durationSliceValue) Set(val string) error { + ss := strings.Split(val, ",") + out := make([]time.Duration, len(ss)) + for i, d := range ss { + var err error + out[i], err = time.ParseDuration(d) + if err != nil { + return err + } + + } + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + s.changed = true + return nil +} + +func (s *durationSliceValue) Type() string { + return "durationSlice" +} + +func (s *durationSliceValue) String() string { + out := make([]string, len(*s.value)) + for i, d := range *s.value { + out[i] = fmt.Sprintf("%s", d) + } + return "[" + strings.Join(out, ",") + "]" +} + +func durationSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []time.Duration{}, nil + } + ss := strings.Split(val, ",") + out := make([]time.Duration, len(ss)) + for i, d := range ss { + var err error + out[i], err = time.ParseDuration(d) + if err != nil { + return nil, err + } + + } + return out, nil +} + +// GetDurationSlice returns the []time.Duration value of a flag with the given name +func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) { + val, err := f.getFlagType(name, "durationSlice", durationSliceConv) + if err != nil { + return []time.Duration{}, err + } + return val.([]time.Duration), nil +} + +// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string. +// The argument p points to a []time.Duration variable in which to store the value of the flag. +func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) { + f.VarP(newDurationSliceValue(value, p), name, "", usage) +} + +// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) { + f.VarP(newDurationSliceValue(value, p), name, shorthand, usage) +} + +// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string. +// The argument p points to a duration[] variable in which to store the value of the flag. +func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) { + CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage) +} + +// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash. +func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) { + CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage) +} + +// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a []time.Duration variable that stores the value of the flag. +func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration { + p := []time.Duration{} + f.DurationSliceVarP(&p, name, "", value, usage) + return &p +} + +// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration { + p := []time.Duration{} + f.DurationSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a []time.Duration variable that stores the value of the flag. +func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration { + return CommandLine.DurationSliceP(name, "", value, usage) +} + +// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash. +func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration { + return CommandLine.DurationSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/duration_slice_test.go b/vendor/github.com/spf13/pflag/duration_slice_test.go new file mode 100644 index 00000000..489b012f --- /dev/null +++ b/vendor/github.com/spf13/pflag/duration_slice_test.go @@ -0,0 +1,165 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code ds governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "fmt" + "strings" + "testing" + "time" +) + +func setUpDSFlagSet(dsp *[]time.Duration) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.DurationSliceVar(dsp, "ds", []time.Duration{}, "Command separated list!") + return f +} + +func setUpDSFlagSetWithDefault(dsp *[]time.Duration) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.DurationSliceVar(dsp, "ds", []time.Duration{0, 1}, "Command separated list!") + return f +} + +func TestEmptyDS(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSet(&ds) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + if len(getDS) != 0 { + t.Fatalf("got ds %v with len=%d but expected length=0", getDS, len(getDS)) + } +} + +func TestDS(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSet(&ds) + + vals := []string{"1ns", "2ms", "3m", "4h"} + arg := fmt.Sprintf("--ds=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %s but got: %d", i, vals[i], v) + } + } + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatalf("got error: %v", err) + } + for i, v := range getDS { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %s but got: %d from GetDurationSlice", i, vals[i], v) + } + } +} + +func TestDSDefault(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSetWithDefault(&ds) + + vals := []string{"0s", "1ns"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d but got: %d", i, d, v) + } + } + + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + for i, v := range getDS { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d from GetDurationSlice but got: %d", i, d, v) + } + } +} + +func TestDSWithDefault(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSetWithDefault(&ds) + + vals := []string{"1ns", "2ns"} + arg := fmt.Sprintf("--ds=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d but got: %d", i, d, v) + } + } + + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + for i, v := range getDS { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d from GetDurationSlice but got: %d", i, d, v) + } + } +} + +func TestDSCalledTwice(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSet(&ds) + + in := []string{"1ns,2ns", "3ns"} + expected := []time.Duration{1, 2, 3} + argfmt := "--ds=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + if expected[i] != v { + t.Fatalf("expected ds[%d] to be %d but got: %d", i, expected[i], v) + } + } +} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go index 6f1fc300..5cc710cc 100644 --- a/vendor/github.com/spf13/pflag/flag.go +++ b/vendor/github.com/spf13/pflag/flag.go @@ -101,6 +101,7 @@ package pflag import ( "bytes" "errors" + goflag "flag" "fmt" "io" "os" @@ -123,6 +124,12 @@ const ( PanicOnError ) +// ParseErrorsWhitelist defines the parsing errors that can be ignored +type ParseErrorsWhitelist struct { + // UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags + UnknownFlags bool +} + // NormalizedName is a flag name that has been normalized according to rules // for the FlagSet (e.g. making '-' and '_' equivalent). type NormalizedName string @@ -138,6 +145,9 @@ type FlagSet struct { // help/usage messages. SortFlags bool + // ParseErrorsWhitelist is used to configure a whitelist of errors + ParseErrorsWhitelist ParseErrorsWhitelist + name string parsed bool actual map[NormalizedName]*Flag @@ -153,6 +163,8 @@ type FlagSet struct { output io.Writer // nil means stderr; use out() accessor interspersed bool // allow interspersed option/non-option args normalizeNameFunc func(f *FlagSet, name string) NormalizedName + + addedGoFlagSets []*goflag.FlagSet } // A Flag represents the state of a flag. @@ -202,12 +214,18 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag { func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { f.normalizeNameFunc = n f.sortedFormal = f.sortedFormal[:0] - for k, v := range f.orderedFormal { - delete(f.formal, NormalizedName(v.Name)) - nname := f.normalizeFlagName(v.Name) - v.Name = string(nname) - f.formal[nname] = v - f.orderedFormal[k] = v + for fname, flag := range f.formal { + nname := f.normalizeFlagName(flag.Name) + if fname == nname { + continue + } + flag.Name = string(nname) + delete(f.formal, fname) + f.formal[nname] = flag + if _, set := f.actual[fname]; set { + delete(f.actual, fname) + f.actual[nname] = flag + } } } @@ -261,16 +279,16 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) { } } -// HasFlags returns a bool to indicate if the FlagSet has any flags definied. +// HasFlags returns a bool to indicate if the FlagSet has any flags defined. func (f *FlagSet) HasFlags() bool { return len(f.formal) > 0 } // HasAvailableFlags returns a bool to indicate if the FlagSet has any flags -// definied that are not hidden or deprecated. +// that are not hidden. func (f *FlagSet) HasAvailableFlags() bool { for _, flag := range f.formal { - if !flag.Hidden && len(flag.Deprecated) == 0 { + if !flag.Hidden { return true } } @@ -380,6 +398,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { return fmt.Errorf("deprecated message for flag %q must be set", name) } flag.Deprecated = usageMessage + flag.Hidden = true return nil } @@ -440,13 +459,15 @@ func (f *FlagSet) Set(name, value string) error { return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) } - if f.actual == nil { - f.actual = make(map[NormalizedName]*Flag) - } - f.actual[normalName] = flag - f.orderedActual = append(f.orderedActual, flag) + if !flag.Changed { + if f.actual == nil { + f.actual = make(map[NormalizedName]*Flag) + } + f.actual[normalName] = flag + f.orderedActual = append(f.orderedActual, flag) - flag.Changed = true + flag.Changed = true + } if flag.Deprecated != "" { fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) @@ -556,6 +577,14 @@ func UnquoteUsage(flag *Flag) (name string, usage string) { name = "int" case "uint64": name = "uint" + case "stringSlice": + name = "strings" + case "intSlice": + name = "ints" + case "uintSlice": + name = "uints" + case "boolSlice": + name = "bools" } return @@ -570,11 +599,14 @@ func wrapN(i, slop int, s string) (string, string) { return s, "" } - w := strings.LastIndexAny(s[:i], " \t") + w := strings.LastIndexAny(s[:i], " \t\n") if w <= 0 { return s, "" } - + nlPos := strings.LastIndex(s[:i], "\n") + if nlPos > 0 && nlPos < w { + return s[:nlPos], s[nlPos+1:] + } return s[:w], s[w+1:] } @@ -583,7 +615,7 @@ func wrapN(i, slop int, s string) (string, string) { // caller). Pass `w` == 0 to do no wrapping func wrap(i, w int, s string) string { if w == 0 { - return s + return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1) } // space between indent i and end of line width w into which @@ -601,7 +633,7 @@ func wrap(i, w int, s string) string { } // If still not enough space then don't even try to wrap. if wrap < 24 { - return s + return strings.Replace(s, "\n", r, -1) } // Try to avoid short orphan words on the final line, by @@ -613,14 +645,14 @@ func wrap(i, w int, s string) string { // Handle first line, which is indented by the caller (or the // special case above) l, s = wrapN(wrap, slop, s) - r = r + l + r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1) // Now wrap the rest for s != "" { var t string t, s = wrapN(wrap, slop, s) - r = r + "\n" + strings.Repeat(" ", i) + t + r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1) } return r @@ -637,7 +669,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { maxlen := 0 f.VisitAll(func(flag *Flag) { - if flag.Deprecated != "" || flag.Hidden { + if flag.Hidden { return } @@ -660,6 +692,10 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { if flag.NoOptDefVal != "true" { line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } + case "count": + if flag.NoOptDefVal != "+1" { + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } default: line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } @@ -680,6 +716,9 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { line += fmt.Sprintf(" (default %s)", flag.DefValue) } } + if len(flag.Deprecated) != 0 { + line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated) + } lines = append(lines, line) }) @@ -857,8 +896,10 @@ func VarP(value Value, name, shorthand, usage string) { // returns the error. func (f *FlagSet) failf(format string, a ...interface{}) error { err := fmt.Errorf(format, a...) - fmt.Fprintln(f.out(), err) - f.usage() + if f.errorHandling != ContinueOnError { + fmt.Fprintln(f.out(), err) + f.usage() + } return err } @@ -874,6 +915,25 @@ func (f *FlagSet) usage() { } } +//--unknown (args will be empty) +//--unknown --next-flag ... (args will be --next-flag ...) +//--unknown arg ... (args will be arg ...) +func stripUnknownFlagValue(args []string) []string { + if len(args) == 0 { + //--unknown + return args + } + + first := args[0] + if first[0] == '-' { + //--unknown --next-flag ... + return args + } + + //--unknown arg ... (args will be arg ...) + return args[1:] +} + func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { a = args name := s[2:] @@ -885,13 +945,24 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin split := strings.SplitN(name, "=", 2) name = split[0] flag, exists := f.formal[f.normalizeFlagName(name)] + if !exists { - if name == "help" { // special case for nice help message. + switch { + case name == "help": f.usage() return a, ErrHelp + case f.ParseErrorsWhitelist.UnknownFlags: + // --unknown=unknownval arg ... + // we do not want to lose arg in this case + if len(split) >= 2 { + return a, nil + } + + return stripUnknownFlagValue(a), nil + default: + err = f.failf("unknown flag: --%s", name) + return } - err = f.failf("unknown flag: --%s", name) - return } var value string @@ -912,27 +983,43 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin } err = fn(flag, value) + if err != nil { + f.failf(err.Error()) + } return } func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { + outArgs = args + if strings.HasPrefix(shorthands, "test.") { return } - outArgs = args outShorts = shorthands[1:] c := shorthands[0] flag, exists := f.shorthands[c] if !exists { - if c == 'h' { // special case for nice help message. + switch { + case c == 'h': f.usage() err = ErrHelp return + case f.ParseErrorsWhitelist.UnknownFlags: + // '-f=arg arg ...' + // we do not want to lose arg in this case + if len(shorthands) > 2 && shorthands[1] == '=' { + outShorts = "" + return + } + + outArgs = stripUnknownFlagValue(outArgs) + return + default: + err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) + return } - err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) - return } var value string @@ -962,6 +1049,9 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse } err = fn(flag, value) + if err != nil { + f.failf(err.Error()) + } return } @@ -1016,6 +1106,11 @@ func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) { // are defined and before flags are accessed by the program. // The return value will be ErrHelp if -help was set but not defined. func (f *FlagSet) Parse(arguments []string) error { + if f.addedGoFlagSets != nil { + for _, goFlagSet := range f.addedGoFlagSets { + goFlagSet.Parse(nil) + } + } f.parsed = true if len(arguments) < 0 { @@ -1034,6 +1129,7 @@ func (f *FlagSet) Parse(arguments []string) error { case ContinueOnError: return err case ExitOnError: + fmt.Println(err) os.Exit(2) case PanicOnError: panic(err) diff --git a/vendor/github.com/spf13/pflag/flag_test.go b/vendor/github.com/spf13/pflag/flag_test.go index c3def0fd..f600f0ae 100644 --- a/vendor/github.com/spf13/pflag/flag_test.go +++ b/vendor/github.com/spf13/pflag/flag_test.go @@ -106,8 +106,8 @@ func TestUsage(t *testing.T) { if GetCommandLine().Parse([]string{"--x"}) == nil { t.Error("parse did not fail for unknown flag") } - if !called { - t.Error("did not call Usage for unknown flag") + if called { + t.Error("did call Usage while using ContinueOnError") } } @@ -168,6 +168,7 @@ func testParse(f *FlagSet, t *testing.T) { bool3Flag := f.Bool("bool3", false, "bool3 value") intFlag := f.Int("int", 0, "int value") int8Flag := f.Int8("int8", 0, "int value") + int16Flag := f.Int16("int16", 0, "int value") int32Flag := f.Int32("int32", 0, "int value") int64Flag := f.Int64("int64", 0, "int64 value") uintFlag := f.Uint("uint", 0, "uint value") @@ -192,6 +193,7 @@ func testParse(f *FlagSet, t *testing.T) { "--bool3=false", "--int=22", "--int8=-8", + "--int16=-16", "--int32=-32", "--int64=0x23", "--uint", "24", @@ -236,9 +238,15 @@ func testParse(f *FlagSet, t *testing.T) { if *int8Flag != -8 { t.Error("int8 flag should be 0x23, is ", *int8Flag) } + if *int16Flag != -16 { + t.Error("int16 flag should be -16, is ", *int16Flag) + } if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag { t.Error("GetInt8 does not work.") } + if v, err := f.GetInt16("int16"); err != nil || v != *int16Flag { + t.Error("GetInt16 does not work.") + } if *int32Flag != -32 { t.Error("int32 flag should be 0x23, is ", *int32Flag) } @@ -381,7 +389,78 @@ func testParseAll(f *FlagSet, t *testing.T) { } if !reflect.DeepEqual(got, want) { t.Errorf("f.ParseAll() fail to restore the args") - t.Errorf("Got: %v", got) + t.Errorf("Got: %v", got) + t.Errorf("Want: %v", want) + } +} + +func testParseWithUnknownFlags(f *FlagSet, t *testing.T) { + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + f.ParseErrorsWhitelist.UnknownFlags = true + + f.BoolP("boola", "a", false, "bool value") + f.BoolP("boolb", "b", false, "bool2 value") + f.BoolP("boolc", "c", false, "bool3 value") + f.BoolP("boold", "d", false, "bool4 value") + f.BoolP("boole", "e", false, "bool4 value") + f.StringP("stringa", "s", "0", "string value") + f.StringP("stringz", "z", "0", "string value") + f.StringP("stringx", "x", "0", "string value") + f.StringP("stringy", "y", "0", "string value") + f.StringP("stringo", "o", "0", "string value") + f.Lookup("stringx").NoOptDefVal = "1" + args := []string{ + "-ab", + "-cs=xx", + "--stringz=something", + "--unknown1", + "unknown1Value", + "-d=true", + "-x", + "--unknown2=unknown2Value", + "-u=unknown3Value", + "-p", + "unknown4Value", + "-q", //another unknown with bool value + "-y", + "ee", + "--unknown7=unknown7value", + "--stringo=ovalue", + "--unknown8=unknown8value", + "--boole", + "--unknown6", + } + want := []string{ + "boola", "true", + "boolb", "true", + "boolc", "true", + "stringa", "xx", + "stringz", "something", + "boold", "true", + "stringx", "1", + "stringy", "ee", + "stringo", "ovalue", + "boole", "true", + } + got := []string{} + store := func(flag *Flag, value string) error { + got = append(got, flag.Name) + if len(value) > 0 { + got = append(got, value) + } + return nil + } + if err := f.ParseAll(args, store); err != nil { + t.Errorf("expected no error, got %s", err) + } + if !f.Parsed() { + t.Errorf("f.Parse() = false after Parse") + } + if !reflect.DeepEqual(got, want) { + t.Errorf("f.ParseAll() fail to restore the args") + t.Errorf("Got: %v", got) t.Errorf("Want: %v", want) } } @@ -492,6 +571,11 @@ func TestParseAll(t *testing.T) { testParseAll(GetCommandLine(), t) } +func TestIgnoreUnknownFlags(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + testParseWithUnknownFlags(GetCommandLine(), t) +} + func TestFlagSetParse(t *testing.T) { testParse(NewFlagSet("test", ContinueOnError), t) } @@ -604,7 +688,6 @@ func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName { switch name { case oldName: name = newName - break } return NormalizedName(name) @@ -658,6 +741,70 @@ func TestNormalizationFuncShouldChangeFlagName(t *testing.T) { } } +// Related to https://github.com/spf13/cobra/issues/521. +func TestNormalizationSharedFlags(t *testing.T) { + f := NewFlagSet("set f", ContinueOnError) + g := NewFlagSet("set g", ContinueOnError) + nfunc := wordSepNormalizeFunc + testName := "valid_flag" + normName := nfunc(nil, testName) + if testName == string(normName) { + t.Error("TestNormalizationSharedFlags meaningless: the original and normalized flag names are identical:", testName) + } + + f.Bool(testName, false, "bool value") + g.AddFlagSet(f) + + f.SetNormalizeFunc(nfunc) + g.SetNormalizeFunc(nfunc) + + if len(f.formal) != 1 { + t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal) + } + if f.orderedFormal[0].Name != string(normName) { + t.Error("Flag name not normalized") + } + for k := range f.formal { + if k != "valid.flag" { + t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k) + } + } + + if !reflect.DeepEqual(f.formal, g.formal) || !reflect.DeepEqual(f.orderedFormal, g.orderedFormal) { + t.Error("Two flag sets sharing the same flags should stay consistent after being normalized. Original set:", f.formal, "Duplicate set:", g.formal) + } +} + +func TestNormalizationSetFlags(t *testing.T) { + f := NewFlagSet("normalized", ContinueOnError) + nfunc := wordSepNormalizeFunc + testName := "valid_flag" + normName := nfunc(nil, testName) + if testName == string(normName) { + t.Error("TestNormalizationSetFlags meaningless: the original and normalized flag names are identical:", testName) + } + + f.Bool(testName, false, "bool value") + f.Set(testName, "true") + f.SetNormalizeFunc(nfunc) + + if len(f.formal) != 1 { + t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal) + } + if f.orderedFormal[0].Name != string(normName) { + t.Error("Flag name not normalized") + } + for k := range f.formal { + if k != "valid.flag" { + t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k) + } + } + + if !reflect.DeepEqual(f.formal, f.actual) { + t.Error("The map of set flags should get normalized. Formal:", f.formal, "Actual:", f.actual) + } +} + // Declare a user-defined flag type. type flagVar []string @@ -819,10 +966,14 @@ func TestTermination(t *testing.T) { } } -func TestDeprecatedFlagInDocs(t *testing.T) { +func getDeprecatedFlagSet() *FlagSet { f := NewFlagSet("bob", ContinueOnError) f.Bool("badflag", true, "always true") f.MarkDeprecated("badflag", "use --good-flag instead") + return f +} +func TestDeprecatedFlagInDocs(t *testing.T) { + f := getDeprecatedFlagSet() out := new(bytes.Buffer) f.SetOutput(out) @@ -833,6 +984,27 @@ func TestDeprecatedFlagInDocs(t *testing.T) { } } +func TestUnHiddenDeprecatedFlagInDocs(t *testing.T) { + f := getDeprecatedFlagSet() + flg := f.Lookup("badflag") + if flg == nil { + t.Fatalf("Unable to lookup 'bob' in TestUnHiddenDeprecatedFlagInDocs") + } + flg.Hidden = false + + out := new(bytes.Buffer) + f.SetOutput(out) + f.PrintDefaults() + + defaults := out.String() + if !strings.Contains(defaults, "badflag") { + t.Errorf("Did not find deprecated flag in usage!") + } + if !strings.Contains(defaults, "use --good-flag instead") { + t.Errorf("Did not find 'use --good-flag instead' in defaults") + } +} + func TestDeprecatedFlagShorthandInDocs(t *testing.T) { f := NewFlagSet("bob", ContinueOnError) name := "noshorthandflag" @@ -978,16 +1150,17 @@ const defaultOutput = ` --A for bootstrapping, allo --IP ip IP address with no default --IPMask ipMask Netmask address with no default --IPNet ipNet IP network with no default - --Ints intSlice int slice with zero default + --Ints ints int slice with zero default --N int a non-zero int (default 27) --ND1 string[="bar"] a string with NoOptDefVal (default "foo") --ND2 num[=4321] a num with NoOptDefVal (default 1234) --StringArray stringArray string array with zero default - --StringSlice stringSlice string slice with zero default + --StringSlice strings string slice with zero default --Z int an int that defaults to zero --custom custom custom Value implementation --customP custom a VarP with default (default 10) --maxT timeout set timeout for dial + -v, --verbose count verbosity ` // Custom value that satisfies the Value interface. @@ -1028,6 +1201,7 @@ func TestPrintDefaults(t *testing.T) { fs.ShorthandLookup("E").NoOptDefVal = "1234" fs.StringSlice("StringSlice", []string{}, "string slice with zero default") fs.StringArray("StringArray", []string{}, "string array with zero default") + fs.CountP("verbose", "v", "verbosity") var cv customValue fs.Var(&cv, "custom", "custom Value implementation") diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go index c4f47ebe..d3dd72b7 100644 --- a/vendor/github.com/spf13/pflag/golangflag.go +++ b/vendor/github.com/spf13/pflag/golangflag.go @@ -98,4 +98,8 @@ func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { newSet.VisitAll(func(goflag *goflag.Flag) { f.AddGoFlag(goflag) }) + if f.addedGoFlagSets == nil { + f.addedGoFlagSets = make([]*goflag.FlagSet, 0) + } + f.addedGoFlagSets = append(f.addedGoFlagSets, newSet) } diff --git a/vendor/github.com/spf13/pflag/golangflag_test.go b/vendor/github.com/spf13/pflag/golangflag_test.go index 77e2d7d8..5bd831bf 100644 --- a/vendor/github.com/spf13/pflag/golangflag_test.go +++ b/vendor/github.com/spf13/pflag/golangflag_test.go @@ -36,4 +36,12 @@ func TestGoflags(t *testing.T) { if getBool != true { t.Fatalf("expected getBool=true but got getBool=%v", getBool) } + if !f.Parsed() { + t.Fatal("f.Parsed() return false after f.Parse() called") + } + + // in fact it is useless. because `go test` called flag.Parse() + if !goflag.CommandLine.Parsed() { + t.Fatal("goflag.CommandLine.Parsed() return false after f.Parse() called") + } } diff --git a/vendor/github.com/spf13/pflag/int16.go b/vendor/github.com/spf13/pflag/int16.go new file mode 100644 index 00000000..f1a01d05 --- /dev/null +++ b/vendor/github.com/spf13/pflag/int16.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- int16 Value +type int16Value int16 + +func newInt16Value(val int16, p *int16) *int16Value { + *p = val + return (*int16Value)(p) +} + +func (i *int16Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 16) + *i = int16Value(v) + return err +} + +func (i *int16Value) Type() string { + return "int16" +} + +func (i *int16Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int16Conv(sval string) (interface{}, error) { + v, err := strconv.ParseInt(sval, 0, 16) + if err != nil { + return 0, err + } + return int16(v), nil +} + +// GetInt16 returns the int16 value of a flag with the given name +func (f *FlagSet) GetInt16(name string) (int16, error) { + val, err := f.getFlagType(name, "int16", int16Conv) + if err != nil { + return 0, err + } + return val.(int16), nil +} + +// Int16Var defines an int16 flag with specified name, default value, and usage string. +// The argument p points to an int16 variable in which to store the value of the flag. +func (f *FlagSet) Int16Var(p *int16, name string, value int16, usage string) { + f.VarP(newInt16Value(value, p), name, "", usage) +} + +// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int16VarP(p *int16, name, shorthand string, value int16, usage string) { + f.VarP(newInt16Value(value, p), name, shorthand, usage) +} + +// Int16Var defines an int16 flag with specified name, default value, and usage string. +// The argument p points to an int16 variable in which to store the value of the flag. +func Int16Var(p *int16, name string, value int16, usage string) { + CommandLine.VarP(newInt16Value(value, p), name, "", usage) +} + +// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash. +func Int16VarP(p *int16, name, shorthand string, value int16, usage string) { + CommandLine.VarP(newInt16Value(value, p), name, shorthand, usage) +} + +// Int16 defines an int16 flag with specified name, default value, and usage string. +// The return value is the address of an int16 variable that stores the value of the flag. +func (f *FlagSet) Int16(name string, value int16, usage string) *int16 { + p := new(int16) + f.Int16VarP(p, name, "", value, usage) + return p +} + +// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int16P(name, shorthand string, value int16, usage string) *int16 { + p := new(int16) + f.Int16VarP(p, name, shorthand, value, usage) + return p +} + +// Int16 defines an int16 flag with specified name, default value, and usage string. +// The return value is the address of an int16 variable that stores the value of the flag. +func Int16(name string, value int16, usage string) *int16 { + return CommandLine.Int16P(name, "", value, usage) +} + +// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash. +func Int16P(name, shorthand string, value int16, usage string) *int16 { + return CommandLine.Int16P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/printusage_test.go b/vendor/github.com/spf13/pflag/printusage_test.go new file mode 100644 index 00000000..df982aab --- /dev/null +++ b/vendor/github.com/spf13/pflag/printusage_test.go @@ -0,0 +1,74 @@ +package pflag + +import ( + "bytes" + "io" + "testing" +) + +const expectedOutput = ` --long-form Some description + --long-form2 Some description + with multiline + -s, --long-name Some description + -t, --long-name2 Some description with + multiline +` + +func setUpPFlagSet(buf io.Writer) *FlagSet { + f := NewFlagSet("test", ExitOnError) + f.Bool("long-form", false, "Some description") + f.Bool("long-form2", false, "Some description\n with multiline") + f.BoolP("long-name", "s", false, "Some description") + f.BoolP("long-name2", "t", false, "Some description with\n multiline") + f.SetOutput(buf) + return f +} + +func TestPrintUsage(t *testing.T) { + buf := bytes.Buffer{} + f := setUpPFlagSet(&buf) + f.PrintDefaults() + res := buf.String() + if res != expectedOutput { + t.Errorf("Expected \n%s \nActual \n%s", expectedOutput, res) + } +} + +func setUpPFlagSet2(buf io.Writer) *FlagSet { + f := NewFlagSet("test", ExitOnError) + f.Bool("long-form", false, "Some description") + f.Bool("long-form2", false, "Some description\n with multiline") + f.BoolP("long-name", "s", false, "Some description") + f.BoolP("long-name2", "t", false, "Some description with\n multiline") + f.StringP("some-very-long-arg", "l", "test", "Some very long description having break the limit") + f.StringP("other-very-long-arg", "o", "long-default-value", "Some very long description having break the limit") + f.String("some-very-long-arg2", "very long default value", "Some very long description\nwith line break\nmultiple") + f.SetOutput(buf) + return f +} + +const expectedOutput2 = ` --long-form Some description + --long-form2 Some description + with multiline + -s, --long-name Some description + -t, --long-name2 Some description with + multiline + -o, --other-very-long-arg string Some very long description having + break the limit (default + "long-default-value") + -l, --some-very-long-arg string Some very long description having + break the limit (default "test") + --some-very-long-arg2 string Some very long description + with line break + multiple (default "very long default + value") +` + +func TestPrintUsage_2(t *testing.T) { + buf := bytes.Buffer{} + f := setUpPFlagSet2(&buf) + res := f.FlagUsagesWrapped(80) + if res != expectedOutput2 { + t.Errorf("Expected \n%q \nActual \n%q", expectedOutput2, res) + } +} diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go index 276b7ed4..fa7bc601 100644 --- a/vendor/github.com/spf13/pflag/string_array.go +++ b/vendor/github.com/spf13/pflag/string_array.go @@ -52,7 +52,7 @@ func (f *FlagSet) GetStringArray(name string) ([]string, error) { // StringArrayVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the values of the multiple flags. -// The value of each argument will not try to be separated by comma +// The value of each argument will not try to be separated by comma. Use a StringSlice for that. func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { f.VarP(newStringArrayValue(value, p), name, "", usage) } @@ -64,7 +64,7 @@ func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []s // StringArrayVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the value of the flag. -// The value of each argument will not try to be separated by comma +// The value of each argument will not try to be separated by comma. Use a StringSlice for that. func StringArrayVar(p *[]string, name string, value []string, usage string) { CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) } @@ -76,7 +76,7 @@ func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage // StringArray defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma +// The value of each argument will not try to be separated by comma. Use a StringSlice for that. func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { p := []string{} f.StringArrayVarP(&p, name, "", value, usage) @@ -92,7 +92,7 @@ func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage str // StringArray defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma +// The value of each argument will not try to be separated by comma. Use a StringSlice for that. func StringArray(name string, value []string, usage string) *[]string { return CommandLine.StringArrayP(name, "", value, usage) } diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go index 05eee754..0cd3ccc0 100644 --- a/vendor/github.com/spf13/pflag/string_slice.go +++ b/vendor/github.com/spf13/pflag/string_slice.go @@ -82,6 +82,11 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) { // StringSliceVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the value of the flag. +// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. +// For example: +// --ss="v1,v2" -ss="v3" +// will result in +// []string{"v1", "v2", "v3"} func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { f.VarP(newStringSliceValue(value, p), name, "", usage) } @@ -93,6 +98,11 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s // StringSliceVar defines a string flag with specified name, default value, and usage string. // The argument p points to a []string variable in which to store the value of the flag. +// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. +// For example: +// --ss="v1,v2" -ss="v3" +// will result in +// []string{"v1", "v2", "v3"} func StringSliceVar(p *[]string, name string, value []string, usage string) { CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) } @@ -104,6 +114,11 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage // StringSlice defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. +// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. +// For example: +// --ss="v1,v2" -ss="v3" +// will result in +// []string{"v1", "v2", "v3"} func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { p := []string{} f.StringSliceVarP(&p, name, "", value, usage) @@ -119,6 +134,11 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str // StringSlice defines a string flag with specified name, default value, and usage string. // The return value is the address of a []string variable that stores the value of the flag. +// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. +// For example: +// --ss="v1,v2" -ss="v3" +// will result in +// []string{"v1", "v2", "v3"} func StringSlice(name string, value []string, usage string) *[]string { return CommandLine.StringSliceP(name, "", value, usage) } diff --git a/vendor/github.com/spf13/viper/.travis.yml b/vendor/github.com/spf13/viper/.travis.yml index f1deac3d..22a8a00e 100644 --- a/vendor/github.com/spf13/viper/.travis.yml +++ b/vendor/github.com/spf13/viper/.travis.yml @@ -2,8 +2,8 @@ go_import_path: github.com/spf13/viper language: go go: - - 1.7.5 - - 1.8 + - 1.10.x + - 1.11.x - tip os: diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md index 848d92d6..87bbc8b4 100644 --- a/vendor/github.com/spf13/viper/README.md +++ b/vendor/github.com/spf13/viper/README.md @@ -185,13 +185,13 @@ with ENV: * `AutomaticEnv()` * `BindEnv(string...) : error` * `SetEnvPrefix(string)` - * `SetEnvReplacer(string...) *strings.Replacer` + * `SetEnvKeyReplacer(string...) *strings.Replacer` _When working with ENV variables, it’s important to recognize that Viper treats ENV variables as case sensitive._ Viper provides a mechanism to try to ensure that ENV variables are unique. By -using `SetEnvPrefix`, you can tell Viper to use add a prefix while reading from +using `SetEnvPrefix`, you can tell Viper to use a prefix while reading from the environment variables. Both `BindEnv` and `AutomaticEnv` will use this prefix. @@ -212,7 +212,7 @@ time a `viper.Get` request is made. It will apply the following rules. It will check for a environment variable with a name matching the key uppercased and prefixed with the `EnvPrefix` if set. -`SetEnvReplacer` allows you to use a `strings.Replacer` object to rewrite Env +`SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env keys to an extent. This is useful if you want to use `-` or something in your `Get()` calls, but want your environmental variables to use `_` delimiters. An example of using it can be found in `viper_test.go`. @@ -373,12 +373,33 @@ how to use Consul. ### Remote Key/Value Store Example - Unencrypted +#### etcd ```go viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json") viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop" err := viper.ReadRemoteConfig() ``` +#### Consul +You need to set a key to Consul key/value storage with JSON value containing your desired config. +For example, create a Consul key/value store key `MY_CONSUL_KEY` with value: + +```json +{ + "port": 8080, + "hostname": "myhostname.com" +} +``` + +```go +viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY") +viper.SetConfigType("json") // Need to explicitly set this to json +err := viper.ReadRemoteConfig() + +fmt.Println(viper.Get("port")) // 8080 +fmt.Println(viper.Get("hostname")) // myhostname.com +``` + ### Remote Key/Value Store Example - Encrypted ```go @@ -437,6 +458,7 @@ The following functions and methods exist: * `GetTime(key string) : time.Time` * `GetDuration(key string) : time.Duration` * `IsSet(key string) : bool` + * `AllSettings() : map[string]interface{}` One important thing to recognize is that each Get function will return a zero value if it’s not found. To check if a given key exists, the `IsSet()` method @@ -590,6 +612,27 @@ if err != nil { } ``` +### Marshalling to string + +You may need to marhsal all the settings held in viper into a string rather than write them to a file. +You can use your favorite format's marshaller with the config returned by `AllSettings()`. + +```go +import ( + yaml "gopkg.in/yaml.v2" + // ... +) + +func yamlStringSettings() string { + c := viper.AllSettings() + bs, err := yaml.Marshal(c) + if err != nil { + t.Fatalf("unable to marshal config to YAML: %v", err) + } + return string(bs) +} +``` + ## Viper or Vipers? Viper comes ready to use out of the box. There is no configuration or diff --git a/vendor/github.com/spf13/viper/go.mod b/vendor/github.com/spf13/viper/go.mod new file mode 100644 index 00000000..3f4e1c22 --- /dev/null +++ b/vendor/github.com/spf13/viper/go.mod @@ -0,0 +1,16 @@ +module github.com/spf13/viper + +require ( + github.com/fsnotify/fsnotify v1.4.7 + github.com/hashicorp/hcl v1.0.0 + github.com/magiconair/properties v1.8.0 + github.com/mitchellh/mapstructure v1.0.0 + github.com/pelletier/go-toml v1.2.0 + github.com/spf13/afero v1.1.2 + github.com/spf13/cast v1.2.0 + github.com/spf13/jwalterweatherman v1.0.0 + github.com/spf13/pflag v1.0.2 + golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 // indirect + golang.org/x/text v0.3.0 // indirect + gopkg.in/yaml.v2 v2.2.1 +) diff --git a/vendor/github.com/spf13/viper/go.sum b/vendor/github.com/spf13/viper/go.sum new file mode 100644 index 00000000..3e3b874b --- /dev/null +++ b/vendor/github.com/spf13/viper/go.sum @@ -0,0 +1,26 @@ +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I= +github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= +github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBmaiBH81O8BugSjHeTFg= +golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/spf13/viper/nohup.out b/vendor/github.com/spf13/viper/nohup.out deleted file mode 100644 index 8973bf27..00000000 --- a/vendor/github.com/spf13/viper/nohup.out +++ /dev/null @@ -1 +0,0 @@ -QProcess::start: Process is already running diff --git a/vendor/github.com/spf13/viper/remote/remote.go b/vendor/github.com/spf13/viper/remote/remote.go index 68a35d69..810d0702 100644 --- a/vendor/github.com/spf13/viper/remote/remote.go +++ b/vendor/github.com/spf13/viper/remote/remote.go @@ -8,10 +8,11 @@ package remote import ( "bytes" - "github.com/spf13/viper" - crypt "github.com/xordataexchange/crypt/config" "io" "os" + + "github.com/spf13/viper" + crypt "github.com/xordataexchange/crypt/config" ) type remoteConfigProvider struct{} diff --git a/vendor/github.com/spf13/viper/util.go b/vendor/github.com/spf13/viper/util.go index 3ebada91..952cad44 100644 --- a/vendor/github.com/spf13/viper/util.go +++ b/vendor/github.com/spf13/viper/util.go @@ -11,22 +11,16 @@ package viper import ( - "bytes" - "encoding/json" "fmt" - "io" "os" "path/filepath" "runtime" "strings" "unicode" - "github.com/hashicorp/hcl" - "github.com/magiconair/properties" - toml "github.com/pelletier/go-toml" + "github.com/spf13/afero" "github.com/spf13/cast" jww "github.com/spf13/jwalterweatherman" - "gopkg.in/yaml.v2" ) // ConfigParseError denotes failing to parse configuration file. @@ -121,8 +115,8 @@ func absPathify(inPath string) string { } // Check if File / Directory Exists -func exists(path string) (bool, error) { - _, err := v.fs.Stat(path) +func exists(fs afero.Fs, path string) (bool, error) { + _, err := fs.Stat(path) if err == nil { return true, nil } @@ -152,61 +146,6 @@ func userHomeDir() string { return os.Getenv("HOME") } -func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType string) error { - buf := new(bytes.Buffer) - buf.ReadFrom(in) - - switch strings.ToLower(configType) { - case "yaml", "yml": - if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil { - return ConfigParseError{err} - } - - case "json": - if err := json.Unmarshal(buf.Bytes(), &c); err != nil { - return ConfigParseError{err} - } - - case "hcl": - obj, err := hcl.Parse(string(buf.Bytes())) - if err != nil { - return ConfigParseError{err} - } - if err = hcl.DecodeObject(&c, obj); err != nil { - return ConfigParseError{err} - } - - case "toml": - tree, err := toml.LoadReader(buf) - if err != nil { - return ConfigParseError{err} - } - tmap := tree.ToMap() - for k, v := range tmap { - c[k] = v - } - - case "properties", "props", "prop": - var p *properties.Properties - var err error - if p, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil { - return ConfigParseError{err} - } - for _, key := range p.Keys() { - value, _ := p.Get(key) - // recursively build nested maps - path := strings.Split(key, ".") - lastKey := strings.ToLower(path[len(path)-1]) - deepestMap := deepSearch(c, path[0:len(path)-1]) - // set innermost value - deepestMap[lastKey] = value - } - } - - insensitiviseMap(c) - return nil -} - func safeMul(a, b uint) uint { c := a * b if a > 1 && b > 1 && c/b != a { diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go index 2a221e53..051a3eff 100644 --- a/vendor/github.com/spf13/viper/viper.go +++ b/vendor/github.com/spf13/viper/viper.go @@ -22,6 +22,7 @@ package viper import ( "bytes" "encoding/csv" + "encoding/json" "fmt" "io" "log" @@ -31,14 +32,30 @@ import ( "strings" "time" + yaml "gopkg.in/yaml.v2" + "github.com/fsnotify/fsnotify" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/printer" + "github.com/magiconair/properties" "github.com/mitchellh/mapstructure" + toml "github.com/pelletier/go-toml" "github.com/spf13/afero" "github.com/spf13/cast" jww "github.com/spf13/jwalterweatherman" "github.com/spf13/pflag" ) +// ConfigMarshalError happens when failing to marshal the configuration. +type ConfigMarshalError struct { + err error +} + +// Error returns the formatted configuration error. +func (e ConfigMarshalError) Error() string { + return fmt.Sprintf("While marshaling config: %s", e.err.Error()) +} + var v *Viper type RemoteResponse struct { @@ -96,6 +113,23 @@ func (fnfe ConfigFileNotFoundError) Error() string { return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) } +// A DecoderConfigOption can be passed to viper.Unmarshal to configure +// mapstructure.DecoderConfig options +type DecoderConfigOption func(*mapstructure.DecoderConfig) + +// DecodeHook returns a DecoderConfigOption which overrides the default +// DecoderConfig.DecodeHook value, the default is: +// +// mapstructure.ComposeDecodeHookFunc( +// mapstructure.StringToTimeDurationHookFunc(), +// mapstructure.StringToSliceHookFunc(","), +// ) +func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption { + return func(c *mapstructure.DecoderConfig) { + c.DecodeHook = hook + } +} + // Viper is a prioritized configuration registry. It // maintains a set of configuration sources, fetches // values to populate those, and provides them according @@ -162,6 +196,10 @@ type Viper struct { aliases map[string]string typeByDefValue bool + // Store read properties on the object so that we can write back in order with comments. + // This will only be used if the configuration read is a properties file. + properties *properties.Properties + onConfigChange func(fsnotify.Event) } @@ -188,7 +226,7 @@ func New() *Viper { // can use it in their testing as well. func Reset() { v = New() - SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"} + SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"} SupportedRemoteProviders = []string{"etcd", "consul"} } @@ -610,8 +648,10 @@ func (v *Viper) Get(key string) interface{} { return cast.ToBool(val) case string: return cast.ToString(val) - case int64, int32, int16, int8, int: + case int32, int16, int8, int: return cast.ToInt(val) + case int64: + return cast.ToInt64(val) case float64, float32: return cast.ToFloat64(val) case time.Time: @@ -661,6 +701,12 @@ func (v *Viper) GetInt(key string) int { return cast.ToInt(v.Get(key)) } +// GetInt32 returns the value associated with the key as an integer. +func GetInt32(key string) int32 { return v.GetInt32(key) } +func (v *Viper) GetInt32(key string) int32 { + return cast.ToInt32(v.Get(key)) +} + // GetInt64 returns the value associated with the key as an integer. func GetInt64(key string) int64 { return v.GetInt64(key) } func (v *Viper) GetInt64(key string) int64 { @@ -718,9 +764,11 @@ func (v *Viper) GetSizeInBytes(key string) uint { } // UnmarshalKey takes a single key and unmarshals it into a Struct. -func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) } -func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { - err := decode(v.Get(key), defaultDecoderConfig(rawVal)) +func UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error { + return v.UnmarshalKey(key, rawVal, opts...) +} +func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error { + err := decode(v.Get(key), defaultDecoderConfig(rawVal, opts...)) if err != nil { return err @@ -733,9 +781,11 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { // Unmarshal unmarshals the config into a Struct. Make sure that the tags // on the fields of the structure are properly set. -func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) } -func (v *Viper) Unmarshal(rawVal interface{}) error { - err := decode(v.AllSettings(), defaultDecoderConfig(rawVal)) +func Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error { + return v.Unmarshal(rawVal, opts...) +} +func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error { + err := decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...)) if err != nil { return err @@ -747,14 +797,21 @@ func (v *Viper) Unmarshal(rawVal interface{}) error { } // defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot -// of time.Duration values -func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { - return &mapstructure.DecoderConfig{ +// of time.Duration values & string slices +func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *mapstructure.DecoderConfig { + c := &mapstructure.DecoderConfig{ Metadata: nil, Result: output, WeaklyTypedInput: true, - DecodeHook: mapstructure.StringToTimeDurationHookFunc(), + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + ), } + for _, opt := range opts { + opt(c) + } + return c } // A wrapper around mapstructure.Decode that mimics the WeakDecode functionality @@ -1084,7 +1141,7 @@ func (v *Viper) SetDefault(key string, value interface{}) { deepestMap[lastKey] = value } -// Set sets the value for the key in the override regiser. +// Set sets the value for the key in the override register. // Set is case-insensitive for a key. // Will be used instead of values obtained via // flags, config file, ENV, default, or key/value store. @@ -1116,6 +1173,7 @@ func (v *Viper) ReadInConfig() error { return UnsupportedConfigError(v.getConfigType()) } + jww.DEBUG.Println("Reading file: ", filename) file, err := afero.ReadFile(v.fs, filename) if err != nil { return err @@ -1175,6 +1233,195 @@ func (v *Viper) MergeConfig(in io.Reader) error { return nil } +// WriteConfig writes the current configuration to a file. +func WriteConfig() error { return v.WriteConfig() } +func (v *Viper) WriteConfig() error { + filename, err := v.getConfigFile() + if err != nil { + return err + } + return v.writeConfig(filename, true) +} + +// SafeWriteConfig writes current configuration to file only if the file does not exist. +func SafeWriteConfig() error { return v.SafeWriteConfig() } +func (v *Viper) SafeWriteConfig() error { + filename, err := v.getConfigFile() + if err != nil { + return err + } + return v.writeConfig(filename, false) +} + +// WriteConfigAs writes current configuration to a given filename. +func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) } +func (v *Viper) WriteConfigAs(filename string) error { + return v.writeConfig(filename, true) +} + +// SafeWriteConfigAs writes current configuration to a given filename if it does not exist. +func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) } +func (v *Viper) SafeWriteConfigAs(filename string) error { + return v.writeConfig(filename, false) +} + +func writeConfig(filename string, force bool) error { return v.writeConfig(filename, force) } +func (v *Viper) writeConfig(filename string, force bool) error { + jww.INFO.Println("Attempting to write configuration to file.") + ext := filepath.Ext(filename) + if len(ext) <= 1 { + return fmt.Errorf("Filename: %s requires valid extension.", filename) + } + configType := ext[1:] + if !stringInSlice(configType, SupportedExts) { + return UnsupportedConfigError(configType) + } + if v.config == nil { + v.config = make(map[string]interface{}) + } + var flags int + if force == true { + flags = os.O_CREATE | os.O_TRUNC | os.O_WRONLY + } else { + if _, err := os.Stat(filename); os.IsNotExist(err) { + flags = os.O_WRONLY + } else { + return fmt.Errorf("File: %s exists. Use WriteConfig to overwrite.", filename) + } + } + f, err := v.fs.OpenFile(filename, flags, os.FileMode(0644)) + if err != nil { + return err + } + return v.marshalWriter(f, configType) +} + +// Unmarshal a Reader into a map. +// Should probably be an unexported function. +func unmarshalReader(in io.Reader, c map[string]interface{}) error { + return v.unmarshalReader(in, c) +} +func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { + buf := new(bytes.Buffer) + buf.ReadFrom(in) + + switch strings.ToLower(v.getConfigType()) { + case "yaml", "yml": + if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil { + return ConfigParseError{err} + } + + case "json": + if err := json.Unmarshal(buf.Bytes(), &c); err != nil { + return ConfigParseError{err} + } + + case "hcl": + obj, err := hcl.Parse(string(buf.Bytes())) + if err != nil { + return ConfigParseError{err} + } + if err = hcl.DecodeObject(&c, obj); err != nil { + return ConfigParseError{err} + } + + case "toml": + tree, err := toml.LoadReader(buf) + if err != nil { + return ConfigParseError{err} + } + tmap := tree.ToMap() + for k, v := range tmap { + c[k] = v + } + + case "properties", "props", "prop": + v.properties = properties.NewProperties() + var err error + if v.properties, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil { + return ConfigParseError{err} + } + for _, key := range v.properties.Keys() { + value, _ := v.properties.Get(key) + // recursively build nested maps + path := strings.Split(key, ".") + lastKey := strings.ToLower(path[len(path)-1]) + deepestMap := deepSearch(c, path[0:len(path)-1]) + // set innermost value + deepestMap[lastKey] = value + } + } + + insensitiviseMap(c) + return nil +} + +// Marshal a map into Writer. +func marshalWriter(f afero.File, configType string) error { + return v.marshalWriter(f, configType) +} +func (v *Viper) marshalWriter(f afero.File, configType string) error { + c := v.AllSettings() + switch configType { + case "json": + b, err := json.MarshalIndent(c, "", " ") + if err != nil { + return ConfigMarshalError{err} + } + _, err = f.WriteString(string(b)) + if err != nil { + return ConfigMarshalError{err} + } + + case "hcl": + b, err := json.Marshal(c) + ast, err := hcl.Parse(string(b)) + if err != nil { + return ConfigMarshalError{err} + } + err = printer.Fprint(f, ast.Node) + if err != nil { + return ConfigMarshalError{err} + } + + case "prop", "props", "properties": + if v.properties == nil { + v.properties = properties.NewProperties() + } + p := v.properties + for _, key := range v.AllKeys() { + _, _, err := p.Set(key, v.GetString(key)) + if err != nil { + return ConfigMarshalError{err} + } + } + _, err := p.WriteComment(f, "#", properties.UTF8) + if err != nil { + return ConfigMarshalError{err} + } + + case "toml": + t, err := toml.TreeFromMap(c) + if err != nil { + return ConfigMarshalError{err} + } + s := t.String() + if _, err := f.WriteString(s); err != nil { + return ConfigMarshalError{err} + } + + case "yaml", "yml": + b, err := yaml.Marshal(c) + if err != nil { + return ConfigMarshalError{err} + } + if _, err = f.WriteString(string(b)); err != nil { + return ConfigMarshalError{err} + } + } + return nil +} + func keyExists(k string, m map[string]interface{}) string { lk := strings.ToLower(k) for mk := range m { @@ -1287,16 +1534,6 @@ func (v *Viper) WatchRemoteConfigOnChannel() error { return v.watchKeyValueConfigOnChannel() } -// Unmarshal a Reader into a map. -// Should probably be an unexported function. -func unmarshalReader(in io.Reader, c map[string]interface{}) error { - return v.unmarshalReader(in, c) -} - -func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { - return unmarshallConfigReader(in, c, v.getConfigType()) -} - func (v *Viper) insensitiviseMaps() { insensitiviseMap(v.config) insensitiviseMap(v.defaults) @@ -1516,25 +1753,21 @@ func (v *Viper) getConfigType() string { } func (v *Viper) getConfigFile() (string, error) { - // if explicitly set, then use it - if v.configFile != "" { - return v.configFile, nil + if v.configFile == "" { + cf, err := v.findConfigFile() + if err != nil { + return "", err + } + v.configFile = cf } - - cf, err := v.findConfigFile() - if err != nil { - return "", err - } - - v.configFile = cf - return v.getConfigFile() + return v.configFile, nil } func (v *Viper) searchInPath(in string) (filename string) { jww.DEBUG.Println("Searching for config in ", in) for _, ext := range SupportedExts { jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext)) - if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b { + if b, _ := exists(v.fs, filepath.Join(in, v.configName+"."+ext)); b { jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext)) return filepath.Join(in, v.configName+"."+ext) } diff --git a/vendor/github.com/spf13/viper/viper_test.go b/vendor/github.com/spf13/viper/viper_test.go index 774ca116..15966e4a 100644 --- a/vendor/github.com/spf13/viper/viper_test.go +++ b/vendor/github.com/spf13/viper/viper_test.go @@ -7,6 +7,7 @@ package viper import ( "bytes" + "encoding/json" "fmt" "io" "io/ioutil" @@ -18,6 +19,8 @@ import ( "testing" "time" + "github.com/mitchellh/mapstructure" + "github.com/spf13/afero" "github.com/spf13/cast" "github.com/spf13/pflag" @@ -262,7 +265,7 @@ func TestDefault(t *testing.T) { assert.Equal(t, "leather", Get("clothing.jacket")) } -func TestUnmarshalling(t *testing.T) { +func TestUnmarshaling(t *testing.T) { SetConfigType("yaml") r := bytes.NewReader(yamlExample) @@ -417,7 +420,7 @@ func TestAutoEnvWithPrefix(t *testing.T) { assert.Equal(t, "13", Get("bar")) } -func TestSetEnvReplacer(t *testing.T) { +func TestSetEnvKeyReplacer(t *testing.T) { Reset() AutomaticEnv() @@ -502,6 +505,42 @@ func TestUnmarshal(t *testing.T) { assert.Equal(t, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond}, &C) } +func TestUnmarshalWithDecoderOptions(t *testing.T) { + Set("credentials", "{\"foo\":\"bar\"}") + + opt := DecodeHook(mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + // Custom Decode Hook Function + func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) { + if rf != reflect.String || rt != reflect.Map { + return data, nil + } + m := map[string]string{} + raw := data.(string) + if raw == "" { + return m, nil + } + return m, json.Unmarshal([]byte(raw), &m) + }, + )) + + type config struct { + Credentials map[string]string + } + + var C config + + err := Unmarshal(&C, opt) + if err != nil { + t.Fatalf("unable to decode into struct, %v", err) + } + + assert.Equal(t, &config{ + Credentials: map[string]string{"foo": "bar"}, + }, &C) +} + func TestBindPFlags(t *testing.T) { v := New() // create independent Viper object flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) @@ -847,6 +886,190 @@ func TestSub(t *testing.T) { assert.Equal(t, (*Viper)(nil), subv) } +var hclWriteExpected = []byte(`"foos" = { + "foo" = { + "key" = 1 + } + + "foo" = { + "key" = 2 + } + + "foo" = { + "key" = 3 + } + + "foo" = { + "key" = 4 + } +} + +"id" = "0001" + +"name" = "Cake" + +"ppu" = 0.55 + +"type" = "donut"`) + +func TestWriteConfigHCL(t *testing.T) { + v := New() + fs := afero.NewMemMapFs() + v.SetFs(fs) + v.SetConfigName("c") + v.SetConfigType("hcl") + err := v.ReadConfig(bytes.NewBuffer(hclExample)) + if err != nil { + t.Fatal(err) + } + if err := v.WriteConfigAs("c.hcl"); err != nil { + t.Fatal(err) + } + read, err := afero.ReadFile(fs, "c.hcl") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, hclWriteExpected, read) +} + +var jsonWriteExpected = []byte(`{ + "batters": { + "batter": [ + { + "type": "Regular" + }, + { + "type": "Chocolate" + }, + { + "type": "Blueberry" + }, + { + "type": "Devil's Food" + } + ] + }, + "id": "0001", + "name": "Cake", + "ppu": 0.55, + "type": "donut" +}`) + +func TestWriteConfigJson(t *testing.T) { + v := New() + fs := afero.NewMemMapFs() + v.SetFs(fs) + v.SetConfigName("c") + v.SetConfigType("json") + err := v.ReadConfig(bytes.NewBuffer(jsonExample)) + if err != nil { + t.Fatal(err) + } + if err := v.WriteConfigAs("c.json"); err != nil { + t.Fatal(err) + } + read, err := afero.ReadFile(fs, "c.json") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, jsonWriteExpected, read) +} + +var propertiesWriteExpected = []byte(`p_id = 0001 +p_type = donut +p_name = Cake +p_ppu = 0.55 +p_batters.batter.type = Regular +`) + +func TestWriteConfigProperties(t *testing.T) { + v := New() + fs := afero.NewMemMapFs() + v.SetFs(fs) + v.SetConfigName("c") + v.SetConfigType("properties") + err := v.ReadConfig(bytes.NewBuffer(propertiesExample)) + if err != nil { + t.Fatal(err) + } + if err := v.WriteConfigAs("c.properties"); err != nil { + t.Fatal(err) + } + read, err := afero.ReadFile(fs, "c.properties") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, propertiesWriteExpected, read) +} + +func TestWriteConfigTOML(t *testing.T) { + fs := afero.NewMemMapFs() + v := New() + v.SetFs(fs) + v.SetConfigName("c") + v.SetConfigType("toml") + err := v.ReadConfig(bytes.NewBuffer(tomlExample)) + if err != nil { + t.Fatal(err) + } + if err := v.WriteConfigAs("c.toml"); err != nil { + t.Fatal(err) + } + + // The TOML String method does not order the contents. + // Therefore, we must read the generated file and compare the data. + v2 := New() + v2.SetFs(fs) + v2.SetConfigName("c") + v2.SetConfigType("toml") + v2.SetConfigFile("c.toml") + err = v2.ReadInConfig() + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, v.GetString("title"), v2.GetString("title")) + assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio")) + assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob")) + assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization")) +} + +var yamlWriteExpected = []byte(`age: 35 +beard: true +clothing: + jacket: leather + pants: + size: large + trousers: denim +eyes: brown +hacker: true +hobbies: +- skateboarding +- snowboarding +- go +name: steve +`) + +func TestWriteConfigYAML(t *testing.T) { + v := New() + fs := afero.NewMemMapFs() + v.SetFs(fs) + v.SetConfigName("c") + v.SetConfigType("yaml") + err := v.ReadConfig(bytes.NewBuffer(yamlExample)) + if err != nil { + t.Fatal(err) + } + if err := v.WriteConfigAs("c.yaml"); err != nil { + t.Fatal(err) + } + read, err := afero.ReadFile(fs, "c.yaml") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, yamlWriteExpected, read) +} + var yamlMergeExampleTgt = []byte(` hello: pop: 37890 @@ -879,8 +1102,8 @@ func TestMergeConfig(t *testing.T) { t.Fatalf("pop != 37890, = %d", pop) } - if pop := v.GetInt("hello.lagrenum"); pop != 765432101234567 { - t.Fatalf("lagrenum != 765432101234567, = %d", pop) + if pop := v.GetInt32("hello.pop"); pop != int32(37890) { + t.Fatalf("pop != 37890, = %d", pop) } if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) { @@ -903,8 +1126,8 @@ func TestMergeConfig(t *testing.T) { t.Fatalf("pop != 45000, = %d", pop) } - if pop := v.GetInt("hello.lagrenum"); pop != 7654321001234567 { - t.Fatalf("lagrenum != 7654321001234567, = %d", pop) + if pop := v.GetInt32("hello.pop"); pop != int32(45000) { + t.Fatalf("pop != 45000, = %d", pop) } if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) { diff --git a/vendor/github.com/syndtr/goleveldb/.travis.yml b/vendor/github.com/syndtr/goleveldb/.travis.yml index 8014f396..f31939eb 100644 --- a/vendor/github.com/syndtr/goleveldb/.travis.yml +++ b/vendor/github.com/syndtr/goleveldb/.travis.yml @@ -1,7 +1,6 @@ language: go go: - - 1.4 - 1.5 - 1.6 - 1.7 diff --git a/vendor/github.com/syndtr/goleveldb/README.md b/vendor/github.com/syndtr/goleveldb/README.md index 9b43dfec..41a47614 100644 --- a/vendor/github.com/syndtr/goleveldb/README.md +++ b/vendor/github.com/syndtr/goleveldb/README.md @@ -10,7 +10,7 @@ Installation Requirements ----------- -* Need at least `go1.4` or newer. +* Need at least `go1.5` or newer. Usage ----------- diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db.go b/vendor/github.com/syndtr/goleveldb/leveldb/db.go index fc3c408f..e7ac0654 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db.go @@ -32,6 +32,12 @@ type DB struct { // Need 64-bit alignment. seq uint64 + // Stats. Need 64-bit alignment. + cWriteDelay int64 // The cumulative duration of write delays + cWriteDelayN int32 // The cumulative number of write delays + inWritePaused int32 // The indicator whether write operation is paused by compaction + aliveSnaps, aliveIters int32 + // Session. s *session @@ -49,9 +55,6 @@ type DB struct { snapsMu sync.Mutex snapsList *list.List - // Stats. - aliveSnaps, aliveIters int32 - // Write. batchPool sync.Pool writeMergeC chan writeMerge @@ -904,6 +907,10 @@ func (db *DB) GetSnapshot() (*Snapshot, error) { // Returns the number of files at level 'n'. // leveldb.stats // Returns statistics of the underlying DB. +// leveldb.iostats +// Returns statistics of effective disk read and write. +// leveldb.writedelay +// Returns cumulative write delay caused by compaction. // leveldb.sstables // Returns sstables list for each level. // leveldb.blockpool @@ -955,6 +962,14 @@ func (db *DB) GetProperty(name string) (value string, err error) { level, len(tables), float64(tables.size())/1048576.0, duration.Seconds(), float64(read)/1048576.0, float64(write)/1048576.0) } + case p == "iostats": + value = fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f", + float64(db.s.stor.reads())/1048576.0, + float64(db.s.stor.writes())/1048576.0) + case p == "writedelay": + writeDelayN, writeDelay := atomic.LoadInt32(&db.cWriteDelayN), time.Duration(atomic.LoadInt64(&db.cWriteDelay)) + paused := atomic.LoadInt32(&db.inWritePaused) == 1 + value = fmt.Sprintf("DelayN:%d Delay:%s Paused:%t", writeDelayN, writeDelay, paused) case p == "sstables": for level, tables := range v.levels { value += fmt.Sprintf("--- level %d ---\n", level) @@ -983,6 +998,75 @@ func (db *DB) GetProperty(name string) (value string, err error) { return } +// DBStats is database statistics. +type DBStats struct { + WriteDelayCount int32 + WriteDelayDuration time.Duration + WritePaused bool + + AliveSnapshots int32 + AliveIterators int32 + + IOWrite uint64 + IORead uint64 + + BlockCacheSize int + OpenedTablesCount int + + LevelSizes []int64 + LevelTablesCounts []int + LevelRead []int64 + LevelWrite []int64 + LevelDurations []time.Duration +} + +// Stats populates s with database statistics. +func (db *DB) Stats(s *DBStats) error { + err := db.ok() + if err != nil { + return err + } + + s.IORead = db.s.stor.reads() + s.IOWrite = db.s.stor.writes() + s.WriteDelayCount = atomic.LoadInt32(&db.cWriteDelayN) + s.WriteDelayDuration = time.Duration(atomic.LoadInt64(&db.cWriteDelay)) + s.WritePaused = atomic.LoadInt32(&db.inWritePaused) == 1 + + s.OpenedTablesCount = db.s.tops.cache.Size() + if db.s.tops.bcache != nil { + s.BlockCacheSize = db.s.tops.bcache.Size() + } else { + s.BlockCacheSize = 0 + } + + s.AliveIterators = atomic.LoadInt32(&db.aliveIters) + s.AliveSnapshots = atomic.LoadInt32(&db.aliveSnaps) + + s.LevelDurations = s.LevelDurations[:0] + s.LevelRead = s.LevelRead[:0] + s.LevelWrite = s.LevelWrite[:0] + s.LevelSizes = s.LevelSizes[:0] + s.LevelTablesCounts = s.LevelTablesCounts[:0] + + v := db.s.version() + defer v.release() + + for level, tables := range v.levels { + duration, read, write := db.compStats.getStat(level) + if len(tables) == 0 && duration == 0 { + continue + } + s.LevelDurations = append(s.LevelDurations, duration) + s.LevelRead = append(s.LevelRead, read) + s.LevelWrite = append(s.LevelWrite, write) + s.LevelSizes = append(s.LevelSizes, tables.size()) + s.LevelTablesCounts = append(s.LevelTablesCounts, len(tables)) + } + + return nil +} + // SizeOf calculates approximate sizes of the given key ranges. // The length of the returned sizes are equal with the length of the given // ranges. The returned sizes measure storage space usage, so if the user diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_compaction.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_compaction.go index b6563e87..28e50906 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_compaction.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_compaction.go @@ -640,6 +640,16 @@ func (db *DB) tableNeedCompaction() bool { return v.needCompaction() } +// resumeWrite returns an indicator whether we should resume write operation if enough level0 files are compacted. +func (db *DB) resumeWrite() bool { + v := db.s.version() + defer v.release() + if v.tLen(0) < db.s.o.GetWriteL0PauseTrigger() { + return true + } + return false +} + func (db *DB) pauseCompaction(ch chan<- struct{}) { select { case ch <- struct{}{}: @@ -653,6 +663,7 @@ type cCmd interface { } type cAuto struct { + // Note for table compaction, an empty ackC represents it's a compaction waiting command. ackC chan<- error } @@ -765,8 +776,10 @@ func (db *DB) mCompaction() { } func (db *DB) tCompaction() { - var x cCmd - var ackQ []cCmd + var ( + x cCmd + ackQ, waitQ []cCmd + ) defer func() { if x := recover(); x != nil { @@ -778,6 +791,10 @@ func (db *DB) tCompaction() { ackQ[i].ack(ErrClosed) ackQ[i] = nil } + for i := range waitQ { + waitQ[i].ack(ErrClosed) + waitQ[i] = nil + } if x != nil { x.ack(ErrClosed) } @@ -795,12 +812,25 @@ func (db *DB) tCompaction() { return default: } + // Resume write operation as soon as possible. + if len(waitQ) > 0 && db.resumeWrite() { + for i := range waitQ { + waitQ[i].ack(nil) + waitQ[i] = nil + } + waitQ = waitQ[:0] + } } else { for i := range ackQ { ackQ[i].ack(nil) ackQ[i] = nil } ackQ = ackQ[:0] + for i := range waitQ { + waitQ[i].ack(nil) + waitQ[i] = nil + } + waitQ = waitQ[:0] select { case x = <-db.tcompCmdC: case ch := <-db.tcompPauseC: @@ -813,7 +843,11 @@ func (db *DB) tCompaction() { if x != nil { switch cmd := x.(type) { case cAuto: - ackQ = append(ackQ, x) + if cmd.ackC != nil { + waitQ = append(waitQ, x) + } else { + ackQ = append(ackQ, x) + } case cRange: x.ack(db.tableRangeCompaction(cmd.level, cmd.min, cmd.max)) default: diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go index 5b6cb487..db0c1bec 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go @@ -7,6 +7,7 @@ package leveldb import ( + "sync/atomic" "time" "github.com/syndtr/goleveldb/leveldb/memdb" @@ -88,7 +89,11 @@ func (db *DB) flush(n int) (mdb *memDB, mdbFree int, err error) { return false case tLen >= pauseTrigger: delayed = true + // Set the write paused flag explicitly. + atomic.StoreInt32(&db.inWritePaused, 1) err = db.compTriggerWait(db.tcompCmdC) + // Unset the write paused flag. + atomic.StoreInt32(&db.inWritePaused, 0) if err != nil { return false } @@ -117,6 +122,8 @@ func (db *DB) flush(n int) (mdb *memDB, mdbFree int, err error) { db.writeDelayN++ } else if db.writeDelayN > 0 { db.logf("db@write was delayed N·%d T·%v", db.writeDelayN, db.writeDelay) + atomic.AddInt32(&db.cWriteDelayN, int32(db.writeDelayN)) + atomic.AddInt64(&db.cWriteDelay, int64(db.writeDelay)) db.writeDelay = 0 db.writeDelayN = 0 } @@ -143,7 +150,7 @@ func (db *DB) unlockWrite(overflow bool, merged int, err error) { } } -// ourBatch if defined should equal with batch. +// ourBatch is batch that we can modify. func (db *DB) writeLocked(batch, ourBatch *Batch, merge, sync bool) error { // Try to flush memdb. This method would also trying to throttle writes // if it is too fast and compaction cannot catch-up. @@ -212,6 +219,11 @@ func (db *DB) writeLocked(batch, ourBatch *Batch, merge, sync bool) error { } } + // Release ourBatch if any. + if ourBatch != nil { + defer db.batchPool.Put(ourBatch) + } + // Seq number. seq := db.seq + 1 diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/session.go b/vendor/github.com/syndtr/goleveldb/leveldb/session.go index ad68a870..3f391f93 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/session.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/session.go @@ -42,7 +42,7 @@ type session struct { stTempFileNum int64 stSeqNum uint64 // last mem compacted seq; need external synchronization - stor storage.Storage + stor *iStorage storLock storage.Locker o *cachedOptions icmp *iComparer @@ -68,7 +68,7 @@ func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) { return } s = &session{ - stor: stor, + stor: newIStorage(stor), storLock: storLock, fileRef: make(map[int64]int), } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage.go new file mode 100644 index 00000000..d45fb5df --- /dev/null +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage.go @@ -0,0 +1,63 @@ +package leveldb + +import ( + "github.com/syndtr/goleveldb/leveldb/storage" + "sync/atomic" +) + +type iStorage struct { + storage.Storage + read uint64 + write uint64 +} + +func (c *iStorage) Open(fd storage.FileDesc) (storage.Reader, error) { + r, err := c.Storage.Open(fd) + return &iStorageReader{r, c}, err +} + +func (c *iStorage) Create(fd storage.FileDesc) (storage.Writer, error) { + w, err := c.Storage.Create(fd) + return &iStorageWriter{w, c}, err +} + +func (c *iStorage) reads() uint64 { + return atomic.LoadUint64(&c.read) +} + +func (c *iStorage) writes() uint64 { + return atomic.LoadUint64(&c.write) +} + +// newIStorage returns the given storage wrapped by iStorage. +func newIStorage(s storage.Storage) *iStorage { + return &iStorage{s, 0, 0} +} + +type iStorageReader struct { + storage.Reader + c *iStorage +} + +func (r *iStorageReader) Read(p []byte) (n int, err error) { + n, err = r.Reader.Read(p) + atomic.AddUint64(&r.c.read, uint64(n)) + return n, err +} + +func (r *iStorageReader) ReadAt(p []byte, off int64) (n int, err error) { + n, err = r.Reader.ReadAt(p, off) + atomic.AddUint64(&r.c.read, uint64(n)) + return n, err +} + +type iStorageWriter struct { + storage.Writer + c *iStorage +} + +func (w *iStorageWriter) Write(p []byte) (n int, err error) { + n, err = w.Writer.Write(p) + atomic.AddUint64(&w.c.write, uint64(n)) + return n, err +} diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go index 1189deca..9ba71fd6 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go @@ -9,10 +9,12 @@ package storage import ( "errors" "fmt" + "io" "io/ioutil" "os" "path/filepath" "runtime" + "sort" "strconv" "strings" "sync" @@ -42,6 +44,30 @@ func (lock *fileStorageLock) Unlock() { } } +type int64Slice []int64 + +func (p int64Slice) Len() int { return len(p) } +func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +func writeFileSynced(filename string, data []byte, perm os.FileMode) error { + f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + return err + } + n, err := f.Write(data) + if err == nil && n < len(data) { + err = io.ErrShortWrite + } + if err1 := f.Sync(); err == nil { + err = err1 + } + if err1 := f.Close(); err == nil { + err = err1 + } + return err +} + const logSizeThreshold = 1024 * 1024 // 1 MiB // fileStorage is a file-system backed storage. @@ -60,7 +86,7 @@ type fileStorage struct { day int } -// OpenFile returns a new filesytem-backed storage implementation with the given +// OpenFile returns a new filesystem-backed storage implementation with the given // path. This also acquire a file lock, so any subsequent attempt to open the // same path will fail. // @@ -189,7 +215,8 @@ func (fs *fileStorage) doLog(t time.Time, str string) { // write fs.buf = append(fs.buf, []byte(str)...) fs.buf = append(fs.buf, '\n') - fs.logw.Write(fs.buf) + n, _ := fs.logw.Write(fs.buf) + fs.logSize += int64(n) } func (fs *fileStorage) Log(str string) { @@ -210,7 +237,46 @@ func (fs *fileStorage) log(str string) { } } -func (fs *fileStorage) SetMeta(fd FileDesc) (err error) { +func (fs *fileStorage) setMeta(fd FileDesc) error { + content := fsGenName(fd) + "\n" + // Check and backup old CURRENT file. + currentPath := filepath.Join(fs.path, "CURRENT") + if _, err := os.Stat(currentPath); err == nil { + b, err := ioutil.ReadFile(currentPath) + if err != nil { + fs.log(fmt.Sprintf("backup CURRENT: %v", err)) + return err + } + if string(b) == content { + // Content not changed, do nothing. + return nil + } + if err := writeFileSynced(currentPath+".bak", b, 0644); err != nil { + fs.log(fmt.Sprintf("backup CURRENT: %v", err)) + return err + } + } else if !os.IsNotExist(err) { + return err + } + path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num) + if err := writeFileSynced(path, []byte(content), 0644); err != nil { + fs.log(fmt.Sprintf("create CURRENT.%d: %v", fd.Num, err)) + return err + } + // Replace CURRENT file. + if err := rename(path, currentPath); err != nil { + fs.log(fmt.Sprintf("rename CURRENT.%d: %v", fd.Num, err)) + return err + } + // Sync root directory. + if err := syncDir(fs.path); err != nil { + fs.log(fmt.Sprintf("syncDir: %v", err)) + return err + } + return nil +} + +func (fs *fileStorage) SetMeta(fd FileDesc) error { if !FileDescOk(fd) { return ErrInvalidFile } @@ -223,44 +289,10 @@ func (fs *fileStorage) SetMeta(fd FileDesc) (err error) { if fs.open < 0 { return ErrClosed } - defer func() { - if err != nil { - fs.log(fmt.Sprintf("CURRENT: %v", err)) - } - }() - path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num) - w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - return - } - _, err = fmt.Fprintln(w, fsGenName(fd)) - if err != nil { - fs.log(fmt.Sprintf("write CURRENT.%d: %v", fd.Num, err)) - return - } - if err = w.Sync(); err != nil { - fs.log(fmt.Sprintf("flush CURRENT.%d: %v", fd.Num, err)) - return - } - if err = w.Close(); err != nil { - fs.log(fmt.Sprintf("close CURRENT.%d: %v", fd.Num, err)) - return - } - if err != nil { - return - } - if err = rename(path, filepath.Join(fs.path, "CURRENT")); err != nil { - fs.log(fmt.Sprintf("rename CURRENT.%d: %v", fd.Num, err)) - return - } - // Sync root directory. - if err = syncDir(fs.path); err != nil { - fs.log(fmt.Sprintf("syncDir: %v", err)) - } - return + return fs.setMeta(fd) } -func (fs *fileStorage) GetMeta() (fd FileDesc, err error) { +func (fs *fileStorage) GetMeta() (FileDesc, error) { fs.mu.Lock() defer fs.mu.Unlock() if fs.open < 0 { @@ -268,7 +300,7 @@ func (fs *fileStorage) GetMeta() (fd FileDesc, err error) { } dir, err := os.Open(fs.path) if err != nil { - return + return FileDesc{}, err } names, err := dir.Readdirnames(0) // Close the dir first before checking for Readdirnames error. @@ -276,94 +308,134 @@ func (fs *fileStorage) GetMeta() (fd FileDesc, err error) { fs.log(fmt.Sprintf("close dir: %v", ce)) } if err != nil { - return + return FileDesc{}, err } - // Find latest CURRENT file. - var rem []string - var pend bool - var cerr error + // Try this in order: + // - CURRENT.[0-9]+ ('pending rename' file, descending order) + // - CURRENT + // - CURRENT.bak + // + // Skip corrupted file or file that point to a missing target file. + type currentFile struct { + name string + fd FileDesc + } + tryCurrent := func(name string) (*currentFile, error) { + b, err := ioutil.ReadFile(filepath.Join(fs.path, name)) + if err != nil { + if os.IsNotExist(err) { + err = os.ErrNotExist + } + return nil, err + } + var fd FileDesc + if len(b) < 1 || b[len(b)-1] != '\n' || !fsParseNamePtr(string(b[:len(b)-1]), &fd) { + fs.log(fmt.Sprintf("%s: corrupted content: %q", name, b)) + err := &ErrCorrupted{ + Err: errors.New("leveldb/storage: corrupted or incomplete CURRENT file"), + } + return nil, err + } + if _, err := os.Stat(filepath.Join(fs.path, fsGenName(fd))); err != nil { + if os.IsNotExist(err) { + fs.log(fmt.Sprintf("%s: missing target file: %s", name, fd)) + err = os.ErrNotExist + } + return nil, err + } + return ¤tFile{name: name, fd: fd}, nil + } + tryCurrents := func(names []string) (*currentFile, error) { + var ( + cur *currentFile + // Last corruption error. + lastCerr error + ) + for _, name := range names { + var err error + cur, err = tryCurrent(name) + if err == nil { + break + } else if err == os.ErrNotExist { + // Fallback to the next file. + } else if isCorrupted(err) { + lastCerr = err + // Fallback to the next file. + } else { + // In case the error is due to permission, etc. + return nil, err + } + } + if cur == nil { + err := os.ErrNotExist + if lastCerr != nil { + err = lastCerr + } + return nil, err + } + return cur, nil + } + + // Try 'pending rename' files. + var nums []int64 for _, name := range names { - if strings.HasPrefix(name, "CURRENT") { - pend1 := len(name) > 7 - var pendNum int64 - // Make sure it is valid name for a CURRENT file, otherwise skip it. - if pend1 { - if name[7] != '.' || len(name) < 9 { - fs.log(fmt.Sprintf("skipping %s: invalid file name", name)) - continue - } - var e1 error - if pendNum, e1 = strconv.ParseInt(name[8:], 10, 0); e1 != nil { - fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", name, e1)) - continue - } + if strings.HasPrefix(name, "CURRENT.") && name != "CURRENT.bak" { + i, err := strconv.ParseInt(name[8:], 10, 64) + if err == nil { + nums = append(nums, i) } - path := filepath.Join(fs.path, name) - r, e1 := os.OpenFile(path, os.O_RDONLY, 0) - if e1 != nil { - return FileDesc{}, e1 - } - b, e1 := ioutil.ReadAll(r) - if e1 != nil { - r.Close() - return FileDesc{}, e1 - } - var fd1 FileDesc - if len(b) < 1 || b[len(b)-1] != '\n' || !fsParseNamePtr(string(b[:len(b)-1]), &fd1) { - fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", name)) - if pend1 { - rem = append(rem, name) - } - if !pend1 || cerr == nil { - metaFd, _ := fsParseName(name) - cerr = &ErrCorrupted{ - Fd: metaFd, - Err: errors.New("leveldb/storage: corrupted or incomplete meta file"), + } + } + var ( + pendCur *currentFile + pendErr = os.ErrNotExist + pendNames []string + ) + if len(nums) > 0 { + sort.Sort(sort.Reverse(int64Slice(nums))) + pendNames = make([]string, len(nums)) + for i, num := range nums { + pendNames[i] = fmt.Sprintf("CURRENT.%d", num) + } + pendCur, pendErr = tryCurrents(pendNames) + if pendErr != nil && pendErr != os.ErrNotExist && !isCorrupted(pendErr) { + return FileDesc{}, pendErr + } + } + + // Try CURRENT and CURRENT.bak. + curCur, curErr := tryCurrents([]string{"CURRENT", "CURRENT.bak"}) + if curErr != nil && curErr != os.ErrNotExist && !isCorrupted(curErr) { + return FileDesc{}, curErr + } + + // pendCur takes precedence, but guards against obsolete pendCur. + if pendCur != nil && (curCur == nil || pendCur.fd.Num > curCur.fd.Num) { + curCur = pendCur + } + + if curCur != nil { + // Restore CURRENT file to proper state. + if !fs.readOnly && (curCur.name != "CURRENT" || len(pendNames) != 0) { + // Ignore setMeta errors, however don't delete obsolete files if we + // catch error. + if err := fs.setMeta(curCur.fd); err == nil { + // Remove 'pending rename' files. + for _, name := range pendNames { + if err := os.Remove(filepath.Join(fs.path, name)); err != nil { + fs.log(fmt.Sprintf("remove %s: %v", name, err)) } } - } else if pend1 && pendNum != fd1.Num { - fs.log(fmt.Sprintf("skipping %s: inconsistent pending-file num: %d vs %d", name, pendNum, fd1.Num)) - rem = append(rem, name) - } else if fd1.Num < fd.Num { - fs.log(fmt.Sprintf("skipping %s: obsolete", name)) - if pend1 { - rem = append(rem, name) - } - } else { - fd = fd1 - pend = pend1 - } - if err := r.Close(); err != nil { - fs.log(fmt.Sprintf("close %s: %v", name, err)) } } + return curCur.fd, nil } - // Don't remove any files if there is no valid CURRENT file. - if fd.Zero() { - if cerr != nil { - err = cerr - } else { - err = os.ErrNotExist - } - return + + // Nothing found. + if isCorrupted(pendErr) { + return FileDesc{}, pendErr } - if !fs.readOnly { - // Rename pending CURRENT file to an effective CURRENT. - if pend { - path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num) - if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil { - fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %v", fd.Num, err)) - } - } - // Remove obsolete or incomplete pending CURRENT files. - for _, name := range rem { - path := filepath.Join(fs.path, name) - if err := os.Remove(path); err != nil { - fs.log(fmt.Sprintf("remove %s: %v", name, err)) - } - } - } - return + return FileDesc{}, curErr } func (fs *fileStorage) List(ft FileType) (fds []FileDesc, err error) { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go index bab62bfc..b8297980 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go @@ -8,7 +8,6 @@ package storage import ( "os" - "path/filepath" ) type plan9FileLock struct { @@ -48,8 +47,7 @@ func rename(oldpath, newpath string) error { } } - _, fname := filepath.Split(newpath) - return os.Rename(oldpath, fname) + return os.Rename(oldpath, newpath) } func syncDir(name string) error { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go index 28a59ecc..2e60315f 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go @@ -8,8 +8,11 @@ package storage import ( "fmt" + "io/ioutil" + "math/rand" "os" "path/filepath" + "strings" "testing" ) @@ -53,6 +56,15 @@ var invalidCases = []string{ "100.lop", } +func tempDir(t *testing.T) string { + dir, err := ioutil.TempDir("", "goleveldb-") + if err != nil { + t.Fatal(t) + } + t.Log("Using temp-dir:", dir) + return dir +} + func TestFileStorage_CreateFileName(t *testing.T) { for _, c := range cases { if name := fsGenName(FileDesc{c.ftype, c.num}); name != c.name { @@ -61,6 +73,224 @@ func TestFileStorage_CreateFileName(t *testing.T) { } } +func TestFileStorage_MetaSetGet(t *testing.T) { + temp := tempDir(t) + fs, err := OpenFile(temp, false) + if err != nil { + t.Fatal("OpenFile: got error: ", err) + } + + for i := 0; i < 10; i++ { + num := rand.Int63() + fd := FileDesc{Type: TypeManifest, Num: num} + w, err := fs.Create(fd) + if err != nil { + t.Fatalf("Create(%d): got error: %v", i, err) + } + w.Write([]byte("TEST")) + w.Close() + if err := fs.SetMeta(fd); err != nil { + t.Fatalf("SetMeta(%d): got error: %v", i, err) + } + rfd, err := fs.GetMeta() + if err != nil { + t.Fatalf("GetMeta(%d): got error: %v", i, err) + } + if fd != rfd { + t.Fatalf("Invalid meta (%d): got '%s', want '%s'", i, rfd, fd) + } + } + os.RemoveAll(temp) +} + +func TestFileStorage_Meta(t *testing.T) { + type current struct { + num int64 + backup bool + current bool + manifest bool + corrupt bool + } + type testCase struct { + currents []current + notExist bool + corrupt bool + expect int64 + } + cases := []testCase{ + { + currents: []current{ + {num: 2, backup: true, manifest: true}, + {num: 1, current: true}, + }, + expect: 2, + }, + { + currents: []current{ + {num: 2, backup: true, manifest: true}, + {num: 1, current: true, manifest: true}, + }, + expect: 1, + }, + { + currents: []current{ + {num: 2, manifest: true}, + {num: 3, manifest: true}, + {num: 4, current: true, manifest: true}, + }, + expect: 4, + }, + { + currents: []current{ + {num: 2, manifest: true}, + {num: 3, manifest: true}, + {num: 4, current: true, manifest: true, corrupt: true}, + }, + expect: 3, + }, + { + currents: []current{ + {num: 2, manifest: true}, + {num: 3, manifest: true}, + {num: 5, current: true, manifest: true, corrupt: true}, + {num: 4, backup: true, manifest: true}, + }, + expect: 4, + }, + { + currents: []current{ + {num: 4, manifest: true}, + {num: 3, manifest: true}, + {num: 2, current: true, manifest: true}, + }, + expect: 4, + }, + { + currents: []current{ + {num: 4, manifest: true, corrupt: true}, + {num: 3, manifest: true}, + {num: 2, current: true, manifest: true}, + }, + expect: 3, + }, + { + currents: []current{ + {num: 4, manifest: true, corrupt: true}, + {num: 3, manifest: true, corrupt: true}, + {num: 2, current: true, manifest: true}, + }, + expect: 2, + }, + { + currents: []current{ + {num: 4}, + {num: 3, manifest: true}, + {num: 2, current: true, manifest: true}, + }, + expect: 3, + }, + { + currents: []current{ + {num: 4}, + {num: 3, manifest: true}, + {num: 6, current: true}, + {num: 5, backup: true, manifest: true}, + }, + expect: 5, + }, + { + currents: []current{ + {num: 4}, + {num: 3}, + {num: 6, current: true}, + {num: 5, backup: true}, + }, + notExist: true, + }, + { + currents: []current{ + {num: 4, corrupt: true}, + {num: 3}, + {num: 6, current: true}, + {num: 5, backup: true}, + }, + corrupt: true, + }, + } + for i, tc := range cases { + t.Logf("Test-%d", i) + temp := tempDir(t) + fs, err := OpenFile(temp, false) + if err != nil { + t.Fatal("OpenFile: got error: ", err) + } + for _, cur := range tc.currents { + var curName string + switch { + case cur.current: + curName = "CURRENT" + case cur.backup: + curName = "CURRENT.bak" + default: + curName = fmt.Sprintf("CURRENT.%d", cur.num) + } + fd := FileDesc{Type: TypeManifest, Num: cur.num} + content := fmt.Sprintf("%s\n", fsGenName(fd)) + if cur.corrupt { + content = content[:len(content)-1-rand.Intn(3)] + } + if err := ioutil.WriteFile(filepath.Join(temp, curName), []byte(content), 0644); err != nil { + t.Fatal(err) + } + if cur.manifest { + w, err := fs.Create(fd) + if err != nil { + t.Fatal(err) + } + if _, err := w.Write([]byte("TEST")); err != nil { + t.Fatal(err) + } + w.Close() + } + } + ret, err := fs.GetMeta() + if tc.notExist { + if err != os.ErrNotExist { + t.Fatalf("expect ErrNotExist, got: %v", err) + } + } else if tc.corrupt { + if !isCorrupted(err) { + t.Fatalf("expect ErrCorrupted, got: %v", err) + } + } else { + if err != nil { + t.Fatal(err) + } + if ret.Type != TypeManifest { + t.Fatalf("expecting manifest, got: %s", ret.Type) + } + if ret.Num != tc.expect { + t.Fatalf("invalid num, expect=%d got=%d", tc.expect, ret.Num) + } + fis, err := ioutil.ReadDir(temp) + if err != nil { + t.Fatal(err) + } + for _, fi := range fis { + if strings.HasPrefix(fi.Name(), "CURRENT") { + switch fi.Name() { + case "CURRENT", "CURRENT.bak": + default: + t.Fatalf("found rouge CURRENT file: %s", fi.Name()) + } + } + t.Logf("-> %s", fi.Name()) + } + } + os.RemoveAll(temp) + } +} + func TestFileStorage_ParseFileName(t *testing.T) { for _, c := range cases { for _, name := range append([]string{c.name}, c.oldName...) { @@ -88,18 +318,15 @@ func TestFileStorage_InvalidFileName(t *testing.T) { } func TestFileStorage_Locking(t *testing.T) { - path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-testrwlock-%d", os.Getuid())) - if err := os.RemoveAll(path); err != nil && !os.IsNotExist(err) { - t.Fatal("RemoveAll: got error: ", err) - } - defer os.RemoveAll(path) + temp := tempDir(t) + defer os.RemoveAll(temp) - p1, err := OpenFile(path, false) + p1, err := OpenFile(temp, false) if err != nil { t.Fatal("OpenFile(1): got error: ", err) } - p2, err := OpenFile(path, false) + p2, err := OpenFile(temp, false) if err != nil { t.Logf("OpenFile(2): got error: %s (expected)", err) } else { @@ -110,7 +337,7 @@ func TestFileStorage_Locking(t *testing.T) { p1.Close() - p3, err := OpenFile(path, false) + p3, err := OpenFile(temp, false) if err != nil { t.Fatal("OpenFile(3): got error: ", err) } @@ -134,18 +361,15 @@ func TestFileStorage_Locking(t *testing.T) { } func TestFileStorage_ReadOnlyLocking(t *testing.T) { - path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-testrolock-%d", os.Getuid())) - if err := os.RemoveAll(path); err != nil && !os.IsNotExist(err) { - t.Fatal("RemoveAll: got error: ", err) - } - defer os.RemoveAll(path) + temp := tempDir(t) + defer os.RemoveAll(temp) - p1, err := OpenFile(path, false) + p1, err := OpenFile(temp, false) if err != nil { t.Fatal("OpenFile(1): got error: ", err) } - _, err = OpenFile(path, true) + _, err = OpenFile(temp, true) if err != nil { t.Logf("OpenFile(2): got error: %s (expected)", err) } else { @@ -154,17 +378,17 @@ func TestFileStorage_ReadOnlyLocking(t *testing.T) { p1.Close() - p3, err := OpenFile(path, true) + p3, err := OpenFile(temp, true) if err != nil { t.Fatal("OpenFile(3): got error: ", err) } - p4, err := OpenFile(path, true) + p4, err := OpenFile(temp, true) if err != nil { t.Fatal("OpenFile(4): got error: ", err) } - _, err = OpenFile(path, false) + _, err = OpenFile(temp, false) if err != nil { t.Logf("OpenFile(5): got error: %s (expected)", err) } else { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go index 7e299153..d75f66a9 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go @@ -67,13 +67,25 @@ func isErrInvalid(err error) bool { if err == os.ErrInvalid { return true } + // Go < 1.8 if syserr, ok := err.(*os.SyscallError); ok && syserr.Err == syscall.EINVAL { return true } + // Go >= 1.8 returns *os.PathError instead + if patherr, ok := err.(*os.PathError); ok && patherr.Err == syscall.EINVAL { + return true + } return false } func syncDir(name string) error { + // As per fsync manpage, Linux seems to expect fsync on directory, however + // some system don't support this, so we will ignore syscall.EINVAL. + // + // From fsync(2): + // Calling fsync() does not necessarily ensure that the entry in the + // directory containing the file has also reached disk. For that an + // explicit fsync() on a file descriptor for the directory is also needed. f, err := os.Open(name) if err != nil { return err diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go index 9b0421f0..838f1bee 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go @@ -12,7 +12,11 @@ import ( "sync" ) -const typeShift = 3 +const typeShift = 4 + +// Verify at compile-time that typeShift is large enough to cover all FileType +// values by confirming that 0 == 0. +var _ [0]struct{} = [TypeAll >> typeShift]struct{}{} type memStorageLock struct { ms *memStorage @@ -143,7 +147,7 @@ func (ms *memStorage) Remove(fd FileDesc) error { } func (ms *memStorage) Rename(oldfd, newfd FileDesc) error { - if FileDescOk(oldfd) || FileDescOk(newfd) { + if !FileDescOk(oldfd) || !FileDescOk(newfd) { return ErrInvalidFile } if oldfd == newfd { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go index fb03d301..bb0a19d7 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go @@ -8,6 +8,7 @@ package storage import ( "bytes" + "fmt" "testing" ) @@ -63,3 +64,54 @@ func TestMemStorage(t *testing.T) { t.Fatal("expecting error") } } + +func TestMemStorageRename(t *testing.T) { + fd1 := FileDesc{Type: TypeTable, Num: 1} + fd2 := FileDesc{Type: TypeTable, Num: 2} + + m := NewMemStorage() + w, err := m.Create(fd1) + if err != nil { + t.Fatalf("Storage.Create: %v", err) + } + + fmt.Fprintf(w, "abc") + w.Close() + + rd, err := m.Open(fd1) + if err != nil { + t.Fatalf("Storage.Open(%v): %v", fd1, err) + } + rd.Close() + + fds, err := m.List(TypeAll) + if err != nil { + t.Fatalf("Storage.List: %v", err) + } + for _, fd := range fds { + if !FileDescOk(fd) { + t.Errorf("Storage.List -> FileDescOk(%q)", fd) + } + } + + err = m.Rename(fd1, fd2) + if err != nil { + t.Fatalf("Storage.Rename: %v", err) + } + + rd, err = m.Open(fd2) + if err != nil { + t.Fatalf("Storage.Open(%v): %v", fd2, err) + } + rd.Close() + + fds, err = m.List(TypeAll) + if err != nil { + t.Fatalf("Storage.List: %v", err) + } + for _, fd := range fds { + if !FileDescOk(fd) { + t.Errorf("Storage.List -> FileDescOk(%q)", fd) + } + } +} diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go index c16bce6b..4e4a7242 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go @@ -55,6 +55,14 @@ type ErrCorrupted struct { Err error } +func isCorrupted(err error) bool { + switch err.(type) { + case *ErrCorrupted: + return true + } + return false +} + func (e *ErrCorrupted) Error() string { if !e.Fd.Zero() { return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd) diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/table.go b/vendor/github.com/syndtr/goleveldb/leveldb/table.go index 81d18a53..adf773f1 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/table.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/table.go @@ -451,7 +451,7 @@ func newTableOps(s *session) *tOps { if !s.o.GetDisableBlockCache() { var bcacher cache.Cacher if s.o.GetBlockCacheCapacity() > 0 { - bcacher = cache.NewLRU(s.o.GetBlockCacheCapacity()) + bcacher = s.o.GetBlockCacher().New(s.o.GetBlockCacheCapacity()) } bcache = cache.NewCache(bcacher) } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/util.go b/vendor/github.com/syndtr/goleveldb/leveldb/util.go index e572a329..0e2b519e 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/util.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/util.go @@ -20,7 +20,7 @@ func shorten(str string) string { return str[:3] + ".." + str[len(str)-3:] } -var bunits = [...]string{"", "Ki", "Mi", "Gi"} +var bunits = [...]string{"", "Ki", "Mi", "Gi", "Ti"} func shortenb(bytes int) string { i := 0 diff --git a/vendor/github.com/syndtr/goleveldb/manualtest/dbstress/main.go b/vendor/github.com/syndtr/goleveldb/manualtest/dbstress/main.go index 2886475f..1f52215d 100644 --- a/vendor/github.com/syndtr/goleveldb/manualtest/dbstress/main.go +++ b/vendor/github.com/syndtr/goleveldb/manualtest/dbstress/main.go @@ -425,9 +425,10 @@ func main() { alivesnaps, _ := db.GetProperty("leveldb.alivesnaps") aliveiters, _ := db.GetProperty("leveldb.aliveiters") blockpool, _ := db.GetProperty("leveldb.blockpool") - log.Printf("> BlockCache=%s OpenedTables=%s AliveSnaps=%s AliveIter=%s BlockPool=%q", - cachedblock, openedtables, alivesnaps, aliveiters, blockpool) - + writeDelay, _ := db.GetProperty("leveldb.writedelay") + ioStats, _ := db.GetProperty("leveldb.iostats") + log.Printf("> BlockCache=%s OpenedTables=%s AliveSnaps=%s AliveIter=%s BlockPool=%q WriteDelay=%q IOStats=%q", + cachedblock, openedtables, alivesnaps, aliveiters, blockpool, writeDelay, ioStats) log.Print("------------------------") } }() diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go index 1f4fb69e..c6fd9989 100644 --- a/vendor/golang.org/x/crypto/acme/acme.go +++ b/vendor/golang.org/x/crypto/acme/acme.go @@ -14,7 +14,6 @@ package acme import ( - "bytes" "context" "crypto" "crypto/ecdsa" @@ -23,6 +22,8 @@ import ( "crypto/sha256" "crypto/tls" "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" "encoding/base64" "encoding/hex" "encoding/json" @@ -33,14 +34,26 @@ import ( "io/ioutil" "math/big" "net/http" - "strconv" "strings" "sync" "time" ) -// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. -const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" +const ( + // LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. + LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" + + // ALPNProto is the ALPN protocol name used by a CA server when validating + // tls-alpn-01 challenges. + // + // Package users must ensure their servers can negotiate the ACME ALPN in + // order for tls-alpn-01 challenge verifications to succeed. + // See the crypto/tls package's Config.NextProtos field. + ALPNProto = "acme-tls/1" +) + +// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge. +var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} const ( maxChainLen = 5 // max depth and breadth of a certificate chain @@ -64,6 +77,10 @@ const ( type Client struct { // Key is the account key used to register with a CA and sign requests. // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. + // + // The following algorithms are supported: + // RS256, ES256, ES384 and ES512. + // See RFC7518 for more details about the algorithms. Key crypto.Signer // HTTPClient optionally specifies an HTTP client to use @@ -76,6 +93,22 @@ type Client struct { // will have no effect. DirectoryURL string + // RetryBackoff computes the duration after which the nth retry of a failed request + // should occur. The value of n for the first call on failure is 1. + // The values of r and resp are the request and response of the last failed attempt. + // If the returned value is negative or zero, no more retries are done and an error + // is returned to the caller of the original method. + // + // Requests which result in a 4xx client error are not retried, + // except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests. + // + // If RetryBackoff is nil, a truncated exponential backoff algorithm + // with the ceiling of 10 seconds is used, where each subsequent retry n + // is done after either ("Retry-After" + jitter) or (2^n seconds + jitter), + // preferring the former if "Retry-After" header is found in the resp. + // The jitter is a random value up to 1 second. + RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration + dirMu sync.Mutex // guards writes to dir dir *Directory // cached result of Client's Discover method @@ -99,15 +132,12 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { if dirURL == "" { dirURL = LetsEncryptURL } - res, err := c.get(ctx, dirURL) + res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK)) if err != nil { return Directory{}, err } defer res.Body.Close() c.addNonce(res.Header) - if res.StatusCode != http.StatusOK { - return Directory{}, responseError(res) - } var v struct { Reg string `json:"new-reg"` @@ -166,14 +196,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, req.NotAfter = now.Add(exp).Format(time.RFC3339) } - res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req) + res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, "", err } defer res.Body.Close() - if res.StatusCode != http.StatusCreated { - return nil, "", responseError(res) - } curl := res.Header.Get("Location") // cert permanent URL if res.ContentLength == 0 { @@ -196,26 +223,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, // Callers are encouraged to parse the returned value to ensure the certificate is valid // and has expected features. func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { - for { - res, err := c.get(ctx, url) - if err != nil { - return nil, err - } - defer res.Body.Close() - if res.StatusCode == http.StatusOK { - return c.responseCert(ctx, res, bundle) - } - if res.StatusCode > 299 { - return nil, responseError(res) - } - d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second) - select { - case <-time.After(d): - // retry - case <-ctx.Done(): - return nil, ctx.Err() - } + res, err := c.get(ctx, url, wantStatus(http.StatusOK)) + if err != nil { + return nil, err } + return c.responseCert(ctx, res, bundle) } // RevokeCert revokes a previously issued certificate cert, provided in DER format. @@ -241,14 +253,11 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, if key == nil { key = c.Key } - res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body) + res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK)) if err != nil { return err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return responseError(res) - } return nil } @@ -329,14 +338,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, Resource: "new-authz", Identifier: authzID{Type: "dns", Value: domain}, } - res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req) + res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusCreated { - return nil, responseError(res) - } var v wireAuthz if err := json.NewDecoder(res.Body).Decode(&v); err != nil { @@ -353,14 +359,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, // If a caller needs to poll an authorization until its status is final, // see the WaitAuthorization method. func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - return nil, responseError(res) - } var v wireAuthz if err := json.NewDecoder(res.Body).Decode(&v); err != nil { return nil, fmt.Errorf("acme: invalid response: %v", err) @@ -387,14 +390,11 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { Status: "deactivated", Delete: true, } - res, err := c.retryPostJWS(ctx, c.Key, url, req) + res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK)) if err != nil { return err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return responseError(res) - } return nil } @@ -406,44 +406,42 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { // In all other cases WaitAuthorization returns an error. // If the Status is StatusInvalid, the returned error is of type *AuthorizationError. func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { - sleep := sleeper(ctx) for { - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } - if res.StatusCode >= 400 && res.StatusCode <= 499 { - // Non-retriable error. For instance, Let's Encrypt may return 404 Not Found - // when requesting an expired authorization. - defer res.Body.Close() - return nil, responseError(res) - } - retry := res.Header.Get("Retry-After") - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - res.Body.Close() - if err := sleep(retry, 1); err != nil { - return nil, err - } - continue - } var raw wireAuthz err = json.NewDecoder(res.Body).Decode(&raw) res.Body.Close() - if err != nil { - if err := sleep(retry, 0); err != nil { - return nil, err - } - continue - } - if raw.Status == StatusValid { + switch { + case err != nil: + // Skip and retry. + case raw.Status == StatusValid: return raw.authorization(url), nil - } - if raw.Status == StatusInvalid { + case raw.Status == StatusInvalid: return nil, raw.error(url) } - if err := sleep(retry, 0); err != nil { - return nil, err + + // Exponential backoff is implemented in c.get above. + // This is just to prevent continuously hitting the CA + // while waiting for a final authorization status. + d := retryAfter(res.Header.Get("Retry-After")) + if d == 0 { + // Given that the fastest challenges TLS-SNI and HTTP-01 + // require a CA to make at least 1 network round trip + // and most likely persist a challenge state, + // this default delay seems reasonable. + d = time.Second + } + t := time.NewTimer(d) + select { + case <-ctx.Done(): + t.Stop() + return nil, ctx.Err() + case <-t.C: + // Retry. } } } @@ -452,14 +450,11 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat // // A client typically polls a challenge status using this method. func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - return nil, responseError(res) - } v := wireChallenge{URI: url} if err := json.NewDecoder(res.Body).Decode(&v); err != nil { return nil, fmt.Errorf("acme: invalid response: %v", err) @@ -486,16 +481,14 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error Type: chal.Type, Auth: auth, } - res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req) + res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus( + http.StatusOK, // according to the spec + http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md) + )) if err != nil { return nil, err } defer res.Body.Close() - // Note: the protocol specifies 200 as the expected response code, but - // letsencrypt seems to be returning 202. - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - return nil, responseError(res) - } var v wireChallenge if err := json.NewDecoder(res.Body).Decode(&v); err != nil { @@ -552,7 +545,7 @@ func (c *Client) HTTP01ChallengePath(token string) string { // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. // // The returned certificate is valid for the next 24 hours and must be presented only when -// the server name of the client hello matches exactly the returned name value. +// the server name of the TLS ClientHello matches exactly the returned name value. func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { ka, err := keyAuth(c.Key.Public(), token) if err != nil { @@ -579,7 +572,7 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. // // The returned certificate is valid for the next 24 hours and must be presented only when -// the server name in the client hello matches exactly the returned name value. +// the server name in the TLS ClientHello matches exactly the returned name value. func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { b := sha256.Sum256([]byte(token)) h := hex.EncodeToString(b[:]) @@ -600,6 +593,52 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tl return cert, sanA, nil } +// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response. +// Servers can present the certificate to validate the challenge and prove control +// over a domain name. For more details on TLS-ALPN-01 see +// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3 +// +// The token argument is a Challenge.Token value. +// If a WithKey option is provided, its private part signs the returned cert, +// and the public part is used to specify the signee. +// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. +// +// The returned certificate is valid for the next 24 hours and must be presented only when +// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol +// has been specified. +func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) { + ka, err := keyAuth(c.Key.Public(), token) + if err != nil { + return tls.Certificate{}, err + } + shasum := sha256.Sum256([]byte(ka)) + extValue, err := asn1.Marshal(shasum[:]) + if err != nil { + return tls.Certificate{}, err + } + acmeExtension := pkix.Extension{ + Id: idPeACMEIdentifierV1, + Critical: true, + Value: extValue, + } + + tmpl := defaultTLSChallengeCertTemplate() + + var newOpt []CertOption + for _, o := range opt { + switch o := o.(type) { + case *certOptTemplate: + t := *(*x509.Certificate)(o) // shallow copy is ok + tmpl = &t + default: + newOpt = append(newOpt, o) + } + } + tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension) + newOpt = append(newOpt, WithTemplate(tmpl)) + return tlsChallengeCert([]string{domain}, newOpt) +} + // doReg sends all types of registration requests. // The type of request is identified by typ argument, which is a "resource" // in the ACME spec terms. @@ -619,14 +658,15 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun req.Contact = acct.Contact req.Agreement = acct.AgreedTerms } - res, err := c.retryPostJWS(ctx, c.Key, url, req) + res, err := c.post(ctx, c.Key, url, req, wantStatus( + http.StatusOK, // updates and deletes + http.StatusCreated, // new account creation + http.StatusAccepted, // Let's Encrypt divergent implementation + )) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode < 200 || res.StatusCode > 299 { - return nil, responseError(res) - } var v struct { Contact []string @@ -656,59 +696,6 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun }, nil } -// retryPostJWS will retry calls to postJWS if there is a badNonce error, -// clearing the stored nonces after each error. -// If the response was 4XX-5XX, then responseError is called on the body, -// the body is closed, and the error returned. -func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) { - sleep := sleeper(ctx) - for { - res, err := c.postJWS(ctx, key, url, body) - if err != nil { - return nil, err - } - // handle errors 4XX-5XX with responseError - if res.StatusCode >= 400 && res.StatusCode <= 599 { - err := responseError(res) - res.Body.Close() - // according to spec badNonce is urn:ietf:params:acme:error:badNonce - // however, acme servers in the wild return their version of the error - // https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4 - if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") { - // clear any nonces that we might've stored that might now be - // considered bad - c.clearNonces() - retry := res.Header.Get("Retry-After") - if err := sleep(retry, 1); err != nil { - return nil, err - } - continue - } - return nil, err - } - return res, nil - } -} - -// postJWS signs the body with the given key and POSTs it to the provided url. -// The body argument must be JSON-serializable. -func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) { - nonce, err := c.popNonce(ctx, url) - if err != nil { - return nil, err - } - b, err := jwsEncodeJSON(body, key, nonce) - if err != nil { - return nil, err - } - res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b)) - if err != nil { - return nil, err - } - c.addNonce(res.Header) - return res, nil -} - // popNonce returns a nonce value previously stored with c.addNonce // or fetches a fresh one from the given URL. func (c *Client) popNonce(ctx context.Context, url string) (string, error) { @@ -749,58 +736,12 @@ func (c *Client) addNonce(h http.Header) { c.nonces[v] = struct{}{} } -func (c *Client) httpClient() *http.Client { - if c.HTTPClient != nil { - return c.HTTPClient - } - return http.DefaultClient -} - -func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) { - req, err := http.NewRequest("GET", urlStr, nil) - if err != nil { - return nil, err - } - return c.do(ctx, req) -} - -func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", urlStr, nil) - if err != nil { - return nil, err - } - return c.do(ctx, req) -} - -func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", urlStr, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", contentType) - return c.do(ctx, req) -} - -func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) { - res, err := c.httpClient().Do(req.WithContext(ctx)) - if err != nil { - select { - case <-ctx.Done(): - // Prefer the unadorned context error. - // (The acme package had tests assuming this, previously from ctxhttp's - // behavior, predating net/http supporting contexts natively) - // TODO(bradfitz): reconsider this in the future. But for now this - // requires no test updates. - return nil, ctx.Err() - default: - return nil, err - } - } - return res, nil -} - func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) { - resp, err := c.head(ctx, url) + r, err := http.NewRequest("HEAD", url, nil) + if err != nil { + return "", err + } + resp, err := c.doNoRetry(ctx, r) if err != nil { return "", err } @@ -852,24 +793,6 @@ func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bo return cert, nil } -// responseError creates an error of Error type from resp. -func responseError(resp *http.Response) error { - // don't care if ReadAll returns an error: - // json.Unmarshal will fail in that case anyway - b, _ := ioutil.ReadAll(resp.Body) - e := &wireError{Status: resp.StatusCode} - if err := json.Unmarshal(b, e); err != nil { - // this is not a regular error response: - // populate detail with anything we received, - // e.Status will already contain HTTP response code value - e.Detail = string(b) - if e.Detail == "" { - e.Detail = resp.Status - } - } - return e.error(resp.Header) -} - // chainCert fetches CA certificate chain recursively by following "up" links. // Each recursive call increments the depth by 1, resulting in an error // if the recursion level reaches maxChainLen. @@ -880,14 +803,11 @@ func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte return nil, errors.New("acme: certificate chain is too deep") } - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return nil, responseError(res) - } b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) if err != nil { return nil, err @@ -932,65 +852,6 @@ func linkHeader(h http.Header, rel string) []string { return links } -// sleeper returns a function that accepts the Retry-After HTTP header value -// and an increment that's used with backoff to increasingly sleep on -// consecutive calls until the context is done. If the Retry-After header -// cannot be parsed, then backoff is used with a maximum sleep time of 10 -// seconds. -func sleeper(ctx context.Context) func(ra string, inc int) error { - var count int - return func(ra string, inc int) error { - count += inc - d := backoff(count, 10*time.Second) - d = retryAfter(ra, d) - wakeup := time.NewTimer(d) - defer wakeup.Stop() - select { - case <-ctx.Done(): - return ctx.Err() - case <-wakeup.C: - return nil - } - } -} - -// retryAfter parses a Retry-After HTTP header value, -// trying to convert v into an int (seconds) or use http.ParseTime otherwise. -// It returns d if v cannot be parsed. -func retryAfter(v string, d time.Duration) time.Duration { - if i, err := strconv.Atoi(v); err == nil { - return time.Duration(i) * time.Second - } - t, err := http.ParseTime(v) - if err != nil { - return d - } - return t.Sub(timeNow()) -} - -// backoff computes a duration after which an n+1 retry iteration should occur -// using truncated exponential backoff algorithm. -// -// The n argument is always bounded between 0 and 30. -// The max argument defines upper bound for the returned value. -func backoff(n int, max time.Duration) time.Duration { - if n < 0 { - n = 0 - } - if n > 30 { - n = 30 - } - var d time.Duration - if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil { - d = time.Duration(x.Int64()) * time.Millisecond - } - d += time.Duration(1< max { - return max - } - return d -} - // keyAuth generates a key authorization string for a given token. func keyAuth(pub crypto.PublicKey, token string) (string, error) { th, err := JWKThumbprint(pub) @@ -1000,15 +861,25 @@ func keyAuth(pub crypto.PublicKey, token string) (string, error) { return fmt.Sprintf("%s.%s", token, th), nil } +// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges. +func defaultTLSChallengeCertTemplate() *x509.Certificate { + return &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now(), + NotAfter: time.Now().Add(24 * time.Hour), + BasicConstraintsValid: true, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + } +} + // tlsChallengeCert creates a temporary certificate for TLS-SNI challenges // with the given SANs and auto-generated public/private key pair. // The Subject Common Name is set to the first SAN to aid debugging. // To create a cert with a custom key pair, specify WithKey option. func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { - var ( - key crypto.Signer - tmpl *x509.Certificate - ) + var key crypto.Signer + tmpl := defaultTLSChallengeCertTemplate() for _, o := range opt { switch o := o.(type) { case *certOptKey: @@ -1017,7 +888,7 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { } key = o.key case *certOptTemplate: - var t = *(*x509.Certificate)(o) // shallow copy is ok + t := *(*x509.Certificate)(o) // shallow copy is ok tmpl = &t default: // package's fault, if we let this happen: @@ -1030,16 +901,6 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { return tls.Certificate{}, err } } - if tmpl == nil { - tmpl = &x509.Certificate{ - SerialNumber: big.NewInt(1), - NotBefore: time.Now(), - NotAfter: time.Now().Add(24 * time.Hour), - BasicConstraintsValid: true, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - } - } tmpl.DNSNames = san if len(san) > 0 { tmpl.Subject.CommonName = san[0] diff --git a/vendor/golang.org/x/crypto/acme/acme_test.go b/vendor/golang.org/x/crypto/acme/acme_test.go index 63cb79b9..ef1fe478 100644 --- a/vendor/golang.org/x/crypto/acme/acme_test.go +++ b/vendor/golang.org/x/crypto/acme/acme_test.go @@ -13,9 +13,9 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/base64" + "encoding/hex" "encoding/json" "fmt" - "io/ioutil" "math/big" "net/http" "net/http/httptest" @@ -485,88 +485,37 @@ func TestGetAuthorization(t *testing.T) { } func TestWaitAuthorization(t *testing.T) { - var count int - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - count++ - w.Header().Set("Retry-After", "0") - if count > 1 { - fmt.Fprintf(w, `{"status":"valid"}`) - return + t.Run("wait loop", func(t *testing.T) { + var count int + authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) { + count++ + w.Header().Set("Retry-After", "0") + if count > 1 { + fmt.Fprintf(w, `{"status":"valid"}`) + return + } + fmt.Fprintf(w, `{"status":"pending"}`) + }) + if err != nil { + t.Fatalf("non-nil error: %v", err) } - fmt.Fprintf(w, `{"status":"pending"}`) - })) - defer ts.Close() - - type res struct { - authz *Authorization - err error - } - done := make(chan res) - defer close(done) - go func() { - var client Client - a, err := client.WaitAuthorization(context.Background(), ts.URL) - done <- res{a, err} - }() - - select { - case <-time.After(5 * time.Second): - t.Fatal("WaitAuthz took too long to return") - case res := <-done: - if res.err != nil { - t.Fatalf("res.err = %v", res.err) - } - if res.authz == nil { - t.Fatal("res.authz is nil") - } - } -} - -func TestWaitAuthorizationInvalid(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{"status":"invalid"}`) - })) - defer ts.Close() - - res := make(chan error) - defer close(res) - go func() { - var client Client - _, err := client.WaitAuthorization(context.Background(), ts.URL) - res <- err - }() - - select { - case <-time.After(3 * time.Second): - t.Fatal("WaitAuthz took too long to return") - case err := <-res: - if err == nil { - t.Error("err is nil") + if authz == nil { + t.Fatal("authz is nil") } + }) + t.Run("invalid status", func(t *testing.T) { + _, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, `{"status":"invalid"}`) + }) if _, ok := err.(*AuthorizationError); !ok { - t.Errorf("err is %T; want *AuthorizationError", err) + t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err) } - } -} - -func TestWaitAuthorizationClientError(t *testing.T) { - const code = http.StatusBadRequest - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(code) - })) - defer ts.Close() - - ch := make(chan error, 1) - go func() { - var client Client - _, err := client.WaitAuthorization(context.Background(), ts.URL) - ch <- err - }() - - select { - case <-time.After(3 * time.Second): - t.Fatal("WaitAuthz took too long to return") - case err := <-ch: + }) + t.Run("non-retriable error", func(t *testing.T) { + const code = http.StatusBadRequest + _, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(code) + }) res, ok := err.(*Error) if !ok { t.Fatalf("err is %v (%T); want a non-nil *Error", err, err) @@ -574,34 +523,60 @@ func TestWaitAuthorizationClientError(t *testing.T) { if res.StatusCode != code { t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code) } + }) + for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} { + t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) { + var count int + authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) { + count++ + w.Header().Set("Retry-After", "0") + if count > 1 { + fmt.Fprintf(w, `{"status":"valid"}`) + return + } + w.WriteHeader(code) + }) + if err != nil { + t.Fatalf("non-nil error: %v", err) + } + if authz == nil { + t.Fatal("authz is nil") + } + }) } -} - -func TestWaitAuthorizationCancel(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Retry-After", "60") - fmt.Fprintf(w, `{"status":"pending"}`) - })) - defer ts.Close() - - res := make(chan error) - defer close(res) - go func() { - var client Client + t.Run("context cancel", func(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) defer cancel() - _, err := client.WaitAuthorization(ctx, ts.URL) - res <- err - }() - - select { - case <-time.After(time.Second): - t.Fatal("WaitAuthz took too long to return") - case err := <-res: + _, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Retry-After", "60") + fmt.Fprintf(w, `{"status":"pending"}`) + }) if err == nil { t.Error("err is nil") } + }) +} +func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) { + t.Helper() + ts := httptest.NewServer(h) + defer ts.Close() + type res struct { + authz *Authorization + err error } + ch := make(chan res, 1) + go func() { + var client Client + a, err := client.WaitAuthorization(ctx, ts.URL) + ch <- res{a, err} + }() + select { + case <-time.After(3 * time.Second): + t.Fatal("WaitAuthorization took too long to return") + case v := <-ch: + return v.authz, v.err + } + panic("runWaitAuthorization: out of select") } func TestRevokeAuthorization(t *testing.T) { @@ -628,7 +603,7 @@ func TestRevokeAuthorization(t *testing.T) { t.Errorf("req.Delete is false") } case "/2": - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) } })) defer ts.Close() @@ -849,7 +824,7 @@ func TestFetchCertRetry(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if count < 1 { w.Header().Set("Retry-After", "0") - w.WriteHeader(http.StatusAccepted) + w.WriteHeader(http.StatusTooManyRequests) count++ return } @@ -1096,44 +1071,6 @@ func TestNonce_postJWS(t *testing.T) { } } -func TestRetryPostJWS(t *testing.T) { - var count int - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - count++ - w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count)) - if r.Method == "HEAD" { - // We expect the client to do 2 head requests to fetch - // nonces, one to start and another after getting badNonce - return - } - - head, err := decodeJWSHead(r) - if err != nil { - t.Errorf("decodeJWSHead: %v", err) - } else if head.Nonce == "" { - t.Error("head.Nonce is empty") - } else if head.Nonce == "nonce1" { - // return a badNonce error to force the call to retry - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`)) - return - } - // Make client.Authorize happy; we're not testing its result. - w.WriteHeader(http.StatusCreated) - w.Write([]byte(`{"status":"valid"}`)) - })) - defer ts.Close() - - client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}} - // This call will fail with badNonce, causing a retry - if _, err := client.Authorize(context.Background(), "example.com"); err != nil { - t.Errorf("client.Authorize 1: %v", err) - } - if count != 4 { - t.Errorf("total requests count: %d; want 4", count) - } -} - func TestLinkHeader(t *testing.T) { h := http.Header{"Link": { `;rel="next"`, @@ -1157,37 +1094,6 @@ func TestLinkHeader(t *testing.T) { } } -func TestErrorResponse(t *testing.T) { - s := `{ - "status": 400, - "type": "urn:acme:error:xxx", - "detail": "text" - }` - res := &http.Response{ - StatusCode: 400, - Status: "400 Bad Request", - Body: ioutil.NopCloser(strings.NewReader(s)), - Header: http.Header{"X-Foo": {"bar"}}, - } - err := responseError(res) - v, ok := err.(*Error) - if !ok { - t.Fatalf("err = %+v (%T); want *Error type", err, err) - } - if v.StatusCode != 400 { - t.Errorf("v.StatusCode = %v; want 400", v.StatusCode) - } - if v.ProblemType != "urn:acme:error:xxx" { - t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType) - } - if v.Detail != "text" { - t.Errorf("v.Detail = %q; want text", v.Detail) - } - if !reflect.DeepEqual(v.Header, res.Header) { - t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header) - } -} - func TestTLSSNI01ChallengeCert(t *testing.T) { const ( token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA" @@ -1255,6 +1161,58 @@ func TestTLSSNI02ChallengeCert(t *testing.T) { } } +func TestTLSALPN01ChallengeCert(t *testing.T) { + const ( + token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA" + keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint + // echo -n | shasum -a 256 + h = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0" + domain = "example.com" + ) + + extValue, err := hex.DecodeString(h) + if err != nil { + t.Fatal(err) + } + + client := &Client{Key: testKeyEC} + tlscert, err := client.TLSALPN01ChallengeCert(token, domain) + if err != nil { + t.Fatal(err) + } + + if n := len(tlscert.Certificate); n != 1 { + t.Fatalf("len(tlscert.Certificate) = %d; want 1", n) + } + cert, err := x509.ParseCertificate(tlscert.Certificate[0]) + if err != nil { + t.Fatal(err) + } + names := []string{domain} + if !reflect.DeepEqual(cert.DNSNames, names) { + t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names) + } + if cn := cert.Subject.CommonName; cn != domain { + t.Errorf("CommonName = %q; want %q", cn, domain) + } + acmeExts := []pkix.Extension{} + for _, ext := range cert.Extensions { + if idPeACMEIdentifierV1.Equal(ext.Id) { + acmeExts = append(acmeExts, ext) + } + } + if len(acmeExts) != 1 { + t.Errorf("acmeExts = %v; want exactly one", acmeExts) + } + if !acmeExts[0].Critical { + t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical) + } + if bytes.Compare(acmeExts[0].Value, extValue) != 0 { + t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue) + } + +} + func TestTLSChallengeCertOpt(t *testing.T) { key, err := rsa.GenerateKey(rand.Reader, 512) if err != nil { @@ -1353,28 +1311,3 @@ func TestDNS01ChallengeRecord(t *testing.T) { t.Errorf("val = %q; want %q", val, value) } } - -func TestBackoff(t *testing.T) { - tt := []struct{ min, max time.Duration }{ - {time.Second, 2 * time.Second}, - {2 * time.Second, 3 * time.Second}, - {4 * time.Second, 5 * time.Second}, - {8 * time.Second, 9 * time.Second}, - } - for i, test := range tt { - d := backoff(i, time.Minute) - if d < test.min || test.max < d { - t.Errorf("%d: d = %v; want between %v and %v", i, d, test.min, test.max) - } - } - - min, max := time.Second, 2*time.Second - if d := backoff(-1, time.Minute); d < min || max < d { - t.Errorf("d = %v; want between %v and %v", d, min, max) - } - - bound := 10 * time.Second - if d := backoff(100, bound); d != bound { - t.Errorf("d = %v; want %v", d, bound) - } -} diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go index 263b2913..a50d9bfc 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -44,7 +44,7 @@ var createCertRetryAfter = time.Minute var pseudoRand *lockedMathRand func init() { - src := mathrand.NewSource(timeNow().UnixNano()) + src := mathrand.NewSource(time.Now().UnixNano()) pseudoRand = &lockedMathRand{rnd: mathrand.New(src)} } @@ -69,7 +69,7 @@ func HostWhitelist(hosts ...string) HostPolicy { } return func(_ context.Context, host string) error { if !whitelist[host] { - return errors.New("acme/autocert: host not configured") + return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host) } return nil } @@ -81,9 +81,9 @@ func defaultHostPolicy(context.Context, string) error { } // Manager is a stateful certificate manager built on top of acme.Client. -// It obtains and refreshes certificates automatically using "tls-sni-01", -// "tls-sni-02" and "http-01" challenge types, as well as providing them -// to a TLS server via tls.Config. +// It obtains and refreshes certificates automatically using "tls-alpn-01", +// "tls-sni-01", "tls-sni-02" and "http-01" challenge types, +// as well as providing them to a TLS server via tls.Config. // // You must specify a cache implementation, such as DirCache, // to reuse obtained certificates across program restarts. @@ -98,11 +98,11 @@ type Manager struct { // To always accept the terms, the callers can use AcceptTOS. Prompt func(tosURL string) bool - // Cache optionally stores and retrieves previously-obtained certificates. - // If nil, certs will only be cached for the lifetime of the Manager. + // Cache optionally stores and retrieves previously-obtained certificates + // and other state. If nil, certs will only be cached for the lifetime of + // the Manager. Multiple Managers can share the same Cache. // - // Manager passes the Cache certificates data encoded in PEM, with private/public - // parts combined in a single Cache.Put call, private key first. + // Using a persistent Cache, such as DirCache, is strongly recommended. Cache Cache // HostPolicy controls which domains the Manager will attempt @@ -127,8 +127,10 @@ type Manager struct { // Client is used to perform low-level operations, such as account registration // and requesting new certificates. + // // If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL - // directory endpoint and a newly-generated ECDSA P-256 key. + // as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is + // generated and, if Cache is not nil, stored in cache. // // Mutating the field after the first call of GetCertificate method will have no effect. Client *acme.Client @@ -140,22 +142,30 @@ type Manager struct { // If the Client's account key is already registered, Email is not used. Email string - // ForceRSA makes the Manager generate certificates with 2048-bit RSA keys. + // ForceRSA used to make the Manager generate RSA certificates. It is now ignored. // - // If false, a default is used. Currently the default - // is EC-based keys using the P-256 curve. + // Deprecated: the Manager will request the correct type of certificate based + // on what each client supports. ForceRSA bool + // ExtraExtensions are used when generating a new CSR (Certificate Request), + // thus allowing customization of the resulting certificate. + // For instance, TLS Feature Extension (RFC 7633) can be used + // to prevent an OCSP downgrade attack. + // + // The field value is passed to crypto/x509.CreateCertificateRequest + // in the template's ExtraExtensions field as is. + ExtraExtensions []pkix.Extension + clientMu sync.Mutex client *acme.Client // initialized by acmeClient method stateMu sync.Mutex - state map[string]*certState // keyed by domain name + state map[certKey]*certState // renewal tracks the set of domains currently running renewal timers. - // It is keyed by domain name. renewalMu sync.Mutex - renewal map[string]*domainRenewal + renewal map[certKey]*domainRenewal // tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens. tokensMu sync.RWMutex @@ -167,21 +177,60 @@ type Manager struct { // to be provisioned. // The entries are stored for the duration of the authorization flow. httpTokens map[string][]byte - // certTokens contains temporary certificates for tls-sni challenges + // certTokens contains temporary certificates for tls-sni and tls-alpn challenges // and is keyed by token domain name, which matches server name of ClientHello. - // Keys always have ".acme.invalid" suffix. + // Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names + // for tls-alpn. // The entries are stored for the duration of the authorization flow. certTokens map[string]*tls.Certificate + // nowFunc, if not nil, returns the current time. This may be set for + // testing purposes. + nowFunc func() time.Time +} + +// certKey is the key by which certificates are tracked in state, renewal and cache. +type certKey struct { + domain string // without trailing dot + isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA) + isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA +} + +func (c certKey) String() string { + if c.isToken { + return c.domain + "+token" + } + if c.isRSA { + return c.domain + "+rsa" + } + return c.domain +} + +// TLSConfig creates a new TLS config suitable for net/http.Server servers, +// supporting HTTP/2 and the tls-alpn-01 ACME challenge type. +func (m *Manager) TLSConfig() *tls.Config { + return &tls.Config{ + GetCertificate: m.GetCertificate, + NextProtos: []string{ + "h2", "http/1.1", // enable HTTP/2 + acme.ALPNProto, // enable tls-alpn ACME challenges + }, + } } // GetCertificate implements the tls.Config.GetCertificate hook. // It provides a TLS certificate for hello.ServerName host, including answering -// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored. +// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges. +// All other fields of hello are ignored. // // If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting // a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation. // The error is propagated back to the caller of GetCertificate and is user-visible. // This does not affect cached certs. See HostPolicy field description for more details. +// +// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will +// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler +// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers +// due to security issues in the ecosystem.) func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { if m.Prompt == nil { return nil, errors.New("acme/autocert: Manager.Prompt not set") @@ -194,7 +243,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, if !strings.Contains(strings.Trim(name, "."), ".") { return nil, errors.New("acme/autocert: server name component count invalid") } - if strings.ContainsAny(name, `/\`) { + if strings.ContainsAny(name, `+/\`) { return nil, errors.New("acme/autocert: server name contains invalid character") } @@ -203,14 +252,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() - // check whether this is a token cert requested for TLS-SNI challenge - if strings.HasSuffix(name, ".acme.invalid") { + // Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge. + if wantsTokenCert(hello) { m.tokensMu.RLock() defer m.tokensMu.RUnlock() + // It's ok to use the same token cert key for both tls-sni and tls-alpn + // because there's always at most 1 token cert per on-going domain authorization. + // See m.verify for details. if cert := m.certTokens[name]; cert != nil { return cert, nil } - if cert, err := m.cacheGet(ctx, name); err == nil { + if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil { return cert, nil } // TODO: cache error results? @@ -218,8 +270,11 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, } // regular domain - name = strings.TrimSuffix(name, ".") // golang.org/issue/18114 - cert, err := m.cert(ctx, name) + ck := certKey{ + domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114 + isRSA: !supportsECDSA(hello), + } + cert, err := m.cert(ctx, ck) if err == nil { return cert, nil } @@ -231,14 +286,71 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, if err := m.hostPolicy()(ctx, name); err != nil { return nil, err } - cert, err = m.createCert(ctx, name) + cert, err = m.createCert(ctx, ck) if err != nil { return nil, err } - m.cachePut(ctx, name, cert) + m.cachePut(ctx, ck, cert) return cert, nil } +// wantsTokenCert reports whether a TLS request with SNI is made by a CA server +// for a challenge verification. +func wantsTokenCert(hello *tls.ClientHelloInfo) bool { + // tls-alpn-01 + if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto { + return true + } + // tls-sni-xx + return strings.HasSuffix(hello.ServerName, ".acme.invalid") +} + +func supportsECDSA(hello *tls.ClientHelloInfo) bool { + // The "signature_algorithms" extension, if present, limits the key exchange + // algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1. + if hello.SignatureSchemes != nil { + ecdsaOK := false + schemeLoop: + for _, scheme := range hello.SignatureSchemes { + const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10 + switch scheme { + case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256, + tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512: + ecdsaOK = true + break schemeLoop + } + } + if !ecdsaOK { + return false + } + } + if hello.SupportedCurves != nil { + ecdsaOK := false + for _, curve := range hello.SupportedCurves { + if curve == tls.CurveP256 { + ecdsaOK = true + break + } + } + if !ecdsaOK { + return false + } + } + for _, suite := range hello.CipherSuites { + switch suite { + case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: + return true + } + } + return false +} + // HTTPHandler configures the Manager to provision ACME "http-01" challenge responses. // It returns an http.Handler that responds to the challenges and must be // running on port 80. If it receives a request that is not an ACME challenge, @@ -252,8 +364,8 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, // Because the fallback handler is run with unencrypted port 80 requests, // the fallback should not serve TLS-only requests. // -// If HTTPHandler is never called, the Manager will only use TLS SNI -// challenges for domain verification. +// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01" +// challenge for domain verification. func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler { m.tokensMu.Lock() defer m.tokensMu.Unlock() @@ -304,16 +416,16 @@ func stripPort(hostport string) string { // cert returns an existing certificate either from m.state or cache. // If a certificate is found in cache but not in m.state, the latter will be filled // with the cached value. -func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) { +func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) { m.stateMu.Lock() - if s, ok := m.state[name]; ok { + if s, ok := m.state[ck]; ok { m.stateMu.Unlock() s.RLock() defer s.RUnlock() return s.tlscert() } defer m.stateMu.Unlock() - cert, err := m.cacheGet(ctx, name) + cert, err := m.cacheGet(ctx, ck) if err != nil { return nil, err } @@ -322,25 +434,25 @@ func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, erro return nil, errors.New("acme/autocert: private key cannot sign") } if m.state == nil { - m.state = make(map[string]*certState) + m.state = make(map[certKey]*certState) } s := &certState{ key: signer, cert: cert.Certificate, leaf: cert.Leaf, } - m.state[name] = s - go m.renew(name, s.key, s.leaf.NotAfter) + m.state[ck] = s + go m.renew(ck, s.key, s.leaf.NotAfter) return cert, nil } // cacheGet always returns a valid certificate, or an error otherwise. -// If a cached certficate exists but is not valid, ErrCacheMiss is returned. -func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate, error) { +// If a cached certificate exists but is not valid, ErrCacheMiss is returned. +func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) { if m.Cache == nil { return nil, ErrCacheMiss } - data, err := m.Cache.Get(ctx, domain) + data, err := m.Cache.Get(ctx, ck.String()) if err != nil { return nil, err } @@ -371,7 +483,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate } // verify and create TLS cert - leaf, err := validCert(domain, pubDER, privKey) + leaf, err := validCert(ck, pubDER, privKey, m.now()) if err != nil { return nil, ErrCacheMiss } @@ -383,7 +495,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate return tlscert, nil } -func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error { +func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error { if m.Cache == nil { return nil } @@ -415,7 +527,7 @@ func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Cert } } - return m.Cache.Put(ctx, domain, buf.Bytes()) + return m.Cache.Put(ctx, ck.String(), buf.Bytes()) } func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error { @@ -432,9 +544,9 @@ func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error { // // If the domain is already being verified, it waits for the existing verification to complete. // Either way, createCert blocks for the duration of the whole process. -func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) { +func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) { // TODO: maybe rewrite this whole piece using sync.Once - state, err := m.certState(domain) + state, err := m.certState(ck) if err != nil { return nil, err } @@ -452,44 +564,44 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica defer state.Unlock() state.locked = false - der, leaf, err := m.authorizedCert(ctx, state.key, domain) + der, leaf, err := m.authorizedCert(ctx, state.key, ck) if err != nil { // Remove the failed state after some time, // making the manager call createCert again on the following TLS hello. time.AfterFunc(createCertRetryAfter, func() { - defer testDidRemoveState(domain) + defer testDidRemoveState(ck) m.stateMu.Lock() defer m.stateMu.Unlock() // Verify the state hasn't changed and it's still invalid // before deleting. - s, ok := m.state[domain] + s, ok := m.state[ck] if !ok { return } - if _, err := validCert(domain, s.cert, s.key); err == nil { + if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil { return } - delete(m.state, domain) + delete(m.state, ck) }) return nil, err } state.cert = der state.leaf = leaf - go m.renew(domain, state.key, state.leaf.NotAfter) + go m.renew(ck, state.key, state.leaf.NotAfter) return state.tlscert() } // certState returns a new or existing certState. // If a new certState is returned, state.exist is false and the state is locked. // The returned error is non-nil only in the case where a new state could not be created. -func (m *Manager) certState(domain string) (*certState, error) { +func (m *Manager) certState(ck certKey) (*certState, error) { m.stateMu.Lock() defer m.stateMu.Unlock() if m.state == nil { - m.state = make(map[string]*certState) + m.state = make(map[certKey]*certState) } // existing state - if state, ok := m.state[domain]; ok { + if state, ok := m.state[ck]; ok { return state, nil } @@ -498,7 +610,7 @@ func (m *Manager) certState(domain string) (*certState, error) { err error key crypto.Signer ) - if m.ForceRSA { + if ck.isRSA { key, err = rsa.GenerateKey(rand.Reader, 2048) } else { key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -512,22 +624,22 @@ func (m *Manager) certState(domain string) (*certState, error) { locked: true, } state.Lock() // will be unlocked by m.certState caller - m.state[domain] = state + m.state[ck] = state return state, nil } // authorizedCert starts the domain ownership verification process and requests a new cert upon success. // The key argument is the certificate private key. -func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) { +func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) { client, err := m.acmeClient(ctx) if err != nil { return nil, nil, err } - if err := m.verify(ctx, client, domain); err != nil { + if err := m.verify(ctx, client, ck.domain); err != nil { return nil, nil, err } - csr, err := certRequest(key, domain) + csr, err := certRequest(key, ck.domain, m.ExtraExtensions) if err != nil { return nil, nil, err } @@ -535,25 +647,55 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain if err != nil { return nil, nil, err } - leaf, err = validCert(domain, der, key) + leaf, err = validCert(ck, der, key, m.now()) if err != nil { return nil, nil, err } return der, leaf, nil } +// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice. +// It ignores revocation errors. +func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) { + client, err := m.acmeClient(ctx) + if err != nil { + return + } + for _, u := range uri { + client.RevokeAuthorization(ctx, u) + } +} + // verify runs the identifier (domain) authorization flow // using each applicable ACME challenge type. func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error { // The list of challenge types we'll try to fulfill // in this specific order. - challengeTypes := []string{"tls-sni-02", "tls-sni-01"} + challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"} m.tokensMu.RLock() if m.tryHTTP01 { challengeTypes = append(challengeTypes, "http-01") } m.tokensMu.RUnlock() + // Keep track of pending authzs and revoke the ones that did not validate. + pendingAuthzs := make(map[string]bool) + defer func() { + var uri []string + for k, pending := range pendingAuthzs { + if pending { + uri = append(uri, k) + } + } + if len(uri) > 0 { + // Use "detached" background context. + // The revocations need not happen in the current verification flow. + go m.revokePendingAuthz(context.Background(), uri) + } + }() + + // errs accumulates challenge failure errors, printed if all fail + errs := make(map[*acme.Challenge]error) var nextTyp int // challengeType index of the next challenge type to try for { // Start domain authorization and get the challenge. @@ -570,6 +712,8 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI) } + pendingAuthzs[authz.URI] = true + // Pick the next preferred challenge. var chal *acme.Challenge for chal == nil && nextTyp < len(challengeTypes) { @@ -577,28 +721,44 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string nextTyp++ } if chal == nil { - return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes) + errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain) + for chal, err := range errs { + errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err) + } + return errors.New(errorMsg) } - cleanup, err := m.fulfill(ctx, client, chal) + cleanup, err := m.fulfill(ctx, client, chal, domain) if err != nil { + errs[chal] = err continue } defer cleanup() if _, err := client.Accept(ctx, chal); err != nil { + errs[chal] = err continue } // A challenge is fulfilled and accepted: wait for the CA to validate. - if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil { - return nil + if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil { + errs[chal] = err + continue } + delete(pendingAuthzs, authz.URI) + return nil } } // fulfill provisions a response to the challenge chal. // The cleanup is non-nil only if provisioning succeeded. -func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) { +func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) { switch chal.Type { + case "tls-alpn-01": + cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain) + if err != nil { + return nil, err + } + m.putCertToken(ctx, domain, &cert) + return func() { go m.deleteCertToken(domain) }, nil case "tls-sni-01": cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) if err != nil { @@ -634,8 +794,8 @@ func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { return nil } -// putCertToken stores the cert under the named key in both m.certTokens map -// and m.Cache. +// putCertToken stores the token certificate with the specified name +// in both m.certTokens map and m.Cache. func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) { m.tokensMu.Lock() defer m.tokensMu.Unlock() @@ -643,17 +803,18 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi m.certTokens = make(map[string]*tls.Certificate) } m.certTokens[name] = cert - m.cachePut(ctx, name, cert) + m.cachePut(ctx, certKey{domain: name, isToken: true}, cert) } -// deleteCertToken removes the token certificate for the specified domain name +// deleteCertToken removes the token certificate with the specified name // from both m.certTokens map and m.Cache. func (m *Manager) deleteCertToken(name string) { m.tokensMu.Lock() defer m.tokensMu.Unlock() delete(m.certTokens, name) if m.Cache != nil { - m.Cache.Delete(context.Background(), name) + ck := certKey{domain: name, isToken: true} + m.Cache.Delete(context.Background(), ck.String()) } } @@ -704,7 +865,7 @@ func (m *Manager) deleteHTTPToken(tokenPath string) { // httpTokenCacheKey returns a key at which an http-01 token value may be stored // in the Manager's optional Cache. func httpTokenCacheKey(tokenPath string) string { - return "http-01-" + path.Base(tokenPath) + return path.Base(tokenPath) + "+http-01" } // renew starts a cert renewal timer loop, one per domain. @@ -715,18 +876,18 @@ func httpTokenCacheKey(tokenPath string) string { // // The key argument is a certificate private key. // The exp argument is the cert expiration time (NotAfter). -func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) { +func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) { m.renewalMu.Lock() defer m.renewalMu.Unlock() - if m.renewal[domain] != nil { + if m.renewal[ck] != nil { // another goroutine is already on it return } if m.renewal == nil { - m.renewal = make(map[string]*domainRenewal) + m.renewal = make(map[certKey]*domainRenewal) } - dr := &domainRenewal{m: m, domain: domain, key: key} - m.renewal[domain] = dr + dr := &domainRenewal{m: m, ck: ck, key: key} + m.renewal[ck] = dr dr.start(exp) } @@ -742,7 +903,10 @@ func (m *Manager) stopRenew() { } func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) { - const keyName = "acme_account.key" + const keyName = "acme_account+key" + + // Previous versions of autocert stored the value under a different key. + const legacyKeyName = "acme_account.key" genKey := func() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -753,6 +917,9 @@ func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) { } data, err := m.Cache.Get(ctx, keyName) + if err == ErrCacheMiss { + data, err = m.Cache.Get(ctx, legacyKeyName) + } if err == ErrCacheMiss { key, err := genKey() if err != nil { @@ -824,6 +991,13 @@ func (m *Manager) renewBefore() time.Duration { return 720 * time.Hour // 30 days } +func (m *Manager) now() time.Time { + if m.nowFunc != nil { + return m.nowFunc() + } + return time.Now() +} + // certState is ready when its mutex is unlocked for reading. type certState struct { sync.RWMutex @@ -849,12 +1023,12 @@ func (s *certState) tlscert() (*tls.Certificate, error) { }, nil } -// certRequest creates a certificate request for the given common name cn -// and optional SANs. -func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) { +// certRequest generates a CSR for the given common name cn and optional SANs. +func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) { req := &x509.CertificateRequest{ - Subject: pkix.Name{CommonName: cn}, - DNSNames: san, + Subject: pkix.Name{CommonName: cn}, + DNSNames: san, + ExtraExtensions: ext, } return x509.CreateCertificateRequest(rand.Reader, req, key) } @@ -885,12 +1059,12 @@ func parsePrivateKey(der []byte) (crypto.Signer, error) { return nil, errors.New("acme/autocert: failed to parse private key") } -// validCert parses a cert chain provided as der argument and verifies the leaf, der[0], -// corresponds to the private key, as well as the domain match and expiration dates. -// It doesn't do any revocation checking. +// validCert parses a cert chain provided as der argument and verifies the leaf and der[0] +// correspond to the private key, the domain and key type match, and expiration dates +// are valid. It doesn't do any revocation checking. // // The returned value is the verified leaf cert. -func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) { +func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) { // parse public part(s) var n int for _, b := range der { @@ -902,22 +1076,21 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi n += copy(pub[n:], b) } x509Cert, err := x509.ParseCertificates(pub) - if len(x509Cert) == 0 { + if err != nil || len(x509Cert) == 0 { return nil, errors.New("acme/autocert: no public key found") } // verify the leaf is not expired and matches the domain name leaf = x509Cert[0] - now := timeNow() if now.Before(leaf.NotBefore) { return nil, errors.New("acme/autocert: certificate is not valid yet") } if now.After(leaf.NotAfter) { return nil, errors.New("acme/autocert: expired certificate") } - if err := leaf.VerifyHostname(domain); err != nil { + if err := leaf.VerifyHostname(ck.domain); err != nil { return nil, err } - // ensure the leaf corresponds to the private key + // ensure the leaf corresponds to the private key and matches the certKey type switch pub := leaf.PublicKey.(type) { case *rsa.PublicKey: prv, ok := key.(*rsa.PrivateKey) @@ -927,6 +1100,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi if pub.N.Cmp(prv.N) != 0 { return nil, errors.New("acme/autocert: private key does not match public key") } + if !ck.isRSA && !ck.isToken { + return nil, errors.New("acme/autocert: key type does not match expected value") + } case *ecdsa.PublicKey: prv, ok := key.(*ecdsa.PrivateKey) if !ok { @@ -935,6 +1111,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 { return nil, errors.New("acme/autocert: private key does not match public key") } + if ck.isRSA && !ck.isToken { + return nil, errors.New("acme/autocert: key type does not match expected value") + } default: return nil, errors.New("acme/autocert: unknown public key algorithm") } @@ -955,8 +1134,6 @@ func (r *lockedMathRand) int63n(max int64) int64 { // For easier testing. var ( - timeNow = time.Now - // Called when a state is removed. - testDidRemoveState = func(domain string) {} + testDidRemoveState = func(certKey) {} ) diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go index 2da1912e..95e12e16 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go @@ -5,6 +5,7 @@ package autocert import ( + "bytes" "context" "crypto" "crypto/ecdsa" @@ -14,11 +15,13 @@ import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" + "encoding/asn1" "encoding/base64" "encoding/json" "fmt" "html/template" "io" + "io/ioutil" "math/big" "net/http" "net/http/httptest" @@ -29,6 +32,13 @@ import ( "time" "golang.org/x/crypto/acme" + "golang.org/x/crypto/acme/autocert/internal/acmetest" +) + +var ( + exampleDomain = "example.org" + exampleCertKey = certKey{domain: exampleDomain} + exampleCertKeyRSA = certKey{domain: exampleDomain, isRSA: true} ) var discoTmpl = template.Must(template.New("disco").Parse(`{ @@ -64,6 +74,7 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{ }`)) type memCache struct { + t *testing.T mu sync.Mutex keyData map[string][]byte } @@ -79,7 +90,26 @@ func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) { return v, nil } +// filenameSafe returns whether all characters in s are printable ASCII +// and safe to use in a filename on most filesystems. +func filenameSafe(s string) bool { + for _, c := range s { + if c < 0x20 || c > 0x7E { + return false + } + switch c { + case '\\', '/', ':', '*', '?', '"', '<', '>', '|': + return false + } + } + return true +} + func (m *memCache) Put(ctx context.Context, key string, data []byte) error { + if !filenameSafe(key) { + m.t.Errorf("invalid characters in cache key %q", key) + } + m.mu.Lock() defer m.mu.Unlock() @@ -95,12 +125,29 @@ func (m *memCache) Delete(ctx context.Context, key string) error { return nil } -func newMemCache() *memCache { +func newMemCache(t *testing.T) *memCache { return &memCache{ + t: t, keyData: make(map[string][]byte), } } +func (m *memCache) numCerts() int { + m.mu.Lock() + defer m.mu.Unlock() + + res := 0 + for key := range m.keyData { + if strings.HasSuffix(key, "+token") || + strings.HasSuffix(key, "+key") || + strings.HasSuffix(key, "+http-01") { + continue + } + res++ + } + return res +} + func dummyCert(pub interface{}, san ...string) ([]byte, error) { return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...) } @@ -137,53 +184,58 @@ func decodePayload(v interface{}, r io.Reader) error { return json.Unmarshal(payload, v) } +func clientHelloInfo(sni string, ecdsaSupport bool) *tls.ClientHelloInfo { + hello := &tls.ClientHelloInfo{ + ServerName: sni, + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}, + } + if ecdsaSupport { + hello.CipherSuites = append(hello.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305) + } + return hello +} + func TestGetCertificate(t *testing.T) { man := &Manager{Prompt: AcceptTOS} defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: "example.org"} + hello := clientHelloInfo("example.org", true) testGetCertificate(t, man, "example.org", hello) } func TestGetCertificate_trailingDot(t *testing.T) { man := &Manager{Prompt: AcceptTOS} defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: "example.org."} + hello := clientHelloInfo("example.org.", true) testGetCertificate(t, man, "example.org", hello) } func TestGetCertificate_ForceRSA(t *testing.T) { man := &Manager{ Prompt: AcceptTOS, - Cache: newMemCache(), + Cache: newMemCache(t), ForceRSA: true, } defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: "example.org"} - testGetCertificate(t, man, "example.org", hello) + hello := clientHelloInfo(exampleDomain, true) + testGetCertificate(t, man, exampleDomain, hello) - cert, err := man.cacheGet(context.Background(), "example.org") + // ForceRSA was deprecated and is now ignored. + cert, err := man.cacheGet(context.Background(), exampleCertKey) if err != nil { t.Fatalf("man.cacheGet: %v", err) } - if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok { - t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey) + if _, ok := cert.PrivateKey.(*ecdsa.PrivateKey); !ok { + t.Errorf("cert.PrivateKey is %T; want *ecdsa.PrivateKey", cert.PrivateKey) } } func TestGetCertificate_nilPrompt(t *testing.T) { man := &Manager{} defer man.stopRenew() - url, finish := startACMEServerStub(t, man, "example.org") + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org") defer finish() - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } - man.Client = &acme.Client{ - Key: key, - DirectoryURL: url, - } - hello := &tls.ClientHelloInfo{ServerName: "example.org"} + man.Client = &acme.Client{DirectoryURL: url} + hello := clientHelloInfo("example.org", true) if _, err := man.GetCertificate(hello); err == nil { t.Error("got certificate for example.org; wanted error") } @@ -197,7 +249,7 @@ func TestGetCertificate_expiredCache(t *testing.T) { } tmpl := &x509.Certificate{ SerialNumber: big.NewInt(1), - Subject: pkix.Name{CommonName: "example.org"}, + Subject: pkix.Name{CommonName: exampleDomain}, NotAfter: time.Now(), } pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk) @@ -209,16 +261,16 @@ func TestGetCertificate_expiredCache(t *testing.T) { PrivateKey: pk, } - man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()} + man := &Manager{Prompt: AcceptTOS, Cache: newMemCache(t)} defer man.stopRenew() - if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil { + if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil { t.Fatalf("man.cachePut: %v", err) } // The expired cached cert should trigger a new cert issuance // and return without an error. - hello := &tls.ClientHelloInfo{ServerName: "example.org"} - testGetCertificate(t, man, "example.org", hello) + hello := clientHelloInfo(exampleDomain, true) + testGetCertificate(t, man, exampleDomain, hello) } func TestGetCertificate_failedAttempt(t *testing.T) { @@ -227,7 +279,6 @@ func TestGetCertificate_failedAttempt(t *testing.T) { })) defer ts.Close() - const example = "example.org" d := createCertRetryAfter f := testDidRemoveState defer func() { @@ -236,51 +287,168 @@ func TestGetCertificate_failedAttempt(t *testing.T) { }() createCertRetryAfter = 0 done := make(chan struct{}) - testDidRemoveState = func(domain string) { - if domain != example { - t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example) + testDidRemoveState = func(ck certKey) { + if ck != exampleCertKey { + t.Errorf("testDidRemoveState: domain = %v; want %v", ck, exampleCertKey) } close(done) } - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } man := &Manager{ Prompt: AcceptTOS, Client: &acme.Client{ - Key: key, DirectoryURL: ts.URL, }, } defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: example} + hello := clientHelloInfo(exampleDomain, true) if _, err := man.GetCertificate(hello); err == nil { t.Error("GetCertificate: err is nil") } select { case <-time.After(5 * time.Second): - t.Errorf("took too long to remove the %q state", example) + t.Errorf("took too long to remove the %q state", exampleCertKey) case <-done: man.stateMu.Lock() defer man.stateMu.Unlock() - if v, exist := man.state[example]; exist { - t.Errorf("state exists for %q: %+v", example, v) + if v, exist := man.state[exampleCertKey]; exist { + t.Errorf("state exists for %v: %+v", exampleCertKey, v) } } } +// testGetCertificate_tokenCache tests the fallback of token certificate fetches +// to cache when Manager.certTokens misses. ecdsaSupport refers to the CA when +// verifying the certificate token. +func testGetCertificate_tokenCache(t *testing.T, ecdsaSupport bool) { + man1 := &Manager{ + Cache: newMemCache(t), + Prompt: AcceptTOS, + } + defer man1.stopRenew() + man2 := &Manager{ + Cache: man1.Cache, + Prompt: AcceptTOS, + } + defer man2.stopRenew() + + // Send the verification request to a different Manager from the one that + // initiated the authorization, when they share caches. + url, finish := startACMEServerStub(t, getCertificateFromManager(man2, ecdsaSupport), "example.org") + defer finish() + man1.Client = &acme.Client{DirectoryURL: url} + hello := clientHelloInfo("example.org", true) + if _, err := man1.GetCertificate(hello); err != nil { + t.Error(err) + } + if _, err := man2.GetCertificate(hello); err != nil { + t.Error(err) + } +} + +func TestGetCertificate_tokenCache(t *testing.T) { + t.Run("ecdsaSupport=true", func(t *testing.T) { + testGetCertificate_tokenCache(t, true) + }) + t.Run("ecdsaSupport=false", func(t *testing.T) { + testGetCertificate_tokenCache(t, false) + }) +} + +func TestGetCertificate_ecdsaVsRSA(t *testing.T) { + cache := newMemCache(t) + man := &Manager{Prompt: AcceptTOS, Cache: cache} + defer man.stopRenew() + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org") + defer finish() + man.Client = &acme.Client{DirectoryURL: url} + + cert, err := man.GetCertificate(clientHelloInfo("example.org", true)) + if err != nil { + t.Error(err) + } + if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok { + t.Error("an ECDSA client was served a non-ECDSA certificate") + } + + cert, err = man.GetCertificate(clientHelloInfo("example.org", false)) + if err != nil { + t.Error(err) + } + if _, ok := cert.Leaf.PublicKey.(*rsa.PublicKey); !ok { + t.Error("a RSA client was served a non-RSA certificate") + } + + if _, err := man.GetCertificate(clientHelloInfo("example.org", true)); err != nil { + t.Error(err) + } + if _, err := man.GetCertificate(clientHelloInfo("example.org", false)); err != nil { + t.Error(err) + } + if numCerts := cache.numCerts(); numCerts != 2 { + t.Errorf("found %d certificates in cache; want %d", numCerts, 2) + } +} + +func TestGetCertificate_wrongCacheKeyType(t *testing.T) { + cache := newMemCache(t) + man := &Manager{Prompt: AcceptTOS, Cache: cache} + defer man.stopRenew() + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), exampleDomain) + defer finish() + man.Client = &acme.Client{DirectoryURL: url} + + // Make an RSA cert and cache it without suffix. + pk, err := rsa.GenerateKey(rand.Reader, 512) + if err != nil { + t.Fatal(err) + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: exampleDomain}, + NotAfter: time.Now().Add(90 * 24 * time.Hour), + } + pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk) + if err != nil { + t.Fatal(err) + } + rsaCert := &tls.Certificate{ + Certificate: [][]byte{pub}, + PrivateKey: pk, + } + if err := man.cachePut(context.Background(), exampleCertKey, rsaCert); err != nil { + t.Fatalf("man.cachePut: %v", err) + } + + // The RSA cached cert should be silently ignored and replaced. + cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, true)) + if err != nil { + t.Error(err) + } + if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok { + t.Error("an ECDSA client was served a non-ECDSA certificate") + } + if numCerts := cache.numCerts(); numCerts != 1 { + t.Errorf("found %d certificates in cache; want %d", numCerts, 1) + } +} + +func getCertificateFromManager(man *Manager, ecdsaSupport bool) func(string) error { + return func(sni string) error { + _, err := man.GetCertificate(clientHelloInfo(sni, ecdsaSupport)) + return err + } +} + // startACMEServerStub runs an ACME server // The domain argument is the expected domain name of a certificate request. -func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) { +// TODO: Drop this in favour of x/crypto/acme/autocert/internal/acmetest. +func startACMEServerStub(t *testing.T, getCertificate func(string) error, domain string) (url string, finish func()) { // echo token-02 | shasum -a 256 // then divide result in 2 parts separated by dot tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid" verifyTokenCert := func() { - hello := &tls.ClientHelloInfo{ServerName: tokenCertName} - _, err := man.GetCertificate(hello) - if err != nil { + if err := getCertificate(tokenCertName); err != nil { t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err) return } @@ -362,8 +530,7 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, tick := time.NewTicker(100 * time.Millisecond) defer tick.Stop() for { - hello := &tls.ClientHelloInfo{ServerName: tokenCertName} - if _, err := man.GetCertificate(hello); err != nil { + if err := getCertificate(tokenCertName); err != nil { return } select { @@ -387,21 +554,13 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, // tests man.GetCertificate flow using the provided hello argument. // The domain argument is the expected domain name of a certificate request. func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) { - url, finish := startACMEServerStub(t, man, domain) + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), domain) defer finish() - - // use EC key to run faster on 386 - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } - man.Client = &acme.Client{ - Key: key, - DirectoryURL: url, - } + man.Client = &acme.Client{DirectoryURL: url} // simulate tls.Config.GetCertificate var tlscert *tls.Certificate + var err error done := make(chan struct{}) go func() { tlscert, err = man.GetCertificate(hello) @@ -445,13 +604,13 @@ func TestVerifyHTTP01(t *testing.T) { if w.Code != http.StatusOK { t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK) } - if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") { + if v := w.Body.String(); !strings.HasPrefix(v, "token-http-01.") { t.Errorf("http token value = %q; want 'token-http-01.' prefix", v) } } // ACME CA server stub, only the needed bits. - // TODO: Merge this with startACMEServerStub, making it a configurable CA for testing. + // TODO: Replace this with x/crypto/acme/autocert/internal/acmetest. var ca *httptest.Server ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Replay-Nonce", "nonce") @@ -505,18 +664,18 @@ func TestVerifyHTTP01(t *testing.T) { })) defer ca.Close() - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } m := &Manager{ Client: &acme.Client{ - Key: key, DirectoryURL: ca.URL, }, } http01 = m.HTTPHandler(nil) - if err := m.verify(context.Background(), m.Client, "example.org"); err != nil { + ctx := context.Background() + client, err := m.acmeClient(ctx) + if err != nil { + t.Fatalf("m.acmeClient: %v", err) + } + if err := m.verify(ctx, client, "example.org"); err != nil { t.Errorf("m.verify: %v", err) } // Only tls-sni-01, tls-sni-02 and http-01 must be accepted @@ -529,6 +688,111 @@ func TestVerifyHTTP01(t *testing.T) { } } +func TestRevokeFailedAuthz(t *testing.T) { + // Prefill authorization URIs expected to be revoked. + // The challenges are selected in a specific order, + // each tried within a newly created authorization. + // This means each authorization URI corresponds to a different challenge type. + revokedAuthz := map[string]bool{ + "/authz/0": false, // tls-sni-02 + "/authz/1": false, // tls-sni-01 + "/authz/2": false, // no viable challenge, but authz is created + } + + var authzCount int // num. of created authorizations + var revokeCount int // num. of revoked authorizations + done := make(chan struct{}) // closed when revokeCount is 3 + + // ACME CA server stub, only the needed bits. + // TODO: Replace this with x/crypto/acme/autocert/internal/acmetest. + var ca *httptest.Server + ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "nonce") + if r.Method == "HEAD" { + // a nonce request + return + } + + switch r.URL.Path { + // Discovery. + case "/": + if err := discoTmpl.Execute(w, ca.URL); err != nil { + t.Errorf("discoTmpl: %v", err) + } + // Client key registration. + case "/new-reg": + w.Write([]byte("{}")) + // New domain authorization. + case "/new-authz": + w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount)) + w.WriteHeader(http.StatusCreated) + if err := authzTmpl.Execute(w, ca.URL); err != nil { + t.Errorf("authzTmpl: %v", err) + } + authzCount++ + // tls-sni-02 challenge "accept" request. + case "/challenge/2": + // Refuse. + http.Error(w, "won't accept tls-sni-02 challenge", http.StatusBadRequest) + // tls-sni-01 challenge "accept" request. + case "/challenge/1": + // Accept but the authorization will be "expired". + w.Write([]byte("{}")) + // Authorization requests. + case "/authz/0", "/authz/1", "/authz/2": + // Revocation requests. + if r.Method == "POST" { + var req struct{ Status string } + if err := decodePayload(&req, r.Body); err != nil { + t.Errorf("%s: decodePayload: %v", r.URL, err) + } + switch req.Status { + case "deactivated": + revokedAuthz[r.URL.Path] = true + revokeCount++ + if revokeCount >= 3 { + // Last authorization is revoked. + defer close(done) + } + default: + t.Errorf("%s: req.Status = %q; want 'deactivated'", r.URL, req.Status) + } + w.Write([]byte(`{"status": "invalid"}`)) + return + } + // Authorization status requests. + // Simulate abandoned authorization, deleted by the CA. + w.WriteHeader(http.StatusNotFound) + default: + http.NotFound(w, r) + t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) + } + })) + defer ca.Close() + + m := &Manager{ + Client: &acme.Client{DirectoryURL: ca.URL}, + } + // Should fail and revoke 3 authorizations. + // The first 2 are tsl-sni-02 and tls-sni-01 challenges. + // The third time an authorization is created but no viable challenge is found. + // See revokedAuthz above for more explanation. + if _, err := m.createCert(context.Background(), exampleCertKey); err == nil { + t.Errorf("m.createCert returned nil error") + } + select { + case <-time.After(3 * time.Second): + t.Error("revocations took too long") + case <-done: + // revokeCount is at least 3. + } + for uri, ok := range revokedAuthz { + if !ok { + t.Errorf("%q authorization was not revoked", uri) + } + } +} + func TestHTTPHandlerDefaultFallback(t *testing.T) { tt := []struct { method, url string @@ -571,7 +835,7 @@ func TestHTTPHandlerDefaultFallback(t *testing.T) { } func TestAccountKeyCache(t *testing.T) { - m := Manager{Cache: newMemCache()} + m := Manager{Cache: newMemCache(t)} ctx := context.Background() k1, err := m.accountKey(ctx) if err != nil { @@ -587,36 +851,57 @@ func TestAccountKeyCache(t *testing.T) { } func TestCache(t *testing.T) { - privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } - tmpl := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{CommonName: "example.org"}, - NotAfter: time.Now().Add(time.Hour), - } - pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey) + cert, err := dummyCert(ecdsaKey.Public(), exampleDomain) if err != nil { t.Fatal(err) } - tlscert := &tls.Certificate{ - Certificate: [][]byte{pub}, - PrivateKey: privKey, + ecdsaCert := &tls.Certificate{ + Certificate: [][]byte{cert}, + PrivateKey: ecdsaKey, } - man := &Manager{Cache: newMemCache()} + rsaKey, err := rsa.GenerateKey(rand.Reader, 512) + if err != nil { + t.Fatal(err) + } + cert, err = dummyCert(rsaKey.Public(), exampleDomain) + if err != nil { + t.Fatal(err) + } + rsaCert := &tls.Certificate{ + Certificate: [][]byte{cert}, + PrivateKey: rsaKey, + } + + man := &Manager{Cache: newMemCache(t)} defer man.stopRenew() ctx := context.Background() - if err := man.cachePut(ctx, "example.org", tlscert); err != nil { + + if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil { t.Fatalf("man.cachePut: %v", err) } - res, err := man.cacheGet(ctx, "example.org") + if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil { + t.Fatalf("man.cachePut: %v", err) + } + + res, err := man.cacheGet(ctx, exampleCertKey) if err != nil { t.Fatalf("man.cacheGet: %v", err) } - if res == nil { - t.Fatal("res is nil") + if res == nil || !bytes.Equal(res.Certificate[0], ecdsaCert.Certificate[0]) { + t.Errorf("man.cacheGet = %+v; want %+v", res, ecdsaCert) + } + + res, err = man.cacheGet(ctx, exampleCertKeyRSA) + if err != nil { + t.Fatalf("man.cacheGet: %v", err) + } + if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) { + t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert) } } @@ -680,26 +965,28 @@ func TestValidCert(t *testing.T) { } tt := []struct { - domain string - key crypto.Signer - cert [][]byte - ok bool + ck certKey + key crypto.Signer + cert [][]byte + ok bool }{ - {"example.org", key1, [][]byte{cert1}, true}, - {"example.org", key3, [][]byte{cert3}, true}, - {"example.org", key1, [][]byte{cert1, cert2, cert3}, true}, - {"example.org", key1, [][]byte{cert1, {1}}, false}, - {"example.org", key1, [][]byte{{1}}, false}, - {"example.org", key1, [][]byte{cert2}, false}, - {"example.org", key2, [][]byte{cert1}, false}, - {"example.org", key1, [][]byte{cert3}, false}, - {"example.org", key3, [][]byte{cert1}, false}, - {"example.net", key1, [][]byte{cert1}, false}, - {"example.org", key1, [][]byte{early}, false}, - {"example.org", key1, [][]byte{expired}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{cert1}, true}, + {certKey{domain: "example.org", isRSA: true}, key3, [][]byte{cert3}, true}, + {certKey{domain: "example.org"}, key1, [][]byte{cert1, cert2, cert3}, true}, + {certKey{domain: "example.org"}, key1, [][]byte{cert1, {1}}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{{1}}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{cert2}, false}, + {certKey{domain: "example.org"}, key2, [][]byte{cert1}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{cert3}, false}, + {certKey{domain: "example.org"}, key3, [][]byte{cert1}, false}, + {certKey{domain: "example.net"}, key1, [][]byte{cert1}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{early}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{expired}, false}, + {certKey{domain: "example.org", isRSA: true}, key1, [][]byte{cert1}, false}, + {certKey{domain: "example.org"}, key3, [][]byte{cert3}, false}, } for i, test := range tt { - leaf, err := validCert(test.domain, test.cert, test.key) + leaf, err := validCert(test.ck, test.cert, test.key, now) if err != nil && test.ok { t.Errorf("%d: err = %v", i, err) } @@ -748,10 +1035,155 @@ func TestManagerGetCertificateBogusSNI(t *testing.T) { {"fo.o", "cache.Get of fo.o"}, } for _, tt := range tests { - _, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name}) + _, err := m.GetCertificate(clientHelloInfo(tt.name, true)) got := fmt.Sprint(err) if got != tt.wantErr { t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr) } } } + +func TestCertRequest(t *testing.T) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + // An extension from RFC7633. Any will do. + ext := pkix.Extension{ + Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1}, + Value: []byte("dummy"), + } + b, err := certRequest(key, "example.org", []pkix.Extension{ext}, "san.example.org") + if err != nil { + t.Fatalf("certRequest: %v", err) + } + r, err := x509.ParseCertificateRequest(b) + if err != nil { + t.Fatalf("ParseCertificateRequest: %v", err) + } + var found bool + for _, v := range r.Extensions { + if v.Id.Equal(ext.Id) { + found = true + break + } + } + if !found { + t.Errorf("want %v in Extensions: %v", ext, r.Extensions) + } +} + +func TestSupportsECDSA(t *testing.T) { + tests := []struct { + CipherSuites []uint16 + SignatureSchemes []tls.SignatureScheme + SupportedCurves []tls.CurveID + ecdsaOk bool + }{ + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, nil, nil, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, nil, nil, true}, + + // SignatureSchemes limits, not extends, CipherSuites + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, nil, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, + }, nil, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, nil, true}, + + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, []tls.CurveID{ + tls.CurveP521, + }, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, []tls.CurveID{ + tls.CurveP256, + tls.CurveP521, + }, true}, + } + for i, tt := range tests { + result := supportsECDSA(&tls.ClientHelloInfo{ + CipherSuites: tt.CipherSuites, + SignatureSchemes: tt.SignatureSchemes, + SupportedCurves: tt.SupportedCurves, + }) + if result != tt.ecdsaOk { + t.Errorf("%d: supportsECDSA = %v; want %v", i, result, tt.ecdsaOk) + } + } +} + +// TODO: add same end-to-end for http-01 challenge type. +func TestEndToEnd(t *testing.T) { + const domain = "example.org" + + // ACME CA server + ca := acmetest.NewCAServer([]string{"tls-alpn-01"}, []string{domain}) + defer ca.Close() + + // User dummy server. + m := &Manager{ + Prompt: AcceptTOS, + Client: &acme.Client{DirectoryURL: ca.URL}, + } + us := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("OK")) + })) + us.TLS = &tls.Config{ + NextProtos: []string{"http/1.1", acme.ALPNProto}, + GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { + cert, err := m.GetCertificate(hello) + if err != nil { + t.Errorf("m.GetCertificate: %v", err) + } + return cert, err + }, + } + us.StartTLS() + defer us.Close() + // In TLS-ALPN challenge verification, CA connects to the domain:443 in question. + // Because the domain won't resolve in tests, we need to tell the CA + // where to dial to instead. + ca.Resolve(domain, strings.TrimPrefix(us.URL, "https://")) + + // A client visiting user dummy server. + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: ca.Roots, + ServerName: domain, + }, + } + client := &http.Client{Transport: tr} + res, err := client.Get(us.URL) + if err != nil { + t.Logf("CA errors: %v", ca.Errors()) + t.Fatal(err) + } + defer res.Body.Close() + b, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if v := string(b); v != "OK" { + t.Errorf("user server response: %q; want 'OK'", v) + } +} diff --git a/vendor/golang.org/x/crypto/acme/autocert/cache.go b/vendor/golang.org/x/crypto/acme/autocert/cache.go index 61a5fd23..aa9aa845 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/cache.go +++ b/vendor/golang.org/x/crypto/acme/autocert/cache.go @@ -16,10 +16,10 @@ import ( var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss") // Cache is used by Manager to store and retrieve previously obtained certificates -// as opaque data. +// and other account data as opaque blobs. // -// The key argument of the methods refers to a domain name but need not be an FQDN. -// Cache implementations should not rely on the key naming pattern. +// Cache implementations should not rely on the key naming pattern. Keys can +// include any printable ASCII characters, except the following: \/:*?"<>| type Cache interface { // Get returns a certificate data for the specified key. // If there's no such key, Get returns ErrCacheMiss. diff --git a/vendor/golang.org/x/crypto/acme/autocert/example_test.go b/vendor/golang.org/x/crypto/acme/autocert/example_test.go index 552a6254..d4225e5c 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/example_test.go +++ b/vendor/golang.org/x/crypto/acme/autocert/example_test.go @@ -5,7 +5,6 @@ package autocert_test import ( - "crypto/tls" "fmt" "log" "net/http" @@ -25,12 +24,11 @@ func ExampleManager() { m := &autocert.Manager{ Cache: autocert.DirCache("secret-dir"), Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist("example.org"), + HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"), } - go http.ListenAndServe(":http", m.HTTPHandler(nil)) s := &http.Server{ Addr: ":https", - TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, + TLSConfig: m.TLSConfig(), } s.ListenAndServeTLS("", "") } diff --git a/vendor/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go b/vendor/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go new file mode 100644 index 00000000..acc486af --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go @@ -0,0 +1,416 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package acmetest provides types for testing acme and autocert packages. +// +// TODO: Consider moving this to x/crypto/acme/internal/acmetest for acme tests as well. +package acmetest + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "net/http/httptest" + "sort" + "strings" + "sync" + "time" +) + +// CAServer is a simple test server which implements ACME spec bits needed for testing. +type CAServer struct { + URL string // server URL after it has been started + Roots *x509.CertPool // CA root certificates; initialized in NewCAServer + + rootKey crypto.Signer + rootCert []byte // DER encoding + rootTemplate *x509.Certificate + + server *httptest.Server + challengeTypes []string // supported challenge types + domainsWhitelist []string // only these domains are valid for issuing, unless empty + + mu sync.Mutex + certCount int // number of issued certs + domainAddr map[string]string // domain name to addr:port resolution + authorizations map[string]*authorization // keyed by domain name + errors []error // encountered client errors +} + +// NewCAServer creates a new ACME test server and starts serving requests. +// The returned CAServer issues certs signed with the CA roots +// available in the Roots field. +// +// The challengeTypes argument defines the supported ACME challenge types +// sent to a client in a response for a domain authorization. +// If domainsWhitelist is non-empty, the certs will be issued only for the specified +// list of domains. Otherwise, any domain name is allowed. +func NewCAServer(challengeTypes []string, domainsWhitelist []string) *CAServer { + var whitelist []string + for _, name := range domainsWhitelist { + whitelist = append(whitelist, name) + } + sort.Strings(whitelist) + ca := &CAServer{ + challengeTypes: challengeTypes, + domainsWhitelist: whitelist, + domainAddr: make(map[string]string), + authorizations: make(map[string]*authorization), + } + + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(fmt.Sprintf("ecdsa.GenerateKey: %v", err)) + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Test Acme Co"}, + CommonName: "Root CA", + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageCertSign, + BasicConstraintsValid: true, + IsCA: true, + } + der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key) + if err != nil { + panic(fmt.Sprintf("x509.CreateCertificate: %v", err)) + } + cert, err := x509.ParseCertificate(der) + if err != nil { + panic(fmt.Sprintf("x509.ParseCertificate: %v", err)) + } + ca.Roots = x509.NewCertPool() + ca.Roots.AddCert(cert) + ca.rootKey = key + ca.rootCert = der + ca.rootTemplate = tmpl + + ca.server = httptest.NewServer(http.HandlerFunc(ca.handle)) + ca.URL = ca.server.URL + return ca +} + +// Close shuts down the server and blocks until all outstanding +// requests on this server have completed. +func (ca *CAServer) Close() { + ca.server.Close() +} + +// Errors returns all client errors. +func (ca *CAServer) Errors() []error { + ca.mu.Lock() + defer ca.mu.Unlock() + return ca.errors +} + +// Resolve adds a domain to address resolution for the ca to dial to +// when validating challenges for the domain authorization. +func (ca *CAServer) Resolve(domain, addr string) { + ca.mu.Lock() + defer ca.mu.Unlock() + ca.domainAddr[domain] = addr +} + +type discovery struct { + NewReg string `json:"new-reg"` + NewAuthz string `json:"new-authz"` + NewCert string `json:"new-cert"` +} + +type challenge struct { + URI string `json:"uri"` + Type string `json:"type"` + Token string `json:"token"` +} + +type authorization struct { + Status string `json:"status"` + Challenges []challenge `json:"challenges"` + + id int + domain string +} + +func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "nonce") + if r.Method == "HEAD" { + // a nonce request + return + } + + // TODO: Verify nonce header for all POST requests. + + switch { + default: + err := fmt.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + + // Discovery request. + case r.URL.Path == "/": + resp := &discovery{ + NewReg: ca.serverURL("/new-reg"), + NewAuthz: ca.serverURL("/new-authz"), + NewCert: ca.serverURL("/new-cert"), + } + if err := json.NewEncoder(w).Encode(resp); err != nil { + panic(fmt.Sprintf("discovery response: %v", err)) + } + + // Client key registration request. + case r.URL.Path == "/new-reg": + // TODO: Check the user account key against a ca.accountKeys? + w.Write([]byte("{}")) + + // Domain authorization request. + case r.URL.Path == "/new-authz": + var req struct { + Identifier struct{ Value string } + } + if err := decodePayload(&req, r.Body); err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + ca.mu.Lock() + defer ca.mu.Unlock() + authz, ok := ca.authorizations[req.Identifier.Value] + if !ok { + authz = &authorization{ + domain: req.Identifier.Value, + Status: "pending", + } + for _, typ := range ca.challengeTypes { + authz.Challenges = append(authz.Challenges, challenge{ + Type: typ, + URI: ca.serverURL("/challenge/%s/%s", typ, authz.domain), + Token: challengeToken(authz.domain, typ), + }) + } + ca.authorizations[authz.domain] = authz + } + w.Header().Set("Location", ca.serverURL("/authz/%s", authz.domain)) + w.WriteHeader(http.StatusCreated) + if err := json.NewEncoder(w).Encode(authz); err != nil { + panic(fmt.Sprintf("new authz response: %v", err)) + } + + // Accept tls-alpn-01 challenge type requests. + // TODO: Add http-01 and dns-01 handlers. + case strings.HasPrefix(r.URL.Path, "/challenge/tls-alpn-01/"): + domain := strings.TrimPrefix(r.URL.Path, "/challenge/tls-alpn-01/") + ca.mu.Lock() + defer ca.mu.Unlock() + if _, ok := ca.authorizations[domain]; !ok { + err := fmt.Errorf("challenge accept: no authz for %q", domain) + ca.addError(err) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + go func(domain string) { + err := ca.verifyALPNChallenge(domain) + ca.mu.Lock() + defer ca.mu.Unlock() + authz := ca.authorizations[domain] + if err != nil { + authz.Status = "invalid" + return + } + authz.Status = "valid" + + }(domain) + w.Write([]byte("{}")) + + // Get authorization status requests. + case strings.HasPrefix(r.URL.Path, "/authz/"): + domain := strings.TrimPrefix(r.URL.Path, "/authz/") + ca.mu.Lock() + defer ca.mu.Unlock() + authz, ok := ca.authorizations[domain] + if !ok { + http.Error(w, fmt.Sprintf("no authz for %q", domain), http.StatusNotFound) + return + } + if err := json.NewEncoder(w).Encode(authz); err != nil { + panic(fmt.Sprintf("get authz for %q response: %v", domain, err)) + } + + // Cert issuance request. + case r.URL.Path == "/new-cert": + var req struct { + CSR string `json:"csr"` + } + decodePayload(&req, r.Body) + b, _ := base64.RawURLEncoding.DecodeString(req.CSR) + csr, err := x509.ParseCertificateRequest(b) + if err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + names := unique(append(csr.DNSNames, csr.Subject.CommonName)) + if err := ca.matchWhitelist(names); err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + if err := ca.authorized(names); err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + der, err := ca.leafCert(csr) + if err != nil { + err = fmt.Errorf("new-cert response: ca.leafCert: %v", err) + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + } + w.Header().Set("Link", fmt.Sprintf("<%s>; rel=up", ca.serverURL("/ca-cert"))) + w.WriteHeader(http.StatusCreated) + w.Write(der) + + // CA chain cert request. + case r.URL.Path == "/ca-cert": + w.Write(ca.rootCert) + } +} + +func (ca *CAServer) addError(err error) { + ca.mu.Lock() + defer ca.mu.Unlock() + ca.errors = append(ca.errors, err) +} + +func (ca *CAServer) serverURL(format string, arg ...interface{}) string { + return ca.server.URL + fmt.Sprintf(format, arg...) +} + +func (ca *CAServer) matchWhitelist(dnsNames []string) error { + if len(ca.domainsWhitelist) == 0 { + return nil + } + var nomatch []string + for _, name := range dnsNames { + i := sort.SearchStrings(ca.domainsWhitelist, name) + if i == len(ca.domainsWhitelist) || ca.domainsWhitelist[i] != name { + nomatch = append(nomatch, name) + } + } + if len(nomatch) > 0 { + return fmt.Errorf("matchWhitelist: some domains don't match: %q", nomatch) + } + return nil +} + +func (ca *CAServer) authorized(dnsNames []string) error { + ca.mu.Lock() + defer ca.mu.Unlock() + var noauthz []string + for _, name := range dnsNames { + authz, ok := ca.authorizations[name] + if !ok || authz.Status != "valid" { + noauthz = append(noauthz, name) + } + } + if len(noauthz) > 0 { + return fmt.Errorf("CAServer: no authz for %q", noauthz) + } + return nil +} + +func (ca *CAServer) leafCert(csr *x509.CertificateRequest) (der []byte, err error) { + ca.mu.Lock() + defer ca.mu.Unlock() + ca.certCount++ // next leaf cert serial number + leaf := &x509.Certificate{ + SerialNumber: big.NewInt(int64(ca.certCount)), + Subject: pkix.Name{Organization: []string{"Test Acme Co"}}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(90 * 24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + DNSNames: csr.DNSNames, + BasicConstraintsValid: true, + } + if len(csr.DNSNames) == 0 { + leaf.DNSNames = []string{csr.Subject.CommonName} + } + return x509.CreateCertificate(rand.Reader, leaf, ca.rootTemplate, csr.PublicKey, ca.rootKey) +} + +func (ca *CAServer) addr(domain string) (string, error) { + ca.mu.Lock() + defer ca.mu.Unlock() + addr, ok := ca.domainAddr[domain] + if !ok { + return "", fmt.Errorf("CAServer: no addr resolution for %q", domain) + } + return addr, nil +} + +func (ca *CAServer) verifyALPNChallenge(domain string) error { + const acmeALPNProto = "acme-tls/1" + + addr, err := ca.addr(domain) + if err != nil { + return err + } + conn, err := tls.Dial("tcp", addr, &tls.Config{ + ServerName: domain, + InsecureSkipVerify: true, + NextProtos: []string{acmeALPNProto}, + }) + if err != nil { + return err + } + if v := conn.ConnectionState().NegotiatedProtocol; v != acmeALPNProto { + return fmt.Errorf("CAServer: verifyALPNChallenge: negotiated proto is %q; want %q", v, acmeALPNProto) + } + if n := len(conn.ConnectionState().PeerCertificates); n != 1 { + return fmt.Errorf("len(PeerCertificates) = %d; want 1", n) + } + // TODO: verify conn.ConnectionState().PeerCertificates[0] + return nil +} + +func decodePayload(v interface{}, r io.Reader) error { + var req struct{ Payload string } + if err := json.NewDecoder(r).Decode(&req); err != nil { + return err + } + payload, err := base64.RawURLEncoding.DecodeString(req.Payload) + if err != nil { + return err + } + return json.Unmarshal(payload, v) +} + +func challengeToken(domain, challType string) string { + return fmt.Sprintf("token-%s-%s", domain, challType) +} + +func unique(a []string) []string { + seen := make(map[string]bool) + var res []string + for _, s := range a { + if s != "" && !seen[s] { + seen[s] = true + res = append(res, s) + } + } + return res +} diff --git a/vendor/golang.org/x/crypto/acme/autocert/listener.go b/vendor/golang.org/x/crypto/acme/autocert/listener.go index d744df0e..1e069818 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/listener.go +++ b/vendor/golang.org/x/crypto/acme/autocert/listener.go @@ -72,11 +72,8 @@ func NewListener(domains ...string) net.Listener { // the Manager m's Prompt, Cache, HostPolicy, and other desired options. func (m *Manager) Listener() net.Listener { ln := &listener{ - m: m, - conf: &tls.Config{ - GetCertificate: m.GetCertificate, // bonus: panic on nil m - NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2 - }, + m: m, + conf: m.TLSConfig(), } ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443") return ln diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vendor/golang.org/x/crypto/acme/autocert/renewal.go index 3fa4d61a..665f870d 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/renewal.go +++ b/vendor/golang.org/x/crypto/acme/autocert/renewal.go @@ -17,9 +17,9 @@ const renewJitter = time.Hour // domainRenewal tracks the state used by the periodic timers // renewing a single domain's cert. type domainRenewal struct { - m *Manager - domain string - key crypto.Signer + m *Manager + ck certKey + key crypto.Signer timerMu sync.Mutex timer *time.Timer @@ -77,7 +77,7 @@ func (dr *domainRenewal) updateState(state *certState) { dr.m.stateMu.Lock() defer dr.m.stateMu.Unlock() dr.key = state.key - dr.m.state[dr.domain] = state + dr.m.state[dr.ck] = state } // do is similar to Manager.createCert but it doesn't lock a Manager.state item. @@ -91,7 +91,7 @@ func (dr *domainRenewal) updateState(state *certState) { func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { // a race is likely unavoidable in a distributed environment // but we try nonetheless - if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil { + if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil { next := dr.next(tlscert.Leaf.NotAfter) if next > dr.m.renewBefore()+renewJitter { signer, ok := tlscert.PrivateKey.(crypto.Signer) @@ -107,7 +107,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { } } - der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain) + der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck) if err != nil { return 0, err } @@ -120,7 +120,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { if err != nil { return 0, err } - if err := dr.m.cachePut(ctx, dr.domain, tlscert); err != nil { + if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil { return 0, err } dr.updateState(state) @@ -128,7 +128,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { } func (dr *domainRenewal) next(expiry time.Time) time.Duration { - d := expiry.Sub(timeNow()) - dr.m.renewBefore() + d := expiry.Sub(dr.m.now()) - dr.m.renewBefore() // add a bit of randomness to renew deadline n := pseudoRand.int63n(int64(renewJitter)) d -= time.Duration(n) diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go b/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go index 6e88672b..5d1c63ff 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go +++ b/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go @@ -23,10 +23,10 @@ import ( func TestRenewalNext(t *testing.T) { now := time.Now() - timeNow = func() time.Time { return now } - defer func() { timeNow = time.Now }() - - man := &Manager{RenewBefore: 7 * 24 * time.Hour} + man := &Manager{ + RenewBefore: 7 * 24 * time.Hour, + nowFunc: func() time.Time { return now }, + } defer man.stopRenew() tt := []struct { expiry time.Time @@ -48,8 +48,6 @@ func TestRenewalNext(t *testing.T) { } func TestRenewFromCache(t *testing.T) { - const domain = "example.org" - // ACME CA server stub var ca *httptest.Server ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -84,7 +82,7 @@ func TestRenewFromCache(t *testing.T) { if err != nil { t.Fatalf("new-cert: CSR: %v", err) } - der, err := dummyCert(csr.PublicKey, domain) + der, err := dummyCert(csr.PublicKey, exampleDomain) if err != nil { t.Fatalf("new-cert: dummyCert: %v", err) } @@ -105,30 +103,28 @@ func TestRenewFromCache(t *testing.T) { })) defer ca.Close() - // use EC key to run faster on 386 - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } man := &Manager{ Prompt: AcceptTOS, - Cache: newMemCache(), + Cache: newMemCache(t), RenewBefore: 24 * time.Hour, Client: &acme.Client{ - Key: key, DirectoryURL: ca.URL, }, } defer man.stopRenew() // cache an almost expired cert + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } now := time.Now() - cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain) + cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain) if err != nil { t.Fatal(err) } tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}} - if err := man.cachePut(context.Background(), domain, tlscert); err != nil { + if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil { t.Fatal(err) } @@ -152,7 +148,7 @@ func TestRenewFromCache(t *testing.T) { // ensure the new cert is cached after := time.Now().Add(future) - tlscert, err := man.cacheGet(context.Background(), domain) + tlscert, err := man.cacheGet(context.Background(), exampleCertKey) if err != nil { t.Fatalf("man.cacheGet: %v", err) } @@ -163,9 +159,9 @@ func TestRenewFromCache(t *testing.T) { // verify the old cert is also replaced in memory man.stateMu.Lock() defer man.stateMu.Unlock() - s := man.state[domain] + s := man.state[exampleCertKey] if s == nil { - t.Fatalf("m.state[%q] is nil", domain) + t.Fatalf("m.state[%q] is nil", exampleCertKey) } tlscert, err = s.tlscert() if err != nil { @@ -177,7 +173,7 @@ func TestRenewFromCache(t *testing.T) { } // trigger renew - hello := &tls.ClientHelloInfo{ServerName: domain} + hello := clientHelloInfo(exampleDomain, true) if _, err := man.GetCertificate(hello); err != nil { t.Fatal(err) } @@ -191,19 +187,11 @@ func TestRenewFromCache(t *testing.T) { } func TestRenewFromCacheAlreadyRenewed(t *testing.T) { - const domain = "example.org" - - // use EC key to run faster on 386 - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } man := &Manager{ Prompt: AcceptTOS, - Cache: newMemCache(), + Cache: newMemCache(t), RenewBefore: 24 * time.Hour, Client: &acme.Client{ - Key: key, DirectoryURL: "invalid", }, } @@ -215,38 +203,42 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { t.Fatal(err) } now := time.Now() - newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), domain) + newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), exampleDomain) if err != nil { t.Fatal(err) } - newLeaf, err := validCert(domain, [][]byte{newCert}, newKey) + newLeaf, err := validCert(exampleCertKey, [][]byte{newCert}, newKey, now) if err != nil { t.Fatal(err) } newTLSCert := &tls.Certificate{PrivateKey: newKey, Certificate: [][]byte{newCert}, Leaf: newLeaf} - if err := man.cachePut(context.Background(), domain, newTLSCert); err != nil { + if err := man.cachePut(context.Background(), exampleCertKey, newTLSCert); err != nil { t.Fatal(err) } // set internal state to an almost expired cert - oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain) + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } - oldLeaf, err := validCert(domain, [][]byte{oldCert}, key) + oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain) + if err != nil { + t.Fatal(err) + } + oldLeaf, err := validCert(exampleCertKey, [][]byte{oldCert}, key, now) if err != nil { t.Fatal(err) } man.stateMu.Lock() if man.state == nil { - man.state = make(map[string]*certState) + man.state = make(map[certKey]*certState) } s := &certState{ key: key, cert: [][]byte{oldCert}, leaf: oldLeaf, } - man.state[domain] = s + man.state[exampleCertKey] = s man.stateMu.Unlock() // veriy the renewal accepted the newer cached cert @@ -267,7 +259,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { } // ensure the cached cert was not modified - tlscert, err := man.cacheGet(context.Background(), domain) + tlscert, err := man.cacheGet(context.Background(), exampleCertKey) if err != nil { t.Fatalf("man.cacheGet: %v", err) } @@ -278,9 +270,9 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { // verify the old cert is also replaced in memory man.stateMu.Lock() defer man.stateMu.Unlock() - s := man.state[domain] + s := man.state[exampleCertKey] if s == nil { - t.Fatalf("m.state[%q] is nil", domain) + t.Fatalf("m.state[%q] is nil", exampleCertKey) } stateKey := s.key.Public().(*ecdsa.PublicKey) if stateKey.X.Cmp(newKey.X) != 0 || stateKey.Y.Cmp(newKey.Y) != 0 { @@ -295,9 +287,9 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { } // verify the private key is replaced in the renewal state - r := man.renewal[domain] + r := man.renewal[exampleCertKey] if r == nil { - t.Fatalf("m.renewal[%q] is nil", domain) + t.Fatalf("m.renewal[%q] is nil", exampleCertKey) } renewalKey := r.key.Public().(*ecdsa.PublicKey) if renewalKey.X.Cmp(newKey.X) != 0 || renewalKey.Y.Cmp(newKey.Y) != 0 { @@ -307,7 +299,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { } // assert the expiring cert is returned from state - hello := &tls.ClientHelloInfo{ServerName: domain} + hello := clientHelloInfo(exampleDomain, true) tlscert, err := man.GetCertificate(hello) if err != nil { t.Fatal(err) @@ -317,7 +309,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { } // trigger renew - go man.renew(domain, s.key, s.leaf.NotAfter) + go man.renew(exampleCertKey, s.key, s.leaf.NotAfter) // wait for renew loop select { @@ -325,7 +317,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { t.Fatal("renew took too long to occur") case <-done: // assert the new cert is returned from state after renew - hello := &tls.ClientHelloInfo{ServerName: domain} + hello := clientHelloInfo(exampleDomain, true) tlscert, err := man.GetCertificate(hello) if err != nil { t.Fatal(err) diff --git a/vendor/golang.org/x/crypto/acme/http.go b/vendor/golang.org/x/crypto/acme/http.go new file mode 100644 index 00000000..a43ce6a5 --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/http.go @@ -0,0 +1,281 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package acme + +import ( + "bytes" + "context" + "crypto" + "crypto/rand" + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "net/http" + "strconv" + "strings" + "time" +) + +// retryTimer encapsulates common logic for retrying unsuccessful requests. +// It is not safe for concurrent use. +type retryTimer struct { + // backoffFn provides backoff delay sequence for retries. + // See Client.RetryBackoff doc comment. + backoffFn func(n int, r *http.Request, res *http.Response) time.Duration + // n is the current retry attempt. + n int +} + +func (t *retryTimer) inc() { + t.n++ +} + +// backoff pauses the current goroutine as described in Client.RetryBackoff. +func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error { + d := t.backoffFn(t.n, r, res) + if d <= 0 { + return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n) + } + wakeup := time.NewTimer(d) + defer wakeup.Stop() + select { + case <-ctx.Done(): + return ctx.Err() + case <-wakeup.C: + return nil + } +} + +func (c *Client) retryTimer() *retryTimer { + f := c.RetryBackoff + if f == nil { + f = defaultBackoff + } + return &retryTimer{backoffFn: f} +} + +// defaultBackoff provides default Client.RetryBackoff implementation +// using a truncated exponential backoff algorithm, +// as described in Client.RetryBackoff. +// +// The n argument is always bounded between 1 and 30. +// The returned value is always greater than 0. +func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration { + const max = 10 * time.Second + var jitter time.Duration + if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil { + // Set the minimum to 1ms to avoid a case where + // an invalid Retry-After value is parsed into 0 below, + // resulting in the 0 returned value which would unintentionally + // stop the retries. + jitter = (1 + time.Duration(x.Int64())) * time.Millisecond + } + if v, ok := res.Header["Retry-After"]; ok { + return retryAfter(v[0]) + jitter + } + + if n < 1 { + n = 1 + } + if n > 30 { + n = 30 + } + d := time.Duration(1< max { + return max + } + return d +} + +// retryAfter parses a Retry-After HTTP header value, +// trying to convert v into an int (seconds) or use http.ParseTime otherwise. +// It returns zero value if v cannot be parsed. +func retryAfter(v string) time.Duration { + if i, err := strconv.Atoi(v); err == nil { + return time.Duration(i) * time.Second + } + t, err := http.ParseTime(v) + if err != nil { + return 0 + } + return t.Sub(timeNow()) +} + +// resOkay is a function that reports whether the provided response is okay. +// It is expected to keep the response body unread. +type resOkay func(*http.Response) bool + +// wantStatus returns a function which reports whether the code +// matches the status code of a response. +func wantStatus(codes ...int) resOkay { + return func(res *http.Response) bool { + for _, code := range codes { + if code == res.StatusCode { + return true + } + } + return false + } +} + +// get issues an unsigned GET request to the specified URL. +// It returns a non-error value only when ok reports true. +// +// get retries unsuccessful attempts according to c.RetryBackoff +// until the context is done or a non-retriable error is received. +func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) { + retry := c.retryTimer() + for { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + res, err := c.doNoRetry(ctx, req) + switch { + case err != nil: + return nil, err + case ok(res): + return res, nil + case isRetriable(res.StatusCode): + retry.inc() + resErr := responseError(res) + res.Body.Close() + // Ignore the error value from retry.backoff + // and return the one from last retry, as received from the CA. + if retry.backoff(ctx, req, res) != nil { + return nil, resErr + } + default: + defer res.Body.Close() + return nil, responseError(res) + } + } +} + +// post issues a signed POST request in JWS format using the provided key +// to the specified URL. +// It returns a non-error value only when ok reports true. +// +// post retries unsuccessful attempts according to c.RetryBackoff +// until the context is done or a non-retriable error is received. +// It uses postNoRetry to make individual requests. +func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) { + retry := c.retryTimer() + for { + res, req, err := c.postNoRetry(ctx, key, url, body) + if err != nil { + return nil, err + } + if ok(res) { + return res, nil + } + resErr := responseError(res) + res.Body.Close() + switch { + // Check for bad nonce before isRetriable because it may have been returned + // with an unretriable response code such as 400 Bad Request. + case isBadNonce(resErr): + // Consider any previously stored nonce values to be invalid. + c.clearNonces() + case !isRetriable(res.StatusCode): + return nil, resErr + } + retry.inc() + // Ignore the error value from retry.backoff + // and return the one from last retry, as received from the CA. + if err := retry.backoff(ctx, req, res); err != nil { + return nil, resErr + } + } +} + +// postNoRetry signs the body with the given key and POSTs it to the provided url. +// The body argument must be JSON-serializable. +// It is used by c.post to retry unsuccessful attempts. +func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) { + nonce, err := c.popNonce(ctx, url) + if err != nil { + return nil, nil, err + } + b, err := jwsEncodeJSON(body, key, nonce) + if err != nil { + return nil, nil, err + } + req, err := http.NewRequest("POST", url, bytes.NewReader(b)) + if err != nil { + return nil, nil, err + } + req.Header.Set("Content-Type", "application/jose+json") + res, err := c.doNoRetry(ctx, req) + if err != nil { + return nil, nil, err + } + c.addNonce(res.Header) + return res, req, nil +} + +// doNoRetry issues a request req, replacing its context (if any) with ctx. +func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) { + res, err := c.httpClient().Do(req.WithContext(ctx)) + if err != nil { + select { + case <-ctx.Done(): + // Prefer the unadorned context error. + // (The acme package had tests assuming this, previously from ctxhttp's + // behavior, predating net/http supporting contexts natively) + // TODO(bradfitz): reconsider this in the future. But for now this + // requires no test updates. + return nil, ctx.Err() + default: + return nil, err + } + } + return res, nil +} + +func (c *Client) httpClient() *http.Client { + if c.HTTPClient != nil { + return c.HTTPClient + } + return http.DefaultClient +} + +// isBadNonce reports whether err is an ACME "badnonce" error. +func isBadNonce(err error) bool { + // According to the spec badNonce is urn:ietf:params:acme:error:badNonce. + // However, ACME servers in the wild return their versions of the error. + // See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4 + // and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66. + ae, ok := err.(*Error) + return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") +} + +// isRetriable reports whether a request can be retried +// based on the response status code. +// +// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code. +// Callers should parse the response and check with isBadNonce. +func isRetriable(code int) bool { + return code <= 399 || code >= 500 || code == http.StatusTooManyRequests +} + +// responseError creates an error of Error type from resp. +func responseError(resp *http.Response) error { + // don't care if ReadAll returns an error: + // json.Unmarshal will fail in that case anyway + b, _ := ioutil.ReadAll(resp.Body) + e := &wireError{Status: resp.StatusCode} + if err := json.Unmarshal(b, e); err != nil { + // this is not a regular error response: + // populate detail with anything we received, + // e.Status will already contain HTTP response code value + e.Detail = string(b) + if e.Detail == "" { + e.Detail = resp.Status + } + } + return e.error(resp.Header) +} diff --git a/vendor/golang.org/x/crypto/acme/http_test.go b/vendor/golang.org/x/crypto/acme/http_test.go new file mode 100644 index 00000000..15e401ba --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/http_test.go @@ -0,0 +1,209 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package acme + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" + "time" +) + +func TestDefaultBackoff(t *testing.T) { + tt := []struct { + nretry int + retryAfter string // Retry-After header + out time.Duration // expected min; max = min + jitter + }{ + {-1, "", time.Second}, // verify the lower bound is 1 + {0, "", time.Second}, // verify the lower bound is 1 + {100, "", 10 * time.Second}, // verify the ceiling + {1, "3600", time.Hour}, // verify the header value is used + {1, "", 1 * time.Second}, + {2, "", 2 * time.Second}, + {3, "", 4 * time.Second}, + {4, "", 8 * time.Second}, + } + for i, test := range tt { + r := httptest.NewRequest("GET", "/", nil) + resp := &http.Response{Header: http.Header{}} + if test.retryAfter != "" { + resp.Header.Set("Retry-After", test.retryAfter) + } + d := defaultBackoff(test.nretry, r, resp) + max := test.out + time.Second // + max jitter + if d < test.out || max < d { + t.Errorf("%d: defaultBackoff(%v) = %v; want between %v and %v", i, test.nretry, d, test.out, max) + } + } +} + +func TestErrorResponse(t *testing.T) { + s := `{ + "status": 400, + "type": "urn:acme:error:xxx", + "detail": "text" + }` + res := &http.Response{ + StatusCode: 400, + Status: "400 Bad Request", + Body: ioutil.NopCloser(strings.NewReader(s)), + Header: http.Header{"X-Foo": {"bar"}}, + } + err := responseError(res) + v, ok := err.(*Error) + if !ok { + t.Fatalf("err = %+v (%T); want *Error type", err, err) + } + if v.StatusCode != 400 { + t.Errorf("v.StatusCode = %v; want 400", v.StatusCode) + } + if v.ProblemType != "urn:acme:error:xxx" { + t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType) + } + if v.Detail != "text" { + t.Errorf("v.Detail = %q; want text", v.Detail) + } + if !reflect.DeepEqual(v.Header, res.Header) { + t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header) + } +} + +func TestPostWithRetries(t *testing.T) { + var count int + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + count++ + w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count)) + if r.Method == "HEAD" { + // We expect the client to do 2 head requests to fetch + // nonces, one to start and another after getting badNonce + return + } + + head, err := decodeJWSHead(r) + switch { + case err != nil: + t.Errorf("decodeJWSHead: %v", err) + case head.Nonce == "": + t.Error("head.Nonce is empty") + case head.Nonce == "nonce1": + // Return a badNonce error to force the call to retry. + w.Header().Set("Retry-After", "0") + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`)) + return + } + // Make client.Authorize happy; we're not testing its result. + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"status":"valid"}`)) + })) + defer ts.Close() + + client := &Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}} + // This call will fail with badNonce, causing a retry + if _, err := client.Authorize(context.Background(), "example.com"); err != nil { + t.Errorf("client.Authorize 1: %v", err) + } + if count != 4 { + t.Errorf("total requests count: %d; want 4", count) + } +} + +func TestRetryErrorType(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "nonce") + w.WriteHeader(http.StatusTooManyRequests) + w.Write([]byte(`{"type":"rateLimited"}`)) + })) + defer ts.Close() + + client := &Client{ + Key: testKey, + RetryBackoff: func(n int, r *http.Request, res *http.Response) time.Duration { + // Do no retries. + return 0 + }, + dir: &Directory{AuthzURL: ts.URL}, + } + + t.Run("post", func(t *testing.T) { + testRetryErrorType(t, func() error { + _, err := client.Authorize(context.Background(), "example.com") + return err + }) + }) + t.Run("get", func(t *testing.T) { + testRetryErrorType(t, func() error { + _, err := client.GetAuthorization(context.Background(), ts.URL) + return err + }) + }) +} + +func testRetryErrorType(t *testing.T, callClient func() error) { + t.Helper() + err := callClient() + if err == nil { + t.Fatal("client.Authorize returned nil error") + } + acmeErr, ok := err.(*Error) + if !ok { + t.Fatalf("err is %v (%T); want *Error", err, err) + } + if acmeErr.StatusCode != http.StatusTooManyRequests { + t.Errorf("acmeErr.StatusCode = %d; want %d", acmeErr.StatusCode, http.StatusTooManyRequests) + } + if acmeErr.ProblemType != "rateLimited" { + t.Errorf("acmeErr.ProblemType = %q; want 'rateLimited'", acmeErr.ProblemType) + } +} + +func TestRetryBackoffArgs(t *testing.T) { + const resCode = http.StatusInternalServerError + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "test-nonce") + w.WriteHeader(resCode) + })) + defer ts.Close() + + // Canceled in backoff. + ctx, cancel := context.WithCancel(context.Background()) + + var nretry int + backoff := func(n int, r *http.Request, res *http.Response) time.Duration { + nretry++ + if n != nretry { + t.Errorf("n = %d; want %d", n, nretry) + } + if nretry == 3 { + cancel() + } + + if r == nil { + t.Error("r is nil") + } + if res.StatusCode != resCode { + t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, resCode) + } + return time.Millisecond + } + + client := &Client{ + Key: testKey, + RetryBackoff: backoff, + dir: &Directory{AuthzURL: ts.URL}, + } + if _, err := client.Authorize(ctx, "example.com"); err == nil { + t.Error("err is nil") + } + if nretry != 3 { + t.Errorf("nretry = %d; want 3", nretry) + } +} diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go index 6cbca25d..1093b503 100644 --- a/vendor/golang.org/x/crypto/acme/jws.go +++ b/vendor/golang.org/x/crypto/acme/jws.go @@ -25,7 +25,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byt if err != nil { return nil, err } - alg, sha := jwsHasher(key) + alg, sha := jwsHasher(key.Public()) if alg == "" || !sha.Available() { return nil, ErrUnsupportedKey } @@ -97,13 +97,16 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { } // jwsSign signs the digest using the given key. -// It returns ErrUnsupportedKey if the key type is unknown. -// The hash is used only for RSA keys. +// The hash is unused for ECDSA keys. +// +// Note: non-stdlib crypto.Signer implementations are expected to return +// the signature in the format as specified in RFC7518. +// See https://tools.ietf.org/html/rfc7518 for more details. func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { - switch key := key.(type) { - case *rsa.PrivateKey: - return key.Sign(rand.Reader, digest, hash) - case *ecdsa.PrivateKey: + if key, ok := key.(*ecdsa.PrivateKey); ok { + // The key.Sign method of ecdsa returns ASN1-encoded signature. + // So, we use the package Sign function instead + // to get R and S values directly and format the result accordingly. r, s, err := ecdsa.Sign(rand.Reader, key, digest) if err != nil { return nil, err @@ -118,18 +121,18 @@ func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) copy(sig[size*2-len(sb):], sb) return sig, nil } - return nil, ErrUnsupportedKey + return key.Sign(rand.Reader, digest, hash) } // jwsHasher indicates suitable JWS algorithm name and a hash function // to use for signing a digest with the provided key. // It returns ("", 0) if the key is not supported. -func jwsHasher(key crypto.Signer) (string, crypto.Hash) { - switch key := key.(type) { - case *rsa.PrivateKey: +func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) { + switch pub := pub.(type) { + case *rsa.PublicKey: return "RS256", crypto.SHA256 - case *ecdsa.PrivateKey: - switch key.Params().Name { + case *ecdsa.PublicKey: + switch pub.Params().Name { case "P-256": return "ES256", crypto.SHA256 case "P-384": diff --git a/vendor/golang.org/x/crypto/acme/jws_test.go b/vendor/golang.org/x/crypto/acme/jws_test.go index 0ff0fb5a..ee30b1e1 100644 --- a/vendor/golang.org/x/crypto/acme/jws_test.go +++ b/vendor/golang.org/x/crypto/acme/jws_test.go @@ -5,6 +5,7 @@ package acme import ( + "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" @@ -13,6 +14,7 @@ import ( "encoding/json" "encoding/pem" "fmt" + "io" "math/big" "testing" ) @@ -241,6 +243,79 @@ func TestJWSEncodeJSONEC(t *testing.T) { } } +type customTestSigner struct { + sig []byte + pub crypto.PublicKey +} + +func (s *customTestSigner) Public() crypto.PublicKey { return s.pub } +func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) { + return s.sig, nil +} + +func TestJWSEncodeJSONCustom(t *testing.T) { + claims := struct{ Msg string }{"hello"} + const ( + // printf '{"Msg":"hello"}' | base64 | tr -d '=' | tr '/+' '_-' + payload = "eyJNc2ciOiJoZWxsbyJ9" + // printf 'testsig' | base64 | tr -d '=' + testsig = "dGVzdHNpZw" + + // printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":,"y":,"nonce":"nonce"}' | \ + // base64 | tr -d '=' | tr '/+' '_-' + es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjVsaEV1" + + "ZzV4SzR4QkRaMm5BYmF4THRhTGl2ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFH" + + "a3YwVGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6Im5vbmNlIn0" + + // {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"} + rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" + + "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" + + "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" + + "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" + + "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" + + "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" + + "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" + + "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" + + "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" + + "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" + + "UVEifSwibm9uY2UiOiJub25jZSJ9" + ) + + tt := []struct { + alg, phead string + pub crypto.PublicKey + }{ + {"RS256", rs256phead, testKey.Public()}, + {"ES256", es256phead, testKeyEC.Public()}, + } + for _, tc := range tt { + tc := tc + t.Run(tc.alg, func(t *testing.T) { + signer := &customTestSigner{ + sig: []byte("testsig"), + pub: tc.pub, + } + b, err := jwsEncodeJSON(claims, signer, "nonce") + if err != nil { + t.Fatal(err) + } + var j struct{ Protected, Payload, Signature string } + if err := json.Unmarshal(b, &j); err != nil { + t.Fatal(err) + } + if j.Protected != tc.phead { + t.Errorf("j.Protected = %q\nwant %q", j.Protected, tc.phead) + } + if j.Payload != payload { + t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload) + } + if j.Signature != testsig { + t.Errorf("j.Signature = %q\nwant %q", j.Signature, testsig) + } + }) + } +} + func TestJWKThumbprintRSA(t *testing.T) { // Key example from RFC 7638 const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" + diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go index 3e199749..54792c06 100644 --- a/vendor/golang.org/x/crypto/acme/types.go +++ b/vendor/golang.org/x/crypto/acme/types.go @@ -104,7 +104,7 @@ func RateLimit(err error) (time.Duration, bool) { if e.Header == nil { return 0, true } - return retryAfter(e.Header.Get("Retry-After"), 0), true + return retryAfter(e.Header.Get("Retry-After")), true } // Account is a user account. It is associated with a private key. @@ -296,8 +296,8 @@ func (e *wireError) error(h http.Header) *Error { } } -// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for -// customizing a temporary certificate for TLS-SNI challenges. +// CertOption is an optional argument type for the TLS ChallengeCert methods for +// customizing a temporary certificate for TLS-based challenges. type CertOption interface { privateCertOpt() } @@ -317,7 +317,7 @@ func (*certOptKey) privateCertOpt() {} // WithTemplate creates an option for specifying a certificate template. // See x509.CreateCertificate for template usage details. // -// In TLSSNIxChallengeCert methods, the template is also used as parent, +// In TLS ChallengeCert methods, the template is also used as parent, // resulting in a self-signed certificate. // The DNSNames field of t is always overwritten for tls-sni challenge certs. func WithTemplate(t *x509.Certificate) CertOption { diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go index aecf759e..b7162d82 100644 --- a/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go +++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go @@ -209,19 +209,19 @@ func TestMinorNotRequired(t *testing.T) { func BenchmarkEqual(b *testing.B) { b.StopTimer() passwd := []byte("somepasswordyoulike") - hash, _ := GenerateFromPassword(passwd, 10) + hash, _ := GenerateFromPassword(passwd, DefaultCost) b.StartTimer() for i := 0; i < b.N; i++ { CompareHashAndPassword(hash, passwd) } } -func BenchmarkGeneration(b *testing.B) { +func BenchmarkDefaultCost(b *testing.B) { b.StopTimer() passwd := []byte("mylongpassword1234") b.StartTimer() for i := 0; i < b.N; i++ { - GenerateFromPassword(passwd, 10) + GenerateFromPassword(passwd, DefaultCost) } } diff --git a/vendor/golang.org/x/crypto/blake2b/blake2x.go b/vendor/golang.org/x/crypto/blake2b/blake2x.go index c814496a..52c414db 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2x.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2x.go @@ -29,7 +29,7 @@ type XOF interface { } // OutputLengthUnknown can be used as the size argument to NewXOF to indicate -// the the length of the output is not known in advance. +// the length of the output is not known in advance. const OutputLengthUnknown = 0 // magicUnknownOutputLength is a magic value for the output size that indicates diff --git a/vendor/golang.org/x/crypto/blake2s/blake2x.go b/vendor/golang.org/x/crypto/blake2s/blake2x.go index eaff2a7f..828749ff 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2x.go +++ b/vendor/golang.org/x/crypto/blake2s/blake2x.go @@ -29,7 +29,7 @@ type XOF interface { } // OutputLengthUnknown can be used as the size argument to NewXOF to indicate -// the the length of the output is not known in advance. +// the length of the output is not known in advance. const OutputLengthUnknown = 0 // magicUnknownOutputLength is a magic value for the output size that indicates diff --git a/vendor/golang.org/x/crypto/bn256/bn256.go b/vendor/golang.org/x/crypto/bn256/bn256.go index f88f3fc3..ff27febd 100644 --- a/vendor/golang.org/x/crypto/bn256/bn256.go +++ b/vendor/golang.org/x/crypto/bn256/bn256.go @@ -97,14 +97,18 @@ func (e *G1) Neg(a *G1) *G1 { // Marshal converts n to a byte slice. func (e *G1) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if e.p.IsInfinity() { + return make([]byte, numBytes*2) + } + e.p.MakeAffine(nil) xBytes := new(big.Int).Mod(e.p.x, p).Bytes() yBytes := new(big.Int).Mod(e.p.y, p).Bytes() - // Each value is a 256-bit number. - const numBytes = 256 / 8 - ret := make([]byte, numBytes*2) copy(ret[1*numBytes-len(xBytes):], xBytes) copy(ret[2*numBytes-len(yBytes):], yBytes) @@ -205,6 +209,13 @@ func (e *G2) Add(a, b *G2) *G2 { // Marshal converts n into a byte slice. func (n *G2) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if n.p.IsInfinity() { + return make([]byte, numBytes*4) + } + n.p.MakeAffine(nil) xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes() @@ -212,9 +223,6 @@ func (n *G2) Marshal() []byte { yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes() yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes() - // Each value is a 256-bit number. - const numBytes = 256 / 8 - ret := make([]byte, numBytes*4) copy(ret[1*numBytes-len(xxBytes):], xxBytes) copy(ret[2*numBytes-len(xyBytes):], xyBytes) diff --git a/vendor/golang.org/x/crypto/bn256/curve.go b/vendor/golang.org/x/crypto/bn256/curve.go index 55b7063f..63c052bc 100644 --- a/vendor/golang.org/x/crypto/bn256/curve.go +++ b/vendor/golang.org/x/crypto/bn256/curve.go @@ -245,10 +245,19 @@ func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoi return c } +// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets +// c to 0 : 1 : 0. func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint { if words := c.z.Bits(); len(words) == 1 && words[0] == 1 { return c } + if c.IsInfinity() { + c.x.SetInt64(0) + c.y.SetInt64(1) + c.z.SetInt64(0) + c.t.SetInt64(0) + return c + } zInv := pool.Get().ModInverse(c.z, p) t := pool.Get().Mul(c.y, zInv) diff --git a/vendor/golang.org/x/crypto/bn256/gfp12.go b/vendor/golang.org/x/crypto/bn256/gfp12.go index f084eddf..2b0151eb 100644 --- a/vendor/golang.org/x/crypto/bn256/gfp12.go +++ b/vendor/golang.org/x/crypto/bn256/gfp12.go @@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 { } func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 { - e.x.Mul(e.x, b, pool) - e.y.Mul(e.y, b, pool) + e.x.Mul(a.x, b, pool) + e.y.Mul(a.y, b, pool) return e } diff --git a/vendor/golang.org/x/crypto/bn256/twist.go b/vendor/golang.org/x/crypto/bn256/twist.go index 4f8b3fed..056d80f1 100644 --- a/vendor/golang.org/x/crypto/bn256/twist.go +++ b/vendor/golang.org/x/crypto/bn256/twist.go @@ -219,10 +219,19 @@ func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoi return c } +// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets +// c to 0 : 1 : 0. func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint { if c.z.IsOne() { return c } + if c.IsInfinity() { + c.x.SetZero() + c.y.SetOne() + c.z.SetZero() + c.t.SetZero() + return c + } zInv := newGFp2(pool).Invert(c.z, pool) t := newGFp2(pool).Mul(c.y, zInv, pool) diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go index e28f49d1..bbb86efe 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539. +// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539, +// and its extended nonce variant XChaCha20-Poly1305. package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305" import ( @@ -14,15 +15,24 @@ import ( const ( // KeySize is the size of the key used by this AEAD, in bytes. KeySize = 32 - // NonceSize is the size of the nonce used with this AEAD, in bytes. + + // NonceSize is the size of the nonce used with the standard variant of this + // AEAD, in bytes. + // + // Note that this is too short to be safely generated at random if the same + // key is reused more than 2³² times. NonceSize = 12 + + // NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305 + // variant of this AEAD, in bytes. + NonceSizeX = 24 ) type chacha20poly1305 struct { key [8]uint32 } -// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key. +// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key. func New(key []byte) (cipher.AEAD, error) { if len(key) != KeySize { return nil, errors.New("chacha20poly1305: bad key length") diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go index ff21390d..2aa4fd89 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go @@ -9,6 +9,7 @@ package chacha20poly1305 import ( "encoding/binary" + "golang.org/x/crypto/internal/subtle" "golang.org/x/sys/cpu" ) @@ -19,8 +20,7 @@ func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte) var ( - useASM = cpu.X86.HasSSSE3 - useAVX2 = cpu.X86.HasAVX2 + useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2 ) // setupState writes a ChaCha20 input matrix to state. See @@ -47,7 +47,7 @@ func setupState(state *[16]uint32, key *[8]uint32, nonce []byte) { } func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte { - if !useASM { + if !cpu.X86.HasSSSE3 { return c.sealGeneric(dst, nonce, plaintext, additionalData) } @@ -55,12 +55,15 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) [] setupState(&state, &c.key, nonce) ret, out := sliceForAppend(dst, len(plaintext)+16) + if subtle.InexactOverlap(out, plaintext) { + panic("chacha20poly1305: invalid buffer overlap") + } chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData) return ret } func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { - if !useASM { + if !cpu.X86.HasSSSE3 { return c.openGeneric(dst, nonce, ciphertext, additionalData) } @@ -69,6 +72,9 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ( ciphertext = ciphertext[:len(ciphertext)-16] ret, out := sliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { + panic("chacha20poly1305: invalid buffer overlap") + } if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) { for i := range out { out[i] = 0 diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s index 1c57e389..af76bbcc 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s @@ -2693,22 +2693,3 @@ sealAVX2Tail512LoopB: VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 JMP sealAVX2SealHash - -// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuid(SB), NOSPLIT, $0-24 - MOVL eaxArg+0(FP), AX - MOVL ecxArg+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func xgetbv() (eax, edx uint32) -TEXT ·xgetbv(SB),NOSPLIT,$0-8 - MOVL $0, CX - XGETBV - MOVL AX, eax+0(FP) - MOVL DX, edx+4(FP) - RET diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go index 8d28ce27..c2797121 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go @@ -8,6 +8,7 @@ import ( "encoding/binary" "golang.org/x/crypto/internal/chacha20" + "golang.org/x/crypto/internal/subtle" "golang.org/x/crypto/poly1305" ) @@ -17,6 +18,9 @@ func roundTo16(n int) int { func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte { ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize) + if subtle.InexactOverlap(out, plaintext) { + panic("chacha20poly1305: invalid buffer overlap") + } var polyKey [32]byte s := chacha20.New(c.key, [3]uint32{ @@ -62,6 +66,9 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData [] binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext))) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { + panic("chacha20poly1305: invalid buffer overlap") + } if !poly1305.Verify(&tag, polyInput, &polyKey) { for i := range out { out[i] = 0 diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go index 78f981a7..a23af5df 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go @@ -6,9 +6,13 @@ package chacha20poly1305 import ( "bytes" - cr "crypto/rand" + "crypto/cipher" + cryptorand "crypto/rand" "encoding/hex" - mr "math/rand" + "fmt" + "log" + mathrand "math/rand" + "strconv" "testing" ) @@ -19,7 +23,18 @@ func TestVectors(t *testing.T) { ad, _ := hex.DecodeString(test.aad) plaintext, _ := hex.DecodeString(test.plaintext) - aead, err := New(key) + var ( + aead cipher.AEAD + err error + ) + switch len(nonce) { + case NonceSize: + aead, err = New(key) + case NonceSizeX: + aead, err = NewX(key) + default: + t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce)) + } if err != nil { t.Fatal(err) } @@ -42,7 +57,7 @@ func TestVectors(t *testing.T) { } if len(ad) > 0 { - alterAdIdx := mr.Intn(len(ad)) + alterAdIdx := mathrand.Intn(len(ad)) ad[alterAdIdx] ^= 0x80 if _, err := aead.Open(nil, nonce, ct, ad); err == nil { t.Errorf("#%d: Open was successful after altering additional data", i) @@ -50,14 +65,14 @@ func TestVectors(t *testing.T) { ad[alterAdIdx] ^= 0x80 } - alterNonceIdx := mr.Intn(aead.NonceSize()) + alterNonceIdx := mathrand.Intn(aead.NonceSize()) nonce[alterNonceIdx] ^= 0x80 if _, err := aead.Open(nil, nonce, ct, ad); err == nil { t.Errorf("#%d: Open was successful after altering nonce", i) } nonce[alterNonceIdx] ^= 0x80 - alterCtIdx := mr.Intn(len(ct)) + alterCtIdx := mathrand.Intn(len(ct)) ct[alterCtIdx] ^= 0x80 if _, err := aead.Open(nil, nonce, ct, ad); err == nil { t.Errorf("#%d: Open was successful after altering ciphertext", i) @@ -68,87 +83,117 @@ func TestVectors(t *testing.T) { func TestRandom(t *testing.T) { // Some random tests to verify Open(Seal) == Plaintext - for i := 0; i < 256; i++ { - var nonce [12]byte - var key [32]byte + f := func(t *testing.T, nonceSize int) { + for i := 0; i < 256; i++ { + var nonce = make([]byte, nonceSize) + var key [32]byte - al := mr.Intn(128) - pl := mr.Intn(16384) - ad := make([]byte, al) - plaintext := make([]byte, pl) - cr.Read(key[:]) - cr.Read(nonce[:]) - cr.Read(ad) - cr.Read(plaintext) + al := mathrand.Intn(128) + pl := mathrand.Intn(16384) + ad := make([]byte, al) + plaintext := make([]byte, pl) + cryptorand.Read(key[:]) + cryptorand.Read(nonce[:]) + cryptorand.Read(ad) + cryptorand.Read(plaintext) - aead, err := New(key[:]) - if err != nil { - t.Fatal(err) - } - - ct := aead.Seal(nil, nonce[:], plaintext, ad) - - plaintext2, err := aead.Open(nil, nonce[:], ct, ad) - if err != nil { - t.Errorf("Random #%d: Open failed", i) - continue - } - - if !bytes.Equal(plaintext, plaintext2) { - t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext) - continue - } - - if len(ad) > 0 { - alterAdIdx := mr.Intn(len(ad)) - ad[alterAdIdx] ^= 0x80 - if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { - t.Errorf("Random #%d: Open was successful after altering additional data", i) + var ( + aead cipher.AEAD + err error + ) + switch len(nonce) { + case NonceSize: + aead, err = New(key[:]) + case NonceSizeX: + aead, err = NewX(key[:]) + default: + t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce)) + } + if err != nil { + t.Fatal(err) } - ad[alterAdIdx] ^= 0x80 - } - alterNonceIdx := mr.Intn(aead.NonceSize()) - nonce[alterNonceIdx] ^= 0x80 - if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { - t.Errorf("Random #%d: Open was successful after altering nonce", i) - } - nonce[alterNonceIdx] ^= 0x80 + ct := aead.Seal(nil, nonce[:], plaintext, ad) - alterCtIdx := mr.Intn(len(ct)) - ct[alterCtIdx] ^= 0x80 - if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { - t.Errorf("Random #%d: Open was successful after altering ciphertext", i) + plaintext2, err := aead.Open(nil, nonce[:], ct, ad) + if err != nil { + t.Errorf("Random #%d: Open failed", i) + continue + } + + if !bytes.Equal(plaintext, plaintext2) { + t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext) + continue + } + + if len(ad) > 0 { + alterAdIdx := mathrand.Intn(len(ad)) + ad[alterAdIdx] ^= 0x80 + if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { + t.Errorf("Random #%d: Open was successful after altering additional data", i) + } + ad[alterAdIdx] ^= 0x80 + } + + alterNonceIdx := mathrand.Intn(aead.NonceSize()) + nonce[alterNonceIdx] ^= 0x80 + if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { + t.Errorf("Random #%d: Open was successful after altering nonce", i) + } + nonce[alterNonceIdx] ^= 0x80 + + alterCtIdx := mathrand.Intn(len(ct)) + ct[alterCtIdx] ^= 0x80 + if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { + t.Errorf("Random #%d: Open was successful after altering ciphertext", i) + } + ct[alterCtIdx] ^= 0x80 } - ct[alterCtIdx] ^= 0x80 } + t.Run("Standard", func(t *testing.T) { f(t, NonceSize) }) + t.Run("X", func(t *testing.T) { f(t, NonceSizeX) }) } -func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) { +func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) { + b.ReportAllocs() b.SetBytes(int64(len(buf))) var key [32]byte - var nonce [12]byte + var nonce = make([]byte, nonceSize) var ad [13]byte var out []byte - aead, _ := New(key[:]) + var aead cipher.AEAD + switch len(nonce) { + case NonceSize: + aead, _ = New(key[:]) + case NonceSizeX: + aead, _ = NewX(key[:]) + } + b.ResetTimer() for i := 0; i < b.N; i++ { out = aead.Seal(out[:0], nonce[:], buf[:], ad[:]) } } -func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) { +func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) { + b.ReportAllocs() b.SetBytes(int64(len(buf))) var key [32]byte - var nonce [12]byte + var nonce = make([]byte, nonceSize) var ad [13]byte var ct []byte var out []byte - aead, _ := New(key[:]) + var aead cipher.AEAD + switch len(nonce) { + case NonceSize: + aead, _ = New(key[:]) + case NonceSizeX: + aead, _ = NewX(key[:]) + } ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:]) b.ResetTimer() @@ -157,26 +202,54 @@ func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) { } } -func BenchmarkChacha20Poly1305Open_64(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, 64)) +func BenchmarkChacha20Poly1305(b *testing.B) { + for _, length := range []int{64, 1350, 8 * 1024} { + b.Run("Open-"+strconv.Itoa(length), func(b *testing.B) { + benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize) + }) + b.Run("Seal-"+strconv.Itoa(length), func(b *testing.B) { + benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize) + }) + + b.Run("Open-"+strconv.Itoa(length)+"-X", func(b *testing.B) { + benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX) + }) + b.Run("Seal-"+strconv.Itoa(length)+"-X", func(b *testing.B) { + benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX) + }) + } } -func BenchmarkChacha20Poly1305Seal_64(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, 64)) -} +var key = make([]byte, KeySize) -func BenchmarkChacha20Poly1305Open_1350(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, 1350)) -} +func ExampleNewX() { + aead, err := NewX(key) + if err != nil { + log.Fatalln("Failed to instantiate XChaCha20-Poly1305:", err) + } -func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350)) -} + for _, msg := range []string{ + "Attack at dawn.", + "The eagle has landed.", + "Gophers, gophers, gophers everywhere!", + } { + // Encryption. + nonce := make([]byte, NonceSizeX) + if _, err := cryptorand.Read(nonce); err != nil { + panic(err) + } + ciphertext := aead.Seal(nil, nonce, []byte(msg), nil) -func BenchmarkChacha20Poly1305Open_8K(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024)) -} + // Decryption. + plaintext, err := aead.Open(nil, nonce, ciphertext, nil) + if err != nil { + log.Fatalln("Failed to decrypt or authenticate message:", err) + } -func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024)) + fmt.Printf("%s\n", plaintext) + } + + // Output: Attack at dawn. + // The eagle has landed. + // Gophers, gophers, gophers everywhere! } diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go index 49f0da6b..fa3607e8 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go @@ -7,6 +7,13 @@ package chacha20poly1305 var chacha20Poly1305Tests = []struct { plaintext, aad, key, nonce, out string }{ + { + "", + "", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "070000004041424344454647", + "a0784d7a4716f3feb4f64e7f4b39bf04", + }, { "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e", "50515253c0c1c2c3c4c5c6c7", @@ -329,4 +336,391 @@ var chacha20Poly1305Tests = []struct { "129039b5572e8a7a8131f76a", "2c125232a59879aee36cacc4aca5085a4688c4f776667a8fbd86862b5cfb1d57c976688fdd652eafa2b88b1b8e358aa2110ff6ef13cdc1ceca9c9f087c35c38d89d6fbd8de89538070f17916ecb19ca3ef4a1c834f0bdaa1df62aaabef2e117106787056c909e61ecd208357dd5c363f11c5d6cf24992cc873cf69f59360a820fcf290bd90b2cab24c47286acb4e1033962b6d41e562a206a94796a8ab1c6b8bade804ff9bdf5ba6062d2c1f8fe0f4dfc05720bd9a612b92c26789f9f6a7ce43f5e8e3aee99a9cd7d6c11eaa611983c36935b0dda57d898a60a0ab7c4b54", }, + + // XChaCha20-Poly1305 vectors + { + "000000000000000000000000000000", + "", + "0000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000", + "789e9689e5208d7fd9e1f3c5b5341fb2f7033812ac9ebd3745e2c99c7bbfeb", + }, + { + "02dc819b71875e49f5e1e5a768141cfd3f14307ae61a34d81decd9a3367c00c7", + "", + "b7bbfe61b8041658ddc95d5cbdc01bbe7626d24f3a043b70ddee87541234cff7", + "e293239d4c0a07840c5f83cb515be7fd59c333933027e99c", + "7a51f271bd2e547943c7be3316c05519a5d16803712289aa2369950b1504dd8267222e47b13280077ecada7b8795d535", + }, + { + "7afc5f3f24155002e17dc176a8f1f3a097ff5a991b02ff4640f70b90db0c15c328b696d6998ea7988edfe3b960e47824e4ae002fbe589be57896a9b7bf5578599c6ba0153c7c", + "d499bb9758debe59a93783c61974b7", + "4ea8fab44a07f7ffc0329b2c2f8f994efdb6d505aec32113ae324def5d929ba1", + "404d5086271c58bf27b0352a205d21ce4367d7b6a7628961", + "26d2b46ad58b6988e2dcf1d09ba8ab6f532dc7e0847cdbc0ed00284225c02bbdb278ee8381ebd127a06926107d1b731cfb1521b267168926492e8f77219ad922257a5be2c5e52e6183ca4dfd0ad3912d7bd1ec968065", + }, + { + "", + "", + "48d8bd02c2e9947eae58327114d35e055407b5519c8019535efcb4fc875b5e2b", + "cc0a587a475caba06f8dbc09afec1462af081fe1908c2cba", + "fc3322d0a9d6fac3eb4a9e09b00b361e", + }, + { + "e0862731e5", + "", + "6579e7ee96151131a1fcd06fe0d52802c0021f214960ecceec14b2b8591f62cd", + "e2230748649bc22e2b71e46a7814ecabe3a7005e949bd491", + "e991efb85d8b1cfa3f92cb72b8d3c882e88f4529d9", + }, + { + "00c7dd8f440af1530b44", + "", + "ffb733657c849d50ab4ab40c4ae18f8ee2f0acf7c907afefdc04dff3537fdff3", + "02c6fd8032a8d89edbedcd1db024c09d29f08b1e74325085", + "13dbcdb8c60c3ed28449a57688edfaea89e309ab4faa6d51e532", + }, + { + "7422f311ea476cf819cb8b3c77369f", + "", + "ef0d05d028d6abdd5e99d1761d2028de75ee6eb376ff0dc8036e9a8e10743876", + "f772745200b0f92e38f1d8dae79bf8138e84b301f0be74df", + "d5f992f9834df1be86b580ac59c7eae063a68072829c51bc8a26970dd3d310", + }, + { + "ba09ca69450e6c7bece31a7a3f216e3b9ed0e536", + "", + "8d93e31abfe22a63faf45cbea91877050718f13fef6e2664a1892d7f23007ccf", + "260b7b3554a7e6ff8aae7dd6234077ca539689a20c1610a8", + "c99e9a768eb2ec8569bdff8a37295069552faebcafb1a76e98bc7c5b6b778b3d1b6291f0", + }, + { + "424ec5f98a0fdc5a7388532d11ab0edb26733505627b7f2d1f", + "", + "b68d5e6c46cdbb0060445522bdc5c562ae803b6aaaf1e103c146e93527a59299", + "80bb5dc1dd44a35ec4f91307f1a95b4ca31183a1a596fb7c", + "29d4eed0fff0050d4bb40de3b055d836206e7cbd62de1a63904f0cf731129ba3f9c2b9d46251a6de89", + }, + { + "e7e4515cc0a6ef0491af983eaac4f862d6e726758a3c657f4ec444841e42", + "", + "e31a1d3af650e8e2848bd78432d89ecd1fdece9842dc2792e7bda080f537b17b", + "f3f09905e9a871e757348834f483ed71be9c0f437c8d74b0", + "f5c69528963e17db725a28885d30a45194f12848b8b7644c7bded47a2ee83e6d4ef34006305cfdf82effdced461d", + }, + { + "0f5ca45a54875d1d19e952e53caeaa19389342f776dab11723535503338d6f77202a37", + "", + "1031bc920d4fcb4434553b1bf2d25ab375200643bf523ff037bf8914297e8dca", + "4cc77e2ef5445e07b5f44de2dc5bf62d35b8c6f69502d2bf", + "7aa8669e1bfe8b0688899cdddbb8cee31265928c66a69a5090478da7397573b1cc0f64121e7d8bff8db0ddd3c17460d7f29a12", + }, + { + "c45578c04c194994e89025c7ffb015e5f138be3cd1a93640af167706aee2ad25ad38696df41ad805", + "", + "ac8648b7c94328419c668ce1c57c71893adf73abbb98892a4fc8da17400e3a5e", + "4ad637facf97af5fc03207ae56219da9972858b7430b3611", + "49e093fcd074fb67a755669119b8bd430d98d9232ca988882deeb3508bde7c00160c35cea89092db864dcb6d440aefa5aacb8aa7b9c04cf0", + }, + { + "b877bfa192ea7e4c7569b9ee973f89924d45f9d8ed03c7098ad0cad6e7880906befedcaf6417bb43efabca7a2f", + "", + "125e331d5da423ecabc8adf693cdbc2fc3d3589740d40a3894f914db86c02492", + "913f8b2f08006e6260de41ec3ee01d938a3e68fb12dc44c4", + "1be334253423c90fc8ea885ee5cd3a54268c035ba8a2119e5bd4f7822cd7bf9cb4cec568d5b6d6292606d32979e044df3504e6eb8c0b2fc7e2a0e17d62", + }, + { + "d946484a1df5f85ff72c92ff9e192660cde5074bd0ddd5de900c35eb10ed991113b1b19884631bc8ceb386bcd83908061ce9", + "", + "b7e83276373dcf8929b6a6ea80314c9de871f5f241c9144189ee4caf62726332", + "f59f9d6e3e6c00720dc20dc21586e8330431ebf42cf9180e", + "a38a662b18c2d15e1b7b14443cc23267a10bee23556b084b6254226389c414069b694159a4d0b5abbe34de381a0e2c88b947b4cfaaebf50c7a1ad6c656e386280ad7", + }, + { + "d266927ca40b2261d5a4722f3b4da0dd5bec74e103fab431702309fd0d0f1a259c767b956aa7348ca923d64c04f0a2e898b0670988b15e", + "", + "a60e09cd0bea16f26e54b62b2908687aa89722c298e69a3a22cf6cf1c46b7f8a", + "92da9d67854c53597fc099b68d955be32df2f0d9efe93614", + "9dd6d05832f6b4d7f555a5a83930d6aed5423461d85f363efb6c474b6c4c8261b680dea393e24c2a3c8d1cc9db6df517423085833aa21f9ab5b42445b914f2313bcd205d179430", + }, + { + "f7e11b4d372ed7cb0c0e157f2f9488d8efea0f9bbe089a345f51bdc77e30d1392813c5d22ca7e2c7dfc2e2d0da67efb2a559058d4de7a11bd2a2915e", + "", + "194b1190fa31d483c222ec475d2d6117710dd1ac19a6f1a1e8e894885b7fa631", + "6b07ea26bb1f2d92e04207b447f2fd1dd2086b442a7b6852", + "25ae14585790d71d39a6e88632228a70b1f6a041839dc89a74701c06bfa7c4de3288b7772cb2919818d95777ab58fe5480d6e49958f5d2481431014a8f88dab8f7e08d2a9aebbe691430011d", + }, + { + "", + "1e2b11e3", + "70cd96817da85ede0efdf03a358103a84561b25453dee73735e5fb0161b0d493", + "5ddeba49f7266d11827a43931d1c300dd47a3c33f9f8bf9b", + "592fc4c19f3cddec517b2a00f9df9665", + }, + { + "81b3cb7eb3", + "efcfd0cf", + "a977412f889281a6d75c24186f1bfaa00dcc5132f0929f20ef15bbf9e63c4c91", + "3f26ca997fb9166d9c615babe3e543ca43ab7cab20634ac5", + "8e4ade3e254cf52e93eace5c46667f150832725594", + }, + { + "556f97f2ebdb4e949923", + "f7cee2e0", + "787b3e86546a51028501c801dadf8d5b996fd6f6f2363d5d0f900c44f6a2f4c2", + "7fa6af59a779657d1cada847439ea5b92a1337cfbebbc3b1", + "608ec22dae5f48b89d6f0d2a940d5a7661e0a8e68aaee4ad2d96", + }, + { + "c06847a36ad031595b60edd44dc245", + "d4175e1f", + "16de31e534dd5af32801b1acd0ec541d1f8d82bcbc3af25ec815f3575b7aca73", + "29f6656972838f56c1684f6a278f9e4e207b51d68706fc25", + "836082cc51303e500fceade0b1a18f1d97d64ff41cc81754c07d6231b9fd1b", + }, + { + "0d03c22ced7b29c6741e72166cd61792028dfc80", + "e505dad0", + "ac2b426e5c5c8e00666180a3410e8a2f6e52247a43aecea9622163e8433c93b2", + "c1123430468228625967bbc0fbd0f963e674372259ff2deb", + "bf09979bf4fed2eec6c97f6e1bcfac35eeffc6d54a55cc1d83d8767ae74db2d7cdfbc371", + }, + { + "05bf00e1707cffe7ccbd06a9f846d0fd471a700ed43b4facb8", + "d863bebe", + "66c121f0f84b95ba1e6d29e7d81900bc96a642421b9b6105ae5eb5f2e7b07577", + "8ed6ae211a661e967995b71f7316ba88f44322bb62b4187b", + "b2c5c85d087e0305e9058fba52b661fb3d7f21cb4d4915ae048bc9e5d66a2f921dd4a1c1b030f442c9", + }, + { + "5f2b91a9be8bfaa21451ddc6c5cf28d1cc00b046b76270b95cda3c280c83", + "a8750275", + "39592eb276877fca9dd11e2181c0b23127328407e3cc11e315e5d748f43529cc", + "1084bebd756f193d9eea608b3a0193a5028f8ced19684821", + "eaee1f49ac8468154c601a5dd8b84d597602e5a73534b5fad5664f97d0f017dd114752be969679cf610340c6a312", + }, + { + "01e8e269b5376943f3b2d245483a76461dc8b7634868b559165f5dbb20839029fae9bb", + "a1e96da0", + "b8386123b87e50d9d046242cf1bf141fce7f65aff0fba76861a2bc72582d6ff0", + "0fbe2a13a89bea031de96d78f9f11358ba7b6a5e724b4392", + "705ec3f910ec85c6005baa99641de6ca43332ff52b5466df6af4ffbe4ef2a376a8f871d1eae503b5896601fee005cdc1f4c1c6", + }, + { + "706daba66e2edb1f828f3c0051e3cc214b12210bde0587bba02580f741a4c83e84d4e9fe961120cd", + "87663c5a", + "d519d82ba8a3f0c3af9efe36682b62e285167be101a526c1d73000f169c2a486", + "ad651aac536978e2bc1a54816345ac5e9a9b43b3d9cc0bfc", + "07051b5e72da9c4811beb07ff9f95aece67eae18420eb3f0e8bb8a5e26d4b483fa40eb063a2354842d0c8a41d981cc2b77c530b496db01c8", + }, + { + "1f6b24f2f0d9eb460d726bed953d66fcc4ecc29da6ed2fd711358eac3b2609d74ba3e21885156cde3cbe6d9b6f", + "f5efbc4e", + "86068a00544f749ad4ad15bb8e427ae78577ae22f4ca9778efff828ba10f6b20", + "c8420412c9626dcd34ece14593730f6aa2d01ec51cacd59f", + "a99f6c88eac35bb34439e34b292fe9db8192446dcdc81e2192060ec36d98b47de2bee12bf0f67cb24fb0949c07733a6781cd9455cdc61123f506886b04", + }, + { + "d69389d83362be8c0ddb738659a6cc4bd65d88cb5b525232f4d59a7d4751a7203c254923ecb6873e803220aab19664789a63", + "bc35fb1c", + "835855b326a98682b3075b4d7f1b89059c3cdfc547d4296c80ce7a77ba6434e3", + "c27cb75fc319ba431cbaeb120341d0c4745d883eb47e92bc", + "db6dc3f9a0f4f1a6df2495a88910550c2c6205478bfc1e81282e34b5b36d984c72c0509c522c987c61d2e640ced69402a6d33aa10d3d0b81e680b3c19bc142e81923", + }, + { + "a66a7f089115ed9e2d5bb5d33d7282a7afe401269b00f2a233a59c04b794a42901d862140b61d18d7c7f0ad5da040613e557f8abc74219", + "2c060aaf", + "99758aa7714fd707931f71803eefe04a06955041308a0b2a1104313b270ccf34", + "63f690d8926408c7a34fe8ddd505a8dc58769dc74e8d5da6", + "92b21ee85afcd8996ac28f3aed1047ad814d6e4ffbca3159af16f26eded83e4abda9e4275eb3ff0ad90dffe09f2d443b628f824f680b46527ce0128e8de1920f7c44350ebe7913", + }, + { + "f955183b1f762d4536d3f6885ea7f5ac27414caf46c2e24a2fd3bd56b91c53d840fb657224565e0a6f686f8ba320e04a401057399d9a3d995ab17c13", + "c372ddc5", + "a188be3795b2ca2e69b6aa263244f0963c492d694cf6c9b705a1d7045f3f2a26", + "51bb484ea094ee140474681e1c838e4442fd148de2cc345a", + "48759a5ddfdd829d11de8e0c538ce4a9c475faab6912039b568ad92d737d172fc1eb0c00c3793de6dddbfacfdbbc7f44aeba33684e18005aa982b6fc6c556e63bb90ff7a1dde8153a63eabe0", + }, + { + "", + "e013cd0bfafd486d", + "af3d3ba094d38299ecb91c17bfe3d085da5bd42e11acf8acb5bc26a4be9a7583", + "7dd63c14173831f109761b1c1abe18f6ba937d825957011b", + "8bc685a7d9d501952295cd25d8c92517", + }, + { + "284b64597e", + "31d013e53aa3ea79", + "93c77409d7f805f97fe683b2dd6ee06152a5e918b3eed5b731acccffdcb2cc04", + "3d331e90c4597cf0c30d1b7cfbd07bcb6ab927eda056873c", + "3538a449d6c18d148a8c6cb76f1bc288657ac7036a", + }, + { + "9fe67f5c78180ede8274", + "188608d230d75860", + "b7cca89a82640aea6f80b458c9e633d88594fb498959d39787be87030892d48f", + "ef891d50e8c08958f814590fdb7a9f16c61cc2aae1682109", + "bbb40c30f3d1391a5b38df480cbbf964b71e763e8140751f4e28", + }, + { + "3a2826b6f7e3d542e4ded8f23c9aa4", + "260033e789c4676a", + "7fe2731214f2b4b42f93217d43f1776498413725e4f6cfe62b756e5a52df10ea", + "888728219ebf761547f5e2218532714403020e5a8b7a49d0", + "fe0328f883fcd88930ae017c0f54ed90f883041efc020e959125af370c1d47", + }, + { + "91858bf7b969005d7164acbd5678052b651c53e0", + "f3cc53ecafcbadb3", + "d69c04e9726b22d51f97bc9da0f0fda86736e6b78e8ef9f6f0000f79890d6d43", + "6de3c45161b434e05445cf6bf69eef7bddf595fc6d8836bd", + "a8869dd578c0835e120c843bb7dedc7a1e9eae24ffd742be6bf5b74088a8a2c550976fcb", + }, + { + "b3b1a4d6b2a2b9c5a1ca6c1efaec34dcfa1acbe7074d5e10cc", + "d0f72bd16cda3bae", + "2b317857b089c9305c49b83019f6e158bc4ecc3339b39ade02ee10c37c268da0", + "cb5fa6d1e14a0b4bdf350cd10c8a7bd638102911ec74be09", + "e6372f77c14343650074e07a2b7223c37b29242224b722b24d63b5956f27aa64ce7ce4e39cd14a2787", + }, + { + "057d3e9f865be7dff774938cab6d080e50cf9a1593f53c0063201e0bb7ae", + "fd3881e505c8b12d", + "36e42b1ef1ee8d068f09b5fad3ee43d98d34aa3e3f994f2055aee139da71de9d", + "24124da36473d01bdca30297c9eef4fe61955525a453da17", + "a8b28139524c98c1f8776f442eac4c22766fe6aac83224641c58bf021fc9cb709ec4706f49c2d0c1828acf2bfe8d", + }, + { + "bd8f13e928c34d67a6c70c3c7efdf2982ecc31d8cee68f9cbddc75912cd828ac93d28b", + "193206c8fcc5b19b", + "6e47c40c9d7b757c2efca4d73890e4c73f3c859aab4fdc64b564b8480dd84e72", + "ca31340ae20d30fe488be355cb36652c5db7c9d6265a3e95", + "a121efc5e1843deade4b8adbfef1808de4eda222f176630ad34fb476fca19e0299e4a13668e53cf13882035ba4f04f47c8b4e3", + }, + { + "23067a196e977d10039c14ff358061c918d2148d31961bb3e12c27c5122383cb25c4d1d79c775720", + "62338d02fff78a00", + "2c5c79c92d91fb40ef7d0a77e8033f7b265e3bab998b8116d17b2e62bb4f8a09", + "024736adb1d5c01006dffd8158b57936d158d5b42054336d", + "46d0905473a995d38c7cdbb8ef3da96ecc82a22c5b3c6c9d1c4a61ae7a17db53cb88c5f7eccf2da1d0c417c300f989b4273470e36f03542f", + }, + { + "252e966c680329eb687bff813b78fea3bfd3505333f106c6f9f45ba69896723c41bb763793d9b266e897d05557", + "1e93e0cfe6523380", + "9ec6fd1baa13ee16aec3fac16718a2baccf18a403cec467c25b7448e9b321110", + "e7120b1018ab363a36e61102eedbcbe9847a6cbacaa9c328", + "2934f034587d4144bb11182679cd2cd1c99c8088d18e233379e9bc9c41107a1f57a2723ecc7b9ba4e6ee198adf0fd766738e828827dc73136fc5b996e9", + }, + { + "6744aefcb318f12bc6eeb59d4d62f7eb95f347cea14bd5158415f07f84e4e3baa3de07512d9b76095ac1312cfcb1bb77f499", + "608d2a33ce5d0b04", + "0f665cbdaaa40f4f5a00c53d951b0a98aac2342be259a52670f650a783be7aab", + "378bdb57e957b8c2e1500c9513052a3b02ff5b7edbd4a3a7", + "341c60fcb374b394f1b01a4a80aedef49ab0b67ec963675e6eec43ef106f7003be87dbf4a8976709583dccc55abc7f979c4721837e8664a69804ea31736aa2af615a", + }, + { + "bcf1004f988220b7ce063ef2ec4e276ffd074f0a90aa807de1532679d2a1505568eaa4192d9a6ea52cc500322343ce9f8e68cc2c606d83", + "e64bd00126c8792c", + "58e65150d6a15dcefbc14a171998987ad0d709fb06a17d68d6a778759681c308", + "106d2bd120b06e4eb10bc674fe55c77a3742225268319303", + "a28052a6686a1e9435fee8702f7da563a7b3d7b5d3e9e27f11abf73db309cd1f39a34756258c1c5c7f2fb12cf15eb20175c2a08fc93dd19c5e482ef3fbef3d8404a3cfd54a7baf", + }, + { + "acd08d4938a224b4cb2d723bf75420f3ea27b698fadd815bb7db9548a05651398644354334e69f8e4e5503bf1a6f92b38e860044a7edca6874038ce1", + "28a137808d0225b8", + "a031203b963a395b08be55844d81af39d19b23b7cc24b21afa31edc1eea6edd6", + "e8b31c52b6690f10f4ae62ba9d50ba39fb5edcfb78400e35", + "35cf39ba31da95ac9b661cdbd5e9c9655d13b8ff065c4ec10c810833a47a87d8057dd1948a7801bfe6904b49fed0aabfb3cd755a1a262d372786908ddcf64cae9f71cb9ed199c3ddacc50116", + }, + { + "", + "cda7ee2857e09e9054ef6806", + "d91dffb18132d8dd3d144a2f10ba28bc5df36cb60369f3b19893ec91db3cf904", + "ee56f19c62b0438da6a0d9e01844313902be44f84a6a4ce7", + "ccd48b61a5683c195d4424009eb1d147", + }, + { + "350f4c7ac2", + "7c104b539c1d2ae022434cd6", + "cbb61e369117f9250f68fa707240c554359262a4d66c757f80e3aeb6920894fb", + "fbb14c9943444eac5413c6f5c8095451eddece02c9461043", + "b5c6a35865ed8e5216ff6c77339ee1ab570de50e51", + }, + { + "4f0d61d3ea03a44a8df0", + "51c20a8ae9e9794da931fe23", + "ba6ced943aa62f9261d7513b822e02054e099acafb5360f0d850064da48b5a4f", + "04c68cb50cdbb0ec03f8381cf59b886e64c40548bf8e3f82", + "ea45a73957e2a853655623f2a3bb58791f7ea36dd2957ed66ffa", + }, + { + "4fbdd4d4293a8f34fdbc8f3ad44cf6", + "8212f315e3759c3253c588bb", + "5354791bc2370415811818e913e310dd12e6a0cf5dcab2b6424816eecccf4b65", + "7ee6353c2fbc73c9ebc652270bc86e4008e09583e623e679", + "50a354811a918e1801fb567621a8924baf8dd79da6d36702855d3753f1319c", + }, + { + "5a6f68b5a9a9920ca9c6edf5be7c0af150a063c4", + "9a524aa62938fb7a1e50ed06", + "fd91605a6ad85d8ba7a71b08dce1032aa9992bf4f28d407a53ddda04c043cada", + "46791d99d6de33e79025bf9e97c198e7cf409614c6284b4d", + "648033c1eb615467e90b7d3ac24202d8b849549141f9bab03e9e910c29b8eab3d4fb3f2c", + }, + { + "d9318c2c0d9ed89e35d242a6b1d496e7e0c5bbdf77eba14c56", + "a16053c35fbe8dc93c14a81f", + "f21406aec83134ebf7bc48c6d0f45acb5f341fbc7d3b5a9bff3ea1333c916af7", + "de6b977be450d5efa7777e006802ddbb10814a22da1c3cd9", + "8d3dad487d5161663da830b71c3e24ec5cdb74d858cbb73b084ed0902198532aad3a18416966bff223", + }, + { + "68d0ee08d38cb4bcc9268fee3030666e70e41fcabf6fe06536eeec43eec5", + "11e09447d40b22dc98070eec", + "da5ee1ec02eab13220fcb94f16efec848a8dd57c0f4d67955423f5d17fde5aa3", + "8f13e61d773a250810f75d46bf163a3f9205be5751f6049a", + "92a103b03764c1ad1f88500d22eeae5c0fe1044c872987c0b97affc5e8c3d783f8cc28a11dc91990ea22dd1bad74", + }, + { + "a1d960bda08efcf19e136dc1e8b05b6b381c820eda5f9a8047e1a2dd1803a1e4d11a7f", + "aa73d8d4aaa0cfd9d80a9ae8", + "08028833d617c28ba75b48f177cb5da87189189abb68dcb8974eca9230c25945", + "f7b6f34a910fd11588f567de8555932291f7df05f6e2b193", + "99cfc4cca193998bae153b744e6c94a82a2867780aa0f43acddb7c433fcb297311313ec2199f00d7ca7da0646b40113c60e935", + }, + { + "3b4ae39a745b6247ce5baf675ec36c5065b1bf76c8379eab4b769961d43a753896d068938017777e", + "128c017a985052f8cdbc6b28", + "4683d5caff613187a9b16af897253848e9c54fc0ec319de62452a86961d3cbb2", + "5612a13c2da003b91188921cbac3fa093eba99d8cbbb51ff", + "91a98b93b2174257175f7c882b45cc252e0db8667612bd270c1c12fe28b6bf209760bf8f370318f92ae3f88a5d4773b05714132cc28dddb8", + }, + { + "22ccf680d2995ef6563de281cff76882a036a59ad73f250e710b3040590d69bccde8a8411abe8b0d3cb728ca82", + "13a97d0a167a61aa21e531ec", + "9e140762eed274948b66de25e6e8f36ab65dc730b0cb096ef15aaba900a5588c", + "d0e9594cfd42ab72553bf34062a263f588bb8f1fc86a19f5", + "f194fc866dfba30e42c4508b7d90b3fa3f8983831ede713334563e36aa861f2f885b40be1dbe20ba2d10958a12823588d4bbbefb81a87d87315204f5e3", + }, + { + "a65f5d10c482b3381af296e631eb605eba6a11ccec6ceab021460d0bd35feb676ec6dbba5d4ad6c9f4d683ea541035bc80fa", + "f15ae71ffed50a8fcc4996b0", + "f535d60e8b75ac7e526041eed86eb4d65ae7e315eff15dba6c0133acc2a6a4bf", + "01ba61691ebb3c66d2f94c1b1c597ecd7b5ff7d2a30be405", + "d79e7c3893df5a5879c2f0a3f7ca619f08e4540f3ac7db35790b4211b9d47ae735adadf35fd47252a4763e3fd2b2cd8157f6ea7986108a53437962670a97d68ee281", + }, + { + "8c014655b97f6da76b0b168b565fd62de874c164fd7e227346a0ec22c908bed1e2a0b429620e6f3a68dd518f13a2c0250608a1cb08a7c3", + "10a7eff999029c5040c1b3bd", + "bf11af23e88c350a443493f6fa0eb34f234f4daa2676e26f0701bce5642d13f4", + "f14c97392afd2e32e2c625910ca029f9b6e81676c79cc42f", + "78d5226f372d5d60681dbfc749d12df74249f196b0cbf14fa65a3a59dc65ae458455ec39baa1df3397afe752bb06f6f13bf03c99abda7a95c1d0b73fd92d5f888a5f6f889a9aea", + }, + { + "66234d7a5b71eef134d60eccf7d5096ee879a33983d6f7a575e3a5e3a4022edccffe7865dde20b5b0a37252e31cb9a3650c63e35b057a1bc200a5b5b", + "ccc2406f997bcae737ddd0f5", + "d009eeb5b9b029577b14d200b7687b655eedb7d74add488f092681787999d66d", + "99319712626b400f9458dbb7a9abc9f5810f25b47fc90b39", + "543a2bbf52fd999027ae7c297353f3ce986f810bc2382583d0a81fda5939e4c87b6e8d262790cd614d6f753d8035b32adf43acc7f6d4c2c44289538928564b6587c2fcb99de1d8e34ffff323", + }, } diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go new file mode 100644 index 00000000..a02fa571 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go @@ -0,0 +1,104 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package chacha20poly1305 + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + + "golang.org/x/crypto/internal/chacha20" +) + +type xchacha20poly1305 struct { + key [8]uint32 +} + +// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key. +// +// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce, +// suitable to be generated randomly without risk of collisions. It should be +// preferred when nonce uniqueness cannot be trivially ensured, or whenever +// nonces are randomly generated. +func NewX(key []byte) (cipher.AEAD, error) { + if len(key) != KeySize { + return nil, errors.New("chacha20poly1305: bad key length") + } + ret := new(xchacha20poly1305) + ret.key[0] = binary.LittleEndian.Uint32(key[0:4]) + ret.key[1] = binary.LittleEndian.Uint32(key[4:8]) + ret.key[2] = binary.LittleEndian.Uint32(key[8:12]) + ret.key[3] = binary.LittleEndian.Uint32(key[12:16]) + ret.key[4] = binary.LittleEndian.Uint32(key[16:20]) + ret.key[5] = binary.LittleEndian.Uint32(key[20:24]) + ret.key[6] = binary.LittleEndian.Uint32(key[24:28]) + ret.key[7] = binary.LittleEndian.Uint32(key[28:32]) + return ret, nil +} + +func (*xchacha20poly1305) NonceSize() int { + return NonceSizeX +} + +func (*xchacha20poly1305) Overhead() int { + return 16 +} + +func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if len(nonce) != NonceSizeX { + panic("chacha20poly1305: bad nonce length passed to Seal") + } + + // XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no + // size limit. However, since we reuse the ChaCha20-Poly1305 implementation, + // the second half of the counter is not available. This is unlikely to be + // an issue because the cipher.AEAD API requires the entire message to be in + // memory, and the counter overflows at 256 GB. + if uint64(len(plaintext)) > (1<<38)-64 { + panic("chacha20poly1305: plaintext too large") + } + + hNonce := [4]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + binary.LittleEndian.Uint32(nonce[12:16]), + } + c := &chacha20poly1305{ + key: chacha20.HChaCha20(&x.key, &hNonce), + } + // The first 4 bytes of the final nonce are unused counter space. + cNonce := make([]byte, NonceSize) + copy(cNonce[4:12], nonce[16:24]) + + return c.seal(dst, cNonce[:], plaintext, additionalData) +} + +func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if len(nonce) != NonceSizeX { + panic("chacha20poly1305: bad nonce length passed to Open") + } + if len(ciphertext) < 16 { + return nil, errOpen + } + if uint64(len(ciphertext)) > (1<<38)-48 { + panic("chacha20poly1305: ciphertext too large") + } + + hNonce := [4]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + binary.LittleEndian.Uint32(nonce[12:16]), + } + c := &chacha20poly1305{ + key: chacha20.HChaCha20(&x.key, &hNonce), + } + // The first 4 bytes of the final nonce are unused counter space. + cNonce := make([]byte, NonceSize) + copy(cNonce[4:12], nonce[16:24]) + + return c.open(dst, cNonce[:], ciphertext, additionalData) +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/builder.go b/vendor/golang.org/x/crypto/cryptobyte/builder.go index 29b4c764..ca7b1db5 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/builder.go +++ b/vendor/golang.org/x/crypto/cryptobyte/builder.go @@ -50,8 +50,14 @@ func NewFixedBuilder(buffer []byte) *Builder { } } +// SetError sets the value to be returned as the error from Bytes. Writes +// performed after calling SetError are ignored. +func (b *Builder) SetError(err error) { + b.err = err +} + // Bytes returns the bytes written by the builder or an error if one has -// occurred during during building. +// occurred during building. func (b *Builder) Bytes() ([]byte, error) { if b.err != nil { return nil, b.err @@ -94,7 +100,7 @@ func (b *Builder) AddBytes(v []byte) { b.add(v...) } -// BuilderContinuation is continuation-passing interface for building +// BuilderContinuation is a continuation-passing interface for building // length-prefixed byte sequences. Builder methods for length-prefixed // sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation // supplied to them. The child builder passed to the continuation can be used @@ -268,9 +274,11 @@ func (b *Builder) flushChild() { return } - if !b.fixedSize { - b.result = child.result // In case child reallocated result. + if b.fixedSize && &b.result[0] != &child.result[0] { + panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer") } + + b.result = child.result } func (b *Builder) add(bytes ...byte) { @@ -278,7 +286,7 @@ func (b *Builder) add(bytes ...byte) { return } if b.child != nil { - panic("attempted write while child is pending") + panic("cryptobyte: attempted write while child is pending") } if len(b.result)+len(bytes) < len(bytes) { b.err = errors.New("cryptobyte: length overflow") @@ -290,6 +298,26 @@ func (b *Builder) add(bytes ...byte) { b.result = append(b.result, bytes...) } +// Unwrite rolls back n bytes written directly to the Builder. An attempt by a +// child builder passed to a continuation to unwrite bytes from its parent will +// panic. +func (b *Builder) Unwrite(n int) { + if b.err != nil { + return + } + if b.child != nil { + panic("cryptobyte: attempted unwrite while child is pending") + } + length := len(b.result) - b.pendingLenLen - b.offset + if length < 0 { + panic("cryptobyte: internal error") + } + if n > length { + panic("cryptobyte: attempted to unwrite more than was written") + } + b.result = b.result[:len(b.result)-n] +} + // A MarshalingValue marshals itself into a Builder. type MarshalingValue interface { // Marshal is called by Builder.AddValue. It receives a pointer to a builder diff --git a/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go b/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go index f294dd55..fb637091 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go +++ b/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go @@ -327,12 +327,14 @@ func TestWriteWithPendingChild(t *testing.T) { var b Builder b.AddUint8LengthPrefixed(func(c *Builder) { c.AddUint8LengthPrefixed(func(d *Builder) { - defer func() { - if recover() == nil { - t.Errorf("recover() = nil, want error; c.AddUint8() did not panic") - } + func() { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; c.AddUint8() did not panic") + } + }() + c.AddUint8(2) // panics }() - c.AddUint8(2) // panics defer func() { if recover() == nil { @@ -351,6 +353,92 @@ func TestWriteWithPendingChild(t *testing.T) { }) } +func TestSetError(t *testing.T) { + const errorStr = "TestSetError" + var b Builder + b.SetError(errors.New(errorStr)) + + ret, err := b.Bytes() + if ret != nil { + t.Error("expected nil result") + } + if err == nil { + t.Fatal("unexpected nil error") + } + if s := err.Error(); s != errorStr { + t.Errorf("expected error %q, got %v", errorStr, s) + } +} + +func TestUnwrite(t *testing.T) { + var b Builder + b.AddBytes([]byte{1, 2, 3, 4, 5}) + b.Unwrite(2) + if err := builderBytesEq(&b, 1, 2, 3); err != nil { + t.Error(err) + } + + func() { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.Unwrite() did not panic") + } + }() + b.Unwrite(4) // panics + }() + + b = Builder{} + b.AddBytes([]byte{1, 2, 3, 4, 5}) + b.AddUint8LengthPrefixed(func(b *Builder) { + b.AddBytes([]byte{1, 2, 3, 4, 5}) + + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.Unwrite() did not panic") + } + }() + b.Unwrite(6) // panics + }) + + b = Builder{} + b.AddBytes([]byte{1, 2, 3, 4, 5}) + b.AddUint8LengthPrefixed(func(c *Builder) { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.Unwrite() did not panic") + } + }() + b.Unwrite(2) // panics (attempted unwrite while child is pending) + }) +} + +func TestFixedBuilderLengthPrefixed(t *testing.T) { + bufCap := 10 + inner := bytes.Repeat([]byte{0xff}, bufCap-2) + buf := make([]byte, 0, bufCap) + b := NewFixedBuilder(buf) + b.AddUint16LengthPrefixed(func(b *Builder) { + b.AddBytes(inner) + }) + if got := b.BytesOrPanic(); len(got) != bufCap { + t.Errorf("Expected output length to be %d, got %d", bufCap, len(got)) + } +} + +func TestFixedBuilderPanicReallocate(t *testing.T) { + defer func() { + recover() + }() + + b := NewFixedBuilder(make([]byte, 0, 10)) + b1 := NewFixedBuilder(make([]byte, 0, 10)) + b.AddUint16LengthPrefixed(func(b *Builder) { + *b = *b1 + }) + + t.Error("Builder did not panic") +} + // ASN.1 func TestASN1Int64(t *testing.T) { diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go index a57771a1..d6f683ba 100644 --- a/vendor/golang.org/x/crypto/ed25519/ed25519.go +++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go @@ -6,7 +6,10 @@ // https://ed25519.cr.yp.to/. // // These functions are also compatible with the “Ed25519” function defined in -// RFC 8032. +// RFC 8032. However, unlike RFC 8032's formulation, this package's private key +// representation includes a public key suffix to make multiple signing +// operations with the same key more efficient. This package refers to the RFC +// 8032 private key as the “seed”. package ed25519 // This code is a port of the public domain, “ref10” implementation of ed25519 @@ -31,6 +34,8 @@ const ( PrivateKeySize = 64 // SignatureSize is the size, in bytes, of signatures generated and verified by this package. SignatureSize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 32 ) // PublicKey is the type of Ed25519 public keys. @@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey { return PublicKey(publicKey) } +// Seed returns the private key seed corresponding to priv. It is provided for +// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds +// in this package. +func (priv PrivateKey) Seed() []byte { + seed := make([]byte, SeedSize) + copy(seed, priv[:32]) + return seed +} + // Sign signs the given message with priv. // Ed25519 performs two passes over messages to be signed and therefore cannot // handle pre-hashed messages. Thus opts.HashFunc() must return zero to @@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp // GenerateKey generates a public/private key pair using entropy from rand. // If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) { +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { if rand == nil { rand = cryptorand.Reader } - privateKey = make([]byte, PrivateKeySize) - publicKey = make([]byte, PublicKeySize) - _, err = io.ReadFull(rand, privateKey[:32]) - if err != nil { + seed := make([]byte, SeedSize) + if _, err := io.ReadFull(rand, seed); err != nil { return nil, nil, err } - digest := sha512.Sum512(privateKey[:32]) + privateKey := NewKeyFromSeed(seed) + publicKey := make([]byte, PublicKeySize) + copy(publicKey, privateKey[32:]) + + return publicKey, privateKey, nil +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + if l := len(seed); l != SeedSize { + panic("ed25519: bad seed length: " + strconv.Itoa(l)) + } + + digest := sha512.Sum512(seed) digest[0] &= 248 digest[31] &= 127 digest[31] |= 64 @@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er var publicKeyBytes [32]byte A.ToBytes(&publicKeyBytes) + privateKey := make([]byte, PrivateKeySize) + copy(privateKey, seed) copy(privateKey[32:], publicKeyBytes[:]) - copy(publicKey, publicKeyBytes[:]) - return publicKey, privateKey, nil + return privateKey } // Sign signs the message with privateKey and returns a signature. It will diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go index 5f946e99..80946036 100644 --- a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go +++ b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go @@ -139,6 +139,19 @@ func TestGolden(t *testing.T) { if !Verify(pubKey, msg, sig2) { t.Errorf("signature failed to verify on line %d", lineNo) } + + priv2 := NewKeyFromSeed(priv[:32]) + if !bytes.Equal(priv[:], priv2) { + t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2) + } + + if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) { + t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2) + } + + if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) { + t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed) + } } if err := scanner.Err(); err != nil { diff --git a/vendor/golang.org/x/crypto/hkdf/example_test.go b/vendor/golang.org/x/crypto/hkdf/example_test.go index df843951..e89c260e 100644 --- a/vendor/golang.org/x/crypto/hkdf/example_test.go +++ b/vendor/golang.org/x/crypto/hkdf/example_test.go @@ -9,49 +9,44 @@ import ( "crypto/rand" "crypto/sha256" "fmt" - "golang.org/x/crypto/hkdf" "io" + + "golang.org/x/crypto/hkdf" ) -// Usage example that expands one master key into three other cryptographically -// secure keys. +// Usage example that expands one master secret into three other +// cryptographically secure keys. func Example_usage() { - // Underlying hash function to use + // Underlying hash function for HMAC. hash := sha256.New - // Cryptographically secure master key. - master := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this. + // Cryptographically secure master secret. + secret := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this. - // Non secret salt, optional (can be nil) - // Recommended: hash-length sized random + // Non-secret salt, optional (can be nil). + // Recommended: hash-length random value. salt := make([]byte, hash().Size()) - n, err := io.ReadFull(rand.Reader, salt) - if n != len(salt) || err != nil { - fmt.Println("error:", err) - return + if _, err := rand.Read(salt); err != nil { + panic(err) } - // Non secret context specific info, optional (can be nil). - // Note, independent from the master key. - info := []byte{0x03, 0x14, 0x15, 0x92, 0x65} + // Non-secret context info, optional (can be nil). + info := []byte("hkdf example") - // Create the key derivation function - hkdf := hkdf.New(hash, master, salt, info) + // Generate three 128-bit derived keys. + hkdf := hkdf.New(hash, secret, salt, info) - // Generate the required keys - keys := make([][]byte, 3) - for i := 0; i < len(keys); i++ { - keys[i] = make([]byte, 24) - n, err := io.ReadFull(hkdf, keys[i]) - if n != len(keys[i]) || err != nil { - fmt.Println("error:", err) - return + var keys [][]byte + for i := 0; i < 3; i++ { + key := make([]byte, 16) + if _, err := io.ReadFull(hkdf, key); err != nil { + panic(err) } + keys = append(keys, key) } - // Keys should contain 192 bit random keys - for i := 1; i <= len(keys); i++ { - fmt.Printf("Key #%d: %v\n", i, !bytes.Equal(keys[i-1], make([]byte, 24))) + for i := range keys { + fmt.Printf("Key #%d: %v\n", i+1, !bytes.Equal(keys[i], make([]byte, 16))) } // Output: diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go index 5bc24635..dda3f143 100644 --- a/vendor/golang.org/x/crypto/hkdf/hkdf.go +++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go @@ -8,8 +8,6 @@ // HKDF is a cryptographic key derivation function (KDF) with the goal of // expanding limited input keying material into one or more cryptographically // strong secret keys. -// -// RFC 5869: https://tools.ietf.org/html/rfc5869 package hkdf // import "golang.org/x/crypto/hkdf" import ( @@ -19,6 +17,21 @@ import ( "io" ) +// Extract generates a pseudorandom key for use with Expand from an input secret +// and an optional independent salt. +// +// Only use this function if you need to reuse the extracted key with multiple +// Expand invocations and different context values. Most common scenarios, +// including the generation of multiple keys, should use New instead. +func Extract(hash func() hash.Hash, secret, salt []byte) []byte { + if salt == nil { + salt = make([]byte, hash().Size()) + } + extractor := hmac.New(hash, salt) + extractor.Write(secret) + return extractor.Sum(nil) +} + type hkdf struct { expander hash.Hash size int @@ -26,22 +39,22 @@ type hkdf struct { info []byte counter byte - prev []byte - cache []byte + prev []byte + buf []byte } func (f *hkdf) Read(p []byte) (int, error) { // Check whether enough data can be generated need := len(p) - remains := len(f.cache) + int(255-f.counter+1)*f.size + remains := len(f.buf) + int(255-f.counter+1)*f.size if remains < need { return 0, errors.New("hkdf: entropy limit reached") } - // Read from the cache, if enough data is present - n := copy(p, f.cache) + // Read any leftover from the buffer + n := copy(p, f.buf) p = p[n:] - // Fill the buffer + // Fill the rest of the buffer for len(p) > 0 { f.expander.Reset() f.expander.Write(f.prev) @@ -51,25 +64,30 @@ func (f *hkdf) Read(p []byte) (int, error) { f.counter++ // Copy the new batch into p - f.cache = f.prev - n = copy(p, f.cache) + f.buf = f.prev + n = copy(p, f.buf) p = p[n:] } // Save leftovers for next run - f.cache = f.cache[n:] + f.buf = f.buf[n:] return need, nil } -// New returns a new HKDF using the given hash, the secret keying material to expand -// and optional salt and info fields. -func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { - if salt == nil { - salt = make([]byte, hash().Size()) - } - extractor := hmac.New(hash, salt) - extractor.Write(secret) - prk := extractor.Sum(nil) - - return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil} +// Expand returns a Reader, from which keys can be read, using the given +// pseudorandom key and optional context info, skipping the extraction step. +// +// The pseudorandomKey should have been generated by Extract, or be a uniformly +// random or pseudorandom cryptographically strong key. See RFC 5869, Section +// 3.3. Most common scenarios will want to use New instead. +func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader { + expander := hmac.New(hash, pseudorandomKey) + return &hkdf{expander, expander.Size(), info, 1, nil, nil} +} + +// New returns a Reader, from which keys can be read, using the given hash, +// secret, salt and context info. Salt and info can be nil. +func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { + prk := Extract(hash, secret, salt) + return Expand(hash, prk, info) } diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf_test.go b/vendor/golang.org/x/crypto/hkdf/hkdf_test.go index cee659bc..ea575772 100644 --- a/vendor/golang.org/x/crypto/hkdf/hkdf_test.go +++ b/vendor/golang.org/x/crypto/hkdf/hkdf_test.go @@ -18,6 +18,7 @@ type hkdfTest struct { hash func() hash.Hash master []byte salt []byte + prk []byte info []byte out []byte } @@ -35,6 +36,12 @@ var hkdfTests = []hkdfTest{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, }, + []byte{ + 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, + 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, + 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5, + }, []byte{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, @@ -74,6 +81,12 @@ var hkdfTests = []hkdfTest{ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, }, + []byte{ + 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, + 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c, + 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, + 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44, + }, []byte{ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, @@ -108,6 +121,12 @@ var hkdfTests = []hkdfTest{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, }, []byte{}, + []byte{ + 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, + 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, + 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, + 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04, + }, []byte{}, []byte{ 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, @@ -118,6 +137,30 @@ var hkdfTests = []hkdfTest{ 0x96, 0xc8, }, }, + { + sha256.New, + []byte{ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }, + nil, + []byte{ + 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, + 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, + 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, + 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04, + }, + nil, + []byte{ + 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, + 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, + 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, + 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, + 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, + 0x96, 0xc8, + }, + }, { sha1.New, []byte{ @@ -128,6 +171,11 @@ var hkdfTests = []hkdfTest{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, }, + []byte{ + 0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f, + 0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b, + 0xaa, 0x2b, 0xa2, 0x43, + }, []byte{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, @@ -167,6 +215,11 @@ var hkdfTests = []hkdfTest{ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, }, + []byte{ + 0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59, + 0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a, + 0x22, 0x4c, 0xfa, 0xf6, + }, []byte{ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, @@ -201,6 +254,11 @@ var hkdfTests = []hkdfTest{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, }, []byte{}, + []byte{ + 0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28, + 0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a, + 0xa0, 0xd3, 0x2d, 0x01, + }, []byte{}, []byte{ 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, @@ -219,7 +277,12 @@ var hkdfTests = []hkdfTest{ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, }, nil, - []byte{}, + []byte{ + 0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c, + 0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d, 0x3f, 0x3e, + 0x73, 0x13, 0x85, 0xdd, + }, + nil, []byte{ 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, @@ -233,6 +296,11 @@ var hkdfTests = []hkdfTest{ func TestHKDF(t *testing.T) { for i, tt := range hkdfTests { + prk := Extract(tt.hash, tt.master, tt.salt) + if !bytes.Equal(prk, tt.prk) { + t.Errorf("test %d: incorrect PRK: have %v, need %v.", i, prk, tt.prk) + } + hkdf := New(tt.hash, tt.master, tt.salt, tt.info) out := make([]byte, len(tt.out)) @@ -244,6 +312,17 @@ func TestHKDF(t *testing.T) { if !bytes.Equal(out, tt.out) { t.Errorf("test %d: incorrect output: have %v, need %v.", i, out, tt.out) } + + hkdf = Expand(tt.hash, prk, tt.info) + + n, err = io.ReadFull(hkdf, out) + if n != len(tt.out) || err != nil { + t.Errorf("test %d: not enough output bytes from Expand: %d.", i, n) + } + + if !bytes.Equal(out, tt.out) { + t.Errorf("test %d: incorrect output from Expand: have %v, need %v.", i, out, tt.out) + } } } diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go index 7ed1cd9b..6570847f 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go @@ -9,6 +9,8 @@ package chacha20 import ( "crypto/cipher" "encoding/binary" + + "golang.org/x/crypto/internal/subtle" ) // assert that *Cipher implements cipher.Stream @@ -30,6 +32,30 @@ func New(key [8]uint32, nonce [3]uint32) *Cipher { return &Cipher{key: key, nonce: nonce} } +// ChaCha20 constants spelling "expand 32-byte k" +const ( + j0 uint32 = 0x61707865 + j1 uint32 = 0x3320646e + j2 uint32 = 0x79622d32 + j3 uint32 = 0x6b206574 +) + +func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { + a += b + d ^= a + d = (d << 16) | (d >> 16) + c += d + b ^= c + b = (b << 12) | (b >> 20) + a += b + d ^= a + d = (d << 8) | (d >> 24) + c += d + b ^= c + b = (b << 7) | (b >> 25) + return a, b, c, d +} + // XORKeyStream XORs each byte in the given slice with a byte from the // cipher's key stream. Dst and src must overlap entirely or not at all. // @@ -41,6 +67,13 @@ func New(key [8]uint32, nonce [3]uint32) *Cipher { // the src buffers was passed in a single run. That is, Cipher // maintains state and does not reset at each XORKeyStream call. func (s *Cipher) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("chacha20: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("chacha20: invalid buffer overlap") + } + // xor src with buffered keystream first if s.len != 0 { buf := s.buf[len(s.buf)-s.len:] @@ -64,6 +97,9 @@ func (s *Cipher) XORKeyStream(dst, src []byte) { return } if haveAsm { + if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 { + panic("chacha20: counter overflow") + } s.xorKeyStreamAsm(dst, src) return } @@ -76,59 +112,34 @@ func (s *Cipher) XORKeyStream(dst, src []byte) { copy(s.buf[len(s.buf)-64:], src[fin:]) } - // qr calculates a quarter round - qr := func(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { - a += b - d ^= a - d = (d << 16) | (d >> 16) - c += d - b ^= c - b = (b << 12) | (b >> 20) - a += b - d ^= a - d = (d << 8) | (d >> 24) - c += d - b ^= c - b = (b << 7) | (b >> 25) - return a, b, c, d - } - - // ChaCha20 constants - const ( - j0 = 0x61707865 - j1 = 0x3320646e - j2 = 0x79622d32 - j3 = 0x6b206574 - ) - // pre-calculate most of the first round - s1, s5, s9, s13 := qr(j1, s.key[1], s.key[5], s.nonce[0]) - s2, s6, s10, s14 := qr(j2, s.key[2], s.key[6], s.nonce[1]) - s3, s7, s11, s15 := qr(j3, s.key[3], s.key[7], s.nonce[2]) + s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0]) + s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1]) + s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2]) n := len(src) src, dst = src[:n:n], dst[:n:n] // BCE hint for i := 0; i < n; i += 64 { // calculate the remainder of the first round - s0, s4, s8, s12 := qr(j0, s.key[0], s.key[4], s.counter) + s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter) // execute the second round - x0, x5, x10, x15 := qr(s0, s5, s10, s15) - x1, x6, x11, x12 := qr(s1, s6, s11, s12) - x2, x7, x8, x13 := qr(s2, s7, s8, s13) - x3, x4, x9, x14 := qr(s3, s4, s9, s14) + x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15) + x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12) + x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13) + x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14) // execute the remaining 18 rounds for i := 0; i < 9; i++ { - x0, x4, x8, x12 = qr(x0, x4, x8, x12) - x1, x5, x9, x13 = qr(x1, x5, x9, x13) - x2, x6, x10, x14 = qr(x2, x6, x10, x14) - x3, x7, x11, x15 = qr(x3, x7, x11, x15) + x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) + x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) + x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) + x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) - x0, x5, x10, x15 = qr(x0, x5, x10, x15) - x1, x6, x11, x12 = qr(x1, x6, x11, x12) - x2, x7, x8, x13 = qr(x2, x7, x8, x13) - x3, x4, x9, x14 = qr(x3, x4, x9, x14) + x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) + x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) + x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) + x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) } x0 += j0 @@ -225,3 +236,29 @@ func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) { } s.XORKeyStream(out, in) } + +// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a +// nonce. It should only be used as part of the XChaCha20 construction. +func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 { + x0, x1, x2, x3 := j0, j1, j2, j3 + x4, x5, x6, x7 := key[0], key[1], key[2], key[3] + x8, x9, x10, x11 := key[4], key[5], key[6], key[7] + x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3] + + for i := 0; i < 10; i++ { + x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) + x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) + x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) + x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) + + x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) + x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) + x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) + x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) + } + + var out [8]uint32 + out[0], out[1], out[2], out[3] = x0, x1, x2, x3 + out[4], out[5], out[6], out[7] = x12, x13, x14, x15 + return out +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/asm_s390x.s b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s similarity index 100% rename from vendor/golang.org/x/crypto/internal/chacha20/asm_s390x.s rename to vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go index bf993304..9a7a0994 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go @@ -5,6 +5,7 @@ package chacha20 import ( + "encoding/binary" "encoding/hex" "fmt" "math/rand" @@ -186,3 +187,39 @@ func BenchmarkChaCha20(b *testing.B) { }) } } + +func TestHChaCha20(t *testing.T) { + // See draft-paragon-paseto-rfc-00 §7.2.1. + key := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f} + nonce := []byte{0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x41, 0x59, 0x27} + expected := []byte{0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe, + 0xd3, 0x0e, 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73, + 0xa0, 0xf9, 0xe4, 0xd5, 0x8a, 0x74, 0xa8, 0x53, + 0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3, 0xec, 0xdc, + } + result := HChaCha20(&[8]uint32{ + binary.LittleEndian.Uint32(key[0:4]), + binary.LittleEndian.Uint32(key[4:8]), + binary.LittleEndian.Uint32(key[8:12]), + binary.LittleEndian.Uint32(key[12:16]), + binary.LittleEndian.Uint32(key[16:20]), + binary.LittleEndian.Uint32(key[20:24]), + binary.LittleEndian.Uint32(key[24:28]), + binary.LittleEndian.Uint32(key[28:32]), + }, &[4]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + binary.LittleEndian.Uint32(nonce[12:16]), + }) + for i := 0; i < 8; i++ { + want := binary.LittleEndian.Uint32(expected[i*4 : (i+1)*4]) + if got := result[i]; got != want { + t.Errorf("word %d incorrect: want 0x%x, got 0x%x", i, want, got) + } + } +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go new file mode 100644 index 00000000..f38797bf --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go @@ -0,0 +1,32 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go new file mode 100644 index 00000000..0cc4a8a6 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go @@ -0,0 +1,35 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +// This is the Google App Engine standard variant based on reflect +// because the unsafe package and cgo are disallowed. + +import "reflect" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && + reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_test.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_test.go new file mode 100644 index 00000000..a5b62ff7 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_test.go @@ -0,0 +1,50 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package subtle_test + +import ( + "testing" + + "golang.org/x/crypto/internal/subtle" +) + +var a, b [100]byte + +var aliasingTests = []struct { + x, y []byte + anyOverlap, inexactOverlap bool +}{ + {a[:], b[:], false, false}, + {a[:], b[:0], false, false}, + {a[:], b[:50], false, false}, + {a[40:50], a[50:60], false, false}, + {a[40:50], a[60:70], false, false}, + {a[:51], a[50:], true, true}, + {a[:], a[:], true, false}, + {a[:50], a[:60], true, false}, + {a[:], nil, false, false}, + {nil, nil, false, false}, + {a[:], a[:0], false, false}, + {a[:10], a[:10:20], true, false}, + {a[:10], a[5:10:20], true, true}, +} + +func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) { + any := subtle.AnyOverlap(x, y) + if any != anyOverlap { + t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any) + } + inexact := subtle.InexactOverlap(x, y) + if inexact != inexactOverlap { + t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any) + } +} + +func TestAliasing(t *testing.T) { + for i, tt := range aliasingTests { + testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap) + testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap) + } +} diff --git a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go index 53ee83cf..a98d1bd4 100644 --- a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go +++ b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go @@ -35,6 +35,7 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html. package secretbox // import "golang.org/x/crypto/nacl/secretbox" import ( + "golang.org/x/crypto/internal/subtle" "golang.org/x/crypto/poly1305" "golang.org/x/crypto/salsa20/salsa" ) @@ -87,6 +88,9 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte { copy(poly1305Key[:], firstBlock[:]) ret, out := sliceForAppend(out, len(message)+poly1305.TagSize) + if subtle.AnyOverlap(out, message) { + panic("nacl: invalid buffer overlap") + } // We XOR up to 32 bytes of message with the keystream generated from // the first block. @@ -118,7 +122,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte { // Open authenticates and decrypts a box produced by Seal and appends the // message to out, which must not overlap box. The output will be Overhead // bytes smaller than box. -func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) { +func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) { if len(box) < Overhead { return nil, false } @@ -143,6 +147,9 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) } ret, out := sliceForAppend(out, len(box)-Overhead) + if subtle.AnyOverlap(out, box) { + panic("nacl: invalid buffer overlap") + } // We XOR up to 32 bytes of box with the keystream generated from // the first block. diff --git a/vendor/golang.org/x/crypto/nacl/sign/sign.go b/vendor/golang.org/x/crypto/nacl/sign/sign.go index a9ac0a77..d0762701 100644 --- a/vendor/golang.org/x/crypto/nacl/sign/sign.go +++ b/vendor/golang.org/x/crypto/nacl/sign/sign.go @@ -24,6 +24,7 @@ import ( "io" "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/internal/subtle" ) // Overhead is the number of bytes of overhead when signing a message. @@ -47,6 +48,9 @@ func GenerateKey(rand io.Reader) (publicKey *[32]byte, privateKey *[64]byte, err func Sign(out, message []byte, privateKey *[64]byte) []byte { sig := ed25519.Sign(ed25519.PrivateKey((*privateKey)[:]), message) ret, out := sliceForAppend(out, Overhead+len(message)) + if subtle.AnyOverlap(out, message) { + panic("nacl: invalid buffer overlap") + } copy(out, sig) copy(out[Overhead:], message) return ret @@ -63,6 +67,9 @@ func Open(out, signedMessage []byte, publicKey *[32]byte) ([]byte, bool) { return nil, false } ret, out := sliceForAppend(out, len(signedMessage)-Overhead) + if subtle.AnyOverlap(out, signedMessage) { + panic("nacl: invalid buffer overlap") + } copy(out, signedMessage[Overhead:]) return ret, true } diff --git a/vendor/golang.org/x/crypto/ocsp/ocsp.go b/vendor/golang.org/x/crypto/ocsp/ocsp.go index 5edc9c97..f079d9ea 100644 --- a/vendor/golang.org/x/crypto/ocsp/ocsp.go +++ b/vendor/golang.org/x/crypto/ocsp/ocsp.go @@ -63,7 +63,7 @@ func (r ResponseStatus) String() string { } // ResponseError is an error that may be returned by ParseResponse to indicate -// that the response itself is an error, not just that its indicating that a +// that the response itself is an error, not just that it's indicating that a // certificate is revoked, unknown, etc. type ResponseError struct { Status ResponseStatus diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go index def4caba..a9437dc1 100644 --- a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go +++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go @@ -13,6 +13,7 @@ import ( "bufio" "bytes" "crypto" + "fmt" "hash" "io" "net/textproto" @@ -177,8 +178,9 @@ func Decode(data []byte) (b *Block, rest []byte) { // message. type dashEscaper struct { buffered *bufio.Writer - h hash.Hash + hashers []hash.Hash // one per key in privateKeys hashType crypto.Hash + toHash io.Writer // writes to all the hashes in hashers atBeginningOfLine bool isFirstLine bool @@ -186,8 +188,8 @@ type dashEscaper struct { whitespace []byte byteBuf []byte // a one byte buffer to save allocations - privateKey *packet.PrivateKey - config *packet.Config + privateKeys []*packet.PrivateKey + config *packet.Config } func (d *dashEscaper) Write(data []byte) (n int, err error) { @@ -198,7 +200,7 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { // The final CRLF isn't included in the hash so we have to wait // until this point (the start of the next line) before writing it. if !d.isFirstLine { - d.h.Write(crlf) + d.toHash.Write(crlf) } d.isFirstLine = false } @@ -219,12 +221,12 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { if _, err = d.buffered.Write(dashEscape); err != nil { return } - d.h.Write(d.byteBuf) + d.toHash.Write(d.byteBuf) d.atBeginningOfLine = false } else if b == '\n' { // Nothing to do because we delay writing CRLF to the hash. } else { - d.h.Write(d.byteBuf) + d.toHash.Write(d.byteBuf) d.atBeginningOfLine = false } if err = d.buffered.WriteByte(b); err != nil { @@ -245,13 +247,13 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { // Any buffered whitespace wasn't at the end of the line so // we need to write it out. if len(d.whitespace) > 0 { - d.h.Write(d.whitespace) + d.toHash.Write(d.whitespace) if _, err = d.buffered.Write(d.whitespace); err != nil { return } d.whitespace = d.whitespace[:0] } - d.h.Write(d.byteBuf) + d.toHash.Write(d.byteBuf) if err = d.buffered.WriteByte(b); err != nil { return } @@ -269,25 +271,29 @@ func (d *dashEscaper) Close() (err error) { return } } - sig := new(packet.Signature) - sig.SigType = packet.SigTypeText - sig.PubKeyAlgo = d.privateKey.PubKeyAlgo - sig.Hash = d.hashType - sig.CreationTime = d.config.Now() - sig.IssuerKeyId = &d.privateKey.KeyId - - if err = sig.Sign(d.h, d.privateKey, d.config); err != nil { - return - } out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil) if err != nil { return } - if err = sig.Serialize(out); err != nil { - return + t := d.config.Now() + for i, k := range d.privateKeys { + sig := new(packet.Signature) + sig.SigType = packet.SigTypeText + sig.PubKeyAlgo = k.PubKeyAlgo + sig.Hash = d.hashType + sig.CreationTime = t + sig.IssuerKeyId = &k.KeyId + + if err = sig.Sign(d.hashers[i], k, d.config); err != nil { + return + } + if err = sig.Serialize(out); err != nil { + return + } } + if err = out.Close(); err != nil { return } @@ -300,8 +306,17 @@ func (d *dashEscaper) Close() (err error) { // Encode returns a WriteCloser which will clear-sign a message with privateKey // and write it to w. If config is nil, sensible defaults are used. func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) { - if privateKey.Encrypted { - return nil, errors.InvalidArgumentError("signing key is encrypted") + return EncodeMulti(w, []*packet.PrivateKey{privateKey}, config) +} + +// EncodeMulti returns a WriteCloser which will clear-sign a message with all the +// private keys indicated and write it to w. If config is nil, sensible defaults +// are used. +func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) { + for _, k := range privateKeys { + if k.Encrypted { + return nil, errors.InvalidArgumentError(fmt.Sprintf("signing key %s is encrypted", k.KeyIdString())) + } } hashType := config.Hash() @@ -313,7 +328,14 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) ( if !hashType.Available() { return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType))) } - h := hashType.New() + var hashers []hash.Hash + var ws []io.Writer + for range privateKeys { + h := hashType.New() + hashers = append(hashers, h) + ws = append(ws, h) + } + toHash := io.MultiWriter(ws...) buffered := bufio.NewWriter(w) // start has a \n at the beginning that we don't want here. @@ -338,16 +360,17 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) ( plaintext = &dashEscaper{ buffered: buffered, - h: h, + hashers: hashers, hashType: hashType, + toHash: toHash, atBeginningOfLine: true, isFirstLine: true, byteBuf: make([]byte, 1), - privateKey: privateKey, - config: config, + privateKeys: privateKeys, + config: config, } return diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go index 2c094807..96f5d781 100644 --- a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go +++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go @@ -6,8 +6,11 @@ package clearsign import ( "bytes" - "golang.org/x/crypto/openpgp" + "fmt" "testing" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/packet" ) func testParse(t *testing.T, input []byte, expected, expectedPlaintext string) { @@ -125,6 +128,71 @@ func TestSigning(t *testing.T) { } } +// We use this to make test keys, so that they aren't all the same. +type quickRand byte + +func (qr *quickRand) Read(p []byte) (int, error) { + for i := range p { + p[i] = byte(*qr) + } + *qr++ + return len(p), nil +} + +func TestMultiSign(t *testing.T) { + zero := quickRand(0) + config := packet.Config{Rand: &zero} + + for nKeys := 0; nKeys < 4; nKeys++ { + nextTest: + for nExtra := 0; nExtra < 4; nExtra++ { + var signKeys []*packet.PrivateKey + var verifyKeys openpgp.EntityList + + desc := fmt.Sprintf("%d keys; %d of which will be used to verify", nKeys+nExtra, nKeys) + for i := 0; i < nKeys+nExtra; i++ { + e, err := openpgp.NewEntity("name", "comment", "email", &config) + if err != nil { + t.Errorf("cannot create key: %v", err) + continue nextTest + } + if i < nKeys { + verifyKeys = append(verifyKeys, e) + } + signKeys = append(signKeys, e.PrivateKey) + } + + input := []byte("this is random text\r\n4 17") + var output bytes.Buffer + w, err := EncodeMulti(&output, signKeys, nil) + if err != nil { + t.Errorf("EncodeMulti (%s) failed: %v", desc, err) + } + if _, err := w.Write(input); err != nil { + t.Errorf("Write(%q) to signer (%s) failed: %v", string(input), desc, err) + } + if err := w.Close(); err != nil { + t.Errorf("Close() of signer (%s) failed: %v", desc, err) + } + + block, _ := Decode(output.Bytes()) + if string(block.Bytes) != string(input) { + t.Errorf("Inline data didn't match original; got %q want %q", string(block.Bytes), string(input)) + } + _, err = openpgp.CheckDetachedSignature(verifyKeys, bytes.NewReader(block.Bytes), block.ArmoredSignature.Body) + if nKeys == 0 { + if err == nil { + t.Errorf("verifying inline (%s) succeeded; want failure", desc) + } + } else { + if err != nil { + t.Errorf("verifying inline (%s) failed (%v); want success", desc, err) + } + } + } + } +} + var clearsignInput = []byte(` ;lasjlkfdsa diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index fd582a89..3e251860 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -333,7 +333,6 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) { return nil, errors.StructuralError("primary key cannot be used for signatures") } - var current *Identity var revocations []*packet.Signature EachPacket: for { @@ -346,32 +345,8 @@ EachPacket: switch pkt := p.(type) { case *packet.UserId: - current = new(Identity) - current.Name = pkt.Id - current.UserId = pkt - e.Identities[pkt.Id] = current - - for { - p, err = packets.Next() - if err == io.EOF { - return nil, io.ErrUnexpectedEOF - } else if err != nil { - return nil, err - } - - sig, ok := p.(*packet.Signature) - if !ok { - return nil, errors.StructuralError("user ID packet not followed by self-signature") - } - - if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { - if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { - return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) - } - current.SelfSignature = sig - break - } - current.Signatures = append(current.Signatures, sig) + if err := addUserID(e, packets, pkt); err != nil { + return nil, err } case *packet.Signature: if pkt.SigType == packet.SigTypeKeyRevocation { @@ -380,11 +355,9 @@ EachPacket: // TODO: RFC4880 5.2.1 permits signatures // directly on keys (eg. to bind additional // revocation keys). - } else if current == nil { - return nil, errors.StructuralError("signature packet found before user id packet") - } else { - current.Signatures = append(current.Signatures, pkt) } + // Else, ignoring the signature as it does not follow anything + // we would know to attach it to. case *packet.PrivateKey: if pkt.IsSubkey == false { packets.Unread(p) @@ -425,33 +398,105 @@ EachPacket: return e, nil } +func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { + // Make a new Identity object, that we might wind up throwing away. + // We'll only add it if we get a valid self-signature over this + // userID. + identity := new(Identity) + identity.Name = pkt.Id + identity.UserId = pkt + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return err + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { + if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { + return errors.StructuralError("user ID self-signature invalid: " + err.Error()) + } + identity.SelfSignature = sig + e.Identities[pkt.Id] = identity + } else { + identity.Signatures = append(identity.Signatures, sig) + } + } + + return nil +} + func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { var subKey Subkey subKey.PublicKey = pub subKey.PrivateKey = priv - p, err := packets.Next() - if err == io.EOF { - return io.ErrUnexpectedEOF + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { + return errors.StructuralError("subkey signature with wrong type") + } + + if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + + switch sig.SigType { + case packet.SigTypeSubkeyRevocation: + subKey.Sig = sig + case packet.SigTypeSubkeyBinding: + + if shouldReplaceSubkeySig(subKey.Sig, sig) { + subKey.Sig = sig + } + } } - if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - var ok bool - subKey.Sig, ok = p.(*packet.Signature) - if !ok { + + if subKey.Sig == nil { return errors.StructuralError("subkey packet not followed by signature") } - if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation { - return errors.StructuralError("subkey signature with wrong type") - } - err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) - if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } + e.Subkeys = append(e.Subkeys, subKey) + return nil } +func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { + if potentialNewSig == nil { + return false + } + + if existingSig == nil { + return true + } + + if existingSig.SigType == packet.SigTypeSubkeyRevocation { + return false // never override a revocation signature + } + + return potentialNewSig.CreationTime.After(existingSig.CreationTime) +} + const defaultRSAKeyBits = 2048 // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a @@ -500,6 +545,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err IssuerKeyId: &e.PrimaryKey.KeyId, }, } + err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config) + if err != nil { + return nil, err + } // If the user passes in a DefaultHash via packet.Config, // set the PreferredHash for the SelfSignature. @@ -529,13 +578,16 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err } e.Subkeys[0].PublicKey.IsSubkey = true e.Subkeys[0].PrivateKey.IsSubkey = true - + err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config) + if err != nil { + return nil, err + } return e, nil } -// SerializePrivate serializes an Entity, including private key material, to -// the given Writer. For now, it must only be used on an Entity returned from -// NewEntity. +// SerializePrivate serializes an Entity, including private key material, but +// excluding signatures from other entities, to the given Writer. +// Identities and subkeys are re-signed in case they changed since NewEntry. // If config is nil, sensible defaults will be used. func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { err = e.PrivateKey.Serialize(w) @@ -573,8 +625,8 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error return nil } -// Serialize writes the public part of the given Entity to w. (No private -// key material will be output). +// Serialize writes the public part of the given Entity to w, including +// signatures from other entities. No private key material will be output. func (e *Entity) Serialize(w io.Writer) error { err := e.PrimaryKey.Serialize(w) if err != nil { diff --git a/vendor/golang.org/x/crypto/openpgp/keys_data_test.go b/vendor/golang.org/x/crypto/openpgp/keys_data_test.go new file mode 100644 index 00000000..7779bd97 --- /dev/null +++ b/vendor/golang.org/x/crypto/openpgp/keys_data_test.go @@ -0,0 +1,200 @@ +package openpgp + +const expiringKeyHex = "988d0451d1ec5d010400ba3385721f2dc3f4ab096b2ee867ab77213f0a27a8538441c35d2fa225b08798a1439a66a5150e6bdc3f40f5d28d588c712394c632b6299f77db8c0d48d37903fb72ebd794d61be6aa774688839e5fdecfe06b2684cc115d240c98c66cb1ef22ae84e3aa0c2b0c28665c1e7d4d044e7f270706193f5223c8d44e0d70b7b8da830011010001b40f4578706972792074657374206b657988be041301020028050251d1ec5d021b03050900278d00060b090807030206150802090a0b0416020301021e01021780000a091072589ad75e237d8c033503fd10506d72837834eb7f994117740723adc39227104b0d326a1161871c0b415d25b4aedef946ca77ea4c05af9c22b32cf98be86ab890111fced1ee3f75e87b7cc3c00dc63bbc85dfab91c0dc2ad9de2c4d13a34659333a85c6acc1a669c5e1d6cecb0cf1e56c10e72d855ae177ddc9e766f9b2dda57ccbb75f57156438bbdb4e42b88d0451d1ec5d0104009c64906559866c5cb61578f5846a94fcee142a489c9b41e67b12bb54cfe86eb9bc8566460f9a720cb00d6526fbccfd4f552071a8e3f7744b1882d01036d811ee5a3fb91a1c568055758f43ba5d2c6a9676b012f3a1a89e47bbf624f1ad571b208f3cc6224eb378f1645dd3d47584463f9eadeacfd1ce6f813064fbfdcc4b5a53001101000188a504180102000f021b0c050251d1f06b050900093e89000a091072589ad75e237d8c20e00400ab8310a41461425b37889c4da28129b5fae6084fafbc0a47dd1adc74a264c6e9c9cc125f40462ee1433072a58384daef88c961c390ed06426a81b464a53194c4e291ddd7e2e2ba3efced01537d713bd111f48437bde2363446200995e8e0d4e528dda377fd1e8f8ede9c8e2198b393bd86852ce7457a7e3daf74d510461a5b77b88d0451d1ece8010400b3a519f83ab0010307e83bca895170acce8964a044190a2b368892f7a244758d9fc193482648acb1fb9780d28cc22d171931f38bb40279389fc9bf2110876d4f3db4fcfb13f22f7083877fe56592b3b65251312c36f83ffcb6d313c6a17f197dd471f0712aad15a8537b435a92471ba2e5b0c72a6c72536c3b567c558d7b6051001101000188a504180102000f021b0c050251d1f07b050900279091000a091072589ad75e237d8ce69e03fe286026afacf7c97ee20673864d4459a2240b5655219950643c7dba0ac384b1d4359c67805b21d98211f7b09c2a0ccf6410c8c04d4ff4a51293725d8d6570d9d8bb0e10c07d22357caeb49626df99c180be02d77d1fe8ed25e7a54481237646083a9f89a11566cd20b9e995b1487c5f9e02aeb434f3a1897cd416dd0a87861838da3e9e" +const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98" +const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f" +const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011" + +const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Charset: UTF-8 + +mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY +ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG +zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 +QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ +QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo +9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu +Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ +dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R +JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL +ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew +RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW +/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu +yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv +2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR +bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL +C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP +WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y +MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA +EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ +MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N +1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm ++ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N +lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW +CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF +4artDmrG +=7FfJ +-----END PGP PUBLIC KEY BLOCK-----` + +const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY +ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG +zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 +QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ +QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo +9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu +Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ +dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R +JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL +ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew +RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW +/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu +yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ +UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe +iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK +FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8 +R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh ++SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA +EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO +52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb +u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl +w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep +54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+ +YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL +bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E +i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB +DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1 +8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY +s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745 +U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL +6LCg2mg= +=Dhm4 +-----END PGP PUBLIC KEY BLOCK-----` + +const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo +7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom +lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0 +E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw +6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH +7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv +X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7 +GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl +y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw +R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW +CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+ +LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO +aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx +yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl +BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr +Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK +CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp +C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ +SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/ +MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70= +=vtbN +-----END PGP PUBLIC KEY BLOCK-----` + +const revokedUserIDKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0qlX2e +DZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN91KtLsz/ +uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xOXO3YtLdmJMBW +ClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBbnaIYO6fXVXELUjkx +nmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX8vY7vwC34pm22fAUVLCJ +x1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEBAAG0I0dvbGFuZyBHb3BoZXIg +PG5vLXJlcGx5QGdvbGFuZy5jb20+iQFUBBMBCgA+FiEE5Ik5JLcNx6l6rZfw1oFy +9I6cUoMFAlsgO5ECGwMFCQPCZwAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ +1oFy9I6cUoMIkwf8DNPeD23i4jRwd/pylbvxwZintZl1fSwTJW1xcOa1emXaEtX2 +depuqhP04fjlRQGfsYAQh7X9jOJxAHjTmhqFBi5sD7QvKU00cPFYbJ/JTx0B41bl +aXnSbGhRPh63QtEZL7ACAs+shwvvojJqysx7kyVRu0EW2wqjXdHwR/SJO6nhNBa2 +DXzSiOU/SUA42mmG+5kjF8Aabq9wPwT9wjraHShEweNerNMmOqJExBOy3yFeyDpa +XwEZFzBfOKoxFNkIaVf5GSdIUGhFECkGvBMB935khftmgR8APxdU4BE7XrXexFJU +8RCuPXonm4WQOwTWR0vQg64pb2WKAzZ8HhwTGbQiR29sYW5nIEdvcGhlciA8cmV2 +b2tlZEBnb2xhbmcuY29tPokBNgQwAQoAIBYhBOSJOSS3Dcepeq2X8NaBcvSOnFKD +BQJbIDv3Ah0AAAoJENaBcvSOnFKDfWMIAKhI/Tvu3h8fSUxp/gSAcduT6bC1JttG +0lYQ5ilKB/58lBUA5CO3ZrKDKlzW3M8VEcvohVaqeTMKeoQd5rCZq8KxHn/KvN6N +s85REfXfniCKfAbnGgVXX3kDmZ1g63pkxrFu0fDZjVDXC6vy+I0sGyI/Inro0Pzb +tvn0QCsxjapKK15BtmSrpgHgzVqVg0cUp8vqZeKFxarYbYB2idtGRci4b9tObOK0 +BSTVFy26+I/mrFGaPrySYiy2Kz5NMEcRhjmTxJ8jSwEr2O2sUR0yjbgUAXbTxDVE +/jg5fQZ1ACvBRQnB7LvMHcInbzjyeTM3FazkkSYQD6b97+dkWwb1iWG5AQ0EWyA7 +kQEIALkg04REDZo1JgdYV4x8HJKFS4xAYWbIva1ZPqvDNmZRUbQZR2+gpJGEwn7z +VofGvnOYiGW56AS5j31SFf5kro1+1bZQ5iOONBng08OOo58/l1hRseIIVGB5TGSa +PCdChKKHreJI6hS3mShxH6hdfFtiZuB45rwoaArMMsYcjaezLwKeLc396cpUwwcZ +snLUNd1Xu5EWEF2OdFkZ2a1qYdxBvAYdQf4+1Nr+NRIx1u1NS9c8jp3PuMOkrQEi +bNtc1v6v0Jy52mKLG4y7mC/erIkvkQBYJdxPaP7LZVaPYc3/xskcyijrJ/5ufoD8 +K71/ShtsZUXSQn9jlRaYR0EbojMAEQEAAYkBPAQYAQoAJhYhBOSJOSS3Dcepeq2X +8NaBcvSOnFKDBQJbIDuRAhsMBQkDwmcAAAoJENaBcvSOnFKDkFMIAIt64bVZ8x7+ +TitH1bR4pgcNkaKmgKoZz6FXu80+SnbuEt2NnDyf1cLOSimSTILpwLIuv9Uft5Pb +OraQbYt3xi9yrqdKqGLv80bxqK0NuryNkvh9yyx5WoG1iKqMj9/FjGghuPrRaT4l +QinNAghGVkEy1+aXGFrG2DsOC1FFI51CC2WVTzZ5RwR2GpiNRfESsU1rZAUqf/2V +yJl9bD5R4SUNy8oQmhOxi+gbhD4Ao34e4W0ilibslI/uawvCiOwlu5NGd8zv5n+U +heiQvzkApQup5c+BhH5zFDFdKJ2CBByxw9+7QjMFI/wgLixKuE0Ob2kAokXf7RlB +7qTZOahrETw= +=IKnw +-----END PGP PUBLIC KEY BLOCK-----` + +const keyWithSubKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mI0EWyKwKQEEALwXhKBnyaaNFeK3ljfc/qn9X/QFw+28EUfgZPHjRmHubuXLE2uR +s3ZoSXY2z7Dkv+NyHYMt8p+X8q5fR7JvUjK2XbPyKoiJVnHINll83yl67DaWfKNL +EjNoO0kIfbXfCkZ7EG6DL+iKtuxniGTcnGT47e+HJSqb/STpLMnWwXjBABEBAAG0 +I0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFuZy5jb20+iM4EEwEKADgWIQQ/ +lRafP/p9PytHbwxMvYJsOQdOOAUCWyKwKQIbAwULCQgHAwUVCgkICwUWAgMBAAIe +AQIXgAAKCRBMvYJsOQdOOOsFBAC62mXww8XuqvYLcVOvHkWLT6mhxrQOJXnlfpn7 +2uBV9CMhoG/Ycd43NONsJrB95Apr9TDIqWnVszNbqPCuBhZQSGLdbiDKjxnCWBk0 +69qv4RNtkpOhYB7jK4s8F5oQZqId6JasT/PmJTH92mhBYhhTQr0GYFuPX2UJdkw9 +Sn9C67iNBFsisDUBBAC3A+Yo9lgCnxi/pfskyLrweYif6kIXWLAtLTsM6g/6jt7b +wTrknuCPyTv0QKGXsAEe/cK/Xq3HvX9WfXPGIHc/X56ZIsHQ+RLowbZV/Lhok1IW +FAuQm8axr/by80cRwFnzhfPc/ukkAq2Qyj4hLsGblu6mxeAhzcp8aqmWOO2H9QAR +AQABiLYEKAEKACAWIQQ/lRafP/p9PytHbwxMvYJsOQdOOAUCWyK16gIdAAAKCRBM +vYJsOQdOOB1vA/4u4uLONsE+2GVOyBsHyy7uTdkuxaR9b54A/cz6jT/tzUbeIzgx +22neWhgvIEghnUZd0vEyK9k1wy5vbDlEo6nKzHso32N1QExGr5upRERAxweDxGOj +7luDwNypI7QcifE64lS/JmlnunwRCdRWMKc0Fp+7jtRc5mpwyHN/Suf5RokBagQY +AQoAIBYhBD+VFp8/+n0/K0dvDEy9gmw5B044BQJbIrA1AhsCAL8JEEy9gmw5B044 +tCAEGQEKAB0WIQSNdnkaWY6t62iX336UXbGvYdhXJwUCWyKwNQAKCRCUXbGvYdhX +JxJSA/9fCPHP6sUtGF1o3G1a3yvOUDGr1JWcct9U+QpbCt1mZoNopCNDDQAJvDWl +mvDgHfuogmgNJRjOMznvahbF+wpTXmB7LS0SK412gJzl1fFIpK4bgnhu0TwxNsO1 +8UkCZWqxRMgcNUn9z6XWONK8dgt5JNvHSHrwF4CxxwjL23AAtK+FA/UUoi3U4kbC +0XnSr1Sl+mrzQi1+H7xyMe7zjqe+gGANtskqexHzwWPUJCPZ5qpIa2l8ghiUim6b +4ymJ+N8/T8Yva1FaPEqfMzzqJr8McYFm0URioXJPvOAlRxdHPteZ0qUopt/Jawxl +Xt6B9h1YpeLoJwjwsvbi98UTRs0jXwoY +=3fWu +-----END PGP PUBLIC KEY BLOCK-----` + +const keyWithSubKeyAndBadSelfSigOrder = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mI0EWyLLDQEEAOqIOpJ/ha1OYAGduu9tS3rBz5vyjbNgJO4sFveEM0mgsHQ0X9/L +plonW+d0gRoO1dhJ8QICjDAc6+cna1DE3tEb5m6JtQ30teLZuqrR398Cf6w7NNVz +r3lrlmnH9JaKRuXl7tZciwyovneBfZVCdtsRZjaLI1uMQCz/BToiYe3DABEBAAG0 +I0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFuZy5jb20+iM4EEwEKADgWIQRZ +sixZOfQcZdW0wUqmgmdsv1O9xgUCWyLLDQIbAwULCQgHAwUVCgkICwUWAgMBAAIe +AQIXgAAKCRCmgmdsv1O9xql2A/4pix98NxjhdsXtazA9agpAKeADf9tG4Za27Gj+ +3DCww/E4iP2X35jZimSm/30QRB6j08uGCqd9vXkkJxtOt63y/IpVOtWX6vMWSTUm +k8xKkaYMP0/IzKNJ1qC/qYEUYpwERBKg9Z+k99E2Ql4kRHdxXUHq6OzY79H18Y+s +GdeM/riNBFsiyxsBBAC54Pxg/8ZWaZX1phGdwfe5mek27SOYpC0AxIDCSOdMeQ6G +HPk38pywl1d+S+KmF/F4Tdi+kWro62O4eG2uc/T8JQuRDUhSjX0Qa51gPzJrUOVT +CFyUkiZ/3ZDhtXkgfuso8ua2ChBgR9Ngr4v43tSqa9y6AK7v0qjxD1x+xMrjXQAR +AQABiQFxBBgBCgAmAhsCFiEEWbIsWTn0HGXVtMFKpoJnbL9TvcYFAlsizTIFCQAN +MRcAv7QgBBkBCgAdFiEEJcoVUVJIk5RWj1c/o62jUpRPICQFAlsiyxsACgkQo62j +UpRPICQq5gQApoWIigZxXFoM0uw4uJBS5JFZtirTANvirZV5RhndwHeMN6JttaBS +YnjyA4+n1D+zB2VqliD2QrsX12KJN6rGOehCtEIClQ1Hodo9nC6kMzzAwW1O8bZs +nRJmXV+bsvD4sidLZLjdwOVa3Cxh6pvq4Uur6a7/UYx121hEY0Qx0s8JEKaCZ2y/ +U73GGi0D/i20VW8AWYAPACm2zMlzExKTOAV01YTQH/3vW0WLrOse53WcIVZga6es +HuO4So0SOEAvxKMe5HpRIu2dJxTvd99Bo9xk9xJU0AoFrO0vNCRnL+5y68xMlODK +lEw5/kl0jeaTBp6xX0HDQOEVOpPGUwWV4Ij2EnvfNDXaE1vK1kffiQFrBBgBCgAg +AhsCFiEEWbIsWTn0HGXVtMFKpoJnbL9TvcYFAlsi0AYAv7QgBBkBCgAdFiEEJcoV +UVJIk5RWj1c/o62jUpRPICQFAlsiyxsACgkQo62jUpRPICQq5gQApoWIigZxXFoM +0uw4uJBS5JFZtirTANvirZV5RhndwHeMN6JttaBSYnjyA4+n1D+zB2VqliD2QrsX +12KJN6rGOehCtEIClQ1Hodo9nC6kMzzAwW1O8bZsnRJmXV+bsvD4sidLZLjdwOVa +3Cxh6pvq4Uur6a7/UYx121hEY0Qx0s8JEKaCZ2y/U73GRl0EAJokkXmy4zKDHWWi +wvK9gi2gQgRkVnu2AiONxJb5vjeLhM/07BRmH6K1o+w3fOeEQp4FjXj1eQ5fPSM6 +Hhwx2CTl9SDnPSBMiKXsEFRkmwQ2AAsQZLmQZvKBkLZYeBiwf+IY621eYDhZfo+G +1dh1WoUCyREZsJQg2YoIpWIcvw+a +=bNRo +-----END PGP PUBLIC KEY BLOCK----- +` diff --git a/vendor/golang.org/x/crypto/openpgp/keys_test.go b/vendor/golang.org/x/crypto/openpgp/keys_test.go index 3a155063..0eb1a9ef 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys_test.go +++ b/vendor/golang.org/x/crypto/openpgp/keys_test.go @@ -29,16 +29,16 @@ func TestKeyExpiry(t *testing.T) { // // So this should select the newest, non-expired encryption key. key, _ := entity.encryptionKey(time1) - if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" { - t.Errorf("Expected key 1ABB25A0 at time %s, but got key %s", time1.Format(timeFormat), id) + if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected { + t.Errorf("Expected key %s at time %s, but got key %s", expected, time1.Format(timeFormat), id) } // Once the first encryption subkey has expired, the second should be // selected. time2, _ := time.Parse(timeFormat, "2013-07-09") key, _ = entity.encryptionKey(time2) - if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" { - t.Errorf("Expected key 96A672F5 at time %s, but got key %s", time2.Format(timeFormat), id) + if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected { + t.Errorf("Expected key %s at time %s, but got key %s", expected, time2.Format(timeFormat), id) } // Once all the keys have expired, nothing should be returned. @@ -105,6 +105,33 @@ func TestGoodCrossSignature(t *testing.T) { } } +func TestRevokedUserID(t *testing.T) { + // This key contains 2 UIDs, one of which is revoked: + // [ultimate] (1) Golang Gopher + // [ revoked] (2) Golang Gopher + keys, err := ReadArmoredKeyRing(bytes.NewBufferString(revokedUserIDKey)) + if err != nil { + t.Fatal(err) + } + + if len(keys) != 1 { + t.Fatal("Failed to read key with a revoked user id") + } + + var identities []*Identity + for _, identity := range keys[0].Identities { + identities = append(identities, identity) + } + + if numIdentities, numExpected := len(identities), 1; numIdentities != numExpected { + t.Errorf("obtained %d identities, expected %d", numIdentities, numExpected) + } + + if identityName, expectedName := identities[0].Name, "Golang Gopher "; identityName != expectedName { + t.Errorf("obtained identity %s expected %s", identityName, expectedName) + } +} + // TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission. func TestExternallyRevocableKey(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex)) @@ -153,6 +180,44 @@ func TestKeyRevocation(t *testing.T) { } } +func TestKeyWithRevokedSubKey(t *testing.T) { + // This key contains a revoked sub key: + // pub rsa1024/0x4CBD826C39074E38 2018-06-14 [SC] + // Key fingerprint = 3F95 169F 3FFA 7D3F 2B47 6F0C 4CBD 826C 3907 4E38 + // uid Golang Gopher + // sub rsa1024/0x945DB1AF61D85727 2018-06-14 [S] [revoked: 2018-06-14] + + keys, err := ReadArmoredKeyRing(bytes.NewBufferString(keyWithSubKey)) + if err != nil { + t.Fatal(err) + } + + if len(keys) != 1 { + t.Fatal("Failed to read key with a sub key") + } + + identity := keys[0].Identities["Golang Gopher "] + + // Test for an issue where Subkey Binding Signatures (RFC 4880 5.2.1) were added to the identity + // preceding the Subkey Packet if the Subkey Packet was followed by more than one signature. + // For example, the current key has the following layout: + // PUBKEY UID SELFSIG SUBKEY REV SELFSIG + // The last SELFSIG would be added to the UID's signatures. This is wrong. + if numIdentitySigs, numExpected := len(identity.Signatures), 0; numIdentitySigs != numExpected { + t.Fatalf("got %d identity signatures, expected %d", numIdentitySigs, numExpected) + } + + if numSubKeys, numExpected := len(keys[0].Subkeys), 1; numSubKeys != numExpected { + t.Fatalf("got %d subkeys, expected %d", numSubKeys, numExpected) + } + + subKey := keys[0].Subkeys[0] + if subKey.Sig == nil { + t.Fatalf("subkey signature is nil") + } + +} + func TestSubkeyRevocation(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(revokedSubkeyHex)) if err != nil { @@ -189,6 +254,51 @@ func TestSubkeyRevocation(t *testing.T) { } } +func TestKeyWithSubKeyAndBadSelfSigOrder(t *testing.T) { + // This key was altered so that the self signatures following the + // subkey are in a sub-optimal order. + // + // Note: Should someone have to create a similar key again, look into + // gpgsplit, gpg --dearmor, and gpg --enarmor. + // + // The packet ordering is the following: + // PUBKEY UID UIDSELFSIG SUBKEY SELFSIG1 SELFSIG2 + // + // Where: + // SELFSIG1 expires on 2018-06-14 and was created first + // SELFSIG2 does not expire and was created after SELFSIG1 + // + // Test for RFC 4880 5.2.3.3: + // > An implementation that encounters multiple self-signatures on the + // > same object may resolve the ambiguity in any way it sees fit, but it + // > is RECOMMENDED that priority be given to the most recent self- + // > signature. + // + // This means that we should keep SELFSIG2. + + keys, err := ReadArmoredKeyRing(bytes.NewBufferString(keyWithSubKeyAndBadSelfSigOrder)) + if err != nil { + t.Fatal(err) + } + + if len(keys) != 1 { + t.Fatal("Failed to read key with a sub key and a bad selfsig packet order") + } + + key := keys[0] + + if numKeys, expected := len(key.Subkeys), 1; numKeys != expected { + t.Fatalf("Read %d subkeys, expected %d", numKeys, expected) + } + + subKey := key.Subkeys[0] + + if lifetime := subKey.Sig.KeyLifetimeSecs; lifetime != nil { + t.Errorf("The signature has a key lifetime (%d), but it should be nil", *lifetime) + } + +} + func TestKeyUsage(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex)) if err != nil { @@ -370,100 +480,16 @@ func TestNewEntityWithoutPreferredSymmetric(t *testing.T) { } } -const expiringKeyHex = "988d0451d1ec5d010400ba3385721f2dc3f4ab096b2ee867ab77213f0a27a8538441c35d2fa225b08798a1439a66a5150e6bdc3f40f5d28d588c712394c632b6299f77db8c0d48d37903fb72ebd794d61be6aa774688839e5fdecfe06b2684cc115d240c98c66cb1ef22ae84e3aa0c2b0c28665c1e7d4d044e7f270706193f5223c8d44e0d70b7b8da830011010001b40f4578706972792074657374206b657988be041301020028050251d1ec5d021b03050900278d00060b090807030206150802090a0b0416020301021e01021780000a091072589ad75e237d8c033503fd10506d72837834eb7f994117740723adc39227104b0d326a1161871c0b415d25b4aedef946ca77ea4c05af9c22b32cf98be86ab890111fced1ee3f75e87b7cc3c00dc63bbc85dfab91c0dc2ad9de2c4d13a34659333a85c6acc1a669c5e1d6cecb0cf1e56c10e72d855ae177ddc9e766f9b2dda57ccbb75f57156438bbdb4e42b88d0451d1ec5d0104009c64906559866c5cb61578f5846a94fcee142a489c9b41e67b12bb54cfe86eb9bc8566460f9a720cb00d6526fbccfd4f552071a8e3f7744b1882d01036d811ee5a3fb91a1c568055758f43ba5d2c6a9676b012f3a1a89e47bbf624f1ad571b208f3cc6224eb378f1645dd3d47584463f9eadeacfd1ce6f813064fbfdcc4b5a53001101000188a504180102000f021b0c050251d1f06b050900093e89000a091072589ad75e237d8c20e00400ab8310a41461425b37889c4da28129b5fae6084fafbc0a47dd1adc74a264c6e9c9cc125f40462ee1433072a58384daef88c961c390ed06426a81b464a53194c4e291ddd7e2e2ba3efced01537d713bd111f48437bde2363446200995e8e0d4e528dda377fd1e8f8ede9c8e2198b393bd86852ce7457a7e3daf74d510461a5b77b88d0451d1ece8010400b3a519f83ab0010307e83bca895170acce8964a044190a2b368892f7a244758d9fc193482648acb1fb9780d28cc22d171931f38bb40279389fc9bf2110876d4f3db4fcfb13f22f7083877fe56592b3b65251312c36f83ffcb6d313c6a17f197dd471f0712aad15a8537b435a92471ba2e5b0c72a6c72536c3b567c558d7b6051001101000188a504180102000f021b0c050251d1f07b050900279091000a091072589ad75e237d8ce69e03fe286026afacf7c97ee20673864d4459a2240b5655219950643c7dba0ac384b1d4359c67805b21d98211f7b09c2a0ccf6410c8c04d4ff4a51293725d8d6570d9d8bb0e10c07d22357caeb49626df99c180be02d77d1fe8ed25e7a54481237646083a9f89a11566cd20b9e995b1487c5f9e02aeb434f3a1897cd416dd0a87861838da3e9e" -const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98" -const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f" -const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011" -const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- -Charset: UTF-8 +func TestNewEntityPublicSerialization(t *testing.T) { + entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil) + if err != nil { + t.Fatal(err) + } + serializedEntity := bytes.NewBuffer(nil) + entity.Serialize(serializedEntity) -mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY -ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG -zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 -QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ -QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo -9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu -Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ -dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R -JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL -ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew -RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW -/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu -yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv -2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR -bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL -C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP -WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y -MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA -EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ -MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N -1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm -+ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N -lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW -CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF -4artDmrG -=7FfJ ------END PGP PUBLIC KEY BLOCK-----` - -const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY -ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG -zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 -QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ -QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo -9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu -Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ -dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R -JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL -ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew -RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW -/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu -yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ -UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe -iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK -FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8 -R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh -+SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA -EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO -52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb -u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl -w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep -54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+ -YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL -bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E -i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB -DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1 -8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY -s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745 -U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL -6LCg2mg= -=Dhm4 ------END PGP PUBLIC KEY BLOCK-----` - -const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo -7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom -lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0 -E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC -CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw -6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH -7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv -X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7 -GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl -y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw -R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW -CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+ -LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO -aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx -yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl -BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr -Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK -CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp -C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ -SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/ -MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70= -=vtbN ------END PGP PUBLIC KEY BLOCK-----` + _, err = ReadEntity(packet.NewReader(bytes.NewBuffer(serializedEntity.Bytes()))) + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go index 625bb5ac..5af64c54 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go @@ -404,14 +404,16 @@ const ( type PublicKeyAlgorithm uint8 const ( - PubKeyAlgoRSA PublicKeyAlgorithm = 1 - PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 - PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 - PubKeyAlgoElGamal PublicKeyAlgorithm = 16 - PubKeyAlgoDSA PublicKeyAlgorithm = 17 + PubKeyAlgoRSA PublicKeyAlgorithm = 1 + PubKeyAlgoElGamal PublicKeyAlgorithm = 16 + PubKeyAlgoDSA PublicKeyAlgorithm = 17 // RFC 6637, Section 5. PubKeyAlgoECDH PublicKeyAlgorithm = 18 PubKeyAlgoECDSA PublicKeyAlgorithm = 19 + + // Deprecated in RFC 4880, Section 13.5. Use key flags instead. + PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 + PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 ) // CanEncrypt returns true if it's possible to encrypt a message to a public diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go index 34734cc6..bd31ccea 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go @@ -64,14 +64,19 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK return pk } -// NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that +// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that // implements RSA or ECDSA. func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { pk := new(PrivateKey) + // In general, the public Keys should be used as pointers. We still + // type-switch on the values, for backwards-compatibility. switch pubkey := signer.Public().(type) { + case *rsa.PublicKey: + pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) case rsa.PublicKey: pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) - pk.PubKeyAlgo = PubKeyAlgoRSASignOnly + case *ecdsa.PublicKey: + pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) case ecdsa.PublicKey: pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) default: diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go index ac651d91..cc08b483 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go @@ -14,7 +14,6 @@ import ( "crypto/x509" "encoding/hex" "hash" - "io" "testing" "time" ) @@ -162,15 +161,7 @@ func TestECDSAPrivateKey(t *testing.T) { } type rsaSigner struct { - priv *rsa.PrivateKey -} - -func (s *rsaSigner) Public() crypto.PublicKey { - return s.priv.PublicKey -} - -func (s *rsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - return s.priv.Sign(rand, msg, opts) + *rsa.PrivateKey } func TestRSASignerPrivateKey(t *testing.T) { @@ -181,12 +172,8 @@ func TestRSASignerPrivateKey(t *testing.T) { priv := NewSignerPrivateKey(time.Now(), &rsaSigner{rsaPriv}) - if priv.PubKeyAlgo != PubKeyAlgoRSASignOnly { - t.Fatal("NewSignerPrivateKey should have made a sign-only RSA private key") - } - sig := &Signature{ - PubKeyAlgo: PubKeyAlgoRSASignOnly, + PubKeyAlgo: PubKeyAlgoRSA, Hash: crypto.SHA256, } msg := []byte("Hello World!") @@ -208,15 +195,7 @@ func TestRSASignerPrivateKey(t *testing.T) { } type ecdsaSigner struct { - priv *ecdsa.PrivateKey -} - -func (s *ecdsaSigner) Public() crypto.PublicKey { - return s.priv.PublicKey -} - -func (s *ecdsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - return s.priv.Sign(rand, msg, opts) + *ecdsa.PrivateKey } func TestECDSASignerPrivateKey(t *testing.T) { diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go index 6ce0cbed..b2a24a53 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/signature.go @@ -542,7 +542,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e r, s, err = ecdsa.Sign(config.Random(), pk, digest) } else { var b []byte - b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, nil) + b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) if err == nil { r, s, err = unwrapECDSASig(b) } diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go index 96a2b382..d19ffbc7 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go @@ -80,7 +80,7 @@ func (uat *UserAttribute) Serialize(w io.Writer) (err error) { // ImageData returns zero or more byte slices, each containing // JPEG File Interchange Format (JFIF), for each photo in the -// the user attribute packet. +// user attribute packet. func (uat *UserAttribute) ImageData() (imageData [][]byte) { for _, sp := range uat.Contents { if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { diff --git a/vendor/golang.org/x/crypto/openpgp/read_test.go b/vendor/golang.org/x/crypto/openpgp/read_test.go index 1fbfbac4..f5bba301 100644 --- a/vendor/golang.org/x/crypto/openpgp/read_test.go +++ b/vendor/golang.org/x/crypto/openpgp/read_test.go @@ -124,7 +124,7 @@ func checkSignedMessage(t *testing.T, signedHex, expected string) { return } - if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted { + if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.DecryptedWith != (Key{}) { t.Errorf("bad MessageDetails: %#v", md) } diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go index 65a304cc..4ee71784 100644 --- a/vendor/golang.org/x/crypto/openpgp/write.go +++ b/vendor/golang.org/x/crypto/openpgp/write.go @@ -164,12 +164,12 @@ func hashToHashId(h crypto.Hash) uint8 { return v } -// Encrypt encrypts a message to a number of recipients and, optionally, signs -// it. hints contains optional information, that is also encrypted, that aids -// the recipients in processing the message. The resulting WriteCloser must -// be closed after the contents of the file have been written. -// If config is nil, sensible defaults will be used. -func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { +// writeAndSign writes the data as a payload package and, optionally, signs +// it. hints contains optional information, that is also encrypted, +// that aids the recipients in processing the message. The resulting +// WriteCloser must be closed after the contents of the file have been +// written. If config is nil, sensible defaults will be used. +func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { var signer *packet.PrivateKey if signed != nil { signKey, ok := signed.signingKey(config.Now()) @@ -185,6 +185,83 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } + var hash crypto.Hash + for _, hashId := range candidateHashes { + if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { + hash = h + break + } + } + + // If the hash specified by config is a candidate, we'll use that. + if configuredHash := config.Hash(); configuredHash.Available() { + for _, hashId := range candidateHashes { + if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { + hash = h + break + } + } + } + + if hash == 0 { + hashId := candidateHashes[0] + name, ok := s2k.HashIdToString(hashId) + if !ok { + name = "#" + strconv.Itoa(int(hashId)) + } + return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") + } + + if signer != nil { + ops := &packet.OnePassSignature{ + SigType: packet.SigTypeBinary, + Hash: hash, + PubKeyAlgo: signer.PubKeyAlgo, + KeyId: signer.KeyId, + IsLast: true, + } + if err := ops.Serialize(payload); err != nil { + return nil, err + } + } + + if hints == nil { + hints = &FileHints{} + } + + w := payload + if signer != nil { + // If we need to write a signature packet after the literal + // data then we need to stop literalData from closing + // encryptedData. + w = noOpCloser{w} + + } + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) + if err != nil { + return nil, err + } + + if signer != nil { + return signatureWriter{payload, literalData, hash, hash.New(), signer, config}, nil + } + return literalData, nil +} + +// Encrypt encrypts a message to a number of recipients and, optionally, signs +// it. hints contains optional information, that is also encrypted, that aids +// the recipients in processing the message. The resulting WriteCloser must +// be closed after the contents of the file have been written. +// If config is nil, sensible defaults will be used. +func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { + if len(to) == 0 { + return nil, errors.InvalidArgumentError("no encryption recipient provided") + } + // These are the possible ciphers that we'll use for the message. candidateCiphers := []uint8{ uint8(packet.CipherAES128), @@ -194,6 +271,7 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint // These are the possible hash functions that we'll use for the signature. candidateHashes := []uint8{ hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), hashToHashId(crypto.SHA512), hashToHashId(crypto.SHA1), hashToHashId(crypto.RIPEMD160), @@ -241,33 +319,6 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } - var hash crypto.Hash - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { - hash = h - break - } - } - - // If the hash specified by config is a candidate, we'll use that. - if configuredHash := config.Hash(); configuredHash.Available() { - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { - hash = h - break - } - } - } - - if hash == 0 { - hashId := candidateHashes[0] - name, ok := s2k.HashIdToString(hashId) - if !ok { - name = "#" + strconv.Itoa(int(hashId)) - } - return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") - } - symKey := make([]byte, cipher.KeySize()) if _, err := io.ReadFull(config.Random(), symKey); err != nil { return nil, err @@ -279,49 +330,38 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } - encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) + payload, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) if err != nil { return } - if signer != nil { - ops := &packet.OnePassSignature{ - SigType: packet.SigTypeBinary, - Hash: hash, - PubKeyAlgo: signer.PubKeyAlgo, - KeyId: signer.KeyId, - IsLast: true, - } - if err := ops.Serialize(encryptedData); err != nil { - return nil, err - } + return writeAndSign(payload, candidateHashes, signed, hints, config) +} + +// Sign signs a message. The resulting WriteCloser must be closed after the +// contents of the file have been written. hints contains optional information +// that aids the recipients in processing the message. +// If config is nil, sensible defaults will be used. +func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) { + if signed == nil { + return nil, errors.InvalidArgumentError("no signer provided") } - if hints == nil { - hints = &FileHints{} + // These are the possible hash functions that we'll use for the signature. + candidateHashes := []uint8{ + hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA1), + hashToHashId(crypto.RIPEMD160), } - - w := encryptedData - if signer != nil { - // If we need to write a signature packet after the literal - // data then we need to stop literalData from closing - // encryptedData. - w = noOpCloser{encryptedData} - + defaultHashes := candidateHashes[len(candidateHashes)-1:] + preferredHashes := signed.primaryIdentity().SelfSignature.PreferredHash + if len(preferredHashes) == 0 { + preferredHashes = defaultHashes } - var epochSeconds uint32 - if !hints.ModTime.IsZero() { - epochSeconds = uint32(hints.ModTime.Unix()) - } - literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) - if err != nil { - return nil, err - } - - if signer != nil { - return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil - } - return literalData, nil + candidateHashes = intersectPreferences(candidateHashes, preferredHashes) + return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, config) } // signatureWriter hashes the contents of a message while passing it along to diff --git a/vendor/golang.org/x/crypto/openpgp/write_test.go b/vendor/golang.org/x/crypto/openpgp/write_test.go index f2d50a0c..cbc8f4da 100644 --- a/vendor/golang.org/x/crypto/openpgp/write_test.go +++ b/vendor/golang.org/x/crypto/openpgp/write_test.go @@ -271,3 +271,92 @@ func TestEncryption(t *testing.T) { } } } + +var testSigningTests = []struct { + keyRingHex string +}{ + { + testKeys1And2PrivateHex, + }, + { + dsaElGamalTestKeysHex, + }, +} + +func TestSigning(t *testing.T) { + for i, test := range testSigningTests { + kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex)) + + passphrase := []byte("passphrase") + for _, entity := range kring { + if entity.PrivateKey != nil && entity.PrivateKey.Encrypted { + err := entity.PrivateKey.Decrypt(passphrase) + if err != nil { + t.Errorf("#%d: failed to decrypt key", i) + } + } + for _, subkey := range entity.Subkeys { + if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted { + err := subkey.PrivateKey.Decrypt(passphrase) + if err != nil { + t.Errorf("#%d: failed to decrypt subkey", i) + } + } + } + } + + signed := kring[0] + + buf := new(bytes.Buffer) + w, err := Sign(buf, signed, nil /* no hints */, nil) + if err != nil { + t.Errorf("#%d: error in Sign: %s", i, err) + continue + } + + const message = "testing" + _, err = w.Write([]byte(message)) + if err != nil { + t.Errorf("#%d: error writing plaintext: %s", i, err) + continue + } + err = w.Close() + if err != nil { + t.Errorf("#%d: error closing WriteCloser: %s", i, err) + continue + } + + md, err := ReadMessage(buf, kring, nil /* no prompt */, nil) + if err != nil { + t.Errorf("#%d: error reading message: %s", i, err) + continue + } + + testTime, _ := time.Parse("2006-01-02", "2013-07-01") + signKey, _ := kring[0].signingKey(testTime) + expectedKeyId := signKey.PublicKey.KeyId + if md.SignedByKeyId != expectedKeyId { + t.Errorf("#%d: message signed by wrong key id, got: %v, want: %v", i, *md.SignedBy, expectedKeyId) + } + if md.SignedBy == nil { + t.Errorf("#%d: failed to find the signing Entity", i) + } + + plaintext, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + t.Errorf("#%d: error reading contents: %v", i, err) + continue + } + + if string(plaintext) != message { + t.Errorf("#%d: got: %q, want: %q", i, plaintext, message) + } + + if md.SignatureError != nil { + t.Errorf("#%d: signature error: %q", i, md.SignatureError) + } + if md.Signature == nil { + t.Error("signature missing") + } + } +} diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305_test.go b/vendor/golang.org/x/crypto/poly1305/poly1305_test.go index 017027fe..256bdbba 100644 --- a/vendor/golang.org/x/crypto/poly1305/poly1305_test.go +++ b/vendor/golang.org/x/crypto/poly1305/poly1305_test.go @@ -5,7 +5,6 @@ package poly1305 import ( - "bytes" "encoding/hex" "flag" "testing" @@ -14,80 +13,51 @@ import ( var stressFlag = flag.Bool("stress", false, "run slow stress tests") -var testData = []struct { - in, k, correct []byte -}{ - { - []byte("Hello world!"), - []byte("this is 32-byte key for Poly1305"), - []byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0}, - }, - { - make([]byte, 32), - []byte("this is 32-byte key for Poly1305"), - []byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07}, - }, - { - make([]byte, 2007), - []byte("this is 32-byte key for Poly1305"), - []byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa}, - }, - { - make([]byte, 2007), - make([]byte, 32), - make([]byte, 16), - }, - { - // This test triggers an edge-case. See https://go-review.googlesource.com/#/c/30101/. - []byte{0x81, 0xd8, 0xb2, 0xe4, 0x6a, 0x25, 0x21, 0x3b, 0x58, 0xfe, 0xe4, 0x21, 0x3a, 0x2a, 0x28, 0xe9, 0x21, 0xc1, 0x2a, 0x96, 0x32, 0x51, 0x6d, 0x3b, 0x73, 0x27, 0x27, 0x27, 0xbe, 0xcf, 0x21, 0x29}, - []byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d}, - []byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14}, - }, - { - // This test generates a result of (2^130-1) % (2^130-5). - []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - { - // This test generates a result of (2^130-6) % (2^130-5). - []byte{ - 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - []byte{0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - }, - { - // This test generates a result of (2^130-5) % (2^130-5). - []byte{ - 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, +type test struct { + in string + key string + tag string } -func testSum(t *testing.T, unaligned bool) { - var out [16]byte - var key [32]byte +func (t *test) Input() []byte { + in, err := hex.DecodeString(t.in) + if err != nil { + panic(err) + } + return in +} +func (t *test) Key() [32]byte { + buf, err := hex.DecodeString(t.key) + if err != nil { + panic(err) + } + var key [32]byte + copy(key[:], buf[:32]) + return key +} + +func (t *test) Tag() [16]byte { + buf, err := hex.DecodeString(t.tag) + if err != nil { + panic(err) + } + var tag [16]byte + copy(tag[:], buf[:16]) + return tag +} + +func testSum(t *testing.T, unaligned bool, sumImpl func(tag *[TagSize]byte, msg []byte, key *[32]byte)) { + var tag [16]byte for i, v := range testData { - in := v.in + in := v.Input() if unaligned { in = unalignBytes(in) } - copy(key[:], v.k) - Sum(&out, in, &key) - if !bytes.Equal(out[:], v.correct) { - t.Errorf("%d: expected %x, got %x", i, v.correct, out[:]) + key := v.Key() + sumImpl(&tag, in, &key) + if tag != v.Tag() { + t.Errorf("%d: expected %x, got %x", i, v.Tag(), tag[:]) } } } @@ -125,8 +95,10 @@ func TestBurnin(t *testing.T) { } } -func TestSum(t *testing.T) { testSum(t, false) } -func TestSumUnaligned(t *testing.T) { testSum(t, true) } +func TestSum(t *testing.T) { testSum(t, false, Sum) } +func TestSumUnaligned(t *testing.T) { testSum(t, true, Sum) } +func TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) } +func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, sumGeneric) } func benchmark(b *testing.B, size int, unaligned bool) { var out [16]byte @@ -146,6 +118,7 @@ func Benchmark64(b *testing.B) { benchmark(b, 64, false) } func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) } func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) } func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) } +func Benchmark2M(b *testing.B) { benchmark(b, 2097152, true) } func unalignBytes(in []byte) []byte { out := make([]byte, len(in)+1) diff --git a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go new file mode 100644 index 00000000..751eec52 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go @@ -0,0 +1,14 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,!go1.11 !arm,!amd64,!s390x gccgo appengine nacl + +package poly1305 + +// Sum generates an authenticator for msg using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { + sumGeneric(out, msg, key) +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ref.go b/vendor/golang.org/x/crypto/poly1305/sum_ref.go index b2805a5c..c4d59bd0 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_ref.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_ref.go @@ -2,16 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!arm gccgo appengine nacl - package poly1305 import "encoding/binary" -// Sum generates an authenticator for msg using a one-time key and puts the -// 16-byte result into out. Authenticating two different messages with the same -// key allows an attacker to forge messages at will. -func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { +// sumGeneric generates an authenticator for msg using a one-time key and +// puts the 16-byte result into out. This is the generic implementation of +// Sum and should be called if no assembly implementation is available. +func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { var ( h0, h1, h2, h3, h4 uint32 // the hash accumulators r0, r1, r2, r3, r4 uint64 // the r part of the key diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go new file mode 100644 index 00000000..7a266cec --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go @@ -0,0 +1,49 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,go1.11,!gccgo,!appengine + +package poly1305 + +// hasVectorFacility reports whether the machine supports +// the vector facility (vx). +func hasVectorFacility() bool + +// hasVMSLFacility reports whether the machine supports +// Vector Multiply Sum Logical (VMSL). +func hasVMSLFacility() bool + +var hasVX = hasVectorFacility() +var hasVMSL = hasVMSLFacility() + +// poly1305vx is an assembly implementation of Poly1305 that uses vector +// instructions. It must only be called if the vector facility (vx) is +// available. +//go:noescape +func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte) + +// poly1305vmsl is an assembly implementation of Poly1305 that uses vector +// instructions, including VMSL. It must only be called if the vector facility (vx) is +// available and if VMSL is supported. +//go:noescape +func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) + +// Sum generates an authenticator for m using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[16]byte, m []byte, key *[32]byte) { + if hasVX { + var mPtr *byte + if len(m) > 0 { + mPtr = &m[0] + } + if hasVMSL && len(m) > 256 { + poly1305vmsl(out, mPtr, uint64(len(m)), key) + } else { + poly1305vx(out, mPtr, uint64(len(m)), key) + } + } else { + sumGeneric(out, m, key) + } +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s new file mode 100644 index 00000000..356c07a6 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s @@ -0,0 +1,400 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,go1.11,!gccgo,!appengine + +#include "textflag.h" + +// Implementation of Poly1305 using the vector facility (vx). + +// constants +#define MOD26 V0 +#define EX0 V1 +#define EX1 V2 +#define EX2 V3 + +// temporaries +#define T_0 V4 +#define T_1 V5 +#define T_2 V6 +#define T_3 V7 +#define T_4 V8 + +// key (r) +#define R_0 V9 +#define R_1 V10 +#define R_2 V11 +#define R_3 V12 +#define R_4 V13 +#define R5_1 V14 +#define R5_2 V15 +#define R5_3 V16 +#define R5_4 V17 +#define RSAVE_0 R5 +#define RSAVE_1 R6 +#define RSAVE_2 R7 +#define RSAVE_3 R8 +#define RSAVE_4 R9 +#define R5SAVE_1 V28 +#define R5SAVE_2 V29 +#define R5SAVE_3 V30 +#define R5SAVE_4 V31 + +// message block +#define F_0 V18 +#define F_1 V19 +#define F_2 V20 +#define F_3 V21 +#define F_4 V22 + +// accumulator +#define H_0 V23 +#define H_1 V24 +#define H_2 V25 +#define H_3 V26 +#define H_4 V27 + +GLOBL ·keyMask<>(SB), RODATA, $16 +DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f +DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f + +GLOBL ·bswapMask<>(SB), RODATA, $16 +DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 +DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 + +GLOBL ·constants<>(SB), RODATA, $64 +// MOD26 +DATA ·constants<>+0(SB)/8, $0x3ffffff +DATA ·constants<>+8(SB)/8, $0x3ffffff +// EX0 +DATA ·constants<>+16(SB)/8, $0x0006050403020100 +DATA ·constants<>+24(SB)/8, $0x1016151413121110 +// EX1 +DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706 +DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716 +// EX2 +DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d +DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d + +// h = (f*g) % (2**130-5) [partial reduction] +#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ + VMLOF f0, g0, h0 \ + VMLOF f0, g1, h1 \ + VMLOF f0, g2, h2 \ + VMLOF f0, g3, h3 \ + VMLOF f0, g4, h4 \ + VMLOF f1, g54, T_0 \ + VMLOF f1, g0, T_1 \ + VMLOF f1, g1, T_2 \ + VMLOF f1, g2, T_3 \ + VMLOF f1, g3, T_4 \ + VMALOF f2, g53, h0, h0 \ + VMALOF f2, g54, h1, h1 \ + VMALOF f2, g0, h2, h2 \ + VMALOF f2, g1, h3, h3 \ + VMALOF f2, g2, h4, h4 \ + VMALOF f3, g52, T_0, T_0 \ + VMALOF f3, g53, T_1, T_1 \ + VMALOF f3, g54, T_2, T_2 \ + VMALOF f3, g0, T_3, T_3 \ + VMALOF f3, g1, T_4, T_4 \ + VMALOF f4, g51, h0, h0 \ + VMALOF f4, g52, h1, h1 \ + VMALOF f4, g53, h2, h2 \ + VMALOF f4, g54, h3, h3 \ + VMALOF f4, g0, h4, h4 \ + VAG T_0, h0, h0 \ + VAG T_1, h1, h1 \ + VAG T_2, h2, h2 \ + VAG T_3, h3, h3 \ + VAG T_4, h4, h4 + +// carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4 +#define REDUCE(h0, h1, h2, h3, h4) \ + VESRLG $26, h0, T_0 \ + VESRLG $26, h3, T_1 \ + VN MOD26, h0, h0 \ + VN MOD26, h3, h3 \ + VAG T_0, h1, h1 \ + VAG T_1, h4, h4 \ + VESRLG $26, h1, T_2 \ + VESRLG $26, h4, T_3 \ + VN MOD26, h1, h1 \ + VN MOD26, h4, h4 \ + VESLG $2, T_3, T_4 \ + VAG T_3, T_4, T_4 \ + VAG T_2, h2, h2 \ + VAG T_4, h0, h0 \ + VESRLG $26, h2, T_0 \ + VESRLG $26, h0, T_1 \ + VN MOD26, h2, h2 \ + VN MOD26, h0, h0 \ + VAG T_0, h3, h3 \ + VAG T_1, h1, h1 \ + VESRLG $26, h3, T_2 \ + VN MOD26, h3, h3 \ + VAG T_2, h4, h4 + +// expand in0 into d[0] and in1 into d[1] +#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ + VGBM $0x0707, d1 \ // d1=tmp + VPERM in0, in1, EX2, d4 \ + VPERM in0, in1, EX0, d0 \ + VPERM in0, in1, EX1, d2 \ + VN d1, d4, d4 \ + VESRLG $26, d0, d1 \ + VESRLG $30, d2, d3 \ + VESRLG $4, d2, d2 \ + VN MOD26, d0, d0 \ + VN MOD26, d1, d1 \ + VN MOD26, d2, d2 \ + VN MOD26, d3, d3 + +// pack h4:h0 into h1:h0 (no carry) +#define PACK(h0, h1, h2, h3, h4) \ + VESLG $26, h1, h1 \ + VESLG $26, h3, h3 \ + VO h0, h1, h0 \ + VO h2, h3, h2 \ + VESLG $4, h2, h2 \ + VLEIB $7, $48, h1 \ + VSLB h1, h2, h2 \ + VO h0, h2, h0 \ + VLEIB $7, $104, h1 \ + VSLB h1, h4, h3 \ + VO h3, h0, h0 \ + VLEIB $7, $24, h1 \ + VSRLB h1, h4, h1 + +// if h > 2**130-5 then h -= 2**130-5 +#define MOD(h0, h1, t0, t1, t2) \ + VZERO t0 \ + VLEIG $1, $5, t0 \ + VACCQ h0, t0, t1 \ + VAQ h0, t0, t0 \ + VONE t2 \ + VLEIG $1, $-4, t2 \ + VAQ t2, t1, t1 \ + VACCQ h1, t1, t1 \ + VONE t2 \ + VAQ t2, t1, t1 \ + VN h0, t1, t2 \ + VNC t0, t1, t1 \ + VO t1, t2, h0 + +// func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]key) +TEXT ·poly1305vx(SB), $0-32 + // This code processes up to 2 blocks (32 bytes) per iteration + // using the algorithm described in: + // NEON crypto, Daniel J. Bernstein & Peter Schwabe + // https://cryptojedi.org/papers/neoncrypto-20120320.pdf + LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key + + // load MOD26, EX0, EX1 and EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), MOD26, EX2 + + // setup r + VL (R4), T_0 + MOVD $·keyMask<>(SB), R6 + VL (R6), T_1 + VN T_0, T_1, T_0 + EXPAND(T_0, T_0, R_0, R_1, R_2, R_3, R_4) + + // setup r*5 + VLEIG $0, $5, T_0 + VLEIG $1, $5, T_0 + + // store r (for final block) + VMLOF T_0, R_1, R5SAVE_1 + VMLOF T_0, R_2, R5SAVE_2 + VMLOF T_0, R_3, R5SAVE_3 + VMLOF T_0, R_4, R5SAVE_4 + VLGVG $0, R_0, RSAVE_0 + VLGVG $0, R_1, RSAVE_1 + VLGVG $0, R_2, RSAVE_2 + VLGVG $0, R_3, RSAVE_3 + VLGVG $0, R_4, RSAVE_4 + + // skip r**2 calculation + CMPBLE R3, $16, skip + + // calculate r**2 + MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5SAVE_1, R5SAVE_2, R5SAVE_3, R5SAVE_4, H_0, H_1, H_2, H_3, H_4) + REDUCE(H_0, H_1, H_2, H_3, H_4) + VLEIG $0, $5, T_0 + VLEIG $1, $5, T_0 + VMLOF T_0, H_1, R5_1 + VMLOF T_0, H_2, R5_2 + VMLOF T_0, H_3, R5_3 + VMLOF T_0, H_4, R5_4 + VLR H_0, R_0 + VLR H_1, R_1 + VLR H_2, R_2 + VLR H_3, R_3 + VLR H_4, R_4 + + // initialize h + VZERO H_0 + VZERO H_1 + VZERO H_2 + VZERO H_3 + VZERO H_4 + +loop: + CMPBLE R3, $32, b2 + VLM (R2), T_0, T_1 + SUB $32, R3 + MOVD $32(R2), R2 + EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) + VLEIB $4, $1, F_4 + VLEIB $12, $1, F_4 + +multiply: + VAG H_0, F_0, F_0 + VAG H_1, F_1, F_1 + VAG H_2, F_2, F_2 + VAG H_3, F_3, F_3 + VAG H_4, F_4, F_4 + MULTIPLY(F_0, F_1, F_2, F_3, F_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) + REDUCE(H_0, H_1, H_2, H_3, H_4) + CMPBNE R3, $0, loop + +finish: + // sum vectors + VZERO T_0 + VSUMQG H_0, T_0, H_0 + VSUMQG H_1, T_0, H_1 + VSUMQG H_2, T_0, H_2 + VSUMQG H_3, T_0, H_3 + VSUMQG H_4, T_0, H_4 + + // h may be >= 2*(2**130-5) so we need to reduce it again + REDUCE(H_0, H_1, H_2, H_3, H_4) + + // carry h1->h4 + VESRLG $26, H_1, T_1 + VN MOD26, H_1, H_1 + VAQ T_1, H_2, H_2 + VESRLG $26, H_2, T_2 + VN MOD26, H_2, H_2 + VAQ T_2, H_3, H_3 + VESRLG $26, H_3, T_3 + VN MOD26, H_3, H_3 + VAQ T_3, H_4, H_4 + + // h is now < 2*(2**130-5) + // pack h into h1 (hi) and h0 (lo) + PACK(H_0, H_1, H_2, H_3, H_4) + + // if h > 2**130-5 then h -= 2**130-5 + MOD(H_0, H_1, T_0, T_1, T_2) + + // h += s + MOVD $·bswapMask<>(SB), R5 + VL (R5), T_1 + VL 16(R4), T_0 + VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big) + VAQ T_0, H_0, H_0 + VPERM H_0, H_0, T_1, H_0 // reverse bytes (to little) + VST H_0, (R1) + + RET + +b2: + CMPBLE R3, $16, b1 + + // 2 blocks remaining + SUB $17, R3 + VL (R2), T_0 + VLL R3, 16(R2), T_1 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, T_1 + EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) + CMPBNE R3, $16, 2(PC) + VLEIB $12, $1, F_4 + VLEIB $4, $1, F_4 + + // setup [r²,r] + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, RSAVE_3, R_3 + VLVGG $1, RSAVE_4, R_4 + VPDI $0, R5_1, R5SAVE_1, R5_1 + VPDI $0, R5_2, R5SAVE_2, R5_2 + VPDI $0, R5_3, R5SAVE_3, R5_3 + VPDI $0, R5_4, R5SAVE_4, R5_4 + + MOVD $0, R3 + BR multiply + +skip: + VZERO H_0 + VZERO H_1 + VZERO H_2 + VZERO H_3 + VZERO H_4 + + CMPBEQ R3, $0, finish + +b1: + // 1 block remaining + SUB $1, R3 + VLL R3, (R2), T_0 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, T_0 + VZERO T_1 + EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) + CMPBNE R3, $16, 2(PC) + VLEIB $4, $1, F_4 + VLEIG $1, $1, R_0 + VZERO R_1 + VZERO R_2 + VZERO R_3 + VZERO R_4 + VZERO R5_1 + VZERO R5_2 + VZERO R5_3 + VZERO R5_4 + + // setup [r, 1] + VLVGG $0, RSAVE_0, R_0 + VLVGG $0, RSAVE_1, R_1 + VLVGG $0, RSAVE_2, R_2 + VLVGG $0, RSAVE_3, R_3 + VLVGG $0, RSAVE_4, R_4 + VPDI $0, R5SAVE_1, R5_1, R5_1 + VPDI $0, R5SAVE_2, R5_2, R5_2 + VPDI $0, R5SAVE_3, R5_3, R5_3 + VPDI $0, R5SAVE_4, R5_4, R5_4 + + MOVD $0, R3 + BR multiply + +TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 + MOVD $x-24(SP), R1 + XC $24, 0(R1), 0(R1) // clear the storage + MOVD $2, R0 // R0 is the number of double words stored -1 + WORD $0xB2B01000 // STFLE 0(R1) + XOR R0, R0 // reset the value of R0 + MOVBZ z-8(SP), R1 + AND $0x40, R1 + BEQ novector + +vectorinstalled: + // check if the vector instruction has been enabled + VLEIB $0, $0xF, V16 + VLGVB $0, V16, R1 + CMPBNE R1, $0xF, novector + MOVB $1, ret+0(FP) // have vx + RET + +novector: + MOVB $0, ret+0(FP) // no vx + RET diff --git a/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s new file mode 100644 index 00000000..e548020b --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s @@ -0,0 +1,931 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,go1.11,!gccgo,!appengine + +#include "textflag.h" + +// Implementation of Poly1305 using the vector facility (vx) and the VMSL instruction. + +// constants +#define EX0 V1 +#define EX1 V2 +#define EX2 V3 + +// temporaries +#define T_0 V4 +#define T_1 V5 +#define T_2 V6 +#define T_3 V7 +#define T_4 V8 +#define T_5 V9 +#define T_6 V10 +#define T_7 V11 +#define T_8 V12 +#define T_9 V13 +#define T_10 V14 + +// r**2 & r**4 +#define R_0 V15 +#define R_1 V16 +#define R_2 V17 +#define R5_1 V18 +#define R5_2 V19 +// key (r) +#define RSAVE_0 R7 +#define RSAVE_1 R8 +#define RSAVE_2 R9 +#define R5SAVE_1 R10 +#define R5SAVE_2 R11 + +// message block +#define M0 V20 +#define M1 V21 +#define M2 V22 +#define M3 V23 +#define M4 V24 +#define M5 V25 + +// accumulator +#define H0_0 V26 +#define H1_0 V27 +#define H2_0 V28 +#define H0_1 V29 +#define H1_1 V30 +#define H2_1 V31 + +GLOBL ·keyMask<>(SB), RODATA, $16 +DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f +DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f + +GLOBL ·bswapMask<>(SB), RODATA, $16 +DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 +DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 + +GLOBL ·constants<>(SB), RODATA, $48 +// EX0 +DATA ·constants<>+0(SB)/8, $0x18191a1b1c1d1e1f +DATA ·constants<>+8(SB)/8, $0x0000050403020100 +// EX1 +DATA ·constants<>+16(SB)/8, $0x18191a1b1c1d1e1f +DATA ·constants<>+24(SB)/8, $0x00000a0908070605 +// EX2 +DATA ·constants<>+32(SB)/8, $0x18191a1b1c1d1e1f +DATA ·constants<>+40(SB)/8, $0x0000000f0e0d0c0b + +GLOBL ·c<>(SB), RODATA, $48 +// EX0 +DATA ·c<>+0(SB)/8, $0x0000050403020100 +DATA ·c<>+8(SB)/8, $0x0000151413121110 +// EX1 +DATA ·c<>+16(SB)/8, $0x00000a0908070605 +DATA ·c<>+24(SB)/8, $0x00001a1918171615 +// EX2 +DATA ·c<>+32(SB)/8, $0x0000000f0e0d0c0b +DATA ·c<>+40(SB)/8, $0x0000001f1e1d1c1b + +GLOBL ·reduce<>(SB), RODATA, $32 +// 44 bit +DATA ·reduce<>+0(SB)/8, $0x0 +DATA ·reduce<>+8(SB)/8, $0xfffffffffff +// 42 bit +DATA ·reduce<>+16(SB)/8, $0x0 +DATA ·reduce<>+24(SB)/8, $0x3ffffffffff + +// h = (f*g) % (2**130-5) [partial reduction] +// uses T_0...T_9 temporary registers +// input: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2 +// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 +// output: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2 +#define MULTIPLY(m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) \ + \ // Eliminate the dependency for the last 2 VMSLs + VMSLG m02_0, r_2, m4_2, m4_2 \ + VMSLG m13_0, r_2, m5_2, m5_2 \ // 8 VMSLs pipelined + VMSLG m02_0, r_0, m4_0, m4_0 \ + VMSLG m02_1, r5_2, V0, T_0 \ + VMSLG m02_0, r_1, m4_1, m4_1 \ + VMSLG m02_1, r_0, V0, T_1 \ + VMSLG m02_1, r_1, V0, T_2 \ + VMSLG m02_2, r5_1, V0, T_3 \ + VMSLG m02_2, r5_2, V0, T_4 \ + VMSLG m13_0, r_0, m5_0, m5_0 \ + VMSLG m13_1, r5_2, V0, T_5 \ + VMSLG m13_0, r_1, m5_1, m5_1 \ + VMSLG m13_1, r_0, V0, T_6 \ + VMSLG m13_1, r_1, V0, T_7 \ + VMSLG m13_2, r5_1, V0, T_8 \ + VMSLG m13_2, r5_2, V0, T_9 \ + VMSLG m02_2, r_0, m4_2, m4_2 \ + VMSLG m13_2, r_0, m5_2, m5_2 \ + VAQ m4_0, T_0, m02_0 \ + VAQ m4_1, T_1, m02_1 \ + VAQ m5_0, T_5, m13_0 \ + VAQ m5_1, T_6, m13_1 \ + VAQ m02_0, T_3, m02_0 \ + VAQ m02_1, T_4, m02_1 \ + VAQ m13_0, T_8, m13_0 \ + VAQ m13_1, T_9, m13_1 \ + VAQ m4_2, T_2, m02_2 \ + VAQ m5_2, T_7, m13_2 \ + +// SQUARE uses three limbs of r and r_2*5 to output square of r +// uses T_1, T_5 and T_7 temporary registers +// input: r_0, r_1, r_2, r5_2 +// temp: TEMP0, TEMP1, TEMP2 +// output: p0, p1, p2 +#define SQUARE(r_0, r_1, r_2, r5_2, p0, p1, p2, TEMP0, TEMP1, TEMP2) \ + VMSLG r_0, r_0, p0, p0 \ + VMSLG r_1, r5_2, V0, TEMP0 \ + VMSLG r_2, r5_2, p1, p1 \ + VMSLG r_0, r_1, V0, TEMP1 \ + VMSLG r_1, r_1, p2, p2 \ + VMSLG r_0, r_2, V0, TEMP2 \ + VAQ TEMP0, p0, p0 \ + VAQ TEMP1, p1, p1 \ + VAQ TEMP2, p2, p2 \ + VAQ TEMP0, p0, p0 \ + VAQ TEMP1, p1, p1 \ + VAQ TEMP2, p2, p2 \ + +// carry h0->h1->h2->h0 || h3->h4->h5->h3 +// uses T_2, T_4, T_5, T_7, T_8, T_9 +// t6, t7, t8, t9, t10, t11 +// input: h0, h1, h2, h3, h4, h5 +// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 +// output: h0, h1, h2, h3, h4, h5 +#define REDUCE(h0, h1, h2, h3, h4, h5, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) \ + VLM (R12), t6, t7 \ // 44 and 42 bit clear mask + VLEIB $7, $0x28, t10 \ // 5 byte shift mask + VREPIB $4, t8 \ // 4 bit shift mask + VREPIB $2, t11 \ // 2 bit shift mask + VSRLB t10, h0, t0 \ // h0 byte shift + VSRLB t10, h1, t1 \ // h1 byte shift + VSRLB t10, h2, t2 \ // h2 byte shift + VSRLB t10, h3, t3 \ // h3 byte shift + VSRLB t10, h4, t4 \ // h4 byte shift + VSRLB t10, h5, t5 \ // h5 byte shift + VSRL t8, t0, t0 \ // h0 bit shift + VSRL t8, t1, t1 \ // h2 bit shift + VSRL t11, t2, t2 \ // h2 bit shift + VSRL t8, t3, t3 \ // h3 bit shift + VSRL t8, t4, t4 \ // h4 bit shift + VESLG $2, t2, t9 \ // h2 carry x5 + VSRL t11, t5, t5 \ // h5 bit shift + VN t6, h0, h0 \ // h0 clear carry + VAQ t2, t9, t2 \ // h2 carry x5 + VESLG $2, t5, t9 \ // h5 carry x5 + VN t6, h1, h1 \ // h1 clear carry + VN t7, h2, h2 \ // h2 clear carry + VAQ t5, t9, t5 \ // h5 carry x5 + VN t6, h3, h3 \ // h3 clear carry + VN t6, h4, h4 \ // h4 clear carry + VN t7, h5, h5 \ // h5 clear carry + VAQ t0, h1, h1 \ // h0->h1 + VAQ t3, h4, h4 \ // h3->h4 + VAQ t1, h2, h2 \ // h1->h2 + VAQ t4, h5, h5 \ // h4->h5 + VAQ t2, h0, h0 \ // h2->h0 + VAQ t5, h3, h3 \ // h5->h3 + VREPG $1, t6, t6 \ // 44 and 42 bit masks across both halves + VREPG $1, t7, t7 \ + VSLDB $8, h0, h0, h0 \ // set up [h0/1/2, h3/4/5] + VSLDB $8, h1, h1, h1 \ + VSLDB $8, h2, h2, h2 \ + VO h0, h3, h3 \ + VO h1, h4, h4 \ + VO h2, h5, h5 \ + VESRLG $44, h3, t0 \ // 44 bit shift right + VESRLG $44, h4, t1 \ + VESRLG $42, h5, t2 \ + VN t6, h3, h3 \ // clear carry bits + VN t6, h4, h4 \ + VN t7, h5, h5 \ + VESLG $2, t2, t9 \ // multiply carry by 5 + VAQ t9, t2, t2 \ + VAQ t0, h4, h4 \ + VAQ t1, h5, h5 \ + VAQ t2, h3, h3 \ + +// carry h0->h1->h2->h0 +// input: h0, h1, h2 +// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8 +// output: h0, h1, h2 +#define REDUCE2(h0, h1, h2, t0, t1, t2, t3, t4, t5, t6, t7, t8) \ + VLEIB $7, $0x28, t3 \ // 5 byte shift mask + VREPIB $4, t4 \ // 4 bit shift mask + VREPIB $2, t7 \ // 2 bit shift mask + VGBM $0x003F, t5 \ // mask to clear carry bits + VSRLB t3, h0, t0 \ + VSRLB t3, h1, t1 \ + VSRLB t3, h2, t2 \ + VESRLG $4, t5, t5 \ // 44 bit clear mask + VSRL t4, t0, t0 \ + VSRL t4, t1, t1 \ + VSRL t7, t2, t2 \ + VESRLG $2, t5, t6 \ // 42 bit clear mask + VESLG $2, t2, t8 \ + VAQ t8, t2, t2 \ + VN t5, h0, h0 \ + VN t5, h1, h1 \ + VN t6, h2, h2 \ + VAQ t0, h1, h1 \ + VAQ t1, h2, h2 \ + VAQ t2, h0, h0 \ + VSRLB t3, h0, t0 \ + VSRLB t3, h1, t1 \ + VSRLB t3, h2, t2 \ + VSRL t4, t0, t0 \ + VSRL t4, t1, t1 \ + VSRL t7, t2, t2 \ + VN t5, h0, h0 \ + VN t5, h1, h1 \ + VESLG $2, t2, t8 \ + VN t6, h2, h2 \ + VAQ t0, h1, h1 \ + VAQ t8, t2, t2 \ + VAQ t1, h2, h2 \ + VAQ t2, h0, h0 \ + +// expands two message blocks into the lower halfs of the d registers +// moves the contents of the d registers into upper halfs +// input: in1, in2, d0, d1, d2, d3, d4, d5 +// temp: TEMP0, TEMP1, TEMP2, TEMP3 +// output: d0, d1, d2, d3, d4, d5 +#define EXPACC(in1, in2, d0, d1, d2, d3, d4, d5, TEMP0, TEMP1, TEMP2, TEMP3) \ + VGBM $0xff3f, TEMP0 \ + VGBM $0xff1f, TEMP1 \ + VESLG $4, d1, TEMP2 \ + VESLG $4, d4, TEMP3 \ + VESRLG $4, TEMP0, TEMP0 \ + VPERM in1, d0, EX0, d0 \ + VPERM in2, d3, EX0, d3 \ + VPERM in1, d2, EX2, d2 \ + VPERM in2, d5, EX2, d5 \ + VPERM in1, TEMP2, EX1, d1 \ + VPERM in2, TEMP3, EX1, d4 \ + VN TEMP0, d0, d0 \ + VN TEMP0, d3, d3 \ + VESRLG $4, d1, d1 \ + VESRLG $4, d4, d4 \ + VN TEMP1, d2, d2 \ + VN TEMP1, d5, d5 \ + VN TEMP0, d1, d1 \ + VN TEMP0, d4, d4 \ + +// expands one message block into the lower halfs of the d registers +// moves the contents of the d registers into upper halfs +// input: in, d0, d1, d2 +// temp: TEMP0, TEMP1, TEMP2 +// output: d0, d1, d2 +#define EXPACC2(in, d0, d1, d2, TEMP0, TEMP1, TEMP2) \ + VGBM $0xff3f, TEMP0 \ + VESLG $4, d1, TEMP2 \ + VGBM $0xff1f, TEMP1 \ + VPERM in, d0, EX0, d0 \ + VESRLG $4, TEMP0, TEMP0 \ + VPERM in, d2, EX2, d2 \ + VPERM in, TEMP2, EX1, d1 \ + VN TEMP0, d0, d0 \ + VN TEMP1, d2, d2 \ + VESRLG $4, d1, d1 \ + VN TEMP0, d1, d1 \ + +// pack h2:h0 into h1:h0 (no carry) +// input: h0, h1, h2 +// output: h0, h1, h2 +#define PACK(h0, h1, h2) \ + VMRLG h1, h2, h2 \ // copy h1 to upper half h2 + VESLG $44, h1, h1 \ // shift limb 1 44 bits, leaving 20 + VO h0, h1, h0 \ // combine h0 with 20 bits from limb 1 + VESRLG $20, h2, h1 \ // put top 24 bits of limb 1 into h1 + VLEIG $1, $0, h1 \ // clear h2 stuff from lower half of h1 + VO h0, h1, h0 \ // h0 now has 88 bits (limb 0 and 1) + VLEIG $0, $0, h2 \ // clear upper half of h2 + VESRLG $40, h2, h1 \ // h1 now has upper two bits of result + VLEIB $7, $88, h1 \ // for byte shift (11 bytes) + VSLB h1, h2, h2 \ // shift h2 11 bytes to the left + VO h0, h2, h0 \ // combine h0 with 20 bits from limb 1 + VLEIG $0, $0, h1 \ // clear upper half of h1 + +// if h > 2**130-5 then h -= 2**130-5 +// input: h0, h1 +// temp: t0, t1, t2 +// output: h0 +#define MOD(h0, h1, t0, t1, t2) \ + VZERO t0 \ + VLEIG $1, $5, t0 \ + VACCQ h0, t0, t1 \ + VAQ h0, t0, t0 \ + VONE t2 \ + VLEIG $1, $-4, t2 \ + VAQ t2, t1, t1 \ + VACCQ h1, t1, t1 \ + VONE t2 \ + VAQ t2, t1, t1 \ + VN h0, t1, t2 \ + VNC t0, t1, t1 \ + VO t1, t2, h0 \ + +// func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]key) +TEXT ·poly1305vmsl(SB), $0-32 + // This code processes 6 + up to 4 blocks (32 bytes) per iteration + // using the algorithm described in: + // NEON crypto, Daniel J. Bernstein & Peter Schwabe + // https://cryptojedi.org/papers/neoncrypto-20120320.pdf + // And as moddified for VMSL as described in + // Accelerating Poly1305 Cryptographic Message Authentication on the z14 + // O'Farrell et al, CASCON 2017, p48-55 + // https://ibm.ent.box.com/s/jf9gedj0e9d2vjctfyh186shaztavnht + + LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key + VZERO V0 // c + + // load EX0, EX1 and EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 // c + + // setup r + VL (R4), T_0 + MOVD $·keyMask<>(SB), R6 + VL (R6), T_1 + VN T_0, T_1, T_0 + VZERO T_2 // limbs for r + VZERO T_3 + VZERO T_4 + EXPACC2(T_0, T_2, T_3, T_4, T_1, T_5, T_7) + + // T_2, T_3, T_4: [0, r] + + // setup r*20 + VLEIG $0, $0, T_0 + VLEIG $1, $20, T_0 // T_0: [0, 20] + VZERO T_5 + VZERO T_6 + VMSLG T_0, T_3, T_5, T_5 + VMSLG T_0, T_4, T_6, T_6 + + // store r for final block in GR + VLGVG $1, T_2, RSAVE_0 // c + VLGVG $1, T_3, RSAVE_1 // c + VLGVG $1, T_4, RSAVE_2 // c + VLGVG $1, T_5, R5SAVE_1 // c + VLGVG $1, T_6, R5SAVE_2 // c + + // initialize h + VZERO H0_0 + VZERO H1_0 + VZERO H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + // initialize pointer for reduce constants + MOVD $·reduce<>(SB), R12 + + // calculate r**2 and 20*(r**2) + VZERO R_0 + VZERO R_1 + VZERO R_2 + SQUARE(T_2, T_3, T_4, T_6, R_0, R_1, R_2, T_1, T_5, T_7) + REDUCE2(R_0, R_1, R_2, M0, M1, M2, M3, M4, R5_1, R5_2, M5, T_1) + VZERO R5_1 + VZERO R5_2 + VMSLG T_0, R_1, R5_1, R5_1 + VMSLG T_0, R_2, R5_2, R5_2 + + // skip r**4 calculation if 3 blocks or less + CMPBLE R3, $48, b4 + + // calculate r**4 and 20*(r**4) + VZERO T_8 + VZERO T_9 + VZERO T_10 + SQUARE(R_0, R_1, R_2, R5_2, T_8, T_9, T_10, T_1, T_5, T_7) + REDUCE2(T_8, T_9, T_10, M0, M1, M2, M3, M4, T_2, T_3, M5, T_1) + VZERO T_2 + VZERO T_3 + VMSLG T_0, T_9, T_2, T_2 + VMSLG T_0, T_10, T_3, T_3 + + // put r**2 to the right and r**4 to the left of R_0, R_1, R_2 + VSLDB $8, T_8, T_8, T_8 + VSLDB $8, T_9, T_9, T_9 + VSLDB $8, T_10, T_10, T_10 + VSLDB $8, T_2, T_2, T_2 + VSLDB $8, T_3, T_3, T_3 + + VO T_8, R_0, R_0 + VO T_9, R_1, R_1 + VO T_10, R_2, R_2 + VO T_2, R5_1, R5_1 + VO T_3, R5_2, R5_2 + + CMPBLE R3, $80, load // less than or equal to 5 blocks in message + + // 6(or 5+1) blocks + SUB $81, R3 + VLM (R2), M0, M4 + VLL R3, 80(R2), M5 + ADD $1, R3 + MOVBZ $1, R0 + CMPBGE R3, $16, 2(PC) + VLVGB R3, R0, M5 + MOVD $96(R2), R2 + EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) + EXPACC(M2, M3, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) + VLEIB $2, $1, H2_0 + VLEIB $2, $1, H2_1 + VLEIB $10, $1, H2_0 + VLEIB $10, $1, H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO T_4 + VZERO T_10 + EXPACC(M4, M5, M0, M1, M2, M3, T_4, T_10, T_0, T_1, T_2, T_3) + VLR T_4, M4 + VLEIB $10, $1, M2 + CMPBLT R3, $16, 2(PC) + VLEIB $10, $1, T_10 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + + SUB $16, R3 + CMPBLE R3, $0, square + +load: + // load EX0, EX1 and EX2 + MOVD $·c<>(SB), R5 + VLM (R5), EX0, EX2 + +loop: + CMPBLE R3, $64, add // b4 // last 4 or less blocks left + + // next 4 full blocks + VLM (R2), M2, M5 + SUB $64, R3 + MOVD $64(R2), R2 + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, T_0, T_1, T_3, T_4, T_5, T_2, T_7, T_8, T_9) + + // expacc in-lined to create [m2, m3] limbs + VGBM $0x3f3f, T_0 // 44 bit clear mask + VGBM $0x1f1f, T_1 // 40 bit clear mask + VPERM M2, M3, EX0, T_3 + VESRLG $4, T_0, T_0 // 44 bit clear mask ready + VPERM M2, M3, EX1, T_4 + VPERM M2, M3, EX2, T_5 + VN T_0, T_3, T_3 + VESRLG $4, T_4, T_4 + VN T_1, T_5, T_5 + VN T_0, T_4, T_4 + VMRHG H0_1, T_3, H0_0 + VMRHG H1_1, T_4, H1_0 + VMRHG H2_1, T_5, H2_0 + VMRLG H0_1, T_3, H0_1 + VMRLG H1_1, T_4, H1_1 + VMRLG H2_1, T_5, H2_1 + VLEIB $10, $1, H2_0 + VLEIB $10, $1, H2_1 + VPERM M4, M5, EX0, T_3 + VPERM M4, M5, EX1, T_4 + VPERM M4, M5, EX2, T_5 + VN T_0, T_3, T_3 + VESRLG $4, T_4, T_4 + VN T_1, T_5, T_5 + VN T_0, T_4, T_4 + VMRHG V0, T_3, M0 + VMRHG V0, T_4, M1 + VMRHG V0, T_5, M2 + VMRLG V0, T_3, M3 + VMRLG V0, T_4, M4 + VMRLG V0, T_5, M5 + VLEIB $10, $1, M2 + VLEIB $10, $1, M5 + + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + CMPBNE R3, $0, loop + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + + // load EX0, EX1, EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 + + // sum vectors + VAQ H0_0, H0_1, H0_0 + VAQ H1_0, H1_1, H1_0 + VAQ H2_0, H2_1, H2_0 + + // h may be >= 2*(2**130-5) so we need to reduce it again + // M0...M4 are used as temps here + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + +next: // carry h1->h2 + VLEIB $7, $0x28, T_1 + VREPIB $4, T_2 + VGBM $0x003F, T_3 + VESRLG $4, T_3 + + // byte shift + VSRLB T_1, H1_0, T_4 + + // bit shift + VSRL T_2, T_4, T_4 + + // clear h1 carry bits + VN T_3, H1_0, H1_0 + + // add carry + VAQ T_4, H2_0, H2_0 + + // h is now < 2*(2**130-5) + // pack h into h1 (hi) and h0 (lo) + PACK(H0_0, H1_0, H2_0) + + // if h > 2**130-5 then h -= 2**130-5 + MOD(H0_0, H1_0, T_0, T_1, T_2) + + // h += s + MOVD $·bswapMask<>(SB), R5 + VL (R5), T_1 + VL 16(R4), T_0 + VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big) + VAQ T_0, H0_0, H0_0 + VPERM H0_0, H0_0, T_1, H0_0 // reverse bytes (to little) + VST H0_0, (R1) + RET + +add: + // load EX0, EX1, EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 + + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + CMPBLE R3, $64, b4 + +b4: + CMPBLE R3, $48, b3 // 3 blocks or less + + // 4(3+1) blocks remaining + SUB $49, R3 + VLM (R2), M0, M2 + VLL R3, 48(R2), M3 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M3 + MOVD $64(R2), R2 + EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) + VLEIB $10, $1, H2_0 + VLEIB $10, $1, H2_1 + VZERO M0 + VZERO M1 + VZERO M4 + VZERO M5 + VZERO T_4 + VZERO T_10 + EXPACC(M2, M3, M0, M1, M4, M5, T_4, T_10, T_0, T_1, T_2, T_3) + VLR T_4, M2 + VLEIB $10, $1, M4 + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, T_10 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M4, M5, M2, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + SUB $16, R3 + CMPBLE R3, $0, square // this condition must always hold true! + +b3: + CMPBLE R3, $32, b2 + + // 3 blocks remaining + + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // H*[r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, T_10, M5) + + SUB $33, R3 + VLM (R2), M0, M1 + VLL R3, 32(R2), M2 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M2 + + // H += m0 + VZERO T_1 + VZERO T_2 + VZERO T_3 + EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6) + VLEIB $10, $1, T_3 + VAG H0_0, T_1, H0_0 + VAG H1_0, T_2, H1_0 + VAG H2_0, T_3, H2_0 + + VZERO M0 + VZERO M3 + VZERO M4 + VZERO M5 + VZERO T_10 + + // (H+m0)*r + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M3, M4, M5, V0, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_10, H0_1, H1_1, H2_1, T_9) + + // H += m1 + VZERO V0 + VZERO T_1 + VZERO T_2 + VZERO T_3 + EXPACC2(M1, T_1, T_2, T_3, T_4, T_5, T_6) + VLEIB $10, $1, T_3 + VAQ H0_0, T_1, H0_0 + VAQ H1_0, T_2, H1_0 + VAQ H2_0, T_3, H2_0 + REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10) + + // [H, m2] * [r**2, r] + EXPACC2(M2, H0_0, H1_0, H2_0, T_1, T_2, T_3) + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, H2_0 + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, M5, T_10) + SUB $16, R3 + CMPBLE R3, $0, next // this condition must always hold true! + +b2: + CMPBLE R3, $16, b1 + + // 2 blocks remaining + + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // H*[r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + + // move h to the left and 0s at the right + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + + // get message blocks and append 1 to start + SUB $17, R3 + VL (R2), M0 + VLL R3, 16(R2), M1 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M1 + VZERO T_6 + VZERO T_7 + VZERO T_8 + EXPACC2(M0, T_6, T_7, T_8, T_1, T_2, T_3) + EXPACC2(M1, T_6, T_7, T_8, T_1, T_2, T_3) + VLEIB $2, $1, T_8 + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, T_8 + + // add [m0, m1] to h + VAG H0_0, T_6, H0_0 + VAG H1_0, T_7, H1_0 + VAG H2_0, T_8, H2_0 + + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + VZERO T_10 + VZERO M0 + + // at this point R_0 .. R5_2 look like [r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M2, M3, M4, M5, T_10, M0, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M2, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10) + SUB $16, R3, R3 + CMPBLE R3, $0, next + +b1: + CMPBLE R3, $0, next + + // 1 block remaining + + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // H*[r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + + // set up [0, m0] limbs + SUB $1, R3 + VLL R3, (R2), M0 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M0 + VZERO T_1 + VZERO T_2 + VZERO T_3 + EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)// limbs: [0, m] + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, T_3 + + // h+m0 + VAQ H0_0, T_1, H0_0 + VAQ H1_0, T_2, H1_0 + VAQ H2_0, T_3, H2_0 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + + BR next + +square: + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // (h0*r**2) + (h1*r) + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + BR next + +TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1 + MOVD $x-24(SP), R1 + XC $24, 0(R1), 0(R1) // clear the storage + MOVD $2, R0 // R0 is the number of double words stored -1 + WORD $0xB2B01000 // STFLE 0(R1) + XOR R0, R0 // reset the value of R0 + MOVBZ z-8(SP), R1 + AND $0x01, R1 + BEQ novmsl + +vectorinstalled: + // check if the vector instruction has been enabled + VLEIB $0, $0xF, V16 + VLGVB $0, V16, R1 + CMPBNE R1, $0xF, novmsl + MOVB $1, ret+0(FP) // have vx + RET + +novmsl: + MOVB $0, ret+0(FP) // no vx + RET diff --git a/vendor/golang.org/x/crypto/poly1305/vectors_test.go b/vendor/golang.org/x/crypto/poly1305/vectors_test.go new file mode 100644 index 00000000..18d7ff8e --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/vectors_test.go @@ -0,0 +1,2943 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poly1305 + +var testData = [...]test{ + // edge cases + { + // see https://go-review.googlesource.com/#/c/30101/ + key: "3b3a29e93b213a5c5c3b3b053a3a8c0d00000000000000000000000000000000", + tag: "6dc18b8c344cd79927118bbe84b7f314", + in: "81d8b2e46a25213b58fee4213a2a28e921c12a9632516d3b73272727becf2129", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "04000000000000000000000000000000", // (2¹³⁰-1) % (2¹³⁰-5) + in: "ffffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "faffffffffffffffffffffffffffffff", // (2¹³⁰-6) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (2¹³⁰-5) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f9ffffffffffffffffffffffffffffff", // (2*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (2*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f8ffffffffffffffffffffffffffffff", // (3*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (3*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f7ffffffffffffffffffffffffffffff", // (4*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (4*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f3ffffffffffffffffffffffffffffff", // (8*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (8*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "ebffffffffffffffffffffffffffffff", // (16*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (16*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + // original smoke tests + { + key: "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + tag: "a6f745008f81c916a20dcc74eef2b2f0", + in: "48656c6c6f20776f726c6421", + }, + { + key: "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + tag: "49ec78090e481ec6c26b33b91ccc0307", + in: "0000000000000000000000000000000000000000000000000000000000000000", + }, + { + key: "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + tag: "da84bcab02676c38cdb015604274c2aa", + in: "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000", + }, + { + key: "0000000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", + in: "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000", + }, + // randomly generated + { + key: "52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649", + tag: "9566c74d10037c4d7bbb0407d1e2c649", + in: "", + }, + { + key: "81855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999", + tag: "eaa270caaa12faa39b797374a4b8a420", + in: "eb", + }, + { + key: "9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f15f", + tag: "dbea66e1da48a8f822887c6162c2acf1", + in: "b90b", + }, + { + key: "adb37c5821b6d95526a41a9504680b4e7c8b763a1b1d49d4955c848621632525", + tag: "6ac09aaa88c32ee95a7198376f16abdb", + in: "3fec73", + }, + { + key: "8dd7a9e28bf921119c160f0702448615bbda08313f6a8eb668d20bf505987592", + tag: "b1443487f97fe340b04a74719ed4de68", + in: "1e668a5b", + }, + { + key: "df2c7fc4844592d2572bcd0668d2d6c52f5054e2d0836bf84c7174cb7476364c", + tag: "7463be0f9d99a5348039e4afcbf4019c", + in: "c3dbd968b0", + }, + { + key: "f7172ed85794bb358b0c3b525da1786f9fff094279db1944ebd7a19d0f7bbacb", + tag: "2edaee3bcf303fd05609e131716f8157", + in: "e0255aa5b7d4", + }, + { + key: "4bec40f84c892b9bffd43629b0223beea5f4f74391f445d15afd4294040374f6", + tag: "965f18767420c1d94a4ef657e8d15e1e", + in: "924b98cbf8713f", + }, + { + key: "8d962d7c8d019192c24224e2cafccae3a61fb586b14323a6bc8f9e7df1d92933", + tag: "2bf4a33287dd6d87e1ed4282f7342b6a", + in: "3ff993933bea6f5b", + }, + { + key: "3af6de0374366c4719e43a1b067d89bc7f01f1f573981659a44ff17a4c7215a3", + tag: "c5e987b60373a48893c5af30acf2471f", + in: "b539eb1e5849c6077d", + }, + { + key: "bb5722f5717a289a266f97647981998ebea89c0b4b373970115e82ed6f4125c8", + tag: "19f0f640b309d168ea1b480e6a4faee5", + in: "fa7311e4d7defa922daa", + }, + { + key: "e7786667f7e936cd4f24abf7df866baa56038367ad6145de1ee8f4a8b0993ebd", + tag: "de75e5565d97834b9fa84ad568d31359", + in: "f8883a0ad8be9c3978b048", + }, + { + key: "83e56a156a8de563afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e", + tag: "de184a5a9b826aa203c5c017986d6690", + in: "4da6430105220d0b29688b73", + }, + { + key: "4b8ea0f3ca9936e8461f10d77c96ea80a7a665f606f6a63b7f3dfd2567c18979", + tag: "7478f18d9684905aa5d1a34ee67e4c84", + in: "e4d60f26686d9bf2fb26c901ff", + }, + { + key: "354cde1607ee294b39f32b7c7822ba64f84ab43ca0c6e6b91c1fd3be89904341", + tag: "3b2008a9c52b5308f5538b789ab5506f", + in: "79d3af4491a369012db92d184fc3", + }, + { + key: "9d1734ff5716428953bb6865fcf92b0c3a17c9028be9914eb7649c6c93478009", + tag: "71c8e76a67a505b7370b562ba15ba032", + in: "79d1830356f2a54c3deab2a4b4475d", + }, + { + key: "63afbe8fb56987c77f5818526f1814be823350eab13935f31d84484517e924ae", + tag: "1dc895f74f866bdb3edf6c4430829c1c", + in: "f78ae151c00755925836b7075885650c", + }, + { + key: "30ec29a3703934bf50a28da102975deda77e758579ea3dfe4136abf752b3b827", + tag: "afca2b3ba7b0e1a928001966883e9b16", + in: "1d03e944b3c9db366b75045f8efd69d22ae5411947cb553d7694267aef4e" + + "bcea406b32d6108bd68584f57e37caac6e33feaa3263a399437024ba9c9b" + + "14678a274f01a910ae295f6efbfe5f5abf44ccde263b5606633e2bf0006f" + + "28295d7d39069f01a239c4365854c3af7f6b41d631f92b9a8d12f4125732" + + "5fff332f7576b0620556304a3e3eae14c28d0cea39d2901a52720da85ca1" + + "e4b38eaf3f", + }, + { + key: "44c6c6ef8362f2f54fc00e09d6fc25640854c15dfcacaa8a2cecce5a3aba53ab", + tag: "6f2a09aa76c9b76774e31ec02dcf7991", + in: "705b18db94b4d338a5143e63408d8724b0cf3fae17a3f79be1072fb63c35" + + "d6042c4160f38ee9e2a9f3fb4ffb0019b454d522b5ffa17604193fb89667" + + "10a7960732ca52cf53c3f520c889b79bf504cfb57c7601232d589baccea9" + + "d6e263e25c27741d3f6c62cbbb15d9afbcbf7f7da41ab0408e3969c2e2cd" + + "cf233438bf1774ace7709a4f091e9a83fdeae0ec55eb233a9b5394cb3c78" + + "56b546d313c8a3b4c1c0e05447f4ba370eb36dbcfdec90b302dcdc3b9ef5" + + "22e2a6f1ed0afec1f8e20faabedf6b162e717d3a748a58677a0c56348f89" + + "21a266b11d0f334c62fe52ba53af19779cb2948b6570ffa0b773963c130a" + + "d797ddea", + }, + { + key: "fe4e3ad29b5125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd", + tag: "27381e3fc2a356103fb796f107d826e7", + in: "58b00ce73bff706f7ff4b6f44090a32711f3208e4e4b89cb5165ce64002c" + + "bd9c2887aa113df2468928d5a23b9ca740f80c9382d9c6034ad2960c7965" + + "03e1ce221725f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e1386" + + "47a4b44ed4bce964ed47f74aa594468ced323cb76f0d3fac476c9fb03fc9" + + "228fbae88fd580663a0454b68312207f0a3b584c62316492b49753b5d502" + + "7ce15a4f0a58250d8fb50e77f2bf4f0152e5d49435807f9d4b97be6fb779" + + "70466a5626fe33408cf9e88e2c797408a32d29416baf206a329cfffd4a75" + + "e498320982c85aad70384859c05a4b13a1d5b2f5bfef5a6ed92da482caa9" + + "568e5b6fe9d8a9ddd9eb09277b92cef9046efa18500944cbe800a0b1527e" + + "a6", + }, + { + key: "4729a861d2f6497a3235c37f4192779ec1d96b3b1c5424fce0b727b03072e641", + tag: "0173965669fb9de88d38a827a0271271", + in: "5a761f03abaa40abc9448fddeb2191d945c04767af847afd0edb5d8857b7" + + "99acb18e4affabe3037ffe7fa68aa8af5e39cc416e734d373c5ebebc9cdc" + + "c595bcce3c7bd3d8df93fab7e125ddebafe65a31bd5d41e2d2ce9c2b1789" + + "2f0fea1931a290220777a93143dfdcbfa68406e877073ff08834e197a403" + + "4aa48afa3f85b8a62708caebbac880b5b89b93da53810164402104e648b6" + + "226a1b78021851f5d9ac0f313a89ddfc454c5f8f72ac89b38b19f53784c1" + + "9e9beac03c875a27db029de37ae37a42318813487685929359ca8c5eb94e" + + "152dc1af42ea3d1676c1bdd19ab8e2925c6daee4de5ef9f9dcf08dfcbd02" + + "b80809398585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c9" + + "18bba3e933e5c400cde5e60c5ead6fc7ae77ba1d259b188a4b21c86fbc23" + + "d728b45347eada650af24c56d0800a8691332088a805bd55c446e25eb075" + + "90bafcccbec6177536401d9a2b7f512b54bfc9d00532adf5aaa7c3a96bc5" + + "9b489f77d9042c5bce26b163defde5ee6a0fbb3e9346cef81f0ae9515ef3" + + "0fa47a364e75aea9e111d596e685a591121966e031650d510354aa845580" + + "ff560760fd36514ca197c875f1d02d9216eba7627e2398322eb5cf43d72b" + + "d2e5b887d4630fb8d4747ead6eb82acd1c5b078143ee26a586ad23139d50" + + "41723470bf24a865837c", + }, + { + key: "9123461c41f5ff99aa99ce24eb4d788576e3336e65491622558fdf297b9fa007", + tag: "1eb0cdad9237905250d30a24fe172a34", + in: "864bafd7cd4ca1b2fb5766ab431a032b72b9a7e937ed648d0801f29055d3" + + "090d2463718254f9442483c7b98b938045da519843854b0ed3f7ba951a49" + + "3f321f0966603022c1dfc579b99ed9d20d573ad53171c8fef7f1f4e4613b" + + "b365b2ebb44f0ffb6907136385cdc838f0bdd4c812f042577410aca008c2" + + "afbc4c79c62572e20f8ed94ee62b4de7aa1cc84c887e1f7c31e927dfe52a" + + "5f8f46627eb5d3a4fe16fafce23623e196c9dfff7fbaff4ffe94f4589733" + + "e563e19d3045aad3e226488ac02cca4291aed169dce5039d6ab00e40f67a" + + "ab29332de1448b35507c7c8a09c4db07105dc31003620405da3b2169f5a9" + + "10c9d0096e5e3ef1b570680746acd0cc7760331b663138d6d342b051b5df" + + "410637cf7aee9b0c8c10a8f9980630f34ce001c0ab7ac65e502d39b216cb" + + "c50e73a32eaf936401e2506bd8b82c30d346bc4b2fa319f245a8657ec122" + + "eaf4ad5425c249ee160e17b95541c2aee5df820ac85de3f8e784870fd87a" + + "36cc0d163833df636613a9cc947437b6592835b9f6f4f8c0e70dbeebae7b" + + "14cdb9bc41033aa5baf40d45e24d72eac4a28e3ca030c9937ab8409a7cbf" + + "05ae21f97425254543d94d115900b90ae703b97d9856d2441d14ba49a677" + + "de8b18cb454b99ddd9daa7ccbb7500dae4e2e5df8cf3859ebddada6745fb" + + "a6a04c5c37c7ca35036f11732ce8bc27b48868611fc73c82a491bfabd7a1" + + "9df50fdc78a55dbbc2fd37f9296566557fab885b039f30e706f0cd5961e1" + + "9b642221db44a69497b8ad99408fe1e037c68bf7c5e5de1d2c68192348ec" + + "1189fb2e36973cef09ff14be23922801f6eaee41409158b45f2dec82d17c" + + "aaba160cd6", + }, + { + key: "40ff73495fe4a05ce1202ca7287ed3235b95e69f571fa5e656aaa51fae1ebdd7", + tag: "2e619d8ea81b77484e4fddeb29844e4b", + in: "aa6269c2ec7f4057b33593bc84888c970fd528d4a99a1eab9d2420134537" + + "cd6d02282e0981e140232a4a87383a21d1845c408ad757043813032a0bd5" + + "a30dcca6e3aa2df04715d879279a96879a4f3690ac2025a60c7db15e0501" + + "ebc34b734355fe4a059bd3899d920e95f1c46d432f9b08e64d7f9b38965d" + + "5a77a7ac183c3833e1a3425ead69d4f975012fd1a49ed832f69e6e9c63b4" + + "53ec049c9e7a5cf944232d10353f64434abae060f6506ad3fdb1f4415b0a" + + "f9ce8c208bc20ee526741539fa3203c77ecba410fd6718f227e0b430f9bc" + + "b049a3d38540dc222969120ce80f2007cd42a708a721aa29987b45d4e428" + + "811984ecad349cc35dd93515cefe0b002cee5e71c47935e281ebfc4b8b65" + + "2b69ccb092e55a20f1b9f97d046296124621928739a86671cc180152b953" + + "e3bf9d19f825c3dd54ae1688e49efb5efe65dcdad34bc860010e7c8c997c" + + "d5f9e320ca7d39d4ba801a175b1c76f057832f3f36d7d893e216e4c7bbdb" + + "548d0ba48449330027368b34f9c69776b4591532da1c5be68ef4eebe8cb8" + + "fa7dc5483fb70c2c896334cb1f9cb5dfe044fa086197ff5dfd02f2ba3884" + + "c53dd718c8560da743a8e9d4aeae20ccef002d82ca352592b8d8f2a8df3b" + + "0c35f15b9b370dca80d4ca8e9a133eb52094f2dd5c08731f52315d828846" + + "e37df68fd10658b480f2ac84233633957e688e924ffe3713b52c76fd8a56" + + "da8bb07daa8eb4eb8f7334f99256e2766a4109150eed424f0f743543cdea" + + "66e5baaa03edc918e8305bb19fc0c6b4ddb4aa3886cb5090940fc6d4cabe" + + "2153809e4ed60a0e2af07f1b2a6bb5a6017a578a27cbdc20a1759f76b088" + + "9a83ce25ce3ca91a4eb5c2f8580819da04d02c41770c01746de44f3db6e3" + + "402e7873db7635516e87b33e4b412ba3df68544920f5ea27ec097710954f" + + "42158bdba66d4814c064b4112538676095467c89ba98e6a543758d7093a4" + + "94df", + }, + { + key: "5cc36d09c7a6472a41f29c380a987b1ecdcf84765f4e5d3ceefc1c02181f570f", + tag: "0d57b8cbea8090df0541354673dcb4e0", + in: "44fcd629f08dc1ef53c9ae0d8869fe67fdc7a2c67b425f13c5be8d9f630c" + + "1d063c02fd75cf64c1aec9d2e2ef6e6431d5f5ad0489078dc61f46494dcc" + + "f403dad7f094170d2c3e29c198b0f341e284c4be8fa60c1a478d6bd55dd2" + + "c04dad86d2053d5d25b014e3d8b64322cdcb5004faa46cfa2d6ad2ff933b" + + "c3bd9a5a74660af3d048a9a43634c0250427d9a6219197a3f3633f841753" + + "ba7c27f3619f387b6b1a6cb9c1dc227674aa020724d137da2cb87b1615d5" + + "12974fa4747dd1e17d02c9462a44fec150ca3a8f99cc1e4953365e429956" + + "5e108535b1f62e1d4ba18e17a52164418bfd1a933f7fb3a126c860830a87" + + "293d9271da736e4398c1e37fb75c4bf02786e1faf4b610cd1377fbb9ae18" + + "0655a0abefbad700c09473469f1eca5a66d53fa3dc7cd3e7c3b0411d7e14" + + "5f96eb9654ab94913dda503a50f9e773842f4d2a5faa60869bf365830511" + + "f2ededd03e0a73000edb60c9a29a5f5e194cf3b5667a694690384599d116" + + "f8d2fd93b2aed55b7d44b5b054f3f38e788e4fdf36e591568c41d1052cad" + + "0fcb68ca4c4bf5090d57df9db6f0d91dd8b11b804f331adb7efb087a5604" + + "e9e22b4d54db40bcbc6e272ff5eaddfc1471459e59f0554c58251342134a" + + "8daaef1498069ba581ef1da2510be92843487a4eb8111c79a6f0195fc38a" + + "d6aee93c1df2b5897eaa38ad8f47ab2fe0e3aa3e6accbfd4c16d46843318" + + "5fc61c861b96ca65e34d31f24d6f56ee85092314a4d7656205c15322f1c9" + + "7613c079eae292ba966e10d1e700164e518b243f424c46f9ea63db1c2c34" + + "b512c403c128ee19030a6226517b805a072512a5e4cd274b7fd1fa23f830" + + "058208ff1a063b41039c74036b5b3da8b1a0b93135a710352da0f6c31203" + + "a09d1f2329651bb3ab3984ab591f2247e71cd44835e7a1a1b66d8595f7ae" + + "f9bf39d1417d2d31ea3599d405ff4b5999a86f52f3259b452909b57937d8" + + "5364d6c23deb4f14e0d9fcee9184df5994fdc11f045c025c8d561adb0e7d" + + "fd4748fd4b20f84e53322471a410cdb3fd88e48b2e7eb7ae5dae994cb5ea" + + "e3eaf21cf9005db560d6d22e4d9b97d7e9e488751afcd72aa176c0fcde93" + + "16f676fd527d9c42105b851639f09ea70533d26fc60cbeb4b76ed554fc99" + + "177620b28ca6f56a716f8cb384", + }, + { + key: "811c3e356e7c793acf114c624dc86ace38e67bff2a60e5b2a6c20723c1b9f003", + tag: "c6e59044cefc43ee681c3eed872d02b3", + in: "e115b304c023792448794546a2474f04294d7a616215e5dd6c40a65bb6ed" + + "b508c3680b14c176c327fdfb1ee21962c0006b7deb4e5de87db21989d13c" + + "3ab0462d5d2a52ef4ca0d366ae06a314f50e3a21d9247f814037798cc5e1" + + "0a63de027477decdeb8a8e0c279299272490106ddf8683126f60d35772c6" + + "dfc744b0adbfd5dcf118c4f2b06cfaf077881d733a5e643b7c46976647d1" + + "c1d3f8f6237c6218fa86fb47080b1f7966137667bd6661660c43b75b6339" + + "0b514bbe491aa46b524bde1c5b7456255fb214c3f74907b7ce1cba94210b" + + "78b5e68f049fcb002b96a5d38d59df6e977d587abb42d0972d5f3ffc898b" + + "3cbec26f104255761aee1b8a232d703585dd276ee1f43c8cd7e92a993eb1" + + "5107d02f59ba75f8dd1442ee37786ddb902deb88dd0ebdbf229fb25a9dca" + + "86d0ce46a278a45f5517bff2c049cc959a227dcdd3aca677e96ce84390e9" + + "b9a28e0988777331847a59f1225b027a66c1421422683dd6081af95e16f2" + + "48ab03da494112449ce7bdace6c988292f95699bb5e4d9c8d250aa28a6df" + + "44c0c265156deb27e9476a0a4af44f34bdf631b4af1146afe34ea988fc95" + + "3e71fc21ce60b3962313000fe46d757109281f6e55bc950200d0834ceb5c" + + "41553afd12576f3fbb9a8e05883ccc51c9a1269b6d8e9d27123dce5d0bd6" + + "db649c6fea06b4e4e9dea8d2d17709dc50ae8aa38231fd409e9580e255fe" + + "2bf59e6e1b6e310610ea4881206262be76120d6c97db969e003947f08bad" + + "8fa731f149397c47d2c964e84f090e77e19046277e18cd8917c48a776c9d" + + "e627b6656203b522c60e97cc61914621c564243913ae643f1c9c9e0ad00a" + + "14f66eaa45844229ecc35abb2637317ae5d5e338c68691bea8fa1fd469b7" + + "b54d0fccd730c1284ec7e6fccdec800b8fa67e6e55ac574f1e53a65ab976" + + "4c218a404184793cc9892308e296b334c85f7097edc16927c2451c4cd7e5" + + "3f239aa4f4c83241bde178f692898b1ece2dbcb19a97e64c4710326528f2" + + "4b099d0b674bd614fad307d9b9440adab32117f0f15b1450277b00eb366e" + + "0260fca84c1d27e50a1116d2ce16c8f5eb212c77c1a84425744ea3195edb" + + "b54c970b77e090b644942d43fe8c4546a158bad7620217a40e34b9bb84d1" + + "89eff32b20ef3f015714dbb1f150015d6eeb84cbccbd3fffa63bde89", + }, + { + key: "f33691f5db2dea41e1e608af3ff39f3a6988dba204ce1b09214475ae0ea864b8", + tag: "6e50e70411201378c8d67857d7b631d2", + in: "439bc9ea10db4d2b08c7fcf2e8bd89fa9844f8061d462e28f174489e7514" + + "0f84e842040141cc59ce38f9551850cfbdfac2d75337d155090d70d0d930" + + "04340bdfe60062f17c53f3c9005b9995a0feb49f6bef8eaff80f4feb7ef3" + + "f2181733a4b43b6ac43a5130a73a9b3c2cbc93bd296cd5f48c9df022b6c8" + + "2bb752bc21e3d8379be31328aa32edc11efc8a4b4b3f370ee8c870cd281d" + + "614e6bc2c0a5ca303bc48696a3bd574ee34738de4c4c29910f8feb7557bf" + + "ffcfe7428b4703144bd6d7fe5b3f5de748918553df5453b3c6001696f3de" + + "0137e454aadf30cedfb6be36b0b908a38409f1a2dc202fc285610765e4c8" + + "6414692bf4bde20ed899e97727b7ea1d95d7c621717c560f1d260ab3624e" + + "d6168d77c483dd5ce0d234049017795f2e5a7569d7ad323c50a5b1170337" + + "4174a9977026c20cd52c10b72f14e0569a684a3dcf2ccbc148fd3db506e2" + + "8d24f6c55544cb3980a36e86747adc89ebad78d1630618d113fa445f8625" + + "b583cd7be33913c30c419d047cf3baf40fd05219a1fcec717b87a65fa022" + + "1a3aa8143062d77588168019454240ae3d37640996f2967810459bc658df" + + "e556de4d07263dc3d9158ec242008226d1c6aea7f0846e12ce2d316e80da" + + "522343264ec9451ec23aaaa367d640faad4af3d44d6d86544ade34c93518" + + "2843f6b4d1c934996778affa9ee962e7dfef5e70d933d4309f0f343e9606" + + "1b91b11ac380a9675e17a96099fe411bedc28a298cd78d5496e28fbbd4f5" + + "b0a27735d1144348e22be5b75724d8f125e99c4cb4e9c3a1f0b4e9da5146" + + "e6afaa33d02fda74bf58a8badee2b634b989c01755afa6ab20ee494c6ae4" + + "c2c6f17af6b53b61d2947d83a18eb3b8a1612aad5d3ea7e8e35f325c9168" + + "ac490f22cb713ddb61fbd96011c5849ac8e2fcd42db820349bdf9157dcc0" + + "0d9f9ed9c099b10c7194d48b623b0df43759734b2a2e5f8a35e7192bf9a0" + + "03dcb9d16a54bd84d922f85b6021b28aacc5264fe9e83deb48f18f864cbd" + + "367eb163d39c45b0eb907311a2a4b09fb26109088df782ce031b02f3caff" + + "d2dbe25b1cbde9f35ba7c47292a4fd49e7def7a28824f3dfda259a86c3de" + + "59257c255c712686ee47d128a55c7b9e8c546035eab7e2da420f32ed5c94" + + "bc12a34dc68eb99257a7ea03b69d6c760b0681fa24e4ca97b7c377182ab5" + + "fee30a278b08c44c988a8f925af2997883111c750d176b432735868208f4" + + "0de7137331b544f2d28040a3581d195e82811c945c3f9fde68fc21b36a44" + + "e1cfa2d8eb625f3102461539b3f13c660936a5ddb29a0ae791fbf52c2f69" + + "7bd334653f3605b362d91cd78569b41dbd09b2a5892440b5097fa08d0b4b" + + "291fc5b934585dd8d5adc80d573fdd194b2eae26dfc49f5e51c1f1607d7e" + + "87740702f244bf39ca1d52423e0ae84891dfdf4f43ef984c7a5f293a2007" + + "a1e00e39c757f064518953f55621f955986f63", + }, + { + key: "d115b6ac998a65b48b3dae5977abaf985258d3d1cfe1616cec3d6a77f7a75785", + tag: "b431c9318ec2769fc8ee8f5fc3c079c3", + in: "7e7eb43839a6d7616b8a7b1fb7144817904342a9bd34167051162941a6b1" + + "b85db5e587f76e4a53211755d5ab29c11822d7711a97b3f1ff5b21f2485d" + + "9c86241fb56cdd6796245d3112df11ad9a7344db44d09934c4efb280ed65" + + "80cfcafb5c97a32993cbbf4917183e0b7bb38f2ce2479c28e1d39f673962" + + "17a7010448dfd39a4e7f406c8bd2d804f993bb410fffa4eb57518a531ecf" + + "259a8af068230acb826d9ffc20ee0fc43885221a321e3928971bb28615f0" + + "d9f099f5b68a80503a910fdba0bc643c60b64837900be38770b6b30c362c" + + "4580722b5dbb1b9c8cd02a18fd7b5661d2c4d28aa941c50af6655c826690" + + "37312fbf9f1cf4adb0b9400532755011b40e8252bd0e3c7a22efb0ef9122" + + "1e04b4aa8316d4a4ffeaa11909d38cc264650e7ca416835ded0953f39e29" + + "b01d3a33bba454760fb0a96d9fe50b3e42c95271e57840380d1fd39a375b" + + "3e5513a31a4b80a2dad8731d4fd1ced5ff61e1fbe8ff3ff90a277e6b5631" + + "f99f046c4c3c66158554f61af2ede73aede97e94b1d1f129aaadf9b53548" + + "553cc2304103e245b77701f134d94d2a3658f2b41108c5a519c2c8f450db" + + "027824f1c0ab94010589a4139ff521938b4f0c7bf0986585f535b6e292e5" + + "b3ded23bf81cec17c8420fe67a449e508864e4cbb7eaf335975668f013e9" + + "da70b33bd52a72094a8f03762ea7440ce9fcd10e251837cfc9ccc1a8cc47" + + "0c67379f6a32f16cf70ea8c19d1a67779a9b2d2b379665e0e908a88b26e7" + + "8c9f94f17acefa6d5feb70a7095e0297c53e091cf98df132a23a5ce5aa72" + + "59f1154b92e079f0b6f95d2a38aa5d62a2fd97c12ee7b085e57cc4652863" + + "8defacc1e70c3aceab82a9fa04e6aa70f5fbfd19de075bee4e3aac4a87d0" + + "ad0226a463a554816f1ebac08f30f4c3a93fa85d79b92f0da06348b4f008" + + "880fac2df0f768d8f9d082f5a747afb0f62eb29c89d926de9fc491921474" + + "1d8647c67d57ac55f94751389ee466bbd44dbe186f2f38abbc61a0425613" + + "e9b6a64e6bcb45a2e2bb783b9103483643d5610a7e2dcdb10b5d78423285" + + "506b42a99b00a4fb7b619b4526bb4ec78299dd01ad894fde2f053e18c55b" + + "6047f86333f2690c2cb8e87d9834ab8a5e339aa346e4d9952ed62dc083e3" + + "b11a823a67f23fec099a033f127ebe8626a89fa1a5a6b3520aa0d215a8e7" + + "dea3af37907686c16521739a95d6c532cc259c497bf397fceaea49cd46b9" + + "ad5c1b39a36fdd2f0d2225fef1b6ca2bb73fe604646c10ba4c572ab13a26" + + "559ededc98f5a34c874cc25621e65ba4852529b5a4e9c1b2bf8e1a8f8ff0" + + "5a31095b84696c6381eb9ad37ac0db184fe5fccf3554e514946a33cabe6f" + + "4d617b549d28ad1cc4642dac96e0215ee1596481600d3619e8f45e2c9ae1" + + "da834d44aca216bba0efef6254503ca90339f2d7ca508b2722d50c08def8" + + "a736590fa44855cd9eb9979c743783aa26e633696739f2ae25ff7b72ceb2" + + "4dff4455b85bbd675c8cb71ad18386dc58c371bdf37b4b3875b98a9423ff" + + "3becfc0d0ba2aacab3ee7683cb3b345095fefcaca5751ca793da63c89428", + }, + { + key: "f3717306b9729be998cdb2c9d856306c5ae3d89da2cdcef12f86f6110c98d873", + tag: "907dba0f4849c7cf4570b5128b5f31d5", + in: "079572187d4559f24d8e48dc366441acf226a4db79e214ec3ee288acc349" + + "887e2e377419bcafa377d0151497b52e4d9cf2a02b0fc91ad9516482bdf6" + + "eccd1497954b53241bfb0bc5c04cc45045c6251f23a510060fee32721872" + + "bbc95cd8d400dff00bcac2ecce6229c7d73d8f85ed5a87afdccf6dedd299" + + "2d5c7b5b8090c47c737ded036ff0e9aedf02a2242fd9820be618b9601e73" + + "d3ba5d8f1ae9805cfd2306251704bc74e3546997f109f1dfae20c03ff31f" + + "17564769aa49f01233c9c4b79f90fa3d1433d18cdc497914046ad77d2792" + + "2588a7d0e61d4258d7d80cdab8503e3111ddca22cf7f39c1f80f1e16a68d" + + "9e21db8b53dd316dfa4233cb453a39a90101c60efc08514a3057db007e96" + + "507745bd4a0764ed8717a250bffb5fd1ea58474bdfb5b869681939693926" + + "40d832a3387ed4ac9cdab0d2af8fcb51b86e4d927097f1e79b5af96574ec" + + "d59d0dd150a0208978c41de28ad6cadf72a49279cffd6dc281c640f2e294" + + "4cde49a13ed390da1dd92e3011ce0f4a0863375a9db3f67fca1e3b8288a0" + + "78611161d7cb668ecdb932e1ff3733982c8c460eeeff2bca46c96e8a02cf" + + "b55d770940de556373a4dd676e3a0dd66f1280c8cb77a85136b3f003fab4" + + "887dad548de7bfe6488ae55e7a71da4097db03900d4b94e776a939530328" + + "83492da900b2a6c3e73d7a6f12ee30c9dd06cc34e5a3893976eb1de5864d" + + "32e792ac02e68d052d9d0cfc7cfb40b77728422f6c26cf68987c6b40fcfe" + + "9d660abc657360eb129de11bd70af5eb8fe350af2c27a6ece2cdf81b94c8" + + "0e68e8c51106497cfa5171236efe2d71d76b5dff3352af9b407dc5aab60f" + + "46b5683646f5b28732b7c750d351a08a507243d8e437cc4bef13a3edaa20" + + "5fc4e9968b4e563fa0dc965ba20b8e48bc188a321b16d3213bed69647512" + + "7a20afc1a3680ef261df6d37b017dee05cfc3a42e4130216e5540cf715c4" + + "e638d7d615c50bef576eeb19b3b15b2c2b454dfcef2b18161a143ddf52fc" + + "8e88fa71cbe34c92cd4b5a0adc81e5c33e11d2721bc1b95a9e693ac3cabc" + + "490889a8a42bf7e22375b679e8598c8faef22a006ed2da8ab1c08aaed2f5" + + "6d6f26649036335c0881bfec1e3a5346335c3b3707ee92173f1a7a3305c2" + + "933f78e995da8f1df64daf12b81ce23c8813c27fd4551103dc33561c2e80" + + "45b6b6770fa03498fd359a104884699d628020173edbcc4398b977e456e4" + + "885964840466176a490e7c513ba5d66090277c1ab1632a995a54f555a452" + + "1170a000507865b6650730aa6d6050a55959102836fff3d37e4773340e59" + + "2e56951ff9652519de4421d9c5b63edbeb30a3852a1ea110a9a29721aee3" + + "23d5a306de1624cecc87badc47aa87f489635d2fb60bff62ba67f5257999" + + "6af0a1f1a6fbcd8704e119196fcc289a6db6a4170a2cae31a1d30744b702" + + "2536d1526d41659c2dcc8b39c26aecfc0f8a707136d81b2827a158fd7386" + + "a537514471c213a8c859016748e0264cf3fbde10f40c620840ec4df99432" + + "e2b9e1e368e33f126ec40c572e841c2618d49d4eb098b9533b1f4ae00b46" + + "8d15de8c8ab6d0b650e599576f2bd90a124c9c6a0f911fd1bd8253bac272" + + "942cbdf8864f3747ff7f09d8a5a9d8599be7ee1744e5f1faf3e526cd2a06" + + "b157527272af9d38565957c9ce663c295766c0e0e464971c6282b70d4c0c" + + "1fb3b69856b34c089ad2b2c745f5a033cee1429c5b855581ee285278893c" + + "43a5968d9c28384b7abe8d072ba69089c938685cb1eab461f05314ad6d06" + + "eaa58512f8738bde35b7b15ef359dd2e8753cb1ed6", + }, + { + key: "9772c1a4b74cbf53586e5df04369b35f1fdca390565872251bc6844bc81bda88", + tag: "68eb7fc459ecc3be819485001ab438dc", + in: "e115cc2f33e367cb85c01a914b3a512404ad6a98b5b0c3a211d4bffd5802" + + "ee43b3fb07451c74524ec8b4eddbb41ca33dd6e49791875d716a44bec97b" + + "7c2d4546616939ffa3b1ab9b8ba1d1a637e7c985cc922606caa0453085e3" + + "5f2fe0bd2de129d1d1856ade975a3281a62965927d8bb695e54514e69558" + + "89361a2a00a1b24e62bda78d0b71a0d40147016fcdaf1a702331dda8e678" + + "d8f476dcc91698da1688c610ec0cb1d9b8fbcd45dfde6d1503ba60a01337" + + "ae5b2f5c854a82c3087779babd2e522dd92f4718cd9f8c649ac226745ca2" + + "fa1696442764758f67cd926369578ae87612790dc56ed9cda935281a490e" + + "5c984950ec7a4e930520d273a69da4ed3a330e532508e26f942961fed0e3" + + "efeed52a7b96250d723155aa39a8ae85131c255c32bf406b647de1a37fba" + + "dc61e302bb5b70adec4505ee66b3a1d1b7bfe9c58b11e53ad556d56e5807" + + "017bb30b71be94e8f86aaf1496e8b8d6db75ec0afbe1cd336c23963c745d" + + "7b4ba1787ceb30728f1762b46f6eaad5064c8029d29b86266b87f93142a2" + + "74f519f3281d8c1cb43c23eb184ae41f3f625cf624b05a48d73cd7783fdf" + + "14954a03ec1a930e9a954424eff030e3f15357de4c19983f484619a0e9e2" + + "b67221cf965e9aa8d8926595c793adfe0181050df8b845ce648a66df532f" + + "78b10c83ecc86374a4f8abf8edcc303654bafd3dcc7de9c77a0a9d1d98fb" + + "121534b47d16f75b55fdc2a5e2e6799f8a2f8000d4292282e56863ae422a" + + "5779900ad6881b78946e750d7777f33f2f013a75c19615632c0e40b98338" + + "1e9b8d35a26abe30242c45662eebb157e6d7a8a5519de60268ac289b8295" + + "5d4feb47b9eef6da65031c6f52c2c4f5baa36fce3618b6a331f1e8bdd621" + + "48954fcf0846afeeb0a6cadb495c909a7fe671b021d5b0b4669961052187" + + "d01b67d44218471bfb04c1a3d82bf7b776208013fc8adabaefb11719f7a7" + + "e6cb0b92d4cc39b403ceb56bd806cbdcc9ee75362ab4aaeb760e170fdc6a" + + "23c038d45f465d8ec8519af8b0aad2eb5fae2972c603ed35ff8e46644803" + + "fc042ff8044540280766e35d8aaddcaa81e7c0c7eba28674f710492924c6" + + "1743da4d241e12b0c519910d4e31de332c2672ea77c9a3d5c60cd78a35d7" + + "924fda105b6f0a7cc11523157982418405be0bacf554b6398aeb9a1a3b12" + + "fe411c09e9bfb66416a47dd51cbd29abf8fbbd264dd57ba21a388c7e19e8" + + "12e66768b2584ad8471bef36245881fc04a22d9900a246668592ca35cfc3" + + "a8faf77da494df65f7d5c3daa129b7c98cef57e0826dee394eb927b3d6b3" + + "a3c42fa2576dcc6efd1259b6819da9544c82728276b324a36121a519aee5" + + "ae850738a44349cdec1220a6a933808aee44ba48ce46ec8fb7d897bd9e6b" + + "c4c325a27d1b457eb6be5c1806cd301c5d874d2e863fb0a01cbd3e1f5b0f" + + "8e0c771fca0c0b14042a7b0f3ae6264294a82212119b73821dcfbbfd85bb" + + "625b6f75e4dc0ee0292ab4f17daf1d507e6c97364260480d406bd43b7d8e" + + "8c2f26672a916321b482d5fa7166e282bfeed9b3598c8f8c19d2f8c8b98d" + + "f24c2500c8ad41cd6ed3f2835737916d846f1a6406cda1125ed7740fe301" + + "d1144559b7c95fa407599ae40a795226513153f86c9b8abe7d8aa6963c99" + + "5646ec586cbf20a03a698cc0681b7bd333402d00fa8e15cb32300b5a24ea" + + "316c5e1df67de78891846cb9183a4b112c3bcc17bcaa5fecd6c1dbbf6ef8" + + "272d9269e7f0ba9f17050a6aa5f11cb28874360396ab647941f2c9a85cb0" + + "6a969919b16997b0827af8f909c614545f1ad638ebb23109f6bab6b49b22" + + "b2285cabbb998b3e1bf42771b4d4e52330b224e5a1d63169ec85fe1c7dd2" + + "46dbafa6138448420f463d547a41c2b26026d4621b854bc7786ab3a0a93a" + + "e5390dd840f2454028b7c3bb87680f04f084089bbc8786ee42cf06904d01" + + "7e405144d2fae141599e2babe71abfbe7644fb25ec8a8a44a8928ff77a59" + + "a3e235de6bd7c7b803cf3cf60435e473e3315f02d7292b1c3f5a19c93646" + + "3cc4ccd6b24961083756f86ffa107322c5c7dd8d2e4ca0466f6725e8a35b" + + "574f0439f34ca52a393b2f017d2503ba2018fb4a0991fddc1949832d370a" + + "27c42e", + }, + { + key: "d18a328b63a1d0f34e987682fe6ca3d48b4834b4312a17e99b3d88827b8d2238", + tag: "938b43b80cb3935e39b21dd8ba133cf8", + in: "bc2b0baf92580ee6c5efe640f2a029a791a3c77bec459be74cbc30931508" + + "d9f312c3a0944212831cbe4fc92e8f107f2f750c91bcc09f7624fa9a09b4" + + "9b7712cf5d619ea9da100fc23068ae2f4e353047e3956b215884bdb12235" + + "3f06b8ee98f36c3212493d61ae9ce151cd0453f3075b18a12d7d73da3de7" + + "dc2d98376cfb420069ca8148c511ca6bbae57572394a3c615a6fefb30c5f" + + "d727f964b4065ac9ee252bdd2bcae3e70162fe0e8069974e073f0a093d45" + + "be52d7de16a8f5f65c548aa6525822ffb00dc642530fedf355f7188ef017" + + "56384760c80afb61ad903d10119a7d615ec4fbdc79c490160bdeaf200915" + + "e405f2a921a2380c0ab9d2ac1e4fdc8ec4b907368c004458598efac13dc7" + + "2751e7faded538e3dc8b16590cac9b7ec294da0ad53e22cb9c05d8ef494f" + + "a04f6ab7c843c867fbe3cf1b4eb146d65339b0b03392259f12627a8e98e8" + + "0f4896c30b8ecd210acb2365539a872541921dcd8e1e54caf4936dfc7e1f" + + "68f3bbce61d325b447a8cce7f0fcad28494f2e47dae46b136594b5dfca7a" + + "bdafd6856f91496c05b21079aa55aa8c41628220a2cf0cdd755893375b7b" + + "b13d914c9a1d1db4a18f8fa36c55e52d0342352052032fb62d32fcd51cb1" + + "ac46f44b06e682db5d96d583cda03b966c650c03ae53542e8da1066b6884" + + "4a7e2280c664415e413f270b1fdcfbb40b9daa6131d071ee7eb1553dc5b1" + + "a50677971223dc316d2d326d57cbd529c88698facdca425e2d5c6b10d7ae" + + "cae28b8890aa44ede9b9193dbe8d1d8aa1fa580ca384b57eadcbefc96dd8" + + "bfccbe3b855a96f1fd4913035f817b75954ef1827c7718aab24d353e41cb" + + "a73748e14e0c2750d5b6a9752125708cc7ee7a498c7fbadf4186e7f8fa93" + + "bfdf281a49400f877621651b8ba87edda5231e80b758564e75139b61b1a9" + + "9fb9ec694f928ab1f47c6c4287bd4182d1b2be053380616e98da06f3ef57" + + "b570ade17c51da1d602b6ebc5a638ebde30d99bf4f91d0e01557c7dcd8f7" + + "9e5120143c935fc699eb5616ccd3cac56b5f8a53ed9e6c47ba896bfefe71" + + "2004ad908c12cf6d954b83bec8fb0e641cc261ff8f542b86e62d90e227f2" + + "a5bd59c9d390c0dd857f6da2b7624787a0bb31908bae84896890b283da61" + + "d8ec4f56eea38b22b438d6374b42243f9c1d94288874e53ab90c554cc1f1" + + "d736acde67aff55007fd4b3becc4d0f3ddd96f10dc75255cb0327aa47076" + + "2b3a3a656e33c87b02a682658b6cd2a75d9c0462803c9bbffa51441501a0" + + "3a2fbb2344aa13d27ffb9e98704ea6720b6a9992e53449688cd74d0648fa" + + "e8e776b0ea6bf048b2ec05341e5948cab0af015328b284ae7bd89a5f763c" + + "eaf5ca3e647a9f5bff7197e4d357e4359fa5fe30709545453149be510e3b" + + "ff86beeba5110c79c0215fbe9ac9339a8ac7d41f7488588ab14ac657aaf7" + + "d5c03a353932bbb2b261f0e83f3526c5e8e0c2348a10ab4eed6ecdcf9014" + + "7550abcb0a722f257e01d38bad47cdd5a64eef43ef4e741bf50da275720a" + + "0aee47adfc5cd2534b911dc269197c3c396820b303f6941e3fd85b5ed21d" + + "6d8136745c3eeb9f36b1f226434e334dc94be8a5606079cb7643136aacd2" + + "da9c38b2eb7e2b898bd8632003767bf0c87d00a3c2fcee48bbbcdd949af3" + + "3455128216709df25879b0ce894ac4f121dfca6b8c7865002b828696641d" + + "14ffc59924fbda50866fded0afaea545c8008c564a3a0b023f519a9980ea" + + "d541d91d1c07a739fd02286ea5660e473f80494236a68e84ea31aad71348" + + "e45055ded69c39941e31d51df257a4d0b0d8f025dbedee093f2b91795bc1" + + "533dc472020769a157a187abd6d8d52e1693e2ef56b2212759d0c0120e54" + + "c425d0084fdb3925e296dd6cdd8e677043a90674904057d88ebdea5998aa" + + "03562a790adecc4399352df43e5179cf8c584d95ef8e4b37295946b1d37f" + + "faf4b3b7b98869184e42ea8b304fe1059f180ff83d14a0861ca7c0682c34" + + "b48a70df8653bd8d9a26f9489e1271fa44e41b392e648d0e619ecdad2c53" + + "952094802eeb70ade4ffe096e3049867de93a824217e31364b18204e9681" + + "dd8e84ae2678aad155b238f59dd9bf9ce07e97183a690b2a46a8f3624843" + + "5b2f713e7d8dcda4dea1e3c4cf9692dda082322c51f7bb1f63d92aa987ec" + + "cf1355a043e21a7b8d60a2b97f18487f6fff4c77df92dbfdc9837540c518" + + "9fd9585731bc6e726a34ca21154b0499522c9d1016953dd0fa2eb6a92b6d" + + "14d6e3da5c12fabe92bd639e253983fc91041091791643", + }, + { + key: "46e8eb27acfdc8f4be622d8741c7bc414464c149e21da97ab4afbf3e07b98b0e", + tag: "56b5f49be824c7a19b19faabf0787a87", + in: "ced52b76c057872a60107194b432cf04b7be05e65209045d2952ea0284d8" + + "3e2ed5a15cfdc58071204573c18ab03765b4d5e63a601419e039c42075b2" + + "7ebb2827de9c6233d6632e6d3db9140bdb4a9291d53f33734c2dc8e24df9" + + "0764dc10e0d321d20fdf659bfa2a81bc9e04fd0f83448143276647c08bfa" + + "dcfe3bc23898eda655c9353693ed7b022f43eefa23c21db7660c5029ca64" + + "a6085d93029ea6c43197356f56b7624d4819f5008d053357d981ffbe7f40" + + "96d6c55d8417002d36189b04bbb2c637339d90f4910a400833a8d422d88d" + + "c816c1636e8d9f7f926c244a28d9e0a956cec11e81d0fd81d4b2b5d4904a" + + "d1a5f55b5ec078dcb5c2bc1112bbfd5efc8c2577fe6d9872a985ee129e5b" + + "953e9cebf28cf23c6f9c6a5e09cb09ab586c6a50e4389cd3110777591d7f" + + "0608a3fd95b99f6ba03984fb0e13c6bbbde3668c59f2f2b69d7caadffa94" + + "6f67e725d56280e59e66dca025a18d4616e81abd9801835bd94485bb2025" + + "dee81fba440005b181ee81dc1d7796cbec92e4ec1c9016c8e8073cf281ce" + + "f749993f09a618a4671d58b476feffa454600f82955c591882715148a826" + + "586f68bb50059914dce1c1c85e5e3951647c9964ec9316005209a58baeb5" + + "2c6d01e6b4c275c0050a7e2bdc52133e433b050a700b556d4314e5c041d1" + + "93ee47f47adc971aed1b63259dd5cd4f95854a71a947eae3d3d12d0d7b52" + + "c6cd2fef2d2e892607a9681d73ac3236fad21ee30a4f857010bc95c00d5f" + + "6f0c6b3fe50cd6452be6eec4f5f01542dc2cb5e2db1f52224f11348fe2a0" + + "5d1e5885f1317f2d06ce2813dc4c723008e836a2ee95d0aac66855fe4c3b" + + "1b2e02ba0700be759b1ef1c2a3123ee4ccf9200d8d4de5e0d503f04c2053" + + "66393d1e91b648392ca28389d976aa618b4796acbfe8aa356ecdce1f7786" + + "bf09af226bb9402317b6fa319bbb9248d8ce00b1f49f066c69d4df93266b" + + "938342cd7fd4b07c320c2409ef72d8a57c21d0c6d6d493f7ca94d01b9852" + + "e4fca6a9291e9060154bc38af6c86932645f53914709fc90e11db56ec471" + + "6d600ee6452041248ea8244f79534f793bfc1f2020855d817cb4ca3c48ea" + + "7f6441ce9af9bda61936c226d810086c04a35e8654fdc30d4b35701adccc" + + "016d5895b2121ba4066e44d694f6371d97911786edb73dc3020ba186a01f" + + "ee3dd6036c0e205a8d05979bad228fd12c0fd2fded6c7f1e4c11354d266e" + + "d9c2f706269c43cd90504997d93a17b39b10dab0ff083ab3bd06540ce612" + + "d08f46ce75a16ef330525737410a0d98fb3d484968f9c12edcaf50103fdc" + + "c14128ea4ad6c30b56247eab28197fe617e5f88afa5cbe003c63d423647a" + + "d3042626fafd2084a0582ff1b1efdb5baa162662048019546234e2f6b6a1" + + "d8bb971114aae41df7795b4f3598f2af9e8921a9aadc7fab6c780aaa32a3" + + "84865a4ccb02351dbc55ec92a3152d1e66ec9d478be5dca17b4a131b4a0d" + + "3d4420fc6123fef80fd56ca266407d58a7880d6b7e5ce2b6bdc9a3721071" + + "7feec573d83c83a2e3f7d4023f2f68e785cde728fdbf5054060e4c89faa6" + + "1c9dd10524a08811d15c627b3b4ada549a3fa1d8dd77c005daaf2addeb10" + + "0abf694da8dd692f113965cd6366a5a7b0c17e1f2a320243e2c90b01418e" + + "22426d0401a2c8fd02cb3129a14fdfa6cbcaa1f1c2f17706e9ac374a3458" + + "777761e986ee4c358d26f8e420d33230d198fd86704e77298dd4c40c5205" + + "7566ac0cd92993b21937c3a3b4a8b89110a97cf38c781ad758bdc28f3565" + + "60cf3acbedfa8e05b396d226ef619746e8e4fa84c8e00a7f0e6d652808c8" + + "9c9b123d9bd802624cfa949eb68af85ca459b9aa85b81dbc0b630856cb9d" + + "7e18cdc96b3c069a006dd5b716e218a5ed1f580be3e3ccf0083017607902" + + "a7967a02d0a439e7c54b3b7ca4cc9d94a7754efba0bb5e192e8d1a6e7c79" + + "4aa59e410869b21009d9443204213f7bceb880ccf1f61edb6a67c395a361" + + "ff14144262b4d90c0e715dbefce92339ff704cc4065d56118624a7e429e4" + + "cadf0b9d2e7ffc4eb31c6078474a5265beba0774209c79bf81a930b302bd" + + "0f142534a6ae402da6d355a010d8c82dc379ea16d49b9d859a7de4db6e62" + + "40f6976ae0f47bc583b327df7ec88f5bd68f713b5d53796e72e28c29e843" + + "6c64cd411d335623ff4f5d167f3c7b8cba411e82f03714662425c8e1bc1e" + + "fbf435d28df541a914a55317de0ded8c744a1c3a6e047590244b207bcdcb" + + "f4bd1f9f81210deddd629192c58e6fd73e83812f084ef52f21c67bea98ee" + + "17554437d9642e2e", + }, + { + key: "b41210e5ef845bd5a8128455c4e67b533e3e2b19dffc1fb754caa528c234d6a0", + tag: "72c9534aec8c1d883eef899f04e1c65e", + in: "7eeca180bb20d99635e36b9208221b2b8ef073fbf5a57f5190e19cb86c49" + + "89b0e8150d22ec3aaf56f6ed9cb6720284d13a4b0a34cd3d7f7fc7089326" + + "6d1893fa4185269fb806677ff490aec8f889896fca50d6c80d295875b1d5" + + "4a779b6d49305360b31011b48537157d0f323ff4e865d46fba6bd23a06c1" + + "46878cf9404360d325432312ff08ce495edca63a3c93c44d79c050e3f1de" + + "4b6ca5fedbbd43dbdef9ceb26d440a59c7e0be3a8e461c4f15b6b1e1dc36" + + "a71fc723ad593fb903e83d0804ce497fc49bfc6b6a602b9dc6e9891010b1" + + "4ca066cb1c68044c1ad837c638076dd3708078509cba49fdc54922cdf5d7" + + "715fb43e9b5a5942cb8950eade143577bc9dcedde58d51deddc70075e452" + + "bbceab1e95b5d003eb96bea69687faa6d50d9c605769cb4287b5d9924dd6" + + "8881c699abaa6f93e41dac7639cdbbbd0259099a3ed096f482a1fa322b15" + + "ffc379812c74e09e95f1bd3706347eac421fe56895e738a47fcd3e118773" + + "c3a7e7e264cc7ff5a53a80e436df058265dab9756fdf6913786a47e98bbc" + + "411052d58ffec9ee948e28cbaadaae471c5d828eaf3b3c87d3bfd495477b" + + "403da54f1418a15ace0d4d0df68f6a8f2b0457b127d5eae1f45ae055afa1" + + "8f058d5dd7eea559de3ae9378ca53f7d6dc9a9465ea1f945295f16ee0404" + + "7fc9dd3deda8ee32631d7af70c20edc1e12c5f8abd2e78f43dbd4cd6407f" + + "038efab144a24ea8a090a7ba3e6499345a60106220c2959a388e1a73d070" + + "1d854bfaaa86165a5aee934b615ac7f45da7c43a1e8f74613917ed10dcd2" + + "27e4b070414412e77851db5bc053e5f502bb4e2b2645bca074c18643e814" + + "4caeccb58be49ea9a552913c0616382c899635eea79a166988c206b9aaa0" + + "977c7ced89c4c7aaeaa8fb89b38030c44530a97187fda592b088198b63a5" + + "2dfad59a0a4c1aadf812bdf1881924e8b51b8fd4dbca8e73b2986b3ab484" + + "171e9d0cbb08be40ae60de8818bd7f400191b42c7b3200c27643f06720a7" + + "e0a17441f34131629388ac43955b78c31ea6602a70dd665f872e7669e865" + + "f6f40e634e8772d747608cd3a570e1726eb1ddca64f08582b022bb026eda" + + "6a913dc83f174ce3c18b9fc0503d3ac74e2fe45691d6dfb4af8c86d752a1" + + "6d6664fab4de08afe8858392fcc35cb9ea82fc42c42d48c0c0556267ea0d" + + "cc19b10f05e0318c4488ffe704b5036908f5cb938eebd3163503acaa874f" + + "592d945448fbeb93a877a26a72306a36e181745ba300afdc30cb7986919f" + + "3dbdc5c47ef1fa052a9e4aeeda3955f61ce2f30a0593a81dbaffebac5a49" + + "e5a8d1308352701d1ca9e620a67a89abdf5f0f8b1a0acfde5819981d4b77" + + "58799c0fe41030b86754837712af821c315301aa8dd50d1387b9fb92ee63" + + "10777e08229edd54e5e86b086ac281bd321082ef46ce298a6211aaa3aa4f" + + "6e55b5a4641220ec94cca73087760da1b1ac3e0da3f438214e691aa184b0" + + "535950b715a64d11485940dcaa3f72e0aa521002b1443f5e7880e2a85b83" + + "40d32db0fc4c4702e10f0fa24a35da9307850e945f608ad34d6cfdf6f2b9" + + "ff4f6b8e9eb5a883546578e2ff3cc5787322e4384640f42dc5bd05f432d9" + + "610dcf7c06cdf34762dd2a5e805e24aee8cebb3b4db9e4d1471da995bba9" + + "a72cf59ea8a040671b1d8ce24a3dce4fc86d2df85c8ab5e1eb2b0567c186" + + "4fb464f48c3ca72c7df2749542ed4d4be51b63769012ce3d06356856b2a4" + + "24995a2429a156ad93bc79c705e7b163149ce53a42c34a19680dfe4fd0f7" + + "fce38c30dffe9da9bc941d131f435c1398f8284a230e9d6e3992710074c3" + + "881d03aa309a9edd0fde7a39c33f6455dfcc5ae3fa20ea0e0d6549a43536" + + "b4cd8a2991a135b7d7a4265fb840318813091274414108f13fe191db7774" + + "6a5f4270f6d51a29ff523954f84cb76131d4abee79161dcbd97dc1ef24cf" + + "db1fade057dddee00a1e0de0db1afaeed1b535f7bb402afa3b297551fd14" + + "8c8f3e05f1351d3a8ee2948daaf14e7fc448c4670c906ae076eac5a7c656" + + "fd5f9cd937b91e26c9e5adb43c138f8d65e447b0022a524e059f879c6e27" + + "4ff7e671f75717233aae70853d5bd7bbb41b43c47bb08d6dc2f54f9ec606" + + "9487d1267add72403d01552a3d138abab9ca8a0d2dc32439759aa5695f70" + + "1a17d28dfb85850fdb55fddadcdde4d220e4b05821e5736d346e7dc9c945" + + "72743366488b1de8975184771361894b6520e3407c5c2e38473430969e35" + + "b106024da8618665d58c9d084824a28991a33658d6ec702139e01b65b7d0" + + "cc537a644caeee880657803d95f5f67816948d5ab362922f8ffbd531473e" + + "b0ff8fde2afc37a4abfa28dbed0be1b3d4ed48a1d02358e8403905d33b12" + + "3066e7a9fe2491ee9eb24fc9de7dbd322c8ddbc5ebcd0d92cd102ebac96b" + + "90e2fd784fd6d4b699304df23b17d963080a013794322690456be525c071" + + "b78fcd2d1148026e44ff14c4d0f942cd44d2b3263f4a93b79ec7a618b4b0" + + "d77ae7a1f6e6c7c7e2f498b825bf1954df348bae45ae1d7c87b6787f1212" + + "60c9a724429a4a2491ef989f65acfdc72fa717486dcf1984905218e11cc3" + + "970a09d71061e6df751f100abfbf", + }, + { + key: "d9b0dc303188756312c12d08488c29f43a72e78714560fe476703c1d9d3e20c1", + tag: "6b9782f2a09b59653aa448348a49291b", + in: "dbde1820035997dc8a8ff3015b4e0674e7ce7bf0c2d994b7977f2d91b49b" + + "f200995040daeb1218a0f4307b6b8211913992b070d321bdb947b4ba5017" + + "a0885e7e5502710a75cbbcb56d49e1bdc2bc2afa5a0e83851162dec41340" + + "bafc41c5e11fcbf4ea2ac45bc57def4742281bbf734777f83c9ae1ea3d5e" + + "d42380230570f59c40d5dd9a2d89b75fa3c92664f12a274d965ed8de79a8" + + "b37f3763939ad21d1703ad794f617c8b32b20cc4dd7c1b7f969a65e1bafa" + + "f6c43f30c9eba256f10201910e2cc31a9b13a46ad29257024ef8f2ee29b2" + + "ee63cc5b6230ab9f87cd5cb534f4b0bb08a790466e0d57b849fffa1ed21b" + + "fb0b27804e3ff9df7bebf14e100cf91691a493e53870abfad6321f6711c5" + + "0fbcf1f0b2c1e5231d6c0a08e710525176355f6f82bedc1f787f0d3cb41f" + + "a11e91ebf9f4cbae46035a371232d63ef0d8bda0355af8cd0a2f7d1327d8" + + "0ab769ea0f1da0f76ec99cc737b5ce84675fa8a9ac0c98342bb82b5848bf" + + "656d35327ea01a1b09d84ab974c307511af68a30cd6978b529a8f58c68a5" + + "9d476062ace8897ec0d1a90d5d167e29ebaa6f46d93d697760c8771417ce" + + "94c0f3698985a98702833d1b68641b811840ca3d935386dbd4600fbc81c8" + + "728c4fd0e4588be739a048f03bd4ac651ceecd7e2fb120fe7190011f957f" + + "cbbfdc025f1ca0b356208db8cad87fcd53c5d3a30a7c2a48140ccd4cdb49" + + "f3961cef742caedd1e848bf3cacafb0da030416bf3177877aa0bc5f9d1cc" + + "41fafcb829d5e3ace9394028683d712552579e024084a6b855830ad9f567" + + "ff58f05d3ec263eddd6f56adec378f167e8dabbeaf7d0a9e65c71660314d" + + "6c8d54beeca2711113fbc32a2ff8c0daa8373278d10085d2a0660ad53f4e" + + "1ade74a483be180180acf9e9ad3ea5bdd9162ccd69599163a451c6837d5e" + + "a5e115bd9a560f395128ea002ee739009a44fa46078b18959933fb6e866f" + + "eb4612a56ce93b1affcb95fccaa18d71a148582ba1412a5daa07404fcb39" + + "c3cb4a2519cc506c1172c6c326016ae2e5410f6a438569f35a50d45cbf3c" + + "c46188651aa22c257858f60649cee8c05c75953ce49358dfe5980445fce9" + + "614ccd16d333ad236e29d204691ca0bf46f29da954bcaae52e41016556d2" + + "f4cae1d37565bcbe84de1b49f344d0200478a38187da29c155cc98184d9d" + + "33dca088d70054e0fce321f7a90c48a14963d0ace2b4e7a24b21c14a5e67" + + "1994fe1f7d22d1135d4df9268dd18d323fde3603288735626a5449582d35" + + "30e2c2225414e05a8c7b987c873a82e272a5d83e59b90f3d7264631d6ad0" + + "4a0cf3b5e96596a66ed5bfbc24ab6e4870aeec0acbad2cc5affaee06de32" + + "dca06f175bf763cf8e7fdf95941a177e934f0078be7dbaa4c9b6f5c16b4a" + + "5607bab5d56144a6ba3c7d9a084b8d1f4b24b6f9754ed207b230d3a2cc26" + + "259ccc725e1f8a44c4df8143e13edb5ebf073e2c9d2da5f1562df4feece2" + + "f6480987f093f642eb7afa3aa92dce2a8b60bb925cd2d11cf6c2ae7d2153" + + "1a9c8f068d71d0e682023932fe64e956a49347aed22b21084c4a84480491" + + "244ac6b337b6d12d5551ad5684766c68bacca62bdcafab6603c81bdbd8e6" + + "80d9d8b3825eaea4df023142e840f98ee251466a0422d810a54726a9f03a" + + "7e0afeb0043e60e2ba4908f951d2e87fcbc372096f2a9f4f2a95ad5faede" + + "3796b11ecf4401c3ee3d268bd8c46476c61e0ffc5c43c0f3c58c79e20f75" + + "520c102aa3c260972a870fc50f8841fa0553a9e30bf37ad282fb51b34adc" + + "7a933ca1691a8a706605ce0b906fdccbe954f8e5f2f63c42599a483c4be7" + + "3a041ef90ad930fe60e7e6d44bab29eebde5abb111e433447825c8a46ef7" + + "070d1f65862b30418efd93bfea9c2b601a994354a2ff1fc11c383e7bc555" + + "9e7546b8bf8d44358b1ce8cb63978dd194260e00a88a8fd17df06373aa80" + + "04a89172a6051bd5b8cea41bdaf3f23fc0612197f5573f3f72bce39c9f89" + + "faf3fb48d8ca918586d4feaea7e0f2a0d7a6afca096a081af462ea5318cc" + + "898a9cc09e8258a837559570cbd5eb901e8c0e04ee88ba31c81a76b000b8" + + "0e544feba576b3eb5272b53e46e96a0b35b9c759caadcec61444f8ec47c3" + + "45a1d2304e2708eeddfbfa75a98eab3493889047d690e84431d445407fdd" + + "99560c0bdd287e0944116f8ac62ab992ed3f1e2b415aea784b03c6904795" + + "f4326ff60bc839615f2894570dc9c27cf928ef192047528a1a19ec990978" + + "3b0d1a13dd4baf4a19e49bf798975abe2ad167dd574b32b3d0c22aa4d9b5" + + "2761e8f56cf2100fe5a39fceae3d865f3724d4f299d07ff899fed6baf7fc" + + "eb7189357bf56cf94a6493e61301b43e3ed158cb9c7a0e615fd9888c2db0" + + "7f7689762f62ef6b3ad4125e06b07a422f5040c3aa8b8f205d68356c9225" + + "56fc4c976165fed9599daeb297498ecf744bf6c7dc5e30604c461ad99402" + + "2eea0fb6fe33f82a97b5c272fd24162a94b761ec7e52173e7bb42e88b343" + + "64f5fa2c141ed04a86b8d00fd9c25bf77a8dc3e63f5543331405be6bf421" + + "6a891089b316aa4f887cb4aff0dfb4e80c2ccd65ddd9daa74b17b4411c0f" + + "c849dc748d9b138279dcd9ebfc6e6759a53f5c28a41bb82107d71cc161fa" + + "81291a8290", + }, + { + key: "fb70ae7ec12264ff9f51124da188e5b11dbf53cae2671363f6054b575b1ddcc1", + tag: "d9ab81fab28b3be96fa3331714e78c9a", + in: "c62edf20b1d53962b42386eb570b10378f9764421ecbd7c4802853332747" + + "19ff4c89c06005050fa9ba6579a844060eb7ece6c43bab520e683e0f36ba" + + "49cba259edc6ae35d41e0d7812a7d5edbe4d90cd5e0504d16f4c3f70d01f" + + "5a0313de55934b661ce1ec317968c2c4de60f45c66cded8c10565a1ca6d2" + + "3a84bf182df2fcb05956ed4d46b49fc0fe3bd23961d9466fde070341ce41" + + "bc6e148449360a31634fe10e91082d82def90d9da2c250ea72c58add2058" + + "d046b4392b78bc3af5b3936ed568733e8ad5672dabbfa3130a6a535ec73b" + + "da8e7223535f49f96cd35d56ed4792c5cb7076720d5461d96a2692b2ada5" + + "2be08fb7bad15d15a0108143790024f0f15f5adc275e783aa56b70844061" + + "e30952a040e4cb9650f2a010417812790105d8f58bd25d99b0db3cb16229" + + "3f6322e86cd5b0bb1505a7b998fb0f81d1e1915faca3c2c8ddea39115507" + + "80339430a7955521839deff5b301f3fad54edd5ebd2ac4ec9b1795cb4dc0" + + "e2eb62ebca8e886c3f1e507d10a0228c3027b472a7104b815f5ec8dae55e" + + "0783ff7ae9a3e6b99e381ad788206b135520cb870ba0cdbe876feea843b8" + + "5a82adc95a6d71c555f798da92b82daf0abfcdbc82ec30b1f12d78490b06" + + "7315735017a94ac150b44dfaace151896f873923310ffcd41e91bac04de6" + + "d70ea71565948c907ab21c4a23703fbbd2a8de6d3095f3d8f901538968e3" + + "60e7bfddb9d22036b1c23f4f5f1b2ee22623426a2d5de68c1e1a38e38e08" + + "e2b5670aac1edff69e9c73c2ca56cb69c709009ef1d541aff1fdb2b40c92" + + "9b87f162f394b76cdbba1f5605993e4dd9c312321d59b0aa5c6e33be1b10" + + "bfd00b92d4c02db064d0e4a98f2913c89051b0f0ead163deb5087b6466d9" + + "84f57553b0fa53850eaa142e072fd91802eb9f0d2eb7318dd620555e6ce1" + + "86706b866d41cf6ba81f100342faa14d801dc6f3d522db38fab17a879fcb" + + "b6acfe922163505bd23a6842f6ef6397ae5fb6e6016421998bd43b0142b0" + + "3ca3b16d6ccb7a47891c75c687d791a930b26aaa2e3412e7aa16e2cf1501" + + "7bf6df6d2e1c289af0d7ce03954a60c1dfcee5e4b3da51eb43ddd14faf59" + + "082005d0c8b104561f66c002ff426be60be769282fc5685cfd1968df1941" + + "73667e48e9ad681d35757f1199f1d93377bbad093c8cc3efa2bcb6ecb703" + + "694422772d15aaa58cab9e9ab277ed510f684114cc4a44ccadb3eb1c9a76" + + "d8619a9b7743106df6fb6f927ac49b22ae5bb9a9a4d231e340a2cd0e3282" + + "53f6d75df694826f60e4b3e758398793eaf73ef5d4b56cd1471e16400f40" + + "4a947e9737f4f874fe09a29ad799f4525156e3abbf0585c3c3c0a3744c86" + + "5d56db3d2ecba6bcbb1adcc8bf5f3b2a2d46d3eba18cda55201598a8112f" + + "d8f14e205f0e615f081b8ff6c5aa6669da776bfc7c34d5af4d0b26d0d819" + + "f6aacc53cf3c6653138b9a962acee9d6ea01d280c35bb1f05d1509238ccf" + + "004c5013167f804d1780d9f4ef9d45742fccac346b0472bde24ff5db9ae0" + + "16455a3c02256358fcd8e6a9aae94f8a37a1a3da58a889bbe3d295e16544" + + "2e580f59bdd31c92ffcab40c49c1cdbb4db1dd4882b66edc10fcb1704203" + + "c518c1d8d4c268588ce13fc38e0210aeb47d11d2603d4b3de5c6ff5e969b" + + "9d5904abb282b699bd04a6e9f1cb323679e30400d725aab128a032745dc0" + + "be05a46b02b34b93bff02523cd8498c021fc35a488f164a70ef1ceb873d9" + + "14a681d3a3a34cc76bfd5a547e2630d7741a284511bae5897d9f7a197fc2" + + "456af5c6cd7e1a93d3388c7a990b5feacd7749cf39fdecdc20adfdd540c6" + + "9d330195db7cc0d4555ea5f5356a3647e2265399f153c34ed1e217c5dafd" + + "c2c5dd3d566c332c7ddacb0d76ecd3a0ad505a4165443aa81b0f43cabfb4" + + "62942fe74a77c22b8f68a8b1a6d712d1e9b86e6a750005a3796ba1545396" + + "13170906d228dabf572ab969c762f8b296054f23d5d4a37bff64bf9cc46f" + + "43b491b41101256018376d487fe8097f1653a7a9e99e1ef2492600598fb0" + + "bbb7df8270be8b9106126d6f491f8b342a96ab95df6133e883d3db4c6a99" + + "402aeb58d371263a32dcf76d33c8904395b9cf0016fdfc15608eb43e20b0" + + "99cbe7455f7a76f69bba058ef96f83ae752587485657f89c7f26fde7fbeb" + + "a82ede581ee92821dc13b8202930aa58bd4f1c86f68926baca0d06fee642" + + "ea8c652d226af91a9638a0244f1a03c7ce56969b87cd5c1f86110d192e0b" + + "98dd979d74acca6c1956b1127d9a1f456053d17974081ed8ced0faa4293a" + + "319e5b25ba285c1151214f52c283e39c35af51c4572c8e395b7856697bfe" + + "dfc4145ab4ed0bdbe43ba509c06a196ae6bf30d7582550cb546c63b51833" + + "cb0dfff7196d83f6a1c6d6d712cce2ec1989fd9ff5a0a22ac5022b49d566" + + "58f196703e4809e7624fe7cfa6c13b378f5aac7e66e657ed7eaa942d1a00" + + "544a947199f24d736b8976ec2cfb563433c49ba131bd08b63636854219d4" + + "c45100c98e3092773ef492dd9210bfd8f54cfe2cddafcf5c05468d90e620" + + "0c2ef99d17fa6992cc45eff3072b7cfd51cabb07ea3019582c245b3ff758" + + "0302e88edc2c13fc43646ba34de37338568baa66ecff3accfebad88d143a" + + "fd1c3b09ae39c501e3f116af33b0b720d6c2baf5acd7f31220788b2f9017" + + "3ed7a51f400054e174d3b692273fcab263eb87bc38b1f486e707d399fe8d" + + "5a3f0a7ed4f5e443d477d1ab30bc0b312b7d85754cb886e9", + }, + { + key: "f7e7affceb80a0127d9ce2f27693f447be80efc695d2e3ee9ca37c3f1b4120f4", + tag: "41c32ced08a16bb35ac8c23868f58ac9", + in: "5a3607fb98eaea52e4d642e98aa35719bfce5b7d7902950995f4a87c3dc6" + + "ad6238aadc71b7884318c2b93cd24139eed13d68773f901307a90189e272" + + "6471e4bf9e786b2e4cf144764f33c3ac3e66521f845f6f0688f09eaa227f" + + "e71033b0f74295f6ddb91fe741323f2b54f420cb9b774d4291b06219f1fb" + + "4410b55900425c5e6fcabec76a5c2424d637a1641db6f0f6cad564a36a91" + + "0f49894bfd598e91f38ceea65e8253c1284f210cf7b50a96e664e562f3cc" + + "01c4fc490fa6d4679fd63fbb3ed8995a8a05166b573e92d22ef4370c6aac" + + "74ae94c94177e5f71143c6f340efceefda679ae76f6ed7f26eaa4848a8de" + + "8c40894316efbb06400f9695b18ba279e8947c032a84a40ca647d9ace457" + + "6dd0082494d6bd7be4e7928e749c78110af8774a5d43e9c9479964e2fddc" + + "ee51146460eac734311225d08c60706e40f298a7cb97f369ef599be097ac" + + "3bf1c275497bbd68968a235fdf8a61bc7cfeef0fe451bb04e662ca39f34e" + + "a8e3acdd0befe9762f9eeb275c0cdd43c80fc91131d1e0e790020975ab65" + + "afbea81f303ebd86760821efb4cad7cc01fd6d6fd194ac5ffe7703d890d0" + + "169e21b444cdbaf691fc741a5d99bd47357c37785755fa72582ca4754a03" + + "b4def86ded39aa6d9eb3f38801077e6d17e3cee3fb57ae83f30c79c3cf29" + + "0e2739c6b7323612cec3a561ebeadb4faa642f150323aaa9d270658c907c" + + "4c1610a5e1834730c08be3379cf1abc50c30e2bf01ce903927c27d85e135" + + "3db9e216dda8860c45925e2bb791abe5c8281ee6d16607bdca87f60662dc" + + "bd6e20224e7f009a86db66fadd8e37e0a59559328385090c6953cd20bb61" + + "f28a734fb056714f5159977f18e5c5f11de75f7a00ba807e47a29e4da32d" + + "5c67ec76ce4d7b669b5e6ee17e1df7c673dd8a7c87fce665cda8adb9547d" + + "1dccbdbe7be44846b4b121b0bfa65e4ed530789510d79bc4477e50178060" + + "f2668ac8956f39ef422ecb0e4cf90b8ce508552eedeeefa6c7d1bccc077e" + + "8088bd7e0e6aaf0bda9f11c412c270ee2ad6912f9808f9344a4bb137bdac" + + "b5b9372b00b0de026a8f5d1fb13972e1290b5005689f7636c43aee2fd443" + + "93d390371ae573f0e064b2d7df552b9adf04bf173d71c621795b9fb503dc" + + "5e918536c6ad25ce4a76f70e6b752b6d44be321187269a19bcf33ec899ca" + + "40e88b4eb23217095a85057bf95d8a54812cae4a7d32e0c2966a21376110" + + "74c6c8c3dd45a553c43c675d23308709f91be0b235d0222aa5e1e1ce08f9" + + "c6b45ceb5b47bcd7d7b2d4380bcdbd6eced452d93e6d8cbe18123277889c" + + "7f86b15fb991364a501fbf5d8244f2e3332ea0ab49e833c6f765017a4006" + + "cc7cd1a0365945a8d8873cb21832b210c83e451c01ac949de2fb0f7a420e" + + "405bf64eb251c6f022181595d68174b91e503187d3b3f49b60c23e44ea40" + + "ca20311305b413047bb22e89672758b74d6bd1a06decf09e9556421087a4" + + "0c1d2c44c5fb13d4d9625581ac4ccef1a1b5eeb5689aac5c0291aebda276" + + "50daf9d4396a64d02c6d58bcbd609d9a0017880ae0cbaf02ad0f1fc8d1b3" + + "ec987ffe13102d77352690c9b761bf13ea0b3a8ebad4a0823817fcaab4d0" + + "9b0bf03486620761dc77a6ba007ba07153b17425c4026597473e78863cbf" + + "430c0e5e9b04a83ad11506b61b8d9be3aeb06b5114e0d53d4724863eba12" + + "4f3b974bdb0d02743520409910621cd730c97ca984fe2921c38055f83ee8" + + "c4611db92e52d8ea51d89203e89df7586c574df15f3a96ed5a10bf04cb27" + + "f9656b5b11cf35fd21360b029ab26e9a741c6b3e6357aa1a41de2cac6e85" + + "f9a49e3441e60a60e74f434e1b8cd4454b11962e5507ebf904e9d6c52a7d" + + "9722300517c434758fbd6191f4550108b143eb16c0b60094fdc29327492c" + + "18a3f36737e506fda2ae48cd48691533f525acfffb619d356bf8347a8bbb" + + "4babdc2ac866e497f192e65a694d620687cfb4f631fbd6ae5d20ac2e3a12" + + "4d85f9391a240b616d829ac2adceedf8f3451ee77e4835639b13c622ef8c" + + "48a181fc7598eacb419fa438d4046aa971942c86b36eb8e16eab67105783" + + "d27fc56f5b66f35451b2a407d4648a87ae70807e45bccf14983b3abcb198" + + "d661d562dfcb00ffc569ca967171746e4e36f839946bc7d2ea9a0eda85b5" + + "a5594f6a9c1b179f7230eaa7797a6aaf8628d67fd538050cf47aa654778c" + + "11dbdc149458c1ec2233c7ca5cb172356424eb79479b6a3eed1deb9f3278" + + "5282a1034ba165032b0d30733912e7cd775cdb7e0f2616b05d521dc407a2" + + "ae7dfcf46fbae30547b56f14dbb0ead11b3666666c45d345cd5dbfa200ae" + + "24d5d0b747cdc29dfe7d9029a3e8c94d205c0b78b56d5e18613b3169bd44" + + "1b3c31513528fe102f9bac588c400f29c515d59bbcb0725a62c2e5bfb32b" + + "5cf291d737e67f923080f52d8a79f2324e45a3bd051bd51bac2816c501af" + + "873b27f253ef9b92ba4d7a422e2fb26a35c1e99eca605acc10d2a60369d0" + + "1f52bca5850299a522b3aa126f470675fa2ec84793a31e9ac0d11beab08e" + + "2c66d989a1e1b89db8d11439ad0d0e79617eafe0160e88384f936c15eb15" + + "ece4ff00e1ba80b0f9fb7a7d6138bdf0bf48d5d2ad494deae0ccf448c4bd" + + "60f0788d3f2b76de8ad1456f7572bd0ffd27bc2836d704d95e9c0df34571" + + "9dab267dd805577fafda03b834dd225ad9714d2bd182b4103faa5975180f" + + "90d5d6cac1825a19b9d4c87cc825512ae9dbeb33d2759c990905050f960c" + + "db3eb364c15b593524c882902b2a1d7fe40ea3f54fb0202fd8821463c7e3" + + "4b02a1209ba0048a9805f0468a13e03d18009318ecd92042959be263a51a" + + "407f1e660632c4247419659a4e073a8e9cd4a226763a7daea464d5427270" + + "7efd053cb4efc0504602c4f63e7d247b55db2ce1c07138f585d16cec97a3" + + "0731d5aec2166cb4de41695feb76280cbae1af8a2e67c2d5a3ac5487ffe8" + + "640f308ace6137e83576b79d586b663122221c20aba7a6bf60f73958f436" + + "59f087f850ba6e2d7fd862249c5fa6b20e3e43d4f2aa10d4c9cebfcbdf02" + + "6b8d103e4f89b93dd8af172f421001c8b162bd6d0b847a58ac108b6d6cc4" + + "9c7a9ba069deee", + }, + { + key: "e3d21f9674f72ae65661aebe726a8a6496dd3cc4b3319f797e75ccbc98125caa", + tag: "3c95668130de728d24f7bca0c91588bc", + in: "baaea2b4b4cbe9dbc4fa193c376271f40a9e216836dc35ac8012476e9abd" + + "43dac6b9ce67dc6815904e6c84a5730cea0f9b4c6900a04ae2f7344fd846" + + "58a99513ffb268c6899dfe98d605c11e7dc77de77b0d30986f3051754503" + + "7c26be7b719aa9ca1140cfdf4c586b7fe726a8bc403249396a11cfee0a6a" + + "f6c5e72259785cfd13c2897384fe527100170001ea19106aed38f7d5d9a7" + + "ad43f0b41451e19989192a46b4f9734a774b6304cb74feb7d83822044a24" + + "2e51d55c0b8318e0439493bd1a57cc13f6079166cabc46877d003dcd39b2" + + "c0b90f6b32fc77acf04a6c125e11b35d91e2b18401cd53df4aff804e3c67" + + "a8bb3894b27c6e9b0070b53a85aafab0c0a253f9cfd4d3cd3be52428385b" + + "24a3f9f71660ca2c38474d14a0309e2f400e2c21af6e379099283ff241d7" + + "51da5a96a8dcbfdc43b913b29cc8cf8020eebb4a67f5bed31f2e383f8656" + + "8c815ff172382b425e95902e80f5fc219eccb51b656d37b56660f749e5b1" + + "4976a23648680a472d02ba71476e0afb29a0e084984f4eac3befbf8dd802" + + "2b7dca4dadd18bbe58e49c49ce48a06a71557a9a620c51e2623f818e4d62" + + "c2564c7ba04595cc109685869b183faeff2ac7a65049fc57cb10fb01951e" + + "a525332782d691f9759ec2ecd68bebb9c7aece5d522a08ce7830be520db4" + + "c9d60a2e490eaa0c91e37b256a97f84b39fe3c77953748c3b86fd84e9547" + + "a298c049cb28b8c85d59548b8dce635d59487c9de615802d16a8adc4c0e7" + + "80f35b9f10588a431b39b499dca929ab9d225f26e5721820627fe62427fe" + + "06d5773a50878b6effe840dc55bd3ea0c35168f6b6a972d57e8f88c5993d" + + "1ae33e0b7e9459c123753b518c184de7aaf429df078c9a18a29af77c727b" + + "796f5c1a501fa8105ee873c4e78c907142eb19690638a182fddb413adb06" + + "d66db19c7f6f46dac582bd72a6347b4427a576eb769d233febaf7be8f768" + + "337273c12253924f15653f9f3602b783703a81454a1dd7a8772a9ab1eeb8" + + "51be33e0c6c0708f3cc2012cabe8e2f0c38e35372abe27bc148fc4e1054d" + + "9d151f80aec0232a3a92dd77928a3678ebd7d09ba7b4e1d83227257292c0" + + "b8bc4a76de36bff6c9deb383029afaf4f37d5b935dc080a18665545e4acc" + + "195da0b9545d8902408886204b64f8548b32d012e0cdc520c17d9fb3be97" + + "800c2e2b945cb09a75a0a49e5d4d81c4194d91e839333b2b9b9e34d588e4" + + "e20cc1e911ca0a1429fa70ff063f0090fd842f89dfc5cc44affcce4e1e1b" + + "8b11c612f66b074c03ac2a055fd8f51ac9ed4f2e624589ff5730721d077a" + + "fb4c19e43abf8cf3ffa698362be8be51e92c2c91a4a56be64d9ac6d3fbaf" + + "5536a24c7fd0adaf74ca84c508e5e8c8bf7d4254e0c44158bd26acdf3f64" + + "e78438b3aaff89ac9986cef1e3a88d5bf2016340367a1cacd01ec167ec6d" + + "185d93a2a220d718b43ce1d429d2cb598605660b030e51e8d75fdbdd5b8f" + + "8677675e196a40a88285b18b24c5d2d594bab3d457e6f9e503e38cd470a6" + + "9ff8037c9a0a0f110a434335d954fa856a3721e0edcfb14287c3dd9639ba" + + "4db32b7da0670dd0a872e468e3819741d0d4ecf0a4f7a011bbae1493c01e" + + "642757491189f8664be3ec6437c4f3c76abfb0276e44a4d28871d3487c2c" + + "ce2f230452cb06184bb8620919659a7ba0a3d5c12ec25678b03403715ee4" + + "acb6a53d281036d8f3a085143cf5ecc3a0c6c92129caa7ac1f645c7bb95e" + + "4f63da38dc319e2ccff4a9006f9b9b1a38c4c39f6dc686bb82d43fb9fce4" + + "0c767d3ff22f52c5f9900130c65bb6a9cc7408a777d49b70946665f4a733" + + "5099376b276a43dc9a6382bb2d40425f6481b1846148434c672b84dd7a20" + + "33deb5140d43ba39e04ffe83659b6deb48629e1abf51e68748deffb756a3" + + "ed9e0807506b248a024cd509f539f4161366547c62c72933584e851599b6" + + "82ec16f1d79e9c6a01cff6f51ba7f46b67cdca09f3ab8496322b990a6116" + + "8d7574854a1cb1cb8f30a303dbd13a095df56dbb940dd16ce79879cd2d73" + + "80a419842fa1b34da668286de4c1ff5917b7aaa64713c349dc8f855d04ae" + + "de9a3a4d0739dfc36510b1e7bb1695418164285c44631b4b1a7c5798ecb2" + + "d976c1a3679a827bf0e8c662567e402bcc1354222036ad5959a6f0b8508c" + + "6a8c7d4a63e7dde154d778fc80a011592771d55801c7e1297b00b77f80d6" + + "314ebd1f5b3057398d1943599897cfabb65e7568d8fbdfcbecfd4b8a83ca" + + "0a7bed08ab9a656424831e0d7718c15727af7c83b2ef5eb5684aa044eca2" + + "ba896811246766248b20a325094a4b4159f9cde1ee349be6dc3c9a190453" + + "0349212a9537f65ae333c288753cd2bef6c5beb2f4164168d965a2c0fb9c" + + "c8c73d9e776e23d53ddcfb83bb7dfe2a1b8c781280f449d6f310faf8b53e" + + "89e6a611d6d3f42f2aaed5259730d149b3e7dabdc9f865bc1555374738c8" + + "456abe112e9628fb31efc2ecdc972da05987aafce728ccaed246cfcdf518" + + "3fe5dae528bbfb99d33194167e0f84d462d3d0da83e92227cf57922c7956" + + "4fe44648d87c69ad708e797972c44c4a5183fd5d1150a1182e3d39c3cd16" + + "3920f1d7ed83992bc4116d9351ae1c6c4827d1374242e374310409f32d5f" + + "0f38c78b6489c568b791c70394d29ea2516dcb10e51bdad862ce3339d5e6" + + "14fe14f150961809c36e0a2c8eb872e9f7a1c0956fbc9194cb63ff9993e5" + + "d0dcf62c0f49e81dbe99f3656c4dea57b766ae9a11254f9970618f1b33c8" + + "f339f440de240170f7a21f03ff2da42102b323ce2b9b7d0de5aae324d1ba" + + "c87b1e4c5279a566bf659778f8b03882aded57377a0f1b063af2897060e4" + + "23be7cefd4aa9a28479c16773944d254fc21d3e1acdf508b7972372b5991" + + "3b8b088e93471a7d54c6ae4c52ba465ef07f19f269677fc2f64d3fb3d7f1" + + "9069d6c7001d4b002ed6683c59bd5651a450503b68a4a00820b8c17e3263" + + "18f32c21dfbcb2a02a104edaeff67ec09533aaf3d1a7fb41aa5d506ccdbb" + + "e6e35fa0a263c0aad3acc91182addf8c5bdfbd0626702694b8d652a63c65" + + "8d6b2b7c75d015630de508195e1fca9573b61bc549ca017c4bd888194d44" + + "3e031f36170215a301f922736a819f3ffda69117170d1933300366c5f2ae" + + "1052446ef7c3b82c5868be158a881597132f51c91c80c24ebf621393dc45" + + "05fe057364a76ae67494a8a5f67acb551cfe89f447df272ed9c1509fc330" + + "2c3e16541452d4d68438f26858724012ad3b72c094b9f166c6bedb8336a3" + + "41e032988f39cf53535789b320b5424d07b6bf5f8792e3aceb0e868765b8" + + "611d7905089949e0c273e2410c72a146cd63981f420405bd883e5390e985" + + "8214a8db714e8400a21d0636d7e5d9671a3582ab9ff032170b8dd6b9d5a2" + + "144d065228fa54aea9a22654df67f3f62c5fc59d68914d8b219829b536cd" + + "2ae937ecccdb6031d94cb3", + }, + { + key: "84373472e362a356bd5c9b50f55c588d067b939009944f02564f136c62dac36b", + tag: "12dd5297cfcec53deae1dd5f9325d894", + in: "860d9b2954c3daf18fd67eb8bd9e6e3de2e4988ad9b04b1987219204dee2" + + "388db1c59a935de27bce29e7cd3ebdf038785efb35eabd4c3785a62b1d9c" + + "3ffa25e2273cfe5eb10b4ec6152cd8f21dea415421b452efc7cc4ea6bf1a" + + "b85fa6614e7f6d650125424865386ff8ab53247a63ff023b2d0753a9e5bd" + + "458d6ab0156fd3cf2d5002f902f927a847e8c4a8426b0a5191f5e237d590" + + "2659ce9be9024750d1d618a6b8dd57efb6c2bbac2930858f1132639391aa" + + "9e8a620a2a7d64bb7e943c77753401b5b619d95ef857df25a52b4eb97372" + + "a05416706b2644e2687bf1d42c0cf06e5eef8a1fc7e178440bfebb85c44a" + + "4837f69e43a1789728a999c5e04291576e757510f22bca11583a4e93688b" + + "442f2b2dab8d5ea9441ff09b8287862ca538ad979297cc75510a3d9ef36a" + + "662b4b7c373f184202befa5bf3f315642e6210763d033b7e2c59731cb356" + + "045e9470bf2f83cd62f11b3e904b0c0b1be99bcb805150ba7ef12b8df3ca" + + "bfc5055640687d710ab88e0fa8034b26112ebfd044a4b290b1c6f6d18c31" + + "ba9880b1cf2d81b5d02f00d6d351da5dbf47b6a5cb7b53eaf6de52c8a68d" + + "053602ccffa37ccb44a7683ab4f8a58c4bbc9e140e4e6f3cc10a5c07ebd6" + + "070818db983f9f415168606011efab6b8d7b4e61e8eadd8bfd8d028b89bf" + + "b0a16996252d7b4ee4f9ab50fc9d6e482ecf99beeabc38d70efbb9a0d4b7" + + "9a1c5d2835adf8e25111352eabd24d562644efc97637f695e4792f2049c6" + + "00f4d889ceb951cfe289adf159865d013046985d7fe2598014bf2dbbc528" + + "b4166fc2180e724ded8e7ea1c8d66338ec50d955d5594a0a7b4655338b70" + + "e8978485a722df814fdc6fd2436dbc060121fcb575672b2a5e454c1209bc" + + "2bb21a99d39dcb3c697306dbc2104d60fd8051c43ea2fce268987d0ec249" + + "a5c02f91d3b0dfee181b3cf8ef1ba9665daf7ea1f1d3b216e378943b78b6" + + "bb41e5dba095748bc776f8df6383033a1f5504955da3f42153b1c7ea83e2" + + "f90b990ea0c5bd3906b5c4060b19f447ec7762916b8766e5a23bc4d39cdf" + + "8e27752df8129b60ccee1731e47383b589d4fcad865eed4041a186df206e" + + "9fb69ab6ea092e36f186a6fea8d77bd7f3ab0fa0e29404d617317c75c832" + + "854427848237cfc18486c95f7213b9d53f324da036e8d298133b5003984a" + + "b9d71836f9f1b059db90005a9067c261bd85aaeed4d623df2220eb52b73d" + + "d683abcdee5cebd411996f853752f638bd28df6d78bec2ed3e00d7beea06" + + "2b81c19682ffb2f6abe3a3623a2e0570650c1384f1818d76fbefe3a7ef3f" + + "46138160ef897f9934e00e066e215230e719c23905dc60d7fa4d666fa52f" + + "e7737db15126d3262c3a4c385cdb23ff3b56c131e43b241f4a6062a1a248" + + "de9f13eb82c11f7b6a22c28904a1eb6513cdb11179067b13c7b5f83a58c1" + + "4f2753f19fdb356f124f52923249d6e4a2c8dadc8bb0fc91e360155a14c5" + + "c194334b9f0a566d51fad98592b59c1cc4b40eeddb34e64f337f83874884" + + "0583f853398c343dabc29b9444be1e316309fb8d81304d654b3d4bc4cff3" + + "55fc31278fe22e649324ef10acd247c0b72397edf96a1c16bbbef0640296" + + "4d219575fd23c36efc1fb8f8a34b510ba9bdfb3b478e236777ef7c6c47f5" + + "5a2bd0383d8eed3759456ffcffb15e61985b08c022658a5ffc875821bdf8" + + "83f69f096dcc72a96888c3af76db57a54be701759670bf05cc9015f5bf1a" + + "745cf755a25b1403a870875701427f820c4b29eccc260f30113629ba03e2" + + "785014bdcbf34d0c67aa6aca20d2dece811788686d5a45820d2980bf7d69" + + "d5c820a09bad7bd95166f63dcfbe8652565c285e60e2704955d69b3037d8" + + "7f5e6567d95b8891276d5cf7c59047d10a02ae4a28794405e2524ec2d595" + + "1b36ad1b9d5265fa098a033b88aa66cd9eaf01eea49c7dc4cc51c486f624" + + "507a2be23f152f43709b2cfecee44945ca506950e90e70164b77e12e1c13" + + "0b4d1021c2afa20038f190096276cd22e89b6e7dd10fd58fa033c9d42536" + + "98de3f4908203be8dbf259112f840c76726d982b4a837cae7139e27182b6" + + "1b4dfbcc50e42d5ab8532edfbd30f668879824e9ebc34b63ff1526cda81a" + + "e38352a774d79f73219500e57f0159a32326195d8895d965071834876a45" + + "c1a3c0bc4b1638535f7d40011cd5b23343fc27fa318c1aa3f9d8c43351c6" + + "6148dc2175e0e620813266da3000954dfa22048f305244629d512e852376" + + "6248a897a3ec3e2983aaa8a0f025f18feea57a5153a59b02604ebfcc7a9f" + + "b03e62443df88ead9dee955e23bcf6528c278a353f254c9484a67a7b263d" + + "a301923a4efb6866aeaaafd428e6da48781365bc49e90cd16b2388220d08" + + "bb9f79d14012b5a8299a651917b6a829488753b6ca449a14e8dd8c5fd5ef" + + "657d627b8e7773475b802655dc033694f24376e3b01e519d1aa8365d0e55" + + "92d0a4adbf555639b6d75d7ee59a7d12c6c11317b7927f11bbe75ed90508" + + "b0698420e231206704d22dd1f1740edbdcaf19a47d66ace4eecbcefb77b0" + + "85cfcfaced4d2d6048ce76434eb79990f0898adb4af2c377b581ebab3f3a" + + "150f40dcae002d4caa60050591c0de4ba83bfd59a08670beaa4641aa9829" + + "bdbb720d6eb8b2f3e864a98676a67271a82cffdca2b3590a0b5f97efa5d4" + + "ba062b4798707159782bedc75e5363d5f5d55ec2bef70db22955adf401fa" + + "c3b7af937816eb25d54d9f2a92e5a2a04bd8b8d7568204fd289f5ed2e033" + + "a76209d288e11e8a4dbb06b9029e90cb186446746853f02d738e06bba538" + + "894e03e2658ab3d7f9ac861d2cffdf12396004d1cd15f18812d3803ab9e0" + + "6f41c9b374d6a0678bb82ce06d9e3b9dbc8d2e90b8f64d0d040f3fa8a3fa" + + "8be71d2b3183cceae1bcbfa2353689d842f7d7052e5699dcc70ab2b58761" + + "7041e5aa1e2f41911d525505f061d3ca45152f5a7a1fab50c674e4597a52" + + "b46aafb4ba57413879cad1308321843abb7c39696fc2f2e225878bb1191e" + + "e151cc76f1a1b8d491c1672fecbf710db82dcd32554361967fc839c8e5d4" + + "e488856e1b9382eb3fc3bdc3b6886a3cd79761b02bafa080a745ef6afa26" + + "822f1d10d5e8eefb842837d82c9986e78fc3390caa142b7643de8f613e5a" + + "890a57f5883409549537f8139534f4ca1b60f33e42be25433f1d82add530" + + "6a4cfce258c0d4f1f3c9148ffb5c4b626d51f78ac20bff0393b7fdb4b9cd" + + "70fee7f69892c8a9ee089c6c5c7bee0a1b825e5b9517f2c82d6c149735fe" + + "45a8839812c2deb2a355b6230697053092eca450b7b0d3242b2689efe364" + + "09e820d91fa4932034d96495d9dd3baa4b385da815a7cb69438ff648b326" + + "e7efe8d688e88570ba59df7c439faf72c95317a10c984c5ec0043407e9fc" + + "9b46487810eac19d2bb40e0a654935f76e7d8861480c5f48419eb33084d4" + + "0e1070e5ad542c94f58b49e67dd05b6637a2c67d41451b7e00ba30eff221" + + "755d6d427ec634a2b95980d274a89579feccf1c7df3787a9435e588f2496" + + "06a93b7ac41c8aaa84b91c95cad9463d4881de7353d95b13bbde4c9da90b" + + "f1fe96257309a416407c64368b5564f022c4a493f2a39df1696f45801e42" + + "a5", + }, + { + key: "2d0035a30d19b9cbc7a27561f3ab474c01115c4499b4adec660ea06ebaa1a14c", + tag: "a2c77b55cb0c076d8ea83cfe0e64f293", + in: "4e667580ba4f38f64e5cb5566bffb486dcae10cd17acb3754251e837767f" + + "16429bba2b832f29ba538f97f3556548d163be25e69f88fff0743150623b" + + "e0a1d82af9384ca335927a0e9cacc3dadbdf1e24fa5c81f2602d109e1400" + + "33929e409b9a0fa4f2653944edcb8b3ef963ba7f8806196c73bff0ded670" + + "c6def5d240c5f3daa121f8d5bec9b2a0b0f1d62d54b013dc742d6bd46325" + + "460f692b76d4991f0796820ddebf150c7d33829795784dd2759b334d2706" + + "70a7264941be5d99d460d078a9eedc3660cb3176ad302f9365f0bd698e46" + + "9f3e63511abc81109995dba17be1abe8bcd28407c7fc8d02c14794bb033e" + + "178a94f6dc73719d5bc235f980a16eccb4121ca83b13c4e165931ae4f192" + + "4292f8cfdf1c3ed40feb71e13d919b48fa296dddb4d23114a3d86ec10f16" + + "f314de4cef813ed24b49f4c7bc44cb8424df1f70e8d77366161c7cdd709e" + + "97610aca3a24fb2202ffe15eaaa25d711cb5179212a2c6497a13e5d7c365" + + "7bc502b3d2ebde2e57b714dd9bc21e73795f3d35d620613918c4c9aa0e89" + + "031481c97a5a4c15ec6abe42d40498c33d71c823bf1d5bb5fee457e2fff0" + + "bf777c80c6e3336ab3ce793440e74b336a8f7034f6ea2e4ff5ea4ea7c350" + + "65cf2ccd2da1d6df29bde10f4cc0202b5e4cf7ed097da49b970a6db41e5e" + + "98f3845b42f46663b1d1ff01da71389a8737ba8f51eac1ef357ba5ac9a80" + + "dd2c7f9476111dcd651fc33f4c86dc8658656f3f02a8878bc38ff0d0a1af" + + "2e31fb92eaef08c50195490818661feaf90e8b6f5daa1ebedb2cdbc8d5dc" + + "16db3505f9611ac46bc37931e02c1fd6aad6e4b7e187d5e6f990fddc9563" + + "2b33f55bf68b0db3890b11113ecc839a4fa4de25160e574289aabe4d8fb7" + + "9cecf9d2fa75ac8d0195beefbdfe0815f8d7d9751c1280a29b547149ec7c" + + "2295f5afa53cfb516158086bf203357eec2a5db71143f996c81555a47f92" + + "209719a71570a5553f1ff9b4b41827dd74657b463f36623565f0c9f4d2ee" + + "8735d6af56ceb3b3d0ec516b22f0ddafbc24647481f61ab169e2616c91c0" + + "e1f6a35436598ed801670e1dba76226cbd0544959ebe70f836c8a7df575c" + + "b907d780ed5aa0d6e4e8e0d2f457efe89a777374aa49d4961db96dbb787f" + + "021d99231001360d532a70ee1fb94bd6f26524dd4b7556c6d40e08723d7f" + + "9905aca66c4743f2bf8b34493bdabcfca617809a867bfe0a4f94c756a6a3" + + "dcd04ffc0a3ac671a0afefe0d5d447efcec48c6368998760db6a572676d4" + + "29b6d3d6e0c815650447748c4b27541c5447acfb8f7261b6378f3fc0fdd7" + + "375eb9d458648c7fe9cd96344f11aca912cc5098e9ee39e0b6794cc1dc2d" + + "f1b10f927102705efa20e667b63a91f935c17764650b287f5289d5790766" + + "555f31985c5aad94c652ba41fa9c0195d15405f1fcce9e23054a42c8a252" + + "da83bf6268782ba44edec5d8f94a20b1830cd1c5894cc6b9b52ad0b12a5e" + + "cf3195a32a0b02483ae3b954ac6f3af1e0f334221279d03a72138f3a2cb2" + + "1e706427c4d604674dab88d429f28a67be7a996126e077a1dcf8989d90d0" + + "8b08f4abb9a546b3c64ecaa287bf3468c59add86365b885f52afe13ed8d2" + + "69ea61832a7ecbb96ff3336f58a1eeaa6dde3611f3ff7c2cc8c9b745b0e8" + + "b5919914245a49ac192cd77d10deb9a249623f696065a532c20eef9e9b0f" + + "e706579566a9eeb14d4e8251a7750e29eaa60f034c1a7a1d51aa03a45fff" + + "89acf41080deec5506128b06f003fa46bc4021a82fad6a8052a49744ed69" + + "45bd9331b5ae80d873cd042bff079b2b9d8af8065a22c449c32a56dbbe7a" + + "80d0f3e30b9167532506915883dce0aa9cb749e4368c595c5bd33b57e36d" + + "98cc9bf91cbfa47331d69b5cbe9c92bc66c0fc9ca8717bfc108e1f710333" + + "14dba02a28b9aa05890cb01ae9175806c3c4215bd446f6cc96ec5d08982b" + + "4f83cd1646160e1d306b3cdec02d251f0901b03e8c3c35464eaa5082586b" + + "b55482db97599d513ed8d7a82e32fae302684b7ede058474c1fac7893444" + + "16fec93fb982accd162dd956ba2f31a894e9366eca00e6e997fbbf9a2980" + + "8b83a139f6432147a717381bb8baa2205715f735c1e0db273cdda6897c9f" + + "39bf0d7eb7caf93f657ef4d3fecea28baf69cf36d3cf347081df3114455e" + + "b4fe3e49ad3c3f14435e0b39b6c0d16db0fbcfd7ba8da8760d5952c03667" + + "251e7a4c3008cfb0904225e55c23b884bb09d26631650460c4240bd5a165" + + "b531ee76ba5749b3bc60adad35de519321c1672b47bc35fb59f7792a3495" + + "11b2bb3504ba4a28717823a27a1f99ce6970290b26efcf1e7a0399b10eb1" + + "0c1299c09b80f4520d00e7908d004d5b6a72a411759cfa9523f6b2912234" + + "481b1d8fe4c2365961c0528bd593d42bebb398b5836ae6ca013fe440adbb" + + "0090e8ea274f4d8bcae483e3663051a328f7c12870b40e4973a9797a2336" + + "3d3c53e1b0d1a9159bfb26158f44734b3c34b571be641bba2db937d4ae1e" + + "edc807b95b1c2a7d44804885536316ad38aedf0d83b1519661f2bb5283cb" + + "9c50dd61c3753433e988189f26962d1f4befd444257d0b6d5b819d5fd572" + + "22c9fdff032e07a4d8686d451e71de4748965309c0a2d7c422ab7cf3d96a" + + "8c0a1b0afb229debd1c9421cb828b9f2be96bb9d6b5be7ef8134bd9ccf81" + + "51620937d720d83dbdddbfaba8ecd2eab6f1974090efde0ca963e9fdd691" + + "ed0cc5e074c5780779222552fa46ddcd951763a32aa3a044ff4a73cbab41" + + "dabb3c2c03fcda68303477f0dc26f35bdb5c9bde721fba1a2db732a89629" + + "a8de3cfebc3918df1a9d5053d09da5b7316e3285bf62156ca28cb64d343e" + + "72445fd66757bf4ab374fe7932a65f3d7fb6e42cb12e5b67ddf8530383a4" + + "6c1ee7ec8883e454a467df1aa7e468a6e7035515f473901efca5d46ff358" + + "70e0cc2575bbd7f8866c8e73cb157903a1694ff3051424f28de826984dcd" + + "065dc3658df144ae3a6d37b88c367e3cf7c58169dfdedda4a2821ce22188" + + "40472ff72f0dd1a6b0100555ff188b80f835259a634405e3dad61fc299f9" + + "307e27503b2cb7714bf3b636cc64b61d2e374119c8ef8adb21f1516c7fe2" + + "38c807818065bf312003c12e02525d69d9629a99e4ac66ad2e792f302cd2" + + "a6f5f702dd28040738a084a7052f2c3ed0924c33b7a5d357b7c9a29cebd8" + + "621a4bfb7bb34676ff210d59f7f9d4eafb7c5c490c9ea48402af5bb072c4" + + "731bdebcbed4e8e08a67931b6d7342d4ef7bc4a75ca1dfbd32ed6027d8fc" + + "b71e3f55565c02e06daa8c579b69774889181291c470576a99e11f2c5acf" + + "77e091ef65ed243d4287176f7f6ac7aba6908c9ff1fa43b894a499b642ad" + + "c01b2fa1c4b58801411941bb448f1f7a04794d2cfe5db1be61f7b86d6eca" + + "c547ee51d4c9050f9e9f318dae958c150acc21c878f0c7df6065294eb1d9" + + "a278c920838a0db752b080a32e67ac312fa76b589a385f31847196076ed8" + + "1021fcc375bfcc8e1361878e2693860eb21ff0595e4eaaf7897f2b79367f" + + "7c4f711279bf0c93a97dcb1cd8d87e444ad5f4cb5c1de44e37868c6743f1" + + "cd72cec376726f26c8bd4836f9a9f9c68042f95ca6f9d7cde493e531c553" + + "8bf7ace6dd768db69ac7b41ce93e8ca27ff20a83ff2148ec5b89e05d8b8f" + + "5d78d0fe16b96f6eb8d3b20126a186085c6825df81aa16b3dbf57eabc360" + + "71299ccdda60e250c652408d9cd1da94d73c728440ae08fddb901aec0fac" + + "1050a778b10f94f84883bee158bc53b1c001807c43a3151fbf581b18dda2" + + "527430872834e5c380575c54b7aa50f817cf3249fb943d46933cad32092e" + + "bfc575bd31cc744b7405580a5f2eabe27a02eec31e0d7306750adbbb9f08" + + "c78cb2d4c738b2274c7310cbf8dd0e59138b6a91b8253ae9512fe3d7367e" + + "a965ac44d54a7ed664e5e5c3c6c2d942eac388cd32beffb38f", + }, + { + key: "2f29d71d73f7af98f96b34e939e1a21e2789ec6271b878bbebd14d7942d30080", + tag: "ec02f4953a9a63ab6f2bfc3501e4fab8", + in: "0e0950987f3508239063e26a13727fefcdfd2cea6a903615c64bf12d9ed3" + + "887f9b2cf7ccaa196ccc7756b09471475b9daefd4261e69abd23b9faf9c5" + + "1fd5d5788bb39d3c068fa6807d30f6201d3f6dfd31715d08b1733440cde1" + + "049608d23c4e45c5ed61f863350232f85827e7c292dc5f1eced1cbc912e3" + + "f5c420bd945911d3881ede5153d3b2cc85371fff98d2caf97cad6ef59001" + + "4017f9690cab08989851c2647e77e81401714a93ed9f938b79f8f54e3133" + + "fc2cdef259df2ba0d48f37bf9e43792e3a777214cf4aab6dde6deeb543a8" + + "813b71b5974136c1220d6218a252881f0f5677ff5b6aba127f19a5f3c5aa" + + "c988543d7839a90a3f947c4e4d5c6ae1ab48dbd40456d1aa65339a4c15eb" + + "520e8ff9f965ac4c37735937cf09942e7958f8a6cddee41707423f715903" + + "ffe0d15af8c3140d3a736d23be7485fceb9f07c6509f2c506eda4ec9d30c" + + "cc133708f48d8828e332808c84a745d337296d871b9794de1c5d06534aaf" + + "65587526a84e2521f8b332645e0e72564bb308ecf99b7bc69608474389d1" + + "686ffab8c49b7f04dadc28d2ecdd0f508dad2135843304e378b3bc7a4f25" + + "7fa4316be956e0a021edb8045f39fa9f002087f067199bd6001acaadd261" + + "4bf6aefd3f098f92a959685f24bb2206c347359d9c6adc6847117bb434ac" + + "6c40ec618f6ae8b75a5e2e4d44c332b7b06c8b4d521493b9b0bde8894209" + + "717a24b320214297b62dec741cea018ea681c9b56702068528b3726953e8" + + "c5e4ccd5029e4183e772d9834a56a88d45bf87603dfda40e03f7e894766a" + + "7623ab4dcc0dfc3086d17566945069173935916f772e2a5f8e1547348f28" + + "782400fc069ac0e2b94242e9e0f1ba2d0e76898f9b986540e61ea64d7f69" + + "1006b86ce61565da75eb16a8b4c5865ca4eebdde2190e354734bda94fe7e" + + "12ff47dcb5d5e6ad93cfadcc491cb350b09ffe391a157e14b65e3a211b5d" + + "4e447c3ff95571dbab33a83126d68dfddf9383b4359d4103ca64af1e6963" + + "d09e17eb944aa71e76711dca33168586bfc44ebe9fdc55497d83f238c66d" + + "bcb16063bc85635f0f1a6280563bca49ef971db96a41b6ac5e0642643262" + + "61eb4662f3d6ad4cac826db895de22c9b8aa35e6464a7f44e1ae7238e355" + + "068d68754ffcca76c50b7ce7ef9bfebac9eeab32c87d059cc7ef2adb5d57" + + "c7419adb394eef48441952253e8391e555730e29789d6293c3696f441449" + + "0aebe2bbe541e191a6652ffbec1192f0f9395b7ea370aefc1f1cc8438035" + + "d7681f12f1e11d6e334da188b10c302fc0f4bcf1de448090510a8f1d5683" + + "0c943a3c388b33a038c26741a4cf3487313f755fe7a28e25e44b5383c5f4" + + "cd6ef34d7dd73462226281899dc3f2e69809a0150f694673f31addc89888" + + "072a7d4ecd63d6b90540f9522ec05829a7f17d48728345ad808fb0203883" + + "3cbd018d612992a88df944b8e34a70920b3f26cda2e8bb16c3aa38b12b33" + + "b395c9ba5e809f60ff05f087112151af1b5987403cff8bb2dce79093f431" + + "2c744f911a6f3091e4f9ef9375c4dce4c241d2f6024a1797321851ca316c" + + "4e460fc060e7839deaff8ab5e8bf682c0f21ab6952eb793cffe690db911f" + + "50b11f56ea352942c43bfff51d4360882754faeb7cf28b6b32bf7fc9ca71" + + "fbfe1d72be05b8bac9ba513d731e2c9d13d6f2f10eb926edaaf0e3996656" + + "da8718a8e103c59326529e91ebac6ed52657c9690ccbf81028cd9fb189ec" + + "4de94fc0771e53302c8d9082835a68780cccd772660a110a1b40c57bef3a" + + "c1d69428aea549ed17663a96895a66a3bb5ff6ff61dc64908df49b760caf" + + "a5aff05e2766a418dbaa1e7d189a9edd55a04fee8c9d6e506d299abc36a9" + + "d67be035fea5d220f41d081af67615fe627c4dd04bd8659c7fa4f57f35d0" + + "db40d9684aa178d7483ed5d86f04eaea412e0ea05a4698377dbff4fc3a39" + + "1f6ce0cb833d3118d6c69319b511cce65fdc74928e270da0c537f8201eff" + + "77416155d4a39c7ad38c22cdbf7d2b7ff7d85383c178a835ec604c3f9ee3" + + "7399f7dd826e34f1a35ab75da44ba56f86097ddc0f3658ef5bd65a24f4de" + + "4255d0b03411a9d7f0ddc29e33cb865da23393471aa94e6c9e72e789206d" + + "3ba118aecd39727068f528f01b25fae2280d70033e4ee46b41b864bb922e" + + "001d8bf46d6fbaa5a594e926f45eb3a4d2f074506d7834b606f43c89699a" + + "6db00b374658d9333700894d440a712a1f25f5538f9e7c8ee57ae7e612df" + + "13292c8ba9dbede4fb77cc6c8944aaef59ea6ad3b36db398f4bb0f82d40b" + + "44879835f224d6e05992b1b8a68dd58c3dbda2fd73786492ee48c7a25f87" + + "264b766930fe9427487504fad17f8d230934f044e49ba219f26ead728856" + + "cb30eecc33a3946d3b1b781061f2458c7c46f6d96f3e06f369f97be91835" + + "f23b38347d1e381ad5be4419275772c2abd549522a0203c1ee9c96faefe1" + + "df413c4b7b2624417890e0716854b7092b3b3b368cb674035d3e6bab2357" + + "e7c262b606f7141b6dad2f6145ebc1deb7597814719784f3c17848a90ffb" + + "cb0289e2f3cc7da12442b837c4e47f468bca3eb4e944a31c48562c2f144e" + + "9e920ab5e4cf90a14ccadbae29af13db38cda911e3c8f6f525e6722809b5" + + "31a4de1926ab12f643d25af87eb8610df59eded6ec278242247dc69a4213" + + "13f7c2b26ae7a917c1bdaf66c56876e9104d40b59e6ca1431ddb77fc89f3" + + "14b46a154cf127688564a4f9e120d7b5816cd24a6e095dc8ab8b43bc3639" + + "329719f0e0f723e2f5136d82638e2249e648ebca67cf0306741e9e8d45cb" + + "903bca85485c4007397c88a1ce07266f4f611b96b7e0ace3074247a7dfb1" + + "cdbbdd66e25e172fd2bda74abde7f3b4cb5cc7ee7859f053b2f04f9de03b" + + "a8e96264117f502087c3ddbee8d850bf3618b4de90f7b3e562dfa57e4426" + + "5357236e35e71d1669226d63bca50b1b944ac07a1f794e73e80985689b25" + + "f18fc709367d63b8639d71865cee667536040be827145c08cf3e57a66678" + + "4c81115706a146eccadc7aa1a9f074b47e95bcba7db8108a13279077bef2" + + "64699fb87e5abf5b05ff3879d7c7c5169c7cae817c13f0859d4e9c05db0f" + + "74c045ecc30a51e515feea627da387ff780719395b5b9ad93179b16fad10" + + "5856049169dcebd43a7f39c549762405f807378e854b1654a1179d895ef0" + + "85aafc72c7fe1e0e1cd3abf8e20935e331145bbcece4f17ad24ebb6c64ea" + + "73bd98a7494c134859206c9422f7c4a057db0ae0770c4bcb08c1a6b9ca4b" + + "7dd8c1cdb3e4977c7ce6c1e79b9d6ad98e27d2759b53cee73ec037a8b686" + + "f1ff78eb8421f41c74ce9c62a90d38b75159ec925f232e0db71362f31e29" + + "4336f5580a34b26c5a01ee3454cba227c7f400f6889a319d7121dcea27b9" + + "584f33ac796d48a9a24cc5b6799ee12f10725fbc10d7cf83e4b87d9c444b" + + "f43e2f5ee49d8f3b531ebb58fed4234cb8bcab1b8b18bf50956506baae8b" + + "c1b7492250f3adf64294310387f1d4bcac12652895d4f2dce26f380733ce" + + "0b5820e9fcd8512a1585a49940a32fc8875ac3c9542a4270602e5e97e720" + + "90ed71b51badb775340429fdbe45b887fb9ee61cf9e091c06092cf0a2129" + + "b26572574c46910cb458bca7c63eddd29d89753d57e568323e380065794d" + + "3fa1ffb874543f5b0ddc702b087e91e22604d9600d37fa0dd90d7acb2458" + + "4cd408a4e66bb781dde5f39efda6a8fc26be0d08ffdf851e422ab1500c28" + + "bf6b4c85bdfa94e8aef5cda22870c39ad49c3c6acdbb3b0d58cd05424c65" + + "20740b5c2bce4336545eda12716317df58e6fb764fcb3004f5248c5ccd84" + + "f63abdc0dd2a64e447c0de4da4a1082a729d8ebe14810d396933085cde18" + + "318278481fdb9a748b637cacb491f5234bfe16b53a35da6677336baeedb7" + + "4a28c19a412e7812dace251446d40ec07afd63854c3dffbd5c0f6a9a3cac" + + "ee3bab07fba94800fd1fa0fe44f5f2ecb2b4a188cd02b8a2df0728347c50" + + "7d0cc58fcd5d54dffdbda11dd1bcc59758396ed8db77498fbe13238d3d8a" + + "0040194dfe66811542ddaa658094a9580d4e4b4e29", + }, + { + key: "1285f117bd90b70ef078ae62f37d2218419e894b7d334759ddb2d88833b287b5", + tag: "429b2b39195a10357043c9601590a277", + in: "00ef065a1adb4ce7108b497813ccc748933fa8442689a7cb8dc7c1ffdbf6" + + "c09adfe05ca2cc5ec3acb7493f3497ee8f9cd9bb8a4b332c18e33f78114a" + + "c8f9a72ddb9f13494e934ad711818909831013ba195b53f5e9e5b4689399" + + "6d0b669f3860958a32b85a21009d47fddbc8697b7c9b92dc75d5060eb4fb" + + "40aed7a1dbe69dbbeb6296f5467ea2426cd17d323671fa408855bc53e5c2" + + "d111203ae38cecac7719c0bd7f21f6bd6a1588187b3b513983627b80ac0b" + + "300b7fa038af1cc8512403ac2cea6e406595202ec3e74014d94cf8780ed0" + + "33c570e887ca7fb35ee4768202aa52427d02c24e63f7f2cede95ca9909e9" + + "dfa86246a27db757750667c198c9aff4ce348f7ac51864b36ef5695df713" + + "d17b8f561a972d0136bd9ee9aa16079c2ab5d29ac9ab472255ade05dc49c" + + "b966e0c1c04258ef9ec59ded01f402d9fdcd9a2020a2038a8c78892ca218" + + "30136069485527069132959dab2b81c73ca590fde2a7ecff761d95a54d63" + + "a2664aa5a6deec163e46b5225bc98976a4f363063b0f42e29f792d138af8" + + "eae68d3854b5c1985d5cd1c9f49f529b0b4d2c936887b5b92cdebacef992" + + "c35e0b7bbd52114aff8c6b261852e28e451b02099814f809b0289cba0586" + + "04a363e3f969aad3d982f645ec4c549f943fb360fb8fa0d5a597bf89842f" + + "8ced6014a5b2590ef71524a7ad50fe0ef0e2f81b6e26b99f9ebbc8036549" + + "f7eacbf6ab884710c6406ff59788e03ede35c30d4781ad5af171e0623e8f" + + "cf5344d71165f0475e256e9159040f702b359a2963116ed135dd6c1d111d" + + "2a1e33e15c178ca4f02c5fb15593c50cf9a8a492f01e04778dbb81d26c99" + + "0c58cf50a9bcf4fe38fbfc0fc0685d8bd422a773c7bce649f7a86c59118e" + + "f5f857b2c72508cd1ef05e1a0c0b7ab4687fdd57437092eb49bf41a9ae8b" + + "bd98272ea2f8ee2515ff267fa6ae892c266a7effe61ed54984924aefc461" + + "6cf483dec024ad666bc797beaa429a742d1b8806f67d451b6d3a85b4d474" + + "003cfe9e9dd906df47da5559c41f15afabecc3e6af279cca0f2a200eb2e8" + + "31437e034d457fc880f60f5ae635690bce82bf6d1ad6b4f5344ec042bf25" + + "7d010273c861e3ac516e9ee2bab3a255f570baa32298467bf704bf6d9076" + + "a4c0b08a528a05cd1fcbdf51f3885fbaba7891a144fc058919903b269b4a" + + "29f43926eda32c38853b814a7d528156c223748d674d8f7f5448350f011b" + + "bfab1511001b8014e20fee37ccd4a0456f638c197c86dc116b34f955c0b7" + + "dee10bac5ea0c2fec8a780ac05098b51b902ca6afff4db3c6fb4f761df79" + + "b2039dc5f16d9402442a6fcf6c4297769e6c36824d908beba8e584ea0b3a" + + "91b9017baeefac651d0307bd89f517789236c0693c65a5a20f244d39684c" + + "eb810cd2ffd3c78fe9285d2eb9f55d133b86113efb8dffcbc6d258e84c38" + + "2dd8f4d7d63b65672516d9bfcc3310a79ce244b60d380128d529487f99b7" + + "d532d5f5c28fad8b9a071fd2fab8fd98f6d7ed9dadbd2fc4396476eba6e2" + + "1a1b1cc594a31fbd3418d98e4aa736cab285a2786fbbd4650e49f9b080ed" + + "3fda34941c28d25545395e1408fc3e60730d0696061f821a4d24123cadf2" + + "3af3d37ba7ce1ba3cde1368d468f136df82c02f9be9210022192aa02117a" + + "ef5ff70bcfeffd47bc37b920826a4d3db001f956939abc0df520f3ec1613" + + "ba1c4b3385cad97e42bfd15a3150711fe86ba4562f17780cee1cdf198615" + + "ca06270db84986f33e1d53d552b0da82397c496a23c7a78ca7641a908e71" + + "89249cc657c0431f1e09ae0213f28a27e6267e9d17b5bba0ea4f3c21f266" + + "fe538e215ec62f85517ae6bd87799ac5ce68453f09cbbc50d6e2a168f0cf" + + "7166ad50cb65b6c76406c326573c00e04a3186251c6181933828c58f4198" + + "f8208c4484805639b0d428fd05b57e4356239638f458a84000c7a7a8de62" + + "ec25b54d1e39d2579ec9c512fec475f243576f35efc02a1cd6b0478e2dc8" + + "be5f17aa4e3849cd42e76fbffe6e7d6f912d6edf80f718f94a7e48e1fc10" + + "6cac29627d9d4b82f05a30cd7c739f7f3ef7ea368d22612f189da450e274" + + "de7b61c6361521e684d639be5af4cb11fefa5fce6f8a5065c90873e504c1" + + "2c940571ea7bd7e9221129b83039d2edb069e8b5bb68567d8fcae34c6ee0" + + "cb94474d8b056cc3c7403873f2fe6db3b567a44e702e4f4813b2a264231b" + + "0a998207b41916715ef94e5eec281589d0a711f8e74be32bc60f43d693de" + + "77f21d5f7eef892abe87725f3d2b01d9ddb6dee15f40735a8fb67766dbcd" + + "020a93b8eef4361dc3a891d521551f65dbe6e3f68c60819b0a540b0991c6" + + "4449d207cf5b1c198c17ad6caf3adc628d09fa0baae7a696d84e1879577c" + + "ffe9b3f62669d4ea5ebab6364f08c66d170ee4a94d61fb77d60b33dd6b60" + + "650f034c5c9879243d5c16f853dd7a89885a9047a341b076912d47872b3b" + + "3de49edf7451b435698ac4e182d16c339be83e18531a34aebad36c5c7c93" + + "aaf121cf99ff92d3844d40740fe001eeca9ee71300d826bc3cfc87a29d39" + + "ea108a3cf259657ec4b967fbb534e7513ef3a96bffb35abc5ce0e890696e" + + "54fab515af3d2c0be6e003747504e486c0ec6e30fa4ca79d6596ae0425f3" + + "396e40fd37432e52c74f812250dad603b3502f97ada48a26e39fd4d44584" + + "6591bfa5ffb3770d95d3dbd49e9c3a38c6305796b8f7d79bd0845170925d" + + "575774445299bdf9d3f8ad3dc2dc5cfd3ef0293b84d6e11370851af05ebf" + + "b3510a22edd930797dcb76b759a9b5a77ed8dd5130e79ff5ac44b01901bb" + + "79603cecf674202bc5d84076ff41b3c806454ce80cb9e5fa9db77294d20e" + + "6d3008ae3017aba712862ecd4b32daafef1b8cc8b19ee8f8bc3835e2372b" + + "5cec66222ad5ea9df753c033508ec43c8b5995e88c36c13ea3465c8bc462" + + "ae0a659d9767db34499e9d01fb1588410257d6f588b3fdb766a66bce28b5" + + "e0880f8cf988a2e5eb5bf80cd7d83192b7392fbb2e3a07d51aea2b6bfac0" + + "d74d304f56d5af3598a0712cb09c04c5dc14194eca8e1b9b29f88344c0ea" + + "55638c0f8ebb70b6242b797fe2525fa1bde76293dbc0a66ab4715e6f9b11" + + "f7ecd8f35a20ee4ff3552caf01bb307e257ec0576023d624d6094d43d25a" + + "aadfce939a6808f8baacb2109c3de50a1cfada9e384cdba3e97d2c9025a3" + + "2377bb195fce68c5569d2d1267e1bc68fcd925ddb4acf567fb29ea80517a" + + "7e4056fb014cdee597333ac2408157ff60cfa1afdc363a11fd4883308cab" + + "d9a8fe56c2b41c95eaef854f20bf5941ed23156d86de3bd413465a3bc74d" + + "5acffcd15722879849c261c1bbe987f89a1f00b3069453841b7da667d566" + + "e41fd894d94de44c23fed08d9bdffb723aa8449bf236261240d865efd7b1" + + "74a4460e5004ff77f4196d1d421227dff7c78f1726df7b5eebddb4bb5f57" + + "5ade25296dda2e71ab87ea2b44ef2ce8742a7ad5c1e7a40e097eb336561e" + + "865515f7ee0efbe01d5a928f208f7c9f2f58974d1c11af0e737c673dc446" + + "1795da9757010cefc6e7f2784658717938735ed8cbcbd7981a1bb8f31cab" + + "b901c87a3218dd1195c59f64d0bc3ce8b72580fe38e6dbf1181e0090e5c6" + + "d162df9f31cc52fa6a8ac61897e9b4b3cb0ca2bfb38a38d9b78e46d775d5" + + "7645d2d6da16bda8edd8675e2ba121f7f85400cf7cacb9ffcdfae583fb93" + + "753d07985a00afc3a4e26c9939a5116d9b61196502f5d774ab4c7fb6cfa6" + + "01bcfddcfabfcd28055e858d7d3c19feb6bd7c02565add3a3af61bfba8b6" + + "f4b52c072a8613e878368318383143059a98a85ba521f781a8983c2486ba" + + "b83f5b91fce02acee0be8d0dda7489975f0506c8f363b5adc48ba971adeb" + + "4e1c830b5f264ed42da36d2b5ce2fdab1e63333b1061ec5a44ec1b6e99da" + + "0f25e7f7250e788fe3f1b8e64467d3d709aeb7360720f854afe38e190cc0" + + "925c6cbd77fbfccc07d8beeb0ce68e47442fadaf13b53c30a03ce317cf79" + + "dc9155ddf96814583695f15c970fd0b6cea0b04b1825eb26e65ea9351bf2" + + "f7a841ddaa8c9f8e885b7c30b9985bac23d3ce777b", + }, + { + key: "491ebd0dddefc9f0117176772f9bab61b92a1f1de13796176091c56d1e53dfbe", + tag: "fbd3f884a3dc2a8be06ce03883282e1e", + in: "953b9a40789b206fb507ec2c5e9c88ca1baf25ad24c11a62f664db1da8bf" + + "dbe9b54f8e93b0bfb4adb12f8873096b8960fd91eb92a8ddb53232ac9141" + + "57caced33424cff943a8db129049af7e7b733afbec6637d8ee4f39d063e2" + + "be241cca6a339e48d72372efabceac57220692c40856532d95529adfae87" + + "a71c72f30244126d01a875375ad8836ef8db929bc81027935042a05c346f" + + "bc94dcc057db015e55c56064d2b11154596b813ee64b73bcac05d2688bf6" + + "f1fbb0cf3f8307b3df44c3e2dd1d226a4d0e9dc5f7482bada9611970f887" + + "f656dcb19ce1f8c5c86f4cbd1e4f49b18f170ecfd184028e769e79d7424f" + + "d01cb315897c21111f53f4d41c3b71402eea695272cb5b4e5f33abb9df50" + + "cbdaa55ed629d3ed7d93b43e550295502db1f2ed884afc320518e88be4c6" + + "b62a13f8d3636ba091d07dbc6c20c7e7fda016c05b2fadcfc9ea32f4ee2c" + + "4893de78ad8a1771aacf6efdbd8fb1f6ee9b0572ced3edc6313185b5d398" + + "88ce77950aa4c5201a256e3ae3e74f05b70faada14124b35b105a70e7769" + + "7184576b69708eaabd36e0ba885fc6bafd5738a67307a1181792333cddfd" + + "a4ef19c88497c82fccff05a8f9f732fc7505f0467a14e135288ee018aef3" + + "d0412f6b0760573d8ee4ab455d2789b4d22a42eebdf60616fe403627cfca" + + "fea672bd0a49e8e7b80e7b7b8feebce3381f2fc16819a8996a99ea230c3a" + + "84b510cf2e0d914610d646a2f45a14268ec1d6fca03d0aea5c9ae1c8d519" + + "b0e8b0f6fb8ad176b5d6aa620b253cc492b5e5645353fbd9b6c02bea48f0" + + "286e2c669782b5ffefa4d8f3f1037151026d9cca78e7808dfbe61df29e82" + + "951d7154f3c97606cd1e99300012578ea6a776dcef0811338b56606b51a6" + + "9893fe68f762af6c9c26066b1d503e64877d8cd988b443af66a36af8bdfa" + + "41b4dfb3721d1d81895884755b9c52527030afdfaecd66d4638fab1d1786" + + "3d5517ef7ee7d081b5555d24991810f1edde30930fd392f817cfe632b4ca" + + "6fb0460c36bde4a5620b9c369bf51c7d870c43998b8171a553d2f643fe8a" + + "58aabfce8cf7363ea978ff4d53f58284db822ca95b80306ec02a64d26a29" + + "c98520f1924c70d161682c54d08a2c48f54bb72980a8cf5babd0aaf0fd72" + + "7d5b1b9d9b731dc49bad228fe83f7347750e277a4fbd526983c206e075d6" + + "a03d68957b3e925a71bc1ea7304c77660d112a5d19fd21a785d4a8d7f2eb" + + "dc4183376d8125341eb28b2df5be0b4e04bbf95c47d2fe2aed939619cb97" + + "79548b752f57b723cf8295dfce69c9b7486b75a4e900f91926636f3fc78f" + + "7b7720a5151abdf5868fecf1e1a1d830cd6a4c5e3cd739da4432cf1fe2af" + + "a1090d6a1eeb32e7236ecfddb9d07b97220ab8e23edcc93d91abc11b0c30" + + "460d2027869d1c2487070cf60b85ad0b8bc5df566f6fdb0e58fd044da530" + + "6d277e564ca6cbfa820ca73fb6201b240a5a94c4ecd11d466cdc44046a66" + + "32478221bfa69b3a2cebd16baa302a573c90895d7f4cab453b11e3a4d8bb" + + "b5a9bf264781ce5b9796e3c47d0fa57f46b923889af4d073270a360dae8d" + + "51d85ea916f14787c6500d2d906ccaaa92d20d93edd09139f79bfeb5fcd9" + + "8c1cdbcbe9f2587e9c9094e3c4a32ab9ba56f400b929e80c0551f953896b" + + "e8eda6ecf22e6d4a541957dec21d6a9cf388ff0ba58169ab934902892a58" + + "86e1126b16118e965a271495ffa339c49466209ed3875b568a4290b7b949" + + "69d0465744a3c2a75c599c3a04ab1a3fd09125fe8f45724b2f48c7822b9f" + + "ef95af4b758ae66a8b6646df7a0a1aabe2a24c052fd6d30561cae0389263" + + "e3388c4c1effe431a04356c334aac64f36593544885c4b7295b57dc39638" + + "b665b22dcbf7dd6da867615de38c6a575cc66391135d47f8e1f0c73c6129" + + "17ada4099723933a758d83311b384364263cad5fe14bdd7c825d9601c400" + + "3537a5aca7f9da4710c132ce8b0f1464cee625633ef57f507739a0ab1cd2" + + "21ae634d4d0b3ff07e9ecb1baaef0a82a97279d46543a0464855cd62c07d" + + "5e890265612906a9eac88bec07b1dea5f67054c31ae40f8c673296cc5df7" + + "f0dd8cc9e643b44fd90dc2d1e870ad8acdbe165237642fd04c00965837cf" + + "bd2344ae830887a5719a3c16dc8ec08bd9131d055bfb959b64ff4cb638a1" + + "002a4fe02e369871cc4e3ffda17dd85343e679fab43e11970e60198b424b" + + "676ab17fb0dee10cc9c2e92b32b68d5b05b7a559176f822850c0557ed98b" + + "7454916e32af549a0027db95f02b88cfc5e7e05f28f53757dd97cc0f0594" + + "212f8801e58043cb17b040413c226dfce2104a172d218caa4353890de17d" + + "be1f53af6ceda24b8781801516cc51de9ca459e469b3c322be13d8c9541f" + + "755c518ca41a0ed42e44b9f87faa2a968b0292216e9f3d3e8987282103e5" + + "016fe9f7681496e1e8d663eb2d8bc30b41d735465527f19e336a98d2dc54" + + "d7c020bfab30fe6c62cbae7d09f84af69bc2c51a1839ffba15015d381ba0" + + "a44a3758771c4f18d13827f518f30bb74f4bff29a87d4b9e949f1063f63f" + + "662721cfd64ffe1dab3761852387f78fa83fb48ae2c75fc567475b673da6" + + "fa8f53770b6e5a3c9fad951ec099c6bc1e72d1c489e1ae620e7f12ddc29f" + + "ed65f29c65cef75014b999d739e2e6e015f928a30f2fee3f2e59bf65b54d" + + "89948bf2bfde98b076e5460643952befd02fc1b0f472a8b75195c53ea296" + + "6403b9028db529cd04b97231bac3068855fa211f4d976a88bc27a0088f04" + + "576e2487ac0467992066ef7667ca8429faee92db38003728e5c219c751f6" + + "6f011b5d679fdd957f4575a0cfb6b54693a9624f2c7e66c578f5f0367005" + + "c66addd1e3ab7ea1ac404e357cbdab9438b9b4f80b3a6761b864b006f1df" + + "689ae4c0434b06b686d5353d3e421b57381ea24fdcf6199195ccdb3d5cf4" + + "623a6bb1f9eba9b22fa15395f65f8093b5f90455061c1cbf8128b44a31e3" + + "910862a59e187aa7f4d22e0317ae6c177cef24eebc44171f70c25efac73b" + + "38ada0cba0b74f72d1c171277a734819c1111ebe46d5db20a6ff20e2c1a9" + + "a57edae95a3c1f80ddf2b12c86d3df0078a7bf68695b16ccf92053c727a4" + + "80586b8d87d0d1772e456fde0c20a7927f351a641bff5f22f9ee2217b6a2" + + "d0983c8102d7d5356dea60a19e105ce366b9d000987c8c33396569f97c56" + + "2d0fc0bc5859779aa10efd1f8df0909c307a9110083cc6d9748456c9bddf" + + "16dccee52b7974867cec718bb0b76b3353379a621257094277a30148ac38" + + "e5cf67ed7cc9c1bae12dbdeb99d7d880ce98e17f0dc93c5330d1824a3c9e" + + "ffd86f89e15b59a4bee5a48d4f674766896e187abaa39917b83f8d2f3265" + + "bbe7aac44c9f8d92f775fe6493e85ab44e6e28f79f28eff156c21e1abdae" + + "d10a291b88c4020b1ae8be001080870847a852d073e82bfc751028ac62d5" + + "6aeac1b18f2cff1c0c7d336bf08f8cd5099d9d3b28f9e16077e9caabab49" + + "f2d234616a7522a6bde1a3b3c608df4cc74a6c633d4c8068138abda8d26b" + + "4ca70f95d152888fb32bdee5dfad8ff4a5b002a0a327c873656db8d6fdd8" + + "ed882e47ce8e47c729e1292db9122ce2e9fa275f9bb986eb7e0a1dccb7cf" + + "abd0449c92fd35e2aedc4aa89caf53bcd28170cae85e93f93988e723a896" + + "10cefb4edb6fa545835fba3107e21dceb272c5a32da26fa77df070f41d7c" + + "ad1d68b836199ff0f1221e36b9b976b5e69bed54b5bfec67fe9cbb383484" + + "696265204797634594bc335150daea92dbc1004f613b4c27bf5c699debf9" + + "4365041b5a894701da68a93bcb61f4e546c553fe61f14ab0322b45915da6" + + "ecacaa093b0071f2516ca8c3fef2f1e3c403993d734403c47bfe5f4379e9" + + "cb5b613fde3c0d880cecef4101aad8b8b1c60a92ac5185f6c243fdf1711b" + + "0b56f0fd8e5ed6cc0f99da888e4f156455a0f0eb365b8964347eedd15d80" + + "2f297977af667ed1376dfcc610f5152421b97afaaf16f9db57a435328595" + + "b9aa00b5ed9ff106c66970fafef379f4d2f98f2c5984ea05aad64651fbf7" + + "7968c8cbc4e959859b85302a88a3c2faed37765f3f6ced59d8feb6c72e71" + + "f9d4497d98bccf95fcb650f29131e1df1bf06a5443f8af844aa1a7b5a68e" + + "bb250c7de3a65ae9b1086cf83f832050e55030d0f67c6a54ea2a1dbe18e2" + + "8a96c9e0dea2966997bfc5c5afd4244e3c8477c4f5e8bee8fc8ca9a5cde4" + + "d9c5a2c7f3d2e811b1de7ce4279229319e432674c609b4c8b70dc6172e9e" + + "653fe1969bbc2cb3685e64fd81d96d33", + }, + { + key: "b41db44465a0f0d70093f0303bbd7776017bca8461c92116595ae89f1da1e95f", + tag: "d8a111a09db22b841fa28367ce35438b", + in: "b074b0984fb83749586881e8ec2c5ce9e086cfb2aad17b42b2429d4cf43a" + + "0400fd15352d182e6c51e9338da892f886f460d40bd178d81c52e9ab9c1c" + + "bdd812594e6fe7a9bb7fb729c11328d3288604097600a0c151fa3d9e4268" + + "de75866558e9f47d8dd331994bf69f826fd4a6cb475ae5e18365f59a477a" + + "dde7fbcf7e40b4e3dee020a115830b86f0faae561751e9b596c07491c42d" + + "e02fc979e69071113953729d7b99f1867116d058a90f1b8c0f9ba12c6322" + + "4ebd1b563a87734f5d6e2d4e6715d5f0213e33316500cc4b23784f78a9bf" + + "13fdf99bfe149cf47aeaaeb9df1cee140c3c1264fe89bcde8acda6bde16c" + + "e3d770ba51950b67ad2c5232ae0cff048ddfda8540cf18e673582dc96987" + + "4b127f655e7d4e08859f2c6b95403cd5b4e2c21f72bb872e49e592306286" + + "48ba1b16fc9637709636b198f9a297aec364d4c3bc869dcad32b1830e434" + + "b556b429136f0012a0a0b6fb3797bc8668014b010ea51674ef8865348dcc" + + "197672047fcf72e6b6910a0e32a4f110d85e28db0e338d9cfdec715a8800" + + "b4f007a7951d09e41620815848c89f8768344c50bd522c46f64ac6c98e53" + + "92176651961c7a70b62f3d1819bfda674e2ecd3167415edc4b97419e8ae4" + + "9974b56cd8d52e1d05b82610b59606a750b34844ca33bfc9b21fb970738d" + + "b66f48928df79cf67730a30b0b612f8c15c22892120548ab460a6b9bb3ac" + + "e30554c86c9681c797821a1b1ce91d0e87fe90ad4097c974cfbdfd5c4c24" + + "a5f808f388e1b1473e858f48a387614501c8c39d6973ded69b1764663cd5" + + "166be02b596a49e392d637e3d8afc91323f7450318b79d5488c040e346cf" + + "0cee512044514b570aa66bb98d639a9ee23a7cebe28474592623d082873b" + + "73efb3eaa4721fc4761e15a390497cb13cce181107e8b1a0186b9e47a5a4" + + "b67a5be3cd88a43d341ef63f10af6970aaf56035db938655020809033a92" + + "8d4fe6d2f5424fbde2fe82adfd991d388edf293cb4e3eb68d876f225a5f1" + + "58208bcb1aaefcbc28d6763d267406aa8d6ecb413d18cff7a318ba031ba6" + + "0ac4560748c248de64eec56dd4540124b38581604f502d94a2004f9eb1d6" + + "edb009e16af6c6d3ccbea79b10743da98aee7ace407a90c6cfdde694f36b" + + "e0271e722618a457be68619b980754795f4ac95ebf4f1820b85ca8e3fbff" + + "a2430f8e01ab422d7140751f7741f2c921400dac404b04e049736738a87b" + + "6f49bd54b1b447b922c473831a65f224ab84fc96e4551a0333bc6187e15c" + + "c0f0ad628068bcd7c043bd1e3036ec01e7fdc3d157476149917baafaced0" + + "15d09fafb92181a0ec65b00c9c13631e65de184377416e04d3d93b847e0e" + + "286c1d88245d4d550d30d4fbfcb416ff26a39a94275631c2deafc7cb6780" + + "f149e4d0e9c4515b708fcd62be5252485407a6ceeb9247de34e0266ef384" + + "976f6d31284c97468b3b03e951d87a5a00836ea303a266147a79ff3431b4" + + "b382e86c74d92661e0f65e266b7d569c03994b667a8137f3080eda2ff542" + + "0f0b52b427558dc26932a22a615c9e6b1834a251c6b68fdfc0bbe0e8781e" + + "36adf669f2d78bd23509ef7e086634e526258e8d11a1e0be0a678ac09c7b" + + "b4e3c5758504011e701dc85997fe2a3e40c7af83f032bdbe7adc10ef1e4a" + + "666946c2bf31dd8e3a383211c9684d5302f89dafcf77976d5a02c14e2462" + + "09d2d99918e82402cb0eacaa12032ad8316315af1b3d3bd5058f7c935d35" + + "ef0d4e71373958fd5e4140a9a586d89c53e4144c00148a4706a524896eb0" + + "5b1479a0de5d3f57be46b3f5fa4e49bffe027c81a33e37abc01a4cafe08b" + + "8e21fa86b42be52d75d6407e6cdf399de7aedb9b61a6917b2677b211c979" + + "33536664c637a57ce2234e3319fe8b4a77d7285ae6347464dfd0aab3e6f1" + + "178e0029686770d3b0dd541490b097f001e95f27efe8eb16e4747937d643" + + "cdefd49e586ecad541270cedc3064bdb7c79f086bf1fa8c666304d977a15" + + "54ae268881e17d8bc3fe51fa9969f7e560e3d3e050424febec0998b35f2a" + + "7378b2c3e384cbfc80c4987734d76c78224cb81cc5376f88f0ceda28aa50" + + "44e956537c3ee209071d84a66173384e0aa466d989759fb1f2f17fe627a0" + + "ffeaae7c5a3884b237f5151278a07117c2e833f1815c7e0e0b1611f25058" + + "ca338d21deb1a571faf1d0486667cb7c58e2814c3722d24fb77ce1b7e018" + + "2ae5746442b5ad00208b17c0a68bab4df8a8f36edead4fbe79b4c9220dd6" + + "acea6d23c7caaf6ce7cabeeca677a1c764d610ea6c7e994d6a9c88f57fda" + + "ef160b251e7595578ea2cc1441d480c14b8b6945e76a001891b1f214979b" + + "c52ec15e9480d706a40cb6e3b259ee99a9e84e63a738f1b52cf71c8ecb04" + + "fc833c2c680bfed587aa1541e5ffe8bbd7b21302bbf745011e559f94f952" + + "8b7fad8a37f6d855306a5be22725859cc950bcc334179d49564af3b9c78c" + + "e1de59a9cb45086a33856ba7195c17cef573950155bea73ed16645768bf0" + + "a5cefce78ba3ff98a54a8e8afc5dfcb0d422bd811ba9b7770a663b081dbb" + + "40aefffbeabca955a9638830f0c5d70663cbf5b26067cd061c4a3f5cf8fa" + + "4b6678d82d9a2aa33f8538b7499a3466f6b0ae2a1daf280ab91a6c220684" + + "12705245f353b4b83db50bedd3bf99d42bde6363fd6212cb745467acb007" + + "b678128f6580629a06171f7f3af272f8900b801af3bf47439167871e7b0c" + + "33f198333992a6c52c32be46071738cfbf245937d48f816ebb88ff0e726a" + + "dc41de4c771ff0bd320a4c0b1fcccd9fd6c42ec9c5185943c70e9a4b7c26" + + "a980afe104bb1f99576671a254704c7d4233eaf9915e1d56c103ba9f6e8a" + + "46aff466933bf58c9842796ae9cd21f7ac6aa96ef42ca54e390203bac354" + + "b7c1de7d1887c48255201335f819020e2782a2ee8af92ceb206b651ae92b" + + "3f4fdefed05e08974aee0a353d104b1be9a5e75c7f958f1981271b0a6928" + + "05a7a2f28a0448d86102b4fadf9ab4ec2f98e31e64fcfdf2b524780b3342" + + "7a2a3100c2032fc93199f3ea7a9e8063fe73282dcb1fafaa9496c7da868f" + + "dcf33bbb761df0bfc6fef30fadd2b6efef4fd3216a8aee48a2ef28102491" + + "cf7278b567c272d1064a277eb193b3f6f01df641ddb729f72454943cbd3b" + + "671ec077f9e3548f5f57d063c653ebee4f228a78f8a128d26f7f4b44160a" + + "07e942bab87b2d043c77ecdf10c1a419e0a1c4162a99c21d4abae0558b8f" + + "4dc0b7f1ca3892a6babf71f2f70aaca26bb813ac884ee5d71abd273ff1c4" + + "add230a771b678afbb12a1ca7fbcb2c0f5589c9ce67fe8f78a8db87825b3" + + "09ca34f48ac35aa7ac69c2fb2423807650fcf47ee5529e9d79dd2628718e" + + "230ffe5b83f9d5bdfd9c5d211282e71cbcacf972995bf1b13d21419f7fa2" + + "8829ed1dcc459da35883b9269a474f7fceff01d44ab78caf1ef7d8117f50" + + "cc83eb624062b149a6ed06ddd1cd1feafccdee7122353e7b3eb82978ca69" + + "247fde52d2d6cfe7324f04af5259e1b5c2460889da4541b431ba342a1c25" + + "3a1b1b65fce7120829e5466e7ad2fe4e0f773c7c13954a9c92d906c91aa1" + + "de211f40916596bfa8245344e257e5907a2c49ebcc864cfbe28663e700d8" + + "472c50355313d5cf088e9e8a19cdd85bcfc483520498c6386050e53a3ff8" + + "1e2b77b55b116a853d71f60d621265166cd7e95ff5cb4466226d7cef68ff" + + "d0a35b61e76a43cdcfa8da7fff9558e2f89b981ec6be632b126303ca1fe8" + + "53d5c628d967d39317b60ac904d6a882beb0746f6925a86693aff4deaac2" + + "e5b64b611de86767d55a6e11221605508b1c5cc828251539b1b6f65c2c04" + + "8e65be5422c1b11194eb687d906c559068c0a810713b23b30d8b17f10df7" + + "0962c5e7e782aff7bb95adfe4cba9d90b0ebc975fa56822025100b5cb8b3" + + "8bdc8928c1a2a8034dd66e2a763696d7ce6cef4dd586b83f7d01749d37fc" + + "4fe8d7abd324d4ff1efdbdbfeb0a2fbb8b266fc2bce8e5e5b95d0089e7c5" + + "d7de4db837d1822ac8db8198889d6bfe778d0b19e842f12b5afd740aaecd" + + "e36e2cefc2cf0b082aa0c4f75684d024b8d828d8f2911fe1aae270251f62" + + "4f49584e40bb193577c9d8e04eb16c094653cdf9a15fe9210f724c7a7c73" + + "74cfd1a74abb5ceae88ea54f7e7569f8eb674529cbec965ed05bb62f1968" + + "8fdaa97297268bfeefd06eb21f700cc56f9bf7f6cecbbbe7278ada8399fb" + + "960371a2d5cdb852b11c9fa17650e614c5297bf46cb7889d52bcf49d2560" + + "720852822b75bb16524d88273cb366b84b88282da91875562e5a1fe73973" + + "afe90e5cdd3f5381612d3ba7bfa058d023a9326e403ec474d8938313fb32" + + "bdb5bf899b900c3818c43c8a0af6a061bd26e847ed75983402ee8a9cf4ef" + + "85bba5545a0d329ba81495157eda0286f1917de512fe448251697dea406d" + + "a510adcb05", + }, + { + key: "b78d5b3019688e6ef5980c17d28d7f543ca5b8f9f360f805ee459717ca0d85a1", + tag: "f01babc4901e957d0c2032a7279321e1", + in: "ba7d35b2ef8af1118bce1e78018c9314b0c8c320591e103d23f715acb05e" + + "dc98fbc618de06627661df5842dbba9f604c2d20d664e5db06e949b11d49" + + "665088dbafdb0d39d20beaca7d723f8dcdc57e9c5583d303b6cdfdbecf95" + + "7d8daf2f1c72b2a6fa27e3d18841f4841abafd334c110cd2b74efb6191db" + + "ab9b8fc8427ee17664082f31db98d30bf15dda967e20730a9ef525abe9f3" + + "f620e559ed22bf74d347c9869f0311f33da7f1a3dc858b3a8aa73a35989d" + + "b055a4a2c269c95e352259c57de8b94d8de48984ecde426d3ef60ec1c7b4" + + "41cc950f7764f55bd0cf52d069b9ad446d1f765f35d02ec104ffcc00bf1e" + + "dc1b951ef953acd19984ff1b41041bea0e9f5326a7c9ed97e6aab42174ee" + + "971ea1dbe2fd1c1f67f977ab215962b0195417170f6b7748fd57262424d6" + + "cf7c235b34425f4047191232722932213b3eb73904cadd6a2e9c7571d7c6" + + "6c2f705b5039ff75e5e71c5aa738bf4177653e6eb0b49303a4bc0e641e91" + + "2691f217296a3325431d578d615afddf47784e4618a2ca40ccecb05d621d" + + "a52f272b8cf84f7fd8177c83af1580d25a764cc06436d67171cb5d1e3b39" + + "367b46d9a59d849d87ab6bfcf3fb9bac2b1ebfcd1cef4459e74b0e1b7080" + + "dabd2dea79f75581a55de63c4b23ff67d986ad060102933fc6cce8d614c9" + + "c86dc84068828dd9e21ffc5665c809d83b09432fd315dfce5d7a4ebd8143" + + "181953e3f8716e47b0b30cc1f753e31a7d509f2dbd4177b6da310cf3cd02" + + "5db270adf98e96259a5ae1b81f5be4d5c76f502a612ca73c76b91e0ca695" + + "aa921f9489948619482c2956205ae71fffc3aba4476ff754e4878e36c763" + + "2c935c076857c5b90cd63ea4764efbcee53e2ddc9bdce54b1cbbcf0e7544" + + "d023e7c2b79419ad92221a1f76abe31a8236e370d38e2493cc9ca2aaa811" + + "30fc713d11f500fd071d6eba6861e8b0859b372e62fe60b627a96c377f66" + + "236aedf307e1d148a61bdad072b93d7d2a73367c595b1e048f7023e72729" + + "1ec508326f5424a5bbf4e010d0240b71fa9137e6642ab40c5e4fff79877d" + + "b3253c663a221b49b3e77ea307c7b9f3f72a0f3a54d0112c45c64a0c0034" + + "baf2b55ae36ea6f811bbb480cee663136474dacac174c73b1e8be817916c" + + "fd4eb1876582bb3a36cfbabad91776aa676305ddf568a86e3a5eb687fa81" + + "67771fca7b5ca00e974b3cc3e322b4bd9bcee2a87d0ae7976da5e04fa18c" + + "219fa988d4f6fce62f194b05c26ed3ae1b066cd9751a2d916d53426a454d" + + "58f9c3b2fb49374e5791b412fdee1b6029144f1ca787f56fece4f64f4fac" + + "bfe4cfd8ba7c807a83cf44008fe5126a283ab2631a87acd8e2a3bd10979c" + + "4b07a84a49b0687a45a4798ded0b5e9b2acce30e714d78395bfa8f33ca91" + + "e68b2138bd67d8a694cd87c88dcefcd101a3b408d7a9095cc6a4b38898ec" + + "c8b375f5a67deaaf73eb7e99b10314ca6bba824658bee85dd731d9a1475f" + + "976b7c0aed4b67b088f0db5ca5091273217f724969dff6cf184181377c45" + + "5722beb23fd9d097a82ea2d8d527ba6284acc20cb30f2e52af28800c61fd" + + "1faf9f4f619550e0162a1a63758e202533889b27420fe7d0eac9a47a6e11" + + "1d80054412340e0426cdddbb3c7b9b823b8db3ef58230fad7a3ac21a7805" + + "d30878d4ea78dda95c951b7a5dc552e9434c35e03e1dd88652d3714f8fbe" + + "a39936cc0717c2e0335371f2a751204f5d9386baaec853f019325edfd1b0" + + "719d1fdac3fbd774a64bf957fc54039501f66df94b5b9b82c2076c597065" + + "dfcfe58b2e215a3734066aeb685ef97759c704b5f32dd672ba59b74806cf" + + "ad5daeeb98d16f7332ff0ca713d541c84e4aef0750bab7477ea707e2e497" + + "e12882dbc0765106070ec6a722d08fe5c84a677817b28fa3a41a6117f2f5" + + "465c2a2f0eb2b8be4f36e676b4115008bade3573c86cfb1370c03b6b0dc4" + + "bbbb0ada4dedac10a593655068a26febc2bf10d869cac84e046c9c846ce7" + + "927431f606f07b92abdfd81260199ae05ed01dfa07088c56a6a8de9c6d51" + + "d61d6a6d3f9904c216ea8329467a006a3d2495a768a39ef99a21827d2def" + + "909bb743fed7209f7fe59ff1c1e710095b05f166c6173deef5c6ec4105c5" + + "fc3b87c8269c786bebd999af4acbf12d20453b125f338aee87e9509ee405" + + "9c9e568e336304d7be9ffe81d1700555b0800242d9b7450d7256f2b17f6e" + + "d46a39f67bb2980572ce73169e352070dbafd4c7fa5a6be78cf9b72981c0" + + "a01f1e1e30ee3736c59828b791d2373799854497a28a44bbe0e074925723" + + "4986696fbb06ef9ea83fbd49c45a583ce12ff10258ba06127c67b0f66dd1" + + "09f1366d8036853973d8884f93de54fb2a12949eefc020717eff47898cef" + + "306b5de068411f1e113ffdfe2556e0faedc3e27d95a45b8afc15ba0eeeff" + + "eb86da7b4324e20af80c62bf0ceb4aee1515f5912f71c6bf2febf20123e3" + + "dd3a82dc1e58a108f1039942dcdacdeb1f0ad0b2ef34488d98d6a52311ae" + + "acbd03c12f6e775e375d5979c7c295bb049f2cfd3580e3da3841ddd8e6af" + + "4de5e6512ca79cebcab9280554524881da37984d340e8f0163fe10a02ed0" + + "88682560bc6d3c4dbcf1a542ffb3dcc2ed16a2eb96896e8269697ffeb50b" + + "73f2cc354092e782a0072fc12e1eaff117c2cc8a5a1ad8b47802ac9e23fb" + + "91a0cef9e4027595e0885464e61563093ee2b1dc5f22dfd04af7de6a70d5" + + "977d3751a4b3cc0c71a71c59c0534cb1f8c0eeddcf1c0e1b3e5ad0d083b6" + + "6e8b998ddf9ae9d3b365c851d42e995b9afdf8d66b2ac40bf514ce32e456" + + "0880afd38c42c08926067eb243c4b1184e667ba756c14ace5f525eb48df7" + + "ebb429d0a23d159664f8021d27dc7167081de331c7114c9c6456e1ffdb42" + + "2172a81c06d8deca995e158c48df27261a83f83e0127f5e056a139be9b76" + + "e25dadf534d3d1ed6ebc0b5d77d51e5b90ff86f30d4023066115bc11b33c" + + "c827b1103098826d0bf8777176b2da6f1e5b580e407ccf7e614fdf4f5b53" + + "3ef6d30b20c1bee61eab90e983b1a97173a62720ffd27abb8976a948d532" + + "d06596c23b0ef31c79831bead8f8e99ad209af3658cac0cb3c3f9c88379b" + + "9bc871d8e84171d53400902da1243f664afeaff60bd96ba2639a7644676c" + + "a79f43130af12ba2c877d67f7ec030a4217a72f5368af7c9f24e643db6ac" + + "97a04adaf57dbc53762d8dfa1afd49667c4041adcb5ec303e191b786273b" + + "bb065cd9f16a3a4a399c6a7aab9c1a6604998264e8b3dbd13d8f2228b13b" + + "2c2b9fec5055d8e9f2df1d9a25e4bfe2029776389877bbef7e2c7621f06b" + + "c0b7fc0786e2b2d042483ccd4a59d2872a6c5ac73e217123e5c8401580a8" + + "d967e0895aaa28f4d25ce68c90b4394d8113bc423e9fae46ac47bc2ac191" + + "fb97b80b5a85feb2bb54f84c493235c1408662fe253c6786fcf6fdb8be87" + + "dc66a72cc847f94dfb5214af5905b7039a7363a1b23a07853daa26862783" + + "ba08a80846fbb93ce98700a4f9961115128dd67bd7d19e0c588fdf6196c1" + + "1cb0154002ae862f11421f5dc3a57b6c0870b452272be556a1d14eab1af0" + + "a91ff5b89de6bbeed6e03bc64f5efddf9e54da71c594bc5ef78e0192cfde" + + "da36e4ad1a6b0b51110c1b24d20dea1f19e18cb1184d80189f842d4f07ac" + + "834744dd009aa3771b1e5502fe4b65a403a4bb319e1880ff6ba852e90a8f" + + "4fcb52cf374c88408428cdb1255291b04ed58c992310955198d61fa1fd9d" + + "762d48f2f65a287773efc67d549981c291b427889d3e3dfc0cc6cd68415c" + + "dbed81b516786dacf431472a7dfc99688d15bb6c1b85b1a2015a106e5de8" + + "cb9eec4c80b17d00fdcf4a9c64de4643a95dade8fa9f1bc5c839037d86c1" + + "3800a244188e3b18561a74912ed72f99f2365f0126732d037dd54a3ab77f" + + "9a9f6a1c1469ea92eb707482066bd4990dec4d7614ccb4ea6dd4deb8bee2" + + "2c4dc0b9b4d4cc70a500d2c8a5ac3ef88a38439b7dc254a6d920cfd317a8" + + "4d7747148c65b6730709e43369d4c995b03c58b9df444f77f216944e70f6" + + "6446554d8d513b8f7f28ef0a2d7ad5ca2f6110304196953247a7ac184f68" + + "61fba896c2d5a59007ec2b2c8e263957e54cdc1f3b4a145228823fdf0960" + + "c33a28f59b03ee4be21001d2f56fd49ed14db33b2c4eec2c3f41b250a624" + + "99a9b6602c1e838526a54cdcd058af1c252d56009d4c7769deace53bdb66" + + "543f5a081cdde775e61efa70956fe2a7a6019a164c6e413ded314bc928b4" + + "aebccb946ffdf3eb33e187bf421febe26112b3262a526de65678cd1fa03b" + + "83513705108fe0bb87aa99aceb28af3641c46a2c4427cc1063de01aedaea" + + "fba68155d4de494a27ff6b7fcc8f5c5c3f7d3a115c397a1a295bc55aec8f" + + "7f150cbce2a8aa4706d54ec863877bb966ad441c57e612a1b5d438b98d9e" + + "fcdfe6d4f66e885f96407e038015cf974ae5a3540692b054d2ddfde59b28" + + "ede7e2f581eeb56c5b88e2779aea60c1d8ca6107b0cdda1ac93e6c7520da" + + "edc66afeed12f980e20e1e1c327d15ade4bb90de30b011a9cb33855ca3ca" + + "e2", + }, + { + key: "2b0b0fd3347e73c2fa3a9234e2787e690a11aec97a1c6d555ff7b4047b36f372", + tag: "81b1a6633f849ab0aa7baafa58a5d9b8", + in: "427f3a7a5f1142ffa68e83df5f917e07b2bc454f3adce068a8ae9e0908e1" + + "3e0099aaa9074697593c6d8c2528fedddeca05e3888be1a0a201c389a72d" + + "20cb661017544d95a431e70e7c6580d8fb46ea4495bc59db6ae2cd69510a" + + "02426c50de1b6110120f759960605aca718d4d0a497e003e1ea2b8ae9a53" + + "df3c1eb4f704eb32f8f05eb08cecba0fd4a94f0daa3b0984c30a38f94b7a" + + "10cde723182d30588bc40f1f9d38a3bab4800fdd5148e34e396144763696" + + "c9b3e9b8adfdb337123d54237c7413f98bb2056152b256e37a27bb947c67" + + "240fa3ce8da62ab367db540bcdd9eb873d6c71c75a08fe99b5c11ec8e6af" + + "f926d2adfcf073479de394d4aac5fdc6241824d944b8773db604c59afc01" + + "495ee755905e5616f256c8a64321d743a1c9368d46418826d99b762e2f6b" + + "f998d37a995969cdc1de85f0ce3987c6550459f5e5bfd9173bfcb9e0112a" + + "d91f092de446beba14fb3b8ce3fb2f9c941815b2cb5a3b406e2d887b7912" + + "bba07c8dc7caab9836827da93ca71fa5ada810da1e5e9b09738524564d8c" + + "923746d19c78dc9107b9f20f653e05d7f2eb6bd90cf5eb30fdd7b587eb46" + + "74a1064c70ef0af2e75373044d32b78d96eb1db3112342d38dca0e47b96e" + + "9307fcdd711b1c66355186369a28481cb47ef6bf6651c2ff7ee4665247cb" + + "12b573933d3b626d1c6264c88bd77873c2e73e73ee649216bf0b6d6615ab" + + "245c43569d0b8096596f25ceca8667661de1cd60dd575697370ebd63f7e9" + + "5333e8a2cdb829b75ea83d72cd246d50358f7c094c8a515805fda03165d5" + + "21391617c9f9a2ea562b419632df611a67912d2b369e5e505dbd5c719253" + + "16d66cd608cc4a9583a8eaa4661b7279870345fac3031631c1a220551527" + + "5be7d8d89b71960e687aace3a0e8f206e475053d6fbf97717b154c75406f" + + "2caa97d1ab66048f1c99281c188a2f37b8bfc736c25840a9130ef2031c05" + + "6acd9dc10592eddf94f5bac85319b10ae46cc136a0738aa803837287ed7e" + + "dafe08d1fcf31d5e63763e39a5e1f4d7d0edab368d44e63fdb33c28905ff" + + "d6be406a024c017081b4f2d70860776e9d2556cd008fa5017b58733da13c" + + "634938407a118827a80baa28d4e605db59430f65862b90cd8356baa287b8" + + "4e6d9199fd80abb9fa697e2c2c4c760128e4ec0438388cf407e2a2fe0f57" + + "908187ed8efd4c5cb83cc91dbe6a11444eede85099149ca82921bc28bdd6" + + "b9999594a41d97307f8854b1bf77b697e8cdd4daead2aa49fbc571aa44c0" + + "bc84a57cb5fd85f06847ad897ceaf449eec45bddd4e4eb1e1e119d15d5e7" + + "90957e686acbdda1bbe47ea935ebc4b8c2e3cf9b7157cc6dc03bcb19508d" + + "a9e19cb76d166da55559ec7e0995d9b50c6c45932d5b46eee400c56d9dee" + + "618977dcf6f76e3e86bc5207493afbc2aae9f569ec9277f33d9f61c03d59" + + "dd6d8250ee8cb3e54e5e941afb74f0735c41d52ef967610c9f55b2b52868" + + "4b549a99ae3392a7237bb52ff5f8d97327e2837268e767bed0bea51f76bf" + + "88bf0286bf22b881f93f1d54fab5cd4e3c148c96c39e7aeef375de249df0" + + "4d89d1bd97a7afb2be0cbfd3380cb861d31e4ad1ea8627721e4518b9db3c" + + "cda20273ec23549c4adc3c027e3ac9558de2010a0263c1225a77dac8be60" + + "d498b913f91391d8b2656ffddb06e748cb454dc2b7226745f11030a6b9ae" + + "09ac8ac428d9c6500801fb540650c94610ab70465b1210c6db2064dc84dd" + + "7f52573f8f40c281470e85176c85ec6de3c718663d30ad6b3dfc1a3a9606" + + "1936744357ca62fb8bb066aa1fcac6d7a2adf0a635cd546bef39fbd3ee0a" + + "8802ab0466ec9b049b5892a9befa4377cd199a887c34569b6f90852139a7" + + "86babc0049ee2b527aa96b988237a52eae8b4b49d2ee15ee5294118cee62" + + "3c3e11cecb836b21af88555f10be2eff8379beb615b7b3d6c01d545cacf6" + + "61be8ebbf7a3c58ac5e0e7b17997659a2bf15f2b2e3d680d142fd29d23a7" + + "aea9890f3ff7c337fce49ecedaf38573edfae07810ba9806723e576d687e" + + "a11700b8ccb96a6559259c367cef4e3999a05a373ab00a5672ce8b3d1dec" + + "a414187f383e449d10021b73c1f7e39ce01516b7af96193f9993036049fc" + + "72ac059ef36b2bcfbe13acf140d41592880fb8294ebffb98eb428ce9e65e" + + "1094521bcf8ecd71b84c7064539a7a1aac1ad2a8a22558fb3febe8a44b87" + + "72fc00c735773d4ce2868a0b478ee574b4f2e2ceb189221d36780b66212c" + + "dd8fd3627cf2faaa23a3d0b3cd7779b4d2b7f5b01eb8f1d78f5b6549c32a" + + "cc27945b5209f2dc82979324aebb5a80ab8a3b02129d358a7a98003e701c" + + "788a64de89726da470010eda8fdcf3da58b020fadc8970fafb08a29bef20" + + "2bd0707e994015258b08958fc2af4c86c3a570443fe6e1d786d7617b0c66" + + "29a6d9a97740c487622b5b8186c529d7f8af04d9f0a9f883043f08103ca4" + + "d70057ee76639f3b1046d86928d54cd79fb5bb7b46defdf15d2f8578568f" + + "1d7b73e475e798ec6812586700e038ed4791b23ac9439d679a1a4bc04cea" + + "e328330c24b065c9cdcdcedfbaf58e5299779e6f48783d29ec3b1643bc8f" + + "1095c724dea75770583b15797fc666f787510d91e65a8e2090cc1ed2013f" + + "e63ab17bc7640ee817487f4eac8326e9c4698cb4df05d01bae8c0d00fc00" + + "08919484d5e386c8f60b8ac097c93c025d74faa56e8cb688d1f0c554fc95" + + "aae30873e09aae39b2b53b1fd330b8546e82d9e09bbb80132d794c46263f" + + "4fd7b45fda61f86576dec52c49f2373e4dca31f276d033e155bbcdda82af" + + "8f823948498f4949bf23a08f4c8ca5fcc8598b89c7691a13e5aba3299ee0" + + "0b479b031463a11b97a9d0ed3189d60a6b6c2390fa5c27ce27e28384e4fb" + + "04291b476f01689292ace4db14abcb22a1a37556675c3497ac08098dfd94" + + "d682401cabec239377dff592c91aca7eb86634e9d5a2848161dc9f8c0c3a" + + "f7b6a728371fac9be057107b32634478476a34cbc8b95f83e5b7c08d28f6" + + "fb793e557513ca4c5342b124ad7808c7de9ecd2ac22d35d6d3c9ce2f8418" + + "7f16103879ed1f4827d1537f7a92b5bbd7cd12d1ecc13b91b2257ad073b7" + + "a9b1ea8f56b781bea1bddf19b3d7b5973f1065fb72105bb4aeecca5b7513" + + "ffd44d62bf41751e58490f171eb9e9eb6d57ffebedd4f77dd32f4016b769" + + "fed08dd96929e8efb39774d3c694b0d30c58610541dcfab3c1cd34970195" + + "7bf50204acd498da7e83947815e40f42338204392563a7b9039c8583a4dc" + + "faba5eaf2d0c27ada3b357b4fccd1595b9de09c607ebf20c537eb5b214b8" + + "e358cd97992fa5487bc1572c8459c583116a71e87c45c0ba2ca801931a47" + + "a18ef0785ebbe420790a30278d2d0d42a0225d211900618438d1a0b2d5be" + + "d14f8b4be850dc8cb08d775a011683a69ee1970bb114d8d5017de492f672" + + "09062d9ba3616e256d24078536f30489e4dacd6429ed37aab9b73c53fdd8" + + "a8a7aff1b914b9d82d75a46d0ccf85f48d3ce9a8d3f959b596ae9994ac3e" + + "3b4af137d0c8e07ece1b21fd8aa05522ba98f85a7ab24ed8c1e265fadf4e" + + "9a18c5ab5684d8ba8d3382ad53b415c73ebfaba35abeebaf973b6f18e0d8" + + "7f019420eb34e09bbb12afc5b149f1e9e9b6ae36ebde429d437ada1a2d52" + + "b998f7c75ef731132aafc3bb106a2ad3ae11223a355804d4869ebaa47166" + + "2df261d95d48ac6eb17c1781e81c0027ccf8f05c39e1eda7793cb16622be" + + "ce7a1ad5d2f72f8bf4bdb2f4f4dcadac3db3bf727f0d447adddad4500360" + + "09ee011bf4155e5e46c74b00d72e8e6a88de9a81a5a4685651b90e874dfe" + + "eba41698c98370fd9e99619ce59ebb8342417d03fc724f9c910ae36ac5e5" + + "b46c424141073199aaac34232a8e17ebbfdd80eb75e82290de92968f3893" + + "0ab53dc83ac433833576e86fbabfb9d7cd792c7e062811f4cb017710f841" + + "1e0fb65ea4b3cd68b0af132cb08330aa13579196ec632091476f268b44ba" + + "8f2e64b482427dfc535d40d3f58b4dee99053b35a3fed1cb245c711fa16f" + + "c141974c8db04f4c525205dad6ca23ccaebde585cd3bc91f5874452ed473" + + "08de95cb6164102744f90b3007e511e091653c97d364fe0cbd7f4cd3249c" + + "1f5c452becd722ccc8c6b4e371e2631337dff78efd903a8fc195a90ca5a2" + + "aa4513bc63cd43794ff06c5337329055c43d4fb547e63d6e4d14fbe37b52" + + "1411caf2f1b0df51a68f677db59aa227c725cf494ccb7f8cacc5a06ac5bd" + + "f135a2603175a5fd5e5af615fd2e7cea61934e6d938b9e672290aaccd99a" + + "7e26dc55efe928e56ae6354168264e61668a61f842a581cd0c4b39e0e429" + + "04631c01320857b4d7e260a39c7fbed0593875b495a76aa782b51fee4f88" + + "84ca8ddb8dda560b695323cdde78f82dd85757cadea12ef7cf205138c7ba" + + "db6a7361a8d7868c7aefa7aaf15f212f5f5ab090fd40113e5e3ad1ab04f9" + + "b7f68a12ad0c6db642d4efb3d9f54070cc80d05842272991bcdae54cd484" + + "9a017d2879fd2f6d6ebce27469dda28ad5c345c7f3c9738038667cc9a5bf" + + "97f8f3bc", + }, + { + key: "aa3a83a6843cec16ab9a02db3725654cb177e55ec9c0c4abd03ada0fbafca99a", + tag: "719dbe5a028d634398ce98e6702a164b", + in: "643883153c215352a4ff2bb2d6c857bafa6444f910653cacd2bbdb50ffdb" + + "cae23cc297a66e3afefbd85ab885e8ccf8d8f4930e403662fb4db5121aca" + + "82dfcc3069bd5f90be4f5bfd3c10f8038272021f155e5de0a381d1716abe" + + "0b64b6d0f73c30baf6ddfe0e6a700483cad0fa14f637afb2f72361e84915" + + "78ba117e1c03f01fd61aa8f31da6464f3d0c529524d12dc53b68f4d4b326" + + "db7fc45c63f75244002b8f9a185556f8aab85948647818f1486d32c73614" + + "b8c4763e2645bdb457721ff3901327588da01622a37ccbbd0374fec6fd1b" + + "cce62157e64c4cde22c3a5f14c54cd6db63db0bd77e14579989f1dd46461" + + "4c8691ef26406984b3f794bb7b612e8b160374be11586ec91e3dbb3d2ccc" + + "dbfd9c4b52f0069df27f04853e7cc8b2e382323345b82ce19473c30296cc" + + "453f479af9a09ec759597337221e37e395b5ef958d91767eeb2df37069a4" + + "f3a530399961b6bf01a88ce9dfcc21c573e899b7951723d76d3993666b7e" + + "24dc2570afe738cbe215272ccedb9d752e1a2da00d76adb4bc0bd05b52c3" + + "fa08445671c7c99981a1b535582e9b3228ce61662a1d90a9c79afbdcfcd4" + + "74def2b7880cac6533ba0a73fa0ba595e81fd9a72ec26965acc0f4159ba5" + + "08cd42553c23540bc582e6e9ac996a95a63309f3fa012eac14128818a377" + + "4d39936338827bbaafad7316e500a89ed0df7af81be99e2f6aae6bb62568" + + "1dfa7e100ebca5c8d70f67be3c1e534f25446738d990ee821c195c98d19c" + + "fd901e7722b4e388da90b95ac0b5b5dc5d052ad6b54f6ea34a824bcf0cd8" + + "7f1fc9a07e8f5b8aa0793e3c9c1022109a7c7ae97ee2a2867fd0cf0f8971" + + "34b3d150d3b24fcf8323de929b73cca01244df02510393f0b3905caa0268" + + "7fe35f64391e7d4b30be1cc98319716528ca4f35bb75d7e55cf7749968c5" + + "37136eddb149a9f91c456fde51937c0f35e7e524647311077e6fbe7f3c12" + + "37b9584fcf3b0f78744c7b2d3b452823aca06d144e4463eb5b01014201cc" + + "bfed1adf3414427072135d48e705b1b36ab602cae69428e7c19d39cbb4e0" + + "ca26a871d607ed4daa158b5c58a0a9f4aa935c18a66bdeff42f3dc44166b" + + "a299d71a2141877f23213b11c52d068b5afadc1fad76387cf1e76571e334" + + "0b066ade8da02fe3b0bdc575b1d9ec5d5f5a5f78599f14b62db0bef7ccc6" + + "1711482dfa4787957d42a58fdc2f99525c32962b06492229399980601bd2" + + "ee252306b1464914424de9aa414a0a6e5dadf8ffbf789e6d18a761035d3e" + + "f2ff0753becbd2dd19fc1c28f9acebec86f934f20b608a9ef735ac91f6b7" + + "83d9327cce7f4870d39bbbfb0100838dee83e6baf2b40cfc98415dd174ed" + + "72e393ad0459e8035dce7eb18eb3af2f39d2712846b9e1852cd61d06dfc3" + + "5e34fb761b67e2a711ceb4a82557371ed32ca8db2e4cd7fea0b6bd026177" + + "4057b9abc45dae6869cab1097459473a389a80a4523e5de696554f8b0bec" + + "0ca605e6acfaa00386fb5a48e0f5893860a29f35e680be979cf3bf81ee7e" + + "ed88262dc80af042b8cfe6359cf8b475560bb704728034e2bd67e590bd76" + + "1632e516e3292b564c7265d7a6dc15c75ba6f6a447b1c98c25315ac7de59" + + "9edc4993e4dc7d1dbfcea7e50ebd0b226e096500216c42de3abe352e5b09" + + "a3c9754aa35d00883906599c90a80284d172a90abbeaf7e156fe2166ada1" + + "794420fe55b1a166d752d0eb7f04e822d021c615e84777101e7c9f9dd12e" + + "565b7d093fe978f85e6142c1ca26798b45f4b8d23ecff6be836e810e314f" + + "ebd2ea66f2ac95bad84b39b7a6bac41448f237b45e9ec579235ba2bf5fa1" + + "f00286379ec107c743f06ae0d11b57a2f5b32e3bc5f1697aae812d7ca303" + + "b196a8a43259257f7697bae67adc7f121be561b2d0725982532ffc06cb22" + + "839d9066dce0e4d683d9348899089f6732de62751ca77f1c439e43054468" + + "2c531b9c61977bc221b66030f7571dfb3ddfb91d9838529dbc99612f650a" + + "d72bb78de061192068941a81d6ac341101aeb745b61bd7a87a35a2714d50" + + "c3eb2c3ea148fb9ebed948307f8b491aec277ac01903ba36e6ad54f89fe4" + + "280a17f8e7ae639e75aec16d56576f03c2a1efe4af995eb825ccaa6efe0f" + + "d6d878299a351591d791c286cac5cb049834580d47a9bb7720d0603e3141" + + "ad7c1ec2dd23d3002e15d73c1828a7f08062848b1b6fcf816bd954743547" + + "6f0d6f882125bd03095eb1b1a846d535730e258fc279f7095de7c2d3fcca" + + "a4640a2e2d5ce0974c1e073c60bb78171c1c88ae62c7213a95d36ea9ab17" + + "59093813b85d17ff106e69100bd739ede9656388bf47cc52730766a8a186" + + "9dcc623e09e43cfba1f83ae1d9f16789064ec73504c29686760ea02c6634" + + "a929ca10c6d334b1751494c6d143671ce8e1e7dcc9bcda25af895a193032" + + "ce27c1016ccc4d85507fd2265ebf280d3419f54f66ba2a161c068491578f" + + "be056f02f97be745db443e25ed2647c5348f278f4ad8bf5b2a2c2d56e795" + + "532e25585984a3a94f435ef2742a0413abed7230ff2e9724187c91f73a7a" + + "726ebf36bc8d0d959418dd586452664990889358c56720c1001c004ff768" + + "54b9850890ce1b31735fd9f4a3640622ef0b25c659e8a937daa0df7a21f1" + + "77be13dfdb8f729da1f48e39a05f592d8c98da416b022fd8edab8e6132eb" + + "a80c00501f5cc1e0243b6b096c8dbe7f8c6ffa2f8bcc7f309fb80b489b92" + + "c4878fabad42d91876e10ee64ccd415124461cdc7d86c7bb6bcd9133f3c0" + + "dfa8f629ddb43ab914c0ac5ecddf4398052229876fd838b9ae72523946cb" + + "bba0906a6b3ef26672c78cb24cbf691a5ec869d9fc912009d840772b7da0" + + "c7f47856037c7608705cd533918c207a744f75fdfac618a6981778e09332" + + "5c7d22170da85bdc61044b4c397919d601a30746cefefa798c58f02cb827" + + "0d130c813cbeb67b77fe67da37a1b04bf3f1e9ee95b104939220fb8a0394" + + "86ab8954b2a1468016f546406d1946d531966eadce8af3e02a1f59043ff6" + + "e1efc237dbf4dfd482c876531d131c9b120af8b8fd9662cef1a47a32da40" + + "da96c57dc4efad707a4e86d0b84262d850b451bda48e630c482ef7ede5bd" + + "c55147f69e2ff8d49262d9fe66368d1e38ecdb5c1d4e4042effff0670e69" + + "04e47d7d3047a971d65372126ff5d0426d82b12b253bb4b55005e7a22de5" + + "6fa54f1dfcce30b1e4b4f12b1e3c0de27cea30ce79b08c8c1aceb1ffa285" + + "c317d203a9f2e01d542874fc8035b7670f3648eec79561d6ff2fc20d114f" + + "ba4fbed462f1cd975ee78763c41663849b44cb2827ee875e500b445193e1" + + "4556bcccfaba833bb4ea331d24a6a3bd8ec09906c7b75598b44ce1820a49" + + "fca4a0c1501e6c67515d4fa7f88f6aa3cd7fbc6802131a7b14b219e154db" + + "9ed241133e10ace40e4d963f904dd9f3bdaaade99f19de1ddfe8af2b3cc4" + + "0a48374dd8eb559782bea5410f8f9a1cd128523c0157b6baad9ea331c273" + + "311492fa65c032d0d3b513d23b13b86201840d51759021e4133f873f2781" + + "8f54f34ba73b4f33107d49c8de1533856ec37bb440f3c67d42148765610c" + + "3296bce932c839fd866bec3762a38406ac2b39d0d93730d0c88cb8f765dc" + + "d8ee71263fc96068b538da06fc49e25dbeaa10a5111a9af8e8f8d78e6ed1" + + "3752ad021d9f2c6b5ff18a859fee9651d23a7237bd5a5c29029db3882c47" + + "0470de59fd19fb3bfbd25d116f2f13ef5c534bf3a84284ae03e3cf9cf01d" + + "9e984af9a2e63de54e030857b1a071267cc33d22843b28b64b66e4e02803" + + "c6ab5635291aefa69cfeb3958c09d0b37176842b902da26caae3f0d305e7" + + "c6ab550414e862e1d13d9bb9dc6122cb90ddb1a7bc6d31c55f146659baa9" + + "6cca4ea283e5e1639967889543ecb6849e355b6c0227572097221dd46c1d" + + "f8600b230e9644ba611ba45cd83fa4ac7df647b3be57387b6db12682018a" + + "de9be50a8ea7d5f7c743bf0c6382964bb385b3c207c0cdd63279c16130b3" + + "73ba974125291673344b35c8ef9a33be5a8a394e28dc1448f54d46af675a" + + "edc88ce85a11ad7e50058df4f3f2364abd243683d58a2b13fcb0dc0eed21" + + "380b666eb87f4be75e7f2842bae916c15af3e9658c55408537b2301faa6e" + + "42af4d94e3eda6a41d6d302be281e2a9299e9d0fb1f20cf4ca978e66bdd7" + + "4c8bea0f15c84d6513cdea787dacbd4bb529ed03528284cb12f6ecd841d3" + + "c58c3a57c6bc19b65d6d10692f4e1ad63b091137c8acacc6bc1496953f81" + + "2972bf6362cf883bb75a2d10614029596bf9f35e92addbb50315b30161b7" + + "de8867a1393d9583887a292cadceb54078c9c846ec30882e6ff987494060" + + "721d3c761940b91a126e8d1e0118617bdae01a7f9c1aa96bdd6c78ca06f2" + + "6c8d85664a8705334f4997c724ef98fe265985593d5a9c30798714e6de1e" + + "bd04b648be47a6b5d986a3103e738a5cd114b19b7ba99d2e2eec6181bf3d" + + "ff0fec8c54ae6118be8702c3e775d493a6fafb509712a43ee66c3f4b75b0" + + "194c88937cffa5fa17b284d2556f2b0eebf876e05f92c065515198bd5e83" + + "00d0db432cb256a4a0f9963a05694ffce3ecbd182209e0b7bb50120f6be4" + + "eeb9d268b17790ee14a2c887dc5753e0086630b3123734053aa37595aa8f" + + "31968ddae4991af4ab970c1e3cfa1146a2efd9dc42abd6af14777b8a0455" + + "3865691cbac4b4417b3fa13c154d581b498f3b8cb77adf0e42dc2f2fb521" + + "732447de97271e542c6cf8cad3ba0148cc3ba1f2983ead836a25a2c022d0" + + "43ba18fcd009d518d07b53344a5bc4d626b3b38405a114471f75dc70e015" + + "d11e8f6f57d087fa72909785573008b1", + }, + { + key: "1793bfda9c8666f0839b4b983776735a927bdaa3da99b13c9f3d1cc57d4d6b03", + tag: "bc89cfec34ab2f4f2d5308b8c1a5e70a", + in: "a09f661aa125471417d88912f0a4a14115df9a3a19c1de184878291acb0e" + + "89ee1f9d8213f62df442f8969a9a5a7c402fea09bdbe236fb832544e1f93" + + "9cdd4873802b2bb8fc35ba06b7ff96da6dc7efddfeeda84116bc525a7fc5" + + "2d84d2e63cbac00b122dc64f2d15b36595259d81a1d2a09f204c54072751" + + "dd812259df1104bb2d2ee58baee917c5d0aa2649c8a1503114501e6ed6fe" + + "239847d3d88dccd63d5f842426b600079c6bf06e80a2813b2208181163b8" + + "61dca07fa4d88254e84dac1c78c38397a016b5ad55a6b58878f99036db56" + + "89871ab3c321f6ed5895f218f8fd976c348b3f1269fcdf4d38c9492b4721" + + "6c45f499f5705830b33114d721f9731acf6c69fca681b74c2d82c92e145b" + + "7bab77110821d3a12cc818d7595a5c60c4b5e5219376c38a4dd52d435d41" + + "562802ff65ba2bba5c331c333d5adf194d29b2cd9ebb55927bb4ec17681a" + + "3f5574ad34fb4e964f2c756f6dbbb7a6876a21579a515263444de7a30a33" + + "15005458bc137ccfdff18a3892fc9f58f1de10d4de20bbcf860f5f036d8e" + + "8a188f18e5cf7ea3cd260710e7491befcb131d49a28dfb1ef688fd021a1e" + + "e4420d32fbfb03b47f5e85c37d91e49a1b0db85d966eb5434c4197433eb4" + + "9d56f2ff999c9a72230447032dc949202468261b48b6ac212e3f651d6c63" + + "03a06c90bb2d3a755ed91ba73bcdc28e1c5b0936e51e0a9f69c3ebabd3db" + + "add7abab6d8f6a44daeb3126429a01815f57444fb7022a4a510f8b564ae2" + + "dd9779b3a273fef15859a33e233724846c30d89fb78a595b6ff6c834812c" + + "00a991e405806aafd0c26a788895ad00a5e43c5426197aa8247207077548" + + "ee67db4cd6f878431a2e36e952d84b5fb89d681f553198e2c066310ea6ac" + + "3a31f5b1792620616f6c41d486fb844eeacc7fd36971abf416e8d6d50985" + + "c83cc92ea46ac37da8f0026aba30c945d8bb15080d2d95e4081bad626199" + + "3f95f57ed3252822a7caa035ae22a36c35e280cbbc82d729346cacdb1794" + + "ae9a9bb2793fd1d5c47121b135c2836063367339c5151b4e35278e97f62a" + + "fdd2f231d4b47812d083a829ebb9c374ff2ae8479cc4b76d55f9cef3ec6c" + + "4894f53e8caaeb0d8cd072960cedaf758e48e3640590d4f728626e0a08ee" + + "ebf719c96bf8ed4d0c283be09c0ae67b609e22d3b9aa6b03642854909de0" + + "5ed52b39673867bf586a632ab8072de15c637cc212cba8387515c9c9c433" + + "abd7ba6b02abd09da06a34694ad34f88515b65c0c9c247fdf9819fb05a1a" + + "ea4728c1182f8a08a64b7581cd0fb2131265edcb3d4874b009aede0e87ed" + + "463a2e4392aefd55e008eb7ba931788262f56e53193122a3555d4c08133b" + + "66020154b15643fa7f4f5e9f17621d350ede3dc70be02c59e40fea74dbbd" + + "7919d1a8d4e22ef07c916fa65e7d4b89fb11a7c24ddc4ca5f43344c753b6" + + "1331c3fa4558738ba7832b5b2a275bc9b7989b6e6888865793329806cd3b" + + "f0ba57c941d4428623e062f4ac05e7cd79ad5446f8838f2b247b66bddadf" + + "540845a1bb304a04b7edbbff579c8d37e2f6718f8690abd5231822c7e565" + + "69365ce532449a41ae963ec23a2a75e88307dc6b59cbb3fab913e43ed74d" + + "841ca9f6e4ef96dfd9f04e29e89361aece439c0b2e1943b30410a63d495c" + + "522ac3ec1b04ec4cb345f7f86969957ad750e5bd7dbf1d6a22eed02f70b8" + + "1cb5b2b020c0694d7f63044f9de0c3de1ede52009c858992d01ebb92ff19" + + "a9e0fbea18942fbafb77746c8e9e687dd58ccc569e767528bde43b62c7c1" + + "270a5721f1212de2b29a7aae2d6ba6cd173d7fbc78aec4356ce2e8ba9164" + + "d97dec061dd0c3a0e3c520a7611ac99739049dd5825537c70b7ef660046c" + + "1785546cd99aa400da848eb7c3c91247415c8e245d0f14c30d482c5849ae" + + "aaeab2568288229b08267818dae8f76fc674c684c99eb5faf88a0783813d" + + "f7298e0b50cb233f78471e5ca9cc3b04927c26a3871cf253798cc49aa717" + + "d8f18a1ddcbdc26497d188f15f86ec494dcf8f942c3e07e572385c6fa0ef" + + "40c0b625f1737543074a747a369482a0b342a08b3eccac9f9209be31aefe" + + "5a7794974f71ac0bc9a58026397ea3dd4f5e40511d58d2a3b45925c194ef" + + "13987037d736dd48b509d003a86471d5f161e0e5dd168b4f1ce32f703b89" + + "15004d8dfc708a5bb02b2e6fb67424b2cbcb31ddaa0114c4016b0917382d" + + "aad11815ff5b6e37d5af48daa5ef67cee3439283712bc51b5adf2356cb2a" + + "5181b8941fd78945c7c9d61497683e44fee456ad345e12b4258f15945d45" + + "b6ca4369ee792d849112d583fdb39cd4d333ee057355f0abc8d1eea4640c" + + "128cc1617982db0394233dbd416102eec1874081247d2982bbf9fed1b1b3" + + "8f4da923d68c8975c698f189a4d7840fd7aca9dceb7d91c076f85e1c546f" + + "4d5de4f60c91348455aaea30cac134c844dad93d583c139dd52b3be6346c" + + "4d2e6864125c5a2d0aed8f67930e1ebf8700ca88aacc914ea76ff17148f0" + + "777738cc126e75a2c81110faf02fefc47c91edbab7814599000ce55fe20e" + + "f313566e9b62457acf2f22e1141e220bd9d4747417d03e703d4e39282803" + + "386327fc65dd597f723ee28185c78d9195fc70a75706c36287ab9c6e00e8" + + "5cecbbd6043c6af8d30df6cdd8777be0686853b7c8a55a5b1e03e4431d39" + + "1725ff99875a85cae6926998723b36d13ad458220712209bfc5e8d2ca5d4" + + "4ea044d5ba846b4035e7ac7e9885f55d3f85c0c1b3d09fe929a74450f5d2" + + "9c9672e42d3f59be4ca9d864a4322cc454c2578493bd498a51bbe960e657" + + "3e5dd02c4a3a386d4f29e4578a39e9184024cd28d0e86ecac893b8e271bf" + + "ce3f944d130817378c74d471bd20a4086f2429ed66c5c99969fd8da358ff" + + "5c3be72bf356ae49a385aa0a631b588ddb63628fd162673e915cfc4de56e" + + "ae6ff7101df3b33125c9bab95928f6e61c60039b6cc07a66f9c733251447" + + "ef9c1ffefa2158a8ddf89dc08686a4cf9b86ea09914e79842d72a3236afc" + + "98a3afa0a1cac5590ab6a923e35a2ab8db6410a9d33cb84d1c48a054377e" + + "549774b25f50fbb343ecd5db095155cce9fb0c77d09752f62d4bbf16a770" + + "30452a75f6bdf73f7807d8f3a6bae16ad06b22175fee60549c22548de9c1" + + "3df35ef4e7bf7b66491a62b93c2c3fb0c5edc51f60f5704b56af30f1079d" + + "7c385b99f958ef8209e030e381d1ee8d67d3cb84f32e030e8ea2c1d0c77f" + + "d6b242a9f48707557c8682a08e1127f51221a55c733ab1edd00a9c2912cb" + + "36dde85f73b524e1a4f4da6414c5e4c18d9537722b2becc8a91bcc63f2b0" + + "9f32409c53c2beee0de6726dabcd6bf33118a5c23fb9c5c1810476efe658" + + "4bb6109c516b45e16b2f79f96755680374d82b91f2c519639a1815fd485b" + + "a3c00b46fbefeafcf25554ec5a6a5ae2da07c85b8a0f9fcde50263d9ed85" + + "038b2f7aadb9de765655bd201235218bfc74bcad6a9ddf4506167a649afa" + + "df400b85752d68a92b7a97f26b334dd77fce824862046b286a7c8e0adc36" + + "f713a252a673d4d995b268badf4bec8b8eefe85c25b823b6728582d35c4a" + + "60041114dab72b0623b99e2758f6a1e97365279bfba0eb1fc8952ca4f2c6" + + "fbffd9f5fd7dcad1125b18a796981b5ead0b6431141315898ace96f0d38f" + + "865698df8822ca7b65644b6b1f0a0f0d2e5850d4c93ec48ca3eba1b919e2" + + "4413a46d595ffa427715e499db3b7b9ab53c64abec7302bc737a5bd124bc" + + "da756abbca132f7f67e6989e09bfb23b497da31bf156bb9c69ae54588df1" + + "7420e8fe989f0472c8893b2bfe57cdae265a8cc7aeb39624167a567a6fbe" + + "bb1aa30c3dcfd14f2808a070994085e6e1fa79021e77c399f90ab1f995a7" + + "baff672cb693bd39b798b4c890b7d0a57978d6b9bcdc5bf3f4d205f8f24b" + + "2b43d3ae300a96971c9182be297618b9adceebedba1ab0f324b01d23d7e6" + + "35f009db3dbbc643c2d787567594bc639bfd78c4f3e6d948caf06f013423" + + "eb3c764666b58f886d5d28137c053c2a28535efcea400147e92ac6753574" + + "3b47f9cb48852abed1d057647d5b1c6f334eab1a813401fccd3dae332738" + + "776bb223e359f3c459b5c573ba64fa945bdd66c5ac0fcbd53b67032a7b80" + + "25f551e8d1fd2a4291bdb7941cbabe3a09765dc263e2bbb6db7077cc8fe6" + + "790d4bed5e36bd976d1e37dfdba36aafcdaa10c5f3ed51ba973379bcb8fd" + + "203d8b7282abbd271ecf947e54486e8653b7712c9df996a8ad035f41f29c" + + "ab81509f922c67dacb03f25f8f120cb1365ab3c1c286849c2722448ba9bc" + + "ff42a6b8a7a52f2c79b2bfcbdd22ef8a5651c18879a9575dac35f57d8107" + + "d6bece37b15d7dfff480c01f4461ef11f22228792accda4f7936d29d4c56" + + "cbba103b6d3e6db86e39e5f1bb9e9fd955df65b8a6e44a148620f02b5b90" + + "b2be9e5bb526d0ec75b1e723e94da933a356d7ca42d0ce8349699f730b8e" + + "59bac24a6b633759c88041d29399ce60a2ca2261c7eec1acb9a56e0e65bd" + + "e37653ce2cf7eb83a4d019c755bdc5d685b6394ecddb9006823182dd8138" + + "a1bf79a32d07a8e5e8ab221995c714e571b40bb255b79e328ab883542c16" + + "4899fffa16eb3296f310e302512352a864fd809beaab4169113027c6ccca" + + "99a92c6ce35c30f9449a3add70f10db1ed08078e8e6cbaafef630aab7e9f" + + "c8adb09c18e33fe1af3620d1e4d069ac11325e23cc18e5519a1ed249caf8" + + "ddba871c701f1287cc160019766988f63e089bd9bf1af7e6f5b9002e3b6c" + + "264d69a8bac16914ab55c418d3a8e974677cdcbea36c912e90386a839a37" + + "77b878e680c07c7cc99f42a7dd71924babf7fb0627d1f2cc60d9d390d1e1" + + "50d47386be6eefec9ddbb83b28fa7e2fd28cc3867cbe42d13b00545af8a0" + + "48cc07016ec79808b180e0b258c564739185da754f2e", + }, + { + key: "0d41cb4ac25217feb20e86fc2490e8d2ea2e8225c051252a9395cc4f56e1ae5a", + tag: "42df9f9a59d6dc05c98fd9e9577f7176", + in: "01caba7a19cdb09dc0ec6c522c61c628eacf17ef15485aa5710fed723875" + + "2e4e8e93dd4bbc414e4c5620bab596876dfbea33987e568ddabf7814b318" + + "8210a5f8d70041351e4d8410840642a29cc8d901c25fa67cc8f9664ea5e1" + + "9e433eaff7c722d0258ae112b7aca47120aa8af4420d4412a10732551db2" + + "cd3e0af6e5855d5eea61035af15a4d0d898d04033809e995706eba750a7c" + + "ac07aaa0dc71477d3020f778d0347f1a8e37c18540deb9ae967e734c0264" + + "df0e1f52b0b5334805579ea744c8784c3ae0c3ff8217cd3f53cb747f6996" + + "f3d2147699799e649061b205f97f7992e147fb20f21ff862c6c512e95534" + + "f03075e8e52f162e0d70d7a259e3618474427f400f44f75198edebae6e40" + + "a2173257d114e1bb5a13cf419c821eb124d90e89a938d91f4d2e70dfd1ab" + + "60446f1b602614930a329e98a0c30f107d342281db25b8f8259933e14d20" + + "8bbd991e42969e8b0600272f9bd408483cddfc4cb8dfe7bc19be1989c7fa" + + "129d38e1078d094b82e0a845040ddd69f220dc4aa2b236c44101d7da7779" + + "9827a7b037561b51e50fa033a045571c7267af93b96192df3bf6180c9a30" + + "7e8c8f2b1d6b9391767369625015da02730ad6070df4595eb8099bd8e484" + + "59214310cb62c3a91a4fa8ac3b3d7b2017d4254fb465f0a248e1bf45819b" + + "4f0360f37c9a79d405e2bb72e5c25a1b4df192cfd524d61e1e8b274f2fe0" + + "634c73f0653c7c9e9062c9d081f22a8b0327897eed7c6e870f2815bbac8f" + + "585c1bd868759a98dcb5c3db2f6c53244b9cc494a56f28a9ba673167cea8" + + "b799f37049ee7b0772972b3a6603f0b80eddb58ef03f916106814d72f000" + + "250b3573c97c5c105910d79b2f85ad9d56002a76a1f43d9d1c244ef56d3e" + + "032a9bab95fe3bd5dd830ad7d7e341f28b58c0440658f7fc2ca98f157708" + + "1c647e91432cb0739d9acdbf973ceb9b0047634d695279e8837b04dc5357" + + "f013fde3c55c9c53bf1d817ec59a1b18ed0ac0081ed9bbb3bcd1a5d3634f" + + "50f7506f79dc6a4ebfa640bf65682fe9aeca68088e276937669250064de1" + + "c19ad6d5c697f862114d0f81d2cc52be831ed20d3aab1e41fe6f476b5392" + + "af4799392464c51394c2d1a8325ee2e84f1635d295ee663490e538eb338c" + + "7126a8e731ad5c0becf144c7a9cae5c6493350b589385de29e1a0ad6716c" + + "346ec4f0a31ca5ea35c59ab6b099f65d7f0b3d00925a1da1b5777c029aea" + + "9679e895d7100645dc83f81d82a6174beab2357f7888ea640900cf3ee67a" + + "e0724a123919d78e70e05288f67e5e69ffa6f345be8a96e58bbe260184b5" + + "ec5c0c1354cfd516ebdb8d420029137d41b029641959cc07fa7b4e16b39d" + + "17f36b2367057410a42e0550e9ec1dcd2df4604d52d4f9dd1140d57af08d" + + "50e1527dad793b6d649324de799754f755818bf10e6d1ab614958dbb24ac" + + "8e2c01270a90ec3df4379c3f509b5ef721b0fd4f91a1bdb8127ae4dc74d0" + + "75f6cd8bb28319d6f8e8d8ff64fb4a42d646e9365156c6bc72cc46e9cd1c" + + "f9e735549e3df9a8e6b5fe541948b126190117db71fd1d61ad84be0f725f" + + "20b99eb141b240326d399976c4f2ce5823d94649a9580e1e8820bf49184d" + + "fc34378a60bea89b12aca69cb996c17847b7fb517cf2d51f16d78e3875ce" + + "aa33be15f6a154004f0e1134c6652c815c705efc34bcf35bd7743d28f0a2" + + "77d82dea4709dab41fbfb4e0cbc118c17aa00808872f0edc6437c357cd31" + + "74a02aee61890464e03e9458853189431bf5df6a0ad5d69951e24be7f266" + + "5bb3c904aa03f799fe7edc7bc6779d621cab7e520b5994f81505d0f01e55" + + "96e14b4c1efdf3e8aadee866c5337c1e50066b3acc039c84567b29b7d957" + + "683cadfb04fb35402acaba631e46ca83dbdd8adf28e377ec147e4d555a21" + + "e6d779d7c5a3078ab72702234d36ca65f68bd01221c9411f68f32e16ef04" + + "99a20c2d945fa31b79d9965853d38ada9d48eead9084d868c6bad974b0f4" + + "0956aa0fcbce6dac905858e46c4b62c0ee576b8db7d484a524e951f4c179" + + "decfc7d6f619e86dee808f246dd71c7e0b51d28bc958110d122fa2717148" + + "77823242711632f6e1c7c15248655ced8e451a107707cec8c84929beece4" + + "efe5503d3c1763d0ab7f139f043e26027d5e52a00d5414dd98a324a8fc2a" + + "06a1345cbde747f41099c3377b86bbdc5a17c8f6e5b773a761f78573832e" + + "4359b143810361dedc79142fffc49ddc0b32f225d50d360ceec3920fb0ba" + + "0693b644ee07fbd1ce829e223a02794b197614061c4bfa46112d105c2b7b" + + "4efea448501d146dece44f6640d674d5749db498b32969de6e165e705a18" + + "2aa1f3d8e16892b0120337640d52c9bee35e5b4b17f03eaeb31205c8ecbe" + + "1ae1b110023016e40ee87370a65c5c20bfb00f100d3c6c1de6e4a1c90162" + + "f25bddbf300ed637330206788a4ff96903f971c9618493ad074412af625c" + + "ff9e0f8f183bbd5e96c1f28307e6cae8b50cc0eb1a3a8154e44e9de947af" + + "002e4d1098d6b0ee3f2e71a10d03eb444729c42461283f37be8af2ce81ba" + + "bac246a05c2c94efacc43f0cf9ff3df38ab6fc1648c796ae7026ea95752e" + + "b70873a6da59da10d8b5316126431c4a17289466e95dc739c061d7a4b13a" + + "450809479eef421bddcdade77a6df133410328c754af8999a09b1a5c056b" + + "ecbb6fc2c339586ab92100f46d2fa1fa689994b36aa70703d76bf7738adc" + + "f0589fdfa6bd215339ad69ed983f62efce0add5a63fe7dfe4bfa006ff16e" + + "0cc06d39199ad60adcae12b75ca98d764502a783373da3a41281e03c2037" + + "e1b3ca7f7eb60e2b67427e97ec72d36670db7662c6daa505701fd279f116" + + "ac0ef569471f204e1531c25a4ac3ce19b6f68a8994b6f89b5abf034a6507" + + "32c7fad4206eb4eaa7cd9a710d866bf3c3f13c16faa268ae0cf4f69be909" + + "bb9b79aab80dd25101d4cc813a48d3f38d870f10ac0b6768005aa0e69e87" + + "dfc0424deef06414c9ba6f498c93c41c692a7a6221fb5595b390a32c70e0" + + "2cd64471c797ee8a143725849c1e054ee2043dcfc0b4cb1c00be21a14be9" + + "2d9a07f1b4e975d4c86b8a5c1387e6c42bf393e078fe86d24612d497e14b" + + "874485a3cc922b5b6d91295d7b79ab8bfa1c7f64b51e761d19bb9da82a5a" + + "a34aa469699036b6b2c55e2b84f84942f10585027ab07e2e0e562e0fc3dd" + + "36047850ded84be4416e22aa41c7a2f7d4a4d8e3dd420d746a1d8d56d87e" + + "5133a1b4380bd9a89500fd6d7e68a1ec02eb9e79e4a13edfdde1273466e4" + + "6b0e6a75f59ff6175716629da52463ad21de27f40fa2e25a566eec4b2696" + + "4af3a717dfb0170a73144c0bd9b00bed67ad8c0a146eb5a055812d071209" + + "c9d530cd4f50a41488c2238898dea8bb36b0f1496d3ea8c4ff8e263b367f" + + "64977679e697d88e5295bd97ac16a0420850d1ead9621e25a3f58925c266" + + "ef5246488b1c15a8fe0d8ec4291864faa5a67b2388b7786f47b6d27e8fe8" + + "46f85f85163e54155ef95cea4901e712a44404a4d3f27f28dd961ce36b84" + + "f3856770f07f20a2ebd34d77405beab04ddfc09770167d7d6340f494dc6b" + + "7e4c3df896bd974730193b1e862b58d4a5938e6e4ae8897dba8812924379" + + "e54f51a71364d39f76e24fdf2c6c704479ce85b456558ca6947b8fd76f03" + + "78273f0a7bcd1d860ef1defe4eea8fdb81c73eda028d82fdcb2248582ac4" + + "59eb7698a811e6c5823be886410f6b8577ff2e8252343b6ea890016ae846" + + "01c5894cfb988121059fd9c8fbc1596da470a149404fc67baa15383d38cb" + + "d17ac107b4ff3c1ca4c76b7930de02b240e7547d39f4978e0cc1fa37f8c1" + + "012b677f07bb4df4486196e9b0beb823a3827585475b878e3f6f0a2d3836" + + "2c7d34f9f3c91ed46c39cec95c2a0b6f0279a03a00ed5035b0725c393849" + + "cdb1ed3c0ecbcf3c2ce108017f468e1c3d469c03e8231d4195344ced70cf" + + "daa667252cc1554dce8d0c54eb4cf4da62367d77d7dcc02f81e788ce9f8d" + + "d306ba1b48192359cfe92bdbea9980f87ea0677d7d2082205a436cf514e6" + + "fde5eadd21b13dc836ce33b5dfb6118bcac79ae00fbb16d61f00a923b145" + + "f9caa9f3a2c7f0104f8b052e390987e57c8dc80cd5f0358afb0111af1fc4" + + "e31f92bd832ad35fd2e0bdf768272de52ce0b152f74d43a8973ad516b3ea" + + "f5937ec8a236ebc86adeba610de0cf7168453111f3c983b64df07678cae0" + + "a75466ae15adfb127328e716448cdbd2c1b73424cc29d93df11a765441e0" + + "0eeed72228e1099bd20569d9d0e9e5a0b3c11d0002e2896631186483db61" + + "c1a0cb407951f9b1ea6d3ebc79b37afb5a7037e957985e4955979b91fb85" + + "61ca7d5e8b9cdd5b7ce0130a880d9241027b011fea7696b0c695d4949ca2" + + "d0cf22d44b9fee073ecaef66d4981e172e03ea71a6edc7144393bfea5071" + + "2afac137f091bae2f5700bfb073a6d57fddcba674a899d7349044a10aadb" + + "2e7f547887dd2f765f394de5dc9ef5dbf1eab4d869be8cb68aad8e2614ac" + + "37bbf21ccd5a832ee09fdd07ce50a580a2af36256b1046e646fe3dff6d20" + + "0c5110f1ad1311bc39b8114cd11ecdb87f94df43d4f6468932fc0ed892d0" + + "3d8f3db3f8323ebb29776ab7d260493a36700bcda668abd62126a8189e91" + + "df2d2970ef688d4e8172fc942e69ba63941a36b79ac546fff38f5f7d1176" + + "57612a662ea38134e1090c3e903c9adacdeefd3ac2a0467e9f5125058c19" + + "7b2260d2afad2b0e627a9ae52cd579ee27168065658089e1b83a2d8cdb47" + + "e08966e4ec0018e78c4d267f9575b8fea2a42de5c2d25356fe4b8c9cb1ac" + + "daf0d1af4bf58b9704cd4bc08471e3b9a0e45a5693433ede2eb1374bce44" + + "1f1811cdc7612d7bb61f4f34aea0a44757bbcc12a55c1ba41a7901eb004e" + + "689587a38e5b4df4574ddcc7b2eda97f6e480d7d39f45247ea3b03c90a93" + + "0dd168b65d52a59ce9c2cb4e860cc6aaa0ee02a58d0c8ba990194bce80fe" + + "8c34ba5693fb0943ec2cbfc919e534cc47c04f502b6c217c2f860d1d482a" + + "a016aa02adfc2bea3171fc4e27e2a262fd37b824099aa227fccca508f778" + + "b8c6ec7aaff1d15f6497753f439daa9e52060fd6e9e056e6843d770fb057" + + "6d9e2e782db4843c0c2c7f408a17376719a3c5cf9fa08f04f8a779885a16" + + "5cf93ce404be", + }, + { + key: "ddbd5d6c5ebd61fa72b453dd849dc302c98a0f3e300f4768bf1dc698a3827dd2", + tag: "af608b71a353e63c64911558baa122f3", + in: "c67e2524b0de16483158a0232078fadcf611e4fbdb9e642e397b21222423" + + "cc2ed42ed34ffcb178448919ee337eff9d7d691f622e70fd3317cfd271df" + + "fe6a9d9b7e07db0d20813e2331164a654386db2ab06ae2983bf2460eaaa6" + + "3aa0171fb87afb82e85b40d95c8993b2039d32e9d38473dd13f41fb1ff1e" + + "261752ab004b221a4472b9b1a0e139f0c999f826a26a7e7df362b0611aac" + + "fa83c55cca2f7c0138d2c30313c2f6eb357278328ea6ebd6a5077947e18a" + + "a97c34b9dde3b6f2de4b83778ffcebc8c9cb58756691d5e2a3d15a759a2e" + + "5050b6da937a6f5551aec069a08027d60dd870d175d2a5b5f0b4f3143904" + + "7445c368a5c866370e9426abbc1a1c5a272b96731c4128aedeee93e8e00b" + + "b450601a6d31ea279b9450e738b4a47c0dc22d2d8ed5d44257f6318e0c59" + + "b951fb6b57746062ab95cd73c23ef0a5c000a7d14c18bfff172e59b6f6de" + + "aa61b81009e803eb05e24fb0b706870e18889a9180ac16a042d12dfff9d9" + + "1b88130f045d2342fd5ddc5f443681c31090459f262d1a65654c55251fc7" + + "d5a67bd2e62940ccd606f3e50700e4d1e992a3fdf0388b9ce3df9de6dda1" + + "5c1cd6b70622ac062dcb7ed7058872c00ff3df94032853927126cf6fa4cd" + + "c468d91c9b52dcbc272fd7ba920dcd3ea1e048af9c3286dba74d988ce9ce" + + "77174e25a87935352721dc23b60a9549322fadbe6a00dd1197dfa25b33fd" + + "9e5713afcfd0fae6dbcf27147fa58d995580d7e0a903c895752fe9819f5b" + + "b002ed752719552d0f3575312f2e618173a8ae7c147ca64a709053e5d2e1" + + "2f4d1ea337afa9ac4f9ba62760046ec1e48f4ed8f6df66786c9fd9f5bc7f" + + "9ca2526e1327b042f4657c405757690e190c91f260dee2dd3d2e6616b721" + + "e489c7c3cb828478a3d953b88f09904e7927cdf6dbd6a5419eeeb83c0be2" + + "51934a80dfe61e09442f0761aa2d013e10aeec3a32df204571ce8984a430" + + "9bbe30ccc91977790bf0305d2651ee450b749c3e7761534e45970e70a0a8" + + "473cadbc88f096970c275f188c9d2644e237fd50c2e24c1eabbf7578e80e" + + "6500762ac513fcd68cf6f8bb7a9d9eedadca059d9ecec07fe6fe7792b468" + + "9311861728dd482f087c28374cf9c5ea20b2c8630029e8485fa6fe518c74" + + "ef77d44eb7526ca764e50b5f34ed0f253a91fb2af6e59338e2af6e041e01" + + "084e1efade1aebb7d1b698ccdb8b4248ac89cd40d9517d840960c08f5e86" + + "88d8ba2b54889c1870d315498b70e0e9720f2c8c53a3377a8c0bd2d6a1c6" + + "f17c6ff847eb14def6855dc3886b99039e528b421ccbf6064e39263f8f3d" + + "340d5d20b1b14c264ac2310b5f3a0c6f0c1006d0d4f1a69af68d28ab447f" + + "cd17387e1fc98f164982a6d05dd32d6b4f0f1b04e40c6c6e0fb4467dd6b1" + + "0c5a9c92cc8c2bc97ef669b6d55cdd0aa8a15c46af954359165949012713" + + "4ea9f74181d54a300d3172c9f01db73288ef6a709c763a4891666d0baf88" + + "8531dcc77f0911412d096aef9033fa36b5c1ed283b8b5c109e45b5cde911" + + "6f3da2533fa0ab81929bd5783271d5501a9e4fce2aff9eb5a70a4215b253" + + "46885d7e4225fe34bb55b309a114a312693d60ccc61267359a8c2dd28141" + + "226e7cfd99f0f12c69df57d75dd790dbabfe3145f7fd1a24fa58e03bc2e2" + + "6ea19288af4929e5acc517d8f52a074745ff4644d94179eae6ba7d267292" + + "bbd2053167a0da9be5e4b6cd0a4200fcac5182d9957dffbefa857e662b82" + + "fc3a7cc32506e78030ed5c5d448d7f1b4fd854a735a0c50016bb85e6e716" + + "0f87527bca0de235f4b7dacb75be84919c15a5b8cf6bec035795cb67061b" + + "7855c2134c1b1bfa6affe04b7db239f73af6ea9c02bc9f7972b7f6400b6b" + + "838f4653aefc42179c21765e3ca7a5e96b4402ff544d4bc2332756a23500" + + "11241dc42ec6848afe127c00b9c333e69bb5a54ea5c7193e59ea22bd6d32" + + "af4f56b1bd2d5982ef7d9c1b02d7668525e4e81b68a400f7afc2653f0f41" + + "a03e11c7a02bd094830093481afbab96397245b9f37a568ea1c4ae248cdf" + + "afc87f88b1fb5dc300d8e9039af4e6e701b458ed3f32d693f2e869b76bb5" + + "1358cbbe5b5089013bf452734388a176cccfc1ae9b7cff603631ca48e129" + + "b5c9573d4e379547272cce8aeeeb407d3fc57f782a0eb5fcbd41e6fb13be" + + "7e4f1067cd407b42a6121b2969c384916ba2b32563e659f52aae09c8ce2e" + + "3c500fbb7e58be74cc1592dcfacd9f0d4cea1a90a18658147c81cccf6fb3" + + "078ed27f369e7646f551386a74e1b07074d93e0c1f298c761af46cdaae9f" + + "f4be86808b66d0e228016d27a3a77c843365cb847fddccb0bbcfb3b9008a" + + "1bacac59ffb0aa759a0568c72c556caf0ac1091431b574687c5fc7bd486e" + + "963e0fc3bdc828d988734a21070747c955cf8dba2df1c3a0ba8146cd58b5" + + "91b6d54712db67a9851b1607c8445bc97406eeb7488f5f85e547850d619c" + + "407f97632ca1801f52c09c2b314b4ab0f8e7fb5851fd60852f4666913ca6" + + "bc840c1ec8f8f06caefdbfbf02ce00f20b87b14ba9e651c80f40a31d0306" + + "403f541776075fbf23733a6b19e3b44d04b455b29ef8effa70cce0c59331" + + "7119abc07aa8c8d0246a760b0b36a3d87b244e83bae8a745b8277a531298" + + "f5d0283498a509c89898ddf0f7a7455be1f8a6889c46d323f1dd18c3babe" + + "1751a05f871f0639f50967afa46c19cb93d9c2a79c81e2436a7a62f225bc" + + "37c90698640f5b43673e1dc276de05ff1e29acdb4ace5121659db5f23c49" + + "57aae22f53e6f2cc935824fbd07c2ac87672eeeab895c3f06e09e178560e" + + "2fcfa7097f10201dfb8b1ebac08ca806c1b3ba3aff9284846a1a3beada53" + + "e9f7ade12eb89b5591f462b2543bb4090e081fee9fb53bbf821dc92d6b16" + + "fe820ab2ee4b1f6c0b6a6f19edb0bf6479e257fc73bcd60dc2261d0a4752" + + "e23a0be18abf355f3065177d8c3c14e21edc178d0abd1b39f703e6335131" + + "ec90cba3d9846cee7354a06c320a3f61b8a269abc7138831614f57ca6c19" + + "a4a621142889cd924bf4ffb82b57f871b854f3157e8874c22d43a5726900" + + "bafbb8f2260a1eba3a462e23d4def2ccf68ebaae8e52739a1ce67c039eaf" + + "9a6c3232fbb5a91d1e59a8dcd3798ba71345fbf83d09b83b41cc49d5ff5f" + + "2e809d2b1d5fbc1e7001ea76b9b2d8f896eb6609e2e1c5c562d2a6e74960" + + "2d67a0f6b43a201d5087509b8dc7b0440144e308c18ff8b96b607de2f20c" + + "6ee99bb05367a8b25947011889f724965a2b5c52c9db1e0622df9343c548" + + "d054699badeb15fc41055af0d79a2bfc1a5b4574634fa0dd9dd10a6213ed" + + "b6991187dc560facdc27440456a0a209fd7f5ee4fb350ae71f869723e5eb" + + "5338e3d1448bc993afca6957f4cc7b047a2c7c9593b7234725e66cc0eb23" + + "3824eb4cb905701cc522ec210950b871397c6c0bb3d0b839f2eb1a120f70" + + "36107246df4dfb2c24891bef0bd1dc131f2c9d7c295ee967e3184d963037" + + "fcc9e0b8c7011c8e04b4e70038150d34caab4f8c0230418cd2d8a91146e4" + + "4e11cf6707452ddc03d9b4e6380658135dfb48f62c0690ebad75167f4dd1" + + "c0df3ed555b5081a7b82616d9e501757c83c2193d0f640236d59f9c97a4a" + + "5c8bf532aea2cf5964ed2dbd8a70c01ca5c7677224cf2a37f3b24d8fe4ba" + + "91cd3b5033715de227de51deed15afb8eda9d2b9615d197b8f98322d7096" + + "79c5131eed48050fbe0145a9284e236605c25a4876e2adba42f4e35a8949" + + "3d59bbf44b3338d9d2e65a7d7ec6c863cd47cae9e23181b07298078a5e9b" + + "06a5c7e1059f474eb1a4247e8f02cdd4efdca67d22035b12abecf9b15982" + + "de4932a28e797bc4de38442cff2cba263eeddba0ab14fc706dbca04eaca1" + + "b4cc13000a10e35b32461424809b299798e4d8e66c92aa3181c5df16ab65" + + "9611cb625e895a8021af8c60960227d6f2ebeacb17b13536a5ff139734ef" + + "37cb67018ef9a410b856e6f6eddbe3f59b088d538c50a8f3f0912d06e47b" + + "88d773069aa759cc614e1f53cf6e572c127123d1ab56b79ee753a921cb22" + + "a60e4e6cae768c9966de4e2625484f2e990154da7fca84b6e6c0b59201e7" + + "fb8a729cb20b4c774381e84f1bd6e304543d952dc76ef741b72f3a4ca7a6" + + "ea7958b8b6337994ed82dcf988eb70f509610b9a279ab4d0f28cc2b2dd99" + + "3b8637a6be0cb4b5f67c79654c6b15e1b61120374ba9b974a628c547f11e" + + "52d72d39f8f9c5dbfc23a89f22d38984dd8d5c3ca72cd54e6adfe2b3d163" + + "86afdb50967846a4c311351a51e5fd322757bdb061d44c8796a61fa4db36" + + "793bc11984eac83bbcefb40d0bc7bab0ca81e7df3a7f58c6fe800396716d" + + "832acaddff6d72c8e19dc9ea838294ead800deadb6bc18d3e399fa76c46c" + + "5d88ee72a86a87399423b0578eb6e27d78156ea2abf6f08b5cbf747f2f74" + + "5301b694bfba84bfe3c5527acd50660eea5105a2644c1aa92f954a604fb6" + + "a1b3b2d0331497deafc3aaadc7040b9188a36cf607ee85a0655ae963fd32" + + "91dd58f8bb50b4e46dcf7c2957639bffa6b12d895660dc0323b7a092f999" + + "813380b820e1873c60d3e3038129c66d507862100a5d5842150869e7873d" + + "6bb6ad022350ffa3813aca26c80ccae72692bed9c77c9d4da23178c57153" + + "90b5f4505240a796ec9d10a7f280bd60a570b1b693453807707651fc0464" + + "03e4768965a6f42f112152942134f0a38c84137c7a6e086ef1ab9ad20d24" + + "3b93356b305c0996ab7d02c02c44cbaf8f7e60b8c0b8c9fece3f189b099d" + + "dbd126b7357c1c4ea1c8bc1ad93db91ea9bf043a4320acb60b502bec37b8" + + "6b2a5004b8225e549e613c6f83b97b7e4aeda1b013e0a442d7ce2f14e78e" + + "a94bab700c9ac0abba945e28f39fdadff223c4498cb204f01ddfcb450a41" + + "f32ae47f99a49114c6646a5cb103e9cd75f9d81dba417e48c4053e3b0295" + + "2267cd30589b0f5d993a5485a6ead1ffab9f2f4294c5853ba76383a326a6" + + "a42fb8b78948aa49f0f1f614bd0a3fbd2a58a3197daf2094605bd838285a" + + "1260f1265dca74aadd95652632335fd17cafcb73b202c3f0e5da836c2dcf" + + "2934f005935dca80154af43fa34c8ba440d1581b74ff17dfaca369dc9aa6" + + "734c03916d78e1b952691cef918fe033d33f7f4323cf724ffb8cd6c219bd" + + "046e9f268eb0601098e93daa59dde370e46269dd7c54891f71bee2829a53" + + "df86a2c7fb1046cd7c98fa21cd83597be554997a70acebe0b6e60f1f7098" + + "6f65adcae24385cb7102bdd3e01300ffd15d00f9764b3a5c51e35e5c9cdd" + + "da84f4b656fe514ec4ff8dcd774373f8a9103cf36abefe875f7084b9bbd9" + + "42e0c997ec2d860a4b622ff1a39a628582fd81f237d3d8f6843d26ac77cf" + + "bd48003e8e8c591ff813a9a897e3149ff0297ff476299d717e54d885cdd4" + + "4c3ba6ebf54bc7a1", + }, + { + key: "b15578da1020f662ada0ad4f33a180d9f8ad4991b3720bc42a22b52625c7414a", + tag: "b0e4ad4a010afd6dd41ed82868cda555", + in: "6d2afb7a9154064341bdbb533f11990d4987e7c90fbfc0167c1e58d6efff" + + "6010f7ed569dac62ad37183b0d384519ebed0bf9c6e05a070b4858e6b846" + + "547ab5e45619c866f83cce83dcdab6a8a6c36b115ac832de1c6d433b94fa" + + "35803fa1a36f1ee114f8632402a027a74ac110394f32ec4006beb0057f09" + + "a94dada8bd0d1ca9a14b1f2efb8f526d79d6438bbbaac0ca1a43935627e5" + + "d129d52c06bf6413af07513bc579447eccc3a9406645c94dae59dab98d6a" + + "f92fa90fd4efaaa4bec466806ed401d2083cda587139ad7e9ee2adbb1dfe" + + "a88b59dd788b954a0f52c3854a3fffecb4bea83debbb2f5f8883e6415d3b" + + "ac1b872df1afe185468adc59364c173082f1dd6da9d348f5f5ba2d216243" + + "23de1f623eeec875bf31d12acec40dc0c1b9562826f3105cdad4c43cf45d" + + "829aa8b14012c47847aef7a2a6e3935fd972235f5d3a7ce4ad3582785393" + + "602e2e27329914021eff38ed2926c88acec1551f17a1b818fc1c3ed4b3b6" + + "6825d55bea269d710123b52e12ca9520a069d9c6a21df3a0253b3a4a6a8c" + + "dc226d667541548834da6bdbbdc165f39e40047d4b647c507d981be17b3a" + + "836063436241a8bb46b11a2867b621413c42d838e4578b72cc1982e34bde" + + "c303b5575ef4b8dd9fea8ed5bf69539413909d03461d3853b5fbf714a61c" + + "769569f42b38fac4b849104e2f2ac1dad0e388646278789f83e0b0511571" + + "019d3bfc5b03ca4cb5564e4e75e103ea1b6000be6588e27105d7cdc2d2f1" + + "f680ad34ef823ac4bd4068146e9997834665aec7dcc7a82ff28d85d52dd6" + + "9c18dd35f326bcf709f74df5981bb90ca8e765fef9f0698a19e12220b287" + + "24a6d9e4f4c7ce93f8ca9a126689ad1df820072557ce3db246cdf41599dd" + + "44ca841bece6c7869358005536e1189aa86b764e890ef90970d6e3831def" + + "fa890bf8692381123924e7d9df804fd770a0a30ee97d5dcdca302833efe8" + + "1d4b2505b17382f0b3429b38c41269ac95e36e9f5a1dbc6e6c8963741917" + + "02a23198decb4efe6809fcbeb5d0c9098a4c300155dc841610e55c8a6e27" + + "2a38a39de3d8ebf38a750af25836ffb1bb7822bb98886280f0cab6838c01" + + "cec57961bdc2e1bf158248309ff9294adcb962252b1c24646d132a3be2c9" + + "1ff82e8e101facbdb807826cc9d1840a90874ba08692e808c336c9d280ee" + + "f36a43a75c746fb864f85711e802546ab5cc3f8f117904ba1a85d6e4b729" + + "85122c5041891e16d55b93d6fc1b7fcfdc80ed3d72d55d64b8895bbf2f8e" + + "d188684e7e89afdc1e6a7ab9bd1d3da95d68698df2cdcbb2e1a4ae70e2fd" + + "dd4760f9e5cf4255eeb1e9e8009ab507395bacb8b2177e7c5757ad02baa9" + + "a96db967d20a150d2dd7f3081d90675fe0c82f94aa3cfdf6ac5585583901" + + "7a8e122170cc817f327a3c8ef44acd6e4fa81b73bcd0bcb5792eed470481" + + "152e87f7a20c3f7c69d5a8199bf9bb7c7269b450dc37a9b22102acaa8438" + + "134d6d733d231cee9522f7d02fbb37b5818ad3ca72df4752230ee11392ef" + + "8f8219be55202bc3d476f5a9078b32fb63d42bed4cda5ef90cc62467bf5e" + + "418ecd9d5d0cf1a33eb9a930e652ce96057fef40b65588aac67621d651a0" + + "9003dbc3925912e385296cd3b2b386a44113308ddf2af52ca390487eb20c" + + "716b76d78ad45129e7c285d918de7107ea8c3b0cfd9e73933b87c0b2b505" + + "cb4c95794f2ee6d6d43e2e76026923a0bbfbc3bb22df9ad729452283ce62" + + "dc9b26684fd45e07650581afd73713a708869a069c58b599ab478974f206" + + "dbd3e4e563e346ff1881723c5fd440bdf9f70f761c6f746113397d7c04b6" + + "b341d7e44de7de0aae79badaaef5ed372ef629dffd52926110683ab2d4da" + + "a4be83eb86c8700703a660edd5a5029f66f1581da96fe1feefc970ab4086" + + "a83ae02e959821967bd27b3b629652f5bc3db2b7f1af674f9f3fb3a788f7" + + "88e6dc1722382971831a7ed72502f85b25888c1534d81c0a4f7351ecc40f" + + "4e0412e05718403fae5746d313a78c80ac297f1391ad389070410e1330a1" + + "b07d683d1c795bda74bde947f2cf0dc9638b5d0851cda27df030403816dd" + + "3b70f042888c9c192656cc4b9fea10b81b5347900d9199c8f0f47d42f2ee" + + "482b68acfa5ff47d9950c950a926a497d94c6a796e0b715416520bd6c59f" + + "30217718d5f1d7bf7c24039f6467214ac8783cf011b25c37c67dfddde426" + + "40afe97f94879f4586954737b86701b32d560f08caec3fc45184bc719c7c" + + "5bf699074fde814acae32c189158c737665a8f94637068322f0c23ff8860" + + "f1b1c1bd766440afee290aa6f7150c7adefa6d72a738cd2268da7c94788e" + + "bb39002e9a328a51f3a92dc5c7cd9e4faed5702d3592ad16217c4978f84e" + + "af0fd2c9e4c6f4dcdd9112c781eb41a9aacb0f7935bb5c92d41e67cfff6b" + + "991ccefbd667ffeded1de325da50c33e28e2eef2f636c9726dc5bfe753ee" + + "c7bb6e1f080c89451f81bc8c29dc9067ce83deed02769714fa9bb477aca5" + + "c09089934674a0cc8e4b2c3136b2e4af8040cc601b90a4dec898dc922ca4" + + "976ab5ae4ac5af93fa5b1854a76ac3bcc2090bdeaa49ec4f319cf7c7b674" + + "6d8e617abb3361b28b27983dd1b139ec4f5af7e116439d7ecb16534817bf" + + "264dbd8f59e80b443be12c17fa013c7f4d029504c9bb62b296c2326f4f49" + + "cc3201b70ac3f62abb683c630179594a6d4cf30fd55b163bf8d01986bb6b" + + "cb7050fd527f095c45661920268e56f760fee80a29c9d37b7fc23f608710" + + "1e723038e64ee1b91c4849d69bd95fc9bc24fc4a234f4855f2a203e3f699" + + "c32698585c83781677739f2c48697c93b3388dcc64aa61f01118495ded33" + + "21ef9a1c949481f96005f8d5b277a7d6a0d906ec304cf4292df172e72d20" + + "29ecdeb65f06267a605f376804bf7bc5b82d5c8facfe7e41dc10806d27e0" + + "bcc5a341d80b3c1532407f75088716d732632cd88b0037f0d829bf385fec" + + "b52a202956489f61f16b0f4781bf59068b33d7330571d0b4a6ed91830258" + + "e1220b308784fa155be9bc821f5c0009a33802fa66dd66d1dde997dddd97" + + "873ddf65927dc1be979af2b5f110eee627dc1e210326ac20544a757ac168" + + "1823f3dd04b1ddc4bf96677a0a87633994e7af2ec99b7d5dfe44c6192be6" + + "a6e69d17b074256da3947808fbf68c7506a7e2c99e6b64d1ffadbd6285d8" + + "e7e032e24d42dde0594bf03fd550be05e5d66c91a660cd1ab7cb1f43fa9d" + + "69885203a7aee35a28f117427d7ac02b742f53d13b818f8631081b1730d1" + + "5b4e1e283cc8e5c4fc3b4652fce05fd8db821f99fcf93e6842816a549791" + + "7f6c49cc53d733788b2fe3c687de58bfe6153c70d99380df1fd566a7c758" + + "8052c62e73340d6a9eccd2ed26b763d518f3a0c4d6362212fbecebb4ffb7" + + "dc94d29944fcc4ab37725b105aa7571f364146782356d8ef056a0be93a55" + + "0c890df8fecc178776fe40703ad1bd2443d92c420be4306d99686592c030" + + "fd3e2230c0b48d8db79002e8a832ef27edb53a45532955f1171203d38414" + + "b4692e901e9f40f918528fc494430f86cf967452f456b01846ac6a383fc0" + + "de2243c7d804e8643aabcb78e2653b145f400a999670217c8da43bbb9c11" + + "e074176424be0c116c304a420120138e901eca4b12ce68fec460b23bc0c7" + + "765a74fc66cbda0e503e7b1baf5883744e468c97c5f1c4b0acc4b87de9f1" + + "4b537405dfb28195439d1ff848d9cd28a8d375038ebb540a9075b7b5074b" + + "ebc18418a370f1d3ac5d68f5d239513002ad11bfc2b7ff53e2e41ccffc4b" + + "0503acc4967c93ae8590a43439b5e7987d10cb8d1957bd9ef717ee3d12df" + + "5d6736c1d8bd8da102337a94b7d14f830f6c403cbaf7925a8a2a7af1311c" + + "57224967a38f6ca374013a9819c55fd2e2a5fac4f2490be5b059f4cd9c60" + + "2d62f80789eb8d9ab893c7f44a4945e41886af218179dfa754bbb59aab68" + + "13b71d2202eb8fc8a425625d21176a28a620e21bb0dad820c0b7051ce8d1" + + "3a33f3af0958bb6cd89f9d6414ab00ddd1d2f9fdece9183d0c05fcdfd117" + + "10d250e4b2029e6992a88293d0457e73e5b1b6a1aae182c69b9cb664992f" + + "073595ef68117026ad7ea579a4043cda318931eee7b2946a34cdc7c9755f" + + "80cc79a2bfe3ed9c79dc52faa5126b824868c965eeb37e9e4e6a49600f3a" + + "cce93c0853b546edb310dcd16a5755f15b1098b2f59dbd2d90e2ea8360ba" + + "f12108236e854465456598ae2f7bc380f008f2e3cd7c98c87643cafd7c36" + + "d40e2597236428d46aa5b260f84b4212d5e26804086adcf00363ce4becb4" + + "9b57eb2847b2f18ec82c99714ad4ddfe4ff3bcac1d0fcaa32660a1dccc68" + + "5bed83254c8e2ea0ae3632a70cfbcbeadef922d78a006d43ac7ab1f8a609" + + "c6e0ebc3ca6bb8430f1a562f41010db74b9febf931ca794fa08d1bc17780" + + "532ae76f25c4ee679d788835dfa4e70ca154c9e2865c3750ffe7b837eed1" + + "972be058fdf2bdb3eb301867bb132306c7aa237f6771d60bbc56cf31cb30" + + "32a87204d454542de747418470025ab84935d3eaaca01dbbdae9ef6b5d3a" + + "ca62ce9f871a3e1272b2b671582c096a349c00f32d742ddb17993994d8ae" + + "fc178cbcf9abc03114ff2bf7db8f757c63d6898faccd822f5c2e9a7570fb" + + "9cfff148570888be24ae42644c1a5bebb6f6287147a4bcc01c7675be9e4a" + + "897519dd3132a7cc2e778f8c90d23dc8073f6fa108d7ef82d561794bd9d5" + + "f1faa306334f338ac3ba99c853f79c24f7048fa906fde87d1ed28a7b11c0" + + "66a3bb98f8d21055aaafdf7e069b77b60b3d5cbe7c5e4379c7651af955cd" + + "82a19a09caf36becb6cd3fe9e12f40379941542709991066df21b7b12dfb" + + "2416d83fcdc33bb583e3b42f24f53edf8dc7c579ad3be831c99f72bf9fb7" + + "a35b6562e824e039e6bf1adc8f5ca53846de7bae11c4317e696d887df33c" + + "525f0a9c01fc29f2c26c90b85fe82ed8bd50954cd4e9ac7c85c7f3efec75" + + "da1da4ed173cb695cee295190527edb3cb06c5dbdabe0228cc60b6455153" + + "76244f27aa56da2db10f2659090137ffb82c57233c833e0bbf22d6f647fb" + + "97b3652d2888b3ab08010b8e8a6967d560b747757806736dc98b78226634" + + "f1eecaa4a2e23ba36591acb5737d735c5bc7a2e36f1a46946927e061fdf7" + + "7a3b68ef582c26b01f5aa9a438ecc26c6941221d1590c838072f9e471fe7" + + "fd59dacb0d092d40d76ea2f7c6e954a132a015bd4cb31147f3ebe4518322" + + "916438a62836ac85a4cf4492190a85bcc8edb37e38b99ea552d749c30f74" + + "ca20c298165e8ed02d4671e0b41cac3a32a345b9349ad22c2a4bb2c16a4c" + + "e0613ca0f0518759f7d2b33cfad2fae764f410d4d9ff8a76ae02a8107e7e" + + "01d9cd0552676b85ba002f19c01ad5f416d1d08bb84fec7c3555b098dbce" + + "48e1a5d847895e54db9c5b80cc22d5b87cd41a1a94be102bdd45a3cda5d1" + + "181e10446d213d6b3fdc350d486d2011d705c5f16ccf7519065c47bad7d6" + + "89c71e5fdf9d04bfb91eb1f07fa0f001009c1d4b1f6a116a570823a8580b", + }, + { + key: "392468efccff36dade31fc1c62eb38bb61394fe448def9d9d9beec2413ddb418", + tag: "e1122e7c8e6965b90addbd46d8a548d6", + in: "6a13d37f0ec933194c227351f4a19b507d93465b1f3e88dcb5f1ed1262fa" + + "58ea99ff31e6fc85c39c04129fa69195b71b2060122fe618dd9430a63f97" + + "54b52a80b3cd099f248f91a468bae211a27bdb47ba005d29881ea5143a82" + + "967c4c30c9a4f0dba1a4975e6407fe296d40023a00efa06be763f2d73d46" + + "a2901ae28b3d8ce18009a462e223b71476d7b954c138e177d15a390847de" + + "96a7f7fd0598748e86b0f08e64d915e67c7e3cf936f3dcd60edebd36e2a1" + + "d65b6ac29530c48ab3bd52d45b4f938a19b9b31e2911105a8561600d5377" + + "905a67112ec28025aa680350ff85b808c5b4c98b7b9567d03f5ed3911ec9" + + "365a8de4b15ca62adaa69e5ba710eb1756a346016c67a297d8624f9f1ab5" + + "b3fbce98b141049f0ce26c85d2f8a9cc6ca8ab6c6e148be968931430dcc6" + + "2bf58ea9698ef52a5d271cf48e6748ac9e04bc7ae7da205a1a7535478322" + + "d820eca146cedf4b2f9aa9fcfd77ab56a7276977401dcc1f96baa1b607e0" + + "256bd04ec324ec67a4313e2d5a53d3a3fb5332927929b20c63bde805f637" + + "eb1050fee2a152a0405634f55c48a59fe370d54b2ab1671dae2c7fd92243" + + "10627808e553127c74f724362b4a6ee49b697daae7df3ddc5d2ed9d6befd" + + "77fb9f68fe3041f6ef13f46f34ab682ab8563e8996344f82b2ef006a8d54" + + "3dd9c1db4979d7da97bda45e722065f8a238f0873217b783a9a629a12b3a" + + "4de437445039997bd243efbf5e3b6059b9459d395290efb9081c632fb694" + + "81000dc74c395cb507422df181aba20f776ce3fd8765ac485021992c98b1" + + "67c68805662cb4356a0ee7ba6bdae51ac10cd06bb5b2f3a72841c714c8ed" + + "bc56998fe2fefb9bf69e172fdf54b2ab138ae59372c52a67e93882a3000f" + + "d966992aa2250c6ff93e9cac89645d70625d79332ade5dab7eb1adbe7dce" + + "5a013fb65ad32fe22ed16fb9bb35eca1f37a0433c320e8752f8fc4b7618c" + + "5e4df2efece832e259ad98b895c474e47d0e3fc488bea8f717a17de0dcf7" + + "597fb8fe12e62246296f9a887dcc3a700820c190a55a4931a7d44bd3bb2e" + + "ab6c8a8126f1be93790cebabc1d69e01796e6cc80e7c16bbc82fb333fb21" + + "c774ab7db843242838e82d8e1cb8ccab385e67a4271fe7031d74b6e8edcc" + + "8ed585d1c05a365c7665899c1dbc561151d3b44bceace77c4f53c0e0f6f7" + + "74d42f9ad3e56f1c2a8d53879d695f895690afb4698472a3d52d67159313" + + "133c87823fe0500eb68fe286f8b9a2f59f12785d026dc97bdbf793c7d1eb" + + "155f1f136aae66c256583e987f718afbe733e0a5ce30d021493fb84e2242" + + "5b18754d126235ef80335004fa84f88361a584753df409360cd8bd45bace" + + "8f48156bec66577bf2c685089f5ac7e7ec76c0df068fbaa47661f8517f92" + + "e14723b3b278f151816537a7212c96bd340a00c15c9c9bc9a2a5d163655d" + + "84b38073e2be9217cad97d362d89d4baf3ce0a8d8562f19a8c97a9aaf5e7" + + "77d60456360ffb77b30f177d2809052020d141697ecf9cb65f42b9190caf" + + "6540b2c82f6e5a8482934a6a1a5711a8c24546cd8ba432068404eae5a827" + + "2e09efc3c6037af4feaac0a46329229b010ecac6b9f077a9b076bb6d9ce1" + + "38401eb38d124baa11507a994185295020bf9b754fcf78430db9253f5929" + + "87c46c0f8589c4e463b15a3840b1cea795e24cf6b20f29a630136e0589b3" + + "8dd7fbe5ea21da72c88bd8e56473586822aa3765660a45a988df9b8eb8e8" + + "141939d3e4cc637c5d788064d40a9f7c734e43fdf8d7189a5d76700d9743" + + "fe0122944663afdb88c5201318ca782f6848b742ddebe7463fd4a32280ac" + + "1cf8311e9137d319de05ce9cd85abab24c5364041c14d3b4ce650400498e" + + "122166eccc12784b7ac3b262ac0b198ffc26eeed9a5da5374f7a2a53c87a" + + "78c217ea1fbf8d38f62511657b73109f31691aef14d82ce6e1010eae9e6f" + + "a419e5c1c16c0cc70651eb3374c03549a1bc7d3ed42d60f886102c798dbc" + + "ba56f0a2b3b9b412530c35f5f7ed06311ee14571f9c26ed9c81ef38ff000" + + "2f5ef3aab7351e32049a6ef8f48a43da1d84402d229df513dfaf1b2e4043" + + "6ce68c70ebeddd7477c9164f0dce45a6fc5de050f52ec269659d5854bcae" + + "f7762ed7400713c27a4d523eaf8c136c4a1ca00b9e9e55902daf6cdf8528" + + "c22ca1f2fa7ce87902d75a6850e1a5a4592497be1bb401878f18b189b0e2" + + "c59d10705bfabde3cd2da01eb452006b294108d5d42e88e9e15424d8cd0b" + + "8ab43a6c546b3dbf52e47b59cde6a3e417b0395220b6d63736d429da3458" + + "9a2524f1629320206fa7f1d8a041e17222c4a5814561937e1030e6375c77" + + "9dc988bb928bbdbe2c2eb20111639725d82b5d7192cd3e4acc27581f0ba7" + + "286cff41f97aa5a52ea0083de5057fd2ba985aa738e4d03fcf11ebab1d97" + + "e2ac77d1c2beb8799150a421a07b3777d0b850f24194b8309135b13da6c7" + + "e38653a711e407a1811290fbb7bc15d8b12efc6916e97ead41e042a44721" + + "e9cde3388073d921595bcddcac758dc675173f38242e65e4a284aaa7e8fa" + + "6adddaf00bc46428ab2d8601205b8895bcedfc80ca0aa4619ed6bb082ddf" + + "33ec04fa5d417f33fcdd238c6b11320c5a08f800e0f350b75d81e3bcbd15" + + "58a1eab87a3c8c2ffd7ba1d7e754e607cf98ba22a3fc766c45bd6f2569b4" + + "84639e6611714119d188a24a5e963089a16ed34e20b9f154cad8ac6031dd" + + "7a3a885afc2ae5e003ae8d4e4aabdb3e51dfc423b8cf4ed9ae2010072cbb" + + "b1108c7da1ff075e54ed827a0963ac5523ecdf3fc5eee7b4d1a6773764ec" + + "5c30f41690523fd70d895edb7ca6a1806d54240c4c7b43410da73503a323" + + "90d9070ed30da3a2fb5eccd40d083be7cf8bf40b4279f819cf795b6f075b" + + "5a67a10a06a6076d0d83c72efea05f244901c4b5fd9eb380432519311baf" + + "8c81f6325df4d37ff4d30d318f904ebb837ec76b341dd00a8f247cf0bbe9" + + "6f3784dc8f5feb344958fdf1a9ececb105f8770826db1f17a5281e997951" + + "d3c60cc28fc3e66ffeb5dbac315f98f6d240208043f28dee963d843e68ab" + + "57d847f76ae2f96ce6e37f377ef5dfef2176ecd7440ce4dadcec2231b606" + + "e4a80420fb3ed135640e1f05d6bd58b8dce062dd7d36b885d424f6318e5e" + + "a0753efbb33bbc7360d2b5dfab3ae0d5e000b8d31f2ba0f5fd8b34f96b55" + + "28fff35e769461d0f03cf3bfdf0b801dcbbf2838180cb9b108e06c353e3f" + + "0b9ef61678cfed1ea37ae76bccb5ef5957ac2c8e8f4794c8145a15f1cc88" + + "bfb0881080326c481b373c3bc9b07a9b60a0c8bd5fa4f6f90145590a5227" + + "6fcc0ccc2375d0ccb571d414d1b0c38b4e02c39db4d701c5e25e90785ef4" + + "d26f35edd8c4b96455bdca7245cfefd9cfbd2f319615e5fdf07bb9564fa0" + + "44bb35a58391d02e3927780b4076bc0893dfcb4b63a32cd7a541a4a8c253" + + "0349c6e96e378dbeb66dedf87d813d0b744452c1c4088507dca722193827" + + "9e2dfa24e4a409de494acf654f44262db9206a7717fa434ac4fdc6a6eb5b" + + "1fd5a193b6043bc4327c8c09fd6822eaa9df37bbcac1077754a295621601" + + "267b68733b62dadc2563f1700af180141f29899e2689dbbe9745ba8477f4" + + "352921900b403a01c9dd042a8c1b0e0489959fb0b0a8431c97b41e202204" + + "212ebfa00c593399dbd14d7aec07b8292d2e40b48f05fcd54a15da4a24d7" + + "2759e409f4c7b5b98fce4abac6c30e4872d92efa1f96479ec30f21699825" + + "50fa60584f5a09051a00f8e7dbb3853e66ca3f05fbfe43bef9b120a25a01" + + "eb436ba8ecda715201eda72e517d628f883386c1503aa8b8e75610f7155e" + + "9f916335ab6d6f0f9589b6220cd2b81c2c937dc065d3d14a7df8cc916cd0" + + "0ce1bb53fd9c8974298d3bd316f3658aa8cc6904f073a1472149e4b08c64" + + "5e11abe0428ccb6174df2103edd735965d6454b543d3f01410f77053f65e" + + "c1d1aee56fdd3af23bcd4e1a7fcc4e600c4831007c33fe5f0c8300f686eb" + + "9b4d1e4f08fe4ddc8a90be14dc3a5a88ff96716509341d5db24c0d016863" + + "998b1859c5021df815a6f1ca9845f1a8e99dbad132b406227c5897a1bdf3" + + "e698962f799133ff4429decbef6ce036296facf38e4812fec102b76c6d30" + + "beba1b70722254fafbc471096153478c971db7d96263660209265cb10f13" + + "b34b5fd55c4abe818a5f9715d8a85094e2946b7a001b47f629e26c636d86" + + "4968ad2ab616dfe28840bd60b4b9855c8dbe1cb873fcbc4577b5fefeb8bb" + + "4832039867dc35db9c036c83bc204396e3474ddfe806c77c65c936f488b6" + + "7c1028739562d7bb055d21441af29ae2921290e548dccf8a56021385422b" + + "15da6b232b24151309a75a00296d11aa1952a1513110b0faa93d1d8cd9ae" + + "fa9f1c59377ec9165b2c9e07cbde40db7b81bca6d58fc28bae8f473cd0e9" + + "a2420e0b943a83d284108626c24ac570b1d6c1ab971e71f43fbd6c00e171" + + "238141a6dc987a60385c3a04dd147a2f8e80dfe727b104c0fdd80b326f59" + + "0b9f86fd7b2fd1122a390979889eabd803ab57159c8509a1443eb6789382" + + "090a770ae4eba03306f96e50e19a7d44c584ccc230d104548946efca4520" + + "d61de5f473e2f4eada6c8ce9c7ee975eb4f63c0483cb775ed7d3cf690a61" + + "7d6656d683a8512707d81ca5ba176a42bcffcfa692129f292607d2a47536" + + "ccaeb464c9272d6f3816074b712af602470088b253deba18771e5f67734b" + + "587707cdd06f35264b2262fd253c25b5d38ee7db287610e5398062b7a34e" + + "6e4cf7447d00873b930ad148fd96f0ab18771bc468b874bb109924101c84" + + "c4e239ecc7687d875e4d94a1a973620ca61e35a872c2e2e61a502169f1bb" + + "4e5ff5fa2bff657be6195b3e2c7151a52fc0096d98e7f08f5a98f570aee1" + + "7b4275f1356e87e080ce0e1b9bbabe7dea48b5903bc390ce23472ad64a89" + + "41c3247bfd23ea90b2dee09085571bad85568040105e098f993bb37e43c3" + + "e6d511171c77cfc450570dfb9fc6a3930ef43c03f8213f6203d545d791c7" + + "d3fa42d5dde1655038d35c5dfacc12e9dee24fe833977549eda68ae8b508" + + "be277e743921b584f9dfa0eefbd8bf3c23f51efdef7f7487001d29e8097b" + + "ba63289cfca743023d1668555a46fe6d5b7421377414df1e9ef135480622" + + "22e2e9a7baa618d88f407517f6317b6a0ba3384ace16d68631d59ea169d5" + + "092d20afc1a481b82be5e734bb092953a0a94702bae1a0f48d2a22b9a05f" + + "f64493b7b2e984f27582b1eb937fddf8512c49830435d146dcc291a4118d" + + "5dc638b99cdcbcc5860de7a92c5b13cbd1e01e051f01af40afe124346320" + + "d3626bf9d8f7850744e032a993c276fd388718237740c6caf260fca60b8d" + + "d846102e3262b6e05ceca00c6affe938fac1847350865fc858d3ddd1d130" + + "71d1221ce7c5d575587fcba580e544b74d877ed5ca92763ef0ca0d7bfa08" + + "d57a0216b2a01a2b9ec74b8430051e0074862b7be25b6766ab520f2eb75d" + + "eeb979c28f03795f6f1e4b8410beab19a20febc91985b8a7c298534a6598" + + "f2c5b0dc5de9f5e55a97791507bc6373db26", + }, +} diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go index 6c6e8423..fd97ba1b 100644 --- a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go @@ -5,7 +5,7 @@ // Package ripemd160 implements the RIPEMD-160 hash algorithm. package ripemd160 // import "golang.org/x/crypto/ripemd160" -// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart +// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart // Preneel with specifications available at: // http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf. diff --git a/vendor/golang.org/x/crypto/salsa20/salsa20.go b/vendor/golang.org/x/crypto/salsa20/salsa20.go index 0ee62485..6f9bb106 100644 --- a/vendor/golang.org/x/crypto/salsa20/salsa20.go +++ b/vendor/golang.org/x/crypto/salsa20/salsa20.go @@ -24,6 +24,7 @@ package salsa20 // import "golang.org/x/crypto/salsa20" // TODO(agl): implement XORKeyStream12 and XORKeyStream8 - the reduced round variants of Salsa20. import ( + "golang.org/x/crypto/internal/subtle" "golang.org/x/crypto/salsa20/salsa" ) @@ -32,7 +33,10 @@ import ( // be either 8 or 24 bytes long. func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte) { if len(out) < len(in) { - in = in[:len(out)] + panic("salsa20: output smaller than input") + } + if subtle.InexactOverlap(out[:len(in)], in) { + panic("salsa20: invalid buffer overlap") } var subNonce [16]byte diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go index ff28aaef..3362afd1 100644 --- a/vendor/golang.org/x/crypto/scrypt/scrypt.go +++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go @@ -29,7 +29,7 @@ func blockXOR(dst, src []uint32, n int) { } // salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in, -// and puts the result into both both tmp and out. +// and puts the result into both tmp and out. func salsaXOR(tmp *[16]uint32, in, out []uint32) { w0 := tmp[0] ^ in[0] w1 := tmp[1] ^ in[1] @@ -218,7 +218,7 @@ func smix(b []byte, r, N int, v, xy []uint32) { // For example, you can get a derived key for e.g. AES-256 (which needs a // 32-byte key) by doing: // -// dk, err := scrypt.Key([]byte("some password"), salt, 16384, 8, 1, 32) +// dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) // // The recommended parameters for interactive logins as of 2017 are N=32768, r=8 // and p=1. The parameters N, r, and p should be increased as memory latency and diff --git a/vendor/golang.org/x/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go index a0ee3ae7..c2fef30a 100644 --- a/vendor/golang.org/x/crypto/sha3/doc.go +++ b/vendor/golang.org/x/crypto/sha3/doc.go @@ -43,7 +43,7 @@ // is then "full" and the permutation is applied to "empty" it. This process is // repeated until all the input has been "absorbed". The input is then padded. // The digest is "squeezed" from the sponge in the same way, except that output -// output is copied out instead of input being XORed in. +// is copied out instead of input being XORed in. // // A sponge is parameterized by its generic security strength, which is equal // to half its capacity; capacity + rate is equal to the permutation's width. diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go index f35a42ff..0d8043fd 100644 --- a/vendor/golang.org/x/crypto/sha3/hashes.go +++ b/vendor/golang.org/x/crypto/sha3/hashes.go @@ -52,6 +52,18 @@ func New512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x06} } +// NewLegacyKeccak256 creates a new Keccak-256 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New256 instead. +func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } + +// NewLegacyKeccak512 creates a new Keccak-512 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New512 instead. +func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } + // Sum224 returns the SHA3-224 digest of the data. func Sum224(data []byte) (digest [28]byte) { h := New224() diff --git a/vendor/golang.org/x/crypto/sha3/sha3_test.go b/vendor/golang.org/x/crypto/sha3/sha3_test.go index 2c8719b4..26d1549b 100644 --- a/vendor/golang.org/x/crypto/sha3/sha3_test.go +++ b/vendor/golang.org/x/crypto/sha3/sha3_test.go @@ -36,15 +36,17 @@ func newHashShake256() hash.Hash { } // testDigests contains functions returning hash.Hash instances -// with output-length equal to the KAT length for both SHA-3 and -// SHAKE instances. +// with output-length equal to the KAT length for SHA-3, Keccak +// and SHAKE instances. var testDigests = map[string]func() hash.Hash{ - "SHA3-224": New224, - "SHA3-256": New256, - "SHA3-384": New384, - "SHA3-512": New512, - "SHAKE128": newHashShake128, - "SHAKE256": newHashShake256, + "SHA3-224": New224, + "SHA3-256": New256, + "SHA3-384": New384, + "SHA3-512": New512, + "Keccak-256": NewLegacyKeccak256, + "Keccak-512": NewLegacyKeccak512, + "SHAKE128": newHashShake128, + "SHAKE256": newHashShake256, } // testShakes contains functions that return ShakeHash instances for @@ -124,9 +126,39 @@ func TestKeccakKats(t *testing.T) { }) } +// TestKeccak does a basic test of the non-standardized Keccak hash functions. +func TestKeccak(t *testing.T) { + tests := []struct { + fn func() hash.Hash + data []byte + want string + }{ + { + NewLegacyKeccak256, + []byte("abc"), + "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", + }, + { + NewLegacyKeccak512, + []byte("abc"), + "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", + }, + } + + for _, u := range tests { + h := u.fn() + h.Write(u.data) + got := h.Sum(nil) + want := decodeHex(u.want) + if !bytes.Equal(got, want) { + t.Errorf("unexpected hash for size %d: got '%x' want '%s'", h.Size()*8, got, u.want) + } + } +} + // TestUnalignedWrite tests that writing data in an arbitrary pattern with // small input buffers. -func testUnalignedWrite(t *testing.T) { +func TestUnalignedWrite(t *testing.T) { testUnalignedAndGeneric(t, func(impl string) { buf := sequentialBytes(0x10000) for alg, df := range testDigests { diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go index b1808dd2..51f74050 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -25,10 +25,22 @@ import ( "math/big" "sync" + "crypto" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" ) +// SignatureFlags represent additional flags that can be passed to the signature +// requests an defined in [PROTOCOL.agent] section 4.5.1. +type SignatureFlags uint32 + +// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. +const ( + SignatureFlagReserved SignatureFlags = 1 << iota + SignatureFlagRsaSha256 + SignatureFlagRsaSha512 +) + // Agent represents the capabilities of an ssh-agent. type Agent interface { // List returns the identities known to the agent. @@ -57,6 +69,26 @@ type Agent interface { Signers() ([]ssh.Signer, error) } +type ExtendedAgent interface { + Agent + + // SignWithFlags signs like Sign, but allows for additional flags to be sent/received + SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) + + // Extension processes a custom extension request. Standard-compliant agents are not + // required to support any extensions, but this method allows agents to implement + // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. + // If agent extensions are unsupported entirely this method MUST return an + // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in + // the request is unsupported by the agent then ErrExtensionUnsupported MUST be + // returned. + // + // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents + // of the response are unspecified (including the type of the message), the complete + // response will be returned as a []byte slice, including the "type" byte of the message. + Extension(extensionType string, contents []byte) ([]byte, error) +} + // ConstraintExtension describes an optional constraint defined by users. type ConstraintExtension struct { // ExtensionName consist of a UTF-8 string suffixed by the @@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct { Rest []byte `ssh:"rest"` } +// See [PROTOCOL.agent], section 4.7 +const agentExtension = 27 +const agentExtensionFailure = 28 + +// ErrExtensionUnsupported indicates that an extension defined in +// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this +// error indicates that the agent returned a standard SSH_AGENT_FAILURE message +// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol +// specification (and therefore this error) does not distinguish between a +// specific extension being unsupported and extensions being unsupported entirely. +var ErrExtensionUnsupported = errors.New("agent: extension unsupported") + +type extensionAgentMsg struct { + ExtensionType string `sshtype:"27"` + Contents []byte +} + // Key represents a protocol 2 public key as defined in // [PROTOCOL.agent], section 2.5.2. type Key struct { @@ -260,7 +309,7 @@ type client struct { // NewClient returns an Agent that talks to an ssh-agent process over // the given connection. -func NewClient(rw io.ReadWriter) Agent { +func NewClient(rw io.ReadWriter) ExtendedAgent { return &client{conn: rw} } @@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent { // unmarshaled into reply and replyType is set to the first byte of // the reply, which contains the type of the message. func (c *client) call(req []byte) (reply interface{}, err error) { + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + reply, err = unmarshal(buf) + if err != nil { + return nil, clientErr(err) + } + return reply, nil +} + +// callRaw sends an RPC to the agent. On success, the raw +// bytes of the response are returned; no unmarshalling is +// performed on the response. +func (c *client) callRaw(req []byte) (reply []byte, err error) { c.mu.Lock() defer c.mu.Unlock() @@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) { } respSize := binary.BigEndian.Uint32(respSizeBuf[:]) if respSize > maxAgentResponseBytes { - return nil, clientErr(err) + return nil, clientErr(errors.New("response too large")) } buf := make([]byte, respSize) if _, err = io.ReadFull(c.conn, buf); err != nil { return nil, clientErr(err) } - reply, err = unmarshal(buf) - if err != nil { - return nil, clientErr(err) - } - return reply, err + return buf, nil } func (c *client) simpleCall(req []byte) error { @@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) { // Sign has the agent sign the data using a protocol 2 key as defined // in [PROTOCOL.agent] section 2.6.2. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return c.SignWithFlags(key, data, 0) +} + +func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { req := ssh.Marshal(signRequestAgentMsg{ KeyBlob: key.Marshal(), Data: data, + Flags: uint32(flags), }) msg, err := c.call(req) @@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, // The agent has its own entropy source, so the rand argument is ignored. return s.agent.Sign(s.pub, data) } + +func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { + var flags SignatureFlags + if opts != nil { + switch opts.HashFunc() { + case crypto.SHA256: + flags = SignatureFlagRsaSha256 + case crypto.SHA512: + flags = SignatureFlagRsaSha512 + } + } + return s.agent.SignWithFlags(s.pub, data, flags) +} + +// Calls an extension method. It is up to the agent implementation as to whether or not +// any particular extension is supported and may always return an error. Because the +// type of the response is up to the implementation, this returns the bytes of the +// response and does not attempt any type of unmarshalling. +func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { + req := ssh.Marshal(extensionAgentMsg{ + ExtensionType: extensionType, + Contents: contents, + }) + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + if len(buf) == 0 { + return nil, errors.New("agent: failure; empty response") + } + // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message + // represents an agent that does not support the extension + if buf[0] == agentFailure { + return nil, ErrExtensionUnsupported + } + if buf[0] == agentExtensionFailure { + return nil, errors.New("agent: generic extension failure") + } + + return buf, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/client_test.go b/vendor/golang.org/x/crypto/ssh/agent/client_test.go index 266fd6d4..2f798f94 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client_test.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client_test.go @@ -20,7 +20,7 @@ import ( ) // startOpenSSHAgent executes ssh-agent, and returns an Agent interface to it. -func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func()) { +func startOpenSSHAgent(t *testing.T) (client ExtendedAgent, socket string, cleanup func()) { if testing.Short() { // ssh-agent is not always available, and the key // types supported vary by platform. @@ -79,13 +79,12 @@ func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func( } } -// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client. -func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) { +func startAgent(t *testing.T, agent Agent) (client ExtendedAgent, cleanup func()) { c1, c2, err := netPipe() if err != nil { t.Fatalf("netPipe: %v", err) } - go ServeAgent(NewKeyring(), c2) + go ServeAgent(agent, c2) return NewClient(c1), func() { c1.Close() @@ -93,6 +92,11 @@ func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) { } } +// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client. +func startKeyringAgent(t *testing.T) (client ExtendedAgent, cleanup func()) { + return startAgent(t, NewKeyring()) +} + func testOpenSSHAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() @@ -107,7 +111,7 @@ func testKeyringAgent(t *testing.T, key interface{}, cert *ssh.Certificate, life testAgentInterface(t, agent, key, cert, lifetimeSecs) } -func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { +func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { signer, err := ssh.NewSignerFromKey(key) if err != nil { t.Fatalf("NewSignerFromKey(%T): %v", key, err) @@ -159,6 +163,25 @@ func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Ce t.Fatalf("Verify(%s): %v", pubKey.Type(), err) } + // For tests on RSA keys, try signing with SHA-256 and SHA-512 flags + if pubKey.Type() == "ssh-rsa" { + sshFlagTest := func(flag SignatureFlags, expectedSigFormat string) { + sig, err = agent.SignWithFlags(pubKey, data, flag) + if err != nil { + t.Fatalf("SignWithFlags(%s): %v", pubKey.Type(), err) + } + if sig.Format != expectedSigFormat { + t.Fatalf("Signature format didn't match expected value: %s != %s", sig.Format, expectedSigFormat) + } + if err := pubKey.Verify(data, sig); err != nil { + t.Fatalf("Verify(%s): %v", pubKey.Type(), err) + } + } + sshFlagTest(0, ssh.SigAlgoRSA) + sshFlagTest(SignatureFlagRsaSha256, ssh.SigAlgoRSASHA2256) + sshFlagTest(SignatureFlagRsaSha512, ssh.SigAlgoRSASHA2512) + } + // If the key has a lifetime, is it removed when it should be? if lifetimeSecs > 0 { time.Sleep(time.Second*time.Duration(lifetimeSecs) + 100*time.Millisecond) @@ -218,6 +241,35 @@ func netPipe() (net.Conn, net.Conn, error) { return c1, c2, nil } +func TestServerResponseTooLarge(t *testing.T) { + a, b, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + + defer a.Close() + defer b.Close() + + var response identitiesAnswerAgentMsg + response.NumKeys = 1 + response.Keys = make([]byte, maxAgentResponseBytes+1) + + agent := NewClient(a) + go func() { + n, _ := b.Write(ssh.Marshal(response)) + if n < 4 { + t.Fatalf("At least 4 bytes (the response size) should have been successfully written: %d < 4", n) + } + }() + _, err = agent.List() + if err == nil { + t.Fatal("Did not get error result") + } + if err.Error() != "agent: client error: response too large" { + t.Fatal("Did not get expected error result") + } +} + func TestAuth(t *testing.T) { agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() @@ -377,3 +429,38 @@ func testAgentLifetime(t *testing.T, agent Agent) { t.Errorf("Want 0 keys, got %v", len(keys)) } } + +type keyringExtended struct { + *keyring +} + +func (r *keyringExtended) Extension(extensionType string, contents []byte) ([]byte, error) { + if extensionType != "my-extension@example.com" { + return []byte{agentExtensionFailure}, nil + } + return append([]byte{agentSuccess}, contents...), nil +} + +func TestAgentExtensions(t *testing.T) { + agent, _, cleanup := startOpenSSHAgent(t) + defer cleanup() + result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02}) + if err == nil { + t.Fatal("should have gotten agent extension failure") + } + + agent, cleanup = startAgent(t, &keyringExtended{}) + defer cleanup() + result, err = agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02}) + if err != nil { + t.Fatalf("agent extension failure: %v", err) + } + if len(result) != 4 || !bytes.Equal(result, []byte{agentSuccess, 0x00, 0x01, 0x02}) { + t.Fatalf("agent extension result invalid: %v", result) + } + + result, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02}) + if err == nil { + t.Fatal("should have gotten agent extension failure") + } +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go index 1a516327..c9d97943 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go +++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go @@ -182,6 +182,10 @@ func (r *keyring) Add(key AddedKey) error { // Sign returns a signature for the data. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return r.SignWithFlags(key, data, 0) +} + +func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { r.mu.Lock() defer r.mu.Unlock() if r.locked { @@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { wanted := key.Marshal() for _, k := range r.keys { if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { - return k.signer.Sign(rand.Reader, data) + if flags == 0 { + return k.signer.Sign(rand.Reader, data) + } else { + if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { + return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) + } else { + var algorithm string + switch flags { + case SignatureFlagRsaSha256: + algorithm = ssh.SigAlgoRSASHA2256 + case SignatureFlagRsaSha512: + algorithm = ssh.SigAlgoRSASHA2512 + default: + return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) + } + return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + } + } } } return nil, errors.New("not found") @@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) { } return s, nil } + +// The keyring does not support any extensions +func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { + return nil, ErrExtensionUnsupported +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go index 2e4692cb..a1949762 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/server.go +++ b/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) { Blob: req.KeyBlob, } - sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. + var sig *ssh.Signature + var err error + if extendedAgent, ok := s.agent.(ExtendedAgent); ok { + sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) + } else { + sig, err = s.agent.Sign(k, req.Data) + } + if err != nil { return nil, err } @@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) { case agentAddIDConstrained, agentAddIdentity: return nil, s.insertIdentity(data) + + case agentExtension: + // Return a stub object where the whole contents of the response gets marshaled. + var responseStub struct { + Rest []byte `ssh:"rest"` + } + + if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { + // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 + // requires that we return a standard SSH_AGENT_FAILURE message. + responseStub.Rest = []byte{agentFailure} + } else { + var req extensionAgentMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) + if err != nil { + // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE + // message as required by [PROTOCOL.agent] section 4.7. + if err == ErrExtensionUnsupported { + responseStub.Rest = []byte{agentFailure} + } else { + // As the result of any other error processing an extension request, + // [PROTOCOL.agent] section 4.7 requires that we return a + // SSH_AGENT_EXTENSION_FAILURE code. + responseStub.Rest = []byte{agentExtensionFailure} + } + } else { + if len(res) == 0 { + return nil, nil + } + responseStub.Rest = res + } + } + + return responseStub, nil } return nil, fmt.Errorf("unknown opcode %d", data[0]) diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go index 42106f3f..00ed9923 100644 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -222,6 +222,11 @@ type openSSHCertSigner struct { signer Signer } +type algorithmOpenSSHCertSigner struct { + *openSSHCertSigner + algorithmSigner AlgorithmSigner +} + // NewCertSigner returns a Signer that signs with the given Certificate, whose // private key is held by signer. It returns an error if the public key in cert // doesn't match the key used by signer. @@ -230,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { return nil, errors.New("ssh: signer and cert have different public key") } - return &openSSHCertSigner{cert, signer}, nil + if algorithmSigner, ok := signer.(AlgorithmSigner); ok { + return &algorithmOpenSSHCertSigner{ + &openSSHCertSigner{cert, signer}, algorithmSigner}, nil + } else { + return &openSSHCertSigner{cert, signer}, nil + } } func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { @@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey { return s.pub } +func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) +} + const sourceAddressCriticalOption = "source-address" // CertChecker does the work of verifying a certificate. Its methods diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go index 6fd19945..7b00bff1 100644 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -19,6 +19,8 @@ import ( type Client struct { Conn + handleForwardsOnce sync.Once // guards calling (*Client).handleForwards + forwards forwardList // forwarded tcpip connections from the remote side mu sync.Mutex channelHandlers map[string]chan NewChannel @@ -60,8 +62,6 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { conn.Wait() conn.forwards.closeAll() }() - go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) - go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com")) return conn } @@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) { // keys. A HostKeyCallback must return nil if the host key is OK, or // an error to reject it. It receives the hostname as passed to Dial // or NewClientConn. The remote address is the RemoteAddr of the -// net.Conn underlying the the SSH connection. +// net.Conn underlying the SSH connection. type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error // BannerCallback is the function type used for treat the banner sent by diff --git a/vendor/golang.org/x/crypto/ssh/client_auth_test.go b/vendor/golang.org/x/crypto/ssh/client_auth_test.go index 5fbb20d8..026d137e 100644 --- a/vendor/golang.org/x/crypto/ssh/client_auth_test.go +++ b/vendor/golang.org/x/crypto/ssh/client_auth_test.go @@ -9,6 +9,7 @@ import ( "crypto/rand" "errors" "fmt" + "io" "os" "strings" "testing" @@ -28,8 +29,14 @@ func (cr keyboardInteractive) Challenge(user string, instruction string, questio var clientPassword = "tiger" // tryAuth runs a handshake with a given config against an SSH server -// with config serverConfig +// with config serverConfig. Returns both client and server side errors. func tryAuth(t *testing.T, config *ClientConfig) error { + err, _ := tryAuthBothSides(t, config) + return err +} + +// tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection. +func tryAuthBothSides(t *testing.T, config *ClientConfig) (clientError error, serverAuthErrors []error) { c1, c2, err := netPipe() if err != nil { t.Fatalf("netPipe: %v", err) @@ -79,9 +86,13 @@ func tryAuth(t *testing.T, config *ClientConfig) error { } serverConfig.AddHostKey(testSigners["rsa"]) + serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) { + serverAuthErrors = append(serverAuthErrors, err) + } + go newServer(c1, serverConfig) _, _, _, err = NewClientConn(c2, "", config) - return err + return err, serverAuthErrors } func TestClientAuthPublicKey(t *testing.T) { @@ -213,6 +224,45 @@ func TestAuthMethodRSAandDSA(t *testing.T) { } } +type invalidAlgSigner struct { + Signer +} + +func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + sig, err := s.Signer.Sign(rand, data) + if sig != nil { + sig.Format = "invalid" + } + return sig, err +} + +func TestMethodInvalidAlgorithm(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(&invalidAlgSigner{testSigners["rsa"]}), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + err, serverErrors := tryAuthBothSides(t, config) + if err == nil { + t.Fatalf("login succeeded") + } + + found := false + want := "algorithm \"invalid\"" + + var errStrings []string + for _, err := range serverErrors { + found = found || (err != nil && strings.Contains(err.Error(), want)) + errStrings = append(errStrings, err.Error()) + } + if !found { + t.Errorf("server got error %q, want substring %q", errStrings, want) + } +} + func TestClientHMAC(t *testing.T) { for _, mac := range supportedMACs { config := &ClientConfig{ diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index 73697ded..96980479 100644 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -38,6 +38,16 @@ const ( KeyAlgoED25519 = "ssh-ed25519" ) +// These constants represent non-default signature algorithms that are supported +// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See +// [PROTOCOL.agent] section 4.5.1 and +// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10 +const ( + SigAlgoRSA = "ssh-rsa" + SigAlgoRSASHA2256 = "rsa-sha2-256" + SigAlgoRSASHA2512 = "rsa-sha2-512" +) + // parsePubKey parses a public key of the given algorithm. // Use ParsePublicKey for keys with prepended algorithm. func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { @@ -301,6 +311,19 @@ type Signer interface { Sign(rand io.Reader, data []byte) (*Signature, error) } +// A AlgorithmSigner is a Signer that also supports specifying a specific +// algorithm to use for signing. +type AlgorithmSigner interface { + Signer + + // SignWithAlgorithm is like Signer.Sign, but allows specification of a + // non-default signing algorithm. See the SigAlgo* constants in this + // package for signature algorithms supported by this package. Callers may + // pass an empty string for the algorithm in which case the AlgorithmSigner + // will use its default algorithm. + SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) +} + type rsaPublicKey rsa.PublicKey func (r *rsaPublicKey) Type() string { @@ -349,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte { } func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != r.Type() { + var hash crypto.Hash + switch sig.Format { + case SigAlgoRSA: + hash = crypto.SHA1 + case SigAlgoRSASHA2256: + hash = crypto.SHA256 + case SigAlgoRSASHA2512: + hash = crypto.SHA512 + default: return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) } - h := crypto.SHA1.New() + h := hash.New() h.Write(data) digest := h.Sum(nil) - return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) + return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) } func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { @@ -459,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey { } func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { + return k.SignWithAlgorithm(rand, data, "") +} + +func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm != "" && algorithm != k.PublicKey().Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + h := crypto.SHA1.New() h.Write(data) digest := h.Sum(nil) @@ -691,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey { } func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.SignWithAlgorithm(rand, data, "") +} + +func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { var hashFunc crypto.Hash - switch key := s.pubKey.(type) { - case *rsaPublicKey, *dsaPublicKey: - hashFunc = crypto.SHA1 - case *ecdsaPublicKey: - hashFunc = ecHash(key.Curve) - case ed25519PublicKey: - default: - return nil, fmt.Errorf("ssh: unsupported key type %T", key) + if _, ok := s.pubKey.(*rsaPublicKey); ok { + // RSA keys support a few hash functions determined by the requested signature algorithm + switch algorithm { + case "", SigAlgoRSA: + algorithm = SigAlgoRSA + hashFunc = crypto.SHA1 + case SigAlgoRSASHA2256: + hashFunc = crypto.SHA256 + case SigAlgoRSASHA2512: + hashFunc = crypto.SHA512 + default: + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + } else { + // The only supported algorithm for all other key types is the same as the type of the key + if algorithm == "" { + algorithm = s.pubKey.Type() + } else if algorithm != s.pubKey.Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + + switch key := s.pubKey.(type) { + case *dsaPublicKey: + hashFunc = crypto.SHA1 + case *ecdsaPublicKey: + hashFunc = ecHash(key.Curve) + case ed25519PublicKey: + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } } var digest []byte @@ -745,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { } return &Signature{ - Format: s.pubKey.Type(), + Format: algorithm, Blob: signature, }, nil } @@ -803,7 +868,7 @@ func encryptedBlock(block *pem.Block) bool { } // ParseRawPrivateKey returns a private key from a PEM encoded private key. It -// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys. +// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { block, _ := pem.Decode(pemBytes) if block == nil { @@ -817,6 +882,9 @@ func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { switch block.Type { case "RSA PRIVATE KEY": return x509.ParsePKCS1PrivateKey(block.Bytes) + // RFC5208 - https://tools.ietf.org/html/rfc5208 + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) case "EC PRIVATE KEY": return x509.ParseECPrivateKey(block.Bytes) case "DSA PRIVATE KEY": @@ -900,8 +968,8 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { // Implemented based on the documentation at // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) { - magic := append([]byte("openssh-key-v1"), 0) - if !bytes.Equal(magic, key[0:len(magic)]) { + const magic = "openssh-key-v1\x00" + if len(key) < len(magic) || string(key[:len(magic)]) != magic { return nil, errors.New("ssh: invalid openssh private key format") } remaining := key[len(magic):] diff --git a/vendor/golang.org/x/crypto/ssh/keys_test.go b/vendor/golang.org/x/crypto/ssh/keys_test.go index 9a90abc0..3847b3bf 100644 --- a/vendor/golang.org/x/crypto/ssh/keys_test.go +++ b/vendor/golang.org/x/crypto/ssh/keys_test.go @@ -13,7 +13,9 @@ import ( "crypto/rsa" "crypto/x509" "encoding/base64" + "encoding/pem" "fmt" + "io" "reflect" "strings" "testing" @@ -107,6 +109,49 @@ func TestKeySignVerify(t *testing.T) { } } +func TestKeySignWithAlgorithmVerify(t *testing.T) { + for _, priv := range testSigners { + if algorithmSigner, ok := priv.(AlgorithmSigner); !ok { + t.Errorf("Signers constructed by ssh package should always implement the AlgorithmSigner interface: %T", priv) + } else { + pub := priv.PublicKey() + data := []byte("sign me") + + signWithAlgTestCase := func(algorithm string, expectedAlg string) { + sig, err := algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + if err != nil { + t.Fatalf("Sign(%T): %v", priv, err) + } + if sig.Format != expectedAlg { + t.Errorf("signature format did not match requested signature algorithm: %s != %s", sig.Format, expectedAlg) + } + + if err := pub.Verify(data, sig); err != nil { + t.Errorf("publicKey.Verify(%T): %v", priv, err) + } + sig.Blob[5]++ + if err := pub.Verify(data, sig); err == nil { + t.Errorf("publicKey.Verify on broken sig did not fail") + } + } + + // Using the empty string as the algorithm name should result in the same signature format as the algorithm-free Sign method. + defaultSig, err := priv.Sign(rand.Reader, data) + if err != nil { + t.Fatalf("Sign(%T): %v", priv, err) + } + signWithAlgTestCase("", defaultSig.Format) + + // RSA keys are the only ones which currently support more than one signing algorithm + if pub.Type() == KeyAlgoRSA { + for _, algorithm := range []string{SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512} { + signWithAlgTestCase(algorithm, algorithm) + } + } + } + } +} + func TestParseRSAPrivateKey(t *testing.T) { key := testPrivateKeys["rsa"] @@ -498,3 +543,32 @@ func TestFingerprintSHA256(t *testing.T) { t.Errorf("got fingerprint %q want %q", fingerprint, want) } } + +func TestInvalidKeys(t *testing.T) { + keyTypes := []string{ + "RSA PRIVATE KEY", + "PRIVATE KEY", + "EC PRIVATE KEY", + "DSA PRIVATE KEY", + "OPENSSH PRIVATE KEY", + } + + for _, keyType := range keyTypes { + for _, dataLen := range []int{0, 1, 2, 5, 10, 20} { + data := make([]byte, dataLen) + if _, err := io.ReadFull(rand.Reader, data); err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + pem.Encode(&buf, &pem.Block{ + Type: keyType, + Bytes: data, + }) + + // This test is just to ensure that the function + // doesn't panic so the return value is ignored. + ParseRawPrivateKey(buf.Bytes()) + } + } +} diff --git a/vendor/golang.org/x/crypto/ssh/mux_test.go b/vendor/golang.org/x/crypto/ssh/mux_test.go index d88b64e4..94596ec2 100644 --- a/vendor/golang.org/x/crypto/ssh/mux_test.go +++ b/vendor/golang.org/x/crypto/ssh/mux_test.go @@ -20,7 +20,7 @@ func muxPair() (*mux, *mux) { return s, c } -// Returns both ends of a channel, and the mux for the the 2nd +// Returns both ends of a channel, and the mux for the 2nd // channel. func channelPair(t *testing.T) (*channel, *channel, *mux) { c, s := muxPair() diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index d0f48253..e86e8966 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -404,7 +404,7 @@ userAuthLoop: perms, authErr = config.PasswordCallback(s, password) case "keyboard-interactive": if config.KeyboardInteractiveCallback == nil { - authErr = errors.New("ssh: keyboard-interactive auth not configubred") + authErr = errors.New("ssh: keyboard-interactive auth not configured") break } @@ -484,6 +484,7 @@ userAuthLoop: // sig.Format. This is usually the same, but // for certs, the names differ. if !isAcceptableAlgo(sig.Format) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) break } signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go index a2dccc64..b171b330 100644 --- a/vendor/golang.org/x/crypto/ssh/streamlocal.go +++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go @@ -32,6 +32,7 @@ type streamLocalChannelForwardMsg struct { // ListenUnix is similar to ListenTCP but uses a Unix domain socket. func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) m := streamLocalChannelForwardMsg{ socketPath, } diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go index acf17175..80d35f5e 100644 --- a/vendor/golang.org/x/crypto/ssh/tcpip.go +++ b/vendor/golang.org/x/crypto/ssh/tcpip.go @@ -90,10 +90,19 @@ type channelForwardMsg struct { rport uint32 } +// handleForwards starts goroutines handling forwarded connections. +// It's called on first use by (*Client).ListenTCP to not launch +// goroutines until needed. +func (c *Client) handleForwards() { + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip")) + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com")) +} + // ListenTCP requests the remote peer open a listening socket // on laddr. Incoming connections will be available by calling // Accept on the returned net.Listener. func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { return c.autoPortListenWorkaround(laddr) } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go index 901c72ab..5e5d33b1 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd windows plan9 solaris + package terminal import ( "bytes" "io" "os" + "runtime" "testing" ) @@ -324,6 +327,11 @@ func TestMakeRawState(t *testing.T) { if err != nil { t.Fatalf("failed to get terminal state from GetState: %s", err) } + + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("MakeRaw not allowed on iOS; skipping test") + } + defer Restore(fd, st) raw, err := MakeRaw(fd) if err != nil { diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go index 731c89a2..39110408 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd +// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd // Package terminal provides support functions for dealing with terminals, as // commonly found on UNIX systems. @@ -25,7 +25,7 @@ type State struct { termios unix.Termios } -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) return err == nil diff --git a/vendor/golang.org/x/sys/windows/asm_windows_arm.s b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go similarity index 51% rename from vendor/golang.org/x/sys/windows/asm_windows_arm.s rename to vendor/golang.org/x/crypto/ssh/terminal/util_aix.go index 55d8b91a..dfcd6278 100644 --- a/vendor/golang.org/x/sys/windows/asm_windows_arm.s +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "textflag.h" +// +build aix -TEXT ·getprocaddress(SB),NOSPLIT,$0 - B syscall·getprocaddress(SB) +package terminal -TEXT ·loadlibrary(SB),NOSPLIT,$0 - B syscall·loadlibrary(SB) +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS +const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go index 799f049f..9317ac7e 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go @@ -21,7 +21,7 @@ import ( type State struct{} -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { return false } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go index 9e41b9f4..3d5f06a9 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go @@ -17,7 +17,7 @@ type State struct { termios unix.Termios } -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { _, err := unix.IoctlGetTermio(fd, unix.TCGETA) return err == nil diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go index 8618955d..6cb8a950 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -26,7 +26,7 @@ type State struct { mode uint32 } -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { var st uint32 err := windows.GetConsoleMode(windows.Handle(fd), &st) diff --git a/vendor/golang.org/x/crypto/ssh/testdata/keys.go b/vendor/golang.org/x/crypto/ssh/testdata/keys.go index 521b6be9..bfae85fe 100644 --- a/vendor/golang.org/x/crypto/ssh/testdata/keys.go +++ b/vendor/golang.org/x/crypto/ssh/testdata/keys.go @@ -60,6 +60,35 @@ NDvRS0rjwt6lJGv7zPZoqDc65VfrK2aNyHx2PgFyzwrEOtuF57bu7pnvEIxpLTeM z26i6XVMeYXAWZMTloMCQBbpGgEERQpeUknLBqUHhg/wXF6+lFA+vEGnkY+Dwab2 KCXFGd+SQ5GdUcEMe9isUH6DYj/6/yCDoFrXXmpQb+M= -----END RSA PRIVATE KEY----- +`), + "pkcs8": []byte(`-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCitzS2KiRQTccf +VApb0mbPpo1lt29JjeLBYAehXHWfQ+w8sXpd8e04n/020spx1R94yg+v0NjXyh2R +NFXNBYdhNei33VJxUeKNlExaecvW2yxfuZqka+ZxT1aI8zrAsjh3Rwc6wayAJS4R +wZuzlDv4jZitWqwD+mb/22Zwq/WSs4YX5dUHDklfdWSVnoBfue8K/00n8f5yMTdJ +vFF0qAJwf9spPEHla0lYcozJk64CO5lRkqfLor4UnsXXOiA7aRIoaUSKa+rlhiqt +1EMGYiBjblPt4SwMelGGU2UfywPb4d85gpQ/s8SBARbpPxNVs2IbHDMwj70P3uZc +74M3c4VJAgMBAAECggEAFIzY3mziGzZHgMBncoNXMsCRORh6uKpvygZr0EhSHqRA +cMXlc3n7gNxL6aGjqc7F48Z5RrY0vMQtCcq3T2Z0W6WoV5hfMiqqV0E0h3S8ds1F +hG13h26NMyBXCILXl8Cqev4Afr45IBISCHIQTRTaoiCX+MTr1rDIU2YNQQumvzkz +fMw2XiFTFTgxAtJUAgKoTqLtm7/T+az7TKw+Hesgbx7yaJoMh9DWGBh4Y61DnIDA +fcxJboAfxxnFiXvdBVmzo72pCsRXrWOsjW6WxQmCKuXHvyB1FZTmMaEFNCGSJDa6 +U+OCzA3m65loAZAE7ffFHhYgssz/h9TBaOjKO0BX1QKBgQDZiCBvu+bFh9pEodcS +VxaI+ATlsYcmGdLtnZw5pxuEdr60iNWhpEcV6lGkbdiv5aL43QaGFDLagqeHI77b ++ITFbPPdCiYNaqlk6wyiXv4pdN7V683EDmGWSQlPeC9IhUilt2c+fChK2EB/XlkO +q8c3Vk1MsC6JOxDXNgJxylNpswKBgQC/fYBTb9iD+uM2n3SzJlct/ZlPaONKnNDR +pbTOdxBFHsu2VkfY858tfnEPkmSRX0yKmjHni6e8/qIzfzLwWBY4NmxhNZE5v+qJ +qZF26ULFdrZB4oWXAOliy/1S473OpQnp2MZp2asd0LPcg/BNaMuQrz44hxHb76R7 +qWD0ebIfEwKBgQCRCIiP1pjbVGN7ZOgPS080DSC+wClahtcyI+ZYLglTvRQTLDQ7 +LFtUykCav748MIADKuJBnM/3DiuCF5wV71EejDDfS/fo9BdyuKBY1brhixFTUX+E +Ww5Hc/SoLnpgALVZ/7jvWTpIBHykLxRziqYtR/YLzl+IkX/97P2ePoZ0rwKBgHNC +/7M5Z4JJyepfIMeVFHTCaT27TNTkf20x6Rs937U7TDN8y9JzEiU4LqXI4HAAhPoI +xnExRs4kF04YCnlRDE7Zs3Lv43J3ap1iTATfcymYwyv1RaQXEGQ/lUQHgYCZJtZz +fTrJoo5XyWu6nzJ5Gc8FLNaptr5ECSXGVm3Rsr2xAoGBAJWqEEQS/ejhO05QcPqh +y4cUdLr0269ILVsvic4Ot6zgfPIntXAK6IsHGKcg57kYm6W9k1CmmlA4ENGryJnR +vxyyqA9eyTFc1CQNuc2frKFA9It49JzjXahKc0aDHEHmTR787Tmk1LbuT0/gm9kA +L4INU6g+WqF0fatJxd+IJPrp +-----END PRIVATE KEY----- `), "ed25519": []byte(`-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW @@ -126,7 +155,7 @@ var SSHCertificates = map[string][]byte{ // Generated by the following commands: // // 1. Assumes "rsa" key above in file named "rsa", write out the public key to "rsa.pub": - // ssh-keygen -y -f rsa > rsa.pu + // ssh-keygen -y -f rsa > rsa.pub // // 2. Assumes "ca" key above in file named "ca", sign a cert for "rsa.pub": // ssh-keygen -s ca -h -n host.example.com -V +500w -I host.example.com-key rsa.pub diff --git a/vendor/golang.org/x/crypto/xts/xts.go b/vendor/golang.org/x/crypto/xts/xts.go index 92cbce99..9654e1fc 100644 --- a/vendor/golang.org/x/crypto/xts/xts.go +++ b/vendor/golang.org/x/crypto/xts/xts.go @@ -25,6 +25,8 @@ import ( "crypto/cipher" "encoding/binary" "errors" + + "golang.org/x/crypto/internal/subtle" ) // Cipher contains an expanded key structure. It doesn't contain mutable state @@ -64,6 +66,9 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) { if len(plaintext)%blockSize != 0 { panic("xts: plaintext is not a multiple of the block size") } + if subtle.InexactOverlap(ciphertext[:len(plaintext)], plaintext) { + panic("xts: invalid buffer overlap") + } var tweak [blockSize]byte binary.LittleEndian.PutUint64(tweak[:8], sectorNum) @@ -95,6 +100,9 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) { if len(ciphertext)%blockSize != 0 { panic("xts: ciphertext is not a multiple of the block size") } + if subtle.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) { + panic("xts: invalid buffer overlap") + } var tweak [blockSize]byte binary.LittleEndian.PutUint64(tweak[:8], sectorNum) diff --git a/vendor/golang.org/x/net/CONTRIBUTING.md b/vendor/golang.org/x/net/CONTRIBUTING.md index 88dff59b..d0485e88 100644 --- a/vendor/golang.org/x/net/CONTRIBUTING.md +++ b/vendor/golang.org/x/net/CONTRIBUTING.md @@ -4,16 +4,15 @@ Go is an open source project. It is the work of hundreds of contributors. We appreciate your help! - ## Filing issues When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: -1. What version of Go are you using (`go version`)? -2. What operating system and processor architecture are you using? -3. What did you do? -4. What did you expect to see? -5. What did you see instead? +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. The gophers there will answer or ask you to file an issue if you've tripped over a bug. @@ -23,9 +22,5 @@ The gophers there will answer or ask you to file an issue if you've tripped over Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) before sending patches. -**We do not accept GitHub pull requests** -(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). - Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file. - diff --git a/vendor/golang.org/x/net/bpf/instructions.go b/vendor/golang.org/x/net/bpf/instructions.go index 3b4fd089..f9dc0e8e 100644 --- a/vendor/golang.org/x/net/bpf/instructions.go +++ b/vendor/golang.org/x/net/bpf/instructions.go @@ -198,7 +198,7 @@ func (a LoadConstant) Assemble() (RawInstruction, error) { return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val) } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a LoadConstant) String() string { switch a.Dst { case RegA: @@ -224,7 +224,7 @@ func (a LoadScratch) Assemble() (RawInstruction, error) { return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N)) } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a LoadScratch) String() string { switch a.Dst { case RegA: @@ -248,7 +248,7 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) { return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off) } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a LoadAbsolute) String() string { switch a.Size { case 1: // byte @@ -277,7 +277,7 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) { return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off) } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a LoadIndirect) String() string { switch a.Size { case 1: // byte @@ -306,7 +306,7 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) { return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off) } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a LoadMemShift) String() string { return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off) } @@ -325,7 +325,7 @@ func (a LoadExtension) Assemble() (RawInstruction, error) { return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num)) } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a LoadExtension) String() string { switch a.Num { case ExtLen: @@ -392,7 +392,7 @@ func (a StoreScratch) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a StoreScratch) String() string { switch a.Src { case RegA: @@ -418,7 +418,7 @@ func (a ALUOpConstant) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a ALUOpConstant) String() string { switch a.Op { case ALUOpAdd: @@ -458,7 +458,7 @@ func (a ALUOpX) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a ALUOpX) String() string { switch a.Op { case ALUOpAdd: @@ -496,7 +496,7 @@ func (a NegateA) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a NegateA) String() string { return fmt.Sprintf("neg") } @@ -514,7 +514,7 @@ func (a Jump) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a Jump) String() string { return fmt.Sprintf("ja %d", a.Skip) } @@ -566,7 +566,7 @@ func (a JumpIf) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a JumpIf) String() string { switch a.Cond { // K == A @@ -621,7 +621,7 @@ func (a RetA) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a RetA) String() string { return fmt.Sprintf("ret a") } @@ -639,7 +639,7 @@ func (a RetConstant) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a RetConstant) String() string { return fmt.Sprintf("ret #%d", a.Val) } @@ -654,7 +654,7 @@ func (a TXA) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a TXA) String() string { return fmt.Sprintf("txa") } @@ -669,7 +669,7 @@ func (a TAX) Assemble() (RawInstruction, error) { }, nil } -// String returns the the instruction in assembler notation. +// String returns the instruction in assembler notation. func (a TAX) String() string { return fmt.Sprintf("tax") } diff --git a/vendor/golang.org/x/net/dns/dnsmessage/example_test.go b/vendor/golang.org/x/net/dns/dnsmessage/example_test.go index 5415c2d3..8600a6bc 100644 --- a/vendor/golang.org/x/net/dns/dnsmessage/example_test.go +++ b/vendor/golang.org/x/net/dns/dnsmessage/example_test.go @@ -37,20 +37,20 @@ func ExampleParser() { }, Answers: []dnsmessage.Resource{ { - dnsmessage.ResourceHeader{ + Header: dnsmessage.ResourceHeader{ Name: mustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, }, - &dnsmessage.AResource{[4]byte{127, 0, 0, 1}}, + Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}}, }, { - dnsmessage.ResourceHeader{ + Header: dnsmessage.ResourceHeader{ Name: mustNewName("bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, }, - &dnsmessage.AResource{[4]byte{127, 0, 0, 2}}, + Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 2}}, }, }, } diff --git a/vendor/golang.org/x/net/dns/dnsmessage/message.go b/vendor/golang.org/x/net/dns/dnsmessage/message.go index c7244b78..13fbc081 100644 --- a/vendor/golang.org/x/net/dns/dnsmessage/message.go +++ b/vendor/golang.org/x/net/dns/dnsmessage/message.go @@ -5,6 +5,9 @@ // Package dnsmessage provides a mostly RFC 1035 compliant implementation of // DNS message packing and unpacking. // +// The package also supports messages with Extension Mechanisms for DNS +// (EDNS(0)) as defined in RFC 6891. +// // This implementation is designed to minimize heap allocations and avoid // unnecessary packing and unpacking as much as possible. package dnsmessage @@ -13,21 +16,11 @@ import ( "errors" ) -// Packet formats +// Message formats // A Type is a type of DNS request and response. type Type uint16 -// A Class is a type of network. -type Class uint16 - -// An OpCode is a DNS operation code. -type OpCode uint16 - -// An RCode is a DNS response status code. -type RCode uint16 - -// Wire constants. const ( // ResourceHeader.Type and Question.Type TypeA Type = 1 @@ -39,6 +32,7 @@ const ( TypeTXT Type = 16 TypeAAAA Type = 28 TypeSRV Type = 33 + TypeOPT Type = 41 // Question.Type TypeWKS Type = 11 @@ -46,7 +40,46 @@ const ( TypeMINFO Type = 14 TypeAXFR Type = 252 TypeALL Type = 255 +) +var typeNames = map[Type]string{ + TypeA: "TypeA", + TypeNS: "TypeNS", + TypeCNAME: "TypeCNAME", + TypeSOA: "TypeSOA", + TypePTR: "TypePTR", + TypeMX: "TypeMX", + TypeTXT: "TypeTXT", + TypeAAAA: "TypeAAAA", + TypeSRV: "TypeSRV", + TypeOPT: "TypeOPT", + TypeWKS: "TypeWKS", + TypeHINFO: "TypeHINFO", + TypeMINFO: "TypeMINFO", + TypeAXFR: "TypeAXFR", + TypeALL: "TypeALL", +} + +// String implements fmt.Stringer.String. +func (t Type) String() string { + if n, ok := typeNames[t]; ok { + return n + } + return printUint16(uint16(t)) +} + +// GoString implements fmt.GoStringer.GoString. +func (t Type) GoString() string { + if n, ok := typeNames[t]; ok { + return "dnsmessage." + n + } + return printUint16(uint16(t)) +} + +// A Class is a type of network. +type Class uint16 + +const ( // ResourceHeader.Class and Question.Class ClassINET Class = 1 ClassCSNET Class = 2 @@ -55,7 +88,44 @@ const ( // Question.Class ClassANY Class = 255 +) +var classNames = map[Class]string{ + ClassINET: "ClassINET", + ClassCSNET: "ClassCSNET", + ClassCHAOS: "ClassCHAOS", + ClassHESIOD: "ClassHESIOD", + ClassANY: "ClassANY", +} + +// String implements fmt.Stringer.String. +func (c Class) String() string { + if n, ok := classNames[c]; ok { + return n + } + return printUint16(uint16(c)) +} + +// GoString implements fmt.GoStringer.GoString. +func (c Class) GoString() string { + if n, ok := classNames[c]; ok { + return "dnsmessage." + n + } + return printUint16(uint16(c)) +} + +// An OpCode is a DNS operation code. +type OpCode uint16 + +// GoString implements fmt.GoStringer.GoString. +func (o OpCode) GoString() string { + return printUint16(uint16(o)) +} + +// An RCode is a DNS response status code. +type RCode uint16 + +const ( // Message.Rcode RCodeSuccess RCode = 0 RCodeFormatError RCode = 1 @@ -65,6 +135,116 @@ const ( RCodeRefused RCode = 5 ) +var rCodeNames = map[RCode]string{ + RCodeSuccess: "RCodeSuccess", + RCodeFormatError: "RCodeFormatError", + RCodeServerFailure: "RCodeServerFailure", + RCodeNameError: "RCodeNameError", + RCodeNotImplemented: "RCodeNotImplemented", + RCodeRefused: "RCodeRefused", +} + +// String implements fmt.Stringer.String. +func (r RCode) String() string { + if n, ok := rCodeNames[r]; ok { + return n + } + return printUint16(uint16(r)) +} + +// GoString implements fmt.GoStringer.GoString. +func (r RCode) GoString() string { + if n, ok := rCodeNames[r]; ok { + return "dnsmessage." + n + } + return printUint16(uint16(r)) +} + +func printPaddedUint8(i uint8) string { + b := byte(i) + return string([]byte{ + b/100 + '0', + b/10%10 + '0', + b%10 + '0', + }) +} + +func printUint8Bytes(buf []byte, i uint8) []byte { + b := byte(i) + if i >= 100 { + buf = append(buf, b/100+'0') + } + if i >= 10 { + buf = append(buf, b/10%10+'0') + } + return append(buf, b%10+'0') +} + +func printByteSlice(b []byte) string { + if len(b) == 0 { + return "" + } + buf := make([]byte, 0, 5*len(b)) + buf = printUint8Bytes(buf, uint8(b[0])) + for _, n := range b[1:] { + buf = append(buf, ',', ' ') + buf = printUint8Bytes(buf, uint8(n)) + } + return string(buf) +} + +const hexDigits = "0123456789abcdef" + +func printString(str []byte) string { + buf := make([]byte, 0, len(str)) + for i := 0; i < len(str); i++ { + c := str[i] + if c == '.' || c == '-' || c == ' ' || + 'A' <= c && c <= 'Z' || + 'a' <= c && c <= 'z' || + '0' <= c && c <= '9' { + buf = append(buf, c) + continue + } + + upper := c >> 4 + lower := (c << 4) >> 4 + buf = append( + buf, + '\\', + 'x', + hexDigits[upper], + hexDigits[lower], + ) + } + return string(buf) +} + +func printUint16(i uint16) string { + return printUint32(uint32(i)) +} + +func printUint32(i uint32) string { + // Max value is 4294967295. + buf := make([]byte, 10) + for b, d := buf, uint32(1000000000); d > 0; d /= 10 { + b[0] = byte(i/d%10 + '0') + if b[0] == '0' && len(b) == len(buf) && len(buf) > 1 { + buf = buf[1:] + } + b = b[1:] + i %= d + } + return string(buf) +} + +func printBool(b bool) string { + if b { + return "true" + } + return "false" +} + var ( // ErrNotStarted indicates that the prerequisite information isn't // available yet because the previous records haven't been appropriately @@ -90,6 +270,8 @@ var ( errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)") errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)") errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)") + errStringTooLong = errors.New("character string exceeds maximum length (255)") + errCompressedSRV = errors.New("compressed name in SRV resource data") ) // Internal constants. @@ -159,6 +341,19 @@ func (m *Header) pack() (id uint16, bits uint16) { return } +// GoString implements fmt.GoStringer.GoString. +func (m *Header) GoString() string { + return "dnsmessage.Header{" + + "ID: " + printUint16(m.ID) + ", " + + "Response: " + printBool(m.Response) + ", " + + "OpCode: " + m.OpCode.GoString() + ", " + + "Authoritative: " + printBool(m.Authoritative) + ", " + + "Truncated: " + printBool(m.Truncated) + ", " + + "RecursionDesired: " + printBool(m.RecursionDesired) + ", " + + "RecursionAvailable: " + printBool(m.RecursionAvailable) + ", " + + "RCode: " + m.RCode.GoString() + "}" +} + // Message is a representation of a DNS message. type Message struct { Header @@ -218,6 +413,7 @@ func (h *header) count(sec section) uint16 { return 0 } +// pack appends the wire format of the header to msg. func (h *header) pack(msg []byte) []byte { msg = packUint16(msg, h.id) msg = packUint16(msg, h.bits) @@ -270,32 +466,43 @@ type Resource struct { Body ResourceBody } +func (r *Resource) GoString() string { + return "dnsmessage.Resource{" + + "Header: " + r.Header.GoString() + + ", Body: &" + r.Body.GoString() + + "}" +} + // A ResourceBody is a DNS resource record minus the header. type ResourceBody interface { // pack packs a Resource except for its header. - pack(msg []byte, compression map[string]int) ([]byte, error) + pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) // realType returns the actual type of the Resource. This is used to // fill in the header Type field. realType() Type + + // GoString implements fmt.GoStringer.GoString. + GoString() string } -func (r *Resource) pack(msg []byte, compression map[string]int) ([]byte, error) { +// pack appends the wire format of the Resource to msg. +func (r *Resource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { if r.Body == nil { return msg, errNilResouceBody } oldMsg := msg r.Header.Type = r.Body.realType() - msg, length, err := r.Header.pack(msg, compression) + msg, lenOff, err := r.Header.pack(msg, compression, compressionOff) if err != nil { return msg, &nestedError{"ResourceHeader", err} } preLen := len(msg) - msg, err = r.Body.pack(msg, compression) + msg, err = r.Body.pack(msg, compression, compressionOff) if err != nil { return msg, &nestedError{"content", err} } - if err := r.Header.fixLen(msg, length, preLen); err != nil { + if err := r.Header.fixLen(msg, lenOff, preLen); err != nil { return oldMsg, err } return msg, nil @@ -436,7 +643,13 @@ func (p *Parser) Question() (Question, error) { // AllQuestions parses all Questions. func (p *Parser) AllQuestions() ([]Question, error) { - qs := make([]Question, 0, p.header.questions) + // Multiple questions are valid according to the spec, + // but servers don't actually support them. There will + // be at most one question here. + // + // Do not pre-allocate based on info in p.header, since + // the data is untrusted. + qs := []Question{} for { q, err := p.Question() if err == ErrSectionDone { @@ -492,7 +705,16 @@ func (p *Parser) Answer() (Resource, error) { // AllAnswers parses all Answer Resources. func (p *Parser) AllAnswers() ([]Resource, error) { - as := make([]Resource, 0, p.header.answers) + // The most common query is for A/AAAA, which usually returns + // a handful of IPs. + // + // Pre-allocate up to a certain limit, since p.header is + // untrusted data. + n := int(p.header.answers) + if n > 20 { + n = 20 + } + as := make([]Resource, 0, n) for { a, err := p.Answer() if err == ErrSectionDone { @@ -533,7 +755,16 @@ func (p *Parser) Authority() (Resource, error) { // AllAuthorities parses all Authority Resources. func (p *Parser) AllAuthorities() ([]Resource, error) { - as := make([]Resource, 0, p.header.authorities) + // Authorities contains SOA in case of NXDOMAIN and friends, + // otherwise it is empty. + // + // Pre-allocate up to a certain limit, since p.header is + // untrusted data. + n := int(p.header.authorities) + if n > 10 { + n = 10 + } + as := make([]Resource, 0, n) for { a, err := p.Authority() if err == ErrSectionDone { @@ -574,7 +805,16 @@ func (p *Parser) Additional() (Resource, error) { // AllAdditionals parses all Additional Resources. func (p *Parser) AllAdditionals() ([]Resource, error) { - as := make([]Resource, 0, p.header.additionals) + // Additionals usually contain OPT, and sometimes A/AAAA + // glue records. + // + // Pre-allocate up to a certain limit, since p.header is + // untrusted data. + n := int(p.header.additionals) + if n > 10 { + n = 10 + } + as := make([]Resource, 0, n) for { a, err := p.Additional() if err == ErrSectionDone { @@ -765,6 +1005,24 @@ func (p *Parser) AAAAResource() (AAAAResource, error) { return r, nil } +// OPTResource parses a single OPTResource. +// +// One of the XXXHeader methods must have been called before calling this +// method. +func (p *Parser) OPTResource() (OPTResource, error) { + if !p.resHeaderValid || p.resHeader.Type != TypeOPT { + return OPTResource{}, ErrNotStarted + } + r, err := unpackOPTResource(p.msg, p.off, p.resHeader.Length) + if err != nil { + return OPTResource{}, err + } + p.off += int(p.resHeader.Length) + p.resHeaderValid = false + p.index++ + return r, nil +} + // Unpack parses a full Message. func (m *Message) Unpack(msg []byte) error { var p Parser @@ -819,6 +1077,7 @@ func (m *Message) AppendPack(b []byte) ([]byte, error) { h.authorities = uint16(len(m.Authorities)) h.additionals = uint16(len(m.Additionals)) + compressionOff := len(b) msg := h.pack(b) // RFC 1035 allows (but does not require) compression for packing. RFC @@ -826,32 +1085,32 @@ func (m *Message) AppendPack(b []byte) ([]byte, error) { // unconditionally enabling it is fine. // // DNS lookups are typically done over UDP, and RFC 1035 states that UDP - // DNS packets can be a maximum of 512 bytes long. Without compression, - // many DNS response packets are over this limit, so enabling + // DNS messages can be a maximum of 512 bytes long. Without compression, + // many DNS response messages are over this limit, so enabling // compression will help ensure compliance. compression := map[string]int{} for i := range m.Questions { var err error - if msg, err = m.Questions[i].pack(msg, compression); err != nil { + if msg, err = m.Questions[i].pack(msg, compression, compressionOff); err != nil { return nil, &nestedError{"packing Question", err} } } for i := range m.Answers { var err error - if msg, err = m.Answers[i].pack(msg, compression); err != nil { + if msg, err = m.Answers[i].pack(msg, compression, compressionOff); err != nil { return nil, &nestedError{"packing Answer", err} } } for i := range m.Authorities { var err error - if msg, err = m.Authorities[i].pack(msg, compression); err != nil { + if msg, err = m.Authorities[i].pack(msg, compression, compressionOff); err != nil { return nil, &nestedError{"packing Authority", err} } } for i := range m.Additionals { var err error - if msg, err = m.Additionals[i].pack(msg, compression); err != nil { + if msg, err = m.Additionals[i].pack(msg, compression, compressionOff); err != nil { return nil, &nestedError{"packing Additional", err} } } @@ -859,37 +1118,104 @@ func (m *Message) AppendPack(b []byte) ([]byte, error) { return msg, nil } +// GoString implements fmt.GoStringer.GoString. +func (m *Message) GoString() string { + s := "dnsmessage.Message{Header: " + m.Header.GoString() + ", " + + "Questions: []dnsmessage.Question{" + if len(m.Questions) > 0 { + s += m.Questions[0].GoString() + for _, q := range m.Questions[1:] { + s += ", " + q.GoString() + } + } + s += "}, Answers: []dnsmessage.Resource{" + if len(m.Answers) > 0 { + s += m.Answers[0].GoString() + for _, a := range m.Answers[1:] { + s += ", " + a.GoString() + } + } + s += "}, Authorities: []dnsmessage.Resource{" + if len(m.Authorities) > 0 { + s += m.Authorities[0].GoString() + for _, a := range m.Authorities[1:] { + s += ", " + a.GoString() + } + } + s += "}, Additionals: []dnsmessage.Resource{" + if len(m.Additionals) > 0 { + s += m.Additionals[0].GoString() + for _, a := range m.Additionals[1:] { + s += ", " + a.GoString() + } + } + return s + "}}" +} + // A Builder allows incrementally packing a DNS message. +// +// Example usage: +// buf := make([]byte, 2, 514) +// b := NewBuilder(buf, Header{...}) +// b.EnableCompression() +// // Optionally start a section and add things to that section. +// // Repeat adding sections as necessary. +// buf, err := b.Finish() +// // If err is nil, buf[2:] will contain the built bytes. type Builder struct { - msg []byte - header header - section section + // msg is the storage for the message being built. + msg []byte + + // section keeps track of the current section being built. + section section + + // header keeps track of what should go in the header when Finish is + // called. + header header + + // start is the starting index of the bytes allocated in msg for header. + start int + + // compression is a mapping from name suffixes to their starting index + // in msg. compression map[string]int } -// Start initializes the builder. +// NewBuilder creates a new builder with compression disabled. // -// buf is optional (nil is fine), but if provided, Start takes ownership of buf. -func (b *Builder) Start(buf []byte, h Header) { - b.StartWithoutCompression(buf, h) - b.compression = map[string]int{} +// Note: Most users will want to immediately enable compression with the +// EnableCompression method. See that method's comment for why you may or may +// not want to enable compression. +// +// The DNS message is appended to the provided initial buffer buf (which may be +// nil) as it is built. The final message is returned by the (*Builder).Finish +// method, which may return the same underlying array if there was sufficient +// capacity in the slice. +func NewBuilder(buf []byte, h Header) Builder { + if buf == nil { + buf = make([]byte, 0, packStartingCap) + } + b := Builder{msg: buf, start: len(buf)} + b.header.id, b.header.bits = h.pack() + var hb [headerLen]byte + b.msg = append(b.msg, hb[:]...) + b.section = sectionHeader + return b } -// StartWithoutCompression initializes the builder with compression disabled. +// EnableCompression enables compression in the Builder. // -// This avoids compression related allocations, but can result in larger message -// sizes. Be careful with this mode as it can cause messages to exceed the UDP -// size limit. +// Leaving compression disabled avoids compression related allocations, but can +// result in larger message sizes. Be careful with this mode as it can cause +// messages to exceed the UDP size limit. // -// buf is optional (nil is fine), but if provided, Start takes ownership of buf. -func (b *Builder) StartWithoutCompression(buf []byte, h Header) { - *b = Builder{msg: buf} - b.header.id, b.header.bits = h.pack() - if cap(b.msg) < headerLen { - b.msg = make([]byte, 0, packStartingCap) - } - b.msg = b.msg[:headerLen] - b.section = sectionHeader +// According to RFC 1035, section 4.1.4, the use of compression is optional, but +// all implementations must accept both compressed and uncompressed DNS +// messages. +// +// Compression should be enabled before any sections are added for best results. +func (b *Builder) EnableCompression() { + b.compression = map[string]int{} } func (b *Builder) startCheck(s section) error { @@ -970,7 +1296,7 @@ func (b *Builder) Question(q Question) error { if b.section > sectionQuestions { return ErrSectionDone } - msg, err := q.pack(b.msg, b.compression) + msg, err := q.pack(b.msg, b.compression, b.start) if err != nil { return err } @@ -997,15 +1323,15 @@ func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"CNAMEResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1021,15 +1347,15 @@ func (b *Builder) MXResource(h ResourceHeader, r MXResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"MXResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1045,15 +1371,15 @@ func (b *Builder) NSResource(h ResourceHeader, r NSResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"NSResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1069,15 +1395,15 @@ func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"PTRResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1093,15 +1419,15 @@ func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"SOAResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1117,15 +1443,15 @@ func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"TXTResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1141,15 +1467,15 @@ func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"SRVResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1165,15 +1491,15 @@ func (b *Builder) AResource(h ResourceHeader, r AResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"AResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1189,15 +1515,15 @@ func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error { return err } h.Type = r.realType() - msg, length, err := h.pack(b.msg, b.compression) + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) if err != nil { return &nestedError{"ResourceHeader", err} } preLen := len(msg) - if msg, err = r.pack(msg, b.compression); err != nil { + if msg, err = r.pack(msg, b.compression, b.start); err != nil { return &nestedError{"AAAAResource body", err} } - if err := h.fixLen(msg, length, preLen); err != nil { + if err := h.fixLen(msg, lenOff, preLen); err != nil { return err } if err := b.incrementSectionCount(); err != nil { @@ -1207,13 +1533,38 @@ func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error { return nil } -// Finish ends message building and generates a binary packet. +// OPTResource adds a single OPTResource. +func (b *Builder) OPTResource(h ResourceHeader, r OPTResource) error { + if err := b.checkResourceSection(); err != nil { + return err + } + h.Type = r.realType() + msg, lenOff, err := h.pack(b.msg, b.compression, b.start) + if err != nil { + return &nestedError{"ResourceHeader", err} + } + preLen := len(msg) + if msg, err = r.pack(msg, b.compression, b.start); err != nil { + return &nestedError{"OPTResource body", err} + } + if err := h.fixLen(msg, lenOff, preLen); err != nil { + return err + } + if err := b.incrementSectionCount(); err != nil { + return err + } + b.msg = msg + return nil +} + +// Finish ends message building and generates a binary message. func (b *Builder) Finish() ([]byte, error) { if b.section < sectionHeader { return nil, ErrNotStarted } b.section = sectionDone - b.header.pack(b.msg[:0]) + // Space for the header was allocated in NewBuilder. + b.header.pack(b.msg[b.start:b.start]) return b.msg, nil } @@ -1243,20 +1594,30 @@ type ResourceHeader struct { Length uint16 } -// pack packs all of the fields in a ResourceHeader except for the length. The -// length bytes are returned as a slice so they can be filled in after the rest -// of the Resource has been packed. -func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]int) (msg []byte, length []byte, err error) { +// GoString implements fmt.GoStringer.GoString. +func (h *ResourceHeader) GoString() string { + return "dnsmessage.ResourceHeader{" + + "Name: " + h.Name.GoString() + ", " + + "Type: " + h.Type.GoString() + ", " + + "Class: " + h.Class.GoString() + ", " + + "TTL: " + printUint32(h.TTL) + ", " + + "Length: " + printUint16(h.Length) + "}" +} + +// pack appends the wire format of the ResourceHeader to oldMsg. +// +// lenOff is the offset in msg where the Length field was packed. +func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]int, compressionOff int) (msg []byte, lenOff int, err error) { msg = oldMsg - if msg, err = h.Name.pack(msg, compression); err != nil { - return oldMsg, nil, &nestedError{"Name", err} + if msg, err = h.Name.pack(msg, compression, compressionOff); err != nil { + return oldMsg, 0, &nestedError{"Name", err} } msg = packType(msg, h.Type) msg = packClass(msg, h.Class) msg = packUint32(msg, h.TTL) - lenBegin := len(msg) + lenOff = len(msg) msg = packUint16(msg, h.Length) - return msg, msg[lenBegin : lenBegin+uint16Len], nil + return msg, lenOff, nil } func (h *ResourceHeader) unpack(msg []byte, off int) (int, error) { @@ -1280,19 +1641,63 @@ func (h *ResourceHeader) unpack(msg []byte, off int) (int, error) { return newOff, nil } -func (h *ResourceHeader) fixLen(msg []byte, length []byte, preLen int) error { +// fixLen updates a packed ResourceHeader to include the length of the +// ResourceBody. +// +// lenOff is the offset of the ResourceHeader.Length field in msg. +// +// preLen is the length that msg was before the ResourceBody was packed. +func (h *ResourceHeader) fixLen(msg []byte, lenOff int, preLen int) error { conLen := len(msg) - preLen if conLen > int(^uint16(0)) { return errResTooLong } // Fill in the length now that we know how long the content is. - packUint16(length[:0], uint16(conLen)) + packUint16(msg[lenOff:lenOff], uint16(conLen)) h.Length = uint16(conLen) return nil } +// EDNS(0) wire costants. +const ( + edns0Version = 0 + + edns0DNSSECOK = 0x00008000 + ednsVersionMask = 0x00ff0000 + edns0DNSSECOKMask = 0x00ff8000 +) + +// SetEDNS0 configures h for EDNS(0). +// +// The provided extRCode must be an extedned RCode. +func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error { + h.Name = Name{Data: [nameLen]byte{'.'}, Length: 1} // RFC 6891 section 6.1.2 + h.Type = TypeOPT + h.Class = Class(udpPayloadLen) + h.TTL = uint32(extRCode) >> 4 << 24 + if dnssecOK { + h.TTL |= edns0DNSSECOK + } + return nil +} + +// DNSSECAllowed reports whether the DNSSEC OK bit is set. +func (h *ResourceHeader) DNSSECAllowed() bool { + return h.TTL&edns0DNSSECOKMask == edns0DNSSECOK // RFC 6891 section 6.1.3 +} + +// ExtendedRCode returns an extended RCode. +// +// The provided rcode must be the RCode in DNS message header. +func (h *ResourceHeader) ExtendedRCode(rcode RCode) RCode { + if h.TTL&ednsVersionMask == edns0Version { // RFC 6891 section 6.1.3 + return RCode(h.TTL>>24<<4) | rcode + } + return rcode +} + func skipResource(msg []byte, off int) (int, error) { newOff, err := skipName(msg, off) if err != nil { @@ -1317,6 +1722,7 @@ func skipResource(msg []byte, off int) (int, error) { return newOff, nil } +// packUint16 appends the wire format of field to msg. func packUint16(msg []byte, field uint16) []byte { return append(msg, byte(field>>8), byte(field)) } @@ -1335,6 +1741,7 @@ func skipUint16(msg []byte, off int) (int, error) { return off + uint16Len, nil } +// packType appends the wire format of field to msg. func packType(msg []byte, field Type) []byte { return packUint16(msg, uint16(field)) } @@ -1348,6 +1755,7 @@ func skipType(msg []byte, off int) (int, error) { return skipUint16(msg, off) } +// packClass appends the wire format of field to msg. func packClass(msg []byte, field Class) []byte { return packUint16(msg, uint16(field)) } @@ -1361,6 +1769,7 @@ func skipClass(msg []byte, off int) (int, error) { return skipUint16(msg, off) } +// packUint32 appends the wire format of field to msg. func packUint32(msg []byte, field uint32) []byte { return append( msg, @@ -1386,17 +1795,16 @@ func skipUint32(msg []byte, off int) (int, error) { return off + uint32Len, nil } -func packText(msg []byte, field string) []byte { - for len(field) > 0 { - l := len(field) - if l > 255 { - l = 255 - } - msg = append(msg, byte(l)) - msg = append(msg, field[:l]...) - field = field[l:] +// packText appends the wire format of field to msg. +func packText(msg []byte, field string) ([]byte, error) { + l := len(field) + if l > 255 { + return nil, errStringTooLong } - return msg + msg = append(msg, byte(l)) + msg = append(msg, field...) + + return msg, nil } func unpackText(msg []byte, off int) (string, int, error) { @@ -1422,6 +1830,7 @@ func skipText(msg []byte, off int) (int, error) { return endOff, nil } +// packBytes appends the wire format of field to msg. func packBytes(msg []byte, field []byte) []byte { return append(msg, field...) } @@ -1462,18 +1871,33 @@ func NewName(name string) (Name, error) { return n, nil } +// MustNewName creates a new Name from a string and panics on error. +func MustNewName(name string) Name { + n, err := NewName(name) + if err != nil { + panic("creating name: " + err.Error()) + } + return n +} + +// String implements fmt.Stringer.String. func (n Name) String() string { return string(n.Data[:n.Length]) } -// pack packs a domain name. +// GoString implements fmt.GoStringer.GoString. +func (n *Name) GoString() string { + return `dnsmessage.MustNewName("` + printString(n.Data[:n.Length]) + `")` +} + +// pack appends the wire format of the Name to msg. // // Domain names are a sequence of counted strings split at the dots. They end // with a zero-length string. Compression can be used to reuse domain suffixes. // // The compression map will be updated with new domain suffixes. If compression // is nil, compression will not be used. -func (n *Name) pack(msg []byte, compression map[string]int) ([]byte, error) { +func (n *Name) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { oldMsg := msg // Add a trailing dot to canonicalize name. @@ -1525,7 +1949,7 @@ func (n *Name) pack(msg []byte, compression map[string]int) ([]byte, error) { // Miss. Add the suffix to the compression table if the // offset can be stored in the available 14 bytes. if len(msg) <= int(^uint16(0)>>2) { - compression[string(n.Data[i:])] = len(msg) + compression[string(n.Data[i:])] = len(msg) - compressionOff } } } @@ -1534,6 +1958,10 @@ func (n *Name) pack(msg []byte, compression map[string]int) ([]byte, error) { // unpack unpacks a domain name. func (n *Name) unpack(msg []byte, off int) (int, error) { + return n.unpackCompressed(msg, off, true /* allowCompression */) +} + +func (n *Name) unpackCompressed(msg []byte, off int, allowCompression bool) (int, error) { // currOff is the current working offset. currOff := off @@ -1569,6 +1997,9 @@ Loop: name = append(name, '.') currOff = endOff case 0xC0: // Pointer + if !allowCompression { + return off, errCompressedSRV + } if currOff >= len(msg) { return off, errInvalidPtr } @@ -1648,8 +2079,9 @@ type Question struct { Class Class } -func (q *Question) pack(msg []byte, compression map[string]int) ([]byte, error) { - msg, err := q.Name.pack(msg, compression) +// pack appends the wire format of the Question to msg. +func (q *Question) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { + msg, err := q.Name.pack(msg, compression, compressionOff) if err != nil { return msg, &nestedError{"Name", err} } @@ -1657,6 +2089,14 @@ func (q *Question) pack(msg []byte, compression map[string]int) ([]byte, error) return packClass(msg, q.Class), nil } +// GoString implements fmt.GoStringer.GoString. +func (q *Question) GoString() string { + return "dnsmessage.Question{" + + "Name: " + q.Name.GoString() + ", " + + "Type: " + q.Type.GoString() + ", " + + "Class: " + q.Class.GoString() + "}" +} + func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, int, error) { var ( r ResourceBody @@ -1709,6 +2149,11 @@ func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody, rb, err = unpackSRVResource(msg, off) r = &rb name = "SRV" + case TypeOPT: + var rb OPTResource + rb, err = unpackOPTResource(msg, off, hdr.Length) + r = &rb + name = "OPT" } if err != nil { return nil, off, &nestedError{name + " record", err} @@ -1728,8 +2173,14 @@ func (r *CNAMEResource) realType() Type { return TypeCNAME } -func (r *CNAMEResource) pack(msg []byte, compression map[string]int) ([]byte, error) { - return r.CNAME.pack(msg, compression) +// pack appends the wire format of the CNAMEResource to msg. +func (r *CNAMEResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { + return r.CNAME.pack(msg, compression, compressionOff) +} + +// GoString implements fmt.GoStringer.GoString. +func (r *CNAMEResource) GoString() string { + return "dnsmessage.CNAMEResource{CNAME: " + r.CNAME.GoString() + "}" } func unpackCNAMEResource(msg []byte, off int) (CNAMEResource, error) { @@ -1750,16 +2201,24 @@ func (r *MXResource) realType() Type { return TypeMX } -func (r *MXResource) pack(msg []byte, compression map[string]int) ([]byte, error) { +// pack appends the wire format of the MXResource to msg. +func (r *MXResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { oldMsg := msg msg = packUint16(msg, r.Pref) - msg, err := r.MX.pack(msg, compression) + msg, err := r.MX.pack(msg, compression, compressionOff) if err != nil { return oldMsg, &nestedError{"MXResource.MX", err} } return msg, nil } +// GoString implements fmt.GoStringer.GoString. +func (r *MXResource) GoString() string { + return "dnsmessage.MXResource{" + + "Pref: " + printUint16(r.Pref) + ", " + + "MX: " + r.MX.GoString() + "}" +} + func unpackMXResource(msg []byte, off int) (MXResource, error) { pref, off, err := unpackUint16(msg, off) if err != nil { @@ -1781,8 +2240,14 @@ func (r *NSResource) realType() Type { return TypeNS } -func (r *NSResource) pack(msg []byte, compression map[string]int) ([]byte, error) { - return r.NS.pack(msg, compression) +// pack appends the wire format of the NSResource to msg. +func (r *NSResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { + return r.NS.pack(msg, compression, compressionOff) +} + +// GoString implements fmt.GoStringer.GoString. +func (r *NSResource) GoString() string { + return "dnsmessage.NSResource{NS: " + r.NS.GoString() + "}" } func unpackNSResource(msg []byte, off int) (NSResource, error) { @@ -1802,8 +2267,14 @@ func (r *PTRResource) realType() Type { return TypePTR } -func (r *PTRResource) pack(msg []byte, compression map[string]int) ([]byte, error) { - return r.PTR.pack(msg, compression) +// pack appends the wire format of the PTRResource to msg. +func (r *PTRResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { + return r.PTR.pack(msg, compression, compressionOff) +} + +// GoString implements fmt.GoStringer.GoString. +func (r *PTRResource) GoString() string { + return "dnsmessage.PTRResource{PTR: " + r.PTR.GoString() + "}" } func unpackPTRResource(msg []byte, off int) (PTRResource, error) { @@ -1833,13 +2304,14 @@ func (r *SOAResource) realType() Type { return TypeSOA } -func (r *SOAResource) pack(msg []byte, compression map[string]int) ([]byte, error) { +// pack appends the wire format of the SOAResource to msg. +func (r *SOAResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { oldMsg := msg - msg, err := r.NS.pack(msg, compression) + msg, err := r.NS.pack(msg, compression, compressionOff) if err != nil { return oldMsg, &nestedError{"SOAResource.NS", err} } - msg, err = r.MBox.pack(msg, compression) + msg, err = r.MBox.pack(msg, compression, compressionOff) if err != nil { return oldMsg, &nestedError{"SOAResource.MBox", err} } @@ -1850,6 +2322,18 @@ func (r *SOAResource) pack(msg []byte, compression map[string]int) ([]byte, erro return packUint32(msg, r.MinTTL), nil } +// GoString implements fmt.GoStringer.GoString. +func (r *SOAResource) GoString() string { + return "dnsmessage.SOAResource{" + + "NS: " + r.NS.GoString() + ", " + + "MBox: " + r.MBox.GoString() + ", " + + "Serial: " + printUint32(r.Serial) + ", " + + "Refresh: " + printUint32(r.Refresh) + ", " + + "Retry: " + printUint32(r.Retry) + ", " + + "Expire: " + printUint32(r.Expire) + ", " + + "MinTTL: " + printUint32(r.MinTTL) + "}" +} + func unpackSOAResource(msg []byte, off int) (SOAResource, error) { var ns Name off, err := ns.unpack(msg, off) @@ -1885,19 +2369,41 @@ func unpackSOAResource(msg []byte, off int) (SOAResource, error) { // A TXTResource is a TXT Resource record. type TXTResource struct { - Txt string // Not a domain name. + TXT []string } func (r *TXTResource) realType() Type { return TypeTXT } -func (r *TXTResource) pack(msg []byte, compression map[string]int) ([]byte, error) { - return packText(msg, r.Txt), nil +// pack appends the wire format of the TXTResource to msg. +func (r *TXTResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { + oldMsg := msg + for _, s := range r.TXT { + var err error + msg, err = packText(msg, s) + if err != nil { + return oldMsg, err + } + } + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *TXTResource) GoString() string { + s := "dnsmessage.TXTResource{TXT: []string{" + if len(r.TXT) == 0 { + return s + "}}" + } + s += `"` + printString([]byte(r.TXT[0])) + for _, t := range r.TXT[1:] { + s += `", "` + printString([]byte(t)) + } + return s + `"}}` } func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) { - var txt string + txts := make([]string, 0, 1) for n := uint16(0); n < length; { var t string var err error @@ -1909,9 +2415,9 @@ func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) return TXTResource{}, errCalcLen } n += uint16(len(t)) + 1 - txt += t + txts = append(txts, t) } - return TXTResource{txt}, nil + return TXTResource{txts}, nil } // An SRVResource is an SRV Resource record. @@ -1926,18 +2432,28 @@ func (r *SRVResource) realType() Type { return TypeSRV } -func (r *SRVResource) pack(msg []byte, compression map[string]int) ([]byte, error) { +// pack appends the wire format of the SRVResource to msg. +func (r *SRVResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { oldMsg := msg msg = packUint16(msg, r.Priority) msg = packUint16(msg, r.Weight) msg = packUint16(msg, r.Port) - msg, err := r.Target.pack(msg, nil) + msg, err := r.Target.pack(msg, nil, compressionOff) if err != nil { return oldMsg, &nestedError{"SRVResource.Target", err} } return msg, nil } +// GoString implements fmt.GoStringer.GoString. +func (r *SRVResource) GoString() string { + return "dnsmessage.SRVResource{" + + "Priority: " + printUint16(r.Priority) + ", " + + "Weight: " + printUint16(r.Weight) + ", " + + "Port: " + printUint16(r.Port) + ", " + + "Target: " + r.Target.GoString() + "}" +} + func unpackSRVResource(msg []byte, off int) (SRVResource, error) { priority, off, err := unpackUint16(msg, off) if err != nil { @@ -1952,7 +2468,7 @@ func unpackSRVResource(msg []byte, off int) (SRVResource, error) { return SRVResource{}, &nestedError{"Port", err} } var target Name - if _, err := target.unpack(msg, off); err != nil { + if _, err := target.unpackCompressed(msg, off, false /* allowCompression */); err != nil { return SRVResource{}, &nestedError{"Target", err} } return SRVResource{priority, weight, port, target}, nil @@ -1967,10 +2483,17 @@ func (r *AResource) realType() Type { return TypeA } -func (r *AResource) pack(msg []byte, compression map[string]int) ([]byte, error) { +// pack appends the wire format of the AResource to msg. +func (r *AResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { return packBytes(msg, r.A[:]), nil } +// GoString implements fmt.GoStringer.GoString. +func (r *AResource) GoString() string { + return "dnsmessage.AResource{" + + "A: [4]byte{" + printByteSlice(r.A[:]) + "}}" +} + func unpackAResource(msg []byte, off int) (AResource, error) { var a [4]byte if _, err := unpackBytes(msg, off, a[:]); err != nil { @@ -1988,7 +2511,14 @@ func (r *AAAAResource) realType() Type { return TypeAAAA } -func (r *AAAAResource) pack(msg []byte, compression map[string]int) ([]byte, error) { +// GoString implements fmt.GoStringer.GoString. +func (r *AAAAResource) GoString() string { + return "dnsmessage.AAAAResource{" + + "AAAA: [16]byte{" + printByteSlice(r.AAAA[:]) + "}}" +} + +// pack appends the wire format of the AAAAResource to msg. +func (r *AAAAResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { return packBytes(msg, r.AAAA[:]), nil } @@ -1999,3 +2529,78 @@ func unpackAAAAResource(msg []byte, off int) (AAAAResource, error) { } return AAAAResource{aaaa}, nil } + +// An OPTResource is an OPT pseudo Resource record. +// +// The pseudo resource record is part of the extension mechanisms for DNS +// as defined in RFC 6891. +type OPTResource struct { + Options []Option +} + +// An Option represents a DNS message option within OPTResource. +// +// The message option is part of the extension mechanisms for DNS as +// defined in RFC 6891. +type Option struct { + Code uint16 // option code + Data []byte +} + +// GoString implements fmt.GoStringer.GoString. +func (o *Option) GoString() string { + return "dnsmessage.Option{" + + "Code: " + printUint16(o.Code) + ", " + + "Data: []byte{" + printByteSlice(o.Data) + "}}" +} + +func (r *OPTResource) realType() Type { + return TypeOPT +} + +func (r *OPTResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) { + for _, opt := range r.Options { + msg = packUint16(msg, opt.Code) + l := uint16(len(opt.Data)) + msg = packUint16(msg, l) + msg = packBytes(msg, opt.Data) + } + return msg, nil +} + +// GoString implements fmt.GoStringer.GoString. +func (r *OPTResource) GoString() string { + s := "dnsmessage.OPTResource{Options: []dnsmessage.Option{" + if len(r.Options) == 0 { + return s + "}}" + } + s += r.Options[0].GoString() + for _, o := range r.Options[1:] { + s += ", " + o.GoString() + } + return s + "}}" +} + +func unpackOPTResource(msg []byte, off int, length uint16) (OPTResource, error) { + var opts []Option + for oldOff := off; off < oldOff+int(length); { + var err error + var o Option + o.Code, off, err = unpackUint16(msg, off) + if err != nil { + return OPTResource{}, &nestedError{"Code", err} + } + var l uint16 + l, off, err = unpackUint16(msg, off) + if err != nil { + return OPTResource{}, &nestedError{"Data", err} + } + o.Data = make([]byte, l) + if copy(o.Data, msg[off:]) != int(l) { + return OPTResource{}, &nestedError{"Data", errCalcLen} + } + off += int(l) + opts = append(opts, o) + } + return OPTResource{opts}, nil +} diff --git a/vendor/golang.org/x/net/dns/dnsmessage/message_test.go b/vendor/golang.org/x/net/dns/dnsmessage/message_test.go index 2bb76342..25ba8f06 100644 --- a/vendor/golang.org/x/net/dns/dnsmessage/message_test.go +++ b/vendor/golang.org/x/net/dns/dnsmessage/message_test.go @@ -8,15 +8,109 @@ import ( "bytes" "fmt" "reflect" + "strings" "testing" ) -func mustNewName(name string) Name { - n, err := NewName(name) - if err != nil { +func TestPrintPaddedUint8(t *testing.T) { + tests := []struct { + num uint8 + want string + }{ + {0, "000"}, + {1, "001"}, + {9, "009"}, + {10, "010"}, + {99, "099"}, + {100, "100"}, + {124, "124"}, + {104, "104"}, + {120, "120"}, + {255, "255"}, + } + + for _, test := range tests { + if got := printPaddedUint8(test.num); got != test.want { + t.Errorf("got printPaddedUint8(%d) = %s, want = %s", test.num, got, test.want) + } + } +} + +func TestPrintUint8Bytes(t *testing.T) { + tests := []uint8{ + 0, + 1, + 9, + 10, + 99, + 100, + 124, + 104, + 120, + 255, + } + + for _, test := range tests { + if got, want := string(printUint8Bytes(nil, test)), fmt.Sprint(test); got != want { + t.Errorf("got printUint8Bytes(%d) = %s, want = %s", test, got, want) + } + } +} + +func TestPrintUint16(t *testing.T) { + tests := []uint16{ + 65535, + 0, + 1, + 10, + 100, + 1000, + 10000, + 324, + 304, + 320, + } + + for _, test := range tests { + if got, want := printUint16(test), fmt.Sprint(test); got != want { + t.Errorf("got printUint16(%d) = %s, want = %s", test, got, want) + } + } +} + +func TestPrintUint32(t *testing.T) { + tests := []uint32{ + 4294967295, + 65535, + 0, + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 324, + 304, + 320, + } + + for _, test := range tests { + if got, want := printUint32(test), fmt.Sprint(test); got != want { + t.Errorf("got printUint32(%d) = %s, want = %s", test, got, want) + } + } +} + +func mustEDNS0ResourceHeader(l int, extrc RCode, do bool) ResourceHeader { + h := ResourceHeader{Class: ClassINET} + if err := h.SetEDNS0(l, extrc, do); err != nil { panic(err) } - return n + return h } func (m *Message) String() string { @@ -50,7 +144,7 @@ func (m *Message) String() string { func TestNameString(t *testing.T) { want := "foo" - name := mustNewName(want) + name := MustNewName(want) if got := fmt.Sprint(name); got != want { t.Errorf("got fmt.Sprint(%#v) = %s, want = %s", name, got, want) } @@ -58,13 +152,13 @@ func TestNameString(t *testing.T) { func TestQuestionPackUnpack(t *testing.T) { want := Question{ - Name: mustNewName("."), + Name: MustNewName("."), Type: TypeA, Class: ClassINET, } - buf, err := want.pack(make([]byte, 1, 50), map[string]int{}) + buf, err := want.pack(make([]byte, 1, 50), map[string]int{}, 1) if err != nil { - t.Fatal("Packing failed:", err) + t.Fatal("Question.pack() =", err) } var p Parser p.msg = buf @@ -73,13 +167,13 @@ func TestQuestionPackUnpack(t *testing.T) { p.off = 1 got, err := p.Question() if err != nil { - t.Fatalf("Unpacking failed: %v\n%s", err, string(buf[1:])) + t.Fatalf("Parser{%q}.Question() = %v", string(buf[1:]), err) } if p.off != len(buf) { - t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", p.off, len(buf)) + t.Errorf("unpacked different amount than packed: got = %d, want = %d", p.off, len(buf)) } if !reflect.DeepEqual(got, want) { - t.Errorf("Got = %+v, want = %+v", got, want) + t.Errorf("got from Parser.Question() = %+v, want = %+v", got, want) } } @@ -99,11 +193,11 @@ func TestName(t *testing.T) { for _, test := range tests { n, err := NewName(test) if err != nil { - t.Errorf("Creating name for %q: %v", test, err) + t.Errorf("NewName(%q) = %v", test, err) continue } if ns := n.String(); ns != test { - t.Errorf("Got %#v.String() = %q, want = %q", n, ns, test) + t.Errorf("got %#v.String() = %q, want = %q", n, ns, test) continue } } @@ -127,11 +221,11 @@ func TestNamePackUnpack(t *testing.T) { } for _, test := range tests { - in := mustNewName(test.in) - want := mustNewName(test.want) - buf, err := in.pack(make([]byte, 0, 30), map[string]int{}) + in := MustNewName(test.in) + want := MustNewName(test.want) + buf, err := in.pack(make([]byte, 0, 30), map[string]int{}, 0) if err != test.err { - t.Errorf("Packing of %q: got err = %v, want err = %v", test.in, err, test.err) + t.Errorf("got %q.pack() = %v, want = %v", test.in, err, test.err) continue } if test.err != nil { @@ -140,23 +234,45 @@ func TestNamePackUnpack(t *testing.T) { var got Name n, err := got.unpack(buf, 0) if err != nil { - t.Errorf("Unpacking for %q failed: %v", test.in, err) + t.Errorf("%q.unpack() = %v", test.in, err) continue } if n != len(buf) { t.Errorf( - "Unpacked different amount than packed for %q: got n = %d, want = %d", + "unpacked different amount than packed for %q: got = %d, want = %d", test.in, n, len(buf), ) } if got != want { - t.Errorf("Unpacking packing of %q: got = %#v, want = %#v", test.in, got, want) + t.Errorf("unpacking packing of %q: got = %#v, want = %#v", test.in, got, want) } } } +func TestIncompressibleName(t *testing.T) { + name := MustNewName("example.com.") + compression := map[string]int{} + buf, err := name.pack(make([]byte, 0, 100), compression, 0) + if err != nil { + t.Fatal("first Name.pack() =", err) + } + buf, err = name.pack(buf, compression, 0) + if err != nil { + t.Fatal("second Name.pack() =", err) + } + var n1 Name + off, err := n1.unpackCompressed(buf, 0, false /* allowCompression */) + if err != nil { + t.Fatal("unpacking incompressible name without pointers failed:", err) + } + var n2 Name + if _, err := n2.unpackCompressed(buf, off, false /* allowCompression */); err != errCompressedSRV { + t.Errorf("unpacking compressed incompressible name with pointers: got %v, want = %v", err, errCompressedSRV) + } +} + func checkErrorPrefix(err error, prefix string) bool { e, ok := err.(*nestedError) return ok && e.s == prefix @@ -176,7 +292,7 @@ func TestHeaderUnpackError(t *testing.T) { for _, want := range wants { n, err := h.unpack(buf, 0) if n != 0 || !checkErrorPrefix(err, want) { - t.Errorf("got h.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want) + t.Errorf("got header.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want) } buf = append(buf, 0, 0) } @@ -188,7 +304,7 @@ func TestParserStart(t *testing.T) { for i := 0; i <= 1; i++ { _, err := p.Start([]byte{}) if !checkErrorPrefix(err, want) { - t.Errorf("got p.Start(nil) = _, %v, want = _, %s", err, want) + t.Errorf("got Parser.Start(nil) = _, %v, want = _, %s", err, want) } } } @@ -211,7 +327,7 @@ func TestResourceNotStarted(t *testing.T) { for _, test := range tests { if err := test.fn(&Parser{}); err != ErrNotStarted { - t.Errorf("got _, %v = p.%s(), want = _, %v", err, test.name, ErrNotStarted) + t.Errorf("got Parser.%s() = _ , %v, want = _, %v", test.name, err, ErrNotStarted) } } } @@ -221,7 +337,7 @@ func TestDNSPackUnpack(t *testing.T) { { Questions: []Question{ { - Name: mustNewName("."), + Name: MustNewName("."), Type: TypeAAAA, Class: ClassINET, }, @@ -235,15 +351,49 @@ func TestDNSPackUnpack(t *testing.T) { for i, want := range wants { b, err := want.Pack() if err != nil { - t.Fatalf("%d: packing failed: %v", i, err) + t.Fatalf("%d: Message.Pack() = %v", i, err) } var got Message err = got.Unpack(b) if err != nil { - t.Fatalf("%d: unpacking failed: %v", i, err) + t.Fatalf("%d: Message.Unapck() = %v", i, err) } if !reflect.DeepEqual(got, want) { - t.Errorf("%d: got = %+v, want = %+v", i, &got, &want) + t.Errorf("%d: Message.Pack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want) + } + } +} + +func TestDNSAppendPackUnpack(t *testing.T) { + wants := []Message{ + { + Questions: []Question{ + { + Name: MustNewName("."), + Type: TypeAAAA, + Class: ClassINET, + }, + }, + Answers: []Resource{}, + Authorities: []Resource{}, + Additionals: []Resource{}, + }, + largeTestMsg(), + } + for i, want := range wants { + b := make([]byte, 2, 514) + b, err := want.AppendPack(b) + if err != nil { + t.Fatalf("%d: Message.AppendPack() = %v", i, err) + } + b = b[2:] + var got Message + err = got.Unpack(b) + if err != nil { + t.Fatalf("%d: Message.Unapck() = %v", i, err) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("%d: Message.AppendPack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want) } } } @@ -252,11 +402,11 @@ func TestSkipAll(t *testing.T) { msg := largeTestMsg() buf, err := msg.Pack() if err != nil { - t.Fatal("Packing large test message:", err) + t.Fatal("Message.Pack() =", err) } var p Parser if _, err := p.Start(buf); err != nil { - t.Fatal(err) + t.Fatal("Parser.Start(non-nil) =", err) } tests := []struct { @@ -271,7 +421,7 @@ func TestSkipAll(t *testing.T) { for _, test := range tests { for i := 1; i <= 3; i++ { if err := test.f(); err != nil { - t.Errorf("Call #%d to %s(): %v", i, test.name, err) + t.Errorf("%d: Parser.%s() = %v", i, test.name, err) } } } @@ -282,11 +432,11 @@ func TestSkipEach(t *testing.T) { buf, err := msg.Pack() if err != nil { - t.Fatal("Packing test message:", err) + t.Fatal("Message.Pack() =", err) } var p Parser if _, err := p.Start(buf); err != nil { - t.Fatal(err) + t.Fatal("Parser.Start(non-nil) =", err) } tests := []struct { @@ -300,10 +450,10 @@ func TestSkipEach(t *testing.T) { } for _, test := range tests { if err := test.f(); err != nil { - t.Errorf("First call: got %s() = %v, want = %v", test.name, err, nil) + t.Errorf("first Parser.%s() = %v, want = nil", test.name, err) } if err := test.f(); err != ErrSectionDone { - t.Errorf("Second call: got %s() = %v, want = %v", test.name, err, ErrSectionDone) + t.Errorf("second Parser.%s() = %v, want = %v", test.name, err, ErrSectionDone) } } } @@ -313,11 +463,11 @@ func TestSkipAfterRead(t *testing.T) { buf, err := msg.Pack() if err != nil { - t.Fatal("Packing test message:", err) + t.Fatal("Message.Pack() =", err) } var p Parser if _, err := p.Start(buf); err != nil { - t.Fatal(err) + t.Fatal("Parser.Srart(non-nil) =", err) } tests := []struct { @@ -332,10 +482,10 @@ func TestSkipAfterRead(t *testing.T) { } for _, test := range tests { if err := test.read(); err != nil { - t.Errorf("Got %s() = _, %v, want = _, %v", test.name, err, nil) + t.Errorf("got Parser.%s() = _, %v, want = _, nil", test.name, err) } if err := test.skip(); err != ErrSectionDone { - t.Errorf("Got Skip%s() = %v, want = %v", test.name, err, ErrSectionDone) + t.Errorf("got Parser.Skip%s() = %v, want = %v", test.name, err, ErrSectionDone) } } } @@ -354,7 +504,7 @@ func TestSkipNotStarted(t *testing.T) { } for _, test := range tests { if err := test.f(); err != ErrNotStarted { - t.Errorf("Got %s() = %v, want = %v", test.name, err, ErrNotStarted) + t.Errorf("got Parser.%s() = %v, want = %v", test.name, err, ErrNotStarted) } } } @@ -398,7 +548,7 @@ func TestTooManyRecords(t *testing.T) { for _, test := range tests { if _, got := test.msg.Pack(); got != test.want { - t.Errorf("Packing %d %s: got = %v, want = %v", recs, test.name, got, test.want) + t.Errorf("got Message.Pack() for %d %s = %v, want = %v", recs, test.name, got, test.want) } } } @@ -406,31 +556,66 @@ func TestTooManyRecords(t *testing.T) { func TestVeryLongTxt(t *testing.T) { want := Resource{ ResourceHeader{ - Name: mustNewName("foo.bar.example.com."), + Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, }, - &TXTResource{loremIpsum}, + &TXTResource{[]string{ + "", + "", + "foo bar", + "", + "www.example.com", + "www.example.com.", + strings.Repeat(".", 255), + }}, } - buf, err := want.pack(make([]byte, 0, 8000), map[string]int{}) + buf, err := want.pack(make([]byte, 0, 8000), map[string]int{}, 0) if err != nil { - t.Fatal("Packing failed:", err) + t.Fatal("Resource.pack() =", err) } var got Resource off, err := got.Header.unpack(buf, 0) if err != nil { - t.Fatal("Unpacking ResourceHeader failed:", err) + t.Fatal("ResourceHeader.unpack() =", err) } body, n, err := unpackResourceBody(buf, off, got.Header) if err != nil { - t.Fatal("Unpacking failed:", err) + t.Fatal("unpackResourceBody() =", err) } got.Body = body if n != len(buf) { - t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", n, len(buf)) + t.Errorf("unpacked different amount than packed: got = %d, want = %d", n, len(buf)) } if !reflect.DeepEqual(got, want) { - t.Errorf("Got = %#v, want = %#v", got, want) + t.Errorf("Resource.pack/unpack() roundtrip: got = %#v, want = %#v", got, want) + } +} + +func TestTooLongTxt(t *testing.T) { + rb := TXTResource{[]string{strings.Repeat(".", 256)}} + if _, err := rb.pack(make([]byte, 0, 8000), map[string]int{}, 0); err != errStringTooLong { + t.Errorf("packing TXTResource with 256 character string: got err = %v, want = %v", err, errStringTooLong) + } +} + +func TestStartAppends(t *testing.T) { + buf := make([]byte, 2, 514) + wantBuf := []byte{4, 44} + copy(buf, wantBuf) + + b := NewBuilder(buf, Header{}) + b.EnableCompression() + + buf, err := b.Finish() + if err != nil { + t.Fatal("Builder.Finish() =", err) + } + if got, want := len(buf), headerLen+2; got != want { + t.Errorf("got len(buf) = %d, want = %d", got, want) + } + if string(buf[:2]) != string(wantBuf) { + t.Errorf("original data not preserved, got = %#v, want = %#v", buf[:2], wantBuf) } } @@ -457,7 +642,7 @@ func TestStartError(t *testing.T) { for _, env := range envs { for _, test := range tests { if got := test.fn(env.fn()); got != env.want { - t.Errorf("got Builder{%s}.Start%s = %v, want = %v", env.name, test.name, got, env.want) + t.Errorf("got Builder{%s}.Start%s() = %v, want = %v", env.name, test.name, got, env.want) } } } @@ -477,6 +662,7 @@ func TestBuilderResourceError(t *testing.T) { {"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }}, {"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }}, {"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }}, + {"OPTResource", func(b *Builder) error { return b.OPTResource(ResourceHeader{}, OPTResource{}) }}, } envs := []struct { @@ -493,7 +679,7 @@ func TestBuilderResourceError(t *testing.T) { for _, env := range envs { for _, test := range tests { if got := test.fn(env.fn()); got != env.want { - t.Errorf("got Builder{%s}.%s = %v, want = %v", env.name, test.name, got, env.want) + t.Errorf("got Builder{%s}.%s() = %v, want = %v", env.name, test.name, got, env.want) } } } @@ -503,7 +689,7 @@ func TestFinishError(t *testing.T) { var b Builder want := ErrNotStarted if _, got := b.Finish(); got != want { - t.Errorf("got Builder{}.Finish() = %v, want = %v", got, want) + t.Errorf("got Builder.Finish() = %v, want = %v", got, want) } } @@ -511,89 +697,96 @@ func TestBuilder(t *testing.T) { msg := largeTestMsg() want, err := msg.Pack() if err != nil { - t.Fatal("Packing without builder:", err) + t.Fatal("Message.Pack() =", err) } - var b Builder - b.Start(nil, msg.Header) + b := NewBuilder(nil, msg.Header) + b.EnableCompression() if err := b.StartQuestions(); err != nil { - t.Fatal("b.StartQuestions():", err) + t.Fatal("Builder.StartQuestions() =", err) } for _, q := range msg.Questions { if err := b.Question(q); err != nil { - t.Fatalf("b.Question(%#v): %v", q, err) + t.Fatalf("Builder.Question(%#v) = %v", q, err) } } if err := b.StartAnswers(); err != nil { - t.Fatal("b.StartAnswers():", err) + t.Fatal("Builder.StartAnswers() =", err) } for _, a := range msg.Answers { switch a.Header.Type { case TypeA: if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil { - t.Fatalf("b.AResource(%#v): %v", a, err) + t.Fatalf("Builder.AResource(%#v) = %v", a, err) } case TypeNS: if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil { - t.Fatalf("b.NSResource(%#v): %v", a, err) + t.Fatalf("Builder.NSResource(%#v) = %v", a, err) } case TypeCNAME: if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil { - t.Fatalf("b.CNAMEResource(%#v): %v", a, err) + t.Fatalf("Builder.CNAMEResource(%#v) = %v", a, err) } case TypeSOA: if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil { - t.Fatalf("b.SOAResource(%#v): %v", a, err) + t.Fatalf("Builder.SOAResource(%#v) = %v", a, err) } case TypePTR: if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil { - t.Fatalf("b.PTRResource(%#v): %v", a, err) + t.Fatalf("Builder.PTRResource(%#v) = %v", a, err) } case TypeMX: if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil { - t.Fatalf("b.MXResource(%#v): %v", a, err) + t.Fatalf("Builder.MXResource(%#v) = %v", a, err) } case TypeTXT: if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { - t.Fatalf("b.TXTResource(%#v): %v", a, err) + t.Fatalf("Builder.TXTResource(%#v) = %v", a, err) } case TypeAAAA: if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil { - t.Fatalf("b.AAAAResource(%#v): %v", a, err) + t.Fatalf("Builder.AAAAResource(%#v) = %v", a, err) } case TypeSRV: if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil { - t.Fatalf("b.SRVResource(%#v): %v", a, err) + t.Fatalf("Builder.SRVResource(%#v) = %v", a, err) } } } if err := b.StartAuthorities(); err != nil { - t.Fatal("b.StartAuthorities():", err) + t.Fatal("Builder.StartAuthorities() =", err) } for _, a := range msg.Authorities { if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil { - t.Fatalf("b.NSResource(%#v): %v", a, err) + t.Fatalf("Builder.NSResource(%#v) = %v", a, err) } } if err := b.StartAdditionals(); err != nil { - t.Fatal("b.StartAdditionals():", err) + t.Fatal("Builder.StartAdditionals() =", err) } for _, a := range msg.Additionals { - if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { - t.Fatalf("b.TXTResource(%#v): %v", a, err) + switch a.Body.(type) { + case *TXTResource: + if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { + t.Fatalf("Builder.TXTResource(%#v) = %v", a, err) + } + case *OPTResource: + if err := b.OPTResource(a.Header, *a.Body.(*OPTResource)); err != nil { + t.Fatalf("Builder.OPTResource(%#v) = %v", a, err) + } } } got, err := b.Finish() if err != nil { - t.Fatal("b.Finish():", err) + t.Fatal("Builder.Finish() =", err) } if !bytes.Equal(got, want) { - t.Fatalf("Got from Builder: %#v\nwant = %#v", got, want) + t.Fatalf("got from Builder.Finish() = %#v\nwant = %#v", got, want) } } @@ -606,7 +799,7 @@ func TestResourcePack(t *testing.T) { Message{ Questions: []Question{ { - Name: mustNewName("."), + Name: MustNewName("."), Type: TypeAAAA, Class: ClassINET, }, @@ -619,7 +812,7 @@ func TestResourcePack(t *testing.T) { Message{ Questions: []Question{ { - Name: mustNewName("."), + Name: MustNewName("."), Type: TypeAAAA, Class: ClassINET, }, @@ -636,7 +829,7 @@ func TestResourcePack(t *testing.T) { Message{ Questions: []Question{ { - Name: mustNewName("."), + Name: MustNewName("."), Type: TypeA, Class: ClassINET, }, @@ -648,15 +841,202 @@ func TestResourcePack(t *testing.T) { } { _, err := tt.m.Pack() if !reflect.DeepEqual(err, tt.err) { - t.Errorf("got %v for %v; want %v", err, tt.m, tt.err) + t.Errorf("got Message{%v}.Pack() = %v, want %v", tt.m, err, tt.err) } } } -func BenchmarkParsing(b *testing.B) { - b.ReportAllocs() +func TestResourcePackLength(t *testing.T) { + r := Resource{ + ResourceHeader{ + Name: MustNewName("."), + Type: TypeA, + Class: ClassINET, + }, + &AResource{[4]byte{127, 0, 0, 2}}, + } - name := mustNewName("foo.bar.example.com.") + hb, _, err := r.Header.pack(nil, nil, 0) + if err != nil { + t.Fatal("ResourceHeader.pack() =", err) + } + buf := make([]byte, 0, len(hb)) + buf, err = r.pack(buf, nil, 0) + if err != nil { + t.Fatal("Resource.pack() =", err) + } + + var hdr ResourceHeader + if _, err := hdr.unpack(buf, 0); err != nil { + t.Fatal("ResourceHeader.unpack() =", err) + } + + if got, want := int(hdr.Length), len(buf)-len(hb); got != want { + t.Errorf("got hdr.Length = %d, want = %d", got, want) + } +} + +func TestOptionPackUnpack(t *testing.T) { + for _, tt := range []struct { + name string + w []byte // wire format of m.Additionals + m Message + dnssecOK bool + extRCode RCode + }{ + { + name: "without EDNS(0) options", + w: []byte{ + 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80, + 0x00, 0x00, 0x00, + }, + m: Message{ + Header: Header{RCode: RCodeFormatError}, + Questions: []Question{ + { + Name: MustNewName("."), + Type: TypeA, + Class: ClassINET, + }, + }, + Additionals: []Resource{ + { + mustEDNS0ResourceHeader(4096, 0xfe0|RCodeFormatError, true), + &OPTResource{}, + }, + }, + }, + dnssecOK: true, + extRCode: 0xfe0 | RCodeFormatError, + }, + { + name: "with EDNS(0) options", + w: []byte{ + 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34, + }, + m: Message{ + Header: Header{RCode: RCodeServerFailure}, + Questions: []Question{ + { + Name: MustNewName("."), + Type: TypeAAAA, + Class: ClassINET, + }, + }, + Additionals: []Resource{ + { + mustEDNS0ResourceHeader(4096, 0xff0|RCodeServerFailure, false), + &OPTResource{ + Options: []Option{ + { + Code: 12, // see RFC 7828 + Data: []byte{0x00, 0x00}, + }, + { + Code: 11, // see RFC 7830 + Data: []byte{0x12, 0x34}, + }, + }, + }, + }, + }, + }, + dnssecOK: false, + extRCode: 0xff0 | RCodeServerFailure, + }, + { + // Containing multiple OPT resources in a + // message is invalid, but it's necessary for + // protocol conformance testing. + name: "with multiple OPT resources", + w: []byte{ + 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x02, 0x12, + 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x02, + 0x00, 0x00, + }, + m: Message{ + Header: Header{RCode: RCodeNameError}, + Questions: []Question{ + { + Name: MustNewName("."), + Type: TypeAAAA, + Class: ClassINET, + }, + }, + Additionals: []Resource{ + { + mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false), + &OPTResource{ + Options: []Option{ + { + Code: 11, // see RFC 7830 + Data: []byte{0x12, 0x34}, + }, + }, + }, + }, + { + mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false), + &OPTResource{ + Options: []Option{ + { + Code: 12, // see RFC 7828 + Data: []byte{0x00, 0x00}, + }, + }, + }, + }, + }, + }, + }, + } { + w, err := tt.m.Pack() + if err != nil { + t.Errorf("Message.Pack() for %s = %v", tt.name, err) + continue + } + if !bytes.Equal(w[len(w)-len(tt.w):], tt.w) { + t.Errorf("got Message.Pack() for %s = %#v, want %#v", tt.name, w[len(w)-len(tt.w):], tt.w) + continue + } + var m Message + if err := m.Unpack(w); err != nil { + t.Errorf("Message.Unpack() for %s = %v", tt.name, err) + continue + } + if !reflect.DeepEqual(m.Additionals, tt.m.Additionals) { + t.Errorf("got Message.Pack/Unpack() roundtrip for %s = %+v, want %+v", tt.name, m, tt.m) + continue + } + } +} + +// TestGoString tests that Message.GoString produces Go code that compiles to +// reproduce the Message. +// +// This test was produced as follows: +// 1. Run (*Message).GoString on largeTestMsg(). +// 2. Remove "dnsmessage." from the output. +// 3. Paste the result in the test to store it in msg. +// 4. Also put the original output in the test to store in want. +func TestGoString(t *testing.T) { + msg := Message{Header: Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, RCode: RCodeSuccess}, Questions: []Question{{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET}}, Answers: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AResource{A: [4]byte{127, 0, 0, 1}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AResource{A: [4]byte{127, 0, 0, 2}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeAAAA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AAAAResource{AAAA: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeCNAME, Class: ClassINET, TTL: 0, Length: 0}, Body: &CNAMEResource{CNAME: MustNewName("alias.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeSOA, Class: ClassINET, TTL: 0, Length: 0}, Body: &SOAResource{NS: MustNewName("ns1.example.com."), MBox: MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, Expire: 4, MinTTL: 5}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypePTR, Class: ClassINET, TTL: 0, Length: 0}, Body: &PTRResource{PTR: MustNewName("ptr.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeMX, Class: ClassINET, TTL: 0, Length: 0}, Body: &MXResource{Pref: 7, MX: MustNewName("mx.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeSRV, Class: ClassINET, TTL: 0, Length: 0}, Body: &SRVResource{Priority: 8, Weight: 9, Port: 11, Target: MustNewName("srv.example.com.")}}}, Authorities: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns1.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns2.example.com.")}}}, Additionals: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, TTL: 0, Length: 0}, Body: &TXTResource{TXT: []string{"So Long\x2c and Thanks for All the Fish"}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, TTL: 0, Length: 0}, Body: &TXTResource{TXT: []string{"Hamster Huey and the Gooey Kablooie"}}}, {Header: ResourceHeader{Name: MustNewName("."), Type: TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &OPTResource{Options: []Option{{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}} + if !reflect.DeepEqual(msg, largeTestMsg()) { + t.Error("Message.GoString lost information or largeTestMsg changed: msg != largeTestMsg()") + } + got := msg.GoString() + want := `dnsmessage.Message{Header: dnsmessage.Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, RCode: dnsmessage.RCodeSuccess}, Questions: []dnsmessage.Question{dnsmessage.Question{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET}}, Answers: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 2}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeAAAA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AAAAResource{AAAA: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeCNAME, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.CNAMEResource{CNAME: dnsmessage.MustNewName("alias.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeSOA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.SOAResource{NS: dnsmessage.MustNewName("ns1.example.com."), MBox: dnsmessage.MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, Expire: 4, MinTTL: 5}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypePTR, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.PTRResource{PTR: dnsmessage.MustNewName("ptr.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeMX, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.MXResource{Pref: 7, MX: dnsmessage.MustNewName("mx.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeSRV, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.SRVResource{Priority: 8, Weight: 9, Port: 11, Target: dnsmessage.MustNewName("srv.example.com.")}}}, Authorities: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeNS, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.NSResource{NS: dnsmessage.MustNewName("ns1.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeNS, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.NSResource{NS: dnsmessage.MustNewName("ns2.example.com.")}}}, Additionals: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeTXT, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.TXTResource{TXT: []string{"So Long\x2c and Thanks for All the Fish"}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeTXT, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.TXTResource{TXT: []string{"Hamster Huey and the Gooey Kablooie"}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("."), Type: dnsmessage.TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &dnsmessage.OPTResource{Options: []dnsmessage.Option{dnsmessage.Option{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}}` + if got != want { + t.Errorf("got msg1.GoString() = %s\nwant = %s", got, want) + } +} + +func benchmarkParsingSetup() ([]byte, error) { + name := MustNewName("foo.bar.example.com.") msg := Message{ Header: Header{Response: true, Authoritative: true}, Questions: []Question{ @@ -700,116 +1080,166 @@ func BenchmarkParsing(b *testing.B) { buf, err := msg.Pack() if err != nil { - b.Fatal("msg.Pack():", err) + return nil, fmt.Errorf("Message.Pack() = %v", err) + } + return buf, nil +} + +func benchmarkParsing(tb testing.TB, buf []byte) { + var p Parser + if _, err := p.Start(buf); err != nil { + tb.Fatal("Parser.Start(non-nil) =", err) } + for { + _, err := p.Question() + if err == ErrSectionDone { + break + } + if err != nil { + tb.Fatal("Parser.Question() =", err) + } + } + + for { + h, err := p.AnswerHeader() + if err == ErrSectionDone { + break + } + if err != nil { + tb.Fatal("Parser.AnswerHeader() =", err) + } + + switch h.Type { + case TypeA: + if _, err := p.AResource(); err != nil { + tb.Fatal("Parser.AResource() =", err) + } + case TypeAAAA: + if _, err := p.AAAAResource(); err != nil { + tb.Fatal("Parser.AAAAResource() =", err) + } + case TypeCNAME: + if _, err := p.CNAMEResource(); err != nil { + tb.Fatal("Parser.CNAMEResource() =", err) + } + case TypeNS: + if _, err := p.NSResource(); err != nil { + tb.Fatal("Parser.NSResource() =", err) + } + case TypeOPT: + if _, err := p.OPTResource(); err != nil { + tb.Fatal("Parser.OPTResource() =", err) + } + default: + tb.Fatalf("got unknown type: %T", h) + } + } +} + +func BenchmarkParsing(b *testing.B) { + buf, err := benchmarkParsingSetup() + if err != nil { + b.Fatal(err) + } + + b.ReportAllocs() for i := 0; i < b.N; i++ { - var p Parser - if _, err := p.Start(buf); err != nil { - b.Fatal("p.Start(buf):", err) - } + benchmarkParsing(b, buf) + } +} - for { - _, err := p.Question() - if err == ErrSectionDone { - break - } - if err != nil { - b.Fatal("p.Question():", err) - } - } +func TestParsingAllocs(t *testing.T) { + buf, err := benchmarkParsingSetup() + if err != nil { + t.Fatal(err) + } - for { - h, err := p.AnswerHeader() - if err == ErrSectionDone { - break - } - if err != nil { - panic(err) - } + if allocs := testing.AllocsPerRun(100, func() { benchmarkParsing(t, buf) }); allocs > 0.5 { + t.Errorf("allocations during parsing: got = %f, want ~0", allocs) + } +} - switch h.Type { - case TypeA: - if _, err := p.AResource(); err != nil { - b.Fatal("p.AResource():", err) - } - case TypeAAAA: - if _, err := p.AAAAResource(); err != nil { - b.Fatal("p.AAAAResource():", err) - } - case TypeCNAME: - if _, err := p.CNAMEResource(); err != nil { - b.Fatal("p.CNAMEResource():", err) - } - case TypeNS: - if _, err := p.NSResource(); err != nil { - b.Fatal("p.NSResource():", err) - } - default: - b.Fatalf("unknown type: %T", h) - } - } +func benchmarkBuildingSetup() (Name, []byte) { + name := MustNewName("foo.bar.example.com.") + buf := make([]byte, 0, packStartingCap) + return name, buf +} + +func benchmarkBuilding(tb testing.TB, name Name, buf []byte) { + bld := NewBuilder(buf, Header{Response: true, Authoritative: true}) + + if err := bld.StartQuestions(); err != nil { + tb.Fatal("Builder.StartQuestions() =", err) + } + q := Question{ + Name: name, + Type: TypeA, + Class: ClassINET, + } + if err := bld.Question(q); err != nil { + tb.Fatalf("Builder.Question(%+v) = %v", q, err) + } + + hdr := ResourceHeader{ + Name: name, + Class: ClassINET, + } + if err := bld.StartAnswers(); err != nil { + tb.Fatal("Builder.StartQuestions() =", err) + } + + ar := AResource{[4]byte{}} + if err := bld.AResource(hdr, ar); err != nil { + tb.Fatalf("Builder.AResource(%+v, %+v) = %v", hdr, ar, err) + } + + aaar := AAAAResource{[16]byte{}} + if err := bld.AAAAResource(hdr, aaar); err != nil { + tb.Fatalf("Builder.AAAAResource(%+v, %+v) = %v", hdr, aaar, err) + } + + cnr := CNAMEResource{name} + if err := bld.CNAMEResource(hdr, cnr); err != nil { + tb.Fatalf("Builder.CNAMEResource(%+v, %+v) = %v", hdr, cnr, err) + } + + nsr := NSResource{name} + if err := bld.NSResource(hdr, nsr); err != nil { + tb.Fatalf("Builder.NSResource(%+v, %+v) = %v", hdr, nsr, err) + } + + extrc := 0xfe0 | RCodeNotImplemented + if err := (&hdr).SetEDNS0(4096, extrc, true); err != nil { + tb.Fatalf("ResourceHeader.SetEDNS0(4096, %#x, true) = %v", extrc, err) + } + optr := OPTResource{} + if err := bld.OPTResource(hdr, optr); err != nil { + tb.Fatalf("Builder.OPTResource(%+v, %+v) = %v", hdr, optr, err) + } + + if _, err := bld.Finish(); err != nil { + tb.Fatal("Builder.Finish() =", err) } } func BenchmarkBuilding(b *testing.B) { + name, buf := benchmarkBuildingSetup() b.ReportAllocs() - - name := mustNewName("foo.bar.example.com.") - buf := make([]byte, 0, packStartingCap) - for i := 0; i < b.N; i++ { - var bld Builder - bld.StartWithoutCompression(buf, Header{Response: true, Authoritative: true}) + benchmarkBuilding(b, name, buf) + } +} - if err := bld.StartQuestions(); err != nil { - b.Fatal("bld.StartQuestions():", err) - } - q := Question{ - Name: name, - Type: TypeA, - Class: ClassINET, - } - if err := bld.Question(q); err != nil { - b.Fatalf("bld.Question(%+v): %v", q, err) - } - - hdr := ResourceHeader{ - Name: name, - Class: ClassINET, - } - if err := bld.StartAnswers(); err != nil { - b.Fatal("bld.StartQuestions():", err) - } - - ar := AResource{[4]byte{}} - if err := bld.AResource(hdr, ar); err != nil { - b.Fatalf("bld.AResource(%+v, %+v): %v", hdr, ar, err) - } - - aaar := AAAAResource{[16]byte{}} - if err := bld.AAAAResource(hdr, aaar); err != nil { - b.Fatalf("bld.AAAAResource(%+v, %+v): %v", hdr, aaar, err) - } - - cnr := CNAMEResource{name} - if err := bld.CNAMEResource(hdr, cnr); err != nil { - b.Fatalf("bld.CNAMEResource(%+v, %+v): %v", hdr, cnr, err) - } - - nsr := NSResource{name} - if err := bld.NSResource(hdr, nsr); err != nil { - b.Fatalf("bld.NSResource(%+v, %+v): %v", hdr, nsr, err) - } - - if _, err := bld.Finish(); err != nil { - b.Fatal("bld.Finish():", err) - } +func TestBuildingAllocs(t *testing.T) { + name, buf := benchmarkBuildingSetup() + if allocs := testing.AllocsPerRun(100, func() { benchmarkBuilding(t, name, buf) }); allocs > 0.5 { + t.Errorf("allocations during building: got = %f, want ~0", allocs) } } func smallTestMsg() Message { - name := mustNewName("example.com.") + name := MustNewName("example.com.") return Message{ Header: Header{Response: true, Authoritative: true}, Questions: []Question{ @@ -859,7 +1289,7 @@ func BenchmarkPack(b *testing.B) { for i := 0; i < b.N; i++ { if _, err := msg.Pack(); err != nil { - b.Fatal(err) + b.Fatal("Message.Pack() =", err) } } } @@ -872,13 +1302,13 @@ func BenchmarkAppendPack(b *testing.B) { for i := 0; i < b.N; i++ { if _, err := msg.AppendPack(buf[:0]); err != nil { - b.Fatal(err) + b.Fatal("Message.AppendPack() = ", err) } } } func largeTestMsg() Message { - name := mustNewName("foo.bar.example.com.") + name := MustNewName("foo.bar.example.com.") return Message{ Header: Header{Response: true, Authoritative: true}, Questions: []Question{ @@ -919,7 +1349,7 @@ func largeTestMsg() Message { Type: TypeCNAME, Class: ClassINET, }, - &CNAMEResource{mustNewName("alias.example.com.")}, + &CNAMEResource{MustNewName("alias.example.com.")}, }, { ResourceHeader{ @@ -928,8 +1358,8 @@ func largeTestMsg() Message { Class: ClassINET, }, &SOAResource{ - NS: mustNewName("ns1.example.com."), - MBox: mustNewName("mb.example.com."), + NS: MustNewName("ns1.example.com."), + MBox: MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, @@ -943,7 +1373,7 @@ func largeTestMsg() Message { Type: TypePTR, Class: ClassINET, }, - &PTRResource{mustNewName("ptr.example.com.")}, + &PTRResource{MustNewName("ptr.example.com.")}, }, { ResourceHeader{ @@ -953,7 +1383,7 @@ func largeTestMsg() Message { }, &MXResource{ 7, - mustNewName("mx.example.com."), + MustNewName("mx.example.com."), }, }, { @@ -966,7 +1396,7 @@ func largeTestMsg() Message { 8, 9, 11, - mustNewName("srv.example.com."), + MustNewName("srv.example.com."), }, }, }, @@ -977,7 +1407,7 @@ func largeTestMsg() Message { Type: TypeNS, Class: ClassINET, }, - &NSResource{mustNewName("ns1.example.com.")}, + &NSResource{MustNewName("ns1.example.com.")}, }, { ResourceHeader{ @@ -985,7 +1415,7 @@ func largeTestMsg() Message { Type: TypeNS, Class: ClassINET, }, - &NSResource{mustNewName("ns2.example.com.")}, + &NSResource{MustNewName("ns2.example.com.")}, }, }, Additionals: []Resource{ @@ -995,7 +1425,7 @@ func largeTestMsg() Message { Type: TypeTXT, Class: ClassINET, }, - &TXTResource{"So Long, and Thanks for All the Fish"}, + &TXTResource{[]string{"So Long, and Thanks for All the Fish"}}, }, { ResourceHeader{ @@ -1003,139 +1433,19 @@ func largeTestMsg() Message { Type: TypeTXT, Class: ClassINET, }, - &TXTResource{"Hamster Huey and the Gooey Kablooie"}, + &TXTResource{[]string{"Hamster Huey and the Gooey Kablooie"}}, + }, + { + mustEDNS0ResourceHeader(4096, 0xfe0|RCodeSuccess, false), + &OPTResource{ + Options: []Option{ + { + Code: 10, // see RFC 7873 + Data: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + }, + }, + }, }, }, } } - -const loremIpsum = ` -Lorem ipsum dolor sit amet, nec enim antiopam id, an ullum choro -nonumes qui, pro eu debet honestatis mediocritatem. No alia enim eos, -magna signiferumque ex vis. Mei no aperiri dissentias, cu vel quas -regione. Malorum quaeque vim ut, eum cu semper aliquid invidunt, ei -nam ipsum assentior. - -Nostrum appellantur usu no, vis ex probatus adipiscing. Cu usu illum -facilis eleifend. Iusto conceptam complectitur vim id. Tale omnesque -no usu, ei oblique sadipscing vim. At nullam voluptua usu, mei laudem -reformidans et. Qui ei eros porro reformidans, ius suas veritus -torquatos ex. Mea te facer alterum consequat. - -Soleat torquatos democritum sed et, no mea congue appareat, facer -aliquam nec in. Has te ipsum tritani. At justo dicta option nec, movet -phaedrum ad nam. Ea detracto verterem liberavisse has, delectus -suscipiantur in mei. Ex nam meliore complectitur. Ut nam omnis -honestatis quaerendum, ea mea nihil affert detracto, ad vix rebum -mollis. - -Ut epicurei praesent neglegentur pri, prima fuisset intellegebat ad -vim. An habemus comprehensam usu, at enim dignissim pro. Eam reque -vivendum adipisci ea. Vel ne odio choro minimum. Sea admodum -dissentiet ex. Mundi tamquam evertitur ius cu. Homero postea iisque ut -pro, vel ne saepe senserit consetetur. - -Nulla utamur facilisis ius ea, in viderer diceret pertinax eum. Mei no -enim quodsi facilisi, ex sed aeterno appareat mediocritatem, eum -sententiae deterruisset ut. At suas timeam euismod cum, offendit -appareat interpretaris ne vix. Vel ea civibus albucius, ex vim quidam -accusata intellegebat, noluisse instructior sea id. Nec te nonumes -habemus appellantur, quis dignissim vituperata eu nam. - -At vix apeirian patrioque vituperatoribus, an usu agam assum. Debet -iisque an mea. Per eu dicant ponderum accommodare. Pri alienum -placerat senserit an, ne eum ferri abhorreant vituperatoribus. Ut mea -eligendi disputationi. Ius no tation everti impedit, ei magna quidam -mediocritatem pri. - -Legendos perpetua iracundia ne usu, no ius ullum epicurei intellegam, -ad modus epicuri lucilius eam. In unum quaerendum usu. Ne diam paulo -has, ea veri virtute sed. Alia honestatis conclusionemque mea eu, ut -iudico albucius his. - -Usu essent probatus eu, sed omnis dolor delicatissimi ex. No qui augue -dissentias dissentiet. Laudem recteque no usu, vel an velit noluisse, -an sed utinam eirmod appetere. Ne mea fuisset inimicus ocurreret. At -vis dicant abhorreant, utinam forensibus nec ne, mei te docendi -consequat. Brute inermis persecuti cum id. Ut ipsum munere propriae -usu, dicit graeco disputando id has. - -Eros dolore quaerendum nam ei. Timeam ornatus inciderint pro id. Nec -torquatos sadipscing ei, ancillae molestie per in. Malis principes duo -ea, usu liber postulant ei. - -Graece timeam voluptatibus eu eam. Alia probatus quo no, ea scripta -feugiat duo. Congue option meliore ex qui, noster invenire appellantur -ea vel. Eu exerci legendos vel. Consetetur repudiandae vim ut. Vix an -probo minimum, et nam illud falli tempor. - -Cum dico signiferumque eu. Sed ut regione maiorum, id veritus insolens -tacimates vix. Eu mel sint tamquam lucilius, duo no oporteat -tacimates. Atqui augue concludaturque vix ei, id mel utroque menandri. - -Ad oratio blandit aliquando pro. Vis et dolorum rationibus -philosophia, ad cum nulla molestie. Hinc fuisset adversarium eum et, -ne qui nisl verear saperet, vel te quaestio forensibus. Per odio -option delenit an. Alii placerat has no, in pri nihil platonem -cotidieque. Est ut elit copiosae scaevola, debet tollit maluisset sea -an. - -Te sea hinc debet pericula, liber ridens fabulas cu sed, quem mutat -accusam mea et. Elitr labitur albucius et pri, an labore feugait mel. -Velit zril melius usu ea. Ad stet putent interpretaris qui. Mel no -error volumus scripserit. In pro paulo iudico, quo ei dolorem -verterem, affert fabellas dissentiet ea vix. - -Vis quot deserunt te. Error aliquid detraxit eu usu, vis alia eruditi -salutatus cu. Est nostrud bonorum an, ei usu alii salutatus. Vel at -nisl primis, eum ex aperiri noluisse reformidans. Ad veri velit -utroque vis, ex equidem detraxit temporibus has. - -Inermis appareat usu ne. Eros placerat periculis mea ad, in dictas -pericula pro. Errem postulant at usu, ea nec amet ornatus mentitum. Ad -mazim graeco eum, vel ex percipit volutpat iudicabit, sit ne delicata -interesset. Mel sapientem prodesset abhorreant et, oblique suscipit -eam id. - -An maluisset disputando mea, vidit mnesarchum pri et. Malis insolens -inciderint no sea. Ea persius maluisset vix, ne vim appellantur -instructior, consul quidam definiebas pri id. Cum integre feugiat -pericula in, ex sed persius similique, mel ne natum dicit percipitur. - -Primis discere ne pri, errem putent definitionem at vis. Ei mel dolore -neglegentur, mei tincidunt percipitur ei. Pro ad simul integre -rationibus. Eu vel alii honestatis definitiones, mea no nonumy -reprehendunt. - -Dicta appareat legendos est cu. Eu vel congue dicunt omittam, no vix -adhuc minimum constituam, quot noluisse id mel. Eu quot sale mutat -duo, ex nisl munere invenire duo. Ne nec ullum utamur. Pro alterum -debitis nostrum no, ut vel aliquid vivendo. - -Aliquip fierent praesent quo ne, id sit audiam recusabo delicatissimi. -Usu postulant incorrupte cu. At pro dicit tibique intellegam, cibo -dolore impedit id eam, et aeque feugait assentior has. Quando sensibus -nec ex. Possit sensibus pri ad, unum mutat periculis cu vix. - -Mundi tibique vix te, duo simul partiendo qualisque id, est at vidit -sonet tempor. No per solet aeterno deseruisse. Petentium salutandi -definiebas pri cu. Munere vivendum est in. Ei justo congue eligendi -vis, modus offendit omittantur te mel. - -Integre voluptaria in qui, sit habemus tractatos constituam no. Utinam -melius conceptam est ne, quo in minimum apeirian delicata, ut ius -porro recusabo. Dicant expetenda vix no, ludus scripserit sed ex, eu -his modo nostro. Ut etiam sonet his, quodsi inciderint philosophia te -per. Nullam lobortis eu cum, vix an sonet efficiendi repudiandae. Vis -ad idque fabellas intellegebat. - -Eum commodo senserit conclusionemque ex. Sed forensibus sadipscing ut, -mei in facer delicata periculis, sea ne hinc putent cetero. Nec ne -alia corpora invenire, alia prima soleat te cum. Eleifend posidonium -nam at. - -Dolorum indoctum cu quo, ex dolor legendos recteque eam, cu pri zril -discere. Nec civibus officiis dissentiunt ex, est te liber ludus -elaboraret. Cum ea fabellas invenire. Ex vim nostrud eripuit -comprehensam, nam te inermis delectus, saepe inermis senserit. -` diff --git a/vendor/golang.org/x/net/html/atom/gen.go b/vendor/golang.org/x/net/html/atom/gen.go index cc5dc5db..5d052781 100644 --- a/vendor/golang.org/x/net/html/atom/gen.go +++ b/vendor/golang.org/x/net/html/atom/gen.go @@ -306,7 +306,7 @@ func (t *table) push(i uint32, depth int) bool { // The lists of element names and attribute keys were taken from // https://html.spec.whatwg.org/multipage/indices.html#index -// as of the "HTML Living Standard - Last Updated 18 September 2017" version. +// as of the "HTML Living Standard - Last Updated 16 April 2018" version. // "command", "keygen" and "menuitem" have been removed from the spec, // but are kept here for backwards compatibility. @@ -665,6 +665,7 @@ var eventHandlers = []string{ // extra are ad-hoc values not covered by any of the lists above. var extra = []string{ + "acronym", "align", "annotation", "annotation-xml", @@ -700,6 +701,8 @@ var extra = []string{ "plaintext", "prompt", "public", + "rb", + "rtc", "spacer", "strike", "svg", diff --git a/vendor/golang.org/x/net/html/atom/table.go b/vendor/golang.org/x/net/html/atom/table.go index f74018ec..2a938864 100644 --- a/vendor/golang.org/x/net/html/atom/table.go +++ b/vendor/golang.org/x/net/html/atom/table.go @@ -10,366 +10,369 @@ const ( Accept Atom = 0x1a06 AcceptCharset Atom = 0x1a0e Accesskey Atom = 0x2c09 - Action Atom = 0x25a06 - Address Atom = 0x6ed07 - Align Atom = 0x6d405 - Allowfullscreen Atom = 0x1f00f - Allowpaymentrequest Atom = 0x6913 - Allowusermedia Atom = 0x850e - Alt Atom = 0xb003 - Annotation Atom = 0x1b90a - AnnotationXml Atom = 0x1b90e - Applet Atom = 0x30106 - Area Atom = 0x34a04 - Article Atom = 0x3f007 - As Atom = 0xb902 - Aside Atom = 0xc105 - Async Atom = 0xb905 - Audio Atom = 0xcf05 - Autocomplete Atom = 0x2600c - Autofocus Atom = 0xeb09 - Autoplay Atom = 0x10608 + Acronym Atom = 0xaa07 + Action Atom = 0x27206 + Address Atom = 0x6f307 + Align Atom = 0xb105 + Allowfullscreen Atom = 0x2080f + Allowpaymentrequest Atom = 0xc113 + Allowusermedia Atom = 0xdd0e + Alt Atom = 0xf303 + Annotation Atom = 0x1c90a + AnnotationXml Atom = 0x1c90e + Applet Atom = 0x31906 + Area Atom = 0x35604 + Article Atom = 0x3fc07 + As Atom = 0x3c02 + Aside Atom = 0x10705 + Async Atom = 0xff05 + Audio Atom = 0x11505 + Autocomplete Atom = 0x2780c + Autofocus Atom = 0x12109 + Autoplay Atom = 0x13c08 B Atom = 0x101 - Base Atom = 0x11504 - Basefont Atom = 0x11508 - Bdi Atom = 0x16103 - Bdo Atom = 0x13403 - Bgsound Atom = 0x14707 - Big Atom = 0x15903 - Blink Atom = 0x15c05 - Blockquote Atom = 0x1680a + Base Atom = 0x3b04 + Basefont Atom = 0x3b08 + Bdi Atom = 0xba03 + Bdo Atom = 0x14b03 + Bgsound Atom = 0x15e07 + Big Atom = 0x17003 + Blink Atom = 0x17305 + Blockquote Atom = 0x1870a Body Atom = 0x2804 Br Atom = 0x202 - Button Atom = 0x17206 - Canvas Atom = 0xbd06 - Caption Atom = 0x21907 - Center Atom = 0x20806 - Challenge Atom = 0x28309 + Button Atom = 0x19106 + Canvas Atom = 0x10306 + Caption Atom = 0x23107 + Center Atom = 0x22006 + Challenge Atom = 0x29b09 Charset Atom = 0x2107 - Checked Atom = 0x46d07 - Cite Atom = 0x55804 - Class Atom = 0x5b905 - Code Atom = 0x19004 - Col Atom = 0x19703 - Colgroup Atom = 0x19708 - Color Atom = 0x1af05 - Cols Atom = 0x1b404 - Colspan Atom = 0x1b407 - Command Atom = 0x1c707 - Content Atom = 0x57f07 - Contenteditable Atom = 0x57f0f - Contextmenu Atom = 0x3740b - Controls Atom = 0x1ce08 - Coords Atom = 0x1da06 - Crossorigin Atom = 0x1e30b - Data Atom = 0x49904 - Datalist Atom = 0x49908 - Datetime Atom = 0x2a008 - Dd Atom = 0x2bf02 - Default Atom = 0xc407 - Defer Atom = 0x19205 - Del Atom = 0x44603 - Desc Atom = 0x55504 - Details Atom = 0x4607 - Dfn Atom = 0x5f03 - Dialog Atom = 0x16206 - Dir Atom = 0xa303 - Dirname Atom = 0xa307 - Disabled Atom = 0x14d08 - Div Atom = 0x15403 - Dl Atom = 0x5e202 - Download Atom = 0x45708 - Draggable Atom = 0x18309 - Dropzone Atom = 0x3f908 - Dt Atom = 0x64702 - Em Atom = 0x4202 - Embed Atom = 0x4205 - Enctype Atom = 0x27507 - Face Atom = 0x20604 - Fieldset Atom = 0x20e08 - Figcaption Atom = 0x2160a - Figure Atom = 0x23006 - Font Atom = 0x11904 - Footer Atom = 0xb306 - For Atom = 0x23c03 - ForeignObject Atom = 0x23c0d - Foreignobject Atom = 0x2490d - Form Atom = 0x25604 - Formaction Atom = 0x2560a - Formenctype Atom = 0x2710b - Formmethod Atom = 0x28c0a - Formnovalidate Atom = 0x2960e - Formtarget Atom = 0x2a80a - Frame Atom = 0x5705 - Frameset Atom = 0x5708 - H1 Atom = 0x14502 - H2 Atom = 0x2c602 - H3 Atom = 0x2f502 - H4 Atom = 0x33902 - H5 Atom = 0x34302 - H6 Atom = 0x64902 - Head Atom = 0x32504 - Header Atom = 0x32506 - Headers Atom = 0x32507 - Height Atom = 0x12c06 - Hgroup Atom = 0x2b206 - Hidden Atom = 0x2bd06 - High Atom = 0x2c304 - Hr Atom = 0x14002 - Href Atom = 0x2c804 - Hreflang Atom = 0x2c808 - Html Atom = 0x13004 - HttpEquiv Atom = 0x2d00a + Checked Atom = 0x47907 + Cite Atom = 0x19c04 + Class Atom = 0x56405 + Code Atom = 0x5c504 + Col Atom = 0x1ab03 + Colgroup Atom = 0x1ab08 + Color Atom = 0x1bf05 + Cols Atom = 0x1c404 + Colspan Atom = 0x1c407 + Command Atom = 0x1d707 + Content Atom = 0x58b07 + Contenteditable Atom = 0x58b0f + Contextmenu Atom = 0x3800b + Controls Atom = 0x1de08 + Coords Atom = 0x1ea06 + Crossorigin Atom = 0x1fb0b + Data Atom = 0x4a504 + Datalist Atom = 0x4a508 + Datetime Atom = 0x2b808 + Dd Atom = 0x2d702 + Default Atom = 0x10a07 + Defer Atom = 0x5c705 + Del Atom = 0x45203 + Desc Atom = 0x56104 + Details Atom = 0x7207 + Dfn Atom = 0x8703 + Dialog Atom = 0xbb06 + Dir Atom = 0x9303 + Dirname Atom = 0x9307 + Disabled Atom = 0x16408 + Div Atom = 0x16b03 + Dl Atom = 0x5e602 + Download Atom = 0x46308 + Draggable Atom = 0x17a09 + Dropzone Atom = 0x40508 + Dt Atom = 0x64b02 + Em Atom = 0x6e02 + Embed Atom = 0x6e05 + Enctype Atom = 0x28d07 + Face Atom = 0x21e04 + Fieldset Atom = 0x22608 + Figcaption Atom = 0x22e0a + Figure Atom = 0x24806 + Font Atom = 0x3f04 + Footer Atom = 0xf606 + For Atom = 0x25403 + ForeignObject Atom = 0x2540d + Foreignobject Atom = 0x2610d + Form Atom = 0x26e04 + Formaction Atom = 0x26e0a + Formenctype Atom = 0x2890b + Formmethod Atom = 0x2a40a + Formnovalidate Atom = 0x2ae0e + Formtarget Atom = 0x2c00a + Frame Atom = 0x8b05 + Frameset Atom = 0x8b08 + H1 Atom = 0x15c02 + H2 Atom = 0x2de02 + H3 Atom = 0x30d02 + H4 Atom = 0x34502 + H5 Atom = 0x34f02 + H6 Atom = 0x64d02 + Head Atom = 0x33104 + Header Atom = 0x33106 + Headers Atom = 0x33107 + Height Atom = 0x5206 + Hgroup Atom = 0x2ca06 + Hidden Atom = 0x2d506 + High Atom = 0x2db04 + Hr Atom = 0x15702 + Href Atom = 0x2e004 + Hreflang Atom = 0x2e008 + Html Atom = 0x5604 + HttpEquiv Atom = 0x2e80a I Atom = 0x601 - Icon Atom = 0x57e04 - Id Atom = 0xc302 - Iframe Atom = 0x2e406 - Image Atom = 0x2ea05 - Img Atom = 0x2ef03 - Input Atom = 0x43f05 - Inputmode Atom = 0x43f09 - Ins Atom = 0x1ec03 - Integrity Atom = 0x22709 - Is Atom = 0x14e02 - Isindex Atom = 0x2f707 - Ismap Atom = 0x2fe05 - Itemid Atom = 0x37f06 - Itemprop Atom = 0x55908 - Itemref Atom = 0x3c107 - Itemscope Atom = 0x66d09 - Itemtype Atom = 0x30708 - Kbd Atom = 0x16003 + Icon Atom = 0x58a04 + Id Atom = 0x10902 + Iframe Atom = 0x2fc06 + Image Atom = 0x30205 + Img Atom = 0x30703 + Input Atom = 0x44b05 + Inputmode Atom = 0x44b09 + Ins Atom = 0x20403 + Integrity Atom = 0x23f09 + Is Atom = 0x16502 + Isindex Atom = 0x30f07 + Ismap Atom = 0x31605 + Itemid Atom = 0x38b06 + Itemprop Atom = 0x19d08 + Itemref Atom = 0x3cd07 + Itemscope Atom = 0x67109 + Itemtype Atom = 0x31f08 + Kbd Atom = 0xb903 Keygen Atom = 0x3206 - Keytype Atom = 0x7e07 - Kind Atom = 0x18004 - Label Atom = 0xda05 - Lang Atom = 0x2cc04 - Legend Atom = 0x18a06 - Li Atom = 0x11102 - Link Atom = 0x15d04 - List Atom = 0x49d04 - Listing Atom = 0x49d07 - Loop Atom = 0xde04 - Low Atom = 0x6b03 + Keytype Atom = 0xd607 + Kind Atom = 0x17704 + Label Atom = 0x5905 + Lang Atom = 0x2e404 + Legend Atom = 0x18106 + Li Atom = 0xb202 + Link Atom = 0x17404 + List Atom = 0x4a904 + Listing Atom = 0x4a907 + Loop Atom = 0x5d04 + Low Atom = 0xc303 Main Atom = 0x1004 - Malignmark Atom = 0x6d30a - Manifest Atom = 0x30f08 - Map Atom = 0x30003 - Mark Atom = 0x6d904 - Marquee Atom = 0x31b07 - Math Atom = 0x32204 - Max Atom = 0x33103 - Maxlength Atom = 0x33109 - Media Atom = 0x8e05 - Mediagroup Atom = 0x8e0a - Menu Atom = 0x37b04 - Menuitem Atom = 0x37b08 - Meta Atom = 0x4ac04 - Meter Atom = 0xa805 - Method Atom = 0x29006 - Mglyph Atom = 0x2f006 - Mi Atom = 0x33b02 - Min Atom = 0x33b03 - Minlength Atom = 0x33b09 - Mn Atom = 0x29902 - Mo Atom = 0x6302 - Ms Atom = 0x67002 - Mtext Atom = 0x34505 - Multiple Atom = 0x35308 - Muted Atom = 0x35b05 - Name Atom = 0xa604 + Malignmark Atom = 0xb00a + Manifest Atom = 0x6d708 + Map Atom = 0x31803 + Mark Atom = 0xb604 + Marquee Atom = 0x32707 + Math Atom = 0x32e04 + Max Atom = 0x33d03 + Maxlength Atom = 0x33d09 + Media Atom = 0xe605 + Mediagroup Atom = 0xe60a + Menu Atom = 0x38704 + Menuitem Atom = 0x38708 + Meta Atom = 0x4b804 + Meter Atom = 0x9805 + Method Atom = 0x2a806 + Mglyph Atom = 0x30806 + Mi Atom = 0x34702 + Min Atom = 0x34703 + Minlength Atom = 0x34709 + Mn Atom = 0x2b102 + Mo Atom = 0xa402 + Ms Atom = 0x67402 + Mtext Atom = 0x35105 + Multiple Atom = 0x35f08 + Muted Atom = 0x36705 + Name Atom = 0x9604 Nav Atom = 0x1303 Nobr Atom = 0x3704 - Noembed Atom = 0x4007 - Noframes Atom = 0x5508 - Nomodule Atom = 0x6108 - Nonce Atom = 0x56205 - Noscript Atom = 0x1fe08 - Novalidate Atom = 0x29a0a - Object Atom = 0x25006 - Ol Atom = 0x10102 - Onabort Atom = 0x17607 - Onafterprint Atom = 0x21e0c - Onautocomplete Atom = 0x25e0e - Onautocompleteerror Atom = 0x25e13 - Onauxclick Atom = 0x61b0a - Onbeforeprint Atom = 0x69a0d - Onbeforeunload Atom = 0x6e10e - Onblur Atom = 0x5c206 - Oncancel Atom = 0xd308 - Oncanplay Atom = 0x13609 - Oncanplaythrough Atom = 0x13610 - Onchange Atom = 0x40f08 - Onclick Atom = 0x2dd07 - Onclose Atom = 0x36007 - Oncontextmenu Atom = 0x3720d - Oncopy Atom = 0x38506 - Oncuechange Atom = 0x38b0b - Oncut Atom = 0x39605 - Ondblclick Atom = 0x39b0a - Ondrag Atom = 0x3a506 - Ondragend Atom = 0x3a509 - Ondragenter Atom = 0x3ae0b - Ondragexit Atom = 0x3b90a - Ondragleave Atom = 0x3d30b - Ondragover Atom = 0x3de0a - Ondragstart Atom = 0x3e80b - Ondrop Atom = 0x3f706 - Ondurationchange Atom = 0x40710 - Onemptied Atom = 0x3fe09 - Onended Atom = 0x41707 - Onerror Atom = 0x41e07 - Onfocus Atom = 0x42507 - Onhashchange Atom = 0x4310c - Oninput Atom = 0x43d07 - Oninvalid Atom = 0x44909 - Onkeydown Atom = 0x45209 - Onkeypress Atom = 0x45f0a - Onkeyup Atom = 0x47407 - Onlanguagechange Atom = 0x48110 - Onload Atom = 0x49106 - Onloadeddata Atom = 0x4910c - Onloadedmetadata Atom = 0x4a410 - Onloadend Atom = 0x4ba09 - Onloadstart Atom = 0x4c30b - Onmessage Atom = 0x4ce09 - Onmessageerror Atom = 0x4ce0e - Onmousedown Atom = 0x4dc0b - Onmouseenter Atom = 0x4e70c - Onmouseleave Atom = 0x4f30c - Onmousemove Atom = 0x4ff0b - Onmouseout Atom = 0x50a0a - Onmouseover Atom = 0x5170b - Onmouseup Atom = 0x52209 - Onmousewheel Atom = 0x5300c - Onoffline Atom = 0x53c09 - Ononline Atom = 0x54508 - Onpagehide Atom = 0x54d0a - Onpageshow Atom = 0x5670a - Onpaste Atom = 0x57307 - Onpause Atom = 0x58e07 - Onplay Atom = 0x59806 - Onplaying Atom = 0x59809 - Onpopstate Atom = 0x5a10a - Onprogress Atom = 0x5ab0a - Onratechange Atom = 0x5c80c - Onrejectionhandled Atom = 0x5d412 - Onreset Atom = 0x5e607 - Onresize Atom = 0x5ed08 - Onscroll Atom = 0x5fc08 - Onsecuritypolicyviolation Atom = 0x60419 - Onseeked Atom = 0x62508 - Onseeking Atom = 0x62d09 - Onselect Atom = 0x63608 - Onshow Atom = 0x64006 - Onsort Atom = 0x64b06 - Onstalled Atom = 0x65509 - Onstorage Atom = 0x65e09 - Onsubmit Atom = 0x66708 - Onsuspend Atom = 0x67709 - Ontimeupdate Atom = 0x11a0c - Ontoggle Atom = 0x68008 - Onunhandledrejection Atom = 0x68814 - Onunload Atom = 0x6a708 - Onvolumechange Atom = 0x6af0e - Onwaiting Atom = 0x6bd09 - Onwheel Atom = 0x6c607 - Open Atom = 0x55f04 - Optgroup Atom = 0xe008 - Optimum Atom = 0x6cd07 - Option Atom = 0x6dd06 - Output Atom = 0x51106 + Noembed Atom = 0x6c07 + Noframes Atom = 0x8908 + Nomodule Atom = 0xa208 + Nonce Atom = 0x1a605 + Noscript Atom = 0x21608 + Novalidate Atom = 0x2b20a + Object Atom = 0x26806 + Ol Atom = 0x13702 + Onabort Atom = 0x19507 + Onafterprint Atom = 0x2360c + Onautocomplete Atom = 0x2760e + Onautocompleteerror Atom = 0x27613 + Onauxclick Atom = 0x61f0a + Onbeforeprint Atom = 0x69e0d + Onbeforeunload Atom = 0x6e70e + Onblur Atom = 0x56d06 + Oncancel Atom = 0x11908 + Oncanplay Atom = 0x14d09 + Oncanplaythrough Atom = 0x14d10 + Onchange Atom = 0x41b08 + Onclick Atom = 0x2f507 + Onclose Atom = 0x36c07 + Oncontextmenu Atom = 0x37e0d + Oncopy Atom = 0x39106 + Oncuechange Atom = 0x3970b + Oncut Atom = 0x3a205 + Ondblclick Atom = 0x3a70a + Ondrag Atom = 0x3b106 + Ondragend Atom = 0x3b109 + Ondragenter Atom = 0x3ba0b + Ondragexit Atom = 0x3c50a + Ondragleave Atom = 0x3df0b + Ondragover Atom = 0x3ea0a + Ondragstart Atom = 0x3f40b + Ondrop Atom = 0x40306 + Ondurationchange Atom = 0x41310 + Onemptied Atom = 0x40a09 + Onended Atom = 0x42307 + Onerror Atom = 0x42a07 + Onfocus Atom = 0x43107 + Onhashchange Atom = 0x43d0c + Oninput Atom = 0x44907 + Oninvalid Atom = 0x45509 + Onkeydown Atom = 0x45e09 + Onkeypress Atom = 0x46b0a + Onkeyup Atom = 0x48007 + Onlanguagechange Atom = 0x48d10 + Onload Atom = 0x49d06 + Onloadeddata Atom = 0x49d0c + Onloadedmetadata Atom = 0x4b010 + Onloadend Atom = 0x4c609 + Onloadstart Atom = 0x4cf0b + Onmessage Atom = 0x4da09 + Onmessageerror Atom = 0x4da0e + Onmousedown Atom = 0x4e80b + Onmouseenter Atom = 0x4f30c + Onmouseleave Atom = 0x4ff0c + Onmousemove Atom = 0x50b0b + Onmouseout Atom = 0x5160a + Onmouseover Atom = 0x5230b + Onmouseup Atom = 0x52e09 + Onmousewheel Atom = 0x53c0c + Onoffline Atom = 0x54809 + Ononline Atom = 0x55108 + Onpagehide Atom = 0x5590a + Onpageshow Atom = 0x5730a + Onpaste Atom = 0x57f07 + Onpause Atom = 0x59a07 + Onplay Atom = 0x5a406 + Onplaying Atom = 0x5a409 + Onpopstate Atom = 0x5ad0a + Onprogress Atom = 0x5b70a + Onratechange Atom = 0x5cc0c + Onrejectionhandled Atom = 0x5d812 + Onreset Atom = 0x5ea07 + Onresize Atom = 0x5f108 + Onscroll Atom = 0x60008 + Onsecuritypolicyviolation Atom = 0x60819 + Onseeked Atom = 0x62908 + Onseeking Atom = 0x63109 + Onselect Atom = 0x63a08 + Onshow Atom = 0x64406 + Onsort Atom = 0x64f06 + Onstalled Atom = 0x65909 + Onstorage Atom = 0x66209 + Onsubmit Atom = 0x66b08 + Onsuspend Atom = 0x67b09 + Ontimeupdate Atom = 0x400c + Ontoggle Atom = 0x68408 + Onunhandledrejection Atom = 0x68c14 + Onunload Atom = 0x6ab08 + Onvolumechange Atom = 0x6b30e + Onwaiting Atom = 0x6c109 + Onwheel Atom = 0x6ca07 + Open Atom = 0x1a304 + Optgroup Atom = 0x5f08 + Optimum Atom = 0x6d107 + Option Atom = 0x6e306 + Output Atom = 0x51d06 P Atom = 0xc01 Param Atom = 0xc05 - Pattern Atom = 0x4f07 - Picture Atom = 0x9707 - Ping Atom = 0xe704 - Placeholder Atom = 0xfb0b - Plaintext Atom = 0x19e09 - Playsinline Atom = 0x10a0b - Poster Atom = 0x2b706 - Pre Atom = 0x46403 - Preload Atom = 0x47a07 - Progress Atom = 0x5ad08 - Prompt Atom = 0x52a06 - Public Atom = 0x57a06 - Q Atom = 0x7701 + Pattern Atom = 0x6607 + Picture Atom = 0x7b07 + Ping Atom = 0xef04 + Placeholder Atom = 0x1310b + Plaintext Atom = 0x1b209 + Playsinline Atom = 0x1400b + Poster Atom = 0x2cf06 + Pre Atom = 0x47003 + Preload Atom = 0x48607 + Progress Atom = 0x5b908 + Prompt Atom = 0x53606 + Public Atom = 0x58606 + Q Atom = 0xcf01 Radiogroup Atom = 0x30a - Readonly Atom = 0x34b08 - Referrerpolicy Atom = 0x3c50e - Rel Atom = 0x47b03 - Required Atom = 0x23408 - Reversed Atom = 0x9c08 - Rows Atom = 0x3a04 - Rowspan Atom = 0x3a07 - Rp Atom = 0x22402 - Rt Atom = 0x17b02 - Ruby Atom = 0xac04 + Rb Atom = 0x3a02 + Readonly Atom = 0x35708 + Referrerpolicy Atom = 0x3d10e + Rel Atom = 0x48703 + Required Atom = 0x24c08 + Reversed Atom = 0x8008 + Rows Atom = 0x9c04 + Rowspan Atom = 0x9c07 + Rp Atom = 0x23c02 + Rt Atom = 0x19a02 + Rtc Atom = 0x19a03 + Ruby Atom = 0xfb04 S Atom = 0x2501 - Samp Atom = 0x4c04 - Sandbox Atom = 0xf307 - Scope Atom = 0x67105 - Scoped Atom = 0x67106 - Script Atom = 0x20006 - Seamless Atom = 0x36508 - Section Atom = 0x5bd07 - Select Atom = 0x63806 - Selected Atom = 0x63808 - Shape Atom = 0x1d505 - Size Atom = 0x5f104 - Sizes Atom = 0x5f105 - Slot Atom = 0x1df04 - Small Atom = 0x1ee05 - Sortable Atom = 0x64d08 - Sorted Atom = 0x32b06 - Source Atom = 0x36c06 - Spacer Atom = 0x42b06 - Span Atom = 0x3d04 - Spellcheck Atom = 0x4680a - Src Atom = 0x5b403 - Srcdoc Atom = 0x5b406 - Srclang Atom = 0x5f507 - Srcset Atom = 0x6f306 - Start Atom = 0x3ee05 - Step Atom = 0x57704 - Strike Atom = 0x7a06 - Strong Atom = 0x31506 - Style Atom = 0x6f905 - Sub Atom = 0x66903 - Summary Atom = 0x6fe07 - Sup Atom = 0x70503 - Svg Atom = 0x70803 - System Atom = 0x70b06 - Tabindex Atom = 0x4b208 - Table Atom = 0x58905 - Target Atom = 0x2ac06 + Samp Atom = 0x7804 + Sandbox Atom = 0x12907 + Scope Atom = 0x67505 + Scoped Atom = 0x67506 + Script Atom = 0x21806 + Seamless Atom = 0x37108 + Section Atom = 0x56807 + Select Atom = 0x63c06 + Selected Atom = 0x63c08 + Shape Atom = 0x1e505 + Size Atom = 0x5f504 + Sizes Atom = 0x5f505 + Slot Atom = 0x1ef04 + Small Atom = 0x20605 + Sortable Atom = 0x65108 + Sorted Atom = 0x33706 + Source Atom = 0x37806 + Spacer Atom = 0x43706 + Span Atom = 0x9f04 + Spellcheck Atom = 0x4740a + Src Atom = 0x5c003 + Srcdoc Atom = 0x5c006 + Srclang Atom = 0x5f907 + Srcset Atom = 0x6f906 + Start Atom = 0x3fa05 + Step Atom = 0x58304 + Strike Atom = 0xd206 + Strong Atom = 0x6dd06 + Style Atom = 0x6ff05 + Sub Atom = 0x66d03 + Summary Atom = 0x70407 + Sup Atom = 0x70b03 + Svg Atom = 0x70e03 + System Atom = 0x71106 + Tabindex Atom = 0x4be08 + Table Atom = 0x59505 + Target Atom = 0x2c406 Tbody Atom = 0x2705 - Td Atom = 0x5e02 - Template Atom = 0x70e08 - Textarea Atom = 0x34608 - Tfoot Atom = 0xb205 - Th Atom = 0x13f02 - Thead Atom = 0x32405 - Time Atom = 0x11c04 - Title Atom = 0xca05 - Tr Atom = 0x7402 - Track Atom = 0x17c05 - Translate Atom = 0x1a609 - Tt Atom = 0x5102 - Type Atom = 0x8104 - Typemustmatch Atom = 0x2780d + Td Atom = 0x9202 + Template Atom = 0x71408 + Textarea Atom = 0x35208 + Tfoot Atom = 0xf505 + Th Atom = 0x15602 + Thead Atom = 0x33005 + Time Atom = 0x4204 + Title Atom = 0x11005 + Tr Atom = 0xcc02 + Track Atom = 0x1ba05 + Translate Atom = 0x1f209 + Tt Atom = 0x6802 + Type Atom = 0xd904 + Typemustmatch Atom = 0x2900d U Atom = 0xb01 - Ul Atom = 0x6602 - Updateviacache Atom = 0x1200e - Usemap Atom = 0x59206 + Ul Atom = 0xa702 + Updateviacache Atom = 0x460e + Usemap Atom = 0x59e06 Value Atom = 0x1505 - Var Atom = 0x15603 - Video Atom = 0x2d905 - Wbr Atom = 0x57003 - Width Atom = 0x64505 - Workertype Atom = 0x7160a - Wrap Atom = 0x72004 - Xmp Atom = 0xf903 + Var Atom = 0x16d03 + Video Atom = 0x2f105 + Wbr Atom = 0x57c03 + Width Atom = 0x64905 + Workertype Atom = 0x71c0a + Wrap Atom = 0x72604 + Xmp Atom = 0x12f03 ) const hash0 = 0x81cdf10e @@ -377,401 +380,404 @@ const hash0 = 0x81cdf10e const maxAtomLen = 25 var table = [1 << 9]Atom{ - 0x1: 0x8e0a, // mediagroup - 0x2: 0x2cc04, // lang + 0x1: 0xe60a, // mediagroup + 0x2: 0x2e404, // lang 0x4: 0x2c09, // accesskey - 0x5: 0x5708, // frameset - 0x7: 0x63608, // onselect - 0x8: 0x70b06, // system - 0xa: 0x64505, // width - 0xc: 0x2710b, // formenctype - 0xd: 0x10102, // ol - 0xe: 0x38b0b, // oncuechange - 0x10: 0x13403, // bdo - 0x11: 0xcf05, // audio - 0x12: 0x18309, // draggable - 0x14: 0x2d905, // video - 0x15: 0x29902, // mn - 0x16: 0x37b04, // menu - 0x17: 0x2b706, // poster - 0x19: 0xb306, // footer - 0x1a: 0x29006, // method - 0x1b: 0x2a008, // datetime - 0x1c: 0x17607, // onabort - 0x1d: 0x1200e, // updateviacache - 0x1e: 0xb905, // async - 0x1f: 0x49106, // onload - 0x21: 0xd308, // oncancel - 0x22: 0x62508, // onseeked - 0x23: 0x2ea05, // image - 0x24: 0x5d412, // onrejectionhandled - 0x26: 0x15d04, // link - 0x27: 0x51106, // output - 0x28: 0x32504, // head - 0x29: 0x4f30c, // onmouseleave - 0x2a: 0x57307, // onpaste - 0x2b: 0x59809, // onplaying - 0x2c: 0x1b407, // colspan - 0x2f: 0x1af05, // color - 0x30: 0x5f104, // size - 0x31: 0x2d00a, // http-equiv + 0x5: 0x8b08, // frameset + 0x7: 0x63a08, // onselect + 0x8: 0x71106, // system + 0xa: 0x64905, // width + 0xc: 0x2890b, // formenctype + 0xd: 0x13702, // ol + 0xe: 0x3970b, // oncuechange + 0x10: 0x14b03, // bdo + 0x11: 0x11505, // audio + 0x12: 0x17a09, // draggable + 0x14: 0x2f105, // video + 0x15: 0x2b102, // mn + 0x16: 0x38704, // menu + 0x17: 0x2cf06, // poster + 0x19: 0xf606, // footer + 0x1a: 0x2a806, // method + 0x1b: 0x2b808, // datetime + 0x1c: 0x19507, // onabort + 0x1d: 0x460e, // updateviacache + 0x1e: 0xff05, // async + 0x1f: 0x49d06, // onload + 0x21: 0x11908, // oncancel + 0x22: 0x62908, // onseeked + 0x23: 0x30205, // image + 0x24: 0x5d812, // onrejectionhandled + 0x26: 0x17404, // link + 0x27: 0x51d06, // output + 0x28: 0x33104, // head + 0x29: 0x4ff0c, // onmouseleave + 0x2a: 0x57f07, // onpaste + 0x2b: 0x5a409, // onplaying + 0x2c: 0x1c407, // colspan + 0x2f: 0x1bf05, // color + 0x30: 0x5f504, // size + 0x31: 0x2e80a, // http-equiv 0x33: 0x601, // i - 0x34: 0x54d0a, // onpagehide - 0x35: 0x68814, // onunhandledrejection - 0x37: 0x41e07, // onerror - 0x3a: 0x11508, // basefont + 0x34: 0x5590a, // onpagehide + 0x35: 0x68c14, // onunhandledrejection + 0x37: 0x42a07, // onerror + 0x3a: 0x3b08, // basefont 0x3f: 0x1303, // nav - 0x40: 0x18004, // kind - 0x41: 0x34b08, // readonly - 0x42: 0x2f006, // mglyph - 0x44: 0x11102, // li - 0x46: 0x2bd06, // hidden - 0x47: 0x70803, // svg - 0x48: 0x57704, // step - 0x49: 0x22709, // integrity - 0x4a: 0x57a06, // public - 0x4c: 0x19703, // col - 0x4d: 0x1680a, // blockquote - 0x4e: 0x34302, // h5 - 0x50: 0x5ad08, // progress - 0x51: 0x5f105, // sizes - 0x52: 0x33902, // h4 - 0x56: 0x32405, // thead - 0x57: 0x7e07, // keytype - 0x58: 0x5ab0a, // onprogress - 0x59: 0x43f09, // inputmode - 0x5a: 0x3a509, // ondragend - 0x5d: 0x39605, // oncut - 0x5e: 0x42b06, // spacer - 0x5f: 0x19708, // colgroup - 0x62: 0x14e02, // is - 0x65: 0xb902, // as - 0x66: 0x53c09, // onoffline - 0x67: 0x32b06, // sorted - 0x69: 0x48110, // onlanguagechange - 0x6c: 0x4310c, // onhashchange - 0x6d: 0xa604, // name - 0x6e: 0xb205, // tfoot - 0x6f: 0x55504, // desc - 0x70: 0x33103, // max - 0x72: 0x1da06, // coords - 0x73: 0x2f502, // h3 - 0x74: 0x6e10e, // onbeforeunload - 0x75: 0x3a04, // rows - 0x76: 0x63806, // select - 0x77: 0xa805, // meter - 0x78: 0x37f06, // itemid - 0x79: 0x5300c, // onmousewheel - 0x7a: 0x5b406, // srcdoc - 0x7d: 0x17c05, // track - 0x7f: 0x30708, // itemtype - 0x82: 0x6302, // mo - 0x83: 0x40f08, // onchange - 0x84: 0x32507, // headers - 0x85: 0x5c80c, // onratechange - 0x86: 0x60419, // onsecuritypolicyviolation - 0x88: 0x49908, // datalist - 0x89: 0x4dc0b, // onmousedown - 0x8a: 0x1df04, // slot - 0x8b: 0x4a410, // onloadedmetadata + 0x40: 0x17704, // kind + 0x41: 0x35708, // readonly + 0x42: 0x30806, // mglyph + 0x44: 0xb202, // li + 0x46: 0x2d506, // hidden + 0x47: 0x70e03, // svg + 0x48: 0x58304, // step + 0x49: 0x23f09, // integrity + 0x4a: 0x58606, // public + 0x4c: 0x1ab03, // col + 0x4d: 0x1870a, // blockquote + 0x4e: 0x34f02, // h5 + 0x50: 0x5b908, // progress + 0x51: 0x5f505, // sizes + 0x52: 0x34502, // h4 + 0x56: 0x33005, // thead + 0x57: 0xd607, // keytype + 0x58: 0x5b70a, // onprogress + 0x59: 0x44b09, // inputmode + 0x5a: 0x3b109, // ondragend + 0x5d: 0x3a205, // oncut + 0x5e: 0x43706, // spacer + 0x5f: 0x1ab08, // colgroup + 0x62: 0x16502, // is + 0x65: 0x3c02, // as + 0x66: 0x54809, // onoffline + 0x67: 0x33706, // sorted + 0x69: 0x48d10, // onlanguagechange + 0x6c: 0x43d0c, // onhashchange + 0x6d: 0x9604, // name + 0x6e: 0xf505, // tfoot + 0x6f: 0x56104, // desc + 0x70: 0x33d03, // max + 0x72: 0x1ea06, // coords + 0x73: 0x30d02, // h3 + 0x74: 0x6e70e, // onbeforeunload + 0x75: 0x9c04, // rows + 0x76: 0x63c06, // select + 0x77: 0x9805, // meter + 0x78: 0x38b06, // itemid + 0x79: 0x53c0c, // onmousewheel + 0x7a: 0x5c006, // srcdoc + 0x7d: 0x1ba05, // track + 0x7f: 0x31f08, // itemtype + 0x82: 0xa402, // mo + 0x83: 0x41b08, // onchange + 0x84: 0x33107, // headers + 0x85: 0x5cc0c, // onratechange + 0x86: 0x60819, // onsecuritypolicyviolation + 0x88: 0x4a508, // datalist + 0x89: 0x4e80b, // onmousedown + 0x8a: 0x1ef04, // slot + 0x8b: 0x4b010, // onloadedmetadata 0x8c: 0x1a06, // accept - 0x8d: 0x25006, // object - 0x91: 0x6af0e, // onvolumechange + 0x8d: 0x26806, // object + 0x91: 0x6b30e, // onvolumechange 0x92: 0x2107, // charset - 0x93: 0x25e13, // onautocompleteerror - 0x94: 0x6913, // allowpaymentrequest + 0x93: 0x27613, // onautocompleteerror + 0x94: 0xc113, // allowpaymentrequest 0x95: 0x2804, // body - 0x96: 0xc407, // default - 0x97: 0x63808, // selected - 0x98: 0x20604, // face - 0x99: 0x1d505, // shape - 0x9b: 0x68008, // ontoggle - 0x9e: 0x64702, // dt - 0x9f: 0x6d904, // mark + 0x96: 0x10a07, // default + 0x97: 0x63c08, // selected + 0x98: 0x21e04, // face + 0x99: 0x1e505, // shape + 0x9b: 0x68408, // ontoggle + 0x9e: 0x64b02, // dt + 0x9f: 0xb604, // mark 0xa1: 0xb01, // u - 0xa4: 0x6a708, // onunload - 0xa5: 0xde04, // loop - 0xa6: 0x14d08, // disabled - 0xaa: 0x41707, // onended - 0xab: 0x6d30a, // malignmark - 0xad: 0x67709, // onsuspend - 0xae: 0x34505, // mtext - 0xaf: 0x64b06, // onsort - 0xb0: 0x55908, // itemprop - 0xb3: 0x66d09, // itemscope - 0xb4: 0x15c05, // blink - 0xb6: 0x3a506, // ondrag - 0xb7: 0x6602, // ul - 0xb8: 0x25604, // form - 0xb9: 0xf307, // sandbox - 0xba: 0x5705, // frame + 0xa4: 0x6ab08, // onunload + 0xa5: 0x5d04, // loop + 0xa6: 0x16408, // disabled + 0xaa: 0x42307, // onended + 0xab: 0xb00a, // malignmark + 0xad: 0x67b09, // onsuspend + 0xae: 0x35105, // mtext + 0xaf: 0x64f06, // onsort + 0xb0: 0x19d08, // itemprop + 0xb3: 0x67109, // itemscope + 0xb4: 0x17305, // blink + 0xb6: 0x3b106, // ondrag + 0xb7: 0xa702, // ul + 0xb8: 0x26e04, // form + 0xb9: 0x12907, // sandbox + 0xba: 0x8b05, // frame 0xbb: 0x1505, // value - 0xbc: 0x65e09, // onstorage - 0xc0: 0x17b02, // rt + 0xbc: 0x66209, // onstorage + 0xbf: 0xaa07, // acronym + 0xc0: 0x19a02, // rt 0xc2: 0x202, // br - 0xc3: 0x20e08, // fieldset - 0xc4: 0x2780d, // typemustmatch - 0xc5: 0x6108, // nomodule - 0xc6: 0x4007, // noembed - 0xc7: 0x69a0d, // onbeforeprint - 0xc8: 0x17206, // button - 0xc9: 0x2dd07, // onclick - 0xca: 0x6fe07, // summary - 0xcd: 0xac04, // ruby - 0xce: 0x5b905, // class - 0xcf: 0x3e80b, // ondragstart - 0xd0: 0x21907, // caption - 0xd4: 0x850e, // allowusermedia - 0xd5: 0x4c30b, // onloadstart - 0xd9: 0x15403, // div - 0xda: 0x49d04, // list - 0xdb: 0x32204, // math - 0xdc: 0x43f05, // input - 0xdf: 0x3de0a, // ondragover - 0xe0: 0x2c602, // h2 - 0xe2: 0x19e09, // plaintext - 0xe4: 0x4e70c, // onmouseenter - 0xe7: 0x46d07, // checked - 0xe8: 0x46403, // pre - 0xea: 0x35308, // multiple - 0xeb: 0x16103, // bdi - 0xec: 0x33109, // maxlength - 0xed: 0x7701, // q - 0xee: 0x61b0a, // onauxclick - 0xf0: 0x57003, // wbr - 0xf2: 0x11504, // base - 0xf3: 0x6dd06, // option - 0xf5: 0x40710, // ondurationchange - 0xf7: 0x5508, // noframes - 0xf9: 0x3f908, // dropzone - 0xfb: 0x67105, // scope - 0xfc: 0x9c08, // reversed - 0xfd: 0x3ae0b, // ondragenter - 0xfe: 0x3ee05, // start - 0xff: 0xf903, // xmp - 0x100: 0x5f507, // srclang - 0x101: 0x2ef03, // img + 0xc3: 0x22608, // fieldset + 0xc4: 0x2900d, // typemustmatch + 0xc5: 0xa208, // nomodule + 0xc6: 0x6c07, // noembed + 0xc7: 0x69e0d, // onbeforeprint + 0xc8: 0x19106, // button + 0xc9: 0x2f507, // onclick + 0xca: 0x70407, // summary + 0xcd: 0xfb04, // ruby + 0xce: 0x56405, // class + 0xcf: 0x3f40b, // ondragstart + 0xd0: 0x23107, // caption + 0xd4: 0xdd0e, // allowusermedia + 0xd5: 0x4cf0b, // onloadstart + 0xd9: 0x16b03, // div + 0xda: 0x4a904, // list + 0xdb: 0x32e04, // math + 0xdc: 0x44b05, // input + 0xdf: 0x3ea0a, // ondragover + 0xe0: 0x2de02, // h2 + 0xe2: 0x1b209, // plaintext + 0xe4: 0x4f30c, // onmouseenter + 0xe7: 0x47907, // checked + 0xe8: 0x47003, // pre + 0xea: 0x35f08, // multiple + 0xeb: 0xba03, // bdi + 0xec: 0x33d09, // maxlength + 0xed: 0xcf01, // q + 0xee: 0x61f0a, // onauxclick + 0xf0: 0x57c03, // wbr + 0xf2: 0x3b04, // base + 0xf3: 0x6e306, // option + 0xf5: 0x41310, // ondurationchange + 0xf7: 0x8908, // noframes + 0xf9: 0x40508, // dropzone + 0xfb: 0x67505, // scope + 0xfc: 0x8008, // reversed + 0xfd: 0x3ba0b, // ondragenter + 0xfe: 0x3fa05, // start + 0xff: 0x12f03, // xmp + 0x100: 0x5f907, // srclang + 0x101: 0x30703, // img 0x104: 0x101, // b - 0x105: 0x23c03, // for - 0x106: 0xc105, // aside - 0x107: 0x43d07, // oninput - 0x108: 0x34a04, // area - 0x109: 0x28c0a, // formmethod - 0x10a: 0x72004, // wrap - 0x10c: 0x22402, // rp - 0x10d: 0x45f0a, // onkeypress - 0x10e: 0x5102, // tt - 0x110: 0x33b02, // mi - 0x111: 0x35b05, // muted - 0x112: 0xb003, // alt - 0x113: 0x19004, // code - 0x114: 0x4202, // em - 0x115: 0x3b90a, // ondragexit - 0x117: 0x3d04, // span - 0x119: 0x30f08, // manifest - 0x11a: 0x37b08, // menuitem - 0x11b: 0x57f07, // content - 0x11d: 0x6bd09, // onwaiting - 0x11f: 0x4ba09, // onloadend - 0x121: 0x3720d, // oncontextmenu - 0x123: 0x5c206, // onblur - 0x124: 0x3f007, // article - 0x125: 0xa303, // dir - 0x126: 0xe704, // ping - 0x127: 0x23408, // required - 0x128: 0x44909, // oninvalid - 0x129: 0x6d405, // align - 0x12b: 0x57e04, // icon - 0x12c: 0x64902, // h6 - 0x12d: 0x1b404, // cols - 0x12e: 0x2160a, // figcaption - 0x12f: 0x45209, // onkeydown - 0x130: 0x66708, // onsubmit - 0x131: 0x13609, // oncanplay - 0x132: 0x70503, // sup + 0x105: 0x25403, // for + 0x106: 0x10705, // aside + 0x107: 0x44907, // oninput + 0x108: 0x35604, // area + 0x109: 0x2a40a, // formmethod + 0x10a: 0x72604, // wrap + 0x10c: 0x23c02, // rp + 0x10d: 0x46b0a, // onkeypress + 0x10e: 0x6802, // tt + 0x110: 0x34702, // mi + 0x111: 0x36705, // muted + 0x112: 0xf303, // alt + 0x113: 0x5c504, // code + 0x114: 0x6e02, // em + 0x115: 0x3c50a, // ondragexit + 0x117: 0x9f04, // span + 0x119: 0x6d708, // manifest + 0x11a: 0x38708, // menuitem + 0x11b: 0x58b07, // content + 0x11d: 0x6c109, // onwaiting + 0x11f: 0x4c609, // onloadend + 0x121: 0x37e0d, // oncontextmenu + 0x123: 0x56d06, // onblur + 0x124: 0x3fc07, // article + 0x125: 0x9303, // dir + 0x126: 0xef04, // ping + 0x127: 0x24c08, // required + 0x128: 0x45509, // oninvalid + 0x129: 0xb105, // align + 0x12b: 0x58a04, // icon + 0x12c: 0x64d02, // h6 + 0x12d: 0x1c404, // cols + 0x12e: 0x22e0a, // figcaption + 0x12f: 0x45e09, // onkeydown + 0x130: 0x66b08, // onsubmit + 0x131: 0x14d09, // oncanplay + 0x132: 0x70b03, // sup 0x133: 0xc01, // p - 0x135: 0x3fe09, // onemptied - 0x136: 0x38506, // oncopy - 0x137: 0x55804, // cite - 0x138: 0x39b0a, // ondblclick - 0x13a: 0x4ff0b, // onmousemove - 0x13c: 0x66903, // sub - 0x13d: 0x47b03, // rel - 0x13e: 0xe008, // optgroup - 0x142: 0x3a07, // rowspan - 0x143: 0x36c06, // source - 0x144: 0x1fe08, // noscript - 0x145: 0x55f04, // open - 0x146: 0x1ec03, // ins - 0x147: 0x23c0d, // foreignObject - 0x148: 0x5a10a, // onpopstate - 0x14a: 0x27507, // enctype - 0x14b: 0x25e0e, // onautocomplete - 0x14c: 0x34608, // textarea - 0x14e: 0x2600c, // autocomplete - 0x14f: 0x14002, // hr - 0x150: 0x1ce08, // controls - 0x151: 0xc302, // id - 0x153: 0x21e0c, // onafterprint - 0x155: 0x2490d, // foreignobject - 0x156: 0x31b07, // marquee - 0x157: 0x58e07, // onpause - 0x158: 0x5e202, // dl - 0x159: 0x12c06, // height - 0x15a: 0x33b03, // min - 0x15b: 0xa307, // dirname - 0x15c: 0x1a609, // translate - 0x15d: 0x13004, // html - 0x15e: 0x33b09, // minlength - 0x15f: 0x47a07, // preload - 0x160: 0x70e08, // template - 0x161: 0x3d30b, // ondragleave - 0x164: 0x5b403, // src - 0x165: 0x31506, // strong - 0x167: 0x4c04, // samp - 0x168: 0x6ed07, // address - 0x169: 0x54508, // ononline - 0x16b: 0xfb0b, // placeholder - 0x16c: 0x2ac06, // target - 0x16d: 0x1ee05, // small - 0x16e: 0x6c607, // onwheel - 0x16f: 0x1b90a, // annotation - 0x170: 0x4680a, // spellcheck - 0x171: 0x4607, // details - 0x172: 0xbd06, // canvas - 0x173: 0xeb09, // autofocus + 0x135: 0x40a09, // onemptied + 0x136: 0x39106, // oncopy + 0x137: 0x19c04, // cite + 0x138: 0x3a70a, // ondblclick + 0x13a: 0x50b0b, // onmousemove + 0x13c: 0x66d03, // sub + 0x13d: 0x48703, // rel + 0x13e: 0x5f08, // optgroup + 0x142: 0x9c07, // rowspan + 0x143: 0x37806, // source + 0x144: 0x21608, // noscript + 0x145: 0x1a304, // open + 0x146: 0x20403, // ins + 0x147: 0x2540d, // foreignObject + 0x148: 0x5ad0a, // onpopstate + 0x14a: 0x28d07, // enctype + 0x14b: 0x2760e, // onautocomplete + 0x14c: 0x35208, // textarea + 0x14e: 0x2780c, // autocomplete + 0x14f: 0x15702, // hr + 0x150: 0x1de08, // controls + 0x151: 0x10902, // id + 0x153: 0x2360c, // onafterprint + 0x155: 0x2610d, // foreignobject + 0x156: 0x32707, // marquee + 0x157: 0x59a07, // onpause + 0x158: 0x5e602, // dl + 0x159: 0x5206, // height + 0x15a: 0x34703, // min + 0x15b: 0x9307, // dirname + 0x15c: 0x1f209, // translate + 0x15d: 0x5604, // html + 0x15e: 0x34709, // minlength + 0x15f: 0x48607, // preload + 0x160: 0x71408, // template + 0x161: 0x3df0b, // ondragleave + 0x162: 0x3a02, // rb + 0x164: 0x5c003, // src + 0x165: 0x6dd06, // strong + 0x167: 0x7804, // samp + 0x168: 0x6f307, // address + 0x169: 0x55108, // ononline + 0x16b: 0x1310b, // placeholder + 0x16c: 0x2c406, // target + 0x16d: 0x20605, // small + 0x16e: 0x6ca07, // onwheel + 0x16f: 0x1c90a, // annotation + 0x170: 0x4740a, // spellcheck + 0x171: 0x7207, // details + 0x172: 0x10306, // canvas + 0x173: 0x12109, // autofocus 0x174: 0xc05, // param - 0x176: 0x45708, // download - 0x177: 0x44603, // del - 0x178: 0x36007, // onclose - 0x179: 0x16003, // kbd - 0x17a: 0x30106, // applet - 0x17b: 0x2c804, // href - 0x17c: 0x5ed08, // onresize - 0x17e: 0x4910c, // onloadeddata - 0x180: 0x7402, // tr - 0x181: 0x2a80a, // formtarget - 0x182: 0xca05, // title - 0x183: 0x6f905, // style - 0x184: 0x7a06, // strike - 0x185: 0x59206, // usemap - 0x186: 0x2e406, // iframe + 0x176: 0x46308, // download + 0x177: 0x45203, // del + 0x178: 0x36c07, // onclose + 0x179: 0xb903, // kbd + 0x17a: 0x31906, // applet + 0x17b: 0x2e004, // href + 0x17c: 0x5f108, // onresize + 0x17e: 0x49d0c, // onloadeddata + 0x180: 0xcc02, // tr + 0x181: 0x2c00a, // formtarget + 0x182: 0x11005, // title + 0x183: 0x6ff05, // style + 0x184: 0xd206, // strike + 0x185: 0x59e06, // usemap + 0x186: 0x2fc06, // iframe 0x187: 0x1004, // main - 0x189: 0x9707, // picture - 0x18c: 0x2fe05, // ismap - 0x18e: 0x49904, // data - 0x18f: 0xda05, // label - 0x191: 0x3c50e, // referrerpolicy - 0x192: 0x13f02, // th - 0x194: 0x52a06, // prompt - 0x195: 0x5bd07, // section - 0x197: 0x6cd07, // optimum - 0x198: 0x2c304, // high - 0x199: 0x14502, // h1 - 0x19a: 0x65509, // onstalled - 0x19b: 0x15603, // var - 0x19c: 0x11c04, // time - 0x19e: 0x67002, // ms - 0x19f: 0x32506, // header - 0x1a0: 0x4ce09, // onmessage - 0x1a1: 0x56205, // nonce - 0x1a2: 0x2560a, // formaction - 0x1a3: 0x20806, // center + 0x189: 0x7b07, // picture + 0x18c: 0x31605, // ismap + 0x18e: 0x4a504, // data + 0x18f: 0x5905, // label + 0x191: 0x3d10e, // referrerpolicy + 0x192: 0x15602, // th + 0x194: 0x53606, // prompt + 0x195: 0x56807, // section + 0x197: 0x6d107, // optimum + 0x198: 0x2db04, // high + 0x199: 0x15c02, // h1 + 0x19a: 0x65909, // onstalled + 0x19b: 0x16d03, // var + 0x19c: 0x4204, // time + 0x19e: 0x67402, // ms + 0x19f: 0x33106, // header + 0x1a0: 0x4da09, // onmessage + 0x1a1: 0x1a605, // nonce + 0x1a2: 0x26e0a, // formaction + 0x1a3: 0x22006, // center 0x1a4: 0x3704, // nobr - 0x1a5: 0x58905, // table - 0x1a6: 0x49d07, // listing - 0x1a7: 0x18a06, // legend - 0x1a9: 0x28309, // challenge - 0x1aa: 0x23006, // figure - 0x1ab: 0x8e05, // media - 0x1ae: 0x8104, // type - 0x1af: 0x11904, // font - 0x1b0: 0x4ce0e, // onmessageerror - 0x1b1: 0x36508, // seamless - 0x1b2: 0x5f03, // dfn - 0x1b3: 0x19205, // defer - 0x1b4: 0x6b03, // low - 0x1b5: 0x62d09, // onseeking - 0x1b6: 0x5170b, // onmouseover - 0x1b7: 0x29a0a, // novalidate - 0x1b8: 0x7160a, // workertype - 0x1ba: 0x3c107, // itemref + 0x1a5: 0x59505, // table + 0x1a6: 0x4a907, // listing + 0x1a7: 0x18106, // legend + 0x1a9: 0x29b09, // challenge + 0x1aa: 0x24806, // figure + 0x1ab: 0xe605, // media + 0x1ae: 0xd904, // type + 0x1af: 0x3f04, // font + 0x1b0: 0x4da0e, // onmessageerror + 0x1b1: 0x37108, // seamless + 0x1b2: 0x8703, // dfn + 0x1b3: 0x5c705, // defer + 0x1b4: 0xc303, // low + 0x1b5: 0x19a03, // rtc + 0x1b6: 0x5230b, // onmouseover + 0x1b7: 0x2b20a, // novalidate + 0x1b8: 0x71c0a, // workertype + 0x1ba: 0x3cd07, // itemref 0x1bd: 0x1, // a - 0x1be: 0x30003, // map - 0x1bf: 0x11a0c, // ontimeupdate - 0x1c0: 0x14707, // bgsound + 0x1be: 0x31803, // map + 0x1bf: 0x400c, // ontimeupdate + 0x1c0: 0x15e07, // bgsound 0x1c1: 0x3206, // keygen 0x1c2: 0x2705, // tbody - 0x1c5: 0x64006, // onshow + 0x1c5: 0x64406, // onshow 0x1c7: 0x2501, // s - 0x1c8: 0x4f07, // pattern - 0x1cc: 0x13610, // oncanplaythrough - 0x1ce: 0x2bf02, // dd - 0x1cf: 0x6f306, // srcset - 0x1d0: 0x15903, // big - 0x1d2: 0x64d08, // sortable - 0x1d3: 0x47407, // onkeyup - 0x1d5: 0x59806, // onplay - 0x1d7: 0x4ac04, // meta - 0x1d8: 0x3f706, // ondrop - 0x1da: 0x5fc08, // onscroll - 0x1db: 0x1e30b, // crossorigin - 0x1dc: 0x5670a, // onpageshow + 0x1c8: 0x6607, // pattern + 0x1cc: 0x14d10, // oncanplaythrough + 0x1ce: 0x2d702, // dd + 0x1cf: 0x6f906, // srcset + 0x1d0: 0x17003, // big + 0x1d2: 0x65108, // sortable + 0x1d3: 0x48007, // onkeyup + 0x1d5: 0x5a406, // onplay + 0x1d7: 0x4b804, // meta + 0x1d8: 0x40306, // ondrop + 0x1da: 0x60008, // onscroll + 0x1db: 0x1fb0b, // crossorigin + 0x1dc: 0x5730a, // onpageshow 0x1dd: 0x4, // abbr - 0x1de: 0x5e02, // td - 0x1df: 0x57f0f, // contenteditable - 0x1e0: 0x25a06, // action - 0x1e1: 0x10a0b, // playsinline - 0x1e2: 0x42507, // onfocus - 0x1e3: 0x2c808, // hreflang - 0x1e5: 0x50a0a, // onmouseout - 0x1e6: 0x5e607, // onreset - 0x1e7: 0x10608, // autoplay - 0x1ea: 0x67106, // scoped + 0x1de: 0x9202, // td + 0x1df: 0x58b0f, // contenteditable + 0x1e0: 0x27206, // action + 0x1e1: 0x1400b, // playsinline + 0x1e2: 0x43107, // onfocus + 0x1e3: 0x2e008, // hreflang + 0x1e5: 0x5160a, // onmouseout + 0x1e6: 0x5ea07, // onreset + 0x1e7: 0x13c08, // autoplay + 0x1e8: 0x63109, // onseeking + 0x1ea: 0x67506, // scoped 0x1ec: 0x30a, // radiogroup - 0x1ee: 0x3740b, // contextmenu - 0x1ef: 0x52209, // onmouseup - 0x1f1: 0x2b206, // hgroup - 0x1f2: 0x1f00f, // allowfullscreen - 0x1f3: 0x4b208, // tabindex - 0x1f6: 0x2f707, // isindex + 0x1ee: 0x3800b, // contextmenu + 0x1ef: 0x52e09, // onmouseup + 0x1f1: 0x2ca06, // hgroup + 0x1f2: 0x2080f, // allowfullscreen + 0x1f3: 0x4be08, // tabindex + 0x1f6: 0x30f07, // isindex 0x1f7: 0x1a0e, // accept-charset - 0x1f8: 0x2960e, // formnovalidate - 0x1fb: 0x1b90e, // annotation-xml - 0x1fc: 0x4205, // embed - 0x1fd: 0x20006, // script - 0x1fe: 0x16206, // dialog - 0x1ff: 0x1c707, // command + 0x1f8: 0x2ae0e, // formnovalidate + 0x1fb: 0x1c90e, // annotation-xml + 0x1fc: 0x6e05, // embed + 0x1fd: 0x21806, // script + 0x1fe: 0xbb06, // dialog + 0x1ff: 0x1d707, // command } -const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobro" + - "wspanoembedetailsampatternoframesetdfnomoduleallowpaymentreq" + - "uestrikeytypeallowusermediagroupictureversedirnameterubyaltf" + - "ooterasyncanvasidefaultitleaudioncancelabelooptgroupingautof" + - "ocusandboxmplaceholderautoplaysinlinebasefontimeupdateviacac" + - "heightmlbdoncanplaythrough1bgsoundisabledivarbigblinkbdialog" + - "blockquotebuttonabortrackindraggablegendcodefercolgrouplaint" + - "extranslatecolorcolspannotation-xmlcommandcontrolshapecoords" + - "lotcrossoriginsmallowfullscreenoscriptfacenterfieldsetfigcap" + - "tionafterprintegrityfigurequiredforeignObjectforeignobjectfo" + - "rmactionautocompleteerrorformenctypemustmatchallengeformmeth" + - "odformnovalidatetimeformtargethgrouposterhiddenhigh2hreflang" + - "http-equivideonclickiframeimageimglyph3isindexismappletitemt" + - "ypemanifestrongmarqueematheadersortedmaxlength4minlength5mte" + - "xtareadonlymultiplemutedoncloseamlessourceoncontextmenuitemi" + - "doncopyoncuechangeoncutondblclickondragendondragenterondrage" + - "xitemreferrerpolicyondragleaveondragoverondragstarticleondro" + - "pzonemptiedondurationchangeonendedonerroronfocuspaceronhashc" + - "hangeoninputmodeloninvalidonkeydownloadonkeypresspellchecked" + - "onkeyupreloadonlanguagechangeonloadeddatalistingonloadedmeta" + - "databindexonloadendonloadstartonmessageerroronmousedownonmou" + - "seenteronmouseleaveonmousemoveonmouseoutputonmouseoveronmous" + - "eupromptonmousewheelonofflineononlineonpagehidescitempropeno" + - "nceonpageshowbronpastepublicontenteditableonpausemaponplayin" + - "gonpopstateonprogressrcdoclassectionbluronratechangeonreject" + - "ionhandledonresetonresizesrclangonscrollonsecuritypolicyviol" + - "ationauxclickonseekedonseekingonselectedonshowidth6onsortabl" + - "eonstalledonstorageonsubmitemscopedonsuspendontoggleonunhand" + - "ledrejectionbeforeprintonunloadonvolumechangeonwaitingonwhee" + - "loptimumalignmarkoptionbeforeunloaddressrcsetstylesummarysup" + - "svgsystemplateworkertypewrap" +const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" + + "asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" + + "sampictureversedfnoframesetdirnameterowspanomoduleacronymali" + + "gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" + + "ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" + + "dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" + + "bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" + + "penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" + + "ntrolshapecoordslotranslatecrossoriginsmallowfullscreenoscri" + + "ptfacenterfieldsetfigcaptionafterprintegrityfigurequiredfore" + + "ignObjectforeignobjectformactionautocompleteerrorformenctype" + + "mustmatchallengeformmethodformnovalidatetimeformtargethgroup" + + "osterhiddenhigh2hreflanghttp-equivideonclickiframeimageimgly" + + "ph3isindexismappletitemtypemarqueematheadersortedmaxlength4m" + + "inlength5mtextareadonlymultiplemutedoncloseamlessourceoncont" + + "extmenuitemidoncopyoncuechangeoncutondblclickondragendondrag" + + "enterondragexitemreferrerpolicyondragleaveondragoverondragst" + + "articleondropzonemptiedondurationchangeonendedonerroronfocus" + + "paceronhashchangeoninputmodeloninvalidonkeydownloadonkeypres" + + "spellcheckedonkeyupreloadonlanguagechangeonloadeddatalisting" + + "onloadedmetadatabindexonloadendonloadstartonmessageerroronmo" + + "usedownonmouseenteronmouseleaveonmousemoveonmouseoutputonmou" + + "seoveronmouseupromptonmousewheelonofflineononlineonpagehides" + + "classectionbluronpageshowbronpastepublicontenteditableonpaus" + + "emaponplayingonpopstateonprogressrcdocodeferonratechangeonre" + + "jectionhandledonresetonresizesrclangonscrollonsecuritypolicy" + + "violationauxclickonseekedonseekingonselectedonshowidth6onsor" + + "tableonstalledonstorageonsubmitemscopedonsuspendontoggleonun" + + "handledrejectionbeforeprintonunloadonvolumechangeonwaitingon" + + "wheeloptimumanifestrongoptionbeforeunloaddressrcsetstylesumm" + + "arysupsvgsystemplateworkertypewrap" diff --git a/vendor/golang.org/x/net/html/atom/table_test.go b/vendor/golang.org/x/net/html/atom/table_test.go index 16891054..8a30762e 100644 --- a/vendor/golang.org/x/net/html/atom/table_test.go +++ b/vendor/golang.org/x/net/html/atom/table_test.go @@ -10,6 +10,7 @@ var testAtomList = []string{ "accept", "accept-charset", "accesskey", + "acronym", "action", "address", "align", @@ -295,6 +296,7 @@ var testAtomList = []string{ "public", "q", "radiogroup", + "rb", "readonly", "referrerpolicy", "rel", @@ -304,6 +306,7 @@ var testAtomList = []string{ "rowspan", "rp", "rt", + "rtc", "ruby", "s", "samp", diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go index b37e6212..5eb7c5a8 100644 --- a/vendor/golang.org/x/net/html/const.go +++ b/vendor/golang.org/x/net/html/const.go @@ -4,7 +4,7 @@ package html -// Section 12.2.3.2 of the HTML5 specification says "The following elements +// Section 12.2.4.2 of the HTML5 specification says "The following elements // have varying levels of special parsing rules". // https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements var isSpecialElementMap = map[string]bool{ diff --git a/vendor/golang.org/x/net/html/entity.go b/vendor/golang.org/x/net/html/entity.go index a50c04c6..b628880a 100644 --- a/vendor/golang.org/x/net/html/entity.go +++ b/vendor/golang.org/x/net/html/entity.go @@ -75,2083 +75,2083 @@ var entity = map[string]rune{ "Copf;": '\U00002102', "Coproduct;": '\U00002210', "CounterClockwiseContourIntegral;": '\U00002233', - "Cross;": '\U00002A2F', - "Cscr;": '\U0001D49E', - "Cup;": '\U000022D3', - "CupCap;": '\U0000224D', - "DD;": '\U00002145', - "DDotrahd;": '\U00002911', - "DJcy;": '\U00000402', - "DScy;": '\U00000405', - "DZcy;": '\U0000040F', - "Dagger;": '\U00002021', - "Darr;": '\U000021A1', - "Dashv;": '\U00002AE4', - "Dcaron;": '\U0000010E', - "Dcy;": '\U00000414', - "Del;": '\U00002207', - "Delta;": '\U00000394', - "Dfr;": '\U0001D507', - "DiacriticalAcute;": '\U000000B4', - "DiacriticalDot;": '\U000002D9', - "DiacriticalDoubleAcute;": '\U000002DD', - "DiacriticalGrave;": '\U00000060', - "DiacriticalTilde;": '\U000002DC', - "Diamond;": '\U000022C4', - "DifferentialD;": '\U00002146', - "Dopf;": '\U0001D53B', - "Dot;": '\U000000A8', - "DotDot;": '\U000020DC', - "DotEqual;": '\U00002250', - "DoubleContourIntegral;": '\U0000222F', - "DoubleDot;": '\U000000A8', - "DoubleDownArrow;": '\U000021D3', - "DoubleLeftArrow;": '\U000021D0', - "DoubleLeftRightArrow;": '\U000021D4', - "DoubleLeftTee;": '\U00002AE4', - "DoubleLongLeftArrow;": '\U000027F8', - "DoubleLongLeftRightArrow;": '\U000027FA', - "DoubleLongRightArrow;": '\U000027F9', - "DoubleRightArrow;": '\U000021D2', - "DoubleRightTee;": '\U000022A8', - "DoubleUpArrow;": '\U000021D1', - "DoubleUpDownArrow;": '\U000021D5', - "DoubleVerticalBar;": '\U00002225', - "DownArrow;": '\U00002193', - "DownArrowBar;": '\U00002913', - "DownArrowUpArrow;": '\U000021F5', - "DownBreve;": '\U00000311', - "DownLeftRightVector;": '\U00002950', - "DownLeftTeeVector;": '\U0000295E', - "DownLeftVector;": '\U000021BD', - "DownLeftVectorBar;": '\U00002956', - "DownRightTeeVector;": '\U0000295F', - "DownRightVector;": '\U000021C1', - "DownRightVectorBar;": '\U00002957', - "DownTee;": '\U000022A4', - "DownTeeArrow;": '\U000021A7', - "Downarrow;": '\U000021D3', - "Dscr;": '\U0001D49F', - "Dstrok;": '\U00000110', - "ENG;": '\U0000014A', - "ETH;": '\U000000D0', - "Eacute;": '\U000000C9', - "Ecaron;": '\U0000011A', - "Ecirc;": '\U000000CA', - "Ecy;": '\U0000042D', - "Edot;": '\U00000116', - "Efr;": '\U0001D508', - "Egrave;": '\U000000C8', - "Element;": '\U00002208', - "Emacr;": '\U00000112', - "EmptySmallSquare;": '\U000025FB', - "EmptyVerySmallSquare;": '\U000025AB', - "Eogon;": '\U00000118', - "Eopf;": '\U0001D53C', - "Epsilon;": '\U00000395', - "Equal;": '\U00002A75', - "EqualTilde;": '\U00002242', - "Equilibrium;": '\U000021CC', - "Escr;": '\U00002130', - "Esim;": '\U00002A73', - "Eta;": '\U00000397', - "Euml;": '\U000000CB', - "Exists;": '\U00002203', - "ExponentialE;": '\U00002147', - "Fcy;": '\U00000424', - "Ffr;": '\U0001D509', - "FilledSmallSquare;": '\U000025FC', - "FilledVerySmallSquare;": '\U000025AA', - "Fopf;": '\U0001D53D', - "ForAll;": '\U00002200', - "Fouriertrf;": '\U00002131', - "Fscr;": '\U00002131', - "GJcy;": '\U00000403', - "GT;": '\U0000003E', - "Gamma;": '\U00000393', - "Gammad;": '\U000003DC', - "Gbreve;": '\U0000011E', - "Gcedil;": '\U00000122', - "Gcirc;": '\U0000011C', - "Gcy;": '\U00000413', - "Gdot;": '\U00000120', - "Gfr;": '\U0001D50A', - "Gg;": '\U000022D9', - "Gopf;": '\U0001D53E', - "GreaterEqual;": '\U00002265', - "GreaterEqualLess;": '\U000022DB', - "GreaterFullEqual;": '\U00002267', - "GreaterGreater;": '\U00002AA2', - "GreaterLess;": '\U00002277', - "GreaterSlantEqual;": '\U00002A7E', - "GreaterTilde;": '\U00002273', - "Gscr;": '\U0001D4A2', - "Gt;": '\U0000226B', - "HARDcy;": '\U0000042A', - "Hacek;": '\U000002C7', - "Hat;": '\U0000005E', - "Hcirc;": '\U00000124', - "Hfr;": '\U0000210C', - "HilbertSpace;": '\U0000210B', - "Hopf;": '\U0000210D', - "HorizontalLine;": '\U00002500', - "Hscr;": '\U0000210B', - "Hstrok;": '\U00000126', - "HumpDownHump;": '\U0000224E', - "HumpEqual;": '\U0000224F', - "IEcy;": '\U00000415', - "IJlig;": '\U00000132', - "IOcy;": '\U00000401', - "Iacute;": '\U000000CD', - "Icirc;": '\U000000CE', - "Icy;": '\U00000418', - "Idot;": '\U00000130', - "Ifr;": '\U00002111', - "Igrave;": '\U000000CC', - "Im;": '\U00002111', - "Imacr;": '\U0000012A', - "ImaginaryI;": '\U00002148', - "Implies;": '\U000021D2', - "Int;": '\U0000222C', - "Integral;": '\U0000222B', - "Intersection;": '\U000022C2', - "InvisibleComma;": '\U00002063', - "InvisibleTimes;": '\U00002062', - "Iogon;": '\U0000012E', - "Iopf;": '\U0001D540', - "Iota;": '\U00000399', - "Iscr;": '\U00002110', - "Itilde;": '\U00000128', - "Iukcy;": '\U00000406', - "Iuml;": '\U000000CF', - "Jcirc;": '\U00000134', - "Jcy;": '\U00000419', - "Jfr;": '\U0001D50D', - "Jopf;": '\U0001D541', - "Jscr;": '\U0001D4A5', - "Jsercy;": '\U00000408', - "Jukcy;": '\U00000404', - "KHcy;": '\U00000425', - "KJcy;": '\U0000040C', - "Kappa;": '\U0000039A', - "Kcedil;": '\U00000136', - "Kcy;": '\U0000041A', - "Kfr;": '\U0001D50E', - "Kopf;": '\U0001D542', - "Kscr;": '\U0001D4A6', - "LJcy;": '\U00000409', - "LT;": '\U0000003C', - "Lacute;": '\U00000139', - "Lambda;": '\U0000039B', - "Lang;": '\U000027EA', - "Laplacetrf;": '\U00002112', - "Larr;": '\U0000219E', - "Lcaron;": '\U0000013D', - "Lcedil;": '\U0000013B', - "Lcy;": '\U0000041B', - "LeftAngleBracket;": '\U000027E8', - "LeftArrow;": '\U00002190', - "LeftArrowBar;": '\U000021E4', - "LeftArrowRightArrow;": '\U000021C6', - "LeftCeiling;": '\U00002308', - "LeftDoubleBracket;": '\U000027E6', - "LeftDownTeeVector;": '\U00002961', - "LeftDownVector;": '\U000021C3', - "LeftDownVectorBar;": '\U00002959', - "LeftFloor;": '\U0000230A', - "LeftRightArrow;": '\U00002194', - "LeftRightVector;": '\U0000294E', - "LeftTee;": '\U000022A3', - "LeftTeeArrow;": '\U000021A4', - "LeftTeeVector;": '\U0000295A', - "LeftTriangle;": '\U000022B2', - "LeftTriangleBar;": '\U000029CF', - "LeftTriangleEqual;": '\U000022B4', - "LeftUpDownVector;": '\U00002951', - "LeftUpTeeVector;": '\U00002960', - "LeftUpVector;": '\U000021BF', - "LeftUpVectorBar;": '\U00002958', - "LeftVector;": '\U000021BC', - "LeftVectorBar;": '\U00002952', - "Leftarrow;": '\U000021D0', - "Leftrightarrow;": '\U000021D4', - "LessEqualGreater;": '\U000022DA', - "LessFullEqual;": '\U00002266', - "LessGreater;": '\U00002276', - "LessLess;": '\U00002AA1', - "LessSlantEqual;": '\U00002A7D', - "LessTilde;": '\U00002272', - "Lfr;": '\U0001D50F', - "Ll;": '\U000022D8', - "Lleftarrow;": '\U000021DA', - "Lmidot;": '\U0000013F', - "LongLeftArrow;": '\U000027F5', - "LongLeftRightArrow;": '\U000027F7', - "LongRightArrow;": '\U000027F6', - "Longleftarrow;": '\U000027F8', - "Longleftrightarrow;": '\U000027FA', - "Longrightarrow;": '\U000027F9', - "Lopf;": '\U0001D543', - "LowerLeftArrow;": '\U00002199', - "LowerRightArrow;": '\U00002198', - "Lscr;": '\U00002112', - "Lsh;": '\U000021B0', - "Lstrok;": '\U00000141', - "Lt;": '\U0000226A', - "Map;": '\U00002905', - "Mcy;": '\U0000041C', - "MediumSpace;": '\U0000205F', - "Mellintrf;": '\U00002133', - "Mfr;": '\U0001D510', - "MinusPlus;": '\U00002213', - "Mopf;": '\U0001D544', - "Mscr;": '\U00002133', - "Mu;": '\U0000039C', - "NJcy;": '\U0000040A', - "Nacute;": '\U00000143', - "Ncaron;": '\U00000147', - "Ncedil;": '\U00000145', - "Ncy;": '\U0000041D', - "NegativeMediumSpace;": '\U0000200B', - "NegativeThickSpace;": '\U0000200B', - "NegativeThinSpace;": '\U0000200B', - "NegativeVeryThinSpace;": '\U0000200B', - "NestedGreaterGreater;": '\U0000226B', - "NestedLessLess;": '\U0000226A', - "NewLine;": '\U0000000A', - "Nfr;": '\U0001D511', - "NoBreak;": '\U00002060', - "NonBreakingSpace;": '\U000000A0', - "Nopf;": '\U00002115', - "Not;": '\U00002AEC', - "NotCongruent;": '\U00002262', - "NotCupCap;": '\U0000226D', - "NotDoubleVerticalBar;": '\U00002226', - "NotElement;": '\U00002209', - "NotEqual;": '\U00002260', - "NotExists;": '\U00002204', - "NotGreater;": '\U0000226F', - "NotGreaterEqual;": '\U00002271', - "NotGreaterLess;": '\U00002279', - "NotGreaterTilde;": '\U00002275', - "NotLeftTriangle;": '\U000022EA', - "NotLeftTriangleEqual;": '\U000022EC', - "NotLess;": '\U0000226E', - "NotLessEqual;": '\U00002270', - "NotLessGreater;": '\U00002278', - "NotLessTilde;": '\U00002274', - "NotPrecedes;": '\U00002280', - "NotPrecedesSlantEqual;": '\U000022E0', - "NotReverseElement;": '\U0000220C', - "NotRightTriangle;": '\U000022EB', - "NotRightTriangleEqual;": '\U000022ED', - "NotSquareSubsetEqual;": '\U000022E2', - "NotSquareSupersetEqual;": '\U000022E3', - "NotSubsetEqual;": '\U00002288', - "NotSucceeds;": '\U00002281', - "NotSucceedsSlantEqual;": '\U000022E1', - "NotSupersetEqual;": '\U00002289', - "NotTilde;": '\U00002241', - "NotTildeEqual;": '\U00002244', - "NotTildeFullEqual;": '\U00002247', - "NotTildeTilde;": '\U00002249', - "NotVerticalBar;": '\U00002224', - "Nscr;": '\U0001D4A9', - "Ntilde;": '\U000000D1', - "Nu;": '\U0000039D', - "OElig;": '\U00000152', - "Oacute;": '\U000000D3', - "Ocirc;": '\U000000D4', - "Ocy;": '\U0000041E', - "Odblac;": '\U00000150', - "Ofr;": '\U0001D512', - "Ograve;": '\U000000D2', - "Omacr;": '\U0000014C', - "Omega;": '\U000003A9', - "Omicron;": '\U0000039F', - "Oopf;": '\U0001D546', - "OpenCurlyDoubleQuote;": '\U0000201C', - "OpenCurlyQuote;": '\U00002018', - "Or;": '\U00002A54', - "Oscr;": '\U0001D4AA', - "Oslash;": '\U000000D8', - "Otilde;": '\U000000D5', - "Otimes;": '\U00002A37', - "Ouml;": '\U000000D6', - "OverBar;": '\U0000203E', - "OverBrace;": '\U000023DE', - "OverBracket;": '\U000023B4', - "OverParenthesis;": '\U000023DC', - "PartialD;": '\U00002202', - "Pcy;": '\U0000041F', - "Pfr;": '\U0001D513', - "Phi;": '\U000003A6', - "Pi;": '\U000003A0', - "PlusMinus;": '\U000000B1', - "Poincareplane;": '\U0000210C', - "Popf;": '\U00002119', - "Pr;": '\U00002ABB', - "Precedes;": '\U0000227A', - "PrecedesEqual;": '\U00002AAF', - "PrecedesSlantEqual;": '\U0000227C', - "PrecedesTilde;": '\U0000227E', - "Prime;": '\U00002033', - "Product;": '\U0000220F', - "Proportion;": '\U00002237', - "Proportional;": '\U0000221D', - "Pscr;": '\U0001D4AB', - "Psi;": '\U000003A8', - "QUOT;": '\U00000022', - "Qfr;": '\U0001D514', - "Qopf;": '\U0000211A', - "Qscr;": '\U0001D4AC', - "RBarr;": '\U00002910', - "REG;": '\U000000AE', - "Racute;": '\U00000154', - "Rang;": '\U000027EB', - "Rarr;": '\U000021A0', - "Rarrtl;": '\U00002916', - "Rcaron;": '\U00000158', - "Rcedil;": '\U00000156', - "Rcy;": '\U00000420', - "Re;": '\U0000211C', - "ReverseElement;": '\U0000220B', - "ReverseEquilibrium;": '\U000021CB', - "ReverseUpEquilibrium;": '\U0000296F', - "Rfr;": '\U0000211C', - "Rho;": '\U000003A1', - "RightAngleBracket;": '\U000027E9', - "RightArrow;": '\U00002192', - "RightArrowBar;": '\U000021E5', - "RightArrowLeftArrow;": '\U000021C4', - "RightCeiling;": '\U00002309', - "RightDoubleBracket;": '\U000027E7', - "RightDownTeeVector;": '\U0000295D', - "RightDownVector;": '\U000021C2', - "RightDownVectorBar;": '\U00002955', - "RightFloor;": '\U0000230B', - "RightTee;": '\U000022A2', - "RightTeeArrow;": '\U000021A6', - "RightTeeVector;": '\U0000295B', - "RightTriangle;": '\U000022B3', - "RightTriangleBar;": '\U000029D0', - "RightTriangleEqual;": '\U000022B5', - "RightUpDownVector;": '\U0000294F', - "RightUpTeeVector;": '\U0000295C', - "RightUpVector;": '\U000021BE', - "RightUpVectorBar;": '\U00002954', - "RightVector;": '\U000021C0', - "RightVectorBar;": '\U00002953', - "Rightarrow;": '\U000021D2', - "Ropf;": '\U0000211D', - "RoundImplies;": '\U00002970', - "Rrightarrow;": '\U000021DB', - "Rscr;": '\U0000211B', - "Rsh;": '\U000021B1', - "RuleDelayed;": '\U000029F4', - "SHCHcy;": '\U00000429', - "SHcy;": '\U00000428', - "SOFTcy;": '\U0000042C', - "Sacute;": '\U0000015A', - "Sc;": '\U00002ABC', - "Scaron;": '\U00000160', - "Scedil;": '\U0000015E', - "Scirc;": '\U0000015C', - "Scy;": '\U00000421', - "Sfr;": '\U0001D516', - "ShortDownArrow;": '\U00002193', - "ShortLeftArrow;": '\U00002190', - "ShortRightArrow;": '\U00002192', - "ShortUpArrow;": '\U00002191', - "Sigma;": '\U000003A3', - "SmallCircle;": '\U00002218', - "Sopf;": '\U0001D54A', - "Sqrt;": '\U0000221A', - "Square;": '\U000025A1', - "SquareIntersection;": '\U00002293', - "SquareSubset;": '\U0000228F', - "SquareSubsetEqual;": '\U00002291', - "SquareSuperset;": '\U00002290', - "SquareSupersetEqual;": '\U00002292', - "SquareUnion;": '\U00002294', - "Sscr;": '\U0001D4AE', - "Star;": '\U000022C6', - "Sub;": '\U000022D0', - "Subset;": '\U000022D0', - "SubsetEqual;": '\U00002286', - "Succeeds;": '\U0000227B', - "SucceedsEqual;": '\U00002AB0', - "SucceedsSlantEqual;": '\U0000227D', - "SucceedsTilde;": '\U0000227F', - "SuchThat;": '\U0000220B', - "Sum;": '\U00002211', - "Sup;": '\U000022D1', - "Superset;": '\U00002283', - "SupersetEqual;": '\U00002287', - "Supset;": '\U000022D1', - "THORN;": '\U000000DE', - "TRADE;": '\U00002122', - "TSHcy;": '\U0000040B', - "TScy;": '\U00000426', - "Tab;": '\U00000009', - "Tau;": '\U000003A4', - "Tcaron;": '\U00000164', - "Tcedil;": '\U00000162', - "Tcy;": '\U00000422', - "Tfr;": '\U0001D517', - "Therefore;": '\U00002234', - "Theta;": '\U00000398', - "ThinSpace;": '\U00002009', - "Tilde;": '\U0000223C', - "TildeEqual;": '\U00002243', - "TildeFullEqual;": '\U00002245', - "TildeTilde;": '\U00002248', - "Topf;": '\U0001D54B', - "TripleDot;": '\U000020DB', - "Tscr;": '\U0001D4AF', - "Tstrok;": '\U00000166', - "Uacute;": '\U000000DA', - "Uarr;": '\U0000219F', - "Uarrocir;": '\U00002949', - "Ubrcy;": '\U0000040E', - "Ubreve;": '\U0000016C', - "Ucirc;": '\U000000DB', - "Ucy;": '\U00000423', - "Udblac;": '\U00000170', - "Ufr;": '\U0001D518', - "Ugrave;": '\U000000D9', - "Umacr;": '\U0000016A', - "UnderBar;": '\U0000005F', - "UnderBrace;": '\U000023DF', - "UnderBracket;": '\U000023B5', - "UnderParenthesis;": '\U000023DD', - "Union;": '\U000022C3', - "UnionPlus;": '\U0000228E', - "Uogon;": '\U00000172', - "Uopf;": '\U0001D54C', - "UpArrow;": '\U00002191', - "UpArrowBar;": '\U00002912', - "UpArrowDownArrow;": '\U000021C5', - "UpDownArrow;": '\U00002195', - "UpEquilibrium;": '\U0000296E', - "UpTee;": '\U000022A5', - "UpTeeArrow;": '\U000021A5', - "Uparrow;": '\U000021D1', - "Updownarrow;": '\U000021D5', - "UpperLeftArrow;": '\U00002196', - "UpperRightArrow;": '\U00002197', - "Upsi;": '\U000003D2', - "Upsilon;": '\U000003A5', - "Uring;": '\U0000016E', - "Uscr;": '\U0001D4B0', - "Utilde;": '\U00000168', - "Uuml;": '\U000000DC', - "VDash;": '\U000022AB', - "Vbar;": '\U00002AEB', - "Vcy;": '\U00000412', - "Vdash;": '\U000022A9', - "Vdashl;": '\U00002AE6', - "Vee;": '\U000022C1', - "Verbar;": '\U00002016', - "Vert;": '\U00002016', - "VerticalBar;": '\U00002223', - "VerticalLine;": '\U0000007C', - "VerticalSeparator;": '\U00002758', - "VerticalTilde;": '\U00002240', - "VeryThinSpace;": '\U0000200A', - "Vfr;": '\U0001D519', - "Vopf;": '\U0001D54D', - "Vscr;": '\U0001D4B1', - "Vvdash;": '\U000022AA', - "Wcirc;": '\U00000174', - "Wedge;": '\U000022C0', - "Wfr;": '\U0001D51A', - "Wopf;": '\U0001D54E', - "Wscr;": '\U0001D4B2', - "Xfr;": '\U0001D51B', - "Xi;": '\U0000039E', - "Xopf;": '\U0001D54F', - "Xscr;": '\U0001D4B3', - "YAcy;": '\U0000042F', - "YIcy;": '\U00000407', - "YUcy;": '\U0000042E', - "Yacute;": '\U000000DD', - "Ycirc;": '\U00000176', - "Ycy;": '\U0000042B', - "Yfr;": '\U0001D51C', - "Yopf;": '\U0001D550', - "Yscr;": '\U0001D4B4', - "Yuml;": '\U00000178', - "ZHcy;": '\U00000416', - "Zacute;": '\U00000179', - "Zcaron;": '\U0000017D', - "Zcy;": '\U00000417', - "Zdot;": '\U0000017B', - "ZeroWidthSpace;": '\U0000200B', - "Zeta;": '\U00000396', - "Zfr;": '\U00002128', - "Zopf;": '\U00002124', - "Zscr;": '\U0001D4B5', - "aacute;": '\U000000E1', - "abreve;": '\U00000103', - "ac;": '\U0000223E', - "acd;": '\U0000223F', - "acirc;": '\U000000E2', - "acute;": '\U000000B4', - "acy;": '\U00000430', - "aelig;": '\U000000E6', - "af;": '\U00002061', - "afr;": '\U0001D51E', - "agrave;": '\U000000E0', - "alefsym;": '\U00002135', - "aleph;": '\U00002135', - "alpha;": '\U000003B1', - "amacr;": '\U00000101', - "amalg;": '\U00002A3F', - "amp;": '\U00000026', - "and;": '\U00002227', - "andand;": '\U00002A55', - "andd;": '\U00002A5C', - "andslope;": '\U00002A58', - "andv;": '\U00002A5A', - "ang;": '\U00002220', - "ange;": '\U000029A4', - "angle;": '\U00002220', - "angmsd;": '\U00002221', - "angmsdaa;": '\U000029A8', - "angmsdab;": '\U000029A9', - "angmsdac;": '\U000029AA', - "angmsdad;": '\U000029AB', - "angmsdae;": '\U000029AC', - "angmsdaf;": '\U000029AD', - "angmsdag;": '\U000029AE', - "angmsdah;": '\U000029AF', - "angrt;": '\U0000221F', - "angrtvb;": '\U000022BE', - "angrtvbd;": '\U0000299D', - "angsph;": '\U00002222', - "angst;": '\U000000C5', - "angzarr;": '\U0000237C', - "aogon;": '\U00000105', - "aopf;": '\U0001D552', - "ap;": '\U00002248', - "apE;": '\U00002A70', - "apacir;": '\U00002A6F', - "ape;": '\U0000224A', - "apid;": '\U0000224B', - "apos;": '\U00000027', - "approx;": '\U00002248', - "approxeq;": '\U0000224A', - "aring;": '\U000000E5', - "ascr;": '\U0001D4B6', - "ast;": '\U0000002A', - "asymp;": '\U00002248', - "asympeq;": '\U0000224D', - "atilde;": '\U000000E3', - "auml;": '\U000000E4', - "awconint;": '\U00002233', - "awint;": '\U00002A11', - "bNot;": '\U00002AED', - "backcong;": '\U0000224C', - "backepsilon;": '\U000003F6', - "backprime;": '\U00002035', - "backsim;": '\U0000223D', - "backsimeq;": '\U000022CD', - "barvee;": '\U000022BD', - "barwed;": '\U00002305', - "barwedge;": '\U00002305', - "bbrk;": '\U000023B5', - "bbrktbrk;": '\U000023B6', - "bcong;": '\U0000224C', - "bcy;": '\U00000431', - "bdquo;": '\U0000201E', - "becaus;": '\U00002235', - "because;": '\U00002235', - "bemptyv;": '\U000029B0', - "bepsi;": '\U000003F6', - "bernou;": '\U0000212C', - "beta;": '\U000003B2', - "beth;": '\U00002136', - "between;": '\U0000226C', - "bfr;": '\U0001D51F', - "bigcap;": '\U000022C2', - "bigcirc;": '\U000025EF', - "bigcup;": '\U000022C3', - "bigodot;": '\U00002A00', - "bigoplus;": '\U00002A01', - "bigotimes;": '\U00002A02', - "bigsqcup;": '\U00002A06', - "bigstar;": '\U00002605', - "bigtriangledown;": '\U000025BD', - "bigtriangleup;": '\U000025B3', - "biguplus;": '\U00002A04', - "bigvee;": '\U000022C1', - "bigwedge;": '\U000022C0', - "bkarow;": '\U0000290D', - "blacklozenge;": '\U000029EB', - "blacksquare;": '\U000025AA', - "blacktriangle;": '\U000025B4', - "blacktriangledown;": '\U000025BE', - "blacktriangleleft;": '\U000025C2', - "blacktriangleright;": '\U000025B8', - "blank;": '\U00002423', - "blk12;": '\U00002592', - "blk14;": '\U00002591', - "blk34;": '\U00002593', - "block;": '\U00002588', - "bnot;": '\U00002310', - "bopf;": '\U0001D553', - "bot;": '\U000022A5', - "bottom;": '\U000022A5', - "bowtie;": '\U000022C8', - "boxDL;": '\U00002557', - "boxDR;": '\U00002554', - "boxDl;": '\U00002556', - "boxDr;": '\U00002553', - "boxH;": '\U00002550', - "boxHD;": '\U00002566', - "boxHU;": '\U00002569', - "boxHd;": '\U00002564', - "boxHu;": '\U00002567', - "boxUL;": '\U0000255D', - "boxUR;": '\U0000255A', - "boxUl;": '\U0000255C', - "boxUr;": '\U00002559', - "boxV;": '\U00002551', - "boxVH;": '\U0000256C', - "boxVL;": '\U00002563', - "boxVR;": '\U00002560', - "boxVh;": '\U0000256B', - "boxVl;": '\U00002562', - "boxVr;": '\U0000255F', - "boxbox;": '\U000029C9', - "boxdL;": '\U00002555', - "boxdR;": '\U00002552', - "boxdl;": '\U00002510', - "boxdr;": '\U0000250C', - "boxh;": '\U00002500', - "boxhD;": '\U00002565', - "boxhU;": '\U00002568', - "boxhd;": '\U0000252C', - "boxhu;": '\U00002534', - "boxminus;": '\U0000229F', - "boxplus;": '\U0000229E', - "boxtimes;": '\U000022A0', - "boxuL;": '\U0000255B', - "boxuR;": '\U00002558', - "boxul;": '\U00002518', - "boxur;": '\U00002514', - "boxv;": '\U00002502', - "boxvH;": '\U0000256A', - "boxvL;": '\U00002561', - "boxvR;": '\U0000255E', - "boxvh;": '\U0000253C', - "boxvl;": '\U00002524', - "boxvr;": '\U0000251C', - "bprime;": '\U00002035', - "breve;": '\U000002D8', - "brvbar;": '\U000000A6', - "bscr;": '\U0001D4B7', - "bsemi;": '\U0000204F', - "bsim;": '\U0000223D', - "bsime;": '\U000022CD', - "bsol;": '\U0000005C', - "bsolb;": '\U000029C5', - "bsolhsub;": '\U000027C8', - "bull;": '\U00002022', - "bullet;": '\U00002022', - "bump;": '\U0000224E', - "bumpE;": '\U00002AAE', - "bumpe;": '\U0000224F', - "bumpeq;": '\U0000224F', - "cacute;": '\U00000107', - "cap;": '\U00002229', - "capand;": '\U00002A44', - "capbrcup;": '\U00002A49', - "capcap;": '\U00002A4B', - "capcup;": '\U00002A47', - "capdot;": '\U00002A40', - "caret;": '\U00002041', - "caron;": '\U000002C7', - "ccaps;": '\U00002A4D', - "ccaron;": '\U0000010D', - "ccedil;": '\U000000E7', - "ccirc;": '\U00000109', - "ccups;": '\U00002A4C', - "ccupssm;": '\U00002A50', - "cdot;": '\U0000010B', - "cedil;": '\U000000B8', - "cemptyv;": '\U000029B2', - "cent;": '\U000000A2', - "centerdot;": '\U000000B7', - "cfr;": '\U0001D520', - "chcy;": '\U00000447', - "check;": '\U00002713', - "checkmark;": '\U00002713', - "chi;": '\U000003C7', - "cir;": '\U000025CB', - "cirE;": '\U000029C3', - "circ;": '\U000002C6', - "circeq;": '\U00002257', - "circlearrowleft;": '\U000021BA', - "circlearrowright;": '\U000021BB', - "circledR;": '\U000000AE', - "circledS;": '\U000024C8', - "circledast;": '\U0000229B', - "circledcirc;": '\U0000229A', - "circleddash;": '\U0000229D', - "cire;": '\U00002257', - "cirfnint;": '\U00002A10', - "cirmid;": '\U00002AEF', - "cirscir;": '\U000029C2', - "clubs;": '\U00002663', - "clubsuit;": '\U00002663', - "colon;": '\U0000003A', - "colone;": '\U00002254', - "coloneq;": '\U00002254', - "comma;": '\U0000002C', - "commat;": '\U00000040', - "comp;": '\U00002201', - "compfn;": '\U00002218', - "complement;": '\U00002201', - "complexes;": '\U00002102', - "cong;": '\U00002245', - "congdot;": '\U00002A6D', - "conint;": '\U0000222E', - "copf;": '\U0001D554', - "coprod;": '\U00002210', - "copy;": '\U000000A9', - "copysr;": '\U00002117', - "crarr;": '\U000021B5', - "cross;": '\U00002717', - "cscr;": '\U0001D4B8', - "csub;": '\U00002ACF', - "csube;": '\U00002AD1', - "csup;": '\U00002AD0', - "csupe;": '\U00002AD2', - "ctdot;": '\U000022EF', - "cudarrl;": '\U00002938', - "cudarrr;": '\U00002935', - "cuepr;": '\U000022DE', - "cuesc;": '\U000022DF', - "cularr;": '\U000021B6', - "cularrp;": '\U0000293D', - "cup;": '\U0000222A', - "cupbrcap;": '\U00002A48', - "cupcap;": '\U00002A46', - "cupcup;": '\U00002A4A', - "cupdot;": '\U0000228D', - "cupor;": '\U00002A45', - "curarr;": '\U000021B7', - "curarrm;": '\U0000293C', - "curlyeqprec;": '\U000022DE', - "curlyeqsucc;": '\U000022DF', - "curlyvee;": '\U000022CE', - "curlywedge;": '\U000022CF', - "curren;": '\U000000A4', - "curvearrowleft;": '\U000021B6', - "curvearrowright;": '\U000021B7', - "cuvee;": '\U000022CE', - "cuwed;": '\U000022CF', - "cwconint;": '\U00002232', - "cwint;": '\U00002231', - "cylcty;": '\U0000232D', - "dArr;": '\U000021D3', - "dHar;": '\U00002965', - "dagger;": '\U00002020', - "daleth;": '\U00002138', - "darr;": '\U00002193', - "dash;": '\U00002010', - "dashv;": '\U000022A3', - "dbkarow;": '\U0000290F', - "dblac;": '\U000002DD', - "dcaron;": '\U0000010F', - "dcy;": '\U00000434', - "dd;": '\U00002146', - "ddagger;": '\U00002021', - "ddarr;": '\U000021CA', - "ddotseq;": '\U00002A77', - "deg;": '\U000000B0', - "delta;": '\U000003B4', - "demptyv;": '\U000029B1', - "dfisht;": '\U0000297F', - "dfr;": '\U0001D521', - "dharl;": '\U000021C3', - "dharr;": '\U000021C2', - "diam;": '\U000022C4', - "diamond;": '\U000022C4', - "diamondsuit;": '\U00002666', - "diams;": '\U00002666', - "die;": '\U000000A8', - "digamma;": '\U000003DD', - "disin;": '\U000022F2', - "div;": '\U000000F7', - "divide;": '\U000000F7', - "divideontimes;": '\U000022C7', - "divonx;": '\U000022C7', - "djcy;": '\U00000452', - "dlcorn;": '\U0000231E', - "dlcrop;": '\U0000230D', - "dollar;": '\U00000024', - "dopf;": '\U0001D555', - "dot;": '\U000002D9', - "doteq;": '\U00002250', - "doteqdot;": '\U00002251', - "dotminus;": '\U00002238', - "dotplus;": '\U00002214', - "dotsquare;": '\U000022A1', - "doublebarwedge;": '\U00002306', - "downarrow;": '\U00002193', - "downdownarrows;": '\U000021CA', - "downharpoonleft;": '\U000021C3', - "downharpoonright;": '\U000021C2', - "drbkarow;": '\U00002910', - "drcorn;": '\U0000231F', - "drcrop;": '\U0000230C', - "dscr;": '\U0001D4B9', - "dscy;": '\U00000455', - "dsol;": '\U000029F6', - "dstrok;": '\U00000111', - "dtdot;": '\U000022F1', - "dtri;": '\U000025BF', - "dtrif;": '\U000025BE', - "duarr;": '\U000021F5', - "duhar;": '\U0000296F', - "dwangle;": '\U000029A6', - "dzcy;": '\U0000045F', - "dzigrarr;": '\U000027FF', - "eDDot;": '\U00002A77', - "eDot;": '\U00002251', - "eacute;": '\U000000E9', - "easter;": '\U00002A6E', - "ecaron;": '\U0000011B', - "ecir;": '\U00002256', - "ecirc;": '\U000000EA', - "ecolon;": '\U00002255', - "ecy;": '\U0000044D', - "edot;": '\U00000117', - "ee;": '\U00002147', - "efDot;": '\U00002252', - "efr;": '\U0001D522', - "eg;": '\U00002A9A', - "egrave;": '\U000000E8', - "egs;": '\U00002A96', - "egsdot;": '\U00002A98', - "el;": '\U00002A99', - "elinters;": '\U000023E7', - "ell;": '\U00002113', - "els;": '\U00002A95', - "elsdot;": '\U00002A97', - "emacr;": '\U00000113', - "empty;": '\U00002205', - "emptyset;": '\U00002205', - "emptyv;": '\U00002205', - "emsp;": '\U00002003', - "emsp13;": '\U00002004', - "emsp14;": '\U00002005', - "eng;": '\U0000014B', - "ensp;": '\U00002002', - "eogon;": '\U00000119', - "eopf;": '\U0001D556', - "epar;": '\U000022D5', - "eparsl;": '\U000029E3', - "eplus;": '\U00002A71', - "epsi;": '\U000003B5', - "epsilon;": '\U000003B5', - "epsiv;": '\U000003F5', - "eqcirc;": '\U00002256', - "eqcolon;": '\U00002255', - "eqsim;": '\U00002242', - "eqslantgtr;": '\U00002A96', - "eqslantless;": '\U00002A95', - "equals;": '\U0000003D', - "equest;": '\U0000225F', - "equiv;": '\U00002261', - "equivDD;": '\U00002A78', - "eqvparsl;": '\U000029E5', - "erDot;": '\U00002253', - "erarr;": '\U00002971', - "escr;": '\U0000212F', - "esdot;": '\U00002250', - "esim;": '\U00002242', - "eta;": '\U000003B7', - "eth;": '\U000000F0', - "euml;": '\U000000EB', - "euro;": '\U000020AC', - "excl;": '\U00000021', - "exist;": '\U00002203', - "expectation;": '\U00002130', - "exponentiale;": '\U00002147', - "fallingdotseq;": '\U00002252', - "fcy;": '\U00000444', - "female;": '\U00002640', - "ffilig;": '\U0000FB03', - "fflig;": '\U0000FB00', - "ffllig;": '\U0000FB04', - "ffr;": '\U0001D523', - "filig;": '\U0000FB01', - "flat;": '\U0000266D', - "fllig;": '\U0000FB02', - "fltns;": '\U000025B1', - "fnof;": '\U00000192', - "fopf;": '\U0001D557', - "forall;": '\U00002200', - "fork;": '\U000022D4', - "forkv;": '\U00002AD9', - "fpartint;": '\U00002A0D', - "frac12;": '\U000000BD', - "frac13;": '\U00002153', - "frac14;": '\U000000BC', - "frac15;": '\U00002155', - "frac16;": '\U00002159', - "frac18;": '\U0000215B', - "frac23;": '\U00002154', - "frac25;": '\U00002156', - "frac34;": '\U000000BE', - "frac35;": '\U00002157', - "frac38;": '\U0000215C', - "frac45;": '\U00002158', - "frac56;": '\U0000215A', - "frac58;": '\U0000215D', - "frac78;": '\U0000215E', - "frasl;": '\U00002044', - "frown;": '\U00002322', - "fscr;": '\U0001D4BB', - "gE;": '\U00002267', - "gEl;": '\U00002A8C', - "gacute;": '\U000001F5', - "gamma;": '\U000003B3', - "gammad;": '\U000003DD', - "gap;": '\U00002A86', - "gbreve;": '\U0000011F', - "gcirc;": '\U0000011D', - "gcy;": '\U00000433', - "gdot;": '\U00000121', - "ge;": '\U00002265', - "gel;": '\U000022DB', - "geq;": '\U00002265', - "geqq;": '\U00002267', - "geqslant;": '\U00002A7E', - "ges;": '\U00002A7E', - "gescc;": '\U00002AA9', - "gesdot;": '\U00002A80', - "gesdoto;": '\U00002A82', - "gesdotol;": '\U00002A84', - "gesles;": '\U00002A94', - "gfr;": '\U0001D524', - "gg;": '\U0000226B', - "ggg;": '\U000022D9', - "gimel;": '\U00002137', - "gjcy;": '\U00000453', - "gl;": '\U00002277', - "glE;": '\U00002A92', - "gla;": '\U00002AA5', - "glj;": '\U00002AA4', - "gnE;": '\U00002269', - "gnap;": '\U00002A8A', - "gnapprox;": '\U00002A8A', - "gne;": '\U00002A88', - "gneq;": '\U00002A88', - "gneqq;": '\U00002269', - "gnsim;": '\U000022E7', - "gopf;": '\U0001D558', - "grave;": '\U00000060', - "gscr;": '\U0000210A', - "gsim;": '\U00002273', - "gsime;": '\U00002A8E', - "gsiml;": '\U00002A90', - "gt;": '\U0000003E', - "gtcc;": '\U00002AA7', - "gtcir;": '\U00002A7A', - "gtdot;": '\U000022D7', - "gtlPar;": '\U00002995', - "gtquest;": '\U00002A7C', - "gtrapprox;": '\U00002A86', - "gtrarr;": '\U00002978', - "gtrdot;": '\U000022D7', - "gtreqless;": '\U000022DB', - "gtreqqless;": '\U00002A8C', - "gtrless;": '\U00002277', - "gtrsim;": '\U00002273', - "hArr;": '\U000021D4', - "hairsp;": '\U0000200A', - "half;": '\U000000BD', - "hamilt;": '\U0000210B', - "hardcy;": '\U0000044A', - "harr;": '\U00002194', - "harrcir;": '\U00002948', - "harrw;": '\U000021AD', - "hbar;": '\U0000210F', - "hcirc;": '\U00000125', - "hearts;": '\U00002665', - "heartsuit;": '\U00002665', - "hellip;": '\U00002026', - "hercon;": '\U000022B9', - "hfr;": '\U0001D525', - "hksearow;": '\U00002925', - "hkswarow;": '\U00002926', - "hoarr;": '\U000021FF', - "homtht;": '\U0000223B', - "hookleftarrow;": '\U000021A9', - "hookrightarrow;": '\U000021AA', - "hopf;": '\U0001D559', - "horbar;": '\U00002015', - "hscr;": '\U0001D4BD', - "hslash;": '\U0000210F', - "hstrok;": '\U00000127', - "hybull;": '\U00002043', - "hyphen;": '\U00002010', - "iacute;": '\U000000ED', - "ic;": '\U00002063', - "icirc;": '\U000000EE', - "icy;": '\U00000438', - "iecy;": '\U00000435', - "iexcl;": '\U000000A1', - "iff;": '\U000021D4', - "ifr;": '\U0001D526', - "igrave;": '\U000000EC', - "ii;": '\U00002148', - "iiiint;": '\U00002A0C', - "iiint;": '\U0000222D', - "iinfin;": '\U000029DC', - "iiota;": '\U00002129', - "ijlig;": '\U00000133', - "imacr;": '\U0000012B', - "image;": '\U00002111', - "imagline;": '\U00002110', - "imagpart;": '\U00002111', - "imath;": '\U00000131', - "imof;": '\U000022B7', - "imped;": '\U000001B5', - "in;": '\U00002208', - "incare;": '\U00002105', - "infin;": '\U0000221E', - "infintie;": '\U000029DD', - "inodot;": '\U00000131', - "int;": '\U0000222B', - "intcal;": '\U000022BA', - "integers;": '\U00002124', - "intercal;": '\U000022BA', - "intlarhk;": '\U00002A17', - "intprod;": '\U00002A3C', - "iocy;": '\U00000451', - "iogon;": '\U0000012F', - "iopf;": '\U0001D55A', - "iota;": '\U000003B9', - "iprod;": '\U00002A3C', - "iquest;": '\U000000BF', - "iscr;": '\U0001D4BE', - "isin;": '\U00002208', - "isinE;": '\U000022F9', - "isindot;": '\U000022F5', - "isins;": '\U000022F4', - "isinsv;": '\U000022F3', - "isinv;": '\U00002208', - "it;": '\U00002062', - "itilde;": '\U00000129', - "iukcy;": '\U00000456', - "iuml;": '\U000000EF', - "jcirc;": '\U00000135', - "jcy;": '\U00000439', - "jfr;": '\U0001D527', - "jmath;": '\U00000237', - "jopf;": '\U0001D55B', - "jscr;": '\U0001D4BF', - "jsercy;": '\U00000458', - "jukcy;": '\U00000454', - "kappa;": '\U000003BA', - "kappav;": '\U000003F0', - "kcedil;": '\U00000137', - "kcy;": '\U0000043A', - "kfr;": '\U0001D528', - "kgreen;": '\U00000138', - "khcy;": '\U00000445', - "kjcy;": '\U0000045C', - "kopf;": '\U0001D55C', - "kscr;": '\U0001D4C0', - "lAarr;": '\U000021DA', - "lArr;": '\U000021D0', - "lAtail;": '\U0000291B', - "lBarr;": '\U0000290E', - "lE;": '\U00002266', - "lEg;": '\U00002A8B', - "lHar;": '\U00002962', - "lacute;": '\U0000013A', - "laemptyv;": '\U000029B4', - "lagran;": '\U00002112', - "lambda;": '\U000003BB', - "lang;": '\U000027E8', - "langd;": '\U00002991', - "langle;": '\U000027E8', - "lap;": '\U00002A85', - "laquo;": '\U000000AB', - "larr;": '\U00002190', - "larrb;": '\U000021E4', - "larrbfs;": '\U0000291F', - "larrfs;": '\U0000291D', - "larrhk;": '\U000021A9', - "larrlp;": '\U000021AB', - "larrpl;": '\U00002939', - "larrsim;": '\U00002973', - "larrtl;": '\U000021A2', - "lat;": '\U00002AAB', - "latail;": '\U00002919', - "late;": '\U00002AAD', - "lbarr;": '\U0000290C', - "lbbrk;": '\U00002772', - "lbrace;": '\U0000007B', - "lbrack;": '\U0000005B', - "lbrke;": '\U0000298B', - "lbrksld;": '\U0000298F', - "lbrkslu;": '\U0000298D', - "lcaron;": '\U0000013E', - "lcedil;": '\U0000013C', - "lceil;": '\U00002308', - "lcub;": '\U0000007B', - "lcy;": '\U0000043B', - "ldca;": '\U00002936', - "ldquo;": '\U0000201C', - "ldquor;": '\U0000201E', - "ldrdhar;": '\U00002967', - "ldrushar;": '\U0000294B', - "ldsh;": '\U000021B2', - "le;": '\U00002264', - "leftarrow;": '\U00002190', - "leftarrowtail;": '\U000021A2', - "leftharpoondown;": '\U000021BD', - "leftharpoonup;": '\U000021BC', - "leftleftarrows;": '\U000021C7', - "leftrightarrow;": '\U00002194', - "leftrightarrows;": '\U000021C6', - "leftrightharpoons;": '\U000021CB', - "leftrightsquigarrow;": '\U000021AD', - "leftthreetimes;": '\U000022CB', - "leg;": '\U000022DA', - "leq;": '\U00002264', - "leqq;": '\U00002266', - "leqslant;": '\U00002A7D', - "les;": '\U00002A7D', - "lescc;": '\U00002AA8', - "lesdot;": '\U00002A7F', - "lesdoto;": '\U00002A81', - "lesdotor;": '\U00002A83', - "lesges;": '\U00002A93', - "lessapprox;": '\U00002A85', - "lessdot;": '\U000022D6', - "lesseqgtr;": '\U000022DA', - "lesseqqgtr;": '\U00002A8B', - "lessgtr;": '\U00002276', - "lesssim;": '\U00002272', - "lfisht;": '\U0000297C', - "lfloor;": '\U0000230A', - "lfr;": '\U0001D529', - "lg;": '\U00002276', - "lgE;": '\U00002A91', - "lhard;": '\U000021BD', - "lharu;": '\U000021BC', - "lharul;": '\U0000296A', - "lhblk;": '\U00002584', - "ljcy;": '\U00000459', - "ll;": '\U0000226A', - "llarr;": '\U000021C7', - "llcorner;": '\U0000231E', - "llhard;": '\U0000296B', - "lltri;": '\U000025FA', - "lmidot;": '\U00000140', - "lmoust;": '\U000023B0', - "lmoustache;": '\U000023B0', - "lnE;": '\U00002268', - "lnap;": '\U00002A89', - "lnapprox;": '\U00002A89', - "lne;": '\U00002A87', - "lneq;": '\U00002A87', - "lneqq;": '\U00002268', - "lnsim;": '\U000022E6', - "loang;": '\U000027EC', - "loarr;": '\U000021FD', - "lobrk;": '\U000027E6', - "longleftarrow;": '\U000027F5', - "longleftrightarrow;": '\U000027F7', - "longmapsto;": '\U000027FC', - "longrightarrow;": '\U000027F6', - "looparrowleft;": '\U000021AB', - "looparrowright;": '\U000021AC', - "lopar;": '\U00002985', - "lopf;": '\U0001D55D', - "loplus;": '\U00002A2D', - "lotimes;": '\U00002A34', - "lowast;": '\U00002217', - "lowbar;": '\U0000005F', - "loz;": '\U000025CA', - "lozenge;": '\U000025CA', - "lozf;": '\U000029EB', - "lpar;": '\U00000028', - "lparlt;": '\U00002993', - "lrarr;": '\U000021C6', - "lrcorner;": '\U0000231F', - "lrhar;": '\U000021CB', - "lrhard;": '\U0000296D', - "lrm;": '\U0000200E', - "lrtri;": '\U000022BF', - "lsaquo;": '\U00002039', - "lscr;": '\U0001D4C1', - "lsh;": '\U000021B0', - "lsim;": '\U00002272', - "lsime;": '\U00002A8D', - "lsimg;": '\U00002A8F', - "lsqb;": '\U0000005B', - "lsquo;": '\U00002018', - "lsquor;": '\U0000201A', - "lstrok;": '\U00000142', - "lt;": '\U0000003C', - "ltcc;": '\U00002AA6', - "ltcir;": '\U00002A79', - "ltdot;": '\U000022D6', - "lthree;": '\U000022CB', - "ltimes;": '\U000022C9', - "ltlarr;": '\U00002976', - "ltquest;": '\U00002A7B', - "ltrPar;": '\U00002996', - "ltri;": '\U000025C3', - "ltrie;": '\U000022B4', - "ltrif;": '\U000025C2', - "lurdshar;": '\U0000294A', - "luruhar;": '\U00002966', - "mDDot;": '\U0000223A', - "macr;": '\U000000AF', - "male;": '\U00002642', - "malt;": '\U00002720', - "maltese;": '\U00002720', - "map;": '\U000021A6', - "mapsto;": '\U000021A6', - "mapstodown;": '\U000021A7', - "mapstoleft;": '\U000021A4', - "mapstoup;": '\U000021A5', - "marker;": '\U000025AE', - "mcomma;": '\U00002A29', - "mcy;": '\U0000043C', - "mdash;": '\U00002014', - "measuredangle;": '\U00002221', - "mfr;": '\U0001D52A', - "mho;": '\U00002127', - "micro;": '\U000000B5', - "mid;": '\U00002223', - "midast;": '\U0000002A', - "midcir;": '\U00002AF0', - "middot;": '\U000000B7', - "minus;": '\U00002212', - "minusb;": '\U0000229F', - "minusd;": '\U00002238', - "minusdu;": '\U00002A2A', - "mlcp;": '\U00002ADB', - "mldr;": '\U00002026', - "mnplus;": '\U00002213', - "models;": '\U000022A7', - "mopf;": '\U0001D55E', - "mp;": '\U00002213', - "mscr;": '\U0001D4C2', - "mstpos;": '\U0000223E', - "mu;": '\U000003BC', - "multimap;": '\U000022B8', - "mumap;": '\U000022B8', - "nLeftarrow;": '\U000021CD', - "nLeftrightarrow;": '\U000021CE', - "nRightarrow;": '\U000021CF', - "nVDash;": '\U000022AF', - "nVdash;": '\U000022AE', - "nabla;": '\U00002207', - "nacute;": '\U00000144', - "nap;": '\U00002249', - "napos;": '\U00000149', - "napprox;": '\U00002249', - "natur;": '\U0000266E', - "natural;": '\U0000266E', - "naturals;": '\U00002115', - "nbsp;": '\U000000A0', - "ncap;": '\U00002A43', - "ncaron;": '\U00000148', - "ncedil;": '\U00000146', - "ncong;": '\U00002247', - "ncup;": '\U00002A42', - "ncy;": '\U0000043D', - "ndash;": '\U00002013', - "ne;": '\U00002260', - "neArr;": '\U000021D7', - "nearhk;": '\U00002924', - "nearr;": '\U00002197', - "nearrow;": '\U00002197', - "nequiv;": '\U00002262', - "nesear;": '\U00002928', - "nexist;": '\U00002204', - "nexists;": '\U00002204', - "nfr;": '\U0001D52B', - "nge;": '\U00002271', - "ngeq;": '\U00002271', - "ngsim;": '\U00002275', - "ngt;": '\U0000226F', - "ngtr;": '\U0000226F', - "nhArr;": '\U000021CE', - "nharr;": '\U000021AE', - "nhpar;": '\U00002AF2', - "ni;": '\U0000220B', - "nis;": '\U000022FC', - "nisd;": '\U000022FA', - "niv;": '\U0000220B', - "njcy;": '\U0000045A', - "nlArr;": '\U000021CD', - "nlarr;": '\U0000219A', - "nldr;": '\U00002025', - "nle;": '\U00002270', - "nleftarrow;": '\U0000219A', - "nleftrightarrow;": '\U000021AE', - "nleq;": '\U00002270', - "nless;": '\U0000226E', - "nlsim;": '\U00002274', - "nlt;": '\U0000226E', - "nltri;": '\U000022EA', - "nltrie;": '\U000022EC', - "nmid;": '\U00002224', - "nopf;": '\U0001D55F', - "not;": '\U000000AC', - "notin;": '\U00002209', - "notinva;": '\U00002209', - "notinvb;": '\U000022F7', - "notinvc;": '\U000022F6', - "notni;": '\U0000220C', - "notniva;": '\U0000220C', - "notnivb;": '\U000022FE', - "notnivc;": '\U000022FD', - "npar;": '\U00002226', - "nparallel;": '\U00002226', - "npolint;": '\U00002A14', - "npr;": '\U00002280', - "nprcue;": '\U000022E0', - "nprec;": '\U00002280', - "nrArr;": '\U000021CF', - "nrarr;": '\U0000219B', - "nrightarrow;": '\U0000219B', - "nrtri;": '\U000022EB', - "nrtrie;": '\U000022ED', - "nsc;": '\U00002281', - "nsccue;": '\U000022E1', - "nscr;": '\U0001D4C3', - "nshortmid;": '\U00002224', - "nshortparallel;": '\U00002226', - "nsim;": '\U00002241', - "nsime;": '\U00002244', - "nsimeq;": '\U00002244', - "nsmid;": '\U00002224', - "nspar;": '\U00002226', - "nsqsube;": '\U000022E2', - "nsqsupe;": '\U000022E3', - "nsub;": '\U00002284', - "nsube;": '\U00002288', - "nsubseteq;": '\U00002288', - "nsucc;": '\U00002281', - "nsup;": '\U00002285', - "nsupe;": '\U00002289', - "nsupseteq;": '\U00002289', - "ntgl;": '\U00002279', - "ntilde;": '\U000000F1', - "ntlg;": '\U00002278', - "ntriangleleft;": '\U000022EA', - "ntrianglelefteq;": '\U000022EC', - "ntriangleright;": '\U000022EB', - "ntrianglerighteq;": '\U000022ED', - "nu;": '\U000003BD', - "num;": '\U00000023', - "numero;": '\U00002116', - "numsp;": '\U00002007', - "nvDash;": '\U000022AD', - "nvHarr;": '\U00002904', - "nvdash;": '\U000022AC', - "nvinfin;": '\U000029DE', - "nvlArr;": '\U00002902', - "nvrArr;": '\U00002903', - "nwArr;": '\U000021D6', - "nwarhk;": '\U00002923', - "nwarr;": '\U00002196', - "nwarrow;": '\U00002196', - "nwnear;": '\U00002927', - "oS;": '\U000024C8', - "oacute;": '\U000000F3', - "oast;": '\U0000229B', - "ocir;": '\U0000229A', - "ocirc;": '\U000000F4', - "ocy;": '\U0000043E', - "odash;": '\U0000229D', - "odblac;": '\U00000151', - "odiv;": '\U00002A38', - "odot;": '\U00002299', - "odsold;": '\U000029BC', - "oelig;": '\U00000153', - "ofcir;": '\U000029BF', - "ofr;": '\U0001D52C', - "ogon;": '\U000002DB', - "ograve;": '\U000000F2', - "ogt;": '\U000029C1', - "ohbar;": '\U000029B5', - "ohm;": '\U000003A9', - "oint;": '\U0000222E', - "olarr;": '\U000021BA', - "olcir;": '\U000029BE', - "olcross;": '\U000029BB', - "oline;": '\U0000203E', - "olt;": '\U000029C0', - "omacr;": '\U0000014D', - "omega;": '\U000003C9', - "omicron;": '\U000003BF', - "omid;": '\U000029B6', - "ominus;": '\U00002296', - "oopf;": '\U0001D560', - "opar;": '\U000029B7', - "operp;": '\U000029B9', - "oplus;": '\U00002295', - "or;": '\U00002228', - "orarr;": '\U000021BB', - "ord;": '\U00002A5D', - "order;": '\U00002134', - "orderof;": '\U00002134', - "ordf;": '\U000000AA', - "ordm;": '\U000000BA', - "origof;": '\U000022B6', - "oror;": '\U00002A56', - "orslope;": '\U00002A57', - "orv;": '\U00002A5B', - "oscr;": '\U00002134', - "oslash;": '\U000000F8', - "osol;": '\U00002298', - "otilde;": '\U000000F5', - "otimes;": '\U00002297', - "otimesas;": '\U00002A36', - "ouml;": '\U000000F6', - "ovbar;": '\U0000233D', - "par;": '\U00002225', - "para;": '\U000000B6', - "parallel;": '\U00002225', - "parsim;": '\U00002AF3', - "parsl;": '\U00002AFD', - "part;": '\U00002202', - "pcy;": '\U0000043F', - "percnt;": '\U00000025', - "period;": '\U0000002E', - "permil;": '\U00002030', - "perp;": '\U000022A5', - "pertenk;": '\U00002031', - "pfr;": '\U0001D52D', - "phi;": '\U000003C6', - "phiv;": '\U000003D5', - "phmmat;": '\U00002133', - "phone;": '\U0000260E', - "pi;": '\U000003C0', - "pitchfork;": '\U000022D4', - "piv;": '\U000003D6', - "planck;": '\U0000210F', - "planckh;": '\U0000210E', - "plankv;": '\U0000210F', - "plus;": '\U0000002B', - "plusacir;": '\U00002A23', - "plusb;": '\U0000229E', - "pluscir;": '\U00002A22', - "plusdo;": '\U00002214', - "plusdu;": '\U00002A25', - "pluse;": '\U00002A72', - "plusmn;": '\U000000B1', - "plussim;": '\U00002A26', - "plustwo;": '\U00002A27', - "pm;": '\U000000B1', - "pointint;": '\U00002A15', - "popf;": '\U0001D561', - "pound;": '\U000000A3', - "pr;": '\U0000227A', - "prE;": '\U00002AB3', - "prap;": '\U00002AB7', - "prcue;": '\U0000227C', - "pre;": '\U00002AAF', - "prec;": '\U0000227A', - "precapprox;": '\U00002AB7', - "preccurlyeq;": '\U0000227C', - "preceq;": '\U00002AAF', - "precnapprox;": '\U00002AB9', - "precneqq;": '\U00002AB5', - "precnsim;": '\U000022E8', - "precsim;": '\U0000227E', - "prime;": '\U00002032', - "primes;": '\U00002119', - "prnE;": '\U00002AB5', - "prnap;": '\U00002AB9', - "prnsim;": '\U000022E8', - "prod;": '\U0000220F', - "profalar;": '\U0000232E', - "profline;": '\U00002312', - "profsurf;": '\U00002313', - "prop;": '\U0000221D', - "propto;": '\U0000221D', - "prsim;": '\U0000227E', - "prurel;": '\U000022B0', - "pscr;": '\U0001D4C5', - "psi;": '\U000003C8', - "puncsp;": '\U00002008', - "qfr;": '\U0001D52E', - "qint;": '\U00002A0C', - "qopf;": '\U0001D562', - "qprime;": '\U00002057', - "qscr;": '\U0001D4C6', - "quaternions;": '\U0000210D', - "quatint;": '\U00002A16', - "quest;": '\U0000003F', - "questeq;": '\U0000225F', - "quot;": '\U00000022', - "rAarr;": '\U000021DB', - "rArr;": '\U000021D2', - "rAtail;": '\U0000291C', - "rBarr;": '\U0000290F', - "rHar;": '\U00002964', - "racute;": '\U00000155', - "radic;": '\U0000221A', - "raemptyv;": '\U000029B3', - "rang;": '\U000027E9', - "rangd;": '\U00002992', - "range;": '\U000029A5', - "rangle;": '\U000027E9', - "raquo;": '\U000000BB', - "rarr;": '\U00002192', - "rarrap;": '\U00002975', - "rarrb;": '\U000021E5', - "rarrbfs;": '\U00002920', - "rarrc;": '\U00002933', - "rarrfs;": '\U0000291E', - "rarrhk;": '\U000021AA', - "rarrlp;": '\U000021AC', - "rarrpl;": '\U00002945', - "rarrsim;": '\U00002974', - "rarrtl;": '\U000021A3', - "rarrw;": '\U0000219D', - "ratail;": '\U0000291A', - "ratio;": '\U00002236', - "rationals;": '\U0000211A', - "rbarr;": '\U0000290D', - "rbbrk;": '\U00002773', - "rbrace;": '\U0000007D', - "rbrack;": '\U0000005D', - "rbrke;": '\U0000298C', - "rbrksld;": '\U0000298E', - "rbrkslu;": '\U00002990', - "rcaron;": '\U00000159', - "rcedil;": '\U00000157', - "rceil;": '\U00002309', - "rcub;": '\U0000007D', - "rcy;": '\U00000440', - "rdca;": '\U00002937', - "rdldhar;": '\U00002969', - "rdquo;": '\U0000201D', - "rdquor;": '\U0000201D', - "rdsh;": '\U000021B3', - "real;": '\U0000211C', - "realine;": '\U0000211B', - "realpart;": '\U0000211C', - "reals;": '\U0000211D', - "rect;": '\U000025AD', - "reg;": '\U000000AE', - "rfisht;": '\U0000297D', - "rfloor;": '\U0000230B', - "rfr;": '\U0001D52F', - "rhard;": '\U000021C1', - "rharu;": '\U000021C0', - "rharul;": '\U0000296C', - "rho;": '\U000003C1', - "rhov;": '\U000003F1', - "rightarrow;": '\U00002192', - "rightarrowtail;": '\U000021A3', - "rightharpoondown;": '\U000021C1', - "rightharpoonup;": '\U000021C0', - "rightleftarrows;": '\U000021C4', - "rightleftharpoons;": '\U000021CC', - "rightrightarrows;": '\U000021C9', - "rightsquigarrow;": '\U0000219D', - "rightthreetimes;": '\U000022CC', - "ring;": '\U000002DA', - "risingdotseq;": '\U00002253', - "rlarr;": '\U000021C4', - "rlhar;": '\U000021CC', - "rlm;": '\U0000200F', - "rmoust;": '\U000023B1', - "rmoustache;": '\U000023B1', - "rnmid;": '\U00002AEE', - "roang;": '\U000027ED', - "roarr;": '\U000021FE', - "robrk;": '\U000027E7', - "ropar;": '\U00002986', - "ropf;": '\U0001D563', - "roplus;": '\U00002A2E', - "rotimes;": '\U00002A35', - "rpar;": '\U00000029', - "rpargt;": '\U00002994', - "rppolint;": '\U00002A12', - "rrarr;": '\U000021C9', - "rsaquo;": '\U0000203A', - "rscr;": '\U0001D4C7', - "rsh;": '\U000021B1', - "rsqb;": '\U0000005D', - "rsquo;": '\U00002019', - "rsquor;": '\U00002019', - "rthree;": '\U000022CC', - "rtimes;": '\U000022CA', - "rtri;": '\U000025B9', - "rtrie;": '\U000022B5', - "rtrif;": '\U000025B8', - "rtriltri;": '\U000029CE', - "ruluhar;": '\U00002968', - "rx;": '\U0000211E', - "sacute;": '\U0000015B', - "sbquo;": '\U0000201A', - "sc;": '\U0000227B', - "scE;": '\U00002AB4', - "scap;": '\U00002AB8', - "scaron;": '\U00000161', - "sccue;": '\U0000227D', - "sce;": '\U00002AB0', - "scedil;": '\U0000015F', - "scirc;": '\U0000015D', - "scnE;": '\U00002AB6', - "scnap;": '\U00002ABA', - "scnsim;": '\U000022E9', - "scpolint;": '\U00002A13', - "scsim;": '\U0000227F', - "scy;": '\U00000441', - "sdot;": '\U000022C5', - "sdotb;": '\U000022A1', - "sdote;": '\U00002A66', - "seArr;": '\U000021D8', - "searhk;": '\U00002925', - "searr;": '\U00002198', - "searrow;": '\U00002198', - "sect;": '\U000000A7', - "semi;": '\U0000003B', - "seswar;": '\U00002929', - "setminus;": '\U00002216', - "setmn;": '\U00002216', - "sext;": '\U00002736', - "sfr;": '\U0001D530', - "sfrown;": '\U00002322', - "sharp;": '\U0000266F', - "shchcy;": '\U00000449', - "shcy;": '\U00000448', - "shortmid;": '\U00002223', - "shortparallel;": '\U00002225', - "shy;": '\U000000AD', - "sigma;": '\U000003C3', - "sigmaf;": '\U000003C2', - "sigmav;": '\U000003C2', - "sim;": '\U0000223C', - "simdot;": '\U00002A6A', - "sime;": '\U00002243', - "simeq;": '\U00002243', - "simg;": '\U00002A9E', - "simgE;": '\U00002AA0', - "siml;": '\U00002A9D', - "simlE;": '\U00002A9F', - "simne;": '\U00002246', - "simplus;": '\U00002A24', - "simrarr;": '\U00002972', - "slarr;": '\U00002190', - "smallsetminus;": '\U00002216', - "smashp;": '\U00002A33', - "smeparsl;": '\U000029E4', - "smid;": '\U00002223', - "smile;": '\U00002323', - "smt;": '\U00002AAA', - "smte;": '\U00002AAC', - "softcy;": '\U0000044C', - "sol;": '\U0000002F', - "solb;": '\U000029C4', - "solbar;": '\U0000233F', - "sopf;": '\U0001D564', - "spades;": '\U00002660', - "spadesuit;": '\U00002660', - "spar;": '\U00002225', - "sqcap;": '\U00002293', - "sqcup;": '\U00002294', - "sqsub;": '\U0000228F', - "sqsube;": '\U00002291', - "sqsubset;": '\U0000228F', - "sqsubseteq;": '\U00002291', - "sqsup;": '\U00002290', - "sqsupe;": '\U00002292', - "sqsupset;": '\U00002290', - "sqsupseteq;": '\U00002292', - "squ;": '\U000025A1', - "square;": '\U000025A1', - "squarf;": '\U000025AA', - "squf;": '\U000025AA', - "srarr;": '\U00002192', - "sscr;": '\U0001D4C8', - "ssetmn;": '\U00002216', - "ssmile;": '\U00002323', - "sstarf;": '\U000022C6', - "star;": '\U00002606', - "starf;": '\U00002605', - "straightepsilon;": '\U000003F5', - "straightphi;": '\U000003D5', - "strns;": '\U000000AF', - "sub;": '\U00002282', - "subE;": '\U00002AC5', - "subdot;": '\U00002ABD', - "sube;": '\U00002286', - "subedot;": '\U00002AC3', - "submult;": '\U00002AC1', - "subnE;": '\U00002ACB', - "subne;": '\U0000228A', - "subplus;": '\U00002ABF', - "subrarr;": '\U00002979', - "subset;": '\U00002282', - "subseteq;": '\U00002286', - "subseteqq;": '\U00002AC5', - "subsetneq;": '\U0000228A', - "subsetneqq;": '\U00002ACB', - "subsim;": '\U00002AC7', - "subsub;": '\U00002AD5', - "subsup;": '\U00002AD3', - "succ;": '\U0000227B', - "succapprox;": '\U00002AB8', - "succcurlyeq;": '\U0000227D', - "succeq;": '\U00002AB0', - "succnapprox;": '\U00002ABA', - "succneqq;": '\U00002AB6', - "succnsim;": '\U000022E9', - "succsim;": '\U0000227F', - "sum;": '\U00002211', - "sung;": '\U0000266A', - "sup;": '\U00002283', - "sup1;": '\U000000B9', - "sup2;": '\U000000B2', - "sup3;": '\U000000B3', - "supE;": '\U00002AC6', - "supdot;": '\U00002ABE', - "supdsub;": '\U00002AD8', - "supe;": '\U00002287', - "supedot;": '\U00002AC4', - "suphsol;": '\U000027C9', - "suphsub;": '\U00002AD7', - "suplarr;": '\U0000297B', - "supmult;": '\U00002AC2', - "supnE;": '\U00002ACC', - "supne;": '\U0000228B', - "supplus;": '\U00002AC0', - "supset;": '\U00002283', - "supseteq;": '\U00002287', - "supseteqq;": '\U00002AC6', - "supsetneq;": '\U0000228B', - "supsetneqq;": '\U00002ACC', - "supsim;": '\U00002AC8', - "supsub;": '\U00002AD4', - "supsup;": '\U00002AD6', - "swArr;": '\U000021D9', - "swarhk;": '\U00002926', - "swarr;": '\U00002199', - "swarrow;": '\U00002199', - "swnwar;": '\U0000292A', - "szlig;": '\U000000DF', - "target;": '\U00002316', - "tau;": '\U000003C4', - "tbrk;": '\U000023B4', - "tcaron;": '\U00000165', - "tcedil;": '\U00000163', - "tcy;": '\U00000442', - "tdot;": '\U000020DB', - "telrec;": '\U00002315', - "tfr;": '\U0001D531', - "there4;": '\U00002234', - "therefore;": '\U00002234', - "theta;": '\U000003B8', - "thetasym;": '\U000003D1', - "thetav;": '\U000003D1', - "thickapprox;": '\U00002248', - "thicksim;": '\U0000223C', - "thinsp;": '\U00002009', - "thkap;": '\U00002248', - "thksim;": '\U0000223C', - "thorn;": '\U000000FE', - "tilde;": '\U000002DC', - "times;": '\U000000D7', - "timesb;": '\U000022A0', - "timesbar;": '\U00002A31', - "timesd;": '\U00002A30', - "tint;": '\U0000222D', - "toea;": '\U00002928', - "top;": '\U000022A4', - "topbot;": '\U00002336', - "topcir;": '\U00002AF1', - "topf;": '\U0001D565', - "topfork;": '\U00002ADA', - "tosa;": '\U00002929', - "tprime;": '\U00002034', - "trade;": '\U00002122', - "triangle;": '\U000025B5', - "triangledown;": '\U000025BF', - "triangleleft;": '\U000025C3', - "trianglelefteq;": '\U000022B4', - "triangleq;": '\U0000225C', - "triangleright;": '\U000025B9', - "trianglerighteq;": '\U000022B5', - "tridot;": '\U000025EC', - "trie;": '\U0000225C', - "triminus;": '\U00002A3A', - "triplus;": '\U00002A39', - "trisb;": '\U000029CD', - "tritime;": '\U00002A3B', - "trpezium;": '\U000023E2', - "tscr;": '\U0001D4C9', - "tscy;": '\U00000446', - "tshcy;": '\U0000045B', - "tstrok;": '\U00000167', - "twixt;": '\U0000226C', - "twoheadleftarrow;": '\U0000219E', - "twoheadrightarrow;": '\U000021A0', - "uArr;": '\U000021D1', - "uHar;": '\U00002963', - "uacute;": '\U000000FA', - "uarr;": '\U00002191', - "ubrcy;": '\U0000045E', - "ubreve;": '\U0000016D', - "ucirc;": '\U000000FB', - "ucy;": '\U00000443', - "udarr;": '\U000021C5', - "udblac;": '\U00000171', - "udhar;": '\U0000296E', - "ufisht;": '\U0000297E', - "ufr;": '\U0001D532', - "ugrave;": '\U000000F9', - "uharl;": '\U000021BF', - "uharr;": '\U000021BE', - "uhblk;": '\U00002580', - "ulcorn;": '\U0000231C', - "ulcorner;": '\U0000231C', - "ulcrop;": '\U0000230F', - "ultri;": '\U000025F8', - "umacr;": '\U0000016B', - "uml;": '\U000000A8', - "uogon;": '\U00000173', - "uopf;": '\U0001D566', - "uparrow;": '\U00002191', - "updownarrow;": '\U00002195', - "upharpoonleft;": '\U000021BF', - "upharpoonright;": '\U000021BE', - "uplus;": '\U0000228E', - "upsi;": '\U000003C5', - "upsih;": '\U000003D2', - "upsilon;": '\U000003C5', - "upuparrows;": '\U000021C8', - "urcorn;": '\U0000231D', - "urcorner;": '\U0000231D', - "urcrop;": '\U0000230E', - "uring;": '\U0000016F', - "urtri;": '\U000025F9', - "uscr;": '\U0001D4CA', - "utdot;": '\U000022F0', - "utilde;": '\U00000169', - "utri;": '\U000025B5', - "utrif;": '\U000025B4', - "uuarr;": '\U000021C8', - "uuml;": '\U000000FC', - "uwangle;": '\U000029A7', - "vArr;": '\U000021D5', - "vBar;": '\U00002AE8', - "vBarv;": '\U00002AE9', - "vDash;": '\U000022A8', - "vangrt;": '\U0000299C', - "varepsilon;": '\U000003F5', - "varkappa;": '\U000003F0', - "varnothing;": '\U00002205', - "varphi;": '\U000003D5', - "varpi;": '\U000003D6', - "varpropto;": '\U0000221D', - "varr;": '\U00002195', - "varrho;": '\U000003F1', - "varsigma;": '\U000003C2', - "vartheta;": '\U000003D1', - "vartriangleleft;": '\U000022B2', - "vartriangleright;": '\U000022B3', - "vcy;": '\U00000432', - "vdash;": '\U000022A2', - "vee;": '\U00002228', - "veebar;": '\U000022BB', - "veeeq;": '\U0000225A', - "vellip;": '\U000022EE', - "verbar;": '\U0000007C', - "vert;": '\U0000007C', - "vfr;": '\U0001D533', - "vltri;": '\U000022B2', - "vopf;": '\U0001D567', - "vprop;": '\U0000221D', - "vrtri;": '\U000022B3', - "vscr;": '\U0001D4CB', - "vzigzag;": '\U0000299A', - "wcirc;": '\U00000175', - "wedbar;": '\U00002A5F', - "wedge;": '\U00002227', - "wedgeq;": '\U00002259', - "weierp;": '\U00002118', - "wfr;": '\U0001D534', - "wopf;": '\U0001D568', - "wp;": '\U00002118', - "wr;": '\U00002240', - "wreath;": '\U00002240', - "wscr;": '\U0001D4CC', - "xcap;": '\U000022C2', - "xcirc;": '\U000025EF', - "xcup;": '\U000022C3', - "xdtri;": '\U000025BD', - "xfr;": '\U0001D535', - "xhArr;": '\U000027FA', - "xharr;": '\U000027F7', - "xi;": '\U000003BE', - "xlArr;": '\U000027F8', - "xlarr;": '\U000027F5', - "xmap;": '\U000027FC', - "xnis;": '\U000022FB', - "xodot;": '\U00002A00', - "xopf;": '\U0001D569', - "xoplus;": '\U00002A01', - "xotime;": '\U00002A02', - "xrArr;": '\U000027F9', - "xrarr;": '\U000027F6', - "xscr;": '\U0001D4CD', - "xsqcup;": '\U00002A06', - "xuplus;": '\U00002A04', - "xutri;": '\U000025B3', - "xvee;": '\U000022C1', - "xwedge;": '\U000022C0', - "yacute;": '\U000000FD', - "yacy;": '\U0000044F', - "ycirc;": '\U00000177', - "ycy;": '\U0000044B', - "yen;": '\U000000A5', - "yfr;": '\U0001D536', - "yicy;": '\U00000457', - "yopf;": '\U0001D56A', - "yscr;": '\U0001D4CE', - "yucy;": '\U0000044E', - "yuml;": '\U000000FF', - "zacute;": '\U0000017A', - "zcaron;": '\U0000017E', - "zcy;": '\U00000437', - "zdot;": '\U0000017C', - "zeetrf;": '\U00002128', - "zeta;": '\U000003B6', - "zfr;": '\U0001D537', - "zhcy;": '\U00000436', - "zigrarr;": '\U000021DD', - "zopf;": '\U0001D56B', - "zscr;": '\U0001D4CF', - "zwj;": '\U0000200D', - "zwnj;": '\U0000200C', - "AElig": '\U000000C6', - "AMP": '\U00000026', - "Aacute": '\U000000C1', - "Acirc": '\U000000C2', - "Agrave": '\U000000C0', - "Aring": '\U000000C5', - "Atilde": '\U000000C3', - "Auml": '\U000000C4', - "COPY": '\U000000A9', - "Ccedil": '\U000000C7', - "ETH": '\U000000D0', - "Eacute": '\U000000C9', - "Ecirc": '\U000000CA', - "Egrave": '\U000000C8', - "Euml": '\U000000CB', - "GT": '\U0000003E', - "Iacute": '\U000000CD', - "Icirc": '\U000000CE', - "Igrave": '\U000000CC', - "Iuml": '\U000000CF', - "LT": '\U0000003C', - "Ntilde": '\U000000D1', - "Oacute": '\U000000D3', - "Ocirc": '\U000000D4', - "Ograve": '\U000000D2', - "Oslash": '\U000000D8', - "Otilde": '\U000000D5', - "Ouml": '\U000000D6', - "QUOT": '\U00000022', - "REG": '\U000000AE', - "THORN": '\U000000DE', - "Uacute": '\U000000DA', - "Ucirc": '\U000000DB', - "Ugrave": '\U000000D9', - "Uuml": '\U000000DC', - "Yacute": '\U000000DD', - "aacute": '\U000000E1', - "acirc": '\U000000E2', - "acute": '\U000000B4', - "aelig": '\U000000E6', - "agrave": '\U000000E0', - "amp": '\U00000026', - "aring": '\U000000E5', - "atilde": '\U000000E3', - "auml": '\U000000E4', - "brvbar": '\U000000A6', - "ccedil": '\U000000E7', - "cedil": '\U000000B8', - "cent": '\U000000A2', - "copy": '\U000000A9', - "curren": '\U000000A4', - "deg": '\U000000B0', - "divide": '\U000000F7', - "eacute": '\U000000E9', - "ecirc": '\U000000EA', - "egrave": '\U000000E8', - "eth": '\U000000F0', - "euml": '\U000000EB', - "frac12": '\U000000BD', - "frac14": '\U000000BC', - "frac34": '\U000000BE', - "gt": '\U0000003E', - "iacute": '\U000000ED', - "icirc": '\U000000EE', - "iexcl": '\U000000A1', - "igrave": '\U000000EC', - "iquest": '\U000000BF', - "iuml": '\U000000EF', - "laquo": '\U000000AB', - "lt": '\U0000003C', - "macr": '\U000000AF', - "micro": '\U000000B5', - "middot": '\U000000B7', - "nbsp": '\U000000A0', - "not": '\U000000AC', - "ntilde": '\U000000F1', - "oacute": '\U000000F3', - "ocirc": '\U000000F4', - "ograve": '\U000000F2', - "ordf": '\U000000AA', - "ordm": '\U000000BA', - "oslash": '\U000000F8', - "otilde": '\U000000F5', - "ouml": '\U000000F6', - "para": '\U000000B6', - "plusmn": '\U000000B1', - "pound": '\U000000A3', - "quot": '\U00000022', - "raquo": '\U000000BB', - "reg": '\U000000AE', - "sect": '\U000000A7', - "shy": '\U000000AD', - "sup1": '\U000000B9', - "sup2": '\U000000B2', - "sup3": '\U000000B3', - "szlig": '\U000000DF', - "thorn": '\U000000FE', - "times": '\U000000D7', - "uacute": '\U000000FA', - "ucirc": '\U000000FB', - "ugrave": '\U000000F9', - "uml": '\U000000A8', - "uuml": '\U000000FC', - "yacute": '\U000000FD', - "yen": '\U000000A5', - "yuml": '\U000000FF', + "Cross;": '\U00002A2F', + "Cscr;": '\U0001D49E', + "Cup;": '\U000022D3', + "CupCap;": '\U0000224D', + "DD;": '\U00002145', + "DDotrahd;": '\U00002911', + "DJcy;": '\U00000402', + "DScy;": '\U00000405', + "DZcy;": '\U0000040F', + "Dagger;": '\U00002021', + "Darr;": '\U000021A1', + "Dashv;": '\U00002AE4', + "Dcaron;": '\U0000010E', + "Dcy;": '\U00000414', + "Del;": '\U00002207', + "Delta;": '\U00000394', + "Dfr;": '\U0001D507', + "DiacriticalAcute;": '\U000000B4', + "DiacriticalDot;": '\U000002D9', + "DiacriticalDoubleAcute;": '\U000002DD', + "DiacriticalGrave;": '\U00000060', + "DiacriticalTilde;": '\U000002DC', + "Diamond;": '\U000022C4', + "DifferentialD;": '\U00002146', + "Dopf;": '\U0001D53B', + "Dot;": '\U000000A8', + "DotDot;": '\U000020DC', + "DotEqual;": '\U00002250', + "DoubleContourIntegral;": '\U0000222F', + "DoubleDot;": '\U000000A8', + "DoubleDownArrow;": '\U000021D3', + "DoubleLeftArrow;": '\U000021D0', + "DoubleLeftRightArrow;": '\U000021D4', + "DoubleLeftTee;": '\U00002AE4', + "DoubleLongLeftArrow;": '\U000027F8', + "DoubleLongLeftRightArrow;": '\U000027FA', + "DoubleLongRightArrow;": '\U000027F9', + "DoubleRightArrow;": '\U000021D2', + "DoubleRightTee;": '\U000022A8', + "DoubleUpArrow;": '\U000021D1', + "DoubleUpDownArrow;": '\U000021D5', + "DoubleVerticalBar;": '\U00002225', + "DownArrow;": '\U00002193', + "DownArrowBar;": '\U00002913', + "DownArrowUpArrow;": '\U000021F5', + "DownBreve;": '\U00000311', + "DownLeftRightVector;": '\U00002950', + "DownLeftTeeVector;": '\U0000295E', + "DownLeftVector;": '\U000021BD', + "DownLeftVectorBar;": '\U00002956', + "DownRightTeeVector;": '\U0000295F', + "DownRightVector;": '\U000021C1', + "DownRightVectorBar;": '\U00002957', + "DownTee;": '\U000022A4', + "DownTeeArrow;": '\U000021A7', + "Downarrow;": '\U000021D3', + "Dscr;": '\U0001D49F', + "Dstrok;": '\U00000110', + "ENG;": '\U0000014A', + "ETH;": '\U000000D0', + "Eacute;": '\U000000C9', + "Ecaron;": '\U0000011A', + "Ecirc;": '\U000000CA', + "Ecy;": '\U0000042D', + "Edot;": '\U00000116', + "Efr;": '\U0001D508', + "Egrave;": '\U000000C8', + "Element;": '\U00002208', + "Emacr;": '\U00000112', + "EmptySmallSquare;": '\U000025FB', + "EmptyVerySmallSquare;": '\U000025AB', + "Eogon;": '\U00000118', + "Eopf;": '\U0001D53C', + "Epsilon;": '\U00000395', + "Equal;": '\U00002A75', + "EqualTilde;": '\U00002242', + "Equilibrium;": '\U000021CC', + "Escr;": '\U00002130', + "Esim;": '\U00002A73', + "Eta;": '\U00000397', + "Euml;": '\U000000CB', + "Exists;": '\U00002203', + "ExponentialE;": '\U00002147', + "Fcy;": '\U00000424', + "Ffr;": '\U0001D509', + "FilledSmallSquare;": '\U000025FC', + "FilledVerySmallSquare;": '\U000025AA', + "Fopf;": '\U0001D53D', + "ForAll;": '\U00002200', + "Fouriertrf;": '\U00002131', + "Fscr;": '\U00002131', + "GJcy;": '\U00000403', + "GT;": '\U0000003E', + "Gamma;": '\U00000393', + "Gammad;": '\U000003DC', + "Gbreve;": '\U0000011E', + "Gcedil;": '\U00000122', + "Gcirc;": '\U0000011C', + "Gcy;": '\U00000413', + "Gdot;": '\U00000120', + "Gfr;": '\U0001D50A', + "Gg;": '\U000022D9', + "Gopf;": '\U0001D53E', + "GreaterEqual;": '\U00002265', + "GreaterEqualLess;": '\U000022DB', + "GreaterFullEqual;": '\U00002267', + "GreaterGreater;": '\U00002AA2', + "GreaterLess;": '\U00002277', + "GreaterSlantEqual;": '\U00002A7E', + "GreaterTilde;": '\U00002273', + "Gscr;": '\U0001D4A2', + "Gt;": '\U0000226B', + "HARDcy;": '\U0000042A', + "Hacek;": '\U000002C7', + "Hat;": '\U0000005E', + "Hcirc;": '\U00000124', + "Hfr;": '\U0000210C', + "HilbertSpace;": '\U0000210B', + "Hopf;": '\U0000210D', + "HorizontalLine;": '\U00002500', + "Hscr;": '\U0000210B', + "Hstrok;": '\U00000126', + "HumpDownHump;": '\U0000224E', + "HumpEqual;": '\U0000224F', + "IEcy;": '\U00000415', + "IJlig;": '\U00000132', + "IOcy;": '\U00000401', + "Iacute;": '\U000000CD', + "Icirc;": '\U000000CE', + "Icy;": '\U00000418', + "Idot;": '\U00000130', + "Ifr;": '\U00002111', + "Igrave;": '\U000000CC', + "Im;": '\U00002111', + "Imacr;": '\U0000012A', + "ImaginaryI;": '\U00002148', + "Implies;": '\U000021D2', + "Int;": '\U0000222C', + "Integral;": '\U0000222B', + "Intersection;": '\U000022C2', + "InvisibleComma;": '\U00002063', + "InvisibleTimes;": '\U00002062', + "Iogon;": '\U0000012E', + "Iopf;": '\U0001D540', + "Iota;": '\U00000399', + "Iscr;": '\U00002110', + "Itilde;": '\U00000128', + "Iukcy;": '\U00000406', + "Iuml;": '\U000000CF', + "Jcirc;": '\U00000134', + "Jcy;": '\U00000419', + "Jfr;": '\U0001D50D', + "Jopf;": '\U0001D541', + "Jscr;": '\U0001D4A5', + "Jsercy;": '\U00000408', + "Jukcy;": '\U00000404', + "KHcy;": '\U00000425', + "KJcy;": '\U0000040C', + "Kappa;": '\U0000039A', + "Kcedil;": '\U00000136', + "Kcy;": '\U0000041A', + "Kfr;": '\U0001D50E', + "Kopf;": '\U0001D542', + "Kscr;": '\U0001D4A6', + "LJcy;": '\U00000409', + "LT;": '\U0000003C', + "Lacute;": '\U00000139', + "Lambda;": '\U0000039B', + "Lang;": '\U000027EA', + "Laplacetrf;": '\U00002112', + "Larr;": '\U0000219E', + "Lcaron;": '\U0000013D', + "Lcedil;": '\U0000013B', + "Lcy;": '\U0000041B', + "LeftAngleBracket;": '\U000027E8', + "LeftArrow;": '\U00002190', + "LeftArrowBar;": '\U000021E4', + "LeftArrowRightArrow;": '\U000021C6', + "LeftCeiling;": '\U00002308', + "LeftDoubleBracket;": '\U000027E6', + "LeftDownTeeVector;": '\U00002961', + "LeftDownVector;": '\U000021C3', + "LeftDownVectorBar;": '\U00002959', + "LeftFloor;": '\U0000230A', + "LeftRightArrow;": '\U00002194', + "LeftRightVector;": '\U0000294E', + "LeftTee;": '\U000022A3', + "LeftTeeArrow;": '\U000021A4', + "LeftTeeVector;": '\U0000295A', + "LeftTriangle;": '\U000022B2', + "LeftTriangleBar;": '\U000029CF', + "LeftTriangleEqual;": '\U000022B4', + "LeftUpDownVector;": '\U00002951', + "LeftUpTeeVector;": '\U00002960', + "LeftUpVector;": '\U000021BF', + "LeftUpVectorBar;": '\U00002958', + "LeftVector;": '\U000021BC', + "LeftVectorBar;": '\U00002952', + "Leftarrow;": '\U000021D0', + "Leftrightarrow;": '\U000021D4', + "LessEqualGreater;": '\U000022DA', + "LessFullEqual;": '\U00002266', + "LessGreater;": '\U00002276', + "LessLess;": '\U00002AA1', + "LessSlantEqual;": '\U00002A7D', + "LessTilde;": '\U00002272', + "Lfr;": '\U0001D50F', + "Ll;": '\U000022D8', + "Lleftarrow;": '\U000021DA', + "Lmidot;": '\U0000013F', + "LongLeftArrow;": '\U000027F5', + "LongLeftRightArrow;": '\U000027F7', + "LongRightArrow;": '\U000027F6', + "Longleftarrow;": '\U000027F8', + "Longleftrightarrow;": '\U000027FA', + "Longrightarrow;": '\U000027F9', + "Lopf;": '\U0001D543', + "LowerLeftArrow;": '\U00002199', + "LowerRightArrow;": '\U00002198', + "Lscr;": '\U00002112', + "Lsh;": '\U000021B0', + "Lstrok;": '\U00000141', + "Lt;": '\U0000226A', + "Map;": '\U00002905', + "Mcy;": '\U0000041C', + "MediumSpace;": '\U0000205F', + "Mellintrf;": '\U00002133', + "Mfr;": '\U0001D510', + "MinusPlus;": '\U00002213', + "Mopf;": '\U0001D544', + "Mscr;": '\U00002133', + "Mu;": '\U0000039C', + "NJcy;": '\U0000040A', + "Nacute;": '\U00000143', + "Ncaron;": '\U00000147', + "Ncedil;": '\U00000145', + "Ncy;": '\U0000041D', + "NegativeMediumSpace;": '\U0000200B', + "NegativeThickSpace;": '\U0000200B', + "NegativeThinSpace;": '\U0000200B', + "NegativeVeryThinSpace;": '\U0000200B', + "NestedGreaterGreater;": '\U0000226B', + "NestedLessLess;": '\U0000226A', + "NewLine;": '\U0000000A', + "Nfr;": '\U0001D511', + "NoBreak;": '\U00002060', + "NonBreakingSpace;": '\U000000A0', + "Nopf;": '\U00002115', + "Not;": '\U00002AEC', + "NotCongruent;": '\U00002262', + "NotCupCap;": '\U0000226D', + "NotDoubleVerticalBar;": '\U00002226', + "NotElement;": '\U00002209', + "NotEqual;": '\U00002260', + "NotExists;": '\U00002204', + "NotGreater;": '\U0000226F', + "NotGreaterEqual;": '\U00002271', + "NotGreaterLess;": '\U00002279', + "NotGreaterTilde;": '\U00002275', + "NotLeftTriangle;": '\U000022EA', + "NotLeftTriangleEqual;": '\U000022EC', + "NotLess;": '\U0000226E', + "NotLessEqual;": '\U00002270', + "NotLessGreater;": '\U00002278', + "NotLessTilde;": '\U00002274', + "NotPrecedes;": '\U00002280', + "NotPrecedesSlantEqual;": '\U000022E0', + "NotReverseElement;": '\U0000220C', + "NotRightTriangle;": '\U000022EB', + "NotRightTriangleEqual;": '\U000022ED', + "NotSquareSubsetEqual;": '\U000022E2', + "NotSquareSupersetEqual;": '\U000022E3', + "NotSubsetEqual;": '\U00002288', + "NotSucceeds;": '\U00002281', + "NotSucceedsSlantEqual;": '\U000022E1', + "NotSupersetEqual;": '\U00002289', + "NotTilde;": '\U00002241', + "NotTildeEqual;": '\U00002244', + "NotTildeFullEqual;": '\U00002247', + "NotTildeTilde;": '\U00002249', + "NotVerticalBar;": '\U00002224', + "Nscr;": '\U0001D4A9', + "Ntilde;": '\U000000D1', + "Nu;": '\U0000039D', + "OElig;": '\U00000152', + "Oacute;": '\U000000D3', + "Ocirc;": '\U000000D4', + "Ocy;": '\U0000041E', + "Odblac;": '\U00000150', + "Ofr;": '\U0001D512', + "Ograve;": '\U000000D2', + "Omacr;": '\U0000014C', + "Omega;": '\U000003A9', + "Omicron;": '\U0000039F', + "Oopf;": '\U0001D546', + "OpenCurlyDoubleQuote;": '\U0000201C', + "OpenCurlyQuote;": '\U00002018', + "Or;": '\U00002A54', + "Oscr;": '\U0001D4AA', + "Oslash;": '\U000000D8', + "Otilde;": '\U000000D5', + "Otimes;": '\U00002A37', + "Ouml;": '\U000000D6', + "OverBar;": '\U0000203E', + "OverBrace;": '\U000023DE', + "OverBracket;": '\U000023B4', + "OverParenthesis;": '\U000023DC', + "PartialD;": '\U00002202', + "Pcy;": '\U0000041F', + "Pfr;": '\U0001D513', + "Phi;": '\U000003A6', + "Pi;": '\U000003A0', + "PlusMinus;": '\U000000B1', + "Poincareplane;": '\U0000210C', + "Popf;": '\U00002119', + "Pr;": '\U00002ABB', + "Precedes;": '\U0000227A', + "PrecedesEqual;": '\U00002AAF', + "PrecedesSlantEqual;": '\U0000227C', + "PrecedesTilde;": '\U0000227E', + "Prime;": '\U00002033', + "Product;": '\U0000220F', + "Proportion;": '\U00002237', + "Proportional;": '\U0000221D', + "Pscr;": '\U0001D4AB', + "Psi;": '\U000003A8', + "QUOT;": '\U00000022', + "Qfr;": '\U0001D514', + "Qopf;": '\U0000211A', + "Qscr;": '\U0001D4AC', + "RBarr;": '\U00002910', + "REG;": '\U000000AE', + "Racute;": '\U00000154', + "Rang;": '\U000027EB', + "Rarr;": '\U000021A0', + "Rarrtl;": '\U00002916', + "Rcaron;": '\U00000158', + "Rcedil;": '\U00000156', + "Rcy;": '\U00000420', + "Re;": '\U0000211C', + "ReverseElement;": '\U0000220B', + "ReverseEquilibrium;": '\U000021CB', + "ReverseUpEquilibrium;": '\U0000296F', + "Rfr;": '\U0000211C', + "Rho;": '\U000003A1', + "RightAngleBracket;": '\U000027E9', + "RightArrow;": '\U00002192', + "RightArrowBar;": '\U000021E5', + "RightArrowLeftArrow;": '\U000021C4', + "RightCeiling;": '\U00002309', + "RightDoubleBracket;": '\U000027E7', + "RightDownTeeVector;": '\U0000295D', + "RightDownVector;": '\U000021C2', + "RightDownVectorBar;": '\U00002955', + "RightFloor;": '\U0000230B', + "RightTee;": '\U000022A2', + "RightTeeArrow;": '\U000021A6', + "RightTeeVector;": '\U0000295B', + "RightTriangle;": '\U000022B3', + "RightTriangleBar;": '\U000029D0', + "RightTriangleEqual;": '\U000022B5', + "RightUpDownVector;": '\U0000294F', + "RightUpTeeVector;": '\U0000295C', + "RightUpVector;": '\U000021BE', + "RightUpVectorBar;": '\U00002954', + "RightVector;": '\U000021C0', + "RightVectorBar;": '\U00002953', + "Rightarrow;": '\U000021D2', + "Ropf;": '\U0000211D', + "RoundImplies;": '\U00002970', + "Rrightarrow;": '\U000021DB', + "Rscr;": '\U0000211B', + "Rsh;": '\U000021B1', + "RuleDelayed;": '\U000029F4', + "SHCHcy;": '\U00000429', + "SHcy;": '\U00000428', + "SOFTcy;": '\U0000042C', + "Sacute;": '\U0000015A', + "Sc;": '\U00002ABC', + "Scaron;": '\U00000160', + "Scedil;": '\U0000015E', + "Scirc;": '\U0000015C', + "Scy;": '\U00000421', + "Sfr;": '\U0001D516', + "ShortDownArrow;": '\U00002193', + "ShortLeftArrow;": '\U00002190', + "ShortRightArrow;": '\U00002192', + "ShortUpArrow;": '\U00002191', + "Sigma;": '\U000003A3', + "SmallCircle;": '\U00002218', + "Sopf;": '\U0001D54A', + "Sqrt;": '\U0000221A', + "Square;": '\U000025A1', + "SquareIntersection;": '\U00002293', + "SquareSubset;": '\U0000228F', + "SquareSubsetEqual;": '\U00002291', + "SquareSuperset;": '\U00002290', + "SquareSupersetEqual;": '\U00002292', + "SquareUnion;": '\U00002294', + "Sscr;": '\U0001D4AE', + "Star;": '\U000022C6', + "Sub;": '\U000022D0', + "Subset;": '\U000022D0', + "SubsetEqual;": '\U00002286', + "Succeeds;": '\U0000227B', + "SucceedsEqual;": '\U00002AB0', + "SucceedsSlantEqual;": '\U0000227D', + "SucceedsTilde;": '\U0000227F', + "SuchThat;": '\U0000220B', + "Sum;": '\U00002211', + "Sup;": '\U000022D1', + "Superset;": '\U00002283', + "SupersetEqual;": '\U00002287', + "Supset;": '\U000022D1', + "THORN;": '\U000000DE', + "TRADE;": '\U00002122', + "TSHcy;": '\U0000040B', + "TScy;": '\U00000426', + "Tab;": '\U00000009', + "Tau;": '\U000003A4', + "Tcaron;": '\U00000164', + "Tcedil;": '\U00000162', + "Tcy;": '\U00000422', + "Tfr;": '\U0001D517', + "Therefore;": '\U00002234', + "Theta;": '\U00000398', + "ThinSpace;": '\U00002009', + "Tilde;": '\U0000223C', + "TildeEqual;": '\U00002243', + "TildeFullEqual;": '\U00002245', + "TildeTilde;": '\U00002248', + "Topf;": '\U0001D54B', + "TripleDot;": '\U000020DB', + "Tscr;": '\U0001D4AF', + "Tstrok;": '\U00000166', + "Uacute;": '\U000000DA', + "Uarr;": '\U0000219F', + "Uarrocir;": '\U00002949', + "Ubrcy;": '\U0000040E', + "Ubreve;": '\U0000016C', + "Ucirc;": '\U000000DB', + "Ucy;": '\U00000423', + "Udblac;": '\U00000170', + "Ufr;": '\U0001D518', + "Ugrave;": '\U000000D9', + "Umacr;": '\U0000016A', + "UnderBar;": '\U0000005F', + "UnderBrace;": '\U000023DF', + "UnderBracket;": '\U000023B5', + "UnderParenthesis;": '\U000023DD', + "Union;": '\U000022C3', + "UnionPlus;": '\U0000228E', + "Uogon;": '\U00000172', + "Uopf;": '\U0001D54C', + "UpArrow;": '\U00002191', + "UpArrowBar;": '\U00002912', + "UpArrowDownArrow;": '\U000021C5', + "UpDownArrow;": '\U00002195', + "UpEquilibrium;": '\U0000296E', + "UpTee;": '\U000022A5', + "UpTeeArrow;": '\U000021A5', + "Uparrow;": '\U000021D1', + "Updownarrow;": '\U000021D5', + "UpperLeftArrow;": '\U00002196', + "UpperRightArrow;": '\U00002197', + "Upsi;": '\U000003D2', + "Upsilon;": '\U000003A5', + "Uring;": '\U0000016E', + "Uscr;": '\U0001D4B0', + "Utilde;": '\U00000168', + "Uuml;": '\U000000DC', + "VDash;": '\U000022AB', + "Vbar;": '\U00002AEB', + "Vcy;": '\U00000412', + "Vdash;": '\U000022A9', + "Vdashl;": '\U00002AE6', + "Vee;": '\U000022C1', + "Verbar;": '\U00002016', + "Vert;": '\U00002016', + "VerticalBar;": '\U00002223', + "VerticalLine;": '\U0000007C', + "VerticalSeparator;": '\U00002758', + "VerticalTilde;": '\U00002240', + "VeryThinSpace;": '\U0000200A', + "Vfr;": '\U0001D519', + "Vopf;": '\U0001D54D', + "Vscr;": '\U0001D4B1', + "Vvdash;": '\U000022AA', + "Wcirc;": '\U00000174', + "Wedge;": '\U000022C0', + "Wfr;": '\U0001D51A', + "Wopf;": '\U0001D54E', + "Wscr;": '\U0001D4B2', + "Xfr;": '\U0001D51B', + "Xi;": '\U0000039E', + "Xopf;": '\U0001D54F', + "Xscr;": '\U0001D4B3', + "YAcy;": '\U0000042F', + "YIcy;": '\U00000407', + "YUcy;": '\U0000042E', + "Yacute;": '\U000000DD', + "Ycirc;": '\U00000176', + "Ycy;": '\U0000042B', + "Yfr;": '\U0001D51C', + "Yopf;": '\U0001D550', + "Yscr;": '\U0001D4B4', + "Yuml;": '\U00000178', + "ZHcy;": '\U00000416', + "Zacute;": '\U00000179', + "Zcaron;": '\U0000017D', + "Zcy;": '\U00000417', + "Zdot;": '\U0000017B', + "ZeroWidthSpace;": '\U0000200B', + "Zeta;": '\U00000396', + "Zfr;": '\U00002128', + "Zopf;": '\U00002124', + "Zscr;": '\U0001D4B5', + "aacute;": '\U000000E1', + "abreve;": '\U00000103', + "ac;": '\U0000223E', + "acd;": '\U0000223F', + "acirc;": '\U000000E2', + "acute;": '\U000000B4', + "acy;": '\U00000430', + "aelig;": '\U000000E6', + "af;": '\U00002061', + "afr;": '\U0001D51E', + "agrave;": '\U000000E0', + "alefsym;": '\U00002135', + "aleph;": '\U00002135', + "alpha;": '\U000003B1', + "amacr;": '\U00000101', + "amalg;": '\U00002A3F', + "amp;": '\U00000026', + "and;": '\U00002227', + "andand;": '\U00002A55', + "andd;": '\U00002A5C', + "andslope;": '\U00002A58', + "andv;": '\U00002A5A', + "ang;": '\U00002220', + "ange;": '\U000029A4', + "angle;": '\U00002220', + "angmsd;": '\U00002221', + "angmsdaa;": '\U000029A8', + "angmsdab;": '\U000029A9', + "angmsdac;": '\U000029AA', + "angmsdad;": '\U000029AB', + "angmsdae;": '\U000029AC', + "angmsdaf;": '\U000029AD', + "angmsdag;": '\U000029AE', + "angmsdah;": '\U000029AF', + "angrt;": '\U0000221F', + "angrtvb;": '\U000022BE', + "angrtvbd;": '\U0000299D', + "angsph;": '\U00002222', + "angst;": '\U000000C5', + "angzarr;": '\U0000237C', + "aogon;": '\U00000105', + "aopf;": '\U0001D552', + "ap;": '\U00002248', + "apE;": '\U00002A70', + "apacir;": '\U00002A6F', + "ape;": '\U0000224A', + "apid;": '\U0000224B', + "apos;": '\U00000027', + "approx;": '\U00002248', + "approxeq;": '\U0000224A', + "aring;": '\U000000E5', + "ascr;": '\U0001D4B6', + "ast;": '\U0000002A', + "asymp;": '\U00002248', + "asympeq;": '\U0000224D', + "atilde;": '\U000000E3', + "auml;": '\U000000E4', + "awconint;": '\U00002233', + "awint;": '\U00002A11', + "bNot;": '\U00002AED', + "backcong;": '\U0000224C', + "backepsilon;": '\U000003F6', + "backprime;": '\U00002035', + "backsim;": '\U0000223D', + "backsimeq;": '\U000022CD', + "barvee;": '\U000022BD', + "barwed;": '\U00002305', + "barwedge;": '\U00002305', + "bbrk;": '\U000023B5', + "bbrktbrk;": '\U000023B6', + "bcong;": '\U0000224C', + "bcy;": '\U00000431', + "bdquo;": '\U0000201E', + "becaus;": '\U00002235', + "because;": '\U00002235', + "bemptyv;": '\U000029B0', + "bepsi;": '\U000003F6', + "bernou;": '\U0000212C', + "beta;": '\U000003B2', + "beth;": '\U00002136', + "between;": '\U0000226C', + "bfr;": '\U0001D51F', + "bigcap;": '\U000022C2', + "bigcirc;": '\U000025EF', + "bigcup;": '\U000022C3', + "bigodot;": '\U00002A00', + "bigoplus;": '\U00002A01', + "bigotimes;": '\U00002A02', + "bigsqcup;": '\U00002A06', + "bigstar;": '\U00002605', + "bigtriangledown;": '\U000025BD', + "bigtriangleup;": '\U000025B3', + "biguplus;": '\U00002A04', + "bigvee;": '\U000022C1', + "bigwedge;": '\U000022C0', + "bkarow;": '\U0000290D', + "blacklozenge;": '\U000029EB', + "blacksquare;": '\U000025AA', + "blacktriangle;": '\U000025B4', + "blacktriangledown;": '\U000025BE', + "blacktriangleleft;": '\U000025C2', + "blacktriangleright;": '\U000025B8', + "blank;": '\U00002423', + "blk12;": '\U00002592', + "blk14;": '\U00002591', + "blk34;": '\U00002593', + "block;": '\U00002588', + "bnot;": '\U00002310', + "bopf;": '\U0001D553', + "bot;": '\U000022A5', + "bottom;": '\U000022A5', + "bowtie;": '\U000022C8', + "boxDL;": '\U00002557', + "boxDR;": '\U00002554', + "boxDl;": '\U00002556', + "boxDr;": '\U00002553', + "boxH;": '\U00002550', + "boxHD;": '\U00002566', + "boxHU;": '\U00002569', + "boxHd;": '\U00002564', + "boxHu;": '\U00002567', + "boxUL;": '\U0000255D', + "boxUR;": '\U0000255A', + "boxUl;": '\U0000255C', + "boxUr;": '\U00002559', + "boxV;": '\U00002551', + "boxVH;": '\U0000256C', + "boxVL;": '\U00002563', + "boxVR;": '\U00002560', + "boxVh;": '\U0000256B', + "boxVl;": '\U00002562', + "boxVr;": '\U0000255F', + "boxbox;": '\U000029C9', + "boxdL;": '\U00002555', + "boxdR;": '\U00002552', + "boxdl;": '\U00002510', + "boxdr;": '\U0000250C', + "boxh;": '\U00002500', + "boxhD;": '\U00002565', + "boxhU;": '\U00002568', + "boxhd;": '\U0000252C', + "boxhu;": '\U00002534', + "boxminus;": '\U0000229F', + "boxplus;": '\U0000229E', + "boxtimes;": '\U000022A0', + "boxuL;": '\U0000255B', + "boxuR;": '\U00002558', + "boxul;": '\U00002518', + "boxur;": '\U00002514', + "boxv;": '\U00002502', + "boxvH;": '\U0000256A', + "boxvL;": '\U00002561', + "boxvR;": '\U0000255E', + "boxvh;": '\U0000253C', + "boxvl;": '\U00002524', + "boxvr;": '\U0000251C', + "bprime;": '\U00002035', + "breve;": '\U000002D8', + "brvbar;": '\U000000A6', + "bscr;": '\U0001D4B7', + "bsemi;": '\U0000204F', + "bsim;": '\U0000223D', + "bsime;": '\U000022CD', + "bsol;": '\U0000005C', + "bsolb;": '\U000029C5', + "bsolhsub;": '\U000027C8', + "bull;": '\U00002022', + "bullet;": '\U00002022', + "bump;": '\U0000224E', + "bumpE;": '\U00002AAE', + "bumpe;": '\U0000224F', + "bumpeq;": '\U0000224F', + "cacute;": '\U00000107', + "cap;": '\U00002229', + "capand;": '\U00002A44', + "capbrcup;": '\U00002A49', + "capcap;": '\U00002A4B', + "capcup;": '\U00002A47', + "capdot;": '\U00002A40', + "caret;": '\U00002041', + "caron;": '\U000002C7', + "ccaps;": '\U00002A4D', + "ccaron;": '\U0000010D', + "ccedil;": '\U000000E7', + "ccirc;": '\U00000109', + "ccups;": '\U00002A4C', + "ccupssm;": '\U00002A50', + "cdot;": '\U0000010B', + "cedil;": '\U000000B8', + "cemptyv;": '\U000029B2', + "cent;": '\U000000A2', + "centerdot;": '\U000000B7', + "cfr;": '\U0001D520', + "chcy;": '\U00000447', + "check;": '\U00002713', + "checkmark;": '\U00002713', + "chi;": '\U000003C7', + "cir;": '\U000025CB', + "cirE;": '\U000029C3', + "circ;": '\U000002C6', + "circeq;": '\U00002257', + "circlearrowleft;": '\U000021BA', + "circlearrowright;": '\U000021BB', + "circledR;": '\U000000AE', + "circledS;": '\U000024C8', + "circledast;": '\U0000229B', + "circledcirc;": '\U0000229A', + "circleddash;": '\U0000229D', + "cire;": '\U00002257', + "cirfnint;": '\U00002A10', + "cirmid;": '\U00002AEF', + "cirscir;": '\U000029C2', + "clubs;": '\U00002663', + "clubsuit;": '\U00002663', + "colon;": '\U0000003A', + "colone;": '\U00002254', + "coloneq;": '\U00002254', + "comma;": '\U0000002C', + "commat;": '\U00000040', + "comp;": '\U00002201', + "compfn;": '\U00002218', + "complement;": '\U00002201', + "complexes;": '\U00002102', + "cong;": '\U00002245', + "congdot;": '\U00002A6D', + "conint;": '\U0000222E', + "copf;": '\U0001D554', + "coprod;": '\U00002210', + "copy;": '\U000000A9', + "copysr;": '\U00002117', + "crarr;": '\U000021B5', + "cross;": '\U00002717', + "cscr;": '\U0001D4B8', + "csub;": '\U00002ACF', + "csube;": '\U00002AD1', + "csup;": '\U00002AD0', + "csupe;": '\U00002AD2', + "ctdot;": '\U000022EF', + "cudarrl;": '\U00002938', + "cudarrr;": '\U00002935', + "cuepr;": '\U000022DE', + "cuesc;": '\U000022DF', + "cularr;": '\U000021B6', + "cularrp;": '\U0000293D', + "cup;": '\U0000222A', + "cupbrcap;": '\U00002A48', + "cupcap;": '\U00002A46', + "cupcup;": '\U00002A4A', + "cupdot;": '\U0000228D', + "cupor;": '\U00002A45', + "curarr;": '\U000021B7', + "curarrm;": '\U0000293C', + "curlyeqprec;": '\U000022DE', + "curlyeqsucc;": '\U000022DF', + "curlyvee;": '\U000022CE', + "curlywedge;": '\U000022CF', + "curren;": '\U000000A4', + "curvearrowleft;": '\U000021B6', + "curvearrowright;": '\U000021B7', + "cuvee;": '\U000022CE', + "cuwed;": '\U000022CF', + "cwconint;": '\U00002232', + "cwint;": '\U00002231', + "cylcty;": '\U0000232D', + "dArr;": '\U000021D3', + "dHar;": '\U00002965', + "dagger;": '\U00002020', + "daleth;": '\U00002138', + "darr;": '\U00002193', + "dash;": '\U00002010', + "dashv;": '\U000022A3', + "dbkarow;": '\U0000290F', + "dblac;": '\U000002DD', + "dcaron;": '\U0000010F', + "dcy;": '\U00000434', + "dd;": '\U00002146', + "ddagger;": '\U00002021', + "ddarr;": '\U000021CA', + "ddotseq;": '\U00002A77', + "deg;": '\U000000B0', + "delta;": '\U000003B4', + "demptyv;": '\U000029B1', + "dfisht;": '\U0000297F', + "dfr;": '\U0001D521', + "dharl;": '\U000021C3', + "dharr;": '\U000021C2', + "diam;": '\U000022C4', + "diamond;": '\U000022C4', + "diamondsuit;": '\U00002666', + "diams;": '\U00002666', + "die;": '\U000000A8', + "digamma;": '\U000003DD', + "disin;": '\U000022F2', + "div;": '\U000000F7', + "divide;": '\U000000F7', + "divideontimes;": '\U000022C7', + "divonx;": '\U000022C7', + "djcy;": '\U00000452', + "dlcorn;": '\U0000231E', + "dlcrop;": '\U0000230D', + "dollar;": '\U00000024', + "dopf;": '\U0001D555', + "dot;": '\U000002D9', + "doteq;": '\U00002250', + "doteqdot;": '\U00002251', + "dotminus;": '\U00002238', + "dotplus;": '\U00002214', + "dotsquare;": '\U000022A1', + "doublebarwedge;": '\U00002306', + "downarrow;": '\U00002193', + "downdownarrows;": '\U000021CA', + "downharpoonleft;": '\U000021C3', + "downharpoonright;": '\U000021C2', + "drbkarow;": '\U00002910', + "drcorn;": '\U0000231F', + "drcrop;": '\U0000230C', + "dscr;": '\U0001D4B9', + "dscy;": '\U00000455', + "dsol;": '\U000029F6', + "dstrok;": '\U00000111', + "dtdot;": '\U000022F1', + "dtri;": '\U000025BF', + "dtrif;": '\U000025BE', + "duarr;": '\U000021F5', + "duhar;": '\U0000296F', + "dwangle;": '\U000029A6', + "dzcy;": '\U0000045F', + "dzigrarr;": '\U000027FF', + "eDDot;": '\U00002A77', + "eDot;": '\U00002251', + "eacute;": '\U000000E9', + "easter;": '\U00002A6E', + "ecaron;": '\U0000011B', + "ecir;": '\U00002256', + "ecirc;": '\U000000EA', + "ecolon;": '\U00002255', + "ecy;": '\U0000044D', + "edot;": '\U00000117', + "ee;": '\U00002147', + "efDot;": '\U00002252', + "efr;": '\U0001D522', + "eg;": '\U00002A9A', + "egrave;": '\U000000E8', + "egs;": '\U00002A96', + "egsdot;": '\U00002A98', + "el;": '\U00002A99', + "elinters;": '\U000023E7', + "ell;": '\U00002113', + "els;": '\U00002A95', + "elsdot;": '\U00002A97', + "emacr;": '\U00000113', + "empty;": '\U00002205', + "emptyset;": '\U00002205', + "emptyv;": '\U00002205', + "emsp;": '\U00002003', + "emsp13;": '\U00002004', + "emsp14;": '\U00002005', + "eng;": '\U0000014B', + "ensp;": '\U00002002', + "eogon;": '\U00000119', + "eopf;": '\U0001D556', + "epar;": '\U000022D5', + "eparsl;": '\U000029E3', + "eplus;": '\U00002A71', + "epsi;": '\U000003B5', + "epsilon;": '\U000003B5', + "epsiv;": '\U000003F5', + "eqcirc;": '\U00002256', + "eqcolon;": '\U00002255', + "eqsim;": '\U00002242', + "eqslantgtr;": '\U00002A96', + "eqslantless;": '\U00002A95', + "equals;": '\U0000003D', + "equest;": '\U0000225F', + "equiv;": '\U00002261', + "equivDD;": '\U00002A78', + "eqvparsl;": '\U000029E5', + "erDot;": '\U00002253', + "erarr;": '\U00002971', + "escr;": '\U0000212F', + "esdot;": '\U00002250', + "esim;": '\U00002242', + "eta;": '\U000003B7', + "eth;": '\U000000F0', + "euml;": '\U000000EB', + "euro;": '\U000020AC', + "excl;": '\U00000021', + "exist;": '\U00002203', + "expectation;": '\U00002130', + "exponentiale;": '\U00002147', + "fallingdotseq;": '\U00002252', + "fcy;": '\U00000444', + "female;": '\U00002640', + "ffilig;": '\U0000FB03', + "fflig;": '\U0000FB00', + "ffllig;": '\U0000FB04', + "ffr;": '\U0001D523', + "filig;": '\U0000FB01', + "flat;": '\U0000266D', + "fllig;": '\U0000FB02', + "fltns;": '\U000025B1', + "fnof;": '\U00000192', + "fopf;": '\U0001D557', + "forall;": '\U00002200', + "fork;": '\U000022D4', + "forkv;": '\U00002AD9', + "fpartint;": '\U00002A0D', + "frac12;": '\U000000BD', + "frac13;": '\U00002153', + "frac14;": '\U000000BC', + "frac15;": '\U00002155', + "frac16;": '\U00002159', + "frac18;": '\U0000215B', + "frac23;": '\U00002154', + "frac25;": '\U00002156', + "frac34;": '\U000000BE', + "frac35;": '\U00002157', + "frac38;": '\U0000215C', + "frac45;": '\U00002158', + "frac56;": '\U0000215A', + "frac58;": '\U0000215D', + "frac78;": '\U0000215E', + "frasl;": '\U00002044', + "frown;": '\U00002322', + "fscr;": '\U0001D4BB', + "gE;": '\U00002267', + "gEl;": '\U00002A8C', + "gacute;": '\U000001F5', + "gamma;": '\U000003B3', + "gammad;": '\U000003DD', + "gap;": '\U00002A86', + "gbreve;": '\U0000011F', + "gcirc;": '\U0000011D', + "gcy;": '\U00000433', + "gdot;": '\U00000121', + "ge;": '\U00002265', + "gel;": '\U000022DB', + "geq;": '\U00002265', + "geqq;": '\U00002267', + "geqslant;": '\U00002A7E', + "ges;": '\U00002A7E', + "gescc;": '\U00002AA9', + "gesdot;": '\U00002A80', + "gesdoto;": '\U00002A82', + "gesdotol;": '\U00002A84', + "gesles;": '\U00002A94', + "gfr;": '\U0001D524', + "gg;": '\U0000226B', + "ggg;": '\U000022D9', + "gimel;": '\U00002137', + "gjcy;": '\U00000453', + "gl;": '\U00002277', + "glE;": '\U00002A92', + "gla;": '\U00002AA5', + "glj;": '\U00002AA4', + "gnE;": '\U00002269', + "gnap;": '\U00002A8A', + "gnapprox;": '\U00002A8A', + "gne;": '\U00002A88', + "gneq;": '\U00002A88', + "gneqq;": '\U00002269', + "gnsim;": '\U000022E7', + "gopf;": '\U0001D558', + "grave;": '\U00000060', + "gscr;": '\U0000210A', + "gsim;": '\U00002273', + "gsime;": '\U00002A8E', + "gsiml;": '\U00002A90', + "gt;": '\U0000003E', + "gtcc;": '\U00002AA7', + "gtcir;": '\U00002A7A', + "gtdot;": '\U000022D7', + "gtlPar;": '\U00002995', + "gtquest;": '\U00002A7C', + "gtrapprox;": '\U00002A86', + "gtrarr;": '\U00002978', + "gtrdot;": '\U000022D7', + "gtreqless;": '\U000022DB', + "gtreqqless;": '\U00002A8C', + "gtrless;": '\U00002277', + "gtrsim;": '\U00002273', + "hArr;": '\U000021D4', + "hairsp;": '\U0000200A', + "half;": '\U000000BD', + "hamilt;": '\U0000210B', + "hardcy;": '\U0000044A', + "harr;": '\U00002194', + "harrcir;": '\U00002948', + "harrw;": '\U000021AD', + "hbar;": '\U0000210F', + "hcirc;": '\U00000125', + "hearts;": '\U00002665', + "heartsuit;": '\U00002665', + "hellip;": '\U00002026', + "hercon;": '\U000022B9', + "hfr;": '\U0001D525', + "hksearow;": '\U00002925', + "hkswarow;": '\U00002926', + "hoarr;": '\U000021FF', + "homtht;": '\U0000223B', + "hookleftarrow;": '\U000021A9', + "hookrightarrow;": '\U000021AA', + "hopf;": '\U0001D559', + "horbar;": '\U00002015', + "hscr;": '\U0001D4BD', + "hslash;": '\U0000210F', + "hstrok;": '\U00000127', + "hybull;": '\U00002043', + "hyphen;": '\U00002010', + "iacute;": '\U000000ED', + "ic;": '\U00002063', + "icirc;": '\U000000EE', + "icy;": '\U00000438', + "iecy;": '\U00000435', + "iexcl;": '\U000000A1', + "iff;": '\U000021D4', + "ifr;": '\U0001D526', + "igrave;": '\U000000EC', + "ii;": '\U00002148', + "iiiint;": '\U00002A0C', + "iiint;": '\U0000222D', + "iinfin;": '\U000029DC', + "iiota;": '\U00002129', + "ijlig;": '\U00000133', + "imacr;": '\U0000012B', + "image;": '\U00002111', + "imagline;": '\U00002110', + "imagpart;": '\U00002111', + "imath;": '\U00000131', + "imof;": '\U000022B7', + "imped;": '\U000001B5', + "in;": '\U00002208', + "incare;": '\U00002105', + "infin;": '\U0000221E', + "infintie;": '\U000029DD', + "inodot;": '\U00000131', + "int;": '\U0000222B', + "intcal;": '\U000022BA', + "integers;": '\U00002124', + "intercal;": '\U000022BA', + "intlarhk;": '\U00002A17', + "intprod;": '\U00002A3C', + "iocy;": '\U00000451', + "iogon;": '\U0000012F', + "iopf;": '\U0001D55A', + "iota;": '\U000003B9', + "iprod;": '\U00002A3C', + "iquest;": '\U000000BF', + "iscr;": '\U0001D4BE', + "isin;": '\U00002208', + "isinE;": '\U000022F9', + "isindot;": '\U000022F5', + "isins;": '\U000022F4', + "isinsv;": '\U000022F3', + "isinv;": '\U00002208', + "it;": '\U00002062', + "itilde;": '\U00000129', + "iukcy;": '\U00000456', + "iuml;": '\U000000EF', + "jcirc;": '\U00000135', + "jcy;": '\U00000439', + "jfr;": '\U0001D527', + "jmath;": '\U00000237', + "jopf;": '\U0001D55B', + "jscr;": '\U0001D4BF', + "jsercy;": '\U00000458', + "jukcy;": '\U00000454', + "kappa;": '\U000003BA', + "kappav;": '\U000003F0', + "kcedil;": '\U00000137', + "kcy;": '\U0000043A', + "kfr;": '\U0001D528', + "kgreen;": '\U00000138', + "khcy;": '\U00000445', + "kjcy;": '\U0000045C', + "kopf;": '\U0001D55C', + "kscr;": '\U0001D4C0', + "lAarr;": '\U000021DA', + "lArr;": '\U000021D0', + "lAtail;": '\U0000291B', + "lBarr;": '\U0000290E', + "lE;": '\U00002266', + "lEg;": '\U00002A8B', + "lHar;": '\U00002962', + "lacute;": '\U0000013A', + "laemptyv;": '\U000029B4', + "lagran;": '\U00002112', + "lambda;": '\U000003BB', + "lang;": '\U000027E8', + "langd;": '\U00002991', + "langle;": '\U000027E8', + "lap;": '\U00002A85', + "laquo;": '\U000000AB', + "larr;": '\U00002190', + "larrb;": '\U000021E4', + "larrbfs;": '\U0000291F', + "larrfs;": '\U0000291D', + "larrhk;": '\U000021A9', + "larrlp;": '\U000021AB', + "larrpl;": '\U00002939', + "larrsim;": '\U00002973', + "larrtl;": '\U000021A2', + "lat;": '\U00002AAB', + "latail;": '\U00002919', + "late;": '\U00002AAD', + "lbarr;": '\U0000290C', + "lbbrk;": '\U00002772', + "lbrace;": '\U0000007B', + "lbrack;": '\U0000005B', + "lbrke;": '\U0000298B', + "lbrksld;": '\U0000298F', + "lbrkslu;": '\U0000298D', + "lcaron;": '\U0000013E', + "lcedil;": '\U0000013C', + "lceil;": '\U00002308', + "lcub;": '\U0000007B', + "lcy;": '\U0000043B', + "ldca;": '\U00002936', + "ldquo;": '\U0000201C', + "ldquor;": '\U0000201E', + "ldrdhar;": '\U00002967', + "ldrushar;": '\U0000294B', + "ldsh;": '\U000021B2', + "le;": '\U00002264', + "leftarrow;": '\U00002190', + "leftarrowtail;": '\U000021A2', + "leftharpoondown;": '\U000021BD', + "leftharpoonup;": '\U000021BC', + "leftleftarrows;": '\U000021C7', + "leftrightarrow;": '\U00002194', + "leftrightarrows;": '\U000021C6', + "leftrightharpoons;": '\U000021CB', + "leftrightsquigarrow;": '\U000021AD', + "leftthreetimes;": '\U000022CB', + "leg;": '\U000022DA', + "leq;": '\U00002264', + "leqq;": '\U00002266', + "leqslant;": '\U00002A7D', + "les;": '\U00002A7D', + "lescc;": '\U00002AA8', + "lesdot;": '\U00002A7F', + "lesdoto;": '\U00002A81', + "lesdotor;": '\U00002A83', + "lesges;": '\U00002A93', + "lessapprox;": '\U00002A85', + "lessdot;": '\U000022D6', + "lesseqgtr;": '\U000022DA', + "lesseqqgtr;": '\U00002A8B', + "lessgtr;": '\U00002276', + "lesssim;": '\U00002272', + "lfisht;": '\U0000297C', + "lfloor;": '\U0000230A', + "lfr;": '\U0001D529', + "lg;": '\U00002276', + "lgE;": '\U00002A91', + "lhard;": '\U000021BD', + "lharu;": '\U000021BC', + "lharul;": '\U0000296A', + "lhblk;": '\U00002584', + "ljcy;": '\U00000459', + "ll;": '\U0000226A', + "llarr;": '\U000021C7', + "llcorner;": '\U0000231E', + "llhard;": '\U0000296B', + "lltri;": '\U000025FA', + "lmidot;": '\U00000140', + "lmoust;": '\U000023B0', + "lmoustache;": '\U000023B0', + "lnE;": '\U00002268', + "lnap;": '\U00002A89', + "lnapprox;": '\U00002A89', + "lne;": '\U00002A87', + "lneq;": '\U00002A87', + "lneqq;": '\U00002268', + "lnsim;": '\U000022E6', + "loang;": '\U000027EC', + "loarr;": '\U000021FD', + "lobrk;": '\U000027E6', + "longleftarrow;": '\U000027F5', + "longleftrightarrow;": '\U000027F7', + "longmapsto;": '\U000027FC', + "longrightarrow;": '\U000027F6', + "looparrowleft;": '\U000021AB', + "looparrowright;": '\U000021AC', + "lopar;": '\U00002985', + "lopf;": '\U0001D55D', + "loplus;": '\U00002A2D', + "lotimes;": '\U00002A34', + "lowast;": '\U00002217', + "lowbar;": '\U0000005F', + "loz;": '\U000025CA', + "lozenge;": '\U000025CA', + "lozf;": '\U000029EB', + "lpar;": '\U00000028', + "lparlt;": '\U00002993', + "lrarr;": '\U000021C6', + "lrcorner;": '\U0000231F', + "lrhar;": '\U000021CB', + "lrhard;": '\U0000296D', + "lrm;": '\U0000200E', + "lrtri;": '\U000022BF', + "lsaquo;": '\U00002039', + "lscr;": '\U0001D4C1', + "lsh;": '\U000021B0', + "lsim;": '\U00002272', + "lsime;": '\U00002A8D', + "lsimg;": '\U00002A8F', + "lsqb;": '\U0000005B', + "lsquo;": '\U00002018', + "lsquor;": '\U0000201A', + "lstrok;": '\U00000142', + "lt;": '\U0000003C', + "ltcc;": '\U00002AA6', + "ltcir;": '\U00002A79', + "ltdot;": '\U000022D6', + "lthree;": '\U000022CB', + "ltimes;": '\U000022C9', + "ltlarr;": '\U00002976', + "ltquest;": '\U00002A7B', + "ltrPar;": '\U00002996', + "ltri;": '\U000025C3', + "ltrie;": '\U000022B4', + "ltrif;": '\U000025C2', + "lurdshar;": '\U0000294A', + "luruhar;": '\U00002966', + "mDDot;": '\U0000223A', + "macr;": '\U000000AF', + "male;": '\U00002642', + "malt;": '\U00002720', + "maltese;": '\U00002720', + "map;": '\U000021A6', + "mapsto;": '\U000021A6', + "mapstodown;": '\U000021A7', + "mapstoleft;": '\U000021A4', + "mapstoup;": '\U000021A5', + "marker;": '\U000025AE', + "mcomma;": '\U00002A29', + "mcy;": '\U0000043C', + "mdash;": '\U00002014', + "measuredangle;": '\U00002221', + "mfr;": '\U0001D52A', + "mho;": '\U00002127', + "micro;": '\U000000B5', + "mid;": '\U00002223', + "midast;": '\U0000002A', + "midcir;": '\U00002AF0', + "middot;": '\U000000B7', + "minus;": '\U00002212', + "minusb;": '\U0000229F', + "minusd;": '\U00002238', + "minusdu;": '\U00002A2A', + "mlcp;": '\U00002ADB', + "mldr;": '\U00002026', + "mnplus;": '\U00002213', + "models;": '\U000022A7', + "mopf;": '\U0001D55E', + "mp;": '\U00002213', + "mscr;": '\U0001D4C2', + "mstpos;": '\U0000223E', + "mu;": '\U000003BC', + "multimap;": '\U000022B8', + "mumap;": '\U000022B8', + "nLeftarrow;": '\U000021CD', + "nLeftrightarrow;": '\U000021CE', + "nRightarrow;": '\U000021CF', + "nVDash;": '\U000022AF', + "nVdash;": '\U000022AE', + "nabla;": '\U00002207', + "nacute;": '\U00000144', + "nap;": '\U00002249', + "napos;": '\U00000149', + "napprox;": '\U00002249', + "natur;": '\U0000266E', + "natural;": '\U0000266E', + "naturals;": '\U00002115', + "nbsp;": '\U000000A0', + "ncap;": '\U00002A43', + "ncaron;": '\U00000148', + "ncedil;": '\U00000146', + "ncong;": '\U00002247', + "ncup;": '\U00002A42', + "ncy;": '\U0000043D', + "ndash;": '\U00002013', + "ne;": '\U00002260', + "neArr;": '\U000021D7', + "nearhk;": '\U00002924', + "nearr;": '\U00002197', + "nearrow;": '\U00002197', + "nequiv;": '\U00002262', + "nesear;": '\U00002928', + "nexist;": '\U00002204', + "nexists;": '\U00002204', + "nfr;": '\U0001D52B', + "nge;": '\U00002271', + "ngeq;": '\U00002271', + "ngsim;": '\U00002275', + "ngt;": '\U0000226F', + "ngtr;": '\U0000226F', + "nhArr;": '\U000021CE', + "nharr;": '\U000021AE', + "nhpar;": '\U00002AF2', + "ni;": '\U0000220B', + "nis;": '\U000022FC', + "nisd;": '\U000022FA', + "niv;": '\U0000220B', + "njcy;": '\U0000045A', + "nlArr;": '\U000021CD', + "nlarr;": '\U0000219A', + "nldr;": '\U00002025', + "nle;": '\U00002270', + "nleftarrow;": '\U0000219A', + "nleftrightarrow;": '\U000021AE', + "nleq;": '\U00002270', + "nless;": '\U0000226E', + "nlsim;": '\U00002274', + "nlt;": '\U0000226E', + "nltri;": '\U000022EA', + "nltrie;": '\U000022EC', + "nmid;": '\U00002224', + "nopf;": '\U0001D55F', + "not;": '\U000000AC', + "notin;": '\U00002209', + "notinva;": '\U00002209', + "notinvb;": '\U000022F7', + "notinvc;": '\U000022F6', + "notni;": '\U0000220C', + "notniva;": '\U0000220C', + "notnivb;": '\U000022FE', + "notnivc;": '\U000022FD', + "npar;": '\U00002226', + "nparallel;": '\U00002226', + "npolint;": '\U00002A14', + "npr;": '\U00002280', + "nprcue;": '\U000022E0', + "nprec;": '\U00002280', + "nrArr;": '\U000021CF', + "nrarr;": '\U0000219B', + "nrightarrow;": '\U0000219B', + "nrtri;": '\U000022EB', + "nrtrie;": '\U000022ED', + "nsc;": '\U00002281', + "nsccue;": '\U000022E1', + "nscr;": '\U0001D4C3', + "nshortmid;": '\U00002224', + "nshortparallel;": '\U00002226', + "nsim;": '\U00002241', + "nsime;": '\U00002244', + "nsimeq;": '\U00002244', + "nsmid;": '\U00002224', + "nspar;": '\U00002226', + "nsqsube;": '\U000022E2', + "nsqsupe;": '\U000022E3', + "nsub;": '\U00002284', + "nsube;": '\U00002288', + "nsubseteq;": '\U00002288', + "nsucc;": '\U00002281', + "nsup;": '\U00002285', + "nsupe;": '\U00002289', + "nsupseteq;": '\U00002289', + "ntgl;": '\U00002279', + "ntilde;": '\U000000F1', + "ntlg;": '\U00002278', + "ntriangleleft;": '\U000022EA', + "ntrianglelefteq;": '\U000022EC', + "ntriangleright;": '\U000022EB', + "ntrianglerighteq;": '\U000022ED', + "nu;": '\U000003BD', + "num;": '\U00000023', + "numero;": '\U00002116', + "numsp;": '\U00002007', + "nvDash;": '\U000022AD', + "nvHarr;": '\U00002904', + "nvdash;": '\U000022AC', + "nvinfin;": '\U000029DE', + "nvlArr;": '\U00002902', + "nvrArr;": '\U00002903', + "nwArr;": '\U000021D6', + "nwarhk;": '\U00002923', + "nwarr;": '\U00002196', + "nwarrow;": '\U00002196', + "nwnear;": '\U00002927', + "oS;": '\U000024C8', + "oacute;": '\U000000F3', + "oast;": '\U0000229B', + "ocir;": '\U0000229A', + "ocirc;": '\U000000F4', + "ocy;": '\U0000043E', + "odash;": '\U0000229D', + "odblac;": '\U00000151', + "odiv;": '\U00002A38', + "odot;": '\U00002299', + "odsold;": '\U000029BC', + "oelig;": '\U00000153', + "ofcir;": '\U000029BF', + "ofr;": '\U0001D52C', + "ogon;": '\U000002DB', + "ograve;": '\U000000F2', + "ogt;": '\U000029C1', + "ohbar;": '\U000029B5', + "ohm;": '\U000003A9', + "oint;": '\U0000222E', + "olarr;": '\U000021BA', + "olcir;": '\U000029BE', + "olcross;": '\U000029BB', + "oline;": '\U0000203E', + "olt;": '\U000029C0', + "omacr;": '\U0000014D', + "omega;": '\U000003C9', + "omicron;": '\U000003BF', + "omid;": '\U000029B6', + "ominus;": '\U00002296', + "oopf;": '\U0001D560', + "opar;": '\U000029B7', + "operp;": '\U000029B9', + "oplus;": '\U00002295', + "or;": '\U00002228', + "orarr;": '\U000021BB', + "ord;": '\U00002A5D', + "order;": '\U00002134', + "orderof;": '\U00002134', + "ordf;": '\U000000AA', + "ordm;": '\U000000BA', + "origof;": '\U000022B6', + "oror;": '\U00002A56', + "orslope;": '\U00002A57', + "orv;": '\U00002A5B', + "oscr;": '\U00002134', + "oslash;": '\U000000F8', + "osol;": '\U00002298', + "otilde;": '\U000000F5', + "otimes;": '\U00002297', + "otimesas;": '\U00002A36', + "ouml;": '\U000000F6', + "ovbar;": '\U0000233D', + "par;": '\U00002225', + "para;": '\U000000B6', + "parallel;": '\U00002225', + "parsim;": '\U00002AF3', + "parsl;": '\U00002AFD', + "part;": '\U00002202', + "pcy;": '\U0000043F', + "percnt;": '\U00000025', + "period;": '\U0000002E', + "permil;": '\U00002030', + "perp;": '\U000022A5', + "pertenk;": '\U00002031', + "pfr;": '\U0001D52D', + "phi;": '\U000003C6', + "phiv;": '\U000003D5', + "phmmat;": '\U00002133', + "phone;": '\U0000260E', + "pi;": '\U000003C0', + "pitchfork;": '\U000022D4', + "piv;": '\U000003D6', + "planck;": '\U0000210F', + "planckh;": '\U0000210E', + "plankv;": '\U0000210F', + "plus;": '\U0000002B', + "plusacir;": '\U00002A23', + "plusb;": '\U0000229E', + "pluscir;": '\U00002A22', + "plusdo;": '\U00002214', + "plusdu;": '\U00002A25', + "pluse;": '\U00002A72', + "plusmn;": '\U000000B1', + "plussim;": '\U00002A26', + "plustwo;": '\U00002A27', + "pm;": '\U000000B1', + "pointint;": '\U00002A15', + "popf;": '\U0001D561', + "pound;": '\U000000A3', + "pr;": '\U0000227A', + "prE;": '\U00002AB3', + "prap;": '\U00002AB7', + "prcue;": '\U0000227C', + "pre;": '\U00002AAF', + "prec;": '\U0000227A', + "precapprox;": '\U00002AB7', + "preccurlyeq;": '\U0000227C', + "preceq;": '\U00002AAF', + "precnapprox;": '\U00002AB9', + "precneqq;": '\U00002AB5', + "precnsim;": '\U000022E8', + "precsim;": '\U0000227E', + "prime;": '\U00002032', + "primes;": '\U00002119', + "prnE;": '\U00002AB5', + "prnap;": '\U00002AB9', + "prnsim;": '\U000022E8', + "prod;": '\U0000220F', + "profalar;": '\U0000232E', + "profline;": '\U00002312', + "profsurf;": '\U00002313', + "prop;": '\U0000221D', + "propto;": '\U0000221D', + "prsim;": '\U0000227E', + "prurel;": '\U000022B0', + "pscr;": '\U0001D4C5', + "psi;": '\U000003C8', + "puncsp;": '\U00002008', + "qfr;": '\U0001D52E', + "qint;": '\U00002A0C', + "qopf;": '\U0001D562', + "qprime;": '\U00002057', + "qscr;": '\U0001D4C6', + "quaternions;": '\U0000210D', + "quatint;": '\U00002A16', + "quest;": '\U0000003F', + "questeq;": '\U0000225F', + "quot;": '\U00000022', + "rAarr;": '\U000021DB', + "rArr;": '\U000021D2', + "rAtail;": '\U0000291C', + "rBarr;": '\U0000290F', + "rHar;": '\U00002964', + "racute;": '\U00000155', + "radic;": '\U0000221A', + "raemptyv;": '\U000029B3', + "rang;": '\U000027E9', + "rangd;": '\U00002992', + "range;": '\U000029A5', + "rangle;": '\U000027E9', + "raquo;": '\U000000BB', + "rarr;": '\U00002192', + "rarrap;": '\U00002975', + "rarrb;": '\U000021E5', + "rarrbfs;": '\U00002920', + "rarrc;": '\U00002933', + "rarrfs;": '\U0000291E', + "rarrhk;": '\U000021AA', + "rarrlp;": '\U000021AC', + "rarrpl;": '\U00002945', + "rarrsim;": '\U00002974', + "rarrtl;": '\U000021A3', + "rarrw;": '\U0000219D', + "ratail;": '\U0000291A', + "ratio;": '\U00002236', + "rationals;": '\U0000211A', + "rbarr;": '\U0000290D', + "rbbrk;": '\U00002773', + "rbrace;": '\U0000007D', + "rbrack;": '\U0000005D', + "rbrke;": '\U0000298C', + "rbrksld;": '\U0000298E', + "rbrkslu;": '\U00002990', + "rcaron;": '\U00000159', + "rcedil;": '\U00000157', + "rceil;": '\U00002309', + "rcub;": '\U0000007D', + "rcy;": '\U00000440', + "rdca;": '\U00002937', + "rdldhar;": '\U00002969', + "rdquo;": '\U0000201D', + "rdquor;": '\U0000201D', + "rdsh;": '\U000021B3', + "real;": '\U0000211C', + "realine;": '\U0000211B', + "realpart;": '\U0000211C', + "reals;": '\U0000211D', + "rect;": '\U000025AD', + "reg;": '\U000000AE', + "rfisht;": '\U0000297D', + "rfloor;": '\U0000230B', + "rfr;": '\U0001D52F', + "rhard;": '\U000021C1', + "rharu;": '\U000021C0', + "rharul;": '\U0000296C', + "rho;": '\U000003C1', + "rhov;": '\U000003F1', + "rightarrow;": '\U00002192', + "rightarrowtail;": '\U000021A3', + "rightharpoondown;": '\U000021C1', + "rightharpoonup;": '\U000021C0', + "rightleftarrows;": '\U000021C4', + "rightleftharpoons;": '\U000021CC', + "rightrightarrows;": '\U000021C9', + "rightsquigarrow;": '\U0000219D', + "rightthreetimes;": '\U000022CC', + "ring;": '\U000002DA', + "risingdotseq;": '\U00002253', + "rlarr;": '\U000021C4', + "rlhar;": '\U000021CC', + "rlm;": '\U0000200F', + "rmoust;": '\U000023B1', + "rmoustache;": '\U000023B1', + "rnmid;": '\U00002AEE', + "roang;": '\U000027ED', + "roarr;": '\U000021FE', + "robrk;": '\U000027E7', + "ropar;": '\U00002986', + "ropf;": '\U0001D563', + "roplus;": '\U00002A2E', + "rotimes;": '\U00002A35', + "rpar;": '\U00000029', + "rpargt;": '\U00002994', + "rppolint;": '\U00002A12', + "rrarr;": '\U000021C9', + "rsaquo;": '\U0000203A', + "rscr;": '\U0001D4C7', + "rsh;": '\U000021B1', + "rsqb;": '\U0000005D', + "rsquo;": '\U00002019', + "rsquor;": '\U00002019', + "rthree;": '\U000022CC', + "rtimes;": '\U000022CA', + "rtri;": '\U000025B9', + "rtrie;": '\U000022B5', + "rtrif;": '\U000025B8', + "rtriltri;": '\U000029CE', + "ruluhar;": '\U00002968', + "rx;": '\U0000211E', + "sacute;": '\U0000015B', + "sbquo;": '\U0000201A', + "sc;": '\U0000227B', + "scE;": '\U00002AB4', + "scap;": '\U00002AB8', + "scaron;": '\U00000161', + "sccue;": '\U0000227D', + "sce;": '\U00002AB0', + "scedil;": '\U0000015F', + "scirc;": '\U0000015D', + "scnE;": '\U00002AB6', + "scnap;": '\U00002ABA', + "scnsim;": '\U000022E9', + "scpolint;": '\U00002A13', + "scsim;": '\U0000227F', + "scy;": '\U00000441', + "sdot;": '\U000022C5', + "sdotb;": '\U000022A1', + "sdote;": '\U00002A66', + "seArr;": '\U000021D8', + "searhk;": '\U00002925', + "searr;": '\U00002198', + "searrow;": '\U00002198', + "sect;": '\U000000A7', + "semi;": '\U0000003B', + "seswar;": '\U00002929', + "setminus;": '\U00002216', + "setmn;": '\U00002216', + "sext;": '\U00002736', + "sfr;": '\U0001D530', + "sfrown;": '\U00002322', + "sharp;": '\U0000266F', + "shchcy;": '\U00000449', + "shcy;": '\U00000448', + "shortmid;": '\U00002223', + "shortparallel;": '\U00002225', + "shy;": '\U000000AD', + "sigma;": '\U000003C3', + "sigmaf;": '\U000003C2', + "sigmav;": '\U000003C2', + "sim;": '\U0000223C', + "simdot;": '\U00002A6A', + "sime;": '\U00002243', + "simeq;": '\U00002243', + "simg;": '\U00002A9E', + "simgE;": '\U00002AA0', + "siml;": '\U00002A9D', + "simlE;": '\U00002A9F', + "simne;": '\U00002246', + "simplus;": '\U00002A24', + "simrarr;": '\U00002972', + "slarr;": '\U00002190', + "smallsetminus;": '\U00002216', + "smashp;": '\U00002A33', + "smeparsl;": '\U000029E4', + "smid;": '\U00002223', + "smile;": '\U00002323', + "smt;": '\U00002AAA', + "smte;": '\U00002AAC', + "softcy;": '\U0000044C', + "sol;": '\U0000002F', + "solb;": '\U000029C4', + "solbar;": '\U0000233F', + "sopf;": '\U0001D564', + "spades;": '\U00002660', + "spadesuit;": '\U00002660', + "spar;": '\U00002225', + "sqcap;": '\U00002293', + "sqcup;": '\U00002294', + "sqsub;": '\U0000228F', + "sqsube;": '\U00002291', + "sqsubset;": '\U0000228F', + "sqsubseteq;": '\U00002291', + "sqsup;": '\U00002290', + "sqsupe;": '\U00002292', + "sqsupset;": '\U00002290', + "sqsupseteq;": '\U00002292', + "squ;": '\U000025A1', + "square;": '\U000025A1', + "squarf;": '\U000025AA', + "squf;": '\U000025AA', + "srarr;": '\U00002192', + "sscr;": '\U0001D4C8', + "ssetmn;": '\U00002216', + "ssmile;": '\U00002323', + "sstarf;": '\U000022C6', + "star;": '\U00002606', + "starf;": '\U00002605', + "straightepsilon;": '\U000003F5', + "straightphi;": '\U000003D5', + "strns;": '\U000000AF', + "sub;": '\U00002282', + "subE;": '\U00002AC5', + "subdot;": '\U00002ABD', + "sube;": '\U00002286', + "subedot;": '\U00002AC3', + "submult;": '\U00002AC1', + "subnE;": '\U00002ACB', + "subne;": '\U0000228A', + "subplus;": '\U00002ABF', + "subrarr;": '\U00002979', + "subset;": '\U00002282', + "subseteq;": '\U00002286', + "subseteqq;": '\U00002AC5', + "subsetneq;": '\U0000228A', + "subsetneqq;": '\U00002ACB', + "subsim;": '\U00002AC7', + "subsub;": '\U00002AD5', + "subsup;": '\U00002AD3', + "succ;": '\U0000227B', + "succapprox;": '\U00002AB8', + "succcurlyeq;": '\U0000227D', + "succeq;": '\U00002AB0', + "succnapprox;": '\U00002ABA', + "succneqq;": '\U00002AB6', + "succnsim;": '\U000022E9', + "succsim;": '\U0000227F', + "sum;": '\U00002211', + "sung;": '\U0000266A', + "sup;": '\U00002283', + "sup1;": '\U000000B9', + "sup2;": '\U000000B2', + "sup3;": '\U000000B3', + "supE;": '\U00002AC6', + "supdot;": '\U00002ABE', + "supdsub;": '\U00002AD8', + "supe;": '\U00002287', + "supedot;": '\U00002AC4', + "suphsol;": '\U000027C9', + "suphsub;": '\U00002AD7', + "suplarr;": '\U0000297B', + "supmult;": '\U00002AC2', + "supnE;": '\U00002ACC', + "supne;": '\U0000228B', + "supplus;": '\U00002AC0', + "supset;": '\U00002283', + "supseteq;": '\U00002287', + "supseteqq;": '\U00002AC6', + "supsetneq;": '\U0000228B', + "supsetneqq;": '\U00002ACC', + "supsim;": '\U00002AC8', + "supsub;": '\U00002AD4', + "supsup;": '\U00002AD6', + "swArr;": '\U000021D9', + "swarhk;": '\U00002926', + "swarr;": '\U00002199', + "swarrow;": '\U00002199', + "swnwar;": '\U0000292A', + "szlig;": '\U000000DF', + "target;": '\U00002316', + "tau;": '\U000003C4', + "tbrk;": '\U000023B4', + "tcaron;": '\U00000165', + "tcedil;": '\U00000163', + "tcy;": '\U00000442', + "tdot;": '\U000020DB', + "telrec;": '\U00002315', + "tfr;": '\U0001D531', + "there4;": '\U00002234', + "therefore;": '\U00002234', + "theta;": '\U000003B8', + "thetasym;": '\U000003D1', + "thetav;": '\U000003D1', + "thickapprox;": '\U00002248', + "thicksim;": '\U0000223C', + "thinsp;": '\U00002009', + "thkap;": '\U00002248', + "thksim;": '\U0000223C', + "thorn;": '\U000000FE', + "tilde;": '\U000002DC', + "times;": '\U000000D7', + "timesb;": '\U000022A0', + "timesbar;": '\U00002A31', + "timesd;": '\U00002A30', + "tint;": '\U0000222D', + "toea;": '\U00002928', + "top;": '\U000022A4', + "topbot;": '\U00002336', + "topcir;": '\U00002AF1', + "topf;": '\U0001D565', + "topfork;": '\U00002ADA', + "tosa;": '\U00002929', + "tprime;": '\U00002034', + "trade;": '\U00002122', + "triangle;": '\U000025B5', + "triangledown;": '\U000025BF', + "triangleleft;": '\U000025C3', + "trianglelefteq;": '\U000022B4', + "triangleq;": '\U0000225C', + "triangleright;": '\U000025B9', + "trianglerighteq;": '\U000022B5', + "tridot;": '\U000025EC', + "trie;": '\U0000225C', + "triminus;": '\U00002A3A', + "triplus;": '\U00002A39', + "trisb;": '\U000029CD', + "tritime;": '\U00002A3B', + "trpezium;": '\U000023E2', + "tscr;": '\U0001D4C9', + "tscy;": '\U00000446', + "tshcy;": '\U0000045B', + "tstrok;": '\U00000167', + "twixt;": '\U0000226C', + "twoheadleftarrow;": '\U0000219E', + "twoheadrightarrow;": '\U000021A0', + "uArr;": '\U000021D1', + "uHar;": '\U00002963', + "uacute;": '\U000000FA', + "uarr;": '\U00002191', + "ubrcy;": '\U0000045E', + "ubreve;": '\U0000016D', + "ucirc;": '\U000000FB', + "ucy;": '\U00000443', + "udarr;": '\U000021C5', + "udblac;": '\U00000171', + "udhar;": '\U0000296E', + "ufisht;": '\U0000297E', + "ufr;": '\U0001D532', + "ugrave;": '\U000000F9', + "uharl;": '\U000021BF', + "uharr;": '\U000021BE', + "uhblk;": '\U00002580', + "ulcorn;": '\U0000231C', + "ulcorner;": '\U0000231C', + "ulcrop;": '\U0000230F', + "ultri;": '\U000025F8', + "umacr;": '\U0000016B', + "uml;": '\U000000A8', + "uogon;": '\U00000173', + "uopf;": '\U0001D566', + "uparrow;": '\U00002191', + "updownarrow;": '\U00002195', + "upharpoonleft;": '\U000021BF', + "upharpoonright;": '\U000021BE', + "uplus;": '\U0000228E', + "upsi;": '\U000003C5', + "upsih;": '\U000003D2', + "upsilon;": '\U000003C5', + "upuparrows;": '\U000021C8', + "urcorn;": '\U0000231D', + "urcorner;": '\U0000231D', + "urcrop;": '\U0000230E', + "uring;": '\U0000016F', + "urtri;": '\U000025F9', + "uscr;": '\U0001D4CA', + "utdot;": '\U000022F0', + "utilde;": '\U00000169', + "utri;": '\U000025B5', + "utrif;": '\U000025B4', + "uuarr;": '\U000021C8', + "uuml;": '\U000000FC', + "uwangle;": '\U000029A7', + "vArr;": '\U000021D5', + "vBar;": '\U00002AE8', + "vBarv;": '\U00002AE9', + "vDash;": '\U000022A8', + "vangrt;": '\U0000299C', + "varepsilon;": '\U000003F5', + "varkappa;": '\U000003F0', + "varnothing;": '\U00002205', + "varphi;": '\U000003D5', + "varpi;": '\U000003D6', + "varpropto;": '\U0000221D', + "varr;": '\U00002195', + "varrho;": '\U000003F1', + "varsigma;": '\U000003C2', + "vartheta;": '\U000003D1', + "vartriangleleft;": '\U000022B2', + "vartriangleright;": '\U000022B3', + "vcy;": '\U00000432', + "vdash;": '\U000022A2', + "vee;": '\U00002228', + "veebar;": '\U000022BB', + "veeeq;": '\U0000225A', + "vellip;": '\U000022EE', + "verbar;": '\U0000007C', + "vert;": '\U0000007C', + "vfr;": '\U0001D533', + "vltri;": '\U000022B2', + "vopf;": '\U0001D567', + "vprop;": '\U0000221D', + "vrtri;": '\U000022B3', + "vscr;": '\U0001D4CB', + "vzigzag;": '\U0000299A', + "wcirc;": '\U00000175', + "wedbar;": '\U00002A5F', + "wedge;": '\U00002227', + "wedgeq;": '\U00002259', + "weierp;": '\U00002118', + "wfr;": '\U0001D534', + "wopf;": '\U0001D568', + "wp;": '\U00002118', + "wr;": '\U00002240', + "wreath;": '\U00002240', + "wscr;": '\U0001D4CC', + "xcap;": '\U000022C2', + "xcirc;": '\U000025EF', + "xcup;": '\U000022C3', + "xdtri;": '\U000025BD', + "xfr;": '\U0001D535', + "xhArr;": '\U000027FA', + "xharr;": '\U000027F7', + "xi;": '\U000003BE', + "xlArr;": '\U000027F8', + "xlarr;": '\U000027F5', + "xmap;": '\U000027FC', + "xnis;": '\U000022FB', + "xodot;": '\U00002A00', + "xopf;": '\U0001D569', + "xoplus;": '\U00002A01', + "xotime;": '\U00002A02', + "xrArr;": '\U000027F9', + "xrarr;": '\U000027F6', + "xscr;": '\U0001D4CD', + "xsqcup;": '\U00002A06', + "xuplus;": '\U00002A04', + "xutri;": '\U000025B3', + "xvee;": '\U000022C1', + "xwedge;": '\U000022C0', + "yacute;": '\U000000FD', + "yacy;": '\U0000044F', + "ycirc;": '\U00000177', + "ycy;": '\U0000044B', + "yen;": '\U000000A5', + "yfr;": '\U0001D536', + "yicy;": '\U00000457', + "yopf;": '\U0001D56A', + "yscr;": '\U0001D4CE', + "yucy;": '\U0000044E', + "yuml;": '\U000000FF', + "zacute;": '\U0000017A', + "zcaron;": '\U0000017E', + "zcy;": '\U00000437', + "zdot;": '\U0000017C', + "zeetrf;": '\U00002128', + "zeta;": '\U000003B6', + "zfr;": '\U0001D537', + "zhcy;": '\U00000436', + "zigrarr;": '\U000021DD', + "zopf;": '\U0001D56B', + "zscr;": '\U0001D4CF', + "zwj;": '\U0000200D', + "zwnj;": '\U0000200C', + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Acirc": '\U000000C2', + "Agrave": '\U000000C0', + "Aring": '\U000000C5', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "COPY": '\U000000A9', + "Ccedil": '\U000000C7', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecirc": '\U000000CA', + "Egrave": '\U000000C8', + "Euml": '\U000000CB', + "GT": '\U0000003E', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Igrave": '\U000000CC', + "Iuml": '\U000000CF', + "LT": '\U0000003C', + "Ntilde": '\U000000D1', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ograve": '\U000000D2', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Ouml": '\U000000D6', + "QUOT": '\U00000022', + "REG": '\U000000AE', + "THORN": '\U000000DE', + "Uacute": '\U000000DA', + "Ucirc": '\U000000DB', + "Ugrave": '\U000000D9', + "Uuml": '\U000000DC', + "Yacute": '\U000000DD', + "aacute": '\U000000E1', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "aelig": '\U000000E6', + "agrave": '\U000000E0', + "amp": '\U00000026', + "aring": '\U000000E5', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "brvbar": '\U000000A6', + "ccedil": '\U000000E7', + "cedil": '\U000000B8', + "cent": '\U000000A2', + "copy": '\U000000A9', + "curren": '\U000000A4', + "deg": '\U000000B0', + "divide": '\U000000F7', + "eacute": '\U000000E9', + "ecirc": '\U000000EA', + "egrave": '\U000000E8', + "eth": '\U000000F0', + "euml": '\U000000EB', + "frac12": '\U000000BD', + "frac14": '\U000000BC', + "frac34": '\U000000BE', + "gt": '\U0000003E', + "iacute": '\U000000ED', + "icirc": '\U000000EE', + "iexcl": '\U000000A1', + "igrave": '\U000000EC', + "iquest": '\U000000BF', + "iuml": '\U000000EF', + "laquo": '\U000000AB', + "lt": '\U0000003C', + "macr": '\U000000AF', + "micro": '\U000000B5', + "middot": '\U000000B7', + "nbsp": '\U000000A0', + "not": '\U000000AC', + "ntilde": '\U000000F1', + "oacute": '\U000000F3', + "ocirc": '\U000000F4', + "ograve": '\U000000F2', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "oslash": '\U000000F8', + "otilde": '\U000000F5', + "ouml": '\U000000F6', + "para": '\U000000B6', + "plusmn": '\U000000B1', + "pound": '\U000000A3', + "quot": '\U00000022', + "raquo": '\U000000BB', + "reg": '\U000000AE', + "sect": '\U000000A7', + "shy": '\U000000AD', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "szlig": '\U000000DF', + "thorn": '\U000000FE', + "times": '\U000000D7', + "uacute": '\U000000FA', + "ucirc": '\U000000FB', + "ugrave": '\U000000F9', + "uml": '\U000000A8', + "uuml": '\U000000FC', + "yacute": '\U000000FD', + "yen": '\U000000A5', + "yuml": '\U000000FF', } // HTML entities that are two unicode codepoints. diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go index d3b38440..01477a96 100644 --- a/vendor/golang.org/x/net/html/foreign.go +++ b/vendor/golang.org/x/net/html/foreign.go @@ -67,7 +67,7 @@ func mathMLTextIntegrationPoint(n *Node) bool { return false } -// Section 12.2.5.5. +// Section 12.2.6.5. var breakout = map[string]bool{ "b": true, "big": true, @@ -115,7 +115,7 @@ var breakout = map[string]bool{ "var": true, } -// Section 12.2.5.5. +// Section 12.2.6.5. var svgTagNameAdjustments = map[string]string{ "altglyph": "altGlyph", "altglyphdef": "altGlyphDef", @@ -155,7 +155,7 @@ var svgTagNameAdjustments = map[string]string{ "textpath": "textPath", } -// Section 12.2.5.1 +// Section 12.2.6.1 var mathMLAttributeAdjustments = map[string]string{ "definitionurl": "definitionURL", } diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 26b657ae..2c1cade6 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -21,9 +21,10 @@ const ( scopeMarkerNode ) -// Section 12.2.3.3 says "scope markers are inserted when entering applet -// elements, buttons, object elements, marquees, table cells, and table -// captions, and are used to prevent formatting from 'leaking'". +// Section 12.2.4.3 says "The markers are inserted when entering applet, +// object, marquee, template, td, th, and caption elements, and are used +// to prevent formatting from "leaking" into applet, object, marquee, +// template, td, th, and caption elements". var scopeMarker = Node{Type: scopeMarkerNode} // A Node consists of a NodeType and some Data (tag name for element nodes, @@ -173,6 +174,16 @@ func (s *nodeStack) index(n *Node) int { return -1 } +// contains returns whether a is within s. +func (s *nodeStack) contains(a atom.Atom) bool { + for _, n := range *s { + if n.DataAtom == a { + return true + } + } + return false +} + // insert inserts a node at the given index. func (s *nodeStack) insert(i int, n *Node) { (*s) = append(*s, nil) @@ -191,3 +202,19 @@ func (s *nodeStack) remove(n *Node) { (*s)[j] = nil *s = (*s)[:j] } + +type insertionModeStack []insertionMode + +func (s *insertionModeStack) pop() (im insertionMode) { + i := len(*s) + im = (*s)[i-1] + *s = (*s)[:i-1] + return im +} + +func (s *insertionModeStack) top() insertionMode { + if i := len(*s); i > 0 { + return (*s)[i-1] + } + return nil +} diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index be4b2bf5..091fb0d1 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -25,20 +25,22 @@ type parser struct { hasSelfClosingToken bool // doc is the document root element. doc *Node - // The stack of open elements (section 12.2.3.2) and active formatting - // elements (section 12.2.3.3). + // The stack of open elements (section 12.2.4.2) and active formatting + // elements (section 12.2.4.3). oe, afe nodeStack - // Element pointers (section 12.2.3.4). + // Element pointers (section 12.2.4.4). head, form *Node - // Other parsing state flags (section 12.2.3.5). + // Other parsing state flags (section 12.2.4.5). scripting, framesetOK bool + // The stack of template insertion modes + templateStack insertionModeStack // im is the current insertion mode. im insertionMode // originalIM is the insertion mode to go back to after completing a text // or inTableText insertion mode. originalIM insertionMode // fosterParenting is whether new elements should be inserted according to - // the foster parenting rules (section 12.2.5.3). + // the foster parenting rules (section 12.2.6.1). fosterParenting bool // quirks is whether the parser is operating in "quirks mode." quirks bool @@ -56,7 +58,7 @@ func (p *parser) top() *Node { return p.doc } -// Stop tags for use in popUntil. These come from section 12.2.3.2. +// Stop tags for use in popUntil. These come from section 12.2.4.2. var ( defaultScopeStopTags = map[string][]a.Atom{ "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, @@ -79,7 +81,7 @@ const ( // popUntil pops the stack of open elements at the highest element whose tag // is in matchTags, provided there is no higher element in the scope's stop -// tags (as defined in section 12.2.3.2). It returns whether or not there was +// tags (as defined in section 12.2.4.2). It returns whether or not there was // such an element. If there was not, popUntil leaves the stack unchanged. // // For example, the set of stop tags for table scope is: "html", "table". If @@ -126,7 +128,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { return -1 } case tableScope: - if tagAtom == a.Html || tagAtom == a.Table { + if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { return -1 } case selectScope: @@ -162,17 +164,17 @@ func (p *parser) clearStackToContext(s scope) { tagAtom := p.oe[i].DataAtom switch s { case tableScope: - if tagAtom == a.Html || tagAtom == a.Table { + if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { p.oe = p.oe[:i+1] return } case tableRowScope: - if tagAtom == a.Html || tagAtom == a.Tr { + if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template { p.oe = p.oe[:i+1] return } case tableBodyScope: - if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead { + if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template { p.oe = p.oe[:i+1] return } @@ -183,7 +185,7 @@ func (p *parser) clearStackToContext(s scope) { } // generateImpliedEndTags pops nodes off the stack of open elements as long as -// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt. +// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc. // If exceptions are specified, nodes with that name will not be popped off. func (p *parser) generateImpliedEndTags(exceptions ...string) { var i int @@ -192,7 +194,7 @@ loop: n := p.oe[i] if n.Type == ElementNode { switch n.DataAtom { - case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt: + case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc: for _, except := range exceptions { if n.Data == except { break loop @@ -234,9 +236,9 @@ func (p *parser) shouldFosterParent() bool { } // fosterParent adds a child node according to the foster parenting rules. -// Section 12.2.5.3, "foster parenting". +// Section 12.2.6.1, "foster parenting". func (p *parser) fosterParent(n *Node) { - var table, parent, prev *Node + var table, parent, prev, template *Node var i int for i = len(p.oe) - 1; i >= 0; i-- { if p.oe[i].DataAtom == a.Table { @@ -245,6 +247,19 @@ func (p *parser) fosterParent(n *Node) { } } + var j int + for j = len(p.oe) - 1; j >= 0; j-- { + if p.oe[j].DataAtom == a.Template { + template = p.oe[j] + break + } + } + + if template != nil && (table == nil || j > i) { + template.AppendChild(n) + return + } + if table == nil { // The foster parent is the html element. parent = p.oe[0] @@ -304,7 +319,7 @@ func (p *parser) addElement() { }) } -// Section 12.2.3.3. +// Section 12.2.4.3. func (p *parser) addFormattingElement() { tagAtom, attr := p.tok.DataAtom, p.tok.Attr p.addElement() @@ -351,7 +366,7 @@ findIdenticalElements: p.afe = append(p.afe, p.top()) } -// Section 12.2.3.3. +// Section 12.2.4.3. func (p *parser) clearActiveFormattingElements() { for { n := p.afe.pop() @@ -361,7 +376,7 @@ func (p *parser) clearActiveFormattingElements() { } } -// Section 12.2.3.3. +// Section 12.2.4.3. func (p *parser) reconstructActiveFormattingElements() { n := p.afe.top() if n == nil { @@ -390,12 +405,12 @@ func (p *parser) reconstructActiveFormattingElements() { } } -// Section 12.2.4. +// Section 12.2.5. func (p *parser) acknowledgeSelfClosingTag() { p.hasSelfClosingToken = false } -// An insertion mode (section 12.2.3.1) is the state transition function from +// An insertion mode (section 12.2.4.1) is the state transition function from // a particular state in the HTML5 parser's state machine. It updates the // parser's fields depending on parser.tok (where ErrorToken means EOF). // It returns whether the token was consumed. @@ -403,7 +418,7 @@ type insertionMode func(*parser) bool // setOriginalIM sets the insertion mode to return to after completing a text or // inTableText insertion mode. -// Section 12.2.3.1, "using the rules for". +// Section 12.2.4.1, "using the rules for". func (p *parser) setOriginalIM() { if p.originalIM != nil { panic("html: bad parser state: originalIM was set twice") @@ -411,18 +426,38 @@ func (p *parser) setOriginalIM() { p.originalIM = p.im } -// Section 12.2.3.1, "reset the insertion mode". +// Section 12.2.4.1, "reset the insertion mode". func (p *parser) resetInsertionMode() { for i := len(p.oe) - 1; i >= 0; i-- { n := p.oe[i] - if i == 0 && p.context != nil { + last := i == 0 + if last && p.context != nil { n = p.context } switch n.DataAtom { case a.Select: + if !last { + for ancestor, first := n, p.oe[0]; ancestor != first; { + if ancestor == first { + break + } + ancestor = p.oe[p.oe.index(ancestor)-1] + switch ancestor.DataAtom { + case a.Template: + p.im = inSelectIM + return + case a.Table: + p.im = inSelectInTableIM + return + } + } + } p.im = inSelectIM case a.Td, a.Th: + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 p.im = inCellIM case a.Tr: p.im = inRowIM @@ -434,25 +469,37 @@ func (p *parser) resetInsertionMode() { p.im = inColumnGroupIM case a.Table: p.im = inTableIM + case a.Template: + p.im = p.templateStack.top() case a.Head: - p.im = inBodyIM + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 + p.im = inHeadIM case a.Body: p.im = inBodyIM case a.Frameset: p.im = inFramesetIM case a.Html: - p.im = beforeHeadIM + if p.head == nil { + p.im = beforeHeadIM + } else { + p.im = afterHeadIM + } default: + if last { + p.im = inBodyIM + return + } continue } return } - p.im = inBodyIM } const whitespace = " \t\r\n\f" -// Section 12.2.5.4.1. +// Section 12.2.6.4.1. func initialIM(p *parser) bool { switch p.tok.Type { case TextToken: @@ -479,7 +526,7 @@ func initialIM(p *parser) bool { return false } -// Section 12.2.5.4.2. +// Section 12.2.6.4.2. func beforeHTMLIM(p *parser) bool { switch p.tok.Type { case DoctypeToken: @@ -517,7 +564,7 @@ func beforeHTMLIM(p *parser) bool { return false } -// Section 12.2.5.4.3. +// Section 12.2.6.4.3. func beforeHeadIM(p *parser) bool { switch p.tok.Type { case TextToken: @@ -560,7 +607,7 @@ func beforeHeadIM(p *parser) bool { return false } -// Section 12.2.5.4.4. +// Section 12.2.6.4.4. func inHeadIM(p *parser) bool { switch p.tok.Type { case TextToken: @@ -590,19 +637,41 @@ func inHeadIM(p *parser) bool { case a.Head: // Ignore the token. return true + case a.Template: + p.addElement() + p.afe = append(p.afe, &scopeMarker) + p.framesetOK = false + p.im = inTemplateIM + p.templateStack = append(p.templateStack, inTemplateIM) + return true } case EndTagToken: switch p.tok.DataAtom { case a.Head: - n := p.oe.pop() - if n.DataAtom != a.Head { - panic("html: bad parser state: element not found, in the in-head insertion mode") - } + p.oe.pop() p.im = afterHeadIM return true case a.Body, a.Html, a.Br: p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) return false + case a.Template: + if !p.oe.contains(a.Template) { + return true + } + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 + p.generateImpliedEndTags() + for i := len(p.oe) - 1; i >= 0; i-- { + if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template { + p.oe = p.oe[:i] + break + } + } + p.clearActiveFormattingElements() + p.templateStack.pop() + p.resetInsertionMode() + return true default: // Ignore the token. return true @@ -622,7 +691,7 @@ func inHeadIM(p *parser) bool { return false } -// Section 12.2.5.4.6. +// Section 12.2.6.4.6. func afterHeadIM(p *parser) bool { switch p.tok.Type { case TextToken: @@ -648,7 +717,7 @@ func afterHeadIM(p *parser) bool { p.addElement() p.im = inFramesetIM return true - case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title: p.oe = append(p.oe, p.head) defer p.oe.remove(p.head) return inHeadIM(p) @@ -660,6 +729,8 @@ func afterHeadIM(p *parser) bool { switch p.tok.DataAtom { case a.Body, a.Html, a.Br: // Drop down to creating an implied tag. + case a.Template: + return inHeadIM(p) default: // Ignore the token. return true @@ -697,7 +768,7 @@ func copyAttributes(dst *Node, src Token) { } } -// Section 12.2.5.4.7. +// Section 12.2.6.4.7. func inBodyIM(p *parser) bool { switch p.tok.Type { case TextToken: @@ -727,10 +798,16 @@ func inBodyIM(p *parser) bool { case StartTagToken: switch p.tok.DataAtom { case a.Html: + if p.oe.contains(a.Template) { + return true + } copyAttributes(p.oe[0], p.tok) - case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: + case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title: return inHeadIM(p) case a.Body: + if p.oe.contains(a.Template) { + return true + } if len(p.oe) >= 2 { body := p.oe[1] if body.Type == ElementNode && body.DataAtom == a.Body { @@ -767,9 +844,13 @@ func inBodyIM(p *parser) bool { // The newline, if any, will be dealt with by the TextToken case. p.framesetOK = false case a.Form: - if p.form == nil { - p.popUntil(buttonScope, a.P) - p.addElement() + if p.form != nil && !p.oe.contains(a.Template) { + // Ignore the token + return true + } + p.popUntil(buttonScope, a.P) + p.addElement() + if !p.oe.contains(a.Template) { p.form = p.top() } case a.Li: @@ -952,11 +1033,16 @@ func inBodyIM(p *parser) bool { } p.reconstructActiveFormattingElements() p.addElement() - case a.Rp, a.Rt: + case a.Rb, a.Rtc: if p.elementInScope(defaultScope, a.Ruby) { p.generateImpliedEndTags() } p.addElement() + case a.Rp, a.Rt: + if p.elementInScope(defaultScope, a.Ruby) { + p.generateImpliedEndTags("rtc") + } + p.addElement() case a.Math, a.Svg: p.reconstructActiveFormattingElements() if p.tok.DataAtom == a.Math { @@ -993,15 +1079,29 @@ func inBodyIM(p *parser) bool { case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul: p.popUntil(defaultScope, p.tok.DataAtom) case a.Form: - node := p.form - p.form = nil - i := p.indexOfElementInScope(defaultScope, a.Form) - if node == nil || i == -1 || p.oe[i] != node { - // Ignore the token. - return true + if p.oe.contains(a.Template) { + i := p.indexOfElementInScope(defaultScope, a.Form) + if i == -1 { + // Ignore the token. + return true + } + p.generateImpliedEndTags() + if p.oe[i].DataAtom != a.Form { + // Ignore the token. + return true + } + p.popUntil(defaultScope, a.Form) + } else { + node := p.form + p.form = nil + i := p.indexOfElementInScope(defaultScope, a.Form) + if node == nil || i == -1 || p.oe[i] != node { + // Ignore the token. + return true + } + p.generateImpliedEndTags() + p.oe.remove(node) } - p.generateImpliedEndTags() - p.oe.remove(node) case a.P: if !p.elementInScope(buttonScope, a.P) { p.parseImpliedToken(StartTagToken, a.P, a.P.String()) @@ -1022,6 +1122,8 @@ func inBodyIM(p *parser) bool { case a.Br: p.tok.Type = StartTagToken return false + case a.Template: + return inHeadIM(p) default: p.inBodyEndTagOther(p.tok.DataAtom) } @@ -1030,6 +1132,21 @@ func inBodyIM(p *parser) bool { Type: CommentNode, Data: p.tok.Data, }) + case ErrorToken: + // TODO: remove this divergence from the HTML5 spec. + if len(p.templateStack) > 0 { + p.im = inTemplateIM + return false + } else { + for _, e := range p.oe { + switch e.DataAtom { + case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th, + a.Thead, a.Tr, a.Body, a.Html: + default: + return true + } + } + } } return true @@ -1135,6 +1252,12 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { switch commonAncestor.DataAtom { case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: p.fosterParent(lastNode) + case a.Template: + // TODO: remove namespace checking + if commonAncestor.Namespace == "html" { + commonAncestor = commonAncestor.LastChild + } + fallthrough default: commonAncestor.AppendChild(lastNode) } @@ -1160,7 +1283,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { } // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. -// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content +// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign func (p *parser) inBodyEndTagOther(tagAtom a.Atom) { for i := len(p.oe) - 1; i >= 0; i-- { @@ -1174,7 +1297,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom) { } } -// Section 12.2.5.4.8. +// Section 12.2.6.4.8. func textIM(p *parser) bool { switch p.tok.Type { case ErrorToken: @@ -1203,12 +1326,9 @@ func textIM(p *parser) bool { return p.tok.Type == EndTagToken } -// Section 12.2.5.4.9. +// Section 12.2.6.4.9. func inTableIM(p *parser) bool { switch p.tok.Type { - case ErrorToken: - // Stop parsing. - return true case TextToken: p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1) switch p.oe.top().DataAtom { @@ -1249,7 +1369,7 @@ func inTableIM(p *parser) bool { } // Ignore the token. return true - case a.Style, a.Script: + case a.Style, a.Script, a.Template: return inHeadIM(p) case a.Input: for _, t := range p.tok.Attr { @@ -1261,7 +1381,7 @@ func inTableIM(p *parser) bool { } // Otherwise drop down to the default action. case a.Form: - if p.form != nil { + if p.oe.contains(a.Template) || p.form != nil { // Ignore the token. return true } @@ -1291,6 +1411,8 @@ func inTableIM(p *parser) bool { case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr: // Ignore the token. return true + case a.Template: + return inHeadIM(p) } case CommentToken: p.addChild(&Node{ @@ -1301,6 +1423,8 @@ func inTableIM(p *parser) bool { case DoctypeToken: // Ignore the token. return true + case ErrorToken: + return inBodyIM(p) } p.fosterParenting = true @@ -1309,7 +1433,7 @@ func inTableIM(p *parser) bool { return inBodyIM(p) } -// Section 12.2.5.4.11. +// Section 12.2.6.4.11. func inCaptionIM(p *parser) bool { switch p.tok.Type { case StartTagToken: @@ -1355,7 +1479,7 @@ func inCaptionIM(p *parser) bool { return inBodyIM(p) } -// Section 12.2.5.4.12. +// Section 12.2.6.4.12. func inColumnGroupIM(p *parser) bool { switch p.tok.Type { case TextToken: @@ -1386,11 +1510,13 @@ func inColumnGroupIM(p *parser) bool { p.oe.pop() p.acknowledgeSelfClosingTag() return true + case a.Template: + return inHeadIM(p) } case EndTagToken: switch p.tok.DataAtom { case a.Colgroup: - if p.oe.top().DataAtom != a.Html { + if p.oe.top().DataAtom == a.Colgroup { p.oe.pop() p.im = inTableIM } @@ -1398,17 +1524,21 @@ func inColumnGroupIM(p *parser) bool { case a.Col: // Ignore the token. return true + case a.Template: + return inHeadIM(p) } + case ErrorToken: + return inBodyIM(p) } - if p.oe.top().DataAtom != a.Html { - p.oe.pop() - p.im = inTableIM - return false + if p.oe.top().DataAtom != a.Colgroup { + return true } - return true + p.oe.pop() + p.im = inTableIM + return false } -// Section 12.2.5.4.13. +// Section 12.2.6.4.13. func inTableBodyIM(p *parser) bool { switch p.tok.Type { case StartTagToken: @@ -1460,7 +1590,7 @@ func inTableBodyIM(p *parser) bool { return inTableIM(p) } -// Section 12.2.5.4.14. +// Section 12.2.6.4.14. func inRowIM(p *parser) bool { switch p.tok.Type { case StartTagToken: @@ -1511,7 +1641,7 @@ func inRowIM(p *parser) bool { return inTableIM(p) } -// Section 12.2.5.4.15. +// Section 12.2.6.4.15. func inCellIM(p *parser) bool { switch p.tok.Type { case StartTagToken: @@ -1560,12 +1690,9 @@ func inCellIM(p *parser) bool { return inBodyIM(p) } -// Section 12.2.5.4.16. +// Section 12.2.6.4.16. func inSelectIM(p *parser) bool { switch p.tok.Type { - case ErrorToken: - // Stop parsing. - return true case TextToken: p.addText(strings.Replace(p.tok.Data, "\x00", "", -1)) case StartTagToken: @@ -1597,7 +1724,7 @@ func inSelectIM(p *parser) bool { p.tokenizer.NextIsNotRawText() // Ignore the token. return true - case a.Script: + case a.Script, a.Template: return inHeadIM(p) } case EndTagToken: @@ -1618,6 +1745,8 @@ func inSelectIM(p *parser) bool { if p.popUntil(selectScope, a.Select) { p.resetInsertionMode() } + case a.Template: + return inHeadIM(p) } case CommentToken: p.addChild(&Node{ @@ -1627,12 +1756,14 @@ func inSelectIM(p *parser) bool { case DoctypeToken: // Ignore the token. return true + case ErrorToken: + return inBodyIM(p) } return true } -// Section 12.2.5.4.17. +// Section 12.2.6.4.17. func inSelectInTableIM(p *parser) bool { switch p.tok.Type { case StartTagToken, EndTagToken: @@ -1650,7 +1781,73 @@ func inSelectInTableIM(p *parser) bool { return inSelectIM(p) } -// Section 12.2.5.4.18. +// Section 12.2.6.4.18. +func inTemplateIM(p *parser) bool { + switch p.tok.Type { + case TextToken, CommentToken, DoctypeToken: + return inBodyIM(p) + case StartTagToken: + switch p.tok.DataAtom { + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title: + return inHeadIM(p) + case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead: + p.templateStack.pop() + p.templateStack = append(p.templateStack, inTableIM) + p.im = inTableIM + return false + case a.Col: + p.templateStack.pop() + p.templateStack = append(p.templateStack, inColumnGroupIM) + p.im = inColumnGroupIM + return false + case a.Tr: + p.templateStack.pop() + p.templateStack = append(p.templateStack, inTableBodyIM) + p.im = inTableBodyIM + return false + case a.Td, a.Th: + p.templateStack.pop() + p.templateStack = append(p.templateStack, inRowIM) + p.im = inRowIM + return false + default: + p.templateStack.pop() + p.templateStack = append(p.templateStack, inBodyIM) + p.im = inBodyIM + return false + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Template: + return inHeadIM(p) + default: + // Ignore the token. + return true + } + case ErrorToken: + if !p.oe.contains(a.Template) { + // Ignore the token. + return true + } + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 + p.generateImpliedEndTags() + for i := len(p.oe) - 1; i >= 0; i-- { + if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template { + p.oe = p.oe[:i] + break + } + } + p.clearActiveFormattingElements() + p.templateStack.pop() + p.resetInsertionMode() + return false + } + return false +} + +// Section 12.2.6.4.19. func afterBodyIM(p *parser) bool { switch p.tok.Type { case ErrorToken: @@ -1688,7 +1885,7 @@ func afterBodyIM(p *parser) bool { return false } -// Section 12.2.5.4.19. +// Section 12.2.6.4.20. func inFramesetIM(p *parser) bool { switch p.tok.Type { case CommentToken: @@ -1738,7 +1935,7 @@ func inFramesetIM(p *parser) bool { return true } -// Section 12.2.5.4.20. +// Section 12.2.6.4.21. func afterFramesetIM(p *parser) bool { switch p.tok.Type { case CommentToken: @@ -1777,7 +1974,7 @@ func afterFramesetIM(p *parser) bool { return true } -// Section 12.2.5.4.21. +// Section 12.2.6.4.22. func afterAfterBodyIM(p *parser) bool { switch p.tok.Type { case ErrorToken: @@ -1806,7 +2003,7 @@ func afterAfterBodyIM(p *parser) bool { return false } -// Section 12.2.5.4.22. +// Section 12.2.6.4.23. func afterAfterFramesetIM(p *parser) bool { switch p.tok.Type { case CommentToken: @@ -1844,7 +2041,7 @@ func afterAfterFramesetIM(p *parser) bool { const whitespaceOrNUL = whitespace + "\x00" -// Section 12.2.5.5. +// Section 12.2.6.5 func parseForeignContent(p *parser) bool { switch p.tok.Type { case TextToken: @@ -1924,7 +2121,7 @@ func parseForeignContent(p *parser) bool { return true } -// Section 12.2.5. +// Section 12.2.6. func (p *parser) inForeignContent() bool { if len(p.oe) == 0 { return false @@ -2012,6 +2209,15 @@ func (p *parser) parse() error { } // Parse returns the parse tree for the HTML from the given Reader. +// +// It implements the HTML5 parsing algorithm +// (https://html.spec.whatwg.org/multipage/syntax.html#tree-construction), +// which is very complicated. The resultant tree can contain implicitly created +// nodes that have no explicit listed in r's data, and nodes' parents can +// differ from the nesting implied by a naive processing of start and end +// s. Conversely, explicit s in r's data can be silently dropped, +// with no corresponding node in the resulting tree. +// // The input is assumed to be UTF-8 encoded. func Parse(r io.Reader) (*Node, error) { p := &parser{ @@ -2033,6 +2239,8 @@ func Parse(r io.Reader) (*Node, error) { // ParseFragment parses a fragment of HTML and returns the nodes that were // found. If the fragment is the InnerHTML for an existing element, pass that // element in context. +// +// It has the same intricacies as Parse. func ParseFragment(r io.Reader, context *Node) ([]*Node, error) { contextTag := "" if context != nil { @@ -2064,6 +2272,9 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) { } p.doc.AppendChild(root) p.oe = nodeStack{root} + if context != nil && context.DataAtom == a.Template { + p.templateStack = append(p.templateStack, inTemplateIM) + } p.resetInsertionMode() for n := context; n != nil; n = n.Parent { diff --git a/vendor/golang.org/x/net/html/parse_test.go b/vendor/golang.org/x/net/html/parse_test.go index 7e47d11b..1c232c71 100644 --- a/vendor/golang.org/x/net/html/parse_test.go +++ b/vendor/golang.org/x/net/html/parse_test.go @@ -125,6 +125,7 @@ func (a sortedAttributes) Swap(i, j int) { func dumpLevel(w io.Writer, n *Node, level int) error { dumpIndent(w, level) + level++ switch n.Type { case ErrorNode: return errors.New("unexpected ErrorNode") @@ -140,13 +141,19 @@ func dumpLevel(w io.Writer, n *Node, level int) error { sort.Sort(attr) for _, a := range attr { io.WriteString(w, "\n") - dumpIndent(w, level+1) + dumpIndent(w, level) if a.Namespace != "" { fmt.Fprintf(w, `%s %s="%s"`, a.Namespace, a.Key, a.Val) } else { fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val) } } + if n.Namespace == "" && n.DataAtom == atom.Template { + io.WriteString(w, "\n") + dumpIndent(w, level) + level++ + io.WriteString(w, "content") + } case TextNode: fmt.Fprintf(w, `"%s"`, n.Data) case CommentNode: @@ -176,7 +183,7 @@ func dumpLevel(w io.Writer, n *Node, level int) error { } io.WriteString(w, "\n") for c := n.FirstChild; c != nil; c = c.NextSibling { - if err := dumpLevel(w, c, level+1); err != nil { + if err := dumpLevel(w, c, level); err != nil { return err } } @@ -196,34 +203,36 @@ func dump(n *Node) (string, error) { return b.String(), nil } -const testDataDir = "testdata/webkit/" +var testDataDirs = []string{"testdata/webkit/", "testdata/go/"} func TestParser(t *testing.T) { - testFiles, err := filepath.Glob(testDataDir + "*.dat") - if err != nil { - t.Fatal(err) - } - for _, tf := range testFiles { - f, err := os.Open(tf) + for _, testDataDir := range testDataDirs { + testFiles, err := filepath.Glob(testDataDir + "*.dat") if err != nil { t.Fatal(err) } - defer f.Close() - r := bufio.NewReader(f) - - for i := 0; ; i++ { - text, want, context, err := readParseTest(r) - if err == io.EOF { - break - } + for _, tf := range testFiles { + f, err := os.Open(tf) if err != nil { t.Fatal(err) } + defer f.Close() + r := bufio.NewReader(f) - err = testParseCase(text, want, context) + for i := 0; ; i++ { + text, want, context, err := readParseTest(r) + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } - if err != nil { - t.Errorf("%s test #%d %q, %s", tf, i, text, err) + err = testParseCase(text, want, context) + + if err != nil { + t.Errorf("%s test #%d %q, %s", tf, i, text, err) + } } } } @@ -320,6 +329,7 @@ var renderTestBlacklist = map[string]bool{ `ababrx
aoe`: true, `